summaryrefslogtreecommitdiffstats
path: root/contrib/gcc
diff options
context:
space:
mode:
authorobrien <obrien@FreeBSD.org>1999-08-26 09:30:50 +0000
committerobrien <obrien@FreeBSD.org>1999-08-26 09:30:50 +0000
commit0bedf4fb30066e5e1d4342a1d3914dae7d37cba7 (patch)
tree68d8110b41afd0ebbf39167b1a4918eea667a7c5 /contrib/gcc
parentd4db5fb866b7ad5216abd5047774a3973b9901a9 (diff)
downloadFreeBSD-src-0bedf4fb30066e5e1d4342a1d3914dae7d37cba7.zip
FreeBSD-src-0bedf4fb30066e5e1d4342a1d3914dae7d37cba7.tar.gz
Virgin import of gcc from EGCS 1.1.2
Diffstat (limited to 'contrib/gcc')
-rw-r--r--contrib/gcc/BUGS2
-rw-r--r--contrib/gcc/ChangeLog16779
-rw-r--r--contrib/gcc/LANGUAGES79
-rw-r--r--contrib/gcc/Makefile.in2093
-rw-r--r--contrib/gcc/NEWS340
-rw-r--r--contrib/gcc/PROJECTS135
-rw-r--r--contrib/gcc/README5
-rw-r--r--contrib/gcc/README-bugs144
-rw-r--r--contrib/gcc/README.DWARF6
-rw-r--r--contrib/gcc/README.g77263
-rw-r--r--contrib/gcc/SERVICE1821
-rw-r--r--contrib/gcc/acconfig.h79
-rw-r--r--contrib/gcc/aclocal.m4221
-rw-r--r--contrib/gcc/alias.c1261
-rw-r--r--contrib/gcc/alloca.c16
-rw-r--r--contrib/gcc/basic-block.h227
-rw-r--r--contrib/gcc/bitmap.c642
-rw-r--r--contrib/gcc/bitmap.h317
-rw-r--r--contrib/gcc/build-make9
-rw-r--r--contrib/gcc/c-aux-info.c79
-rw-r--r--contrib/gcc/c-common.c1198
-rw-r--r--contrib/gcc/c-convert.c1
-rw-r--r--contrib/gcc/c-decl.c954
-rw-r--r--contrib/gcc/c-iterate.c62
-rw-r--r--contrib/gcc/c-lang.c72
-rw-r--r--contrib/gcc/c-lex.c648
-rw-r--r--contrib/gcc/c-lex.h14
-rw-r--r--contrib/gcc/c-parse.in341
-rw-r--r--contrib/gcc/c-pragma.c23
-rw-r--r--contrib/gcc/c-tree.h73
-rw-r--r--contrib/gcc/c-typeck.c918
-rw-r--r--contrib/gcc/caller-save.c83
-rw-r--r--contrib/gcc/calls.c1278
-rw-r--r--contrib/gcc/cccp.121
-rw-r--r--contrib/gcc/cccp.c4084
-rw-r--r--contrib/gcc/cexp.y605
-rw-r--r--contrib/gcc/choose-temp.c211
-rw-r--r--contrib/gcc/collect2.c1375
-rw-r--r--contrib/gcc/combine.c2125
-rw-r--r--contrib/gcc/conditions.h2
-rwxr-xr-xcontrib/gcc/config.guess579
-rw-r--r--contrib/gcc/config.in202
-rwxr-xr-xcontrib/gcc/config.sub221
-rw-r--r--contrib/gcc/config/alpha/alpha.c3669
-rw-r--r--contrib/gcc/config/alpha/alpha.h1125
-rw-r--r--contrib/gcc/config/alpha/alpha.md3300
-rw-r--r--contrib/gcc/config/alpha/crtbegin.asm111
-rw-r--r--contrib/gcc/config/alpha/crtend.asm105
-rw-r--r--contrib/gcc/config/alpha/elf.h190
-rw-r--r--contrib/gcc/config/alpha/linux-ecoff.h36
-rw-r--r--contrib/gcc/config/alpha/linux-elf.h47
-rw-r--r--contrib/gcc/config/alpha/linux.h44
-rw-r--r--contrib/gcc/config/alpha/netbsd-elf.h31
-rw-r--r--contrib/gcc/config/alpha/netbsd.h38
-rw-r--r--contrib/gcc/config/alpha/openbsd.h126
-rw-r--r--contrib/gcc/config/alpha/osf.h127
-rw-r--r--contrib/gcc/config/alpha/osf12.h10
-rw-r--r--contrib/gcc/config/alpha/osf2or3.h30
-rw-r--r--contrib/gcc/config/alpha/t-crtbe9
-rw-r--r--contrib/gcc/config/alpha/t-vms6
-rw-r--r--contrib/gcc/config/alpha/va_list.h16
-rw-r--r--contrib/gcc/config/alpha/vms-tramp.asm22
-rw-r--r--contrib/gcc/config/alpha/vms.h510
-rw-r--r--contrib/gcc/config/alpha/vxworks.h51
-rw-r--r--contrib/gcc/config/alpha/x-alpha1
-rw-r--r--contrib/gcc/config/alpha/xm-alpha.h18
-rw-r--r--contrib/gcc/config/alpha/xm-openbsd.h23
-rw-r--r--contrib/gcc/config/alpha/xm-vms.h93
-rw-r--r--contrib/gcc/config/aoutos.h47
-rw-r--r--contrib/gcc/config/dbx.h30
-rw-r--r--contrib/gcc/config/dbxcoff.h87
-rw-r--r--contrib/gcc/config/float-i128.h96
-rw-r--r--contrib/gcc/config/float-i32.h96
-rw-r--r--contrib/gcc/config/float-i386.h104
-rw-r--r--contrib/gcc/config/float-i64.h96
-rw-r--r--contrib/gcc/config/float-m68k.h97
-rw-r--r--contrib/gcc/config/float-sh.h130
-rw-r--r--contrib/gcc/config/float-vax.h96
-rw-r--r--contrib/gcc/config/fp-bit.c250
-rw-r--r--contrib/gcc/config/gnu.h7
-rw-r--r--contrib/gcc/config/i386/386bsd.h9
-rw-r--r--contrib/gcc/config/i386/aix386ng.h15
-rw-r--r--contrib/gcc/config/i386/att.h21
-rw-r--r--contrib/gcc/config/i386/bsd.h8
-rw-r--r--contrib/gcc/config/i386/bsd386.h19
-rw-r--r--contrib/gcc/config/i386/crtdll.h42
-rw-r--r--contrib/gcc/config/i386/dgux.c190
-rw-r--r--contrib/gcc/config/i386/dgux.h265
-rw-r--r--contrib/gcc/config/i386/freebsd-elf.h44
-rw-r--r--contrib/gcc/config/i386/freebsd.h349
-rw-r--r--contrib/gcc/config/i386/freebsd.h.fixed349
-rw-r--r--contrib/gcc/config/i386/gas.h48
-rw-r--r--contrib/gcc/config/i386/gmon-sol2.c409
-rw-r--r--contrib/gcc/config/i386/gnu.h15
-rw-r--r--contrib/gcc/config/i386/go32.h34
-rw-r--r--contrib/gcc/config/i386/i386.c2818
-rw-r--r--contrib/gcc/config/i386/i386.h1313
-rw-r--r--contrib/gcc/config/i386/i386.md4049
-rw-r--r--contrib/gcc/config/i386/isc.h8
-rw-r--r--contrib/gcc/config/i386/linux-aout.h20
-rw-r--r--contrib/gcc/config/i386/linux-oldld.h21
-rw-r--r--contrib/gcc/config/i386/linux.h73
-rw-r--r--contrib/gcc/config/i386/lynx.h8
-rw-r--r--contrib/gcc/config/i386/mingw32.h95
-rw-r--r--contrib/gcc/config/i386/moss.h34
-rw-r--r--contrib/gcc/config/i386/netbsd.h23
-rw-r--r--contrib/gcc/config/i386/next.h15
-rw-r--r--contrib/gcc/config/i386/openbsd.h130
-rw-r--r--contrib/gcc/config/i386/osf1-ci.asm65
-rw-r--r--contrib/gcc/config/i386/osf1-cn.asm46
-rw-r--r--contrib/gcc/config/i386/osf1elf.h260
-rw-r--r--contrib/gcc/config/i386/osf1elfgdb.h7
-rw-r--r--contrib/gcc/config/i386/osfelf.h4
-rw-r--r--contrib/gcc/config/i386/osfrose.h37
-rw-r--r--contrib/gcc/config/i386/ptx4-i.h247
-rw-r--r--contrib/gcc/config/i386/rtems.h34
-rw-r--r--contrib/gcc/config/i386/rtemself.h169
-rw-r--r--contrib/gcc/config/i386/sco.h8
-rw-r--r--contrib/gcc/config/i386/sco4.h6
-rw-r--r--contrib/gcc/config/i386/sco4dbx.h6
-rw-r--r--contrib/gcc/config/i386/sco5.h957
-rw-r--r--contrib/gcc/config/i386/sco5gas.h24
-rw-r--r--contrib/gcc/config/i386/scodbx.h8
-rw-r--r--contrib/gcc/config/i386/seq-gas.h4
-rw-r--r--contrib/gcc/config/i386/seq-sysv3.h14
-rw-r--r--contrib/gcc/config/i386/sol2-c1.asm4
-rw-r--r--contrib/gcc/config/i386/sol2-gc1.asm160
-rw-r--r--contrib/gcc/config/i386/sol2.h46
-rw-r--r--contrib/gcc/config/i386/sun386.h7
-rw-r--r--contrib/gcc/config/i386/svr3.ifile5
-rw-r--r--contrib/gcc/config/i386/svr3dbx.h22
-rw-r--r--contrib/gcc/config/i386/svr3gas.h18
-rw-r--r--contrib/gcc/config/i386/svr3z.ifile5
-rw-r--r--contrib/gcc/config/i386/sysv3.h8
-rw-r--r--contrib/gcc/config/i386/sysv4.h14
-rw-r--r--contrib/gcc/config/i386/t-crtpic1
-rw-r--r--contrib/gcc/config/i386/t-dgux4
-rw-r--r--contrib/gcc/config/i386/t-mingw324
-rw-r--r--contrib/gcc/config/i386/t-next3
-rw-r--r--contrib/gcc/config/i386/t-osf2
-rw-r--r--contrib/gcc/config/i386/t-osf1elf18
-rw-r--r--contrib/gcc/config/i386/t-sco520
-rw-r--r--contrib/gcc/config/i386/t-sco5gas20
-rw-r--r--contrib/gcc/config/i386/t-sol222
-rw-r--r--contrib/gcc/config/i386/t-winnt6
-rw-r--r--contrib/gcc/config/i386/unix.h47
-rw-r--r--contrib/gcc/config/i386/vxi386.h23
-rw-r--r--contrib/gcc/config/i386/winnt.c526
-rw-r--r--contrib/gcc/config/i386/x-dgux11
-rw-r--r--contrib/gcc/config/i386/x-osf1elf8
-rw-r--r--contrib/gcc/config/i386/x-osfrose10
-rw-r--r--contrib/gcc/config/i386/x-sco510
-rw-r--r--contrib/gcc/config/i386/xm-aix.h35
-rw-r--r--contrib/gcc/config/i386/xm-bsd386.h3
-rw-r--r--contrib/gcc/config/i386/xm-dgux.h12
-rw-r--r--contrib/gcc/config/i386/xm-dos.h6
-rw-r--r--contrib/gcc/config/i386/xm-isc.h2
-rw-r--r--contrib/gcc/config/i386/xm-linux.h4
-rw-r--r--contrib/gcc/config/i386/xm-mingw32.h42
-rw-r--r--contrib/gcc/config/i386/xm-openbsd.h23
-rw-r--r--contrib/gcc/config/i386/xm-os2.h28
-rw-r--r--contrib/gcc/config/i386/xm-osf.h30
-rw-r--r--contrib/gcc/config/i386/xm-osf1elf.h6
-rw-r--r--contrib/gcc/config/i386/xm-sco.h9
-rw-r--r--contrib/gcc/config/i386/xm-sco5.h7
-rw-r--r--contrib/gcc/config/i386/xm-sun.h6
-rw-r--r--contrib/gcc/config/i386/xm-sysv4.h11
-rw-r--r--contrib/gcc/config/i386/xm-vsta.h24
-rw-r--r--contrib/gcc/config/libgloss.h35
-rw-r--r--contrib/gcc/config/linux-aout.h13
-rw-r--r--contrib/gcc/config/linux.h67
-rw-r--r--contrib/gcc/config/lynx.h5
-rw-r--r--contrib/gcc/config/netbsd.h37
-rw-r--r--contrib/gcc/config/nextstep.c48
-rw-r--r--contrib/gcc/config/nextstep.h75
-rw-r--r--contrib/gcc/config/openbsd.h302
-rw-r--r--contrib/gcc/config/psos.h183
-rw-r--r--contrib/gcc/config/ptx4.h859
-rw-r--r--contrib/gcc/config/sparc/aout.h26
-rw-r--r--contrib/gcc/config/sparc/bsd.h7
-rw-r--r--contrib/gcc/config/sparc/elf.h42
-rw-r--r--contrib/gcc/config/sparc/gmon-sol2.c429
-rw-r--r--contrib/gcc/config/sparc/lb1spc.asm784
-rw-r--r--contrib/gcc/config/sparc/lb1spl.asm246
-rw-r--r--contrib/gcc/config/sparc/linux-aout.h130
-rw-r--r--contrib/gcc/config/sparc/linux.h259
-rw-r--r--contrib/gcc/config/sparc/linux64.h245
-rw-r--r--contrib/gcc/config/sparc/lite.h38
-rw-r--r--contrib/gcc/config/sparc/litecoff.h113
-rw-r--r--contrib/gcc/config/sparc/lynx-ng.h41
-rw-r--r--contrib/gcc/config/sparc/lynx.h53
-rw-r--r--contrib/gcc/config/sparc/netbsd.h46
-rw-r--r--contrib/gcc/config/sparc/openbsd.h68
-rw-r--r--contrib/gcc/config/sparc/pbd.h184
-rw-r--r--contrib/gcc/config/sparc/rtems.h35
-rw-r--r--contrib/gcc/config/sparc/sol2-c1.asm86
-rw-r--r--contrib/gcc/config/sparc/sol2-ci.asm60
-rw-r--r--contrib/gcc/config/sparc/sol2-cn.asm54
-rw-r--r--contrib/gcc/config/sparc/sol2-g1.asm88
-rw-r--r--contrib/gcc/config/sparc/sol2-sld.h11
-rw-r--r--contrib/gcc/config/sparc/sol2.h232
-rw-r--r--contrib/gcc/config/sparc/sp64-aout.h38
-rw-r--r--contrib/gcc/config/sparc/sp64-elf.h157
-rw-r--r--contrib/gcc/config/sparc/sparc.c6461
-rw-r--r--contrib/gcc/config/sparc/sparc.h3287
-rw-r--r--contrib/gcc/config/sparc/sparc.md6684
-rw-r--r--contrib/gcc/config/sparc/splet.h53
-rw-r--r--contrib/gcc/config/sparc/sun4gas.h27
-rw-r--r--contrib/gcc/config/sparc/sun4o3.h29
-rw-r--r--contrib/gcc/config/sparc/sunos4.h49
-rw-r--r--contrib/gcc/config/sparc/sysv4.h231
-rw-r--r--contrib/gcc/config/sparc/t-elf39
-rw-r--r--contrib/gcc/config/sparc/t-sol230
-rw-r--r--contrib/gcc/config/sparc/t-sp642
-rw-r--r--contrib/gcc/config/sparc/t-sparcbare26
-rw-r--r--contrib/gcc/config/sparc/t-sparclite24
-rw-r--r--contrib/gcc/config/sparc/t-splet23
-rw-r--r--contrib/gcc/config/sparc/t-sunos407
-rw-r--r--contrib/gcc/config/sparc/t-sunos4116
-rw-r--r--contrib/gcc/config/sparc/t-vxsparc17
-rw-r--r--contrib/gcc/config/sparc/vxsim.h131
-rw-r--r--contrib/gcc/config/sparc/vxsparc.h61
-rw-r--r--contrib/gcc/config/sparc/x-sysv42
-rw-r--r--contrib/gcc/config/sparc/xm-linux.h26
-rw-r--r--contrib/gcc/config/sparc/xm-lynx.h39
-rw-r--r--contrib/gcc/config/sparc/xm-openbsd.h23
-rw-r--r--contrib/gcc/config/sparc/xm-pbd.h10
-rw-r--r--contrib/gcc/config/sparc/xm-sol2.h4
-rw-r--r--contrib/gcc/config/sparc/xm-sp64.h25
-rw-r--r--contrib/gcc/config/sparc/xm-sparc.h49
-rw-r--r--contrib/gcc/config/sparc/xm-sysv4.h48
-rw-r--r--contrib/gcc/config/svr3.h36
-rw-r--r--contrib/gcc/config/svr4.h187
-rw-r--r--contrib/gcc/config/t-freebsd5
-rw-r--r--contrib/gcc/config/t-gnu13
-rw-r--r--contrib/gcc/config/t-libc-ok1
-rw-r--r--contrib/gcc/config/t-linux-aout11
-rw-r--r--contrib/gcc/config/t-netbsd9
-rw-r--r--contrib/gcc/config/t-openbsd9
-rw-r--r--contrib/gcc/config/t-openbsd-thread5
-rw-r--r--contrib/gcc/config/t-rtems6
-rw-r--r--contrib/gcc/config/t-svr43
-rw-r--r--contrib/gcc/config/x-linux15
-rw-r--r--contrib/gcc/config/x-linux-aout14
-rw-r--r--contrib/gcc/config/xm-alloca.h4
-rw-r--r--contrib/gcc/config/xm-freebsd.h9
-rw-r--r--contrib/gcc/config/xm-gnu.h5
-rw-r--r--contrib/gcc/config/xm-linux.h19
-rw-r--r--contrib/gcc/config/xm-netbsd.h1
-rw-r--r--contrib/gcc/config/xm-openbsd.h35
-rw-r--r--contrib/gcc/config/xm-siglist.h6
-rw-r--r--contrib/gcc/config/xm-std32.h34
-rw-r--r--contrib/gcc/config/xm-svr3.h10
-rw-r--r--contrib/gcc/config/xm-svr4.h12
-rwxr-xr-xcontrib/gcc/configure6138
-rw-r--r--contrib/gcc/configure.frag77
-rw-r--r--contrib/gcc/configure.in3833
-rw-r--r--contrib/gcc/configure.lang233
-rw-r--r--contrib/gcc/convert.c290
-rw-r--r--contrib/gcc/cp/ChangeLog15356
-rw-r--r--contrib/gcc/cp/Make-lang.in192
-rw-r--r--contrib/gcc/cp/Makefile.in168
-rw-r--r--contrib/gcc/cp/NEWS226
-rw-r--r--contrib/gcc/cp/call.c6115
-rw-r--r--contrib/gcc/cp/class.c2837
-rw-r--r--contrib/gcc/cp/config-lang.in8
-rw-r--r--contrib/gcc/cp/cp-tree.def240
-rw-r--r--contrib/gcc/cp/cp-tree.h1549
-rw-r--r--contrib/gcc/cp/cvt.c1292
-rw-r--r--contrib/gcc/cp/decl.c8058
-rw-r--r--contrib/gcc/cp/decl.h2
-rw-r--r--contrib/gcc/cp/decl2.c3663
-rw-r--r--contrib/gcc/cp/errfn.c280
-rw-r--r--contrib/gcc/cp/error.c816
-rw-r--r--contrib/gcc/cp/except.c2131
-rw-r--r--contrib/gcc/cp/exception.cc324
-rw-r--r--contrib/gcc/cp/expr.c258
-rw-r--r--contrib/gcc/cp/friend.c484
-rw-r--r--contrib/gcc/cp/g++.132
-rw-r--r--contrib/gcc/cp/g++spec.c269
-rw-r--r--contrib/gcc/cp/gxx.gperf24
-rw-r--r--contrib/gcc/cp/gxxint.texi575
-rw-r--r--contrib/gcc/cp/inc/exception43
-rw-r--r--contrib/gcc/cp/inc/new46
-rw-r--r--contrib/gcc/cp/inc/new.h13
-rw-r--r--contrib/gcc/cp/inc/typeinfo62
-rw-r--r--contrib/gcc/cp/init.c2677
-rw-r--r--contrib/gcc/cp/input.c81
-rw-r--r--contrib/gcc/cp/lang-options.h182
-rw-r--r--contrib/gcc/cp/lang-specs.h67
-rw-r--r--contrib/gcc/cp/lex.c2257
-rw-r--r--contrib/gcc/cp/lex.h18
-rw-r--r--contrib/gcc/cp/method.c2878
-rw-r--r--contrib/gcc/cp/mpw-config.in11
-rw-r--r--contrib/gcc/cp/mpw-make.sed112
-rw-r--r--contrib/gcc/cp/new.cc42
-rw-r--r--contrib/gcc/cp/new1.cc89
-rw-r--r--contrib/gcc/cp/new2.cc80
-rw-r--r--contrib/gcc/cp/parse.y3187
-rw-r--r--contrib/gcc/cp/pt.c7895
-rw-r--r--contrib/gcc/cp/ptree.c61
-rw-r--r--contrib/gcc/cp/repo.c136
-rw-r--r--contrib/gcc/cp/rtti.c1135
-rw-r--r--contrib/gcc/cp/search.c1407
-rw-r--r--contrib/gcc/cp/semantics.c1393
-rw-r--r--contrib/gcc/cp/sig.c149
-rw-r--r--contrib/gcc/cp/spew.c232
-rw-r--r--contrib/gcc/cp/tinfo.cc134
-rw-r--r--contrib/gcc/cp/tinfo.h55
-rw-r--r--contrib/gcc/cp/tinfo2.cc300
-rw-r--r--contrib/gcc/cp/tree.c1801
-rw-r--r--contrib/gcc/cp/typeck.c4128
-rw-r--r--contrib/gcc/cp/typeck2.c514
-rw-r--r--contrib/gcc/cp/xref.c94
-rw-r--r--contrib/gcc/cplus-dem.c2327
-rw-r--r--contrib/gcc/cpp.texi185
-rw-r--r--contrib/gcc/cppalloc.c28
-rw-r--r--contrib/gcc/cpperror.c95
-rw-r--r--contrib/gcc/cppexp.c182
-rw-r--r--contrib/gcc/cpphash.c78
-rw-r--r--contrib/gcc/cpphash.h4
-rw-r--r--contrib/gcc/cpplib.c2517
-rw-r--r--contrib/gcc/cpplib.h184
-rw-r--r--contrib/gcc/cppmain.c43
-rw-r--r--contrib/gcc/cross-make6
-rw-r--r--contrib/gcc/crtstuff.c221
-rw-r--r--contrib/gcc/cse.c1171
-rw-r--r--contrib/gcc/cstamp-h.in1
-rw-r--r--contrib/gcc/dbxout.c673
-rw-r--r--contrib/gcc/dbxout.h33
-rw-r--r--contrib/gcc/demangle.h48
-rw-r--r--contrib/gcc/doprint.c286
-rw-r--r--contrib/gcc/doschk.c8
-rw-r--r--contrib/gcc/dwarf.h6
-rw-r--r--contrib/gcc/dwarf2.h548
-rw-r--r--contrib/gcc/dwarf2out.c9884
-rw-r--r--contrib/gcc/dwarf2out.h41
-rw-r--r--contrib/gcc/dwarfout.c1285
-rw-r--r--contrib/gcc/dwarfout.h40
-rw-r--r--contrib/gcc/dyn-string.c100
-rw-r--r--contrib/gcc/dyn-string.h31
-rw-r--r--contrib/gcc/eh-common.h125
-rw-r--r--contrib/gcc/emit-rtl.c876
-rw-r--r--contrib/gcc/enquire.c170
-rw-r--r--contrib/gcc/except.c2694
-rw-r--r--contrib/gcc/except.h385
-rw-r--r--contrib/gcc/explow.c439
-rw-r--r--contrib/gcc/expmed.c780
-rw-r--r--contrib/gcc/expr.c6008
-rw-r--r--contrib/gcc/expr.h193
-rw-r--r--contrib/gcc/extend.texi814
-rw-r--r--contrib/gcc/f/BUGS211
-rw-r--r--contrib/gcc/f/ChangeLog4804
-rw-r--r--contrib/gcc/f/Make-lang.in472
-rw-r--r--contrib/gcc/f/Makefile.in530
-rw-r--r--contrib/gcc/f/NEWS1623
-rw-r--r--contrib/gcc/f/README7
-rw-r--r--contrib/gcc/f/ansify.c208
-rw-r--r--contrib/gcc/f/assert.j27
-rw-r--r--contrib/gcc/f/bad.c544
-rw-r--r--contrib/gcc/f/bad.def711
-rw-r--r--contrib/gcc/f/bad.h108
-rw-r--r--contrib/gcc/f/bit.c201
-rw-r--r--contrib/gcc/f/bit.h84
-rw-r--r--contrib/gcc/f/bld-op.def69
-rw-r--r--contrib/gcc/f/bld.c5794
-rw-r--r--contrib/gcc/f/bld.h1024
-rw-r--r--contrib/gcc/f/bugs.texi341
-rw-r--r--contrib/gcc/f/bugs0.texi17
-rw-r--r--contrib/gcc/f/com-rt.def282
-rw-r--r--contrib/gcc/f/com.c16510
-rw-r--r--contrib/gcc/f/com.h376
-rw-r--r--contrib/gcc/f/config-lang.in37
-rw-r--r--contrib/gcc/f/config.j27
-rw-r--r--contrib/gcc/f/convert.j28
-rw-r--r--contrib/gcc/f/data.c1816
-rw-r--r--contrib/gcc/f/data.h74
-rw-r--r--contrib/gcc/f/equiv.c1498
-rw-r--r--contrib/gcc/f/equiv.h103
-rw-r--r--contrib/gcc/f/expr.c19304
-rw-r--r--contrib/gcc/f/expr.h194
-rw-r--r--contrib/gcc/f/fini.c773
-rw-r--r--contrib/gcc/f/flags.j27
-rw-r--r--contrib/gcc/f/g77.1357
-rw-r--r--contrib/gcc/f/g77.texi14999
-rw-r--r--contrib/gcc/f/g77spec.c580
-rw-r--r--contrib/gcc/f/glimits.j28
-rw-r--r--contrib/gcc/f/global.c1536
-rw-r--r--contrib/gcc/f/global.h200
-rw-r--r--contrib/gcc/f/hconfig.j27
-rw-r--r--contrib/gcc/f/implic.c382
-rw-r--r--contrib/gcc/f/implic.h74
-rw-r--r--contrib/gcc/f/info-b.def36
-rw-r--r--contrib/gcc/f/info-k.def37
-rw-r--r--contrib/gcc/f/info-w.def41
-rw-r--r--contrib/gcc/f/info.c304
-rw-r--r--contrib/gcc/f/info.h186
-rw-r--r--contrib/gcc/f/input.j27
-rw-r--r--contrib/gcc/f/intdoc.c1336
-rw-r--r--contrib/gcc/f/intdoc.in2519
-rw-r--r--contrib/gcc/f/intdoc.texi10745
-rw-r--r--contrib/gcc/f/intrin.c2055
-rw-r--r--contrib/gcc/f/intrin.def3351
-rw-r--r--contrib/gcc/f/intrin.h130
-rw-r--r--contrib/gcc/f/lab.c159
-rw-r--r--contrib/gcc/f/lab.h154
-rw-r--r--contrib/gcc/f/lang-options.h158
-rw-r--r--contrib/gcc/f/lang-specs.h106
-rw-r--r--contrib/gcc/f/lex.c4717
-rw-r--r--contrib/gcc/f/lex.h201
-rw-r--r--contrib/gcc/f/malloc.c554
-rw-r--r--contrib/gcc/f/malloc.h183
-rw-r--r--contrib/gcc/f/name.c242
-rw-r--r--contrib/gcc/f/name.h109
-rw-r--r--contrib/gcc/f/news.texi2330
-rw-r--r--contrib/gcc/f/news0.texi14
-rw-r--r--contrib/gcc/f/output.j28
-rw-r--r--contrib/gcc/f/parse.c95
-rw-r--r--contrib/gcc/f/proj.c68
-rw-r--r--contrib/gcc/f/proj.h83
-rw-r--r--contrib/gcc/f/rtl.j28
-rw-r--r--contrib/gcc/f/src.c445
-rw-r--r--contrib/gcc/f/src.h144
-rw-r--r--contrib/gcc/f/st.c554
-rw-r--r--contrib/gcc/f/st.h81
-rw-r--r--contrib/gcc/f/sta.c2000
-rw-r--r--contrib/gcc/f/sta.h117
-rw-r--r--contrib/gcc/f/stb.c25198
-rw-r--r--contrib/gcc/f/stb.h253
-rw-r--r--contrib/gcc/f/stc.c13898
-rw-r--r--contrib/gcc/f/stc.h360
-rw-r--r--contrib/gcc/f/std.c6905
-rw-r--r--contrib/gcc/f/std.h298
-rw-r--r--contrib/gcc/f/ste.c5419
-rw-r--r--contrib/gcc/f/ste.h168
-rw-r--r--contrib/gcc/f/storag.c573
-rw-r--r--contrib/gcc/f/storag.h167
-rw-r--r--contrib/gcc/f/stp.c59
-rw-r--r--contrib/gcc/f/stp.h508
-rw-r--r--contrib/gcc/f/str-1t.fin135
-rw-r--r--contrib/gcc/f/str-2t.fin60
-rw-r--r--contrib/gcc/f/str-fo.fin55
-rw-r--r--contrib/gcc/f/str-io.fin43
-rw-r--r--contrib/gcc/f/str-nq.fin55
-rw-r--r--contrib/gcc/f/str-op.fin57
-rw-r--r--contrib/gcc/f/str-ot.fin50
-rw-r--r--contrib/gcc/f/str.c217
-rw-r--r--contrib/gcc/f/str.h85
-rw-r--r--contrib/gcc/f/sts.c273
-rw-r--r--contrib/gcc/f/sts.h89
-rw-r--r--contrib/gcc/f/stt.c1044
-rw-r--r--contrib/gcc/f/stt.h230
-rw-r--r--contrib/gcc/f/stu.c1161
-rw-r--r--contrib/gcc/f/stu.h69
-rw-r--r--contrib/gcc/f/stv.c66
-rw-r--r--contrib/gcc/f/stv.h165
-rw-r--r--contrib/gcc/f/stw.c428
-rw-r--r--contrib/gcc/f/stw.h184
-rw-r--r--contrib/gcc/f/symbol.c1477
-rw-r--r--contrib/gcc/f/symbol.def654
-rw-r--r--contrib/gcc/f/symbol.h293
-rw-r--r--contrib/gcc/f/system.j27
-rw-r--r--contrib/gcc/f/target.c2564
-rw-r--r--contrib/gcc/f/target.h1865
-rw-r--r--contrib/gcc/f/tconfig.j27
-rw-r--r--contrib/gcc/f/tm.j27
-rw-r--r--contrib/gcc/f/top.c922
-rw-r--r--contrib/gcc/f/top.h264
-rw-r--r--contrib/gcc/f/toplev.j27
-rw-r--r--contrib/gcc/f/tree.j28
-rw-r--r--contrib/gcc/f/type.c107
-rw-r--r--contrib/gcc/f/type.h64
-rw-r--r--contrib/gcc/f/version.c1
-rw-r--r--contrib/gcc/f/version.h6
-rw-r--r--contrib/gcc/f/where.c542
-rw-r--r--contrib/gcc/f/where.h138
-rw-r--r--contrib/gcc/final.c1510
-rw-r--r--contrib/gcc/fix-header.c654
-rw-r--r--contrib/gcc/fixinc.ptx70
-rwxr-xr-xcontrib/gcc/fixinc.sco112
-rwxr-xr-xcontrib/gcc/fixinc.svr4133
-rwxr-xr-xcontrib/gcc/fixincludes779
-rwxr-xr-xcontrib/gcc/fixproto35
-rw-r--r--contrib/gcc/flags.h148
-rw-r--r--contrib/gcc/floatlib.c259
-rw-r--r--contrib/gcc/flow.c2517
-rw-r--r--contrib/gcc/fold-const.c2188
-rw-r--r--contrib/gcc/fp-test.c231
-rw-r--r--contrib/gcc/frame.c815
-rw-r--r--contrib/gcc/frame.h65
-rw-r--r--contrib/gcc/function.c1639
-rw-r--r--contrib/gcc/function.h61
-rw-r--r--contrib/gcc/future.options29
-rw-r--r--contrib/gcc/gansidecl.h91
-rw-r--r--contrib/gcc/gbl-ctors.h18
-rw-r--r--contrib/gcc/gcc.184
-rw-r--r--contrib/gcc/gcc.c2861
-rw-r--r--contrib/gcc/gcc.texi1906
-rw-r--r--contrib/gcc/gcov-io.h142
-rw-r--r--contrib/gcc/gcov.c1375
-rw-r--r--contrib/gcc/gcov.texi344
-rw-r--r--contrib/gcc/gcse.c4758
-rw-r--r--contrib/gcc/gen-protos.c218
-rw-r--r--contrib/gcc/genattr.c49
-rw-r--r--contrib/gcc/genattrtab.c687
-rw-r--r--contrib/gcc/gencheck.c82
-rw-r--r--contrib/gcc/gencodes.c36
-rw-r--r--contrib/gcc/genconfig.c46
-rw-r--r--contrib/gcc/genemit.c94
-rw-r--r--contrib/gcc/genextract.c69
-rw-r--r--contrib/gcc/genflags.c46
-rw-r--r--contrib/gcc/gengenrtl.c337
-rw-r--r--contrib/gcc/genopinit.c59
-rw-r--r--contrib/gcc/genoutput.c95
-rw-r--r--contrib/gcc/genpeep.c66
-rw-r--r--contrib/gcc/genrecog.c98
-rw-r--r--contrib/gcc/getopt.c397
-rw-r--r--contrib/gcc/getopt.h12
-rw-r--r--contrib/gcc/getopt1.c28
-rw-r--r--contrib/gcc/getpwd.c28
-rw-r--r--contrib/gcc/glimits.h7
-rw-r--r--contrib/gcc/global.c146
-rw-r--r--contrib/gcc/gmon.c21
-rw-r--r--contrib/gcc/gsyms.h12
-rw-r--r--contrib/gcc/gthr-dce.h150
-rw-r--r--contrib/gcc/gthr-posix.h147
-rw-r--r--contrib/gcc/gthr-single.h62
-rw-r--r--contrib/gcc/gthr-solaris.h177
-rw-r--r--contrib/gcc/gthr-vxworks.h132
-rw-r--r--contrib/gcc/gthr.h99
-rw-r--r--contrib/gcc/haifa-sched.c8738
-rw-r--r--contrib/gcc/halfpic.c17
-rw-r--r--contrib/gcc/halfpic.h26
-rw-r--r--contrib/gcc/hard-reg-set.h199
-rw-r--r--contrib/gcc/hash.c204
-rw-r--r--contrib/gcc/hash.h130
-rw-r--r--contrib/gcc/input.h4
-rw-r--r--contrib/gcc/integrate.c679
-rw-r--r--contrib/gcc/integrate.h12
-rw-r--r--contrib/gcc/invoke.texi2428
-rw-r--r--contrib/gcc/jump.c693
-rwxr-xr-xcontrib/gcc/just-fixinc2
-rw-r--r--contrib/gcc/libgcc1-test.c6
-rw-r--r--contrib/gcc/libgcc2.c2249
-rwxr-xr-xcontrib/gcc/listing6
-rw-r--r--contrib/gcc/local-alloc.c874
-rw-r--r--contrib/gcc/longlong.h683
-rw-r--r--contrib/gcc/loop.c2022
-rw-r--r--contrib/gcc/loop.h17
-rw-r--r--contrib/gcc/machmode.def10
-rw-r--r--contrib/gcc/machmode.h107
-rw-r--r--contrib/gcc/makefile.vms413
-rw-r--r--contrib/gcc/md.texi329
-rw-r--r--contrib/gcc/mips-tdump.c141
-rw-r--r--contrib/gcc/mips-tfile.c617
-rw-r--r--contrib/gcc/objc/Make-lang.in312
-rw-r--r--contrib/gcc/objc/Makefile.in91
-rw-r--r--contrib/gcc/objc/NXConstStr.h8
-rw-r--r--contrib/gcc/objc/NXConstStr.m8
-rw-r--r--contrib/gcc/objc/Object.h2
-rw-r--r--contrib/gcc/objc/Object.m10
-rw-r--r--contrib/gcc/objc/README2
-rw-r--r--contrib/gcc/objc/archive.c203
-rw-r--r--contrib/gcc/objc/class.c45
-rw-r--r--contrib/gcc/objc/config-lang.in37
-rw-r--r--contrib/gcc/objc/encoding.c27
-rw-r--r--contrib/gcc/objc/encoding.h4
-rw-r--r--contrib/gcc/objc/hash.c57
-rw-r--r--contrib/gcc/objc/hash.h6
-rw-r--r--contrib/gcc/objc/init.c535
-rw-r--r--contrib/gcc/objc/makefile.dos8
-rw-r--r--contrib/gcc/objc/misc.c130
-rw-r--r--contrib/gcc/objc/objc-act.c8455
-rw-r--r--contrib/gcc/objc/objc-act.h117
-rw-r--r--contrib/gcc/objc/objc-api.h147
-rw-r--r--contrib/gcc/objc/objc-tree.def37
-rw-r--r--contrib/gcc/objc/objc.gperf64
-rw-r--r--contrib/gcc/objc/objc.h12
-rw-r--r--contrib/gcc/objc/objects.c14
-rw-r--r--contrib/gcc/objc/runtime.h32
-rw-r--r--contrib/gcc/objc/sarray.c339
-rw-r--r--contrib/gcc/objc/sarray.h23
-rw-r--r--contrib/gcc/objc/selector.c191
-rw-r--r--contrib/gcc/objc/sendmsg.c301
-rw-r--r--contrib/gcc/objc/typedstream.h2
-rw-r--r--contrib/gcc/obstack.c198
-rw-r--r--contrib/gcc/obstack.h367
-rw-r--r--contrib/gcc/optabs.c591
-rw-r--r--contrib/gcc/output.h76
-rwxr-xr-xcontrib/gcc/patch-apollo-includes69
-rw-r--r--contrib/gcc/pexecute.c775
-rw-r--r--contrib/gcc/prefix.c331
-rw-r--r--contrib/gcc/print-rtl.c133
-rw-r--r--contrib/gcc/print-tree.c128
-rw-r--r--contrib/gcc/profile.c1702
-rw-r--r--contrib/gcc/protoize.c473
-rw-r--r--contrib/gcc/real.c923
-rw-r--r--contrib/gcc/real.h99
-rw-r--r--contrib/gcc/recog.c138
-rw-r--r--contrib/gcc/recog.h86
-rw-r--r--contrib/gcc/reg-stack.c617
-rw-r--r--contrib/gcc/regclass.c588
-rw-r--r--contrib/gcc/regmove.c1983
-rw-r--r--contrib/gcc/regs.h73
-rw-r--r--contrib/gcc/reload.c1345
-rw-r--r--contrib/gcc/reload.h39
-rw-r--r--contrib/gcc/reload1.c3002
-rw-r--r--contrib/gcc/reorg.c698
-rw-r--r--contrib/gcc/rtl.c120
-rw-r--r--contrib/gcc/rtl.def123
-rw-r--r--contrib/gcc/rtl.h827
-rw-r--r--contrib/gcc/rtl.texi118
-rw-r--r--contrib/gcc/rtlanal.c235
-rw-r--r--contrib/gcc/scan-decls.c32
-rw-r--r--contrib/gcc/scan.c19
-rw-r--r--contrib/gcc/scan.h16
-rw-r--r--contrib/gcc/sched.c1322
-rw-r--r--contrib/gcc/sdbout.c196
-rw-r--r--contrib/gcc/sdbout.h39
-rw-r--r--contrib/gcc/stab.def24
-rw-r--r--contrib/gcc/stmt.c2513
-rw-r--r--contrib/gcc/stor-layout.c288
-rw-r--r--contrib/gcc/stupid.c131
-rw-r--r--contrib/gcc/sys-protos.h21
-rw-r--r--contrib/gcc/sys-types.h1
-rw-r--r--contrib/gcc/system.h316
-rw-r--r--contrib/gcc/tlink.c633
-rw-r--r--contrib/gcc/tm.texi1547
-rw-r--r--contrib/gcc/toplev.c3094
-rw-r--r--contrib/gcc/toplev.h65
-rw-r--r--contrib/gcc/tree.c1539
-rw-r--r--contrib/gcc/tree.def391
-rw-r--r--contrib/gcc/tree.h1036
-rw-r--r--contrib/gcc/unprotoize.c1
-rw-r--r--contrib/gcc/unroll.c505
-rw-r--r--contrib/gcc/varasm.c1860
-rw-r--r--contrib/gcc/varray.c70
-rw-r--r--contrib/gcc/varray.h166
-rw-r--r--contrib/gcc/version.c2
-rw-r--r--contrib/gcc/xcoffout.c34
-rw-r--r--contrib/gcc/xcoffout.h48
641 files changed, 401398 insertions, 71366 deletions
diff --git a/contrib/gcc/BUGS b/contrib/gcc/BUGS
index dc023cf..33c9386 100644
--- a/contrib/gcc/BUGS
+++ b/contrib/gcc/BUGS
@@ -1,5 +1,5 @@
If you think you may have found a bug in GNU CC, please
-read the Bugs section of the Emacs manual for advice on
+read the Bugs section of the GCC manual for advice on
(1) how to tell when to report a bug,
(2) where to send your bug report, and
diff --git a/contrib/gcc/ChangeLog b/contrib/gcc/ChangeLog
index ffdc477..f1be44e 100644
--- a/contrib/gcc/ChangeLog
+++ b/contrib/gcc/ChangeLog
@@ -1,5890 +1,14111 @@
-Thu Aug 22 23:47:38 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+Sun Mar 14 02:38:07 PST 1999 Jeff Law (law@cygnus.com)
- * Version 2.7.2.3 released.
+ * egcs-1.1.2 Released.
-Wed Aug 13 08:28:18 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+Sun Mar 14 03:23:47 1999 Jeffrey A Law (law@cygnus.com)
- * INSTALL, install.texi: Update for m68k-*-linuxaout,
- m68k-*-linux-gnulibc1 and m68k-*-linux.
+ * README, gcc.1, gcc.texi, version.c: Update for egcs-1.1.2 release.
-1997-08-12 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+Thu Mar 11 14:00:58 1999 Richard Henderson <rth@cygnus.com>
- * config/m68k/t-linux: Define INSTALL_ASSERT_H and
- TARGET_LIBGCC2_CFLAGS.
- * config/m68k/t-linux-gnulibc1: New file.
+ * alpha.h (HARD_REGNO_MODE_OK): Disallow QI/HImode in fp regs.
+ (MODES_TIEABLE_P): Update.
- * configure: Don't use GNU setup for *-*-linux-gnu*.
- (m68k-*-linux*gnulibc1): New target.
- (m68k-*-linux*): Set $extra_parts correctly.
+Thu Mar 11 00:20:52 1999 Alexandre Oliva <oliva@dcc.unicamp.br>
- * config/m68k/linux.h (STRICT_ALIGNMENT): Define to zero.
- (CPP_SPEC, LIB_SPEC, LINK_SPEC): Add support for glibc 2.
- (LIBGCC_SPEC): Always link in -lgcc independent of -shared.
- (LIBCALL_VALUE): Use correct register for XFmode.
- (LEGITIMATE_PIC_OPERAND_P): Reject CONST_DOUBLE with MEM with
- invalid pic address.
- (FINALIZE_TRAMPOLINE, CLEAR_INSN_CACHE): New.
+ * gcc.texi: Update bug reporting instructions to match
+ current ezmlm list reality.
-Mon Mar 17 17:03:55 1997 J.T. Conklin <jtc@cygnus.com>
+Mon Mar 8 01:19:23 1999 Jeffrey A Law (law@cygnus.com)
- * m68k.md (beq0_di, bne0_di, bge0_di, blt0_di): Use cmpw #0
- instead of tstl when testing address registers on the 68000.
+ * version.c: Bump for prerelease.
-Fri Aug 8 08:15:55 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+Mon Mar 8 01:16:30 1999 Manfred Hollstein <manfred@s-direktnet.de>
+ Jeff Law <law@cygnus.com>
- * Makefile.in (INSTALL): Fix the rule.
- (stamp-crtS): Depend on stamp-crt for parallel make.
+ * configure.in (cpp_install_dir): Initialize from $enable_cpp
+ if that's looking like a pathname.
+ * configure: Rebuilt.
- * install1.texi: New.
+ * Makefile.in (install-cpp, uninstall-cpp): cpp_install_dir is an
+ absolute pathname, not a $prefix relative pathname.
-Mon Jul 21 22:47:13 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+Fri Mar 5 01:19:22 1999 Jeffrey A Law (law@cygnus.com)
- * configure (gxx_include_dir): Set it to $prefix/include/g++
- for Linux.
+ Thu Dec 17 18:21:49 1998 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>
+ * fixincludes (c_asm.h): Wrap Digital UNIX V4.0B DEC C specific
+ asm() etc. function declarations in __DECC.
-Tue Jun 24 11:24:56 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+Wed Mar 3 23:55:14 1999 Zack Weinberg <zack@rabi.columbia.edu>
- * INSTALL, install.texi: Refer Linux running libc 5.x.x as
- i386-*-linux-gnulibc1.
+ * cpp.in: New. Better cpp shell script.
+ * cpp.sh: Delete.
+ * Makefile.in (cpp.sh): Build from cpp.in
- * config/i386/linux.h, config.guess, config.sub, configure:
- Correct support for glibc 2.
+Tue Mar 2 01:27:52 1999 H.J. Lu (hjl@gnu.org)
- * config/t-linux: New, makefile fragment for Linux target with
- glibc 2.
+ * Makefile.in (cpp_install_dir, INSTALL_CPP, UNINSTALL_CPP): New
+ variables.
+ (install-cpp, uninstall-cpp): New targets.
+ (install-normal): Depend on $(INSTALL_CPP).
+ (uninstall): Depend on $(UNINSTALL_CPP).
+ * configure.in (cpp_install_dir): New, substitute.
+ (tmake_file): Added t-install-cpp for --enable-cpp.
+ * configure: Rebuilt.
+ * cpp.sh: New cpp script.
+ * config/t-install-cpp: New target fragment.
- * config/t-linux-gnulibc1: New, makefile fragment for Linux
- target with libc 5.x.x.
+Mon Mar 1 23:38:20 1999 Jeffrey A Law (law@cygnus.com)
- * config/t-linux-libc1: Removed.
+ Tue Feb 2 23:38:35 1999 David O'Brien <obrien@FreeBSD.org>
+ * i386/freebsd*.h now allows '$' in label names and does not use the
+ PCC struct return method.
- * config.sub: Add support for i686.
+ Wed Dec 30 23:00:28 1998 David O'Brien <obrien@NUXI.com>
+ * configure.in (FreeBSD ELF): Needs special crt files.
+ * configure: Rebuilt.
- * gcc.c (main): check and read ${libdir}/gcc-lib/specs to
- override the default specs.
+Sun Feb 28 14:47:53 1999 Arturo Montes <mitosys@colomsat.com.co>
-Mon Jun 23 22:48:00 1997 Jim Wilson <wilson@cygnus.com>
-
- * unroll.c (find_splittable_givs): Set splittable_regs_updates
- to biv_count for reduced givs.
+ * config/i386/t-sco5gas (crti.o): New target.
-Tue Apr 16 16:59:49 1996 Richard Henderson <rth@tamu.edu>
+Sun Feb 28 00:50:28 1999 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
+ Jeffrey A Law (law@cygnus.com)
- * function.c (expand_function_end): Allow TRAMPOLINE_TEMPLATE
- to be omitted on systems for which it is not cost effective.
- * varasm.c (assemble_trampoline_template): No such function
- if no TRAMPOLINE_TEMPLATE.
- * m68k.h: Greatly simplify the run-time trampoline code:
- (TRAMPOLINE_TEMPLATE, TRANSFER_FROM_TRAMPOLINE): Delete define.
- (TRAMPOLINE_SIZE, INITIALIZE_TRAMPOLINE): Changed.
- (TRAMPOLINE_ALIGN): No point aligning to cache line.
- (FINISH_INIT_TRAMPOLINE): New define.
- * m68k/next.h: Instead of redefining INITIALIZE_TRAMPOLINE,
- make use of the new FINISH_INIT_TRAMPOLINE.
- * m68k/{m68k.h,next.h} (FINISH_INIT_TRAMPOLINE):
- Rename to FINALIZE_TRAMPOLINE.
+ * cse.c (fold_rtx): Update comments for (const (minus (label) (label)))
+ case.
+ (cse_insn): Avoid creating a bogus REG_EQUAL note for
+ (const (minus (label) (label)))
+ (record_jump_cond): Fix mismatched paren in comment.
+
+Sat Feb 27 22:48:38 1999 H.J. Lu (hjl@gnu.org)
+ Jeffrey A Law (law@cygnus.com)
+
+ * frame.h: Update some comments.
+ * crtstuff.c (TARGET_ATTRIBUTE_WEAK): Define.
+ (__register_frame_info, __deregister_frame_info): Declare using
+ TARGET_WEAK_ATTRIBUTE.
+ (__do_global_dtors_aux): Check if __deregister_frame_info is
+ zero before calling it.
+ (__do_global_dtors): Likewise.
+ (frame_dummy): Check if __register_frame_info is zero before
+ calling it.
+ (__frame_dummy): Likewise.
+
+Sat Feb 27 19:47:39 1999 Marc Espie <espie@openbsd.org>
-Mon Apr 15 08:49:20 1996 Tom May (ftom@netcom.com)
+ * config/t-openbsd (T_CFLAGS): Add -Dmkstemps=my_mkstemps.
- * cse.c (invalidate_skipped_set): Ignore CLOBBER after calling
- note_mem_written, not before.
+Sat Feb 27 19:37:04 1999 Arturo Montes <mitosys@colomsat.com.co>
-Sat Jun 29 12:33:39 1996 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+ * i386/t-sco5 (crti.o): New target.
+ * i386/sco5.h (STARTFILE_SPEC): Include crti.o when
+ linking -shared.
+ * configure.in (i[34567]86-*-sco3.2v5*): Add crti.o.
+ * configure: Rebuilt.
- * Version 2.7.2.1 released.
+Sat Feb 27 19:29:46 1999 Toon Moene <toon@moene.indiv.nluug.nl>
+ Mark Mitchell <mark@markmitchell.com>
+ Jeffrey A Law (law@cygnus.com)
-Tue Jun 11 20:18:03 1996 Per Bothner <bothner@cygnus.com>
+ * alias.c (true_dependence): Only apply MEM_IN_STRUCT_P tests
+ when flag_structure_noalias is set.
+ * toplev.c (flag_structure_noalias): New variable.
+ (f_options): Add -fstructure-noalias.
+ * flags.h (flag_structure_noalias): Declare.
+ * invoke.texi: Update documentation.
- * fix-header.c (read_scna_file): Invoke FIXPROTO_INIT if defined.
- * alpha.h (FIXPROTO_INIT): Define new macro.
+Sat Feb 27 19:19:36 1999 Jeffrey A Law (law@cygnus.com)
-Fri May 10 18:35:00 1996 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * SERVICE: Update from the FSF.
- * loop.c (maybe_eliminate_biv_1): Disable all but two cases
- of biv elimination with givs and restrict those two cases to
- an ADD_VAL that is an address.
+Fri Feb 26 19:31:25 1999 Dave Love <fx@gnu.org>
-Mon Apr 22 16:50:19 1996 Jeremy Bettis <jeremy@hksys.com>
+ * md.texi, invoke.texi: Fix unterminated @xrefs.
- * objc/hash.c (hash_value_for_key): Prevent endless loop when 0 was
- stored in a hashtable.
+Fri Feb 26 01:47:46 1999 Jeffrey A Law (law@cygnus.com)
-Wed Apr 17 17:53:23 1996 Michael Meissner <meissner@tiktok.cygnus.com>
+ Sun Jan 17 03:20:47 1999 H.J. Lu (hjl@gnu.org)
+ * reg-stack.c (subst_stack_regs_pat): Abort if the destination
+ of a FP conditional move is not on the FP register stack.
- * rs6000.c (expand_block_move_mem): Copy RTX_UNCHANGING_P.
- (expand_block_move): Copy dest/src to registers using
- copy_addr_to_reg, call expand_block_move_mem to copy all of the
- bits.
+ * Makefile.in (compare, gnucompare): We do not care about
+ comparison failures for objc/linking.o either.
-Mon Apr 8 13:46:28 1996 Michael Meissner <meissner@tiktok.cygnus.com>
+Wed Feb 24 23:17:41 1999 Jeffrey A Law (law@cygnus.com)
- * rs6000.c (output_{prolog,epilog}): For V.4/eabi systems, change
- prologue and epilogue so that accesses beyond the current stack
- pointer are not done like they are for AIX.
+ Thu Feb 18 19:59:37 1999 Marc Espie <espie@cvs.openbsd.org>
+ * configure.in :Handle OpenBSD platforms.
+ * configure: Rebuilt.
+ * config/openbsd.h: New file.
+ * config/xm-openbsd.h: New file.
+ * config/t-openbsd: New file.
+ * config/t-openbsd-thread: New file.
-Fri Mar 26 05:43:06 1996 Torbjorn Granlund <tege@noisy.matematik.su.se>
+ Thu Feb 18 13:15:56 1999 Marc Espie <espie@cvs.openbsd.org>
+ * alpha/openbsd.h: New file.
+ * alpha/xm-openbsd.h: New file.
+ * sparc/openbsd.h: New file.
+ * sparc/xm-openbsd.h: New file.
+ * m68k/openbsd.h: New file.
+ * m68k/xm-openbsd.h: New file.
+ * i386/openbsd.h: New file, originally from netbsd.
+ * i386/xm-openbsd.h: New file.
- * vax.md (insv matcher): Call CC_STATUS_INIT.
- * vax.h (NOTICE_UPDATE_CC): Handle ZERO_EXTRACT destination.
+ Wed Nov 19 12:56:54 1997 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+ * configure.in: Fix check for <inttypes.h>.
+ * configure: Rebuilt.
-Sat Mar 23 18:25:39 1996 J"orn Rennecke (amylaar@meolyon.hanse.de)
+ * varasm.c (declare_weak): If HANDLE_PRAGMA_WEAK, call
+ handle_pragma_weak.
+
+Wed Feb 24 03:17:56 1999 Jeffrey A Law (law@cygnus.com)
- * c-typeck.c (set_init_index): Check for use outside an array
- initializer.
+ * version.c: Bump for prerelease.
-Sat Mar 23 09:21:40 1996 Doug Evans <dje@canuck.cygnus.com>
+ * Makefile.in (compare, gnucompare): Ignore comparison failures
+ for some objects in the ObjC runtime.
- * sparc/sparc.h (CONDITIONAL_REGISTER_USAGE): Don't unfix %g[234]
- if fixed with -ffixed-.
+Wed Feb 24 02:39:08 1999 Jeffrey A Law (law@cygnus.com)
-Wed Mar 13 20:36:10 1996 Jim Wilson <wilson@chestnut.cygnus.com>
+ Mon Dec 7 16:15:51 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+ * sh.c (output_far_jump): Emit braf only for TARGET_SH2.
- * mips.c (mips_expand_prologue): Change TYPE_NEEDS_CONSTRUCTING to
- TREE_ADDRESSABLE;
- * pa.h (ASM_DECLARE_FUNCTION_NAME): Likewise.
+ Mon Nov 23 16:46:46 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+ * va-sh.h (__va_arg_sh1): Use __asm instead of asm.
-Tue Mar 12 14:36:02 1996 Jason Merrill <jason@yorick.cygnus.com>
+Tue Feb 23 00:38:17 1999 Jeffrey A Law (law@cygnus.com)
- * lex.c (real_yylex): Warn about using the `namespace' keyword.
+ Thu Sep 3 00:23:21 1998 Richard Henderson <rth@cygnus.com>
+ * ginclude/va-alpha.h: Protect entire second portion of the
+ file against double inclusion.
-Tue Feb 27 08:18:12 1996 Richard Earnshaw (rearnsha@armltd.co.uk)
+ Mon Aug 31 13:57:55 1998 Richard Henderson <rth@cygnus.com>
+ * alpha/va_list.h: New file.
+ * alpha/x-alpha (EXTRA_HEADERS): New. Add va_list.h.
- * arm.md (mov{si,sf,df}cc and matchers): All conditional move
- patterns must have a mode.
+ Sat Aug 1 17:59:30 1998 Richard Henderson <rth@cygnus.com>
+ * ginclude/va-alpha.h (va_list): Use a typedef, not a define.
-Mon Feb 19 07:35:07 1996 Torbjorn Granlund <tege@tmg.se>
+Sun Feb 21 20:35:10 1999 Jeffrey A Law (law@cygnus.com)
- * rs6000.md (not:SI with assign and compare): Fix typo.
+ Wed Oct 28 22:58:35 1998 Jason Merrill <jason@yorick.cygnus.com>
+ * tree.c (append_random_chars): New fn.
+ (get_file_function_name_long): Use it.
-Wed Jan 24 18:00:12 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+ Thu Aug 13 17:08:11 1998 Jason Merrill <jason@yorick.cygnus.com>
+ * tree.c (get_file_function_name_long): Split out...
+ (get_file_function_name): ...from here.
- * alpha.c (alpha_write_verstamp): Only emit MS_STAMP and LS_STAMP,
- not the extra numbers.
+ * config/aoutos.h (ASM_OUTPUT_CONSTRUCTOR): Delete.
+ (ASM_OUTPUT_DESTRUCTOR, ASM_OUTPUT_GC_ENTRY): Likewise.
+ * tm.texi: Update docs for constructors and destructors.
-Wed Jan 17 21:22:40 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+Tue Feb 16 21:02:07 1999 Anton Hartl <toni@devsoft.com>
- * cp/decl2.c (grokfield): Call cplus_decl_attributes with the attrlist.
- Pass a null tree to grokdeclarator for its ATTRLIST arg, since it's
- only ever used for functions in it.
+ * rs6000.md (call_value): Fix typo.
-Tue Jan 16 06:01:28 1996 Thomas Graichen <graichen@omega.physik.fu-berlin.de>
+Tue Feb 16 01:37:33 1999 Charles G Waldman <cgw@alum.mit.edu>
- * i386/freebsd.h (ASM_WEAKEN_LABEL): Deleted; not supported.
+ * c-common.c (shorten_compare): Get the min/max value from the
+ underlying type of an enumeration, not the enumerated type itself.
-Sun Jan 7 17:11:11 1996 David Edelsohn <edelsohn@mhpcc.edu>
+Mon Feb 15 11:33:51 1999 Jeffrey A Law (law@cygnus.com)
- * collect2.c (scan_libraries): Correct Import File ID interpretation.
+ Sat Jan 16 21:48:17 1999 Marc Espie (Marc.Espie@openbsd.org)
+ * gcc.c: (do_spec_1): Fix obvious typo.
-Thu Dec 28 22:24:53 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+ * jump.c: Include insn-attr.h.
+ (delete_computation): If reload has completed and insn scheduling
+ after reload is enabled, then do not depend on REG_DEAD notes.
+ * Makefile.in (jump.o): Depend on insn-attr.h.
- * rs6000.md (common mode functions): Add condition reg clobbers.
+ * sparc.c (output_scc_insn): Add missing argument to output_cbranch.
-Tue Dec 19 15:08:31 1995 Jason Merrill <jason@yorick.cygnus.com>
+ * loop.c (mark_loop_jump): Handle LO_SUM. If we encounter something
+ we do not understand, mark the loop and containing loops as invalid.
- * collect2.c: Remove auto_export functionality.
+Sun Feb 14 23:05:34 1999 Jeffrey A Law (law@cygnus.com)
-Mon Dec 18 18:40:34 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ Tue Feb 9 21:14:03 1999 J"orn Rennecke <amylaar@cygnus.co.uk>
+ * alias.c (init_alias_analysis): Avoid self-referential value
+ when setting reg_known_value from REG_EQUAL notes.
- * svr4.h (ASM_IDENTIFY_GCC): Don't output stab here.
- (ASM_IDENTIFY_GCC_AFTER_SOURCE): Output stab here instead of
- above.
+ Mon Aug 17 02:03:55 1998 Richard Henderson <rth@cygnus.com>
+ * regclass.c (allocate_reg_info): Respect MIN when clearing data.
-Sat Dec 16 07:03:33 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ * loop.c (scan_loop): Fix typo in last change.
- * stor-layout.c (layout_record): When PCC_BITFIELD_TYPE_MATTERS,
- compute bitpos using field_size % type_align instead of field_size.
+Sat Feb 13 11:53:12 1999 Jeffrey A Law (law@cygnus.com)
-Fri Dec 15 18:41:50 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ 1999-02-05 Michael Meissner <meissner@cygnus.com>
+ J"orn Rennecke <amylaar@cygnus.co.uk>
+ * loop.c (check_dbra_loop): A store using an address giv for which
+ we have no life information is not reversible.
+ * loop.c (first_loop_store_insn): New file-scope variable.
+ (prescan_loop): Set it.
+ (check_dbra_loop): Check if a store depends on a register
+ that is set after the store.
- * fixincludes (sys/wait.h): Add forward declaration of struct rusage
- on AIX 3.2.5.
+ Sun Jan 31 13:22:02 1999 John Wehle (john@feith.com)
+ * i386.md (movsicc, movhicc, movsfcc, movdfcc,
+ movxfcc, movdicc): Delete unconstrained alternatives.
+ * i386.c (output_fp_conditional_move,
+ output_int_conditional_move): Delete unused case.
-Sat Dec 9 18:05:03 1995 Jim Wilson <wilson@cygnus.com>
+ Tue Aug 18 10:33:30 1998 Jeffrey A Law (law@cygnus.com)
+ * expr.c (emit_block_move): Do not call memcpy as a libcall
+ instead build up a CALL_EXPR and call it like any other
+ function.
+ (clear_storage): Similarly for memset.
- * expr.c (expand_expr, case INDIRECT_REF): Correct typo in May 8
- change.
+ Sun Sep 20 20:57:02 1998 Robert Lipe <robertl@dgii.com>
+ * configure.in (i*86-*-sysv5*): Use fixinc.svr4 to patch byteorder
+ problems.
+ * configure: Regenerate.
-Sun Nov 26 14:47:42 1995 Richard Kenner <kenner@mole.gnu.ai.mit.edu>
+Fri Feb 12 23:20:54 1999 Michael P. Hayes <michaelh@ongaonga.chch.cri.nz>
- * Version 2.7.2 released.
+ * loop.c (scan_loop): Call reg_in_basic_block_p before
+ loop_reg_used_before_p.
- * function.c (fixup_var_refs_1): Make pseudo for DEST
- in PROMOTED_MODE unless in a SUBREG.
+Thu Feb 11 01:53:10 1999 Jeffrey A Law (law@cygnus.com)
- * cse.c (insert): Don't put a REG into qty_const.
+ Wed Nov 18 22:13:00 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+ * expr.c (store_expr): Don't generate load-store pair
+ if TEMP is identical (according to ==) with TARGET.
- * msdos/top.sed: Change version to 2.7.2.
- * winnt/config-nt.sed: Likewise.
+Thu Feb 11 01:06:49 1999 Nathan Sidwell <nathan@acm.org>
-Sun Nov 26 14:41:49 1995 Douglas Rupp (drupp@cs.washington.edu)
+ * fold-const.c (range_binop): Take account of the bounded nature
+ of fixed length arithmetic when comparing unbounded ranges.
- * Makefile.in (stamp-objlist): Change .o to $objext.
+Wed Feb 10 11:03:22 1999 Richard Henderson <rth@cygnus.com>
- * alpha/win-nt.h (CPP_PREDEFINES): Set __unaligned and __stdcall
- to null.
- (ASM_SPEC): Add a translation for -g to -Zi.
- * winnt/ld.c (main): Don't pass -g to link.
- * winnt/oldnames.c: Reformat and add some new functions for gnat1.
- * winnt/win-nt.h (LINK_SPEC): Pass -g to ld.exe.
- Increase default stack size.
- * configure ({alpha-dec,i386-ibm}-winnt3.5): Add oldnames.o
- to extra_objs.
- * libgcc2.c (trampoline): Add getpagesize and mprotect for WINNT.
-
-Sun Nov 26 14:25:26 1995 Uwe Seimet (seimet@chemie.uni-kl.de)
+ * configure.in (alphaev6*): Fix typo in target_cpu_default2.
- * atari.h (FUNCTION_VALUE): Deleted; incorrect.
+Tue Feb 9 00:00:14 1999 Mark Kettenis <kettenis@gnu.org>
-Sun Nov 26 14:23:03 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ * configure.in (i[34567]86-*gnu*): Set float_format to i386.
+ * configure: Rebuilt.
- * fixincludes (curses.h): Allow space or tab after bool keyword,
- instead of tab or tab.
+Sat Feb 6 16:03:36 1999 Jeffrey A Law (law@cygnus.com)
-Sun Nov 26 14:14:11 1995 Oliver Kellogg (oliver.kellogg@space.otn.dasa.de)
+ * invoke.texi, expr.c: Update email addresses.
- * 1750a.md (pattern for HImode PSHM): Corrected.
- (trunchiqi2, zero_extendqihi2, extendhftqf2): Corrected.
- (pattern for movhi of CONST_INT to REG): Corrected.
- (divmodqi pattern for DISN): Corrected.
- (all shift patterns): Corrected.
+ * gcc.c, gcc.texi: Update email addresses.
- * 1750a.h (REG_OK_FOR_INDEX_P, REG_OK_FOR_BASE_P): Corrected.
- (ASM_OUTPUT_[datatype]): Corrected datalbl[].size computation
- for output of arrays.
+Sat Jan 30 05:27:25 1999 Jeffrey A Law (law@cygnus.com)
-Sun Nov 26 14:08:57 1995 Dave Love <d.love@dl.ac.uk>
+ Thu Jan 21 01:59:30 1999 Richard Henderson <rth@cygnus.com>
+ * explow.c (allocate_dynamic_stack_space): Use register_operand
+ instead of arith_operand, which does not exist.
- * mips/iris5.h (NO_IMPLICIT_EXTERN_C): Define this again so
- that unistd.h doesn't get badly `fixed' for C++. libg++ will now
- build with this definition.
+Thu Jan 28 09:44:04 1999 Jeffrey A Law (law@cygnus.com)
-Sun Nov 26 14:02:43 1995 Robert E. Brown (brown@grettir.bibliotech.com)
+ * configure.in (hppa1.0-hp-hpux10*): Use t-pa.
+ * configure: Rebuilt.
- * configure: Better workaround for Nextstep bug.
+Thu Jan 21 23:27:06 1999 Jeffrey A Law (law@cygnus.com)
-Sun Nov 26 13:55:07 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+ * m68k.md (ashldi_const): Disable for !TARGET_5200. Fix indention.
+ (ashldi3 expander): Similarly. Update comments.
+ (ashrdi_const, lshrdi_const): Fix indention.
+ (ashrdi3, lshrdi3): FIx indention. Update comments.
- * rs6000.md (load_multiple matcher): Fix typo in opcode.
+Thu Jan 21 20:33:31 1999 Richard Henderson <rth@cygnus.com>
-Sun Nov 26 13:51:08 1995 Lee Iverson <leei@Canada.AI.SRI.COM>
+ * rs6000.h (LEGITIMIZE_RELOAD_ADDRESS): Recognize and accept
+ transformations that we have performed earlier.
+ * alpha.h (LEGITIMIZE_RELOAD_ADDRESS): Likewise.
- * final.c (final_start_function): Move call to sdbout_begin_function
- back to final_scan_insn on MIPS systems so parameter descriptions are
- recognized.
+Sun Jan 17 20:39:20 1999 Richard Henderson <rth@cygnus.com>
-Sun Nov 26 13:43:06 1995 DJ Delorie (dj@delorie.co)m
+ * jump.c (rtx_renumbered_equal_p): Special case CODE_LABEL.
- * msdos/top.sed: Don't insert "go32".
+Sun Jan 17 19:01:47 1999 Jeffrey A Law (law@cygnus.com)
-Sun Nov 26 12:08:23 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * i386.md (integer conditional moves): Add missing earlyclobbers.
- * combine.c (nonzero_bits, case REG): Put POINTERS_EXTEND_UNSIGNED
- code before stack pointer code. Return nonzero at end of stack
- pointer code.
+ * regmove.c (optimize_reg_copy_1): Undo Aug 18 change. Update
+ REG_N_CALLS_CROSSED and REG_LIVE_LENGH if and only if we change
+ where a register is live.
- * sparc.h (PRINT_OPERAND_ADDRESS): Handle CONST inside PLUS.
+Fri Jan 15 01:19:42 1999 Jeffrey A Law (law@cygnus.com)
- * Makefile.in (cppalloc.o): Add a rule to build it.
+ * unroll.c (find_splittable_givs): For a DEST_ADDR giv, do not share
+ a register with another DEST_ADDR giv if the address is not valid.
- * alpha.c (alpha_emit_set_const): Don't output SImode sequences
- that rely on invisible overflow. Sign extend new when SImode.
- Don't recur if new == c. Don't allow shift outside mode. Make
- logical right shift be unsigned.
+ * h8300.h (ASM_OUTPUT_LABELREF): Use asm_fprintf, not fprintf.
-Sun Nov 26 11:37:50 1995 Arne H. Juul (arnej@idt.unit.no)
+Mon Jan 11 20:23:34 1999 Richard Henderson <rth@cygnus.com>
- * Makefile.in (compare*): Add "|| true" to avoid spurious
- failure messages from some versions of make.
+ * sparc.c (legitimize_pic_address): Treat labels like symbols.
+ (emit_move_sequence): Likewise.
+ * sparc.h (PRINT_OPERAND_ADDRESS): Likewise.
+ (ASM_OUTPUT_ADDR_VEC_ELT): Don't special case CM_MEDLOW.
+ (ASM_OUTPUT_ADDR_DIFF_ELT): Likewise. Don't reference magic `1b'.
+ * sparc.md (move_pic_label_si): Kill.
+ (move_label_di): Kill.
+ (pic_tablejump_32, pic_tablejump_64): Kill.
+ (tablejump): Expose pic arithmetic to the compiler.
-Sun Nov 26 11:20:09 1995 Dmitry K. Butskoy (buc@stu.spb.su)
+Thu Jan 7 00:33:33 1999 Bernd Schmidt <crux@ohara.Informatik.RWTH-Aachen.DE>
- * expr.c (truthvalue_conversion): Add declaration.
+ * combine.c (num_sign_bit_copies): In NEG, MULT, DIV and MOD cases,
+ when a test can't be performed due to limited width of
+ HOST_BITS_PER_WIDE_INT, use the more conservative approximation.
+ Fix UDIV case for cases where the first operand has the highest bit
+ set.
-Sun Nov 12 18:09:35 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Wed Jan 6 23:37:47 1999 Jeffrey A Law (law@cygnus.com)
- * Version 2.7.1 released.
+ * h8300.h (ASM_OUTPUT_LABELREF): Define.
- * function.c (put_reg_into_stack): New arg volatile_p.
- (put_var_into_stack): Call with new arg.
+Wed Jan 6 02:23:36 1999 "Charles M. Hannum" <root@ihack.net>
-Sat Nov 11 08:25:34 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * expr.c (store_expr): If the lhs is a memory location pointed
+ to be a postincremented (or postdecremented) pointer, always
+ force the rhs to be evaluated into a pseudo.
- * reload.c (output.h): Include it.
- * Makefile.in (reload.o): Add dependence on output.h.
+Fri Jan 1 11:48:20 1999 Jeffrey A Law (law@cygnus.com)
-Thu Nov 9 11:24:20 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * i386.md (doubleword shifts): Fix dumb mistakes in previous change.
- * mips.h (HARD_REGNO_NREGS): If FP_REG_P, always use UNITS_PER_FPREG
- to calculate number of words needed.
+Wed Dec 30 23:44:11 1998 Jeffrey A Law (law@cygnus.com)
-Thu Nov 9 11:04:50 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de)
+ * m68k.md (adddi_dilshr32): Allow all operands to be registers too.
+ (adddi_dishl32): Similarly.
- * 1750a.md (cmphf): Addd Base Reg with Offset address mode (LB,STB,..)
- (movqi,movhi,movhf,addqi3,addhf3,subqi3,subhf3,mulqihi3): Likewise.
- (mulhf3,divhf3,andqi3,iorqi3): Likewise.
- (define_peephole): Remove the Base mode peepholes. Replace the
- special addqi define_insn for "LIM Ra,sym,Rb" by a define_peephole.
- (ashlqi3): Took out futile 0th alternative.
- (lshrqi3, lshrhi3, ashrqi3, ahsrhi3): Correct case of non-constant
- shift count.
+ * cse.c (invalidate_skipped_block): Call invalidate_from_clobbers
+ for each insn in the skipped block.
- * 1750a.h (REG_ALLOC_ORDER): Define.
- (REGNO_OK_FOR_BASE_P): Include stack pointer in test against
- reg_renumber[REGNO].
- (ASM_OUTPUT_DESTRUCTOR): Remove bogus assembler comment.
+ * i386.md (doubleword shifts): Avoid namespace pollution.
-Thu Nov 9 11:01:33 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Mon Dec 28 10:44:40 1998 Richard Henderson <rth@cygnus.com>
- * expr.c (expand_expr, case ARRAY_REF): Properly convert types
- of index, size, and multiplication.
+ * combine.c (subst): Process the inputs to a parallel asm_operands
+ only once.
-Wed Nov 8 09:00:22 1995 Richard Earnshaw (rearnsha@armltd.co.uk)
+Sun Dec 13 00:09:47 1998 Jeffrey A Law (law@cygnus.com)
- * arm.md (mov*cc_{,soft_}insn): Use match_operator to test the
- comparison and check that the condition code register is used.
+ * i386/next.h (ASM_OUTPUT_ALIGN): Use 0x90 for fill character.
-Wed Nov 8 08:49:35 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+ * h8300.c (h8300_encode_label): Use '&' for tiny data items.
+ * h8300.h (TINY_DATA_NAME_P): Likewise.
+ (STRIP_NAME_ENCODING): Handle '&'.
- * rs6000/sysv4.h (ASM_OUTPUT_{CONSTRUCTOR,DESTRUCTOR}): Undef before
- including svr4.h.
+Wed Dec 2 01:44:58 1998 Jeffrey A Law (law@cygnus.com)
-Tue Nov 7 10:58:12 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+ * egcs-1.1.1 released.
- * m68k.md (subxf3): Properly name pattern.
+Mon Nov 23 20:28:02 1998 Mike Stump <mrs@wrs.com>
-Tue Nov 7 10:53:09 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+ * libgcc2.c (top_elt): Remove top_elt, it isn't thread safe.
+ The strategy we now use is to pre allocate the top_elt along
+ with the EH context so that each thread has its own top_elt.
+ This is necessary as the dynmanic cleanup chain is used on the
+ top element of the stack and each thread MUST have its own.
+ (new_eh_context): Likewise.
+ (__sjthrow): Likewise.
- * libgcc2.c (__{C,D}TOR_LIST): For AIX, initialize these arrays to
- 0,0, just like NeXT to avoid a warning message from the AIX 4.1
- linker.
+Mon Nov 23 09:53:44 1998 Richard Henderson <rth@cygnus.com>
-Tue Nov 7 09:58:34 1995 John F. Carr <jfc@mit.edu>
+ * local-alloc.c (local_alloc): Use malloc not alloca for
+ reg_qty, reg_offset, ref_next_in_qty.
- * cppexp.c (cpp_lex): Correctly parse character constants.
+Mon Nov 23 09:49:49 1998 Andrew MacLeod <amacleod@cygnus.com>
-Tue Nov 7 09:52:15 1995 Jason Merrill <jason@yorick.cygnus.com>
+ * cplus-dem.c (demangle_prefix): Use the last "__"
+ in the mangled name when looking for the signature. This allows
+ template names to begin with "__".
- * rs6000.h (ASM_OUTPUT_{DES,CONS}TRUCTOR): Define.
+Mon Nov 23 09:40:41 1998 David Edelsohn <edelsohn@mhpcc.edu>
-Mon Nov 6 10:27:15 1995 Doug Evans <dje@cygnus.com>
+ * rs6000.h (LEGITIMIZE_ADDRESS): Add missing "goto WIN".
- * combine.c (force_to_mode): Fix typo.
+Mon Nov 9 23:29:39 1998 David Edelsohn <edelsohn@mhpcc.edu>
-Sun Nov 5 18:37:02 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+ * rs6000.md (floatunssidf2_internal splitter): Use base register
+ operand, not hard-coded SP.
- * m68k.md (cmpxf): Don't call force_const_mem, it looses for PIC;
- get predicates right instead. Get rid of separate DEFINE_EXPAND.
- (addxf3, subxf3, mulxf3, divxf3): Likewise.
- (All XFmode patterns): Delete `F' and `G' constraints.
- (absxf2, negxf2): Delete spurious condition on TARGET_FPA.
+Mon Nov 9 23:05:51 1998 Richard Earnshaw (rearnsha@arm.com)
-Sun Nov 5 11:05:44 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ Restore ABI compatibility for NetBSD.
+ * arm/netbsd.h (DEFAULT_PCC_STRUCT_RETURN): Override setting in
+ arm.h
+ (RETURN_IN_MEMORY): Likewise.
- * fixincludes (malloc.h): Fix return type of {m,re}alloc.
+ * arm.c (add_constant): When taking the address of an item in the
+ pool, get the mode of the item addressed.
-Sun Nov 5 11:02:26 1995 J"orn Rennecke (amylaar@meolyon.hanse.de)
+ * arm.c (final_prescan_insn, case INSN): If an insn doesn't
+ contain a SET or a PARALLEL, don't consider it for conditional
+ execution.
- * cse.c (invalidate): For a pseudo register, do a loop to
- invalidate all table entries, irrespective of mode.
+Mon Nov 9 22:43:57 1998 Jean-Pierre Radley <jpr@jpr.com>
-Sun Nov 5 10:57:43 1995 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+ * fixinc.sco: Paramaterize #include_next values.
+ * fixinc/fixinc.sco: Likewise.
- * combine.c (force_to_mode): Put in last change properly.
+Mon Nov 9 22:43:57 1998 Robert Lipe <robertl@dgii.com>
-Sun Nov 5 10:53:49 1995 Jeffrey A Law (law@cygnus.com)
+ * fixinc.sco: Borrow code to wrap 'bool' typedefs from tinfo.h
+ and term.h from fixinc.wrap.
- * pa.h (CONDITIONAL_REGISTER_USAGE): Make sure FP regs
- get disabled regardless of PA1.0 vs PA1.1 code generation
- when TARGET_SOFT_FLOAT or TARGET_DISABLE_FPREGS is on.
+Thu Nov 5 07:57:45 EST 1998 Andrew MacLeod <amacleod@cygnus.com>
-Sun Nov 5 10:49:43 1995 Doug Evans <dje@lisa.cygnus.com>
+ * except.c (expand_fixup_region_end): Make sure outer context labels
+ are not issued in an inner context during cleanups.
- * i960.c (emit_move_sequence): Add a scratch register to
- multi-reg stores.
- (i960_output_move_{double,quad}): New functions.
- (i960_print_operand): Handle new operand types E, F.
- * i960.md (movdi matchers): Rewrite.
- (store_unaligned_di_reg): New pattern.
- (movti matchers): Rewrite.
- (store_unaligned_ti_reg): New pattern.
-
-Sun Nov 5 10:45:24 1995 Ian Lance Taylor (ian@cygnus.com)
+Sun Nov 1 11:04:32 1998 Jeffrey A Law (law@cygnus.com)
- * mips.h (MULTILIB_DEFAULTS): Define.
- * mips/elf64.h, mips/iris6.h (MULTILIB_DEFAULTS): Define.
+ * i386/linux.h (CPP_PREDEFINES): Bring back -Di386 for the last time.
-Sun Nov 5 10:41:48 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * From Christian Gafton:
+ * i386/linux.h (CPP_PREDEFINES): Add -D__i386__.
+ * sparc/linux.h (CPP_PREDEFINES): Add -D__sparc__.
+ * sparc/linux64.h (CPP_PREDEFIENS): Add -D__sparc__.
- * reload.c (push_reload): Delete abort for RELOAD_OTHER case added
- in last change.
- * reload1.c (emit_reload_insns): For RELOAD_OTHER output reloads,
- output the reload insns in descending order of reloads.
-
- * sh.md (mulsidi3-1, mulsidi3, umulsidi3-1, umulsidi3): Enable.
- (smulsi3_highpart-1, smulsi3_highpart): New patterns.
- (umulsi3_highpart-1, umulsi3_highpart): Likewise.
- (movdi-1): Add r/x constraint.
- * t-sh (MULTILIB_OPTIONS): Add m2.
- (MULTILIB_DIRNAMES): Add m2.
- (MULTILIB_MATCHES): Define.
+Sat Oct 31 00:40:05 1998 Jeffrey A Law (law@cygnus.com)
- * sparc.h (RTX_COSTS, case MULT): Check for TARGET_SPARCLITE.
+ * jump.c (jump_optimize): Initialize mappings from INSN_UID to
+ EH region if exceptions are enabled and we're performing cross
+ jump optimizations.
+ (find_cross_jump): Exit loop if the insns are in different EH regions.
- * abi64.h, elf64.h (CPP_SPEC): Add -EB and -EL support.
+Fri Oct 30 00:54:25 1998 Peter Jakubek <pjak@snafu.de>
-Sat Nov 4 10:36:26 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * m68k.h (INDIRECTABLE_1_ADDRESS_P): Fix thinko.
- * sh.md (casesi_worker): Change constraint from = to +.
+Thu Oct 29 12:14:58 1998 Jason Merrill <jason@yorick.cygnus.com>
- * svr4.h (ASM_IDENTIFY_GCC_AFTER_SOURCE): Delete.
- (ASM_IDENTIFY_GCC): Output stab here.
+ * alpha/linux.h (CPP_PREDEFINES): Add missing space.
-Sat Nov 4 10:32:37 1995 John Carr <jfc@mit.edu>
+Tue Oct 27 16:11:43 1998 David Edelsohn <edelsohn@mhpcc.edu>
- * cpplib.c (finclude): Set current input pointer when input
- is not a regular file.
+ * collect2.c (aix64_flag): New variable.
+ (main, case 'b'): Parse it.
+ (GCC_CHECK_HDR): object magic number must match mode.
+ (scan_prog_file): Only check for shared object if valid header.
+ Print debugging if header/mode mismatch.
+ * README.RS6000: Update.
- * cppmain.c: Define progname, required by cpplib.
+Sun Oct 25 23:36:52 1998 Jason Merrill <jason@yorick.cygnus.com>
-Sun Oct 29 07:48:36 1995 Michael Meissner <meissner@cygnus.com>
+ * stmt.c (expand_fixup): Set fixup->before_jump to a
+ NOTE_INSN_DELETED instead of a NOTE_INSN_BLOCK_BEG.
- * xcoffout.h (DBX_FINISH_SYMBOL): Deal with names created via
- the __asm__ construct that start with a leading '*'.
- * xcoffout.c (xcoff_declare_function): Likewise.
+Sun Oct 25 18:35:06 1998 David Edelsohn <edelsohn@mhpcc.edu>
-Sun Oct 29 07:45:41 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * ginclude/va-ppc.h (va_arg): longlong types in overflow area are
+ not doubleword aligned.
- * stupid.c (stupid_mark_refs): Handle SUBREG of pseudo-reg in a
- SET_DEST same as we handle a pseudo-reg in a SET_DEST.
+Sun Oct 25 12:07:00 1998 Mumit Khan <khan@xraylith.wisc.edu>
-Sun Oct 29 07:43:15 1995 Pat Rankin <rankin@eql.caltech.edu>
+ * i386/crtdll.h (CPP_PREDEFINES): Fix typo.
+ * i386/mingw32.h (CPP_PREDEFINES): Likewise.
- * libgcc2.c (L_eh: __unwind_function): Implement for VAX.
- * vax.h (RETURN_ADDRESS_OFFSET, RETURN_ADDR_RTX): Define.
+Fri Oct 23 22:41:40 1998 David Edelsohn <edelsohn@mhpcc.edu>
-Sun Oct 29 12:39:08 1995 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>a
+ * rs6000.md (movsf): Disable explicit secondary-reload-like
+ functionality if TARGET_POWERPC64.
+ (movdf): Remove TARGET_POWERPC64 explicit secondary-reload-like
+ functionality.
- * i386/sol2.h (CPP_PREDEFINES): Add -D__SVR4.
+Fri Oct 23 22:38:57 1998 Jeffrey A Law (law@cygnus.com)
-Sun Oct 29 07:14:36 1995 J"orn Rennecke (amylaar@meolyon.hanse.de)
+ * m68k.md (5200 movqi): Do not allow byte sized memory references
+ using address regs.
+ * m68k.c (output_move_qimode): Do not use byte sized operations on
+ address registers.
- * reload.c (find_equiv_reg): Check for nonsaving setjmp.
+Fri Oct 23 00:56:11 1998 Jason Merrill <jason@yorick.cygnus.com>
-Fri Oct 27 15:15:56 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * expr.c (pending_chain): Move up.
+ (save_expr_status): Do save pending_chain.
+ (restore_expr_status): And restore it.
+ * function.h (struct function): Add pending_chain.
- * Makefile.in (out_object_file): Depend on TREE_H.
+Mon Oct 19 13:22:13 1998 Geoff Keating <geoffk@ozemail.com.au>
-Fri Oct 27 06:42:36 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * loop.c (scan_loop): Be more selective about what invariants are
+ moved out of a loop.
- * alpha.c (call_operand): Only allow reg 27 on NT too.
- * alpha.md (call_value_nt, call_nt): Force non-SYMBOL_REF
- into reg 27, just like for OSF.
+Wed Oct 14 23:27:08 1998 Didier FORT (didier.fort@fedex.com)
- * rs6000.c (struct asm_option): Changed from struct option.
- (expand_block_move_mem): Remove erroneously-added line.
+ * fixincludes: Fix up rpc/{clnt,svr,xdr}.h for SunOS.
- * expr.c (clear_storage): SIZE is now rtx, not int.
- (store_constructor): Call clear_storage with rtx.
- (get_inner_reference): Convert index to precision of
- sizetype, not POINTER_SIZE.
- (expand_expr, case ARRAY_REF): Likewise.
- * expr.h (clear_storage): Second arg is rtx, not int.
+Wed Oct 14 22:13:28 1998 Joel Sherrill (joel@OARcorp.com)
-Fri Oct 27 05:45:58 1995 J"orn Rennecke (amylaar@meolyon.hanse.de)
+ * Makefile.in (stmp-fixinc): Do not install assert.h if not desired.
+ * config/t-rtems: Do not install assert.h -- use newlib's.
- * combine.c (force_to_mode, case ASHIFTRT): Properly handle
- mask wider than HOST_WIDE_INT.
+Sat Oct 3 19:01:03 1998 Richard Henderson <rth@cygnus.com>
- * c-decl.c (pushdecl): Don't test TREE_PUBLIC when deciding whether
- to register a duplicate decl in the current block.
+ * alpha/linux.h (CPP_PREDEFINES): Define __alpha__ for imake.
-Thu Oct 26 21:55:39 1995 Jason Merrill <jason@sethra.cygnus.com>
+Fri Oct 2 01:33:30 1998 Jim Wilson <wilson@cygnus.com>
- * calls.c (expand_call): Don't trust the callee to copy a
- TREE_ADDRESSABLE type.
- * function.c (assign_parms): Likewise.
+ * i386/winnt.c (i386_pe_asm_file_end): Check
+ TREE_SYMBOL_REFERENCED.
-Thu Oct 26 19:25:05 1995 Mike Stump <mrs@cygnus.com>
+Fri Oct 2 01:31:54 1998 Jeffrey A Law (law@cygnus.com)
- * libgcc2.c (__unwind_function): Provide a default definition for
- implementations that don't yet have a function unwinder.
+ * regclass.c (reg_scan_mark_refs): Return immediately if passed a
+ NULL_RTX as an argument.
-Thu Oct 26 18:08:19 1995 Paul Eggert <eggert@twinsun.com>
+ * gcc.texi: Fix version # that somehow slipped through.
- * cccp.c (handle_directive): Don't treat newline as white
- space when coalescing white space around a backslash-newline.
+Fri Oct 2 01:24:19 1998 Geoff Keating <geoffk@ozemail.com.au>
-Thu Oct 26 17:57:34 1995 Ian Lance Taylor <ian@cygnus.com>
+ * gcse.c: New definition NEVER_SET for reg_first_set, reg_last_set,
+ mem_first_set, mem_last_set; because 0 can be a CUID.
+ (oprs_unchanged_p): Use new definition.
+ (record_last_reg_set_info): Likewise.
+ (record_last_mem_set_info): Likewise.
+ (compute_hash_table): Likewise.
- * mips-tdump.c (enum st): Define st_Struct, st_Union, and st_Enum.
- (st_to_string): Handle them.
- (type_to_string): Add fdp argument; pass it to emit_aggregate.
- (print_symbol): Add fdp argument; pass it to type_to_string.
- Handle st_Struct, st_Union, and st_Enum.
- (emit_aggregate): Add fdp argument. Handle opaque types. Map
- through RFD entries.
- (print_file_desc): Pass FDR to print_symbol.
- (main): Pass null FDR to type_to_string.
+Fri Oct 2 01:20:04 1998 Richard Earnshaw (rearnsha@arm.com)
-Thu Oct 26 08:07:10 1995 Michael Meissner <meissner@cygnus.com>
+ * arm.c (add_constant): New parameter address_only, change caller.
+ Set it non-zero if taking the address of an item in the pool.
+ (arm_reorg): Handle cases where we need the address of an item in
+ the pool.
- * configure (powerpc-ibm-aix[456789]*): Use rs6000/t-newas,
- not rs6000/t-rs6000.
- (rs6000-ibm-aix3.2.[456789]*): Likewise.
- (rs6000-ibm-aix[456789]*): Likewise.
+ * arm.c (bad_signed_byte_operand): Check both arms of a sum in
+ a memory address.
+ * arm.md (splits for *extendqihi_insn and *extendqisi_insn): Handle
+ memory addresses that are not in standard canonical form.
- * rs6000/t-newas: Copy from t-rs6000.
- * t-rs6000: Don't build -mcpu=common multilib variants of libgcc.a.
+Fri Oct 2 01:16:02 1998 Jeffrey A Law (law@cygnus.com)
- * rs6000.md (load_multiple insn): If address register is among regs,
- don't load it with a lwsi instruction, which is undefined on PowerPC.
+ * reg-stack.c (straighten_stack): Do nothing if the virtual stack is
+ empty or has a single entry.
-Thu Oct 26 08:01:32 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Sat Sep 5 23:29:39 1998 Mumit Khan <khan@xraylith.wisc.edu>
- * dwarfout.c (output_compile_unit_die): Handle language_string
- of "GNU F77".
+ * i386/cygwin32.h (ASM_OUTPUT_SECTION_NAME): Don't check for
+ for exact section attributions.
- * reload.c (find_reloads_address): When check for out of range constant
- plus register, accept any hard register instead of just fp, ap, sp.
+ * i386/mingw32.h (CPP_PREDEFINES): Add __MSVCRT__ for msvc
+ runtime.
+ * i386/crtdll.h (CPP_PREDEFINES): Define.
- * combine.c (distribute_notes): For Oct 19 change, add additional
- check to verify that place has a valid INSN_CUID.
+Sat Sep 5 21:46:47 1998 Richard Henderson <rth@cygnus.com>
- * sparc/t-vxsparc (LIBGCC1_TEST): Define.
+ * alpha.c (alpha_ra_ever_killed): Inspect the topmost sequence,
+ not whatever we're generating now.
- * sh.md (negdi2): Use TARGET_LITTLE_ENDIAN.
+Sat Sep 5 14:23:31 1998 Torbjorn Granlund <tege@matematik.su.se>
- * combine.c (force_to_mode, case ASHIFTRT): Verify mode bitsize is
- within HOST_BITS_PER_WIDE_INT before shifting by it.
+ * m68k.md (zero_extendsidi2): Fix typo.
- * final.c (final_scan_insn): When recur for instruction in delay slot,
- add loop around recursive call in case the instruction gets split.
+Tue Sep 1 01:58:38 1998 Jeffrey A Law (law@cygnus.com)
-Thu Oct 26 07:28:45 1995 J"orn Rennecke (amylaar@meolyon.hanse.de)
+ * egcs-1.1 released.
+ * version.c: Update for egcs-1.1 release.
- * genrecog.c (write_tree_1): Avoid emitting '-2147483648'.
+Mon Aug 31 14:55:02 1998 Jeffrey A Law (law@cygnus.com)
- * jump.c (duplicate_loop_exit_test): Return 0 if found
- a NOTE_INSN_LOOP_CONT.
+ * NEWS: Add SCO Openserver and Unixware 7 notes.
-Tue Oct 24 15:30:14 1995 Jeffrey A Law <law@cygnus.com>
+ * NEWS: Fix typos.
- * calls.c (expand_call): Make sure valreg is at least
- a full word.
+Sat Aug 29 14:52:28 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
-Sun Oct 22 19:35:41 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * config/sparc/sparc.md (movdf_insn, movtf_insn): Fix type and
+ length attributes to match May 3rd changes made here.
+ * config/sparc/sparc.h (CONDITIONAL_REGISTER_USAGE): Fix and make
+ call-used %l7 when generating pic code.
- * sh.h (INIT_SECTION_ASM_OP): Delete.
- (HAVE_ATEXIT): Define.
+Sat Aug 29 14:59:32 1998 Mumit Khan <khan@xraylith.wisc.edu>
-Sun Oct 22 07:46:04 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * i386/cygwin32.h (ASM_OUTPUT_SECTION_NAME): Don't emit
+ .linkonce directive after the first time.
- * libgcc2.c (__fixuns[xds]fsi): #undef MIN and MAX before #include
- of limits.h.
+Sat Aug 29 14:48:12 1998 Jeffrey A Law (law@cygnus.com)
- * pa.c (pa_adjust_cost): Use pa_cpu, not pa_cpu_attr.
+ * m68k.md (beq0_di): Generate correct (and more efficient) code when
+ the clobbered operand overlaps with an input.
+ (bne0_di): Similarly.
-Sun Oct 22 07:38:58 1995 J"orn Rennecke (amylaar@meolyon.hanse.de)
+Sat Aug 29 12:38:54 1998 Jeffrey A Law (law@cygnus.com)
- * alpha.h (CONST_OK_FOR_LETTER_P): Use 'U' for unsigned constants.
- * alpha.c (alpha_emit_set_const): Likewise.
- * mips.c (gen_int_relational): Likewise.
+ * NEWS: Various updates.
-Sun Oct 22 07:14:35 1995 Douglas Rupp (drupp@cs.washington.edu)
+Tue Aug 25 19:35:24 1998 Jim Wilson <wilson@cygnus.com>
- * i386.c (i386_return_pops_args): Don't need a FUNDECL to
- check for type attributes in FUNTYPE.
+ * configure.in (powerpc-ibm-aix4.[12]*): Change from 4.[12].*.
+ (rs6000-ibm-aix4.[12]*): Likewise.
+ * configure: Regnerate.
-Sat Oct 21 18:17:42 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Thu Aug 27 23:44:49 1998 Jeffrey A Law (law@cygnus.com)
- * sh.md (define_delay): Don't accept any instruction for an annulled
- slot, only accept those for which in_delay_slot is yes.
- * sh.c (find_barrier): When hi_const returns true, increment count_si
- by two if found_si is true.
- Always use get_attr_length to compute length of instructions.
- If count_hi or count_si out of range at end, need two PREV_INSN calls
- not one.
- When create new label, set LABEL_NUSES to 1.
- (reg_unused_after): Ifdef out code for handling labels.
- (prepare_scc_operands): New local variable mode. Set it from
- sh_compare_op0 or sh_compare_op1. Use it instead of SImode in
- force_reg calls.
-
- * optabs.c (expand_float): Emit missing barrier after unconditional
- jump.
+ * reload1.c (forget_old_reloads_1): Keep track of the largest mode
+ found while stripping SUBREGS and invalidate reloads for all the hard
+ regs specified by that largest mode. egcs-1.1 only hack. The
+ mainline tree will get a better fix.
-Sat Oct 21 14:16:46 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+Tue Aug 25 19:43:11 1998 Jeffrey A Law (law@cygnus.com)
- * alpha.md (cmpdf): Make conditional on TARGET_FP.
+ * From Alexandre:
+ * configure.in: Do not set thread_file to "irix" since no such
+ support exists yet.
-Fri Oct 20 19:11:12 1995 J"orn Rennecke (amylaar@meolyon.hanse.de)
+ * reorg.c (fill_simple_delay_slots): Do not abort if we encounter
+ an insn on the unfilled_slots_list that has no delay slots.
+ (fill_eager_delay_slots): Similarly.
- * combine.c (distribute_notes): Delete instructions without
- side effect that set a subreg of an unused register.
+Mon Aug 24 15:20:19 1998 David Edelsohn <edelsohn@mhpcc.edu>
- * m68k.h (PREFERRED_RELOAD_CLASS): Check for !G constants
- for DATA_OR_FP_REGS also.
+ * rs6000.h (GO_IF_LEGITIMATE_ADDRESS): Use TARGET_POWERPC64
+ when testing LEGITIMATE_INDEXED_ADDRESS_P DFmode and DImode.
+ (LEGITIMIZE_ADDRESS): Use TARGET_POWERPC64 for INDEXED fixup.
+ * rs6000.c (print_operand, case 'L'): Add UNITS_PER_WORD, not 4.
+ (print_operand, cases 'O' and 'T'): Fix typos in lossage strings.
+ * rs6000.md (fix_truncdfsi2_store): Remove %w from non-CONST_INT
+ operand.
+ (movdf_softfloat32, movdf_hardfloat64, movdf_softfloat64): Change
+ 'o' to 'm' for GPR variant constraints.
-Fri Oct 20 18:57:10 1995 Ian Lance Taylor <ian@cygnus.com>
+ * rs6000.md (movqi, movhi): Add CONSTANT_P_RTX.
- * genmultilib: Output negations of unused alternatives, even if
- one of the alternatives is selected.
+Mon Aug 24 01:21:38 PDT 1998 Jeff Law (law@cygnus.com)
-Fri Oct 20 18:48:50 1995 Jeff Law (law@hurl.cygnus.com)
+ * version.c: Bump for snapshot.
- * integrate.c (output_inline_function): Turn on flag_no_inline
- to avoid function integration once we begin writing deferred
- output functions.
+Sun Aug 23 00:47:52 1998 Jeffrey A Law (law@cygnus.com)
-Fri Oct 20 18:46:33 1995 Michael Meissner <meissner@wogglebug.tiac.net>
+ * regmove.c (optimize_reg_copy_3): Disable for egcs-1.1.
- * rs6000.c (float_conv_temp): Delete global variable.
- (stack_temps): New static array to hold stack temps.
- (offsettable_mem_operand): Delete function.
- (offsettable_addr_operand, rs6000_stack_temp): New functions.
- (output_epilog): Zero stack_temps.
+Thu Aug 20 13:56:53 1998 Michael Meissner <meissner@cygnus.com>
- * rs6000.h (offsettable_addr_operand): Declare instead of
- offsettable_mem_operand.
- (PREDICATE_CODES): Use offsettable_addr_operand.
- (float_conv_temp): Delete variable.
+ * config/i386/winnt.c: Include system.h, not stdio.h to get
+ sys/param.h pulled in before rtl.h in case the system defines MIN
+ and MAX.
- * rs6000.md (move_to_float insns): Change move_to_float so
- that it doesn't have a clobber of the memory address, and instead
- passes the stack temp's memory address as one of the unspec args.
- (fix_truncdfsi2): Use rs6000_stack_temp to allocate the temp.
- (multiply, shift insns): Fix all cases of multiply and shift insns so
- that the right mnemonics are used for -mcpu=common with both
- -m{old,new}-mnemonics.
+Wed Aug 19 21:33:19 1998 David Edelsohn <edelsohn@mhpcc.edu>
-Fri Oct 20 17:58:19 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * rs6000.c (rs6000_output_load_toc_table): Use ld for 64-bit.
+ (output_toc): Use single TOC slot or llong minimal-toc for DFmode
+ and DImode 64-bit. Use llong for minimal-toc SFmode and
+ SYMBOL_REF / LABEL_REF 64-bit.
+ (output_function_profiler): Use llong for profiler label and ld to
+ load 64-bit label address.
- * expr.c (safe_from_p, case RTL_EXPR): Return 0 if RTL_EXPR_SEQUENCE
- exists. Delete code to return 0 if exp_rtl is zero.
+Tue Aug 18 23:48:30 1998 Richard Henderson <rth@cygnus.com>
- * function.c (init_function_start): Don't call init_insn_lengths here.
- * toplev.c (rest_of_compilation): Call it here.
+ * c-common.c (decl_attributes): Issue an error if the argument
+ to alias is not a string.
-Thu Oct 19 19:19:06 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Aug 18 13:05:59 BST 1998 Richard Earnshaw (rearnsha@arm.com)
- * c-common.c (check_format_info): Make test for null pointer
- more general.
+ * arm.c (arm_override_options): Remove lie about ignoring PIC flag.
-Thu Oct 19 18:56:16 1995 Satoshi Adachi (adachi@wisdom.aa.ap.titech.ac.jp)
+Tue Aug 18 10:32:11 1998 Jeffrey A Law (law@cygnus.com)
- * fixincludes (stdlib.h): Be more general in edit to change
- declaration of {c,m,re}alloc.
+ * haifa-sched.c (sched_analyze): Put all JUMP_INSNs on the last
+ pending memory flush list.
-Thu Oct 19 18:48:53 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+ * regmove.c (fixup_match_2): Do not call reg_overlap_mentioned_p
+ on notes.
- * libgcc2.c (__udiv_w_sdiv): If we don't have sdiv_qrnnd, define
- dummy variant of __udiv_w_sdiv.
-
-Thu Oct 19 18:45:21 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * regmove.c (optimize_reg_copy_1): Update REG_N_CALLS_CROSSED
+ and REG_LIVE_LENGTH as successful substitutions are made.
- * alpha.h (ASM_SPEC): If GNU as is the default, then pass -g to
- the assembler if -malpha-as. If GNU as is not the default, then pass
- -g to the assembler is not -mgas.
+Mon Aug 17 21:07:19 1998 Jeffrey A Law (law@cygnus.com)
- * combine.c (distribute_notes): When search for new place to put
- REG_DEAD note, call distribute_links if this new place is between
- i2 and i3, and i2 uses the register.
+ * From Graham
+ * tree.c (build_index_type): Copy TYPE_SIZE_UNIT from sizetype
+ to itype.
+ * c-decl.c (finish_enum): Copy TYPE_SIZ_UNIT from enumtype to tem.
-Thu Oct 19 18:41:36 1995 Michael Meissner <meissner@cygnus.com>
+ * rs6000.c (secondary_reload_class): For TARGET_ELF, indicate that
+ a BASE_REGS register is needed as an intermediate when copying
+ a symbolic value into any register class other than BASE_REGS.
- * rs6000.md (float{,uns}sidf2): Rewrite to break the conversion
- process into several general insns.
- (move_to_float): New insns to move 2 integer regs into a float register
- through memory, taking endianess into account. Make sure that the
- floating temporary is a valid address. Use one temporary for all
- floats converted.
- (fix_truncdfsi2): Take endianess into account.
+Mon Aug 17 11:25:52 1998 Richard Earnshaw <rearnsha@arm.com>
- * rs6000.c ({low_32_bit,offsettable_mem}_operand): The function
- low_32_bit_operand is now unused, delete it. New function
- offsettable_mem_operand to determine if a memory address is
- offsettable.
- * rs6000.h ({low_32_bit,offsettable_mem}_operand): Ditto.
- (PREDICATE_CODES): Ditto.
+ * arm.h (SECONDARY_INPUT_RELOAD_CLASS): Return NO_REGS if compiling
+ for architecture v4.
- * rs6000.{c,h} (float_conv_temp): New global.
- * rs6000.c (output_epilog): Zero out float_conv_temp.
+Sun Aug 16 00:57:48 PDT 1998 Jeff Law (law@cygnus.com)
- * Makefile.in (libgcc{1,2}.a): Allow LIB{1,2}FUNCS_EXTRA files to
- end in .S as well as .c and .asm.
+ * version.c: Bump for snapshot.
-Wed Oct 18 17:56:45 1995 Jose Alonso (sidinf@fpsp.fapesp.br)
+Sun Aug 16 01:53:21 1998 Richard Henderson <rth@cygnus.com>
- * c-typeck.c (parser_build_binary_op): Warn about x^y==z, etc.
+ * reload.c (find_equiv_reg): Reject equivalences separated
+ by a volatile instruction.
-Mon Oct 9 12:38:06 1995 Michael Meissner <meissner@cygnus.com>
+Sun Aug 16 00:21:44 1998 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
- * protoize.c (reverse_def_dec_list): Silence compiler warnings.
+ * rs6000/linux.h (CPP_OS_DEFAULT_SPEC): Define.
-Mon Oct 9 12:35:54 1995 Andrew Cagney <cagney@highland.com.au>
+Sat Aug 15 20:22:33 1998 H.J. Lu (hjl@gnu.org)
- * ginclude/va-ppc.h (va_arg): Deal with long longs that would be
- passed in the 7th register, and are passed in the stack instead.
+ * config/alpha/alpha.h (ASM_OUTPUT_MI_THUNK): Handle aggregated
+ return type.
+ * config/alpha/win-nt.h (ASM_OUTPUT_MI_THUNK): Likewise.
-Fri Oct 6 13:47:10 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Fri Aug 14 21:07:03 1998 Jeffrey A Law (law@cygnus.com)
- * alpha.h (ASM_SPEC): Add -g.
+ From Joern:
+ * expr.c (store_expr): Don't optimize away load-store pair
+ when either source or destination have a side effect.
-Fri Oct 6 13:42:50 1995 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+ * loop.c (add_label_notes): Do not ignore references to labels
+ before dispatch tables. Mirrors Apr 8 change to mark_jump_label.
+ * gcse.c (add_label_notes): Similarly.
- * alpha.h (alpha_{arg,auto}_offset): Make extern.
+ * pa.h (ASM_OUTPUT_MI_THUNK): Strip name encoding.
-Fri Oct 6 13:24:43 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+ * m68k.md (adddi_dilshr32): One of the operands must be a register.
+ (adddi_dishl32): Similarly.
- * rs6000.h (RETURN_ADDRESS_OFFSET): Correct previous change.
+Fri Aug 14 01:45:06 1998 Mumit Khan <khan@xraylith.wisc.edu>
-Fri Oct 6 13:14:43 1995 Doug Evans <dje@canuck.cygnus.com>
+ * i386/cygwin32.h (DEFAULT_PCC_STRUCT_RETURN): Define.
- * rtlanal.c (reg_set_last): Fix call to reg_set_between_p.
+Fri Aug 14 01:40:21 1998 Geoffrey Keating <geoffk@ozemail.com.au>
-Tue Oct 3 12:31:38 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * rs6000/linux.h (LINK_SPEC): Pass -G args to the linker.
- * stor-layout.c (layout_type, case ARRAY_TYPE): Strip MAX_EXPR
- from upper bound when computing length if it just protects against
- negative length.
+Fri Aug 14 01:23:23 1998 Richard Earnshaw (rearnsha@arm.com)
- * expr.c (emit_move_insn_1): When doing multi-word move, show
- output is clobbered.
+ * arm/netbsd.h (TARGET_DEFAULT): Default includes software floating
+ point.
+ (CPP_FLOAT_DEFAULT_SPEC): Re-define accordingly.
-Tue Oct 3 12:26:07 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Fri Aug 14 01:23:23 1998 Jeffrey A Law (law@cygnus.com)
- * cse.c (set_nonvarying_address_components, case AND): Add *pend to
- end. Add constant to start instead of subtracting it.
+ * README.RS6000: Bring over dje's changes from the mainline
+ source tree.
-Tue Oct 3 12:23:28 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+Fri Aug 14 01:19:08 1998 Robert Lipe <robertl@dgii.com>
- * combine.c (simplify_rtx): In code that attempts to simplify
- conditional expressions, if the result is an NE around another
- comparison, return the original expression.
+ * install.texi: Various SCO OpenServer tweaks.
- * longlong.h (mips umul_ppmm): Use `l' and `h' constraints;
- remove mflo and mfhi instructions.
+Thu Aug 13 19:55:05 1998 Jim Wilson <wilson@cygnus.com>
-Tue Oct 3 12:21:29 1995 Michael Meissner <meissner@cygnus.com>
+ * reload1.c (eliminate_regs_in_insn): Handle another case when
+ eliminating the frame pointer to the hard frame pointer. Add
+ missing ep->to_rtx check to one existing case.
- * ginclude/va-ppc.h (va_start, stdarg case): Call
- __builtin_next_arg, and ignore the result, so that the compiler
- can report the proper error, if the second argument is not the
- last argument.
+Tue Aug 11 17:45:39 1998 Dave Love <d.love@dl.ac.uk>
-Tue Oct 3 12:02:51 1995 Kohtala Marko <Marko.Kohtala@ntc.nokia.com>
+ * README.g77: Update from Craig.
- * function.c (assign_stack_temp): Adjust full_size field of
- temp_slot when splitting an unused slot.
+Sat Aug 8 19:20:22 1998 Gary Thomas (gdt@linuxppc.org)
-Tue Oct 3 11:51:59 1995 Mike Stump <mrs@cygnus.com>
+ * rs6000.c (rs6000_allocate_stack_space) Fix typo which
+ caused bad assembly code to be generated.
- * expr.c (expand_builtin_return_addr): Break out functionality
- from expand_builtin.
- (expand_builtin): Call expand_builtin_return_addr.
- * rs6000.h (RETURN_ADDR_RTX): Remove call to copy_to_reg.
- Offset to return address is 4 when !TARGET_64BIT and v4_call_p,
- 8 otherwise.
- * sparc.h (RETURN_ADDR_RTX): Remove call to copy_to_reg.
- * alpha.h (RETURN_ADDR_RTX): New definition.
+Sat Aug 8 18:52:51 1998 Jeffrey A Law (law@cygnus.com)
-Sun Oct 1 21:23:30 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * netbsd.h: Fix typo.
- * tree.c (staticp, case INDIRECT_EXPR): Disable case.
+Mon Aug 3 23:43:55 PDT 1998 Jeff Law (law@cygnus.com)
- * expr.c (expand_expr, case COMPONENT_REF): If getting component
- of union of variable size, propagate TARGET.
+ * version.c: Bump for snapshot.
-Fri Sep 29 07:48:09 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Sun Aug 2 00:42:50 1998 Jeffrey A Law (law@cygnus.com)
- * expr.c (store_expr): When storing promoted value, don't return
- MEM if address contains target.
+ * i386/netbsd.h: Undo previous change to DWARF2_UNWIND_INFO.
+ * m68k/netbsd.h: Likewise.
+ * ns32k/netbsd.h: Likewise.
+ * sparc/netbsd.h: Likewise.
-Thu Sep 28 14:30:03 1995 Paul Eggert <eggert@twinsun.com>
+Fri Jul 31 17:08:59 1998 Jeffrey A Law (law@cygnus.com)
- * cccp.c (rescan): Expand `#if foo && #bar' without a bogus
- complaint about preprocessor directives within macro args.
- Expand `foo' in `foo#bar' without requiring a space before `#'.
+ * configure.in (mingw configuration): Fix typo.
+ * configure: Rebuilt.
-Thu Sep 28 14:24:26 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+Fri Jul 31 20:22:02 1998 Michael Meissner <meissner@cygnus.com>
- * m68k.md (anonymous DImode shift patterns setting cc0): Turned
- off due to reload problems.
+ * rs6000.c (rs6000_override_options): If big endian and -Os, use
+ load/store multiple instructions unless user overrides.
-Thu Sep 28 14:05:22 1995 Niklas Hallqvist (niklas@appli.se)
+Fri Jul 31 17:08:59 1998 Jeffrey A Law (law@cygnus.com)
- * Makefile.in (USER_H): Move up so can override.
- (INSTALL_ASSERT_H): New definition.
- (install-headers): Use it.
- (stmp-int-hdrs): Handle USER_H being empty.
- * config/x-netbsd (INSTALL_ASSERT_H): Define as empty.
+ * ns32k/netbsd.h: Fix typo.
- * i386/netbsd.h (WCHAR_{TYPE,UNSIGNED,TYPE_SIZE}): Now int.
- * m68k/netbsd.h, ns32k/netbsd.h, sparc/netbsd.h: Likewise.
- * vax/netbsd.h: Likewise.
- (SIZE_TYPE): Use unsigned int.
+Thu Jul 30 19:50:15 1998 David Edelsohn <edelsohn@mhpcc.edu>
- * m68k.c (output_scc_di): Swap operands when needed.
- * m68k.h (LEGITIMATE_PIC_OPERAND): Allow SYMBOL_REF_FLAG symref.
- * m68k.md: Make both assembler syntaxes do the same for PIC calls.
+ * rs6000/x-aix43 (AR_FOR_TARGET_FLAGS): Delete.
+ (AR_FOR_TARGET): Define.
-Tue Sep 26 16:51:44 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+Thu Jul 30 19:11:30 1998 Richard Henderson <rth@cygnus.com>
- * mips.c (override_options): Don't allow anything but integers to
- go in the HI/LO registers.
+ * alpha.md (fp cmp): Replicate patterns for ALPHA_TP_INSN.
+ (fcmov): Remove ALPHA_TP_INSN patterns -- fcmov doesn't trap.
-Tue Sep 26 16:36:18 1995 John F. Carr <jfc@mit.edu>
+Thu Jul 30 12:51:09 1998 Mark Mitchell <mark@markmitchell.com>
- * c-common.c (check_format_info): Don't warn about format type
- mismatch if the argument is an ERROR_MARK.
+ * dyn-string.h: New file.
+ * dyn-string.c: Likewise.
+ * Makefile.in (OBJS): Add dyn-string.o.
+ (dwarf2out.o): Add dyn-string.h dependency.
+ (dyn-string.o): List dependencies.
+ * dwarf2out.c: Include dyn-string.h.
+ (ASM_NAME_TO_STRING): Use dyn_string_append, rather than strcpy.
+ (addr_const_to_string): Take a dyn_string_t, not a char* as a
+ prototype. Use dyn_string_append rather than strcat, throughout.
+ (addr_to_string): Use dyn_string_t.
-Mon Sep 25 17:50:50 1995 Craig Burley (burley@gnu.ai.mit.edu)
+Thu Jul 30 00:58:34 1998 Jeffrey A Law (law@cygnus.com)
- * stor-layout.c (put_pending_sizes): New function.
- * tree.h (put_pending_sizes): Add declaration.
- * tree.c (save_expr): Return original for ERROR_MARK.
+ * i386.md (movqi): When optimizing a load of (const_int 1) into a
+ NON_QI_REG_P, pretend the register is SImode.
-Fri Sep 22 19:20:01 1995 Jeff Law (law@hurl.cygnus.com)
+Wed Jul 29 23:49:23 1998 Todd Vierling <tv@netbsd.org>
- * expr.c (expand_builtin, case BUILT_IN_MEMCPY): Strip off
- all NOP exprs from the source and destination nodes, then
- set MEM_IN_STRUCT_P.
+ * configure.in: Use xm-netbsd.h as the NetBSD xm file (not xm-siglist).
+ Accept arm32 as arm, m68k4k as m68k, mipsle as mips-dec, and any
+ manufacturer id for ns32k.
+ * configure: Regenerated.
+ * config/netbsd.h: When using ASM_WEAKEN_LABEL, make it global too.
+ * config/t-netbsd: Don't compile libgcc1-test as the fns are in libc.
+ * config/i386/netbsd.h: Undefine DWARF2_UNWIND_INFO, not define as 0.
+ * config/m68k/netbsd.h: Same.
+ * config/ns32k/netbsd.h: Same.
+ * config/sparc/netbsd.h: Same.
-Fri Sep 22 18:50:31 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+Wed Jul 29 22:39:21 1998 Jeffrey A Law (law@cygnus.com)
- * rs6000/eabi.h (ASM_OUTPUT_INT): Test for whether the integer
- being output is also a constant so &sym - &sym2 is not fixed up.
+ * unroll.c (unroll_loop): Do not abort for an UNROLL_MODULO
+ or UNROLL_COMPLETELY loop that starts with a jump to its
+ exit code.
-Fri Sep 22 18:49:07 1995 Peter Flass (FLASS@LBDRSCS.BITNET)
+Wed Jul 29 22:18:14 1998 David Edelsohn <edelsohn@mhpcc.edu>
- * i370.md (cmpsi): Add missing constraints to operand 1.
+ * rs6000/rs6000.md (absdi2 define_split): Swap operands of MINUS.
+ * rs6000/rs6000.c (mask64_operand): Use HOST_BITS_PER_WIDE_INT.
+ (print_operand, case 'B'): Don't fall through.
+ (print_operand, case 'S'): Correct mask begin/end computation.
+ Use HOST_BITS_PER_WIDE_INT.
+ * rs6000/rs6000.h (CPP_PREDEFINES): Define _LONG_LONG.
+ (CONDITIONAL_REGISTER_USAGE): GPR13 fixed if TARGET_64BIT.
+ * rs6000/aix41.h (CPP_PREDEFINES): Same.
+ * rs6000/aix43.h (CPP_PREDEFINES): Same.
-Fri Sep 22 18:27:33 1995 Torbjorn Granlund <tege@matematik.su.se>
+Tue Jul 28 23:29:04 1998 Jason Merrill <jason@yorick.cygnus.com>
- * i386.h (CONST_OK_FOR_LETTER_P): Make `N' match range 0..255
- for `outb' instruction.
+ * configure.in: Fix --without/--disable cases for local-prefix,
+ gxx-include-dir and checking.
- * pyr.h (PRINT_OPERAND): Handle code `R' for REG.
- * longlong.h (pyr umul_ppmm): Use it.
+Tue Jul 28 22:10:43 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
-Fri Sep 22 18:24:38 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * configure.in (enable_haifa): Set by default for sparc64 too.
+ configure: Rebuilt.
- * c-parse.in (enumlist): Propagate error_mark_node.
+Tue Jul 28 23:29:04 1998 Jason Merrill <jason@yorick.cygnus.com>
- * c-aux-info.c (gen_type): Handle ERROR_MARK.
+ * i386/cygwin32.h (VALID_MACHINE_TYPE_ATTRIBUTE): New macro.
+ * i386/winnt.c (associated_type): New fn.
+ (i386_pe_valid_type_attribute_p): New fn.
+ (i386_pe_check_vtable_importexport): Remove.
+ (i386_pe_dllexport_p): Use associated_type.
+ (i386_pe_dllimport_p): Likewise.
- * alpha.md (movdi): Avoid memory sharing problem when in reload.
+ From Antonio M. O. Neto <anmendes@cruzeironet.com.br>:
+ * i386.c (i386_valid_type_attribute_p): Also accept
+ attributes for METHOD_TYPEs.
-Wed Sep 20 14:27:09 1995 Peter Flass <flass@lbdrscs.bitnet>
+Tue Jul 28 23:17:39 1998 Peter Gerwinski <peter@gerwinski.de>
- * mvs.h (FUNCTION_PROLOGUE): Maintain savearea forward chain
- per MVS standards.
+ * tree.c (build_range_type): Copy TYPE_SIZE_UNIT.
-Wed Sep 20 14:20:52 1995 Torbjorn Granlund <tege@matematik.su.se>
+Tue Jul 28 22:31:12 1998 Craig Burley <burley@gnu.org>
- * pyr.md (cmphi recognizer): Make condition match constraints.
- (cmpqi recognizer): Likewise.
+ * gcc.c: Fix commentary describing %g, %u, %U, and %O.
-Wed Sep 20 12:42:59 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * gcc.c (do_spec_1): Fix handling of %g%O and %U%O to prevent
+ them from generating a new base name for each occurence of
+ a specific suffix.
- * integrate.c (expand_inline_function): Do copy something setting
- the result register if it is setting it to itself and has a REG_NOTE.
+1998-07-28 Vladimir N. Makarov <vmakarov@cygnus.com>
- * integrate.c (set_decl_{origin_self,abstract_flags}): Treat
- a DECL_INITIAL of error_mark_node the same as one of NULL_TREE.
+ * cse.c (cse_insn): Enable subsitution inside libcall only for REG,
+ SUBREG, MEM.
+ * rtlanal.c (replace_rtx): Prohibit replaces in CONST_DOUBLE.
-Tue Sep 19 19:30:18 1995 Dave Pitts (dpitts@nyx.cs.du.edu)
+Mon Jul 27 00:54:41 1998 Jason Merrill <jason@yorick.cygnus.com>
- * i370.md (cmphi, movhi, movstricthi, extendhisi2): Correct generation
- of short integer (Halfword)
- ({add,sub,mul,and,ior,xor}hi3): Likewise.
- * i370/mvs.h (MACROPROLOGUE): New macro.
- (FUNCTION_{PRO,EPI}LOGUE): Added ability to use IBM supplied function
- prologue macros.
- (FUNCTION_PROLOGUE): Corrected function "in-line" prologue alignment
- problems.
- (ASM_DECLARE_FUNCTION_NAME): Changed alignment to FullWord.
- (ASM_OUTPUT_{SHORT,ASCII}): Reworked.
+ * tree.c (simple_cst_equal, case CONSTRUCTOR): OK if the elts are
+ identical.
+
+Mon Jul 27 22:20:02 1998 Jeffrey A Law (law@cygnus.com)
+
+ * pa.c (move_operand): Accept CONSTANT_P_RTX.
+
+Mon Jul 27 00:46:56 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sun Jul 26 01:11:12 1998 H.J. Lu (hjl@gnu.org)
+
+ * i386.h (CONST_DOUBLE_OK_FOR_LETTER_P): Return 0 when eliminating
+ the frame pointer and compiling PIC code and reload has not completed.
+
+ * i386.c (output_to_reg): Add code to emulate non-popping DImode
+ case.
+
+Sun Jul 26 01:02:54 1998 Jeffrey A Law (law@cygnus.com)
+
+ * regmove.c (regmove_optimize): Fix typo initializing regmove_bb_head.
+
+Sat Jul 25 23:29:23 1998 Gerald Pfeifer <pfeifer@dbai.tuwien.ac.at>
+
+ * Makefile.in (install-info): Only try to update the info
+ directory file if it exists in the first place.
+
+Fri Jul 24 18:58:37 1998 Klaus Espenlaub <kespenla@student.informatik.uni-ulm.de>
+
+ * rs6000.h (ASM_OUTPUT_CONSTRUCTOR, ASM_OUTPUT_DESTRUCTOR): Delete.
+
+Thu Jul 23 18:53:20 1998 Jim Wilson <wilson@cygnus.com>
+
+ * dbxout.c (dbxout_range_type): Only call dbxout_type_index for
+ already defined type.
+
+Wed Jul 22 14:08:54 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
+
+ * profile.c (branch_prob): Call allocate_reg_info after outputting
+ profile rtl in instrument_arcs.
+
+Tue Jul 21 22:40:09 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Tue Jul 21 23:28:35 1998 Klaus Kaempf <kkaempf@rmi.de>
+
+ * cccp.c (do_include): Fix vax c style include handling.
-Tue Sep 19 19:22:15 1995 Douglas Rupp (drupp@cs.washington.edu)
+Tue Jul 21 15:49:31 1998 David Edelsohn <edelsohn@mhpcc.edu>
- * winnt/win-nt.h: Renamed from winnt/win-nt.h.
- (LINK_SPEC): Add -noinhibit-exec.
- * {alpha,i386}/win-nt.h: Renamed from {alpha,i386}/winnt.h.
- Include winnt/win-nt.h, not winnt/winnt.h.
- * winnt/oldnames.c: New file.
- * winnt/headers.mak (fixinc-nt.obj): Fix typo.
- * winnt/config-nt.bat: Change winnt.h to win-nt.h.
- * i386/config-nt.sed: Likewise.
- * configure ({alpha,i386}-*-winnt3*): Likewise.
+ * rs6000.h (PREDICATE_CODES): Add CONSTANT_P_RTX.
+ * rs6000.md (movsi, movdi): Add CONSTANT_P_RTX.
+ * rs6000.c (short_cint_operand): Add CONSTANT_P_RTX.
+ (u_short_cint_operand): Same.
+ (reg_or_cint_operand): Same.
+ (logical_operand): Same.
+ (input_operand): Same.
+ (reg_or_short_operand): Use u_short_cint_operand.
-Mon Sep 18 14:00:45 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de)
+Tue Jul 21 03:59:08 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
- * 1750a.h (enum reg_class, REG_CLASS_NAMES, REG_CLASS_CONTENTS):
- Added R2 and R0_1.
- (REG_CLASS_FROM_LETTER): New letters 't' and 'z'.
- (EXTRA_CONSTRAINT): New letter 'Q'.
+ * jump.c (jump_optimize): When simplifying noop moves and
+ PUSH_ROUNDING, fix thinko so we use same criterion for identifying
+ the PUSHes to rewrite in second loop as we did in the first.
-Sun Sep 17 12:39:22 1995 Jeff Law (law@snake.cs.utah.edu)
+Tue Jul 21 00:31:01 1998 Jeffrey A Law (law@cygnus.com)
- * pa.h (ASM_DECLARE_FUNCTION_NAME): If a parameter's type
- has TYPE_NEEDS_CONSTRUCTING on, then it's passed by invisible
- reference.
+ * gcc.c (do_spec): Call "error" not "warning".
-Sat Sep 16 17:42:33 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * configure.in: Fix minor problems with gas feature detection code.
+ * configure: Rebuilt.
- * loop.c (find_and_verify_loops): Fix error in last change.
+ * gcc.c (do_spec): Issue a warning for '%[]' usage.
-Sat Sep 16 08:38:22 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * Undo this change.
+ * gcc.c: Delete %[spec] support.
+ (do_spec_1, case '('): Likewise.
+ (do_spec_1, case '['): Call error.
- * alpha.h (GO_IF_LEGITIMATE_ADDRESS): Disallow SYMBOL_REF for
- current function.
+Mon Jul 20 22:34:17 1998 Richard Henderson <rth@cygnus.com>
- * cse.c (recorded_label_ref): New variable.
- (insert): Set instead of cse_jumps_altered.
- (cse_main): Initialize it and return 1 if nonzero at end.
+ * alpha.h (CPP_SPEC): Tidy. Hook to cpp_cpu and cpp_subtarget.
+ (CPP_SUBTARGET_SPEC): Default to empty string.
+ (CPP_AM_*, CPP_IM_*, CPP_CPU_*, CPP_CPU_SPEC): New.
+ (EXTRA_SPECS, SUBTARGET_EXTRA_SPECS): New.
+ * alpha/elf.h (LD_SPEC): Use %(elf_dynamic_linker).
+ * alpha/linux-elf.h (SUBTARGET_EXTRA_SPECS): New.
+ (LIB_SPEC): Tidy.
+ * alpha/linux.h (CPP_PREDEFINES): Tidy.
+ * alpha/netbsd-elf.h (SUBTARGET_EXTRA_SPECS): New.
+ * alpha/netbsd.h (CPP_PREDEFINES): Tidy.
+ * alpha/osf.h (CPP_PREDEFINES): Remove bits subsumed by CPP_CPU_SPEC.
+ * alpha/win-nt.h (CPP_PREDEFINES): Likewise.
+ * alpha/vsf.h (CPP_PREDEFINES): Likewise.
+ (CPP_SUBTARGET_SPEC): New. Do this instead of overriding CPP_SPEC.
+ * alpha/vxworks.h: Likewise.
-Fri Sep 15 18:26:49 1995 Torbjorn Granlund (tege@matematik.su.se)
+Mon Jul 20 22:51:57 1998 Ken Raeburn <raeburn@cygnus.com>
- * fold-const (div_and_round_double): Change `carry', `quo_est',
- and `scale' from plain int to `unsigned HOST_WIDE_INT'.
+ * mips.md (reload_outsi): Added missing REGNO call.
+ (smulsi3_highpart, umulsi3_highpart): Provide prototype for
+ function pointer.
+ (mul_acc_di, mul_acc_64bit_di): Don't use match_op_dup, use
+ another match_operator and compare the codes.
-Fri Sep 15 18:24:24 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * mips.h (MASK_DEBUG_E, MASK_DEBUG_I): Set to zero.
- * cse.c (insert): Set cse_jumps_altered when inserting a LABEL_REF.
+ * MIPS multiply pattern fixes:
+ * mips.h (enum reg_class, REG_CLASS_NAMES, REG_CLASS_CONTENTS):
+ Add union classes for HI, LO, or HILO plus general registers.
+ (GENERATE_MADD): Deleted.
+ * mips.md (mulsi3_mult3): Don't disparage output-LO alternative.
+ Add TARGET_MAD to condition.
+ (mulsi3): Test HAVE_mulsi3_mult3, not specific flags.
+ (mul_acc_si): Expand GENERATE_MADD here; it's the only use. Use
+ "*d" for accumulator, to give preference to LO initially but not
+ during reload.
-Fri Sep 15 17:29:41 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de)
+Mon Jul 20 01:13:19 1998 Jim Wilson <wilson@cygnus.com>
- * 1750a.c (b_mode_operand): New function.
- (print_operand): Added code 'Q'.
+ * function.c (fixup_var_refs_insns): Handle CLOBBER of a CONCAT.
-Fri Sep 15 17:27:23 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Sat Jul 18 15:20:19 1998 Mark Mitchell <mark@markmitchell.com>
- * loop.c (find_and_verify_loops): When moving exit blocks out of
- the loop, verify that the target of P is within the current loop.
+ * loop.c (maybe_eliminate_biv_1): Avoid signed/unsigned comparison
+ confusion when setting cc0.
- * reorg.c (fill_slots_from_thread): Update thread if it is split.
+Fri Jul 17 03:26:12 1998 Rihcard Earnshaw (rearnsha@arm.com)
-Fri Sep 15 17:06:51 1995 Michael Meissner <meissner@cygnus.com>
+ * tree.c (valid_machine_attribute): Only create a new type variant if
+ there is a decl to use it.
- * rs6000.md (decrement_and_branchsi and related insns): Don't use
- a "2" to select a register preference for operand 1 if operand 2
- hasn't been seen yet.
- Add appropriate clobbers in decrement_and_branchsi.
- Add patterns where the pc/label_ref are interchanged.
+Fri Jul 17 02:01:00 1998 Jeffrey A Law (law@cygnus.com)
- * Makefile.in (gnucompare, stmp-multilib-sub): Remove extra . in
- front of $(objext).
+ * Makefile.in (WARN_CFLAGS): Disable -W -Wall for the release
+ branch.
- * rs6000.c (output_toc): Align DF constants if STRICT_ALIGNMENT.
+Thu Jul 16 14:48:04 1998 Nick Clifton <nickc@cygnus.com>
- * config/fp-bit.c (FLO_union_type): Add words field if double
- precision to get at the separate words.
- (FLO_union_type, pack_d, unpack_d): Use FLOAT_BIT_ORDER_MISMATCH
- to determine when the bitfields need to be reversed, and
- FLOAT_WORD_ORDER_MISMATCH when the words need to be reversed.
+ * gcc.c (do_spec_1): Cope with %g/%u/%U options which do not have
+ a suffix.
-Fri Sep 15 16:41:43 1995 Jeff Law (law@snake.cs.utah.edu)
+Thu Jul 16 17:07:24 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * reorg.c (fill_simple_delay_slots): When filling insn's delay slot
- with JUMP_INSN, don't assume it immediately follows insn on
- unfilled slots obstack.
+ * cplus-dem.c (demangle_nested_args): Make function definition
+ static to match the prototype.
- * Makefile.in (caller-save.o): Depend on insn-codes.h.
+Thu Jul 16 01:17:44 1998 Richard Henderson <rth@cygnus.com>
-Thu Sep 14 17:41:49 1995 Jim Meyering (meyering@comco.com)
+ * loop.c (emit_iv_add_mult): Scan the entire insn list generated
+ for the sequence, recording base values.
- * protoize.c (do_cleaning): Don't blank out backslash-escaped
- newlines in double quoted strings.
+Wed Jul 15 00:52:54 PDT 1998 Jeff Law (law@cygnus.com)
-Thu Sep 14 16:20:35 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * version.c: Bump for snapshot.
- * emit-rtl.c (gen_lowpart): If gen_lowpart_common fails
- for a REG, load it into a pseudo and try again.
+Wed Jul 15 00:52:20 PDT 1998 Jeff Law (law@cygnus.com)
-Thu Sep 14 14:15:16 1995 Stan Cox (coxs@dg-rtp.dg.com)
+ * version.c: Bump for snapshot.
- * m88k.h (VERSION_INFO1): Removed BCS reference.
- * m88k/dgux.h (ASM_SPEC, *_LEGEND):
- Added -mno-legend option. -mstandard no longer implies that legend
- legend information not be produced.
- (LINK_SPEC): Removed -z text
+Tue Jul 14 14:15:30 1998 Nick Clifton <nickc@cygnus.com>
-Tue Sep 12 19:05:39 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * gcc.c: Remove ANSI-C ism from --help code.
- * cccp.c (is_system_include): Call skip_redundant_dir_prefix.
+ * toplev.c: Support --help with USE_CPPLIB.
-Tue Sep 12 18:58:21 1995 John Carr <jfc@mit.edu>
+Tue Jul 14 02:20:38 1998 Jeffrey A Law (law@cygnus.com)
- * sparc.md: Change `*return "string"' to "string" in patterns.
+ * configure.in: Rework gas feature code to work with symlink based
+ source trees.
-Tue Sep 12 18:48:47 1995 Craig Burley (burley@gnu.ai.mit.edu)
+ * version.c: Bump to avoid problems with old spec files during
+ bootstrap.
- * function.c (put_var_into_stack): For CONCAT case, order of
- placement depends on FRAME_GROWS_DOWNWARD, not STACK_GROWS_DOWNWARD.
+Mon Jul 13 23:11:44 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
-Tue Sep 12 18:34:10 1995 Doug Evans <dje@canuck.cygnus.com>
+ * config/sparc/sparc.c (output_scc_insn): Enclose || conditions in
+ parens while walking over notes.
+ * config/sparc/sparc.md (reg movdi split): Clean up matching
+ conditions.
+ (all DI arithop splits on 32-bit): Handle immediate arguments
+ correctly when they are CONST_INTs.
- * va-sparc.h (v9 varargs va_start): Handle __builtin_va_alist
- being stack argument.
+Mon Jul 13 23:57:21 1998 Kamil Iskra <iskra@student.uci.agh.edu.pl>
- * sparc.h (STATIC_CHAIN_REGNUM): Use %g5 for sparc64.
- (TRAMPOLINE_TEMPLATE): Rewrite for sparc64.
- (TRAMPOLINE_SIZE): Is 40 for sparc64.
- * sparc.c (sparc64_initialize_trampoline): Rewrite.
+ * m68k/m68k.h (TARGET_SWITCHES): Clear MASK_68040_ONLY for
+ -m68020-40, -m68020-60 and -m5200.
-Tue Sep 12 18:30:22 1995 Douglas Rupp (drupp@cs.washington.edu)
+Mon Jul 13 23:52:05 1998 Weiwen Liu <weiwen.liu@yale.edu>
- * cp/Make-lang.in (cc1plus) : Removed unnecessary $(exeext).
+ * gcc.c (do_spec_1): Fix %O handling for secure temporary file
+ creation.
- * configure: Added code to handle gcc_extra_objs.
- (alpha-winnt): Changed xmake_file to winnt/x-winnt.
- Added extra_gcc_objs=spawnv.o; changed extra_programs to ld.exe.
- (i386-winnt): Changed xmake_file to winnt/x-winnt.
- Added extra_gcc_objs=spawnv.o; changed extra_programs to ld.exe.
- * configure.bat: Changed to used common winnt/config-nt.bat.
- * Makefile.in: Changed various .o's to .$(objext)'s
- (specs): Removed unnecessary $(exeext).
- (EXTRA_GCC_OBJS): New variable.
- (clean): Removed $(LIB2FUNCS_EXTRA)
- * objc/Makefile: Changed archive command for libobjc.a to use $?
- for objects.
+Mon Jul 13 23:42:36 1998 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
- * alpha/x-winnt, i386/x-winnt: Deleted.
- * alpha/config-nt.bat, i386/config-nt.bat: Deleted.
- * alpha/config-nt.sed, i386/config-nt.sed: Moved architecture
- independent commands to config/winnt/config-nt.sed.
- * alpha/winnt.h: Added -D_M_ALPHA to CPP_PREDEFINES.
- Changed LIB_SPEC to be compatible with Gnu ld for NT.
- * i386/winnt.h: Added -D_cdecl=__attribute__((__cdecl__)).
- Change LIB_SPEC to be compatible with Gnu ld for NT.
- * winnt/config-nt.bat, winnt/config-nt.sed: New files.
- * winnt/dirent.{c,h}, winnt/fixinc-nt.c, winnt/headers.mak: New files.
- * winnt/ld.c: Changed precedence of libraries to look for
- libfoo.lib before libfoo.a
- Changed to work like Gnu ld for NT.
- * winnt/libgcc.mak, winnt/mklibgcc.c: New files.
- * winnt/spawnv.c: Changed spawn function entry points to __spawn*
- instead of spawn*.
- * winnt/x-winnt: New file.
- * fixinc-nt.sed: New file.
- * fixinc.winnt: Rewritten to use fixinc-nt.sed.
+ * sh/elf.h (MAX_OFILE_ALIGNMENT): Undefine before including svr4.h.
- * gcc.c: Remove fix_argv kludge.
+Mon Jul 13 23:36:08 1998 Jim Wilson <wilson@cygnus.com>
-Tue Sep 12 13:24:17 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+ * i386/i386.h (CPP_486_SPEC, CPP_586_SPEC, CPP_686_SPEC): New specs.
+ (CPP_CPU_DEFAULT_SPEC, CPP_CPU_SPEC): Use them.
+ (EXTRA_SPECS): Support them.
+ * gcc.c: Delete %[spec] support.
+ (do_spec_1, case '('): Likewise.
+ (do_spec_1, case '['): Call error.
+ * i386/aix386ng.h, cygwin32.h, freebsd-elf.h, gas.h, isc.h,
+ linux-aout.h, linux-oldld.h, linux.h, osfelf.h, osfrose.h, sco.h,
+ sco4.h, sco4dbx.h, sco5.h, sol2.h, sysv3.h (CPP_SPEC): Delete
+ %[cpp_cpu].
- * rs6000.md (power subdi3 pattern): Fix pattern to have 5
- alternatives, and correct 4th alternative to match reality.
+Mon Jul 13 23:31:04 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- * rs6000.md (adddi3, subdi3, negdi2): Add constraints so output reg
- does not overlap one reg with one of the inputs.
+ * m68k.c (output_scc_di): Use cmpw #0 only for address registers.
-Tue Sep 12 13:09:48 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+Mon Jul 13 23:26:43 1998 Jeffrey A Law (law@cygnus.com)
- * m68k.c (output_scc_di): Fixed for non-SGS_CMP_ORDER syntax.
+ * tree.h (tree_common): Note front-end dependencies on layout of
+ this structure.
- * collect2.c (scan_libraries): Cast lsyms' alloca to LDSYM*.
+Mon Jul 13 23:18:39 1998 Craig Burley <burley@gnu.org>
-Tue Sep 12 13:04:12 1995 Niklas Hallqvist (niklas@appli.se)
+ * stmt.c (expand_expr_stmt): If not assigning fresh
+ value to last_expr_value, zero it, so old garbage
+ doesn't get dereferenced.
- * stmt.c (expand_start_stmt_expr): Do stack adjust in right place.
+Mon Jul 13 23:06:55 1998 Henning.Petersen@t-online.de (Henning Petersen)
- * stdarg.h (__gnuc_va_list): Make char * for NetBSD.
+ * gcse.c (hash_scan_insn): Add missing argument declaration.
-Tue Sep 12 12:44:46 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Mon Jul 13 18:59:13 1998 Jim Wilson <wilson@cygnus.com>
- * ginclude/va-ppc.h (va_arg): Reorganize to avoid BIND_EXPRs of
- aggregate or array type.
+ * configure.in (mips-sgi-irix5cross64, mips-sgi-irix5*): Remove
+ HAVE_INTTYPES_H from xm_defines. Define xm_file to mips/xm-iris5.h.
+ * mips/xm-iris5.h (USG): Delete.
-Tue Sep 12 12:42:27 1995 Ian Lance Taylor <ian@cygnus.com>
+Mon Jul 13 17:18:47 1998 Nick Clifton <nickc@cygnus.com>
- * fixincludes: Fix HP/UX <sys/file.h> for g++ -pedantic-errors.
+ * cccp.c (main): Add support for parsing --help.
+ (display_help): New function: display command line switches.
- * fixincludes (curses.h): typedef bool need not take up entire line.
+ * cpplib.c (cpp_handle_option): Add support for parsing --help.
+ (display_help): New function: display command line switches.
-Mon Sep 11 19:05:42 1995 Stan Cox (coxs@dg-rtp.dg.com)
+ * gcc.c (main): Add support for parsing --help, and passing it on
+ to the sub-processes invoked by gcc.
+ (display_help): New function: display comman line switches.
- * c-typeck.c (digest_init): Don't recursively call digest_init
- when in traditional mode if the type is invalid.
+ * tm.texi (TARGET_SWITCHES and TARGET_OPTIONS): Document
+ 'description' field added to structure.
-Mon Sep 11 18:58:26 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de)
+ * toplev.c: Add support for parsing --help.
+ Add documentation strings to command line option tables.
+ (display_help): New function: display comman line switches.
- * 1750a.md: Added DLB/DSTB peepholes for HFmode.
- Corrected mnemonics for HImode DSTB peephole.
+Mon Jul 13 16:15:10 1998 John Carr <jfc@mit.edu>
-Mon Sep 11 18:48:06 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+ * sparc.c, sparc.h, sparc.md: New trampoline code.
+ Allow integer operand 1 to V8+ DImode shift instructions.
+ Fix bugs in V8+ wide multiply patterns.
+ In 32 bit mode, split DImode register moves and logical instructions.
+ Write V9 branch prediction flag.
+ Use V9 conditional move more often for scc.
- * config/fp-bit.c (FLO_union_type): Remove bitfields to set sign,
- exponent, and mantissa, and add value_raw field, which is an
- integer of the appropriate type. If _DEBUG_BITFLOAT is defined,
- provide little and big endian bitfields. If the macro
- FLOAT_BIT_ORDER_MISMATCH is defined, use explicit bitfields.
- (pack_d, unpack_d): Switch to use value_raw and explicit shifts
- and masks so that we don't have to worry about whether the target
- is big or little endian unless FLOAT_BIT_ORDER_MISMATCH is
- defined. If single precision floating point, rename to pack_f and
- unpack_f, so there is no confusion in the debugger.
+Mon Jul 13 15:10:09 1998 Philippe De Muyter <phdm@macqel.be>
+
+ * invoke.texi(-fno-builtin): Explain that the names of built-in
+ functions begin with `__builtin_', not `__'.
+
+Mon Jul 13 19:01:52 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * reload1.c (reload_reg_free_before_p): Abort for RELOAD_FOR_OUTPUT.
+
+Mon Jul 13 10:50:17 1998 Mark Mitchell <mark@markmitchell.com>
+
+ * cplus-dem.c (SCOPE_STRING): Remove DMGL_JAVA stuff.
+ (cplus_demangle_opname): Initialize work.
+ (demangle_template): Remove is_java_array.
+ (do_type): Remove DMGL_JAVA stuff.
+ (long_options): Remove "java".
+ (main): Remove 'j' option.
+
+Mon Jul 13 10:19:00 1998 Jeffrey A Law (law@cygnus.com)
+
+ * mn10300.h (REG_CLASS_FROM_LETTER): Map 'y' to SP_REGS.
+ Handle 'x' as NO_REGS for this cpu.
+ (REGNO_OK_FOR_BIT_BASE_P): Define.
+ (REG_OK_FOR_BIT_BASE_P): Define.
+ (GO_IF_LEGITIMATE_ADDRESS): Use them.
+ (REG_OK_FOR_INDEX_P): Tweak.
+ * mn13000.c (REG_SAVE_BYTES): Define.
+ (expand_epilogue, initial_offset): Use it.
+ (secondary_reload_class): Slightly reformat.
+ (output_tst): Tweak comments.
+ * mn10300.md: Change 'x' to 'y' for SP_REGS. Then add 'x' to many
+ patterns.
+ (addsi3): Turn into a define_expand/define_insn pair. Rework code for
+ three operand addition case to be more efficient.
+ (subsi3): Turn into a define_expand/define_insn pair.
+
+ * expr.c (expand_expr): Only set MEM_IN_STRUCT_P if the memory address
+ is not varying for REFERENCE_TYPE or when we think we might have found
+ an optimized access to the first element in an array.
+
+Mon Jul 13 02:24:08 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
+
+ * regclass.c (reg_scan_mark_refs): New arg min_regno. Only update
+ regscan information for REGs with numbers greater than or equal to
+ this. All callers changed.
+ (reg_scan_update): New function to efficiently update regscan
+ information on the fly.
+ * rtl.h: Add prototype.
+ * jump.c (jump_optimize): Call it when we make a transformation
+ which generates new pseudo-REGs.
+
+Sun Jul 12 13:08:14 1998 Jeffrey A Law (law@cygnus.com)
+
+ * collect2.c (main): Use "-x c" instead of "-lang-c" for force the
+ compiler into C mode.
+
+Sun Jul 12 01:27:05 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * cplus-dem.c (demangle_nested_args): Return a value.
+
+ * tree.h (TYPE_P): New macro.
+
+Sat Jul 11 16:19:48 1998 Mark Mitchell <mark@markmitchell.com>
+
+ * cplus-dem.c (string): Move definition before work_stuff.
+ (work_stuff): Add volatile_type, forgetting_types,
+ previous_argument, and nrepeats fields.
+ (SCOPE_STRING): New macro.
+ (demangle_template): Add `remember' parameter. Add comment.
+ Register the `B' code type here, if remembering. Tidy. Fix crash
+ on NULL tmpl_argvec. Be consistent with use of tname/trawname.
+ (demangle_nested_args): New function.
+ (internal_cplus_demangle): Handle volatile-qualified member
+ functions.
+ (mop_up): Delete the previous_argument string if present.
+ (demangle_signature): Tidy. Handle volatile-qualified member
+ functions. Handle back-references using the `B' code. Use extra
+ parameter to demangle_template and SCOPE_STRING where appropriate.
+ (demangle_template_value_parm): Fix thinko; 'B' is not an integral
+ code.
+ (demangle_class): Use SCOPE_STRING.
+ (gnu_special): Pass additional argument to demangle_template.
+ Use SCOPE_STRING.
+ (demangle_qualified): Save qualified types for later
+ back-references. Handle constructors and destructors for template
+ types correctly.
+ (do_type): Tidy. Use SCOPE_STRING. Pass extra argument to
+ demangle_template. Use demangled_nested_args. Don't remember
+ qualified types here; that's now done in demangle_qualified.
+ Similarly for templates.
+ (do_arg): Improve commment. Handle 'n' repeat code.
+ (remember_type): Check forgetting_types.
+ (demangle_args): Deal with 'n' repeat codes. Tidy.
- * rs6000.h (rs6000_abi): New enumeration to describe which
- ABI we're conforming to.
- (rs6000_stack): Use abi enum, not AIX vs. V.4 boolean.
- (ASM_OUTPUT_OPTIONS): New macro to print output options in .s file.
- (ASM_FILE_START): Use it.
- (output_options,rs6000_float_const): Declare new functions.
+Sat Jul 11 02:59:08 1998 Richard Earnshaw <rearnsha@arm.com>
- * rs6000.c (output_option{,s}): New functions to write -f, -m,
- and -W options to the asm file.
- (rs6000_float_const): New function to generate floating point
- constants portably used in signed,unsigned -> double conversions.
- (rs6000_stack_info,debug_stack_info): Use ABI enumeration instead
- of AIX vs. V.4 boolean.
+ * arm.md (extendhisi2_mem, movhi, movhi_bytes): Propagate the volatile
+ and structure attribute flags to MEMs generated.
+ (splits for sign-extended HI & QI mode from memory): Also propagate
+ the volatile flag.
- * rs6000.md (float{,uns}sidf2): Call rs6000_float_const to
- portably build the proper floating point constant for conversions.
- (movdi): Properly handle movdi of CONST_{INT,DOUBLE} on little
- endian systems.
+ * configure.in (thumb-*-coff*): Don't cause fixincludes to be run.
- * rs6000/sysv4.h (LIBGCC2_WORDS_BIG_ENDIAN): Define to be 0/1
- depending on the target endianess.
- (ASM_FILE_START): Define, to call output_options in addition to
- output_file_directive.
- (TRAMPOLINE_SIZE): Correct size to match code.
+Fri Jul 10 19:06:59 1998 Michael Meissner <meissner@cygnus.com>
- * rs6000/eabi{,le}sim.h (CPP_SPEC): Define the correct endian
- macro for varargs/stdargs use.
+ * varray.h: Include system.h if it hasn't already been included
+ before to get size_t declared.
-Mon Sep 11 18:41:58 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Fri Jul 10 12:53:58 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
- * c-decl.c (redeclaration_error_message): For TYPE_DECLs, return 0
- if TYPE_MAIN_VARIANT of old type is same as new type.
+ * jump.c (jump_optimize): If after_regscan and our transformations
+ generate new REGs, rerun reg_scan.
-Mon Sep 11 17:39:35 1995 Rob Ryan (robr@cmu.edu)
+Fri Jul 10 11:50:43 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
- * xcoffout.c (xcoff_inlining): New variable, used in place of
- xcoff_current_include_file when determining whether to use
- absolute line numbers.
- (xcoffout_source_file): Switched to using xcoff_inlining to
- determine when to emit .bi/.ei directives.
+ * config/i960/i960.c (i960_address_cost): MEMA operands with
+ positive offsets < 4096 are free.
-Mon Sep 11 16:55:06 1995 Torbjorn Granlund <tege@matematik.su.se>
+Fri Jul 10 12:34:37 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- * m68k.md (cmpdi): Change patterns to allocate scratch register at
- RTL generation time.
- (tstdi): Likewise.
+ * config/m68k/m68k.c (const_uint32_operand): Recognize
+ CONSTANT_P_RTX.
+ (const_sint32_operand): Likewise.
-Sun Sep 3 09:03:50 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Thu Jul 9 22:58:59 1998 Jeffrey A Law (law@cygnus.com)
- * fold-const.c (size_binop): Don't pass 1 to NOTRUNC.
+ * Makefile.in (alias.o): Depend on $(EXPR_H).
-Thu Aug 31 19:27:00 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+Thu Jul 9 18:24:56 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * libgcc2.c: Include longlong.h.
- [L_udivdi3 || L_divdi3 || L_umoddi3 || L_moddi3] (__udivmoddi4):
- Define this `static inline' when defining these, so they all
- remain leaf functions.
+ * reload1.c (choose_reload_regs): If using an equivalence from
+ find_equiv_reg and reg_reloaded_valid is not set for this register,
+ clear the associated spill_reg_store.
-Thu Aug 31 18:38:21 1995 Paul Eggert <eggert@twinsun.com>
+Thu Jul 9 18:12:49 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * c-parse.in (ends_in_label): New %union member.
- (stmts, stmt_or_label): Use new member to avoid lexical lookahead hack.
- (lineno_stmt_or_labels): New rule.
- (lineno_stmt_or_label, stmt_or_label): Yield nonzero if it ends
- in a label.
+ * reload1.c (emit_reload_insns): If an output reload copies only
+ to a secondary reload register, indicate that the secondary reload
+ does the actual store.
-Thu Aug 31 08:31:40 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Thu Jul 9 18:01:05 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * cse.c (canon_hash, CONST_DOUBLE): Hash integer and real
- differently.
- * varasm.c (struct rtx_const): Add new field DI to union.
- (decode_rtx_const, case CONST_DOUBLE): Use to hash CONST_DOUBLE
- representing an integer.
+ * reload.c (find_equiv_reg): If need_stable_sp is set,
+ check if stack pointer is changed directly in a PARALLEL.
- * va-alpha.h (__gnuc_va_list): Make __offset an int.
- * alpha.c (alpha_builtin_saveregs): Properly compute address
- of __offset both both OSF and WINNT.
+Thu Jul 9 10:38:14 1998 Jeffrey A Law (law@cygnus.com)
- * xm-alpha.h (sbrk): Don't define here.
- * gmon.c (sbrk): Define here for __alpha.
- * toplev.c (sbrk): Likewise.
- * mips-tfile.c (malloc, calloc, realloc): Don't define for anybody.
+ * jump.c (duplicate_loop_exit_test): Fix thinko.
- * reload.c (push_reload): Add case for output reload of a SUBREG
- of a hard reg when output mode is invalid for that mode.
- In both that case and existing case for in, don't remove SUBREG.
- * reload1.c (emit_reload_insn): Emit RELOAD_OTHER output reloads last.
+Thu Jul 9 01:30:37 1998 Joel Sherrill <joel@OARcorp.com>
+ Ralf Corsepius <corsepiu@faw.uni-ulm.de>
-Tue Aug 29 19:16:06 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * config/i386/rtemself.h: Updated to keep in sync with
+ config/i386/linux.h.
- * c-common.c (decl_attribute, case A_PACKED): Check is_type first.
- (decl_attribute, case A_T_UNION): Likewise.
- Don't access TYPE_FIELDS if DECL is zero.
- * c-decl.c (finish_struct): If transparent_union attribute
- specified, validate it once we finish laying the union out.
+ * configure.in: Added sh-rtemself.
+ * configure: Rebuilt.
+ * config/sh/rtems.h: Removed -D__ELF__ since it is now COFF.
+ * config/sh/rtemself.h: New file.
-Mon Aug 28 05:58:03 1995 Paul Eggert <eggert@twinsun.com>
+ * config/rs6000/rtems.h: Defined STARTFILE_DEFAULT_SPEC.
- * arm.c (arm_gen_movstrqi): Remove unused variable const_sxteen.
+Wed Jul 8 21:43:14 1998 Jeffrey A Law (law@cygnus.com)
- * bi-lexer.c (buffer, inpoint): Remove unused variables.
+ * configure.in: Check if the assembler supports ".balign" and
+ ".p2align" and define HAVE_GAS_BALIGN_AND_P2ALIGN appropriately.
+ * acconfig.h (HAVE_GAS_BALIGN_AND_P2ALIGN): New tag.
+ * i386/gas.h (ASM_OUTPUT_ALIGN): If the assembler has support for
+ ".balign" then use it.
- * i370/mvs.h, i370/mvs370.c (mvs_label_emitted): Renamed
- from mvs_label_emited.
+ * print-rtl.c (print_rtx): Revert previous patch.
- * msdos/configur.bat: Fix misspelling of `maintainer-clean'.
+ * jump.c (duplicate_loop_exit_test): Do not duplicate the loop exit
+ test if the exit code has an insn with ASM_OPERANDS.
-Sat Aug 26 06:57:17 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * i386/cygwin32.h (STDIO_PROTO): Fix typo.
+ * m32r.h (STDIO_PROTO): Fix typo.
- * reload.c (push_secondary_reload): If X is a paradoxical SUBREG,
- get mode and thing to reload from inside.
- * reload1.c (emit_reload_insns): Do nothing for SUBREG whose
- operand is unused subsequently.
- In secondary reload case, if paradoxical SUBREG for output, reload
- thing inside SUBREG, just like gen_reload.
+ * pa.h (LEGITIMIZE_RELOAD_ADDRESS): Handle addresses created by
+ LEGITIMIZE_RELOAD_ADDRESS.
+ * tm.texi (LEGITIMIZE_RELOAD_ADDRESS): Note that this macro must be
+ able to handle addresses created by previous invocations of the macro.
-Fri Aug 25 19:26:53 1995 Paul Eggert <eggert@twinsun.com>
+ * flow.c (find_auto_inc): Remove most recent change. Real bug was
+ elsewhere.
- * c-typeck.c (set_init_label): Don't die if an entire
- brace-pair level is superfluous in the containing level.
+ * cse.c (count_reg_usage): Count registers used in addresses of
+ CLOBBERs.
-Fri Aug 25 19:22:46 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+Wed Jul 8 15:08:29 1998 Jim Wilson <wilson@cygnus.com>
- * configure (powerpc{,le}-eabisim): Add support for a new target
- that works under the PSIM simulator.
- * rs6000/eabisim.h, rs6000/eabilesim.h, rs6000/t-eabisim: New files.
+ * Makefile.in (STAGESTUFF): Readd line lost during June 9 FSF merge.
- * rs6000/eabi.h (STRICT_ALIGNMENT): If little endian, always set
- strict alignment to 1.
+ * configure.in (mips64orion-*-rtems*): Use elf64.h not elfl64.h.
-Fri Aug 25 19:22:23 1995 David Edelsohn <edelsohn@mhpcc.edu>
+1998-07-08 Vladimir N. Makarov <vmakarov@cygnus.com>
- * rs6000.md ({add,sub,mulsi}di3): Support both endian possibilities.
- (negdi2): Likewise.
+ * config/fp-bit.c (__gexf2, __fixxfsi, __floatsixf): Add function
+ stubs.
-Fri Aug 25 19:10:41 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de)
+ * toplev.c (lang_options): Add -Wlong-long, -Wno-long-long
+ options.
+ * c-decl.c (warn_long_long): Define.
+ (c_decode_option): Parse -Wlong-long, -Wno-long-long options.
+ (grokdeclarator): Add flag `warn_long_long' as guard for
+ warning "ANSI C does not support `long long'".
+ * invoke.texi: Add description of options -Wlong-long,
+ -Wno-long-long.
+ * gcc.1: The same as above.
+
+Wed Jul 8 02:43:34 1998 Jeffrey A Law (law@cygnus.com)
- * 1750a.md: Added peephole definitions for Load/Store Base insns
- and eliminating redundant load in an equivalent store/load sequence.
+ * rtlanal.c (reg_overlap_mentioned_p): Handle STRICT_LOW_PART. If
+ either argument is CONSTANT_P, then return zero.
+ * reload.c (reg_overlap_mentioned_for_reload_p): Similarly.
-Fri Aug 25 18:33:27 1995 Craig Burley (burley@gnu.ai.mit.edu)
+ * configure.in: Also look at $srcdir/gas/configure to find a
+ gas version #.
- * toplev.c (report_error_function): Don't attempt to use input
- file stack to identify nesting of #include's if file name oflocation
- diagnosed is not same as input_filename.
+Wed Jul 8 00:28:22 1998 Carlo Wood <carlo@runaway.xs4all.nl>
-Fri Aug 25 07:31:47 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * dsp16xx.h : Clean up of macro OPTIMIZATION_OPTIONS
- * integrate.c (output_inline_function): Switch to function obstack.
+Tue Jul 7 21:18:14 1998 Mumit Khan <khan@xraylith.wisc.edu>
-Mon Aug 21 13:29:54 1995 J"orn Rennecke (amylaar@meolyon.hanse.de)
+ * i386/cygwin32.h (ASM_DECLARE_FUNCTION_NAME): Merge duplicate
+ definitions from last two patches.
- * i386.c (arithmetic_comparison_operator): New function.
- (print_operand): Take into account that overflow flag is not
- set the same as after a compare instruction.
- * i386.md (decrement_and_branch_until_zero): Use
- arithmetic_comparison_operator to decide if there is comparison
- suitable to be expressed by condition code from an arithmetic op.
+Tue Jul 7 23:03:34 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
-Mon Aug 21 13:26:13 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ * reload1.c (choose_reload_regs): Don't set reload_override_in
+ if EQUIV is clobbered in INSN and the reload is done after INSN.
- * m68k.md (adddi3, subdi3): "&" added to clobber's constraints.
+Tue Jul 7 21:23:36 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
-Mon Aug 21 12:11:14 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * expr.c (emit_queue): If emitting a SEQUENCE, set QUEUED_INSN
+ to the first insn of the sequence.
- * t-sparclite (MULTILIB_*, LIBGCC, INSTALL_LIBGCC): Define.
+Tue Jul 7 21:05:25 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * sh.md (movdi-1, movdf-1): Make conditional on reload_completed,
- delete conditions checking for pseudo registers and Q addresses.
- Add code to handle SUBREG.
+ * cse.c (cse_insn): Don't make change without validation.
- * local-alloc.c (wipe_dead_reg): Make a register mentioned in a
- REG_INC note die after the instruction.
+Tue Jul 7 11:40:05 1998 Jeffrey A Law (law@cygnus.com)
- * m68k.md: For all dbra pattern, change constraint from 'g' to 'd*g'.
+ * mn10200.md (various zero/sign extension patterns): zero and sign
+ extensions which use "sub" clobber cc0.
- * Makefile.in: (underscore.c): Rename rule to stamp-under, and
- touch stamp-under at the end. Add new rule for underscore.c that
- depends on stamp-under.
+Tue Jul 7 09:12:08 PDT 1998 Jeff Law (law@cygnus.com)
- * sh.c (reg_unused_after): For a SEQUENCE, make sure all insns are
- safe before returning 1.
+ * version.c: Bump for snapshot.
- * sh.h (PROMOTE_FUNCTION_ARGS, PROMOTE_FUNCTION_RETURN): Define.
+Tue Jul 7 10:07:20 1998 Jeffrey A Law (law@cygnus.com)
- * sh.c (output_stack_adjust): Add new argument reg. Use it instead
- of stack_pointer_rtx.
- (sh_expand_prologue, sh_expand_epilogue): Pass new argument to
- output_stack_adjust.
+ * print-rtl.c (print_rtx): Use REAL_VALUE_TYPE instead of "double".
-Sat Aug 19 17:34:15 1995 Jim Wilson <wilson@phydeaux.cygnus.com>
+Tue Jul 7 08:41:27 1998 Richard Henderson (rth@cygnus.com)
- * sparc/gmon-sol2.c (_mcount): Define.
- * sparc/sol2.h (STARTFILE_SPEC, ENDFILE_SPEC): Delete superfluous
- -pg tests.
- (LINK_SPEC): Add libp directories to -Y when -pg.
+ * print-rtl.c (print_rtx): Only print fp values when REAL_VALUE_TYPE
+ is a double.
- * unroll.c (calculate_giv_inc): Handle increment computed by ASHIFT.
+Tue Jul 7 00:31:58 PDT 1998 Jeff Law (law@cygnus.com)
-Sat Aug 19 17:28:56 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ * version.c: Bump for snapshot.
- * m68k.md (subdi3): Should not be commutative.
- (one_cmpldi2): Fixed typo with register operand.
+Tue Jul 7 01:03:03 1998 Mumit Khan <khan@xraylith.wisc.edu>
-Sat Aug 19 17:20:43 1995 Michael Meissner <meissner@cygnus.com>
+ Support for dllimport and dllexport attributes for i386-pe.
- * rs6000.c (output_prolog): Fixup code to set stack pointer
- if stack size > 32k.
- * rs6000.md (sync_isync): Renamed from sync; added an isync insn
- after the sync to properly deal with PowerPC's with split I/D caches.
- * sysv4.h (INITIALIZE_TRAMPOLINE): Sync function now named sync_isync.
+ * tree.h (DECL_NON_ADDR_CONST_P): New accessor macro.
+ (struct tree_decl): Add non_addr_const_p field.
+ * tree.c (staticp): Use.
-Sat Aug 19 17:07:09 1995 Doug Evans <dje@canuck.cygnus.com>
+ * i386/cygwin32.h (CPP_PREDEFINES): Map __declspec(x) to GCC
+ attributes.
+ (SUBTARGET_SWITCHES): Switches to turn on/off dllimport|export
+ attributes. Also accept -mwindows option.
+ (VALID_MACHINE_DECL_ATTRIBUTE): New macro.
+ (MERGE_MACHINE_DECL_ATTRIBUTE): New macro.
+ (REDO_SECTION_INFO_P): New macro.
+ (DRECTVE_SECTION_FUNCTION): New macro.
+ (drectve_section): Cover function to implement above.
+ (SWITCH_TO_SECTION_FUNCTION): New macro.
+ (switch_to_section): Covert function to implement above.
+ (EXTRA_SECTIONS): Add in_drectve.
+ (EXTRA_SECTION_FUNCTIONS): Add in_drectve and switch_to_section.
+ (ENCODE_SECTION_INFO): Delete old macro and redefine as a function.
+ (STRIP_NAME_ENCODING): Handle new attributes.
+ (ASM_OUTPUT_LABELREF): New macro.
+ (ASM_OUTPUT_FUNCTION_NAME): New macro.
+ (ASM_OUTPUT_COMMON): New macro.
+ (ASM_OUTPUT_DECLARE_OBJECT_NAME): New macro.
- * h8300.h (STATIC_CHAIN_REGNUM): Use r3.
- (REGISTER_NAMES): Print r7 as sp.
- (ADDITIONAL_REGISTER_NAMES): Recognize r7.
- (ASM_OUTPUT_ALIGN): Alignment is power of 2.
- * h8300.md (fancy_btst,fancy_btst1): Branch target must be
- operand 0 for length attribute to work.
+ * i386/mingw32.h (CPP_PREDEFINES): Map __declspec(x) to GCC
+ attributes.
-Sat Aug 19 16:43:11 1995 Paul Franklin <paul@cs.washington.edu>
+ * i386/winnt.c (i386_pe_valid_decl_attribute_p): New function.
+ (i386_pe_merge_decl_attributes): New function.
+ (i386_pe_check_vtable_importexport): New function.
+ (i386_pe_dllexport_p): New function.
+ (i386_pe_dllimport_p): New function.
+ (i386_pe_dllexport_name_p): New function.
+ (i386_pe_dllimport_name_p): New function.
+ (i386_pe_mark_dllexport): New function.
+ (i386_pe_mark_dllimport): New function.
+ (i386_pe_encode_section_info): New function.
+ (i386_pe_unique_section): Strip encoding from name first.
- * assert.h: Declare __eprintf with attribute noreturn.
+Tue Jul 7 00:50:17 1998 Manfred Hollstein (manfred@s-direktnet.de)
-Sat Aug 19 16:40:12 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * libgcc2.c (L_exit): Provide a fake for atexit on systems which
+ define ON_EXIT but not HAVE_ATEXIT.
- * stddef.h: Don't define wchar_t if __cplusplus is defined.
+Tue Jul 7 00:44:35 1998 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
-Tue Aug 15 18:01:01 1995 Paul Eggert <eggert@twinsun.com>
+ * m68k.md (zero_extend QI to HI): Correctly handle TARGET_5200.
- * cccp.c (warning_with_line): Fix typo in declaration when
- !HAVE_VPRINTF and defined (__STDC__).
+Tue Jul 7 00:36:41 1998 Ulrich Drepper <drepper@cygnus.com>
-Tue Aug 15 17:57:54 1995 Stephen L Moshier <moshier@world.std.com>
+ * i386.c: Remove random whitespace at end of lines.
- * real.c (ediv, emul): Set sign bit of IEEE -0.0 result.
+ * i386.c (ix86_epilogue): For pentium processors, try to deallocate
+ 4 or 8 byte stacks with pop instructions instead of an add instruction.
-Tue Aug 15 17:49:47 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Jul 7 00:30:08 1998 Klaus Kaempf <kkaempf@rmi.de>
- * expr.c (safe_from_p): Only safe if EXP is variable-size and X
- is BLKmode.
+ * alpha.c: Include tree.h before expr.h.
- * stmt.c (fixup_gotos): When some fixups done, reset to point
- to next instead of zeroing TREE_VALUE, which may be shared.
+Mon Jul 6 22:50:48 1998 Jason Merrill <jason@yorick.cygnus.com>
-Mon Aug 14 09:15:45 1995 Doug Evans <dje@canuck.cygnus.com>
+ * c-parse.in (struct_head, union_head, enum_head): New nonterminals.
+ (structsp): Use them. Update files generated from c-parse.in.
+ * extend.texi (Type Attributes): Document it.
- * m68k/m68kemb.h (STARTFILE_SPEC): Define as empty.
+ * c-decl.c: Add warn_multichar.
+ (c_decode_option): Handle -Wno-multichar.
+ * c-lex.c (yylex): Check it.
+ * c-tree.h: Declare it.
+ * toplev.c (lang_options): Add it.
+ * invoke.texi: Document it.
-Mon Aug 14 09:08:57 1995 Pat Rankin <rankin@eql.caltech.edu>
+Mon Jul 6 22:47:55 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * vax.c (vms_check_external): Update `pending_head' properly
- when the first list element is removed.
+ * reload.c (find_equiv_reg): When looking for stack pointer + const,
+ make sure we don't use a stack adjust.
-Mon Aug 14 09:01:32 1995 Jeffrey A. Law <law@adder.cygnus.com>
+ * reload.c (find_equiv_reg): If need_stable_sp is set,
+ check if stack pointer is changed directly.
- * pa.md (call expanders): Emit a blockage insn after restoring
- %r19 when generating PIC.
+ * reload1.c (delete_dead_insn): Don't delete feeding insn
+ if that insn has side effects.
-Sun Aug 13 21:58:49 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * flow.c (find_auto_inc): Clear UNCHANGING bit of register that is
+ changed.
- * toplev.c (main): Change text of unsupported -g option warning.
+ * reload1.c (reload_reg_free_before_p): RELOAD_FOR_OPADDR_ADDR
+ precedes RELOAD_FOR_OUTADDR_ADDRESS.
-Sun Aug 13 21:47:57 1995 Andrew McCallum <mccallum@graphite.cs.rochester.edu>
+ * gcse.c (hash_scan_insn): New argument IN_LIBCALL_BLOCK. Changed
+ caller.
- * objc/selector.c (sel_get_any_typed_uid): New function.
- * objc/objc-api.h (sel_get_any_typed_uid): Declare new function.
+Mon Jul 6 22:21:56 1998 Kamil Iskra <iskra@student.uci.agh.edu.pl>
-Sun Aug 13 21:43:17 1995 John Carr <jfc@mit.edu>
+ * m68k.c (output_scc_di): Use cmpw #0 instead of tstl when
+ testing address registers on the 68000.
- * c-typeck.c (c_expand_asm_operands): Check for read-only output
- operand where the variable is read-only but the type is not.
+Mon Jul 6 22:17:19 1998 Alasdair Baird <alasdair@wildcat.demon.co.uk>
-Sun Aug 13 21:16:12 1995 David Edelsohn <edelsohn@mhpcc.edu>
+ * i386.c (is_fp_test): Fix thinko.
- * rs6000.c (direct_return): Epilogue required if CR saved.
+ * jump.c (jump_optimize) Check for CONST_INT before using INTVAL.
-Sun Aug 13 19:09:25 1995 Jeff Law (law@snake.cs.utah.edu)
+Mon Jul 6 22:14:31 1998 Richard Henderson (rth@cygnus.com)
- * configure (hppa1.?-hp-hpux10): Recognize and treat just like hpux9.
+ * print-rtl.c (print_rtx): Display the real-value equivalent of
+ a const_double when easy.
-Sun Aug 13 19:07:23 1995 Doug Evans <dje@canuck.cygnus.com>
+ * real.h (REAL_VALUE_TO_TARGET_SINGLE): Use a union to pun types.
+ Zero memory first for predictability.
+ (REAL_VALUE_TO_TARGET_DOUBLE): Likewise.
+ * varasm.c (immed_real_const_1): Notice width of H_W_I == double.
- * i960.md (movdi matchers): Fix src/dest order in unaligned
- reg->reg case.
+ * regclass.c (allocate_reg_info): Initialize the entire reg_data
+ virtual array.
-Sun Aug 13 18:49:01 1995 DJ Delorie <dj@delorie.com>
+Mon Jul 6 22:09:32 1998 Ian Lance Taylor <ian@cygnus.com>
+ Jeff Law <law@cygnus.com>
- * i386/xm-dos.h (HAVE_STRERROR): New definition.
- * msdos/configur.bat: Add missing carriage return.
+ * i386/cygwin32.h: Add some declaration of external functions.
+ (ASM_DECLARE_FUNCTION_NAME): Define.
+ (ASM_OUTPUT_EXTERNAL, ASM_OUTPUT_EXTERNAL_LIBCALL): Define.
+ (ASM_FILE_END): Define.
+ * i386/winnt.c (i386_pe_declare_function_type): New function.
+ (struct extern_list, extern_head): Define.
+ (i386_pe_record_external_function): New function.
+ (i386_pe_asm_file_end): New function.
-Sun Aug 13 18:40:55 1995 Andrew Cagney <cagney@highland.com.au>
+ * cpplib.c (cpp_options_init): Initialize cplusplus_comments to 1,
+ matching July 18, 1995 change to cccp.c. If -traditional then
+ disable cplusplus_comments.
- * Makefile.in (USER_H): Add va-ppc.h.
+Mon Jul 6 21:28:14 1998 Jeffrey A Law (law@cygnus.com)
-Sun Aug 13 18:36:17 1995 M. Warner Losh <imp@village.org>
+ * combine.c (expand_compound_operation): Fix thinko in code to optimize
+ (zero_extend:DI (subreg:SI (foo:DI) 0)) to foo:DI.
- * stmt.c (expand_asm_operands): Type '0'..'4' operands may
- allow regs, so move them to the default case.
+ * Disable the following change from gcc2. Not appropriate for egcs:
-Sun Aug 13 18:32:35 1995 Paul Eggert <eggert@twinsun.com>
+ Sun Jun 7 09:30:31 1998 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+ * reload.c (find_reloads): Give preference to pseudo that was the
+ reloaded output of previous insn.
- * cccp.c (warning_with_line): New function.
- (trigraph_pcp): Use it, to avoid reporting line number.
- (vwarning_with_line): Don't report line number if zero.
+Mon Jul 6 21:07:14 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
-Sun Aug 13 18:23:08 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * aclocal.m4 (GCC_FUNC_PRINTF_PTR): Don't define HOST_PTR_PRINTF.
+ Instead, define a new macro HAVE_PRINTF_PTR which only signifies
+ whether we have the %p format specifier or not.
- * toplev.c (vmessage): Support four arguments.
+ * acconfig.h: Delete stub for HOST_PTR_PRINTF, add HAVE_PRINTF_PTR.
+
+ * machmode.h (HOST_PTR_PRINTF): When determining the definition,
+ check HAVE_PRINTF_PTR to see whether "%p" is okay.
-Sun Aug 13 18:19:51 1995 Michael Meissner <meissner@cygnus.com>
+ * mips-tfile.c: Include machmode.h to get HOST_PTR_PRINTF.
- * ginclude/stdarg.h: Add ppc svr4 calling sequence support.
- * ginclude/varargs.h: Likewise.
- * ginclude/va-ppc.h: New file.
+ * Makefile.in (mips-tfile.o): Depend on machmode.h.
-Sun Aug 13 18:05:20 1995 Michael Gschwind <mike@donoussa.vlsivie.tuwien.ac.at>
+Mon Jul 6 10:42:05 1998 Mark Mitchell <mark@markmitchell.com>
- * configure (pdp-*-*): Add support for t-pdp11.
- * t-pdp11: New file.
- * Makefile.in (LIBGCC2_CFLAGS): Add TARGET_LIBGCC2_CFLAGS.
+ * jump.c (duplicate_loop_exit_test): Don't refuse to copy a
+ section of code just because it contains
+ NOTE_INSN_BLOCK_{BEG,END}.
+ * stmt.c (expand_end_loop): Likewise. Also, don't refuse to
+ move CALL_INSNs or CODE_LABELs. When moving code, don't move
+ NOTE_INSN_BLOCK_{BEG,END}.
-Sun Aug 13 14:50:58 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Mon Jul 6 09:38:15 1998 Mark Mitchell <mark@markmitchell.com>
- * final.c (final_start_function): Always call sdbout_begin_function
- and xcoffout_begin_function, even if no line number info.
+ * cse.c (CSE_ADDRESS_COST): New macro, based on ADDRESS_COST, but
+ dealing with ADDRESSOF.
+ (find_best_addr): Use it.
- * mips/abi64.h (SETUP_INCOMING_VARARGS): In if statement, only
- subtract one for stdarg. Don't subtract PRETEND_SIZE from
- argument pointer when calculating stack address.
- * mips.h (INITIAL_ELIMINATION_OFFSET): For 64 bit ABI, subtract
- current_function_pretend_args_size when converting from argument
- pointer.
- * va-mips.h (va_start): For stdarg, delete separate define for
- 64 bit ABI. For varargs, don't subtract 64, and only add -8 when
- all argument registers are used.
+Mon Jul 6 09:27:08 1998 Richard Henderson <rth@cygnus.com>
- * gcc.c (main): When concat gcc_exec_prefix and
- standard_startfile_prefix, put machine_suffix in the middle.
+ * alpha/vms.h (TRAMPOLINE_TEMPLATE): Revert last change.
- * iris6.h (INIT_SECTION_ASM_OP): Don't define.
- (LD_INIT_SWITCH, LD_FINI_SWITCH, HAS_INIT_SECTION): Don't undef.
- (ASM_OUTPUT_CONSTRUCTOR, ASM_OUTPUT_DESTRUCTOR): Ifdef out.
- * configure (mips-sgi-irix6, mips-sgi-irix5cross64): Define
- use_collect2 to yes.
+Mon Jul 6 09:25:06 1998 Dave Love <d.love@dl.ac.uk>
- * combine.c (move_deaths): When have a multi-reg hard register,
- if don't find a note, then recur for each individual hard register.
+ * libgcc2.c (__eprintf): Make args consistent with prototype in
+ assert.h.
- * cse.c (set_nonvarying_address_components): Handle addresses
- which are the sum of two constant pseudo regs.
- (cse_rtx_addr_varies_p): Likewise.
+Mon Jul 6 00:28:43 1998 Mark Mitchell <mark@markmitchell.com>
- * Makefile.in (gfloat.h): Add a - before the rm command.
+ * cse.c (cse_insn): When SETting (MEM (ADDRESSOF (X))) to Y,
+ don't claim that the former is equivalent to the latter.
- * loop.c (find_and_verify_loops): Set dest_loop only if
- JUMP_LABEL (insn) is non-zero.
+Sun Jul 5 23:58:19 1998 Jeffrey A Law (law@cygnus.com)
-Mon Jul 31 14:31:53 1995 Ian Lance Taylor <ian@cygnus.com>
+ * cse.c (cse_insn): Second arg is an RTX now. Update all callers.
+ (cse_basic_block): Keep track of the current RETVAL insn for a
+ libcall instead of just noting that we're in a libcall.
- * fixincludes: Avoid clobbering VxWorks drv/netif/if_med.h file.
+ * combine.c (simplify_comparison): Do not commute a AND into
+ a paradoxical SUBREG if not WORD_REGISTER_OPERATIONS.
-Sat Jul 29 16:21:42 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * i386/freebsd-elf.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Protect with
+ HAVE_GAS_MAX_SKIP_P2ALIGN.
+ * i386/linux.h: Likewise.
+
+Fri Jul 3 02:33:35 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
+
+ * sparc.c (sparc_operand, move_operand, arith_operand,
+ arith11_operand, arith10_operand, arith_double_operand,
+ arith11_double_operand, arith10_double_operand, small_int,
+ uns_small_int): Recognize CONSTANT_P_RTX.
+ (output_sized_memop, output_move_with_extension,
+ output_load_address, output_size_for_block_move,
+ output_block_move, delay_operand): Remove, has not been
+ enabled or referenced for years.
+ * sparc.md (movstrsi, block_move_insn): Likewise.
+ * sparc.h (PREDICATE_CODES): Define.
+ * linux-aout.h (MACHINE_STATE_{SAVE,RESTORE}): Override with
+ version which uses getcc/setcc traps to save/restore condition
+ codes.
+ * linux64.h: Likewise.
+ * sunos4.h: Likewise.
+ * linux.h: Likewise.
+ * sol2.h: Likewise.
+ * sun4o3.h: Likewise.
+
+Fri Jul 3 02:28:05 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_initialize_trampoline): Hack around Pmode/ptr_mode
+ lossage on VMS. Reported by kkaempf@rmi.de.
+ * alpha/vms.h (TRAMPOLINE_TEMPLATE): Add missing 0.
+
+Thu Jul 2 17:41:14 1998 Nick Clifton <nickc@cygnus.com>
+
+ * config/m32r/m32r.h (MUST_PASS_IN_STACK): Override default
+ version.
+
+Thu Jul 2 14:34:48 1998 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * expr.h (STACK_SIZE_MODE): New macro.
+ * explow.c (allocate_dynamic_stack_space): Use it for
+ mode of allocate_stack pattern increment operand.
+ * tm.texi (STACK_SAVEAREA_MODE, STACK_SIZE_MODE): Document.
+ * md.texi (stack_save_block, ...): Reflect use of macro.
+
+ * rs6000.h (PROMOTE_MODE): Always promote to word_mode.
+ (PROMOTE_FUNCTION_ARGS): Define.
+ (PROMOTE_FUNCTION_RETURN): Define.
+ (FUNCTION_VALUE): Promote to word_mode if smaller.
+ Convert to gen_rtx_FOO.
+ * rs6000.md (call_indirect): Store doubleword in 64-bit mode.
+ Convert to gen_rtx_FOO.
+ * rs6000.c: Convert to gen_rtx_FOO.
+
+Thu Jul 2 14:16:11 1998 Michael Meissner <meissner@cygnus.com>
- * collect2.c: (XCOFF_SCAN_LIBS): Define if OBJECT_FORMAT_COFF and
- XCOFF_DEBUGGING_FORMAT.
- (SCAN_LIBRARIES): Also define if XCOFF_SCAN_LIBS.
+ * varray.{c,h}: New files to provide virtual array support.
-Sat Jul 29 16:19:42 1995 Stuart D. Gathman <stuart@bmsi.com>
+ * Makefile.in (OBJS): Add varray.o.
+ (varray.o): Add new file.
+ (REGS_H): New variable for dependencies for files including
+ regs.h. Add varray.h and files it includes. Change all regs.h
+ dependencies to $(REGS_H).
- * collect2.c (scan_libraries): Implement for AIX.
+ * toplev.c (x{m,re}alloc): If size is 0, allocate 1 byte.
+ (xcalloc): Provide frontend for calloc.
+ * {tree,rtl}.h (xcalloc): Add declaration.
-Sat Jul 29 09:59:33 1995 Michael Gschwind <mike@lanai.vlsivie.tuwien.ac.at>
+ * basic-block.h (REG_BASIC_BLOCK): Convert reg_n_info to be a
+ varray.
- * configure: (pdp11-*-bsd) New target.
- * 2bsd.h: New file.
+ * regs.h (toplevel): Include varray.h.
+ (reg_n_info): Switch to use a varray.
+ (REG_*): Ditto.
+ (allocate_reg_info): Change num_regs argument to be size_t.
- * pdp11.c (output_move_double): Handle CONST_INT parameters properly.
- * pdp11.h (RTX_COSTS): Fill in missing default values.
- * pdp11.md (truncdfsf2, extendsfdf2, floatsidf2, fix_truncdfsi2):
- Allow register parameters, required by gcc to generate correct code.
- * xm-pdp11.h: Include tm.h.
+ * regclass.c (reg_info_data): New structure to remember groups of
+ reg_info structures allocated that are to be zeroed.
+ ({pref,alt}class_buffer): New statics to hold buffers
+ allocate_reg_info allocates for {pref,alt}class_buffer.
+ (regclass): Use {pref,alt}class_buffer to initialize
+ {pref,alt}class.
+ (allocate_reg_info): Switch to make reg_n_info use varrays.
+ Allocate buffers for the preferred and alter register class
+ information. Change num_regs argument to be size_t, not int.
-Sat Jul 29 09:55:17 1995 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+ * flow.c (reg_n_info): Switch to use varrays.
- * configure (m68k-*-linux*aout*, m68k-*-linux*): New targets.
- * m68k/linux-aout.h, m68k/linux.h, m68k/t-linux, m68k/xm-linux.h: New.
- * m68k.md [USE_GAS]: Output `jbsr' instead of `jsr' for normal
- function calls and `bsr.l' instead of `bsr' for pic function calls.
+Thu Jul 2 10:11:47 1998 Robert Lipe <robertl@dgii.com>
-Sat Jul 29 09:44:13 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * install.texi (sco3.2v5): Document new --with-gnu-as flag.
+ * config/i386/sco5.h (JUMP_TABLES_IN_TEXT_SECTION): Defined as
+ in other targets.
+ (USE_GAS): Conditionalize away native assembler usage.
+ * config/i386/sco5gas.h: New file.
+ * config/i386/t-sco5gas: New file.
+ * configure.in (ix86-sco3.2v5*): Use new files if --with-gnu-as
- * sh.h (CAN_DEBUG_WITHOUT_FP): Comment out.
+Thu Jul 2 08:20:00 1998 Catherine Moore <clm@cygnus.com>
- * reload.c (find_reloads_address_1, case PLUS): When handle SUBREG,
- add SUBREG_WORD offset to SUBREG_REG register number.
- (find_reloads_address_1, case SUBREG): If a pseudo register inside
- a SUBREG is larger than the class, then reload the entire SUBREG.
- * sh.h (SUBREG_OK_FOR_INDEX_P): New macro.
- (INDEX_REGISTER_RTX_P): Use it.
+ * haifa-sched.c (alloc_EXPR_LIST): Change to use
+ unused_expr_list.
-Sat Jul 29 09:33:19 1995 Doug Evans <dje@canuck.cygnus.com>
+Thu Jul 2 14:13:28 1998 Dave Love <d.love@dl.ac.uk>
- * mips/netbsd.h (CPP_SPEC): Fix typo.
+ * Makefile.in (install-info): Don't use $realfile. Ignore
+ possible errors from the install-info program.
- * configure (a29k-*-vxworks*): Define extra_parts for crt{begin,end}.o.
- * t-a29k, t-a29kbase, t-vx29k ({,CROSS_}LIBGCC1): Define as empty.
+Thu Jul 2 01:53:32 1998 Alasdair Baird <alasdair@wildcat.demon.co.uk>
-Sat Jul 29 09:15:17 1995 Jeffrey A. Law <law@rtl.cygnus.com>
+ * combine.c (simplify_comparison): Apply SUBREG_REG to SUBREGs.
- * pa/lib2funcs.asm (gcc_plt_call): Rewrite to avoid the need
- for being called by _sr4export. Inline expand $$dyncall to
- avoid the need for long-call and PIC support.
+Wed Jul 1 23:06:03 1998 Richard Henderson <rth@cygnus.com>
-Sat Jul 29 07:30:04 1995 Oliver Kellogg (Oliver.Kellogg@space.otn.dasa.de)
+ * i386.h (HARD_REGNO_MODE_OK): Kill spurrious test.
+ (MODES_TIEABLE_P): Tie SImode and HImode.
- * ms1750.inc (ucim.m, ucr.m, uc.m): New.
- * 1750a.md (cmpqi): Account for unsigned comparisons.
- (rotrqi3, rotrhi3): Reworked.
- * 1750a.c (notice_update_cc): INCM and DECM set condition codes.
- (unsigned_comparison_operator, next_cc_user_is_unsigned): New fcns.
- * 1750a.h (FUNCTION_EPILOGUE): Local variables freed from SP, not FP.
- (ASM_OUTPUT_BYTE): Make distinct from ASM_OUTPUT_CHAR.
- (ASM_OUTPUT_CONSTRUCTOR): Add FILE arg to assemble_name.
+1998-07-01 Andreas Jaeger <aj@arthur.rhein-neckar.de>
-Fri Jul 28 09:40:07 1995 Jeffrey A. Law <law@rtl.cygnus.com>
+ * invoke.texi (Optimize Options): Fix typo.
- * pa.h (DO_GLOBAL_DTORS_BODY): Use an asm statement to keep optimizer
- from deleting an assignment it believes dead.
+Wed Jul 1 22:25:43 1998 Jim Wilson <wilson@cygnus.com>
-Fri Jul 28 08:47:51 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * xcoffout.c (xcoffout_begin_function): Call xcoffout_block for
+ the zero'th block.
- * unroll.c (unroll_loop): When preconditioning, output code to
- execute loop once if initial value is greater than or equal to final
- value.
+Wed Jul 1 23:12:58 1998 Ken Raeburn <raeburn@cygnus.com>
+
+ * h8300.c (print_operand): Delete %L support.
+ * h8300.md (branch_true, branch_false): Use %= with a prefix
+ instead of %L for local branch labels.
+
+Wed Jul 1 21:27:13 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * reload1.c (emit_reload_insns): Use proper register classes for
+ SECONDARY_INPUT_RELOAD_CLASS / SECONDARY_MEMORY_NEEDED code.
+
+Wed Jul 1 21:17:36 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * reload.c (find_reloads): If there are multiple
+ RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_OUTPUT_ADDRESS reloads for
+ one operand, change RELOAD_FOR_INPADDR_ADDRESS /
+ RELOAD_FOR_OUTADDR_ADDRESS for all but the first
+ RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_OUTPUT_ADDRESS reloads.
+
+Wed Jul 1 17:23:23 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * regmove.c (fixup_match_2): Check that P has RTX_CLASS 'i' before
+ using its PATTERN.
+
+Wed Jul 1 05:04:41 1998 Richard Henderson <rth@cygnus.com>
+
+ * expr.c (emit_group_load, emit_group_store): Rewrite considering
+ the size and alignment of the structure being manipulated.
+ * expr.c, calls.c, function.c: Update all callers.
+ * expr.h: Update prototypes.
+ * cse.c (invalidate): Cope with parallels.
+
+Wed Jul 1 04:22:23 1998 Richard Henderson <rth@cygnus.com>
+
+ * sparc.c (function_arg_record_value): Take a MODE arg with which to
+ create the PARALLEL. Update all callers.
+
+Wed Jul 1 04:10:35 1998 Richard Henderson <rth@cygnus.com>
+
+ * expr.c (expand_assignment, store_constructor, expand_expr): Use
+ convert_memory_address instead of convert_to_mode when possible.
+
+Wed Jul 1 03:48:00 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_initialize_trampoline): Take arguments describing
+ the layout. Use ptr_mode. Disable hint generation. Use gen_imb.
+ * alpha.h (INITIALIZE_TRAMPOLINE): Pass extra args to the init func.
+ (TRANSFER_FROM_TRAMPOLINE): Move ...
+ * alpha/osf.h: ... here.
+ * alpha/vms.h (INITIALIZE_TRAMPOLINE): Use alpha_initialize_trampoline.
+ (TRANSFER_FROM_TRAMPOLINE): Remove undef.
+ * alpha/win-nt.h: Likewise.
+ * alpha/vxworks.h: Likewise.
+
+ * alpha/linux.h: Revert gcc2 merge lossage.
+
+Wed Jul 1 10:56:55 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * c-decl.c (grokdeclarator): Don't warn about implicit int in
+ `typedef foo = bar'.
+
+Wed Jul 1 02:12:33 1998 Robert Lipe <robertl@dgii.com>
+
+ * i386.c (asm_output_function_prefix): Make 686 function
+ prologues not issue .types for non-global lables.
+
+Tue Jun 30 23:46:53 1998 Dmitrij Tejblum <tejblum@arc.hq.cti.ru>
+
+ * i386/freebsd.h (WCHAR_TYPE): Chagne to an "int".
+ (WCHAR_TYPE_SIZE): Update appropriately.
+
+Tue Jun 30 23:16:39 1998 Jeffrey A Law (law@cygnus.com)
+
+ * flow.c (recompute_reg_usage): Does not return a value.
+ * rtl.h (recompute_reg_usage): Update prototype.
+
+ * jump.c (jump_optimize): Show that the jump chain is not
+ valid when not optimizing.
+
+Tue Jun 30 16:01:01 1998 Richard Henderson <rth@cygnus.com>
+
+ * rtl.def (CONSTANT_P_RTX): New.
+ * rtl.h (CONSTANT_P): Recognize it.
+ * cse.c (fold_rtx): Eliminate it.
+ * expr.c (can_handle_constant_p): New variable.
+ (init_expr_once): Initialize it.
+ (expand_builtin): Generate CONSTANT_P_RTX if the expression is not
+ immediately recognizable as a constant.
+
+ * alpha.c (reg_or_6bit_operand): Recognize CONSTANT_P_RTX.
+ (reg_or_8bit_operand, cint8_operand, add_operand): Likewise.
+ (sext_add_operand, and_operand, or_operand): Likewise.
+ (reg_or_cint_operand, some_operand, input_operand): Likewise.
+ * alpha.h (PREDICATE_CODES): Add CONSTANT_P_RTX where needed.
+
+1998-06-30 Benjamin Kosnik <bkoz@bliss.nabi.net>
+
+ * dbxout.c (dbxout_type_methods): Remove warn_template_debugging.
+
+Tue Jun 30 14:03:34 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * aclocal.m4 (GCC_NEED_DECLARATION): Accept an optional second
+ argument, which is typically preprocessor code used to draw in
+ additional header files when looking for a function declaration.
+ (GCC_NEED_DECLARATIONS): Likewise.
+
+ * configure.in (GCC_NEED_DECLARATIONS): Add checks for getrlimit
+ and setrlimit, search for them in sys/resource.h.
+
+ * acconfig.h: Add stubs for NEED_DECLARATION_GETRLIMIT and
+ NEED_DECLARATION_SETRLIMIT.
+
+ * system.h: Prototype getrlimit/setrlimit if necessary.
+
+Tue Jun 30 10:54:48 1998 Mark Mitchell <mark@markmitchell.com>
+
+ * rtl.texi: Don't say that RTX_INTEGRATED_P is not depended
+ upon.
+
+Tue Jun 30 13:11:42 1998 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
+
+ * rs6000/sysv4.h (asm output): add tabs for asm directives.
+
+Tue Jun 30 13:11:42 1998 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * Makefile.in (FLAGS_TO_PASS): Set AR_FLAGS to AR_FOR_TARGET_FLAGS.
+
+Tue Jun 30 08:59:15 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * gansidecl.h (ATTRIBUTE_UNUSED): Use __unused__ not `unused'.
+ Don't define NULL here. Also, remove all vestiges of autoconf
+ based checks for bcmp/bcopy/bzero/index/rindex.
+
+ * system.h: Immediately after including stdio.h, check for and if
+ necessary provide a default definition of NULL.
+
+Tue Jun 30 08:22:05 1998 Michael Meissner <meissner@cygnus.com>
+
+ * reload1.c (reload_cse_simplify_operands): Call
+ fatal_insn_not_found, not abort.
+
+Tue Jun 30 02:34:02 1998 Jeffrey A Law (law@cygnus.com)
+
+ * choose-temp.c (make_temp_file): Accept new argument for the
+ file suffix to use. Allocate space for it and add it to the
+ template.
+ * mkstemp.c (mkstemps): Renamed from mkstemp. Accept new argument
+ for the length of the suffix. Update template struture checks
+ to handle optinal suffix.
+ * collect2.c (make_temp_file): Update prototype.
+ (main): Put proper suffixes on temporary files.
+ * gcc.c (make_temp_file): Update prototype.
+ (do_spec_1): Put proper suffixes on temporary files.
+
+Tue Jun 30 00:56:19 1998 Bruno Haible <haible@ilog.fr>
+
+ * invoke.texi: Document new implicit structure initialization
+ warning.
+
+Mon Jun 29 22:12:06 1998 Jeffrey A Law (law@cygnus.com)
+
+ * Merge from gcc2 June 9, 1998 snapshot. See ChangeLog.13 for
+ details.
+
+ * pa.c, pa.h, pa.md: Convert to gen_rtx_FOO.
+
+Mon Jun 29 20:12:41 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (fix-header): Don't needlessly depend on cpperror.o.
+
+ * alias.c (CHECK_ALIAS_SETS_FOR_CONSISTENCY): Cast expansion to
+ void since it is evaluated in a comma list.
+
+ * mips.h (ASM_GENERATE_INTERNAL_LABEL): Always sprintf `NUM'
+ argument as a long and cast `NUM' to long to ensure it is of the
+ proper width. Wrap macro arguments in parens when they appear in
+ the expansion.
+
+ * sol2.h (ASM_GENERATE_INTERNAL_LABEL): Likewise.
+
+ * sparc.h (ASM_GENERATE_INTERNAL_LABEL): Likewise.
+ (ASM_DECLARE_RESULT): Fix fprintf format specifier to match
+ function argument return type.
+ (REGNO_OK_FOR_INDEX_P, REGNO_OK_FOR_BASE_P, REGNO_OK_FOR_FP_P,
+ REGNO_OK_FOR_CCFP_P): Use `(unsigned)' not `U'.
+
+ * cpplib.c (cpp_message_from_errno): Remove unneeded argument to
+ cpp_message.
+
+ * dbxout.c: Fix the comments after an #endif to reflect the actual
+ condition tested in the preceding #if.
+
+ * except.c (find_all_handler_type_matches): Switch to old-style
+ function definition.
+
+ * expr.c (expand_builtin): Remove unused variable `type' twice.
+
+ * gbl-ctors.h (DO_GLOBAL_CTORS_BODY): Cast -1 before comparing it
+ to an unsigned long.
+
+ * haifa-sched.c (print_insn_chain): Remove unused function.
+
+ * objc/objc-act.c (build_msg_pool_reference): Hide prototype and
+ definition.
+
+ * toplev.c: When testing whether to include dbxout.h, also include
+ it when XCOFF_DEBUGGING_INFO is defined.
+
+ * unroll.c (unroll_loop): Add parentheses around assignment used
+ as truth value.
+
+Mon Jun 29 12:18:00 1998 Catherine Moore <clm@cygnus.com>
+
+ * config/lb1spc.asm (.div, .udiv): Replace routines.
+
+Mon Jun 29 09:44:24 1998 Mark Mitchell <mark@markmitchell.com>
+
+ * rtl.h: Update comment about special gen_rtx variants.
+ * emit-rtl.c (gen_rtx): Handle MEMs using gen_rtx_MEM.
+
+Sun Jun 28 20:58:51 1998 Jeffrey A Law (law@cygnus.com)
+
+ * choose-temp.c (choose_temp_base): Restore original variant of
+ this function for compatibility.
+ (make_temp_file): This is the new, preferred interface to create
+ temporary files.
+ * collect2.c (choose_temp_base): Delete declaration.
+ (make_temp_file): Declare.
+ (temp_filename_length, temp_filename): Delete.
+ (main): Use make_temp_file to get temporary files. Use --lang-c
+ to force the resulting ctort/dtor file to be compiled with the C
+ compiler. Make sure to remove temporary files on all exit paths.
+ * gcc.c (make_temp_file): Provide prototype if MKTEMP_EACH_FILE is
+ defined.
+ (choose_temp_base): Only provide prototype if MKTEMP_EACH_FILE is
+ not defined.
+ (do_spec): Use make_temp_file if MKTEMP_EACH_FILE is defined.
+
+Sun Jun 28 08:57:09 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * configure.in (GCC_NEED_DECLARATIONS): Add strerror, getcwd and
+ getwd.
+
+ * acconfig.m4: Add stubs for NEED_DECLARATION_STRERROR,
+ NEED_DECLARATION_GETCWD and NEED_DECLARATION_GETWD.
+
+ * cccp.c: Remove strerror()/sys_nerr/sys_errlist decls.
+ (my_strerror): Add prototype and make it static.
+
+ * collect2.c: Likewise.
+
+ * cpplib.c: Likewise.
+
+ * gcc.c: Likewise, but keep `my_strerror' extern.
+
+ * protoize.c: Likewise.
+
+ * pexecute.c (my_strerror): Add argument to prototype.
+
+ * system.h: Add prototypes for getcwd, getwd and strerror. Add
+ extern decls for sys_nerr and sys_errlist. Make abort decl
+ explicitly extern.
+
+ * getpwd.c: Remove decls for getwd and getcwd.
+
+Sun Jun 28 02:11:16 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sat Jun 27 23:32:25 1998 Richard Henderson <rth@cygnus.com>
+
+ * jump.c (jump_optimize): Use side_effects_p & may_trap_p instead
+ of rtx_unsafe_p. Use modified_between_p instead of reg_set_between_p.
+ Allow FP moves to be optimized.
+ (rtx_unsafe_p): Delete.
- * configure (lang_specs_files, lang_options_files): Add $srcdir to
- file names when adding them to these variables.
+Sat Jun 27 23:02:04 1998 Richard Henderson <rth@cygnus.com>
- * c-typeck.c (pointer_int_sum): Don't distribute if intop is unsigned
- and not the same size as ptrop.
+ * objc/archive.c: Remove <string.h> prototypes.
- * function.c (assign_stack_temp): When split a slot, set base_offset
- and full_size in the newly created slot.
- (combine_temp_slots): Update full_size when slots are combined.
+Sat Jun 27 22:37:05 1998 Jeffrey A Law (law@cygnus.com)
- * sh.c (reg_unused_after): New function.
- * sh.md (define_peephole): Add peepholes to use r0+rN addressing mode
- for some address reloads.
+ * tm.texi (NEED_MATH_LIBRARY): Document new target macro.
- * final.c (final_start_function): If SDB_DEBUG, call
- sdbout_begin_function. If XCOFF_DEBUG, call xcoffout_begin_function
- instead of xcoffout_output_first_source_line.
- (final_scan_insn): Don't call sdbout_begin_function or
- xcoffout_begin_function.
- * xcoffout.c (xcoffout_output_first_source_line): Delete.
- (xcoffout_begin_function): Call dbxout_parms and
- ASM_OUTPUT_SOURCE_LINE.
+ * Makefile.in (gencheck): Remove $(TREE_H) dependency.
- * va-mips.h: Change every occurance of #if __mips>=3 to
- #ifdef __mips64.
- * mips/abi64.h (CPP_SPEC): Output -D__mips64 when -mips3, or -mips4,
- or -mgp64. Output -U__mips64 when -mgp32.
- * mips/dec-bsd.h, mips/elf64.h, mips/iris3.h: Likewise.
- * mips/iris5.h, mips/mips.h, mips/netbsd.h, mips/osfrose.h: Likewise.
+Sat Jun 27 20:20:00 1998 John Carr <jfc@mit.edu>
- * i960.c (i960_function_epilogue): Don't clear g14 for functions with
- an argument block.
- (i960_output_reg_insn): Likewise.
- (i960_output_call_insn): Clear g14 for functions wtih an argument
- block.
+ * dsp16xx.h (FIRST_PSEUDO_REGISTER): Add parentheses to definition.
+ * dsp16xx.c (next_cc_user_unsigned): New function.
+ Remove save_next_cc_user_code.
+ (print_operand): Use HOST_WIDE_INT_PRINT_* macros.
+ * dsp16xx.md: Call next_cc_user_unsigned instead of using
+ save_next_cc_user_code.
+ Use gen_rtx_* functions instead of gen_rtx.
-Fri Jul 28 08:43:52 1995 Doug Evans <dje@canuck.cygnus.com>
+Sat Jun 27 20:18:34 1998 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
- * i960.c (i960_arg_size_and_align): Correct alignment of XFmode
- values in library calls.
- * i960.md (movdi matchers): Support odd numbered regs.
+ * rs6000.h: Add trap_comparison_operator to PREDICATE_CODES.
-Fri Jul 28 08:37:25 1995 Michael Gschwind <mike@lanai.vlsivie.tuwien.ac.at>
+Sat Jun 27 16:45:42 1998 Jeffrey A Law (law@cygnus.com)
- * pdp11.md (divhi3, modhi3, divmodhi4): Rewrite.
+ * flow.c (count_reg_sets): New function.
+ (count_reg_sets_1, count_ref_references): Likewise.
+ (recompute_reg_usage): Likewise.
+ * rtl.h (recompute_reg_usage): Add prototype.
+ * toplev.c (rest_of_compilation): Call recompute_reg_usage just
+ before local register allocation.
+
+Sat Jun 27 13:15:30 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.md (negsf, negdf): Revert Jan 22 change.
+
+Sat Jun 27 07:35:21 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * mkstemp.c: Include gansidecl.h. Rename uint64_t to gcc_uint64_t.
+ (mkstemp): Remove size specifier for variable `letters'. Call
+ gettimeofday, not __gettimeofday.
+
+ * Makefile.in (EXPR_H): New dependency variable.
+ (c-typeck.o): Depend on $(EXPR_H) instead of expr.h.
+ (c-iterate.o): Likewise.
+ (gencheck): Depend on $(TREE_H) instead of tree.h, etc.
+ (stor-layout.o): Depend on $(EXPR_H) instead of expr.h.
+ (toplev.o): Likewise. Also depend on $(RECOG_H) instead of recog.h.
+ (varasm.o): Depend on $(EXPR_H) instead of expr.h.
+ (function.o): Likewise.
+ (stmt.o): Likewise.
+ (except.o): Likewise.
+ (expr.o): Likewise.
+ (calls.o): Likewise.
+ (expmed.o): Likewise.
+ (explow.o): Likewise.
+ (optabs.o): Likewise.
+ (sdbout.o): Likewise.
+ (dwarf2out.o): Likewise.
+ (emit-rtl.o): Likewise.
+ (integrate.o): Likewise.
+ (jump.o): Likewise.
+ (cse.o): Likewise.
+ (gcse.o): Likewise. Also depend on $(BASIC_BLOCK_H) instead of
+ basic-block.h.
+ (loop.o): Depend on $(EXPR_H) instead of expr.h.
+ (unroll.o): Likewise.
+ (combine.o): Likewise.
+ (reload.o): Likewise.
+ (reload1.o): Likewise.
+ (caller-save.o): Likewise.
+ (reorg.o): Likewise.
+ (alias.o): Don't depend on insn-codes.h.
+ (regmove.o): Depend on $(RECOG_H)/$(EXPR_H) instead of recog.h/expr.h.
+ (insn-emit.o): Depend on $(EXPR_H) instead of expr.h.
+ (insn-opinit.o): Likewise.
+
+Sat Jun 27 01:35:14 1998 Jeffrey A Law (law@cygnus.com)
+
+ * choose-temp.c (choose_temp_base): Remove MPW bits. Use mkstemp
+ instead of mktemp.
+ * gcc.c (MKTEMP_EACH_FILE): Define.
+ (main): No need to call choose_temp_base if we are going to
+ use choose_temp_base to create each file later.
+ * mkstemp.c: New file. Adapted from glibc.
+ * Makefile.in (xgcc, colect2, protoize, unprotoize): Link in mkstemp.o
+ (mkstemp.o): Add dependencies.
+
+ * configure.in (gettimeofday): Check for its existance.
+ * config.in (HAVE_GETTIMEOFDAY): Define.
+ * configure: Rebuilt.
+
+1998-06-26 Michael Meissner <meissner@cygnus.com>
+
+ * rs6000.md (ne 0, non power case): Add missing & constraint.
+ Name pattern ne0.
+ (negative abs insns): Add pattern names.
+
+Fri Jun 26 17:36:42 1998 Dave Love <d.love@dl.ac.uk>
+
+ * Makefile.in (install-info): Run install-info program in separate
+ loop.
+
+Fri Jun 26 16:03:15 1998 Michael Meissner <meissner@cygnus.com>
+
+ * haifa-sched.c (schedule_block): Add hooks for the machine
+ description to reorder the ready list, and update how many more
+ instructions can be issued this cycle.
+ * tm.texi (MD_SCHED_{INIT,REORDER,VARIABLE_ISSUE}): Document.
+
+Fri Jun 26 11:54:11 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
+
+ * config/sparc/sparc.h (REGNO_OK_FOR_{INDEX,BASE,FP,CCFP}_P):
+ Explicitly mark the constant being compared against as unsigned.
+ * config/sparc/sparc.c (sparc_select, cpu_default, cpu_table):
+ Fully initialize final members.
+ (mem_aligned_8): Explicit init of offset to zero.
+ (output_function_prologue): Explicit init of n_regs to zero.
+ (output_function_epilogue): Likewise, and mark arg size as
+ unused.
+ (init_cumulative_args): Mark libname and indirect as unused.
+ (function_arg_pass_by_reference): Likewise for cum and named.
+ (sparc_builtin_saveregs): Likewise for arglist.
+ (sparc_flat_eligible_for_epilogue_delay): Likewise for slot.
+
+Fri Jun 26 06:58:54 1998 Richard Earnshaw (rearnsha@arm.com)
+
+ * arm.h (SECONDARY_INPUT_RELOAD_CLASS): Only need a secondary reload
+ if reloading a MEM.
+
+ * arm.h (arm_adjust_cost): Renamed bogus prototype from
+ arm_adjust_code.
+ (bad_signed_byte_operand): Add prototype.
+ * arm.c (arm_override_options): Make I unsigned.
+ (const_ok_for_arm): Add casts to the constants.
+ (load_multiple_operation): Don't redeclare elt in sub-block.
+ (arm_gen_movstrqi): Delete external declaration of optimize.
+ (gen_compare_reg): Declare parameter fp.
+
+ * arm.c (final_prescan_insn): Only initialize scanbody if the insn
+ has a pattern.
+
+Fri Jun 26 09:31:24 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * alpha.c: Include system.h and toplev.h.
+ (cint8_operand): Mark parameter `mode' with ATTRIBUTE_UNUSED.
+ (const48_operand): Likewise.
+ (mode_width_operand): Likewise.
+ (mode_mask_operand): Likewise.
+ (mul8_operand): Likewise.
+ (current_file_function_operand): Likewise.
+ (signed_comparison_operator): Likewise.
+ (divmod_operator): Likewise.
+ (any_memory_operand): Likewise.
+ (alpha_return_addr): Likewise for parameter `frame'.
+ (alpha_builtin_saveregs): Likewise for parameter `arglist'.
+ (vms_valid_decl_attribute_p): Likewise for parameters `decl' and
+ `attributes'.
+ (alpha_start_function): Likewise for parameter `decl'. Use
+ HOST_WIDE_INT_PRINT_DEC in call to fprintf. Fix various format
+ specifiers. Remove unused variables `lab' and `name'.
+ (alpha_end_function): Mark parameter `decl' with ATTRIBUTE_UNUSED.
+ (check_float_value): Likewise for parameter `overflow'.
+ (alpha_need_linkage): Likewise for parameters `name' and `is_local'.
+
+ * alpha.h (ASM_IDENTIFY_GCC, ASM_IDENTIFY_LANGUAGE): Define as
+ taking an argument.
+ (ASM_OUTPUT_SHORT): Cast argument to `int' in call to fprintf.
+ (ASM_OUTPUT_CHAR): Likewise.
+ (ASM_OUTPUT_BYTE): Likewise.
+ (PRINT_OPERAND_ADDRESS): Use HOST_WIDE_INT_PRINT_DEC in call to
+ fprintf.
+ (PUT_SDB_EPILOGUE_END): Mention argument `NAME' in definition.
+ Add prototypes for functions in alpha.c.
+
+ * alpha.md (ashldi3): Add default case in switch.
+
+1998-06-26 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * Makefile.in (gcc_version, gcc_version_trigger): New macros.
+ (version): Initialize from $(gcc_version).
+
+ * configure.in (version): Rename to gcc_version.
+ (gcc_version_trigger): New variable; call AC_SUBST for it and
+ emit it into the generated config.status.
+ * configure: Regenerate.
+
+Thu Jun 25 12:47:41 1998 Mark Mitchell <mark@markmitchell.com>
+
+ * fold-const.c (make_range): Don't go looking at TREE_OPERANDs of
+ nodes that are not expressions.
+
+Thu Jun 25 15:08:16 1998 Mark Mitchell <mark@markmitchell.com>
+
+ * invoke.texi (-fstrict-aliasing): Document.
+ * rtl.texi (MEM_ALIAS_SET): Document.
+
+ * flags.h (flag_strict_aliasing): Declare.
+ * toplev.c (flag_strict_aliasing): Define.
+ (f_options): Add -strict-aliasing.
+ (main): Set flag_strict_aliasing if -O2 or higher.
+
+ * tree.h (tree_type): Add alias_set field.
+ (TYPE_ALIAS_SET): New macro.
+ (TYPE_ALIAS_SET_KNOWN_P): Likewise.
+ (get_alias_set): Declare.
+ * tree.c (lang_get_alias_set): Define.
+ (make_node): Initialize TYPE_ALIAS_SET.
+ (get_alias_set): New function.
+ * print-tree.c (print_node): Dump the alias set for a type.
+
+ * c-tree.h (c_get_alias_set): Declare.
+ * c-common.c (c_get_alias_set): New function.
+ * c-decl.c (init_decl_processing): Set lang_get_alias_set.
+
+ * expr.c (protect_from_queue): Propogage alias sets.
+ (expand_assignment): Calculate alias set for new MEMs.
+ (expand_expr): Likewise.
+ * function.c (put_var_into_stack): Likewise.
+ (put_reg_into_stack): Likewise.
+ (gen_mem_addressof): Likewise.
+ (assign_parms): Likewise.
+ * stmt.c (expand_decl): Likewise.
+ * varasm.c (make_decl_rtl): Eliminate redundant clearing of
+ DECL_RTL. Calculate alias set for new MEMs.
+
+ * rtl.def (REG): Add dummy operand.
+ (MEM): Add extra operand to store the MEM_ALIAS_SET.
+ * rtl.h (MEM_ALIAS_SET): New macro.
+ (gen_rtx_MEM): Declare.
+ * emit-rtl.c (gen_rtx_MEM): New function.
+ * gengenrtl.c (sepcial_rtx): Make MEMs special.
+
+ * alias.c (CHECK_ALIAS_SETS_FOR_CONSISTENCY): New macro.
+ (DIFFERENT_ALIAS_SETS_P): Likewise.
+ (canon_rtx): Propogate the alias set to the new MEM.
+ (true_dependence): Check the alias sets.
+ (anti_dependence): Likewise.
+ (output_dependence): Likewise.
+ * explow.c (stabilize): Progoate alias sets.
+ * integrate.c (copy_rtx_and_substitute): Likewise.
+ * final.c (alter_subreg): Make sure not to leave MEM_IN_STRUCT_P
+ in an unpredictable state. Propogate alias sets.
+ * reload1.c (reload): Clear MEM_ALIAS_SET for new MEMs about which
+ we have no alias information.
-Wed Jul 26 10:15:52 1995 Hallvard B Furuseth (h.b.furuseth@usit.uio.no)
+Thu Jun 25 16:59:18 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
+
+ * except.h (CATCH_ALL_TYPE): Definition moved to eh-common.h.
+ (find_all_handler_type_matches): Add function prototype.
+ * eh-common.h (CATCH_ALL_TYPE): Definition added.
+ * except.c (find_all_handler_type_matches): Add function to find all
+ runtime type info in the exception table.
+ (output_exception_table_entry): Special case for CATCH_ALL_TYPE.
+
+Thu Jun 25 15:47:55 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (xcoffout.o): Depend on toplev.h, output.h and dbxout.h.
+
+ * config/fp-bit.c (_fpmul_parts): Move variables `x', `ylow',
+ `yhigh' and `bit' into the scope in which they are used.
+ (_fpdiv_parts): Remove unused variables `low', `high', `r0', `r1',
+ `y0', `y1', `q', `remainder', `carry', `d0' and `d1'.
+
+ * rs6000.c: Move include of output.h below tree.h. Include toplev.h.
+ (any_operand): Mark unused parameters `op' and `mode' with
+ ATTRIBUTE_UNUSED.
+ (count_register_operand): Likewise for parameter `mode'.
+ (fpmem_operand): Likewise.
+ (short_cint_operand): Likewise.
+ (u_short_cint_operand): Likewise.
+ (non_short_cint_operand): Likewise.
+ (got_operand): Likewise.
+ (got_no_const_operand): Likewise.
+ (non_add_cint_operand): Likewise.
+ (non_logical_cint_operand): Likewise.
+ (mask_operand): Likewise.
+ (current_file_function_operand): Likewise.
+ (small_data_operand): Likewise for parameters `op' and `mode' but
+ only when !TARGET_ELF.
+ (init_cumulative_args): Mark parameters `libname' with
+ ATTRIBUTE_UNUSED.
+ (function_arg_pass_by_reference): Likewise for parameters `cum',
+ `mode' and `named'.
+ (expand_builtin_saveregs): Likewise for parameter `args'.
+ (load_multiple_operation): Likewise for parameter `mode'.
+ (store_multiple_operation): Likewise.
+ (branch_comparison_operator): Likewise.
+ (secondary_reload_class): Likewise.
+ (print_operand): Add parentheses around & operation.
+ (output_prolog): Mark parameter `size' with ATTRIBUTE_UNUSED.
+ (output_epilog): Likewise. Cast argument to fprintf to int.
+ (rs6000_adjust_cost): Mark parameter `dep_insn' with ATTRIBUTE_UNUSED.
+ (rs6000_valid_decl_attribute_p): Likewise for parameters `decl',
+ `attributes', `identifier' and `args'.
+ (rs6000_valid_type_attribute_p): Likewise for parameter `attributes'.
+ (rs6000_comp_type_attributes): Likewise for parameters `type1' and
+ `type2'.
+ (rs6000_set_default_type_attributes): Likewise for parameter `type'.
+
+ * rs6000.h (RTX_COSTS): Add parentheses around & operation.
+ (toc_section, private_data_section, trap_comparison_operator): Add
+ prototypes.
+
+ * dbxout.h (dbxout_parms, dbxout_reg_parms, dbxout_syms): Add
+ prototypes.
+
+ * xcoffout.c: Include toplev.h, outout.h and dbxout.h.
+
+ * xcoffout.h (stab_to_sclass, xcoffout_begin_function,
+ xcoffout_begin_block, xcoffout_end_epilogue,
+ xcoffout_end_function, xcoffout_end_block,
+ xcoff_output_standard_types, xcoffout_declare_function,
+ xcoffout_source_line): Add prototypes.
+
+Thu Jun 25 09:54:55 1998 Nick Clifton <nickc@cygnus.com>
+
+ * config/arm/arm.h (REG_ALLOC_ORDER): Add ARG_POINTER_REGNUM,
+ noticed by grahams@rcp.co.uk.
+
+Thu Jun 25 11:12:29 1998 Dave Brolley <brolley@cygnus.com>
+
+ * gcc.c (default_compilers): Use new | syntax to eliminate
+ string concatenation.
+
+Thu Jun 25 01:00:48 1998 Richard Henderson <rth@cygnus.com>
- * collect2.c (end_file): Fix typo in error message text.
+ * alpha.c (alpha_function_name): Delete.
+ (alpha_ra_ever_killed): Notice current_function_is_thunk.
+ (alpha_sa_mask, alpha_sa_size, alpha_does_function_need_gp): Likewise.
+ (alpha_start_function): Reorg from output_prologue.
+ (alpha_end_function): Reorg from output_epilogue.
+ * alpha.h (ASM_DECLARE_FUNCTION_NAME): Call alpha_start_function.
+ (ASM_DECLARE_FUNCTION_SIZE): New.
+ (FUNCTION_PROLOGUE, FUNCTION_EPILOGUE): Delete.
+ (PROFILE_BEFORE_PROLOGUE): Set.
+ (ASM_OUTPUT_MI_THUNK): Remove bits now output by start/end_function.
+ * alpha/win-nt.h (ASM_OUTPUT_MI_THUNK): Likewise.
-Wed Jul 26 09:22:22 1995 Jeff Law (law@snake.cs.utah.edu)
+Thu Jun 25 01:18:47 1998 John Wehle (john@feith.com)
- * xm-pa.h (USE_C_ALLOCA): Always define.
- * xm-pahpux.h (USE_C_ALLOCA): Likewise.
+ * i386/freebsd-elf.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Define.
- * x-pa (CC): Remove useless definition.
- * xm-pa.h (HAVE_STRERROR): Define.
- (__BSD_NET2__): Define.
+1998-06-25 Herman A.J. ten Brugge <Haj.Ten.Brugge@net.HCC.nl>
-Wed Jul 26 09:10:25 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * expr.c (expand_assignment): Rework address calculation for structure
+ field members to expose more invariant computations to the loop
+ optimizer.
+ (expand_expr): Likewise.
- * expr.c (preexpand_calls): Don't look past a CLEANUP_POINT_EXPR.
+Wed Jun 24 22:44:22 1998 Jeffrey A Law (law@cygnus.com)
-Wed Jul 26 08:43:42 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * local-alloc.c (block_alloc): Do not try to avoid false dependencies
+ when SMALL_REGISTER_CLASSES is nonzero.
- * cse.c (cse_insn): When do special handling for (set REG0 REG1),
- must delete REG_EQUAL note from insn if it mentions REG0.
+Wed Jun 24 17:55:15 1998 Klaus Kaempf <kkaempf@progis.de>
- * loop.c (find_and_verify_loops): When moving blocks of code, verify
- that the just destination is not in an inner nested loop.
- (mark_loop_jump): Don't mark label as loop exit if it jumps to
- an inner nested loop.
+ * alpha.md (call_vms, call_value_vms): Strip leading * from symbol.
-Wed Jul 26 08:40:31 1995 Paul Eggert <eggert@twinsun.com>
+Wed Jun 24 16:27:23 1998 John Carr <jfc@mit.edu>
- * cccp.c (do_include, read_name_map): Omit leading "./" and
- trailing "/" when it makes sense.
- (skip_redundant_dir_prefix): New function.
+ * expr.c (get_memory_rtx): New function.
+ (expand_builtin): Call get_memory_rtx for MEM arguments to builtin
+ string functions.
-Wed Jul 26 08:36:41 1995 Michael Meissner <meissner@cygnus.com>
+ * expmed.c (init_expmed): Initialize all elements of *_cost arrays.
- * stmt.c (emit_nop): Do not emit a nop if there is a single
- insn before a label or at the start of a function.
+ * optabs.c: Use gen_rtx_FOO (...) instead of gen_rtx (FOO, ...).
+ * expr.c: Likewise.
+ * explow.c: Likewise.
+ * combine.c: Likewise.
+ * reload1.c: Likewise.
+ * gcse.c: Likewise.
-Wed Jul 26 08:21:21 1995 Doug Evans <dje@cygnus.com>
+Wed Jun 24 15:13:01 1998 Dave Brolley <brolley@cygnus.com>
- * Makefile.in (gfloat.h): Delete previous copy before updating.
+ * README.gnat: Add patch for new lang_decode_options interface.
-Wed Jul 26 08:18:29 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+Wed Jun 24 09:14:04 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
- * Makefile.in (STAGESTUFF): Add stamp-crtS.
- (crtbeginS.o, crtendS.o, stamp-crtS): New rules; just like
- crtbegin.o et al, but compiled using -fPIC.
- * configure (*-*-gnu*): Add crtbeginS.o and crtendS.o to $extra_parts.
+ * except.c (start_catch_handler): Do nothing if EH is not on.
-Wed Jul 26 08:11:52 1995 Michael Gschwind <mike@java.vlsivie.tuwien.ac.at>
+1998-06-24 Manfred Hollstein <manfred@s-direktnet.de>
- * pdp11.md: Fixed typos ('bhos' -> 'bhis').
+ * configure.in (gxx_include_dir): Initialize default value depending on
+ new flag --enable-version-specific-runtime-libs; remove superfluous
+ default initialization afterwards.
+ * configure: Regenerate.
-Wed Jul 26 08:05:41 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Wed Jun 24 01:32:12 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
- * hp320.h, m68k.h, m68kv4.h (LEGITIMATE_PIC_OPERAND_P): Reject
- CONST_DOUBLE with MEM with invalid pic address.
- * reload1.c (real.h): Include it.
- * Makefile.in (reload1.o): Depends on real.h.
+ * toplev.c (rest_of_compilation): Revert May 15 change.
-Wed Jul 26 07:58:22 1995 Ian Lance Taylor <ian@cygnus.com>
+Tue Jun 23 21:27:27 1998 Ken Raeburn <raeburn@cygnus.com>
- * gcc.c (MULTILIB_DIRS): Provide default if not defined.
- (multilib_defaults): New static variable.
- (default_arg): New static function.
- (set_multilib_dir): Ignore default arguments.
- (print_multilib_info): Ignore entries which use default arguments.
+ * reload.c (find_reloads): Fix check for failure to match any
+ alternative, to account for Mar 26 change in initial "best" cost.
-Tue Jul 25 10:06:09 1995 Michael Meissner <meissner@cygnus.com>
+Tue Jun 23 16:44:21 1998 Dave Brolley <brolley@cygnus.com>
- * rs6000.md (allocate_stack): Don't copy the LR register to
- the new stack end.
- * rs6000.c (rs6000_stack_info): Correctly store the LR in
- the caller's frame, not the current frame, for V.4 calls.
- * rs6000/eabi.asm (_save*, _rest*): Provide all mandated V.4 save
- and restore functions, except for the save*_g functions which
- return the GOT address.
+ * cpplib.c (do_line): Typo broke #line directive.
+ (cpp_message_from_errno): New function.
+ (cpp_error_from_errno): Call cpp_message_from_errno.
+ * cpplib.h (cpp_message_from_errno): New function.
-Fri Jul 21 14:24:25 1995 Michael Meissner <meissner@cygnus.com>
+Tue Jun 23 13:38:18 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
- * rs6000/eabi.h (__eabi): Load up r13 to be the small data
- pointer, unless -mrelocatable.
+ * libgcc2.c (__get_eh_table_version, __get_eh_table_language): New
+ functions to return exception descriptor information.
+ (find_exception_handler): Pass match_info field to runtime matcher,
+ not a descriptor table entry.
- * rs6000/aix3newas.h (LINK_SPEC): Import machine independent
- functions if -mcpu=common.
- * rs6000/milli.exp: Import file referenced in aix3newas.h.
+Tue Jun 23 09:30:58 1998 Dave Love <d.love@dl.ac.uk>
- * rs6000/eabi.asm (__eabi): Support for fixing up user initialized
- pointers when -mrelocatable is used.
- * rs6000/eabi.h (ASM_OUTPUT_INT): Record any pointers initialized
- by the user if -mrelocatable, to be fixed up by __eabi.
- (CONST_SECTION_ASM_OP): If -mrelocatable, put read-only stuff in .data,
- not .rodata, to allow user initialized pointers to be updated by __eabi.
+ * cpp.texi, gcc.texi: Add @dircategory, @direntry meant to
+ accompany previous Makefile.in (install-info) change.
- * rs6000.h (TARGET_SWITCHES): Add -mdebug-{stack,arg}.
- (TARGET_{ELF,NO_TOC,TOC}): Add defaults for non system V.
- (rs6000_stack): New structure to describe stack layout.
- (RS6000_{REG_SAVE,SAVE_AREA,VARARGS_*}): New macros used to
- support both AIX and V.4 calling sequences.
- (FP_ARG_*, GP_ARG_*): Ditto.
- (FP_SAVE_INLINE): Ditto.
- (STARTING_FRAME_OFFSET): Modify to support both AIX and V.4
- calling sequences.
- (FIRST_PARM_OFFSET): Ditto.
- (REG_PARM_STACK_SPACE): Ditto.
- (STACK_POINTER_OFFSET): Ditto.
- (FUNCTION_ARG_REGNO_P): Ditto.
- ({,INIT_}CUMULATIVE_ARGS): Ditto.
- (LEGITIMATE_LO_SUM_ADDRESS_P): Ditto.
- (FUNCTION_ARG{,_ADVANCE,PARTIAL_NREGS,PASS_BY_REFERENCE}): Ditto.
- (SETUP_INCOMING_VARARGS): Ditto.
- (EXPAND_BUILTIN_SAVEREGS): Ditto.
- (CAN_ELIMINATE): Ditto.
- (INITIAL_ELIMINATION_OFFSET): Ditto.
- (LEGITIMATE_CONSTANT_POOL_{BASE,ADDRESS}_P): Ditto.
- (GO_IF_{LEGITIMATE_ADDRESS,MODE_DEPENDENT_ADDRESS}): Ditto.
- (LEGITIMIZE_ADDRESS): Ditto.
- (CONST_COSTS): Ditto.
- (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P): Ditto.
- (ASM_OUTPUT_REG_{PUSH,POP}): Use reg_names to print registers.
- (function declarations): Add new rs6000.c function declarations,
- and delete decls of deleted functions.
- (SHIFT_COUNT_TRUNCATED): Parenthesize the expression.
+Tue Jun 23 10:06:07 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
+
+ * eh-common.h (struct __eh_info): Remove coerced value field.
+ * libgcc2.c (find_exception_handler): Don't set coerced_value field.
+ * except.c (get_dynamic_handler_chain, get_dynamic_cleanup_chain): Use
+ POINTER_SIZE instead of Pmode.
+ (expand_start_all_catch): Call start_catch_handler() if we are not
+ using new style exceptions.
+
+Tue Jun 23 06:45:00 1998 Catherine Moore <clm@cygnus.com>
+
+ * varasm.c (assemble_variable): Remove reference to warn_bss_align.
+
+Mon Jun 22 23:57:31 1998 David S. Miller <davem@pierdol.cobaltmicro.com>
+
+ * config/sparc/sparc.md (zero_extendhidi2, extendhisi2,
+ extendqihi2, extendqisi2, extendqidi2, extendhidi2, adddi3,
+ subdi3, negdi2, call, call_value, untyped_return, nonlocal_goto,
+ splits and peepholes): Change remaining generic gen_rtx calls to
+ specific genrtl ones.
+ * config/sparc/sparc.c: Likewise.
- * rs6000.c (init_cumulative_args): New function to support AIX
- and V.4 calling sequences.
- (function_arg{,_advance,partial_nregs,pass_by_reference}): Ditto.
- (setup_incoming_varargs): Ditto.
- (expand_builtin_saveregs): Ditto.
- (rs6000_stack_info): Ditto.
- (debug_stack_info): Ditto.
- (direct_return): Changes to support AIX and V.4 calling sequences.
- (first_reg_to_save): Ditto.
- (svr4_traceback): Ditto.
- (output_{prolog,epilog}): Ditto.
- (print_operand): Use reg_names to print registers. Add support
- for V.4 HIGH/LO_SUM address modes.
- (must_save_cr): Function deleted, in rewrite of AIX/V.4 calling
- sequence support.
- (rs6000_sa_size): Ditto.
- (rs6000_pushes_stack): Ditto.
- (output_toc): Add abort if no toc.
-
- * rs6000.md (call insns): Add a new argument to flag a V.4
- function needs to set bit 6 of the CR.
- (elf_{low,high}): New V.4 functions to create addresses via HIGH
- and LO_SUM patterns.
- (movsi): Use elf_{low,high} if appropriate.
- (mov{si,di}_update): Name these patterns for allocate_stack.
- (allocate_stack): Support for V.4 stack layout.
- (sync): New pattern for V.4 trampolines to issue the sync
- instruction.
+Mon Jun 22 22:21:46 1998 Richard Henderson <rth@cygnus.com>
+
+ * gcc.c (handle_braces): Recognize | between options as an or.
+
+Mon Jun 22 23:13:47 1998 John Wehle (john@feith.com)
+
+ * i386/freebsd-elf.h (JUMP_TABLES_IN_TEXT_SECTION): Define as flag_pic.
+ * i386/sysv4.h (JUMP_TABLES_IN_TEXT_SECTION): Define as flag_pic.
+
+ * i386.md (exception_receiver): Define.
+
+Mon Jun 22 12:01:48 1998 Jim Wilson <wilson@cygnus.com>
+
+ * Makefile.in (PROTOIZE_INSTALL_NAME, UNPROTOIZE_INSTALL_NAME,
+ PROTOIZE_CROSS_NAME, UNPROTOIZE_CROSS_NAME): New variables.
+ (install-common): Use them.
+
+ * gcse.c (add_label_notes): New function.
+ (pre_insert_insn): Call it.
+ * unroll.c (unroll_loop): Look for insns with a REG_LABEL note, and
+ pass the label to set_label_in_map.
+
+Mon Jun 22 19:01:14 1998 Dave Love <d.love@dl.ac.uk>
+
+ * Makefile.in (install-info): Fix typpo in previous change.
+
+Mon Jun 22 11:10:00 1998 Catherine Moore <clm@cygnus.com>
+
+ * varasm.c (assemble_variable): Emit alignment warning.
+
+Mon Jun 22 08:18:46 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (varasm.o): Depend on sdbout.h.
+ (sdbout.o): Depend on toplev.h.
+
+ * collect2.c (scan_prog_file): Cast fprintf argument to `long' and
+ use %ld specifier.
+
+ * final.c (shorten_branches): Cast first arg of `bzero' to char *.
+
+ * genextract.c (main): When creating insn-extract.c, mark variable
+ `i' with ATTRIBUTE_UNUSED.
+
+ * genpeep.c (main): When creating insn-peep.c, mark variables
+ `insn', `x' and `pat' with ATTRIBUTE_UNUSED.
+
+ * objc/init.c (__objc_tree_print): Wrap function definition in
+ macro `DEBUG'.
+
+ * objc/objc-act.c (encode_array): Cast sprintf argument to `long'
+ and use %ld specifier.
+ (adorn_decl): Likewise, twice.
+
+ * reload1.c (reload_cse_regs): Cast first arg of `bzero' to char *.
+
+ * sdbout.c: Include output.h and toplev.h.
+ (PUT_SDB_INT_VAL): Use HOST_WIDE_INT_PRINT_DEV to print argument
+ `a'. Cast `a' to HOST_WIDE_INT to force it to always be so.
+ (PUT_SDB_SIZE): Likewise.
+
+ * sdbout.h (sdbout_mark_begin_function): Add prototype.
+
+ * stmt.c (check_for_full_enumeration_handling): Cast argument of
+ `warning' to long and use %ld specifier.
+
+ * toplev.c (main): Likewise for `fprintf'.
+
+ * toplev.h (output_file_directive): Add prototype.
+
+ * unroll.c (unroll_loop): Use HOST_WIDE_INT_PRINT_DEC specifier in
+ call to `fprintf'.
+ (precondition_loop_p): Likewise.
+
+ * varasm.c Include sdbout.h.
+ (assemble_static_space): Move sometimes-unused variable `rounded'
+ into the scope in which it is used.
- * rs6000/sysv4.h (TARGET_SWTICHES): Add -mcall-{aix,sysv}, and
- -mprototype. Remove separate flag bit for -mno-toc.
- (SUBTARGET_OVERRIDE_OPTIONS): Don't test for -mno-toc.
- (FP_ARG_*): Adjust for V.4 calling sequences.
- (RS6000_*): Ditto.
- (FP_SAVE_INLINE): Ditto.
- (toc_section): Eliminate use of AIX style full TOC.
- (TRAMPOLINE_{TEMPLATE,SIZE}): Redefine for V.4 support.
- (INITIALIZE_TRAMPOLINE): Ditto.
+ * mips.c (gpr_mode): Don't say `static' twice.
+
+ * cpplib.c (cpp_handle_option): Don't pass unneeded NULL to cpp_fatal.
+
+ * objc/objc-act.c (init_selector): Hide prototype and definition.
+
+ * optabs.c (gen_cond_trap): Remove unused variable `icode'.
- * rs6000/eabi.h (CPP_SPEC): Define _CALL_SYSV or _CALL_AIX,
- depending on whether -mcall-sysv or -mcall-aix was used.
- * rs6000/eabile.h (CPP_SPEC): Ditto.
- * rs6000/sysv4le.h (CPP_SPEC): Ditto.
-
- * rs6000/t-eabigas (MULTILIB_{OPTIONS,DIRNAMES}): Delete no-toc
- libraries, explicit big endian libraries.
- * rs6000/t-ppcgas (MULTILIB_{OPTIONS,DIRNAMES}): Ditto.
+ * regmove.c (copy_src_to_dest): Likewise for `i'.
+
+ * mips-tfile.c (add_local_symbol): Cast width format specifier to int.
+ (add_ext_symbol): Likewise.
+ (add_file): Likewise.
+ (parse_def): Likewise.
+ (write_varray): Use HOST_PTR_PRINTF to print a pointer. Fix
+ remaining format specifiers and arguments.
+ (write_object): Likewise, several times.
+ (read_seek): Likewise.
+ (out_of_bounds): Likewise.
+ (allocate_cluster): Likewise.
+ (xmalloc): Likewise.
+ (xcalloc): Likewise.
+ (xrealloc): Likewise.
+ (xfree): Likewise.
+
+ * mips-tdump.c (print_symbol): Likewise.
- * rs6000/t-eabiaix: New file for eabi, using -mcall-aix as the
- default.
- * rs6000/eabiaix.h: Ditto.
+Sun Jun 21 17:05:34 1998 Dave Love <d.love@dl.ac.uk>
+
+ * Makefile.in (install-info): Use install-info program if
+ available, per GNU standard.
+
+Sun Jun 21 18:56:44 1998 Jeffrey A Law (law@cygnus.com)
+
+ * invoke.texi: Document -mrelax for the mn10300 and mn10200.
+
+ * basic-block.h (init_regset_vector): Delete declaration.
+ * flow.c (init_regset_vector): Make it static and add a prototype.
+
+ * bitmap.h (debug_bitmap): Declare.
+
+ * haifa-sched.c (debug_ready_list): Make static.
+
+ * toplev.h (fancy_abort): Declare.
- * rs6000/t-eabilegas: New file for eabi on little endian systems.
- * rs6000/t-ppclegas: New file for V.4 on little endian systems.
+Sun Jun 21 18:30:13 1998 H.J. Lu (hjl@gnu.org)
- * rs6000/t-rs6000 (MULTILIB_{OPTIONS,DIRNAMES}): Build libgcc.a
- for -mcpu=common.
+ * basic-block.h (init_regset_vector): New declaration.
- * configure (powerpc-*-eabiaix): New configuration for defaulting
- to old-style AIX calling sequence.
- (powerpcle*): Use new t-{eabi,ppc}legas files, to avoid building
- explicit little endian multilib libraries.
+ * Makefile.in (sdbout.o): Add insn-codes.h to dependency.
-Fri Jul 21 13:23:06 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * global.c: Include machmode.h amd move hard-reg-set.h before
+ rtl.h.
- * toplev.c (main): Don't define sbrk #ifdef __alpha__.
+ * haifa-sched.c (insn_issue_delay, birthing_insn_p,
+ adjust_priority, print_insn_chaino): New declaration.
+ (schedule_insns): Remove declaration.
+ (init_target_units, get_visual_tbl_length,
+ init_block_visualization): Add prototype.
-Tue Jul 18 19:23:44 1995 Paul Eggert <eggert@twinsun.com>
+ * integrate.c (pushdecl, poplevel): Remove declaration.
- * cccp.c (do_include): Prefix -H output lines with spaces, not dots.
- (output_dots): Remove.
+ * rtl.h (expand_expr): Remove declaration.
- * cccp.c (main): cplusplus_comments now defaults to 1.
- But clear it if -traditional or the new option -lang-c89 is given.
- * gcc.c (default_compilers, cpp): Specify -lang-c89 if -ansi is given.
- This turns off C++ comment recognition.
+ * loop.c (oballoc): Remove declaration.
+ (replace_call_address): Add prototype.
-Tue Jul 18 19:16:38 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Sun Jun 21 01:08:17 PDT 1998 Jeff Law (law@cygnus.com)
- * va-sparc.h (va_arg): Add support for 128 bit long double type.
+ * version.c: Bump for snapshot.
-Tue Jul 18 19:11:18 1995 Jorn Rennecke (amylaar@meolyon.hanse.de)
+Sun Jun 21 01:16:38 1998 John Wehle (john@feith.com)
- * c-common.c (decl_attributes, case A_ALIGNED): Handle is_type
- case properly.
+ * i386.c (output_fp_conditional_move): Don't bother handling
+ (cc_prev_status.flags && CC_NO_OVERFLOW) since the INSN patterns
+ prevent this from happening.
-Tue Jul 18 19:03:02 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * i386.md (nonlocal_goto_receiver): Delete.
- * fold-const.c (fold, case CONVERT_EXPR): Don't merge conversions
- if outer is to handle a type with differing precision.
+Sun Jun 21 00:42:20 1998 H.J. Lu (hjl@gnu.org)
-Mon Jul 17 14:37:35 1995 Pat Rankin (rankin@eql.caltech.edu)
+ * Makefile.in (crtbeginS.o, crtendS.o): Add -fno-exceptions and
+ -DCRTSTUFFS_O.
+ (INSTALL): cd $(srcdir) before make.
- * vax/vms.h (HAVE_ATEXIT): Define.
- (DO_GLOBAL_CTORS_BODY): Don't call atexit; let __do_global_ctors do it.
- * vax/xm-vms.h (HAVE_VPRINTF): Define.
+ * flow.c (allocate_for_life_analysis, init_regset_vector):
+ Remove declaration.
+
+ * function.h (get_first_block_beg): New declaration.
+
+ * gbl-ctors.h (__do_global_dtors): Add prototype.
+
+ * gcov-io.h (__fetch_long): New declaration.
+ (__store_long): Likewise.
+ (__read_long): Likewise.
+ (__write_long): Likewise.
+
+ * gcov.c (print_usage): New declaration.
+
+ * Makefile.in (c-iterate.o): Depend on insn-codes.h too.
+
+Sat Jun 20 00:36:16 1998 Jeffrey A Law (law@cygnus.com)
+
+ * calls.c (expand_call): Initialize "src" and "dest".
+ * stmt.c (expand_return): Likewise.
+ * expmed.c (extract_split_bit_field): Similarly for "result"
+ * gcse.c (compute_hash_table): Mark first arg as unused.
+ * jump.c (jump_optimize): Initialize reversep.
+ * tree.c (make_node): Initialize length.
-Mon Jul 17 06:41:19 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * c-common.c (check_format_info): Initialize length_char and
+ fci to keep -Wall quiet.
- * c-typeck.c ({unsigned,signed}_type): Handle intXX_type_node types.
+ * except.c (jumpif_rtx): Put declaration and definition
+ inside a suitable #ifdef.
+ (jumpifnot_rtx): Delete dead function.
- * xm-alpha.h (sbrk): Add declaration.
+ * i386.h (output_int_conditional_move): Declare.
+ (output_fp_conditional_move): Likewise.
+ (ix86_can_use_return_insn_p): Likewise.
- * convert.c (convert_to_integer): If TYPE is a enumeral type or
- if its precision is not the same as the size of its mode,
- convert in two steps.
+ * optabs.c (init_traps): Put prototype inside a suitable #ifdef.
- * m68k.md (tstdi, cmpdi): Use match_scratch, not match_operand.
+Sat Jun 20 00:27:40 1998 Graham <grahams@rcp.co.uk>
-Fri Jul 14 19:23:42 1995 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+ * alias.c: Include toplev.h
+ * caller-save.c: Include toplev.h
+ * combine.c: Include toplev.h
+ * flow.c Include toplev.h
+ * global.c: Include toplev.h
+ * jump.c: Include toplev.h
+ * local-alloc.c: Include toplev.h
+ * loop.c: Include toplev.h
+ * regmove.c: Include toplev.h
+ * stupid.c: Include toplev.h
+ * unroll.c: Include toplev.h
+ * Makefile.in: Add toplev.h dependencies.
- * c-decl.c (field_decl_cmp): Rewritten to make sure that a null
- name always sorts low against other names.
- * c-typeck.c (lookup_field): Change name comparison to match what
- field_decl_cmp does.
+Fri Jun 19 22:40:25 1998 Jason Merrill <jason@yorick.cygnus.com>
-Fri Jul 14 18:46:24 1995 Michael Meissner <meissner@cygnus.com>
+ * regmove.c (copy_src_to_dest): Add decl for loop_depth.
- * rs6000.md (movsi): Convert a CONST_DOUBLE into a CONST_INT of
- the low part.
+ * svr4.h (ASM_GENERATE_INTERNAL_LABEL): Cast arg to unsigned.
+ * dwarf2out.c (ASM_OUTPUT_DWARF_DATA1): Likewise.
+ Add parens to various macros.
+
+Fri Jun 19 23:22:42 1998 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
+
+ * c-typeck.c (pop_init_level): Warn about implicit zero initialization
+ of struct members.
+
+Fri Jun 19 23:06:33 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * varasm.c (assemble_start_function): Add weak_global_object_name.
+ * tree.c (get_file_function_name): Use it.
+
+Fri Jun 19 22:55:14 1998 Jeffrey A Law (law@cygnus.com)
+
+ * except.c (jumpif_rtx): Make static and add prototype.
+ (jumpifnot_rtx): Likewise.
+
+ * README.gnat: Add a build patch from Fred Fish.
+
+ * c-lang.c (GNU_xref_begin, GNU_xref_end): Deleted.
+
+ * Makefile.in (c-iterate.o): Depend on expr.h.
+
+Fri Jun 19 20:38:34 1998 H.J. Lu (hjl@gnu.org)
+
+ * except.h (emit_unwinder, end_eh_unwinder): Removed.
+
+ * dwarfout.c (getpwd): Add prototype.
+ (is_pseudo_reg, type_main_variant, is_tagged_type,
+ is_redundant_typedef): New declaration.
+ (output_decl): Add prototype for FUNC.
+ (type_main_variant): Make it static.
+ (is_tagged_type): Likewise.
+ (is_redundant_typedef): Likewise.
+
+ * expr.c (do_jump_by_parts_greater_rtx): Removed.
+ (truthvalue_conversion): Likewise.
+
+ * c-iterate.c: Include "expr.h".
+ (expand_expr): Use proper values when calling the function.
+
+ * explow.c (emit_stack_save): Add prototype for FCN.
+ (emit_stack_restore): Likewise.
+
+ * dwarf2out.c (getpwd): Add prototype.
+
+ * dwarf2out.h (debug_dwarf, debug_dwarf_die): New declarations.
+
+ * c-typeck.c (c_expand_asm_operands): Use proper values when calling
+ expand_expr.
+
+ * c-lex.c (yyprint): Add prototype.
+ (check_newline, build_objc_string): Remove declaration.
+
+ * c-tree.h (comptypes_record_hook): Removed.
+ (finish_incomplete_decl): New prototype.
+
+ * alias.c (find_base_value): Add prototype.
+ (true_dependence): Add prototype for function argument.
+
+ * c-aux-info.c (xmalloc): Remove declaration.
+
+Fri Jun 19 20:23:05 1998 Robert Lipe <robertl@dgii.com>
+
+ * i386.c: Include system.h. Remove redundant includes.
+ (optimization_options): Mark param 'size' with ATTRIBUTE_UNUSED.
+ (i386_cc_probably_useless_p): Likewise for 'decl', 'attributes',
+ 'identifier', 'args'.
+ (i386_valid_type_attribute_p): Likewise for 'attributes'.
+ (i386_comp_type_attribute_p): Likewise for 'type1', 'type2'.
+ (function_arg_partial_nregs): Likewise for 'cum', 'mode', 'type',
+ and 'named'.
+ (symbolic_operand): Likewise for 'mode'.
+ (call_insn_operand): Likewise.
+ (expander_call_insn_operand): Likewise.
+ (ix86_logical_operator): Likewise.
+ (ix86_binary_operator_ok): Likewise.
+ (emit_pic_move): Likewise.
+ (VOIDmode_compare_op): Likewise.
+ (is_mul): Likewise.
+ (str_immediate_operand): Likewise.
+ (ix86_uary_operator_ok): Likewise for 'code', 'mode', and 'operands'.yy
+ (asm_output_function_prefix): Likewise for 'name'.
+ (function_prologue): Likewise for 'file', and 'size'.
+ (function_epilogue): Likewise.
+
+1998-06-19 Jim Wilson <wilson@cygnus.com>
+
+ * loop.h (struct induction): Clarify comment for unrolled field.
+ * unroll.c (find_splittable_givs): Move set of unrolled field
+ after address validity check.
+
+Fri Jun 19 18:38:04 1998 Michael Meissner <meissner@cygnus.com>
+
+ * config/fp-bit.c (INLINE): Only define if not already defined.
+
+1998-06-19 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * Makefile.in (installdirs): Loop over directories in $(libsubdir)
+ creating probably missing ones, instead of single if statements.
+
+Fri Jun 19 10:43:52 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * c-common.c (truthvalue_conversion): Protect side effects in the
+ expression when splitting a complex value.
+ * fold-const.c (fold): Likewise.
+
+Fri Jun 19 02:31:16 1998 Klaus Kaempf (kkaempf@progis.de)
+
+ * cccp.c (hack_vms_include_specification): rewrite to handle
+ '#include <dir/file.h>' correctly.
+
+Fri Jun 19 02:24:11 1998 H.J. Lu (hjl@gnu.org)
+
+ * config/i386/linux.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Defined.
+
+Fri Jun 19 02:10:10 1998 John Wehle (john@feith.com)
+
+ * i386.c (notice_update_cc): Integer conditional moves don't
+ affect cc0.
+
+ * i386.md (movsfcc, movdfcc, movxfcc): Use emit_store_flag
+ to support LT, LE, GE, and GT signed integer comparisons.
+ (movsfcc+1, movsfcc+2, movdfcc+1, movdfcc+2,
+ movxfcc+1, movxfcc+2): Pattern doesn't match if the comparison
+ is LT, LE, GE, or GT.
+ (movdicc): Remove code resulting from an earlier patch which
+ didn't apply correctly.
+
+Fri Jun 19 02:00:19 1998 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * reload1.c (reload_cse_regno_equal_p): If -ffloat-store, don't
+ consider a MEM in FP mode as equal.
+
+Fri Jun 19 01:02:17 1998 Jeffrey A Law (law@cygnus.com)
+
+ * c-decl.c (duplicate_decls): Avoid setting TREE_ASM_WRITTEN for
+ duplicate declarations of a function.
+
+Fri Jun 19 00:33:33 1998 H.J. Lu (hjl@gnu.org)
+
+ * config/float-i386.h: New.
+
+ * configure.in (i[34567]86-*-linux-*): Set float_format to i386.
+
+Thu Jun 18 20:11:00 1998 Jim Wilson <wilson@cygnus.com>
+
+ * sched.c (schedule_insns): Use xmalloc not alloca for max_uid
+ indexed arrays. Call free at the end of the function for them.
+ * haifa-sched.c (schedule_insns): Likewise.
+
+Thu Jun 18 18:16:01 1998 Jim Wilson <wilson@cygnus.com>
+
+ * dwarf2out.c (size_of_string): Do count backslashes.
+
+Thu Jun 18 11:43:54 1998 Nick Clifton <nickc@cygnus.com>
+
+ * config/arm/thumb.h (GO_IF_LEGITIMATE_ADDRESS): Disallow REG+REG
+ addressing when one register is the frame pointer or stack
+ pointer. Disallow REG+CONST addressing in HI mode.
+
+Thu Jun 18 17:30:39 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * reload.c (find_reloads): Don't narrow scope of RELOAD_OTHER to
+ RELOAD_FOR_INSN.
+
+Thu Jun 18 09:36:50 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (c-lang.o): Depend on output.h.
+
+ * c-lang.c: Include output.h.
+
+ * sparc.c (sparc_builtin_saveregs): Remove unused variable `fntype'.
+
+ * except.c (expand_builtin_eh_stub): Likewise for variable `jump_to'.
+
+ * genrecog.c (write_subroutine): When writing insn-recog.c, mark
+ variables `insn', `pnum_clobbers', `x[0 .. max_depth]' and `tem'
+ with ATTRIBUTE_UNUSED.
+
+ * regmove.c (copy_src_to_dest): Make function static to match its
+ prototype.
+
+ * reload1.c Include hard-reg-set.h before rtl.h to get macro
+ HARD_CONST. Include machmode.h before hard-reg-set.h.
+
+ * rtl.h: Prototype `retry_global_alloc' and wrap with macro
+ HARD_CONST to protect usage of typedef HARD_REG_SET.
+
+ * tree.c: Prototype `_obstack_allocated_p'.
+
+ * varasm.c: Wrap prototype of `asm_output_aligned_bss' in macro
+ BSS_SECTION_ASM_OP.
+
+Thu Jun 18 09:20:47 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * pa.c: Include system.h and toplev.h. Remove redundant code.
+ (call_operand_address): Mark parameter `mode' with ATTRIBUTE_UNUSED.
+ (symbolic_operand): Likewise.
+ (symbolic_memory_operand): Likewise.
+ (pic_label_operand): Likewise.
+ (fp_reg_operand): Likewise.
+ (pre_cint_operand): Likewise.
+ (post_cint_operand): Likewise.
+ (ireg_or_int5_operand): Likewise.
+ (int5_operand): Likewise.
+ (uint5_operand): Likewise.
+ (int11_operand): Likewise.
+ (uint32_operand): Likewise.
+ (ior_operand): Likewise.
+ (lhs_lshift_cint_operand): Likewise.
+ (pc_or_label_operand): Likewise.
+ (legitimize_pic_address): Likewise.
+ (hppa_legitimize_address): Likewise for parameter `old'.
+ (output_block_move): Likewise for parameter `size_is_constant'.
+ (output_function_prologue): Likewise for parameter `size'.
+ (output_function_epilogue): Likewise.
+ (return_addr_rtx): Likewise for parameter `count'.
+ (output_mul_insn): Likewise for parameter `unsignedp'.
+ (hppa_builtin_saveregs): Likewise for parameter `arglist'.
+ (output_bb): Likewise for parameter `operands'.
+ (output_bvb): Likewise.
+ (function_label_operand): Likewise for parameter `mode'.
+ (plus_xor_ior_operator): Likewise.
+ (shadd_operand): Likewise.
+ (non_hard_reg_operand): Likewise.
+ (eq_neq_comparison_operator): Likewise.
+ (movb_comparison_operator): Likewise.
+ (pa_combine_instructions): Likewise for parameter `insns'.
-Fri Jul 14 18:30:52 1995 Doug Evans <dje@cygnus.com>
+ * pa.h: Add prototypes for functions `output_deferred_plabels',
+ `override_options', `output_ascii', `output_function_prologue',
+ `output_function_epilogue', `print_operand',
+ `symbolic_expression_p', `reloc_needed', `compute_frame_size',
+ `hppa_address_cost', `and_mask_p', `symbolic_memory_operand',
+ `pa_adjust_cost', `pa_adjust_insn_length' and
+ `secondary_reload_class'.
- * toplev.c (main): Reword dwarf/c++/-g warning.
+Wed Jun 17 22:28:48 1998 Jason Merrill <jason@yorick.cygnus.com>
-Fri Jul 14 18:19:34 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * configure.in: Don't turn on collect2 unconditionally.
- * expr.h (NO_DEFER_POP): Remove last change.
- * expr.c (stor_expr): Force stack adjust before NO_DEFER_POP.
- (expand_expr, case COND_EXPR): Likewise.
- * stmt.c (expand_start_stmt_expr): Likewise.
+Wed Jun 17 20:20:48 1998 Mark Mitchell <mark@markmitchell.com>
-Fri Jul 14 07:58:35 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * cse.c (cse_basic_block): Don't include NOTE insns in the count
+ that is used to decide whether or not it is time to erase the
+ equivalence table.
- * function.c (struct temp_slot): New fields base_offset, full_size.
- (assign_stack_temp): For !FRAME_GROWS_DOWNWARD, set p->size to size.
- Set new fields base_offset and full_size.
- (combine_temp_slots): Use new fields base_offset and full_size instead
- of slot and size.
+Wed Jun 17 18:30:43 1998 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
- * loop.c (loop_number_exit_count): New global variable.
- (loop_optimize): Allocate space for it.
- (find_and_verify_loops, mark_loop_jump): Set it.
- (strength_reduce, check_dbra_loop): Use loop_number_exit_count
- instead of loop_number_exit_labels.
- * loop.h (loop_number_exit_count): Declare it.
- * unroll.c (find_splittable_{regs,givs}, final_[bg]iv_value): Use
- loop_number_exit_count instead of loop_number_exit_labels.
- (reg_dead_after_loop): Check loop_number_exit_count, and fail
- if the count doesn't match loop_number_exit_labels.
+ * rs6000/linux.h (JUMP_TABLES_IN_TEXT_SECTION): Define to zero.
- * cse.c (cse_insn): Ifdef out code that pre-truncates src_folded.
+Wed Jun 17 19:05:03 1998 John Carr <jfc@mit.edu>
- * sparc.md (sethi_di_sp64): Return null string at end.
+ * haifa-sched.c (haifa_classify_insn): TRAP_IF is risky.
+ (sched_analyze_2): Allow scheduling TRAP_IF.
- * function.h (struct function): Add stdarg field.
- * function.c (current_function_stdarg): New global variable.
+ * reorg.c (mark_referenced_resources): Examine operands of TRAP_IF.
+
+ * rtl.h (TRAP_CODE): New macro.
+
+ * rtl.def (TRAP_IF): Change second operand type to rtx.
+
+ * optabs.c (gen_cond_trap): New function.
+ (init_traps): New function.
+ (init_optabs): Call init_traps.
+ * expr.h: Declare gen_cond_trap.
+
+ * jump.c (jump_optimize): Optimize jumps to and around traps.
+
+ * sparc.md: Define trap instructions.
+
+ * rs6000.md: Define trap instructions.
+ * rs6000.c (print_operand): New code 'V' for trap condition.
+ (trap_comparison_operator): New function.
+
+ * m88k.md: Update use of TRAP_IF.
+
+ * tree.h (enum built_in_function): New function code BUILT_IN_TRAP.
+ * c-decl.c (init_decl_processing): New builtin __builtin_trap.
+ * expr.c (expand_builtin): Handle BUILT_IN_TRAP.
+
+ * expr.c (expand_builtin): Error if __builtin_longjmp second argument
+ is not 1.
+
+Wed Jun 17 15:20:00 PDT 1998 Catherine Moore <clm@cygnus.com>
+
+ * reload1.c (spill_hard_reg): Check mode of register when
+ spilling from scratch_list.
+
+Wed Jun 17 16:25:38 EDT 1998 Andrew MacLeod (amacleod@cygnus.com)
+
+ * except.c (add_new_handler): fix bug in finding last region handler.
+ * libgcc2.c (find_exception_handler): Pass exception table pointer
+ to runtime type matcher, not the match info field.
+
+Wed Jun 17 15:57:48 EDT 1998 Andrew MacLeod (amacleod@cygnus.com)
+
+ * eh-common.h (struct eh_context): Add comment for hidden use of
+ field dynamic_handler_chain.
+ * except.c (get_dynamic_handler_chain): Comment on, and use the
+ correct offset of the dynamic_handler_chain field.
+
+1998-06-17 12:46:56 1998 Jim Wilson <wilson@cygnus.com>
+
+ * mips/iris6.h (LINK_SPEC): Add -woff 131.
+
+1998-06-17 Jason Merrill <jason@yorick.cygnus.com>
+
+ * dwarf2out.c: Disable EH_FRAME_SECTION if we don't have .init.
+
+ * configure.in: Don't disable collect2 when we have GNU ld.
+
+Wed Jun 17 08:38:13 1998 Jeffrey A Law (law@cygnus.com)
+
+ * fold-const.c (make_range): Do not widen the type of the expression.
+
+ * expr.c (check_max_integer_computation_mode): New function.
+ (expand_expr): Avoid integer computations in modes wider than
+ MAX_INTEGER_COMPUTATION_MODE.
+ * fold-const.c (fold): Likewise.
+ * tree.h (check_max_integer_computation_mode): Declare.
+ * tm.texi (MAX_INTEGER_COMPUTATION_MODE): Document it.
+
+ * configure.in (nm): Make a link to "nm" in the build tree too.
+
+ * mn10300.md (andsi3): Fix typo.
+
+Tue Jun 16 22:58:40 1998 Richard Henderson <rth@cygnus.com>
+
+ * reload1.c (reload_cse_regs): Call bzero instead of looping.
+
+Tue Jun 16 18:30:35 1998 Jim Wilson <wilson@cygnus.com>
+
+ * dwarf2out.c (stripattributes): Prepend '*' to the section name.
+
+Tue Jun 16 16:49:26 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_expand_prologue, alpha_expand_epilogue): New fns.
+ (output_prologue, output_epilogue): Merge VMS and OSF versions;
+ Remove anything related to the actual code generation.
+ (output_end_prologue): New function.
+ (alpha_sa_mask, alpha_sa_size): Merge VMS and OSF versions.
+ (alpha_does_function_need_gp): Return false for VMS.
+ (alpha_function_needs_gp): Make static.
+ (add_long_const): Delete.
+ (summarize_insn): Don't assume a SUBREG is of a REG.
+ Prototype all static functions. Rename VMS-specific global
+ variables vms_*.
+ * alpha.h (TARGET_CAN_FAULT_IN_PROLOGUE): Default to 0.
+ (FUNCTION_BOUNDARY): Align to cache line.
+ (LOOP_ALIGN, ALIGN_LABEL_AFTER_BARRIER): Align to octaword.
+ (FUNCTION_END_PROLOGUE): New macro.
+ * alpha.md (attribute length): New. Mark all insns.
+ (return_internal, prologue_stack_probe_loop) New patterns.
+ (prologue, init_fp, epilogue): New patterns.
+ Disable peepholes.
+ * linux.h (TARGET_CAN_FAULT_IN_PROLOGUE): Define.
+
+Tue Jun 16 17:36:35 1998 Dave Brolley <brolley@cygnus.com>
+
+ * toplev.c (lang_options): Add -trigraphs option for cpplib.
+
+Tue Jun 16 23:33:24 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * reload1.c (reload_reg_free_before_p): RELOAD_FOR_OUTADDR_ADDRESS
+ is earlier than RELOAD_FOR_OUTPUT_ADDRESS; RELOAD_FOR_INPADDR_ADDRESS
+ is earlier than RELOAD_FOR_INPUT_ADDRESS.
+
+Tue Jun 16 13:15:16 1998 Jim Wilson <wilson@cygnus.com>
+
+ * libgcc1-test.c (memcpy): Define.
+
+Tue Jun 16 13:44:02 1998 Michael Meissner <meissner@cygnus.com>
+
+ * genattrtab.c (struct attr_desc): Change int flags to bit
+ fields. Add bit fields for this being function_units_used
+ or *_blockage_range attributes.
+ (write_unit_name): New function to print a function unit name
+ given unit #.
+ (expand_units): Indicate whether this is function_units_used or
+ *_blockage_range attributes.
+ (write_toplevel_expr): Print function_units_used and
+ *_blockage_range attributes in a more friendly fashion.
+ (make_internal_attr): Indicate whether this attribute is either
+ function_units_used or *_blockage_range.
+
+Mon Jun 15 17:06:43 1998 Michael Meissner <meissner@cygnus.com>
+ Jim Wilson <wilson@cygnus.com>
+
+ * regmove.c (copy_src_to_dest): Do not copy src to dest if either
+ the source or destination is special.
+
+Mon Jun 15 13:20:33 1998 Jim Wilson <wilson@cygnus.com>
+
+ * c-decl.c (shadow_tag_warned): Use specs not declspecs in for loop.
+
+Mon Jun 15 07:16:29 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sat Jun 13 13:10:40 1998 Krister Walfridsson <cato@df.lth.se>
+
+ * config/sparc/netbsd.h (DEFAULT_PCC_STRUCT_RETURN): Undefine before
+ redefining it.
+
+Fri Jun 12 18:06:45 1998 Doug Evans <devans@egcs.cygnus.com>
+
+ * m32r/m32r.h (STARTFILE_SPEC): Delete crtsysc.o.
+ (ENDFILE_SPEC): Add -lgloss.
+
+Fri Jun 12 14:57:59 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * mips.c (small_int): Mark parameter `mode' with ATTRIBUTE_UNUSED.
+ (large_int): Likewise.
+ (pc_or_label_operand): Likewise.
+ (call_insn_operand): Likewise.
+ (consttable_operand): Likewise.
+ (m16_uimm3_b): Likewise.
+ (m16_simm4_1): Likewise.
+ (m16_nsimm4_1): Likewise.
+ (m16_simm5_1): Likewise.
+ (m16_nsimm5_1): Likewise.
+ (m16_uimm5_4): Likewise.
+ (m16_nuimm5_4): Likewise.
+ (m16_simm8_1): Likewise.
+ (m16_nsimm8_1): Likewise.
+ (m16_uimm8_1): Likewise.
+ (m16_nuimm8_1): Likewise.
+ (m16_uimm8_m1_1): Likewise.
+ (m16_uimm8_4): Likewise.
+ (m16_nuimm8_4): Likewise.
+ (m16_simm8_8): Likewise.
+ (m16_nsimm8_8): Likewise.
+ (m16_usym8_4): Likewise.
+ (m16_usym5_4): Likewise.
+ (mips_move_1word): Change type of variable `i' from int to size_t.
+ (mips_move_2words): Likewise.
+ (output_block_move): Mark parameter `libname' with ATTRIBUTE_UNUSED.
+ (function_arg_advance): Use HOST_PTR_PRINTF to print an address.
+ (function_arg): Likewise.
+ (function_arg_partial_nregs): Mark parameter `named' with
+ ATTRIBUTE_UNUSED.
+ (override_options): Use ISDIGIT instead of isdigit.
+ (mips_output_external): Mark parameter `file' with ATTRIBUTE_UNUSED.
+ (final_prescan_insn): Likewise for parameters `opvec' and `noperands'.
+ (save_restore_insns): Cast HOST_WIDE_INT arguments passed to
+ function `fatal' to long before printing. Use
+ HOST_WIDE_INT_PRINT_DEC in fprintf. Both changes done several
+ times in this function.
+ (function_prologue): Mark parameter `size' with ATTRIBUTE_UNUSED.
+ (function_epilogue): Likewise for parameters `file' and `size'.
+ Print an int with "%d" not "%ld".
+ (mips_select_rtx_section): Mark parameter `x' with ATTRIBUTE_UNUSED.
+ (mips_function_value): Likewise for parameter `func'.
+ (function_arg_pass_by_reference): Likewise for parameters `cum'
+ and `named'.
+ (extend_operator): Likewise for parameter `mode'
+ (highpart_shift_operator): Likewise.
+
+ * mips.md (mul_acc_si): Remove unused variable `macc'.
+
+Fri Jun 12 09:33:44 1998 Richard Henderson <rth@cygnus.com>
+
+ * fold-const.c (fold): Revert last change. It breaks constant
+ expressions somehow.
+
+Fri Jun 12 10:23:36 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * expr.c (do_jump, case EQ_EXPR, NE_EXPR): When comparing complex
+ prevent operands from being evaluated twice.
+
+Fri Jun 12 00:50:27 1998 Sergey Okhapkin <sos@prospect.com.ru>
+
+ * toplev.c (lang_options): Add -remap as a preprocessor option.
+
+Fri Jun 12 00:30:32 1998 John Wehle (john@feith.com)
+
+ * i386.md (cmpsi_1, cmphi_1, cmpqi_1): Remove code
+ which set CC_REVERSED since reload should ensure that
+ the operands are already the correct type.
+
+Thu Jun 11 17:14:15 1998 Jim Wilson <wilson@cygnus.com>
+
+ * except.c (expand_builtin_eh_stub): Call emit_move_insn rather than
+ calling gen_rtx_SET.
+
+Thu Jun 11 18:45:49 1998 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * config/rs6000/x-aix43 (AR): Delete.
+ (AR_FOR_TARGET_FLAGS): Add -X32_64 here.
+
+Thu Jun 11 16:19:17 1998 David W. Schuler <schuld@btv.ibm.com>
+
+ * config/i386/aix386ng.h (CPP_SPEC): Remove extraneous quote.
+
+Thu Jun 11 12:40:27 1998 Jim Wilson <wilson@cygnus.com>
+
+ * mips.c (override_options): Replace word_mode with explicit
+ TARGET_64BIT check.
+
+Thu Jun 11 14:50:02 1998 Michael Meissner <meissner@cygnus.com>
+
+ * regmove.c (regmove_optimize): If we can't replace the
+ destination in an insn that sets the source, generate an explicit
+ move of the source to the destination.
+ (copy_src_to_dest): New function.
+ (toplevel): Include basic-block.h
+
+ * Makefile.in (regmove.o): Add basic-block.h dependencies.
+
+Thu Jun 11 10:30:09 1998 Dave Brolley <brolley@cygnus.com>
+
+ * toplev.c (lang_options): Add missing options (nostdinc, idirafter).
+
+Wed Jun 10 23:39:32 1998 Mark Mitchell <mark@markmitchell.com>
+
+ * rtl.h (rtx_def): Improve documentation.
+ (MEM_IN_STRUCT_P): Likewise.
+
+Wed Jun 10 23:23:17 1998 Graham <grahams@rcp.co.uk>
+
+ * c-decl.c (start_decl): Correct test for -Wmain.
+
+ * c-decl.c (grokdeclarator): Remove unused variable "last".
+
+Wed Jun 10 14:52:27 1998 Jim Wilson <wilson@cygnus.com>
+
+ * expr.c (expand_builtin_setjmp): Store const1_rtx in target.
+ (expand_builtin_longjmp): Abort if value isn't const1_rtx.
+ Delete code storing value in static_chain_rtx.
+ (expand_builtin, case BUILT_IN_LONGJMP): Pass NULL_RTX for target
+ to second expand_expr call.
+
+Wed Jun 10 13:08:41 1998 Mark Mitchell <mark@markmitchell.com>
+
+ * mips/mips.c: Remove -mabi=o32 and -mabi=n64.
+
+Wed Jun 10 13:41:23 1998 Dave Brolley <brolley@cygnus.com>
+
+ * cppmain.c (fatal): New function.
+ * configure.in (cpp_main): New configuration variable.
+ * configure: Regenerated.
+ * Makefile.in (CCCP): Use a configuration variable to select basex
+ for cccp.
+ (cppmain$(exeext)): Add @extra_cpp_objs@.
+
+Wed Jun 10 13:07:02 1998 Dave Brolley <brolley@cygnus.com>
+
+ * objc/objc-act.c: Add cpplib declarations.
+ (lang_decode_option): Initialize cpplib if necessary.
+ (lang_decode_option): New argc/argv interface.
+ * tree.h (lang_decode_option): New argc/argv interface.
+ * toplev.c (lang_options): Add cpp options.
+ (main): New interface for lang_decode_option.
+ * gcc.c (default_compilers): Don't call cpp for a cpplib-enabled C compiler
+ unless -E, -M or -MM is specified.
+ * cpplib.h (cpp_handle_option): New function.
+ * cpplib.c (cpp_handle_option): New function.
+ (cpp_handle_options): Now calls cpp_handle_option.
+ * c-tree.h (c_decode_option): New argc/argv interface.
+ * c-lex.c (init_parse): cpplib now initialized in c_decode_option.
+ * c-lang.c (lang_decode_option): New argc/argv interface.
+ * c-decl.c: Add cpplib declarations.
+ (c_decode_option): New argc/argv interface.
+ (c_decode_option): Call cpp_handle_option.
+ (c_decode_option): Now returns number of strings processed.
+
+Wed Jun 10 09:47:13 1998 Richard Earnshaw (rearnsha@arm.com)
+
+ * unroll.c (verify_addresses): Use validate_replace_rtx to undo the
+ changes. Abort if the undo fails.
+
+1998-06-10 Vladimir N. Makarov <vmakarov@cygnus.com>
+
+ * config/rs6000/rs6000.c (output_prolog): Change locations and
+ directions of saving and restoring arguments of main on the stack.
+
+Wed Jun 10 08:56:27 1998 John Carr <jfc@mit.edu>
+
+ * reload1.c (reload_cse_simplify_operands): Do not call gen_rtx_REG
+ for each alternative. Do not replace a CONST_INT with a REG unless
+ the reg is cheaper.
+
+Wed Jun 10 02:11:55 1998 Jeffrey A Law (law@cygnus.com)
+
+ * decl.c (init_decl_processing): Fix typo.
+
+ * mips.c (gpr_mode): New variable.
+ (override_options): Initialize gpr_mode.
+ (compute_frame_size): Use "gpr_mode" instead of "word_mode" to
+ determine size and offset of general purpose registers save slots.
+ (save_restore_insns, mips_expand_prologue): Similarly.
+
+ * reload.c (find_reloads_toplev): Use gen_lowpart common to convert
+ between constant representations when we have (SUBREG (REG)) with
+ REG equivalent to a constant.
+
+Wed Jun 10 01:39:00 1998 Juha Sarlin <juha@c3l.tyreso.se>
+
+ * h8300.c (get_shift_alg): Add special cases for shifts of 8 and 24.
+
+Tue Jun 9 22:05:34 1998 Richard Henderson <rth@cygnus.com>
+
+ * fold-const.c (fold): Even with otherwise constant trees, look for
+ opportunities to combine integer constants.
+
+Wed Jun 3 23:41:24 EDT 1998 John Wehle (john@feith.com)
+
+ * i386.c (notice_update_cc): Clear cc_status.value2 in the
+ case of UNSPEC 5 (bsf).
+
+ * i386.md (movsfcc, movdfcc, movxfcc): The floating point
+ conditional move instructions don't support signed integer
+ comparisons.
+
+Tue Jun 9 14:31:19 1998 Nick Clifton <nickc@cygnus.com>
+
+ * config/v850/t-v850 (TCFLAGS): Add assembler options to warn of
+ overlfows.
+
+ * config/v850/lib1funcs.asm (__return_interrupt): Use 'addi
+ 16,sp,sp' ratehr than 'add 16,sp'. Patch courtesy of Biomedin
+ <glctr@abc.it>.
+
+Tue Jun 9 16:23:13 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
+
+ * except.c (expand_start_catch): Rename to start_catch_handler.
+ (expand_end_catch): Delete function.
+ (expand_end_all_catch): Remove catch status that expand_end_catch
+ use to do.
+ * except.h (expand_start_catch): Rename prototype.
+ (expand_end_catch): Delete prototype.
+
+Tue Jun 9 12:57:32 1998 Mark Mitchell <mark@markmitchell.com>
+
+ * invoke.texi: Add documentation for -mips4 and -mabi=*.
+
+Tue Jun 9 12:12:34 1998 Klaus Kaempf (kkaempf@progis.de)
+
+ * alpha/vms.h (EXTRA_SECTIONS): Add in_ctors and in_dtors.
+ (EXTRA_SECTION_FUNCTIONS): Add ctors_section and dtors_section.
+ (ASM_OUTPUT_CONSTRUCTOR, ASM_OUTPUT_DESTRUCTOR): Define.
+
+Tue Jun 9 12:10:27 1998 John Carr <jfc@mit.edu>
+
+ * haifa-sched.c (update_flow_info): Use UNITS_PER_WORD, not MOVE_MAX,
+ as the threshold to permit splitting memory operations.
+
+Tue Jun 9 12:36:16 1998 Jeffrey A Law (law@cygnus.com)
+
+ * mips.c (gpr_mode): New variable.
+ (override_options): Initialize gpr_mode.
+ (compute_frame_size): Use "gpr_mode" instead of "word_mode" to
+ determine size and offset of general purpose registers save slots.
+ (save_restore_insns, mips_expand_prologue): Similarly.
+
+ * Makefile.in (LIB2FUNCS_EH): Define. Just "_eh" for now.
+ (LIBGCC2_CFLAGS): Remove -fexceptions.
+ (LIB2FUNCS): Remove "_eh".
+ (libgcc2.a): Iterate over LIB2FUNCS_EH and build everything in
+ it with -fexceptions.
+
+ * Makefile.in (local-alloc.o): Depend on insn-attr.h.
+ * local-alloc.c (block_alloc): Avoid creating false
+ dependencies for targets which use instruction scheduling.
+
+Tue Jun 9 02:40:49 1998 Richard Henderson <rth@cygnus.com>
+
+ * mips/elf.h (ASM_DECLARE_OBJECT_NAME): Define.
+ (ASM_FINISH_DECLARE_OBJECT): Define;
+ * mips/elf64.h: Likewise.
+
+Tue Jun 9 01:08:47 1998 Richard Henderson <rth@cygnus.com>
+
+ * toplev.c (flag_new_exceptions): Remove extraneous `extern'.
+
+Mon Jun 8 23:24:48 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Mon Jun 8 23:24:58 1998 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * rs6000.md (mulsidi3): Add !TARGET_POWERPC64 constraint.
+ (mulsidi3_ppc64): Delete.
+
+Mon Jun 8 20:57:40 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (varasm.o): Depend on dbxout.h.
+ (cse.o): Depend on toplev.h and output.h.
+ (gcse.o): Depend on output.h.
+
+ * mips.c: Include system.h and toplev.h and remove redundant code.
+ Include output.h after tree.h so all its prototypes get activated.
+ * mips.md (table_jump): Remove unused variable `dest'.
+
+ * sparc.h: Add prototype for `v8plus_regcmp_op'.
+
+ * crtstuff.c (fini_dummy, init_dummy): Mark function definitions
+ with __attribute__ ((__unused__)).
+ (__frame_dummy): Provide prototype before use, wrap it with
+ EH_FRAME_SECTION_ASM_OP.
+
+ * cse.c: Move inclusion of <setjmp.h> above local headers.
+ Include toplev.h and output.h.
+
+ * dbxout.h: Add prototype for `dbxout_begin_function'.
+
+ * final.c (final_scan_insn): Wrap variable `max_skip' in macro
+ ASM_OUTPUT_MAX_SKIP_ALIGN.
+
+ * gcse.c: Include system.h and output.h.
+ (dump_cuid_table, dump_rd_table, dump_cprop_data, dump_pre_data):
+ Make extern instead of static.
+ (compute_can_copy): Only declare variables `reg' and `insn' when
+ AVOID_CCMODE_COPIES is not defined.
+ (record_set_info): Mark parameter `setter' with ATTRIBUTE_UNUSED.
+ (hash_scan_clobber): Likewise for `x' and `insn'.
+ (hash_scan_call): Likewise.
+ (record_last_set_info): Likewise for `setter'.
+ (mark_call): Likewise for `pat'.
+ (pre_insert_insn): Wrap variable `note' in macro HAVE_cc0.
+
+ * libgcc2.c (__bb_init_prg): Replace bzero with memset and fix the
+ length parameter so that it multiplies the number of elements by
+ the sizeof(element).
+
+ * output.h: Add prototype for `weak_finish'.
+
+ * recog.h: Likewise for `validate_replace_src'.
+
+ * rtl.h: Likewise for `optimize_save_area_alloca',
+ `fix_sched_param', `purge_addressof', `gcse_main',
+ `regmove_optimize', `dbr_schedule', `branch_prob' and
+ `end_branch_prob'.
+
+ * toplev.h: Likewise for `set_float_handler' and
+ `output_quoted_string'.
+
+ * varasm.c: Include dbxout.h.
+
+Mon Jun 8 18:12:06 1998 Jim Wilson <wilson@cygnus.com>
+
+ * mips.c (mips_secondary_reload_class): Use gp_reg_p instead of
+ GP_REG_P. Use gr_regs instead of GR_REGS.
+
+Mon Jun 8 16:54:12 1998 Ken Raeburn <raeburn@cygnus.com>
+ Jeff Law <law@cygnus.com>
+
+ * Revamped multiply support for MIPS chips.
+ * mips.c (extend_operator): New function.
+ (highpart_shift_operator): Likewise.
+ * mips.h: Declare new functions.
+ (PREDICATE_CODES): Add support for new predicates.
+ * mips.md (mulsi3 expander): Simplify.
+ (mulsi_mult3): Add another constraint alternative. Support
+ 3 operand multiply instructions as found on various mips
+ parts.
+ (mulsi3_r4650): Delete pattern, now handled by mulsi_mult3.
+ (mul_acc_si): New pattern and associated splitters.
+ (mulsidi3 expander): Rework to use mulsidi3_64bit and
+ mulsidi3_internal.
+ (umulsidi3): New expander.
+ (mulsidi3_internal): Accept either sign or zero extended
+ operands and generate code as appropriate appropriately.
+ (mulsidi3_64bit): Similarly.
+ (smulsi3_highpart): Turn into an expander and generate code
+ to match new patterns.
+ (umulsi3_highpart): Likewise.
+ (xmulsi3_highpart_internal): New pattern.
+ (maddi patterns): Delete. Replace with:
+ (mul_acc_di, mul-acc_64bit_di): New patterns.
+
+Mon Jun 8 14:16:15 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
+
+ * eh-common.h: Remove NEW_EH_MODEL compile time flag, and replace with
+ flag_new_exceptions runtime flag.
+ (struct old_exception_table): New struct which represents what
+ the exception table looks like without the new model.
+ (NEW_EH_RUNTIME): New value used as a tag in the exception table to
+ flag that this is a new style table.
+ * except.h: Remove compile time flag NEW_EH_MODEL.
+ (expand_builtin_eh_stub_old): New prototype.
+ * tree.h (enum built_in_function): Add BUILT_IN_EH_STUB_OLD.
+ * expr.c (expand_builtin): New builtin func BUILT_IN_EH_STUB_OLD.
+ * c-decl.c (init_decl_processing): Add new builtin function
+ __builtin_eh_stub_old.
+ * final.c (final_scan_insn): Replace compile time flag NEW_EH_MODEL.
+ * flags.h (flag_new_exceptions): New runtime flag.
+ * toplev.c (flag_new_exceptions): Initialize default to 0,
+ -fnew-exceptions sets to 1.
+ * except.c (output_exception_table_entry): Output New style exception
+ identifier into table, and replace compile time flag NEW_EH_MODEL
+ with runtime flag flag_new_exceptions.
+ (output_exception_table): Replace compile time flag NEW_EH_MODEL.
+ (expand_builtin_eh_stub_old): Duplicates original functionality of
+ expand_builtin_eh_stub.
+ (expand_builtin_eh_stub): Replace compile time flag NEW_EH_MODEL.
+ * libgcc2.c (find_exception_handler): Remove NEW_EH_MODEL #ifdefs.
+ (old_find_exception_handler): New func, same as find_exception_handler
+ except it works on the old style exception table.
+ (__throw): Replace NEW_EH_MODEL. Detect new model based on presence
+ of identifier in the exception table, and call appropriate routines.
+
+Mon Jun 8 01:21:13 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * function.c: Define current_function_cannot_inline.
(push_function_context_to): Save it.
(pop_function_context_from): Restore it.
- (assign_parms): Set it.
- (init_function_start): Clear it.
- * output.h (current_function_stdarg): Declare it.
- * i960.md: Modify all patterns which handle stores to memory to also
- check current_function_varargs and current_function_stdarg.
+ * function.h (struct function): Provide it a home.
+ * output.h: Declare it.
+ * integrate.c (function_cannot_inline_p): Check it.
+
+Mon Jun 8 10:43:15 1998 Richard Henderson <rth@cygnus.com>
+
+ * expr.c (force_operand): Detect PIC address loads before
+ splitting arithmetic.
+
+Mon Jun 8 09:22:38 PDT 1998 Jeff Law (law@cygnus.com)
- * reorg.c (fill_simple_delay_slots): When trying to take instruction
- from after the branch, don't continue past target label. Local
- variables passed_label and target_uses are no longer necessary.
+ * version.c: Bump for snapshot.
-Thu Jul 13 19:30:04 1995 Jeff Law (law@snake.cs.utah.edu)
+Mon Jun 8 02:55:56 1998 Graham <grahams@rcp.co.uk>
- * pa.c (output_bb): Fix error in long backwards branch with
- nullified delay slot.
+ * tree.c (tree_class_check): Add braces to eliminate ambigious
+ else warning.
+ (tree_check): Likewise.
-Thu Jul 13 19:26:13 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Mon Jun 8 02:49:23 1998 H.J. Lu (hjl@gnu.org)
- * expmed.c (SHIFT_COUNT_TRUNCATED): Use #ifdef not #if.
+ * reg-stack.c (subst_stack_regs_pat): Make sure the top of
+ stack is the destination for conditional move insn.
-Mon Jul 10 20:16:44 1995 Paul Eggert <eggert@twinsun.com>
+Mon Jun 8 01:21:13 1998 Jason Merrill <jason@yorick.cygnus.com>
- * cccp.c (rescan): Don't address outside of array when
- preprocessing C++ comments.
+ * tree.h (TREE_VEC_END): Cast unused value to void.
-Mon Jul 10 20:05:46 1995 Michael Meissner <meissner@tiktok.cygnus.com>
+ * i386.c (print_operand): Use %lx for long operand.
- * rs6000.c (expand_block_move): Remove #if 0 conditionals
- against using larger block moves.
+Mon Jun 8 00:04:07 1998 Richard Henderson <rth@cygnus.com>
- * t-rs6000 (EXTRA_PARTS): Copy milli.exp to release dir.
- (milli.exp): Copy to build dir from machine dependend dir.
+ * alpha.c (summarize_insn): Ignore rtl slot format 'i'.
-Mon Jul 10 20:03:29 1995 Richard Earnshaw (rearnsha@armltd.co.uk)
+Sun Jun 7 14:15:45 1998 John Carr <jfc@mit.edu>
- * arm.md (matcher for (shiftable_op (cond-exp) (reg))): If
- shiftable_op is minus, then subtract from zero when cond fails.
+ * sol2.h (INIT_SUBTARGET_OPTABS): Use Solaris libc float/long long
+ conversion functions.
-Mon Jul 10 19:58:26 1995 John F. Carr <jfc@mit.edu>
+Sun Jun 7 14:02:58 1998 Richard Henderson <rth@cygnus.com>
- * sparc.h (SELECT_SECTION): Use TREE_CODE_CLASS instead of directly
- referencing tree_code_type.
+ * toplev.c (flag_exceptions): Default to 0.
+ (compile_file): Remove flag_exceptions == 2 hack.
+ (main): Call lang_init_options.
+ * tree.h: Declare it.
+ * c-lang.c: Implement it.
+ * objc/objc-act.c: Likewise.
-Mon Jul 10 19:54:31 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Sun Jun 7 12:27:30 1998 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * rs6000.md (restore_stack_block): Generate MEM and specify mode.
+ * rs6000.h (STACK_SAVEAREA_MODE): SAVE_FUNCTION is VOIDmode.
+ * rs6000.c (rs6000_output_load_toc_table): Use fputs.
+ (output_function_profiler): Use asm_fprintf and fputs.
+
+Sat Jun 6 12:17:12 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * gencheck.c: Remove redundant stdio.h include. Add a definition
+ of xmalloc for when we are forced to link with alloca.o.
+
+ * reload1.c (reload_reg_free_for_value_p): Use `(unsigned)1'
+ instead of `1U'.
+
+ * fold-const.c (constant_boolean_node): Make definition static to
+ match the prototype.
+
+Fri Jun 5 15:53:17 1998 Per Bothner <bothner@cygnus.com>
+
+ * gcc.c (lang_specific_pre_link): New LANG_SPECIFIC_DRIVER function.
+ (lang_specific_extra_outfiles): New LANG_SPECIFIC_DRIVER variable.
+ (do_spec, input_filename, input_filename_length): Make public.
+ (main): Adjust outfiles allocation by lang_specific_extra_outfiles.
+ Call lang_specific_pre_link befor elinking.
+
+Fri Jun 5 12:29:28 1998 Jeffrey A Law (law@cygnus.com)
+
+ * haifa-sched.c (rank_for_schedule): For "equally good insns", prefer
+ the insn which has the most insns dependent on it.
+
+Fri Jun 5 09:03:22 1998 John Carr <jfc@mit.edu>
+
+ * alias.c (find_base_value): Avoid reading past end of reg_base_value.
+
+Fri Jun 5 03:05:34 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.md (insxh-1): New insxl pattern for combine.
+
+Fri Jun 5 01:12:15 1998 H.J. Lu (hjl@gnu.org)
+
+ * i386/i386.c (output_fp_conditional_move): New function
+ to output floating point conditional move.
+ (output_int_conditional_move): New function to output integer
+ conditional move.
+
+ * i386/i386.md (movsicci+5, movhicc+5, movdicc+5): Call
+ output_int_conditional_move () to output int conditional move.
+ (movsfcc+5, movdfcc+5, movxfcc+5): Call
+ output_fp_conditional_move () to output floating point
+ conditional move.
+
+ * i386/i386.c (put_condition_code): In INT mode, check
+ cc_prev_status.flags & CC_NO_OVERFLOW for GE and LT.
+
+Thu Jun 4 16:09:51 1998 Dave Brolley <brolley@cygnus.com>
+
+ * dbxout.c (dbxout_type): Output arrays of bits as if
+ they were bitstrings for Chill
+
+Thu Jun 4 14:35:27 1998 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * tree.c (get_inner_array_type): New function.
+ * tree.h (get_inner_array_type): Prototype.
+ * expr.h (STACK_SAVEAREA_MODE): New macro.
+ * expr.c (expand_builtin_setjmp): Initialize sa_mode using
+ STACK_SAVEAREA_MODE.
+ (expand_builtin_longjmp): Likewise.
+ * explow.c (emit_stack_save): Likewise.
+ (allocate_dynamic_stack_space): Use Pmode not insn_operand_mode.
+
+ * rs6000/aix41.h (ASM_CPU_SPEC): Define relative to ASM_DEFAULT_SPEC.
+ (CPP_CPU_SPEC): Define relative to CPU_DEFAULT_SPEC.
+ * rs6000/aix43.h: New file.
+ * rs6000/t-aix43: New file.
+ * rs6000/x-aix41: New file.
+ * rs6000/x-aix43: New file.
+ * configure.in (rs6000-ibm-aix*): Use them.
+ * rs6000/powerpc.h: Delete.
+ * rs6000/sysv4.h: Move necessary powerpc.h definitions to here.
+ * rs6000/netware.h: and here.
+ * rs6000/win-nt.h: and here.
+
+ * rs6000/rs6000.c (processor_target_table, 620): Do not affect
+ MASK_POWERPC64.
+ (rs6000_override_options): Ignore flag_pic for AIX.
+ (rs6000_immed_double_const): Delete.
+ (u_short_cint_operand): Don't assume 32-bit CONST_INT.
+ (reg_or_u_short_operand): Don't assume 32-bit CONST_INT.
+ (num_insns_constant): mask64_operand() is 2 insns.
+ (logical_operand): Don't assume 32-bit CONST_INT.
+ (non_logical_cint_operand): Don't assume 32-bit CONST_INT.
+ (easy_fp_constant): Any CONST_DOUBLE_HIGH is okay for 64-bit.
+ (mask_constant): HOST_WIDE_INT parameter.
+ (non_and_cint_operand): Delete.
+ (mask64_operand): New function.
+ (and64_operand): New function.
+ (function_arg_advance): DImode arguments do not need special
+ alignment when 64-bit.
+ (function_arg): Likewise.
+ (setup_incoming_varargs): Reverse reg_size assignment.
+ (print_operand): HOST_WIDE_INT second parameter.
+ (print_operand, 'B'): New case.
+ (print_operand, 'M'): Fix typo in lossage string.
+ (print_operandm 'S'): New case.
+ (rs6000_stack_info): Reverse reg_size assignment. Use total_raw_size
+ to compute AIX push_p. Use reg_size to compute {cr,lr}_save_offset.
+ (rs6000_output_load_toc_table): Reverse init_ptr assignment. Use
+ TARGET_64BIT not TARGET_POWERPC64. Convert fprintf to fputs.
+ Load GOT highpart, don't add it. Add lowpart with {cal|la}.
+ (rs6000_allocate_stack_space): Use {cal|la}.
+ (output_epilog): Use {cal|la}
+ (output_function_profiler): Add call glue to mcount call.
+ Load GOT highpart, don't add it. Add lowpart with {cal|la}.
+
+ * rs6000/rs6000.h (TARGET_SWITCHES): Add powerpc64.
+ (STACK_BOUNDARY): Depend on TARGET_32BIT.
+ (ADJUST_FIELD_ALIGN): Calculate array alignment using innermost type.
+ (CONST_OK_FOR_LETTER_P): Don't assume 32-bit CONST_INT.
+ (EXTRA_CONSTRAINTS): Remove NT 'S' and 'T'. Replace 'S' with
+ 64-bit mask operand.
+ (RS6000_SAVE_TOC): Depend on TARGET_32BIT.
+ (STACK_SAVEAREA_MODE): New macro.
+ (LEGITIMATE_CONSTANT_P): DImode okay for 64bit.
+ (LEGITIMIZE_RELOAD_ADDRESS): New macro.
+ (RTX_COSTS, AND/IOR/XOR): Reflect current machine description.
+ (ASM_FILE_START): Emit 64-bit ABI directive.
+ (ASM_DECLARE_FUNCTION_NAME): Align CSECT on doubleword in 64-bit mode.
+ (ASM_OUTPUT_SPECIAL_POOL_ENTRY): DImode okay for 64-bit.
+ (PREDICATE_CODES): Add "and64_operand" and "mask64_operand".
+ Delete "non_and_cint_operand". "input_operand" includes CONST_DOUBLE.
+
+ * rs6000/rs6000.md (iorsi3, xorsi3): Use HOST_WIDE_INT for mask.
+ Restore define_splits.
+ (floatsidf2, floatunssidf2): Remove !TARGET_POWERPC64 final constraint.
+ (floatsidf2_internal, floatunssidf2_internal2): Likewise.
+ Do not specify base register operand mode.
+ (floatsidf2_loadaddr): Do not specify base register operand mode.
+ (floatsidf2_store1, floatsidf2_store2): Operand 1 must be base
+ register; do not specify mode. Remove !TARGET_POWERPC64 final
+ constraint.
+ (floatsidf2_load): Do not specify base register operand mode. Remove
+ !TARGET_POWERPC64 final constraint.
+ (fix_truncdfsi2_internal, fix_truncdfsi2_{store,load}): Do not specify
+ base register operand mode.
+ (adddi3): Split large constants early.
+ (absdi3): Shift by 63, not 31.
+ (*mulsidi3_ppc64): New pattern.
+ (rotldi3): Add masking combiner patterns.
+ (anddi3): Add rldic{r,l} masking. Remove split of large constants
+ because PPC insns zero-extend.
+ (iordi3, xordi3): Split large constants early.
+ (movsi matcher): Remove S and T constraints.
+ (movsf const_double): create SImode constant from TARGET_DOUBLE.
+ (movdf_hardfloat32): Add default abort() case.
+ (movdf easy_fp_const): create DImode constant from TARGET_DOUBLE.
+ (movdi): Remove 64-bit constant generator. Try to convert
+ CONST_DOUBLE to CONST_INT. Handle TOC memory constants.
+ (movdi_32): Add default abort() case.
+ (movdi_64): Add numerous ways to split 64-bit constants.
+ Make catch-all define_split more optimal and never FAIL.
+ (movti_ppc64): Add default abort() case.
+ (allocate_stack): Remove operand modes. Use Pmode.
+ (restore_stack_block): Remove operand modes. Generate Pmode
+ temporary.
+ (save_stack_nonlocal, restore_stack_nonlocal): Generate Pmode
+ temporary. Save area is double Pmode.
+ (call_indirect_aix64, call_value_indirect_aix64): New patterns.
+ (call, call_value): Do not specify address operand mode. Choose
+ appropriate AIX ABI.
+ (*call_local64, *ret_call_local64): New patterns.
+ (*call_nonlocal_aix64, *ret_call_nonlocal_aix64): New patterns.
+ (*ret_call_nonlocal_aix32): Use call_value_indirect for REG.
+ (compare): Materialize DImode truthvalues.
- * protoize.c (reverse_def_dec_list): Delete const qualifiers from
- local variables, and delete casts which were casting away const.
+Thu Jun 4 01:26:57 1998 Craig Burley <burley@gnu.org>
-Mon Jul 10 19:14:39 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * expr.c (safe_from_p): Avoid combinatorial explosion
+ over duplicate SAVE_EXPRs by ensuring we never recurse
+ on one that has already been visited.
- * c-lang.c (finish_file): Add missing parm to start_function call.
+Thu Jun 4 00:54:21 1998 Graham <grahams@rcp.co.uk>
- * jump.c (jump_optimize): Pass outer_code arg to rtx_cost.
+ * loop.c (check_dbra_loop): Initialise final_value before
+ normalizing the loop.
- * varasm.c (assemble_name, bc_assemble_integer): Call
- bc_emit_labelref with proper args.
+Wed Jun 3 20:00:04 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * function.c (setjmp_args_warning): Remove bogus arg.
+ * reload1.c (reload_reg_free_for_value_p): New arguments out and
+ reloadnum. Changed all callers.
-Mon Jul 10 18:20:54 1995 Fergus Henderson (fjh@cs.mu.oz.au)
+1998-06-03 Ulrich Drepper <drepper@cygnus.com>
- * gcc.c (p{fatal,error}_with_name, perror_exec): Quote filename.
+ * system.h: Add _() and N_() macros in preparation for gettext.
-Mon Jul 10 18:12:51 1995 Gran Uddeborg (uddeborg@carmen.se)
+Wed Jun 3 11:02:24 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- * i386/iscdbx.h (STARTFILE_SPEC): Handle -Xp.
+ * c-common.c (check_format_info): Put back check for C9x `hh'
+ length modifier. Warn about %n format writing into const. Remove
+ obsolete comment.
+ (format_char_info): Fix comments.
-Wed Jul 5 02:42:17 1995 Per Bothner (bothner@spiff.gnu.ai.mit.edu)
+ * configure.in: Set float_format to m68k for all m68k targets that
+ do not override LONG_DOUBLE_TYPE_SIZE.
+ * config/float-m68k.h: New file.
- * cpphash.h (enum node_type): Remove unneeded and non-standard
- forward declaration.
+Tue Jun 2 23:14:01 1998 Richard Henderson <rth@cygnus.com>
-Sat Jul 1 20:15:39 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * jump.c (jump_optimize): Remove debug messages accidentally left in
+ with the previous change.
- * mips/t-mips, mips/t-mips-gas (MULTILIB_*, LIBGCC, INSTALL_LIBGCC):
- Delete.
+Tue Jun 2 22:46:08 1998 Richard Henderson <rth@cygnus.com>
- * sparc/sol2.h (LINK_SPEC): Revert March 16 change. Do not add -R
- for each -L.
-
- * collect2.c (libcompare): Verify that file name extensions are valid.
- Put files with invalid extensions last in the sort.
+ * expr.c (store_expr): Revert stray patch associated with
+ 1998-05-23 commit.
- * integrate.c (integrate_decl_tree): Set DECL_ABTRACT_ORIGIN before
- pushdecl call for local variables.
+Tue Jun 2 21:59:01 1998 Richard Henderson <rth@cygnus.com>
-Sat Jul 1 08:13:38 1995 Richard Earnshaw (rearnsha@armltd.co.uk)
+ * jump.c (rtx_unsafe_p): New function.
+ (jump_optimize): Use it on if/then/else transformations and
+ conditional move transformations.
- * cpplib.c (output_line_command): If not emitting #line directives
- delay returning until after adjust_position has been called.
+Tue Jun 2 22:50:10 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- * arm.md (mov{si,sf,df}cc): Call gen_compare_reg to generate
- the condition code register.
+ * fold-const.c (fold, case EQ_EXPR): When folding VAR++ == CONST
+ or VAR-- == CONST construct a proper mask if VAR is a bitfield.
+ Cope with CONST being out of range for the bitfield.
-Sat Jul 1 06:55:09 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Jun 2 22:28:31 1998 Bernd Schmidt <crux@ohara.Informatik.RWTH-Aachen.DE>
- * fold-const.c (decode_field_reference): New parm PAND_MASK.
- (unextend): New parm MASK.
- (fold_truthop): Pass new parms to decode_field_reference and unextend.
+ * expr.c (emit_move_insn_1): When moving complex values in several
+ steps, emit a CLOBBER to show the destination dies.
- * va-alpha.h (__va_tsize): Use __extension__ to avoid warning
- on use of `long long'.
+Tue Jun 2 22:17:26 1998 Jeffrey A Law (law@cygnus.com)
- * expr.h (NO_DEFER_POP): Do any pending stack adjusts.
+ * Makefile.in (site.exp): Use the object testsuite directory as
+ the temporary directory.
- * recog.c (register_operand): Disallow subreg of reg not allowed to
- change size.
+ * expr.c (expand_expr, case ADDR_EXPR): Handle taking the
+ address of an ADDRESSOF rtx.
-Thu Jun 29 05:51:57 1995 Jeff Law (law@snake.cs.utah.edu)
+1998-06-02 Mike Stump <mrs@wrs.com>
- * pa.md (reload addsi3): New pattern to avoid reload lossage
- with register eliminations.
+ * expr.c (expand_builtin_setjmp): Handle BUILTIN_SETJMP_FRAME_VALUE.
+ * i960.h (SETUP_FRAME_ADDRESSES, BUILTIN_SETJMP_FRAME_VALUE): Define.
+ * i960.md (ret, flush_register_windows): Define.
+ (nonlocal_goto): Likewise. Nested function nonlocal gotos don't
+ work yet.
+ * tm.texi (BUILTIN_SETJMP_FRAME_VALUE): Document new macro.
- * pa.c (output_cbranch): When checking for a jump to the given
- insn's delay slot, handle the case where JUMP_LABEL for the
- given insn does not point to the first label in a series of
- labels.
- (output_bb, output_dbra, output_movb): Likewise.
+Tue Jun 2 14:02:38 1998 Richard Henderson <rth@cygnus.com>
-Wed Jun 28 18:04:56 1995 Jeff Law (law@snake.cs.utah.edu)
+ * alpha.md (divsi3, udivsi3, modsi3, umodsi3): Enable, and work
+ around an OSF/1 library bug wrt sign-extension of inputs.
- * pa.h (PIC_OFFEST_TABLE_REGNUM_SAVED): Define to %r4.
- (CONDITIONAL_REGISTER_USAGE): Make it fixed when compiling
- PIC code.
- (INIT_EXPANDERS): Delete.
- * pa.c (hppa_save_pic_table_rtx): Delete variable.
- (hppa_expand_prologue): For PIC generation, copy the PIC
- register into a fixed callee register at the end of the
- prologue of non-leaf functions.
- * pa.md (call expanders): Reload the PIC register from the
- fixed callee saved register. Don't try to save the PIC
- register before the call.
+Tue Jun 2 13:02:44 1998 Richard Henderson <rth@cygnus.com>
-Wed Jun 28 18:01:14 1995 Stan Cox (coxs@dg-rtp.dg.com)
+ * vax/netbsd.h (DWARF2_UNWIND_INFO): Must be undef, not defined 0.
- * m88k/dguxbcs.h (ASM_SPEC): Removed -h flag.
- * m88k/dgux.h (ASM_SPEC): Likewise.
+Mon Jun 1 03:44:03 1998 Catherine Moore <clm@cygnus.com>
-Wed Jun 28 17:01:58 1995 David Edelsohn <edelsohn@mhpcc.edu>
+ * config/sh/sh.h (MAX_OFILE_ALIGNMENT): Define.
- * rs6000.c (processor_target_table): Remove CPU name synonyms.
- * rs6000.h (CPP_SPEC): Likewise.
- * rs6000/sysv4.h (CPP_SPEC): Likewise.
- (ASM_SPEC): Likewise.
- * rs6000/sysv4le.h (CPP_SPEC): Likewise.
- * rs6000/eabile.h (CPP_SPEC): Likewise.
- * rs6000/powerpc.h (CPP_SPEC): Likewise.
- (ASM_SPEC): Set assembler target according to compiler target.
- * rs6000/aix3newas.h (CPP_SPEC): Likewise.
- (ASM_SPEC): Likewise.
- * rs6000/aix41.h (CPP_SPEC): Likewise.
- (ASM_SPEC): Likewise.
+ * varasm.c (assemble_variable): Augment alignment warning.
-Wed Jun 28 16:25:53 1995 Gran Uddeborg (uddeborg@carmen.se)
+Mon Jun 1 12:14:28 1998 Michael Meissner <meissner@cygnus.com>
- * i386/x-isc3 (INSTALL_HEADERS_DIR): Delete; done by configure.
+ * config/fp-bit.c (_fp{add,div}_parts): Return correct IEEE result
+ in the presence of IEEE negative 0's.
-Wed Jun 28 16:10:47 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+Sun May 31 16:11:41 1998 John Wehle (john@feith.com)
- * xm-rs6000.h (alloca): Extern decl added for non-GNU compiler.
+ * reload.c (find_reloads): Record the existing mode if
+ operand_mode == VOIDmode before replacing a register with
+ a constant.
+ * i386.md (tstsi, tsthi, tstqi, tstsf, tstdf, tstxf): Set
+ i386_compare_op1 to const0_rtx for the benefit of the
+ conditional move patterns.
+ (movsicc, movhicc, movsfcc, movdfcc, movxfcc, movdicc): Rewrite
+ based on suggestions from Jim Wilson.
-Wed Jun 28 11:31:30 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Sun May 31 00:44:02 PDT 1998 Jeff Law (law@cygnus.com)
- * cpplib.c (progname): Remove definition from here.
+ * version.c: Bump for snapshot.
- * final.c (final_scan_insn): Fix error in last change.
+Sun May 31 00:34:17 1998 Bruce Korb <korbb@datadesign.com>
- * rtlanal.c (reg_set_p_1): Now static; add extra parm.
+ * Makefile.in (fixinc.sh): Update rules again.
- * stmt.c: Delete redundant forward decls.
- (expand_anon_union_decl): Correctly call expand_decl.
+Sun May 31 00:27:47 1998 Jeffrey A Law (law@cygnus.com)
- * toplev.c (strip_off_ending): Strip off any ending; don't
- pretend we know what valid endings are.
+ * extend.texi: Bring back reference to trampoline paper.
- * svr4.h (ASM_OUTPUT_SECTION_NAME): Don't crash if DECL is null.
+Sun May 31 00:22:34 1998 Ulrich Drepper <drepper@cygnus.com>
- * rs6000.md ({load,store}_multiple): Don't use indirect_operand
- in define_insn; use explicit MEM of register_operand instead.
+ * Makefile.in (USER_H): Add stdbool.h.
+ * ginclude/stdbool.h: New file.
-Tue Jun 27 11:42:56 1995 Stephen L Moshier <moshier@world.std.com>
+Fri May 29 01:48:25 1998 Jeffrey A Law (law@cygnus.com)
- * i386/i386.c (print_operand, case `J'): Use jns for GE and js for
- LT.
+ * jump.c (thread_jumps): Do not look at the NOTE_LINE_NUMBER
+ of a non-note insn.
-Tue Jun 27 07:58:55 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * gcse.c (pre_delete): Fix code to determine the mode of
+ the reaching pseudo register.
- * expr.c (expand_expr, TARGET_EXPR): Only use original_target
- if !ignore.
+Fri May 29 01:07:28 1998 Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>
-Tue Jun 27 07:27:26 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * Makefile.in (GEN): Add gencheck
+ (STAGESTUFF): Add tree-check.h and gencheck.
- * fold-const.c (fold_truthop): Commute unextend and convert on
- l_const and r_const.
+Fri May 29 00:57:37 1998 Bruce Korb <korbb@datadesign.com>
- * c-common.c (decl_attributes, case A_CONSTRUCTOR, A_DESTRUCTOR):
- Set TREE_USED.
+ * Makefile.in (cstamp-h.in): Remove before trying to recreate.
+ (fixinc.sh): Set some additional environment variables before
+ calling mkfixinc.sh.
- * final.c (final_scan_insn): Don't call alter_cond unless
- condition is on cc0.
+Thu May 28 12:57:05 1998 Jeffrey A Law (law@cygnus.com)
- * stmt.c (expand_asm_operands): Handle input operands that may not
- be in a register.
+ * reload.c (find_reloads): Do not force a reloads of match_operators.
-Mon Jun 26 19:23:05 1995 Richard Earnshaw (rearnsha@armltd.co.uk)
+Thu May 28 10:22:22 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
- * arm/lib1funcs.asm (L_dvmd_tls): Renamed from L_divmodsi_tools.
- * arm/t-semi (LIB1ASMFUNCS): Rename _dvmd_tls from _divmodsi_tools.
+ * except.h (remove_handler): Add new prototype.
+ * except.c (remove_handler): New function to remove handlers
+ from an exception region.
+ * flow.c (find_basic_blocks_1): Remove handlers from regions when
+ handler label is deleted; remove exception regions with no handlers.
-Mon Jun 26 19:18:06 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Thu May 28 09:36:39 1998 Michael Meissner <meissner@cygnus.com>
- * unroll.c (find_splittable_regs): When completely unrolling loop,
- check for non-invariant initial biv values.
+ * except.h (rtx): Define rtx type correctly if needed.
+ * function.h (rtx): Ditto.
+ (tree): Define tree type correctly if needed.
-Mon Jun 26 19:13:54 1995 Gran Uddeborg <uddeborg@carmen.se>
+ * c-pragma.c (toplevel): Include rtl.h.
- * configure (i[345]86-*-isc*): Fix misspelled "rfile" to "ifile".
+ * stor-layout.c (toplevel): Move include of rtl.h before
+ except.h.
-Mon Jun 26 18:58:22 1995 Mike Stump <mrs@cygnus.com>
+ * Makefile.in (c-pragma.o): Add except.h, rtl.h dependencies.
+ (tree.o): Add except.h dependency.
- * expr.c (expand_expr, case COND_EXPR): Protect the condition from
- being evaluated more than once.
- (do_jump, case TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR): Likewise.
+Wed May 27 22:02:40 1998 Jeffrey A Law (law@cygnus.com)
-Mon Jun 26 18:52:36 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ * reload1.c: Revert accidental checkin.
- * fixincludes (string.h): Fix return value for mem{ccpy,chr,cpy,set}
- and str{len,spn,cspn} on sysV68.
+ * configure.lang: Fix thinko when adding a definition for
+ target_alias to the Makefile.
-Mon Jun 26 06:54:50 1995 Michael Meissner (meissner@cygnus.com)
+Wed May 27 02:50:00 1998 Catherine Moore (clm@cygnus.com)
- * i386/osfrose.h (LONG_DOUBLE_TYPE_SIZE): Go back to making long
- double == double.
+ * config/sparc/lb1spc.asm (.rem and .urem): Replace
+ routines.
-Thu Jun 22 19:14:41 1995 Pat Rankin (rankin@eql.caltech.edu)
+Wed May 27 02:48:31 1998 Richard Earnshaw (rearnsha@arm.com)
- * make-cc1.com (if DO_LINK): Skip c-parse.* processing when
- only relinking.
- (gas_message): Update to reflect current version, and give
- a different message if/when no version of gas is found.xo
+ * arm.c (arm_gen_constant): Rework to eliminate uninitialized
+ variable warnings. Don't generate scratch registers if only
+ counting insns.
+ (find_barrier): Eliminate unused variable SRC.
-Thu Jun 22 18:52:37 1995 Richard Earnshaw (rearnsha@armltd.co.uk)
+1998-05-27 Manfred Hollstein <manfred@s-direktnet.de>
- * arm/lib1funcs.asm (___modsi3): Correctly set SIGN register for
- modulo involving negative numbers.
+ * toplev.h (rtx_def): Provide global declaration to avoid
+ `limited scope' warnings.
-Thu Jun 22 18:32:27 1995 Uwe Seimet (seimet@chemie.uni-kl.de)
+Tue May 26 23:47:52 1998 Mumit Khan <khan@xraylith.wisc.edu>
- * xm-atari.h (HZ): Now 100 and don't define if already defined.
+ * Makefile.in (gencheck.o): Use HOST_CC.
+ * i386/t-mingw32: New file.
+ * configure.in (i386-*-mingw32*): Use.
-Thu Jun 22 18:26:12 1995 Jeffrey A Law (law@snake.cs.utah.edu)
+Tue May 26 07:31:04 1998 Richard Earnshaw (rearnsha@arm.com)
- * calls.c (expand_call): Correctly handle returning BLKmode
- structures in registers when the size of the structure is not
- a multiple of word_size.
- * stmt.c (expand_return): Likewise.
+ * arm.c (bad_signed_byte_operand): New predicate function.
+ * arm.h (PREDICATE_CODES): Add it to the list.
+ * arm.md (*extendqi[sh]i_insn): Split any addresses that ldrsb
+ can't handle.
+ (define_split): Two new splits for above insns.
- * pa-gux7.h (LIB_SPEC): Undefine before redefining.
- * pa-hpux.h (LIB_SPEC): Likewise.
- * pa-hpux7.h (LIB_SPEC): Likewise.
+ * arm.c: Include toplev.h.
+ (arm_override_options): Add parentheses around use of tune_flags.
+ (arm_split_constant): Remove unused variable.
+ (arm_gen_constant, arm_gen_movstrqi, add_constant): Likewise.
+ (output_func_prologue, arm_expand_prologue): Likewise.
+ (arm_canonicalize_comparison): Make I unsigned; rework constants
+ accordignly. Add missing paratheses around << operation.
+ (arm_rtx_costs): Correctly parenthesise MULT costs. Add a DEFAULT
+ clause.
+ ({load,store}_multiple_sequence): Initialize BASE_REG.
+ (select_dominance_cc_mode): Add DEFAULT clauses.
+ (broken_move): Return zero if the destination is not a register.
+ (arm_reorg): Move unused REGNO declaration into the dead code.
+ * arm.h (CANONICALIZE_COMPARISON): Ensure OP1 is updated.
- * genmultilib: Work around hpux8 /bin/sh case bug.
+Mon May 25 22:49:56 PDT 1998 Jeff Law (law@cygnus.com)
- * pa.h (LIB_SPEC): Define to avoid -lg.
+ * version.c: Bump for snapshot.
-Thu Jun 22 18:19:09 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Mon May 25 11:56:24 PDT 1998 Jeff Law (law@cygnus.com)
- * expr.c (expand_expr, TARGET_EXPR): Use original_target.
+ * version.c: Bump for snapshot.
- * collect2.c (locatelib): Fix parsing of LD_LIBRARY_PATH.
+Mon May 25 14:00:13 1998 Dave Brolley <brolley@cygnus.com>
-Thu Jun 22 18:15:54 1995 Paul Eggert <eggert@twinsun.com>
+ * cpperror.c (v_cpp_message): Remove static prototype.
+ * cpplib.c (v_cpp_message): Move prototype to cpplib.h.
+ * cpplib.h (v_cpp_message): Add protoptype.
+ (stdarg.h,varargs.h): Needed for v_cpp_message prototype.
- * configure: Create an empty Makefile.sed first, to work
- around a Nextstep 3.3 bug.
+Sun May 24 20:36:15 PDT 1998 Jeff Law (law@cygnus.com)
-Thu Jun 22 18:03:44 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * version.c: Bump for snapshot.
- * Makefile.in (STAGESTUFF): Add stamp-crt.
- (crtbegin.o, crtend.o): Now depend on stamp-crt.
- (stamp-crt): New rule, to actually build crt{begin,end}.o.
-
- * collect2.c (main): Unlink export_file before we return.
+Sun May 24 02:08:57 PDT 1998 Jeff Law (law@cygnus.com)
-Thu Jun 22 14:25:56 1995 Michael Meissner (meissner@cygnus.com)
+ * version.c: Bump for snapshot.
- * rs6000.h (STRIP_NAME_ENCODING): Store NAME and strlen(NAME) into
- local variables; cast result of alloca to avoid compiler warnings.
+1998-05-24 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-Tue Jun 20 18:25:29 1995 Douglas Rupp (drupp@cs.washington.edu)
+ * m68k.h: Declare more functions used in macros.
+ (REG_CLASS_CONTENTS): Completely embrace initializer.
+ * m68k.md (adddi3, subdi3): Add abort call to avoid warning
+ about returning no value.
+ * cse.c (find_best_addr): Declare p and found_better only if
+ needed.
+ * dbxout.c (dbxout_continue): Define only if DBX_CONTIN_LENGTH > 0.
+ * dwarfout.c (string_length_attribute): #if 0 away.
+ * function.c (expand_function_end): Define varible blktramp only
+ if needed.
+ * jump.c (find_insert_position): Define only if !HAVE_cc0.
+ * loop.c (combine_givs_p): Define variable tem only if needed.
+ * real.c: Comment out unused functions eabs, eround,
+ e{24,53,64,113}toasc and eiinfin.
- * alpha/config-nt.sed, i386/config-nt.sed: Edit to add
- a missing $(exeext) for CCCP.
-Tue Jun 20 18:18:00 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Sat May 23 23:44:53 1998 Alexandre Oliva <oliva@dcc.unicamp.br>
- * protoize.c (default_include): Use name and two ints to be
- compatible with definition of INCLUDE_DEFAULTS.
+ * Makefile.in (boostrap2-lean, bootstrap3-lean,
+ bootstrap4-lean): New targets.
-Mon Jun 19 19:24:29 1995 Ted Lemon <mellon@toccata.fugue.com>
+Sat May 23 23:35:14 1998 Jeffrey A Law (law@cygnus.com)
- * mips/netbsd.h (ASM_DECLARE_FUNCTION_NAME): Don't emit function label.
+ * warn_summary, test_summary: Moved into the contrib directory.
-Mon Jun 19 18:34:55 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-05-23 Manfred Hollstein <manfred@s-direktnet.de>
- * fixincludes: Don't define wchar_t under C++.
+ * Makefile.in (ENQUIRE_CFLAGS, ENQUIRE_LDFLAGS): Move down to the end
+ of the Makefile.
+ (FLOAT_H_TEST): Likewise.
+ (ENQUIRE): Likewise.
+ (float.h-nat): Likewise.
+ (float.h-cross): Likewise.
+ (enquire): Likewise.
+ (enquire.o): Likewise.
+ (stmp-int-hdrs): Fix comment about enquire; depend upon gfloat.h.
+ (stmp-headers): Move actions to stmp-int-hdrs, retaining only a
+ no-op.
+ (FLOAT_H): Remove old float.h-nat version; move current definition
+ to CROSS_FLOAT_H location.
+ (all.cross): Remove comments about enquire stuff.
-Mon Jun 19 17:12:41 1995 Paul Eggert <eggert@twinsun.com>
+ * Makefile.in (all.cross): Swap $(LIBGCC) and $(STMP_FIXPROTO).
+ (rest.encap): Likewise.
+ (libgcc2.ready): Depend upon $(STMP_FIXPROTO)
- * cccp.c (collect_expansion): Work around enum bug in vax
- ultrix 4.3 pcc.
- * tree.c (simple_cst_equal): Likewise.
+ * toplev.h (tree_node): Provide global declaration to avoid
+ `limited scope' warnings.
-Mon Jun 19 16:53:00 1995 Douglas Rupp (drupp@cs.washington.edu)
+Sat May 23 23:23:35 1998 Robert Lipe <robertl@dgii.com>
- * winnt/spawnv.c: New file.
+ * test_summary: Display section breaks for each entry
+ in a multilibbed target's output.
-Mon Jun 19 16:30:29 1995 Glenn Brown <glenn@mars.myri.com>
+1998-05-23 Richard Henderson <rth@cygnus.com>
- * caller-save.c (save_call_clobbered_regs): If AUTO_INC_DEC, mark
- register indicated by REG_INC notes as live so they will be saved.
+ * expr.c (expand_expr): For {BITFIELD,COMPONENT,ARRAY}_REF, if the
+ offset's mode is not ptr_mode, convert it.
-Mon Jun 19 16:21:12 1995 Jeffrey A Law (law@snake.cs.utah.edu)
+1998-05-22 Jason Merrill <jason@yorick.cygnus.com>
- * pa.h (PRINT_OPERAND_ADDRESS, case LOW_SUM): Fix logic bug
- in last change.
+ * fold-const.c (ssize_binop): New fn.
+ * tree.h: Declare it.
-Mon Jun 19 14:11:49 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Fri May 22 03:42:05 1998 Richard Earnshaw (rearnsha@arm.com)
- * integrate.c (integrate_decl_tree): Only set DECL_ABSTRACT_ORIGIN
- if the decl returned by pushdecl is the one we started with.
+ * genextract.c (print_path): Handle zero-length path as a special
+ case.
- * mips.h (current_function_name): Delete declaration.
- (ASM_DECLARE_FUNCTION_NAME): Don't set current_function_name.
- * gnu.h (ASM_DECLARE_FUNCTION_NAME): Likewise.
- * mips.c (current_function_decl): Delete declaration.
- (function_prologue): New variable fnname. Use it instead of
- current_function_name.
- (function_epilogue): Likewise.
+Fri May 22 01:38:07 1998 Hans-Peter Nilsson <hp@axis.se>
-Mon Jun 19 13:13:15 1995 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+ * cplus-dem.c (MBUF_SIZE): Bumped from 512 to 32767.
- * alpha.h (ASM_OUTPUT_ASCII): Always reset line count when
- starting new line.
+Fri May 22 00:57:00 1998 Bernd Schmidt (crux@pool.informatik.rwth-aachen.de>
- * scan-decls.c (scan_decls): Fix typo when resetting PREV_ID_START.
+ * final.c (JUMP_TABLES_IN_TEXT_SECTION): Provide a default value.
+ (shorten_branches, final_scan_insn): Test value of
+ JUMP_TABLES_IN_TEXT_SECTION instead of just testing whether it
+ is defined.
+ * tm.texi (JUMP_TABLES_IN_TEXT_SECTION): Corresponding changes.
+ * arm/coff.h: Define JUMP_TABLES_IN_TEXT_SECTION to 1.
+ * arm/tcoff.h: Likewise.
+ * i386/386bsd.h: Likewise.
+ * i386/freebsd-elf.h: Likewise.
+ * i386/freebsd.h: Likewise.
+ * i386/netbsd.h: Likewise.
+ * i386/ptx4-i.h: Likewise.
+ * i386/sysv4.h: Likewise.
+ * pa/pa.h: Likewise.
+ * rs6000/linux.h: Likewise.
+ * rs6000/rs6000.h: Likewise.
+ * sh/sh.h: Likewise.
+ * sparc/sp64-elf.h: Likewise.
+ * v850/v850.h: Likewise.
+ * rs6000/sysv4.h: Define JUMP_TABLES_IN_TEXT_SECTION to 0.
+ * i386/linux.h: Define JUMP_TABLES_IN_TEXT_SECTION to (flag_pic).
- * i386/config-nt.sed, alpha/config-nt.sed: Change version to 2.7.1.
+Thu May 21 19:50:13 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
-Mon Jun 19 13:06:14 1995 DJ Delorie (dj@delorie.com)
+ * regmove.c (gen_add3_insn): New function.
+ (fixup_match_2): Use it instead of calling gen_addsi3.
- * msdos/top.sed: Support new build variables.
- * msdos/configur.bat: Make options.h and specs.h.
- Change realclean to maintainer-clean.
+Thu May 21 23:09:50 1998 Jeffrey A Law (law@cygnus.com)
-Fri Jun 16 06:54:03 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * Makefile.in (gencheck): Depend on HOST_LIBDEPS.
- * Version 2.7.0 Released.
+ * alias.c (rtx_equal_for_memref_p): Handle SCRATCH as a memory
+ address.
- * obstack.c: Always enable this code for now.
+Thu May 21 20:18:13 1998 Martin von Loewis <loewis@informatik.hu-berlin.de>
- * alpha.c (alpha_builtin_saveregs): Use ptr_mode and conversions
- when need so works for both OSF and NT.
- * va-alpha.h (__va_tsize): Round to long long not long.
+ * Makefile.in (TREE_H): Add tree-check.h.
+ (tree-check.h, gencheck): New targets.
+ * gencheck.c: New file.
+ * tree.c (tree_check, tree_class_check): New functions.
+ * tree.h (TREE_CHECK, TREE_CLASS_CHECK): Define.
+ (TYPE_CHECK, DECL_CHECK): Define.
+ Modify all access macros to use generated checking macros.
-Thu Jun 15 17:54:52 1995 Bdale Garbee <bdale@gag.com>
+Wed May 20 23:44:28 EDT 1998 John Wehle (john@feith.com)
- * configure (a29k-*-coff): Synonym for a29k-*-udi.
+ * acconfig.h (HAVE_GAS_MAX_SKIP_P2ALIGN): New tag.
+ * configure.in: Check for it.
+ * i386/gas.h (ASM_OUTPUT_MAX_SKIP_ALIGN): Use it.
+ * final.c (uid_align, uid_shuid, label_align): Make static.
+ (label_align): Change type to struct label_alignment pointer.
+ (LABEL_TO_ALIGNMENT, shorten_branches): Update due to type change.
+ (LABEL_TO_MAX_SKIP): Define.
+ (LABEL_ALIGN_MAX_SKIP, LOOP_ALIGN_MAX_SKIP,
+ LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP): Provide defaults.
+ (shorten_branches): Record the maximum bytes to skip when
+ aligning a label.
+ (final_scan_insn): Use the maximum bytes to skip when aligning a label
+ if ASM_OUTPUT_MAX_SKIP_ALIGN is available.
+ * i386.h (LOOP_ALIGN_MAX_SKIP,
+ LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP): Define.
+ * i386.c (override_options): i386_align_jumps and i386_align_loops
+ default to 4 if ASM_OUTPUT_MAX_SKIP_ALIGN is available.
+ * invoke.texi: Document new i386 align-loops and align-jumps behavior.
-Thu Jun 15 17:51:21 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+1998-05-21 Mark Mitchell <mmitchell@usa.net>
- * function.c (assign_parms): Do all conversions in CONVERSION_INSNS.
+ * cplus-dem.c (do_type): Handle volatile qualification.
-Thu Jun 15 17:36:49 1995 Michael Meissner <meissner@cygnus.com>
+Thu May 21 12:23:17 1998 Per Bothner <bothner@cygnus.com>
- * reg-stack.c (record_reg_life): Call record_reg_life_pat with 0
- for douse argument so that USE's created to mark variables within
- blocks don't get marked as set.
+ * function.c (init_function_start): Don't call emit_line_note if
+ lineno is 0. (Can happen when compiling Java .class files.)
-Thu Jun 15 06:28:15 1995 Dennis Glatting (dennisg@CyberSAFE.COM)
+Thu May 21 19:50:13 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * configure: Change one sed command to work around m68k-next bug.
+ * reload1.c (reload_reg_free_for_value_p): Fix RELOAD_FOR_INPUT
+ end of lifetime and RELOAD_FOR_OUTPUT start of lifetime.
-Wed Jun 14 22:14:39 1995 Jason Merrill <jason@deneb.cygnus.com>
+Thu May 21 19:32:27 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * collect2.c (main): Don't turn off auto_export because of -g.
- (main): Ignore the argument to -o.
+ * combine.c (nonzero_bits): For paradoxical subregs, take
+ LOAD_EXTENDED_OP into account.
- * alpha.h (LINK_SPEC): Don't pass -init __main anymore.
- * alpha/osf12.h (LINK_SPEC): Ditto.
- * mips/iris5.h (LINK_SPEC): Ditto.
+Thu May 21 11:51:15 1998 Dave Brolley <brolley@cygnus.com>
- * collect2.c (main): Place o_file after an initial .o (like crt0.o).
- If we have LD_INIT_SWITCH, use init and fini functions for
- executables, too. Specify the unique function names.
- (write_c_file_stat): Fix the case of destructors but no constructors.
- Don't include the generic-named functions for executables.
- (write_c_file): If we have LD_INIT_SWITCH, always use
- write_c_file_stat.
+ * configure.in (extra_c_objs): add prefix.o.
+ (extra_cxx_objs): extra objects for C++ with cpplib.
+ * configure: Regenerate.
- * collect2.c (main): Also add _GLOBAL__D? to export list.
+ * c-tree.h: (get_directive_line): Different prototype for cpplib.
+ (GET_DIRECTIVE_LINE): Macro wrapper for get_directive_line.
- * ginclude/iso646.h: Do nothing if compiled as C++.
+ * c-lex.h: (get_directive_line): Not needed here for cpplib.
-Wed Jun 14 17:39:10 1995 Roland McGrath (roland@gnu.ai.mit.edu)
+ * c-lex.c: (yy_cur,yy_lim,yy_get_token): Move to c-common.c.
+ (GET_DIRECTIVE_LINE): Move to c-common.c and rename to get_directive_line.
- * c-common.c (format_char_info, case 'm'): Set type to void.
- (check_format_info): If type is void, ignore operand.
+ * c-common.c (parse_in,parse_options,cpp_token): Declare for cpplib.
+ (yy_cur,yy_lim,yy_get_token,get_directive,line): Moved here from c-lex.c
-Wed Jun 14 17:04:10 1995 Paul F. Kunz (Paul_Kunz@SLAC.Stanford.EDU)
+Thu May 21 09:04:42 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * expr.c (expand_builtin_apply_args): Put back original
- register save and restore order.
+ * gengenrtl.c (type_from_format, accessor_from_format): Change
+ type of parameter `c' from `char' to `int'.
-Wed Jun 14 16:56:22 1995 Michael Meissner <meissner@cygnus.com>
+Wed May 20 22:28:34 1998 Jeffrey A Law (law@cygnus.com)
- * rs6000/eabi.h (INVOKE__main): Define, so __eabi is called after
- main's arguments are saved.
+ * warn_summary, test_summary: New scripts from
+ Kaveh Ghazi and Alexandre Oliva respectively.
- * rs6000.c (output_prolog): Don't call __eabi here, let
- compiler call it after the arguments to main are saved.
- (output_{prolog,epilog}): Don't use functions under V.4 to save
- and restore floating point registers.
+ * gcse.c (current_function_calls_longjmp): Declare.
-Wed Jun 14 16:52:12 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+1998-05-20 Jason Merrill <jason@yorick.cygnus.com>
- * m68k/mot3300.h (PCC_BITFIELD_TYPE_MATTERS): Defined.
+ * dwarf2out.c (base_type_die): Use int_size_in_bytes.
-Wed Jun 14 16:48:53 1995 Jerry Frain (jerry@tivoli.com)
+Wed May 20 01:11:02 1998 Doug Evans (devans@cygnus.com)
+ Jeff Law (law@cygnus.com)
- * Makefile.in (stage[1-4]): Correctly link `as', `ld', and `collect2'.
+ * Global CSE and constant/copy propagation.
+ * Makefile.in (OBJS): Add gcse.o
+ (STAGESTUFF): Add *.gcse.
+ (gcse.o): Add dependencies.
+ (mostlyclean): Remove *.gcse and */*.gcse.
+ * gcse.c: New file.
+ * loop.c (loop_optimize): Move call to init_alias_analysis.
+ * recog.c (validate_replace_src): New function.
+ * toplev.c (gcse_dump): New global variable.
+ (flag_gcse, gcse_time): Likewise.
+ (compile_file): Initialize gcse_time and clean out the gcse dump
+ file if necessary.
+ (rest_of_compilation): Call gcse_main as requested. Dump RTL
+ after gcse if requested.
+ (main): Enable gcse for -O2 and above. Handle -dG. Enable gcse
+ dumps for -da.
+ * gcc.texi: Add gcse related internal documentation.
+ * invoke.texi: Note new command line options for gcse.
+ * tm.texi: Document AVOID_CCMODE_COPIES.
+ * mips.h (AVOID_CCMODE_COPIES): Define.
-Wed Jun 14 05:52:04 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue May 19 22:31:20 1998 Jeffrey A Law (law@cygnus.com)
- * objc-act.c (hack_method_prototype): Set DECL_CONTEXT of parms.
+ * Makefile.in (deduced.h): Only run scan-types if $(SYSTEM_HEADER_DIR)
+ exists.
+ (stmp-fixproto): Simlarly for running fixproto.
+ * cross-make (SYSTEM_HEADER_DIR): Now $(tooldir)/sys-include.
- * expmed.c (emit_store_flag): Always set LAST.
+Tue May 19 19:08:52 1998 Jim Wilson <wilson@cygnus.com>
- * c-decl.c (start_function): New parameter for attributes.
- * c-tree.h (start_function): Likewise.
- * c-lang.c (finish_file): Pass extra parm to start_function.
- * objc-act.c (build_module_descriptor, really_start_method): Likewise.
- * c-parse.in (fndef, nested_function, notype_nested_function):
- Likewise.
+ * config/mips/mips.c (double_memory_operand): Accept any MEM during
+ reload when TARGET_64BIT.
- * function.c (assign_parms): Use convert_to_mode instead of
- gen_lowpart when converting incoming parm.
+Tue May 19 18:21:25 1998 Jim Wilson <wilson@cygnus.com>
-Tue Jun 13 19:10:32 1995 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+ Finish incomplete change started by Kenner.
+ * configure.in (*-*-linux-gnu*): Delete NO_STAB_H from xm_defines.
+ (powerpcle-*-cygwin32): Delete xm_defines.
+ * final.c, mips-tfile.c, xcoffout.c, config/mips/mips.c: Use
+ HAVE_STAB_H instead of NO_STAB_H.
+ * config/xm-linux.h (NO_STAB_H): Delete.
+ (HAVE_STAB_H): Undefine.
+ * config/i386/xm-go32.h (NO_STAB_H): Delete.
- * rs6000.md (decrement_and_branch): Finish last fix; update matching
- constraint.
+1998-05-19 Jim Wilson <wilson@cygnus.com>
-Tue Jun 13 18:32:51 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+ * dwarfout.c (dwarfout_file_scope_decl, case TYPE_DECL): Ignore
+ LANG_TYPE trees with DECL_SOURCE_LINE of 0.
- * fold-const.c (fold): When converting a COND_EXPR to an ABS_EXPR,
- get the types right for ABS_EXPR to work.
+Tue May 19 15:07:54 1998 Todd Vierling <tv@netbsd.org>
-Mon Jun 12 17:09:55 1995 Michael Tiemann (tiemann@axon.cygnus.com)
+ * arm/netbsd.h: Ensure DWARF2_UNWIND_INFO is undefined.
- * reorg.c (fill_simple_delay_slots): Set MAYBE_NEVER according to
- code of TRIAL_DELAY, not TRIAL.
+Tue May 19 17:19:16 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
-Mon Jun 12 15:02:37 1995 Doug Evans <dje@cygnus.com>
+ * reload1.c (reload_reg_free_for_value_p): New function.
+ (allocate_reload_reg, choose_reload_regs): Use it.
- * configure: Restore code to make ld symlink if ! use_collect2.
+Tue May 19 11:51:00 EDT 1998 Andrew MacLeod (amacleod@cygnus.com)
- * gcc.c (link_command_spec): Undo patch of May 11.
- -nostdlib implies -nostartfiles again.
- * dsp16xx.h (CROSS_LINK_SPEC): Likewise.
- * i386/freebsd.h (LINK_SPEC): Undo patch of May 24.
- Don't pass "-e start" if nostdlib.
- * i386/sun.h (LINK_SPEC): Likewise.
- * m68k/sun2o4.h (LINK_SPEC): Likewise.
- * m68k/sun3.h (LINK_SPEC): Likewise.
- * m68k/vxm68k.h (LINK_SPEC): Likewise.
- * mips/netbsd.h (LINK_SPEC): Likewise.
- * config/netbsd.h (LINK_SPEC): Likewise.
- * rs6000/mach.h (LINK_SPEC): Likewise.
- * sparc.h (LINK_SPEC): Likewise.
- * sparc/vxsparc.h (LINK_SPEC): Likewise.
+ * except.c (expand_start_catch): Correct logic for when to
+ generate a new handler label, and when to use the old one.
- * gcc.c (link_command_spec): New argument -nodefaultlibs.
+Tue May 19 11:08:52 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
-Sun Jun 11 20:47:53 1995 Stephen L Moshier (moshier@world.std.com)
+ * Makefile.in (print-rtl.o): Depend on bitmap.h.
+ (dbxout.o): Depend on toplev.h.
+ ($(SCHED_PREFIX)sched.o): Likewise.
+ ($(out_object_file)): Likewise for system.h and toplev.h.
+ (cppmain.o): Depend on gansidecl.h.
+ (cpplib.o): Likewise.
+ (cpperror.o): Likewise.
+ (cppexp.o): Likewise.
+ (cpphash.o): Likewise.
+ (cppalloc.o): Likewise.
+ (fix-header.o): Depend on cpplib.h and cpphash.h.
+ (scan-decls.o): Depend on gansidecl.h.
+
+ * basic-block.h (free_regset_vector): Add prototype.
+
+ * cccp.c (check_precompiled): Mark parameter `fname' with
+ ATTRIBUTE_UNUSED.
+ (do_assert): Likewise for `op' and `keyword'.
+ (do_unassert): Likewise.
+ (do_line): Likewise for `keyword'.
+ (do_error): Likewise for `op' and `keyword'.
+ (do_warning): Likewise.
+ (do_ident): Likewise for `keyword'.
+ (do_pragma): Likewise for `limit', `op' and `keyword'.
+ (do_sccs): Likewise.
+ (do_if): Likewise for `keyword'.
+ (do_elif): Likewise.
+ (do_else): Likewise.
+ (do_endif): Likewise.
- * Makefile.in (fix-header.o): Depends on xsys-protos.h.
+ * collect2.c (getenv): Remove redundant prototype.
+ (collect_exit, collect_execute, dump_file): Likewise.
+ (dump_list): Wrap prototype and definition in COLLECT_EXPORT_LIST.
+ (dump_prefix_list): Hide prototype and definition.
+
+ * sparc.c: Include toplev.h.
+ (intreg_operand): Mark parameter `mode' with ATTRIBUTE_UNUSED.
+ (symbolic_memory_operand): Likewise.
+ (sp64_medium_pic_operand): Likewise.
+ (data_segment_operand): Likewise.
+ (text_segment_operand): Likewise.
+ (splittable_symbolic_memory_operand): Likewise.
+ (splittable_immediate_memory_operand): Likewise.
+ (eq_or_neq): Likewise.
+ (normal_comp_operator): Likewise.
+ (noov_compare_op): Likewise.
+ (v9_regcmp_op): Likewise.
+ (v8plus_regcmp_op): Likewise.
+ (extend_op): Likewise.
+ (cc_arithop): Likewise.
+ (cc_arithopn): Likewise.
+ (small_int): Likewise.
+ (uns_small_int): Likewise.
+ (clobbered_register): Likewise.
+ (legitimize_pic_address): Likewise.
+ (delay_operand): Likewise.
+ (sparc_builtin_saveregs): Remove unused variable `stdarg'.
+
+ * sparc.h (order_regs_for_local_alloc, eligible_for_return_delay,
+ sparc_issue_rate, v8plus_regcmp_p): Add prototypes.
+
+ * sparc.md (cmpdi_v8plus): Add abort for default case in switch.
+
+ * cppalloc.c: Include gansidecl.h.
+
+ * cpperror.c: Include stdarg.h/varargs.h and gansidecl.h.
+ (cpp_file_line_for_message): Mark parameter `pfile' with
+ ATTRIBUTE_UNUSED.
+ (v_cpp_message): New function.
+ (cpp_message): Use it. Also convert to variable arguments.
+ (cpp_fatal): Likewise.
+ (cpp_pfatal_with_name): Constify parameter `name'.
+
+ * cppexp.c: Move gansidecl.h before cpplib.h.
+ * cpphash.c: Likewise.
+ * cpphash.h (hashf, delete_macro): Add prototypes.
+
+ * cpplib.c: Include stdarg.h/varargs.h and move gansidecl.h before
+ cpplib.h. Don't include errno.h.
+ (update_path): Add arguments to prototype.
+ (cpp_fatal, cpp_file_line_for_message, cpp_message, delete_macro,
+ cpp_print_containing_files): Remove redundant prototypes.
+ (cpp_hash_cleanup, add_import, append_include_chain,
+ make_assertion, path_include, initialize_builtins,
+ initialize_char_syntax, finclude, validate_else, comp_def_part,
+ lookup_import, redundant_include_p, is_system_include,
+ read_name_map, read_filename_string, open_include_file,
+ check_macro_name, compare_defs, compare_token_lists,
+ eval_if_expression, change_newlines): Add prototype arguments.
+ (hashf): Remove redundant prototype.
+ (read_token_list, free_token_list, safe_read, xcalloc, savestring,
+ conditional_skip, skip_if_group): Add prototype arguments.
+ (fdopen): Remove redundant prototype.
+ (do_define, do_line, do_include, do_undef, do_error, do_pragma,
+ do_ident, do_if, do_xifdef, do_else, do_elif, do_endif, do_sccs,
+ do_once, do_assert, do_unassert, do_warning): Add prototype arguments.
+ (struct directive): Add prototype arguments to function pointer
+ member `func'.
+ (handle_directive): Add missing arguments to call to `do_line'.
+ (do_include): Mark parameters `unused1' and `unused2' with
+ ATTRIBUTE_UNUSED.
+ (do_line): Likewise for `keyword' and new parameters `unused1' and
+ `unused2'.
+ (do_error): Likewise for `keyword'.
+ (do_warning): Likewise. Also add missing argument `pfile' in call
+ to cpp_pedwarn.
+ (do_once): Mark parameter `keyword', `unused1' and `unused2' with
+ ATTRIBUTE_UNUSED.
+ (do_ident): Likewise for `keyword', `buf' and `limit'.
+ (do_pragma): Likewise. Also add missing arguments in call to do_once.
+ (do_sccs): Mark parameter `keyword', `buf' and `limit' with
+ ATTRIBUTE_UNUSED.
+ (do_if): Likewise for `keyword'.
+ (do_elif): Likewise.
+ (eval_if_expression): Likewise for `buf' and `length'.
+ (do_xifdef): Likewise for `unused1' and `unused2'.
+ (do_else): Likewise for `keyword', `buf' and `limit'.
+ (do_endif): Likewise.
+ (parse_name): Add missing argument `pfile' in call to cpp_pedwarn.
+ (cpp_handle_options): Remove superfluous NULL argument in call to
+ cpp_fatal.
+ (cpp_handle_options): Likewise.
+ (do_assert): Mark parameter `keyword', `buf' and `limit' with
+ ATTRIBUTE_UNUSED.
+ (do_unassert): Likewise.
+ (cpp_print_file_and_line): Add missing argument `pfile' in call to
+ cpp_file_line_for_message.
+ (v_cpp_error): New function.
+ (cpp_error): Use it. Also accept variable arguments.
+ (v_cpp_warning): New function.
+ (cpp_warning): Use it. Also accept variable arguments.
+ (cpp_pedwarn): Accept variable arguments.
+ (v_cpp_error_with_line): New function
+ (cpp_error_with_line): Use it. Accept variable arguments.
+ (v_cpp_warning_with_line): New function.
+ (cpp_warning_with_line): Use it. Accept variable arguments. Hide
+ definition.
+ (cpp_pedwarn_with_line): Accept variable arguments.
+ (cpp_pedwarn_with_file_and_line): Likewise.
+ (cpp_error_from_errno): Constify parameter `name'. Add missing
+ argument `pfile' in call to cpp_file_line_for_message.
+ (cpp_perror_with_name): Constify parameter `name'.
+
+ * cpplib.h: Define PARAMS() in terms of PROTO().
+ (fatal): Remove redundant prototype.
+ (cpp_error, cpp_warning, cpp_pedwarn, cpp_error_with_line,
+ cpp_pedwarn_with_line, cpp_pedwarn_with_file_and_line,
+ cpp_error_from_errno, cpp_perror_with_name, cpp_pfatal_with_name,
+ cpp_fatal, cpp_message, cpp_pfatal_with_name,
+ cpp_file_line_for_message, cpp_print_containing_files): Add
+ arguments to prototypes.
+ (scan_decls, cpp_finish): Add prototypes.
+
+ * cppmain.c: Include gansidecl.h.
+ (main): Remove unused variable `i'.
+
+ * dbxout.c: Include toplev.h.
+
+ * demangle.h (do_tlink, collect_execute, collect_exit,
+ collect_wait, dump_file, file_exists): Add prototype.
+
+ * dwarf2out.c (dwarf_type_encoding_name, decl_start_label): Hide
+ prototype and definition.
+ (gen_unspecified_parameters_die): Don't assign results of call to
+ function new_die() to unused variable `parm_die'.
+ (dwarf2out_line): Mark parameter `filename' with ATTRIBUTE_UNUSED.
+ (dwarf2out_define): Likewise for `lineno' and `buffer'.
+
+ * dwarfout.c (output_unsigned_leb128, output_signed_leb128): Hide
+ prototype and definition.
+ (output_die): Add prototype arguments to function pointer arg.
+ (output_unspecified_parameters_die): Mark parameter `arg' with
+ ATTRIBUTE_UNUSED.
+
+ * except.c (output_exception_table_entry): Remove unused variable
+ `eh_entry'.
-Sun Jun 11 15:07:58 1995 Tim Carver (timc@ibeam.intel.com)
+ * except.h (expand_fixup_region_start, expand_fixup_region_end):
+ Add prototypes.
+
+ * expr.c (do_jump_by_parts_equality_rtx): Remove prototype.
+
+ * expr.h (do_jump_by_parts_equality_rtx): Add prototype.
+
+ * fix-header.c: Include stdarg.h/varargs.h, move gansidecl.h
+ before cpplib.h, include cpphash.h, remove redundant prototype of
+ cpp_fatal, don't define `const', add a prototype for `fatal'.
+ (cpp_file_line_for_message): Add missing arguments `pfile'.
+ (v_cpp_message): New function.
+ (cpp_message): Use it.
+ (v_fatal): New function.
+ (fatal, cpp_fatal): Use it.
+ (cpp_pfatal_with_name): Constify parameter `name'.
+
+ * flow.c (free_regset_vector): Remove redundant prototype.
+
+ * function.c (round_down): Wrap prototype and definition with
+ macro ARGS_GROW_DOWNWARD.
+ (record_insns): Wrap prototype and definition with
+ defined (HAVE_prologue) || defined (HAVE_epilogue).
+
+ * gansidecl.h (ATTRIBUTE_PRINTF_4, ATTRIBUTE_PRINTF_5): New macros.
+
+ * gen-protos.c: Include gansidecl.h.
+ (hashf): Don't make it static, constify parameter `name'.
+
+ * genattrtab.c (check_attr_test): Change XEXP() to XSTR() to match
+ specifier %s in calls to function `fatal'.
+
+ * haifa-sched.c: Include toplev.h.
+ (find_rgns): Remove unused variable `j'.
+
+ * integrate.c (note_modified_parmregs): Mark parameter `x' with
+ ATTRIBUTE_UNUSED.
+ (mark_stores): Likewise.
+
+ * jump.c (mark_modified_reg): Likewise.
+
+ * output.h (insn_current_reference_address): Add prototype.
+ (eh_frame_section): Likewise.
+
+ * print-rtl.c: Include bitmap.h.
+
+ * reload1.c (reload): Wrap variables `note' and `next' in macro
+ PRESERVE_DEATH_INFO_REGNO_P.
+ (forget_old_reloads_1): Mark parameter `ignored' with
+ ATTRIBUTE_UNUSED.
+ (choose_reload_regs): Remove unused variable `in'.
+ (reload_cse_invalidate_mem): Mark parameter `ignore' with
+ ATTRIBUTE_UNUSED.
+ (reload_cse_check_clobber): Likewise.
- * reload1.c (emit_reload_insns): Don't call HARD_REGNO_NREGS
- on psuedo when clearing reg_last_reload_reg.
+ * rtl.h (expand_null_return, reg_classes_intersect_p): Add prototype.
+ (mark_elimination): Fix typo in prototype.
-Sun Jun 11 14:07:05 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ * scan-decls.c: Include gansidecl.h.
- * m68k.md ({add,sub}di{_mem,3}): Patterns merged.
+ * tree.h (using_eh_for_cleanups, supports_one_only): Add prototype.
-Sun Jun 11 13:43:26 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+Mon May 18 22:37:33 1998 Jeffrey A Law (law@cygnus.com)
- * m68k.md (cmpdi matcher): Set cc_status before returning.
+ * function.c (identify_blocks): Fix thinko when setting the
+ block number for NOTE_INSN_BLOCK_END.
- * config/xm-freebsd.h (DONT_DECLARE_SYS_SIGLIST): Define.
+Mon May 18 15:30:42 1998 Nick Clifton <nickc@cygnus.com>
-Sun Jun 11 13:38:49 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * config/v850/lib1funcs.asm: Add .text pseudo op to start of
+ ___udivsi3.
- * fixincludes (math.h): Keep declaration of abs on HPUX.
+ * config/v850/lib1funcs.asm: Fix .size pseudo ops to use three
+ underscores for the prefixes to the names of the maths functions.
-Sun Jun 11 12:31:42 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * dbxout.c (dbxout_parms): Revert to using DECL_ARG_TYPE. Add
+ comment explaining why.
- * stor-layout.c (variable_size): Do nothing if SIZE is constant.
+Mon May 18 13:20:23 1998 Richard Henderson <rth@cygnus.com>
- * stmt.c (expand_asm_operands): See if output operand permits
- register. If not, mark output addressable, call expand_operand
- on it, and give error if not MEM.
+ * tree.h (TYPE_SIZE_UNIT): New.
+ (struct tree_type): Add size_unit member.
+ * stor-layout.c (layout_type): Initialize it.
+ * expr.c (get_inner_reference) [ARRAY_REF]: Use it.
+ * tree.c (size_in_bytes, int_size_in_bytes): Likewise.
- * function.c (assign_parms): Handle promotions of both
- passed and nominal modes separately and insert needed conversions.
- (promoted_input_arg): Return 0 if nominal and passed modes differ.
+Mon May 18 12:07:37 1998 Richard Earnshaw (rearnsha@arm.com)
- * stmt.c (all_cases_count, case INTEGER_TYPE): Fix typo in checking
- for integer bounds.
+ * stor-layout.c (layout_record): Fix off-by-one error when checking
+ length of the TYPE_BINFO vector.
-Sat Jun 10 08:55:25 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Mon May 18 10:59:23 1998 Nick Clifton <nickc@cygnus.com>
- * libgcc2.c (_floatdidf): Correctly set float sizes.
+ * dbxout.c (dbxout_parms): Use TREE_ARG to compute the type of a
+ function parameter passed in memory.
- * c-decl.c (c_decode_option, case "-Wall"): Don't set extra_warnings.
+Mon May 18 09:02:09 1998 Robert Lipe <robertl@dgii.com>
- * Makefile.in (cpplib.o, fix-header.o): Update dependencies.
- (cpperror.o, cppexp.o, cpphash.o): New rules, to show .h dependencies.
+ * dwarfout.h, dwarf2out.h, dbxout.h, sdbout.h: New files.
+ Prototypes for externally used functions in respective C files.
+ * dwarfout.c, dbxout.c, dwarf2out.c, sdbout.c, toplev,c,
+ final.c: Include above files.
+ * Makefile.in (toplev.o): Add dependency for above four headers.
+ (final.o): Likewise.
+ (dwarfout.o, dbxout.o, dwarf2out.o, sdbout.o): Depend on four
+ respective header files.
-Fri Jun 9 18:06:10 1995 Doug Evans <dje@canuck.cygnus.com>
+Mon May 18 01:23:33 1998 Jeffrey A Law (law@cygnus.com)
- * cse.c (cse_basic_block): Fix test for whether block ends with a
- barrier. Return next insn, not 0, if block ends in a barrier.
+ * Makefile.in (TARGET_TOOLPREFIX): No longer define.
+ (AR_FOR_TARGET, RANLIB_FOR_TARGET): Define to use versions in
+ the build tree if they exist.
+ (AR, AR_FLAGS, OLDAR, OLDAR_FLAGS, RANLIB, RANLIB_TEST): Update
+ appropriately.
+ (objdir): Let configure substitute value.
+ (FLOAT_H): Let configure select a pre-built version from the
+ config subdir.
+ * build-make (INSTALL_TARGET, ALL): Disable, no longer needed.
+ * configure.in: Substitute for objdir.
-Fri Jun 9 17:58:29 1995 Paul Eggert <eggert@twinsun.com>
+ * Makefile.in (build_canonical, host_canonical): Let configure
+ substitute values for these variables.
+ * configure.in: Substitute for build_canonical, host_canonical
+ and target_subdir in generated Makefile.
- * fold-const.c (lshift_double): Replace `&' with `%' to fix typo.
- ([lr]shift_double): Truncate shift count only if SHIFT_COUNT_TRUNCATED.
- Remove unnecessary `count >= prec' test.
+ * output.h (find_basic_blocks): Declare.
+ (free_basic_block_vars, set_block_num, life_analysis): Likewise.
- * cexp.y (left_shift): Ignore integer overflow.
+ * Makefile.in (BISON): Use bison from the build tree if it exists.
+ (FLEX): Similarly.
- * cexp.y (skip_evaluation): New variable.
- (&&, ||, ?:): Increment it in unevaluated subexpressions.
- (/, %, integer_overflow): Suppress diagnostics if skip_evaluation != 0.
- (yyerror): Clear skip_evaluation.
+Mon May 18 00:08:19 1998 Nick Clifton <nickc@cygnus.com>
-Fri Jun 9 17:49:05 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+ * gcc.c (SWITCH_CURTAILS_COMPILATION): Definition.
+ (DEFAULT_SWITCH_CURTAILS_COMPILATION): True for options -S and -c.
+ (process_command): If HAVE_EXECUTABLE_SUFFIX is defined then scan
+ command line arguments to see if an executable is not being
+ created, and if so - do not append the suffix.
- * m68k.md (tstdi): Rewrite.
+ * tm.texi (SWITCH_CURTAILS_COMPILATION): Add description of new
+ driver macro.
-Fri Jun 9 17:28:55 1995 Per Bothner <bothner@cygnus.com>
+Sun May 17 23:59:45 1998 John Wehle (john@feith.com)
- * scan-decls.c (scan_decls): Handle declarations with
- multiple comma-separated declarators.
+ * i386.h (ALIGN_DFmode): Delete.
+ (CONSTANT_ALIGNMENT): Define.
+ * varasm.c (force_const_mem): Use it.
-Thu Jun 8 19:16:12 1995 Richard Earnshaw (rearnsha@armltd.co.uk)
+Sun May 17 19:31:05 1998 Richard Henderson <rth@cygnus.com>
- * arm.md (mov[sd]f expands): Don't allow fp constants in pseudos
- when TARGET_SOFT_FLOAT.
+ * alpha.c (alpha_emit_conditional_branch): Clear cmp_code after
+ using it with swap_condition, not before.
-Thu Jun 8 19:11:43 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+Sun May 17 13:44:32 1998 Jim Wilson <wilson@cygnus.com>
- * expmed.c (store_split_bit_field): When adjust arg in
- BYTES_BIT_ENDIAN case, use number of bits in arg for MEM operands
- and BITS_PER_WORD for other operands.
- (extract_fixed_bit_field): Undo last change.
+ * alias.c (mode_alias_check): Delete.
+ (true_dependence, anti_dependence, output_dependence): Revert April 21
+ change.
- * unroll.c (verify_addresses): New function.
- (find_splittable_givs): Use it instead of memory_address_p.
+Sun May 17 08:45:21 1998 Krister Walfridsson <cato@df.lth.se>
-Thu Jun 8 18:58:18 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+ * toplev.c (output_lang_identify): Enable prototype and definition.
- * expmed.c (expand_divmod): Always check result of emit_store_flag.
+Sun May 17 01:12:27 PDT 1998 Jeff Law (law@cygnus.com)
-Thu Jun 8 12:02:34 1995 David D Zuhn (zoo@armadillo.com)
+ * version.c: Bump for snapshot.
- * cpplib.c (cpp_push_buffer): Include filename in error message.
+Sat May 16 23:20:32 1998 Richard Henderson <rth@cygnus.com>
-Thu Jun 8 11:53:45 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * alpha/osf.h (HAVE_STAMP_H): Define.
+ * alpha.c: Use it.
+ * alpha/netbsd.h, alpha/netbsd-elf.h: New files.
+ * configure.in (alpha*-*-netbsd*): New.
+ Based on patches from Paul H. Anderson <pha@pdq.com>.
- * function.c (assign_parms): Don't call promote_mode on arg
- unless PROMOTE_FUNCTION_ARGS defined.
+ * configure.in (alpha*-*-linux-*): Kill xm_defines.
+ (alpha*-*-linux-gnulibc1*) [fixincludes]: Define.
+ * alpha/xm-linux.h: Remove file.
- * rs6000.md (decrement_and_branch): Ensure label is operand 0.
+Sat May 16 18:32:45 1998 Doug Evans <devans@canuck.cygnus.com>
- * rs6000.md (aux_truncdfsf2): New pattern.
- (movsf): Use it instead of invalid SUBREG and truncdfsf2.
+ * dbxout.c (dbxout_parms): If mode of type of parameter living
+ in memory doesn't match mode of DECL_RTL, make big endian correction.
- * varasm.c (assemble_name): Disable warn_id_clash around
- get_identifier call.
+Fri May 15 21:40:06 1998 John Wehle (john@feith.com)
-Wed Jun 7 17:22:25 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ * i386.md (movdi-1, movdi): Rewrite based on SI move patterns.
- * configure (gdb_needs_out_file_path): New variable.
- (m68k-motorola-sysv): Set gdb_needs_out_file_path if not using gas.
- (.gdbinit): If gdb_needs_out_file_path is set, add a 'dir' command
- for $(out_file).
+Fri May 15 18:55:22 1998 Jason Merrill <jason@yorick.cygnus.com>
-Wed Jun 7 17:17:19 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+ * tree.h (BINFO_SIZE, TYPE_BINFO_SIZE): New macros.
+ * stor-layout.c (layout_record): Set it.
- * fold-const.c (fold): When folding `<' type nodes, make true_value
- and false_value have correct types.
+Fri May 15 18:49:30 1998 Mark Mitchell <mmitchell@usa.net>
-Wed Jun 7 05:06:42 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * toplev.c (rest_of_compilation): Don't defer nested functions.
- * collect2.c (COFF scan_prog_file): Use the AIX duplicate entry.
+Fri May 15 17:42:52 1998 Bob Manson <manson@charmed.cygnus.com>
-Tue Jun 6 18:43:09 1995 Jeffrey A Law (law@snake.cs.utah.edu)
+ * config/rs6000/rs6000.c (rs6000_stack_info): Align the stack bottom
+ to an 8-byte boundary if info_ptr->fpmem_p.
- * pa.h (FUNCTION_ARG_CALLEE_COPIES): Define.
+Fri May 15 17:36:11 1998 Bill Moyer <ttk@cygnus.com>
-Tue Jun 6 18:21:18 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * loop.c (basic_induction_var): Added test preventing
+ CCmode parameter passed to convert_modes().
- * expr.c (expand_expr, case PLACEHOLDER_EXPR): Consider two types
- identical if their TYPE_MAIN_VARIANTs are the same.
+Fri May 15 17:26:18 1998 Alexandre Petit-Bianco <apbianco@cygnus.com>
- * c-decl.c (start_decl): Set DECL_COMMON before calling
- decl_attributes.
+ * expr.c (expand_expr, case EXPR_WITH_FILE_LOCATION): Save/restore
+ input_filename and lineno around expand_expr call. Set them to values
+ in WFL before expand_expr call.
- * a29k.c (print_operands): Cast args to bcopy to char *.
+Fri May 15 12:44:57 1998 Benjamin Kosnik <bkoz@rhino.cygnus.com>
- * c-decl.c (duplicate_decls): Don't clear DECL_CONTEXT of
- new decl if it is a function.
+ * stor-layout.c (set_sizetype): Set TYPE_NAME on bitsizetype.
-Tue Jun 6 17:57:44 1995 Eberhard Mattes (mattes@azu.informatik.uni-stuttgart.de)
+Fri May 15 07:20:03 1998 Mark Mitchell <mmitchell@usa.net>
- * gcc.c (do_spec_1, case 'g'): Handle %O as suffix if MKTEMP_EACH_FILE.
+ * fold-const.c (constant_boolean_node): New function.
+ (fold): Use it.
-Tue Jun 6 17:53:05 1995 Michael Meissner <meissner@cygnus.com>
+Fri May 15 11:21:16 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * rs6000.c (expand_block_move): Update source and destination pointers
- inside the loop moving the bytes, not outside.
+ * sh.c (gen_shl_and): Don't sign extend constant for kind two.
+ Abort if trying to split kind 3 or 4 outside of combine.
-Tue Jun 6 14:58:37 1995 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+Fri May 15 01:47:37 1998 Jeffrey A Law (law@cygnus.com)
- * m68k.h (CONDITIONAL_REGISTER_USAGE): Don't mark pic reg as fixed.
- * m68k.c (finalize_pic): Emit USE insn at start and end of function.
+ * mips.c (print_operand, case 'x'): Use HOST_WIDE_INT_PRINT_HEX.
-Tue Jun 6 13:46:57 1995 Jim Wilson <wilson@mole.gnu.ai.mit.edu>
+Fri May 15 01:42:45 1998 Mumit Khan <khan@xraylith.wisc.edu>
- * sh.c (print_operand): Check for annulled branches.
- (output_movedouble): Handle SUBREG addresses.
- (output_branch): Handle annulled branches.
- (sh_expand_prologue): Correct number of saved registers for
- varargs functions.
- * sh.h: Add some comments.
- * sh.md: Add some comments. Cleanup formatting.
- (type attribute): Add pstore and call.
- (return define_delay): Reorganize to make clearer.
- (call/sfunc define_delay): Define.
- (cbranch define_delay): Define to have annul-true delay slot.
- (subsi3): Use arith_reg_operand for operand 2.
- (shift patterns): Use const_int_operand instead of immediate_operand
- for shift counts.
- (push): Add pstore constraint case.
- (movsi_i): Move t/z constraint pair to the front of the list.
- (calli, call_valuei): Add "call" attribute.
-
-Mon Jun 5 19:23:13 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * objc/Make-lang.in (OBJC_O): Add missing exeext.
+ (libobjc.a, runtime-info.h): Likewise.
- * sched.c (attach_deaths): In last change, use find_reg_note instead
- of find_regno_note.
+Fri May 15 01:29:39 1998 John Wehle (john@feith.com)
-Mon Jun 5 19:17:31 1995 Tom Quiggle (quiggle@lovelace.engr.sgi.com)
+ * i386.h (DATA_ALIGNMENT): Define.
- * mips/iris5.h (MACHINE_TYPE): Say "IRIX 5.x", not "5.0".
- (NO_DOLLAR_IN_LABEL): Undefine.
- * mips.h (sdb_begin_function_line): New declaration.
- (PUT_SDB_FUNCTION_END): New definition.
+Fri May 15 05:35:37 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
-Mon Jun 5 18:56:10 1995 Michael Meissner <meissner@cygnus.com>
+ * reload1.c (delete_output_reload): Ignore single USE that
+ was emitted for the pseudo use of this INSN.
+ If the no reference to REG between OUTPUT_RELOAD_INSN and INSN
+ remains, we can always delete OUTPUT_RELOAD_INSN.
- * rs6000.c (expand_block_move): Don't do block moves where we clobber
- fixed numbers of regs, instead move just 1-8 bytes at a time.
+Thu May 14 18:38:50 1998 Jim Wilson <wilson@cygnus.com>
- * Makefile.in (STAGESTUFF): Copy files produced by -da and
- -save-temps to the stage subdirectories.
+ * reload.c (find_reloads): Don't penalize SCRATCH output reload.
-Mon Jun 5 08:18:46 1995 Torbjorn Granlund <tege@bozo.matematik.su.se>
+Thu May 14 15:10:30 1998 Jeffrey A Law (law@cygnus.com)
- * combine.c (reg_dead_at_p): When scanning backwards, stop at BARRIER.
+ * Makefile.in (expr.o): Remove dependency on deleted modemap.def file.
- * m68k.c (print_operand): Handle 'R' for registers.
- * m68k.md (cmpdi): Rewrite to avoid bogus matching constraints.
+Thu May 14 16:30:47 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
- * optabs.c (expand_binop): In last change, don't defererence TARGET
- if it is 0.
+ * eh-common.h: New file for basic EH data structures.
+ * except.h: Various prototypes and structures for NEW_EH_MODEL
+ * function.h (struct function): Add a struct eh_stack for the catch
+ clause stack.
+ * except.c (gen_exception_label): New function to generate an
+ exception label.
+ (push_eh_entry): Use gen_exception_label() and init 'label_used' field.
+ (push_entry): New function to push an existing entry onto a stack.
+ (receive_exception_label): New function to emit the code required
+ at the start of all catch blocks.
+ (struct func_eh_entry): New structure for maintaining handlers
+ associated with EH regions.
+ (new_eh_region_entry): New function to register an EH region.
+ (add_new_handler): New function to register a handler with a region.
+ (get_new_handler): Creates anew handler entry for registering.
+ (find_func_region): New function to convert a NOTE eh region number
+ to an Eh region index.
+ (get_first_handler): New function to get the first handler in a region.
+ (clear_function_eh_region): New function to release memory.
+ (duplicate_handlers): New function to duplicate a list of handlers.
+ (expand_eh_region_end): Create a new region entry node as well.
+ (expand_leftover_cleanups): Call receive_exception_label() and
+ register the cleanup as a handler to the current region.
+ (expand_start_catch): New function to start a catch clause.
+ (expand_end_catch): New function to end a catch clause.
+ (expand_start_all_catch): restructure to not do the equivilent of
+ what expand_start_catch() does now. Push the exception region being
+ handled onto the catch stack.
+ (output_exception_table_entry): Issue an entry for each handler
+ associated with a region.
+ (set_exception_lang_code): New function for setting the language code.
+ (set_exception_version_code): New function to set the version number.
+ (output_exception_table): Output version and language codes.
+ (find_exception_handler_labels): Find handler labels using new scheme.
+ (is_exception_handler_label): New function, returns 1 if label is
+ present as a handler in some exception region.
+ (check_exception_handler_labels): Use the new scheme.
+ (init_eh_for_function): Initialize the catch stack.
+ (save_eh_status): Save the catch stack.
+ (restore_eh_status): Restore the catch stack.
+ (scan_region): Don't remove unreferenced handler label. Flow does it.
+ (get_reg_for_handler): New function to get the eh_context pointer
+ passed by __throw.
+ (expand_builtin_eh_stub): Changes required for NEW_EH_MODEL only.
+ * final.c (final_scan_insn): With NEW_EH_MODEL, add EH table
+ entry when processing END region rather that START region.
+ * flow.c (find_basic_blocks_1): Find all potential handler regions
+ now that we don't automatically know what the labels might be.
+ Let scan_region() remove unreferenced EH BEGIN/END labels.
+ * integrate.c (get_label_from_map): Put inlined labels onto the
+ permanent obstack since we dont know which ones might be exception
+ labels.
+ (save_for_inline_copying): Make new copies of all the handlers.
+ (expand_inline_function): Make new copies of all the handlers.
+ * libgcc2.c: Remove local struct decls, and include eh-common.h.
+ (find_exception_handler): With NEW_EH_MODEL the first matching
+ region we find is the right one. Add eh_info as a new parameter.
+ (__throw): Pass eh_info to find_exception_handler. Set handler
+ and pass use different regs under NEW_EH_MODEL.
+
+Thu May 14 12:58:21 1998 Jim Wilson <wilson@cygnus.com>
+
+ * i960.h (hard_regno_mode_ok): Changed to function from array of
+ unsigned.
+ (HARD_REGNO_MODE_OK): Call function instead of testing bit.
+ * i960.c (hard_regno_mode_ok): Changed to function from array of
+ unsigned.
+
+Thu May 14 08:41:46 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * reload.c (remove_replacements): New function.
+ * reload.h (remove_replacements): Declare.
+ * reload1.c (choose_reload_regs): Disable some reloads that
+ belong to inherited reloads.
+
+Thu May 14 02:17:17 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * loop.c (scan_loop): Don't call move_moveables for optimize_size.
+
+ * reload1.c (merge_assigned_reloads): When merging, reset
+ reload_spill_index for the eliminated reload.
+
+Wed May 13 17:51:13 1998 Jeffrey A Law (law@cygnus.com)
+
+ * haifa-sched.c (schedule_insns): Fix merge goof.
+
+1998-05-13 Jim Wilson <wilson@cygnus.com>
+
+ * varasm.c (make_decl_rtl): Revert April 1 change.
+ * alpha/alpha.h, alpha/win-nt.h, arm/arm.h, i386/unix.h, i960/i960.h,
+ m68k/linux.h, pa/pa.h, sparc/sparc.h, vax/vax.h (ASM_OUTPUT_MI_THUNK):
+ Get function name from the SYMBOL_REF in the DECL_RTL, not from
+ DECL_ASSEMBLER_NAME.
+ * i386/winnt.c (gen_stdcall_suffix): Comment for questionable use of
+ DECL_ASSEMBLER_NAME.
+
+Wed May 13 13:09:19 1998 Jim Wilson <wilson@cygnus.com>
+
+ * i386.c (notice_update_cc, output_float_compare): Disable
+ TARGET_CMOVE support.
+
+Wed May 13 15:28:59 1998 Michael Meissner <meissner@cygnus.com>
+ Jeff Law <law@cygnus.com>
+
+ * rtlanal.c (find_reg_note): Ignore notes that are not on on
+ insns of class 'i'.
+ (find_regno_note): Likewise.
+
+ * Makefile.in (stor-layout.o): Depend on except.h
+ (varasm.o, function.o): Likewise.
+ (expr.o): Depend on except.h, modemap.def and hard-reg-set.h.
+
+ * Makefile.in (HOST_RTL): Add $(HOST_PREFIX)bitmap.o.
+ (rtl.o, emit-rtl.o): Add dependency on bitmap.h.
+ ($(HOST_PREFIX_1)rtl.o): Likewise.
+ ($(HOST_PREFIX_1)bitmap.o): New host object.
+ * emit-rtl.c (toplevel): Include bitmap.h.
+ (gen_rtx): Handle 't' and 'b' nodes.
+ * print-rtl.c (print_rtx): Handle printing NOTE_INSN_LIVE notes.
+ Print block number for block begin/end notes. Print 't' type
+ nodes as a pointer. Know that the 3rd argument of live range
+ start/stop notes is really a range_info rtx. If type is 'b', print
+ out argument as a bitmap.
+ * rtl.c: Include bitmap.c.
+ (copy_rtx): Copy tree nodes as is. Copy bitmaps if type is 'b'.
+ (note_insn_name): Add NOTE_INSN_RANGE_{START,END}, NOTE_INSN_LIVE.
+ * rtl.def (RANGE_LIVE): New node to hold live information while we
+ recalculate the basic blocks.
+ (RANGE_REG, RANGE_INFO): New rtl types for live range splitting.
+ (RANGE_VAR): New node, to hold information saved in symbol node for New
+ communicating live range information to the debug output functions.
+ * rtl.h (rtunion_def): Add rttree and rtbit fields.
+ (XBITMAP, XTREE): New accessor macros.
+ (NOTE_LIVE_INFO): Overload NOTE_SOURCE_FILE for NOTE_INSN_LIVE notes.
+ (NOTE_RANGE_INFO): Similarly for NOTE_INSN_RANGE_{START,END} notes.
+ (NOTE_BLOCK_LIVE_RANGE_BLOCK): Define.
+ (NOTE_INSN_RANGE_START, NOTE_INSN_RANGE_END, NOTE_INSN_LIVE): New notes.
+ (RANGE_LIVE_{BITMAP,ORIG_BLOCK}): New accessor macros.
+ (RANGE_REG_{SYMBOL,BLOCK}_NODE, RANGE_VAR_*): New accessor macros.
+ (RANGE_INFO_*): Likewise.
+ * sched.c (sched_analyze): Keep live range start/stop notes.
+ (unlink_other_notes): Likewise.
+ * haifa-sched.c (sched_analyze): Keep live range start/stop notes.
+ (unlink_other_notes): Likewise.
+ * tree.h (BLOCK_LIVE_RANGE_{START,END,VAR_FLAG}): New accessor macros.
+ (BLOCK_LIVE_RANGE_FLAG): Likewise.
+ (DECL_LIVE_RANGE_RTL): Likewise.
+ (struct tree_block): Add live_range_flag, live_range_var_flag,
+ live_range_start and live_range_end.
+ (struct tree_decl): Add live_range_rtl field.
+ * gengenrtl.c (type_from_format): Handle 'b' and 't'.
+ (accessor_from_format): Likewise.
+
+ * haifa-sched.c (schedule_block): Make verbose output line up.
+ Also add a blank line in printing the individual ready lists.
+
+Wed May 13 15:43:44 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (c-lang.o): Depend on c-tree.h, c-lex.h and toplev.h.
+ (c-lex.o): Depend on output.h.
+ (c-common.o): Likewise.
+ (stmt.o): Likewise.
+ (calls.o): Likewise.
+ (integrate.o): Depend on toplev.h.
+ (regclass.o): Depend on output.h.
+ (final.o): Depend on reload.h.
+
+ * c-common.c: Include output.h.
+ (check_format_info): Remove unused variable `integral_format'.
+
+ * c-decl.c (print_lang_decl): Mark parameters `file', `node' and
+ `indent' with ATTRIBUTE_UNUSED.
+ (print_lang_type): Likewise.
+ (maybe_build_cleanup): Likewise for parameter `decl'.
+ (copy_lang_decl): Likewise for parameter `node'.
+
+ * c-lang.c: Include c-tree.h, c-lex.h and toplev.h.
+ (lang_print_xnode): Mark parameters `file', `node' and `indent'
+ with ATTRIBUTE_UNUSED.
+ (lookup_interface): Likewise for parameter `arg'.
+ (is_class_name): Likewise.
+ (maybe_objc_check_decl): Likewise for parameter `decl'.
+ (maybe_objc_comptypes): Likewise for parameters `lhs', `rhs' and
+ `reflexive'.
+ (maybe_objc_method_name): Likewise for parameter `decl'.
+ (build_objc_string): Likewise for parameters `len' and `str'.
+
+ * c-lex.c: Include output.h.
+
+ * c-lex.h (position_after_white_space): Correct typo in prototype.
+
+ * c-tree.h (finish_file, c_expand_start_cond, c_expand_start_else,
+ c_expand_end_cond, init_iterators): Add prototypes.
+
+ * caller-save.c (set_reg_live): Mark parameters `reg' and `setter'
+ with ATTRIBUTE_UNUSED.
+
+ * calls.c: Include output.h.
+
+ * cccp.c (pipe_closed): Mark parameter `signo' with
+ ATTRIBUTE_UNUSED.
+
+ * combine.c: Move inclusion of expr.h to after insn-config.h.
+
+ * iris6.h (ASM_IDENTIFY_GCC, ASM_IDENTIFY_LANGUAGE): Don't define
+ as empty, rather define as ((void)0).
+
+ * sparc.c (sparc_check_64): Add braces around ambiguous `else'.
+ Add parentheses around assignment used as truth value.
+
+ * cplus-dem.c (squangle_mop_up): Change return type to void.
+ (internal_cplus_demangle): Remove unused parameter `options'.
+ All callers changed.
+ (cplus_demangle_opname): Remove function wide variable `int i' and
+ replace with `size_t i' at each location where it is used.
+ (cplus_demangle_opname): change type of `i' from int to size_t.
+
+ * cppexp.c (right_shift): Mark parameter `pfile' with
+ ATTRIBUTE_UNUSED.
- * pa.md (movsicc): Use MATCH_DUP for operand 4 and 5.
+ * cpphash.c (cpp_lookup): Likewise.
+ (cpp_hash_cleanup): Likewise.
-Mon Jun 5 08:14:56 1995 Jeffrey A Law (law@cs.utah.edu)
+ * cpplib.c (parse_name): Add a prototype and make it static.
+ (null_underflow): Mark parameter `pfile' with ATTRIBUTE_UNUSED.
+ (null_cleanup): Likewise for parameters `pbuf' and `pfile'.
+ (macro_cleanup): Likewise for parameter `pfile'.
+ (file_cleanup): Likewise.
- * pa.c (hppa_encode_label): Allocate stuff on permanent_obstack
- rather than via malloc.
+ * cpplib.h (cpp_reader_init, cpp_options_init, cpp_start_read,
+ cpp_read_check_assertion, skip_rest_of_line): Add prototypes.
- * c-common.c (decl_attributes): Fix typo in size passed to alloca.
+ * crtstuff.c (force_to_data, __CTOR_LIST__, force_to_data,
+ __DTOR_END__, __FRAME_END__): Mark with ATTRIBUTE_UNUSED.
-Mon Jun 5 08:10:55 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * cse.c (cse_check_loop_start): Mark parameter `set' with
+ ATTRIBUTE_UNUSED.
- * alpha.md: Use "some_operand" for patterns valid only during
- reload and meant to handle adding more PLUS operators during
- register elimination.
+ * dbxout.c (flag_minimal_debug, have_used_extensions,
+ source_label_number): Move inside macro wrapper check against
+ defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO).
-Mon Jun 5 07:31:53 1995 Stephen L Moshier (moshier@world.std.com)
+ * dwarf2out.c (gen_entry_point_die): Hide prototype and definition.
- * cse.c (simplify_unary_operation, case FLOAT, UNSIGNED_FLOAT):
- Truncate to requested mode.
+ * except.h (doing_eh): Provide prototype.
-Sat Jun 3 22:08:51 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * expr.c: Move inclusion of expr.h to after insn-config.h.
- * sched.c (attach_deaths): Don't add a REG_DEAD note if a REG_UNUSED
- note is already present.
+ * final.c: Include reload.h.
+ (shorten_branches): Cast the first argument of bzero to char *.
-Sat Jun 3 18:36:57 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * fix-header.c (cpp_print_containing_files): Mark parameter
+ `pfile' with ATTRIBUTE_UNUSED.
+ (cpp_fatal): Likewise.
- * pa.h (hppa_builtin_saveregs): Add declaration.
+ * flow.c (find_basic_blocks_1): Cast the first argument of bzero
+ to char *.
-Sat Jun 3 18:11:26 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * genattrtab.c (make_length_attrs): Change the type of variable
+ `i' from int to size_t.
+ (zero_fn): Mark parameter `exp' with ATTRIBUTE_UNUSED.
+ (one_fn): Likewise.
- * Makefile.in (scan-decls.o): Depends on cpplib.h.
+ * genextract.c (main): When generating insn-extract.c, mark
+ variable `junk' with ATTRIBUTE_UNUSED.
-Fri Jun 2 19:23:47 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * gengenrtl.c (gencode): When generating genrtl.c, cast the first
+ argument of bzero to char*.
- * optabs.c (expand_binop): Don't use non-REG TARGET in 2-word case.
+ * integrate.c: Include toplev.h.
-Thu Jun 1 19:30:30 1995 Tor Egge (tegge@flipper.pvv.unit.no)
+ * libgcc2.c: Wrap `struct exception_table' and
+ `find_exception_handler' in macro DWARF2_UNWIND_INFO.
- * m88k.h (RETURN_POPS_ARGS): New argument.
- * m88k/dolphin.ld: Added start of comment.
+ * objc/Make-lang.in (objc-act.o): Depend on toplev.h.
-Thu Jun 1 19:12:28 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * objc/objc-act.c: Include toplev.h.
+ (lang_print_xnode): Mark parameters `file', `node' and `indent'
+ with ATTRIBUTE_UNUSED.
+ (finish_protocol): Likewise for parameter `protocol'.
- * configure (a29k-*-bsd*): Fix typo in last change.
+ * output.h (declare_weak): Add prototype.
+ (decode_reg_name): Don't wrap with TREE_CODE macro.
+ (assemble_alias): Add prototype.
-Thu Jun 1 18:51:53 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * regclass.c: Include output.h.
- * expmed.c (extract_fixed_bit_field): For REG case, compute total_bits
- from mode instead of assuming BITS_PER_WORD.
+ * reload.h (reloads_conflict): Add prototype.
-Thu Jun 1 18:34:31 1995 Michael Meissner <meissner@cygnus.com>
+ * rtl.h (print_rtl_single, mark_elimiation, reg_class_subset_p,
+ output_func_start_profiler): Add prototypes.
- * rs6000.h (FIXED_R13): Default to 0.
- ({FIXED,CALL_USED}_REGISTERS): Use FIXED_R13 for register 13.
- * sysv4.h (FIXED_R13): Define to be 1.
+ * rtlanal.c (reg_set_p_1): Mark parameters `x' and `pat' with
+ ATTRIBUTE_UNUSED.
-Wed May 31 20:57:26 1995 Torbjorn Granlund <tege@matematik.su.se>
+ * scan-decls.c: Include scan.h.
- * m68k.md ([su]mulsi3_highpart): Pass correct number of arguments to
- const_uint32_operand.
- * m68k.c (const_uint32_operand): Reject negative numbers.
+ * scan.h (recognized_function, recognized_extern): Add prototypes.
- * expmed.c (expand_mult_highpart): Use wide_op1 for all multiplies.
- (expand_divmod): Undo Nov 12 change. Instead, add special case
- for division by MIN_INT in signed TRUNC_DIV_EXPR case.
+ * stmt.c: Include output.h.
-Wed May 31 20:44:21 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ * toplev.c (error_for_asm, warning_for_asm): Remove prototypes.
+ (output_lang_identify): Hide prototype and definition.
+ (float_signal): Mark parameter `signo' with ATTRIBUTE_UNUSED.
+ (pipe_closed): Likewise.
- * m68k.md (one_cmpldi2): New pattern.
- ({a,l}shrdi{3,_const}): Allow 63 as shift count.
+ * toplev.h (count_error, strip_off_ending, error_for_asm,
+ warning_for_asm): Add prototypes.
-Wed May 31 14:56:31 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Wed May 13 12:54:19 1998 Michael Meissner <meissner@cygnus.com>
- * varasm.c (assemble_start_function, assemble_variable):
- Make sure first_global_object_name is in permanent obstack.
+ * toplev.c (rest_of_compilation): "Charge" final for any time
+ doing various cleanup operations after finishing compilation
+ of a function.
- * reload1.c (alter_reg): Clean up setting of RTX_UNCHANGING_P
- when making a MEM.
+ * flow.c (dump_flow_info): Also print number of sets and
+ whether or not the pseudo is a user variable.
- * reorg.c (struct resources): New field unch_memory.
- (CLEAR_RESOURCES, mark_target_live_regs, dbr_schedule): Clear it.
- (mark_{referenced,set}_resources, redundant_insn): Set it.
- (fill_simple_delay_slots): Likewise.
- (resource_conflicts_p): Test it.
+ * flow.c (reg_n_max): New global variable.
+ * regclass.c (allocate_reg_info): Keep reg_n_max up to date.
+ Delete regno_max variable.
+ * regs.h (REG_N_CHECK): Define.
+ (REG_N_REFS, REG_N_SETS, REG_N_DEATHS): Use REG_N_CHECK.
+ (REG_N_CHANGES_SIZE, REG_N_CALLS_CROSSED, REG_LIVE_LENGTH): Likewise.
+ (REGNO_FIRST_UID, REGNO_LAST_UID, REGNO_LAST_NOTE_UID): Likewise.
- * unroll.c (copy_loop_body): Fix typo in call to sets_cc0_p.
+Wed May 13 12:54:19 1998 Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>
- * integrate.c (output_inline_function): Don't call expand_function_end.
+ * acconfig.h (ENABLE_CHECKING): Undefine.
+ * configure.in (--enable-checking): New option.
- * calls.c (prepare_call_address): Only call use_reg on
- static_chain_rtx if it is a REG.
+Wed May 13 08:52:08 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * configure (a29k-*-bsd*): Use t-a29k.
- * t-a29k: New file.
- * a29k/t-a29kbare (LIBGCC1_TEST): New null definition.
- * a29k/t-vx29k (LIBGCC1_TEST): Likewise.
+ * reload1.c (merge_assigned_reloads): Can merge
+ RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_OTHER_ADDRESS even
+ if RELOAD_FOR_INPUT with the same reload_reg_rtx is present.
-Wed May 31 14:17:42 1995 Jeffrey A Law (law@snake.cs.utah.edu)
+Tue May 12 20:05:57 1998 Jim Wilson <wilson@cygnus.com>
- * configure (hppa*-*-bsd*): Do not run fixincludes.
- (hppa*-*-osf*): Likewise.
- (hppa*-*-lites*): Likewise.
+ * collect2.c (main): Ignore do_collecting when COLLECT_EXPORT_LIST.
- * pa.h (PRINT_OPERAND_ADDRESS): Use "RR'" rather than "R'" for
- symbolic addresses.
- * pa.md (symbolic HIGH patterns): Likewise.
- (symbolic LO_SUM pattern): Likewise.
+Wed May 13 03:23:45 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
-Wed May 31 14:11:53 1995 Michael Meissner <meissner@cygnus.com>
+ * reload1.c (gen_reload): Create REG_EQUIV notes.
- * rs6000.md (all movstri recognizers): Eliminate updating the pointers.
- * rs6000.c (expand_block_move): Don't pass argument of # bytes to
- increment pointers by to movstrsi expanders.
+Tue May 12 22:21:07 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * rs6000.c (rs6000_override_options): Fix typo with -mstring handling.
+ * reload1.c (reload): Fix check for USEs to use code of pattern.
+ (choose_reload_regs): Remove dead variable use_insn.
- * rs6000.h (TARGET_SWITCHES): Set MASK_STRING_SET explicitly
- if -mno-string, so that it can override the processor default.
+Tue May 12 14:04:49 1998 Jeffrey A Law (law@cygnus.com)
-Wed May 31 07:31:53 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pa.h (DBX_CONTIN_LENGTH): Reduce to 3000 bytes.
- * c-common.c (truthvalue_conversion, BIT_AND_EXPR): Make sure that
- the result has boolean_type_node.
+Tue May 12 15:16:02 1998 Michael Meissner <meissner@cygnus.com>
-Tue May 30 19:03:21 1995 J.T. Conklin <jtc@cygnus.com>
+ * haifa-sched.c (HAIFA_INLINE): Define to be __inline unless
+ already defined.
+ (find_insn_{,mem_}list): Use HAIFA_INLINE, not __inline.
+ (insn_{unit,issue_delay}): Ditto.
+ (blockage_range): Ditto.
+ (actual_hazard{,_this_instance}): Ditto.
+ (schedule_unit): Ditto.
+ (potential_hazard): Ditto.
+ (insn_cost): Ditto.
+ (swap_sort): Ditto.
+ (queue_insn): Ditto.
+ (birthing_insn_p): Ditto.
+ (adjust_priority): Ditto.
+ (get_block_head_tail): Ditto.
+ (init_rgn_data_dependences): Ditto.
- * stddef.h: Undefine _BSD_XXX_T_ if _GCC_XXX_T is defined on BSD
- Net/2 derived systems.
+Tue May 12 10:27:54 1998 Klaus Kaempf <kkaempf@progis.de>
-Tue May 30 08:17:37 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ * alpha/vms.h (COMMON_ASM_OP, ASM_OUTPUT_ALIGNED_COMMON): Define.
- * m68k.md (decrement_and_branch_until_zero): Operand 0 constraint
- changed from "+g" to "+d*am".
- (similar anonymous HImode pattern): Likewise.
+Tue May 12 11:44:14 1998 Gavin Koch <gavin@cygnus.com>
- * m68k.md (tstdi): Use tst/subx #0 instead of neg/negx.
- Allow "a" and ">" for operand 0.
+ * config/mips/mips.h (ASM_OUTPUT_ALIGN): Remove trailing semi-colon.
-Mon May 29 19:24:43 1995 Niklas Hallqvist (niklas@appli.se)
+Tue May 12 11:38:31 1998 Gavin Koch <gavin@cygnus.com>
- * m68k.md (addsi_lshrsi_31): Use match_dup, not constraint "1",
- for matching inputs.
+ * config/mips/mips.md (dslot): Move after definition of "cpu"
+ attribute. Handle r3900 case.
-Mon May 29 12:39:58 1995 Allen Briggs <briggs@rrinc.com>
+Tue May 12 10:21:36 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * i386/isc.h ({STARTFILE,LIB,CPP}_SPEC): Handle -Xp like -posix.
- * i386/x-isc3 (X_CFLAGS): Add -Xp.
-
-Mon May 29 12:28:41 1995 J.T. Conklin (jtc@cygnus.com)
+ * system.h: Define the STRINGIFY macro here.
+ * protoize.c: Not here.
+ * gengenrtl.c (DEF_RTL_EXPR): Use the STRINGIFY macro.
- * configure (sparc-*-netbsd): Add missing asterisk at end.
+Tue May 12 00:47:33 1998 John Wehle (john@feith.com)
-Mon May 29 08:55:48 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * varasm.c (assemble_variable): Compute the alignment of the data
+ earlier so that both initialized and uninitialized variables are
+ effected by DATA_ALIGNMENT.
+ * tm.texi (DATA_ALIGNMENT): Updated appropriately.
- * combine.c (recog_for_combine): New parm PADDED_SCRATCHES; set it.
- (try_combine): Accumulate number of scratches and update max_scratch.
- (simplify_set): Add extra parm to recog_for_combine.
+Mon May 11 19:57:58 1998 Jeffrey A Law (law@cygnus.com)
- * romp.md (call): Put USE for r0 in CALL_INSN; call call_internal
- to emit insn.
- (call_internal): New name for anonymous call.
- (call_value, call_value_internal): Likewise.
+ * mips.c: Prototype static functions.
- * winnt/xm-winnt.h: Protect most definitions with #ifndef.
- * alpha/xm-winnt.h: Include alpha/xm-alpha.h, then winnt/xm-winnt.h.
- (POSIX): Undefine.
- * xm-alpha.h: Don't include alloca.h for winnt.
+Mon May 11 17:43:03 1998 Jim Wilson <wilson@cygnus.com>
-Sun May 28 18:34:01 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * regmove.c (fixup_match_2, find_matches, regmove_profitable):
+ Add explanatory comments.
- * configure: Make sed commands more uniform.
+ * sparc.h (SPARC_INCOMING_INT_ARG_FIRST): Support TARGET_FLAT.
- * Makefile.in: Properly use $(srcdir) for files that have it
- in their reference as a target of a rule.
- (libgcc1.a): Add missing RANLIB_TEST use.
+Mon May 11 17:24:27 1998 Richard Henderson <rth@cygnus.com>
- * stmt.c (expand_computed_goto): Call do_pending_stack_adjust.
+ * sparc.md (ffsdi2): Disable. Simplify the expression as well.
-Sun May 28 18:08:41 1995 Torbjorn Granlund <tege@mole.gnu.ai.mit.edu>
+Mon May 11 13:30:44 1998 Jim Wilson <wilson@cygnus.com>
- * m68k.md (divmodhi4, udivmodhi4): Use "dmsK" for operand 2.
+ * varasm.c (make_decl_rtl): Disable April 1 change.
-Fri May 26 17:01:22 1995 Paul Eggert <eggert@twinsun.com>
+Mon May 11 09:14:41 1998 Richard Henderson <rth@cygnus.com>
- * fixincludes: Fix bogus recursive <stdlib.h> in NEWS-OS 4.0C.
+ * configure.in (alpha-*-linux-gnu): Undo lossage from gcc2 merge.
-Fri May 26 08:02:14 1995 Michael Meissner (meissner@cygnus.com)
+Mon May 11 08:24:18 1998 Richard Henderson <rth@cygnus.com>
- * c-typeck.c (initializer_constant_valid_p): For the CONSTRUCTOR
- case, if the type is a record, recurse, just like for unions.
+ * alpha.h (PRINT_OPERAND_PUNCT_VALID_P): Add '`'.
+ * alpha.c (print_operand): Handle it.
+ * alpha.md (fix_truncdfsi2, fix_truncsfsi2): New patterns and
+ related define_splits. Also add peepholes for SImode reload
+ plus sign_extend lossage.
-Thu May 25 07:56:14 1995 Paul Eggert <eggert@twinsun.com>
+Mon May 11 09:33:10 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * fixincludes: Add `sel', `tahoe', `r3000', `r4000' to the
- list of pre-ANSI symbols that need to be surrounded with __ __.
- Allow white space between `#' and `if' when looking for lines to patch.
+ * genattr.c: Include stdarg.h/varargs.h. Change function
+ `fatal' to use variable arguments instead of faking it with
+ integer parameters. Provide a prototype which also
+ checks the format specifiers using ATTRIBUTE_PRINTF_1.
- * objc/sarray.h (PRECOMPUTE_SELECTORS, struct soffset):
- Use #ifdef __sparc__, not sparc.
+ * genattrtab.c: Likewise.
+ * gencodes.c: Likewise.
+ * genconfig.c: Likewise.
+ * genemit.c: Likewise.
+ * genextract.c: Likewise.
+ * genflags.c: Likewise.
+ * genopinit.c: Likewise.
+ * genpeep.c: Likewise.
+ * genrecog.c: Likewise.
+ * genoutput.c: Likewise. Similarly for function `error'.
- * m68k.md (addsi_lshrsi_31, ashldi_const, ashrdi_const, lshrdi_const):
- Replace `mov' with `move'.
+Sun May 10 02:27:03 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
-Thu May 25 07:35:37 1995 Allen Briggs <briggs@rrinc.com>
+ * acconfig.h (HAVE_VOLATILE): Insert stub for autoconf.
+ * alocal.m4 (GCC_C_VOLATILE): New autoconf test.
+ * configure.in: Use GCC_C_VOLATILE.
+ * system.h (volatile): Define as empty if no volatile support is
+ available.
- * libgcc2.c (L_eh, i386): Remove in-line comments in assembly
- code--the '#' character is not valid for the SYSV as.
-
-Thu May 25 07:28:54 1995 Pat Rankin (rankin@eql.caltech.edu)
+Sun May 10 01:21:43 1998 Jeffrey A Law (law@cygnus.com)
- * Makefile.in (BC_ALL): Restore it from May 22 change; vms uses it.
- (STAGESTUFF): Use it.
+ * genemit.c (output_add_clobbers): Removed unused variable 'i' from
+ generated fucntion.
-Thu May 25 07:11:56 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Sat May 9 02:02:15 1998 Richard Henderson <rth@cygnus.com>
- * alpha.c (alpha_emit_set_const): Don't call expand_binop for
- other than add if SImode and can't create pseudos.
+ * loop.c (get_condition): Don't combine when either compare is MODE_CC.
+ * alpha.c (alpha_emit_conditional_branch): New function. Taken from
+ the body of beq; additionally set the mode of the branch to CCmode for
+ FP compares and not fast_math.
+ (alpha_emit_conditional_move): Always use a compare insn for FP
+ when not fast_math, as well as setting CCmode on the cmov.
+ * alpha.md (beq, bne, blt, et al): Call alpha_emit_conditional_branch.
-Wed May 24 21:38:24 1995 Jim Wilson <wilson@cygnus.com>
+ * machmode.h (COMPLEX_MODE_P): New macro.
- * sched.c (reemit_notes): New function.
- (schedule_block): Call reemit_notes twice. Reorganize code for
- handling SCHED_GROUP_P insns, so that reemit_notes works.
+Sat May 9 01:53:23 1998 Richard Henderson <rth@cygnus.com>
- * sh/sh.c (shiftcosts, genshifty_op): Add SH3 support.
- * sh/sh.md (ashlsi3, lshrsi3): Add SH3 support.
- (ashlsi3_d, ashrsi3_d, lshrsi3_d): New patterns for SH3.
- (ashrsi2_31): Remove r/!r constraint.
+ * haifa-sched.c (print_exp): Fix typo.
-Wed May 24 17:00:47 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Fri May 8 21:48:50 PDT 1998 Jeff Law (law@cygnus.com)
- * tree.c (type_list_equal): Call simple_cst_equal before checking
- types.
+ * version.c: Bump for snapshot.
-Wed May 24 16:49:49 1995 Douglas Rupp (drupp@cs.washington.edu)
+Fri May 8 18:23:08 1998 Michael Meissner <meissner@cygnus.com>
- * Makefile.in (libgcc2.a): Handle case of separate srcdir.
+ * final.c (final_scan_insn): Call fatal_insn instead of abort if
+ we could not split an insn when required to.
-Wed May 24 16:22:01 1995 Paul Eggert <eggert@twinsun.com>
+ * m32r.md ({add,sub}di3): Add define_splits and appropriate low
+ level insns.
+ (peepholes): Disable peepholes that call dead_or_set_p.
+ (movsi): Rewrite to handle addresses better after last change.
+ Add define_split to split load of addresses in large/medium modes.
+ (prologue): Call m32r_expand_prologue.
+ (movsi_{push,pop}): Generators for push/pop.
+ (movsi): Support PRE_{INC,DEC}, POST_INC.
+ (mov{di,df}): Rewrite. Always split the insns.
+ (movsf): Add define_split to get register load in correct mode.
+ (cmp_ne_small_const_insn): Use 'N' instead of 'S' constraint.
+ (attributes): Rewrite attributes so that type indicates both the
+ type and the length of the insn directly.
+ (all insns): Change to use new type attributes.
+ (debug): New attribute to convey whether -mdebug was used.
+ (opt_space): New attribute to convey whether -Os was used.
+ (function units): Loads are 3 cycles, not 2. Better classify all
+ insns into short/long.
+ (load/store/extend insns): Add separate case for load/store
+ indirect operations without an offset.
+ (divsi3): Division is a long operation, not short.
- * configure: Define $(MAKE) if `make' doesn't.
+ * m32r.h (LEGITIMATE_LO_SUM_ADDRESS_P): Do not allow LO_SUM for
+ modes > 1 word.
+ (GO_IF_MODE_DEPENDENT_ADDRESS): LO_SUM is now mode dependent.
+ (CONST_OK_FOR_LETTER_P): Make 'N' handle reverse 8 bit compares.
+ (EXTRA_CONSTRAINT): Remove 'S' special support. Add 'U' for
+ operands with PRE_{INC,DEC}, POST_INC.
+ (FUNCTION_PROFILER): Call abort instead of doing nothing.
+ (GO_IF_LEGITIMATE_ADDRESS): Allow PRE_{INC,DEC}, POST_INC of
+ SImode variables.
+ (gen_split_move_double): Declare.
+ (EXTRA_CONSTRAINT): Add 'T' for memory reference with no offset.
+
+ * m32r.c (gen_split_move_double): Fix typo. Also, don't call
+ emit_move_insn, build up SET's directly.
+ (toplevel): Include system.h, not stdio.h.
+ (move_double_src_operand): Allow any DF or DI mode constant.
+ (gen_split_move_double): Split moves of DI or DF values into the
+ appropriate moves, loads, or stores. Don't handle use of auto
+ inc/dec if using dead index. Do handle overlapping moves, etc.
+ (m32r_frame_info): Remove prologue_size field.
+ (m32r_compute_frame_size): Don't calculate prologue size.
+ (m32r_output_function_prologue): Change to pretty much a NOP.
+ (m32r_expand_prologue): Expand prologue as a series of INSNs.
+ (m32r_print_operand): Add support for PRE_{INC,DEC}, POST_INC.
+ (m32r_print_operand_address): Ditto.
+
+Fri May 8 14:13:21 1998 H.J. Lu (hjl@gnu.org)
+
+ * reload1.c (emit_reload_insns): When performing expensive
+ optimizations, do not output the last reload insn if OLD is
+ not the dest of NSN and is in the src and is clobbered by INSN.
+
+Fri May 8 09:47:29 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (genrtl.o): Depend on system.h.
+ * gengenrtl.c (gencode): When creating genrtl.c, have it
+ include system.h.
-Wed May 24 15:50:51 1995 Doug Evans <dje@cygnus.com>
+Fri May 8 10:57:33 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- * dsp16xx.h (CROSS_LINK_SPEC): ENDFILE_SPEC moved to -nostartfiles.
- * i386/freebsd.h (LINK_SPEC): Don't pass "-e start" if nostartfiles
- rather than nostdlib.
- * i386/sun.h (LINK_SPEC): Likewise.
- * m68k/sun2o4.h (LINK_SPEC): Likewise.
- * m68k/sun3.h (LINK_SPEC): Likewise.
- * m68k/vxm68k.h (LINK_SPEC): Likewise.
- * mips/netbsd.h (LINK_SPEC): Likewise.
- * config/netbsd.h (LINK_SPEC): Likewise.
- * rs6000/mach.h (LINK_SPEC): Likewise.
- * sparc.h (LINK_SPEC): Likewise.
- * sparc/vxsparc.h (LINK_SPEC): Likewise.
+ * config/m68k/t-linux: Remove extra stuff already included in
+ config/t-linux.
+
+Fri May 8 09:53:24 Paul Eggert <eggert@twinsun.com>
+
+ * fixinc.wrap: Renamed from fixinc.math. Put wrapper around
+ curses.h if it contains `typedef char bool;', as suggested by
+ Manfred Hollstein <manfred@s-direktnet.de>.
+
+ * configure.in: Rename fixinc.math to fixinc.wrap.
+
+Thu May 7 19:26:34 1998 Jim Wilson <wilson@cygnus.com>
+
+ * gcc.c (read_specs): Handle missing blank line at end of specs file.
+
+ * i386.md (movsicc, movhicc, movsicc_1, movhicc_1, movsfcc_1,
+ movdfcc_1): Disable.
+
+Thu May 7 15:39:14 1998 Jim Wilson <wilson@cygnus.com>
+
+ * configure.in (enable_threads): Rename to enable_threads_flag before
+ main loop. Set enable_threads to enable_threads_flag inside main
+ loop.
+
+Thu May 7 17:38:03 1998 Michael Meissner <meissner@cygnus.com>
+
+ * r6000/eabi.asm (__eabi): Restore LR in case __eabi is called
+ multiple times.
+
+Thu May 7 14:26:05 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * aclocal.m4 (GCC_FUNC_VFPRINTF_DOPRNT): New macro.
+
+ * configure.in: Add a call to GCC_FUNC_VFPRINTF_DOPRNT.
+ (AC_CHECK_HEADERS): Remove unused check for varargs.h,sys/varargs.h.
+ (AC_CHECK_FUNCS): Remove unused check for vprintf.
+
+ * Makefile.in: Add support for linking in vfprintf.c and doprint.c.
+ (cccp.o): Depend on gansidecl.h.
+ (cexp.o): Likewise.
+
+ * cccp.c: Convert from using PRINTF_ALIST/PRINTF_DCL to VPROTO as
+ per the rest of gcc source.
+ * cexp.y: Likewise. Include gansidecl.h and remove all code made
+ redundant.
+
+ * cccp.c: Remove checks for HAVE_VPRINTF and the associated code
+ used when vfprintf is missing.
+ * cexp.y: Likewise.
+ * gcc.c: Likewise.
+ * genattrtab.c: Likewise.
+ * mips-tfile.c: Likewise.
+ * toplev.c: Likewise.
+
+ * vfprintf.c: New file.
+ * doprint.c: New file.
+
+Thu May 7 10:18:41 1998 Jeffrey A Law (law@cygnus.com)
- * m88k/m88k.h (FUNCTION_ARG_BOUNDARY): Use GET_MODE_BITSIZE.
+ * config/linux.h (ASM_COMMENT_START): Remove from here,
+ * config/linux-aout.h (ASM_COMMENT_START): and here,
+ * config/i386/linux.h (ASM_COMMENT_START): to here,
+ * config/i386/linux-aout.h (ASM_COMMENT_START): and here.
+ * config/i386/linux-oldld.h (ASM_COMMENT_START): Define
+ here as '#' too.
-Wed May 24 15:44:04 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Thu May 7 10:55:59 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * config/m68k/m68k.md (adddi3, subdi3): Properly negate the DImode
+ constant.
- * fold-const.c (fold): Make sure that a folded TRUTH_NOT_EXPR
- retains the same type.
+Wed May 6 22:32:37 CDT 1998 Robert Lipe <robertl@dgii.com>
- * c-common.c (truthvalue_conversion): Also accept TRUTH_NOT_EXPR.
+ * Makefile.in (dwarfout.o) Add toplev.h dependency.
+ * dwarfout.c, i386.c: Include toplev.h
+ * toplev.h: (pfatal_with_name) Add prototype.
-Wed May 24 15:41:51 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Wed May 6 19:02:29 1998 Jason Merrill <jason@yorick.cygnus.com>
- * cplus-dem.c (strstr, strncmp, strlen): Remove declarations.
+ * Makefile.in: Fix .SUFFIXES.
- * tree.c (type_list_equal, simple_cst_list_equal, index_type_equal):
- Check for simple_cst_equal return value of -1.
+Wed May 6 19:31:32 1998 Alan Modra <alan@spri.levels.unisa.edu.au>
-Wed May 24 10:05:24 1995 Michael Meissner <meissner@cygnus.com>
+ * config/linux.h (ASM_COMMENT_START): Define as "#".
+ * config/linux-aout.h (ASM_COMMENT_START): Likewise.
- * libgcc1-test.c (start, _start): Provide declarations, so that
- the GNU linker doesn't give a warning message about defaulting the
- start address.
+Wed May 6 15:51:39 1998 Jim Wilson <wilson@cygnus.com>
- * rs6000/sysv4.h (STRIP_NAME_ENCODING): Redefine back to the
- original defination, rather than the defination used in rs6000.h.
- (ASM_OUTPUT_SOURCE_LINE): Use STRIP_NAME_ENCODING.
- * rs6000.h (STRIP_NAME_ENCODING): Skip leading '*'.
+ * objc/Make-lang.h (objc-parse.o): Add toplev.h dependency.
+ * objc/objc-parse.y, objc/objc-parse.c: Regenerate.
- * rs6000.h (MASK_STRING_SET, TARGET_STRING_SET): Add target
- flags bit for whether -mstring was actually used.
- (TARGET_SWITCHES): Add MASK_STRING to all power targets. Set
- MASK_STRING_SET for -mstring and -mno-string.
- (TARGET_DEFAULT): Add MASK_STRING.
+ * toplev.c: Include toplev.h.
+ * Makefile.in (c-common.o, c-convert.o, c-decl.o, c-iterate.o,
+ c-lex.o, c-parse.o, c-pragma.o, c-typeck.o, calls.o, convert.o,
+ dwarf2out.o, except.o, expr.o, final.o, fold-const.o, function.o,
+ hash.o, profile.o, real.o, reg-stack.o, regclass.o, reload.o,
+ reload1.o, stmt.o, stor-layout.o, tlink.o, tree.o, varasm.o): Add
+ toplev.h dependency.
- * rs6000.c (rs6000_override_options): Add MASK_STRING to
- all power targets. Make an explicit -mstring/-mno-string override
- the -mcpu=processor default.
+ * mips/mips.c (save_restore_insns): Change FRAME_POINTER_REGNUM to
+ HARD_FRAME_POINTER_REGNUM.
- * rs6000/eabile.h (CPP_SPEC): Copy from sysvle.h to provide the
- appropriate little endian defaults.
+ * expr.c (target_temp_slot_level): Delete duplicate definition.
- * rs6000/sysv4.h (ASM_OUTPUT_SOURCE_LINE): Use assemble_name to
- output the canonical name.
+Wed May 6 16:46:01 1998 Jeffrey A Law (law@cygnus.com)
-Wed May 24 01:21:15 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * stmt.c (mark_seen_cases): Make it have external linkage again.
+ * expr.h (mark_seen_cases): Add declaration, but only when tree.h
+ has been included.
- * rs6000.h (STRIP_NAME_ENCODING): Define.
- (RS6000_OUTPUT_BASENAME): Use it.
+ * haifa-sched.c (print_value, case SUBREG): Fix typo.
-Tue May 23 19:54:21 1995 Doug Evans <dje@cygnus.com>
+ * i386.c (output_387_binary_op): Add some braces to avoid warnings.
+ * i386.h (REG_CLASS_CONTENTS): Similarly.
- * gcc.c (link_command_spec): Move ENDFILE_SPEC from -nostdlib
- to -nostartfiles.
+ * toplev.c (-fsched-max): Delete flag.
+ (-fsched-interblock-max-blocks,-fsched-interblock-max-insns): Likewise.
+ * haifa-sched.c: Remove -fsched-max-N, -fsched-interblock-max-blocks-N
+ and -fsched-interblock-max-insns-N support. Remove INTERBLOCK_DEBUG
+ conditionals.
-Tue May 23 17:01:50 1995 Jim Wilson <wilson@cygnus.com>
+ * haifa-sched.c (find_rgns): Correctly handle reducible loops with
+ inner loops which are not reducible.
- * alpha.md (negsi2-2): Change output pattern to #.
+ * loop.c (regs_match_p): Fix typo in prototype.
- * mips.c (embedded_pic_offset): Output RTL to initialize
- embedded_pic_fnaddr_rtx.
- (mips_finalize_pic): Delete.
- * mips.h (mips_finalize_pic): Delete declaration.
- (FINALIZE_PIC): Delete.
- (INIT_EXPANDERS): Clear embedded_pic_fnaddr_rtx.
- * mips.md (get_fnaddr): Add = to output contraint.
+ * regmove.c (try_auto_increment): Wrap declaration inside an
+ #ifdef AUTO_INC_DEC.
- * sh.c (shift_amounts): Correct entry for shifts by 29.
- * sh.md (sett): New pattern.
- (movsi_i): Change source constraint for move to T reg to be 'z'.
-
- * mips/ecoff.h (STARTFILE_SPEC): Define to null string.
- * mips/elfl.h, mips/elfl64.h: Correct typo in comment.
-
- * mips/elflorion.h, mips/elforion.h (MIPS_CPU_DEFAULT): Delete.
- * mips.c (override_options): Delete #ifdef MIPS_CPU_DEFAULT code.
- Add #ifdef MIPS_CPU_DEFAULT_STRING code before the first
- mips_cpu_string test.
-
-Tue May 23 07:22:36 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * romp.c (hash_rtx): Avoid warning on int-to-pointer conversion.
- (output_fpops): Cast args to bcopy to char *.
-
- * cpplib.c (initialize_builtins): Add missing parm to timestamp call.
-
- * Makefile.in (install-libobjc): Don't depend on libobjc.a.
-
- * c-parse.in: Objc shift/reduce conflicts now 48.
- (parm): Use setspecs/restore here.
- (parmlist_or_identifiers): Not here.
-
-Mon May 22 19:30:30 1995 Doug Evans <dje@cygnus.com>
-
- * h8300.md (movsf_h8300h): Add missing post-inc case to constraints.
-
-Mon May 22 14:38:36 1995 Michael Meissner <meissner@cygnus.com>
-
- * rs6000.c (rs6000_override_options): Do SUBTARGET_OVERRIDE_OPTIONS
- here.
- * rs6000.h (OVERRIDE_OPTIONS): Not here.
-
- * rs6000.c (expand_block_move): Handle moves without string
- instructions by generating a series of loads and stores.
- (output_prolog): Support -mno-toc on V.4 and eabi systems.
-
- * rs6000/sysv4.h (TARGET_SWITCHES): Add -mtoc and -mno-toc.
- (SUBTARGET_OVERRIDE_OPTIONS): Add some warnings for incompatible
- switches.
- (TOC_SECTION_FUNCTION): Make -mno-toc like -mrelocatable in that
- we don't put the minimal toc pointer in the global toc section.
- (LINK_SPEC): Use -oformat to set link output format, not -m.
-
- * rs6000/t-eabigas (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): Build
- libgcc.a variants with -mno-toc support.
- * rs6000/t-ppcgas (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): Ditto.
-
-Mon May 22 07:10:52 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * cplus-dem.c (mystrstr): Replacement for strstr.
-
- * configure: Split up long sed command.
- * Makefile.in (SYMLINK): Deleted; unused.
- (oldobjext): Deleted; no longer used.
- (FLAGS_TO_PASS): Include objext and exeext.
- (STAGESTUFF, protoize.o, unprotoize.o): Use $(objext), not .o.
- (test_protoize_simple, compare{,3}, gnucompare{,3}): Likewise.
- (STAGESTUFF, specs, gcc-cross, collect2): Add missing $(exeext).
- (libgcc1.null, libgcc[12].a, stage[1-4]): Likewise.
- (xgcc, cc1, cc1obj, enquire): Use $@ instead of filename for -o value.
- (collect2, mips-tfile, mips-tdump, gen*): Likewise.
- (bi-arity, bi-opcode, bi-opname, cccp, cppmain): Likewise.
- (protoize, unprotoize, gen-protos, fix-header): Likewise.
- (crtbegin.o, crtend.o): Don't use -o; move output to proper
- filename (using objext) instead.
- (BI_ALL, BC_ALL, bytecode): Deleted; unused.
- (bi-*.o, cexp.o, stamp-{proto,fixinc}): Remove unneeded $(srcdir).
- (getopt{,1}.o, SYSCALLS.c.X): Likewise.
- (install-driver): New target.
- (install-normal): Depend on it.
- (install-common): Don't depend on xgcc.
- (maketest): Deleted; no longer used.
- (stage[1-4]): Use name collect-ld, not real-ld.
- (risky-stage[1-4]): Use stage[1-4] as dependencies; don't copy.
- * alpha/config-nt.bat, i386/config-nt.bat: Make {,h,t}config.h
- and tm.h by writing a single #include line.
- Update way specs.h and options.h are written.
- * alpha/config-nt.sed, i386/config-nt.sed: Set new variables
- into Makefile.
- Build winnt.obj.
- Edit CCCP definition.
- * alpha/x-winnt, i386/x-winnt (oldobjext): Deleted.
- Add rules for .c.obj, .adb.obj, and .ads.obj.
- (LIB2FUNCS_EXTRA, spawnv.o): New rules.
- * i386/x-winnt (objext): Now .obj, not .o.
-
- * gcc.c (HAVE_OBJECT_SUFFIX): New macro.
- (process_command): Convert x.o to x.foo for OBJECT_SUFFIX of ".foo".
- (do_spec_1): Avoid shadow variable "i" and always use for loop var.
-
- * c-decl.c (finish_decl_top_level): Removed; no longer used.
- * objc-act.c: Numerous formatting changes.
- (NULLT): Deleted; all uses changed to NULL_TREE.
- (get_{static,object}_reference, objc_add_static_instance):
- Use push_obstacks instead of saving obstacks manually.
- (build_{selector,class}_reference_decl): Likewise.
- (build_objc_string_decl, build_protocol_reference): Likewise.
- (comp_{method,proto}_with_proto): Likewise.
- (create_builtin_decl, synth_module_prologue): Set DECL_ARTIFICIAL
- for internal objects.
- (build_{selector,class}_reference_decl, add_objc_decls): Likewise.
- (generate_objc_symtab_decl, build_module_descriptor): Likewise.
- (build_protocol_reference): Likewise.
- (build_objc_string_decl, synch_forward_declarations): Likewise.
- Delete call to end_temporary_allocation.
- (generate_static_references, generate_strings): Likewise.
- (build_selector_translation_table, generate_category): Likewise.
- (generate_{ivars,protocol}_list, build_protocol_reference): Likewise.
- (build_objc_string_object): If next_runtime, put everything in
- permanent obstack.
- (objc_add_static_instance): Use build_decl instead of start_decl
- and finish_decl_top_level.
- (build_{class_reference,objc_string}_decl): Clear DECL_CONTEXT.
- (start_class): Exit with FATAL_EXIT_CODE, not 1.
- (add_objc_decls): Don't set DECL_IN_SYSTEM_HEADER.
-
- * tree.c (valid_machine_attribute): Handle attribute on
- pointer-to-function types.
-
-Sun May 21 17:16:37 1995 J. T. Conklin <jtc@cygnus.com>
-
- * mips/netbsd.h (HAVE_STRERROR): Remove.
- * mips/xm-netbsd.h: New file.
- * mips/t-mips-netbsd: Deleted.
- * configure (mips-dec-netbsd): Use xm-netbsd.h and t-libc-ok.
-
-Sun May 21 17:16:37 1995 Arne H. Juul (arnej@pvv.unit.no)
-
- * mips/netbsd.h: Use __start as entry point. Ifdef some
- paths on CROSS_COMPILE.
-
-Sun May 21 08:39:26 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * c-parse.in (datadef, fndef, ivar_decl, mydecls):
- Restore declspec_stack since setspecs is used.
- (parmlist_or_identifiers): Use setspecs before parsing parms
- and restore after parsing parms.
-
-Sun May 21 01:04:52 1995 Jeffrey A. Law <law@snake.cs.utah.edu>
-
- * pa.c (hppa_encode_label): New variable "permanent" to
- where/how memory is allocated for the new label. All
- callers changed.
-
-Sat May 20 16:53:30 1995 Mike Meissner <meissner@cygnus.com>
-
- * rs6000.md (insv, extz): Fail if the structure is QI or HI reg to
- avoid paradoxical subreg's being created in RTL phase, which uses
- SImode to load from memory if structure is later moved to stack.
-
-Sat May 20 06:44:59 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
-
- * m68k.md (udivmodhi4): Output "divu" instead of "divs".
-
-Sat May 20 06:11:32 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * reload.c (push_reload): Don't reload inside a SUBREG
- when SUBREG_WORD is nonzero.
-
- * c-decl.c (shadow_tag_warned): Don't warn about useless keyword
- if in system header file.
-
- * tree.c (simple_cst_equal): Don't look at language-specific
- nodes since we don't know what's in them.
-
- * cpperror.c: #include config.h before any other .h file.
+Wed May 6 17:07:47 1998 Michael Meissner <meissner@cygnus.com>
+
+ * final.c (output_operand_lossage): Call fatal with the operand
+ lossage message instead of calling abort.
+
+Wed May 6 15:37:27 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * c-common.c: Convert to using ctype macros defined in system.h.
+ * c-lex.c: Likewise.
+ * cccp.c: Likewise.
* collect2.c: Likewise.
+ * rs6000.c: Likewise.
+ * cpplib.c: Likewise.
+ * fix-header.c: Likewise.
+ * gcc.c: Likewise.
+ * gen-protos.c: Likewise.
+ * pexecute.c: Likewise.
+ * protoize.c: Likewise.
+ * rtl.c: Likewise.
+ * scan.c: Likewise.
+ * stmt.c: Likewise.
+ * tlink.c: Likewise.
+ * toplev.c: Likewise.
- * i386/config-nt.bat: Add missing ^M on two lines.
- Add case for Fortran; fix typo in Ada case.
- * alpha/config-nt.bat: Add case for Fortran; fix typo in Ada case.
+Wed May 6 14:44:14 1998 Gavin Koch <gavin@cygnus.com>
- * m68k/t-next (LIBGCC1, CROSS_LIBGCC1): Make not, not "libgcc1.null".
- (OTHER_FIXINCLUDES_DIRS, LIMITS_H_TEST): Delete from here.
- * m68k/x-next (OTHER_FIXINCLUDES_DIR, LIMITS_H_TEST): Move to here.
+ * config/mips/r3900.h (SUBTARGET_ASM_DEBUGGING_SPEC) :
+ Replace -gdwarf-2 with -g0.
-Fri May 19 19:30:20 1995 Stan Cox (gcc@dg-rtp.dg.com)
+Wed May 6 11:43:18 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * crtstuff.c: Added reference to INIT_SECTION_PREAMBLE for systems that
- do something which must be undone prior to __do_global_ctors.
+ * Makefile.in (mips-tfile.o, mips-tdump.o): Depend on system.h.
+ * mips-tdump.c: Include system.h, remove redundant headers.
+ * mips-tfile.c: Likewise. Also, convert all ctype function calls
+ to calls of the macro versions defined in system.h.
-Fri May 19 19:27:08 1995 Alan Modra <alan@SPRI.Levels.UniSA.Edu.Au>
+ * objc/Make-lang.in (objc-act.o): Depend on system.h.
+ * objc/objc-act.c: Include system.h, remove redundant headers.
- * i386/linux-aout.h (CPP_SPEC): Add defines for -fPIC.
- * i386/linux-oldld.h (CPP_SPEC): Likewise.
+Wed May 6 11:21:06 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
-Fri May 19 17:46:28 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+ * configure.in (AC_CHECK_FUNCS): Add isascii.
+ (GCC_NEED_DECLARATIONS): Add atof.
- * collect2.c (strstr): Deleted.
- * cplus-dem.c (strstr): Define ifndef POSIX.
+ * system.h: Provide prototypes for abort, atof, atol and sbrk here.
+ * rtl.c, rtl.h, toplev.c, tree.h: Not here.
-Fri May 19 11:16:51 1995 Per Bothner <bothner@kalessin.cygnus.com>
+Wed May 6 10:52:49 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * cpplib.c (collect_expansion): Don't escape '@' inside string.
+ * system.h: Wrap time.h and sys/file.h in autoconf checks.
+ Provide default definitions for O_RDONLY and O_WRONLY here.
-Fri May 19 06:59:21 1995 Pat Rankin (rankin@eql.caltech.edu)
+ * cccp.c, cpplib.c, fix-header.c, gcc.c, protoize.c: Not here.
- * vmsconfig.com (process_objc_lib, configure_makefile): New routines.
- (bc_all.list, ./vax.md, objc-objs.opt, objc-hdrs.list): New files
- created at config time.
- (bc_all.opt, ./md.): No longer created.
- * make-cc1.com: Handle revised filenames from vmsconfig.com;
- (DO_OBJCLIB): New variable, plus code to compile objc/*.{c,m}.
+1998-05-06 Mark Mitchell <mmitchell@usa.net>
-Wed May 17 16:15:31 1995 Torbjorn Granlund <tege@cygnus.com>
+ * tree.h (IS_EXPR_CODE_CLASS): Remove bogus '3'.
- * i960.c (i960_output_ldconst): New code for XFmode.
- Also, move SFmode code to immediately after DFmode code.
- (S_MODES, D_MODES): Handle XFmode.
- (XF_MODES): Was TF_MODES, handle XFmode instead of TFmode.
- (hard_regno_mode_ok): Replace TFmode with XFmode.
- (i960_output_long_double): New function.
+Wed May 6 06:35:38 1998 Robert Lipe <robertl@dgii.com>
- * i960.h (DATA_ALIGNMENT): Define.
- (ROUND_TYPE_ALIGN): Align XFmode scalars at 128 bit boundaries.
- (ROUND_TYPE_SIZE): Round up the size of XFmode objects to 128 bits.
- (CONST_DOUBLE_OK_FOR_LETTER_P): Use CONST0_RTX and CONST1_RTX
- so that all FP modes are recognized.
- (ASM_OUTPUT_LONG_DOUBLE): Define.
+ * toplev.h: New file. Protypes for functions in toplev.c.
+ * tree.h, rtl.h: Deleted protos for functions in toplev.c.
+ * c-common.c, c-convert.c, c-decl.c, c-iterate.c, c-lex.c,
+ c-parse.in, c-parse.y, c-pragma.c, c-typeck.c, calls.c,
+ convert.c, dwarf2out.c, except.c, expr.c, final.c, fold-const.c,
+ function.c, hash.c, profile.c, real.c, reg-stack.c, regclass.c,
+ reload.c, reload1.c, stmt.c, stor-layout.c, tlink.c, tree.c,
+ varasm.c: include it.
- * i960.md: Change all TFmode patterns to have XFmode.
- (movxf recognizer, frame version): Use movt, ldt, and stt.
- (movxf recognizer, non-frame version): Delete.
- (extenddfxf2): Delete * before f constraint.
- (extendsfxf2): Likewise.
+Wed May 6 01:09:01 1998 Jeffrey A Law (law@cygnus.com)
+ Jim Wilson (wilson@cygnus.com)
-Wed May 17 17:53:35 1995 Jim Wilson <wilson@mole.gnu.ai.mit.edu>
+ * haifa-sched.c (find_rgns): In no_loops case, fix test for leaf
+ blocks. Check for 1 successor which is the EXIT_BLOCK.
- * unroll.c (unroll_loop): Increment copy_start_luid if copy_start
- is loop_start.
+ * haifa-sched.c (find_rgns): Detect unreachable blocks, including
+ unreachable loops with more than one block.
-Wed May 17 17:44:57 1995 Lee Iverson <leei@Canada.AI.SRI.COM>
+Wed May 6 08:22:24 1998 Manfred Hollstein <manfred@s-direktnet.de>
- * fold-const.c (invert_truthvalue, case CLEANUP_POINT_EXPR): New case.
+ * fix-header.c (write_rbrac): Add "abort" to functions which need to
+ be protected.
-Tue May 16 18:51:16 1995 Michael Meissner <meissner@cygnus.com>
+Wed May 6 00:09:36 1998 Jeffrey A Law (law@cygnus.com)
- * rs6000/rs6000.h (TARGET_SWITCHES): Add -mstring to enable string
- instructions, and -mno-string to disable them.
- (MOVE_MAX): Don't test TARGET_MULTIPLE anymore.
- (MAX_MOVE_MAX): Set to 8, not 16.
- (expand_block_move): Add declaration.
+ * Check in merge from gcc2. See ChangeLog.12 for details.
- * rs6000/rs6000.c (expand_block_move): New function to expand
- block moves when -mstring is used.
+Tue May 5 14:33:49 1998 Jim Wilson <wilson@cygnus.com>
- * rs6000/rs6000.md (movti): Use TARGET_STRING, not TARGET_MULTIPLE.
- (load_multiple, store_multiple): Ditto.
- (string insns): Add 8, 6, 4, 2, and 1 register variants for using
- the native string instructions if -mstring.
+ * c-common.c (scan_char_table): Separate 's' and 'c'. 'c' does not
+ accept 'a' flag. 'S' does accept 'a' flag.
+ (check_format_info): When pedantic, warn for m/C/S/a/A formats,
+ and `a' flag.
- * rs6000/sysv4.h (CPP_SPEC): If little endian, define
- _LITTLE_ENDIAN and set littleendian assertion. If big endian,
- define _BIG_ENDIAN and set bigendian assertion.
- * rs6000/sysv4le.h (CPP_SPEC): Copy from sysv4.h, and change
- default to little endian.
+ * elf64.h (MULTILIB_DEFAULTS): Move definition after mips.h include.
- * rs6000/rs6000.c (override_options): Check for -mmultiple and
- -mstring on little endian systems here.
- * rs6000/sysv4.h (SUBTARGET_OVERRIDE_OPTIONS): Don't do the check
- here.
+Tue May 5 10:50:39 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-Tue May 16 18:36:41 1995 Douglas Rupp (drupp@cs.washington.edu)
+ * config/m68k/m68k.h: Declare functions from m68k.c used in
+ macros and machine description.
+ (ASM_OUTPUT_LONG_DOUBLE): Always use `l' flag in print format for
+ long values.
+ (ASM_OUTPUT_FLOAT): Likewise.
+ (ASM_OUTPUT_FLOAT_OPERAND): Likewise.
- * alpha.c: Changed WINNT to _WIN32.
- * alpha/config-nt.bat, i386/config-nt.bat: Added commands to
- generate specs.h and options.h.
- * i386/config-nt.sed: Changed link32 to link.
- * winnt/ld.c (main): Removed call to free.
- * configure.bat: Added line to echo usage on invalid input.
- * gcc.c (fix_argv): Removed call to free.
- * gcc.c, getpwd.c, protoize.c, sdbout.c: Changed WINNT to _WIN32.
- * toplev.c: Likewise.
+Tue May 5 01:28:12 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * tree.def: Add NAMESPACE_DECL.
+ * dwarfout.c (type_ok_for_scope): Ignore NAMESPACE_DECLs for now.
+ * dwarf2out.c (push_decl_scope): Likewise.
+ (scope_die_for): Likewise.
+ * tree.c (decl_function_context): Use TREE_CODE_CLASS to determine
+ how to get next context level.
+
+Tue May 5 01:43:16 1998 Jim Wilson <wilson@cygnus.com>
+
+ * i386.c (output_fix_trunc): Add code to emulate non-popping DImode
+ case.
+
+Tue May 5 01:15:06 1998 Jeffrey A Law (law@cygnus.com)
+
+ * h8300.h (ADDITIONAL_REGISTER_NAMES): Add "er" registers.
+
+ * reorg.c (fill_slots_from_thread): Update REG_DEAD/REG_UNUSED notes
+ for any insns skipped at the start of a block because they were
+ redundant.
+
+Mon May 4 20:23:51 1998 Jim Wilson <wilson@cygnus.com>
+
+ * alpha.h (DBX_CONTIN_LENGTH): Decrease to 3000.
+
+1998-05-04 Ulrich Drepper <drepper@cygnus.com>
+
+ * c-common.c (format_char_info): Add new field hhlen.
+ (print_char_table, scan_char_table, time_char_table): Initialize
+ hhlen field appropriately.
+ (char_format_info): Recognize hh modifier and lookup correct char
+ table entry.
+
+Mon May 4 19:15:29 1998 Jim Wilson <wilson@cygnus.com>
+
+ * expr.c (expand_expr, case INDIRECT_REF): Don't optimize string
+ reference if this is a store.
+
+Mon May 4 17:25:17 1998 Richard Henderson <rth@cygnus.com>
+
+ * sparc.c (output_move_quad): Fix typo in mov_by_64 argument.
+
+Sun May 3 23:57:25 1998 Robert Lipe <robertl@dgii.com>
+
+ Make UnixWare 7 bootstrap support work with final shipping product.
+ * configure.in: (i[34567]86-*-sysv5): append, not overwrite, xm_file.
+ Pick up xm-siglist and xm-alloca.
+ (xm_defines): Add USG so dbxout will build.
+ * configure: Regenerate.
+
+Sun May 3 13:51:34 PDT 1998 Richard Henderson <rth@cygnus.com>
+
+ Support for official Sparc V9 ABI:
+ * sparc.c (sparc_override_options): Force stack bias off for !arch64.
+ Care for flag_pcc_struct_return default.
+ (output_move_quad): Rewrite to move by halves on v9 and in the
+ proper direction.
+ (move_quad_direction): New function.
+ (output_fp_move_quad): Use it to determine the direction of copy.
+ (function_arg_slotno): Return -1 for FP reg overflow as well.
+ (function_arg_record_value*): New functions.
+ (function_arg): Use them. Streamline unprototyped parameter passing.
+ (function_arg_pass_by_reference): Pass TCmode by reference.
+ (function_value): New function.
+ * sparc.h (PTRDIFF_TYPE, SIZE_TYPE): For -pedantic's sake, don't use
+ long long in 64-bit mode.
+ (RETURN_IN_MEMORY): v9 returns structs < 32-bytes in regs.
+ (DEFAULT_PCC_STRUCT_RETURN): Make the default detectable.
+ (BASE_RETURN_VALUE_REG): Consider complex float types for arch64.
+ (BASE_OUTGOING_VALUE_REG, BASE_PASSING_ARG_REG): Likewise.
+ (BASE_INCOMING_ARG_REG): Likewise.
+ (FUNCTION_VALUE): Call function_value.
+ (FUNCTION_OUTGOING_VALUE, LIBCALL_VALUE): Likewise.
+ * sparc.md (movdi_sp32_v9): Disable for arch64.
+ (movsf, movdf, movtf): Sort all ulternatives using fp regs first.
+ (call_value_address_sp64): Remove register class constraints.
+ (call_value_symbolic_sp64): Likewise.
+ (nonlocal_goto): Pass label reg directly to goto_handlers. Constrain
+ v9 case to 32-bit constants.
+ (goto_handler_and_restore_v9): Provide a version for arch64.
+ * sparc/linux64.h (SIZE_TYPE, PTRDIFF_TYPE): Remove private definition.
+ * sparc/sp64-aout.h (TARGET_DEFAULT): Turn on stack bias.
+ (CPP_PREDEFINES): New.
+ * sparc/sp64-elf.h: Likewise.
+ (PREFERRED_DEBUGGING_TYPE): Dwarf2.
+ (ASM_OUTPUT_DWARF2_ADDR_CONST): New.
+ * sparc/sysv4.h (SIZE_TYPE, PTRDIFF_TYPE): Undo svr4.h's changes.
+
+Sat May 2 17:47:17 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sat May 2 01:37:29 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * reload.c (find_reloads): Emit USEs to mark where a pseudo
+ is reloaded with the MEM of its stack slot.
+ * reload1.c (cannot_omit_stores): Delete.
+ (reload): Don't initialize it.
+ Don't apply avoid_return_reg logic to USEs.
+ When done, remove USEs that have a REG_EQUAL note on them.
+ (emit_reload_insns): Handle case where we have inherited a MEM.
+ (choose_reload_regs): Likewise.
+ (delete_output_reload): Don't use cannot_omit_stores.
+
+Thu Apr 30 18:59:03 1998 Jim Wilson <wilson@cygnus.com>
+
+ * Makefile.in (cpp.info, gcc.info): Put -o option before input file.
+
+Thu Apr 30 16:57:34 1998 Michael Meissner <meissner@cygnus.com>
+
+ * haifa-sched.c (print_{exp,value}): Various changes to make the
+ debug output easier to read. Also, use only one buffer, and make
+ sure the buffer we are passed in doesn't overflow.
+ (safe_concat): Concatenate to a buffer without overflow.
+
+Thu Apr 30 16:57:34 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * haifa-sched.c (alloc_{INSN,EXPR}_LIST): Make static to agree
+ with the prototype.
+
+Wed Apr 29 21:45:16 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sched.c (new_insn_dead_notes): Check if the register was
+ used in the original instruction.
+ * haifa-sched.c (new_insn_dead_notes): Likewise.
+
+Wed Apr 29 13:46:03 1998 Jim Wilson <wilson@cygnus.com>
+
+ * dwarf2out.c (scope_die_for): If could not find proper scope,
+ check for and handle tagged type with incorrect TYPE_CONTEXT.
+
+Wed Apr 29 15:34:40 1998 John Carr <jfc@mit.edu>
+
+ * calls.c (expand_call): Fix recognition of C++ operator new.
+
+ * alias.c (mode_alias_check): Disable type based alias detection.
+
+Wed Apr 29 15:06:42 1998 Gavin Koch <gavin@cygnus.com>
+
+ * config/mips/elf.h (ASM_OUTPUT_DEF,ASM_WEAKEN_LABEL,
+ ASM_OUTPUT_WEAK_ALIAS): Define.
+ * config/mips/elf64.h: Same.
+ * config/mips/r3900.h (ASM_OUTPUT_DEF,SUPPORTS_WEAK,
+ ASM_WEAKEN_LABEL): Removed.
+
+Wed Apr 29 10:53:29 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * calls.c (expand_call): Bump the length limit on the specially
+ recognized function names to 17.
+
+Tue Apr 28 17:53:33 1998 Jim Wilson <wilson@cygnus.com>
+
+ * ginclude/stddef.h: Add check for _MACHINE_ANSI_H_ for BSD/OS
+ when undefining macros at the end.
+
+ * expr.c (expand_builtin, case BUILT_IN_MEMSET): Break if either
+ val or len has TREE_SIDE_EFFECTS set.
+
+ * sparc.md (mulsidi3): Call const v8plus and v8plus routines.
+ (mulsidi3_v8plus, const_mulsidi3_v8plus): Delete asterisk from name.
+ (smuldi3_highpart): Call const v8plus routine.
+ (smulsi3_highpart_v8plus): Renamed from smulsidi3_highpart_v8plus.
+ (const_smulsi3_highpart_v8plus): New pattern.
+ (smulsi3_highpart_sp32): Renamed from smulsidi3_highpart_sp32.
+ (umulsidi3): Call const v8plus routine.
+ (umulsi3_highpart): Handle const before v8plus. Call const v8plus
+ routine.
+ (umulsi3_highpart_v8plus): Renamed from umulsidi3_highpart_v8plus.
+ (umulsi3_highpart_sp32): Renamed from umulsidi3_highpart_sp32.
+
+Tue Apr 28 08:55:26 1998 Michael Meissner <meissner@cygnus.com>
+
+ * m32r.c (*_oper{and|ator}): Change enum arguments and return
+ values to int, so they can be prototyped even in files that don't
+ include rtl.h.
+ ({small,large}_insn_p): Ditto.
+ (m32r_select_cc_mode): Ditto.
+ (gen_compare): Ditto.
+ (function_arg_partial_nregs): Ditto.
+ (m32r_setup_incoming_varargs): Ditto.
+ (init_reg_tables): Add prototype.
+ (m32r_frame_info): Add prolog_size field.
+ (m32r_compute_frame_size): Calculate the size of the prologue.
+ (m32r_first_insn_address): Return prologue size.
+ (m32r_output_function_prologue): Calculate frame size before
+ printing out information. Print out the prologue size.
+
+ * m32r.h: Prototype all functions in m32r.c.
+ (FIRST_INSN_ADDRESS): Declare, returning prologue size.
+
+ * m32r.md (bcc functions): Cast enum's to int.
+
+ * m32r.c (conditional_move_operand): Silence a debug message.
+ ({small,long}_insn): New predicates.
+
+ * m32r.h (TARGET_M32R): New macro.
+ (PREDICATE_CODES): Rearrange somewhat, add small_insn/long_insn.
+ (HAIFA_P): Define as 1/0 depending on whether the Haifa scheduler
+ was selected.
+ (ISSUE_RATE): Define as 2.
+
+ * m32r.md (insn_size): New attribute.
+ ({,rev_}branch_insn): Add .s qualifier to branches believed to be
+ short.
+ (m32r): New attribute.
+
+ * configure.in (enable_haifa): Switch m32r to Haifa by default.
+ * configure: Regenerate.
+
+ (Changes from Nick Clifton <nickc@cygnus.com>)
+ * m32r.h (EXTRA_CONSTRAINT): Implement 'S' constraint to perfoirm
+ the equivalent of a negated 'I' constraint.
+ (PRESERVE_DEATH_INFO_REGNO_P): Define in order to allow peephole
+ optimisation to work.
+
+ * m32r.md (cmp_ne_small_const_insn): Use 'S' constriant rather
+ than 'I' since the value is negated.
+ (peephole): Add peephole optimisation to cope with optimization of
+ divide and subtracts of the same operands.
+
+ * m32r.c zero_and_one, emit_cond_move): Add support for MVFC.
+ * m32r.h: Ditto.
+ * m32r.md: Ditto.
+
+ * m32r.h (PREDICATE_CODES): Add declaration of machine specific
+ predicates.
+
+Tue Apr 28 07:25:53 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * Makefile.in (libgcc2.ready): Revert last patch (Apr 24).
+
+Mon Apr 27 18:39:47 1998 Nick Clifton <nickc@cygnus.com>
+
+ * config/arm/thumb.h (GO_IF_LEGITIMATE_ADDRESS): Check against
+ frame_pointer_rtx not FRAME_POINTER_REGNUM.
+
+Mon Apr 27 18:36:28 1998 Jim Wilson <wilson@cygnus.com>
+
+ * reg-stack.c: Revert last patch (Apr 20).
+ (convert_regs): Set insn to PREV_INSN (next) after do while loop.
+
+ * m68k/lb1sf68.asm (Laddsf$3): Fix typos in mcf5200 exg code.
+
+ * loop.c (check_dbra_loop): New locals jump, first_compare, and
+ compare_and_branch. Call get_condition to set first_compare.
+ Set compare_and_branch to number of compare/branch instructions.
+ Replace PREV_INSN (PREV_INSN (loop_end)) with first_compare.
+ Replace '2' with compare_and_branch.
+
+Mon Apr 27 15:53:30 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
+
+ * cplus-dem.c (demangle_qualified): Replace missing else.
+
+Mon Apr 27 20:22:08 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.c (gen_ashift_hi): Don't make SUBREG of a SUBREG.
+
+Mon Apr 27 18:23:51 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.c (sh_expand_prologue, sh_expand_epilogue):
+ If TARGET_DOUBLE_ALIGN, preserve 64 bit stack alignment.
+ * sh.h (STACK_BOUNDARY): Likewise.
+
+Mon Apr 27 17:22:48 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.h (LEGITIMIZE_RELOAD_ADDRESS): Define.
+
+Mon Apr 27 08:55:23 1998 Michael Meissner <meissner@cygnus.com>
+
+ * system.h (abort): If abort is not defined, and neither is
+ USE_SYSTEM_ABORT, redefine abort to call fprintf and exit,
+ reporting the line and filename of the error.
+
+ * .gdbinit: Add breakpoints on exit and fancy_abort.
+
+ * final.c (split_double): Avoid a compiler warning if
+ BITS_PER_WORD is less than or equal to HOST_BIT_PER_WIDE_INT.
+
+ * rtl.h (JUMP_{CROSS_JUMP,NOOP_MOVES,AFTER_REGSCAN}): New macros
+ for calling jump_optimize.
+
+ * toplev.c (rest_of_compilation): Call jump_optimize using JUMP_*
+ macros, rather than 0/1's.
+
+Sun Apr 26 23:19:10 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.h (CONST_COSTS): Zero is always free.
+ (RTX_COSTS): Add EV6 costs. Abort if alpha_cpu is unknown.
+
+Sun Apr 26 15:38:50 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * cplus-dem.c (gnu_special): Fix off-by-one bug when checking the
+ length in the name of a virtual table.
+
+Sun Apr 26 01:21:06 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (print_operand): Don't add 'v' suffix for ALPHA_FPTM_N.
+
+Sat Apr 25 22:11:38 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sat Apr 25 17:17:15 1998 Jeffrey A Law (law@cygnus.com)
+
+ * fold-const.c (fold_convert): Fix typo.
+
+Sat Apr 25 17:55:54 1998 John Carr <jfc@mit.edu>
+
+ * alias.c (alias_invariant): New variable.
+ (record_base_value): New argument INVARIANT.
+ (memrefs_conflict_p): If a register has an entry in the alias_invariant
+ array, try substituting that value for the register.
+
+ * rtl.h: Declare record_base_value.
+
+ * loop.c, unroll.c: Update callers of record_base_value.
+
+ * alias.c (find_base_value, find_base_term): SIGN_EXTEND and
+ ZERO_EXTEND do not affect base values.
+
+Fri Apr 24 15:57:02 1998 Jeffrey A Law (law@cygnus.com)
+
+ * dbxout.c (dbxout_type): Fix typo.
+ (dbxout_range_type): Another HOST_WIDE_INT_PRINT_DEC fix.
+
+ * configure.in: Use CC_FOR_BUILD, not BUILD_CC.
+
+Fri Apr 24 16:11:47 1998 John Carr <jfc@mit.edu>
+
+ * expr.c (expand_builtin, case MEMSET): Set MEM_IN_STRUCT_P
+ if the argument is the address of a structure or array.
+
+ * configure.in: Enable Haifa scheduler by default for SPARC.
+
+Fri Apr 24 20:55:47 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * cse.c (cse_set_around_loop): Don't do optimization when
+ new pseudos are created.
+
+Fri Apr 24 11:00:18 1998 Jeffrey A Law (law@cygnus.com)
+
+ * dbxout.c (dbxout_type_fields): Use HOST_WIDE_INT_PRINT_DEC
+ appropriately.
+ (dbxout_type_method_1, dbxout_type): Likewise.
+ (print_int_cst_octal, print_octal, dbxout_symbol): Likewise.
+ (dbxout_type): Fix check for when to print a type range in
+ octal vs decimal.
+
+Fri Apr 24 16:45:03 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * (gen_shl_and, in case 1): Fix comparison with mask.
+
+Fri Apr 24 06:46:40 1998 Nick Clifton <nickc@cygnus.com>
+
+ * config/arm/thumb.h (GO_IF_LEGITIMATE_ADDRESS): Disallow frame
+ pointer as second register in REG+REG pair.
+
+Fri Apr 24 09:22:23 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * c-common.c (check_format_info): Don't check for the 'x' format
+ character twice, instead check for 'x' and 'X'
+
+Fri Apr 24 08:02:30 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * Makefile.in (libgcc2.ready): Add explicit dependancy from
+ $(STMP_FIXPROTO) to ensure all necessary include files have
+ been created and to guarantee proper parallel builds.
+
+Fri Apr 24 04:42:35 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.c (sh_expand_prologue, in !SH3E code): Don't push an extra
+ register for stdarg functions.
+ * sh.h (current_function_varargs): Declare.
+ (FUNCTION_ARG): Ignore NAMED for stdarg functions.
+
+1998-04-23 Jim Wilson <wilson@cygnus.com>
+
+ * frame.c, libgcc2.c (stdlib.h, unistd.h): Don't include when
+ inhibit_libc is defined.
+
+ * c-aux-info.c (gen_type): Use DECL_NAME only for TYPE_DECL.
+
+Thu Apr 23 19:09:33 1998 Jim Wilson <wilson@cygnus.com>
+
+ * profile.c (tablejump_entry_p): New function.
+ (branch_prob): Add code to recognize MIPS tablejump entry branch.
+ Use tablejump_entry_p in MIPS and HPPA tablejump checking code.
+
+Thu Apr 23 15:01:13 1998 Nick Clifton <nickc@cygnus.com>
+
+ * config/arm/arm.c (find_barrier): Return as soon as a barrier is
+ found, rather than at end of the loop, after the insn has been
+ changed.
+
+Thu Apr 23 20:21:06 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.c (gen_ashift_hi): Implement right shifts via gen_ashift.
+ * sh.md (ashrhi3_k, lshrhi3_k, lshrhi3_m, lshrhi3, lshrhi3+1): Delete.
+
+Wed Apr 22 17:07:35 1998 Michael Meissner <meissner@cygnus.com>
+
+ * loop.c (note_addr_stored): Correct function to take 2 arguments,
+ instead of 1.
+
+ * rtl.def (MATCH_INSN2): Add new matching pattern.
+ * genrecog.c (add_to_sequence): Support MATCH_INSN2.
+
+Wed Apr 22 15:52:22 1998 John Carr <jfc@mit.edu>
+
+ * emit-rtl.c (gen_highpart): The high part of a CONST_INT is not zero
+ if HOST_BITS_PER_WIDE_INT is larger than BITS_PER_WORD.
+
+ * final.c (split_double): Sign extend both halves of a split CONST_INT.
+
+Wed Apr 22 10:42:45 1998 Jeffrey A Law (law@cygnus.com)
+
+ * mips.c (compute_frame_size): Change only argument to a HOST_WIDE_INT.
+
+Wed Apr 22 10:53:49 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
+
+ * cplus-dem.c (struct work stuff): Add field for B and K mangle codes.
+ (cplus_demangle_opname): Call mop_up_squangle.
+ (cplus_demangle): Initialize squangle info, then call
+ internal_cplus_demangle. (Most code moved there as well)
+ (internal_cplus_demangle): New function, performs most of what use
+ to be done in cplus_demangle, but is only called with this file.
+ (squangle_mop_up): New function to clean up B and K code data.
+ (mop_up): set pointers to NULL after freeing.
+ (demangle_signature, demangle_template, demangle_class): Add
+ switch elements to handle K and B codes.
+ (demangle_prefix, gnu_special, demangle_qualified): Add
+ code to handle K and B codes.
+ (do_type, demangle_fund_type): Handle B and K codes.
+ (remember_Ktype): New function to store K info.
+ (register_Btype, remember_Btype): New functions for B codes.
+ (forget_B_and_K_types): New function to destroy B and K info.
+
+1998-04-21 Jim Wilson <wilson@cygnus.com>
+
+ * stmt.c (check_seenlabel): When search for line number note for
+ warning, handle case where there is no such note.
+
+Tue Apr 21 20:48:37 1998 John Carr <jfc@mit.edu>
+
+ * genemit.c (gen_exp): Allow machine description to set mode of
+ MATCH_OP_DUP.
+
+Tue Apr 21 16:36:01 1998 John Carr <jfc@mit.edu>
+
+ * alias.c (mode_alias_check): New function.
+ (true_dependence, anti_dependence, output_dependence): Call
+ mode_alias_check.
+
+Tue Apr 21 12:05:32 1998 Jeffrey A Law (law@cygnus.com)
+
+ * mips.h (STACK_BOUNDARY): Allow specific targets to override.
+ (MIPS_STACK_ALIGN): Similarly.
+
+ * c-common.c (type_for_mode): Handle TI types.
+ * c-decl.c (intTI_type_node, unsigned_int_TI_type_node): Define.
+ (init_decl_processing): Handle TI types.
+ * c-tree.h (intTI_type_node, unsigned_int_TI_type_node): Declare.
+
+ * mips.c (block_move_loop): Test Pmode == DImode instead of
+ TARGET_MIPS64.
+ (expand_block_move, save_restore_insns): Likewise.
+ (function_prologue, mips_expand_prologue): Likewise.
+ (mips_expand_epilogue): Likewise.
+ * mips.h (POINTER_SIZE): Allow specific targets to override.
+ (Pmode): Allow specific targets to override.
+ (FUNCTION_PROFILER): Test Pmode == DImode instead of TARGET_MIPS64
+ (POINTER_BOUNDARY, FUNCTION_MODE): Likewise.
+ (TRAMPOLINE_TEMPLATE, TRAMPOLINE_SIZE): Likewise.
+ (TRAMPOLINE_ALIGNMENT, INITIALIZE_TRAMPOLINE): Likewise.
+ (CASE_VECTOR_MODE, ASM_OUTPUT_ADDR_VEC_ELT): Likewise.
+ (ASM_OUTPUT_ADDR_DIFF_ELT, SIZE_TYPE, PTRDIFF_TYPE): Likewise.
+ * mips.md (indirect, tablejump & casesi support): Test for
+ Pmode == DImode instead of TARGET_MIPS64.
+ (call patterns): Likewise.
+
+Tue Apr 21 09:43:55 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * objc/sendmsg.c: Define gen_rtx_MEM() to 1, as is already done
+ for gen_rtx(MEM, ...).
+
+Tue Apr 21 02:15:36 1998 Richard Henderson <rth@cygnus.com>
+
+ * sparc.h (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Rewrite
+ to not be so gross, and to properly function with PIC.
+
+Mon Apr 20 20:44:25 1998 Jim Wilson <wilson@cygnus.com>
+
+ * frame.c (heapsort): Rename to frame_heapsort.
+
+ * gcc.c (do_spec_1, case '['): Move flag out of loop and initialize it.
+
+Mon Apr 20 12:43:09 1998 Doug Evans <devans@canuck.cygnus.com>
+
+ * flow.c (sbitmap_vector_alloc): Ensure sbitmaps properly aligned.
+
+Mon Apr 20 15:04:14 1998 John Wehle (john@feith.com)
+
+ * i386.md (movsf_push, movdf_push, movxf_push): Allow memory
+ operands during and after reload.
+
+Mon Apr 20 22:37:50 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * final.c (shorten_branches, init_insn_lengths): Move code
+ to free label_align, uid_shuid, insn_lengths, insn_addresses
+ and uid_align from the former function into the latter one;
+ Add code to clear these variables.
+ * sh.h (label_align): Remove declaration.
+
+Mon Apr 20 14:48:29 1998 Michael Meissner <meissner@cygnus.com>
+
+ * gcc.c (lang_specific_driver): Declare prototype properly so
+ fatal can be passed to it without error.
+
+ * configure.in (AC_CHECK_FUNCS): Check for strchr and strrchr.
+ * configure: Regenerate.
+ * config.in: Add #undef's for strchr and strrchr.
+
+ * protoize.c (toplevel): If we have rindex, but not strrchr, map
+ rindex to strrchr.
+ (file_could_be_converted): Use strrchr, not rindex since rindex is
+ not defined on Linux systems when _POSIX_SOURCE is defined.
+ (file_normally_convertible): Ditto.
+ (process_aux_info_file): Ditto.
+ (main): Ditto.
+
+ * rs6000.md (mov{sf,df} define_splits): When splitting a move of
+ a constant to an integer register, don't split the insns that do
+ the simple AND and OR operations, rather just split each word, and
+ let the normal movsi define split handle it further.
+
+Mon Apr 20 18:19:40 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.c (find_barrier): Fix bug in ADDR_DIFF_VEC handling.
+ (split_branches): Call init_insn_lengths.
+
+Mon Apr 20 07:37:49 1998 Michael Meissner <meissner@cygnus.com>
+
+ * i386.c: Include expr.h to get the change_address prototype
+ declared.
+
+Mon Apr 20 01:00:05 1998 H.J. Lu (hjl@gnu.org)
+
+ * reg-stack.c (subst_asm_stack_regs): Change to return the last
+ new insn generated by this function.
+ (subst_stack_regs): Likewise.
+ (convert_regs): Record the last newly generated insn and use
+ it for change_stack () instead of INSN.
+
+Sun Apr 19 15:41:24 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * fix-header.c (enum special_file): Undefine enumerators if they
+ are already defined by include files.
+ * fixproto (rel_source_file in unistd.h stdlib.h): Prefix file protection
+ macro with '__' to not pollute user namespace.
+
+Sun Apr 19 02:42:06 1998 Richard Henderson <rth@cygnus.com>
+
+ * haifa-sched.c (queue_to_ready): Fix typo in prototype.
+
+Sat Apr 18 23:52:35 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sat Apr 18 18:30:22 1998 Jim Wilson <wilson@cygnus.com>
+
+ * i386.md (fix_truncsfdi2+[123]): Add + to operand 1 constraints.
+
+ * i386.h (CPP_CPU_DEFAULT): Renamed to CPP_CPU_DEFAULT_SPEC.
+ Add missing -Dpentium* options.
+ (CPP_CPU_SPEC): Delete redundant definition. Include cpp_cpu_default
+ instead of CPP_CPU_DEFAULT.
+ (EXTRA_SPECS): Add entry for cpp_cpu_default.
+
+Sat Apr 18 19:06:59 1998 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * rs6000.md (floatsidf2_loadaddr): rs6000_fpmem_offset will be
+ negative in a stackless frame.
+ * rs6000.c (rs6000_stack_info): Don't include fixed-size link area
+ in stackless frame size. Support 64-bit stackless frame size.
+ Combine fpmem offset calculations and don't add total_size to
+ offset if not pushing a stack frame.
+
+Sat Apr 18 15:41:16 1998 Jim Wilson <wilson@cygnus.com>
+
+ * regmove.c (fixup_match_1): In three places, in flag_exceptions
+ check, change p to q.
+
+Sat Apr 18 15:30:49 1998 Jim Wilson <wilson@cygnus.com>
+
+ * gcc.c (lang_specific_driver): Add new parm type to prototype.
+ (added_libraries): New file scope static variable.
+ (process_command): Initialize added_libraries. Pass it to
+ lang_specific_driver.
+ (main): Use added_libraries in check for no input files.
+
+Sat Apr 18 01:23:11 1998 John Carr <jfc@mit.edu>
+
+ * sparc.c, sparc.h, sparc.md, sol2.h: Many changes related to V9
+ code generation. Use 64 bit instructions in 32 bit mode when
+ possible. Use V9 return instruction. UltraSPARC optimizations.
+
+ * sparc.h: Change gen_rtx (CODE to gen_rtx_CODE (.
+
+Fri Apr 17 22:38:17 1998 Jeffrey A Law (law@cygnus.com)
+
+ * global.c (global_alloc): Don't pass HARD_CONST (0) to find_reg,
+ just pass zero. That will work regardless of the size of HARD_REG_SET.
+
+ * libgcc2.c (__floatdisf): Fix a couple typos.
+
+Fri Apr 17 17:28:26 1998 Jim Wilson <wilson@cygnus.com>
+
+ * Makefile.in (mostlyclean): Delete *.mach and *.bp files.
+
+Fri Apr 17 16:35:35 1998 Greg McGary <gkm@gnu.org>
+
+ * emit-rtl.c (gen_highpart): initialize `word' properly for pseudo.
+
+Fri Apr 17 14:30:37 1998 John Carr <jfc@mit.edu>
+
+ * emit-rtl.c (operand_subword_force): If a register can not be
+ accessed by words, copy it to a pseudo register.
+
+Fri Apr 17 14:30:37 1998 Jim Wilson <wilson@cygnus.com>
+
+ * rs6000/vxppc.h (CPP_SPEC): Add support for mrelocatable*.
+
+Fri Apr 17 17:01:25 1998 Michael Meissner <meissner@cygnus.com>
+
+ * tree.h (mark_seen_cases): Delete declaration.
+
+Fri Apr 17 13:32:20 1998 Jeffrey A Law (law@cygnus.com)
+
+ * stmt.c (mark_seen_cases): Make static and add prototype.
+
+Fri Apr 17 11:21:43 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * frame.c: Include stdlib.h and unistd.h to possibly get various
+ function prototypes. The fixproto script guarantees these header
+ files exist on the target system.
+ * libgcc2.c: Likewise.
+
+ * gthr-single.h (__gthread_mutex_lock, __gthread_mutex_trylock,
+ __gthread_mutex_unlock): Add __attribute__ ((__unused__)) to the
+ function parameters.
+ * libgcc2.c (__udiv_w_sdiv): Likewise.
+
+Thu Apr 16 22:41:02 1998 Jeffrey A Law (law@cygnus.com)
+
+ * varasm.c (asm_output_bss): Add prototype.
+ (asm_output_aligned_bss): Likewise.
+
+ * unroll.c (verify_addresses): Add prototype.
+
+ * toplev.c: Add many prototypes. Too many to mention here.
+
+ * stmt.c (check_seenlabel): Add prototype.
+
+ * rtlanal.c (reg_set_p_1): Add prototype.
+ (reg_set_last_1): Likewise.
+
+ * reorg.c (find_dead_or_set_registers): Add prototype.
+
+ * regmove (try_auto_increment): Add prototype.
+
+ * reg-stack.c (pop_stack): Add prototype.
+
+ * recog.c (validate_replace_rtx_1): Add prototype.
+ (find_cosntant_term_loc): Likewise.
+
+ * loop.c (regs_patch_p): Add prototype.
+ (add_label_notes, count_nonfixed_reads): Likewise.
+ (find_single_use_in_loop): Likewise.
+ (express_from): Surround prototype with #ifdef.
+ (giv_sort): Similarly.
+
+ * jump.c (mark_modified_reg): Add prototype.
+
+ * haifa-sched.c (is_prisky): Add prototype.
+ (queue_to_ready): Likewise.
+
+ * genextract.c (gen_insn): Add prototype.
+
+ * genemit.c (max_operand_1): Add prototype.
+ (max_operand_vec, print_code, gen_exp, gen_insn): Likewise.
+ (gen_expand, gen_explit, output_add_clobbers): Likewise.
+ (output_init_mov_optab): Likewise.
+
+ * genattrtab.c (attr_hash_add_rtx): Add prototype.
+ (attr_hash_add_string, write_length_unit_log): Likewise.
+
+ * genattr.c (init_range): Add prototype.
+
+ * combine.c (sets_function_arg_p): Add prototype.
+
+ * expr.c (store_constructor_field): Add prototype.
+ (get_memory_usage_from_modifier): Likewise
+
+ * expmed.c (synth_mult): Add prototype.
+ (choose_multiplier, invert_mod2n): Likewise.
+
+ * except.c (push_eh_entry): Add prototype.
+ (pop_eh_entry, enqueue_eh_entry, dequeu_eh_entry): Likewise.
+ (call_get_eh_context, start_dynamic_cleanup): Likewise.
+ (start_dynamic_handler, can_throw): Likewise.
+ (output_exception_table_entry, scan_region): Likewise.
+ (eh_regs, set_insn_eh_region): Likewise.
+
+ * dwarfout.c (decl_class_context): Add prototype.
+ (output_inheritance_die, type_ok_for_scope): Likewise.
+
+ * c-lex.c (skip_white_space_on_line): Add prototype.
+
+ * alias.c (record_set): Add prototype.
+ (find_base_term, base_alias_check): Likewise.
+
+ * function.c (assign_outer_stack_local): Make static and add prototype.
+
+ * haifa-sched.c (build_control_flow): Accept raw data as inputs
+ instead of computing it locally. Callers changed.
+ (find_rgns): Several new arguments. Callers changed.
+ Generally clean up and comment better. Use dominators to
+ identify reducible loops. Convert some flag arrays to bitmaps.
+ Convert most of the code to work on pred/succ lists instead of
+ an edge table. Add comments for future improvements.
+ (schedule_insns): Allocate temporary tables for flow data, call
+ routines to compute flow data and pass it along to children as
+ arguments.
+ (debug_control_flow): Delete. Use dump_bb_data instead.
+
+ * basic-block.h (compute_dominators): Declare.
+
+ * flow.c (dump_sbitmap, dump_sbitmap_vector): New debugging
+ functions.
+ * basic-block.h: Declare them.
+
+Thu Apr 16 13:45:51 1998 Jim Wilson <wilson@cygnus.com>
+
+ * reg-stack.c (constrain_asm_operands): Set n_alternatives to zero if
+ no operands.
+
+Wed Apr 15 11:33:09 1998 Alexandre Petit-Bianco <apbianco@sendai.cygnus.com>
+
+ * tree.c (build_expr_wfl): Use NULL_TREE if the file name is NULL.
+ Propagate TREE_SIDE_EFFECTS and TREE_TYPE iff the encapsulated
+ node is non NULL. Cache last file name and file name identifier node.
+
+1998-04-15 Mark Mitchell <mmitchell@usa.net>
+
+ * c-common.c (declare_hidden_char_array): Use TYPE_DOMAIN to get
+ the length of an array, not TREE_TYPE.
+
+Wed Apr 15 15:31:34 1998 Jeffrey A Law (law@cygnus.com)
+
+ * flow.c (sbitmap_union_of_successors): New function.
+ * basic-block.h (sbitmap_union_of_successors): Declare it.
+
+Wed Apr 15 12:38:03 1998 Jim Wilson <wilson@cygnus.com>
+
+ * configure.in (gnu_ld): Rename to gnu_ld_flag before main loop.
+ Set gnu_ld to gnu_ld_flag inside main loop.
+ (gas): Likewise.
+
+Wed Apr 15 14:50:05 1998 Dave Brolley <brolley@cygnus.com>
+
+ * toplev.c (compile_file): Call init_parse using new interface.
+ (init_lex): Remove declaration.
+
+ * c-lex.c (init_parse): Now returns char* containing filename.
+
+Wed Apr 15 12:37:10 1998 Jeffrey A Law (law@cygnus.com)
+
+ * pa.h (LEGITIMIZE_RELOAD_ADDRESS): Do nothing if not optimizing.
+
+Wed Apr 15 12:10:18 1998 Michael Meissner <meissner@cygnus.com>
+
+ * Makefile.in (gen{config,flags,codes,emit}): Link in host print-rtl.o.
+ (gen{extract,peep,opinit,output}): Ditto.
+
+ * gen{attr,codes,config,emit,output}.c (insn_attr_name): Provide a
+ global definition so print-rtl.o can be linked in.
+ * gen{peep,recog}.c (insn_attr_name): Ditto.
+
+Tue Apr 14 07:30:57 1998 K. Richard Pixley <rich@kyoto.noir.com>
+
+ * fixincludes: discard empty C++ comments, as found in sys/time.h
+ on hpux-11.0.
+
+Wed Apr 15 10:47:21 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * config/m68k/m68k.md (adddi3, subdi3): Optimize for constant
+ operand.
+
+Wed Apr 15 01:21:21 1998 Jeffrey A Law (law@cygnus.com)
+
+ * emit-rtl.c (operand_subword): Rework slightly to avoid
+ bogus warning from previous change.
+
+Tue Apr 14 23:39:13 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.md: Revert Oct 27 change, as it is superceeded by Kenner's
+ Nov 8 find_replacement change. Move decls of get_unaligned_address
+ * alpha.h: ... here.
+
+Tue Apr 14 22:00:39 1998 John Carr <jfc@mit.edu>
+
+ * function.c (assign_parms): Initialize unsignedp before passing
+ its pointer to promote_mode.
+
+ * genattrtab.c (check_attr_test): Handle MATCH_INSN like MATCH_OPERAND.
+ (write_test_expr): Allow MATCH_INSN.
+
+Tue Apr 14 21:57:57 1998 Paul Eggert <eggert@twinsun.com>
+
+ * install.texi: Update section on warnings that can be safely ignored.
+
+Tue Apr 14 14:55:16 1998 Jim Wilson <wilson@cygnus.com>
+
+ * mips.md (reload_outdi): Change the scratch mode from DImode to
+ TImode. New variable scratch, used instead of operand[2] in template.
+ Add code for MIPS16 HILO_REGNUM case where output reg is not M16_REG_P.
+
+Tue Apr 14 16:19:03 1998 Michael Meissner <meissner@cygnus.com>
+
+ * expr.c (MOVE_RATIO): Set to 3 if optimizing for space.
+
+Tue Apr 14 11:31:28 1998 Krister Walfridsson <cato@df.lth.se>
+
+ * i386/bsd386.h (ASM_OUTPUT_ALIGN): Redefine.
+
+Tue Apr 14 09:02:32 1998 Jeffrey A Law (law@cygnus.com)
+
+ * svr4.h (ASM_DECLARE_OBJECT_NAME): Use HOST_WIDE_INT_PRINT_DEC.
+ (ASM_FINISH_DECLARE_OBJECT): Likewise.
+
+ * Idea and part of the patch from HJ.
+ * Makefile.in: auto-host.h renamed from auto-config.h. All references
+ changed.
+ (distclean): Remove auto-build.h too.
+ * configure.in: Rename host autoconf generated file to auto-host.h.
+ If host != build, then run autoconf to generate auto-build.h for
+ the build machine and include it in build_xm_files.
+ Check for wait.h and sys/wait.h.
+
+ * combine.c (simplify_rtx, case TRUNCATE): Respect value of
+ TRULY_NOOP_TRUNCATION.
+
+Mon Apr 13 11:31:49 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * tree.h (BINFO_OFFSET_ZEROP): Use integer_zerop.
+
+Sun Apr 12 20:55:32 1998 Catherine Moore <clm@cygnus.com>
+
+ * invoke.texi (ld options) Include memset requirements
+ for options -nodstdlib and -nodefaultlibs.
+
+1998-04-12 Paul Eggert <eggert@twinsun.com>
+
+ This change is from an idea suggested by Arthur David Olson.
+
+ * c-common.c (decl_attributes, record_function_format,
+ check_format_info, init_function_format_info):
+ Add support for strftime format checking.
+ (enum format_type): New type.
+ (record_function_format): Now static, and takes value of type
+ enum format_type instead of int.
+ (time_char_table): New constant.
+ (struct function_format_info): format_type member renamed from is_scan.
+ (check_format_info): Use `warning' rather than sprintf followed by
+ `warning', to avoid mishandling `%' in warnings.
+ Change `pedwarn' to `warning', since these warnings do not necessarily
+ mean the program does not conform to the C Standard, as the code
+ need not be executed.
+
+ * c-tree.h (record_function_format): Remove decl; no longer extern.
+
+ * extend.texi: Add documentation for strftime format checking.
+
+Sun Apr 12 20:23:03 1998 Jeffrey A Law (law@cygnus.com)
+
+ * mips/ecoffl.h: Do not include mips.h.
+ * mips/elf.h: Likewise.
+
+ * configure.in (mips-*-ecoff): Do not mention mips/mips.h in tm_files.
+ * mips/ecoff.h: Include "mips/mips.h".
+
+Sat Apr 11 22:42:54 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sat Apr 11 01:24:28 1998 Jeffrey A Law (law@cygnus.com)
+
+ * cse.c (count_reg_usage): Correctly handle REG_NONNEG notes.
+ (delete_trivially_dead_insns): Renamed from delete_dead_from_cse.
+ * toplev.c (rest_of_compilation): Call delete_trivially_dead_insns instead of delete_dead_from_cse. Also call delete_trivially_dead_insns
+ between loop optimization passes.
+ * rtl.h: Updated appropriately.
+
+Fri Apr 10 22:28:32 1998 Jeffrey A Law (law@cygnus.com)
+
+ Reinstall this patch from Jason.
+ * function.c (push_function_context_to): Don't call init_emit.
+
+Fri Apr 10 13:40:20 1998 Nick Clifton <nickc@cygnus.com>
+
+ * rtl.c (read_skip_spaces): Prevent infinite loops upon
+ encountering unterminated comments.
+
+Fri Apr 10 10:43:41 1998 Jeffrey A Law (law@cygnus.com)
+
+ * emit-rtl.c (operand_subword): Properly handle CONST_INTs for
+ 64x32 cross builds.
+
+ * configure.in: Handle --with-fast-fixincludes.
+ (fixincludes): If --with-fast-fixincludes, then use a different
+ fixincludes program by default.
+ * Makefile.in (fixinc.sh): New rule.
+
+Fri Apr 10 00:36:31 1998 H.J. Lu (hjl@gnu.org)
+
+ * i386.md (movqi+1): Handle invalid QI register.
+ (movsf_push-1): Likewise.
+
+Thu Apr 9 16:53:59 1998 Nick Clifton <nickc@cygnus.com>
+
+ * config/m32r/m32r.c: call_address_operand(): Only accept symbolic
+ addresses.
+ symbolic_memort_operand(), call32_operand(), int8_operand(),
+ int16_operand(), uint24_operand(), reg_or_int8_operand(): Removed.
+ Not used.
+ uint16_operand(): Made static.
+
+Thu Apr 9 01:43:04 1998 Jeffrey A Law (law@cygnus.com)
+
+ * calls.c (expand_call): Fix typo.
+
+Thu Apr 9 00:18:44 1998 Dave Brolley (brolley@cygnus.com)
+
+ * c-lex.c (finput): New global.
+ (init_parse): Always included. Handle !USE_CPPLIB using
+ code originally in compile_file.
+ (finish_parse): Update for CPPLIB.
+ * toplev.c (init_parse, finish_parse): Declare.
+ (finput): Delete variable. Now in front-ends.
+ (compile_file): Remove code which is now handled by init_parse
+ which is unconditionally called. Similarly for finish_parse.
+
+Wed Apr 8 23:13:50 1998 Gavin Koch <gavin@cygnus.com>
+
+ * config/mips/r3900.h (ASM_OUTPUT_DEF,SUPPORTS_WEAK,
+ ASM_WEAKEN_LABEL): Add.
+
+Wed Apr 8 18:21:30 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha/crtbegin.asm, alpha/crtend.asm, alpha/t-crtb: New files.
+ * configure.in (alpha-*-linux*): Use them.
+
+Fri Apr 3 17:02:13 1998 Alexandre Petit-Bianco <apbianco@cygnus.com>
+
+ * tree.def (EXPR_WITH_FILE_LOCATION): New tree node definition.
+ * tree.h (EXPR_WFL_{NODE,FILENAME,FILENAME_NODE,LINENO,
+ COLNO,LINECOL,SET_LINECOL,EMIT_LINE_NOTE}): New macros.
+ (build_expr_wfl): New prototype declaration.
+ * tree.c (build_expr_wfl): New function, to build
+ EXPR_WITH_FILE_LOCATION nodes.
+ (copy_node): Don't zero TREE_CHAIN if copying a
+ EXPR_WITH_FILE_LOCATION node.
+ * print-tree.c (print_node): Handle EXPR_WITH_FILE_LOCATION.
+ * expr.c (expand_expr): Handle EXPR_WITH_FILE_LOCATION.
+
+Wed Apr 8 12:51:19 1998 Jeffrey A Law (law@cygnus.com)
+
+ * configure.in (v850): Use t-v850.
+ (ix86-wrs-vxworks): Recognize 786 just like other x86 configurations.
+
+ * protoize.c (creat, read, write): Do not declare.
+
+ * jump.c (mark_jump_label): Record REG_LABEL notes for insns which
+ refer to the CODE_LABEL before a dispatch table.
+
+ * invoke.texi: Add ARC options.
+
+ * gcc.c (proces_command): Improve error message for -o with
+ either -c or -S.
+
+ * i386/x-cygwin32 (CLIB): Link in advapi32.
+
+ * alpha.h (ASM_IDENTIFY_GCC): Define to nothing.
+ (ASM_IDENTIFY_LANGUAGE): Likewise.
+
+ * i386.md (movqi recognizer): Don't perfom byte increment into
+ a NON_QI_REG_P.
+
+ * configure.in (x86-dg-dgux): Run fixinc.dgux.
+
+ * i370.h: Fix typo in GEN_INT changes.
+
+ * bitmap.c (bitmap_element_allocate): Use "void" for arglist instead
+ of an empty arglist in prototype.
+
+ * Makefile.in: Remove bytecode crud that crept back in after the
+ gcc2 merge.
+
+1998-04-08 Brendan Kehoe <brendan@cygnus.com>
+
+ * c-lex.h (is_class_name): Fix arg type to be tree, not void.
+ (make_pointer_declarator, reinit_parse_for_function): Fix typo.
+
+Wed Apr 8 06:16:45 1998 Richard Earnshaw (rearnsha@arm.com)
+
+ * arm.h (LEGITIMIZE_RELOAD_ADDRESS): Define.
+
+Wed Apr 8 00:44:18 1998 Bernd Schmidt (crux@pool.informatik.rwth-aachen.de>
+
+ * c-lex.c (is_class_name): Delete declaration.
+ (whitespace_cr): Make static and add prototype.
+ * c-lex.h (make_pointer_declarator, reinit_parse_for_function,
+ yylex, get_directive_line): Turn declarations into prototypes.
+ (position_after_whitespace, check_newline, yyerror,, is_class_name,
+ forget_protocol_qualifiers, remember_protocol_qualifiers): Add
+ prototypes.
+ * genattr.c (extend_range, write_upcase, gen_attr, write_units): Add
+ prototypes.
+ * gencodes.c (gen_insn): Add prototype.
+ * genconfig.c (walk_insn, gen_insn, gen_expand, gen_split,
+ gen_peephole): Add prototypes.
+ * genflags.c (num_operands, gen_proto, gen_nonproto, gen_insn): Add
+ prototypes.
+ * gengenrtl.c (type_from_format, accessor_from_format, special_rtx,
+ special_format, find_formats, gendecl, genmacro, gendef, genlegend,
+ genheader, gencode): Add prototypes.
+ * genopinit.c (gen_insn): Add prototype.
+ * genoutput.c (output_prologue, output_epilogue, scan_operands,
+ process_template, validate_insn_alternatives, gen_insn, gen_peephole,
+ gen_expand, gen_split, n_occurrences): Add prototypes.
+ * genpeep.c (gen_peephole): Add prototype.
+ * loop.c (find_and_verify_loops, mark_loop_jump, prescan_loop,
+ reg_in_basic_block_p, consec_sets_invariant_p, libcall_other_reg,
+ labels_in_range_p, count_loop_regs_set, note_addr_stored,
+ loop_reg_used_before_p, scan_loop, replace_call_address,
+ skip_consec_insns, libcall_benefit, ignore_some_movables,
+ force_movables, combine_movables, rtx_equal_for_loop_p, move_movables,
+ strength_reduce, valid_initial_value_p, find_mem_givs, record_biv,
+ check_final_value, record_giv, update_giv_derive, basic_induction_var,
+ simplify_giv_expr, general_induction_var, consec_sets_giv,
+ check_dbra_loop, express_from, combine_givs_p, combine_givs,
+ product_cheap_p, maybe_eliminate_biv, maybe_eliminate_biv_1,
+ last_use_this_basic_block, record_initial, update_reg_last_use,
+ iteration_info, analyze_loop_iterations, insert_bct,
+ instrument_loop_bct, indirect_jump_in_function_p): Turn declarations
+ into prototypes.
+
+Tue Apr 7 21:48:52 1998 Jeffrey A Law (law@cygnus.com)
+
+ * pa.h (LEGITIMIZE_RELOAD_ADDRESS): Define.
+
+1998-04-07 Ken Raeburn <raeburn@cygnus.com>
+
+ * config/mips/mips.c (siginfo): Deleted.
+ (override_options): Don't install SIGINFO signal handler.
+
+Tue Apr 7 11:58:04 1998 Jim Wilson <wilson@cygnus.com>
+
+ * loop.c (check_dbra_loop): When normalize comparison_val, add check
+ to verify it is non-negative.
+
+Tue Apr 7 02:01:47 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_expand_block_move): Correctly collect block offsets.
+ (alpha_expand_block_clear): Likewise.
+
+Mon Apr 6 23:36:01 1998 Richard Henderson <rth@cygnus.com>
+
+ * tree.h (sizetype_tab): Fix previous change for K&R.
+
+Mon Apr 6 22:23:29 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Mon Apr 6 23:16:10 1998 Richard Earnshaw (rearnsha@arm.com)
+
+ * configure.in (sparc-*-solaris2*): Add xm-siglist.h to xm_file.
+ Add USG and POSIX to xm_defines.
+
+Mon Apr 6 21:49:57 1998 Bob Manson <manson@charmed.cygnus.com>
+
+ * gcc.c: Add linker spec.
+ (link_command_spec): Use %(linker) instead of ld.
+ (main): If collect2 is requested as the linker, see if it exists;
+ if not, use ld instead.
+
+ * Makefile.in (USE_COLLECT2): It's named collect2 now, not ld.
+ (ld:) Deleted.
+ (install-collect2): Install as collect2, not ld.
+
+ * configure.in(will_use_collect2): It's named collect2 now.
+
+ * collect2: Remove checks to see if we were invoked recursively.
+ (collect_execute): Use _spawnvp under cygwin32.
+
+Mon Apr 6 17:23:41 1998 Jim Wilson <wilson@cygnus.com>
+
+ * haifa-sched.c (build_control_flow): Set unreachable for block whose
+ only predecessor is itself.
+
+Mon Apr 6 16:08:04 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * c-parse.in: Include system.h, and remove stuff now made redundant.
+ * cccp.c: Likewise.
+ * cexp.y: Likewise.
+ * protoize.c: Likewise. Properly check for cpp stringification.
+
+ * Makefile.in (c-parse.o, cccp.o, cexp.o, protoize.o, unprotoize.o):
+ Depend on system.h.
+
+ * objc/Make-lang.in (objc-parse.o): Likewise.
+
+Mon Apr 6 14:59:58 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * gansidecl.h: Check if compiler supports __attribute__. Provide
+ definitions for ATTRIBUTE_UNUSED and ATTRIBUTE_PRINTF using
+ __attribute__ when its available. Also provide definitions for
+ ATTRIBUTE_PRINTF_1, ATTRIBUTE_PRINTF_2 and ATTRIBUTE_PRINTF_3 in
+ terms of ATTRIBUTE_PRINTF.
+
+ * genoutput.c (process_template): Use ATTRIBUTE_UNUSED in place
+ of __attribute__.
+
+Mon Apr 6 07:17:52 1998 Catherine Moore <clm@cygnus.com>
+
+ * combine.c (can_combine_p): Include successor in volatile test.
+
+Mon Apr 6 14:16:33 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.h (CASE_VECTOR_SHORTEN_MODE): Fix logic when to set
+ offset_unsigned.
+
+Mon Apr 6 02:03:29 1998 Jeffrey A Law (law@cygnus.com)
+
+ * objc/objc-act.c (encode_aggregate_within): Avoid GNU extensions
+ in prototype and definition.
+
+Mon Apr 6 00:48:56 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Mon Apr 6 00:08:50 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_expand_block_clear): Add missing offset arg to
+ alpha_expand_unaligned_store_words.
+
+Sun Apr 5 21:31:24 1998 John Wehle (john@feith.com)
+
+ * i386.md (movsf_push, movsf_mem): Remove.
+ (movsf_push): Rename from movsf_push_nomove and move in front of
+ movsf. Use nonmemory_operand predicate and don't bother checking
+ TARGET_MOVE.
+ (movsf_push_memory): New pattern.
+ (movsf): Don't bother checking for push_operand. If TARGET_MOVE and
+ both operands refer to memory then force operand[1] into a register.
+ (movsf_normal): Change to unnamed pattern.
+ Likewise for movdf, movxf, and friends.
+
+Sun Apr 5 18:45:51 PDT 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sun Apr 5 16:31:10 1998 Richard Henderson <rth@cygnus.com>
+
+ * configure.in (alpha-dec-osf*): Match osf1.3 correctly.
+
+Sun Apr 5 16:53:37 1998 Don Bowman <don@pixsci.com>
+
+ * configure.in (mips-wrs-vxworks): New target.
+
+Sat Apr 4 23:34:32 PST 1998 Jeff Law (law@cygnus.com)
+
+ * expmed.c (synth_mult): The value -1, has no zeros, so it can
+ never have the form ...011.
+
+ * version.c: Bump for snapshot.
+
+Sat Apr 4 20:16:46 1998 Richard Henderson <rth@cygnus.com>
+
+ * i386.c (asm_output_function_prefix, load_pic_register):
+ Use ASM_GENERATE_INTERNAL_LABEL properly.
+ (output_pic_addr_const): Recognize %X to supress any PIC sym suffix.
+ (print_operand): Ignore it.
+ (load_pic_register): Use it for the got load call.
+ * i386.md (prologue_set_got, prologue_get_pc): Likewise.
+ (prologue_get_pc_and_set_got): Likewise.
+ * i386.h: Update print_operand docs.
+
+Sat Apr 4 19:08:37 1998 Richard Henderson <rth@cygnus.com>
+
+ * i386.md (ffssi, ffshi): Rewrite as define_expands.
+ (ffssi_1, ffshi_1): New (unspec [] 5) support patterns.
+ * i386.c (notice_update_cc): Recognize unspec 5.
+
+Sat Apr 4 18:07:16 1998 David Mosberger-Tang (davidm@mostang.com)
+
+ * alpha.h (PRINT_OPERAND_PUNCT_VALID_P): Accept '(' for s/sv/svi.
+ * alpha.c (print_operand): Handle it.
+ * alpha.md (fix_truncsfdi2): Use it. Add earlyclobber pattern
+ for ALPHA_TP_INSN.
+ (fix_truncdfdi2): Likewise.
+
+Sat Apr 4 17:42:05 1998 Richard Henderson <rth@cygnus.com>
+
+ * tree.h (sizetype_tab[2], sbitsizetype, ubitsizetype): Merge all
+ of these into a single struct, with additional [us]sizetype entries.
+ * stor-layout.c (set_sizetype): Initialize [us]sizetype.
+ * fold-const.c (size_int_wide): Don't rely on sizetype_tab being
+ an array.
+
+Sat Apr 4 17:04:41 1998 Richard Henderson <rth@cygnus.com>
+
+ * configure.in (alpha-*-linux-*): Undo tm_file changes from gcc2 merge.
+
+Sat Apr 4 13:50:01 1998 Richard Henderson <rth@cygnus.com>
+
+ * haifa-sched.c (split_block_insns): Don't supress insn splitting
+ on subsequent passes.
+
+ * alpha.c (hard_fp_register_operand): New function.
+ * alpha.h (PREDICATE_CODES): Add it.
+ * alpha.md (extendsidi2): Kill bogus f<-f cvtql+cvtlq case. Add an
+ f<-m case and accompanying define_split.
+ (trapb): Use a unique unspec_volatile number.
+
+Sat Apr 4 13:32:08 1998 Richard Henderson <rth@cygnus.com>
+
+ * configure.in (alpha-*-linux-gnu*): Undo Feb 3 change brought in
+ from gcc2 merge.
+
+Sat Apr 4 10:23:41 1998 Jeffrey A Law (law@cygnus.com)
+
+ * Check in merge from gcc2. See ChangeLog.11 and ChangeLog.12
+ for details.
+
+ * haifa-sched.c: Mirror recent changes from gcc2.
+
+Fri Apr 3 00:17:01 1998 Jeffrey A Law (law@cygnus.com)
+
+ * Makefile.in (insn*.o): Depend on system.h.
+
+ * pa.c (output_global_address): Initialize base.
+ * pa.h (GO_IF_LEGITIMATE_ADDRESS): Initialize index.
+
+1998-04-03 Mike Stump <mrs@wrs.com>
+
+ * gthr.h: Support systems that don't have weak, but have threads.
+ * configure.in (*wrs-vxworks*): Use VxWorks threads by default.
+ * gthr-vxworks.h: New file.
+ * objc/thr-vxworks.h: Dummy file from thr-single.c for now.
+
+Thu Apr 2 18:00:52 1998 Jim Wilson <wilson@cygnus.com>
+
+ * i386.md (movqi+1): Change alternative 1 from *r/r to *r/*rn.
+
+1998-04-02 Vladimir N. Makarov <vmakarov@cygnus.com>
+
+ * ginclude/va-i960.h (va_end): Change void * to void.
+
+Thu Apr 2 13:51:10 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (choose-temp.o): Depend on system.h.
+
+ * choose-temp.c: Include system.h when IN_GCC.
+
+Thu Apr 2 02:37:07 1998 Joern Rennecke (amylaar@cygnus.co.uk)
+ Richard Henderson <rth@cygnus.com>
+
+ * reload.c (find_reloads_address): Try LEGITIMIZE_RELOAD_ADDRESS.
+ (move_replacements): New function.
+ * reload.h: Prototype it.
+
+ * alpha.h (LEGITIMIZE_RELOAD_ADDRESS): New definition.
+
+Thu Apr 2 01:01:34 1998 Richard Henderson <rth@cygnus.com>
+
+ * configure (alpha-*-linuxecoff, alpha-*-linux-gnulibc1):
+ Run fixincludes.
+
+ * emit-rtl.c (gen_lowpart_common): Skip count by HARD_REGNO_NREGS.
+ (gen_highpart): Likewise.
+ * final.c (alter_subreg): Allow the target to hook by-mode subreg
+ hard register number changes.
+
+Wed Apr 1 22:26:22 1998 Jeffrey A Law (law@cygnus.com)
+
+ * fold-const.c optimze_bit_field_compare): Initialize rnbitpos,
+ rnbitsize, rnmode and rinner.
+ (make_range): Initialize type.
+ (fold): Initialize arg0, arg1 and varop.
+
+ * function.c (instantiate_virtual_regs_1): Initialize offset, regnoi
+ and regnor.
+ (expand_function_start): Initialize last_ptr.
+
+ * stor-layout.c (layout_record): Initialize desired_align.
+ (get_best_mode): Initialize unit.
+
+ * tree.c (copy_node): Initialize length.
+
+ * c-lex.c (yylex): Initialize traditional_type, ansi_type and type.
+
+ * caller-save.c (insert_save_restore): Initialize pat, code and
+ numregs.
+
+ * emit-rtl.c (push_to_sequence): Initialize top.
+ (push_topmost_sequence): Likewise.
+
+ * genattrtab.c (simplify_by_exploding): Initialize defval.
+
+ * profile.c (branch_prob): Initialize dest.
+
+ * rtl.h (note_stores): Remove duplicate prototype.
+ (GEN_INT): Re-instate cast of second arg to HOST_WIDE_INT.
+
+ * cplus-dem.c (gnu_special): Don't get confused by .<digits>
+ strings that are not actually lengths.
+
+ * genattrtab.c: Make generated file use system.h, instead of
+ including stdio.h, etc directly.
+ * genextract.c, genopinit.c, genoutput.c: Likewise.
+ * genpeep.c, genrecog.c: Likewise
+
+ * genoutput.c (process_template): Mark operands in the generated
+ function as potentially unused if compiling with GNU CC.
+
+ * i386/freebsd-elf.h (CPP_PREDEFINES): Update from FreeBSD folks.
+
+ * pa.md (reload peepholes): Remove unused variable "mode".
+
+Wed Apr 1 17:06:19 1998 Nick Clifton <nickc@cygnus.com>
+
+ * config/arm/thumb.h: Add super interworking support.
+ * config/arm/thumb.c: Add super interworking support.
+ * config/arm/thumb.md: Add super interworking support.
+ * config/arm/lib1funcs.asm: Add interworking support.
+ * config/arm/lib1thumb.asm: Add super interworking support.
+ * config/arm/t-semi: Add interworking support.
+ * config/arm/t-thumb: Add interworking support.
+ * config/arm/README-interworking: New file.
+
+Wed Apr 1 14:38:10 1998 Jim Wilson <wilson@cygnus.com>
+
+ * config/mips/iris6.h (MD_EXEC_PREFIX): Set to /usr/bin/.
+ (MD_STARTFILE_PREFIX): Unset.
+
+1998-04-01 Mark Mitchell <mmitchell@usa.net>
+
+ * varasm.c (make_decl_rtl): Update the DECL_ASSEMBLER_NAME for a
+ entity in a local scope.
+
+ * fold-const.c (fold): Call truthvalue_conversion for values which
+ are folded to boolean type.
+
+Wed Apr 1 06:09:53 1998 Jeffrey A Law (law@cygnus.com)
+
+ * 1750a.md, arm.c, clipper.c, clipper.md: Use GEN_INT consistently.
+ * convex.h, dsp16xx.c, fx80.md, gmicro.c, gmicro.md: Likewise.
+ * i370.h, i370.md, i860.c, i860.h, i860.md, i960.c: Likewise.
+ * i960.h, i960.md, m32r.md, m68k.md, m68kv4.h, m88k.c: Likewise.
+ * m88k.md, ns32k.c, ns32k.md, pdp11.c, pdp11.h, pdp11.md: Likewise.
+ * pyr.c, pyr.h, pyr.md, romp.c, romp.h, romp.md: Likewise.
+ * rs6000.md, sparc.c, sparc.h, sparc.md, spur.c, spur.md: Likewise.
+ * tahoe.md, vax.h, vax.md, we32k.c, we32k.h, we32k.md: Likewise.
+ * md.texi: Likewise.
+
+Wed Apr 1 08:33:44 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * fixincludes (limits.h): Fix nested comments in Motorola's
+ limits.h and sys/limits.h.
+
+Tue Mar 31 16:57:33 1998 Jim Wilson <wilson@cygnus.com>
+
+ * alpha.c (alpha_expand_unaligned_load): Use tgt instead of addr
+ as dest of expand_binop call.
+
+ * alpha.md (extzv): Correct check for valid operand[2] values.
+
+ * profile.c (branch_prob): Add code to recognize HPPA tablejump entry
+ branch.
+
+ * toplev.c (rest_of__compilation): Call init_recog_no_volatile at end.
+
+Mon Mar 30 13:11:05 1998 Stan Cox <scox@cygnus.com>
+
+ * libgcc2.c: (__main, __do_global_dtors, __do_global_ctors):
+ For __CYGWIN32__ use the versions in winsup/dcrt0.cc.
+
+ * gcc.c, cccp.c, cpplib.c, collect2.c (GET_ENVIRONMENT): Added.
+ cygwin32 can override this to allow both unix and win32 style PATHs.
+
+ * i386/xm-cygwin32.h (GET_ENVIRONMENT): Defined to allow win32
+ style environment paths.
+
+Mon Mar 30 14:43:20 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (cppalloc.o, cpperror.o, cppexp.o, cpphash.o,
+ cpplib.o, cppmain.o, fix-header.o, gcov.o, gen-protos.o,
+ gengenrtl.o, halfpic.o, hash.o, scan-decls.o, scan.o): Depend on
+ system.h.
+
+ * cpphash.c: Include config.h.
+ * cppalloc.c: Include system.h. Add parameters to various
+ function prototypes.
+ * cpperror.c: Likewise.
+ * cppexp.c: Likewise.
+ * cpphash.c: Likewise.
+ * cpplib.c: Likewise.
+ * cppmain.c: Likewise.
+ * fix-header.c: Likewise.
+ * gcov.c: Likewise.
+ * gen-protos.c: Likewise.
+ * gengenrtl.c: Likewise.
+ * halfpic.c: Likewise.
+ * hash.c: Likewise.
+ * scan-decls.c: Likewise.
+ * scan.c: Likewise.
+
+Mon Mar 30 11:06:45 1998 Jim Wilson <wilson@cygnus.com>
+
+ * README.gnat: Add lang_print_xnode definition.
+
+Mon Mar 30 11:12:24 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * config/m68k/m68k.c (standard_68881_constant_p): Don't use
+ fmovecr on the 68060.
+
+Mon Mar 30 00:21:03 1998 Jeffrey A Law (law@cygnus.com)
+
+ * genemit.c (DONE): Rework so that it works in the true arm if
+ an if-else conditional.
+ (FAIL): Likewise.
+
+Sun Mar 29 12:45:23 1998 Jeffrey A Law (law@cygnus.com)
+
+ * rs6000.c: Do not include stdioh or ctype.h anymore.
+
+ * Makefile.in (c-typeck.o): Delete on expr.h, insn-codes.h and
+ $(RTL_H).
+ (stor-layout.o): Likewise.
+ * c-typeck.c: Include rtl.h and expr.h.
+ * stor-layout.c: Likewise.
+
+ * cpplib.c (cpp_file_line_for_message): Delete unused parameter.
+ All callers changed.
+ (do_sccs): Wrap in an SCCS_DIRECTIVE ifdef.
+ * fix-header.c (cpp_file_line_for_message): Delete unused paramter.
+ All callers changed.
+
+ * collect2.c (is_in_list): Wrap inside COLLECT_EXPORT_LIST ifdef.
+
+ * local-alloc.c (reg_classes_overlap_p): Delete dead function.
+
+ * tree.h (lang_print_xnode): Provide prototype.
+
+Sat Mar 28 23:50:44 PST 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sun Mar 29 00:42:21 1998 Jeffrey A Law (law@cygnus.com)
+
+ * objc/sendmsg.c (__objc_block_forward): Add braces for return
+ value if INVISIBLE_STRUCT_RETURN.
+
+ * pa.c (arith_double_operand): Fix parens.
+
+ * haifa-sched.c (print_pattern): Correct arg to sprintf.
+
+ * Makefile.in (libgcc1.null): Make return type for __foo void.
+
+Sat Mar 28 14:37:20 1998 Jeffrey A Law (law@cygnus.com)
+
+ * pa.h: Add declarations for many functions defined in pa.c.
+
+ * genpeep.c (main): Remove unused variable 'i' from the generated
+ file.
+
+ * genemit.c (gen_expand): Do not emit "_done" or "_fail" labels.
+ (gen_split): Likewise.
+ (main): Rework generated definitions of DONE and FAIL so that they
+ no longer use gotos. Avoids warnings about unused labels.
+
+ * integrate.c (copy_rtx_and_substitute): Rework to avoid need for
+ unused "junk" variable.
+
+ * genattrtab.c (write_complex_function): Add a default case in
+ generated switch statement to keep -W -Wall quiet.
+
+Sat Mar 28 10:47:21 1998 Nick Clifton <nickc@cygnus.com>
+
+ * invoke.texi: Document more ARM and Thumb command line options.
+
+ * config/arm/xm-thumb.h: New file.
+
+Sat Mar 28 01:37:33 1998 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * stmt.c (expand_expr_stmt): Must generate code for
+ statements within an expression (gcc's `({ ... )}')
+ even if -fsyntax-only.
+
+Sat Mar 28 01:06:12 1998 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
+ Jeffrey A Law (law@cygnus.com)
+
+ * basic-block.h (basic_block_computed_jump_target): Declare.
+ * flags.h: (current_function_has_computed_jump): Declare.
+ * flow.c: (basic_block_computed_jump_target): Define.
+ (flow_analysis): Allocate it. Set current_function_has_computed_jump
+ to 0.
+ (find_basic_blocks): Set current_function_has_computed_jump and
+ elements of basic_block_computed_jump_target to 1 as appropriate.
+ * function.c: (current_function_has_computed_jump): Define.
+ * global.c (global_conflicts): Don't allocate pseudos into stack regs
+ at the start of a block that is reachable by a computed jump.
+ * reg-stack.c (stack_reg_life_analysis): If must restart, do so
+ immediately.
+ (subst_stack_regs): Undo change from Sep 4 1997.
+ (uses_reg_or_mem): Now unused, deleted.
+ * stupid.c (stupid_life_analysis): Compute
+ current_function_has_computed_jump.
+ (stupid_find_reg): Don't allocate stack regs if the function has a
+ computed goto.
+ * haifa-sched.c (is_cfg_nonregular): Delete code to determine if
+ the current function has a computed jump. Use the global value
+ instead.
+
+Sat Mar 28 00:21:37 1998 Jeffrey A Law (law@cygnus.com)
+
+ * i386/freebsd.h (CPP_PREDEFINES): Remove __386BSD__.
+ (DWARF2_UNWIND_INFO): Define to zero.
+
+Fri Mar 27 16:04:49 1998 Michael Meissner <meissner@cygnus.com>
+
+ * gcc.c (set_std_prefix): Add declaration.
+ (process_command): If GCC_EXEC_PREFIX is set, remove /lib/gcc-lib/
+ suffix, and update the standard prefix prefix.c uses.
+
+ * prefix.c (std_prefix): New global to hold default prefix value.
+ (get_key_value): Change to use std_prefix instead of PREFIX.
+ (translate_name): Ditto.
+ (update_path): Ditto.
+ (get_key_value): Release allocated scratch storage.
+ (set_std_prefix): New function to reset the standard prefix.
+
+Fri Mar 27 18:08:21 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.c (find_barrier): Fix calculations for alignment increase.
+
+Fri Mar 27 08:56:52 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * Makefile.in (stmp-fixinc): If we're actually fixing include
+ files, copy gcc's assert.h into the fixed include dir.
+ * fixincludes (assert.h): Avoid any attempts to fix a probably
+ broken system specific assert.h file.
+ * fixproto (stdlib.h): Make sure, it'll contain a definition of
+ size_t.
+
+Fri Mar 27 00:49:46 1998 Jeffrey A Law (law@cygnus.com)
+
+ * regclass.c (reg_scan_mark_refs): Be more selective about
+ when we mark a register with REGNO_POINTER_FLAG.
+
+Thu Mar 26 23:00:11 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ reload inheritance improvement:
+ * reload1.c (reg_reloaded_contents, reg_reloaded_insn):
+ Change meaning: index is now hard reg number.
+ (reg_reloaded_valid, reg_reloaded_dead): New variables.
+ (reload_spill_index): Content is now a hard reg number.
+ (reload_as_needed): Change to fit new variable meaning.
+ (forget_old_reloads_1, allocate_reload_reg): Likewise.
+ (choose_reload_regs, emit_reload_insns): Likewise.
+
+Thu Mar 26 18:34:13 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * regclass.c (record_reg_classes): '?' increases cost by two.
+
+ * reload.c (find_reloads): Double previous costs. Output
+ reloads cost one unit extra.
+
+ * reload1.c (eliminate_regs): Delete LOAD_EXTENDED_OP code that
+ boiled down to && ! 0.
+
+ * reload.c (find_equiv_reg): Also consider a goal offset from the
+ frame pointer to be constant.
+
+Thu Mar 26 17:34:46 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.h (OPTIMIZATION_OPTIONS): Define.
+
+Thu Mar 26 00:19:47 1998 Richard Henderson <rth@cygnus.com>
+
+ * combine.c (make_compound_operation): Simplify (subreg (*_extend) 0).
+
+Wed Mar 25 23:53:11 1998 Jeffrey A Law (law@cygnus.com)
+
+ * pa.c (pa_adjust_cost): Avoid redundant calls to get_attr_type.
+
+Wed Mar 25 13:40:48 1998 Jim Wilson <wilson@cygnus.com>
+
+ * c-common.c (check_format_info): Initialize type, is_type. New local
+ integral_format. Don't warn for 'L' when pedantic. Do warn for 'L'
+ when pedantic if used with integral format specifier.
+
+Wed Mar 25 16:09:01 1998 Michael Meissner <meissner@cygnus.com>
+
+ * rs6000.h (FUNCTION_ARG_PADDING): Cast result to be enum
+ direction.
+ (function_arg_padding): Declare.
+
+ * rs6000.c: Include system.h.
+ (function_arg_padding): Change return type to int, cast enum's to
+ int.
+
+ (From Kaveh R. Ghazi <ghazi@caip.rutgers.edu>)
+ * collect2.c (scan_prog_file): Add explicit braces to avoid
+ ambiguous `else'.
+
+ * dbxout.c (dbxout_type_fields): Add braces around empty body in
+ an if-statement.
+ (dbxout_type): Likewise.
+
+ * rs6000.c (rs6000_override_options): Change type of `i', `j' and
+ `ptt_size' from int to size_t.
+ (rs6000_file_start): Likewise for `i'.
+ (rs6000_replace_regno): Add default case in enumeration switch.
+ (output_epilog): Remove unused variable `i'.
+ (rs6000_longcall_ref): Remove unused variables `len', `p', `reg1'
+ and `reg2'.
+
+ * rs6000.h (ADDITIONAL_REGISTER_NAMES): Add missing braces around
+ initializer.
+ (get_issue_rate, non_logical_cint_operand): Add prototype.
+ (rs6000_output_load_toc_table): Ditto.
+
+ * rs6000.md (udivmodsi4): Add explicit braces to avoid ambiguous
+ `else'.
+
+Wed Mar 25 10:05:19 1998 Nick Clifton <nickc@cygnus.com>
+
+ * config/arm/thumb.c: New File. Support for ARM's Thumb
+ instruction set.
+ * config/arm/thumb.h: New File. Thumb definitions.
+ * config/arm/thumb.md: New File. Thumb machine description.
+ * config/arm/tcoff.h: New File. Thumb COFF support.
+ * config/arm/t-thumb: New File. Thumb makefile fragment.
+ * config/arm/lib1thumb.asm: New File. Thumb libgcc support functions.
+
+ * configure.in: Add Thumb-coff target.
+ * configure: Add Thumb-coff target.
+ * config.sub: Add Thumb-coff target.
+
+Wed Mar 25 10:30:32 1998 Jim Wilson <wilson@cygnus.com>
+
+ * loop.c (scan_loop): Initialize move_insn_first to zero.
+
+Wed Mar 25 01:06:49 1998 Joel Sherrill (joel@OARcorp.com)
+
+ * config/i386/go32-rtems.h: Defined TARGET_MEM_FUNCTIONS.
+ * config/i386/rtems.h: Likewise.
+ * config/i960/rtems.h: Likewise.
+ * config/m68k/rtems.h: Likewise.
+ * config/mips/rtems64.h: Likewise.
+ * config/pa/rtems.h: Likewise.
+ * config/rs6000/rtems.h: Likewise.
+ * config/sh/rtems.h: Likewise.
+ * config/sparc/rtems.h: Likewise.
+
+Wed Mar 25 00:57:26 1998 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * pa.c (emit_move_sequence): If in reload, call find_replacement.
+
+Tue Mar 24 10:44:11 1998 Nick Clifton <nickc@cygnus.com>
+
+ * Makefile.in (gcov$(exeext)): Support .exe extension to gcov.
+
+ * collect2.c (find_a_file): Add debugging.
+ (find_a_file): Test for win32 style absolute paths if
+ DIR_SERPARATOR is defined.
+ (prefix_from_string): Add debugging.
+ (main): Test for debug command line switch at start of program
+ execution.
+ (main): Use GET_ENVIRONMENT rather than getenv().
+ (prefix_from_env): Use GET_ENVIRONMENT.
+
+1998-03-24 Mark Mitchell <mmitchell@usa.net>
+
+ * cplus-dem.c (optable): Add sizeof.
+ (demangle_template_value_parm): New function containing code
+ previously found in demangle_template.
+ (demangle_integral_value): New function which handles complicated
+ integral expressions.
+ (demangle_template): Use them.
+
+Tue Mar 24 12:13:18 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (genconfig.o, genflags.o, gencodes.o, genemit.o,
+ genopinit.o, genrecog.o, genextract.o, genpeep.o, genattr.o,
+ genattrtab.o, genoutput.o): Depend on system.h.
+
+ * genattr.c: Include system.h. Add arguments to various function
+ prototypes. Remove redundant prototype of read_rtx().
+ * genattrtab.c: Likewise.
+ * gencodes.c: Likewise.
+ * genconfig.c: Likewise.
+ * genemit.c: Likewise.
+ * genextract.c: Likewise.
+ * genflags.c: Likewise.
+ * genopinit.c: Likewise.
+ * genoutput.c: Likewise.
+ * genpeep.c: Likewise.
+ * genrecog.c: Likewise.
+
+1998-03-24 Martin von Loewis <loewis@informatik.hu-berlin.de>
+
+ * c-lang.c (lang_print_xnode): New function.
+ * objc/objc-act.c (lang_print_xnode): Likewise.
+ * print-tree.c (print_node): Call it
+
+Mon Mar 23 23:59:11 1998 H.J. Lu (hjl@gnu.org)
+
+ * c-parse.in: Recognize protocol qualifiers in class
+ definitions for objc.
+ Include "output.h".
+ (yyerror): Remove redundant decl.
+ (yyprint): Fix prototype.
+
+Mon Mar 23 23:49:47 1998 Jeffrey A Law (law@cygnus.com)
+
+ * cse.c (rtx_cost): Only call CONST_COSTS if it is defined.
+
+ * stmt.c (unroll_block_trees): Free block_vector if needed.
+
+Mon Mar 23 23:26:42 1998 Philippe De Muyter <phdm@macqel.be>
+
+ * m68k/m68k.md (zero_extendqidi2, zero_extendhidi2): New patterns.
+ (zero_extendsidi2): Avoid useless copy.
+ (iordi_zext): New pattern.
+ (iorsi_zexthi_ashl16): Pattern reworked to avoid "0" constraint for
+ operand 2.
+ (iorsi_zext): New name for old unnamed pattern; indentation fixes.
+
+ * m68k/m68k.md (ashldi_const): Allow shift count in range ]32,63].
+ (ashldi3): Allow constant shift count in range ]32,63].
+ (ashrdi_const, ashrid3, lshrdi_const, lshrdi3): Likewise.
+
+1998-03-22 Mark Mitchell <mmitchell@usa.net>
+
+ * tree.h (IS_EXPR_CODE_CLASS): New macro.
+
+Mon Mar 23 23:18:48 1998 Jeffrey A Law (law@cygnus.com)
+
+ * h8300.h (CONST_COSTS): Remove definition.
+ (DEFAULT_RTX_COSTS): Define.
+
+Mon Mar 23 22:58:22 1998 Joel Sherrill (joel@OARcorp.com)
+
+ * config/sh/rtems.h: Switched from ELF to COFF.
+
+Mon Mar 23 14:14:20 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * freebsd.h (ASM_OUTPUT_ALIGN): Redefine.
+
+Sat Mar 21 23:52:56 PST 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sun Mar 22 00:50:42 1998 Nick Clifton <nickc@cygnus.com>
+ Geoff Noer <noer@cygnus.com>
+
+ * Makefile.in: Various fixes for building cygwin32 native toolchains.
+
+ * objc/Makefile.in: Various fixes for building cygwin32 native toolchains.
+ * objc/Make-lang.in: Likewise.
+
+ * config/i386/xm-cygwin32.h (PATH_SEPARATOR): Set to a semi-colon.
+
+Sun Mar 22 00:21:46 1998 R. Ganesan <rganesan@novell.com>
+
+ * configure.in: Handle with-PACKAGE=no correctly
+
+Fri Mar 20 17:36:23 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (alias.o, bitmap.o, c-aux-info.o, c-common.o,
+ c-decl.o, c-iterate.o, c-lang.o, c-lex.o, c-pragma.o, c-typeck.o,
+ caller-save.o, calls.o, collect2.o, combine.o, cse.o, dbxout.o,
+ dwarf2out.o, dwarfout.o, emit-rtl.o, except.o, explow.o, expmed.o,
+ expr.o, final.o, flow.o, function.o, getpwd.o, global.o,
+ integrate.o, jump.o, local-alloc.o, loop.o, optabs.o, pexecute.o,
+ prefix.o, print-rtl.o, print-tree.o, profile.o, real.o, recog.o,
+ reg-stack.o, regclass.o, regmove.o, reload.o, reload1.o, reorg.o,
+ rtl.o, rtlanal.o, sdbout.o, stmt.o, stor-layout.o, stupid.o,
+ tlink.o, toplev.o, tree.o, unroll.o, varasm.o, xcoffout.o): Depend
+ on system.h.
+
+ * alias.c, bitmap.c, c-aux-info.c, c-common.c, c-decl.c,
+ c-iterate.c, c-lang.c, c-lex.c, c-pragma.c, c-typeck.c,
+ caller-save.c, calls.c, collect2.c, combine.c, cse.c, dbxout.c,
+ dwarf2out.c, dwarfout.c, emit-rtl.c, except.c, explow.c, expmed.c,
+ expr.c, final.c, flow.c, function.c, gcc.c, getpwd.c, global.c,
+ integrate.c, jump.c, local-alloc.c, loop.c, optabs.c, pexecute.c,
+ prefix.c, print-rtl.c, print-tree.c, profile.c, real.c, recog.c,
+ reg-stack.c, regclass.c, regmove.c, reload.c, reload1.c, reorg.c,
+ rtl.c, rtlanal.c, sched.c, sdbout.c, stmt.c, stor-layout.c,
+ stupid.c, tlink.c, toplev.c, tree.c, unroll.c, varasm.c,
+ xcoffout.c: Include system.h. Organize include ordering so
+ that stdarg/varargs comes before other system headers. Remove
+ spurious casts of functions assured of a prototype in system.h.
+
+Fri Mar 20 11:19:40 1998 Stan Cox <scox@equinox.cygnus.com>
+
+ * reg-stack.c (pop_stack): Define. Pops any register on the
+ regstack and adjusts regstack.
+ (compare_for_stack_reg): Use pop_stack.
+
+Thu Mar 19 23:51:01 1998 Jeffrey A Law (law@cygnus.com)
+
+ * configure.in (hppa1.0-hp-hpux10): Handle threads for this
+ config too.
+
+Thu Mar 19 20:30:31 1998 Philippe De Muyter <phdm@macqel.be>
+
+ * libgcc2.c (exit): Do not call __bb_exit_func if HAVE_ATEXIT.
+
+ * fold-const.c (fold): Replace sign-extension of a zero extended
+ value by a single zero extension.
+
+Thu Mar 19 00:58:07 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.c (init_eh): Do nothing.
+ (save_eh_status): Call init_eh_for_function, not init_eh.
+ * function.c (push_function_context_to): Don't call init_emit.
+
+Thu Mar 19 13:39:52 1998 Michael Meissner <meissner@cygnus.com>
+
+ * rs6000/sysv4.h (RELATIVE_PREFIX_NOT_LINKDIR): Undef for System V
+ and EABI.
+
+Thu Mar 19 10:10:36 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * final.c (shorten_branches): Add parentheses around +/- in
+ operand of &.
+
+ * flow.c (life_analysis): Wrap variable `i' in macro ELIMINABLE_REGS.
+
+Thu Mar 19 09:15:17 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * regclass.c (memory_move_secondary_cost): Wrap uses of
+ SECONDARY_INPUT_RELOAD_CLASS and SECONDARY_OUTPUT_RELOAD_CLASS
+ with #ifdef tests.
+
+Thu Mar 19 09:06:35 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * config/m68k/m68k.md (addqi3): Fix typo gen_INT vs. GEN_INT.
+
+ * flow.c (life_analysis): #include <sys/types.h> to make sure
+ size_t is defined.
+ * cplus-dem.c (demangle_function_name): Likewise.
+
+Thu Mar 19 09:00:01 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * final.c (insn_noperands): Change type to unsigned int.
+ (final_scan_insn): Likewise for noperands;
+ properly check operand number boundaries.
+
+Wed Mar 18 16:20:30 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.md (extzv): Don't reject register operands. Fix
+ mode of operand 1.
+
+Wed Mar 18 16:14:23 1998 Richard Henderson <rth@cygnus.com>
+
+ * dbxout.c (dbxout_function_end): Fix last change. The correct
+ predicate is ASM_OUTPUT_SECTION_NAME.
+
+Wed Mar 18 12:43:20 1998 Jim Wilson <wilson@cygnus.com>
+
+ * sh.md (ashlsi_c-1): Delete 3rd argument to gen_ashlsi_c.
+ (ashlsi): Use match_dup 1 instead of match_operand 2.
+
+Wed Mar 18 13:46:07 1998 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * fold-const.c (operand_equal_for_comparison_p): See if equal
+ when nop conversions are removed.
+
+Wed Mar 18 13:42:01 1998 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * expr.c (expand_expr, case COND_EXPR): If have conditional move,
+ don't use ORIGINAL_TARGET unless REG.
+
+Wed Mar 18 16:53:19 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * netbsd.h (ASM_OUTPUT_ALIGN): Redefine.
+
+Wed Mar 18 12:43:20 1998 Jim Wilson <wilson@cygnus.com>
+
+ * loop.c (struct movable): New field move_insn_first.
+ (scan_loop): In consec sets code, set it. Clear it otherwise.
+ (move_movables): In consec sets code, use it. Copy REG_NOTES from
+ p to i1 only if i1 does not have REG_NOTES. Delete obsolete ifdefed
+ out code.
+
+Wed Mar 18 09:52:56 1998 Richard Henderson <rth@cygnus.com>
+
+ * rtl.c (read_rtx): Fall back on homebrew atoll if HOST_WIDE_INT
+ is large, and the system doesn't provide atoll or atoq.
+ (atoll): New.
+
+ * alpha/xm-vms.h (HAVE_ATOLL): Define.
+ Reported by Klaus Kaempf <kkaempf@progis.de>.
+
+Wed Mar 18 09:56:26 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * c-lang.c (finish_file): Wrap variable `void_list_node' with macro
+ test !ASM_OUTPUT_CONSTRUCTOR || !ASM_OUTPUT_DESTRUCTOR.
+
+ * calls.c (emit_call_1): Wrap variable `already_popped' with macro
+ test !ACCUMULATE_OUTGOING_ARGS.
+
+ * collect2.c (write_c_file_glob): Wrap function definition in
+ macro test !LD_INIT_SWITCH.
+
+ * combine.c (try_combine): Wrap variables `cc_use' and
+ `compare_mode' in macro test EXTRA_CC_MODES.
+
+ * cpplib.c (do_ident): Remove unused variable `len'.
+ (skip_if_group): Remove unused variables `at_beg_of_line' and
+ `after_ident'.
+ (cpp_get_token): Remove unused variable `dummy'.
+
+ * dbxout.c (scope_labelno): Move static variable definition inside
+ the one function scope where it is used.
+ (dbxout_function_end): Wrap prototype and definition in
+ macro test !NO_DBX_FUNCTION_END.
+
+ * dwarf2out.c (add_subscript_info): Wrap variable `dimension_number'
+ in macro test !MIPS_DEBUGGING_INFO.
+
+ * expr.c (expand_builtin_setjmp): Move declaration of variable `i'
+ into the scope where it is used. Wrap empty else-statement body
+ in braces.
+
+ * fix-header.c: Fix typo in comment.
+ (inf_skip_spaces): Cast results of INF_UNGET to (void).
+ (check_protection, main): Likewise.
+
+ * flow.c (find_basic_blocks_1): Remove dangling comment text.
+
+ * function.c (contains): Wrap prototype and definition in macro
+ test HAVE_prologue || HAVE_epilogue.
+ (fixup_var_refs_1): Remove unused variable `width'.
+
+ * gen-protos.c (main): Remove unused variable `optr'.
+
+ * haifa-sched.c (debug_control_flow): Remove unused variable `j'.
+
+ * libgcc2.c (__udiv_w_sdiv): Provide dummy return value of 0.
+ (__sjpopnthrow): Remove unused variable `jmpbuf'.
+ (__throw): Remove unused variable `val'.
+
+ * protoize.c: Check for a previously existing definition before
+ defining *_OK macros.
+
+ * scan-decls.c (scan_decls): Remove unused variable `old_written'.
+
+Tue Mar 17 00:45:48 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * vax.h (ADDR_VEC_ALIGN): Define.
+
+Mon Mar 16 15:57:17 1998 Michael Meissner <meissner@cygnus.com>
+
+ * gcc.c (default_arg): Don't wander off the end of allocated
+ memory.
+
+ (From Geoffrey Keating <geoffk@ozemail.com.au>)
+ * rs6000.c (small_data_operand): Ensure that any address
+ referenced relative to the small data area is inside the SDA.
+
+Mon Mar 16 12:55:15 1998 Jim Wilson <wilson@cygnus.com>
+
+ * config/m68k/netbsd.h (ASM_SPEC): Add %{m68060}.
+
+Mon Mar 16 15:50:20 EST 1998 Andrew MacLeod <amacleod@cygnus.com>
+
+ * except.h (in_same_eh_region): New prototype.
+ (free_insn_eh_region, init_insn_eh_region): New prototypes.
+ * except.c (insn_eh_region, maximum_uid): New static variables.
+ (set_insn_eh_region): New static function to set region numbers.
+ (free_insn_eh_region): New function to free EH region table.
+ (init_insn_eh_region): New function to initialize EH region table.
+ (in_same_eh_region): New function used to determine if two rtl
+ instructions are in the same exception region or not.
+ * final.c (final): Initialize the table indicating which instructions
+ belong in which exception region.
+ * genpeep.c (main): Add "except.h" to include file list in generated
+ file insn-peep.c.
+ * config/sparc/sparc.md: Add calls to 'in_same_eh_region' in 4
+ peepholes involving calls and unconditional branches.
+
+Mon Mar 16 11:16:50 1998 Jim Wilson <wilson@cygnus.com>
+
+ * README.gnat: New file.
+
+Mon Mar 16 11:14:20 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * config/m68k/m68k.c: Include <stdlib.h> for atoi. Include
+ "recog.h" for offsettable_memref_p.
+ (legitimize_pic_address): Remove unused variable `offset'.
+ (notice_update_cc): Change return type to void. Add default label
+ to switch.
+ (standard_68881_constant_p): Remove unused variable mode.
+ (print_operand): Define local variable i only if SUPPORT_SUN_FPA.
+ (const_int_cost): Explicitly declare as returning int.
+ (output_dbcc_and_branch): Change return type to void.
+
+ * config/m68k/linux.h, config/m68k/m68k.md, config/m68k/m68k.c,
+ config/m68k/m68k.h: Replace gen_rtx (XXX, ...) with gen_rtx_XXX
+ (...). Use GEN_INT instead of gen_rtx_CONST_INT.
+
+Sun Mar 15 22:30:44 PST 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Fri Mar 13 11:30:12 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * config/m68k/m68k.h (CONST_OK_FOR_LETTER_P): Fix logic in range
+ check for 'M' constraint.
+
+Thu Mar 12 14:47:14 1998 Jim Wilson <wilson@cygnus.com>
+
+ * cccp.c (create_definition): If pedantic, call pedwarn for macro
+ varargs feature.
+
+Thu Mar 12 13:43:25 1998 Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>
+
+ * i386.c (ix86_logical_operator): New function.
+ (split_di): Ensure that when a MEM is split, the resulting MEMs have
+ SImode.
+ * i386.md (anddi3, xordi3, iordi3): New patterns. Add a define_split
+ to implement them.
+
+Thu Mar 12 15:13:16 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+ Richard Earnshaw <rearnsha@arm.com>
+ Nick Clifton <nickc@cygnus.com>
+
+ * tm.texi (DEFAULT_RTX_COSTS): Document new macro.
+
+ * arm.h (DEFAULT_RTX_COSTS): Define instead of RTX_COSTS.
+
+ * cse.c (rtx_cost): Provide a default case in an enumeration
+ switch, and call DEFAULT_RTX_COSTS if it's defined.
+
+Thu Mar 12 10:02:38 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * basic-block.h (compute_preds_succs): Change return type in
+ prototype to void.
+ * flow.c (compute_preds_succs): Likewise in function definition.
+
+ * regmove.c (find_matches): Cast char used as array index to unsigned char
+ to supress warning.
+
+Thu Mar 12 09:39:40 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * i386.h (RTX_COSTS): Insert braces around nested if.
+ (ADDITIONAL_REGISTER_NAMES): Insert braces around structured
+ elements.
+
+ * gcc.c (default_compilers): Properly put brackets around array elements in
+ initializer.
+
+ * getopt.c (_getopt_internal): Add explicit braces around nested if;
+ reformatted.
+
+ * reg-stack.c (record_asm_reg_life): Add explicit braces around nested if's.
+ (record_reg_life_pat): Add explicit parens around && and || in expression.
+ (stack_reg_life_analysis): Add parens around assignment used as expression.
+ (convert_regs): Likewise.
+
+Thu Mar 12 09:25:29 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * bitmap.c (bitmap_element_allocate): Remove unused parameter;
+ change callers accordingly.
+
+ * cplus-dem.c (arm_special): Remove unused parameter work in prototype
+ and definition; change all callers accordingly.
+
+ * except.c (init_eh): Avoid assignment of unused return value of
+ build_pointer_type; cast it to void, instead, and remove unused
+ variable type.
+
+ * gcc.c (lang_specific_driver): Define prototype only #ifdef
+ LANG_SPECIFIC_DRIVER.
+ (temp_names): Define only #ifdef MKTEMP_EACH_FILE.
+
+ * genoutput.c (output_epilogue): Initialize next_name to 0.
+
+ * real.c (efrexp): #if 0 prototype and function definition.
+ (eremain): Likewise.
+ (uditoe): Likewise.
+ (ditoe): Likewise.
+ (etoudi): Likewise.
+ (etodi): Likewise.
+ (esqrt): Likewise.
+
+ * reload.c (push_secondary_reload): Define prototype only
+ #ifdef HAVE_SECONDARY_RELOADS.
+
+ * varasm.c (assemble_static_space): Define rounded only
+ #ifndef ASM_OUTPUT_ALIGNED_LOCAL.
+
+Thu Mar 12 09:11:35 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * i386.md (andsi): Add default case in enumeration switch.
+ (iorsi3): Likewise.
+ (iorhi3): Likewise.
+ (xorsi3): Likewise.
+
+Thu Mar 12 08:37:02 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * c-decl (finish_struct): Change type of min_align to unsigned.
+
+ * cplus-dem.c (demangle_function_name): Change type of variable i to size_t;
+ remove unused variable len.
+
+ * dwarf2out.c (reg_save): Add explicit cast of -1 to unsigned and a
+ comment indicating this is proper behaviour.
+ (reg_loc_descriptor): Remove redundant comparison of unsigned variable
+ reg >= 0.
+ (based_loc_descr): Likewise.
+
+ * enquire.c (bitpattern): Change type of variable i to unsigned.
+
+ * final.c (output_asm_insn): Don't cast insn_noperands to unsigned.
+
+ * flow.c (life_analysis): Change type of variable i to size_t;
+ remove unused variable insn.
+
+ * gcc.c (translate_options): Change type of variables optlen, arglen and
+ complen to size_t.
+ (input_filename_length): Change type to size_t.
+ (do_spec_1): Change type of variable bufsize to size_t.
+ (main): Change type of variables i and j to size_t;
+ remove subblock local definition of variable i.
+ (lookup_compiler): Change type of second argument to size_t;
+ change type of variable i to size_t.
+
+ * genemit.c (output_init_mov_optab): Change type of variable i to size_t.
+
+ * genopinit.c (get_insn): Change type of variable pindex to size_t.
+
+ * genrecog.c (add_to_sequence): Change type of variable i to size_t.
+
+ * global.c (global_alloc): Change type of variable i to size_t.
+
+ * regclass.c (init_reg_sets): Change type of variables i and j to unsigned.
+
+ * stmt.c (expand_end_bindings): Change type of variable i to size_t.
+ (expand_end_case): Change type of variable count to size_t.
+
+ * toplev.c (main): Change type of variable j to size_t.
+ (set_target_switch): Change type of variable j to size_t.
+ (print_switch_values): Change type of variable j to size_t;
+ remove unused variable flags.
+
+ * varasm.c (assemble_variable): Change type of variable align to size_t.
+ (const_hash_rtx): Change type of variable i to size_t.
+
+1998-03-11 Mark Mitchell <mmitchell@usa.net>
+
+ * dbxout.c (dbxout_type_methods): Only treat TYPE_METHODS as a
+ TREE_VEC if that's what it really is.
-Tue May 16 18:04:47 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Wed Mar 11 15:16:01 1998 Michael Meissner <meissner@cygnus.com>
- * toplev.c (pfatal_with_name, fatal_io_error, vfatal):
- Use FATAL_EXIT_CODE instead of magic number.
- * cccp.c, cpplib.c, cpplib.h: Use FATAL_EXIT_CODE instead
- of FAILURE_EXIT_CODE.
- * fix-header.c, gen-protos.c: Likewise.
- * cpperror.c, cppmain.c: Likewise.
- Include config.h #ifndef EMACS.
- * xm-alpha.h, xm-rs6000.h, xm-vms.h (FAILURE_EXIT_CODE): Remove.
+ * {haifa-,}sched.c (rank_for_schedule): Only take void * arguments
+ as per ISO C spec.
-Tue May 16 17:46:57 1995 Adam Fedor <fedor@colorado.edu>
+Wed Mar 11 12:05:20 1998 Teemu Torma <tot@trema.com>
- * objc/archive.c (__objc_write_class): Write class version.
- (__objc_write_selector, objc_{write,read}_selector): Handle null
- selector.
+ * gthr.h: Changed the comment about return values.
+ * gthr-solaris.h (__gthread_once): Do not use errno; return the
+ error number instead of -1.
+ (__gthread_key_create): Any non-zero return value is an error.
+ * libgcc2.c (eh_context_initialize): Check for non-zero return
+ value from __gthread_once.
+ Check that the value of get_eh_context was really changed.
- * objc/sarray.h (struct sarray): Make capacity size_t.
- * objc/sarray.c (sarray_realloc): Make array index variables size_t.
+Wed Mar 11 18:26:25 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
-Tue May 16 06:59:08 1995 Paul Eggert <eggert@twinsun.com>
+ * sh.h (LOOP_ALIGN): Only align when optimizing.
+ * sh.c (find_barrier): Clear inc for CODE_LABELs.
+ When not optimizing, calculate alignment for BARRIERs directly.
- * dsp16xx.c (print_operand_address): Fix misspellings in messages.
- * i370/mvs.h (FUNCTION_PROFILER): Likewise.
- * mips-tdump.c (type_to_string): Likewise.
+Wed Mar 11 15:07:18 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * final.c (shorten_branches): Remove conditionalizing on
+ SHORTEN_WITH_ADJUST_INSN_LENGTH
+ * sh.h, pa.h (SHORTEN_WITH_ADJUST_INSN_LENGTH): Remove.
+
+Wed Mar 11 02:37:41 1998 Jeffrey A Law (law@cygnus.com)
+
+ * flow.c (find_basic_blocks_1): Keep the cfg accurate when removing
+ an unconditional jump around deleted blocks.
+
+Mon Mar 9 12:02:23 1998 Jim Wilson <wilson@cygnus.com>
+
+ * profile.c (branch_prob): If see computed goto, call fatal instead of
+ abort.
+
+ * config/mips/sni-svr4.h (CPP_PREDEFINE): Add -DSNI and -Dsinix.
+
+ * configure.in (alpha-dec-osf): Add default case for osf* to switch.
+ Patch from Bruno Haible.
+
+ * function.c (put_reg_into_stack): Copy MEM_IN_STRUCT_P from new.
+ (assign_parms): Set aggregate if hide_last_arg and last_named.
+
+Mon Mar 9 19:57:56 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * final.c (shorten_branches): Initialize insn_addresses.
+
+Mon Mar 9 14:10:23 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.h (MUST_PASS_IN_STACK): Define.
+
+Sun Mar 8 13:01:56 1998 Jeffrey A Law (law@cygnus.com)
+
+ * final.c (shorten_branches): Fix minor logic error in
+ ADDR_DIFF_VEC shortening support.
+
+Sun Mar 8 02:17:42 PST 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sat Mar 7 00:54:15 1998 Jeffrey A Law (law@cygnus.com)
+
+ * haifa-sched.c (is_cfg_nonregular): Change return type to
+ an int. No longer compute "estimated" number of edges. Use
+ computed_jump_p instead of duplicating the code. Fixup/add
+ some comments.
+ (build_control_flow): Returns a value indicating an irregularity
+ in the cfg was detected. Count the number of edges in the cfg.
+ allocate various edge tables.
+ (find_rgns): No longer look for unreachable blocks.
+ (schedule_insns): Do not allocate memory for edge tables here.
+ Free memory for edge tables before returning. Do not perform
+ cross block scheduling if build_control_flow returns nonzero.
+ * flow.c (compute_preds_succs): More accurately determine when
+ a block drops in.
+
+ * basic-block.h (free_basic_block_vargs): Provide prototype.
+
+ * cccp.c (main): Fix dumb mistakes in last change.
+
+Fri Mar 6 21:28:45 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * rtl.h (addr_diff_vec_flags): New typedef.
+ (union rtunion_def): New member rt_addr_diff_vec_flags.
+ (ADDR_DIFF_VEC_FLAGS): New macro.
+
+ * sh.c (output_branch): Fix offset overflow problems.
+
+ * final.c (shorten_branches): Implement CASE_VECTOR_SHORTEN_MODE.
+ (final_scan_insn): New argument BODY for ASM_OUTPUT_ADDR_DIFF_ELT.
+ * rtl.def (ADDR_DIFF_VEC): Three new fields (min, max and flags).
+ * stmt.c (expand_end_case): Supply new arguments to
+ gen_rtx_ADDR_DIFF_VEC.
+ * 1750a.h (ASM_OUTPUT_ADDR_DIFF_ELT): New argument BODY.
+ * alpha.h, arc.h, clipper.h, convex.h : Likewise.
+ * dsp16xx.h, elxsi.h, fx80.h, gmicro.h, h8300.h : Likewise.
+ * i370.h, i386.h, i860.h, i960.h, m32r.h, m68k.h, m88k.h : Likewise.
+ * mips.h, mn10200.h, mn10300.h, ns32k.h, pa.h, pyr.h : Likewise.
+ * rs6000.h, sh.h, sparc.h, spur.h, tahoe.h, v850.h : Likewise.
+ * vax.h, we32k.h, alpha/vms.h, arm/aof.h, arm/aout.h : Likewise.
+ * i386/386bsd.h, i386/freebsd-elf.h : Likewise.
+ * i386/freebsd.h, i386/linux.h : Likewise.
+ * i386/netbsd.h, i386/osfrose.h, i386/ptx4-i.h, i386/sco5.h : Likewise.
+ * i386/sysv4.h, m68k/3b1.h, m68k/dpx2.h, m68k/hp320.h : Likewise.
+ * m68k/mot3300.h, m68k/sgs.h : Likewise.
+ * m68k/tower-as.h, ns32k/encore.h, sparc/pbd.h : Likewise.
+ * sh.h (INSN_ALIGN, INSN_LENGTH_ALIGNMENT): Define.
+ (CASE_VECTOR_SHORTEN_MODE): Define.
+ (short_cbranch_p, align_length, addr_diff_vec_adjust): Don't declare.
+ (med_branch_p, braf_branch_p): Don't declare.
+ (mdep_reorg_phase, barrier_align): Declare.
+ (ADJUST_INSN_LENGTH): Remove alignment handling.
+ * sh.c (uid_align, uid_align_max): Deleted.
+ (max_uid_before_fixup_addr_diff_vecs, branch_offset): Deleted.
+ (short_cbranch_p, med_branch_p, braf_branch_p, align_length): Deleted.
+ (cache_align_p, fixup_aligns, addr_diff_vec_adjust): Deleted.
+ (output_far_jump): Don't use braf_branch_p.
+ (output_branchy_insn): Don't use branch_offset.
+ (find_barrier): Remove checks for max_uid_before_fixup_addr_diff_vecs.
+ Remove paired barrier stuff.
+ Don't use cache_align_p.
+ Take alignment insns into account.
+ (fixup_addr_diff_vecs): Reduce to only fixing up the base label of
+ the addr_diff_vec.
+ (barrier_align, branch_dest): New function.
+ (machine_dependent_reorg, split_branches): Remove infrastructure
+ for branch shortening that is now provided in the backend.
+ * sh.md (short_cbranch_p, med_branch_p, med_cbranch_p): New attributes.
+ (braf_branch_p, braf_cbranch_p): Likewise.
+ (attribute length): Use new attributes.
+ (casesi_worker): Get mode and unsignednedd from ADDR_DIFF_VEC.
+ (addr_diff_vec_adjust): Delete.
+ (align_2): Now a define_expand.
+ (align_log): Now length 0.
+
+Fri Mar 6 14:41:33 1998 Michael Meissner <meissner@cygnus.com>
+
+ * m32r.md (right): Correctly check for length == 2, not 1.
+
+Fri Mar 6 14:00:04 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * mips/mips.h: Prototype `machine_dependent_reorg'.
+ (ASM_OUTPUT_ALIGN): Remove unused variable `mask'.
+
+Fri Mar 6 11:43:35 1998 Joern Rennecke (amylaar@cygnus.co.uk)
+
+ * final.c (shorten_branches): Restore accidentally removed code.
+
+Fri Mar 6 11:00:49 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * configure.in: Remove duplicate uses of AC_PROG_CC and
+ AC_PROG_MAKE_SET.
+
+Fri Mar 6 00:59:30 1998 Richard Henderson <rth@cygnus.com>
+
+ * configure.in (target_cpu_default2): Correct typo for alphapca56.
+
+Thu Mar 5 23:24:50 1998 Jeffrey A Law (law@cygnus.com)
+ Doug Evans (devans@cygnus.com)
+
+ * haifa-sched.c (build_jmp_edges): Delete dead function.
+ (build_control_flow): Use cfg routines from flow.c
+ (schedule_insns): Remove debugging code accidentally checked
+ in earlier today.
+
+ * basic-block.h: Add external integer list structures, typdefs,
+ accessor macros and function declarations. Simlarly for
+ basic block pred/succ support and simple bitmap stuff.
+ * flow.c: Add functions for integer list, basic block pred/succ
+ support and simple bitmap support.
+ (compute_dominators): New function to compute dominators and
+ post dominators.
+ (find_basic_blocks): Split into two functions.
+ (life_analysis): Likewise.
+ (flow_analysis): Removed. Now handled by calling find_basic_blocks,
+ the life_analysis from toplev.c
+ * toplev.c (rest_of_compilation): Call find_basic_blocks, then
+ life_analysis instead of flow_analysis.
+
+Thu Mar 5 23:06:26 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * jump.c (jump_optimize): Call mark_jump_label also for deleted
+ insns.
+ (mark_jump_label): Don't increment ref counts for deleted insns.
+
+Thu Mar 5 09:55:15 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * mips/iris6.h (TARGET_DEFAULT): Parenthesize macro definition.
+
+ * mips/mips.c: Include stdlib.h and unistd.h.
+ (mips_asm_file_end): Add braces around empty body in an if-statement.
+ (function_prologue): Wrap variable `fnname' in
+ !FUNCTION_NAME_ALREADY_DECLARED. Correct format specifier in fprintf.
+ (mips_select_rtx_section, mips_select_section): Declare as void.
+
+ * mips/mips.h: Add prototypes for extern functions in mips.c.
+ (FUNCTION_ARG_REGNO_P): Add parentheses around && within ||.
+ (ENCODE_SECTION_INFO): Add braces around empty body in an
+ if-statement.
+
+ * mips/mips.md (movdi): Add parentheses around && within ||.
+ (movsf, movdf): Likewise.
+ (branch_zero, branch_zero_di): Add default case in
+ enumeration switch.
+
+
+Thu Mar 5 02:45:48 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha/alpha.h (TARGET_WINDOWS_NT, TARGET_OPEN_VMS): Just make them
+ real constants, since they can't be changed.
+ (TARGET_AS_CAN_SUBTRACT_LABELS): New.
+ * alpha/alpha.md (builtin_setjmp_receiver): Use it.
+ * alpha/osf.h (TARGET_AS_CAN_SUBTRACT_LABELS): New.
+ * alpha/osf2or3.h (TARGET_AS_CAN_SUBTRACT_LABELS): New.
+ * alpha/vms.h (TARGET_OPEN_VMS): New.
+ * alpha/win-nt.h (TARGET_WINDOWS_NT): New.
+
+Thu Mar 5 02:41:27 1998 Richard Henderson <rth@cygnus.com>
+
+ * reload.c (find_reloads): Always force (subreg (mem)) to be
+ reloaded if WORD_REGISTER_OPERATIONS.
+
+Thu Mar 5 02:14:44 1998 Richard Henderson <rth@cygnus.com>
+
+ * haifa-sched.c (free_list): Rename from free_pnd_lst.
+ (free_pending_lists): Rename free_pnd_lst uses.
+ (remove_dependence): Place expunged element on unused_insn_list.
+ (alloc_INSN_LIST, alloc_EXPR_LIST): New. Change all callers of
+ gen_rtx_*_LIST and alloc_rtx to use them.
+ (compute_block_backward_dependences): Free the reg_last_* lists.
+
+Thu Mar 5 00:05:40 1998 Jeffrey A Law (law@cygnus.com)
+
+ * cccp.c (main): Avoid undefined behavior when setting pend_includes
+ and pend_files.
+
+Wed Mar 4 21:58:25 1998 Franz Sirl <franz.sirl-kernel@lauterbach.com>
+
+ * rs6000/linux.h: don't define DEFAULT_VTABLE_THUNKS to 1 if
+ USE_GNULIBC_1 is defined
+ * configure.in: add a new case powerpc-*-linux-gnulibc1 which
+ includes the t-linux-gnulibc1 fragment
+
+Wed Mar 4 12:11:36 1998 Jim Wilson <wilson@cygnus.com>
+
+ * mips.md (movdf_internal1a): Fix misplaced parenthesis in condition.
+
+Wed Mar 4 18:47:48 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * final.c (final_scan_insn, case CODE_LABEL: Cleanup.
+
+Wed Mar 4 15:51:19 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * final.c (shorten_branches): Tag the loop alignment onto the
+ first label after NOTE_INSN_LOOP_BEG even if there is an
+ intervening insn.
+
+Tue Mar 3 21:48:35 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * final.c (insn_current_reference_address):
+ Use SEQ instead of BRANCH as argument to align_fuzz, to get a
+ proper alignment chain.
+
+ * final.c (max_labelno): New static variable.
+ (final_scan_insn): Check max_labelno before outputting an
+ alignment for a label.
+ (shorten_branches): Remove unused variable length_align.
+
+Tue Mar 3 14:27:23 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * sparc.c (ultrasparc_adjust_cost): Add default case in
+ enumeration switch.
+
+ * sparc.h: Add prototypes for extern functions defined in
+ sparc.c.
+
+Tue Mar 3 10:00:11 1998 Nick Clifton <nickc@cygnus.com>
+
+ * toplev.c: Only generate <name>.dbr file when dumping RTL if
+ DEALY_SLOTS is defined.
+
+Tue Mar 3 07:36:37 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * reorg.c (fill_eager_delay_slots): Add new argument delay_list
+ in call to fill_slots_from_thread.
+
+Mon Mar 2 13:45:03 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha/linux.h (CPP_PREDEFINES): Correct connecting whitespace
+ to SUB_CPP_PREDEFINES. Reported by asun@saul4.u.washington.edu.
+
+Mon Mar 2 22:59:28 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * final.c (insn_last_address, insn_current_align, uid_align):
+ New variables.
+ (in_align_chain, align_fuzz, align_shrink_fuzz): New functions.
+ (insn_current_reference_address): Likewise.
+ (shorten_branches, final_scan_insn): Implement LABEL_ALIGN,
+ LABEL_ALIGN_AFTER_BARRIER and LOOP_ALIGN target macros.
+ (label_to_alignment): New function.
+ * genattrtab.c (write_test_expr): If one of LABEL_ALIGN,
+ LABEL_ALIGN_AFTER_BARRIER or LOOP_ALIGN is defined, call
+ insn_current_reference_address instead of insn_current_address.
+ (or_attr_value, write_length_unit_log): New functions.
+ (main): Call write_length_unit_log.
+ (write_const_num_delay_slots): Output extra '\n'.
+ * alpha.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE):
+ replace with:
+ (LOOP_ALIGN, ALIGN_LABEL_AFTER_BARRIER).
+ * i386.h, i386/osfrose.h, i386/svr3dbx.h, m68k.h, sparc.h: Likewise.
+ * arc.h, m32r.h (ASM_OUTPUT_LOOP_ALIGN): replace with:
+ (LOOP_ALIGN).
+ * i960.h, m88k.h: (ASM_OUTPUT_ALIGN_CODE): Replace with:
+ (LABEL_ALIGN_AFTER_BARRIER).
+ * ns32k/encore.h, ns32k/merlin.h, ns32k.h, ns32k/sequent.h: Likewise.
+ * ns32k/tek6000.h: Likewise.
+ * i386/gas.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): Delete.
+ * i386.md (casesi+1): Use ASM_OUTPUT_ALIGN instead of
+ ASM_OUTPUT_ALIGN_CODE.
+
+Mon Mar 2 01:05:50 PST 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Mon Mar 2 00:52:18 PST 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sun Mar 1 18:25:49 1998 Michael P. Hayes <michaelh@ongaonga.chch.cri.nz>
+
+ * reorg.c (fill_slots_from_thread): Don't steal delay list from target
+ if condition code of jump conflicts with opposite_needed.
+
+ * reorg.c (fill_slots_from_thread): Mark resources referenced in
+ opposite_needed thread. Return delay_list even when cannot get
+ any more delay insns from end of subroutine.
+
+Sun Mar 1 18:26:21 1998 Ken Rose (rose@acm.org)
+
+ * reorg.c (fill_slots_from_thread): New parameter, delay_list.
+ All callers changed.
+
+Sun Mar 1 18:25:37 1998 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
+
+ * frame.c (start_fde_sort, fde_split, heapsort, fde_merge,
+ end_fde_sort): New functions for fast sorting of an FDE array.
+ (fde_insert): Simplified.
+ (add_fdes): Change argument list.
+ (frame_init): Use the new functions.
+
+Sun Mar 1 18:06:21 1998 Jeffrey A Law (law@cygnus.com)
+
+ * ginclude/va-ppc.h (va_arg): Fix typo in long long support.
+
+ * i386.c (reg_mentioned_in_mem): Fix dangling else statement.
+
+ * fold-const.c (fold_range_test): Always return a value.
+
+Sun Mar 1 17:57:34 1998 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * config/i386/winnt.c (i386_pe_unique_section): Put read-only
+ data in the text section unless READONLY_DATA_SECTION is defined.
+
+Sun Mar 1 17:48:46 1998 Jeffrey A Law (law@cygnus.com)
+
+ * c-parse.in (undeclared variable error): Tweak error message to
+ be clearer.
+
+Sun Mar 1 10:22:36 PST 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+1998-02-28 Mark Mitchell <mmitchell@usa.net>
+
+ * final.c (final_scan_insn): Undo overzealous removal of `set'.
+
+Sat Feb 28 07:54:03 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * pa.h (CONST_COSTS): When checking the CONST_DOUBLE enumerated
+ case, add parentheses to specify the proper order of precedence in
+ the if-statement.
+
+
+ * c-aux-info.c: Include string.h/strings.h.
+
+ * pa.c: Include stdlib.h.
+ (pa_combine_instructions): Prototype the function.
+ (pa_can_combine_p, forward_branch_p, shadd_constant_p): Likewise.
+ (reloc_needed): Add default case for enumeration switch.
+ (remove_useless_addtr_insns): Remove unused variable `all'.
+ (hppa_expand_prologue): Add explicit braces to avoid
+ ambiguous `else'.
+ (output_function_epilogue): Remove unused variable `i'.
+ (output_millicode_call): Remove unused variable `link'.
+ (shadd_constant_p, forward_branch_p): Make the function static.
+ (following_call): Explicitly declare to return int.
+ (pa_reorg): Declare as void.
+ (pa_combine_instructions): Declare as static void. Add
+ parentheses around && within ||.
+
+ * pa.h: Add prototypes for pa_reorg, symbolic_operand,
+ following_call, function_label_operand, lhs_lshift_cint_operand
+ and zdepi_cint_p.
+
+ * pa.md: Add parentheses around && within ||.
+
+ * cppalloc.c: Include stdlib.h.
+
+ * cpperror.c (cpp_print_containing_files): Remove unused variable
+ `i'. Fix format specifier in fprintf.
+
+ * cse.c (cse_around_loop): Add explicit braces to avoid
+ ambiguous `else'.
+ (delete_dead_from_cse): Wrap variable `tem' in macro HAVE_cc0.
+
+ * expr.c (expand_expr): Add parentheses around && within ||.
+
+ * final.c (app_enable): Replace fprintf with fputs where there are
+ no format specifiers and no trailing argument after the string.
+ Eg, when printing ASM_APP_ON/ASM_APP_OFF.
+ (app_disable): Likewise.
+ (final_end_function): Likewise.
+ (final_scan_insn): Likewise. Remove unused variable `set'.
+ (profile_function): Wrap empty if-statement body in {} brackets.
+
+ * function.c: Include stdlib.h.
+ (pad_below): Wrap prototype and definition in ARGS_GROW_DOWNWARD.
+ (reposition_prologue_and_epilogue_notes): Add parentheses
+ around assignment used as truth value.
+
+ * integrate.c (expand_inline_function): Wrap variable
+ `cc0_insn' in macro HAVE_cc0.
+
+ * jump.c (jump_optimize): Wrap variable `q' in macro
+ HAVE_cc0. Remove unused variable `prev1'.
+
+ * libgcc2.c (__bb_exit_trace_func): Add parentheses around &&
+ within ||. Fix format specifier in fprintf.
+ (__bb_init_prg): Add parentheses around assignment used as
+ truth value.
+
+ * local-alloc.c: Include stdlib.h.
+ (requires_inout): Add parentheses around assignment used
+ as truth value.
+
+ * loop.c (analyze_loop_iterations): Wrap prototype and definition
+ in macro HAVE_decrement_and_branch_on_count.
+ (insert_bct, instrument_loop_bct): Likewise.
+ (move_movables): Add parentheses around assignment used as
+ truth value.
+ (consec_sets_invariant_p): Likewise.
+ (maybe_eliminate_biv_1): Wrap variable `new' in macro HAVE_cc0.
+
+ * objc/objc-act.c: Include stdlib.h.
+ (lookup_method_in_protocol_list): Wrap empty else-statement body
+ in braces.
+ (lookup_protocol_in_reflist): Likewise.
+ (objc_add_static_instance): Remove unused variables `decl_expr'
+ and `decl_spec'.
+ (get_objc_string_decl): Remove unused variable `decl'.
+ (generate_static_references): Remove unused variables `idecl' and
+ `instance'.
+ (check_protocols): Wrap empty else-statement body in braces.
+
+ * protoize.c: Include stdlib.h.
+ (substr): Add parentheses around assignment used as truth value.
+ (abspath): Likewise.
+ (shortpath): Likewise.
+
+ * regmove.c (fixup_match_1): Add parentheses around assignment
+ used as truth value.
+
+ * reload.c (push_secondary_reload): Remove unused variable `i'.
+ (find_reloads): Add parentheses around assignment used as truth
+ value.
+
+ * reload1.c: Include stdlib.h.
+
+ * rtl.h: Correct typo in prototype of offsettable_memref_p.
+
+ * stmt.c (add_case_node): Add parentheses around assignment used
+ as truth value.
+ (case_tree2list): Likewise.
+
+ * tree.c (valid_machine_attribute): Wrap variable `decl_attr_list'
+ in macro VALID_MACHINE_DECL_ATTRIBUTE. Wrap variable
+ `type_attr_list' in macro VALID_MACHINE_TYPE_ATTRIBUTE.
+ (merge_attributes): Add explicit braces to avoid ambiguous
+ `else'.
+
+ * unroll.c (copy_loop_body): Wrap variable `cc0_insn' in
+ macro HAVE_cc0.
+
+ * varasm.c: Include stdlib.h.
+
+
+ * system.h: Remove sys/stat.h.
+ * gcc.c: Add sys/stat.h.
+
+ * genattr.c: Wrap prototype of `free' in NEED_DECLARATION_FREE.
+ * genattrtab.c: Likewise.
+ * genconfig.c: Likewise.
+ * genemit.c: Likewise.
+ * genextract.c: Likewise.
+ * genflags.c: Likewise.
+ * genopinit.c: Likewise.
+ * genoutput.c: Likewise.
+ * genpeep.c: Likewise.
+ * genrecog.c: Likewise.
+ * tlink.c: Likewise. Also wrap `getenv' in NEED_DECLARATION_GETENV.
+
+Fri Feb 27 11:02:47 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * invoke.texi: Use @itemx for a secondary item in a @table.
+
+ * config/m68k/m68k.md (movsf+1): Optimize moving a CONST_DOUBLE
+ zero.
+
+Thu Feb 26 00:13:21 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * choose-temp.c: Fix handling of sys/file.h to work in libiberty.
+
+Wed Feb 25 23:40:54 1998 Jeffrey A Law (law@cygnus.com)
+
+ * i386.c (struct machine_function): Add new fields for PIC stuff.
+ (save_386_machine_status): Fix argument to xmalloc. Save pic_label_rtx
+ and pic_label_name.
+ (restore_386_machine_status): Corresponding changes.
+ (clear_386_stack_locals): Also clear pic_label_rtx and pic_label_name.
+
+Wed Feb 25 01:31:40 1998 Jeffrey A Law (law@cygnus.com)
+
+ * c-parse.y (undeclared variable error): Tweak error message
+ to be clearer.
+
+Tue Feb 24 23:54:07 1998 Richard Henderson <rth@cygnus.com>
+
+ * flags.h (g_switch_value, g_switch_set): Declare.
+ * alpha.c (override_options): Set g_switch_value=8 if not set.
+ * alpha/elf.h (CC1_SPEC): New.
+ (ASM_SPEC): New.
+ (LINK_SPEC): Pass along the -G value we were given.
+ (LOCAL_ASM_OP): Remove.
+ (ASM_OUTPUT_ALIGNED_LOCAL): Output to .bss or .sbss by size.
+ (MAX_OFILE_ALIGNMENT): New.
+ (BSS_SECTION_ASM_OP, SBSS_SECTION_ASM_OP, SDATA_SECTION_ASM_OP): New.
+ (EXTRA_SECTIONS): Add sbss and sdata.
+ (SECTION_FUNCTION_TEMPLATE): New.
+ (EXTRA_SECTION_FUNCTIONS): Use it.
+ (CTORS_SECTION_FUNCTION, DTORS_SECTION_FUNCTION): Remove.
+ (SELECT_SECTION): Use sdata when small enough.
+ * alpha/linux.h (ASM_SPEC): Remove.
+
+
+Mon Feb 23 15:09:18 1998 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
+ * config.sub (sco5): Fix typo.
+
+Mon Feb 23 18:19:31 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * config/t-linux (LIBGCC1, CROSS_LIBGCC1, LIBGCC1_TEST): Add macros and
+ set to empty.
+ * config/t-linux-aout (LIBGCC1, CROSS_LIBGCC1, LIBGCC1_TEST): Likewise.
+ * config/alpha/t-linux: Remove file.
+ * config/sparc/t-linux: Remove file.
+ * config/m68k/t-linux (LIBGCC1, CROSS_LIBGCC1): Remove.
+ * config/m68k/t-linux-aout (LIBGCC1, CROSS_LIBGCC1): Likewise.
+ * configure.in (alpha*-*-linux-gnulibc1*): Use t-linux instead of alpha/t-linux
+ for tmake_file.
+ (alpha*-*-linux-gnu*): Likewise.
+ (sparc-*-linux-gnulibc1*): Use t-linux instead of sparc/t-linux for tmake_file.
+ (sparc-*-linux-gnu*): Likewise.
+
+Mon Feb 23 10:47:39 1998 Robert Lipe <robertl@dgii.com>
+ * collect2.c (ldd_file_name): Bracket declaration with same
+ manifests as use.
+ (full_real_ld_suffix): Deleted. Variable was calloced and
+ written into, but never read.
+
+1998-02-23 Mike Stump <mrs@wrs.com>
+
+ * configure.in: Add support for i386-wrs-vxworks configuration.
+ * i386/vxi386.h: New file.
+
+Sun Feb 22 21:16:51 1998 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
+
+ * tree.c (contains_placeholder_p): Ensure function always returns
+ a value.
+ * sparc.md (movdi_sp64_insn): Add default case in enumeration switch.
+ (movsf_const_insn, movdf_const_insn, movtf_const_insn): Likewise.
+
+Sun Feb 22 20:58:19 1998 Jeffrey A Law (law@cygnus.com)
+
+ * vms.h (SELECT_SECTION): Use TREE_CODE_CLASS correctly.
+
+1998-02-22 Paul Eggert <eggert@twinsun.com>
+
+ * config/sparc/sol2-sld.h (LINKER_DOES_NOT_WORK_WITH_DWARF2):
+ Define this new symbol.
+ (DWARF2_DEBUGGING_INFO, DWARF_DEBUGGING_INFO): Do not #undef.
+ * toplev.c (main): Do not default to DWARF2_DEBUG with -ggdb if
+ LINKER_DOES_NOT_WORK_WITH_DWARF2 is defined.
+
+Sun Feb 22 20:07:32 1998 Jim Wilson <wilson@cygnus.com>
+
+ * iris5.h (DWARF2_UNWIND_INFO): Define to 0.
+ * iris5gas.h (DWARF2_UNWIND_INFO): Define to 1.
+
+Sun Feb 22 15:29:48 1998 Richard Henderson <rth@cygnus.com>
+
+ * objc/Object.m (-error): Call objc_verror with our va_list.
+
+Sun Feb 22 09:45:39 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * collect2.c (scan_prog_file): Completely cover uses of variable
+ `exports' with macro COLLECT_EXPORT_LIST.
+
+Sat Feb 21 20:36:23 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Fri Feb 20 16:22:13 1998 Michael Meissner <meissner@cygnus.com>
+
+ * sched.c (schedule_block): Remove code to get arguments from hard
+ regs into pseudos early. Same as Aug 25, 1997 change to
+ haifa-sched.c.
+
+1998-02-20 Jason Merrill <jason@yorick.cygnus.com>
+
+ * collect2.c (main): Still handle !do_collecting for non-AIX targets.
+
+1998-02-16 Mark Mitchell <mmitchell@usa.net>
+
+ * toplev.c (rest_of_compilation): Do not defer the output of a
+ nested function.
+
+Fri Feb 20 10:39:47 1998 Michael Tiemann <michael@impact.tiemann.org>
+
+ * ginclude/va-mips.h (va_arg): Remove trailing space after '\'
+ continuation character (line 243).
+
+Fri Feb 20 12:10:26 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * genrecog.c (main): Remove duplicated sentence in emitted comment.
+
+Thu Feb 19 22:36:53 1998 Andrey Slepuhin <pooh@msu.net>
+ David Edelsohn <edelsohn@mhpcc.edu>
+
+ * collect2.c (XCOFF_SCAN_LIBS): Remove.
+ (export_flag): New variable.
+ (export_file): #ifdef COLLECT_EXPORT_LIST.
+ (import_file, exports, imports, undefined): New variables.
+ (libs, cmdline_lib_dirs, libpath_lib_dirs, libpath, libexts): Same.
+ (dump_list, dump_prefix_list, is_in_list): New functions.
+ (write_export_file): $ifdef COLLECT_EXPORT_LIST.
+ (write_import_file, resolve_lib_name): New functions.
+ (use_import_list, ignore_library): Same.
+ (collect_exit): maybe_unlink import_file and #ifdef.
+ (handler): Same.
+ (main): New variable importf, #ifdef exportf. Move parsing of
+ -shared before general argument parsing. Resolve AIX library
+ paths and import libgcc.a symbols. Treat .so shared libraries the
+ same as objects and .a libraries. Create alias for object_lst and
+ increment it instead of original pointer. Scan AIX libraries as
+ objects earlier instead of using scan_libraries. Perform AIX
+ tlink later to resolve templates instead of forking ld.
+ (GCC_OK_SYMBOL): Ensure symbol not in undef section.
+ (GCC_UNDEF_SYMBOL): New macro.
+ (scan_prog_file): Loop for members of AIX libraries. Handle
+ export/import of ctors/dtors.
+ (aix_std_libs): New variable.
+ (scan_libraries, XCOFF): Delete.
+
+Thu Feb 19 22:36:52 1998 Robert Lipe <robertl@dgii.com>
+
+ * collect2.c (full_real_ld_suffix): #ifdef CROSS_COMPILE.
+
+1998-02-19 Mike Stump <mrs@wrs.com>
+
+ * Makefile.in: Use $tooldir for sys-include to match toplevel
+ configure.
+
+Thu Feb 19 01:32:37 1998 Jeffrey A Law (law@cygnus.com)
+ Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * emit-rtl.c (gen_lowpart_common): Suppress last change if __complex__.
+
+ * emit-rtl.c (hard-reg-set.h): Include.
+ (get_lowpart_common): Don't make new REG for hard reg in a
+ class that cannot change size.
+ * Makefile.in (emit-rtl.o): Depend on hard-reg-set.h.
+
+ * combine.c: Revert previous patch.
+
+1998-02-19 Paul Eggert <eggert@twinsun.com>
+
+ * config/sparc/sol2-sld.h: New file.
+ * configure.in (sparc-*-solaris2*): Use it when using the
+ system linker.
+
+Thu Feb 19 00:46:59 1998 Jeffrey A Law (law@cygnus.com)
+
+ * loop.c (force_movables): Fix typo.
+
+Thu Feb 19 08:26:30 1998 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * m88k.h: Change file pattern to match reality.
+
+Wed Feb 18 23:19:52 1998 Jeffrey A Law (law@cygnus.com)
+
+ * varasm.c (output_constant_pool): Fix dumb thinko in last
+ change.
+
+ * pa.h (ASM_OUTPUT_FUNCTION_PREFIX): Correctly translate from
+ a function name to a section name.
+
+1998-02-18 Doug Evans <devans@cygnus.com>
+
+ * tree.h (merge_machine_{type,decl}_attributes): Declare.
+ (split_specs_attrs, strip_attrs): Add prototypes.
+ * tree.c (merge_machine_{type,decl}_attributes): New functions.
+ * c-decl.c (duplicate_decls): Call merge_machine_decl_attributes.
+ Update olddecl's attributes too.
+ * c-common.c (strip_attrs): New function.
+ * c-typeck.c (common_type): Call merge_machine_type_attributes.
+ * varasm.c (make_function_rtl): New target macro REDO_SECTION_INFO_P.
+ (make_decl_rtl): Likewise.
+
+1998-02-18 Jim Wilson <wilson@cygnus.com>
+
+ * c-decl.c (shadow_tag_warned): Call split_specs_attrs.
+
+Wed Feb 18 09:09:50 1998 Jeffrey A Law (law@cygnus.com)
+
+ Remove this change until we can fix it correctly.
+ * collect2.c: Bracket declaration of 'exportf' and
+ 'full_real_ld_suffix'.
+
+Wed Feb 18 08:44:25 1998 Bernd Schmidt <crux@ohara.Informatik.RWTH-Aachen.DE>
+
+ * Makefile.in (STAGESTUFF): Add genrtl.c, genrtl.h and gengenrtl.
+
+Tue Feb 17 23:30:20 1998 Bernd Schmidt <crux@ohara.Informatik.RWTH-Aachen.DE>
+
+ * c-common.c (c_expand_start_cond, c_expand_end_cond,
+ c_expand_start_else): Don't warn about non-ambiguous else even if
+ braces are missing.
+
+Tue Feb 17 23:56:50 1998 Robert Lipe <robertl@dgii.com>
+
+ * sco5.h (ASM_OUTPUT_DOUBLE, ASM_OUTPUT_FLOAT,
+ ASM_OUTPUT_LONG_DOUBLE): Delete. Use the ones from i386.h
+ instead.
+
+Tue Feb 17 22:56:14 1998 Richard Henderson <rth@cygnus.com>
+
+ * combine.c (simplify_rtx): Obey CLASS_CANNOT_CHANGE_SIZE when
+ simplifying a subreg of a hard reg.
+ (expand_compound_operation): Likewise.
+ (force_to_mode): Likewise.
+
+Tue Feb 17 22:37:22 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * fold-const.c: Include "system.h" to get stdlib.h and stdio.h.
+ (lshift_double): Add parentheses around + or - inside shift.
+ (rshift_double): Likewise.
+ (size_int_wide): Explicitly set type of `bit_p' to `int'.
+
+ * Makefile.in (fold-const.o): Depend on system.h.
+
+ * Makefile.in (gcc.o): Depend on system.h, in accordance with last
+ change to gcc.c.
+
+ * haifa-sched.c: Include "system.h" to get <stdlib.h> and <stdio.h>.
+ (BLOCKAGE_RANGE): Add parentheses around arithmetic in operand of |.
+ (sched_note_set): Remove unused parameter `b', all callers changed.
+ (schedule_block): Likewise for `rgn'.
+ (split_hard_reg_notes): Likewise for `orig_insn'.
+ (check_live): Likewise for `trg'.
+ (update_live): Likewise.
+ (check_live_1): Explcitly declare variable `i' as int.
+ (update_live_1): Likewise.
+ (insn_issue_delay): Remove unused variable `link'.
+ (sched_analyze_2): Add default case in enumeration switch.
+ (schedule_insns): Remove unused variable `i'.
+
+ * Makefile.in ($(SCHED_PREFIX)sched.o): Depend on system.h.
+
+Tue Feb 17 22:31:04 1998 Jeffrey A Law (law@cygnus.com)
+
+ * loop.c (rtx_equal_for_loop_p): Add some braces to disambiguate
+ a dangling else clause.
+
+Tue Feb 17 21:28:12 1998 Gavin Koch <gavin@cygnus.com>
+
+ * mips/mips.h (CAN_ELIMINATE): Don't eliminate the frame
+ pointer for the stack pointer in MIPS16 and 64BIT.
+
+Tue Feb 17 21:17:30 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * rtl.h (force_line_numbers, restore_line_number_status): Declare.
+ * emit-rtl.c (force_line_numbers, restore_line_number_status):
+ New functions.
+ * stmt.c (struct nesting): Replace seenlabel with line_number_status.
+ (expand_start_case): Adjust to this change.
+ (check_seenlabel): New function.
+ (pushcase, pushcase_range, expand_endcase): Use it.
+
+Tue Feb 17 10:14:32 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * i386.md (adddi3): Add =!r,0,0,X alternative.
+
+Mon Feb 16 16:13:43 1998 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * rs6000.h (MY_ISCOFF): Add numeric value of U803XTOCMAGIC.
+ * x-aix31 (INSTALL): Delete.
+
+Mon Feb 16 09:24:32 1998 Gavin Koch <gavin@cygnus.com>
+
+ * mips/mips.c (mips_expand_epilogue): Update tsize_rtx if
+ tsize changes to something other than zero.
+
+Mon Feb 16 09:11:48 1998 Gavin Koch <gavin@cygnus.com>
+
+ * ginclude/va-mips.h: Replace casts of pointers to int with
+ casts of pointers to __PTRDIFF_TYPE__.
+
+Mon Feb 16 08:17:14 1998 John Carr <jfc@mit.edu>
+
+ * loop.c (strength_reduce, record_biv, record_giv): Use
+ HOST_WIDE_INT_PRINT_DEC to print CONST_INT values.
+
+1998-02-16 Jason Merrill <jason@yorick.cygnus.com>
+
+ * tree.c (first_rtl_op): New fn.
+ (unsave_expr_now): Use it.
* print-tree.c (print_node): Likewise.
+ * tree.c (has_cleanups): New fn.
+ * fold-const.c (fold, case CLEANUP_POINT_EXPR): Use it. Be more
+ conservative about pushing the cleanup point down.
+ * tree.h: Declare them.
+
+Sun Feb 15 23:28:44 1998 Jeffrey A Law (law@cygnus.com)
- * protoize.c (edit_fn_definition): Fix mispelled local `have_flotsam'.
+ * toplev.c (flag_schedule_reverse_before_reload): Delete variable.
+ (flag_schedule_reverse_after_reload): Likewise.
+ (f_options): Remove reverse scheduling support.
+ * flags.h (flag_schedule_reverse_before_reload): Delete declaration.
+ (flag_schedule_reverse_after_reload): Likewise.
+ * haifa-sched.c (rank_for_schedule): Remove support for reverse
+ scheduling.
- * objc/sendmsg.c (__objc_init_install_dtable): Fix misspelling
- in name of local label `already_initialized'.
+Sun Feb 15 21:33:55 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * winnt/winnt.h (STDC_VALUE): Was misspelled.
+ * gcc.c: Get system includes, prototypes and macros via "system.h"
+ instead of doing it manually. Change all calls of the ctype
+ macros to custom versions defined in "system.h".
- * m68k/ccur-GAS.h (FUNCTION_BOUNDARY): Was misspelled.
+ * system.h: Fix return type of bcmp prototype from `void' to `int'.
+ Make bcopy, bcmp and bzero prototypes explicitly `extern'.
+ Add a prototype for getenv.
- * 1750a.h (DEFAULT_PCC_STRUCT_RETURN): Was misspelled.
+Sun Feb 15 17:05:41 1998 Jim Wilson <wilson@cygnus.com>
-Mon May 15 23:41:25 1995 Jeffrey A. Law <law@snake.cs.utah.edu>
+ * mips/mips.h (INITIAL_ELIMINATION_OFFSET): Readd Jun 6 change.
- * pa.h (ASM_OUTPUT_EXTERNAL_LIBCALL): Make sure to encode section
- info for all libcalls.
+Sun Feb 15 15:23:15 1998 John Carr <jfc@mit.edu>
-Mon May 15 20:58:00 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * alias.c: Include <stdlib.h> and <string.h>.
+ (init_alias_analysis): Pass NULL_RTX instead of 0 to record_set.
- * collect2.c (strstr): Define ifndef POSIX.
+Sat Feb 14 11:23:09 PST 1998 Jeff Law (law@cygnus.com)
- * defaults.h (SUPPORTS_WEAK): Provide default.
- * aoutos.h, sparc/sunos4.h: Don't support weak symbols.
- * netbsd.h, svr4.h, i386/freebsd.h, i386/osfrose.h,
- m88k/m88k.h: Define ASM_WEAKEN_LABEL instead of WEAK_ASM_OP.
- * c-pragma.h: Check ASM_WEAKEN_LABEL instead of WEAK_ASM_OP.
- HANDLE_PRAGMA_WEAK is never defined in a tm.h file.
- * c-decl.c (duplicate_decls): Propagate DECL_WEAK.
- * tree.h (DECL_WEAK): New macro.
- (tree_decl): Add weak_flag.
- * varasm.c (assemble_start_function): Declare the symbol weak if
- appropriate.
- (assemble_variable): Ditto.
- (assemble_alias): Ditto. Mark the decl as written.
- (declare_weak): Check for weak declaration after definition.
- Set DECL_WEAK.
- (weak_finish): Use ASM_WEAKEN_LABEL.
- * libgcc2.c: The C++ free-store management functions are weak
- aliases on targets that always support them.
+ * version.c: Bump for snapshot.
-Mon May 15 19:01:43 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Sat Feb 14 05:08:21 1998 Richard Earnshaw (rearnsha@arm.com)
- * configure (out_object_file): New variable; put value in Makefile.
- * Makefile.in (out_object_file): Use in place of aux-output.o.
+ * arm.md (movsfcc): Also validate operands[3] when compiling hard
+ float.
+ (movdfcc): Only accept fpu_add_operand for operands[3].
- * fold-const.c (const_binop): Don't pass OVERFLOW to force_fit_type
- if type is unsigned.
+ * arm/t-semi (STMP_FIXPROTO): Define to nothing.
+ * arm/t-semiaof (STMP_FIXPROTO): Likewise.
-Mon May 15 18:48:26 1995 Paul Eggert <eggert@twinsun.com>
+Sat Feb 14 02:02:41 1998 Jeffrey A Law (law@cygnus.com)
- * install.sh (transformbasename): Fix misspelling.
+ * varasm.c (output_constant_pool): Bring back 'done' label inside
+ an appropriate #ifdef.
- * tahoe.h (CHECK_FLOAT_VALUE): Fix misspelling of OVERFLOW parameter.
+ * bitmap.c (bitmap_element_allocate): Wrap variable 'i' in an
+ appropriate #ifdef.
+ (bitmap_copy, bitmap_operation): Likewise.
+ * combine.c (combinable_i3pat): Similarly for 'src'.
+ * function.c (fixup_var_refs_1): Similarly for 'outerdest'.
+ (locate_and_pad_parm): Similarly for 'reg_parm_stack_space'.
+ * regclass.c (copy_cost): Similarly for 'secondary_class'.
+ * reload.c (make_memloc): Simliarly for 'i'.
+ (find_reloads_address_1): Similarly for 'link'.
+ * reload1.c (reload): Similarly for 'previous_frame_pointer_needed'.
+ (emit_reload_insns): Similarly for 'second_reloadreg'.
+ * unroll.c (iteration_info): Similarly for 'v'.
- * i386.h (VALID_MACHINE_{DECL,TYPE_ATTRIBUTE): Fix typo.
+ * caller-save.c (insert_save_restore): Remove unused variable 'i'.
+ * calls.c (expand_call): Similarly for 'i'.
+ (emit_library_call, emit_library_call_value): Similarly for 'mode'.
+ * fold-const.c (strip_compund_expr): Similarly for 'type'.
+ * function.c (fixup_var_refs_1): Similarly for 'width'.
+ (fixup_memory_subreg): Similarly for 'saved'.
+ (locate_and_pad_parm): Similarly for 'boundary_in_bytes.'
+ (setjmp_protect): Similarly for 'sub'.
+ (thread_prologue_and_epilogue_insns): Similarly for 'insn'.
+ * loop.c (record_giv): Similarly for 'p'.
+ (combine_givs): Similarly for 'temp_iv'.
+ (indirect_jump_in_function_p): Similarly for 'is_indirect_jump'.
+ * recog.c (validate_replace_rtx_1): Similarly for 'width'.
+ * tree.c (get_set_constructor_bytes): Similarly for 'vals'.
+ * unroll.c (unroll_loop): Similarly for 'copy'.
+ (iteration_info): Similarly for 'b'.
+ * varasm.c (assemble_string): Similarly for 'i'.
+ * i386.h (LEGITIMIZE_ADDRESS): Similarly for 'orig_x'.
- * fx80.h (CHECK_FLOAT_VALUE): Fix misspelled use of parameter.
+1998-02-13 Martin von Loewis <loewis@informatik.hu-berlin.de>
- * a29k.c (spec_reg_operand): Fix misspelling of `default:'.
+ * c-lang.c (lang_print_xnode): New function.
+ * objc/objc-act.c (lang_print_xnode): Likewise.
+ * print-tree.c (print_node): Call it
-Mon May 15 18:36:41 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+Fri Feb 13 14:38:34 1998 Jim Wilson <wilson@cygnus.com>
- * m68k.md (b{eq,ne,ge,lt}0_di): Fixed for non-MOTOROLA syntax.
- * m68k/xm-mot3300.h (alloca): Extern decl added for non-GNU compiler.
+ * dwarf2out.c (decl_scope_node): New type.
+ (decl_scope_table): Change type to use it.
+ (decl_scope_table_allocated, decl_scope_depth): Change type to int.
+ (push_decl_scope): Use new type. New locals containing_scope, i.
+ Add code to handle setting previous field.
+ (scope_die_for): Change type of local i to int. Add code to use
+ previous field.
+ (dwarf2out_init): Use new type.
-Mon May 15 13:14:29 1995 Per Bothner <bothner@kalessin.cygnus.com>
+1998-02-13 Jason Merrill <jason@yorick.cygnus.com>
- * cppexp.c (cpp_reader): Test for '#' (start of assertion) *after*
- skipping hspace, not before.
+ * except.c (emit_throw): Lose throw_used.
-Mon May 15 08:13:54 1995 Pat Rankin (rankin@eql.caltech.edu)
+Fri Feb 13 20:36:05 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * vmsconfig.com: Construct options.h and specs.h to #include
- all "*/lang-{options|specs}.h" files found.
+ * sched.c (update_flow_info, REG_WAS_0): Ignore if setting insn
+ was deleted.
+ * haifa-sched.c (update_flow_info, REG_WAS_0): Likewise.
-Sun May 14 21:32:49 1995 Doug Evans <dje@cygnus.com>
+Fri Feb 13 12:18:40 1998 Jeffrey A Law (law@cygnus.com)
- * alpha/alpha.md (movsicc, case NE): Don't generate unrecognizable
- insn.
- (movdicc, case NE): Likewise.
+ * genextract.c (main): Fix typo.
-Sun May 14 15:44:54 1995 Jim Wilson <wilson@mole.gnu.ai.mit.edu>
+Fri Feb 13 08:41:49 1998 Robert Lipe <robertl@dgii.com>
- * unroll.c (unroll_loop): Make local_regno have size
- max_reg_before_loop. Don't do local register optimization if
- copy_end has no INSN_LUID.
+ * c-lang.c (finish_file): Bracket declaration of static_ctors,
+ static_dtors.
-Sun May 14 10:38:23 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * calls.c (expand_call): Bracket declaration of 'rtx_before_call',
+ 'old_stack_arg_under_construction'
+ (emit_library_call): Bracket declaration of 'upper_bound',
+ 'lower_bound', 'i', 'reg_parm_stack_space'
+ (emit_library_call_value): Likewise.
+ (store_one_arg):
- * objc-act.c (start_method_def): Mark _self as possibly unused.
+ * collect2.c: include <unistd.h> when appropriate.
+ Bracket declaration of 'exportf' and 'full_real_ld_suffix'.
- * configure: Create specs.h and options.h from */lang-specs.h
- and */lang-options.h.
- Set lang_specs_files and lang_options_file variables in Makefile.
- * Makefile.in (lang_{specs,options}_files): New variables.
- (gcc.o): Depends on $(lang_specs_files).
- (toplev.o): Depends on $(lang_options_file); merge two dep lists.
- (distclean): Remove spes.h and options.
- * gcc.c (default_compilers): Remove entries for Ada, C++, Chill,
- and Fortran; #include specs.h instead.
- * toplev.c (lang_options): Remove entries for Ada, C++, and Fortran;
- include options.h instead.
+ * emit-rtl.c (prev_cc0_setter): Remove unused variable 'link'.
-Sat May 13 23:11:21 1995 DJ Delorie <dj@delorie.com>
+ * explow.c (plus_constant_for_output_wide): Remove unused variable
+ 'code'.
+ (memory_address): Remove unused variable 'orig_x'.
- * configure (i[345]86-go32-msdos, i[345]86-*-go32): New targets.
+ * genattrtab.c (make_canonical): Remove unreferenced label 'cond:'.
+ (write_const_num_delay_slots): Remove unused variable 'i'.
-Sat May 13 10:58:38 1995 Jim Wilson <wilson@cygnus.com>
+ * genopinit.c (main): Remove unused variables 'dummy', 'insn_ptr'.
+ (gen_insn): Remove unused variable 'obstack_ptr'.
- * loop.c (record_giv): When computing replaceable, use
- back_branch_in_range_p instead of looking for branches to named
- labels.
- * loop.h (back_branch_in_range_p): Declare.
- * unroll.c (back_branch_in_range_p): No longer static.
+ * libgcc2.c (__bb_exit_func): Remove unused variables 'ret',
+ 'j', 'tmp', 'i'.
+ (__bb_exit_trace_func): Remove unused variable 'e'.
+
+ * optabs.c (expand_binop): remove unused variables 'lhs', 'rhs',
+ 'funexp'.
+ (expand_unop): Remove unused variable 'funexp'.
+ (expand_complex_abs): Remove unused variable 'funexp'.
+ (init_optabs): Bracket declaration of 'j'.
+ (init_complex_libfuncs): Deleted. Dead static function.
+
+ * profile.c (branch_prob): Remove unused variables 'insn', 'dest'.
+
+ * reg-stack.c: Fix typo in proto for 'get_asm_operand_lengths'
+ (reg_to_stack): 'initialized', 'before_function_beg'
+ explictly type as ints instead of defaulting.
+ (emit_swap_insn): Remove unused variable 'i2'.
+ (compare_for_stack_reg): Remove unused variable 'src_note'.
+
+ * rtlanal.c (computed_jump_p): Remove unused variable 'computed_jump'.
+
+ * sched.c (actual_hazard): Bracket declaration of 'this_cost'.
+
+ * stmt.c (add_case_node): Add parens for assignment used as truth.
+ (all_cases_count): Remove unused variable 'count_high'.
+ (mark_seen_cases): Remove unused variable 'i'.
+ (check_for_full_enumeration_handling): Remove unused variable 't'.
+ Bracket declaration of 'all_values', 'l'.
+
+ * tlink.c: Include <stdlib.h>, <unistd.h>, <string.h>/<strings.h>.
+
+ * varasm.c (assemble_string): Remove unused variable 'i'.
+ (immed_double_const): Remove unused variable 'in_current_obstack'.
+ (immed_real_const_1): Likewise.
+ (output_constant_pool): Remove unreferenced label 'done'.
+ (output_constant): Remove unused variable 'x'.
+
+ * i386/i386.h (ENCODE_SECTION_INFO): TREE_PUBLIC is an int, not
+ a string.
+
+ * i386/sco5.h (ASM_OUTPUT_ASCII): Add parens for assignment used
+ as truth.
+
+Fri Feb 13 10:21:41 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * combine.c (can_combine_p): Handle USEs in PARALLELs.
+
+Fri Feb 13 01:34:14 1998 H.J. Lu (hjl@gnu.org)
+
+ * config/linux.h (LIB_SPEC): Add -lc for -shared if
+ USE_GNULIBC_1 is not defined.
+ * config/sparc/linux.h; Ditto.
+
+ * config/sparc/linux64.h (LIB_SPEC): Add -lc for -shared.
+
+ * config/alpha/linux-elf.h (LIB_SPEC): New. Defined if
+ USE_GNULIBC_1 is not defined.
+
+Fri Feb 13 01:29:29 1998 Franz Sirl <franz.sirl-kernel@lauterbach.com>
+
+ * rs6000/sysv4.h (ENDFILE_SPEC): add missing %(endfile_linux)
+ for -mcall-linux
+
+Fri Feb 13 01:23:46 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * system.h: New file to get common systems includes and various
+ definitions and declarations based on autoconf macros.
+
+Fri Feb 13 00:46:19 1998 Jeffrey A Law (law@cygnus.com)
+
+ * cccp.c (new_include_prefix): Correctly handle -I./.
+
+Thu Feb 12 20:16:35 1998 Michael Meissner <meissner@cygnus.com>
+
+ * rs6000.md: Replace gen_rtx (CONST_INT,...) with GEN_INT.
+
+Thu Feb 12 16:45:17 1998 Robert Lipe <robertl@dgii.com>
+
+ * expr.c (expand_assignment): Correct typo exposed by -Wall.
+ offset should have been a truth value, not an assignment.
+
+Thu Feb 12 15:26:50 1998 Jeffrey A Law (law@cygnus.com)
+
+ * cse.c (delete_dead_from_cse): If a libcall produces a constant
+ result and that result can be substituted into SET_SRC of the
+ insn with the REG_RETVAL note, then perform the substitution
+ and delete the libcall.
+
+Thu Feb 12 14:04:09 1998 Gavin Koch <gavin@cygnus.com>
+
+ * mips.md (trucndihi2,truncdiqi2): Change these to support
+ mips16.
+
+Thu Feb 12 11:34:55 1998 Gavin Koch <gavin@cygnus.com>
+
+ * mips/mips.c (movdi_operand): Direct referances to symbols
+ that arn't mips16 consts in mips16 mode arn't valid operands.
+
+ * mips/mips.c (mips_move_2words): Add gprel handling.
+
+Thu Feb 12 11:18:37 1998 Gavin Koch <gavin@cygnus.com>
+
+ * mips.md (extendsidi2): Allow extension to/from a non-mips16
+ register.
+
+Thu Feb 12 00:04:16 1998 Marc Lehmann <pcg@goof.com>
+
+ * i386.c: Conditionally include <stdlib.h>, <string.h>, and
+ <strings.h>.
+
+Wed Feb 11 11:43:34 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (WARN_CFLAGS): New variable.
+ (bootstrap, bootstrap2, bootstrap3, bootstrap4): Use it.
+
+1998-02-11 Mark Mitchell <mmitchell@usa.net>
+
+ * config/i386/i386.c (reg_mentioned_in_mem): Don't abort when
+ falling through default case in switch.
+ (i386_aligned_p): Likewise.
+
+Wed Feb 11 12:59:56 1998 Lee Iverson <leei@Canada.AI.SRI.COM>
+
+ * mips/mips.h (mips_abi_string): Correct typo in comment.
+
+Wed Feb 11 08:29:56 1998 Gavin Koch <gavin@cygnus.com>
+
+ * mips/mips.md (movdi): These PLUS's need to be Pmode.
+
+Wed Feb 11 01:47:54 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Makefile.in (dwarf2out.o, emit-rtl.o, jump.o, cse.o, unroll.o,
+ reorg.o, regmove.o): Depend on insn-codes.h, it gets included
+ indirectly via expr.h.
+
+Wed Feb 11 01:44:13 1998 Richard Henderson <rth@cygnus.com>
+
+ * stor-layout.c (layout_type): Do upper - lower in the native type,
+ so as to properly handle negative indices.
+
+Wed Feb 11 01:35:55 1998 Robert Lipe <robertl@dgii.com>
+
+ * except.c (start_dynamic_cleanup): Remove unused variable 'dhc'.
+ (expand_eh_region_start_tree): Remove unused variable 'note'.
+ (exception_optimize): Remove unused variable 'regions'.
+ (expand_builtin_eh_stub): Remove unused variable 'temp'.
+ (copy_eh_entry): Deleted. Dead function.
+
+ * expr.c (move_block_to_reg) Bracket declaration of 'pat' and
+ 'last' with same #if HAVE_load_multiple as use of it.
+ (move_block_from_reg): Likewise.
+ (emit_move_insn_1): Remove unused variable 'insns'.
+ (store_constructor): Bracket declaration of startb, endb with
+ #if TARGET_MEMFUNCTIONS. Remove unused variables 'set_word_size'
+ 'target', and 'xtarget'.
+ (expand_builtin_setjmp): Remove unused variables 'op0',
+ 'next_arg_reg', 'old_inhibit_defer_pop'.
+ (expand_builtin): Remove unused variable 'offset'.
+ (do_store_flag): Remove unused variables 'pattern', 'jump_pat'.
+ (emit_queue): Add parens for assignment used as conditional.
+ (expand_expr): case TARGET_EXPR: Remove unused variable 'temp'.
+
+Wed Feb 11 01:30:49 1998 Marc Lehmann <pcg@goof.com>
+
+ * i386.c: Added include for recog.h.
+ (override_options): Removed unused variable p. Initialized regno to
+ avoid warning.
+ (order_regs_for_local_alloc): Initialized regno to avoid warning.
+ (legitimize_address): Likewise for 'other'.
+ (i386_aligned_reg_p): Added default case with abort ().
+ (print_operand): Likewise.
+ (reg_mentioned_in_mem): Likewise.
+ (ix86_expand_binary_operator): Removed unused variables i & insn.
+ (ix86_expand_unary_operator): Removed unused variable insn.
+ (output_fp_cc0_set): Removed unused variable unordered_label.
+
+Wed Feb 11 01:23:03 1998 John F. Carr <jfc@mit.edu>
+
+ * i386.c, i386.h, i386.md: Change gen_rtx (X, ...) to gen_rtx_X (...).
+ Use GEN_INT instead of gen_rtx (CONST_INT). Make printf arguments
+ and format string match.
+
+Wed Feb 11 01:17:39 1998 Jeffrey A Law (law@cygnus.com)
+
+ * flow.c (life_analysis): Do not conside the stack pointer live at
+ the end of a function if the fucntio ncalls alloca.
+ (mark_used_regs): Similarly.
+
+1998-02-10 John F Carr <jfc@mit.edu>
+
+ * config/sparc/sparc.md (movdi_v8plus): Output stx on alternative
+ 1, fzero on alternative 8.
+
+Tue Feb 10 09:02:19 1998 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * rs6000.c (setup_incoming_varargs): Always set rs6000_sysv_varargs_p.
+
+Tue Feb 10 03:35:43 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * reload.c (find_reloads_toplev): Handle arbitrary non-paradoxical
+ SUBREGs of CONST_INTs.
-Sat May 13 06:47:11 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Mon Feb 9 17:52:36 1998 John Carr <jfc@mit.edu>
- * combine.c (simplify_shift_count, case LSHIFTRT): Don't merge
- shifts of different modes if first is any right shift.
+ * mips.c (print_operand, function_prologue): Make printf format
+ match argument type.
-Sat May 13 05:39:09 1995 Richard Earnshaw (rearnsha@armltd.co.uk)
+Mon Feb 9 02:37:25 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * configure (arm-semi-aout): New configuration.
- * config.sub: Add support for semi-hosted ARM.
- * arm/t-semi, arm/semi.h: New files.
+ * alpha.c (alpha_return_addr): Remove unused variable `first'.
+ (alpha_ra_ever_killed): Remove unused variables `ra' and `i'.
+ (output_epilog): Remove unused variable `frame_size_from_reg_save'.
-Fri May 12 21:51:22 1995 Doug Evans <dje@cygnus.com>
+Sun Feb 8 14:56:03 1998 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
- * flow.c (find_basic_blocks): Only perform n_basic_blocks sanity
- check on first pass, and on second pass ensure it has the correct
+ * loop.c (strength_reduce): When placing increment for auto-inc
+ case, do comparison in loop order.
+
+Sun Feb 8 13:21:38 1998 John Carr <jfc@mit.edu>
+
+ * bitmap.c (bitmap_debug_file): HOST_PTR_PRINTF converts a pointer,
+ not a HOST_WIDE_INT.
+
+ * calls.c (expand_call): Change test of expand_inline_function
+ return value to stop compiler warning.
+
+ * genattrtab.c (RTL_HASH): Cast pointer to long, not HOST_WIDE_INT.
+
+Sun Feb 8 12:04:24 1998 Jim Wilson (wilson@cygnus.com)
+ Jeff Law (law@cygnus.com)
+
+ * regmove.c: Fix various minor formatting problems.
+ (optimize_reg_copy_1): Stop search at CALL_INSNs if flag_exceptions
+ is true. Make end of basic block tests consistent through regmove.c.
+ (optimize_reg_copy_2, optimize_reg_copy_3): Likewise.
+ (fixup_match_2, fixup_match_1, regmove_optimize): Likewise.
+
+Sun Feb 8 01:49:18 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * gansidecl.h: Check for a conflicting macro definition before
+ attempting to prototype bcopy, bcmp or bzero.
+
+Sun Feb 8 00:09:59 1998 Jeffrey A Law (law@cygnus.com)
+
+ * expr.c (clear_pending_stack_adjust): Handle case where a function
+ calls alloca, but the user has specified -fomit-fframe-pointer.
+
+ * function.c (assign_parms): Fix typo in last change.
+
+Sat Feb 7 23:54:29 1998 Robert Lipe <robertl@dgii.com>
+
+ * gcc.c: Include <strings.h>/<string.h>, <stdlib.h>, <unistd.h>,
+ <fcntl.h>.
+ (free_path_suffix): Remove unreferenced static function.
+ (process_command): Remove unused variable temp.
+ (default_arg): Remove unused variable i.
+ (do_spec_1): Add parens for assignment used as truth value.
+ (main): Likewise.
+ (validate_all_switches): Likewise.
+ (main): Remove unused variables i, first_time>
+
+ * c-common.c: Include <stdlib.h> and <string.h>/<strings.h>.
+
+ * calls.c (expand_call): Remove unused variables funtree,
+ n_regs, and tmpmode.
+
+ * dbxout.c, except.c: Include <string.h>/<strings.h>.
+
+ * explow.c: (plus_constant_for_output_wide) Removed unused
+ variable all_constant.
+
+ * c-decl.c, genattr.c, genattrtab.c, getconfig.c, genemit.c
+ genextract.c, genflags.c, genopinit.c genoutput.c, genpeep.c,
+ genrecog.c, global.c, integrate.c , stupid.c : Include
+ <stdlib.h>.
+
+ * genextract.c: (walk_rtx) Remove unused variable link.
+
+ * genrecog.c: (concat) Remove unreferenced static function.
+
+ * prefix.c: Include <string.h>/<strings.h>, <stdlib.h>
+
+ * stmt.c: Include <stdlib.h>.
+ (expand_asm_operands): Remove unused variable val1.
+ (expand_return): Remove unused variable block.
+ (pushcase): Remove unused variables l and n.
+ (pushcaserange): Likewise.
+
+ * unroll.c (unroll_loop): Remove unused variable temp.
+
+Sat Feb 7 23:46:09 1998 Greg McGary <gkm@gnu.org>
+
+ * c-decl.c (pushdecl): Set DECL_ORIGINAL_TYPE once only.
+
+Sat Feb 7 15:11:28 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * aclocal.m4 (GCC_FUNC_PRINTF_PTR): New macro to test the printf
+ functions for whether they support the %p format specifier.
+ * acconfig.h (HOST_PTR_PRINTF): Insert stub for autoconf.
+ * configure.in (GCC_FUNC_PRINTF_PTR): Use it.
+ * configure, config.in: Rebuild.
+
+Fri Feb 6 14:20:16 1998 Jim Wilson <wilson@cygnus.com>
+
+ * function.c (assign_parms): New variable named_arg, with value
+ depending on STRICT_ARGUMENT_NAMING. Use instead of ! last_named.
+
+Fri Feb 6 14:34:28 1998 Gavin Koch <gavin@cygnus.com>
+
+ * mips/t-r3900: New - same as t-ecoff but eliminate
+ multilibs: mips1 and mips3.
+ * configure.in (tx39*): Use new mips/t-r3900.
+ * configure: Rebuild.
+ * mips/r3900.h (MULTILIB_DEFAULTS): Eliminate mips1.
+
+1998-02-06 Jason Merrill <jason@yorick.cygnus.com>
+
+ * dwarf2out.c: Add old_args_size.
+ (dwarf2out_args_size): Use it.
+ (dwarf2out_begin_prologue): Initialize it.
+ (dwarf2out_stack_adjust): If !asynchronous_exceptions, save up
+ pushed args until we see a call.
+ * final.c (final_scan_insn): Hand CALL_INSNs off to the dwarf2 code
+ before outputting them.
+
+1998-02-06 Kriang Lerdsuwanakij <lerdsuwa@scf.usc.edu>
+
+ * cplus-dem.c (demangle_template_template_parm): New function.
+ (demangle_template): Handle template template parameters.
+
+1998-02-02 Mark Mitchell <mmitchell@usa.net>
+
+ * calls.c (expand_call): Don't confuse member functions named
+ realloc, setjmp, and so forth with the standard library
+ functions of the same names.
+
+Thu Feb 5 21:59:49 1998 Jeffrey A Law (law@cygnus.com)
+
+ * stmt.c (expand_asm_operands): Correctly identify asm statements
+ no output operands.
+
+Thu Feb 5 21:56:06 1998 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * c-common.c (decl_attributes): Flag unrecognized attribute
+ functions as warnings instead of as errors.
+
+1998-02-05 Marc Lehmann <pcg@goof.com>
+
+ * integrate.c (INTEGRATE_THRESHOLD): Inline only small functions
+ when -Os is specified.
+ * toplev.c (main): Don't disable flag_inline_functions anymore when
+ -Os is in effect.
+
+Fri Feb 6 00:27:36 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * regmove.c: Update.
+ * flags.h (flag_regmove): Declare.
+ * rtl.h (optimize_reg_copy_1, optimize_reg_copy_2): Don't declare.
+ * local-alloc.c (optimize_reg_copy_1, optimize_reg_copy_2):
+ Moved into regmove; changed caller.
+ * toplev.c (rest_of_compilation): Call regmove_optimize also for
+ expensive_optimizations.
+
+Thu Feb 5 13:38:42 PST 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Thu Feb 5 01:45:19 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+ Undo this change (the problem was actually in reload):
+ Fri Jan 23 23:28:59 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.md (movqi_i+1): New peephole.
+
+Tue Feb 3 01:11:12 1998 Jeffrey A Law (law@cygnus.com)
+
+ * jump.c (jump_optimize): Lose calls to modified_in_p they are
+ not needed anymore due to changes elsewhere in jump.c.
+
+ * jump.c (jump_optimize): Fix first arg to modified_in_p in
+ previous change.
+
+Mon Feb 2 19:18:14 1998 Richard Henderson <rth@cygnus.com>
+
+ * expr.c (expand_builtin_setjmp): Accept two new arguments for
+ the labels to branch to on first and subsequent executions. Don't
+ play with __dummy. Rename `setjmp' insn to `builtin_setjmp_setup',
+ and provide it with the jmp_buf. Use only one of
+ `builtin_setjmp_receiver' or `nonlocal_goto_receiver',
+ and provide the former with the target label.
+ (expand_builtin) [BUILTIN_SETJMP]: Generate a label for use by setjmp.
+ (expand_builtin) [BUILTIN_LONGJMP]: Split out to ...
+ (expand_builtin_longjmp): ... here. Recognize a `builtin_longjmp'
+ insn to replace all of the normal nonlocal_goto code. Don't play
+ with __dummy. Correct arguments to nonlocal_goto.
+ * expr.h (expand_builtin_setjmp): Update prototype.
+ * except.c (start_dynamic_handler): When using builtin_setjmp,
+ generate more accurate flow information.
+
+ * alpha.md (nonlocal_goto_receiver_osf): Delete.
+ (nonlocal_goto_receiver_vms): Rename to nonlocal_goto_receiver.
+ (builtin_longjmp, builtin_setjmp_receiver): New.
+ * sparc.md (update_return): Disambiguate unspec number.
+ (nonlocal_goto): Rearrange arguments to match caller in except.c.
+ (builtin_setjmp_setup): Rename from setjmp. Match and ignore the
+ jmp_buf operand.
+ * mips.md (nonlocal_goto_receiver, builtin_setjmp_receiver): Remove.
+ (builtin_setjmp_setup*, builtin_longjmp): New.
+
+Mon Feb 2 16:43:10 1998 John Carr <jfc@mit.edu>
+
+ * mips.md: Change gen_rtx (CONST_INT) to GEN_INT.
+
+Mon Feb 2 13:06:47 1998 Jim Wilson <wilson@cygnus.com>
+
+ * vmsconfig.com: Remove bytecode references.
+
+1998-01-30 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * dwarf2out.c (dwarf2out_frame_init): Undo last change, so that
+ -fno-sjlj-exceptions works for a target that defines
+ DWARF2_UNWIND_INFO as zero.
+
+ * regmove.c (fixup_match_1): Undo last change which removed some
+ "useless" code, and add a comment explaining this.
+
+Mon Feb 2 10:47:14 1998 Gavin Koch (gavin@cygnus.com)
+
+ * mips.c (mips_expand_prologue): Change uses of TARGET_64BIT
+ to TARGET_LONG64.
+
+Mon Feb 2 10:38:41 1998 Klaus Kaempf <kkaempf@progis.de>
+
+ * makefile.vms: Remove bytecode references.
+ Create genrtl files.
+
+Mon Feb 2 02:08:04 1998 Michael P. Hayes <michaelh@ongaonga.chch.cri.nz>
+
+ * jump.c (jump_optimize): Allow conditional loading of floating point
+ constants and constants from memory. Reinstalled modified_in_p tests.
+
+Mon Feb 2 01:38:39 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * loop.c (get_condition): Handle sign-extended constants.
+
+Mon Feb 2 01:22:46 1998 Hans-Peter Nilsson <hp@axis.se>
+
+ * expr.c (emit_push_insn): Add code to use movstrti if present.
+
+ * expr.c (emit_push_insn): Use same max-move-amount for movstrhi
+ and movstrqi as in emit_block_move ().
+
+Mon Feb 2 00:09:52 1998 Toon Moene <toon@moene.indiv.nluug.nl>
+
+ * config/m68k/x-next: Remove /NextDeveloper/Headers from
+ the directories to fixinclude - /usr/include is a link
+ to it and hence its contents are fixed by default.
+
+Sun Feb 1 14:15:33 1998 Franz Sirl <franz.sirl-kernel@lauterbach.com>
+
+ * rs6000/linux.h: define JUMP_TABLES_IN_TEXT_SECTION
+
+Sun Feb 1 13:01:15 1998 Klaus Kaempf <kkaempf@progis.de>
+
+ * cccp.c (main): Predefine __VMS_VER on VMS.
+
+Sun Feb 1 12:39:53 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * expr.c (get_inner_reference): Use sbitsizetype for type sizes.
+ * fold-const.c (size_int): Replace with
+ (size_int_wide).
+ (make_bit_field_ref): Use bitsize_int for bit position.
+ * stor-layout.c (sizetype): Delete.
+ (sizetype_tab, sbitsizetype, ubitsizetype): Declare.
+ (layout_record, layout_union, layout_type):
+ Use bitsize_int for bit size.
+ (set_sizetype): New function.
+ (make_signed_type, make_unsigned_type): Use it.
+ * c-decl.c (init_decl_processing): Likewise.
+ * tree.h (size_int): Don't delcare, #define.
+ (size_int_wide, sizetype_tab, sbitsize, ubitsize): Declare.
+ (set_sizetype): Declare.
+ (bitsize_int, size_int_2, BITS_PER_UNIT_LOG, sizetype, bitsizetype):
+ Define.
+ * c-typeck.c (c_sizeof, c_sizeof_nowarn, c_size_in_bytes):
+ Convert result to sizetype.
+ (really_start_incremental_init, push_init_level):
+ Set type of constructor_bit_index to sbitsizetype.
+ (push_init_level): Use unsigned arithmetic to determine padding.
+ (output_init_element): Likewise.
+
+Sun Feb 1 03:32:07 1998 Jeffrey A Law (law@cygnus.com)
+
+ * combine.c (simplify_shift_const): Fix typo in last change.
+
+Sun Feb 1 02:50:46 1998 John Carr <jfc@mit.edu>
+
+ * combine.c (simplify_shift_const): (lshiftrt (truncate (lshiftrt)))
+ is (truncate (lshiftrt)).
+
+Sun Feb 1 01:06:53 1998 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_expand_unaligned_load): Use expand_binop properly.
+ Make sure result winds up in TGT.
+ (alpha_expand_unaligned_store): Use expand_binop properly. Allow
+ src to be other than DImode.
+ (alpha_expand_unaligned_load_words): Tidy. Take an offset argument.
+ (alpha_expand_unaligned_store_words): Likewise.
+ (alpha_expand_block_move): Use REGNO_POINTER_ALIGN. Restructure so
+ that source and destination are separately optimized for alignment.
+ (alpha_expand_block_clear): Use REGNO_POINTER_ALIGN.
+
+Sun Feb 1 01:55:09 1998 Jeffrey A Law (law@cygnus.com)
+
+ * mips.md (adddi3_internal_2): Be consistent with adddi3 expander
+ with handling of -32768.
+
+Sun Feb 1 01:48:18 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * aclocal.m4 (GCC_NEED_DECLARATION): Modify macro to accept a
+ shell variable argument instead of only hard coded functions.
+ (GCC_NEED_DECLARATIONS): New macro to accept multiple functions.
+
+ * configure.in: Collapse multiple calls to AC_CHECK_FUNCS into one
+ call. Collapse multiple calls to GCC_NEED_DECLARATION into one
+ call to GCC_NEED_DECLARATIONS (new macro.) Check if we need
+ declarations for bcopy, bcmp and bzero.
+
+ * acconfig.h: Add stubs for bcopy, bcmp and bzero declarations.
+
+ * gansidecl.h: If we have bcopy but don't declare it, then do so.
+ Likewise for bcmp and bzero. Only define macros for bcopy, bcmp,
+ bzero, index and rindex if they aren't already present.
+
+Sat Jan 31 11:26:58 1998 Jeffrey A Law (law@cygnus.com)
+
+ * toplev.c (close_dump_file): Wrap function prototype for
+ argument "func" in PROTO.
+ (dump_rtl): Likewise.
+
+Fri Jan 30 22:30:39 1998 John Carr <jfc@mit.edu>
+
+ * sparc.c (sparc_override_options): Make v8plus and ultrasparc set
+ MASK_V8PLUS.
+ (output_function_epilogue): Omit epilogue if nothing drops through.
+ (output_move_double): Supress int ldd usage on ultrasparc and v9.
+ (registers_ok_for_ldd_peep): Likewise.
+ (print_operand): Supress b,a on ultrasparc. Let Y accept a constant.
+ (ultrasparc_adjust_cost): New function.
+ (sparc_issue_rate): New function.
+ * sparc.h (MASK_VIS, TARGET_VIS): New
+ (MASK_V8PLUS, TARGET_V8PLUS): New.
+ (TARGET_HARD_MUL32, TARGET_HARD_MUL): New.
+ (TARGET_SWITCHES): Add vis and v8plus.
+ (REG_CLASS_FROM_LETTER): Accept d and b for VIS.
+ (REGISTER_MOVE_COST): FP<->INT move cost 12 for ultrasparc.
+ (RTX_COSTS): Use TARGET_HARD_MUL
+ (ADJUST_COST): Call ultrasparc_adjust_cost.
+ (ISSUE_RATE): New.
+ * sparc.md (attr type): Add sload, fpmove, fpcmove. Adjust users
+ of load & fp appropritely.
+ (supersparc function units): Adjust for Haifa.
+ (ultrasparc function units): Likewise.
+ (get_pc_via_rdpc): All v9, not just arch64.
+ (movdi_v8plus, movdi_v8plus+1): New.
+ (adddi3_sp32+1): New.
+ (subdi3_sp32+1): New.
+ (movsi_insn, movsf_const_insn, movdf_const_insn): Know VIS.
+ (addsi3, subsi3, anddi3_sp32, andsi3, and_not_di_sp32): Likewise.
+ (and_not_si, iordi3_sp32, iorsi3, or_not_di_sp32, or_not_si): Likewise.
+ (xorsi3_sp32, xorsi3, xor_not_di_sp32, xor_not_si): Likewise.
+ (one_cmpldi2_sp32, one_cmplsi2): Likewise.
+ (ldd peepholes): Suppress for v9.
+ (return_adddi): Kill redundant test. Arg1 may be arith_operand.
+ (return_subsi): Revmove.
+
+Fri Jan 30 18:30:03 1998 John F Carr <jfc@mit.edu>
+
+ * mips.c (save_restore_insns): Set RTX_UNCHANGING_P in register
+ save/restore MEM rtl.
+
+Fri Jan 30 09:08:16 1998 Jeffrey A Law (law@cygnus.com)
+
+ * configure.in: Check for declaration of abort.
+ * acconfig.h: Corresponding changes.
+ * toplev.c: Use NEED_DECLARATION_ABORT to determine if abort should
+ be declared.
+
+Thu Jan 29 20:26:12 1998 Jeffrey A Law (law@cygnus.com)
+
+ * genattrtab.c (optimize): Define in case PRESERVE_DEATH_INFO_REGNO_P
+ uses it.
+
+Thu Jan 29 09:27:56 PST 1998 Jeff Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Thu Jan 29 10:12:27 1998 Jeffrey A Law (law@cygnus.com)
+
+ * configure.in: Check for atoq and atoll.
+ * rtl.c (read_rtx): Use HAVE_ATOLL and HAVE_ATOQ to select the
+ proper routine for converting ascii into long long values.
+
+Thu Jan 29 01:28:14 1998 Klaus Kaempf <kkaempf@progis.de>
+
+ * cccp.c (SYS$SEARCH, SYS$PARSE): Write as upper-case.
+
+ * vmsconfig.com: Remove bytecode references.
+
+ * alpha/vms.h (PREFIX): Define.
+
+ * alpha/vms.h (ASM_OUTPUT_ALIGNED_COMMON): Remove.
+
+ * am-alpha.h: Don't include alloca for OPEN_VMS.
+
+ * alpha/xm-vms.h (HAVE_CPP_STRINGIFY): Define.
+
+ * alpha/xm-vms.h (INCLUDE_DEFAULTS): Define.
+ (GCC_INCLUDE_DIR): Define
+
+ * make-cc.com, make-cccp.com, make-cc1.com: Removed.
+ * makefile.vms: New file.
+
+ * alpha/vms.h (CPP_PREDEFINES): Remove -Dalpha.
+
+ * alpha.c (output_prolog): Output '.name' directive
+ for minimal traceback information.
+
+ * alpha.c (output_prolog): Don't prepend entry point symbols
+ with '$' on OPEN_VMS.
+
+Thu Jan 29 00:25:35 1998 David S. Miller <davem@tanya.rutgers.edu>
+ Jeffrey A Law (law@cygnus.com)
+
+ * rtl.c (read_rtx): Use atol/atoq based upon disposition of
+ HOST_WIDE_INT.
+
+ * genattrtab.c (write_test_expr): Use HOST_WIDE_INT_PRINT_DEC
+ as needed.
+ * genemit.c (gen_exp): Likewise.
+ * genpeep.c (match_rtx): Likewise.
+ * genrecog.c (write_tree_1): Likewise.
+
+ * c-lex.c (yyprint): Use proper format string based upon
+ disposition of HOST_BITS_PER_WIDE_INT.
+ (yylex): Put casts in right place for args to build_int_2.
+
+Thu Jan 29 00:24:29 1998 Jeffrey A Law (law@cygnus.com)
+
+ * combine.c: Fix typos in Jan27 changes.
+
+Thu Jan 29 00:07:49 1998 Ollivier Robert <roberto@keltia.freenix.fr>
+
+ * i386/freebsd.h (LIB_SPEC): Correctly handle -shared, -p and friends.
+ (LINK_SPEC): Likewise.
+ (STARTFILE_SPEC): Likewise.
+
+1998-01-28 Mike Stump <mrs@wrs.com>
+
+ * rtlanal.c (dead_or_set_regno_p): Ignore REG_DEAD notes after
+ reload completes.
+ * genattrtab.c (reload_completed): Define.
+
+ * m32r.md, mips.md, mn10200.md, mn10300.md, pyr.md: Remove obsolete
+ comments.
+
+Wed Jan 28 20:11:06 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * reload.c (push_reload): If WORD_REGISTER_OPERATIONS, reload the
+ SUBREG_REG if the word count is unchanged, also in the input reload
+ case. Disable non-applicable sanity checks.
+
+Wed Jan 28 20:08:26 1998 Jeffrey A Law (law@cygnus.com)
+
+ * config/t-svr4 (TARGET_LIBGCC2_CFLAGS): Add -fPIC.
+
+Wed Jan 28 20:04:43 1998 Ian Lance Taylor <ian@cygnus.com>
+
+ * i386/t-cygwin32 (LIMITS_H_TEST, LIBGCC2_INCLUDES): Define.
+
+Wed Jan 28 11:45:27 1998 Per Bothner <bothner@cygnus.com>
+
+ * dbxout.c (dbxout_type): For a RECORD_TYPE, check that TYPE_BINFO
+ is a TREE_VEC before trying to use it for baseclasses.
+ (Chill uses the same field for a different purpose.)
+
+ * toplev.c (strip_off_ending): Generalize to endings up to 5 chars.
+
+Tue Jan 27 23:15:55 1998 Lassi A. Tuura <lat@iki.fi>
+
+ * config.sub: More accurate determination of HP processor types.
+
+Tue Jan 27 23:11:11 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * c-lex.c: Include <stdlib.h> and <string.h>/<strings.h>. Add
+ prototype for `handle_sysv_pragma', and make it static. Add
+ parentheses around assignment used as truth value.
+
+ * combine.c (combine_instructions): Protect variable `prev' with
+ macro HAVE_cc0.
+ (can_combine_p): Protect variable `link' with AUTO_INC_DEC.
+ (extract_left_shift): Add parentheses around operand of &.
+ (merge_outer_ops): Avoid an empty body in an else-statement.
+ (gen_rtx_combine): Remove unused variable `i'.
+
+ * sparc/gmon-sol2.c: Include <fcntl.h>. Make return type of
+ function monstartup `void'. Likewise for internal_mcount. Add
+ `static void' prototype for moncontrol. Reconcile sprintf format
+ vs. args.
+
+ * sparc/sparc.c: Include <stdlib.h> and <string.h>/<strings.h>.
+ Make return type of function_arg_slotno explicitly `int'.
+ (reg_unused_after): Add parentheses around assignment used as
+ truth value.
+ (save_regs): Add explicit braces to avoid ambiguous `else'.
+ (function_arg_slotno): Add parentheses around && within ||.
+ (function_arg_pass_by_reference): Likewise.
+ (sparc_flat_output_function_prologue): Reconcile fprintf format
+ vs. args.
+
+ * svr4.h (ASM_OUTPUT_LIMITED_STRING): Add parentheses around
+ assignment used as truth value.
+
+ * cplus-dem.c: Include <stdlib.h>.
+ (demangle_signature): Avoid an empty body in an else-statement.
+ (do_type): Remove unused variable `lvl'.
+
+ * cppexp.c: Don't have <stdlib.h> depend on MULTIBYTE_CHARS.
+ Include <string.h>/<strings.h>.
+ (cpp_lex): Remove unused variable `namelen'.
+ (cpp_lex): Explicitly declare `num_chars' as an int.
+
+ * cpplib.c: Avoid duplicate inclusion of <stdlib.h>, include
+ <unistd.h> instead. Explicitly declare is_system_include
+ returning int.
+ (make_assertion): Remove unused variable `kt'.
+ (cpp_expand_to_buffer): Hide variable `obuf'.
+ (output_line_command): Remove unused variables, `line_end',
+ `line_cmd_buf' and `len'.
+ (macarg): Remove unused variable `arg_start'.
+ (special_symbol): Remove unused variable `i'. Add parentheses
+ around assignment used as truth value.
+ (do_include): Remove unused variables `pcfname' and `retried',
+ hide `pcf' and `pcfbuflimit'.
+ (do_line): Remove unused variable `i'.
+ (finclude): Hide variable `missing_newline'.
+ (cpp_handle_options): Remove unused variable `j'.
+ (read_token_list): Remove unused variable `eofp'.
+ (cpp_error_with_line): Remove unused variable `i'.
+ (cpp_warning_with_line): Likewise.
+ (cpp_pedwarn_with_line): Explicitly declare `column' as int.
+ (cpp_error_from_errno): Remove unused variable `i'.
+
+ * cse.c (invalidate): Add parentheses around assignment used as
+ truth value.
+ (find_best_addr): Move declaration of variable `our_cost' inside
+ the conditional macro where its used.
+ (fold_rtx): Avoid an empty body in an if-statement.
+ (cse_insn): Wrap variables `this_insn_cc0_mode' and
+ `this_insn_cc0' in macro HAVE_cc0.
+
+ * dwarf2out.c: Include <stdlib.h> and <string.h>/<string.h>.
+ (ASM_OUTPUT_DWARF_DATA8): Reconcile format vs. args in fprintf's.
+ (output_uleb128): Likewise.
+ (output_sleb128): Likewise.
+ (output_cfi): Likewise.
+ (output_call_frame_info): Remove unused variables `j', `fde_size'
+ and `fde_pad'.
+ (comp_unit_has_inlines): Hide declaration as per rest of file.
+ (size_of_line_prolog): Correct typo in prototype.
+ (add_arange): Likewise.
+ (output_aranges): Likewise.
+ (add_name_and_src_coords_attributes): Likewise.
+ (gen_array_type_die): Likewise.
+ (gen_inlined_subroutine_die): Likewise.
+ (equate_decl_number_to_die): Remove unused variable `i'.
+ (print_die): Reconcile format vs. args in fprintf's.
+ (print_dwarf_line_table): Likewise.
+ (output_die): Likewise.
+ (output_line_info): Likewise.
+ (add_subscript_info): Avoid an empty body in an else-statement.
+ (gen_subprogram_die): Remove unused variable `fp_loc'.
+
+ * dwarfout.c: Explicitly declare `next_pubname_number' as int.
+ Protect `ordering_attribute' prototype with USE_ORDERING_ATTRIBUTE
+ macro. Protect `src_coords_attribute' prototype with
+ DWARF_DECL_COORDINATES macro. Hide `output_entry_point_die'
+ prototype as in the rest of the file. Likewise for
+ `output_pointer_type_die' and `output_reference_type_die'. Remove
+ prototype for `type_of_for_scope'.
+ (output_unsigned_leb128): Reconcile format vs. args in fprintf.
+ (type_attribute): Add explicit braces to avoid ambiguous `else'.
+
+ * final.c: Include <stdlib.h> and <string.h>/<strings.h>.
+ (shorten_branches): Protect declaration of tmp_length with
+ SHORTEN_WITH_ADJUST_INSN_LENGTH and ADJUST_INSN_LENGTH macros.
+ (profile_function): Protect declaration of `sval' and `cxt'
+ variables with appropriate macros.
+ (final_scan_insn): Likewise for `note' variable. Add explicit
+ braces to avoid empty body in an if-statement.
+ (output_asm_insn): Move variable `i' inside macro conditional
+ where it is used. Add parentheses around assignment used as truth
value.
+ (asm_fprintf) Likewise, likewise.
-Fri May 12 19:23:11 1995 Jim Wilson <wilson@cygnus.com>
-
- * c-typeck.c (build_binary_op): Warn when ~unsigned is compared
- against unsigned, and type promotions result in an unexpected
- answer.
-
-Fri May 12 19:10:21 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
-
- * configure (*-*-gnu*): Always use ELF; set tm_file=${cpu_type}/gnu.h.
- * config/i386/gnu.h: Contents replaced with old i386/gnuelf.h.
- * config/i386/gnuelf.h: File removed.
-
-Fri May 12 17:29:57 1995 Ken Raeburn (raeburn@cygnus.com)
-
- * m68k/lb1sf68.asm (__IMMEDIATE_PREFIX__): Default to #.
- (IMM): New macro.
- (all code): Use IMM macro instead of hardcoding # for immediate
- operands.
-
-Fri May 12 16:52:10 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
-
- * m68k.c (output_scc_di): New function.
- (extend_operator) : Allow DImode target.
- * m68k.h (HARD_REGNO_MODE_OK): Don't allow d7/a0 as DImode reg pair.
- * m68k.md (tstdi, cmpdi, addsi_lshrsi_31, ashldi_extsi): New patterns.
- (extendqidi2, extendhidi2, extendsidi2): Allow "general_operand"
- instead of "register_operand" 0.
- (adddid_sexthishl32, subdid_sexthishl32, subdi_dishl32): Likewise.
- (adddi_dilshr32): Operand 0 constraint changed from "ro" to "do";
- Code generation fixed.
- (adddi_mem, subdi_mem): Fixed for "<" and ">" operand 0.
- (adddi3, subdi3): Operand 2 constraint changed from "ao" to "*ao"
- (ashldi_sexthi, ashrdi_const32): Allow only "register_operand"
- instead of "general_operand" 0.
- (ash[lr]di_const, ash[lr]di3): Allow also 8 and 16 as shift count.
- (subreg1ashrdi_const32): Pattern deleted.
- (subreghi1ashrdi_const32, subregsi1ashrdi_const32): New pattern.
- (lshrsi_31): New implementation.
- (scc0_di, scc_di, beq0_di, bne0_di, bge0_di, blt0_di): New patterns.
-
-Fri May 12 16:50:49 1995 Jeffrey A. Law <law@mole.gnu.ai.mit.edu>
-
- * pa.md (bb patterns): Fix bugs in length computation exposed by
- recent branch shortening and genattrtab changes.
-
-Fri May 12 16:22:27 1995 Ken Raeburn <raeburn@cygnus.com>
-
- * cccp.c (enum node_type): Add T_IMMEDIATE_PREFIX_TYPE.
- (special_symbol): Handle it; emit value of IMMEDIATE_PREFIX.
- (IMMEDIATE_PREFIX): Default to empty string.
- (initialize_builtins): Install __IMMEDIATE_PREFIX__ builtin,
- parallel to __REGISTER_PREFIX__.
-
-Fri May 12 14:40:03 1995 Pat Rankin (rankin@eql.caltech.edu)
-
- * cccp.c: #if VMS, don't define `stat' macro to be VMS_stat.
- Compare enums explicitly to 0 to work around VAX C bug.
- (do_include): Cast alloca's value.
-
- * make-cc1.com (bc_loop): Process comma-separated list rather
- than space-separated one; restore .h suffix stripped by vmsconfig;
- (loop1): More robust handling of directory prefix on file names.
- * vmsconfig.com (TPU makefile.in): Reorganize and reformat code.
- Make generated .opt files have more consistent format (all comma
- separated, excess whitespace eliminated);
- (additional_compiler): New routine.
- (process_makefile): Use it to handle cc1plus via cp/Make-lang.in.
-
-Fri May 12 13:35:07 1995 Doug Evans <dje@cygnus.com>
-
- * arm.h: Replace ARM_REG_PREFIX with REGISTER_PREFIX.
- Replace ARM_COMMENT_CHAR with ASM_COMMENT_START.
- (REGISTER_PREFIX): Define.
- (USER_LABEL_PREFIX, LOCAL_LABEL_PREFIX): Define.
- (SECONDARY_OUTPUT_RELOAD_CLASS): Handle DFmodes only if
- TARGET_HARD_FLOAT.
- (PREDICATE_CODES): Add soft_df_operand.
- * arm.c: Replace ARM_REG_PREFIX with REGISTER_PREFIX.
- Replace ARM_COMMENT_CHAR with ASM_COMMENT_START.
- (arm_asm_output_label): Use USER_LABEL_PREFIX.
- (soft_df_operand): New function.
- * arm.md (movsicc): New pattern.
- (movsfcc, movdfcc, *movsicc_insn, *movsfcc_hard_insn): Likewise.
- (*movsfcc_soft_insn, *movdfcc_insn): Likewise.
- (*movdf_soft_insn): Rewrite.
- (movsi matcher): Fix typo in type attribute.
-
-Fri May 12 10:25:40 1995 Michael Meissner (meissner@cygnus.com)
-
- * i386.h (TARGET_RTD): Use MASK_RTD, not MASK_REGPARM.
- (TARGET_SWITCHES): Add -m{,no-}align-double switch.
- (TARGET_OPTIONS): Add -mregparm= switch to set number of registers
- to use for passing arguments. Add -malign-loops= switch to set
- the alignment for loops. Add -malign-jumps= switch to set the
- alignment for code that is jumped to. Add -malign-functions=
- switch to set the initial alignment of functions.
- (TARGET_REGPARM): Delete, in favor of -mregparm=
- (TARGET_SWITCHES): Delete -mregparm, add -mdebug-arg switches.
- (RETURN_POPS_ARGS): Call i386_return_pops_args to do the real work.
- (VALID_MACHINE_DECL_ATTRIBUTE): Define as function call.
- (VALID_MACHINE_TYPE_ATTRIBUTE): Define as function call.
- (COMP_TYPE_ATTRIBUTES): Define as function call.
- (REGPARM_MAX): Maximum number of regs to use for passing arguments.
- (CUMULATIVE_ARGS): Make this a structure, not an int.
- (INIT_CUMULATIVE_ARGS, FUNCTION_ARG{,_ADVANCE}): Call function.
- (FUNCTION_ARG_PARTIAL_NREGS): Likewise.
- (MAX_CODE_ALIGN): Maximum value to align loops/jumps to.
- (BIGGEST_ALIGNMENT): Return 64 if -malign-double, 32 otherwise.
- (ASM_OUTPUT_ALIGN_CODE): Use value of -malign-jumps= switch.
- (ASM_OUTPUT_LOOP_ALIGN): Use value of -malign-loops= switch.
- (toplevel): Declare all new functions and external variables added
- in i386.c.
-
- * i386.c (i386_regparm_string, i386_regparm): New variables
- for -mregparm= switch to set the number of registers to use for
- passing arguments.
- (i386_align_loops_string, i386_align_loops): New variables for
- -malign-loops= switch to set alignment to use for loops.
- (i386_align_jumps_string, i386_align_jumps): New variables for
- -malign-jumps= switch to set alignment to use for labels that are
- jumped to.
- (override_options): Support new switches.
- (i386_valid_decl_attribute_p): New function to validate decl
- specific attributes. Presently returns 0.
- (i386_valid_type_attribute_p): New function to validate type
- specific attributes. Recognize "stdcall", which says function
- with fixed numbers of arguments is responsible for popping stack,
- "cdecl", which says to use the normal C calling sequence, even if
- -mrtd is used, and "regparm", which specifies the number of
- registers to use for passing arguments.
- (i386_comp_type_attributes): New function, to validate whether
- attributes are compatible.
- (i386_return_pops_args): New function, to return whether or not
- the function pops its argument list or not, taking into account
- -mrtd, and the stdcall/cdecl attributes.
- (init_cumulative_args): Rewrite as a function, taking variable
- argument functions, and regparm support into account.
- (function_arg{,_advance,_partial_nreg}): Likewise.
- (print_operand): Support %J, to print appropriate jump insn.
-
- * i386.md (decrement_and_branch_until_zero): Define pattern,
- so that loops that count down to zero, don't have an unneeded
- compare after the decrement. Add a general insn recognizer for
- add to a value and compare against zero.
-
- * i386/go32.h, i386/winnt.h (VALID_MACHINE_DECL_ATTRIBUTE):
- Delete, code folded into the mainline.
- (RETURN_POPS_ARGS): Likewise.
-
- * i386/winnt.h (ENCODE_SECTION_INFO): The stdcall attribute is now
- stored on the type field, rather than the decl.
-
- * i386/gas.h (ASM_OUTPUT_ALIGN_CODE, ASM_OUTPUT_LOOP_ALIGN): Use
- i386_align_{loops,jumps} variables to do alignment.
- * i386/osfrose.h, i386/svr3dbx.h: Likewise.
-
-Fri May 12 12:48:19 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * stor-layout.c (layout_type, case ARRAY_TYPE): Compute length using
- MAX of length and zero if sizetype signed and neither bound constant.
-
- * i386/gnuelf.h, i386/linux-oldld.h, i386/lynx-ng.h, i386/v3gas.h:
- Use <...> in #include instead of "...".
- * m68k/lynx-ng.h, sparc/lynx-ng.h: Likewise.
-
- * c-parse.in (myparm): Handle attributes.
- * objc-act.c (unused_list): New variable.
- (build_tmp_function_decl): Call push_parm_decl with new format.
- (start_class): Initialize unused_list.
- (start_method_def): Call push_parm_decl with new format and
- mark _cmp as possibly unused.
-
- * combine.c (simplify_shift_const): Don't change SHIFT_MODE
- for LSHIFTRT either.
-
- * unroll.c (unroll_loop): Don't move reg if used in copy_end and
- that is a JUMP_INSN.
-
-Fri May 12 12:31:37 1995 Doug Evans <dje@cygnus.com>
-
- * arm/lib1funcs.asm: New file.
-
-Fri May 12 11:52:03 1995 Kung Hsu <kung@cygnus.com>
-
- * configure (a29k-*-vxworks*): New target.
- * config.sub (vxworks29k): New alias.
- * a29k/t-vx29k: New file.
- * a29k/vx29k.h: New file.
+ * fix-header.c (main): Remove unused variable `done'. Protect
+ declaration of `i' with FIXPROTO_IGNORE_LIST.
-Fri May 12 11:17:28 1995 Jim Wilson <wilson@mole.gnu.ai.mit.edu>
+ * pexecute.c: Include <unistd.h>. Prototype `my_strerror'.
- * loop.c (check_dbra_loop): When reversing loop when
- no_use_except_counting is false, there must be only one biv.
+ * print-rtl.c (print_inline_rtx): Explicitly declare the parameter
+ `ind'.
-Fri May 12 07:10:00 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * profile.c: Include <string.h>/<strings.h>.
+ (instrument_arcs): Remove unused variables `note', `inverted',
+ `zero' and `neg_one'.
+ (branch_prob): Avoid empty body in an if-statement.
- * unroll.c (unroll_loop): Only use local_regno for pseudos.
+ * regclass.c: Include <stdlib.h>.
+ (reg_alternate_class): Explicitly declare parameter `regno'.
- * genattrtab.c (write_test_expr, case MATCH_DUP): Use operands[N]
- instead of JUMP_LABEL (which may not be set).
- (walk_attr_value, case MATCH_DUP): Set must_extract.
+ * regmove.c (regmove_optimize): Remove unused variable `p'. Add
+ parentheses around assignment used as truth value.
+ (find_matches): Remove unused variables `output_operand' and
+ `matching_operand'.
+ (fixup_match_1): Remove statement with no effect: "if (0) ;".
- * c-parse.in: Adjust number of shift/reduce conflicts.
- (parm): Support attributes.
- * c-decl.c (push_parm_decl): Pass any attributes to decl_attributes.
+ * scan.c (sstring_append): Explicitly declare `count' as int.
+ (scan_string): Explicitly declare parameter `init' as int.
-Fri May 12 00:36:26 1995 Per Bothner <bothner@kalessin.cygnus.com>
+ * sched.c: Include <stdlib.h>.
+ (BLOCKAGE_RANGE): Add parentheses around arithmetic in operand of |.
+ (rank_for_schedule): Add parentheses around assignment used as
+ truth value.
+ (schedule_block): Likewise.
+ (regno_use_in): Likewise.
+ (schedule_insns): Remove unused variable `i'.
- * cpplib.c (skip_quoted_string): Removed - no longer needed.
- (skip_if_group): Use cpp_get_token instead of skip_quoted_string.
+ * toplev.c: Include <stdlib.h> and <string.h>/<strings.h>.
+ (v_message_with_decl): Remove unused variable `n'.
+ (botch): Explicitly declare parameter `s' as char *.
+ (main): Add parentheses around assignment used as truth value.
- * cpplib.h (struct cpp_reader): Remove start_line field.
- Add multiline_string_line field.
+ * tree.c (make_node): Protect the variable `kind' with the
+ GATHER_STATISTICS macro.
+ (real_value_from_int_cst): Move variable `e' inside conditional
+ macro area where it is used.
+ (tree_last): Add parentheses around assignment used as truth value.
+ (build1): Protect the variable `kind' with the GATHER_STATISTICS
+ macro.
+ (print_obstack_statistics): Reconcile format vs. args in fprintf.
+ Protect variables `i', `total_nodes', and `total_bytes' with the
+ GATHER_STATISTICS macro.
- * cpplib.c (cpp_error_with_line, cpp_warning_with_line,
- cpp_pedwarn_with_line): Take extra column number parameter.
- (macroexpand, cpp_get_token): Fix reporting of unterminated strings.
- (line_for_error): Removed - no longer needed.
+Tue Jan 27 23:01:55 1998 Mike Stump (mrs@wrs.com)
-Fri May 12 02:21:34 1995 Jim Wilson <wilson@cygnus.com>
+ * m32r.md, mips.md, mn10200.md, mn10300.md, pyr.md: Add
+ some comments regarding use of dead_or_set_p.
- * mips/svr4-t.h (MD_STARTFILE_PREFIX, MD_EXEC_PREFIX,
- STARTFILE_SPEC, LINK_SPEC): Define.
- * configure (mips-tandem-sysv4): Use t-mips not t-svr4.
+Tue Jan 27 22:14:48 1998 Todd Vierling <tv@pobox.com>
-Thu May 11 19:18:54 1995 Per Bothner <bothner@kalessin.cygnus.com>
+ * fixincludes: Tweak fix for struct exception in math.h
- * cpplib.c (line_for_error): Make it work; add extra parameter.
- (skip_quoted_string, cpp_get_token): Update calls to line_for_error.
- (macroexpand): Remember initial line so we can report it if the
- call is unterminated. Also, simplify error logic slightly.
- (do_include): Cast alloca return value, to avoid pcc warning.
+Tue Jan 27 17:21:09 1998 Gavin Koch (gavin@cygnus.com)
- * cppexp.c (parse_number): Cleanup some Cygnus crud for MPW.
+ * mips/mips.c (mips_expand_prologue,mips_expand_epilogue):
+ Change mode of registers used to add/sub from
+ hard_frame_pointer_rtx from word_mode to Pmode.
-Thu May 11 21:35:23 1995 Torbjorn Granlund <tege@cygnus.com>
+Tue Jan 27 11:02:04 1998 Nick Clifton <nickc@cygnus.com>
- From Moshier:
- * i960.c (i960_output_ldconst): Let split_double handle DImode.
- (i960_print_operand): Use REAL_VALUE_TO_DECIMAL for decimal strings.
- (i960_output_double, i960_output_float): Likewise; also change arg
- VALUE from `double' to `REAL_VALUE_TYPE'.
+ * v850.h (ASM_OUTPUT_ALIGNED_BSS): Use
+ asm_output_aligned_bss() instead of asm_output_bss().
-Thu May 11 21:09:25 1995 Per Bothner (bothner@wombat.gnu.ai.mit.edu)
+ * toplev.c (rest_of_compilation): Replace references to
+ stack_reg_dump_file and dbr_sched_dump_file with references to
+ rtl_dump_file.
- * cpperror.c (cpp_print_containing_files): Remove some
- Cygnus-local stuff.
+Tue Jan 27 10:22:13 1998 Kamil Iskra <iskra@student.uci.agh.edu.pl>
-Thu May 11 21:06:47 1995 Doug Evans <dje@canuck.cygnus.com>
+ * tlink.c (scan_linker_output): Call fclose() for opened files.
- * gcc.c (link_command_spec): Make -nostdlib no longer imply
- -nostartfiles.
+Tue Jan 27 05:05:26 1998 Richard Henderson <rth@cygnus.com>
-Thu May 11 18:48:57 1995 Paul Eggert <eggert@twinsun.com>
+ * alpha.c (output_epilog [!VMS]): Don't tag global functions if
+ compiling with -fpic -- we want to be able to override symbols
+ properly.
+ (alpha_expand_block_move): Fix thinko in last change.
- * c-common.c (convert_and_check): Don't diagnose overflow in constant
- expression merely because conversion overflowed.
+ * alpha.h (ASM_OUTPUT_MI_THUNK): New define.
+ * config/alpha/win-nt.h (ASM_OUTPUT_MI_THUNK): New define.
+ * config/alpha/vms.h (ASM_OUTPUT_MI_THUNK): New undef.
-Thu May 11 18:43:59 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Jan 27 03:21:23 1998 Richard Henderson <rth@cygnus.com>
- * c-decl.c (grokdeclarator): Use PARM_FLAG to see if should
- make PARM_DECL.
- * c-parse.in (nested_function, notype_nested_function):
- Allow old-style arg definitions (use xdecls).
+ * alpha.md (abssf, absdf): Revert last change.
- * c-decl.c (finish_struct): Properly update DECL_PACKED.
+Tue Jan 27 00:26:50 1998 John Carr <jfc@mit.edu>
-Thu May 11 15:24:15 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * dwarf2out.c (dwarf2out_frame_init): Test value of DWARF2_UNWIND_INFO.
+ * mips/sni-svr4.h: Define DWARF2_UNWIND_INFO as 0.
- * fold-const.c (fold): Also fold CLEANUP_POINT_EXPRs into
- TRUTH_*_EXPRs and into the first operand.
- (operand_equal_for_comparison_p): Also make sure the second operand
- is integral.
+Tue Jan 27 00:07:02 1998 Jeffrey A Law (law@cygnus.com)
-Thu May 11 14:22:03 1995 Ted Lemon <mellon@toccata.fugue.com>
+ * emit-rtl.c (gen_lowpart_common): Handle more case where converting
+ a CONST_INT into SFmode.
- * config/mips/netbsd.h: New file.
- * config/mips/t-mips-netbsd: New file.
- * config/mips/x-netbsd: New file.
+Tue Jan 20 16:01:03 1998 Anthony Green <green@cygnus.com>
- * configure (mips-dec-netbsd*): Add entry.
+ * flags.h: New flag (optimize_size).
+ * toplev.c (main): Parse -Os option and set optimize_space
+ accordingly.
+ * gcc.c (default_compilers), cp/lang-specs.h, f/lang-specs.h: Define
+ __OPTIMIZE_SIZE__ when compiling with -Os.
+ * config/dsp16xx/dsp16xx.h, config/i386/i386.h,
+ config/i386/dgux.h, config/i960/i960.h, config/pdp11/pdp11.h,
+ config/v850/v850.h (OPTIMIZATION_OPTIONS): New SIZE argument
+ to macro.
+ * config/i386/i386.c (optimization_options): Accept new SIZE argument.
- * mips.h (LOCAL_LABEL_PREFIX, USER_LABEL_PREFIX): Define.
- (PUT_SDB_BLOCK_START, PUT_SDB_BLOCK_END, ASM_OUTPUT_LABEL_REF,
- ASM_OUTPUT_INTERNAL_LABEL, ASM_GENERATE_INTERNAL_LABEL,
- ASM_OUTPUT_ADDR_VEC_ELT, ASM_OUTPUT_ADDR_DIFF_ELT): Use them.
+Mon Jan 26 23:57:39 1998 Manfred Hollstein <manfred@s-direktnet.de>
- * mips.c (mips_output_lineno): Use LOCAL_LABEL_PREFIX.
+ * libgcc2.c (__clear_insn_cache): On sysV68 enable the memctl
+ stuff only if MCT_TEXT is #define'd.
-Thu May 11 14:22:03 1995 Stan Cox (gcc@dg-rtp.dg.com)
+Mon Jan 26 23:52:51 1998 Markus F.X.J. Oberhumer <k3040e4@c210.edvz.uni-linz.ac.at>
- * dwarfout.c (output_decl): Don't output DIE for struct or union type
- with no name or with ERROR_MARK for the fields.
+ * configure.in (i*86-pc-msdosdjgpp): Treat like msdos & go32
+ configurations.
-Thu May 11 06:36:34 1995 Michael Meissner (meissner@cygnus.com)
+Fri Jan 23 09:39:36 1998 Nick Clifton <nickc@cygnus.com>
- * flow.c (mark_used_regs): If a SUBREG does not have a REG in the
- SUBREG_REG position, recursively call mark_used_regs, instead of
- segfaulting.
+ * toplev.c: Add -dM command line option to dump RTL after the
+ machine dependent reorganisation pass, if there is one.
+ Reorganise RTL dump code, so that only one file handle is
+ needed.
-Thu May 11 06:44:34 1995 Pat Rankin (rankin@eql.caltech.edu)
+Mon Jan 26 12:09:42 1998 Benjamin Kosnik <bkoz@rhino.cygnus.com>
- * expr.c (do_jump, case EQ_EXPR, NE_EXPR): Fix typo for complex.
+ * except.c (check_exception_handler_labels): Disable warning when
+ flag_syntax_only.
-Wed May 10 12:34:46 1995 Michael Meissner <meissner@cygnus.com>
+Mon Jan 26 18:17:32 1998 Jim Wilson <wilson@cygnus.com>
- * configure: Add support for the little endian variant of the
- PowerPC System V.4 and Eabi targets. If the GNU assembler was not
- specified, don't build libgcc.a variants on the PowerPC systems
- that use -mrelocatable, -mlittle, and -mbig.
+ * sparc.c (pic_setup_code): Don't set LABEL_PRESERVE_P.
- * genmultilib: For MULTILIB_MATCHES arguments, map question marks
- into equal signs after spliting the left and right side of
- equivalent options, to all support for options like: -mcpu=403.
+Mon Jan 26 18:11:30 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * rs6000/rs6000.md (rs6000_immed_double_const): New function that
- is like immed_double_const, except that it reverses the two words
- in the constant if the target is little endian.
+ * c-decl.c (grokdeclarator): Get parameter tags from
+ last_function_parm_tags.
+ * dwarfout.c (output_formal_types): Set TREE_ASM_WRITTEN before
+ traversing the parameter types.
+ (output_type): No early exit for FUNCTION_TYPE / METHOD_TYPE context.
- * rs6000/rs6000.md (floatsidf2): Use rs6000_immed_double_const,
- not immed_double_const.
- (floatunssidf2): Ditto.
+Mon Jan 26 01:44:12 1998 Jeffrey A Law (law@cygnus.com)
- * rs6000/rs6000.h: Add declarations for all functions in rs6000.c.
+ * h8300.c (print_operand): Handle CONST_DOUBLE for 'e', 'f', and
+ the default case.
+ (get_shift_alg): Fix typo.
- * rs6000/sysv4.h (TARGET_SWITCHES): Add -mlittle, -mlittle-endian,
- -mbig, and -mbig-endian for bi-endian support.
- (ASM_SPEC): Pass -mlittle/-mbig to the assembler if it was passed
- to us.
- (LINK_SPEC): If explicit little or big endian support was
- requested, tell the GNU linker to use the appropriate target
- format.
+Sun Jan 25 22:22:04 1998 Richard Henderson <rth@cygnus.com>
- * rs6000/t-eabi (MULTILIB_*): Build libgcc.a variants for software
- floating point. Remove mrelocatable libgcc.a variant.
+ * alpha.c (alpha_expand_block_move): Copy ADDRESSOF to reg.
- * rs6000/t-eabigas: New file, cloned from t-eabi. Build
- mrelocatable libgcc.a variant in addition to the other variants.
+Sun Jan 25 22:14:28 1998 Richard Henderson <rth@cygnus.com>
- * rs6000/t-ppc: New file, for PowerPC System V.4 support without
- the GNU assembler.
+ * toplev.c (get_run_time): Make sure each case gets its variables.
- * rs6000/t-ppcgas: New file, for PowerPC System V.4 support with
- the GNU assembler.
+Sun Jan 25 22:10:21 1998 Richard Henderson <rth@cygnus.com>
- * rs6000/eabile.h: New file, little endian eabi config file.
- * rs6000/sysv4le.h: New file, little endian V.4 config file.
+ * configure.in (build_xm_file): Add auto-config.h if host=build.
+ (host_xm_file_list): Don't add $(srcdir) to auto-config.h.
+ (build_xm_file_list): Likewise.
+ * configure: Rebuild.
-Wed May 10 14:22:28 1995 Doug Evans <dje@cygnus.com>
+Sun Jan 25 22:00:25 1998 Alasdair Baird <alasdair@wildcat.demon.co.uk>
- * libgcc1-test.c (main_without__main): Renamed from `main'.
- * Makefile.in (libgcc1-test): Tell the user to ignore warnings.
+ * recog.c (validate_replace_rtx_1): Only perform substitutions
+ of arguments to commutative and comparison operators once.
- * configure: Support --enable-foo, --disable-foo.
+Sun Jan 25 12:30:18 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
-Wed May 10 10:34:00 1995 Lee Iverson <leei@Canada.AI.SRI.COM>
+ * sparc.c (output_cbranch): Add default case in
+ enumeration switch.
- * unroll.c: Add declarations of static functions.
- (unroll_loop): Renumber regs local to loop for each unrolled iteration.
+ * reorg.c (insn_sets_resource_p): Correct typo in prototype.
+ (emit_delay_sequence): Eliminate unused parameter, all callers
+ changed.
+ (fill_simple_delay_slots): Likewise.
+ (fill_slots_from_thread): Likewise.
+ (fill_eager_delay_slots): Likewise.
+ (mark_referenced_resources): Add default case in enumeration switch.
+ (mark_set_resources): Likewise.
+ (rare_destination): Likewise.
+ (mostly_true_jump): Likewise.
+ (find_dead_or_set_registers): Likewise.
+ (redirect_with_delay_slots_safe_p): Remove unused variable `slots'.
+ (update_reg_unused_notes): Remove unused variable `p'.
+ (mark_target_live_regs): Remove unused variables `next' and
+ `jump_count'.
+ (fill_simple_delay_slots): Remove unused variable `j'.
+ (fill_slots_from_thread): Add parentheses around assignment used
+ as truth value.
+ (dbr_schedule): Likewise.
-Wed May 10 08:27:03 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * objc/Make-lang.in (objc.stage1): Depend on stage1-start.
+ (objc.stage2, objc.stage3, objc.stage4): Likewise.
- * alpha.c (alpha_set_emit_const): Cleanups to work properly
- when run on 32-bit host.
+Sun Jan 25 12:13:47 1998 Michael Tiemann <michael@tiemann.org>
- * configure: Instead of symlinking tm.h and {h,t,}config.h,
- make them files that #include the proper file; pass to Makefile.
- Pass out_file and md_file to Makefile instead of making symlinks.
- * Makefile.in (out_file, md_file, tm_file, {build,host}_xm_file):
- New symbols, to be overridden by configure.
- (insn-*): Use $(md_file), not md.
- (aux-output.o): Use $(out_file), not aux-output.c.
- ($(MD_FILE)): Rework to use new conventions.
- (gen*.o, bi-*.o): Depend on $(build_xm_file), not hconfig.h.
- (scan.o, fix-header.o, scan-decls.o): Likewise.
- (distclean): Adjust files removed for new convention.
+ * cse.c (simplify_ternary_operation): Don't try to simplify
+ IF_THEN_ELSE expressions (created by combine) that don't use
+ relational operators.
-Tue May 9 19:26:42 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Fri Jan 23 22:48:24 1998 Jeffrey A Law (law@cygnus.com)
- * rs6000/rs6000.h (LIBGCC_SPEC): Do link with libgcc when -shared.
+ * cse.c (simplify_ternary_operation): Handle more IF_THEN_ELSE
+ simplifications.
- * Makefile.in (STAGESTUFF): Add underscore.c.
- (underscore.c): Rename temporary files to begin with 'tmp-' so that
- they will be removed by 'make mostlyclean'.
+ * crtstuff.c (init_dummy): Keep the epilogue in the init
+ section for non-ELF systems.
-Tue May 9 19:19:55 1995 Mike Stump <mrs@cygnus.com>
+Fri Jan 23 23:28:59 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
- * toplev.c (lang_options): Add new flag -ffor-scope.
+ * sh.md (movqi_i+1): New peephole.
-Tue May 9 19:11:47 1995 Lee Iverson (leei@ai.sri.com)
+Fri Jan 23 15:39:42 1998 Jim Wilson <wilson@cygnus.com>
- * objc/init.c (objc_init_statics): Fix missing part of last change.
+ * Makefile.in: Remove remaining bytecode stuff.
+ * emit-rtl.c, expr.c: Likewise.
-Tue May 9 18:25:34 1995 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+Fri Jan 23 12:41:10 1998 Nick Clifton (nickc@cygnus.com)
- * i386/gnu.h, i386/linux.h, i386/linux-aout.h, i386/lynx.h:
- Use <...> in #include instead of "..." to avoid recursion.
- * i386/netbsd.h, i386/xm-gnu.h, i386/xm-linux.h: Likewise.
- * i386/xm-lynx.h, i386/xm-freebsd.h, i386/xm-netbsd.h: Likewise.
- * m68k/lynx.h, m68k/netbsd.h, m68k/xm-lynx.h: Likewise.
- * m68k/xm-netbsd.h, mips/gnu.h, ns32k/netbsd.h: Likewise.
- * ns32k/xm-netbsd.h, rs6000/lynx.h, rs6000/xm-lynx.h: Likewise.
- * sparc/lynx.h, sparc/netbsd.h, sparc/xm-lynx.h: Likewise.
- * sparc/xm-netbsd.h, vax/netbsd.h, vax/xm-netbsd.h: Likewise.
+ * toplev.c (lang_options): Add unknown-pragma options.
-Tue May 9 15:52:05 1995 Michael Meissner <meissner@cygnus.com>
+Thu Jan 22 23:43:38 1998 Per Bothner <bothner@cygnus.com>
- * config.sub: Recognize powerpcle as the little endian varient of
- the PowerPC. Recgonize ppc as a PowerPC variant, and ppcle as a
- powerpcle variant. Convert pentium into i586, not i486. Add p5
- alias for i586. Map new x86 variants p6, k5, nexgen into i586
- temporarily.
+ * dwarfout.c (byte_size_attribute): Simplify and fix - don't need
+ special (and incomplete) handling for Chill arrays.
-Tue May 9 15:43:27 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Fri Jan 23 00:27:23 1998 John Carr <jfc@mit.edu>
- * rs6000/rs6000.h (LINK_SPEC, LIB_SPEC): Don't mess with libg
- if -shared.
- * rs6000/aix41ppc.h (LINK_SPEC): Ditto.
+ * toplev.c (get_run_time): Call sysconf(_SC_CLK_TCK), when available,
+ to get clock rate.
- * rs6000/powerpc.h: Don't emit .extern directives.
+Fri Jan 23 00:19:36 1998 Gavin Koch (gavin@cygnus.com)
-Tue May 9 14:08:09 1995 Jim Wilson <wilson@cygnus.com>
+ * mips.md (muldi3_internal2): Reverse test for TARGET_MIPS16.
- * sh/lib1funcs.asm (__ashrsi3, __ashlsi3, __lshrsi3): Use .byte
- instead of .word offsets in switch table.
+1998-01-22 scott snyder <snyder@d0sgif.fnal.gov>
-Tue May 9 11:44:47 1995 Jeremy Bettis <jbettis@cse.unl.edu>
+ * mips.c (function_prologue): Use HARD_FRAME_POINTER_REGNUM in
+ .frame directive instead of FRAME_POINTER_REGNUM.
- * objc/sendmsg.c (__objc_send_initialize): Call superclass if object
- does not implement +initialize.
-
-Tue May 9 02:44:16 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Fri Jan 23 00:08:55 1998 Robin Kirkham <rjk@mlb.dmt.csiro.au>
- * rs6000/xm-rs6000.h (COLLECT_EXPORT_LIST): Define if not
- cross-compiling.
- * rs6000/xm-mach.h: #undef COLLECT_EXPORT_LIST.
- * rs6000/rs6000.h (COLLECT_SCAN_OBJECTS): Lose.
+ * m68k.h (TARGET_SWITCHES): -mcpu32 now clears MASK_68881.
+ (MACHINE_STATE_m68010_up): Replaced __mc68332__ with __mcpu32__.
+ * m68k/m68k-none.h(CPP_FPU_SPEC): Update relative to TARGET_SWITCHES.
+ (CPP_SPEC, ASM_SPEC, CC1_SPEC): Likewise.
+ (CPP_SPEC): -m68332 defines both __mc68332 and __mcpu32__.
+ * m68k/t-m68kbare (MULTILIB_OPTIONS): Add mcpu32.
+ (MULTILIB_MATCHES): -m68332 now uses mcpu32 libraries, not m68000.
+ (MULTILIB_EXCEPTIONS): Don't build 68881 libraries for m68000,
+ mcpu32 or m5200.
+ * longlong.h: Replace __mc68332__ with __mcpu32__.
- * collect2.c (collect_exit): Unlink export_file.
- (prefix_from_string): Broken out from prefix_from_env.
- (prefix_from_env): Call it.
- (main): Under AIX, recognize -bE: and -bexport:, and don't
- automatically export everything if we see one. Otherwise, scan the
- objects individually and add all their symbols to an export file to be
- passed to the linker.
- (write_export_file): New function.
- (scan_prog_file): Ignore symbols starting with '.'
+Thu Jan 22 19:55:40 PST 1998 Jeff Law (law@cygnus.com)
- * c-common.c (declare_hidden_char_array): Mark decl artificial.
+ * version.c: Bump for snapshot.
-Mon May 8 18:13:57 1995 Adam Fedor <fedor@colorado.edu>
+Thu Jan 22 14:47:31 1998 Jim Wilson <wilson@cygnus.com>
- * objc/init.c (_objc_load_callback): Add declaration.
- (__objc_exec_class): Call _objc_load_callback after every Class
- or Category is added.
- * objc/objc-api.h (_objc_load_callback): Add declaration.
+ * reload.c (push_reload): In WORD_REGISTER_OPERATIONS code, add test
+ to require the SUBREG mode to be smaller than the SUBREG_REG mode.
+ * reload1.c (eliminate_regs): Likewise.
-Mon May 8 17:56:28 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Thu Jan 22 14:49:14 1998 Jeffrey A Law (law@cygnus.com)
- * expr.c (expand_expr, case INDIRECT_REF): Set RTX_UNCHANGING_P
- if both TREE_READONLY and TREE_STATIC set.
+ * regmove.c (find_matches): Initialize matches->earlyclobber too.
- * c-typeck.c (convert_for_assignment): Don't give errors about
- adding const or volatile unless both sides point to functions.
+Thu Jan 22 01:40:52 1998 Richard Henderson <rth@cygnus.com>
-Mon May 8 11:48:23 1995 Michael Meissner <meissner@cygnus.com>
+ * alpha.md (abssf2, absdf2): Disable in IEEE mode.
+ (negsf2, negdf2): Use proper subtract in IEEE mode.
- * configure: If ../ld/Makefile, symlink ../ld/ld.new to collect-ld,
- not real-ld. Don't test for $use_collect2 any more.
+Tue Jan 20 09:29:09 1998 Jeffrey A Law (law@cygnus.com)
-Sun May 7 17:52:23 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * Makefile.in: Remove more bytecode stuff.
+ * expr.c, stmt.c, config/msdos/top.sed: Likewise.
+ * vax/xm-vms.h, winnt/config-nt.sed: Likewise.
+ * f/install.texi, objc/Make-lang.in: Likewise.
- * calls.c (expand_call): Improve -Winline warnings.
+ * Makefile.in: Remove all bytecode support.
+ (OBJS): Make sure last entry is a real object file, not EXTRA_OBJS.
+ * emit-rtl.c: Remove all bytecode support.
+ * expr.c, expr.h function.c, integrate.c: Likewise.
+ * output.h, regclass.c, rtl.h, stmt.c, toplev.c: Likewise.
+ * tree.h, varasm.c: Likewise.
+ * config/m68k/m68k.h: Likewise.
+ * bi-*, bc-*, bytecode*: Delete bytecode related files.
+ * modemap.def: Likewise.
-Sun May 7 17:28:27 1995 DJ Delorie (dj@delorie.com)
+Tue Jan 20 09:02:31 1998 Gavin Koch (gavin@cygnus.com)
- * configure.bat: Use "go32" instead of "msdos" for future expansion.
+ * mips/mips.md (divsi3,divdi3,modsi3,moddi3,udivsi3,udivdi3,
+ umodsi3,umoddi3): Handle mips16 div/mod by a constant.
- * i386/go32.h: Add support for win32's stdcall functions.
+Mon Jan 19 21:57:00 1998 Richard Henderson <rth@cygnus.com>
- * configure.bat: Add ^M to end of each line.
- * i386/config-nt.bat, alpha/config-nt.bat: Likewise.
+ * i386.md (push): Prohibit symbolic constants if flag_pic.
+ (movsi+1): Likewise for move to non-register.
-Sun May 7 02:12:26 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Mon Jan 19 11:15:38 1998 Jim Wilson <wilson@cygnus.com>
- * tree.h (DECL_ARTIFICIAL): New macro.
+ * alpha.c (mode_mask_operand): Accept 0xffffffff on 32 bit host.
+ (print_operand): Handle 0xffffffff on 32 bit host.
- * function.c (expand_function_end): Don't warn about unused
- anonymous or artificial parms.
+ * configure.in (thread_file): Rename uses before main loop to
+ target_thread_file. Initialize to empty in main loop. Set thread_file
+ to target_thread_file after main loop if not set.
+ * configure: Rebuild.
-Fri May 5 18:41:22 1995 Jim Meyering (meyering@comco.com)
+ * genattrtab.c (find_and_mark_used_attributes): Handle CONST_INT.
+ (add_values_to_cover): Revert last change (which had no ChangeLog
+ entry).
+ (simplify_with_current_value_aux): Handle CONST_INT.
- * configure: Fix typo in name of "maintainer-clean".
+Mon Jan 19 10:14:55 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-Fri May 5 14:58:01 1995 Jeffrey A. Law <law@snake.cs.utah.edu>
+ * unprotoize.c: Define UNPROTOIZE first, to actually take effect.
- * pa.c (emit_move_sequence): Force problematical constants
- into memory during the reload pass when generating PIC.
+Mon Jan 19 10:11:52 1998 Richard Henderson <rth@cygnus.com>
-Fri May 5 13:30:33 1995 Doug Evans <dje@cygnus.com>
+ * configure.in: Add cpp stringify test.
+ * acconfig.h (HAVE_CPP_STRINGIFY): New tag.
+ * gengenrtl.c: Use it.
+ * configure, config.in: Rebuild.
- * objc/NXConstStr.m: NXConstantString.h renamed to NXConststr.h.
+Mon Jan 19 09:43:15 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-Fri May 5 07:10:15 1995 Stephen L Moshier (moshier@world.std.com)
+ * Makefile.in (genrtl.c genrtl.h): Add dummy command for GNU make.
- * real.c (emdnorm, toe64, etoe64): Significand of Intel long double
- denormals is shifted down one bit.
+Mon Jan 19 09:38:18 1998 Richard Henderson <rth@cygnus.com>
-Fri May 5 07:04:12 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * configure.in: Find declaration for sbrk.
+ * acconfig.h (NEED_DECLARATION_SBRK): New tag.
+ * config.in, configure: Rebuild.
+ * mips-tfile.c: Properly protect declaration of sbrk and free.
+ * toplev.c: Properly protect declaration of sbrk.
- * c-typeck.c (process_init_element): Don't clear_momentary if
- constructor_stack is not empty.
+Sun Jan 18 20:18:01 1998 Richard Henderson <rth@cygnus.com>
- * objc/Makefile (SHELL): Now /bin/sh.
+ * alpha.c (alpha_handle_trap_shadows): Ignore CLOBBERs.
- * c-typeck.c (build_binary_op): Also warn about ordered
- comparison of pointer with zero if -Wall.
+Sun Jan 18 01:54:27 1998 Jeffrey A Law (law@cygnus.com)
- * expr.c (do_jump, case EQ_EXPR, NE_EXPR): Properly compare complex.
+ * alpha/xm-winnt.h (HAS_INIT_SECTION): Undefine.
-Thu May 4 18:01:25 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+Sun Jan 18 00:57:35 1998 Mike Stump (mrs@wrs.com)
- * objc/Makefile: NXConstantString renamed to NXConstStr.
- * objc/NXConstStr.m: Renamed from objc/NXConstantString.m.
- * objc/NXConstStr.h: Renamed from objc/NXConstantString.h.
+ * configure.in (i960-wrs-vxworks): Default to latest vxworks release.
-Thu May 4 17:38:21 1995 J.T. Conklin <jtc@netbsd.org>
+Sat Jan 17 23:41:36 1998 David S. Miller <davem@tanya.rutgers.edu>
- * configure (vax-*-netbsd*): New configuration.
- * vax/netbsd.h, vax/xm-netbsd.h: New files.
+ * combine.c (force_to_mode, nonzero_bits): Correctly optimize
+ constant offset computations from objects with known alignment in
+ the presence of STACK_BIAS.
-Thu May 4 16:39:05 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * varasm.c (immed_double_const): Add casts to HOST_WIDE_INT where
+ necessary.
+ (const_hash): Hash val is unsigned long.
+ (SYMHASH): Likewise.
- * collect2.c (main): Add check for 'collect-ld', just like
- 'real-ld', except that old versions won't be looking for it in the
- path. Don't look for 'real-ld' in the path anymore. Sigh.
+ * tree.c (TYPE_HASH): Type of hash val is unsigned long.
- * collect2.c: #include demangle.h and obstack.h.
- (obstack_chunk_alloc): Define.
- (obstack_chunk_free): Define.
- (generic): Don't define. Don't use.
- (main): Initialize obstacks and demangling.
+ * print-tree.c (print_node_brief): HOST_PTR_PRINTF format wants a
+ char pointer, not HOST_WIDE_INT.
+ (print_node): Likewise. Also hash is unsigned long not
+ HOST_WIDE_INT.
- * collect2.c (dump_file): Adjust space padding in output to
- maintain tabulation with Solaris ld. Don't demangle if the
- environment variable COLLECT_NO_DEMANGLE is set.
+ * cse.c (canon_hash): Hash is unsigned long not HOST_WIDE_INT.
- * collect2.c (main): Redirect the output of the first link and
- demangle it. Don't collect static c/dtors unless USE_COLLECT2 is
- defined. Null-terminate the list of objects.
- (dump_file): New function.
- (file_exists): New function.
- (collect_exit): Renamed from my_exit. Dump and remove the temporary
- ld output file.
- (collect_execute): Break out from fork_execute. Support redirection.
- (fork_execute): Call it.
- (fatal_perror, fatal, error): Make non-static.
- (xcalloc, xmalloc): Don't use generic.
- (xrealloc): Define.
- (collect_wait): Break out for do_wait. Just return the exit status.
- (do_wait): Call it.
+ * explow.c (optimize_save_area_alloca): New function for targets
+ where SETJMP_VIA_SAVE_AREA is true.
+ (allocate_dynamic_stack_space): On SETJMP_VIA_SAVE_AREA targets,
+ compute the amount of stack space needed should we find later that
+ setjmp is never called by this function, stuff rtl for this inside
+ a REG_NOTE of the final SET of stack_pointer_rtx.
+ * toplev.c (rest_of_compilation): If SETJMP_VIA_SAVE_AREA and
+ current_function_calls_alloca, call optimize_save_area_alloca.
- * collect2.c: Check SUNOS4_SHARED_LIBRARIES using #if, not #ifdef.
+Sat Jan 17 23:22:59 1998 John Wehle (john@feith.com)
- * Makefile.in (collect2): Now uses cplus-dem.o and underscore.o.
- (collect2.o): Pass MAYBE_USE_COLLECT2 to compile.
- (underscore.c): Rules for creation.
+ * i386.md: Remove redundant integer push patterns.
+ Don't bother checking for TARGET_PUSH_MEMORY when
+ pushing constants or registers.
- * cplus-dem.c, demangle.h: Copy from libiberty.
+Sat Jan 17 22:35:39 1998 Mumit Khan <khan@xraylith.wisc.edu>
+ J.J VanderHeijden <J.J.vanderHeijden@student.utwente.nl>
-Thu May 4 14:12:35 1995 Jim Wilson <wilson@cygnus.com>
+ * pexecute.c (pexecute): New function for mingw32. Supports pipes.
+ (pwait): New function for mingw32.
- * sdbout.c (plain_type): Pass additional argument to plain_type_1.
- (plain_type_1): New parameter level. Increment it when making
- recursive calls. Force the type to void_type_mode before starting
- a 7th level of recursion.
+ * gcc.c (execute): Mingw32 pexecute() supports pipes, but cygwin32
+ pipe support is broken for now.
- * sh.c (general_movsrc_operand, general_movdst_operand): Delete
- references to POST_DEC and PRE_INC.
- * sh.h: Clean up whitespace, comments, etc.
- (TARGET_SH, RTL_BIT, DT_BIT, C_BIT, R_BIT, TARGET_DUMP_RTL,
- TARGET_DUMP_R, TARGET_CDUMP): Delete.
- (TARGET_SWITCHES): Delete -mR, -mc, -mr options.
- (CONST_DOUBLE_OK_FOR_LETTER_P): Delete 'G' contraint.
- (FUNCTION_VALUE): Simplify.
- (REG_OK_FOR_PRE_POST_P, IS_INDEX): Delete.
- (BASE_REGISTER_RTX_P, INDEX_REGISTER_RTX_P): Rewrite to allow
- SUBREGs.
- (GO_IF_LEGITIMATE_INDEX): Delete unused REGNO argument.
- (GO_IF_LEGITIMATE_ADDRESS): Use BASE_REGISTER_RTX_P instead of
- REG_OK_FOR_PRE_POST_P. Don't accept PRE_INC or POST_DEC addresses.
- (PREDICATE_CODES, PROMOTE_MODE): Define.
+1998-01-17 Lee Iverson <leei@Canada.AI.SRI.COM>
-Wed May 3 09:57:55 1995 Michael Meissner <meissner@cygnus.com>
+ * emit_rtl.c (init_emit_once): Ensure that potential aliasing
+ between frame_pointer_rtx, hard_frame_pointer_rtx, and
+ arg_pointer_rtx is respected in initialization.
+ (init_emit_once): Use gen_rtx_raw_REG() to create
+ return_address_pointer_rtx.
- * rs6000/rs6000.md (non power abs insns): If not powerpc, use
- sf/subfc instructions, not subf.
+ * reorg.c: #include "expr.h" for rtx prototypes.
+ * Makefile.in (reorg.o): Depend on expr.h
-Wed May 3 08:49:06 1995 Alan Modra <alan@SPRI.Levels.UniSA.Edu.Au>
+Sat Jan 17 21:28:08 1998 Pieter Nagel <pnagel@epiuse.co.za>
- * protoize.c (gen_aux_info_file): Use strerror #ifdef HAVE_STRERROR.
+ * Makefile.in (FLAGS_TO_PASS): Pass down gcc_include_dir and
+ local_prefix to sub-make invocations.
-Wed May 3 01:06:01 1995 Jeffrey A. Law <law@mole.gnu.ai.mit.edu>
+Sat Jan 17 21:24:16 1998 David T. McWherter <dtm@waterw.com>
- * pa.c (output_call): Fix typo/thinko in last change.
- (output_function_epilogue): Align the data section before
- emitting deferred plabels.
+ * objc-parse.c: Recognize protocol qualifiers in class definitions.
- From Torbjorn:
- * pa.c (before functions): Declare deferred_plabels and
- n_deferred_plabels.
- (output_call): When generating pic, don't use LP and RP. Use 32 bit
- plabel instead.
- (output_function_epilogue): Output plabels accumulated in output_call.
+Sat Jan 17 21:16:19 1998 Jeffrey A Law (law@cygnus.com)
-Tue May 2 17:15:08 1995 Jeffrey A. Law <law@mole.gnu.ai.mit.edu>
+ * rtl.h: Fix typos.
- * pa.c (hppa_expand_epilogue): Fix thinko in last change.
+ * acconfig.h (NEED_DECLARATION_ATOL): New declaration to check for.
+ * configure.in: Check for atol.
+ * rtl.c (atol): Only provide the declaration if NEED_DECLARATION_ATOL.
-Tue May 2 16:54:35 1995 Doug Evans <dje@cygnus.com>
+ * rtl.c (read_rtx): Initialize list_rtx to NULL, not NULL_RTX.
- * jump.c (jump_optimize, can_reach_end determination): A barrier can
- follow the return insn.
+ * loop.c (find_and_verify_loops): When attempting to move insns from
+ inside the loop outside the loop, create a BARRIER if no suitable
+ one was found.
-Tue May 2 12:39:55 1995 Mike Stump <mrs@cygnus.com>
+ * jump.c (jump_optimize): Remove Dec 17, 1997 chance in
+ favor of an equivalent change from gcc-2.8.
- * fold-const.c (fold): Ensure that we don't alter the expression's
- type when folding CLEANUP_POINT_EXPRs.
+ * i386/x-sco5 (CC): Remove trailing whitespace.
-Tue May 2 13:36:08 1995 Michael Meissner <meissner@cygnus.com>
+Sat Jan 17 21:09:46 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * expmed.c (emit_store_flag): When creating store flag
- instructions from simpler parts, such as XOR, ABS, etc. do not
- reuse pseudo registers if expensive optimizations, instead create new
- pseudos for each insn result.
+ * gengenrtl.c (type_from_format): De-ANSIfy function signature.
+ (accessor_from_format): Likewise.
+ (xmalloc): New function for use when linking with alloca.o.
-Tue May 2 01:25:29 1995 Jeffrey A. Law <law@snake.cs.utah.edu>
+Mon Jan 5 02:53:01 1998 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
- * pa.c (hppa_expand_epilogue): Correctly handle restore of %rp
- for functions with a stack size of exactly 8kbytes and no frame
- pointer.
+ * frame.c (find_fde): Correct FDE's upper bound.
-Mon May 1 19:27:08 1995 Jim Wilson <wilson@cygnus.com>
+Fri Jan 16 16:23:52 1998 Richard Henderson <rth@cygnus.com>
- * sdbout.c (sdbout_one_type): Don't switch to text section if
- in function with section attribute.
+ * gengenrtl.c (DEF_RTL_EXPR): Provide a K&R compliant version.
- * combine.c (combine_instrutions): Set subst_prev_insn to zero.
- (try_combine, undo_all): Likewise.
- (get_last_value): Return zero if subst_prev_insn set.
+Fri Jan 16 10:16:10 1998 Jeffrey A Law (law@cygnus.com)
- * sparc.h (INIT_TARGET_OPTABS): Move INIT_SUBTARGET_OPTABS to end.
+ * calls.c (expand_call): Move #ifdef code out of macro argument
+ lists.
+ (emit_library_call, emit_library_call_value): Likewise.
- * Makefile.in (install-dir): chmod a+rx all newly created directories.
+Fri Jan 16 00:46:40 1998 Jeffrey A Law (law@cygnus.com)
- * expr.c (expand_expr, case SAVE_EXPR): Handle the case where
- mode is VOIDmode.
+ * rtl.def (INLINE_HEADER): Fix bug exposed by gen_rtx_FOO changes.
-Fri Apr 28 15:39:38 1995 Per Bothner <bothner@kalessin.cygnus.com>
+Thu Jan 15 01:02:30 1998 Jeffrey A Law (law@cygnus.com)
- * cpplib.h (cpp_buffer): Note new escape combination "@ ".
- * cpplib.c (macroexpand): Delete "@ " if stringifying.
- (cpp_skip_hspace): Also skip "@ " if input buffer has_escapes.
- (collect_expansion): Cleanup white-space handling.
- (create_definition): Remove all leading spaces, not just first one.
- (cpp_expand_to_buffer): Set has_escapes on resulting input buffer.
- (macroexpand): Set output_escapes during whole function (and
- specifically during calls of macarg).
- (macroexpand): Set "@ " before and after expansion result.
- (push_macro_expansion): Remove unneeded initial "@ ", not " ".
- (cpp_get_token): Remove unneeded "@ " (not " ") at end of expansion.
- (cpp_get_token): Handle "@ ".
+ * version.c: Bump for snapshot.
- * cpplib.c (read_name_map): Add cpp_reader parameter. Access
- map_list from former (instead of having it be static).
- (open_include_file): Extra parameter (because of above changes).
- (do_include, lookup_import): Update calls of open_include_file.
+Wed Jan 14 22:49:17 1998 Richard Henderson <rth@cygnus.com>
- * cpplib.c (do_include): Fix memory leak.
+ * alias.c: Change all uses of gen_rtx(FOO...) to gen_rtx_FOO;
+ change gen_rtx(expr...) to gen_rtx_fmt_foo(expr...).
+ * caller-save.c, calls.c, combine.c, cse.c: Likewise.
+ * dwarf2out.c, except.c, explow.c, expmed.c, expr.c: Likewise.
+ * final.c, flow.c, function.c, genpeep.c, haifa-sched.c: Likewise.
+ * halfpic.c, integrate.c, jump.c, local-alloc.c, loop.c: Likewise.
+ * profile.c, recog.c, reg-stack.c, regclass.c, regmove.c: Likewise.
+ * reload.c, reload1.c, reorg.c, sched.c, stmt.c, stupid.c: Likewise.
+ * unroll.c, varasm.c: Likewise.
+ * config/alpha/alpha.c, config/alpha/alpha.md: Likewise.
- * cpplib.c (delete_assertion): Also delete tokenlist.
- (do_unassert): Don't delete tokenlist (handled by delete_assertion).
- (cpp_cleanup): New function. Frees resources used by a cpp_reader.
- * cpphash.c (cpp_hash_cleanup): New function.
- (delete_macro): Enable commented-out code.
- (file_cleanup): Free actual buffer.
+Wed Jan 14 19:36:08 1998 Gavin Koch (gavin@cygnus.com)
- * cpplib.c (cpp_options): Add map_list.
+ * mips.h: Fix some type-o's from a previous change.
- * cpplib.h (PARSE_GETC): Removed. Bogus and unused.
- * cppmain.c (main): Remove commented-out code that used PARSE_GETC.
+Wed Jan 14 01:26:05 1998 Jeffrey A Law (law@cygnus.com)
- * cpplib.c: Don't #include <string.h>. Causes clashes
- on Nextstep (when index/rindex are macros).
- (cpp_grow_buffer, int_parse_file): Cast to U_CHAR*, rather than char*.
+ * loop.c (check_dbra_loop): Make sure initial value is a
+ CONST_INT before trying to normalize it.
-Sun Apr 30 08:11:23 1995 Alan Modra (alan@spri.levels.unisa.edu.au)
+Tue Jan 13 23:27:54 1998 Robert Lipe (robertl@dgii.com)
- * stdarg.h, varargs.h (va_arg): Don't assume __va_rounded_size (char)
- has the value of 4.
+ * sco5.h (ASM_OUTPUT_SECTION_NAME): Refresh from ../svr4.h.
-Sun Apr 30 07:13:43 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Jan 13 22:47:02 1998 Herman ten Brugge <herman@htbrug.net.HCC.nl>
- * vax.h (NOTICE_UPDATE_CC): Correctly handle aob insns.
+ * cppexp.c: Include gansidecl.h
- * expr.c (expand_expr, case CONSTRUCTOR): Don't set target to
- zero if more then one word.
- Pass size and alignment to move_by_pieces_ninsns in bytes, not bits.
+Tue Jan 13 22:43:35 1998 Ian Lance Taylor <ian@cygnus.com>
- * cse.c (cse_insn): Properly set IN_MEMORY for SET_DEST.
+ * svr4.h (LINK_SPEC): Never specify -h.
+ * ptx4.h (LINK_SPEC): Likewise.
+ * rs6000/sysv4.h (LINK_SPEC): Likewise.
+ * sparc/sol2.h (LINK_SPEC): Likewise.
- * tree.c (substitute_in_expr): Preserve TREE_READONLY.
+Tue Jan 13 22:39:40 1998 Richard Henderson (rth@cygnus.com)
- * c-common.c (enum attrs): Add A_UNUSED.
- (init_attributes): Initialize it.
- (decl_attributes, case A_UNUSED): New case.
+ * c-typeck.c (comptypes): Exit early on NULL input.
-Sat Apr 29 15:42:03 1995 Paul Eggert <eggert@twinsun.com>
+ * haifa-sched.c (schedule_insns): Correctly remove inter-block
+ dependencies after reload.
- * cccp.c (do_include): Re-fix minor memory leak by using
- alloca instead of xmalloc and free.
+Tue Jan 13 22:22:31 1998 Franz Sirl <franz.sirl-kernel@lauterbach.com>
- * cccp.c (macarg): Except for reporting error, treat unterminated
- macro call as if it were terminated, since `macroexpand' relies
- on *argptr being filled in.
+ * rs6000/linux.h (CPP_PREDEFINES): Add -D__ELF__.
-Sat Apr 29 06:09:35 1995 Torbjorn Granlund <tege@cygnus.com>
+Tue Jan 13 22:14:57 1998 Klaus Kaempf <kkaempf@progis.de>
- * pa.c (output_mul_insn): Simplify, it is never called with
- UNSIGNEDP set.
+ * alpha/vms.h (DIR_SEPARATOR): define
- * pa.md (divsi3, udivsi3, modsi3, umodsi3): Simplify.
- (ashlsi3): Clean up indentation and commentary.
+Tue Jan 13 22:13:04 1998 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
-Fri Apr 28 12:48:01 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * Makefile.in (stamp-proto): Remove.
+ (protoize.o, unprotoize.o): Straightforward compile.
+ * unprotoize.c: Define UNPROTOIZE here, not in the Makefile.
- * integrate.c (expand_inline_function): Don't emit any notes until
- after we've expanded the actual parameters.
+Tue Jan 13 21:59:39 1998 Mumit Khan <khan@xraylith.wisc.edu>
-Fri Apr 28 11:51:06 1995 Stan Cox (gcc@dg-rtp.dg.com)
+ * i386/cygwin32.h (STRIP_NAME_ENCODING): Define for Win32 to strip
+ off the trailing @[NUM] added by ENCODE_SECTION_INFO.
- * m88k/dgux.h: (ENDFILE_SPEC, LIB_SPEC) Fix crtbegin and crtend
- (SELECT_RTX_SECTION) Put relocatable pic constants in data section
+Tue Jan 13 21:55:06 1998 Jeffrey A Law (law@cygnus.com)
- * m88k/dguxbcs.h: (LIB_SPEC) Likewise
+ * arm/netbsd.h (DWARF2_UNWIND_INFO): Define as zero for now.
+ * i386/netbsd.h, m68k/netbsd.h, ns32k/netbsd.h: Likewise.
+ * sparc/netbsd.h, vax/netbsd.h: Likewise.
- * m88k/m88k.c: (symbolic_operand) Put relocatable pic constants in data
+Tue Jan 13 21:37:07 1998 Shigeya Suzuki <shigeya@foretune.co.jp>
- * m88k/m88k.h: (FRAME_POINTER_REQUIRED) Add -momit-leaf-frame-pointer
+ * i386/bsd386.h (DWARF2_UNWIND_INFO): Define as zero for now.
- * m88k/m88k.md: (umulsidi3) Doesn't work for 88110 with mod/div changes
+Tue Jan 13 17:50:55 1998 Jim Wilson <wilson@cygnus.com>
- * m88k/x-dgux: (GCC_FOR_TARGET) tdesc gets mixed up for crtbegin/crtend
+ * configure.in (target_cpu_default, target_cpu_default2): Use double
+ quotes around them when testing their value.
+ * configure: Rebuilt.
-Fri Apr 28 06:36:47 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Jan 13 09:07:44 1998 John Carr <jfc@mit.edu>
- * c-typeck.c (pop_init_level, output_init_element): Pass
- require_constant_* to digest_init.
+ * gengenrtl.c (gencode): Emit new function obstack_alloc_rtx
+ to allocate rtx.
+ (gendef): Call obstack_alloc_rtx.
- * alpha.c (alpha_emit_set_const): Now returns rtx and take MODE arg.
- Rework to use a new pseudo for intermediate values if high opt level.
- Also use expand_{bin,un}op.
- * alpha.h (alpha_emit_set_const): Add declaration.
- * alpha.md (mov[sd]i and splits): Change call to alpha_emit_set_const.
+Tue Jan 13 01:16:36 1998 Robert Lipe (robertl@dgii.com)
- * reg-stack.c (stack_result): Fix bug in last change.
+ * configure.in: (i[3456]86-UnixWare7-sysv5): Treat much like SVR4
+ for now.
-Fri Apr 28 01:08:43 1995 Doug Evans <dje@cygnus.com>
+Thu Dec 18 18:40:17 1997 Mumit Khan <khan@xraylith.wisc.edu>
- * objc-act.c: Update calls to start_decl, finish_struct,
- pass NULLs for attributes.
+ * i386/mingw32.h (INCOMING_RETURN_ADDR_RTX): Delete. Use the value
+ of DWARF2_UNWIND_INFO, if any, from i386/cygwin32.h instead.
+ (STANDARD_INCLUDE_DIR): Change to /usr/local/i386-mingw32/include.
-Thu Apr 27 21:13:14 1995 Doug Evans <dje@cygnus.com>
+Tue Jan 13 00:44:02 1998 Jim Wilson <wilson@cygnus.com>
- * sparc.md (tablejump): Only if ! TARGET_MEDANY.
- (casesi): New pattern for TARGET_MEDANY case.
+ * mips.md (return_internal): Change mode from SImode to VOIDmode.
- * c-common.c (decl_attributes): Always continue if attribute not found.
- * c-typeck.c (common_type): Call lookup_attribute instead of
- value_member.
- * tree.c (attribute_hash_list): New function.
- (build_type_attribute_variant): Call it.
- (valid_machine_attribute): Handle attributes with arguments.
- (is_attribute_p): New function.
- (lookup_attribute): New function.
- (attribute_in_list): Deleted.
- (attribute_list_contained): Check TREE_PURPOSE and TREE_VALUE.
- * tree.h (valid_machine_attribute): Add prototype.
- (is_attribute_p, lookup_attribute): Likewise.
- * i386/winnt.h (RETURN_POPS_ARGS): Call lookup_attribute.
- (ENCODE_SECTION_INFO): Likewise.
- (CPP_PREDEFINES): Use __stdcall__, __cdecl__.
- (VALID_MACHINE_DECL_ATTRIBUTE): Call is_attribute_p.
- `args' must be NULL.
+Sat Jan 10 22:11:39 1998 J. Kean Johnston <jkj@sco.com>
-Thu Apr 27 21:10:41 1995 David Edelsohn <edelsohn@mhpcc.edu>
+ * i386/sco5.h (STARTFILE_SPEC, ENDFILE_SPEC): Correctly handle
+ "-static".
- * rs6000.md (insv): New anonymous patterns to combine insert with
- arbitrary ashift, ashiftrt, lshiftrt, or zero_extract. (Based on
- patch from John Brooks <jbrooks@ea.com>.)
- (ashlsi3): Remove extraneous operand processing.
+Sat Jan 10 22:04:15 1998 Stan Cox <scox@equinox.cygnus.com>
-Thu Apr 27 18:47:24 1995 Jim Wilson <wilson@cygnus.com>
+ * i386.md: (movsicc_1, movhicc_1): For alternate 3 set the opcode
+ suffix from operand 3.
- * sh/ashlsi3.c, sh/ashrsi3.c, sh/lshrsi3.c: Delete.
- * sh/lib1funcs.asm (ashiftrt_r4_*): Rewrite for efficiency.
- (ashrsi3, lshrsi3, lshrsi3): Add.
- * t-sh (LIB1ASMFUNCS): Add new functions.
- (LIBGCC2_CFLAGS): Delete.
- (LIB2FUNCS_EXTRA): Remove deleted files.
- (ashlsi3.c, ashrsi3.c, lshrsi3.c): Remove rules for deleted files.
+Sat Jan 10 21:50:16 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+ Jeffrey A Law (law@cygnus.com)
- * stmt.c (expand_return): When returning BLKmode structure, use
- operand_subword instead of doing arithmetic on the register number.
- Also, for structures smaller than word_mode, copy it into a word_mode
- temporary and then subreg it.
+ * regmove.c: New implementation of regmove pass.
+ * local-alloc.c (optimize_reg_copy_1, optimize_reg_copy_2): Remove
+ decls, make them have external linkage. Return a value from
+ optimize_reg_copy_1.
+ * reload.h (count_occurrences): Add decl.
+ * reload1.c (count_occurrences): Delete decl, make it have external
+ linkage.
+ * rtl.h (optimize_reg_copy_1, optimize_reg_copy_2): Declare.
- * sparc.md: Delete two define_peepholes which print `bad peephole'.
+Sat Jan 10 20:30:12 1998 Jeffrey A Law (law@cygnus.com)
-Thu Apr 27 16:17:01 1995 Torbjorn Granlund <tege@cygnus.com>
+ * regclass.c (record_address_regs): Don't use REG_OK_FOR_BASE_P
+ if it is not defined.
- * toplev.c (rest_of_compilation): Call shorten_branches even when
- !optimize.
- * final.c (shorten_branches): For non-optimizing compiles, break
- after first pass.
+Thu Jan 8 21:06:54 1998 Richard Henderson <rth@cygnus.com>
-Thu Apr 27 14:22:50 1995 Michael Meissner <meissner@cygnus.com>
+ * Makefile.in (OBJ, GEN, RTL_H): Add genrtl.[oh] bits.
+ * emit-rtl.c (gen_rtx): Move special code to ...
+ (gen_rtx_CONST_INT): New function.
+ (gen_rtx_REG): New function.
+ (*): Update all calls to gen_rtx.
+ * genemit.c (gen_exp): Emit calls to gen_rtx_FOO for constant FOO.
+ * rtl.h: Include genrtl.h; prototype CONST_INT & REG generators.
+ (GEN_INT): Call gen_rtx_CONST_INT.
+ * gengenrtl.c: New file.
- * i386/linux-oldld.h: New file, that is cloned from linux-aout.h,
- except that it does not pass -m i386linux to the linker. This is
- to support the original Linux ld that is on most distributions.
+Mon Jan 5 13:00:18 1998 John F. Carr <jfc@mit.edu>
- * configure (i[345]86-*-linux*oldld*): Use i386/linux-oldld.h as
- the target file.
+ * alias.c (*_dependence): Call base_alias_check before canon_rtx.
+ (base_alias_check): If no base found for address call canon_rtx and
+ try again.
-Thu Apr 27 08:56:50 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Mon Jan 5 11:39:49 1998 Jeffrey A Law (law@cygnus.com)
- * tree.c (valid_machine_attribute): Update last change.
+ * mips.c (mips_expand_prologue): Handle large frame with no outgoing
+ arguments for mips16.
+ (mips_expand_epilogue): Pass "orig_tsize" to save_restore_insns.
+ Don't lose if tsize is zero after handling large stack for mips16.
+ * mips.md (return): For trivial return, return address is in $31.
-Thu Apr 27 08:06:33 1995 Philippe De Muyter (phdm@info.ucl.ac.be)
+Sun Jan 4 20:24:00 1998 Nigel Stephens <nigel@algor.co.uk>
- * fix-header.c, cpplib.c: Don't include <sys/stat.h> twice.
- * cpplib.c (cpp_grow_buffer, init_parse_file): Cast {xmalloc,xrealloc}
- for token_buffer to U_CHAR* instead of char*.
+ * mips/mips16.S: Various changes to make it work with -msingle-float
+ and -EL.
- * m68k/x-mot3300: New file.
- * configure (m68k-motorola-sysv*): Use x-mot3300 instead of x-alloca.
+Sun Jan 4 14:25:18 1998 Gavin Koch <gavin@cygnus.com>
+ Ian Lance Taylor <ian@cygnus.com>
+ Jeff Law <law@cygnus.com>
-Thu Apr 27 07:04:09 1995 Paul Eggert <eggert@twinsun.com>
+ * mips.c, mips.h, mips.md: First cut at merging in mips16
+ support. Major modifications throughout all three files.
- * cccp.c (do_include): Fix minor memory leak.
+Sun Jan 4 01:01:50 1998 scott snyder <snyder@d0sgif.fnal.gov>
- * cccp.c (struct argdata): Remove unused `comments' member.
- (macarg): Don't set `comments' member.
+ * configure.in: Make gthr-default.h a forwarding header instead of
+ a symlink.
- * cccp.c (collect_expansion): Assume leading white space
- already removed.
- Don't allocate unnecessary space for expansion.
+Sat Jan 3 12:08:06 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * cccp.c (deps_output): Don't generate overly long output lines.
- Do not invoke self recursively with spacer == 0; this simplifies
- the code a bit.
+ * gcov-io.h: Include sys/types.h to ensure we get size_t.
-Wed Apr 26 19:20:02 1995 Andrew McCallum <mccallum@leopard.cs.rochester.edu>
+ * pa.h (ASM_OUTPUT_MI_THUNK): Add missing % in fprintf.
- * objc/Object.h: Changed Class * to Class in order to match NEXTSTEP
- and OpenStep runtime.
- * objc/Object.m, objc/Object.h, objc/archive.c, objc/class.c: Likewise.
- * objc/encoding.c, objc/init.c, objc/objc-api.h, objc/objc.h: Likewise.
- * objc/objects.c, objc/runtime.h, objc/selector.c: Likewise.
- * objc/sendmsg.c, objc/typedstream.h: Likewise.
+Fri Jan 2 23:40:09 1998 Jim Wilson (wilson@cygnus.com)
+ Jeffrey A Law (law@cygnus.com)
-Wed Apr 26 19:18:52 1995 Pieter Schoenmakers <tiggr@es.ele.tue.nl>
+ * crtstuff.c (__frame_dummy): New function for irix6.
+ (__do_global_ctors): Call __frame_dummy for irix6.
+ * iris6.h (LINK_SPEC): Hide __frame_dummy too.
- * objc/objc-api.h (objc_static_instances): New struct to record
- static instances of a certain class.
- (objc_module): New tag STATICS to point to the table of
- objc_statics_instances.
-
- * objc/init.c (OBJC_VERSION): Version 7.
- (objc_init_statics): New function.
- (__objc_exec_class): Invoke objc_init_statics if needed.
-
- * objc/NXConstantString.m, objc/NXConstantString.h: New files.
- * objc/Makefile (OBJC_O): Added bare-bones implementation of
- NXConstantString.
-
- * objc-act.c (OBJC_VERSION): Version 7.
- (build_objc_string_object): Build a full declaration if not using
- the next runtime.
- (objc_add_static_instance): New function.
- (init_module_descriptor): Add reference to static instances table.
- (build_module_descriptor): Add field for static instances table.
- (get_objc_string_decl): New function.
- (generate_static_references): New function.
- (finish_objc): Call generate_static_references if needed.
-
- * c-tree.h (finish_decl_top_level): New declaration.
- * c-decl.c (finish_decl_top_level): New function.
-
-Wed Apr 26 18:04:32 1995 Dirk Steinberg (Dirk.Steinberg@gmd.de)
-
- * stddef.h: Treat _MACHINE_ANSI_H_ like _ANSI_H_.
-
-Wed Apr 26 14:09:59 1995 Jim Wilson <wilson@cygnus.com>
-
- * sparc.h (NEGTF2_LIBCALL): Define.
- (INIT_TARGET_OPTABS): Add support for all TFmode *_LIBCALL macros.
- * optabs.c (init_optabs): Delete all uses of undocumented TImode and
- TFmode *_LIBCALL macros.
-
- * combine.c (simplify_rtx, case TRUNCATE): Add. Use force_to_mode.
- (force_to_mode, case AND): Allow some simplifications when GET_MODE (x)
- has more bits than HOST_BITS_PER_WIDE_INT.
- * mips/mips.md (truncdiqi2+[456]): Add patterns to simplify ZERO_EXTEND
- of a TRUNCATE.
-
-Wed Apr 26 13:01:22 1995 Doug Evans <dje@cygnus.com>
-
- * sparc.md (memop define_splits): Rewrite to not use memop.
- Preserve MEM_IN_STRUCT_P, MEM_VOLATILE_P, RTX_UNCHANGING_P bits.
- * sparc.c (memop): Deleted.
- (splittable_symbolic_memory_operand): New function.
- (splittable_immediate_memory_operand): New function.
-
-Wed Apr 26 12:54:26 1995 Jeffrey A. Law <law@snake.cs.utah.edu>
-
- * configure: Add hppa1.1-hp-lites support.
-
-Wed Apr 26 08:04:46 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * sh.md (ashrsi2_31): Don't use dead_or_set_p after reload.
- * pyr.md: Remove bad peepholes that improperly use dead_or_set_p.
-
- * function.c (expand_function_end): Warn about unused parms
- if both -Wunused and -W.
-
- * tree.h (TYPE_PARSE_INFO): Delete unused field.
- (TYPE_PACKED): Add new macro.
- (struct tree_type): Delete unused field `parse_info'.
- Add new field `packed_flag'.
- * c-tree.h (finish_enum, finish_struct): Add ATTRIBUTES argument.
- * c-common.c (init_attributes): Don't require decl for A_PACKED.
- (decl_attributes, case A_PACKED): Set TYPE_PACKED for type.
- * c-parse.in: Update number of shift/reduce conflicts.
- (structsp): Pass attribute arg to finish_struct.
- Support attributes on enums and pass to finish_enum.
- * c-decl.c (finish_struct): Add ATTRIBUTES argument, call
- decl_attributes and set DECL_PACKED from TYPE_PACKED.
- (finish_enum): Add ATTRIBUTES argument, call decl_attributes,
- and make enum narrow if TYPE_PACKED.
- * print-tree.c (print_node): Print TYPE_PACKED.
-
- * c-decl.c (init_decl_processing): Don't give builtin__constant_p an
- argument type.
- * expr.c (expand_builtin, case BUILT_IN_CONSTANT_P): A pointer to a
- string constant is a constant.
-
- * c-typeck.c (output_init_element): Constructor is not simple if
- a bitfield is being assigned a non-integer.
-
- * c-typeck.c (push_init_level): Update constructor_depth when we
- push spelling level.
-
-Tue Apr 25 19:50:06 1995 Jeffrey A. Law <law@snake.cs.utah.edu>
-
- * pa.c (emit_move_sequence): Handle function label arithmetic for
- PIC code generation too.
-
-Tue Apr 25 18:52:43 1995 Stephen R. van den Berg (berg@pool.informatik.rwth-aachen.de)
-
- * reg-stack.c (current_function_returns_real): Deleted (unused).
- (FP_mode_reg): Trimmed to a smaller size, less overhead.
- (FP_MODE_REG): New macro over which FP_mode_reg will be accessed.
- (mark_regs_pat, straighten_stack): New functions.
- (reg_to_stack): Amend initialisation of FP_mode_reg.
- Mark FP registers mentioned in USE insns before NOTE_INSN_FUNCTION_BEG.
- (get_true_reg): Eliminate FP subreg accesses in favour of the
- actual FP register in use.
- (record_reg_life_pat): Make it work on SUBREGs as well. Make use of
- the new mark_regs_pat function. Handle USE insns if called unnested.
- (record_reg_life): Don't check for QImode again, we know that it
- is there. Process CALL_INSNs like all other insns, they might `use'
- some FP argument registers if register passing.
- (stack_result_p): Changed in stack_result and returning an rtx.
- (stack_reg_life_analysis): Take a new stackentry state argument.
- Use stack_result and the rtx to mark using mark_regs_pat. This ensures
- that types that need multiple FP registers are handled correctly.
- Delete the no_live_regs shortcut to save space.
- Use stackentry state to determine filled registers.
- (replace_reg): Accept COMPLEX_FLOAT as well.
- (move_for_stack_reg): Optimise away some pointer dereferencing.
- (subst_stack_regs): Make sure the stack is in the right order
- and of the right size for register passing.
- (goto_block_pat): Make sure the stack is in the right order
- to return possible multi-register values from the function.
- (convert_regs): Fix comment about CALL_INSN, it's no longer valid.
- Make sure the stack is of the right size and in the right order
- to return possible multi-register values from the function.
-
- * function.c (assign_parms): If STACK_REGS is defined, generate USE
- insns before the function body, thus showing which registers are filled
- with parameters.
- * expr.c (expand_builtin_apply_args): Likewise.
- Reverse order of saving registers, more compact code for i387.
- (expand_builtin_apply): Likewise.
- * emit-rtl.c (gen_highpart): Add comment about broken implementation.
- * i386.md (untyped_call): Make it return a complex double.
-
- * c-parse.in (attrib): Permit null-length argument list to attributes.
-
- * tree.c (valid_machine_attribute): Use new function attribute_in_list,
- makes sure type_attribute_variants are reused even when attributes have
- parameters.
- Assign any new type to TREE_TYPE (decl).
- (attribute_in_list): New function.
- (attribute_list_contained): Use it.
- * tree.h (attribute_in_list): New declaration.
-
-Tue Apr 25 18:25:53 1995 Jim Wilson <wilson@cygnus.com>
-
- * expr.c (struct move_by_pieces): Add to_struct and from_struct fields.
- (move_by_pieces): Set to_struct and from_struct fields.
- (move_by_pieces_1): Set MEM_IN_STRUCT_P of to1 and from1.
- (expand_builtin, case BUILT_IN_MEMCPY): New variable type.
- Set MEM_IN_STRUCT_P of src_mem and dest_mem.
-
- * Makefile.in (clean): Delete libgcc1-asm.a.
-
- * m68k/vxm68k.h (CPP_SPEC): Define.
-
- * c-decl.c (pushdecl): Don't test DECL_EXTERNAL when deciding whether
- to register a duplicate decl in the current block.
-
- * cross64.h (INIT_ENVIRONMENT): Define as string not putenv call.
- * gcc.c (main): Pass INIT_ENVIRONMENT to putenv.
-
- * stmt.c (expand_return): When returning BLKmode structure in
- registers, copy it to a psuedo-reg instead of to hard registers.
-
-Tue Apr 25 15:14:58 1995 Michael Meissner <meissner@cygnus.com>
-
- * rs6000.h (LEGITIMIZE_ADDRESS): Don't create a DF address using two
- regs if -msoft-float or -mcpu=403.
-
-Tue Apr 25 15:45:44 1995 Richard Henderson (richard@atheist.tamu.edu)
-
- * m68k.md (divhi3, udivhi3, modhi3, umodhi3): Deleted
- these insns plus some surrounding trash.
- (divmodhi4, udivmodhi4): Added these insns.
-
-Tue Apr 25 10:12:40 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * alpha.c (alpha_builtin_saveregs): Refine last change to work
- for both stdarg and varargs.
-
- * tree.c (chain_member_purpose): Make similar to chain_member_value.
-
- * Makefile.in, configure: Change "realclean" to "maintainer-clean".
-
- * protoize.c: Removed __NetBSD__ from conditional.
- Declare strerror if HAVE_STRERROR is defined; otherwise
- declare sys_errlist and sys_nerr.
- (my_strerror): New function.
- (errno): Don't define if already defined as a macro.
-
- * alpha.c (current_file_function_operand): Return false if profiling.
+Fri Jan 2 04:57:57 1998 Weiwen Liu <liu@hepmail.physics.yale.edu>
+
+ * alpha.c (vms_valid_decl_attribute_p): Move within #if OPEN_VMS.
+
+Fri Jan 2 04:34:14 1998 Richard Henderson <rth@cygnus.com>
+
+ * c-decl.c (init_decl_processing): Provide proper fallback symbol
+ for __builtin_memset.
+ * expr.c (expand_builtin) [MEMSET]: Arg 3 type code is INTEGER_TYPE
+ not INTEGER_CST. Assert arg 3 is a constant.
+
+ * alpha.c (mode_width_operand): Accept 64-bit modes.
+ (mode_mask_operand): Likewise.
+ (print_operand): Likewise for 'M' and 'U' codes.
+ (alpha_expand_unaligned_load): New function.
+ (alpha_expand_unaligned_store): Likewise.
+ (alpha_expand_unaligned_load_words): Likewise.
+ (alpha_expand_unaligned_store_words): Likewise.
+ (alpha_expand_block_move): Likewise.
+ (alpha_expand_block_clear): Likewise.
+ * alpha.h (MOVE_RATIO): New define.
+ * alpha.md (extxl, ext*h, ins*l, mskxl): Name them.
+ (insql, insxh, mskxh, extv, extzv, insv, movstrqi, clrstrqi): New.
+
+ * alpha.h (ASM_OUTPUT_LOOP_ALIGN, ASM_OUTPUT_ALIGN_CODE): Set to 3.
+ (CONSTANT_ALIGNMENT, DATA_ALIGNMENT): Disable.
+
+Thu Jan 1 15:40:15 1998 Richard Henderson <rth@cygnus.com>
+
+ * configure.in: Put parenthesis around TARGET_CPU_DEFAULT's value.
+ * configure: Update.
+
+Thu Jan 1 10:49:12 1998 Jeffrey A Law (law@cygnus.com)
+
+ * emit-rtl.c (operand_subword): Correctly handle extracting a word
+ from a CONST_DOUBLE for 16bit targets with !WORDS_BIG_ENDIAN.
+
+ * mn10200.md (tstxx, cmpxx): Use "nonimmediate_operand" as predicate
+ for first argument.
+
+Wed Dec 31 14:42:18 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * configure.in: Set and subsitute host_exeext. Use it when creating
+ the assembler and linker symlinks.
+ * configure: Rebuild.
+ * Makefile.in (exeext): Set to @host_exeext@.
+ (build_exeext): New variable, set to @build_exeext@.
+ (FLAGS_TO_PASS): Pass down build_exeext.
+ (STAGESTUFF): Use build_exeext, not exeext, for gen* and bi*
+ programs.
+
+Wed Dec 31 10:05:44 1997 Jeffrey A Law (law@cygnus.com)
+
+ * mn10200.md (addsi3, subsi3): Fix thinkos.
+
+Tue Dec 30 00:04:49 1997 Richard Henderson <rth@cygnus.com>
+
+ * sparc.h (ASM_OUTPUT_MI_THUNK): Move %o7 through %g1 instead of
+ save+restore. Fix pic+big_offset delay slot. Use "pic" case for
+ unix always, since we want to be able to thunk to functions in a
+ shared library from an application.
+
+Mon Dec 29 14:37:31 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * mips/t-ecoff (CROSS_LIBGCC1): Define to libgcc1-asm.a.
+ (LIB1ASMSRC, LIB1ASMFUNCS): Define.
+
+Mon Dec 29 14:03:38 1997 Jeffrey A Law (law@cygnus.com)
+
+ * expr.c (expand_expr): For {BITFIELD,COMPONENT,ARRAY}_REF, if the
+ offset's mode is not ptr_mode, convert it.
+
+Mon Dec 29 15:58:18 1997 Michael Meissner <meissner@cygnus.com>
+
+ * libgcc2.c (inhibit_libc): Don't define inhibit_libc when cross
+ compiling if it was already defined.
+
+Sun Dec 28 00:32:16 1997 Jeffrey A Law (law@cygnus.com)
+
+ * flow.c (find_basic_blocks): Don't create a new basic block
+ for calls in a LIBCALL block.
+
+Sun Dec 28 00:30:24 1997 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * config/fp-bit.c (L_df_to_sf): Fix typo in last change.
+
+Sat Dec 27 22:43:12 1997 Jeffrey A Law (law@cygnus.com)
+
+ * cse.c (rtx_cost): Remove conflicting default case.
+
+Sat Dec 27 21:20:02 1997 Richard Henderson <rth@cygnus.com>
+
+ * configure.in: Move default enabling of Haifa out of for loop.
+ * configure: Rebuild.
+
+Thu Dec 25 01:02:54 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+1997-12-25 Teemu Torma <tot@trema.com>
+
+ * Makefile.in (GTHREAD_FLAGS): New var.
+ (LIBGCC2_CFLAGS): Added $(GTHREAD_FLAGS).
+ (distclean): Remove gthr-default.h.
+
+ * configure.in: Accept dce as a thread package.
+ Check for thread.h and pthread.h.
+ Link gthr-default.h to appropriate thread file and set
+ gthread_flags.
+ (hppa1.1-*-hpux10*): If --enable-threads, use dce threads and
+ include multilib definitions from pa/t-dce-thr.
+ (sparc-*-solaris2*): Enable threads by default, if thread.h or
+ pthread.h is found, preferring posix threads over solaris ones.
+
+ * config/pa/t-dce-thr: New file.
+ * config/pa/t-pa: Removed multilibs.
+ * config/sparc/t-sol2: Ditto.
+
+ * gthr.h: New file.
+ * gthr-single.h: New file.
+ * gthr-posix.h: New file.
+ * gthr-solaris.h: New file.
+ * gthr-dce.h: New file.
+ * libgcc-thr.h: Removed.
+ * objc/thr-dce.c: New file copied from thr-decosf1.c.
+
+ * frame.c: Include gthr.h instead of libgcc-thr.h.
+ * libgcc2.c: Include gthr.h instead of libgcc-thr.h.
+ (eh_context_initialize): If __gthread_once fails, use static eh
+ context.
+ (eh_context_free): Call __gthread_key_dtor.
+
+Wed Dec 24 23:33:17 1997 Jeffrey A Law (law@cygnus.com)
+
+ * expr.h (MUST_PASS_IN_STACK): Allow target port to override.
+
+Wed Dec 24 23:12:14 1997 Jim Wilson <wilson@cygnus.com>
+
+ * cse.c (max_insn_uid): New variable.
+ (cse_around_loop): Use max_insn_uid.
+ (cse_main): Set max_insn_uid.
+
+ * abi64.h (LONG_MAX_SPEC): Check MIPS_ABI_DEFAULT and TARGET_DEFAULT,
+ and define __LONG_MAX__ appropriately. Add support for -mabi=X,
+ -mlong64, and -mgp{32,64} options.
+ * mips.c (mips_abi): Change type to int.
+ * mips.h (enum mips_abi_type): Delete.
+ (ABI_32, ABI_N32, ABI_64, ABI_EABI): Define as constants.
+ (mips_abi): Change type to int.
+
+Wed Dec 24 22:38:34 1997 John Carr <jfc@mit.edu>
+
+ * flags.h, toplev.c, calls.c, alias.c: Remove flag_alias_check;
+ optimization is now always enabled.
+
+ * calls.c (expand_call): Recognize C++ operator new as malloc-like
+ function.
+
+ * alias.c (memrefs_conflict_p): Eliminate tests now done by
+ base_alias_check.
+ (*_dependence): Call canon_rtx before base_alias_check.
+ (init_alias_once): New function to precompute set of registers which
+ can hold Pmode function arguments.
+
+ * rtl.h: Declare init_alias_once.
+
+ * toplev.c (compile_file): Call init_alias_once.
+
+Wed Dec 24 22:34:55 1997 Jeffrey A Law (law@cygnus.com)
+
+ * tree.c (restore_tree_status): Do not dereference a null pointer.
+
+Tue Dec 23 12:56:46 1997 Paul Eggert <eggert@twinsun.com>:
+
+ * genattrtab.c (main): Check HAVE_{G,S}ETRLIMIT in addition to
+ RLIMIT_STACK. This maintains consistency with the recent, similar
+ patch to cccp.c and toplev.c.
+
+Tue Dec 23 05:17:28 1997 Richard Henderson <rth@cygnus.com>
+
+ * genattrtab.c (expand_units): For large nr opclasses, expand
+ function_units_used with ORX to prevent blowups. Tag with FFS.
+ (num_unit_opclasses): New variable.
+ (gen_unit): Update it.
+ (enum operator): Add ORX_OP.
+ (operate_exp): Treat ORX as or, except don't expand across an if.
+ Reuse number rtx's after operating on them.
+ (check_attr_value): Accept IOR, AND, & FFS.
+ (write_test_expr): Transmute `in_comparison' to `flags'. Allow
+ for attribute value caching. Handle CONST_STRING, IF_THEN_ELSE.
+ (write_expr_attr_cache, write_toplevel_expr): New functions.
+ (write_attr_get): Handle FFS-tagged expressions.
+ (make_canonical): Don't expand const attributes.
+ (convert_const_symbol_ref): Dike out.
+ (evaluate_eq_attr): Handle SYMBOL_REF.
+ (main): Don't emit get_attr_foo for const attributes.
+
+ * alpha.c (override_options): Reinstate PROCESSOR_EV6.
+ (alpha_adjust_cost): Add EV6 tuning; streamline EV5 tests.
+ * alpha.h (REGISTER_MOVE_COST): Increase ftoi/itof cost slightly.
+ * alpha.md: Redo all of the scheduling, adding EV6 support, and
+ combining function units where possible.
+ (attr "type"): Split loads, stores, cmov into int/fp. Combine
+ multiplies and divides. Add EV6 sqrt, ftoi, itof.
+ (attr "opsize"): New attribute.
+ (sqrtsf2-1, sqrtdf2-1): Provide proper TP_INSN patterns.
+ (movsf2-[12], movdf2-[12]): Provide CIX varients; don't allow CIX
+ to control register allocation.
+ (movsi2-1, movdi2-1): Likewise.
+
+Tue Dec 23 03:53:21 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.h (CPP_PREDEFINES, LIB_SPEC, LINK_SPEC, STARTFILE_SPEC,
+ MD_STARTFILE_PREFIX, ASM_FILE_START, ASM_SPEC, ASM_FINAL_SPEC):
+ Move OSF/1 specific defines out.
+ * alpha/elf.h (TARGET_VERSION, CPP_PREDEFINES, DEFAULT_VTABLE_THUNKS):
+ Move Linux specific defines out.
+ (LINK_SPEC): Genericize.
+ (ASM_FILE_START): Emit .arch if using more than the base insn set.
+ (ASM_OUTPUT_SOURCE_LINE): Remove; identical to alpha.h version.
+ (SDB_DEBUGGING_INFO): Remove; gas can't handle it.
+ (HANDLE_SYSV_PRAGMA): Define.
+ * alpha/osf.h: New file.
+ * alpha/linux.h: Split. Retain file-format independant defines.
+ Import Linux bits from elf.h.
+ (CPP_PREDEFINES): Take a file-format specific SUB_CPP_PREDEFINES
+ (FUNCTION_PROFILER): _mcount takes its address in $28.
+ (MD_EXEC_PREFIX, MD_STARTFILE_PREFIX): Remove undef.
+ * alpha/linux-ecoff.h: New file.
+ * alpha/linux-elf.h: New file.
+ * alpha/vms.h (LIB_SPEC, LINK_SPEC): Copy from osf.h.
+ * alpha/win-nt.h (TARGET_DEFAULT): Define.
+ * configure.in (alpha*-*-osf*, alpha*-*-linux*) [tm_file]:
+ Add new headers as appropriate.
+
+ * configure.in (alpha*): Enable Haifa by default.
+ (*-*-winnt3*): Change to winnt*, since we're not v3 specific.
+ * configure: Rebuild.
+
+Tue Dec 23 03:14:54 1997 Richard Henderson <rth@cygnus.com>
+
+ * Makefile.in (clean): Remove the stages with their objects here ...
+ (distclean): ... instead of here.
+
+Mon Dec 22 11:24:01 1997 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * cse.c (rtx_cost): Add default case in enumeration switch.
+ * fix-header.c (recognized_macro): Likewise.
+ (recognized_extern): Likewise.
+ (write_rbrac): Likewise.
+ * objc/objc-act.c (encode_aggregate): Likewise.
+ (gen_declarator): Likewise.
+ (gen_declspecs): Likewise.
+
+Mon Dec 22 09:58:51 1997 Jeffrey A Law (law@cygnus.com)
+
+ * haifa-sched.c (create_reg_dead_note): Detect and handle another
+ case where we kill more regs after sched than were killed before
+ sched.
+ * sched.c (create_reg_dead_note): Similarly.
+
+Mon Dec 22 09:18:37 1997 Jeffrey A Law (law@cygnus.com)
+
+ * c-pragma.c: Include flags.h.
+
+Sun Dec 21 22:10:59 1997 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * i386/cygwin32.h (NO_IMPLICIT_EXTERN_C): Don't assume anything
+ about system headers.
+ (LIB_SPEC): Add -ladvapi32 -lshell32 to be consistent with mingw32
+ and also to resolve symbols in prefix.c.
+
+ * i386/xm-cygwin32.h (HAVE_BCOPY): Define. This avoids a conflict
+ between gansidecl.h and newlib's _ansi.h when building libgcc2.a,
+ when the definitions in auto-config.h is not visible.
+ (HAVE_BZERO): Likewise.
+ (HAVE_BCMP): Likewise.
+ (HAVE_RINDEX): Likewise.
+ (HAVE_INDEX): Likewise.
+
+Sun Dec 21 21:54:22 1997 Jeffrey A Law (law@cygnus.com)
+
+ * pa.c (emit_move_sequence): Handle a function label source
+ operand.
+
+Sun Dec 21 16:13:55 1997 Nick Clifton <nickc@cygnus.com
+
+ * c-pragma.c (handle_pragma_token): Generate warning messages
+ about unknown pragmas if warn_unknown_pragmas is set.
+
+ * c-decl.c (c_decode_option): Parse -Wunknown-pragmas command
+ line option to set variable: warn_unknown_pragmas.
+
+Sun Dec 21 15:51:10 1997 Manfred Hollstein <manfred@lts.sel.alcatel.de>
+
+ * m68k/mot3300.h (ASM_BYTE_OP): Don't include '\t' in the
+ definition.
+ (ASM_OUTPUT_ASCII): Prefix ASM_BYTE_OP by one single '\t'.
+
+Sun Dec 21 13:58:39 1997 Jeffrey A Law (law@cygnus.com)
+
+ * Makefile.in (FPBIT_FUNCS, DPBIT_FUNCS): Define.
+ (libgcc2.a): Depend on $(DPBIT) and $(FPBIT). Add rules to
+ generate more fine grained floating point emulation libraries.
+ * config/fp-bit.c: Add protecting #ifdef to all functions so
+ that they can be compiled separately. If !FINE_GRAINED_LIBRARIES,
+ then compile all suitable functions.
+ (pack_d, unpack_d, fpcmp_parts): Add declarations, define with two
+ underscores to avoid namespace pollution.
+ * t-mn10200 (LIB2FUNCS_EXTRA): Remove fp-bit.c
+ (FPBIT): Define.
+ * t-mn10300 (LIB2FUNCS_EXTRA): Remove fp-bit.c and dp-bit.c
+ (FPBIT): Define.
+ (DPBIT): Define.
+
+Sat Dec 20 11:26:47 1997 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+ Jeff Law <law@cygnus.com>
+
+ * bitmap.c (bitmap_clear): Ensure `inline' is at the beginning
+ of the declaration.
+ * c-decl.c (finish_decl): Use parentheses around && within ||.
+ * rtl.c: Include stdlib.h.
+ (read_skip_spaces): Add parentheses around assignments used as
+ truth values.
+ (read_rtx): Initialize list_rtx.
+ * cppexp.c (parse_number): Use || when operands are truth values.
+ * alias.c (find_base_value): Add default case.
+ (memrefs_conflict): Likewise.
+ * combine.c (sets_function_arg_p): Likewise.
+ * genemit.c (gen_exp): Likewise.
+ * local-alloc.c (contains_replace_regs): Likewise.
+ * rtlanal.c (jmp_uses_reg_or_mem): Likewise.
+ * fold-const.c (fold_convert): Use "&&" for truth values.
+ (fold): Add default case.
+ * sdbout.c (sdbout_field_types): Fix typo in declaration.
+ (sdbout_one_type): Add default case.
+ * alpha.c (alpha_sa_mask): Prototype only if OPEN_VMS.
+ (some_operand): Add default case.
+ (input_operand): Likewise.
+ (signed_comparison_operator): Likewise.
+ (divmod_operator): Likewise.
+ (alpha_set_memflags_1): Likewise.
+ * reload1.c (reload_cse_simplify_operands): Ensure function
+ always returns a value.
+ * scan-decls.c (scan_decls): Likewise.
+ * c-lex.c (skip_white_space): Fix typo in declaraion.
+ * c-typeck.c (comp_target_types): Add parentheses around assignment
+ used as truth value.
+ (print_spelling): Likewise.
+ (constructor_implicit, constructor_result): Remove unused variables.
+ * collect2.c (scan_library): Protect prototype with
+ #ifdef SCAN_LIBRARIES.
+ * emit-rtl.c (find_line_note): Fix typo in declaration.
+ * final.c (asm_insn_count): Protect prototype with
+ #ifdef HAVE_ATTR_length.
+ * flow.c (find_auto_inc): Protect prototype with #ifdef AUTO_INC_DEC.
+ (try_pre_increment_1, try_pre_increment): Likewise.
+ * regclass.c (auto_inc_dec_reg_p): Protect prototype with
+ #ifdef FORBIDDEN_INC_DEC_CLASSES. Make return type explicit.
+ * gcov-io.h (__store_long, __write_long, __read_long): Fix
+ unsigned/signed comparisons.
+ * gcov.c (read_files): Remove unused "first_type" variable.
+ (scan _for_source_files): Initialize s_ptr.
+ (function_summary): Eliminate "%lf" formatting, use %ld for
+ longs.
+ (output_data): Initialize branch_probs and last_line_num.
+ Eliminate "%lf" formatting, use "%ld" for longs.
+
+Fri Dec 19 17:31:11 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * mips16.S: New file.
+
+ * libgcc2.c (varargs): Handle mips16.
+
+ * expr.c (do_tablejump): Let CASE_VECTOR_PC_RELATIVE be an
+ expression.
+ * stmt.c (expand_end_case): Likewise.
+ * alpha.h (CASE_VECTOR_PC_RELATIVE): Update.
+ * fx80.h, gmicro.h, m68k.h, m88k.h, ns32k.h: Likewise.
+ * rs6000.h, sh.h, tahoe.h, v850.h, vax.h: Likewise.
+
+Tue Dec 16 15:14:09 1997 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * objc/Make-lang.in: Create runtime-info.h and libobjc_entry.o in
+ the build directory.
+ (libobjc.a): Update dependency list.
+ (libobjc.dll): Likewise. Use libobjc_entry.o from the build
+ directory.
+ (objc/sendmsg.o): Add -Iobjc to find runtime-info.h.
+ (objc.mostlyclean): Remove runtime-info.h.
+
+Fri Dec 19 00:19:42 1997 Richard Henderson <rth@cygnus.com>
+
+ * tree.c (build_range_type): Allow creation of ranges with no maximum.
+ * dbxout.c (dbxout_range_type): Handle missing TYPE_MAX_VALUE.
+ * dwarf2out.c (add_subscript_info): Likewise.
+ * dwarfout.c (subscript_data_attribute, byte_size_attribute): Likewise.
+ * sdbout.c (plain_type_1): Likewise.
+ * stmt.c (pushcase_range, all_cases_count, node_has_high_bound):
+ Likewise.
+ * fold-const.c (int_const_binop, fold_convert, make_range, fold):
+ Likewise.
+
+Thu Dec 18 17:05:10 1997 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * mips.c (fatal): Remove declaration.
+
+1997-12-18 Mark Mitchell <mmitchell@usa.net>
+
+ * integrate.c (get_label_from_map): New function.
+ (expand_inline_function): Use it. Initialize the label_map to
+ NULL_RTX instead of gen_label_rtx.
+ (copy_rtx_and_substitute): Use get_label_from_map.
+ * integrate.h (get_label_from_map): New function.
+ (set_label_from_map): New macro.
+ * unroll.c (unroll_loop): Use them.
+ (copy_loop_body): Ditto.
+
+Thu Dec 18 19:19:57 1997 Ian Lance Taylor <ian@cygnus.com>
+
+ * mips/mips.h (INIT_SUBTARGET_OPTABS): Define if not defined.
+ (INIT_TARGET_OPTABS): Define.
+ * mips/ecoff.h: Include gofast.h before mips.h.
+ (INIT_SUBTARGET_OPTABS): Define instead of INIT_TARGET_OPTABS.
+ * mips/elf64.h: Likewise.
+ * mips/elf.h (ASM_OUTPUT_SECTION_NAME): Define.
+
+Thu Dec 18 14:51:12 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.c: Remove register_exception_table{,_p}.
+
+Thu Dec 18 14:57:29 1997 Gavin Koch <gavin@cygnus.com>
+
+ * unroll.c (calculate_giv_inc): Handle constant increment found in
+ a MEM with an appropriate REG_EQUAL note.
+
+ * calls.c (expand_call): Implement LOAD_ARGS_REVERSED.
+
+ * dwarf2out.c (dwarf2out_frame_debug): Handle adjustments of the
+ frame pointer in the prologue.
+
+Thu Dec 18 00:19:38 1997 Robert Lipe <robertl@dgii.com>
+
+ * i386/x-sco5 (CLIB) Deleted. (ALLOCA) Added.
+ * i386/xm-sco5.h (USE_C_ALLOCA) Added.
+
+Tue Dec 16 18:51:00 1997 Bill Moyer <billm@cygnus.com>
+
+ * config/m68k/m68k.c (output_function_prologue): Typecast
+ dwarf2out_cfi_label to (char *).
+ * config/m68k/m68kemb.h (STARTFILE_SPEC): Redefined to "".
+
+Wed Dec 17 15:06:04 1997 Richard Henderson <rth@cygnus.com>
+
+ * sparc.md (jump): Don't use the annul bit around an empty loop.
+ Patch from Kevin.Kelly@East.Sun.COM.
+
+Wed Dec 17 00:51:36 1997 Stan Cox (scox@cygnus.com)
+
+ * jump.c: (jump_optimize): Don't use the return register as a
+ source1 of a conditional move.
+
+Tue Dec 16 23:45:40 1997 Richard Henderson <rth@cygnus.com>
+
+ * sparc.c (DF_MODES): Or the mask not the bit number.
+ (function_arg) [ARCH64]: Send unprototyped arg to fp reg first.
+
+Wed Dec 17 00:13:48 1997 Christian Iseli <Christian.Iseli@lslsun.epfl.ch>
+
+ * combine.c (force_to_mode): return immediately if operand is a CLOBBER.
+
+Tue Dec 16 23:44:54 1997 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * fixincludes (size_t): Add support for Motorola's stdlib.h
+ which fails to provide a definition for size_t.
+ (fabs/hypot): Provide a prototype for fabs on m88k-motorola-sysv3.
+ (strlen,strspn,strcspn return value): Handle different layout on sysV88.
+ (hypot): Provide a fake for hypot for m88k-motorola-sysv3.
+
+ * m68k/xm-mot3300.h (ADD_MISSING_POSIX, ADD_MISSING_XOPEN): Define to
+ prevent unresolved externals in libio.
+ * m88k/xm-sysv3.h (ADD_MISSING_POSIX, ADD_MISSING_XOPEN): Likewise.
+
+Tue Dec 16 23:25:45 1997 H.J. Lu (hjl@gnu.org)
+
+ * config/sparc/linux64.h (LIBGCC_SPEC): Removed.
+ (CPP_SUBTARGET_SPEC): Add %{pthread:-D_REENTRANT}.
+ (LIB_SPEC): Updated for glibc 2.
+
+Tue Dec 16 20:11:36 1997 Jeffrey A Law (law@cygnus.com)
+
+ * ginclude/stdarg.h: Undo BeOS changes, they break hpux.
+ * ginclude/varargs.h: Likewise.
+
+Tue Dec 16 00:32:01 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Tue Dec 16 00:14:29 1997 H.J. Lu (hjl@gnu.org)
+
+ * frame.h (__register_frame, __register_frame_table,
+ __deregister_frame): New.
+ * frame.c (__register_frame, __register_frame_table,
+ __deregister_frame): New.
+ * frame.c (__deregister_frame_info): Return void *.
+ * frame.h (__deregister_frame_info): Ditto.
+ * collect2.c (__deregister_frame_info): Ditto.
+
+Mon Dec 15 18:40:08 1997 Richard Henderson <rth@cygnus.com>
+
+ * expmed.c (expand_shift): If SHIFT_COUNT_TRUNCATED, drop a SUBREG.
+
+Mon Dec 15 18:31:43 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_cpu_name): New variable.
+ (alpha_mlat_string): Likewise.
+ (alpha_memory_latency): Likewise.
+ (override_options): Handle -mmemory-latency.
+ (alpha_adjust_cost): Adjust load cost for latency.
+ * alpha.h (TARGET_OPTIONS): Add meory-latency.
+ (REGISTER_MOVE_COST): Define in terms of memory_latency. Take
+ TARGET_CIX into account.
+ (MEMORY_MOVE_COST): Define in terms of memory_latency.
+ * invoke.texi (DEC Alpha Options): Document -mmemory-latency.
+
+ * alpha.h (ASM_COMMENT_START): New macro.
+
+Mon Dec 15 17:48:05 1997 Richard Henderson <rth@cygnus.com>
+
+ * reload.h, reload1.c (eliminate_regs), caller-save.c, dbxout.c,
+ dwarfout.c, dwarf2out.c, reload.c, sdbout.c: Revert March 15 change.
+
+ * reload.c (push_reload): If WORD_REGISTER_OPERATIONS, reload the
+ SUBREG_REG if the word count is unchanged.
+ * reload1.c (eliminate_regs) [case SET]: If W_R_O, preserve
+ subregs of identical word size for push_reload.
+
+Mon Dec 15 Mark Mitchell <mmitchell@usa.net> 11:41:32 1997
+
+ * toplev.c (rest_of_compilation): Don't call save_for_inline_copy
+ if all we're doing is dealing with -Wreturn-type.
+
+Mon Dec 15 09:44:39 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.md (zero_extendqihi2, zero_extendqisi2, zero_extendqidi2):
+ Use and 255 instead of zapnot 1, since it schedules better.
+
+Mon Dec 15 08:48:24 1997 Jeffrey A Law (law@cygnus.com)
+
+ * stmt.c (expand_asm_operands): If an ASM has no outputs, then treat
+ it as volatile.
+
+Mon Dec 15 00:04:48 1997 Jeffrey A Law (law@cygnus.com)
+
+ * haifa-sched.c (remove_dependencies): Set RTX_INTEGRATED_P on
+ dependency we delete. Properly update prev for multiple consecutive
+ deletions.
+ (priority): Skip deleted dependence.
+
+Fri Dec 12 18:54:23 1997 Per Bothner <bothner@cygnus.com>
+
+ * expr.c (expand_builtin): Support BUILT_IN_FMOD - just call fmod.
+
+Fri Dec 12 01:19:48 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * flow.c (flow_analysis): Be consistent with find_basic_blocks in
+ determining when a new basic block starts.
+
+ * alpha/osf2or3.h (LIB_SPEC): Restore missing defn.
+
+ * pa.h (TEXT_SPACE_P): Use TREE_CODE_CLASS.
+ * pa.md (iorsi3): Add missing args to *_operand calls.
+
+ * except.c (call_get_eh_context): Don't mess with sequences.
+ (emit_eh_context): Include the call in the sequence here.
+
+1997-12-11 Paul Eggert <eggert@twinsun.com>
+
+ * collect2.c (write_c_file_glob): Allocate initial frame object
+ in static storage and pass its address.
+
+Thu Dec 11 23:33:48 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.c (call_get_eh_context): Don't take a parm.
+ Put the call at the top of the function.
+ (emit_eh_context): Adjust.
+ (get_eh_context): Replace with former use_eh_context.
+ (get_eh_context_once, get_saved_pc_ref): Remove.
+ (start_eh_unwinder, end_eh_unwinder, emit_unwinder): Remove.
+ * except.h: Adjust.
+ * integrate.c (expand_inline_function): Adjust.
+ * toplev.c (rest_of_compilation): Don't call emit_unwinder.
+
+Fri Oct 10 17:58:31 CEST 1997 Marc Lehmann <pcg@goof.com>
+
+ * i386/xm-go32.h (EXECUTABLE_SUFFIX): Define.
+ (DIR_SEPARATOR, NO_SYS_SIGLIST): Likewise.
+
+Thu Dec 11 23:55:17 1997 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * fixincludes (strlen,strspn,strcspn return value): Handle different
+ layout on sysV88.
+ (hypot): Provide a fake for hypot which is broken on
+ m88k-motorola-sysv3.
+
+Thu Dec 11 23:50:17 1997 John F. Carr <jfc@mit.edu>
+
+ * tree.c, tree.h: Change tree_code_type, tree_code_length, and
+ tree_code_name from pointers to arrays.
+ * tree.c: Remove standard_tree_code_* variables, no longer used.
+ * print-tree.c: Remove declaration of tree_code_name.
+
+ * cp/lex.c (init_lex): Update for tree_code_* changes.
+ * objc/objc-act.c (init_objc): Likewise.
+
+ * tree.def, cp/cp-tree.def, objc/objc-tree.def: Update for tree_code
+ changes.
+
+Thu Dec 11 23:34:54 1997 Fred Fish <fnf@ninemoons.com>
+
+ * config.sub: Add support for BeOS target.
+ * configure.in: Likewise.
+ * ginclude/stdarg.h: Likewise.
+ * ginclude/stddef.h: Likewise.
+ * ginclude/varargs.h: Likewise.
+ * rs6000/beos.h: New file for BeOS.
+ * rs6000/t-beos: Likewise.
+ * rs6000/x-beos: Likewise.
+ * rs6000/xm-beos.h: Likewise.
+ * toplev.c (get_run_time): Just return 0 on BeOS.
+
+Thu Dec 11 23:25:23 1997 Jeffrey A Law (law@cygnus.com)
+ Toon Moene (toon@moene.indiv.nluug.nl)
+
+ * m68k.h (GO_IF_LEGITIMATE_ADDRESS): No longer cater to horribly
+ old and broken Sun3 assemblers. Newer versions handle large
+ offsets correctly as does the GNU assembler.
+
+Thu Dec 11 23:06:48 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+
+ * objc/objc-act.c (lang_report_error_function): Disable.
+ * objc/objc-parse.y: Include "output.h".
+ (yyerror): Remove redundant decl.
+ (yyprint): Fix prototype.
+ (apply_args_register_offset): Remove redundant decl.
+ (get_file_function_name): Likewise.
+
+Thu Dec 11 22:02:10 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * flow.c (find_basic_blocks): A CALL_INSN that can throw starts
+ a new basic block.
+ (find_basic_blocks_1): Likewise.
+
+Thu Dec 11 21:08:48 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.c (use_eh_context): Don't copy_rtx a REG.
+ (emit_throw): Lose old unwinder support.
+ (expand_internal_throw): Likewise.
+ * libgcc2.c (struct eh_context): Likewise.
+ (new_eh_context): Likewise.
+ (__get_eh_info): Lose redundant cast.
+ (__get_dynamic_handler_chain): Likewise.
+ (__get_saved_pc): Lose.
+ Lose all old unwinder support code.
+
+Thu Dec 11 20:42:18 1997 Teemu Torma <tot@trema.com>
+
+ Thread-safe EH support for pthreads, DCE threads and Solaris threads.
+
+ * integrate.c (expand_inline_function): If the inline fn uses eh
+ context, make sure that the current fn has one.
+ * toplev.c (rest_of_compilation): Call emit_eh_context.
+ * except.c (use_eh_context): New fn.
+ (get_eh_context_once): New fn.
+ (call_get_eh_context): New fn.
+ (emit_eh_context): New fn.
+ (get_eh_context): Call either get_eh_context_once or
+ call_get_eh_context, depending on what we have.
+ (get_dynamic_handler_chain): Call get_eh_context_once.
+ * except.h: Prototypes for fns above.
+ * optabs.c (get_eh_context_libfunc): Removed.
+ (init_optabs): Don't initialize it.
+ * expr.h (get_eh_context_libfunc): Removed.
+ * rtl.h, rtl.c: New reg_note REG_EH_CONTEXT.
+ * config/pa/pa.h (CPP_SPEC): Support for -threads.
+ * config/pa/pa-hpux10.h (LIB_SPEC): Ditto.
+ * config/pa/t-pa (MULTILIB_OPTIONS, MULTILIB_DIRNAMES):
+ New multilib for -threads.
+ * config/sparc/t-sol2: Added multilibs for -threads and
+ made -pthreads alias to it.
+ * config/sparc/sol2.h (CPP_SPEC, LIB_SPEC):
+ Added -threads and -pthreads options.
+ * libgcc-thr.h: New file.
+ * libgcc2.c: (__get_cpp_eh_context): Removed.
+ (struct cpp_eh_context): Removed.
+ (struct eh_context): Replaced cpp_eh_context with generic language
+ specific pointer.
+ (__get_eh_info): New function.
+ (__throw): Check eh_context::info.
+ (__sjthrow): Ditto.
+ * libgcc2.c: Include libgcc-thr.h.
+ (new_eh_context, __get_eh_context,
+ eh_pthread_initialize, eh_context_initialize, eh_context_static,
+ eh_context_specific, eh_context_free): New functions.
+ (get_eh_context, eh_context_key): New variables.
+ (__sjthrow, __sjpopnthrow, __eh_pcnthrow, __throw): Use
+ get_eh_context to get the context.
+ (longjmp): Move the declaration inside
+ #ifdef DONT_USE_BUILTIN_SETJMP.
+ * frame.c: Include libgcc-thr.h.
+ (object_mutex): Mutex to protect the object list.
+ (find_fde, __register_frame, __register_frame_table,
+ __deregister_frame): Hold the lock while accessing objects.
+ * except.h (get_eh_context): Declare.
+ * except.c (current_function_ehc): Define.
+ (current_function_dhc, current_function_dcc): Removed.
+ (get_eh_context): New function.
+ (get_dynamic_handler_chain): Use get_eh_context.
+ (get_saved_pc_ref): Ditto.
+ (get_dynamic_cleanup_chain): Removed references to
+ current_function_dcc.
+ (save_eh_status, restore_eh_status): Save and restore
+ current_function_ehc instead.
+ * optabs.c (get_eh_context_libfunc): New variable.
+ (init_optabs): Initialize it.
+ * expr.h: Declare get_eh_context_libfunc.
+ * function.h (struct function): Replaced dhc and dcc with ehc.
+ * except.c (get_saved_pc_ref): New functions.
+ (eh_saved_pc_rtx, eh_saved_pc): Deleted.
+ (expand_internal_throw_indirect): Use get_saved_pc_ref() instead
+ of eh_saved_pc.
+ (end_eh_unwinder): Likewise.
+ (init_eh): Remove initialization of eh_saved_pc.
+ * optabs.c (get_saved_pc_libfunc): New variable.
+ (init_optabs): Initialize it.
+ * expr.h: Declare get_saved_pc_libfunc.
+ * except.h (eh_saved_pc_rtx): Deleted.
+ (get_saved_pc_ref): Declared.
+
+ From Scott Snyder <snyder@d0sgif.fnal.gov>:
+ * libgcc2.c (__get_saved_pc): New.
+ (__eh_type, __eh_pc): Deleted.
+ (__eh_pcnthrow): Use __get_saved_pc() instead of __eh_pc.
+ (__get_dynamic_handler_chain): Move __dynamic_handler_chain inside
+ this fcn.
+
+Thu Dec 11 17:23:48 1997 John F. Carr <jfc@mit.edu>
+
+ * sparc/sol2.h: Use 64 bit multiply and divide functions in
+ Solaris libc. Define TARGET_LIVE_G0 and TARGET_BROKEN_SAVERESTORE
+ as 0.
+
+ * rtl.h (global_rtl): New variable, replacing separate variables for
+ commonly used rtl.
+ (const_int_rtx): Now array of rtx_def, not rtx.
+ * emit-rtl.c: Update for new rtl data structures.
+ * genattrtab.c: Define global_rtl.
+
+Thu Dec 11 15:50:29 1997 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * configure.in ({rs6000,powerpc}-*-*): Enable Haifa scheduler by
+ default.
+
+Wed Dec 10 12:30:18 1997 Anthony Green <green@cygnus.com>
+
+ * crtstuff.c (__do_global_ctors): Fix typo.
- * expr.c (convert_move): Don't access a hard reg in an invalid
- mode when doing a truncation.
+Tue Dec 9 09:43:59 1997 Manfred Hollstein <manfred@s-direktnet.de>
- * alpha.c (add_operand): Test for exactly the constants allowed by
- the constraints.
- * alpha.h (CONST_OK_FOR_LETTER_P, case 'L'): Reject 0x80000000.
+ * toplev.c (main): Check HAVE_GETRLIMIT and HAVE_SETRLIMIT in addition
+ to RLIMIT_STACK to see if we can call getrlimit and setrlimit.
- * c-parse.in (initdcl, notype_initdcl): Pass attributes to
- start_decl; delete call to decl_attributes.
- * c-tree.h (start_decl): Two new tree parameters.
- * c-decl.c (start_decl): New args for attributes; call decl_attributes.
+Tue Dec 9 09:38:58 1997 David Edelsohn <edelsohn@mhpcc.edu>
- * c-decl.c (duplicate_decls): Don't look at TYPE_ACTUAL_ARG_TYPES
- if it is not set.
+ * rs6000.h (FUNCTION_ARG_PADDING): Define.
+ * rs6000.c (function_arg_padding): New function.
- * xm-1750a.h: New file.
+Tue Dec 9 10:34:21 1997 Manfred Hollstein <manfred@s-direktnet.de>
- * alpha.c (alpha_builtin_saveregs): Add to incoming args addr
- if less than 6 named args, not less than or equal to.
+ * m68k.c: Include tree.h only once.
-Mon Apr 24 15:25:19 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Dec 9 09:32:33 1997 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
- * mips-tfile.c (fatal, error): Make first arg const to avoid warning.
+ * integrate.c (save_for_inline_copying): Make a new reg_parm_stack_loc.
- * stmt.c (expand_end_bindings): Write a BARRIER after call
- to abort in nonlocal handler.
+Tue Dec 9 01:16:06 1997 Jeffrey A Law (law@cygnus.com)
- * stmt.c (expand_decl_init): Call preserve_temp_slots to keep
- around any temp whose address was taken.
+ * Partially cleaned up prototyping code from HJ.
+ * tree.h: Add many prototypes.
+ * haifa-sched.c (haifa_classify_insn): Renamed from classify_insn.
+ All references changed.
+ * rtl.h: Protect from multiple inclusions. Add many prototypes.
-Fri Apr 21 16:26:15 1995 Torbjorn Granlund <tege@adder.cygnus.com>
+Tue Dec 9 01:15:15 1997 Fred Fish <fnf@ninemoons.com>
- * pa.md (call_internal_reg): Fix typos in length calculation.
- (call_value_internal_reg): Likewise.
+ * libgcc2.c (string.h): Hoist inclusion to occur before first use of
+ string functions like strlen.
-Fri Apr 21 13:17:15 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+Tue Dec 9 00:57:38 1997 Manfred Hollstein <manfred@s-direktnet.de>
- * config/gnu.h (STANDARD_INCLUDE_DIR): New macro.
- * config/mips/gnu.h (STANDARD_INCLUDE_DIR): Macro moved there.
+ * configure.in: Check for functions getrlimit and setrlimit.
+ * cccp.c (main): Check HAVE_GETRLIMIT and HAVE_SETRLIMIT in addition
+ to RLIMIT_STACK to see if we can call getrlimit and setrlimit.
-Fri Apr 21 08:23:58 1995 Tom Quiggle (quiggle@lovelace.engr.sgi.com)
+Mon Dec 8 23:53:26 1997 Jay Sachs <sachs@bull.cs.williams.edu>
- * toplev.c (lang_options): Add -I for GNAT.
- * gcc.c (default_compilers): Pass -I to gnat1.
+ * Makefile.in (compare*): Handle losing behavior from 4.4bsd make.
-Fri Apr 21 07:58:06 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Mon Dec 8 21:03:28 1997 Richard Henderson <rth@cygnus.com>
- * tree.c (integer_all_onesp): Test to size of mode, not TYPE_PRECISION.
+ * alpha.c (REG_RA, alpha_return_addr, output_epilog):
+ Fix merge problems.
- * toplev.c (main): Turn on -fforce-mem for -O2.
+ * alpha.c (override_options): Don't know about scheduling for EV6.
+ * alpha.md (ev5 function units): Don't overload as ev6.
- * fold-const.c ([lr]rotate_double): Replace; old versions were bogus.
- (fold, shift and rotate): Don't call tree_int_cst_sgn on non-integer.
- (fold, case LROTATE_EXPR): If constant count, convert to RROTATE_EXPR.
- (fold, case RROTATE_EXPR): Sometimes commute logical op with rotate.
- Delete pair of counteracting shifts.
+ * alpha.c (alpha_adjust_cost): Simplify. Fix typo in ev5 mult case.
+ * alpha.md (define_attr type): Add mvi.
+ (ev5_e0): Define sceduling parameters for it.
+ (TARGET_MAX insns): Type is mvi not shift.
- * combine.c (simplify_logical, case AND): If still an AND, get
- new values for op0 and op1.
+Mon Dec 8 18:15:00 1997 Richard Henderson <rth@cygnus.com>
-Thu Apr 20 17:52:10 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * alpha/win-nt.h (TRAMPOLINE_TEMPLATE): Fix backported gcc-2.8 bug.
- * sh.c: Completely rewritten.
- * sh.h (FAST_BIT, CONSTLEN_2_BIT, CONSTLEN_3_BIT, CONSTLEN_0_BIT,
- TARGET_FASTCODE, TARGET_CLEN3, TARGET_CLEN0, TARGET_OPTIONS): Delete.
- (TARGET_SWITCHES): Delete -mclen3 and -mclen0 options.
- (TARGET_DEFAULT): Is zero.
- (OVERRIDE_OPTIONS): Delete code to set max_count_si and max_count_hi.
- (SPECIAL_REG): New macro.
- (HARD_REGNO_MODE_OK): Allow any mode in any general register.
- (GO_IF_LEGITIMATE_ADDRESS): Delete constant + reg address case.
- (MOVE_RATIO): Define to 2 when TARGET_SMALLCODE.
- (max_si, max_hi, max_count_si, max_count_hi): Delete.
- * sh.md: Delete spurious constraints from all define_expands.
- (rotlsi3_1): Set T reg instead of clobbering it.
- (ashrsi3): Use expand_ashiftrt instead of gen_shifty_op.
- (movsi_i, movhi_i, movsf_i): Add conditions to reject patterns
- needing a reload.
- (movdi-2, movdf_k): Correct conditions to reject patterns needing
- a reload.
- ([inverse_]branch_{true,false}): Pass operands to output_branch.
- (jump): Delete unnecessary braces.
- (call, call_value): Don't use expand_acall. Force operand0 into
- a register.
+Mon Dec 8 21:17:28 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
-Thu Apr 20 12:57:16 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cstamp-h, auto-config.h: Delete.
- * function.c (assign_parms): Use TREE_ADDRESSABLE rather than
- TYPE_NEEDS_CONSTRUCTING to decide whether a parameter needs to be
- passed by invisible reference.
+Sun Dec 7 19:19:03 1997 Jeffrey A Law (law@cygnus.com)
- * calls.c (expand_call): Ditto. Abort if we try to pre-evaluate a
- parameter of TREE_ADDRESSABLE type.
+ * version.c: Bump for snapshot.
-Wed Apr 19 17:50:24 1995 Torbjorn Granlund <tege@cygnus.com>
+Sat Dec 6 22:22:22 1997 Jeffrey A Law (law@cygnus.com)
- * pa.h (TARGET_SWITCHES): Fix typo.
+ * cccp.c: Fix typo brought over in merge.
-Tue Apr 18 18:06:03 1995 Per Bothner <bothner@kalessin.cygnus.com>
+ * Merge in changes from gcc-2.8.
- * expr.c (store_constructor): Use BYTES_BIG_ENDIAN rather
- than BITS_BIG_ENDIAN to layout bits within bitstring.
- * tree.c (get_set_constructor_bytes): Likewise.
+Mon Nov 3 05:45:32 1997 Philippe De Muyter <phdm@macqel.be>
-Tue Apr 18 17:22:46 1995 Per Bothner (bothner@wombat.gnu.ai.mit.edu)
+ * m68k.c: Include tree.h for dwarf2out_cfi_label.
- * config/m68k/{x-hp320,x-hp320g} (FIXPROTO_DEFINES):
- Define _HPUX_SOURCE so putenv and other functions get seen.
+ * gcc.c (process_command): Do not take address of function fatal when
+ calling lang_specific_driver.
-Tue Apr 18 03:57:35 1995 Michael Meissner (meissner@cygnus.com)
+Sat Dec 6 01:02:38 1997 Mumit Khan <khan@xraylith.wisc.edu>
- * varasm.c (weak_decls): Make this a unique structure, instead of
- a tree structure.
- (handle_pragma_weak): Don't redeclare asm_out_file. Use new weak
- structure to copy name and value to. Protect name and value by
- copying them to the permanent obstack.
- (declare_weak): Call handle_pragma_weak, instead of duplicating
- the code.
- (finish_weak): Rewrite to use new weak symbols list structure.
+ * config/i386/cygwin32.h (DWARF2_UNWIND): Exception handling
+ doesn't work with it yet, so set it to 0.
+ * config/i386/xm-cygwin32.h (NO_SYS_SIGLIST): Define.
- * c-pragma.h: New file to define the c-pragma.c interfaces.
- * c-pragma.c: Include it.
- * varasm.c: Include it.
- * c-lex.c: Include it.
- * cp/lex.c: Include it.
+Sat Dec 6 01:01:02 1997 Christian Iseli <Christian.Iseli@lslsun.epfl.ch>
- * varasm.c (handle_pragma_weak): No longer pass output file
- stream, since weak pragmas are delayed until the end of the
- compilation.
- * c-pragma.c (handle_pragma_token): Call handle_pragma_weak
- without file stream argument.
+ * cse.c (cse_insn): Check for invalid entries when taking references.
- * Makefile.in (varasm.o, c-lex.o, c-pragma.o): Add dependencies on
- c-pragma.h.
+Fri Dec 5 18:26:25 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
- * config/rs6000.md (movdf): If -msoft-float, do not generate
- memory to memory references, like is already done for the
- -mhard-float case. Remove an extra test for -mhard-float inside
- of -mhard-float code.
+ * loop.c (invariant_p): Don't test flag_rerun_loop_opt.
+ (loop_optimize, scan_loop, strength_reduce): New argument unroll_p.
+ * toplev.c (rest_of_compilation): Pass it. Remove code to
+ save / clear / restore flag_unroll_{,all_}loops.
-Tue Apr 18 06:19:50 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Fri Dec 5 16:26:03 1997 Bernd Schmidt <crux@ohara.Informatik.RWTH-Aachen.DE>
- * fold-const.c (size_int): Arg is unsigned HOST_WIDE_INT.
- * tree.h (size_int): Likewise.
+ * i386.c (notice_update_cc): Remove bogus pentium GCC code.
-Mon Apr 17 23:36:57 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Fri Dec 5 16:25:14 1997 Jeffrey A Law (law@cygnus.com)
- * rs6000/aix41.h: Restore March 11th changes, plus
- (ASM_OUTPUT_EXTERNAL): Do add [DS] or [RW], just don't emit
- anything.
- * rs6000/aix3newas.h (ASM_OUTPUT_EXTERNAL): Ditto.
+ * stmt.c (warn_if_unused_value): Don't warn for TRY_CATCH_EXPR.
-Mon Apr 17 15:58:52 1995 Per Bothner <bothner@kalessin.cygnus.com>
+Thu Dec 4 11:51:00 1997 Jason Merrill <jason@yorick.cygnus.com>
- * config/mips/x-iris (FIXPROTO_DEFINES): Add -D_LANGUAGE_C_PLUS_PLUS.
- * config/mips/x-iris6: Likewise.
+ * except.c (get_dynamic_handler_chain): Only make the call once per
+ function.
- * cpplib.c: Rename make_definition to cpp_define.
- * cpplib.h (cpp_define): New declaration.
+ * except.c (expand_end_all_catch): Fix for sjlj exceptions.
- * cpplib.c (special_symbol): For T_SPECLINE, calculate __LINE__
- in enclosing file buffer, not current buffer (if macro expanding).
- (cpp_get_token): Fix thinko (in code for chopping unneeded space).
+Thu Dec 4 12:30:40 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
-Mon Apr 17 11:36:07 1995 Jim Wilson <wilson@cygnus.com>
+ * sh.c (final_prescan_insn): Use local label prefix
+ when emitting .uses pseudo-ops.
- * abi64.h (CPP_SPECS): Define and use _ABI64 instead of
- _MIPS_SIM_ABI64.
- (SETUP_INCOMING_VARARGS): Set MEM_IN_STRUCT_P if big endian target.
- * iris6.h (ASM_IDENTIFY_GCC, ASM_IDENTIFY_LANGUAGE): Define.
+Wed Dec 3 12:01:56 1997 Jason Merrill <jason@yorick.cygnus.com>
- * combine.c (get_last_value): Ignore BARRIER when scanning backwards.
- (move_deaths): New variables before_dead and after_dead. Set them
- to instructions that have valid INSN_CUID values and use in test.
+ * libgcc2.c (__throw): Use __builtin_return_addr instead of __eh_pc.
+ * except.c: Lose outer_context_label_stack.
+ (expand_eh_region_end): Rethrow from outer_context here.
+ (expand_fixup_region_end): Let expand_eh_region_end do the rethrow.
+ (expand_internal_throw): Take no args.
+ (expand_internal_throw_indirect): Lose.
+ (expand_leftover_cleanups, expand_start_all_catch): Use expand_rethrow.
+ (expand_start_all_catch): Start a rethrow region.
+ (expand_end_all_catch): End it.
+ (expand_rethrow): New fn.
+ * except.h: Reflect above changes.
+ * flow.c: Revert change of Nov 27.
- * combine.c (subst_prev_insn): New variable.
- (try_combine): Set it.
- (get_last_value): Use it.
+Thu Dec 4 00:24:09 1997 Jeffrey A Law (law@cygnus.com)
- * reload.c (find_reloads): Recompute reg_equiv_address from
- reg_equiv_memory_loc before using it.
- (find_reloads_toplev, make_memloc): Likewise.
+ * i386/t-sol2 (CRTSTUFF_T_CFLAGS): Turn on the optimizer.
- * expr.c (expand_builtin, case BUILT_IN_MEMCPY): Call force_operand
- on dest_rtx before returning it.
+Wed Dec 3 12:01:56 1997 Jason Merrill <jason@yorick.cygnus.com>
- * function.c (instantiate_decls): Use temporary allocation if
- DECL_DEFER_OUTPUT is set.
+ * except.c (expand_fixup_region_end): New fn.
+ (expand_fixup_region_start): Likewise.
+ (expand_eh_region_start_tree): Store cleanup into finalization here.
+ * stmt.c (expand_cleanups): Use them to protect fixups.
-Sat Apr 15 23:19:03 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed Dec 3 11:41:13 1997 Gavin Koch <gavin@cygnus.com>
- * aoutos.h (ASM_OUTPUT_DEF): Define instead of SET_ASM_OP.
- * sparc/sunos4.h (ASM_OUTPUT_DEF): Ditto.
+ * mips/mips.md (muldi3_r4000): Broaden the output template
+ and attribute assignments to handle three operand dmult;
+ rename to muldi3_internal2.
+ (muldi3): Call the new muldi3_internal2 for R4000, and
+ any GENERATE_MULT3 chip.
- * varasm.c (weak_finish): Don't handle aliases.
- (declare_weak): Ditto.
- (assemble_alias): Handle aliases.
+Tue Dec 2 19:40:43 1997 Jason Merrill <jason@yorick.cygnus.com>
- * c-common.c (enum attrs): Add A_ALIAS.
- (init_attributes): Ditto.
- (decl_attributes): Ditto.
+ * stmt.c (expand_decl_cleanup): Update thisblock after eh_region_start.
-Sat Apr 15 13:26:34 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Dec 2 12:54:33 1997 Jim Wilson <wilson@cygnus.com>
- * calls.c (expand_call): Call preserve_temp_slots on temps
- made for BLKmode args returned in registers.
+ * unroll.c (find_splittable_givs): Remove last change. Handle givs
+ with a dest_reg that was created by loop.
- * pa.c (override_options): Fix typo.
+Sat Nov 29 12:44:57 1997 David Edelsohn <edelsohn@mhpcc.edu>
-Sat Apr 15 12:11:46 1995 Brendan Kehoe <brendan@cygnus.com>
+ * rs6000.c (function_arg_partial_nregs): Undo Nov. 26 patch.
- * alpha/alpha.c (output_epilog): Initialize fp_offset to 0, and
- make sure it's non-zero before we try to use it to restore the
- frame pointer.
+ * rs6000/aix41.h (ASM_CPU_SPEC): Define.
-Fri Apr 14 19:45:05 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Fri Nov 28 10:00:27 1997 Jeffrey A Law (law@cygnus.com)
- * ginclude/va-{clipper,pa,pyr,sparc,spur}.h (va_arg): Reorganize
- to avoid BIND_EXPRs and COND_EXPRs of aggregate type.
+ * configure.in: Fix NCR entries.
-Fri Apr 14 19:31:14 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+Thu Nov 27 12:20:19 1997 Jeffrey A Law (law@cygnus.com)
- * config/svr4.h (ASM_OUTPUT_SECTION_NAME): Make the section
- read-only executable "ax" if DECL is a FUNCTION_DECL; read-only
- "a" (previously the case always) if DECL is TREE_READONLY;
- otherwise writable "aw".
+ * flow.c (find_basic_blocks): Handle cfg issues for rethrows and
+ nested exceptions correctly.
-Fri Apr 14 18:49:11 1995 Linus Torvalds <Linus.Torvalds@cs.Helsinki.FI>
+ * unroll.c (find_splittable_givs): Don't split givs with a dest_reg
+ that was created by loop.
- * alpha.md (probe_stack): Probe with write, not read.
- (allocate_stack): Update and correct stack probe code.
- * alpha.c (output_prolog): Changed stack probe at function entry.
+Thu Nov 27 09:34:58 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri Apr 14 18:42:34 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * expr.c (preexpand_calls): Don't look past a TRY_CATCH_EXPR.
- * jump.c (delete_insn): When deleting after label, delete
- a BARRIER as well.
+ * except.c (expand_start_all_catch): One more do_pending_stack_adjust.
-Fri Apr 14 14:40:48 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed Nov 26 15:47:30 1997 Michael Meissner <meissner@cygnus.com>
- * toplev.c (compile_file): Call weak_finish.
+ * rs6000.c (SMALL_DATA_REG): Register to use for small data relocs.
+ (print_operand): Use SMALL_DATA_REG for the register involved in
+ small data relocations.
+ (print_operand_address): Ditto.
- * c-common.c (enum attrs): Add A_WEAK.
- (init_attributes): Ditto.
- (decl_attributes): Support __attribute__ ((weak)) by
- calling declare_weak.
+ * rs6000/linux.h (LINK_SPEC): Pass -dynamic-linker /lib/ld.so.1 if
+ -dynamic linker is not used.
- * sparc/sunos4.h (HANDLE_PRAGMA_WEAK, WEAK_ASM_OP, SET_ASM_OP):
- Define to support weak symbols with -fgnu-linker.
- * aoutos.h: Ditto.
+ * rs6000.md (call insns): For local calls, use @local suffix under
+ System V. Don't use @plt under Solaris.
- * varasm.c (handle_pragma_weak): Add declared weak symbols to
- weak_decls rather than emitting them immediately.
- (declare_weak): Add the indicated declaration to weak_decls.
- (weak_finish): Emit .weak directives for any weak symbols.
+ * rs6000.c (output_function_profiler): Put label address in r0, and
+ store LR in 4(sp) for System V/eabi.
- * libgcc2.c: The C++ free-store management functions are weak.
+ * rs6000.h (ASM_OUTPUT_REG_{PUSH,POP}): Keep stack aligned to 16
+ byte boundary, and maintain stack backchain.
-Fri Apr 14 13:00:29 1995 Michael Meissner (meissner@cygnus.com)
+Tue Nov 25 14:08:12 1997 Jim Wilson <wilson@cygnus.com>
- * rs6000/rs6000.c (output_prolog): For eabi systems, emit main's
- call to __eabi before setting up the minimal TOC used with the
- -mrelocatable support.
+ * mips.md (fix_truncdfsi2, fix_truncsfsi2, fix_truncdfdi2,
+ fix_truncsfdi2): Change *.
- * rs6000/eabi.h (INVOKE__main): Don't define any more,
- output_prolog will emit the call.
+Wed Nov 26 11:12:26 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri Apr 14 09:09:03 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * toplev.c (main): Complain about -gdwarfn.
- * alpha.c (call_operand): Any reg is valid for NT.
- (output_prologue): Never need GP for Windows/NT.
- Set SYMBOL_REF_FLAG in current function decl.
+Tue Nov 25 22:43:30 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Apr 13 20:19:30 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * dwarfout.c (output_type): If finalizing, write out nested types
+ of types we've already written.
- * alpha/xm-alpha.h (HAVE_VPRINTF): Define.
- (HAVE_PUTENV): Define.
- (POSIX): Define.
+Tue Nov 25 20:32:24 1997 Michael Meissner <meissner@cygnus.com>
-Thu Apr 13 19:57:44 1995 Doug Evans <dje@cygnus.com>
+ (patches originally from Geoffrey Keating)
+ * rs6000.c (function_arg): Excess floating point arguments don't
+ go into GPR registers after exhausting FP registers under the
+ System V.4 ABI.
+ (function_arg_partial_nregs): Ditto.
- * emit-rtl.c (gen_sequence): If the insn has a non-null
- CALL_INSN_FUNCTION_USAGE field, output it as a sequence so the
- latter isn't discarded.
+ * rs6000.md (call insns): If -fPIC or -mrelocatable, add @plt
+ suffix to calls.
- * c-parse.in: Update expected conflict count.
+Tue Nov 25 23:37:27 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Apr 13 08:10:20 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * integrate.c (output_inline_function): Just unset DECL_INLINE.
- * configure.bat: Arg 2 is which machine (i386 or alpha).
- * configure (alpha-*-winnt3*): New configuration.
- * alpha.c: Don't #include stamp.h for WINNT.
- (input_operand, case CONST): Allow ptr_mode and DImode.
- * alpha.h (WINDOWS_NT): Provide default definition.
- (ASM_OUTPUT_INT): Use output_addr_const.
- (ASM_OUTPUT_ADDR_DIFF_ELT): Use .long for NT.
- * alpha.md (calll, tablejump, movsi): New variants for NT.
- * alpha/winnt.h, alpha/xm-winnt.h, alpha/x-winnt: New files.
- * alpha/config-nt.bat, alpha/config-nt.sed: New files.
- * i386/config-nt.bat: Add Ada fragments to Makefile.
- * i386/config-nt.sed: Adjust for deletion of config.run in Makefile.in
- Change version to 2.6.3.
- Add some missing tabs.
- * winnt/winnt.h (TARGET_MEM_FUNCTIONS): Define.
- (LINK_SPEC): Delete "align:0x1000".
- * winnt/xm-winnt.h (OBJECT_SUFFIX): Define.
- * ginclude/stdarg.h, ginclude/varargs.h: Clean up code that
- defines *DEFINED* symbols.
+Tue Nov 25 23:33:29 1997 scott snyder <snyder@d0sgif.fnal.gov>
- * configure (a29k-*-sym1*): Same as a29k-*-bsd*.
- * a29k.h (ASM_OUTPUT_SECTION_NAME): New macro.
+ * dwarf2out.c (outout_call_frame_info): Ensure that the info has
+ proper alignment.
-Wed Apr 12 14:36:03 1995 Jim Wilson <wilson@cygnus.com>
+ * libgcc2.c (__throw): Initialize HANDLER.
- * dbxout.c (dbxout_type_fields): Correct arguments to CHARS macro
- in flag_minimal_debug case.
- (dbxout_symbol_name): Use DECL_ASSEMBLER_NAME unconditionally.
- * sdbout.c (sdbout_record_type_name): Correct indentation.
- (sdbout_symbol): Use DECL_ASSEMBLER_NAME unconditionally.
- (sdbout_one_type): Likewise.
+Tue Nov 25 14:08:12 1997 Jim Wilson <wilson@cygnus.com>
-Tue Apr 11 13:24:13 1995 Per Bothner <bothner@kalessin.cygnus.com>
+ * mips.md (fix_truncdfsi2, fix_truncsfsi2, fix_truncdfdi2,
+ fix_truncsfdi2): Change *X to ?*X.
- * fix-header.c (main): Fix loop over required_functions_list.
- (fatal): Also print inc_filename.
+Tue Nov 25 10:00:42 1997 Richard Henderson (rth@cygnus.com)
- * cpplib.c (cpp_push_buffer): Added missing initializatuon of buf.
- (cpp_file_buffer): Compare against CPP_NULL_BUFFER, not NULL.
- (finclude): No longer call cpp_push_buffer - let callers do it.
- (do_include): Add call to cpp_push_buffer.
- (push_parse_file): Call cpp_push_buffer early, so initial
- defines can use file and line from a valid cpp_buffer.
- (nreverse_pending): New function.
- (push_parse_file): Use nreverse_pending.
- (push_parse_file): For -include files, just push them in reverse
- order - we don't need to scan them now.
- (cpp_error_from_errno, cpp_perror_with_name): Don't emit extra '\n'.
+ * alpha.h (CONST_OK_FOR_LETTER): Fix 'L' handling.
-Tue Apr 11 13:36:44 1995 Jim Wilson <wilson@cygnus.com>
-
- * configure (mips-dec-mach3): Add.
-
- * sh.c (shiftby_operand): Delete.
- * sh.h (TARGET_SWITCHES): -m3 and -m3l also set SH2_BIT.
- (OVERRIDE_OPTIONS): Don't add CPU_SH2 to CPU_SH3 when TARGET_SH3.
- * sh.md (ashlsi3): Use nonmemory_operand as a predicate instead of
- shiftby_operand. Don't use shiftby_operand in the output statement.
+Tue Nov 25 10:00:42 1997 Jeffrey A Law (law@cygnus.com)
+
+ * crtstuff.c (do_global_dtors_aux): Handle multiple calls better.
+
+Tue Nov 25 01:26:55 1997 Bruno Haible <haible@ilog.fr>:
+
+ * dwarf2out.c (ASM_OUTPUT_DWARF_DELTA1): Implement.
+
+Mon Nov 24 22:41:55 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.c (get_dynamic_handler_chain): Build up a FUNCTION_DECL.
+ * optabs.c (init_optabs): Lose get_dynamic_handler_chain_libfunc.
+ * expr.h: Likewise.
+
+Sat Nov 22 18:58:20 1997 Jeffrey A Law (law@cygnus.com)
+
+ * pa-hpux10.h (NEW_HP_ASSEMBLER): Define.
+ * pa.h (LEGITIMATE_CONSTANT_P): Reject LABEL_REFs if not using
+ gas and not using the new HP assembler.
+
+Fri Nov 21 15:20:05 1997 Jeffrey A Law (law@cygnus.com)
+
+ * Makefile.in (program_transform_cross_name): Clean up "-e" confusion.
+ (GCC_INSTALL_NAME, GCC_CROSS_NAME): Likewise.
+
+Fri Nov 21 19:37:40 1997 Andrew Cagney <cagney@b1.cygnus.com>
+
+ * config/mips/elf64.h (MULTILIB_DEFAULTS): Test for
+ TARGET_ENDIAN_DEFAULT == zero instead of testing for macro
+ definition.
+
+Fri Nov 21 12:49:56 1997 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
+
+ * stmt.c (expand_end_bindings): Allow jump into block with cleanups.
+
+Fri Nov 21 12:18:51 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.h: Add outer_context_label_stack.
+ * except.c: Likewise.
+ (expand_start_all_catch): Push the outer_context for the try block
+ onto outer_context_label_stack.
+ (expand_end_all_catch): Use it and pop it.
+
+Fri Nov 21 10:13:11 1997 Robert Lipe (robertl@dgii.com)
+
+ * i386/sco5.h (HAVE_ATEXIT): Revert last change.
+
+Thu Nov 20 16:11:50 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_emit_set_const_1): Handle narrow hosts better.
+
+Thu Nov 20 16:11:50 1997 Klaus Kaempf <kkaempf@progis.de>
+
+ * alpha/vms.h (ASM_OUTPUT_ADDR_VEC_ELT): Add an L for the local label
+ to correspond with the change to ASM_GENERATE_INTERNAL_LABEL.
+
+Thu Nov 20 14:42:15 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * Makefile.in (LIB2FUNCS): Remove C++ memory management support.
+ * libgcc2.c: Remove __builtin_new, __builtin_vec_new, set_new_handler,
+ __builtin_delete, and __builtin_vec_delete.
+
+ * except.c (output_exception_table): Don't bother with
+ __EXCEPTION_END__.
+
+Thu Nov 20 16:11:50 1997 Jeffrey A Law (law@cygnus.com)
+
+ * pa.md (pre_stwm, post_stwm, pre_ldwm, post_ldwm): Base register
+ is an in/out operand.
+ (zero extended variants of stwm/stwm patterns): Similarly.
+
+ * mips/x-iris (FIXPROTO_DEFINES): Add -D_SGI_SOURCE.
+
+Thu Nov 20 13:19:32 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * dwarf2out.c (ASM_OUTPUT_DWARF_OFFSET4): Rename from VALUE4.
+ Use assemble_name.
+ (ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL): Use assemble_name.
+ (output_call_frame_info): Emit a \n after using it.
+
+Thu Nov 20 00:38:46 1997 Dave Love <d.love@dl.ac.uk>
+
+ * configure.in: Add AC_ARG_ENABLE for Haifa as documentation.
+
+Wed Nov 19 12:03:04 1997 Philippe De Muyter <phdm@macqel.be>
+
+ * dwarf2out.c (CIE_LENGTH_LABEL, FDE_LENGTH_LABEL): New macros.
+ (ASM_OUTPUT_DWARF_VALUE4): New macro.
+ (ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL): Define if SET_ASM_OP is
+ defined.
+ (output_call_frame_info): Do not output forward label differences
+ if ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL is defined.
+ * m68k/mot3300.h (SET_ASM_OP): Define when not using gas.
+
+Tue Nov 18 23:03:30 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.md (attribute "type"): Add nil.
+ (movsi_ie): y/y alternative is type nil.
+ (movsf_ie): Replace ry/yr/X alternative by r/y/X , y/r/X and y/y/X
+ alternatives.
+ (movsf_ie+1): Delete.
+
+Tue Nov 18 15:39:59 1997 Jim Wilson <wilson@cygnus.com>
+
+ * mips/mips.c (save_restore_insns): If gp_offset or fp_offset are
+ large_int, emit two insns instead of one splitable insn.
+ * dwarf2out.c (dwarf2out_frame_debug): When set cfa_store_offset
+ from cfa_temp_value, use cfa_offset. Add assert checking that
+ cfa_reg is SP.
+
+Mon Nov 17 15:35:38 1997 Tom Tromey <tromey@cygnus.com>
+
+ * cccp.c (deps_output): Properly quote file names for make.
+
+Mon Nov 17 13:21:40 1997 Jeffrey A Law (law@cygnus.com)
+
+ * t-h8300 (MULTILIB_EXCEPTIONS): Define.
+
+Fri Nov 7 15:33:11 1997 Robert Lipe (robertl@dgii.com)
+
+ * i386/sco5.h (HAVE_ATEXIT): Delete definition.
+
+Sun Nov 16 23:52:48 1997 Jeffrey A Law (law@cygnus.com)
+
+ * cse.c (cse_insn): Don't look at JUMP_LABEL field of a conditionl
+ return.
+ (cse_end_of_basic_block): Similarly.
+
+Sun Nov 16 23:01:40 1997 J. Kean Johnston <jkj@sco.com>
+
+ * i386/sco5.h (ASM_OUTPUT_ALIGNED_BSS): Define.
+ (SELECT_RTX_SECTION): Define.
+ (LIBGCC_SPEC, LIB_SPEC): Do the right thing for PIC.
+
+Sun Nov 16 22:47:03 1997 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * Makefile.in (compare, compare-lean): Define $stage for each
+ shell command.
+ (gnucompare, gnucompare-lean): Likewise.
+
+Sun Nov 16 22:02:16 1997 Richard Henderson (rth@cygnus.com)
+
+ * alpha/win-nt.h (TRAMPOLINE_TEMPLATE): Fix offsets.
+
+ * alpha.h (ASM_OUTPUT_ADDR_DIFF_ELT): Add an L for the local label
+ to correspond with the change to ASM_GENERATE_INTERNAL_LABEL.
+
+Fri Nov 14 09:09:20 1997 Fred Fish (fnf@cygnus.com)
+
+ * dwarfout.c (byte_size_attribute): Add local var upper_bound
+ and add case to handle STRING_TYPE.
+ * dwarfout.c (output_string_type_die): Fix code to generate
+ correct string length attribute for fixed length strings.
+ Still needs support for varying length strings.
+
+Fri Nov 14 08:46:56 1997 Jeffrey A Law (law@cygnus.com)
+
+ * toplev.c (get_run_time): Do something sensible for cygwin32.
+
+Fri Nov 14 07:24:20 1997 Richard Henderson <rth@cygnus.com>
+
+ * expr.c (expand_builtin_setjmp): Set
+ current_function_has_nonlocal_label.
+ * stupid.c (stupid_life_analysis): If has_nonlocal_label, kill
+ call-saved registers across calls.
+
+ * alpha.md (exception_receiver): Remove.
+ (nonlocal_goto_receiver_osf): New
+ (nonlocal_goto_receiver_vms): Renamed from nonlocal_goto_receiver.
+ (nonlocal_goto_receiver): New, select _osf or _vms.
+
+ * alpha.c (output_prolog [*]): Prefix entry labels with '$' to
+ keep them from being propogated to the object file.
+ (alpha_write_linkage): Likewise.
+ * alpha.md (call_vms): Likewise.
+ (call_value_vms): Likewise.
+ (unnamed osf call insns): Likewise.
+
+ * alpha.h (ASM_OUTPUT_INTERNAL_LABEL): Don't omit L from local label.
+ (ASM_GENERATE_INTERNAL_LABEL): Likewise.
+
+ * alpha.c (call_operand): Any reg is valid for WinNT.
+ * alpha.md (call_nt, call_value_nt): Don't force address into $27.
+ (anon nt calls): Add 'R' alternative.
+ * alpha/win-nt.h (TRAMPOLINE_TEMPLATE, TRAMPOLINE_SIZE,
+ INITIALIZE_TRAMPOLINE): Handle lack of original $27 and 32-bit ptrs.
+
+Fri Nov 14 06:59:33 1997 Jeffrey A Law (law@cygnus.com)
+
+ * calls.c (expand_call): Handle pcc_struct_value correctly for C++.
+
+ * i386/xm-cygwin32.h (HAVE_FILE_H, HAVE_RUSAGE): Delete defines.
+ * i386/xm-mingw32.h (HAVE_FILE_H, HAVE_RUSAGE): Likewise.
+ * rs6000/xm-cygwin32.h (HAVE_FILE_H, HAVE_RUSAGE): Likewise.
+
+Thu Nov 13 20:37:33 1997 Michael Meissner <meissner@tiktok.cygnus.com>
+
+ * reload1.c (new_spill_reg): Improve fixed or forbidden register
+ spill error message.
+
+Thu Nov 13 20:29:08 1997 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * prefix.c: Use stdarg.h only ifdef __STDC__. Otherwise,
+ use varargs.h. Wrap header with <>, not "".
+
+Thu Nov 13 20:21:17 1997 Jeffrey A Law (law@cygnus.com)
+
+ * integrate.c (save_for_inline_copying): Add return value from
+ savealloc.
+
+Thu Nov 13 19:12:33 1997 Brendan Kehoe <brendan@cygnus.com>
+
+ * fixincludes: Be a little more restrictive on what we will
+ substitute to replace definitions of MAXINT for HPUX.
+
+Thu Nov 13 18:41:02 1997 Michael Meissner <meissner@cygnus.com>
+
+ * dbxout.c (dbxout_symbol_location): Don't assume that variables
+ whose address is the stack or argument pointers are indirect
+ pointers.
+
+1997-11-13 Paul Eggert <eggert@twinsun.com>
+
+ * cccp.c, cpplib.c (compare_defs):
+ Don't complain about arg name respellings unless pedantic.
+ * cpplib.c (compare_defs): Accept pfile as new arg.
+ All callers changed.
+
+Thu Nov 13 23:33:50 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * fold-const.c (fold_truthop): Fix bug in last change.
+
+1997-11-13 Paul Eggert <eggert@twinsun.com>
+
+ Fix some confusion with IEEE minus zero.
+
+ * real.h (REAL_VALUES_IDENTICAL): New macro.
+
+ * expr.c (is_zeros_p): Don't consider -0.0 to be all zeros.
+ * fold-const.c (operand_equal_p): Don't consider -0.0 to be
+ identical to 0.0.
+ * tree.c (simple_cst_equal): Don't consider -0.0 to have the
+ same tree structure as 0.0.
+
+ * varasm.c (immed_real_const_1): Use new REAL_VALUES_IDENTICAL
+ macro instead of doing it by hand.
+
+Thu Nov 13 16:56:14 1997 Jeffrey A Law (law@cygnus.com)
+
+ * v850/lib1funcs.asm: Minor whitespace changes.
+ * v850.c: Fix minor formatting problems in many places.
+ (construct_restore_jr, construct_save_jarl): Remove unwanted aborts.
+
+Thu Nov 13 12:53:44 1997 Jim Wilson <wilson@cygnus.com>
+
+ * mips.h (GO_IF_LEGITIMATE_ADDRESS): Delete code swapping xplus0 and
+ xplus1 when xplus0 is not a register.
+
+Thu Nov 13 11:41:42 1997 Jeffrey A Law (law@cygnus.com)
+
+ * flow.c (find_basic_blocks): During marking phase, if we encounter
+ an insn with a REG_LABEL note, make the target block live and
+ create an edge from the insn to the target block. Do not make
+ edges from all blocks to the target block.
+
+ * m68k/x-next (OTHER_FIXINCLUDES_DIRS): Include /NextDeveloper/Headers.
+
+ * confiugre.in: Tweak NCR entries.
+ * configure: Rebuilt.
+
+Thu Nov 13 11:07:41 1997 Michael Meissner <meissner@cygnus.com>
+
+ * rs6000.c (num_insns_constant): Use REAL_VALUE_FROM_CONST_DOUBLE to
+ pick apart floating point values, instead of using CONST_DOUBLE_LOW
+ and CONST_DOUBLE_HIGH.
+
+ * rs6000.md (define_splits for DF constants): Use the appropriate
+ REAL_VALUE_* interface to pick apart DF floating point constants in
+ a machine independent fashion.
+
+Thu Nov 13 00:06:58 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * fold-const.c (fold_truthop): When changing a one-bit comparison
+ against zero into a comparison against mask, do a proper sign
+ extension.
+
+Wed Nov 12 09:37:01 1997 Jeffrey A Law (law@cygnus.com)
+
+ * except.c: Do not include "assert.h".
+ (save_eh_status): Turn asserts into conditional aborts.
+ (restore_eh_status, scan_region): Likewise.
+ * dwarfout.c: Do not include "assert.h".
+ (bit_offset_attribute): Turn asserts into conditional aborts.
+ (bit_size_attribute, output_inlined_enumeration_type_die): Likewise.
+ (output_inlined_structure_type_die): Likewise.
+ (output_inlined_union_type_die): Likewise
+ (output_tagged_type_instantiation): Likewise.
+ (dwarfout_file_scope_decl): Likewise.
+ * dwarf2out.c: Do not include "assert.h"
+ (expand_builtin_dwarf_reg_size): Turn asserts into conditional aborts.
+ (reg_save, initial_return_save, dwarf2out_frame_debug): Likewise.
+ (add_child_die, modified_type_die, add_bit_offset_attribute): Likewise.
+ (add_bit_size_attribute, scope_die_for): Likewise.
+ (output_pending_types_for_scope): Likewise.
+ (get_inlined_enumeration_type_die): Likewise.
+ (get_inlined_structure_type_die): Likewise.
+ (get_inlined_union_type_die, gen_subprogram_die): Likewise.
+ (gen_tagged_type_instantiation_die): Likewise.
+
+ * flow.c (find_basic_blocks): Refine further to get a more correct
+ cfg, especially in the presense of exception handling, computed
+ gotos, and other non-trivial cases. Call abort if an inaccuracy
+ is detected in the cfg.
+
+Tue Nov 11 21:47:27 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * glimits.h (SHRT_MIN): Define in a way suitable for 16 bit hosts.
+
+ * c-lex.c (whitespace_cr, skip_white_space_on_line): New functions.
+ (skip_white_space): Use whitespace_cr.
+ (check_newline): Handle whitespace more consistently.
+
+Tue Nov 11 16:25:49 1997 Jim Wilson <wilson@cygnus.com>
+
+ * i386/cygwin32.h (CPP_PREDEFINES): Delete -DPOSIX.
+ * i386/xm-cygwin32.h (POSIX): Define.
+
+Mon Nov 10 20:53:11 1997 Gavin Koch <gavin@cygnus.com>
+
+ * config/mips/mips.h (MASK_DEBUG_H): Set to zero, so this bit
+ is available elsewhere.
+
+Mon Nov 10 16:21:58 1997 Doug Evans <devans@canuck.cygnus.com>
+
+ * sparc/sparc.md (mov[sdt]f_const_insn): Fix condition to match
+ what the instruction can handle.
+
+Mon Nov 10 03:02:19 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * stmt.c (expand_decl_cleanup_no_eh): New fn.
+
+ * except.c (expand_leftover_cleanups): do_pending_stack_adjust.
+
+Mon Nov 10 00:05:56 1997 Jeffrey A Law (law@cygnus.com)
+
+ * alias.c (MAX_ALIAS_LOOP_PASSES): Define.
+ (init_alias_analysis): Break out of loops after MAX_ALIAS_LOOP_PASSES.
+
+Sun Nov 9 14:34:47 1997 David Edelsohn <edelsohn@mhpcc.edu>
+
+ * rs6000.md (lshrdi3_power): Delete '&' from first alternative and
+ swap instruction order.
+
+Sun Nov 9 02:07:16 1997 Jeffrey A Law (law@cygnus.com)
+
+ * fixinc.svr4 (__STDC__): Add another case.
+
+Sun Nov 9 02:00:29 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * a29k.h (ELIGIBLE_FOR_EPILOGUE_DELAY): Avoid loads from varying
+ addresses in the epilogue delay slot.
+
+Sun Nov 9 01:40:40 1997 Manfred Hollstein (manfred@s-direktnet.de)
+
+ * m88k/dgux.h (ASM_CPU_SPEC): Reformatted to suppress wrong whitespace
+ in generated `specs' file.
+
+Sun Nov 9 01:37:11 1997 Jim Wilson (wilson@cygnus.com)
+
+ * flags.h (flag_rerun_loop_opt): Declare.
+ * loop.c (invariant_p, case LABEL_REF): Check flag_rerun_loop_opt.
+ * toplev.c (flag_rerum_loop_opt): Delete static.
+
+Sat Nov 8 18:20:21 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ Bring over from FSF:
+
+ Thu Oct 30 12:21:06 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * va-sh.h (__va_arg_sh1): Define.
+ (va_arg): Use it.
+ SH3E doesn't use any integer registers for subsequent arguments
+ once a non-float value was passed in the stack.
+ * sh.c (machine_dependent_reorg): If optimizing, put explicit
+ alignment in front label for ADDR_DIFF_VEC.
+ * sh.h (PASS_IN_REG_P): Fix SH3E case.
+ (ADJUST_INSN_LENGTH): If not optimizing, add two extra bytes length.
+
+ Tue Oct 28 15:06:44 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh/elf.h (PREFERRED_DEBUGGING_TYPE): Undefine before including
+ svr4.h.
+
+ Mon Oct 27 16:11:52 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh.c (machine_dependent_reorg): When -flag_delayed_branches,
+ put an use_sfunc_addr before each sfunc.
+ * sh.md (use_sfunc_addr, dummy_jump): New insns.
+ (casesi): For TARGET_SH2, emit a dummy_jump after LAB.
+
+ Tue Oct 21 07:12:28 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sh/elf.h (PREFERRED_DEBUGGING_TYPE): Don't redefine.
+
+Fri Nov 7 10:22:24 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * frame.c (add_fdes, count_fdes): Go back to checking pc_begin for
+ linked once FDEs.
+
+Wed Nov 5 14:26:05 1997 Jeffrey A Law (law@cygnus.com)
+
+ * alias.c (find_base_value): Only return the known base value for
+ pseudo registers.
+
+Wed Nov 5 11:27:14 1997 Jim Wilson <wilson@cygnus.com>
+
+ * i386.c (load_pic_register): Call prologue_get_pc_and_set_got.
+ * i386.md (prologue_set_got, prologue_get_pc): Add UNSPEC_VOLATILE
+ to pattern.
+ (prologue_get_pc_and_set_got): New pattern.
+
+Tue Nov 4 20:36:50 1997 Richard Henderson (rth@cygnus.com)
+
+ * alpha.c (summarize_insn): Handle ASM_OPERANDS. Don't recurse
+ for SUBREG, just fall through.
+
+ * alpha.c (alpha_handle_trap_shadows): Init sum.defd to zero.
+
+ * alpha.md (attr trap): Make TRAP_YES non-zero for sanity's sake.
+
+Tue Nov 4 18:49:42 1997 Jeffrey A Law (law@cygnus.com)
+
+ * fixincludes: Fix "hypot" prototype in NeXT math.h.
+
+ * Makefile.in (USE_ALLOCA): Always include alloca.o.
+ (USE_HOST_ALLOCA): Likewise.
+
+ * rtl.def (CODE_LABEL): Use separate fields for LABEL_NUSES
+ and LABEL_REFS fields.
+ * rtl.h (LABEL_REFS): Update.
+
+Tue Nov 4 16:55:11 1997 Jim Wilson <wilson@cygnus.com>
+
+ * combine.c (try_combine): When setting elim_i2, check whether newi2pat
+ sets i2dest. When calling distribute_notes for i3dest_killed, pass
+ elim_i2 and elim_i1. When setting elim_i1, check if newi2pat
+ sets i1dest.
+
+ * mips.md (insv, extzv, extv): Add change_address call.
+ (movsi_ulw, movsi_usw): Change QImode to BLKmode in pattern.
+
+ * integrate.c (save_for_inline_copying): Copy parm_reg_stack_loc.
+
+ * reload.c (find_reloads, case 'm' and 'o'): Reject HIGH constants.
+
+ * mips.c (mips_expand_epilogue): Emit blockage insn before call to
+ save_restore_insns if no FP and GP will be restored.
+
+ * dwarf2out.c (expand_builtin_dwarf_reg_size): New variable mode.
+ Convert CCmode to word_mode before calling GET_MODE_SIZE.
+
+ * acconfig.h (HAVE_INTTYPES_H): Undef.
+ * configure.in (inttypes.h): Check for conflicts between sys/types.h
+ and inttypes.h, and verify that intmax_t is defined.
+ * config/mips/x-iris (CC, OPT, OLDCC): Comment out.
+ * config/mips/x-iris3: Likewise.
+
+Tue Nov 4 16:07:15 1997 Jeffrey A Law (law@cygnus.com)
+
+ * alias.c (find_base_value): When copying arguments, return the
+ tenative value for a hard register.
+
+Tue Nov 4 13:40:35 1997 Doug Evans <devans@canuck.cygnus.com>
+
+ * c-lex.c (MULTIBYTE_CHARS): #undef if cross compiling.
+ (yylex): Record wide strings using target endianness, not host.
+
+Tue Nov 4 13:13:12 1997 Jeffrey A Law (law@cygnus.com)
+
+ * mn10200.h (ASM_OUTPUT_BSS): Delete.
+ (ASM_OUTPUT_ALIGNED_BSS): New macro
+ * mn10300.h (ASM_OUTPUT_BSS): Delete.
+ (ASM_OUTPUT_ALIGNED_BSS): New macro.
+ * v850.h (ASM_OUTPUT_BSS): Delete.
+ (ASM_OUTPUT_ALIGNED_BSS): New macro.
+
+Tue Nov 4 00:55:48 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * profile.c (branch_prob): Insert an insn after a NOTE_INSN_SETJMP.
+
+Mon Nov 3 14:36:50 1997 Jeffrey A Law (law@cygnus.com)
+
+ * configure.in (sco5): Use cpio to install header files.
+
+Sun Nov 2 23:31:43 1997 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * aclocal.m4 (conftestdata_from, conftestdata_to): Names shortened to
+ 14 char length.
+ * configure: Rebuild.
+
+Sun Nov 2 19:44:00 1997 Robert Lipe (robertl@dgii.com)
+
+ * i386/sco5.h: enable -gstabs once again.
+
+Sun Nov 2 19:27:21 1997 Jeffrey A Law (law@cygnus.com)
+
+ * arm.c (output_move_double): Allocate 3 entries in otherops array.
+
+Sat Nov 1 21:43:00 1997 Mike Stump (mrs@wrs.com)
+
+ * except.c (expand_ex_region_start_for_decl): Emit EH_REGION_BEG
+ notes for sjlj exceptions too.
+ (expand_eh_region_end): Similarly for EH_REGION_END notes.
+ (exception_optimize): Optimize EH regions for sjlj exceptions too.
+ * final.c (final_scan_insn): Don't output labels for EH REGION
+ notes if doing sjlj exceptions.
+
+Sat Nov 1 19:15:28 1997 Jeffrey A Law (law@cygnus.com)
+
+ * alias.c (init_alias_analysis): Handle -fno-alias-check when
+ optimizing correctly.
+
+ * expr.c (expand_builtin_setjmp): Don't emit a SETJMP note
+ or set current_function_calls_setjmp anymore.
+
+ * flow.c (find_basic_blocks): If we delete the label for an
+ exception handler, remove it from the EH label list and remove
+ the EH_BEGIN/EH_END notes for that EH region.
+
+Sat Nov 1 16:44:49 1997 Jason Merrill (jason@cygnus.com)
+
+ * flow.c (find_basic_blocks): Generate correct flow control
+ information when exception handling notes are present.
+
+Sat Nov 1 13:42:19 1997 Jeffrey A Law (law@cygnus.com)
+
+ * dwarf2out.c (output_call_frame_info): Fix length argument
+ to ASM_OUTPUT_ASCII.
+ (output_die, output_pubnames, output_line_info): Likewise.
+
+Fri Oct 31 07:10:09 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+ * dwarf2out.c (output_call_frame_info): Use ASM_OUTPUT_ASCII to
+ output ASCII by default. Only use ASM_OUTPUT_DWARF_STRING if
+ flag_debug_asm is on.
+ (output_die, output_pubnames, output_line_info): Likewise.
+
+ * alias.c (init_alias_analysis): Add struct_value_incoming_rtx
+ and static_chain_rtx into the potential base values array if
+ they are registers.
+
+ * alias.c (new_reg_base_value): New array of potential base values.
+ (unique_id): Now file scoped static.
+ (find_base_value, case REG): Return the value in reg_base_value
+ array for the REG if it exists. Else, return the value from
+ new_reg_base_value if copying args and REG is a hard register.
+ (find_base_value, case PLUS): If either operand of the PLUS is
+ a REG, try to get its base value. Handle base + index and
+ index + base.
+ (record_set): Use new_reg_base_value instead of reg_base_value.
+ (init_alias_analysis): Allocate space for new_reg_base_value too.
+ Rework code to iterate over the insns propagating base value
+ information until nothing changes.
+
+ * global.c (global_alloc): Free the conflict matrix after
+ reload has finished.
+
+Fri Oct 31 01:45:31 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * libgcc2.c (L_eh): Define __eh_pc.
+ Replace __eh_type with generic pointer __eh_info.
+
+Fri Oct 31 00:34:55 1996 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * expr.c (expand_increment): When enqueing a postincrement for a MEM,
+ use copy_to_reg if address is not a general_operand.
+
+Fri Oct 31 00:16:55 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * profile.c (output_func_start_profiler): Clear flag_inline_functions
+ for the duration of the call to rest_of_compilation.
+
+Thu Oct 30 14:40:10 1997 Doug Evans <devans@canuck.cygnus.com>
+
+ * configure.in (sparc-*-elf*): Use sparc/elf.h, sparc/t-elf.
+ Set extra_parts.
+ (sparc*-*-*): Recognize --with-cpu=v9.
+ * sparc/elf.h: New file.
+ * sparc/t-elf: New file.
+
+Thu Oct 30 13:26:12 1997 Jeffrey A Law (law@cygnus.com)
+
+ * mn10300.c (const_8bit_operand): New function.
+ (mask_ok_for_mem_btst): New funtion.
+ * mn10300.md (btst patterns with mem operands): Use new functions
+ to avoid creating btst instructions with invalid operands.
+
+Wed Oct 29 16:57:19 1997 Michael Meissner <meissner@cygnus.com>
+
+ * rs6000/xm-sysv4.h: Include xm-linux.h instead of xm-svr4.h if we
+ are running on PowerPC Linux.
+
+Wed Oct 29 13:10:11 1997 Gavin Koch <gavin@cygnus.com>
+
+ * config/mips/elf64.h (PREFERRED_DEBUGGING_TYPE): Only define
+ if not previously defined.
+
+Tue Oct 28 23:55:27 1997 Doug Evans (devans@cygnus.com)
+
+ * function.c (assign_parms): Correct mode of stack_parm if
+ entry_parm underwent a mode conversion.
+
+1997-10-28 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * global.c (global_alloc): Use xmalloc instead of alloca for
+ CONFLICTS, since max_allocno * allocno_row_words alone can be more
+ than 2.5Mb sometimes.
+
+Tue Oct 28 15:29:15 1997 Richard Henderson <rth@cygnus.com>
+
+ * reload1.c (eliminate_regs [SET]): If [SUBREG] widened the mode of
+ DEST for the spill, adjust mode of SRC to compensate.
+
+Tue Oct 28 14:36:45 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.md (reload_inqi): Check for MEM before strict_memory_address_p,
+ since any_memory_operand() allows pseudos during reload.
+ (reload_inhi, reload_outqi, reload_outhi): Likewise.
+
+Tue Oct 28 11:53:14 1997 Jim Wilson <wilson@cygnus.com>
+
+ * m68k.md (btst patterns): Add 5200 support.
+
+Tue Oct 28 11:58:40 1997 Toon Moene <toon@moene.indiv.nluug.nl>
+
+ * fold-const.c (fold): For ((a * C1) / C3) or (((a * C1) + C2) / C3)
+ optimizations, look inside dividend to determine if the expression
+ can be simplified by using EXACT_DIV_EXPR.
+
+Tue Oct 28 10:19:01 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ From Brendan:
+ * dwarf2out.c (output_call_frame_info): Use l1 instead of ".".
+
+Tue Oct 28 00:32:14 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (summarize_insn [SUBREG]): Propogate SET.
+
+Mon Oct 27 23:59:26 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_handle_trap_shadows): Don't call get_attr_trap
+ on a CLOBBER.
+
+Mon Oct 27 21:25:20 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.md (movqi, movhi): Make sure new insns created during reload
+ won't need reloading themselves.
+ (reload_inqi, reload_inhi, reload_outqi, reload_outhi): Likewise.
+
+Mon Oct 27 16:11:10 1997 Jeffrey A Law (law@cygnus.com)
+
+ * mn10300.h (GO_IF_LEGITIMATE_ADDRESS): Disable reg+reg.
+
+Sun Oct 26 13:50:44 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_sa_mask [VMS]): Don't include $26 in the mask.
+ Patch from Klaus Kaempf <kkaempf@progis.de>.
+
+Sun Oct 26 13:31:47 1997 Jim Wilson (wilson@cygnus.com)
+
+ * expr.c (expand_expr, case INDIRECT_REF): Optimize a reference
+ to an element in a constant string.
+
+Sun Oct 26 11:41:49 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * dwarf2out.c (output_call_frame_info): The CIE pointer is now a 32
+ bit PC-relative offset. The exception range table pointer is now in
+ the CIE.
+ * frame.c (dwarf_cie, dwarf_fde): Rename CIE_pointer to CIE_delta.
+ (count_fdes, add_fdes, get_cie): Adjust.
+ (cie_info, extract_cie_info, __frame_state_for): Adjust eh_ptr uses.
+
+ From H.J. Lu:
+ * frame.c (count_fdes, add_fdes): Skip linked once FDE entries.
+
+Sun Oct 26 11:52:01 1997 Richard Henderson <rth@cygnus.com>
+
+ * alias.c (memrefs_conflict_p): Treat arg_pointer_rtx just
+ like stack_pointer_rtx.
+
+Sun Oct 26 11:32:16 1997 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * Makefile.in (bootstrap-lean): Combined with `normal' bootstrap
+ targets using "$@" to provide support for similar but not identical
+ targets without having to duplicate code.
+ (bootstrap4): New goal.
+
+ * Makefile.in (compare, compare-lean, compare3): Combined to one
+ ruleset determining actions to be performed via $@.
+ (compare4, compare4-lean): New targets.
+ (gnucompare, gnucompare3): Combined to one ruleset determining
+ actions to be performed via $@. Also, note which files failed
+ the comparison test in .bad_compare.
+ (gnucompare-lean, gnucompare3-lean, gnucompare4-lean): New targets.
+
+Sun Oct 26 10:06:11 1997 Toon Moene <toon@moene.indiv.nluug.nl>
+
+ * fold-const (fold): Also simplify FLOOR_DIV_EXPR to EXACT_DIV_EXPR
+ if the dividend is a multiple of the divisor.
+
+Sun Oct 26 09:21:40 1997 Jeffrey A Law (law@cygnus.com)
+
+ * Makefile.in (LIBGCC2_CFLAGS): Add -fexceptions.
+
+ * alias.c (find_base_term): Handle PRE_INC, PRE_DEC, POST_INC,
+ and POS_DEC.
+
+ * alias.c (true_dependence): Fix typo.
+
+ * toplev.c (flag_rerun_loop_opt): New variable.
+ (f_options): Handle -frerun-loop-opt.
+ (rest_of_compilation): If -frerun-loop-opt, then run the loop
+ optimizer twice.
+ (main): Enable -frerun-loop-opt by default for -O2 or greater.
+
+ * loop.c (simplify_giv_expr): Adding two invariants results
+ in an invariant.
+
+Sun Oct 26 09:15:15 1997 Richard Henderson <rth@cygnus.com>
+
+ * expr.c (get_inner_reference): Remove the array bias after
+ converting the index to Pmode.
+
+Sat Oct 25 12:20:58 1997 Jeffrey A Law (law@cygnus.com)
+
+ * mn10300.h (TARGET_SWITCHES): Add -mmult-bug and -mno-mult-bug.
+ (TARGET_MULT_BUG): Define.
+ (TARGET_DEFAULT): Default to TARGET_MULT_BUG.
+ * mn10300.md (mulsi3): Handle TARGET_MULT_BUG.
+
+Fri Oct 24 17:40:34 1997 Jeffrey A Law (law@cygnus.com)
+
+ * mn10200.c (indirect_memory_operand): Delete unused function.
+ * mn10200.h (EXTRA_CONSTRAINT): Handle 'R'.
+ * mn10200.md (bset, bclr insns): Handle output in a reg too.
+
+Fri Oct 24 15:54:57 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.md (call patterns): Revert Oct 16 change; if we are to elide
+ the callee's ldgp, we must do it ourselves, and we use the jsr tag
+ for more than scheduling.
+
+Fri Oct 24 13:23:04 1997 Doug Evans <devans@canuck.cygnus.com>
+
+ * sparc/sparc.h (ASM_SPEC): Delete asm_arch.
+
+Fri Oct 24 13:19:40 1997 Jeffrey A Law (law@cygnus.com)
+
+ * mn10300.c (symbolic_operand, legitimize_address): New functions.
+ * mn10300.h (LEGITIMIZE_ADDRESS): Call legitimize_address.
+ (GO_IF_LEGITIMATE_ADDRESS): Don't allow base + symbolic.
+
+Thu Oct 23 09:35:12 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Thu Oct 23 08:03:59 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * dbxout.c (dbxout_start_new_source_file): Use output_quoted_string
+ for FILENAME.
+
+Wed Oct 22 00:34:12 1997 Jeffrey A Law (law@cygnus.com)
+
+ * toplev.c (flag_exceptions): Default value is 2.
+ (compile_file): If flag_exceptions still has the value 2, then
+ set it to 0.
+
+ * rs6000.c (struct machine_function): Add pic_offset_table_rtx.
+ (rs6000_save_machine_status): Save pic_offset_table_rtx.
+ (rs6000_restore_machine_status: Restore pic_offset_table_rtx.
+
+ * local-alloc.c (block_alloc): Don't lose if two SCRATCH expressions
+ are shared.
+
+ * rs6000.md (*movsi_got_internal_mem): New pattern.
+ (*movsi_got_internal_mem splitter): New define_split.
+
+Tue Oct 21 18:14:03 1997 Jim Wilson <wilson@cygnus.com>
+
+ * obstack.h (obstack_empty_p): Fix spurious space after backslash.
+
+Tue Oct 21 18:34:01 1997 Geoffrey KEATING <geoffk@ozemail.com.au>
+
+ * rs6000.c: Avoid creating a stack frame under SYSV ABI if we
+ only need to save LR.
+
+Tue Oct 21 10:06:40 1997 Jeffrey A Law (law@cygnus.com)
+
+ * mn10300.md (movqi, movhi): Avoid using address registers as
+ destinations unless absolutely necessary.
+
+ * mn10200.c (expand_prologue): Fix typo.
+
+ * mn10200.h (GO_IF_LEGITIMATE_ADDRESS): Do not allow indexed
+ addresses.
+ * mn10200.md (neghi2): Provide an alternative which works if
+ the input and output register are the same.
+
+ * mn10300.c (print_operand): Handle 'S'.
+ * mn10300.md (ashlsi3, lshrsi3, ashrsi3): Use %S for
+ shift amount in last alternative
+
+ * mn10300.c (expand_epilogue): Rework to handle register restores
+ in "ret" and "retf" instructions correctly.
+
+Mon Oct 20 16:47:08 1997 Jim Wilson <wilson@cygnus.com>
+
+ * expmed.c (extract_bit_field): Don't make flag_force_mem disable
+ extzv for memory operands.
+
+ * cse.c (simplify_ternary_operation, case IF_THEN_ELSE): Collapse
+ redundant conditional moves to single operand.
+
+Mon Oct 20 15:30:26 1997 Nick Clifton <nickc@cygnus.com>
+
+ * v850.h: Move define of __v850__ from CPP_PREDEFINES
+ to CPP_SPEC.
+
+ * xm-v850.h: Use __v850 rather than __v850__ to
+ identify v850 port.
+
+Mon Oct 20 14:15:02 1997 Jim Wilson <wilson@cygnus.com>
+
+ * mips/mips.c (compute_frame_size): Not a leaf function if
+ profile_flag set.
+
+Mon Oct 20 14:16:38 1997 Geoffrey KEATING <geoffk@ozemail.com.au>
+
+ * rs6000/t-ppccomm: Use -msdata=none for crtstuff.
+
+Mon Oct 20 12:28:17 1997 Doug Evans <devans@canuck.cygnus.com>
+
+ * sparc/sparc.h (SPARC_V9,SPARC_ARCH64): Delete.
+ (DEFAULT_ARCH32_P): New macro.
+ (TARGET_ARCH{32,64}): Allow compile time or runtime selection.
+ (enum cmodel): Declare.
+ (sparc_cmodel_string,sparc_cmodel): Declare.
+ (SPARC_DEFAULT_CMODEL): Provide default.
+ (TARGET_{MEDLOW,MEDANY}): Renamed to TARGET_CM_{MEDLOW,MEDANY}.
+ (TARGET_FULLANY): Deleted.
+ (TARGET_CM_MEDMID): New macro.
+ (CPP_CPU_DEFAULT_SPEC): Renamed from CPP_DEFAULT_SPEC.
+ (ASM_CPU_DEFAULT_SPEC): Renamed from ASM_DEFAULT_SPEC.
+ (CPP_PREDEFINES): Take out stuff now handled by %(cpp_arch).
+ (CPP_SPEC): Rewrite.
+ (CPP_ARCH{,32,64,_DEFAULT}_SPEC): New macros.
+ (CPP_{ENDIAN,SUBTARGET}_SPEC): New macros.
+ (ASM_ARCH{,32,64,_DEFAULT}_SPEC): New macros.
+ (ASM_SPEC): Add %(asm_arch).
+ (EXTRA_SPECS): Rename cpp_default to cpp_cpu_default.
+ Rename asm_default to asm_cpu_default.
+ Add cpp_arch32, cpp_arch64, cpp_arch_default, cpp_arch, cpp_endian,
+ cpp_subtarget, asm_arch32, asm_arch64, asm_arch_default, asm_arch.
+ (NO_BUILTIN_{PTRDIFF,SIZE}_TYPE): Define ifdef SPARC_BI_ARCH.
+ ({PTRDIFF,SIZE}_TYPE): Provide 32 and 64 bit values.
+ (MASK_INT64,MASK_LONG64): Delete.
+ (MASK_ARCH64): Renamed to MASK_64BIT.
+ (MASK_{MEDLOW,MEDANY,FULLANY,CODE_MODEL}): Delete.
+ (EMBMEDANY_BASE_REG): Renamed from MEDANY_BASE_REG.
+ (TARGET_SWITCHES): Always provide 64 bit options.
+ (ARCH64_SWITCHES): Delete.
+ (TARGET_OPTIONS): New option -mcmodel=.
+ (INT_TYPE_SIZE): Always 32.
+ (MAX_LONG_TYPE_SIZE): Define ifdef SPARC_BI_ARCH.
+ (INIT_EXPANDERS): sparc64_init_expanders renamed to sparc_init_....
+ (FUNCTION_{,BLOCK_}PROFILER): Delete TARGET_EMBMEDANY support.
+ (PRINT_OPERAND_PUNCT_VALID_P): Add '_'.
+ * sparc/linux-aout.h (CPP_PREDEFINES): Take out stuff handled by
+ CPP_SPEC.
+ (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC.
+ * sparc/linux.h: Likewise.
+ * sparc/linux64.h (SPARC_V9,SPARC_ARCH64): Delete.
+ (ASM_CPU_DEFAULT_SPEC): Renamed from ASM_DEFAULT_SPEC.
+ (TARGET_DEFAULT): Delete MASK_LONG64, MASK_MEDANY, add MASK_64BIT.
+ (SPARC_DEFAULT_CMODEL): Define.
+ (CPP_PREDEFINES): Take out stuff handled by CPP_SPEC.
+ (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC.
+ (LONG_DOUBLE_TYPE_SIZE): Define.
+ (ASM_SPEC): Add %(asm_arch).
+ * sparc/sol2.h (CPP_PREDEFINES): Take out stuff handled by CPP_SPEC.
+ (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC.
+ (TARGET_CPU_DEFAULT): Add ultrasparc case.
+ * sparc/sp64-aout.h (SPARC_V9,SPARC_ARCH64): Delete.
+ (TARGET_DEFAULT): MASK_ARCH64 renamed to MASK_64BIT.
+ (SPARC_DEFAULT_CMODEL): Define.
+ * sparc/sp64-elf.h (SPARC_V9,SPARC_ARCH64): Delete.
+ (TARGET_DEFAULT): MASK_ARCH64 renamed to MASK_64BIT. Delete
+ MASK_LONG64, MASK_MEDANY.
+ (SPARC_DEFAULT_CMODEL): Define.
+ (CPP_PREDEFINES): Delete.
+ (CPP_SUBTARGET_SPEC): Renamed from CPP_SPEC.
+ (ASM_SPEC): Add %(asm_arch).
+ (LONG_DOUBLE_TYPE_SIZE): Define.
+ (DWARF2_DEBUGGING_INFO): Define.
+ * sparc/splet.h (CPP_SPEC): Delete.
+ * sparc/sysv4.h (CPP_PREDEFINES): Take out stuff handled by CPP_SPEC.
+ (FUNCTION_BLOCK_PROFILER): Delete TARGET_EMBMEDANY support.
+ (BLOCK_PROFILER): Likewise.
+ * sparc/sparc.c (sparc_cmodel_string,sparc_cmodel): New globals.
+ (sparc_override_options): Handle code model selection.
+ (sparc_init_expanders): Renamed from sparc64_init_expanders.
+ * sparc/sparc.md: TARGET_<code_model> renamed to TARGET_CM_....
+ TARGET_MEDANY renamed to TARGET_CM_EMBMEDANY.
+ (sethi_di_embmedany_{data,text}): Renamed from sethi_di_medany_....
+ (sethi_di_fullany): Delete.
+
+Mon Oct 20 02:00:18 1997 Klaus Kaempf <kkaempf@progis.de>
+ Jeff Law <law@cygnus.com>
+ Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * alpha/vms.h (DIVSI3_LIBCALL): OTS$ functions are upper case.
+ (DIVDI3_LIBCALL, UDIVSI3_LIBCALL, UDIVDI3_LIBVALL): Likewise.
+ (MODSI3_LIBCALL, MODDI3_LIBCALL): Likewise.
+ (UMODSI3_LIBCALL, UMODDI3_LIBCALL): Likewise.
+ * alpha/alpha.md (arg_home): Likewise.
+
+ * alpha/alpha.c (vmskrunch): Delete
+ * alpha/vms.h (ENCODE_SECTION_INFO, ASM_DECLARE_FUNCTION_NAME): Delete.
+ * alpha.c (output_prolog, VMS): Use alloca for entry_label and don't
+ truncate to 64 characters.
+
+ * make-l2.com: Support openVMS/Alpha.
+
+ * vmsconfig.com: Fix to work on openVMS/Alpha and openVMS/VAX.
+
+Sun Oct 19 19:00:35 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * longlong.h (count_leading_zeros): Add missing casts to USItype.
+
+Sun Oct 19 18:44:06 1997 Jeffrey A Law (law@cygnus.com)
+
+ * i386/bsd386.h (ASM_COMMENT_START): Define.
+
+Sat Oct 18 13:47:15 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * tree.c (restore_tree_status): Also free up temporary storage
+ when we finish a toplevel function.
+ (dump_tree_statistics): Print stats for backend obstacks.
+
+Sat Oct 18 12:47:31 1997 Doug Evans <dje@canuck.cygnus.com>
+
+ * expr.c (use_group_regs): Don't call use_reg for MEMs.
+
+Sat Oct 18 09:49:46 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * libgcc2.c (__throw): Don't copy the return address.
+ * dwarf2out.c (expand_builtin_dwarf_reg_size): Ignore return address.
+
+ * except.c (exceptions_via_longjmp): Initialize to 2 (uninitialized).
+ * toplev.c (main): Initialize exceptions_via_longjmp.
+
+ * tree.c: Add extra_inline_obstacks.
+ (save_tree_status): Use it.
+ (restore_tree_status): If this is a toplevel inline obstack and we
+ didn't want to save anything on it, recycle it.
+ (print_inline_obstack_statistics): New fn.
+ * function.c (pop_function_context_from): Pass context to
+ restore_tree_status.
+ * obstack.h (obstack_empty_p): New macro.
+
+Sat Oct 18 00:43:59 1997 Jeffrey A Law (law@cygnus.com)
+
+ * i386/freebsd.h (ASM_COMMENT_START): Fix.
+
+Fri Oct 17 23:48:52 1997 Jim Wilson (wilson@cygnus.com)
+
+ * v850.c (ep_memory_offset): New function.
+ (ep_memory_operand, substitute_ep_register, v850_reorg): Call it.
+
+ * v850.h (CONST_OK_FOR_*): Add and correct comments.
+ (CONSTANT_ADDRESS_P): Add comment.
+ (EXTRA_CONSTRAINT): Define 'U'.
+ * v850.md: Add comments on bit field instructions.
+ (addsi3): Delete &r/r/r alternative. Add r/r/U alternative.
+ (lshrsi3): Use N not J constraint.
+
+ * v850.md (v850_tst1+1): New define_split for tst1 instruction.
+
+ * v850.c (reg_or_0_operand): Call register_operand.
+ (reg_or_int5_operand): Likewise.
+ * v850.h (MASK_BIG_SWITCH, TARGET_BIG_SWITCH): New macros.
+ (TARGET_SWITCHES): Add "big-switch".
+ (ASM_OUTPUT_ADDR_VEC_ELT, ASM_OUTPUT_ADDR_DIFF_ELT, CASE_VECTOR_MODE,
+ ASM_OUTPUT_BEFORE_BASE_LABEL): Add support for TARGET_BIG_SWITCH.
+ (CASE_DROPS_THROUGH): Comment out.
+ (CASE_VECTOR_PC_RELATIVE, JUMP_TABLES_IN_TEXT_SECTION): Define.
+ * v850.md (cmpsi): Delete compare mode.
+ (casesi): New pattern.
+
+ * v850.h (CONST_OK_FOR_N): Delete redundant compare against zero.
+ * v850.md (ashlsi3): Use SImode not QImode for shift count.
(lshrsi3): Likewise.
- * c-decl.c (poplevel): Do output inline function if
- DECL_ABSTRACT_ORIGIN points to itself.
+ * v850.c (print_operand): Add 'c', 'C', and 'z' support. Delete
+ unreachable switch statement after 'b' support. Remove "b" from
+ strings for 'b' support.
+ * v850.md (branch_normal, branch_invert): Change %b to b%b.
+
+Fri Oct 17 23:33:20 1997 Jeffrey A Law (law@cygnus.com)
+
+ * Makefile.in (LIBGCC2_CFLAGS): Avoid a backslash then an
+ empty line if @inhibit_libc@ is empty.
+
+Fri Oct 17 23:24:40 1997 Robert Lipe (robertl@dgii.com)
+
+ * i386/sco5.h: Let ELF use dwarf2 unwinding. COFF uses sjlj.
+ (EH_FRAME_SECTION_ASM_OP, EH_FRAME_SECTION_ASM_OP_ELF): Defined.
+ (EH_FRAME_SECTION_ASM_OP_COFF): Likewise.
+ (DWARF2_UNWIND_INFO): Let this track object file format.
+ (EXTRA_SECTIONS): Add in_eh.
+ (EH_FRAME_SECTION_ASM_OP, EH_FRAME_SECTION_ASM_OP_ELF): Define.
+ (EH_FRAME_SECTION_ASM_OP_COFF): Likewise.
+
+Fri Oct 17 17:13:42 1997 David S. Miller <davem@tanya.rutgers.edu>
+
+ * sparc/linux64.h (LINK_SPEC): Dynamic linker is ld-linux64.so.2.
+ * sparc/sparc.h (FUNCTION_PROFILER): Fix format string when
+ TARGET_MEDANY.
+ * sparc/sparc.c (dwarf2out_cfi_label): Extern no longer needed.
+ (output_double_int): Output DI mode values correctly when
+ HOST_BITS_PER_WIDE_INT is 64.
+ (output_fp_move_quad): If TARGET_V9 and not TARGET_HARD_QUAD, use
+ fmovd so it works if a quad float ends up in one of the upper 32
+ float regs.
+ * sparc/sparc.md (pic_{lo_sum,sethi}_di): New patterns
+ necessary for PIC support on sparc64.
+
+Fri Oct 17 13:39:56 1997 Doug Evans <dje@canuck.cygnus.com>
+
+ * sparc/sp64-elf.h (TARGET_DEFAULT): Delete MASK_STACK_BIAS.
+ * sparc/sparc.h (PROMOTE_MODE): Promote small ints if arch64.
+ (PROMOTE_FUNCTION_ARGS,PROMOTE_FUNCTION_RETURN): Define.
+ (SPARC_FIRST_FP_REG, SPARC_FP_REG_P): New macros.
+ (SPARC_{OUTGOING,INCOMING}_INT_ARG_FIRST): New macros.
+ (SPARC_FP_ARG_FIRST): New macro.
+ (CONDITIONAL_REGISTER_USAGE): All v9 fp regs are volatile now.
+ (REG_ALLOC_ORDER,REG_LEAF_ALLOC_ORDER): Reorganize fp regs.
+ (NPARM_REGS): There are 32 fp argument registers now.
+ (FUNCTION_ARG_REGNO_P): Likewise.
+ (FIRST_PARM_OFFSET): Update to new v9 abi.
+ (REG_PARM_STACK_SPACE): Define for arch64.
+ (enum sparc_arg_class): Delete.
+ (sparc_arg_count,sparc_n_named_args): Delete.
+ (struct sparc_args): Redefine and use for arch32 as well as arch64.
+ (GET_SPARC_ARG_CLASS,ROUND_REG,ROUND_ADVANCE): Delete.
+ (FUNCTION_ARG_ADVANCE): Rewrite.
+ (FUNCTION_ARG,FUNCTION_INCOMING_ARG): Rewrite.
+ (FUNCTION_ARG_{PARTIAL_NREGS,PASS_BY_REFERENCE}): Rewrite.
+ (FUNCTION_ARG_CALLEE_COPIES): Delete.
+ (FUNCTION_ARG_{PADDING,BOUNDARY}): Define.
+ (STRICT_ARGUMENT_NAMING): Define.
+ (doublemove_string): Declare.
+ * sparc/sparc.c (sparc_arg_count,sparc_n_named_args): Delete.
+ (single_move_string): Use GEN_INT, and HOST_WIDE_INT.
+ (doublemove_string): New function.
+ (output_move_quad): Clean up some of the arch64 support.
+ (compute_frame_size): Add REG_PARM_STACK_SPACE if arch64.
+ Don't add 8 bytes of reserved space if arch64.
+ (sparc_builtin_saveregs): Combine arch32/arch64 versions.
+ (init_cumulative_args): New function.
+ (function_arg_slotno): New static function.
+ (function_arg,function_arg_partial_nregs): New functions.
+ (function_arg_{pass_by_reference,advance}): New functions.
+ (function_arg_padding): New function.
+ * ginclude/va-sparc.h: Rewrite v9 support.
+
+Fri Oct 17 12:29:48 1997 Christian Iseli <Christian.Iseli@lslsun.epfl.ch>
+
+ * regclass.c (record_address_regs): Look at REG_OK_FOR_{BASE,INDEX}_P
+ for hard regs to determine base and index registers.
+
+ * reload.c (debug_reload_to_stream): New function. Specify stream
+ into which to write debug info.
+ (debug_reload): Modify to call debug_reload_to_stream with stderr.
+
+Thu Oct 16 15:07:51 1997 Richard Henderson <rth@cygnus.com>
+
+ * combine.c (can_combine_p): Don't combine with an asm whose
+ output is a hard register.
+
+Thu Oct 16 15:43:26 1997 Mike Stump (mrs@wrs.com)
+
+ * c-decl.c (start_struct): Ensure that structs with forward
+ declarations are in fact packed when -fpack-struct is given.
+
+ * stor-layout.c (layout_record): Ignore STRUCTURE_SIZE_BOUNDARY if
+ we are packing a structure. This allows a structure with only
+ bytes to be aligned on a byte boundary and have no padding on a
+ m68k.
+
+Thu Oct 16 15:17:54 1997 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * rs6000.h (ROUND_TYPE_ALIGN): Don't blow up if no fields in record.
+
+Thu Oct 16 11:20:30 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.c (alpha_return_addr_rtx): New variable.
+ (alpha_save_machine_status): New; save it.
+ (alpha_restore_machine_status): New; restore it.
+ (alpha_init_expanders): New; clear it.
+ (alpha_return_addr): New; set it.
+ (alpha_ra_ever_killed): New; if alpha_return_addr_rtx, regs_ever_live
+ is overly conservative, so search the insns explicitly.
+ (alpha_sa_mask [VMS]): Check alpha_ra_ever_killed.
+ (alpha_sa_size [VMS && !VMS]): Likewise.
+ * alpha.h (RETURN_ADDR_RTX): Call alpha_return_addr.
+ (INIT_EXPANDERS): New definition.
- * varasm.c (output_constant): Cast assemble_string argument to char *.
+ * alpha.c: Move REG_PV, REG_RA somewhere more visible in the file.
+ (output_prolog [!VMS]): Use them.
-Mon Apr 10 14:29:28 1995 Torbjorn Granlund <tege@adder.cygnus.com>
+ * alpha.c (output_prolog [!VMS]): Move gp detection to ...
+ (alpha_does_function_need_gp): ... a new function. Refine the
+ CALL_INSN test to just TYPE_JSR.
+ * alpha.md (most call insns): Fix some jsr/ibr type transpositions.
- * recog.c (constrain_operands, case 'E'): Make this work like
- constraint character `F' when REAL_ARITHMETIC is defined.
- * regclass.c (record_reg_classes, case 'E'): Likewise.
- * reload.c (find_reloads, case 'E'): Likewise.
+Thu Oct 16 09:36:47 1997 Jeffrey A Law (law@cygnus.com)
-Mon Apr 10 14:30:31 1995 Michael Meissner <meissner@cygnus.com>
+ * version.c: Bump for snapshot.
- * rs6000/aix3newas.h, rs6000/aix41.h: Eliminate March 11th changes
- to undefine ASM_OUTPUT_EXTERNAL{,_LIBCALL}, since this causes the
- compiler not to bootstrap.
+Wed Oct 15 21:38:18 1997 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
-Mon Apr 10 07:17:39 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * pa.c (move_operand): Respect -mdisable-indexing.
+ * pa.h (GO_IF_LEGITIMATE_ADDRESS): Likewise.
- * cppalloc.c: #include config.h.
- * cppexp.c: Add declarations of xmalloc and xrealloc.
- (cpp_parse_expr): Cast args to bcopy to char *.
- * cpphash.c: Add declaration of xmalloc.
- * cpplib.c (init_parse_options, cpp_reader): Cast args to bcopy,
- bcmp, and bzero to char *.
- (add_import, push_parse_file, init_parse_file): Likewise.
+Wed Oct 15 21:34:45 1997 David Edelsohn <edelsohn@mhpcc.edu>
- * c-common.c (enum attrs): New attribute, A_NOCOMMON.
- (init_attribute): Initialize it.
- (decl_attributes): Implement it.
- * varasm.c (make_decl_rtl): Allow section attribute if -fno-common
- or variable is not to be placed in common for some other reason.
+ * rs6000.md (udivsi3, divsi3): Split into MQ and non-MQ cases for
+ PPC601.
+ (umulsidi3,umulsi3_highpart): Ditto.
+ (smulsi3_highpart_no_mq): Add !TARGET_POWER.
- * combine.c (simplify_set): Don't move a SUBREG to dest if it
- is changing the size of a hard reg in CLASS_CANNOT_CHANGE_SIZE.
+Wed Oct 15 18:21:46 1997 Richard Henderson <rth@cygnus.com>
- * reload.c (find_equiv_reg): If goal is a pseudo that got memory,
- a store into memory makes it invalid.
- * reload1.c (reload_as_needed): Call forget_old_reloads_1 on
- pattern before reg elimination.
+ * alpha.c (final_prescan_insn): Gut, remove and transform to ...
+ (alpha_handle_trap_shadows): ... a new function. Handle the entire
+ function in one go. Emit RTL for trapb, instead of printf directly.
+ (alpha_reorg): New function. Call alpha_handle_trap_shadows.
+ (trap_pending): Kill global variable.
+ (output_epilog): Don't call final_prescan_insn.
+ (struct shadow_summary): Elide $31 and $f31; now it fits in a word.
+ * alpha.h (FINAL_PRESCAN_INSN): Remove.
+ (MACHINE_DEPENENT_REORG): Define.
+ * alpha.md (jsr patterns with trapb): Stupid and useless. Kill.
+ (trapb): New insn.
-Mon Apr 10 00:26:14 1995 Jeffrey A. Law <law@snake.cs.utah.edu>
+Wed Oct 15 18:16:05 1997 Richard Henderson <rth@cygnus.com>
- * pa.c (pa_reorg): Bump label use count for each entry in an
- exploded ADDR_VEC.
+ Tune Haifa scheduler for Alpha:
+ * alpha.h (ISSUE_RATE): Define.
+ * alpha.c (alpha_adjust_cost): Handle EV5 mult delay; don't apply
+ EV4 adjustments to EV5.
+ * alpha.md: Remove all scaling from function unit delays. Rework
+ EV5 function units to match the CPU.
+ (umuldi3_highpart): EV5 added the IMULH insn class.
-Sun Apr 9 09:22:51 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Wed Oct 15 17:42:41 1997 Jeffrey A Law (law@cygnus.com)
- * i386.md (adddi3, subdi3): Need scratch reg whenever operand 0 in
- mem and operands 1 not '0'.
- (subdi3): Don't treat two non-equal MEMs as non-aliasing.
+ * pa.c (following_call): Fail if the CALL_INSN is an indirect
+ call.
-Sat Apr 8 22:53:38 1995 Jeffrey A. Law <law@snake.cs.utah.edu>
+Tue Oct 14 12:01:00 1997 Mark Mitchell <mmitchell@usa.net>
- * pa.c (pa_reorg): Fix typo.
+ * cplus-dem.c (demangle_signature): Don't look for return types on
+ constructors. Handle member template constructors.
-Sat Apr 8 19:36:36 1995 Michael Meissner <meissner@cygnus.com>
+Tue Oct 14 11:30:29 1997 Jason Merrill <jason@yorick.cygnus.com>
- * rs6000/rs6000.h (SELECT_SECTION): TREE_CODE_CLASS must be called
- with a tree code, not a tree value.
+ * tree.c (expr_tree_cons, build_expr_list, expralloc): New fns.
+ * tree.h: Declare them.
-Sat Apr 8 12:41:01 1995 Mike Stump <mrs@cygnus.com>
+Fri Oct 10 13:46:56 1997 Doug Evans <dje@canuck.cygnus.com>
- * cpphash.c: Don't use const on compilers that don't support it.
+ * configure.in: Handle --with-newlib.
+ * Makefile.in (LIBGCC2_CFLAGS): Add @inhibit_libc@.
-Sat Apr 8 16:32:22 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * sparc/t-sp64 (LIBGCC2_CFLAGS): Delete.
- * expr.c (expand_increment): Handle case where INCREMENTED
- has a non-trivial conversion.
+Wed Oct 8 14:37:44 1997 Jeffrey A Law (law@cygnus.com)
-Fri Apr 7 19:33:21 1995 Phil Nelson (phil@cs.wwu.edu)
+ * config/ptx4.h: Fix typo.
- * ns32k.h (TRAMPOLINE_TEMPLATE, TRANSFER_FROM_TRAMPOLINE):
- Fix assembler syntax errors.
+Wed Oct 8 08:57:20 1997 Jeffrey A Law (law@cygnus.com)
-Fri Apr 7 19:27:23 1995 Pat Rankin (rankin@eql.caltech.edu)
+ * version.c: Bump for snapshot.
- * cccp.c (VMS_fstat, VMS_stat): New functions.
+Tue Oct 7 16:27:34 1997 Manfred Hollstein <manfred@s-direktnet.de>
-Fri Apr 7 19:25:21 1995 Paul Eggert <eggert@twinsun.com>
+ * aclocal.m4: Substitute INSTALL.
+ * configure: Re-built.
- * cccp.c (collect_expansion): If traditional, set stringify
- member to SHARP_TOKEN regardless of the value of
- stringify_sharp_token_type.
+Tue Oct 7 15:37:35 1997 Jeffrey A Law (law@cygnus.com)
-Fri Apr 7 07:48:35 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * integrate.c (save_for_inline_copying): Avoid undefined pointer
+ operations.
+ (expand_inline_function): Likewise.
- * cse.c (simplify_unary_operation): #ifdef POINTERS_EXTEND_UNSIGNED,
- handle sign- or zero-extending addresses.
+ * dwarf2out.c (output_call_frame_info): Reinstate last change
+ using flag_debug_asm check instead of flag_verbose_asm.
- * optabs.c (init{,_integral,_floating,_complex}_libfuncs):
- Change SUFFIX to "char" to avoid confusion with prototype.
+Tue Oct 7 12:57:26 1997 Jim Wilson <wilson@cygnus.com>
- * explow.c (convert_memory_address): No longer static.
- New arg, TO_MODE.
- Do something special for SYMBOL_REF, LABEL_REF, and CONST.
- (memory_address): Add extra arg to call to convert_memory_address.
- * rtl.h (convert_memory_address): Add extra arg.
- * expr.c (expand_expr, case ADDR_EXPR): Always call
- convert_memory_address when converting; add extra arg.
- * stmt.c (expand_computed_goto): Convert from ptr_mode to Pmode.
+ * dwarf2out.c (output_call_frame_info): Remove last change.
- * gcc.c (OBJECT_SUFFIX): Default now ".o", not "o".
- (all specs): Remove "." before %O; use %O in a few missing cases.
- * i386/os2.h (OBJECT_SUFFIX): Delete from here.
- * i386/xm-os2.h (OBJECT_SUFFIX): Move to here; now has period.
+1997-10-04 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- * Makefile.in (STAGESTUFF): Use $(exeext) for executables.
+ * frame.c (__frame_state_for): Execute the FDE insns until the
+ current pc value is strictly bigger than the target pc value.
-Fri Apr 7 03:32:29 1995 Richard Stallman <rms@mole.gnu.ai.mit.edu>
+Tue Oct 7 11:00:42 1997 Jason Merrill <jason@yorick.cygnus.com>
- * config.sub: Accept -lites* as op sys.
+ * regclass.c (init_reg_modes): If we can't find a mode for the
+ register, use the previous one.
-Thu Apr 6 23:08:50 1995 Per Bothner <bothner@kalessin.cygnus.com>
+Tue Oct 7 10:55:34 1997 Richard Henderson <rth@cygnus.com>
- * cpplib.c (bcopy, bzero, bcmp): Remove #undefs.
- * cppalloc.c (xcalloc): Re-implement using calloc,
- rather than malloc+bzero.
- * cpplib.c (SELF_DIR_DUMMY): New macro.
- (do_include): Don't pass searchptr to finclude if it is dsp,
- since that is on the stack, and would cause a dangling pointer.
- If handling #include_next, recognize SELF_DIR_DUMMY.
+ * haifa-sched.c (print_block_visualization): Call fprintf directly,
+ don't sprintf through an alloca'ed buffer.
-Fri Apr 7 00:54:24 1995 Jeffrey A. Law <law@snake.cs.utah.edu>
+Tue Oct 7 10:52:29 1997 Thomas Koenig (ig25@rz.uni-karlsruhe.de)
- * pa.h (MACHINE_DEPENDENT_REORG): Define.
- * pa.md (switch_jump): New pattern for jumps which implement
- a switch table.
- * pa.c (pa_reorg): New function to explode jump tables.
- (pa_adjust_insn_length): Account for jumps in switch tables with
- unfilled delay slots.
+ * reload.c (decompose): Always initialize val.base.
-Thu Apr 6 14:31:10 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Tue Oct 7 10:19:26 1997 Manfred Hollstein (manfred@lts.sel.alcatel.de)
- * c-typeck.c (build_binary_op): Don't call common_type for
- uncommon pointer types.
+ * m68k/mot3300.h (ASM_OUTPUT_ALIGN): Accept any alignment
+ instead of aborting.
+ * dwarf2out.c (output_call_frame_info): Call app_enable and
+ app_disable to let GNU as accept the generated comments.
-Wed Apr 5 13:53:17 1995 Per Bothner <bothner@kalessin.cygnus.com>
+Tue Oct 7 11:41:21 1997 Michael Meissner <meissner@cygnus.com>
- Re-write fixproto/fix-header/etc to use cpplib:
- * fix-header.c: Comment out support for adding missing extern "C"
- using #ifdef ADD_MISSING_EXTERN_C instead of #if 0.
- * fixproto: Removed case of required functions. Instead use ...
- * fix-header.c (std_include_table): ... new required-functions table.
- (cpp_file_line_for_message, cpp_print_containing_files, cpp_message):
- New stub functions, to intercept cpplib error message.
- * fixproto: Don't call $CPP, since fix-header now incorporates cpplib.
- * gen-protos.c (fatal, hashf): New functions.
- (main): Use hashf, instead of hash.
- * scan-decls.c (scan_decls, skip_to_closing_brace): Re-write to
- take a cpp_reader* as argument, not a FILE*.
- * scan.h (hash): Make parameter const.
- * scan.c (hash): Removed.
- * scan.c (memory_full, xmalloc, xrealloc): Removed.
- Use functions from cppalloc.c instead.
- * Makefile.in (gen-prtos, fix-header, stmp-fixproto): Update.
+ * tree.h (get_file_function_name): Add declaration.
+ * dwarf2out.c (output_call_frame_info): No need to cast
+ get_file_function_name call anymore.
+ * profile.c (toplevel): Remove get_file_function_name
+ declaration.
+ * c-lang.c (finish_file): Ditto.
-Wed Apr 5 13:24:14 1995 Per Bothner <bothner@kalessin.cygnus.com>
+Tue Oct 7 10:01:45 1997 Chip Salzenberg <chip@rio.atlantic.net>
- * cpplib.c (cpp_get_token): If traditional, return after comment,
- instead of reading more, so end-of-line can be peeked at.
- * cpperror.c (cpp_file_line_for_message, cpp_message): New
- functions, that do the actual printing of error messages.
- (cpp_print_file_and_line, cpp_error, cpp_warning, cpp_pedwarn,
- cpp_error_with_line, cpp_warning_with_line, cpp_pedwarn_with_line,
- cpp_pedwarn_with_file_and_line, cpp_error_from_errno, my_strerror,
- cpp_perror_with_name): Re-write to use cpp_file_line_for_message
- and cpp_message, and move to cpplib.c.
+ * Makefile.in (program_transform_name): Let autoconf substitute
+ the correct value.
-Tue Apr 4 23:35:49 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+Tue Oct 7 09:54:35 1997 Jeffrey A Law (law@cygnus.com)
- * config/gnu.h (GNU_CPP_PREDEFINES): Remove -D__HURD__.
+ * haifa-sched.c (schedule_block): If the first real insn in a
+ block has any special notes attached to it, remove them.
-Tue Apr 4 17:15:54 1995 Jeffrey A. Law <law@mole.gnu.ai.mit.edu>
+Tue Oct 7 09:48:51 1997 Richard Henderson <rth@cygnus.com>
- * pa.h (DO_GLOBAL_DTORS_BODY): Fix pointer -> integer assignment
- problem.
+ * alpha.h (FLOAT_STORE_FLAG_VALUE): It's 2.0 not 0.5.
- * reorg.c (fill_simple_delay_slots): Don't use a JUMP_INSN
- a the target of another JUMP_INSN to fill a delay slot.
-
-Mon Apr 3 19:03:48 1995 Torbjorn Granlund <tege@adder.cygnus.com>
-
- * cse.c (simplify_unary_operation): Sign-extend constants when
- they have the most significant bit set for the target.
-
- * m68k.md (umulsi3_highpart): Test for CONST_INT and CONST_DOUBLE,
- not CONSTANT_P.
- (smulsi3_highpart): Likewise.
- * m68k.c (const_uint32_operand): New function.
- (const_sint32_operand): New function.
- * m68k.md (const_umulsi3_highpart): Use const_uint32_operand instead
- of immediate_operand for op3. Delete mode.
- (const_smulsi3_highpart): Analogous change.
-
-Mon Apr 3 19:03:48 1995 Jim Wilson <wilson@cygnus.com>
-
- * cse.c (simplify_binary_operation): Sign-extend constants when
- they have the most significant bit set for the target.
-
- * combine.c (force_to_mode, case PLUS): Sign extend masks that are
- negative in OP_MODE.
- (simplify_and_const_int): Sign-extend constants when they have the
- most significant bit set for the target.
- (merge_outer_ops): Likewise.
- (simplify_shift_const): Likewise.
+Mon Oct 6 12:47:32 1997 Manfred Hollstein (manfred@lts.sel.alcatel.de)
-Mon Apr 3 18:23:48 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * toplev.c (lang_options): Add -f{no-,}repo.
-
-Mon Apr 3 18:13:15 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * combine.c (nonzero_bits, case REG): Check POINTERS_EXTEND_UNSIGNED.
- (num_sign_bit_copies, case REG): Likewise.
- * explow.c (convert_memory_address): New function.
- (memory_address): Call if it needed.
- (promote_mode, case POINTER_TYPE): Use Pmode and pointer extension.
- (allocate_dynamic_stack_space): Convert size from ptr_mode.
- * expr.c (clear_storage, expand_assignment, store_{expr,constructor}):
- Use ptr_mode instead of Pmode in some places.
- (expand_expr, expand_builtin): Likewise.
- (push_block, store_expr): Convert size to Pmode.
- (expand_expr, case ADDR_EXPR): Convert from Pmode to ptr_mode.
-
-Mon Apr 3 18:00:52 1995 Jim Wilson <wilson@cygnus.com>
-
- * explow.c (allocate_dynamic_stack_space): Correct typo in last
- change.
+ * m88k.c (m88k_begin_prologue): Remove superfluous backslash.
- * sh.c (gen_shifty_op, case ASHIFTRT): Return 0 if shift count is not
- a constant.
+Mon Oct 6 12:04:24 1997 Jeffrey A Law (law@cygnus.com)
-Mon Apr 3 12:17:10 1995 Michael Meissner (meissner@cygnus.com)
+ * Makefile.in (check-g77): New test target.
+ (CHECK-TARGETS): Add check-g77.
- * expmed.c (extract_bit_field): When converting a SUBREG into a
- REG, if the system is big endian, adjust the bit offset
- appropriately.
+Fri Oct 3 11:56:36 1997 Jason Merrill <jason@yorick.cygnus.com>
-Mon Apr 3 00:08:45 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+ * toplev.c (rest_of_compilation): Defer all non-nested inlines.
- * config/i386/linux.h: Include "config/linux.h" instead of
- "linux.h", to avoid recursion.
+Fri Oct 3 15:49:27 1997 Michael Meissner <meissner@cygnus.com>
-Sun Apr 2 23:50:27 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
+ * flow.c (print_rtl_with_bb): Cast alloca return value for
+ in_bb_p.
- * config/i386/gnuelf.h: Include i386/linux.h instead of
- i386/linuxelf.h.
+Thu Oct 2 21:15:03 1997 Richard Henderson <rth@cygnus.com>
-Sun Apr 2 17:35:10 1995 Jim Wilson <wilson@cygnus.com>
+ * i386.h (RETURN_ADDR_RTX): New definition that works for
+ __builtin_return_address(0) and -fomit-frame-pointer.
- * cse.c (simplify_relational_operation): Don't simplify A-B for
- compare of A and B when the compare is unsigned.
+Wed Oct 1 13:43:53 1997 Jim Wilson <wilson@cygnus.com>
-Sun Apr 2 08:23:38 1995 Paul Eggert <eggert@twinsun.com>
+ Bring over from FSF.
+ Tue Aug 5 16:10:45 1997 Jason Merrill <jason@yorick.cygnus.com>
- * fixincludes (stdio.h): BSDI 2.0 changed the spelling of _VA_LIST_
- to _BSD_VA_LIST_.
-
-Sun Apr 2 07:57:28 1995 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
-
- * i386/xm-bsd386.h: New file.
- * configure (i[345]86-*-bsd*): Add xm_file.
-
- * gcc.c (default_compilers): Pass -W and -w to gnat1.
-
- * winnt/winnt.h (STDC_VALUE): Add #undef.
- * i386/winnt.h (LIB_SPEC): Likewise.
-
-Sun Apr 2 07:55:25 1995 Douglas Rupp (drupp@cs.washington.edu)
-
- * i386/winnt.h (RETURN_POPS_ARGS, ENCODE_SECTION_INFO): Call
- chain_member_purpose, not chain_member_value.
- (ASM_FILE_START, LIB_SPEC): Move to here.
- * winnt/winnt.h (ASM_FILE_START, LIB_SPEC): Delete from here.
- * tree.c (chain_member_purpose): New function.
+ * mips.c (function_arg): Handle passing a struct
+ containing a double in a DFmode register without the PARALLEL.
-Sat Apr 1 12:19:14 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed Oct 1 11:13:25 1997 Ian Lance Taylor <ian@cygnus.com>
- * c-typeck.c (build_binary_op): New variable build_type controls
- type given to expression when created. Set to integer_type_node for
- comparison ops instead of result_type so result_type still holds type
- in which comparison is done. When checking for comparison between
- signed and unsigned, use result_type rather than (possibly shortened)
- type of op0. Don't warn about equality comparison of signed operand
- to unsigned constant that fits in signed type.
+ * pexecute.c: Use spawn if __CYGWIN32__.
-Sat Apr 1 09:47:02 1995 Douglas Rupp (drupp@cs.washington.edu)
+ * pexecute.c: Include "config.h" first, as per autoconf manual
+ (from Paul Eggert <eggert@twinsun.com>).
- * i386/winnt.h (CPP_PREDEFINES): Add definitions for __stdcall
- and __cdecl.
- * winnt/winnt.h (LIB_SPEC): Add OLDNAMES.LIB.
- * winnt/xm-winnt.h: Remove unneeded #define's for non-ANSI functions.
- * fixinc.winnt: Remove unneeded fixes relating to __stdcall.
+Wed Oct 1 01:44:36 1997 Philippe De Muyter <phdm@info.ucl.ac.be>
- * objc/Makefile (SHELL): New definition.
+ * m68k/x-mot3300 (XCFLAGS): Disable as's long/short jump
+ optimisation for f/expr.o and f/stb.o.
-Sat Apr 1 08:25:26 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Sep 30 23:48:57 1997 Jeffrey A Law (law@cygnus.com)
- * cse.c (cse_insn): When emitting a BARRIER, don't put it after
- a deleted insn.
+ * cse.c (this_insn_cc0_mode): Initialize.
- * reload.c (push_reload): Initialize secondary_{in,out}_icode.
+Tue Sep 30 23:09:40 1997 Thomas Koenig <ig25@mvmap66.ciw.uni-karlsruhe.de>
- * gcc.c (print_multilib_info): Don't use LAST_PATH if not set.
+ * cccp.c (expand_to_temp_buffer): Initialize all members of obuf.
-Sat Apr 1 08:15:59 1995 Pat Rankin (rankin@eql.caltech.edu)
+ * haifa-sched.c (get_block_head_tail): Remove unneeded initialization.
- * vax.md (extv, extzv): Don't use immediate value for operand 1.
+Tue Sep 30 23:06:43 1997 Richard Henderson <rth@cygnus.com>
-Sat Apr 1 07:48:29 1995 Yury Shevchuk (sizif@botik.yaroslavl.su)
+ * alpha.md (beq): For registers and ints 0-255, use cmpeq+bne, since
+ that pair will dual-issue on the 21164 and plus+beq won't.
+ (bne): Likewise for cmpeq+beq.
- * stmt.c (expand_asm_operands): Properly ignore invalid reg in clobber.
+Tue Sep 30 16:07:58 1997 Jim Wilson <wilson@cygnus.com>
-Sat Apr 1 07:02:24 1995 Paul Eggert <eggert@twinsun.com>
+ * except.c (find_exception_handler_labels): Correct argument to free.
- * cccp.c: General code cleanup.
- Add prototypes for static functions.
- Remove unnecessary casts to (char *); add casts to (U_CHAR *).
- Add parentheses suggested by `gcc -Wparentheses'.
- Rename local variables as suggested by `gcc -Wshadow'.
- <fcntl.h>, <stdlib.h>, <string.h>, <unistd.h>: New includes.
- <sys/time.h>, <sys/resource.h>: Include only if defined(RLIMIT_STACK).
- <time.h>: Include, unless <sys/time.h> already does.
- (HAVE_FCNTL_H, HAVE_STDLIB_H, HAVE_SYS_TIME_H): New symbols.
- (HAVE_UNISTD_H, STDC_HEADERS, TIME_WITH_SYS_TIME): Likewise.
- (__attribute__, PROTO, VA_START, PRINTF_ALIST, PRINTF_DCL): New macros.
- (PRINTF_PROTO{,_1,_2,_3}, DO_PROTO): Likewise.
- (bcopy, bzero, bcmp): If #defined by configuration file, use that.
- If STDC_HEADERS is defined, use standard C functions.
- If BSTRING is defined, or USG and VMS are not defined, use
- the C library. Otherwise, use my_bcopy, my_bzero, my_bcmp.
- (localtime): Remove no-longer-necessary explicit declaration.
- (getenv, index, rindex): Don't declare explicitly if the
- appropriate system header should declare it.
- (fdopen): Remove no-longer-used declaration.
- (vprintf): Define a subsitute macro if !defined(HAVE_VPRINTF).
- (main): Replace `fdopen (dup (fileno (stdout)), "w"))'
- with `stdout'.
- (get_lintcmd, rescan, create_definition): Use bcmp instead of strncmp
- when both operands are known to be free of null bytes.
- (check_macro_name, compare_defs, collect_expansion): Likewise.
- (do_assert, compare_token_lists, assertion_lookup, do_line): Likewise.
- (skip_if_group, lookup): Likewise.
- (rescan): Remove unused label `startagain'.
- Abort instead of printing nonsense if the stack is corrupted
- when there was an unterminated successful conditional.
- (pcfinclude): Include explicit double-cast through GENERICPTR
- to identify particularly egregious type puns.
- (create_definition, do_define, check_macro_name): Use %.*s
- printf format to avoid painful copying-and-casting.
- (do_once): Return void, not (unused) int.
- (do_ident, do_pragma, do_sccs): Accept extra arguments so that
- all directive-handler's types match.
- (do_sccs): Define only if SCCS_DIRECTIVE is defined.
- (skip_if_group, dump_single_macro): Add `default: break;' to
- keep -Wswitch happy.
- (error, warning, error_with_line, vwarning_with_line, pedwarn): Use
- stdarg/vararg/vfprintf instead of passing bogus char * args around.
- (pedwarn_with_line, pedwarn_with_file_and_line, fatal): Likewise.
- (verror, vwarning, verror_with_line, vwarning_with_line): New fcns.
- (dump_single_macro): Abort if ap points to garbage.
- (make_definition, make_undef, make_assertion): Parameter now char *.
- (xmalloc, xrealloc, xcalloc, savestring, index0): Make sizes size_t
- instead of unsigned; make pointer parameters GENERICPTR, not char *.
- (xcalloc): Use bzero to clear memory instead of using own loop.
-
-Fri Mar 31 08:33:07 1995 Ken Raeburn (raeburn@wombat.gnu.ai.mit.edu)
+Tue Sep 30 11:00:00 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * longlong.h (umul_ppmm mc68000): Use %# instead of #.
-
-Fri Mar 31 06:37:54 1995 Michael Meissner (meissner@cygnus.com)
-
- * stor-layout.c (layout_decl): Implment -fpack-struct.
- (layout_record): Ditto.
+ * except.c (find_exception_handler_labels): Free LABELS when we're
+ done.
- * flags.h (flag_pack_struct): New flag variable.
-
- * toplev.c (flag_pack_struct): New flag variable.
- (f_options): Add -fpack-struct support.
-
- * Makefile.in (stor-layout.o): Add flags.h dependency.
-
-Fri Mar 31 08:40:16 1995 Douglas Rupp (drupp@cs.washington.edu)
+Mon Sep 29 14:04:35 1997 Jeffrey A Law (law@cygnus.com)
- * configure (i[345]86-*-winnt3*): Add tmake_file.
- * i386/x-winnt (winnt.o): Deleted.
- * i386/t-winnt: New file.
+ * version.c: Bump for snapshot.
-Fri Mar 31 07:26:37 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * m68k/netbsd.h, m68k/hp3bsd44.h: Remove #include of machine/ansi.h.
+Mon Sep 29 10:51:53 1997 Jason Merrill <jason@yorick.cygnus.com>
- * configure (a29k-*-bsd): Set tmake_file to t-libc-ok.
+ * flow.c (find_basic_blocks): Mark calls as potentially jumping
+ to the EH labels.
- * stmt.c (expand_asm_operands): Properly handle output that can't
- be directly written into.
-
- * c-parse.in (structsp): Correct error in last change.
- * c-common.c (init_attributes): A_FORMAT is only for decls.
-
-Thu Mar 30 18:27:34 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * libgcc2.c: Remove explicit 0-initializations of static variables.
-
-Thu Mar 30 18:22:39 1995 Fergus Henderson <fjh@cs.mu.oz.au>
-
- * c-typeck.c (internal_build_compound_expr): Warn if LHS of comma
- expression has no side effects, or computes value which is not used.
- * stmt.c (make warn_if_unused_value): No longer static.
- * tree.h (warn_if_unused_value): Add declaration.
-
-Thu Mar 30 18:15:11 1995 Jim Wilson <wilson@cygnus.com>
-
- * combine.c (get_last_value): Revert back to use prev_nonnote_insn
- instead of prev_real_insn. Modify test that ignores USE insns.
-
- * rs6000.h (SELECT_SECTION): Apply constant DECL_INITIAL test
- only to DECLs.
-
- * explow.c (allocate_dynamic_stack_space): Test STACK_BOUNDARY against
- BIGGEST_ALIGNMENT at run time instead of at compile time.
- Give MUST_ALIGN macro a value, and test this value in if statements.
-
-Thu Mar 30 08:59:56 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * c-parse.in: Now have 27 shift/reduce conflicts.
- (attribute_list): Just make chain of all attributes.
- (attrib): Consistently put name as PURPOSE, args, if any, as VALUE.
- (structsp): Allow attributes on any struct or union.
- * c-common.c (enum attrs): New enum class.
- (attrtab, attrtab_idx): New variables.
- (add_attribute, init_attributes): New functions.
- (decl_attributes): Major rewrite.
- * tree.c (valid_machine_attribute): Now receive name and args.
+Mon Sep 29 09:58:06 1997 Jeffrey A Law (law@cygnus.com)
-Thu Mar 30 07:20:14 1995 Paul Eggert <eggert@twinsun.com>
+ * configure.in: Substitute for "install" too.
+ * configure: Rebuilt.
- * protoize.c: Use the phrase `preprocessing directive' consistently.
- * cccp.c (handle_directive, do_line, skip_if_group): Likewise.
- (output_line_directive): Renamed from output_line_command.
- (no_line_directives): Renamed from no_line_commands.
+Mon Sep 29 00:38:42 1997 Aaron Jackson <jackson@negril.msrce.howard.edu>
- * cccp.c (rescan): Don't recognize preprocessing directives
- within macro args. Warn if one is found.
+ * Makefile.in (bootstrap-lean, compare-lean): New targets.
-Thu Mar 30 06:20:36 1995 H.J. Lu (hjl@nynexst.com)
+Mon Sep 29 00:18:16 1997 Richard Henderson (rth@cygnus.com)
- * configure (i[345]86-*-linux*): Set xmake_file=x-linux,
- tm_file=i386/linux.h, and don't set extra_parts.
- (i[345]86-*-linux*aout*): New configuration.
- (i[345]86-*-linuxelf): Deleted.
- * config/linux{,-aout}.h, config/x-linux, config/xm-linux.h: New files.
- * config/i386/linux-aout.h: New file.
- * config/i386/linux.h: Extensive modifications to use ELF format
- as default.
- (LIB_SPEC): Don't use libc_p.a for -p. don't use libg.a
- unless for -ggdb.
- (LINUX_DEFAULT_ELF): Defined.
- * config/i386/linuxelf.h,config/i386/x-linux: Files deleted.
- * config/i386/xm-linux.h: Just include xm-i386.h and xm-linux.h.
+ * alias.c (base_alias_check): Two symbols can conflict if they
+ are accessed via AND.
+ (memrefs_conflict_p): Likewise.
-Wed Mar 29 19:09:36 1995 Mike Stump <mrs@cygnus.com>
+ * alpha.h (SETUP_INCOMING_VARARGS): Emit a blockage insn
+ after flushing argument registers to the stack.
- * libgcc2.c (__throw_type_match): Update to use new calling convention.
+ * Makefile.in (mostlyclean): Remove .regmove files.
-Wed Mar 29 14:53:23 1995 Jim Wilson <wilson@cygnus.com>
+Sun Sep 28 18:59:58 1997 Jason Merrill <jason@yorick.cygnus.com>
- * gcc.c (process_command): Delete code modifying gcc_exec_prefix.
- (main): Put it here after last use of gcc_exec_prefix. For cross
- compiler, set startfile_prefixes if gcc_exec_prefix is set and
- standard_startfile_prefix is a relative path.
+ * libgcc2.c (__throw): Fix thinko.
- * combine.c (make_compound_operation, AND case): Undo July 7, 1994
- change.
+Sun Sep 28 12:00:52 1997 Mark Mitchell <mmitchell@usa.net>
- * mips/mips.md (call_internal1, call_value_internal1): Move %* from
- start of assembler output to immediately before the jal.
-
- * mips/mips.c (function_prologue): Put SDB_DEBUGGING_INFO ifdef around
- code for SDB_DEBUG support.
- (mips_select_rtx_section, mips_select_section): Change rdata_section
- to READONLY_DATA_SECTION and sdata_section to SMALL_DATA_SECTION.
- * mips/mips.h (SMALL_DATA_SECTION): Define.
-
- * reorg.c (mark_referenced_resources): Make setjmp use all registers.
-
- * flow.c (mark_used_regs, case SUBREG): Only fall through to REG case
- if operand is a REG.
+ * cplus-dem.c (demangle_template): Add new parameter. Handle new
+ template-function mangling.
+ (consume_count_with_underscores): New function.
+ (demangle_signature): Handle new name-mangling scheme.
- * i960/i960.h (TARGET_SWITCHES): Make -mold-align set
- TARGET_FLAG_STRICT_ALIGN.
- (STRICT_ALIGNMENT): Test TARGET_STRICT_ALIGN.
+Sun Sep 28 01:55:04 1997 Philippe De Muyter <phdm@info.ucl.ac.be>
- * sh/sh.c (andcosts): Modify costs to match the hardware, and add
- explanatory comments.
+ * flow.c (print_rtl_with_bb): Cast alloca return values for variables
+ start and end.
- * sparc/sol2.h (CPP_PREDEFINES): Add -D__SVR4.
-
-Wed Mar 29 14:30:30 1995 Michael Meissner <meissner@cygnus.com>
+Sun Sep 28 01:05:16 1997 Jeffrey A Law (law@cygnus.com)
- * rs6000/rs6000.md (movsf): When moving to/from integer registers,
- don't move floating point to memory if it is being simulated with
- -msoft-float.
+ * frame.c: Remove last change.
+ * dwarf2.h: Remove last change.
+ * tree.h: Add declarations of DWARF2 unwind info support
+ functions.
-Wed Mar 29 06:47:36 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
-
- * c-parse.in (initdcl): Only call decl_attributes once.
- * c-common.c (decl_attributes): Clean up test for __mode__.
+Sat Sep 27 11:02:38 1997 Jason Merrill <jason@yorick.cygnus.com>
-Tue Mar 28 08:34:37 1995 John Hassey (hassey@dg-rtp.dg.com)
+ * c-decl.c (init_decl_processing): Add __builtin_dwarf_reg_size.
+ * tree.h (built_in_function): Likewise.
+ * expr.c (expand_builtin): Likewise.
+ * except.h: Likewise.
+ * dwarf2out.c (expand_builtin_dwarf_reg_size): New fn.
+ * libgcc2.c (copy_reg): New fn.
+ (__throw): Use it.
- * i386.md (adddi3): Don't treat two non-equal MEMs as non-aliasing.
+Fri Sep 26 08:54:59 1997 Paul Eggert <eggert@twinsun.com>
-Tue Mar 28 08:20:49 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * c-typeck.c (build_binary_op): Warn about comparing signed vs
+ unsigned if -W is specified and -Wno-sign-compare is not.
+ * c-decl.c (warn_sign_compare): Initialize to -1.
+ (c_decode_option): -Wall no longer implies -Wsign-compare.
- * a29k.h (CONSTANT_ADDRESS_P): Provide consistent definition.
+Fri Sep 26 09:00:13 1997 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-Tue Mar 28 07:26:41 1995 Paul Eggert <eggert@twinsun.com>
+ * frame.c: Include gansidecl.h for PROTO.
+ * dwarf2out.c: Move inclusion of dwarf2.h down so that PROTO is
+ defined. Don't declare dwarf2out_cfi_label here.
+ * dwarf2.h: Add declarations of DWARF2 unwind info support
+ functions.
+ * m68k.c: Include dwarf2.h.
+ (output_function_prologue): Add dwarf2 support.
+ * m68k.h (INCOMING_RETURN_ADDR_RTX, DWARF_FRAME_REGNUM): New macros.
+ (INCOMING_FRAME_SP_OFFSET): Likewise.
- * cccp.c (do_xifdef, do_endif): Remove unnecessary pointer comparisons.
+ * integrate.c (expand_inline_function): Make sure there is at
+ least one insn that can be used as an insertion point.
-Mon Mar 27 20:45:15 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Wed Sep 24 21:34:06 1997 Jason Merrill <jason@yorick.cygnus.com>
- * calls.c (expand_call, store_one_arg): Don't set KEEP in calls
- to assign_stack_temp.
- * function.c (preserve_temp_slots): Clear ADDR_TAKEN on item
- that we are preserving.
+ * dwarf2out.c: s/flag_verbose_asm/flag_debug_asm/
-Mon Mar 27 14:39:35 1995 Ian Lance Taylor <ian@cygnus.com>
+Wed Sep 24 22:05:30 1997 Jeffrey A Law (law@cygnus.com)
- * mips/mips.h (FIRST_PSEUDO_REGISTER): Increment.
- (FIXED_REGISTERS, CALL_USED_REGISTERS): Add new register.
- (MD_REG_LAST): Increment.
- (ST_REG_FIRST, ST_REG_LAST): Increment.
- (HILO_REGNUM): Define.
- (enum reg_class): Add HILO_REG.
- (REG_CLASS_NAMES): Add "HILO_REG".
- (REG_CLASS_CONTENTS): Add HILO_REG initializer, and adjust ST_REGS
- and ALL_REGS initializers.
- (SECONDARY_RELOAD_CLASS): Remove.
- (SECONDARY_INPUT_RELOAD_CLASS): Define.
- (SECONDARY_OUTPUT_RELOAD_CLASS): Define.
- (REGISTER_MOVE_COST): Treat HILO_REG as MD_REGS.
- (REGISTER_NAMES): Add initialization line.
- (DEBUG_REGISTER_NAMES): Add "accum".
- * mips/mips.md: For each instruction which sets HI or LO, clobber
- HILO_REGNUM with (clobber (match_scratch:MODE N "=a")). Change
- each explicit reference to register 66 to register 67.
- (mulsidi3): Change to define_expand.
- (mulsidi3_internal): New name of old mulsidi3.
- (mulsidi3_64bit): New insn.
- (umulsidi3): Change to define_expand.
- (umulsidi3_internal): New name of old umulsidi3.
- (umulsidi3_64bit): New insn.
- (madddi_64bit, umaddi_64bit): New insns.
- (movdi_internal2): Add case for setting HILO_REG to zero.
- (reload_indi, reload_outdi): New define_expands.
- (movsi_internal1, movsi_internal2): Add cases for setting MD_REGS
- to zero, and for setting a general reg to HILO_REG.
- (reload_outsi): New define_expand.
- * mips/mips.c (mips_reg_names): Add "accum".
- (mips_sw_reg_names): Likewise.
- (mips_regno_to_class): Map HILO_REGNUM to HILO_REG.
- (mips_move_1word): Handle moving HILO_REGNUM to a general
- register. Make sure that the normal MD_REG cases aren't used for
- HILO_REGNUM. Handle moving zero to a MD_REG.
- (mips_move_2words): Make sure that the normal MD_REG cases aren't
- used for HILO_REGNUM. Handle moving zero to a MD_REG.
- (override_options): Set mips_char_to_class for 'a' and 'b'.
- (mips_secondary_reload_class): Add in_p argument. Handle
- HILO_REGNUM.
+ * version.c: Bump for snapshot.
-Mon Mar 27 07:16:05 1995 Warner Losh <imp@village.org>
+Wed Sep 24 17:36:23 1997 Doug Evans <dje@canuck.cygnus.com>
- * gcc.c: Removed __NetBSD__ from conditional.
- Declare strerror if HAVE_STRERROR is defined; otherwise
- declare sys_errlist and sys_nerr.
- (my_strerror): New function.
-
-Fri Mar 24 18:08:14 1995 Jason Merrill <jason@python.cygnus.com>
-
- * i386/linux.h (LIB_SPEC): Don't try to link with libraries we
- know only exist in archive form unless -static.
+ Bring over from FSF.
-Fri Mar 24 16:12:16 1995 Doug Evans <dje@cygnus.com>
-
- * Makefile.in (multilib.h): Depend on Makefile, not config.status.
-
-Fri Mar 24 15:01:17 1995 Michael Meissner <meissner@cygnus.com>
-
- * rs6000/rs6000.h (TARGET_MULTIPLE_SET): New target_flags bit that
- indicates -mmultiple or -mno-multiple was explicitly passed by the
- user, and not set as part of the cpu defaults.
- (TARGET_SWITCHES): Set TARGET_MULTIPLE_SET bit for both -mmultiple
- and -mno-multiple.
-
- * rs6000/rs6000.c (rs6000_override_options): If -mmultiple or
- -mno-multiple was explicitly used, don't override the setting with
- the processor default.
-
-Wed Mar 22 21:42:13 1995 Doug Evans <dje@cygnus.com>
-
- * i960/i960.c (i960_function_arg_advance): Ensure all regs marked
- as used if stack is also used (for va_start).
- (i960_setup_incoming_varargs): Rewrite to be similar to Intel's
- version, but don't allocate reg block unless necessary.
- * ginclude/va-i960.h (varargs va_start): Save g14 explicitly.
- Account for arguments preceding va_alist.
-
-Wed Mar 22 13:24:55 1995 Torbjorn Granlund <tege@adder.cygnus.com>
-
- * pa.c (singlemove_string): Handle SFmode constants again. Simplify.
- (zdepi_cint_p): Make some variables HOST_WIDE_INT.
- (lhs_lshift_cint_operand): Likewise.
- (output_and): Likewise.
- (output_ior): Likewise.
+ Wed Sep 24 19:17:08 1997 Doug Evans <dje@cygnus.com>
-Wed Mar 22 12:40:09 1995 Jim Wilson <wilson@chestnut.cygnus.com>
+ * sparc/sparc.md (get_pc_via_call): Renamed from get_pc_sp32.
+ (get_pc_via_rdpc): Renamed from get_pc_sp64.
+ * sparc/sparc.c (finalize_pic): Update call to gen_get_pc_via_call.
- * sh.md (udivsi3): Don't clobber register 6.
- (udivsi3, divsi3, mulsi3_call): Use a pseudo-reg with regclass 'z'
- for output rather than hard register 0.
- (block_move_real): Don't clobber registers 4 and 5.
+ Wed Sep 24 18:38:22 1997 David S. Miller <davem@tanya.rutgers.edu>
- * mips.c (mips_select_section): Apply constant DEC_INITIAL tests
- only to VAR_DECLs.
+ * sparc/sparc.h (ASM_CPU_SPEC): Pass -Av9a for v8plus, ultrasparc.
+ (TARGET_OPTIONS): Add -malign-loops=, -malign-jumps=,
+ -malign-functions=.
+ (sparc_align_{loops,jumps,funcs}_string): Declare.
+ (sparc_align_{loops,jumps,funcs}): Declare.
+ (DEFAULT_SPARC_ALIGN_FUNCS): New macro.
+ (FUNCTION_BOUNDARY): Use sparc_align_funcs.
+ (STACK_BIAS): Define.
+ (SPARC_SIMM*_P): Cast to unsigned HOST_WIDE_INT first, then perform
+ test.
+ (SPARC_SETHI_P): New macro.
+ (CONST_OK_FOR_LETTER_P): Use it.
+ (ASM_OUTPUT_ALIGN_CODE): Define.
+ (ASM_OUTPUT_LOOP_ALIGN): Define.
+ * sparc/sparc.c (sparc_align_{loops,jumps,funcs}_string): New globals.
+ (sparc_align_{loops,jumps,funcs}): New globals.
+ (sparc_override_options): Handle -malign-loops=, -malign-jumps=,
+ -malign-functions=.
+ (move_operand): Use SPARC_SETHI_P.
+ (arith_double_operand): Cast to unsigned HOST_WIDE_INT first, then
+ perform test.
+ (arith11_double_operand): Likewise.
+ (arith10_double_operand): Likewise.
+ (finalize_pic): Finish sparc64 support.
+ (emit_move_sequence): Use SPARC_SETHI_P. Simplify low part of
+ 64 bit constants if able.
+ (output_fp_move_quad): Don't use fmovq unless TARGET_HARD_QUAD.
+ (sparc_builtin_saveregs, sparc64 case): Don't save fp regs if
+ ! TARGET_FPU.
+ * sparc/sparc.md (*): Use GEN_INT instead of gen_rtx.
+ (get_pc_sp32): Use for sparc64 as well.
+ (lo_sum_di_sp{32,64}): Fix handling on 64 bit hosts.
+ (sethi_di_sp64_const): Likewise.
+ (movtf_cc_sp64): Check TARGET_HARD_QUAD.
+ (cmp_zero_extract_sp64): Use unsigned HOST_WIDE_INT in cast.
+ (ashlsi3, ashldi3, ashrsi3, ashrdi3, lshrsi3, lshrdi3): Likewise.
-Wed Mar 22 03:53:17 1995 Richard Stallman <rms@mole.gnu.ai.mit.edu>
+ Tue Sep 23 19:02:46 1997 Doug Evans <dje@cygnus.com>
- * config.sub (rm400, rm600): New machine names.
- (sinix5.*, sinix): New os aliases.
- (mips-siemens): Default os to sysv4.
+ * sparc/linux-aout.h (COMMENT_BEGIN): Delete.
+ * sparc/linux.h (COMMENT_BEGIN): Likewise.
+ * sparc/linux64.h (COMMENT_BEGIN): Likewise.
-Mon Mar 20 21:56:47 1995 Per Bothner <bothner@kalessin.cygnus.com>
+ Tue Sep 23 14:48:18 1997 David S. Miller <davem@tanya.rutgers.edu>
- Merged Paul Eggert's patch to cccp.c of Wed Mar 8 18:21:51 1995:
- * cpplib.c (do_include): Fix type typo: pcfbuflimit is char *, not int.
-
- Merged Doug Evans' patch to cccp.c of Mon Feb 27 17:06:47 1995:
- * cpplib.c (do_include): Check for redundant file before opening in
- relative path case. Don't call fstat unnecessarily.
+ Add sparc64 linux support.
+ * configure.in (sparc64-*-linux*): Recognize. Add sparc/xm-sparc.h
+ to xm_file list on 32-bit sparc-linux.
+ * sparc/xm-sp64.h: New file.
+ * sparc/linux64.h: New file.
+ * sparc/xm-linux.h: Include some standard headers if not inhibit_libc.
+ Don't include xm-sparc.h.
+ * config/xm-linux.h (HAVE_PUTENV, HAVE_ATEXIT): Define.
+ * glimits.h (LONG_MAX): Handle sparc64.
- Merged J.T. Conklin's patch to cccp.c of Wed Feb 22 20:29:31 1995:
- * cpperror.c: Removed __NetBSD__ from conditional.
+ Sat Sep 20 03:07:54 1997 Doug Evans <dje@cygnus.com>
- Merged Kenner's patch to cccp.c & cexp.y of Tue Sep 20 17:49:47 1994:
- * cppexp.c (struct operation): Make value by HOST_WIDE_INT.
- (cpp_parse_expr): Change return type to HOST_WIDE_INT.
- * cpplib (eval_if_expr): Likewise.
- (do_if, do_elif): Update appropriately.
- * cpplib.h (cpp_parse_expr): Removed, to avoid defining HOST_WIDE_INT.
+ * sparc/sysv4.h (ASM_COMMENT_START): Delete.
+ * sparc.h (ASM_COMMENT_START): Define.
+ * sparc.c (output_function_prologue): Use it.
+ (sparc_flat_output_function_{epi,pro}logue): Likewise.
- Merged Paul Eggert's patch to cccp.c of Mon Aug 8 19:42:09 1994:
- * cpplib.c (create_definition): Warn about `#define a@', since a
- diagnostic is now required (see ISO TC1's addition to subclause 6.8).
- Also warn about `#define is-empty(x) (!x)'.
+ Wed Sep 17 15:04:19 1997 Doug Evans <dje@cygnus.com>
-Tue Mar 21 00:10:50 1995 Jeffrey A. Law <law@mole.gnu.ai.mit.edu>
+ * sparc/sysv4.h (ASM_OUTPUT_{FLOAT,DOUBLE,LONG_DOUBLE}): Delete,
+ use sparc.h's copies.
+ * sparc/sparc.h (ASM_OUTPUT_{FLOAT,DOUBLE,LONG_DOUBLE}): Print
+ ascii form as well.
- * x-pa (CC): Add "-Dbsd4_4".
+ Mon Sep 8 08:45:19 1997 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
-Mon Mar 20 18:40:31 1995 Per Bothner <bothner@kalessin.cygnus.com>
+ * sparc.c (dwarf2out_cfi_label): Add declaration.
+ (save_regs, output_function_prologue): Remove cast for it.
+ (sparc_flat_{save_restore,output_function_prologue): Likewise.
+ ({save,restore}_regs): No longer inline.
- * toplev.c (print_error_function): New function hook.
- (default_print_error_function): New function. Default value
- of print_error_function. Code moved here from report_error_function.
- (report_error_function): Use print_error_function hook.
+Tue Sep 23 12:34:51 1997 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
-Mon Mar 20 20:27:43 1995 Doug Evans <dje@cygnus.com>
+ * fold-const.c (make_range): Correctly handle cases of converting
+ from unsigned to signed type.
- * cccp.c (do_xifdef): Handle c++ comments.
- (do_endif): Likewise.
+Tue Sep 23 12:34:51 1997 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
-Mon Mar 20 15:31:45 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * fold-const.c (merge_ranges): Make sure that if one range is subset
+ of another, it will always be the second range. Correct (+,-) case to
+ account for this.
+
+Tue Sep 23 08:32:51 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * final.c (final_end_function): Also do dwarf2 thing if
+ DWARF2_DEBUGGING_INFO.
+ (final_start_function): Likewise.
+
+Tue Sep 23 01:15:50 1997 David S. Miller <davem@tanya.rutgers.edu>
+
+ * expmed.c (expand_divmod): If compute_mode is not the same as
+ mode, handle the case where convert_modes() causes op1 to no
+ longer be a CONST_INT.
+
+ * reorg.c (dbr_schedule): At end of this pass, add REG_BR_PRED
+ note holding get_jump_flags() calculation to all JUMP_INSNs.
+ * rtl.h (enum reg_note): New note types REG_BR_PRED and REG_SAVE_AREA.
+ * rtl.c (reg_note_name): Add new note types.
+
+Tue Sep 23 00:59:54 1997 Jeffrey A Law (law@cygnus.com)
+
+ * rtlanal.c (computed_jump_p): Fix typo in last change.
+
+Tue Sep 23 00:42:44 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+
+ * loop.c (indirect_jump_in_function_p): Return 0
+ by default.
+
+Tue Sep 23 00:33:55 1997 Jeffrey A Law (law@cygnus.com)
+
+ * rs6000/xm-rs6000.h: Fix thinko in last change.
+ * rs6000/xm-sysv4.h: Likewise.
- * configure (i386 configurations): Prepend i386/ to t-crt*.
+Mon Sep 22 19:33:53 1997 Jim Wilson <wilson@cygnus.com>
-Mon Mar 20 07:58:04 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * mips.c (save_restore_insns): Only set RTX_FRAME_RELATED_P if store_p.
- * stmt.c (fixup_gotos): Add missing call from last change.
+Mon Sep 22 14:41:00 1997 Jeffrey A Law (law@cygnus.com)
- * objc/misc.c: Put Alpha-specific decls before #include of runtime.h.
+ * reg-stack.c (find_blocks): Fix thinko in last change.
- * alpha.h (EXTRA_SECTIONS): Write zeros first time in .rdata.
+1997-09-21 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-Sat Mar 18 16:37:24 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * m68k.c (output_function_prologue): Add dwarf2 support.
- * flow.c (mark_used_regs, case SUBREG): Set reg_changes_size even
- for integer modes.
- (mark_used_regs): Set reg_changes_size for RHS, if necessary.
- * combine.c (gen_lowpart_for_combine): Set reg_changes_size, if needed.
- * reload.c (push_reload): Reload a SUBREG if paradoxical and
- class is CLASS_CANNOT_CHANGE_SIZE.
- * reload1.c (gen_reload): Handle paradoxical SUBREGs.
- * alpha.h (SECONDARY_{INPUT,OUTPUT}_RELOAD_CLASS): Need GENERAL_REGS
- for paradoxical SUBREG and FLOAT_REGS.
- (SECONDARY_NEEDED_MODE): Use actual mode for 4 bytes or wider.
- * alpha.md (movsi): Allow FP regs and add case for store of FP reg.
- Remove cvtlq from MEM to FP reg case.
+ * m68k.h (INCOMING_RETURN_ADDR_RTX, DWARF_FRAME_REGNUM,
+ INCOMING_FRAME_SP_OFFSET): New definitions.
- * rtl.h (emit_insns_after): Add declaration.
- * stmt.c (fixup_gotos): Do a cleanup for a block when it is exited
- even if label if not defined yet.
+Mon Sep 22 11:36:42 1997 David S. Miller <davem@tanya.rutgers.edu>
- * function.c (pop_function_context): Fix error in last change;
- reference old value of current_function_decl before we modify it.
+ * combine.c (try_combine): Use NULL_RTX instead of '0' where
+ appropriate in calls to gen_rtx().
+ * cse.c (cse_main): Likewise.
+ * emit-rtl.c (gen_label_rtx): Likewise.
+ * expr.c (init_expr_once): Likewise.
+ * haifa-sched.c (flush_pending_lists, sched_analyze_insn,
+ sched_analyze, init_rgn_data_dependences,
+ compute_block_backward_dependences): Likewise.
+ * sched.c (schedule_insns): Likewise.
+ * varasm.c (immed_double_const): Likewise.
-Fri Mar 17 21:57:44 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * sparc.h (INCOMING_FRAME_SP_OFFSET): Define to
+ SPARC_STACK_BIAS for sake of dwarf2 on sparc64.
- * toplev.c (rest_of_compilation): Handle -Wreturn-type properly
- for inlines we aren't compiling yet.
+Mon Sep 22 11:21:33 1997 J. Kean Johnston <jkj@sco.com>
-Fri Mar 17 21:26:48 1995 Mike Stump <mrs@cygnus.com>
+ * i386/sco5.h: Make ELF default file format and add -mcoff/-melf..
+ (MULTILIB_DEFAULTS): Define.
+ (ASM_SPEC, CPP_SPEC): Handle -mcoff.
+ (STARTFILE_SPEC, ENDFILE_SPEC, LINK_SPEC): Likewise.
+ (LIBGCC_SPEC): Likewise.
+ (MASK_COFF, TARGET_COFF, TARGET_ELF): Define.
+ (SUBTARGET_SWITCHES): Add -mcoff and -melf.
+ * i386/t-sco5 (CRTSTUFF_T_CFLAGS): Add -fPIC.
+ (CRTSTUFF_T_CFLAGS_S): Tweak for COFF.
+ (EXTRA_PARTS, TAROUTOPTS): Delete.
+ (libgcc1-elf, libgcc2-elf, libgcc-elf targets): Delete.
+ (MULTILIB_OPTIONS): Define.
+ (MULTILIB_DIRNAMES, MULTILIB_EXCEPTIONS): Likewise.
+ (MULTILIB_MATCHE, MULTILIB_EXTRA_OPTS): Likewise.
- * libgcc2.c (__register_exceptions): Handle empty tables.
+Mon Sep 22 02:10:43 1997 Jeffrey A Law (law@cygnus.com)
-Fri Mar 17 11:48:31 1995 Douglas Rupp (drupp@cs.washington.edu)
+ * version.c: Bump for snapshot.
- * i386/winnt.c (winnt_function_prologue): Deleted.
- (gen_stdcall_suffix): New function.
+Sun Sep 21 17:45:45 1997 Jeffrey A Law (law@cygnus.com)
-Thu Mar 16 17:36:52 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * loop.c (loop_number): Delete function. Change all references
+ to use uid_loop_num array.
+ * loop.h (loop_number): Delete declaration.
+ * unroll.c (unroll_loop): Change "loop_number" references to
+ use uid_loop_num instead.
- * svr4.h (LINK_SPEC): If the user did not specify -h name, use the
- output file name, if any.
- * sparc/sol2.h (LINK_SPEC): Ditto. Also, if the user did not
- specify -R path, add an -R for each -L.
+ * loop.c (loop_unroll_factor): Move outside #ifdef HAIFA
+ conditional.
+ (loop_unroll_iter): Remove unused variable and all references.
+ (loop_optimize): Always allocate and clear space for loop_unroll_factor.
+ (insert_bct): Fix minor formatting problems.
+ * loop.h (loop_unroll_factor): Move decl outside #ifdef HAIFA.
+ (loop_unroll_iter): Removed unused decl.
+ * unroll.c (unroll_loop): Remove code to set loop_unroll_iter.
+ Always record the unrolling factor.
- Move SunOS 4-specific assembler switches into the appropriate place.
- * m68k/sun[23].h (ASM_SPEC): Add %{R} %{j} %{J} %{h} %{d2}
- %{keep-local-as-symbols:-L}.
- * i386/sun.h (ASM_SPEC): Add %{R} %{keep-local-as-symbols:-L}.
- * sparc/sparc.h (ASM_SPEC): Ditto.
- * gcc.c (default_compilers): Remove %{R} %{j} %{J} %{h} %{d2}
- %{keep-local-as-symbols:-L} from assembler rules.
+ * cse.c (simplify_relational_operation): Set h0u just like h0s.
+ Similarly for h1u and h1s.
-Thu Mar 16 16:58:09 1995 Michael Meissner <meissner@cygnus.com>
+ * flow.c (jmp_uses_reg_or_mem): Deleted unused function.
+ (find_basic_blocks): Use computed_jump_p to determine if a
+ particular JUMP_INSN is a computed jump.
+ * reg-stack.c (find_blocks): Use computed_jump_p to determine
+ if a particular JUMP_INSN is a computed jump.
+ * rtlanal.c (jmp_uses_reg_or_mem): New function.
+ (computed_jump_p): Likewise.
+ * rtl.h (computed_jump_p): Declare.
+ * genattrtab.c (pc_rtx): Define and initialize.
+ * loop.c (loop_optimize): Always determine if the current
+ function has a computed jump.
+ (indirect_jump_in_function_p): Use computed_jump_p to determine
+ if a particular JUMP_INSN is a computed jump.
- * rs6000/eabi-ctors.c: New file, handle C++ static constructors
- and destructors without requiring anything else from a libc.
+ * loop.c (fix_bct_param): Delete unused function.
+ (check_bct_param): Likewise.
- * rs6000/t-eabi (LIB2FUNCS_EXTRA): Build eabi-ctors.c.
+Sat Sep 20 16:22:06 1997 Jason Merrill <jason@yorick.cygnus.com>
- * rs6000/eabi.asm: Do not load up register 2 if there is no .got
- section. Jump to the __do_global_ctors function at the end of
- processing to call C++ static constructors, and it will return to
- __eabi's caller. Use normal volatile registers, instead of saving
- and restoring registers 30 and 31.
+ * frame.c (__deregister_frame): Check properly for initialized object.
- * rs6000/eabi.h (STARTFILE_SPEC): Define as null.
- (LIB_SPEC): Ditto.
- (ENDFILE_SPEC): Ditto.
- (LIBGCC_SPEC): Always look for libgcc.a.
+Fri Sep 19 20:51:03 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
-Thu Mar 16 17:05:14 1995 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+ * alpha/linux.h (HANDLE_SYSV_PRAGMA): Defined.
- * stmt.c (warn_if_unused_value, case SAVE_EXPR): New case.
- (warn_if_unused_value, case NOP_EXPR): OK if CALL_EXPR inside.
+Fri Sep 19 18:53:50 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
- * c-common.c (decl_attributes): Allow alignment for TYPE_DECLs.
+ * jump.c (thread_jumps): check can_reverse_comparison_p before
+ threading a reversed-condition jump.
- * Makefile.in (xsys-protos.h): Fix typo in -U operand.
+ * sched.c (update_flow_info): Don't pass SCRATCH to dead_or_set_p.
+ * haifa-sched.c (update_flow_info): Likewise.
-Thu Mar 16 13:49:10 1995 Per Bothner <bothner@rtl.cygnus.com>
+Thu Sep 18 21:13:40 1997 Jeffrey A Law (law@cygnus.com)
- * cpplib.c, cpplib.h: New files - a C PreProcessor library.
- * cpphash.c, cpphash.h, cppalloc.c, cpperror.c, cppexp.c:
- New files - utility features used by cpplib.
- * cppmain.c: New file - cpp replacement main program for cpplib.
- * Makefile.in: New rules to build cppmain.
+ * Makefile.in (BOOT_CFLAGS): Use -O2.
-Thu Mar 16 16:11:05 1995 Douglas Rupp (drupp@cs.washington.edu)
+ * configure.in (strtoul, bsearch): Have autoconf check for these
+ functions.
+ * configure, config.in: Rebuilt.
- * i386/winnt.h (FUNCTION_PROLOGUE, HAVE_probe, gen_probe): Deleted.
- (ENCODE_SECTION_INFO, VALID_MACHINE_DECL_ATTRIBUTE): New macro.
+ * m68k/xm-mot3300.h (alloca): Properly declare if __STDC__.
+ * mips/mips.h (alloca): Likewise.
+ * rs6000/xm-rs6000.h (alloca): Likewise.
+ * rs6000/xm-sysv4.h: Likewise.
-Thu Mar 16 15:58:24 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Thu Sep 18 14:22:22 1997 Jason Merrill <jason@yorick.cygnus.com>
- * combine.c (apply_distributive_law, case SUBREG): Fix typo when
- checking for paradoxical SUBREG.
+ * final.c (final_scan_insn): Hand BARRIERs off to the dwarf2 code.
+ * dwarf2out.c (dwarf2out_frame_debug): Pass the whole insn along.
+ (dwarf2out_stack_adjust): A BARRIER resets the args space to 0.
-Wed Mar 15 18:45:08 1995 Doug Evans <dje@cygnus.com>
+ * except.c (end_eh_unwinder): Subtract 1 from return address.
+ * libgcc2.c (__throw): Likewise.
+ (find_exception_handler): Don't change PC here. Compare end with >.
- * libgcc1-test.c: Renamed from cross-test.c.
- * Makefile.in (LIBGCC1_TEST): Renamed from CROSS_TEST.
- (all.cross): Delete $(ENQUIRE) dependency.
- (libgcc1-test): Renamed from cross-test.
- Delete unnecessary gcc-cross and $(LIBGCC) dependencies.
- Link with -nostartfiles -nostdlib
- `$(GCC_FOR_TARGET) --print-libgcc-file-name`.
- (libgcc1-test.o): Renamed from cross-test.o.
- Change gcc-cross dependency to xgcc since the latter is used.
+Thu Sep 18 10:43:07 1997 Nick Clifton <nickc@cygnus.com>
-Wed Mar 15 13:49:21 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * v850.c (compute_register_save_size): Correct register
+ number.
+ * v850.md (save_interrupt, return_interrupt): Correct
+ register number.
+ * v850/lib1funcs.asm (save_interrupt): Correct register number.
+ (return_interrupt): Use stack pointer, not element pointer.
- * tree.c (save_tree_status): Now takes a tree 'context' instead of
- a boolean 'toplevel' as an argument. If 'context' is not
- current_function_decl, create a new obstack for the new function.
- Also save inline_obstacks.
- (restore_tree_status): No longer takes a second argument. Also
- restore inline_obstacks.
- (temporary_allocation): Clear inline_obstacks.
- (permanent_allocation): Free up the obstacks in inline_obstacks.
+1997-09-18 Brendan Kehoe <brendan@lisa.cygnus.com>
- * function.h (struct function): New fields contains_functions and
- inline_obstacks.
+ * configure.in, configure: Make sure to create the stage* and include
+ symbolic links in each subdirectory.
- * function.c (push_function_context_to): Now takes a tree
- 'context' instead of a boolean 'toplevel' as an argument.
- Also save current_function_contains_functions.
- (push_function_context): Pass current_function_decl to it.
- (pop_function_context_from): Takes 'context' instead of 'toplevel'.
- Set current_function_contains_functions properly.
- (pop_function_context): Pass current_function_decl to it.
+Thu Sep 18 01:47:06 1997 Jeffrey A Law (law@cygnus.com)
-Wed Mar 15 14:53:09 1995 Michael Meissner <meissner@cygnus.com>
+ * pa.md (reload_peepholes): Don't allow addresses with side
+ effects for the memory operand.
- * rs6000/rs6000.md (abssi2): Turn into a define_expand. If
- TARGET_POWER, do old code that uses the abs instruction. If not,
- do abs in three instructions, using a temporary register, which
- enables generating more reasonable code for sne. Add a recognizer
- for negative of the absolute value. Add define_splits for the
- PowerPC.
- (sne insn): Add a recognizer for sne on the PowerPc to use two
- instructions, compared to the four generated using the absolute
- value insn.
+Wed Sep 17 18:19:53 1997 Jason Merrill <jason@yorick.cygnus.com>
-Tue Mar 14 18:38:40 1995 J.T. Conklin <jtc@cygnus.com>
+ * libgcc2.c (find_exception_handler): Subtract one from our PC when
+ looking for a handler, to avoid hitting the beginning of the next
+ region.
- * m68k.md ({add,sub,mul,div}[sdx]f3): Add new patterns for recognizing
- SImode, HImode, and QImode operands.
+ * except.c (expand_builtin_set_return_addr_reg): Use force_operand.
-Mon Mar 13 18:59:36 EST 1995 David Edelsohn <edelsohn@mhpcc.edu>
+Wed Sep 17 18:33:59 1997 Jeffrey A Law (law@cygnus.com)
- * rs6000.h (CPP_SPEC): Add PPC403.
- (processor_type): Add PPC403.
- (RTX_COSTS): Add PPC403.
- * powerpc.h (CPP_SPEC): Add PPC403.
- * sysv4.h (CPP_SPEC): Add PPC403.
- * rs6000.c (processor_target_table): Add PPC403.
- * rs6000.md (define_attr cpu and function units): Add PPC403.
+ * mips/abi64.h (LONG_MAX_SPEC): Define.
+ * mips.h (LONG_MAX_SPEC): Define.
+ (CPP_SPEC): Include long_max_spec.
+ (EXTRA_SPECS): Include long_max_spec.
-Mon Mar 13 14:40:23 1995 Michael Meissner <meissner@cygnus.com>
+Wed Sep 17 14:11:38 1997 Jeffrey A Law (law@cygnus.com)
- * rs6000/rs6000.md (call, call_value insns): Do not put a nop
- after a bl instruction on System V.4 and eABI.
+ * v850.c (construct_save_jarl): Fix thinko in last change.
- * rs6000/sysv.4 (SUBTARGET_SWITCHES): Add support for
- -mno-traceback to suppress the V.4 traceback word.
- (ASM_DECLARE_FUNCTION_NAME): Don't put out a traceback work if
- -mno-traceback.
+Wed Sep 17 09:53:07 1997 Jeffrey A Law (law@cygnus.com)
-Mon Mar 13 13:36:37 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * version.c: Bump for snapshot.
- * t-svr4, i386/t-{crtpic,sol2}, m88k/t-svr4, sparc/t-sol2:
- Use -fPIC, rather than -fpic, for building crtstuff.
+Tue Sep 16 14:22:36 1997 Jason Merrill <jason@yorick.cygnus.com>
-Sat Mar 11 17:27:08 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * libgcc2.c (find_exception_handler): Not found is -1.
- * configure: Use aix3newas.h for AIX 3.2.4 and 5.
- * rs6000/aix41.h: Undefine ASM_OUTPUT_EXTERNAL{,_LIBCALL}.
- * rs6000/aix3newas.h: New file. Define ASM_SPEC to -u, and
- undefine ASM_OUTPUT_EXTERNAL{,_LIBCALL}.
+ * integrate.c (expand_inline_function): Move expand_start_bindings
+ after expanding the arguments.
-Sat Mar 11 06:42:50 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Sep 16 11:13:46 1997 Jim Wilson <wilson@cygnus.com>
- * dbxout.c (dbxout_symbol): Properly handle decl whose DECL_NAME
- points to a TYPE_DECL with a zero TYPE_NAME.
+ * expr.c (expand_expr): Remove previous incorrect change.
+ If target and slot has no DECL_RTL, then call mark_addressable
+ again for the slot after we give it RTL.
-Fri Mar 10 18:18:33 1995 Torbjorn Granlund <tege@cygnus.com>
+Tue Sep 16 09:18:52 1997 Jason Merrill (jason@cygnus.com)
- * pa.h (PROMOTE_MODE): Define.
+ * expr.c (expand_expr, case TARGET_EXPR): Call mark_addressable
+ again for the slot after we give it RTL.
-Fri Mar 10 14:37:58 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Tue Sep 16 00:13:20 1997 Nick Clifton <nickc@cygnus.com>
- * sdbout.c (sdbout_record_type_name): If TYPE_NAME is
- a TYPE_DECL, get name from DECL_NAME.
+ * v850.c (register_is_ok_for_epilogue,
+ pattern_is_ok_for_epilogue, construct_restore_jr,
+ pattern_is_ok_for_prologue, construct_save_jarl): New functions.
-Fri Mar 10 14:09:26 1995 Doug Evans <dje@cygnus.com>
+ * v850.h (pattern_is_ok_for_prologue,
+ pattern_is_ok_for_epilogue, register_is_ok_for_epilogue): New
+ predicates.
- * arm/riscix.h (SUBTARGET_SWITCHES): Renamed from
- ARM_EXTRA_TARGET_SWITCHES.
- * arm/riscix1-1.h (SUBTARGET_SWITCHES): Likewise.
- * arm.h (SUBTARGET_SWITCHES): Likewise.
- (TARGET_HARD_FLOAT, TARGET_SOFT_FLOAT): Define.
- (TARGET_SWITCHES): Add -msoft-float, -mhard-float.
- (BYTES_BIG_ENDIAN): Delete #ifndef/#endif.
- (CONDITIONAL_REGISTER_USAGE): If -msoft-float, disable fp regs.
- (FUNCTION_VALUE): R16 is return reg only if !-msoft-float.
- (LIBCALL_VALUE): Likewise.
- * arm.md (all fp patterns): Conditionalize on TARGET_HARD_FLOAT.
- (*movsf_soft_insn, *movdf_soft_insn): New patterns.
+ * v850.md: Replace prologue and epilogue patterns with a
+ match_parallel pattern.
-Fri Mar 10 13:53:46 1995 Jim Wilson <wilson@cygnus.com>
+Mon Sep 15 22:53:01 1997 Jeffrey A Law (law@cygnus.com)
- * reorg.c (steal_delay_list_from_target): Exit at the top if the
- branch in SEQ is not a single set.
+ * aclocal.m4: Add replacement for AC_PROG_INSTALL.
+ * configure.in: Use EGCS_PROG_INSTALL.
- * sh.md (movdi define_split, movdf define_split): Correct indentation
- and formatting. Make the condition fail if an operand is a MEM
- with an auto-inc address.
+Mon Sep 15 22:40:55 1997 Jim Wilson (wilson@cygnus.com)
- * varasm.c (copy_constant): Copy operand of ADDR_EXPR if it is a
- constant.
+ * dwarf2out.c (gen_subprogram_die): Handle redefinition of an
+ extern inline function.
+
+Mon Sep 15 22:40:55 1997 Richard Henderson (rth@cygnus.com)
+
+ * dwarf2out.c (reg_loc_descriptor): Fix prototype.
+ (concat_loc_descriptor): New function.
+ (loc_descriptor): Call it.
+ (add_AT_location_description): Also elide the descriptor if both
+ halves of a CONCAT are pseudos.
+ (add_location_or_const_value_attribute): Recognize CONCAT too.
+
+Mon Sep 15 15:24:00 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha.md (movdi): Handle CONST_DOUBLE for TARGET_BUILD_CONSTANTS.
+
+ * alpha/alpha.c (output_prolog): New variable sa_reg. Use it for
+ out-or-range reg_offset.
+ (output_epilog): Likewise.
+
+Mon Sep 15 15:39:26 1997 Jeffrey A Law (law@cygnus.com)
+
+ * cse.c (simplify_relational_operation): If MODE specifies a
+ mode wider than HOST_WIDE_INT, then the high word of a CONST_INT
+ is derived from the sign bit of the low word.
+
+Mon Sep 15 11:43:38 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ Support dwarf2 unwinding on PUSH_ROUNDING targets like the x86.
+
+ * dwarf2.h: Add DW_CFA_GNU_args_size.
+ * frame.c (execute_cfa_insn): Likewise.
+ * dwarf2out.c (dwarf_cfi_name, output_cfi): Likewise.
+ (dwarf2out_args_size, dwarf2out_stack_adjust): New fns.
+ (dwarf2out_frame_debug): If this isn't a prologue or epilogue
+ insn, hand it off to dwarf2out_stack_adjust.
+ (dwarf2out_begin_prologue): Initialize args_size.
+ * frame.h (struct frame_state): Add args_size.
+ * libgcc2.c (__throw): Use args_size.
+ * final.c (final_scan_insn): If we push args, hand off all insns
+ to dwarf2out_frame_debug.
+ * defaults.h (DWARF2_UNWIND_INFO): OK for !ACCUMULATE_OUTGOING_ARGS.
+
+ * dwarf2out.c dwarf2out_frame_debug): Fix typo.
+ Handle epilogue restore of SP from FP.
+ * emit-rtl.c (gen_sequence): Still generate a sequence if the
+ lone insn has RTX_FRAME_RELATED_P set.
+
+ * frame.c (extract_cie_info): Handle "e" augmentation.
+ * dwarf2out.c (ASM_OUTPUT_DWARF_*): Provide definitions in the
+ absence of UNALIGNED_*_ASM_OP.
+ (UNALIGNED_*_ASM_OP): Only provide defaults if OBJECT_FORMAT_ELF.
+ (output_call_frame_info): Use "e" instead of "z" for augmentation.
+ Don't emit augmentation fields length.
+ (dwarf2out_do_frame): Move outside of #ifdefs.
+ * defaults.h (DWARF2_UNWIND_INFO): Don't require unaligned data
+ opcodes.
+
+ * sparc.h (UNALIGNED_INT_ASM_OP et al): Don't define here after all.
+ * sparc/sysv4.h (UNALIGNED_INT_ASM_OP): Define here.
+ * sparc/sunos4.h (DWARF2_UNWIND_INFO): Define to 0.
+ * sparc/sun4gas.h: New file.
+ * configure.in: Use sun4gas.h if SunOS 4 --with-gnu-as.
+
+ * collect2.c (write_c_file_stat, write_c_file_glob): Declare
+ __register_frame_table and __deregister_frame.
+
+1997-09-15 Brendan Kehoe <brendan@cygnus.com>
+
+ * except.c (find_exception_handler_labels): Use xmalloc instead of
+ alloca, since MAX_LABELNO - MIN_LABELNO can be more than 1 million
+ in some cases.
+
+Sun Sep 14 21:01:23 1997 Jeffrey A Law (law@cygnus.com)
+
+ * Makefile.in: Various changes to build info files
+ in the object tree rather than the source tree.
+
+Sun Sep 14 12:24:30 1997 Jeffrey A Law (law@cygnus.com)
+
+ * fixinc.math: New file to fix math.h on some systems.
+ * configure.in (freebsd, netbsd): Use fixinc.math on these
+ systems.
+ * configure: Rebuilt.
+
+Sun Sep 14 11:11:05 1997 Jeffrey A Law (law@cygnus.com)
+
+ * regmove.c (regmove_optimize): If we end up moving the
+ original insn due to lifetime overlaps, make sure to move
+ REG_NOTES too.
+
+Sat Sep 13 15:51:11 1997 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * Makefile.in (INSTALL_{PROGRAM,DATA}): Use value found by configure.
+
+Sat Sep 13 12:57:26 1997 Jeffrey A Law (law@cygnus.com)
+
+ * haifa-sched.c (add_branch_dependences): Make each insn in
+ a SCHED_GROUP_P block explicitly depend on the previous insn.
+
+Fri Sep 12 13:49:58 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.h: Prototype dwarf2 hooks.
+ * expr.c: Adjust.
+
+Thu Sep 11 17:43:55 1997 Jim Wilson <wilson@cygnus.com>
+
+ * configure.in (native_prefix): Delete.
+ (mips-dec-netbsd): Don't set prefix.
+ (*linux*): Don't set prefix.
+
+Thu Sep 11 15:48:32 1997 Fred Fish <fnf@ninemoons.com>
+
+ * protoize.c: Include <varargs.h> only if HAVE_VARARGS_H is
+ defined. If not defined, include <sys/varargs.h> if
+ HAVE_SYS_VARARGS_H is defined.
+ * configure.in: Test for varargs.h and sys/varargs.h.
+ * configure: Regenerate with autoconf.
+ * config.in: Regenerate with autoheader.
+
+ * cpplib.c (quote_string): Cast first arg of sprintf call
+ from "unsigned char *" to "char *".
+ (output_line_command): Ditto.
+ (macroexpand): Ditto.
+ (do_line): Cast atoi arg from "unsigned char *" to "char *".
+
+Wed Sep 10 21:37:30 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+ * Makefile.in (compare): Exit with nonzero status if there
+ are comparison failures. Note which files failed the
+ comparison test in .bad_compare.
+
+Wed Sep 10 17:05:46 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+
+ * config/alpha/elf.h (CPP_PREDEFINES): Remove -D__PIC__ -D__pic__.
+
+Wed Sep 10 16:37:28 1997 Fred Fish <fnf@ninemoons.com>
+
+ * Makefile.in (LN, LN_S): New macros, use where appropriate.
+ * aclocal.m4 (GCC_PROG_LN_S, GCC_PROG_LN): New tests.
+ * configure.in: Use GCC_PROG_LN_S and GCC_PROG_LN.
+ * configure: Regenerated.
+
+Thu Sep 11 11:09:43 1997 Jeffrey A Law (law@cygnus.com)
+
+ * loop.c (strength_reduce): Fix typo.
+
+Wed Sep 10 16:01:15 1997 Jim Wilson <wilson@cygnus.com>
+
+ * m88k/m88k.c (struct option): Rename to struct options.
+ * m88k/dolph.h (INITIALIZE_TRAMPOLINE): Delete here.
+ * m88k/sysv3.h (INITIALIZE_TRAMPOLINE): Delete ifdef and comments.
+ * libgcc2.c (__enable_execute_stack): Check for __sysV88__ not
+ __DOLPHIN__ or sysV88.
+
+Wed Sep 10 14:58:40 1997 Jim Wilson <wilson@cygnus.com>
+
+ * emit-rtl.c (gen_lowpart_common): For a SUBREG, add in word when
+ create new subreg.
+
+Wed Sep 10 15:19:22 1997 Jeffrey A Law (law@cygnus.com)
+
+ * config.sub: Accept 'amigados' for backward compatability.
+
+Wed Sep 10 14:05:08 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+
+ * Makefile.in (testsuite/site.exp): New target.
+ (check-gcc, check-g++): Depend on testsuite/site.exp.
+ Don't stop for failure.
+
+Wed Sep 10 12:59:57 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * expr.c (expand_builtin): Only support __builtin_dwarf_fp_regnum()
+ if DWARF2_UNWIND_INFO.
+
+Wed Sep 10 11:49:20 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ Add support for exception handling using DWARF 2 frame unwind info.
+ Currently works on SPARC and MIPS, and almost on x86.
+
+ * libgcc2.c (get_reg, put_reg, get_return_addr, put_return_addr,
+ next_stack_level, in_reg_window): Helper fns.
+ (__throw): Implement for DWARF2_UNWIND_INFO.
+
+ * expr.c (expand_builtin): Handle builtins used by __throw.
+ * tree.h (enum built_in_function): Add builtins used by __throw.
+ * c-decl.c (init_decl_processing): Declare builtins used by __throw.
+ * dwarf2out.c (expand_builtin_dwarf_fp_regnum): Used by __throw.
+ * except.c (expand_builtin_unwind_init): Hook for dwarf2 __throw.
+ (expand_builtin_extract_return_addr): Likewise.
+ (expand_builtin_frob_return_addr): Likewise.
+ (expand_builtin_set_return_addr_reg): Likewise.
+ (expand_builtin_eh_stub): Likewise.
+ (expand_builtin_set_eh_regs): Likewise.
+ (eh_regs): Choose two call-clobbered registers for passing back values.
+
+ * frame.c, frame.h: New files for parsing dwarf 2 frame info.
+ * Makefile.in (LIB2ADD): New variable. Add $(srcdir)/frame.c.
+ (libgcc2.a): Use it instead of $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
+ (stmp-multilib): Likewise.
+ ($(T)crtbegin.o, $(T)crtend.o): Add -fno-exceptions.
+
+ * except.c: #include "defaults.h".
+ (exceptions_via_longjmp): Default depends on DWARF2_UNWIND_INFO.
+ (emit_throw): Don't defeat assemble_external if DWARF2_UNWIND_INFO.
+ (register_exception_table_p): New fn.
+ (start_eh_unwinder): Don't do anything if DWARF2_UNWIND_INFO.
+ (end_eh_unwinder): Likewise.
+
+ * crtstuff.c: Wrap .eh_frame section, use EH_FRAME_SECTION_ASM_OP,
+ call __register_frame and __deregister_frame as needed.
+ * varasm.c (eh_frame_section): New fn if EH_FRAME_SECTION_ASM_OP.
+ * dwarf2out.c (EH_FRAME_SECTION): Now a function-like macro. Check
+ EH_FRAME_SECTION_ASM_OP.
+ * sparc/sysv4.h (EH_FRAME_SECTION_ASM_OP): Define.
+ * mips/iris6.h: (EH_FRAME_SECTION_ASM_OP): Define.
+ (LINK_SPEC): Add __EH_FRAME_BEGIN__ to hidden symbols.
+
+ * dwarf2out.c (output_call_frame_info): If no support for
+ EXCEPTION_SECTION, mark the start of the frame info with a
+ collectable tag.
+ * collect2.c (frame_tables): New list.
+ (is_ctor_dtor): Recognise frame entries.
+ (scan_prog_file): Likewise.
+ (main): Pass -fno-exceptions to sub-compile. Also do collection
+ if there are any frame entries.
+ (write_c_file_stat): Call __register_frame_table and
+ __deregister_frame as needed.
+ (write_c_file_glob): Likewise.
+
+ * defaults.h (DWARF2_UNWIND_INFO): Default to 1 if supported.
+ Also require unaligned reloc support.
+ * sparc.h (UNALIGNED_SHORT_ASM_OP, UNALIGNED_INT_ASM_OP,
+ UNALIGNED_DOUBLE_INT_ASM_OP): Define here.
+ * sparc/sysv4.h: Not here.
+
+ * toplev.c (compile_file): Call dwarf2out_frame_{init,finish}.
+ * dwarf2out.c (dwarf2out_init): Don't call dwarf2out_frame_init.
+ (dwarf2out_finish): Don't call dwarf2out_frame_finish.
+
+ * libgcc2.c (L_eh): Reorganize, moving code shared by different
+ EH implementations to the top.
+ (find_exception_handler): Split out. Start from 0. Compare against
+ end with >=.
+ (__find_first_exception_table_match): Use it.
+ * except.c (output_exception_table): Don't do anything if there's
+ no table. Don't output a first entry of zeroes.
+ (eh_outer_context): Adjust properly.
+ (add_eh_table_entry): Use xrealloc.
+ * toplev.c (compile_file): Just call output_exception_table.
+
+Wed Sep 10 11:30:36 1997 Jason Merrill <jason@cygnus.com>
+
+ * i386.c (ix86_prologue): Add dwarf2 support for !do_rtl case.
+
+Wed Sep 10 08:17:10 1997 Torbjorn Granlund <tege@pdc.kth..se>
+
+ * except.c (eh_outer_context): Do masking using expand_and.
+
+Wed Sep 10 01:38:30 1997 Doug Evans <dje@cygnus.com>
+
+ Add port done awhile ago for the ARC cpu.
+ * arc/arc.h: New file.
+ * arc/arc.c: New file.
+ * arc/arc.md: New file.
+ * arc/initfini.c: New file.
+ * arc/lib1funcs.asm: New file.
+ * arc/t-arc: New file.
+ * arc/xm-arc.h: New file.
+ * ginclude/va-arc.h: New file.
+ * ginclude/stdarg.h: Include va-arc.h ifdef __arc__.
+ * ginclude/varargs.h: Likewise.
+ * Makefile.in (USER_H): Add va-arc.h.
+ * configure.in (arc-*-elf*): Recognize.
+ * longlong.h: Add ARC support.
+
+Wed Sep 10 01:32:54 1997 Jeffrey A Law (law@cygnus.com)
+
+ * expr.c (clear_storage): Use CONST0_RTX instead of const0_rtx.
+ when clearing non-BLKmode data.
+
+Wed Sep 10 00:29:29 1997 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * m88k/sysv3.h (INITIALIZE_TRAMPOLINE) Define.
+ * libgcc2.c (__enable_execute_stack): Provide for sysV88 too.
+
+ * xm-m88k.h (USG): Only define if it hasn't already been defined.
+
+ * Makefile.in (risky-stage1): Delete gratutious whitespace.
+
+ * Makefile.in (clean): Delete libgcc1-test.
+
+ * Makefile.in (INSTALL): cd to $(srcdir) before running texinfo.
+
+Tue Sep 9 17:07:36 1997 Stan Cox <coxs@dg-rtp.dg.com>
+
+ * m88k.c (m88k_expand_prologue): Set MEM_IN_STRUCT_P of va_list
+ template.
+
+Tue Sep 9 09:50:02 1997 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+
+ * dwarf2out.c (output_call_frame_info): Call named_section.
+
+Tue Sep 9 09:12:17 1997 Jeffrey A Law (law@cygnus.com)
+
+ * haifa-sched.c (print_value): Fix last change.
+
+Tue Sep 9 01:30:37 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * mips.h (DWARF_FRAME_REGNUM): Use the same numbering regardless of
+ write_symbols.
+
+Mon Sep 8 16:32:43 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * mips.c (function_prologue): Set up the CFA when ABI_32.
+
+ * sparc.c (save_regs): Check dwarf2out_do_frame instead of DWARF2_DEBUG
+ for dwarf2 unwind info.
+ (output_function_prologue, sparc_flat_output_function_prologue): Same.
+
+ * final.c (final_end_function): Check dwarf2out_do_frame instead
+ of DWARF2_DEBUG for dwarf2 unwind info.
+ (final_scan_insn): Likewise.
+ (final_start_function): Likewise. Initialize dwarf2 frame debug here.
+ (final): Not here.
+
+ * expr.c (expand_builtin_return_addr): Only SETUP_FRAME_ADDRESSES if
+ count > 0.
+
+ * varasm.c (exception_section): Check EXCEPTION_SECTION first.
+
+Mon Sep 8 15:15:11 1997 Nick Clifton <nickc@cygnus.com>
+
+ * v850.h (ASM_SPEC): Pass on target processor.
+ (CPP_PREDEFINES): Only define if not already specified.
+ (TARGET_VERSION): Only define if not already specified.
+ (MASK_CPU, MASK_V850, MASK_DEFAULT): Bits to specify target
+ processor.
+ (EXTRA_SWITCHES): Extra entries in the switches array.
+ (TARGET_DEFAULT): Set default target processor.
+
+Mon Sep 8 18:26:35 1997 Jim Wilson <wilson@cygnus.com>
+
+ * m68k.h (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): In MOTOROLA
+ cases, add %# and %/, and add : to make them into extended asms.
+
+Sun Sep 7 23:57:50 1997 Weiwen Liu <liu@hepunix.physics.yale.edu>
+
+ * alias.c (init_alias_analysis): Clean up incompatible pointer
+ type warning in bzero.
+ * regmove.c (regmove_optimize): Ditto.
+ * haifa-sched.c (find_rgns): Ditto.
+
+ * haifa-sched.c (print_value): Clean up ptr->int cast
+ warnings.
+
+Sun Sep 7 23:18:32 1997 Fred Fish <fnf@ninemoons.com>
+
+ * INSTALL: Change 'amigados' to 'amigaos' to match current usage.
+ * install.texi (Configurations): Ditto.
+ * config.sub: Ditto.
+
+Sun Sep 7 22:56:56 1997 Weiwen Liu (liu@hepvms.physics.yale.edu)
+
+ * Makefile.in (sdbout.o): Depend on insn-config.h.
+
+Sun Sep 7 18:44:50 1997 Jim Wilson <wilson@cygnus.com>
+
+ * m68k/m68k.h (TARGET_SWITCHES): For 68000, 68302, subtract MASK_68881.
+ For 68303, 68332, cpu32, subtract MASK_68040_ONLY.
+
+Sun Sep 7 18:30:46 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * dwarf2out.c (dwarf2out_frame_debug): Assume that in a PARALLEL
+ prologue insn, only the first elt is significant.
+ (output_call_frame_info): For exception handling, always use 4-byte
+ fields as specified by the dwarf2 spec.
+ Don't skip trivial FDEs.
+
+Sun Sep 7 14:19:39 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Bump for snapshot.
+
+Sun Sep 7 14:17:36 1997 Torbjorn Granlund (tege@pdc.kth.se)
+
+ * expmed.c (expand_divmod): Make op1_is_pow2 depend on unsignedp
+ for negative constants. Promote EXACT_DIV_EXPR to TRUNC_DIV_EXPR
+ when op1_is_pow2.
+
+Sun Sep 7 13:46:46 1997 Jeffrey A Law (law@cygnus.com)
+
+ * final.c (shorten_branches): During first pass, assume worst
+ possible alignment for ADDR_VEC and ADDR_VEC_DIFF insns.
+
+ * Makefile.in (distclean): Remove various things left around
+ by running the testsuite.
+
+Sun Sep 7 13:16:06 1997 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * configure.in (out_file): Emit definition to config.status in order
+ to have a defined value for configure.lang.
+ * configure: Re-built.
+
+Sun Sep 7 09:59:08 1997 Jan-Jaap van der Heijden (J.J.vanderHeijden@student.utwente.nl)
+
+ * configure.in: Make symlink to as-new rather than as.new. Similarly
+ for ld-new.
+ * configure: Rebuilt.
+
+Fri Sep 5 16:54:55 1997 Jim Wilson <wilson@cygnus.com>
+
+ * profile.c (output_func_start_profiler): Set DECL_EXTERNAL to zero.
+
+Fri Sep 5 16:16:44 1997 Christian Kuehnke <Christian.Kuehnke@arbi.Informatik.Uni-Oldenburg.DE>
+
+ * sparc/sparc.md: Add ultrasparc scheduling support.
+ * sparc/sparc.h (RTX_COSTS): For MULT give v9 a cost of 25 insns.
+
+Fri Sep 5 14:04:59 1997 Philippe De Muyter <phdm@info.ucl.ac.be>
+
+ * integrate.c (save_for_inline_copying): Use 0, not NULL_PTR,
+ as initial value for real_label_map.
+ (copy_for_inline): Likewise.
+
+Fri Sep 5 13:36:44 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * sched.c (update_flow_info) When looking if to set found_split_dest
+ or found_orig_dest, look at all parts of a PARALLEL.
+ * haifa-sched.c (update_flow_info): Likewise.
+
+Fri Sep 5 10:08:44 1997 Jeffrey A Law (law@cygnus.com)
+
+ * v850: New directory for v850 port.
+ * v850/lib1funcs.asm: New file.
+ * t-v850, v850.c, v850.h, v850.md, xm-v850.h: New files.
+ * ginclude/va-v850.h: New file.
+ * ginclude/varargs.h, ginclude/stdarg.h: Include va-mn10200.h.
+ * configure.in (mn10200-*-*): New target.
+ * configure: Rebuilt.
+ * config.sub: Handle v850-elf.
+ * Makefile.in (USER_H): Add va-mn10200.h.
+ * invoke.texi: Document v850 stuff.
+
+Fri Sep 5 09:37:50 1997 Jim Wilson (wilson@cygnus.com)
+
+ * sdbout.c (plain_type_1, case ARRAY_TYPE): Verify that TYPE_DOMAIN
+ has integer TYPE_{MAX,MIN}_VALUE before using them.
+
+ * m68k/m68k.h (MACHINE_STATE_SAVE, MACHINE_STATE_RESTORE): Add
+ __HPUX_ASM__ versions.
+
+Fri Sep 5 09:08:44 1997 Jeffrey A Law (law@cygnus.com)
+
+ * install.sh: Delete duplicate install script.
+
+Thu Sep 4 23:14:27 1997 Stan Cox (coxs@dg-rtp.dg.com)
+
+ * reg-stack.c (subst_stack_regs): Pop the stack register for a
+ computed goto which sets the same stack register.
+
+ * reg-stack.c (compare_for_stack_reg): Swap only if the source and
+ destination are both on the regstack.
+ (subst_stack_regs_pat): Put the destination at the top of the regstack.
+
+Thu Sep 4 15:02:27 1997 Jim Wilson <wilson@cygnus.com>
+
+ * mips.md (nonlocal_goto_receiver): Define.
+
+ * profile.c (output_arc_profiler): Check next_insert_after for non
+ NULL before deferencing it.
+
+ * i386/t-sol2 (TARGET_LIBGCC2_CFLAGS): Define to -fPIC.
+
+Thu Sep 4 14:51:57 1997 Jeffrey A Law (law@cygnus.com)
+
+ * i386.h (CPP_CPU_DEFAULT): Avoid using #elif.
- * mips/abi64.h (SETUP_INCOMING_VARARGS): Correct arguments to
- move_block_from_reg call.
+Thu Sep 4 15:01:49 1997 Michael Meissner <meissner@cygnus.com>
- * expr.c (expand_assignment): When offset is zero, make new MEM
- before setting MEM_VOLATILE_P.
+ * toplev.c (rest_of_compilation): For passes starting with
+ flow_analysis, use print_rtl_with_bb instead of print_rtl.
- * reload.c (find_reloads, case 'o'): Accept a fully reloaded
- auto-increment address.
+ * print-rtl.c (print_rtl_single): Print a single rtl value to a
+ file.
- * combine.c (max_uid_cuid): New static variable.
- (INSN_CUID): Call abort if INSN is out of range.
- (combine_instructions): Set max_uid_cuid. Set uid_cuid directly
- instead of through INSN_CUID.
- (get_last_value): Use prev_real_insn instead of prev_nonnote_insn.
- Ignore USE insns generated by combine.
+ * flow.c (print_rtl_with_bb): Print which insns start and end
+ basic blocks. For the start of a basic block, also print the live
+ information.
-Fri Mar 10 13:47:08 1995 Rod Barman <rodb@cs.ubc.ca>
+Thu Sep 4 11:51:43 1997 Jim Wilson <wilson@cygnus.com>
- * m68k/fpgnulib.c (__fixdfsi): Catch values < 0.5 in magnitude.
+ * toplev.c (main): Change #elif to #else/#ifdef
-Fri Mar 10 12:02:33 1995 Ian Lance Taylor <ian@cygnus.com>
+ * tlink.c: Include ctype.h.
+ * ginclude/va-mips.h: Add _VA_MIPS_H_ENUM ifdef/define/endif.
- * fixincludes: Fix `typedef struct term;' on hppa1.1-hp-hpux9.
+Thu Sep 4 11:17:16 1997 Mikeael Meissner (meissner@cygnus.com)
-Fri Mar 10 05:50:11 1995 Oliver Kellogg (Oliver.Kellogg@RST13.DASA.DBMAIL.d400.de)
+ * bitmap.c: Conditionally include stdlib.h.
+ (free): Provide a declaration if NEED_DECLARATION_FREE.
- * 1750a.c (sectname): Reverse Init and Normal.
- (print_operand_address, case PLUS): Add case for LABEL_REF.
- (print_operand_address, case LABEL_REF): Split fom SYMBOL_REF.
- (print_operand_address, case CODE_LABEL): New case.
- (ASM_FILE_END): Delete.
- * 1750a.h (FUNCTION_EPILOGUE): Restore stack before freeing local vars.
- (DEFAULT_SIGNED_CHAR): Now 1.
- (DATA_SECTION_ASM_OP): Use pseudo-op for read-only data (later copied).
- (JUMP_TABLES_IN_TEXT_SECTION): Define.
- (ASM_OUTPUT_ASCII): Split into multiple lines if long.
- (ASM_OUTPUT_{CHAR,SHORT,INT,LONG_INT}): Split up.
- (ASM_OUTPUT_COMMON): Call check_section.
+Thu Sep 4 09:58:53 1997 Joel Sherrill (joel@OARcorp.com)
-Thu Mar 9 12:46:53 1995 Michael Meissner <meissner@cygnus.com>
+ * i960/i960.h: Added default for SUBTARGET_SWITCHES macro.
- * rs6000.md (movsf): Do not call truncdfsf2 for non PowerPC
- when expanding a store to memory and -msoft-float was used.
+Thu Sep 4 09:53:20 1997 Jim Wilson (wilson@cygnus.com)
-Thu Mar 9 08:51:35 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * profile.c (output_arc_profiler): Verify next_insert_after is an
+ INSN before and after skipping a stack pop.
- * c-decl.c (start_function): Handle new parameter ATTRIBUTES.
- * c-tree.h (start_function): Add new parameter.
- * c-lang.c (finish_file): Pass new parm to start_function.
- * objc-act.c (build_module_descriptor, really_start_method): Likewise.
- * c-parse.in (fndef, nested_function): Pass prefix_attributes
- to start_function.
- (setspecs): Save prefix_attributes in declspec_stack.
- (decl rules): Restore prefix_attributes along with current_declspecs.
- (setattrs): Concatenate prefix_attributes to previous value.
- * c-common.c (decl_attributes): Handle prefix and suffix attributes
- the same way.
+Thu Sep 4 07:39:19 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
- * print-tree.c (print_node): Fix typo in printing large INTEGER_CST.
+ * final.c (shorten_branches): Don't count the lengths of deleted
+ instructions.
- * varasm.c (assemble_variable): Consistently use DECL_SIZE for
- everything.
+Thu Sep 4 09:43:01 1997 Jeffrey A Law (law@cygnus.com)
- * c-typeck.c (convert_for_assignment): Fix typo in testing for
- pointer to function type.
+ * version.c: Bump for snapshot.
- * varasm.c (record_constant_1): Handle NON_LVALUE_EXPR.
- Rewrite to use switch instead of if/then/elseif/else.
+Thu Sep 4 11:04:21 1997 Michael Meissner <meissner@cygnus.com>
-Wed Mar 8 18:21:51 1995 Paul Eggert <eggert@twinsun.com>
+ * bitmap.h (EXECUTE_IF_AND_IN_BITMAP): New macro, to iterate over
+ two bitmaps ANDed together.
+ (bitmap_print): Declare.
- * cccp.c (do_include): Fix type typo: pcfbuflimit is char *, not int.
+ * bitmap.c (function_obstack): Don't declare any more.
+ (bitmap_obstack): Obstack for allocating links from.
+ (bitmap_obstack_init): New static to say whether to initialize
+ bitmap_obstack.
+ (bitmap_element_allocate): Use bitmap_obstack to allocate from.
+ (bitmap_release_memory): Free all memory allocated from
+ bitmap_obstack.
-Wed Mar 8 17:30:29 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * basic-block.h (EXECUTE_IF_AND_IN_REG_SET): New macro, invoke
+ EXECUTE_IF_AND_IN_BITMAP.
- * fold-const.c (force_fit_type): Always propagate OVERFLOW.
+Wed Sep 3 10:39:42 1997 Jim Wilson <wilson@cygnus.com>
- * rtl.def (INLINE_HEADER): Add new "e" field.
- * rtl.h (FORCED_LABELS): New field; other fields adjusted.
- (gen_inline_header_rtx): New parm FORCED_LABELS.
- * emit-rtl.c (gen_inline_header): Add new parm FORCED_LABELS.
- * integrate.c (initialize_for_inline, output_inline_function):
- Handle FORCED_LABELS.
+ * alias.c (true_dependence): Address with AND can alias scalars.
+ (anti_dependence, output_dependence): Likewise.
-Wed Mar 8 13:47:20 1995 Jason Merrill (jason@cygnus.com)
+ * alias.c (true_dependence): Test x for BLKmode, in addition to mem.
- * alpha.h (WORD_SWITCH_TAKES_ARG): Add -rpath.
- (LINK_SPEC): Pass through -taso and -rpath.
- * alpha/osf12.h (LINK_SPEC): Ditto.
+Wed Sep 3 09:28:50 CDT 1997 Joel Sherrill (joel@OARcorp.com)
-Wed Mar 8 09:59:56 1995 Michael Meissner <meissner@cygnus.com>
+ * i386/go32-rtems.h, i386/rtems.h, i960/rtems.h, m68k/rtems.h,
+ mips/rtems64.h, pa/rtems.h, rs6000/rtems.h, sh/rtems.h,
+ sparc/rtems.h (subtarget_switches): Removed SUBTARGET_SWITCHES
+ definitions. Use -qrtems instead of -mrtems.
- * rs6000/eabi.asm: Rewrite so that the initialized pointers go
- into the .got2 section, which allows eabi.asm to be assembled with
- the -mrelocatable option. Move the data picked up from the bl
- instruction to before the traceback tag.
+Wed Sep 3 09:05:41 1997 Robert Lipe (robert@dgii.com)
- * rs6000/sysv4.h (CPP_SPEC): Define _RELOCATABLE if -mrelocatable
- switch is used.
+ * xm-sco5.h (sys_siglist): Define.
+ (SYS_SIGLIST_DECLARED): Likewise.
- * libgcc2.c (__new_handler): Don't initialize the pointer variable
- with the address of __default_new_handler, which may not work in
- some shared library mechanisms.
- (__builtin_new): If __new_handler is NULL, call the function
- __default_new_handler.
+Tue Sep 2 23:33:33 1997 Jeffrey A Law (law@cygnus.com)
-Tue Mar 7 17:34:59 1995 Ian Lance Taylor <ian@cygnus.com>
+ * expr.c (convert_move): Handle truncation from TQFmode to QFmode.
- * i960.h (PROCESS_PRAGMA): Define.
- (ROUND_TYPE_ALIGN): Pass maximum of COMPUTED and SPECIFIED to
- i960_round_align.
- (ROUND_TYPE_SIZE): Delete.
- * i960.c (process_pragma): Uncomment, and rewrite for gcc 2.
- (i960_round_size): Delete.
- (i960_round_align): Don't adjust suggested alignment downward.
- Restrict alignment to value set by #pragma align.
+Wed Sep 3 02:09:30 1997 Torbjorn Granlund <tege@pdc.kth..se>
-Tue Mar 7 12:14:46 1995 Doug Evans <dje@cygnus.com>
+ * except.c (eh_outer_context): Expand masking operation using
+ expand_binop.
- * configure (sparc64-*-elf): Add crtbegin.o, crtend.o to extra_parts.
- * sparc/sp64-elf.h (TARGET_VERSION): Define.
- (CPP_PREDEFINES): Delete sun, sparc, unix. Delete OS assertions.
- (ASM_SPEC): Define.
- (LINK_SPEC): Delete solaris stuff, this is an embedded target.
- (STARTFILE_SPEC, ENDFILE_SPEC): Define.
+Tue Sep 2 18:09:39 1997 Jim Wilson <wilson@cygnus.com>
-Mon Mar 6 17:54:01 1995 Doug Evans <dje@cygnus.com>
+ * alpha.md (floatdisf2-1): New pattern.
- * Makefile.in (install-common): Fix typo in installation of cpp.
- Likewise with gcc-cross.
+Tue Sep 2 18:41:55 1997 Jeffrey A Law (law@cygnus.com)
-Mon Mar 6 02:29:05 1995 Jeffrey A. Law <law@mole.gnu.ai.mit.edu>
+ * xm-svr4.h (SYS_SIGLIST_DECLARED): Define.
+ * xm-news.h (SYS_SIGLIST_DECLARED): Likewise.
+ * xm-sysv4.h (SYS_SIGLIST_DECLARED): Likewise.
+ * gcc.texi: Note that if you define sys_siglist that you should
+ also define SYS_SIGLIST_DECLARED.
- * pa.md (movsicc): New expander.
+ * mn10200.h (INITIALIZE_TRAMPOLINE): PC relative instructions
+ are relative to the next instruction, not the current instruction.
-Fri Mar 3 13:34:20 1995 Michael Meissner (meissner@cygnus.com)
+Tue Sep 2 14:22:43 1997 Jim Wilson <wilson@cygnus.com>
- * rs6000/sysv4.h (ASM_SPEC): If -mrelocatable was passed to
- compiler, pass it on to the assembler.
+ * local-alloc.c (contains_replace_regs): New function.
+ (update_equiv_regs): When adding a REG_EQUIV note for a set of a MEM,
+ verify that there is no existing REG_EQUIV note, and add a call to
+ contains_place_regs.
-Fri Mar 3 12:11:28 1995 Ian Lance Taylor <ian@cygnus.com>
+Tue Sep 2 12:48:11 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
- * fixincludes: Add fixes for VxWorks header files.
- * ginclude/stddef.h: If VxWorks typedef macros are defined, invoke
- them as appropriate.
+ * config/alpha/elf.h (CPP_PREDEFINES): Add -D__PIC__ -D__pic__.
+ (STARTFILE_SPEC): Always use crtbegin.o%s
+ (ENDFILE_SPEC): Always use crtend.o%s.
-Fri Mar 3 05:48:54 1995 Paul Eggert <eggert@twinsun.com>
+Tue Sep 2 12:00:36 1997 Jim Wilson <wilson@cygnus.com>
- * cccp.c (dump_single_macro): Fix typo: % wasn't properly
- doubled in printf formats.
+ * alpha/alpha.h (PREFERRED_RELOAD_CLASS): Return NO_REGS if NO_REGS
+ is passed in.
+ * emit-rtl.c (gen_lowpart_common): Add code to convert CONST_INT to
+ SFmode for 64 bit hosts.
-Thu Mar 2 19:44:02 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Tue Sep 2 13:42:38 1997 Paul N. Hilfinger <hilfingr@CS.Berkeley.EDU>
- * expr.c (expand_expr, CLEANUP_POINT_EXPR): Force the operand out
- of memory before running cleanups.
+ * fixincludes: Permits spaces between # and define. Discard C++
+ comments in sys/pci.h on HP/UX 10.20.
-Thu Mar 2 19:15:24 1995 Paul Eggert <eggert@twinsun.com>
+Mon Sep 1 22:13:18 1997 Jeffrey A Law (law@cygnus.com)
- * cccp.c (rescan): Prevent accidental token-pasting to
- get !=, *=, /=, ==, or ^=.
+ * version.c: Bump for snapshot.
-Thu Mar 2 15:37:13 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pa.c (restore_unscaled_index_insn_codes): New function.
+ (record_unscaled_index_insn_codes): Likewise.
+ (output_function_prologue): Call restore_unscaled_index_insn_codes.
+ (output_function_epilogue): Free memory for unscaled_index_insn_codes.
+ (pa_reorg): Call record_unscaled_index_insn_codes.
- * c-typeck.c (build_binary_op): Avoid spurious warning
- comparing enumerator to unsigned variable.
+ * haifa-sched.c (move_insn): Handle notes correctly for insns
+ with SCHED_GROUP_P set.
-Thu Mar 2 18:18:38 1995 J.T. Conklin <jtc@netbsd.org>
+Mon Sep 1 16:58:57 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
- * m68k.md (sqrtsf2,sqrtdf2): Use fp precision specifiers.
+ * alpha/xm-linux.h (USE_BFD): Undef before define.
-Thu Mar 2 18:09:01 1995 Stephen L Moshier (moshier@world.std.com)
+Mon Sep 1 16:25:34 1997 Jim Wilson <wilson@cygnus.com>
- * c-lex.c (yylex, case !NOT_FLOAT): Remove previous change.
+ * cse.c (cse_insn): Don't record BLKmode values.
-Thu Mar 2 15:26:50 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+Mon Sep 1 11:25:47 1997 Stephen Williams (steve@icarus.icarus.com)
- * Makefile.in (bootstrap*): Pass new STAGE_PREFIX to recursive makes.
+ * i960.h (LINK_SPEC): Handle "-mjX" and "-mrp" switches.
-Wed Mar 1 14:52:16 1995 Ian Lance Taylor <ian@cygnus.com>
+Mon Sep 1 08:29:46 1997 Jeffrey A Law (law@cygnus.com)
- * i960/i960-coff.h (ASM_FILE_START): Define.
- (CTORS_SECTION_ASM_OP, DTORS_SECTION_ASM_OP): Define.
- (EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS): Define.
- (CTORS_SECTION_FUNCTION, DTORS_SECTION_FUNCTION): Define.
- (INT_ASM_OP): Define.
- (ASM_OUTPUT_CONSTRUCTOR, ASM_OUTPUT_DESTRUCTOR): Define.
- * i960/vx960-coff.h (CPP_PREDEFINES): Define.
- (CPP_SPEC): Define.
- (CC1_SPEC): Default to -mca.
+ * cccp.c (sys_errlist): Remove special 4.4bsd declaration.
+ * collect2.c (sys_errlist): Likewise.
+ * cpplib.c (sys_errlist): Likewise.
+ * gcc.c (sys_errlist): Likewise.
+ * protoize (sys_errlist): Likewise.
+ * configure.in: Check for strerror.
+ * xm-freebsd.h (HAVE_STRERROR): Remove definition.
+ * xm-gnu.h (HAVE_STRERROR): Likewise.
+ * xm-linux.h (HAVE_STRERROR): Likewise.
+ * xm-netbsd.h (HAVE_STRERROR): Likewise.
+ * xm-bsd386.h (HAVE_STRERROR): Likewise.
+ * xm-cygwin32.h (HAVE_STRERROR): Likewise.
+ * xm-dos.h (HAVE_STRERROR): Likewise.
+ * xm-mingw32.h (HAVE_STRERROR): Likewise.
+ * xm-pa.h (HAVE_STRERROR): Likewise.
+ * xm-papro.h (HAVE_STRERROR): Likewise.
+ * xm-sysv4.h (HAVE_STRERROR): Likewise.
+ * configure, config.in: Rebuilt.
-Wed Mar 1 11:10:54 1995 Michael Meissner (meissner@cygnus.com)
+ * Makefile.in: Add several missing "else true" clauses.
- * rs6000/rs6000.c (output_prologue): Do not emit the word that
- gives the PC relative location to the local GOT table for the
- -mrelocatable option here.
- * rs6000/sysv4.h (ASM_DECLARE_FUNCTION_NAME): Emit it here.
+ * collect2.c: Change DONT_DECLARE_SYS_SIGLIST to SYS_SIGLIST_DECLARED.
+ * mips-tfile.c: Likewise.
+ * gcc.texi: DONT_DECLARE_SYS_SIGLIST: Remove docs.
+ * xm-linux.h (DONT_DECLARE_SYS_SIGLIST): Delete definition.
+ * xm-freebsd.h, xm-bsd386.h, xm-sysv4.h, xm-sol2.h: Likewise.
+ * configure.in: Check for sys_siglist declaration.
+ * configure, config.in: Rebuilt.
- * t-eabi (MULTILIB_OPTIONS, MULTILIB_DIRNAMES): Build -msoft-float
- and -mrelocatable versions of the library.
+Mon Sep 1 08:04:07 1997 Joel Sherrill (joel@OARcorp.com)
- * rs6000/powerpc.h (CPP_PREDEFINES): Define the cpu and machine as
- powerpc, not rs6000.
+ * i386/go32-rtems.h, i386/rtems.h, i960/rtems.h,
+ m68k/rtems.h, mips/rtems64.h, pa/rtems.h, rs6000/rtems.h,
+ sparc/rtems.h (subtarget_switches): Added -mrtems as a switch.
+ * i960/i960.h: Added SUBTARGET_SWITCHES macro.
+ * rs6000/sysv4.h (extra_subtarget_switches): Added new
+ macro EXTRA_SUBTARGET_SWITCHES.
+ * configure.in (sh*-*-rtems*): New target.
+ * sh/rtems.h: New file.
+ * sh/sh.h: Added SUBTARGET_SWITCHES macro.
+ * configure: Rebuilt.
- * libgcc2.c (_unwind_function): Clone for powerpc, using the
- PowerPC mnemonics.
+Sat Aug 30 22:54:26 1997 Jim Wilson <wilson@cygnus.com>
- * rs6000/rs6000.md (uminsi3, umaxsi3): Silence warnings that
- -2147483648 is too large to fit in a signed integer on 32-bit
- hosts.
+ * unroll.c (calculate_giv_inc): Handle increment with code PLUS.
-Wed Mar 1 06:48:31 1995 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+Sat Aug 30 10:49:46 1997 David Edelsohn <edelsohn@mhpcc.edu>
- * fold-const.c (decode_field_reference): Don't check TREE_CODE
- of EXP; let get_inner_reference decide if have reference.
- Allow no bit reference if have AND_MASK.
- (all_ones_mask_p): Use tree_int_cst_equal, not operand_equal_p.
- (unextend): New function.
- (fold_truthop): For constant cases, use new function, rework
- conversion, and warn if comparison can never be true.
+ * rs6000.md: Make DF fused-add operations pay attention to
+ -mno-fused-add.
- * expr.c (store_expr): Do conversion in two steps for promoted lhs.
+Fri Aug 29 19:19:54 1997 Jim Wilson <wilson@cygnus.com>
-See ChangeLog.9 for earlier changes.
+ * i386/xm-sysv4.h (DONT_DECLARE_SYS_SIGLIST): Define.
+
+Fri Aug 29 16:13:51 1997 Jeffrey A Law (law@cygnus.com)
+
+ * pa.md (reload_peepholes): Make sure operand is a REG before
+ examining REGNO. Allow general registers too.
+
+Fri Aug 29 11:42:04 1997 Jim Wilson <wilson@cygnus.com>
+
+ * varasm.c (mark_constants): Don't look inside CONST_DOUBLEs.
+
+Fri Aug 29 09:33:20 1997 Philipp Thomas (kthomas@lxi165.gwdg.de)
+
+ * dwarf2out.c (build_abbrev_table): Use xrealloc, not xmalloc
+ to reallocate abbrev_die_table.
+
+Thu Aug 28 15:14:46 1997 Jim Wilson <wilson@cygnus.com>
+
+ * m68k/m68k.md (iorsi_zexthi_ashl16): Disable.
+
+1997-08-27 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * Makefile.in (config.status): Depend on version.c
+
+ * expr.h (insn_gen_function): Reenable prototype.
+
+ * expr.c (move_by_pieces_1, clear_by_pieces_1): Fix prototype of
+ first parameter.
+
+Thu Aug 28 13:01:43 1997 Jim Wilson <wilson@cygnus.com>
+
+ * i386.c (ix86_expand_epilogue): Emit blockage instruction when pic.
+
+Thu Aug 28 07:03:15 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Bump for latest snapshot.
+
+ * bc-optab.c: Conditionally include stdlib.h.
+ (free): Provide a declaration if NEED_DECLARATION_FREE.
+ * tree.c (free): Provide a declaration if NEED_DECLARATION_FREE.
+ * rtl.h (free): Remove declaration.
+ * tree.h (free): Remvoe declaration.
+
+ * configure: Rebuilt.
+
+Wed Aug 27 21:32:20 1997 Jeffrey A Law (law@cygnus.com)
+
+ * flags.h (flag_move_all_movables): Declare.
+ (flag_reduce_all_givs): Likewise.
+ * loop.c (move_movables): Handle flag_move_all_movables.
+ (strength_reduce): Handle flag_reduce_all_givs.
+ * toplev.c (flag_move_all_movables): Define.
+ (flag_reduce_all_givs): Likewise.
+ (f_options): Add -fmove-all-movables and -freduce-all-givs.
+ * invoke.texi: Document new options, including alias stuff that
+ wasn't included last time.
+
+Wed Aug 27 18:08:51 1997 Bob Manson (manson@cygnus.com)
+
+ * t-h8300: Use TARGET_LIBGCC2_CFLAGS instead of LIBGCC2_CFLAGS.
+ * t-mn10200: Ditto.
+ * t-vxsparc: Ditto.
+ * t-vxworks68: Ditto.
+ * t-vxworks960: Ditto.
+ * t-vx29k: Ditto.
+
+Wed Aug 27 16:35:29 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha/xm-alpha.h (alloca): Define alloca to builtin_alloca for GNUC
+ if not already defined, and USE_C_ALLOCA not defined.
+
+Wed Aug 27 16:08:43 1997 Jim Wilson <wilson@cygnus.com>
+
+ * config.guess: Replace with script that uses ../config.guess.
+
+ * config/alpha/elf.h (DEFAULT_VTABLE_THUNKS): New. Defined as 1
+ if USE_GNULIBC_1 is not defined.
+
+Wed Aug 27 15:49:12 1997 Richard Henderson <rth@cygnus.com>
+
+ * alpha/elf.h (LINK_SPEC): Conditionalize on USE_GNULIBC_1.
+ * config.guess: Recognize alpha-linux-gnulibc1.
+ * configure.in (alpha-*-linux-gnulibc1): New target.
+ (alpha-*-linux-gnu*): Don't build crtbegin/end.
+
+Wed Aug 27 11:52:58 1997 Jim Wilson <wilson@cygnus.com>
+
+ * m68k.md (iorsi3_internal): Readd ! TARGET_5200 check lost in
+ last change.
+
+Wed Aug 27 01:56:18 1997 Doug Evans <dje@seba.cygnus.com>
+
+ * loop.c (combine_movables): Earlier insns don't match later ones.
+
+Wed Aug 27 01:24:25 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+
+ * config/linux.h (CC1_SPEC): Define it only if not defined.
+
+ * config/m68k/linux.h (CC1_SPEC): Undefine it before include
+ <linux.h>
+
+ * config/linux.h (DEFAULT_VTABLE_THUNKS): New. Defined as 1 if
+ USE_GNULIBC_1 is not defined.
+
+ * config/rs6000/linux.h (DEFAULT_VTABLE_THUNKS): New. Defined as 1.
+
+ * config/sparc/linux.h (DEFAULT_VTABLE_THUNKS): New. Defined
+ as 1 if USE_GNULIBC_1 is not defined.
+
+Wed Aug 27 00:49:14 1997 Jeffrey A Law (law@cygnus.com)
+
+ * reorg.c (dbr_schedule): Allow current_function_return_rtx
+ to be something other than a REG.
+ * function.c (expand_function_end): Fix current_function_return_rtx
+ if it was a pseudo.
+
+ * t-freebsd (USER_H): Include EXTRA_HEADERS and LANG_EXTRA_HEADERS.
+ * x-netbsd: Likewise
+ * x-dgux (USER_H): Include EXTRA_HEADERS and LANG_EXTRA_HEADERS
+ (INSTALL_HEADERS): Delete.
+ * x-dguxbcs: Likewise.
+ * x-hp3bsd44: Likewise
+ * x-pa: Likewise.
+
+Wed Aug 27 00:30:00 1997 Bernd Schmidt <crux@pool.informatik.rwth-aachen.de>
+
+ * i386.md (pop): pop increments the stack pointer.
+ (prologue_set_stack_ptr): New pattern.
+ * i386.c (ix86_expand_prologue): Use prologue_set_stack_ptr
+ instead of subsi3.
+
+Tue Aug 26 18:50:32 1997 Jim Wilson <wilson@cygnus.com>
+
+ * reload.c (find_reloads, case '0'): Reject matching a non-offsettable
+ address where an offsettable address is required.
+
+Tue Aug 26 17:54:56 1997 Michael P. Hayes (michaelh@ongaonga.chch.cri.nz>
+
+ * loop.c (check_final_value): Don't miss a biv increment in a
+ parallel.
+
+Tue Aug 26 12:03:49 1997 Jim Wilson (wilson@cygnus.com)
+
+ * dwarfout.c (dwarfout_file_scope_decl, case TYPE_DECL): Check
+ TYPE_DECL_IS_STUB instead of DECL_NAME.
+
+Mon Aug 25 23:27:10 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+
+ * objc/Make-lang.in ($(OBJC_O)): Also depend on cc1obj.
+
+Mon Aug 25 23:27:10 1997 Jim Meyering <meyering@eng.ascend.com>
+
+ * objc/Make-lang.in ($(OBJC_O)): Also depend on $(GCC_PASSES).
+
+Mon Aug 25 13:12:24 1997 Jeffrey A Law (law@cygnus.com)
+
+ * haifa-sched.c (find_pre_sched_live): Remove #if 0 code.
+ (find_post_sched_live): Likewise.
+
+ * haifa-sched.c (schedule_block): Remove old code to get arguments
+ from hard regs into pseudos early.
+
+Mon Aug 25 08:55:00 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Bump for new snapshot.
+
+ * local-alloc.c (update_equiv_regs): All the target to reject
+ promotion of some REG_EQUAL to REG_EQUIV notes.
+ * pa.h (DONT_RECORD_EQUIVALENCE): Define.
+
+ * pa.c (secondary_reload_class): (mem (mem ... )) does not need
+ secondary reloads.
+
+ * pa.c (hppa_builtin_saveregs): Emit a blockage insn after the
+ store of the argument registers.
+
+Mon Aug 25 08:39:02 1997 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * fold-const.c (multiple_of_p): New function.
+ (fold): Turn some cases of *_DIV_EXPR into EXACT_DIV_EXPR.
+
+Mon Aug 25 01:47:41 1997 Jeffrey A Law (law@cygnus.com)
+
+ * expr.h (insn_gen_function): Temporarily remove prototype.
+
+Sun Aug 24 17:22:21 1997 Jim Wilson <wilson@cygnus.com>
+
+ * Makefile.in (install-info): Don't cd into srcdir. Add srcdir to
+ filenames. Use sed to extract base filename for install.
+
+Sat Aug 23 18:19:40 1997 John F. Carr <jfc@mit.edu>
+
+ * unroll.c (find_splittable_givs): Only share if two givs have the
+ same add and multiply values.
+
+Sat Aug 23 14:36:27 1997 Jim Wilson <wilson@cygnus.com>
+
+ * m68k/next.h (GO_IF_INDEXABLE_BASE): Fix typo in undef.
+ * m68k/m68kemb.h (LIB_SPEC): Add missing comment end before it.
+
+Sat Aug 23 00:18:22 1997 Jeffrey A Law (law@cygnus.com)
+
+ * pa.c (pa_reorg): Always put begin_brtab and end_brtab insns
+ around branch tables.
+ * pa.md (begin_brtab, end_brtab): Only emit the .begin_brtab
+ and .end_brtab directives if TARGET_GAS.
+
+Fri Aug 22 14:05:55 1997 Jim Wilson <wilson@cygnus.com>
+
+ * alias.c (true_dependence): Pass x_addr not x to varies.
+
+ * acconfig.h (NEED_DECLARATION_CALLOC): Add.
+ * configure.in: Add GCC_NEED_DECLARATION call for calloc.
+ * rs6000/xm-rs6000.h (malloc, realloc, calloc, free): Delete
+ declarations.
+ * config.in, configure: Regenerate.
+
+Thu Aug 21 23:52:16 1997 John F. Carr <jfc@mit.edu>
+
+ * alias.c (find_base_value): Improve handling of PLUS, MINUS, and
+ LO_SUM.
+ (record_set): Handle LO_SUM like PLUS.
+ (init_alias_analysis): When following chains of base addresses,
+ do not stop on reaching a hard register.
+
+Thu Aug 21 20:17:37 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Bump for new snapshot.
+
+Thu Aug 21 17:28:00 1997 Jim Wilson <wilson@cygnus.com>
+
+ * alpha.h (ARCH_ASM_FILE_START): Define.
+ (ASM_FILE_START): Use ARCH_ASM_FILE_START.
+ * osf12.h, osf2or3.h (ARCH_ASM_FILE_START): Redefine to null string.
+
+Thu Aug 21 10:22:19 1997 Jeffrey A Law (law@cygnus.com)
+
+ * Makefile.in (install-common): Put gcov comment at start of line.
+
+Wed Aug 20 22:47:33 1997 Jeffrey A Law (law@cygnus.com)
+
+ * alias.c (init_alias_analysis): When simplifying the reg_base_value
+ array, simplify entries for hard registers too.
+
+Wed Aug 20 12:35:47 1997 Dave Love <d.love@dl.ac.uk>
+
+ * dwarf2.h (enum dwarf_call_frame_info): Remove trailing comma from
+ list.
+
+Wed Aug 20 11:58:33 1997 Jim Wilson <wilson@cygnus.com>
+
+ * stmt.c (start_cleanup_deferal, end_cleanup_deferal): Test
+ block_stack before dereferencing it.
+
+Wed Aug 20 11:57:11 1997 Michael Meissner <meissner@cygnus.com>
+
+ * rs6000.h (ISSUE_RATE): Define instead of MACHINE_issue_rate.
+
+Tue Aug 19 17:10:56 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * cplus-dem.c: Add 'extern' to prepends_underscore.
+
+Tue Aug 19 09:34:57 1997 Jeffrey A Law (law@cygnus.com)
+
+ * haifa-sched.c (ISSUE_RATE): Renamed from MACHINE_issue_rate.
+ (get_issue_rate): Delete.
+ * pa.h (ISSUE_RATE): Define.
+
+ * configure.in: Turn on haifa by default for the PA.
+ * configure: Rebuilt.
+ * pa.c (override_options): Accept -mschedule=7200 option.
+ (pa_adjust_cost): No longer need to scale costs for newer
+ processors.
+ * pa.h (enum processor_type): Add PROCESSOR_7200.
+ * pa.md: Revamp scheduling parameters to work better with
+ haifa. Add scheduling parameters for the 7200.
+
+ * haifa-sched.c (move_insn): Reemit notes for SCHED_GROUP_P
+ insns too.
+ (schedule_block): When adjusting basic_block_{head,end}, account
+ for movement of SCHED_GROUP_P insns too.
+
+ * haifa-sched.c (debug_dependencies): Fix thinko.
+
+ * Makefile.in (EXPECT, RUNTEST, RUNTESTFLAGS): Define.
+ (site.exp, check, check-g++, check-gcc): New targets.
+
+ * haifa-sched.c: Make lots of variables static.
+
+Tue Aug 19 07:18:34 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+
+ * expr.h, real.h: Finish prototyping.
+
+Mon Aug 18 21:49:02 1997 Jim Wilson <wilson@cygnus.com>
+
+ * reload.c (find_reloads): Add code to convert RELOAD_FOR_OPADDR_ADDR
+ reloads to RELOAD_FOR_OPERAND_ADDRESS reloads.
+ * reload1.c: Undo bugfix from Aug 11.
+
+Mon Aug 18 17:39:02 1997 Mike Meissner <meissner@cygnus.com>
+
+ * configure.in ({powerpc,rs6000}*-*-*, --with-cpu): Remove single
+ quotes around the name.
+ * configure: Regenerate.
+
+Mon Aug 18 13:46:47 1997 Jim Wilson <wilson@cygnus.com>
+
+ * Makefile.in (stmp-multilib-sub): Fix typo in last change.
+
+Thu Aug 7 10:33:13 1997 Manfred Hollstein <manfred@s-direktnet.de>
+
+ * Makefile.in (sub-makes): Pass the current value of LANGUAGES down
+ to sub-makes to avoid building more passes than the user might have
+ requested on the command line.
+
+Sun Aug 17 15:42:17 1997 Dave Love (d.love@dl.ac.uk)
+
+ * configure.in: Expurgate `broken_install' (install is
+ autoconfed).
+
+ * configure.lang: Substitute autoconfed ${INSTALL} (not currently
+ relevant).
+
+Sat Aug 16 01:08:12 1997 Jeffrey A Law (law@cygnus.com)
+
+ * loop.c (is_power_of_2, is_conditional_branch): Delete unused
+ functions and declarations.
+ (analyze_loop_iterations): Use condjump_p.
+ (insert_bct): Likewise. Use exact_log2.
+
+Fri Aug 15 23:48:32 1997 Jeffrey A Law (law@cygnus.com)
+
+ * haifa-sched.c (find_post_sched_live): Call FREE_REG_SET as needed.
+ (schedule_region): Likewise.
+ (schedule_insns): Likewise.
+
+ * PROJECTS: Update with Haifa stuff.
+
+Fri Aug 15 12:49:56 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Change the version string to look like:
+ egcs-2.90.00 970814 (gcc2-970802 experimental).
+
+ * loop.c (is_conditional_branch): Make definition match declaration.
+
+ * gcc.c: Take out experimental snapshot warning message.
+
+Fri Aug 15 13:43:39 1997 Michael Meissner <meissner@cygnus.com>
+
+ * haifa-sched.c (debug_dependencies): Use GET_NOTE_INSN_NAME to
+ print out the names of the notes. Print out the name of the insn
+ that is not a note, and not an {,CALL_,JUMP_}INSN.
+
+Wed Aug 13 17:32:38 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * expr.c (expand_expr, case TARGET_EXPR): Call mark_addressable
+ again for the slot after we give it RTL.
+
+Wed Aug 13 01:03:37 1997 Doug Evans <dje@canuck.cygnus.com>
+
+ * configure.in (haifa configury): Fix typo.
+ * configure: Regenerate.
+
+Tue Aug 12 10:20:36 1997 Jeffrey A Law (law@cygnus.com)
+
+ * version.c: Bump version to "gcc-3.0.0 970802 experimental".
+
+ * gcc.info*: Rebuilt.
+
+ * COPYING.g77, README.g77: New files.
+ * real.c (ereal_unto_float, ereal_unto_double): New functions.
+ * real.h (ereal_unto_float, ereal_unto_double): Declare them.
+ (REAL_VALUE_UNTO_TARGET_DOUBLE, REAL_VALUE_UNTO_TARGET_SINGLE): Define.
+
+Mon Aug 11 14:50:55 1997 Jeffrey A Law (law@cygnus.com)
+
+ * Integrate Haifa instruction scheduler.
+ * Makefile.in (ALL_CFLAGS): Add SCHED_CFLAGS. Prefix all references
+ to sched with $(SCHED_CFLAGS.
+ * configure.in: Handle --enable-haifa.
+ * configure: Rebuilt.
+ * flags.h: Add new flags for haifa instruction scheduler.
+ * genattrtab.c (expand_units): For haifa, don't subtract one
+ when computing blockage.
+ * toplev.h (flag_schedule_interblock): Haifa scheduler flag.
+ (flag_schedule_speculative): Ditto.
+ (flag_schedule_speculative_load): Ditto.
+ (flag_schedule_speculative_load_dangerous): Ditto.
+ (flag_schedule_reverse_before_reload): Ditto.
+ (flag_schedule_reverse_after_reload): Ditto.
+ (flag_branch_on_count_reg): Ditto.
+ (f_options): Add Haifa switches.
+ (main): Turn off some Haifa options if appropriate macro is
+ defined. Process Haifa switches.
+ * unroll.c (iteration_info): No longer static, since Haifa
+ scheduler uses it.
+ (unroll_loop): Inform HAIFA scheduler about loop unrolling factor.
+ * unroll.c (unroll_loop): Set loop_unroll_iter, loop_start_value.
+ * loop.h (loop_unroll_factor, loop_number): Add HAIFA decls.
+ * loop.h (loop_initial_value,loop_unroll_iter): New globals.
+ * loop.c (loop_optimize): If HAIFA is defined, allocate additional
+ storage for the Haifa scheduler.
+ (mark_loop_jump): If HAIFA defined, set LABEL_OUTSIDE_LOOP_P and
+ LABEL_NEXTREF.
+ (strength_reduce): If HAIFA and HAVE_decrement_and_branch_on_count
+ are defined, call analyze_loop_iterations and insert_bct to use
+ countdown loops.
+ (record_giv): Refine test for jumps out of loops if HAIFA is
+ defined.
+ (analyze_loop_iterations): New function to identify if we can use
+ a countdown loop.
+ (insert_bct): Insert countdown loop.
+ (instrument_loop_bct): Low level code to insert countdown loop.
+ (loop_number): Calculate UID of loop.
+ (indirect_jump_in_function_p): Return true if an indirect jump is
+ in the function.
+ (is_power_of_2): Return true if value is a power of 2.
+ (is_conditional_branch): Return true if insn is a conditional
+ jump.
+ (fix_bct_param): Process -fbct-{min,max}-N switches.
+ (check_bct_param): Return true if loop should be instrumented.
+ * loop.c (loop_initial_value,loop_unroll_iter): New globals.
+ (loop_optimize): Initialize.
+ (get_condition_for_loop): Ditto.
+ * loop.c (strength_reduce): Inside of code that uses #ifdef
+ HAVE_decrement_and_branch_on_count code, test it to make sure the
+ condition is true.
+ (instrument_loop_bct): Ditto.
+ * haifa-sched.c: New file.
+
+
+ * Integrate regmove pass.
+ * Makefile.in (OBJS): Add regmove.o
+ (regmove.o): Add dependencies.
+ * flow.c (find_use_as_address): No longer static.
+ * rtl.h (find_use_as_address): Declare.
+ * toplev.c (regmove_dump, flag_regmove): Define.
+ (f_options): Add -fregmove.
+ (regmove_dump_file, regmove_time): Define.
+ (fatal_insn): Close the regmove dump file.
+ (compile_file): Initialize regmove_time; open/close the regmove dump
+ file as needed. Print regmove time as needed.
+ (rest_of_compilation): Run regmove pass if requested, dump
+ RTL after regmove if requested.
+ (main): If -O2 or more, turn on regmove. Handle dump switches.
+ * regmove.c: New file.
+
+Mon Aug 11 14:15:02 1997 Jeffrey A Law (law@cygnus.com)
+
+ * Integrate tlink patch from jason@cygnus.com
+ * gcc.c (SWITCH_TAKES_ARG): Add 'V', 'B' and 'b'.
+ (process_command): Increment n_switches for them. Don't discard
+ their args. Validate them.
+ (main): Escape " marks when creating COLLECT_GCC_OPTIONS.
+ From Rohan Lenard.
+ (process_command): Set include_prefixes from COMPILER_PATH.
+ (main): Set COLLECT_GCC_OPTIONS sooner.
+ * confiugre.in: Link ../ld/ld.new to collect-ld rather than real-ld.
+ * tlink.c, hash.c, hash.h: New files.
+ * Makefile.in (USE_COLLECT2): Always use collect2.
+ (collect2): Depend on and link in hash.o and tlink.o.
+ (tlink.o, hash.o): Add dependencies.
+
+Mon Aug 11 10:04:49 1997 Jeffrey A Law (law@cygnus.com)
+
+ * Integrate alias analysis changes from jfc@mit.edu
+ * Makefile.in (OBJS): Add alias.o
+ (alias.o): Add dependencies.
+ * alias.c: New file.
+ * sched.c: Remove alias analysis code. It lives in alias.c now.
+ (sched_analyze_2): Add new arguments to true_dependence.
+ (schedule_insns): Always call init_alias_analysis.
+ * calls.c (expand_call): Note calls to malloc, calloc, and realloc;
+ mark return value from such functions as a pointer and keep track of
+ them for alias analysis. If a return value from a function is a
+ pointer, mark it as such.
+ * combine.c (distribute_notes): Handle REG_NOALIAS.
+ * cse.c (struct write_data): Delete. No longer needed.
+ (invalidate): Don't call set_nonvarying_address_components anymore.
+ Use true_dependence to decide if an entry should be removed from
+ the hash table.
+ (invalidate_memory): Remove WRITES argument, simplify appropriately.
+ Fix all callers.
+ (note_mem_written): Similarly for WRITE_PTR argument.
+ (invalidate_from_clobbers): Similarly for W argument.
+ (invalidate_for_call): Remove memory elements from the hash table.
+ (refers_to_mem_p, cse_rtx_addr_varies_p): Deleted.
+ (cse_rtx_varies_p): New function. Derived from old
+ cse_rtx_addr_varies_p.
+ (cse_insn): Remove WRITES_MEMORY and INIT variables and all references.
+ Don't call note_mem_written anymore. Stack pushes invalidate the stack
+ pointer if PUSH_ROUNDING is defined. No longer need to call
+ cse_rtx_addr_varies_p to decide if a MEM should be invalidated.
+ (skipped_writes_memory): Remove variable.
+ (invalidate_skipped_set): Simplify and wewrite to use invalidate_memory.
+ (invalidate_skipped_block): Simplify for new alias analysis code.
+ (cse_set_around_loop): Likewise.
+ (cse_main): Call init_alias_analysis.
+ * flags.h (flag_alias_check, flag_argument_noalias): Declare.
+ * toplev.c (flag_alias_check, flag_argument_noalias): Define.
+ (f_options): Add new alias checking arguments.
+ (main): Set flag_alias_check when optimizing.
+ * local_alloc (validate_equiv_mem_from_store): Add new arguments
+ to true_dependence.
+ (memref_referenced_p): Likewise.
+ * loop.c (NUM_STORES): Increase to 30.
+ (prescan_loop): Only non-constant calls set unknown_address_altered.
+ (invariant_p): Add new arguments to true_dependence.
+ (record_giv): Initialize unrolled and shared fields.
+ (emit_iv_add_mult): Call record_base_value as needed.
+ * loop.h (struct induction): Add unrolled and shared fields.
+ * unroll.c (unroll_loop): Call record_base_value as needed.
+ (copy_loop_body): Likewise.
+ (final_biv_value): Likewise.
+ (final_giv_value): Likewise.
+ (find_splittable_regs): Likewise. Only create one new pseudo
+ if we have multiple address GIVs that were combined with the same
+ dst_reg GIV. Note when a new register is created due to unrolling.
+ * rtl.c (reg_note_name): Add REG_NOALIAS.
+ * rtl.h (enum reg_note): Similarly.
+ (rtx_varies_p, may_trap_p, side_effects_p): Declare.
+ (volatile_refs_p, volatile_insn_p, remove_note): Likewise.
+ (note_stores, refers_to_regno_p, reg_overlap_mentioned_p): Likewise.
+ (true_dependence, read_dependence, anti_dependence): Likewise.
+ (output_dependence, init_alias_analysis, end_alias_analysis): Likewise.
+ (mark_user_reg, mark_reg_pointer): Likewise.
+
+
+ * Integrate reload bugfix from Wilon which enables the PA port
+ to bootstrap again.
+ * reload1.c (reload): Sum needs for both OPADDR_ADDR and
+ OPERAND_ADDRESS when computing how many registers an insn needs.
+ (reload_reg_free_p): OPADDR_ADDR and OPERAND_ADDRESS reloads do
+ conflict.
+ (reload_reg_free_before_p): Treat OPERAND_ADDRESS reloads just like
+ OPADDR_ADDR reload.
+ (reload_reg_reaches_end_p): For RELOAD_FOR_OPADDR_ADDR insns, registers
+ in reload_reg_use_in_op_addr do not reach the end.
+ do not reach the end.
+ (reloads_conflict): RELOAD_FOR_OPADDR_ADDR conflicts with
+ RELOAD_FOR_OPERAND_ADDRESS.
+
+Sun Aug 10 12:00:20 1997 Jeffrey A Law (law@cygnus.com)
+
+ * egcs project officially starts.
+
+Local Variables:
+add-log-time-format: current-time-string
+End:
diff --git a/contrib/gcc/LANGUAGES b/contrib/gcc/LANGUAGES
new file mode 100644
index 0000000..bce134c
--- /dev/null
+++ b/contrib/gcc/LANGUAGES
@@ -0,0 +1,79 @@
+Right now there is no documentation for the GCC tree -> rtl interfaces
+(or more generally the interfaces for adding new languages).
+
+Such documentation would be of great benefit to the project. Until such
+time as we can formally start documenting the interface this file will
+serve as a repository for information on these interface and any incompatable
+changes we've made.
+
+Jun 10, 1998:
+ The interface to lang_decode_option has changed. It now uses and argc/argv
+ interface to allow for options that use more than one input string. The new
+ declaration is: int lang_decode_option (int argc, char** argv). It now
+ returns the number of input strings processed, or 0 if the option is
+ unknown.
+
+Jun 7, 1998:
+ Front-ends must now define lang_init_options. It is safe for this
+ function to do nothing. See c-lang.c.
+
+Apr 21, 1998:
+ Front ends which link with c-common or other files from the C/C++
+ front-ends may need to handle TI types. Look for references to
+ [unsigned]int_DI_type_node in your front end. If you have references
+ to these variables, you'll need up update the front end.
+
+ To update the front end you must mirror all the code which currently
+ deals with intDI_type_node to also handle intTI_type_node.
+
+
+Apr 7, 1998:
+ The interface between toplev.c and the language front ends for opening the
+ source file has changed:
+
+ o init_lex() has been renamed to init_parse (char *filename) where filename
+ is the name of the source file.
+ o The code in toplev.c which opened the source file should be moved to
+ the new init_parse function.
+ o toplev.c now calls finish_parse() instead of closing the source file
+ using fclose(). This should now be done in finish_parse, if necessary.
+
+Apr 1, 1998:
+ Front-ends must now define lang_print_xnode. It is safe for this
+ function to do nothing. See c-lang.c.
+
+Feb 1, 1998:
+
+ GCC used to store structure sizes & offsets to elements as bitsize
+ quantities. This causes problems because a structure can only be
+ (target memsize / 8) bytes long (this may effect arrays too). This
+ is particularly problematical on machines with small address spaces.
+
+ So:
+
+ All trees that represent sizes in bits should have a TREE_TYPE of
+ bitsizetype (rather than sizetype).
+
+ Accordingly, when such values are computed / initialized, care has to
+ be takes to use / compute the proper type.
+
+ When a size in bits is converted into a size in bytes, which is expressed
+ in trees, care should be taken to change the tree's type again to sizetype.
+
+ We've updated C, C++, Fortran & Objective-C to work with the new
+ scheme. Other languages will need to be updated accordingly.
+ Contact amylaar@cygnus.com for additional information.
+
+?? 1997:
+
+ In an effort to decrease cache thrashing and useless loads we've changed the
+ third argument to the DEFTREECODE macro to be a single char. This will
+ effect languages that defined their own tree codes (usually in a .def file).
+
+ Old way:
+
+ DEFTREECODE (CLASS_METHOD_DECL, "class_method_decl", "d", 0)
+
+ New way:
+
+ DEFTREECODE (CLASS_METHOD_DECL, "class_method_decl", 'd', 0)
diff --git a/contrib/gcc/Makefile.in b/contrib/gcc/Makefile.in
index 7ab05ff..15a789e 100644
--- a/contrib/gcc/Makefile.in
+++ b/contrib/gcc/Makefile.in
@@ -1,5 +1,5 @@
# Makefile for GNU C compiler.
-# Copyright (C) 1987, 88, 90-94, 1995 Free Software Foundation, Inc.
+# Copyright (C) 1987, 88, 90-97, 1998 Free Software Foundation, Inc.
#This file is part of GNU CC.
@@ -26,16 +26,24 @@
# Suppress smart makes who think they know how to automake Yacc files
.y.c:
+# Directory where sources are, from where we are.
+srcdir = @srcdir@
+VPATH = @srcdir@
+
# Variables that exist for you to override.
# See below for how to change them for certain systems.
# List of language subdirectories.
# This is overridden by configure.
-SUBDIRS =
+SUBDIRS =@subdirs@
# Selection of languages to be made.
# This is overridden by configure.
-LANGUAGES = c objective-c proto
+LANGUAGES = c proto gcov$(exeext) @all_languages@
+
+# Selection of languages to be made during stage1 build.
+# This is overridden by configure.
+BOOT_LANGUAGES = c @all_boot_languages@
ALLOCA =
ALLOCA_FLAGS =
@@ -45,10 +53,17 @@ ALLOCA_FINISH = true
# CFLAGS is for the user to override to, e.g., do a bootstrap with -O2.
# BOOT_CFLAGS is the value of CFLAGS to pass
# to the stage2 and stage3 compilations
+# WARN_CFLAGS are the warning flags to pass to stage2 and stage3. It is
+# separate from BOOT_CFLAGS because people tend to override optimization
+# flags and we'd like them to still have warnings turned on. They are free
+# to explicitly turn warnings off if they wish.
# XCFLAGS is used for most compilations but not when using the GCC just built.
+# TCFLAGS is used for compilations with the GCC just built.
XCFLAGS =
+TCFLAGS =
CFLAGS = -g
-BOOT_CFLAGS = -O $(CFLAGS)
+BOOT_CFLAGS = -O2 $(CFLAGS)
+WARN_CFLAGS =
# These exists to be overridden by the x-* and t-* files, respectively.
X_CFLAGS =
T_CFLAGS =
@@ -56,24 +71,37 @@ T_CFLAGS =
X_CPPFLAGS =
T_CPPFLAGS =
-CC = cc
-BISON = bison
+CC = @CC@
+# srcdir might be a relative pathname which won't be valid in a subdirectory,
+# so we must use objdir/srcdir instead to make it safe. objdir is always
+# a full pathname.
+BISON = `if [ -f $(objdir)/../bison/bison ] ; then case $(srcdir) in \
+ /*) echo $(objdir)/../bison/bison -L $(srcdir)/../bison/ ;; \
+ *) echo $(objdir)/../bison/bison -L $(objdir)/$(srcdir)/../bison/ ;; \
+ esac else echo bison ; fi`
BISONFLAGS =
-LEX = flex
+LEX = `if [ -f $(objdir)/../flex/flex ] ; then echo $(objdir)/../flex/flex ; else echo flex ; fi`
LEXFLAGS =
AR = ar
-OLDAR_FLAGS = qc
AR_FLAGS = rc
+LN = @symbolic_link@
+DLLTOOL = dlltool
SHELL = /bin/sh
# on sysV, define this as cp.
-INSTALL = install -c
+INSTALL = @INSTALL@
+# Some systems may be missing symbolic links, regular links, or both.
+# Allow configure to check this and use "ln -s", "ln", or "cp" as appropriate.
+LN=@LN@
+LN_S=@LN_S@
# These permit overriding just for certain files.
-INSTALL_PROGRAM = $(INSTALL)
-INSTALL_DATA = $(INSTALL)
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
MAKEINFO = makeinfo
+MAKEINFOFLAGS =
TEXI2DVI = texi2dvi
# For GNUmake: let us decide what gets passed to recursive makes.
MAKEOVERRIDES =
+@SET_MAKE@
# Define this as & to perform parallel make on a Sequent.
# Note that this has some bugs, and it seems currently necessary
@@ -97,10 +125,11 @@ CCLIBFLAGS = -O
# Version of ar to use when compiling libgcc1.a.
OLDAR = ar
+OLDAR_FLAGS = qc
# Target to use when installing include directory. Either
# install-headers-tar or install-headers-cpio.
-INSTALL_HEADERS_DIR = install-headers-tar
+INSTALL_HEADERS_DIR = @build_install_headers_dir@
# Header files that are made available under the same name
# to programs compiled with GCC.
@@ -108,11 +137,15 @@ USER_H = $(srcdir)/ginclude/stdarg.h $(srcdir)/ginclude/stddef.h \
$(srcdir)/ginclude/varargs.h $(srcdir)/ginclude/va-alpha.h \
$(srcdir)/ginclude/va-h8300.h $(srcdir)/ginclude/va-i860.h \
$(srcdir)/ginclude/va-i960.h $(srcdir)/ginclude/va-mips.h \
- $(srcdir)/ginclude/va-m88k.h $(srcdir)/ginclude/va-pa.h \
+ $(srcdir)/ginclude/va-m88k.h $(srcdir)/ginclude/va-mn10200.h \
+ $(srcdir)/ginclude/va-mn10300.h $(srcdir)/ginclude/va-pa.h \
$(srcdir)/ginclude/va-pyr.h $(srcdir)/ginclude/va-sparc.h \
$(srcdir)/ginclude/va-clipper.h $(srcdir)/ginclude/va-spur.h \
+ $(srcdir)/ginclude/va-m32r.h $(srcdir)/ginclude/va-sh.h \
+ $(srcdir)/ginclude/va-v850.h $(srcdir)/ginclude/va-arc.h \
$(srcdir)/ginclude/iso646.h $(srcdir)/ginclude/va-ppc.h \
- $(srcdir)/ginclude/proto.h $(EXTRA_HEADERS)
+ $(EXTRA_HEADERS) $(LANG_EXTRA_HEADERS) \
+ $(srcdir)/ginclude/proto.h $(srcdir)/ginclude/stdbool.h
# Target to use whe installing assert.h. Some systems may
# want to set this empty.
@@ -126,27 +159,62 @@ GCC_FOR_TARGET = ./xgcc -B./
# This is used instead of ALL_CFLAGS when compiling with GCC_FOR_TARGET.
# It omits XCFLAGS, and specifies -B./.
# It also specifies -I./include to find, e.g., stddef.h.
-GCC_CFLAGS=$(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) -I./include
-
-# Special flags for compiling enquire.
-# We disable optimization to make floating point more reliable.
-ENQUIRE_CFLAGS = -DNO_MEM -DNO_LONG_DOUBLE_IO -O0
-ENQUIRE_LDFLAGS = $(LDFLAGS)
+GCC_CFLAGS=$(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) -I./include $(TCFLAGS)
# Sed command to transform gcc to installed name. Overwritten by configure.
-program_transform_name = -e s,x,x,
-program_transform_cross_name = -e s,^,$(target)-,
+program_transform_name = @program_transform_name@
+program_transform_cross_name = s,^,$(target_alias)-,
+
+build_canonical = @build_canonical@
+host_canonical = @host_canonical@
# Tools to use when building a cross-compiler.
# These are used because `configure' appends `cross-make'
# to the makefile when making a cross-compiler.
-TARGET_TOOLPREFIX = $(tooldir)/bin/
-AR_FOR_TARGET = $(TARGET_TOOLPREFIX)ar
+# Use the tools from the build tree, if they are available.
+
+# objdir is set by configure.
+objdir = @objdir@
+
+AR_FOR_TARGET = ` \
+ if [ -f $(objdir)/../binutils/ar ] ; then \
+ echo $(objdir)/../binutils/ar ; \
+ else \
+ if [ "$(host_canonical)" = "$(target)" ] ; then \
+ echo ar; \
+ else \
+ t='$(program_transform_name)'; echo ar | sed -e $$t ; \
+ fi; \
+ fi`
AR_FOR_TARGET_FLAGS = rc
-RANLIB_FOR_TARGET = $(TARGET_TOOLPREFIX)ranlib
-RANLIB_TEST_FOR_TARGET = [ -f $(TARGET_TOOLPREFIX)ranlib ]
-
+RANLIB_FOR_TARGET = ` \
+ if [ -f $(objdir)/../binutils/ranlib ] ; then \
+ echo $(objdir)/../binutils/ranlib ; \
+ else \
+ if [ "$(host_canonical)" = "$(target)" ] ; then \
+ echo ranlib; \
+ else \
+ t='$(program_transform_name)'; echo ranlib | sed -e $$t ; \
+ fi; \
+ fi`
+RANLIB_TEST_FOR_TARGET = \
+ [ -f $(RANLIB_FOR_TARGET) ] \
+ || ( [ "$(host_canonical)" = "$(target)" ] \
+ && [ -f /usr/bin/ranlib -o -f /bin/ranlib ] )
+
+# We always act like a cross-compiler, even when we're
+# compiling native. This is because we want to use our own tools if
+# we can. We don't just set RANLIB to a complicated expression,
+# because the top level Makefile.in might override RANLIB_FOR_TARGET.
+# These are from the FSF file "cross-make".
+AR = $(AR_FOR_TARGET)
+AR_FLAGS = $(AR_FOR_TARGET_FLAGS)
+OLDAR = $(AR_FOR_TARGET)
+OLDAR_FLAGS = $(AR_FOR_TARGET_FLAGS)
+RANLIB = $(RANLIB_FOR_TARGET)
+RANLIB_TEST = $(RANLIB_TEST_FOR_TARGET)
+
# Dir to search for system headers. Overridden by cross-make.
SYSTEM_HEADER_DIR = /usr/include
@@ -163,57 +231,68 @@ LIMITS_H_TEST = [ -f $(SYSTEM_HEADER_DIR)/limits.h ]
PREMADE_ATTRTAB_MD = Makefile # Guaranteed not to cmp equal to md.
PREMADE_ATTRTAB =
-target= ... `configure' substitutes actual target name here.
-xmake_file= ... `configure' substitutes actual x- file name here.
-tmake_file= ... `configure' substitutes actual t- file name here.
-out_file= ... `configure' substitutes actual out file name here.
-out_object_file= ... `configure' substitutes actual out object file name here.
-md_file= ... `configure' substitutes actual md file name here.
-tm_file= ... `configure' substitutes actual tm file name here.
-build_xm_file= ... `configure' substitutes actual build xm- file name here.
-host_xm_file= ... `configure' substitutes actual host xm- file name here.
-lang_specs_files= ... `configure' substitutes actual lang spec file names here.
-lang_options_files= ... `configure' puts actual lang options file names here.
-version=`sed -e 's/.*\"\([^ \"]*\)[ \"].*/\1/' < $(srcdir)/version.c`
+target=@target@
+target_alias=@target_alias@
+xmake_file=@dep_host_xmake_file@
+tmake_file=@dep_tmake_file@
+out_file=$(srcdir)/config/@out_file@
+out_object_file=@out_object_file@
+md_file=$(srcdir)/config/@md_file@
+tm_file=@tm_file_list@
+build_xm_file=@build_xm_file_list@
+host_xm_file=@host_xm_file_list@
+lang_specs_files=@lang_specs_files@
+lang_options_files=@lang_options_files@
+GCC_THREAD_FILE=@thread_file@
+GTHREAD_FLAGS=@gthread_flags@
+# Be prepared for gcc2 merges.
+gcc_version=@gcc_version@
+gcc_version_trigger=@gcc_version_trigger@
+version=$(gcc_version)
mainversion=`sed -e 's/.*\"\([0-9]*\.[0-9]*\).*/\1/' < $(srcdir)/version.c`
-# Directory where sources are, from where we are.
-srcdir = .
# Common prefix for installation directories.
# NOTE: This directory must exist when you start installation.
-prefix = /usr/local
+prefix = @prefix@
# Directory in which to put localized header files. On the systems with
# gcc as the native cc, `local_prefix' may not be `prefix' which is
# `/usr'.
# NOTE: local_prefix *should not* default from prefix.
-local_prefix = /usr/local
+local_prefix = @local_prefix@
# Directory in which to put host dependent programs and libraries
-exec_prefix = $(prefix)
+exec_prefix = @exec_prefix@
# Directory in which to put the executable for the command `gcc'
-bindir = $(exec_prefix)/bin
+bindir = @bindir@
# Directory in which to put the directories used by the compiler.
-libdir = $(exec_prefix)/lib
+libdir = @libdir@
# Directory in which the compiler finds executables, libraries, etc.
-libsubdir = $(libdir)/gcc-lib/$(target)/$(version)
+libsubdir = $(libdir)/gcc-lib/$(target_alias)/$(version)
# Directory in which the compiler finds g++ includes.
-gxx_include_dir= $(libdir)/g++-include
+gxx_include_dir= @gxx_include_dir@
+# Directory in which the old g++ header files may be found.
+# The reason we use $(libdir)/g++-include rather than using libsubdir
+# is for compatibility with older versions of libg++.
+old_gxx_include_dir= $(libdir)/g++-include
# Directory to search for site-specific includes.
includedir = $(local_prefix)/include
# assertdir is overridden in cross-make.
# (But this currently agrees with what is in cross-make.)
assertdir = $(tooldir)/include
# where the info files go
-infodir = $(prefix)/info
+infodir = @infodir@
+# Where cpp should go besides $prefix/bin if necessary
+cpp_install_dir = @cpp_install_dir@
# Extension (if any) to put in installed man-page filename.
manext = .1
objext = .o
-exeext =
+exeext = @host_exeext@
+build_exeext = @build_exeext@
# Directory in which to put man pages.
-mandir = $(prefix)/man/man1
+mandir = @mandir@/man1
# Directory in which to find other cross-compilation tools and headers.
# Used in install-cross.
-tooldir = $(exec_prefix)/$(target)
+tooldir = $(exec_prefix)/$(target_alias)
# Dir for temp files.
tmpdir = /tmp
@@ -224,6 +303,10 @@ CLIB=
# system library.
OBSTACK=obstack.o
+# Configure will set these if you need vfprintf and possibly _doprnt support.
+VFPRINTF=@vfprintf@
+DOPRINT=@doprint@
+
# Specify the rule for actually making libgcc.a,
LIBGCC = libgcc.a
# and the rule for installing it.
@@ -245,7 +328,9 @@ LIBGCC2 = libgcc2.a
# -g1 causes output of debug info only for file-scope entities.
# we use this here because that should be enough, and also
# so that -g1 will be tested.
-LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(TARGET_LIBGCC2_CFLAGS) -g1
+#
+LIBGCC2_DEBUG_CFLAGS = -g1
+LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(TARGET_LIBGCC2_CFLAGS) $(LIBGCC2_DEBUG_CFLAGS) $(GTHREAD_FLAGS) -DIN_LIBGCC2 -D__GCC_FLOAT_NOT_NEEDED @inhibit_libc@
# Additional options to use when compiling libgcc2.a.
# Some targets override this to -Iinclude
@@ -258,41 +343,39 @@ TARGET_LIBGCC2_CFLAGS =
# Some targets override this to stmp-int-hdrs
LIBGCC2_DEPS =
-# Enquire target (This is a variable so that a target can choose not to
-# build it.)
-ENQUIRE = enquire
-
# libgcc1-test target (must also be overridable for a target)
LIBGCC1_TEST = libgcc1-test
# List of extra executables that should be compiled for this target machine
# that are used for compiling from source code to object code.
# The rules for compiling them should be in the t-* file for the machine.
-EXTRA_PASSES =
+EXTRA_PASSES =@extra_passes@
# Like EXTRA_PASSES, but these are used when linking.
-EXTRA_PROGRAMS =
+EXTRA_PROGRAMS = @extra_programs@
# List of extra object files that should be compiled for this target machine.
# The rules for compiling them should be in the t-* file for the machine.
-EXTRA_PARTS =
+EXTRA_PARTS = @extra_parts@
# List of extra object files that should be compiled and linked with
# compiler proper (cc1, cc1obj, cc1plus).
-EXTRA_OBJS =
+EXTRA_OBJS = @extra_objs@
# List of extra object files that should be compiled and linked with
# the gcc driver.
-EXTRA_GCC_OBJS =
+EXTRA_GCC_OBJS =@host_extra_gcc_objs@
# List of additional header files to install.
# Often this is edited directly by `configure'.
-EXTRA_HEADERS =
+EXTRA_HEADERS =@extra_headers_list@
-# Set this to `ld' to enable use of collect2.
-# USE_COLLECT2 =
+# Set this to `collect2' to enable use of collect2.
+USE_COLLECT2 = @will_use_collect2@
+MAYBE_USE_COLLECT2 = @maybe_use_collect2@
# It is convenient for configure to add the assignment at the beginning,
# so don't override it here.
+USE_COLLECT2 = collect2$(exeext)
# List of extra C and assembler files to add to libgcc1.a.
# Assembler files should have names ending in `.asm'.
@@ -302,8 +385,17 @@ LIB1FUNCS_EXTRA =
# Assembler files should have names ending in `.asm'.
LIB2FUNCS_EXTRA =
+# Handle cpp installation.
+INSTALL_CPP=
+UNINSTALL_CPP=
+
# Default float.h source to use for cross-compiler.
-CROSS_FLOAT_H=float.h-cross
+# This is overridden by configure.
+CROSS_FLOAT_H=$(srcdir)/config/float-@float_format@.h
+
+# We do not try to build float.h anymore. Let configure select the
+# appropriate pre-built float.h file for the target.
+FLOAT_H=$(srcdir)/config/float-@float_format@.h
# Program to convert libraries.
LIBCONVERT =
@@ -316,7 +408,7 @@ TAROUTOPTS = xpBf
# Select which version of fixincludes to use (I.E. regular versus SVR4)
# This value is overridden directly by configure.
-FIXINCLUDES=fixincludes
+FIXINCLUDES = @fixincludes@
# Additional directories of header files to run fixincludes on.
# These should be directories searched automatically by default
@@ -326,9 +418,13 @@ FIXINCLUDES=fixincludes
# On most systems, this is empty.
OTHER_FIXINCLUDES_DIRS=
+# A list of all the language-specific executables.
+# This is overridden by configure.
+COMPILERS = cc1$(exeext) @all_compilers@
+
# List of things which should already be built whenever we try to use xgcc
# to compile anything (without linking).
-GCC_PASSES=xgcc cc1 cpp $(EXTRA_PASSES)
+GCC_PASSES=xgcc$(exeext) cc1$(exeext) cpp$(exeext) $(EXTRA_PASSES)
# List of things which should already be built whenever we try to use xgcc
# to link anything.
@@ -358,12 +454,18 @@ HOST_CPPFLAGS=$(ALL_CPPFLAGS)
HOST_ALLOCA=$(ALLOCA)
HOST_MALLOC=$(MALLOC)
HOST_OBSTACK=$(OBSTACK)
+HOST_VFPRINTF=$(VFPRINTF)
+HOST_DOPRINT=$(DOPRINT)
# Actual name to use when installing a native compiler.
-GCC_INSTALL_NAME = `t='$(program_transform_name)'; echo gcc | sed $$t`
+GCC_INSTALL_NAME = `t='$(program_transform_name)'; echo gcc | sed -e $$t`
+PROTOIZE_INSTALL_NAME = `t='$(program_transform_name)'; echo protoize | sed -e $$t`
+UNPROTOIZE_INSTALL_NAME = `t='$(program_transform_name)'; echo unprotoize | sed -e $$t`
# Actual name to use when installing a cross-compiler.
-GCC_CROSS_NAME = `t='$(program_transform_cross_name)'; echo gcc | sed $$t`
+GCC_CROSS_NAME = `t='$(program_transform_cross_name)'; echo gcc | sed -e $$t`
+PROTOIZE_CROSS_NAME = `t='$(program_transform_cross_name)'; echo protoize | sed -e $$t`
+UNPROTOIZE_CROSS_NAME = `t='$(program_transform_cross_name)'; echo unprotoize | sed -e $$t`
# Choose the real default target.
ALL=all.internal
@@ -371,8 +473,15 @@ ALL=all.internal
# Choose the real install target.
INSTALL_TARGET=install-normal
-# Source for float.h. Overridden by cross-make.
-FLOAT_H=float.h-nat
+# Setup the testing framework, if you have one
+EXPECT = `if [ -f $${rootme}/../expect/expect ] ; then \
+ echo $${rootme}/../expect/expect ; \
+ else echo expect ; fi`
+
+RUNTEST = `if [ -f $${srcdir}/../dejagnu/runtest ] ; then \
+ echo $${srcdir}/../dejagnu/runtest ; \
+ else echo runtest; fi`
+RUNTESTFLAGS =
# Extra symbols for fixproto to define when parsing headers.
FIXPROTO_DEFINES =
@@ -380,6 +489,12 @@ FIXPROTO_DEFINES =
# Extra flags to use when compiling crt{begin,end}.o.
CRTSTUFF_T_CFLAGS =
+# Extra flags to use when compiling [m]crt0.o.
+CRT0STUFF_T_CFLAGS =
+
+# "t" or nothing, for building multilibbed versions of, say, crtbegin.o.
+T =
+
# End of variables for you to override.
# Definition of `all' is here so that new rules inserted by sed
@@ -393,50 +508,61 @@ all: all.indirect
# sed inserts variable overrides after the following line.
####target overrides
+@target_overrides@
+
####host overrides
+@host_overrides@
+
####cross overrides
+@cross_defines@
+@cross_overrides@
+
####build overrides
-
+@build_overrides@
+#
# Now figure out from those variables how to compile and link.
all.indirect: $(ALL)
# IN_GCC tells obstack.h that we are using gcc's <stddef.h> file.
# ??? IN_GCC should be obsolete now.
-INTERNAL_CFLAGS = $(CROSS) -DIN_GCC
+INTERNAL_CFLAGS = $(CROSS) -DIN_GCC @extra_c_flags@
# This is the variable actually used when we compile.
-ALL_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS)
+ALL_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS) \
+ @DEFS@ $(SCHED_CFLAGS)
# Likewise.
ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS)
# Even if ALLOCA is set, don't use it if compiling with GCC.
-USE_ALLOCA= ` case "${CC}" in "${OLDCC}") echo "${ALLOCA}" ;; esac `
-USE_HOST_ALLOCA= ` case "${HOST_CC}"@"${HOST_ALLOCA}" in "${OLDCC}"@?*) echo ${HOST_PREFIX}${HOST_ALLOCA} ;; esac `
+USE_ALLOCA= ${ALLOCA}
+USE_HOST_ALLOCA= ` case "${HOST_ALLOCA}" in ?*) echo ${HOST_PREFIX}${HOST_ALLOCA} ;; esac `
USE_HOST_MALLOC= ` case "${HOST_MALLOC}" in ?*) echo ${HOST_PREFIX}${HOST_MALLOC} ;; esac `
USE_HOST_OBSTACK= ` case "${HOST_OBSTACK}" in ?*) echo ${HOST_PREFIX}${HOST_OBSTACK} ;; esac `
+USE_HOST_VFPRINTF= ` case "${HOST_VFPRINTF}" in ?*) echo ${HOST_PREFIX}${HOST_VFPRINTF} ;; esac `
+USE_HOST_DOPRINT= ` case "${HOST_DOPRINT}" in ?*) echo ${HOST_PREFIX}${HOST_DOPRINT} ;; esac `
# Dependency on obstack, alloca, malloc or whatever library facilities
# are not installed in the system libraries.
# We don't use USE_ALLOCA because backquote expansion doesn't work in deps.
-LIBDEPS= $(OBSTACK) $(ALLOCA) $(MALLOC)
+LIBDEPS= $(OBSTACK) $(ALLOCA) $(MALLOC) $(VFPRINTF) $(DOPRINT)
# Likewise, for use in the tools that must run on this machine
# even if we are cross-building GCC.
# We don't use USE_ALLOCA because backquote expansion doesn't work in deps.
-HOST_LIBDEPS= $(HOST_PREFIX)$(HOST_OBSTACK) $(HOST_PREFIX)$(HOST_ALLOCA) $(HOST_PREFIX)$(HOST_MALLOC)
+HOST_LIBDEPS= $(HOST_PREFIX)$(HOST_OBSTACK) $(HOST_PREFIX)$(HOST_ALLOCA) $(HOST_PREFIX)$(HOST_MALLOC) $(HOST_PREFIX)$(HOST_VFPRINTF) $(HOST_PREFIX)$(HOST_DOPRINT)
# How to link with both our special library facilities
# and the system's installed libraries.
-LIBS = $(OBSTACK) $(USE_ALLOCA) $(MALLOC) $(CLIB)
+LIBS = $(OBSTACK) $(USE_ALLOCA) $(MALLOC) $(VFPRINTF) $(DOPRINT) $(CLIB)
# Likewise, for use in the tools that must run on this machine
# even if we are cross-building GCC.
HOST_LIBS = $(USE_HOST_OBSTACK) $(USE_HOST_ALLOCA) $(USE_HOST_MALLOC) \
- $(HOST_CLIB)
+ $(USE_HOST_VFPRINTF) $(USE_HOST_DOPRINT) $(HOST_CLIB)
-HOST_RTL = $(HOST_PREFIX)rtl.o
+HOST_RTL = $(HOST_PREFIX)rtl.o $(HOST_PREFIX)bitmap.o
HOST_RTLANAL = $(HOST_PREFIX)rtlanal.o
HOST_PRINT = $(HOST_PREFIX)print-rtl.o
@@ -453,14 +579,16 @@ INCLUDES = -I. -I$(srcdir) -I$(srcdir)/config
# This tells GNU make version 3 not to export all the variables
# defined in this file into the environment.
.NOEXPORT:
-
+#
# Support for additional languages (other than c and objc).
# ??? objc can be supported this way too (leave for later).
# These next lines are overridden by configure.
-LANG_MAKEFILES =
-LANG_STAGESTUFF =
-LANG_DIFF_EXCLUDES =
+LANG_MAKEFILES = @all_lang_makefiles@
+LANG_STAGESTUFF = @all_stagestuff@
+LANG_DIFF_EXCLUDES = @all_diff_excludes@
+LANG_LIB2FUNCS = @all_lib2funcs@
+LANG_EXTRA_HEADERS = @all_headers@
# Flags to pass to recursive makes.
# CC is set by configure. Hosts without symlinks need special handling
@@ -468,88 +596,88 @@ LANG_DIFF_EXCLUDES =
# subdirectories.
# ??? The choices here will need some experimenting with.
FLAGS_TO_PASS = \
- "AR_FLAGS=$(AR_FLAGS)" \
+ "AR_FLAGS=$(AR_FOR_TARGET_FLAGS)" \
"AR_FOR_TARGET=$(AR_FOR_TARGET)" \
"BISON=$(BISON)" \
"BISONFLAGS=$(BISONFLAGS)" \
- "CC=set-by-configure" \
+ "CC=@cc_set_by_configure@" \
"CFLAGS=$(CFLAGS)" \
+ "CLIB=$(CLIB)" \
"GCC_FOR_TARGET=$(GCC_FOR_TARGET)" \
"LDFLAGS=$(LDFLAGS)" \
"LEX=$(LEX)" \
"LEXFLAGS=$(LEXFLAGS)" \
+ "LN=$(LN)" \
+ "LN_S=$(LN_S)" \
"MAKEINFO=$(MAKEINFO)" \
"MAKEINFOFLAGS=$(MAKEINFOFLAGS)" \
"RANLIB_FOR_TARGET=$(RANLIB_FOR_TARGET)" \
"RANLIB_TEST_FOR_TARGET=$(RANLIB_TEST_FOR_TARGET)" \
"SHELL=$(SHELL)" \
+ "STAGE_PREFIX=@stage_prefix_set_by_configure@" \
"exeext=$(exeext)" \
+ "build_exeext=$(build_exeext)" \
"objext=$(objext)" \
"exec_prefix=$(exec_prefix)" \
"prefix=$(prefix)" \
+ "local_prefix=$(local_prefix)" \
+ "gxx_include_dir=$(gxx_include_dir)" \
"tooldir=$(tooldir)" \
"bindir=$(bindir)" \
"libsubdir=$(libsubdir)"
-
+#
# Lists of files for various purposes.
-# A list of all the language-specific executables.
-# This is overridden by configure.
-COMPILERS = cc1$(exeext) cc1obj$(exeext)
+# Language-specific object files for C and Objective C.
+C_AND_OBJC_OBJS = c-lex.o c-pragma.o c-decl.o c-typeck.o c-convert.o \
+ c-aux-info.o c-common.o c-iterate.o @extra_c_objs@
# Language-specific object files for C.
-C_OBJS = c-parse.o c-lang.o c-lex.o c-pragma.o \
- c-decl.o c-typeck.o c-convert.o c-aux-info.o c-common.o c-iterate.o
-
-# Language-specific object files for Objective C.
-OBJC_OBJS = objc-parse.o objc-act.o c-lex.o c-pragma.o \
- c-decl.o c-typeck.o c-convert.o c-aux-info.o c-common.o c-iterate.o
+C_OBJS = c-parse.o c-lang.o $(C_AND_OBJC_OBJS)
-# Files specific to the C interpreter bytecode compiler(s).
-BC_OBJS = bc-emit.o bc-optab.o
-
-# Bytecode header files constructed at build time; vmsconfig.com wants this.
-BC_ALL = bc-arity.h bc-opcode.h bc-opname.h
+SCHED_PREFIX = @sched_prefix@
+SCHED_CFLAGS = @sched_cflags@
# Language-independent object files.
OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \
- function.o stmt.o expr.o calls.o expmed.o explow.o optabs.o varasm.o \
- rtl.o print-rtl.o rtlanal.o emit-rtl.o real.o \
- dbxout.o sdbout.o dwarfout.o xcoffout.o \
- integrate.o jump.o cse.o loop.o unroll.o flow.o stupid.o combine.o \
- regclass.o local-alloc.o global.o reload.o reload1.o caller-save.o \
- insn-peep.o reorg.o sched.o final.o recog.o reg-stack.o \
+ function.o stmt.o except.o expr.o calls.o expmed.o explow.o optabs.o \
+ varasm.o rtl.o print-rtl.o rtlanal.o emit-rtl.o genrtl.o real.o regmove.o \
+ dbxout.o sdbout.o dwarfout.o dwarf2out.o xcoffout.o bitmap.o alias.o \
+ integrate.o jump.o cse.o loop.o unroll.o flow.o stupid.o combine.o varray.o \
+ regclass.o local-alloc.o global.o reload.o reload1.o caller-save.o gcse.o \
+ insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \
insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o \
- insn-attrtab.o $(out_object_file) getpwd.o convert.o $(EXTRA_OBJS)
+ profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \
+ dyn-string.o
# GEN files are listed separately, so they can be built before doing parallel
# makes for cc1 or cc1plus. Otherwise sequent parallel make attempts to load
# them before rtl.o is compiled.
-GEN= genemit genoutput genrecog genextract genflags gencodes genconfig genpeep
+GEN= genemit genoutput genrecog genextract genflags gencodes genconfig \
+ genpeep gengenrtl gencheck
-CCCP=cccp
-# Uncomment this line if you want to use cppmain (w/cpplib) as cpp.
-#CCCP=cppmain
+CCCP=@cpp_main@
# Files to be copied away after each stage in building.
STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \
insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \
- insn-attr.h insn-attrtab.c insn-opinit.c \
- stamp-flags stamp-config stamp-codes \
- stamp-output stamp-recog stamp-emit stamp-extract stamp-peep \
- stamp-attr stamp-attrtab stamp-opinit stamp-proto stamp-crt stamp-crtS \
- genemit$(exeext) genoutput$(exeext) genrecog$(exeext) genextract$(exeext) \
- genflags$(exeext) gencodes$(exeext) genconfig$(exeext) genpeep$(exeext) \
- genattrtab$(exeext) genattr$(exeext) genopinit$(exeext) \
- $(BC_ALL) \
- stamp-bcarity stamp-bcopcode stamp-bcopname \
- bi-arity$(exeext) bi-opcode$(exeext) bi-opname$(exeext) \
- $(GCC_PASSES) $(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) \
+ insn-attr.h insn-attrtab.c insn-opinit.c genrtl.c genrtl.h tree-check.h \
+ s-flags s-config s-codes s-mlib s-under\
+ s-output s-recog s-emit s-extract s-peep s-check \
+ s-attr s-attrtab s-opinit s-crt s-crtS s-crt0 \
+ genemit$(build_exeext) genoutput$(build_exeext) genrecog$(build_exeext) \
+ genextract$(build_exeext) genflags$(build_exeext) gencodes$(build_exeext) \
+ genconfig$(build_exeext) genpeep$(build_exeext) genattrtab$(build_exeext) \
+ genattr$(build_exeext) genopinit$(build_exeext) gengenrtl$(build_exeext) \
+ gencheck$(build_exeext) \
+ xgcc$(exeext) cc1$(exeext) cpp$(exeext) $(EXTRA_PASSES) \
+ $(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) \
$(CCCP)$(exeext) cc1obj$(exeext) enquire$(exeext) \
protoize$(exeext) unprotoize$(exeext) \
specs collect2$(exeext) $(USE_COLLECT2) underscore.c \
+ gcov$(exeext) *.bp \
*.greg *.lreg *.combine *.flow *.cse *.jump *.rtl *.tree *.loop \
- *.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack \
+ *.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack *.gcse \
*.[si] \
$(LANG_STAGESTUFF)
@@ -569,9 +697,21 @@ LIB2FUNCS = _muldi3 _divdi3 _moddi3 _udivdi3 _umoddi3 _negdi2 \
_fixunsdfsi _fixunssfsi _fixunsdfdi _fixdfdi _fixunssfdi _fixsfdi \
_fixxfdi _fixunsxfdi _floatdixf _fixunsxfsi \
_fixtfdi _fixunstfdi _floatditf \
- __gcc_bcmp _varargs _eprintf _op_new _op_vnew _new_handler _op_delete \
- _op_vdel _bb _shtab _clear_cache _trampoline __main _exit _ctors _eh \
- _pure
+ __gcc_bcmp _varargs __dummy _eprintf \
+ _bb _shtab _clear_cache _trampoline __main _exit \
+ _ctors _pure
+
+LIB2FUNCS_EH = _eh
+
+FPBIT_FUNCS = _pack_sf _unpack_sf _addsub_sf _mul_sf _div_sf \
+ _fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \
+ _lt_sf _le_sf _si_to_sf _sf_to_si _negate_sf _make_sf \
+ _sf_to_df
+
+DPBIT_FUNCS = _pack_df _unpack_df _addsub_df _mul_df _div_df \
+ _fpcmp_parts_df _compare_df _eq_df _ne_df _gt_df _ge_df \
+ _lt_df _le_df _si_to_df _df_to_si _negate_df _make_df \
+ _df_to_sf
# The files that "belong" in CONFIG_H are deliberately omitted
# because having them there would not be useful in actual practice.
@@ -581,10 +721,15 @@ LIB2FUNCS = _muldi3 _divdi3 _moddi3 _udivdi3 _umoddi3 _negdi2 \
# If it is, rm *.o is an easy way to do it.
# CONFIG_H = $(host_xm_file) $(tm_file)
CONFIG_H =
-RTL_H = rtl.h rtl.def machmode.h machmode.def
-TREE_H = tree.h real.h tree.def machmode.h machmode.def
-BYTECODE_H = bytecode.h bc-emit.h bc-optab.h
-
+RTL_BASE_H = rtl.h rtl.def gansidecl.h machmode.h machmode.def
+RTL_H = $(RTL_BASE_H) genrtl.h
+TREE_H = tree.h real.h tree.def gansidecl.h machmode.h machmode.def tree-check.h
+BASIC_BLOCK_H = basic-block.h bitmap.h
+DEMANGLE_H = demangle.h gansidecl.h
+RECOG_H = recog.h gansidecl.h
+EXPR_H = expr.h insn-codes.h
+REGS_H = regs.h varray.h machmode.h machmode.def gansidecl.h
+#
# Language makefile fragments.
# The following targets define the interface between us and the languages.
@@ -601,57 +746,82 @@ BYTECODE_H = bytecode.h bc-emit.h bc-optab.h
# Configure computes and adds these here.
####language hooks
+@language_hooks@
# sed inserts language fragments after the following line.
####language fragments
+@language_fragments@
# End of language makefile fragments.
-
-# Avoid a lot of time thinking about remaking Makefile.in and *.def.
-.SUFFIXES: .in .def
-
-Makefile: $(srcdir)/Makefile.in $(srcdir)/configure $(srcdir)/version.c \
- $(srcdir)/config/$(xmake_file) $(srcdir)/config/$(tmake_file) \
- $(LANG_MAKEFILES)
+#
+# The only suffixes we want for implicit rules are .c and .o, so clear
+# the list and add them. This speeds up GNU Make, and allows -r to work.
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+Makefile: $(srcdir)/Makefile.in config.status $(srcdir)/version.c \
+ $(xmake_file) $(tmake_file) $(LANG_MAKEFILES)
+ $(SHELL) $(srcdir)/configure.frag $(srcdir) "$(SUBDIRS)" \
+ "$(xmake_file)" "$(tmake_file)"
cp config.status config.run
$(SHELL) config.run
rm -f config.run
+$(srcdir)/configure: $(srcdir)/configure.in
+ cd $(srcdir); autoconf
+
+# cstamp-h.in controls rebuilding of config.in.
+# It is named cstamp-h.in and not stamp-h.in so the mostlyclean rule doesn't
+# delete it. A stamp file is needed as autoheader won't update the file if
+# nothing has changed.
+# It remains in the source directory and is part of the distribution.
+# This follows what is done in shellutils, fileutils, etc.
+# "echo timestamp" is used instead of touch to be consistent with other
+# packages that use autoconf (??? perhaps also to avoid problems with patch?).
+# ??? Newer versions have a maintainer mode that may be useful here.
+$(srcdir)/config.in: $(srcdir)/cstamp-h.in
+$(srcdir)/cstamp-h.in: $(srcdir)/configure.in $(srcdir)/acconfig.h
+ cd $(srcdir) && autoheader
+ @rm -f $(srcdir)/cstamp-h.in
+ echo timestamp > $(srcdir)/cstamp-h.in
+auto-host.h: cstamp-h ; @true
+cstamp-h: config.in config.status
+ CONFIG_HEADERS=auto-host.h:config.in $(SHELL) config.status
+
+# Really, really stupid make features, such as SUN's KEEP_STATE, may force
+# a target to build even if it is up-to-date. So we must verify that
+# config.status does not exist before failing.
+config.status: configure version.c
+ @if [ ! -f config.status ] ; then \
+ echo You must configure gcc. Look at the INSTALL file for details.; \
+ false; \
+ else \
+ $(SHELL) config.status --recheck; \
+ fi
+
all.internal: start.encap rest.encap
# This is what to compile if making a cross-compiler.
# Note that we can compile enquire using the cross-compiler just built,
# although we can't run it on this machine.
-all.cross: native gcc-cross specs stmp-headers $(LIBGCC) $(STMP_FIXPROTO) \
+all.cross: native gcc-cross specs stmp-headers $(STMP_FIXPROTO) $(LIBGCC) \
$(LIBGCC1_TEST) $(EXTRA_PARTS) lang.all.cross
# This is what to compile if making gcc with a cross-compiler.
-all.build: native xgcc $(EXTRA_PARTS) lang.all.build
+all.build: native xgcc$(exeext) $(EXTRA_PARTS) lang.all.build
# This is what must be made before installing GCC and converting libraries.
-start.encap: native xgcc specs $(LIBGCC1) xlimits.h lang.start.encap
+start.encap: native xgcc$(exeext) specs $(LIBGCC1) xlimits.h lang.start.encap
# These can't be made until after GCC can run.
-rest.encap: stmp-headers $(LIBGCC) $(STMP_FIXPROTO) $(EXTRA_PARTS) lang.rest.encap
+rest.encap: stmp-headers $(STMP_FIXPROTO) $(LIBGCC) $(EXTRA_PARTS) lang.rest.encap
# This is what is made with the host's compiler
# whether making a cross compiler or not.
-native: config.status cpp $(LANGUAGES) $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(USE_COLLECT2)
+native: config.status auto-host.h cpp$(exeext) $(LANGUAGES) \
+ $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(USE_COLLECT2)
# Define the names for selecting languages in LANGUAGES.
-C c: cc1
-OBJC objc: cc1obj objc-runtime
-OBJECTIVE-C objective-c: cc1obj objc-runtime
+C c: cc1$(exeext)
PROTO: proto
# Tell GNU make these are phony targets.
-.PHONY: C c OBJC objc OBJECTIVE-C objective-c PROTO proto
-
-# Really, really stupid make features, such as SUN's KEEP_STATE, may force
-# a target to build even if it is up-to-date. So we must verify that
-# config.status does not exist before failing.
-config.status:
- @if [ ! -f config.status ] ; then \
- echo You must configure gcc. Look at the INSTALL file for details.; \
- false; \
- else \
- true; \
- fi
+.PHONY: C c PROTO proto
# On the target machine, finish building a cross compiler.
# This does the things that can't be done on the host machine.
@@ -663,7 +833,7 @@ libgcc1-test: libgcc1-test.o native $(GCC_PARTS)
@echo "Testing libgcc1. Ignore linker warning messages."
$(GCC_FOR_TARGET) $(GCC_CFLAGS) libgcc1-test.o -o libgcc1-test \
-nostartfiles -nostdlib `$(GCC_FOR_TARGET) --print-libgcc-file-name`
-libgcc1-test.o: libgcc1-test.c native xgcc
+libgcc1-test.o: libgcc1-test.c native xgcc$(exeext)
$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) -c $(srcdir)/libgcc1-test.c
# Recompile all the language-independent object files.
@@ -672,55 +842,36 @@ compilations: ${OBJS}
# Create a list of the language-independent object files so the language
# subdirectories needn't mention their names explicitly.
-stamp-objlist: Makefile $(OBJS) $(BC_OBJS)
- echo " $(OBJS) $(BC_OBJS)" | sed -e 's, \([a-z]\), ../\1,g' -e 's/\.o/$(objext)/g' >stamp-objlist
+stamp-objlist: $(OBJS)
+ echo " $(OBJS)" | sed -e 's, \([a-z0-9]\), ../\1,g' -e 's/\.o/$(objext)/g' >stamp-objlist
# We call this executable `xgcc' rather than `gcc'
# to avoid confusion if the current directory is in the path
# and CC is `gcc'. It is renamed to `gcc' when it is installed.
-xgcc: gcc.o version.o $(LIBDEPS) $(EXTRA_GCC_OBJS)
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ gcc.o version.o $(EXTRA_GCC_OBJS) $(LIBS)
+xgcc$(exeext): gcc.o version.o choose-temp.o pexecute.o prefix.o version.o \
+ mkstemp.o $(LIBDEPS) $(EXTRA_GCC_OBJS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ gcc.o prefix.o version.o \
+ choose-temp.o pexecute.o mkstemp.o $(EXTRA_GCC_OBJS) $(LIBS)
# Dump a specs file to make -B./ read these specs over installed ones.
-specs: xgcc
+specs: xgcc$(exeext)
$(GCC_FOR_TARGET) -dumpspecs > tmp-specs
mv tmp-specs specs
# We do want to create an executable named `xgcc', so we can use it to
# compile libgcc2.a.
# Also create gcc-cross, so that install-common will install properly.
-gcc-cross: xgcc
+gcc-cross: xgcc$(exeext)
cp xgcc$(exeext) gcc-cross$(exeext)
-cc1: $(P) $(C_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(C_OBJS) $(OBJS) $(BC_OBJS) $(LIBS)
-
-cc1obj: $(P) $(OBJC_OBJS) $(OBJS) $(BC_OBJS) $(LIBDEPS)
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(OBJC_OBJS) $(OBJS) $(BC_OBJS) $(LIBS)
+cc1$(exeext): $(P) $(C_OBJS) $(OBJS) $(LIBDEPS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(C_OBJS) $(OBJS) $(LIBS)
# Copy float.h from its source.
gfloat.h: $(FLOAT_H)
-rm -f gfloat.h
cp $(FLOAT_H) gfloat.h
-# Create float.h source for the native machine.
-float.h-nat: enquire
- -./enquire -f > tmp-float.h
- mv tmp-float.h float.h-nat
-
-# Create a dummy float.h source for a cross-compiler.
-float.h-cross:
- echo "#error float.h values not known for cross-compiler" > t-float.h-cross
- mv t-float.h-cross float.h-cross
-
-# Used to compile enquire with standard cc, but have forgotten why.
-# Let's try with GCC.
-enquire: enquire.o $(GCC_PARTS)
- $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ENQUIRE_LDFLAGS) enquire.o -o $@
-enquire.o: $(srcdir)/enquire.c $(GCC_PASSES) stmp-int-hdrs
-# Breaking this line caused a problem with one version of GNU make.
- $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) $(ENQUIRE_CFLAGS) -I. -c $(srcdir)/enquire.c
-
# Build the version of limits.h that we will install.
xlimits.h: glimits.h limitx.h limity.h
if $(LIMITS_H_TEST) ; then \
@@ -729,7 +880,7 @@ xlimits.h: glimits.h limitx.h limity.h
cat $(srcdir)/glimits.h > tmp-xlimits.h; \
fi
mv tmp-xlimits.h xlimits.h
-
+#
# Build libgcc.a.
# This is done in two parts because some functions, in libgcc1.c,
# must be compiled with something other than GCC,
@@ -744,7 +895,7 @@ libgcc1.conv: libgcc1.a
# Use this as value of LIBGCC1 to inhibit use of libgcc1.c entirely.
# Make an empty file instead.
libgcc1.null: $(GCC_PASSES)
- echo "__foo () {}" > dummy.c
+ echo "void __foo () {}" > dummy.c
$(GCC_FOR_TARGET) $(GCC_CFLAGS) -c dummy.c
$(OLDAR) $(OLDAR_FLAGS) libgcc1.null dummy$(objext)
rm -f dummy$(objext) dummy.c
@@ -760,6 +911,10 @@ libgcc1.cross:
# Compile the library of arithmetic subroutines with the native compiler.
# Don't compile it with GCC!
# (That would cause most arithmetic functions to call themselves.)
+#
+# NOTE: If you modify these rules substantially, please be sure to
+# check at least config/i386/t-sco5 and possibly other makefile
+# fragments.
libgcc1.a: libgcc1.c $(CONFIG_H) $(LIB1FUNCS_EXTRA) config.status
-rm -f tmplibgcc1.a
# Actually build it in tmplibgcc1.a, then rename at end,
@@ -774,7 +929,7 @@ libgcc1.a: libgcc1.c $(CONFIG_H) $(LIB1FUNCS_EXTRA) config.status
do \
echo $${name}; \
rm -f $${name}$(objext); \
- $(OLDCC) $(CCLIBFLAGS) $(INCLUDES) -c -DL$${name} $(srcdir)/libgcc1.c; \
+ $(OLDCC) -DIN_LIBGCC1 $(CCLIBFLAGS) $(INCLUDES) -c -DL$${name} $(srcdir)/libgcc1.c; \
if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
mv libgcc1$(objext) $${name}$(objext); \
$(OLDAR) $(OLDAR_FLAGS) tmplibgcc1.a $${name}$(objext); \
@@ -794,7 +949,7 @@ libgcc1.a: libgcc1.c $(CONFIG_H) $(LIB1FUNCS_EXTRA) config.status
if [ $${name}.asm = $${file} ]; then \
cp $${file} $${name}.s || exit 1; file=$${name}.s; \
else true; fi; \
- $(OLDCC) $(CCLIBFLAGS) $(INCLUDES) -c $${file}; \
+ $(OLDCC) -DIN_LIBGCC1 $(CCLIBFLAGS) $(INCLUDES) -c $${file}; \
if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
$(OLDAR) $(OLDAR_FLAGS) tmplibgcc1.a $${name}$(objext); \
if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
@@ -840,7 +995,7 @@ libgcc1.S: libgcc1.c $(CONFIG_H) config.status
for name in $(LIB1FUNCS); \
do \
echo $${name}; \
- $(OLDCC) $(CCLIBFLAGS) $(INCLUDES) -S -DL$${name} $(srcdir)/libgcc1.c; \
+ $(OLDCC) -DIN_LIBGCC1 $(CCLIBFLAGS) $(INCLUDES) -S -DL$${name} $(srcdir)/libgcc1.c; \
if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
echo '#ifdef ' L$${name} >> libgcc1.S; \
cat libgcc1.s >> libgcc1.S; \
@@ -851,15 +1006,16 @@ libgcc1.S: libgcc1.c $(CONFIG_H) config.status
# Compiling libgcc2.a requires making sure that cc1, etc. have been compiled.
# But recompiling cc1 should not force recompilation of libgcc2.a.
# If you want to force recompilation, delete libgcc2.a.
-libgcc2.ready: $(GCC_PASSES) $(LIBGCC2_DEPS) stmp-int-hdrs
+libgcc2.ready: $(GCC_PASSES) $(LIBGCC2_DEPS) stmp-int-hdrs $(STMP_FIXPROTO)
-if [ -f libgcc2.ready ] ; then \
true; \
else \
touch libgcc2.ready; \
fi
-libgcc2.a: libgcc2.c libgcc2.ready $(CONFIG_H) $(LIB2FUNCS_EXTRA) \
- machmode.h longlong.h gbl-ctors.h config.status
+LIB2ADD = $(srcdir)/frame.c $(LIB2FUNCS_EXTRA) $(LANG_LIB2FUNCS)
+libgcc2.a: libgcc2.c libgcc2.ready $(CONFIG_H) $(FPBIT) $(DPBIT) $(LIB2ADD) \
+ machmode.h longlong.h frame.h gansidecl.h gbl-ctors.h config.status
# Actually build it in tmplibgcc2.a, then rename at end,
# so that libgcc2.a itself remains nonexistent if compilation is aborted.
-rm -f tmplibgcc2.a
@@ -878,17 +1034,60 @@ libgcc2.a: libgcc2.c libgcc2.ready $(CONFIG_H) $(LIB2FUNCS_EXTRA) \
$(AR) $(AR_FLAGS) tmplibgcc2.a $${name}$(objext); \
rm -f $${name}$(objext); \
done
+ for name in $(LIB2FUNCS_EH); \
+ do \
+ echo $${name}; \
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -fexceptions $(INCLUDES) -c \
+ -DL$${name} $(srcdir)/libgcc2.c -o $${name}$(objext); \
+ if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
+ $(AR) $(AR_FLAGS) tmplibgcc2.a $${name}$(objext); \
+ rm -f $${name}$(objext); \
+ done
+ if [ x$(FPBIT) != x ]; then \
+ for name in $(FPBIT_FUNCS); \
+ do \
+ echo $${name}; \
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c -DL$${name} \
+ -DFINE_GRAINED_LIBRARIES $(FPBIT) -o $${name}$(objext); \
+ if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
+ $(AR) $(AR_FLAGS) tmplibgcc2.a $${name}$(objext); \
+ rm -f $${name}$(objext); \
+ done; \
+ else true; fi;
+ if [ x$(DPBIT) != x ]; then \
+ for name in $(DPBIT_FUNCS); \
+ do \
+ echo $${name}; \
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) -c -DL$${name} \
+ -DFINE_GRAINED_LIBRARIES $(DPBIT) -o $${name}$(objext); \
+ if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
+ $(AR) $(AR_FLAGS) tmplibgcc2.a $${name}$(objext); \
+ rm -f $${name}$(objext); \
+ done; \
+ else true; fi;
# Some shells crash when a loop has no items.
# So make sure there is always at least one--`..'.
# Then ignore it.
# We don't use -e here because there are if statements
# that should not make the command give up when the if condition is false.
# Instead, we test for failure after each command where it matters.
- for file in .. $(LIB2FUNCS_EXTRA); \
- do \
- if [ x$${file} != x.. ]; then \
- name=`echo $${file} | sed -e 's/[.][cS]$$//' -e 's/[.]asm$$//'`; \
- oname=` echo $${name} | sed -e 's,.*/,,'`; \
+ for file in $(LIB2ADD); do \
+ name=`echo $${file} | sed -e 's/[.][cSo]$$//' -e 's/[.]asm$$//' -e 's/[.]txt$$//'`; \
+ oname=` echo $${name} | sed -e 's,.*/,,'`; \
+ if [ $${name}.txt = $${file} ]; then \
+ for f in .. `cat $${file}`; do if [ x$${f} != x.. ]; then \
+ $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
+ AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" CC="$(CC)" \
+ CFLAGS="$(CFLAGS)" HOST_PREFIX="$(HOST_PREFIX)" \
+ HOST_PREFIX_1="$(HOST_PREFIX_1)" \
+ LANGUAGES="$(LANGUAGES)" \
+ LIBGCC2_CFLAGS="$(LIBGCC2_CFLAGS)" $${f}; \
+ if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
+ $(AR) $(AR_FLAGS) tmplibgcc2.a $${f}; \
+ rm -f $${f}; \
+ else true; \
+ fi; done; \
+ else \
echo $${name}; \
if [ $${name}.asm = $${file} ]; then \
cp $${file} $${name}.s || exit 1; file=$${name}.s; \
@@ -897,7 +1096,6 @@ libgcc2.a: libgcc2.c libgcc2.ready $(CONFIG_H) $(LIB2FUNCS_EXTRA) \
if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
$(AR) $(AR_FLAGS) tmplibgcc2.a $${oname}$(objext); \
rm -f $${name}.s $${oname}$(objext); \
- else true; \
fi; \
done
mv tmplibgcc2.a libgcc2.a
@@ -931,21 +1129,31 @@ libgcc.a: $(LIBGCC1) $(LIBGCC2)
# Use the genmultilib shell script to generate the information the gcc
# driver program needs to select the library directory based on the
# switches.
-multilib.h: $(srcdir)/genmultilib Makefile
- $(SHELL) $(srcdir)/genmultilib "$(MULTILIB_OPTIONS)" \
- "$(MULTILIB_DIRNAMES)" "$(MULTILIB_MATCHES)" > multilib.h
+multilib.h: s-mlib; @true
+s-mlib: $(srcdir)/genmultilib Makefile
+ $(SHELL) $(srcdir)/genmultilib \
+ "$(MULTILIB_OPTIONS)" \
+ "$(MULTILIB_DIRNAMES)" \
+ "$(MULTILIB_MATCHES)" \
+ "$(MULTILIB_EXCEPTIONS)" \
+ "$(MULTILIB_EXTRA_OPTS)" > tmp-mlib.h
+ $(srcdir)/move-if-change tmp-mlib.h multilib.h
+ touch s-mlib
# Build multiple copies of libgcc.a, one for each target switch.
stmp-multilib: $(LIBGCC1) libgcc2.c libgcc2.ready $(CONFIG_H) \
- $(LIB2FUNCS_EXTRA) machmode.h longlong.h gbl-ctors.h config.status
+ frame.h gansidecl.h \
+ $(LIB2ADD) machmode.h longlong.h gbl-ctors.h config.status
for i in `$(GCC_FOR_TARGET) --print-multi-lib`; do \
dir=`echo $$i | sed -e 's/;.*$$//'`; \
flags=`echo $$i | sed -e 's/^[^;]*;//' -e 's/@/ -/g'`; \
$(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" CC="$(CC)" CFLAGS="$(CFLAGS)" \
RANLIB="$(RANLIB)" RANLIB_TEST="$(RANLIB_TEST)" \
+ LANGUAGES="$(LANGUAGES)" \
HOST_PREFIX="$(HOST_PREFIX)" HOST_PREFIX_1="$(HOST_PREFIX_1)" \
LIBGCC2_CFLAGS="$(LIBGCC2_CFLAGS) $${flags}" \
+ MULTILIB_CFLAGS="$${flags}" \
LIBGCC1="$(LIBGCC1)" LIBGCC2="$(LIBGCC2)" \
dir="$${dir}" stmp-multilib-sub; \
if [ $$? -eq 0 ] ; then true; else exit 1; fi; \
@@ -954,10 +1162,16 @@ stmp-multilib: $(LIBGCC1) libgcc2.c libgcc2.ready $(CONFIG_H) \
# Subroutine of stmp-multilib so make -n works.
stmp-multilib-sub:
- rm -f $(dir)/libgcc.a $(LIBGCC2)
+ rm -f $(LIBGCC2)
+ if [ -d $(dir) ]; then \
+ cd $(dir); \
+ rm -f libgcc.a $(EXTRA_MULTILIB_PARTS); \
+ else true; \
+ fi
$(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" CC="$(CC)" CFLAGS="$(CFLAGS)" \
HOST_PREFIX="$(HOST_PREFIX)" HOST_PREFIX_1="$(HOST_PREFIX_1)" \
+ LANGUAGES="$(LANGUAGES)" \
LIBGCC2_CFLAGS="$(LIBGCC2_CFLAGS)" $(LIBGCC2)
if [ x$(LIBGCC1) != xlibgcc1-asm.a ]; \
then true; \
@@ -969,6 +1183,7 @@ stmp-multilib-sub:
$(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" CC="$(CC)" CFLAGS="$(CFLAGS)" \
HOST_PREFIX="$(HOST_PREFIX)" HOST_PREFIX_1="$(HOST_PREFIX_1)" \
+ LANGUAGES="$(LANGUAGES)" \
LIBGCC2_CFLAGS="$(LIBGCC2_CFLAGS)" $(LIBGCC1); \
fi
rm -rf tmplibgcc.a tmpcopy
@@ -983,65 +1198,57 @@ stmp-multilib-sub:
if $(RANLIB_TEST) ; then $(RANLIB) tmplibgcc.a; else true; fi
if [ -d $(dir) ]; then true; else mkdir $(dir); fi
mv tmplibgcc.a $(dir)/libgcc.a
-
-objc-runtime: libobjc.a
-
-# Build the Objective C runtime library.
-libobjc.a: cc1obj stmp-int-hdrs libgcc2.ready $(USE_COLLECT2) $(EXTRA_PARTS)
- if [ -d objc ]; then true; else mkdir objc; fi
- thisdir1=`pwd`; \
- srcdir1=`cd $(srcdir); pwd`; \
- cd objc; \
- $(MAKE) -f $${srcdir1}/objc/Makefile libobjc.a \
- srcdir=$${srcdir1} tooldir=$(tooldir) AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" \
- GCC_FOR_TARGET="$${thisdir1}/xgcc -B$${thisdir1}/" \
- GCC_CFLAGS="$(GCC_CFLAGS)"
- -rm -f libobjc.a
- ln objc/libobjc.a . >/dev/null 2>&1 || cp objc/libobjc.a .
- -if $(RANLIB_TEST) ; then $(RANLIB) libobjc.a; else true; fi
-
-# This is used by objc/Makefile if the user runs that directly.
-sublibobjc.a: cc1obj stmp-int-hdrs libgcc2.ready
- thisdir1=`pwd`; \
- srcdir1=`cd $(srcdir); pwd`; \
- cd objc; \
- $(MAKE) -f $$srcdir1/objc/Makefile libobjc.a \
- srcdir=$$srcdir1 tooldir=$(tooldir) AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" \
- GCC_FOR_TARGET="$$thisdir1/xgcc -B$$thisdir1/" \
- GCC_CFLAGS="$(GCC_CFLAGS)"
+ for f in .. $(EXTRA_MULTILIB_PARTS); do if [ x$${f} != x.. ]; then \
+ $(MAKE) GCC_FOR_TARGET="$(GCC_FOR_TARGET)" \
+ AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" CC="$(CC)" CFLAGS="$(CFLAGS)" \
+ HOST_PREFIX="$(HOST_PREFIX)" HOST_PREFIX_1="$(HOST_PREFIX_1)" \
+ LANGUAGES="$(LANGUAGES)" \
+ MULTILIB_CFLAGS="$(MULTILIB_CFLAGS)" T="t" t$${f}; \
+ mv t$${f} $(dir)/$${f}; \
+ else true; \
+ fi; done
# Compile two additional files that are linked with every program
# linked using GCC on systems using COFF or ELF, for the sake of C++
# constructors.
-crtbegin.o: stamp-crt ; @true
-crtend.o: stamp-crt; @true
-
-stamp-crt: crtstuff.c $(GCC_PASSES) $(CONFIG_H) gbl-ctors.h
- $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(CRTSTUFF_T_CFLAGS) \
- -DCRT_BEGIN -finhibit-size-directive -fno-inline-functions \
- -g0 -c $(srcdir)/crtstuff.c
- mv crtstuff$(objext) crtbegin$(objext)
- $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(CRTSTUFF_T_CFLAGS) \
- -DCRT_END -finhibit-size-directive -fno-inline-functions \
- -g0 -c $(srcdir)/crtstuff.c
- mv crtstuff$(objext) crtend$(objext)
- touch stamp-crt
+$(T)crtbegin.o: crtstuff.c $(GCC_PASSES) $(CONFIG_H) \
+ defaults.h frame.h gbl-ctors.h
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \
+ -finhibit-size-directive -fno-inline-functions -fno-exceptions $(CRTSTUFF_T_CFLAGS) \
+ -c $(srcdir)/crtstuff.c -DCRT_BEGIN -o $(T)crtbegin$(objext)
+
+$(T)crtend.o: crtstuff.c $(GCC_PASSES) $(CONFIG_H) \
+ defaults.h frame.h gbl-ctors.h
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(MULTILIB_CFLAGS) -g0 \
+ -finhibit-size-directive -fno-inline-functions -fno-exceptions $(CRTSTUFF_T_CFLAGS) \
+ -c $(srcdir)/crtstuff.c -DCRT_END -o $(T)crtend$(objext)
# On some systems we also want to install versions of these files
# compiled using PIC for use in shared libraries.
-crtbeginS.o crtendS.o: stamp-crtS ; @true
+crtbeginS.o crtendS.o: s-crtS ; @true
-stamp-crtS: stamp-crt crtstuff.c $(GCC_PASSES) $(CONFIG_H) gbl-ctors.h
- $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(CRTSTUFF_T_CFLAGS) \
- -DCRT_BEGIN -finhibit-size-directive -fno-inline-functions \
- -g0 -c $(srcdir)/crtstuff.c -fPIC
+s-crtS: crtstuff.c $(GCC_PASSES) $(CONFIG_H) \
+ defaults.h frame.h gbl-ctors.h
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(CRTSTUFF_T_CFLAGS_S) \
+ -DCRT_BEGIN -DCRTSTUFFS_O -finhibit-size-directive -fno-inline-functions \
+ -fno-exceptions -g0 -c $(srcdir)/crtstuff.c
mv crtstuff$(objext) crtbeginS$(objext)
- $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(CRTSTUFF_T_CFLAGS) \
- -DCRT_END -finhibit-size-directive -fno-inline-functions \
- -g0 -c $(srcdir)/crtstuff.c -fPIC
- mv crtstuff$(objext) crtendS$(objext)
- touch stamp-crtS
-
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) $(CRTSTUFF_T_CFLAGS_S) \
+ -DCRT_END -DCRTSTUFFS_O -finhibit-size-directive -fno-inline-functions \
+ -fno-exceptions -g0 -c $(srcdir)/crtstuff.c -o crtendS$(objext)
+ touch s-crtS
+
+# Compile the start modules crt0.o and mcrt0.o that are linked with every program
+crt0.o: s-crt0 ; @true
+mcrt0.o: s-crt0; @true
+
+s-crt0: $(CRT0_S) $(MCRT0_S) $(GCC_PASSES) $(CONFIG_H)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(CRT0STUFF_T_CFLAGS) \
+ -o crt0.o -c $(CRT0_S)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(CRT0STUFF_T_CFLAGS) \
+ -o mcrt0.o -c $(MCRT0_S)
+ touch s-crt0
+#
# Compiling object files from source files.
# Note that dependencies on obstack.h are not written
@@ -1050,15 +1257,16 @@ stamp-crtS: stamp-crt crtstuff.c $(GCC_PASSES) $(CONFIG_H) gbl-ctors.h
# C language specific files.
c-parse.o : $(srcdir)/c-parse.c $(CONFIG_H) $(TREE_H) c-lex.h \
- $(srcdir)/c-parse.h c-tree.h input.h flags.h
+ $(srcdir)/c-parse.h c-tree.h input.h flags.h system.h toplev.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c $(srcdir)/c-parse.c
$(srcdir)/c-parse.h: $(srcdir)/c-parse.c
$(srcdir)/c-parse.c: $(srcdir)/c-parse.y
cd $(srcdir); $(BISON) $(BISONFLAGS) -d c-parse.y -o c-parse.c
$(srcdir)/c-parse.y: c-parse.in
+ echo '/*WARNING: This file is automatically generated!*/' >tmp-c-parse.y
sed -e "/^ifobjc$$/,/^end ifobjc$$/d" \
-e "/^ifc$$/d" -e "/^end ifc$$/d" \
- $(srcdir)/c-parse.in >tmp-c-parse.y
+ $(srcdir)/c-parse.in >>tmp-c-parse.y
$(srcdir)/move-if-change tmp-c-parse.y $(srcdir)/c-parse.y
$(srcdir)/c-gperf.h: c-parse.gperf
@@ -1066,38 +1274,42 @@ $(srcdir)/c-gperf.h: c-parse.gperf
$(srcdir)/c-parse.gperf >tmp-gperf.h
$(srcdir)/move-if-change tmp-gperf.h $(srcdir)/c-gperf.h
-c-decl.o : c-decl.c $(CONFIG_H) $(TREE_H) c-tree.h c-lex.h flags.h output.h
-c-typeck.o : c-typeck.c $(CONFIG_H) $(TREE_H) c-tree.h flags.h output.h
-c-lang.o : c-lang.c $(CONFIG_H) $(TREE_H)
-c-lex.o : c-lex.c $(CONFIG_H) $(TREE_H) c-lex.h c-tree.h $(srcdir)/c-parse.h \
- input.h flags.h $(srcdir)/c-gperf.h c-pragma.h
-c-aux-info.o : c-aux-info.c $(CONFIG_H) $(TREE_H) c-tree.h flags.h
-c-convert.o : c-convert.c $(CONFIG_H) $(TREE_H) flags.h
-c-pragma.o: c-pragma.c $(CONFIG_H) $(TREE_H) c-pragma.h
-c-iterate.o: c-iterate.c $(CONFIG_H) $(TREE_H) $(RTL_H) c-tree.h flags.h
-
-# To make a configuration always use collect2, set USE_COLLECT2 to ld.
-ld: collect2
- rm -f ld$(exeext)
- ln collect2$(exeext) ld$(exeext) > /dev/null 2>&1 \
- || cp collect2$(exeext) ld$(exeext)
-
-collect2 : collect2.o cplus-dem.o underscore.o version.o $(LIBDEPS)
+c-decl.o : c-decl.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h flags.h \
+ output.h toplev.h
+c-typeck.o : c-typeck.c $(CONFIG_H) system.h $(TREE_H) c-tree.h flags.h \
+ output.h $(EXPR_H) $(RTL_H) toplev.h
+c-lang.o : c-lang.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h toplev.h \
+ output.h
+c-lex.o : c-lex.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) c-lex.h c-tree.h \
+ $(srcdir)/c-parse.h input.h flags.h $(srcdir)/c-gperf.h c-pragma.h \
+ toplev.h output.h
+c-aux-info.o : c-aux-info.c $(CONFIG_H) system.h $(TREE_H) c-tree.h flags.h
+c-convert.o : c-convert.c $(CONFIG_H) system.h $(TREE_H) flags.h toplev.h
+c-pragma.o: c-pragma.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) except.h \
+ function.h defaults.h c-pragma.h toplev.h
+c-iterate.o: c-iterate.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) c-tree.h \
+ flags.h toplev.h $(EXPR_H)
+
+collect2$(exeext): collect2.o tlink.o hash.o cplus-dem.o underscore.o \
+ version.o choose-temp.o mkstemp.o $(LIBDEPS)
# Don't try modifying collect2 (aka ld) in place--it might be linking this.
-rm -f collect2$(exeext)
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ collect2.o \
- cplus-dem.o underscore.o version.o $(LIBS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ collect2.o tlink.o hash.o \
+ cplus-dem.o underscore.o version.o choose-temp.o mkstemp.o $(LIBS)
-collect2.o : collect2.c $(CONFIG_H) gstab.h obstack.h demangle.h
+collect2.o : collect2.c $(CONFIG_H) system.h gansidecl.h gstab.h obstack.h \
+ $(DEMANGLE_H)
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
- -DTARGET_MACHINE=\"$(target)\" $(MAYBE_USE_COLLECT2) \
+ -DTARGET_MACHINE=\"$(target_alias)\" $(MAYBE_USE_COLLECT2) \
-c `echo $(srcdir)/collect2.c | sed 's,^\./,,'`
-cplus-dem.o: cplus-dem.c demangle.h
+tlink.o: tlink.c $(DEMANGLE_H) hash.h $(CONFIG_H) system.h toplev.h
+hash.o: hash.c hash.h system.h toplev.h
+cplus-dem.o: cplus-dem.c $(DEMANGLE_H)
-underscore.c: stamp-under ; @true
+underscore.c: s-under ; @true
-stamp-under: $(GCC_PASSES)
+s-under: $(GCC_PASSES)
echo "int xxy_us_dummy;" >tmp-dum.c
$(GCC_FOR_TARGET) -S tmp-dum.c
echo '/*WARNING: This file is automatically generated!*/' >tmp-under.c
@@ -1108,164 +1320,202 @@ stamp-under: $(GCC_PASSES)
fi
$(srcdir)/move-if-change tmp-under.c underscore.c
-rm -f tmp-dum.c tmp-dum.s
- touch stamp-under
-
-# Objective C language specific files.
-
-objc-parse.o : $(srcdir)/objc-parse.c $(CONFIG_H) $(TREE_H) c-lex.h \
- c-tree.h input.h flags.h objc-act.h
- $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c $(srcdir)/objc-parse.c
-$(srcdir)/objc-parse.c : $(srcdir)/objc-parse.y
- cd $(srcdir); $(BISON) $(BISONFLAGS) objc-parse.y -o objc-parse.c
-$(srcdir)/objc-parse.y: $(srcdir)/c-parse.in
- sed -e "/^ifc$$/,/^end ifc$$/d" \
- -e "/^ifobjc$$/d" -e "/^end ifobjc$$/d" \
- $(srcdir)/c-parse.in >tmp-objc-prs.y
- $(srcdir)/move-if-change tmp-objc-prs.y $(srcdir)/objc-parse.y
-
-objc-act.o : objc-act.c $(CONFIG_H) $(TREE_H) $(RTL_H) c-tree.h c-lex.h \
- flags.h objc-act.h input.h function.h $(srcdir)/c-parse.h
+ touch s-under
# A file used by all variants of C.
-c-common.o : c-common.c $(CONFIG_H) $(TREE_H) c-tree.h c-lex.h flags.h
+c-common.o : c-common.c $(CONFIG_H) system.h $(TREE_H) c-tree.h c-lex.h \
+ flags.h toplev.h output.h
# Language-independent files.
-gcc.o: gcc.c $(CONFIG_H) multilib.h config.status $(lang_specs_files)
- $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+DRIVER_DEFINES = \
-DSTANDARD_STARTFILE_PREFIX=\"$(libdir)/\" \
-DSTANDARD_EXEC_PREFIX=\"$(libdir)/gcc-lib/\" \
-DDEFAULT_TARGET_VERSION=\"$(version)\" \
- -DDEFAULT_TARGET_MACHINE=\"$(target)\" \
- -DTOOLDIR_BASE_PREFIX=\"$(exec_prefix)/\" \
- $(MAYBE_TARGET_DEFAULT) \
+ -DDEFAULT_TARGET_MACHINE=\"$(target_alias)\" \
+ -DTOOLDIR_BASE_PREFIX=\"$(exec_prefix)/\"
+gcc.o: gcc.c $(CONFIG_H) system.h gansidecl.h multilib.h Makefile \
+ $(lang_specs_files)
+ $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+ $(DRIVER_DEFINES) \
-c `echo $(srcdir)/gcc.c | sed 's,^\./,,'`
+tree-check.h: s-check ; @true
+s-check : gencheck $(srcdir)/move-if-change
+ ./gencheck > tmp-check.h
+ $(srcdir)/move-if-change tmp-check.h tree-check.h
+ touch s-check
+
+gencheck : gencheck.o tree.def $(HOST_LIBDEPS)
+ $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
+ gencheck.o $(HOST_LIBS)
+
+gencheck.o : gencheck.c hconfig.h system.h
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/gencheck.c
+
dumpvers: dumpvers.c
version.o: version.c
-obstack.o: obstack.c
+obstack.o: obstack.c $(CONFIG_H)
+choose-temp.o: choose-temp.c $(CONFIG_H) gansidecl.h system.h
+mkstemp.o: mkstemp.c $(CONFIG_H) gansidecl.h system.h
+pexecute.o: pexecute.c $(CONFIG_H) system.h gansidecl.h
+prefix.o: prefix.c $(CONFIG_H) system.h gansidecl.h Makefile
+ $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+ -DPREFIX=\"$(prefix)\" \
+ -c `echo $(srcdir)/prefix.c | sed 's,^\./,,'`
-convert.o: convert.c $(CONFIG_H) $(TREE_H) flags.h convert.h
+convert.o: convert.c $(CONFIG_H) $(TREE_H) flags.h convert.h toplev.h
-tree.o : tree.c $(CONFIG_H) $(TREE_H) flags.h function.h
-print-tree.o : print-tree.c $(CONFIG_H) $(TREE_H)
-stor-layout.o : stor-layout.c $(CONFIG_H) $(TREE_H) flags.h function.h
-fold-const.o : fold-const.c $(CONFIG_H) $(TREE_H) flags.h
-toplev.o : toplev.c $(CONFIG_H) $(TREE_H) $(RTL_H) bytecode.h bc-emit.h \
+tree.o : tree.c $(CONFIG_H) system.h $(TREE_H) flags.h function.h toplev.h except.h
+print-tree.o : print-tree.c $(CONFIG_H) system.h $(TREE_H)
+stor-layout.o : stor-layout.c $(CONFIG_H) system.h $(TREE_H) flags.h \
+ function.h $(EXPR_H) $(RTL_H) toplev.h except.h
+fold-const.o : fold-const.c $(CONFIG_H) system.h $(TREE_H) flags.h toplev.h
+toplev.o : toplev.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) \
flags.h input.h insn-attr.h xcoffout.h defaults.h output.h \
+ insn-codes.h insn-config.h $(RECOG_H) Makefile toplev.h dwarfout.h \
+ dwarf2out.h sdbout.h dbxout.h \
$(lang_options_files)
- $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
- $(MAYBE_TARGET_DEFAULT) $(MAYBE_USE_COLLECT2) \
+ $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(MAYBE_USE_COLLECT2) \
+ -DTARGET_NAME=\"$(target_alias)\" \
-c `echo $(srcdir)/toplev.c | sed 's,^\./,,'`
-rtl.o : rtl.c $(CONFIG_H) $(RTL_H)
-
-print-rtl.o : print-rtl.c $(CONFIG_H) $(RTL_H)
-rtlanal.o : rtlanal.c $(CONFIG_H) $(RTL_H)
-
-varasm.o : varasm.c $(CONFIG_H) $(TREE_H) $(RTL_H) flags.h function.h \
- defaults.h insn-codes.h expr.h hard-reg-set.h regs.h xcoffout.h \
- output.h bytecode.h c-pragma.h
-function.o : function.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h function.h \
- insn-flags.h insn-codes.h expr.h regs.h hard-reg-set.h insn-config.h \
- recog.h output.h bytecode.h
-stmt.o : stmt.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h function.h \
- insn-flags.h insn-config.h insn-codes.h hard-reg-set.h expr.h loop.h \
- recog.h bytecode.h bc-typecd.h bc-typecd.def bc-opcode.h bc-optab.h \
- bc-emit.h
-expr.o : expr.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h function.h regs.h \
- insn-flags.h insn-codes.h expr.h insn-config.h recog.h output.h \
- typeclass.h bytecode.h bc-opcode.h bc-typecd.h bc-typecd.def bc-optab.h \
- bc-emit.h modemap.def
-calls.o : calls.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h expr.h insn-codes.h \
- insn-flags.h
-expmed.o : expmed.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h \
- insn-flags.h insn-config.h insn-codes.h expr.h recog.h real.h
-explow.o : explow.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h hard-reg-set.h \
- insn-config.h expr.h recog.h insn-flags.h insn-codes.h
-optabs.o : optabs.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h \
- insn-flags.h insn-config.h insn-codes.h expr.h recog.h reload.h
-dbxout.o : dbxout.c $(CONFIG_H) $(TREE_H) $(RTL_H) flags.h regs.h \
- insn-config.h reload.h gstab.h xcoffout.h defaults.h output.h
-sdbout.o : sdbout.c $(CONFIG_H) $(TREE_H) $(RTL_H) gsyms.h flags.h \
- insn-config.h reload.h
-dwarfout.o : dwarfout.c $(CONFIG_H) $(TREE_H) $(RTL_H) dwarf.h flags.h \
- insn-config.h reload.h output.h defaults.h
-xcoffout.o : xcoffout.c $(CONFIG_H) $(TREE_H) $(RTL_H) xcoffout.h flags.h
-emit-rtl.o : emit-rtl.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h \
- function.h regs.h insn-config.h insn-codes.h real.h expr.h bytecode.h \
- bc-opcode.h bc-typecd.h bc-typecd.def bc-optab.h bc-emit.h bc-opname.h
-real.o : real.c $(CONFIG_H) $(TREE_H)
-getpwd.o : getpwd.c $(CONFIG_H)
-
-integrate.o : integrate.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h integrate.h \
- insn-flags.h insn-config.h insn-codes.h expr.h real.h function.h \
- bytecode.h
-
-jump.o : jump.c $(CONFIG_H) $(RTL_H) flags.h hard-reg-set.h regs.h \
- insn-config.h insn-flags.h insn-codes.h expr.h real.h
-stupid.o : stupid.c $(CONFIG_H) $(RTL_H) regs.h hard-reg-set.h flags.h
-
-cse.o : cse.c $(CONFIG_H) $(RTL_H) regs.h hard-reg-set.h flags.h real.h \
- insn-config.h recog.h
-loop.o : loop.c $(CONFIG_H) $(RTL_H) flags.h loop.h insn-config.h \
- insn-flags.h insn-codes.h regs.h hard-reg-set.h recog.h expr.h real.h
-unroll.o : unroll.c $(CONFIG_H) $(RTL_H) insn-config.h insn-codes.h \
- integrate.h regs.h flags.h expr.h loop.h
-flow.o : flow.c $(CONFIG_H) $(RTL_H) flags.h insn-config.h \
- basic-block.h regs.h hard-reg-set.h output.h
-combine.o : combine.c $(CONFIG_H) $(RTL_H) flags.h \
- insn-config.h insn-flags.h insn-codes.h insn-attr.h regs.h expr.h \
- basic-block.h recog.h real.h hard-reg-set.h
-regclass.o : regclass.c $(CONFIG_H) $(RTL_H) hard-reg-set.h flags.h \
- basic-block.h regs.h insn-config.h recog.h reload.h real.h bytecode.h
-local-alloc.o : local-alloc.c $(CONFIG_H) $(RTL_H) flags.h basic-block.h \
- regs.h hard-reg-set.h insn-config.h recog.h output.h
-global.o : global.c $(CONFIG_H) $(RTL_H) flags.h \
- basic-block.h regs.h hard-reg-set.h insn-config.h output.h
-
-reload.o : reload.c $(CONFIG_H) $(RTL_H) flags.h output.h \
- reload.h recog.h hard-reg-set.h insn-config.h insn-codes.h regs.h real.h
-reload1.o : reload1.c $(CONFIG_H) $(RTL_H) real.h flags.h expr.h \
- reload.h regs.h hard-reg-set.h insn-config.h insn-flags.h insn-codes.h \
- basic-block.h recog.h output.h
-caller-save.o : caller-save.c $(CONFIG_H) $(RTL_H) flags.h \
- regs.h hard-reg-set.h insn-codes.h insn-config.h basic-block.h recog.h \
- reload.h expr.h
-reorg.o : reorg.c $(CONFIG_H) $(RTL_H) conditions.h hard-reg-set.h \
- basic-block.h regs.h insn-config.h insn-attr.h insn-flags.h recog.h \
- flags.h output.h
-sched.o : sched.c $(CONFIG_H) $(RTL_H) basic-block.h regs.h hard-reg-set.h \
- flags.h insn-config.h insn-attr.h
-final.o : final.c $(CONFIG_H) $(RTL_H) $(TREE_H) flags.h regs.h \
- recog.h conditions.h insn-config.h insn-attr.h real.h output.h \
- hard-reg-set.h insn-flags.h insn-codes.h gstab.h xcoffout.h defaults.h
-recog.o : recog.c $(CONFIG_H) $(RTL_H) \
- regs.h recog.h hard-reg-set.h flags.h insn-config.h insn-attr.h \
+rtl.o : rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h
+
+print-rtl.o : print-rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h
+rtlanal.o : rtlanal.c $(CONFIG_H) system.h $(RTL_H)
+
+varasm.o : varasm.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) flags.h \
+ function.h defaults.h $(EXPR_H) hard-reg-set.h $(REGS_H) \
+ xcoffout.h output.h c-pragma.h toplev.h except.h dbxout.h sdbout.h
+function.o : function.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \
+ function.h insn-flags.h insn-codes.h $(EXPR_H) $(REGS_H) hard-reg-set.h \
+ insn-config.h $(RECOG_H) output.h toplev.h except.h
+stmt.o : stmt.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h function.h \
+ insn-flags.h insn-config.h insn-codes.h hard-reg-set.h $(EXPR_H) except.h \
+ loop.h $(RECOG_H) toplev.h output.h
+except.o : except.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \
+ function.h insn-flags.h $(EXPR_H) $(REGS_H) hard-reg-set.h \
+ insn-config.h $(RECOG_H) output.h except.h toplev.h
+expr.o : expr.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h function.h \
+ $(REGS_H) insn-flags.h insn-codes.h $(EXPR_H) insn-config.h $(RECOG_H) output.h \
+ typeclass.h hard-reg-set.h toplev.h hard-reg-set.h except.h
+calls.o : calls.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h $(EXPR_H) \
+ insn-flags.h $(REGS_H) toplev.h output.h
+expmed.o : expmed.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \
+ insn-flags.h insn-config.h insn-codes.h $(EXPR_H) $(RECOG_H) real.h
+explow.o : explow.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \
+ hard-reg-set.h insn-config.h $(EXPR_H) $(RECOG_H) insn-flags.h insn-codes.h
+optabs.o : optabs.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \
+ insn-flags.h insn-config.h insn-codes.h $(EXPR_H) $(RECOG_H) reload.h
+dbxout.o : dbxout.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) flags.h $(REGS_H) \
+ insn-config.h reload.h gstab.h xcoffout.h defaults.h output.h dbxout.h \
+ toplev.h
+sdbout.o : sdbout.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) flags.h except.h \
+ function.h $(EXPR_H) output.h hard-reg-set.h $(REGS_H) defaults.h real.h \
+ insn-config.h obstack.h xcoffout.h c-pragma.h sdbout.h toplev.h
+dwarfout.o : dwarfout.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) dwarf.h \
+ flags.h insn-config.h reload.h output.h defaults.h toplev.h dwarfout.h
+dwarf2out.o : dwarf2out.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) dwarf2.h \
+ flags.h insn-config.h reload.h output.h defaults.h \
+ hard-reg-set.h $(REGS_H) $(EXPR_H) toplev.h dwarf2out.h dyn-string.h
+xcoffout.o : xcoffout.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) xcoffout.h \
+ flags.h toplev.h output.h dbxout.h
+emit-rtl.o : emit-rtl.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \
+ except.h function.h $(REGS_H) insn-config.h $(RECOG_H) real.h \
+ $(EXPR_H) obstack.h hard-reg-set.h bitmap.h
+real.o : real.c $(CONFIG_H) system.h $(TREE_H) toplev.h
+getpwd.o : getpwd.c $(CONFIG_H) system.h
+
+integrate.o : integrate.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h \
+ integrate.h insn-flags.h insn-config.h $(EXPR_H) real.h $(REGS_H) \
+ function.h output.h $(RECOG_H) except.h toplev.h
+
+jump.o : jump.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h $(REGS_H) \
+ insn-config.h insn-flags.h $(RECOG_H) $(EXPR_H) real.h except.h \
+ toplev.h insn-attr.h
+stupid.o : stupid.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h \
+ flags.h toplev.h
+
+cse.o : cse.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \
+ real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h output.h
+gcse.o : gcse.c $(CONFIG_H) system.h $(RTL_H) $(REGS_H) hard-reg-set.h flags.h \
+ real.h insn-config.h $(RECOG_H) $(EXPR_H) $(BASIC_BLOCK_H) output.h
+profile.o : profile.c $(CONFIG_H) system.h $(RTL_H) flags.h insn-flags.h \
+ gcov-io.h $(TREE_H) output.h $(REGS_H) toplev.h
+loop.o : loop.c $(CONFIG_H) system.h $(RTL_H) flags.h loop.h insn-config.h \
+ insn-flags.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) real.h \
+ toplev.h
+unroll.o : unroll.c $(CONFIG_H) system.h $(RTL_H) insn-config.h \
+ integrate.h $(REGS_H) $(RECOG_H) flags.h $(EXPR_H) loop.h toplev.h
+flow.o : flow.c $(CONFIG_H) system.h $(RTL_H) flags.h insn-config.h \
+ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h output.h toplev.h
+combine.o : combine.c $(CONFIG_H) system.h $(RTL_H) flags.h \
+ insn-config.h insn-flags.h insn-codes.h insn-attr.h $(REGS_H) $(EXPR_H) \
+ $(BASIC_BLOCK_H) $(RECOG_H) real.h hard-reg-set.h toplev.h
+regclass.o : regclass.c $(CONFIG_H) system.h $(RTL_H) hard-reg-set.h flags.h \
+ $(BASIC_BLOCK_H) $(REGS_H) insn-config.h $(RECOG_H) reload.h real.h toplev.h \
+ output.h
+local-alloc.o : local-alloc.c $(CONFIG_H) system.h $(RTL_H) flags.h \
+ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) output.h \
+ insn-attr.h toplev.h
+bitmap.o : bitmap.c $(CONFIG_H) system.h $(RTL_H) flags.h $(BASIC_BLOCK_H) \
+ $(REGS_H)
+global.o : global.c $(CONFIG_H) system.h $(RTL_H) flags.h \
+ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h insn-config.h output.h toplev.h
+varray.o : varray.c $(CONFIG_H) system.h varray.h $(RTL_H) $(TREE_H) bitmap.h
+
+reload.o : reload.c $(CONFIG_H) system.h $(RTL_H) flags.h output.h $(EXPR_H) \
+ reload.h $(RECOG_H) hard-reg-set.h insn-config.h insn-codes.h $(REGS_H) \
+ real.h toplev.h
+reload1.o : reload1.c $(CONFIG_H) system.h $(RTL_H) real.h flags.h $(EXPR_H) \
+ reload.h $(REGS_H) hard-reg-set.h insn-config.h insn-flags.h insn-codes.h \
+ $(BASIC_BLOCK_H) $(RECOG_H) output.h toplev.h
+caller-save.o : caller-save.c $(CONFIG_H) system.h $(RTL_H) flags.h \
+ $(REGS_H) hard-reg-set.h insn-config.h $(BASIC_BLOCK_H) \
+ $(RECOG_H) reload.h $(EXPR_H) toplev.h
+reorg.o : reorg.c $(CONFIG_H) system.h $(RTL_H) conditions.h hard-reg-set.h \
+ $(BASIC_BLOCK_H) $(REGS_H) insn-config.h insn-attr.h \
+ insn-flags.h $(RECOG_H) flags.h output.h $(EXPR_H)
+alias.o : alias.c $(CONFIG_H) system.h $(RTL_H) flags.h hard-reg-set.h \
+ $(REGS_H) toplev.h $(EXPR_H)
+regmove.o : regmove.c $(CONFIG_H) system.h $(RTL_H) insn-config.h \
+ $(RECOG_H) output.h reload.h $(REGS_H) hard-reg-set.h flags.h \
+ $(EXPR_H) insn-flags.h $(BASIC_BLOCK_H) toplev.h
+$(SCHED_PREFIX)sched.o : $(SCHED_PREFIX)sched.c $(CONFIG_H) system.h $(RTL_H) \
+ $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h insn-attr.h \
+ toplev.h
+final.o : final.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) flags.h $(REGS_H) \
+ $(RECOG_H) conditions.h insn-config.h insn-attr.h except.h real.h output.h \
+ hard-reg-set.h insn-flags.h insn-codes.h gstab.h xcoffout.h defaults.h \
+ toplev.h reload.h dwarfout.h dwarf2out.h sdbout.h dbxout.h
+recog.o : recog.c $(CONFIG_H) system.h $(RTL_H) \
+ $(REGS_H) $(RECOG_H) hard-reg-set.h flags.h insn-config.h insn-attr.h \
insn-flags.h insn-codes.h real.h
-reg-stack.o : reg-stack.c $(CONFIG_H) $(RTL_H) $(TREE_H) \
- regs.h hard-reg-set.h flags.h insn-config.h
+reg-stack.o : reg-stack.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) \
+ $(REGS_H) hard-reg-set.h flags.h insn-config.h insn-flags.h toplev.h
+dyn-string.o: dyn-string.c dyn-string.h $(CONFIG_H) system.h gansidecl.h
$(out_object_file): $(out_file) $(CONFIG_H) $(TREE_H) \
- $(RTL_H) regs.h hard-reg-set.h real.h insn-config.h conditions.h \
- insn-flags.h output.h insn-attr.h insn-codes.h
+ $(RTL_H) $(REGS_H) hard-reg-set.h real.h insn-config.h conditions.h \
+ insn-flags.h output.h insn-attr.h insn-codes.h system.h toplev.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(out_file)
# Build auxiliary files that support ecoff format.
mips-tfile: mips-tfile.o version.o $(LIBDEPS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ mips-tfile.o version.o $(LIBS)
-mips-tfile.o : mips-tfile.c $(CONFIG_H) $(RTL_H)
+mips-tfile.o : mips-tfile.c $(CONFIG_H) $(RTL_H) system.h machmode.h
mips-tdump: mips-tdump.o version.o $(LIBDEPS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ mips-tdump.o version.o $(LIBS)
-mips-tdump.o : mips-tdump.c $(CONFIG_H) $(RTL_H)
+mips-tdump.o : mips-tdump.c $(CONFIG_H) $(RTL_H) system.h
# Build file to support OSF/rose half-pic format.
-halfpic.o: halfpic.c $(CONFIG_H) $(RTL_H) $(TREE_H)
+halfpic.o: halfpic.c $(CONFIG_H) $(RTL_H) $(TREE_H) system.h
# Normally this target is not used; but it is used if you
# define ALLOCA=alloca.o. In that case, you must get a suitable alloca.c
@@ -1274,7 +1524,7 @@ alloca.o: alloca.c
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(ALLOCA_FLAGS) \
-c `echo $(srcdir)/alloca.c | sed 's,^\./,,'`
$(ALLOCA_FINISH)
-
+#
# Generate header and source files from the machine description,
# and compile them.
@@ -1289,7 +1539,7 @@ alloca.o: alloca.c
# Each of the other insn-* files is handled by a similar pair of rules.
# This causes an anomaly in the results of make -n
-# because insn-* is older than stamp-*
+# because insn-* is older than s-*
# and thus make -n thinks that insn-* will be updated
# and force recompilation of things that depend on it.
# We use move-if-change precisely to avoid such recompilation.
@@ -1301,84 +1551,84 @@ alloca.o: alloca.c
# versions of make which don't like empty commands (nothing after the
# trailing `;'), we call true for each.
-insn-config.h: stamp-config ; @true
-stamp-config : $(md_file) genconfig $(srcdir)/move-if-change
+insn-config.h: s-config ; @true
+s-config : $(md_file) genconfig $(srcdir)/move-if-change
./genconfig $(md_file) > tmp-config.h
$(srcdir)/move-if-change tmp-config.h insn-config.h
- touch stamp-config
+ touch s-config
-insn-flags.h: stamp-flags ; @true
-stamp-flags : $(md_file) genflags $(srcdir)/move-if-change
+insn-flags.h: s-flags ; @true
+s-flags : $(md_file) genflags $(srcdir)/move-if-change
./genflags $(md_file) > tmp-flags.h
$(srcdir)/move-if-change tmp-flags.h insn-flags.h
- touch stamp-flags
+ touch s-flags
-insn-codes.h: stamp-codes ; @true
-stamp-codes : $(md_file) gencodes $(srcdir)/move-if-change
+insn-codes.h: s-codes ; @true
+s-codes : $(md_file) gencodes $(srcdir)/move-if-change
./gencodes $(md_file) > tmp-codes.h
$(srcdir)/move-if-change tmp-codes.h insn-codes.h
- touch stamp-codes
+ touch s-codes
-insn-emit.o : insn-emit.c $(CONFIG_H) $(RTL_H) expr.h real.h output.h \
- insn-config.h insn-flags.h insn-codes.h
+insn-emit.o : insn-emit.c $(CONFIG_H) $(RTL_H) $(EXPR_H) real.h output.h \
+ insn-config.h insn-flags.h insn-codes.h system.h reload.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-emit.c
-insn-emit.c: stamp-emit ; @true
-stamp-emit : $(md_file) genemit $(srcdir)/move-if-change
+insn-emit.c: s-emit ; @true
+s-emit : $(md_file) genemit $(srcdir)/move-if-change
./genemit $(md_file) > tmp-emit.c
$(srcdir)/move-if-change tmp-emit.c insn-emit.c
- touch stamp-emit
+ touch s-emit
-insn-recog.o : insn-recog.c $(CONFIG_H) $(RTL_H) insn-config.h recog.h \
- real.h output.h flags.h
+insn-recog.o : insn-recog.c $(CONFIG_H) $(RTL_H) insn-config.h $(RECOG_H) \
+ real.h output.h flags.h system.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-recog.c
-insn-recog.c: stamp-recog ; @true
-stamp-recog : $(md_file) genrecog $(srcdir)/move-if-change
+insn-recog.c: s-recog ; @true
+s-recog : $(md_file) genrecog $(srcdir)/move-if-change
./genrecog $(md_file) > tmp-recog.c
$(srcdir)/move-if-change tmp-recog.c insn-recog.c
- touch stamp-recog
+ touch s-recog
insn-opinit.o : insn-opinit.c $(CONFIG_H) $(RTL_H) insn-codes.h insn-flags.h \
- insn-config.h flags.h rtl.h recog.h expr.h reload.h
+ insn-config.h flags.h $(RECOG_H) $(EXPR_H) reload.h system.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-opinit.c
-insn-opinit.c: stamp-opinit ; @true
-stamp-opinit : $(md_file) genopinit $(srcdir)/move-if-change
+insn-opinit.c: s-opinit ; @true
+s-opinit : $(md_file) genopinit $(srcdir)/move-if-change
./genopinit $(md_file) > tmp-opinit.c
$(srcdir)/move-if-change tmp-opinit.c insn-opinit.c
- touch stamp-opinit
+ touch s-opinit
-insn-extract.o : insn-extract.c $(CONFIG_H) $(RTL_H)
+insn-extract.o : insn-extract.c $(CONFIG_H) $(RTL_H) system.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-extract.c
-insn-extract.c: stamp-extract ; @true
-stamp-extract : $(md_file) genextract $(srcdir)/move-if-change
+insn-extract.c: s-extract ; @true
+s-extract : $(md_file) genextract $(srcdir)/move-if-change
./genextract $(md_file) > tmp-extract.c
$(srcdir)/move-if-change tmp-extract.c insn-extract.c
- touch stamp-extract
+ touch s-extract
-insn-peep.o : insn-peep.c $(CONFIG_H) $(RTL_H) regs.h output.h real.h
+insn-peep.o : insn-peep.c $(CONFIG_H) $(RTL_H) $(REGS_H) output.h real.h system.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-peep.c
-insn-peep.c: stamp-peep ; @true
-stamp-peep : $(md_file) genpeep $(srcdir)/move-if-change
+insn-peep.c: s-peep ; @true
+s-peep : $(md_file) genpeep $(srcdir)/move-if-change
./genpeep $(md_file) > tmp-peep.c
$(srcdir)/move-if-change tmp-peep.c insn-peep.c
- touch stamp-peep
+ touch s-peep
-insn-attrtab.o : insn-attrtab.c $(CONFIG_H) $(RTL_H) regs.h real.h output.h \
- insn-attr.h insn-config.h
+insn-attrtab.o : insn-attrtab.c $(CONFIG_H) $(RTL_H) $(REGS_H) real.h output.h \
+ insn-attr.h insn-config.h system.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-attrtab.c
-insn-attr.h: stamp-attr ; @true
-stamp-attr : $(md_file) genattr $(srcdir)/move-if-change
+insn-attr.h: s-attr ; @true
+s-attr : $(md_file) genattr $(srcdir)/move-if-change
./genattr $(md_file) > tmp-attr.h
$(srcdir)/move-if-change tmp-attr.h insn-attr.h
- touch stamp-attr
+ touch s-attr
-insn-attrtab.c: stamp-attrtab ; @true
-stamp-attrtab : $(md_file) genattrtab $(srcdir)/move-if-change
+insn-attrtab.c: s-attrtab ; @true
+s-attrtab : $(md_file) genattrtab $(srcdir)/move-if-change
if cmp -s $(PREMADE_ATTRTAB_MD) $(md_file); \
then \
echo Using $(PREMADE_ATTRTAB); \
@@ -1387,19 +1637,30 @@ stamp-attrtab : $(md_file) genattrtab $(srcdir)/move-if-change
./genattrtab $(md_file) > tmp-attrtab.c; \
fi
$(srcdir)/move-if-change tmp-attrtab.c insn-attrtab.c
- touch stamp-attrtab
+ touch s-attrtab
-insn-output.o : insn-output.c $(CONFIG_H) $(RTL_H) regs.h real.h conditions.h \
- hard-reg-set.h insn-config.h insn-flags.h insn-attr.h output.h recog.h \
- insn-codes.h
+insn-output.o : insn-output.c $(CONFIG_H) $(RTL_H) $(REGS_H) real.h conditions.h \
+ hard-reg-set.h insn-config.h insn-flags.h insn-attr.h output.h $(RECOG_H) \
+ insn-codes.h system.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c insn-output.c
-insn-output.c: stamp-output ; @true
-stamp-output : $(md_file) genoutput $(srcdir)/move-if-change
+insn-output.c: s-output ; @true
+s-output : $(md_file) genoutput $(srcdir)/move-if-change
./genoutput $(md_file) > tmp-output.c
$(srcdir)/move-if-change tmp-output.c insn-output.c
- touch stamp-output
-
+ touch s-output
+
+genrtl.o : genrtl.c $(CONFIG_H) $(RTL_H) system.h
+genrtl.c genrtl.h : s-genrtl
+ @true # force gnu make to recheck modification times.
+
+s-genrtl: gengenrtl $(srcdir)/move-if-change $(RTL_BASE_H)
+ ./gengenrtl tmp-genrtl.h tmp-genrtl.c
+ $(srcdir)/move-if-change tmp-genrtl.h genrtl.h
+ $(srcdir)/move-if-change tmp-genrtl.c genrtl.c
+ touch s-genrtl
+
+#
# Compile the programs that generate insn-* from the machine description.
# They are compiled with $(HOST_CC), and associated libraries,
# since they need to run on this machine
@@ -1416,88 +1677,96 @@ $(MD_FILE): $(MD_DEPS)
$(MD_CPP) $(MD_CPPFLAGS) $(md_file) | sed 's/^# /; /g' > tmp-$@
mv tmp-$@ $@
-genconfig : genconfig.o $(HOST_RTL) $(HOST_LIBDEPS)
+genconfig : genconfig.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- genconfig.o $(HOST_RTL) $(HOST_LIBS)
+ genconfig.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS)
-genconfig.o : genconfig.c $(RTL_H) $(build_xm_file)
+genconfig.o : genconfig.c $(RTL_H) $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genconfig.c
-genflags : genflags.o $(HOST_RTL) $(HOST_LIBDEPS)
+genflags : genflags.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- genflags.o $(HOST_RTL) $(HOST_LIBS)
+ genflags.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS)
-genflags.o : genflags.c $(RTL_H) $(build_xm_file)
+genflags.o : genflags.c $(RTL_H) $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genflags.c
-gencodes : gencodes.o $(HOST_RTL) $(HOST_LIBDEPS)
+gencodes : gencodes.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- gencodes.o $(HOST_RTL) $(HOST_LIBS)
+ gencodes.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS)
-gencodes.o : gencodes.c $(RTL_H) $(build_xm_file)
+gencodes.o : gencodes.c $(RTL_H) $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/gencodes.c
-genemit : genemit.o $(HOST_RTL) $(HOST_LIBDEPS)
+genemit : genemit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- genemit.o $(HOST_RTL) $(HOST_LIBS)
+ genemit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS)
-genemit.o : genemit.c $(RTL_H) $(build_xm_file)
+genemit.o : genemit.c $(RTL_H) $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genemit.c
-genopinit : genopinit.o $(HOST_RTL) $(HOST_LIBDEPS)
+genopinit : genopinit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- genopinit.o $(HOST_RTL) $(HOST_LIBS)
+ genopinit.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS)
-genopinit.o : genopinit.c $(RTL_H) $(build_xm_file)
+genopinit.o : genopinit.c $(RTL_H) $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genopinit.c
-genrecog : genrecog.o $(HOST_RTL) $(HOST_LIBDEPS)
+genrecog : genrecog.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- genrecog.o $(HOST_RTL) $(HOST_LIBS)
+ genrecog.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS)
-genrecog.o : genrecog.c $(RTL_H) $(build_xm_file)
+genrecog.o : genrecog.c $(RTL_H) $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genrecog.c
-genextract : genextract.o $(HOST_RTL) $(HOST_LIBDEPS)
+genextract : genextract.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- genextract.o $(HOST_RTL) $(HOST_LIBS)
+ genextract.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS)
-genextract.o : genextract.c $(RTL_H) $(build_xm_file) insn-config.h
+genextract.o : genextract.c $(RTL_H) $(build_xm_file) system.h insn-config.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genextract.c
-genpeep : genpeep.o $(HOST_RTL) $(HOST_LIBDEPS)
+genpeep : genpeep.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- genpeep.o $(HOST_RTL) $(HOST_LIBS)
+ genpeep.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS)
-genpeep.o : genpeep.c $(RTL_H) $(build_xm_file)
+genpeep.o : genpeep.c $(RTL_H) $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genpeep.c
-genattr : genattr.o $(HOST_RTL) $(HOST_LIBDEPS)
+genattr : genattr.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- genattr.o $(HOST_RTL) $(HOST_LIBS)
+ genattr.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS)
-genattr.o : genattr.c $(RTL_H) $(build_xm_file)
+genattr.o : genattr.c $(RTL_H) $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genattr.c
genattrtab : genattrtab.o $(HOST_RTL) $(HOST_PRINT) $(HOST_RTLANAL) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
genattrtab.o $(HOST_RTL) $(HOST_PRINT) $(HOST_RTLANAL) $(HOST_LIBS)
-genattrtab.o : genattrtab.c $(RTL_H) $(build_xm_file) insn-config.h
+genattrtab.o : genattrtab.c $(RTL_H) $(build_xm_file) system.h insn-config.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genattrtab.c
-genoutput : genoutput.o $(HOST_RTL) $(HOST_LIBDEPS)
+genoutput : genoutput.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBDEPS)
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- genoutput.o $(HOST_RTL) $(HOST_LIBS)
+ genoutput.o $(HOST_RTL) $(HOST_PRINT) $(HOST_LIBS)
-genoutput.o : genoutput.c $(RTL_H) $(build_xm_file)
+genoutput.o : genoutput.c $(RTL_H) $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genoutput.c
-
+
+gengenrtl : gengenrtl.o $(HOST_LIBDEPS)
+ $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
+ gengenrtl.o $(HOST_LIBS)
+
+gengenrtl.o : gengenrtl.c $(RTL_BASE_H) system.h
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/gengenrtl.c
+
+#
# Compile the libraries to be used by gen*.
# If we are not cross-building, gen* use the same .o's that cc1 will use,
# and HOST_PREFIX_1 is `foobar', just to ensure these rules don't conflict
# with the rules for rtl.o, alloca.o, etc.
-$(HOST_PREFIX_1)rtl.o: $(srcdir)/rtl.c $(CONFIG_H) $(RTL_H)
+$(HOST_PREFIX_1)rtl.o: $(srcdir)/rtl.c $(CONFIG_H) system.h $(RTL_H) bitmap.h
rm -f $(HOST_PREFIX)rtl.c
sed -e 's/config[.]h/hconfig.h/' $(srcdir)/rtl.c > $(HOST_PREFIX)rtl.c
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)rtl.c
@@ -1507,6 +1776,12 @@ $(HOST_PREFIX_1)print-rtl.o: $(srcdir)/print-rtl.c $(CONFIG_H) $(RTL_H)
sed -e 's/config[.]h/hconfig.h/' $(srcdir)/print-rtl.c > $(HOST_PREFIX)print-rtl.c
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)print-rtl.c
+$(HOST_PREFIX_1)bitmap.o: $(srcdir)/bitmap.c $(CONFIG_H) system.h $(RTL_H) \
+ flags.h $(BASIC_BLOCK_H) $(REGS_H)
+ rm -f $(HOST_PREFIX)bitmap.c
+ sed -e 's/config[.]h/hconfig.h/' $(srcdir)/bitmap.c > $(HOST_PREFIX)bitmap.c
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)bitmap.c
+
$(HOST_PREFIX_1)rtlanal.o: $(srcdir)/rtlanal.c $(CONFIG_H) $(RTL_H)
rm -f $(HOST_PREFIX)rtlanal.c
sed -e 's/config[.]h/hconfig.h/' $(srcdir)/rtlanal.c > $(HOST_PREFIX)rtlanal.c
@@ -1522,6 +1797,16 @@ $(HOST_PREFIX_1)obstack.o: obstack.c
sed -e 's/config[.]h/hconfig.h/' $(srcdir)/obstack.c > $(HOST_PREFIX)obstack.c
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)obstack.c
+$(HOST_PREFIX_1)vfprintf.o: vfprintf.c
+ rm -f $(HOST_PREFIX)vfprintf.c
+ sed -e 's/config[.]h/hconfig.h/' $(srcdir)/vfprintf.c > $(HOST_PREFIX)vfprintf.c
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)vfprintf.c
+
+$(HOST_PREFIX_1)doprint.o: doprint.c
+ rm -f $(HOST_PREFIX)doprint.c
+ sed -e 's/config[.]h/hconfig.h/' $(srcdir)/doprint.c > $(HOST_PREFIX)doprint.c
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)doprint.c
+
$(HOST_PREFIX_1)malloc.o: malloc.c
rm -f $(HOST_PREFIX)malloc.c
sed -e 's/config[.]h/hconfig.h/' $(srcdir)/malloc.c > $(HOST_PREFIX)malloc.c
@@ -1531,158 +1816,94 @@ $(HOST_PREFIX_1)malloc.o: malloc.c
# that does not need to compile alloca, malloc or whatever.
$(HOST_PREFIX_1):
touch $(HOST_PREFIX_1)
-
-# Remake bytecode files.
-BI_OBJ=bi-parser.o bi-lexer.o bi-reverse.o
-
-bc-emit.o : bc-emit.c $(CONFIG_H) $(RTL_H) real.h $(BYTECODE_H) \
- bc-arity.h bc-opcode.h bc-typecd.h bc-typecd.def bi-run.h bytetypes.h
-bc-optab.o : bc-optab.c $(CONFIG_H) $(REAL_H) $(BYTECODE_H) \
- bc-opcode.h bc-typecd.h bc-typecd.def
-bi-arity: bi-arity.o $(BI_OBJ) $(HOST_LIBDEPS)
- $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- bi-arity.o $(BI_OBJ) $(HOST_LIBS)
-bi-opcode: bi-opcode.o $(BI_OBJ) $(HOST_LIBDEPS)
- $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- bi-opcode.o $(BI_OBJ) $(HOST_LIBS)
-bi-opname: bi-opname.o $(BI_OBJ) $(HOST_LIBDEPS)
- $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
- bi-opname.o $(BI_OBJ) $(HOST_LIBS)
-
-$(srcdir)/bi-parser.h: $(srcdir)/bi-parser.c
-$(srcdir)/bi-parser.c: $(srcdir)/bi-parser.y
- cd $(srcdir); $(BISON) $(BISONFLAGS) -d bi-parser.y -o bi-parser.c
-
-bi-parser.o: $(srcdir)/bi-parser.c bi-defs.h $(build_xm_file)
- $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \
- $(srcdir)/bi-parser.c
-bi-lexer.o: bi-lexer.c $(srcdir)/bi-parser.h $(build_xm_file)
- $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \
- $(srcdir)/bi-lexer.c
-bi-arity.o: bi-arity.c bi-defs.h $(build_xm_file)
- $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \
- $(srcdir)/bi-arity.c
-bi-opcode.o: bi-opcode.c bi-defs.h $(build_xm_file)
- $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \
- $(srcdir)/bi-opcode.c
-bi-opname.o: bi-opname.c bi-defs.h $(build_xm_file)
- $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \
- $(srcdir)/bi-opname.c
-bi-reverse.o: bi-reverse.c bi-defs.h
- $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \
- $(srcdir)/bi-reverse.c
-
-bc-arity.h: stamp-bcarity ; @true
-stamp-bcarity : $(srcdir)/bytecode.def bi-arity $(srcdir)/move-if-change
- ./bi-arity < $(srcdir)/bytecode.def >tmp-bc-arity.h
- $(srcdir)/move-if-change tmp-bc-arity.h bc-arity.h
- touch stamp-bcarity
-
-bc-opcode.h: stamp-bcopcode ; @true
-stamp-bcopcode : $(srcdir)/bytecode.def bi-opcode $(srcdir)/move-if-change
- ./bi-opcode < $(srcdir)/bytecode.def >tmp-bcopcd.h
- $(srcdir)/move-if-change tmp-bcopcd.h bc-opcode.h
- touch stamp-bcopcode
-
-bc-opname.h: stamp-bcopname ; @true
-stamp-bcopname : $(srcdir)/bytecode.def bi-opname $(srcdir)/move-if-change
- ./bi-opname < $(srcdir)/bytecode.def >tmp-bcopnm.h
- $(srcdir)/move-if-change tmp-bcopnm.h bc-opname.h
- touch stamp-bcopname
-
-bytecode.mostlyclean:
- -rm -f bc-arity.h bc-opcode.h bc-opname.h
-
-bytecode.distclean bytecode.clean: bytecode.mostlyclean
- -rm -f bi-arity bi-opcode bi-opname bi-lexer
-
-bytecode.maintainer-clean: bytecode.clean
- -rm -f bi-parser.c bi-parser.h
-
-
+#
# Remake cpp and protoize.
# Making the preprocessor
-cpp: $(CCCP)
+cpp$(exeext): $(CCCP)$(exeext)
-rm -f cpp$(exeext)
- ln $(CCCP)$(exeext) cpp$(exeext) > /dev/null 2>&1 \
- || cp $(CCCP)$(exeext) cpp$(exeext)
-cccp: cccp.o cexp.o version.o $(LIBDEPS)
- $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ cccp.o cexp.o \
+ $(LN) $(CCCP)$(exeext) cpp$(exeext)
+cccp$(exeext): cccp.o cexp.o version.o prefix.o $(LIBDEPS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ cccp.o cexp.o prefix.o \
version.o $(LIBS)
-cexp.o: $(srcdir)/cexp.c $(CONFIG_H)
+cexp.o: $(srcdir)/cexp.c $(CONFIG_H) system.h gansidecl.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -c $(srcdir)/cexp.c
$(srcdir)/cexp.c: $(srcdir)/cexp.y
cd $(srcdir); $(BISON) -o cexp.c cexp.y
-cccp.o: cccp.c $(CONFIG_H) pcp.h version.c config.status
-# The reason we use $(libdir)/g++-include rather than using libsubdir
-# is for compatibility with the current version of libg++.
+cccp.o: cccp.c $(CONFIG_H) pcp.h version.c config.status system.h gansidecl.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
-DGCC_INCLUDE_DIR=\"$(libsubdir)/include\" \
-DGPLUSPLUS_INCLUDE_DIR=\"$(gxx_include_dir)\" \
+ -DOLD_GPLUSPLUS_INCLUDE_DIR=\"$(old_gxx_include_dir)\" \
-DLOCAL_INCLUDE_DIR=\"$(includedir)\" \
- -DCROSS_INCLUDE_DIR=\"$(libsubdir)/sys-include\" \
+ -DCROSS_INCLUDE_DIR=\"$(tooldir)/sys-include\" \
-DTOOL_INCLUDE_DIR=\"$(tooldir)/include\" \
-c `echo $(srcdir)/cccp.c | sed 's,^\./,,'`
-cppmain: cppmain.o cpplib.o cpphash.o cppalloc.o cpperror.o cppexp.o \
- version.o $(LIBDEPS)
+cppmain$(exeext): cppmain.o cpplib.o cpphash.o cppalloc.o cpperror.o cppexp.o \
+ prefix.o version.o $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ cppmain.o cpplib.o cpphash.o \
- cppalloc.o cpperror.o cppexp.o version.o $(LIBS)
+ cppalloc.o cpperror.o cppexp.o prefix.o version.o $(LIBS)
-cpplib.o: cpplib.c $(CONFIG_H) cpplib.h cpphash.h config.status
+cppmain.o: cppmain.c $(CONFIG_H) cpplib.h system.h gansidecl.h
+
+cpplib.o: cpplib.c $(CONFIG_H) cpplib.h cpphash.h config.status system.h \
+ gansidecl.h
$(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
-DGCC_INCLUDE_DIR=\"$(libsubdir)/include\" \
-DGPLUSPLUS_INCLUDE_DIR=\"$(gxx_include_dir)\" \
+ -DOLD_GPLUSPLUS_INCLUDE_DIR=\"$(old_gxx_include_dir)\" \
-DLOCAL_INCLUDE_DIR=\"$(includedir)\" \
- -DCROSS_INCLUDE_DIR=\"$(libsubdir)/sys-include\" \
+ -DCROSS_INCLUDE_DIR=\"$(tooldir)/sys-include\" \
-DTOOL_INCLUDE_DIR=\"$(tooldir)/include\" \
-c `echo $(srcdir)/cpplib.c | sed 's,^\./,,'`
-cpperror.o: cpperror.c $(CONFIG_H) cpplib.h
+cpperror.o: cpperror.c $(CONFIG_H) cpplib.h system.h gansidecl.h
-cppexp.o: cppexp.c $(CONFIG_H) cpplib.h
+cppexp.o: cppexp.c $(CONFIG_H) cpplib.h system.h gansidecl.h
-cpphash.o: cpphash.c cpplib.h cpphash.h
+cpphash.o: cpphash.c cpplib.h cpphash.h $(CONFIG_H) system.h gansidecl.h
-cppalloc.o: cppalloc.c $(CONFIG_H)
+cppalloc.o: cppalloc.c $(CONFIG_H) cpplib.h system.h gansidecl.h
# Note for the stamp targets, we run the program `true' instead of
# having an empty command (nothing following the semicolon).
-proto: config.status protoize unprotoize SYSCALLS.c.X
+proto: config.status protoize$(exeext) unprotoize$(exeext) SYSCALLS.c.X
-protoize: protoize.o getopt.o getopt1.o getpwd.o version.o $(LIBDEPS)
+protoize$(exeext): protoize.o getopt.o getopt1.o getpwd.o version.o \
+ pexecute.o choose-temp.o mkstemp.o $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \
- protoize.o getopt.o getopt1.o getpwd.o version.o $(LIBS)
-protoize.o: stamp-proto ; @true
+ protoize.o getopt.o getopt1.o getpwd.o version.o \
+ pexecute.o choose-temp.o mkstemp.o $(LIBS)
-unprotoize: unprotoize.o getopt.o getopt1.o getpwd.o version.o $(LIBDEPS)
+unprotoize$(exeext): unprotoize.o getopt.o getopt1.o getpwd.o version.o \
+ pexecute.o choose-temp.o mkstemp.o $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \
- unprotoize.o getopt.o getopt1.o getpwd.o version.o $(LIBS)
-unprotoize.o: stamp-proto ; @true
+ unprotoize.o getopt.o getopt1.o getpwd.o version.o \
+ pexecute.o choose-temp.o mkstemp.o $(LIBS)
-stamp-proto: protoize.c getopt.h $(CONFIG_H)
+protoize.o: protoize.c getopt.h $(CONFIG_H) system.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
-DGCC_INCLUDE_DIR=\"$(libsubdir)/include\" \
-DGPLUSPLUS_INCLUDE_DIR=\"$(gxx_include_dir)\" \
- -DCROSS_INCLUDE_DIR=\"$(libsubdir)/sys-include\" \
+ -DCROSS_INCLUDE_DIR=\"$(tooldir)/sys-include\" \
-DTOOL_INCLUDE_DIR=\"$(tooldir)/include\" \
-DLOCAL_INCLUDE_DIR=\"$(includedir)\" \
-DSTD_PROTO_DIR=\"$(libsubdir)\" \
- -DUNPROTOIZE $(srcdir)/protoize.c
- mv protoize$(objext) unprotoize$(objext)
+ $(srcdir)/protoize.c
+
+unprotoize.o: unprotoize.c protoize.c getopt.h $(CONFIG_H) system.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
-DGCC_INCLUDE_DIR=\"$(libsubdir)/include\" \
-DGPLUSPLUS_INCLUDE_DIR=\"$(gxx_include_dir)\" \
- -DCROSS_INCLUDE_DIR=\"$(libsubdir)/sys-include\" \
+ -DCROSS_INCLUDE_DIR=\"$(tooldir)/sys-include\" \
-DTOOL_INCLUDE_DIR=\"$(tooldir)/include\" \
-DLOCAL_INCLUDE_DIR=\"$(includedir)\" \
-DSTD_PROTO_DIR=\"$(libsubdir)\" \
- $(srcdir)/protoize.c
- touch stamp-proto
+ $(srcdir)/unprotoize.c
getopt.o: getopt.c getopt.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/getopt.c
@@ -1723,43 +1944,59 @@ test-protoize-simple: ./protoize ./unprotoize $(GCC_PASSES)
@echo Expect zero differences.
diff $(srcdir)/protoize.c tmp-proto.c | cat
-rm -f tmp-proto.[cs] tmp-proto$(objext)
-
+
+gcov.o: gcov.c gcov-io.h system.h
+
+# Only one of 'gcov' or 'gcov.exe' is actually built, depending
+# upon whether $(exeext) is empty or not.
+gcov$(exeext): gcov.o $(LIBDEPS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) gcov.o $(LIBS) -o $@
+#
# Build the include directory. The stamp files are stmp-* rather than
-# stamp-* so that mostlyclean does not force the include directory to
+# s-* so that mostlyclean does not force the include directory to
# be rebuilt.
-# Build the include directory except for float.h (which depends upon
+# Build the include directory including float.h (which no longer depends upon
# enquire).
-stmp-int-hdrs: stmp-fixinc $(USER_H) xlimits.h objc-headers
+stmp-int-hdrs: stmp-fixinc $(USER_H) xlimits.h gfloat.h
# Copy in the headers provided with gcc.
# The sed command gets just the last file name component;
# this is necessary because VPATH could add a dirname.
# Using basename would be simpler, but some systems don't have it.
- objdir=`pwd`; \
- cd $(srcdir); \
+# The touch command is here to workaround an AIX/Linux NFS bug.
for file in .. $(USER_H); do \
if [ X$$file != X.. ]; then \
realfile=`echo $$file | sed -e 's|.*/\([^/]*\)$$|\1|'`; \
- rm -f $$objdir/include/$$realfile; \
- cp ginclude/$$realfile $$objdir/include; \
- chmod a+r $$objdir/include/$$realfile; \
+ touch include/$$realfile; \
+ rm -f include/$$realfile; \
+ cp $$file include; \
+ chmod a+r include/$$realfile; \
fi; \
done
rm -f include/limits.h
cp xlimits.h include/limits.h
chmod a+r include/limits.h
+ rm -f include/float.h
+ if [ -s gfloat.h ]; then \
+ cp gfloat.h include/float.h && \
+ chmod a+r include/float.h; \
+ else :; fi
# Install the README
rm -f include/README
cp $(srcdir)/README-fixinc include/README
chmod a+r include/README
- touch stmp-int-hdrs
+ touch $@
-# Build the complete include directory.
-stmp-headers: stmp-int-hdrs gfloat.h
- rm -f include/float.h
- cp gfloat.h include/float.h
- chmod a+r include/float.h
- touch stmp-headers
+# Now that gfloat.h no longer depends upon enquire, this is actually a no-op.
+stmp-headers:
+ touch $@
+
+fixinc.sh :
+ DEST=`cd $(srcdir) ; pwd`/$@ CC=$(CC) MAKE=$(MAKE) CFLAGS="$(CFLAGS)" \
+ export DEST CC MAKE CFLAGS ; \
+ echo DEST=$$DEST CC=$$CC MAKE=$$MAKE CFLAGS=$$CFLAGS ; \
+ cd ../contrib/fixinc ; \
+ $(SHELL) mkfixinc.sh $(target) $$DEST
# Build fixed copies of system files.
stmp-fixinc: $(FIXINCLUDES) gsyslimits.h
@@ -1773,6 +2010,12 @@ stmp-fixinc: $(FIXINCLUDES) gsyslimits.h
$(SHELL) $(srcdir)/$(FIXINCLUDES) include $$dir; \
else true; fi; \
done; \
+ if [ x$(INSTALL_ASSERT_H) != x ] ; \
+ then \
+ rm -f include/assert.h; \
+ cp $(srcdir)/assert.h include/assert.h; \
+ chmod a+r include/assert.h; \
+ fi \
else true; \
fi
rm -f include/syslimits.h
@@ -1784,35 +2027,27 @@ stmp-fixinc: $(FIXINCLUDES) gsyslimits.h
chmod a+r include/syslimits.h
touch stmp-fixinc
-# copy objc header files into build directory
-objc-headers: stmp-fixinc
- if [ -d include ]; then true; else mkdir include; fi
- if [ -d objc ]; then true; else mkdir objc; fi
- thisdir1=`pwd`; \
- srcdir1=`cd $(srcdir); pwd`; \
- cd objc; \
- $(MAKE) -f $${srcdir1}/objc/Makefile copy-headers \
- srcdir=$${srcdir1} tooldir=$(tooldir) AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" \
- GCC_FOR_TARGET="$${thisdir1}/xgcc -B$${thisdir1}/" \
- GCC_CFLAGS="$(GCC_CFLAGS)" incinstalldir=$${thisdir1}/include
- touch objc-headers
-
# Files related to the fixproto script.
deduced.h: $(GCC_PASSES) $(srcdir)/scan-types.sh stmp-int-hdrs
- CC="$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) -I. -I$(srcdir) -Iinclude -I${SYSTEM_HEADER_DIR}"; \
+ if [ -d $(SYSTEM_HEADER_DIR) ]; \
+ then \
+ CC="$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) -I. -I$(srcdir) -Iinclude -I${SYSTEM_HEADER_DIR}"; \
export CC; \
- $(SHELL) $(srcdir)/scan-types.sh "$(srcdir)" >tmp-deduced.h
- mv tmp-deduced.h deduced.h
+ $(SHELL) $(srcdir)/scan-types.sh "$(srcdir)" >tmp-deduced.h; \
+ mv tmp-deduced.h deduced.h; \
+ else \
+ touch deduced.h; \
+ fi
gen-protos: gen-protos.o scan.o cppalloc.o $(HOST_LIBDEPS)
${HOST_CC} $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
gen-protos.o scan.o cppalloc.o $(HOST_LIBS)
-gen-protos.o: gen-protos.c scan.h $(build_xm_file)
+gen-protos.o: gen-protos.c scan.h $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/gen-protos.c
-scan.o: scan.c scan.h $(build_xm_file)
+scan.o: scan.c scan.h $(build_xm_file) system.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/scan.c
xsys-protos.h: $(GCC_PASSES) $(srcdir)/sys-protos.h deduced.h gen-protos Makefile
@@ -1825,15 +2060,16 @@ xsys-protos.h: $(GCC_PASSES) $(srcdir)/sys-protos.h deduced.h gen-protos Makefil
rm -rf fixtmp.c
fix-header: fix-header.o scan-decls.o scan.o xsys-protos.h $(HOST_LIBDEPS) \
- cpplib.o cpphash.o cppalloc.o cppexp.o cpperror.o version.o
+ cpplib.o cpphash.o cppalloc.o cppexp.o prefix.o version.o
$(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ fix-header.o \
- scan-decls.o scan.o cpplib.o cpphash.o cppalloc.o version.o \
- cppexp.o $(HOST_LIBS)
+ scan-decls.o scan.o cpplib.o cpphash.o cppalloc.o prefix.o \
+ version.o cppexp.o $(HOST_LIBS)
-fix-header.o: fix-header.c obstack.h scan.h xsys-protos.h $(build_xm_file)
+fix-header.o: fix-header.c obstack.h scan.h xsys-protos.h $(build_xm_file) \
+ system.h cpplib.h cpphash.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/fix-header.c
-scan-decls.o: scan-decls.c scan.h cpplib.h $(build_xm_file)
+scan-decls.o: scan-decls.c scan.h cpplib.h $(build_xm_file) system.h gansidecl.h
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/scan-decls.c
# stmp-fixproto depends on this, not on fix-header directly.
@@ -1857,38 +2093,46 @@ stmp-fixproto: fixhdr.ready fixproto stmp-headers
else \
: This line works around a 'make' bug in BSDI 1.1.; \
FIXPROTO_DEFINES="$(FIXPROTO_DEFINES)"; export FIXPROTO_DEFINES; \
- $(SHELL) ${srcdir}/fixproto include include $(SYSTEM_HEADER_DIR); \
+ if [ -d $(SYSTEM_HEADER_DIR) ] ; then \
+ $(SHELL) ${srcdir}/fixproto include include $(SYSTEM_HEADER_DIR); \
+ else true; fi; \
touch include/fixed; \
fi
touch stmp-fixproto
-
+#
# Remake the info files.
doc: info
-info: $(srcdir)/cpp.info $(srcdir)/gcc.info lang.info
+info: cpp.info gcc.info lang.info
-$(srcdir)/cpp.info: cpp.texi
- cd $(srcdir); $(MAKEINFO) cpp.texi
+cpp.info: $(srcdir)/cpp.texi
+ $(MAKEINFO) $(MAKEINFOFLAGS) -I$(srcdir) -o cpp.info $(srcdir)/cpp.texi
-$(srcdir)/gcc.info: gcc.texi extend.texi install.texi invoke.texi \
- md.texi rtl.texi tm.texi
- cd $(srcdir); $(MAKEINFO) gcc.texi
+gcc.info: $(srcdir)/gcc.texi $(srcdir)/extend.texi $(srcdir)/install.texi \
+ $(srcdir)/invoke.texi $(srcdir)/md.texi $(srcdir)/rtl.texi \
+ $(srcdir)/tm.texi $(srcdir)/gcov.texi
+ $(MAKEINFO) $(MAKEINFOFLAGS) -I$(srcdir) -o gcc.info $(srcdir)/gcc.texi
-dvi: $(srcdir)/gcc.dvi $(srcdir)/cpp.dvi lang.dvi
+dvi: gcc.dvi cpp.dvi lang.dvi
# This works with GNU Make's default rule.
-$(srcdir)/gcc.dvi: gcc.texi extend.texi install.texi invoke.texi \
- md.texi rtl.texi tm.texi
- $(TEXI2DVI) $<
+gcc.dvi: $(srcdir)/gcc.texi $(srcdir)/extend.texi $(srcdir)/install.texi \
+ $(srcdir)/invoke.texi $(srcdir)/md.texi $(srcdir)/rtl.texi \
+ $(srcdir)/tm.texi $(srcdir)/gcov.texi
+ TEXINPUTS=${texidir}:$(srcdir):$$TEXINPUTS tex gcc.texi
+ texindex gcc.??
+ TEXINPUTS=${texidir}:$(srcdir):$$TEXINPUTS tex gcc.texi
+
+cpp.dvi: $(srcdir)/cpp.texi
+ TEXINPUTS=${texidir}:$(srcdir):$$TEXINPUTS tex cpp.texi
+ texindex cpp.??
+ TEXINPUTS=${texidir}:$(srcdir):$$TEXINPUTS tex cpp.texi
-# This works with GNU Make's default rule.
-$(srcdir)/cpp.dvi: cpp.texi
- $(TEXI2DVI) $<
-$(srcdir)/INSTALL: install1.texi install.texi
+INSTALL: $(srcdir)/install1.texi $(srcdir)/install.texi
cd $(srcdir); $(MAKEINFO) -D INSTALLONLY --no-header \
- --no-split install1.texi -o INSTALL
-
+ --no-split -o INSTALL install1.texi
+#
# Deletion of files made during compilation.
# There are four levels of this:
# `mostlyclean', `clean', `distclean' and `maintainer-clean'.
@@ -1898,40 +2142,32 @@ $(srcdir)/INSTALL: install1.texi install.texi
# `clean' deletes everything made by running `make all'.
# `distclean' also deletes the files made by config.
# `maintainer-clean' also deletes everything that could be regenerated
-# automatically. We remove as much from the language subdirectories as we can
+# automatically, except for `configure'.
+# We remove as much from the language subdirectories as we can
# (less duplicated code).
-mostlyclean: bytecode.mostlyclean lang.mostlyclean
+mostlyclean: lang.mostlyclean
-rm -f $(STAGESTUFF)
-# Clean the objc subdir if we created one.
- if [ -d objc ]; then \
- srcdir1=`cd $(srcdir); pwd`; \
- cd objc; $(MAKE) -f $$srcdir1/objc/Makefile mostlyclean; \
- else true; fi
- -rm -f libobjc.a
# Delete the temporary source copies for cross compilation.
-rm -f $(HOST_PREFIX_1)rtl.c $(HOST_PREFIX_1)rtlanal.c
-rm -f $(HOST_PREFIX_1)alloca.c $(HOST_PREFIX_1)malloc.c
-rm -f $(HOST_PREFIX_1)obstack.c
# Delete the temp files made in the course of building libgcc.a.
- -rm -f tmplibgcc* tmpcopy xlimits.h
+ -rm -f tmplibgcc* tmpcopy xlimits.h libgcc1-test
for name in $(LIB1FUNCS); do rm -f $${name}.c; done
-# Delete other temporary files.
- -rm -f tmp-float.h tmp-gcc.xtar.gz
- -rm -f tmp-foo1 tmp-foo2 tmp-proto.* tmp-unproto.1 tmp-SYSCALLS.s
- -rm -f tmp-c-parse.y tmp-objc-prs.y tmp-gperf.h
- -rm -f tmp-specs t-float.h-cross tmp-xlimits.h
- -rm -f tmp-fixtmp.c xsys-protos.hT
-# Delete the stamp files.
- -rm -f stamp-* tmp-*
+# Delete other built files.
+ -rm -f t-float.h-cross xsys-protos.hT fp-bit.c dp-bit.c
+# Delete the stamp and temporary files.
+ -rm -f s-* tmp-* stamp-* stmp-*
-rm -f */stamp-* */tmp-*
# Delete debugging dump files.
-rm -f *.greg *.lreg *.combine *.flow *.cse *.jump *.rtl *.tree *.loop
- -rm -f *.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack
+ -rm -f *.dbr *.jump2 *.sched *.cse2 *.sched2 *.stack *.addressof
+ -rm -f *.regmove *.mach *.bp *.gcse
-rm -f */*.greg */*.lreg */*.combine */*.flow */*.cse */*.jump */*.rtl
-rm -f */*.tree */*.loop */*.dbr */*.jump2 */*.sched */*.cse2
- -rm -f */*.sched2 */*.stack
+ -rm -f */*.sched2 */*.stack */*.regmove */*.gcse
# Delete some files made during installation.
-rm -f specs gfloat.h float.h-* enquire SYSCALLS.c.X SYSCALLS.c
-rm -f collect collect2 mips-tfile mips-tdump alloca.s
@@ -1945,10 +2181,11 @@ mostlyclean: bytecode.mostlyclean lang.mostlyclean
-rm -f gcc.vrs gcc.kys gcc.tps gcc.pgs gcc.fns
# Delete core dumps.
-rm -f core */core
+ -rm -f *.bp */*.bp
# Delete all files made by compilation
# that don't exist in the distribution.
-clean: mostlyclean bytecode.clean lang.clean
+clean: mostlyclean lang.clean
# It may not be quite desirable to delete unprotoize.c here,
# but the spec for `make clean' requires it.
# Using unprotoize.c is not quite right in the first place,
@@ -1961,8 +2198,7 @@ clean: mostlyclean bytecode.clean lang.clean
rm -f md ; \
fi
# Delete the include directory.
- -rm -rf stmp-* include objc-headers
- -rm -f */stmp-*
+ -rm -rf include
# Delete files used by the "multilib" facility (including libgcc subdirs).
-rm -f multilib.h tmpmultilib*
-if [ "x$(MULTILIB_DIRNAMES)" != x ] ; then \
@@ -1970,18 +2206,23 @@ clean: mostlyclean bytecode.clean lang.clean
else if [ "x$(MULTILIB_OPTIONS)" != x ] ; then \
rm -rf `echo $(MULTILIB_OPTIONS) | sed -e 's/\// /g'`; \
fi ; fi
+ -rm -fr stage1 stage2 stage3 stage4
# Delete all files that users would normally create
# while building and installing GCC.
-distclean: clean bytecode.distclean lang.distclean
- -rm -f tm.h config.h tconfig.h hconfig.h md
- -rm -f config.status config.run
+distclean: clean lang.distclean
+ -rm -f tm.h config.h auto-host.h auto-build.h tconfig.h hconfig.h
+ -rm -f md cstamp-h
+ -rm -f config.status config.run config.cache config.bak
+ -rm -f Make-lang Make-hooks Make-host Make-target
-rm -f Makefile specs.h options.h *.oaux
- -rm -fr stage1 stage2 stage3 stage4
+ -rm -f gthr-default.h
-rm -f */stage1 */stage2 */stage3 */stage4 */include
- -rm -f objc-parse.output
-rm -f c-parse.output
-rm -f *.asm
+ -rm -f float.h
+ -rm -f site.exp site.bak testsuite/site.exp testsuite/site.bak
+ -rm -f testsuite/{gcc,g++}.{log,sum}
# Delete anything likely to be found in the source directory
# that shouldn't be in the distribution.
@@ -1993,23 +2234,25 @@ extraclean: distclean lang.extraclean
-rm -f *.dvi *.ps *.oaux *.d *.[zZ] *.gz
-rm -f *.tar *.xtar *diff *.diff.* *.tar.* *.xtar.* *diffs
-rm -f *lose config/*lose config/*/*lose
- -rm -f *.s *.s[0-9] *.i install1.texi config/ChangeLog
+ -rm -f *.s *.s[0-9] *.i config/ChangeLog
-rm -f */=* */"#"* */*~*
-rm -f */patch* */*.orig */*.rej
-rm -f */*.dvi */*.oaux */*.d */*.[zZ] */*.gz
-rm -f */*.tar */*.xtar */*diff */*.diff.* */*.tar.* */*.xtar.* */*diffs
-rm -f */*lose */*.s */*.s[0-9] */*.i
-# Get rid of every file that's generated from some other file.
+# Get rid of every file that's generated from some other file, except for `configure'.
# Most of these files ARE PRESENT in the GCC distribution.
-maintainer-clean: distclean bytecode.maintainer-clean lang.maintainer-clean
- -rm -f c-parse.y c-gperf.h objc-parse.y
- -rm -f objc-parse.c objc-parse.output
+maintainer-clean:
+ @echo 'This command is intended for maintainers to use; it'
+ @echo 'deletes files that may need special tools to rebuild.'
+ $(MAKE) distclean lang.maintainer-clean
+ -rm -f c-parse.y c-gperf.h
-rm -f c-parse.c c-parse.h c-parse.output
-rm -f cexp.c cexp.output TAGS
-rm -f cpp.info* cpp.??s cpp.*aux
-rm -f gcc.info* gcc.??s gcc.*aux
-
+#
# Entry points `install' and `uninstall'.
# Also use `install-collect2' to install collect2 when the config files don't.
@@ -2022,7 +2265,8 @@ install: $(INSTALL_TARGET) ; @true
# Install the driver last so that the window when things are
# broken is small.
install-normal: install-common $(INSTALL_HEADERS) $(INSTALL_LIBGCC) \
- install-libobjc install-man install-info lang.install-normal install-driver
+ $(INSTALL_CPP) install-man install-info lang.install-normal \
+ install-driver
# Do nothing while making gcc with a cross-compiler. The person who
# makes gcc for the target machine has to know how to put a complete
@@ -2034,9 +2278,28 @@ install-build: force
# to finish installation of cross compiler.
install-cross-rest: install-float-h-cross
+# Handle cpp installation.
+install-cpp: cpp.sh
+ -rm -f $(bindir)/cpp
+ $(INSTALL_PROGRAM) -m 755 cpp.sh $(bindir)/cpp
+ if [ x$(cpp_install_dir) != x ]; then \
+ rm -f $(cpp_install_dir)/cpp; \
+ $(INSTALL_PROGRAM) -m 755 cpp.sh $(cpp_install_dir)/cpp; \
+ else true; fi
+
+cpp.sh: $(srcdir)/cpp.in Makefile
+ sed -e 's%@GCC@%'$(GCC_INSTALL_NAME)'%' $(srcdir)/cpp.in > xcpp.T
+ mv -f xcpp.T cpp.sh
+
+uninstall-cpp:
+ -rm -f $(bindir)/cpp
+ -if [ x$(cpp_install_dir) != x ]; then \
+ rm -f $(cpp_install_dir)/cpp; \
+ else true; fi
+
# Install float.h for cross compiler.
# Run this on the target machine!
-install-float-h-cross: install-dir
+install-float-h-cross: installdirs
# if [ -f enquire ] ; then true; else false; fi
# Note: don't use -. We should fail right away if enquire was not made.
./enquire -f > $(tmpdir)/float.h
@@ -2045,15 +2308,18 @@ install-float-h-cross: install-dir
-rm -f $(tmpdir)/float.h
chmod a-x $(libsubdir)/include/float.h
-# Create the installation directory.
-install-dir:
+# Create the installation directories.
+installdirs:
+ -if [ -d $(prefix) ] ; then true ; else mkdir $(prefix) ; chmod a+rx $(prefix) ; fi
+ -if [ -d $(exec_prefix) ] ; then true ; else mkdir $(exec_prefix) ; chmod a+rx $(exec_prefix) ; fi
-if [ -d $(libdir) ] ; then true ; else mkdir $(libdir) ; chmod a+rx $(libdir) ; fi
-if [ -d $(libdir)/gcc-lib ] ; then true ; else mkdir $(libdir)/gcc-lib ; chmod a+rx $(libdir)/gcc-lib ; fi
# This dir isn't currently searched by cpp.
# -if [ -d $(libdir)/gcc-lib/include ] ; then true ; else mkdir $(libdir)/gcc-lib/include ; chmod a+rx $(libdir)/gcc-lib/include ; fi
- -if [ -d $(libdir)/gcc-lib/$(target) ] ; then true ; else mkdir $(libdir)/gcc-lib/$(target) ; chmod a+rx $(libdir)/gcc-lib/$(target) ; fi
- -if [ -d $(libdir)/gcc-lib/$(target)/$(version) ] ; then true ; else mkdir $(libdir)/gcc-lib/$(target)/$(version) ; chmod a+rx $(libdir)/gcc-lib/$(target)/$(version) ; fi
- -if [ -d $(libdir)/gcc-lib/$(target)/$(version)/include ] ; then true ; else mkdir $(libdir)/gcc-lib/$(target)/$(version)/include ; chmod a+rx $(libdir)/gcc-lib/$(target)/$(version)/include ; fi
+ -fdir= ; for dir in `echo $(libsubdir) | tr '/' ' '`; do \
+ fdir=$${fdir}/$${dir}; \
+ if [ -d $${fdir} ] ; then true ; else mkdir $${fdir}; chmod a+rx $${fdir}; fi ; \
+ done
-if [ -d $(bindir) ] ; then true ; else mkdir $(bindir) ; chmod a+rx $(bindir) ; fi
-if [ -d $(includedir) ] ; then true ; else mkdir $(includedir) ; chmod a+rx $(includedir) ; fi
-if [ -d $(tooldir) ] ; then true ; else mkdir $(tooldir) ; chmod a+rx $(tooldir) ; fi
@@ -2067,7 +2333,7 @@ install-dir:
-if [ -d $(mandir) ] ; then true ; else mkdir $(mandir) ; chmod a+rx $(mandir) ; fi
# Install the compiler executables built during cross compilation.
-install-common: native install-dir $(EXTRA_PARTS) lang.install-common
+install-common: native installdirs $(EXTRA_PARTS) lang.install-common
for file in $(COMPILERS); do \
if [ -f $$file ] ; then \
rm -f $(libsubdir)/$$file; \
@@ -2085,30 +2351,46 @@ install-common: native install-dir $(EXTRA_PARTS) lang.install-common
if [ x"$$file" != x.. ]; then \
rm -f $(libsubdir)/$$file; \
$(INSTALL_DATA) $$file $(libsubdir)/$$file; \
+ chmod a-x $(libsubdir)/$$file; \
else true; fi; \
done
# Don't mess with specs if it doesn't exist yet.
-if [ -f specs ] ; then \
rm -f $(libsubdir)/specs; \
$(INSTALL_DATA) specs $(libsubdir)/specs; \
+ chmod a-x $(libsubdir)/specs; \
fi
# Install protoize if it was compiled.
-if [ -f protoize$(exeext) ]; \
then \
- rm -f $(bindir)/protoize$(exeext); \
- $(INSTALL_PROGRAM) protoize$(exeext) $(bindir)/protoize$(exeext); \
- rm -f $(bindir)/unprotoize$(exeext); \
- $(INSTALL_PROGRAM) unprotoize$(exeext) $(bindir)/unprotoize$(exeext); \
+ if [ -f gcc-cross$(exeext) ] ; then \
+ rm -f $(bindir)/$(PROTOIZE_CROSS_NAME)$(exeext); \
+ $(INSTALL_PROGRAM) protoize$(exeext) $(bindir)/$(PROTOIZE_CROSS_NAME)$(exeext); \
+ rm -f $(bindir)/$(UNPROTOIZE_CROSS_NAME)$(exeext); \
+ $(INSTALL_PROGRAM) unprotoize$(exeext) $(bindir)/$(UNPROTOIZE_CROSS_NAME)$(exeext); \
+ else \
+ rm -f $(bindir)/$(PROTOIZE_INSTALL_NAME)$(exeext); \
+ $(INSTALL_PROGRAM) protoize$(exeext) $(bindir)/$(PROTOIZE_INSTALL_NAME)$(exeext); \
+ rm -f $(bindir)/$(UNPROTOIZE_INSTALL_NAME)$(exeext); \
+ $(INSTALL_PROGRAM) unprotoize$(exeext) $(bindir)/$(UNPROTOIZE_INSTALL_NAME)$(exeext); \
+ fi ; \
rm -f $(libsubdir)/SYSCALLS.c.X; \
$(INSTALL_DATA) SYSCALLS.c.X $(libsubdir)/SYSCALLS.c.X; \
chmod a-x $(libsubdir)/SYSCALLS.c.X; \
fi
-rm -f $(libsubdir)/cpp$(exeext)
$(INSTALL_PROGRAM) cpp$(exeext) $(libsubdir)/cpp$(exeext)
+# Install gcov if it was compiled.
+ -if [ -f gcov$(exeext) ]; \
+ then \
+ rm -f $(bindir)/gcov$(exeext); \
+ $(INSTALL_PROGRAM) gcov$(exeext) $(bindir)/gcov$(exeext); \
+ chmod a+x $(bindir)/gcov$(exeext); \
+ fi
-# Install the driver program as $(target)-gcc
+# Install the driver program as $(target_alias)-gcc
# and also as either gcc (if native) or $(tooldir)/bin/gcc.
-install-driver: xgcc
+install-driver: xgcc$(exeext)
-if [ -f gcc-cross$(exeext) ] ; then \
rm -f $(bindir)/$(GCC_CROSS_NAME)$(exeext); \
$(INSTALL_PROGRAM) gcc-cross$(exeext) $(bindir)/$(GCC_CROSS_NAME)$(exeext); \
@@ -2119,23 +2401,31 @@ install-driver: xgcc
else \
rm -f $(bindir)/$(GCC_INSTALL_NAME)$(exeext); \
$(INSTALL_PROGRAM) xgcc$(exeext) $(bindir)/$(GCC_INSTALL_NAME)$(exeext); \
- rm -f $(bindir)/$(target)-gcc-1$(exeext); \
- ln $(bindir)/$(GCC_INSTALL_NAME)$(exeext) $(bindir)/$(target)-gcc-1$(exeext) \
- > /dev/null 2>&1 \
- || cp $(bindir)/$(GCC_INSTALL_NAME)$(exeext) $(bindir)/$(target)-gcc-1$(exeext); \
- mv $(bindir)/$(target)-gcc-1$(exeext) $(bindir)/$(target)-gcc$(exeext); \
+ rm -f $(bindir)/$(target_alias)-gcc-1$(exeext); \
+ $(LN) $(bindir)/$(GCC_INSTALL_NAME)$(exeext) $(bindir)/$(target_alias)-gcc-1$(exeext); \
+ mv $(bindir)/$(target_alias)-gcc-1$(exeext) $(bindir)/$(target_alias)-gcc$(exeext); \
fi
# Install the info files.
-install-info: doc install-dir lang.install-info
+# $(INSTALL_DATA) might be a relative pathname, so we can't cd into srcdir
+# to do the install.
+install-info: doc installdirs lang.install-info
-rm -f $(infodir)/cpp.info* $(infodir)/gcc.info*
- cd $(srcdir); for f in cpp.info* gcc.info*; \
- do $(INSTALL_DATA) $$f $(infodir)/$$f; done
+ for f in cpp.info* gcc.info*; do \
+ $(INSTALL_DATA) $$f $(infodir)/$$f; \
+ done
+ -if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \
+ if [ -f $(infodir)/dir ] ; then \
+ for f in cpp.info gcc.info; do \
+ install-info --dir-file=$(infodir)/dir $(infodir)/$$f; \
+ done; \
+ else true; fi; \
+ else true; fi;
-chmod a-x $(infodir)/cpp.info* $(infodir)/gcc.info*
# Install the man pages.
-install-man: install-dir $(srcdir)/gcc.1 $(srcdir)/cccp.1 lang.install-man
- -if [ -f gcc-cross ] ; then \
+install-man: installdirs $(srcdir)/gcc.1 $(srcdir)/cccp.1 lang.install-man
+ -if [ -f gcc-cross$(exeext) ] ; then \
rm -f $(mandir)/$(GCC_CROSS_NAME)$(manext); \
$(INSTALL_DATA) $(srcdir)/gcc.1 $(mandir)/$(GCC_CROSS_NAME)$(manext); \
chmod a-x $(mandir)/$(GCC_CROSS_NAME)$(manext); \
@@ -2149,7 +2439,7 @@ install-man: install-dir $(srcdir)/gcc.1 $(srcdir)/cccp.1 lang.install-man
-chmod a-x $(mandir)/cccp$(manext)
# Install the library.
-install-libgcc: libgcc.a install-dir
+install-libgcc: libgcc.a installdirs
-if [ -f libgcc.a ] ; then \
rm -f $(libsubdir)/libgcc.a; \
$(INSTALL_DATA) libgcc.a $(libsubdir)/libgcc.a; \
@@ -2159,31 +2449,24 @@ install-libgcc: libgcc.a install-dir
else true; fi
# Install multiple versions of libgcc.a.
-install-multilib: stmp-multilib install-dir
+install-multilib: stmp-multilib installdirs
for i in `$(GCC_FOR_TARGET) --print-multi-lib`; do \
dir=`echo $$i | sed -e 's/;.*$$//'`; \
if [ -d $(libsubdir)/$${dir} ]; then true; else mkdir $(libsubdir)/$${dir}; fi; \
- rm -f $(libsubdir)/$${dir}/libgcc.a; \
- $(INSTALL_DATA) $${dir}/libgcc.a $(libsubdir)/$${dir}/libgcc.a; \
+ for f in libgcc.a $(EXTRA_MULTILIB_PARTS); do \
+ rm -f $(libsubdir)/$${dir}/$${f}; \
+ $(INSTALL_DATA) $${dir}/$${f} $(libsubdir)/$${dir}/$${f}; \
+ done; \
if $(RANLIB_TEST); then \
(cd $(libsubdir)/$${dir}; $(RANLIB) libgcc.a); else true; fi; \
chmod a-x $(libsubdir)/$${dir}/libgcc.a; \
done
-# Install the objc run time library.
-install-libobjc: install-dir
- -if [ -f libobjc.a ] ; then \
- rm -f $(libsubdir)/libobjc.a; \
- $(INSTALL_DATA) libobjc.a $(libsubdir)/libobjc.a; \
- if $(RANLIB_TEST) ; then \
- (cd $(libsubdir); $(RANLIB) libobjc.a); else true; fi; \
- chmod a-x $(libsubdir)/libobjc.a; \
- else true; fi
-
# Install all the header files built in the include subdirectory.
install-headers: install-include-dir $(INSTALL_HEADERS_DIR) $(INSTALL_ASSERT_H)
# Fix symlinks to absolute paths in the installed include directory to
# point to the installed directory, not the build directory.
+# Don't need to use LN_S here since we really do need ln -s and no substitutes.
-files=`cd $(libsubdir)/include; find . -type l -print 2>/dev/null`; \
if [ $$? -eq 0 ]; then \
dir=`cd include; pwd`; \
@@ -2197,7 +2480,7 @@ install-headers: install-include-dir $(INSTALL_HEADERS_DIR) $(INSTALL_ASSERT_H)
fi
# Create or recreate the gcc private include file directory.
-install-include-dir: install-dir
+install-include-dir: installdirs
-rm -rf $(libsubdir)/include
mkdir $(libsubdir)/include
-chmod a+rx $(libsubdir)/include
@@ -2221,7 +2504,7 @@ install-headers-cpio: stmp-headers $(STMP_FIXPROTO) install-include-dir
## Don't replace the assert.h already there if it is not from GCC.
## This code would be simpler if it tested for -f ... && ! grep ...
## but supposedly the ! operator is missing in sh on some systems.
-install-assert-h: assert.h install-dir
+install-assert-h: assert.h installdirs
if [ -f $(assertdir)/assert.h ]; \
then \
if grep "__eprintf" $(assertdir)/assert.h >/dev/null; \
@@ -2237,57 +2520,150 @@ install-assert-h: assert.h install-dir
chmod a-x $(assertdir)/assert.h; \
fi
-# Use this target to install the program `collect2' under the name `ld'.
-install-collect2: collect2 install-dir
- $(INSTALL_PROGRAM) collect2$(exeext) $(libsubdir)/ld$(exeext)
+# Use this target to install the program `collect2' under the name `collect2'.
+install-collect2: collect2 installdirs
+ $(INSTALL_PROGRAM) collect2$(exeext) $(libsubdir)/collect2$(exeext)
# Install the driver program as $(libsubdir)/gcc for collect2.
$(INSTALL_PROGRAM) xgcc$(exeext) $(libsubdir)/gcc$(exeext)
# Cancel installation by deleting the installed files.
-uninstall: lang.uninstall
+uninstall: lang.uninstall $(UNINSTALL_CPP)
-rm -rf $(libsubdir)
-rm -rf $(bindir)/$(GCC_INSTALL_NAME)$(exeext)
-rm -rf $(bindir)/$(GCC_CROSS_NAME)$(exeext)
-rm -rf $(bindir)/protoize$(exeext)
-rm -rf $(bindir)/unprotoize$(exeext)
+ -rm -rf $(bindir)/gcov$(exeext)
-rm -rf $(mandir)/$(GCC_INSTALL_NAME)$(manext)
-rm -rf $(mandir)/$(GCC_CROSS_NAME)$(manext)
-rm -rf $(mandir)/cccp$(manext)
-rm -rf $(mandir)/protoize$(manext)
-rm -rf $(mandir)/unprotoize$(manext)
-
+ -rm -f $(infodir)/cpp.info* $(infodir)/gcc.info*
+#
+# These targets are for the dejagnu testsuites. The file site.exp
+# contains global variables that all the testsuites will use.
+
+# Set to $(target_alias)/ for cross.
+target_subdir = @target_subdir@
+
+site.exp: ./config.status Makefile
+ @echo "Making a new config file..."
+ -@rm -f ./tmp?
+ @touch site.exp
+ -@mv site.exp site.bak
+ @echo "## these variables are automatically generated by make ##" > ./tmp0
+ @echo "# Do not edit here. If you wish to override these values" >> ./tmp0
+ @echo "# add them to the last section" >> ./tmp0
+ @echo "set rootme \"`pwd`\"" >> ./tmp0
+ @echo "set srcdir \"`cd ${srcdir}; pwd`\"" >> ./tmp0
+ @echo "set host_triplet $(host_canonical)" >> ./tmp0
+ @echo "set build_triplet $(build_canonical)" >> ./tmp0
+ @echo "set target_triplet $(target)" >> ./tmp0
+ @echo "set target_alias $(target_alias)" >> ./tmp0
+# CFLAGS is set even though it's empty to show we reserve the right to set it.
+ @echo "set CFLAGS \"\"" >> ./tmp0
+ @echo "set CXXFLAGS \"-I$(objdir)/../$(target_subdir)libio -I\$$srcdir/../libg++/src -I\$$srcdir/../libio -I\$$srcdir/../libstdc++ -I\$$srcdir/../libstdc++/stl -L$(objdir)/../$(target_subdir)libg++ -L$(objdir)/../$(target_subdir)libstdc++\"" >> ./tmp0
+# If newlib has been configured, we need to pass -B to gcc so it can find
+# newlib's crt0.o if it exists. This will cause a "path prefix not used"
+# message if it doesn't, but the testsuite is supposed to ignore the message -
+# it's too difficult to tell when to and when not to pass -B (not all targets
+# have crt0's). We could only add the -B if ../newlib/crt0.o exists, but that
+# seems like too selective a test.
+# ??? Another way to solve this might be to rely on linker scripts. Then
+# theoretically the -B won't be needed.
+# We also need to pass -L ../ld so that the linker can find ldscripts.
+ @if [ -d $(objdir)/../$(target_subdir)newlib ] ; then \
+ echo "set newlib_cflags \"-I$(objdir)/../$(target_subdir)newlib/targ-include -I\$$srcdir/../newlib/libc/include\"" >> ./tmp0; \
+ echo "set newlib_ldflags \"-B$(objdir)/../$(target_subdir)newlib/\"" >> ./tmp0; \
+ echo "append CFLAGS \" \$$newlib_cflags\"" >> ./tmp0; \
+ echo "append CXXFLAGS \" \$$newlib_cflags\"" >> ./tmp0; \
+ echo "append LDFLAGS \" \$$newlib_ldflags\"" >> ./tmp0; \
+ else true; \
+ fi
+ @if [ -d $(objdir)/../ld ] ; then \
+ echo "append LDFLAGS \" -L$(objdir)/../ld\"" >> ./tmp0; \
+ else true; \
+ fi
+ echo "set tmpdir $(objdir)/testsuite" >> ./tmp0
+ @echo "set srcdir \"\$${srcdir}/testsuite\"" >> ./tmp0
+ @echo "## All variables above are generated by configure. Do Not Edit ##" >> ./tmp0
+ @cat ./tmp0 > site.exp
+ @cat site.bak | sed \
+ -e '1,/^## All variables above are.*##/ d' >> site.exp
+ -@rm -f ./tmp?
+
+CHECK_TARGETS = check-gcc check-g++ check-g77
+
+check: $(CHECK_TARGETS)
+
+testsuite/site.exp: site.exp
+ if [ -d testsuite ]; then \
+ true; \
+ else \
+ mkdir testsuite; \
+ fi
+ rm -rf testsuite/site.exp
+ cp site.exp testsuite/site.exp
+
+check-g++: testsuite/site.exp
+ -rootme=`pwd`; export rootme; \
+ srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \
+ cd testsuite; \
+ EXPECT=${EXPECT} ; export EXPECT ; \
+ if [ -f $${rootme}/../expect/expect ] ; then \
+ TCL_LIBRARY=$${srcdir}/../tcl/library ; \
+ export TCL_LIBRARY ; fi ; \
+ $(RUNTEST) --tool g++ $(RUNTESTFLAGS)
+
+check-gcc: testsuite/site.exp
+ -rootme=`pwd`; export rootme; \
+ srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \
+ cd testsuite; \
+ EXPECT=${EXPECT} ; export EXPECT ; \
+ if [ -f $${rootme}/../expect/expect ] ; then \
+ TCL_LIBRARY=$${srcdir}/../tcl/library ; \
+ export TCL_LIBRARY ; fi ; \
+ $(RUNTEST) --tool gcc $(RUNTESTFLAGS)
+
+check-g77: testsuite/site.exp
+ -rootme=`pwd`; export rootme; \
+ srcdir=`cd ${srcdir}; pwd` ; export srcdir ; \
+ cd testsuite; \
+ EXPECT=${EXPECT} ; export EXPECT ; \
+ if [ -f $${rootme}/../expect/expect ] ; then \
+ TCL_LIBRARY=$${srcdir}/../tcl/library ; \
+ export TCL_LIBRARY ; fi ; \
+ $(RUNTEST) --tool g77 $(RUNTESTFLAGS)
+
# These exist for maintenance purposes.
# Update the tags table.
TAGS: force
cd $(srcdir); \
- mkdir temp; \
- mv -f c-parse.[ch] objc-parse.c cexp.c =*.[chy] temp; \
+ mkdir tmp-tags; \
+ mv -f c-parse.[ch] cexp.c =*.[chy] tmp-tags; \
etags *.y *.h *.c; \
- mv temp/* .; \
- rmdir temp
+ mv tmp-tags/* .; \
+ rmdir tmp-tags
-# Create the distribution tar file.
-#dist: gcc-$(version).tar.gz
-dist: gcc.xtar.gz
+# Create the distribution tar.gz file.
+dist: tmp-gcc.xtar
+ gzip --best < tmp-gcc.xtar > tmp-gcc.xtar.gz
+ mv tmp-gcc.xtar.gz gcc-$(version).tar.gz
-gcc.xtar.gz: gcc.xtar
- gzip --best < gcc.xtar > tmp-gcc.xtar.gz
- mv tmp-gcc.xtar.gz gcc.xtar.gz
-
-#gcc-$(version).tar.gz: gcc-$(version).tar
-# gzip < gcc-$(version).tar > gcc-$(version).tar.gz
-
-#gcc-$(version).tar:
-gcc.xtar: distdir
+tmp-gcc.xtar: distdir
# Make the distribution.
- tar -chf gcc.xtar gcc-$(version)
+ tar -chf tmp-gcc.xtar gcc-$(version)
+
+distdir-cvs: force
+ if [ -d $(srcdir)/CVS ]; then cvs -r update; fi
# This target exists to do the initial work before the language specific
# stuff gets done.
distdir-start: doc $(srcdir)/INSTALL $(srcdir)/c-parse.y $(srcdir)/c-gperf.h \
- $(srcdir)/objc-parse.y $(srcdir)/c-parse.c $(srcdir)/objc-parse.c \
- $(srcdir)/cexp.c
+ $(srcdir)/c-parse.c $(srcdir)/cexp.c $(srcdir)/config.in \
+ $(srcdir)/version.c TAGS
@if grep -s "for version ${mainversion}" gcc.texi > /dev/null; \
then true; \
else echo "You must update the version number in \`gcc.texi'"; sleep 10;\
@@ -2304,35 +2680,31 @@ distdir-start: doc $(srcdir)/INSTALL $(srcdir)/c-parse.y $(srcdir)/c-gperf.h \
mkdir tmp
mkdir tmp/config
mkdir tmp/ginclude
- mkdir tmp/objc
for file in *[0-9a-zA-Z+]; do \
- ln $$file tmp > /dev/null 2>&1 || cp $$file tmp; \
+ $(LN) $$file tmp; \
done
cd config; \
for file in *[0-9a-zA-Z+]; do \
- if test -d $$file && test "$$file" != RCS; then \
+ if test -d $$file && test "$$file" != RCS && test "$$file" != CVS; then \
mkdir ../tmp/config/$$file; \
cd $$file; \
for subfile in *[0-9a-zA-Z+]; do \
- ln $$subfile ../../tmp/config/$$file >/dev/null 2>&1 \
- || cp $$subfile ../../tmp/config/$$file; \
+ $(LN) $$subfile ../../tmp/config/$$file; \
done; \
cd ..; \
else \
- ln $$file ../tmp/config >/dev/null 2>&1 \
- || cp $$file ../tmp/config; \
+ $(LN) $$file ../tmp/config; \
fi; \
done
cd ginclude; \
for file in *[0-9a-zA-Z+]; do \
- ln $$file ../tmp/ginclude >/dev/null 2>&1 \
- || cp $$file ../tmp/ginclude; \
+ $(LN) $$file ../tmp/ginclude; \
done
cd objc; \
for file in *[0-9a-zA-Z+]; do \
- ln $$file ../tmp/objc >/dev/null 2>&1 || cp $$file ../tmp/objc; \
+ $(LN) $$file ../tmp/objc; \
done
- ln .gdbinit tmp
+ $(LN) .gdbinit tmp
# Finish making `distdir', after the languages have done their thing.
distdir-finish:
@@ -2340,112 +2712,117 @@ distdir-finish:
# Get rid of everything we don't want in the distribution. We'd want
# this to use Makefile.in, but it doesn't have the `lang.foo' targets
# expanded.
- cd gcc-$(version); make extraclean
+ cd gcc-$(version); make extraclean VERSION_DEP=
-distdir: distdir-start lang.distdir distdir-finish
+distdir: distdir-cvs distdir-start lang.distdir distdir-finish
# make diff oldversion=M.N
# creates a diff file between an older distribution and this one.
# The -P option assumes this is GNU diff.
diff:
diff -rc2P -x c-parse.y -x c-parse.c -x c-parse.h -x c-gperf.h \
- -x cexp.c -x bi-parser.c -x objc-parse.y -x objc-parse.c \
- -x TAGS \
+ -x cexp.c -x -x TAGS -x INSTALL \
+ -x configure -x config.in \
-x "gcc.??" -x "gcc.??s" -x gcc.aux -x "gcc.info*" \
-x "cpp.??" -x "cpp.??s" -x cpp.aux -x "cpp.info*" \
$(LANG_DIFF_EXCLUDES) \
- gcc-$(oldversion) gcc-$(version) > diffs
+ gcc-$(oldversion) gcc-$(version) > gcc-$(oldversion)-$(version).diff
-bootstrap: force
+bootstrap bootstrap-lean: force
# Only build the C compiler for stage1, because that is the only one that
# we can guarantee will build with the native compiler, and also it is the
# only thing useful for building stage2.
- $(MAKE) CC="$(CC)" libdir=$(libdir) LANGUAGES=c
+ $(MAKE) CC="$(CC)" libdir=$(libdir) LANGUAGES="$(BOOT_LANGUAGES)"
$(MAKE) stage1
# This used to define ALLOCA as empty, but that would lead to bad results
# for a subsequent `make install' since that would not have ALLOCA empty.
# To prevent `make install' from compiling alloca.o and then relinking cc1
# because alloca.o is newer, we permit these recursive makes to compile
# alloca.o. Then cc1 is newer, so it won't have to be relinked.
- $(MAKE) CC="stage1/xgcc -Bstage1/" CFLAGS="$(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage1/ LANGUAGES="$(LANGUAGES)"
+ $(MAKE) CC="stage1/xgcc$(exeext) -Bstage1/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage1/ LANGUAGES="$(LANGUAGES)"
$(MAKE) stage2
- $(MAKE) CC="stage2/xgcc -Bstage2/" CFLAGS="$(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage2/ LANGUAGES="$(LANGUAGES)"
+ -if test $@ = bootstrap-lean; then rm -rf stage1; else true; fi
+ $(MAKE) CC="stage2/xgcc$(exeext) -Bstage2/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage2/ LANGUAGES="$(LANGUAGES)"
-bootstrap2: force
- $(MAKE) CC="stage1/xgcc -Bstage1/" CFLAGS="$(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage1/ LANGUAGES="$(LANGUAGES)"
+bootstrap2 bootstrap2-lean: force
+ $(MAKE) CC="stage1/xgcc$(exeext) -Bstage1/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage1/ LANGUAGES="$(LANGUAGES)"
$(MAKE) stage2
- $(MAKE) CC="stage2/xgcc -Bstage2/" CFLAGS="$(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage2/ LANGUAGES="$(LANGUAGES)"
+ -if test $@ = bootstrap2-lean; then rm -rf stage1; else true; fi
+ $(MAKE) CC="stage2/xgcc$(exeext) -Bstage2/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage2/ LANGUAGES="$(LANGUAGES)"
+
+bootstrap3 bootstrap3-lean: force
+ $(MAKE) CC="stage2/xgcc$(exeext) -Bstage2/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage2/ LANGUAGES="$(LANGUAGES)"
-bootstrap3: force
- $(MAKE) CC="stage2/xgcc -Bstage2/" CFLAGS="$(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage2/ LANGUAGES="$(LANGUAGES)"
+bootstrap4 bootstrap4-lean: force
+ $(MAKE) CC="stage3/xgcc$(exeext) -Bstage3/" CFLAGS="$(WARN_CFLAGS) $(BOOT_CFLAGS)" LDFLAGS="$(BOOT_LDFLAGS)" libdir=$(libdir) STAGE_PREFIX=stage3/ LANGUAGES="$(LANGUAGES)"
# Compare the object files in the current directory with those in the
# stage2 directory.
# ./ avoids bug in some versions of tail.
-compare: force
- for file in *$(objext); do \
- tail +16c ./$$file > tmp-foo1; \
- tail +16c stage2/$$file > tmp-foo2 2>/dev/null \
- && (cmp tmp-foo1 tmp-foo2 || echo $$file differs) || true; \
- done
- for dir in tmp-foo $(SUBDIRS); do \
- if [ "`echo $$dir/*$(objext)`" != "$$dir/*$(objext)" ] ; then \
- for file in $$dir/*$(objext); do \
- tail +16c ./$$file > tmp-foo1; \
- tail +16c stage2/$$file > tmp-foo2 2>/dev/null \
- && (cmp tmp-foo1 tmp-foo2 || echo $$file differs) || true; \
- done; \
- fi; \
- done
- -rm -f tmp-foo*
-
-# Similar, but compare with stage3 directory
-compare3: force
+compare compare3 compare4 compare-lean compare3-lean compare4-lean: force
+ -rm -f .bad_compare
+ case "$@" in compare | compare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^compare\([0-9][0-9]*\).*,\1,'` ;; esac; \
for file in *$(objext); do \
tail +16c ./$$file > tmp-foo1; \
- tail +16c stage3/$$file > tmp-foo2 2>/dev/null \
- && (cmp tmp-foo1 tmp-foo2 || echo $$file differs) || true; \
+ tail +16c stage$$stage/$$file > tmp-foo2 \
+ && (cmp tmp-foo1 tmp-foo2 > /dev/null 2>&1 || echo $$file differs >> .bad_compare) || true; \
done
+ case "$@" in compare | compare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^compare\([0-9][0-9]*\).*,\1,'` ;; esac; \
for dir in tmp-foo $(SUBDIRS); do \
if [ "`echo $$dir/*$(objext)`" != "$$dir/*$(objext)" ] ; then \
for file in $$dir/*$(objext); do \
- tail +16c ./$$file > tmp-foo1; \
- tail +16c stage3/$$file > tmp-foo2 2>/dev/null \
- && (cmp tmp-foo1 tmp-foo2 || echo $$file differs) || true; \
+ if [ $$file != objc/NXConstStr.o -a $$file != objc/Object.o -a $$file != objc/Protocol.o -a $$file != objc/linking.o ] ; then \
+ tail +16c ./$$file > tmp-foo1; \
+ tail +16c stage$$stage/$$file > tmp-foo2 \
+ && (cmp tmp-foo1 tmp-foo2 > /dev/null 2>&1 || echo $$file differs >> .bad_compare) || true; \
+ else true; fi; \
done; \
fi; \
done
-rm -f tmp-foo*
+ case "$@" in compare | compare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^compare\([0-9][0-9]*\).*,\1,'` ;; esac; \
+ if [ -f .bad_compare ]; then \
+ echo "Bootstrap comparison failure!"; \
+ cat .bad_compare; \
+ exit 1; \
+ else \
+ case "$@" in \
+ *-lean ) rm -rf stage$$stage ;; \
+ *) ;; \
+ esac; true; \
+ fi
# Compare the object files in the current directory with those in the
# stage2 directory. Use gnu cmp (diffutils v2.4 or later) to avoid
# running tail and the overhead of twice copying each object file.
-gnucompare: force
+gnucompare gnucompare3 gnucompare4 gnucompare-lean gnucompare3-lean gnucompare4-lean: force
+ -rm -f .bad_compare
+ case "$@" in gnucompare | gnucompare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^gnucompare\([0-9][0-9]*\).*,\1,'` ;; esac; \
for file in *$(objext); do \
- cmp --ignore-initial=16 $$file stage2/$$file || true ; \
+ (cmp --ignore-initial=16 $$file stage$$stage/$$file > /dev/null 2>&1 || echo $$file differs >> .bad_compare) || true; \
done
+ case "$@" in gnucompare | gnucompare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^gnucompare\([0-9][0-9]*\).*,\1,'` ;; esac; \
for dir in tmp-foo $(SUBDIRS); do \
if [ "`echo $$dir/*$(objext)`" != "$$dir/*$(objext)" ] ; then \
for file in $$dir/*$(objext); do \
- cmp --ignore-initial=16 $$file stage2/$$file || true ; \
- done; \
- fi; \
- done
-
-# Similar, but compare with stage3 directory
-gnucompare3: force
- for file in *$(objext); do \
- cmp --ignore-initial=16 $$file stage3/$$file || true ; \
- done
- for dir in tmp-foo $(SUBDIRS); do \
- if [ "`echo $$dir/*$(objext)`" != "$$dir/*$(objext)" ] ; then \
- for file in $$dir/*$(objext); do \
- cmp --ignore-initial=16 $$file stage3/$$file || true ; \
+ if [ $$file != objc/NXConstStr.o -a $$file != objc/Object.o -a $$file != objc/Protocol.o -a $$file != objc/linking.o ] ; then \
+ (cmp --ignore-initial=16 $$file stage$$stage/$$file > /dev/null 2>&1 || echo $$file differs >> .bad_compare) || true; \
+ else true; fi; \
done; \
fi; \
done
+ case "$@" in gnucompare | gnucompare-lean ) stage=2 ;; * ) stage=`echo $@ | sed -e 's,^gnucompare\([0-9][0-9]*\).*,\1,'` ;; esac; \
+ if [ -f .bad_compare ]; then \
+ echo "Bootstrap comparison failure!"; \
+ cat .bad_compare; \
+ exit 1; \
+ else \
+ case "$@" in \
+ *-lean ) rm -rf stage$$stage ;; \
+ esac; true; \
+ fi
# Copy the object files from a particular stage into a subdirectory.
stage1-start:
@@ -2457,12 +2834,16 @@ stage1-start:
-mv $(STAGESTUFF) stage1
# Copy as/ld if they exist to stage dir, so that running xgcc from the stage
# dir will work properly.
- -if [ -f as$(exeext) ] ; then ln -s ../as$(exeext) stage1 || cp as$(exeext) stage1 ; else true ; fi
- -if [ -f ld$(exeext) ] ; then ln -s ../ld$(exeext) stage1 || cp ld$(exeext) stage1 ; else true ; fi
- -if [ -f collect-ld$(exeext) ] ; then ln -s ../collect-ld$(exeext) stage1 || cp collect-ld$(exeext) stage1 ; else true ; fi
+ -if [ -f as$(exeext) ] ; then $(LN_S) ../as$(exeext) stage1 ; else true ; fi
+ -if [ -f ld$(exeext) ] ; then $(LN_S) ../ld$(exeext) stage1 ; else true ; fi
+ -if [ -f collect-ld$(exeext) ] ; then $(LN_S) ../collect-ld$(exeext) stage1 ; else true ; fi
-rm -f stage1/libgcc.a
-cp libgcc.a stage1
-if $(RANLIB_TEST) ; then $(RANLIB) stage1/libgcc.a; else true; fi
+ -for f in .. $(EXTRA_MULTILIB_PARTS); do if [ x$${f} != x.. ]; then \
+ cp stage1/$${f} . ; \
+ else true; \
+ fi; done
stage1: force stage1-start lang.stage1
stage2-start:
@@ -2474,12 +2855,16 @@ stage2-start:
-mv $(STAGESTUFF) stage2
# Copy as/ld if they exist to stage dir, so that running xgcc from the stage
# dir will work properly.
- -if [ -f as$(exeext) ] ; then ln -s ../as$(exeext) stage2 || cp as$(exeext) stage2 ; else true ; fi
- -if [ -f ld$(exeext) ] ; then ln -s ../ld$(exeext) stage2 || cp ld$(exeext) stage2 ; else true ; fi
- -if [ -f collect-ld ] ; then ln -s ../collect-ld$(exeext) stage2 || cp collect-ld$(exeext) stage2 ; else true ; fi
+ -if [ -f as$(exeext) ] ; then $(LN_S) ../as$(exeext) stage2 ; else true ; fi
+ -if [ -f ld$(exeext) ] ; then $(LN_S) ../ld$(exeext) stage2 ; else true ; fi
+ -if [ -f collect-ld ] ; then $(LN_S) ../collect-ld$(exeext) stage2 ; else true ; fi
-rm -f stage2/libgcc.a
-cp libgcc.a stage2
-if $(RANLIB_TEST) ; then $(RANLIB) stage2/libgcc.a; else true; fi
+ -for f in .. $(EXTRA_MULTILIB_PARTS); do if [ x$${f} != x.. ]; then \
+ cp stage2/$${f} . ; \
+ else true; \
+ fi; done
stage2: force stage2-start lang.stage2
stage3-start:
@@ -2491,12 +2876,16 @@ stage3-start:
-mv $(STAGESTUFF) stage3
# Copy as/ld if they exist to stage dir, so that running xgcc from the stage
# dir will work properly.
- -if [ -f as$(exeext) ] ; then ln -s ../as$(exeext) stage3 || cp as$(exeext) stage3 ; else true ; fi
- -if [ -f ld$(exeext) ] ; then ln -s ../ld$(exeext) stage3 || cp ld$(exeext) stage3 ; else true ; fi
- -if [ -f collect-ld$(exeext) ] ; then ln -s ../collect-ld$(exeext) stage3 || cp collect-ld$(exeext) stage3 ; else true ; fi
+ -if [ -f as$(exeext) ] ; then $(LN_S) ../as$(exeext) stage3 ; else true ; fi
+ -if [ -f ld$(exeext) ] ; then $(LN_S) ../ld$(exeext) stage3 ; else true ; fi
+ -if [ -f collect-ld$(exeext) ] ; then $(LN_S) ../collect-ld$(exeext) stage3 ; else true ; fi
-rm -f stage3/libgcc.a
-cp libgcc.a stage3
-if $(RANLIB_TEST) ; then $(RANLIB) stage3/libgcc.a; else true; fi
+ -for f in .. $(EXTRA_MULTILIB_PARTS); do if [ x$${f} != x.. ]; then \
+ cp stage3/$${f} . ; \
+ else true; \
+ fi; done
stage3: force stage3-start lang.stage3
stage4-start:
@@ -2508,19 +2897,23 @@ stage4-start:
-mv $(STAGESTUFF) stage4
# Copy as/ld if they exist to stage dir, so that running xgcc from the stage
# dir will work properly.
- -if [ -f as$(exeext) ] ; then ln -s ../as$(exeext) stage4 || cp as$(exeext) stage4 ; else true ; fi
- -if [ -f ld$(exeext) ] ; then ln -s ../ld$(exeext) stage4 || cp ld$(exeext) stage4 ; else true ; fi
- -if [ -f collect-ld$(exeext) ] ; then ln -s ../collect-ld$(exeext) stage4 || cp collect-ld$(exeext) stage4 ; else true ; fi
+ -if [ -f as$(exeext) ] ; then $(LN_S) ../as$(exeext) stage4 ; else true ; fi
+ -if [ -f ld$(exeext) ] ; then $(LN_S) ../ld$(exeext) stage4 ; else true ; fi
+ -if [ -f collect-ld$(exeext) ] ; then $(LN_S) ../collect-ld$(exeext) stage4 ; else true ; fi
-rm -f stage4/libgcc.a
-cp libgcc.a stage4
-if $(RANLIB_TEST) ; then $(RANLIB) stage4/libgcc.a; else true; fi
+ -for f in .. $(EXTRA_MULTILIB_PARTS); do if [ x$${f} != x.. ]; then \
+ cp stage4/$${f} . ; \
+ else true; \
+ fi; done
stage4: force stage4-start lang.stage4
# Copy just the executable files from a particular stage into a subdirectory,
# and delete the object files. Use this if you're just verifying a version
# that is pretty sure to work, and you are short of disk space.
risky-stage1: stage1
- - make clean
+ -make clean
risky-stage2: stage2
-make clean
@@ -2536,3 +2929,57 @@ risky-stage4: stage4
.PHONY: risky-stage1 risky-stage2 risky-stage3 risky-stage4
force:
+
+# ---
+# The enquire rules are still useful for building new float-anything.h.
+# Special flags for compiling enquire.
+# We disable optimization to make floating point more reliable.
+ENQUIRE_CFLAGS = -DNO_MEM -DNO_LONG_DOUBLE_IO -O0
+ENQUIRE_LDFLAGS = $(LDFLAGS)
+
+# Enquire target (This is a variable so that a target can choose not to
+# build it.)
+ENQUIRE = enquire
+
+# Test to see whether <float.h> exists in the system header files,
+# and is not derived from GCC.
+FLOAT_H_TEST = \
+ [ -f $(SYSTEM_HEADER_DIR)/float.h ] && \
+ if grep 'ifndef _FLOAT_H___' $(SYSTEM_HEADER_DIR)/float.h >/dev/null; \
+ then false; \
+ else :; fi
+# We pretend to not having a usable <float.h>, hence disable the FLOAT_H_TEST
+# to ensure, we're emitting a full blown <float.h> ourselves.
+FLOAT_H_TEST = false
+
+# Used to compile enquire with standard cc, but have forgotten why.
+# Let's try with GCC.
+enquire: enquire.o $(GCC_PARTS)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ENQUIRE_LDFLAGS) enquire.o -o $@
+enquire.o: $(srcdir)/enquire.c $(GCC_PASSES) stmp-int-hdrs
+ if $(FLOAT_H_TEST); then \
+ rm -f include/float.h; \
+ SYS_FLOAT_H_WRAP=1; \
+ else :; \
+ SYS_FLOAT_H_WRAP=0; \
+ fi; \
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(ALL_CPPFLAGS) $(ENQUIRE_CFLAGS) \
+ -DSYS_FLOAT_H_WRAP=$$SYS_FLOAT_H_WRAP \
+ -I. -c $(srcdir)/enquire.c
+
+# Create float.h source for the native machine.
+# Make it empty if we can use the system float.h without changes.
+float.h-nat: enquire
+ -./enquire -f > tmp-float.h
+ grep '#define [^_]' tmp-float.h >/dev/null || true > tmp-float.h
+ mv tmp-float.h float.h-nat
+
+# Create a dummy float.h source for a cross-compiler.
+# ??? This isn't used anymore. Should we create config/float-unkn.h
+# and make that the default float_format in configure?
+float.h-cross:
+ echo "#ifndef __GCC_FLOAT_NOT_NEEDED" > t-float.h-cross
+ echo "#error float.h values not known for cross-compiler" >> t-float.h-cross
+ echo "#endif" >> t-float.h-cross
+ mv t-float.h-cross float.h-cross
+
diff --git a/contrib/gcc/NEWS b/contrib/gcc/NEWS
index 9c23093..628b03c 100644
--- a/contrib/gcc/NEWS
+++ b/contrib/gcc/NEWS
@@ -1,13 +1,336 @@
-Noteworthy changes in GCC version 2.7.2.1:
+Noteworthy changes in GCC for EGCS 1.1.
+---------------------------------------
-This release fixes some serious bugs discovered since the 2.7.2 release.
+The compiler now implements global common subexpression elimination (gcse) as
+well as global constant/copy propagation. (link to gcse page).
-Noteworthy changes in GCC version 2.7.2:
+More major improvements have been made to the alias analysis code. A new
+option to allow front-ends to provide alias information to the optimizers
+has also been added (-fstrict-aliasing). -fstrict-aliasing is off by default
+now, but will be enabled by default in the future. (link to alias page)
+
+Major changes continue in the exception handling support. This release
+includes some changes to reduce static overhead for exception handling. It
+also includes some major changes to the setjmp/longjmp based EH mechanism to
+make it less pessimistic. And finally, major infrastructure improvements
+to the dwarf2 EH mechanism have been made to make our EH support extensible.
+
+We have fixed the infamous security problems with temporary files.
+
+The "regmove" optimization pass has been nearly completely rewritten. It now
+uses much more information about the target to determine profitability of
+transformations.
+
+The compiler now recomputes register usage information immediately before
+register allocation. Previously such information was only not kept up to
+date after instruction combination which led to poor register allocation
+choices by our priority based register allocator.
+
+The register reloading phase of the compiler has been improved to better
+optimize spill code. This primarily helps targets which generate lots of
+spills (like the x86 ports and many register poor embedded ports).
+
+A few changes in the heuristics used by the register allocator and scheduler
+have been made which can significantly improve performance for certain
+applications.
+
+The compiler's branch shortening algorithms have been significantly improved
+to work better on targets which align jump targets.
+
+The compiler now supports the "ADDRESSOF" optimization which can significantly
+reduce the overhead for certain inline calls (and inline calls in general).
+
+The compiler now supports a code size optimization switch (-Os). When enabled
+the compiler will prefer optimizations which improve code size over those
+which improve code speed.
+
+The compiler has been improved to completely eliminate library calls which
+compute constant values. This is particularly useful on machines which
+do not have integer mul/div or floating point support on-chip.
+
+GCC now supports a "--help" option to print detailed help information.
+
+cpplib has been greatly improved. It is probably useable for some sites now
+(major missing feature is trigraphs).
+
+Memory footprint for the compiler has been significantly reduced for certain
+pathalogical cases.
+
+Build time improvements for targets which support lots of sched parameters
+(alpha and mips primarily).
+
+Compile time for certain programs using large constant initializers has been
+improved (effects glibc significantly).
+
+Plus an incredible number of infrastructure changes, warning fixes, bugfixes
+and local optimizations.
+
+Various improvements have been made to better support cross compilations. They
+are still not easy, but they are improving.
+
+Target specific NEWS
+
+ Sparc: Now includes V8 plus and V9 support, lots of tuning for Ultrasparcs
+ and uses the Haifa scheduler by default.
+
+ Alpha: EV6 tuned, optimized expansion of memcpy/bzero.
+
+ x86: Data in the static store is aligned per Intel recommendations. Jump
+ targets are aligned per Intel recommendations. Improved epilogue
+ sequences for Pentium chips. Backend improvements which should help
+ register allocation on all x86 variants. Support for PPro conditional
+ move instructions has been fixed and enabled. Random changes
+ throughout the port to make generated code more Pentium friendly.
+ Improved support for 64bit integer operations.
+ Unixware 7, a System V Release 5 target is now supported.
+ SCO OpenServer targets can support GAS. See gcc/INSTALL for details.
+
+ RS6000/PowerPC: Includes AIX4.3 support as well as PowerPC64 support.
+ Haifa instruction scheduling is enabled by default now.
+
+ MIPS: Multiply/Multiply-Add support has been largely rewritten to generate
+ more efficient code. Includes mips16 support.
+
+ M68K: Various micro-optimizations and Coldfire fixes.
+
+ M32r: Major improvements to this port.
+
+ Arm: Includes Thumb and super interworking support.
+
+EGCS includes all gcc2 changes up to and including the June 9, 1998 snapshot.
+
+
+Noteworthy changes in GCC version 2.8.1
+---------------------------------------
+
+Numerous bugs have been fixed and some minor performance
+improvements (compilation speed) have been made.
+
+Noteworthy changes in GCC version 2.8.0
+---------------------------------------
+
+A major change in this release is the addition of a framework for
+exception handling, currently used by C++. Many internal changes and
+optimization improvements have been made. These increase the
+maintainability and portability of GCC. GCC now uses autoconf to
+compute many host parameters.
+
+The following lists changes that add new features or targets.
+
+See cp/NEWS for new features of C++ in this release.
+
+New tools and features:
+
+ The Dwarf 2 debugging information format is supported on ELF systems, and
+ is the default for -ggdb where available. It can also be used for C++.
+ The Dwarf version 1 debugging format is also permitted for C++, but
+ does not work well.
+
+ gcov.c is provided for test coverage analysis and branch profiling
+ analysis is also supported; see -fprofile-arcs, -ftest-coverage,
+ and -fbranch-probabilities.
+
+ Support for the Checker memory checking tool.
+
+ New switch, -fstack-check, to check for stack overflow on systems that
+ don't have such built into their ABI.
+
+ New switches, -Wundef and -Wno-undef to warn if an undefined identifier
+ is evaluated in an #if directive.
+
+ Options -Wall and -Wimplicit now cause GCC to warn about implicit int
+ in declarations (e.g. `register i;'), since the C Standard committee
+ has decided to disallow this in the next revision of the standard;
+ -Wimplicit-function-declarations and -Wimplicit-int are subsets of
+ this.
+
+ Option -Wsign-compare causes GCC to warn about comparison of signed and
+ unsigned values.
+
+ Add -dI option of cccp for cxref.
+
+New features in configuration, installation and specs file handling:
+
+ New option --enable-c-cpplib to configure script.
+
+ You can use --with-cpu on the configure command to specify the default
+ CPU that GCC should generate code for.
+
+ The -specs=file switch allows you to override default specs used in
+ invoking programs like cc1, as, etc.
+
+ Allow including one specs file from another and renaming a specs
+ variable.
+
+ You can now relocate all GCC files with a single environment variable
+ or a registry entry under Windows 95 and Windows NT.
+
+Changes in Objective-C:
+
+ The Objective-C Runtime Library has been made thread-safe.
+
+ The Objective-C Runtime Library contains an interface for creating
+ mutexes, condition mutexes, and threads; it requires a back-end
+ implementation for the specific platform and/or thread package.
+ Currently supported are DEC/OSF1, IRIX, Mach, OS/2, POSIX, PCThreads,
+ Solaris, and Windows32. The --enable-threads parameter can be used
+ when configuring GCC to enable and select a thread back-end.
+
+ Objective-C is now configured as separate front-end language to GCC,
+ making it more convenient to conditionally build it.
+
+ The internal structures of the Objective-C Runtime Library have
+ changed sufficiently to warrant a new version number; now version 8.
+ Programs compiled with an older version must be recompiled.
+
+ The Objective-C Runtime Library can be built as a DLL on Windows 95
+ and Windows NT systems.
+
+ The Objective-C Runtime Library implements +load.
+
+The following new targets are supported (see also list under each
+individual CPU below):
+
+ Embedded target m32r-elf.
+ Embedded Hitachi Super-H using ELF.
+ RTEMS real-time system on various CPU targets.
+ ARC processor.
+ NEC V850 processor.
+ Matsushita MN10200 processor.
+ Matsushita MN10300 processor.
+ Sparc and PowerPC running on VxWorks.
+ Support both glibc versions 1 and 2 on Linux-based GNU systems.
+
+New features for DEC Alpha systems:
+
+ Allow detailed specification of IEEE fp support:
+ -mieee, -mieee-with-inexact, and -mieee-conformant
+ -mfp-trap-mode=xxx, -mfp-round-mode=xxx, -mtrap-precision=xxx
+ -mcpu=xxx for CPU selection
+ Support scheduling parameters for EV5.
+ Add support for BWX, CIX, and MAX instruction set extensions.
+ Support Linux-based GNU systems.
+ Support VMS.
+
+Additional supported processors and systems for MIPS targets:
+
+ MIPS4 instruction set.
+ R4100, R4300 and R5000 processors.
+ N32 and N64 ABI.
+ IRIX 6.2.
+ SNI SINIX.
+
+New features for Intel x86 family:
+
+ Add scheduling parameters for Pentium and Pentium Pro.
+ Support stabs on Solaris-x86.
+ Intel x86 processors running the SCO OpenServer 5 family.
+ Intel x86 processors running DG/UX.
+ Intel x86 using Cygwin32 or Mingw32 on Windows 95 and Windows NT.
+
+New features for Motorola 68k family:
+
+ Support for 68060 processor.
+ More consistent switches to specify processor.
+ Motorola 68k family running AUX.
+ 68040 running pSOS, ELF object files, DBX debugging.
+ Coldfire variant of Motorola m68k family.
+
+New features for the HP PA RISC:
+
+ -mspace and -mno-space
+ -mlong-load-store and -mno-long-load-store
+ -mbig-switch -mno-big-switch
+
+ GCC on the PA requires either gas-2.7 or the HP assembler; for best
+ results using GAS is highly recommended. GAS is required for -g and
+ exception handling support.
+
+New features for SPARC-based systems:
+
+ The ultrasparc cpu.
+ The sparclet cpu, supporting only a.out file format.
+ Sparc running SunOS 4 with the GNU assembler.
+ Sparc running the Linux-based GNU system.
+ Embedded Sparc processors running the ELF object file format.
+ -mcpu=xxx
+ -mtune=xxx
+ -malign-loops=xxx
+ -malign-jumps=xxx
+ -malign-functions=xxx
+ -mimpure-text and -mno-impure-text
+
+ Options -mno-v8 and -mno-sparclite are no longer supported on SPARC
+ targets. Options -mcypress, -mv8, -msupersparc, -msparclite, -mf930,
+ and -mf934 are deprecated and will be deleted in GCC 2.9. Use
+ -mcpu=xxx instead.
+
+New features for rs6000 and PowerPC systems:
+
+ Solaris 2.51 running on PowerPC's.
+ The Linux-based GNU system running on PowerPC's.
+ -mcpu=604e,602,603e,620,801,823,mpc505,821,860,power2
+ -mtune=xxx
+ -mrelocatable-lib, -mno-relocatable-lib
+ -msim, -mmve, -memb
+ -mupdate, -mno-update
+ -mfused-madd, -mno-fused-madd
+
+ -mregnames
+ -meabi
+ -mcall-linux, -mcall-solaris, -mcall-sysv-eabi, -mcall-sysv-noeabi
+ -msdata, -msdata=none, -msdata=default, -msdata=sysv, -msdata=eabi
+ -memb, -msim, -mmvme
+ -myellowknife, -mads
+ wchar_t is now of type long as per the ABI, not unsigned short.
+ -p/-pg support
+ -mcpu=403 now implies -mstrict-align.
+ Implement System V profiling.
+
+ Aix 4.1 GCC targets now default to -mcpu=common so that programs
+ compiled can be moved between rs6000 and powerpc based systems. A
+ consequence of this is that -static won't work, and that some programs
+ may be slightly slower.
+
+ You can select the default value to use for -mcpu=xxx on rs6000 and
+ powerpc targets by using the --with-cpu=xxx option when configuring the
+ compiler. In addition, a new options, -mtune=xxx was added that
+ selects the machine to schedule for but does not select the
+ architecture level.
+
+ Directory names used for storing the multilib libraries on System V
+ and embedded PowerPC systems have been shortened to work with commands
+ like tar that have fixed limits on pathname size.
+
+New features for the Hitachi H8/300(H):
+
+ -malign-300
+ -ms (for the Hitachi H8/S processor)
+ -mint32
+
+New features for the ARM:
+
+ -march=xxx, -mtune=xxx, -mcpu=xxx
+ Support interworking with Thumb code.
+ ARM processor with a.out object format, COFF, or AOF assembler.
+ ARM on "semi-hosted" platform.
+ ARM running NetBSD.
+ ARM running the Linux-based GNU system.
+
+New feature for Solaris systems:
+
+ GCC installation no longer makes a copy of system include files,
+ thus insulating GCC better from updates to the operating system.
+
+
+Noteworthy changes in GCC version 2.7.2
+---------------------------------------
A few bugs have been fixed (most notably the generation of an
invalid assembler opcode on some RS/6000 systems).
-Noteworthy changes in GCC version 2.7.1:
+Noteworthy changes in GCC version 2.7.1
+---------------------------------------
This release fixes numerous bugs (mostly minor) in GCC 2.7.0, but
also contains a few new features, mostly related to specific targets.
@@ -31,8 +354,9 @@ sequence used in GCC version 2.7.0. That calling sequence was based on the AIX
calling sequence without function descriptors. To compile code for that older
calling sequence, either configure the compiler for powerpc-*-eabiaix or use
the -mcall-aix switch when compiling and linking.
-
-Noteworthy changes in GCC version 2.7.0:
+
+Noteworthy changes in GCC version 2.7.0
+---------------------------------------
GCC now works better on systems that use ".obj" and ".exe" instead of
".o" and no extension. This involved changes to the driver program,
@@ -284,7 +608,7 @@ The following new configurations are supported:
GNU on x86 (instead of treating it like MACH)
NetBSD on Sparc and Motorola 68k
AIX 4.1 on RS/6000 and PowerPC systems
- Sequent DYNUX/ptx 1.x and 2.x.
+ Sequent DYNIX/ptx 1.x and 2.x.
Both COFF and ELF configurations on AViiON without using /bin/gcc
Windows/NT on x86 architecture; preliminary
AT&T DSP1610 digital signal processor chips
@@ -508,7 +832,7 @@ to declare complex data types. See the manual for details.
* GCC now supports `long double' meaningfully on the Sparc (128-bit
floating point) and on the 386 (96-bit floating point). The Sparc
-support is enabled on on Solaris 2.x because earlier system versions
+support is enabled on Solaris 2.x because earlier system versions
(SunOS 4) have bugs in the emulation.
* All targets now have assertions for cpu, machine and system. So you
diff --git a/contrib/gcc/PROJECTS b/contrib/gcc/PROJECTS
index ee9be02..2c2111a 100644
--- a/contrib/gcc/PROJECTS
+++ b/contrib/gcc/PROJECTS
@@ -1,12 +1,64 @@
-0. Improved efficiency.
+C++ template friend functions (mmitchell@usa.net)
-* Parse and output array initializers an element at a time, freeing
-storage after each, instead of parsing the whole initializer first and
-then outputting. This would reduce memory usage for large
-initializers.
+Haifa scheduler (haifa-sched.c, loop.[ch], unroll.[ch], genattrtab.c):
+(contact law@cygnus.com before starting any serious haifa work)
-* See if the techniques describe in Oct 1991 SIGPLAN Notices
-(Frazer and Hanson) are applicable to GCC.
+ * Fix all the formatting problems. Simple, mindless work.
+
+ * Fix/add comments throughout the code. Many of the comments are from
+ the old scheduler and are out of date and misleading. Many new hunks
+ of code don't have sufficient comments and documentation. Those which
+ do have comments need to be rewritten to use complete sentences and
+ proper formatting.
+
+ * Someone needs make one (or more) passes over the scheduler as a whole to
+ just clean it up. Try to move the machine dependent bits into the target
+ files where they belong, avoid re-creating functions where or near
+ equivalents already exist (ie is_conditional_branch and friends), etc., etc.
+
+ * Document the new scheduling options. Remove those options which are
+ not really useful (like reverse scheduling for example). In general
+ the haifa scheduler adds _way_ too many options. I'm definitely of the
+ opinion that gcc already has too many -foptions, and haifa doesn't help
+ that situation.
+
+ * Testing and benchmarking. We've converted a few ports to using the
+ Haifa scheduler (hppa, sparc, ppc, alpha). We need to continue testing
+ and benchmarking the new scheduler on additional targets.
+
+ We need to have some kind of docs for how to best describe a machine to
+ the haifa scheduler to get good performance. Some existing ports have
+ been tuned to deal with the old scheduler -- they may need to be tuned
+ to generate good schedules with haifa.
+
+
+
+Improvements to global cse and partial redundancy elimination:
+
+The current implementation of global cse uses partial redundancy elimination
+as described in Chow's thesis.
+
+Long term we want to use lazy code motion as the basis for partial redundancy
+elimination. lcm will find as many (or more) redunancies *and* it will
+place the remaining computations at computationally optimal placement points
+within the function. This reduces the number of redundant operations performed
+as well as reducing register lifetimes. My experiments have shown that the
+cases were the current PRE code hurts performance are greatly helped by using
+lazy code motion.
+
+lcm also provides the underlying framework for several additional optimizations
+such as shrink wrapping, spill code motion, dead store elimination, and generic
+load/store motion (all the other examples are subcases of load/store motion).
+
+It can probably also be used to improve the reg-stack pass of the compiler.
+
+Contact law@cygnus.com if you're interested in working on lazy code motion.
+
+-------------
+
+The old PROJECTS file. Stuff I know has been done has been deleted.
+Stuff in progress has a contact name associated with it.
+has been
1. Better optimization.
@@ -20,28 +72,6 @@ The difficulty is in finding a clean way for the RTL which refers
to the constant (currently, only by an assembler symbol name)
to point to the constant and cause it to be output.
-* More cse
-
-The techniques for doing full global cse are described in the red
-dragon book, or (a different version) in Frederick Chow's thesis from
-Stanford. It is likely to be slow and use a lot of memory, but it
-might be worth offering as an additional option.
-
-It is probably possible to extend cse to a few very frequent cases
-without so much expense.
-
-For example, it is not very hard to handle cse through if-then
-statements with no else clauses. Here's how to do it. On reaching a
-label, notice that the label's use-count is 1 and that the last
-preceding jump jumps conditionally to this label. Now you know it
-is a simple if-then statement. Remove from the hash table
-all the expressions that were entered since that jump insn
-and you can continue with cse.
-
-It is probably not hard to handle cse from the end of a loop
-around to the beginning, and a few loops would be greatly sped
-up by this.
-
* Optimize a sequence of if statements whose conditions are exclusive.
It is possible to optimize
@@ -174,42 +204,8 @@ or outside of a particular loop where the variable is not used. (The
latter is nice because it might let the variable be in a register most
of the time even though the loop needs all the registers.)
-It might not be very hard to do this in global.c when a variable
-fails to get a hard register for its entire life span.
-
-The first step is to find a loop in which the variable is live, but
-which is not the whole life span or nearly so. It's probably best to
-use a loop in which the variable is heavily used.
-
-Then create a new pseudo-register to represent the variable in that loop.
-Substitute this for the old pseudo-register there, and insert move insns
-to copy between the two at the loop entry and all exits. (When several
-such moves are inserted at the same place, some new feature should be
-added to say that none of those registers conflict merely because of
-overlap between the new moves. And the reload pass should reorder them
-so that a store precedes a load, for any given hard register.)
-
-After doing this for all the reasonable candidates, run global-alloc
-over again. With luck, one of the two pseudo-registers will be fit
-somewhere. It may even have a much higher priority due to its reduced
-life span.
-
-There will be no room in general for the new pseudo-registers in
-basic_block_live_at_start, so there will need to be a second such
-matrix exclusively for the new ones. Various other vectors indexed by
-register number will have to be made bigger, or there will have to be
-secondary extender vectors just for global-alloc.
-
-A simple new feature could arrange that both pseudo-registers get the
-same stack slot if they both fail to get hard registers.
-
-Other compilers split live ranges when they are not connected, or
-try to split off pieces `at the edge'. I think splitting around loops
-will provide more speedup.
-
-Creating a fake binding block and a new like-named variable with
-shorter life span and different address might succeed in describing
-this technique for the debugger.
+Contact meissner@cygnus.com before starting any work on live range
+splitting.
* Detect dead stores into memory?
@@ -218,6 +214,10 @@ the same location; and, in between, there is no reference to anything
that might be that location (including no reference to a variable
address).
+This can be modeled as a partial redundancy elimination/lazy code motion
+problem. Contact law@cygnus.com before working on dead store elimination
+optimizations.
+
* Loop optimization.
Strength reduction and iteration variable elimination could be
@@ -286,8 +286,9 @@ to the order in which to generate code for subexpressions of an expression.
* More code motion.
-Consider hoisting common code up past conditional branches or
-tablejumps.
+Consider hoisting common code up past conditional branches or tablejumps.
+
+Contact law@cygnus.com before working on code hoisting.
* Trace scheduling.
diff --git a/contrib/gcc/README b/contrib/gcc/README
index 0923669..c606f65 100644
--- a/contrib/gcc/README
+++ b/contrib/gcc/README
@@ -1,10 +1,7 @@
-This directory contains the version 2.7.2.3 release of the GNU C
+This directory contains the egcs version 1.1.2 release of the GNU C
compiler. It includes all of the support for compiling C++ and
Objective C, including a run-time library for Objective C.
-The reason for the 2.7.2.3 release is to correct the support for GNU C
-library version 2 on GNU/Linux systems.
-
The GNU C compiler is free software. See the file COPYING for copying
permission.
diff --git a/contrib/gcc/README-bugs b/contrib/gcc/README-bugs
new file mode 100644
index 0000000..06e15bb
--- /dev/null
+++ b/contrib/gcc/README-bugs
@@ -0,0 +1,144 @@
+The purpose of GCC pretesting is to verify that the new GCC
+distribution, about to be released, works properly on your system *with
+no change whatever*, when installed following the precise
+recommendations that come with the distribution.
+
+Here are some guidelines on how to do pretesting so as to make it
+helpful. All of them follow from common sense together with the
+nature of the purpose and the situation.
+
+* It is absolutely vital that you mention even the smallest change or
+departure from the standard sources and installation procedure.
+
+Otherwise, you are not testing the same program that I wrote. Testing
+a different program is usually of no use whatever. It can even cause
+trouble if you fail to tell me that you tested some other program
+instead of what I know as GCC. I might think that GCC works, when in
+fact it has not been properly tried, and might have a glaring fault.
+
+* Even changing the compilation options counts as a change in the
+program. The GCC sources specify which compilation options to use.
+Some of them are specified in makefiles, and some in machine-specific
+configuration files.
+
+You have ways to override this--but if you do, then you are not
+testing what ordinary users will do. Therefore, when pretesting, it
+is vital to test with the default compilation options.
+
+(It is okay to test with nonstandard options as well as testing with
+the standard ones.)
+
+* The machine and system configuration files of GCC are parts of
+GCC. So when you test GCC, you need to do it with the
+configuration files that come with GCC.
+
+If GCC does not come with configuration files for a certain machine,
+and you test it with configuration files that don't come with GCC,
+this is effectively changing GCC. Because the crucial fact about
+the planned release is that, without changes, it doesn't work on that
+machine.
+
+To make GCC work on that machine, I would need to install new
+configuration files. That is not out of the question, since it is
+safe--it certainly won't break any other machines that already work.
+But you will have to rush me the legal papers to give the FSF
+permission to use a large piece of text.
+
+* Look for recommendations for your system.
+
+You can find these recommendations in the Installation node of the
+manual, and in the file INSTALL. (These two files have the same text.)
+
+These files say which configuration name to use for your machine, so
+use the ones that are recommended. If you guess, you might guess
+wrong and encounter spurious difficulties. What's more, if you don't
+follow the recommendations then you aren't helping to test that its
+recommendations are valid.
+
+These files may describe other things that you need to do to make GCC
+work on your machine. If so, you should follow these recommendations
+also, for the same reason.
+
+Also look at the Trouble chapter of the manual for items that
+pertain to your machine.
+
+* Don't delay sending information.
+
+When you find a problem, please double check it if you can do so
+quickly. But don't spend a long time double-checking. A good rule is
+always to tell me about every problem on the same day you encounter
+it, even if that means you can't find a solution before you report the
+problem.
+
+I'd much rather hear about a problem today and a solution tomorrow
+than get both of them tomorrow at the same time.
+
+* Make each bug report self-contained.
+
+If you refer back to another message, whether from you or from someone
+else, then it will be necessary for anyone who wants to investigate
+the bug to find the other message. This may be difficult, it is
+probably time-consuming.
+
+To help me save time, simply copy the relevant parts of any previous
+messages into your own bug report.
+
+In particular, if I ask you for more information because a bug report
+was incomplete, it is best to send me the *entire* collection of
+relevant information, all together. If you send just the additional
+information, that makes me do extra work. There is even a risk that
+I won't remember what question you are sending me the answer to.
+
+* Always be precise when talking about changes you have made. Show
+things rather than describing them. Use exact filenames (relative to
+the main directory of the distribution), not partial ones. For
+example, say "I changed Makefile" rather than "I changed the
+makefile". Instead of saying "I defined the MUMBLE macro", send a
+diff that shows your change.
+
+* Always use `diff -c' to make diffs. If you don't include context,
+it may be hard for me to figure out where you propose to make the
+changes. I might have to ignore your patch because I can't tell what
+it means.
+
+* When you write a fix, keep in mind that I can't install a change
+that would break other systems.
+
+People often suggest fixing a problem by changing machine-independent
+files such as toplev.c to do something special that a particular
+system needs. Sometimes it is totally obvious that such changes would
+break GCC for almost all users. I can't possibly make a change like
+that. All I can do is send it back to you and ask you to find a fix
+that is safe to install.
+
+Sometimes people send fixes that *might* be an improvement in
+general--but it is hard to be sure of this. I can install such
+changes some of the time, but not during pretest, when I am trying to
+get a new version to work reliably as quickly as possible.
+
+The safest changes for me to install are changes to the configuration
+files for a particular machine. At least I know those can't create
+bugs on other machines.
+
+* Don't try changing GCC unless it fails to work if you don't change it.
+
+* Don't even suggest changes that would only make GCC cleaner.
+Every change I install could introduce a bug, so I won't install
+a change unless I see it is necessary.
+
+* If you would like to suggest changes for purposes other than fixing
+serious bugs, don't wait till pretest time. Instead, send them just
+after I make a release. That's the best time for me to install them.
+
+* In some cases, if you don't follow these guidelines, your
+information might still be useful, but I might have to do more work to
+make use of it. Unfortunately, I am so far behind in my work that I
+just can't get the job done unless you help me to do it efficiently.
+
+
+ Thank you
+ rms
+
+Local Variables:
+mode: text
+End:
diff --git a/contrib/gcc/README.DWARF b/contrib/gcc/README.DWARF
index ac4719d..9745950 100644
--- a/contrib/gcc/README.DWARF
+++ b/contrib/gcc/README.DWARF
@@ -11,7 +11,7 @@ For general information about the DWARF debugging information language,
you should obtain the DWARF version 1 specification document (and perhaps
also the DWARF version 2 draft specification document) developed by the
UNIX International Programming Languages Special Interest Group. A copy
-of the the DWARF version 1 specification (in PostScript form) may be
+of the DWARF version 1 specification (in PostScript form) may be
obtained either from me <rfg@netcom.com> or from the main Data General
FTP server. (See below.) The file you are looking at now only describes
known deviations from the DWARF version 1 specification, together with
@@ -117,7 +117,7 @@ more of the formal parameter values, they may not have been "homed" yet,
so you may get inaccurate answers (or perhaps even addressing errors).
Some people may consider this simply a non-feature, but I consider it a
-bug, and I hope to provide some some GNU-specific attributes (on function
+bug, and I hope to provide some GNU-specific attributes (on function
DIEs) which will specify the address of the end of the prologue and the
address of the beginning of the epilogue in a future release.
@@ -159,7 +159,7 @@ is required by the current DWARF draft specification.
Specifically, the current DWARF draft specification seems to require that
the type of an non-unsigned integral bit-field member of a struct or union
type be represented as either a "signed" type or as a "plain" type,
-depending upon the the exact set of keywords that were used in the
+depending upon the exact set of keywords that were used in the
type specification for the given bit-field member. It was felt (by the
UI/PLSIG) that this distinction between "plain" and "signed" integral types
could have some significance (in the case of bit-fields) because ANSI C
diff --git a/contrib/gcc/README.g77 b/contrib/gcc/README.g77
new file mode 100644
index 0000000..f22f179
--- /dev/null
+++ b/contrib/gcc/README.g77
@@ -0,0 +1,263 @@
+1998-08-11
+
+This directory contains the egcs variant of version 0.5.24 of the
+GNU Fortran compiler (g77). The GNU Fortran compiler is free software.
+See the file COPYING.g77 for copying permission.
+
+Currently, two variants of g77 exist. One is the Free Software Foundation
+(FSF) variant. The other is the egcs variant. As of egcs version 1.1,
+these variants are kept fairly similar in most respects. Pertinent
+differences, such as the layout of the source code, are specified below.
+
+Below, `[FSF]' denotes information applicable to only the FSF variant of
+g77, while `[egcs]' denotes egcs-only information.
+
+
+* IMPORTANT: Things you *must* do (or avoid) are marked with a * at the
+ beginning of the line in this file!!!
+
+
+The email address to which bugs are to be reported is either
+[FSF] <fortran@gnu.org> or [egcs] <egcs-bugs@cygnus.com>.
+
+* *DO NOT* send any email (reporting bugs, asking questions, etc.) to
+ either of these addresses without *first* reading the g77 documentation.
+ Use `info', Info mode in GNU Emacs, or a text viewer such as `more' to
+ do this.
+
+ The g77 documentation is in the source files named `g77.info',
+ `g77.info-1', `g77.info-2', and so on in the `f' subdirectory. If these
+ files are not present or you can't find them, contact the person or
+ organization that put together the g77 distribution you are using (probably
+ not the FSF or egcs), or ask your system administrator for help.
+
+
+This README applies to only the g77-specific portions of the source-code
+tree that contains it. These portions include:
+
+ - The README.g77 and [FSF] COPYING.g77 files, in this directory, "this
+ directory" being [FSF] the top-level directory containing a g77
+ distribution or [egcs] the gcc/ subdirectory of an egcs distribution.
+
+ - The g77 front end, in the f/ subdirectory of this directory.
+
+ - The libg2c library, in [FSF] the f/runtime/ subdirectory of this
+ directory or [egcs] the libf2c/ directory under the top-level
+ directory of the egcs distribution.
+
+
+* To build g77, you must have a source distribution of [FSF] gcc
+ version 2.8 or [egcs] egcs version 1.1. Do not attempt to use
+ any other version of gcc or egcs, because this version of g77 is
+ designed to work with only those versions.
+
+ Note that you must have *source* copies of the gcc or egcs distribution!
+ You cannot build g77 just using binaries of gcc or egcs. Also, unless
+ you are an expert, avoid using any distribution of gcc or egcs not
+ identical to the ones distributed by the FSF and Cygnus Support,
+ respectively. The primary FSF distribution site is:
+
+ <ftp://ftp.gnu.org/pub/gnu/>
+
+ The primary egcs distribution site is:
+
+ <ftp://ftp.cygnus.com/pub/egcs/>
+
+ Both of these sites have approved mirror sites from which valid
+ distributions also may be obtained.
+
+* Do not attempt to combine the egcs version of g77 with the FSF
+ gcc distribution, or the FSF version of g77 with the egcs gcc
+ distribution. Although the differences are minor, they might
+ be sufficient to prevent g77 from building properly, or from
+ working properly if the build appears to succeed.
+
+[FSF] g77 is distributed as g77-<version>/f/ so that unpacking the g77
+distribution is done in the normal GNU way, resulting in a directory having
+the version number in the name. However, to build g77, the g77 distribution
+must be merged with an appropriate gcc distribution, normally in a gcc
+source directory, before configuring, building, and installing g77.
+
+[FSF] If you have just unpacked the g77 distribution, before proceeding,
+you must merge the contents of the g77 distribution with the appropriate
+gcc distribution on your system.
+
+* [FSF] Read and follow the instructions in f/INSTALL that
+ explain how to merge a g77 source directory into a gcc source
+ directory. You can use Info to read the same installation
+ instructions via:
+
+ info -f f/g77.info -n Unpacking
+
+[FSF] The resulting directory layout includes the following, where gcc/
+might be a link to, for example, gcc-2.8.1/:
+
+ gcc/ Non-g77 files in gcc
+ gcc/COPYING.g77 A copy of the GPL, under which g77 is licensed
+ gcc/README.g77 This file
+ gcc/f/ GNU Fortran front end
+ gcc/f/runtime/ libg2c configuration and g2c.h file generation
+ gcc/f/runtime/libF77/ Non-I/O portion of libg2c
+ gcc/f/runtime/libI77/ I/O portion of libg2c
+ gcc/f/runtime/libU77/ Additional interfaces to libc for libg2c
+
+[FSF] Applying g77 patches in the form of .diff files is done by typing
+`patch -p1 -d gcc' (where gcc/ contains the f/ subdirectory). That is,
+g77 patches are distributed in the same form, and at the same directory
+level, as patches to the gcc distribution. (Note: make sure you're
+using GNU patch, version 2.5 or later! Other versions of patch
+have trouble with g77-related patches.)
+
+[egcs] The egcs version of g77 is distributed already merged with
+the rest of egcs (such as the gcc back end).
+
+[egcs] The resulting directory layout includes the following, where egcs/
+might be a link to, for example, egcs-1.1/:
+
+ egcs/gcc/ Non-g77 files in gcc
+ egcs/gcc/README.g77 This file
+ egcs/gcc/f/ GNU Fortran front end
+ egcs/libf2c/ libg2c configuration and g2c.h file generation
+ egcs/libf2c/libF77/ Non-I/O portion of libg2c
+ egcs/libf2c/libI77/ I/O portion of libg2c
+ egcs/libf2c/libU77/ Additional interfaces to libc for libg2c
+
+[egcs] Applying g77-specific patches to egcs is done the same way as
+applying other egcs patches.
+
+
+Below, `libf2c/' shall denote [FSF] gcc/f/runtime/ or [egcs] egcs/libf2c/,
+while `f/' shall denote [FSF] the rest of gcc/f/ or [egcs] egcs/gcc/f/.
+
+
+Components of note in g77 are described below.
+
+f/ as a whole contains the program GNU Fortran (g77), while libf2c/
+contains a portion of the separate program f2c. Note: The libf2c
+code is not part of the program g77, just distributed with it.
+
+f/ contains text files that document the Fortran compiler, source
+files for the GNU Fortran Front End (FFE), and some other stuff.
+The g77 compiler code is placed in f/ because it, along with its contents,
+is designed to be a subdirectory of a GNU CC (gcc) source directory, gcc/,
+which is structured so that language-specific front ends can be "dropped
+in" as subdirectories. The C++ front end (g++), is an example of this --
+it resides in the cp/ subdirectory. Note that the C front end (also
+referred to as gcc) is an exception to this, as its source files reside
+in the gcc/ directory itself.
+
+libf2c/ contains the run-time libraries for the f2c program, also used
+by g77. These libraries normally referred to collectively as libf2c.
+When built as part of g77, libf2c is installed under the name libg2c to avoid
+conflict with any existing version of libf2c, and thus is often referred
+to as libg2c when the g77 version is specifically being referred to.
+
+The netlib version of libf2c/ contains two distinct libraries, libF77 and
+libI77, each in their own subdirectories. In g77, this distinction is not
+made, beyond maintaining the subdirectory structure in the source-code tree.
+
+libf2c/ is not part of the program g77, just distributed with it. It
+contains files not present in the official (netlib) version of libf2c,
+and also contains some minor changes made from libf2c, to fix some bugs,
+and to facilitate automatic configuration, building, and installation of
+libf2c (as libg2c) for use by g77 users.
+
+* See libf2c/README for more information, including licensing conditions
+ governing distribution of programs containing code from libg2c.
+
+libg2c, g77's version of libf2c, adds Dave Love's implementation of
+libU77, in the libf2c/libU77/ directory. This library is distributed
+under the GNU Library General Public License (LGPL) -- see the
+file libf2c/libU77/COPYING.LIB for more information, as this license
+governs distribution conditions for programs containing code from
+this portion of the library.
+
+
+Files of note in g77 are described below.
+
+f/BUGS lists some important bugs known to be in g77. Or:
+
+ info -f f/g77.info -n "Actual Bugs"
+
+f/ChangeLog lists recent changes to g77 internals.
+
+libf2c/ChangeLog lists recent changes to libg2c internals.
+
+[FSF] f/INSTALL describes how to build and install GNU Fortran. Or:
+
+ info -f f/g77.info -n Installation
+
+f/NEWS contains the per-release changes. These include the user-visible
+changes described under "Changes" in the g77 documentation, plus internal
+changes of import. Or:
+
+ info -f f/g77.info -n News
+
+* All users of g77 (not just installers) should read f/g77.info*
+ as well, using the `more' command if neither the `info' command,
+ nor GNU Emacs (with its Info mode), are available, or if they
+ aren't yet accustomed to using these tools. Read f/BUGS and f/NEWS
+ plus, if you are planning on building or installing the FSF version
+ of g77, f/INSTALL, at the very least! All of these files are
+ readable as "plain text" files.
+
+* Also see <ftp://alpha.gnu.org/g77.plan> for up-to-date information
+ regarding g77 bug reports, known bugs, bug-fixes, and new versions.
+
+
+The rest of this file is of note to only those who wish to
+debug, modify, or test the FFE (in conjunction with the gcc back end).
+
+If you want to explore the FFE code, which lives entirely in f/, here
+are a few clues. The file g77spec.c contains the g77-specific source code
+for the `g77' command only -- this just forms a variant of the `gcc'
+command, so, just as the `gcc' command itself does not contain
+the C front end, the `g77' command does not contain the Fortran front
+end (FFE). The FFE code ends up in an executable named `f771', which
+does the actual compiling, so it contains the FFE plus the gcc back end
+(the latter to do most of the optimization, and the code generation).
+
+The file parse.c is the source file for main() for a stand-alone FFE and
+yyparse() for f771. (Stand-alone building of the FFE doesn't work these days.)
+The file top.c contains the top-level FFE function ffe_file and it (along
+with top.h) define all ffe_[a-z].*, ffe[A-Z].*, and FFE_[A-Za-z].* symbols.
+The file fini.c is a main() program that is used when building the FFE to
+generate C header and source files for recognizing keywords. The files
+malloc.c and malloc.h comprise a memory manager that defines all
+malloc_[a-z].*, malloc[A-Z].*, and MALLOC_[A-Za-z].* symbols. All other
+modules named <xyz> are comprised of all files named <xyz>*.<ext> and
+define all ffe<xyz>_[a-z].*, ffe<xyz>[A-Z].*, and FFE<XYZ>_[A-Za-z].* symbols.
+If you understand all this, congratulations -- it's easier for me to remember
+how it works than to type in these grep patterns (such as they are). But it
+does make it easy to find where a symbol is defined -- for example,
+the symbol "ffexyz_set_something" would be defined in xyz.h and implemented
+there (if it's a macro) or in xyz.c.
+
+The "porting" files of note currently are: proj.h, which defines the
+"language" used by all the other source files (the language being
+Standard C plus some useful things like ARRAY_SIZE and such) -- change
+this file when you find your system doesn't properly define a Standard C
+macro or function, for example; target.h and target.c, which describe
+the target machine in terms of what data types are supported, how they are
+denoted (what C type does an INTEGER*8 map to, for example), how to convert
+between them, and so on (though as of 0.5.3, more and more of this information
+is being dynamically configured by ffecom_init_0); com.h and com.c, which
+interface to the target back end (currently only FFE stand-alone and the GBE);
+ste.c, which contains code for implementing recognized executable statements
+in the target back end (again currently either FFE or GBE); src.h and src.c,
+which describe information on the format(s) of source files (such as whether
+they are never to be processed as case-insensitive with regard to Fortran
+keywords); and proj.c, which contains whatever code is needed to support
+the language defined by proj.h.
+
+If you want to debug the f771 executable, for example if it crashes,
+note that the global variables "lineno" and "input_filename" are set
+to reflect the current line being read by the lexer during the first-pass
+analysis of a program unit and to reflect the current line being
+processed during the second-pass compilation of a program unit. If
+an invocation of the function ffestd_exec_end() is on the stack,
+the compiler is in the second pass, otherwise it is in the first.
+(This information might help you reduce a test case and/or work around
+a bug in g77 until a fix is available.)
+
+Any questions or comments on these topics? Read the g77 documentation!
diff --git a/contrib/gcc/SERVICE b/contrib/gcc/SERVICE
index 11e266a..6404b7c 100644
--- a/contrib/gcc/SERVICE
+++ b/contrib/gcc/SERVICE
@@ -35,78 +35,243 @@ have nothing to go by. Please put each e-mail address inside "<>".
Please put nothing else inside "<>". Thanks!
For a current copy of this directory, or to have yourself listed, ask:
- gnu@prep.ai.mit.edu
+ gnu@gnu.org
** Please keep the entries in this file alphabetical **
+
+Alc?ve <infos@alcove.fr>
+12 place Indira Gandhi
+92230 Gennevilliers
+France
+
+http://www.alcove.fr
+T?l.: +33 1 47 33 82 84
+Fax: +33 1 47 33 76 98
+
+Alc?ve offers a comprehensive range of corporate-quality
+Free Software related solutions, with technical support
+via telephone, fax or email and remote system management.
+We also offers consulting and training.
+Rates approximately 3000FF per day, depending on the job.
+
+Updated: 1998-09-09

-Joseph Arceneaux <jla@ai.mit.edu>
-PO Box 460633 http://www.samsara.com/~jla
-San Francisco, CA 94146-0633
-+1 415 648 9988
-+1 415 285 9088
+Altrasoft <info@altrasoft.com>
+4880 Stevens Creek Blvd., Suite 205
+San Jose, CA 95129-1034
++1 408 243 3300
+http://www.altrasoft.com
+
+Altrasoft provides corporate-quality support, development and user
+documentation for GNU Emacs, XEmacs and InfoDock. (InfoDock is a turnkey
+information management and software development toolset built atop emacs,
+written by one of our associates.) Emacs distributions for a variety of
+platforms are also available, as is support for other emacs variants, such as
+those often found on PCs.
+
+Our unique focus on emacs-related work allows us to attract expert talent in
+this area to keep you on the leading edge of productivity, especially if you
+do software development work. We do the porting, patching, coding,
+integrating, debugging, documenting and testing so that your people spend
+much more productive time on their mainline tasks.
+
+Standard support packages include help on all aspects of the packages
+supported, including all tools shipped as a standard part of the original
+package distribution. In general, we want to give you an unbelievably strong
+level of support, so where we can, we will also answer questions concerning
+any add-on Lisp code that is used at your site. Setup and customization
+help, bug fixes, and announcements of new releases are, of course, included.
+
+Support rates start at $1,500 USD, for single user support for one year.
+Discounts are available for group contracts. We also offer Golden Support
+contracts for those who need the absolute best in mission-critical support;
+contact us for details. Hourly development rates and fixed bid work are
+available.
+
+Updated: 1997-05-12
+
+Magnus Alvestad <magnus@itanalyse.no>
-Recently led the project making Wells Fargo Bank the first to provide
-secure customer account access over the Internet.
+GNU Emacs, GCC, the Unix tools, Linux, Jolt.
-Former FSF staffmember. Performed X11 implementation of Emacs version
-19, designed and implemented WYSIWYG Emacs. Installed and
-administered FSF network. Maintainer of GNU indent. Over 15 years
-experience with Unix and other systems, from writing ROM monitors to
-UI design and system administration.
+Rates: Free, or from $50/hour.
+
+Updated: 1997-05-09
+
+AO UrbanSoft <info@usoft.spb.su>
+St. Petersburg State University Science Campus
+St. Petersburg, Russia
+www.usoft.spb.ru
+
+AO UrbanSoft packages, markets and supports
+industry standard free software products,
+including the Linux operating system and
+TeX document compiler.
+The company also provides programming services
+based on TeX, Tk, Python, HTML, Java, Perl and
+Intranet.
+
+Rates approximately 15 USD per hour.
+
+Updated: 1997-05-25
+
+Joseph Arceneaux <joe@arceneaux.com>
+307 Chattanooga St. http://www.arceneaux.com
+San Francisco, CA 94114
++1 415 648 9988
+
+I am a former FSF staffmember who made Wells Fargo Bank the first bank
+to provide secure banking over the Internet. I have 20 years
+experience with various computer systems. I performed the X11
+implementation of Emacs version 19, and designed and implemented
+WYSIWYG features of Emacs. I also installed and administered FSF
+network. Maintainer of GNU indent.
I provide installation, porting, debugging and customization or
-development of GNU and other Unix software. I also design and
-implement free software projects and consult on software engineering
-and systems design. Handholding and teaching services are also
-available as well as things like LAN and compute--infrastructure design.
+development of GNU and other software. I also design and implement
+free software projects and consult on software engineering, security,
+and intranet design.
Time and material rates around $150 USD per hour, depending upon the
particular job. I am also very interested in fixed-bid jobs. For
selected non-profit organizations with worthy goals, I work for free.
-Updated: 17Oct95
+Updated: 1998-06-24

-Gerd Aschemann <aschemann@Informatik.TH-Darmstadt.de>
+Dipl.-Inform. Gerd Aschemann <Aschemann@Informatik.TU-Darmstadt.de>
Osannstr. 49
D-64285 Darmstadt
Tel.: +49 6151 16 2259
-http://www.informatik.th-darmstadt.de/~ascheman/
+http://www.informatik.tu-darmstadt.de/VS/Mitarbeiter/Aschemann/
-- System Administrator (UNIX) at CS Department, TU Darmstadt, Germany
-- 15 years expirience with CS, Systemadministration on different platforms
-- 8 years with UNIX/Networking/FreeWare/GNU/X11
-- 6 years organizer of Operating Systems and Distributed Systems courses
+- System Administrator (UNIX and NT) at CS Department, TU Darmstadt, Germany
+- 18 years working in the CS field, System administration on different platforms
+- 12 years with UNIX/Networking/FreeWare/GNU/X11
+- 9 years courses on Operating Systems and Distributed Systems
- Lectures on System and Network Administration
-- Platforms: Solaris, SunOS, Ultrix, OSF1, HP-UX, Linux, FreeBSD, AIX
+- Platforms: Solaris, Linux, SunOS, Ultrix, HP-UX, Digital Unix, AIX, SCO, FreeBSDs
+- Distributed Platforms and Information Systems (CORBA, WWW, Java)
- Experience with parallel environments (Connection Machine, Meiko, Parsytec)
-- Consultant for other UNIX users at TU Darmstadt
+- Consultant
-Rates are at 100,-- DM (~60 US$) per hour minimum, depending on the job.
+Rates are at 150,-- DM (~85 US$) per hour minimum, depending on the job.
I am willing to travel for sufficiently large jobs.
-Updated: 17Oct95
+Updated: 1998-07-23
+
+
+ Basis Technology Corp.
+ One Kendall Square, Bldg 200
+ Cambridge, MA 02139
+ U.S.A.
+
+ Tel: +1-617-252-5636
+ Fax: +1-617-252-9150
+ E-mail: <info@basistech.com>
+ Web: http://www.basistech.com
+
+Technical Expertise:
+ Multilingual software development
+ Internationalization and localization of software products
+ International character encodings, including Unicode, ISO-10646,
+ ISO-2022, ISO-8859-n, JIS, KSC5601, BIG5, GB2312
+ Translation of technical materials into Japanese, Korean, and Chinese
+ including HTML, SGML, RTF, MIF, etc.
+
+GNU-related Services:
+ Custom internationalization and localization of GNU software, or
+ applications developed using GNU tools (GCC, G++, Emacs Lisp, etc.)
+ Custom multilingual application development based on MULE.
+
+GNU Contributions:
+ Organized 1992, 1993, and 1994 fund-raising seminars and lecture
+ tours for FSF in Japan.
+ Negotiated book royalty agreements with Japanese publishers on
+ behalf of the FSF.
+ Negotiated hardware contributions from Japanese PC vendors to
+ the FSF.
+
+Contacts:
+ Carl Hoffman, Steve Cohen, or Karen Watts
+
+Updated: 1998-07-23
+
+Laurent Bernardin
+16, rue Dicks
+L-6944 Niederanven
+Luxemburg
+<bernardin@inf.ethz.ch>
++41 1 632 7469
+
+Support and installation of all GNU software.
+
+Expertise: C, C++, Java, Motif, X, Unix administration, network security
+
+Rates: ~60 US$ / hour (Flux 2000.-)
+
+Updated: 1998-07-23

-Giuseppe Attardi <attardi@di.unipi.it>
-Dipartimento di Informatica
-Corso Italia 40
-I-56125 Pisa, Italy
-+39 50 887-244
+Dean Brettle Computer Consulting
+
+<dean@brettle.com>
+http://www.brettle.com/
+
+7485 Rush River Drive
+Suite 710-193
+Sacramento, CA 95831
+916-422-8129
-GNU: help on obtaininig GNU, for italian sites.
+I provide development, technical support, and training for free software
+and open source systems including GNU/Linux, the GNU development suite,
+Tcl/Tk, Emacs, and the GIMP.
-Updated: 5Apr94
+I have over 9 years experience building and maintaining systems ranging
+from computed tomography systems to airborne sensor control systems --
+all with free software.
+
+Rates range from $65.00/hr to $72.50/hr USD, depending upon work
+location. I am also willing to work on fixed price contracts.
+
+Updated: 1998-07-07
+
+Philip Brown
+<phil@mitre.org>
+(703) 893-8967 (prefer email)
+Northern-VA, D.C. Area (world-wide via internet)
+Rates: $45/Hr + extra for site visit; less for educational or charitable organizations
+
+Systems Supported:
+
+ Sun boxes running Solaris 2.5-up
+ HP9000s running HP/UX 8.07 - 10.X
+ IBM RS6000 running AIX 3.2.X-up
+ Also SGI/Indy
+
+Software Supported:
+ Most all FSF (Gnu) software
+ esp. GCC, GDB, Emacs, Binutils, GS, et al...
+
+Statement:
+ I'd be more than happy to assist anyone in my area with acquiring,
+ installing, and configuring any FSF tools/utilities on any of the
+ above systems. I'm also willing to work with other UNIX systems not
+ listed above. In addition, I'm glad to share my many years of
+ experience with anyone having difficulty using or configuring these
+ tools. I've been installing and using them for about 5 years now
+ and I'll swear by their quality and the people/principles that made
+ them available.
+
+
+ Phil Brown
+
+Updated: 1998-07-23

James Craig Burley
97 Arrowhead Circle
Ashland, MA 01721-1987
-508 881-6087, -4745
-(Please call only between 0900-1700 Eastern time, and only if you
-are prepared to hire me -- ask me to help you for free only
-via email, to which I might or might not respond.)
-Email: <burley@gnu.ai.mit.edu> --preferred--
- <burley@cygnus.com>
- <burley@world.std.com>
+(Email and postal mail contacts only, please.)
+Email: <craig@jcb-sc.com>
Expertise:
Compiler Internals (author of GNU Fortran, for example)
@@ -117,117 +282,280 @@ Expertise:
Debugging (often asked to help debug Other People's Code)
Documentation (authored many books and ran a few doc projects)
Extensive experience with a variety of operating systems, hardware,
- languages, and so on
+ languages, and so on
-Rate: $70/hour -- willing to consider flat-fee arrangements
+Rate: $100/hour -- willing to consider flat-fee arrangements
-Updated: 14Aug95
+Updated: 1999-02-01

-Michael I. Bushnell <mib@gnu.ai.mit.edu>
-545 Technology Square, NE43-426
-Cambridge, MA 02139
-(617) 253-8568
+Thomas Bushnell, BSG <thomas@gnu.org>
+Becket House
+66 Highland Ave. No. 8
+Somerville, MA 02143
+(617) 623-0654
All GNU software: Installation, customization, answering simple or
- complex questions, bug fixing, extension.
+ complex questions, bug fixing, extension.
-Experience: I have done Unix and GNU programming for several years,
- I am the primary author of the Hurd (which provides most
- kernel related facilities for the GNU OS).
+Experience: I have done Unix and GNU programming for many years.
+ I am the primary author of the Hurd (which provides most
+ kernel related facilities for the GNU OS).
I am easily available in the Cambridge/Boston area; work via email.
I am willing to travel for sufficiently large jobs.
-Rates: $100/hr, negotiable, less for non-profit organizaions.
+Rates: $100/hr, negotiable, less for non-profit organizations.
-Updated: 5Apr94
+Updated: 1998-07-27

-C2V Renaud Dumeur <renaud@ccv.fr>
-82 bd Haussmann Michel Delval <mfd@ccv.fr>
-75009 Paris Jean-Alain Le Borgne <jalb@ccv.fr>
+C2V Michel Delval <mfd@c2v.com>
+82 bd Haussmann Jean-Alain Le Borgne <jalb@c2v.com>
+75008 Paris
France
-Tel (1) 40.08.07.07
-Fax (1) 43.87.35.99
+Tel (33 1) 40.08.07.07
+Fax (33 1) 43.87.35.99
+Compuserve 100413,1012
+http://www.c2v.com/freesoft.htm
+e-mail: <consult@c2v.com>
-We offer source or source+binary distribution, installation, training,
-maintenance, technical support, consulting, specific development and
-followup on the GNU software development environment: Emacs, gcc/g++,
-binutils, gas, gdb.
+Services: we offer source or source+binary distribution,
+installation, training, maintenance, technical support,
+consulting, specific development and followup on the GNU software
+development environment: Emacs, gcc/g++, binutils, gas, gdb.
-Experience: adapted gcc, gas and binutils to work as cross-development
-tools for the Thomson st18950 DSP chip: GCC parser and typing system
-have been augmented to allow the manipulation of variables located in
-separated memory spaces. Porting on new platforms, and professionally
-developing software with the GNU tools in the Unix/X11 environment
-since they were first available.
+Porting on new platforms, and professionally developing software
+with the GNU tools in the Unix/X11 environment since they were
+first available.
+
+Experience: GNU C Compilation toolchain for the SGS-Thomson D950
+and ST20 DSP chips.
+
+GNU C compilation toolchain (cross-compiler, compiler, linker,
+assembler, debugger) for SparcV7 ERC32 based space systems
+(Sextant Avionique / Alcatel Espace).
+
+Feasability study, analysis and prototyping of a complete
+compilation toolchain based on the GNU programming tools for the
+CSEM RISC microprocessor family.
Rates: from 2000 FF/day to 150 000 FF/year, 40% discount for
educational institutions, add taxes and expenses. Ask for list.
-Entered: 5May94
-
-Contributed Software
-Graefestr. 76
-10967 Berlin, Germany
-phone: (+49 30) 694 69 07
-FAX: (+49 30) 694 68 09
-modems: (+49 30) 694 60 55 (5xZyXEL )
-modems: (+49 30) 693 40 51 (8xUSR DS)
-email: <info@contrib.de>
-internet: uropax.contrib.de [192.109.39.2], login as 'guest'.
-
-We distribute, install, port, teach and support free software
-in general, i.e. X11, GNU, khoros etc. Rates are ECU 80,-- plus
-tax per hour. We offer maintenance and support contracts for full
-customer satisfaction.
-Highlights are transparent development environments for multi-platform
-sites and configuration management. Traveling is no problem.
-
-Free Archive login for downloading on above modem numbers.
-
-Updated: 5Apr94
-
-Stuart Cracraft <cracraft@ai.mit.edu>
-25682 Cresta Loma
-Laguna Niguel, Ca.
-92677
-GNUline: 714-347-8106
-Rate: $75/hour
+Updated: 1998-07-23
+
+Bruce Dawson - <jbd@codemeta.com>
+CodeMeta, Inc.
+Manchester, NH USA
+800-354-2209
+
+Specializing in GNU tools such as guile, CVS, gnats, bash, gawk, fileutils...
+
+Services:
+
+ o 800 phone support.
+
+ o Modification and development.
+
+ o Training.
+
+Rate: $75/hour or per quote.
+
+http://www.codemeta.com
+
+Updated: 1998-07-23
+
+Kevin Cosgrove <kevinc@dOink.COM>
+
+
+ I can help folks with porting & installation of many GNU
+ and X packages on a variety of Unix platforms.
+
+
+ My rates depend on the scope of each project but range
+ from $35 to $90 per hour.
+
+Updated: 1997-05-07
+
+Couvares Consulting
+1312 Chandler St.
+Madison, WI 53715
+Phone: (608) 256-6901
+Email: <couvares@poboxes.com>
+Contact: Peter F. Couvares
+
+Type of support: We offer phone/email support, installation, systems
+integration, systems programming, training, and specialized consulting
+services for free software in UNIX and NT environments.
+
+Sample prices: USD100/hour commercial, 50/hour non-profit, sliding
+scale for individuals.
+
+Updated: 1998-07-23
+
+Stuart Cracraft <cracraft@ai.mit.edu>
+P.O. Box 6752
+Laguna Niguel, CA, 92607, USA
+Phone: 714-308-7900
+Website: http://home.earthlink.net/~cracraft/index.html
+Rate: $50/hour, and as appropriate for the project.
+
Consultation topics:
- Entire GNU suite - porting, compilation, installation,
- user-training, administrator-training
-Method: telephone line support, call-in via modem to your site,
-or direct visit.
-
-Experience: supporting GNU since the mid-1980's, coordinator
-of GNU Chess (original author), GNU Shogi, GNU Go. Ported GNU Emacs
-to Solaris (System V Release 4). Expertise in C, Emacs Lisp, and Perl.
-Customized programming also available.
-
-Entered: 5Apr94
-
-Cygnus Support <info@cygnus.com>
-1937 Landings Drive ...uunet!cygint!info
-Mountain View, CA 94043 USA
-+1 415 903 1400 voice
-+1 415 903 0122 fax
-
-Cygnus Support
-48 Grove Street
-Somerville, MA 02144
-+1 617 629 3000 voice
-+1 617 629 3010 fax
-
-Cygnus Support continues to provide supported, maintained versions of
-the GNU toolset including GCC, G++, the GNU debugger with graphical
-user interface, GNU linker, GNU macro-assembler and Emacs 19. In
-keeping with the rapidly advancing needs of software developers,
-Cygnus maintains a 90 day release cycle of the GNU toolset. Each
-release is regression tested and includes substantial improvements and
-additions to the existing matrix of over 65 supported platform
-configurations.
-
-Updated: 2Feb95
+Entire GNU suite - porting, compilation, installation,
+user-training, administrator-training.
+
+Method: via any combination of telephone, dialup, Internet, in-person, email.
+
+Experience: supporting GNU since project inception, original port of
+GNU Emacs to Sun Solaris, original author of GNU Emacs online tutorial.
+Expertise in C, Emacs Lisp, Perl, Expect, Oracle, Informix, SunOS, Solaris,
+NIS, NFS, system-monitoring via paging. Unix System and Database
+administration or development. Coordinator of the GNU mascots: GNU Chess,
+GNU Shogi, GNU Go.
+
+Updated: 1998-07-23
+
+Noel Cragg <noel@cyclic.com>
+6244 Aberdeen Av
+Goleta CA 93117
+805-964-1892
+
+I'll do installation, debugging, and extension of GNU tools on a
+contract basis. CVS and configuration management are my current
+specialties. Rate: $75/hour or per-project negotiated fee.
+
+Updated: 1998-07-22
+
+Cygnus Solutions
+<info@cygnus.com>
+1325 Chesapeake Terrace
+Sunnyvale, CA 94089 USA
++1 408 542 9600 voice
++1 408 542 9699 fax
+
+Cygnus Solutions provides supported and maintained versions of gcc, g++, gdb
+with GUI, GNU linker and GNU macro assembler. In addition, Cygnus provides
+these GNU software development tools for well over 100 host-target
+configurations. Support includes bug fixes and semi-annual releases of the
+toolset. Each release is regression tested and includes substantial
+improvements and additions to the current release. Support is available for
+groups of 5 or 25 on a wide range of standard, special and vintage
+toolchains for native and embedded applications. New target processors are
+being added regularly. Rates for support for standard products start at $7495.
+
+Cygnus Solutions contacts:
+
+ Kathy Powers
+ ph: +1-206-888-6002
+ fx: +1-206-888-6145
+ email: <kpowers@cygnus.com>
+
+
+ Erik Westcott
+ ph: +1 408 542 9637
+ fx: +1 408 542 9699
+ email: <westcott@cygnus.com>
+Updated: 1997-09-02 by rms
+
+Marcus G. Daniels <marcusd@gnu.org>
+1399 Hyde Park Road <mgd@santafe.edu>
+Santa Fe, NM 87501 <marcus@tdb.com>
+(505)984-8800 x267
+
+I can customize, extend, port, and repair many types of free software.
+I have software maintenance experience (e.g. CLISP, Swarm), and have
+contributed to several GNU packages (e.g. Emacs). Twelve years of C
+and Unix experience. Consulting rates start at $60 US/hr.
+
+Updated: 1998-07-22
+
+DSS Distributed Systems Software, Inc.
+7500 Abercrombie Dr., Suite 103 <dss@dss.bc.ca>
+Richmond, British Columbia V6Y 3J9 http://www.dss.bc.ca
+CANADA (604) 270-9559
+
+GNU-related services:
+ We specialize in support for GCC (mainly C and C++), including porting,
+ retargeting, and customizing.
+ Also, GNU and other free software that falls within our areas of expertise.
+
+Expertise:
+ DSS provides software design, implementation, and consulting services.
+
+ Distributed systems:
+ o Client/Server architectures, computer networking, communication
+protocols
+ o Directory systems, including X.500 and LDAP
+ o High-performance and special-purpose distributed systems and databases:
+ scalability, reliability, availability, transactions
+ o Computer systems performance analysis
+
+ Compilers, translators, and interpreters, including "small" and
+ special-purpose languages
+
+Rates:
+ Consulting rates are $85-$300 (Canadian dollars) per hour, plus
+ applicable taxes. Fixed-cost projects are also possible.
+
+Updated: 1998-06-24
+
+Echo Labs <echo@iinet.net.au>
+29 Weld St, http://www.iinet.net.au/~echo/
+Nedlands, WA 6009
+Perth, Australia
++61 (0) 41 985 9603
+
+Echo Labs is a software consultancy that also provides support and
+development skills. Specialising in GNU software, particularly Tcl/Tk
+and Linux. We can deliver systems at a fraction of the cost of those
+based on more traditional technologies. Internet/intranet and data
+communications solutions, for all platforms are undertaken. GUI
+front-ends done quickly.
+
+While typically involved in engineering and technical areas, any
+GNU/Open Source software will be supported.
+
+For further details see: http://www.iinet.net.au/~echo/
+
+Experience: 13+ years C/Unix, Sun, SCO, Linux, Win/NT.
+ Secure WWW servers (Apache SSL), Ecommerce solutions.
+ Systems programming, device drivers, hardware interfacing.
+ GNU tools/utilities, Embedded & realtime systems.
+ Communications protocols and implementation.
+
+Degrees: BAppSc (CS), Curtin University, Perth
+
+Rates: AUS $50-75/hr neg.
+
+Updated: 1998-07-23
+
+Andrew Ford <A.Ford@ford-mason.co.uk>
+Ford & Mason Ltd. http://www.ford-mason.co.uk/aford/
+South Wing, Compton House Tel: +44 1531 829900
+Compton Green, Redmarley Fax: +44 1531 829901
+Gloucester, United Kingdom
+
+Experience:
+ * 18 years in the computer industry
+ * 14 years Unix/C programming experience
+ * 10 years experience with GNU software
+ * 4 years web experience (author of the first book about setting up a web site)
+
+Services offered:
+ * Installing and customizing GNU and other free software
+ * GNU Emacs customization and emacs lisp coding
+ * Perl module development
+ * TeX and LaTeX macro development
+ * software development (especially in Perl, C, C++)
+ * web site setup (with Apache)
+ * web application development with mod_perl
+ * translation (German -> English)
+ * writing documentation
+
+Rates:
+ around 60 pounds/hour (approx US$80/hour) plus expenses
+ less for charities and non-profit organization
+
+Updated: 1998-06-24

Free Software Association of Germany
Michaela Merz
@@ -249,33 +577,33 @@ organizations : 40 US$ / hour
ert (24h Emergency
response team) : 300 US$ / hour
-Entered: 14Apr94
+Entered: 1994-04-14

-Noah Friedman <friedman@prep.ai.mit.edu>
-Building 600, Suite 214 2002-A Guadalupe St. #214
-One Kendall Square Austin, TX 78705
-Cambridge, MA 02139 (Local, faster to reach me)
-(Permanent)
-
+Noah Friedman <friedman@splode.com>
+4463 Moraga Avenue
+Oakland, CA 94611
+(permanent)
-Author of several Emacs Lisp packages and parts of Emacs 19, as well as
-numerous utilities written in shell script and perl. Co-maintained GNU
-Texinfo and Autoconf for a couple of years. System administrator for a
-network of heterogenous machines. FSF employee Feb 1991--Sep 1994.
+Author of several Emacs Lisp packages and parts of Emacs, as well as
+numerous network and unix system utilities. Co-maintained GNU Texinfo and
+Autoconf for a couple of years. Experienced unix systems engineer.
+FSF employee Feb 1991--Sep 1994.
I can perform installation, porting, and enhancement of all GNU software
-and any other free software; system administration for unix-type systems
-and ethernet networks; and I am willing to teach shell programming and
-Emacs Lisp.
+and any other free software, especially for Linux/GNU systems; design
+high-capacity hardware-redundant servers for production environments;
+provide consulting on the use of version control management with CVS; and I
+am willing to provide handholding for shell programming and Emacs Lisp
+development.
-Fees negotiable, averaging $60-$75/hour. I can work in the Austin, TX area
-or anywhere accessible on the Internet. For larger jobs I may be willing
-to travel.
+Fees negotiable, averaging $100-$150/hour. I can work in the California
+bay area or anywhere accessible on the Internet. For larger jobs I may be
+willing to travel.
-Updated: 16Aug95
+Updated: 1998-06-24

Ronald F. Guilmette <rfg@monkeys.com>
-Infinite Monkeys & Co.
+RG Consulting
1751 East Roseville Pkwy. #1828
Roseville, CA 95661
Tel: +1 916 786 7945
@@ -315,243 +643,564 @@ Other qualifications:
Rates: Variable depending upon contract duration. Call for quote.
-Updated: 23Sep95
-
-Hundred Acre Consulting <info@pooh.com>
-1155 W Fourth St Ste 225
-PO Box 6209
-Reno NV 89513-6209
-(702)-348-7299
-Hundred Acre is a consulting group providing support and development
-services to organizations of all sizes. We support GNU C++ and C in
-particular, but also provide support for all other GNU software and
-certain non-GNU public domain software as well. We work on a "service
-contract" basis for support -- for a yearly fee, we provide multiple
-levels of email and toll free telephone support, and free updates and
-bug fixes. The highersupport levels have on-site support. Development
-is charged on either an hourly or fixed bid basis.
-
-Consulting rates: $70 to $90 per hour, or fixed bid.
-Support contracts: Several levels, from $495 to $90000 per year.
-
-Updated: 27Dec94
-
-Interactive Information Limited
-
-Interactive Information Limited is an Edinburgh-based company that
-specialises in WWW services and support for using the Internet for
-marketing.
-
-Our staff have many years experience in using, and developing lisp packages
-within, Emacs, and in using other GNU/Unix tools, particularly under public
-domain UNIXes.
-
-We can provide services throughout the UK, at any level from general
-consultancy through fetching, installing and customising software to
-bespoke programming. Fees would be in the range #300 - #600 per day,
-depending primarily on the size of the job.
-
-You can contact us
- by email: <enquire@interactive.co.uk>
- by phone: 0370 30 40 52 (UK)
- (+44) 370 30 40 52 (International)
- by post: 3, Lauriston Gardens,
- Edinburgh EH3 9HH
- Scotland
-
-Entered: 13Nov95
-
-Scott D. Kalter <sdk@mithril.com)
-2032 Corral Canyon
-Malibu, CA 90265-9503
-Home: (310) 456-0254
-
-Emacs: Eoops, Elisp, and C level customization/extension training for
- general use and customization user support, installation, and
- troubleshooting.
-
-Rates: $50/hr
- May answer brief and interesting questions for free.
- Prefer e-mail communication to telephone.
+Updated: 1998-07-10
+
+Kevin Harris <gordie@cyberramp.net>
+Dallas, Texas USA
+
+Entire GNU suite - porting, compilation, installation and maintenance
+Platforms: Any unix variant (AIX, *BSD, Digital Unix, HP/UX, GNU/Linux,
+Solaris, SunOS, et al)
+
+Method: Call-in via modem to your site, telnet, or on-site.
+
+Rates: US $0-75/hour depending upon client requirements
-Qualifications: BS Math/CS 1985: Carnegie Mellon University
- MS CS 1988: UCLA
+Note: If you are an individual installing GNU software on your personal Linux
+system, or are a non-profit organization, my hourly rate for you is simple:
+FREE. You just have to pay for the phone calls and/or travel/lodging, if any is
+required.
- Very familiar with all levels of elisp programming. Taught
- Emacs use and customization in universities and industry. Extensive
- troubleshooting and user support experience. Co-developed an
- object-oriented extension to Elisp that can be used for
- projects. Extensive Elisp level modification for rapid
- prototyping of designs used in groupware research. This
- includes the development of an infrastructure to support
- multiple, communicating Emacs processes.
+Experience: I've used, supported and maintained GNU software on numerous unix
+systems since 1989.
-Updated: 6Apr94
+I have extensive experience in C, Emacs Lisp, Perl and general unix systems.
+
+Updated: 1998-06-24

-KAMAN SCIENCES CORPORATION
-258 GENESEE STREET
-UTICA NY 13502
-(315) 734-3600
+Michael P. Deignan
+Ideamation, Inc.
+136 Nelson Street
+Providence, RI 02908
+(401) 331-3708
+(401) 272-6449 fax.
-CONTACTS: Alan Piszcz (peesh) <apiszcz@utica1.kaman.com>
- : Dennis Fitzgerald <dennis@utica.kaman.com>
+Rate: Varies depending on complexity of task.
+ Hourly and fixed-rate contracts are available.
+Programs Supported: All
+Updated: 1998-07-23
+
+ Interactive Information Limited is an Edinburgh-based company that
+ specialises in WWW services and in particular support for accessing
+ existing systems and information.
+
+ Our staff have many years experience in using, and developing lisp packages
+ within, Emacs, and in using other GNU/Unix tools, particularly under public
+ domain UNIXes.
+
+ We can provide services throughout the UK, at any level from general
+ consultancy through fetching, installing and customising software to
+ bespoke programming. Fees would be in the range #300 - #600 per day,
+ depending primarily on the size of the job.
+
+ You can contact us
+ by email: <enquire@interactive.co.uk>
+ by phone: 0370 30 40 52 (UK)
+ (+44) 370 30 40 52 (International)
+ by post: 3, Lauriston Gardens,
+ Edinburgh EH3 9HH
+ Scotland
+
+Updated: 1998-07-24
+
+Kaman Sciences Corporation
+Griffiss Business & Technology Park
+775 Daedalian Drive
+Rome, NY 13441-4909
+(315) 334-4900
+
+CONTACTS:
+ Dennis Fitzgerald <dfitzgerald@rome.kaman.com>
+ Tom Robbins <trobbins@rome.kaman.com>
+
Kaman Sciences has performed a GNU port for a custom RISC processor.
We have experience in the definition and description of the machine
register transfer language to the GNU tool-set. This includes rewriting
and modification of the necessary description and source files of gcc, gas,
and gld and other binutils. Kaman also has services for installation and
setup of GNU tools, (GAWK, GCC, EMACS, etc.) on Sun workstations.
-
+
Work is on a "service contract" basis and development is charged either
hourly or as a fixed price contract.
-
-Consulting rates: $70 to $200 per hour.
-
-Entered: 13Jan95
+
+Consulting rates: $70 to $175 per hour.
+
+Updated: 1997-05-07

-Scott J. Kramer <sjk@aura.nbn.com>
-P.O. Box 620207
-Woodside, CA 94062
-+1 415-941-0755
+Joseph R. Kiniry <kiniry@cs.caltech.edu>
+Caltech Mailstop 256-80 http://www.cs.caltech.edu/~kiniry/
+Pasadena, CA 91125 <jrk@metagenesis.com>
+Phone: 626-395-4840
+Fax: 626-792-4257
+
+Long-term high-level consultant with four advanced degrees in a
+variety of domains. See http://www.cs.caltech.edu/~kiniry/resume.html
+for more information on professional and academic background.
+
+I provide installation, porting, debugging, customization, design, and
+development of GNU and other UNIX and non-UNIX software. I am or have
+been a certified developer with Microsoft, SunSoft, NeXT, and Amiga.
+I have a great deal of development and management experience and an
+extremely broad background which contributes to my excellent system
+integration capabilities. I have a special expertise and conduct
+research in distributed systems and component/object technologies.
+
+Time and material rates for local work vary regionally, but are
+currently $250 per hour on the west coast. Other rates apply for
+long-term jobs (day rates, travel, etc.) and remote work (usually 1/2
+fee). I am interested in fixed-bid jobs and will work for lower rates
+for non-profit organizations and educational institutions.
+
+Updated: 1998-08-27
+
+Bradley M. Kuhn
+<bkuhn@ebb.org>
+http://www.ebb.org/bkuhn
-GNU Software: Tutoring, installations/upgrades, Emacs Lisp customizations,
- general troubleshooting/support. Prefer that work I do
- becomes part integrated into official Free Software Foundation
- distributions.
+I am available for Unix system administration and software development
+consulting, including but not limited to installation, configuration and
+integration of GNU tools and other copy-lefted software such as GNU/Linux
+and the various distributions of GNU/Linux.
-Systems Administration: Sun (SunOS & Solaris) and SGI (IRIX)
- UNIX hardware/software platforms.
+Please visit my homepage for more information on my background and skills. My
+resume is also available there.
-Rate: Task- and time-dependent; non-monetary offers accepted.
+I am available for both 1099 (preferred) and W2 on-site contracting in the
+Cincinnati, OH, USA metropolitan area, as well as remote consulting via dialup
+or Internet connection anywhere in the USA. I have no interest in permanent
+relocation at this time.
-Updated: 12Apr94
-
-Fen Labalme <fen@comedia.com)
-Broadcatch Technologies
-40 Carl St. #4 WE ARE EVERYWHERE
-San Francisco CA 94117 JUST SAY "KNOW"
-(415) 731-1174 ARE YOU KIND?
+My rate varies greatly between $25-$40/hour, depending on the circumstances.
+Rates for non-profit organizations are substantially lower, and possibly free.
-Rates: $80 hour (negotiable); quick email or phone questions free.
- Lower rates -- free of barter -- for schools and non-profits.
+Updated: 1998-09-12
+
+Fen Labalme <fen@comedia.com>
+CoMedia Consulting http://www.comedia.com/
+142 S. Lake Merced Hill WE ARE EVERYWHERE
+San Francisco CA 94132 JUST SAY "KNOW"
Consulting, installation, customization and training for GNU Emacs,
-and selected other GNU & network software (but not G++). I have been
-hacking Emacs since '76 when it was TECO and ^R macros (don't ask).
+and selected other GNU & network software. Design & implementation
+of free software projects, as well as software engineering & system
+design. I have been hacking Emacs since '76 when it was TECO and ^R
+macros (don't ask), and am inter/intra-network, UNIX & Web friendly.
+
+Rates: $150 hour & up, depending; flat rate jobs considered.
+ Lower rates, barter or free for selected non-profits.
-Updated: 6Apr94
+Updated: 1998-06-24

Greg Lehey
LEMIS
-Schellnhausen 2
-36325 Feldatal
-Germany
+PO Box 460
+Echunga SA 5153
+Australia
-Phone: +49-6637-919123
-Fax: +49-6637-919122
-Mail <grog@lemis.de>
+Phone: +61-8-8388-8250
+Fax: +61-8-8388-8250
+Mobile: +61-41-739-7062
+Mail <grog@lemis.com>
Services: Supply, porting, installation, consultation on all GNU
products.
-Experience: 20 years OS and compiler experience, portations of most
-GNU products. Author of ported software CD-ROM for Unix 4.2.
+Experience: 25 years OS and compiler experience, ports of most GNU
+products. Author of ported software CD-ROM for UNIX System V.4.2,
+"Porting UNIX Software" (O'Reilly), "Installing and Running FreeBSD"
+and "The Complete FreeBSD" (both Walnut Creek).
+
+Rates: Choice of AUD 180 per hour or hotline rates AUD 3 per minute.
+Outside Australia, $US 100 per hour or $US 2 per minute. Quick
+questions may be free. Limited free support available for
+purchasers of LEMIS CD-ROMs.
+
+Updated: 1998-08-26
+
+Alan Lehotsky <qsmgmt@tiac.net>
+Quality Software Management
+634 West St
+Carlisle, MA 01741
+
+Phone: (978)287-0435
+Fax: (978)287-0436
+
+Services:
+ - Support for GNU compilers, including rehost/retarget
+ - General system software work (SW tools, O/S, device drivers)
+ - runtime library (especially floating point)
+ - project management
+ - software process improvement
+
+Experience: 15+ years of design and implementation of optimizing
+ compilers. "Mr. Bliss" at Digital in the 70's and early
+ 80's. Experience with Motorola 68k, PowerPC, SPARC, x86,
+ NS32K, ADI SHARC DSP. Compilers for languages including
+ Ada, BLISS, C, C++, FORTRAN, Pascal, Modula/2, O/S
+ experience includes Unix (OSF/1, SunOS, Solaris, AIX, HP/UX),
+ VAX/VMS, Windows/NT, MacOS.
+
+ 4 years experience with GCC internals, including major
+ changes to support 8 bit bytes on word-address SHARC DSP.
+
+References available
-Rates: Choice of DM 150 per hour or hotline rates 3 DM per minute + 10
-DM per phone call. Quick questions may be free. Limited free support
-available for purchasers of LEMIS CD-ROMs.
+Rates: $100/hr
+ fixed price possible for well-defined deliverables
-Updated: 21Feb95
+Updated: 1998-06-24

-Marty Leisner <leisner@sdsp.mc.xerox.com>
-332 Shaftsbury Road
-Rochester, New York 14610
-Home:(716) 654-7931
+Rohan Lenard <rjl@wr.com.au>
+32 Holtermann St.
+Crows Nest, NSW 2065
+AUSTRALIA
++61 411250024
-Experience: 12 years C/Unix, 7 years DOS.
- Extensive experience with GNU binary tools, cross-compilers,
- embedded/hosted systems, realtime.
-Degree : BS CS, Cornell University
-Rates: $75/hr
+* The human face behind the bug-g++@gnu.org mailing list - known
+ in the past as <rjl@iassf.easams.com.au> and <rjl@ot.com.au> - now
+ known as <rjl@wr.com.au>.
+* Interested in providing first line support and development.
+Experience: 10+ years C/Unix, 6+ years C++
+ Extensive experience with GNU tools, cross-compilers,
+ embedded/hosted systems, realtime, simulations,
+ and military software.
-marty
-<leisner@sdsp.mc.xerox.com> <leisner@eso.mc.xerox.com>
+Degrees: BSc (CS), BE (Comms), University of Melbourne
-Updated: 15Apr94
+Rates: AUS $75+/hr neg.
+
+Updated: 1997-05-17
+
+Reuven M. Lerner <reuven@netvision.net.il>
+17 Disraeli Street
+Haifa 34333
+Israel
+
+Phone: 04-824-2265 (within Israel)
+ +972-4-824-2265 (outside of Israel)
+
+Fax: 04-826-1219 (within Israel)
+ +972-4-826-1219 (outside of Israel)
+
+WWW: http://www.netvision.net.il/php/reuven
+
+- System and network administration, especially Linux-based systems
+ and networks
+- Administration, training, and programming for Internet nodes and
+ World-Wide Web sites
+- Installation, support and training in the use of Linux, Emacs, Perl,
+ and other free software
+- Expertise in C, Emacs Lisp, and Perl
+
+Consulting rates: $75/hour, less for educational institutions.
+
+Updated: 1998-06-24

Richard Levitte (in TeX: Richard Levitte
-Södra Långgatan 39, II S\"odra L{\aa}nggatan 39, II
-S-171 49 Solna S-171 49 Solna
+Levitte Programming Levitte Programming
+Spannvagen 38, I Spannv\"agen 28, I
+S-168 35 Bromma S-168 35 Bromma
Sweden Sweden)
-Tel.nr.: +46 (8) 18 30 99 (there is an answering machine)
-e-mail: <levitte@e.kth.se> (preferred)
- <levitte@vms.stacken.kth.se>
+Tel.nr.: +46 (8) 26 52 47 (there is an answering machine)
+Cellular: +46 (10) 222 64 05
+e-mail: <levitte@lp.se>
What I do:
- Primarly I work on GNU software for VMS, both VAX and AXP. I
- also work on GNU stuff for Unix on occasion. I'm familiar with
- SunOS (version 4.x.x), BSD (version 4.2 and up),
- Ultrix (version 4.2 and up).
- I've been porting GNU Emacs to VMS since spring 1991. This
- includes versions 18.57 to 18.59 and version 19.22.
- I maintain GNU vmslib.
+ Primarily I work on GNU software for VMS, both VAX and AXP. I've
+ been porting GNU Emacs to VMS since spring 1991. I've ported a
+ bunch of other GNU programs as well. I maintain GNU vmslib.
+ For further info, see http://www.lp.se/~levitte/prof/resume.html
Programs supported:
- GNU vmslib: extending, installation, upgrading aid,
- simple and complex questions, you name it.
- GNU Emacs: porting, extending, installation, upgrading aid,
- customization, simple or complex questions,
- training, you name it.
- GNU autoconf: porting, extending, installation, upgrading aid.
- GNU zip, diffutils, m4, patch, texinfo:
- porting, installation, upgrading aid.
- GNU C/C++: installation, upgrading aid. I might start to
- hack at it some day.
-
-The list of programs I currently support represents both my interests and
-current priorities. Your interest and funding can influence my priorities.
+ To a varying degree (ranging from extension and porting to
+ installation and simple questions) at the time of updating this
+ entry:
+ - GNU vmslib, emacs, autoconf, zip, diffutils, m4, patch, texinfo,
+ C/C++; on both VMS and Unix.
+ - Other GNU programs to a small degree; on Unix.
+ For further info, look at http://www.lp.se/products/gnu.html
Experience:
- Fluent in C, C++, Emacs Lisp, Pascal as well as assembler
- on VAX, Motorola 680x0, Intel 8086 and 80x86. Modified key
- elements in Emacs (e.g., memory and process management) to work
- transparently on VMS. I have very good knowledge in the VMS
- operating system, as well as MS-DOS and IBM PC compatibles.
- I have worked for four and a half years as a VMS system manager.
- I've also provided consulting services on IBM PC compatibles,
- as well as held classes for IBM PC users.
- A reference list is available on request.
+ Fluent in TeX/LaTeX and many programming languages.
+ Modified key elements in Emacs (e.g., memory and process management)
+ to work transparently on VMS. I have very good knowledge in the VMS
+ operating system. I'm also knowledged in the a few Unix flavors.
+ For further info, see http://www.lp.se/~levitte/prof/resume.html
Your Rate:
- $50-$80/hour (400-700 SEK in sweden), plus expenses. My rates
+ $70-$100/hour (500-800 SEK in sweden), plus expenses. My rates
are negotiable, depending on how interesting the project is to me.
+Updated: 1997-05-08
+
+Sean Levy <attila@StAlphonsos.COM>
+352 Roup Ave http://www.StAlphonsos.COM/~attila/
+Pittsburgh, PA 15232 +1.412.361.7802
+USA
+
+I have been a professional hacker for over 15 years, and have worked on
+everything from PDP-10's and -11's and early microcomputers to modern Unix
+workstations of various kinds, at all levels. I've done every kind of
+hacking, in many different languages (including some I designed and
+implemented). Current efforts are focused on Linux, GNU software, WWW-based
+systems, and security. My resume and PGP key are available via my web
+pages.
+
+Based in Pittsburgh, PA, available anywhere via the Internet. Possibility
+of travel for some jobs. Speak Spanish, have traveled in Europe and
+Scandinavia.
+
+Rates: $100 USD/hour standard, lower for non-profits or other worthy causes,
+ $200 USD/hour for pager access and 24-hour support
+
+Updated: 1998-06-24
+
+Lexa Software info@lexa.com
+1590 The Alameda, Suite 102
+San Jose, CA 95126
+
++1 800 278-2040
++1 408 278-2043 voice
++1 408 278-2045 fax
-Entered: 18Aug94
+http://www.lexa.com
+
+Lexa Software provides support for GNU C/C++ including the GNU debugger
+and linker. Lexa has extensive experience supporting GCC/G++ on SNI
+and Pyramid as well as all other MIPS ABI platforms. We offer support
+to 2, 5, 25 and larger number of users via phone, email, ftp.
+
+Updated: 1997-05-01

-Roland McGrath <roland@frob.com>
-545 Tech Sq, Rm 426
-Cambridge, MA 02139
-Work: (617) 253-8568
+Gord Matzigkeit <gord@gnu.org>
+#15, 2105 Cornwall Street http://www.fig.org/~gord/
+Regina, Saskatchewan S4P 2K8 Voice: (306) 522-7884
+CANADA
-Co-author of GNU Make (with Richard Stallman); maintainer of GNU Make.
-Author and maintainer of the GNU C Library and co-author of the GNU Hurd.
-Author of several GNU Emacs Lisp packages and parts of GNU Emacs 19.
-FSF employee summer 1989, fall 1990 to the present.
+I will gladly help novice and intermediate computer users to install,
+understand, and use free software, whether or not I have prior
+experience with that software. I know my limitations well, and will
+freely give other contacts if I cannot solve your problem myself.
-Installation, maintenance, porting, enhancement of all GNU software. I can
-install GNU software and maintain its installation on call via the Internet.
+I have over 3 years of experience with several of the major free OSes:
+Linux/GNU (Red Hat, Debian, Slackware), NetBSD, FreeBSD, and GNU/Hurd.
+Some of my specialties are networking, Emacs, Automake, Autoconf, C,
+Perl, and shell script programming.
-Fees negotiable; $75-$100/hour, higher for very short term projects. I can
-work anywhere in the Boston or SF Bay Area, or anywhere on the Internet. I
-am working full-time for the FSF on the GNU Hurd, so I am likely to take on
-only jobs that either can be done entirely via the Internet and are
-short-term, or that are very interesting.
+My rates are negotiable depending on the task: usually $10-$40
+(Canadian) per hour.
-Updated: 21Jan95
+Updated: 1998-10-19
+
+Andrew McCallum
+6623 Dalzell Place
+Pittsburgh, PA 15217
+Home: (412) 422-0688
+<mccallum@cs.cmu.edu>
+http://www.cs.rochester.edu/u/mccallum
+
+Services: Support, enhancements, new development in:
+ GNU Objective C
+ GNUstep, both graphical and non-graphical.
+ GNUstep Base Library: libgnustep-base
+ (especially Distributed Objects)
+ Interface between Objective-C and Guile or TCL: libguileobjc.
+
+Experience: 10+ years of UNIX experience.
+ Programming for NeXTSTEP since version 0.8, 1988.
+ MA and PhD in Computer Science.
+ Extensive work on GNU Objective C Runtime.
+ Author of GNUstep Base Library, including Distributed Objects
+ FSF Chief Maintainer of the GNUstep Project.
+ Contributor to GCC, Emacs, Guile.
+ C, Objective-C, Postscript, Scheme, Lisp, ELisp, Linux.
+ English and Francais.
+
+Rates: $90-$150 / hour, negotiable, depending on many variables.
+
+Updated: 1997-05-07
+
+Mark P. Mitchell <mmitchell@usa.net>
+3421 El Camino Real #35
+Atherton, CA 94027
+(650) 364-5360
+http://home.earthlink.net/~mbmitchell/consulting.html
+
+Experience
+----------
+I am an experienced software engineer, with particular expertise in
+the field of programming tools. I am responsible for the
+implementation of member templates in currently available versions of
+G++ as well as many other G++ bug-fixes, and continue to work actively on
+improving G++.
+
+I am willing to work on any and all projects involving free software.
+
+Please see my resume at the above URL for further information on
+my experience and qualifications.
+
+Rates
+-----
+My standard rate is $125/hr, but I am willing to negotiate flat fees, and
+discounts for deserving organizations.
+
+Updated: 1998-02-13
+
+NET-Community <scottc@net-community.com>
+526 NW 21st, #48 http://www.net-community.com
+Portland, OR 97209 USA
+1-503-279-8845 voice
+
+NET-Community provides support for the complete GNUstep toolset
+including the Objective-C runtime within GCC, the GNUstep Base Library,
+the Display Ghostscript system, the GNUstep GUI Library, the GNUstep
+X/DPS GUI Backend, and the GNUstep Database Library. NET-Community also
+provides support for its own MediaBook software including the MediaBook
+Random Library and the MediaBook Speech Synthesis Library.
+NET-Community actively supports and develops free software on all
+GNUstep platforms; a portion of the proceeds, usually 20%, generated
+from CD-ROM sales go towards additional development and enhancement of
+GNUstep.
+
+Updated: 1998-09-08
+
+Thi Nguyen <ttn@netcom.com>
+San Jose, CA, USA +1 408 314 3470
+
+Expertise: Hardware Verification Tools and Environment
+ - simulators / transactors / stimulus generators
+ - scripts of all sorts / environment / flows
+ - elisp customizations
+ - speak: C, C++, elisp, Scheme, Perl, Verilog, sh
+
+Please see ftp://ftp.netcom.com/pub/tt/ttn/resume.html for resume.
+
+Rate: $100/hr, possibly less
+
+Updated: 1998-06-24
+
+Peter Olsen
+P.O. Box 410
+Simpsonville, MD 21150
+
+pcolsen@acm.org
+
+What I do: Mathematical modeling and model building using Gnu
+ and other Free Software. Scientific and engineering
+ analysis, modeling, and programming in FORTRAN, C, LISP,
+ Java, and Smalltalk. Statistical analysis.
+ Emacs customization.
+
+Examples of my previous work:
+ 1. I built the model used predict the
+ amount of work required to clean up the Exxon Valdez oil
+ spill. Model was completed in ten days, used to allocate
+ resources for $2 billion summer cleanup, predictions were
+ accurate.
+ 2. I built a model applying commercial capital
+ investment standards to a Federal Agency budget, helped
+ support $250 Million budget increase.
+
+Credo: Engineering is the art of applying a professional
+ knowledge of mathematics and the physical sciences to
+ improve the quality of life.
+
+Rates: $225/hour (+ travel and expenses) on site,
+ $175/hour remote access.
+
+Notes: 1. Visiting Lecturer for Society for Industrial and Applied
+ Mathematics: Will speak without fee about Valdez model
+ (or other work) to Educational and not-for-profit
+ organizations (plus most-economical travel and living
+ expenses or travel or living arrangements in kind).
+
+ 2. I do not accept offers which pose even the appearance
+ of conflict of interest with any present or former client
+ or employer.
+
+Updated: 1998-06-24
+
+ Open Systems Consultants a.s Open Systems Consultants a.s
+ St. Olavsgt. 24 Fabrikkvn 8
+ N-0166 OSLO N-4033 FORUS
+ NORWAY NORWAY
+
+
+Phone: Fax:
+ +47 22 20 40 50 +47 22 20 02 85
+
+Web: E-mail:
+ http://www.osc.no <gnu-support@osc.no>
+
+Open Systems Consultants a.s can provide programming support for all
+GNU software -- extending or adopting it to meet customer needs.
+Prices vary with software and project. Hourly fees are in the $80-120
+range. Fixed-priced projects are also available. Phone support is
+available only for customers with support contracts.
+
+Updated: 1998-08-26
+
+Francesco Potorti` <F.Potorti@cnuce.cnr.it>
+Via S.Stefano, 8
+56123 Pisa, Italy
+Tel. (050)560671
+
+Emacs: installation and maintenance, training and tutorials,
+ customisation, extensions, troubleshooting. Author of some of
+ the packages in the emacs distribution, has made the porting
+ of emacs to the Motorola Delta architecture.
+
+Other: installation and maintenance of GNU software. Experience with
+ hylafax, RCS, gperf, etags, smail, indent, diff, gawk, gcc,
+ screen. Is the current maintainer of etags.
+
+Rates: 30-80 KL/hr, depending on experience on the particular task.
+ Average is 50 KL/hr $50/hr.
+ Prefer e-mail communication to telephone.
+
+Qualifications: Electronic Engineering degree, Pisa. Full time
+ researcher in CNUCE-CNR.
+ Familiar with elisp programming and porting of C programs.
+
+Updated: 1998-08-26
+
+Dipl.-Inform. Klaus K?mpf <kkaempf@rmi.de>
+L?hnerstrasse 14
+D-90491 N?rnberg
+Germany
+
+- 15 years C/Unix experience
+- 6 years VMS experience
+- Ported BFD library, Binutils, GNU Assembler, GNU C, GNU C++,
+ GNU C++ libraries, and GNU Make to openVMS/Alpha.
+
+I do a lot of cross-platform (Unix/Linux-OpenVMS-WindowsNT) development
+mostly with the GNU compiler environment. I am actively supporting GNU
+software on OpenVMS/Alpha and OpenVMS/VAX.
+
+Updated: 1998-08-26
+
+Quiotix Corporation
+Menlo Park, CA
+
+Contact: Jeffrey Siegal
+ jbs@quiotix.com
+ 415 324-0535
+
+Area of focus: Embedded systems--using GNU software to develop for
+embedded systems, porting GNU software to embedded systems, extending GNU
+software to better support embedded environments, developing new tools and
+utilities for embedded development using GNU software.
+
+Services: porting, development, support, project management, advisory
+consulting.
+
+Rates: $125-$250/hour or fixed fees depending on services provided.
+
+Updated: 1997-05-16

Wolfgang S. Rupprecht <wolfgang@wsrcc.com>
47 Esparito Ave.
@@ -564,86 +1213,137 @@ author of the floating point additions in Emacs 19.
Rates: $95/hr.
-Updated: 14Apr94
+Updated: 1997-05-08
+
+Stanislav Shalunov
+
+Email: shalunov@mccme.ru
+Phones: on request
+
+Installing, configuring, helping learn any free software.
+Handholding, trouble shooting. Making custom changes to free
+software written in C. Teaching, lecturing, consulting.
+
+Want to have a free OS with free software serving your needs but do
+not want to spend time yourself or not very skilled with the
+computers? Cannot decide which free software suits your needs
+better? Drop me a line.
+
+Well, essentially, anything else on special request. :-)
+
+Rate: $30/hour if you are in Moscow and I am there when you request
+job done, $50 if the job may be done remotely (like configuring user
+level program), $60/hour + travel expenses otherwise. (Negotiable,
+significant discounts may apply.)
+
+Entered 1997-07-17
+
+Vin Shelton
+EtherSoft, Inc
+781.488.5135
+<acs@alumni.princeton.edu>
+
+I have been a professional programmer for 20 years, with most of that time
+spent doing UNIX/C/C++ hacking. My specialties are (in no particular
+order): system/kernel hacking, speech recognition, perl, object-oriented
+design and analysis, FSF software (I have built nearly every FSF package on
+several different platforms), small language design and implementation, and
+HTML/web programming. Currently I'm a member of the XEmacs and egcs beta
+teams. My rates vary from $60 - $100 per hour, depending on the size of the
+project.
+
+Updated: 1998-06-24

Signum Support AB <info@signum.se>
-Box 2044 _ ...!seunet!signum!info
-S-580 02 Linkoping, Sweden
+Teknikringen 8
+S-583 30 Linkoping, Sweden
+46 13 21 46 00 voice
+46 13 21 47 00 fax
+http://www.signum.se/
-Signum Support AB is a company dedicated to supporting, developing
-and distributing free software for, including but not limited to,
-UNIX systems. The people behind Signum Support AB have many years
-of general UNIX experience, both as system administrators and as
-programmers, and also extensive experience in maintaining the GNU
-programs, both administrating it and finding and fixing bugs.
+Signum Support AB is a company dedicated to supporting, developing and
+distributing free software for mainly UNIX systems. The people behind
+Signum Support AB have many years of general UNIX and Internet
+experience, both as system administrators and as programmers, and also
+extensive experience in maintaining and administering the GNU programs
+and Linux.
+
+Signum Support develops and markets the free GUI equipped Readynet
+Internet server, the free PHTTPD http server and the easy to use Linux
+based Fuego firewall.
Services offered:
- - Installation and customizing GNU and other free software. We will
- make free software as easy to install and use as shrink wrapped
+ - Support on Internet service software, especially the free
+ Readynet Internet server we have developed for Linux.
+ - Support on Linux.
+ - Customization of Linux.
+ - Installation and customizing GNU and other free software. We are
+ making free software as easy to install and use as shrink wrapped
programs.
- Warranty protection.
- - Customization and porting.
- - Subscriptions to new versions which we will send monthly or with
- any other interval.
- Finding, Recommending and Investigation of free software in any
- area of the customers choise.
+ area of the customer's choice.
- Regular consulting.
Rates: For software items, request our price list.
- For consulting, 400-800 SEK/hour.
+ For consulting, 700-900 SEK/hour.
-Updated: 14Apr94
+Updated: 1997-05-12

-Small Business Systems, Inc. <postmaster@anomaly.sbs.com>
-Box 17220, Route 104
-Esmond, RI 02917
-401.273.4669
-
-Rate: Varies depending on complexity of task.
- Hourly and fixed-rate contracts are available.
-Programs Supported: All
-
-Updated: 14Apr94
-
-Julian H. Stacey. <stacey@freefall.cdrom.com>
-Vector Systems Ltd, Holz Strasse 27d, D 80469 Munich (Muenchen), GERMANY.
-Tel. +49 89 268616 (089 268616 in Germany) 09:00-21:00 Timezone=GMT+01:00
-
-Sources: All FSF/GNU, FreeBSD-current, X-Windows, XFree86, NetBSD, Mach, etc.
- (Plus various other things, such as, but not limited to:
- blas blt cflow CAD cnews crypt dvi2lj eispack elm encryption expect
- ezd f2c flexfax gic gopher info-zip ingres inn jpeg kermit ksh
- less lha linpack md5 mh mprof mtools mush nntp octave pbmplus
- popper sather sc schemetoc slurp sml spreadsheet sup tcl tcl-dp
- tcsh tcx term tex tiff tk top trn unarj ups urt wine xlock xv
- xview xxgdb zmodem zip zircon zoo zsh.)
-Media: QIC 1/4" Cartridge 525M, 150M, & 60M, TEAC CAS-60 60M Cassette,
- CD-ROM, Floppies 1.4M & 1.2 & 720K & 360K. DAT arrangeable.
- Postal Service C.O.D.(=`Nachnahme') or pre payment available.
-Commercial Consultancy:
- Custom Designs, Provision & support of FreeBSD or Unix, C, FSF tools,
- X Windows, own tools, systems engineering, hardware interfacing,
- multi lingual European, Cyrillic & Chinese tools & systems,
- Unix, MSDOS, real time etc, communications & scientific & industrial.
-DEUTSCH + FRANCAIS:
- Man kann mir in Deutsch schreiben, (oder mich anrufen).
- Je comprend Francais, mais je n'ecris pas des responses en Francais.
- (Contact me in English, German, or French).
-FREE for Symmetric Computer Systems Model 375 owners:
- Free Binaries & sources on SCS/375's TEAC 50/60M Cassette, for:
- GCC-1.40, UUCP-1.4, Ghostscript 2.3, Tar-1.08, Gzip-1.2.2 etc.
- (Native SCS compiler can't compile GCC on this NSC32016 based BSD4.2)
-On Request: Resume, Company Profile, Index of public & proprietary tools,
-Rate: ~120 DM/hour. ~100DM/Cartridge. (1.5DM = $1 USA = 0.6 UK Pounds @4/'94)
-Short enquiries free. (Kurze Anfragen Ohne Gebuhr).
-
-Updated: 14Jun94
-
-Richard M. Stallman <rms@prep.ai.mit.edu>
-UUCP: {mit-eddie,ucbvax,uunet,harvard,uw-beaver}!ai.mit.edu!rms
+ Jon Solomon <jsol@gnu.org>
+ 235 Main St., Apt 3C-1
+ East Hartford, Conn. 06118
+ +1 860 895-8289
+
+ Maintains all GNU software... Available for General Consulting
+ (contact me if you are interested)...
+ Sendmail a specialty... Can answer questions pertaining to the
+ installation, maintenance, bug reporting and fixing for
+ most GNU products... Adhering to the FSF/GNU copyleft for all
+ work... (I only charge for the time it takes to do the above,
+ the software (and most GNU copyleft'd software) is free.
+ I can make tapes for you if you need that...
+
+Updated: 1997-05-09
+
+Name: Julian Stacey <jhs@freebsd.org>
+Location: Munich Germany, & on the Internet.
+Qualifications: University Degree, BSc Hons Computer & Cybernetics, 1980.
+Phone: +49.89.268616 Fax: +49.89.260812 Data: +49.89.26023276
+Resume: http://www.freebsd.org/~jhs/
+Time Zone: +01:00
+Rate: 130-170 DM/Hour. 2.7846 DM = 1 Pound = US $1.6332
+Commercial Independent Freelance Consultancy:
+ Any Unix (inc FreeBSD, Linux etc), C, X-Windows, FSF Tools,
+ Internet, Systems engineering, hardware interfacing,
+ real time, comms & scientific industrial, even Cyrillic &
+ Chinese interfaces etc. No Emacs. No Cobol.
+Free Sources: FSF, FreeBSD & NetBSD CVS & current (daily!) & releases,
+ X-Windows, XFree86, Free dial in soon (details on web).
+ Media Copy Charge ~DM 100 QIC 1/4" 525M, 150M, & 60M; & CAS-60M.
+Free GCC-1.40 For Symmetric Computer Systems Model 375 (native cc is broken).
+Languages: Deutsch & Francais
+ Man kann mir in Deutsch schreiben, (oder mich anrufen).
+ Je comprend Francais, mais je n'ecris pas des responses en Fr.
+! NO FREE HELP !
+ - The Free Software Foundation do not pay me.
+ - I earn my living from professional consultancy fees.
+ - Though I write code for public domain ...
+ - I will Not solve stranger's complex problems for free !
+WHEN CONTACTING ME, DO THIS :-
+ 1) Tell me Immediately, Are You:
+ A) Expecting to pay my bill for professional consultancy.
+ B) Seeking a few minutes advice free of charge.
+ 2) Give me your email address, or that of a friend.
+ or Volunteer to phone back ~ 5 days later to collect follow-up
+ info. from the net. (No I will not incur bills phoning you back).
+ 3) Speak English if you want free advice ! I speak German, &
+ listen in French, but if you're not paying, make some effort too !
+
+Updated: 1997-05-15
+
+Richard M. Stallman <rms@gnu.org>
545 Tech Sq, Rm 430
Cambridge, MA 02139
@@ -654,104 +1354,141 @@ Original inventor of Emacs and main author of GNU Emacs and GCC.
Rates: $6/min or $250/hr.
-Updated: 14Apr94
+Updated: 1997-05-09

-JoS-Ware Comp Tech Johan Svensson <support@spird.jos.ec.lu.se>
-Box 739
-220 07 LUND
-SWEDEN
-Tel +46-46-104505 (Dept. of Economics, University of LUND)
-Fax +46-46-188445 (JoS-Ware Comp Tech)
-
-What: We offer consulting services regarding installation,
- customization, troubleshooting, porting and integration
- of all free software, including GNU software.
-
-Spec.: Network integration, integration of public domain software
- into commercial systems, WorldWideWeb, C, X-Windows, Linux,
- networked information systems
-
-How: Remote login over internet, email, modem, phone, personal
- visits (in southern Sweden mainly)
-
-Rates: 550SEK (+ tax) per hour within Sweden
- 370SEK (+ tax) per hour within Sweden for educational org.
- US $90 per hour outside Sweden
- US $70 per hour outside Sweden for educational org.
- Note: fees may vary and special arrangements may be considered
-
-Entered: 7Apr94
-
-Kayvan Sylvan <kayvan@satyr.Sylvan.COM>
+Kayvan Sylvan <kayvan@sylvan.com>
Sylvan Associates
879 Lewiston Drive
-San Jose, CA 95136
-Phone: 408-978-1407
+San Jose, CA 95136-1517
+Phone: (408) 978-1407
+Fax: (408) 978-1417
I will help you port, install and customize GNU Emacs, GCC, G++,
-bison, and other GNU tools on almost any architechture and operating
+bison, and other GNU tools on almost any architecture and operating
system. Questions answered. GNU C and lisp hacking available. I will
also do ongoing support and periodic upgrades if you get on my GNU
software subscription list.
-Rates: $60-$100/hour, depending on type of work. Substantial discounts
+Rates: $70-$100/hour, depending on type of work. Substantial discounts
for long-term contracts and also for educational or non-profit
institutions.
-Experience: Many different Unix systems (2.9BSD to 4.4BSD, SVR3 and
-SVR4, Linux, Xenix). Systems programming and system administration on all
+Experience: Many different Unix systems (2.9BSD to 4.4BSD, Xenix, SVR3 and
+SVR4, Linux, FreeBSD). Systems programming and system administration on all
brands of Unix. Kernel hacking experience. Lots of porting experience.
-I can port anything to anything (within reason).
-Updated: 14Apr94
+Updated: 1997-05-09

-Leonard H. Tower Jr. <tower@prep.ai.mit.edu>
+TerraTel AB <info@netg.se>
+Tankeg=E5ngen 4
+S-417 56 G=F6teborg, Sweden
++46 31 50 79 40 voice
++46 31 50 79 39 fax
+http://www.netg.se
+
+TerraTel AB is a company that does consultant jobs and holds courses
+in the fields of Unix software, TCP/IP networking and Internet
+applications. The people behind TerraTel AB have many years
+of general UNIX experience, both as system administrators and as
+programmers, and also extensive experience in maintaining the GNU
+programs; in administration as well as finding and fixing bugs.
+
+Services offered:
+
+- Installation and customizing GNU and other free software. We will
+ make free software as easy to install and use as shrink wrapped
+ programs.
+- Service and support subscriptions.
+- Warranty protection.
+- Customization and porting.
+- Subscriptions to new versions which we will send monthly or with
+ any other interval.
+- Finding, recommending and investigating free software in any
+ area of the customers choice.
+- Regular consulting.
+- Support on Internet service software, especially the free
+- Support on Linux.
+- Freeware based courses in Unix usage, C, C++, or any GNU tools
+
+Rates: For courses, contact us for a quote,
+For consulting, $60-120/hour, depending on contract length.
+
+Entered: 1997-05-12
+
+Jonathan Thornburg / BKIS Consulting
+E-mail: <bkis@island.net> (preferred way to contact me)
+Postal: Box 8-7, Thetis Island BC V0R 2Y0, Canada
+Phone: (250) 246-3640 (somewhat unreliable)
+
+* B.Sc (Honors 1st Class) in Math+Physics+CS, M.Sc and Ph.D in Astronomy
+* 20+ years computing experience using a wide range of software and
+ hardware environments
+
+* Very fluent in C (15+ years experience)
+* Fluent in C++, Perl, sh, csh, Awk, Fortran, PL/I, Pascal, APL, Lisp,
+ Basic, Maple, Reduce, various machine languages
+* Very fluent (10+ years experience) in general Unix toolset and programming
+* Good knowledge (4+ years experience) of Unix system administration
+ (SunOS, Linux, SGI)
+* Strong background (both theory and practical experience) in Unix/network
+ security, computer graphics, X and Motif GUI programming
+* Good general knowledge of Unix (kernel) internals and device drivers
+* Very fluent in LaTeX, TeX, also HTML, HTTP, and CGI programming
+* Member of Usenix (professional and technical Unix association) and
+ SAGE (system administrator's guild)
+
+* Very strong background (extensive experience) in numerical analysis
+* Strong backgrounds in hardware architecture, microprogramming,
+ programming language implementation, compiler theory, data structures,
+ OS design and internals, networking, symbolic manipulation, AI
+
+I'm available for Unix-based contract programming, software installation,
+and/or general system administration. My recent projects include several
+20K-50K 50K line C/Maple/Awk scientific applications, several small (1K line)
+Perl/Awk text processors and "system glue" CGI programs, finding and fixing
+bugs in a (free) 50K line graphics package, and a partially completed project
+to port (really rewrite) the GUI of a 50K line C++ Netscape plugin from
+Win32 to Unix/X/Motif.
+
+Unless otherwise required by a client, all the software I write is covered
+by the GNU General Public License. My basic rate is Can$50/hour for work I
+can do remotely over the Internet, more for on-site work, less for selected
+non-profit organizations.
+
+Updated: 1997-05-19
+
+Leonard H. Tower Jr. <tower@ai.mit.edu>
36 Porter Street
-Somerville, MA 02143, USA
-+1 (617) 623-7739
+Somerville, MA 02143
+USA
++1-617-623-7739
Will work on most GNU software.
Installation, handholding, trouble shooting, extensions, teaching.
-Rates: 100.00/hour + travel expenses. Negotiable for non-profits.
+Rates: $ 150.00/hour + travel expenses. Fixed fee quotes available.
+ Negotiable for non-profits.
Experience: Have hacked on over a dozen architectures in many languages. Have
-system mothered several varieties of Unixes. Assisted rms with the front end
-of gcc and it's back-end support. Resume available on request.
-
-Entered: 14Apr94
-
-UrbanSoft AO <info@usoft.spb.su>
-68 Malooktinskii Prospect
-St. Petersburg, Russia 195272
-
-Custom GhostScript and TeX programming by e-mail.
-Database documents, directories, standard forms.
-
-UrbanSoft uses a portion of its revenues to contribute
-diskette distributions of GNU software to Russian
-universities (most of which lack FTP access).
-
-Rates: 30,000 rubles (currently USD 16.80) per hour.
- Fixed rate contracts also possible.
- Payable by bank transfer.
+system mothered too many varieties of Unixes. Assisted rms with the front end
+of gcc and its back-end support. Resume available on request.
-Updated: 20Apr94
+Updated: 1998-02-10

-noris network
+noris network GmbH
Matthias Urlichs
Schleiermacherstrasse 12
90491 Nuernberg
Germany
-Phone: +49 911 9959621
-Fax: +49 911 5980150
+Phone: +49 911 59818-0
+Fax: +49 911 59818-11
<info@noris.de>
http://info.noris.de/ (German)
Expertise:
OS internals, esp. Linux and BSD, esp. device drivers
Network protocol / program design and coding
- Utilities coding and maintainance
+ Utilities coding and maintenance
Program debugging, testing
User interface design and testing
Several programming and tool languages
@@ -766,87 +1503,107 @@ Services:
Internet access
Rates:
- DM 110 (~$70) per hour
- Support contracts start at DM 170/month + DM 30/supported system.
+ DM 150 (~$85) per hour
+ Support contracts start at DM 220/month + DM 30/supported system.
Willing to travel for sufficiently large jobs.
Rates don't include taxes.
-Entered: 16Aug94
+Updated: 1997-08-04

-Joe Wells <jbw@cs.bu.edu>
-Postal Address:
- care of: Boston University Computer Science Department
- 111 Cummington Street, Room 138
- Boston, Massachusetts 02215
-Work Telephone: (617) 353-3381 (sorry, but no answering machine or voice mail)
-Home Telephone: (617) 739-7456 (until August 1995)
-Finger "jbw@cs.bu.edu" for up-to-date contact information.
+Paul C.A. van Gool
+ <vangool@fel.tno.nl>
-Experience:
- I have B.A. and M.A. degrees in Computer Science and have completed
- all but the dissertation for a Ph.D. in C.S. My research for my
- Ph.D. is in the areas of logic, type systems, and programming
- language theory. My primary programming languages are Emacs Lisp,
- Perl, and Bourne shell, but of course I can program in any language.
- I have written numerous Emacs Lisp packages. I started the USENET
- "List of Frequently Asked Questions about GNU Emacs with Answers" and
- maintained it for more than two years. Most of my work has been
- related to the telephone system (modems, voice mail, etc.), but I am
- not limited to that. Send e-mail for my complete resume or curriculum
- vita.
+Address: Netherlands Organization for Applied Scientific Research
+ Physics and Electronics Laboratory
+ PO Box 96864, 2509 JG the Hague
+ The Netherlands
-Programs supported:
- GNU Emacs and Taylor UUCP:
- Installation, training, customization, bug fixing, troubleshooting,
- extension, development, porting, or answering any kind of question.
- Any other GNU program:
- The same things, but I don't necessarily have huge amounts of
- experience with the particular program.
-
-Working conditions:
- I am usually available for part-time work (less than 20 hours per week
- including any travel time). I can sometimes make time for full-time
- work for a month or two; please inquire. I can either work in or near
- Boston or via the Internet or via telephone; travel outside the Boston
- metropolitan area can be negotiated. My schedule is very flexible.
- Any programs I write will normally have the copying conditions of the
- GNU General Public License; this is negotiable.
-
-Rates: $65/hour as an independent contractor.
- travel and telephone expenses.
- higher rates if extensive travel is required.
-
-Updated: 27Sep94.
-
-Herb Wood
-phone: 1-415-789-7173
-email: <ru@ccnext.ucsf.edu>
-
-I'm a better "planner" than I am a hacker. A really good hacker will be able
-to keep many pieces of information in their short-term memory and to memorize
-new pieces of information at a fast rate. This is not my strong point.
-Rather, I excel in domains that require knowledge of the slightly more
-theoretical parts of computer science --for example, logic, formal methods of
-program development, and functional programming. I can write, and I have
-"tutoring" (teaching one-on-one) experience, an, unlike some programmers,
-I enjoy doing these things.
-
-I have spend a lot of time looking at the Emacs Lisp sources and customizing
-Emacs and VM. I think I can customize Emacs and its packages quickly and
-effectively.
-
-Entered: 30Jul95
-
-Yggdrasil Computing, Inc./ Freesoft, Inc. <info@yggdrasil.com>
-4880 Stevens Creek Blvd. Ste. 205
-San Jose, CA 95129
-(408) 261-6630
-(800) 261 6630
-
-Updated: 14Apr94
+Phone: +31-70-3740260
+Fax : +31-70-3740652
+
+I would like to provide unpaid support for the following things:
+
+- C
+- C++
+- f2c
+- compilation and installation of most GNU packages
+
+Updated: 1998-06-24
+
+Joel N. Weber II
+185 Lowell St #2
+Somerville, MA 02144-2629
+devnull@gnu.org
+
+I can install GNU software, customize it, fix bugs, answer questions,
+and teach.
+
+I am fluent in C, emacs lisp, Bourne shell, and awk. I also have a
+good understanding of automake and autoconf.
+
+I have modified identd, cvs, and ftpd to change their security
+procedures; I have modified the GNU fileutils to understand new flag
+bits that were added to the Hurd. I have been involved in developing
+Hurd translators. Long ago, I worked on developing a web browser;
+that project was eventually killed, but I learned a lot in the
+process.
+
+I am experienced in webmastering and system administration.
+
+Rate: $100/hour, negotiable.
+
+Arne Wichmann
+
+EMail: <aw@math.uni-sb.de>
+Telephone on request.
+
+I support GNU software on the following platforms:
+
+Linux
+SunOS 4.X 5.X
+HPUX 9.X
+other platforms on request.
+
+Usual rates: 20DM per hour. Free support for private people as time
+permits.
+
+Updated: 1997-05-16
+
+Jody Winston
+xprt Computer Consulting, Inc.
+731 Voyager
+Houston, TX, 77058
+(281) 480-UNIX, <jody@sccsi.com>
+
+We have supported, installed, and used the entire GNU software suite
+for over 8 years on many different Unix platforms. We have written
+character device drivers and proc file systems for custom hardware
+running on Linux. In addition, we have developed a custom X11 server
+and X input extensions. Our consulting rate is $150.00 US dollars per
+hour, negotiable, plus a per diem for out of town work.
+
+Updated: 1997-05-12
+
+Lige Zhou
+Consultant
+Open Technologies Corporation
+Sun Lotus Bldg. 2nd Floor
+2-9-1 Chuou, Nakano-ku, Tokyo 164 Japan
+Tel: +81-3-3365-2911 Fax: +81-3-3365-2920
+E-mail: <zhou@opentech.co.jp>
+
+My profile is listed at: http://www.opentech.co.jp/~zhou/
+
+I have two years of experience porting and supporting GNU C Compiler and
+GNU Assembler at the Wingnut project of SRA, Inc., Tokyo.
+
+I can provide free consultation on these products if the problem is not
+time-consuming.
+
+Updated: 1996-12-04

For a current copy of this directory, or to have yourself listed, ask:
- gnu@prep.ai.mit.edu
+ gnu@gnu.org
** Please keep the entries in this file alphabetical **
diff --git a/contrib/gcc/acconfig.h b/contrib/gcc/acconfig.h
new file mode 100644
index 0000000..e1ac384
--- /dev/null
+++ b/contrib/gcc/acconfig.h
@@ -0,0 +1,79 @@
+/* Define if printf supports "%p". */
+#undef HAVE_PRINTF_PTR
+
+/* Define if you want expensive run-time checks. */
+#undef ENABLE_CHECKING
+
+/* Define if your cpp understands the stringify operator. */
+#undef HAVE_CPP_STRINGIFY
+
+/* Define if your compiler understands volatile. */
+#undef HAVE_VOLATILE
+
+/* Define if your assembler supports specifying the maximum number
+ of bytes to skip when using the GAS .p2align command. */
+#undef HAVE_GAS_MAX_SKIP_P2ALIGN
+
+/* Define if your assembler supports .balign and .p2align. */
+#undef HAVE_GAS_BALIGN_AND_P2ALIGN
+
+/* Define if you have a working <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Whether malloc must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_MALLOC
+
+/* Whether realloc must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_REALLOC
+
+/* Whether calloc must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_CALLOC
+
+/* Whether free must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_FREE
+
+/* Whether bcopy must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_BCOPY
+
+/* Whether bcmp must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_BCMP
+
+/* Whether bzero must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_BZERO
+
+/* Whether index must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_INDEX
+
+/* Whether rindex must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_RINDEX
+
+/* Whether getenv must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_GETENV
+
+/* Whether atol must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_ATOL
+
+/* Whether sbrk must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_SBRK
+
+/* Whether abort must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_ABORT
+
+/* Whether strerror must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_STRERROR
+
+/* Whether getcwd must be declared even if <unistd.h> is included. */
+#undef NEED_DECLARATION_GETCWD
+
+/* Whether getwd must be declared even if <unistd.h> is included. */
+#undef NEED_DECLARATION_GETWD
+
+/* Whether getrlimit must be declared even if <sys/resource.h> is included. */
+#undef NEED_DECLARATION_GETRLIMIT
+
+/* Whether setrlimit must be declared even if <sys/resource.h> is included. */
+#undef NEED_DECLARATION_SETRLIMIT
+
+/* Define if you want expensive run-time checks. */
+#undef ENABLE_CHECKING
+@TOP@
diff --git a/contrib/gcc/aclocal.m4 b/contrib/gcc/aclocal.m4
new file mode 100644
index 0000000..febe8a7
--- /dev/null
+++ b/contrib/gcc/aclocal.m4
@@ -0,0 +1,221 @@
+dnl See whether we need a declaration for a function.
+dnl GCC_NEED_DECLARATION(FUNCTION [, EXTRA-HEADER-FILES])
+AC_DEFUN(GCC_NEED_DECLARATION,
+[AC_MSG_CHECKING([whether $1 must be declared])
+AC_CACHE_VAL(gcc_cv_decl_needed_$1,
+[AC_TRY_COMPILE([
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef HAVE_RINDEX
+#define rindex strrchr
+#endif
+#ifndef HAVE_INDEX
+#define index strchr
+#endif
+$2],
+[char *(*pfn) = (char *(*)) $1],
+eval "gcc_cv_decl_needed_$1=no", eval "gcc_cv_decl_needed_$1=yes")])
+if eval "test \"`echo '$gcc_cv_decl_needed_'$1`\" = yes"; then
+ AC_MSG_RESULT(yes)
+ gcc_tr_decl=NEED_DECLARATION_`echo $1 | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ AC_DEFINE_UNQUOTED($gcc_tr_decl)
+else
+ AC_MSG_RESULT(no)
+fi
+])dnl
+
+dnl Check multiple functions to see whether each needs a declaration.
+dnl GCC_NEED_DECLARATIONS(FUNCTION... [, EXTRA-HEADER-FILES])
+AC_DEFUN(GCC_NEED_DECLARATIONS,
+[for ac_func in $1
+do
+GCC_NEED_DECLARATION($ac_func, $2)
+done
+])
+
+dnl Check if we have vprintf and possibly _doprnt.
+dnl Note autoconf checks for vprintf even though we care about vfprintf.
+AC_DEFUN(GCC_FUNC_VFPRINTF_DOPRNT,
+[AC_FUNC_VPRINTF
+vfprintf=
+doprint=
+if test $ac_cv_func_vprintf != yes ; then
+ vfprintf=vfprintf.o
+ if test $ac_cv_func__doprnt != yes ; then
+ doprint=doprint.o
+ fi
+fi
+AC_SUBST(vfprintf)
+AC_SUBST(doprint)
+])
+
+dnl See if the printf functions in libc support %p in format strings.
+AC_DEFUN(GCC_FUNC_PRINTF_PTR,
+[AC_CACHE_CHECK(whether the printf functions support %p,
+ gcc_cv_func_printf_ptr,
+[AC_TRY_RUN([#include <stdio.h>
+
+main()
+{
+ char buf[64];
+ char *p = buf, *q = NULL;
+ sprintf(buf, "%p", p);
+ sscanf(buf, "%p", &q);
+ exit (p != q);
+}], gcc_cv_func_printf_ptr=yes, gcc_cv_func_printf_ptr=no,
+ gcc_cv_func_printf_ptr=no)
+rm -f core core.* *.core])
+if test $gcc_cv_func_printf_ptr = yes ; then
+ AC_DEFINE(HAVE_PRINTF_PTR)
+fi
+])
+
+dnl See if symbolic links work and if not, try to substitute either hard links or simple copy.
+AC_DEFUN(GCC_PROG_LN_S,
+[AC_MSG_CHECKING(whether ln -s works)
+AC_CACHE_VAL(gcc_cv_prog_LN_S,
+[rm -f conftestdata_t
+echo >conftestdata_f
+if ln -s conftestdata_f conftestdata_t 2>/dev/null
+then
+ gcc_cv_prog_LN_S="ln -s"
+else
+ if ln conftestdata_f conftestdata_t 2>/dev/null
+ then
+ gcc_cv_prog_LN_S=ln
+ else
+ gcc_cv_prog_LN_S=cp
+ fi
+fi
+rm -f conftestdata_f conftestdata_t
+])dnl
+LN_S="$gcc_cv_prog_LN_S"
+if test "$gcc_cv_prog_LN_S" = "ln -s"; then
+ AC_MSG_RESULT(yes)
+else
+ if test "$gcc_cv_prog_LN_S" = "ln"; then
+ AC_MSG_RESULT([no, using ln])
+ else
+ AC_MSG_RESULT([no, and neither does ln, so using cp])
+ fi
+fi
+AC_SUBST(LN_S)dnl
+])
+
+dnl See if hard links work and if not, try to substitute either symbolic links or simple copy.
+AC_DEFUN(GCC_PROG_LN,
+[AC_MSG_CHECKING(whether ln works)
+AC_CACHE_VAL(gcc_cv_prog_LN,
+[rm -f conftestdata_t
+echo >conftestdata_f
+if ln conftestdata_f conftestdata_t 2>/dev/null
+then
+ gcc_cv_prog_LN="ln"
+else
+ if ln -s conftestdata_f conftestdata_t 2>/dev/null
+ then
+ gcc_cv_prog_LN="ln -s"
+ else
+ gcc_cv_prog_LN=cp
+ fi
+fi
+rm -f conftestdata_f conftestdata_t
+])dnl
+LN="$gcc_cv_prog_LN"
+if test "$gcc_cv_prog_LN" = "ln"; then
+ AC_MSG_RESULT(yes)
+else
+ if test "$gcc_cv_prog_LN" = "ln -s"; then
+ AC_MSG_RESULT([no, using ln -s])
+ else
+ AC_MSG_RESULT([no, and neither does ln -s, so using cp])
+ fi
+fi
+AC_SUBST(LN)dnl
+])
+
+dnl See whether the stage1 host compiler accepts the volatile keyword.
+AC_DEFUN(GCC_C_VOLATILE,
+[AC_CACHE_CHECK([for volatile], gcc_cv_c_volatile,
+[AC_TRY_COMPILE(, [volatile int foo;],
+ gcc_cv_c_volatile=yes, gcc_cv_c_volatile=no)])
+if test $gcc_cv_c_volatile = yes ; then
+ AC_DEFINE(HAVE_VOLATILE)
+fi
+])
+
+AC_DEFUN(EGCS_PROG_INSTALL,
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+AC_MSG_CHECKING(for a BSD compatible install)
+if test -z "$INSTALL"; then
+AC_CACHE_VAL(ac_cv_path_install,
+[ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+])dnl
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+dnl We do special magic for INSTALL instead of AC_SUBST, to get
+dnl relative paths right.
+AC_MSG_RESULT($INSTALL)
+AC_SUBST(INSTALL)dnl
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+AC_SUBST(INSTALL_PROGRAM)dnl
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+AC_SUBST(INSTALL_DATA)dnl
+])
diff --git a/contrib/gcc/alias.c b/contrib/gcc/alias.c
new file mode 100644
index 0000000..172b676
--- /dev/null
+++ b/contrib/gcc/alias.c
@@ -0,0 +1,1261 @@
+/* Alias analysis for GNU C
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+ Contributed by John Carr (jfc@mit.edu).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "expr.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "flags.h"
+#include "toplev.h"
+
+static rtx canon_rtx PROTO((rtx));
+static int rtx_equal_for_memref_p PROTO((rtx, rtx));
+static rtx find_symbolic_term PROTO((rtx));
+static int memrefs_conflict_p PROTO((int, rtx, int, rtx,
+ HOST_WIDE_INT));
+static void record_set PROTO((rtx, rtx));
+static rtx find_base_term PROTO((rtx));
+static int base_alias_check PROTO((rtx, rtx));
+static rtx find_base_value PROTO((rtx));
+
+/* Set up all info needed to perform alias analysis on memory references. */
+
+#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
+
+/* Perform a basic sanity check. Namely, that there are
+ no alias sets if we're not doing strict aliasing. This helps
+ to catch bugs whereby someone uses PUT_CODE, but doesn't clear
+ MEM_ALIAS_SET, or where a MEM is allocated in some way other
+ than by the use of gen_rtx_MEM, and the MEM_ALIAS_SET is not
+ cleared. */
+#ifdef ENABLE_CHECKING
+#define CHECK_ALIAS_SETS_FOR_CONSISTENCY(MEM1, MEM2) \
+ (!flag_strict_aliasing \
+ && (MEM_ALIAS_SET (MEM1) || MEM_ALIAS_SET (MEM2)) \
+ ? (abort (), 0) : 0)
+#else
+#define CHECK_ALIAS_SETS_FOR_CONSISTENCY(MEM1, MEM2) ((void)0)
+#endif
+
+/* Returns nonzero if MEM1 and MEM2 do not alias because they are in
+ different alias sets. */
+#define DIFFERENT_ALIAS_SETS_P(MEM1, MEM2) \
+ (CHECK_ALIAS_SETS_FOR_CONSISTENCY(MEM1, MEM2), \
+ MEM_ALIAS_SET (MEM1) && MEM_ALIAS_SET (MEM2) \
+ && MEM_ALIAS_SET (MEM1) != MEM_ALIAS_SET (MEM2))
+
+/* Cap the number of passes we make over the insns propagating alias
+ information through set chains.
+
+ 10 is a completely arbitrary choice. */
+#define MAX_ALIAS_LOOP_PASSES 10
+
+/* reg_base_value[N] gives an address to which register N is related.
+ If all sets after the first add or subtract to the current value
+ or otherwise modify it so it does not point to a different top level
+ object, reg_base_value[N] is equal to the address part of the source
+ of the first set.
+
+ A base address can be an ADDRESS, SYMBOL_REF, or LABEL_REF. ADDRESS
+ expressions represent certain special values: function arguments and
+ the stack, frame, and argument pointers. The contents of an address
+ expression are not used (but they are descriptive for debugging);
+ only the address and mode matter. Pointer equality, not rtx_equal_p,
+ determines whether two ADDRESS expressions refer to the same base
+ address. The mode determines whether it is a function argument or
+ other special value. */
+
+rtx *reg_base_value;
+rtx *new_reg_base_value;
+unsigned int reg_base_value_size; /* size of reg_base_value array */
+#define REG_BASE_VALUE(X) \
+ (REGNO (X) < reg_base_value_size ? reg_base_value[REGNO (X)] : 0)
+
+/* Vector of known invariant relationships between registers. Set in
+ loop unrolling. Indexed by register number, if nonzero the value
+ is an expression describing this register in terms of another.
+
+ The length of this array is REG_BASE_VALUE_SIZE.
+
+ Because this array contains only pseudo registers it has no effect
+ after reload. */
+static rtx *alias_invariant;
+
+/* Vector indexed by N giving the initial (unchanging) value known
+ for pseudo-register N. */
+rtx *reg_known_value;
+
+/* Indicates number of valid entries in reg_known_value. */
+static int reg_known_value_size;
+
+/* Vector recording for each reg_known_value whether it is due to a
+ REG_EQUIV note. Future passes (viz., reload) may replace the
+ pseudo with the equivalent expression and so we account for the
+ dependences that would be introduced if that happens. */
+/* ??? This is a problem only on the Convex. The REG_EQUIV notes created in
+ assign_parms mention the arg pointer, and there are explicit insns in the
+ RTL that modify the arg pointer. Thus we must ensure that such insns don't
+ get scheduled across each other because that would invalidate the REG_EQUIV
+ notes. One could argue that the REG_EQUIV notes are wrong, but solving
+ the problem in the scheduler will likely give better code, so we do it
+ here. */
+char *reg_known_equiv_p;
+
+/* True when scanning insns from the start of the rtl to the
+ NOTE_INSN_FUNCTION_BEG note. */
+
+static int copying_arguments;
+
+/* Inside SRC, the source of a SET, find a base address. */
+
+static rtx
+find_base_value (src)
+ register rtx src;
+{
+ switch (GET_CODE (src))
+ {
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return src;
+
+ case REG:
+ /* At the start of a function argument registers have known base
+ values which may be lost later. Returning an ADDRESS
+ expression here allows optimization based on argument values
+ even when the argument registers are used for other purposes. */
+ if (REGNO (src) < FIRST_PSEUDO_REGISTER && copying_arguments)
+ return new_reg_base_value[REGNO (src)];
+
+ /* If a pseudo has a known base value, return it. Do not do this
+ for hard regs since it can result in a circular dependency
+ chain for registers which have values at function entry.
+
+ The test above is not sufficient because the scheduler may move
+ a copy out of an arg reg past the NOTE_INSN_FUNCTION_BEGIN. */
+ if (REGNO (src) >= FIRST_PSEUDO_REGISTER
+ && REGNO (src) < reg_base_value_size
+ && reg_base_value[REGNO (src)])
+ return reg_base_value[REGNO (src)];
+
+ return src;
+
+ case MEM:
+ /* Check for an argument passed in memory. Only record in the
+ copying-arguments block; it is too hard to track changes
+ otherwise. */
+ if (copying_arguments
+ && (XEXP (src, 0) == arg_pointer_rtx
+ || (GET_CODE (XEXP (src, 0)) == PLUS
+ && XEXP (XEXP (src, 0), 0) == arg_pointer_rtx)))
+ return gen_rtx_ADDRESS (VOIDmode, src);
+ return 0;
+
+ case CONST:
+ src = XEXP (src, 0);
+ if (GET_CODE (src) != PLUS && GET_CODE (src) != MINUS)
+ break;
+ /* fall through */
+
+ case PLUS:
+ case MINUS:
+ {
+ rtx temp, src_0 = XEXP (src, 0), src_1 = XEXP (src, 1);
+
+ /* If either operand is a REG, then see if we already have
+ a known value for it. */
+ if (GET_CODE (src_0) == REG)
+ {
+ temp = find_base_value (src_0);
+ if (temp)
+ src_0 = temp;
+ }
+
+ if (GET_CODE (src_1) == REG)
+ {
+ temp = find_base_value (src_1);
+ if (temp)
+ src_1 = temp;
+ }
+
+ /* Guess which operand is the base address.
+
+ If either operand is a symbol, then it is the base. If
+ either operand is a CONST_INT, then the other is the base. */
+
+ if (GET_CODE (src_1) == CONST_INT
+ || GET_CODE (src_0) == SYMBOL_REF
+ || GET_CODE (src_0) == LABEL_REF
+ || GET_CODE (src_0) == CONST)
+ return find_base_value (src_0);
+
+ if (GET_CODE (src_0) == CONST_INT
+ || GET_CODE (src_1) == SYMBOL_REF
+ || GET_CODE (src_1) == LABEL_REF
+ || GET_CODE (src_1) == CONST)
+ return find_base_value (src_1);
+
+ /* This might not be necessary anymore.
+
+ If either operand is a REG that is a known pointer, then it
+ is the base. */
+ if (GET_CODE (src_0) == REG && REGNO_POINTER_FLAG (REGNO (src_0)))
+ return find_base_value (src_0);
+
+ if (GET_CODE (src_1) == REG && REGNO_POINTER_FLAG (REGNO (src_1)))
+ return find_base_value (src_1);
+
+ return 0;
+ }
+
+ case LO_SUM:
+ /* The standard form is (lo_sum reg sym) so look only at the
+ second operand. */
+ return find_base_value (XEXP (src, 1));
+
+ case AND:
+ /* If the second operand is constant set the base
+ address to the first operand. */
+ if (GET_CODE (XEXP (src, 1)) == CONST_INT && INTVAL (XEXP (src, 1)) != 0)
+ return find_base_value (XEXP (src, 0));
+ return 0;
+
+ case ZERO_EXTEND:
+ case SIGN_EXTEND: /* used for NT/Alpha pointers */
+ case HIGH:
+ return find_base_value (XEXP (src, 0));
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Called from init_alias_analysis indirectly through note_stores. */
+
+/* while scanning insns to find base values, reg_seen[N] is nonzero if
+ register N has been set in this function. */
+static char *reg_seen;
+
+/* Addresses which are known not to alias anything else are identified
+ by a unique integer. */
+static int unique_id;
+
+static void
+record_set (dest, set)
+ rtx dest, set;
+{
+ register int regno;
+ rtx src;
+
+ if (GET_CODE (dest) != REG)
+ return;
+
+ regno = REGNO (dest);
+
+ if (set)
+ {
+ /* A CLOBBER wipes out any old value but does not prevent a previously
+ unset register from acquiring a base address (i.e. reg_seen is not
+ set). */
+ if (GET_CODE (set) == CLOBBER)
+ {
+ new_reg_base_value[regno] = 0;
+ return;
+ }
+ src = SET_SRC (set);
+ }
+ else
+ {
+ if (reg_seen[regno])
+ {
+ new_reg_base_value[regno] = 0;
+ return;
+ }
+ reg_seen[regno] = 1;
+ new_reg_base_value[regno] = gen_rtx_ADDRESS (Pmode,
+ GEN_INT (unique_id++));
+ return;
+ }
+
+ /* This is not the first set. If the new value is not related to the
+ old value, forget the base value. Note that the following code is
+ not detected:
+ extern int x, y; int *p = &x; p += (&y-&x);
+ ANSI C does not allow computing the difference of addresses
+ of distinct top level objects. */
+ if (new_reg_base_value[regno])
+ switch (GET_CODE (src))
+ {
+ case LO_SUM:
+ case PLUS:
+ case MINUS:
+ if (XEXP (src, 0) != dest && XEXP (src, 1) != dest)
+ new_reg_base_value[regno] = 0;
+ break;
+ case AND:
+ if (XEXP (src, 0) != dest || GET_CODE (XEXP (src, 1)) != CONST_INT)
+ new_reg_base_value[regno] = 0;
+ break;
+ default:
+ new_reg_base_value[regno] = 0;
+ break;
+ }
+ /* If this is the first set of a register, record the value. */
+ else if ((regno >= FIRST_PSEUDO_REGISTER || ! fixed_regs[regno])
+ && ! reg_seen[regno] && new_reg_base_value[regno] == 0)
+ new_reg_base_value[regno] = find_base_value (src);
+
+ reg_seen[regno] = 1;
+}
+
+/* Called from loop optimization when a new pseudo-register is created. */
+void
+record_base_value (regno, val, invariant)
+ int regno;
+ rtx val;
+ int invariant;
+{
+ if (regno >= reg_base_value_size)
+ return;
+
+ /* If INVARIANT is true then this value also describes an invariant
+ relationship which can be used to deduce that two registers with
+ unknown values are different. */
+ if (invariant && alias_invariant)
+ alias_invariant[regno] = val;
+
+ if (GET_CODE (val) == REG)
+ {
+ if (REGNO (val) < reg_base_value_size)
+ {
+ reg_base_value[regno] = reg_base_value[REGNO (val)];
+ }
+ return;
+ }
+ reg_base_value[regno] = find_base_value (val);
+}
+
+static rtx
+canon_rtx (x)
+ rtx x;
+{
+ /* Recursively look for equivalences. */
+ if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER
+ && REGNO (x) < reg_known_value_size)
+ return reg_known_value[REGNO (x)] == x
+ ? x : canon_rtx (reg_known_value[REGNO (x)]);
+ else if (GET_CODE (x) == PLUS)
+ {
+ rtx x0 = canon_rtx (XEXP (x, 0));
+ rtx x1 = canon_rtx (XEXP (x, 1));
+
+ if (x0 != XEXP (x, 0) || x1 != XEXP (x, 1))
+ {
+ /* We can tolerate LO_SUMs being offset here; these
+ rtl are used for nothing other than comparisons. */
+ if (GET_CODE (x0) == CONST_INT)
+ return plus_constant_for_output (x1, INTVAL (x0));
+ else if (GET_CODE (x1) == CONST_INT)
+ return plus_constant_for_output (x0, INTVAL (x1));
+ return gen_rtx_PLUS (GET_MODE (x), x0, x1);
+ }
+ }
+ /* This gives us much better alias analysis when called from
+ the loop optimizer. Note we want to leave the original
+ MEM alone, but need to return the canonicalized MEM with
+ all the flags with their original values. */
+ else if (GET_CODE (x) == MEM)
+ {
+ rtx addr = canon_rtx (XEXP (x, 0));
+ if (addr != XEXP (x, 0))
+ {
+ rtx new = gen_rtx_MEM (GET_MODE (x), addr);
+ MEM_VOLATILE_P (new) = MEM_VOLATILE_P (x);
+ RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
+ MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (x);
+ MEM_ALIAS_SET (new) = MEM_ALIAS_SET (x);
+ x = new;
+ }
+ }
+ return x;
+}
+
+/* Return 1 if X and Y are identical-looking rtx's.
+
+ We use the data in reg_known_value above to see if two registers with
+ different numbers are, in fact, equivalent. */
+
+static int
+rtx_equal_for_memref_p (x, y)
+ rtx x, y;
+{
+ register int i;
+ register int j;
+ register enum rtx_code code;
+ register char *fmt;
+
+ if (x == 0 && y == 0)
+ return 1;
+ if (x == 0 || y == 0)
+ return 0;
+ x = canon_rtx (x);
+ y = canon_rtx (y);
+
+ if (x == y)
+ return 1;
+
+ code = GET_CODE (x);
+ /* Rtx's of different codes cannot be equal. */
+ if (code != GET_CODE (y))
+ return 0;
+
+ /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
+ (REG:SI x) and (REG:HI x) are NOT equivalent. */
+
+ if (GET_MODE (x) != GET_MODE (y))
+ return 0;
+
+ /* REG, LABEL_REF, and SYMBOL_REF can be compared nonrecursively. */
+
+ if (code == REG)
+ return REGNO (x) == REGNO (y);
+ if (code == LABEL_REF)
+ return XEXP (x, 0) == XEXP (y, 0);
+ if (code == SYMBOL_REF)
+ return XSTR (x, 0) == XSTR (y, 0);
+ if (code == CONST_INT)
+ return INTVAL (x) == INTVAL (y);
+ if (code == ADDRESSOF)
+ return REGNO (XEXP (x, 0)) == REGNO (XEXP (y, 0)) && XINT (x, 1) == XINT (y, 1);
+
+ /* For commutative operations, the RTX match if the operand match in any
+ order. Also handle the simple binary and unary cases without a loop. */
+ if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
+ return ((rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0))
+ && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 1)))
+ || (rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 1))
+ && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 0))));
+ else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
+ return (rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0))
+ && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 1)));
+ else if (GET_RTX_CLASS (code) == '1')
+ return rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0));
+
+ /* Compare the elements. If any pair of corresponding elements
+ fail to match, return 0 for the whole things.
+
+ Limit cases to types which actually appear in addresses. */
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ switch (fmt[i])
+ {
+ case 'i':
+ if (XINT (x, i) != XINT (y, i))
+ return 0;
+ break;
+
+ case 'E':
+ /* Two vectors must have the same length. */
+ if (XVECLEN (x, i) != XVECLEN (y, i))
+ return 0;
+
+ /* And the corresponding elements must match. */
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (rtx_equal_for_memref_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0)
+ return 0;
+ break;
+
+ case 'e':
+ if (rtx_equal_for_memref_p (XEXP (x, i), XEXP (y, i)) == 0)
+ return 0;
+ break;
+
+ /* This can happen for an asm which clobbers memory. */
+ case '0':
+ break;
+
+ /* It is believed that rtx's at this level will never
+ contain anything but integers and other rtx's,
+ except for within LABEL_REFs and SYMBOL_REFs. */
+ default:
+ abort ();
+ }
+ }
+ return 1;
+}
+
+/* Given an rtx X, find a SYMBOL_REF or LABEL_REF within
+ X and return it, or return 0 if none found. */
+
+static rtx
+find_symbolic_term (x)
+ rtx x;
+{
+ register int i;
+ register enum rtx_code code;
+ register char *fmt;
+
+ code = GET_CODE (x);
+ if (code == SYMBOL_REF || code == LABEL_REF)
+ return x;
+ if (GET_RTX_CLASS (code) == 'o')
+ return 0;
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ rtx t;
+
+ if (fmt[i] == 'e')
+ {
+ t = find_symbolic_term (XEXP (x, i));
+ if (t != 0)
+ return t;
+ }
+ else if (fmt[i] == 'E')
+ break;
+ }
+ return 0;
+}
+
+static rtx
+find_base_term (x)
+ register rtx x;
+{
+ switch (GET_CODE (x))
+ {
+ case REG:
+ return REG_BASE_VALUE (x);
+
+ case ZERO_EXTEND:
+ case SIGN_EXTEND: /* Used for Alpha/NT pointers */
+ case HIGH:
+ case PRE_INC:
+ case PRE_DEC:
+ case POST_INC:
+ case POST_DEC:
+ return find_base_term (XEXP (x, 0));
+
+ case CONST:
+ x = XEXP (x, 0);
+ if (GET_CODE (x) != PLUS && GET_CODE (x) != MINUS)
+ return 0;
+ /* fall through */
+ case LO_SUM:
+ case PLUS:
+ case MINUS:
+ {
+ rtx tmp = find_base_term (XEXP (x, 0));
+ if (tmp)
+ return tmp;
+ return find_base_term (XEXP (x, 1));
+ }
+
+ case AND:
+ if (GET_CODE (XEXP (x, 0)) == REG && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ return REG_BASE_VALUE (XEXP (x, 0));
+ return 0;
+
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return x;
+
+ default:
+ return 0;
+ }
+}
+
+/* Return 0 if the addresses X and Y are known to point to different
+ objects, 1 if they might be pointers to the same object. */
+
+static int
+base_alias_check (x, y)
+ rtx x, y;
+{
+ rtx x_base = find_base_term (x);
+ rtx y_base = find_base_term (y);
+
+ /* If the address itself has no known base see if a known equivalent
+ value has one. If either address still has no known base, nothing
+ is known about aliasing. */
+ if (x_base == 0)
+ {
+ rtx x_c;
+ if (! flag_expensive_optimizations || (x_c = canon_rtx (x)) == x)
+ return 1;
+ x_base = find_base_term (x_c);
+ if (x_base == 0)
+ return 1;
+ }
+
+ if (y_base == 0)
+ {
+ rtx y_c;
+ if (! flag_expensive_optimizations || (y_c = canon_rtx (y)) == y)
+ return 1;
+ y_base = find_base_term (y_c);
+ if (y_base == 0)
+ return 1;
+ }
+
+ /* If the base addresses are equal nothing is known about aliasing. */
+ if (rtx_equal_p (x_base, y_base))
+ return 1;
+
+ /* The base addresses of the read and write are different
+ expressions. If they are both symbols and they are not accessed
+ via AND, there is no conflict. */
+ /* XXX: We can bring knowledge of object alignment and offset into
+ play here. For example, on alpha, "char a, b;" can alias one
+ another, though "char a; long b;" cannot. Similarly, offsets
+ into strutures may be brought into play. Given "char a, b[40];",
+ a and b[1] may overlap, but a and b[20] do not. */
+ if (GET_CODE (x_base) != ADDRESS && GET_CODE (y_base) != ADDRESS)
+ {
+ return GET_CODE (x) == AND || GET_CODE (y) == AND;
+ }
+
+ /* If one address is a stack reference there can be no alias:
+ stack references using different base registers do not alias,
+ a stack reference can not alias a parameter, and a stack reference
+ can not alias a global. */
+ if ((GET_CODE (x_base) == ADDRESS && GET_MODE (x_base) == Pmode)
+ || (GET_CODE (y_base) == ADDRESS && GET_MODE (y_base) == Pmode))
+ return 0;
+
+ if (! flag_argument_noalias)
+ return 1;
+
+ if (flag_argument_noalias > 1)
+ return 0;
+
+ /* Weak noalias assertion (arguments are distinct, but may match globals). */
+ return ! (GET_MODE (x_base) == VOIDmode && GET_MODE (y_base) == VOIDmode);
+}
+
+/* Return nonzero if X and Y (memory addresses) could reference the
+ same location in memory. C is an offset accumulator. When
+ C is nonzero, we are testing aliases between X and Y + C.
+ XSIZE is the size in bytes of the X reference,
+ similarly YSIZE is the size in bytes for Y.
+
+ If XSIZE or YSIZE is zero, we do not know the amount of memory being
+ referenced (the reference was BLKmode), so make the most pessimistic
+ assumptions.
+
+ If XSIZE or YSIZE is negative, we may access memory outside the object
+ being referenced as a side effect. This can happen when using AND to
+ align memory references, as is done on the Alpha.
+
+ Nice to notice that varying addresses cannot conflict with fp if no
+ local variables had their addresses taken, but that's too hard now. */
+
+
+static int
+memrefs_conflict_p (xsize, x, ysize, y, c)
+ register rtx x, y;
+ int xsize, ysize;
+ HOST_WIDE_INT c;
+{
+ if (GET_CODE (x) == HIGH)
+ x = XEXP (x, 0);
+ else if (GET_CODE (x) == LO_SUM)
+ x = XEXP (x, 1);
+ else
+ x = canon_rtx (x);
+ if (GET_CODE (y) == HIGH)
+ y = XEXP (y, 0);
+ else if (GET_CODE (y) == LO_SUM)
+ y = XEXP (y, 1);
+ else
+ y = canon_rtx (y);
+
+ if (rtx_equal_for_memref_p (x, y))
+ {
+ if (xsize <= 0 || ysize <= 0)
+ return 1;
+ if (c >= 0 && xsize > c)
+ return 1;
+ if (c < 0 && ysize+c > 0)
+ return 1;
+ return 0;
+ }
+
+ /* This code used to check for conflicts involving stack references and
+ globals but the base address alias code now handles these cases. */
+
+ if (GET_CODE (x) == PLUS)
+ {
+ /* The fact that X is canonicalized means that this
+ PLUS rtx is canonicalized. */
+ rtx x0 = XEXP (x, 0);
+ rtx x1 = XEXP (x, 1);
+
+ if (GET_CODE (y) == PLUS)
+ {
+ /* The fact that Y is canonicalized means that this
+ PLUS rtx is canonicalized. */
+ rtx y0 = XEXP (y, 0);
+ rtx y1 = XEXP (y, 1);
+
+ if (rtx_equal_for_memref_p (x1, y1))
+ return memrefs_conflict_p (xsize, x0, ysize, y0, c);
+ if (rtx_equal_for_memref_p (x0, y0))
+ return memrefs_conflict_p (xsize, x1, ysize, y1, c);
+ if (GET_CODE (x1) == CONST_INT)
+ if (GET_CODE (y1) == CONST_INT)
+ return memrefs_conflict_p (xsize, x0, ysize, y0,
+ c - INTVAL (x1) + INTVAL (y1));
+ else
+ return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1));
+ else if (GET_CODE (y1) == CONST_INT)
+ return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
+
+ return 1;
+ }
+ else if (GET_CODE (x1) == CONST_INT)
+ return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1));
+ }
+ else if (GET_CODE (y) == PLUS)
+ {
+ /* The fact that Y is canonicalized means that this
+ PLUS rtx is canonicalized. */
+ rtx y0 = XEXP (y, 0);
+ rtx y1 = XEXP (y, 1);
+
+ if (GET_CODE (y1) == CONST_INT)
+ return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
+ else
+ return 1;
+ }
+
+ if (GET_CODE (x) == GET_CODE (y))
+ switch (GET_CODE (x))
+ {
+ case MULT:
+ {
+ /* Handle cases where we expect the second operands to be the
+ same, and check only whether the first operand would conflict
+ or not. */
+ rtx x0, y0;
+ rtx x1 = canon_rtx (XEXP (x, 1));
+ rtx y1 = canon_rtx (XEXP (y, 1));
+ if (! rtx_equal_for_memref_p (x1, y1))
+ return 1;
+ x0 = canon_rtx (XEXP (x, 0));
+ y0 = canon_rtx (XEXP (y, 0));
+ if (rtx_equal_for_memref_p (x0, y0))
+ return (xsize == 0 || ysize == 0
+ || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
+
+ /* Can't properly adjust our sizes. */
+ if (GET_CODE (x1) != CONST_INT)
+ return 1;
+ xsize /= INTVAL (x1);
+ ysize /= INTVAL (x1);
+ c /= INTVAL (x1);
+ return memrefs_conflict_p (xsize, x0, ysize, y0, c);
+ }
+
+ case REG:
+ /* Are these registers known not to be equal? */
+ if (alias_invariant)
+ {
+ int r_x = REGNO (x), r_y = REGNO (y);
+ rtx i_x, i_y; /* invariant relationships of X and Y */
+
+ i_x = r_x >= reg_base_value_size ? 0 : alias_invariant[r_x];
+ i_y = r_y >= reg_base_value_size ? 0 : alias_invariant[r_y];
+
+ if (i_x == 0 && i_y == 0)
+ break;
+
+ if (! memrefs_conflict_p (xsize, i_x ? i_x : x,
+ ysize, i_y ? i_y : y, c))
+ return 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Treat an access through an AND (e.g. a subword access on an Alpha)
+ as an access with indeterminate size.
+ ??? Could instead convert an n byte reference at (and x y) to an
+ n-y byte reference at (plus x y). */
+ if (GET_CODE (x) == AND && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ return memrefs_conflict_p (-1, XEXP (x, 0), ysize, y, c);
+ if (GET_CODE (y) == AND && GET_CODE (XEXP (y, 1)) == CONST_INT)
+ {
+ /* XXX: If we are indexing far enough into the array/structure, we
+ may yet be able to determine that we can not overlap. But we
+ also need to that we are far enough from the end not to overlap
+ a following reference, so we do nothing for now. */
+ return memrefs_conflict_p (xsize, x, -1, XEXP (y, 0), c);
+ }
+
+ if (CONSTANT_P (x))
+ {
+ if (GET_CODE (x) == CONST_INT && GET_CODE (y) == CONST_INT)
+ {
+ c += (INTVAL (y) - INTVAL (x));
+ return (xsize <= 0 || ysize <= 0
+ || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
+ }
+
+ if (GET_CODE (x) == CONST)
+ {
+ if (GET_CODE (y) == CONST)
+ return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)),
+ ysize, canon_rtx (XEXP (y, 0)), c);
+ else
+ return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)),
+ ysize, y, c);
+ }
+ if (GET_CODE (y) == CONST)
+ return memrefs_conflict_p (xsize, x, ysize,
+ canon_rtx (XEXP (y, 0)), c);
+
+ if (CONSTANT_P (y))
+ return (xsize < 0 || ysize < 0
+ || (rtx_equal_for_memref_p (x, y)
+ && (xsize == 0 || ysize == 0
+ || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0))));
+
+ return 1;
+ }
+ return 1;
+}
+
+/* Functions to compute memory dependencies.
+
+ Since we process the insns in execution order, we can build tables
+ to keep track of what registers are fixed (and not aliased), what registers
+ are varying in known ways, and what registers are varying in unknown
+ ways.
+
+ If both memory references are volatile, then there must always be a
+ dependence between the two references, since their order can not be
+ changed. A volatile and non-volatile reference can be interchanged
+ though.
+
+ A MEM_IN_STRUCT reference at a non-QImode non-AND varying address can never
+ conflict with a non-MEM_IN_STRUCT reference at a fixed address. We must
+ allow QImode aliasing because the ANSI C standard allows character
+ pointers to alias anything. We are assuming that characters are
+ always QImode here. We also must allow AND addresses, because they may
+ generate accesses outside the object being referenced. This is used to
+ generate aligned addresses from unaligned addresses, for instance, the
+ alpha storeqi_unaligned pattern. */
+
+/* Read dependence: X is read after read in MEM takes place. There can
+ only be a dependence here if both reads are volatile. */
+
+int
+read_dependence (mem, x)
+ rtx mem;
+ rtx x;
+{
+ return MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem);
+}
+
+/* True dependence: X is read after store in MEM takes place. */
+
+int
+true_dependence (mem, mem_mode, x, varies)
+ rtx mem;
+ enum machine_mode mem_mode;
+ rtx x;
+ int (*varies) PROTO((rtx));
+{
+ register rtx x_addr, mem_addr;
+
+ if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
+ return 1;
+
+ if (DIFFERENT_ALIAS_SETS_P (x, mem))
+ return 0;
+
+ /* If X is an unchanging read, then it can't possibly conflict with any
+ non-unchanging store. It may conflict with an unchanging write though,
+ because there may be a single store to this address to initialize it.
+ Just fall through to the code below to resolve the case where we have
+ both an unchanging read and an unchanging write. This won't handle all
+ cases optimally, but the possible performance loss should be
+ negligible. */
+ if (RTX_UNCHANGING_P (x) && ! RTX_UNCHANGING_P (mem))
+ return 0;
+
+ if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0)))
+ return 0;
+
+ x_addr = canon_rtx (XEXP (x, 0));
+ mem_addr = canon_rtx (XEXP (mem, 0));
+
+ if (mem_mode == VOIDmode)
+ mem_mode = GET_MODE (mem);
+
+ if (! memrefs_conflict_p (GET_MODE_SIZE (mem_mode), mem_addr,
+ SIZE_FOR_MODE (x), x_addr, 0))
+ return 0;
+
+ /* If both references are struct references, or both are not, nothing
+ is known about aliasing.
+
+ If either reference is QImode or BLKmode, ANSI C permits aliasing.
+
+ If both addresses are constant, or both are not, nothing is known
+ about aliasing. */
+ if (MEM_IN_STRUCT_P (x) == MEM_IN_STRUCT_P (mem)
+ || mem_mode == QImode || mem_mode == BLKmode
+ || GET_MODE (x) == QImode || GET_MODE (x) == BLKmode
+ || GET_CODE (x_addr) == AND || GET_CODE (mem_addr) == AND
+ || varies (x_addr) == varies (mem_addr))
+ return 1;
+
+ /* One memory reference is to a constant address, one is not.
+ One is to a structure, the other is not.
+
+ If either memory reference is a variable structure the other is a
+ fixed scalar and there is no aliasing. */
+
+ /* Disabled by default for egcs 1.1.x as alias analysis isn't good
+ enough yet to discover all cases where this doesn't apply. */
+ if (flag_structure_noalias)
+ {
+ if ((MEM_IN_STRUCT_P (mem) && varies (mem_addr))
+ || (MEM_IN_STRUCT_P (x) && varies (x_addr)))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Anti dependence: X is written after read in MEM takes place. */
+
+int
+anti_dependence (mem, x)
+ rtx mem;
+ rtx x;
+{
+ rtx x_addr, mem_addr;
+
+ if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
+ return 1;
+
+ /* If MEM is an unchanging read, then it can't possibly conflict with
+ the store to X, because there is at most one store to MEM, and it must
+ have occurred somewhere before MEM. */
+ if (RTX_UNCHANGING_P (mem))
+ return 0;
+
+ if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0)))
+ return 0;
+
+ x = canon_rtx (x);
+ mem = canon_rtx (mem);
+
+ if (DIFFERENT_ALIAS_SETS_P (x, mem))
+ return 0;
+
+ x_addr = XEXP (x, 0);
+ mem_addr = XEXP (mem, 0);
+
+ return (memrefs_conflict_p (SIZE_FOR_MODE (mem), mem_addr,
+ SIZE_FOR_MODE (x), x_addr, 0)
+ && ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
+ && GET_MODE (mem) != QImode
+ && GET_CODE (mem_addr) != AND
+ && ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
+ && ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
+ && GET_MODE (x) != QImode
+ && GET_CODE (x_addr) != AND
+ && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem)));
+}
+
+/* Output dependence: X is written after store in MEM takes place. */
+
+int
+output_dependence (mem, x)
+ register rtx mem;
+ register rtx x;
+{
+ if (MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
+ return 1;
+
+ if (! base_alias_check (XEXP (x, 0), XEXP (mem, 0)))
+ return 0;
+
+ x = canon_rtx (x);
+ mem = canon_rtx (mem);
+
+ if (DIFFERENT_ALIAS_SETS_P (x, mem))
+ return 0;
+
+ return (memrefs_conflict_p (SIZE_FOR_MODE (mem), XEXP (mem, 0),
+ SIZE_FOR_MODE (x), XEXP (x, 0), 0)
+ && ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
+ && GET_MODE (mem) != QImode
+ && GET_CODE (XEXP (mem, 0)) != AND
+ && ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
+ && ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
+ && GET_MODE (x) != QImode
+ && GET_CODE (XEXP (x, 0)) != AND
+ && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem)));
+}
+
+
+static HARD_REG_SET argument_registers;
+
+void
+init_alias_once ()
+{
+ register int i;
+
+#ifndef OUTGOING_REGNO
+#define OUTGOING_REGNO(N) N
+#endif
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ /* Check whether this register can hold an incoming pointer
+ argument. FUNCTION_ARG_REGNO_P tests outgoing register
+ numbers, so translate if necessary due to register windows. */
+ if (FUNCTION_ARG_REGNO_P (OUTGOING_REGNO (i))
+ && HARD_REGNO_MODE_OK (i, Pmode))
+ SET_HARD_REG_BIT (argument_registers, i);
+}
+
+void
+init_alias_analysis ()
+{
+ int maxreg = max_reg_num ();
+ int changed, pass;
+ register int i;
+ register rtx insn;
+
+ reg_known_value_size = maxreg;
+
+ reg_known_value
+ = (rtx *) oballoc ((maxreg - FIRST_PSEUDO_REGISTER) * sizeof (rtx))
+ - FIRST_PSEUDO_REGISTER;
+ reg_known_equiv_p =
+ oballoc (maxreg - FIRST_PSEUDO_REGISTER) - FIRST_PSEUDO_REGISTER;
+ bzero ((char *) (reg_known_value + FIRST_PSEUDO_REGISTER),
+ (maxreg-FIRST_PSEUDO_REGISTER) * sizeof (rtx));
+ bzero (reg_known_equiv_p + FIRST_PSEUDO_REGISTER,
+ (maxreg - FIRST_PSEUDO_REGISTER) * sizeof (char));
+
+ /* Overallocate reg_base_value to allow some growth during loop
+ optimization. Loop unrolling can create a large number of
+ registers. */
+ reg_base_value_size = maxreg * 2;
+ reg_base_value = (rtx *)oballoc (reg_base_value_size * sizeof (rtx));
+ new_reg_base_value = (rtx *)alloca (reg_base_value_size * sizeof (rtx));
+ reg_seen = (char *)alloca (reg_base_value_size);
+ bzero ((char *) reg_base_value, reg_base_value_size * sizeof (rtx));
+ if (! reload_completed && flag_unroll_loops)
+ {
+ alias_invariant = (rtx *)xrealloc (alias_invariant,
+ reg_base_value_size * sizeof (rtx));
+ bzero ((char *)alias_invariant, reg_base_value_size * sizeof (rtx));
+ }
+
+
+ /* The basic idea is that each pass through this loop will use the
+ "constant" information from the previous pass to propagate alias
+ information through another level of assignments.
+
+ This could get expensive if the assignment chains are long. Maybe
+ we should throttle the number of iterations, possibly based on
+ the optimization level or flag_expensive_optimizations.
+
+ We could propagate more information in the first pass by making use
+ of REG_N_SETS to determine immediately that the alias information
+ for a pseudo is "constant".
+
+ A program with an uninitialized variable can cause an infinite loop
+ here. Instead of doing a full dataflow analysis to detect such problems
+ we just cap the number of iterations for the loop.
+
+ The state of the arrays for the set chain in question does not matter
+ since the program has undefined behavior. */
+
+ pass = 0;
+ do
+ {
+ /* Assume nothing will change this iteration of the loop. */
+ changed = 0;
+
+ /* We want to assign the same IDs each iteration of this loop, so
+ start counting from zero each iteration of the loop. */
+ unique_id = 0;
+
+ /* We're at the start of the funtion each iteration through the
+ loop, so we're copying arguments. */
+ copying_arguments = 1;
+
+ /* Wipe the potential alias information clean for this pass. */
+ bzero ((char *) new_reg_base_value, reg_base_value_size * sizeof (rtx));
+
+ /* Wipe the reg_seen array clean. */
+ bzero ((char *) reg_seen, reg_base_value_size);
+
+ /* Mark all hard registers which may contain an address.
+ The stack, frame and argument pointers may contain an address.
+ An argument register which can hold a Pmode value may contain
+ an address even if it is not in BASE_REGS.
+
+ The address expression is VOIDmode for an argument and
+ Pmode for other registers. */
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (argument_registers, i))
+ new_reg_base_value[i] = gen_rtx_ADDRESS (VOIDmode,
+ gen_rtx_REG (Pmode, i));
+
+ new_reg_base_value[STACK_POINTER_REGNUM]
+ = gen_rtx_ADDRESS (Pmode, stack_pointer_rtx);
+ new_reg_base_value[ARG_POINTER_REGNUM]
+ = gen_rtx_ADDRESS (Pmode, arg_pointer_rtx);
+ new_reg_base_value[FRAME_POINTER_REGNUM]
+ = gen_rtx_ADDRESS (Pmode, frame_pointer_rtx);
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ new_reg_base_value[HARD_FRAME_POINTER_REGNUM]
+ = gen_rtx_ADDRESS (Pmode, hard_frame_pointer_rtx);
+#endif
+ if (struct_value_incoming_rtx
+ && GET_CODE (struct_value_incoming_rtx) == REG)
+ new_reg_base_value[REGNO (struct_value_incoming_rtx)]
+ = gen_rtx_ADDRESS (Pmode, struct_value_incoming_rtx);
+
+ if (static_chain_rtx
+ && GET_CODE (static_chain_rtx) == REG)
+ new_reg_base_value[REGNO (static_chain_rtx)]
+ = gen_rtx_ADDRESS (Pmode, static_chain_rtx);
+
+ /* Walk the insns adding values to the new_reg_base_value array. */
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ rtx note, set;
+ /* If this insn has a noalias note, process it, Otherwise,
+ scan for sets. A simple set will have no side effects
+ which could change the base value of any other register. */
+
+ if (GET_CODE (PATTERN (insn)) == SET
+ && (find_reg_note (insn, REG_NOALIAS, NULL_RTX)))
+ record_set (SET_DEST (PATTERN (insn)), NULL_RTX);
+ else
+ note_stores (PATTERN (insn), record_set);
+
+ set = single_set (insn);
+
+ if (set != 0
+ && GET_CODE (SET_DEST (set)) == REG
+ && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
+ && (((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
+ && REG_N_SETS (REGNO (SET_DEST (set))) == 1)
+ || (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
+ && GET_CODE (XEXP (note, 0)) != EXPR_LIST
+ && ! reg_overlap_mentioned_p (SET_DEST (set), XEXP (note, 0)))
+ {
+ int regno = REGNO (SET_DEST (set));
+ reg_known_value[regno] = XEXP (note, 0);
+ reg_known_equiv_p[regno] = REG_NOTE_KIND (note) == REG_EQUIV;
+ }
+ }
+ else if (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
+ copying_arguments = 0;
+ }
+
+ /* Now propagate values from new_reg_base_value to reg_base_value. */
+ for (i = 0; i < reg_base_value_size; i++)
+ {
+ if (new_reg_base_value[i]
+ && new_reg_base_value[i] != reg_base_value[i]
+ && ! rtx_equal_p (new_reg_base_value[i], reg_base_value[i]))
+ {
+ reg_base_value[i] = new_reg_base_value[i];
+ changed = 1;
+ }
+ }
+ }
+ while (changed && ++pass < MAX_ALIAS_LOOP_PASSES);
+
+ /* Fill in the remaining entries. */
+ for (i = FIRST_PSEUDO_REGISTER; i < maxreg; i++)
+ if (reg_known_value[i] == 0)
+ reg_known_value[i] = regno_reg_rtx[i];
+
+ /* Simplify the reg_base_value array so that no register refers to
+ another register, except to special registers indirectly through
+ ADDRESS expressions.
+
+ In theory this loop can take as long as O(registers^2), but unless
+ there are very long dependency chains it will run in close to linear
+ time.
+
+ This loop may not be needed any longer now that the main loop does
+ a better job at propagating alias information. */
+ pass = 0;
+ do
+ {
+ changed = 0;
+ pass++;
+ for (i = 0; i < reg_base_value_size; i++)
+ {
+ rtx base = reg_base_value[i];
+ if (base && GET_CODE (base) == REG)
+ {
+ int base_regno = REGNO (base);
+ if (base_regno == i) /* register set from itself */
+ reg_base_value[i] = 0;
+ else
+ reg_base_value[i] = reg_base_value[base_regno];
+ changed = 1;
+ }
+ }
+ }
+ while (changed && pass < MAX_ALIAS_LOOP_PASSES);
+
+ new_reg_base_value = 0;
+ reg_seen = 0;
+}
+
+void
+end_alias_analysis ()
+{
+ reg_known_value = 0;
+ reg_base_value = 0;
+ reg_base_value_size = 0;
+ if (alias_invariant)
+ {
+ free ((char *)alias_invariant);
+ alias_invariant = 0;
+ }
+}
diff --git a/contrib/gcc/alloca.c b/contrib/gcc/alloca.c
index 7020f32..8f98b73 100644
--- a/contrib/gcc/alloca.c
+++ b/contrib/gcc/alloca.c
@@ -25,6 +25,13 @@
#include <config.h>
#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
#ifdef emacs
#include "blockinput.h"
#endif
@@ -66,7 +73,9 @@ typedef void *pointer;
typedef char *pointer;
#endif
+#ifndef NULL
#define NULL 0
+#endif
/* Different portions of Emacs need to call different versions of
malloc. The Emacs executable needs alloca to call xmalloc, because
@@ -171,7 +180,7 @@ alloca (size)
#endif
/* Reclaim garbage, defined as all alloca'd storage that
- was allocated from deeper in the stack than currently. */
+ was allocated from deeper in the stack than currently. */
{
register header *hp; /* Traverses linked list. */
@@ -209,6 +218,9 @@ alloca (size)
register pointer new = malloc (sizeof (header) + size);
/* Address of header. */
+ if (new == 0)
+ abort();
+
((header *) new)->h.next = last_alloca_header;
((header *) new)->h.deep = depth;
@@ -338,7 +350,7 @@ struct stk_trailer
#ifdef CRAY2
/* Determine a "stack measure" for an arbitrary ADDRESS.
- I doubt that "lint" will like this much. */
+ I doubt that "lint" will like this much. */
static long
i00afunc (long *address)
diff --git a/contrib/gcc/basic-block.h b/contrib/gcc/basic-block.h
index 3755388..552f74a 100644
--- a/contrib/gcc/basic-block.h
+++ b/contrib/gcc/basic-block.h
@@ -1,5 +1,5 @@
/* Define control and data flow tables, and regsets.
- Copyright (C) 1987 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,26 +19,82 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* Number of bits in each actual element of a regset. */
+#include "bitmap.h"
-#define REGSET_ELT_BITS HOST_BITS_PER_WIDE_INT
+typedef bitmap regset; /* Head of register set linked list. */
-/* Type to use for a regset element. Note that lots of code assumes
- that the initial part of a regset that contains information on the
- hard registers is the same format as a HARD_REG_SET. */
+/* Clear a register set by freeing up the linked list. */
+#define CLEAR_REG_SET(HEAD) bitmap_clear (HEAD)
-#define REGSET_ELT_TYPE unsigned HOST_WIDE_INT
+/* Copy a register set to another register set. */
+#define COPY_REG_SET(TO, FROM) bitmap_copy (TO, FROM)
-/* Define the type for a pointer to a set with a bit for each
- (hard or pseudo) register. */
+/* `and' a register set with a second register set. */
+#define AND_REG_SET(TO, FROM) bitmap_operation (TO, TO, FROM, BITMAP_AND)
-typedef REGSET_ELT_TYPE *regset;
+/* `and' the complement of a register set with a register set. */
+#define AND_COMPL_REG_SET(TO, FROM) \
+ bitmap_operation (TO, TO, FROM, BITMAP_AND_COMPL)
-/* Size of a regset for the current function,
- in (1) bytes and (2) elements. */
+/* Inclusive or a register set with a second register set. */
+#define IOR_REG_SET(TO, FROM) bitmap_operation (TO, TO, FROM, BITMAP_IOR)
-extern int regset_bytes;
-extern int regset_size;
+/* Or into TO the register set FROM1 `and'ed with the complement of FROM2. */
+#define IOR_AND_COMPL_REG_SET(TO, FROM1, FROM2) \
+ bitmap_ior_and_compl (TO, FROM1, FROM2)
+
+/* Clear a single register in a register set. */
+#define CLEAR_REGNO_REG_SET(HEAD, REG) bitmap_clear_bit (HEAD, REG)
+
+/* Set a single register in a register set. */
+#define SET_REGNO_REG_SET(HEAD, REG) bitmap_set_bit (HEAD, REG)
+
+/* Return true if a register is set in a register set. */
+#define REGNO_REG_SET_P(TO, REG) bitmap_bit_p (TO, REG)
+
+/* Copy the hard registers in a register set to the hard register set. */
+#define REG_SET_TO_HARD_REG_SET(TO, FROM) \
+do { \
+ int i_; \
+ CLEAR_HARD_REG_SET (TO); \
+ for (i_ = 0; i_ < FIRST_PSEUDO_REGISTER; i_++) \
+ if (REGNO_REG_SET_P (FROM, i_)) \
+ SET_HARD_REG_BIT (TO, i_); \
+} while (0)
+
+/* Loop over all registers in REGSET, starting with MIN, setting REGNUM to the
+ register number and executing CODE for all registers that are set. */
+#define EXECUTE_IF_SET_IN_REG_SET(REGSET, MIN, REGNUM, CODE) \
+ EXECUTE_IF_SET_IN_BITMAP (REGSET, MIN, REGNUM, CODE)
+
+/* Loop over all registers in REGSET1 and REGSET2, starting with MIN, setting
+ REGNUM to the register number and executing CODE for all registers that are
+ set in the first regset and not set in the second. */
+#define EXECUTE_IF_AND_COMPL_IN_REG_SET(REGSET1, REGSET2, MIN, REGNUM, CODE) \
+ EXECUTE_IF_AND_COMPL_IN_BITMAP (REGSET1, REGSET2, MIN, REGNUM, CODE)
+
+/* Loop over all registers in REGSET1 and REGSET2, starting with MIN, setting
+ REGNUM to the register number and executing CODE for all registers that are
+ set in both regsets. */
+#define EXECUTE_IF_AND_IN_REG_SET(REGSET1, REGSET2, MIN, REGNUM, CODE) \
+ EXECUTE_IF_AND_IN_BITMAP (REGSET1, REGSET2, MIN, REGNUM, CODE)
+
+/* Allocate a register set with oballoc. */
+#define OBSTACK_ALLOC_REG_SET(OBSTACK) BITMAP_OBSTACK_ALLOC (OBSTACK)
+
+/* Allocate a register set with alloca. */
+#define ALLOCA_REG_SET() BITMAP_ALLOCA ()
+
+/* Do any cleanup needed on a regset when it is no longer used. */
+#define FREE_REG_SET(REGSET) BITMAP_FREE(REGSET)
+
+/* Do any one-time initializations needed for regsets. */
+#define INIT_ONCE_REG_SET() BITMAP_INIT_ONCE ()
+
+/* Grow any tables needed when the number of registers is calculated
+ or extended. For the linked list allocation, nothing needs to
+ be done, other than zero the statistics on the first allocation. */
+#define MAX_REGNO_REG_SET(NUM_REGS, NEW_P, RENUMBER_P)
/* Number of basic blocks in the current function. */
@@ -52,11 +108,20 @@ extern rtx *basic_block_head;
extern rtx *basic_block_end;
+/* Index by basic block number, determine whether the block can be reached
+ through a computed jump. */
+
+extern char *basic_block_computed_jump_target;
+
/* Index by basic block number, get address of regset
describing the registers live at the start of that block. */
extern regset *basic_block_live_at_start;
+/* What registers are live at the setjmp call. */
+
+extern regset regs_live_at_setjmp;
+
/* Indexed by n, gives number of basic block that (REG n) is used in.
If the value is REG_BLOCK_GLOBAL (-2),
it means (REG n) is used in more than one basic block.
@@ -66,4 +131,136 @@ extern regset *basic_block_live_at_start;
#define REG_BLOCK_UNKNOWN -1
#define REG_BLOCK_GLOBAL -2
-extern int *reg_basic_block;
+
+#define REG_BASIC_BLOCK(N) (VARRAY_REG (reg_n_info, N)->basic_block)
+
+/* List of integers.
+ These are used for storing things like predecessors, etc.
+
+ This scheme isn't very space efficient, especially on 64 bit machines.
+ The interface is designed so that the implementation can be replaced with
+ something more efficient if desirable. */
+
+typedef struct int_list {
+ struct int_list *next;
+ int val;
+} int_list;
+
+typedef int_list *int_list_ptr;
+
+/* Integer list elements are allocated in blocks to reduce the frequency
+ of calls to malloc and to reduce the associated space overhead. */
+
+typedef struct int_list_block {
+ struct int_list_block *next;
+ int nodes_left;
+#define INT_LIST_NODES_IN_BLK 500
+ struct int_list nodes[INT_LIST_NODES_IN_BLK];
+} int_list_block;
+
+/* Given a pointer to the list, return pointer to first element. */
+#define INT_LIST_FIRST(il) (il)
+
+/* Given a pointer to a list element, return pointer to next element. */
+#define INT_LIST_NEXT(p) ((p)->next)
+
+/* Return non-zero if P points to the end of the list. */
+#define INT_LIST_END(p) ((p) == NULL)
+
+/* Return element pointed to by P. */
+#define INT_LIST_VAL(p) ((p)->val)
+
+#define INT_LIST_SET_VAL(p, new_val) ((p)->val = (new_val))
+
+extern void free_int_list PROTO ((int_list_block **));
+
+/* Stuff for recording basic block info. */
+
+#define BLOCK_HEAD(B) basic_block_head[(B)]
+#define BLOCK_END(B) basic_block_end[(B)]
+
+/* Special block numbers [markers] for entry and exit. */
+#define ENTRY_BLOCK (-1)
+#define EXIT_BLOCK (-2)
+
+/* from flow.c */
+extern void free_regset_vector PROTO ((regset *, int nelts));
+extern int *uid_block_number;
+#define BLOCK_NUM(INSN) uid_block_number[INSN_UID (INSN)]
+
+extern void compute_preds_succs PROTO ((int_list_ptr *, int_list_ptr *,
+ int *, int *));
+extern void dump_bb_data PROTO ((FILE *, int_list_ptr *, int_list_ptr *));
+extern void free_bb_mem PROTO ((void));
+extern void free_basic_block_vars PROTO ((int));
+
+
+/* Simple bitmaps.
+ It's not clear yet whether using bitmap.[ch] will be a win.
+ It should be straightforward to convert so for now we keep things simple
+ while more important issues are dealt with. */
+
+#define SBITMAP_ELT_BITS HOST_BITS_PER_WIDE_INT
+#define SBITMAP_ELT_TYPE unsigned HOST_WIDE_INT
+
+typedef struct simple_bitmap_def {
+ /* Number of bits. */
+ int n_bits;
+ /* Size in elements. */
+ int size;
+ /* Size in bytes. */
+ int bytes;
+ /* The elements. */
+ SBITMAP_ELT_TYPE elms[1];
+} *sbitmap;
+
+typedef SBITMAP_ELT_TYPE *sbitmap_ptr;
+
+/* Return the set size needed for N elements. */
+#define SBITMAP_SET_SIZE(n) (((n) + SBITMAP_ELT_BITS - 1) / SBITMAP_ELT_BITS)
+
+/* set bit number bitno in the bitmap */
+#define SET_BIT(bitmap, bitno) \
+do { \
+ (bitmap)->elms [(bitno) / SBITMAP_ELT_BITS] |= (SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS; \
+} while (0)
+
+/* test if bit number bitno in the bitmap is set */
+#define TEST_BIT(bitmap, bitno) \
+((bitmap)->elms [(bitno) / SBITMAP_ELT_BITS] & ((SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS))
+
+/* reset bit number bitno in the bitmap */
+#define RESET_BIT(bitmap, bitno) \
+do { \
+ (bitmap)->elms [(bitno) / SBITMAP_ELT_BITS] &= ~((SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS); \
+} while (0)
+
+extern void dump_sbitmap PROTO ((FILE *, sbitmap));
+extern void dump_sbitmap_vector PROTO ((FILE *, char *, char *,
+ sbitmap *, int));
+extern sbitmap sbitmap_alloc PROTO ((int));
+extern sbitmap *sbitmap_vector_alloc PROTO ((int, int));
+extern void sbitmap_copy PROTO ((sbitmap, sbitmap));
+extern void sbitmap_zero PROTO ((sbitmap));
+extern void sbitmap_ones PROTO ((sbitmap));
+extern void sbitmap_vector_zero PROTO ((sbitmap *, int));
+extern void sbitmap_vector_ones PROTO ((sbitmap *, int));
+extern int sbitmap_union_of_diff PROTO ((sbitmap, sbitmap, sbitmap, sbitmap));
+extern void sbitmap_difference PROTO ((sbitmap, sbitmap, sbitmap));
+extern void sbitmap_not PROTO ((sbitmap, sbitmap));
+extern int sbitmap_a_or_b_and_c PROTO ((sbitmap, sbitmap, sbitmap, sbitmap));
+extern int sbitmap_a_and_b_or_c PROTO ((sbitmap, sbitmap, sbitmap, sbitmap));
+extern int sbitmap_a_and_b PROTO ((sbitmap, sbitmap, sbitmap));
+extern int sbitmap_a_or_b PROTO ((sbitmap, sbitmap, sbitmap));
+extern void sbitmap_intersect_of_predsucc PROTO ((sbitmap, sbitmap *,
+ int, int_list_ptr *));
+extern void sbitmap_intersect_of_predecessors PROTO ((sbitmap, sbitmap *, int,
+ int_list_ptr *));
+extern void sbitmap_intersect_of_successors PROTO ((sbitmap, sbitmap *, int,
+ int_list_ptr *));
+extern void sbitmap_union_of_predecessors PROTO ((sbitmap, sbitmap *, int,
+ int_list_ptr *));
+extern void sbitmap_union_of_successors PROTO ((sbitmap, sbitmap *, int,
+ int_list_ptr *));
+extern void compute_dominators PROTO ((sbitmap *, sbitmap *,
+ int_list_ptr *, int_list_ptr *));
diff --git a/contrib/gcc/bitmap.c b/contrib/gcc/bitmap.c
new file mode 100644
index 0000000..a5aa2e7
--- /dev/null
+++ b/contrib/gcc/bitmap.c
@@ -0,0 +1,642 @@
+/* Functions to support general ended bitmaps.
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "flags.h"
+#include "obstack.h"
+#include "regs.h"
+#include "basic-block.h"
+
+/* Obstack to allocate bitmap elements from. */
+static struct obstack bitmap_obstack;
+static int bitmap_obstack_init = FALSE;
+
+
+#ifndef INLINE
+#ifndef __GNUC__
+#define INLINE
+#else
+#define INLINE __inline__
+#endif
+#endif
+
+/* Global data */
+bitmap_element bitmap_zero; /* An element of all zero bits. */
+bitmap_element *bitmap_free; /* Freelist of bitmap elements. */
+
+static void bitmap_element_free PROTO((bitmap, bitmap_element *));
+static bitmap_element *bitmap_element_allocate PROTO((void));
+static int bitmap_element_zerop PROTO((bitmap_element *));
+static void bitmap_element_link PROTO((bitmap, bitmap_element *));
+static bitmap_element *bitmap_find_bit PROTO((bitmap, unsigned int));
+
+/* Free a bitmap element */
+
+static INLINE void
+bitmap_element_free (head, elt)
+ bitmap head;
+ bitmap_element *elt;
+{
+ bitmap_element *next = elt->next;
+ bitmap_element *prev = elt->prev;
+
+ if (prev)
+ prev->next = next;
+
+ if (next)
+ next->prev = prev;
+
+ if (head->first == elt)
+ head->first = next;
+
+ /* Since the first thing we try is to insert before current,
+ make current the next entry in preference to the previous. */
+ if (head->current == elt)
+ head->current = next != 0 ? next : prev;
+
+ elt->next = bitmap_free;
+ bitmap_free = elt;
+}
+
+/* Allocate a bitmap element. The bits are cleared, but nothing else is. */
+
+static INLINE bitmap_element *
+bitmap_element_allocate ()
+{
+ bitmap_element *element;
+#if BITMAP_ELEMENT_WORDS != 2
+ int i;
+#endif
+
+ if (bitmap_free != 0)
+ {
+ element = bitmap_free;
+ bitmap_free = element->next;
+ }
+ else
+ {
+ /* We can't use gcc_obstack_init to initialize the obstack since
+ print-rtl.c now calls bitmap functions, and bitmap is linked
+ into the gen* functions. */
+ if (!bitmap_obstack_init)
+ {
+ bitmap_obstack_init = TRUE;
+
+ /* Let particular systems override the size of a chunk. */
+#ifndef OBSTACK_CHUNK_SIZE
+#define OBSTACK_CHUNK_SIZE 0
+#endif
+ /* Let them override the alloc and free routines too. */
+#ifndef OBSTACK_CHUNK_ALLOC
+#define OBSTACK_CHUNK_ALLOC xmalloc
+#endif
+#ifndef OBSTACK_CHUNK_FREE
+#define OBSTACK_CHUNK_FREE free
+#endif
+
+#if !defined(__GNUC__) || (__GNUC__ < 2)
+#define __alignof__(type) 0
+#endif
+
+ obstack_specify_allocation (&bitmap_obstack, OBSTACK_CHUNK_SIZE,
+ __alignof__ (bitmap_element),
+ (void *(*) ()) OBSTACK_CHUNK_ALLOC,
+ (void (*) ()) OBSTACK_CHUNK_FREE);
+ }
+
+ element = (bitmap_element *) obstack_alloc (&bitmap_obstack,
+ sizeof (bitmap_element));
+ }
+
+#if BITMAP_ELEMENT_WORDS == 2
+ element->bits[0] = element->bits[1] = 0;
+#else
+ for (i = 0; i < BITMAP_ELEMENT_WORDS; i++)
+ element->bits[i] = 0;
+#endif
+
+ return element;
+}
+
+/* Return nonzero if all bits in an element are zero. */
+
+static INLINE int
+bitmap_element_zerop (element)
+ bitmap_element *element;
+{
+#if BITMAP_ELEMENT_WORDS == 2
+ return (element->bits[0] | element->bits[1]) == 0;
+#else
+ int i;
+
+ for (i = 0; i < BITMAP_ELEMENT_WORDS; i++)
+ if (element->bits[i] != 0)
+ return 0;
+
+ return 1;
+#endif
+}
+
+/* Link the bitmap element into the current bitmap linked list. */
+
+static INLINE void
+bitmap_element_link (head, element)
+ bitmap head;
+ bitmap_element *element;
+{
+ unsigned int indx = element->indx;
+ bitmap_element *ptr;
+
+ /* If this is the first and only element, set it in. */
+ if (head->first == 0)
+ {
+ element->next = element->prev = 0;
+ head->first = element;
+ }
+
+ /* If this index is less than that of the current element, it goes someplace
+ before the current element. */
+ else if (indx < head->indx)
+ {
+ for (ptr = head->current;
+ ptr->prev != 0 && ptr->prev->indx > indx;
+ ptr = ptr->prev)
+ ;
+
+ if (ptr->prev)
+ ptr->prev->next = element;
+ else
+ head->first = element;
+
+ element->prev = ptr->prev;
+ element->next = ptr;
+ ptr->prev = element;
+ }
+
+ /* Otherwise, it must go someplace after the current element. */
+ else
+ {
+ for (ptr = head->current;
+ ptr->next != 0 && ptr->next->indx < indx;
+ ptr = ptr->next)
+ ;
+
+ if (ptr->next)
+ ptr->next->prev = element;
+
+ element->next = ptr->next;
+ element->prev = ptr;
+ ptr->next = element;
+ }
+
+ /* Set up so this is the first element searched. */
+ head->current = element;
+ head->indx = indx;
+}
+
+/* Clear a bitmap by freeing the linked list. */
+
+INLINE void
+bitmap_clear (head)
+ bitmap head;
+{
+ bitmap_element *element, *next;
+
+ for (element = head->first; element != 0; element = next)
+ {
+ next = element->next;
+ element->next = bitmap_free;
+ bitmap_free = element;
+ }
+
+ head->first = head->current = 0;
+}
+
+/* Copy a bitmap to another bitmap */
+
+void
+bitmap_copy (to, from)
+ bitmap to;
+ bitmap from;
+{
+ bitmap_element *from_ptr, *to_ptr = 0;
+#if BITMAP_ELEMENT_WORDS != 2
+ int i;
+#endif
+
+ bitmap_clear (to);
+
+ /* Copy elements in forward direction one at a time */
+ for (from_ptr = from->first; from_ptr; from_ptr = from_ptr->next)
+ {
+ bitmap_element *to_elt = bitmap_element_allocate ();
+
+ to_elt->indx = from_ptr->indx;
+
+#if BITMAP_ELEMENT_WORDS == 2
+ to_elt->bits[0] = from_ptr->bits[0];
+ to_elt->bits[1] = from_ptr->bits[1];
+#else
+ for (i = 0; i < BITMAP_ELEMENT_WORDS; i++)
+ to_elt->bits[i] = from_ptr->bits[i];
+#endif
+
+ /* Here we have a special case of bitmap_element_link, for the case
+ where we know the links are being entered in sequence. */
+ if (to_ptr == 0)
+ {
+ to->first = to->current = to_elt;
+ to->indx = from_ptr->indx;
+ to_elt->next = to_elt->prev = 0;
+ }
+ else
+ {
+ to_elt->prev = to_ptr;
+ to_elt->next = 0;
+ to_ptr->next = to_elt;
+ }
+
+ to_ptr = to_elt;
+ }
+}
+
+/* Find a bitmap element that would hold a bitmap's bit.
+ Update the `current' field even if we can't find an element that
+ would hold the bitmap's bit to make eventual allocation
+ faster. */
+
+static INLINE bitmap_element *
+bitmap_find_bit (head, bit)
+ bitmap head;
+ unsigned int bit;
+{
+ bitmap_element *element;
+ unsigned HOST_WIDE_INT indx = bit / BITMAP_ELEMENT_ALL_BITS;
+
+ if (head->current == 0)
+ return 0;
+
+ if (head->indx > indx)
+ for (element = head->current;
+ element->prev != 0 && element->indx > indx;
+ element = element->prev)
+ ;
+
+ else
+ for (element = head->current;
+ element->next != 0 && element->indx < indx;
+ element = element->next)
+ ;
+
+ /* `element' is the nearest to the one we want. If it's not the one we
+ want, the one we want doesn't exist. */
+ head->current = element;
+ head->indx = element->indx;
+ if (element != 0 && element->indx != indx)
+ element = 0;
+
+ return element;
+}
+
+/* Clear a single bit in a bitmap. */
+
+void
+bitmap_clear_bit (head, bit)
+ bitmap head;
+ int bit;
+{
+ bitmap_element *ptr = bitmap_find_bit (head, bit);
+
+ if (ptr != 0)
+ {
+ unsigned bit_num = bit % (unsigned) HOST_BITS_PER_WIDE_INT;
+ unsigned word_num = ((bit / (unsigned) HOST_BITS_PER_WIDE_INT)
+ % BITMAP_ELEMENT_WORDS);
+ ptr->bits[word_num] &= ~ (((unsigned HOST_WIDE_INT) 1) << bit_num);
+
+ /* If we cleared the entire word, free up the element */
+ if (bitmap_element_zerop (ptr))
+ bitmap_element_free (head, ptr);
+ }
+}
+
+
+/* Set a single bit in a bitmap. */
+
+void
+bitmap_set_bit (head, bit)
+ bitmap head;
+ int bit;
+{
+ bitmap_element *ptr = bitmap_find_bit (head, bit);
+ unsigned word_num
+ = ((bit / (unsigned) HOST_BITS_PER_WIDE_INT) % BITMAP_ELEMENT_WORDS);
+ unsigned bit_num = bit % (unsigned) HOST_BITS_PER_WIDE_INT;
+ unsigned HOST_WIDE_INT bit_val = ((unsigned HOST_WIDE_INT) 1) << bit_num;
+
+ if (ptr == 0)
+ {
+ ptr = bitmap_element_allocate ();
+ ptr->indx = bit / BITMAP_ELEMENT_ALL_BITS;
+ ptr->bits[word_num] = bit_val;
+ bitmap_element_link (head, ptr);
+ }
+ else
+ ptr->bits[word_num] |= bit_val;
+}
+
+/* Return whether a bit is set within a bitmap. */
+
+int
+bitmap_bit_p (head, bit)
+ bitmap head;
+ int bit;
+{
+ bitmap_element *ptr;
+ unsigned bit_num;
+ unsigned word_num;
+
+ ptr = bitmap_find_bit (head, bit);
+ if (ptr == 0)
+ return 0;
+
+ bit_num = bit % (unsigned) HOST_BITS_PER_WIDE_INT;
+ word_num
+ = ((bit / (unsigned) HOST_BITS_PER_WIDE_INT) % BITMAP_ELEMENT_WORDS);
+
+ return
+ (ptr->bits[word_num] & (((unsigned HOST_WIDE_INT) 1) << bit_num)) != 0;
+}
+
+/* Store in bitmap TO the result of combining bitmap FROM1 and
+ FROM2 using a specific bit manipulation. */
+
+void
+bitmap_operation (to, from1, from2, operation)
+ bitmap to;
+ bitmap from1;
+ bitmap from2;
+ enum bitmap_bits operation;
+{
+ bitmap_element *delete_list = 0;
+ bitmap_element *from1_ptr = from1->first;
+ bitmap_element *from2_ptr = from2->first;
+ unsigned int indx1
+ = (from1_ptr) ? from1_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0;
+ unsigned int indx2
+ = (from2_ptr) ? from2_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0;
+ bitmap_element *to_ptr = 0;
+ bitmap_element *from1_tmp;
+ bitmap_element *from2_tmp;
+ unsigned int indx;
+#if BITMAP_ELEMENT_WORDS != 2
+ int i;
+#endif
+
+ /* To simplify things, always create a new list. If the old list was one
+ of the inputs, free it later. Otherwise, free it now. */
+ if (to == from1 || to == from2)
+ {
+ delete_list = to->first;
+ to->first = to->current = 0;
+ }
+ else
+ bitmap_clear (to);
+
+ while (from1_ptr != 0 || from2_ptr != 0)
+ {
+ /* Figure out whether we need to substitute zero elements for
+ missing links. */
+ if (indx1 == indx2)
+ {
+ indx = indx1;
+ from1_tmp = from1_ptr;
+ from2_tmp = from2_ptr;
+ from1_ptr = from1_ptr->next;
+ indx1 = (from1_ptr) ? from1_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0;
+ from2_ptr = from2_ptr->next;
+ indx2 = (from2_ptr) ? from2_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0;
+ }
+ else if (indx1 < indx2)
+ {
+ indx = indx1;
+ from1_tmp = from1_ptr;
+ from2_tmp = &bitmap_zero;
+ from1_ptr = from1_ptr->next;
+ indx1 = (from1_ptr) ? from1_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0;
+ }
+ else
+ {
+ indx = indx2;
+ from1_tmp = &bitmap_zero;
+ from2_tmp = from2_ptr;
+ from2_ptr = from2_ptr->next;
+ indx2 = (from2_ptr) ? from2_ptr->indx : ~ (unsigned HOST_WIDE_INT) 0;
+ }
+
+ if (to_ptr == 0)
+ to_ptr = bitmap_element_allocate ();
+
+ /* Do the operation, and if any bits are set, link it into the
+ linked list. */
+ switch (operation)
+ {
+ default:
+ abort ();
+
+ case BITMAP_AND:
+#if BITMAP_ELEMENT_WORDS == 2
+ to_ptr->bits[0] = from1_tmp->bits[0] & from2_tmp->bits[0];
+ to_ptr->bits[1] = from1_tmp->bits[1] & from2_tmp->bits[1];
+#else
+ for (i = BITMAP_ELEMENT_WORDS - 1; i >= 0; i--)
+ to_ptr->bits[i] = from1_tmp->bits[i] & from2_tmp->bits[i];
+#endif
+ break;
+
+ case BITMAP_AND_COMPL:
+#if BITMAP_ELEMENT_WORDS == 2
+ to_ptr->bits[0] = from1_tmp->bits[0] & ~ from2_tmp->bits[0];
+ to_ptr->bits[1] = from1_tmp->bits[1] & ~ from2_tmp->bits[1];
+#else
+ for (i = BITMAP_ELEMENT_WORDS - 1; i >= 0; i--)
+ to_ptr->bits[i] = from1_tmp->bits[i] & ~ from2_tmp->bits[i];
+#endif
+ break;
+
+ case BITMAP_IOR:
+#if BITMAP_ELEMENT_WORDS == 2
+ to_ptr->bits[0] = from1_tmp->bits[0] | from2_tmp->bits[0];
+ to_ptr->bits[1] = from1_tmp->bits[1] | from2_tmp->bits[1];
+#else
+ for (i = BITMAP_ELEMENT_WORDS - 1; i >= 0; i--)
+ to_ptr->bits[i] = from1_tmp->bits[i] | from2_tmp->bits[i];
+#endif
+ break;
+ }
+
+ if (! bitmap_element_zerop (to_ptr))
+ {
+ to_ptr->indx = indx;
+ bitmap_element_link (to, to_ptr);
+ to_ptr = 0;
+ }
+ }
+
+ /* If we have an unallocated element due to the last element being 0,
+ release it back to the free pool. Don't bother calling
+ bitmap_element_free since it was never linked into a bitmap. */
+ if (to_ptr != 0)
+ {
+ to_ptr->next = bitmap_free;
+ bitmap_free = to_ptr;
+ }
+
+ /* If the output bitmap was one of the inputs, free up its
+ elements now that we're done. */
+ for (; delete_list != 0; delete_list = to_ptr)
+ {
+ to_ptr = delete_list->next;
+ delete_list->next = bitmap_free;
+ bitmap_free = delete_list;
+ }
+}
+
+/* Or into bitmap TO bitmap FROM1 and'ed with the complement of
+ bitmap FROM2. */
+
+void
+bitmap_ior_and_compl (to, from1, from2)
+ bitmap to;
+ bitmap from1;
+ bitmap from2;
+{
+ bitmap_head tmp;
+
+ tmp.first = tmp.current = 0;
+
+ bitmap_operation (&tmp, from1, from2, BITMAP_AND_COMPL);
+ bitmap_operation (to, to, &tmp, BITMAP_IOR);
+ bitmap_clear (&tmp);
+}
+
+/* Initialize a bitmap header. */
+
+bitmap
+bitmap_initialize (head)
+ bitmap head;
+{
+ head->first = head->current = 0;
+
+ return head;
+}
+
+/* Debugging function to print out the contents of a bitmap. */
+
+void
+bitmap_debug_file (file, head)
+ FILE *file;
+ bitmap head;
+{
+ bitmap_element *ptr;
+
+ fprintf (file, "\nfirst = ");
+ fprintf (file, HOST_PTR_PRINTF, head->first);
+ fprintf (file, " current = ");
+ fprintf (file, HOST_PTR_PRINTF, head->current);
+ fprintf (file, " indx = %u\n", head->indx);
+
+ for (ptr = head->first; ptr; ptr = ptr->next)
+ {
+ int i, j, col = 26;
+
+ fprintf (file, "\t");
+ fprintf (file, HOST_PTR_PRINTF, ptr);
+ fprintf (file, " next = ");
+ fprintf (file, HOST_PTR_PRINTF, ptr->next);
+ fprintf (file, " prev = ");
+ fprintf (file, HOST_PTR_PRINTF, ptr->prev);
+ fprintf (file, " indx = %u\n\t\tbits = {", ptr->indx);
+
+ for (i = 0; i < BITMAP_ELEMENT_WORDS; i++)
+ for (j = 0; j < HOST_BITS_PER_WIDE_INT; j++)
+ if ((ptr->bits[i] & (((unsigned HOST_WIDE_INT) 1) << j)) != 0)
+ {
+ if (col > 70)
+ {
+ fprintf (file, "\n\t\t\t");
+ col = 24;
+ }
+
+ fprintf (file, " %u", (ptr->indx * BITMAP_ELEMENT_ALL_BITS
+ + i * HOST_BITS_PER_WIDE_INT + j));
+ col += 4;
+ }
+
+ fprintf (file, " }\n");
+ }
+}
+
+/* Function to be called from the debugger to print the contents
+ of a bitmap. */
+
+void
+debug_bitmap (head)
+ bitmap head;
+{
+ bitmap_debug_file (stdout, head);
+}
+
+/* Function to print out the contents of a bitmap. Unlike bitmap_debug_file,
+ it does not print anything but the bits. */
+
+void
+bitmap_print (file, head, prefix, suffix)
+ FILE *file;
+ bitmap head;
+ char *prefix;
+ char *suffix;
+{
+ char *comma = "";
+ int i;
+
+ fputs (prefix, file);
+ EXECUTE_IF_SET_IN_BITMAP (head, 0, i,
+ {
+ fprintf (file, "%s%d", comma, i);
+ comma = ", ";
+ });
+ fputs (suffix, file);
+}
+
+/* Release any memory allocated by bitmaps. */
+
+void
+bitmap_release_memory ()
+{
+ bitmap_free = 0;
+ if (bitmap_obstack_init)
+ {
+ bitmap_obstack_init = FALSE;
+ obstack_free (&bitmap_obstack, NULL_PTR);
+ }
+}
diff --git a/contrib/gcc/bitmap.h b/contrib/gcc/bitmap.h
new file mode 100644
index 0000000..2941574
--- /dev/null
+++ b/contrib/gcc/bitmap.h
@@ -0,0 +1,317 @@
+/* Functions to support general ended bitmaps.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Number of words to use for each element in the linked list. */
+
+#ifndef BITMAP_ELEMENT_WORDS
+#define BITMAP_ELEMENT_WORDS 2
+#endif
+
+/* Number of bits in each actual element of a bitmap. We get slightly better
+ code for bit % BITMAP_ELEMENT_ALL_BITS and bit / BITMAP_ELEMENT_ALL_BITS if
+ bits is unsigned, assuming it is a power of 2. */
+
+#define BITMAP_ELEMENT_ALL_BITS \
+ ((unsigned) (BITMAP_ELEMENT_WORDS * HOST_BITS_PER_WIDE_INT))
+
+/* Bitmap set element. We use a linked list to hold only the bits that
+ are set. This allows for use to grow the bitset dynamically without
+ having to realloc and copy a giant bit array. The `prev' field is
+ undefined for an element on the free list. */
+
+typedef struct bitmap_element_def
+{
+ struct bitmap_element_def *next; /* Next element. */
+ struct bitmap_element_def *prev; /* Previous element. */
+ unsigned int indx; /* regno/BITMAP_ELEMENT_ALL_BITS. */
+ unsigned HOST_WIDE_INT bits[BITMAP_ELEMENT_WORDS]; /* Bits that are set. */
+} bitmap_element;
+
+/* Head of bitmap linked list. */
+typedef struct bitmap_head_def {
+ bitmap_element *first; /* First element in linked list. */
+ bitmap_element *current; /* Last element looked at. */
+ int indx; /* Index of last element looked at. */
+} bitmap_head, *bitmap;
+
+/* Enumeration giving the various operations we support. */
+enum bitmap_bits {
+ BITMAP_AND, /* TO = FROM1 & FROM2 */
+ BITMAP_AND_COMPL, /* TO = FROM1 & ~ FROM2 */
+ BITMAP_IOR /* TO = FROM1 | FROM2 */
+};
+
+/* Global data */
+extern bitmap_element *bitmap_free; /* Freelist of bitmap elements */
+extern bitmap_element bitmap_zero; /* Zero bitmap element */
+
+/* Clear a bitmap by freeing up the linked list. */
+extern void bitmap_clear PROTO((bitmap));
+
+/* Copy a bitmap to another bitmap. */
+extern void bitmap_copy PROTO((bitmap, bitmap));
+
+/* Perform an operation on two bitmaps, yielding a third. */
+extern void bitmap_operation PROTO((bitmap, bitmap, bitmap, enum bitmap_bits));
+
+/* `or' into one bitmap the `and' of a second bitmap witih the complement
+ of a third. */
+extern void bitmap_ior_and_compl PROTO((bitmap, bitmap, bitmap));
+
+/* Clear a single register in a register set. */
+extern void bitmap_clear_bit PROTO((bitmap, int));
+
+/* Set a single register in a register set. */
+extern void bitmap_set_bit PROTO((bitmap, int));
+
+/* Return true if a register is set in a register set. */
+extern int bitmap_bit_p PROTO((bitmap, int));
+
+/* Debug functions to print a bitmap linked list. */
+extern void bitmap_debug PROTO((bitmap));
+extern void bitmap_debug_file PROTO((FILE *, bitmap));
+
+/* Print a bitmap */
+extern void bitmap_print PROTO((FILE *, bitmap, char *, char *));
+
+/* Initialize a bitmap header. */
+extern bitmap bitmap_initialize PROTO((bitmap));
+
+/* Release all memory held by bitmaps. */
+extern void bitmap_release_memory PROTO((void));
+
+extern void debug_bitmap PROTO((bitmap));
+
+/* Allocate a bitmap with oballoc. */
+#define BITMAP_OBSTACK_ALLOC(OBSTACK) \
+ bitmap_initialize ((bitmap) obstack_alloc (OBSTACK, sizeof (bitmap_head)))
+
+/* Allocate a bitmap with alloca. */
+#define BITMAP_ALLOCA() \
+ bitmap_initialize ((bitmap) alloca (sizeof (bitmap_head)))
+
+/* Do any cleanup needed on a bitmap when it is no longer used. */
+#define BITMAP_FREE(BITMAP) \
+do { \
+ if (BITMAP) \
+ { \
+ bitmap_clear (BITMAP); \
+ (BITMAP) = 0; \
+ } \
+} while (0)
+
+/* Do any one-time initializations needed for bitmaps. */
+#define BITMAP_INIT_ONCE()
+
+/* Loop over all bits in BITMAP, starting with MIN, setting BITNUM to the
+ bit number and executing CODE for all bits that are set. */
+
+#define EXECUTE_IF_SET_IN_BITMAP(BITMAP, MIN, BITNUM, CODE) \
+do { \
+ bitmap_element *ptr_ = (BITMAP)->first; \
+ unsigned int indx_ = (MIN) / BITMAP_ELEMENT_ALL_BITS; \
+ unsigned bit_num_ = (MIN) % ((unsigned) HOST_BITS_PER_WIDE_INT); \
+ unsigned word_num_ = (((MIN) / ((unsigned) HOST_BITS_PER_WIDE_INT)) \
+ % BITMAP_ELEMENT_WORDS); \
+ \
+ \
+ /* Find the block the minimum bit is in. */ \
+ while (ptr_ != 0 && ptr_->indx < indx_) \
+ ptr_ = ptr_->next; \
+ \
+ if (ptr_ != 0 && ptr_->indx != indx_) \
+ { \
+ bit_num_ = 0; \
+ word_num_ = 0; \
+ } \
+ \
+ for (; ptr_ != 0; ptr_ = ptr_->next) \
+ { \
+ for (; word_num_ < BITMAP_ELEMENT_WORDS; word_num_++) \
+ { \
+ unsigned HOST_WIDE_INT word_ = ptr_->bits[word_num_]; \
+ \
+ if (word_ != 0) \
+ { \
+ for (; bit_num_ < HOST_BITS_PER_WIDE_INT; bit_num_++) \
+ { \
+ unsigned HOST_WIDE_INT mask_ \
+ = ((unsigned HOST_WIDE_INT) 1) << bit_num_; \
+ \
+ if ((word_ & mask_) != 0) \
+ { \
+ word_ &= ~ mask_; \
+ (BITNUM) = (ptr_->indx * BITMAP_ELEMENT_ALL_BITS \
+ + word_num_ * HOST_BITS_PER_WIDE_INT \
+ + bit_num_); \
+ CODE; \
+ \
+ if (word_ == 0) \
+ break; \
+ } \
+ } \
+ } \
+ \
+ bit_num_ = 0; \
+ } \
+ \
+ word_num_ = 0; \
+ } \
+} while (0)
+
+/* Loop over all bits in BITMAP1 and BITMAP2, starting with MIN, setting
+ BITNUM to the bit number and executing CODE for all bits that are set in
+ the first bitmap and not set in the second. */
+
+#define EXECUTE_IF_AND_COMPL_IN_BITMAP(BITMAP1, BITMAP2, MIN, BITNUM, CODE) \
+do { \
+ bitmap_element *ptr1_ = (BITMAP1)->first; \
+ bitmap_element *ptr2_ = (BITMAP2)->first; \
+ unsigned int indx_ = (MIN) / BITMAP_ELEMENT_ALL_BITS; \
+ unsigned bit_num_ = (MIN) % ((unsigned) HOST_BITS_PER_WIDE_INT); \
+ unsigned word_num_ = (((MIN) / ((unsigned) HOST_BITS_PER_WIDE_INT)) \
+ % BITMAP_ELEMENT_WORDS); \
+ \
+ /* Find the block the minimum bit is in in the first bitmap. */ \
+ while (ptr1_ != 0 && ptr1_->indx < indx_) \
+ ptr1_ = ptr1_->next; \
+ \
+ if (ptr1_ != 0 && ptr1_->indx != indx_) \
+ { \
+ bit_num_ = 0; \
+ word_num_ = 0; \
+ } \
+ \
+ for (; ptr1_ != 0 ; ptr1_ = ptr1_->next) \
+ { \
+ /* Advance BITMAP2 to the equivalent link, using an all \
+ zero element if an equivalent link doesn't exist. */ \
+ bitmap_element *tmp2_; \
+ \
+ while (ptr2_ != 0 && ptr2_->indx < ptr1_->indx) \
+ ptr2_ = ptr2_->next; \
+ \
+ tmp2_ = ((ptr2_ != 0 && ptr2_->indx == ptr1_->indx) \
+ ? ptr2_ : &bitmap_zero); \
+ \
+ for (; word_num_ < BITMAP_ELEMENT_WORDS; word_num_++) \
+ { \
+ unsigned HOST_WIDE_INT word_ = (ptr1_->bits[word_num_] \
+ & ~ tmp2_->bits[word_num_]); \
+ if (word_ != 0) \
+ { \
+ for (; bit_num_ < HOST_BITS_PER_WIDE_INT; bit_num_++) \
+ { \
+ unsigned HOST_WIDE_INT mask_ \
+ = ((unsigned HOST_WIDE_INT)1) << bit_num_; \
+ \
+ if ((word_ & mask_) != 0) \
+ { \
+ word_ &= ~ mask_; \
+ (BITNUM) = (ptr1_->indx * BITMAP_ELEMENT_ALL_BITS \
+ + word_num_ * HOST_BITS_PER_WIDE_INT \
+ + bit_num_); \
+ \
+ CODE; \
+ if (word_ == 0) \
+ break; \
+ } \
+ } \
+ } \
+ \
+ bit_num_ = 0; \
+ } \
+ \
+ word_num_ = 0; \
+ } \
+} while (0)
+
+/* Loop over all bits in BITMAP1 and BITMAP2, starting with MIN, setting
+ BITNUM to the bit number and executing CODE for all bits that are set in
+ the both bitmaps. */
+
+#define EXECUTE_IF_AND_IN_BITMAP(BITMAP1, BITMAP2, MIN, BITNUM, CODE) \
+do { \
+ bitmap_element *ptr1_ = (BITMAP1)->first; \
+ bitmap_element *ptr2_ = (BITMAP2)->first; \
+ unsigned int indx_ = (MIN) / BITMAP_ELEMENT_ALL_BITS; \
+ unsigned bit_num_ = (MIN) % ((unsigned) HOST_BITS_PER_WIDE_INT); \
+ unsigned word_num_ = (((MIN) / ((unsigned) HOST_BITS_PER_WIDE_INT)) \
+ % BITMAP_ELEMENT_WORDS); \
+ \
+ /* Find the block the minimum bit is in in the first bitmap. */ \
+ while (ptr1_ != 0 && ptr1_->indx < indx_) \
+ ptr1_ = ptr1_->next; \
+ \
+ if (ptr1_ != 0 && ptr1_->indx != indx_) \
+ { \
+ bit_num_ = 0; \
+ word_num_ = 0; \
+ } \
+ \
+ for (; ptr1_ != 0 ; ptr1_ = ptr1_->next) \
+ { \
+ /* Advance BITMAP2 to the equivalent link */ \
+ while (ptr2_ != 0 && ptr2_->indx < ptr1_->indx) \
+ ptr2_ = ptr2_->next; \
+ \
+ if (ptr2_ == 0) \
+ { \
+ /* If there are no more elements in BITMAP2, exit loop now.*/ \
+ ptr1_ = (bitmap_element *)0; \
+ break; \
+ } \
+ else if (ptr2_->indx > ptr1_->indx) \
+ { \
+ bit_num_ = word_num_ = 0; \
+ continue; \
+ } \
+ \
+ for (; word_num_ < BITMAP_ELEMENT_WORDS; word_num_++) \
+ { \
+ unsigned HOST_WIDE_INT word_ = (ptr1_->bits[word_num_] \
+ & ptr2_->bits[word_num_]); \
+ if (word_ != 0) \
+ { \
+ for (; bit_num_ < HOST_BITS_PER_WIDE_INT; bit_num_++) \
+ { \
+ unsigned HOST_WIDE_INT mask_ \
+ = ((unsigned HOST_WIDE_INT)1) << bit_num_; \
+ \
+ if ((word_ & mask_) != 0) \
+ { \
+ word_ &= ~ mask_; \
+ (BITNUM) = (ptr1_->indx * BITMAP_ELEMENT_ALL_BITS \
+ + word_num_ * HOST_BITS_PER_WIDE_INT \
+ + bit_num_); \
+ \
+ CODE; \
+ if (word_ == 0) \
+ break; \
+ } \
+ } \
+ } \
+ \
+ bit_num_ = 0; \
+ } \
+ \
+ word_num_ = 0; \
+ } \
+} while (0)
diff --git a/contrib/gcc/build-make b/contrib/gcc/build-make
index 1d6e18b..f9049ae 100644
--- a/contrib/gcc/build-make
+++ b/contrib/gcc/build-make
@@ -1,5 +1,5 @@
# We have to use the cross-compiler we just built to compile it.
-CC = gcc -b $(target)
+CC = gcc -b $(host)
# Need those to compile binaries running on host machine.
# It is configured by
@@ -24,9 +24,12 @@ HOST_OBSTACK=$(OBSTACK)
# target.
FIXINCLUDES=Makefile.in
+# Don't run fixproto either
+STMP_FIXPROTO =
+
# Cause installation using install-build. We do nothing here.
-INSTALL_TARGET = install-build
+#INSTALL_TARGET = install-build
# Don't try to compile the things we can't compile or we have made
# while making gcc with the cross-compiler.
-ALL = all.build
+#ALL = all.build
diff --git a/contrib/gcc/c-aux-info.c b/contrib/gcc/c-aux-info.c
index d8caa6a..3e2edde 100644
--- a/contrib/gcc/c-aux-info.c
+++ b/contrib/gcc/c-aux-info.c
@@ -1,7 +1,7 @@
/* Generate information regarding function declarations and definitions based
on information stored in GCC's tree structure. This code implements the
-aux-info option.
- Copyright (C) 1989, 1991, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1989, 91, 94, 95, 97, 1998 Free Software Foundation, Inc.
Contributed by Ron Guilmette (rfg@segfault.us.com).
This file is part of GNU CC.
@@ -21,14 +21,12 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "flags.h"
#include "tree.h"
#include "c-tree.h"
-extern char* xmalloc ();
-
enum formals_style_enum {
ansi,
k_and_r_names,
@@ -37,26 +35,26 @@ enum formals_style_enum {
typedef enum formals_style_enum formals_style;
-static char* data_type;
+static char *data_type;
-static char * concat ();
-static char * concat3 ();
-static char * gen_formal_list_for_type ();
-static int deserves_ellipsis ();
-static char * gen_formal_list_for_func_def ();
-static char * gen_type ();
-static char * gen_decl ();
-void gen_aux_info_record ();
+static char *concat PROTO((char *, char *));
+static char *concat3 PROTO((char *, char *, char *));
+static char *affix_data_type PROTO((char *));
+static char *gen_formal_list_for_type PROTO((tree, formals_style));
+static int deserves_ellipsis PROTO((tree));
+static char *gen_formal_list_for_func_def PROTO((tree, formals_style));
+static char *gen_type PROTO((char *, tree, formals_style));
+static char *gen_decl PROTO((tree, int, formals_style));
/* Take two strings and mash them together into a newly allocated area. */
-static char*
+static char *
concat (s1, s2)
- char* s1;
- char* s2;
+ char *s1;
+ char *s2;
{
int size1, size2;
- char* ret_val;
+ char *ret_val;
if (!s1)
s1 = "";
@@ -73,14 +71,14 @@ concat (s1, s2)
/* Take three strings and mash them together into a newly allocated area. */
-static char*
+static char *
concat3 (s1, s2, s3)
- char* s1;
- char* s2;
- char* s3;
+ char *s1;
+ char *s2;
+ char *s3;
{
int size1, size2, size3;
- char* ret_val;
+ char *ret_val;
if (!s1)
s1 = "";
@@ -113,7 +111,7 @@ concat3 (s1, s2, s3)
`const char *foo;' and *not* `char const *foo;' so we try to create types
that look as expected. */
-static char*
+static char *
affix_data_type (type_or_decl)
char *type_or_decl;
{
@@ -156,14 +154,14 @@ affix_data_type (type_or_decl)
this function type. Return the whole formal parameter list (including
a pair of surrounding parens) as a string. Note that if the style
we are currently aiming for is non-ansi, then we just return a pair
- of empty parens here. */
+ of empty parens here. */
-static char*
+static char *
gen_formal_list_for_type (fntype, style)
tree fntype;
formals_style style;
{
- char* formal_list = "";
+ char *formal_list = "";
tree formal_type;
if (style != ansi)
@@ -172,16 +170,16 @@ gen_formal_list_for_type (fntype, style)
formal_type = TYPE_ARG_TYPES (fntype);
while (formal_type && TREE_VALUE (formal_type) != void_type_node)
{
- char* this_type;
+ char *this_type;
if (*formal_list)
formal_list = concat (formal_list, ", ");
this_type = gen_type ("", TREE_VALUE (formal_type), ansi);
- formal_list =
- (strlen (this_type))
- ? concat (formal_list, affix_data_type (this_type))
- : concat (formal_list, data_type);
+ formal_list
+ = ((strlen (this_type))
+ ? concat (formal_list, affix_data_type (this_type))
+ : concat (formal_list, data_type));
formal_type = TREE_CHAIN (formal_type);
}
@@ -278,12 +276,12 @@ deserves_ellipsis (fntype)
This routine returns a string which is the source form for the entire
function formal parameter list. */
-static char*
+static char *
gen_formal_list_for_func_def (fndecl, style)
tree fndecl;
formals_style style;
{
- char* formal_list = "";
+ char *formal_list = "";
tree formal_decl;
formal_decl = DECL_ARGUMENTS (fndecl);
@@ -353,15 +351,16 @@ gen_formal_list_for_func_def (fndecl, style)
to do at this point is for the initial caller to prepend the "data_type"
string onto the returned "seed". */
-static char*
+static char *
gen_type (ret_val, t, style)
- char* ret_val;
+ char *ret_val;
tree t;
formals_style style;
{
tree chain_p;
- if (TYPE_NAME (t) && DECL_NAME (TYPE_NAME (t)))
+ /* If there is a typedef name for this type, use it. */
+ if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL)
data_type = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (t)));
else
{
@@ -517,13 +516,13 @@ gen_type (ret_val, t, style)
associated with a function definition. In this case, we can assume that
an attached list of DECL nodes for function formal arguments is present. */
-static char*
+static char *
gen_decl (decl, is_func_definition, style)
tree decl;
int is_func_definition;
formals_style style;
{
- char* ret_val;
+ char *ret_val;
if (DECL_NAME (decl))
ret_val = IDENTIFIER_POINTER (DECL_NAME (decl));
@@ -581,7 +580,7 @@ gen_decl (decl, is_func_definition, style)
ret_val = affix_data_type (ret_val);
- if (DECL_REGISTER (decl))
+ if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
ret_val = concat ("register ", ret_val);
if (TREE_PUBLIC (decl))
ret_val = concat ("extern ", ret_val);
@@ -591,7 +590,7 @@ gen_decl (decl, is_func_definition, style)
return ret_val;
}
-extern FILE* aux_info_file;
+extern FILE *aux_info_file;
/* Generate and write a new line of info to the aux-info (.X) file. This
routine is called once for each function declaration, and once for each
diff --git a/contrib/gcc/c-common.c b/contrib/gcc/c-common.c
index 78b4d85..61600fb 100644
--- a/contrib/gcc/c-common.c
+++ b/contrib/gcc/c-common.c
@@ -1,5 +1,5 @@
/* Subroutines shared by all languages that are variants of C.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,24 +19,139 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "c-lex.h"
#include "c-tree.h"
#include "flags.h"
#include "obstack.h"
-#include <stdio.h>
-#include <ctype.h>
+#include "toplev.h"
+#include "output.h"
+
+#if USE_CPPLIB
+#include "cpplib.h"
+cpp_reader parse_in;
+cpp_options parse_options;
+static enum cpp_token cpp_token;
+#endif
+
+#ifndef WCHAR_TYPE_SIZE
+#ifdef INT_TYPE_SIZE
+#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
+#else
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+#endif
+#endif
extern struct obstack permanent_obstack;
-enum attrs {A_PACKED, A_NOCOMMON, A_NORETURN, A_CONST, A_T_UNION,
+/* Nonzero means the expression being parsed will never be evaluated.
+ This is a count, since unevaluated expressions can nest. */
+int skip_evaluation;
+
+enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
- A_UNUSED, A_FORMAT, A_WEAK, A_ALIAS};
+ A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS};
+
+enum format_type { printf_format_type, scanf_format_type,
+ strftime_format_type };
static void declare_hidden_char_array PROTO((char *, char *));
static void add_attribute PROTO((enum attrs, char *,
int, int, int));
static void init_attributes PROTO((void));
+static void record_function_format PROTO((tree, tree, enum format_type,
+ int, int));
+static void record_international_format PROTO((tree, tree, int));
+
+/* Keep a stack of if statements. We record the number of compound
+ statements seen up to the if keyword, as well as the line number
+ and file of the if. If a potentially ambiguous else is seen, that
+ fact is recorded; the warning is issued when we can be sure that
+ the enclosing if statement does not have an else branch. */
+typedef struct
+{
+ int compstmt_count;
+ int line;
+ char *file;
+ int needs_warning;
+} if_elt;
+
+static if_elt *if_stack;
+
+/* Amount of space in the if statement stack. */
+static int if_stack_space = 0;
+
+/* Stack pointer. */
+static int if_stack_pointer = 0;
+
+/* Generate RTL for the start of an if-then, and record the start of it
+ for ambiguous else detection. */
+
+void
+c_expand_start_cond (cond, exitflag, compstmt_count)
+ tree cond;
+ int exitflag;
+ int compstmt_count;
+{
+ /* Make sure there is enough space on the stack. */
+ if (if_stack_space == 0)
+ {
+ if_stack_space = 10;
+ if_stack = (if_elt *)xmalloc (10 * sizeof (if_elt));
+ }
+ else if (if_stack_space == if_stack_pointer)
+ {
+ if_stack_space += 10;
+ if_stack = (if_elt *)xrealloc (if_stack, if_stack_space * sizeof (if_elt));
+ }
+
+ /* Record this if statement. */
+ if_stack[if_stack_pointer].compstmt_count = compstmt_count;
+ if_stack[if_stack_pointer].file = input_filename;
+ if_stack[if_stack_pointer].line = lineno;
+ if_stack[if_stack_pointer].needs_warning = 0;
+ if_stack_pointer++;
+
+ expand_start_cond (cond, exitflag);
+}
+
+/* Generate RTL for the end of an if-then. Optionally warn if a nested
+ if statement had an ambiguous else clause. */
+
+void
+c_expand_end_cond ()
+{
+ if_stack_pointer--;
+ if (if_stack[if_stack_pointer].needs_warning)
+ warning_with_file_and_line (if_stack[if_stack_pointer].file,
+ if_stack[if_stack_pointer].line,
+ "suggest explicit braces to avoid ambiguous `else'");
+ expand_end_cond ();
+}
+
+/* Generate RTL between the then-clause and the else-clause
+ of an if-then-else. */
+
+void
+c_expand_start_else ()
+{
+ /* An ambiguous else warning must be generated for the enclosing if
+ statement, unless we see an else branch for that one, too. */
+ if (warn_parentheses
+ && if_stack_pointer > 1
+ && (if_stack[if_stack_pointer - 1].compstmt_count
+ == if_stack[if_stack_pointer - 2].compstmt_count))
+ if_stack[if_stack_pointer - 2].needs_warning = 1;
+
+ /* Even if a nested if statement had an else branch, it can't be
+ ambiguous if this one also has an else. So don't warn in that
+ case. Also don't warn for any if statements nested in this else. */
+ if_stack[if_stack_pointer - 1].needs_warning = 0;
+ if_stack[if_stack_pointer - 1].compstmt_count--;
+
+ expand_start_else ();
+}
/* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
@@ -52,15 +167,12 @@ declare_function_name ()
}
else
{
- char *kind = "function";
- if (TREE_CODE (TREE_TYPE (current_function_decl)) == METHOD_TYPE)
- kind = "method";
/* Allow functions to be nameless (such as artificial ones). */
if (DECL_NAME (current_function_decl))
name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
else
name = "";
- printable_name = (*decl_printable_name) (current_function_decl, &kind);
+ printable_name = (*decl_printable_name) (current_function_decl, 2);
}
declare_hidden_char_array ("__FUNCTION__", name);
@@ -78,7 +190,7 @@ declare_hidden_char_array (name, value)
or if we want to give warnings for large objects, make a bigger one. */
vlen = strlen (value) + 1;
type = char_array_type_node;
- if (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TREE_TYPE (type))) < vlen
+ if (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) < vlen
|| warn_larger_than)
type = build_array_type (char_type_node,
build_index_type (build_int_2 (vlen, 0)));
@@ -157,7 +269,12 @@ combine_strings (strings)
{
int i;
for (i = 0; i < len; i++)
- ((int *) q)[i] = TREE_STRING_POINTER (t)[i];
+ {
+ if (WCHAR_TYPE_SIZE == HOST_BITS_PER_SHORT)
+ ((short *) q)[i] = TREE_STRING_POINTER (t)[i];
+ else
+ ((int *) q)[i] = TREE_STRING_POINTER (t)[i];
+ }
q += len * wchar_bytes;
}
}
@@ -183,7 +300,7 @@ combine_strings (strings)
wide_flag = 1;
}
- /* Compute the number of elements, for the array type. */
+ /* Compute the number of elements, for the array type. */
nchars = wide_flag ? length / wchar_bytes : length;
/* Create the array type for the string constant.
@@ -250,9 +367,10 @@ init_attributes ()
{
add_attribute (A_PACKED, "packed", 0, 0, 0);
add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1);
+ add_attribute (A_COMMON, "common", 0, 0, 1);
add_attribute (A_NORETURN, "noreturn", 0, 0, 1);
add_attribute (A_NORETURN, "volatile", 0, 0, 1);
- add_attribute (A_UNUSED, "unused", 0, 0, 1);
+ add_attribute (A_UNUSED, "unused", 0, 0, 0);
add_attribute (A_CONST, "const", 0, 0, 1);
add_attribute (A_T_UNION, "transparent_union", 0, 0, 0);
add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1);
@@ -261,6 +379,7 @@ init_attributes ()
add_attribute (A_SECTION, "section", 1, 1, 1);
add_attribute (A_ALIGNED, "aligned", 0, 1, 0);
add_attribute (A_FORMAT, "format", 3, 3, 1);
+ add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1);
add_attribute (A_WEAK, "weak", 0, 0, 1);
add_attribute (A_ALIAS, "alias", 1, 1, 1);
}
@@ -268,14 +387,14 @@ init_attributes ()
/* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES
and install them in NODE, which is either a DECL (including a TYPE_DECL)
or a TYPE. PREFIX_ATTRIBUTES can appear after the declaration specifiers
- and declaration modifiers but before the declaration proper. */
+ and declaration modifiers but before the declaration proper. */
void
decl_attributes (node, attributes, prefix_attributes)
tree node, attributes, prefix_attributes;
{
- tree decl = 0, type;
- int is_type;
+ tree decl = 0, type = 0;
+ int is_type = 0;
tree a;
if (attrtab_idx == 0)
@@ -298,7 +417,7 @@ decl_attributes (node, attributes, prefix_attributes)
tree args = TREE_VALUE (a);
int i;
enum attrs id;
-
+
for (i = 0; i < attrtab_idx; i++)
if (attrtab[i].name == name)
break;
@@ -308,6 +427,8 @@ decl_attributes (node, attributes, prefix_attributes)
if (! valid_machine_attribute (name, args, decl, type))
warning ("`%s' attribute directive ignored",
IDENTIFIER_POINTER (name));
+ else if (decl != 0)
+ type = TREE_TYPE (decl);
continue;
}
else if (attrtab[i].decl_req && decl == 0)
@@ -345,12 +466,19 @@ decl_attributes (node, attributes, prefix_attributes)
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
break;
+ case A_COMMON:
+ if (TREE_CODE (decl) == VAR_DECL)
+ DECL_COMMON (decl) = 1;
+ else
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ break;
+
case A_NORETURN:
if (TREE_CODE (decl) == FUNCTION_DECL)
TREE_THIS_VOLATILE (decl) = 1;
else if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
- TREE_TYPE (decl) = type
+ TREE_TYPE (decl) = type
= build_pointer_type
(build_type_variant (TREE_TYPE (type),
TREE_READONLY (TREE_TYPE (type)), 1));
@@ -359,8 +487,11 @@ decl_attributes (node, attributes, prefix_attributes)
break;
case A_UNUSED:
- if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL
- || TREE_CODE (decl) == FUNCTION_DECL)
+ if (is_type)
+ TREE_USED (type) = 1;
+ else if (TREE_CODE (decl) == PARM_DECL
+ || TREE_CODE (decl) == VAR_DECL
+ || TREE_CODE (decl) == FUNCTION_DECL)
TREE_USED (decl) = 1;
else
warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
@@ -383,7 +514,8 @@ decl_attributes (node, attributes, prefix_attributes)
if (is_type
&& TREE_CODE (type) == UNION_TYPE
&& (decl == 0
- || TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type))))
+ || (TYPE_FIELDS (type) != 0
+ && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))))
TYPE_TRANSPARENT_UNION (type) = 1;
else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
&& TREE_CODE (type) == UNION_TYPE
@@ -471,8 +603,9 @@ decl_attributes (node, attributes, prefix_attributes)
|| TREE_CODE (decl) == VAR_DECL)
&& TREE_CODE (TREE_VALUE (args)) == STRING_CST)
{
- if (TREE_CODE (decl) == VAR_DECL
- && current_function_decl != NULL_TREE)
+ if (TREE_CODE (decl) == VAR_DECL
+ && current_function_decl != NULL_TREE
+ && ! TREE_STATIC (decl))
error_with_decl (decl,
"section attribute cannot be specified for local variables");
/* The decl may have already been given a section attribute from
@@ -497,7 +630,8 @@ decl_attributes (node, attributes, prefix_attributes)
case A_ALIGNED:
{
tree align_expr
- = args ? TREE_VALUE (args) : size_int (BIGGEST_ALIGNMENT);
+ = (args ? TREE_VALUE (args)
+ : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
int align;
/* Strip any NOPs of any kind. */
@@ -505,7 +639,7 @@ decl_attributes (node, attributes, prefix_attributes)
|| TREE_CODE (align_expr) == CONVERT_EXPR
|| TREE_CODE (align_expr) == NON_LVALUE_EXPR)
align_expr = TREE_OPERAND (align_expr, 0);
-
+
if (TREE_CODE (align_expr) != INTEGER_CST)
{
error ("requested alignment is not a constant");
@@ -529,16 +663,16 @@ decl_attributes (node, attributes, prefix_attributes)
case A_FORMAT:
{
- tree format_type = TREE_VALUE (args);
+ tree format_type_id = TREE_VALUE (args);
tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
tree first_arg_num_expr
= TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
int format_num;
int first_arg_num;
- int is_scan;
+ enum format_type format_type;
tree argument;
int arg_num;
-
+
if (TREE_CODE (decl) != FUNCTION_DECL)
{
error_with_decl (decl,
@@ -546,21 +680,28 @@ decl_attributes (node, attributes, prefix_attributes)
continue;
}
- if (TREE_CODE (format_type) == IDENTIFIER_NODE
- && (!strcmp (IDENTIFIER_POINTER (format_type), "printf")
- || !strcmp (IDENTIFIER_POINTER (format_type),
- "__printf__")))
- is_scan = 0;
- else if (TREE_CODE (format_type) == IDENTIFIER_NODE
- && (!strcmp (IDENTIFIER_POINTER (format_type), "scanf")
- || !strcmp (IDENTIFIER_POINTER (format_type),
- "__scanf__")))
- is_scan = 1;
- else
+ if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
{
- error ("unrecognized format specifier for `%s'");
+ error ("unrecognized format specifier");
continue;
}
+ else
+ {
+ char *p = IDENTIFIER_POINTER (format_type_id);
+
+ if (!strcmp (p, "printf") || !strcmp (p, "__printf__"))
+ format_type = printf_format_type;
+ else if (!strcmp (p, "scanf") || !strcmp (p, "__scanf__"))
+ format_type = scanf_format_type;
+ else if (!strcmp (p, "strftime")
+ || !strcmp (p, "__strftime__"))
+ format_type = strftime_format_type;
+ else
+ {
+ error ("`%s' is an unrecognized format function type", p);
+ continue;
+ }
+ }
/* Strip any conversions from the string index and first arg number
and verify they are constants. */
@@ -612,7 +753,7 @@ decl_attributes (node, attributes, prefix_attributes)
if (first_arg_num != 0)
{
/* Verify that first_arg_num points to the last arg,
- the ... */
+ the ... */
while (argument)
arg_num++, argument = TREE_CHAIN (argument);
if (arg_num != first_arg_num)
@@ -625,7 +766,71 @@ decl_attributes (node, attributes, prefix_attributes)
record_function_format (DECL_NAME (decl),
DECL_ASSEMBLER_NAME (decl),
- is_scan, format_num, first_arg_num);
+ format_type, format_num, first_arg_num);
+ break;
+ }
+
+ case A_FORMAT_ARG:
+ {
+ tree format_num_expr = TREE_VALUE (args);
+ int format_num, arg_num;
+ tree argument;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ {
+ error_with_decl (decl,
+ "argument format specified for non-function `%s'");
+ continue;
+ }
+
+ /* Strip any conversions from the first arg number and verify it
+ is a constant. */
+ while (TREE_CODE (format_num_expr) == NOP_EXPR
+ || TREE_CODE (format_num_expr) == CONVERT_EXPR
+ || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
+ format_num_expr = TREE_OPERAND (format_num_expr, 0);
+
+ if (TREE_CODE (format_num_expr) != INTEGER_CST)
+ {
+ error ("format string has non-constant operand number");
+ continue;
+ }
+
+ format_num = TREE_INT_CST_LOW (format_num_expr);
+
+ /* If a parameter list is specified, verify that the format_num
+ argument is actually a string, in case the format attribute
+ is in error. */
+ argument = TYPE_ARG_TYPES (type);
+ if (argument)
+ {
+ for (arg_num = 1; ; ++arg_num)
+ {
+ if (argument == 0 || arg_num == format_num)
+ break;
+ argument = TREE_CHAIN (argument);
+ }
+ if (! argument
+ || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
+ || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
+ != char_type_node))
+ {
+ error ("format string arg not a string type");
+ continue;
+ }
+ }
+
+ if (TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) != POINTER_TYPE
+ || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_TYPE (decl))))
+ != char_type_node))
+ {
+ error ("function does not return string type");
+ continue;
+ }
+
+ record_international_format (DECL_NAME (decl),
+ DECL_ASSEMBLER_NAME (decl),
+ format_num);
break;
}
@@ -635,13 +840,21 @@ decl_attributes (node, attributes, prefix_attributes)
case A_ALIAS:
if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
- || TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl))
+ || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
error_with_decl (decl,
"`%s' defined both normally and as an alias");
else if (decl_function_context (decl) == 0)
{
- tree id = get_identifier (TREE_STRING_POINTER
- (TREE_VALUE (args)));
+ tree id;
+
+ id = TREE_VALUE (args);
+ if (TREE_CODE (id) != STRING_CST)
+ {
+ error ("alias arg not a string");
+ break;
+ }
+ id = get_identifier (TREE_STRING_POINTER (id));
+
if (TREE_CODE (decl) == FUNCTION_DECL)
DECL_INITIAL (decl) = error_mark_node;
else
@@ -654,6 +867,100 @@ decl_attributes (node, attributes, prefix_attributes)
}
}
}
+
+/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
+ lists. SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
+
+ The head of the declspec list is stored in DECLSPECS.
+ The head of the attribute list is stored in PREFIX_ATTRIBUTES.
+
+ Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
+ the list elements. We drop the containing TREE_LIST nodes and link the
+ resulting attributes together the way decl_attributes expects them. */
+
+void
+split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
+ tree specs_attrs;
+ tree *declspecs, *prefix_attributes;
+{
+ tree t, s, a, next, specs, attrs;
+
+ /* This can happen in c++ (eg: decl: typespec initdecls ';'). */
+ if (specs_attrs != NULL_TREE
+ && TREE_CODE (specs_attrs) != TREE_LIST)
+ {
+ *declspecs = specs_attrs;
+ *prefix_attributes = NULL_TREE;
+ return;
+ }
+
+ /* Remember to keep the lists in the same order, element-wise. */
+
+ specs = s = NULL_TREE;
+ attrs = a = NULL_TREE;
+ for (t = specs_attrs; t; t = next)
+ {
+ next = TREE_CHAIN (t);
+ /* Declspecs have a non-NULL TREE_VALUE. */
+ if (TREE_VALUE (t) != NULL_TREE)
+ {
+ if (specs == NULL_TREE)
+ specs = s = t;
+ else
+ {
+ TREE_CHAIN (s) = t;
+ s = t;
+ }
+ }
+ else
+ {
+ if (attrs == NULL_TREE)
+ attrs = a = TREE_PURPOSE (t);
+ else
+ {
+ TREE_CHAIN (a) = TREE_PURPOSE (t);
+ a = TREE_PURPOSE (t);
+ }
+ /* More attrs can be linked here, move A to the end. */
+ while (TREE_CHAIN (a) != NULL_TREE)
+ a = TREE_CHAIN (a);
+ }
+ }
+
+ /* Terminate the lists. */
+ if (s != NULL_TREE)
+ TREE_CHAIN (s) = NULL_TREE;
+ if (a != NULL_TREE)
+ TREE_CHAIN (a) = NULL_TREE;
+
+ /* All done. */
+ *declspecs = specs;
+ *prefix_attributes = attrs;
+}
+
+/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes.
+ This function is used by the parser when a rule will accept attributes
+ in a particular position, but we don't want to support that just yet.
+
+ A warning is issued for every ignored attribute. */
+
+tree
+strip_attrs (specs_attrs)
+ tree specs_attrs;
+{
+ tree specs, attrs;
+
+ split_specs_attrs (specs_attrs, &specs, &attrs);
+
+ while (attrs)
+ {
+ warning ("`%s' attribute ignored",
+ IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
+ attrs = TREE_CHAIN (attrs);
+ }
+
+ return specs;
+}
/* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against
a parameter list. */
@@ -670,6 +977,7 @@ decl_attributes (node, attributes, prefix_attributes)
#define T_D &double_type_node
#define T_LD &long_double_type_node
#define T_C &char_type_node
+#define T_UC &unsigned_char_type_node
#define T_V &void_type_node
#define T_W &wchar_type_node
#define T_ST &sizetype
@@ -679,6 +987,9 @@ typedef struct {
int pointer_count;
/* Type of argument if no length modifier is used. */
tree *nolen;
+ /* Type of argument if length modifier for shortening to byte is used.
+ If NULL, then this modifier is not allowed. */
+ tree *hhlen;
/* Type of argument if length modifier for shortening is used.
If NULL, then this modifier is not allowed. */
tree *hlen;
@@ -691,89 +1002,146 @@ typedef struct {
/* Type of argument if length modifier `L' is used.
If NULL, then this modifier is not allowed. */
tree *bigllen;
+ /* Type of argument if length modifier `Z' is used.
+ If NULL, then this modifier is not allowed. */
+ tree *zlen;
/* List of other modifier characters allowed with these options. */
char *flag_chars;
} format_char_info;
static format_char_info print_char_table[] = {
- { "di", 0, T_I, T_I, T_L, T_LL, T_LL, "-wp0 +" },
- { "oxX", 0, T_UI, T_UI, T_UL, T_ULL, T_ULL, "-wp0#" },
- { "u", 0, T_UI, T_UI, T_UL, T_ULL, T_ULL, "-wp0" },
-/* Two GNU extensions. */
- { "Z", 0, T_ST, NULL, NULL, NULL, NULL, "-wp0" },
- { "m", 0, T_V, NULL, NULL, NULL, NULL, "-wp" },
- { "feEgG", 0, T_D, NULL, NULL, NULL, T_LD, "-wp0 +#" },
- { "c", 0, T_I, NULL, T_W, NULL, NULL, "-w" },
- { "C", 0, T_W, NULL, NULL, NULL, NULL, "-w" },
- { "s", 1, T_C, NULL, T_W, NULL, NULL, "-wp" },
- { "S", 1, T_W, NULL, NULL, NULL, NULL, "-wp" },
- { "p", 1, T_V, NULL, NULL, NULL, NULL, "-w" },
- { "n", 1, T_I, T_S, T_L, T_LL, NULL, "" },
+ { "di", 0, T_I, T_I, T_I, T_L, T_LL, T_LL, T_ST, "-wp0 +" },
+ { "oxX", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0#" },
+ { "u", 0, T_UI, T_UI, T_UI, T_UL, T_ULL, T_ULL, T_ST, "-wp0" },
+/* A GNU extension. */
+ { "m", 0, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" },
+ { "feEgGaA", 0, T_D, NULL, NULL, NULL, NULL, T_LD, NULL, "-wp0 +#" },
+ { "c", 0, T_I, NULL, NULL, T_W, NULL, NULL, NULL, "-w" },
+ { "C", 0, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-w" },
+ { "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "-wp" },
+ { "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "-wp" },
+ { "p", 1, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "-w" },
+ { "n", 1, T_I, NULL, T_S, T_L, T_LL, NULL, NULL, "" },
{ NULL }
};
static format_char_info scan_char_table[] = {
- { "di", 1, T_I, T_S, T_L, T_LL, T_LL, "*" },
- { "ouxX", 1, T_UI, T_US, T_UL, T_ULL, T_ULL, "*" },
- { "efgEG", 1, T_F, NULL, T_D, NULL, T_LD, "*" },
- { "sc", 1, T_C, NULL, T_W, NULL, NULL, "*a" },
- { "[", 1, T_C, NULL, NULL, NULL, NULL, "*a" },
- { "C", 1, T_W, NULL, NULL, NULL, NULL, "*" },
- { "S", 1, T_W, NULL, NULL, NULL, NULL, "*" },
- { "p", 2, T_V, NULL, NULL, NULL, NULL, "*" },
- { "n", 1, T_I, T_S, T_L, T_LL, NULL, "" },
+ { "di", 1, T_I, T_C, T_S, T_L, T_LL, T_LL, NULL, "*" },
+ { "ouxX", 1, T_UI, T_UC, T_US, T_UL, T_ULL, T_ULL, NULL, "*" },
+ { "efgEGaA", 1, T_F, NULL, NULL, T_D, NULL, T_LD, NULL, "*" },
+ { "c", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "*" },
+ { "s", 1, T_C, NULL, NULL, T_W, NULL, NULL, NULL, "*a" },
+ { "[", 1, T_C, NULL, NULL, NULL, NULL, NULL, NULL, "*a" },
+ { "C", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*" },
+ { "S", 1, T_W, NULL, NULL, NULL, NULL, NULL, NULL, "*a" },
+ { "p", 2, T_V, NULL, NULL, NULL, NULL, NULL, NULL, "*" },
+ { "n", 1, T_I, T_C, T_S, T_L, T_LL, NULL, NULL, "" },
{ NULL }
};
-typedef struct function_format_info {
+/* Handle format characters recognized by glibc's strftime.c.
+ '2' - MUST do years as only two digits
+ '3' - MAY do years as only two digits (depending on locale)
+ 'E' - E modifier is acceptable
+ 'O' - O modifier is acceptable to Standard C
+ 'o' - O modifier is acceptable as a GNU extension
+ 'G' - other GNU extensions */
+
+static format_char_info time_char_table[] = {
+ { "y", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2EO-_0w" },
+ { "D", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2" },
+ { "g", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "2O-_0w" },
+ { "cx", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "3E" },
+ { "%RTXnrt", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "" },
+ { "P", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "G" },
+ { "HIMSUWdemw", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Ow" },
+ { "Vju", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0Oow" },
+ { "Gklsz", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0OGw" },
+ { "ABZa", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^#" },
+ { "p", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "#" },
+ { "bh", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "^" },
+ { "CY", 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-_0EOw" },
+ { NULL }
+};
+
+typedef struct function_format_info
+{
struct function_format_info *next; /* next structure on the list */
tree name; /* identifier such as "printf" */
tree assembler_name; /* optional mangled identifier (for C++) */
- int is_scan; /* TRUE if *scanf */
+ enum format_type format_type; /* type of format (printf, scanf, etc.) */
int format_num; /* number of format argument */
int first_arg_num; /* number of first arg (zero for varargs) */
} function_format_info;
static function_format_info *function_format_list = NULL;
-static void check_format_info PROTO((function_format_info *, tree));
+typedef struct international_format_info
+{
+ struct international_format_info *next; /* next structure on the list */
+ tree name; /* identifier such as "gettext" */
+ tree assembler_name; /* optional mangled identifier (for C++) */
+ int format_num; /* number of format argument */
+} international_format_info;
+
+static international_format_info *international_format_list = NULL;
+
+static void check_format_info PROTO((function_format_info *, tree));
/* Initialize the table of functions to perform format checking on.
The ANSI functions are always checked (whether <stdio.h> is
included or not), since it is common to call printf without
including <stdio.h>. There shouldn't be a problem with this,
since ANSI reserves these function names whether you include the
- header file or not. In any case, the checking is harmless. */
+ header file or not. In any case, the checking is harmless.
+
+ Also initialize the name of function that modify the format string for
+ internationalization purposes. */
void
init_function_format_info ()
{
- record_function_format (get_identifier ("printf"), NULL_TREE, 0, 1, 2);
- record_function_format (get_identifier ("fprintf"), NULL_TREE, 0, 2, 3);
- record_function_format (get_identifier ("sprintf"), NULL_TREE, 0, 2, 3);
- record_function_format (get_identifier ("scanf"), NULL_TREE, 1, 1, 2);
- record_function_format (get_identifier ("fscanf"), NULL_TREE, 1, 2, 3);
- record_function_format (get_identifier ("sscanf"), NULL_TREE, 1, 2, 3);
- record_function_format (get_identifier ("vprintf"), NULL_TREE, 0, 1, 0);
- record_function_format (get_identifier ("vfprintf"), NULL_TREE, 0, 2, 0);
- record_function_format (get_identifier ("vsprintf"), NULL_TREE, 0, 2, 0);
+ record_function_format (get_identifier ("printf"), NULL_TREE,
+ printf_format_type, 1, 2);
+ record_function_format (get_identifier ("fprintf"), NULL_TREE,
+ printf_format_type, 2, 3);
+ record_function_format (get_identifier ("sprintf"), NULL_TREE,
+ printf_format_type, 2, 3);
+ record_function_format (get_identifier ("scanf"), NULL_TREE,
+ scanf_format_type, 1, 2);
+ record_function_format (get_identifier ("fscanf"), NULL_TREE,
+ scanf_format_type, 2, 3);
+ record_function_format (get_identifier ("sscanf"), NULL_TREE,
+ scanf_format_type, 2, 3);
+ record_function_format (get_identifier ("vprintf"), NULL_TREE,
+ printf_format_type, 1, 0);
+ record_function_format (get_identifier ("vfprintf"), NULL_TREE,
+ printf_format_type, 2, 0);
+ record_function_format (get_identifier ("vsprintf"), NULL_TREE,
+ printf_format_type, 2, 0);
+ record_function_format (get_identifier ("strftime"), NULL_TREE,
+ strftime_format_type, 3, 0);
+
+ record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
+ record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
+ record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2);
}
/* Record information for argument format checking. FUNCTION_IDENT is
the identifier node for the name of the function to check (its decl
- need not exist yet). IS_SCAN is true for scanf-type format checking;
- false indicates printf-style format checking. FORMAT_NUM is the number
+ need not exist yet).
+ FORMAT_TYPE specifies the type of format checking. FORMAT_NUM is the number
of the argument which is the format control string (starting from 1).
FIRST_ARG_NUM is the number of the first actual argument to check
- against teh format string, or zero if no checking is not be done
+ against the format string, or zero if no checking is not be done
(e.g. for varargs such as vfprintf). */
-void
-record_function_format (name, assembler_name, is_scan,
+static void
+record_function_format (name, assembler_name, format_type,
format_num, first_arg_num)
tree name;
tree assembler_name;
- int is_scan;
+ enum format_type format_type;
int format_num;
int first_arg_num;
{
@@ -796,11 +1164,48 @@ record_function_format (name, assembler_name, is_scan,
info->assembler_name = assembler_name;
}
- info->is_scan = is_scan;
+ info->format_type = format_type;
info->format_num = format_num;
info->first_arg_num = first_arg_num;
}
+/* Record information for the names of function that modify the format
+ argument to format functions. FUNCTION_IDENT is the identifier node for
+ the name of the function (its decl need not exist yet) and FORMAT_NUM is
+ the number of the argument which is the format control string (starting
+ from 1). */
+
+static void
+record_international_format (name, assembler_name, format_num)
+ tree name;
+ tree assembler_name;
+ int format_num;
+{
+ international_format_info *info;
+
+ /* Re-use existing structure if it's there. */
+
+ for (info = international_format_list; info; info = info->next)
+ {
+ if (info->name == name && info->assembler_name == assembler_name)
+ break;
+ }
+
+ if (! info)
+ {
+ info
+ = (international_format_info *)
+ xmalloc (sizeof (international_format_info));
+ info->next = international_format_list;
+ international_format_list = info;
+
+ info->name = name;
+ info->assembler_name = assembler_name;
+ }
+
+ info->format_num = format_num;
+}
+
static char tfaff[] = "too few arguments for format";
/* Check the argument list of a call to printf, scanf, etc.
@@ -843,7 +1248,7 @@ check_format_info (info, params)
int i;
int arg_num;
int suppressed, wide, precise;
- int length_char;
+ int length_char = 0;
int format_char;
int format_length;
tree format_tree;
@@ -852,8 +1257,7 @@ check_format_info (info, params)
tree wanted_type;
tree first_fillin_param;
char *format_chars;
- format_char_info *fci;
- static char message[132];
+ format_char_info *fci = NULL;
char flag_chars[8];
int has_operand_number = 0;
@@ -871,9 +1275,43 @@ check_format_info (info, params)
params = TREE_CHAIN (params);
if (format_tree == 0)
return;
+
/* We can only check the format if it's a string constant. */
while (TREE_CODE (format_tree) == NOP_EXPR)
format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */
+
+ if (TREE_CODE (format_tree) == CALL_EXPR
+ && TREE_CODE (TREE_OPERAND (format_tree, 0)) == ADDR_EXPR
+ && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0))
+ == FUNCTION_DECL))
+ {
+ tree function = TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0);
+
+ /* See if this is a call to a known internationalization function
+ that modifies the format arg. */
+ international_format_info *info;
+
+ for (info = international_format_list; info; info = info->next)
+ if (info->assembler_name
+ ? (info->assembler_name == DECL_ASSEMBLER_NAME (function))
+ : (info->name == DECL_NAME (function)))
+ {
+ tree inner_args;
+ int i;
+
+ for (inner_args = TREE_OPERAND (format_tree, 1), i = 1;
+ inner_args != 0;
+ inner_args = TREE_CHAIN (inner_args), i++)
+ if (i == info->format_num)
+ {
+ format_tree = TREE_VALUE (inner_args);
+
+ while (TREE_CODE (format_tree) == NOP_EXPR)
+ format_tree = TREE_OPERAND (format_tree, 0);
+ }
+ }
+ }
+
if (integer_zerop (format_tree))
{
warning ("null format string");
@@ -928,15 +1366,55 @@ check_format_info (info, params)
}
flag_chars[0] = 0;
suppressed = wide = precise = FALSE;
- if (info->is_scan)
+ if (info->format_type == scanf_format_type)
{
suppressed = *format_chars == '*';
if (suppressed)
++format_chars;
- while (isdigit (*format_chars))
+ while (ISDIGIT (*format_chars))
++format_chars;
}
- else
+ else if (info->format_type == strftime_format_type)
+ {
+ while (*format_chars != 0 && index ("_-0^#", *format_chars) != 0)
+ {
+ if (pedantic)
+ warning ("ANSI C does not support the strftime `%c' flag",
+ *format_chars);
+ if (index (flag_chars, *format_chars) != 0)
+ {
+ warning ("repeated `%c' flag in format",
+ *format_chars);
+ ++format_chars;
+ }
+ else
+ {
+ i = strlen (flag_chars);
+ flag_chars[i++] = *format_chars++;
+ flag_chars[i] = 0;
+ }
+ }
+ while (ISDIGIT ((unsigned char) *format_chars))
+ {
+ wide = TRUE;
+ ++format_chars;
+ }
+ if (wide && pedantic)
+ warning ("ANSI C does not support strftime format width");
+ if (*format_chars == 'E' || *format_chars == 'O')
+ {
+ i = strlen (flag_chars);
+ flag_chars[i++] = *format_chars++;
+ flag_chars[i] = 0;
+ if (*format_chars == 'E' || *format_chars == 'O')
+ {
+ warning ("multiple E/O modifiers in format");
+ while (*format_chars == 'E' || *format_chars == 'O')
+ ++format_chars;
+ }
+ }
+ }
+ else if (info->format_type == printf_format_type)
{
/* See if we have a number followed by a dollar sign. If we do,
it is an operand number, so set PARAMS to that operand. */
@@ -969,16 +1447,15 @@ check_format_info (info, params)
while (*format_chars != 0 && index (" +#0-", *format_chars) != 0)
{
if (index (flag_chars, *format_chars) != 0)
+ warning ("repeated `%c' flag in format", *format_chars++);
+ else
{
- sprintf (message, "repeated `%c' flag in format",
- *format_chars);
- warning (message);
+ i = strlen (flag_chars);
+ flag_chars[i++] = *format_chars++;
+ flag_chars[i] = 0;
}
- i = strlen (flag_chars);
- flag_chars[i++] = *format_chars++;
- flag_chars[i] = 0;
}
- /* "If the space and + flags both appear,
+ /* "If the space and + flags both appear,
the space flag will be ignored." */
if (index (flag_chars, ' ') != 0
&& index (flag_chars, '+') != 0)
@@ -1013,17 +1490,12 @@ check_format_info (info, params)
&&
(TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
!= unsigned_type_node))
- {
- sprintf (message,
- "field width is not type int (arg %d)",
- arg_num);
- warning (message);
- }
+ warning ("field width is not type int (arg %d)", arg_num);
}
}
else
{
- while (isdigit (*format_chars))
+ while (ISDIGIT (*format_chars))
{
wide = TRUE;
++format_chars;
@@ -1033,7 +1505,7 @@ check_format_info (info, params)
{
precise = TRUE;
++format_chars;
- if (*format_chars != '*' && !isdigit (*format_chars))
+ if (*format_chars != '*' && !ISDIGIT (*format_chars))
warning ("`.' not followed by `*' or digit in format");
/* "...a...precision...may be indicated by an asterisk.
In this case, an int argument supplies the...precision." */
@@ -1052,84 +1524,137 @@ check_format_info (info, params)
++arg_num;
if (TYPE_MAIN_VARIANT (TREE_TYPE (cur_param))
!= integer_type_node)
- {
- sprintf (message,
- "field width is not type int (arg %d)",
- arg_num);
- warning (message);
- }
+ warning ("field width is not type int (arg %d)",
+ arg_num);
}
}
else
{
- while (isdigit (*format_chars))
+ while (ISDIGIT (*format_chars))
++format_chars;
}
}
}
- if (*format_chars == 'h' || *format_chars == 'l' || *format_chars == 'q' ||
- *format_chars == 'L')
- length_char = *format_chars++;
- else
- length_char = 0;
- if (length_char == 'l' && *format_chars == 'l')
- length_char = 'q', format_chars++;
+
aflag = 0;
- if (*format_chars == 'a')
- {
- aflag = 1;
- format_chars++;
- }
- if (suppressed && length_char != 0)
+
+ if (info->format_type != strftime_format_type)
{
- sprintf (message,
- "use of `*' and `%c' together in format",
- length_char);
- warning (message);
+ if (*format_chars == 'h' || *format_chars == 'l')
+ length_char = *format_chars++;
+ else if (*format_chars == 'q' || *format_chars == 'L')
+ {
+ length_char = *format_chars++;
+ if (pedantic)
+ warning ("ANSI C does not support the `%c' length modifier",
+ length_char);
+ }
+ else if (*format_chars == 'Z')
+ {
+ length_char = *format_chars++;
+ if (pedantic)
+ warning ("ANSI C does not support the `Z' length modifier");
+ }
+ else
+ length_char = 0;
+ if (length_char == 'l' && *format_chars == 'l')
+ {
+ length_char = 'q', format_chars++;
+ /* FIXME: Is allowed in ISO C 9x. */
+ if (pedantic)
+ warning ("ANSI C does not support the `ll' length modifier");
+ }
+ else if (length_char == 'h' && *format_chars == 'h')
+ {
+ length_char = 'H', format_chars++;
+ /* FIXME: Is allowed in ISO C 9x. */
+ if (pedantic)
+ warning ("ANSI C does not support the `hh' length modifier");
+ }
+ if (*format_chars == 'a' && info->format_type == scanf_format_type)
+ {
+ if (format_chars[1] == 's' || format_chars[1] == 'S'
+ || format_chars[1] == '[')
+ {
+ /* `a' is used as a flag. */
+ aflag = 1;
+ format_chars++;
+ }
+ }
+ if (suppressed && length_char != 0)
+ warning ("use of `*' and `%c' together in format", length_char);
}
format_char = *format_chars;
- if (format_char == 0)
+ if (format_char == 0
+ || (info->format_type != strftime_format_type && format_char == '%'))
{
warning ("conversion lacks type at end of format");
continue;
}
+ /* The m, C, and S formats are GNU extensions. */
+ if (pedantic && info->format_type != strftime_format_type
+ && (format_char == 'm' || format_char == 'C' || format_char == 'S'))
+ warning ("ANSI C does not support the `%c' format", format_char);
+ /* ??? The a and A formats are C9X extensions, and should be allowed
+ when a C9X option is added. */
+ if (pedantic && info->format_type != strftime_format_type
+ && (format_char == 'a' || format_char == 'A'))
+ warning ("ANSI C does not support the `%c' format", format_char);
format_chars++;
- fci = info->is_scan ? scan_char_table : print_char_table;
+ switch (info->format_type)
+ {
+ case printf_format_type:
+ fci = print_char_table;
+ break;
+ case scanf_format_type:
+ fci = scan_char_table;
+ break;
+ case strftime_format_type:
+ fci = time_char_table;
+ break;
+ default:
+ abort ();
+ }
while (fci->format_chars != 0
&& index (fci->format_chars, format_char) == 0)
++fci;
if (fci->format_chars == 0)
{
if (format_char >= 040 && format_char < 0177)
- sprintf (message,
- "unknown conversion type character `%c' in format",
+ warning ("unknown conversion type character `%c' in format",
format_char);
else
- sprintf (message,
- "unknown conversion type character 0x%x in format",
+ warning ("unknown conversion type character 0x%x in format",
format_char);
- warning (message);
continue;
}
- if (wide && index (fci->flag_chars, 'w') == 0)
+ if (pedantic)
{
- sprintf (message, "width used with `%c' format",
- format_char);
- warning (message);
+ if (index (fci->flag_chars, 'G') != 0)
+ warning ("ANSI C does not support `%%%c'", format_char);
+ if (index (fci->flag_chars, 'o') != 0
+ && index (flag_chars, 'O') != 0)
+ warning ("ANSI C does not support `%%O%c'", format_char);
}
+ if (wide && index (fci->flag_chars, 'w') == 0)
+ warning ("width used with `%c' format", format_char);
+ if (index (fci->flag_chars, '2') != 0)
+ warning ("`%%%c' yields only last 2 digits of year", format_char);
+ else if (index (fci->flag_chars, '3') != 0)
+ warning ("`%%%c' yields only last 2 digits of year in some locales",
+ format_char);
if (precise && index (fci->flag_chars, 'p') == 0)
- {
- sprintf (message, "precision used with `%c' format",
- format_char);
- warning (message);
- }
+ warning ("precision used with `%c' format", format_char);
if (aflag && index (fci->flag_chars, 'a') == 0)
{
- sprintf (message, "`a' flag used with `%c' format",
- format_char);
- warning (message);
+ warning ("`a' flag used with `%c' format", format_char);
+ /* To simplify the following code. */
+ aflag = 0;
}
- if (info->is_scan && format_char == '[')
+ /* The a flag is a GNU extension. */
+ else if (pedantic && aflag)
+ warning ("ANSI C does not support the `a' flag");
+ if (info->format_type == scanf_format_type && format_char == '[')
{
/* Skip over scan set, in case it happens to have '%' in it. */
if (*format_chars == '^')
@@ -1141,63 +1666,42 @@ check_format_info (info, params)
while (*format_chars && *format_chars != ']')
++format_chars;
if (*format_chars != ']')
- /* The end of the format string was reached. */
- warning ("no closing `]' for `%%[' format");
+ /* The end of the format string was reached. */
+ warning ("no closing `]' for `%%[' format");
}
if (suppressed)
{
if (index (fci->flag_chars, '*') == 0)
- {
- sprintf (message,
- "suppression of `%c' conversion in format",
- format_char);
- warning (message);
- }
+ warning ("suppression of `%c' conversion in format", format_char);
continue;
}
for (i = 0; flag_chars[i] != 0; ++i)
{
if (index (fci->flag_chars, flag_chars[i]) == 0)
- {
- sprintf (message, "flag `%c' used with type `%c'",
- flag_chars[i], format_char);
- warning (message);
- }
+ warning ("flag `%c' used with type `%c'",
+ flag_chars[i], format_char);
}
+ if (info->format_type == strftime_format_type)
+ continue;
if (precise && index (flag_chars, '0') != 0
&& (format_char == 'd' || format_char == 'i'
|| format_char == 'o' || format_char == 'u'
|| format_char == 'x' || format_char == 'x'))
- {
- sprintf (message,
- "precision and `0' flag not both allowed with `%c' format",
- format_char);
- warning (message);
- }
+ warning ("`0' flag ignored with precision specifier and `%c' format",
+ format_char);
switch (length_char)
{
default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break;
+ case 'H': wanted_type = fci->hhlen ? *(fci->hhlen) : 0; break;
case 'h': wanted_type = fci->hlen ? *(fci->hlen) : 0; break;
case 'l': wanted_type = fci->llen ? *(fci->llen) : 0; break;
case 'q': wanted_type = fci->qlen ? *(fci->qlen) : 0; break;
case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break;
+ case 'Z': wanted_type = fci->zlen ? *fci->zlen : 0; break;
}
if (wanted_type == 0)
- {
- sprintf (message,
- "use of `%c' length character with `%c' type character",
- length_char, format_char);
- warning (message);
- }
-
- /*
- ** XXX -- should kvetch about stuff such as
- ** {
- ** const int i;
- **
- ** scanf ("%d", &i);
- ** }
- */
+ warning ("use of `%c' length character with `%c' type character",
+ length_char, format_char);
/* Finally. . .check type of argument against desired type! */
if (info->first_arg_num == 0)
@@ -1215,28 +1719,48 @@ check_format_info (info, params)
++arg_num;
cur_type = TREE_TYPE (cur_param);
+ STRIP_NOPS (cur_param);
+
/* Check the types of any additional pointer arguments
that precede the "real" argument. */
- for (i = 0; i < fci->pointer_count; ++i)
+ for (i = 0; i < fci->pointer_count + aflag; ++i)
{
if (TREE_CODE (cur_type) == POINTER_TYPE)
{
cur_type = TREE_TYPE (cur_type);
+
+ if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
+ cur_param = TREE_OPERAND (cur_param, 0);
+ else
+ cur_param = 0;
+
continue;
}
if (TREE_CODE (cur_type) != ERROR_MARK)
- {
- sprintf (message,
- "format argument is not a %s (arg %d)",
- ((fci->pointer_count == 1) ? "pointer" : "pointer to a pointer"),
- arg_num);
- warning (message);
- }
+ warning ("format argument is not a %s (arg %d)",
+ ((fci->pointer_count + aflag == 1)
+ ? "pointer" : "pointer to a pointer"),
+ arg_num);
break;
}
+ /* See if this is an attempt to write into a const type with
+ scanf or with printf "%n". */
+ if ((info->format_type == scanf_format_type
+ || (info->format_type == printf_format_type
+ && format_char == 'n'))
+ && i == fci->pointer_count + aflag
+ && wanted_type != 0
+ && TREE_CODE (cur_type) != ERROR_MARK
+ && (TYPE_READONLY (cur_type)
+ || (cur_param != 0
+ && (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c'
+ || (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'd'
+ && TREE_READONLY (cur_param))))))
+ warning ("writing into constant object (arg %d)", arg_num);
+
/* Check the type of the "real" argument, if there's a type we want. */
- if (i == fci->pointer_count && wanted_type != 0
+ if (i == fci->pointer_count + aflag && wanted_type != 0
&& TREE_CODE (cur_type) != ERROR_MARK
&& wanted_type != TYPE_MAIN_VARIANT (cur_type)
/* If we want `void *', allow any pointer type.
@@ -1257,7 +1781,7 @@ check_format_info (info, params)
{
register char *this;
register char *that;
-
+
this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
that = 0;
if (TREE_CODE (cur_type) != ERROR_MARK
@@ -1293,11 +1817,7 @@ check_format_info (info, params)
that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (cur_type)));
if (strcmp (this, that) != 0)
- {
- sprintf (message, "%s format, %s arg (arg %d)",
- this, that, arg_num);
- warning (message);
- }
+ warning ("%s format, %s arg (arg %d)", this, that, arg_num);
}
}
}
@@ -1335,7 +1855,8 @@ overflow_warning (value)
&& TREE_OVERFLOW (value))
{
TREE_OVERFLOW (value) = 0;
- warning ("integer overflow in expression");
+ if (skip_evaluation == 0)
+ warning ("integer overflow in expression");
}
else if ((TREE_CODE (value) == REAL_CST
|| (TREE_CODE (value) == COMPLEX_CST
@@ -1343,7 +1864,8 @@ overflow_warning (value)
&& TREE_OVERFLOW (value))
{
TREE_OVERFLOW (value) = 0;
- warning ("floating-pointer overflow in expression");
+ if (skip_evaluation == 0)
+ warning ("floating point overflow in expression");
}
}
@@ -1359,6 +1881,7 @@ unsigned_conversion_warning (result, operand)
if (TREE_CODE (operand) == INTEGER_CST
&& TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
&& TREE_UNSIGNED (TREE_TYPE (result))
+ && skip_evaluation == 0
&& !int_fits_type_p (operand, TREE_TYPE (result)))
{
if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
@@ -1394,9 +1917,10 @@ convert_and_check (type, expr)
&& TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr))))
/* If EXPR fits in the unsigned version of TYPE,
don't warn unless pedantic. */
- if (pedantic
- || TREE_UNSIGNED (type)
- || ! int_fits_type_p (expr, unsigned_type (type)))
+ if ((pedantic
+ || TREE_UNSIGNED (type)
+ || ! int_fits_type_p (expr, unsigned_type (type)))
+ && skip_evaluation == 0)
warning ("overflow in implicit constant conversion");
}
else
@@ -1525,6 +2049,9 @@ type_for_mode (mode, unsignedp)
if (mode == TYPE_MODE (intDI_type_node))
return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+ if (mode == TYPE_MODE (intTI_type_node))
+ return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
+
if (mode == TYPE_MODE (float_type_node))
return float_type_node;
@@ -1581,7 +2108,7 @@ void
binary_op_error (code)
enum tree_code code;
{
- register char *opname = "unknown";
+ register char *opname;
switch (code)
{
@@ -1634,6 +2161,8 @@ binary_op_error (code)
case LROTATE_EXPR:
case RROTATE_EXPR:
opname = "rotate"; break;
+ default:
+ opname = "unknown"; break;
}
error ("invalid operands to binary %s", opname);
}
@@ -1720,6 +2249,8 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
case GE_EXPR:
code = LE_EXPR;
break;
+ default:
+ break;
}
*rescode_ptr = code;
}
@@ -1753,6 +2284,12 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0));
+ /* If TYPE is an enumeration, then we need to get its min/max
+ values from it's underlying integral type, not the enumerated
+ type itself. */
+ if (TREE_CODE (type) == ENUMERAL_TYPE)
+ type = type_for_size (TYPE_PRECISION (type), unsignedp0);
+
maxval = TYPE_MAX_VALUE (type);
minval = TYPE_MIN_VALUE (type);
@@ -1850,6 +2387,9 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
primop1 = TYPE_MAX_VALUE (type);
val = 0;
break;
+
+ default:
+ break;
}
type = unsigned_type (type);
}
@@ -1947,6 +2487,10 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
primop0))))
warning ("unsigned value < 0 is always 0");
value = boolean_false_node;
+ break;
+
+ default:
+ break;
}
if (value != 0)
@@ -2048,6 +2592,12 @@ truthvalue_conversion (expr)
return real_zerop (expr) ? boolean_false_node : boolean_true_node;
case ADDR_EXPR:
+ /* If we are taking the address of a external decl, it might be zero
+ if it is weak, so we cannot optimize. */
+ if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (expr, 0))) == 'd'
+ && DECL_EXTERNAL (TREE_OPERAND (expr, 0)))
+ break;
+
if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))
return build (COMPOUND_EXPR, boolean_type_node,
TREE_OPERAND (expr, 0), boolean_true_node);
@@ -2077,7 +2627,7 @@ truthvalue_conversion (expr)
truthvalue_conversion (TREE_OPERAND (expr, 0)));
else
return truthvalue_conversion (TREE_OPERAND (expr, 0));
-
+
case COND_EXPR:
/* Distribute the conversion into the arms of a COND_EXPR. */
return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0),
@@ -2090,7 +2640,7 @@ truthvalue_conversion (expr)
if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
|| TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
break;
- /* fall through... */
+ /* fall through... */
case NOP_EXPR:
/* If this is widening the argument, we can ignore it. */
if (TYPE_PRECISION (TREE_TYPE (expr))
@@ -2104,7 +2654,7 @@ truthvalue_conversion (expr)
if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
&& TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
break;
- /* fall through... */
+ /* fall through... */
case BIT_XOR_EXPR:
/* This and MINUS_EXPR can be changed into a comparison of the
two objects. */
@@ -2128,19 +2678,26 @@ truthvalue_conversion (expr)
if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR)
warning ("suggest parentheses around assignment used as truth value");
break;
+
+ default:
+ break;
}
if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
- return (build_binary_op
- ((TREE_SIDE_EFFECTS (expr)
- ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
- truthvalue_conversion (build_unary_op (REALPART_EXPR, expr, 0)),
- truthvalue_conversion (build_unary_op (IMAGPART_EXPR, expr, 0)),
- 0));
+ {
+ tree tem = save_expr (expr);
+ return (build_binary_op
+ ((TREE_SIDE_EFFECTS (expr)
+ ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
+ truthvalue_conversion (build_unary_op (REALPART_EXPR, tem, 0)),
+ truthvalue_conversion (build_unary_op (IMAGPART_EXPR, tem, 0)),
+ 0));
+ }
return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
}
+#if USE_CPPLIB
/* Read the rest of a #-directive from input stream FINPUT.
In normal use, the directive name and the white space after it
have already been read, so they won't be included in the result.
@@ -2150,6 +2707,107 @@ truthvalue_conversion (expr)
The value is a string in a reusable buffer. It remains valid
only until the next time this function is called. */
+unsigned char *yy_cur, *yy_lim;
+
+#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ())
+#define UNGETC(c) ((c), yy_cur--)
+
+int
+yy_get_token ()
+{
+ for (;;)
+ {
+ parse_in.limit = parse_in.token_buffer;
+ cpp_token = cpp_get_token (&parse_in);
+ if (cpp_token == CPP_EOF)
+ return -1;
+ yy_lim = CPP_PWRITTEN (&parse_in);
+ yy_cur = parse_in.token_buffer;
+ if (yy_cur < yy_lim)
+ return *yy_cur++;
+ }
+}
+
+char *
+get_directive_line ()
+{
+ static char *directive_buffer = NULL;
+ static unsigned buffer_length = 0;
+ register char *p;
+ register char *buffer_limit;
+ register int looking_for = 0;
+ register int char_escaped = 0;
+
+ if (buffer_length == 0)
+ {
+ directive_buffer = (char *)xmalloc (128);
+ buffer_length = 128;
+ }
+
+ buffer_limit = &directive_buffer[buffer_length];
+
+ for (p = directive_buffer; ; )
+ {
+ int c;
+
+ /* Make buffer bigger if it is full. */
+ if (p >= buffer_limit)
+ {
+ register unsigned bytes_used = (p - directive_buffer);
+
+ buffer_length *= 2;
+ directive_buffer
+ = (char *)xrealloc (directive_buffer, buffer_length);
+ p = &directive_buffer[bytes_used];
+ buffer_limit = &directive_buffer[buffer_length];
+ }
+
+ c = GETC ();
+
+ /* Discard initial whitespace. */
+ if ((c == ' ' || c == '\t') && p == directive_buffer)
+ continue;
+
+ /* Detect the end of the directive. */
+ if (c == '\n' && looking_for == 0)
+ {
+ UNGETC (c);
+ c = '\0';
+ }
+
+ *p++ = c;
+
+ if (c == 0)
+ return directive_buffer;
+
+ /* Handle string and character constant syntax. */
+ if (looking_for)
+ {
+ if (looking_for == c && !char_escaped)
+ looking_for = 0; /* Found terminator... stop looking. */
+ }
+ else
+ if (c == '\'' || c == '"')
+ looking_for = c; /* Don't stop buffering until we see another
+ another one of these (or an EOF). */
+
+ /* Handle backslash. */
+ char_escaped = (c == '\\' && ! char_escaped);
+ }
+}
+#else
+/* Read the rest of a #-directive from input stream FINPUT.
+ In normal use, the directive name and the white space after it
+ have already been read, so they won't be included in the result.
+ We allow for the fact that the directive line may contain
+ a newline embedded within a character or string literal which forms
+ a part of the directive.
+
+ The value is a string in a reusable buffer. It remains valid
+ only until the next time this function is called.
+
+ The terminating character ('\n' or EOF) is left in FINPUT for the
+ caller to re-read. */
char *
get_directive_line (finput)
@@ -2193,7 +2851,8 @@ get_directive_line (finput)
continue;
/* Detect the end of the directive. */
- if (c == '\n' && looking_for == 0)
+ if (looking_for == 0
+ && (c == '\n' || c == EOF))
{
ungetc (c, finput);
c = '\0';
@@ -2213,12 +2872,13 @@ get_directive_line (finput)
else
if (c == '\'' || c == '"')
looking_for = c; /* Don't stop buffering until we see another
- another one of these (or an EOF). */
+ one of these (or an EOF). */
/* Handle backslash. */
char_escaped = (c == '\\' && ! char_escaped);
}
}
+#endif /* !USE_CPPLIB */
/* Make a variant type in the proper way for C/C++, propagating qualifiers
down to the element type of an array. */
@@ -2229,27 +2889,95 @@ c_build_type_variant (type, constp, volatilep)
int constp, volatilep;
{
if (TREE_CODE (type) == ARRAY_TYPE)
- {
- tree real_main_variant = TYPE_MAIN_VARIANT (type);
+ return build_array_type (c_build_type_variant (TREE_TYPE (type),
+ constp, volatilep),
+ TYPE_DOMAIN (type));
+ return build_type_variant (type, constp, volatilep);
+}
+
+/* Return the typed-based alias set for T, which may be an expression
+ or a type. */
- push_obstacks (TYPE_OBSTACK (real_main_variant),
- TYPE_OBSTACK (real_main_variant));
- type = build_array_type (c_build_type_variant (TREE_TYPE (type),
- constp, volatilep),
- TYPE_DOMAIN (type));
+int
+c_get_alias_set (t)
+ tree t;
+{
+ static int next_set = 0;
+ tree type;
+
+ if (t == error_mark_node)
+ return 0;
+
+ type = (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
+ ? t : TREE_TYPE (t);
+
+ if (type == error_mark_node)
+ return 0;
+
+ if (TYPE_ALIAS_SET_KNOWN_P (type))
+ /* If we've already calculated the value, just return it. */
+ return TYPE_ALIAS_SET (type);
+
+ if (TREE_CODE (t) == BIT_FIELD_REF)
+ /* Perhaps reads and writes to this piece of data alias fields
+ neighboring the bitfield. Perhaps that's impossible. For now,
+ let's just assume that bitfields can alias everything, which is
+ the conservative assumption. */
+ return 0;
+ if (TREE_CODE (t) == COMPONENT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == UNION_TYPE)
+ /* Permit type-punning when accessing a union, provided the
+ access is directly through the union. For example, this code does
+ not permit taking the address of a union member and then
+ storing through it. Even the type-punning allowed here is a
+ GCC extension, albeit a common and useful one; the C standard
+ says that such accesses have implementation-defined behavior. */
+ return 0;
+ else if (TYPE_MAIN_VARIANT (type) != type)
+ {
+ /* The C standard specifically allows aliasing between
+ cv-qualified variants of types. */
+ TYPE_ALIAS_SET (type) = c_get_alias_set (TYPE_MAIN_VARIANT (type));
+ return TYPE_ALIAS_SET (type);
+ }
+ else if (TREE_CODE (type) == INTEGER_TYPE)
+ {
+ tree signed_variant;
- /* TYPE must be on same obstack as REAL_MAIN_VARIANT. If not,
- make a copy. (TYPE might have come from the hash table and
- REAL_MAIN_VARIANT might be in some function's obstack.) */
+ /* The C standard specifically allows aliasing between signed and
+ unsigned variants of the same type. We treat the signed
+ variant as canonical. */
+ signed_variant = signed_type (type);
- if (TYPE_OBSTACK (type) != TYPE_OBSTACK (real_main_variant))
+ if (signed_variant != type)
{
- type = copy_node (type);
- TYPE_POINTER_TO (type) = TYPE_REFERENCE_TO (type) = 0;
+ TYPE_ALIAS_SET (type) = c_get_alias_set (signed_variant);
+ return TYPE_ALIAS_SET (type);
+ }
+ else if (signed_variant == signed_char_type_node)
+ /* The C standard guarantess that any object may be accessed
+ via an lvalue that has character type. We don't have to
+ check for unsigned_char_type_node or char_type_node because
+ we are specifically looking at the signed variant. */
+ {
+ TYPE_ALIAS_SET (type) = 0;
+ return TYPE_ALIAS_SET (type);
}
-
- TYPE_MAIN_VARIANT (type) = real_main_variant;
- pop_obstacks ();
}
- return build_type_variant (type, constp, volatilep);
+ else if (TREE_CODE (type) == RECORD_TYPE
+ || TREE_CODE (type) == UNION_TYPE)
+ {
+ /* If TYPE is a struct or union type then we're reading or
+ writing an entire struct. Thus, we don't know anything about
+ aliasing. (In theory, such an access can only alias objects
+ whose type is the same as one of the fields, recursively, but
+ we don't yet make any use of that information.) */
+ TYPE_ALIAS_SET (type) = 0;
+ return TYPE_ALIAS_SET (type);
+ }
+
+ /* TYPE is something we haven't seen before. Put it in a new alias
+ set. */
+ TYPE_ALIAS_SET (type) = ++next_set;
+ return TYPE_ALIAS_SET (type);
}
diff --git a/contrib/gcc/c-convert.c b/contrib/gcc/c-convert.c
index 8ba93a9..6f58e76 100644
--- a/contrib/gcc/c-convert.c
+++ b/contrib/gcc/c-convert.c
@@ -28,6 +28,7 @@ Boston, MA 02111-1307, USA. */
#include "tree.h"
#include "flags.h"
#include "convert.h"
+#include "toplev.h"
/* Change of width--truncation and extension of integers or reals--
is represented with NOP_EXPR. Proper functioning of many things
diff --git a/contrib/gcc/c-decl.c b/contrib/gcc/c-decl.c
index ca33a4c..ccaa7d2 100644
--- a/contrib/gcc/c-decl.c
+++ b/contrib/gcc/c-decl.c
@@ -1,5 +1,5 @@
/* Process declarations and variables for C compiler.
- Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1988, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -27,12 +27,20 @@ Boston, MA 02111-1307, USA. */
line numbers. For example, the CONST_DECLs for enum values. */
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "flags.h"
#include "output.h"
#include "c-tree.h"
#include "c-lex.h"
-#include <stdio.h>
+#include "toplev.h"
+
+#if USE_CPPLIB
+#include "cpplib.h"
+extern cpp_reader parse_in;
+extern cpp_options parse_options;
+static int cpp_initialized;
+#endif
/* In grokdeclarator, distinguish syntactic contexts of declarators. */
enum decl_context
@@ -143,11 +151,13 @@ tree intQI_type_node;
tree intHI_type_node;
tree intSI_type_node;
tree intDI_type_node;
+tree intTI_type_node;
tree unsigned_intQI_type_node;
tree unsigned_intHI_type_node;
tree unsigned_intSI_type_node;
tree unsigned_intDI_type_node;
+tree unsigned_intTI_type_node;
/* a VOID_TYPE node. */
@@ -411,16 +421,20 @@ tree static_ctors, static_dtors;
/* Forward declarations. */
-static tree grokparms (), grokdeclarator ();
-tree pushdecl ();
-tree builtin_function ();
-void shadow_tag_warned ();
-
-static tree lookup_tag ();
-static tree lookup_tag_reverse ();
-tree lookup_name_current_level ();
-static char *redeclaration_error_message ();
-static void layout_array_type ();
+static struct binding_level * make_binding_level PROTO((void));
+static void clear_limbo_values PROTO((tree));
+static int duplicate_decls PROTO((tree, tree, int));
+static char *redeclaration_error_message PROTO((tree, tree));
+static void storedecls PROTO((tree));
+static void storetags PROTO((tree));
+static tree lookup_tag PROTO((enum tree_code, tree,
+ struct binding_level *, int));
+static tree lookup_tag_reverse PROTO((tree));
+static tree grokdeclarator PROTO((tree, tree, enum decl_context,
+ int));
+static tree grokparms PROTO((tree, int));
+static int field_decl_cmp PROTO((const GENERIC_PTR, const GENERIC_PTR));
+static void layout_array_type PROTO((tree));
/* C-specific option variables. */
@@ -450,8 +464,12 @@ int flag_no_nonansi_builtin;
int flag_traditional;
+/* Nonzero means that we have builtin functions, and main is an int */
+
+int flag_hosted = 1;
+
/* Nonzero means to allow single precision math even if we're generally
- being traditional. */
+ being traditional. */
int flag_allow_single_precision = 0;
/* Nonzero means to treat bitfields as signed unless they say `unsigned'. */
@@ -463,9 +481,18 @@ int explicit_flag_signed_bitfields = 0;
int flag_no_ident = 0;
-/* Nonzero means warn about implicit declarations. */
+/* Nonzero means warn about use of implicit int. */
+
+int warn_implicit_int;
+
+/* Nonzero means warn about usage of long long when `-pedantic'. */
+
+int warn_long_long = 1;
-int warn_implicit;
+/* Nonzero means message about use of implicit function declarations;
+ 1 means warning; 2 means error. */
+
+int mesg_implicit_function_declaration;
/* Nonzero means give string constants the type `const char *'
to get extra warnings from them. These warnings will be too numerous
@@ -521,7 +548,7 @@ int warn_redundant_decls = 0;
int warn_nested_externs = 0;
-/* Warn about *printf or *scanf format/argument anomalies. */
+/* Warn about *printf or *scanf format/argument anomalies. */
int warn_format;
@@ -541,44 +568,80 @@ int warn_parentheses;
int warn_missing_braces;
-/* Nonzero means `$' can be in an identifier.
- See cccp.c for reasons why this breaks some obscure ANSI C programs. */
+/* Warn if main is suspicious. */
+
+int warn_main;
+
+/* Warn about #pragma directives that are not recognised. */
+
+int warn_unknown_pragmas = 0; /* Tri state variable. */
+
+/* Warn about comparison of signed and unsigned values.
+ If -1, neither -Wsign-compare nor -Wno-sign-compare has been specified. */
+
+int warn_sign_compare = -1;
+
+/* Nonzero means warn about use of multicharacter literals. */
+
+int warn_multichar = 1;
+
+/* Nonzero means `$' can be in an identifier. */
#ifndef DOLLARS_IN_IDENTIFIERS
#define DOLLARS_IN_IDENTIFIERS 1
#endif
-int dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 1;
+int dollars_in_ident = DOLLARS_IN_IDENTIFIERS;
/* Decode the string P as a language-specific option for C.
- Return 1 if it is recognized (and handle it);
- return 0 if not recognized. */
+ Return the number of strings consumed. */
int
-c_decode_option (p)
- char *p;
+c_decode_option (argc, argv)
+ int argc;
+ char **argv;
{
+ int strings_processed;
+ char *p = argv[0];
+#if USE_CPPLIB
+ if (! cpp_initialized)
+ {
+ cpp_reader_init (&parse_in);
+ parse_in.data = &parse_options;
+ cpp_options_init (&parse_options);
+ cpp_initialized = 1;
+ }
+ strings_processed = cpp_handle_option (&parse_in, argc, argv);
+#else
+ strings_processed = 0;
+#endif /* ! USE_CPPLIB */
+
if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional"))
{
flag_traditional = 1;
flag_writable_strings = 1;
-#if DOLLARS_IN_IDENTIFIERS > 0
- dollars_in_ident = 1;
-#endif
}
else if (!strcmp (p, "-fallow-single-precision"))
flag_allow_single_precision = 1;
+ else if (!strcmp (p, "-fhosted") || !strcmp (p, "-fno-freestanding"))
+ {
+ flag_hosted = 1;
+ flag_no_builtin = 0;
+ }
+ else if (!strcmp (p, "-ffreestanding") || !strcmp (p, "-fno-hosted"))
+ {
+ flag_hosted = 0;
+ flag_no_builtin = 1;
+ /* warn_main will be 2 if set by -Wall, 1 if set by -Wmain */
+ if (warn_main == 2)
+ warn_main = 0;
+ }
else if (!strcmp (p, "-fnotraditional") || !strcmp (p, "-fno-traditional"))
{
flag_traditional = 0;
flag_writable_strings = 0;
- dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 1;
}
else if (!strcmp (p, "-fdollars-in-identifiers"))
- {
-#if DOLLARS_IN_IDENTIFIERS > 0
- dollars_in_ident = 1;
-#endif
- }
+ dollars_in_ident = 1;
else if (!strcmp (p, "-fno-dollars-in-identifiers"))
dollars_in_ident = 0;
else if (!strcmp (p, "-fsigned-char"))
@@ -626,11 +689,29 @@ c_decode_option (p)
else if (!strcmp (p, "-fident"))
flag_no_ident = 0;
else if (!strcmp (p, "-ansi"))
- flag_no_asm = 1, flag_no_nonansi_builtin = 1, dollars_in_ident = 0;
+ flag_no_asm = 1, flag_no_nonansi_builtin = 1;
+ else if (!strcmp (p, "-Werror-implicit-function-declaration"))
+ mesg_implicit_function_declaration = 2;
+ else if (!strcmp (p, "-Wimplicit-function-declaration"))
+ mesg_implicit_function_declaration = 1;
+ else if (!strcmp (p, "-Wno-implicit-function-declaration"))
+ mesg_implicit_function_declaration = 0;
+ else if (!strcmp (p, "-Wimplicit-int"))
+ warn_implicit_int = 1;
+ else if (!strcmp (p, "-Wno-implicit-int"))
+ warn_implicit_int = 0;
else if (!strcmp (p, "-Wimplicit"))
- warn_implicit = 1;
+ {
+ warn_implicit_int = 1;
+ if (mesg_implicit_function_declaration != 2)
+ mesg_implicit_function_declaration = 1;
+ }
else if (!strcmp (p, "-Wno-implicit"))
- warn_implicit = 0;
+ warn_implicit_int = 0, mesg_implicit_function_declaration = 0;
+ else if (!strcmp (p, "-Wlong-long"))
+ warn_long_long = 1;
+ else if (!strcmp (p, "-Wno-long-long"))
+ warn_long_long = 0;
else if (!strcmp (p, "-Wwrite-strings"))
warn_write_strings = 1;
else if (!strcmp (p, "-Wno-write-strings"))
@@ -703,6 +784,10 @@ c_decode_option (p)
; /* cpp handles this one. */
else if (!strcmp (p, "-Wno-trigraphs"))
; /* cpp handles this one. */
+ else if (!strcmp (p, "-Wundef"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (p, "-Wno-undef"))
+ ; /* cpp handles this one. */
else if (!strcmp (p, "-Wimport"))
; /* cpp handles this one. */
else if (!strcmp (p, "-Wno-import"))
@@ -711,6 +796,24 @@ c_decode_option (p)
warn_missing_braces = 1;
else if (!strcmp (p, "-Wno-missing-braces"))
warn_missing_braces = 0;
+ else if (!strcmp (p, "-Wmain"))
+ warn_main = 1;
+ else if (!strcmp (p, "-Wno-main"))
+ warn_main = 0;
+ else if (!strcmp (p, "-Wsign-compare"))
+ warn_sign_compare = 1;
+ else if (!strcmp (p, "-Wno-sign-compare"))
+ warn_sign_compare = 0;
+ else if (!strcmp (p, "-Wmultichar"))
+ warn_multichar = 1;
+ else if (!strcmp (p, "-Wno-multichar"))
+ warn_multichar = 0;
+ else if (!strcmp (p, "-Wunknown-pragmas"))
+ /* Set to greater than 1, so that even unknown pragmas in system
+ headers will be warned about. */
+ warn_unknown_pragmas = 2;
+ else if (!strcmp (p, "-Wno-unknown-pragmas"))
+ warn_unknown_pragmas = 0;
else if (!strcmp (p, "-Wall"))
{
/* We save the value of warn_uninitialized, since if they put
@@ -718,7 +821,8 @@ c_decode_option (p)
warning about not using it without also specifying -O. */
if (warn_uninitialized != 1)
warn_uninitialized = 2;
- warn_implicit = 1;
+ warn_implicit_int = 1;
+ mesg_implicit_function_declaration = 1;
warn_return_type = 1;
warn_unused = 1;
warn_switch = 1;
@@ -726,9 +830,14 @@ c_decode_option (p)
warn_char_subscripts = 1;
warn_parentheses = 1;
warn_missing_braces = 1;
+ /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding can turn
+ it off only if it's not explicit. */
+ warn_main = 2;
+ /* Only warn about unknown pragmas that are not in system headers. */
+ warn_unknown_pragmas = 1;
}
else
- return 0;
+ return strings_processed;
return 1;
}
@@ -737,17 +846,17 @@ c_decode_option (p)
void
print_lang_decl (file, node, indent)
- FILE *file;
- tree node;
- int indent;
+ FILE *file ATTRIBUTE_UNUSED;
+ tree node ATTRIBUTE_UNUSED;
+ int indent ATTRIBUTE_UNUSED;
{
}
void
print_lang_type (file, node, indent)
- FILE *file;
- tree node;
- int indent;
+ FILE *file ATTRIBUTE_UNUSED;
+ tree node ATTRIBUTE_UNUSED;
+ int indent ATTRIBUTE_UNUSED;
{
}
@@ -772,13 +881,16 @@ void
finish_incomplete_decl (decl)
tree decl;
{
- if (TREE_CODE (decl) == VAR_DECL && TREE_TYPE (decl) != error_mark_node)
+ if (TREE_CODE (decl) == VAR_DECL)
{
tree type = TREE_TYPE (decl);
- if (TREE_CODE (type) == ARRAY_TYPE
- && TYPE_DOMAIN (type) == 0
- && TREE_CODE (decl) != TYPE_DECL)
+ if (type != error_mark_node
+ && TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_DOMAIN (type) == 0)
{
+ if (! DECL_EXTERNAL (decl))
+ warning_with_decl (decl, "array `%s' assumed to have one element");
+
complete_array_type (type, NULL_TREE, 1);
layout_decl (decl, 0);
@@ -890,6 +1002,22 @@ pushlevel (tag_transparent)
keep_next_if_subblocks = 0;
}
+/* Clear the limbo values of all identifiers defined in BLOCK or a subblock. */
+
+static void
+clear_limbo_values (block)
+ tree block;
+{
+ tree tem;
+
+ for (tem = BLOCK_VARS (block); tem; tem = TREE_CHAIN (tem))
+ if (DECL_NAME (tem) != 0)
+ IDENTIFIER_LIMBO_VALUE (DECL_NAME (tem)) = 0;
+
+ for (tem = BLOCK_SUBBLOCKS (block); tem; tem = TREE_CHAIN (tem))
+ clear_limbo_values (tem);
+}
+
/* Exit a binding level.
Pop the level off, and restore the state of the identifier-decl mappings
that were in effect when this level was entered.
@@ -980,7 +1108,7 @@ poplevel (keep, reverse, functionbody)
if (DECL_ABSTRACT_ORIGIN (decl) != 0
&& DECL_ABSTRACT_ORIGIN (decl) != decl)
TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1;
- else
+ else if (DECL_SAVED_INSNS (decl) != 0)
{
push_function_context ();
output_inline_function (decl);
@@ -1043,6 +1171,8 @@ poplevel (keep, reverse, functionbody)
if (functionbody)
{
+ clear_limbo_values (block);
+
/* If this is the top level block of a function,
the vars are the function's parameters.
Don't leave them in the BLOCK because they are
@@ -1299,6 +1429,10 @@ pushtag (name, type)
tagged type. */
TYPE_STUB_DECL (type) = pushdecl (build_decl (TYPE_DECL, NULL_TREE, type));
+
+ /* An approximation for now, so we can tell this is a function-scope tag.
+ This will be updated in poplevel. */
+ TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type));
}
/* Handle when a new declaration NEWDECL
@@ -1307,11 +1441,15 @@ pushtag (name, type)
Prints an error message if appropriate.
If safely possible, alter OLDDECL to look like NEWDECL, and return 1.
- Otherwise, return 0. */
+ Otherwise, return 0.
+
+ When DIFFERENT_BINDING_LEVEL is true, NEWDECL is an external declaration,
+ and OLDDECL is in an outer binding level and should thus not be changed. */
static int
-duplicate_decls (newdecl, olddecl)
+duplicate_decls (newdecl, olddecl, different_binding_level)
register tree newdecl, olddecl;
+ int different_binding_level;
{
int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
@@ -1321,7 +1459,8 @@ duplicate_decls (newdecl, olddecl)
char *errmsg = 0;
if (TREE_CODE_CLASS (TREE_CODE (olddecl)) == 'd')
- DECL_MACHINE_ATTRIBUTES (newdecl) = DECL_MACHINE_ATTRIBUTES (olddecl);
+ DECL_MACHINE_ATTRIBUTES (newdecl)
+ = merge_machine_decl_attributes (olddecl, newdecl);
if (TREE_CODE (newtype) == ERROR_MARK
|| TREE_CODE (oldtype) == ERROR_MARK)
@@ -1404,8 +1543,8 @@ duplicate_decls (newdecl, olddecl)
else if (!types_match)
{
/* Accept the return type of the new declaration if same modes. */
- tree oldreturntype = TREE_TYPE (TREE_TYPE (olddecl));
- tree newreturntype = TREE_TYPE (TREE_TYPE (newdecl));
+ tree oldreturntype = TREE_TYPE (oldtype);
+ tree newreturntype = TREE_TYPE (newtype);
/* Make sure we put the new type in the same obstack as the old ones.
If the old types are not both in the same obstack, use the
@@ -1422,36 +1561,37 @@ duplicate_decls (newdecl, olddecl)
{
/* Function types may be shared, so we can't just modify
the return type of olddecl's function type. */
- tree newtype
+ tree trytype
= build_function_type (newreturntype,
- TYPE_ARG_TYPES (TREE_TYPE (olddecl)));
+ TYPE_ARG_TYPES (oldtype));
- types_match = comptypes (TREE_TYPE (newdecl), newtype);
+ types_match = comptypes (newtype, trytype);
if (types_match)
- TREE_TYPE (olddecl) = newtype;
+ oldtype = trytype;
}
/* Accept harmless mismatch in first argument type also.
This is for ffs. */
if (TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0
- && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0
- && TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (newdecl))) != 0
- && TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (olddecl))) != 0
- && (TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (newdecl))))
- ==
- TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (olddecl))))))
+ && TYPE_ARG_TYPES (oldtype) != 0
+ && TREE_VALUE (TYPE_ARG_TYPES (newtype)) != 0
+ && TREE_VALUE (TYPE_ARG_TYPES (oldtype)) != 0
+ && (TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (newtype)))
+ == TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (oldtype)))))
{
/* Function types may be shared, so we can't just modify
the return type of olddecl's function type. */
- tree newtype
- = build_function_type (TREE_TYPE (TREE_TYPE (olddecl)),
+ tree trytype
+ = build_function_type (TREE_TYPE (oldtype),
tree_cons (NULL_TREE,
- TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (newdecl))),
- TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (olddecl)))));
+ TREE_VALUE (TYPE_ARG_TYPES (newtype)),
+ TREE_CHAIN (TYPE_ARG_TYPES (oldtype))));
- types_match = comptypes (TREE_TYPE (newdecl), newtype);
+ types_match = comptypes (newtype, trytype);
if (types_match)
- TREE_TYPE (olddecl) = newtype;
+ oldtype = trytype;
}
+ if (! different_binding_level)
+ TREE_TYPE (olddecl) = oldtype;
pop_obstacks ();
}
@@ -1672,7 +1812,7 @@ duplicate_decls (newdecl, olddecl)
/* Optionally warn about more than one declaration for the same name. */
if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0
- /* Dont warn about a function declaration
+ /* Don't warn about a function declaration
followed by a definition. */
&& !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0
&& DECL_INITIAL (olddecl) == 0)
@@ -1691,6 +1831,11 @@ duplicate_decls (newdecl, olddecl)
if (types_match)
{
+ /* When copying info to olddecl, we store into write_olddecl
+ instead. This allows us to avoid modifying olddecl when
+ different_binding_level is true. */
+ tree write_olddecl = different_binding_level ? newdecl : olddecl;
+
/* Make sure we put the new type in the same obstack as the old ones.
If the old types are not both in the same obstack, use the permanent
one. */
@@ -1704,9 +1849,18 @@ duplicate_decls (newdecl, olddecl)
/* Merge the data types specified in the two decls. */
if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
- TREE_TYPE (newdecl)
- = TREE_TYPE (olddecl)
- = common_type (newtype, oldtype);
+ {
+ if (different_binding_level)
+ TREE_TYPE (newdecl)
+ = build_type_attribute_variant
+ (newtype,
+ merge_attributes (TYPE_ATTRIBUTES (newtype),
+ TYPE_ATTRIBUTES (oldtype)));
+ else
+ TREE_TYPE (newdecl)
+ = TREE_TYPE (olddecl)
+ = common_type (newtype, oldtype);
+ }
/* Lay the type out, unless already done. */
if (oldtype != TREE_TYPE (newdecl))
@@ -1733,37 +1887,37 @@ duplicate_decls (newdecl, olddecl)
/* Merge the type qualifiers. */
if (DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl)
&& !TREE_THIS_VOLATILE (newdecl))
- TREE_THIS_VOLATILE (olddecl) = 0;
+ TREE_THIS_VOLATILE (write_olddecl) = 0;
if (TREE_READONLY (newdecl))
- TREE_READONLY (olddecl) = 1;
+ TREE_READONLY (write_olddecl) = 1;
if (TREE_THIS_VOLATILE (newdecl))
{
- TREE_THIS_VOLATILE (olddecl) = 1;
+ TREE_THIS_VOLATILE (write_olddecl) = 1;
if (TREE_CODE (newdecl) == VAR_DECL)
make_var_volatile (newdecl);
}
- /* Keep source location of definition rather than declaration.
- Likewise, keep decl at outer scope. */
- if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
- || (DECL_CONTEXT (newdecl) != 0 && DECL_CONTEXT (olddecl) == 0))
+ /* Keep source location of definition rather than declaration. */
+ /* When called with different_binding_level set, keep the old
+ information so that meaningful diagnostics can be given. */
+ if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0
+ && ! different_binding_level)
{
DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl);
DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl);
-
- if (DECL_CONTEXT (olddecl) == 0
- && TREE_CODE (newdecl) != FUNCTION_DECL)
- DECL_CONTEXT (newdecl) = 0;
}
/* Merge the unused-warning information. */
if (DECL_IN_SYSTEM_HEADER (olddecl))
DECL_IN_SYSTEM_HEADER (newdecl) = 1;
else if (DECL_IN_SYSTEM_HEADER (newdecl))
- DECL_IN_SYSTEM_HEADER (olddecl) = 1;
+ DECL_IN_SYSTEM_HEADER (write_olddecl) = 1;
/* Merge the initialization information. */
- if (DECL_INITIAL (newdecl) == 0)
+ /* When called with different_binding_level set, don't copy over
+ DECL_INITIAL, so that we don't accidentally change function
+ declarations into function definitions. */
+ if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level)
DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
/* Merge the section attribute.
@@ -1783,7 +1937,7 @@ duplicate_decls (newdecl, olddecl)
}
/* If cannot merge, then use the new type and qualifiers,
and don't preserve the old rtl. */
- else
+ else if (! different_binding_level)
{
TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
TREE_READONLY (olddecl) = TREE_READONLY (newdecl);
@@ -1799,6 +1953,8 @@ duplicate_decls (newdecl, olddecl)
TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
/* This is since we don't automatically
copy the attributes of NEWDECL into OLDDECL. */
+ /* No need to worry about different_binding_level here because
+ then TREE_PUBLIC (newdecl) was true. */
TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
/* If this clears `static', clear it in the identifier too. */
if (! TREE_PUBLIC (olddecl))
@@ -1810,6 +1966,8 @@ duplicate_decls (newdecl, olddecl)
DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl);
/* An extern decl does not override previous storage class. */
TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
+ if (! DECL_EXTERNAL (newdecl))
+ DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
}
else
{
@@ -1823,37 +1981,62 @@ duplicate_decls (newdecl, olddecl)
DECL_INLINE (olddecl) = 1;
DECL_INLINE (newdecl) = DECL_INLINE (olddecl);
- /* Get rid of any built-in function if new arg types don't match it
- or if we have a function definition. */
- if (TREE_CODE (newdecl) == FUNCTION_DECL
- && DECL_BUILT_IN (olddecl)
- && (!types_match || new_is_definition))
- {
- TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
- DECL_BUILT_IN (olddecl) = 0;
- }
-
- /* If redeclaring a builtin function, and not a definition,
- it stays built in.
- Also preserve various other info from the definition. */
- if (TREE_CODE (newdecl) == FUNCTION_DECL && !new_is_definition)
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
if (DECL_BUILT_IN (olddecl))
{
- DECL_BUILT_IN (newdecl) = 1;
- DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+ /* Get rid of any built-in function if new arg types don't match it
+ or if we have a function definition. */
+ if (! types_match || new_is_definition)
+ {
+ if (! different_binding_level)
+ {
+ TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
+ DECL_BUILT_IN (olddecl) = 0;
+ }
+ }
+ else
+ {
+ /* If redeclaring a builtin function, and not a definition,
+ it stays built in. */
+ DECL_BUILT_IN (newdecl) = 1;
+ DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+ }
}
- else
+ /* Also preserve various other info from the definition. */
+ else if (! new_is_definition)
DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl);
+ if (! new_is_definition)
+ {
+ DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
+ /* When called with different_binding_level set, don't copy over
+ DECL_INITIAL, so that we don't accidentally change function
+ declarations into function definitions. */
+ if (! different_binding_level)
+ DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+ DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
+ DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+ if (DECL_INLINE (newdecl))
+ DECL_ABSTRACT_ORIGIN (newdecl) = olddecl;
+ }
+ }
+ if (different_binding_level)
+ {
+ /* Don't output a duplicate symbol or debugging information for this
+ declaration.
- DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
- DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
- DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
- DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+ Do not set TREE_ASM_WRITTEN for a FUNCTION_DECL since we may actually
+ just have two declarations without a definition. VAR_DECLs may need
+ the same treatment, I'm not sure. */
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
+ DECL_IGNORED_P (newdecl) = 1;
+ else
+ TREE_ASM_WRITTEN (newdecl) = DECL_IGNORED_P (newdecl) = 1;
+ return 0;
}
/* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
- But preserve OLDdECL's DECL_UID. */
+ But preserve OLDDECL's DECL_UID. */
{
register unsigned olddecl_uid = DECL_UID (olddecl);
@@ -1863,6 +2046,10 @@ duplicate_decls (newdecl, olddecl)
DECL_UID (olddecl) = olddecl_uid;
}
+ /* NEWDECL contains the merged attribute lists.
+ Update OLDDECL to be the same. */
+ DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl);
+
return 1;
}
@@ -1900,15 +2087,21 @@ pushdecl (x)
{
char *file;
int line;
- int declared_global;
+ int different_binding_level = 0;
+ t = lookup_name_current_level (name);
/* Don't type check externs here when -traditional. This is so that
code with conflicting declarations inside blocks will get warnings
not errors. X11 for instance depends on this. */
- if (DECL_EXTERNAL (x) && TREE_PUBLIC (x) && ! flag_traditional)
- t = lookup_name_current_level_global (name);
- else
- t = lookup_name_current_level (name);
+ if (! t && DECL_EXTERNAL (x) && TREE_PUBLIC (x) && ! flag_traditional)
+ {
+ t = IDENTIFIER_GLOBAL_VALUE (name);
+ /* Type decls at global scope don't conflict with externs declared
+ inside lexical blocks. */
+ if (t && TREE_CODE (t) == TYPE_DECL)
+ t = 0;
+ different_binding_level = 1;
+ }
if (t != 0 && t == error_mark_node)
/* error_mark_node is 0 for a while during initialization! */
{
@@ -1922,10 +2115,29 @@ pushdecl (x)
line = DECL_SOURCE_LINE (t);
}
- /* duplicate_decls might write to TREE_PUBLIC (x) and DECL_EXTERNAL (x)
- to make it identical to the initial declaration. */
- declared_global = TREE_PUBLIC (x) || DECL_EXTERNAL (x);
- if (t != 0 && duplicate_decls (x, t))
+ /* If this decl is `static' and an implicit decl was seen previously,
+ warn. But don't complain if -traditional,
+ since traditional compilers don't complain. */
+ if (! flag_traditional && TREE_PUBLIC (name)
+ /* Don't test for DECL_EXTERNAL, because grokdeclarator
+ sets this for all functions. */
+ && ! TREE_PUBLIC (x)
+ && (TREE_CODE (x) == FUNCTION_DECL || b == global_binding_level)
+ /* We used to warn also for explicit extern followed by static,
+ but sometimes you need to do it that way. */
+ && IDENTIFIER_IMPLICIT_DECL (name) != 0)
+ {
+ pedwarn ("`%s' was declared implicitly `extern' and later `static'",
+ IDENTIFIER_POINTER (name));
+ pedwarn_with_file_and_line
+ (DECL_SOURCE_FILE (IDENTIFIER_IMPLICIT_DECL (name)),
+ DECL_SOURCE_LINE (IDENTIFIER_IMPLICIT_DECL (name)),
+ "previous declaration of `%s'",
+ IDENTIFIER_POINTER (name));
+ TREE_THIS_VOLATILE (name) = 1;
+ }
+
+ if (t != 0 && duplicate_decls (x, t, different_binding_level))
{
if (TREE_CODE (t) == PARM_DECL)
{
@@ -1934,32 +2146,7 @@ pushdecl (x)
TREE_ASM_WRITTEN (t) = TREE_ASM_WRITTEN (x);
return t;
}
- /* If this decl is `static' and an implicit decl was seen previously,
- warn. But don't complain if -traditional,
- since traditional compilers don't complain. */
- if (!flag_traditional && TREE_PUBLIC (name)
-
- /* should this be '&& ! declared_global' ? */
- && ! TREE_PUBLIC (x) && ! DECL_EXTERNAL (x)
-
- /* We used to warn also for explicit extern followed by static,
- but sometimes you need to do it that way. */
- && IDENTIFIER_IMPLICIT_DECL (name) != 0)
- {
- pedwarn ("`%s' was declared implicitly `extern' and later `static'",
- IDENTIFIER_POINTER (name));
- pedwarn_with_file_and_line (file, line,
- "previous declaration of `%s'",
- IDENTIFIER_POINTER (name));
- }
-
- /* If this is a global decl, and there exists a conflicting local
- decl in a parent block, then we can't return as yet, because we
- need to register this decl in the current binding block. */
- /* A test for TREE_PUBLIC (x) will fail for variables that have
- been declared static first, and extern now. */
- if (! declared_global || lookup_name (name) == t)
- return t;
+ return t;
}
/* If we are processing a typedef statement, generate a whole new
@@ -1981,7 +2168,7 @@ pushdecl (x)
MY_TYPE object;
Later parts of the compiler might only know that `object' was of
- type `struct S' if if were not for code just below. With this
+ type `struct S' if it were not for code just below. With this
code however, later parts of the compiler see something like:
struct S' == struct S
@@ -2012,10 +2199,11 @@ pushdecl (x)
if (TYPE_NAME (TREE_TYPE (x)) == 0)
TYPE_NAME (TREE_TYPE (x)) = x;
}
- else if (TREE_TYPE (x) != error_mark_node)
+ else if (TREE_TYPE (x) != error_mark_node
+ && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
{
tree tt = TREE_TYPE (x);
-
+ DECL_ORIGINAL_TYPE (x) = tt;
tt = build_type_copy (tt);
TYPE_NAME (tt) = x;
TREE_TYPE (x) = tt;
@@ -2145,9 +2333,16 @@ pushdecl (x)
/* Okay to declare a non-ANSI built-in as anything. */
else if (t != 0 && DECL_BUILT_IN_NONANSI (t))
;
+ /* Okay to have global type decl after an earlier extern
+ declaration inside a lexical block. */
+ else if (TREE_CODE (x) == TYPE_DECL)
+ ;
else if (IDENTIFIER_IMPLICIT_DECL (name))
- pedwarn ("`%s' was declared implicitly `extern' and later `static'",
- IDENTIFIER_POINTER (name));
+ {
+ if (! TREE_THIS_VOLATILE (name))
+ pedwarn ("`%s' was declared implicitly `extern' and later `static'",
+ IDENTIFIER_POINTER (name));
+ }
else
pedwarn ("`%s' was declared `extern' and later `static'",
IDENTIFIER_POINTER (name));
@@ -2217,11 +2412,11 @@ pushdecl (x)
and no file-scope declaration has yet been seen,
then if we later have a file-scope decl it must not be static. */
if (oldlocal == 0
- && oldglobal == 0
&& DECL_EXTERNAL (x)
&& TREE_PUBLIC (x))
{
- TREE_PUBLIC (name) = 1;
+ if (oldglobal == 0)
+ TREE_PUBLIC (name) = 1;
/* Save this decl, so that we can do type checking against
other decls after it falls out of scope.
@@ -2363,9 +2558,15 @@ implicitly_declare (functionid)
rest_of_decl_compilation (decl, NULL_PTR, 0, 0);
- if (warn_implicit && implicit_warning)
- warning ("implicit declaration of function `%s'",
- IDENTIFIER_POINTER (functionid));
+ if (mesg_implicit_function_declaration && implicit_warning)
+ {
+ if (mesg_implicit_function_declaration == 2)
+ error ("implicit declaration of function `%s'",
+ IDENTIFIER_POINTER (functionid));
+ else
+ warning ("implicit declaration of function `%s'",
+ IDENTIFIER_POINTER (functionid));
+ }
else if (warn_traditional && traditional_warning)
warning ("function `%s' was previously declared within a block",
IDENTIFIER_POINTER (functionid));
@@ -2731,32 +2932,9 @@ lookup_name_current_level (name)
return t;
}
-
-/* Similar to `lookup_name_current_level' but also look at the global binding
- level. */
-
-tree
-lookup_name_current_level_global (name)
- tree name;
-{
- register tree t = 0;
-
- if (current_binding_level == global_binding_level)
- return IDENTIFIER_GLOBAL_VALUE (name);
-
- if (IDENTIFIER_LOCAL_VALUE (name) != 0)
- for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
- if (DECL_NAME (t) == name)
- break;
-
- if (t == 0)
- t = IDENTIFIER_GLOBAL_VALUE (name);
-
- return t;
-}
/* Create the predefined scalar types of C,
- and some nodes representing standard constants (0, 1, (void *)0).
+ and some nodes representing standard constants (0, 1, (void *) 0).
Initialize the global binding level.
Make definitions for built-in primitive functions. */
@@ -2767,8 +2945,8 @@ init_decl_processing ()
/* Either char* or void*. */
tree traditional_ptr_type_node;
/* Data types of memcpy and strlen. */
- tree memcpy_ftype, strlen_ftype;
- tree void_ftype_any;
+ tree memcpy_ftype, memset_ftype, strlen_ftype;
+ tree void_ftype_any, ptr_ftype_void, ptr_ftype_ptr;
int wchar_type_size;
tree temp;
tree array_domain_type;
@@ -2816,37 +2994,29 @@ init_decl_processing ()
pushdecl (build_decl (TYPE_DECL, get_identifier ("long long unsigned int"),
long_long_unsigned_type_node));
+ short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"),
+ short_integer_type_node));
+
+ short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"),
+ short_unsigned_type_node));
+
/* `unsigned long' is the standard type for sizeof.
Traditionally, use a signed type.
Note that stddef.h uses `unsigned long',
- and this must agree, even of long and int are the same size. */
- sizetype
- = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)));
+ and this must agree, even if long and int are the same size. */
+ set_sizetype
+ (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))));
if (flag_traditional && TREE_UNSIGNED (sizetype))
- sizetype = signed_type (sizetype);
+ set_sizetype (signed_type (sizetype));
ptrdiff_type_node
= TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
- TREE_TYPE (TYPE_SIZE (integer_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (char_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (unsigned_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (long_unsigned_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (long_integer_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (long_long_integer_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (long_long_unsigned_type_node)) = sizetype;
-
error_mark_node = make_node (ERROR_MARK);
TREE_TYPE (error_mark_node) = error_mark_node;
- short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
- pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"),
- short_integer_type_node));
-
- short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
- pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"),
- short_unsigned_type_node));
-
/* Define both `signed char' and `unsigned char'. */
signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
pushdecl (build_decl (TYPE_DECL, get_identifier ("signed char"),
@@ -2868,6 +3038,9 @@ init_decl_processing ()
intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
+ intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
+ pushdecl (build_decl (TYPE_DECL, NULL_TREE, intTI_type_node));
+
unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
@@ -2880,6 +3053,9 @@ init_decl_processing ()
unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node));
+ unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
+ pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intTI_type_node));
+
float_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_FLOAT],
@@ -3074,6 +3250,19 @@ init_decl_processing ()
sizetype,
endlink))));
+ memset_ftype /* memset prototype */
+ = build_function_type (traditional_ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, integer_type_node,
+ tree_cons (NULL_TREE,
+ sizetype,
+ endlink))));
+
+ ptr_ftype_void = build_function_type (ptr_type_node, endlink);
+ ptr_ftype_ptr
+ = build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node, endlink));
+
builtin_function ("__builtin_constant_p", default_function_type,
BUILT_IN_CONSTANT_P, NULL_PTR);
@@ -3091,6 +3280,44 @@ init_decl_processing ()
endlink)),
BUILT_IN_FRAME_ADDRESS, NULL_PTR);
+ builtin_function ("__builtin_aggregate_incoming_address",
+ build_function_type (ptr_type_node, NULL_TREE),
+ BUILT_IN_AGGREGATE_INCOMING_ADDRESS, NULL_PTR);
+
+ /* Hooks for the DWARF 2 __throw routine. */
+ builtin_function ("__builtin_unwind_init",
+ build_function_type (void_type_node, endlink),
+ BUILT_IN_UNWIND_INIT, NULL_PTR);
+ builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
+ builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
+ builtin_function ("__builtin_dwarf_fp_regnum",
+ build_function_type (unsigned_type_node, endlink),
+ BUILT_IN_DWARF_FP_REGNUM, NULL_PTR);
+ builtin_function ("__builtin_dwarf_reg_size", int_ftype_int,
+ BUILT_IN_DWARF_REG_SIZE, NULL_PTR);
+ builtin_function ("__builtin_frob_return_addr", ptr_ftype_ptr,
+ BUILT_IN_FROB_RETURN_ADDR, NULL_PTR);
+ builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr,
+ BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR);
+ builtin_function ("__builtin_set_return_addr_reg",
+ build_function_type (void_type_node,
+ tree_cons (NULL_TREE,
+ ptr_type_node,
+ endlink)),
+ BUILT_IN_SET_RETURN_ADDR_REG, NULL_PTR);
+ builtin_function ("__builtin_eh_stub_old", ptr_ftype_void,
+ BUILT_IN_EH_STUB_OLD, NULL_PTR);
+ builtin_function ("__builtin_eh_stub", ptr_ftype_void,
+ BUILT_IN_EH_STUB, NULL_PTR);
+ builtin_function
+ ("__builtin_set_eh_regs",
+ build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE,
+ type_for_mode (ptr_mode, 0),
+ endlink))),
+ BUILT_IN_SET_EH_REGS, NULL_PTR);
+
builtin_function ("__builtin_alloca",
build_function_type (ptr_type_node,
tree_cons (NULL_TREE,
@@ -3182,6 +3409,8 @@ init_decl_processing ()
BUILT_IN_MEMCPY, "memcpy");
builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet,
BUILT_IN_MEMCMP, "memcmp");
+ builtin_function ("__builtin_memset", memset_ftype,
+ BUILT_IN_MEMSET, "memset");
builtin_function ("__builtin_strcmp", int_ftype_string_string,
BUILT_IN_STRCMP, "strcmp");
builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
@@ -3206,6 +3435,22 @@ init_decl_processing ()
BUILT_IN_COS, "cos");
builtin_function ("__builtin_cosl", ldouble_ftype_ldouble,
BUILT_IN_COS, "cosl");
+ builtin_function ("__builtin_setjmp",
+ build_function_type (integer_type_node,
+ tree_cons (NULL_TREE,
+ ptr_type_node, endlink)),
+ BUILT_IN_SETJMP, NULL_PTR);
+ builtin_function ("__builtin_longjmp",
+ build_function_type
+ (void_type_node,
+ tree_cons (NULL, ptr_type_node,
+ tree_cons (NULL_TREE,
+ integer_type_node,
+ endlink))),
+ BUILT_IN_LONGJMP, NULL_PTR);
+ builtin_function ("__builtin_trap",
+ build_function_type (void_type_node, endlink),
+ BUILT_IN_TRAP, NULL_PTR);
/* In an ANSI C program, it is okay to supply built-in meanings
for these functions, since applications cannot validly use them
@@ -3222,6 +3467,7 @@ init_decl_processing ()
builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR);
builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP,
NULL_PTR);
+ builtin_function ("memset", memset_ftype, BUILT_IN_MEMSET, NULL_PTR);
builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP,
NULL_PTR);
builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
@@ -3264,8 +3510,6 @@ init_decl_processing ()
BUILT_IN_FMOD, NULL_PTR);
builtin_function ("__builtin_frem", double_ftype_double_double,
BUILT_IN_FREM, NULL_PTR);
- builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int,
- BUILT_IN_MEMSET, NULL_PTR);
builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
NULL_PTR);
builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
@@ -3285,6 +3529,8 @@ init_decl_processing ()
init_iterators ();
incomplete_decl_finalize_hook = finish_incomplete_decl;
+
+ lang_get_alias_set = &c_get_alias_set;
}
/* Return a definition for a builtin function named NAME and whose data type
@@ -3351,10 +3597,15 @@ shadow_tag_warned (declspecs, warned)
{
int found_tag = 0;
register tree link;
+ tree specs, attrs;
pending_invalid_xref = 0;
- for (link = declspecs; link; link = TREE_CHAIN (link))
+ /* Remove the attributes from declspecs, since they will confuse the
+ following code. */
+ split_specs_attrs (declspecs, &specs, &attrs);
+
+ for (link = specs; link; link = TREE_CHAIN (link))
{
register tree value = TREE_VALUE (link);
register enum tree_code code = TREE_CODE (value);
@@ -3467,6 +3718,10 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
/* The corresponding pop_obstacks is in finish_decl. */
push_obstacks_nochange ();
+ if (warn_main && TREE_CODE (decl) != FUNCTION_DECL
+ && !strcmp (IDENTIFIER_POINTER (DECL_NAME (decl)), "main"))
+ warning_with_decl (decl, "`%s' is usually a function");
+
if (initialized)
/* Is it valid for this decl to have an initializer at all?
If not, set INITIALIZED to zero, which will indirectly
@@ -3551,9 +3806,17 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
if (TREE_CODE (decl) == FUNCTION_DECL)
gen_aux_info_record (decl, 0, 0, TYPE_ARG_TYPES (TREE_TYPE (decl)) != 0);
- /* For C and Objective-C, we by default put things in .common when
- possible. */
- DECL_COMMON (decl) = 1;
+ /* ANSI specifies that a tentative definition which is not merged with
+ a non-tentative definition behaves exactly like a definition with an
+ initializer equal to zero. (Section 3.7.2)
+ -fno-common gives strict ANSI behavior. Usually you don't want it.
+ This matters only for variables with external linkage. */
+ if (! flag_no_common || ! TREE_PUBLIC (decl))
+ DECL_COMMON (decl) = 1;
+
+#ifdef SET_DEFAULT_DECL_ATTRIBUTES
+ SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes);
+#endif
/* Set attributes here so if duplicate decl, will have proper attributes. */
decl_attributes (decl, attributes, prefix_attributes);
@@ -3703,10 +3966,11 @@ finish_decl (decl, init, asmspec_tree)
Also if it is not file scope.
Otherwise, let it through, but if it is not `extern'
then it may cause an error message later. */
- /* We must use DECL_CONTEXT instead of current_binding_level,
- because a duplicate_decls call could have changed the binding
- level of this decl. */
- (DECL_INITIAL (decl) != 0 || DECL_CONTEXT (decl) != 0)
+ /* A duplicate_decls call could have changed an extern
+ declaration into a file scope one. This can be detected
+ by TREE_ASM_WRITTEN being set. */
+ (DECL_INITIAL (decl) != 0
+ || (DECL_CONTEXT (decl) != 0 && ! TREE_ASM_WRITTEN (decl)))
:
/* An automatic variable with an incomplete type
is an error. */
@@ -3724,6 +3988,9 @@ finish_decl (decl, init, asmspec_tree)
else
error_with_decl (decl, "storage size of `%s' isn't constant");
}
+
+ if (TREE_USED (type))
+ TREE_USED (decl) = 1;
}
/* If this is a function and an assembler name is specified, it isn't
@@ -3748,7 +4015,9 @@ finish_decl (decl, init, asmspec_tree)
end_temporary_allocation ();
/* This is a no-op in c-lang.c or something real in objc-actions.c. */
maybe_objc_check_decl (decl);
- rest_of_decl_compilation (decl, asmspec, DECL_CONTEXT (decl) == 0,
+ rest_of_decl_compilation (decl, asmspec,
+ (DECL_CONTEXT (decl) == 0
+ || TREE_ASM_WRITTEN (decl)),
0);
pop_obstacks ();
}
@@ -3871,7 +4140,7 @@ finish_decl (decl, init, asmspec_tree)
tree
maybe_build_cleanup (decl)
- tree decl;
+ tree decl ATTRIBUTE_UNUSED;
{
/* There are no cleanups in C. */
return NULL_TREE;
@@ -3990,12 +4259,6 @@ complete_array_type (type, initial_value, do_default)
TYPE_DOMAIN (type) = build_index_type (maxindex);
if (!TREE_TYPE (maxindex))
TREE_TYPE (maxindex) = TYPE_DOMAIN (type);
-#if 0 /* I took out this change
- together with the change in build_array_type. --rms */
- change_main_variant (type,
- build_array_type (TREE_TYPE (type),
- TYPE_DOMAIN (type)));
-#endif
}
/* Lay out the type now that we can get the real answer. */
@@ -4151,7 +4414,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
error ("`long long long' is too long for GCC");
else
{
- if (pedantic && ! in_system_header)
+ if (pedantic && ! in_system_header && warn_long_long)
pedwarn ("ANSI C does not support `long long'");
longlong = 1;
}
@@ -4201,10 +4464,23 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
if (type == 0)
{
- if (funcdef_flag && warn_return_type
- && ! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
- | (1 << (int) RID_SIGNED) | (1 << (int) RID_UNSIGNED))))
- warn_about_return_type = 1;
+ if ((! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
+ | (1 << (int) RID_SIGNED)
+ | (1 << (int) RID_UNSIGNED))))
+ /* Don't warn about typedef foo = bar. */
+ && ! (specbits & (1 << (int) RID_TYPEDEF) && initialized)
+ && ! (in_system_header && ! allocation_temporary_p ()))
+ {
+ /* C9x will probably require a diagnostic here.
+ For now, issue a warning if -Wreturn-type and this is a function,
+ or if -Wimplicit; prefer the former warning since it is more
+ explicit. */
+ if ((warn_implicit_int || warn_return_type) && funcdef_flag)
+ warn_about_return_type = 1;
+ else if (warn_implicit_int)
+ warning ("type defaults to `int' in declaration of `%s'", name);
+ }
+
defaulted_int = 1;
type = integer_type_node;
}
@@ -4214,7 +4490,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
/* Long double is a special combination. */
- if ((specbits & 1 << (int) RID_LONG)
+ if ((specbits & 1 << (int) RID_LONG) && ! longlong
&& TYPE_MAIN_VARIANT (type) == double_type_node)
{
specbits &= ~ (1 << (int) RID_LONG);
@@ -4228,11 +4504,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
{
int ok = 0;
- if (TREE_CODE (type) != INTEGER_TYPE)
- error ("long, short, signed or unsigned invalid for `%s'", name);
- else if ((specbits & 1 << (int) RID_LONG)
- && (specbits & 1 << (int) RID_SHORT))
- error ("long and short specified together for `%s'", name);
+ if ((specbits & 1 << (int) RID_LONG)
+ && (specbits & 1 << (int) RID_SHORT))
+ error ("both long and short specified for `%s'", name);
else if (((specbits & 1 << (int) RID_LONG)
|| (specbits & 1 << (int) RID_SHORT))
&& explicit_char)
@@ -4240,10 +4514,21 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
else if (((specbits & 1 << (int) RID_LONG)
|| (specbits & 1 << (int) RID_SHORT))
&& TREE_CODE (type) == REAL_TYPE)
- error ("long or short specified with floating type for `%s'", name);
+ {
+ static int already = 0;
+
+ error ("long or short specified with floating type for `%s'", name);
+ if (! already && ! pedantic)
+ {
+ error ("the only valid combination is `long double'");
+ already = 1;
+ }
+ }
else if ((specbits & 1 << (int) RID_SIGNED)
&& (specbits & 1 << (int) RID_UNSIGNED))
- error ("signed and unsigned given together for `%s'", name);
+ error ("both signed and unsigned specified for `%s'", name);
+ else if (TREE_CODE (type) != INTEGER_TYPE)
+ error ("long, short, signed or unsigned invalid for `%s'", name);
else
{
ok = 1;
@@ -4538,6 +4823,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
convert (index_type, size),
convert (index_type, size_one_node)));
+ /* If that overflowed, the array is too big.
+ ??? While a size of INT_MAX+1 technically shouldn't cause
+ an overflow (because we subtract 1), the overflow is recorded
+ during the conversion to index_type, before the subtraction.
+ Handling this case seems like an unnecessary complication. */
+ if (TREE_OVERFLOW (itype))
+ {
+ error ("size of array `%s' is too large", name);
+ type = error_mark_node;
+ continue;
+ }
+
if (size_varies)
itype = variable_size (itype);
itype = build_index_type (itype);
@@ -4656,7 +4953,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
{
register tree link;
- for (link = current_function_parm_tags;
+ for (link = last_function_parm_tags;
link;
link = TREE_CHAIN (link))
TYPE_CONTEXT (TREE_VALUE (link)) = type;
@@ -4713,6 +5010,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
/* Now TYPE has the actual type. */
+ /* Did array size calculations overflow? */
+
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_SIZE (type)
+ && TREE_OVERFLOW (TYPE_SIZE (type)))
+ error ("size of array `%s' is too large", name);
+
/* If this is declaring a typedef name, return a TYPE_DECL. */
if (specbits & (1 << (int) RID_TYPEDEF))
@@ -4725,11 +5029,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
pedwarn ("ANSI C forbids const or volatile function types");
if (constp || volatilep)
type = c_build_type_variant (type, constp, volatilep);
- pop_obstacks ();
decl = build_decl (TYPE_DECL, declarator, type);
if ((specbits & (1 << (int) RID_SIGNED))
|| (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
+ pop_obstacks ();
return decl;
}
@@ -4909,6 +5213,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
&& ! DECL_IN_SYSTEM_HEADER (decl))
pedwarn ("ANSI C forbids const or volatile functions");
+ if (pedantic
+ && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl))) == void_type_node
+ && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (decl)))
+ || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (decl))))
+ && ! DECL_IN_SYSTEM_HEADER (decl))
+ pedwarn ("ANSI C forbids const or volatile void function return type");
+
if (volatilep
&& TREE_TYPE (TREE_TYPE (decl)) != void_type_node)
warning ("`noreturn' function returns non-void value");
@@ -4922,13 +5233,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
/* Record presence of `inline', if it is reasonable. */
if (inlinep)
{
- tree last = tree_last (TYPE_ARG_TYPES (type));
-
if (! strcmp (IDENTIFIER_POINTER (declarator), "main"))
warning ("cannot inline function `main'");
- else if (last && (TYPE_MAIN_VARIANT (TREE_VALUE (last))
- != void_type_node))
- warning ("inline declaration ignored for function with `...'");
else
/* Assume that otherwise the function can be inlined. */
DECL_INLINE (decl) = 1;
@@ -5248,7 +5554,7 @@ parmlist_tags_warning ()
enum tree_code code = TREE_CODE (TREE_VALUE (elt));
/* An anonymous union parm type is meaningful as a GNU extension.
So don't warn for that. */
- if (code == UNION_TYPE && !pedantic)
+ if (code == UNION_TYPE && TREE_PURPOSE (elt) == 0 && !pedantic)
continue;
if (TREE_PURPOSE (elt) != 0)
warning ("`%s %s' declared inside parameter list",
@@ -5351,6 +5657,7 @@ start_struct (code, name)
if (ref && TREE_CODE (ref) == code)
{
C_TYPE_BEING_DEFINED (ref) = 1;
+ TYPE_PACKED (ref) = flag_pack_struct;
if (TYPE_FIELDS (ref))
error ((code == UNION_TYPE ? "redefinition of `union %s'"
: "redefinition of `struct %s'"),
@@ -5364,6 +5671,7 @@ start_struct (code, name)
ref = make_node (code);
pushtag (name, ref);
C_TYPE_BEING_DEFINED (ref) = 1;
+ TYPE_PACKED (ref) = flag_pack_struct;
return ref;
}
@@ -5398,9 +5706,12 @@ grokfield (filename, line, declarator, declspecs, width)
/* Function to help qsort sort FIELD_DECLs by name order. */
static int
-field_decl_cmp (x, y)
- tree *x, *y;
+field_decl_cmp (xp, yp)
+ const GENERIC_PTR xp;
+ const GENERIC_PTR yp;
{
+ tree *x = (tree *)xp, *y = (tree *)yp;
+
if (DECL_NAME (*x) == DECL_NAME (*y))
return 0;
if (DECL_NAME (*x) == NULL)
@@ -5450,9 +5761,17 @@ finish_struct (t, fieldlist, attributes)
old_momentary = suspend_momentary ();
- if (fieldlist == 0 && pedantic)
- pedwarn ((TREE_CODE (t) == UNION_TYPE ? "union has no members"
- : "structure has no members"));
+ if (pedantic)
+ {
+ for (x = fieldlist; x; x = TREE_CHAIN (x))
+ if (DECL_NAME (x) != 0)
+ break;
+
+ if (x == 0)
+ pedwarn ("%s has no %smembers",
+ (TREE_CODE (t) == UNION_TYPE ? "union" : "structure"),
+ (fieldlist ? "named " : ""));
+ }
/* Install struct as DECL_CONTEXT of each field decl.
Also process specified field sizes.
@@ -5554,8 +5873,15 @@ finish_struct (t, fieldlist, attributes)
{
register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
+ if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
+ && (width < min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)),
+ TREE_UNSIGNED (TREE_TYPE (x)))
+ || width < min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)),
+ TREE_UNSIGNED (TREE_TYPE (x)))))
+ warning_with_decl (x, "`%s' is narrower than values of its type");
+
DECL_FIELD_SIZE (x) = width;
- DECL_BIT_FIELD (x) = 1;
+ DECL_BIT_FIELD (x) = DECL_C_BIT_FIELD (x) = 1;
DECL_INITIAL (x) = NULL;
if (width == 0)
@@ -5565,14 +5891,15 @@ finish_struct (t, fieldlist, attributes)
DECL_ALIGN (x) = MAX (DECL_ALIGN (x), EMPTY_FIELD_BOUNDARY);
#endif
#ifdef PCC_BITFIELD_TYPE_MATTERS
- DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
- TYPE_ALIGN (TREE_TYPE (x)));
+ if (PCC_BITFIELD_TYPE_MATTERS)
+ DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
+ TYPE_ALIGN (TREE_TYPE (x)));
#endif
}
}
else if (TREE_TYPE (x) != error_mark_node)
{
- int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT
+ unsigned int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT
: TYPE_ALIGN (TREE_TYPE (x)));
/* Non-bit-fields are aligned for their type, except packed
fields which require only BITS_PER_UNIT alignment. */
@@ -5675,27 +6002,6 @@ finish_struct (t, fieldlist, attributes)
TYPE_ALIGN (x) = TYPE_ALIGN (t);
}
- /* Promote each bit-field's type to int if it is narrower than that. */
- for (x = fieldlist; x; x = TREE_CHAIN (x))
- if (DECL_BIT_FIELD (x)
- && (C_PROMOTING_INTEGER_TYPE_P (TREE_TYPE (x))
- || DECL_FIELD_SIZE (x) < TYPE_PRECISION (integer_type_node)))
- {
- tree type = TREE_TYPE (x);
-
- /* Preserve unsignedness if traditional
- or if not really getting any wider. */
- if (TREE_UNSIGNED (type)
- && (flag_traditional
- ||
- (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)
- &&
- DECL_FIELD_SIZE (x) == TYPE_PRECISION (integer_type_node))))
- TREE_TYPE (x) = unsigned_type_node;
- else
- TREE_TYPE (x) = integer_type_node;
- }
-
/* If this was supposed to be a transparent union, but we can't
make it one, warn and turn off the flag. */
if (TREE_CODE (t) == UNION_TYPE
@@ -5703,7 +6009,7 @@ finish_struct (t, fieldlist, attributes)
&& TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t)))
{
TYPE_TRANSPARENT_UNION (t) = 0;
- warning ("cannot make `%s' a transparent union");
+ warning ("union cannot be made transparent");
}
/* If this structure or union completes the type of any previous
@@ -5805,6 +6111,9 @@ start_enum (name)
enum_next_value = integer_zero_node;
enum_overflow = 0;
+ if (flag_short_enums)
+ TYPE_PACKED (enumtype) = 1;
+
return enumtype;
}
@@ -5861,10 +6170,17 @@ finish_enum (enumtype, values, attributes)
highprec = min_precision (maxnode, TREE_UNSIGNED (enumtype));
precision = MAX (lowprec, highprec);
- if (flag_short_enums || TYPE_PACKED (enumtype)
- || precision > TYPE_PRECISION (integer_type_node))
- /* Use the width of the narrowest normal C type which is wide enough. */
- TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size (precision, 1));
+ if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node))
+ {
+ tree narrowest = type_for_size (precision, 1);
+ if (narrowest == 0)
+ {
+ warning ("enumeration values exceed range of largest integer");
+ narrowest = long_long_integer_type_node;
+ }
+
+ TYPE_PRECISION (enumtype) = TYPE_PRECISION (narrowest);
+ }
else
TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
@@ -5900,6 +6216,7 @@ finish_enum (enumtype, values, attributes)
TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
+ TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype);
TYPE_MODE (tem) = TYPE_MODE (enumtype);
TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
@@ -6007,7 +6324,7 @@ start_function (declspecs, declarator, prefix_attributes, attributes, nested)
tree restype;
int old_immediate_size_expand = immediate_size_expand;
- current_function_returns_value = 0; /* Assume, until we see it does. */
+ current_function_returns_value = 0; /* Assume, until we see it does. */
current_function_returns_null = 0;
warn_about_return_type = 0;
current_extern_inline = 0;
@@ -6023,7 +6340,10 @@ start_function (declspecs, declarator, prefix_attributes, attributes, nested)
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
if (decl1 == 0)
- return 0;
+ {
+ immediate_size_expand = old_immediate_size_expand;
+ return 0;
+ }
decl_attributes (decl1, prefix_attributes, attributes);
@@ -6116,6 +6436,67 @@ start_function (declspecs, declarator, prefix_attributes, attributes, nested)
if (current_function_decl != 0)
TREE_PUBLIC (decl1) = 0;
+ /* Warn for unlikely, improbable, or stupid declarations of `main'. */
+ if (warn_main
+ && strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1))) == 0)
+ {
+ tree args;
+ int argct = 0;
+
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1)))
+ != integer_type_node)
+ pedwarn_with_decl (decl1, "return type of `%s' is not `int'");
+
+ for (args = TYPE_ARG_TYPES (TREE_TYPE (decl1)); args;
+ args = TREE_CHAIN (args))
+ {
+ tree type = args ? TREE_VALUE (args) : 0;
+
+ if (type == void_type_node)
+ break;
+
+ ++argct;
+ switch (argct)
+ {
+ case 1:
+ if (TYPE_MAIN_VARIANT (type) != integer_type_node)
+ pedwarn_with_decl (decl1,
+ "first argument of `%s' should be `int'");
+ break;
+
+ case 2:
+ if (TREE_CODE (type) != POINTER_TYPE
+ || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
+ || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
+ != char_type_node))
+ pedwarn_with_decl (decl1,
+ "second argument of `%s' should be `char **'");
+ break;
+
+ case 3:
+ if (TREE_CODE (type) != POINTER_TYPE
+ || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
+ || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
+ != char_type_node))
+ pedwarn_with_decl (decl1,
+ "third argument of `%s' should probably be `char **'");
+ break;
+ }
+ }
+
+ /* It is intentional that this message does not mention the third
+ argument, which is warned for only pedantically, because it's
+ blessed by mention in an appendix of the standard. */
+ if (argct > 0 && (argct < 2 || argct > 3))
+ pedwarn_with_decl (decl1, "`%s' takes only zero or two arguments");
+
+ if (argct == 3 && pedantic)
+ pedwarn_with_decl (decl1, "third argument of `%s' is deprecated");
+
+ if (! TREE_PUBLIC (decl1))
+ pedwarn_with_decl (decl1, "`%s' is normally a non-static function");
+ }
+
/* Record the decl so that the function name is defined.
If we already have a decl for this name, and it is a FUNCTION_DECL,
use the old decl. */
@@ -6729,7 +7110,9 @@ combine_parm_decls (specparms, parmlist, void_at_end)
if (void_at_end)
return saveable_tree_cons (parmdecls, nonparms,
- nreverse (saveable_tree_cons (NULL_TREE, void_type_node, types)));
+ nreverse (saveable_tree_cons (NULL_TREE,
+ void_type_node,
+ types)));
return saveable_tree_cons (parmdecls, nonparms, nreverse (types));
}
@@ -6766,19 +7149,28 @@ finish_function (nested)
setjmp_protect_args ();
}
-#ifdef DEFAULT_MAIN_RETURN
if (! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main"))
{
if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
!= integer_type_node)
- warning_with_decl (fndecl, "return type of `%s' is not `int'");
+ {
+ /* You would expect the sense of this test to be the other way
+ around, but if warn_main is set, we will already have warned,
+ so this would be a duplicate. This is the warning you get
+ in some environments even if you *don't* ask for it, because
+ these are environments where it may be more of a problem than
+ usual. */
+ if (! warn_main)
+ pedwarn_with_decl (fndecl, "return type of `%s' is not `int'");
+ }
else
{
+#ifdef DEFAULT_MAIN_RETURN
/* Make it so that `main' always returns success by default. */
DEFAULT_MAIN_RETURN;
+#endif
}
}
-#endif
/* Generate rtl for function exit. */
expand_function_end (input_filename, lineno, 0);
@@ -6962,6 +7354,6 @@ pop_c_function_context ()
void
copy_lang_decl (node)
- tree node;
+ tree node ATTRIBUTE_UNUSED;
{
}
diff --git a/contrib/gcc/c-iterate.c b/contrib/gcc/c-iterate.c
index b35a167..b8f51d0 100644
--- a/contrib/gcc/c-iterate.c
+++ b/contrib/gcc/c-iterate.c
@@ -1,5 +1,5 @@
/* Build expressions with type checking for C compiler.
- Copyright (C) 1987, 1988, 1989, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92, 93, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -24,26 +24,14 @@ Boston, MA 02111-1307, USA. */
both their declarations and the expansion of statements using them. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "tree.h"
#include "c-tree.h"
#include "flags.h"
#include "obstack.h"
#include "rtl.h"
-
-static void expand_stmt_with_iterators_1 ();
-static tree collect_iterators ();
-static void iterator_loop_prologue ();
-static void iterator_loop_epilogue ();
-static void add_ixpansion ();
-static void delete_ixpansion();
-static int top_level_ixpansion_p ();
-static void istack_sublevel_to_current ();
-
-/* A special obstack, and a pointer to the start of
- all the data in it (so we can free everything easily). */
-static struct obstack ixp_obstack;
-static char *ixp_firstobj;
+#include "toplev.h"
+#include "expr.h"
/*
KEEPING TRACK OF EXPANSIONS
@@ -96,11 +84,26 @@ struct iter_stack_node
};
struct iter_stack_node *iter_stack;
-
struct iter_stack_node sublevel_ixpansions;
+/* A special obstack, and a pointer to the start of
+ all the data in it (so we can free everything easily). */
+static struct obstack ixp_obstack;
+static char *ixp_firstobj;
+
/* During collect_iterators, a list of SAVE_EXPRs already scanned. */
static tree save_exprs;
+
+static void expand_stmt_with_iterators_1 PROTO((tree, tree));
+static tree collect_iterators PROTO((tree, tree));
+static void iterator_loop_prologue PROTO((tree, rtx *, rtx *));
+static void iterator_loop_epilogue PROTO((tree, rtx *, rtx *));
+static int top_level_ixpansion_p PROTO((void));
+static void isn_append PROTO((struct iter_stack_node *,
+ struct iter_stack_node *));
+static void istack_sublevel_to_current PROTO((void));
+static void add_ixpansion PROTO((tree, rtx, rtx, rtx, rtx));
+static void delete_ixpansion PROTO((tree));
/* Initialize our obstack once per compilation. */
@@ -254,6 +257,8 @@ collect_iterators (exp, list)
break;
case RTL_EXPR:
return list;
+ default:
+ break;
}
for (i = 0; i < num_args; i++)
@@ -283,7 +288,8 @@ iterator_loop_prologue (idecl, start_note, end_note)
/* Force the save_expr in DECL_INITIAL to be calculated
if it hasn't been calculated yet. */
- expand_expr (DECL_INITIAL (idecl), const0_rtx, VOIDmode, 0);
+ expand_expr (DECL_INITIAL (idecl), const0_rtx, VOIDmode,
+ EXPAND_NORMAL);
if (DECL_RTL (idecl) == 0)
expand_decl (idecl);
@@ -294,7 +300,7 @@ iterator_loop_prologue (idecl, start_note, end_note)
/* Initialize counter. */
expr = build (MODIFY_EXPR, TREE_TYPE (idecl), idecl, integer_zero_node);
TREE_SIDE_EFFECTS (expr) = 1;
- expand_expr (expr, const0_rtx, VOIDmode, 0);
+ expand_expr (expr, const0_rtx, VOIDmode, EXPAND_NORMAL);
expand_start_loop_continue_elsewhere (1);
@@ -335,7 +341,7 @@ iterator_loop_epilogue (idecl, start_note, end_note)
incr = build_binary_op (PLUS_EXPR, idecl, integer_one_node, 0);
incr = build (MODIFY_EXPR, TREE_TYPE (idecl), idecl, incr);
TREE_SIDE_EFFECTS (incr) = 1;
- expand_expr (incr, const0_rtx, VOIDmode, 0);
+ expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
test = build_binary_op (LT_EXPR, idecl, DECL_INITIAL (idecl), 0);
expand_exit_loop_if_false (0, test);
expand_end_loop ();
@@ -343,7 +349,9 @@ iterator_loop_epilogue (idecl, start_note, end_note)
ITERATOR_BOUND_P (idecl) = 0;
/* we can reset rtl since there is not chance that this expansion */
/* would be superseded by a higher level one */
- if (top_level_ixpansion_p ())
+ /* but don't do this if the decl is static, since we need to share */
+ /* the same decl in that case. */
+ if (top_level_ixpansion_p () && ! TREE_STATIC (idecl))
DECL_RTL (idecl) = 0;
if (end_note)
*end_note = emit_note (0, NOTE_INSN_DELETED);
@@ -409,7 +417,7 @@ void
push_iterator_stack ()
{
struct iter_stack_node *new_top
- = (struct iter_stack_node*)
+ = (struct iter_stack_node *)
obstack_alloc (&ixp_obstack, sizeof (struct iter_stack_node));
new_top->first = 0;
@@ -442,15 +450,15 @@ add_ixpansion (idecl, pro_start, pro_end, epi_start, epi_end)
tree idecl;
rtx pro_start, pro_end, epi_start, epi_end;
{
- struct ixpansion* newix;
+ struct ixpansion *newix;
/* Do nothing if we are not inside "({...})",
as in that case this expansion can't need subsequent RTL modification. */
if (iter_stack == 0)
return;
- newix = (struct ixpansion*) obstack_alloc (&ixp_obstack,
- sizeof (struct ixpansion));
+ newix = (struct ixpansion *) obstack_alloc (&ixp_obstack,
+ sizeof (struct ixpansion));
newix->ixdecl = idecl;
newix->ixprologue_start = pro_start;
newix->ixprologue_end = pro_end;
@@ -471,7 +479,7 @@ static void
delete_ixpansion (idecl)
tree idecl;
{
- struct ixpansion* previx = 0, *ix;
+ struct ixpansion *previx = 0, *ix;
for (ix = sublevel_ixpansions.first; ix; ix = ix->next)
if (ix->ixdecl == idecl)
@@ -577,7 +585,7 @@ pixl (head)
return head;
}
-/* Print Iterator Stack*/
+/* Print Iterator Stack. */
void
pis ()
diff --git a/contrib/gcc/c-lang.c b/contrib/gcc/c-lang.c
index ef9f184..8a5fd6b 100644
--- a/contrib/gcc/c-lang.c
+++ b/contrib/gcc/c-lang.c
@@ -1,5 +1,5 @@
/* Language-specific hook definitions for C front end.
- Copyright (C) 1991, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1995, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,27 +20,39 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "tree.h"
-#include <stdio.h>
#include "input.h"
+#include "c-tree.h"
+#include "c-lex.h"
+#include "toplev.h"
+#include "output.h"
/* Each of the functions defined here
is an alternative to a function in objc-actions.c. */
int
-lang_decode_option (p)
- char *p;
+lang_decode_option (argc, argv)
+ int argc;
+ char **argv;
+{
+ return c_decode_option (argc, argv);
+}
+
+void
+lang_init_options ()
{
- return c_decode_option (p);
}
void
lang_init ()
{
+#if !USE_CPPLIB
/* the beginning of the file is a new line; check for # */
/* With luck, we discover the real source file's name from that
and put it in input_filename. */
ungetc (check_newline (), finput);
+#endif
}
void
@@ -59,39 +71,50 @@ print_lang_statistics ()
{
}
+/* used by print-tree.c */
+
+void
+lang_print_xnode (file, node, indent)
+ FILE *file ATTRIBUTE_UNUSED;
+ tree node ATTRIBUTE_UNUSED;
+ int indent ATTRIBUTE_UNUSED;
+{
+}
+
/* Used by c-lex.c, but only for objc. */
tree
lookup_interface (arg)
- tree arg;
+ tree arg ATTRIBUTE_UNUSED;
{
return 0;
}
tree
is_class_name (arg)
- tree arg;
+ tree arg ATTRIBUTE_UNUSED;
{
return 0;
}
void
maybe_objc_check_decl (decl)
- tree decl;
+ tree decl ATTRIBUTE_UNUSED;
{
}
int
maybe_objc_comptypes (lhs, rhs, reflexive)
- tree lhs, rhs;
- int reflexive;
+ tree lhs ATTRIBUTE_UNUSED;
+ tree rhs ATTRIBUTE_UNUSED;
+ int reflexive ATTRIBUTE_UNUSED;
{
return -1;
}
tree
maybe_objc_method_name (decl)
- tree decl;
+ tree decl ATTRIBUTE_UNUSED;
{
return 0;
}
@@ -110,33 +133,28 @@ recognize_objc_keyword ()
tree
build_objc_string (len, str)
- int len;
- char *str;
+ int len ATTRIBUTE_UNUSED;
+ char *str ATTRIBUTE_UNUSED;
{
abort ();
return NULL_TREE;
}
-void
-GNU_xref_begin ()
-{
- fatal ("GCC does not yet support XREF");
-}
-
-void
-GNU_xref_end ()
-{
- fatal ("GCC does not yet support XREF");
-}
+/* Called at end of parsing, but before end-of-file processing. */
-/* called at end of parsing, but before end-of-file processing. */
void
finish_file ()
{
- extern tree static_ctors, static_dtors;
- extern tree get_file_function_name ();
+#ifndef ASM_OUTPUT_CONSTRUCTOR
+ extern tree static_ctors;
+#endif
+#ifndef ASM_OUTPUT_DESTRUCTOR
+ extern tree static_dtors;
+#endif
extern tree build_function_call PROTO((tree, tree));
+#if !defined(ASM_OUTPUT_CONSTRUCTOR) || !defined(ASM_OUTPUT_DESTRUCTOR)
tree void_list_node = build_tree_list (NULL_TREE, void_type_node);
+#endif
#ifndef ASM_OUTPUT_CONSTRUCTOR
if (static_ctors)
{
diff --git a/contrib/gcc/c-lex.c b/contrib/gcc/c-lex.c
index 007b363..f82ad76 100644
--- a/contrib/gcc/c-lex.c
+++ b/contrib/gcc/c-lex.c
@@ -1,5 +1,5 @@
/* Lexical analyzer for C and Objective C.
- Copyright (C) 1987, 88, 89, 92, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92, 94-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -18,32 +18,43 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-
-#include <stdio.h>
-#include <errno.h>
+#include "config.h"
+#include "system.h"
#include <setjmp.h>
-#include "config.h"
#include "rtl.h"
#include "tree.h"
#include "input.h"
+#include "output.h"
#include "c-lex.h"
#include "c-tree.h"
#include "flags.h"
#include "c-parse.h"
#include "c-pragma.h"
+#include "toplev.h"
-#include <ctype.h>
+/* MULTIBYTE_CHARS support only works for native compilers.
+ ??? Ideally what we want is to model widechar support after
+ the current floating point support. */
+#ifdef CROSS_COMPILE
+#undef MULTIBYTE_CHARS
+#endif
#ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
#include <locale.h>
#endif
-#ifndef errno
-extern int errno;
+#if USE_CPPLIB
+#include "cpplib.h"
+extern cpp_reader parse_in;
+extern cpp_options parse_options;
+#else
+/* Stream for reading from the input file. */
+FILE *finput;
#endif
+extern void yyprint PROTO((FILE *, int, YYSTYPE));
+
/* The elements of `ridpointers' are identifier nodes
for the reserved type names and storage classes.
It is indexed by a RID_... value. */
@@ -52,6 +63,18 @@ tree ridpointers[(int) RID_MAX];
/* Cause the `yydebug' variable to be defined. */
#define YYDEBUG 1
+#if USE_CPPLIB
+extern unsigned char *yy_cur, *yy_lim;
+
+extern int yy_get_token ();
+
+#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ())
+#define UNGETC(c) ((c), yy_cur--)
+#else
+#define GETC() getc (finput)
+#define UNGETC(c) ungetc (c, finput)
+#endif
+
/* the declaration found for the last IDENTIFIER token read in.
yylex must look this up to detect typedefs, which get token type TYPENAME,
so it is left around in case the identifier is not a typedef but is
@@ -62,8 +85,6 @@ tree lastiddecl;
int doing_objc_thang;
-extern tree is_class_name ();
-
extern int yydebug;
/* File used for outputting assembler code. */
@@ -85,13 +106,24 @@ char *token_buffer; /* Pointer to token buffer.
Actual allocated length is maxtoken + 2.
This is not static because objc-parse.y uses it. */
+static int indent_level = 0; /* Number of { minus number of }. */
+
/* Nonzero if end-of-file has been seen on input. */
static int end_of_file;
+#if !USE_CPPLIB
/* Buffered-back input character; faster than using ungetc. */
static int nextchar = -1;
+#endif
-int check_newline ();
+#ifdef HANDLE_SYSV_PRAGMA
+static int handle_sysv_pragma PROTO((int));
+#endif /* HANDLE_SYSV_PRAGMA */
+static int whitespace_cr PROTO((int));
+static int skip_white_space PROTO((int));
+static int skip_white_space_on_line PROTO((void));
+static char *extend_token_buffer PROTO((char *));
+static int readescape PROTO((int *));
/* Do not insert generated code into the source, instead, include it.
This allows us to build gcc automatically even for targets that
@@ -142,6 +174,51 @@ remember_protocol_qualifiers ()
wordlist[i].name = "oneway";
}
+char *
+init_parse (filename)
+ char *filename;
+{
+#if !USE_CPPLIB
+ /* Open input file. */
+ if (filename == 0 || !strcmp (filename, "-"))
+ {
+ finput = stdin;
+ filename = "stdin";
+ }
+ else
+ finput = fopen (filename, "r");
+ if (finput == 0)
+ pfatal_with_name (filename);
+
+#ifdef IO_BUFFER_SIZE
+ setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE);
+#endif
+#endif /* !USE_CPPLIB */
+
+ init_lex ();
+
+#if USE_CPPLIB
+ yy_cur = "\n";
+ yy_lim = yy_cur+1;
+
+ parse_in.show_column = 1;
+ if (! cpp_start_read (&parse_in, filename))
+ abort ();
+#endif
+
+ return filename;
+}
+
+void
+finish_parse ()
+{
+#if USE_CPPLIB
+ cpp_finish (&parse_in);
+#else
+ fclose (finput);
+#endif
+}
+
void
init_lex ()
{
@@ -245,10 +322,14 @@ yyprint (file, yychar, yylval)
if (TREE_CODE (t) == INTEGER_CST)
fprintf (file,
#if HOST_BITS_PER_WIDE_INT == 64
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ " 0x%x%016x",
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
" 0x%lx%016lx",
#else
- " 0x%x%016x",
+ " 0x%llx%016llx",
+#endif
#endif
#else
#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
@@ -261,8 +342,30 @@ yyprint (file, yychar, yylval)
break;
}
}
-
+/* Iff C is a carriage return, warn about it - if appropriate -
+ and return nonzero. */
+static int
+whitespace_cr (c)
+ int c;
+{
+ static int newline_warning = 0;
+
+ if (c == '\r')
+ {
+ /* ANSI C says the effects of a carriage return in a source file
+ are undefined. */
+ if (pedantic && !newline_warning)
+ {
+ warning ("carriage return in source file");
+ warning ("(we only warn about the first carriage return)");
+ newline_warning = 1;
+ }
+ return 1;
+ }
+ return 0;
+}
+
/* If C is not whitespace, return C.
Otherwise skip whitespace and return first nonwhite char read. */
@@ -270,8 +373,6 @@ static int
skip_white_space (c)
register int c;
{
- static int newline_warning = 0;
-
for (;;)
{
switch (c)
@@ -289,28 +390,21 @@ skip_white_space (c)
case '\f':
case '\v':
case '\b':
- c = getc (finput);
+ c = GETC();
break;
case '\r':
- /* ANSI C says the effects of a carriage return in a source file
- are undefined. */
- if (pedantic && !newline_warning)
- {
- warning ("carriage return in source file");
- warning ("(we only warn about the first carriage return)");
- newline_warning = 1;
- }
- c = getc (finput);
+ whitespace_cr (c);
+ c = GETC();
break;
case '\\':
- c = getc (finput);
+ c = GETC();
if (c == '\n')
lineno++;
else
error ("stray '\\' in program");
- c = getc (finput);
+ c = GETC();
break;
default:
@@ -327,12 +421,46 @@ position_after_white_space ()
{
register int c;
+#if !USE_CPPLIB
if (nextchar != -1)
c = nextchar, nextchar = -1;
else
- c = getc (finput);
+#endif
+ c = GETC();
- ungetc (skip_white_space (c), finput);
+ UNGETC (skip_white_space (c));
+}
+
+/* Like skip_white_space, but don't advance beyond the end of line.
+ Moreover, we don't get passed a character to start with. */
+static int
+skip_white_space_on_line ()
+{
+ register int c;
+
+ while (1)
+ {
+ c = GETC();
+ switch (c)
+ {
+ case '\n':
+ default:
+ break;
+
+ case ' ':
+ case '\t':
+ case '\f':
+ case '\v':
+ case '\b':
+ continue;
+
+ case '\r':
+ whitespace_cr (c);
+ continue;
+ }
+ break;
+ }
+ return c;
}
/* Make the token buffer longer, preserving the data in it.
@@ -367,9 +495,9 @@ check_newline ()
/* Read first nonwhite char on the line. */
- c = getc (finput);
+ c = GETC();
while (c == ' ' || c == '\t')
- c = getc (finput);
+ c = GETC();
if (c != '#')
{
@@ -379,9 +507,9 @@ check_newline ()
/* Read first nonwhite char after the `#'. */
- c = getc (finput);
+ c = GETC();
while (c == ' ' || c == '\t')
- c = getc (finput);
+ c = GETC();
/* If a letter follows, then if the word here is `line', skip
it and ignore it; otherwise, ignore the line, with an error
@@ -391,86 +519,105 @@ check_newline ()
{
if (c == 'p')
{
- if (getc (finput) == 'r'
- && getc (finput) == 'a'
- && getc (finput) == 'g'
- && getc (finput) == 'm'
- && getc (finput) == 'a'
- && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'))
+ if (GETC() == 'r'
+ && GETC() == 'a'
+ && GETC() == 'g'
+ && GETC() == 'm'
+ && GETC() == 'a'
+ && ((c = GETC()) == ' ' || c == '\t' || c == '\n'
+ || whitespace_cr (c) ))
{
+ while (c == ' ' || c == '\t' || whitespace_cr (c))
+ c = GETC ();
+ if (c == '\n')
+ return c;
#ifdef HANDLE_SYSV_PRAGMA
- return handle_sysv_pragma (finput, c);
+ UNGETC (c);
+ token = yylex ();
+ if (token != IDENTIFIER)
+ goto skipline;
+ return handle_sysv_pragma (token);
#else /* !HANDLE_SYSV_PRAGMA */
#ifdef HANDLE_PRAGMA
- HANDLE_PRAGMA (finput);
+#if !USE_CPPLIB
+ UNGETC (c);
+ token = yylex ();
+ if (token != IDENTIFIER)
+ goto skipline;
+ if (nextchar >= 0)
+ c = nextchar, nextchar = -1;
+ else
+ c = GETC ();
+ ungetc (c, finput);
+ if (HANDLE_PRAGMA (finput, yylval.ttype))
+ {
+ c = GETC ();
+ return c;
+ }
+#else
+ ??? do not know what to do ???;
+#endif /* !USE_CPPLIB */
#endif /* HANDLE_PRAGMA */
- goto skipline;
#endif /* !HANDLE_SYSV_PRAGMA */
+ goto skipline;
}
}
else if (c == 'd')
{
- if (getc (finput) == 'e'
- && getc (finput) == 'f'
- && getc (finput) == 'i'
- && getc (finput) == 'n'
- && getc (finput) == 'e'
- && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'))
+ if (GETC() == 'e'
+ && GETC() == 'f'
+ && GETC() == 'i'
+ && GETC() == 'n'
+ && GETC() == 'e'
+ && ((c = GETC()) == ' ' || c == '\t' || c == '\n'))
{
-#ifdef DWARF_DEBUGGING_INFO
- if ((debug_info_level == DINFO_LEVEL_VERBOSE)
- && (write_symbols == DWARF_DEBUG))
- dwarfout_define (lineno, get_directive_line (finput));
-#endif /* DWARF_DEBUGGING_INFO */
+ if (c != '\n')
+ debug_define (lineno, GET_DIRECTIVE_LINE ());
goto skipline;
}
}
else if (c == 'u')
{
- if (getc (finput) == 'n'
- && getc (finput) == 'd'
- && getc (finput) == 'e'
- && getc (finput) == 'f'
- && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'))
+ if (GETC() == 'n'
+ && GETC() == 'd'
+ && GETC() == 'e'
+ && GETC() == 'f'
+ && ((c = GETC()) == ' ' || c == '\t' || c == '\n'))
{
-#ifdef DWARF_DEBUGGING_INFO
- if ((debug_info_level == DINFO_LEVEL_VERBOSE)
- && (write_symbols == DWARF_DEBUG))
- dwarfout_undef (lineno, get_directive_line (finput));
-#endif /* DWARF_DEBUGGING_INFO */
+ if (c != '\n')
+ debug_undef (lineno, GET_DIRECTIVE_LINE ());
goto skipline;
}
}
else if (c == 'l')
{
- if (getc (finput) == 'i'
- && getc (finput) == 'n'
- && getc (finput) == 'e'
- && ((c = getc (finput)) == ' ' || c == '\t'))
+ if (GETC() == 'i'
+ && GETC() == 'n'
+ && GETC() == 'e'
+ && ((c = GETC()) == ' ' || c == '\t'))
goto linenum;
}
else if (c == 'i')
{
- if (getc (finput) == 'd'
- && getc (finput) == 'e'
- && getc (finput) == 'n'
- && getc (finput) == 't'
- && ((c = getc (finput)) == ' ' || c == '\t'))
+ if (GETC() == 'd'
+ && GETC() == 'e'
+ && GETC() == 'n'
+ && GETC() == 't'
+ && ((c = GETC()) == ' ' || c == '\t'))
{
/* #ident. The pedantic warning is now in cccp.c. */
/* Here we have just seen `#ident '.
A string constant should follow. */
- while (c == ' ' || c == '\t')
- c = getc (finput);
+ c = skip_white_space_on_line ();
/* If no argument, ignore the line. */
if (c == '\n')
return c;
- ungetc (c, finput);
+ UNGETC (c);
token = yylex ();
if (token != STRING
|| TREE_CODE (yylval.ttype) != STRING_CST)
@@ -499,8 +646,11 @@ linenum:
/* Here we have either `#line' or `# <nonletter>'.
In either case, it should be a line number; a digit should follow. */
- while (c == ' ' || c == '\t')
- c = getc (finput);
+ /* Can't use skip_white_space here, but must handle all whitespace
+ that is not '\n', lest we get a recursion for '\r' '\n' when
+ calling yylex. */
+ UNGETC (c);
+ c = skip_white_space_on_line ();
/* If the # is the only nonwhite char on the line,
just ignore it. Check the new newline. */
@@ -509,7 +659,7 @@ linenum:
/* Something follows the #; read a token. */
- ungetc (c, finput);
+ UNGETC (c);
token = yylex ();
if (token == CONSTANT
@@ -523,16 +673,14 @@ linenum:
int l = TREE_INT_CST_LOW (yylval.ttype) - 1;
/* Is this the last nonwhite stuff on the line? */
- c = getc (finput);
- while (c == ' ' || c == '\t')
- c = getc (finput);
+ c = skip_white_space_on_line ();
if (c == '\n')
{
/* No more: store the line number and check following line. */
lineno = l;
return c;
}
- ungetc (c, finput);
+ UNGETC (c);
/* More follows: it must be a string constant (filename). */
@@ -558,9 +706,7 @@ linenum:
main_input_filename = input_filename;
/* Is this the last nonwhite stuff on the line? */
- c = getc (finput);
- while (c == ' ' || c == '\t')
- c = getc (finput);
+ c = skip_white_space_on_line ();
if (c == '\n')
{
/* Update the name in the top element of input_file_stack. */
@@ -569,7 +715,7 @@ linenum:
return c;
}
- ungetc (c, finput);
+ UNGETC (c);
token = yylex ();
used_up = 0;
@@ -588,14 +734,10 @@ linenum:
input_file_stack->line = old_lineno;
p->next = input_file_stack;
p->name = input_filename;
+ p->indent_level = indent_level;
input_file_stack = p;
input_file_stack_tick++;
-#ifdef DWARF_DEBUGGING_INFO
- if (debug_info_level == DINFO_LEVEL_VERBOSE
- && write_symbols == DWARF_DEBUG)
- dwarfout_start_new_source_file (input_filename);
-#endif /* DWARF_DEBUGGING_INFO */
-
+ debug_start_source_file (input_filename);
used_up = 1;
}
else if (TREE_INT_CST_LOW (yylval.ttype) == 2)
@@ -604,14 +746,18 @@ linenum:
if (input_file_stack->next)
{
struct file_stack *p = input_file_stack;
+ if (indent_level != p->indent_level)
+ {
+ warning_with_file_and_line
+ (p->name, old_lineno,
+ "This file contains more `%c's than `%c's.",
+ indent_level > p->indent_level ? '{' : '}',
+ indent_level > p->indent_level ? '}' : '{');
+ }
input_file_stack = p->next;
free (p);
input_file_stack_tick++;
-#ifdef DWARF_DEBUGGING_INFO
- if (debug_info_level == DINFO_LEVEL_VERBOSE
- && write_symbols == DWARF_DEBUG)
- dwarfout_resume_previous_source_file (input_file_stack->line);
-#endif /* DWARF_DEBUGGING_INFO */
+ debug_end_source_file (input_file_stack->line);
}
else
error ("#-lines for entering and leaving files don't match");
@@ -630,12 +776,10 @@ linenum:
if (used_up)
{
/* Is this the last nonwhite stuff on the line? */
- c = getc (finput);
- while (c == ' ' || c == '\t')
- c = getc (finput);
+ c = skip_white_space_on_line ();
if (c == '\n')
return c;
- ungetc (c, finput);
+ UNGETC (c);
token = yylex ();
used_up = 0;
@@ -651,12 +795,10 @@ linenum:
if (used_up)
{
/* Is this the last nonwhite stuff on the line? */
- c = getc (finput);
- while (c == ' ' || c == '\t')
- c = getc (finput);
+ c = skip_white_space_on_line ();
if (c == '\n')
return c;
- ungetc (c, finput);
+ UNGETC (c);
}
warning ("unrecognized text at end of #line");
@@ -666,37 +808,33 @@ linenum:
/* skip the rest of this line. */
skipline:
- if (c == '\n')
- return c;
- while ((c = getc (finput)) != EOF && c != '\n');
+#if !USE_CPPLIB
+ if (c != '\n' && c != EOF && nextchar >= 0)
+ c = nextchar, nextchar = -1;
+#endif
+ while (c != '\n' && c != EOF)
+ c = GETC();
return c;
}
#ifdef HANDLE_SYSV_PRAGMA
-/* Handle a #pragma directive. INPUT is the current input stream,
- and C is a character to reread. Processes the entire input line
- and returns a character for the caller to reread: either \n or EOF. */
+/* Handle a #pragma directive.
+ TOKEN is the token we read after `#pragma'. Processes the entire input
+ line and returns a character for the caller to reread: either \n or EOF. */
/* This function has to be in this file, in order to get at
the token types. */
-int
-handle_sysv_pragma (input, c)
- FILE *input;
- int c;
+static int
+handle_sysv_pragma (token)
+ register int token;
{
+ register int c;
+
for (;;)
{
- while (c == ' ' || c == '\t')
- c = getc (input);
- if (c == '\n' || c == EOF)
- {
- handle_pragma_token (0, 0);
- return c;
- }
- ungetc (c, input);
- switch (yylex ())
+ switch (token)
{
case IDENTIFIER:
case TYPENAME:
@@ -707,10 +845,22 @@ handle_sysv_pragma (input, c)
default:
handle_pragma_token (token_buffer, 0);
}
+#if !USE_CPPLIB
if (nextchar >= 0)
c = nextchar, nextchar = -1;
else
- c = getc (input);
+#endif
+ c = GETC ();
+
+ while (c == ' ' || c == '\t')
+ c = GETC ();
+ if (c == '\n' || c == EOF)
+ {
+ handle_pragma_token (0, 0);
+ return c;
+ }
+ UNGETC (c);
+ token = yylex ();
}
}
@@ -725,7 +875,7 @@ static int
readescape (ignore_ptr)
int *ignore_ptr;
{
- register int c = getc (finput);
+ register int c = GETC();
register int code;
register unsigned count;
unsigned firstdig = 0;
@@ -745,12 +895,12 @@ readescape (ignore_ptr)
nonnull = 0;
while (1)
{
- c = getc (finput);
+ c = GETC();
if (!(c >= 'a' && c <= 'f')
&& !(c >= 'A' && c <= 'F')
&& !(c >= '0' && c <= '9'))
{
- ungetc (c, finput);
+ UNGETC (c);
break;
}
code *= 16;
@@ -787,9 +937,9 @@ readescape (ignore_ptr)
while ((c <= '7') && (c >= '0') && (count++ < 3))
{
code = (code * 8) + (c - '0');
- c = getc (finput);
+ c = GETC();
}
- ungetc (c, finput);
+ UNGETC (c);
return code;
case '\\': case '\'': case '"':
@@ -913,10 +1063,12 @@ yylex ()
int wide_flag = 0;
int objc_flag = 0;
+#if !USE_CPPLIB
if (nextchar >= 0)
c = nextchar, nextchar = -1;
else
- c = getc (finput);
+#endif
+ c = GETC();
/* Effectively do c = skip_white_space (c)
but do it faster in the usual cases. */
@@ -928,7 +1080,7 @@ yylex ()
case '\f':
case '\v':
case '\b':
- c = getc (finput);
+ c = GETC();
break;
case '\r':
@@ -956,15 +1108,10 @@ yylex ()
value = ENDFILE;
break;
- case '$':
- if (dollars_in_ident)
- goto letter;
- return '$';
-
case 'L':
/* Capital L may start a wide-string or wide-character constant. */
{
- register int c = getc (finput);
+ register int c = GETC();
if (c == '\'')
{
wide_flag = 1;
@@ -975,7 +1122,7 @@ yylex ()
wide_flag = 1;
goto string_constant;
}
- ungetc (c, finput);
+ UNGETC (c);
}
goto letter;
@@ -988,13 +1135,13 @@ yylex ()
else
{
/* '@' may start a constant string object. */
- register int c = getc(finput);
+ register int c = GETC ();
if (c == '"')
{
objc_flag = 1;
goto string_constant;
}
- ungetc(c, finput);
+ UNGETC (c);
/* Fall through to treat '@' as the start of an identifier. */
}
@@ -1011,25 +1158,35 @@ yylex ()
case 'u': case 'v': case 'w': case 'x': case 'y':
case 'z':
case '_':
+ case '$':
letter:
p = token_buffer;
- while (isalnum (c) || c == '_' || c == '$' || c == '@')
+ while (ISALNUM (c) || c == '_' || c == '$' || c == '@')
{
/* Make sure this char really belongs in an identifier. */
if (c == '@' && ! doing_objc_thang)
break;
- if (c == '$' && ! dollars_in_ident)
- break;
+ if (c == '$')
+ {
+ if (! dollars_in_ident)
+ error ("`$' in identifier");
+ else if (pedantic)
+ pedwarn ("`$' in identifier");
+ }
if (p >= token_buffer + maxtoken)
p = extend_token_buffer (p);
*p++ = c;
- c = getc (finput);
+ c = GETC();
}
*p = 0;
+#if USE_CPPLIB
+ UNGETC (c);
+#else
nextchar = c;
+#endif
value = IDENTIFIER;
yylval.itype = 0;
@@ -1039,7 +1196,7 @@ yylex ()
{
register struct resword *ptr;
- if (ptr = is_reserved_word (token_buffer, p - token_buffer))
+ if ((ptr = is_reserved_word (token_buffer, p - token_buffer)))
{
if (ptr->rid)
yylval.ttype = ridpointers[(int) ptr->rid];
@@ -1109,7 +1266,23 @@ yylex ()
break;
- case '0': case '1': case '2': case '3': case '4':
+ case '0': case '1':
+ {
+ int next_c;
+ /* Check first for common special case: single-digit 0 or 1. */
+
+ next_c = GETC ();
+ UNGETC (next_c); /* Always undo this lookahead. */
+ if (!ISALNUM (next_c) && next_c != '.')
+ {
+ token_buffer[0] = (char)c, token_buffer[1] = '\0';
+ yylval.ttype = (c == '0') ? integer_zero_node : integer_one_node;
+ value = CONSTANT;
+ break;
+ }
+ /*FALLTHRU*/
+ }
+ case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
{
@@ -1138,11 +1311,11 @@ yylex ()
if (c == '0')
{
- *p++ = (c = getc (finput));
+ *p++ = (c = GETC());
if ((c == 'x') || (c == 'X'))
{
base = 16;
- *p++ = (c = getc (finput));
+ *p++ = (c = GETC());
}
/* Leading 0 forces octal unless the 0 is the only digit. */
else if (c >= '0' && c <= '9')
@@ -1157,7 +1330,7 @@ yylex ()
/* Read all the digits-and-decimal-points. */
while (c == '.'
- || (isalnum (c) && c != 'l' && c != 'L'
+ || (ISALNUM (c) && c != 'l' && c != 'L'
&& c != 'u' && c != 'U'
&& c != 'i' && c != 'I' && c != 'j' && c != 'J'
&& (floatflag == NOT_FLOAT || ((c != 'f') && (c != 'F')))))
@@ -1181,16 +1354,16 @@ yylex ()
floatflag = AFTER_POINT;
base = 10;
- *p++ = c = getc (finput);
+ *p++ = c = GETC();
/* Accept '.' as the start of a floating-point number
only when it is followed by a digit.
Otherwise, unread the following non-digit
and use the '.' as a structural token. */
- if (p == token_buffer + 2 && !isdigit (c))
+ if (p == token_buffer + 2 && !ISDIGIT (c))
{
if (c == '.')
{
- c = getc (finput);
+ c = GETC();
if (c == '.')
{
*p++ = c;
@@ -1199,7 +1372,7 @@ yylex ()
}
error ("parse error at `..'");
}
- ungetc (c, finput);
+ UNGETC (c);
token_buffer[1] = 0;
value = '.';
goto done;
@@ -1210,7 +1383,7 @@ yylex ()
/* It is not a decimal point.
It should be a digit (perhaps a hex digit). */
- if (isdigit (c))
+ if (ISDIGIT (c))
{
c = c - '0';
}
@@ -1258,7 +1431,7 @@ yylex ()
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
- *p++ = (c = getc (finput));
+ *p++ = (c = GETC());
}
}
@@ -1274,8 +1447,8 @@ yylex ()
if (floatflag != NOT_FLOAT)
{
tree type = double_type_node;
- int garbage_chars = 0, exceeds_double = 0;
int imag = 0;
+ int conversion_errno = 0;
REAL_VALUE_TYPE value;
jmp_buf handler;
@@ -1286,25 +1459,24 @@ yylex ()
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
*p++ = c;
- c = getc (finput);
+ c = GETC();
if ((c == '+') || (c == '-'))
{
*p++ = c;
- c = getc (finput);
+ c = GETC();
}
- if (! isdigit (c))
+ if (! ISDIGIT (c))
error ("floating constant exponent has no digits");
- while (isdigit (c))
+ while (ISDIGIT (c))
{
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
*p++ = c;
- c = getc (finput);
+ c = GETC();
}
}
*p = 0;
- errno = 0;
/* Convert string to a double, checking for overflow. */
if (setjmp (handler))
@@ -1361,7 +1533,7 @@ yylex ()
p = extend_token_buffer (p);
*p++ = c;
*p = 0;
- c = getc (finput);
+ c = GETC();
}
/* The second argument, machine_mode, of REAL_VALUE_ATOF
@@ -1374,7 +1546,9 @@ yylex ()
error ("both `f' and `l' in floating constant");
type = float_type_node;
+ errno = 0;
value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+ conversion_errno = errno;
/* A diagnostic is required here by some ANSI C testsuites.
This is not pedwarn, become some people don't want
an error for this. */
@@ -1384,13 +1558,17 @@ yylex ()
else if (lflag)
{
type = long_double_type_node;
+ errno = 0;
value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+ conversion_errno = errno;
if (REAL_VALUE_ISINF (value) && pedantic)
warning ("floating point number exceeds range of `long double'");
}
else
{
+ errno = 0;
value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+ conversion_errno = errno;
if (REAL_VALUE_ISINF (value) && pedantic)
warning ("floating point number exceeds range of `double'");
}
@@ -1398,31 +1576,13 @@ yylex ()
set_float_handler (NULL_PTR);
}
#ifdef ERANGE
- if (errno == ERANGE && !flag_traditional && pedantic)
- {
- /* ERANGE is also reported for underflow,
- so test the value to distinguish overflow from that. */
- if (REAL_VALUES_LESS (dconst1, value)
- || REAL_VALUES_LESS (value, dconstm1))
- {
- warning ("floating point number exceeds range of `double'");
- exceeds_double = 1;
- }
- }
+ /* ERANGE is also reported for underflow,
+ so test the value to distinguish overflow from that. */
+ if (conversion_errno == ERANGE && !flag_traditional && pedantic
+ && (REAL_VALUES_LESS (dconst1, value)
+ || REAL_VALUES_LESS (value, dconstm1)))
+ warning ("floating point number exceeds range of `double'");
#endif
- garbage_chars = 0;
- while (isalnum (c) || c == '.' || c == '_'
- || (!flag_traditional && (c == '+' || c == '-')
- && (p[-1] == 'e' || p[-1] == 'E')))
- {
- if (p >= token_buffer + maxtoken - 3)
- p = extend_token_buffer (p);
- *p++ = c;
- c = getc (finput);
- garbage_chars++;
- }
- if (garbage_chars > 0)
- error ("garbage at end of number");
/* If the result is not a number, assume it must have been
due to some error message above, so silently convert
@@ -1432,13 +1592,11 @@ yylex ()
/* Create a node with determined type and value. */
if (imag)
- yylval.ttype = build_complex (convert (type, integer_zero_node),
+ yylval.ttype = build_complex (NULL_TREE,
+ convert (type, integer_zero_node),
build_real (type, value));
else
yylval.ttype = build_real (type, value);
-
- ungetc (c, finput);
- *p = 0;
}
else
{
@@ -1450,6 +1608,7 @@ yylex ()
int spec_imag = 0;
int bytes, warn, i;
+ traditional_type = ansi_type = type = NULL_TREE;
while (1)
{
if (c == 'u' || c == 'U')
@@ -1479,46 +1638,22 @@ yylex ()
spec_imag = 1;
}
else
- {
- if (isalnum (c) || c == '.' || c == '_'
- || (!flag_traditional && (c == '+' || c == '-')
- && (p[-1] == 'e' || p[-1] == 'E')))
- {
- error ("garbage at end of number");
- while (isalnum (c) || c == '.' || c == '_'
- || (!flag_traditional && (c == '+' || c == '-')
- && (p[-1] == 'e' || p[-1] == 'E')))
- {
- if (p >= token_buffer + maxtoken - 3)
- p = extend_token_buffer (p);
- *p++ = c;
- c = getc (finput);
- }
- }
- break;
- }
+ break;
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
*p++ = c;
- c = getc (finput);
+ c = GETC();
}
- ungetc (c, finput);
-
- /* If the constant is not long long and it won't fit in an
- unsigned long, or if the constant is long long and won't fit
- in an unsigned long long, then warn that the constant is out
- of range. */
+ /* If the constant won't fit in an unsigned long long,
+ then warn that the constant is out of range. */
/* ??? This assumes that long long and long integer types are
a multiple of 8 bits. This better than the original code
though which assumed that long was exactly 32 bits and long
long was exactly 64 bits. */
- if (spec_long_long)
- bytes = TYPE_PRECISION (long_long_integer_type_node) / 8;
- else
- bytes = TYPE_PRECISION (long_integer_type_node) / 8;
+ bytes = TYPE_PRECISION (long_long_integer_type_node) / 8;
warn = overflow;
for (i = bytes; i < TOTAL_PARTS; i++)
@@ -1585,11 +1720,11 @@ yylex ()
else if (! spec_unsigned && !spec_long_long
&& int_fits_type_p (yylval.ttype, long_integer_type_node))
ansi_type = long_integer_type_node;
- else if (! spec_long_long)
+ else if (! spec_long_long
+ && int_fits_type_p (yylval.ttype,
+ long_unsigned_type_node))
ansi_type = long_unsigned_type_node;
else if (! spec_unsigned
- /* Verify value does not overflow into sign bit. */
- && TREE_INT_CST_HIGH (yylval.ttype) >= 0
&& int_fits_type_p (yylval.ttype,
long_long_integer_type_node))
ansi_type = long_long_integer_type_node;
@@ -1611,8 +1746,9 @@ yylex ()
warning ("width of integer constant may change on other systems with -traditional");
}
- if (!flag_traditional && !int_fits_type_p (yylval.ttype, type)
- && !warn)
+ if (pedantic && !flag_traditional && !spec_long_long && !warn
+ && (TYPE_PRECISION (long_integer_type_node)
+ < TYPE_PRECISION (type)))
pedwarn ("integer constant out of range");
if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type))
@@ -1623,8 +1759,9 @@ yylex ()
if (TYPE_PRECISION (type)
<= TYPE_PRECISION (integer_type_node))
yylval.ttype
- = build_complex (integer_zero_node,
- convert (integer_type_node, yylval.ttype));
+ = build_complex (NULL_TREE, integer_zero_node,
+ convert (integer_type_node,
+ yylval.ttype));
else
error ("complex integer constant is too wide for `complex int'");
}
@@ -1640,10 +1777,16 @@ yylex ()
}
else
TREE_TYPE (yylval.ttype) = type;
-
- *p = 0;
}
+ UNGETC (c);
+ *p = 0;
+
+ if (ISALNUM (c) || c == '.' || c == '_' || c == '$'
+ || (!flag_traditional && (c == '-' || c == '+')
+ && (p[-1] == 'e' || p[-1] == 'E')))
+ error ("missing white space after number `%s'", token_buffer);
+
value = CONSTANT; break;
}
@@ -1671,7 +1814,7 @@ yylex ()
{
tryagain:
- c = getc (finput);
+ c = GETC();
if (c == '\'' || c == EOF)
break;
@@ -1686,7 +1829,7 @@ yylex ()
&& (unsigned) c >= (1 << width))
pedwarn ("escape sequence out of range for character");
#ifdef MAP_CHARACTER
- if (isprint (c))
+ if (ISPRINT (c))
c = MAP_CHARACTER (c);
#endif
}
@@ -1729,7 +1872,7 @@ yylex ()
num_chars = max_chars;
error ("character constant too long");
}
- else if (num_chars != 1 && ! flag_traditional)
+ else if (num_chars != 1 && ! flag_traditional && warn_multichar)
warning ("multi-character character constant");
/* If char type is signed, sign-extend the constant. */
@@ -1742,12 +1885,12 @@ yylex ()
else if (TREE_UNSIGNED (char_type_node)
|| ((result >> (num_bits - 1)) & 1) == 0)
yylval.ttype
- = build_int_2 (result & ((unsigned HOST_WIDE_INT) ~0
+ = build_int_2 (result & (~(unsigned HOST_WIDE_INT) 0
>> (HOST_BITS_PER_WIDE_INT - num_bits)),
0);
else
yylval.ttype
- = build_int_2 (result | ~((unsigned HOST_WIDE_INT) ~0
+ = build_int_2 (result | ~(~(unsigned HOST_WIDE_INT) 0
>> (HOST_BITS_PER_WIDE_INT - num_bits)),
-1);
TREE_TYPE (yylval.ttype) = integer_type_node;
@@ -1781,7 +1924,7 @@ yylex ()
case '"':
string_constant:
{
- c = getc (finput);
+ c = GETC();
p = token_buffer + 1;
while (c != '"' && c >= 0)
@@ -1809,7 +1952,7 @@ yylex ()
*p++ = c;
skipnewline:
- c = getc (finput);
+ c = GETC();
}
*p = 0;
@@ -1836,15 +1979,9 @@ yylex ()
bzero (widep + (len * WCHAR_BYTES), WCHAR_BYTES);
#else
{
- union { long l; char c[sizeof (long)]; } u;
- int big_endian;
char *wp, *cp;
- /* Determine whether host is little or big endian. */
- u.l = 1;
- big_endian = u.c[sizeof (long) - 1];
- wp = widep + (big_endian ? WCHAR_BYTES - 1 : 0);
-
+ wp = widep + (BYTES_BIG_ENDIAN ? WCHAR_BYTES - 1 : 0);
bzero (widep, (p - token_buffer) * WCHAR_BYTES);
for (cp = token_buffer + 1; cp < p; cp++)
*wp = *cp, wp += WCHAR_BYTES;
@@ -1857,7 +1994,6 @@ yylex ()
}
else if (objc_flag)
{
- extern tree build_objc_string();
/* Return an Objective-C @"..." constant string object. */
yylval.ttype = build_objc_string (p - token_buffer,
token_buffer + 1);
@@ -1923,7 +2059,7 @@ yylex ()
yylval.code = GT_EXPR; break;
}
- token_buffer[1] = c1 = getc (finput);
+ token_buffer[1] = c1 = GETC();
token_buffer[2] = 0;
if (c1 == '=')
@@ -1972,16 +2108,16 @@ yylex ()
break;
case '<':
if (c1 == '%')
- { value = '{'; goto done; }
+ { value = '{'; indent_level++; goto done; }
if (c1 == ':')
{ value = '['; goto done; }
break;
case '%':
if (c1 == '>')
- { value = '}'; goto done; }
+ { value = '}'; indent_level--; goto done; }
break;
}
- ungetc (c1, finput);
+ UNGETC (c1);
token_buffer[1] = 0;
if ((c == '<') || (c == '>'))
@@ -1995,6 +2131,16 @@ yylex ()
value = 1;
break;
+ case '{':
+ indent_level++;
+ value = c;
+ break;
+
+ case '}':
+ indent_level--;
+ value = c;
+ break;
+
default:
value = c;
}
diff --git a/contrib/gcc/c-lex.h b/contrib/gcc/c-lex.h
index c1aed08..bd0b9d4 100644
--- a/contrib/gcc/c-lex.h
+++ b/contrib/gcc/c-lex.h
@@ -73,8 +73,14 @@ extern tree lastiddecl;
extern char *token_buffer; /* Pointer to token buffer. */
-extern tree make_pointer_declarator ();
-extern void reinit_parse_for_function ();
-extern int yylex ();
+extern tree make_pointer_declarator PROTO((tree, tree));
+extern void reinit_parse_for_function PROTO((void));
+extern void position_after_white_space PROTO((void));
+extern int check_newline PROTO((void));
-extern char *get_directive_line ();
+extern int yylex PROTO((void));
+extern void yyerror PROTO((char *));
+
+extern void forget_protocol_qualifiers PROTO((void));
+extern void remember_protocol_qualifiers PROTO((void));
+extern tree is_class_name PROTO((tree));
diff --git a/contrib/gcc/c-parse.in b/contrib/gcc/c-parse.in
index 044e452..16500c5 100644
--- a/contrib/gcc/c-parse.in
+++ b/contrib/gcc/c-parse.in
@@ -1,5 +1,5 @@
/* YACC parser for C syntax and for Objective C. -*-c-*-
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -28,10 +28,10 @@ Boston, MA 02111-1307, USA. */
written by AT&T, but I have never seen it. */
ifobjc
-%expect 48
+%expect 66
end ifobjc
ifc
-%expect 34
+%expect 46
/* These are the 23 conflicts you should get in parse.output;
the state numbers may vary if minor changes in the grammar are made.
@@ -58,19 +58,19 @@ State 434 contains 2 shift/reduce conflicts. (Four ways to parse this.) */
end ifc
%{
-#include <stdio.h>
-#include <errno.h>
+#include "config.h"
+#include "system.h"
#include <setjmp.h>
-#include "config.h"
#include "tree.h"
#include "input.h"
#include "c-lex.h"
#include "c-tree.h"
#include "flags.h"
+#include "output.h"
+#include "toplev.h"
#ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
#include <locale.h>
#endif
@@ -87,12 +87,6 @@ ifc
char *language_string = "GNU C";
end ifc
-#ifndef errno
-extern int errno;
-#endif
-
-void yyerror ();
-
/* Like YYERROR but do call yyerror. */
#define YYERROR1 { yyerror ("syntax error"); YYERROR; }
@@ -185,6 +179,8 @@ void yyerror ();
%type <ttype> typed_declspecs reserved_declspecs
%type <ttype> typed_typespecs reserved_typespecquals
%type <ttype> declmods typespec typespecqual_reserved
+%type <ttype> typed_declspecs_no_prefix_attr reserved_declspecs_no_prefix_attr
+%type <ttype> declmods_no_prefix_attr
%type <ttype> SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual
%type <ttype> initdecls notype_initdecls initdcl notype_initdcl
%type <ttype> init maybeasm
@@ -201,6 +197,7 @@ void yyerror ();
%type <ttype> structsp component_decl_list component_decl_list2
%type <ttype> component_decl components component_declarator
%type <ttype> enumlist enumerator
+%type <ttype> struct_head union_head enum_head
%type <ttype> typename absdcl absdcl1 type_quals
%type <ttype> xexpr parms parm identifiers
@@ -224,21 +221,24 @@ ifobjc
%type <ttype> keywordexpr keywordarglist keywordarg
%type <ttype> myparms myparm optparmlist reservedwords objcselectorexpr
%type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
-%type <ttype> objc_string protocolrefs identifier_list objcprotocolexpr
+%type <ttype> objc_string non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
+
%type <ttype> CLASSNAME OBJC_STRING OBJECTNAME
end ifobjc
%{
-/* Number of statements (loosely speaking) seen so far. */
+/* Number of statements (loosely speaking) and compound statements
+ seen so far. */
static int stmt_count;
-
+static int compstmt_count;
+
/* Input file and line number of the end of the body of last simple_if;
used by the stmt-rule immediately after simple_if returns. */
static char *if_stmt_file;
static int if_stmt_line;
/* List of types and structure classes of the current declaration. */
-static tree current_declspecs;
+static tree current_declspecs = NULL_TREE;
static tree prefix_attributes = NULL_TREE;
/* Stack of saved values of current_declspecs and prefix_attributes. */
@@ -264,7 +264,7 @@ end ifobjc
/* Tell yyparse how to print a token's value, if yydebug is set. */
#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
-extern void yyprint ();
+extern void yyprint PROTO ((FILE *, int, YYSTYPE));
%}
%%
@@ -306,6 +306,8 @@ end ifobjc
assemble_asm ($3);
else
error ("argument of `asm' is not a constant string"); }
+ | extension extdef
+ { pedantic = $<itype>1; }
;
datadef:
@@ -342,11 +344,11 @@ datadef:
fndef:
typed_declspecs setspecs declarator
- { if (! start_function ($1, $3, prefix_attributes,
- NULL_TREE, 0))
+ { if (! start_function (current_declspecs, $3,
+ prefix_attributes, NULL_TREE, 0))
YYERROR1;
reinit_parse_for_function (); }
- xdecls
+ old_style_parm_decls
{ store_parm_decls (); }
compstmt_or_error
{ finish_function (0);
@@ -360,11 +362,11 @@ fndef:
declspec_stack = TREE_CHAIN (declspec_stack);
resume_momentary ($2); }
| declmods setspecs notype_declarator
- { if (! start_function ($1, $3, prefix_attributes,
- NULL_TREE, 0))
+ { if (! start_function (current_declspecs, $3,
+ prefix_attributes, NULL_TREE, 0))
YYERROR1;
reinit_parse_for_function (); }
- xdecls
+ old_style_parm_decls
{ store_parm_decls (); }
compstmt_or_error
{ finish_function (0);
@@ -382,7 +384,7 @@ fndef:
prefix_attributes, NULL_TREE, 0))
YYERROR1;
reinit_parse_for_function (); }
- xdecls
+ old_style_parm_decls
{ store_parm_decls (); }
compstmt_or_error
{ finish_function (0);
@@ -444,11 +446,8 @@ unary_expr:
| '*' cast_expr %prec UNARY
{ $$ = build_indirect_ref ($2, "unary *"); }
/* __extension__ turns off -pedantic for following primary. */
- | EXTENSION
- { $<itype>1 = pedantic;
- pedantic = 0; }
- cast_expr %prec UNARY
- { $$ = $3;
+ | extension cast_expr %prec UNARY
+ { $$ = $2;
pedantic = $<itype>1; }
| unop cast_expr %prec UNARY
{ $$ = build_unary_op ($1, $2, 0);
@@ -482,23 +481,35 @@ unary_expr:
$$ = build_unary_op (ADDR_EXPR, $$, 0);
} }
*/
- | SIZEOF unary_expr %prec UNARY
- { if (TREE_CODE ($2) == COMPONENT_REF
- && DECL_BIT_FIELD (TREE_OPERAND ($2, 1)))
+ | sizeof unary_expr %prec UNARY
+ { skip_evaluation--;
+ if (TREE_CODE ($2) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND ($2, 1)))
error ("`sizeof' applied to a bit-field");
$$ = c_sizeof (TREE_TYPE ($2)); }
- | SIZEOF '(' typename ')' %prec HYPERUNARY
- { $$ = c_sizeof (groktypename ($3)); }
- | ALIGNOF unary_expr %prec UNARY
- { $$ = c_alignof_expr ($2); }
- | ALIGNOF '(' typename ')' %prec HYPERUNARY
- { $$ = c_alignof (groktypename ($3)); }
+ | sizeof '(' typename ')' %prec HYPERUNARY
+ { skip_evaluation--;
+ $$ = c_sizeof (groktypename ($3)); }
+ | alignof unary_expr %prec UNARY
+ { skip_evaluation--;
+ $$ = c_alignof_expr ($2); }
+ | alignof '(' typename ')' %prec HYPERUNARY
+ { skip_evaluation--;
+ $$ = c_alignof (groktypename ($3)); }
| REALPART cast_expr %prec UNARY
{ $$ = build_unary_op (REALPART_EXPR, $2, 0); }
| IMAGPART cast_expr %prec UNARY
{ $$ = build_unary_op (IMAGPART_EXPR, $2, 0); }
;
+sizeof:
+ SIZEOF { skip_evaluation++; }
+ ;
+
+alignof:
+ ALIGNOF { skip_evaluation++; }
+ ;
+
cast_expr:
unary_expr
| '(' typename ')' cast_expr %prec UNARY
@@ -561,12 +572,37 @@ expr_no_commas:
{ $$ = parser_build_binary_op ($2, $1, $3); }
| expr_no_commas '^' expr_no_commas
{ $$ = parser_build_binary_op ($2, $1, $3); }
- | expr_no_commas ANDAND expr_no_commas
- { $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $3); }
- | expr_no_commas OROR expr_no_commas
- { $$ = parser_build_binary_op (TRUTH_ORIF_EXPR, $1, $3); }
- | expr_no_commas '?' xexpr ':' expr_no_commas
- { $$ = build_conditional_expr ($1, $3, $5); }
+ | expr_no_commas ANDAND
+ { $1 = truthvalue_conversion (default_conversion ($1));
+ skip_evaluation += $1 == boolean_false_node; }
+ expr_no_commas
+ { skip_evaluation -= $1 == boolean_false_node;
+ $$ = parser_build_binary_op (TRUTH_ANDIF_EXPR, $1, $4); }
+ | expr_no_commas OROR
+ { $1 = truthvalue_conversion (default_conversion ($1));
+ skip_evaluation += $1 == boolean_true_node; }
+ expr_no_commas
+ { skip_evaluation -= $1 == boolean_true_node;
+ $$ = parser_build_binary_op (TRUTH_ORIF_EXPR, $1, $4); }
+ | expr_no_commas '?'
+ { $1 = truthvalue_conversion (default_conversion ($1));
+ skip_evaluation += $1 == boolean_false_node; }
+ expr ':'
+ { skip_evaluation += (($1 == boolean_true_node)
+ - ($1 == boolean_false_node)); }
+ expr_no_commas
+ { skip_evaluation -= $1 == boolean_true_node;
+ $$ = build_conditional_expr ($1, $4, $7); }
+ | expr_no_commas '?'
+ { if (pedantic)
+ pedwarn ("ANSI C forbids omitting the middle term of a ?: expression");
+ /* Make sure first operand is calculated only once. */
+ $<ttype>2 = save_expr ($1);
+ $1 = truthvalue_conversion (default_conversion ($<ttype>2));
+ skip_evaluation += $1 == boolean_true_node; }
+ ':' expr_no_commas
+ { skip_evaluation -= $1 == boolean_true_node;
+ $$ = build_conditional_expr ($1, $<ttype>2, $5); }
| expr_no_commas '=' expr_no_commas
{ $$ = build_modify_expr ($1, NOP_EXPR, $3);
C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); }
@@ -640,7 +676,7 @@ end ifobjc
if (IDENTIFIER_GLOBAL_VALUE ($1) != error_mark_node
|| IDENTIFIER_ERROR_LOCUS ($1) != current_function_decl)
{
- error ("`%s' undeclared (first use this function)",
+ error ("`%s' undeclared (first use in this function)",
IDENTIFIER_POINTER ($1));
if (! undeclared_variable_notice)
@@ -861,7 +897,7 @@ objc_string:
;
end ifobjc
-xdecls:
+old_style_parm_decls:
/* empty */
| datadecls
| datadecls ELLIPSIS
@@ -886,21 +922,25 @@ datadecls:
| lineno_datadecl errstmt
;
+/* We don't allow prefix attributes here because they cause reduce/reduce
+ conflicts: we can't know whether we're parsing a function decl with
+ attribute suffix, or function defn with attribute prefix on first old
+ style parm. */
datadecl:
- typed_declspecs setspecs initdecls ';'
+ typed_declspecs_no_prefix_attr setspecs initdecls ';'
{ current_declspecs = TREE_VALUE (declspec_stack);
prefix_attributes = TREE_PURPOSE (declspec_stack);
declspec_stack = TREE_CHAIN (declspec_stack);
resume_momentary ($2); }
- | declmods setspecs notype_initdecls ';'
+ | declmods_no_prefix_attr setspecs notype_initdecls ';'
{ current_declspecs = TREE_VALUE (declspec_stack);
prefix_attributes = TREE_PURPOSE (declspec_stack);
declspec_stack = TREE_CHAIN (declspec_stack);
resume_momentary ($2); }
- | typed_declspecs ';'
+ | typed_declspecs_no_prefix_attr ';'
{ shadow_tag_warned ($1, 1);
pedwarn ("empty declaration"); }
- | declmods ';'
+ | declmods_no_prefix_attr ';'
{ pedwarn ("empty declaration"); }
;
@@ -930,10 +970,11 @@ setspecs: /* empty */
declspec_stack = tree_cons (prefix_attributes,
current_declspecs,
declspec_stack);
- current_declspecs = $<ttype>0;
- prefix_attributes = NULL_TREE; }
+ split_specs_attrs ($<ttype>0,
+ &current_declspecs, &prefix_attributes); }
;
+/* ??? Yuck. See after_type_declarator. */
setattrs: /* empty */
{ prefix_attributes = chainon (prefix_attributes, $<ttype>0); }
;
@@ -963,11 +1004,14 @@ decl:
{ shadow_tag ($1); }
| declmods ';'
{ pedwarn ("empty declaration"); }
+ | extension decl
+ { pedantic = $<itype>1; }
;
/* Declspecs which contain at least one type specifier or typedef name.
(Just `const' or `volatile' is not enough.)
- A typedef'd name following these is taken as a name to be declared. */
+ A typedef'd name following these is taken as a name to be declared.
+ Declspecs have a non-NULL TREE_VALUE, attributes do not. */
typed_declspecs:
typespec reserved_declspecs
@@ -985,22 +1029,55 @@ reserved_declspecs: /* empty */
warning ("`%s' is not at beginning of declaration",
IDENTIFIER_POINTER ($2));
$$ = tree_cons (NULL_TREE, $2, $1); }
+ | reserved_declspecs attributes
+ { $$ = tree_cons ($2, NULL_TREE, $1); }
+ ;
+
+typed_declspecs_no_prefix_attr:
+ typespec reserved_declspecs_no_prefix_attr
+ { $$ = tree_cons (NULL_TREE, $1, $2); }
+ | declmods_no_prefix_attr typespec reserved_declspecs_no_prefix_attr
+ { $$ = chainon ($3, tree_cons (NULL_TREE, $2, $1)); }
+ ;
+
+reserved_declspecs_no_prefix_attr:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | reserved_declspecs_no_prefix_attr typespecqual_reserved
+ { $$ = tree_cons (NULL_TREE, $2, $1); }
+ | reserved_declspecs_no_prefix_attr SCSPEC
+ { if (extra_warnings)
+ warning ("`%s' is not at beginning of declaration",
+ IDENTIFIER_POINTER ($2));
+ $$ = tree_cons (NULL_TREE, $2, $1); }
;
-/* List of just storage classes and type modifiers.
+/* List of just storage classes, type modifiers, and prefix attributes.
A declaration can start with just this, but then it cannot be used
- to redeclare a typedef-name. */
+ to redeclare a typedef-name.
+ Declspecs have a non-NULL TREE_VALUE, attributes do not. */
declmods:
+ declmods_no_prefix_attr
+ { $$ = $1; }
+ | attributes
+ { $$ = tree_cons ($1, NULL_TREE, NULL_TREE); }
+ | declmods declmods_no_prefix_attr
+ { $$ = chainon ($2, $1); }
+ | declmods attributes
+ { $$ = tree_cons ($2, NULL_TREE, $1); }
+ ;
+
+declmods_no_prefix_attr:
TYPE_QUAL
{ $$ = tree_cons (NULL_TREE, $1, NULL_TREE);
TREE_STATIC ($$) = 1; }
| SCSPEC
{ $$ = tree_cons (NULL_TREE, $1, NULL_TREE); }
- | declmods TYPE_QUAL
+ | declmods_no_prefix_attr TYPE_QUAL
{ $$ = tree_cons (NULL_TREE, $2, $1);
TREE_STATIC ($$) = 1; }
- | declmods SCSPEC
+ | declmods_no_prefix_attr SCSPEC
{ if (extra_warnings && TREE_STATIC ($1))
warning ("`%s' is not at beginning of declaration",
IDENTIFIER_POINTER ($2));
@@ -1041,6 +1118,11 @@ ifobjc
{ $$ = get_static_reference ($1, $2); }
| OBJECTNAME protocolrefs
{ $$ = get_object_reference ($2); }
+
+/* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>"
+ - nisse@lysator.liu.se */
+ | non_empty_protocolrefs
+ { $$ = get_object_reference ($1); }
end ifobjc
| TYPEOF '(' expr ')'
{ $$ = TREE_TYPE ($3); }
@@ -1232,7 +1314,7 @@ nested_function:
YYERROR1;
}
reinit_parse_for_function (); }
- xdecls
+ old_style_parm_decls
{ store_parm_decls (); }
/* This used to use compstmt_or_error.
That caused a bug with input `f(g) int g {}',
@@ -1255,7 +1337,7 @@ notype_nested_function:
YYERROR1;
}
reinit_parse_for_function (); }
- xdecls
+ old_style_parm_decls
{ store_parm_decls (); }
/* This used to use compstmt_or_error.
That caused a bug with input `f(g) int g {}',
@@ -1292,6 +1374,11 @@ after_type_declarator:
{ $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
| '*' type_quals after_type_declarator %prec UNARY
{ $$ = make_pointer_declarator ($2, $3); }
+ /* ??? Yuck. setattrs is a quick hack. We can't use
+ prefix_attributes because $1 only applies to this
+ declarator. We assume setspecs has already been done.
+ setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
+ attributes could be recognized here or in `attributes'). */
| attributes setattrs after_type_declarator
{ $$ = $3; }
| TYPENAME
@@ -1317,6 +1404,11 @@ parm_declarator:
{ $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
| '*' type_quals parm_declarator %prec UNARY
{ $$ = make_pointer_declarator ($2, $3); }
+ /* ??? Yuck. setattrs is a quick hack. We can't use
+ prefix_attributes because $1 only applies to this
+ declarator. We assume setspecs has already been done.
+ setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
+ attributes could be recognized here or in `attributes'). */
| attributes setattrs parm_declarator
{ $$ = $3; }
| TYPENAME
@@ -1339,47 +1431,73 @@ notype_declarator:
{ $$ = build_nt (ARRAY_REF, $1, $3); }
| notype_declarator '[' ']' %prec '.'
{ $$ = build_nt (ARRAY_REF, $1, NULL_TREE); }
+ /* ??? Yuck. setattrs is a quick hack. We can't use
+ prefix_attributes because $1 only applies to this
+ declarator. We assume setspecs has already been done.
+ setattrs also avoids 5 reduce/reduce conflicts (otherwise multiple
+ attributes could be recognized here or in `attributes'). */
| attributes setattrs notype_declarator
{ $$ = $3; }
| IDENTIFIER
;
+struct_head:
+ STRUCT
+ { $$ = NULL_TREE; }
+ | STRUCT attributes
+ { $$ = $2; }
+ ;
+
+union_head:
+ UNION
+ { $$ = NULL_TREE; }
+ | UNION attributes
+ { $$ = $2; }
+ ;
+
+enum_head:
+ ENUM
+ { $$ = NULL_TREE; }
+ | ENUM attributes
+ { $$ = $2; }
+ ;
+
structsp:
- STRUCT identifier '{'
+ struct_head identifier '{'
{ $$ = start_struct (RECORD_TYPE, $2);
/* Start scope of tag before parsing components. */
}
component_decl_list '}' maybe_attribute
- { $$ = finish_struct ($<ttype>4, $5, $7); }
- | STRUCT '{' component_decl_list '}' maybe_attribute
+ { $$ = finish_struct ($<ttype>4, $5, chainon ($1, $7)); }
+ | struct_head '{' component_decl_list '}' maybe_attribute
{ $$ = finish_struct (start_struct (RECORD_TYPE, NULL_TREE),
- $3, $5);
+ $3, chainon ($1, $5));
}
- | STRUCT identifier
+ | struct_head identifier
{ $$ = xref_tag (RECORD_TYPE, $2); }
- | UNION identifier '{'
+ | union_head identifier '{'
{ $$ = start_struct (UNION_TYPE, $2); }
component_decl_list '}' maybe_attribute
- { $$ = finish_struct ($<ttype>4, $5, $7); }
- | UNION '{' component_decl_list '}' maybe_attribute
+ { $$ = finish_struct ($<ttype>4, $5, chainon ($1, $7)); }
+ | union_head '{' component_decl_list '}' maybe_attribute
{ $$ = finish_struct (start_struct (UNION_TYPE, NULL_TREE),
- $3, $5);
+ $3, chainon ($1, $5));
}
- | UNION identifier
+ | union_head identifier
{ $$ = xref_tag (UNION_TYPE, $2); }
- | ENUM identifier '{'
+ | enum_head identifier '{'
{ $<itype>3 = suspend_momentary ();
$$ = start_enum ($2); }
enumlist maybecomma_warn '}' maybe_attribute
- { $$ = finish_enum ($<ttype>4, nreverse ($5), $8);
+ { $$= finish_enum ($<ttype>4, nreverse ($5), chainon ($1, $8));
resume_momentary ($<itype>3); }
- | ENUM '{'
+ | enum_head '{'
{ $<itype>2 = suspend_momentary ();
$$ = start_enum (NULL_TREE); }
enumlist maybecomma_warn '}' maybe_attribute
- { $$ = finish_enum ($<ttype>3, nreverse ($4), $7);
+ { $$= finish_enum ($<ttype>3, nreverse ($4), chainon ($1, $7));
resume_momentary ($<itype>2); }
- | ENUM identifier
+ | enum_head identifier
{ $$ = xref_tag (ENUMERAL_TYPE, $2); }
;
@@ -1461,6 +1579,9 @@ component_decl:
$$ = NULL_TREE; }
| error
{ $$ = NULL_TREE; }
+ | extension component_decl
+ { $$ = $2;
+ pedantic = $<itype>1; }
;
components:
@@ -1553,8 +1674,8 @@ absdcl1: /* a nonempty absolute declarator */
{ $$ = build_nt (ARRAY_REF, NULL_TREE, $2); }
| '[' ']' %prec '.'
{ $$ = build_nt (ARRAY_REF, NULL_TREE, NULL_TREE); }
- | attributes setattrs absdcl1
- { $$ = $3; }
+ /* ??? It appears we have to support attributes here, however
+ using prefix_attributes is wrong. */
;
/* at least one statement, the first of which parses without error. */
@@ -1632,9 +1753,11 @@ compstmt_or_error:
| error compstmt
;
-compstmt: '{' '}'
+compstmt_start: '{' { compstmt_count++; }
+
+compstmt: compstmt_start '}'
{ $$ = convert (void_type_node, integer_zero_node); }
- | '{' pushlevel maybe_label_decls decls xstmts '}'
+ | compstmt_start pushlevel maybe_label_decls decls xstmts '}'
{ emit_line_note (input_filename, lineno);
expand_end_bindings (getdecls (), 1, 0);
$$ = poplevel (1, 1, 0);
@@ -1642,7 +1765,7 @@ compstmt: '{' '}'
pop_momentary_nofree ();
else
pop_momentary (); }
- | '{' pushlevel maybe_label_decls error '}'
+ | compstmt_start pushlevel maybe_label_decls error '}'
{ emit_line_note (input_filename, lineno);
expand_end_bindings (getdecls (), kept_level_p (), 0);
$$ = poplevel (kept_level_p (), 0, 0);
@@ -1650,7 +1773,7 @@ compstmt: '{' '}'
pop_momentary_nofree ();
else
pop_momentary (); }
- | '{' pushlevel maybe_label_decls stmts '}'
+ | compstmt_start pushlevel maybe_label_decls stmts '}'
{ emit_line_note (input_filename, lineno);
expand_end_bindings (getdecls (), kept_level_p (), 0);
$$ = poplevel (kept_level_p (), 0, 0);
@@ -1663,8 +1786,8 @@ compstmt: '{' '}'
/* Value is number of statements counted as of the closeparen. */
simple_if:
if_prefix lineno_labeled_stmt
-/* Make sure expand_end_cond is run once
- for each call to expand_start_cond.
+/* Make sure c_expand_end_cond is run once
+ for each call to c_expand_start_cond.
Otherwise a crash is likely. */
| if_prefix error
;
@@ -1672,7 +1795,8 @@ simple_if:
if_prefix:
IF '(' expr ')'
{ emit_line_note ($<filename>-1, $<lineno>0);
- expand_start_cond (truthvalue_conversion ($3), 0);
+ c_expand_start_cond (truthvalue_conversion ($3), 0,
+ compstmt_count);
$<itype>$ = stmt_count;
if_stmt_file = $<filename>-1;
if_stmt_line = $<lineno>0;
@@ -1685,6 +1809,7 @@ if_prefix:
do_stmt_start:
DO
{ stmt_count++;
+ compstmt_count++;
emit_line_note ($<filename>-1, $<lineno>0);
/* See comment in `while' alternative, above. */
emit_nop ();
@@ -1747,15 +1872,15 @@ stmt:
iterator_expand ($1);
clear_momentary (); }
| simple_if ELSE
- { expand_start_else ();
+ { c_expand_start_else ();
$<itype>1 = stmt_count;
position_after_white_space (); }
lineno_labeled_stmt
- { expand_end_cond ();
+ { c_expand_end_cond ();
if (extra_warnings && stmt_count == $<itype>1)
warning ("empty body in an else-statement"); }
| simple_if %prec IF
- { expand_end_cond ();
+ { c_expand_end_cond ();
/* This warning is here instead of in simple_if, because we
do not want a warning if an empty if is followed by an
else statement. Increment stmt_count so we don't
@@ -1763,11 +1888,11 @@ stmt:
if (extra_warnings && stmt_count++ == $<itype>1)
warning_with_file_and_line (if_stmt_file, if_stmt_line,
"empty body in an if-statement"); }
-/* Make sure expand_end_cond is run once
- for each call to expand_start_cond.
+/* Make sure c_expand_end_cond is run once
+ for each call to c_expand_start_cond.
Otherwise a crash is likely. */
| simple_if ELSE error
- { expand_end_cond (); }
+ { c_expand_end_cond (); }
| WHILE
{ stmt_count++;
emit_line_note ($<filename>-1, $<lineno>0);
@@ -1919,7 +2044,9 @@ stmt:
}
}
| GOTO '*' expr ';'
- { stmt_count++;
+ { if (pedantic)
+ pedwarn ("ANSI C forbids `goto *expr;'");
+ stmt_count++;
emit_line_note ($<filename>-1, $<lineno>0);
expand_computed_goto (convert (ptr_type_node, $3)); }
| ';'
@@ -1997,8 +2124,14 @@ label: CASE expr_no_commas ':'
if (value != error_mark_node)
{
tree duplicate;
- int success = pushcase (value, convert_and_check,
- label, &duplicate);
+ int success;
+
+ if (pedantic && ! INTEGRAL_TYPE_P (TREE_TYPE (value)))
+ pedwarn ("label must have integral type in ANSI C");
+
+ success = pushcase (value, convert_and_check,
+ label, &duplicate);
+
if (success == 1)
error ("case label not within a switch statement");
else if (success == 2)
@@ -2018,6 +2151,8 @@ label: CASE expr_no_commas ':'
register tree label
= build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ if (pedantic)
+ pedwarn ("ANSI C forbids case ranges");
stmt_count++;
if (value1 != error_mark_node && value2 != error_mark_node)
@@ -2250,6 +2385,12 @@ identifiers_or_typenames:
| identifiers_or_typenames ',' identifier
{ $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
;
+
+extension:
+ EXTENSION
+ { $<itype>$ = pedantic;
+ pedantic = 0; }
+ ;
ifobjc
/* Objective-C productions. */
@@ -2436,7 +2577,11 @@ protocolrefs:
{
$$ = NULL_TREE;
}
- | ARITHCOMPARE identifier_list ARITHCOMPARE
+ | non_empty_protocolrefs
+ ;
+
+non_empty_protocolrefs:
+ ARITHCOMPARE identifier_list ARITHCOMPARE
{
if ($1 == LT_EXPR && $3 == GT_EXPR)
$$ = $2;
@@ -2602,20 +2747,28 @@ semi_or_error:
methodproto:
'+'
{
+ /* Remember protocol qualifiers in prototypes. */
+ remember_protocol_qualifiers ();
objc_inherit_code = CLASS_METHOD_DECL;
}
methoddecl
{
+ /* Forget protocol qualifiers here. */
+ forget_protocol_qualifiers ();
add_class_method (objc_interface_context, $3);
}
semi_or_error
| '-'
{
+ /* Remember protocol qualifiers in prototypes. */
+ remember_protocol_qualifiers ();
objc_inherit_code = INSTANCE_METHOD_DECL;
}
methoddecl
{
+ /* Forget protocol qualifiers here. */
+ forget_protocol_qualifiers ();
add_instance_method (objc_interface_context, $3);
}
semi_or_error
diff --git a/contrib/gcc/c-pragma.c b/contrib/gcc/c-pragma.c
index 480cfca..3d01925 100644
--- a/contrib/gcc/c-pragma.c
+++ b/contrib/gcc/c-pragma.c
@@ -1,5 +1,5 @@
/* Handle #pragma, system V.4 style. Supports #pragma weak and #pragma pack.
- Copyright (C) 1992 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -18,18 +18,22 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
+#include "rtl.h"
#include "tree.h"
+#include "except.h"
#include "function.h"
#include "defaults.h"
#include "c-pragma.h"
+#include "flags.h"
+#include "toplev.h"
#ifdef HANDLE_SYSV_PRAGMA
/* When structure field packing is in effect, this variable is the
number of bits to use as the maximum alignment. When packing is not
- in effect, this is zero. */
+ in effect, this is zero. */
extern int maximum_field_alignment;
@@ -64,7 +68,7 @@ handle_pragma_token (string, token)
if (HANDLE_PRAGMA_WEAK)
handle_pragma_weak (state, name, value);
-#endif /* HANDLE_PRAMA_WEAK */
+#endif /* HANDLE_PRAGMA_WEAK */
}
type = state = ps_start;
@@ -81,7 +85,16 @@ handle_pragma_token (string, token)
else if (strcmp (IDENTIFIER_POINTER (token), "weak") == 0)
type = state = ps_weak;
else
- type = state = ps_done;
+ {
+ type = state = ps_done;
+
+ /* Issue a warning message if we have been asked to do so.
+ Ignoring unknown pragmas in system header file unless
+ an explcit -Wunknown-pragmas has been given. */
+ if (warn_unknown_pragmas > 1
+ || (warn_unknown_pragmas && ! in_system_header))
+ warning ("ignoring pragma: %s", string);
+ }
}
else
type = state = ps_done;
diff --git a/contrib/gcc/c-tree.h b/contrib/gcc/c-tree.h
index 02f57c3..7605cfe 100644
--- a/contrib/gcc/c-tree.h
+++ b/contrib/gcc/c-tree.h
@@ -1,5 +1,5 @@
/* Definitions for C parsing and type checking.
- Copyright (C) 1987, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -40,27 +40,27 @@ struct lang_identifier
/* This represents the value which the identifier has in the
file-scope namespace. */
#define IDENTIFIER_GLOBAL_VALUE(NODE) \
- (((struct lang_identifier *)(NODE))->global_value)
+ (((struct lang_identifier *) (NODE))->global_value)
/* This represents the value which the identifier has in the current
scope. */
#define IDENTIFIER_LOCAL_VALUE(NODE) \
- (((struct lang_identifier *)(NODE))->local_value)
+ (((struct lang_identifier *) (NODE))->local_value)
/* This represents the value which the identifier has as a label in
the current label scope. */
#define IDENTIFIER_LABEL_VALUE(NODE) \
- (((struct lang_identifier *)(NODE))->label_value)
+ (((struct lang_identifier *) (NODE))->label_value)
/* This records the extern decl of this identifier, if it has had one
at any point in this compilation. */
#define IDENTIFIER_LIMBO_VALUE(NODE) \
- (((struct lang_identifier *)(NODE))->limbo_value)
+ (((struct lang_identifier *) (NODE))->limbo_value)
/* This records the implicit function decl of this identifier, if it
has had one at any point in this compilation. */
#define IDENTIFIER_IMPLICIT_DECL(NODE) \
- (((struct lang_identifier *)(NODE))->implicit_decl)
+ (((struct lang_identifier *) (NODE))->implicit_decl)
/* This is the last function in which we printed an "undefined variable"
message for this identifier. Value is a FUNCTION_DECL or null. */
#define IDENTIFIER_ERROR_LOCUS(NODE) \
- (((struct lang_identifier *)(NODE))->error_locus)
+ (((struct lang_identifier *) (NODE))->error_locus)
/* In identifiers, C uses the following fields in a special way:
TREE_PUBLIC to record that there was a previous local extern decl.
@@ -109,7 +109,7 @@ struct lang_type
/* Store a value in that field. */
#define C_SET_EXP_ORIGINAL_CODE(exp, code) \
- (TREE_COMPLEXITY (exp) = (int)(code))
+ (TREE_COMPLEXITY (exp) = (int) (code))
/* Record whether a typedef for type `int' was actually `signed int'. */
#define C_TYPEDEF_EXPLICITLY_SIGNED(exp) DECL_LANG_FLAG_1 ((exp))
@@ -124,6 +124,9 @@ struct lang_type
without prototypes. */
#define TYPE_ACTUAL_ARG_TYPES(NODE) TYPE_NONCOPIED_PARTS (NODE)
+/* In a FIELD_DECL, nonzero if the decl was originally a bitfield. */
+#define DECL_C_BIT_FIELD(NODE) DECL_LANG_FLAG_4 (NODE)
+
/* Nonzero if the type T promotes to itself.
ANSI C states explicitly the list of types that promote;
in particular, short promotes to int even if they have the same width. */
@@ -146,6 +149,7 @@ struct lang_type
extern tree lookup_interface PROTO((tree));
extern tree is_class_name PROTO((tree));
extern void maybe_objc_check_decl PROTO((tree));
+extern void finish_file PROTO((void));
extern int maybe_objc_comptypes PROTO((tree, tree, int));
extern tree maybe_building_objc_message_expr PROTO((void));
extern tree maybe_objc_method_name PROTO((tree));
@@ -159,12 +163,15 @@ extern void gen_aux_info_record PROTO((tree, int, int, int));
extern void declare_function_name PROTO((void));
extern void decl_attributes PROTO((tree, tree, tree));
extern void init_function_format_info PROTO((void));
-extern void record_function_format PROTO((tree, tree, int, int, int));
extern void check_function_format PROTO((tree, tree, tree));
+extern int c_get_alias_set PROTO((tree));
/* Print an error message for invalid operands to arith operation CODE.
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error PROTO((enum tree_code));
extern void c_expand_expr_stmt PROTO((tree));
+extern void c_expand_start_cond PROTO((tree, int, int));
+extern void c_expand_start_else PROTO((void));
+extern void c_expand_end_cond PROTO((void));
/* Validate the expression after `case' and apply default promotions. */
extern tree check_case_value PROTO((tree));
/* Concatenate a list of STRING_CST nodes into one STRING_CST. */
@@ -174,7 +181,14 @@ extern tree convert_and_check PROTO((tree, tree));
extern void overflow_warning PROTO((tree));
extern void unsigned_conversion_warning PROTO((tree, tree));
/* Read the rest of the current #-directive line. */
-extern char *get_directive_line STDIO_PROTO((FILE *));
+#if USE_CPPLIB
+extern char *get_directive_line PROTO((void));
+#define GET_DIRECTIVE_LINE() get_directive_line ()
+#else
+extern char *get_directive_line PROTO((FILE *));
+#define GET_DIRECTIVE_LINE() get_directive_line (finput)
+#endif
+
/* Subroutine of build_binary_op, used for comparison operations.
See if the operands have both been converted from subword integer types
and, if so, perhaps change them both back to their original type. */
@@ -199,6 +213,7 @@ extern tree double_ftype_double;
extern tree double_ftype_double_double;
extern tree double_type_node;
extern tree float_type_node;
+extern tree intTI_type_node;
extern tree intDI_type_node;
extern tree intHI_type_node;
extern tree intQI_type_node;
@@ -228,6 +243,7 @@ extern tree signed_wchar_type_node;
extern tree string_ftype_ptr_ptr;
extern tree string_type_node;
extern tree unsigned_char_type_node;
+extern tree unsigned_intTI_type_node;
extern tree unsigned_intDI_type_node;
extern tree unsigned_intHI_type_node;
extern tree unsigned_intQI_type_node;
@@ -248,7 +264,7 @@ extern tree build_enumerator PROTO((tree, tree));
extern tree builtin_function PROTO((char *, tree, enum built_in_function function_, char *));
/* Add qualifiers to a type, in the fashion for C. */
extern tree c_build_type_variant PROTO((tree, int, int));
-extern int c_decode_option PROTO((char *));
+extern int c_decode_option PROTO((int, char **));
extern void c_mark_varargs PROTO((void));
extern tree check_identifier PROTO((tree, tree));
extern void clear_parm_order PROTO((void));
@@ -285,12 +301,9 @@ extern void pending_xref_error PROTO((void));
extern void pop_c_function_context PROTO((void));
extern void pop_label_level PROTO((void));
extern tree poplevel PROTO((int, int, int));
-extern void print_lang_decl STDIO_PROTO((FILE *, tree,
- int));
-extern void print_lang_identifier STDIO_PROTO((FILE *, tree,
- int));
-extern void print_lang_type STDIO_PROTO((FILE *, tree,
- int));
+extern void print_lang_decl PROTO((FILE *, tree, int));
+extern void print_lang_identifier PROTO((FILE *, tree, int));
+extern void print_lang_type PROTO((FILE *, tree, int));
extern void push_c_function_context PROTO((void));
extern void push_label_level PROTO((void));
extern void push_parm_decl PROTO((tree));
@@ -365,6 +378,7 @@ extern void c_expand_return PROTO((tree));
extern tree c_expand_start_case PROTO((tree));
/* in c-iterate.c */
+extern void init_iterators PROTO((void));
extern void iterator_expand PROTO((tree));
extern void iterator_for_loop_start PROTO((tree));
extern void iterator_for_loop_end PROTO((tree));
@@ -382,6 +396,11 @@ extern int current_function_returns_value;
extern int current_function_returns_null;
+/* Nonzero means the expression being parsed will never be evaluated.
+ This is a count, since unevaluated expressions can nest. */
+
+extern int skip_evaluation;
+
/* Nonzero means `$' can be in an identifier. */
extern int dollars_in_ident;
@@ -395,6 +414,10 @@ extern int flag_cond_mismatch;
extern int flag_no_asm;
+/* Nonzero means environment is hosted (i.e., not freestanding) */
+
+extern int flag_hosted;
+
/* Nonzero means ignore `#ident' directives. */
extern int flag_no_ident;
@@ -458,6 +481,10 @@ extern int warn_char_subscripts;
extern int warn_conversion;
+/* Warn if main is suspicious. */
+
+extern int warn_main;
+
/* Nonzero means do some things the same way PCC does. */
extern int flag_traditional;
@@ -474,10 +501,13 @@ extern int warn_parentheses;
extern int warn_missing_braces;
-/* Nonzero means this is a function to call to perform comptypes
- on two record types. */
+/* Warn about comparison of signed and unsigned values. */
-extern int (*comptypes_record_hook) ();
+extern int warn_sign_compare;
+
+/* Warn about multicharacter constants. */
+
+extern int warn_multichar;
/* Nonzero means we are reading code that came from a system header file. */
@@ -487,4 +517,7 @@ extern int system_header_p;
extern int doing_objc_thang;
+/* In c-decl.c */
+extern void finish_incomplete_decl PROTO((tree));
+
#endif /* not _C_TREE_H */
diff --git a/contrib/gcc/c-typeck.c b/contrib/gcc/c-typeck.c
index bae52e3..4ccc1a3 100644
--- a/contrib/gcc/c-typeck.c
+++ b/contrib/gcc/c-typeck.c
@@ -1,5 +1,5 @@
/* Build expressions with type checking for C compiler.
- Copyright (C) 1987, 88, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -29,20 +29,20 @@ Boston, MA 02111-1307, USA. */
like a strange sort of assignment). */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "tree.h"
#include "c-tree.h"
#include "flags.h"
#include "output.h"
+#include "rtl.h"
+#include "expr.h"
+#include "toplev.h"
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
static int missing_braces_mentioned;
-extern char *index ();
-extern char *rindex ();
-
-static tree quality_type PROTO((tree, tree));
+static tree qualify_type PROTO((tree, tree));
static int comp_target_types PROTO((tree, tree));
static int function_types_compatible_p PROTO((tree, tree));
static int type_lists_compatible_p PROTO((tree, tree));
@@ -71,6 +71,8 @@ static tree digest_init PROTO((tree, tree, int, int));
static void check_init_type_bitfields PROTO((tree));
static void output_init_element PROTO((tree, tree, tree, int));
static void output_pending_init_elements PROTO((int));
+static void add_pending_init PROTO((tree, tree));
+static int pending_init_member PROTO((tree));
/* Do `exp = require_complete_type (exp);' to make sure exp
does not have an incomplete type. (That includes void types.) */
@@ -192,40 +194,8 @@ common_type (t1, t2)
if (t2 == error_mark_node)
return t1;
- /* Merge the attributes */
-
- { register tree a1, a2;
- a1 = TYPE_ATTRIBUTES (t1);
- a2 = TYPE_ATTRIBUTES (t2);
-
- /* Either one unset? Take the set one. */
-
- if (!(attributes = a1))
- attributes = a2;
-
- /* One that completely contains the other? Take it. */
-
- else if (a2 && !attribute_list_contained (a1, a2))
- if (attribute_list_contained (a2, a1))
- attributes = a2;
- else
- {
- /* Pick the longest list, and hang on the other list. */
- /* ??? For the moment we punt on the issue of attrs with args. */
-
- if (list_length (a1) < list_length (a2))
- attributes = a2, a2 = a1;
-
- for (; a2; a2 = TREE_CHAIN (a2))
- if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
- attributes) == NULL_TREE)
- {
- a1 = copy_node (a2);
- TREE_CHAIN (a1) = attributes;
- attributes = a1;
- }
- }
- }
+ /* Merge the attributes. */
+ attributes = merge_machine_type_attributes (t1, t2);
/* Treat an enum type as the unsigned integer type of the same width. */
@@ -293,6 +263,12 @@ common_type (t1, t2)
return build_type_attribute_variant (t1, attributes);
}
+ /* Likewise, prefer long double to double even if same size. */
+ if (TYPE_MAIN_VARIANT (t1) == long_double_type_node
+ || TYPE_MAIN_VARIANT (t2) == long_double_type_node)
+ return build_type_attribute_variant (long_double_type_node,
+ attributes);
+
/* Otherwise prefer the unsigned one. */
if (TREE_UNSIGNED (t1))
@@ -427,7 +403,7 @@ common_type (t1, t2)
}
t1 = build_function_type (valtype, newargs);
- /* ... falls through ... */
+ /* ... falls through ... */
}
default:
@@ -450,7 +426,8 @@ comptypes (type1, type2)
/* Suppress errors caused by previously reported errors. */
- if (t1 == t2 || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK)
+ if (t1 == t2 || !t1 || !t2
+ || TREE_CODE (t1) == ERROR_MARK || TREE_CODE (t2) == ERROR_MARK)
return 1;
/* Treat an enum type as the integer type of the same width and
@@ -477,7 +454,7 @@ comptypes (type1, type2)
/* Allow for two different type nodes which have essentially the same
definition. Note that we already checked for equality of the type
- type qualifiers (just above). */
+ qualifiers (just above). */
if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return 1;
@@ -539,6 +516,9 @@ comptypes (type1, type2)
if (maybe_objc_comptypes (t1, t2, 0) == 1)
val = 1;
break;
+
+ default:
+ break;
}
return attrval == 2 && val == 1 ? 2 : val;
}
@@ -553,7 +533,7 @@ comp_target_types (ttl, ttr)
int val;
/* Give maybe_objc_comptypes a crack at letting these types through. */
- if (val = maybe_objc_comptypes (ttl, ttr, 1) >= 0)
+ if ((val = maybe_objc_comptypes (ttl, ttr, 1)) >= 0)
return val;
val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
@@ -767,7 +747,8 @@ unsigned_type (type)
return unsigned_intHI_type_node;
if (type1 == intQI_type_node)
return unsigned_intQI_type_node;
- return type;
+
+ return signed_or_unsigned_type (1, type);
}
/* Return a signed type the same as TYPE in other respects. */
@@ -795,7 +776,8 @@ signed_type (type)
return intHI_type_node;
if (type1 == unsigned_intQI_type_node)
return intQI_type_node;
- return type;
+
+ return signed_or_unsigned_type (0, type);
}
/* Return a type the same as TYPE except unsigned or
@@ -806,7 +788,8 @@ signed_or_unsigned_type (unsignedp, type)
int unsignedp;
tree type;
{
- if (! INTEGRAL_TYPE_P (type))
+ if ((! INTEGRAL_TYPE_P (type) && ! POINTER_TYPE_P (type))
+ || TREE_UNSIGNED (type) == unsignedp)
return type;
if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
@@ -854,6 +837,7 @@ c_sizeof (type)
/* Convert in case a char is more than one unit. */
t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (TYPE_PRECISION (char_type_node)));
+ t = convert (sizetype, t);
/* size_binop does not put the constant in range, so do it now. */
if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0))
TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) = 1;
@@ -877,6 +861,7 @@ c_sizeof_nowarn (type)
/* Convert in case a char is more than one unit. */
t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (TYPE_PRECISION (char_type_node)));
+ t = convert (sizetype, t);
force_fit_type (t, 0);
return t;
}
@@ -905,6 +890,7 @@ c_size_in_bytes (type)
/* Convert in case a char is more than one unit. */
t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (BITS_PER_UNIT));
+ t = convert (sizetype, t);
force_fit_type (t, 0);
return t;
}
@@ -940,7 +926,7 @@ c_alignof_expr (expr)
return size_int (DECL_ALIGN (expr) / BITS_PER_UNIT);
if (TREE_CODE (expr) == COMPONENT_REF
- && DECL_BIT_FIELD (TREE_OPERAND (expr, 1)))
+ && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
{
error ("`__alignof' applied to a bit-field");
return size_int (1);
@@ -970,16 +956,16 @@ c_alignof_expr (expr)
else
return c_alignof (TREE_TYPE (expr));
}
+
/* Return either DECL or its known constant value (if it has one). */
static tree
decl_constant_value (decl)
tree decl;
{
- if (! TREE_PUBLIC (decl)
- /* Don't change a variable array bound or initial value to a constant
+ if (/* Don't change a variable array bound or initial value to a constant
in a place where a variable is invalid. */
- && current_function_decl != 0
+ current_function_decl != 0
&& ! pedantic
&& ! TREE_THIS_VOLATILE (decl)
&& TREE_READONLY (decl) && ! ITERATOR_P (decl)
@@ -1037,11 +1023,30 @@ default_conversion (exp)
type = type_for_size (MAX (TYPE_PRECISION (type),
TYPE_PRECISION (integer_type_node)),
((flag_traditional
- || TYPE_PRECISION (type) >= TYPE_PRECISION (integer_type_node))
+ || (TYPE_PRECISION (type)
+ >= TYPE_PRECISION (integer_type_node)))
&& TREE_UNSIGNED (type)));
return convert (type, exp);
}
+ if (TREE_CODE (exp) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1)))
+ {
+ tree width = DECL_SIZE (TREE_OPERAND (exp, 1));
+ HOST_WIDE_INT low = TREE_INT_CST_LOW (width);
+
+ /* If it's thinner than an int, promote it like a
+ C_PROMOTING_INTEGER_TYPE_P, otherwise leave it alone. */
+
+ if (low < TYPE_PRECISION (integer_type_node))
+ {
+ if (flag_traditional && TREE_UNSIGNED (type))
+ return convert (unsigned_type_node, exp);
+ else
+ return convert (integer_type_node, exp);
+ }
+ }
+
if (C_PROMOTING_INTEGER_TYPE_P (type))
{
/* Traditionally, unsignedness is preserved in default promotions.
@@ -1096,7 +1101,7 @@ default_conversion (exp)
TREE_OPERAND (exp, 0), op1);
}
- if (!lvalue_p (exp)
+ if (! lvalue_p (exp)
&& ! (TREE_CODE (exp) == CONSTRUCTOR && TREE_STATIC (exp)))
{
error ("invalid use of non-lvalue array");
@@ -1162,10 +1167,13 @@ lookup_field (type, component, indirect)
/* Step through all anon unions in linear fashion. */
while (DECL_NAME (field_array[bot]) == NULL_TREE)
{
- tree anon, junk;
+ tree anon = 0, junk;
field = field_array[bot++];
- anon = lookup_field (TREE_TYPE (field), component, &junk);
+ if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ anon = lookup_field (TREE_TYPE (field), component, &junk);
+
if (anon != NULL_TREE)
{
*indirect = field;
@@ -1201,7 +1209,12 @@ lookup_field (type, component, indirect)
if (DECL_NAME (field) == NULL_TREE)
{
tree junk;
- tree anon = lookup_field (TREE_TYPE (field), component, &junk);
+ tree anon = 0;
+
+ if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ anon = lookup_field (TREE_TYPE (field), component, &junk);
+
if (anon != NULL_TREE)
{
*indirect = field;
@@ -1245,6 +1258,9 @@ build_component_ref (datum, component)
(TREE_OPERAND (datum, 0),
build_component_ref (TREE_OPERAND (datum, 1), component),
build_component_ref (TREE_OPERAND (datum, 2), component));
+
+ default:
+ break;
}
/* See if there is a field or component with name COMPONENT. */
@@ -1331,7 +1347,7 @@ build_indirect_ref (ptr, errorstring)
error ("dereferencing pointer to incomplete type");
return error_mark_node;
}
- if (TREE_CODE (t) == VOID_TYPE)
+ if (TREE_CODE (t) == VOID_TYPE && skip_evaluation == 0)
warning ("dereferencing `void *' pointer");
/* We *must* set TREE_READONLY when dereferencing a pointer to const,
@@ -1465,6 +1481,14 @@ build_array_ref (array, index)
tree ar = default_conversion (array);
tree ind = default_conversion (index);
+ /* Do the same warning check as above, but only on the part that's
+ syntactically the index and only if it is also semantically
+ the index. */
+ if (warn_char_subscripts
+ && TREE_CODE (TREE_TYPE (index)) == INTEGER_TYPE
+ && TYPE_MAIN_VARIANT (TREE_TYPE (index)) == char_type_node)
+ warning ("subscript has type `char'");
+
/* Put the integer in IND to simplify error checking. */
if (TREE_CODE (TREE_TYPE (ar)) == INTEGER_TYPE)
{
@@ -1476,7 +1500,8 @@ build_array_ref (array, index)
if (ar == error_mark_node)
return ar;
- if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE)
+ if (TREE_CODE (TREE_TYPE (ar)) != POINTER_TYPE
+ || TREE_CODE (TREE_TYPE (TREE_TYPE (ar))) == FUNCTION_TYPE)
{
error ("subscripted value is neither array nor pointer");
return error_mark_node;
@@ -1567,6 +1592,8 @@ build_function_call (function, params)
if (coerced_params == 0)
return integer_zero_node;
return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
+ default:
+ break;
}
{
@@ -1734,7 +1761,7 @@ convert_arguments (typelist, values, name, fundecl)
}
parmval = convert_for_assignment (type, val,
- (char *)0, /* arg passing */
+ (char *) 0, /* arg passing */
fundecl, name, parmnum + 1);
#ifdef PROMOTE_PROTOTYPES
@@ -2109,7 +2136,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
case RSHIFT_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
- if (TREE_CODE (op1) == INTEGER_CST)
+ if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
if (tree_int_cst_sgn (op1) < 0)
warning ("right shift count is negative");
@@ -2141,7 +2168,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
case LSHIFT_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
- if (TREE_CODE (op1) == INTEGER_CST)
+ if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
if (tree_int_cst_sgn (op1) < 0)
warning ("left shift count is negative");
@@ -2169,7 +2196,7 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
case LROTATE_EXPR:
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
- if (TREE_CODE (op1) == INTEGER_CST)
+ if (TREE_CODE (op1) == INTEGER_CST && skip_evaluation == 0)
{
if (tree_int_cst_sgn (op1) < 0)
warning ("shift count is negative");
@@ -2327,6 +2354,9 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
pedwarn ("comparison between pointer and integer");
}
break;
+
+ default:
+ break;
}
if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
@@ -2471,7 +2501,8 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
converted = 1;
resultcode = xresultcode;
- if (extra_warnings)
+ if ((warn_sign_compare < 0 ? extra_warnings : warn_sign_compare != 0)
+ && skip_evaluation == 0)
{
int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
@@ -2513,9 +2544,9 @@ build_binary_op (code, orig_op0, orig_op1, convert_p)
not use the most significant bit of result_type. */
else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR)
&& ((op0_signed && TREE_CODE (xop1) == INTEGER_CST
- && int_fits_type_p (xop1, signed_type (result_type))
+ && int_fits_type_p (xop1, signed_type (result_type)))
|| (op1_signed && TREE_CODE (xop0) == INTEGER_CST
- && int_fits_type_p (xop0, signed_type (result_type))))))
+ && int_fits_type_p (xop0, signed_type (result_type)))))
/* OK */;
else
warning ("comparison between signed and unsigned");
@@ -2677,11 +2708,13 @@ pointer_int_sum (resultcode, ptrop, intop)
intop = convert (int_type, TREE_OPERAND (intop, 0));
}
- /* Convert the integer argument to a type the same size as a pointer
+ /* Convert the integer argument to a type the same size as sizetype
so the multiply won't overflow spuriously. */
- if (TYPE_PRECISION (TREE_TYPE (intop)) != POINTER_SIZE)
- intop = convert (type_for_size (POINTER_SIZE, 0), intop);
+ if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype)
+ || TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype))
+ intop = convert (type_for_size (TYPE_PRECISION (sizetype),
+ TREE_UNSIGNED (sizetype)), intop);
/* Replace the integer argument with a suitable product by the object size.
Do this multiplication as signed, then convert to the appropriate
@@ -2722,10 +2755,12 @@ pointer_diff (op0, op1)
}
/* First do the subtraction as integers;
- then drop through to build the divide operator. */
+ then drop through to build the divide operator.
+ Do not do default conversions on the minus operator
+ in case restype is a short type. */
op0 = build_binary_op (MINUS_EXPR, convert (restype, op0),
- convert (restype, op1), 1);
+ convert (restype, op1), 0);
/* This generates an error if op1 is pointer to incomplete type. */
if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0)
error ("arithmetic on pointer to an incomplete type");
@@ -3070,7 +3105,7 @@ build_unary_op (code, xarg, noconvert)
addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 0), 0);
- if (DECL_BIT_FIELD (field))
+ if (DECL_C_BIT_FIELD (field))
{
error ("attempt to take address of bit-field structure member `%s'",
IDENTIFIER_POINTER (DECL_NAME (field)));
@@ -3101,6 +3136,9 @@ build_unary_op (code, xarg, noconvert)
TREE_CONSTANT (addr) = 1;
return addr;
}
+
+ default:
+ break;
}
if (!errstring)
@@ -3169,12 +3207,16 @@ lvalue_p (ref)
case PARM_DECL:
case RESULT_DECL:
case ERROR_MARK:
- if (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
- && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE)
- return 1;
- break;
+ return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
+ && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE);
+
+ case BIND_EXPR:
+ case RTL_EXPR:
+ return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE;
+
+ default:
+ return 0;
}
- return 0;
}
/* Return nonzero if REF is an lvalue valid for this language;
@@ -3206,7 +3248,12 @@ unary_complex_lvalue (code, arg)
if (TREE_CODE (arg) == COMPOUND_EXPR)
{
tree real_result = build_unary_op (code, TREE_OPERAND (arg, 1), 0);
- pedantic_lvalue_warning (COMPOUND_EXPR);
+
+ /* If this returns a function type, it isn't really being used as
+ an lvalue, so don't issue a warning about it. */
+ if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE)
+ pedantic_lvalue_warning (COMPOUND_EXPR);
+
return build (COMPOUND_EXPR, TREE_TYPE (real_result),
TREE_OPERAND (arg, 0), real_result);
}
@@ -3215,6 +3262,9 @@ unary_complex_lvalue (code, arg)
if (TREE_CODE (arg) == COND_EXPR)
{
pedantic_lvalue_warning (COND_EXPR);
+ if (TREE_CODE (TREE_TYPE (arg)) != FUNCTION_TYPE)
+ pedantic_lvalue_warning (COMPOUND_EXPR);
+
return (build_conditional_expr
(TREE_OPERAND (arg, 0),
build_unary_op (code, TREE_OPERAND (arg, 1), 0),
@@ -3287,8 +3337,17 @@ mark_addressable (exp)
while (1)
switch (TREE_CODE (x))
{
- case ADDR_EXPR:
case COMPONENT_REF:
+ if (DECL_C_BIT_FIELD (TREE_OPERAND (x, 1)))
+ {
+ error ("cannot take address of bitfield `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (x, 1))));
+ return 0;
+ }
+
+ /* ... fall through ... */
+
+ case ADDR_EXPR:
case ARRAY_REF:
case REALPART_EXPR:
case IMAGPART_EXPR:
@@ -3366,15 +3425,6 @@ build_conditional_expr (ifexp, op1, op2)
register tree result_type = NULL;
tree orig_op1 = op1, orig_op2 = op2;
- /* If second operand is omitted, it is the same as the first one;
- make sure it is calculated only once. */
- if (op1 == 0)
- {
- if (pedantic)
- pedwarn ("ANSI C forbids omitting the middle term of a ?: expression");
- ifexp = op1 = save_expr (ifexp);
- }
-
ifexp = truthvalue_conversion (default_conversion (ifexp));
#if 0 /* Produces wrong result if within sizeof. */
@@ -3721,11 +3771,18 @@ build_c_cast (type, expr)
&& TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE)
{
- if (TYPE_VOLATILE (TREE_TYPE (otype))
- && ! TYPE_VOLATILE (TREE_TYPE (type)))
+ /* Go to the innermost object being pointed to. */
+ tree in_type = type;
+ tree in_otype = otype;
+
+ while (TREE_CODE (in_type) == POINTER_TYPE)
+ in_type = TREE_TYPE (in_type);
+ while (TREE_CODE (in_otype) == POINTER_TYPE)
+ in_otype = TREE_TYPE (in_otype);
+
+ if (TYPE_VOLATILE (in_otype) && ! TYPE_VOLATILE (in_type))
pedwarn ("cast discards `volatile' from pointer target type");
- if (TYPE_READONLY (TREE_TYPE (otype))
- && ! TYPE_READONLY (TREE_TYPE (type)))
+ if (TYPE_READONLY (in_otype) && ! TYPE_READONLY (in_type))
pedwarn ("cast discards `const' from pointer target type");
}
@@ -3735,6 +3792,11 @@ build_c_cast (type, expr)
&& TREE_CODE (otype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (otype)) != VOID_TYPE
&& TREE_CODE (TREE_TYPE (otype)) != FUNCTION_TYPE
+ /* Don't warn about opaque types, where the actual alignment
+ restriction is unknown. */
+ && !((TREE_CODE (TREE_TYPE (otype)) == UNION_TYPE
+ || TREE_CODE (TREE_TYPE (otype)) == RECORD_TYPE)
+ && TYPE_MODE (TREE_TYPE (otype)) == VOIDmode)
&& TYPE_ALIGN (TREE_TYPE (type)) > TYPE_ALIGN (TREE_TYPE (otype)))
warning ("cast increases required alignment of target type");
@@ -3851,6 +3913,8 @@ build_modify_expr (lhs, modifycode, rhs)
/* But cast it to void to avoid an "unused" error. */
convert (void_type_node, rhs), cond);
}
+ default:
+ break;
}
/* If a binary op has been requested, combine the old LHS value with the RHS
@@ -3892,6 +3956,9 @@ build_modify_expr (lhs, modifycode, rhs)
pedantic_lvalue_warning (CONVERT_EXPR);
return convert (TREE_TYPE (lhs), result);
}
+
+ default:
+ break;
}
/* Now we have handled acceptable kinds of LHS that are not truly lvalues.
@@ -4014,26 +4081,27 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
|| coder == COMPLEX_TYPE))
return convert_and_check (type, rhs);
- /* Conversion to a union from its member types. */
- else if (codel == UNION_TYPE)
+ /* Conversion to a transparent union from its member types.
+ This applies only to function arguments. */
+ else if (codel == UNION_TYPE && TYPE_TRANSPARENT_UNION (type) && ! errtype)
{
tree memb_types;
+ tree marginal_memb_type = 0;
for (memb_types = TYPE_FIELDS (type); memb_types;
memb_types = TREE_CHAIN (memb_types))
{
- if (comptypes (TREE_TYPE (memb_types), TREE_TYPE (rhs)))
- {
- if (pedantic
- && !(fundecl != 0 && DECL_IN_SYSTEM_HEADER (fundecl)))
- pedwarn ("ANSI C prohibits argument conversion to union type");
- return build1 (NOP_EXPR, type, rhs);
- }
+ tree memb_type = TREE_TYPE (memb_types);
+
+ if (comptypes (TYPE_MAIN_VARIANT (memb_type),
+ TYPE_MAIN_VARIANT (rhstype)))
+ break;
+
+ if (TREE_CODE (memb_type) != POINTER_TYPE)
+ continue;
- else if (coder == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE)
+ if (coder == POINTER_TYPE)
{
- tree memb_type = TREE_TYPE (memb_types);
register tree ttl = TREE_TYPE (memb_type);
register tree ttr = TREE_TYPE (rhstype);
@@ -4045,50 +4113,76 @@ convert_for_assignment (type, rhs, errtype, fundecl, funname, parmnum)
|| TYPE_MAIN_VARIANT (ttr) == void_type_node
|| comp_target_types (memb_type, rhstype))
{
- /* Const and volatile mean something different for function
- types, so the usual warnings are not appropriate. */
- if (TREE_CODE (ttr) != FUNCTION_TYPE
- || TREE_CODE (ttl) != FUNCTION_TYPE)
- {
- if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
- warn_for_assignment ("%s discards `const' from pointer target type",
- get_spelling (errtype), funname,
- parmnum);
- if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
- warn_for_assignment ("%s discards `volatile' from pointer target type",
- get_spelling (errtype), funname,
- parmnum);
- }
- else
- {
- /* Because const and volatile on functions are
- restrictions that say the function will not do
- certain things, it is okay to use a const or volatile
- function where an ordinary one is wanted, but not
- vice-versa. */
- if (TYPE_READONLY (ttl) && ! TYPE_READONLY (ttr))
- warn_for_assignment ("%s makes `const *' function pointer from non-const",
- get_spelling (errtype), funname,
- parmnum);
- if (TYPE_VOLATILE (ttl) && ! TYPE_VOLATILE (ttr))
- warn_for_assignment ("%s makes `volatile *' function pointer from non-volatile",
- get_spelling (errtype), funname,
- parmnum);
- }
-
- if (pedantic
- && !(fundecl != 0 && DECL_IN_SYSTEM_HEADER (fundecl)))
- pedwarn ("ANSI C prohibits argument conversion to union type");
- return build1 (NOP_EXPR, type, rhs);
+ /* If this type won't generate any warnings, use it. */
+ if ((TREE_CODE (ttr) == FUNCTION_TYPE
+ && TREE_CODE (ttl) == FUNCTION_TYPE)
+ ? ((! TYPE_READONLY (ttl) | TYPE_READONLY (ttr))
+ & (! TYPE_VOLATILE (ttl) | TYPE_VOLATILE (ttr)))
+ : ((TYPE_READONLY (ttl) | ! TYPE_READONLY (ttr))
+ & (TYPE_VOLATILE (ttl) | ! TYPE_VOLATILE (ttr))))
+ break;
+
+ /* Keep looking for a better type, but remember this one. */
+ if (! marginal_memb_type)
+ marginal_memb_type = memb_type;
}
}
/* Can convert integer zero to any pointer type. */
- else if (TREE_CODE (TREE_TYPE (memb_types)) == POINTER_TYPE
- && (integer_zerop (rhs)
- || (TREE_CODE (rhs) == NOP_EXPR
- && integer_zerop (TREE_OPERAND (rhs, 0)))))
- return build1 (NOP_EXPR, type, null_pointer_node);
+ if (integer_zerop (rhs)
+ || (TREE_CODE (rhs) == NOP_EXPR
+ && integer_zerop (TREE_OPERAND (rhs, 0))))
+ {
+ rhs = null_pointer_node;
+ break;
+ }
+ }
+
+ if (memb_types || marginal_memb_type)
+ {
+ if (! memb_types)
+ {
+ /* We have only a marginally acceptable member type;
+ it needs a warning. */
+ register tree ttl = TREE_TYPE (marginal_memb_type);
+ register tree ttr = TREE_TYPE (rhstype);
+
+ /* Const and volatile mean something different for function
+ types, so the usual warnings are not appropriate. */
+ if (TREE_CODE (ttr) == FUNCTION_TYPE
+ && TREE_CODE (ttl) == FUNCTION_TYPE)
+ {
+ /* Because const and volatile on functions are
+ restrictions that say the function will not do
+ certain things, it is okay to use a const or volatile
+ function where an ordinary one is wanted, but not
+ vice-versa. */
+ if (TYPE_READONLY (ttl) && ! TYPE_READONLY (ttr))
+ warn_for_assignment ("%s makes `const *' function pointer from non-const",
+ get_spelling (errtype), funname,
+ parmnum);
+ if (TYPE_VOLATILE (ttl) && ! TYPE_VOLATILE (ttr))
+ warn_for_assignment ("%s makes `volatile *' function pointer from non-volatile",
+ get_spelling (errtype), funname,
+ parmnum);
+ }
+ else
+ {
+ if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr))
+ warn_for_assignment ("%s discards `const' from pointer target type",
+ get_spelling (errtype), funname,
+ parmnum);
+ if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr))
+ warn_for_assignment ("%s discards `volatile' from pointer target type",
+ get_spelling (errtype), funname,
+ parmnum);
+ }
+ }
+
+ if (pedantic && ! DECL_IN_SYSTEM_HEADER (fundecl))
+ pedwarn ("ANSI C prohibits argument conversion to union type");
+
+ return build1 (NOP_EXPR, type, rhs);
}
}
@@ -4270,7 +4364,8 @@ initializer_constant_valid_p (value, endtype)
case CONSTRUCTOR:
if ((TREE_CODE (TREE_TYPE (value)) == UNION_TYPE
|| TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE)
- && TREE_CONSTANT (value))
+ && TREE_CONSTANT (value)
+ && CONSTRUCTOR_ELTS (value))
return
initializer_constant_valid_p (TREE_VALUE (CONSTRUCTOR_ELTS (value)),
endtype);
@@ -4377,9 +4472,10 @@ initializer_constant_valid_p (value, endtype)
return null_pointer_node;
return 0;
}
- }
- return 0;
+ default:
+ return 0;
+ }
}
/* If VALUE is a compound expr all of whose expressions are constant, then
@@ -4600,7 +4696,7 @@ print_spelling (buffer)
{
if (p->kind == SPELLING_MEMBER)
*d++ = '.';
- for (s = p->u.s; *d = *s++; d++)
+ for (s = p->u.s; (*d = *s++); d++)
;
}
*d++ = '\0';
@@ -4994,20 +5090,29 @@ static int constructor_erroneous;
/* 1 if have called defer_addressed_constants. */
static int constructor_subconstants_deferred;
-/* List of pending elements at this constructor level.
+/* Structure for managing pending initializer elements, organized as an
+ AVL tree. */
+
+struct init_node
+{
+ struct init_node *left, *right;
+ struct init_node *parent;
+ int balance;
+ tree purpose;
+ tree value;
+};
+
+/* Tree of pending elements at this constructor level.
These are elements encountered out of order
which belong at places we haven't reached yet in actually
writing the output. */
-static tree constructor_pending_elts;
+static struct init_node *constructor_pending_elts;
/* The SPELLING_DEPTH of this constructor. */
static int constructor_depth;
/* 0 if implicitly pushing constructor levels is allowed. */
-int constructor_no_implicit = 0; /* 0 for C; 1 for some other languages. */
-
-/* 1 if this constructor level was entered implicitly. */
-static int constructor_implicit;
+int constructor_no_implicit = 0; /* 0 for C; 1 for some other languages. */
static int require_constant_value;
static int require_constant_elements;
@@ -5027,9 +5132,6 @@ static char *constructor_asmspec;
/* Nonzero if this is an initializer for a top-level decl. */
static int constructor_top_level;
-/* When we finish reading a constructor expression
- (constructor_decl is 0), the CONSTRUCTOR goes here. */
-static tree constructor_result;
/* This stack has a level for each implicit or explicit level of
structuring in the initializer, including the outermost one. It
@@ -5048,7 +5150,7 @@ struct constructor_stack
tree bit_index;
tree elements;
int offset;
- tree pending_elts;
+ struct init_node *pending_elts;
int depth;
/* If nonzero, this value should replace the entire
constructor at this level. */
@@ -5247,11 +5349,12 @@ really_start_incremental_init (type)
{
constructor_fields = TYPE_FIELDS (constructor_type);
/* Skip any nameless bit fields at the beginning. */
- while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+ while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields)
&& DECL_NAME (constructor_fields) == 0)
constructor_fields = TREE_CHAIN (constructor_fields);
constructor_unfilled_fields = constructor_fields;
constructor_bit_index = copy_node (integer_zero_node);
+ TREE_TYPE (constructor_bit_index) = sbitsizetype;
}
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
@@ -5320,23 +5423,32 @@ push_init_level (implicit)
break;
}
- /* Structure elements may require alignment. Do this now
- if necessary for the subaggregate. */
+ /* Structure elements may require alignment. Do this now if necessary
+ for the subaggregate, and if it comes next in sequence. Don't do
+ this for subaggregates that will go on the pending list. */
if (constructor_incremental && constructor_type != 0
- && TREE_CODE (constructor_type) == RECORD_TYPE && constructor_fields)
+ && TREE_CODE (constructor_type) == RECORD_TYPE && constructor_fields
+ && constructor_fields == constructor_unfilled_fields)
{
/* Advance to offset of this element. */
if (! tree_int_cst_equal (constructor_bit_index,
DECL_FIELD_BITPOS (constructor_fields)))
{
- int next = (TREE_INT_CST_LOW
- (DECL_FIELD_BITPOS (constructor_fields))
- / BITS_PER_UNIT);
- int here = (TREE_INT_CST_LOW (constructor_bit_index)
- / BITS_PER_UNIT);
-
- assemble_zeros (next - here);
+ /* By using unsigned arithmetic, the result will be correct even
+ in case of overflows, if BITS_PER_UNIT is a power of two. */
+ unsigned next = (TREE_INT_CST_LOW
+ (DECL_FIELD_BITPOS (constructor_fields))
+ / (unsigned)BITS_PER_UNIT);
+ unsigned here = (TREE_INT_CST_LOW (constructor_bit_index)
+ / (unsigned)BITS_PER_UNIT);
+
+ assemble_zeros ((next - here)
+ * (unsigned)BITS_PER_UNIT
+ / (unsigned)BITS_PER_UNIT);
}
+ /* Indicate that we have now filled the structure up to the current
+ field. */
+ constructor_unfilled_fields = constructor_fields;
}
p = (struct constructor_stack *) xmalloc (sizeof (struct constructor_stack));
@@ -5419,11 +5531,12 @@ push_init_level (implicit)
{
constructor_fields = TYPE_FIELDS (constructor_type);
/* Skip any nameless bit fields at the beginning. */
- while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+ while (constructor_fields != 0 && DECL_C_BIT_FIELD (constructor_fields)
&& DECL_NAME (constructor_fields) == 0)
constructor_fields = TREE_CHAIN (constructor_fields);
constructor_unfilled_fields = constructor_fields;
constructor_bit_index = copy_node (integer_zero_node);
+ TREE_TYPE (constructor_bit_index) = sbitsizetype;
}
else if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
@@ -5461,7 +5574,7 @@ check_init_type_bitfields (type)
for (tail = TYPE_FIELDS (type); tail;
tail = TREE_CHAIN (tail))
{
- if (DECL_BIT_FIELD (tail)
+ if (DECL_C_BIT_FIELD (tail)
/* This catches cases like `int foo : 8;'. */
|| DECL_MODE (tail) != TYPE_MODE (TREE_TYPE (tail)))
{
@@ -5506,6 +5619,17 @@ pop_init_level (implicit)
if (constructor_type != 0)
size = int_size_in_bytes (constructor_type);
+ /* Warn when some struct elements are implicitly initialized to zero. */
+ if (extra_warnings
+ && constructor_type
+ && TREE_CODE (constructor_type) == RECORD_TYPE
+ && constructor_unfilled_fields)
+ {
+ push_member_name (constructor_unfilled_fields);
+ warning_init ("missing initializer%s", " for `%s'", NULL);
+ RESTORE_SPELLING_DEPTH (constructor_depth);
+ }
+
/* Now output all pending elements. */
output_pending_init_elements (1);
@@ -5729,10 +5853,8 @@ set_init_index (first, last)
error_init ("duplicate array index in initializer%s", " for `%s'", NULL);
else
{
- TREE_INT_CST_LOW (constructor_index)
- = TREE_INT_CST_LOW (first);
- TREE_INT_CST_HIGH (constructor_index)
- = TREE_INT_CST_HIGH (first);
+ TREE_INT_CST_LOW (constructor_index) = TREE_INT_CST_LOW (first);
+ TREE_INT_CST_HIGH (constructor_index) = TREE_INT_CST_HIGH (first);
if (last != 0 && tree_int_cst_lt (last, first))
error_init ("empty index range in initializer%s", " for `%s'", NULL);
@@ -5782,6 +5904,251 @@ set_init_label (fieldname)
}
}
+/* Add a new initializer to the tree of pending initializers. PURPOSE
+ indentifies the initializer, either array index or field in a structure.
+ VALUE is the value of that index or field. */
+
+static void
+add_pending_init (purpose, value)
+ tree purpose, value;
+{
+ struct init_node *p, **q, *r;
+
+ q = &constructor_pending_elts;
+ p = 0;
+
+ if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+ {
+ while (*q != 0)
+ {
+ p = *q;
+ if (tree_int_cst_lt (purpose, p->purpose))
+ q = &p->left;
+ else if (tree_int_cst_lt (p->purpose, purpose))
+ q = &p->right;
+ else
+ abort ();
+ }
+ }
+ else
+ {
+ while (*q != NULL)
+ {
+ p = *q;
+ if (tree_int_cst_lt (DECL_FIELD_BITPOS (purpose),
+ DECL_FIELD_BITPOS (p->purpose)))
+ q = &p->left;
+ else if (tree_int_cst_lt (DECL_FIELD_BITPOS (p->purpose),
+ DECL_FIELD_BITPOS (purpose)))
+ q = &p->right;
+ else
+ abort ();
+ }
+ }
+
+ r = (struct init_node *) oballoc (sizeof (struct init_node));
+ r->purpose = purpose;
+ r->value = value;
+
+ *q = r;
+ r->parent = p;
+ r->left = 0;
+ r->right = 0;
+ r->balance = 0;
+
+ while (p)
+ {
+ struct init_node *s;
+
+ if (r == p->left)
+ {
+ if (p->balance == 0)
+ p->balance = -1;
+ else if (p->balance < 0)
+ {
+ if (r->balance < 0)
+ {
+ /* L rotation. */
+ p->left = r->right;
+ if (p->left)
+ p->left->parent = p;
+ r->right = p;
+
+ p->balance = 0;
+ r->balance = 0;
+
+ s = p->parent;
+ p->parent = r;
+ r->parent = s;
+ if (s)
+ {
+ if (s->left == p)
+ s->left = r;
+ else
+ s->right = r;
+ }
+ else
+ constructor_pending_elts = r;
+ }
+ else
+ {
+ /* LR rotation. */
+ struct init_node *t = r->right;
+
+ r->right = t->left;
+ if (r->right)
+ r->right->parent = r;
+ t->left = r;
+
+ p->left = t->right;
+ if (p->left)
+ p->left->parent = p;
+ t->right = p;
+
+ p->balance = t->balance < 0;
+ r->balance = -(t->balance > 0);
+ t->balance = 0;
+
+ s = p->parent;
+ p->parent = t;
+ r->parent = t;
+ t->parent = s;
+ if (s)
+ {
+ if (s->left == p)
+ s->left = t;
+ else
+ s->right = t;
+ }
+ else
+ constructor_pending_elts = t;
+ }
+ break;
+ }
+ else
+ {
+ /* p->balance == +1; growth of left side balances the node. */
+ p->balance = 0;
+ break;
+ }
+ }
+ else /* r == p->right */
+ {
+ if (p->balance == 0)
+ /* Growth propagation from right side. */
+ p->balance++;
+ else if (p->balance > 0)
+ {
+ if (r->balance > 0)
+ {
+ /* R rotation. */
+ p->right = r->left;
+ if (p->right)
+ p->right->parent = p;
+ r->left = p;
+
+ p->balance = 0;
+ r->balance = 0;
+
+ s = p->parent;
+ p->parent = r;
+ r->parent = s;
+ if (s)
+ {
+ if (s->left == p)
+ s->left = r;
+ else
+ s->right = r;
+ }
+ else
+ constructor_pending_elts = r;
+ }
+ else /* r->balance == -1 */
+ {
+ /* RL rotation */
+ struct init_node *t = r->left;
+
+ r->left = t->right;
+ if (r->left)
+ r->left->parent = r;
+ t->right = r;
+
+ p->right = t->left;
+ if (p->right)
+ p->right->parent = p;
+ t->left = p;
+
+ r->balance = (t->balance < 0);
+ p->balance = -(t->balance > 0);
+ t->balance = 0;
+
+ s = p->parent;
+ p->parent = t;
+ r->parent = t;
+ t->parent = s;
+ if (s)
+ {
+ if (s->left == p)
+ s->left = t;
+ else
+ s->right = t;
+ }
+ else
+ constructor_pending_elts = t;
+ }
+ break;
+ }
+ else
+ {
+ /* p->balance == -1; growth of right side balances the node. */
+ p->balance = 0;
+ break;
+ }
+ }
+
+ r = p;
+ p = p->parent;
+ }
+}
+
+/* Return nonzero if FIELD is equal to the index of a pending initializer. */
+
+static int
+pending_init_member (field)
+ tree field;
+{
+ struct init_node *p;
+
+ p = constructor_pending_elts;
+ if (TREE_CODE (constructor_type) == ARRAY_TYPE)
+ {
+ while (p)
+ {
+ if (tree_int_cst_equal (field, p->purpose))
+ return 1;
+ else if (tree_int_cst_lt (field, p->purpose))
+ p = p->left;
+ else
+ p = p->right;
+ }
+ }
+ else
+ {
+ while (p)
+ {
+ if (field == p->purpose)
+ return 1;
+ else if (tree_int_cst_lt (DECL_FIELD_BITPOS (field),
+ DECL_FIELD_BITPOS (p->purpose)))
+ p = p->left;
+ else
+ p = p->right;
+ }
+ }
+
+ return 0;
+}
+
/* "Output" the next constructor element.
At top level, really output it to assembler code now.
Otherwise, collect it in a list from which we will make a CONSTRUCTOR.
@@ -5815,7 +6182,8 @@ output_init_element (value, type, field, pending)
else if (initializer_constant_valid_p (value, TREE_TYPE (value)) == 0
|| ((TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
- && DECL_BIT_FIELD (field) && TREE_CODE (value) != INTEGER_CST))
+ && DECL_C_BIT_FIELD (field)
+ && TREE_CODE (value) != INTEGER_CST))
constructor_simple = 0;
if (require_constant_value && ! TREE_CONSTANT (value))
@@ -5839,25 +6207,10 @@ output_init_element (value, type, field, pending)
if (pending)
{
if (TREE_CODE (constructor_type) == RECORD_TYPE
- || TREE_CODE (constructor_type) == UNION_TYPE)
+ || TREE_CODE (constructor_type) == UNION_TYPE
+ || TREE_CODE (constructor_type) == ARRAY_TYPE)
{
- if (purpose_member (field, constructor_pending_elts))
- {
- error_init ("duplicate initializer%s", " for `%s'", NULL);
- duplicate = 1;
- }
- }
- if (TREE_CODE (constructor_type) == ARRAY_TYPE)
- {
- tree tail;
- for (tail = constructor_pending_elts; tail;
- tail = TREE_CHAIN (tail))
- if (TREE_PURPOSE (tail) != 0
- && TREE_CODE (TREE_PURPOSE (tail)) == INTEGER_CST
- && tree_int_cst_equal (TREE_PURPOSE (tail), constructor_index))
- break;
-
- if (tail != 0)
+ if (pending_init_member (field))
{
error_init ("duplicate initializer%s", " for `%s'", NULL);
duplicate = 1;
@@ -5873,11 +6226,9 @@ output_init_element (value, type, field, pending)
if (! duplicate)
/* The copy_node is needed in case field is actually
constructor_index, which is modified in place. */
- constructor_pending_elts
- = tree_cons (copy_node (field),
- digest_init (type, value, require_constant_value,
- require_constant_elements),
- constructor_pending_elts);
+ add_pending_init (copy_node (field),
+ digest_init (type, value, require_constant_value,
+ require_constant_elements));
}
else if (TREE_CODE (constructor_type) == RECORD_TYPE
&& field != constructor_unfilled_fields)
@@ -5886,11 +6237,9 @@ output_init_element (value, type, field, pending)
no matter which field is specified, it can be initialized
right away since it starts at the beginning of the union. */
if (!duplicate)
- constructor_pending_elts
- = tree_cons (field,
- digest_init (type, value, require_constant_value,
- require_constant_elements),
- constructor_pending_elts);
+ add_pending_init (field,
+ digest_init (type, value, require_constant_value,
+ require_constant_elements));
}
else
{
@@ -5919,12 +6268,19 @@ output_init_element (value, type, field, pending)
if (! tree_int_cst_equal (constructor_bit_index,
DECL_FIELD_BITPOS (field)))
{
- int next = (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field))
- / BITS_PER_UNIT);
- int here = (TREE_INT_CST_LOW (constructor_bit_index)
- / BITS_PER_UNIT);
-
- assemble_zeros (next - here);
+ /* By using unsigned arithmetic, the result will be
+ correct even in case of overflows, if BITS_PER_UNIT
+ is a power of two. */
+ unsigned next = (TREE_INT_CST_LOW
+ (DECL_FIELD_BITPOS (field))
+ / (unsigned)BITS_PER_UNIT);
+ unsigned here = (TREE_INT_CST_LOW
+ (constructor_bit_index)
+ / (unsigned)BITS_PER_UNIT);
+
+ assemble_zeros ((next - here)
+ * (unsigned)BITS_PER_UNIT
+ / (unsigned)BITS_PER_UNIT);
}
}
output_constant (digest_init (type, value,
@@ -5983,56 +6339,109 @@ static void
output_pending_init_elements (all)
int all;
{
- tree tail;
+ struct init_node *elt = constructor_pending_elts;
tree next;
retry:
- /* Look thru the whole pending list.
+ /* Look thru the whole pending tree.
If we find an element that should be output now,
output it. Otherwise, set NEXT to the element
that comes first among those still pending. */
next = 0;
- for (tail = constructor_pending_elts; tail;
- tail = TREE_CHAIN (tail))
+ while (elt)
{
if (TREE_CODE (constructor_type) == ARRAY_TYPE)
{
- if (tree_int_cst_equal (TREE_PURPOSE (tail),
+ if (tree_int_cst_equal (elt->purpose,
constructor_unfilled_index))
+ output_init_element (elt->value,
+ TREE_TYPE (constructor_type),
+ constructor_unfilled_index, 0);
+ else if (tree_int_cst_lt (constructor_unfilled_index,
+ elt->purpose))
{
- output_init_element (TREE_VALUE (tail),
- TREE_TYPE (constructor_type),
- constructor_unfilled_index, 0);
- goto retry;
+ /* Advance to the next smaller node. */
+ if (elt->left)
+ elt = elt->left;
+ else
+ {
+ /* We have reached the smallest node bigger than the
+ current unfilled index. Fill the space first. */
+ next = elt->purpose;
+ break;
+ }
+ }
+ else
+ {
+ /* Advance to the next bigger node. */
+ if (elt->right)
+ elt = elt->right;
+ else
+ {
+ /* We have reached the biggest node in a subtree. Find
+ the parent of it, which is the next bigger node. */
+ while (elt->parent && elt->parent->right == elt)
+ elt = elt->parent;
+ elt = elt->parent;
+ if (elt && tree_int_cst_lt (constructor_unfilled_index,
+ elt->purpose))
+ {
+ next = elt->purpose;
+ break;
+ }
+ }
}
- else if (tree_int_cst_lt (TREE_PURPOSE (tail),
- constructor_unfilled_index))
- ;
- else if (next == 0
- || tree_int_cst_lt (TREE_PURPOSE (tail), next))
- next = TREE_PURPOSE (tail);
}
else if (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
{
- if (TREE_PURPOSE (tail) == constructor_unfilled_fields)
+ /* If the current record is complete we are done. */
+ if (constructor_unfilled_fields == 0)
+ break;
+ if (elt->purpose == constructor_unfilled_fields)
{
- output_init_element (TREE_VALUE (tail),
+ output_init_element (elt->value,
TREE_TYPE (constructor_unfilled_fields),
constructor_unfilled_fields,
0);
- goto retry;
}
- else if (constructor_unfilled_fields == 0
- || tree_int_cst_lt (DECL_FIELD_BITPOS (TREE_PURPOSE (tail)),
- DECL_FIELD_BITPOS (constructor_unfilled_fields)))
- ;
- else if (next == 0
- || tree_int_cst_lt (DECL_FIELD_BITPOS (TREE_PURPOSE (tail)),
- DECL_FIELD_BITPOS (next)))
- next = TREE_PURPOSE (tail);
+ else if (tree_int_cst_lt (DECL_FIELD_BITPOS (constructor_unfilled_fields),
+ DECL_FIELD_BITPOS (elt->purpose)))
+ {
+ /* Advance to the next smaller node. */
+ if (elt->left)
+ elt = elt->left;
+ else
+ {
+ /* We have reached the smallest node bigger than the
+ current unfilled field. Fill the space first. */
+ next = elt->purpose;
+ break;
+ }
+ }
+ else
+ {
+ /* Advance to the next bigger node. */
+ if (elt->right)
+ elt = elt->right;
+ else
+ {
+ /* We have reached the biggest node in a subtree. Find
+ the parent of it, which is the next bigger node. */
+ while (elt->parent && elt->parent->right == elt)
+ elt = elt->parent;
+ elt = elt->parent;
+ if (elt
+ && tree_int_cst_lt (DECL_FIELD_BITPOS (constructor_unfilled_fields),
+ DECL_FIELD_BITPOS (elt->purpose)))
+ {
+ next = elt->purpose;
+ break;
+ }
+ }
+ }
}
}
@@ -6050,6 +6459,7 @@ output_pending_init_elements (all)
if (TREE_CODE (constructor_type) == RECORD_TYPE
|| TREE_CODE (constructor_type) == UNION_TYPE)
{
+ tree tail;
/* Find the last field written out, if any. */
for (tail = TYPE_FIELDS (constructor_type); tail;
tail = TREE_CHAIN (tail))
@@ -6115,6 +6525,8 @@ output_pending_init_elements (all)
}
}
+ /* ELT now points to the node in the pending tree with the next
+ initializer to output. */
goto retry;
}
@@ -6172,7 +6584,9 @@ process_init_element (value)
&& constructor_fields == 0)
process_init_element (pop_init_level (1));
else if (TREE_CODE (constructor_type) == ARRAY_TYPE
- && tree_int_cst_lt (constructor_max_index, constructor_index))
+ && (constructor_max_index == 0
+ || tree_int_cst_lt (constructor_max_index,
+ constructor_index)))
process_init_element (pop_init_level (1));
else
break;
@@ -6239,7 +6653,8 @@ process_init_element (value)
constructor_fields = TREE_CHAIN (constructor_fields);
/* Skip any nameless bit fields at the beginning. */
- while (constructor_fields != 0 && DECL_BIT_FIELD (constructor_fields)
+ while (constructor_fields != 0
+ && DECL_C_BIT_FIELD (constructor_fields)
&& DECL_NAME (constructor_fields) == 0)
constructor_fields = TREE_CHAIN (constructor_fields);
break;
@@ -6331,9 +6746,23 @@ process_init_element (value)
break;
}
- /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once. */
+ /* In the case of [LO .. HI] = VALUE, only evaluate VALUE once. */
if (constructor_range_end)
- value = save_expr (value);
+ {
+ if (constructor_max_index != 0
+ && tree_int_cst_lt (constructor_max_index,
+ constructor_range_end))
+ {
+ pedwarn_init ("excess elements in array initializer%s",
+ " after `%s'", NULL_PTR);
+ TREE_INT_CST_HIGH (constructor_range_end)
+ = TREE_INT_CST_HIGH (constructor_max_index);
+ TREE_INT_CST_LOW (constructor_range_end)
+ = TREE_INT_CST_LOW (constructor_max_index);
+ }
+
+ value = save_expr (value);
+ }
/* Now output the actual element.
Ordinarily, output once.
@@ -6351,10 +6780,8 @@ process_init_element (value)
tem = size_binop (PLUS_EXPR, constructor_index,
integer_one_node);
- TREE_INT_CST_LOW (constructor_index)
- = TREE_INT_CST_LOW (tem);
- TREE_INT_CST_HIGH (constructor_index)
- = TREE_INT_CST_HIGH (tem);
+ TREE_INT_CST_LOW (constructor_index) = TREE_INT_CST_LOW (tem);
+ TREE_INT_CST_HIGH (constructor_index) = TREE_INT_CST_HIGH (tem);
if (!value)
/* If we are doing the bookkeeping for an element that was
@@ -6446,7 +6873,7 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
if (o[i] != TREE_VALUE (tail))
{
expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)),
- 0, VOIDmode, 0);
+ NULL_RTX, VOIDmode, EXPAND_NORMAL);
free_temp_slots ();
}
/* Detect modification of read-only values.
@@ -6549,6 +6976,9 @@ c_expand_return (retval)
&& DECL_CONTEXT (inner) == current_function_decl)
warning ("function returns address of local variable");
break;
+
+ default:
+ break;
}
break;
diff --git a/contrib/gcc/caller-save.c b/contrib/gcc/caller-save.c
index 6dc9018..4a2deb6 100644
--- a/contrib/gcc/caller-save.c
+++ b/contrib/gcc/caller-save.c
@@ -1,5 +1,5 @@
/* Save and restore call-clobbered registers which are live across a call.
- Copyright (C) 1989, 1992, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1989, 1992, 94-95, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,6 +19,7 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "insn-config.h"
#include "flags.h"
@@ -28,6 +29,7 @@ Boston, MA 02111-1307, USA. */
#include "basic-block.h"
#include "reload.h"
#include "expr.h"
+#include "toplev.h"
#ifndef MAX_MOVE_MAX
#define MAX_MOVE_MAX MOVE_MAX
@@ -143,11 +145,11 @@ init_caller_save ()
if (i == FIRST_PSEUDO_REGISTER)
abort ();
- addr_reg = gen_rtx (REG, Pmode, i);
+ addr_reg = gen_rtx_REG (Pmode, i);
for (offset = 1 << (HOST_BITS_PER_INT / 2); offset; offset >>= 1)
{
- address = gen_rtx (PLUS, Pmode, addr_reg, GEN_INT (offset));
+ address = gen_rtx_PLUS (Pmode, addr_reg, GEN_INT (offset));
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (regno_save_mode[i][1] != VOIDmode
@@ -171,10 +173,10 @@ init_caller_save ()
for (j = 1; j <= MOVE_MAX / UNITS_PER_WORD; j++)
if (regno_save_mode[i][j] != VOIDmode)
{
- rtx mem = gen_rtx (MEM, regno_save_mode[i][j], address);
- rtx reg = gen_rtx (REG, regno_save_mode[i][j], i);
- rtx savepat = gen_rtx (SET, VOIDmode, mem, reg);
- rtx restpat = gen_rtx (SET, VOIDmode, reg, mem);
+ rtx mem = gen_rtx_MEM (regno_save_mode[i][j], address);
+ rtx reg = gen_rtx_REG (regno_save_mode[i][j], i);
+ rtx savepat = gen_rtx_SET (VOIDmode, mem, reg);
+ rtx restpat = gen_rtx_SET (VOIDmode, reg, mem);
rtx saveinsn = emit_insn (savepat);
rtx restinsn = emit_insn (restpat);
int ok;
@@ -182,7 +184,8 @@ init_caller_save ()
reg_save_code[i][j] = recog_memoized (saveinsn);
reg_restore_code[i][j] = recog_memoized (restinsn);
- /* Now extract both insns and see if we can meet their constraints. */
+ /* Now extract both insns and see if we can meet their
+ constraints. */
ok = (reg_save_code[i][j] != -1 && reg_restore_code[i][j] != -1);
if (ok)
{
@@ -261,7 +264,7 @@ setup_save_areas (pchanged)
/* Find and record all call-used hard-registers in this function. */
CLEAR_HARD_REG_SET (hard_regs_used);
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_renumber[i] >= 0 && reg_n_calls_crossed[i] > 0)
+ if (reg_renumber[i] >= 0 && REG_N_CALLS_CROSSED (i) > 0)
{
int regno = reg_renumber[i];
int endregno
@@ -307,7 +310,7 @@ setup_save_areas (pchanged)
ok &= (TEST_HARD_REG_BIT (hard_regs_used, regno) != 0);
}
- /* We have found an acceptable mode to store in. */
+ /* We have found an acceptable mode to store in. */
if (ok)
{
@@ -315,13 +318,13 @@ setup_save_areas (pchanged)
= assign_stack_local (regno_save_mode[i][j],
GET_MODE_SIZE (regno_save_mode[i][j]), 0);
- /* Setup single word save area just in case... */
+ /* Setup single word save area just in case... */
for (k = 0; k < j; k++)
{
/* This should not depend on WORDS_BIG_ENDIAN.
The order of words in regs is the same as in memory. */
- rtx temp = gen_rtx (MEM, regno_save_mode[i+k][1],
- XEXP (regno_save_mem[i][j], 0));
+ rtx temp = gen_rtx_MEM (regno_save_mode[i+k][1],
+ XEXP (regno_save_mem[i][j], 0));
regno_save_mem[i+k][1]
= adj_offsettable_operand (temp, k * UNITS_PER_WORD);
@@ -356,8 +359,7 @@ save_call_clobbered_regs (insn_mode)
{
regset regs_live = basic_block_live_at_start[b];
rtx prev_block_last = PREV_INSN (basic_block_head[b]);
- REGSET_ELT_TYPE bit;
- int offset, i, j;
+ int i, j;
int regno;
/* Compute hard regs live at start of block -- this is the
@@ -366,31 +368,20 @@ save_call_clobbered_regs (insn_mode)
saved because we restore all of them before the end of the basic
block. */
-#ifdef HARD_REG_SET
- hard_regs_live = *regs_live;
-#else
- COPY_HARD_REG_SET (hard_regs_live, regs_live);
-#endif
-
+ REG_SET_TO_HARD_REG_SET (hard_regs_live, regs_live);
CLEAR_HARD_REG_SET (hard_regs_saved);
CLEAR_HARD_REG_SET (hard_regs_need_restore);
n_regs_saved = 0;
- for (offset = 0, i = 0; offset < regset_size; offset++)
- {
- if (regs_live[offset] == 0)
- i += REGSET_ELT_BITS;
- else
- for (bit = 1; bit && i < max_regno; bit <<= 1, i++)
- if ((regs_live[offset] & bit)
- && (regno = reg_renumber[i]) >= 0)
- for (j = regno;
- j < regno + HARD_REGNO_NREGS (regno,
- PSEUDO_REGNO_MODE (i));
- j++)
- SET_HARD_REG_BIT (hard_regs_live, j);
-
- }
+ EXECUTE_IF_SET_IN_REG_SET (regs_live, 0, i,
+ {
+ if ((regno = reg_renumber[i]) >= 0)
+ for (j = regno;
+ j < regno + HARD_REGNO_NREGS (regno,
+ PSEUDO_REGNO_MODE (i));
+ j++)
+ SET_HARD_REG_BIT (hard_regs_live, j);
+ });
/* Now scan the insns in the block, keeping track of what hard
regs are live as we go. When we see a call, save the live
@@ -515,7 +506,8 @@ save_call_clobbered_regs (insn_mode)
static void
set_reg_live (reg, setter)
- rtx reg, setter;
+ rtx reg;
+ rtx setter ATTRIBUTE_UNUSED;
{
register int regno, endregno, i;
enum machine_mode mode = GET_MODE (reg);
@@ -650,9 +642,9 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
enum machine_mode insn_mode;
int maxrestore;
{
- rtx pat;
- enum insn_code code;
- int i, numregs;
+ rtx pat = NULL_RTX;
+ enum insn_code code = CODE_FOR_nothing;
+ int numregs = 0;
/* A common failure mode if register status is not correct in the RTL
is for this routine to be called with a REGNO we didn't expect to
@@ -702,8 +694,9 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
if (! ok)
continue;
- pat = gen_rtx (SET, VOIDmode, regno_save_mem[regno][i],
- gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]), regno));
+ pat = gen_rtx_SET (VOIDmode, regno_save_mem[regno][i],
+ gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
+ regno));
code = reg_save_code[regno][i];
/* Set hard_regs_saved for all the registers we saved. */
@@ -741,9 +734,9 @@ insert_save_restore (insn, save_p, regno, insn_mode, maxrestore)
if (! ok)
continue;
- pat = gen_rtx (SET, VOIDmode,
- gen_rtx (REG, GET_MODE (regno_save_mem[regno][i]),
- regno),
+ pat = gen_rtx_SET (VOIDmode,
+ gen_rtx_REG (GET_MODE (regno_save_mem[regno][i]),
+ regno),
regno_save_mem[regno][i]);
code = reg_restore_code[regno][i];
diff --git a/contrib/gcc/calls.c b/contrib/gcc/calls.c
index ad05be4..8b14019 100644
--- a/contrib/gcc/calls.c
+++ b/contrib/gcc/calls.c
@@ -1,5 +1,5 @@
/* Convert function calls to rtl insns, for GNU C compiler.
- Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,16 +19,20 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
-#include "rtl.h"
-#include "tree.h"
-#include "flags.h"
-#include "expr.h"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
+#include "system.h"
+#include "rtl.h"
+#include "tree.h"
+#include "flags.h"
+#include "expr.h"
+#include "regs.h"
#include "insn-flags.h"
+#include "toplev.h"
+#include "output.h"
/* Decide whether a function's arguments should be processed
from first to last or from last to first.
@@ -60,7 +64,7 @@ struct arg_data
/* Initially-compute RTL value for argument; only for const functions. */
rtx initial_value;
/* Register to pass this argument in, 0 if passed on stack, or an
- EXPR_LIST if the arg is to be copied into multiple different
+ PARALLEL if the arg is to be copied into multiple non-contiguous
registers. */
rtx reg;
/* If REG was promoted from the actual mode of the argument expression,
@@ -95,14 +99,12 @@ struct arg_data
/* Place that this stack area has been saved, if needed. */
rtx save_area;
#endif
-#ifdef STRICT_ALIGNMENT
/* If an argument's alignment does not permit direct copying into registers,
copy in smaller-sized pieces into pseudos. These are stored in a
block pointed to by this field. The next field says how many
word-sized pseudos we made. */
rtx *aligned_regs;
int n_aligned_regs;
-#endif
};
#ifdef ACCUMULATE_OUTGOING_ARGS
@@ -125,7 +127,8 @@ int stack_arg_under_construction;
static int calls_function PROTO((tree, int));
static int calls_function_1 PROTO((tree, int));
-static void emit_call_1 PROTO((rtx, tree, tree, int, int, rtx, rtx,
+static void emit_call_1 PROTO((rtx, tree, tree, HOST_WIDE_INT,
+ HOST_WIDE_INT, rtx, rtx,
int, rtx, int));
static void store_one_arg PROTO ((struct arg_data *, rtx, int, int,
tree, int));
@@ -234,6 +237,9 @@ calls_function_1 (exp, which)
case RTL_EXPR:
return 0;
+
+ default:
+ break;
}
for (i = 0; i < length; i++)
@@ -263,20 +269,17 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen)
funexp = protect_from_queue (funexp, 0);
if (fndecl != 0)
- /* Get possible static chain value for nested function in C. */
+ /* Get possible static chain value for nested function in C. */
static_chain_value = lookup_static_chain (fndecl);
/* Make a valid memory address and copy constants thru pseudo-regs,
but not for a constant address if -fno-function-cse. */
if (GET_CODE (funexp) != SYMBOL_REF)
- funexp =
-#ifdef SMALL_REGISTER_CLASSES
/* If we are using registers for parameters, force the
- function address into a register now. */
- reg_parm_seen ? force_not_mem (memory_address (FUNCTION_MODE, funexp))
- :
-#endif
- memory_address (FUNCTION_MODE, funexp);
+ function address into a register now. */
+ funexp = ((SMALL_REGISTER_CLASSES && reg_parm_seen)
+ ? force_not_mem (memory_address (FUNCTION_MODE, funexp))
+ : memory_address (FUNCTION_MODE, funexp));
else
{
#ifndef NO_FUNCTION_CSE
@@ -303,12 +306,14 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen)
and optionally pop the results.
The CALL_INSN is the first insn generated.
- FNDECL is the declaration node of the function. This is given ot the
+ FNDECL is the declaration node of the function. This is given to the
macro RETURN_POPS_ARGS to determine whether this function pops its own args.
- FUNTYPE is the data type of the function, or, for a library call,
- the identifier for the name of the call. This is given to the
- macro RETURN_POPS_ARGS to determine whether this function pops its own args.
+ FUNTYPE is the data type of the function. This is given to the macro
+ RETURN_POPS_ARGS to determine whether this function pops its own args.
+ We used to allow an identifier for library functions, but that doesn't
+ work when the return type is an aggregate type and the calling convention
+ says that the pointer to this aggregate is to be popped by the callee.
STACK_SIZE is the number of bytes of arguments on the stack,
rounded up to STACK_BOUNDARY; zero if the size is variable.
@@ -345,8 +350,8 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,
rtx funexp;
tree fndecl;
tree funtype;
- int stack_size;
- int struct_value_size;
+ HOST_WIDE_INT stack_size;
+ HOST_WIDE_INT struct_value_size;
rtx next_arg_reg;
rtx valreg;
int old_inhibit_defer_pop;
@@ -356,7 +361,9 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,
rtx stack_size_rtx = GEN_INT (stack_size);
rtx struct_value_size_rtx = GEN_INT (struct_value_size);
rtx call_insn;
+#ifndef ACCUMULATE_OUTGOING_ARGS
int already_popped = 0;
+#endif
/* Ensure address is valid. SYMBOL_REF is already valid, so no need,
and we don't want to load it into a register as an optimization,
@@ -378,10 +385,10 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,
if (valreg)
pat = gen_call_value_pop (valreg,
- gen_rtx (MEM, FUNCTION_MODE, funexp),
+ gen_rtx_MEM (FUNCTION_MODE, funexp),
stack_size_rtx, next_arg_reg, n_pop);
else
- pat = gen_call_pop (gen_rtx (MEM, FUNCTION_MODE, funexp),
+ pat = gen_call_pop (gen_rtx_MEM (FUNCTION_MODE, funexp),
stack_size_rtx, next_arg_reg, n_pop);
emit_call_insn (pat);
@@ -396,11 +403,11 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,
{
if (valreg)
emit_call_insn (gen_call_value (valreg,
- gen_rtx (MEM, FUNCTION_MODE, funexp),
+ gen_rtx_MEM (FUNCTION_MODE, funexp),
stack_size_rtx, next_arg_reg,
NULL_RTX));
else
- emit_call_insn (gen_call (gen_rtx (MEM, FUNCTION_MODE, funexp),
+ emit_call_insn (gen_call (gen_rtx_MEM (FUNCTION_MODE, funexp),
stack_size_rtx, next_arg_reg,
struct_value_size_rtx));
}
@@ -451,10 +458,10 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, struct_value_size,
if (stack_size != 0 && RETURN_POPS_ARGS (fndecl, funtype, stack_size) > 0)
{
if (!already_popped)
- CALL_INSN_FUNCTION_USAGE (call_insn) =
- gen_rtx (EXPR_LIST, VOIDmode,
- gen_rtx (CLOBBER, VOIDmode, stack_pointer_rtx),
- CALL_INSN_FUNCTION_USAGE (call_insn));
+ CALL_INSN_FUNCTION_USAGE (call_insn)
+ = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_CLOBBER (VOIDmode, stack_pointer_rtx),
+ CALL_INSN_FUNCTION_USAGE (call_insn));
stack_size -= RETURN_POPS_ARGS (fndecl, funtype, stack_size);
stack_size_rtx = GEN_INT (stack_size);
}
@@ -485,8 +492,6 @@ expand_call (exp, target, ignore)
tree actparms = TREE_OPERAND (exp, 1);
/* RTX for the function to be called. */
rtx funexp;
- /* Tree node for the function to be called (not the address!). */
- tree funtree;
/* Data type of the function. */
tree funtype;
/* Declaration of the function being called,
@@ -507,7 +512,7 @@ expand_call (exp, target, ignore)
/* Size of aggregate value wanted, or zero if none wanted
or if we are using the non-reentrant PCC calling convention
or expecting the value in registers. */
- int struct_value_size = 0;
+ HOST_WIDE_INT struct_value_size = 0;
/* Nonzero if called function returns an aggregate in memory PCC style,
by returning the address of where to find it. */
int pcc_struct_value = 0;
@@ -534,7 +539,6 @@ expand_call (exp, target, ignore)
/* Nonzero if a reg parm has been scanned. */
int reg_parm_seen;
/* Nonzero if this is an indirect function call. */
- int current_call_is_indirect = 0;
/* Nonzero if we must avoid push-insns in the args for this call.
If stack space is allocated for register parameters, but not by the
@@ -542,15 +546,11 @@ expand_call (exp, target, ignore)
So the entire argument block must then be preallocated (i.e., we
ignore PUSH_ROUNDING in that case). */
-#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
- int must_preallocate = 1;
-#else
#ifdef PUSH_ROUNDING
int must_preallocate = 0;
#else
int must_preallocate = 1;
#endif
-#endif
/* Size of the stack reserved for parameter registers. */
int reg_parm_stack_space = 0;
@@ -563,6 +563,8 @@ expand_call (exp, target, ignore)
/* Nonzero if it is plausible that this is a call to alloca. */
int may_be_alloca;
+ /* Nonzero if this is a call to malloc or a related function. */
+ int is_malloc;
/* Nonzero if this is a call to setjmp or a related function. */
int returns_twice;
/* Nonzero if this is a call to `longjmp'. */
@@ -584,17 +586,23 @@ expand_call (exp, target, ignore)
#ifdef ACCUMULATE_OUTGOING_ARGS
int initial_highest_arg_in_use = highest_outgoing_arg_in_use;
char *initial_stack_usage_map = stack_usage_map;
+ int old_stack_arg_under_construction;
#endif
rtx old_stack_level = 0;
int old_pending_adj = 0;
- int old_stack_arg_under_construction;
int old_inhibit_defer_pop = inhibit_defer_pop;
- tree old_cleanups = cleanups_this_call;
rtx call_fusage = 0;
register tree p;
register int i, j;
+ /* The value of the function call can be put in a hard register. But
+ if -fcheck-memory-usage, code which invokes functions (and thus
+ damages some hard registers) can be inserted before using the value.
+ So, target is always a pseudo-register in that case. */
+ if (flag_check_memory_usage)
+ target = 0;
+
/* See if we can find a DECL-node for the actual function.
As a result, decide whether this is a call to an integrable function. */
@@ -609,7 +617,8 @@ expand_call (exp, target, ignore)
if (!flag_no_inline
&& fndecl != current_function_decl
&& DECL_INLINE (fndecl)
- && DECL_SAVED_INSNS (fndecl))
+ && DECL_SAVED_INSNS (fndecl)
+ && RTX_INTEGRATED_P (DECL_SAVED_INSNS (fndecl)))
is_integrable = 1;
else if (! TREE_ADDRESSABLE (fndecl))
{
@@ -618,7 +627,8 @@ expand_call (exp, target, ignore)
Use abstraction instead of setting TREE_ADDRESSABLE
directly. */
- if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline)
+ if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline
+ && optimize > 0)
{
warning_with_decl (fndecl, "can't inline call to `%s'");
warning ("called from here");
@@ -651,6 +661,11 @@ expand_call (exp, target, ignore)
#endif
#endif
+#if defined(PUSH_ROUNDING) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
+ if (reg_parm_stack_space > 0)
+ must_preallocate = 1;
+#endif
+
/* Warn if this value is an aggregate type,
regardless of which calling convention we are using for it. */
if (warn_aggregate_return && AGGREGATE_TYPE_P (TREE_TYPE (exp)))
@@ -685,7 +700,8 @@ expand_call (exp, target, ignore)
structure_value_addr = XEXP (target, 0);
else
{
- /* Assign a temporary on the stack to hold the value. */
+ /* Assign a temporary to hold the value. */
+ tree d;
/* For variable-sized objects, we must be called with a target
specified. If we were to allocate space on the stack here,
@@ -694,10 +710,13 @@ expand_call (exp, target, ignore)
if (struct_value_size < 0)
abort ();
- structure_value_addr
- = XEXP (assign_stack_temp (BLKmode, struct_value_size, 1), 0);
- MEM_IN_STRUCT_P (structure_value_addr)
- = AGGREGATE_TYPE_P (TREE_TYPE (exp));
+ /* This DECL is just something to feed to mark_addressable;
+ it doesn't get pushed. */
+ d = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
+ DECL_RTL (d) = assign_temp (TREE_TYPE (exp), 1, 0, 1);
+ mark_addressable (d);
+ structure_value_addr = XEXP (DECL_RTL (d), 0);
+ TREE_USED (d) = 1;
target = 0;
}
}
@@ -709,26 +728,17 @@ expand_call (exp, target, ignore)
if (is_integrable)
{
rtx temp;
+#ifdef ACCUMULATE_OUTGOING_ARGS
rtx before_call = get_last_insn ();
+#endif
temp = expand_inline_function (fndecl, actparms, target,
ignore, TREE_TYPE (exp),
structure_value_addr);
/* If inlining succeeded, return. */
- if ((HOST_WIDE_INT) temp != -1)
+ if (temp != (rtx) (HOST_WIDE_INT) -1)
{
- if (flag_short_temps)
- {
- /* Perform all cleanups needed for the arguments of this
- call (i.e. destructors in C++). It is ok if these
- destructors clobber RETURN_VALUE_REG, because the
- only time we care about this is when TARGET is that
- register. But in C++, we take care to never return
- that register directly. */
- expand_cleanups_to (old_cleanups);
- }
-
#ifdef ACCUMULATE_OUTGOING_ARGS
/* If the outgoing argument list must be preserved, push
the stack before executing the inlined function if it
@@ -740,7 +750,9 @@ expand_call (exp, target, ignore)
if (stack_arg_under_construction || i >= 0)
{
- rtx insn = NEXT_INSN (before_call), seq;
+ rtx first_insn
+ = before_call ? NEXT_INSN (before_call) : get_insns ();
+ rtx insn, seq;
/* Look for a call in the inline function code.
If OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) is
@@ -748,7 +760,7 @@ expand_call (exp, target, ignore)
to scan the insns. */
if (OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl)) == 0)
- for (; insn; insn = NEXT_INSN (insn))
+ for (insn = first_insn; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == CALL_INSN)
break;
@@ -762,25 +774,25 @@ expand_call (exp, target, ignore)
outgoing argument list in addition to the requested
space, but there is no way to ask for stack space such
that an argument list of a certain length can be
- safely constructed. */
+ safely constructed.
- int adjust = OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl));
-#ifdef REG_PARM_STACK_SPACE
- /* Add the stack space reserved for register arguments
- in the inline function. What is really needed is the
+ Add the stack space reserved for register arguments, if
+ any, in the inline function. What is really needed is the
largest value of reg_parm_stack_space in the inline
function, but that is not available. Using the current
value of reg_parm_stack_space is wrong, but gives
correct results on all supported machines. */
- adjust += reg_parm_stack_space;
-#endif
+
+ int adjust = (OUTGOING_ARGS_SIZE (DECL_SAVED_INSNS (fndecl))
+ + reg_parm_stack_space);
+
start_sequence ();
emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
allocate_dynamic_stack_space (GEN_INT (adjust),
NULL_RTX, BITS_PER_UNIT);
seq = get_insns ();
end_sequence ();
- emit_insns_before (seq, NEXT_INSN (before_call));
+ emit_insns_before (seq, first_insn);
emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
}
}
@@ -798,7 +810,7 @@ expand_call (exp, target, ignore)
separately after all. If function was declared inline,
give a warning. */
if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline
- && ! TREE_ADDRESSABLE (fndecl))
+ && optimize > 0 && ! TREE_ADDRESSABLE (fndecl))
{
warning_with_decl (fndecl, "inlining failed in call to `%s'");
warning ("called from here");
@@ -816,29 +828,20 @@ expand_call (exp, target, ignore)
if (fndecl && DECL_NAME (fndecl))
name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
- /* On some machines (such as the PA) indirect calls have a different
- calling convention than normal calls. FUNCTION_ARG in the target
- description can look at current_call_is_indirect to determine which
- calling convention to use. */
- current_call_is_indirect = (fndecl == 0);
-#if 0
- = TREE_CODE (TREE_OPERAND (exp, 0)) == NON_LVALUE_EXPR ? 1 : 0;
-#endif
-
#if 0
/* Unless it's a call to a specific function that isn't alloca,
if it has one argument, we must assume it might be alloca. */
- may_be_alloca =
- (!(fndecl != 0 && strcmp (name, "alloca"))
- && actparms != 0
- && TREE_CHAIN (actparms) == 0);
+ may_be_alloca
+ = (!(fndecl != 0 && strcmp (name, "alloca"))
+ && actparms != 0
+ && TREE_CHAIN (actparms) == 0);
#else
/* We assume that alloca will always be called by name. It
makes no sense to pass it as a pointer-to-function to
anything that does not understand its behavior. */
- may_be_alloca =
- (name && ((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6
+ may_be_alloca
+ = (name && ((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6
&& name[0] == 'a'
&& ! strcmp (name, "alloca"))
|| (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16
@@ -851,8 +854,13 @@ expand_call (exp, target, ignore)
returns_twice = 0;
is_longjmp = 0;
+ is_malloc = 0;
- if (name != 0 && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 15)
+ if (name != 0 && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17
+ /* Exclude functions not at the file scope, or not `extern',
+ since they are not the magic functions we would otherwise
+ think they are. */
+ && DECL_CONTEXT (fndecl) == NULL_TREE && TREE_PUBLIC (fndecl))
{
char *tname = name;
@@ -890,6 +898,18 @@ expand_call (exp, target, ignore)
else if (tname[0] == 'l' && tname[1] == 'o'
&& ! strcmp (tname, "longjmp"))
is_longjmp = 1;
+ /* XXX should have "malloc" attribute on functions instead
+ of recognizing them by name. */
+ else if (! strcmp (tname, "malloc")
+ || ! strcmp (tname, "calloc")
+ || ! strcmp (tname, "realloc")
+ /* Note use of NAME rather than TNAME here. These functions
+ are only reserved when preceded with __. */
+ || ! strcmp (name, "__vn") /* mangled __builtin_vec_new */
+ || ! strcmp (name, "__nw") /* mangled __builtin_new */
+ || ! strcmp (name, "__builtin_new")
+ || ! strcmp (name, "__builtin_vec_new"))
+ is_malloc = 1;
}
if (may_be_alloca)
@@ -913,8 +933,13 @@ expand_call (exp, target, ignore)
we make. */
push_temp_slots ();
- /* Start updating where the next arg would go. */
- INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX);
+ /* Start updating where the next arg would go.
+
+ On some machines (such as the PA) indirect calls have a different
+ calling convention than normal calls. The last argument in
+ INIT_CUMULATIVE_ARGS tells the backend if this is an indirect call
+ or not. */
+ INIT_CUMULATIVE_ARGS (args_so_far, funtype, NULL_RTX, (fndecl == 0));
/* If struct_value_rtx is 0, it means pass the address
as if it were an extra parameter. */
@@ -947,11 +972,11 @@ expand_call (exp, target, ignore)
/* Compute number of named args.
Normally, don't include the last named arg if anonymous args follow.
- We do include the last named arg if STRICT_ARGUMENT_NAMING is defined.
+ We do include the last named arg if STRICT_ARGUMENT_NAMING is nonzero.
(If no anonymous args follow, the result of list_length is actually
one too large. This is harmless.)
- If SETUP_INCOMING_VARARGS is defined and STRICT_ARGUMENT_NAMING is not,
+ If SETUP_INCOMING_VARARGS is defined and STRICT_ARGUMENT_NAMING is zero,
this machine will be able to place unnamed args that were passed in
registers into the stack. So treat all args as named. This allows the
insns emitting for a specific argument list to be independent of the
@@ -960,18 +985,20 @@ expand_call (exp, target, ignore)
If SETUP_INCOMING_VARARGS is not defined, we do not have any reliable
way to pass unnamed args in registers, so we must force them into
memory. */
-#if !defined(SETUP_INCOMING_VARARGS) || defined(STRICT_ARGUMENT_NAMING)
- if (TYPE_ARG_TYPES (funtype) != 0)
+
+ if ((STRICT_ARGUMENT_NAMING
+#ifndef SETUP_INCOMING_VARARGS
+ || 1
+#endif
+ )
+ && TYPE_ARG_TYPES (funtype) != 0)
n_named_args
= (list_length (TYPE_ARG_TYPES (funtype))
-#ifndef STRICT_ARGUMENT_NAMING
/* Don't include the last named arg. */
- - 1
-#endif
+ - (STRICT_ARGUMENT_NAMING ? 0 : 1)
/* Count the struct value address, if it is passed as a parm. */
+ structure_value_addr_parm);
else
-#endif
/* If we know nothing, treat all args as named. */
n_named_args = num_actuals;
@@ -1037,14 +1064,19 @@ expand_call (exp, target, ignore)
#endif
)
{
+ /* If we're compiling a thunk, pass through invisible
+ references instead of making a copy. */
+ if (current_function_is_thunk
#ifdef FUNCTION_ARG_CALLEE_COPIES
- if (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type), type,
- argpos < n_named_args)
- /* If it's in a register, we must make a copy of it too. */
- /* ??? Is this a sufficient test? Is there a better one? */
- && !(TREE_CODE (args[i].tree_value) == VAR_DECL
- && REG_P (DECL_RTL (args[i].tree_value)))
- && ! TREE_ADDRESSABLE (type))
+ || (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type),
+ type, argpos < n_named_args)
+ /* If it's in a register, we must make a copy of it too. */
+ /* ??? Is this a sufficient test? Is there a better one? */
+ && !(TREE_CODE (args[i].tree_value) == VAR_DECL
+ && REG_P (DECL_RTL (args[i].tree_value)))
+ && ! TREE_ADDRESSABLE (type))
+#endif
+ )
{
args[i].tree_value = build1 (ADDR_EXPR,
build_pointer_type (type),
@@ -1052,14 +1084,17 @@ expand_call (exp, target, ignore)
type = build_pointer_type (type);
}
else
-#endif
{
/* We make a copy of the object and pass the address to the
function being called. */
rtx copy;
if (TYPE_SIZE (type) == 0
- || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
+ || (flag_stack_check && ! STACK_CHECK_BUILTIN
+ && (TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0
+ || (TREE_INT_CST_LOW (TYPE_SIZE (type))
+ > STACK_CHECK_MAX_VAR_SIZE * BITS_PER_UNIT))))
{
/* This is a variable-sized object. Make space on the stack
for it. */
@@ -1072,10 +1107,10 @@ expand_call (exp, target, ignore)
pending_stack_adjust = 0;
}
- copy = gen_rtx (MEM, BLKmode,
- allocate_dynamic_stack_space (size_rtx,
- NULL_RTX,
- TYPE_ALIGN (type)));
+ copy = gen_rtx_MEM (BLKmode,
+ allocate_dynamic_stack_space (size_rtx,
+ NULL_RTX,
+ TYPE_ALIGN (type)));
}
else
{
@@ -1086,6 +1121,7 @@ expand_call (exp, target, ignore)
MEM_IN_STRUCT_P (copy) = AGGREGATE_TYPE_P (type);
store_expr (args[i].tree_value, copy, 0);
+ is_const = 0;
args[i].tree_value = build1 (ADDR_EXPR,
build_pointer_type (type),
@@ -1114,12 +1150,12 @@ expand_call (exp, target, ignore)
args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type);
- /* If FUNCTION_ARG returned an (expr_list (nil) FOO), it means that
- we are to pass this arg in the register(s) designated by FOO, but
- also to pass it in the stack. */
- if (args[i].reg && GET_CODE (args[i].reg) == EXPR_LIST
- && XEXP (args[i].reg, 0) == 0)
- args[i].pass_on_stack = 1, args[i].reg = XEXP (args[i].reg, 1);
+ /* If FUNCTION_ARG returned a (parallel [(expr_list (nil) ...) ...]),
+ it means that we are to pass this arg in the register(s) designated
+ by the PARALLEL, but also to pass it in the stack. */
+ if (args[i].reg && GET_CODE (args[i].reg) == PARALLEL
+ && XEXP (XVECEXP (args[i].reg, 0, 0), 0) == 0)
+ args[i].pass_on_stack = 1;
/* If this is an addressable type, we must preallocate the stack
since we must evaluate the object into its final location.
@@ -1137,9 +1173,7 @@ expand_call (exp, target, ignore)
/* Compute the stack-size of this argument. */
if (args[i].reg == 0 || args[i].partial != 0
-#ifdef REG_PARM_STACK_SPACE
|| reg_parm_stack_space > 0
-#endif
|| args[i].pass_on_stack)
locate_and_pad_parm (mode, type,
#ifdef STACK_PARMS_IN_REG_PARM_AREA
@@ -1154,14 +1188,12 @@ expand_call (exp, target, ignore)
args[i].slot_offset = args_size;
#endif
-#ifndef REG_PARM_STACK_SPACE
/* If a part of the arg was put into registers,
don't include that part in the amount pushed. */
- if (! args[i].pass_on_stack)
+ if (reg_parm_stack_space == 0 && ! args[i].pass_on_stack)
args[i].size.constant -= ((args[i].partial * UNITS_PER_WORD)
/ (PARM_BOUNDARY / BITS_PER_UNIT)
* (PARM_BOUNDARY / BITS_PER_UNIT));
-#endif
/* Update ARGS_SIZE, the total stack space for args so far. */
@@ -1218,12 +1250,11 @@ expand_call (exp, target, ignore)
args_size.var = round_up (args_size.var, STACK_BYTES);
#endif
-#ifdef REG_PARM_STACK_SPACE
if (reg_parm_stack_space > 0)
{
args_size.var
= size_binop (MAX_EXPR, args_size.var,
- size_int (REG_PARM_STACK_SPACE (fndecl)));
+ size_int (reg_parm_stack_space));
#ifndef OUTGOING_REG_PARM_STACK_SPACE
/* The area corresponding to register parameters is not to count in
@@ -1233,7 +1264,6 @@ expand_call (exp, target, ignore)
size_int (reg_parm_stack_space));
#endif
}
-#endif
}
else
{
@@ -1242,17 +1272,17 @@ expand_call (exp, target, ignore)
/ STACK_BYTES) * STACK_BYTES);
#endif
-#ifdef REG_PARM_STACK_SPACE
args_size.constant = MAX (args_size.constant,
reg_parm_stack_space);
+
#ifdef MAYBE_REG_PARM_STACK_SPACE
if (reg_parm_stack_space == 0)
args_size.constant = 0;
#endif
+
#ifndef OUTGOING_REG_PARM_STACK_SPACE
args_size.constant -= reg_parm_stack_space;
#endif
-#endif
}
/* See if we have or want to preallocate stack space.
@@ -1362,7 +1392,7 @@ expand_call (exp, target, ignore)
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
- if (is_const)
+ if (is_const || is_malloc)
start_sequence ();
/* If we have no actual push instructions, or shouldn't use them,
@@ -1394,8 +1424,9 @@ expand_call (exp, target, ignore)
int needed = args_size.constant;
- /* Store the maximum argument space used. It will be pushed by the
- prologue (if ACCUMULATE_OUTGOING_ARGS, or stack overflow checking). */
+ /* Store the maximum argument space used. It will be pushed by
+ the prologue (if ACCUMULATE_OUTGOING_ARGS, or stack overflow
+ checking). */
if (needed > current_function_outgoing_args_size)
current_function_outgoing_args_size = needed;
@@ -1416,7 +1447,7 @@ expand_call (exp, target, ignore)
Another approach might be to try to reorder the argument
evaluations to avoid this conflicting stack usage. */
-#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
/* Since we will be writing into the entire argument area, the
map must be allocated for its entire size, not just the part that
is the responsibility of the caller. */
@@ -1488,7 +1519,7 @@ expand_call (exp, target, ignore)
to initialize an argument. */
if (stack_arg_under_construction)
{
-#if defined(REG_PARM_STACK_SPACE) && ! defined(OUTGOING_REG_PARM_STACK_SPACE)
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
rtx push_size = GEN_INT (reg_parm_stack_space + args_size.constant);
#else
rtx push_size = GEN_INT (args_size.constant);
@@ -1545,20 +1576,20 @@ expand_call (exp, target, ignore)
if (GET_CODE (offset) == CONST_INT)
addr = plus_constant (arg_reg, INTVAL (offset));
else
- addr = gen_rtx (PLUS, Pmode, arg_reg, offset);
+ addr = gen_rtx_PLUS (Pmode, arg_reg, offset);
addr = plus_constant (addr, arg_offset);
- args[i].stack = gen_rtx (MEM, args[i].mode, addr);
+ args[i].stack = gen_rtx_MEM (args[i].mode, addr);
MEM_IN_STRUCT_P (args[i].stack)
= AGGREGATE_TYPE_P (TREE_TYPE (args[i].tree_value));
if (GET_CODE (slot_offset) == CONST_INT)
addr = plus_constant (arg_reg, INTVAL (slot_offset));
else
- addr = gen_rtx (PLUS, Pmode, arg_reg, slot_offset);
+ addr = gen_rtx_PLUS (Pmode, arg_reg, slot_offset);
addr = plus_constant (addr, arg_offset);
- args[i].stack_slot = gen_rtx (MEM, args[i].mode, addr);
+ args[i].stack_slot = gen_rtx_MEM (args[i].mode, addr);
}
}
@@ -1597,6 +1628,12 @@ expand_call (exp, target, ignore)
push_temp_slots ();
funexp = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0);
pop_temp_slots (); /* FUNEXP can't be BLKmode */
+
+ /* Check the function is executable. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_check_exec_libfunc, 1,
+ VOIDmode, 1,
+ funexp, ptr_mode);
emit_queue ();
}
@@ -1613,7 +1650,7 @@ expand_call (exp, target, ignore)
}
/* Precompute all register parameters. It isn't safe to compute anything
- once we have started filling any specific hard regs. */
+ once we have started filling any specific hard regs. */
reg_parm_seen = 0;
for (i = 0; i < num_actuals; i++)
if (args[i].reg != 0 && ! args[i].pass_on_stack)
@@ -1655,16 +1692,13 @@ expand_call (exp, target, ignore)
&& GET_CODE (SUBREG_REG (args[i].value)) == REG)))
&& args[i].mode != BLKmode
&& rtx_cost (args[i].value, SET) > 2
-#ifdef SMALL_REGISTER_CLASSES
- && (reg_parm_seen || preserve_subexpressions_p ())
-#else
- && preserve_subexpressions_p ()
-#endif
- )
+ && ((SMALL_REGISTER_CLASSES && reg_parm_seen)
+ || preserve_subexpressions_p ()))
args[i].value = copy_to_mode_reg (args[i].mode, args[i].value);
}
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+
/* The argument list is the property of the called routine and it
may clobber it. If the fixed area has been used for previous
parameters, we must save and restore it.
@@ -1699,17 +1733,17 @@ expand_call (exp, target, ignore)
BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1)))
save_mode = BLKmode;
- stack_area = gen_rtx (MEM, save_mode,
- memory_address (save_mode,
-
#ifdef ARGS_GROW_DOWNWARD
- plus_constant (argblock,
- - high_to_save)
+ stack_area = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ - high_to_save)));
#else
- plus_constant (argblock,
- low_to_save)
+ stack_area = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ low_to_save)));
#endif
- ));
if (save_mode == BLKmode)
{
save_area = assign_stack_temp (BLKmode, num_to_save, 0);
@@ -1738,68 +1772,73 @@ expand_call (exp, target, ignore)
store_one_arg (&args[i], argblock, may_be_alloca,
args_size.var != 0, fndecl, reg_parm_stack_space);
-#ifdef STRICT_ALIGNMENT
/* If we have a parm that is passed in registers but not in memory
and whose alignment does not permit a direct copy into registers,
make a group of pseudos that correspond to each register that we
will later fill. */
- for (i = 0; i < num_actuals; i++)
- if (args[i].reg != 0 && ! args[i].pass_on_stack
+ if (STRICT_ALIGNMENT)
+ for (i = 0; i < num_actuals; i++)
+ if (args[i].reg != 0 && ! args[i].pass_on_stack
&& args[i].mode == BLKmode
- && (TYPE_ALIGN (TREE_TYPE (args[i].tree_value))
- < MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD)))
- {
- int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value));
- int big_endian_correction = 0;
+ && (TYPE_ALIGN (TREE_TYPE (args[i].tree_value))
+ < MIN (BIGGEST_ALIGNMENT, BITS_PER_WORD)))
+ {
+ int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value));
+ int big_endian_correction = 0;
- args[i].n_aligned_regs
- = args[i].partial ? args[i].partial
- : (bytes + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
+ args[i].n_aligned_regs
+ = args[i].partial ? args[i].partial
+ : (bytes + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
- args[i].aligned_regs = (rtx *) alloca (sizeof (rtx)
- * args[i].n_aligned_regs);
+ args[i].aligned_regs = (rtx *) alloca (sizeof (rtx)
+ * args[i].n_aligned_regs);
- /* Structures smaller than a word are aligned to the least significant
- byte (to the right). On a BYTES_BIG_ENDIAN machine, this means we
- must skip the empty high order bytes when calculating the bit
- offset. */
- if (BYTES_BIG_ENDIAN && bytes < UNITS_PER_WORD)
- big_endian_correction = (BITS_PER_WORD - (bytes * BITS_PER_UNIT));
+ /* Structures smaller than a word are aligned to the least
+ significant byte (to the right). On a BYTES_BIG_ENDIAN machine,
+ this means we must skip the empty high order bytes when
+ calculating the bit offset. */
+ if (BYTES_BIG_ENDIAN && bytes < UNITS_PER_WORD)
+ big_endian_correction = (BITS_PER_WORD - (bytes * BITS_PER_UNIT));
- for (j = 0; j < args[i].n_aligned_regs; j++)
- {
- rtx reg = gen_reg_rtx (word_mode);
- rtx word = operand_subword_force (args[i].value, j, BLKmode);
- int bitsize = TYPE_ALIGN (TREE_TYPE (args[i].tree_value));
- int bitpos;
-
- args[i].aligned_regs[j] = reg;
-
- /* Clobber REG and move each partword into it. Ensure we don't
- go past the end of the structure. Note that the loop below
- works because we've already verified that padding
- and endianness are compatible. */
-
- emit_insn (gen_rtx (CLOBBER, VOIDmode, reg));
-
- for (bitpos = 0;
- bitpos < BITS_PER_WORD && bytes > 0;
- bitpos += bitsize, bytes -= bitsize / BITS_PER_UNIT)
- {
- int xbitpos = bitpos + big_endian_correction;
-
- store_bit_field (reg, bitsize, xbitpos, word_mode,
- extract_bit_field (word, bitsize, bitpos, 1,
- NULL_RTX, word_mode,
- word_mode,
- bitsize / BITS_PER_UNIT,
- BITS_PER_WORD),
- bitsize / BITS_PER_UNIT, BITS_PER_WORD);
- }
- }
- }
-#endif
+ for (j = 0; j < args[i].n_aligned_regs; j++)
+ {
+ rtx reg = gen_reg_rtx (word_mode);
+ rtx word = operand_subword_force (args[i].value, j, BLKmode);
+ int bitsize = TYPE_ALIGN (TREE_TYPE (args[i].tree_value));
+ int bitpos;
+
+ args[i].aligned_regs[j] = reg;
+
+ /* Clobber REG and move each partword into it. Ensure we don't
+ go past the end of the structure. Note that the loop below
+ works because we've already verified that padding
+ and endianness are compatible.
+
+ We use to emit a clobber here but that doesn't let later
+ passes optimize the instructions we emit. By storing 0 into
+ the register later passes know the first AND to zero out the
+ bitfield being set in the register is unnecessary. The store
+ of 0 will be deleted as will at least the first AND. */
+
+ emit_move_insn (reg, const0_rtx);
+
+ for (bitpos = 0;
+ bitpos < BITS_PER_WORD && bytes > 0;
+ bitpos += bitsize, bytes -= bitsize / BITS_PER_UNIT)
+ {
+ int xbitpos = bitpos + big_endian_correction;
+
+ store_bit_field (reg, bitsize, xbitpos, word_mode,
+ extract_bit_field (word, bitsize, bitpos, 1,
+ NULL_RTX, word_mode,
+ word_mode,
+ bitsize / BITS_PER_UNIT,
+ BITS_PER_WORD),
+ bitsize / BITS_PER_UNIT, BITS_PER_WORD);
+ }
+ }
+ }
/* Now store any partially-in-registers parm.
This is the last place a block-move can happen. */
@@ -1834,6 +1873,16 @@ expand_call (exp, target, ignore)
force_reg (Pmode,
force_operand (structure_value_addr,
NULL_RTX)));
+
+ /* Mark the memory for the aggregate as write-only. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_set_right_libfunc, 1,
+ VOIDmode, 3,
+ structure_value_addr, ptr_mode,
+ GEN_INT (struct_value_size), TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_WO),
+ TYPE_MODE (integer_type_node));
+
if (GET_CODE (struct_value_rtx) == REG)
use_reg (&call_fusage, struct_value_rtx);
}
@@ -1847,22 +1896,18 @@ expand_call (exp, target, ignore)
Mark all register-parms as living through the call, putting these USE
insns in the CALL_INSN_FUNCTION_USAGE field. */
+#ifdef LOAD_ARGS_REVERSED
+ for (i = num_actuals - 1; i >= 0; i--)
+#else
for (i = 0; i < num_actuals; i++)
+#endif
{
- rtx list = args[i].reg;
+ rtx reg = args[i].reg;
int partial = args[i].partial;
+ int nregs;
- while (list)
+ if (reg)
{
- rtx reg;
- int nregs;
-
- /* Process each register that needs to get this arg. */
- if (GET_CODE (list) == EXPR_LIST)
- reg = XEXP (list, 0), list = XEXP (list, 1);
- else
- reg = list, list = 0;
-
/* Set to non-negative if must move a word at a time, even if just
one word (e.g, partial == 1 && mode == DFmode). Set to -1 if
we just use a normal move insn. This value can be zero if the
@@ -1873,36 +1918,45 @@ expand_call (exp, target, ignore)
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
: -1));
+ /* Handle calls that pass values in multiple non-contiguous
+ locations. The Irix 6 ABI has examples of this. */
+
+ if (GET_CODE (reg) == PARALLEL)
+ {
+ emit_group_load (reg, args[i].value,
+ int_size_in_bytes (TREE_TYPE (args[i].tree_value)),
+ (TYPE_ALIGN (TREE_TYPE (args[i].tree_value))
+ / BITS_PER_UNIT));
+ }
+
/* If simple case, just do move. If normal partial, store_one_arg
has already loaded the register for us. In all other cases,
load the register(s) from memory. */
- if (nregs == -1)
+ else if (nregs == -1)
emit_move_insn (reg, args[i].value);
-#ifdef STRICT_ALIGNMENT
/* If we have pre-computed the values to put in the registers in
the case of non-aligned structures, copy them in now. */
else if (args[i].n_aligned_regs != 0)
for (j = 0; j < args[i].n_aligned_regs; j++)
- emit_move_insn (gen_rtx (REG, word_mode, REGNO (reg) + j),
+ emit_move_insn (gen_rtx_REG (word_mode, REGNO (reg) + j),
args[i].aligned_regs[j]);
-#endif
- else if (args[i].partial == 0 || args[i].pass_on_stack)
+ else if (partial == 0 || args[i].pass_on_stack)
move_block_to_reg (REGNO (reg),
validize_mem (args[i].value), nregs,
args[i].mode);
- if (nregs == -1)
+ /* Handle calls that pass values in multiple non-contiguous
+ locations. The Irix 6 ABI has examples of this. */
+ if (GET_CODE (reg) == PARALLEL)
+ use_group_regs (&call_fusage, reg);
+ else if (nregs == -1)
use_reg (&call_fusage, reg);
else
use_regs (&call_fusage, REGNO (reg), nregs == 0 ? 1 : nregs);
-
- /* PARTIAL referred only to the first register, so clear it for the
- next time. */
- partial = 0;
}
}
@@ -1918,23 +1972,31 @@ expand_call (exp, target, ignore)
/* If call is cse'able, make appropriate pair of reg-notes around it.
Test valreg so we don't crash; may safely ignore `const'
- if return type is void. */
- if (is_const && valreg != 0)
+ if return type is void. Disable for PARALLEL return values, because
+ we have no way to move such values into a pseudo register. */
+ if (is_const && valreg != 0 && GET_CODE (valreg) != PARALLEL)
{
rtx note = 0;
rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx insns;
+ /* Mark the return value as a pointer if needed. */
+ if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
+ {
+ tree pointed_to = TREE_TYPE (TREE_TYPE (exp));
+ mark_reg_pointer (temp, TYPE_ALIGN (pointed_to) / BITS_PER_UNIT);
+ }
+
/* Construct an "equal form" for the value which mentions all the
arguments in order as well as the function name. */
#ifdef PUSH_ARGS_REVERSED
for (i = 0; i < num_actuals; i++)
- note = gen_rtx (EXPR_LIST, VOIDmode, args[i].initial_value, note);
+ note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note);
#else
for (i = num_actuals - 1; i >= 0; i--)
- note = gen_rtx (EXPR_LIST, VOIDmode, args[i].initial_value, note);
+ note = gen_rtx_EXPR_LIST (VOIDmode, args[i].initial_value, note);
#endif
- note = gen_rtx (EXPR_LIST, VOIDmode, funexp, note);
+ note = gen_rtx_EXPR_LIST (VOIDmode, funexp, note);
insns = get_insns ();
end_sequence ();
@@ -1951,6 +2013,29 @@ expand_call (exp, target, ignore)
end_sequence ();
emit_insns (insns);
}
+ else if (is_malloc)
+ {
+ rtx temp = gen_reg_rtx (GET_MODE (valreg));
+ rtx last, insns;
+
+ /* The return value from a malloc-like function is a pointer. */
+ if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
+ mark_reg_pointer (temp, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+
+ emit_move_insn (temp, valreg);
+
+ /* The return value from a malloc-like function can not alias
+ anything else. */
+ last = get_last_insn ();
+ REG_NOTES (last) =
+ gen_rtx_EXPR_LIST (REG_NOALIAS, temp, REG_NOTES (last));
+
+ /* Write out the sequence. */
+ insns = get_insns ();
+ end_sequence ();
+ emit_insns (insns);
+ valreg = temp;
+ }
/* For calls to `setjmp', etc., inform flow.c it should complain
if nonvolatile values are live. */
@@ -1974,8 +2059,9 @@ expand_call (exp, target, ignore)
/* If value type not void, return an rtx for the value. */
- /* If there are cleanups to be called, don't use a hard reg as target. */
- if (cleanups_this_call != old_cleanups
+ /* If there are cleanups to be called, don't use a hard reg as target.
+ We need to double check this and see if it matters anymore. */
+ if (any_pending_cleanups (1)
&& target && REG_P (target)
&& REGNO (target) < FIRST_PSEUDO_REGISTER)
target = 0;
@@ -1989,44 +2075,36 @@ expand_call (exp, target, ignore)
{
if (target == 0 || GET_CODE (target) != MEM)
{
- target = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
- memory_address (TYPE_MODE (TREE_TYPE (exp)),
- structure_value_addr));
+ target = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
+ memory_address (TYPE_MODE (TREE_TYPE (exp)),
+ structure_value_addr));
MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (TREE_TYPE (exp));
}
}
else if (pcc_struct_value)
{
+ /* This is the special C++ case where we need to
+ know what the true target was. We take care to
+ never use this value more than once in one expression. */
+ target = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)),
+ copy_to_reg (valreg));
+ MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (TREE_TYPE (exp));
+ }
+ /* Handle calls that return values in multiple non-contiguous locations.
+ The Irix 6 ABI has examples of this. */
+ else if (GET_CODE (valreg) == PARALLEL)
+ {
+ int bytes = int_size_in_bytes (TREE_TYPE (exp));
+
if (target == 0)
{
- /* We used leave the value in the location that it is
- returned in, but that causes problems if it is used more
- than once in one expression. Rather than trying to track
- when a copy is required, we always copy when TARGET is
- not specified. This calling sequence is only used on
- a few machines and TARGET is usually nonzero. */
- if (TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
- {
- target = assign_stack_temp (BLKmode,
- int_size_in_bytes (TREE_TYPE (exp)),
- 0);
-
- MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (TREE_TYPE (exp));
-
- /* Save this temp slot around the pop below. */
- preserve_temp_slots (target);
- }
- else
- target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
+ target = assign_stack_temp (TYPE_MODE (TREE_TYPE (exp)), bytes, 0);
+ MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (TREE_TYPE (exp));
+ preserve_temp_slots (target);
}
- if (TYPE_MODE (TREE_TYPE (exp)) != BLKmode)
- emit_move_insn (target, gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)),
- copy_to_reg (valreg)));
- else
- emit_block_move (target, gen_rtx (MEM, BLKmode, copy_to_reg (valreg)),
- expr_size (exp),
- TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
+ emit_group_store (target, valreg, bytes,
+ TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
}
else if (target && GET_MODE (target) == TYPE_MODE (TREE_TYPE (exp))
&& GET_MODE (target) == GET_MODE (valreg))
@@ -2045,10 +2123,7 @@ expand_call (exp, target, ignore)
Deal with them explicitly by copying from the return registers
into the target MEM locations. */
int bytes = int_size_in_bytes (TREE_TYPE (exp));
- int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
- int i;
- enum machine_mode tmpmode;
- rtx src, dst;
+ rtx src = NULL, dst = NULL;
int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (exp)), BITS_PER_WORD);
int bitpos, xbitpos, big_endian_correction = 0;
@@ -2063,7 +2138,7 @@ expand_call (exp, target, ignore)
copy it into a new pseudo which is a full word. */
if (GET_MODE (valreg) != BLKmode
&& GET_MODE_SIZE (GET_MODE (valreg)) < UNITS_PER_WORD)
- valreg = convert_to_mode (SImode, valreg,
+ valreg = convert_to_mode (word_mode, valreg,
TREE_UNSIGNED (TREE_TYPE (exp)));
/* Structures whose size is not a multiple of a word are aligned
@@ -2128,19 +2203,12 @@ expand_call (exp, target, ignore)
!= promote_mode (type, TYPE_MODE (type), &unsignedp, 1))
abort ();
- target = gen_rtx (SUBREG, TYPE_MODE (type), target, 0);
+ target = gen_rtx_SUBREG (TYPE_MODE (type), target, 0);
SUBREG_PROMOTED_VAR_P (target) = 1;
SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp;
}
#endif
- if (flag_short_temps)
- {
- /* Perform all cleanups needed for the arguments of this call
- (i.e. destructors in C++). */
- expand_cleanups_to (old_cleanups);
- }
-
/* If size of args is variable or this was a constructor call for a stack
argument, restore saved stack-pointer value. */
@@ -2161,15 +2229,19 @@ expand_call (exp, target, ignore)
if (save_area)
{
enum machine_mode save_mode = GET_MODE (save_area);
- rtx stack_area
- = gen_rtx (MEM, save_mode,
- memory_address (save_mode,
#ifdef ARGS_GROW_DOWNWARD
- plus_constant (argblock, - high_to_save)
+ rtx stack_area
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ - high_to_save)));
#else
- plus_constant (argblock, low_to_save)
+ rtx stack_area
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ low_to_save)));
#endif
- ));
if (save_mode != BLKmode)
emit_move_insn (stack_area, save_area);
@@ -2186,9 +2258,9 @@ expand_call (exp, target, ignore)
{
enum machine_mode save_mode = GET_MODE (args[i].save_area);
rtx stack_area
- = gen_rtx (MEM, save_mode,
- memory_address (save_mode,
- XEXP (args[i].stack_slot, 0)));
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ XEXP (args[i].stack_slot, 0)));
if (save_mode != BLKmode)
emit_move_insn (stack_area, args[i].save_area);
@@ -2205,7 +2277,7 @@ expand_call (exp, target, ignore)
/* If this was alloca, record the new stack level for nonlocal gotos.
Check for the handler slots since we might not have a save area
- for non-local gotos. */
+ for non-local gotos. */
if (may_be_alloca && nonlocal_goto_handler_slot != 0)
emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
@@ -2257,12 +2329,32 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
rtx argblock = 0;
CUMULATIVE_ARGS args_so_far;
struct arg { rtx value; enum machine_mode mode; rtx reg; int partial;
- struct args_size offset; struct args_size size; };
+ struct args_size offset; struct args_size size; rtx save_area; };
struct arg *argvec;
int old_inhibit_defer_pop = inhibit_defer_pop;
rtx call_fusage = 0;
- /* library calls are never indirect calls. */
- int current_call_is_indirect = 0;
+ int reg_parm_stack_space = 0;
+#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+ /* Define the boundary of the register parm stack space that needs to be
+ save, if any. */
+ int low_to_save = -1, high_to_save;
+ rtx save_area = 0; /* Place that it is saved */
+#endif
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ int initial_highest_arg_in_use = highest_outgoing_arg_in_use;
+ char *initial_stack_usage_map = stack_usage_map;
+ int needed;
+#endif
+
+#ifdef REG_PARM_STACK_SPACE
+ /* Size of the stack reserved for parameter registers. */
+#ifdef MAYBE_REG_PARM_STACK_SPACE
+ reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
+#else
+ reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
+#endif
+#endif
VA_START (p, nargs);
@@ -2283,8 +2375,10 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
library functions shouldn't have many args. */
argvec = (struct arg *) alloca (nargs * sizeof (struct arg));
+ bzero ((char *) argvec, nargs * sizeof (struct arg));
+
- INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun);
+ INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0);
args_size.constant = 0;
args_size.var = 0;
@@ -2333,7 +2427,7 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
argvec[count].mode = mode;
argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
- if (argvec[count].reg && GET_CODE (argvec[count].reg) == EXPR_LIST)
+ if (argvec[count].reg && GET_CODE (argvec[count].reg) == PARALLEL)
abort ();
#ifdef FUNCTION_ARG_PARTIAL_NREGS
argvec[count].partial
@@ -2350,35 +2444,22 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
if (argvec[count].size.var)
abort ();
-#ifndef REG_PARM_STACK_SPACE
- if (argvec[count].partial)
+ if (reg_parm_stack_space == 0 && argvec[count].partial)
argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD;
-#endif
if (argvec[count].reg == 0 || argvec[count].partial != 0
-#ifdef REG_PARM_STACK_SPACE
- || 1
-#endif
- )
+ || reg_parm_stack_space > 0)
args_size.constant += argvec[count].size.constant;
-#ifdef ACCUMULATE_OUTGOING_ARGS
- /* If this arg is actually passed on the stack, it might be
- clobbering something we already put there (this library call might
- be inside the evaluation of an argument to a function whose call
- requires the stack). This will only occur when the library call
- has sufficient args to run out of argument registers. Abort in
- this case; if this ever occurs, code must be added to save and
- restore the arg slot. */
-
- if (argvec[count].reg == 0 || argvec[count].partial != 0)
- abort ();
-#endif
-
- FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1);
+ FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1);
}
va_end (p);
+#ifdef FINAL_REG_PARM_STACK_SPACE
+ reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
+ args_size.var);
+#endif
+
/* If this machine requires an external definition for library
functions, write one out. */
assemble_external_libcall (fun);
@@ -2389,24 +2470,67 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
/ STACK_BYTES) * STACK_BYTES);
#endif
-#ifdef REG_PARM_STACK_SPACE
args_size.constant = MAX (args_size.constant,
- REG_PARM_STACK_SPACE (NULL_TREE));
+ reg_parm_stack_space);
+
#ifndef OUTGOING_REG_PARM_STACK_SPACE
- args_size.constant -= REG_PARM_STACK_SPACE (NULL_TREE);
-#endif
+ args_size.constant -= reg_parm_stack_space;
#endif
if (args_size.constant > current_function_outgoing_args_size)
current_function_outgoing_args_size = args_size.constant;
#ifdef ACCUMULATE_OUTGOING_ARGS
- args_size.constant = 0;
+ /* Since the stack pointer will never be pushed, it is possible for
+ the evaluation of a parm to clobber something we have already
+ written to the stack. Since most function calls on RISC machines
+ do not use the stack, this is uncommon, but must work correctly.
+
+ Therefore, we save any area of the stack that was already written
+ and that we are using. Here we set up to do this by making a new
+ stack usage map from the old one.
+
+ Another approach might be to try to reorder the argument
+ evaluations to avoid this conflicting stack usage. */
+
+ needed = args_size.constant;
+
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
+ /* Since we will be writing into the entire argument area, the
+ map must be allocated for its entire size, not just the part that
+ is the responsibility of the caller. */
+ needed += reg_parm_stack_space;
#endif
+#ifdef ARGS_GROW_DOWNWARD
+ highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+ needed + 1);
+#else
+ highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+ needed);
+#endif
+ stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);
+
+ if (initial_highest_arg_in_use)
+ bcopy (initial_stack_usage_map, stack_usage_map,
+ initial_highest_arg_in_use);
+
+ if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
+ bzero (&stack_usage_map[initial_highest_arg_in_use],
+ highest_outgoing_arg_in_use - initial_highest_arg_in_use);
+ needed = 0;
+
+ /* The address of the outgoing argument list must not be copied to a
+ register here, because argblock would be left pointing to the
+ wrong place after the call to allocate_dynamic_stack_space below.
+ */
+
+ argblock = virtual_outgoing_args_rtx;
+#else /* not ACCUMULATE_OUTGOING_ARGS */
#ifndef PUSH_ROUNDING
argblock = push_block (GEN_INT (args_size.constant), 0, 0);
#endif
+#endif
#ifdef PUSH_ARGS_REVERSED
#ifdef STACK_BOUNDARY
@@ -2426,19 +2550,131 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
argnum = 0;
#endif
+#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+ /* The argument list is the property of the called routine and it
+ may clobber it. If the fixed area has been used for previous
+ parameters, we must save and restore it.
+
+ Here we compute the boundary of the that needs to be saved, if any. */
+
+#ifdef ARGS_GROW_DOWNWARD
+ for (count = 0; count < reg_parm_stack_space + 1; count++)
+#else
+ for (count = 0; count < reg_parm_stack_space; count++)
+#endif
+ {
+ if (count >= highest_outgoing_arg_in_use
+ || stack_usage_map[count] == 0)
+ continue;
+
+ if (low_to_save == -1)
+ low_to_save = count;
+
+ high_to_save = count;
+ }
+
+ if (low_to_save >= 0)
+ {
+ int num_to_save = high_to_save - low_to_save + 1;
+ enum machine_mode save_mode
+ = mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1);
+ rtx stack_area;
+
+ /* If we don't have the required alignment, must do this in BLKmode. */
+ if ((low_to_save & (MIN (GET_MODE_SIZE (save_mode),
+ BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1)))
+ save_mode = BLKmode;
+
+#ifdef ARGS_GROW_DOWNWARD
+ stack_area = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ - high_to_save)));
+#else
+ stack_area = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ low_to_save)));
+#endif
+ if (save_mode == BLKmode)
+ {
+ save_area = assign_stack_temp (BLKmode, num_to_save, 0);
+ MEM_IN_STRUCT_P (save_area) = 0;
+ emit_block_move (validize_mem (save_area), stack_area,
+ GEN_INT (num_to_save),
+ PARM_BOUNDARY / BITS_PER_UNIT);
+ }
+ else
+ {
+ save_area = gen_reg_rtx (save_mode);
+ emit_move_insn (save_area, stack_area);
+ }
+ }
+#endif
+
/* Push the args that need to be pushed. */
+ /* ARGNUM indexes the ARGVEC array in the order in which the arguments
+ are to be pushed. */
for (count = 0; count < nargs; count++, argnum += inc)
{
register enum machine_mode mode = argvec[argnum].mode;
register rtx val = argvec[argnum].value;
rtx reg = argvec[argnum].reg;
int partial = argvec[argnum].partial;
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ int lower_bound, upper_bound, i;
+#endif
if (! (reg != 0 && partial == 0))
- emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
- argblock, GEN_INT (argvec[count].offset.constant));
- NO_DEFER_POP;
+ {
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* If this is being stored into a pre-allocated, fixed-size, stack
+ area, save any previous data at that location. */
+
+#ifdef ARGS_GROW_DOWNWARD
+ /* stack_slot is negative, but we want to index stack_usage_map
+ with positive values. */
+ upper_bound = -argvec[argnum].offset.constant + 1;
+ lower_bound = upper_bound - argvec[argnum].size.constant;
+#else
+ lower_bound = argvec[argnum].offset.constant;
+ upper_bound = lower_bound + argvec[argnum].size.constant;
+#endif
+
+ for (i = lower_bound; i < upper_bound; i++)
+ if (stack_usage_map[i]
+ /* Don't store things in the fixed argument area at this point;
+ it has already been saved. */
+ && i > reg_parm_stack_space)
+ break;
+
+ if (i != upper_bound)
+ {
+ /* We need to make a save area. See what mode we can make it. */
+ enum machine_mode save_mode
+ = mode_for_size (argvec[argnum].size.constant * BITS_PER_UNIT,
+ MODE_INT, 1);
+ rtx stack_area
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock, argvec[argnum].offset.constant)));
+ argvec[argnum].save_area = gen_reg_rtx (save_mode);
+ emit_move_insn (argvec[argnum].save_area, stack_area);
+ }
+#endif
+ emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
+ argblock, GEN_INT (argvec[argnum].offset.constant),
+ reg_parm_stack_space);
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* Now mark the segment we just used. */
+ for (i = lower_bound; i < upper_bound; i++)
+ stack_usage_map[i] = 1;
+#endif
+
+ NO_DEFER_POP;
+ }
}
#ifndef PUSH_ARGS_REVERSED
@@ -2461,9 +2697,10 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
/* Now load any reg parms into their regs. */
+ /* ARGNUM indexes the ARGVEC array in the order in which the arguments
+ are to be pushed. */
for (count = 0; count < nargs; count++, argnum += inc)
{
- register enum machine_mode mode = argvec[argnum].mode;
register rtx val = argvec[argnum].value;
rtx reg = argvec[argnum].reg;
int partial = argvec[argnum].partial;
@@ -2489,9 +2726,16 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
/* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
will set inhibit_defer_pop to that value. */
+ /* The return type is needed to decide how many bytes the function pops.
+ Signedness plays no role in that, so for simplicity, we pretend it's
+ always signed. We also assume that the list of arguments passed has
+ no impact, so we pretend it is unknown. */
+
emit_call_1 (fun,
get_identifier (XSTR (orgfun, 0)),
- get_identifier (XSTR (orgfun, 0)), args_size.constant, 0,
+ build_function_type (outmode == VOIDmode ? void_type_node
+ : type_for_mode (outmode, 0), NULL_TREE),
+ args_size.constant, 0,
FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
old_inhibit_defer_pop + 1, call_fusage, no_queue);
@@ -2500,6 +2744,50 @@ emit_library_call VPROTO((rtx orgfun, int no_queue, enum machine_mode outmode,
/* Now restore inhibit_defer_pop to its actual original value. */
OK_DEFER_POP;
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+#ifdef REG_PARM_STACK_SPACE
+ if (save_area)
+ {
+ enum machine_mode save_mode = GET_MODE (save_area);
+#ifdef ARGS_GROW_DOWNWARD
+ rtx stack_area
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ - high_to_save)));
+#else
+ rtx stack_area
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock, low_to_save)));
+#endif
+
+ if (save_mode != BLKmode)
+ emit_move_insn (stack_area, save_area);
+ else
+ emit_block_move (stack_area, validize_mem (save_area),
+ GEN_INT (high_to_save - low_to_save + 1),
+ PARM_BOUNDARY / BITS_PER_UNIT);
+ }
+#endif
+
+ /* If we saved any argument areas, restore them. */
+ for (count = 0; count < nargs; count++)
+ if (argvec[count].save_area)
+ {
+ enum machine_mode save_mode = GET_MODE (argvec[count].save_area);
+ rtx stack_area
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock, argvec[count].offset.constant)));
+
+ emit_move_insn (stack_area, argvec[count].save_area);
+ }
+
+ highest_outgoing_arg_in_use = initial_highest_arg_in_use;
+ stack_usage_map = initial_stack_usage_map;
+#endif
}
/* Like emit_library_call except that an extra argument, VALUE,
@@ -2533,16 +2821,39 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
rtx argblock = 0;
CUMULATIVE_ARGS args_so_far;
struct arg { rtx value; enum machine_mode mode; rtx reg; int partial;
- struct args_size offset; struct args_size size; };
+ struct args_size offset; struct args_size size; rtx save_area; };
struct arg *argvec;
int old_inhibit_defer_pop = inhibit_defer_pop;
rtx call_fusage = 0;
rtx mem_value = 0;
int pcc_struct_value = 0;
int struct_value_size = 0;
- /* library calls are never indirect calls. */
- int current_call_is_indirect = 0;
int is_const;
+ int reg_parm_stack_space = 0;
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ int needed;
+#endif
+
+#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+ /* Define the boundary of the register parm stack space that needs to be
+ save, if any. */
+ int low_to_save = -1, high_to_save;
+ rtx save_area = 0; /* Place that it is saved */
+#endif
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* Size of the stack reserved for parameter registers. */
+ int initial_highest_arg_in_use = highest_outgoing_arg_in_use;
+ char *initial_stack_usage_map = stack_usage_map;
+#endif
+
+#ifdef REG_PARM_STACK_SPACE
+#ifdef MAYBE_REG_PARM_STACK_SPACE
+ reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
+#else
+ reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
+#endif
+#endif
VA_START (p, nargs);
@@ -2565,7 +2876,7 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
rtx pointer_reg
= hard_function_value (build_pointer_type (type_for_mode (outmode, 0)),
0);
- mem_value = gen_rtx (MEM, outmode, pointer_reg);
+ mem_value = gen_rtx_MEM (outmode, pointer_reg);
pcc_struct_value = 1;
if (value == 0)
value = gen_reg_rtx (outmode);
@@ -2591,8 +2902,9 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
library functions shouldn't have many args. */
argvec = (struct arg *) alloca ((nargs + 1) * sizeof (struct arg));
+ bzero ((char *) argvec, (nargs + 1) * sizeof (struct arg));
- INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun);
+ INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0);
args_size.constant = 0;
args_size.var = 0;
@@ -2630,13 +2942,10 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
if (argvec[count].reg == 0 || argvec[count].partial != 0
-#ifdef REG_PARM_STACK_SPACE
- || 1
-#endif
- )
+ || reg_parm_stack_space > 0)
args_size.constant += argvec[count].size.constant;
- FUNCTION_ARG_ADVANCE (args_so_far, Pmode, (tree)0, 1);
+ FUNCTION_ARG_ADVANCE (args_so_far, Pmode, (tree) 0, 1);
count++;
}
@@ -2683,7 +2992,7 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
argvec[count].mode = mode;
argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
- if (argvec[count].reg && GET_CODE (argvec[count].reg) == EXPR_LIST)
+ if (argvec[count].reg && GET_CODE (argvec[count].reg) == PARALLEL)
abort ();
#ifdef FUNCTION_ARG_PARTIAL_NREGS
argvec[count].partial
@@ -2700,35 +3009,21 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
if (argvec[count].size.var)
abort ();
-#ifndef REG_PARM_STACK_SPACE
- if (argvec[count].partial)
+ if (reg_parm_stack_space == 0 && argvec[count].partial)
argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD;
-#endif
if (argvec[count].reg == 0 || argvec[count].partial != 0
-#ifdef REG_PARM_STACK_SPACE
- || 1
-#endif
- )
+ || reg_parm_stack_space > 0)
args_size.constant += argvec[count].size.constant;
-#ifdef ACCUMULATE_OUTGOING_ARGS
- /* If this arg is actually passed on the stack, it might be
- clobbering something we already put there (this library call might
- be inside the evaluation of an argument to a function whose call
- requires the stack). This will only occur when the library call
- has sufficient args to run out of argument registers. Abort in
- this case; if this ever occurs, code must be added to save and
- restore the arg slot. */
-
- if (argvec[count].reg == 0 || argvec[count].partial != 0)
- abort ();
-#endif
-
- FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1);
+ FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1);
}
va_end (p);
+#ifdef FINAL_REG_PARM_STACK_SPACE
+ reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
+ args_size.var);
+#endif
/* If this machine requires an external definition for library
functions, write one out. */
assemble_external_libcall (fun);
@@ -2739,24 +3034,67 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
/ STACK_BYTES) * STACK_BYTES);
#endif
-#ifdef REG_PARM_STACK_SPACE
args_size.constant = MAX (args_size.constant,
- REG_PARM_STACK_SPACE (NULL_TREE));
+ reg_parm_stack_space);
+
#ifndef OUTGOING_REG_PARM_STACK_SPACE
- args_size.constant -= REG_PARM_STACK_SPACE (NULL_TREE);
-#endif
+ args_size.constant -= reg_parm_stack_space;
#endif
if (args_size.constant > current_function_outgoing_args_size)
current_function_outgoing_args_size = args_size.constant;
#ifdef ACCUMULATE_OUTGOING_ARGS
- args_size.constant = 0;
+ /* Since the stack pointer will never be pushed, it is possible for
+ the evaluation of a parm to clobber something we have already
+ written to the stack. Since most function calls on RISC machines
+ do not use the stack, this is uncommon, but must work correctly.
+
+ Therefore, we save any area of the stack that was already written
+ and that we are using. Here we set up to do this by making a new
+ stack usage map from the old one.
+
+ Another approach might be to try to reorder the argument
+ evaluations to avoid this conflicting stack usage. */
+
+ needed = args_size.constant;
+
+#ifndef OUTGOING_REG_PARM_STACK_SPACE
+ /* Since we will be writing into the entire argument area, the
+ map must be allocated for its entire size, not just the part that
+ is the responsibility of the caller. */
+ needed += reg_parm_stack_space;
+#endif
+
+#ifdef ARGS_GROW_DOWNWARD
+ highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+ needed + 1);
+#else
+ highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
+ needed);
#endif
+ stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);
+ if (initial_highest_arg_in_use)
+ bcopy (initial_stack_usage_map, stack_usage_map,
+ initial_highest_arg_in_use);
+
+ if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
+ bzero (&stack_usage_map[initial_highest_arg_in_use],
+ highest_outgoing_arg_in_use - initial_highest_arg_in_use);
+ needed = 0;
+
+ /* The address of the outgoing argument list must not be copied to a
+ register here, because argblock would be left pointing to the
+ wrong place after the call to allocate_dynamic_stack_space below.
+ */
+
+ argblock = virtual_outgoing_args_rtx;
+#else /* not ACCUMULATE_OUTGOING_ARGS */
#ifndef PUSH_ROUNDING
argblock = push_block (GEN_INT (args_size.constant), 0, 0);
#endif
+#endif
#ifdef PUSH_ARGS_REVERSED
#ifdef STACK_BOUNDARY
@@ -2776,19 +3114,132 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
argnum = 0;
#endif
+#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
+ /* The argument list is the property of the called routine and it
+ may clobber it. If the fixed area has been used for previous
+ parameters, we must save and restore it.
+
+ Here we compute the boundary of the that needs to be saved, if any. */
+
+#ifdef ARGS_GROW_DOWNWARD
+ for (count = 0; count < reg_parm_stack_space + 1; count++)
+#else
+ for (count = 0; count < reg_parm_stack_space; count++)
+#endif
+ {
+ if (count >= highest_outgoing_arg_in_use
+ || stack_usage_map[count] == 0)
+ continue;
+
+ if (low_to_save == -1)
+ low_to_save = count;
+
+ high_to_save = count;
+ }
+
+ if (low_to_save >= 0)
+ {
+ int num_to_save = high_to_save - low_to_save + 1;
+ enum machine_mode save_mode
+ = mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1);
+ rtx stack_area;
+
+ /* If we don't have the required alignment, must do this in BLKmode. */
+ if ((low_to_save & (MIN (GET_MODE_SIZE (save_mode),
+ BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1)))
+ save_mode = BLKmode;
+
+#ifdef ARGS_GROW_DOWNWARD
+ stack_area = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ - high_to_save)));
+#else
+ stack_area = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ low_to_save)));
+#endif
+ if (save_mode == BLKmode)
+ {
+ save_area = assign_stack_temp (BLKmode, num_to_save, 0);
+ MEM_IN_STRUCT_P (save_area) = 0;
+ emit_block_move (validize_mem (save_area), stack_area,
+ GEN_INT (num_to_save),
+ PARM_BOUNDARY / BITS_PER_UNIT);
+ }
+ else
+ {
+ save_area = gen_reg_rtx (save_mode);
+ emit_move_insn (save_area, stack_area);
+ }
+ }
+#endif
+
/* Push the args that need to be pushed. */
+ /* ARGNUM indexes the ARGVEC array in the order in which the arguments
+ are to be pushed. */
for (count = 0; count < nargs; count++, argnum += inc)
{
register enum machine_mode mode = argvec[argnum].mode;
register rtx val = argvec[argnum].value;
rtx reg = argvec[argnum].reg;
int partial = argvec[argnum].partial;
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ int lower_bound, upper_bound, i;
+#endif
if (! (reg != 0 && partial == 0))
- emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
- argblock, GEN_INT (argvec[count].offset.constant));
- NO_DEFER_POP;
+ {
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* If this is being stored into a pre-allocated, fixed-size, stack
+ area, save any previous data at that location. */
+
+#ifdef ARGS_GROW_DOWNWARD
+ /* stack_slot is negative, but we want to index stack_usage_map
+ with positive values. */
+ upper_bound = -argvec[argnum].offset.constant + 1;
+ lower_bound = upper_bound - argvec[argnum].size.constant;
+#else
+ lower_bound = argvec[argnum].offset.constant;
+ upper_bound = lower_bound + argvec[argnum].size.constant;
+#endif
+
+ for (i = lower_bound; i < upper_bound; i++)
+ if (stack_usage_map[i]
+ /* Don't store things in the fixed argument area at this point;
+ it has already been saved. */
+ && i > reg_parm_stack_space)
+ break;
+
+ if (i != upper_bound)
+ {
+ /* We need to make a save area. See what mode we can make it. */
+ enum machine_mode save_mode
+ = mode_for_size (argvec[argnum].size.constant * BITS_PER_UNIT,
+ MODE_INT, 1);
+ rtx stack_area
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ argvec[argnum].offset.constant)));
+ argvec[argnum].save_area = gen_reg_rtx (save_mode);
+ emit_move_insn (argvec[argnum].save_area, stack_area);
+ }
+#endif
+ emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
+ argblock, GEN_INT (argvec[argnum].offset.constant),
+ reg_parm_stack_space);
+
+#ifdef ACCUMULATE_OUTGOING_ARGS
+ /* Now mark the segment we just used. */
+ for (i = lower_bound; i < upper_bound; i++)
+ stack_usage_map[i] = 1;
+#endif
+
+ NO_DEFER_POP;
+ }
}
#ifndef PUSH_ARGS_REVERSED
@@ -2811,9 +3262,10 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
/* Now load any reg parms into their regs. */
+ /* ARGNUM indexes the ARGVEC array in the order in which the arguments
+ are to be pushed. */
for (count = 0; count < nargs; count++, argnum += inc)
{
- register enum machine_mode mode = argvec[argnum].mode;
register rtx val = argvec[argnum].value;
rtx reg = argvec[argnum].reg;
int partial = argvec[argnum].partial;
@@ -2851,14 +3303,15 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
/* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
will set inhibit_defer_pop to that value. */
+ /* See the comment in emit_library_call about the function type we build
+ and pass here. */
emit_call_1 (fun,
get_identifier (XSTR (orgfun, 0)),
- get_identifier (XSTR (orgfun, 0)), args_size.constant,
- struct_value_size,
+ build_function_type (type_for_mode (outmode, 0), NULL_TREE),
+ args_size.constant, struct_value_size,
FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
- (outmode != VOIDmode && mem_value == 0
- ? hard_libcall_value (outmode) : NULL_RTX),
+ mem_value == 0 ? hard_libcall_value (outmode) : NULL_RTX,
old_inhibit_defer_pop + 1, call_fusage, is_const);
/* Now restore inhibit_defer_pop to its actual original value. */
@@ -2882,6 +3335,49 @@ emit_library_call_value VPROTO((rtx orgfun, rtx value, int no_queue,
value = hard_libcall_value (outmode);
}
+#ifdef ACCUMULATE_OUTGOING_ARGS
+#ifdef REG_PARM_STACK_SPACE
+ if (save_area)
+ {
+ enum machine_mode save_mode = GET_MODE (save_area);
+#ifdef ARGS_GROW_DOWNWARD
+ rtx stack_area
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock,
+ - high_to_save)));
+#else
+ rtx stack_area
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ plus_constant (argblock, low_to_save)));
+#endif
+ if (save_mode != BLKmode)
+ emit_move_insn (stack_area, save_area);
+ else
+ emit_block_move (stack_area, validize_mem (save_area),
+ GEN_INT (high_to_save - low_to_save + 1),
+ PARM_BOUNDARY / BITS_PER_UNIT);
+ }
+#endif
+
+ /* If we saved any argument areas, restore them. */
+ for (count = 0; count < nargs; count++)
+ if (argvec[count].save_area)
+ {
+ enum machine_mode save_mode = GET_MODE (argvec[count].save_area);
+ rtx stack_area
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode, plus_constant (argblock,
+ argvec[count].offset.constant)));
+
+ emit_move_insn (stack_area, argvec[count].save_area);
+ }
+
+ highest_outgoing_arg_in_use = initial_highest_arg_in_use;
+ stack_usage_map = initial_stack_usage_map;
+#endif
+
return value;
}
@@ -2915,11 +3411,11 @@ target_for_arg (type, size, args_addr, offset)
{
/* I have no idea how to guarantee that this
will work in the presence of register parameters. */
- target = gen_rtx (PLUS, Pmode, args_addr, offset_rtx);
+ target = gen_rtx_PLUS (Pmode, args_addr, offset_rtx);
target = memory_address (QImode, target);
}
- return gen_rtx (MEM, BLKmode, target);
+ return gen_rtx_MEM (BLKmode, target);
}
#endif
@@ -2953,7 +3449,9 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
rtx reg = 0;
int partial = 0;
int used = 0;
+#ifdef ACCUMULATE_OUTGOING_ARGS
int i, lower_bound, upper_bound;
+#endif
if (TREE_CODE (pval) == ERROR_MARK)
return;
@@ -2968,12 +3466,12 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
if (argblock && ! variable_size && arg->stack)
{
#ifdef ARGS_GROW_DOWNWARD
- /* stack_slot is negative, but we want to index stack_usage_map */
- /* with positive values. */
+ /* stack_slot is negative, but we want to index stack_usage_map
+ with positive values. */
if (GET_CODE (XEXP (arg->stack_slot, 0)) == PLUS)
upper_bound = -INTVAL (XEXP (XEXP (arg->stack_slot, 0), 1)) + 1;
else
- abort ();
+ upper_bound = 0;
lower_bound = upper_bound - arg->size.constant;
#else
@@ -2987,12 +3485,9 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
for (i = lower_bound; i < upper_bound; i++)
if (stack_usage_map[i]
-#ifdef REG_PARM_STACK_SPACE
/* Don't store things in the fixed argument area at this point;
it has already been saved. */
- && i > reg_parm_stack_space
-#endif
- )
+ && i > reg_parm_stack_space)
break;
if (i != upper_bound)
@@ -3001,8 +3496,9 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
enum machine_mode save_mode
= mode_for_size (arg->size.constant * BITS_PER_UNIT, MODE_INT, 1);
rtx stack_area
- = gen_rtx (MEM, save_mode,
- memory_address (save_mode, XEXP (arg->stack_slot, 0)));
+ = gen_rtx_MEM (save_mode,
+ memory_address (save_mode,
+ XEXP (arg->stack_slot, 0)));
if (save_mode == BLKmode)
{
@@ -3034,19 +3530,11 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
this case. */
abort ();
-#ifdef STRICT_ALIGNMENT
/* If this arg needs special alignment, don't load the registers
here. */
if (arg->n_aligned_regs != 0)
reg = 0;
-#endif
- /* If this is being partially passed in a register, but multiple locations
- are specified, we assume that the one partially used is the one that is
- listed first. */
- if (reg && GET_CODE (reg) == EXPR_LIST)
- reg = XEXP (reg, 0);
-
/* If this is being passed partially in a register, we can't evaluate
it directly into its stack slot. Otherwise, we can. */
if (arg->value == 0)
@@ -3098,8 +3586,21 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
do_pending_stack_adjust ();
if (arg->value == arg->stack)
- /* If the value is already in the stack slot, we are done. */
- ;
+ {
+ /* If the value is already in the stack slot, we are done. */
+ if (flag_check_memory_usage && GET_CODE (arg->stack) == MEM)
+ {
+ if (arg->mode == BLKmode)
+ abort ();
+
+ emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ XEXP (arg->stack, 0), ptr_mode,
+ GEN_INT (GET_MODE_SIZE (arg->mode)),
+ TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_RW),
+ TYPE_MODE (integer_type_node));
+ }
+ }
else if (arg->mode != BLKmode)
{
register int size;
@@ -3132,9 +3633,9 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
/* This isn't already where we want it on the stack, so put it there.
This can either be done with push or copy insns. */
- emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX,
- 0, partial, reg, used - size,
- argblock, ARGS_SIZE_RTX (arg->offset));
+ emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, 0,
+ partial, reg, used - size, argblock,
+ ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space);
}
else
{
@@ -3166,7 +3667,8 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size, fndecl,
emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
TYPE_ALIGN (TREE_TYPE (pval)) / BITS_PER_UNIT, partial,
- reg, excess, argblock, ARGS_SIZE_RTX (arg->offset));
+ reg, excess, argblock, ARGS_SIZE_RTX (arg->offset),
+ reg_parm_stack_space);
}
diff --git a/contrib/gcc/cccp.1 b/contrib/gcc/cccp.1
index 8664c61..84eb19e 100644
--- a/contrib/gcc/cccp.1
+++ b/contrib/gcc/cccp.1
@@ -631,21 +631,14 @@ This option is available only when you call \c
.B \-$
Forbid the use of `\|\c
.B $\c
-\&\|' in identifiers. This is required for ANSI
-conformance. \c
-.B gcc\c
-\& automatically supplies this option to the
-preprocessor if you specify `\|\c
-.B \-ansi\c
-\&\|', but \c
+\&\|' in identifiers. This was formerly required for strict conformance
+to the C Standard before the standard was corrected. \c
+
+This option is available only when you call \c
+.B cpp\c
+\& directly;
.B gcc\c
-\& doesn't
-recognize the `\|\c
-.B \-$\c
-\&\|' option itself\(em\&to use it without the other
-effects of `\|\c
-.B \-ansi\c
-\&\|', you must call the preprocessor directly.
+\& will not pass it from its command line.
.SH "SEE ALSO"
.RB "`\|" Cpp "\|'"
entry in
diff --git a/contrib/gcc/cccp.c b/contrib/gcc/cccp.c
index 39f1a5a..2e87c36 100644
--- a/contrib/gcc/cccp.c
+++ b/contrib/gcc/cccp.c
@@ -1,5 +1,5 @@
/* C Compatible Compiler Preprocessor (CCCP)
- Copyright (C) 1986, 87, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1986, 87, 89, 92-97, 1998 Free Software Foundation, Inc.
Written by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
@@ -16,249 +16,77 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+Boston, MA 02111-1307, USA. */
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding! */
-
-typedef unsigned char U_CHAR;
-
-#ifdef EMACS
-#define NO_SHORTNAMES
-#include "../src/config.h"
-#ifdef open
-#undef open
-#undef read
-#undef write
-#endif /* open */
-#endif /* EMACS */
-
-/* The macro EMACS is defined when cpp is distributed as part of Emacs,
- for the sake of machines with limited C compilers. */
-#ifndef EMACS
#include "config.h"
-#endif /* not EMACS */
-
-#ifndef STANDARD_INCLUDE_DIR
-#define STANDARD_INCLUDE_DIR "/usr/include"
-#endif
-
-#ifndef LOCAL_INCLUDE_DIR
-#define LOCAL_INCLUDE_DIR "/usr/local/include"
-#endif
-
-#if 0 /* We can't get ptrdiff_t, so I arranged not to need PTR_INT_TYPE. */
#ifdef __STDC__
-#define PTR_INT_TYPE ptrdiff_t
+# include <stdarg.h>
#else
-#define PTR_INT_TYPE long
+# include <varargs.h>
#endif
-#endif /* 0 */
-#include "pcp.h"
+#define PRINTF_PROTO(ARGS, m, n) PVPROTO (ARGS) ATTRIBUTE_PRINTF(m, n)
-/* By default, colon separates directories in a path. */
-#ifndef PATH_SEPARATOR
-#define PATH_SEPARATOR ':'
-#endif
+#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2)
+#define PRINTF_PROTO_2(ARGS) PRINTF_PROTO(ARGS, 2, 3)
+#define PRINTF_PROTO_3(ARGS) PRINTF_PROTO(ARGS, 3, 4)
+#define PRINTF_PROTO_4(ARGS) PRINTF_PROTO(ARGS, 4, 5)
-#include <sys/types.h>
+#include "system.h"
#include <sys/stat.h>
-#include <ctype.h>
-#include <stdio.h>
#include <signal.h>
-/* The following symbols should be autoconfigured:
- HAVE_FCNTL_H
- HAVE_STDLIB_H
- HAVE_SYS_TIME_H
- HAVE_UNISTD_H
- STDC_HEADERS
- TIME_WITH_SYS_TIME
- In the mean time, we'll get by with approximations based
- on existing GCC configuration symbols. */
-
-#ifdef POSIX
-# ifndef HAVE_STDLIB_H
-# define HAVE_STDLIB_H 1
-# endif
-# ifndef HAVE_UNISTD_H
-# define HAVE_UNISTD_H 1
-# endif
-# ifndef STDC_HEADERS
-# define STDC_HEADERS 1
-# endif
-#endif /* defined (POSIX) */
-
-#if defined (POSIX) || (defined (USG) && !defined (VMS))
-# ifndef HAVE_FCNTL_H
-# define HAVE_FCNTL_H 1
-# endif
-#endif
-
-#ifndef RLIMIT_STACK
-# include <time.h>
-#else
-# if TIME_WITH_SYS_TIME
-# include <sys/time.h>
-# include <time.h>
-# else
-# if HAVE_SYS_TIME_H
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-# endif
+#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
-#if HAVE_FCNTL_H
-# include <fcntl.h>
-#endif
+typedef unsigned char U_CHAR;
-/* This defines "errno" properly for VMS, and gives us EACCES. */
-#include <errno.h>
+#include "gansidecl.h"
+#include "pcp.h"
-#if HAVE_STDLIB_H
-# include <stdlib.h>
-#else
-char *getenv ();
+#ifndef GET_ENVIRONMENT
+#define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ENV_VALUE = getenv (ENV_NAME)
#endif
-#if STDC_HEADERS
-# include <string.h>
-# ifndef bcmp
-# define bcmp(a, b, n) memcmp (a, b, n)
-# endif
-# ifndef bcopy
-# define bcopy(s, d, n) memcpy (d, s, n)
-# endif
-# ifndef bzero
-# define bzero(d, n) memset (d, 0, n)
-# endif
-#else /* !STDC_HEADERS */
-char *index ();
-char *rindex ();
-
-# if !defined (BSTRING) && (defined (USG) || defined (VMS))
-
-# ifndef bcmp
-# define bcmp my_bcmp
-static int
-my_bcmp (a, b, n)
- register char *a;
- register char *b;
- register unsigned n;
-{
- while (n-- > 0)
- if (*a++ != *b++)
- return 1;
-
- return 0;
-}
-# endif /* !defined (bcmp) */
-
-# ifndef bcopy
-# define bcopy my_bcopy
-static void
-my_bcopy (s, d, n)
- register char *s;
- register char *d;
- register unsigned n;
-{
- while (n-- > 0)
- *d++ = *s++;
-}
-# endif /* !defined (bcopy) */
-
-# ifndef bzero
-# define bzero my_bzero
-static void
-my_bzero (b, length)
- register char *b;
- register unsigned length;
-{
- while (length-- > 0)
- *b++ = 0;
-}
-# endif /* !defined (bzero) */
-
-# endif /* !defined (BSTRING) && (defined (USG) || defined (VMS)) */
-#endif /* ! STDC_HEADERS */
-
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6)
-# define __attribute__(x)
+#ifndef STANDARD_INCLUDE_DIR
+# define STANDARD_INCLUDE_DIR "/usr/include"
#endif
-#ifndef PROTO
-# if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-# define PROTO(ARGS) ARGS
-# else
-# define PROTO(ARGS) ()
-# endif
+/* By default, colon separates directories in a path. */
+#ifndef PATH_SEPARATOR
+# define PATH_SEPARATOR ':'
#endif
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-# include <stdarg.h>
-# define VA_START(va_list, var) va_start (va_list, var)
-# define PRINTF_ALIST(msg) char *msg, ...
-# define PRINTF_DCL(msg)
-# define PRINTF_PROTO(ARGS, m, n) PROTO (ARGS) __attribute__ ((format (printf, m, n)))
+/* By default, the suffix for object files is ".o". */
+#ifdef OBJECT_SUFFIX
+# define HAVE_OBJECT_SUFFIX
#else
-# include <varargs.h>
-# define VA_START(va_list, var) va_start (va_list)
-# define PRINTF_ALIST(msg) msg, va_alist
-# define PRINTF_DCL(msg) char *msg; va_dcl
-# define PRINTF_PROTO(ARGS, m, n) () __attribute__ ((format (printf, m, n)))
-# define vfprintf(file, msg, args) \
- { \
- char *a0 = va_arg(args, char *); \
- char *a1 = va_arg(args, char *); \
- char *a2 = va_arg(args, char *); \
- char *a3 = va_arg(args, char *); \
- fprintf (file, msg, a0, a1, a2, a3); \
- }
-#endif
-
-#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2)
-#define PRINTF_PROTO_2(ARGS) PRINTF_PROTO(ARGS, 2, 3)
-#define PRINTF_PROTO_3(ARGS) PRINTF_PROTO(ARGS, 3, 4)
-
-#if HAVE_UNISTD_H
-# include <unistd.h>
+# define OBJECT_SUFFIX ".o"
#endif
/* VMS-specific definitions */
#ifdef VMS
#include <descrip.h>
-#define O_RDONLY 0 /* Open arg for Read/Only */
-#define O_WRONLY 1 /* Open arg for Write/Only */
-#define read(fd,buf,size) VMS_read (fd,buf,size)
-#define write(fd,buf,size) VMS_write (fd,buf,size)
+#include <ssdef.h>
+#include <syidef.h>
#define open(fname,mode,prot) VMS_open (fname,mode,prot)
#define fopen(fname,mode) VMS_fopen (fname,mode)
#define freopen(fname,mode,ofile) VMS_freopen (fname,mode,ofile)
-#define strncat(dst,src,cnt) VMS_strncat (dst,src,cnt)
#define fstat(fd,stbuf) VMS_fstat (fd,stbuf)
static int VMS_fstat (), VMS_stat ();
-static char * VMS_strncat ();
-static int VMS_read ();
-static int VMS_write ();
static int VMS_open ();
-static FILE * VMS_fopen ();
-static FILE * VMS_freopen ();
-static void hack_vms_include_specification ();
-typedef struct { unsigned :16, :16, :16; } vms_ino_t;
-#define ino_t vms_ino_t
-#define INCLUDE_LEN_FUDGE 10 /* leave room for VMS syntax conversion */
-#ifdef __GNUC__
-#define BSTRING /* VMS/GCC supplies the bstring routines */
-#endif /* __GNUC__ */
+static FILE *VMS_fopen ();
+static FILE *VMS_freopen ();
+static int hack_vms_include_specification ();
+#define INO_T_EQ(a, b) (!bcmp((char *) &(a), (char *) &(b), sizeof (a)))
+#define INO_T_HASH(a) 0
+#define INCLUDE_LEN_FUDGE 12 /* leave room for VMS syntax conversion */
#endif /* VMS */
-#ifndef O_RDONLY
-#define O_RDONLY 0
+/* Windows does not natively support inodes, and neither does MSDOS. */
+#if (defined (_WIN32) && ! defined (CYGWIN32)) || defined (__MSDOS__)
+#define INO_T_EQ(a, b) 0
#endif
#undef MIN
@@ -266,18 +94,24 @@ typedef struct { unsigned :16, :16, :16; } vms_ino_t;
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
-/* Find the largest host integer type and set its size and type. */
-
-#ifndef HOST_BITS_PER_WIDE_INT
-
-#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
-#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
-#define HOST_WIDE_INT long
-#else
-#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
-#define HOST_WIDE_INT int
-#endif
+/* Find the largest host integer type and set its size and type.
+ Watch out: on some crazy hosts `long' is shorter than `int'. */
+#ifndef HOST_WIDE_INT
+# if HAVE_INTTYPES_H
+# include <inttypes.h>
+# define HOST_WIDE_INT intmax_t
+# else
+# if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT)
+# define HOST_WIDE_INT int
+# else
+# if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG || ! (defined LONG_LONG_MAX || defined LLONG_MAX))
+# define HOST_WIDE_INT long
+# else
+# define HOST_WIDE_INT long long
+# endif
+# endif
+# endif
#endif
#ifndef S_ISREG
@@ -288,22 +122,12 @@ typedef struct { unsigned :16, :16, :16; } vms_ino_t;
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
-/* Define a generic NULL if one hasn't already been defined. */
-
-#ifndef NULL
-#define NULL 0
+#ifndef INO_T_EQ
+#define INO_T_EQ(a, b) ((a) == (b))
#endif
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
-#endif
-#endif
-
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
+#ifndef INO_T_HASH
+#define INO_T_HASH(a) (a)
#endif
#ifndef INCLUDE_LEN_FUDGE
@@ -313,26 +137,9 @@ typedef struct { unsigned :16, :16, :16; } vms_ino_t;
/* External declarations. */
extern char *version_string;
-#ifndef VMS
-#ifndef HAVE_STRERROR
-extern int sys_nerr;
-#if defined(bsd4_4)
-extern const char *const sys_errlist[];
-#else
-extern char *sys_errlist[];
-#endif
-#else /* HAVE_STRERROR */
-char *strerror ();
-#endif
-#else /* VMS */
-char *strerror (int,...);
-#endif
-int parse_escape PROTO((char **));
-HOST_WIDE_INT parse_c_expression PROTO((char *));
-
-#ifndef errno
-extern int errno;
-#endif
+extern char *update_path PROTO((char *, char *));
+HOST_WIDE_INT parse_escape PROTO((char **, HOST_WIDE_INT));
+HOST_WIDE_INT parse_c_expression PROTO((char *, int));
/* Name under which this program was invoked. */
@@ -414,6 +221,10 @@ static enum {dump_none, dump_only, dump_names, dump_definitions}
where they are defined. */
static int debug_output = 0;
+/* Nonzero means pass #include lines through to the output,
+ even if they are ifdefed out. */
+static int dump_includes;
+
/* Nonzero indicates special processing used by the pcp program. The
special effects of this mode are:
@@ -429,7 +240,7 @@ static FILE *pcp_outfile;
/* Nonzero means we are inside an IF during a -pcp run. In this mode
macro expansion is done, and preconditions are output for all macro
- uses requiring them. */
+ uses requiring them. */
static int pcp_inside_if;
/* Nonzero means never to include precompiled files.
@@ -449,7 +260,8 @@ static int pedantic_errors;
static int inhibit_warnings = 0;
-/* Nonzero means warn if slash-star appears in a comment. */
+/* Nonzero means warn if slash-star appears in a slash-star comment,
+ or if newline-backslash appears in a slash-slash comment. */
static int warn_comments;
@@ -462,6 +274,10 @@ static int warn_stringify;
static int warn_trigraphs;
+/* Nonzero means warn if undefined identifiers are evaluated in an #if. */
+
+static int warn_undef;
+
/* Nonzero means warn if #import is used. */
static int warn_import = 1;
@@ -474,12 +290,19 @@ static int warnings_are_errors;
int traditional;
+/* Nonzero for the 1989 C Standard, including corrigenda and amendments. */
+
+int c89;
+
/* Nonzero causes output not to be done,
but directives such as #define that have side effects
are still obeyed. */
static int no_output;
+/* Nonzero means we should look for header.gcc files that remap file names. */
+static int remap;
+
/* Nonzero means this file was included with a -imacros or -include
command line and should not be recorded as an include file. */
@@ -505,6 +328,10 @@ static struct file_buf {
char *fname;
/* Filename specified with #line directive. */
char *nominal_fname;
+ /* The length of nominal_fname, which may contain embedded NULs. */
+ size_t nominal_fname_len;
+ /* Include file description. */
+ struct include_file *inc;
/* Record where in the search path this file was found.
For #include_next. */
struct file_name_list *dir;
@@ -521,7 +348,7 @@ static struct file_buf {
struct if_stack *if_stack;
/* Object to be freed at end of input at this level. */
U_CHAR *free_ptr;
- /* True if this is a header file included using <FILENAME>. */
+ /* True if this is a system header file; see is_system_include. */
char system_header_p;
} instack[INPUT_STACK_MAX];
@@ -546,7 +373,7 @@ typedef struct file_buf FILE_BUF;
/* The output buffer. Its LENGTH field is the amount of room allocated
for the buffer, not the number of chars actually present. To get
- that, subtract outbuf.buf from outbuf.bufp. */
+ that, subtract outbuf.buf from outbuf.bufp. */
#define OUTBUF_SIZE 10 /* initial size of output buffer */
static FILE_BUF outbuf;
@@ -561,25 +388,28 @@ static FILE_BUF outbuf;
struct file_name_list
{
struct file_name_list *next;
- char *fname;
- /* If the following is nonzero, it is a macro name.
- Don't include the file again if that macro is defined. */
- U_CHAR *control_macro;
- /* If the following is nonzero, it is a C-language system include
+ /* If the following is 1, it is a C-language system include
directory. */
int c_system_include_path;
/* Mapping of file names for this directory. */
struct file_name_map *name_map;
/* Non-zero if name_map is valid. */
int got_name_map;
+ /* The include directory status. */
+ struct stat st;
+ /* The include prefix: "" denotes the working directory,
+ otherwise fname must end in '/'.
+ The actual size is dynamically allocated. */
+ char fname[1];
};
-/* #include "file" looks in source file dir, then stack. */
-/* #include <file> just looks in the stack. */
-/* -I directories are added to the end, then the defaults are added. */
+/* #include "file" looks in source file dir, then stack. */
+/* #include <file> just looks in the stack. */
+/* -I directories are added to the end, then the defaults are added. */
/* The */
static struct default_include {
char *fname; /* The name of the directory. */
+ char *component; /* The component containing the directory */
int cplusplus; /* Only look here if we're compiling C++. */
int cxx_aware; /* Includes in this directory don't need to
be wrapped in extern "C" when compiling
@@ -590,33 +420,43 @@ static struct default_include {
#else
= {
/* Pick up GNU C++ specific include files. */
- { GPLUSPLUS_INCLUDE_DIR, 1, 1 },
+ { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 },
+ { OLD_GPLUSPLUS_INCLUDE_DIR, 0, 1, 1 },
#ifdef CROSS_COMPILE
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
- { GCC_INCLUDE_DIR, 0, 0 },
+ { GCC_INCLUDE_DIR, "GCC", 0, 0 },
/* For cross-compilation, this dir name is generated
automatically in Makefile.in. */
- { CROSS_INCLUDE_DIR, 0, 0 },
+ { CROSS_INCLUDE_DIR, "GCC", 0, 0 },
+#ifdef TOOL_INCLUDE_DIR
/* This is another place that the target system's headers might be. */
- { TOOL_INCLUDE_DIR, 0, 0 },
+ { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 },
+#endif
#else /* not CROSS_COMPILE */
+#ifdef LOCAL_INCLUDE_DIR
/* This should be /usr/local/include and should come before
the fixincludes-fixed header files. */
- { LOCAL_INCLUDE_DIR, 0, 1 },
+ { LOCAL_INCLUDE_DIR, 0, 0, 1 },
+#endif
+#ifdef TOOL_INCLUDE_DIR
/* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here.
Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h. */
- { TOOL_INCLUDE_DIR, 0, 0 },
+ { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 },
+#endif
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
- { GCC_INCLUDE_DIR, 0, 0 },
+ { GCC_INCLUDE_DIR, "GCC", 0, 0 },
/* Some systems have an extra dir of include files. */
#ifdef SYSTEM_INCLUDE_DIR
- { SYSTEM_INCLUDE_DIR, 0, 0 },
+ { SYSTEM_INCLUDE_DIR, 0, 0, 0 },
+#endif
+#ifndef STANDARD_INCLUDE_COMPONENT
+#define STANDARD_INCLUDE_COMPONENT 0
#endif
- { STANDARD_INCLUDE_DIR, 0, 0 },
+ { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0 },
#endif /* not CROSS_COMPILE */
- { 0, 0, 0 }
+ { 0, 0, 0, 0 }
};
#endif /* no INCLUDE_DEFAULTS */
@@ -643,18 +483,33 @@ static struct file_name_list *last_after_include = 0; /* Last in chain */
static struct file_name_list *before_system = 0;
static struct file_name_list *last_before_system = 0; /* Last in chain */
-/* List of included files that contained #pragma once. */
-static struct file_name_list *dont_repeat_files = 0;
-
-/* List of other included files.
- If ->control_macro if nonzero, the file had a #ifndef
- around the entire contents, and ->control_macro gives the macro name. */
-static struct file_name_list *all_include_files = 0;
-
/* Directory prefix that should replace `/usr' in the standard
include file directories. */
static char *include_prefix;
+/* Maintain and search list of included files. */
+
+struct include_file {
+ struct include_file *next; /* for include_hashtab */
+ struct include_file *next_ino; /* for include_ino_hashtab */
+ char *fname;
+ /* If the following is the empty string, it means #pragma once
+ was seen in this include file, or #import was applied to the file.
+ Otherwise, if it is nonzero, it is a macro name.
+ Don't include the file again if that macro is defined. */
+ U_CHAR *control_macro;
+ /* Nonzero if the dependency on this include file has been output. */
+ int deps_output;
+ struct stat st;
+};
+
+/* Hash tables of files already included with #include or #import.
+ include_hashtab is by full name; include_ino_hashtab is by inode number. */
+
+#define INCLUDE_HASHSIZE 61
+static struct include_file *include_hashtab[INCLUDE_HASHSIZE];
+static struct include_file *include_ino_hashtab[INCLUDE_HASHSIZE];
+
/* Global list of strings read in from precompiled files. This list
is kept in the order the strings are read in, with new strings being
added at the end through stringlist_tailp. We use this list to output
@@ -702,7 +557,7 @@ enum sharp_token_type {
#define f(x) x+x+x+x+x+x+x would have replacement text "++++++" and
pattern list
{ (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
- where (x, y) means (nchars, argno). */
+ where (x, y) means (nchars, argno). */
typedef struct definition DEFINITION;
struct definition {
@@ -713,6 +568,7 @@ struct definition {
U_CHAR *expansion;
int line; /* Line number of definition */
char *file; /* File of definition */
+ size_t file_len; /* Length of file (which can contain NULs) */
char rest_args; /* Nonzero if last arg. absorbs the rest */
struct reflist {
struct reflist *next;
@@ -736,7 +592,7 @@ struct definition {
};
/* different kinds of things that can appear in the value field
- of a hash node. Actually, this may be useless now. */
+ of a hash node. Actually, this may be useless now. */
union hashval {
char *cpval;
DEFINITION *defn;
@@ -763,7 +619,7 @@ static char rest_extension[] = "...";
plus some special tokens like __LINE__ (these each have their own
type, and the appropriate code is run when that type of node is seen.
It does not contain control words like "#define", which are recognized
- by a separate piece of code. */
+ by a separate piece of code. */
/* different flavors of hash nodes --- also used in keyword table */
enum node_type {
@@ -812,7 +668,7 @@ struct hashnode {
struct hashnode *prev;
struct hashnode **bucket_hdr; /* also, a back pointer to this node's hash
chain is kept, in case the node is the head
- of the chain and gets deleted. */
+ of the chain and gets deleted. */
enum node_type type; /* type of special token */
int length; /* length of token, for quick comparison */
U_CHAR *name; /* the actual name */
@@ -826,7 +682,7 @@ typedef struct hashnode HASHNODE;
loop computes the hash value `on the fly' for most tokens,
in order to avoid the overhead of a lot of procedure calls to
the hashf () function. Hashf () only exists for the sake of
- politeness, for use when speed isn't so important. */
+ politeness, for use when speed isn't so important. */
#define HASHSIZE 1403
static HASHNODE *hashtab[HASHSIZE];
@@ -900,7 +756,7 @@ struct assertion_hashnode {
struct assertion_hashnode *prev;
/* also, a back pointer to this node's hash
chain is kept, in case the node is the head
- of the chain and gets deleted. */
+ of the chain and gets deleted. */
struct assertion_hashnode **bucket_hdr;
int length; /* length of token, for quick comparison */
U_CHAR *name; /* the actual name */
@@ -915,7 +771,7 @@ typedef struct assertion_hashnode ASSERTION_HASHNODE;
loop computes the hash value `on the fly' for most tokens,
in order to avoid the overhead of a lot of procedure calls to
the hashf function. hashf only exists for the sake of
- politeness, for use when speed isn't so important. */
+ politeness, for use when speed isn't so important. */
#define ASSERTION_HASHSIZE 37
static ASSERTION_HASHNODE *assertion_hashtab[ASSERTION_HASHSIZE];
@@ -932,12 +788,12 @@ struct directive {
int length; /* Length of name */
int (*func) DO_PROTO; /* Function to handle directive */
char *name; /* Name of directive */
- enum node_type type; /* Code which describes which directive. */
- char angle_brackets; /* Nonzero => <...> is special. */
- char traditional_comments; /* Nonzero: keep comments if -traditional. */
- char pass_thru; /* Copy preprocessed directive to output file. */
+ enum node_type type; /* Code which describes which directive. */
};
+#define IS_INCLUDE_DIRECTIVE_TYPE(t) \
+((int) T_INCLUDE <= (int) (t) && (int) (t) <= (int) T_IMPORT)
+
/* These functions are declared to return int instead of void since they
are going to be placed in the table and some old compilers have trouble with
pointers to functions returning void. */
@@ -964,7 +820,7 @@ static int do_xifdef DO_PROTO;
/* Here is the actual list of #-directives, most-often-used first. */
static struct directive directive_table[] = {
- { 6, do_define, "define", T_DEFINE, 0, 1},
+ { 6, do_define, "define", T_DEFINE},
{ 2, do_if, "if", T_IF},
{ 5, do_xifdef, "ifdef", T_IFDEF},
{ 6, do_xifdef, "ifndef", T_IFNDEF},
@@ -972,16 +828,16 @@ static struct directive directive_table[] = {
{ 4, do_else, "else", T_ELSE},
{ 4, do_elif, "elif", T_ELIF},
{ 4, do_line, "line", T_LINE},
- { 7, do_include, "include", T_INCLUDE, 1},
- { 12, do_include, "include_next", T_INCLUDE_NEXT, 1},
- { 6, do_include, "import", T_IMPORT, 1},
+ { 7, do_include, "include", T_INCLUDE},
+ { 12, do_include, "include_next", T_INCLUDE_NEXT},
+ { 6, do_include, "import", T_IMPORT},
{ 5, do_undef, "undef", T_UNDEF},
{ 5, do_error, "error", T_ERROR},
{ 7, do_warning, "warning", T_WARNING},
#ifdef SCCS_DIRECTIVE
{ 4, do_sccs, "sccs", T_SCCS},
#endif
- { 6, do_pragma, "pragma", T_PRAGMA, 0, 0, 1},
+ { 6, do_pragma, "pragma", T_PRAGMA},
{ 5, do_ident, "ident", T_IDENT},
{ 6, do_assert, "assert", T_ASSERT},
{ 8, do_unassert, "unassert", T_UNASSERT},
@@ -992,14 +848,14 @@ static struct directive directive_table[] = {
this points to the # (or the : of the %:) that started the directive. */
U_CHAR *directive_start;
-/* table to tell if char can be part of a C identifier. */
+/* table to tell if char can be part of a C identifier. */
U_CHAR is_idchar[256];
-/* table to tell if char can be first char of a c identifier. */
+/* table to tell if char can be first char of a c identifier. */
U_CHAR is_idstart[256];
/* table to tell if c is horizontal space. */
-U_CHAR is_hor_space[256];
+static U_CHAR is_hor_space[256];
/* table to tell if c is horizontal or vertical space. */
-static U_CHAR is_space[256];
+U_CHAR is_space[256];
/* names of some characters */
static char *char_name[256];
@@ -1011,18 +867,6 @@ static int errors = 0; /* Error counter for exit code */
/* Name of output file, for error messages. */
static char *out_fname;
-/* Zero means dollar signs are punctuation.
- -$ stores 0; -traditional may store 1. Default is 1 for VMS, 0 otherwise.
- This must be 0 for correct processing of this ANSI C program:
- #define foo(a) #a
- #define lose(b) foo (b)
- #define test$
- lose (test) */
-static int dollars_in_ident;
-#ifndef DOLLARS_IN_IDENTIFIERS
-#define DOLLARS_IN_IDENTIFIERS 1
-#endif
-
/* Stack of conditionals currently in progress
(including both successful and failing conditionals). */
@@ -1030,6 +874,7 @@ static int dollars_in_ident;
struct if_stack {
struct if_stack *next; /* for chaining to the next stack frame */
char *fname; /* copied from input when frame is made */
+ size_t fname_len; /* similarly */
int lineno; /* similarly */
int if_succeeded; /* true if a leg of this if-group
has been passed through rescan */
@@ -1058,6 +903,7 @@ static int ignore_srcdir;
static int safe_read PROTO((int, char *, int));
static void safe_write PROTO((int, char *, int));
+static void eprint_string PROTO((char *, size_t));
int main PROTO((int, char **));
@@ -1081,22 +927,21 @@ static int handle_directive PROTO((FILE_BUF *, FILE_BUF *));
static struct tm *timestamp PROTO((void));
static void special_symbol PROTO((HASHNODE *, FILE_BUF *));
-static int redundant_include_p PROTO((char *));
static int is_system_include PROTO((char *));
-static char *skip_redundant_dir_prefix PROTO((char *));
+static char *base_name PROTO((char *));
+static int absolute_filename PROTO((char *));
+static size_t simplify_filename PROTO((char *));
static char *read_filename_string PROTO((int, FILE *));
static struct file_name_map *read_name_map PROTO((char *));
-static int open_include_file PROTO((char *, struct file_name_list *));
+static int open_include_file PROTO((char *, struct file_name_list *, U_CHAR *, struct include_file **));
+static char *remap_include_file PROTO((char *, struct file_name_list *));
+static int lookup_ino_include PROTO((struct include_file *));
-static void finclude PROTO((int, char *, FILE_BUF *, int, struct file_name_list *));
-static void record_control_macro PROTO((char *, U_CHAR *));
+static void finclude PROTO((int, struct include_file *, FILE_BUF *, int, struct file_name_list *));
+static void record_control_macro PROTO((struct include_file *, U_CHAR *));
-static int import_hash PROTO((char *));
-static int lookup_import PROTO((char *, struct file_name_list *));
-static void add_import PROTO((int, char *));
-
-static char *check_precompiled PROTO((int, char *, char **));
+static char *check_precompiled PROTO((int, struct stat *, char *, char **));
static int check_preconditions PROTO((char *));
static void pcfinclude PROTO((U_CHAR *, U_CHAR *, U_CHAR *, FILE_BUF *));
static void pcstring_used PROTO((HASHNODE *));
@@ -1126,11 +971,11 @@ static void do_once PROTO((void));
static HOST_WIDE_INT eval_if_expression PROTO((U_CHAR *, int));
static void conditional_skip PROTO((FILE_BUF *, int, enum node_type, U_CHAR *, FILE_BUF *));
static void skip_if_group PROTO((FILE_BUF *, int, FILE_BUF *));
-static void validate_else PROTO((U_CHAR *));
+static void validate_else PROTO((U_CHAR *, U_CHAR *));
static U_CHAR *skip_to_end_of_comment PROTO((FILE_BUF *, int *, int));
static U_CHAR *skip_quoted_string PROTO((U_CHAR *, U_CHAR *, int, int *, int *, int *));
-static char *quote_string PROTO((char *, char *));
+static char *quote_string PROTO((char *, char *, size_t));
static U_CHAR *skip_paren_group PROTO((FILE_BUF *));
/* Last arg to output_line_directive. */
@@ -1142,13 +987,13 @@ static void macroexpand PROTO((HASHNODE *, FILE_BUF *));
struct argdata;
static char *macarg PROTO((struct argdata *, int));
-static U_CHAR *macarg1 PROTO((U_CHAR *, U_CHAR *, int *, int *, int *, int));
+static U_CHAR *macarg1 PROTO((U_CHAR *, U_CHAR *, struct hashnode *, int *, int *, int *, int));
static int discard_comments PROTO((U_CHAR *, int, int));
static int change_newlines PROTO((U_CHAR *, int));
-char *my_strerror PROTO((int));
+static char *my_strerror PROTO((int));
void error PRINTF_PROTO_1((char *, ...));
static void verror PROTO((char *, va_list));
static void error_from_errno PROTO((char *));
@@ -1160,7 +1005,7 @@ static void vwarning_with_line PROTO((int, char *, va_list));
static void warning_with_line PRINTF_PROTO_2((int, char *, ...));
void pedwarn PRINTF_PROTO_1((char *, ...));
void pedwarn_with_line PRINTF_PROTO_2((int, char *, ...));
-static void pedwarn_with_file_and_line PRINTF_PROTO_3((char *, int, char *, ...));
+static void pedwarn_with_file_and_line PRINTF_PROTO_4((char *, size_t, int, char *, ...));
static void print_containing_files PROTO((void));
@@ -1185,8 +1030,10 @@ static void make_undef PROTO((char *, FILE_BUF *));
static void make_assertion PROTO((char *, char *));
+static struct file_name_list *new_include_prefix PROTO((struct file_name_list *, char *, char *, char *));
static void append_include_chain PROTO((struct file_name_list *, struct file_name_list *));
+static int quote_string_for_make PROTO((char *, char *));
static void deps_output PROTO((char *, int));
static void fatal PRINTF_PROTO_1((char *, ...)) __attribute__ ((noreturn));
@@ -1200,11 +1047,11 @@ GENERIC_PTR xmalloc PROTO((size_t));
static GENERIC_PTR xrealloc PROTO((GENERIC_PTR, size_t));
static GENERIC_PTR xcalloc PROTO((size_t, size_t));
static char *savestring PROTO((char *));
-
-static int file_size_and_mode PROTO((int, int *, long int *));
+static void print_help PROTO((void));
/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
- retrying if necessary. Return a negative value if an error occurs,
+ retrying if necessary. If MAX_READ_LEN is defined, read at most
+ that bytes at a time. Return a negative value if an error occurs,
otherwise return the actual number of bytes read,
which must be LEN unless end-of-file was reached. */
@@ -1214,9 +1061,16 @@ safe_read (desc, ptr, len)
char *ptr;
int len;
{
- int left = len;
+ int left, rcount, nchars;
+
+ left = len;
while (left > 0) {
- int nchars = read (desc, ptr, left);
+ rcount = left;
+#ifdef MAX_READ_LEN
+ if (rcount > MAX_READ_LEN)
+ rcount = MAX_READ_LEN;
+#endif
+ nchars = read (desc, ptr, rcount);
if (nchars < 0)
{
#ifdef EINTR
@@ -1234,7 +1088,8 @@ safe_read (desc, ptr, len)
}
/* Write LEN bytes at PTR to descriptor DESC,
- retrying if necessary, and treating any real error as fatal. */
+ retrying if necessary, and treating any real error as fatal.
+ If MAX_WRITE_LEN is defined, write at most that many bytes at a time. */
static void
safe_write (desc, ptr, len)
@@ -1242,8 +1097,15 @@ safe_write (desc, ptr, len)
char *ptr;
int len;
{
+ int wcount, written;
+
while (len > 0) {
- int written = write (desc, ptr, len);
+ wcount = len;
+#ifdef MAX_WRITE_LEN
+ if (wcount > MAX_WRITE_LEN)
+ wcount = MAX_WRITE_LEN;
+#endif
+ written = write (desc, ptr, wcount);
if (written < 0)
{
#ifdef EINTR
@@ -1256,14 +1118,108 @@ safe_write (desc, ptr, len)
len -= written;
}
}
+
+/* Print a string to stderr, with extra handling in case it contains
+ embedded NUL characters. Any present are written as is.
+
+ Using fwrite for this purpose produces undesireable results on VMS
+ when stderr happens to be a record oriented file, such as a batch log
+ file, rather than a stream oriented one. */
+
+static void
+eprint_string (string, length)
+ char *string;
+ size_t length;
+{
+ size_t segment_length;
+
+ do {
+ fprintf(stderr, "%s", string);
+ length -= (segment_length = strlen(string));
+ if (length > 0)
+ {
+ fputc('\0', stderr);
+ length -= 1;
+ /* Advance past the portion which has already been printed. */
+ string += segment_length + 1;
+ }
+ } while (length > 0);
+}
+
+
+static void
+print_help ()
+{
+ printf ("Usage: %s [switches] input output\n", progname);
+ printf ("Switches:\n");
+ printf (" -include <file> Include the contents of <file> before other files\n");
+ printf (" -imacros <file> Accept definition of marcos in <file>\n");
+ printf (" -iprefix <path> Specify <path> as a prefix for next two options\n");
+ printf (" -iwithprefix <dir> Add <dir> to the end of the system include paths\n");
+ printf (" -iwithprefixbefore <dir> Add <dir> to the end of the main include paths\n");
+ printf (" -isystem <dir> Add <dir> to the start of the system include paths\n");
+ printf (" -idirafter <dir> Add <dir> to the end of the system include paths\n");
+ printf (" -I <dir> Add <dir> to the end of the main include paths\n");
+ printf (" -nostdinc Do not search the system include directories\n");
+ printf (" -nostdinc++ Do not search the system include directories for C++\n");
+ printf (" -o <file> Put output into <file>\n");
+ printf (" -pedantic Issue all warnings demanded by strict ANSI C\n");
+ printf (" -traditional Follow K&R pre-processor behaviour\n");
+ printf (" -trigraphs Support ANSI C trigraphs\n");
+ printf (" -lang-c Assume that the input sources are in C\n");
+ printf (" -lang-c89 Assume that the input sources are in C89\n");
+ printf (" -lang-c++ Assume that the input sources are in C++\n");
+ printf (" -lang-objc Assume that the input sources are in ObjectiveC\n");
+ printf (" -lang-objc++ Assume that the input sources are in ObjectiveC++\n");
+ printf (" -lang-asm Assume that the input sources are in assembler\n");
+ printf (" -lang-chill Assume that the input sources are in Chill\n");
+ printf (" -+ Allow parsing of C++ style features\n");
+ printf (" -w Inhibit warning messages\n");
+ printf (" -Wtrigraphs Warn if trigraphs are encountered\n");
+ printf (" -Wno-trigraphs Do not warn about trigraphs\n");
+ printf (" -Wcomment{s} Warn if one comment starts inside another\n");
+ printf (" -Wno-comment{s} Do not warn about comments\n");
+ printf (" -Wtraditional Warn if a macro argument is/would be turned into\n");
+ printf (" a string if -tradtional is specified\n");
+ printf (" -Wno-traditional Do not warn about stringification\n");
+ printf (" -Wundef Warn if an undefined macro is used by #if\n");
+ printf (" -Wno-undef Do not warn about testing udefined macros\n");
+ printf (" -Wimport Warn about the use of the #import directive\n");
+ printf (" -Wno-import Do not warn about the use of #import\n");
+ printf (" -Werror Treat all warnings as errors\n");
+ printf (" -Wno-error Do not treat warnings as errors\n");
+ printf (" -Wall Enable all preprocessor warnings\n");
+ printf (" -M Generate make dependencies\n");
+ printf (" -MM As -M, but ignore system header files\n");
+ printf (" -MD As -M, but put output in a .d file\n");
+ printf (" -MMD As -MD, but ignore system header files\n");
+ printf (" -MG Treat missing header file as generated files\n");
+ printf (" -g Include #define and #undef directives in the output\n");
+ printf (" -D<macro> Define a <macro> with string '1' as its value\n");
+ printf (" -D<macro>=<val> Define a <macro> with <val> as its value\n");
+ printf (" -A<question> (<answer>) Assert the <answer> to <question>\n");
+ printf (" -U<macro> Undefine <macro> \n");
+ printf (" -u or -undef Do not predefine any macros\n");
+ printf (" -v Display the version number\n");
+ printf (" -H Print the name of header files as they are used\n");
+ printf (" -C Do not discard comments\n");
+ printf (" -dM Display a list of macro definitions active at end\n");
+ printf (" -dD Preserve macro definitions in output\n");
+ printf (" -dN As -dD except that only the names are preserved\n");
+ printf (" -dI Include #include directives in the output\n");
+ printf (" -ifoutput Describe skipped code blocks in output \n");
+ printf (" -P Do not generate #line directives\n");
+ printf (" -$ Do not include '$' in identifiers\n");
+ printf (" -remap Remap file names when including files.\n");
+ printf (" -h or --help Display this information\n");
+}
int
main (argc, argv)
int argc;
char **argv;
{
- int st_mode;
- long st_size;
+ struct stat st;
char *in_fname;
char *cp;
int f, i;
@@ -1298,42 +1254,31 @@ main (argc, argv)
/* Target-name to write with the dependency information. */
char *deps_target = 0;
-#ifdef RLIMIT_STACK
+#if defined (RLIMIT_STACK) && defined (HAVE_GETRLIMIT) && defined (HAVE_SETRLIMIT)
/* Get rid of any avoidable limit on stack size. */
{
struct rlimit rlim;
/* Set the stack limit huge so that alloca (particularly stringtab
- * in dbxread.c) does not fail. */
+ in dbxread.c) does not fail. */
getrlimit (RLIMIT_STACK, &rlim);
rlim.rlim_cur = rlim.rlim_max;
setrlimit (RLIMIT_STACK, &rlim);
}
-#endif /* RLIMIT_STACK defined */
+#endif
#ifdef SIGPIPE
signal (SIGPIPE, pipe_closed);
#endif
- cp = argv[0] + strlen (argv[0]);
- while (cp != argv[0] && cp[-1] != '/'
-#ifdef DIR_SEPARATOR
- && cp[-1] != DIR_SEPARATOR
-#endif
- )
- --cp;
- progname = cp;
+ progname = base_name (argv[0]);
#ifdef VMS
{
- /* Remove directories from PROGNAME. */
+ /* Remove extension from PROGNAME. */
char *p;
- char *s = progname;
+ char *s = progname = savestring (progname);
- if ((p = rindex (s, ':')) != 0) s = p + 1; /* skip device */
- if ((p = rindex (s, ']')) != 0) s = p + 1; /* skip directory */
- if ((p = rindex (s, '>')) != 0) s = p + 1; /* alternate (int'n'l) dir */
- s = progname = savestring (s);
if ((p = rindex (s, ';')) != 0) *p = '\0'; /* strip version number */
if ((p = rindex (s, '.')) != 0 /* strip type iff ".exe" */
&& (p[1] == 'e' || p[1] == 'E')
@@ -1347,10 +1292,8 @@ main (argc, argv)
in_fname = NULL;
out_fname = NULL;
- /* Initialize is_idchar to allow $. */
- dollars_in_ident = 1;
+ /* Initialize is_idchar. */
initialize_char_syntax ();
- dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 0;
no_line_directives = 0;
no_trigraphs = 1;
@@ -1370,7 +1313,10 @@ main (argc, argv)
for (i = 1; i < argc; i++) {
if (argv[i][0] != '-') {
if (out_fname != NULL)
- fatal ("Usage: %s [switches] input output", argv[0]);
+ {
+ print_help ();
+ fatal ("Too many arguments");
+ }
else if (in_fname != NULL)
out_fname = argv[i];
else
@@ -1380,16 +1326,20 @@ main (argc, argv)
case 'i':
if (!strcmp (argv[i], "-include")) {
+ int temp = i;
+
if (i + 1 == argc)
fatal ("Filename missing after `-include' option");
else
- pend_includes[i] = argv[i+1], i++;
+ simplify_filename (pend_includes[temp] = argv[++i]);
}
if (!strcmp (argv[i], "-imacros")) {
+ int temp = i;
+
if (i + 1 == argc)
fatal ("Filename missing after `-imacros' option");
else
- pend_files[i] = argv[i+1], i++;
+ simplify_filename (pend_files[temp] = argv[++i]);
}
if (!strcmp (argv[i], "-iprefix")) {
if (i + 1 == argc)
@@ -1403,17 +1353,10 @@ main (argc, argv)
if (!strcmp (argv[i], "-isystem")) {
struct file_name_list *dirtmp;
- if (i + 1 == argc)
- fatal ("Filename missing after `-isystem' option");
-
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0;
- dirtmp->control_macro = 0;
+ if (! (dirtmp = new_include_prefix (NULL_PTR, NULL_PTR,
+ "", argv[++i])))
+ break;
dirtmp->c_system_include_path = 1;
- dirtmp->fname = xmalloc (strlen (argv[i+1]) + 1);
- strcpy (dirtmp->fname, argv[++i]);
- dirtmp->got_name_map = 0;
if (before_system == 0)
before_system = dirtmp;
@@ -1436,18 +1379,9 @@ main (argc, argv)
prefix[strlen (prefix) - 7] = 0;
}
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0; /* New one goes on the end */
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 0;
- if (i + 1 == argc)
- fatal ("Directory name missing after `-iwithprefix' option");
-
- dirtmp->fname = xmalloc (strlen (argv[i+1]) + strlen (prefix) + 1);
- strcpy (dirtmp->fname, prefix);
- strcat (dirtmp->fname, argv[++i]);
- dirtmp->got_name_map = 0;
+ if (! (dirtmp = new_include_prefix (NULL_PTR, NULL_PTR,
+ prefix, argv[++i])))
+ break;
if (after_include == 0)
after_include = dirtmp;
@@ -1470,35 +1404,16 @@ main (argc, argv)
prefix[strlen (prefix) - 7] = 0;
}
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0; /* New one goes on the end */
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 0;
- if (i + 1 == argc)
- fatal ("Directory name missing after `-iwithprefixbefore' option");
-
- dirtmp->fname = xmalloc (strlen (argv[i+1]) + strlen (prefix) + 1);
- strcpy (dirtmp->fname, prefix);
- strcat (dirtmp->fname, argv[++i]);
- dirtmp->got_name_map = 0;
-
+ dirtmp = new_include_prefix (NULL_PTR, NULL_PTR, prefix, argv[++i]);
append_include_chain (dirtmp, dirtmp);
}
/* Add directory to end of path for includes. */
if (!strcmp (argv[i], "-idirafter")) {
struct file_name_list *dirtmp;
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0; /* New one goes on the end */
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 0;
- if (i + 1 == argc)
- fatal ("Directory name missing after `-idirafter' option");
- else
- dirtmp->fname = argv[++i];
- dirtmp->got_name_map = 0;
+ if (! (dirtmp = new_include_prefix (NULL_PTR, NULL_PTR,
+ "", argv[++i])))
+ break;
if (after_include == 0)
after_include = dirtmp;
@@ -1529,10 +1444,10 @@ main (argc, argv)
if (i + 1 == argc)
fatal ("Filename missing after -pcp option");
pcp_fname = argv[++i];
- pcp_outfile =
- ((pcp_fname[0] != '-' || pcp_fname[1] != '\0')
- ? fopen (pcp_fname, "w")
- : stdout);
+ pcp_outfile
+ = ((pcp_fname[0] != '-' || pcp_fname[1] != '\0')
+ ? fopen (pcp_fname, "w")
+ : stdout);
if (pcp_outfile == 0)
pfatal_with_name (pcp_fname);
no_precomp = 1;
@@ -1543,8 +1458,6 @@ main (argc, argv)
if (!strcmp (argv[i], "-traditional")) {
traditional = 1;
cplusplus_comments = 0;
- if (dollars_in_ident > 0)
- dollars_in_ident = 1;
} else if (!strcmp (argv[i], "-trigraphs")) {
no_trigraphs = 0;
}
@@ -1552,15 +1465,15 @@ main (argc, argv)
case 'l':
if (! strcmp (argv[i], "-lang-c"))
- cplusplus = 0, cplusplus_comments = 1, objc = 0;
+ cplusplus = 0, cplusplus_comments = 1, c89 = 0, objc = 0;
if (! strcmp (argv[i], "-lang-c89"))
- cplusplus = 0, cplusplus_comments = 0, objc = 0;
+ cplusplus = 0, cplusplus_comments = 0, c89 = 1, objc = 0;
if (! strcmp (argv[i], "-lang-c++"))
- cplusplus = 1, cplusplus_comments = 1, objc = 0;
+ cplusplus = 1, cplusplus_comments = 1, c89 = 0, objc = 0;
if (! strcmp (argv[i], "-lang-objc"))
- objc = 1, cplusplus = 0, cplusplus_comments = 1;
+ cplusplus = 0, cplusplus_comments = 1, c89 = 0, objc = 1;
if (! strcmp (argv[i], "-lang-objc++"))
- objc = 1, cplusplus = 1, cplusplus_comments = 1;
+ cplusplus = 1, cplusplus_comments = 1, c89 = 0, objc = 1;
if (! strcmp (argv[i], "-lang-asm"))
lang_asm = 1;
if (! strcmp (argv[i], "-lint"))
@@ -1592,6 +1505,10 @@ main (argc, argv)
warn_stringify = 1;
else if (!strcmp (argv[i], "-Wno-traditional"))
warn_stringify = 0;
+ else if (!strcmp (argv[i], "-Wundef"))
+ warn_undef = 1;
+ else if (!strcmp (argv[i], "-Wno-undef"))
+ warn_undef = 0;
else if (!strcmp (argv[i], "-Wimport"))
warn_import = 1;
else if (!strcmp (argv[i], "-Wno-import"))
@@ -1666,6 +1583,9 @@ main (argc, argv)
case 'D':
dump_macros = dump_definitions;
break;
+ case 'I':
+ dump_includes = 1;
+ break;
}
}
}
@@ -1676,6 +1596,13 @@ main (argc, argv)
debug_output = 1;
break;
+ case '-':
+ if (strcmp (argv[i], "--help") != 0)
+ return i;
+ print_help ();
+ exit (0);
+ break;
+
case 'v':
fprintf (stderr, "GNU CPP version %s", version_string);
#ifdef TARGET_VERSION
@@ -1746,7 +1673,7 @@ main (argc, argv)
break;
case '$': /* Don't include $ in identifiers. */
- dollars_in_ident = 0;
+ is_idchar['$'] = is_idstart['$'] = 0;
break;
case 'I': /* Add directory to path for includes. */
@@ -1759,18 +1686,8 @@ main (argc, argv)
first_bracket_include = 0;
}
else {
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0; /* New one goes on the end */
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 0;
- if (argv[i][2] != 0)
- dirtmp->fname = argv[i] + 2;
- else if (i + 1 == argc)
- fatal ("Directory name missing after -I option");
- else
- dirtmp->fname = argv[++i];
- dirtmp->got_name_map = 0;
+ dirtmp = new_include_prefix (last_include, NULL_PTR, "",
+ argv[i][2] ? argv[i] + 2 : argv[++i]);
append_include_chain (dirtmp, dirtmp);
}
}
@@ -1788,6 +1705,11 @@ main (argc, argv)
no_precomp = 1;
break;
+ case 'r':
+ if (!strcmp (argv[i], "-remap"))
+ remap = 1;
+ break;
+
case 'u':
/* Sun compiler passes undocumented switch "-undef".
Let's assume it means to inhibit the predefined symbols. */
@@ -1815,13 +1737,10 @@ main (argc, argv)
/* Some people say that CPATH should replace the standard include dirs,
but that seems pointless: it comes before them, so it overrides them
anyway. */
- cp = getenv ("CPATH");
+ GET_ENVIRONMENT (cp, "CPATH");
if (cp && ! no_standard_includes)
path_include (cp);
- /* Now that dollars_in_ident is known, initialize is_idchar. */
- initialize_char_syntax ();
-
/* Initialize output buffer */
outbuf.buf = (U_CHAR *) xmalloc (OUTBUF_SIZE);
@@ -1835,6 +1754,7 @@ main (argc, argv)
if (in_fname == NULL)
in_fname = "";
fp->nominal_fname = fp->fname = in_fname;
+ fp->nominal_fname_len = strlen (in_fname);
fp->lineno = 0;
/* In C++, wchar_t is a distinct basic type, and we can expect
@@ -1851,6 +1771,63 @@ main (argc, argv)
if (!inhibit_predefs) {
char *p = (char *) alloca (strlen (predefs) + 1);
+
+#ifdef VMS
+ struct dsc$descriptor_s lcl_name;
+ struct item_list {
+ unsigned short length; /* input length */
+ unsigned short code; /* item code */
+ unsigned long dptr; /* data ptr */
+ unsigned long lptr; /* output length ptr */
+ };
+
+ unsigned long syi_length;
+ char syi_data[16];
+
+ struct item_list items[] = {
+ { 16, SYI$_VERSION, 0, 0 },
+ { 0, 0, 0, 0 }
+ };
+
+ items[0].dptr = (unsigned long)syi_data;
+ items[0].lptr = (unsigned long)(&syi_length);
+
+ if (SYS$GETSYIW (0, 0, 0, items, NULL, NULL, NULL, NULL) == SS$_NORMAL)
+ {
+ unsigned long vms_version_value;
+ char *vers;
+
+ vers = syi_data;
+ vms_version_value = 0;
+
+ if (*vers == 'V')
+ vers++;
+ if (ISDIGIT (*vers))
+ {
+ vms_version_value = (*vers - '0') * 10000000;
+ }
+ vers++;
+ if (*vers == '.')
+ {
+ vers++;
+ if (ISDIGIT (*vers))
+ {
+ vms_version_value += (*vers - '0') * 100000;
+ }
+ }
+
+ if (vms_version_value > 0)
+ {
+ char versbuf[32];
+
+ sprintf (versbuf, "__VMS_VER=%08ld", vms_version_value);
+ if (debug_output)
+ output_line_directive (fp, &outbuf, 0, same_file);
+ make_definition (versbuf, &outbuf);
+ }
+ }
+#endif
+
strcpy (p, predefs);
while (*p) {
char *q;
@@ -1938,28 +1915,27 @@ main (argc, argv)
done_initializing = 1;
- { /* read the appropriate environment variable and if it exists
- replace include_defaults with the listed path. */
+ { /* Read the appropriate environment variable and if it exists
+ replace include_defaults with the listed path. */
char *epath = 0;
switch ((objc << 1) + cplusplus)
{
case 0:
- epath = getenv ("C_INCLUDE_PATH");
+ GET_ENVIRONMENT (epath, "C_INCLUDE_PATH");
break;
case 1:
- epath = getenv ("CPLUS_INCLUDE_PATH");
+ GET_ENVIRONMENT (epath, "CPLUS_INCLUDE_PATH");
break;
case 2:
- epath = getenv ("OBJC_INCLUDE_PATH");
+ GET_ENVIRONMENT (epath, "OBJC_INCLUDE_PATH");
break;
case 3:
- epath = getenv ("OBJCPLUS_INCLUDE_PATH");
+ GET_ENVIRONMENT (epath, "OBJCPLUS_INCLUDE_PATH");
break;
}
/* If the environment var for this language is set,
add to the default list of include directories. */
if (epath) {
- char *nstore = (char *) alloca (strlen (epath) + 2);
int num_dirs;
char *startp, *endp;
@@ -1973,30 +1949,20 @@ main (argc, argv)
startp = endp = epath;
num_dirs = 0;
while (1) {
- /* Handle cases like c:/usr/lib:d:/gcc/lib */
- if ((*endp == PATH_SEPARATOR
-#if 0 /* Obsolete, now that we use semicolons as the path separator. */
-#ifdef __MSDOS__
- && (endp-startp != 1 || !isalpha (*startp))
-#endif
-#endif
- )
- || *endp == 0) {
- strncpy (nstore, startp, endp-startp);
- if (endp == startp)
- strcpy (nstore, ".");
- else
- nstore[endp-startp] = '\0';
-
- include_defaults[num_dirs].fname = savestring (nstore);
+ char c = *endp++;
+ if (c == PATH_SEPARATOR || !c) {
+ endp[-1] = 0;
+ include_defaults[num_dirs].fname
+ = startp == endp ? "." : savestring (startp);
+ endp[-1] = c;
+ include_defaults[num_dirs].component = 0;
include_defaults[num_dirs].cplusplus = cplusplus;
include_defaults[num_dirs].cxx_aware = 1;
num_dirs++;
- if (*endp == '\0')
+ if (!c)
break;
- endp = startp = endp + 1;
- } else
- endp++;
+ startp = endp;
+ }
}
/* Put the usual defaults back in at the end. */
bcopy ((char *) include_defaults_array,
@@ -2030,18 +1996,14 @@ main (argc, argv)
if (!strncmp (p->fname, default_prefix, default_len)) {
/* Yes; change prefix and add to search list. */
struct file_name_list *new
- = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
- int this_len = strlen (specd_prefix) + strlen (p->fname) - default_len;
- char *str = xmalloc (this_len + 1);
- strcpy (str, specd_prefix);
- strcat (str, p->fname + default_len);
- new->fname = str;
- new->control_macro = 0;
- new->c_system_include_path = !p->cxx_aware;
- new->got_name_map = 0;
- append_include_chain (new, new);
- if (first_system_include == 0)
- first_system_include = new;
+ = new_include_prefix (NULL_PTR, NULL_PTR, specd_prefix,
+ p->fname + default_len);
+ if (new) {
+ new->c_system_include_path = !p->cxx_aware;
+ append_include_chain (new, new);
+ if (first_system_include == 0)
+ first_system_include = new;
+ }
}
}
}
@@ -2050,14 +2012,13 @@ main (argc, argv)
/* Some standard dirs are only for C++. */
if (!p->cplusplus || (cplusplus && !no_standard_cplusplus_includes)) {
struct file_name_list *new
- = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
- new->control_macro = 0;
- new->c_system_include_path = !p->cxx_aware;
- new->fname = p->fname;
- new->got_name_map = 0;
- append_include_chain (new, new);
- if (first_system_include == 0)
- first_system_include = new;
+ = new_include_prefix (NULL_PTR, p->component, "", p->fname);
+ if (new) {
+ new->c_system_include_path = !p->cxx_aware;
+ append_include_chain (new, new);
+ if (first_system_include == 0)
+ first_system_include = new;
+ }
}
}
}
@@ -2074,37 +2035,17 @@ main (argc, argv)
for (p = include; p; p = p->next) {
if (p == first_bracket_include)
fprintf (stderr, "#include <...> search starts here:\n");
- fprintf (stderr, " %s\n", p->fname);
+ if (!p->fname[0])
+ fprintf (stderr, " .\n");
+ else if (!strcmp (p->fname, "/") || !strcmp (p->fname, "//"))
+ fprintf (stderr, " %s\n", p->fname);
+ else
+ /* Omit trailing '/'. */
+ fprintf (stderr, " %.*s\n", (int) strlen (p->fname) - 1, p->fname);
}
fprintf (stderr, "End of search list.\n");
}
- /* Scan the -imacros files before the main input.
- Much like #including them, but with no_output set
- so that only their macro definitions matter. */
-
- no_output++; no_record_file++;
- for (i = 1; i < argc; i++)
- if (pend_files[i]) {
- int fd = open (pend_files[i], O_RDONLY, 0666);
- if (fd < 0) {
- perror_with_name (pend_files[i]);
- return FATAL_EXIT_CODE;
- }
- finclude (fd, pend_files[i], &outbuf, 0, NULL_PTR);
- }
- no_output--; no_record_file--;
-
- /* Copy the entire contents of the main input file into
- the stacked input buffer previously allocated for it. */
-
- /* JF check for stdin */
- if (in_fname == NULL || *in_fname == 0) {
- in_fname = "";
- f = 0;
- } else if ((f = open (in_fname, O_RDONLY, 0666)) < 0)
- goto perror;
-
/* -MG doesn't select the form of output and must be specified with one of
-M or -MM. -MG doesn't make sense with -MD or -MMD since they don't
inhibit compilation. */
@@ -2166,15 +2107,7 @@ main (argc, argv)
char *p, *q;
int len;
- /* Discard all directory prefixes from filename. */
- if ((q = rindex (in_fname, '/')) != NULL
-#ifdef DIR_SEPARATOR
- && (q = rindex (in_fname, DIR_SEPARATOR)) != NULL
-#endif
- )
- ++q;
- else
- q = in_fname;
+ q = base_name (in_fname);
/* Copy remainder to mungable area. */
p = (char *) alloca (strlen(q) + 8);
@@ -2206,23 +2139,48 @@ main (argc, argv)
q = p + (len - 4);
/* Supply our own suffix. */
-#ifndef VMS
- strcpy (q, ".o");
-#else
- strcpy (q, ".obj");
-#endif
+ strcpy (q, OBJECT_SUFFIX);
deps_output (p, ':');
deps_output (in_fname, ' ');
}
}
- file_size_and_mode (f, &st_mode, &st_size);
+ /* Scan the -imacros files before the main input.
+ Much like #including them, but with no_output set
+ so that only their macro definitions matter. */
+
+ no_output++; no_record_file++;
+ for (i = 1; i < argc; i++)
+ if (pend_files[i]) {
+ struct include_file *inc;
+ int fd = open_include_file (pend_files[i], NULL_PTR, NULL_PTR, &inc);
+ if (fd < 0) {
+ perror_with_name (pend_files[i]);
+ return FATAL_EXIT_CODE;
+ }
+ finclude (fd, inc, &outbuf, 0, NULL_PTR);
+ }
+ no_output--; no_record_file--;
+
+ /* Copy the entire contents of the main input file into
+ the stacked input buffer previously allocated for it. */
+
+ /* JF check for stdin */
+ if (in_fname == NULL || *in_fname == 0) {
+ in_fname = "";
+ f = 0;
+ } else if ((f = open (in_fname, O_RDONLY, 0666)) < 0)
+ goto perror;
+
+ if (fstat (f, &st) != 0)
+ pfatal_with_name (in_fname);
fp->nominal_fname = fp->fname = in_fname;
+ fp->nominal_fname_len = strlen (in_fname);
fp->lineno = 1;
fp->system_header_p = 0;
/* JF all this is mine about reading pipes and ttys */
- if (! S_ISREG (st_mode)) {
+ if (! S_ISREG (st.st_mode)) {
/* Read input from a file that is not a normal disk file.
We cannot preallocate a buffer with the correct size,
so we must read in the file a piece at the time and make it bigger. */
@@ -2230,6 +2188,9 @@ main (argc, argv)
int bsize;
int cnt;
+ if (S_ISDIR (st.st_mode))
+ fatal ("Input file `%s' is a directory", in_fname);
+
bsize = 2000;
size = 0;
fp->buf = (U_CHAR *) xmalloc (bsize + 2);
@@ -2244,9 +2205,12 @@ main (argc, argv)
fp->length = size;
} else {
/* Read a file whose size we can determine in advance.
- For the sake of VMS, st_size is just an upper bound. */
- fp->buf = (U_CHAR *) xmalloc (st_size + 2);
- fp->length = safe_read (f, (char *) fp->buf, st_size);
+ For the sake of VMS, st.st_size is just an upper bound. */
+ size_t s = (size_t) st.st_size;
+ if (s != st.st_size || s + 2 < s)
+ memory_full ();
+ fp->buf = (U_CHAR *) xmalloc (s + 2);
+ fp->length = safe_read (f, (char *) fp->buf, s);
if (fp->length < 0) goto perror;
}
fp->bufp = fp->buf;
@@ -2281,12 +2245,13 @@ main (argc, argv)
no_record_file++;
for (i = 1; i < argc; i++)
if (pend_includes[i]) {
- int fd = open (pend_includes[i], O_RDONLY, 0666);
+ struct include_file *inc;
+ int fd = open_include_file (pend_includes[i], NULL_PTR, NULL_PTR, &inc);
if (fd < 0) {
perror_with_name (pend_includes[i]);
return FATAL_EXIT_CODE;
}
- finclude (fd, pend_includes[i], &outbuf, 0, NULL_PTR);
+ finclude (fd, inc, &outbuf, 0, NULL_PTR);
}
no_record_file--;
@@ -2353,38 +2318,23 @@ path_include (path)
if (*p)
while (1) {
char *q = p;
- char *name;
+ char c;
struct file_name_list *dirtmp;
/* Find the end of this name. */
- while (*q != 0 && *q != PATH_SEPARATOR) q++;
- if (p == q) {
- /* An empty name in the path stands for the current directory. */
- name = xmalloc (2);
- name[0] = '.';
- name[1] = 0;
- } else {
- /* Otherwise use the directory that is named. */
- name = xmalloc (q - p + 1);
- bcopy (p, name, q - p);
- name[q - p] = 0;
- }
+ while ((c = *q++) != PATH_SEPARATOR && c)
+ continue;
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0; /* New one goes on the end */
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 0;
- dirtmp->fname = name;
- dirtmp->got_name_map = 0;
+ q[-1] = 0;
+ dirtmp = new_include_prefix (last_include, NULL_PTR,
+ "", p == q ? "." : p);
+ q[-1] = c;
append_include_chain (dirtmp, dirtmp);
/* Advance past this name. */
p = q;
- if (*p == 0)
+ if (! c)
break;
- /* Skip the colon. */
- p++;
}
}
@@ -2423,7 +2373,7 @@ index0 (s, c, n)
Using an extra pass through the buffer takes a little extra time,
but is infinitely less hairy than trying to handle trigraphs inside
strings, etc. everywhere, and also makes sure that trigraphs are
- only translated in the top level of processing. */
+ only translated in the top level of processing. */
static void
trigraph_pcp (buf)
@@ -2474,7 +2424,7 @@ trigraph_pcp (buf)
len = sptr - fptr - 2;
/* BSD doc says bcopy () works right for overlapping strings. In ANSI
- C, this will be memmove (). */
+ C, this will be memmove (). */
if (bptr != fptr && len > 0)
bcopy ((char *) fptr, (char *) bptr, len);
@@ -2488,7 +2438,8 @@ trigraph_pcp (buf)
buf->length -= fptr - bptr;
buf->buf[buf->length] = '\0';
if (warn_trigraphs && fptr != bptr)
- warning_with_line (0, "%d trigraph(s) encountered", (fptr - bptr) / 2);
+ warning_with_line (0, "%lu trigraph(s) encountered",
+ (unsigned long) (fptr - bptr) / 2);
}
/* Move all backslash-newline pairs out of embarrassing places.
@@ -2568,8 +2519,7 @@ name_newline_fix (bp)
Upon return, any arg will be pointed to with argstart and will be
arglen long. Note that we don't parse that arg since it will just
- be printed out again.
-*/
+ be printed out again. */
static char *
get_lintcmd (ibp, limit, argstart, arglen, cmdlen)
@@ -2578,7 +2528,7 @@ get_lintcmd (ibp, limit, argstart, arglen, cmdlen)
U_CHAR **argstart; /* point to command arg */
int *arglen, *cmdlen; /* how long they are */
{
- long linsize;
+ HOST_WIDE_INT linsize;
register U_CHAR *numptr; /* temp for arg parsing */
*arglen = 0;
@@ -2605,10 +2555,10 @@ get_lintcmd (ibp, limit, argstart, arglen, cmdlen)
if ((linsize >= 7) && !bcmp (ibp, "VARARGS", 7)) {
*cmdlen = 7;
ibp += 7; linsize -= 7;
- if ((linsize == 0) || ! isdigit (*ibp)) return "VARARGS";
+ if ((linsize == 0) || ! ISDIGIT (*ibp)) return "VARARGS";
/* OK, read a number */
- for (numptr = *argstart = ibp; (numptr < limit) && isdigit (*numptr);
+ for (numptr = *argstart = ibp; (numptr < limit) && ISDIGIT (*numptr);
numptr++);
*arglen = numptr - *argstart;
return "VARARGS";
@@ -2773,7 +2723,7 @@ do { ip = &instack[indepth]; \
if (ident_length)
goto specialchar;
/* Copy #foo (bar lose) without macro expansion. */
- obp[-1] = '#'; /* In case it was '%'. */
+ obp[-1] = '#'; /* In case it was '%'. */
SKIP_WHITE_SPACE (ibp);
while (is_idchar[*ibp])
*obp++ = *ibp++;
@@ -2900,8 +2850,13 @@ do { ip = &instack[indepth]; \
/* A single quoted string is treated like a double -- some
programs (e.g., troff) are perverse this way */
- if (ident_length)
- goto specialchar;
+ /* Handle any pending identifier;
+ but the L in L'...' or L"..." is not an identifier. */
+ if (ident_length) {
+ if (! (ident_length == 1 && hash == HASHSTEP (0, 'L')))
+ goto specialchar;
+ ident_length = hash = 0;
+ }
start_line = ip->lineno;
@@ -2920,9 +2875,11 @@ do { ip = &instack[indepth]; \
if (!traditional) {
error_with_line (line_for_error (start_line),
"unterminated string or character constant");
- error_with_line (multiline_string_line,
- "possible real start of unterminated constant");
- multiline_string_line = 0;
+ if (multiline_string_line) {
+ error_with_line (multiline_string_line,
+ "possible real start of unterminated constant");
+ multiline_string_line = 0;
+ }
}
break;
}
@@ -2942,29 +2899,34 @@ do { ip = &instack[indepth]; \
"unterminated character constant");
goto while2end;
}
- if (pedantic && multiline_string_line == 0) {
- pedwarn_with_line (line_for_error (start_line),
- "string constant runs past end of line");
- }
- if (multiline_string_line == 0)
+ if (multiline_string_line == 0) {
+ if (pedantic)
+ pedwarn_with_line (line_for_error (start_line),
+ "string constant runs past end of line");
multiline_string_line = ip->lineno - 1;
+ }
break;
case '\\':
- if (ibp >= limit)
- break;
if (*ibp == '\n') {
- /* Backslash newline is replaced by nothing at all,
- but keep the line counts correct. */
- --obp;
+ /* Backslash newline is replaced by nothing at all, but
+ keep the line counts correct. But if we are reading
+ from a macro, keep the backslash newline, since backslash
+ newlines have already been processed. */
+ if (ip->macro)
+ *obp++ = '\n';
+ else
+ --obp;
++ibp;
++ip->lineno;
} else {
/* ANSI stupidly requires that in \\ the second \
is *not* prevented from combining with a newline. */
- while (*ibp == '\\' && ibp[1] == '\n') {
- ibp += 2;
- ++ip->lineno;
+ if (!ip->macro) {
+ while (*ibp == '\\' && ibp[1] == '\n') {
+ ibp += 2;
+ ++ip->lineno;
+ }
}
*obp++ = *ibp++;
}
@@ -2981,22 +2943,21 @@ do { ip = &instack[indepth]; \
break;
case '/':
+ if (ip->macro != 0)
+ goto randomchar;
if (*ibp == '\\' && ibp[1] == '\n')
newline_fix (ibp);
-
if (*ibp != '*'
&& !(cplusplus_comments && *ibp == '/'))
goto randomchar;
- if (ip->macro != 0)
- goto randomchar;
if (ident_length)
goto specialchar;
if (*ibp == '/') {
- /* C++ style comment... */
+ /* C++ style comment... */
start_line = ip->lineno;
- /* Comments are equivalent to spaces. */
+ /* Comments are equivalent to spaces. */
if (! put_out_comments)
obp[-1] = ' ';
@@ -3012,6 +2973,8 @@ do { ip = &instack[indepth]; \
}
break;
}
+ if (warn_comments)
+ warning ("multiline `//' comment");
++ip->lineno;
/* Copy the newline into the output buffer, in order to
avoid the pain of a #line every time a multiline comment
@@ -3029,7 +2992,7 @@ do { ip = &instack[indepth]; \
start_line = ip->lineno;
- ++ibp; /* Skip the star. */
+ ++ibp; /* Skip the star. */
/* If this cpp is for lint, we peek inside the comments: */
if (for_lint) {
@@ -3080,18 +3043,17 @@ do { ip = &instack[indepth]; \
{
U_CHAR *before_bp = ibp;
- while (ibp < limit) {
+ for (;;) {
switch (*ibp++) {
- case '/':
- if (warn_comments && *ibp == '*')
- warning ("`/*' within comment");
- break;
case '*':
+ if (ibp[-2] == '/' && warn_comments)
+ warning ("`/*' within comment");
if (*ibp == '\\' && ibp[1] == '\n')
newline_fix (ibp);
- if (ibp >= limit || *ibp == '/')
+ if (*ibp == '/')
goto comment_end;
break;
+
case '\n':
++ip->lineno;
/* Copy the newline into the output buffer, in order to
@@ -3100,26 +3062,32 @@ do { ip = &instack[indepth]; \
if (!put_out_comments)
*obp++ = '\n';
++op->lineno;
+ break;
+
+ case 0:
+ if (limit < ibp) {
+ error_with_line (line_for_error (start_line),
+ "unterminated comment");
+ goto limit_reached;
+ }
+ break;
}
}
comment_end:
- if (ibp >= limit)
- error_with_line (line_for_error (start_line),
- "unterminated comment");
- else {
- ibp++;
- if (put_out_comments) {
- bcopy ((char *) before_bp, (char *) obp, ibp - before_bp);
- obp += ibp - before_bp;
- }
+ ibp++;
+ if (put_out_comments) {
+ bcopy ((char *) before_bp, (char *) obp, ibp - before_bp);
+ obp += ibp - before_bp;
}
}
break;
case '$':
- if (!dollars_in_ident)
+ if (! is_idchar['$'])
goto randomchar;
+ if (pedantic)
+ pedwarn ("`$' in identifier");
goto letter;
case '0': case '1': case '2': case '3': case '4':
@@ -3132,9 +3100,11 @@ do { ip = &instack[indepth]; \
if (ident_length == 0) {
for (;;) {
- while (ibp[0] == '\\' && ibp[1] == '\n') {
- ++ip->lineno;
- ibp += 2;
+ if (!ip->macro) {
+ while (ibp[0] == '\\' && ibp[1] == '\n') {
+ ++ip->lineno;
+ ibp += 2;
+ }
}
c = *ibp++;
if (!is_idchar[c] && c != '.') {
@@ -3143,16 +3113,19 @@ do { ip = &instack[indepth]; \
}
*obp++ = c;
/* A sign can be part of a preprocessing number
- if it follows an e. */
- if (c == 'e' || c == 'E') {
- while (ibp[0] == '\\' && ibp[1] == '\n') {
- ++ip->lineno;
- ibp += 2;
+ if it follows an `e' or `p'. */
+ if (c == 'e' || c == 'E' || c == 'p' || c == 'P') {
+ if (!ip->macro) {
+ while (ibp[0] == '\\' && ibp[1] == '\n') {
+ ++ip->lineno;
+ ibp += 2;
+ }
}
if (*ibp == '+' || *ibp == '-') {
*obp++ = *ibp++;
- /* But traditional C does not let the token go past the sign. */
- if (traditional)
+ /* But traditional C does not let the token go past the sign,
+ and C89 does not allow `p'. */
+ if (traditional || (c89 && (c == 'p' || c == 'P')))
break;
}
}
@@ -3251,6 +3224,7 @@ do { ip = &instack[indepth]; \
/* Our input really contains a null character. */
goto randomchar;
+ limit_reached:
/* At end of a macro-expansion level, pop it and read next level. */
if (ip->macro != 0) {
obp--;
@@ -3405,35 +3379,6 @@ randomchar:
old_iln = ip->lineno;
old_oln = op->lineno;
}
- /* A comment: copy it unchanged or discard it. */
- else if (*ibp == '/' && ibp[1] == '*') {
- if (put_out_comments) {
- *obp++ = '/';
- *obp++ = '*';
- } else if (! traditional) {
- *obp++ = ' ';
- }
- ibp += 2;
- while (ibp + 1 != limit
- && !(ibp[0] == '*' && ibp[1] == '/')) {
- /* We need not worry about newline-marks,
- since they are never found in comments. */
- if (*ibp == '\n') {
- /* Newline in a file. Count it. */
- ++ip->lineno;
- ++op->lineno;
- }
- if (put_out_comments)
- *obp++ = *ibp++;
- else
- ibp++;
- }
- ibp += 2;
- if (put_out_comments) {
- *obp++ = '*';
- *obp++ = '/';
- }
- }
else if (is_space[*ibp]) {
*obp++ = *ibp++;
if (ibp[-1] == '\n') {
@@ -3460,6 +3405,59 @@ randomchar:
}
}
}
+ else if (ip->macro)
+ break;
+ else if (*ibp == '/') {
+ /* If a comment, copy it unchanged or discard it. */
+ if (ibp[1] == '\\' && ibp[2] == '\n')
+ newline_fix (ibp + 1);
+ if (ibp[1] == '*') {
+ if (put_out_comments) {
+ *obp++ = '/';
+ *obp++ = '*';
+ } else if (! traditional) {
+ *obp++ = ' ';
+ }
+ for (ibp += 2; ibp < limit; ibp++) {
+ /* We need not worry about newline-marks,
+ since they are never found in comments. */
+ if (ibp[0] == '*') {
+ if (ibp[1] == '\\' && ibp[2] == '\n')
+ newline_fix (ibp + 1);
+ if (ibp[1] == '/') {
+ ibp += 2;
+ if (put_out_comments) {
+ *obp++ = '*';
+ *obp++ = '/';
+ }
+ break;
+ }
+ }
+ if (*ibp == '\n') {
+ /* Newline in a file. Count it. */
+ ++ip->lineno;
+ ++op->lineno;
+ }
+ if (put_out_comments)
+ *obp++ = *ibp;
+ }
+ } else if (ibp[1] == '/' && cplusplus_comments) {
+ if (put_out_comments) {
+ *obp++ = '/';
+ *obp++ = '/';
+ } else if (! traditional) {
+ *obp++ = ' ';
+ }
+ for (ibp += 2; *ibp != '\n' || ibp[-1] == '\\'; ibp++)
+ if (put_out_comments)
+ *obp++ = *ibp;
+ } else
+ break;
+ }
+ else if (ibp[0] == '\\' && ibp[1] == '\n') {
+ ibp += 2;
+ ++ip->lineno;
+ }
else break;
}
if (*ibp != '(') {
@@ -3493,9 +3491,9 @@ randomchar:
if (!traditional && obp != op->buf) {
switch (obp[-1]) {
case '!': case '%': case '&': case '*':
- case '+': case '-': case '/': case ':':
- case '<': case '=': case '>': case '^':
- case '|':
+ case '+': case '-': case '.': case '/':
+ case ':': case '<': case '=': case '>':
+ case '^': case '|':
/* If we are expanding a macro arg, make a newline marker
to separate the tokens. If we are making real output,
a plain space will do. */
@@ -3604,9 +3602,14 @@ expand_to_temp_buffer (buf, limit, output_marks, assertions)
obuf.length = length * 2 + 100; /* Usually enough. Why be stingy? */
obuf.bufp = obuf.buf = (U_CHAR *) xmalloc (obuf.length);
+ obuf.nominal_fname = 0;
+ obuf.inc = 0;
+ obuf.dir = 0;
obuf.fname = 0;
obuf.macro = 0;
+ obuf.if_stack = 0;
obuf.free_ptr = 0;
+ obuf.system_header_p = 0;
CHECK_DEPTH ({return obuf;});
@@ -3615,6 +3618,8 @@ expand_to_temp_buffer (buf, limit, output_marks, assertions)
ip = &instack[indepth];
ip->fname = 0;
ip->nominal_fname = 0;
+ ip->nominal_fname_len = 0;
+ ip->inc = 0;
ip->system_header_p = 0;
ip->macro = 0;
ip->free_ptr = 0;
@@ -3680,8 +3685,11 @@ handle_directive (ip, op)
if (*bp != ' ' && *bp != '\t' && pedantic)
pedwarn ("%s in preprocessing directive", char_name[*bp]);
bp++;
- } else if (*bp == '/' && (bp[1] == '*'
- || (cplusplus_comments && bp[1] == '/'))) {
+ } else if (*bp == '/') {
+ if (bp[1] == '\\' && bp[2] == '\n')
+ newline_fix (bp + 1);
+ if (! (bp[1] == '*' || (cplusplus_comments && bp[1] == '/')))
+ break;
ip->bufp = bp + 2;
skip_to_end_of_comment (ip, &ip->lineno, 0);
bp = ip->bufp;
@@ -3773,7 +3781,7 @@ handle_directive (ip, op)
limit = ip->buf + ip->length;
unterminated = 0;
already_output = 0;
- keep_comments = traditional && kt->traditional_comments;
+ keep_comments = traditional && kt->type == T_DEFINE;
/* #import is defined only in Objective C, or when on the NeXT. */
if (kt->type == T_IMPORT
&& !(objc || lookup ((U_CHAR *) "__NeXT__", -1, -1)))
@@ -3799,8 +3807,25 @@ handle_directive (ip, op)
}
break;
+ case '"':
+ /* "..." is special for #include. */
+ if (IS_INCLUDE_DIRECTIVE_TYPE (kt->type)) {
+ while (bp < limit && *bp != '\n') {
+ if (*bp == '"') {
+ bp++;
+ break;
+ }
+ if (*bp == '\\' && bp[1] == '\n') {
+ ip->lineno++;
+ copy_directive = 1;
+ bp++;
+ }
+ bp++;
+ }
+ break;
+ }
+ /* Fall through. */
case '\'':
- case '\"':
bp = skip_quoted_string (bp - 1, limit, ip->lineno, &ip->lineno, &copy_directive, &unterminated);
/* Don't bother calling the directive if we already got an error
message due to unterminated string. Skip everything and pretend
@@ -3818,7 +3843,7 @@ handle_directive (ip, op)
/* <...> is special for #include. */
case '<':
- if (!kt->angle_brackets)
+ if (! IS_INCLUDE_DIRECTIVE_TYPE (kt->type))
break;
while (bp < limit && *bp != '>' && *bp != '\n') {
if (*bp == '\\' && bp[1] == '\n') {
@@ -3841,9 +3866,14 @@ handle_directive (ip, op)
bp = ip->bufp;
/* No need to copy the directive because of a comment at the end;
just don't include the comment in the directive. */
- if (bp == limit || *bp == '\n') {
- bp = obp;
- goto endloop1;
+ if (!put_out_comments) {
+ U_CHAR *p;
+ for (p = bp; *p == ' ' || *p == '\t'; p++)
+ continue;
+ if (*p == '\n') {
+ bp = obp;
+ goto endloop1;
+ }
}
/* Don't remove the comments if -traditional. */
if (! keep_comments)
@@ -3872,9 +3902,12 @@ handle_directive (ip, op)
RESUME_P is the next interesting data after the directive.
A comment may come between. */
- /* If a directive should be copied through, and -E was given,
+ /* If a directive should be copied through, and -C was given,
pass it through before removing comments. */
- if (!no_output && kt->pass_thru && put_out_comments) {
+ if (!no_output && put_out_comments
+ && (kt->type == T_DEFINE ? dump_macros == dump_definitions
+ : IS_INCLUDE_DIRECTIVE_TYPE (kt->type) ? dump_includes
+ : kt->type == T_PRAGMA)) {
int len;
/* Output directive name. */
@@ -3923,7 +3956,7 @@ handle_directive (ip, op)
/* <...> is special for #include. */
case '<':
- if (!kt->angle_brackets)
+ if (! IS_INCLUDE_DIRECTIVE_TYPE (kt->type))
break;
while (xp < bp && c != '>') {
c = *xp++;
@@ -3958,13 +3991,7 @@ handle_directive (ip, op)
= skip_quoted_string (xp - 1, bp, ip->lineno,
NULL_PTR, NULL_PTR, NULL_PTR);
while (xp != bp1)
- if (*xp == '\\') {
- if (*++xp != '\n')
- *cp++ = '\\';
- else
- xp++;
- } else
- *cp++ = *xp++;
+ *cp++ = *xp++;
}
break;
@@ -3998,13 +4025,12 @@ handle_directive (ip, op)
/* Some directives should be written out for cc1 to process,
just as if they were not defined. And sometimes we're copying
- definitions through. */
+ directives through. */
if (!no_output && already_output == 0
- && (kt->pass_thru
- || (kt->type == T_DEFINE
- && (dump_macros == dump_names
- || dump_macros == dump_definitions)))) {
+ && (kt->type == T_DEFINE ? (int) dump_names <= (int) dump_macros
+ : IS_INCLUDE_DIRECTIVE_TYPE (kt->type) ? dump_includes
+ : kt->type == T_PRAGMA)) {
int len;
/* Output directive name. */
@@ -4013,13 +4039,8 @@ handle_directive (ip, op)
bcopy (kt->name, (char *) op->bufp, kt->length);
op->bufp += kt->length;
- if (kt->pass_thru || dump_macros == dump_definitions) {
- /* Output arguments. */
- len = (cp - buf);
- check_expand (op, len);
- bcopy (buf, (char *) op->bufp, len);
- op->bufp += len;
- } else if (kt->type == T_DEFINE && dump_macros == dump_names) {
+ if (kt->type == T_DEFINE && dump_macros == dump_names) {
+ /* Output `#define name' only. */
U_CHAR *xp = buf;
U_CHAR *yp;
SKIP_WHITE_SPACE (xp);
@@ -4028,16 +4049,21 @@ handle_directive (ip, op)
len = (xp - yp);
check_expand (op, len + 1);
*op->bufp++ = ' ';
- bcopy (yp, op->bufp, len);
- op->bufp += len;
+ bcopy (yp, (char *) op->bufp, len);
+ } else {
+ /* Output entire directive. */
+ len = (cp - buf);
+ check_expand (op, len);
+ bcopy (buf, (char *) op->bufp, len);
}
+ op->bufp += len;
} /* Don't we need a newline or #line? */
/* Call the appropriate directive handler. buf now points to
either the appropriate place in the input buffer, or to
the temp buffer if it was necessary to make one. cp
points to the first char after the contents of the (possibly
- copied) directive, in either case. */
+ copied) directive, in either case. */
(*kt->func) (buf, cp, op, kt);
check_expand (op, ip->length - (ip->bufp - ip->buf));
@@ -4055,7 +4081,7 @@ timestamp ()
{
static struct tm *timebuf;
if (!timebuf) {
- time_t t = time ((time_t *)0);
+ time_t t = time ((time_t *) 0);
timebuf = localtime (&t);
}
return timebuf;
@@ -4102,16 +4128,14 @@ special_symbol (hp, op)
case T_FILE:
case T_BASE_FILE:
{
- char *string;
- if (hp->type == T_FILE)
- string = ip->nominal_fname;
- else
- string = instack[0].nominal_fname;
+ FILE_BUF *p = hp->type == T_FILE ? ip : &instack[0];
+ char *string = p->nominal_fname;
if (string)
{
- buf = (char *) alloca (3 + 4 * strlen (string));
- quote_string (buf, string);
+ size_t string_len = p->nominal_fname_len;
+ buf = (char *) alloca (3 + 4 * string_len);
+ quote_string (buf, string, string_len);
}
else
buf = "\"\"";
@@ -4164,6 +4188,12 @@ special_symbol (hp, op)
case T_CONST:
buf = hp->value.cpval;
+#ifdef STDC_0_IN_SYSTEM_HEADERS
+ if (ip->system_header_p
+ && hp->length == 8 && bcmp (hp->name, "__STDC__", 8) == 0
+ && !lookup ((U_CHAR *) "__STRICT_ANSI__", -1, -1))
+ buf = "0";
+#endif
if (pcp_inside_if && pcp_outfile)
/* Output a precondition for this macro use */
fprintf (pcp_outfile, "#define %s %s\n", hp->name, buf);
@@ -4198,11 +4228,13 @@ special_symbol (hp, op)
if (!is_idstart[*ip->bufp])
goto oops;
+ if (ip->bufp[0] == 'L' && (ip->bufp[1] == '\'' || ip->bufp[1] == '"'))
+ goto oops;
if ((hp = lookup (ip->bufp, -1, -1))) {
if (pcp_outfile && pcp_inside_if
&& (hp->type == T_CONST
|| (hp->type == T_MACRO && hp->value.defn->predefined)))
- /* Output a precondition for this macro use. */
+ /* Output a precondition for this macro use. */
fprintf (pcp_outfile, "#define %s\n", hp->name);
buf = " 1 ";
}
@@ -4254,29 +4286,41 @@ do_include (buf, limit, op, keyword)
FILE_BUF *op;
struct directive *keyword;
{
- int importing = (keyword->type == T_IMPORT);
+ U_CHAR *importing = keyword->type == T_IMPORT ? (U_CHAR *) "" : (U_CHAR *) 0;
int skip_dirs = (keyword->type == T_INCLUDE_NEXT);
static int import_warning = 0;
char *fname; /* Dynamically allocated fname buffer */
char *pcftry;
char *pcfname;
- U_CHAR *fbeg, *fend; /* Beginning and end of fname */
+ char *fbeg, *fend; /* Beginning and end of fname */
+ U_CHAR *fin;
struct file_name_list *search_start = include; /* Chain of dirs to search */
- struct file_name_list dsp[1]; /* First in chain, if #include "..." */
+ struct file_name_list *dsp; /* First in chain, if #include "..." */
struct file_name_list *searchptr = 0;
size_t flen;
- int f; /* file number */
+ int f = -3; /* file number */
+ struct include_file *inc = 0;
int retried = 0; /* Have already tried macro
expanding the include line*/
int angle_brackets = 0; /* 0 for "...", 1 for <...> */
+#ifdef VMS
+ int vaxc_include = 0; /* 1 for token without punctuation */
+#endif
int pcf = -1;
char *pcfbuf;
char *pcfbuflimit;
int pcfnum;
- f= -1; /* JF we iz paranoid! */
+
+ if (pedantic && !instack[indepth].system_header_p)
+ {
+ if (importing)
+ pedwarn ("ANSI C does not allow `#import'");
+ if (skip_dirs)
+ pedwarn ("ANSI C does not allow `#include_next'");
+ }
if (importing && warn_import && !inhibit_warnings
&& !instack[indepth].system_header_p && !import_warning) {
@@ -4296,25 +4340,28 @@ do_include (buf, limit, op, keyword)
get_filename:
- fbeg = buf;
- SKIP_WHITE_SPACE (fbeg);
+ fin = buf;
+ SKIP_WHITE_SPACE (fin);
/* Discard trailing whitespace so we can easily see
if we have parsed all the significant chars we were given. */
- while (limit != fbeg && is_hor_space[limit[-1]]) limit--;
+ while (limit != fin && is_hor_space[limit[-1]]) limit--;
+ fbeg = fend = (char *) alloca (limit - fin);
- switch (*fbeg++) {
+ switch (*fin++) {
case '\"':
{
FILE_BUF *fp;
/* Copy the operand text, concatenating the strings. */
{
- U_CHAR *fin = fbeg;
- fbeg = (U_CHAR *) alloca (limit - fbeg + 1);
- fend = fbeg;
- while (fin != limit) {
- while (fin != limit && *fin != '\"')
- *fend++ = *fin++;
- fin++;
+ for (;;) {
+ for (;;) {
+ if (fin == limit)
+ goto invalid_include_file_name;
+ *fend = *fin++;
+ if (*fend == '"')
+ break;
+ fend++;
+ }
if (fin == limit)
break;
/* If not at the end, there had better be another string. */
@@ -4326,48 +4373,46 @@ get_filename:
goto fail;
}
}
- *fend = 0;
/* We have "filename". Figure out directory this source
- file is coming from and put it on the front of the list. */
+ file is coming from and put it on the front of the list. */
- /* If -I- was specified, don't search current dir, only spec'd ones. */
+ /* If -I- was specified, don't search current dir, only spec'd ones. */
if (ignore_srcdir) break;
for (fp = &instack[indepth]; fp >= instack; fp--)
{
int n;
- char *ep,*nam;
+ char *nam;
if ((nam = fp->nominal_fname) != NULL) {
/* Found a named file. Figure out dir of the file,
and put it in front of the search list. */
- dsp[0].next = search_start;
- search_start = dsp;
-#ifndef VMS
- ep = rindex (nam, '/');
-#ifdef DIR_SEPARATOR
- if (ep == NULL) ep = rindex (nam, DIR_SEPARATOR);
- else {
- char *tmp = rindex (nam, DIR_SEPARATOR);
- if (tmp != NULL && tmp > ep) ep = tmp;
- }
+ dsp = ((struct file_name_list *)
+ alloca (sizeof (struct file_name_list)
+ + fp->nominal_fname_len));
+ strcpy (dsp->fname, nam);
+ simplify_filename (dsp->fname);
+ nam = base_name (dsp->fname);
+ *nam = 0;
+#ifdef VMS
+ /* for hack_vms_include_specification(), a local
+ dir specification must start with "./" on VMS. */
+ if (nam == dsp->fname)
+ {
+ *nam++ = '.';
+ *nam++ = '/';
+ *nam = 0;
+ }
#endif
-#else /* VMS */
- ep = rindex (nam, ']');
- if (ep == NULL) ep = rindex (nam, '>');
- if (ep == NULL) ep = rindex (nam, ':');
- if (ep != NULL) ep++;
-#endif /* VMS */
- if (ep != NULL) {
- n = ep - nam;
- dsp[0].fname = (char *) alloca (n + 1);
- strncpy (dsp[0].fname, nam, n);
- dsp[0].fname[n] = '\0';
+ /* But for efficiency's sake, do not insert the dir
+ if it matches the search list's first dir. */
+ dsp->next = search_start;
+ if (!search_start || strcmp (dsp->fname, search_start->fname)) {
+ search_start = dsp;
+ n = nam - dsp->fname;
if (n + INCLUDE_LEN_FUDGE > max_include_len)
max_include_len = n + INCLUDE_LEN_FUDGE;
- } else {
- dsp[0].fname = 0; /* Current directory */
}
dsp[0].got_name_map = 0;
break;
@@ -4377,13 +4422,12 @@ get_filename:
}
case '<':
- fend = fbeg;
- while (fend != limit && *fend != '>') fend++;
- if (*fend == '>' && fend + 1 == limit) {
+ while (fin != limit && *fin != '>')
+ *fend++ = *fin++;
+ if (*fin == '>' && fin + 1 == limit) {
angle_brackets = 1;
/* If -I-, start with the first -I dir after the -I-. */
- if (first_bracket_include)
- search_start = first_bracket_include;
+ search_start = first_bracket_include;
break;
}
goto fail;
@@ -4396,31 +4440,35 @@ get_filename:
* code from case '<' is repeated here) and generates a warning.
* (Note: macro expansion of `xyz' takes precedence.)
*/
- if (retried && isalpha(*(--fbeg))) {
- fend = fbeg;
- while (fend != limit && (!isspace(*fend))) fend++;
+ /* Note: The argument of ISALPHA() can be evaluated twice, so do
+ the pre-decrement outside of the macro. */
+ if (retried && (--fin, ISALPHA(*(U_CHAR *) (fin)))) {
+ while (fin != limit && (!ISSPACE(*fin)))
+ *fend++ = *fin++;
warning ("VAX-C-style include specification found, use '#include <filename.h>' !");
- if (fend == limit) {
+ vaxc_include = 1;
+ if (fin == limit) {
angle_brackets = 1;
/* If -I-, start with the first -I dir after the -I-. */
- if (first_bracket_include)
- search_start = first_bracket_include;
+ search_start = first_bracket_include;
break;
}
}
#endif
fail:
- if (retried) {
- error ("`#%s' expects \"FILENAME\" or <FILENAME>", keyword->name);
- return 0;
- } else {
+ if (! retried) {
/* Expand buffer and then remove any newline markers.
We can't just tell expand_to_temp_buffer to omit the markers,
since it would put extra spaces in include file names. */
FILE_BUF trybuf;
U_CHAR *src;
+ int errors_before_expansion = errors;
trybuf = expand_to_temp_buffer (buf, limit, 1, 0);
+ if (errors != errors_before_expansion) {
+ free (trybuf.buf);
+ goto invalid_include_file_name;
+ }
src = trybuf.buf;
buf = (U_CHAR *) alloca (trybuf.bufp - trybuf.buf + 1);
limit = buf;
@@ -4444,9 +4492,13 @@ get_filename:
}
*limit = 0;
free (trybuf.buf);
- retried++;
+ retried = 1;
goto get_filename;
}
+
+ invalid_include_file_name:
+ error ("`#%s' expects \"FILENAME\" or <FILENAME>", keyword->name);
+ return 0;
}
/* For #include_next, skip in the search path
@@ -4463,7 +4515,8 @@ get_filename:
}
}
- flen = fend - fbeg;
+ *fend = 0;
+ flen = simplify_filename (fbeg);
if (flen == 0)
{
@@ -4473,121 +4526,132 @@ get_filename:
/* Allocate this permanently, because it gets stored in the definitions
of macros. */
- fname = xmalloc (max_include_len + flen + 4);
- /* + 2 above for slash and terminating null. */
- /* + 2 added for '.h' on VMS (to support '#include filename') */
+ fname = xmalloc (max_include_len + flen + 1);
+ /* + 1 above for terminating null. */
+
+ system_include_depth += angle_brackets;
/* If specified file name is absolute, just open it. */
- if (*fbeg == '/'
-#ifdef DIR_SEPARATOR
- || *fbeg == DIR_SEPARATOR
-#endif
- ) {
- strncpy (fname, (char *) fbeg, flen);
- fname[flen] = 0;
- if (redundant_include_p (fname))
- return 0;
- if (importing)
- f = lookup_import (fname, NULL_PTR);
- else
- f = open_include_file (fname, NULL_PTR);
- if (f == -2)
- return 0; /* Already included this file */
+ if (absolute_filename (fbeg)) {
+ strcpy (fname, fbeg);
+ f = open_include_file (fname, NULL_PTR, importing, &inc);
} else {
+
+ struct bypass_dir {
+ struct bypass_dir *next;
+ char *fname;
+ struct file_name_list *searchptr;
+ } **bypass_slot = 0;
+
/* Search directory path, trying to open the file.
Copy each filename tried into FNAME. */
for (searchptr = search_start; searchptr; searchptr = searchptr->next) {
- if (searchptr->fname) {
- /* The empty string in a search path is ignored.
- This makes it possible to turn off entirely
- a standard piece of the list. */
- if (searchptr->fname[0] == 0)
- continue;
- strcpy (fname, skip_redundant_dir_prefix (searchptr->fname));
- if (fname[0] && fname[strlen (fname) - 1] != '/')
- strcat (fname, "/");
- } else {
- fname[0] = 0;
+
+ if (searchptr == first_bracket_include) {
+ /* Go to bypass directory if we know we've seen this file before. */
+ static struct bypass_dir *bypass_hashtab[INCLUDE_HASHSIZE];
+ struct bypass_dir *p;
+ bypass_slot = &bypass_hashtab[hashf ((U_CHAR *) fbeg, flen,
+ INCLUDE_HASHSIZE)];
+ for (p = *bypass_slot; p; p = p->next)
+ if (!strcmp (fbeg, p->fname)) {
+ searchptr = p->searchptr;
+ bypass_slot = 0;
+ break;
+ }
}
- strncat (fname, (char *) fbeg, flen);
+
#ifdef VMS
/* Change this 1/2 Unix 1/2 VMS file specification into a
full VMS file specification */
- if (searchptr->fname && (searchptr->fname[0] != 0)) {
- /* Fix up the filename */
- hack_vms_include_specification (fname);
- } else {
- /* This is a normal VMS filespec, so use it unchanged. */
- strncpy (fname, fbeg, flen);
- fname[flen] = 0;
- /* if it's '#include filename', add the missing .h */
- if (index(fname,'.')==NULL) {
- strcat (fname, ".h");
+ if (searchptr->fname[0])
+ {
+ strcpy (fname, searchptr->fname);
+ if (fname[strlen (fname) - 1] == ':')
+ {
+ char *slashp;
+ slashp = strchr (fbeg, '/');
+
+ /* start at root-dir of logical device if no path given. */
+ if (slashp == 0)
+ strcat (fname, "[000000]");
+ }
+ strcat (fname, fbeg);
+
+ /* Fix up the filename */
+ hack_vms_include_specification (fname, vaxc_include);
}
- }
-#endif /* VMS */
- /* ??? There are currently 3 separate mechanisms for avoiding processing
- of redundant include files: #import, #pragma once, and
- redundant_include_p. It would be nice if they were unified. */
- if (redundant_include_p (fname))
- return 0;
- if (importing)
- f = lookup_import (fname, searchptr);
else
- f = open_include_file (fname, searchptr);
- if (f == -2)
- return 0; /* Already included this file */
-#ifdef EACCES
- else if (f == -1 && errno == EACCES)
- warning ("Header file %s exists, but is not readable", fname);
-#endif
- if (f >= 0)
+ {
+ /* This is a normal VMS filespec, so use it unchanged. */
+ strcpy (fname, fbeg);
+ /* if it's '#include filename', add the missing .h */
+ if (vaxc_include && index(fname,'.')==NULL)
+ strcat (fname, ".h");
+ }
+#else
+ strcpy (fname, searchptr->fname);
+ strcat (fname, fbeg);
+#endif /* VMS */
+ f = open_include_file (fname, searchptr, importing, &inc);
+ if (f != -1) {
+ if (bypass_slot && searchptr != first_bracket_include) {
+ /* This is the first time we found this include file,
+ and we found it after first_bracket_include.
+ Record its location so that we can bypass to here next time. */
+ struct bypass_dir *p
+ = (struct bypass_dir *) xmalloc (sizeof (struct bypass_dir));
+ p->next = *bypass_slot;
+ p->fname = fname + strlen (searchptr->fname);
+ p->searchptr = searchptr;
+ *bypass_slot = p;
+ }
+ break;
+ }
+#ifdef VMS
+ /* Our VMS hacks can produce invalid filespecs, so don't worry
+ about errors other than EACCES. */
+ if (errno == EACCES)
break;
+#else
+ if (errno != ENOENT && errno != ENOTDIR)
+ break;
+#endif
}
}
+
if (f < 0) {
- /* A file that was not found. */
- strncpy (fname, (char *) fbeg, flen);
- fname[flen] = 0;
+ if (f == -2) {
+ /* The file was already included. */
+
/* If generating dependencies and -MG was specified, we assume missing
files are leaf files, living in the same directory as the source file
or other similar place; these missing files may be generated from
other files and may not exist yet (eg: y.tab.h). */
- if (print_deps_missing_files
- && print_deps > (angle_brackets || (system_include_depth > 0)))
+ } else if (print_deps_missing_files
+ && (system_include_depth != 0) < print_deps)
{
/* If it was requested as a system header file,
then assume it belongs in the first place to look for such. */
if (angle_brackets)
{
- for (searchptr = search_start; searchptr; searchptr = searchptr->next)
- {
- if (searchptr->fname)
- {
- char *p;
-
- if (searchptr->fname[0] == 0)
- continue;
- p = (char *) alloca (strlen (searchptr->fname)
- + strlen (fname) + 2);
- strcpy (p, skip_redundant_dir_prefix (searchptr->fname));
- if (p[0] && p[strlen (p) - 1] != '/')
- strcat (p, "/");
- strcat (p, fname);
- deps_output (p, ' ');
- break;
- }
- }
+ if (search_start) {
+ char *p = (char *) alloca (strlen (search_start->fname)
+ + strlen (fbeg) + 1);
+ strcpy (p, search_start->fname);
+ strcat (p, fbeg);
+ deps_output (p, ' ');
+ }
}
else
{
/* Otherwise, omit the directory, as if the file existed
in the directory with the source. */
- deps_output (fname, ' ');
+ deps_output (fbeg, ' ');
}
}
/* If -M was specified, and this header file won't be added to the
@@ -4595,57 +4659,16 @@ get_filename:
still produce correct output. Otherwise, we can't produce correct
output, because there may be dependencies we need inside the missing
file, and we don't know what directory this missing file exists in. */
- else if (print_deps
- && (print_deps <= (angle_brackets || (system_include_depth > 0))))
- warning ("No include path in which to find %s", fname);
- else if (search_start)
- error_from_errno (fname);
+ else if (0 < print_deps && print_deps <= (system_include_depth != 0))
+ warning ("No include path in which to find %s", fbeg);
+ else if (f != -3)
+ error_from_errno (fbeg);
else
- error ("No include path in which to find %s", fname);
- } else {
- /* Check to see if this include file is a once-only include file.
- If so, give up. */
-
- struct file_name_list* ptr;
-
- for (ptr = dont_repeat_files; ptr; ptr = ptr->next) {
- if (!strcmp (ptr->fname, fname)) {
- close (f);
- return 0; /* This file was once'd. */
- }
- }
-
- for (ptr = all_include_files; ptr; ptr = ptr->next) {
- if (!strcmp (ptr->fname, fname))
- break; /* This file was included before. */
- }
+ error ("No include path in which to find %s", fbeg);
- if (ptr == 0) {
- /* This is the first time for this file. */
- /* Add it to list of files included. */
-
- ptr = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
- ptr->control_macro = 0;
- ptr->c_system_include_path = 0;
- ptr->next = all_include_files;
- all_include_files = ptr;
- ptr->fname = savestring (fname);
- ptr->got_name_map = 0;
-
- /* For -M, add this file to the dependencies. */
- if (print_deps > (angle_brackets || (system_include_depth > 0)))
- deps_output (fname, ' ');
- }
-
- /* Handle -H option. */
- if (print_include_names)
- fprintf (stderr, "%*s%s\n", indepth, "", fname);
-
- if (angle_brackets)
- system_include_depth++;
+ } else {
/* Actually process the file. */
- add_import (f, fname); /* Record file on "seen" list for #import. */
pcftry = (char *) alloca (strlen (fname) + 30);
pcfbuf = 0;
@@ -4653,10 +4676,6 @@ get_filename:
if (!no_precomp)
{
- struct stat stat_f;
-
- fstat (f, &stat_f);
-
do {
sprintf (pcftry, "%s%d", fname, pcfnum++);
@@ -4665,12 +4684,12 @@ get_filename:
{
struct stat s;
- fstat (pcf, &s);
- if (bcmp ((char *) &stat_f.st_ino, (char *) &s.st_ino,
- sizeof (s.st_ino))
- || stat_f.st_dev != s.st_dev)
+ if (fstat (pcf, &s) != 0)
+ pfatal_with_name (pcftry);
+ if (! INO_T_EQ (inc->st.st_ino, s.st_ino)
+ || inc->st.st_dev != s.st_dev)
{
- pcfbuf = check_precompiled (pcf, fname, &pcfbuflimit);
+ pcfbuf = check_precompiled (pcf, &s, fname, &pcfbuflimit);
/* Don't need it any more. */
close (pcf);
}
@@ -4692,28 +4711,11 @@ get_filename:
(U_CHAR *) fname, op);
}
else
- finclude (f, fname, op, is_system_include (fname), searchptr);
-
- if (angle_brackets)
- system_include_depth--;
+ finclude (f, inc, op, is_system_include (fname), searchptr);
}
- return 0;
-}
-/* Return nonzero if there is no need to include file NAME
- because it has already been included and it contains a conditional
- to make a repeated include do nothing. */
+ system_include_depth -= angle_brackets;
-static int
-redundant_include_p (name)
- char *name;
-{
- struct file_name_list *l = all_include_files;
- for (; l; l = l->next)
- if (! strcmp (name, l->fname)
- && l->control_macro
- && lookup (l->control_macro, -1, -1))
- return 1;
return 0;
}
@@ -4736,38 +4738,127 @@ is_system_include (filename)
for (searchptr = first_system_include; searchptr;
searchptr = searchptr->next)
- if (searchptr->fname) {
- register char *sys_dir = skip_redundant_dir_prefix (searchptr->fname);
- register unsigned length = strlen (sys_dir);
+ if (! strncmp (searchptr->fname, filename, strlen (searchptr->fname)))
+ return searchptr->c_system_include_path + 1;
+ return 0;
+}
+
+/* Yield the non-directory suffix of a file name. */
+
+static char *
+base_name (fname)
+ char *fname;
+{
+ char *s = fname;
+ char *p;
+#if defined (__MSDOS__) || defined (_WIN32)
+ if (ISALPHA (s[0]) && s[1] == ':') s += 2;
+#endif
+#ifdef VMS
+ if ((p = rindex (s, ':'))) s = p + 1; /* Skip device. */
+ if ((p = rindex (s, ']'))) s = p + 1; /* Skip directory. */
+ if ((p = rindex (s, '>'))) s = p + 1; /* Skip alternate (int'n'l) dir. */
+ if (s != fname)
+ return s;
+#endif
+ if ((p = rindex (s, '/'))) s = p + 1;
+#ifdef DIR_SEPARATOR
+ if ((p = rindex (s, DIR_SEPARATOR))) s = p + 1;
+#endif
+ return s;
+}
- if (! strncmp (sys_dir, filename, length)
- && (filename[length] == '/'
+/* Yield nonzero if FILENAME is absolute (i.e. not relative). */
+
+static int
+absolute_filename (filename)
+ char *filename;
+{
+#if defined (__MSDOS__) || (defined (_WIN32) && !defined (__CYGWIN32__))
+ if (ISALPHA (filename[0]) && filename[1] == ':') filename += 2;
+#endif
+#if defined (__CYGWIN32__)
+ /* At present, any path that begins with a drive spec is absolute. */
+ if (ISALPHA (filename[0]) && filename[1] == ':') return 1;
+#endif
+#ifdef VMS
+ if (index (filename, ':') != 0) return 1;
+#endif
+ if (filename[0] == '/') return 1;
#ifdef DIR_SEPARATOR
- || filename[length] == DIR_SEPARATOR
+ if (filename[0] == DIR_SEPARATOR) return 1;
#endif
- )) {
- if (searchptr->c_system_include_path)
- return 2;
- else
- return 1;
- }
- }
return 0;
}
-
-/* Skip leading "./" from a directory name.
- This may yield the empty string, which represents the current directory. */
-static char *
-skip_redundant_dir_prefix (dir)
- char *dir;
+/* Remove unnecessary characters from FILENAME in place,
+ to avoid unnecessary filename aliasing.
+ Return the length of the resulting string.
+
+ Do only the simplifications allowed by Posix.
+ It is OK to miss simplifications on non-Posix hosts,
+ since this merely leads to suboptimal results. */
+
+static size_t
+simplify_filename (filename)
+ char *filename;
{
- while (dir[0] == '.' && dir[1] == '/')
- for (dir += 2; *dir == '/'; dir++)
- continue;
- if (dir[0] == '.' && !dir[1])
- dir++;
- return dir;
+ register char *from = filename;
+ register char *to = filename;
+ char *to0;
+
+ /* Remove redundant initial /s. */
+ if (*from == '/') {
+ *to++ = '/';
+ if (*++from == '/') {
+ if (*++from == '/') {
+ /* 3 or more initial /s are equivalent to 1 /. */
+ while (*++from == '/')
+ continue;
+ } else {
+ /* On some hosts // differs from /; Posix allows this. */
+ static int slashslash_vs_slash;
+ if (slashslash_vs_slash == 0) {
+ struct stat s1, s2;
+ slashslash_vs_slash = ((stat ("/", &s1) == 0 && stat ("//", &s2) == 0
+ && INO_T_EQ (s1.st_ino, s2.st_ino)
+ && s1.st_dev == s2.st_dev)
+ ? 1 : -1);
+ }
+ if (slashslash_vs_slash < 0)
+ *to++ = '/';
+ }
+ }
+ }
+ to0 = to;
+
+ for (;;) {
+#ifndef VMS
+ if (from[0] == '.' && from[1] == '/')
+ from += 2;
+ else
+#endif
+ {
+ /* Copy this component and trailing /, if any. */
+ while ((*to++ = *from++) != '/') {
+ if (!to[-1]) {
+ /* Trim . component at end of nonempty name. */
+ to -= filename <= to - 3 && to[-3] == '/' && to[-2] == '.';
+
+ /* Trim unnecessary trailing /s. */
+ while (to0 < --to && to[-1] == '/')
+ continue;
+
+ *to = 0;
+ return to - filename;
+ }
+ }
+ }
+
+ /* Skip /s after a /. */
+ while (*from == '/')
+ from++;
+ }
}
/* The file_name_map structure holds a mapping of file names for a
@@ -4819,7 +4910,9 @@ read_filename_string (ch, f)
return alloc;
}
-/* Read the file name map file for DIRNAME. */
+/* Read the file name map file for DIRNAME.
+ If DIRNAME is empty, read the map file for the working directory;
+ otherwise DIRNAME must end in '/'. */
static struct file_name_map *
read_name_map (dirname)
@@ -4838,9 +4931,6 @@ read_name_map (dirname)
char *name;
FILE *f;
size_t dirlen;
- int separator_needed;
-
- dirname = skip_redundant_dir_prefix (dirname);
for (map_list_ptr = map_list; map_list_ptr;
map_list_ptr = map_list_ptr->map_list_next)
@@ -4853,11 +4943,9 @@ read_name_map (dirname)
map_list_ptr->map_list_map = NULL;
dirlen = strlen (dirname);
- separator_needed = dirlen != 0 && dirname[dirlen - 1] != '/';
- name = (char *) alloca (dirlen + strlen (FILE_NAME_MAP_FILE) + 2);
+ name = (char *) alloca (dirlen + strlen (FILE_NAME_MAP_FILE) + 1);
strcpy (name, dirname);
- name[dirlen] = '/';
- strcpy (name + dirlen + separator_needed, FILE_NAME_MAP_FILE);
+ strcat (name, FILE_NAME_MAP_FILE);
f = fopen (name, "r");
if (!f)
map_list_ptr->map_list_map = NULL;
@@ -4869,6 +4957,7 @@ read_name_map (dirname)
{
char *from, *to;
struct file_name_map *ptr;
+ size_t tolen;
if (is_space[ch])
continue;
@@ -4877,19 +4966,21 @@ read_name_map (dirname)
;
to = read_filename_string (ch, f);
+ simplify_filename (from);
+ tolen = simplify_filename (to);
+
ptr = ((struct file_name_map *)
xmalloc (sizeof (struct file_name_map)));
ptr->map_from = from;
/* Make the real filename absolute. */
- if (*to == '/')
+ if (absolute_filename (to))
ptr->map_to = to;
else
{
- ptr->map_to = xmalloc (dirlen + strlen (to) + 2);
+ ptr->map_to = xmalloc (dirlen + tolen + 1);
strcpy (ptr->map_to, dirname);
- ptr->map_to[dirlen] = '/';
- strcpy (ptr->map_to + dirlen + separator_needed, to);
+ strcat (ptr->map_to, to);
free (to);
}
@@ -4910,85 +5001,162 @@ read_name_map (dirname)
}
/* Try to open include file FILENAME. SEARCHPTR is the directory
- being tried from the include file search path. This function maps
- filenames on file systems based on information read by
+ being tried from the include file search path.
+ IMPORTING is "" if we are importing, null otherwise.
+ Return -2 if found, either a matching name or a matching inode.
+ Otherwise, open the file and return a file descriptor if successful
+ or -1 if unsuccessful.
+ Unless unsuccessful, put a descriptor of the included file into *PINC.
+ This function maps filenames on file systems based on information read by
read_name_map. */
static int
-open_include_file (filename, searchptr)
+open_include_file (filename, searchptr, importing, pinc)
+ char *filename;
+ struct file_name_list *searchptr;
+ U_CHAR *importing;
+ struct include_file **pinc;
+{
+ char *fname = remap ? remap_include_file (filename, searchptr) : filename;
+ int fd = -2;
+
+ /* Look up FNAME in include_hashtab. */
+ struct include_file **phead = &include_hashtab[hashf ((U_CHAR *) fname,
+ strlen (fname),
+ INCLUDE_HASHSIZE)];
+ struct include_file *inc, *head = *phead;
+ for (inc = head; inc; inc = inc->next)
+ if (!strcmp (fname, inc->fname))
+ break;
+
+ if (!inc
+ || ! inc->control_macro
+ || (inc->control_macro[0] && ! lookup (inc->control_macro, -1, -1))) {
+
+ fd = open (fname, O_RDONLY, 0);
+
+ if (fd < 0)
+ {
+#ifdef VMS
+ /* if #include <dir/file> fails, try again with hacked spec. */
+ if (!hack_vms_include_specification (fname, 0))
+ return fd;
+ fd = open (fname, O_RDONLY, 0);
+ if (fd < 0)
+#endif
+ return fd;
+ }
+
+ if (!inc) {
+ /* FNAME was not in include_hashtab; insert a new entry. */
+ inc = (struct include_file *) xmalloc (sizeof (struct include_file));
+ inc->next = head;
+ inc->fname = fname;
+ inc->control_macro = 0;
+ inc->deps_output = 0;
+ if (fstat (fd, &inc->st) != 0)
+ pfatal_with_name (fname);
+ *phead = inc;
+
+ /* Look for another file with the same inode and device. */
+ if (lookup_ino_include (inc)
+ && inc->control_macro
+ && (!inc->control_macro[0] || lookup (inc->control_macro, -1, -1))) {
+ close (fd);
+ fd = -2;
+ }
+ }
+
+ /* For -M, add this file to the dependencies. */
+ if (! inc->deps_output && (system_include_depth != 0) < print_deps) {
+ inc->deps_output = 1;
+ deps_output (fname, ' ');
+ }
+
+ /* Handle -H option. */
+ if (print_include_names)
+ fprintf (stderr, "%*s%s\n", indepth, "", fname);
+ }
+
+ if (importing)
+ inc->control_macro = importing;
+
+ *pinc = inc;
+ return fd;
+}
+
+/* Return the remapped name of the include file FILENAME.
+ SEARCHPTR is the directory being tried from the include file path. */
+
+static char *
+remap_include_file (filename, searchptr)
char *filename;
struct file_name_list *searchptr;
{
register struct file_name_map *map;
register char *from;
- char *p, *dir;
- if (searchptr && ! searchptr->got_name_map)
+ if (searchptr)
{
- searchptr->name_map = read_name_map (searchptr->fname
- ? searchptr->fname : ".");
- searchptr->got_name_map = 1;
- }
-
- /* First check the mapping for the directory we are using. */
- if (searchptr && searchptr->name_map)
- {
- from = filename;
- if (searchptr->fname)
- from += strlen (searchptr->fname) + 1;
- for (map = searchptr->name_map; map; map = map->map_next)
+ if (! searchptr->got_name_map)
{
- if (! strcmp (map->map_from, from))
- {
- /* Found a match. */
- return open (map->map_to, O_RDONLY, 0666);
- }
+ searchptr->name_map = read_name_map (searchptr->fname);
+ searchptr->got_name_map = 1;
}
- }
- /* Try to find a mapping file for the particular directory we are
- looking in. Thus #include <sys/types.h> will look up sys/types.h
- in /usr/include/header.gcc and look up types.h in
- /usr/include/sys/header.gcc. */
- p = rindex (filename, '/');
-#ifdef DIR_SEPARATOR
- if (! p) p = rindex (filename, DIR_SEPARATOR);
- else {
- char *tmp = rindex (filename, DIR_SEPARATOR);
- if (tmp != NULL && tmp > p) p = tmp;
- }
-#endif
- if (! p)
- p = filename;
- if (searchptr
- && searchptr->fname
- && strlen (searchptr->fname) == p - filename
- && ! strncmp (searchptr->fname, filename, p - filename))
- {
- /* FILENAME is in SEARCHPTR, which we've already checked. */
- return open (filename, O_RDONLY, 0666);
+ /* Check the mapping for the directory we are using. */
+ from = filename + strlen (searchptr->fname);
+ for (map = searchptr->name_map; map; map = map->map_next)
+ if (! strcmp (map->map_from, from))
+ return map->map_to;
}
- if (p == filename)
+ from = base_name (filename);
+
+ if (from != filename || !searchptr)
{
- dir = ".";
- from = filename;
+ /* Try to find a mapping file for the particular directory we are
+ looking in. Thus #include <sys/types.h> will look up sys/types.h
+ in /usr/include/header.gcc and look up types.h in
+ /usr/include/sys/header.gcc. */
+
+ char *dir = (char *) alloca (from - filename + 1);
+ bcopy (filename, dir, from - filename);
+ dir[from - filename] = '\0';
+
+ for (map = read_name_map (dir); map; map = map->map_next)
+ if (! strcmp (map->map_from, from))
+ return map->map_to;
}
- else
- {
- dir = (char *) alloca (p - filename + 1);
- bcopy (filename, dir, p - filename);
- dir[p - filename] = '\0';
- from = p + 1;
+
+ return filename;
+}
+
+/* Insert INC into the include file table, hashed by device and inode number.
+ If a file with different name but same dev+ino was already in the table,
+ return 1 and set INC's control macro to the already-known macro. */
+
+static int
+lookup_ino_include (inc)
+ struct include_file *inc;
+{
+ int hash = ((unsigned) (inc->st.st_dev + INO_T_HASH (inc->st.st_ino))
+ % INCLUDE_HASHSIZE);
+ struct include_file *i = include_ino_hashtab[hash];
+ inc->next_ino = i;
+ include_ino_hashtab[hash] = inc;
+
+ for (; i; i = i->next_ino)
+ if (INO_T_EQ (inc->st.st_ino, i->st.st_ino)
+ && inc->st.st_dev == i->st.st_dev) {
+ inc->control_macro = i->control_macro;
+ return 1;
}
- for (map = read_name_map (dir); map; map = map->map_next)
- if (! strcmp (map->map_from, from))
- return open (map->map_to, O_RDONLY, 0666);
- return open (filename, O_RDONLY, 0666);
+ return 0;
}
-/* Process the contents of include file FNAME, already open on descriptor F,
+/* Process file descriptor F, which corresponds to include file INC,
with output to OP.
SYSTEM_HEADER_P is 1 if this file resides in any one of the known
"system" include directories (as decided by the `is_system_include'
@@ -4997,58 +5165,55 @@ open_include_file (filename, searchptr)
or 0 if the file name was absolute. */
static void
-finclude (f, fname, op, system_header_p, dirptr)
+finclude (f, inc, op, system_header_p, dirptr)
int f;
- char *fname;
+ struct include_file *inc;
FILE_BUF *op;
int system_header_p;
struct file_name_list *dirptr;
{
- int st_mode;
- long st_size;
- long i;
+ char *fname = inc->fname;
+ int i;
FILE_BUF *fp; /* For input stack frame */
int missing_newline = 0;
CHECK_DEPTH (return;);
- if (file_size_and_mode (f, &st_mode, &st_size) < 0)
- {
- perror_with_name (fname);
- close (f);
- return;
- }
-
fp = &instack[indepth + 1];
bzero ((char *) fp, sizeof (FILE_BUF));
fp->nominal_fname = fp->fname = fname;
+ fp->nominal_fname_len = strlen (fname);
+ fp->inc = inc;
fp->length = 0;
fp->lineno = 1;
fp->if_stack = if_stack;
fp->system_header_p = system_header_p;
fp->dir = dirptr;
- if (S_ISREG (st_mode)) {
- fp->buf = (U_CHAR *) xmalloc (st_size + 2);
+ if (S_ISREG (inc->st.st_mode)) {
+ size_t s = (size_t) inc->st.st_size;
+ if (s != inc->st.st_size || s + 2 < s)
+ memory_full ();
+ fp->buf = (U_CHAR *) xmalloc (s + 2);
fp->bufp = fp->buf;
- /* Read the file contents, knowing that st_size is an upper bound
+ /* Read the file contents, knowing that s is an upper bound
on the number of bytes we can read. */
- fp->length = safe_read (f, (char *) fp->buf, st_size);
+ fp->length = safe_read (f, (char *) fp->buf, s);
if (fp->length < 0) goto nope;
}
- else if (S_ISDIR (st_mode)) {
+ else if (S_ISDIR (inc->st.st_mode)) {
error ("directory `%s' specified in #include", fname);
close (f);
return;
} else {
/* Cannot count its file size before reading.
First read the entire file into heap and
- copy them into buffer on stack. */
+ copy them into buffer on stack. */
int bsize = 2000;
+ int st_size = 0;
- st_size = 0;
fp->buf = (U_CHAR *) xmalloc (bsize + 2);
for (;;) {
@@ -5107,158 +5272,53 @@ finclude (f, fname, op, system_header_p, dirptr)
free (fp->buf);
}
-/* Record that inclusion of the file named FILE
+/* Record that inclusion of the include file INC
should be controlled by the macro named MACRO_NAME.
This means that trying to include the file again
will do something if that macro is defined. */
static void
-record_control_macro (file, macro_name)
- char *file;
+record_control_macro (inc, macro_name)
+ struct include_file *inc;
U_CHAR *macro_name;
{
- struct file_name_list *new;
-
- for (new = all_include_files; new; new = new->next) {
- if (!strcmp (new->fname, file)) {
- new->control_macro = macro_name;
- return;
- }
- }
-
- /* If the file is not in all_include_files, something's wrong. */
- abort ();
-}
-
-/* Maintain and search list of included files, for #import. */
-
-#define IMPORT_HASH_SIZE 31
-
-struct import_file {
- char *name;
- ino_t inode;
- dev_t dev;
- struct import_file *next;
-};
-
-/* Hash table of files already included with #include or #import. */
-
-static struct import_file *import_hash_table[IMPORT_HASH_SIZE];
-
-/* Hash a file name for import_hash_table. */
-
-static int
-import_hash (f)
- char *f;
-{
- int val = 0;
-
- while (*f) val += *f++;
- return (val%IMPORT_HASH_SIZE);
-}
-
-/* Search for file FILENAME in import_hash_table.
- Return -2 if found, either a matching name or a matching inode.
- Otherwise, open the file and return a file descriptor if successful
- or -1 if unsuccessful. */
-
-static int
-lookup_import (filename, searchptr)
- char *filename;
- struct file_name_list *searchptr;
-{
- struct import_file *i;
- int h;
- int hashval;
- struct stat sb;
- int fd;
-
- hashval = import_hash (filename);
-
- /* Attempt to find file in list of already included files */
- i = import_hash_table[hashval];
-
- while (i) {
- if (!strcmp (filename, i->name))
- return -2; /* return found */
- i = i->next;
- }
- /* Open it and try a match on inode/dev */
- fd = open_include_file (filename, searchptr);
- if (fd < 0)
- return fd;
- fstat (fd, &sb);
- for (h = 0; h < IMPORT_HASH_SIZE; h++) {
- i = import_hash_table[h];
- while (i) {
- /* Compare the inode and the device.
- Supposedly on some systems the inode is not a scalar. */
- if (!bcmp ((char *) &i->inode, (char *) &sb.st_ino, sizeof (sb.st_ino))
- && i->dev == sb.st_dev) {
- close (fd);
- return -2; /* return found */
- }
- i = i->next;
- }
- }
- return fd; /* Not found, return open file */
-}
-
-/* Add the file FNAME, open on descriptor FD, to import_hash_table. */
-
-static void
-add_import (fd, fname)
- int fd;
- char *fname;
-{
- struct import_file *i;
- int hashval;
- struct stat sb;
-
- hashval = import_hash (fname);
- fstat (fd, &sb);
- i = (struct import_file *)xmalloc (sizeof (struct import_file));
- i->name = xmalloc (strlen (fname)+1);
- strcpy (i->name, fname);
- bcopy ((char *) &sb.st_ino, (char *) &i->inode, sizeof (sb.st_ino));
- i->dev = sb.st_dev;
- i->next = import_hash_table[hashval];
- import_hash_table[hashval] = i;
+ if (!inc->control_macro || inc->control_macro[0])
+ inc->control_macro = macro_name;
}
/* Load the specified precompiled header into core, and verify its
preconditions. PCF indicates the file descriptor to read, which must
- be a regular file. FNAME indicates the file name of the original
- header. *LIMIT will be set to an address one past the end of the file.
+ be a regular file. *ST is its file status.
+ FNAME indicates the file name of the original header.
+ *LIMIT will be set to an address one past the end of the file.
If the preconditions of the file are not satisfied, the buffer is
freed and we return 0. If the preconditions are satisfied, return
the address of the buffer following the preconditions. The buffer, in
this case, should never be freed because various pieces of it will
be referred to until all precompiled strings are output at the end of
- the run.
-*/
+ the run. */
+
static char *
-check_precompiled (pcf, fname, limit)
+check_precompiled (pcf, st, fname, limit)
int pcf;
- char *fname;
+ struct stat *st;
+ char *fname ATTRIBUTE_UNUSED;
char **limit;
{
- int st_mode;
- long st_size;
int length = 0;
char *buf;
char *cp;
if (pcp_outfile)
return 0;
-
- if (file_size_and_mode (pcf, &st_mode, &st_size) < 0)
- return 0;
- if (S_ISREG (st_mode))
+ if (S_ISREG (st->st_mode))
{
- buf = xmalloc (st_size + 2);
- length = safe_read (pcf, buf, st_size);
+ size_t s = (size_t) st->st_size;
+ if (s != st->st_size || s + 2 < s)
+ memory_full ();
+ buf = xmalloc (s + 2);
+ length = safe_read (pcf, buf, s);
if (length < 0)
goto nope;
}
@@ -5271,7 +5331,7 @@ check_precompiled (pcf, fname, limit)
*limit = buf + length;
- /* File is in core. Check the preconditions. */
+ /* File is in core. Check the preconditions. */
if (!check_preconditions (buf))
goto nope;
for (cp = buf; *cp; cp++)
@@ -5293,6 +5353,7 @@ check_precompiled (pcf, fname, limit)
precompiled header. These are a series of #define and #undef
lines which must match the current contents of the hash
table. */
+
static int
check_preconditions (prec)
char *prec;
@@ -5351,7 +5412,8 @@ check_preconditions (prec)
/* Process the main body of a precompiled file. BUF points to the
string section of the file, following the preconditions. LIMIT is one
character past the end. NAME is the name of the file being read
- in. OP is the main output buffer */
+ in. OP is the main output buffer. */
+
static void
pcfinclude (buf, limit, name, op)
U_CHAR *buf, *limit, *name;
@@ -5368,7 +5430,7 @@ pcfinclude (buf, limit, name, op)
nstrings = (nstrings << 8) | *cp++;
nstrings = (nstrings << 8) | *cp++;
- /* Looping over each string... */
+ /* Looping over each string... */
while (nstrings--) {
U_CHAR *string_start;
U_CHAR *endofthiskey;
@@ -5380,14 +5442,14 @@ pcfinclude (buf, limit, name, op)
/* First skip to a longword boundary */
/* ??? Why a 4-byte boundary? On all machines? */
- /* NOTE: This works correctly even if HOST_WIDE_INT
+ /* NOTE: This works correctly even if size_t
is narrower than a pointer.
Do not try risky measures here to get another type to use!
Do not include stddef.h--it will fail! */
- if ((HOST_WIDE_INT) cp & 3)
- cp += 4 - ((HOST_WIDE_INT) cp & 3);
+ if ((size_t) cp & 3)
+ cp += 4 - ((size_t) cp & 3);
- /* Now get the string. */
+ /* Now get the string. */
str = (STRINGDEF *) (GENERIC_PTR) cp;
string_start = cp += sizeof (STRINGDEF);
@@ -5397,7 +5459,7 @@ pcfinclude (buf, limit, name, op)
/* We need to macro expand the string here to ensure that the
proper definition environment is in place. If it were only
expanded when we find out it is needed, macros necessary for
- its proper expansion might have had their definitions changed. */
+ its proper expansion might have had their definitions changed. */
tmpbuf = expand_to_temp_buffer (string_start, cp++, 0, 0);
/* Lineno is already set in the precompiled file */
str->contents = tmpbuf.buf;
@@ -5410,14 +5472,14 @@ pcfinclude (buf, limit, name, op)
*stringlist_tailp = str;
stringlist_tailp = &str->chain;
- /* Next comes a fourbyte number indicating the number of keys */
- /* for this string. */
+ /* Next comes a fourbyte number indicating the number of keys
+ for this string. */
nkeys = *cp++;
nkeys = (nkeys << 8) | *cp++;
nkeys = (nkeys << 8) | *cp++;
nkeys = (nkeys << 8) | *cp++;
- /* If this number is -1, then the string is mandatory. */
+ /* If this number is -1, then the string is mandatory. */
if (nkeys == -1)
str->writeflag = 1;
else
@@ -5430,11 +5492,11 @@ pcfinclude (buf, limit, name, op)
cp += sizeof (KEYDEF);
/* Find the end of the key. At the end of this for loop we
- advance CP to the start of the next key using this variable. */
+ advance CP to the start of the next key using this variable. */
endofthiskey = cp + strlen ((char *) cp);
kp->str = str;
- /* Expand the key, and enter it into the hash table. */
+ /* Expand the key, and enter it into the hash table. */
tmpbuf = expand_to_temp_buffer (cp, endofthiskey, 0, 0);
tmpbuf.bufp = tmpbuf.buf;
@@ -5461,12 +5523,13 @@ pcfinclude (buf, limit, name, op)
}
/* This output_line_directive serves to switch us back to the current
input file in case some of these strings get output (which will
- result in line directives for the header file being output). */
+ result in line directives for the header file being output). */
output_line_directive (&instack[indepth], op, 0, enter_file);
}
-/* Called from rescan when it hits a key for strings. Mark them all */
- /* used and clean up. */
+/* Called from rescan when it hits a key for strings. Mark them all
+ used and clean up. */
+
static void
pcstring_used (hp)
HASHNODE *hp;
@@ -5478,8 +5541,9 @@ pcstring_used (hp)
delete_macro (hp);
}
-/* Write the output, interspersing precompiled strings in their */
- /* appropriate places. */
+/* Write the output, interspersing precompiled strings in their
+ appropriate places. */
+
static void
write_output ()
{
@@ -5489,10 +5553,10 @@ write_output ()
char *line_directive = xmalloc (line_directive_len);
int len;
- /* In each run through the loop, either cur_buf_loc == */
- /* next_string_loc, in which case we print a series of strings, or */
- /* it is less than next_string_loc, in which case we write some of */
- /* the buffer. */
+ /* In each run through the loop, either cur_buf_loc ==
+ next_string_loc, in which case we print a series of strings, or
+ it is less than next_string_loc, in which case we write some of
+ the buffer. */
cur_buf_loc = outbuf.buf;
next_string = stringlist;
@@ -5506,7 +5570,8 @@ write_output ()
line_directive_len *= 2);
sprintf (line_directive, "\n# %d ", next_string->lineno);
strcpy (quote_string (line_directive + strlen (line_directive),
- (char *) next_string->filename),
+ (char *) next_string->filename,
+ strlen ((char *) next_string->filename)),
"\n");
safe_write (fileno (stdout), line_directive, strlen (line_directive));
safe_write (fileno (stdout),
@@ -5565,7 +5630,7 @@ pass_thru_directive (buf, limit, op, keyword)
appeared. So the arglist is just convenience data passed
between these two routines. It is not kept around after
the current #define has been processed and entered into the
- hash table. */
+ hash table. */
struct arglist {
struct arglist *next;
@@ -5576,7 +5641,8 @@ struct arglist {
};
/* Create a DEFINITION node from a #define directive. Arguments are
- as for do_define. */
+ as for do_define. */
+
static MACRODEF
create_definition (buf, limit, op)
U_CHAR *buf, *limit;
@@ -5587,6 +5653,7 @@ create_definition (buf, limit, op)
int sym_length; /* and how long it is */
int line = instack[indepth].lineno;
char *file = instack[indepth].nominal_fname;
+ size_t file_len = instack[indepth].nominal_fname_len;
int rest_args = 0;
DEFINITION *defn;
@@ -5605,7 +5672,7 @@ create_definition (buf, limit, op)
/* Lossage will occur if identifiers or control keywords are broken
across lines using backslash. This is not the right place to take
- care of that. */
+ care of that. */
if (*bp == '(') {
struct arglist *arg_ptrs = NULL;
@@ -5636,8 +5703,10 @@ create_definition (buf, limit, op)
while (is_idchar[*bp]) {
bp++;
/* do we have a "special" rest-args extension here? */
- if (limit - bp > REST_EXTENSION_LENGTH &&
- bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) {
+ if (limit - bp > REST_EXTENSION_LENGTH
+ && bcmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) {
+ if (pedantic && !instack[indepth].system_header_p)
+ pedwarn ("ANSI C does not allow macro with variable arguments");
rest_args = 1;
temp->rest_args = 1;
break;
@@ -5669,8 +5738,8 @@ create_definition (buf, limit, op)
struct arglist *otemp;
for (otemp = temp->next; otemp != NULL; otemp = otemp->next)
- if (temp->length == otemp->length &&
- bcmp (temp->name, otemp->name, temp->length) == 0) {
+ if (temp->length == otemp->length
+ && bcmp (temp->name, otemp->name, temp->length) == 0) {
error ("duplicate argument name `%.*s' in `#define'",
temp->length, temp->name);
goto nope;
@@ -5680,7 +5749,7 @@ create_definition (buf, limit, op)
++bp; /* skip paren */
SKIP_WHITE_SPACE (bp);
- /* now everything from bp before limit is the definition. */
+ /* now everything from bp before limit is the definition. */
defn = collect_expansion (bp, limit, argno, arg_ptrs);
defn->rest_args = rest_args;
@@ -5709,7 +5778,7 @@ create_definition (buf, limit, op)
if (is_hor_space[*bp]) {
bp++;
SKIP_WHITE_SPACE (bp);
- } else {
+ } else if (sym_length) {
switch (*bp) {
case '!': case '"': case '#': case '%': case '&': case '\'':
case ')': case '*': case '+': case ',': case '-': case '.':
@@ -5727,13 +5796,14 @@ create_definition (buf, limit, op)
}
}
}
- /* Now everything from bp before limit is the definition. */
+ /* Now everything from bp before limit is the definition. */
defn = collect_expansion (bp, limit, -1, NULL_PTR);
defn->args.argnames = (U_CHAR *) "";
}
defn->line = line;
defn->file = file;
+ defn->file_len = file_len;
/* OP is null if this is a predefinition */
defn->predefined = !op;
@@ -5794,7 +5864,9 @@ do_define (buf, limit, op, keyword)
pedwarn ("`%.*s' redefined", mdef.symlen, mdef.symnam);
if (hp->type == T_MACRO)
- pedwarn_with_file_and_line (hp->value.defn->file, hp->value.defn->line,
+ pedwarn_with_file_and_line (hp->value.defn->file,
+ hp->value.defn->file_len,
+ hp->value.defn->line,
"this is the location of the previous definition");
}
/* Replace the old definition. */
@@ -5831,7 +5903,8 @@ check_macro_name (symname, usage)
for (p = symname; is_idchar[*p]; p++)
;
sym_length = p - symname;
- if (sym_length == 0)
+ if (sym_length == 0
+ || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
error ("invalid %s name", usage);
else if (!is_idstart[*symname]
|| (sym_length == 7 && ! bcmp (symname, "defined", 7)))
@@ -5839,9 +5912,8 @@ check_macro_name (symname, usage)
return sym_length;
}
-/*
- * return zero if two DEFINITIONs are isomorphic
- */
+/* Return zero if two DEFINITIONs are isomorphic. */
+
static int
compare_defs (d1, d2)
DEFINITION *d1, *d2;
@@ -5853,7 +5925,8 @@ compare_defs (d1, d2)
if (d1->nargs != d2->nargs)
return 1;
- if (strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames))
+ if (pedantic
+ && strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames))
return 1;
for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
a1 = a1->next, a2 = a2->next) {
@@ -5950,7 +6023,7 @@ collect_expansion (buf, end, nargs, arglist)
/* Scan thru the replacement list, ignoring comments and quoted
strings, picking up on the macro calls. It does a linear search
thru the arg list on every potential symbol. Profiling might say
- that something smarter should happen. */
+ that something smarter should happen. */
if (end < buf)
abort ();
@@ -6058,7 +6131,8 @@ collect_expansion (buf, end, nargs, arglist)
p++;
SKIP_WHITE_SPACE (p);
}
- if (! is_idstart[*p] || nargs == 0)
+ if (! is_idstart[*p] || nargs == 0
+ || (*p == 'L' && (p[1] == '\'' || p[1] == '"')))
error ("`#' operator is not followed by a macro argument name");
else
stringify = p;
@@ -6067,7 +6141,7 @@ collect_expansion (buf, end, nargs, arglist)
}
} else {
/* In -traditional mode, recognize arguments inside strings and
- and character constants, and ignore special properties of #.
+ character constants, and ignore special properties of #.
Arguments inside strings are considered "stringified", but no
extra quote marks are supplied. */
switch (c) {
@@ -6097,9 +6171,12 @@ collect_expansion (buf, end, nargs, arglist)
this must be -traditional. So replace the comment with
nothing at all. */
exp_p--;
- p += 1;
- while (p < limit && !(p[-2] == '*' && p[-1] == '/'))
- p++;
+ while (++p < limit) {
+ if (p[0] == '*' && p[1] == '/') {
+ p += 2;
+ break;
+ }
+ }
#if 0
/* Mark this as a concatenation-point, as if it had been ##. */
concat = p;
@@ -6118,7 +6195,8 @@ collect_expansion (buf, end, nargs, arglist)
while (p != limit && is_idchar[*p]) p++;
id_len = p - id_beg;
- if (is_idstart[c]) {
+ if (is_idstart[c]
+ && ! (id_len == 1 && c == 'L' && (*p == '\'' || *p == '"'))) {
register struct arglist *arg;
for (arg = arglist; arg != NULL; arg = arg->next) {
@@ -6220,8 +6298,8 @@ collect_expansion (buf, end, nargs, arglist)
static int
do_assert (buf, limit, op, keyword)
U_CHAR *buf, *limit;
- FILE_BUF *op;
- struct directive *keyword;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
U_CHAR *bp; /* temp ptr into input buffer */
U_CHAR *symname; /* remember where symbol name starts */
@@ -6244,7 +6322,7 @@ do_assert (buf, limit, op, keyword)
/* Lossage will occur if identifiers or control tokens are broken
across lines using backslash. This is not the right place to take
- care of that. */
+ care of that. */
if (*bp != '(') {
error ("missing token-sequence in `#assert'");
@@ -6297,8 +6375,8 @@ do_assert (buf, limit, op, keyword)
static int
do_unassert (buf, limit, op, keyword)
U_CHAR *buf, *limit;
- FILE_BUF *op;
- struct directive *keyword;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
U_CHAR *bp; /* temp ptr into input buffer */
U_CHAR *symname; /* remember where symbol name starts */
@@ -6323,7 +6401,7 @@ do_unassert (buf, limit, op, keyword)
/* Lossage will occur if identifiers or control tokens are broken
across lines using backslash. This is not the right place to take
- care of that. */
+ care of that. */
if (*bp == '(') {
int error_flag = 0;
@@ -6537,15 +6615,14 @@ free_token_list (tokens)
}
}
-/*
- * Install a name in the assertion hash table.
- *
- * If LEN is >= 0, it is the length of the name.
- * Otherwise, compute the length by scanning the entire name.
- *
- * If HASH is >= 0, it is the precomputed hash code.
- * Otherwise, compute the hash code.
- */
+/* Install a name in the assertion hash table.
+
+ If LEN is >= 0, it is the length of the name.
+ Otherwise, compute the length by scanning the entire name.
+
+ If HASH is >= 0, it is the precomputed hash code.
+ Otherwise, compute the hash code. */
+
static ASSERTION_HASHNODE *
assertion_install (name, len, hash)
U_CHAR *name;
@@ -6576,16 +6653,15 @@ assertion_install (name, len, hash)
return hp;
}
-/*
- * find the most recent hash node for name name (ending with first
- * non-identifier char) installed by install
- *
- * If LEN is >= 0, it is the length of the name.
- * Otherwise, compute the length by scanning the entire name.
- *
- * If HASH is >= 0, it is the precomputed hash code.
- * Otherwise, compute the hash code.
- */
+/* Find the most recent hash node for name "name" (ending with first
+ non-identifier char) installed by install
+
+ If LEN is >= 0, it is the length of the name.
+ Otherwise, compute the length by scanning the entire name.
+
+ If HASH is >= 0, it is the precomputed hash code.
+ Otherwise, compute the hash code. */
+
static ASSERTION_HASHNODE *
assertion_lookup (name, len, hash)
U_CHAR *name;
@@ -6613,8 +6689,8 @@ delete_assertion (hp)
if (hp->next != NULL)
hp->next->prev = hp->prev;
- /* make sure that the bucket chain header that
- the deleted guy was on points to the right thing afterwards. */
+ /* Make sure that the bucket chain header that the deleted guy was
+ on points to the right thing afterwards. */
if (hp == *hp->bucket_hdr)
*hp->bucket_hdr = hp->next;
@@ -6631,7 +6707,7 @@ static int
do_line (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
register U_CHAR *bp;
FILE_BUF *ip = &instack[indepth];
@@ -6646,7 +6722,7 @@ do_line (buf, limit, op, keyword)
bp = tem.buf;
SKIP_WHITE_SPACE (bp);
- if (!isdigit (*bp)) {
+ if (!ISDIGIT (*bp)) {
error ("invalid format `#line' directive");
return 0;
}
@@ -6661,7 +6737,7 @@ do_line (buf, limit, op, keyword)
pedwarn ("line number out of range in `#line' directive");
/* skip over the line number. */
- while (isdigit (*bp))
+ while (ISDIGIT (*bp))
bp++;
#if 0 /* #line 10"foo.c" is supposed to be allowed. */
@@ -6693,7 +6769,7 @@ do_line (buf, limit, op, keyword)
case '\\':
{
char *bpc = (char *) bp;
- int c = parse_escape (&bpc);
+ HOST_WIDE_INT c = parse_escape (&bpc, (HOST_WIDE_INT) (U_CHAR) (-1));
bp = (U_CHAR *) bpc;
if (c < 0)
p--;
@@ -6703,7 +6779,7 @@ do_line (buf, limit, op, keyword)
break;
case '\"':
- p[-1] = 0;
+ *--p = 0;
goto fname_done;
}
fname_done:
@@ -6744,12 +6820,12 @@ do_line (buf, limit, op, keyword)
}
}
- hash_bucket =
- &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)];
+ hash_bucket = &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)];
for (hp = *hash_bucket; hp != NULL; hp = hp->next)
if (hp->length == fname_length &&
bcmp (hp->value.cpval, fname, fname_length) == 0) {
ip->nominal_fname = hp->value.cpval;
+ ip->nominal_fname_len = fname_length;
break;
}
if (hp == 0) {
@@ -6758,9 +6834,9 @@ do_line (buf, limit, op, keyword)
hp->next = *hash_bucket;
*hash_bucket = hp;
- hp->length = fname_length;
ip->nominal_fname = hp->value.cpval = ((char *) hp) + sizeof (HASHNODE);
- bcopy (fname, hp->value.cpval, fname_length);
+ ip->nominal_fname_len = hp->length = fname_length;
+ bcopy (fname, hp->value.cpval, fname_length + 1);
}
} else if (*bp) {
error ("invalid format `#line' directive");
@@ -6773,11 +6849,9 @@ do_line (buf, limit, op, keyword)
return 0;
}
-/*
- * remove the definition of a symbol from the symbol table.
- * according to un*x /lib/cpp, it is not an error to undef
- * something that has no definitions, so it isn't one here either.
- */
+/* Remove the definition of a symbol from the symbol table.
+ according to un*x /lib/cpp, it is not an error to undef
+ something that has no definitions, so it isn't one here either. */
static int
do_undef (buf, limit, op, keyword)
@@ -6815,20 +6889,18 @@ do_undef (buf, limit, op, keyword)
return 0;
}
-/*
- * Report an error detected by the program we are processing.
- * Use the text of the line in the error message.
- * (We use error because it prints the filename & line#.)
- */
+/* Report an error detected by the program we are processing.
+ Use the text of the line in the error message.
+ (We use error because it prints the filename & line#.) */
static int
do_error (buf, limit, op, keyword)
U_CHAR *buf, *limit;
- FILE_BUF *op;
- struct directive *keyword;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
int length = limit - buf;
- U_CHAR *copy = (U_CHAR *) xmalloc (length + 1);
+ U_CHAR *copy = (U_CHAR *) alloca (length + 1);
bcopy ((char *) buf, (char *) copy, length);
copy[length] = 0;
SKIP_WHITE_SPACE (copy);
@@ -6836,24 +6908,28 @@ do_error (buf, limit, op, keyword)
return 0;
}
-/*
- * Report a warning detected by the program we are processing.
- * Use the text of the line in the warning message, then continue.
- * (We use error because it prints the filename & line#.)
- */
+/* Report a warning detected by the program we are processing.
+ Use the text of the line in the warning message, then continue.
+ (We use error because it prints the filename & line#.) */
static int
do_warning (buf, limit, op, keyword)
U_CHAR *buf, *limit;
- FILE_BUF *op;
- struct directive *keyword;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
int length = limit - buf;
- U_CHAR *copy = (U_CHAR *) xmalloc (length + 1);
+ U_CHAR *copy = (U_CHAR *) alloca (length + 1);
bcopy ((char *) buf, (char *) copy, length);
copy[length] = 0;
SKIP_WHITE_SPACE (copy);
- warning ("#warning %s", copy);
+
+ if (pedantic && !instack[indepth].system_header_p)
+ pedwarn ("ANSI C does not allow `#warning'");
+
+ /* Use `pedwarn' not `warning', because #warning isn't in the C Standard;
+ if -pedantic-errors is given, #warning should cause an error. */
+ pedwarn ("#warning %s", copy);
return 0;
}
@@ -6864,34 +6940,21 @@ static void
do_once ()
{
int i;
- FILE_BUF *ip = NULL;
for (i = indepth; i >= 0; i--)
- if (instack[i].fname != NULL) {
- ip = &instack[i];
+ if (instack[i].inc) {
+ record_control_macro (instack[i].inc, (U_CHAR *) "");
break;
}
-
- if (ip != NULL) {
- struct file_name_list *new;
-
- new = (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
- new->next = dont_repeat_files;
- dont_repeat_files = new;
- new->fname = savestring (ip->fname);
- new->control_macro = 0;
- new->got_name_map = 0;
- new->c_system_include_path = 0;
- }
}
-/* #ident has already been copied to the output file, so just ignore it. */
+/* Report program identification. */
static int
do_ident (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
FILE_BUF trybuf;
int len;
@@ -6901,22 +6964,17 @@ do_ident (buf, limit, op, keyword)
pedwarn ("ANSI C does not allow `#ident'");
trybuf = expand_to_temp_buffer (buf, limit, 0, 0);
- buf = (U_CHAR *) alloca (trybuf.bufp - trybuf.buf + 1);
- bcopy ((char *) trybuf.buf, (char *) buf, trybuf.bufp - trybuf.buf);
- limit = buf + (trybuf.bufp - trybuf.buf);
- len = (limit - buf);
- free (trybuf.buf);
-
- /* Output directive name. */
- check_expand (op, 7);
+ buf = trybuf.buf;
+ len = trybuf.bufp - buf;
+
+ /* Output expanded directive. */
+ check_expand (op, 7 + len);
bcopy ("#ident ", (char *) op->bufp, 7);
op->bufp += 7;
-
- /* Output the expanded argument line. */
- check_expand (op, len);
bcopy ((char *) buf, (char *) op->bufp, len);
op->bufp += len;
+ free (buf);
return 0;
}
@@ -6925,9 +6983,9 @@ do_ident (buf, limit, op, keyword)
static int
do_pragma (buf, limit, op, keyword)
- U_CHAR *buf, *limit;
- FILE_BUF *op;
- struct directive *keyword;
+ U_CHAR *buf, *limit ATTRIBUTE_UNUSED;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
SKIP_WHITE_SPACE (buf);
if (!strncmp ((char *) buf, "once", 4)) {
@@ -6941,25 +6999,27 @@ do_pragma (buf, limit, op, keyword)
if (!strncmp ((char *) buf, "implementation", 14)) {
/* Be quiet about `#pragma implementation' for a file only if it hasn't
been included yet. */
- struct file_name_list *ptr;
- U_CHAR *p = buf + 14, *fname, *inc_fname;
+
+ int h;
+ U_CHAR *p = buf + 14, *fname;
SKIP_WHITE_SPACE (p);
- if (*p == '\n' || *p != '\"')
+ if (*p != '\"')
return 0;
fname = p + 1;
if ((p = (U_CHAR *) index ((char *) fname, '\"')))
*p = '\0';
- for (ptr = all_include_files; ptr; ptr = ptr->next) {
- inc_fname = (U_CHAR *) rindex (ptr->fname, '/');
- inc_fname = inc_fname ? inc_fname + 1 : (U_CHAR *) ptr->fname;
- if (inc_fname && !strcmp ((char *) inc_fname, (char *) fname))
- warning ("`#pragma implementation' for `%s' appears after file is included",
- fname);
+ for (h = 0; h < INCLUDE_HASHSIZE; h++) {
+ struct include_file *inc;
+ for (inc = include_hashtab[h]; inc; inc = inc->next) {
+ if (!strcmp (base_name (inc->fname), (char *) fname)) {
+ warning ("`#pragma implementation' for \"%s\" appears after its #include",fname);
+ return 0;
+ }
+ }
}
}
-
return 0;
}
@@ -6967,10 +7027,8 @@ do_pragma (buf, limit, op, keyword)
/* This was a fun hack, but #pragma seems to start to be useful.
By failing to recognize it, we pass it through unchanged to cc1. */
-/*
- * the behavior of the #pragma directive is implementation defined.
- * this implementation defines it as follows.
- */
+/* The behavior of the #pragma directive is implementation defined.
+ this implementation defines it as follows. */
static int
do_pragma ()
@@ -6996,9 +7054,9 @@ nope:
static int
do_sccs (buf, limit, op, keyword)
- U_CHAR *buf, *limit;
- FILE_BUF *op;
- struct directive *keyword;
+ U_CHAR *buf ATTRIBUTE_UNUSED, *limit ATTRIBUTE_UNUSED;
+ FILE_BUF *op ATTRIBUTE_UNUSED;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
if (pedantic)
pedwarn ("ANSI C does not allow `#sccs'");
@@ -7007,24 +7065,22 @@ do_sccs (buf, limit, op, keyword)
#endif /* defined (SCCS_DIRECTIVE) */
-/*
- * handle #if directive by
- * 1) inserting special `defined' keyword into the hash table
- * that gets turned into 0 or 1 by special_symbol (thus,
- * if the luser has a symbol called `defined' already, it won't
- * work inside the #if directive)
- * 2) rescan the input into a temporary output buffer
- * 3) pass the output buffer to the yacc parser and collect a value
- * 4) clean up the mess left from steps 1 and 2.
- * 5) call conditional_skip to skip til the next #endif (etc.),
- * or not, depending on the value from step 3.
- */
+/* Handle #if directive by
+ 1) inserting special `defined' keyword into the hash table
+ that gets turned into 0 or 1 by special_symbol (thus,
+ if the luser has a symbol called `defined' already, it won't
+ work inside the #if directive)
+ 2) rescan the input into a temporary output buffer
+ 3) pass the output buffer to the yacc parser and collect a value
+ 4) clean up the mess left from steps 1 and 2.
+ 5) call conditional_skip to skip til the next #endif (etc.),
+ or not, depending on the value from step 3. */
static int
do_if (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
HOST_WIDE_INT value;
FILE_BUF *ip = &instack[indepth];
@@ -7034,16 +7090,14 @@ do_if (buf, limit, op, keyword)
return 0;
}
-/*
- * handle a #elif directive by not changing if_stack either.
- * see the comment above do_else.
- */
+/* Handle a #elif directive by not changing if_stack either.
+ see the comment above do_else. */
static int
do_elif (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
HOST_WIDE_INT value;
FILE_BUF *ip = &instack[indepth];
@@ -7055,9 +7109,12 @@ do_elif (buf, limit, op, keyword)
if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
error ("`#elif' after `#else'");
fprintf (stderr, " (matches line %d", if_stack->lineno);
- if (if_stack->fname != NULL && ip->fname != NULL &&
- strcmp (if_stack->fname, ip->nominal_fname) != 0)
- fprintf (stderr, ", file %s", if_stack->fname);
+ if (! (if_stack->fname_len == ip->nominal_fname_len
+ && !bcmp (if_stack->fname, ip->nominal_fname,
+ if_stack->fname_len))) {
+ fprintf (stderr, ", file ");
+ eprint_string (if_stack->fname, if_stack->fname_len);
+ }
fprintf (stderr, ")\n");
}
if_stack->type = T_ELIF;
@@ -7077,10 +7134,9 @@ do_elif (buf, limit, op, keyword)
return 0;
}
-/*
- * evaluate a #if expression in BUF, of length LENGTH,
- * then parse the result as a C expression and return the value as an int.
- */
+/* Evaluate a #if expression in BUF, of length LENGTH, then parse the
+ result as a C expression and return the value as an int. */
+
static HOST_WIDE_INT
eval_if_expression (buf, length)
U_CHAR *buf;
@@ -7097,18 +7153,18 @@ eval_if_expression (buf, length)
pcp_inside_if = 0;
delete_macro (save_defined); /* clean up special symbol */
- value = parse_c_expression ((char *) temp_obuf.buf);
+ temp_obuf.buf[temp_obuf.length] = '\n';
+ value = parse_c_expression ((char *) temp_obuf.buf,
+ warn_undef && !instack[indepth].system_header_p);
free (temp_obuf.buf);
return value;
}
-/*
- * routine to handle ifdef/ifndef. Try to look up the symbol,
- * then do or don't skip to the #endif/#else/#elif depending
- * on what directive is actually being processed.
- */
+/* routine to handle ifdef/ifndef. Try to look up the symbol, then do
+ or don't skip to the #endif/#else/#elif depending on what directive
+ is actually being processed. */
static int
do_xifdef (buf, limit, op, keyword)
@@ -7165,18 +7221,20 @@ do_xifdef (buf, limit, op, keyword)
} else {
HASHNODE *hp;
- if (pedantic && buf[0] >= '0' && buf[0] <= '9')
- pedwarn ("`#%s' argument starts with a digit", keyword->name);
- else if (end != limit && !traditional)
- pedwarn ("garbage at end of `#%s' argument", keyword->name);
+ if (! traditional) {
+ if (ISDIGIT (buf[0]))
+ pedwarn ("`#%s' argument starts with a digit", keyword->name);
+ else if (end != limit)
+ pedwarn ("garbage at end of `#%s' argument", keyword->name);
+ }
hp = lookup (buf, end-buf, -1);
if (pcp_outfile) {
/* Output a precondition for this macro. */
- if (hp &&
- (hp->type == T_CONST
- || (hp->type == T_MACRO && hp->value.defn->predefined)))
+ if (hp
+ && (hp->type == T_CONST
+ || (hp->type == T_MACRO && hp->value.defn->predefined)))
fprintf (pcp_outfile, "#define %s\n", hp->name);
else {
U_CHAR *cp = buf;
@@ -7216,6 +7274,7 @@ conditional_skip (ip, skip, type, control_macro, op)
temp = (IF_STACK_FRAME *) xcalloc (1, sizeof (IF_STACK_FRAME));
temp->fname = ip->nominal_fname;
+ temp->fname_len = ip->nominal_fname_len;
temp->lineno = ip->lineno;
temp->next = if_stack;
temp->control_macro = control_macro;
@@ -7232,11 +7291,10 @@ conditional_skip (ip, skip, type, control_macro, op)
}
}
-/*
- * skip to #endif, #else, or #elif. adjust line numbers, etc.
- * leaves input ptr at the sharp sign found.
- * If ANY is nonzero, return at next directive of any sort.
- */
+/* Skip to #endif, #else, or #elif. adjust line numbers, etc.
+ Leaves input ptr at the sharp sign found.
+ If ANY is nonzero, return at next directive of any sort. */
+
static void
skip_if_group (ip, any, op)
FILE_BUF *ip;
@@ -7253,6 +7311,7 @@ skip_if_group (ip, any, op)
/* Save info about where the group starts. */
U_CHAR *beg_of_group = bp;
int beg_lineno = ip->lineno;
+ int skipping_include_directive = 0;
if (output_conditionals && op != 0) {
char *ptr = "#failed\n";
@@ -7281,22 +7340,49 @@ skip_if_group (ip, any, op)
bp = skip_to_end_of_comment (ip, &ip->lineno, 0);
}
break;
+ case '<':
+ if (skipping_include_directive) {
+ while (bp < endb && *bp != '>' && *bp != '\n') {
+ if (*bp == '\\' && bp[1] == '\n') {
+ ip->lineno++;
+ bp++;
+ }
+ bp++;
+ }
+ }
+ break;
case '\"':
+ if (skipping_include_directive) {
+ while (bp < endb && *bp != '\n') {
+ if (*bp == '"') {
+ bp++;
+ break;
+ }
+ if (*bp == '\\' && bp[1] == '\n') {
+ ip->lineno++;
+ bp++;
+ }
+ bp++;
+ }
+ break;
+ }
+ /* Fall through. */
case '\'':
bp = skip_quoted_string (bp - 1, endb, ip->lineno, &ip->lineno,
NULL_PTR, NULL_PTR);
break;
case '\\':
- /* Char after backslash loses its special meaning. */
- if (bp < endb) {
- if (*bp == '\n')
- ++ip->lineno; /* But do update the line-count. */
+ /* Char after backslash loses its special meaning in some cases. */
+ if (*bp == '\n') {
+ ++ip->lineno;
+ bp++;
+ } else if (traditional && bp < endb)
bp++;
- }
break;
case '\n':
++ip->lineno;
beg_of_line = bp;
+ skipping_include_directive = 0;
break;
case '%':
if (beg_of_line == 0 || traditional)
@@ -7357,23 +7443,37 @@ skip_if_group (ip, any, op)
bp++;
else if (*bp == '\\' && bp[1] == '\n')
bp += 2;
- else if (*bp == '/' && bp[1] == '*') {
- bp += 2;
- while (!(*bp == '*' && bp[1] == '/')) {
- if (*bp == '\n')
- ip->lineno++;
- bp++;
- }
- bp += 2;
- } else if (cplusplus_comments && *bp == '/' && bp[1] == '/') {
- bp += 2;
- while (bp[-1] == '\\' || *bp != '\n') {
- if (*bp == '\n')
- ip->lineno++;
- bp++;
- }
- }
- else break;
+ else if (*bp == '/') {
+ if (bp[1] == '\\' && bp[2] == '\n')
+ newline_fix (bp + 1);
+ if (bp[1] == '*') {
+ for (bp += 2; ; bp++) {
+ if (*bp == '\n')
+ ip->lineno++;
+ else if (*bp == '*') {
+ if (bp[-1] == '/' && warn_comments)
+ warning ("`/*' within comment");
+ if (bp[1] == '\\' && bp[2] == '\n')
+ newline_fix (bp + 1);
+ if (bp[1] == '/')
+ break;
+ }
+ }
+ bp += 2;
+ } else if (bp[1] == '/' && cplusplus_comments) {
+ for (bp += 2; ; bp++) {
+ if (*bp == '\n') {
+ if (bp[-1] != '\\')
+ break;
+ if (warn_comments)
+ warning ("multiline `//' comment");
+ ip->lineno++;
+ }
+ }
+ } else
+ break;
+ } else
+ break;
}
cp = bp;
@@ -7449,12 +7549,13 @@ skip_if_group (ip, any, op)
if_stack = temp;
temp->lineno = ip->lineno;
temp->fname = ip->nominal_fname;
+ temp->fname_len = ip->nominal_fname_len;
temp->type = kt->type;
break;
case T_ELSE:
case T_ENDIF:
if (pedantic && if_stack != save_if_stack)
- validate_else (bp);
+ validate_else (bp, endb);
case T_ELIF:
if (if_stack == instack[indepth].if_stack) {
error ("`#%s' not within a conditional", kt->name);
@@ -7475,7 +7576,13 @@ skip_if_group (ip, any, op)
free (temp);
break;
- default:
+ case T_INCLUDE:
+ case T_INCLUDE_NEXT:
+ case T_IMPORT:
+ skipping_include_directive = 1;
+ break;
+
+ default:
break;
}
break;
@@ -7514,18 +7621,16 @@ skip_if_group (ip, any, op)
}
}
-/*
- * handle a #else directive. Do this by just continuing processing
- * without changing if_stack ; this is so that the error message
- * for missing #endif's etc. will point to the original #if. It
- * is possible that something different would be better.
- */
+/* Handle a #else directive. Do this by just continuing processing
+ without changing if_stack ; this is so that the error message
+ for missing #endif's etc. will point to the original #if. It
+ is possible that something different would be better. */
static int
do_else (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
FILE_BUF *ip = &instack[indepth];
@@ -7546,8 +7651,12 @@ do_else (buf, limit, op, keyword)
if (if_stack->type != T_IF && if_stack->type != T_ELIF) {
error ("`#else' after `#else'");
fprintf (stderr, " (matches line %d", if_stack->lineno);
- if (strcmp (if_stack->fname, ip->nominal_fname) != 0)
- fprintf (stderr, ", file %s", if_stack->fname);
+ if (! (if_stack->fname_len == ip->nominal_fname_len
+ && !bcmp (if_stack->fname, ip->nominal_fname,
+ if_stack->fname_len))) {
+ fprintf (stderr, ", file ");
+ eprint_string (if_stack->fname, if_stack->fname_len);
+ }
fprintf (stderr, ")\n");
}
if_stack->type = T_ELSE;
@@ -7562,15 +7671,13 @@ do_else (buf, limit, op, keyword)
return 0;
}
-/*
- * unstack after #endif directive
- */
+/* Unstack after #endif directive. */
static int
do_endif (buf, limit, op, keyword)
U_CHAR *buf, *limit;
FILE_BUF *op;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
{
if (pedantic) {
SKIP_WHITE_SPACE (buf);
@@ -7615,7 +7722,7 @@ do_endif (buf, limit, op, keyword)
if (indepth != 0
&& ! (indepth == 1 && no_record_file)
&& ! (no_record_file && no_output))
- record_control_macro (ip->fname, temp->control_macro);
+ record_control_macro (ip->inc, temp->control_macro);
fail: ;
}
free (temp);
@@ -7626,43 +7733,45 @@ do_endif (buf, limit, op, keyword)
/* When an #else or #endif is found while skipping failed conditional,
if -pedantic was specified, this is called to warn about text after
- the directive name. P points to the first char after the directive name. */
+ the directive name. P points to the first char after the directive
+ name. */
static void
-validate_else (p)
+validate_else (p, limit)
register U_CHAR *p;
+ register U_CHAR *limit;
{
/* Advance P over whitespace and comments. */
while (1) {
- if (*p == '\\' && p[1] == '\n')
+ while (*p == '\\' && p[1] == '\n')
p += 2;
if (is_hor_space[*p])
p++;
else if (*p == '/') {
- if (p[1] == '\\' && p[2] == '\n')
- newline_fix (p + 1);
- if (p[1] == '*') {
+ while (p[1] == '\\' && p[2] == '\n')
p += 2;
+ if (p[1] == '*') {
/* Don't bother warning about unterminated comments
since that will happen later. Just be sure to exit. */
- while (*p) {
- if (p[1] == '\\' && p[2] == '\n')
- newline_fix (p + 1);
- if (*p == '*' && p[1] == '/') {
- p += 2;
- break;
+ for (p += 2; ; p++) {
+ if (p == limit)
+ return;
+ if (*p == '*') {
+ while (p[1] == '\\' && p[2] == '\n')
+ p += 2;
+ if (p[1] == '/') {
+ p += 2;
+ break;
+ }
}
- p++;
}
}
- else if (cplusplus_comments && p[1] == '/') {
- p += 2;
- while (*p && (*p != '\n' || p[-1] == '\\'))
- p++;
- }
+ else if (cplusplus_comments && p[1] == '/')
+ return;
+ else break;
} else break;
}
- if (*p && *p != '\n')
+ if (*p != '\n')
pedwarn ("text following `#else' or `#endif' violates ANSI standard");
}
@@ -7673,9 +7782,10 @@ validate_else (p)
counter is not sufficient to deal with newlines in the string.
If NOWARN is nonzero, don't warn about slash-star inside a comment.
- This feature is useful when processing a comment that is going to be
- processed or was processed at another point in the preprocessor,
- to avoid a duplicate warning. Likewise for unterminated comment errors. */
+ This feature is useful when processing a comment that is going to
+ be processed or was processed at another point in the preprocessor,
+ to avoid a duplicate warning. Likewise for unterminated comment
+ errors. */
static U_CHAR *
skip_to_end_of_comment (ip, line_counter, nowarn)
@@ -7685,54 +7795,38 @@ skip_to_end_of_comment (ip, line_counter, nowarn)
{
register U_CHAR *limit = ip->buf + ip->length;
register U_CHAR *bp = ip->bufp;
- FILE_BUF *op = &outbuf; /* JF */
- int output = put_out_comments && !line_counter;
+ FILE_BUF *op = put_out_comments && !line_counter ? &outbuf : (FILE_BUF *) 0;
int start_line = line_counter ? *line_counter : 0;
/* JF this line_counter stuff is a crock to make sure the
comment is only put out once, no matter how many times
the comment is skipped. It almost works */
- if (output) {
+ if (op) {
*op->bufp++ = '/';
- *op->bufp++ = '*';
+ *op->bufp++ = bp[-1];
}
if (cplusplus_comments && bp[-1] == '/') {
- if (output) {
- while (bp < limit) {
- *op->bufp++ = *bp;
- if (*bp == '\n' && bp[-1] != '\\')
+ for (; bp < limit; bp++) {
+ if (*bp == '\n') {
+ if (bp[-1] != '\\')
break;
- if (*bp == '\n') {
+ if (!nowarn && warn_comments)
+ warning ("multiline `//' comment");
+ if (line_counter)
++*line_counter;
+ if (op)
++op->lineno;
- }
- bp++;
- }
- op->bufp[-1] = '*';
- *op->bufp++ = '/';
- *op->bufp++ = '\n';
- } else {
- while (bp < limit) {
- if (bp[-1] != '\\' && *bp == '\n') {
- break;
- } else {
- if (*bp == '\n' && line_counter)
- ++*line_counter;
- bp++;
- }
}
+ if (op)
+ *op->bufp++ = *bp;
}
ip->bufp = bp;
return bp;
}
while (bp < limit) {
- if (output)
+ if (op)
*op->bufp++ = *bp;
switch (*bp++) {
- case '/':
- if (warn_comments && !nowarn && bp < limit && *bp == '*')
- warning ("`/*' within comment");
- break;
case '\n':
/* If this is the end of the file, we have an unterminated comment.
Don't swallow the newline. We are guaranteed that there will be a
@@ -7745,14 +7839,16 @@ skip_to_end_of_comment (ip, line_counter, nowarn)
}
if (line_counter != NULL)
++*line_counter;
- if (output)
+ if (op)
++op->lineno;
break;
case '*':
+ if (bp[-2] == '/' && !nowarn && warn_comments)
+ warning ("`/*' within comment");
if (*bp == '\\' && bp[1] == '\n')
newline_fix (bp);
if (*bp == '/') {
- if (output)
+ if (op)
*op->bufp++ = '/';
ip->bufp = ++bp;
return bp;
@@ -7767,22 +7863,21 @@ skip_to_end_of_comment (ip, line_counter, nowarn)
return bp;
}
-/*
- * Skip over a quoted string. BP points to the opening quote.
- * Returns a pointer after the closing quote. Don't go past LIMIT.
- * START_LINE is the line number of the starting point (but it need
- * not be valid if the starting point is inside a macro expansion).
- *
- * The input stack state is not changed.
- *
- * If COUNT_NEWLINES is nonzero, it points to an int to increment
- * for each newline passed.
- *
- * If BACKSLASH_NEWLINES_P is nonzero, store 1 thru it
- * if we pass a backslash-newline.
- *
- * If EOFP is nonzero, set *EOFP to 1 if the string is unterminated.
- */
+/* Skip over a quoted string. BP points to the opening quote.
+ Returns a pointer after the closing quote. Don't go past LIMIT.
+ START_LINE is the line number of the starting point (but it need
+ not be valid if the starting point is inside a macro expansion).
+
+ The input stack state is not changed.
+
+ If COUNT_NEWLINES is nonzero, it points to an int to increment
+ for each newline passed.
+
+ If BACKSLASH_NEWLINES_P is nonzero, store 1 thru it
+ if we pass a backslash-newline.
+
+ If EOFP is nonzero, set *EOFP to 1 if the string is unterminated. */
+
static U_CHAR *
skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p, eofp)
register U_CHAR *bp;
@@ -7815,21 +7910,22 @@ skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p,
++*count_newlines;
bp += 2;
}
- if (*bp == '\n' && count_newlines) {
+ if (*bp == '\n') {
if (backslash_newlines_p)
*backslash_newlines_p = 1;
- ++*count_newlines;
+ if (count_newlines)
+ ++*count_newlines;
}
bp++;
} else if (c == '\n') {
if (traditional) {
/* Unterminated strings and character constants are 'valid'. */
- bp--; /* Don't consume the newline. */
+ bp--; /* Don't consume the newline. */
if (eofp)
*eofp = 1;
break;
}
- if (pedantic || match == '\'') {
+ if (match == '\'') {
error_with_line (line_for_error (start_line),
"unterminated string or character constant");
bp--;
@@ -7840,8 +7936,12 @@ skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p,
/* If not traditional, then allow newlines inside strings. */
if (count_newlines)
++*count_newlines;
- if (multiline_string_line == 0)
+ if (multiline_string_line == 0) {
+ if (pedantic)
+ pedwarn_with_line (line_for_error (start_line),
+ "string constant runs past end of line");
multiline_string_line = start_line;
+ }
} else if (c == match)
break;
}
@@ -7849,19 +7949,23 @@ skip_quoted_string (bp, limit, start_line, count_newlines, backslash_newlines_p,
}
/* Place into DST a quoted string representing the string SRC.
+ SRCLEN is the length of SRC; SRC may contain null bytes.
Return the address of DST's terminating null. */
+
static char *
-quote_string (dst, src)
+quote_string (dst, src, srclen)
char *dst, *src;
+ size_t srclen;
{
U_CHAR c;
+ char *srclim = src + srclen;
*dst++ = '\"';
- for (;;)
+ while (src != srclim)
switch ((c = *src++))
{
default:
- if (isprint (c))
+ if (ISPRINT (c))
*dst++ = c;
else
{
@@ -7875,12 +7979,11 @@ quote_string (dst, src)
*dst++ = '\\';
*dst++ = c;
break;
-
- case '\0':
- *dst++ = '\"';
- *dst = '\0';
- return dst;
}
+
+ *dst++ = '\"';
+ *dst = '\0';
+ return dst;
}
/* Skip across a group of balanced parens, starting from IP->bufp.
@@ -7934,13 +8037,11 @@ skip_paren_group (ip)
return p;
}
-/*
- * write out a #line directive, for instance, after an #include file.
- * If CONDITIONAL is nonzero, we can omit the #line if it would
- * appear to be a no-op, and we can output a few newlines instead
- * if we want to increase the line number by a small amount.
- * FILE_CHANGE says whether we are entering a file, leaving, or neither.
- */
+/* Write out a #line directive, for instance, after an #include file.
+ If CONDITIONAL is nonzero, we can omit the #line if it would
+ appear to be a no-op, and we can output a few newlines instead
+ if we want to increase the line number by a small amount.
+ FILE_CHANGE says whether we are entering a file, leaving, or neither. */
static void
output_line_directive (ip, op, conditional, file_change)
@@ -7974,17 +8075,17 @@ output_line_directive (ip, op, conditional, file_change)
}
}
- /* Don't output a line number of 0 if we can help it. */
- if (ip->lineno == 0 && ip->bufp - ip->buf < ip->length
- && *ip->bufp == '\n') {
+ /* Output a positive line number if possible. */
+ while (ip->lineno <= 0 && ip->bufp - ip->buf < ip->length
+ && *ip->bufp == '\n') {
ip->lineno++;
ip->bufp++;
}
- line_directive_buf = (char *) alloca (4 * strlen (ip->nominal_fname) + 100);
+ line_directive_buf = (char *) alloca (4 * ip->nominal_fname_len + 100);
sprintf (line_directive_buf, "# %d ", ip->lineno);
line_end = quote_string (line_directive_buf + strlen (line_directive_buf),
- ip->nominal_fname);
+ ip->nominal_fname, ip->nominal_fname_len);
if (file_change != same_file) {
*line_end++ = ' ';
*line_end++ = file_change == enter_file ? '1' : '2';
@@ -8096,7 +8197,7 @@ macroexpand (hp, op)
if (rest_args)
continue;
if (i < nargs || (nargs == 0 && i == 0)) {
- /* if we are working on last arg which absorbs rest of args... */
+ /* If we are working on last arg which absorbs rest of args... */
if (i == nargs - 1 && defn->rest_args)
rest_args = 1;
parse_error = macarg (&args[i], rest_args);
@@ -8249,29 +8350,30 @@ macroexpand (hp, op)
for (; i < arglen; i++) {
c = arg->raw[i];
- /* Special markers Newline Space
- generate nothing for a stringified argument. */
- if (c == '\n' && arg->raw[i+1] != '\n') {
- i++;
- continue;
- }
+ if (! in_string) {
+ /* Special markers Newline Space
+ generate nothing for a stringified argument. */
+ if (c == '\n' && arg->raw[i+1] != '\n') {
+ i++;
+ continue;
+ }
- /* Internal sequences of whitespace are replaced by one space
- except within an string or char token. */
- if (! in_string
- && (c == '\n' ? arg->raw[i+1] == '\n' : is_space[c])) {
- while (1) {
- /* Note that Newline Space does occur within whitespace
- sequences; consider it part of the sequence. */
- if (c == '\n' && is_space[arg->raw[i+1]])
- i += 2;
- else if (c != '\n' && is_space[c])
- i++;
- else break;
- c = arg->raw[i];
+ /* Internal sequences of whitespace are replaced by one space
+ except within an string or char token. */
+ if (c == '\n' ? arg->raw[i+1] == '\n' : is_space[c]) {
+ while (1) {
+ /* Note that Newline Space does occur within whitespace
+ sequences; consider it part of the sequence. */
+ if (c == '\n' && is_space[arg->raw[i+1]])
+ i += 2;
+ else if (c != '\n' && is_space[c])
+ i++;
+ else break;
+ c = arg->raw[i];
+ }
+ i--;
+ c = ' ';
}
- i--;
- c = ' ';
}
if (escaped)
@@ -8289,12 +8391,10 @@ macroexpand (hp, op)
/* Escape these chars */
if (c == '\"' || (in_string && c == '\\'))
xbuf[totlen++] = '\\';
- if (isprint (c))
- xbuf[totlen++] = c;
- else {
- sprintf ((char *) &xbuf[totlen], "\\%03o", (unsigned int) c);
- totlen += 4;
- }
+ /* We used to output e.g. \008 for control characters here,
+ but this doesn't conform to the C Standard.
+ Just output the characters as-is. */
+ xbuf[totlen++] = c;
}
if (!traditional)
xbuf[totlen++] = '\"'; /* insert ending quote */
@@ -8374,8 +8474,8 @@ macroexpand (hp, op)
abort ();
}
- /* if there is anything left of the definition
- after handling the arg list, copy that in too. */
+ /* If there is anything left of the definition after handling
+ the arg list, copy that in too. */
for (i = offset; i < defn->length; i++) {
/* if we've reached the end of the macro */
@@ -8410,6 +8510,8 @@ macroexpand (hp, op)
ip2->fname = 0;
ip2->nominal_fname = 0;
+ ip2->nominal_fname_len = 0;
+ ip2->inc = 0;
/* This may not be exactly correct, but will give much better error
messages for nested macro calls than using a line number of zero. */
ip2->lineno = start_line;
@@ -8430,11 +8532,9 @@ macroexpand (hp, op)
}
}
-/*
- * Parse a macro argument and store the info on it into *ARGPTR.
- * REST_ARGS is passed to macarg1 to make it absorb the rest of the args.
- * Return nonzero to indicate a syntax error.
- */
+/* Parse a macro argument and store the info on it into *ARGPTR.
+ REST_ARGS is passed to macarg1 to make it absorb the rest of the args.
+ Return nonzero to indicate a syntax error. */
static char *
macarg (argptr, rest_args)
@@ -8449,7 +8549,7 @@ macarg (argptr, rest_args)
/* Try to parse as much of the argument as exists at this
input stack level. */
- U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length,
+ U_CHAR *bp = macarg1 (ip->bufp, ip->buf + ip->length, ip->macro,
&paren, &newlines, &comments, rest_args);
/* If we find the end of the argument at this level,
@@ -8487,7 +8587,7 @@ macarg (argptr, rest_args)
ip = &instack[--indepth];
newlines = 0;
comments = 0;
- bp = macarg1 (ip->bufp, ip->buf + ip->length, &paren,
+ bp = macarg1 (ip->bufp, ip->buf + ip->length, ip->macro, &paren,
&newlines, &comments, rest_args);
final_start = bufsize;
bufsize += bp - ip->bufp;
@@ -8550,8 +8650,6 @@ macarg (argptr, rest_args)
#endif
if (c == '\"' || c == '\\') /* escape these chars */
totlen++;
- else if (!isprint (c))
- totlen += 3;
}
argptr->stringified_length = totlen;
}
@@ -8559,6 +8657,7 @@ macarg (argptr, rest_args)
}
/* Scan text from START (inclusive) up to LIMIT (exclusive),
+ taken from the expansion of MACRO,
counting parens in *DEPTHPTR,
and return if reach LIMIT
or before a `)' that would make *DEPTHPTR negative
@@ -8572,9 +8671,10 @@ macarg (argptr, rest_args)
Set *COMMENTS to 1 if a comment is seen. */
static U_CHAR *
-macarg1 (start, limit, depthptr, newlines, comments, rest_args)
+macarg1 (start, limit, macro, depthptr, newlines, comments, rest_args)
U_CHAR *start;
register U_CHAR *limit;
+ struct hashnode *macro;
int *depthptr, *newlines, *comments;
int rest_args;
{
@@ -8591,43 +8691,44 @@ macarg1 (start, limit, depthptr, newlines, comments, rest_args)
break;
case '\\':
/* Traditionally, backslash makes following char not special. */
- if (bp + 1 < limit && traditional)
- {
- bp++;
- /* But count source lines anyway. */
- if (*bp == '\n')
- ++*newlines;
- }
+ if (traditional && bp + 1 < limit && bp[1] != '\n')
+ bp++;
break;
case '\n':
++*newlines;
break;
case '/':
+ if (macro)
+ break;
if (bp[1] == '\\' && bp[2] == '\n')
newline_fix (bp + 1);
- if (cplusplus_comments && bp[1] == '/') {
+ if (bp[1] == '*') {
*comments = 1;
- bp += 2;
- while (bp < limit && (*bp != '\n' || bp[-1] == '\\')) {
- if (*bp == '\n') ++*newlines;
- bp++;
+ for (bp += 2; bp < limit; bp++) {
+ if (*bp == '\n')
+ ++*newlines;
+ else if (*bp == '*') {
+ if (bp[-1] == '/' && warn_comments)
+ warning ("`/*' within comment");
+ if (bp[1] == '\\' && bp[2] == '\n')
+ newline_fix (bp + 1);
+ if (bp[1] == '/') {
+ bp++;
+ break;
+ }
+ }
+ }
+ } else if (bp[1] == '/' && cplusplus_comments) {
+ *comments = 1;
+ for (bp += 2; bp < limit; bp++) {
+ if (*bp == '\n') {
+ ++*newlines;
+ if (bp[-1] != '\\')
+ break;
+ if (warn_comments)
+ warning ("multiline `//' comment");
+ }
}
- /* Now count the newline that we are about to skip. */
- ++*newlines;
- break;
- }
- if (bp[1] != '*' || bp + 1 >= limit)
- break;
- *comments = 1;
- bp += 2;
- while (bp + 1 < limit) {
- if (bp[0] == '*'
- && bp[1] == '\\' && bp[2] == '\n')
- newline_fix (bp + 1);
- if (bp[0] == '*' && bp[1] == '/')
- break;
- if (*bp == '\n') ++*newlines;
- bp++;
}
break;
case '\'':
@@ -8639,8 +8740,11 @@ macarg1 (start, limit, depthptr, newlines, comments, rest_args)
bp++;
if (*bp == '\n')
++*newlines;
- while (*bp == '\\' && bp[1] == '\n') {
- bp += 2;
+ if (!macro) {
+ while (*bp == '\\' && bp[1] == '\n') {
+ bp += 2;
+ ++*newlines;
+ }
}
} else if (*bp == '\n') {
++*newlines;
@@ -8736,16 +8840,16 @@ discard_comments (start, length, newlines)
obp--;
else
obp[-1] = ' ';
- ibp++;
- while (ibp + 1 < limit) {
- if (ibp[0] == '*'
- && ibp[1] == '\\' && ibp[2] == '\n')
- newline_fix (ibp + 1);
- if (ibp[0] == '*' && ibp[1] == '/')
- break;
- ibp++;
+ while (++ibp < limit) {
+ if (ibp[0] == '*') {
+ if (ibp[1] == '\\' && ibp[2] == '\n')
+ newline_fix (ibp + 1);
+ if (ibp[1] == '/') {
+ ibp += 2;
+ break;
+ }
+ }
}
- ibp += 2;
break;
case '\'':
@@ -8761,10 +8865,16 @@ discard_comments (start, length, newlines)
break;
if (c == '\n' && quotec == '\'')
break;
- if (c == '\\' && ibp < limit) {
- while (*ibp == '\\' && ibp[1] == '\n')
- ibp += 2;
- *obp++ = *ibp++;
+ if (c == '\\') {
+ if (ibp < limit && *ibp == '\n') {
+ ibp++;
+ obp--;
+ } else {
+ while (*ibp == '\\' && ibp[1] == '\n')
+ ibp += 2;
+ if (ibp < limit)
+ *obp++ = *ibp++;
+ }
}
}
}
@@ -8815,7 +8925,7 @@ change_newlines (start, length)
int quotec = c;
while (ibp < limit) {
*obp++ = c = *ibp++;
- if (c == quotec)
+ if (c == quotec && ibp[-2] != '\\')
break;
if (c == '\n' && quotec == '\'')
break;
@@ -8828,11 +8938,10 @@ change_newlines (start, length)
return obp - start;
}
-/*
- * my_strerror - return the descriptive text associated with an `errno' code.
- */
+/* my_strerror - return the descriptive text associated with an
+ `errno' code. */
-char *
+static char *
my_strerror (errnum)
int errnum;
{
@@ -8861,17 +8970,22 @@ my_strerror (errnum)
return result;
}
-/*
- * error - print error message and increment count of errors.
- */
+/* error - print error message and increment count of errors. */
void
-error (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+error VPROTO ((char * msg, ...))
{
+#ifndef __STDC__
+ char * msg;
+#endif
va_list args;
VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
verror (msg, args);
va_end (args);
}
@@ -8892,8 +9006,10 @@ verror (msg, args)
break;
}
- if (ip != NULL)
- fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
+ if (ip != NULL) {
+ eprint_string (ip->nominal_fname, ip->nominal_fname_len);
+ fprintf (stderr, ":%d: ", ip->lineno);
+ }
vfprintf (stderr, msg, args);
fprintf (stderr, "\n");
errors++;
@@ -8905,6 +9021,7 @@ static void
error_from_errno (name)
char *name;
{
+ int e = errno;
int i;
FILE_BUF *ip = NULL;
@@ -8916,10 +9033,12 @@ error_from_errno (name)
break;
}
- if (ip != NULL)
- fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
+ if (ip != NULL) {
+ eprint_string (ip->nominal_fname, ip->nominal_fname_len);
+ fprintf (stderr, ":%d: ", ip->lineno);
+ }
- fprintf (stderr, "%s: %s\n", name, my_strerror (errno));
+ fprintf (stderr, "%s: %s\n", name, my_strerror (e));
errors++;
}
@@ -8927,12 +9046,19 @@ error_from_errno (name)
/* Print error message but don't count it. */
void
-warning (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+warning VPROTO ((char * msg, ...))
{
+#ifndef __STDC__
+ char * msg;
+#endif
va_list args;
VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
vwarning (msg, args);
va_end (args);
}
@@ -8959,25 +9085,31 @@ vwarning (msg, args)
break;
}
- if (ip != NULL)
- fprintf (stderr, "%s:%d: ", ip->nominal_fname, ip->lineno);
+ if (ip != NULL) {
+ eprint_string (ip->nominal_fname, ip->nominal_fname_len);
+ fprintf (stderr, ":%d: ", ip->lineno);
+ }
fprintf (stderr, "warning: ");
vfprintf (stderr, msg, args);
fprintf (stderr, "\n");
}
static void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-error_with_line (int line, PRINTF_ALIST (msg))
-#else
-error_with_line (line, PRINTF_ALIST (msg))
- int line;
- PRINTF_DCL (msg)
-#endif
+error_with_line VPROTO ((int line, char * msg, ...))
{
+#ifndef __STDC__
+ int line;
+ char * msg;
+#endif
va_list args;
VA_START (args, msg);
+
+#ifndef __STDC__
+ line = va_arg (args, int);
+ msg = va_arg (args, char *);
+#endif
+
verror_with_line (line, msg, args);
va_end (args);
}
@@ -8999,25 +9131,31 @@ verror_with_line (line, msg, args)
break;
}
- if (ip != NULL)
- fprintf (stderr, "%s:%d: ", ip->nominal_fname, line);
+ if (ip != NULL) {
+ eprint_string (ip->nominal_fname, ip->nominal_fname_len);
+ fprintf (stderr, ":%d: ", line);
+ }
vfprintf (stderr, msg, args);
fprintf (stderr, "\n");
errors++;
}
static void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-warning_with_line (int line, PRINTF_ALIST (msg))
-#else
-warning_with_line (line, PRINTF_ALIST (msg))
- int line;
- PRINTF_DCL (msg)
-#endif
+warning_with_line VPROTO ((int line, char * msg, ...))
{
+#ifndef __STDC__
+ int line;
+ char * msg;
+#endif
va_list args;
VA_START (args, msg);
+
+#ifndef __STDC__
+ line = va_arg (args, int);
+ msg = va_arg (args, char *);
+#endif
+
vwarning_with_line (line, msg, args);
va_end (args);
}
@@ -9045,22 +9183,31 @@ vwarning_with_line (line, msg, args)
break;
}
- if (ip != NULL)
- fprintf (stderr, line ? "%s:%d: " : "%s: ", ip->nominal_fname, line);
+ if (ip != NULL) {
+ eprint_string (ip->nominal_fname, ip->nominal_fname_len);
+ fprintf (stderr, line ? ":%d: " : ": ", line);
+ }
fprintf (stderr, "warning: ");
vfprintf (stderr, msg, args);
fprintf (stderr, "\n");
}
-/* print an error message and maybe count it. */
+/* Print an error message and maybe count it. */
void
-pedwarn (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+pedwarn VPROTO ((char * msg, ...))
{
+#ifndef __STDC__
+ char * msg;
+#endif
va_list args;
VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
if (pedantic_errors)
verror (msg, args);
else
@@ -9069,17 +9216,21 @@ pedwarn (PRINTF_ALIST (msg))
}
void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-pedwarn_with_line (int line, PRINTF_ALIST (msg))
-#else
-pedwarn_with_line (line, PRINTF_ALIST (msg))
- int line;
- PRINTF_DCL (msg)
-#endif
+pedwarn_with_line VPROTO ((int line, char * msg, ...))
{
+#ifndef __STDC__
+ int line;
+ char * msg;
+#endif
va_list args;
VA_START (args, msg);
+
+#ifndef __STDC__
+ line = va_arg (args, int);
+ msg = va_arg (args, char *);
+#endif
+
if (pedantic_errors)
verror_with_line (line, msg, args);
else
@@ -9091,26 +9242,36 @@ pedwarn_with_line (line, PRINTF_ALIST (msg))
giving specified file name and line number, not current. */
static void
-#if defined (__STDC__) && defined (HAVE_VPRINTF)
-pedwarn_with_file_and_line (char *file, int line, PRINTF_ALIST (msg))
-#else
-pedwarn_with_file_and_line (file, line, PRINTF_ALIST (msg))
- char *file;
- int line;
- PRINTF_DCL (msg)
+pedwarn_with_file_and_line VPROTO ((char *file, size_t file_len, int line,
+ char * msg, ...))
+{
+#ifndef __STDC__
+ char *file;
+ size_t file_len;
+ int line;
+ char * msg;
#endif
-{
va_list args;
if (!pedantic_errors && inhibit_warnings)
return;
- if (file != NULL)
- fprintf (stderr, "%s:%d: ", file, line);
+ if (file) {
+ eprint_string (file, file_len);
+ fprintf (stderr, ":%d: ", line);
+ }
if (pedantic_errors)
errors++;
if (!pedantic_errors)
fprintf (stderr, "warning: ");
VA_START (args, msg);
+
+#ifndef __STDC__
+ file = va_arg (args, char *);
+ file_len = va_arg (args, size_t);
+ line = va_arg (args, int);
+ msg = va_arg (args, char *);
+#endif
+
vfprintf (stderr, msg, args);
va_end (args);
fprintf (stderr, "\n");
@@ -9152,7 +9313,9 @@ print_containing_files ()
fprintf (stderr, ",\n ");
}
- fprintf (stderr, " from %s:%d", ip->nominal_fname, ip->lineno);
+ fprintf (stderr, " from ");
+ eprint_string (ip->nominal_fname, ip->nominal_fname_len);
+ fprintf (stderr, ":%d", ip->lineno);
}
if (! first)
fprintf (stderr, ":\n");
@@ -9200,6 +9363,7 @@ line_for_error (line)
/* You might think void was cleaner for the return type,
but that would get type mismatch in check_expand in strict ANSI. */
+
static int
grow_outbuf (obuf, needed)
register FILE_BUF *obuf;
@@ -9241,8 +9405,9 @@ grow_outbuf (obuf, needed)
* Otherwise, compute the length by scanning the entire name.
*
* If HASH is >= 0, it is the precomputed hash code.
- * Otherwise, compute the hash code.
+ * Otherwise, compute the hash code.
*/
+
static HASHNODE *
install (name, len, type, value, hash)
U_CHAR *name;
@@ -9287,7 +9452,7 @@ install (name, len, type, value, hash)
}
/*
- * find the most recent hash node for name name (ending with first
+ * find the most recent hash node for name "name" (ending with first
* non-identifier char) installed by install
*
* If LEN is >= 0, it is the length of the name.
@@ -9296,6 +9461,7 @@ install (name, len, type, value, hash)
* If HASH is >= 0, it is the precomputed hash code.
* Otherwise, compute the hash code.
*/
+
HASHNODE *
lookup (name, len, hash)
U_CHAR *name;
@@ -9346,8 +9512,8 @@ delete_macro (hp)
if (hp->next != NULL)
hp->next->prev = hp->prev;
- /* make sure that the bucket chain header that
- the deleted guy was on points to the right thing afterwards. */
+ /* Make sure that the bucket chain header that the deleted guy was
+ on points to the right thing afterwards. */
if (hp == *hp->bucket_hdr)
*hp->bucket_hdr = hp->next;
@@ -9370,6 +9536,7 @@ delete_macro (hp)
* return hash function on name. must be compatible with the one
* computed a step at a time, elsewhere
*/
+
static int
hashf (name, len, hashsize)
register U_CHAR *name;
@@ -9386,6 +9553,7 @@ hashf (name, len, hashsize)
/* Dump the definition of a single macro HP to OF. */
+
static void
dump_single_macro (hp, of)
register HASHNODE *hp;
@@ -9567,8 +9735,8 @@ initialize_char_syntax ()
is_idchar[i] = 1;
is_idchar['_'] = 1;
is_idstart['_'] = 1;
- is_idchar['$'] = dollars_in_ident;
- is_idstart['$'] = dollars_in_ident;
+ is_idchar['$'] = 1;
+ is_idstart['$'] = 1;
/* horizontal space table */
is_hor_space[' '] = 1;
@@ -9625,6 +9793,7 @@ initialize_builtins (inp, outp)
/* This is supplied using a -D by the compiler driver
so that it is present only when truly compiling with GNU C. */
/* install ((U_CHAR *) "__GNUC__", -1, T_CONST, "2", -1); */
+ install ((U_CHAR *) "__HAVE_BUILTIN_SETJMP__", -1, T_CONST, "1", -1);
if (debug_output)
{
@@ -9747,10 +9916,7 @@ make_definition (str, op)
if (unterminated)
return;
while (p != p1)
- if (*p == '\\' && p[1] == '\n')
- p += 2;
- else
- *q++ = *p++;
+ *q++ = *p++;
} else if (*p == '\\' && p[1] == '\n')
p += 2;
/* Change newline chars into newline-markers. */
@@ -9768,6 +9934,7 @@ make_definition (str, op)
ip = &instack[++indepth];
ip->nominal_fname = ip->fname = "*Initialization*";
+ ip->nominal_fname_len = strlen (ip->nominal_fname);
ip->buf = ip->bufp = buf;
ip->length = strlen ((char *) buf);
@@ -9797,6 +9964,7 @@ make_undef (str, op)
ip = &instack[++indepth];
ip->nominal_fname = ip->fname = "*undef*";
+ ip->nominal_fname_len = strlen (ip->nominal_fname);
ip->buf = ip->bufp = (U_CHAR *) str;
ip->length = strlen (str);
@@ -9853,6 +10021,7 @@ make_assertion (option, str)
ip = &instack[++indepth];
ip->nominal_fname = ip->fname = "*Initialization*";
+ ip->nominal_fname_len = strlen (ip->nominal_fname);
ip->buf = ip->bufp = buf;
ip->length = strlen ((char *) buf);
@@ -9865,12 +10034,116 @@ make_assertion (option, str)
for (kt = directive_table; kt->type != T_ASSERT; kt++)
;
- /* pass NULL as output ptr to do_define since we KNOW it never
- does any output.... */
+ /* Pass NULL as output ptr to do_define since we KNOW it never does
+ any output.... */
do_assert (buf, buf + strlen ((char *) buf) , NULL_PTR, kt);
--indepth;
}
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+/* The previous include prefix, if any, is PREV_FILE_NAME.
+ Translate any pathnames with COMPONENT.
+ Allocate a new include prefix whose name is the
+ simplified concatenation of PREFIX and NAME,
+ with a trailing / added if needed.
+ But return 0 if the include prefix should be ignored,
+ e.g. because it is a duplicate of PREV_FILE_NAME. */
+
+static struct file_name_list *
+new_include_prefix (prev_file_name, component, prefix, name)
+ struct file_name_list *prev_file_name;
+ char *component;
+ char *prefix;
+ char *name;
+{
+ if (name == 0)
+ fatal ("Directory name missing after command line option");
+
+ if (*name == 0)
+ /* Ignore the empty string. */
+ return 0;
+
+ prefix = update_path (prefix, component);
+ name = update_path (name, component);
+
+ {
+ struct file_name_list *dir
+ = ((struct file_name_list *)
+ xmalloc (sizeof (struct file_name_list)
+ + strlen (prefix) + strlen (name) + 2));
+ size_t len;
+ strcpy (dir->fname, prefix);
+ strcat (dir->fname, name);
+ len = simplify_filename (dir->fname);
+
+ /* Convert directory name to a prefix. */
+ if (len && dir->fname[len - 1] != DIR_SEPARATOR) {
+ if (len == 1 && dir->fname[len - 1] == '.')
+ len = 0;
+ else
+#ifdef VMS
+ /* must be '/', hack_vms_include_specification triggers on it. */
+ dir->fname[len++] = '/';
+#else
+ dir->fname[len++] = DIR_SEPARATOR;
+#endif
+ dir->fname[len] = 0;
+ }
+
+ /* Ignore a directory whose name matches the previous one. */
+ if (prev_file_name && !strcmp (prev_file_name->fname, dir->fname)) {
+ /* But treat `-Idir -I- -Idir' as `-I- -Idir'. */
+ if (!first_bracket_include)
+ first_bracket_include = prev_file_name;
+ free (dir);
+ return 0;
+ }
+
+#ifndef VMS
+ /* VMS can't stat dir prefixes, so skip these optimizations in VMS. */
+
+ /* Add a trailing "." if there is a filename. This increases the number
+ of systems that can stat directories. We remove it below. */
+ if (len != 0)
+ {
+ dir->fname[len] = '.';
+ dir->fname[len + 1] = 0;
+ }
+
+ /* Ignore a nonexistent directory. */
+ if (stat (len ? dir->fname : ".", &dir->st) != 0) {
+ if (errno != ENOENT && errno != ENOTDIR)
+ error_from_errno (dir->fname);
+ free (dir);
+ return 0;
+ }
+
+ if (len != 0)
+ dir->fname[len] = 0;
+
+ /* Ignore a directory whose identity matches the previous one. */
+ if (prev_file_name
+ && INO_T_EQ (prev_file_name->st.st_ino, dir->st.st_ino)
+ && prev_file_name->st.st_dev == dir->st.st_dev) {
+ /* But treat `-Idir -I- -Idir' as `-I- -Idir'. */
+ if (!first_bracket_include)
+ first_bracket_include = prev_file_name;
+ free (dir);
+ return 0;
+ }
+#endif /* ! VMS */
+
+ dir->next = 0;
+ dir->c_system_include_path = 0;
+ dir->got_name_map = 0;
+
+ return dir;
+ }
+}
+
/* Append a chain of `struct file_name_list's
to the end of the main include chain.
FIRST is the beginning of the chain to append, and LAST is the end. */
@@ -9904,6 +10177,67 @@ append_include_chain (first, last)
last_include = last;
}
+/* Place into DST a representation of the file named SRC that is suitable
+ for `make'. Do not null-terminate DST. Return its length. */
+static int
+quote_string_for_make (dst, src)
+ char *dst;
+ char *src;
+{
+ char *p = src;
+ int i = 0;
+ for (;;)
+ {
+ char c = *p++;
+ switch (c)
+ {
+ case '\0':
+ case ' ':
+ case '\t':
+ {
+ /* GNU make uses a weird quoting scheme for white space.
+ A space or tab preceded by 2N+1 backslashes represents
+ N backslashes followed by space; a space or tab
+ preceded by 2N backslashes represents N backslashes at
+ the end of a file name; and backslashes in other
+ contexts should not be doubled. */
+ char *q;
+ for (q = p - 1; src < q && q[-1] == '\\'; q--)
+ {
+ if (dst)
+ dst[i] = '\\';
+ i++;
+ }
+ }
+ if (!c)
+ return i;
+ if (dst)
+ dst[i] = '\\';
+ i++;
+ goto ordinary_char;
+
+ case '$':
+ if (dst)
+ dst[i] = c;
+ i++;
+ /* Fall through. This can mishandle things like "$(" but
+ there's no easy fix. */
+ default:
+ ordinary_char:
+ /* This can mishandle characters in the string "\0\n%*?[\\~";
+ exactly which chars are mishandled depends on the `make' version.
+ We know of no portable solution for this;
+ even GNU make 3.76.1 doesn't solve the problem entirely.
+ (Also, '\0' is mishandled due to our calling conventions.) */
+ if (dst)
+ dst[i] = c;
+ i++;
+ break;
+ }
+ }
+}
+
+
/* Add output to `deps_buffer' for the -M switch.
STRING points to the text to be output.
SPACER is ':' for targets, ' ' for dependencies. */
@@ -9913,7 +10247,7 @@ deps_output (string, spacer)
char *string;
int spacer;
{
- int size = strlen (string);
+ int size = quote_string_for_make ((char *) 0, string);
if (size == 0)
return;
@@ -9930,15 +10264,15 @@ deps_output (string, spacer)
spacer = 0;
}
- if (deps_size + size + 8 > deps_allocated_size) {
- deps_allocated_size = (deps_size + size + 50) * 2;
+ if (deps_size + 2 * size + 8 > deps_allocated_size) {
+ deps_allocated_size = (deps_size + 2 * size + 50) * 2;
deps_buffer = xrealloc (deps_buffer, deps_allocated_size);
}
if (spacer == ' ') {
deps_buffer[deps_size++] = ' ';
deps_column++;
}
- bcopy (string, &deps_buffer[deps_size], size);
+ quote_string_for_make (&deps_buffer[deps_size], string);
deps_size += size;
deps_column += size;
if (spacer == ':') {
@@ -9949,13 +10283,20 @@ deps_output (string, spacer)
}
static void
-fatal (PRINTF_ALIST (msg))
- PRINTF_DCL (msg)
+fatal VPROTO ((char * msg, ...))
{
+#ifndef __STDC__
+ char * msg;
+#endif
va_list args;
fprintf (stderr, "%s: ", progname);
VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
vfprintf (stderr, msg, args);
va_end (args);
fprintf (stderr, "\n");
@@ -9975,8 +10316,7 @@ static void
perror_with_name (name)
char *name;
{
- fprintf (stderr, "%s: ", progname);
- fprintf (stderr, "%s: %s\n", name, my_strerror (errno));
+ fprintf (stderr, "%s: %s: %s\n", progname, name, my_strerror (errno));
errors++;
}
@@ -9997,7 +10337,7 @@ pfatal_with_name (name)
static void
pipe_closed (signo)
/* If this is missing, some compilers complain. */
- int signo;
+ int signo ATTRIBUTE_UNUSED;
{
fatal ("output pipe has been closed");
}
@@ -10052,68 +10392,86 @@ savestring (input)
return output;
}
-/* Get the file-mode and data size of the file open on FD
- and store them in *MODE_POINTER and *SIZE_POINTER. */
+#ifdef VMS
-static int
-file_size_and_mode (fd, mode_pointer, size_pointer)
- int fd;
- int *mode_pointer;
- long int *size_pointer;
-{
- struct stat sbuf;
+/* Under VMS we need to fix up the "include" specification filename.
- if (fstat (fd, &sbuf) < 0) return (-1);
- if (mode_pointer) *mode_pointer = sbuf.st_mode;
- if (size_pointer) *size_pointer = sbuf.st_size;
- return 0;
-}
-
-#ifdef VMS
+ Rules for possible conversions
-/* Under VMS we need to fix up the "include" specification
- filename so that everything following the 1st slash is
- changed into its correct VMS file specification. */
+ fullname tried paths
-static void
-hack_vms_include_specification (fname)
- char *fname;
+ name name
+ ./dir/name [.dir]name
+ /dir/name dir:name
+ /name [000000]name, name
+ dir/name dir:[000000]name, dir:name, dir/name
+ dir1/dir2/name dir1:[dir2]name, dir1:[000000.dir2]name
+ path:/name path:[000000]name, path:name
+ path:/dir/name path:[000000.dir]name, path:[dir]name
+ path:dir/name path:[dir]name
+ [path]:[dir]name [path.dir]name
+ path/[dir]name [path.dir]name
+
+ The path:/name input is constructed when expanding <> includes.
+
+ return 1 if name was changed, 0 else. */
+
+static int
+hack_vms_include_specification (fullname, vaxc_include)
+ char *fullname;
+ int vaxc_include;
{
- register char *cp, *cp1, *cp2;
- int f, check_filename_before_returning, no_prefix_seen;
+ register char *basename, *unixname, *local_ptr, *first_slash;
+ int f, check_filename_before_returning, must_revert;
char Local[512];
check_filename_before_returning = 0;
- no_prefix_seen = 0;
-
- /* Ignore leading "./"s */
- while (fname[0] == '.' && fname[1] == '/') {
- strcpy (fname, fname+2);
- no_prefix_seen = 1; /* mark this for later */
- }
- /* Look for the boundary between the VMS and UNIX filespecs */
- cp = rindex (fname, ']'); /* Look for end of dirspec. */
- if (cp == 0) cp = rindex (fname, '>'); /* ... Ditto */
- if (cp == 0) cp = rindex (fname, ':'); /* Look for end of devspec. */
- if (cp) {
- cp++;
- } else {
- cp = index (fname, '/'); /* Look for the "/" */
- }
+ must_revert = 0;
+ /* See if we can find a 1st slash. If not, there's no path information. */
+ first_slash = index (fullname, '/');
+ if (first_slash == 0)
+ return 0; /* Nothing to do!!! */
+
+ /* construct device spec if none given. */
+
+ if (index (fullname, ':') == 0)
+ {
+
+ /* If fullname has a slash, take it as device spec. */
+
+ if (first_slash == fullname)
+ {
+ first_slash = index (fullname+1, '/'); /* 2nd slash ? */
+ if (first_slash)
+ *first_slash = ':'; /* make device spec */
+ for (basename = fullname; *basename != 0; basename++)
+ *basename = *(basename+1); /* remove leading slash */
+ }
+ else if ((first_slash[-1] != '.') /* keep ':/', './' */
+ && (first_slash[-1] != ':')
+ && (first_slash[-1] != ']')) /* or a vms path */
+ {
+ *first_slash = ':';
+ }
+ else if ((first_slash[1] == '[') /* skip './' in './[dir' */
+ && (first_slash[-1] == '.'))
+ fullname += 2;
+ }
+
+ /* Get part after first ':' (basename[-1] == ':')
+ or last '/' (basename[-1] == '/'). */
+
+ basename = base_name (fullname);
/*
* Check if we have a vax-c style '#include filename'
* and add the missing .h
*/
- if (cp == 0) {
- if (index(fname,'.') == 0)
- strcat(fname, ".h");
- } else {
- if (index(cp,'.') == 0)
- strcat(cp, ".h");
- }
- cp2 = Local; /* initialize */
+ if (vaxc_include && !index (basename,'.'))
+ strcat (basename, ".h");
+
+ local_ptr = Local; /* initialize */
/* We are trying to do a number of things here. First of all, we are
trying to hammer the filenames into a standard format, such that later
@@ -10124,171 +10482,201 @@ hack_vms_include_specification (fname)
needed to get things working properly.
If no device is specified, then the first directory name is taken to be
- a device name (or a rooted logical). */
+ a device name (or a rooted logical). */
+
+ /* Point to the UNIX filename part (which needs to be fixed!)
+ but skip vms path information.
+ [basename != fullname since first_slash != 0]. */
+
+ if ((basename[-1] == ':') /* vms path spec. */
+ || (basename[-1] == ']')
+ || (basename[-1] == '>'))
+ unixname = basename;
+ else
+ unixname = fullname;
+
+ if (*unixname == '/')
+ unixname++;
- /* See if we found that 1st slash */
- if (cp == 0) return; /* Nothing to do!!! */
- if (*cp != '/') return; /* Nothing to do!!! */
- /* Point to the UNIX filename part (which needs to be fixed!) */
- cp1 = cp+1;
/* If the directory spec is not rooted, we can just copy
- the UNIX filename part and we are done */
- if (((cp - fname) > 1) && ((cp[-1] == ']') || (cp[-1] == '>'))) {
- if (cp[-2] != '.') {
- /*
- * The VMS part ends in a `]', and the preceding character is not a `.'.
- * We strip the `]', and then splice the two parts of the name in the
- * usual way. Given the default locations for include files in cccp.c,
- * we will only use this code if the user specifies alternate locations
- * with the /include (-I) switch on the command line. */
- cp -= 1; /* Strip "]" */
- cp1--; /* backspace */
- } else {
- /*
- * The VMS part has a ".]" at the end, and this will not do. Later
- * processing will add a second directory spec, and this would be a syntax
- * error. Thus we strip the ".]", and thus merge the directory specs.
- * We also backspace cp1, so that it points to a '/'. This inhibits the
- * generation of the 000000 root directory spec (which does not belong here
- * in this case).
- */
- cp -= 2; /* Strip ".]" */
- cp1--; }; /* backspace */
- } else {
+ the UNIX filename part and we are done. */
- /* We drop in here if there is no VMS style directory specification yet.
- * If there is no device specification either, we make the first dir a
- * device and try that. If we do not do this, then we will be essentially
- * searching the users default directory (as if they did a #include "asdf.h").
- *
- * Then all we need to do is to push a '[' into the output string. Later
- * processing will fill this in, and close the bracket.
- */
- if (cp[-1] != ':') *cp2++ = ':'; /* dev not in spec. take first dir */
- *cp2++ = '['; /* Open the directory specification */
- }
+ if (((basename - fullname) > 1)
+ && ( (basename[-1] == ']')
+ || (basename[-1] == '>')))
+ {
+ if (basename[-2] != '.')
+ {
+
+ /* The VMS part ends in a `]', and the preceding character is not a `.'.
+ -> PATH]:/name (basename = '/name', unixname = 'name')
+ We strip the `]', and then splice the two parts of the name in the
+ usual way. Given the default locations for include files in cccp.c,
+ we will only use this code if the user specifies alternate locations
+ with the /include (-I) switch on the command line. */
+
+ basename -= 1; /* Strip "]" */
+ unixname--; /* backspace */
+ }
+ else
+ {
+
+ /* The VMS part has a ".]" at the end, and this will not do. Later
+ processing will add a second directory spec, and this would be a syntax
+ error. Thus we strip the ".]", and thus merge the directory specs.
+ We also backspace unixname, so that it points to a '/'. This inhibits the
+ generation of the 000000 root directory spec (which does not belong here
+ in this case). */
+
+ basename -= 2; /* Strip ".]" */
+ unixname--; /* backspace */
+ }
+ }
+
+ else
+
+ {
+
+ /* We drop in here if there is no VMS style directory specification yet.
+ If there is no device specification either, we make the first dir a
+ device and try that. If we do not do this, then we will be essentially
+ searching the users default directory (as if they did a #include "asdf.h").
+
+ Then all we need to do is to push a '[' into the output string. Later
+ processing will fill this in, and close the bracket. */
+
+ if ((unixname != fullname) /* vms path spec found. */
+ && (basename[-1] != ':'))
+ *local_ptr++ = ':'; /* dev not in spec. take first dir */
+
+ *local_ptr++ = '['; /* Open the directory specification */
+ }
+
+ if (unixname == fullname) /* no vms dir spec. */
+ {
+ must_revert = 1;
+ if ((first_slash != 0) /* unix dir spec. */
+ && (*unixname != '/') /* not beginning with '/' */
+ && (*unixname != '.')) /* or './' or '../' */
+ *local_ptr++ = '.'; /* dir is local ! */
+ }
/* at this point we assume that we have the device spec, and (at least
the opening "[" for a directory specification. We may have directories
- specified already */
+ specified already.
- /* If there are no other slashes then the filename will be
+ If there are no other slashes then the filename will be
in the "root" directory. Otherwise, we need to add
- directory specifications. */
- if (index (cp1, '/') == 0) {
- /* Just add "000000]" as the directory string */
- strcpy (cp2, "000000]");
- cp2 += strlen (cp2);
- check_filename_before_returning = 1; /* we might need to fool with this later */
- } else {
- /* As long as there are still subdirectories to add, do them. */
- while (index (cp1, '/') != 0) {
- /* If this token is "." we can ignore it */
- if ((cp1[0] == '.') && (cp1[1] == '/')) {
- cp1 += 2;
- continue;
- }
- /* Add a subdirectory spec. Do not duplicate "." */
- if (cp2[-1] != '.' && cp2[-1] != '[' && cp2[-1] != '<')
- *cp2++ = '.';
- /* If this is ".." then the spec becomes "-" */
- if ((cp1[0] == '.') && (cp1[1] == '.') && (cp[2] == '/')) {
- /* Add "-" and skip the ".." */
- *cp2++ = '-';
- cp1 += 3;
- continue;
- }
- /* Copy the subdirectory */
- while (*cp1 != '/') *cp2++= *cp1++;
- cp1++; /* Skip the "/" */
+ directory specifications. */
+
+ if (index (unixname, '/') == 0)
+ {
+ /* if no directories specified yet and none are following. */
+ if (local_ptr[-1] == '[')
+ {
+ /* Just add "000000]" as the directory string */
+ strcpy (local_ptr, "000000]");
+ local_ptr += strlen (local_ptr);
+ check_filename_before_returning = 1; /* we might need to fool with this later */
+ }
}
- /* Close the directory specification */
- if (cp2[-1] == '.') /* no trailing periods */
- cp2--;
- *cp2++ = ']';
- }
- /* Now add the filename */
- while (*cp1) *cp2++ = *cp1++;
- *cp2 = 0;
- /* Now append it to the original VMS spec. */
- strcpy (cp, Local);
+ else
+ {
+
+ /* As long as there are still subdirectories to add, do them. */
+ while (index (unixname, '/') != 0)
+ {
+ /* If this token is "." we can ignore it
+ if it's not at the beginning of a path. */
+ if ((unixname[0] == '.') && (unixname[1] == '/'))
+ {
+ /* remove it at beginning of path. */
+ if ( ((unixname == fullname) /* no device spec */
+ && (fullname+2 != basename)) /* starts with ./ */
+ /* or */
+ || ((basename[-1] == ':') /* device spec */
+ && (unixname-1 == basename))) /* and ./ afterwards */
+ *local_ptr++ = '.'; /* make '[.' start of path. */
+ unixname += 2;
+ continue;
+ }
+
+ /* Add a subdirectory spec. Do not duplicate "." */
+ if ( local_ptr[-1] != '.'
+ && local_ptr[-1] != '['
+ && local_ptr[-1] != '<')
+ *local_ptr++ = '.';
+
+ /* If this is ".." then the spec becomes "-" */
+ if ( (unixname[0] == '.')
+ && (unixname[1] == '.')
+ && (unixname[2] == '/'))
+ {
+ /* Add "-" and skip the ".." */
+ if ((local_ptr[-1] == '.')
+ && (local_ptr[-2] == '['))
+ local_ptr--; /* prevent [.- */
+ *local_ptr++ = '-';
+ unixname += 3;
+ continue;
+ }
+
+ /* Copy the subdirectory */
+ while (*unixname != '/')
+ *local_ptr++= *unixname++;
+
+ unixname++; /* Skip the "/" */
+ }
+
+ /* Close the directory specification */
+ if (local_ptr[-1] == '.') /* no trailing periods */
+ local_ptr--;
+
+ if (local_ptr[-1] == '[') /* no dir needed */
+ local_ptr--;
+ else
+ *local_ptr++ = ']';
+ }
+
+ /* Now add the filename. */
+
+ while (*unixname)
+ *local_ptr++ = *unixname++;
+ *local_ptr = 0;
+
+ /* Now append it to the original VMS spec. */
+
+ strcpy ((must_revert==1)?fullname:basename, Local);
/* If we put a [000000] in the filename, try to open it first. If this fails,
remove the [000000], and return that name. This provides flexibility
to the user in that they can use both rooted and non-rooted logical names
to point to the location of the file. */
- if (check_filename_before_returning && no_prefix_seen) {
- f = open (fname, O_RDONLY, 0666);
- if (f >= 0) {
- /* The file name is OK as it is, so return it as is. */
- close (f);
- return;
- }
- /* The filename did not work. Try to remove the [000000] from the name,
- and return it. */
- cp = index (fname, '[');
- cp2 = index (fname, ']') + 1;
- strcpy (cp, cp2); /* this gets rid of it */
- }
- return;
-}
-#endif /* VMS */
-
-#ifdef VMS
+ if (check_filename_before_returning)
+ {
+ f = open (fullname, O_RDONLY, 0666);
+ if (f >= 0)
+ {
+ /* The file name is OK as it is, so return it as is. */
+ close (f);
+ return 1;
+ }
-/* These are the read/write replacement routines for
- VAX-11 "C". They make read/write behave enough
- like their UNIX counterparts that CCCP will work */
+ /* The filename did not work. Try to remove the [000000] from the name,
+ and return it. */
+
+ basename = index (fullname, '[');
+ local_ptr = index (fullname, ']') + 1;
+ strcpy (basename, local_ptr); /* this gets rid of it */
-static int
-read (fd, buf, size)
- int fd;
- char *buf;
- int size;
-{
-#undef read /* Get back the REAL read routine */
- register int i;
- register int total = 0;
-
- /* Read until the buffer is exhausted */
- while (size > 0) {
- /* Limit each read to 32KB */
- i = (size > (32*1024)) ? (32*1024) : size;
- i = read (fd, buf, i);
- if (i <= 0) {
- if (i == 0) return (total);
- return (i);
}
- /* Account for this read */
- total += i;
- buf += i;
- size -= i;
- }
- return (total);
-}
-static int
-write (fd, buf, size)
- int fd;
- char *buf;
- int size;
-{
-#undef write /* Get back the REAL write routine */
- int i;
- int j;
-
- /* Limit individual writes to 32Kb */
- i = size;
- while (i > 0) {
- j = (i > (32*1024)) ? (32*1024) : i;
- if (write (fd, buf, j) < 0) return (-1);
- /* Account for the data written */
- buf += j;
- i -= j;
- }
- return (size);
+ return 1;
}
+#endif /* VMS */
+
+#ifdef VMS
/* The following wrapper functions supply additional arguments to the VMS
I/O routines to optimize performance with file handling. The arguments
@@ -10296,27 +10684,27 @@ write (fd, buf, size)
"mbc=16" - Set multi-block count to 16 (use a 8192 byte buffer).
"deq=64" - When extending the file, extend it in chunks of 32Kbytes.
"fop=tef"- Truncate unused portions of file when closing file.
- "shr=nil"- Disallow file sharing while file is open.
- */
+ "shr=nil"- Disallow file sharing while file is open. */
static FILE *
-freopen (fname, type, oldfile)
+VMS_freopen (fname, type, oldfile)
char *fname;
char *type;
FILE *oldfile;
{
-#undef freopen /* Get back the REAL fopen routine */
+#undef freopen /* Get back the real freopen routine. */
if (strcmp (type, "w") == 0)
- return freopen (fname, type, oldfile, "mbc=16", "deq=64", "fop=tef", "shr=nil");
+ return freopen (fname, type, oldfile,
+ "mbc=16", "deq=64", "fop=tef", "shr=nil");
return freopen (fname, type, oldfile, "mbc=16");
}
static FILE *
-fopen (fname, type)
+VMS_fopen (fname, type)
char *fname;
char *type;
{
-#undef fopen /* Get back the REAL fopen routine */
+#undef fopen /* Get back the real fopen routine. */
/* The gcc-vms-1.42 distribution's header files prototype fopen with two
fixed arguments, which matches ANSI's specification but not VAXCRTL's
pre-ANSI implementation. This hack circumvents the mismatch problem. */
@@ -10330,40 +10718,20 @@ fopen (fname, type)
}
static int
-open (fname, flags, prot)
+VMS_open (fname, flags, prot)
char *fname;
int flags;
int prot;
{
-#undef open /* Get back the REAL open routine */
+#undef open /* Get back the real open routine. */
return open (fname, flags, prot, "mbc=16", "deq=64", "fop=tef");
}
-
-/* Avoid run-time library bug, where copying M out of N+M characters with
- N >= 65535 results in VAXCRTL's strncat falling into an infinite loop.
- gcc-cpp exercises this particular bug. [Fixed in V5.5-2's VAXCRTL.] */
-
-static char *
-strncat (dst, src, cnt)
- char *dst;
- const char *src;
- unsigned cnt;
-{
- register char *d = dst, *s = (char *) src;
- register int n = cnt; /* convert to _signed_ type */
-
- while (*d) d++; /* advance to end */
- while (--n >= 0)
- if (!(*d++ = *s++)) break;
- if (n < 0) *d = '\0';
- return dst;
-}
/* more VMS hackery */
#include <fab.h>
#include <nam.h>
-extern unsigned long sys$parse(), sys$search();
+extern unsigned long SYS$PARSE(), SYS$SEARCH();
/* Work around another library bug. If a file is located via a searchlist,
and if the device it's on is not the same device as the one specified
@@ -10377,7 +10745,7 @@ extern unsigned long sys$parse(), sys$search();
bad enough, but then compounding the problem by reporting the reason for
failure as "normal successful completion." */
-#undef fstat /* get back to library version */
+#undef fstat /* Get back to the library version. */
static int
VMS_fstat (fd, statbuf)
@@ -10410,8 +10778,8 @@ VMS_stat (name, statbuf)
{
struct FAB fab;
struct NAM nam;
- char exp_nam[NAM$C_MAXRSS+1], /* expanded name buffer for sys$parse */
- res_nam[NAM$C_MAXRSS+1]; /* resultant name buffer for sys$search */
+ char exp_nam[NAM$C_MAXRSS+1], /* expanded name buffer for SYS$PARSE */
+ res_nam[NAM$C_MAXRSS+1]; /* resultant name buffer for SYS$SEARCH */
fab = cc$rms_fab;
fab.fab$l_fna = (char *) name;
@@ -10421,9 +10789,9 @@ VMS_stat (name, statbuf)
nam.nam$l_esa = exp_nam, nam.nam$b_ess = sizeof exp_nam - 1;
nam.nam$l_rsa = res_nam, nam.nam$b_rss = sizeof res_nam - 1;
nam.nam$b_nop = NAM$M_PWD | NAM$M_NOCONCEAL;
- if (sys$parse (&fab) & 1)
+ if (SYS$PARSE (&fab) & 1)
{
- if (sys$search (&fab) & 1)
+ if (SYS$SEARCH (&fab) & 1)
{
res_nam[nam.nam$b_rsl] = '\0';
result = stat (res_nam, statbuf);
@@ -10431,7 +10799,7 @@ VMS_stat (name, statbuf)
/* Clean up searchlist context cached by the system. */
nam.nam$b_nop = NAM$M_SYNCHK;
fab.fab$l_fna = 0, fab.fab$b_fns = 0;
- (void) sys$parse (&fab);
+ (void) SYS$PARSE (&fab);
}
}
diff --git a/contrib/gcc/cexp.y b/contrib/gcc/cexp.y
index d83de80..6280aed 100644
--- a/contrib/gcc/cexp.y
+++ b/contrib/gcc/cexp.y
@@ -1,5 +1,5 @@
/* Parse C expressions for CCCP.
- Copyright (C) 1987, 1992, 1994, 1995 Free Software Foundation.
+ Copyright (C) 1987, 1992, 94 - 97, 1998 Free Software Foundation.
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
@@ -26,15 +26,25 @@ Boston, MA 02111-1307, USA.
%{
#include "config.h"
+#ifdef __STDC__
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+#define PRINTF_PROTO(ARGS, m, n) PVPROTO (ARGS) ATTRIBUTE_PRINTF(m, n)
+
+#define PRINTF_PROTO_1(ARGS) PRINTF_PROTO(ARGS, 1, 2)
+
+#include "system.h"
#include <setjmp.h>
/* #define YYDEBUG 1 */
#ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
#include <locale.h>
#endif
-#include <stdio.h>
+#include "gansidecl.h"
typedef unsigned char U_CHAR;
@@ -46,42 +56,48 @@ struct arglist {
int argno;
};
-/* Define a generic NULL if one hasn't already been defined. */
-
-#ifndef NULL
-#define NULL 0
+/* Find the largest host integer type and set its size and type.
+ Watch out: on some crazy hosts `long' is shorter than `int'. */
+
+#ifndef HOST_WIDE_INT
+# if HAVE_INTTYPES_H
+# include <inttypes.h>
+# define HOST_WIDE_INT intmax_t
+# define unsigned_HOST_WIDE_INT uintmax_t
+# else
+# if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT)
+# define HOST_WIDE_INT int
+# else
+# if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG || ! (defined LONG_LONG_MAX || defined LLONG_MAX))
+# define HOST_WIDE_INT long
+# else
+# define HOST_WIDE_INT long long
+# endif
+# endif
+# endif
#endif
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
-#endif
+#ifndef unsigned_HOST_WIDE_INT
+#define unsigned_HOST_WIDE_INT unsigned HOST_WIDE_INT
#endif
-/* Find the largest host integer type and set its size and type. */
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
#ifndef HOST_BITS_PER_WIDE_INT
-
-#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
-#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
-#define HOST_WIDE_INT long
-#else
-#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
-#define HOST_WIDE_INT int
+#define HOST_BITS_PER_WIDE_INT (CHAR_BIT * sizeof (HOST_WIDE_INT))
#endif
-#endif
+HOST_WIDE_INT parse_c_expression PROTO((char *, int));
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
+static int yylex PROTO((void));
+static void yyerror PROTO((char *)) __attribute__ ((noreturn));
+static HOST_WIDE_INT expression_value;
+#ifdef TEST_EXP_READER
+static int expression_signedp;
#endif
-int yylex ();
-void yyerror ();
-HOST_WIDE_INT expression_value;
-
static jmp_buf parse_return_error;
/* Nonzero means count most punctuation as part of a name. */
@@ -91,10 +107,11 @@ static int keyword_parsing = 0;
This is a count, since unevaluated expressions can nest. */
static int skip_evaluation;
-/* some external tables of character types */
-extern unsigned char is_idstart[], is_idchar[], is_hor_space[];
+/* Nonzero means warn if undefined identifiers are evaluated. */
+static int warn_undef;
-extern char *xmalloc ();
+/* some external tables of character types */
+extern unsigned char is_idstart[], is_idchar[], is_space[];
/* Flag for -pedantic. */
extern int pedantic;
@@ -102,6 +119,9 @@ extern int pedantic;
/* Flag for -traditional. */
extern int traditional;
+/* Flag for -lang-c89. */
+extern int c89;
+
#ifndef CHAR_TYPE_SIZE
#define CHAR_TYPE_SIZE BITS_PER_UNIT
#endif
@@ -134,17 +154,46 @@ extern int traditional;
#define MAX_WCHAR_TYPE_SIZE WCHAR_TYPE_SIZE
#endif
-/* Yield nonzero if adding two numbers with A's and B's signs can yield a
- number with SUM's sign, where A, B, and SUM are all C integers. */
-#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
-
-static void integer_overflow ();
-static long left_shift ();
-static long right_shift ();
+#define MAX_CHAR_TYPE_MASK (MAX_CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT \
+ ? (~ (~ (HOST_WIDE_INT) 0 << MAX_CHAR_TYPE_SIZE)) \
+ : ~ (HOST_WIDE_INT) 0)
+
+#define MAX_WCHAR_TYPE_MASK (MAX_WCHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT \
+ ? ~ (~ (HOST_WIDE_INT) 0 << MAX_WCHAR_TYPE_SIZE) \
+ : ~ (HOST_WIDE_INT) 0)
+
+/* Suppose A1 + B1 = SUM1, using 2's complement arithmetic ignoring overflow.
+ Suppose A, B and SUM have the same respective signs as A1, B1, and SUM1.
+ Suppose SIGNEDP is negative if the result is signed, zero if unsigned.
+ Then this yields nonzero if overflow occurred during the addition.
+ Overflow occurs if A and B have the same sign, but A and SUM differ in sign,
+ and SIGNEDP is negative.
+ Use `^' to test whether signs differ, and `< 0' to isolate the sign. */
+#define overflow_sum_sign(a, b, sum, signedp) \
+ ((~((a) ^ (b)) & ((a) ^ (sum)) & (signedp)) < 0)
+
+struct constant;
+
+GENERIC_PTR xmalloc PROTO((size_t));
+HOST_WIDE_INT parse_escape PROTO((char **, HOST_WIDE_INT));
+int check_assertion PROTO((U_CHAR *, int, int, struct arglist *));
+struct hashnode *lookup PROTO((U_CHAR *, int, int));
+void error PRINTF_PROTO_1((char *, ...));
+void pedwarn PRINTF_PROTO_1((char *, ...));
+void warning PRINTF_PROTO_1((char *, ...));
+
+static int parse_number PROTO((int));
+static HOST_WIDE_INT left_shift PROTO((struct constant *, unsigned_HOST_WIDE_INT));
+static HOST_WIDE_INT right_shift PROTO((struct constant *, unsigned_HOST_WIDE_INT));
+static void integer_overflow PROTO((void));
+
+/* `signedp' values */
+#define SIGNED (~0)
+#define UNSIGNED 0
%}
%union {
- struct constant {long value; int unsignedp;} integer;
+ struct constant {HOST_WIDE_INT value; int signedp;} integer;
struct name {U_CHAR *address; int length;} name;
struct arglist *keywords;
}
@@ -174,7 +223,12 @@ static long right_shift ();
%%
start : exp1
- { expression_value = $1.value; }
+ {
+ expression_value = $1.value;
+#ifdef TEST_EXP_READER
+ expression_signedp = $1.signedp;
+#endif
+ }
;
/* Expressions, including the comma operator. */
@@ -188,45 +242,46 @@ exp1 : exp
/* Expressions, not including the comma operator. */
exp : '-' exp %prec UNARY
{ $$.value = - $2.value;
- if (($$.value & $2.value) < 0 && ! $2.unsignedp)
- integer_overflow ();
- $$.unsignedp = $2.unsignedp; }
+ $$.signedp = $2.signedp;
+ if (($$.value & $2.value & $$.signedp) < 0)
+ integer_overflow (); }
| '!' exp %prec UNARY
{ $$.value = ! $2.value;
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| '+' exp %prec UNARY
{ $$ = $2; }
| '~' exp %prec UNARY
{ $$.value = ~ $2.value;
- $$.unsignedp = $2.unsignedp; }
+ $$.signedp = $2.signedp; }
| '#' NAME
{ $$.value = check_assertion ($2.address, $2.length,
0, NULL_PTR);
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| '#' NAME
{ keyword_parsing = 1; }
'(' keywords ')'
{ $$.value = check_assertion ($2.address, $2.length,
1, $5);
keyword_parsing = 0;
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| '(' exp1 ')'
{ $$ = $2; }
;
/* Binary operators in order of decreasing precedence. */
exp : exp '*' exp
- { $$.unsignedp = $1.unsignedp || $3.unsignedp;
- if ($$.unsignedp)
- $$.value = (unsigned long) $1.value * $3.value;
- else
+ { $$.signedp = $1.signedp & $3.signedp;
+ if ($$.signedp)
{
$$.value = $1.value * $3.value;
if ($1.value
&& ($$.value / $1.value != $3.value
|| ($$.value & $1.value & $3.value) < 0))
integer_overflow ();
- } }
+ }
+ else
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
+ * $3.value); }
| exp '/' exp
{ if ($3.value == 0)
{
@@ -234,15 +289,16 @@ exp : exp '*' exp
error ("division by zero in #if");
$3.value = 1;
}
- $$.unsignedp = $1.unsignedp || $3.unsignedp;
- if ($$.unsignedp)
- $$.value = (unsigned long) $1.value / $3.value;
- else
+ $$.signedp = $1.signedp & $3.signedp;
+ if ($$.signedp)
{
$$.value = $1.value / $3.value;
if (($$.value & $1.value & $3.value) < 0)
integer_overflow ();
- } }
+ }
+ else
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
+ / $3.value); }
| exp '%' exp
{ if ($3.value == 0)
{
@@ -250,88 +306,91 @@ exp : exp '*' exp
error ("division by zero in #if");
$3.value = 1;
}
- $$.unsignedp = $1.unsignedp || $3.unsignedp;
- if ($$.unsignedp)
- $$.value = (unsigned long) $1.value % $3.value;
+ $$.signedp = $1.signedp & $3.signedp;
+ if ($$.signedp)
+ $$.value = $1.value % $3.value;
else
- $$.value = $1.value % $3.value; }
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
+ % $3.value); }
| exp '+' exp
{ $$.value = $1.value + $3.value;
- $$.unsignedp = $1.unsignedp || $3.unsignedp;
- if (! $$.unsignedp
- && ! possible_sum_sign ($1.value, $3.value,
- $$.value))
+ $$.signedp = $1.signedp & $3.signedp;
+ if (overflow_sum_sign ($1.value, $3.value,
+ $$.value, $$.signedp))
integer_overflow (); }
| exp '-' exp
{ $$.value = $1.value - $3.value;
- $$.unsignedp = $1.unsignedp || $3.unsignedp;
- if (! $$.unsignedp
- && ! possible_sum_sign ($$.value, $3.value,
- $1.value))
+ $$.signedp = $1.signedp & $3.signedp;
+ if (overflow_sum_sign ($$.value, $3.value,
+ $1.value, $$.signedp))
integer_overflow (); }
| exp LSH exp
- { $$.unsignedp = $1.unsignedp;
- if ($3.value < 0 && ! $3.unsignedp)
+ { $$.signedp = $1.signedp;
+ if (($3.value & $3.signedp) < 0)
$$.value = right_shift (&$1, -$3.value);
else
$$.value = left_shift (&$1, $3.value); }
| exp RSH exp
- { $$.unsignedp = $1.unsignedp;
- if ($3.value < 0 && ! $3.unsignedp)
+ { $$.signedp = $1.signedp;
+ if (($3.value & $3.signedp) < 0)
$$.value = left_shift (&$1, -$3.value);
else
$$.value = right_shift (&$1, $3.value); }
| exp EQUAL exp
{ $$.value = ($1.value == $3.value);
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| exp NOTEQUAL exp
{ $$.value = ($1.value != $3.value);
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| exp LEQ exp
- { $$.unsignedp = 0;
- if ($1.unsignedp || $3.unsignedp)
- $$.value = (unsigned long) $1.value <= $3.value;
+ { $$.signedp = SIGNED;
+ if ($1.signedp & $3.signedp)
+ $$.value = $1.value <= $3.value;
else
- $$.value = $1.value <= $3.value; }
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
+ <= $3.value); }
| exp GEQ exp
- { $$.unsignedp = 0;
- if ($1.unsignedp || $3.unsignedp)
- $$.value = (unsigned long) $1.value >= $3.value;
+ { $$.signedp = SIGNED;
+ if ($1.signedp & $3.signedp)
+ $$.value = $1.value >= $3.value;
else
- $$.value = $1.value >= $3.value; }
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
+ >= $3.value); }
| exp '<' exp
- { $$.unsignedp = 0;
- if ($1.unsignedp || $3.unsignedp)
- $$.value = (unsigned long) $1.value < $3.value;
+ { $$.signedp = SIGNED;
+ if ($1.signedp & $3.signedp)
+ $$.value = $1.value < $3.value;
else
- $$.value = $1.value < $3.value; }
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
+ < $3.value); }
| exp '>' exp
- { $$.unsignedp = 0;
- if ($1.unsignedp || $3.unsignedp)
- $$.value = (unsigned long) $1.value > $3.value;
+ { $$.signedp = SIGNED;
+ if ($1.signedp & $3.signedp)
+ $$.value = $1.value > $3.value;
else
- $$.value = $1.value > $3.value; }
+ $$.value = ((unsigned_HOST_WIDE_INT) $1.value
+ > $3.value); }
| exp '&' exp
{ $$.value = $1.value & $3.value;
- $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ $$.signedp = $1.signedp & $3.signedp; }
| exp '^' exp
{ $$.value = $1.value ^ $3.value;
- $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ $$.signedp = $1.signedp & $3.signedp; }
| exp '|' exp
{ $$.value = $1.value | $3.value;
- $$.unsignedp = $1.unsignedp || $3.unsignedp; }
+ $$.signedp = $1.signedp & $3.signedp; }
| exp AND
{ skip_evaluation += !$1.value; }
exp
{ skip_evaluation -= !$1.value;
$$.value = ($1.value && $4.value);
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| exp OR
{ skip_evaluation += !!$1.value; }
exp
{ skip_evaluation -= !!$1.value;
$$.value = ($1.value || $4.value);
- $$.unsignedp = 0; }
+ $$.signedp = SIGNED; }
| exp '?'
{ skip_evaluation += !$1.value; }
exp ':'
@@ -339,14 +398,17 @@ exp : exp '*' exp
exp
{ skip_evaluation -= !!$1.value;
$$.value = $1.value ? $4.value : $7.value;
- $$.unsignedp = $4.unsignedp || $7.unsignedp; }
+ $$.signedp = $4.signedp & $7.signedp; }
| INT
{ $$ = yylval.integer; }
| CHAR
{ $$ = yylval.integer; }
| NAME
- { $$.value = 0;
- $$.unsignedp = 0; }
+ { if (warn_undef && !skip_evaluation)
+ warning ("`%.*s' is not defined",
+ $1.length, $1.address);
+ $$.value = 0;
+ $$.signedp = SIGNED; }
;
keywords :
@@ -383,37 +445,31 @@ static char *lexptr;
/* maybe needs to actually deal with floating point numbers */
-int
+static int
parse_number (olen)
int olen;
{
register char *p = lexptr;
register int c;
- register unsigned long n = 0, nd, ULONG_MAX_over_base;
+ register unsigned_HOST_WIDE_INT n = 0, nd, max_over_base;
register int base = 10;
register int len = olen;
register int overflow = 0;
register int digit, largest_digit = 0;
int spec_long = 0;
- for (c = 0; c < len; c++)
- if (p[c] == '.') {
- /* It's a float since it contains a point. */
- yyerror ("floating point numbers not allowed in #if expressions");
- return ERROR;
- }
-
- yylval.integer.unsignedp = 0;
+ yylval.integer.signedp = SIGNED;
- if (len >= 3 && (!strncmp (p, "0x", 2) || !strncmp (p, "0X", 2))) {
- p += 2;
- base = 16;
- len -= 2;
- }
- else if (*p == '0')
+ if (*p == '0') {
base = 8;
+ if (len >= 3 && (p[1] == 'x' || p[1] == 'X')) {
+ p += 2;
+ base = 16;
+ len -= 2;
+ }
+ }
- ULONG_MAX_over_base = (unsigned long) -1 / base;
+ max_over_base = (unsigned_HOST_WIDE_INT) -1 / base;
for (; len > 0; len--) {
c = *p++;
@@ -429,18 +485,26 @@ parse_number (olen)
while (1) {
if (c == 'l' || c == 'L')
{
- if (spec_long)
- yyerror ("two `l's in integer constant");
- spec_long = 1;
+ if (!pedantic < spec_long)
+ yyerror ("too many `l's in integer constant");
+ spec_long++;
}
else if (c == 'u' || c == 'U')
{
- if (yylval.integer.unsignedp)
+ if (! yylval.integer.signedp)
yyerror ("two `u's in integer constant");
- yylval.integer.unsignedp = 1;
+ yylval.integer.signedp = UNSIGNED;
}
- else
- break;
+ else {
+ if (c == '.' || c == 'e' || c == 'E' || c == 'p' || c == 'P')
+ yyerror ("Floating point numbers not allowed in #if expressions");
+ else {
+ char *buf = (char *) alloca (p - lexptr + 40);
+ sprintf (buf, "missing white space after number `%.*s'",
+ (int) (p - lexptr - 1), lexptr);
+ yyerror (buf);
+ }
+ }
if (--len == 0)
break;
@@ -452,27 +516,22 @@ parse_number (olen)
if (largest_digit < digit)
largest_digit = digit;
nd = n * base + digit;
- overflow |= ULONG_MAX_over_base < n | nd < n;
+ overflow |= (max_over_base < n) | (nd < n);
n = nd;
}
- if (len != 0) {
- yyerror ("Invalid number in #if expression");
- return ERROR;
- }
-
if (base <= largest_digit)
- warning ("integer constant contains digits beyond the radix");
+ pedwarn ("integer constant contains digits beyond the radix");
if (overflow)
- warning ("integer constant out of range");
+ pedwarn ("integer constant out of range");
/* If too big to be signed, consider it unsigned. */
- if ((long) n < 0 && ! yylval.integer.unsignedp)
+ if (((HOST_WIDE_INT) n & yylval.integer.signedp) < 0)
{
if (base == 10)
warning ("integer constant is so large that it is unsigned");
- yylval.integer.unsignedp = 1;
+ yylval.integer.signedp = UNSIGNED;
}
lexptr = p;
@@ -501,7 +560,7 @@ static struct token tokentab2[] = {
/* Read one token, getting characters through lexptr. */
-int
+static int
yylex ()
{
register int c;
@@ -509,6 +568,7 @@ yylex ()
register unsigned char *tokstart;
register struct token *toktab;
int wide_flag;
+ HOST_WIDE_INT mask;
retry:
@@ -529,13 +589,12 @@ yylex ()
}
switch (c) {
- case 0:
+ case '\n':
return 0;
case ' ':
case '\t':
case '\r':
- case '\n':
lexptr++;
goto retry;
@@ -545,18 +604,21 @@ yylex ()
{
lexptr++;
wide_flag = 1;
+ mask = MAX_WCHAR_TYPE_MASK;
goto char_constant;
}
if (lexptr[1] == '"')
{
lexptr++;
wide_flag = 1;
+ mask = MAX_WCHAR_TYPE_MASK;
goto string_constant;
}
break;
case '\'':
wide_flag = 0;
+ mask = MAX_CHAR_TYPE_MASK;
char_constant:
lexptr++;
if (keyword_parsing) {
@@ -564,7 +626,7 @@ yylex ()
while (1) {
c = *lexptr++;
if (c == '\\')
- c = parse_escape (&lexptr);
+ c = parse_escape (&lexptr, mask);
else if (c == '\'')
break;
}
@@ -577,8 +639,8 @@ yylex ()
handles multicharacter constants and wide characters.
It is mostly copied from c-lex.c. */
{
- register int result = 0;
- register num_chars = 0;
+ register HOST_WIDE_INT result = 0;
+ register int num_chars = 0;
unsigned width = MAX_CHAR_TYPE_SIZE;
int max_chars;
char *token_buffer;
@@ -606,19 +668,16 @@ yylex ()
if (c == '\\')
{
- c = parse_escape (&lexptr);
- if (width < HOST_BITS_PER_INT
- && (unsigned) c >= (1 << width))
- pedwarn ("escape sequence out of range for character");
+ c = parse_escape (&lexptr, mask);
}
num_chars++;
/* Merge character into result; ignore excess chars. */
- if (num_chars < max_chars + 1)
+ if (num_chars <= max_chars)
{
- if (width < HOST_BITS_PER_INT)
- result = (result << width) | (c & ((1 << width) - 1));
+ if (width < HOST_BITS_PER_WIDE_INT)
+ result = (result << width) | c;
else
result = c;
token_buffer[num_chars - 1] = c;
@@ -644,13 +703,16 @@ yylex ()
{
int num_bits = num_chars * width;
- if (lookup ("__CHAR_UNSIGNED__", sizeof ("__CHAR_UNSIGNED__")-1, -1)
+ if (lookup ((U_CHAR *) "__CHAR_UNSIGNED__",
+ sizeof ("__CHAR_UNSIGNED__") - 1, -1)
|| ((result >> (num_bits - 1)) & 1) == 0)
yylval.integer.value
- = result & ((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
+ = result & (~ (unsigned_HOST_WIDE_INT) 0
+ >> (HOST_BITS_PER_WIDE_INT - num_bits));
else
yylval.integer.value
- = result | ~((unsigned long) ~0 >> (HOST_BITS_PER_LONG - num_bits));
+ = result | ~(~ (unsigned_HOST_WIDE_INT) 0
+ >> (HOST_BITS_PER_WIDE_INT - num_bits));
}
else
{
@@ -667,7 +729,7 @@ yylex ()
if (mbtowc (& wc, token_buffer, num_chars) == num_chars)
result = wc;
else
- warning ("Ignoring invalid multibyte character");
+ pedwarn ("Ignoring invalid multibyte character");
}
#endif
yylval.integer.value = result;
@@ -675,7 +737,7 @@ yylex ()
}
/* This is always a signed type. */
- yylval.integer.unsignedp = 0;
+ yylval.integer.signedp = SIGNED;
return CHAR;
@@ -712,6 +774,7 @@ yylex ()
return c;
case '"':
+ mask = MAX_CHAR_TYPE_MASK;
string_constant:
if (keyword_parsing) {
char *start_ptr = lexptr;
@@ -719,7 +782,7 @@ yylex ()
while (1) {
c = *lexptr++;
if (c == '\\')
- c = parse_escape (&lexptr);
+ c = parse_escape (&lexptr, mask);
else if (c == '"')
break;
}
@@ -733,10 +796,16 @@ yylex ()
if (c >= '0' && c <= '9' && !keyword_parsing) {
/* It's a number */
- for (namelen = 0;
- c = tokstart[namelen], is_idchar[c] || c == '.';
- namelen++)
- ;
+ for (namelen = 1; ; namelen++) {
+ int d = tokstart[namelen];
+ if (! ((is_idchar[d] || d == '.')
+ || ((d == '-' || d == '+')
+ && (c == 'e' || c == 'E'
+ || ((c == 'p' || c == 'P') && ! c89))
+ && ! traditional)))
+ break;
+ c = d;
+ }
return parse_number (namelen);
}
@@ -744,7 +813,7 @@ yylex ()
if (keyword_parsing) {
for (namelen = 0;; namelen++) {
- if (is_hor_space[tokstart[namelen]])
+ if (is_space[tokstart[namelen]])
break;
if (tokstart[namelen] == '(' || tokstart[namelen] == ')')
break;
@@ -773,6 +842,9 @@ yylex ()
is updated past the characters we use. The value of the
escape sequence is returned.
+ RESULT_MASK is used to mask out the result;
+ an error is reported if bits are lost thereby.
+
A negative value means the sequence \ newline was seen,
which is supposed to be equivalent to nothing at all.
@@ -782,9 +854,10 @@ yylex ()
If \ is followed by 000, we return 0 and leave the string pointer
after the zeros. A value of 0 does not mean end of string. */
-int
-parse_escape (string_ptr)
+HOST_WIDE_INT
+parse_escape (string_ptr, result_mask)
char **string_ptr;
+ HOST_WIDE_INT result_mask;
{
register int c = *(*string_ptr)++;
switch (c)
@@ -823,7 +896,7 @@ parse_escape (string_ptr)
case '6':
case '7':
{
- register int i = c - '0';
+ register HOST_WIDE_INT i = c - '0';
register int count = 0;
while (++count < 3)
{
@@ -836,16 +909,17 @@ parse_escape (string_ptr)
break;
}
}
- if ((i & ~((1 << MAX_CHAR_TYPE_SIZE) - 1)) != 0)
+ if (i != (i & result_mask))
{
- i &= (1 << MAX_CHAR_TYPE_SIZE) - 1;
- warning ("octal character constant does not fit in a byte");
+ i &= result_mask;
+ pedwarn ("octal escape sequence out of range");
}
return i;
}
case 'x':
{
- register unsigned i = 0, overflow = 0, digits_found = 0, digit;
+ register unsigned_HOST_WIDE_INT i = 0, overflow = 0;
+ register int digits_found = 0, digit;
for (;;)
{
c = *(*string_ptr)++;
@@ -866,10 +940,10 @@ parse_escape (string_ptr)
}
if (!digits_found)
yyerror ("\\x used with no following hex digits");
- if (overflow | (i & ~((1 << BITS_PER_UNIT) - 1)))
+ if (overflow | (i != (i & result_mask)))
{
- i &= (1 << BITS_PER_UNIT) - 1;
- warning ("hex character constant does not fit in a byte");
+ i &= result_mask;
+ pedwarn ("hex escape sequence out of range");
}
return i;
}
@@ -878,11 +952,11 @@ parse_escape (string_ptr)
}
}
-void
+static void
yyerror (s)
char *s;
{
- error (s);
+ error ("%s", s);
skip_evaluation = 0;
longjmp (parse_return_error, 1);
}
@@ -894,52 +968,50 @@ integer_overflow ()
pedwarn ("integer overflow in preprocessor expression");
}
-static long
+static HOST_WIDE_INT
left_shift (a, b)
struct constant *a;
- unsigned long b;
+ unsigned_HOST_WIDE_INT b;
{
/* It's unclear from the C standard whether shifts can overflow.
The following code ignores overflow; perhaps a C standard
interpretation ruling is needed. */
- if (b >= HOST_BITS_PER_LONG)
+ if (b >= HOST_BITS_PER_WIDE_INT)
return 0;
- else if (a->unsignedp)
- return (unsigned long) a->value << b;
else
- return a->value << b;
+ return (unsigned_HOST_WIDE_INT) a->value << b;
}
-static long
+static HOST_WIDE_INT
right_shift (a, b)
struct constant *a;
- unsigned long b;
+ unsigned_HOST_WIDE_INT b;
{
- if (b >= HOST_BITS_PER_LONG)
- return a->unsignedp ? 0 : a->value >> (HOST_BITS_PER_LONG - 1);
- else if (a->unsignedp)
- return (unsigned long) a->value >> b;
- else
+ if (b >= HOST_BITS_PER_WIDE_INT)
+ return a->signedp ? a->value >> (HOST_BITS_PER_WIDE_INT - 1) : 0;
+ else if (a->signedp)
return a->value >> b;
+ else
+ return (unsigned_HOST_WIDE_INT) a->value >> b;
}
/* This page contains the entry point to this file. */
/* Parse STRING as an expression, and complain if this fails
- to use up all of the contents of STRING. */
-/* We do not support C comments. They should be removed before
+ to use up all of the contents of STRING.
+ STRING may contain '\0' bytes; it is terminated by the first '\n'
+ outside a string constant, so that we can diagnose '\0' properly.
+ If WARN_UNDEFINED is nonzero, warn if undefined identifiers are evaluated.
+ We do not support C comments. They should be removed before
this function is called. */
HOST_WIDE_INT
-parse_c_expression (string)
+parse_c_expression (string, warn_undefined)
char *string;
+ int warn_undefined;
{
lexptr = string;
-
- if (lexptr == 0 || *lexptr == 0) {
- error ("empty #if expression");
- return 0; /* don't include the #if group */
- }
+ warn_undef = warn_undefined;
/* if there is some sort of scanning error, just return 0 and assume
the parsing routine has printed an error message somewhere.
@@ -947,55 +1019,92 @@ parse_c_expression (string)
if (setjmp (parse_return_error))
return 0;
- if (yyparse ())
- return 0; /* actually this is never reached
- the way things stand. */
- if (*lexptr)
+ if (yyparse () != 0)
+ abort ();
+
+ if (*lexptr != '\n')
error ("Junk after end of expression.");
return expression_value; /* set by yyparse () */
}
#ifdef TEST_EXP_READER
+
+#if YYDEBUG
extern int yydebug;
+#endif
+
+int pedantic;
+int traditional;
+
+int main PROTO((int, char **));
+static void initialize_random_junk PROTO((void));
+static void print_unsigned_host_wide_int PROTO((unsigned_HOST_WIDE_INT));
/* Main program for testing purposes. */
int
-main ()
+main (argc, argv)
+ int argc;
+ char **argv;
{
int n, c;
char buf[1024];
+ unsigned_HOST_WIDE_INT u;
-/*
- yydebug = 1;
-*/
+ pedantic = 1 < argc;
+ traditional = 2 < argc;
+#if YYDEBUG
+ yydebug = 3 < argc;
+#endif
initialize_random_junk ();
for (;;) {
printf ("enter expression: ");
n = 0;
- while ((buf[n] = getchar ()) != '\n' && buf[n] != EOF)
+ while ((buf[n] = c = getchar ()) != '\n' && c != EOF)
n++;
- if (buf[n] == EOF)
+ if (c == EOF)
break;
- buf[n] = '\0';
- printf ("parser returned %ld\n", parse_c_expression (buf));
+ parse_c_expression (buf, 1);
+ printf ("parser returned ");
+ u = (unsigned_HOST_WIDE_INT) expression_value;
+ if (expression_value < 0 && expression_signedp) {
+ u = -u;
+ printf ("-");
+ }
+ if (u == 0)
+ printf ("0");
+ else
+ print_unsigned_host_wide_int (u);
+ if (! expression_signedp)
+ printf("u");
+ printf ("\n");
}
return 0;
}
+static void
+print_unsigned_host_wide_int (u)
+ unsigned_HOST_WIDE_INT u;
+{
+ if (u) {
+ print_unsigned_host_wide_int (u / 10);
+ putchar ('0' + (int) (u % 10));
+ }
+}
+
/* table to tell if char can be part of a C identifier. */
unsigned char is_idchar[256];
/* table to tell if char can be first char of a c identifier. */
unsigned char is_idstart[256];
-/* table to tell if c is horizontal space. isspace () thinks that
- newline is space; this is not a good idea for this program. */
-char is_hor_space[256];
+/* table to tell if c is horizontal or vertical space. */
+unsigned char is_space[256];
/*
* initialize random junk in the hash table and maybe other places
*/
+static void
initialize_random_junk ()
{
register int i;
@@ -1016,32 +1125,100 @@ initialize_random_junk ()
++is_idchar[i];
++is_idchar['_'];
++is_idstart['_'];
-#if DOLLARS_IN_IDENTIFIERS
++is_idchar['$'];
++is_idstart['$'];
+
+ ++is_space[' '];
+ ++is_space['\t'];
+ ++is_space['\v'];
+ ++is_space['\f'];
+ ++is_space['\n'];
+ ++is_space['\r'];
+}
+
+void
+error VPROTO ((char * msg, ...))
+{
+#ifndef __STDC__
+ char * msg;
#endif
+ va_list args;
- /* horizontal space table */
- ++is_hor_space[' '];
- ++is_hor_space['\t'];
+ VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
+ fprintf (stderr, "error: ");
+ vfprintf (stderr, msg, args);
+ fprintf (stderr, "\n");
+ va_end (args);
}
-error (msg)
+void
+pedwarn VPROTO ((char * msg, ...))
{
- printf ("error: %s\n", msg);
+#ifndef __STDC__
+ char * msg;
+#endif
+ va_list args;
+
+ VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
+ fprintf (stderr, "pedwarn: ");
+ vfprintf (stderr, msg, args);
+ fprintf (stderr, "\n");
+ va_end (args);
}
-warning (msg)
+void
+warning VPROTO ((char * msg, ...))
{
- printf ("warning: %s\n", msg);
+#ifndef __STDC__
+ char * msg;
+#endif
+ va_list args;
+
+ VA_START (args, msg);
+
+#ifndef __STDC__
+ msg = va_arg (args, char *);
+#endif
+
+ fprintf (stderr, "warning: ");
+ vfprintf (stderr, msg, args);
+ fprintf (stderr, "\n");
+ va_end (args);
+}
+
+int
+check_assertion (name, sym_length, tokens_specified, tokens)
+ U_CHAR *name;
+ int sym_length;
+ int tokens_specified;
+ struct arglist *tokens;
+{
+ return 0;
}
struct hashnode *
lookup (name, len, hash)
- char *name;
+ U_CHAR *name;
int len;
int hash;
{
return (DEFAULT_SIGNED_CHAR) ? 0 : ((struct hashnode *) -1);
}
+
+GENERIC_PTR
+xmalloc (size)
+ size_t size;
+{
+ return (GENERIC_PTR) malloc (size);
+}
#endif
diff --git a/contrib/gcc/choose-temp.c b/contrib/gcc/choose-temp.c
new file mode 100644
index 0000000..4629336
--- /dev/null
+++ b/contrib/gcc/choose-temp.c
@@ -0,0 +1,211 @@
+/* Utility to pick a temporary filename prefix.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file exports two functions: choose_temp_base and make_temp_file. */
+
+/* This file lives in at least two places: libiberty and gcc.
+ Don't change one without the other. */
+
+#if defined (IN_GCC) || defined (HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#ifdef IN_GCC
+#include "system.h"
+#else
+
+/* If we are in gcc, system.h has handled everything. When not in
+ gcc, if we have a config.h we assume that HAVE_SYS_FILE_H tells us
+ whether to include sys/file.h. However, libiberty does not have a
+ config.h, and instead arranges to define NO_SYS_FILE_H on the
+ command line when there is no sys/file.h. */
+
+#if defined (HAVE_CONFIG_H) ? defined (HAVE_SYS_FILE_H) : ! defined (NO_SYS_FILE_H)
+#include <sys/types.h>
+#include <sys/file.h> /* May get R_OK, etc. on some systems. */
+#endif
+
+#ifndef R_OK
+#define R_OK 4
+#define W_OK 2
+#define X_OK 1
+#endif
+
+#include <stdio.h> /* May get P_tmpdir. */
+#endif /* IN_GCC */
+
+#ifdef IN_GCC
+#include "gansidecl.h"
+extern char *xmalloc ();
+#else
+#include "ansidecl.h"
+#include "libiberty.h"
+#if defined (__MSDOS__) || defined (_WIN32)
+#define DIR_SEPARATOR '\\'
+#endif
+#endif
+
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+/* On MSDOS, write temp files in current dir
+ because there's no place else we can expect to use. */
+/* ??? Although the current directory is tried as a last resort,
+ this is left in so that on MSDOS it is preferred to /tmp on the
+ off chance that someone requires this, since that was the previous
+ behaviour. */
+#ifdef __MSDOS__
+#ifndef P_tmpdir
+#define P_tmpdir "."
+#endif
+#endif
+
+/* Name of temporary file.
+ mktemp requires 6 trailing X's. */
+#define TEMP_FILE "ccXXXXXX"
+
+/* Subroutine of choose_temp_base.
+ If BASE is non-NULL, return it.
+ Otherwise it checks if DIR is a usable directory.
+ If success, DIR is returned.
+ Otherwise NULL is returned. */
+
+static char *
+try (dir, base)
+ char *dir, *base;
+{
+ if (base != 0)
+ return base;
+ if (dir != 0
+ && access (dir, R_OK | W_OK | X_OK) == 0)
+ return dir;
+ return 0;
+}
+
+/* Return a prefix for temporary file names or NULL if unable to find one.
+ The current directory is chosen if all else fails so the program is
+ exited if a temporary directory can't be found (mktemp fails).
+ The buffer for the result is obtained with xmalloc.
+
+ This function is provided for backwards compatability only. It use
+ is not recommended. */
+
+char *
+choose_temp_base ()
+{
+ char *base = 0;
+ char *temp_filename;
+ int len;
+ static char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 };
+ static char usrtmp[] = { DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
+
+ base = try (getenv ("TMPDIR"), base);
+ base = try (getenv ("TMP"), base);
+ base = try (getenv ("TEMP"), base);
+
+#ifdef P_tmpdir
+ base = try (P_tmpdir, base);
+#endif
+
+ /* Try /usr/tmp, then /tmp. */
+ base = try (usrtmp, base);
+ base = try (tmp, base);
+
+ /* If all else fails, use the current directory! */
+ if (base == 0)
+ base = ".";
+
+ len = strlen (base);
+ temp_filename = xmalloc (len + 1 /*DIR_SEPARATOR*/
+ + strlen (TEMP_FILE) + 1);
+ strcpy (temp_filename, base);
+
+ if (len != 0
+ && temp_filename[len-1] != '/'
+ && temp_filename[len-1] != DIR_SEPARATOR)
+ temp_filename[len++] = DIR_SEPARATOR;
+ strcpy (temp_filename + len, TEMP_FILE);
+
+ mktemp (temp_filename);
+ if (strlen (temp_filename) == 0)
+ abort ();
+ return temp_filename;
+}
+/* Return a temporary file name (as a string) or NULL if unable to create
+ one. */
+
+char *
+make_temp_file (suffix)
+ char *suffix;
+{
+ char *base = 0;
+ char *temp_filename;
+ int base_len, suffix_len;
+ int fd;
+ static char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 };
+ static char usrtmp[] = { DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 };
+
+ base = try (getenv ("TMPDIR"), base);
+ base = try (getenv ("TMP"), base);
+ base = try (getenv ("TEMP"), base);
+
+#ifdef P_tmpdir
+ base = try (P_tmpdir, base);
+#endif
+
+ /* Try /usr/tmp, then /tmp. */
+ base = try (usrtmp, base);
+ base = try (tmp, base);
+
+ /* If all else fails, use the current directory! */
+ if (base == 0)
+ base = ".";
+
+ base_len = strlen (base);
+
+ if (suffix)
+ suffix_len = strlen (suffix);
+ else
+ suffix_len = 0;
+
+ temp_filename = xmalloc (base_len + 1 /*DIR_SEPARATOR*/
+ + strlen (TEMP_FILE)
+ + suffix_len + 1);
+ strcpy (temp_filename, base);
+
+ if (base_len != 0
+ && temp_filename[base_len-1] != '/'
+ && temp_filename[base_len-1] != DIR_SEPARATOR)
+ temp_filename[base_len++] = DIR_SEPARATOR;
+ strcpy (temp_filename + base_len, TEMP_FILE);
+
+ if (suffix)
+ strcat (temp_filename, suffix);
+
+ fd = mkstemps (temp_filename, suffix_len);
+ /* If mkstemps failed, then something bad is happening. Maybe we should
+ issue a message about a possible security attack in progress? */
+ if (fd == -1)
+ abort ();
+ /* Similarly if we can not close the file. */
+ if (close (fd))
+ abort ();
+ return temp_filename;
+}
diff --git a/contrib/gcc/collect2.c b/contrib/gcc/collect2.c
index 30fb49d..4fcbe73 100644
--- a/contrib/gcc/collect2.c
+++ b/contrib/gcc/collect2.c
@@ -1,8 +1,6 @@
-/* Collect static initialization info into data structures
- that can be traversed by C++ initialization and finalization
- routines.
-
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+/* Collect static initialization info into data structures that can be
+ traversed by C++ initialization and finalization routines.
+ Copyright (C) 1992, 93-97, 1998 Free Software Foundation, Inc.
Contributed by Chris Smith (csmith@convex.com).
Heavily modified by Michael Meissner (meissner@cygnus.com),
Per Bothner (bothner@cygnus.com), and John Gilmore (gnu@cygnus.com).
@@ -25,67 +23,30 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* Build tables of static constructors and destructors and run ld. */
+/* Build tables of static constructors and destructors and run ld. */
#include "config.h"
-#include <sys/types.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
+#include "system.h"
#include <signal.h>
-#include <sys/file.h>
#include <sys/stat.h>
-#ifdef NO_WAIT_H
-#include <sys/wait.h>
-#endif
#define COLLECT
#include "demangle.h"
#include "obstack.h"
-
-#ifndef errno
-extern int errno;
-#endif
-
-#ifndef HAVE_STRERROR
-#if defined(bsd4_4)
-extern const char *const sys_errlist[];
-#else
-extern char *sys_errlist[];
-#endif
-extern int sys_nerr;
-#else
-char *strerror();
+#include "gansidecl.h"
+#ifdef __CYGWIN32__
+#include <process.h>
#endif
/* Obstack allocation and deallocation routines. */
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-#if !defined (__STDC__) && !defined (const)
-#define const
-#endif
-
#ifdef USG
#define vfork fork
#endif
-/* Add prototype support. */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
-#ifndef R_OK
-#define R_OK 4
-#define W_OK 2
-#define X_OK 1
-#endif
-
#ifndef WIFSIGNALED
#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
#endif
@@ -99,18 +60,12 @@ char *strerror();
#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
#endif
-/* On MSDOS, write temp files in current dir
- because there's no place else we can expect to use. */
-#ifdef __MSDOS__
-#ifndef P_tmpdir
-#define P_tmpdir "./"
-#endif
-#endif
+extern char *make_temp_file PROTO ((char *));
/* On certain systems, we have code that works by scanning the object file
directly. But this code uses system-specific header files and library
functions, so turn it off in a cross-compiler. Likewise, the names of
- the utilities aren't correct for a cross-compiler; we have to hope that
+ the utilities are not correct for a cross-compiler; we have to hope that
cross-versions are in the proper directories. */
#ifdef CROSS_COMPILE
@@ -123,10 +78,10 @@ char *strerror();
#undef REAL_STRIP_FILE_NAME
#endif
-/* If we can't use a special method, use the ordinary one:
+/* If we cannot use a special method, use the ordinary one:
run nm to find what symbols are present.
In a cross-compiler, this means you need a cross nm,
- but that isn't quite as unpleasant as special headers. */
+ but that is not quite as unpleasant as special headers. */
#if !defined (OBJECT_FORMAT_COFF) && !defined (OBJECT_FORMAT_ROSE)
#define OBJECT_FORMAT_NONE
@@ -158,10 +113,6 @@ char *strerror();
#define MY_ISCOFF(X) ISCOFF (X)
#endif
-#ifdef XCOFF_DEBUGGING_INFO
-#define XCOFF_SCAN_LIBS
-#endif
-
#endif /* OBJECT_FORMAT_COFF */
#ifdef OBJECT_FORMAT_ROSE
@@ -200,7 +151,7 @@ char *strerror();
#define SYMBOL__MAIN __main
#endif
-#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES || defined(XCOFF_SCAN_LIBS)
+#if defined (LDD_SUFFIX) || SUNOS4_SHARED_LIBRARIES
#define SCAN_LIBRARIES
#endif
@@ -210,7 +161,7 @@ int do_collecting = 1;
int do_collecting = 0;
#endif
-/* Linked lists of constructor and destructor names. */
+/* Linked lists of constructor and destructor names. */
struct id
{
@@ -236,7 +187,7 @@ enum pass {
};
#ifndef NO_SYS_SIGLIST
-#ifndef DONT_DECLARE_SYS_SIGLIST
+#ifndef SYS_SIGLIST_DECLARED
extern char *sys_siglist[];
#endif
#endif
@@ -245,27 +196,39 @@ extern char *version_string;
int vflag; /* true if -v */
static int rflag; /* true if -r */
static int strip_flag; /* true if -s */
+#ifdef COLLECT_EXPORT_LIST
+static int export_flag; /* true if -bE */
+static int aix64_flag; /* true if -b64 */
+#endif
int debug; /* true if -debug */
static int shared_obj; /* true if -shared */
-static int temp_filename_length; /* Length of temp_filename */
-static char *temp_filename; /* Base of temp filenames */
-static char *c_file; /* <xxx>.c for constructor/destructor list. */
-static char *o_file; /* <xxx>.o for constructor/destructor list. */
-static char *export_file; /* <xxx>.x for AIX export list. */
+static char *c_file; /* <xxx>.c for constructor/destructor list. */
+static char *o_file; /* <xxx>.o for constructor/destructor list. */
+#ifdef COLLECT_EXPORT_LIST
+static char *export_file; /* <xxx>.x for AIX export list. */
+static char *import_file; /* <xxx>.p for AIX import list. */
+#endif
char *ldout; /* File for ld errors. */
static char *output_file; /* Output file for ld. */
static char *nm_file_name; /* pathname of nm */
+#ifdef LDD_SUFFIX
static char *ldd_file_name; /* pathname of ldd (or equivalent) */
+#endif
static char *strip_file_name; /* pathname of strip */
char *c_file_name; /* pathname of gcc */
static char *initname, *fininame; /* names of init and fini funcs */
static struct head constructors; /* list of constructors found */
static struct head destructors; /* list of destructors found */
+#ifdef COLLECT_EXPORT_LIST
static struct head exports; /* list of exported symbols */
+static struct head imports; /* list of imported symbols */
+static struct head undefined; /* list of undefined symbols */
+#endif
+static struct head frame_tables; /* list of frame unwind info tables */
struct obstack temporary_obstack;
struct obstack permanent_obstack;
@@ -274,17 +237,20 @@ char * temporary_firstobj;
/* Defined in the automatically-generated underscore.c. */
extern int prepends_underscore;
-extern char *getenv ();
extern char *mktemp ();
extern FILE *fdopen ();
+#ifndef GET_ENVIRONMENT
+#define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ENV_VALUE = getenv (ENV_NAME)
+#endif
+
/* Structure to hold all the directories in which to search for files to
execute. */
struct prefix_list
{
- char *prefix; /* String to prepend to the path. */
- struct prefix_list *next; /* Next in linked list. */
+ char *prefix; /* String to prepend to the path. */
+ struct prefix_list *next; /* Next in linked list. */
};
struct path_prefix
@@ -294,13 +260,19 @@ struct path_prefix
char *name; /* Name of this list (used in config stuff) */
};
-void collect_exit PROTO((int));
-void collect_execute PROTO((char *, char **, char *));
-void dump_file PROTO((char *));
+#ifdef COLLECT_EXPORT_LIST
+/* Lists to keep libraries to be scanned for global constructors/destructors. */
+static struct head libs; /* list of libraries */
+static struct path_prefix cmdline_lib_dirs; /* directories specified with -L */
+static struct path_prefix libpath_lib_dirs; /* directories in LIBPATH */
+static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs,
+ &libpath_lib_dirs, NULL};
+static char *libexts[3] = {"a", "so", NULL}; /* possible library extentions */
+#endif
+
+static char *my_strerror PROTO((int));
static void handler PROTO((int));
static int is_ctor_dtor PROTO((char *));
-static void choose_temp_base PROTO((void));
-static int is_in_prefix_list PROTO((struct path_prefix *, char *, int));
static char *find_a_file PROTO((struct path_prefix *, char *));
static void add_prefix PROTO((struct path_prefix *, char *));
static void prefix_from_env PROTO((char *, struct path_prefix *));
@@ -310,18 +282,30 @@ static void fork_execute PROTO((char *, char **));
static void maybe_unlink PROTO((char *));
static void add_to_list PROTO((struct head *, char *));
static void write_list PROTO((FILE *, char *, struct id *));
+#ifdef COLLECT_EXPORT_LIST
+static void dump_list PROTO((FILE *, char *, struct id *));
+#endif
+#if 0
+static void dump_prefix_list PROTO((FILE *, char *, struct prefix_list *));
+#endif
static void write_list_with_asm PROTO((FILE *, char *, struct id *));
static void write_c_file PROTO((FILE *, char *));
-static void write_export_file PROTO((FILE *));
static void scan_prog_file PROTO((char *, enum pass));
+#ifdef SCAN_LIBRARIES
static void scan_libraries PROTO((char *));
+#endif
+#ifdef COLLECT_EXPORT_LIST
+static int is_in_list PROTO((char *, struct id *));
+static void write_export_file PROTO((FILE *));
+static void write_import_file PROTO((FILE *));
+static char *resolve_lib_name PROTO((char *));
+static int use_import_list PROTO((char *));
+static int ignore_library PROTO((char *));
+#endif
char *xcalloc ();
char *xmalloc ();
-extern char *index ();
-extern char *rindex ();
-extern void free ();
#ifdef NO_DUP2
int
@@ -345,7 +329,7 @@ dup2 (oldfd, newfd)
}
#endif
-char *
+static char *
my_strerror (e)
int e;
{
@@ -379,9 +363,14 @@ collect_exit (status)
if (o_file != 0 && o_file[0])
maybe_unlink (o_file);
+#ifdef COLLECT_EXPORT_LIST
if (export_file != 0 && export_file[0])
maybe_unlink (export_file);
+ if (import_file != 0 && import_file[0])
+ maybe_unlink (import_file);
+#endif
+
if (ldout != 0 && ldout[0])
{
dump_file (ldout);
@@ -395,7 +384,7 @@ collect_exit (status)
}
-/* Die when sys call fails. */
+/* Die when sys call fails. */
void
fatal_perror (string, arg1, arg2, arg3)
@@ -406,10 +395,10 @@ fatal_perror (string, arg1, arg2, arg3)
fprintf (stderr, "collect2: ");
fprintf (stderr, string, arg1, arg2, arg3);
fprintf (stderr, ": %s\n", my_strerror (e));
- collect_exit (1);
+ collect_exit (FATAL_EXIT_CODE);
}
-/* Just die. */
+/* Just die. */
void
fatal (string, arg1, arg2, arg3)
@@ -418,7 +407,7 @@ fatal (string, arg1, arg2, arg3)
fprintf (stderr, "collect2: ");
fprintf (stderr, string, arg1, arg2, arg3);
fprintf (stderr, "\n");
- collect_exit (1);
+ collect_exit (FATAL_EXIT_CODE);
}
/* Write error message. */
@@ -455,6 +444,14 @@ handler (signo)
if (ldout != 0 && ldout[0])
maybe_unlink (ldout);
+#ifdef COLLECT_EXPORT_LIST
+ if (export_file != 0 && export_file[0])
+ maybe_unlink (export_file);
+
+ if (import_file != 0 && import_file[0])
+ maybe_unlink (import_file);
+#endif
+
signal (signo, SIG_DFL);
kill (getpid (), signo);
}
@@ -469,7 +466,7 @@ xcalloc (size1, size2)
return ptr;
fatal ("out of memory");
- return (char *)0;
+ return (char *) 0;
}
char *
@@ -481,7 +478,7 @@ xmalloc (size)
return ptr;
fatal ("out of memory");
- return (char *)0;
+ return (char *) 0;
}
char *
@@ -514,6 +511,39 @@ savestring (input, size)
output[size] = 0;
return output;
}
+
+/* Parse a reasonable subset of shell quoting syntax. */
+
+static char *
+extract_string (pp)
+ char **pp;
+{
+ char *p = *pp;
+ int backquote = 0;
+ int inside = 0;
+
+ for (;;)
+ {
+ char c = *p;
+ if (c == '\0')
+ break;
+ ++p;
+ if (backquote)
+ obstack_1grow (&temporary_obstack, c);
+ else if (! inside && c == ' ')
+ break;
+ else if (! inside && c == '\\')
+ backquote = 1;
+ else if (c == '\'')
+ inside = !inside;
+ else
+ obstack_1grow (&temporary_obstack, c);
+ }
+
+ obstack_1grow (&temporary_obstack, '\0');
+ *pp = p;
+ return obstack_finish (&temporary_obstack);
+}
void
dump_file (name)
@@ -528,7 +558,7 @@ dump_file (name)
{
int c;
while (c = getc (stream),
- c != EOF && (isalnum (c) || c == '_' || c == '$' || c == '.'))
+ c != EOF && (ISALNUM (c) || c == '_' || c == '$' || c == '.'))
obstack_1grow (&temporary_obstack, c);
if (obstack_object_size (&temporary_obstack) > 0)
{
@@ -570,6 +600,7 @@ dump_file (name)
break;
putc (c, stderr);
}
+ fclose (stream);
}
/* Decide whether the given symbol is:
@@ -590,17 +621,20 @@ is_ctor_dtor (s)
#ifdef NO_DOT_IN_LABEL
{ "GLOBAL__I_", sizeof ("GLOBAL__I_")-1, 1, 0 },
{ "GLOBAL__D_", sizeof ("GLOBAL__D_")-1, 2, 0 },
+ { "GLOBAL__F_", sizeof ("GLOBAL__F_")-1, 5, 0 },
#else
{ "GLOBAL_.I.", sizeof ("GLOBAL_.I.")-1, 1, 0 },
{ "GLOBAL_.D.", sizeof ("GLOBAL_.D.")-1, 2, 0 },
+ { "GLOBAL_.F.", sizeof ("GLOBAL_.F.")-1, 5, 0 },
#endif
#else
{ "GLOBAL_$I$", sizeof ("GLOBAL_$I$")-1, 1, 0 },
{ "GLOBAL_$D$", sizeof ("GLOBAL_$D$")-1, 2, 0 },
+ { "GLOBAL_$F$", sizeof ("GLOBAL_$F$")-1, 5, 0 },
#endif
{ "GLOBAL__FI_", sizeof ("GLOBAL__FI_")-1, 3, 0 },
{ "GLOBAL__FD_", sizeof ("GLOBAL__FD_")-1, 4, 0 },
-#ifdef CFRONT_LOSSAGE /* Don't collect cfront initialization functions.
+#ifdef CFRONT_LOSSAGE /* Do not collect cfront initialization functions.
cfront has its own linker procedure to collect them;
if collect2 gets them too, they get collected twice
when the cfront procedure is run and the compiler used
@@ -628,42 +662,6 @@ is_ctor_dtor (s)
}
return 0;
}
-
-
-/* Compute a string to use as the base of all temporary file names.
- It is substituted for %g. */
-
-static void
-choose_temp_base ()
-{
- char *base = getenv ("TMPDIR");
- int len;
-
- if (base == (char *)0)
- {
-#ifdef P_tmpdir
- if (access (P_tmpdir, R_OK | W_OK) == 0)
- base = P_tmpdir;
-#endif
- if (base == (char *)0)
- {
- if (access ("/usr/tmp", R_OK | W_OK) == 0)
- base = "/usr/tmp/";
- else
- base = "/tmp/";
- }
- }
-
- len = strlen (base);
- temp_filename = xmalloc (len + sizeof("/ccXXXXXX") + 1);
- strcpy (temp_filename, base);
- if (len > 0 && temp_filename[len-1] != '/')
- temp_filename[len++] = '/';
- strcpy (temp_filename + len, "ccXXXXXX");
-
- mktemp (temp_filename);
- temp_filename_length = strlen (temp_filename);
-}
/* Routine to add variables to the environment. */
@@ -730,52 +728,10 @@ static struct path_prefix cpath, path;
static char *target_machine = TARGET_MACHINE;
#endif
-/* Names under which we were executed. Never return one of those files in our
- searches. */
-
-static struct path_prefix our_file_names;
-
-/* Determine if STRING is in PPREFIX.
-
- This utility is currently only used to look up file names. Prefix lists
- record directory names. This matters to us because the latter has a
- trailing slash, so I've added a flag to handle both. */
-
-static int
-is_in_prefix_list (pprefix, string, filep)
- struct path_prefix *pprefix;
- char *string;
- int filep;
-{
- struct prefix_list *pl;
-
- if (filep)
- {
- int len = strlen (string);
-
- for (pl = pprefix->plist; pl; pl = pl->next)
- {
- if (strncmp (pl->prefix, string, len) == 0
- && strcmp (pl->prefix + len, "/") == 0)
- return 1;
- }
- }
- else
- {
- for (pl = pprefix->plist; pl; pl = pl->next)
- {
- if (strcmp (pl->prefix, string) == 0)
- return 1;
- }
- }
-
- return 0;
-}
-
/* Search for NAME using prefix list PPREFIX. We only look for executable
files.
- Return 0 if not found, otherwise return its name, allocated with malloc. */
+ Return 0 if not found, otherwise return its name, allocated with malloc. */
static char *
find_a_file (pprefix, name)
@@ -786,6 +742,9 @@ find_a_file (pprefix, name)
struct prefix_list *pl;
int len = pprefix->max_len + strlen (name) + 1;
+ if (debug)
+ fprintf (stderr, "Looking for '%s'\n", name);
+
#ifdef EXECUTABLE_SUFFIX
len += strlen (EXECUTABLE_SUFFIX);
#endif
@@ -794,35 +753,48 @@ find_a_file (pprefix, name)
/* Determine the filename to execute (special case for absolute paths). */
- if (*name == '/')
+ if (*name == '/'
+#ifdef DIR_SEPARATOR
+ || (DIR_SEPARATOR == '\\' && name[1] == ':'
+ && (name[2] == DIR_SEPARATOR || name[2] == '/'))
+#endif
+ )
{
if (access (name, X_OK) == 0)
{
strcpy (temp, name);
+
+ if (debug)
+ fprintf (stderr, " - found: absolute path\n");
+
return temp;
}
+
+ if (debug)
+ fprintf (stderr, " - failed to locate using absolute path\n");
}
else
for (pl = pprefix->plist; pl; pl = pl->next)
{
strcpy (temp, pl->prefix);
strcat (temp, name);
- if (! is_in_prefix_list (&our_file_names, temp, 1)
- /* This is a kludge, but there seems no way around it. */
- && strcmp (temp, "./ld") != 0
- && access (temp, X_OK) == 0)
+
+ if (access (temp, X_OK) == 0)
return temp;
#ifdef EXECUTABLE_SUFFIX
/* Some systems have a suffix for executable files.
So try appending that. */
strcat (temp, EXECUTABLE_SUFFIX);
- if (! is_in_prefix_list (&our_file_names, temp, 1)
- && access (temp, X_OK) == 0)
+
+ if (access (temp, X_OK) == 0)
return temp;
#endif
}
+ if (debug && pprefix->plist == NULL)
+ fprintf (stderr, " - failed: no entries in prefix list\n");
+
free (temp);
return 0;
}
@@ -870,7 +842,8 @@ prefix_from_env (env, pprefix)
char *env;
struct path_prefix *pprefix;
{
- char *p = getenv (env);
+ char *p;
+ GET_ENVIRONMENT (p, env);
if (p)
prefix_from_string (p, pprefix);
@@ -884,6 +857,9 @@ prefix_from_string (p, pprefix)
char *startp, *endp;
char *nstore = (char *) xmalloc (strlen (p) + 3);
+ if (debug)
+ fprintf (stderr, "Convert string '%s' into prefixes, separator = '%c'\n", p, PATH_SEPARATOR);
+
startp = endp = p;
while (1)
{
@@ -902,6 +878,9 @@ prefix_from_string (p, pprefix)
else
nstore[endp-startp] = 0;
+ if (debug)
+ fprintf (stderr, " - add prefix: %s\n", nstore);
+
add_prefix (pprefix, nstore);
if (*endp == 0)
break;
@@ -912,7 +891,7 @@ prefix_from_string (p, pprefix)
}
}
-/* Main program. */
+/* Main program. */
int
main (argc, argv)
@@ -922,7 +901,6 @@ main (argc, argv)
char *ld_suffix = "ld";
char *full_ld_suffix = ld_suffix;
char *real_ld_suffix = "real-ld";
- char *full_real_ld_suffix = real_ld_suffix;
char *collect_ld_suffix = "collect-ld";
char *nm_suffix = "nm";
char *full_nm_suffix = nm_suffix;
@@ -937,10 +915,12 @@ main (argc, argv)
char *gstrip_suffix = "gstrip";
char *full_gstrip_suffix = gstrip_suffix;
char *arg;
- FILE *outf, *exportf;
+ FILE *outf;
+#ifdef COLLECT_EXPORT_LIST
+ FILE *exportf;
+ FILE *importf;
+#endif
char *ld_file_name;
- char *collect_name;
- char *collect_names;
char *p;
char **c_argv;
char **c_ptr;
@@ -951,75 +931,44 @@ main (argc, argv)
char **object_lst = (char **) xcalloc (sizeof (char *), argc);
char **object = object_lst;
int first_file;
- int num_c_args = argc+7;
+ int num_c_args = argc+9;
#ifdef DEBUG
debug = 1;
- vflag = 1;
#endif
+ /* Parse command line early for instances of -debug. This allows
+ the debug flag to be set before functions like find_a_file()
+ are called. */
+ {
+ int i;
+
+ for (i = 1; argv[i] != NULL; i ++)
+ if (! strcmp (argv[i], "-debug"))
+ debug = 1;
+ vflag = debug;
+ }
+
+#ifndef DEFAULT_A_OUT_NAME
output_file = "a.out";
+#else
+ output_file = DEFAULT_A_OUT_NAME;
+#endif
obstack_begin (&temporary_obstack, 0);
obstack_begin (&permanent_obstack, 0);
temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
- current_demangling_style = gnu_demangling;
-
- /* We must check that we do not call ourselves in an infinite
- recursion loop. We append the name used for us to the COLLECT_NAMES
- environment variable.
-
- In practice, collect will rarely invoke itself. This can happen now
- that we are no longer called gld. A perfect example is when running
- gcc in a build directory that has been installed. When looking for
- ld's, we'll find our installed version and believe that's the real ld. */
-
- /* We must also append COLLECT_NAME to COLLECT_NAMES to watch for the
- previous version of collect (the one that used COLLECT_NAME and only
- handled two levels of recursion). If we don't we may mutually recurse
- forever. This can happen (I think) when bootstrapping the old version
- and a new one is installed (rare, but we should handle it).
- ??? Hopefully references to COLLECT_NAME can be removed at some point. */
-
- collect_name = (char *) getenv ("COLLECT_NAME");
- collect_names = (char *) getenv ("COLLECT_NAMES");
-
- p = (char *) xmalloc (strlen ("COLLECT_NAMES=")
- + (collect_name ? strlen (collect_name) + 1 : 0)
- + (collect_names ? strlen (collect_names) + 1 : 0)
- + strlen (argv[0]) + 1);
- strcpy (p, "COLLECT_NAMES=");
- if (collect_name != 0)
- sprintf (p + strlen (p), "%s%c", collect_name, PATH_SEPARATOR);
- if (collect_names != 0)
- sprintf (p + strlen (p), "%s%c", collect_names, PATH_SEPARATOR);
- strcat (p, argv[0]);
- putenv (p);
-
- prefix_from_env ("COLLECT_NAMES", &our_file_names);
-
- /* Set environment variable COLLECT_NAME to our name so the previous version
- of collect won't find us. If it does we'll mutually recurse forever.
- This can happen when bootstrapping the new version and an old version is
- installed.
- ??? Hopefully this bit of code can be removed at some point. */
-
- p = xmalloc (strlen ("COLLECT_NAME=") + strlen (argv[0]) + 1);
- sprintf (p, "COLLECT_NAME=%s", argv[0]);
- putenv (p);
-
- p = (char *) getenv ("COLLECT_GCC_OPTIONS");
- if (p)
- while (*p)
- {
- char *q = p;
- while (*q && *q != ' ') q++;
- if (*p == '-' && p[1] == 'm')
- num_c_args++;
- if (*q) q++;
- p = q;
- }
+ current_demangling_style = gnu_demangling;
+ p = getenv ("COLLECT_GCC_OPTIONS");
+ while (p && *p)
+ {
+ char *q = extract_string (&p);
+ if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
+ num_c_args++;
+ }
+ obstack_free (&temporary_obstack, temporary_firstobj);
+ ++num_c_args;
c_ptr = c_argv = (char **) xcalloc (sizeof (char *), num_c_args);
@@ -1054,7 +1003,7 @@ main (argc, argv)
#ifdef CROSS_COMPILE
/* If we look for a program in the compiler directories, we just use
the short name, since these directories are already system-specific.
- But it we look for a took in the system directories, we need to
+ But it we look for a program in the system directories, we need to
qualify the program name with the target machine. */
full_ld_suffix
@@ -1063,12 +1012,6 @@ main (argc, argv)
strcat (full_ld_suffix, "-");
strcat (full_ld_suffix, ld_suffix);
- full_real_ld_suffix
- = xcalloc (strlen (real_ld_suffix) + strlen (target_machine) + 2, 1);
- strcpy (full_real_ld_suffix, target_machine);
- strcat (full_real_ld_suffix, "-");
- strcat (full_real_ld_suffix, real_ld_suffix);
-
#if 0
full_gld_suffix
= xcalloc (strlen (gld_suffix) + strlen (target_machine) + 2, 1);
@@ -1131,18 +1074,6 @@ main (argc, argv)
if (ld_file_name == 0)
ld_file_name = find_a_file (&path, full_ld_suffix);
- /* If we've invoked ourselves, try again with LD_FILE_NAME. */
-
- if (collect_names != 0)
- {
- if (ld_file_name != 0)
- {
- argv[0] = ld_file_name;
- execvp (argv[0], argv);
- }
- fatal ("cannot find `ld'");
- }
-
#ifdef REAL_NM_FILE_NAME
nm_file_name = find_a_file (&path, REAL_NM_FILE_NAME);
if (nm_file_name == 0)
@@ -1198,21 +1129,47 @@ main (argc, argv)
*ld1++ = *ld2++ = ld_file_name;
- /* Make temp file names. */
- choose_temp_base ();
- c_file = xcalloc (temp_filename_length + sizeof (".c"), 1);
- o_file = xcalloc (temp_filename_length + sizeof (".o"), 1);
- export_file = xmalloc (temp_filename_length + sizeof (".x"));
- ldout = xmalloc (temp_filename_length + sizeof (".ld"));
- sprintf (ldout, "%s.ld", temp_filename);
- sprintf (c_file, "%s.c", temp_filename);
- sprintf (o_file, "%s.o", temp_filename);
- sprintf (export_file, "%s.x", temp_filename);
+ /* Make temp file names. */
+ c_file = make_temp_file (".c");
+ o_file = make_temp_file (".o");
+#ifdef COLLECT_EXPORT_LIST
+ export_file = make_temp_file (".x");
+ import_file = make_temp_file (".p");
+#endif
+ ldout = make_temp_file (".ld");
*c_ptr++ = c_file_name;
+ *c_ptr++ = "-x";
+ *c_ptr++ = "c";
*c_ptr++ = "-c";
*c_ptr++ = "-o";
*c_ptr++ = o_file;
+#ifdef COLLECT_EXPORT_LIST
+ /* Generate a list of directories from LIBPATH. */
+ prefix_from_env ("LIBPATH", &libpath_lib_dirs);
+ /* Add to this list also two standard directories where
+ AIX loader always searches for libraries. */
+ add_prefix (&libpath_lib_dirs, "/lib");
+ add_prefix (&libpath_lib_dirs, "/usr/lib");
+#endif
+
+ /* Get any options that the upper GCC wants to pass to the sub-GCC.
+
+ AIX support needs to know if -shared has been specified before
+ parsing commandline arguments. */
+
+ p = getenv ("COLLECT_GCC_OPTIONS");
+ while (p && *p)
+ {
+ char *q = extract_string (&p);
+ if (*q == '-' && (q[1] == 'm' || q[1] == 'f'))
+ *c_ptr++ = obstack_copy0 (&permanent_obstack, q, strlen (q));
+ if (strncmp (q, "-shared", sizeof ("-shared") - 1) == 0)
+ shared_obj = 1;
+ }
+ obstack_free (&temporary_obstack, temporary_firstobj);
+ *c_ptr++ = "-fno-exceptions";
+
/* !!! When GCC calls collect2,
it does not know whether it is calling collect2 or ld.
So collect2 cannot meaningfully understand any options
@@ -1220,11 +1177,11 @@ main (argc, argv)
If you propose to make GCC pass some other option,
just imagine what will happen if ld is really ld!!! */
- /* Parse arguments. Remember output file spec, pass the rest to ld. */
+ /* Parse arguments. Remember output file spec, pass the rest to ld. */
/* After the first file, put in the c++ rt0. */
first_file = 1;
- while ((arg = *++argv) != (char *)0)
+ while ((arg = *++argv) != (char *) 0)
{
*ld1++ = *ld2++ = arg;
@@ -1232,11 +1189,21 @@ main (argc, argv)
{
switch (arg[1])
{
+#ifdef COLLECT_EXPORT_LIST
+ /* We want to disable automatic exports on AIX when user
+ explicitly puts an export list in command line */
+ case 'b':
+ if (arg[2] == 'E' || strncmp (&arg[2], "export", 6) == 0)
+ export_flag = 1;
+ if (arg[2] == '6' && arg[3] == '4')
+ aix64_flag = 1;
+ break;
+#endif
+
case 'd':
if (!strcmp (arg, "-debug"))
{
- debug = 1;
- vflag = 1;
+ /* Already parsed. */
ld1--;
ld2--;
}
@@ -1251,7 +1218,31 @@ main (argc, argv)
*ld2++ = o_file;
*ld2++ = arg;
}
+#ifdef COLLECT_EXPORT_LIST
+ {
+ /* Resolving full library name. */
+ char *s = resolve_lib_name (arg+2);
+
+ /* If we will use an import list for this library,
+ we should exclude it from ld args. */
+ if (use_import_list (s))
+ {
+ ld1--;
+ ld2--;
+ }
+
+ /* Saving a full library name. */
+ add_to_list (&libs, s);
+ }
+#endif
+ break;
+
+#ifdef COLLECT_EXPORT_LIST
+ /* Saving directories where to search for libraries. */
+ case 'L':
+ add_prefix (&cmdline_lib_dirs, arg+2);
break;
+#endif
case 'o':
if (arg[2] == '\0')
@@ -1269,7 +1260,7 @@ main (argc, argv)
if (arg[2] == '\0' && do_collecting)
{
/* We must strip after the nm run, otherwise C++ linking
- won't work. Thus we strip in the second ld run, or
+ will not work. Thus we strip in the second ld run, or
else with strip if there is no second ld run. */
strip_flag = 1;
ld1--;
@@ -1282,8 +1273,9 @@ main (argc, argv)
break;
}
}
- else if ((p = rindex (arg, '.')) != (char *)0
- && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0))
+ else if ((p = rindex (arg, '.')) != (char *) 0
+ && (strcmp (p, ".o") == 0 || strcmp (p, ".a") == 0
+ || strcmp (p, ".so") == 0))
{
if (first_file)
{
@@ -1300,47 +1292,71 @@ main (argc, argv)
}
if (p[1] == 'o')
*object++ = arg;
+#ifdef COLLECT_EXPORT_LIST
+ /* libraries can be specified directly, i.e. without -l flag. */
+ else
+ {
+ /* If we will use an import list for this library,
+ we should exclude it from ld args. */
+ if (use_import_list (arg))
+ {
+ ld1--;
+ ld2--;
+ }
+
+ /* Saving a full library name. */
+ add_to_list (&libs, arg);
+ }
+#endif
}
}
- /* Get any options that the upper GCC wants to pass to the sub-GCC. */
- p = (char *) getenv ("COLLECT_GCC_OPTIONS");
- if (p)
- while (*p)
- {
- char *q = p;
- while (*q && *q != ' ') q++;
- if (*p == '-' && (p[1] == 'm' || p[1] == 'f'))
- *c_ptr++ = savestring (p, q - p);
- if (strncmp (p, "-shared", sizeof ("shared") - 1) == 0)
- shared_obj = 1;
-
- if (*q) q++;
- p = q;
- }
-
#ifdef COLLECT_EXPORT_LIST
+ /* This is added only for debugging purposes. */
+ if (debug)
+ {
+ fprintf (stderr, "List of libraries:\n");
+ dump_list (stderr, "\t", libs.first);
+ }
+
/* The AIX linker will discard static constructors in object files if
nothing else in the file is referenced, so look at them first. */
- while (object_lst < object)
- scan_prog_file (*object_lst++, PASS_OBJ);
-
{
- char *buf = alloca (strlen (export_file) + 5);
- sprintf (buf, "-bE:%s", export_file);
- *ld1++ = buf;
- *ld2++ = buf;
+ char **export_object_lst = object_lst;
+ while (export_object_lst < object)
+ scan_prog_file (*export_object_lst++, PASS_OBJ);
+ }
+ {
+ struct id *list = libs.first;
+ for (; list; list = list->next)
+ scan_prog_file (list->name, PASS_FIRST);
+ }
+ {
+ char *buf1 = alloca (strlen (export_file) + 5);
+ char *buf2 = alloca (strlen (import_file) + 5);
+ sprintf (buf1, "-bE:%s", export_file);
+ sprintf (buf2, "-bI:%s", import_file);
+ *ld1++ = buf1;
+ *ld2++ = buf1;
+ *ld1++ = buf2;
+ *ld2++ = buf2;
exportf = fopen (export_file, "w");
- if (exportf == (FILE *)0)
+ if (exportf == (FILE *) 0)
fatal_perror ("%s", export_file);
write_export_file (exportf);
if (fclose (exportf))
fatal_perror ("closing %s", export_file);
+ importf = fopen (import_file, "w");
+ if (importf == (FILE *) 0)
+ fatal_perror ("%s", import_file);
+ write_import_file (importf);
+ if (fclose (importf))
+ fatal_perror ("closing %s", import_file);
}
#endif
*c_ptr++ = c_file;
- *object = *c_ptr = *ld1 = (char *)0;
+ *object = *c_ptr = *ld1 = (char *) 0;
if (vflag)
{
@@ -1371,10 +1387,6 @@ main (argc, argv)
fprintf (stderr, "o_file = %s\n",
(o_file ? o_file : "not found"));
- ptr = getenv ("COLLECT_NAMES");
- if (ptr)
- fprintf (stderr, "COLLECT_NAMES = %s\n", ptr);
-
ptr = getenv ("COLLECT_GCC_OPTIONS");
if (ptr)
fprintf (stderr, "COLLECT_GCC_OPTIONS = %s\n", ptr);
@@ -1394,23 +1406,42 @@ main (argc, argv)
fprintf (stderr, "\n");
}
- /* Load the program, searching all libraries. */
+ /* Load the program, searching all libraries and attempting to provide
+ undefined symbols from repository information. */
- collect_execute ("ld", ld1_argv, ldout);
- do_wait ("ld");
- dump_file (ldout);
- unlink (ldout);
+ /* On AIX we do this later. */
+#ifndef COLLECT_EXPORT_LIST
+ do_tlink (ld1_argv, object_lst);
+#endif
- /* If -r or they'll be run via some other method, don't build the
- constructor or destructor list, just return now. */
- if (rflag || ! do_collecting)
- return 0;
+ /* If -r or they will be run via some other method, do not build the
+ constructor or destructor list, just return now. */
+ if (rflag
+#ifndef COLLECT_EXPORT_LIST
+ || ! do_collecting
+#endif
+ )
+ {
+#ifdef COLLECT_EXPORT_LIST
+ /* But make sure we delete the export file we may have created. */
+ if (export_file != 0 && export_file[0])
+ maybe_unlink (export_file);
+ if (import_file != 0 && import_file[0])
+ maybe_unlink (import_file);
+#endif
+ maybe_unlink (c_file);
+ maybe_unlink (o_file);
+ return 0;
+ }
/* Examine the namelist with nm and search it for static constructors
and destructors to call.
- Write the constructor and destructor tables to a .s file and reload. */
+ Write the constructor and destructor tables to a .s file and reload. */
+ /* On AIX we already done scanning for global constructors/destructors. */
+#ifndef COLLECT_EXPORT_LIST
scan_prog_file (output_file, PASS_FIRST);
+#endif
#ifdef SCAN_LIBRARIES
scan_libraries (output_file);
@@ -1423,14 +1454,19 @@ main (argc, argv)
}
if (constructors.number == 0 && destructors.number == 0
-#ifdef LDD_SUFFIX
+ && frame_tables.number == 0
+#if defined (SCAN_LIBRARIES) || defined (COLLECT_EXPORT_LIST)
/* If we will be running these functions ourselves, we want to emit
- stubs into the shared library so that we don't have to relink
+ stubs into the shared library so that we do not have to relink
dependent programs when we add static objects. */
&& ! shared_obj
#endif
)
{
+#ifdef COLLECT_EXPORT_LIST
+ /* Doing tlink without additional code generation */
+ do_tlink (ld1_argv, object_lst);
+#endif
/* Strip now if it was requested on the command line. */
if (strip_flag)
{
@@ -1443,13 +1479,16 @@ main (argc, argv)
#ifdef COLLECT_EXPORT_LIST
maybe_unlink (export_file);
+ maybe_unlink (import_file);
#endif
+ maybe_unlink (c_file);
+ maybe_unlink (o_file);
return 0;
}
maybe_unlink(output_file);
outf = fopen (c_file, "w");
- if (outf == (FILE *)0)
+ if (outf == (FILE *) 0)
fatal_perror ("%s", c_file);
write_c_file (outf, c_file);
@@ -1464,7 +1503,7 @@ main (argc, argv)
*ld2++ = LD_FINI_SWITCH;
*ld2++ = fininame;
#endif
- *ld2 = (char*)0;
+ *ld2 = (char*) 0;
#ifdef COLLECT_EXPORT_LIST
if (shared_obj)
@@ -1474,7 +1513,7 @@ main (argc, argv)
add_to_list (&exports, "_GLOBAL__DI");
add_to_list (&exports, "_GLOBAL__DD");
exportf = fopen (export_file, "w");
- if (exportf == (FILE *)0)
+ if (exportf == (FILE *) 0)
fatal_perror ("%s", export_file);
write_export_file (exportf);
if (fclose (exportf))
@@ -1496,23 +1535,34 @@ main (argc, argv)
}
/* Assemble the constructor and destructor tables.
- Link the tables in with the rest of the program. */
+ Link the tables in with the rest of the program. */
fork_execute ("gcc", c_argv);
+#ifdef COLLECT_EXPORT_LIST
+ /* On AIX we must call tlink because of possible templates resolution */
+ do_tlink (ld2_argv, object_lst);
+#else
+ /* Otherwise, simply call ld because tlink is already done */
fork_execute ("ld", ld2_argv);
/* Let scan_prog_file do any final mods (OSF/rose needs this for
constructors/destructors in shared libraries. */
scan_prog_file (output_file, PASS_SECOND);
+#endif
maybe_unlink (c_file);
maybe_unlink (o_file);
+
+#ifdef COLLECT_EXPORT_LIST
maybe_unlink (export_file);
+ maybe_unlink (import_file);
+#endif
+
return 0;
}
-/* Wait for a process to finish, and exit if a non-zero status is found. */
+/* Wait for a process to finish, and exit if a non-zero status is found. */
int
collect_wait (prog)
@@ -1539,7 +1589,7 @@ collect_wait (prog)
(status & 0200) ? ", core dumped" : "");
#endif
- collect_exit (127);
+ collect_exit (FATAL_EXIT_CODE);
}
if (WIFEXITED (status))
@@ -1581,7 +1631,7 @@ collect_execute (prog, argv, redir)
else
fprintf (stderr, "[cannot find %s]", prog);
- for (p_argv = &argv[1]; (str = *p_argv) != (char *)0; p_argv++)
+ for (p_argv = &argv[1]; (str = *p_argv) != (char *) 0; p_argv++)
fprintf (stderr, " %s", str);
fprintf (stderr, "\n");
@@ -1590,12 +1640,13 @@ collect_execute (prog, argv, redir)
fflush (stdout);
fflush (stderr);
- /* If we can't find a program we need, complain error. Do this here
- since we might not end up needing something that we couldn't find. */
+ /* If we cannot find a program we need, complain error. Do this here
+ since we might not end up needing something that we could not find. */
if (argv[0] == 0)
fatal ("cannot find `%s'", prog);
+#ifndef __CYGWIN32__
pid = vfork ();
if (pid == -1)
{
@@ -1612,14 +1663,19 @@ collect_execute (prog, argv, redir)
{
unlink (redir);
if (freopen (redir, "a", stdout) == NULL)
- fatal_perror ("redirecting stdout");
+ fatal_perror ("redirecting stdout: %s", redir);
if (freopen (redir, "a", stderr) == NULL)
- fatal_perror ("redirecting stderr");
+ fatal_perror ("redirecting stderr: %s", redir);
}
execvp (argv[0], argv);
fatal_perror ("executing %s", prog);
}
+#else
+ pid = _spawnvp (_P_NOWAIT, argv[0], argv);
+ if (pid == -1)
+ fatal ("spawnvp failed");
+#endif
}
static void
@@ -1694,6 +1750,53 @@ write_list (stream, prefix, list)
}
}
+#ifdef COLLECT_EXPORT_LIST
+/* This function is really used only on AIX, but may be useful. */
+static int
+is_in_list (prefix, list)
+ char *prefix;
+ struct id *list;
+{
+ while (list)
+ {
+ if (!strcmp (prefix, list->name)) return 1;
+ list = list->next;
+ }
+ return 0;
+}
+#endif
+
+/* Added for debugging purpose. */
+#ifdef COLLECT_EXPORT_LIST
+static void
+dump_list (stream, prefix, list)
+ FILE *stream;
+ char *prefix;
+ struct id *list;
+{
+ while (list)
+ {
+ fprintf (stream, "%s%s,\n", prefix, list->name);
+ list = list->next;
+ }
+}
+#endif
+
+#if 0
+static void
+dump_prefix_list (stream, prefix, list)
+ FILE *stream;
+ char *prefix;
+ struct prefix_list *list;
+{
+ while (list)
+ {
+ fprintf (stream, "%s%s,\n", prefix, list->prefix);
+ list = list->next;
+ }
+}
+#endif
+
static void
write_list_with_asm (stream, prefix, list)
FILE *stream;
@@ -1717,6 +1820,7 @@ write_c_file_stat (stream, name)
char *name;
{
char *prefix, *p, *q;
+ int frames = (frame_tables.number > 0);
/* Figure out name of output_file, stripping off .so version. */
p = rindex (output_file, '/');
@@ -1749,7 +1853,7 @@ write_c_file_stat (stream, name)
strncpy (prefix, p, q - p);
prefix[q - p] = 0;
for (q = prefix; *q; q++)
- if (!isalnum (*q))
+ if (!ISALNUM (*q))
*q = '_';
if (debug)
fprintf (stderr, "\nwrite_c_file - output name is %s, prefix is %s\n",
@@ -1770,15 +1874,49 @@ write_c_file_stat (stream, name)
fprintf (stream, "static int count;\n");
fprintf (stream, "typedef void entry_pt();\n");
write_list_with_asm (stream, "extern entry_pt ", constructors.first);
+
+ if (frames)
+ {
+ write_list_with_asm (stream, "extern void *", frame_tables.first);
+
+ fprintf (stream, "\tstatic void *frame_table[] = {\n");
+ write_list (stream, "\t\t&", frame_tables.first);
+ fprintf (stream, "\t0\n};\n");
+
+ /* This must match what's in frame.h. */
+ fprintf (stream, "struct object {\n");
+ fprintf (stream, " void *pc_begin;\n");
+ fprintf (stream, " void *pc_end;\n");
+ fprintf (stream, " void *fde_begin;\n");
+ fprintf (stream, " void *fde_array;\n");
+ fprintf (stream, " __SIZE_TYPE__ count;\n");
+ fprintf (stream, " struct object *next;\n");
+ fprintf (stream, "};\n");
+
+ fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n");
+ fprintf (stream, "extern void *__deregister_frame_info (void *);\n");
+
+ fprintf (stream, "static void reg_frame () {\n");
+ fprintf (stream, "\tstatic struct object ob;\n");
+ fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n");
+ fprintf (stream, "\t}\n");
+
+ fprintf (stream, "static void dereg_frame () {\n");
+ fprintf (stream, "\t__deregister_frame_info (frame_table);\n");
+ fprintf (stream, "\t}\n");
+ }
+
fprintf (stream, "void %s() {\n", initname);
- if (constructors.number > 0)
+ if (constructors.number > 0 || frames)
{
fprintf (stream, "\tstatic entry_pt *ctors[] = {\n");
write_list (stream, "\t\t", constructors.first);
+ if (frames)
+ fprintf (stream, "\treg_frame,\n");
fprintf (stream, "\t};\n");
fprintf (stream, "\tentry_pt **p;\n");
fprintf (stream, "\tif (count++ != 0) return;\n");
- fprintf (stream, "\tp = ctors + %d;\n", constructors.number);
+ fprintf (stream, "\tp = ctors + %d;\n", constructors.number + frames);
fprintf (stream, "\twhile (p > ctors) (*--p)();\n");
}
else
@@ -1786,16 +1924,18 @@ write_c_file_stat (stream, name)
fprintf (stream, "}\n");
write_list_with_asm (stream, "extern entry_pt ", destructors.first);
fprintf (stream, "void %s() {\n", fininame);
- if (destructors.number > 0)
+ if (destructors.number > 0 || frames)
{
fprintf (stream, "\tstatic entry_pt *dtors[] = {\n");
write_list (stream, "\t\t", destructors.first);
+ if (frames)
+ fprintf (stream, "\tdereg_frame,\n");
fprintf (stream, "\t};\n");
fprintf (stream, "\tentry_pt **p;\n");
fprintf (stream, "\tif (--count != 0) return;\n");
fprintf (stream, "\tp = dtors;\n");
fprintf (stream, "\twhile (p < dtors + %d) (*p++)();\n",
- destructors.number);
+ destructors.number + frames);
}
fprintf (stream, "}\n");
@@ -1806,8 +1946,9 @@ write_c_file_stat (stream, name)
}
}
-/* Write the constructor/destructor tables. */
+/* Write the constructor/destructor tables. */
+#ifndef LD_INIT_SWITCH
static void
write_c_file_glob (stream, name)
FILE *stream;
@@ -1815,39 +1956,80 @@ write_c_file_glob (stream, name)
{
/* Write the tables as C code */
+ int frames = (frame_tables.number > 0);
+
fprintf (stream, "typedef void entry_pt();\n\n");
write_list_with_asm (stream, "extern entry_pt ", constructors.first);
-
+
+ if (frames)
+ {
+ write_list_with_asm (stream, "extern void *", frame_tables.first);
+
+ fprintf (stream, "\tstatic void *frame_table[] = {\n");
+ write_list (stream, "\t\t&", frame_tables.first);
+ fprintf (stream, "\t0\n};\n");
+
+ /* This must match what's in frame.h. */
+ fprintf (stream, "struct object {\n");
+ fprintf (stream, " void *pc_begin;\n");
+ fprintf (stream, " void *pc_end;\n");
+ fprintf (stream, " void *fde_begin;\n");
+ fprintf (stream, " void *fde_array;\n");
+ fprintf (stream, " __SIZE_TYPE__ count;\n");
+ fprintf (stream, " struct object *next;\n");
+ fprintf (stream, "};\n");
+
+ fprintf (stream, "extern void __register_frame_info_table (void *, struct object *);\n");
+ fprintf (stream, "extern void *__deregister_frame_info (void *);\n");
+
+ fprintf (stream, "static void reg_frame () {\n");
+ fprintf (stream, "\tstatic struct object ob;\n");
+ fprintf (stream, "\t__register_frame_info_table (frame_table, &ob);\n");
+ fprintf (stream, "\t}\n");
+
+ fprintf (stream, "static void dereg_frame () {\n");
+ fprintf (stream, "\t__deregister_frame_info (frame_table);\n");
+ fprintf (stream, "\t}\n");
+ }
+
fprintf (stream, "\nentry_pt * __CTOR_LIST__[] = {\n");
- fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number);
+ fprintf (stream, "\t(entry_pt *) %d,\n", constructors.number + frames);
write_list (stream, "\t", constructors.first);
+ if (frames)
+ fprintf (stream, "\treg_frame,\n");
fprintf (stream, "\t0\n};\n\n");
write_list_with_asm (stream, "extern entry_pt ", destructors.first);
fprintf (stream, "\nentry_pt * __DTOR_LIST__[] = {\n");
- fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number);
+ fprintf (stream, "\t(entry_pt *) %d,\n", destructors.number + frames);
write_list (stream, "\t", destructors.first);
+ if (frames)
+ fprintf (stream, "\tdereg_frame,\n");
fprintf (stream, "\t0\n};\n\n");
fprintf (stream, "extern entry_pt %s;\n", NAME__MAIN);
fprintf (stream, "entry_pt *__main_reference = %s;\n\n", NAME__MAIN);
}
+#endif /* ! LD_INIT_SWITCH */
static void
write_c_file (stream, name)
FILE *stream;
char *name;
{
+ fprintf (stream, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
#ifndef LD_INIT_SWITCH
if (! shared_obj)
write_c_file_glob (stream, name);
else
#endif
write_c_file_stat (stream, name);
+ fprintf (stream, "#ifdef __cplusplus\n}\n#endif\n");
}
+#ifdef COLLECT_EXPORT_LIST
static void
write_export_file (stream)
FILE *stream;
@@ -1856,6 +2038,17 @@ write_export_file (stream)
for (; list; list = list->next)
fprintf (stream, "%s\n", list->name);
}
+
+static void
+write_import_file (stream)
+ FILE *stream;
+{
+ struct id *list = imports.first;
+ fprintf (stream, "%s\n", "#! .");
+ for (; list; list = list->next)
+ fprintf (stream, "%s\n", list->name);
+}
+#endif
#ifdef OBJECT_FORMAT_NONE
@@ -1885,7 +2078,7 @@ scan_prog_file (prog_name, which_pass)
if (which_pass == PASS_SECOND)
return;
- /* If we don't have an `nm', complain. */
+ /* If we do not have an `nm', complain. */
if (nm_file_name == 0)
fatal ("cannot find `nm'");
@@ -1894,13 +2087,13 @@ scan_prog_file (prog_name, which_pass)
nm_argv[argc++] = NM_FLAGS;
nm_argv[argc++] = prog_name;
- nm_argv[argc++] = (char *)0;
+ nm_argv[argc++] = (char *) 0;
if (pipe (pipe_fd) < 0)
fatal_perror ("pipe");
inf = fdopen (pipe_fd[0], "r");
- if (inf == (FILE *)0)
+ if (inf == (FILE *) 0)
fatal_perror ("fdopen");
/* Trace if needed. */
@@ -1909,7 +2102,7 @@ scan_prog_file (prog_name, which_pass)
char **p_argv;
char *str;
- for (p_argv = &nm_argv[0]; (str = *p_argv) != (char *)0; p_argv++)
+ for (p_argv = &nm_argv[0]; (str = *p_argv) != (char *) 0; p_argv++)
fprintf (stderr, " %s", str);
fprintf (stderr, "\n");
@@ -1958,13 +2151,13 @@ scan_prog_file (prog_name, which_pass)
fprintf (stderr, "\nnm output with constructors/destructors.\n");
/* Read each line of nm output. */
- while (fgets (buf, sizeof buf, inf) != (char *)0)
+ while (fgets (buf, sizeof buf, inf) != (char *) 0)
{
int ch, ch2;
char *name, *end;
/* If it contains a constructor or destructor name, add the name
- to the appropriate list. */
+ to the appropriate list. */
for (p = buf; (ch = *p) != '\0' && ch != '\n' && ch != '_'; p++)
if (ch == ' ' && p[1] == 'U' && p[2] == ' ')
@@ -1975,8 +2168,8 @@ scan_prog_file (prog_name, which_pass)
name = p;
/* Find the end of the symbol name.
- Don't include `|', because Encore nm can tack that on the end. */
- for (end = p; (ch2 = *end) != '\0' && !isspace (ch2) && ch2 != '|';
+ Do not include `|', because Encore nm can tack that on the end. */
+ for (end = p; (ch2 = *end) != '\0' && !ISSPACE (ch2) && ch2 != '|';
end++)
continue;
@@ -2010,6 +2203,10 @@ scan_prog_file (prog_name, which_pass)
#endif
break;
+ case 5:
+ if (which_pass != PASS_LIB)
+ add_to_list (&frame_tables, name);
+
default: /* not a constructor or destructor */
continue;
}
@@ -2043,7 +2240,7 @@ scan_prog_file (prog_name, which_pass)
#include <link.h>
#include <sys/mman.h>
#include <sys/param.h>
-#include <sys/unistd.h>
+#include <unistd.h>
#include <sys/dir.h>
/* pointers to the object file */
@@ -2095,7 +2292,7 @@ libselect (d)
We must verify that the extension is numeric, because Sun saves the
original versions of patched libraries with a .FCS extension. Files with
- invalid extensions must go last in the sort, so that they won't be used. */
+ invalid extensions must go last in the sort, so that they will not be used. */
static int
libcompare (d1, d2)
@@ -2106,7 +2303,7 @@ libcompare (d1, d2)
char *e2 = (*d2)->d_name + i2;
while (*e1 && *e2 && *e1 == '.' && *e2 == '.'
- && e1[1] && isdigit (e1[1]) && e2[1] && isdigit (e2[1]))
+ && e1[1] && ISDIGIT (e1[1]) && e2[1] && ISDIGIT (e2[1]))
{
++e1;
++e2;
@@ -2119,7 +2316,7 @@ libcompare (d1, d2)
if (*e1)
{
/* It has a valid numeric extension, prefer this one. */
- if (*e1 == '.' && e1[1] && isdigit (e1[1]))
+ if (*e1 == '.' && e1[1] && ISDIGIT (e1[1]))
return 1;
/* It has a invalid numeric extension, must prefer the other one. */
else
@@ -2128,7 +2325,7 @@ libcompare (d1, d2)
else if (*e2)
{
/* It has a valid numeric extension, prefer this one. */
- if (*e2 == '.' && e2[1] && isdigit (e2[1]))
+ if (*e2 == '.' && e2[1] && ISDIGIT (e2[1]))
return -1;
/* It has a invalid numeric extension, must prefer the other one. */
else
@@ -2323,7 +2520,7 @@ scan_libraries (prog_name)
char buf[1024];
FILE *inf;
- /* If we don't have an `ldd', complain. */
+ /* If we do not have an `ldd', complain. */
if (ldd_file_name == 0)
{
error ("cannot find `ldd'");
@@ -2401,7 +2598,7 @@ scan_libraries (prog_name)
int ch, ch2;
char *name, *end, *p = buf;
- /* Extract names of libraries and add to list. */
+ /* Extract names of libraries and add to list. */
PARSE_LDD_OUTPUT (p);
if (p == 0)
continue;
@@ -2410,9 +2607,9 @@ scan_libraries (prog_name)
if (strncmp (name, "not found", sizeof ("not found") - 1) == 0)
fatal ("dynamic dependency %s not found", buf);
- /* Find the end of the symbol name. */
+ /* Find the end of the symbol name. */
for (end = p;
- (ch2 = *end) != '\0' && ch2 != '\n' && !isspace (ch2) && ch2 != '|';
+ (ch2 = *end) != '\0' && ch2 != '\n' && !ISSPACE (ch2) && ch2 != '|';
end++)
continue;
*end = '\0';
@@ -2468,11 +2665,16 @@ scan_libraries (prog_name)
# define GCC_SYMENT SYMENT
# define GCC_OK_SYMBOL(X) \
(((X).n_sclass == C_EXT) && \
- (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) || \
- ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT)))
+ ((X).n_scnum > N_UNDEF) && \
+ (((X).n_type & N_TMASK) == (DT_NON << N_BTSHFT) || \
+ ((X).n_type & N_TMASK) == (DT_FCN << N_BTSHFT)))
+# define GCC_UNDEF_SYMBOL(X) \
+ (((X).n_sclass == C_EXT) && ((X).n_scnum == N_UNDEF))
# define GCC_SYMINC(X) ((X).n_numaux+1)
# define GCC_SYMZERO(X) 0
-# define GCC_CHECK_HDR(X) (1)
+# define GCC_CHECK_HDR(X) \
+ ((HEADER (X).f_magic == U802TOCMAGIC && ! aix64_flag) \
+ || (HEADER (X).f_magic == 0757 && aix64_flag))
#endif
extern char *ldgetname ();
@@ -2493,246 +2695,277 @@ scan_prog_file (prog_name, which_pass)
{
LDFILE *ldptr = NULL;
int sym_index, sym_count;
+ int is_shared = 0;
+#ifdef COLLECT_EXPORT_LIST
+ /* Should we generate an import list for given prog_name? */
+ int import_flag = (which_pass == PASS_OBJ ? 0 : use_import_list (prog_name));
+#endif
if (which_pass != PASS_FIRST && which_pass != PASS_OBJ)
return;
- if ((ldptr = ldopen (prog_name, ldptr)) == NULL)
- fatal ("%s: can't open as COFF file", prog_name);
-
- if (!MY_ISCOFF (HEADER (ldptr).f_magic))
- fatal ("%s: not a COFF file", prog_name);
+#ifdef COLLECT_EXPORT_LIST
+ /* We do not need scanning for some standard C libraries. */
+ if (which_pass == PASS_FIRST && ignore_library (prog_name))
+ return;
- if (GCC_CHECK_HDR (ldptr))
+ /* On AIX we have a loop, because there is not much difference
+ between an object and an archive. This trick allows us to
+ eliminate scan_libraries() function. */
+ do
{
- sym_count = GCC_SYMBOLS (ldptr);
- sym_index = GCC_SYMZERO (ldptr);
- while (sym_index < sym_count)
+#endif
+ if ((ldptr = ldopen (prog_name, ldptr)) != NULL)
{
- GCC_SYMENT symbol;
-
- if (ldtbread (ldptr, sym_index, &symbol) <= 0)
- break;
- sym_index += GCC_SYMINC (symbol);
+ if (! MY_ISCOFF (HEADER (ldptr).f_magic))
+ fatal ("%s: not a COFF file", prog_name);
- if (GCC_OK_SYMBOL (symbol))
+ if (GCC_CHECK_HDR (ldptr))
{
- char *name;
+ sym_count = GCC_SYMBOLS (ldptr);
+ sym_index = GCC_SYMZERO (ldptr);
- if ((name = ldgetname (ldptr, &symbol)) == NULL)
- continue; /* should never happen */
+#ifdef COLLECT_EXPORT_LIST
+ /* Is current archive member a shared object? */
+ is_shared = HEADER (ldptr).f_flags & F_SHROBJ;
+#endif
+
+ while (sym_index < sym_count)
+ {
+ GCC_SYMENT symbol;
+
+ if (ldtbread (ldptr, sym_index, &symbol) <= 0)
+ break;
+ sym_index += GCC_SYMINC (symbol);
+
+ if (GCC_OK_SYMBOL (symbol))
+ {
+ char *name;
+
+ if ((name = ldgetname (ldptr, &symbol)) == NULL)
+ continue; /* should never happen */
#ifdef XCOFF_DEBUGGING_INFO
- /* All AIX function names have a duplicate entry beginning
- with a dot. */
- if (*name == '.')
- ++name;
+ /* All AIX function names have a duplicate entry
+ beginning with a dot. */
+ if (*name == '.')
+ ++name;
#endif
- switch (is_ctor_dtor (name))
- {
- case 1:
- add_to_list (&constructors, name);
- if (which_pass == PASS_OBJ)
- add_to_list (&exports, name);
- break;
+ switch (is_ctor_dtor (name))
+ {
+ case 1:
+ if (! is_shared) add_to_list (&constructors, name);
+#ifdef COLLECT_EXPORT_LIST
+ if (which_pass == PASS_OBJ)
+ add_to_list (&exports, name);
+ /* If this symbol was undefined and we are building
+ an import list, we should add a symbol to this
+ list. */
+ else
+ if (import_flag
+ && is_in_list (name, undefined.first))
+ add_to_list (&imports, name);
+#endif
+ break;
+
+ case 2:
+ if (! is_shared) add_to_list (&destructors, name);
+#ifdef COLLECT_EXPORT_LIST
+ if (which_pass == PASS_OBJ)
+ add_to_list (&exports, name);
+ /* If this symbol was undefined and we are building
+ an import list, we should add a symbol to this
+ list. */
+ else
+ if (import_flag
+ && is_in_list (name, undefined.first))
+ add_to_list (&imports, name);
+#endif
+ break;
- case 2:
- add_to_list (&destructors, name);
- if (which_pass == PASS_OBJ)
- add_to_list (&exports, name);
- break;
+#ifdef COLLECT_EXPORT_LIST
+ case 3:
+ if (is_shared)
+ add_to_list (&constructors, name);
+ break;
- default: /* not a constructor or destructor */
- continue;
- }
+ case 4:
+ if (is_shared)
+ add_to_list (&destructors, name);
+ break;
+#endif
+
+ default: /* not a constructor or destructor */
+#ifdef COLLECT_EXPORT_LIST
+ /* If we are building a shared object on AIX we need
+ to explicitly export all global symbols or add
+ them to import list. */
+ if (shared_obj)
+ {
+ if (which_pass == PASS_OBJ && (! export_flag))
+ add_to_list (&exports, name);
+ else if (! is_shared && which_pass == PASS_FIRST
+ && import_flag
+ && is_in_list(name, undefined.first))
+ add_to_list (&imports, name);
+ }
+#endif
+ continue;
+ }
#if !defined(EXTENDED_COFF)
- if (debug)
- fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n",
- symbol.n_scnum, symbol.n_sclass,
- (symbol.n_type ? "0" : ""), symbol.n_type,
- name);
+ if (debug)
+ fprintf (stderr, "\tsec=%d class=%d type=%s%o %s\n",
+ symbol.n_scnum, symbol.n_sclass,
+ (symbol.n_type ? "0" : ""), symbol.n_type,
+ name);
#else
- if (debug)
- fprintf (stderr, "\tiss = %5d, value = %5d, index = %5d, name = %s\n",
- symbol.iss, symbol.value, symbol.index, name);
+ if (debug)
+ fprintf (stderr,
+ "\tiss = %5d, value = %5ld, index = %5d, name = %s\n",
+ symbol.iss, (long) symbol.value, symbol.index, name);
+#endif
+ }
+#ifdef COLLECT_EXPORT_LIST
+ /* If we are building a shared object we should collect
+ information about undefined symbols for later
+ import list generation. */
+ else if (shared_obj && GCC_UNDEF_SYMBOL (symbol))
+ {
+ char *name;
+
+ if ((name = ldgetname (ldptr, &symbol)) == NULL)
+ continue; /* should never happen */
+
+ /* All AIX function names have a duplicate entry
+ beginning with a dot. */
+ if (*name == '.')
+ ++name;
+ add_to_list (&undefined, name);
+ }
#endif
+ }
+ }
+#ifdef COLLECT_EXPORT_LIST
+ else
+ {
+ /* If archive contains both 32-bit and 64-bit objects,
+ we want to skip objects in other mode so mismatch normal. */
+ if (debug)
+ fprintf (stderr, "%s : magic=%o aix64=%d mismatch\n",
+ prog_name, HEADER (ldptr).f_magic, aix64_flag);
}
+#endif
+ }
+ else
+ {
+ fatal ("%s: cannot open as COFF file", prog_name);
}
+#ifdef COLLECT_EXPORT_LIST
+ /* On AIX loop continues while there are more members in archive. */
}
-
+ while (ldclose (ldptr) == FAILURE);
+#else
+ /* Otherwise we simply close ldptr. */
(void) ldclose(ldptr);
+#endif
}
-#ifdef XCOFF_SCAN_LIBS
-/* Scan imported AIX libraries for GCC static ctors and dtors.
- FIXME: it is possible to link an executable without the actual import
- library by using an "import file" - a text file listing symbols
- exported by a library. To support this, we would have to scan
- import files as well as actual shared binaries to find GCC ctors.
- TODO: use memory mapping instead of 'ld' routines, files are already
- memory mapped, but we could eliminate the extra in-memory copies.
- Is it worth the effort? */
-static void
-scan_libraries (prog_name)
+#ifdef COLLECT_EXPORT_LIST
+
+/* This new function is used to decide whether we should
+ generate import list for an object or to use it directly. */
+static int
+use_import_list (prog_name)
char *prog_name;
{
- LDFILE *ldptr;
- SCNHDR ldsh;
- static struct path_prefix libpath; /* we should only do this once */
-
- if ((ldptr = ldopen (prog_name, ldptr)) == NULL)
- fatal ("%s: can't open as COFF file", prog_name);
-
- if (!MY_ISCOFF (HEADER (ldptr).f_magic))
- fatal ("%s: not a COFF file", prog_name);
-
- /* find and read loader section */
- if (ldnshread (ldptr, _LOADER, &ldsh))
- {
- LDHDR ldh;
- char *impbuf;
- int entry;
-
- FSEEK (ldptr, ldsh.s_scnptr, BEGINNING);
- FREAD (&ldh, sizeof (ldh), 1, ldptr);
- /* read import library list */
- impbuf = alloca (ldh.l_istlen);
- FSEEK (ldptr, ldh.l_impoff + ldsh.s_scnptr, BEGINNING);
- FREAD (impbuf, ldh.l_istlen, 1, ldptr);
+ char *p;
- if (debug)
- fprintf (stderr, "LIBPATH=%s\n", impbuf);
- prefix_from_string (impbuf, &libpath);
+ /* If we do not build a shared object then import list should not be used. */
+ if (! shared_obj) return 0;
- /* skip LIBPATH and empty base and member fields */
- impbuf += strlen (impbuf) + 3;
- for (entry = 1; entry < ldh.l_nimpid; ++entry)
- {
- char *impath = impbuf;
- char *implib = impath + strlen (impath) + 1;
- char *impmem = implib + strlen (implib) + 1;
- char *soname = NULL;
- char *trial;
- int pathlen;
- LDFILE *libptr = NULL;
- struct prefix_list *pl;
- ARCHDR ah;
-
- impbuf = impmem + strlen (impmem) + 1;
- if (debug)
- fprintf (stderr, "PATH+BASE=%s%s\n", impath, implib);
- /* Skip AIX kernel exports */
- if (*impath == '/' && *(impath+1) == '\0'
- && strcmp (implib, "unix") == 0)
- continue;
- pathlen = strlen (impath);
- trial = alloca (MAX (pathlen + 1, libpath.max_len)
- + strlen (implib) + 1);
- if (*impath)
- {
- strcpy (trial, impath);
- if (impath[pathlen - 1] != '/')
- trial[pathlen++] = '/';
- strcpy (trial + pathlen, implib);
- if (access (trial, R_OK) == 0)
- soname = trial;
- }
- else
- for (pl = libpath.plist; pl; pl = pl->next)
- {
- strcpy (trial, pl->prefix);
- strcat (trial, implib);
- if (access (trial, R_OK) == 0)
- {
- soname = trial;
- break;
- }
- }
+ /* Currently we check only for libgcc, but this can be changed in future. */
+ p = strstr (prog_name, "libgcc.a");
+ if (p != 0 && (strlen (p) == sizeof ("libgcc.a") - 1))
+ return 1;
+ return 0;
+}
- if (! soname)
- fatal ("%s: library not found", implib);
- if (debug)
- if (*impmem)
- fprintf (stderr, "%s (%s)\n", soname, impmem);
- else
- fprintf (stderr, "%s\n", soname);
+/* Given a library name without "lib" prefix, this function
+ returns a full library name including a path. */
+static char *
+resolve_lib_name (name)
+ char *name;
+{
+ char *lib_buf;
+ int i, j, l = 0;
+
+ for (i = 0; libpaths[i]; i++)
+ if (libpaths[i]->max_len > l)
+ l = libpaths[i]->max_len;
+
+ lib_buf = xmalloc (l + strlen(name) + 10);
- do
+ for (i = 0; libpaths[i]; i++)
+ {
+ struct prefix_list *list = libpaths[i]->plist;
+ for (; list; list = list->next)
+ {
+ for (j = 0; libexts[j]; j++)
{
- /* scan imported shared objects for GCC GLOBAL ctors */
- short type;
- if ((libptr = ldopen (soname, libptr)) == NULL)
- fatal ("%s: can't open import library", soname);
- if (TYPE (libptr) == ARTYPE)
- {
- LDFILE *memptr;
- if (! *impmem)
- fatal ("%s: no archive member specified", soname);
- ldahread (libptr, &ah);
- if (strcmp (ah.ar_name, impmem))
- continue;
- }
- type = HEADER (libptr).f_magic;
- if (HEADER (libptr).f_flags & F_SHROBJ)
+ /* The following lines are needed because path_prefix list
+ may contain directories both with trailing '/' and
+ without it. */
+ char *p = "";
+ if (list->prefix[strlen(list->prefix)-1] != '/')
+ p = "/";
+ sprintf (lib_buf, "%s%slib%s.%s",
+ list->prefix, p, name, libexts[j]);
+if (debug) fprintf (stderr, "searching for: %s\n", lib_buf);
+ if (file_exists (lib_buf))
{
- SCNHDR soldsh;
- LDHDR soldh;
- long symcnt, i;
- char *ldstrings;
- LDSYM *lsyms;
- if (!ldnshread (libptr, _LOADER, &soldsh))
- fatal ("%s: not an import library", soname);
- FSEEK (libptr, soldsh.s_scnptr, BEGINNING);
- if (FREAD (&soldh, sizeof (soldh), 1, libptr) != 1)
- fatal ("%s: can't read loader section", soname);
- /*fprintf (stderr, "\tscanning %s\n", soname);*/
- symcnt = soldh.l_nsyms;
- lsyms = (LDSYM*) alloca (symcnt * sizeof (*lsyms));
- symcnt = FREAD (lsyms, sizeof (*lsyms), symcnt, libptr);
- ldstrings = alloca (soldh.l_stlen);
- FSEEK (libptr, soldsh.s_scnptr+soldh.l_stoff, BEGINNING);
- FREAD (ldstrings, soldh.l_stlen, 1, libptr);
- for (i = 0; i < symcnt; ++i)
- {
- LDSYM *l = lsyms + i;
- if (LDR_EXPORT (*l))
- {
- char *expname = 0;
- if (l->l_zeroes)
- expname = l->l_name;
- else if (l->l_offset < soldh.l_stlen)
- expname = ldstrings + l->l_offset;
- switch (is_ctor_dtor (expname))
- {
- case 3:
- if (debug)
- fprintf (stderr, "\t%s\n", expname);
- add_to_list (&constructors, expname);
- break;
-
- case 4:
- add_to_list (&destructors, expname);
- break;
-
- default: /* not a constructor or destructor */
- continue;
- }
- }
- }
+if (debug) fprintf (stderr, "found: %s\n", lib_buf);
+ return (lib_buf);
}
- else
- fprintf (stderr, "%s: type = %04X flags = %04X\n",
- ah.ar_name, type, HEADER (libptr).f_flags);
}
- while (ldclose (libptr) == FAILURE);
- /* printf (stderr, "closed %s\n", soname); */
}
}
+ if (debug)
+ fprintf (stderr, "not found\n");
+ else
+ fatal ("Library lib%s not found", name);
+ return (NULL);
+}
+
+/* Array of standard AIX libraries which should not
+ be scanned for ctors/dtors. */
+static char* aix_std_libs[] = {
+ "/unix",
+ "/lib/libc.a",
+ "/lib/libc_r.a",
+ "/usr/lib/libc.a",
+ "/usr/lib/libc_r.a",
+ "/usr/lib/threads/libc.a",
+ "/usr/ccs/lib/libc.a",
+ "/usr/ccs/lib/libc_r.a",
+ NULL
+};
+
+/* This function checks the filename and returns 1
+ if this name matches the location of a standard AIX library. */
+static int
+ignore_library (name)
+ char *name;
+{
+ char **p = &aix_std_libs[0];
+ while (*p++ != NULL)
+ if (! strcmp (name, *p)) return 1;
+ return 0;
}
-#endif /* XCOFF_SCAN_LIBS */
+
+#endif
#endif /* OBJECT_FORMAT_COFF */
@@ -2787,7 +3020,7 @@ extern int encode_mach_o_hdr ();
static void add_func_table PROTO((mo_header_t *, load_all_t *,
symbol_info_t *, int));
static void print_header PROTO((mo_header_t *));
-static void print_load_command PROTO((load_union_t*, size_t, int));
+static void print_load_command PROTO((load_union_t *, size_t, int));
static void bad_header PROTO((int));
static struct file_info *read_file PROTO((char *, int, int));
static void end_file PROTO((struct file_info *));
@@ -2826,7 +3059,7 @@ scan_prog_file (prog_name, which_pass)
prog_fd = open (prog_name, (rw) ? O_RDWR : O_RDONLY);
if (prog_fd < 0)
- fatal_perror ("can't read %s", prog_name);
+ fatal_perror ("cannot read %s", prog_name);
obj_file = read_file (prog_name, prog_fd, rw);
obj = obj_file->start;
@@ -2930,10 +3163,10 @@ scan_prog_file (prog_name, which_pass)
continue;
str_sect = load_array[load_hdr->sym.symc_strings_section].section;
- if (str_sect == (char *)0)
+ if (str_sect == (char *) 0)
fatal ("string section missing");
- if (load_cmd->section == (char *)0)
+ if (load_cmd->section == (char *) 0)
fatal ("section pointer missing");
num_syms = load_hdr->sym.symc_nentries;
@@ -2998,11 +3231,11 @@ scan_prog_file (prog_name, which_pass)
fatal ("no cmd_strings found");
/* Add __main to initializer list.
- If we are building a program instead of a shared library, don't
+ If we are building a program instead of a shared library, do not
do anything, since in the current version, you cannot do mallocs
and such in the constructors. */
- if (main_sym != (symbol_info_t *)0
+ if (main_sym != (symbol_info_t *) 0
&& ((hdr.moh_flags & MOH_EXECABLE_F) == 0))
add_func_table (&hdr, load_array, main_sym, FNTC_INITIALIZATION);
@@ -3057,7 +3290,7 @@ scan_prog_file (prog_name, which_pass)
if (debug)
print_load_command (load_hdr, offset, i);
- bcopy ((char *)load_hdr, (char *)(obj + offset), size);
+ bcopy ((char *) load_hdr, (char *) (obj + offset), size);
offset += size;
}
}
@@ -3096,7 +3329,7 @@ add_func_table (hdr_p, load_array, sym, type)
load_cmd = &load_array[load_index];
load_cmd->load = ptr;
- load_cmd->section = (char *)0;
+ load_cmd->section = (char *) 0;
/* Fill in func table load command. */
ptr->func.ldc_header.ldci_cmd_type = LDC_FUNC_TABLE;
@@ -3205,7 +3438,7 @@ print_load_command (load_hdr, offset, number)
int number;
{
mo_long_t type = load_hdr->hdr.ldci_cmd_type;
- char *type_str = (char *)0;
+ char *type_str = (char *) 0;
switch (type)
{
@@ -3230,7 +3463,7 @@ print_load_command (load_hdr, offset, number)
(long) load_hdr->hdr.ldci_section_off,
(long) load_hdr->hdr.ldci_section_len);
- if (type_str == (char *)0)
+ if (type_str == (char *) 0)
fprintf (stderr, ", ty: unknown (%ld)\n", (long) type);
else if (type != LDC_REGION)
@@ -3269,7 +3502,7 @@ static void
bad_header (status)
int status;
{
- char *msg = (char *)0;
+ char *msg = (char *) 0;
switch (status)
{
@@ -3281,7 +3514,7 @@ bad_header (status)
case MO_ERROR_UNSUPPORTED_VERS: msg = "unsupported version"; break;
}
- if (msg == (char *)0)
+ if (msg == (char *) 0)
fatal ("unknown {de,en}code_mach_o_hdr return value %d", status);
else
fatal ("%s", msg);
@@ -3319,14 +3552,14 @@ read_file (name, fd, rw)
page_size = sysconf (_SC_PAGE_SIZE);
p->rounded_size = ((p->size + page_size - 1) / page_size) * page_size;
- p->start = mmap ((caddr_t)0,
+ p->start = mmap ((caddr_t) 0,
(rw) ? p->rounded_size : p->size,
(rw) ? (PROT_READ | PROT_WRITE) : PROT_READ,
MAP_FILE | MAP_VARIABLE | MAP_SHARED,
fd,
0L);
- if (p->start != (char *)0 && p->start != (char *)-1)
+ if (p->start != (char *) 0 && p->start != (char *) -1)
p->use_mmap = 1;
else
diff --git a/contrib/gcc/combine.c b/contrib/gcc/combine.c
index 473adc8..db9bb38 100644
--- a/contrib/gcc/combine.c
+++ b/contrib/gcc/combine.c
@@ -1,5 +1,5 @@
/* Optimize by combining instructions for GNU compiler.
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -81,21 +81,23 @@ Boston, MA 02111-1307, USA. */
#include <varargs.h>
#endif
-/* Must precede rtl.h for FFS. */
-#include <stdio.h>
+/* stdio.h must precede rtl.h for FFS. */
+#include "system.h"
#include "rtl.h"
#include "flags.h"
#include "regs.h"
#include "hard-reg-set.h"
-#include "expr.h"
#include "basic-block.h"
#include "insn-config.h"
+/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
+#include "expr.h"
#include "insn-flags.h"
#include "insn-codes.h"
#include "insn-attr.h"
#include "recog.h"
#include "real.h"
+#include "toplev.h"
/* It is not safe to use ordinary gen_lowpart in combine.
Use gen_lowpart_for_combine instead. See comments there. */
@@ -140,9 +142,8 @@ static int max_uid_cuid;
/* Get the cuid of an insn. */
-#define INSN_CUID(INSN) (INSN_UID (INSN) > max_uid_cuid \
- ? (abort(), 0) \
- : uid_cuid[INSN_UID (INSN)])
+#define INSN_CUID(INSN) \
+(INSN_UID (INSN) > max_uid_cuid ? insn_cuid (INSN) : uid_cuid[INSN_UID (INSN)])
/* Maximum register number, which is the size of the tables below. */
@@ -199,13 +200,6 @@ static HARD_REG_SET newpat_used_regs;
static rtx added_links_insn;
-/* This is the value of undobuf.num_undo when we started processing this
- substitution. This will prevent gen_rtx_combine from re-used a piece
- from the previous expression. Doing so can produce circular rtl
- structures. */
-
-static int previous_num_undos;
-
/* Basic block number of the block in which we are performing combines. */
static int this_basic_block;
@@ -253,7 +247,7 @@ static int this_basic_block;
reg_last_set_invalid[i] is set non-zero when register I is being assigned
to and reg_last_set_table_tick[i] == label_tick. */
-/* Record last value assigned to (hard or pseudo) register n. */
+/* Record last value assigned to (hard or pseudo) register n. */
static rtx *reg_last_set_value;
@@ -263,7 +257,7 @@ static rtx *reg_last_set_value;
static int *reg_last_set_label;
/* Record the value of label_tick when an expression involving register n
- is placed in reg_last_set_value. */
+ is placed in reg_last_set_value. */
static int *reg_last_set_table_tick;
@@ -272,7 +266,7 @@ static int *reg_last_set_table_tick;
static char *reg_last_set_invalid;
-/* Incremented for each label. */
+/* Incremented for each label. */
static int label_tick;
@@ -320,6 +314,7 @@ static char *reg_last_set_sign_bit_copies;
struct undo
{
+ struct undo *next;
int is_int;
union {rtx r; int i;} old_contents;
union {rtx *r; int *i;} where;
@@ -332,15 +327,19 @@ struct undo
The value of storage is what to pass to obfree.
other_insn is nonzero if we have modified some other insn in the process
- of working on subst_insn. It must be verified too. */
+ of working on subst_insn. It must be verified too.
-#define MAX_UNDO 50
+ previous_undos is the value of undobuf.undos when we started processing
+ this substitution. This will prevent gen_rtx_combine from re-used a piece
+ from the previous expression. Doing so can produce circular rtl
+ structures. */
struct undobuf
{
- int num_undo;
char *storage;
- struct undo undo[MAX_UNDO];
+ struct undo *undos;
+ struct undo *frees;
+ struct undo *previous_undos;
rtx other_insn;
};
@@ -353,32 +352,44 @@ static struct undobuf undobuf;
the undo table. */
#define SUBST(INTO, NEWVAL) \
- do { rtx _new = (NEWVAL); \
- if (undobuf.num_undo < MAX_UNDO) \
- { \
- undobuf.undo[undobuf.num_undo].is_int = 0; \
- undobuf.undo[undobuf.num_undo].where.r = &INTO; \
- undobuf.undo[undobuf.num_undo].old_contents.r = INTO; \
- INTO = _new; \
- if (undobuf.undo[undobuf.num_undo].old_contents.r != INTO) \
- undobuf.num_undo++; \
- } \
+ do { rtx _new = (NEWVAL); \
+ struct undo *_buf; \
+ \
+ if (undobuf.frees) \
+ _buf = undobuf.frees, undobuf.frees = _buf->next; \
+ else \
+ _buf = (struct undo *) xmalloc (sizeof (struct undo)); \
+ \
+ _buf->is_int = 0; \
+ _buf->where.r = &INTO; \
+ _buf->old_contents.r = INTO; \
+ INTO = _new; \
+ if (_buf->old_contents.r == INTO) \
+ _buf->next = undobuf.frees, undobuf.frees = _buf; \
+ else \
+ _buf->next = undobuf.undos, undobuf.undos = _buf; \
} while (0)
-/* Similar to SUBST, but NEWVAL is an int. INTO will normally be an XINT
- expression.
- Note that substitution for the value of a CONST_INT is not safe. */
+/* Similar to SUBST, but NEWVAL is an int expression. Note that substitution
+ for the value of a HOST_WIDE_INT value (including CONST_INT) is
+ not safe. */
#define SUBST_INT(INTO, NEWVAL) \
- do { if (undobuf.num_undo < MAX_UNDO) \
-{ \
- undobuf.undo[undobuf.num_undo].is_int = 1; \
- undobuf.undo[undobuf.num_undo].where.i = (int *) &INTO; \
- undobuf.undo[undobuf.num_undo].old_contents.i = INTO; \
- INTO = NEWVAL; \
- if (undobuf.undo[undobuf.num_undo].old_contents.i != INTO) \
- undobuf.num_undo++; \
- } \
+ do { struct undo *_buf; \
+ \
+ if (undobuf.frees) \
+ _buf = undobuf.frees, undobuf.frees = _buf->next; \
+ else \
+ _buf = (struct undo *) xmalloc (sizeof (struct undo)); \
+ \
+ _buf->is_int = 1; \
+ _buf->where.i = (int *) &INTO; \
+ _buf->old_contents.i = INTO; \
+ INTO = NEWVAL; \
+ if (_buf->old_contents.i == INTO) \
+ _buf->next = undobuf.frees, undobuf.frees = _buf; \
+ else \
+ _buf->next = undobuf.undos, undobuf.undos = _buf; \
} while (0)
/* Number of times the pseudo being substituted for
@@ -386,10 +397,11 @@ static struct undobuf undobuf;
static int n_occurrences;
-static void init_reg_last_arrays PROTO(());
-static void setup_incoming_promotions PROTO(());
+static void init_reg_last_arrays PROTO((void));
+static void setup_incoming_promotions PROTO((void));
static void set_nonzero_bits_and_sign_copies PROTO((rtx, rtx));
static int can_combine_p PROTO((rtx, rtx, rtx, rtx, rtx *, rtx *));
+static int sets_function_arg_p PROTO((rtx));
static int combinable_i3pat PROTO((rtx, rtx *, rtx, rtx, int, rtx *));
static rtx try_combine PROTO((rtx, rtx, rtx));
static void undo_all PROTO((void));
@@ -410,6 +422,7 @@ static rtx force_to_mode PROTO((rtx, enum machine_mode,
unsigned HOST_WIDE_INT, rtx, int));
static rtx if_then_else_cond PROTO((rtx, rtx *, rtx *));
static rtx known_cond PROTO((rtx, enum rtx_code, rtx, rtx));
+static int rtx_equal_for_field_assignment_p PROTO((rtx, rtx));
static rtx make_field_assignment PROTO((rtx));
static rtx apply_distributive_law PROTO((rtx));
static rtx simplify_and_const_int PROTO((rtx, enum machine_mode, rtx,
@@ -435,16 +448,17 @@ static void update_table_tick PROTO((rtx));
static void record_value_for_reg PROTO((rtx, rtx, rtx));
static void record_dead_and_set_regs_1 PROTO((rtx, rtx));
static void record_dead_and_set_regs PROTO((rtx));
-static int get_last_value_validate PROTO((rtx *, int, int));
+static int get_last_value_validate PROTO((rtx *, rtx, int, int));
static rtx get_last_value PROTO((rtx));
static int use_crosses_set_p PROTO((rtx, int));
static void reg_dead_at_p_1 PROTO((rtx, rtx));
static int reg_dead_at_p PROTO((rtx, rtx));
-static void move_deaths PROTO((rtx, int, rtx, rtx *));
+static void move_deaths PROTO((rtx, rtx, int, rtx, rtx *));
static int reg_bitfield_target_p PROTO((rtx, rtx));
static void distribute_notes PROTO((rtx, rtx, rtx, rtx, rtx, rtx));
static void distribute_links PROTO((rtx));
static void mark_used_regs_combine PROTO((rtx));
+static int insn_cuid PROTO((rtx));
/* Main entry point for combiner. F is the first insn of the function.
NREGS is the first unused pseudo-reg number. */
@@ -454,7 +468,10 @@ combine_instructions (f, nregs)
rtx f;
int nregs;
{
- register rtx insn, next, prev;
+ register rtx insn, next;
+#ifdef HAVE_cc0
+ register rtx prev;
+#endif
register int i;
register rtx links, nextlinks;
@@ -462,7 +479,7 @@ combine_instructions (f, nregs)
combine_merges = 0;
combine_extras = 0;
combine_successes = 0;
- undobuf.num_undo = previous_num_undos = 0;
+ undobuf.undos = undobuf.previous_undos = 0;
combine_max_regno = nregs;
@@ -535,6 +552,12 @@ combine_instructions (f, nregs)
{
note_stores (PATTERN (insn), set_nonzero_bits_and_sign_copies);
record_dead_and_set_regs (insn);
+
+#ifdef AUTO_INC_DEC
+ for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
+ if (REG_NOTE_KIND (links) == REG_INC)
+ set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX);
+#endif
}
if (GET_CODE (insn) == CODE_LABEL)
@@ -694,17 +717,18 @@ setup_incoming_promotions ()
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (FUNCTION_ARG_REGNO_P (regno)
&& (reg = promoted_input_arg (regno, &mode, &unsignedp)) != 0)
- record_value_for_reg (reg, first,
- gen_rtx (unsignedp ? ZERO_EXTEND : SIGN_EXTEND,
- GET_MODE (reg),
- gen_rtx (CLOBBER, mode, const0_rtx)));
+ {
+ record_value_for_reg
+ (reg, first, gen_rtx_fmt_e ((unsignedp ? ZERO_EXTEND
+ : SIGN_EXTEND),
+ GET_MODE (reg),
+ gen_rtx_CLOBBER (mode, const0_rtx)));
+ }
#endif
}
-/* Called via note_stores. If X is a pseudo that is used in more than
- one basic block, is narrower that HOST_BITS_PER_WIDE_INT, and is being
- set, record what bits are known zero. If we are clobbering X,
- ignore this "set" because the clobbered value won't be used.
+/* Called via note_stores. If X is a pseudo that is narrower than
+ HOST_BITS_PER_WIDE_INT and is being set, record what bits are known zero.
If we are setting only a portion of X and we can't figure out what
portion, assume all bits will be used since we don't know what will
@@ -723,18 +747,15 @@ set_nonzero_bits_and_sign_copies (x, set)
if (GET_CODE (x) == REG
&& REGNO (x) >= FIRST_PSEUDO_REGISTER
- && reg_n_sets[REGNO (x)] > 1
- && reg_basic_block[REGNO (x)] < 0
/* If this register is undefined at the start of the file, we can't
say what its contents were. */
- && ! (basic_block_live_at_start[0][REGNO (x) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (REGNO (x) % REGSET_ELT_BITS)))
+ && ! REGNO_REG_SET_P (basic_block_live_at_start[0], REGNO (x))
&& GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT)
{
- if (GET_CODE (set) == CLOBBER)
+ if (set == 0 || GET_CODE (set) == CLOBBER)
{
reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
- reg_sign_bit_copies[REGNO (x)] = 0;
+ reg_sign_bit_copies[REGNO (x)] = 1;
return;
}
@@ -784,7 +805,7 @@ set_nonzero_bits_and_sign_copies (x, set)
else
{
reg_nonzero_bits[REGNO (x)] = GET_MODE_MASK (GET_MODE (x));
- reg_sign_bit_copies[REGNO (x)] = 0;
+ reg_sign_bit_copies[REGNO (x)] = 1;
}
}
}
@@ -808,7 +829,10 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
{
int i;
rtx set = 0, src, dest;
- rtx p, link;
+ rtx p;
+#ifdef AUTO_INC_DEC
+ rtx link;
+#endif
int all_adjacent = (succ ? (next_active_insn (insn) == succ
&& next_active_insn (succ) == i3)
: next_active_insn (insn) == i3);
@@ -839,6 +863,43 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
switch (GET_CODE (elt))
{
+ /* This is important to combine floating point insns
+ for the SH4 port. */
+ case USE:
+ /* Combining an isolated USE doesn't make sense.
+ We depend here on combinable_i3_pat to reject them. */
+ /* The code below this loop only verifies that the inputs of
+ the SET in INSN do not change. We call reg_set_between_p
+ to verify that the REG in the USE does not change betweeen
+ I3 and INSN.
+ If the USE in INSN was for a pseudo register, the matching
+ insn pattern will likely match any register; combining this
+ with any other USE would only be safe if we knew that the
+ used registers have identical values, or if there was
+ something to tell them apart, e.g. different modes. For
+ now, we forgo such compilcated tests and simply disallow
+ combining of USES of pseudo registers with any other USE. */
+ if (GET_CODE (XEXP (elt, 0)) == REG
+ && GET_CODE (PATTERN (i3)) == PARALLEL)
+ {
+ rtx i3pat = PATTERN (i3);
+ int i = XVECLEN (i3pat, 0) - 1;
+ int regno = REGNO (XEXP (elt, 0));
+ do
+ {
+ rtx i3elt = XVECEXP (i3pat, 0, i);
+ if (GET_CODE (i3elt) == USE
+ && GET_CODE (XEXP (i3elt, 0)) == REG
+ && (REGNO (XEXP (i3elt, 0)) == regno
+ ? reg_set_between_p (XEXP (elt, 0),
+ PREV_INSN (insn), i3)
+ : regno >= FIRST_PSEUDO_REGISTER))
+ return 0;
+ }
+ while (--i >= 0);
+ }
+ break;
+
/* We can ignore CLOBBERs. */
case CLOBBER:
break;
@@ -939,7 +1000,12 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
insns. Eliminate this problem by not combining with such an insn.
Also, on some machines we don't want to extend the life of a hard
- register. */
+ register.
+
+ This is the same test done in can_combine except that we don't test
+ if SRC is a CALL operation to permit a hard register with
+ SMALL_REGISTER_CLASSES, and that we have to take all_adjacent
+ into account. */
if (GET_CODE (src) == REG
&& ((REGNO (dest) < FIRST_PSEUDO_REGISTER
@@ -947,13 +1013,16 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
/* Don't extend the life of a hard register unless it is
user variable (if we have few registers) or it can't
fit into the desired register (meaning something special
- is going on). */
+ is going on).
+ Also avoid substituting a return register into I3, because
+ reload can't handle a conflict with constraints of other
+ inputs. */
|| (REGNO (src) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (src), GET_MODE (src))
-#ifdef SMALL_REGISTER_CLASSES
- || ! REG_USERVAR_P (src)
-#endif
- ))))
+ || (SMALL_REGISTER_CLASSES
+ && ((! all_adjacent && ! REG_USERVAR_P (src))
+ || (FUNCTION_VALUE_REGNO_P (REGNO (src))
+ && ! REG_USERVAR_P (src))))))))
return 0;
}
else if (GET_CODE (dest) != CC0)
@@ -971,14 +1040,26 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
return 0;
/* If INSN contains anything volatile, or is an `asm' (whether volatile
- or not), reject, unless nothing volatile comes between it and I3,
- with the exception of SUCC. */
+ or not), reject, unless nothing volatile comes between it and I3 */
if (GET_CODE (src) == ASM_OPERANDS || volatile_refs_p (src))
- for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
- if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
- && p != succ && volatile_refs_p (PATTERN (p)))
- return 0;
+ {
+ /* Make sure succ doesn't contain a volatile reference. */
+ if (succ != 0 && volatile_refs_p (PATTERN (succ)))
+ return 0;
+
+ for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
+ if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
+ && p != succ && volatile_refs_p (PATTERN (p)))
+ return 0;
+ }
+
+ /* If INSN is an asm, and DEST is a hard register, reject, since it has
+ to be an explicit register variable, and was chosen for a reason. */
+
+ if (GET_CODE (src) == ASM_OPERANDS
+ && GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER)
+ return 0;
/* If there are any volatile insns between INSN and I3, reject, because
they might affect machine state. */
@@ -1028,6 +1109,46 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
return 1;
}
+/* Check if PAT is an insn - or a part of it - used to set up an
+ argument for a function in a hard register. */
+
+static int
+sets_function_arg_p (pat)
+ rtx pat;
+{
+ int i;
+ rtx inner_dest;
+
+ switch (GET_CODE (pat))
+ {
+ case INSN:
+ return sets_function_arg_p (PATTERN (pat));
+
+ case PARALLEL:
+ for (i = XVECLEN (pat, 0); --i >= 0;)
+ if (sets_function_arg_p (XVECEXP (pat, 0, i)))
+ return 1;
+
+ break;
+
+ case SET:
+ inner_dest = SET_DEST (pat);
+ while (GET_CODE (inner_dest) == STRICT_LOW_PART
+ || GET_CODE (inner_dest) == SUBREG
+ || GET_CODE (inner_dest) == ZERO_EXTRACT)
+ inner_dest = XEXP (inner_dest, 0);
+
+ return (GET_CODE (inner_dest) == REG
+ && REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
+ && FUNCTION_ARG_REGNO_P (REGNO (inner_dest)));
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
/* LOC is the location within I3 that contains its pattern or the component
of a PARALLEL of the pattern. We validate that it is valid for combining.
@@ -1056,7 +1177,7 @@ can_combine_p (insn, i3, pred, succ, pdest, psrc)
If I1_NOT_IN_SRC is non-zero, it means that finding I1 in the source
of a SET must prevent combination from occurring.
- On machines where SMALL_REGISTER_CLASSES is defined, we don't combine
+ On machines where SMALL_REGISTER_CLASSES is non-zero, we don't combine
if the destination of a SET is a hard register that isn't a user
variable.
@@ -1085,7 +1206,11 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
rtx set = expand_field_assignment (x);
rtx dest = SET_DEST (set);
rtx src = SET_SRC (set);
- rtx inner_dest = dest, inner_src = src;
+ rtx inner_dest = dest;
+
+#if 0
+ rtx inner_src = src;
+#endif
SUBST (*loc, set);
@@ -1123,17 +1248,28 @@ combinable_i3pat (i3, loc, i2dest, i1dest, i1_not_in_src, pi3dest_killed)
if ((inner_dest != dest
&& (reg_overlap_mentioned_p (i2dest, inner_dest)
|| (i1dest && reg_overlap_mentioned_p (i1dest, inner_dest))))
+
/* This is the same test done in can_combine_p except that we
allow a hard register with SMALL_REGISTER_CLASSES if SRC is a
- CALL operation. */
+ CALL operation. Moreover, we can't test all_adjacent; we don't
+ have to, since this instruction will stay in place, thus we are
+ not considering increasing the lifetime of INNER_DEST.
+
+ Also, if this insn sets a function argument, combining it with
+ something that might need a spill could clobber a previous
+ function argument; the all_adjacent test in can_combine_p also
+ checks this; here, we do a more specific test for this case. */
+
|| (GET_CODE (inner_dest) == REG
&& REGNO (inner_dest) < FIRST_PSEUDO_REGISTER
&& (! HARD_REGNO_MODE_OK (REGNO (inner_dest),
GET_MODE (inner_dest))
-#ifdef SMALL_REGISTER_CLASSES
- || (GET_CODE (src) != CALL && ! REG_USERVAR_P (inner_dest))
-#endif
- ))
+ || (SMALL_REGISTER_CLASSES && GET_CODE (src) != CALL
+ && ! REG_USERVAR_P (inner_dest)
+ && (FUNCTION_VALUE_REGNO_P (REGNO (inner_dest))
+ || (FUNCTION_ARG_REGNO_P (REGNO (inner_dest))
+ && i3 != 0
+ && sets_function_arg_p (prev_nonnote_insn (i3)))))))
|| (i1_not_in_src && reg_overlap_mentioned_p (i1dest, src)))
return 0;
@@ -1240,7 +1376,7 @@ try_combine (i3, i2, i1)
combine_attempts++;
- undobuf.num_undo = previous_num_undos = 0;
+ undobuf.undos = undobuf.previous_undos = 0;
undobuf.other_insn = 0;
/* Save the current high-water-mark so we can free storage if we didn't
@@ -1273,11 +1409,10 @@ try_combine (i3, i2, i1)
if (i1 == 0 && GET_CODE (i3) == INSN && GET_CODE (PATTERN (i3)) == SET
&& GET_CODE (SET_SRC (PATTERN (i3))) == REG
&& REGNO (SET_SRC (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
-#ifdef SMALL_REGISTER_CLASSES
- && (GET_CODE (SET_DEST (PATTERN (i3))) != REG
- || REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
- || REG_USERVAR_P (SET_DEST (PATTERN (i3))))
-#endif
+ && (! SMALL_REGISTER_CLASSES
+ || (GET_CODE (SET_DEST (PATTERN (i3))) != REG
+ || REGNO (SET_DEST (PATTERN (i3))) >= FIRST_PSEUDO_REGISTER
+ || REG_USERVAR_P (SET_DEST (PATTERN (i3)))))
&& find_reg_note (i3, REG_DEAD, SET_SRC (PATTERN (i3)))
&& GET_CODE (PATTERN (i2)) == PARALLEL
&& ! side_effects_p (SET_DEST (PATTERN (i3)))
@@ -1304,7 +1439,8 @@ try_combine (i3, i2, i1)
The problem can also happen if the dest of I3 is a memory ref,
if another dest in I2 is an indirect memory ref. */
for (i = 0; i < XVECLEN (p2, 0); i++)
- if (GET_CODE (XVECEXP (p2, 0, i)) == SET
+ if ((GET_CODE (XVECEXP (p2, 0, i)) == SET
+ || GET_CODE (XVECEXP (p2, 0, i)) == CLOBBER)
&& reg_overlap_mentioned_p (SET_DEST (PATTERN (i3)),
SET_DEST (XVECEXP (p2, 0, i))))
break;
@@ -1371,8 +1507,9 @@ try_combine (i3, i2, i1)
as I2 will not cause a problem. */
subst_prev_insn = i1
- = gen_rtx (INSN, VOIDmode, INSN_UID (i2), 0, i2,
- XVECEXP (PATTERN (i2), 0, 1), -1, 0, 0);
+ = gen_rtx_INSN (VOIDmode, INSN_UID (i2), NULL_RTX, i2,
+ XVECEXP (PATTERN (i2), 0, 1), -1, NULL_RTX,
+ NULL_RTX);
SUBST (PATTERN (i2), XVECEXP (PATTERN (i2), 0, 0));
SUBST (XEXP (SET_SRC (PATTERN (i2)), 0),
@@ -1469,7 +1606,7 @@ try_combine (i3, i2, i1)
I2DEST. */
i2pat = (GET_CODE (PATTERN (i2)) == PARALLEL
- ? gen_rtx (SET, VOIDmode, i2dest, i2src)
+ ? gen_rtx_SET (VOIDmode, i2dest, i2src)
: PATTERN (i2));
if (added_sets_2)
@@ -1513,7 +1650,7 @@ try_combine (i3, i2, i1)
i2src = subst (i2src, pc_rtx, pc_rtx, 0, 0);
}
- previous_num_undos = undobuf.num_undo;
+ undobuf.previous_undos = undobuf.undos;
}
#ifndef HAVE_cc0
@@ -1533,8 +1670,10 @@ try_combine (i3, i2, i1)
&& XEXP (SET_SRC (PATTERN (i3)), 1) == const0_rtx
&& rtx_equal_p (XEXP (SET_SRC (PATTERN (i3)), 0), i2dest))
{
+#ifdef EXTRA_CC_MODES
rtx *cc_use;
enum machine_mode compare_mode;
+#endif
newpat = PATTERN (i3);
SUBST (XEXP (SET_SRC (newpat), 0), i2src);
@@ -1555,10 +1694,10 @@ try_combine (i3, i2, i1)
!= GET_MODE (SET_DEST (newpat))))
{
int regno = REGNO (SET_DEST (newpat));
- rtx new_dest = gen_rtx (REG, compare_mode, regno);
+ rtx new_dest = gen_rtx_REG (compare_mode, regno);
if (regno < FIRST_PSEUDO_REGISTER
- || (reg_n_sets[regno] == 1 && ! added_sets_2
+ || (REG_N_SETS (regno) == 1 && ! added_sets_2
&& ! REG_USERVAR_P (SET_DEST (newpat))))
{
if (regno >= FIRST_PSEUDO_REGISTER)
@@ -1587,7 +1726,7 @@ try_combine (i3, i2, i1)
subst_low_cuid = INSN_CUID (i2);
newpat = subst (PATTERN (i3), i2dest, i2src, 0,
! i1_feeds_i3 && i1dest_in_i1src);
- previous_num_undos = undobuf.num_undo;
+ undobuf.previous_undos = undobuf.undos;
/* Record whether i2's body now appears within i3's body. */
i2_is_used = n_occurrences;
@@ -1600,7 +1739,7 @@ try_combine (i3, i2, i1)
{
/* Before we can do this substitution, we must redo the test done
above (see detailed comments there) that ensures that I1DEST
- isn't mentioned in any SETs in NEWPAT that are field assignments. */
+ isn't mentioned in any SETs in NEWPAT that are field assignments. */
if (! combinable_i3pat (NULL_RTX, &newpat, i1dest, NULL_RTX,
0, NULL_PTR))
@@ -1612,7 +1751,7 @@ try_combine (i3, i2, i1)
n_occurrences = 0;
subst_low_cuid = INSN_CUID (i1);
newpat = subst (newpat, i1dest, i1src, 0, 0);
- previous_num_undos = undobuf.num_undo;
+ undobuf.previous_undos = undobuf.undos;
}
/* Fail if an autoincrement side-effect has been duplicated. Be careful
@@ -1649,22 +1788,22 @@ try_combine (i3, i2, i1)
{
rtvec old = XVEC (newpat, 0);
total_sets = XVECLEN (newpat, 0) + added_sets_1 + added_sets_2;
- newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets));
- bcopy ((char *) &old->elem[0], (char *) &XVECEXP (newpat, 0, 0),
+ newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets));
+ bcopy ((char *) &old->elem[0], (char *) XVEC (newpat, 0)->elem,
sizeof (old->elem[0]) * old->num_elem);
}
else
{
rtx old = newpat;
total_sets = 1 + added_sets_1 + added_sets_2;
- newpat = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (total_sets));
+ newpat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (total_sets));
XVECEXP (newpat, 0, 0) = old;
}
if (added_sets_1)
XVECEXP (newpat, 0, --total_sets)
= (GET_CODE (PATTERN (i1)) == PARALLEL
- ? gen_rtx (SET, VOIDmode, i1dest, i1src) : PATTERN (i1));
+ ? gen_rtx_SET (VOIDmode, i1dest, i1src) : PATTERN (i1));
if (added_sets_2)
{
@@ -1761,17 +1900,17 @@ try_combine (i3, i2, i1)
&& GET_MODE (SET_DEST (newpat)) != VOIDmode
&& GET_CODE (i2dest) == REG
&& (REGNO (i2dest) < FIRST_PSEUDO_REGISTER
- || (reg_n_sets[REGNO (i2dest)] == 1 && ! added_sets_2
+ || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
&& ! REG_USERVAR_P (i2dest))))
- ni2dest = gen_rtx (REG, GET_MODE (SET_DEST (newpat)),
+ ni2dest = gen_rtx_REG (GET_MODE (SET_DEST (newpat)),
REGNO (i2dest));
- m_split = split_insns (gen_rtx (PARALLEL, VOIDmode,
- gen_rtvec (2, newpat,
- gen_rtx (CLOBBER,
- VOIDmode,
- ni2dest))),
- i3);
+ m_split = split_insns
+ (gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2, newpat,
+ gen_rtx_CLOBBER (VOIDmode,
+ ni2dest))),
+ i3);
}
if (m_split && GET_CODE (m_split) == SEQUENCE
@@ -1798,9 +1937,12 @@ try_combine (i3, i2, i1)
&i2_scratches);
/* If I2 or I3 has multiple SETs, we won't know how to track
- register status, so don't use these insns. */
+ register status, so don't use these insns. If I2's destination
+ is used between I2 and I3, we also can't use these insns. */
- if (i2_code_number >= 0 && i2set && i3set)
+ if (i2_code_number >= 0 && i2set && i3set
+ && (next_real_insn (i2) == i3
+ || ! reg_used_between_p (SET_DEST (i2set), i2, i3)))
insn_code_number = recog_for_combine (&newi3pat, i3, &new_i3_notes,
&i3_scratches);
if (insn_code_number >= 0)
@@ -1809,10 +1951,26 @@ try_combine (i3, i2, i1)
/* It is possible that both insns now set the destination of I3.
If so, we must show an extra use of it. */
- if (insn_code_number >= 0 && GET_CODE (SET_DEST (i3set)) == REG
- && GET_CODE (SET_DEST (i2set)) == REG
- && REGNO (SET_DEST (i3set)) == REGNO (SET_DEST (i2set)))
- reg_n_sets[REGNO (SET_DEST (i2set))]++;
+ if (insn_code_number >= 0)
+ {
+ rtx new_i3_dest = SET_DEST (i3set);
+ rtx new_i2_dest = SET_DEST (i2set);
+
+ while (GET_CODE (new_i3_dest) == ZERO_EXTRACT
+ || GET_CODE (new_i3_dest) == STRICT_LOW_PART
+ || GET_CODE (new_i3_dest) == SUBREG)
+ new_i3_dest = XEXP (new_i3_dest, 0);
+
+ while (GET_CODE (new_i2_dest) == ZERO_EXTRACT
+ || GET_CODE (new_i2_dest) == STRICT_LOW_PART
+ || GET_CODE (new_i2_dest) == SUBREG)
+ new_i2_dest = XEXP (new_i2_dest, 0);
+
+ if (GET_CODE (new_i3_dest) == REG
+ && GET_CODE (new_i2_dest) == REG
+ && REGNO (new_i3_dest) == REGNO (new_i2_dest))
+ REG_N_SETS (REGNO (new_i2_dest))++;
+ }
}
/* If we can split it and use I2DEST, go ahead and see if that
@@ -1827,7 +1985,7 @@ try_combine (i3, i2, i1)
&& (GET_MODE (*split) == GET_MODE (i2dest)
|| GET_MODE (*split) == VOIDmode
|| REGNO (i2dest) < FIRST_PSEUDO_REGISTER
- || (reg_n_sets[REGNO (i2dest)] == 1 && ! added_sets_2
+ || (REG_N_SETS (REGNO (i2dest)) == 1 && ! added_sets_2
&& ! REG_USERVAR_P (i2dest)))
&& (next_real_insn (i2) == i3
|| ! use_crosses_set_p (*split, INSN_CUID (i2)))
@@ -1843,7 +2001,7 @@ try_combine (i3, i2, i1)
validated that we can do this. */
if (GET_MODE (i2dest) != split_mode && split_mode != VOIDmode)
{
- newdest = gen_rtx (REG, split_mode, REGNO (i2dest));
+ newdest = gen_rtx_REG (split_mode, REGNO (i2dest));
if (REGNO (i2dest) >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[REGNO (i2dest)], newdest);
@@ -1956,7 +2114,7 @@ try_combine (i3, i2, i1)
that destination. */
PATTERN (i3) = newpat;
- distribute_links (gen_rtx (INSN_LIST, VOIDmode, i3, NULL_RTX));
+ distribute_links (gen_rtx_INSN_LIST (VOIDmode, i3, NULL_RTX));
/* I3 now uses what used to be its destination and which is
now I2's destination. That means we need a LOG_LINK from
@@ -2010,8 +2168,21 @@ try_combine (i3, i2, i1)
&& ! reg_referenced_p (SET_DEST (XVECEXP (newpat, 0, 0)),
XVECEXP (newpat, 0, 1)))
{
- newi2pat = XVECEXP (newpat, 0, 1);
- newpat = XVECEXP (newpat, 0, 0);
+ /* Normally, it doesn't matter which of the two is done first,
+ but it does if one references cc0. In that case, it has to
+ be first. */
+#ifdef HAVE_cc0
+ if (reg_referenced_p (cc0_rtx, XVECEXP (newpat, 0, 0)))
+ {
+ newi2pat = XVECEXP (newpat, 0, 0);
+ newpat = XVECEXP (newpat, 0, 1);
+ }
+ else
+#endif
+ {
+ newi2pat = XVECEXP (newpat, 0, 1);
+ newpat = XVECEXP (newpat, 0, 0);
+ }
i2_code_number
= recog_for_combine (&newi2pat, i2, &new_i2_notes, &i2_scratches);
@@ -2063,7 +2234,7 @@ try_combine (i3, i2, i1)
&& ! reg_set_p (XEXP (note, 0), PATTERN (undobuf.other_insn)))
{
if (GET_CODE (XEXP (note, 0)) == REG)
- reg_n_deaths[REGNO (XEXP (note, 0))]--;
+ REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
remove_note (undobuf.other_insn, note);
}
@@ -2071,7 +2242,7 @@ try_combine (i3, i2, i1)
for (note = new_other_notes; note; note = XEXP (note, 1))
if (GET_CODE (XEXP (note, 0)) == REG)
- reg_n_deaths[REGNO (XEXP (note, 0))]++;
+ REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
distribute_notes (new_other_notes, undobuf.other_insn,
undobuf.other_insn, NULL_RTX, NULL_RTX, NULL_RTX);
@@ -2085,10 +2256,15 @@ try_combine (i3, i2, i1)
rtx i3links, i2links, i1links = 0;
rtx midnotes = 0;
register int regno;
- /* Compute which registers we expect to eliminate. */
- rtx elim_i2 = (newi2pat || i2dest_in_i2src || i2dest_in_i1src
+ /* Compute which registers we expect to eliminate. newi2pat may be setting
+ either i3dest or i2dest, so we must check it. Also, i1dest may be the
+ same as i3dest, in which case newi2pat may be setting i1dest. */
+ rtx elim_i2 = ((newi2pat && reg_set_p (i2dest, newi2pat))
+ || i2dest_in_i2src || i2dest_in_i1src
? 0 : i2dest);
- rtx elim_i1 = i1 == 0 || i1dest_in_i1src ? 0 : i1dest;
+ rtx elim_i1 = (i1 == 0 || i1dest_in_i1src
+ || (newi2pat && reg_set_p (i1dest, newi2pat))
+ ? 0 : i1dest);
/* Get the old REG_NOTES and LOG_LINKS from all our insns and
clear them. */
@@ -2186,11 +2362,18 @@ try_combine (i3, i2, i1)
}
/* Get death notes for everything that is now used in either I3 or
- I2 and used to die in a previous insn. */
+ I2 and used to die in a previous insn. If we built two new
+ patterns, move from I1 to I2 then I2 to I3 so that we get the
+ proper movement on registers that I2 modifies. */
- move_deaths (newpat, i1 ? INSN_CUID (i1) : INSN_CUID (i2), i3, &midnotes);
if (newi2pat)
- move_deaths (newi2pat, INSN_CUID (i1), i2, &midnotes);
+ {
+ move_deaths (newi2pat, NULL_RTX, INSN_CUID (i1), i2, &midnotes);
+ move_deaths (newpat, newi2pat, INSN_CUID (i1), i3, &midnotes);
+ }
+ else
+ move_deaths (newpat, NULL_RTX, i1 ? INSN_CUID (i1) : INSN_CUID (i2),
+ i3, &midnotes);
/* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3. */
if (i3notes)
@@ -2215,7 +2398,7 @@ try_combine (i3, i2, i1)
{
for (temp = new_i2_notes; temp; temp = XEXP (temp, 1))
if (GET_CODE (XEXP (temp, 0)) == REG)
- reg_n_deaths[REGNO (XEXP (temp, 0))]++;
+ REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
distribute_notes (new_i2_notes, i2, i2, NULL_RTX, NULL_RTX, NULL_RTX);
}
@@ -2224,41 +2407,44 @@ try_combine (i3, i2, i1)
{
for (temp = new_i3_notes; temp; temp = XEXP (temp, 1))
if (GET_CODE (XEXP (temp, 0)) == REG)
- reg_n_deaths[REGNO (XEXP (temp, 0))]++;
+ REG_N_DEATHS (REGNO (XEXP (temp, 0)))++;
distribute_notes (new_i3_notes, i3, i3, NULL_RTX, NULL_RTX, NULL_RTX);
}
/* If I3DEST was used in I3SRC, it really died in I3. We may need to
- put a REG_DEAD note for it somewhere. Similarly for I2 and I1.
+ put a REG_DEAD note for it somewhere. If NEWI2PAT exists and sets
+ I3DEST, the death must be somewhere before I2, not I3. If we passed I3
+ in that case, it might delete I2. Similarly for I2 and I1.
Show an additional death due to the REG_DEAD note we make here. If
we discard it in distribute_notes, we will decrement it again. */
if (i3dest_killed)
{
if (GET_CODE (i3dest_killed) == REG)
- reg_n_deaths[REGNO (i3dest_killed)]++;
+ REG_N_DEATHS (REGNO (i3dest_killed))++;
- distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i3dest_killed,
- NULL_RTX),
- NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
- NULL_RTX, NULL_RTX);
+ if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
+ distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
+ NULL_RTX),
+ NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1);
+ else
+ distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i3dest_killed,
+ NULL_RTX),
+ NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
+ elim_i2, elim_i1);
}
- /* For I2 and I1, we have to be careful. If NEWI2PAT exists and sets
- I2DEST or I1DEST, the death must be somewhere before I2, not I3. If
- we passed I3 in that case, it might delete I2. */
-
if (i2dest_in_i2src)
{
if (GET_CODE (i2dest) == REG)
- reg_n_deaths[REGNO (i2dest)]++;
+ REG_N_DEATHS (REGNO (i2dest))++;
if (newi2pat && reg_set_p (i2dest, newi2pat))
- distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i2dest, NULL_RTX),
+ distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
else
- distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i2dest, NULL_RTX),
+ distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i2dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
@@ -2266,13 +2452,13 @@ try_combine (i3, i2, i1)
if (i1dest_in_i1src)
{
if (GET_CODE (i1dest) == REG)
- reg_n_deaths[REGNO (i1dest)]++;
+ REG_N_DEATHS (REGNO (i1dest))++;
if (newi2pat && reg_set_p (i1dest, newi2pat))
- distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i1dest, NULL_RTX),
+ distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i2, NULL_RTX, NULL_RTX, NULL_RTX);
else
- distribute_notes (gen_rtx (EXPR_LIST, REG_DEAD, i1dest, NULL_RTX),
+ distribute_notes (gen_rtx_EXPR_LIST (REG_DEAD, i1dest, NULL_RTX),
NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
NULL_RTX, NULL_RTX);
}
@@ -2303,14 +2489,15 @@ try_combine (i3, i2, i1)
/* If the reg formerly set in I2 died only once and that was in I3,
zero its use count so it won't make `reload' do any work. */
- if (! added_sets_2 && newi2pat == 0 && ! i2dest_in_i2src)
+ if (! added_sets_2
+ && (newi2pat == 0 || ! reg_mentioned_p (i2dest, newi2pat))
+ && ! i2dest_in_i2src)
{
regno = REGNO (i2dest);
- reg_n_sets[regno]--;
- if (reg_n_sets[regno] == 0
- && ! (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))))
- reg_n_refs[regno] = 0;
+ REG_N_SETS (regno)--;
+ if (REG_N_SETS (regno) == 0
+ && ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
+ REG_N_REFS (regno) = 0;
}
}
@@ -2329,11 +2516,10 @@ try_combine (i3, i2, i1)
regno = REGNO (i1dest);
if (! added_sets_1 && ! i1dest_in_i1src)
{
- reg_n_sets[regno]--;
- if (reg_n_sets[regno] == 0
- && ! (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))))
- reg_n_refs[regno] = 0;
+ REG_N_SETS (regno)--;
+ if (REG_N_SETS (regno) == 0
+ && ! REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
+ REG_N_REFS (regno) = 0;
}
}
@@ -2379,20 +2565,22 @@ try_combine (i3, i2, i1)
static void
undo_all ()
{
- register int i;
- if (undobuf.num_undo > MAX_UNDO)
- undobuf.num_undo = MAX_UNDO;
- for (i = undobuf.num_undo - 1; i >= 0; i--)
+ struct undo *undo, *next;
+
+ for (undo = undobuf.undos; undo; undo = next)
{
- if (undobuf.undo[i].is_int)
- *undobuf.undo[i].where.i = undobuf.undo[i].old_contents.i;
+ next = undo->next;
+ if (undo->is_int)
+ *undo->where.i = undo->old_contents.i;
else
- *undobuf.undo[i].where.r = undobuf.undo[i].old_contents.r;
-
+ *undo->where.r = undo->old_contents.r;
+
+ undo->next = undobuf.frees;
+ undobuf.frees = undo;
}
obfree (undobuf.storage);
- undobuf.num_undo = 0;
+ undobuf.undos = undobuf.previous_undos = 0;
/* Clear this here, so that subsequent get_last_value calls are not
affected. */
@@ -2454,7 +2642,7 @@ find_split_point (loc, insn)
&& ! memory_address_p (GET_MODE (x), XEXP (x, 0)))
{
rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER];
- rtx seq = split_insns (gen_rtx (SET, VOIDmode, reg, XEXP (x, 0)),
+ rtx seq = split_insns (gen_rtx_SET (VOIDmode, reg, XEXP (x, 0)),
subst_insn);
/* This should have produced two insns, each of which sets our
@@ -2531,6 +2719,11 @@ find_split_point (loc, insn)
if (split && split != &SET_SRC (x))
return split;
+ /* See if we can split SET_DEST as it stands. */
+ split = find_split_point (&SET_DEST (x), insn);
+ if (split && split != &SET_DEST (x))
+ return split;
+
/* See if this is a bitfield assignment with everything constant. If
so, this is an IOR of an AND, so split it into that. */
if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
@@ -2597,16 +2790,50 @@ find_split_point (loc, insn)
&& XEXP (*split, 0) == SET_DEST (x)
&& XEXP (*split, 1) == const0_rtx)
{
+ rtx extraction = make_extraction (GET_MODE (SET_DEST (x)),
+ XEXP (SET_SRC (x), 0),
+ pos, NULL_RTX, 1, 1, 0, 0);
+ if (extraction != 0)
+ {
+ SUBST (SET_SRC (x), extraction);
+ return find_split_point (loc, insn);
+ }
+ }
+ break;
+
+ case NE:
+ /* if STORE_FLAG_VALUE is -1, this is (NE X 0) and only one bit of X
+ is known to be on, this can be converted into a NEG of a shift. */
+ if (STORE_FLAG_VALUE == -1 && XEXP (SET_SRC (x), 1) == const0_rtx
+ && GET_MODE (SET_SRC (x)) == GET_MODE (XEXP (SET_SRC (x), 0))
+ && 1 <= (pos = exact_log2
+ (nonzero_bits (XEXP (SET_SRC (x), 0),
+ GET_MODE (XEXP (SET_SRC (x), 0))))))
+ {
+ enum machine_mode mode = GET_MODE (XEXP (SET_SRC (x), 0));
+
SUBST (SET_SRC (x),
- make_extraction (GET_MODE (SET_DEST (x)),
- XEXP (SET_SRC (x), 0),
- pos, NULL_RTX, 1, 1, 0, 0));
- return find_split_point (loc, insn);
+ gen_rtx_combine (NEG, mode,
+ gen_rtx_combine (LSHIFTRT, mode,
+ XEXP (SET_SRC (x), 0),
+ GEN_INT (pos))));
+
+ split = find_split_point (&SET_SRC (x), insn);
+ if (split && split != &SET_SRC (x))
+ return split;
}
break;
case SIGN_EXTEND:
inner = XEXP (SET_SRC (x), 0);
+
+ /* We can't optimize if either mode is a partial integer
+ mode as we don't know how many bits are significant
+ in those modes. */
+ if (GET_MODE_CLASS (GET_MODE (inner)) == MODE_PARTIAL_INT
+ || GET_MODE_CLASS (GET_MODE (SET_SRC (x))) == MODE_PARTIAL_INT)
+ break;
+
pos = 0;
len = GET_MODE_BITSIZE (GET_MODE (inner));
unsignedp = 0;
@@ -2626,6 +2853,9 @@ find_split_point (loc, insn)
unsignedp = (code == ZERO_EXTRACT);
}
break;
+
+ default:
+ break;
}
if (len && pos >= 0 && pos + len <= GET_MODE_BITSIZE (GET_MODE (inner)))
@@ -2722,6 +2952,9 @@ find_split_point (loc, insn)
SUBST (XEXP (x, 1), tem);
}
break;
+
+ default:
+ break;
}
/* Otherwise, select our actions depending on our rtx class. */
@@ -2732,14 +2965,14 @@ find_split_point (loc, insn)
split = find_split_point (&XEXP (x, 2), insn);
if (split)
return split;
- /* ... fall through ... */
+ /* ... fall through ... */
case '2':
case 'c':
case '<':
split = find_split_point (&XEXP (x, 1), insn);
if (split)
return split;
- /* ... fall through ... */
+ /* ... fall through ... */
case '1':
/* Some machines have (and (shift ...) ...) insns. If X is not
an AND, but XEXP (X, 0) is, use it as our split point. */
@@ -2811,7 +3044,7 @@ subst (x, from, to, in_dest, unique_copy)
So force this insn not to match in this (rare) case. */
if (! in_dest && code == REG && GET_CODE (from) == REG
&& REGNO (x) == REGNO (from))
- return gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+ return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
/* If this is an object, we are done unless it is a MEM or LO_SUM, both
of which may contain things that can be combined. */
@@ -2827,102 +3060,154 @@ subst (x, from, to, in_dest, unique_copy)
if (COMBINE_RTX_EQUAL_P (x, to))
return to;
- len = GET_RTX_LENGTH (code);
- fmt = GET_RTX_FORMAT (code);
-
- /* We don't need to process a SET_DEST that is a register, CC0, or PC, so
- set up to skip this common case. All other cases where we want to
- suppress replacing something inside a SET_SRC are handled via the
- IN_DEST operand. */
- if (code == SET
- && (GET_CODE (SET_DEST (x)) == REG
- || GET_CODE (SET_DEST (x)) == CC0
- || GET_CODE (SET_DEST (x)) == PC))
- fmt = "ie";
+ /* Parallel asm_operands need special attention because all of the
+ inputs are shared across the arms. Furthermore, unsharing the
+ rtl results in recognition failures. Failure to handle this case
+ specially can result in circular rtl.
- /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a constant. */
- if (fmt[0] == 'e')
- op0_mode = GET_MODE (XEXP (x, 0));
+ Solve this by doing a normal pass across the first entry of the
+ parallel, and only processing the SET_DESTs of the subsequent
+ entries. Ug. */
- for (i = 0; i < len; i++)
+ if (code == PARALLEL
+ && GET_CODE (XVECEXP (x, 0, 0)) == SET
+ && GET_CODE (SET_SRC (XVECEXP (x, 0, 0))) == ASM_OPERANDS)
{
- if (fmt[i] == 'E')
+ new = subst (XVECEXP (x, 0, 0), from, to, 0, unique_copy);
+
+ /* If this substitution failed, this whole thing fails. */
+ if (GET_CODE (new) == CLOBBER
+ && XEXP (new, 0) == const0_rtx)
+ return new;
+
+ SUBST (XVECEXP (x, 0, 0), new);
+
+ for (i = XVECLEN (x, 0) - 1; i >= 1; i--)
{
- register int j;
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ rtx dest = SET_DEST (XVECEXP (x, 0, i));
+
+ if (GET_CODE (dest) != REG
+ && GET_CODE (dest) != CC0
+ && GET_CODE (dest) != PC)
{
- if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
- {
- new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
- n_occurrences++;
- }
- else
- {
- new = subst (XVECEXP (x, i, j), from, to, 0, unique_copy);
+ new = subst (dest, from, to, 0, unique_copy);
- /* If this substitution failed, this whole thing fails. */
- if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
- return new;
- }
+ /* If this substitution failed, this whole thing fails. */
+ if (GET_CODE (new) == CLOBBER
+ && XEXP (new, 0) == const0_rtx)
+ return new;
- SUBST (XVECEXP (x, i, j), new);
+ SUBST (SET_DEST (XVECEXP (x, 0, i)), new);
}
}
- else if (fmt[i] == 'e')
+ }
+ else
+ {
+ len = GET_RTX_LENGTH (code);
+ fmt = GET_RTX_FORMAT (code);
+
+ /* We don't need to process a SET_DEST that is a register, CC0,
+ or PC, so set up to skip this common case. All other cases
+ where we want to suppress replacing something inside a
+ SET_SRC are handled via the IN_DEST operand. */
+ if (code == SET
+ && (GET_CODE (SET_DEST (x)) == REG
+ || GET_CODE (SET_DEST (x)) == CC0
+ || GET_CODE (SET_DEST (x)) == PC))
+ fmt = "ie";
+
+ /* Get the mode of operand 0 in case X is now a SIGN_EXTEND of a
+ constant. */
+ if (fmt[0] == 'e')
+ op0_mode = GET_MODE (XEXP (x, 0));
+
+ for (i = 0; i < len; i++)
{
- if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+ if (fmt[i] == 'E')
+ {
+ register int j;
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ {
+ if (COMBINE_RTX_EQUAL_P (XVECEXP (x, i, j), from))
+ {
+ new = (unique_copy && n_occurrences
+ ? copy_rtx (to) : to);
+ n_occurrences++;
+ }
+ else
+ {
+ new = subst (XVECEXP (x, i, j), from, to, 0,
+ unique_copy);
+
+ /* If this substitution failed, this whole thing
+ fails. */
+ if (GET_CODE (new) == CLOBBER
+ && XEXP (new, 0) == const0_rtx)
+ return new;
+ }
+
+ SUBST (XVECEXP (x, i, j), new);
+ }
+ }
+ else if (fmt[i] == 'e')
{
- /* In general, don't install a subreg involving two modes not
- tieable. It can worsen register allocation, and can even
- make invalid reload insns, since the reg inside may need to
- be copied from in the outside mode, and that may be invalid
- if it is an fp reg copied in integer mode.
-
- We allow two exceptions to this: It is valid if it is inside
- another SUBREG and the mode of that SUBREG and the mode of
- the inside of TO is tieable and it is valid if X is a SET
- that copies FROM to CC0. */
- if (GET_CODE (to) == SUBREG
- && ! MODES_TIEABLE_P (GET_MODE (to),
- GET_MODE (SUBREG_REG (to)))
- && ! (code == SUBREG
- && MODES_TIEABLE_P (GET_MODE (x),
- GET_MODE (SUBREG_REG (to))))
+ if (COMBINE_RTX_EQUAL_P (XEXP (x, i), from))
+ {
+ /* In general, don't install a subreg involving two
+ modes not tieable. It can worsen register
+ allocation, and can even make invalid reload
+ insns, since the reg inside may need to be copied
+ from in the outside mode, and that may be invalid
+ if it is an fp reg copied in integer mode.
+
+ We allow two exceptions to this: It is valid if
+ it is inside another SUBREG and the mode of that
+ SUBREG and the mode of the inside of TO is
+ tieable and it is valid if X is a SET that copies
+ FROM to CC0. */
+
+ if (GET_CODE (to) == SUBREG
+ && ! MODES_TIEABLE_P (GET_MODE (to),
+ GET_MODE (SUBREG_REG (to)))
+ && ! (code == SUBREG
+ && MODES_TIEABLE_P (GET_MODE (x),
+ GET_MODE (SUBREG_REG (to))))
#ifdef HAVE_cc0
- && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
+ && ! (code == SET && i == 1 && XEXP (x, 0) == cc0_rtx)
#endif
- )
- return gen_rtx (CLOBBER, VOIDmode, const0_rtx);
+ )
+ return gen_rtx_CLOBBER (VOIDmode, const0_rtx);
- new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
- n_occurrences++;
+ new = (unique_copy && n_occurrences ? copy_rtx (to) : to);
+ n_occurrences++;
+ }
+ else
+ /* If we are in a SET_DEST, suppress most cases unless we
+ have gone inside a MEM, in which case we want to
+ simplify the address. We assume here that things that
+ are actually part of the destination have their inner
+ parts in the first expression. This is true for SUBREG,
+ STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
+ things aside from REG and MEM that should appear in a
+ SET_DEST. */
+ new = subst (XEXP (x, i), from, to,
+ (((in_dest
+ && (code == SUBREG || code == STRICT_LOW_PART
+ || code == ZERO_EXTRACT))
+ || code == SET)
+ && i == 0), unique_copy);
+
+ /* If we found that we will have to reject this combination,
+ indicate that by returning the CLOBBER ourselves, rather than
+ an expression containing it. This will speed things up as
+ well as prevent accidents where two CLOBBERs are considered
+ to be equal, thus producing an incorrect simplification. */
+
+ if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
+ return new;
+
+ SUBST (XEXP (x, i), new);
}
- else
- /* If we are in a SET_DEST, suppress most cases unless we
- have gone inside a MEM, in which case we want to
- simplify the address. We assume here that things that
- are actually part of the destination have their inner
- parts in the first expression. This is true for SUBREG,
- STRICT_LOW_PART, and ZERO_EXTRACT, which are the only
- things aside from REG and MEM that should appear in a
- SET_DEST. */
- new = subst (XEXP (x, i), from, to,
- (((in_dest
- && (code == SUBREG || code == STRICT_LOW_PART
- || code == ZERO_EXTRACT))
- || code == SET)
- && i == 0), unique_copy);
-
- /* If we found that we will have to reject this combination,
- indicate that by returning the CLOBBER ourselves, rather than
- an expression containing it. This will speed things up as
- well as prevent accidents where two CLOBBERs are considered
- to be equal, thus producing an incorrect simplification. */
-
- if (GET_CODE (new) == CLOBBER && XEXP (new, 0) == const0_rtx)
- return new;
-
- SUBST (XEXP (x, i), new);
}
}
@@ -3052,7 +3337,12 @@ simplify_rtx (x, op0_mode, last, in_dest)
rtx cond, true, false;
cond = if_then_else_cond (x, &true, &false);
- if (cond != 0)
+ if (cond != 0
+ /* If everything is a comparison, what we have is highly unlikely
+ to be simpler, so don't use it. */
+ && ! (GET_RTX_CLASS (code) == '<'
+ && (GET_RTX_CLASS (GET_CODE (true)) == '<'
+ || GET_RTX_CLASS (GET_CODE (false)) == '<')))
{
rtx cop1 = const0_rtx;
enum rtx_code cond_code = simplify_comparison (NE, &cond, &cop1);
@@ -3089,9 +3379,10 @@ simplify_rtx (x, op0_mode, last, in_dest)
gen_binary (reverse_condition (cond_code),
mode, cond, cop1));
else
- return gen_rtx (IF_THEN_ELSE, mode,
- gen_binary (cond_code, VOIDmode, cond, cop1),
- true, false);
+ return gen_rtx_IF_THEN_ELSE (mode,
+ gen_binary (cond_code, VOIDmode,
+ cond, cop1),
+ true, false);
code = GET_CODE (x);
op0_mode = VOIDmode;
@@ -3207,7 +3498,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
if that would change the meaning of the address. */
if (MEM_VOLATILE_P (SUBREG_REG (x))
|| mode_dependent_address_p (XEXP (inner, 0)))
- return gen_rtx (CLOBBER, mode, const0_rtx);
+ return gen_rtx_CLOBBER (mode, const0_rtx);
if (BYTES_BIG_ENDIAN)
{
@@ -3219,10 +3510,10 @@ simplify_rtx (x, op0_mode, last, in_dest)
}
/* Note if the plus_constant doesn't make a valid address
then this combination won't be accepted. */
- x = gen_rtx (MEM, mode,
- plus_constant (XEXP (inner, 0),
- (SUBREG_WORD (x) * UNITS_PER_WORD
- + endian_offset)));
+ x = gen_rtx_MEM (mode,
+ plus_constant (XEXP (inner, 0),
+ (SUBREG_WORD (x) * UNITS_PER_WORD
+ + endian_offset)));
MEM_VOLATILE_P (x) = MEM_VOLATILE_P (inner);
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (inner);
MEM_IN_STRUCT_P (x) = MEM_IN_STRUCT_P (inner);
@@ -3264,10 +3555,10 @@ simplify_rtx (x, op0_mode, last, in_dest)
{
if (HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (x)) + SUBREG_WORD (x),
mode))
- return gen_rtx (REG, mode,
- REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
+ return gen_rtx_REG (mode,
+ REGNO (SUBREG_REG (x)) + SUBREG_WORD (x));
else
- return gen_rtx (CLOBBER, mode, const0_rtx);
+ return gen_rtx_CLOBBER (mode, const0_rtx);
}
/* For a constant, try to pick up the part we want. Handle a full
@@ -3277,7 +3568,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
if (CONSTANT_P (SUBREG_REG (x)) && op0_mode != VOIDmode
&& GET_MODE_SIZE (mode) == UNITS_PER_WORD
- && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD
+ && GET_MODE_SIZE (op0_mode) > UNITS_PER_WORD
&& GET_MODE_CLASS (mode) == MODE_INT)
{
temp = operand_subword (SUBREG_REG (x), SUBREG_WORD (x),
@@ -3289,9 +3580,17 @@ simplify_rtx (x, op0_mode, last, in_dest)
/* If we want a subreg of a constant, at offset 0,
take the low bits. On a little-endian machine, that's
always valid. On a big-endian machine, it's valid
- only if the constant's mode fits in one word. */
- if (CONSTANT_P (SUBREG_REG (x)) && subreg_lowpart_p (x)
- && GET_MODE_SIZE (mode) < GET_MODE_SIZE (op0_mode)
+ only if the constant's mode fits in one word. Note that we
+ cannot use subreg_lowpart_p since SUBREG_REG may be VOIDmode. */
+ if (CONSTANT_P (SUBREG_REG (x))
+ && ((GET_MODE_SIZE (op0_mode) <= UNITS_PER_WORD
+ || ! WORDS_BIG_ENDIAN)
+ ? SUBREG_WORD (x) == 0
+ : (SUBREG_WORD (x)
+ == ((GET_MODE_SIZE (op0_mode)
+ - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+ / UNITS_PER_WORD)))
+ && GET_MODE_SIZE (mode) <= GET_MODE_SIZE (op0_mode)
&& (! WORDS_BIG_ENDIAN
|| GET_MODE_BITSIZE (op0_mode) <= BITS_PER_WORD))
return gen_lowpart_for_combine (mode, SUBREG_REG (x));
@@ -3333,8 +3632,8 @@ simplify_rtx (x, op0_mode, last, in_dest)
but this doesn't seem common enough to bother with. */
if (GET_CODE (XEXP (x, 0)) == ASHIFT
&& XEXP (XEXP (x, 0), 0) == const1_rtx)
- return gen_rtx (ROTATE, mode, gen_unary (NOT, mode, mode, const1_rtx),
- XEXP (XEXP (x, 0), 1));
+ return gen_rtx_ROTATE (mode, gen_unary (NOT, mode, mode, const1_rtx),
+ XEXP (XEXP (x, 0), 1));
if (GET_CODE (XEXP (x, 0)) == SUBREG
&& subreg_lowpart_p (XEXP (x, 0))
@@ -3345,31 +3644,32 @@ simplify_rtx (x, op0_mode, last, in_dest)
{
enum machine_mode inner_mode = GET_MODE (SUBREG_REG (XEXP (x, 0)));
- x = gen_rtx (ROTATE, inner_mode,
- gen_unary (NOT, inner_mode, inner_mode, const1_rtx),
- XEXP (SUBREG_REG (XEXP (x, 0)), 1));
+ x = gen_rtx_ROTATE (inner_mode,
+ gen_unary (NOT, inner_mode, inner_mode,
+ const1_rtx),
+ XEXP (SUBREG_REG (XEXP (x, 0)), 1));
return gen_lowpart_for_combine (mode, x);
}
-#if STORE_FLAG_VALUE == -1
- /* (not (comparison foo bar)) can be done by reversing the comparison
- code if valid. */
- if (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+ /* If STORE_FLAG_VALUE is -1, (not (comparison foo bar)) can be done by
+ reversing the comparison code if valid. */
+ if (STORE_FLAG_VALUE == -1
+ && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
&& reversible_comparison_p (XEXP (x, 0)))
return gen_rtx_combine (reverse_condition (GET_CODE (XEXP (x, 0))),
mode, XEXP (XEXP (x, 0), 0),
XEXP (XEXP (x, 0), 1));
/* (ashiftrt foo C) where C is the number of bits in FOO minus 1
- is (lt foo (const_int 0)), so we can perform the above
- simplification. */
+ is (lt foo (const_int 0)) if STORE_FLAG_VALUE is -1, so we can
+ perform the above simplification. */
- if (XEXP (x, 1) == const1_rtx
+ if (STORE_FLAG_VALUE == -1
+ && XEXP (x, 1) == const1_rtx
&& GET_CODE (XEXP (x, 0)) == ASHIFTRT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (x, 0), 1)) == GET_MODE_BITSIZE (mode) - 1)
return gen_rtx_combine (GE, mode, XEXP (XEXP (x, 0), 0), const0_rtx);
-#endif
/* Apply De Morgan's laws to reduce number of patterns for machines
with negating logical insns (and-not, nand, etc.). If result has
@@ -3417,13 +3717,13 @@ simplify_rtx (x, op0_mode, last, in_dest)
/* (neg (minus X Y)) can become (minus Y X). */
if (GET_CODE (XEXP (x, 0)) == MINUS
&& (! FLOAT_MODE_P (mode)
- /* x-y != -(y-x) with IEEE floating point. */
+ /* x-y != -(y-x) with IEEE floating point. */
|| TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
|| flag_fast_math))
return gen_binary (MINUS, mode, XEXP (XEXP (x, 0), 1),
XEXP (XEXP (x, 0), 0));
- /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1. */
+ /* (neg (xor A 1)) is (plus A -1) if A is known to be either 0 or 1. */
if (GET_CODE (XEXP (x, 0)) == XOR && XEXP (XEXP (x, 0), 1) == const1_rtx
&& nonzero_bits (XEXP (XEXP (x, 0), 0), mode) == 1)
return gen_binary (PLUS, mode, XEXP (XEXP (x, 0), 0), constm1_rtx);
@@ -3484,10 +3784,66 @@ simplify_rtx (x, op0_mode, last, in_dest)
break;
case TRUNCATE:
- if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
+ /* We can't handle truncation to a partial integer mode here
+ because we don't know the real bitsize of the partial
+ integer mode. */
+ if (GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
+ break;
+
+ if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+ GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))))
SUBST (XEXP (x, 0),
force_to_mode (XEXP (x, 0), GET_MODE (XEXP (x, 0)),
GET_MODE_MASK (mode), NULL_RTX, 0));
+
+ /* (truncate:SI ({sign,zero}_extend:DI foo:SI)) == foo:SI. */
+ if ((GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
+ || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
+ && GET_MODE (XEXP (XEXP (x, 0), 0)) == mode)
+ return XEXP (XEXP (x, 0), 0);
+
+ /* (truncate:SI (OP:DI ({sign,zero}_extend:DI foo:SI))) is
+ (OP:SI foo:SI) if OP is NEG or ABS. */
+ if ((GET_CODE (XEXP (x, 0)) == ABS
+ || GET_CODE (XEXP (x, 0)) == NEG)
+ && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SIGN_EXTEND
+ || GET_CODE (XEXP (XEXP (x, 0), 0)) == ZERO_EXTEND)
+ && GET_MODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == mode)
+ return gen_unary (GET_CODE (XEXP (x, 0)), mode, mode,
+ XEXP (XEXP (XEXP (x, 0), 0), 0));
+
+ /* (truncate:SI (subreg:DI (truncate:SI X) 0)) is
+ (truncate:SI x). */
+ if (GET_CODE (XEXP (x, 0)) == SUBREG
+ && GET_CODE (SUBREG_REG (XEXP (x, 0))) == TRUNCATE
+ && subreg_lowpart_p (XEXP (x, 0)))
+ return SUBREG_REG (XEXP (x, 0));
+
+ /* If we know that the value is already truncated, we can
+ replace the TRUNCATE with a SUBREG. */
+ if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (XEXP (x, 0)))
+ >= GET_MODE_BITSIZE (mode) + 1)
+ return gen_lowpart_for_combine (mode, XEXP (x, 0));
+
+ /* A truncate of a comparison can be replaced with a subreg if
+ STORE_FLAG_VALUE permits. This is like the previous test,
+ but it works even if the comparison is done in a mode larger
+ than HOST_BITS_PER_WIDE_INT. */
+ if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+ && ((HOST_WIDE_INT) STORE_FLAG_VALUE &~ GET_MODE_MASK (mode)) == 0)
+ return gen_lowpart_for_combine (mode, XEXP (x, 0));
+
+ /* Similarly, a truncate of a register whose value is a
+ comparison can be replaced with a subreg if STORE_FLAG_VALUE
+ permits. */
+ if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && ((HOST_WIDE_INT) STORE_FLAG_VALUE &~ GET_MODE_MASK (mode)) == 0
+ && (temp = get_last_value (XEXP (x, 0)))
+ && GET_RTX_CLASS (GET_CODE (temp)) == '<')
+ return gen_lowpart_for_combine (mode, XEXP (x, 0));
+
break;
case FLOAT_TRUNCATE:
@@ -3627,16 +3983,15 @@ simplify_rtx (x, op0_mode, last, in_dest)
break;
case MINUS:
-#if STORE_FLAG_VALUE == 1
- /* (minus 1 (comparison foo bar)) can be done by reversing the comparison
- code if valid. */
- if (XEXP (x, 0) == const1_rtx
+ /* If STORE_FLAG_VALUE is 1, (minus 1 (comparison foo bar)) can be done
+ by reversing the comparison code if valid. */
+ if (STORE_FLAG_VALUE == 1
+ && XEXP (x, 0) == const1_rtx
&& GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<'
&& reversible_comparison_p (XEXP (x, 1)))
return gen_binary (reverse_condition (GET_CODE (XEXP (x, 1))),
mode, XEXP (XEXP (x, 1), 0),
XEXP (XEXP (x, 1), 1));
-#endif
/* (minus <foo> (and <foo> (const_int -pow2))) becomes
(and <foo> (const_int pow2-1)) */
@@ -3710,7 +4065,6 @@ simplify_rtx (x, op0_mode, last, in_dest)
/* Simplify our comparison, if possible. */
new_code = simplify_comparison (code, &op0, &op1);
-#if STORE_FLAG_VALUE == 1
/* If STORE_FLAG_VALUE is 1, we can convert (ne x 0) to simply X
if only the low-order bit is possibly nonzero in X (such as when
X is a ZERO_EXTRACT of one bit). Similarly, we can convert EQ to
@@ -3723,13 +4077,14 @@ simplify_rtx (x, op0_mode, last, in_dest)
ZERO_EXTRACT is indeed appropriate, it will be placed back by
the call to make_compound_operation in the SET case. */
- if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
- && op1 == const0_rtx
- && nonzero_bits (op0, mode) == 1)
+ if (STORE_FLAG_VALUE == 1
+ && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+ && op1 == const0_rtx && nonzero_bits (op0, mode) == 1)
return gen_lowpart_for_combine (mode,
expand_compound_operation (op0));
- else if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
@@ -3739,7 +4094,8 @@ simplify_rtx (x, op0_mode, last, in_dest)
gen_lowpart_for_combine (mode, op0));
}
- else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& nonzero_bits (op0, mode) == 1)
{
@@ -3749,7 +4105,8 @@ simplify_rtx (x, op0_mode, last, in_dest)
const1_rtx);
}
- else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
@@ -3757,19 +4114,19 @@ simplify_rtx (x, op0_mode, last, in_dest)
op0 = expand_compound_operation (op0);
return plus_constant (gen_lowpart_for_combine (mode, op0), 1);
}
-#endif
-#if STORE_FLAG_VALUE == -1
/* If STORE_FLAG_VALUE is -1, we have cases similar to
those above. */
- if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+ if (STORE_FLAG_VALUE == -1
+ && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
return gen_lowpart_for_combine (mode,
expand_compound_operation (op0));
- else if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == -1
+ && new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& nonzero_bits (op0, mode) == 1)
{
@@ -3778,7 +4135,8 @@ simplify_rtx (x, op0_mode, last, in_dest)
gen_lowpart_for_combine (mode, op0));
}
- else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == -1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& (num_sign_bit_copies (op0, mode)
== GET_MODE_BITSIZE (mode)))
@@ -3789,14 +4147,14 @@ simplify_rtx (x, op0_mode, last, in_dest)
}
/* If X is 0/1, (eq X 0) is X-1. */
- else if (new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+ else if (STORE_FLAG_VALUE == -1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
&& op1 == const0_rtx
&& nonzero_bits (op0, mode) == 1)
{
op0 = expand_compound_operation (op0);
return plus_constant (gen_lowpart_for_combine (mode, op0), -1);
}
-#endif
/* If STORE_FLAG_VALUE says to just test the sign bit and X has just
one bit that might be nonzero, we can convert (ne x 0) to
@@ -3805,7 +4163,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
going to test the sign bit. */
if (new_code == NE && GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (STORE_FLAG_VALUE
+ && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
== (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
&& op1 == const0_rtx
&& mode == GET_MODE (op0)
@@ -3838,7 +4196,7 @@ simplify_rtx (x, op0_mode, last, in_dest)
case SIGN_EXTRACT:
case ZERO_EXTEND:
case SIGN_EXTEND:
- /* If we are processing SET_DEST, we are done. */
+ /* If we are processing SET_DEST, we are done. */
if (in_dest)
return x;
@@ -3852,11 +4210,16 @@ simplify_rtx (x, op0_mode, last, in_dest)
case XOR:
return simplify_logical (x, last);
- case ABS:
+ case ABS:
/* (abs (neg <foo>)) -> (abs <foo>) */
if (GET_CODE (XEXP (x, 0)) == NEG)
SUBST (XEXP (x, 0), XEXP (XEXP (x, 0), 0));
+ /* If the mode of the operand is VOIDmode (i.e. if it is ASM_OPERANDS),
+ do nothing. */
+ if (GET_MODE (XEXP (x, 0)) == VOIDmode)
+ break;
+
/* If operand is something known to be positive, ignore the ABS. */
if (GET_CODE (XEXP (x, 0)) == FFS || GET_CODE (XEXP (x, 0)) == ABS
|| ((GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
@@ -3908,6 +4271,9 @@ simplify_rtx (x, op0_mode, last, in_dest)
#endif
break;
+
+ default:
+ break;
}
return x;
@@ -3928,11 +4294,11 @@ simplify_if_then_else (x)
rtx temp;
int i;
- /* Simplify storing of the truth value. */
+ /* Simplify storing of the truth value. */
if (comparison_p && true == const_true_rtx && false == const0_rtx)
return gen_binary (true_code, mode, XEXP (cond, 0), XEXP (cond, 1));
- /* Also when the truth value has to be reversed. */
+ /* Also when the truth value has to be reversed. */
if (comparison_p && reversible_comparison_p (cond)
&& true == const0_rtx && false == const_true_rtx)
return gen_binary (reverse_condition (true_code),
@@ -4018,6 +4384,10 @@ simplify_if_then_else (x)
SUBST (XEXP (x, 2), true);
temp = true, true = false, false = temp, cond = XEXP (x, 0);
+
+ /* It is possible that the conditional has been simplified out. */
+ true_code = GET_CODE (cond);
+ comparison_p = GET_RTX_CLASS (true_code) == '<';
}
/* If the two arms are identical, we don't need the comparison. */
@@ -4025,6 +4395,16 @@ simplify_if_then_else (x)
if (rtx_equal_p (true, false) && ! side_effects_p (cond))
return true;
+ /* Convert a == b ? b : a to "a". */
+ if (true_code == EQ && ! side_effects_p (cond)
+ && rtx_equal_p (XEXP (cond, 0), false)
+ && rtx_equal_p (XEXP (cond, 1), true))
+ return false;
+ else if (true_code == NE && ! side_effects_p (cond)
+ && rtx_equal_p (XEXP (cond, 0), true)
+ && rtx_equal_p (XEXP (cond, 1), false))
+ return true;
+
/* Look for cases where we have (abs x) or (neg (abs X)). */
if (GET_MODE_CLASS (mode) == MODE_INT
@@ -4041,6 +4421,8 @@ simplify_if_then_else (x)
case LT:
case LE:
return gen_unary (NEG, mode, mode, gen_unary (ABS, mode, mode, true));
+ default:
+ break;
}
/* Look for MIN or MAX. */
@@ -4064,18 +4446,19 @@ simplify_if_then_else (x)
case LEU:
case LTU:
return gen_binary (UMIN, mode, true, false);
+ default:
+ break;
}
-#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
-
/* If we have (if_then_else COND (OP Z C1) Z) and OP is an identity when its
second operand is zero, this can be done as (OP Z (mult COND C2)) where
C2 = C1 * STORE_FLAG_VALUE. Similarly if OP has an outer ZERO_EXTEND or
SIGN_EXTEND as long as Z is already extended (so we don't destroy it).
We can do this kind of thing in some cases when STORE_FLAG_VALUE is
- neither of the above, but it isn't worth checking for. */
+ neither 1 or -1, but it isn't worth checking for. */
- if (comparison_p && mode != VOIDmode && ! side_effects_p (x))
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && comparison_p && mode != VOIDmode && ! side_effects_p (x))
{
rtx t = make_compound_operation (true, SET);
rtx f = make_compound_operation (false, SET);
@@ -4093,7 +4476,7 @@ simplify_if_then_else (x)
c1 = XEXP (t, 1), op = GET_CODE (t), z = f;
/* If an identity-zero op is commutative, check whether there
- would be a match if we swapped the operands. */
+ would be a match if we swapped the operands. */
else if ((GET_CODE (t) == PLUS || GET_CODE (t) == IOR
|| GET_CODE (t) == XOR)
&& rtx_equal_p (XEXP (t, 1), f))
@@ -4184,7 +4567,6 @@ simplify_if_then_else (x)
return temp;
}
}
-#endif
/* If we have (if_then_else (ne A 0) C1 0) and either A is known to be 0 or
1 and C1 is a single bit or A is known to be 0 or -1 and C1 is the
@@ -4271,10 +4653,10 @@ simplify_set (x)
if (compare_mode != GET_MODE (dest))
{
int regno = REGNO (dest);
- rtx new_dest = gen_rtx (REG, compare_mode, regno);
+ rtx new_dest = gen_rtx_REG (compare_mode, regno);
if (regno < FIRST_PSEUDO_REGISTER
- || (reg_n_sets[regno] == 1 && ! REG_USERVAR_P (dest)))
+ || (REG_N_SETS (regno) == 1 && ! REG_USERVAR_P (dest)))
{
if (regno >= FIRST_PSEUDO_REGISTER)
SUBST (regno_reg_rtx[regno], new_dest);
@@ -4370,7 +4752,7 @@ simplify_set (x)
we only care about the low bits of the result.
However, on machines without WORD_REGISTER_OPERATIONS defined, we cannot
- perform a narrower operation that requested since the high-order bits will
+ perform a narrower operation than requested since the high-order bits will
be undefined. On machine where it is defined, this transformation is safe
as long as M1 and M2 have the same number of words. */
@@ -4407,7 +4789,7 @@ simplify_set (x)
#ifdef LOAD_EXTEND_OP
/* If we have (set FOO (subreg:M (mem:N BAR) 0)) with M wider than N, this
would require a paradoxical subreg. Replace the subreg with a
- zero_extend to avoid the reload that would otherwise be required. */
+ zero_extend to avoid the reload that would otherwise be required. */
if (GET_CODE (src) == SUBREG && subreg_lowpart_p (src)
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (src))) != NIL
@@ -4535,7 +4917,7 @@ simplify_logical (x, last)
/* If we have (ior (and (X C1) C2)) and the next restart would be
the last, simplify this by making C1 as small as possible
- and then exit. */
+ and then exit. */
if (last
&& GET_CODE (x) == IOR && GET_CODE (op0) == AND
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
@@ -4658,9 +5040,9 @@ simplify_logical (x, last)
&& GET_CODE (XEXP (op1, 1)) == CONST_INT
&& (INTVAL (XEXP (op0, 1)) + INTVAL (XEXP (op1, 1))
== GET_MODE_BITSIZE (mode)))
- return gen_rtx (ROTATE, mode, XEXP (op0, 0),
- (GET_CODE (op0) == ASHIFT
- ? XEXP (op0, 1) : XEXP (op1, 1)));
+ return gen_rtx_ROTATE (mode, XEXP (op0, 0),
+ (GET_CODE (op0) == ASHIFT
+ ? XEXP (op0, 1) : XEXP (op1, 1)));
/* If OP0 is (ashiftrt (plus ...) C), it might actually be
a (sign_extend (plus ...)). If so, OP1 is a CONST_INT, and the PLUS
@@ -4725,10 +5107,10 @@ simplify_logical (x, last)
gen_unary (NOT, mode, mode, XEXP (op0, 1)),
op1);
-#if STORE_FLAG_VALUE == 1
/* (xor (comparison foo bar) (const_int 1)) can become the reversed
- comparison. */
- if (op1 == const1_rtx
+ comparison if STORE_FLAG_VALUE is 1. */
+ if (STORE_FLAG_VALUE == 1
+ && op1 == const1_rtx
&& GET_RTX_CLASS (GET_CODE (op0)) == '<'
&& reversible_comparison_p (op0))
return gen_rtx_combine (reverse_condition (GET_CODE (op0)),
@@ -4736,19 +5118,19 @@ simplify_logical (x, last)
/* (lshiftrt foo C) where C is the number of bits in FOO minus 1
is (lt foo (const_int 0)), so we can perform the above
- simplification. */
+ simplification if STORE_FLAG_VALUE is 1. */
- if (op1 == const1_rtx
+ if (STORE_FLAG_VALUE == 1
+ && op1 == const1_rtx
&& GET_CODE (op0) == LSHIFTRT
&& GET_CODE (XEXP (op0, 1)) == CONST_INT
&& INTVAL (XEXP (op0, 1)) == GET_MODE_BITSIZE (mode) - 1)
return gen_rtx_combine (GE, mode, XEXP (op0, 0), const0_rtx);
-#endif
/* (xor (comparison foo bar) (const_int sign-bit))
when STORE_FLAG_VALUE is the sign bit. */
if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (STORE_FLAG_VALUE
+ && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
== (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1))
&& op1 == const_true_rtx
&& GET_RTX_CLASS (GET_CODE (op0)) == '<'
@@ -4756,6 +5138,9 @@ simplify_logical (x, last)
return gen_rtx_combine (reverse_condition (GET_CODE (op0)),
mode, XEXP (op0, 0), XEXP (op0, 1));
break;
+
+ default:
+ abort ();
}
return x;
@@ -4839,7 +5224,7 @@ expand_compound_operation (x)
with a (use (mem ...)) construct that only combine understands
and is used only for this purpose. */
if (len + pos > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
- SUBST (XEXP (x, 0), gen_rtx (USE, GET_MODE (x), XEXP (x, 0)));
+ SUBST (XEXP (x, 0), gen_rtx_USE (GET_MODE (x), XEXP (x, 0)));
if (BITS_BIG_ENDIAN)
pos = GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - len - pos;
@@ -4850,6 +5235,78 @@ expand_compound_operation (x)
return x;
}
+ /* We can optimize some special cases of ZERO_EXTEND. */
+ if (GET_CODE (x) == ZERO_EXTEND)
+ {
+ /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI if we
+ know that the last value didn't have any inappropriate bits
+ set. */
+ if (GET_CODE (XEXP (x, 0)) == TRUNCATE
+ && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
+ && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (XEXP (XEXP (x, 0), 0), GET_MODE (x))
+ & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+ return XEXP (XEXP (x, 0), 0);
+
+ /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)). */
+ if (GET_CODE (XEXP (x, 0)) == SUBREG
+ && GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x)
+ && subreg_lowpart_p (XEXP (x, 0))
+ && GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (SUBREG_REG (XEXP (x, 0)), GET_MODE (x))
+ & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+ return SUBREG_REG (XEXP (x, 0));
+
+ /* (zero_extend:DI (truncate:SI foo:DI)) is just foo:DI when foo
+ is a comparison and STORE_FLAG_VALUE permits. This is like
+ the first case, but it works even when GET_MODE (x) is larger
+ than HOST_WIDE_INT. */
+ if (GET_CODE (XEXP (x, 0)) == TRUNCATE
+ && GET_MODE (XEXP (XEXP (x, 0), 0)) == GET_MODE (x)
+ && GET_RTX_CLASS (GET_CODE (XEXP (XEXP (x, 0), 0))) == '<'
+ && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+ <= HOST_BITS_PER_WIDE_INT)
+ && ((HOST_WIDE_INT) STORE_FLAG_VALUE
+ & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+ return XEXP (XEXP (x, 0), 0);
+
+ /* Likewise for (zero_extend:DI (subreg:SI foo:DI 0)). */
+ if (GET_CODE (XEXP (x, 0)) == SUBREG
+ && GET_MODE (SUBREG_REG (XEXP (x, 0))) == GET_MODE (x)
+ && subreg_lowpart_p (XEXP (x, 0))
+ && GET_RTX_CLASS (GET_CODE (SUBREG_REG (XEXP (x, 0)))) == '<'
+ && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+ <= HOST_BITS_PER_WIDE_INT)
+ && ((HOST_WIDE_INT) STORE_FLAG_VALUE
+ & ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0)))) == 0)
+ return SUBREG_REG (XEXP (x, 0));
+
+ /* If sign extension is cheaper than zero extension, then use it
+ if we know that no extraneous bits are set, and that the high
+ bit is not set. */
+ if (flag_expensive_optimizations
+ && ((GET_MODE_BITSIZE (GET_MODE (x)) <= HOST_BITS_PER_WIDE_INT
+ && ((nonzero_bits (XEXP (x, 0), GET_MODE (x))
+ & ~ (((unsigned HOST_WIDE_INT)
+ GET_MODE_MASK (GET_MODE (XEXP (x, 0))))
+ >> 1))
+ == 0))
+ || (GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+ && (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
+ <= HOST_BITS_PER_WIDE_INT)
+ && (((HOST_WIDE_INT) STORE_FLAG_VALUE
+ & ~ (((unsigned HOST_WIDE_INT)
+ GET_MODE_MASK (GET_MODE (XEXP (x, 0))))
+ >> 1))
+ == 0))))
+ {
+ rtx temp = gen_rtx_SIGN_EXTEND (GET_MODE (x), XEXP (x, 0));
+
+ if (rtx_cost (temp, SET) < rtx_cost (x, SET))
+ return expand_compound_operation (temp);
+ }
+ }
+
/* If we reach here, we want to return a pair of shifts. The inner
shift is a left shift of BITSIZE - POS - LEN bits. The outer
shift is a right shift of BITSIZE - LEN bits. It is arithmetic or
@@ -4907,7 +5364,7 @@ expand_field_assignment (x)
rtx x;
{
rtx inner;
- rtx pos; /* Always counts from low bit. */
+ rtx pos; /* Always counts from low bit. */
int len;
rtx mask;
enum machine_mode compute_mode;
@@ -4920,7 +5377,7 @@ expand_field_assignment (x)
{
inner = SUBREG_REG (XEXP (SET_DEST (x), 0));
len = GET_MODE_BITSIZE (GET_MODE (XEXP (SET_DEST (x), 0)));
- pos = const0_rtx;
+ pos = GEN_INT (BITS_PER_WORD * SUBREG_WORD (XEXP (SET_DEST (x), 0)));
}
else if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
&& GET_CODE (XEXP (SET_DEST (x), 1)) == CONST_INT)
@@ -4933,7 +5390,7 @@ expand_field_assignment (x)
surround INNER with a USE to indicate this. */
if (GET_CODE (pos) == CONST_INT
&& INTVAL (pos) + len > GET_MODE_BITSIZE (GET_MODE (inner)))
- inner = gen_rtx (USE, GET_MODE (SET_DEST (x)), inner);
+ inner = gen_rtx_USE (GET_MODE (SET_DEST (x)), inner);
if (BITS_BIG_ENDIAN)
{
@@ -4962,9 +5419,9 @@ expand_field_assignment (x)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (SET_DEST (x))))
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
{
- x = gen_rtx (SET, VOIDmode, SUBREG_REG (SET_DEST (x)),
- gen_lowpart_for_combine (GET_MODE (SUBREG_REG (SET_DEST (x))),
- SET_SRC (x)));
+ x = gen_rtx_SET (VOIDmode, SUBREG_REG (SET_DEST (x)),
+ gen_lowpart_for_combine (GET_MODE (SUBREG_REG (SET_DEST (x))),
+ SET_SRC (x)));
continue;
}
else
@@ -4984,22 +5441,22 @@ expand_field_assignment (x)
/* Now compute the equivalent expression. Make a copy of INNER
for the SET_DEST in case it is a MEM into which we will substitute;
we don't want shared RTL in that case. */
- x = gen_rtx (SET, VOIDmode, copy_rtx (inner),
- gen_binary (IOR, compute_mode,
- gen_binary (AND, compute_mode,
- gen_unary (NOT, compute_mode,
- compute_mode,
- gen_binary (ASHIFT,
- compute_mode,
- mask, pos)),
- inner),
- gen_binary (ASHIFT, compute_mode,
- gen_binary (AND, compute_mode,
- gen_lowpart_for_combine
- (compute_mode,
- SET_SRC (x)),
- mask),
- pos)));
+ x = gen_rtx_SET (VOIDmode, copy_rtx (inner),
+ gen_binary (IOR, compute_mode,
+ gen_binary (AND, compute_mode,
+ gen_unary (NOT, compute_mode,
+ compute_mode,
+ gen_binary (ASHIFT,
+ compute_mode,
+ mask, pos)),
+ inner),
+ gen_binary (ASHIFT, compute_mode,
+ gen_binary (AND, compute_mode,
+ gen_lowpart_for_combine
+ (compute_mode,
+ SET_SRC (x)),
+ mask),
+ pos)));
}
return x;
@@ -5027,7 +5484,10 @@ expand_field_assignment (x)
IN_COMPARE is non-zero if we are in a COMPARE. This means that a
ZERO_EXTRACT should be built even for bits starting at bit 0.
- MODE is the desired mode of the result (if IN_DEST == 0). */
+ MODE is the desired mode of the result (if IN_DEST == 0).
+
+ The result is an RTX for the extraction or NULL_RTX if the target
+ can't handle it. */
static rtx
make_extraction (mode, inner, pos, pos_rtx, len,
@@ -5045,7 +5505,8 @@ make_extraction (mode, inner, pos, pos_rtx, len,
ignore the POS lowest bits, etc. */
enum machine_mode is_mode = GET_MODE (inner);
enum machine_mode inner_mode;
- enum machine_mode wanted_mem_mode = byte_mode;
+ enum machine_mode wanted_inner_mode = byte_mode;
+ enum machine_mode wanted_inner_reg_mode = word_mode;
enum machine_mode pos_mode = word_mode;
enum machine_mode extraction_mode = word_mode;
enum machine_mode tmode = mode_for_size (len, MODE_INT, 1);
@@ -5092,7 +5553,8 @@ make_extraction (mode, inner, pos, pos_rtx, len,
if (tmode != BLKmode
&& ! (spans_byte && inner_mode != tmode)
- && ((pos_rtx == 0 && pos == 0 && GET_CODE (inner) != MEM
+ && ((pos_rtx == 0 && (pos % BITS_PER_WORD) == 0
+ && GET_CODE (inner) != MEM
&& (! in_dest
|| (GET_CODE (inner) == REG
&& (movstrict_optab->handlers[(int) tmode].insn_code
@@ -5112,8 +5574,8 @@ make_extraction (mode, inner, pos, pos_rtx, len,
field. If the original and current mode are the same, we need not
adjust the offset. Otherwise, we do if bytes big endian.
- If INNER is not a MEM, get a piece consisting of the just the field
- of interest (in this case POS must be 0). */
+ If INNER is not a MEM, get a piece consisting of just the field
+ of interest (in this case POS % BITS_PER_WORD must be 0). */
if (GET_CODE (inner) == MEM)
{
@@ -5124,7 +5586,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
else
offset = pos / BITS_PER_UNIT;
- new = gen_rtx (MEM, tmode, plus_constant (XEXP (inner, 0), offset));
+ new = gen_rtx_MEM (tmode, plus_constant (XEXP (inner, 0), offset));
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (inner);
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (inner);
MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (inner);
@@ -5134,13 +5596,14 @@ make_extraction (mode, inner, pos, pos_rtx, len,
/* We can't call gen_lowpart_for_combine here since we always want
a SUBREG and it would sometimes return a new hard register. */
if (tmode != inner_mode)
- new = gen_rtx (SUBREG, tmode, inner,
- (WORDS_BIG_ENDIAN
- && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD
- ? ((GET_MODE_SIZE (inner_mode)
- - GET_MODE_SIZE (tmode))
- / UNITS_PER_WORD)
- : 0));
+ new = gen_rtx_SUBREG (tmode, inner,
+ (WORDS_BIG_ENDIAN
+ && GET_MODE_SIZE (inner_mode) > UNITS_PER_WORD
+ ? (((GET_MODE_SIZE (inner_mode)
+ - GET_MODE_SIZE (tmode))
+ / UNITS_PER_WORD)
+ - pos / BITS_PER_WORD)
+ : pos / BITS_PER_WORD));
else
new = inner;
}
@@ -5157,7 +5620,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
if (in_dest)
return (GET_CODE (new) == MEM ? new
: (GET_CODE (new) != SUBREG
- ? gen_rtx (CLOBBER, tmode, const0_rtx)
+ ? gen_rtx_CLOBBER (tmode, const0_rtx)
: gen_rtx_combine (STRICT_LOW_PART, VOIDmode, new)));
/* Otherwise, sign- or zero-extend unless we already are in the
@@ -5185,12 +5648,12 @@ make_extraction (mode, inner, pos, pos_rtx, len,
|| (pos_rtx != 0 && len != 1)))
return 0;
- /* Get the mode to use should INNER be a MEM, the mode for the position,
+ /* Get the mode to use should INNER not be a MEM, the mode for the position,
and the mode for the result. */
#ifdef HAVE_insv
if (in_dest)
{
- wanted_mem_mode = insn_operand_mode[(int) CODE_FOR_insv][0];
+ wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_insv][0];
pos_mode = insn_operand_mode[(int) CODE_FOR_insv][2];
extraction_mode = insn_operand_mode[(int) CODE_FOR_insv][3];
}
@@ -5199,7 +5662,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
#ifdef HAVE_extzv
if (! in_dest && unsignedp)
{
- wanted_mem_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
+ wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_extzv][1];
pos_mode = insn_operand_mode[(int) CODE_FOR_extzv][3];
extraction_mode = insn_operand_mode[(int) CODE_FOR_extzv][0];
}
@@ -5208,7 +5671,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
#ifdef HAVE_extv
if (! in_dest && ! unsignedp)
{
- wanted_mem_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
+ wanted_inner_reg_mode = insn_operand_mode[(int) CODE_FOR_extv][1];
pos_mode = insn_operand_mode[(int) CODE_FOR_extv][3];
extraction_mode = insn_operand_mode[(int) CODE_FOR_extv][0];
}
@@ -5224,40 +5687,48 @@ make_extraction (mode, inner, pos, pos_rtx, len,
&& GET_MODE_SIZE (pos_mode) < GET_MODE_SIZE (GET_MODE (pos_rtx)))
pos_mode = GET_MODE (pos_rtx);
- /* If this is not from memory or we have to change the mode of memory and
- cannot, the desired mode is EXTRACTION_MODE. */
- if (GET_CODE (inner) != MEM
- || (inner_mode != wanted_mem_mode
- && (mode_dependent_address_p (XEXP (inner, 0))
- || MEM_VOLATILE_P (inner))))
- wanted_mem_mode = extraction_mode;
+ /* If this is not from memory, the desired mode is wanted_inner_reg_mode;
+ if we have to change the mode of memory and cannot, the desired mode is
+ EXTRACTION_MODE. */
+ if (GET_CODE (inner) != MEM)
+ wanted_inner_mode = wanted_inner_reg_mode;
+ else if (inner_mode != wanted_inner_mode
+ && (mode_dependent_address_p (XEXP (inner, 0))
+ || MEM_VOLATILE_P (inner)))
+ wanted_inner_mode = extraction_mode;
orig_pos = pos;
if (BITS_BIG_ENDIAN)
{
- /* If position is constant, compute new position. Otherwise,
- build subtraction. */
+ /* POS is passed as if BITS_BIG_ENDIAN == 0, so we need to convert it to
+ BITS_BIG_ENDIAN style. If position is constant, compute new
+ position. Otherwise, build subtraction.
+ Note that POS is relative to the mode of the original argument.
+ If it's a MEM we need to recompute POS relative to that.
+ However, if we're extracting from (or inserting into) a register,
+ we want to recompute POS relative to wanted_inner_mode. */
+ int width = (GET_CODE (inner) == MEM
+ ? GET_MODE_BITSIZE (is_mode)
+ : GET_MODE_BITSIZE (wanted_inner_mode));
+
if (pos_rtx == 0)
- pos = (MAX (GET_MODE_BITSIZE (is_mode),
- GET_MODE_BITSIZE (wanted_mem_mode))
- - len - pos);
+ pos = width - len - pos;
else
pos_rtx
= gen_rtx_combine (MINUS, GET_MODE (pos_rtx),
- GEN_INT (MAX (GET_MODE_BITSIZE (is_mode),
- GET_MODE_BITSIZE (wanted_mem_mode))
- - len),
- pos_rtx);
+ GEN_INT (width - len), pos_rtx);
+ /* POS may be less than 0 now, but we check for that below.
+ Note that it can only be less than 0 if GET_CODE (inner) != MEM. */
}
/* If INNER has a wider mode, make it smaller. If this is a constant
extract, try to adjust the byte to point to the byte containing
the value. */
- if (wanted_mem_mode != VOIDmode
- && GET_MODE_SIZE (wanted_mem_mode) < GET_MODE_SIZE (is_mode)
+ if (wanted_inner_mode != VOIDmode
+ && GET_MODE_SIZE (wanted_inner_mode) < GET_MODE_SIZE (is_mode)
&& ((GET_CODE (inner) == MEM
- && (inner_mode == wanted_mem_mode
+ && (inner_mode == wanted_inner_mode
|| (! mode_dependent_address_p (XEXP (inner, 0))
&& ! MEM_VOLATILE_P (inner))))))
{
@@ -5268,7 +5739,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
If it is mixed, we must adjust. */
/* If bytes are big endian and we had a paradoxical SUBREG, we must
- adjust OFFSET to compensate. */
+ adjust OFFSET to compensate. */
if (BYTES_BIG_ENDIAN
&& ! spans_byte
&& GET_MODE_SIZE (inner_mode) < GET_MODE_SIZE (is_mode))
@@ -5278,19 +5749,19 @@ make_extraction (mode, inner, pos, pos_rtx, len,
if (pos_rtx == 0)
{
offset += pos / BITS_PER_UNIT;
- pos %= GET_MODE_BITSIZE (wanted_mem_mode);
+ pos %= GET_MODE_BITSIZE (wanted_inner_mode);
}
if (BYTES_BIG_ENDIAN != BITS_BIG_ENDIAN
&& ! spans_byte
- && is_mode != wanted_mem_mode)
+ && is_mode != wanted_inner_mode)
offset = (GET_MODE_SIZE (is_mode)
- - GET_MODE_SIZE (wanted_mem_mode) - offset);
+ - GET_MODE_SIZE (wanted_inner_mode) - offset);
- if (offset != 0 || inner_mode != wanted_mem_mode)
+ if (offset != 0 || inner_mode != wanted_inner_mode)
{
- rtx newmem = gen_rtx (MEM, wanted_mem_mode,
- plus_constant (XEXP (inner, 0), offset));
+ rtx newmem = gen_rtx_MEM (wanted_inner_mode,
+ plus_constant (XEXP (inner, 0), offset));
RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (inner);
MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (inner);
MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (inner);
@@ -5298,13 +5769,23 @@ make_extraction (mode, inner, pos, pos_rtx, len,
}
}
- /* If INNER is not memory, we can always get it into the proper mode. */
+ /* If INNER is not memory, we can always get it into the proper mode. If we
+ are changing its mode, POS must be a constant and smaller than the size
+ of the new mode. */
else if (GET_CODE (inner) != MEM)
- inner = force_to_mode (inner, extraction_mode,
- pos_rtx || len + orig_pos >= HOST_BITS_PER_WIDE_INT
- ? GET_MODE_MASK (extraction_mode)
- : (((HOST_WIDE_INT) 1 << len) - 1) << orig_pos,
- NULL_RTX, 0);
+ {
+ if (GET_MODE (inner) != wanted_inner_mode
+ && (pos_rtx != 0
+ || orig_pos + len > GET_MODE_BITSIZE (wanted_inner_mode)))
+ return 0;
+
+ inner = force_to_mode (inner, wanted_inner_mode,
+ pos_rtx
+ || len + orig_pos >= HOST_BITS_PER_WIDE_INT
+ ? GET_MODE_MASK (wanted_inner_mode)
+ : (((HOST_WIDE_INT) 1 << len) - 1) << orig_pos,
+ NULL_RTX, 0);
+ }
/* Adjust mode of POS_RTX, if needed. If we want a wider mode, we
have to zero extend. Otherwise, we can just use a SUBREG. */
@@ -5317,7 +5798,7 @@ make_extraction (mode, inner, pos, pos_rtx, len,
/* Make POS_RTX unless we already have it and it is correct. If we don't
have a POS_RTX but we do have an ORIG_POS_RTX, the latter must
- be a CONST_INT. */
+ be a CONST_INT. */
if (pos_rtx == 0 && orig_pos_rtx != 0 && INTVAL (orig_pos_rtx) == pos)
pos_rtx = orig_pos_rtx;
@@ -5367,12 +5848,15 @@ extract_left_shift (x, count)
/* If we can safely shift this constant and we find the inner shift,
make a new operation. */
if (GET_CODE (XEXP (x,1)) == CONST_INT
- && (INTVAL (XEXP (x, 1)) & (((HOST_WIDE_INT) 1 << count)) - 1) == 0
+ && (INTVAL (XEXP (x, 1)) & ((((HOST_WIDE_INT) 1 << count)) - 1)) == 0
&& (tem = extract_left_shift (XEXP (x, 0), count)) != 0)
return gen_binary (code, mode, tem,
GEN_INT (INTVAL (XEXP (x, 1)) >> count));
break;
+
+ default:
+ break;
}
return 0;
@@ -5476,10 +5960,10 @@ make_compound_operation (x, in_code)
{
/* Apply the distributive law, and then try to make extractions. */
new = gen_rtx_combine (GET_CODE (XEXP (x, 0)), mode,
- gen_rtx (AND, mode, XEXP (XEXP (x, 0), 0),
- XEXP (x, 1)),
- gen_rtx (AND, mode, XEXP (XEXP (x, 0), 1),
- XEXP (x, 1)));
+ gen_rtx_AND (mode, XEXP (XEXP (x, 0), 0),
+ XEXP (x, 1)),
+ gen_rtx_AND (mode, XEXP (XEXP (x, 0), 1),
+ XEXP (x, 1)));
new = make_compound_operation (new, in_code);
}
@@ -5557,7 +6041,7 @@ make_compound_operation (x, in_code)
break;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case ASHIFTRT:
lhs = XEXP (x, 0);
@@ -5614,6 +6098,27 @@ make_compound_operation (x, in_code)
return newer;
}
+
+ /* If this is a paradoxical subreg, and the new code is a sign or
+ zero extension, omit the subreg and widen the extension. If it
+ is a regular subreg, we can still get rid of the subreg by not
+ widening so much, or in fact removing the extension entirely. */
+ if ((GET_CODE (tem) == SIGN_EXTEND
+ || GET_CODE (tem) == ZERO_EXTEND)
+ && subreg_lowpart_p (x))
+ {
+ if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (tem))
+ || (GET_MODE_SIZE (mode) >
+ GET_MODE_SIZE (GET_MODE (XEXP (tem, 0)))))
+ tem = gen_rtx_combine (GET_CODE (tem), mode, XEXP (tem, 0));
+ else
+ tem = gen_lowpart_for_combine (mode, XEXP (tem, 0));
+ return tem;
+ }
+ break;
+
+ default:
+ break;
}
if (new)
@@ -5692,9 +6197,13 @@ force_to_mode (x, mode, mask, reg, just_select)
unsigned HOST_WIDE_INT fuller_mask, nonzero;
rtx op0, op1, temp;
- /* If this is a CALL, don't do anything. Some of the code below
- will do the wrong thing since the mode of a CALL is VOIDmode. */
- if (code == CALL)
+ /* If this is a CALL or ASM_OPERANDS, don't do anything. Some of the
+ code below will do the wrong thing since the mode of such an
+ expression is VOIDmode.
+
+ Also do nothing if X is a CLOBBER; this can happen if X was
+ the return value from a call to gen_lowpart_for_combine. */
+ if (code == CALL || code == ASM_OPERANDS || code == CLOBBER)
return x;
/* We want to perform the operation is its present mode unless we know
@@ -5764,7 +6273,7 @@ force_to_mode (x, mode, mask, reg, just_select)
{
case CLOBBER:
/* If X is a (clobber (const_int)), return it since we know we are
- generating something that won't match. */
+ generating something that won't match. */
return x;
case USE:
@@ -5870,15 +6379,35 @@ force_to_mode (x, mode, mask, reg, just_select)
smask |= (HOST_WIDE_INT) -1 << width;
if (GET_CODE (XEXP (x, 1)) == CONST_INT
- && exact_log2 (- smask) >= 0
- && (nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0
- && (INTVAL (XEXP (x, 1)) & ~ mask) != 0)
- return force_to_mode (plus_constant (XEXP (x, 0),
- INTVAL (XEXP (x, 1)) & mask),
- mode, mask, reg, next_select);
+ && exact_log2 (- smask) >= 0)
+ {
+#ifdef STACK_BIAS
+ if (STACK_BIAS
+ && (XEXP (x, 0) == stack_pointer_rtx
+ || XEXP (x, 0) == frame_pointer_rtx))
+ {
+ int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
+ unsigned HOST_WIDE_INT sp_mask = GET_MODE_MASK (mode);
+
+ sp_mask &= ~ (sp_alignment - 1);
+ if ((sp_mask & ~ mask) == 0
+ && ((INTVAL (XEXP (x, 1)) - STACK_BIAS) & ~ mask) != 0)
+ return force_to_mode (plus_constant (XEXP (x, 0),
+ ((INTVAL (XEXP (x, 1)) -
+ STACK_BIAS) & mask)
+ + STACK_BIAS),
+ mode, mask, reg, next_select);
+ }
+#endif
+ if ((nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0
+ && (INTVAL (XEXP (x, 1)) & ~ mask) != 0)
+ return force_to_mode (plus_constant (XEXP (x, 0),
+ INTVAL (XEXP (x, 1)) & mask),
+ mode, mask, reg, next_select);
+ }
}
- /* ... fall through ... */
+ /* ... fall through ... */
case MINUS:
case MULT:
@@ -5904,13 +6433,14 @@ force_to_mode (x, mode, mask, reg, just_select)
+ floor_log2 (INTVAL (XEXP (x, 1))))
< GET_MODE_BITSIZE (GET_MODE (x)))
&& (INTVAL (XEXP (x, 1))
- & ~ nonzero_bits (XEXP (x, 0), GET_MODE (x)) == 0))
+ & ~ nonzero_bits (XEXP (x, 0), GET_MODE (x))) == 0)
{
temp = GEN_INT ((INTVAL (XEXP (x, 1)) & mask)
<< INTVAL (XEXP (XEXP (x, 0), 1)));
temp = gen_binary (GET_CODE (x), GET_MODE (x),
XEXP (XEXP (x, 0), 0), temp);
- x = gen_binary (LSHIFTRT, GET_MODE (x), temp, XEXP (x, 1));
+ x = gen_binary (LSHIFTRT, GET_MODE (x), temp,
+ XEXP (XEXP (x, 0), 1));
return force_to_mode (x, mode, mask, reg, next_select);
}
@@ -6041,7 +6571,7 @@ force_to_mode (x, mode, mask, reg, just_select)
if (GET_MODE_BITSIZE (GET_MODE (x)) > HOST_BITS_PER_WIDE_INT)
{
- nonzero = ~(HOST_WIDE_INT)0;
+ nonzero = ~ (HOST_WIDE_INT) 0;
/* GET_MODE_BITSIZE (GET_MODE (x)) - INTVAL (XEXP (x, 1))
is the number of bits a full-width mask would have set.
@@ -6145,6 +6675,10 @@ force_to_mode (x, mode, mask, reg, just_select)
return force_to_mode (x, mode, mask, reg, next_select);
}
+ /* (and (not FOO) CONST) is (not (or FOO (not CONST))), so we must
+ use the full mask inside the NOT. */
+ mask = fuller_mask;
+
unop:
op0 = gen_lowpart_for_combine (op_mode,
force_to_mode (XEXP (x, 0), mode, mask,
@@ -6155,10 +6689,11 @@ force_to_mode (x, mode, mask, reg, just_select)
case NE:
/* (and (ne FOO 0) CONST) can be (and FOO CONST) if CONST is included
- in STORE_FLAG_VALUE and FOO has no bits that might be nonzero not
- in CONST. */
- if ((mask & ~ STORE_FLAG_VALUE) == 0 && XEXP (x, 0) == const0_rtx
- && (nonzero_bits (XEXP (x, 0), mode) & ~ mask) == 0)
+ in STORE_FLAG_VALUE and FOO has a single bit that might be nonzero,
+ which is equal to STORE_FLAG_VALUE. */
+ if ((mask & ~ STORE_FLAG_VALUE) == 0 && XEXP (x, 1) == const0_rtx
+ && exact_log2 (nonzero_bits (XEXP (x, 0), mode)) >= 0
+ && nonzero_bits (XEXP (x, 0), mode) == STORE_FLAG_VALUE)
return force_to_mode (XEXP (x, 0), mode, mask, reg, next_select);
break;
@@ -6176,6 +6711,9 @@ force_to_mode (x, mode, mask, reg, just_select)
force_to_mode (XEXP (x, 2), mode,
mask, reg,next_select)));
break;
+
+ default:
+ break;
}
/* Ensure we return a value of the proper mode. */
@@ -6227,17 +6765,25 @@ if_then_else_cond (x, ptrue, pfalse)
if ((cond0 != 0 || cond1 != 0)
&& ! (cond0 != 0 && cond1 != 0 && ! rtx_equal_p (cond0, cond1)))
{
+ /* If if_then_else_cond returned zero, then true/false are the
+ same rtl. We must copy one of them to prevent invalid rtl
+ sharing. */
+ if (cond0 == 0)
+ true0 = copy_rtx (true0);
+ else if (cond1 == 0)
+ true1 = copy_rtx (true1);
+
*ptrue = gen_binary (code, mode, true0, true1);
*pfalse = gen_binary (code, mode, false0, false1);
return cond0 ? cond0 : cond1;
}
-#if STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1
-
/* See if we have PLUS, IOR, XOR, MINUS or UMAX, where one of the
- operands is zero when the other is non-zero, and vice-versa. */
+ operands is zero when the other is non-zero, and vice-versa,
+ and STORE_FLAG_VALUE is 1 or -1. */
- if ((code == PLUS || code == IOR || code == XOR || code == MINUS
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && (code == PLUS || code == IOR || code == XOR || code == MINUS
|| code == UMAX)
&& GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
{
@@ -6270,7 +6816,8 @@ if_then_else_cond (x, ptrue, pfalse)
/* Similarly for MULT, AND and UMIN, execpt that for these the result
is always zero. */
- if ((code == MULT || code == AND || code == UMIN)
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && (code == MULT || code == AND || code == UMIN)
&& GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == MULT)
{
cond0 = XEXP (XEXP (x, 0), 0);
@@ -6292,7 +6839,6 @@ if_then_else_cond (x, ptrue, pfalse)
return cond0;
}
}
-#endif
}
else if (code == IF_THEN_ELSE)
@@ -6390,6 +6936,8 @@ known_cond (x, cond, reg, val)
case LT: case LE:
return gen_unary (NEG, GET_MODE (XEXP (x, 0)), GET_MODE (XEXP (x, 0)),
XEXP (x, 0));
+ default:
+ break;
}
/* The only other cases we handle are MIN, MAX, and comparisons if the
@@ -6426,6 +6974,8 @@ known_cond (x, cond, reg, val)
return unsignedp ? XEXP (x, 1) : x;
case LEU: case LTU:
return unsignedp ? XEXP (x, 0) : x;
+ default:
+ break;
}
}
}
@@ -6445,6 +6995,43 @@ known_cond (x, cond, reg, val)
return x;
}
+/* See if X and Y are equal for the purposes of seeing if we can rewrite an
+ assignment as a field assignment. */
+
+static int
+rtx_equal_for_field_assignment_p (x, y)
+ rtx x;
+ rtx y;
+{
+ if (x == y || rtx_equal_p (x, y))
+ return 1;
+
+ if (x == 0 || y == 0 || GET_MODE (x) != GET_MODE (y))
+ return 0;
+
+ /* Check for a paradoxical SUBREG of a MEM compared with the MEM.
+ Note that all SUBREGs of MEM are paradoxical; otherwise they
+ would have been rewritten. */
+ if (GET_CODE (x) == MEM && GET_CODE (y) == SUBREG
+ && GET_CODE (SUBREG_REG (y)) == MEM
+ && rtx_equal_p (SUBREG_REG (y),
+ gen_lowpart_for_combine (GET_MODE (SUBREG_REG (y)), x)))
+ return 1;
+
+ if (GET_CODE (y) == MEM && GET_CODE (x) == SUBREG
+ && GET_CODE (SUBREG_REG (x)) == MEM
+ && rtx_equal_p (SUBREG_REG (x),
+ gen_lowpart_for_combine (GET_MODE (SUBREG_REG (x)), y)))
+ return 1;
+
+ /* We used to see if get_last_value of X and Y were the same but that's
+ not correct. In one direction, we'll cause the assignment to have
+ the wrong destination and in the case, we'll import a register into this
+ insn that might have already have been dead. So fail if none of the
+ above cases are true. */
+ return 0;
+}
+
/* See if X, a SET operation, can be rewritten as a bit-field assignment.
Return that assignment if so.
@@ -6457,6 +7044,7 @@ make_field_assignment (x)
rtx dest = SET_DEST (x);
rtx src = SET_SRC (x);
rtx assign;
+ rtx rhs, lhs;
HOST_WIDE_INT c1;
int pos, len;
rtx other;
@@ -6470,13 +7058,13 @@ make_field_assignment (x)
if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == ROTATE
&& GET_CODE (XEXP (XEXP (src, 0), 0)) == CONST_INT
&& INTVAL (XEXP (XEXP (src, 0), 0)) == -2
- && (rtx_equal_p (dest, XEXP (src, 1))
- || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
- || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
+ && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
1, 1, 1, 0);
- return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+ if (assign != 0)
+ return gen_rtx_SET (VOIDmode, assign, const0_rtx);
+ return x;
}
else if (GET_CODE (src) == AND && GET_CODE (XEXP (src, 0)) == SUBREG
@@ -6485,60 +7073,63 @@ make_field_assignment (x)
< GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (src, 0)))))
&& GET_CODE (SUBREG_REG (XEXP (src, 0))) == ROTATE
&& INTVAL (XEXP (SUBREG_REG (XEXP (src, 0)), 0)) == -2
- && (rtx_equal_p (dest, XEXP (src, 1))
- || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
- || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
+ && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
assign = make_extraction (VOIDmode, dest, 0,
XEXP (SUBREG_REG (XEXP (src, 0)), 1),
1, 1, 1, 0);
- return gen_rtx (SET, VOIDmode, assign, const0_rtx);
+ if (assign != 0)
+ return gen_rtx_SET (VOIDmode, assign, const0_rtx);
+ return x;
}
- /* If SRC is (ior (ashift (const_int 1) POS DEST)), this is a set of a
+ /* If SRC is (ior (ashift (const_int 1) POS) DEST), this is a set of a
one-bit field. */
else if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == ASHIFT
&& XEXP (XEXP (src, 0), 0) == const1_rtx
- && (rtx_equal_p (dest, XEXP (src, 1))
- || rtx_equal_p (dest, get_last_value (XEXP (src, 1)))
- || rtx_equal_p (get_last_value (dest), XEXP (src, 1))))
+ && rtx_equal_for_field_assignment_p (dest, XEXP (src, 1)))
{
assign = make_extraction (VOIDmode, dest, 0, XEXP (XEXP (src, 0), 1),
1, 1, 1, 0);
- return gen_rtx (SET, VOIDmode, assign, const1_rtx);
+ if (assign != 0)
+ return gen_rtx_SET (VOIDmode, assign, const1_rtx);
+ return x;
}
/* The other case we handle is assignments into a constant-position
- field. They look like (ior (and DEST C1) OTHER). If C1 represents
+ field. They look like (ior/xor (and DEST C1) OTHER). If C1 represents
a mask that has all one bits except for a group of zero bits and
OTHER is known to have zeros where C1 has ones, this is such an
assignment. Compute the position and length from C1. Shift OTHER
to the appropriate position, force it to the required mode, and
make the extraction. Check for the AND in both operands. */
- if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 0)) == AND
- && GET_CODE (XEXP (XEXP (src, 0), 1)) == CONST_INT
- && (rtx_equal_p (XEXP (XEXP (src, 0), 0), dest)
- || rtx_equal_p (XEXP (XEXP (src, 0), 0), get_last_value (dest))
- || rtx_equal_p (get_last_value (XEXP (XEXP (src, 0), 1)), dest)))
- c1 = INTVAL (XEXP (XEXP (src, 0), 1)), other = XEXP (src, 1);
- else if (GET_CODE (src) == IOR && GET_CODE (XEXP (src, 1)) == AND
- && GET_CODE (XEXP (XEXP (src, 1), 1)) == CONST_INT
- && (rtx_equal_p (XEXP (XEXP (src, 1), 0), dest)
- || rtx_equal_p (XEXP (XEXP (src, 1), 0), get_last_value (dest))
- || rtx_equal_p (get_last_value (XEXP (XEXP (src, 1), 0)),
- dest)))
- c1 = INTVAL (XEXP (XEXP (src, 1), 1)), other = XEXP (src, 0);
+ if (GET_CODE (src) != IOR && GET_CODE (src) != XOR)
+ return x;
+
+ rhs = expand_compound_operation (XEXP (src, 0));
+ lhs = expand_compound_operation (XEXP (src, 1));
+
+ if (GET_CODE (rhs) == AND
+ && GET_CODE (XEXP (rhs, 1)) == CONST_INT
+ && rtx_equal_for_field_assignment_p (XEXP (rhs, 0), dest))
+ c1 = INTVAL (XEXP (rhs, 1)), other = lhs;
+ else if (GET_CODE (lhs) == AND
+ && GET_CODE (XEXP (lhs, 1)) == CONST_INT
+ && rtx_equal_for_field_assignment_p (XEXP (lhs, 0), dest))
+ c1 = INTVAL (XEXP (lhs, 1)), other = rhs;
else
return x;
- pos = get_pos_from_mask (c1 ^ GET_MODE_MASK (GET_MODE (dest)), &len);
+ pos = get_pos_from_mask ((~ c1) & GET_MODE_MASK (GET_MODE (dest)), &len);
if (pos < 0 || pos + len > GET_MODE_BITSIZE (GET_MODE (dest))
- || (GET_MODE_BITSIZE (GET_MODE (other)) <= HOST_BITS_PER_WIDE_INT
- && (c1 & nonzero_bits (other, GET_MODE (other))) != 0))
+ || GET_MODE_BITSIZE (GET_MODE (dest)) > HOST_BITS_PER_WIDE_INT
+ || (c1 & nonzero_bits (other, GET_MODE (dest))) != 0)
return x;
assign = make_extraction (VOIDmode, dest, pos, NULL_RTX, len, 1, 1, 0);
+ if (assign == 0)
+ return x;
/* The mode to use for the source is the mode of the assignment, or of
what is inside a possible STRICT_LOW_PART. */
@@ -6584,7 +7175,8 @@ apply_distributive_law (x)
lhs = XEXP (x, 0), rhs = XEXP (x, 1);
- /* If either operand is a primitive we can't do anything, so get out fast. */
+ /* If either operand is a primitive we can't do anything, so get out
+ fast. */
if (GET_RTX_CLASS (GET_CODE (lhs)) == 'o'
|| GET_RTX_CLASS (GET_CODE (rhs)) == 'o')
return x;
@@ -6769,7 +7361,7 @@ simplify_and_const_int (x, mode, varop, constop)
else
varop = gen_lowpart_for_combine (mode, varop);
- /* If we can't make the SUBREG, try to return what we were given. */
+ /* If we can't make the SUBREG, try to return what we were given. */
if (GET_CODE (varop) == CLOBBER)
return x ? x : varop;
@@ -6793,6 +7385,13 @@ simplify_and_const_int (x, mode, varop, constop)
return x;
}
+/* We let num_sign_bit_copies recur into nonzero_bits as that is useful.
+ We don't let nonzero_bits recur into num_sign_bit_copies, because that
+ is less useful. We can't allow both, because that results in exponential
+ run time recursion. There is a nullstone testcase that triggered
+ this. This macro avoids accidental uses of num_sign_bit_copies. */
+#define num_sign_bit_copies()
+
/* Given an expression, X, compute which bits in X can be non-zero.
We don't care about bits outside of those defined in MODE.
@@ -6864,12 +7463,26 @@ nonzero_bits (x, mode)
stack to be momentarily aligned only to that amount, so we pick
the least alignment. */
- if (x == stack_pointer_rtx)
+ /* We can't check for arg_pointer_rtx here, because it is not
+ guaranteed to have as much alignment as the stack pointer.
+ In particular, in the Irix6 n64 ABI, the stack has 128 bit
+ alignment but the argument pointer has only 64 bit alignment. */
+
+ if ((x == frame_pointer_rtx
+ || x == stack_pointer_rtx
+ || x == hard_frame_pointer_rtx
+ || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
+ && REGNO (x) <= LAST_VIRTUAL_REGISTER))
+#ifdef STACK_BIAS
+ && !STACK_BIAS
+#endif
+ )
{
int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
#ifdef PUSH_ROUNDING
- sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment);
+ if (REGNO (x) == STACK_POINTER_REGNUM)
+ sp_alignment = MIN (PUSH_ROUNDING (1), sp_alignment);
#endif
/* We must return here, otherwise we may get a worse result from
@@ -6886,7 +7499,7 @@ nonzero_bits (x, mode)
if (reg_last_set_value[REGNO (x)] != 0
&& reg_last_set_mode[REGNO (x)] == mode
- && (reg_n_sets[REGNO (x)] == 1
+ && (REG_N_SETS (REGNO (x)) == 1
|| reg_last_set_label[REGNO (x)] == label_tick)
&& INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
return reg_last_set_nonzero_bits[REGNO (x)];
@@ -6958,18 +7571,26 @@ nonzero_bits (x, mode)
break;
case NEG:
+#if 0
+ /* Disabled to avoid exponential mutual recursion between nonzero_bits
+ and num_sign_bit_copies. */
if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
== GET_MODE_BITSIZE (GET_MODE (x)))
nonzero = 1;
+#endif
if (GET_MODE_SIZE (GET_MODE (x)) < mode_width)
nonzero |= (GET_MODE_MASK (mode) & ~ GET_MODE_MASK (GET_MODE (x)));
break;
case ABS:
+#if 0
+ /* Disabled to avoid exponential mutual recursion between nonzero_bits
+ and num_sign_bit_copies. */
if (num_sign_bit_copies (XEXP (x, 0), GET_MODE (x))
== GET_MODE_BITSIZE (GET_MODE (x)))
nonzero = 1;
+#endif
break;
case TRUNCATE:
@@ -6990,9 +7611,9 @@ nonzero_bits (x, mode)
if (GET_MODE (XEXP (x, 0)) != VOIDmode)
{
inner_nz &= GET_MODE_MASK (GET_MODE (XEXP (x, 0)));
- if (inner_nz &
- (((HOST_WIDE_INT) 1
- << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))))
+ if (inner_nz
+ & (((HOST_WIDE_INT) 1
+ << (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))) - 1))))
inner_nz |= (GET_MODE_MASK (mode)
& ~ GET_MODE_MASK (GET_MODE (XEXP (x, 0))));
}
@@ -7036,6 +7657,22 @@ nonzero_bits (x, mode)
switch (code)
{
case PLUS:
+#ifdef STACK_BIAS
+ if (STACK_BIAS
+ && (XEXP (x, 0) == stack_pointer_rtx
+ || XEXP (x, 0) == frame_pointer_rtx)
+ && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ int sp_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
+
+ nz0 = (GET_MODE_MASK (mode) & ~ (sp_alignment - 1));
+ nz1 = INTVAL (XEXP (x, 1)) - STACK_BIAS;
+ width0 = floor_log2 (nz0) + 1;
+ width1 = floor_log2 (nz1) + 1;
+ low0 = floor_log2 (nz0 & -nz0);
+ low1 = floor_log2 (nz1 & -nz1);
+ }
+#endif
result_width = MAX (width0, width1) + 1;
result_low = MIN (low0, low1);
break;
@@ -7062,6 +7699,8 @@ nonzero_bits (x, mode)
result_width = MIN (width0, width1);
result_low = MIN (low0, low1);
break;
+ default:
+ abort ();
}
if (result_width < mode_width)
@@ -7096,15 +7735,23 @@ nonzero_bits (x, mode)
{
nonzero &= nonzero_bits (SUBREG_REG (x), mode);
-#ifndef WORD_REGISTER_OPERATIONS
- /* On many CISC machines, accessing an object in a wider mode
- causes the high-order bits to become undefined. So they are
- not known to be zero. */
- if (GET_MODE_SIZE (GET_MODE (x))
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
- nonzero |= (GET_MODE_MASK (GET_MODE (x))
- & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
+#if defined (WORD_REGISTER_OPERATIONS) && defined (LOAD_EXTEND_OP)
+ /* If this is a typical RISC machine, we only have to worry
+ about the way loads are extended. */
+ if (LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) == SIGN_EXTEND
+ ? (nonzero
+ & (1L << (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))) - 1)))
+ : LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (x))) != ZERO_EXTEND)
#endif
+ {
+ /* On many CISC machines, accessing an object in a wider mode
+ causes the high-order bits to become undefined. So they are
+ not known to be zero. */
+ if (GET_MODE_SIZE (GET_MODE (x))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+ nonzero |= (GET_MODE_MASK (GET_MODE (x))
+ & ~ GET_MODE_MASK (GET_MODE (SUBREG_REG (x))));
+ }
}
break;
@@ -7164,10 +7811,16 @@ nonzero_bits (x, mode)
nonzero &= (nonzero_bits (XEXP (x, 1), mode)
| nonzero_bits (XEXP (x, 2), mode));
break;
+
+ default:
+ break;
}
return nonzero;
}
+
+/* See the macro definition above. */
+#undef num_sign_bit_copies
/* Return the number of bits at the high-order end of X that are known to
be equal to the sign bit. X will be used in mode MODE; if MODE is
@@ -7197,18 +7850,30 @@ num_sign_bit_copies (x, mode)
bitwidth = GET_MODE_BITSIZE (mode);
- /* For a smaller object, just ignore the high bits. */
+ /* For a smaller object, just ignore the high bits. */
if (bitwidth < GET_MODE_BITSIZE (GET_MODE (x)))
return MAX (1, (num_sign_bit_copies (x, GET_MODE (x))
- (GET_MODE_BITSIZE (GET_MODE (x)) - bitwidth)));
+ if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x)))
+ {
#ifndef WORD_REGISTER_OPERATIONS
/* If this machine does not do all register operations on the entire
register and MODE is wider than the mode of X, we can say nothing
at all about the high-order bits. */
- if (GET_MODE (x) != VOIDmode && bitwidth > GET_MODE_BITSIZE (GET_MODE (x)))
- return 1;
+ return 1;
+#else
+ /* Likewise on machines that do, if the mode of the object is smaller
+ than a word and loads of that size don't sign extend, we can say
+ nothing about the high order bits. */
+ if (GET_MODE_BITSIZE (GET_MODE (x)) < BITS_PER_WORD
+#ifdef LOAD_EXTEND_OP
+ && LOAD_EXTEND_OP (GET_MODE (x)) != SIGN_EXTEND
#endif
+ )
+ return 1;
+#endif
+ }
switch (code)
{
@@ -7224,7 +7889,7 @@ num_sign_bit_copies (x, mode)
if (reg_last_set_value[REGNO (x)] != 0
&& reg_last_set_mode[REGNO (x)] == mode
- && (reg_n_sets[REGNO (x)] == 1
+ && (REG_N_SETS (REGNO (x)) == 1
|| reg_last_set_label[REGNO (x)] == label_tick)
&& INSN_CUID (reg_last_set[REGNO (x)]) < subst_low_cuid)
return reg_last_set_sign_bit_copies[REGNO (x)];
@@ -7264,7 +7929,7 @@ num_sign_bit_copies (x, mode)
return MAX (bitwidth - GET_MODE_BITSIZE (GET_MODE (x)) + 1,
num_sign_bit_copies (SUBREG_REG (x), mode));
- /* For a smaller object, just ignore the high bits. */
+ /* For a smaller object, just ignore the high bits. */
if (bitwidth <= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x))))
{
num0 = num_sign_bit_copies (SUBREG_REG (x), VOIDmode);
@@ -7303,7 +7968,7 @@ num_sign_bit_copies (x, mode)
+ num_sign_bit_copies (XEXP (x, 0), VOIDmode));
case TRUNCATE:
- /* For a smaller object, just ignore the high bits. */
+ /* For a smaller object, just ignore the high bits. */
num0 = num_sign_bit_copies (XEXP (x, 0), VOIDmode);
return MAX (1, (num0 - (GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0)))
- bitwidth)));
@@ -7329,13 +7994,15 @@ num_sign_bit_copies (x, mode)
is known to be positive, the number of sign bit copies is the
same as that of the input. Finally, if the input has just one bit
that might be nonzero, all the bits are copies of the sign bit. */
+ num0 = num_sign_bit_copies (XEXP (x, 0), mode);
+ if (bitwidth > HOST_BITS_PER_WIDE_INT)
+ return num0 > 1 ? num0 - 1 : 1;
+
nonzero = nonzero_bits (XEXP (x, 0), mode);
if (nonzero == 1)
return bitwidth;
- num0 = num_sign_bit_copies (XEXP (x, 0), mode);
if (num0 > 1
- && bitwidth <= HOST_BITS_PER_WIDE_INT
&& (((HOST_WIDE_INT) 1 << (bitwidth - 1)) & nonzero))
num0--;
@@ -7379,19 +8046,27 @@ num_sign_bit_copies (x, mode)
result = bitwidth - (bitwidth - num0) - (bitwidth - num1);
if (result > 0
- && bitwidth <= HOST_BITS_PER_WIDE_INT
- && ((nonzero_bits (XEXP (x, 0), mode)
- & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
- && (nonzero_bits (XEXP (x, 1), mode)
- & ((HOST_WIDE_INT) 1 << (bitwidth - 1)) != 0))
+ && (bitwidth > HOST_BITS_PER_WIDE_INT
+ || (((nonzero_bits (XEXP (x, 0), mode)
+ & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
+ && ((nonzero_bits (XEXP (x, 1), mode)
+ & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))))
result--;
return MAX (1, result);
case UDIV:
- /* The result must be <= the first operand. */
- return num_sign_bit_copies (XEXP (x, 0), mode);
-
+ /* The result must be <= the first operand. If the first operand
+ has the high bit set, we know nothing about the number of sign
+ bit copies. */
+ if (bitwidth > HOST_BITS_PER_WIDE_INT)
+ return 1;
+ else if ((nonzero_bits (XEXP (x, 0), mode)
+ & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
+ return 1;
+ else
+ return num_sign_bit_copies (XEXP (x, 0), mode);
+
case UMOD:
/* The result must be <= the scond operand. */
return num_sign_bit_copies (XEXP (x, 1), mode);
@@ -7402,20 +8077,20 @@ num_sign_bit_copies (x, mode)
to add 1. */
result = num_sign_bit_copies (XEXP (x, 0), mode);
if (result > 1
- && bitwidth <= HOST_BITS_PER_WIDE_INT
- && (nonzero_bits (XEXP (x, 1), mode)
- & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
- result --;
+ && (bitwidth > HOST_BITS_PER_WIDE_INT
+ || (nonzero_bits (XEXP (x, 1), mode)
+ & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
+ result--;
return result;
case MOD:
result = num_sign_bit_copies (XEXP (x, 1), mode);
if (result > 1
- && bitwidth <= HOST_BITS_PER_WIDE_INT
- && (nonzero_bits (XEXP (x, 1), mode)
- & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0)
- result --;
+ && (bitwidth > HOST_BITS_PER_WIDE_INT
+ || (nonzero_bits (XEXP (x, 1), mode)
+ & ((HOST_WIDE_INT) 1 << (bitwidth - 1))) != 0))
+ result--;
return result;
@@ -7444,11 +8119,14 @@ num_sign_bit_copies (x, mode)
num1 = num_sign_bit_copies (XEXP (x, 2), mode);
return MIN (num0, num1);
-#if STORE_FLAG_VALUE == -1
case EQ: case NE: case GE: case GT: case LE: case LT:
case GEU: case GTU: case LEU: case LTU:
- return bitwidth;
-#endif
+ if (STORE_FLAG_VALUE == -1)
+ return bitwidth;
+ break;
+
+ default:
+ break;
}
/* If we haven't been able to figure it out by one of the above rules,
@@ -7560,6 +8238,8 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
case NEG:
op0 = NIL;
break;
+ default:
+ break;
}
}
@@ -7581,7 +8261,7 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
op0 = SET;
else /* op1 == XOR */
/* (a ^ b) | b == a | b */
- ;
+ {;}
break;
case XOR:
@@ -7601,6 +8281,8 @@ merge_outer_ops (pop0, pconst0, op1, const1, mode, pcomp_p)
/* (a ^ b) & b) == (~a) & b */
*pcomp_p = 1;
break;
+ default:
+ break;
}
/* Check for NO-OP cases. */
@@ -7669,7 +8351,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
if (x)
return x;
- return gen_rtx (code, mode, varop, GEN_INT (count));
+ return gen_rtx_fmt_ee (code, mode, varop, GEN_INT (count));
}
/* Unless one of the branches of the `if' in this loop does a `continue',
@@ -7694,7 +8376,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
/* We need to determine what mode we will do the shift in. If the
shift is a right shift or a ROTATE, we must always do it in the mode
it was originally done in. Otherwise, we can do it in MODE, the
- widest mode encountered. */
+ widest mode encountered. */
shift_mode
= (code == ASHIFTRT || code == LSHIFTRT || code == ROTATE
? result_mode : mode);
@@ -7727,7 +8409,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
/* Negative counts are invalid and should not have been made (a
programmer-specified negative count should have been handled
- above). */
+ above). */
else if (count < 0)
abort ();
@@ -7787,11 +8469,11 @@ simplify_shift_const (x, code, result_mode, varop, count)
MODE_INT, 1)) != BLKmode)
{
if (BYTES_BIG_ENDIAN)
- new = gen_rtx (MEM, tmode, XEXP (varop, 0));
+ new = gen_rtx_MEM (tmode, XEXP (varop, 0));
else
- new = gen_rtx (MEM, tmode,
- plus_constant (XEXP (varop, 0),
- count / BITS_PER_UNIT));
+ new = gen_rtx_MEM (tmode,
+ plus_constant (XEXP (varop, 0),
+ count / BITS_PER_UNIT));
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (varop);
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (varop);
MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (varop);
@@ -7880,7 +8562,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
continue;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case LSHIFTRT:
case ASHIFT:
@@ -8216,9 +8898,9 @@ simplify_shift_const (x, code, result_mode, varop, count)
STORE_FLAG_VALUE of 1 or logical with STORE_FLAG_VALUE == -1,
we have a (neg (gt X 0)) operation. */
- if (GET_CODE (XEXP (varop, 0)) == ASHIFTRT
+ if ((STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
+ && GET_CODE (XEXP (varop, 0)) == ASHIFTRT
&& count == GET_MODE_BITSIZE (GET_MODE (varop)) - 1
- && (STORE_FLAG_VALUE == 1 || STORE_FLAG_VALUE == -1)
&& (code == LSHIFTRT || code == ASHIFTRT)
&& GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
&& INTVAL (XEXP (XEXP (varop, 0), 1)) == count
@@ -8234,6 +8916,32 @@ simplify_shift_const (x, code, result_mode, varop, count)
continue;
}
break;
+
+ case TRUNCATE:
+ /* Change (lshiftrt (truncate (lshiftrt))) to (truncate (lshiftrt))
+ if the truncate does not affect the value. */
+ if (code == LSHIFTRT
+ && GET_CODE (XEXP (varop, 0)) == LSHIFTRT
+ && GET_CODE (XEXP (XEXP (varop, 0), 1)) == CONST_INT
+ && (INTVAL (XEXP (XEXP (varop, 0), 1))
+ >= (GET_MODE_BITSIZE (GET_MODE (XEXP (varop, 0)))
+ - GET_MODE_BITSIZE (GET_MODE (varop)))))
+ {
+ rtx varop_inner = XEXP (varop, 0);
+
+ varop_inner = gen_rtx_combine (LSHIFTRT,
+ GET_MODE (varop_inner),
+ XEXP (varop_inner, 0),
+ GEN_INT (count + INTVAL (XEXP (varop_inner, 1))));
+ varop = gen_rtx_combine (TRUNCATE, GET_MODE (varop),
+ varop_inner);
+ count = 0;
+ continue;
+ }
+ break;
+
+ default:
+ break;
}
break;
@@ -8271,7 +8979,7 @@ simplify_shift_const (x, code, result_mode, varop, count)
else if (GET_MODE (varop) != shift_mode)
varop = gen_lowpart_for_combine (shift_mode, varop);
- /* If we can't make the SUBREG, try to return what we were given. */
+ /* If we can't make the SUBREG, try to return what we were given. */
if (GET_CODE (varop) == CLOBBER)
return x ? x : varop;
@@ -8421,10 +9129,10 @@ recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
them. Then check to make sure that all of them are dead. */
if (num_clobbers_to_add)
{
- rtx newpat = gen_rtx (PARALLEL, VOIDmode,
- gen_rtvec (GET_CODE (pat) == PARALLEL
- ? XVECLEN (pat, 0) + num_clobbers_to_add
- : num_clobbers_to_add + 1));
+ rtx newpat = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (GET_CODE (pat) == PARALLEL
+ ? XVECLEN (pat, 0) + num_clobbers_to_add
+ : num_clobbers_to_add + 1));
if (GET_CODE (pat) == PARALLEL)
for (i = 0; i < XVECLEN (pat, 0); i++)
@@ -8442,8 +9150,8 @@ recog_for_combine (pnewpat, insn, pnotes, padded_scratches)
return -1;
else if (GET_CODE (XEXP (XVECEXP (newpat, 0, i), 0)) == SCRATCH)
(*padded_scratches)++;
- notes = gen_rtx (EXPR_LIST, REG_UNUSED,
- XEXP (XVECEXP (newpat, 0, i), 0), notes);
+ notes = gen_rtx_EXPR_LIST (REG_UNUSED,
+ XEXP (XVECEXP (newpat, 0, i), 0), notes);
}
pat = newpat;
}
@@ -8483,7 +9191,7 @@ gen_lowpart_for_combine (mode, x)
&& (GET_CODE (x) == CONST_INT
|| GET_CODE (x) == CONST_DOUBLE))
|| GET_MODE_SIZE (GET_MODE (x)) == GET_MODE_SIZE (mode)))
- return gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+ return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
/* X might be a paradoxical (subreg (mem)). In that case, gen_lowpart
won't know what to do. So we will strip off the SUBREG here and
@@ -8502,7 +9210,7 @@ gen_lowpart_for_combine (mode, x)
&& REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (result))
!= GET_MODE_SIZE (GET_MODE (SUBREG_REG (result)))))
- reg_changes_size[REGNO (SUBREG_REG (result))] = 1;
+ REG_CHANGES_SIZE (REGNO (SUBREG_REG (result))) = 1;
if (result)
return result;
@@ -8515,13 +9223,13 @@ gen_lowpart_for_combine (mode, x)
/* Refuse to work on a volatile memory ref or one with a mode-dependent
address. */
if (MEM_VOLATILE_P (x) || mode_dependent_address_p (XEXP (x, 0)))
- return gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+ return gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
/* If we want to refer to something bigger than the original memref,
generate a perverse subreg instead. That will force a reload
of the original memref X. */
if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (mode))
- return gen_rtx (SUBREG, mode, x, 0);
+ return gen_rtx_SUBREG (mode, x, 0);
if (WORDS_BIG_ENDIAN)
offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
@@ -8533,7 +9241,7 @@ gen_lowpart_for_combine (mode, x)
offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
- MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
}
- new = gen_rtx (MEM, mode, plus_constant (XEXP (x, 0), offset));
+ new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (x);
MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (x);
@@ -8556,7 +9264,7 @@ gen_lowpart_for_combine (mode, x)
word = ((GET_MODE_SIZE (GET_MODE (x))
- MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
/ UNITS_PER_WORD);
- return gen_rtx (SUBREG, mode, x, word);
+ return gen_rtx_SUBREG (mode, x, word);
}
}
@@ -8578,9 +9286,10 @@ gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
va_list p;
int n_args;
rtx args[3];
- int i, j;
+ int j;
char *fmt;
rtx rt;
+ struct undo *undo;
VA_START (p, mode);
@@ -8607,17 +9316,17 @@ gen_rtx_combine VPROTO((enum rtx_code code, enum machine_mode mode, ...))
/* See if this is in undobuf. Be sure we don't use objects that came
from another insn; this could produce circular rtl structures. */
- for (i = previous_num_undos; i < undobuf.num_undo; i++)
- if (!undobuf.undo[i].is_int
- && GET_CODE (undobuf.undo[i].old_contents.r) == code
- && GET_MODE (undobuf.undo[i].old_contents.r) == mode)
+ for (undo = undobuf.undos; undo != undobuf.previous_undos; undo = undo->next)
+ if (!undo->is_int
+ && GET_CODE (undo->old_contents.r) == code
+ && GET_MODE (undo->old_contents.r) == mode)
{
for (j = 0; j < n_args; j++)
- if (XEXP (undobuf.undo[i].old_contents.r, j) != args[j])
+ if (XEXP (undo->old_contents.r, j) != args[j])
break;
if (j == n_args)
- return undobuf.undo[i].old_contents.r;
+ return undo->old_contents.r;
}
/* Otherwise make a new rtx. We know we have 1, 2, or 3 args.
@@ -8656,7 +9365,7 @@ gen_binary (code, mode, op0, op1)
enum machine_mode op_mode = GET_MODE (op0);
/* Strip the COMPARE from (REL_OP (compare X Y) 0) to get
- just (REL_OP X Y). */
+ just (REL_OP X Y). */
if (GET_CODE (op0) == COMPARE && op1 == const0_rtx)
{
op1 = XEXP (op0, 1);
@@ -8684,6 +9393,13 @@ gen_binary (code, mode, op0, op1)
&& GET_RTX_CLASS (GET_CODE (op1)) != 'o')))
return gen_rtx_combine (code, mode, op1, op0);
+ /* If we are turning off bits already known off in OP0, we need not do
+ an AND. */
+ else if (code == AND && GET_CODE (op1) == CONST_INT
+ && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
+ && (nonzero_bits (op0, mode) & ~ INTVAL (op1)) == 0)
+ return op0;
+
return gen_rtx_combine (code, mode, op0, op1);
}
@@ -8816,18 +9532,18 @@ simplify_comparison (code, pop0, pop1)
> GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner_op0))))
&& (GET_MODE (SUBREG_REG (inner_op0))
== GET_MODE (SUBREG_REG (inner_op1)))
- && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0)))
+ && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (inner_op0)))
<= HOST_BITS_PER_WIDE_INT)
- && (0 == (~c0) & nonzero_bits (SUBREG_REG (inner_op0),
- GET_MODE (SUBREG_REG (op0))))
- && (0 == (~c1) & nonzero_bits (SUBREG_REG (inner_op1),
- GET_MODE (SUBREG_REG (inner_op1)))))
+ && (0 == ((~c0) & nonzero_bits (SUBREG_REG (inner_op0),
+ GET_MODE (SUBREG_REG (inner_op0)))))
+ && (0 == ((~c1) & nonzero_bits (SUBREG_REG (inner_op1),
+ GET_MODE (SUBREG_REG (inner_op1))))))
{
op0 = SUBREG_REG (inner_op0);
op1 = SUBREG_REG (inner_op1);
/* The resulting comparison is always unsigned since we masked
- off the original sign bit. */
+ off the original sign bit. */
code = unsigned_condition (code);
changed = 1;
@@ -8863,8 +9579,9 @@ simplify_comparison (code, pop0, pop1)
}
/* If the first operand is a constant, swap the operands and adjust the
- comparison code appropriately. */
- if (CONSTANT_P (op0))
+ comparison code appropriately, but don't do this if the second operand
+ is already a constant integer. */
+ if (CONSTANT_P (op0) && GET_CODE (op1) != CONST_INT)
{
tem = op0, op0 = op1, op1 = tem;
code = swap_condition (code);
@@ -8966,7 +9683,7 @@ simplify_comparison (code, pop0, pop1)
break;
case GE:
- /* >= C is equivalent to > (C - 1). */
+ /* >= C is equivalent to > (C - 1). */
if (const_op > 0)
{
const_op -= 1;
@@ -9002,11 +9719,12 @@ simplify_comparison (code, pop0, pop1)
const_op -= 1;
op1 = GEN_INT (const_op);
code = LEU;
- /* ... fall through ... */
+ /* ... fall through ... */
}
/* (unsigned) < 0x80000000 is equivalent to >= 0. */
- else if (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1))
+ else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+ && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
{
const_op = 0, op1 = const0_rtx;
code = GE;
@@ -9020,8 +9738,9 @@ simplify_comparison (code, pop0, pop1)
if (const_op == 0)
code = EQ;
- /* (unsigned) <= 0x7fffffff is equivalent to >= 0. */
- else if (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
+ /* (unsigned) <= 0x7fffffff is equivalent to >= 0. */
+ else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+ && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
{
const_op = 0, op1 = const0_rtx;
code = GE;
@@ -9035,11 +9754,12 @@ simplify_comparison (code, pop0, pop1)
const_op -= 1;
op1 = GEN_INT (const_op);
code = GTU;
- /* ... fall through ... */
+ /* ... fall through ... */
}
/* (unsigned) >= 0x80000000 is equivalent to < 0. */
- else if (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1))
+ else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+ && (const_op == (HOST_WIDE_INT) 1 << (mode_width - 1)))
{
const_op = 0, op1 = const0_rtx;
code = LT;
@@ -9054,12 +9774,16 @@ simplify_comparison (code, pop0, pop1)
code = NE;
/* (unsigned) > 0x7fffffff is equivalent to < 0. */
- else if (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1)
+ else if ((mode_width <= HOST_BITS_PER_WIDE_INT)
+ && (const_op == ((HOST_WIDE_INT) 1 << (mode_width - 1)) - 1))
{
const_op = 0, op1 = const0_rtx;
code = LT;
}
break;
+
+ default:
+ break;
}
/* Compute some predicates to simplify code below. */
@@ -9088,24 +9812,19 @@ simplify_comparison (code, pop0, pop1)
/* If we are extracting a single bit from a variable position in
a constant that has only a single bit set and are comparing it
with zero, we can convert this into an equality comparison
- between the position and the location of the single bit. We can't
- do this if bit endian and we don't have an extzv since we then
- can't know what mode to use for the endianness adjustment. */
+ between the position and the location of the single bit. */
if (GET_CODE (XEXP (op0, 0)) == CONST_INT
&& XEXP (op0, 1) == const1_rtx
&& equality_comparison_p && const_op == 0
- && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0
- && (! BITS_BIG_ENDIAN
-#ifdef HAVE_extzv
- || HAVE_extzv
-#endif
- ))
+ && (i = exact_log2 (INTVAL (XEXP (op0, 0)))) >= 0)
{
-#ifdef HAVE_extzv
if (BITS_BIG_ENDIAN)
+#ifdef HAVE_extzv
i = (GET_MODE_BITSIZE
(insn_operand_mode[(int) CODE_FOR_extzv][1]) - 1 - i);
+#else
+ i = BITS_PER_WORD - 1 - i;
#endif
op0 = XEXP (op0, 2);
@@ -9117,7 +9836,7 @@ simplify_comparison (code, pop0, pop1)
continue;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case SIGN_EXTRACT:
tem = expand_compound_operation (op0);
@@ -9177,7 +9896,7 @@ simplify_comparison (code, pop0, pop1)
}
/* If we have NEG of something whose two high-order bits are the
- same, we know that "(-a) < 0" is equivalent to "a > 0". */
+ same, we know that "(-a) < 0" is equivalent to "a > 0". */
if (num_sign_bit_copies (op0, mode) >= 2)
{
op0 = XEXP (op0, 0);
@@ -9213,7 +9932,7 @@ simplify_comparison (code, pop0, pop1)
continue;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case ABS:
/* ABS is ignorable inside an equality comparison with zero. */
@@ -9280,7 +9999,7 @@ simplify_comparison (code, pop0, pop1)
else
break;
- /* ... fall through ... */
+ /* ... fall through ... */
case ZERO_EXTEND:
if ((unsigned_comparison_p || equality_comparison_p)
@@ -9484,6 +10203,48 @@ simplify_comparison (code, pop0, pop1)
op0 = gen_lowpart_for_combine (tmode, XEXP (op0, 0));
continue;
}
+
+ /* If this is (and:M1 (subreg:M2 X 0) (const_int C1)) where C1 fits
+ in both M1 and M2 and the SUBREG is either paradoxical or
+ represents the low part, permute the SUBREG and the AND and
+ try again. */
+ if (GET_CODE (XEXP (op0, 0)) == SUBREG
+ && ((mode_width
+ >= GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
+#ifdef WORD_REGISTER_OPERATIONS
+ || subreg_lowpart_p (XEXP (op0, 0))
+#endif
+ )
+#ifndef WORD_REGISTER_OPERATIONS
+ /* It is unsafe to commute the AND into the SUBREG if the SUBREG
+ is paradoxical and WORD_REGISTER_OPERATIONS is not defined.
+ As originally written the upper bits have a defined value
+ due to the AND operation. However, if we commute the AND
+ inside the SUBREG then they no longer have defined values
+ and the meaning of the code has been changed. */
+ && (GET_MODE_SIZE (GET_MODE (XEXP (op0, 0)))
+ <= GET_MODE_SIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0)))))
+#endif
+ && GET_CODE (XEXP (op0, 1)) == CONST_INT
+ && mode_width <= HOST_BITS_PER_WIDE_INT
+ && (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
+ <= HOST_BITS_PER_WIDE_INT)
+ && (INTVAL (XEXP (op0, 1)) & ~ mask) == 0
+ && 0 == (~ GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0))))
+ & INTVAL (XEXP (op0, 1)))
+ && INTVAL (XEXP (op0, 1)) != mask
+ && (INTVAL (XEXP (op0, 1))
+ != GET_MODE_MASK (GET_MODE (SUBREG_REG (XEXP (op0, 0))))))
+
+ {
+ op0
+ = gen_lowpart_for_combine
+ (mode,
+ gen_binary (AND, GET_MODE (SUBREG_REG (XEXP (op0, 0))),
+ SUBREG_REG (XEXP (op0, 0)), XEXP (op0, 1)));
+ continue;
+ }
+
break;
case ASHIFT:
@@ -9563,7 +10324,7 @@ simplify_comparison (code, pop0, pop1)
continue;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case LSHIFTRT:
/* If we have (compare (xshiftrt FOO N) (const_int C)) and
the low order N bits of FOO are known to be zero, we can do this
@@ -9597,13 +10358,16 @@ simplify_comparison (code, pop0, pop1)
continue;
}
break;
+
+ default:
+ break;
}
break;
}
/* Now make any compound operations involved in this comparison. Then,
- check for an outmost SUBREG on OP0 that isn't doing anything or is
+ check for an outmost SUBREG on OP0 that is not doing anything or is
paradoxical. The latter case can only occur when it is known that the
"extra" bits will be zero. Therefore, it is safe to remove the SUBREG.
We can never remove a SUBREG for a non-equality comparison because the
@@ -9727,9 +10491,10 @@ reversible_comparison_p (x)
x = get_last_value (XEXP (x, 0));
return (x && GET_CODE (x) == COMPARE
&& ! FLOAT_MODE_P (GET_MODE (XEXP (x, 0))));
+
+ default:
+ return 0;
}
-
- return 0;
}
/* Utility function for following routine. Called when X is part of a value
@@ -9832,11 +10597,12 @@ record_value_for_reg (reg, insn, value)
/* The value being assigned might refer to X (like in "x++;"). In that
case, we must replace it with (clobber (const_int 0)) to prevent
infinite loops. */
- if (value && ! get_last_value_validate (&value,
+ if (value && ! get_last_value_validate (&value, insn,
reg_last_set_label[regno], 0))
{
value = copy_rtx (value);
- if (! get_last_value_validate (&value, reg_last_set_label[regno], 1))
+ if (! get_last_value_validate (&value, insn,
+ reg_last_set_label[regno], 1))
value = 0;
}
@@ -9957,8 +10723,9 @@ record_dead_and_set_regs (insn)
we don't know exactly what registers it was produced from. */
static int
-get_last_value_validate (loc, tick, replace)
+get_last_value_validate (loc, insn, tick, replace)
rtx *loc;
+ rtx insn;
int tick;
int replace;
{
@@ -9978,20 +10745,30 @@ get_last_value_validate (loc, tick, replace)
if (reg_last_set_invalid[j]
/* If this is a pseudo-register that was only set once, it is
always valid. */
- || (! (regno >= FIRST_PSEUDO_REGISTER && reg_n_sets[regno] == 1)
+ || (! (regno >= FIRST_PSEUDO_REGISTER && REG_N_SETS (regno) == 1)
&& reg_last_set_label[j] > tick))
{
if (replace)
- *loc = gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+ *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
return replace;
}
return 1;
}
+ /* If this is a memory reference, make sure that there were
+ no stores after it that might have clobbered the value. We don't
+ have alias info, so we assume any store invalidates it. */
+ else if (GET_CODE (x) == MEM && ! RTX_UNCHANGING_P (x)
+ && INSN_CUID (insn) <= mem_last_set)
+ {
+ if (replace)
+ *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
+ return replace;
+ }
for (i = 0; i < len; i++)
if ((fmt[i] == 'e'
- && get_last_value_validate (&XEXP (x, i), tick, replace) == 0)
+ && get_last_value_validate (&XEXP (x, i), insn, tick, replace) == 0)
/* Don't bother with these. They shouldn't occur anyway. */
|| fmt[i] == 'E')
return 0;
@@ -10013,7 +10790,7 @@ get_last_value (x)
/* If this is a non-paradoxical SUBREG, get the value of its operand and
then convert it to the desired mode. If this is a paradoxical SUBREG,
- we cannot predict what values the "extra" bits might have. */
+ we cannot predict what values the "extra" bits might have. */
if (GET_CODE (x) == SUBREG
&& subreg_lowpart_p (x)
&& (GET_MODE_SIZE (GET_MODE (x))
@@ -10027,10 +10804,11 @@ get_last_value (x)
regno = REGNO (x);
value = reg_last_set_value[regno];
- /* If we don't have a value or if it isn't for this basic block, return 0. */
+ /* If we don't have a value or if it isn't for this basic block,
+ return 0. */
if (value == 0
- || (reg_n_sets[regno] != 1
+ || (REG_N_SETS (regno) != 1
&& reg_last_set_label[regno] != label_tick))
return 0;
@@ -10077,7 +10855,7 @@ get_last_value (x)
if (reg_mentioned_p (x, value))
value = replace_rtx (copy_rtx (value), x,
- gen_rtx (CLOBBER, GET_MODE (x), const0_rtx));
+ gen_rtx_CLOBBER (GET_MODE (x), const0_rtx));
if (reg_overlap_mentioned_p (x, value))
return 0;
@@ -10087,14 +10865,16 @@ get_last_value (x)
}
/* If the value has all its registers valid, return it. */
- if (get_last_value_validate (&value, reg_last_set_label[regno], 0))
+ if (get_last_value_validate (&value, reg_last_set[regno],
+ reg_last_set_label[regno], 0))
return value;
/* Otherwise, make a copy and replace any invalid register with
(clobber (const_int 0)). If that fails for some reason, return 0. */
value = copy_rtx (value);
- if (get_last_value_validate (&value, reg_last_set_label[regno], 1))
+ if (get_last_value_validate (&value, reg_last_set[regno],
+ reg_last_set_label[regno], 1))
return value;
return 0;
@@ -10240,8 +11020,7 @@ reg_dead_at_p (reg, insn)
}
for (i = reg_dead_regno; i < reg_dead_endregno; i++)
- if (basic_block_live_at_start[block][i / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS)))
+ if (REGNO_REG_SET_P (basic_block_live_at_start[block], i))
return 0;
return 1;
@@ -10322,8 +11101,11 @@ mark_used_regs_combine (x)
mark_used_regs_combine (XEXP (testreg, 0));
mark_used_regs_combine (SET_SRC (x));
- return;
}
+ return;
+
+ default:
+ break;
}
/* Recursively scan the operands of this expression. */
@@ -10360,7 +11142,7 @@ remove_death (regno, insn)
if (note)
{
- reg_n_deaths[regno]--;
+ REG_N_DEATHS (regno)--;
remove_note (insn, note);
}
@@ -10372,12 +11154,15 @@ remove_death (regno, insn)
TO_INSN (exclusive), put a REG_DEAD note for that register in the
list headed by PNOTES.
+ That said, don't move registers killed by maybe_kill_insn.
+
This is done when X is being merged by combination into TO_INSN. These
notes will then be distributed as needed. */
static void
-move_deaths (x, from_cuid, to_insn, pnotes)
+move_deaths (x, maybe_kill_insn, from_cuid, to_insn, pnotes)
rtx x;
+ rtx maybe_kill_insn;
int from_cuid;
rtx to_insn;
rtx *pnotes;
@@ -10392,6 +11177,11 @@ move_deaths (x, from_cuid, to_insn, pnotes)
register rtx where_dead = reg_last_death[regno];
register rtx before_dead, after_dead;
+ /* Don't move the register if it gets killed in between from and to */
+ if (maybe_kill_insn && reg_set_p (x, maybe_kill_insn)
+ && !reg_referenced_p (x, maybe_kill_insn))
+ return;
+
/* WHERE_DEAD could be a USE insn made by combine, so first we
make sure that we have insns with valid INSN_CUID values. */
before_dead = where_dead;
@@ -10420,7 +11210,7 @@ move_deaths (x, from_cuid, to_insn, pnotes)
if (note != 0 && regno < FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
- != GET_MODE_SIZE (GET_MODE (x))))
+ > GET_MODE_SIZE (GET_MODE (x))))
{
int deadregno = REGNO (XEXP (note, 0));
int deadend
@@ -10432,24 +11222,34 @@ move_deaths (x, from_cuid, to_insn, pnotes)
for (i = deadregno; i < deadend; i++)
if (i < regno || i >= ourend)
REG_NOTES (where_dead)
- = gen_rtx (EXPR_LIST, REG_DEAD,
- gen_rtx (REG, reg_raw_mode[i], i),
- REG_NOTES (where_dead));
+ = gen_rtx_EXPR_LIST (REG_DEAD,
+ gen_rtx_REG (reg_raw_mode[i], i),
+ REG_NOTES (where_dead));
}
- /* If we didn't find any note, and we have a multi-reg hard
+ /* If we didn't find any note, or if we found a REG_DEAD note that
+ covers only part of the given reg, and we have a multi-reg hard
register, then to be safe we must check for REG_DEAD notes
for each register other than the first. They could have
their own REG_DEAD notes lying around. */
- else if (note == 0 && regno < FIRST_PSEUDO_REGISTER
+ else if ((note == 0
+ || (note != 0
+ && (GET_MODE_SIZE (GET_MODE (XEXP (note, 0)))
+ < GET_MODE_SIZE (GET_MODE (x)))))
+ && regno < FIRST_PSEUDO_REGISTER
&& HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
{
int ourend = regno + HARD_REGNO_NREGS (regno, GET_MODE (x));
- int i;
+ int i, offset;
rtx oldnotes = 0;
- for (i = regno + 1; i < ourend; i++)
- move_deaths (gen_rtx (REG, reg_raw_mode[i], i),
- from_cuid, to_insn, &oldnotes);
+ if (note)
+ offset = HARD_REGNO_NREGS (regno, GET_MODE (XEXP (note, 0)));
+ else
+ offset = 1;
+
+ for (i = regno + offset; i < ourend; i++)
+ move_deaths (gen_rtx_REG (reg_raw_mode[i], i),
+ maybe_kill_insn, from_cuid, to_insn, &oldnotes);
}
if (note != 0 && GET_MODE (XEXP (note, 0)) == GET_MODE (x))
@@ -10458,9 +11258,9 @@ move_deaths (x, from_cuid, to_insn, pnotes)
*pnotes = note;
}
else
- *pnotes = gen_rtx (EXPR_LIST, REG_DEAD, x, *pnotes);
+ *pnotes = gen_rtx_EXPR_LIST (REG_DEAD, x, *pnotes);
- reg_n_deaths[regno]++;
+ REG_N_DEATHS (regno)++;
}
return;
@@ -10470,7 +11270,7 @@ move_deaths (x, from_cuid, to_insn, pnotes)
{
rtx dest = SET_DEST (x);
- move_deaths (SET_SRC (x), from_cuid, to_insn, pnotes);
+ move_deaths (SET_SRC (x), maybe_kill_insn, from_cuid, to_insn, pnotes);
/* In the case of a ZERO_EXTRACT, a STRICT_LOW_PART, or a SUBREG
that accesses one word of a multi-word item, some
@@ -10485,7 +11285,7 @@ move_deaths (x, from_cuid, to_insn, pnotes)
== ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
+ UNITS_PER_WORD - 1) / UNITS_PER_WORD))))
{
- move_deaths (dest, from_cuid, to_insn, pnotes);
+ move_deaths (dest, maybe_kill_insn, from_cuid, to_insn, pnotes);
return;
}
@@ -10499,7 +11299,8 @@ move_deaths (x, from_cuid, to_insn, pnotes)
being replaced so the old value is not used in this insn. */
if (GET_CODE (dest) == MEM)
- move_deaths (XEXP (dest, 0), from_cuid, to_insn, pnotes);
+ move_deaths (XEXP (dest, 0), maybe_kill_insn, from_cuid,
+ to_insn, pnotes);
return;
}
@@ -10515,10 +11316,11 @@ move_deaths (x, from_cuid, to_insn, pnotes)
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- move_deaths (XVECEXP (x, i, j), from_cuid, to_insn, pnotes);
+ move_deaths (XVECEXP (x, i, j), maybe_kill_insn, from_cuid,
+ to_insn, pnotes);
}
else if (fmt[i] == 'e')
- move_deaths (XEXP (x, i), from_cuid, to_insn, pnotes);
+ move_deaths (XEXP (x, i), maybe_kill_insn, from_cuid, to_insn, pnotes);
}
}
@@ -10603,6 +11405,14 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
next_note = XEXP (note, 1);
switch (REG_NOTE_KIND (note))
{
+ case REG_BR_PROB:
+ case REG_EXEC_COUNT:
+ /* Doesn't matter much where we put this, as long as it's somewhere.
+ It is preferable to keep these notes on branches, which is most
+ likely to be i3. */
+ place = i3;
+ break;
+
case REG_UNUSED:
/* Any clobbers for i3 may still exist, and so we must process
REG_UNUSED notes from that insn.
@@ -10647,6 +11457,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
case REG_EQUAL:
case REG_EQUIV:
case REG_NONNEG:
+ case REG_NOALIAS:
/* These notes say something about results of an insn. We can
only support them if they used to be on I3 in which case they
remain on I3. Otherwise they are ignored.
@@ -10749,9 +11560,9 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
special case. */
if (place == i3 && i2 != 0 && GET_CODE (XEXP (note, 0)) == REG
- && reg_n_refs[REGNO (XEXP (note, 0))]== 2
+ && REG_N_REFS (REGNO (XEXP (note, 0)))== 2
&& reg_referenced_p (XEXP (note, 0), PATTERN (i2)))
- reg_n_refs[REGNO (XEXP (note, 0))] = 3;
+ REG_N_REFS (REGNO (XEXP (note, 0))) = 3;
if (place == 0)
{
@@ -10766,15 +11577,21 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
if (reg_set_p (XEXP (note, 0), PATTERN (tem)))
{
rtx set = single_set (tem);
+ rtx inner_dest = 0;
+
+ if (set != 0)
+ for (inner_dest = SET_DEST (set);
+ GET_CODE (inner_dest) == STRICT_LOW_PART
+ || GET_CODE (inner_dest) == SUBREG
+ || GET_CODE (inner_dest) == ZERO_EXTRACT;
+ inner_dest = XEXP (inner_dest, 0))
+ ;
/* Verify that it was the set, and not a clobber that
modified the register. */
if (set != 0 && ! side_effects_p (SET_SRC (set))
- && (rtx_equal_p (XEXP (note, 0), SET_DEST (set))
- || (GET_CODE (SET_DEST (set)) == SUBREG
- && rtx_equal_p (XEXP (note, 0),
- XEXP (SET_DEST (set), 0)))))
+ && rtx_equal_p (XEXP (note, 0), inner_dest))
{
/* Move the notes and links of TEM elsewhere.
This might delete other dead insns recursively.
@@ -10791,6 +11608,21 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
NOTE_LINE_NUMBER (tem) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (tem) = 0;
}
+ /* If the register is both set and used here, put the
+ REG_DEAD note here, but place a REG_UNUSED note
+ here too unless there already is one. */
+ else if (reg_referenced_p (XEXP (note, 0),
+ PATTERN (tem)))
+ {
+ place = tem;
+
+ if (! find_regno_note (tem, REG_UNUSED,
+ REGNO (XEXP (note, 0))))
+ REG_NOTES (tem)
+ = gen_rtx_EXPR_LIST (REG_UNUSED,
+ XEXP (note, 0),
+ REG_NOTES (tem));
+ }
else
{
PUT_REG_NOTE_KIND (note, REG_UNUSED);
@@ -10836,7 +11668,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
if (REG_NOTE_KIND (note) == REG_DEAD && place == 0 && tem != 0)
{
place
- = emit_insn_after (gen_rtx (USE, VOIDmode, XEXP (note, 0)),
+ = emit_insn_after (gen_rtx_USE (VOIDmode, XEXP (note, 0)),
tem);
/* If this insn was emitted between blocks, then update
@@ -10847,13 +11679,12 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
}
/* If the register is set or already dead at PLACE, we needn't do
- anything with this note if it is still a REG_DEAD note.
+ anything with this note if it is still a REG_DEAD note.
+ We can here if it is set at all, not if is it totally replace,
+ which is what `dead_or_set_p' checks, so also check for it being
+ set partially. */
+
- Note that we cannot use just `dead_or_set_p' here since we can
- convert an assignment to a register into a bit-field assignment.
- Therefore, we must also omit the note if the register is the
- target of a bitfield assignment. */
-
if (place && REG_NOTE_KIND (note) == REG_DEAD)
{
int regno = REGNO (XEXP (note, 0));
@@ -10895,7 +11726,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
if (! refers_to_regno_p (i, i + 1, PATTERN (place), 0)
&& ! find_regno_fusage (place, USE, i))
{
- rtx piece = gen_rtx (REG, reg_raw_mode[i], i);
+ rtx piece = gen_rtx_REG (reg_raw_mode[i], i);
rtx p;
/* See if we already placed a USE note for this
@@ -10914,12 +11745,12 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
if (p)
{
rtx use_insn
- = emit_insn_before (gen_rtx (USE, VOIDmode,
- piece),
+ = emit_insn_before (gen_rtx_USE (VOIDmode,
+ piece),
p);
REG_NOTES (use_insn)
- = gen_rtx (EXPR_LIST, REG_DEAD, piece,
- REG_NOTES (use_insn));
+ = gen_rtx_EXPR_LIST (REG_DEAD, piece,
+ REG_NOTES (use_insn));
}
all_used = 0;
@@ -10942,7 +11773,7 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
for (i = regno; i < endregno; i++)
{
- rtx piece = gen_rtx (REG, reg_raw_mode[i], i);
+ rtx piece = gen_rtx_REG (reg_raw_mode[i], i);
if ((reg_referenced_p (piece, PATTERN (place))
|| (GET_CODE (place) == CALL_INSN
@@ -10950,9 +11781,9 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
&& ! dead_or_set_p (place, piece)
&& ! reg_bitfield_target_p (piece,
PATTERN (place)))
- REG_NOTES (place) = gen_rtx (EXPR_LIST, REG_DEAD,
- piece,
- REG_NOTES (place));
+ REG_NOTES (place)
+ = gen_rtx_EXPR_LIST (REG_DEAD,
+ piece, REG_NOTES (place));
}
place = 0;
@@ -10975,17 +11806,19 @@ distribute_notes (notes, from_insn, i3, i2, elim_i2, elim_i1)
else if ((REG_NOTE_KIND (note) == REG_DEAD
|| REG_NOTE_KIND (note) == REG_UNUSED)
&& GET_CODE (XEXP (note, 0)) == REG)
- reg_n_deaths[REGNO (XEXP (note, 0))]--;
+ REG_N_DEATHS (REGNO (XEXP (note, 0)))--;
if (place2)
{
if ((REG_NOTE_KIND (note) == REG_DEAD
|| REG_NOTE_KIND (note) == REG_UNUSED)
&& GET_CODE (XEXP (note, 0)) == REG)
- reg_n_deaths[REGNO (XEXP (note, 0))]++;
+ REG_N_DEATHS (REGNO (XEXP (note, 0)))++;
- REG_NOTES (place2) = gen_rtx (GET_CODE (note), REG_NOTE_KIND (note),
- XEXP (note, 0), REG_NOTES (place2));
+ REG_NOTES (place2) = gen_rtx_fmt_ee (GET_CODE (note),
+ REG_NOTE_KIND (note),
+ XEXP (note, 0),
+ REG_NOTES (place2));
}
}
}
@@ -11082,6 +11915,22 @@ distribute_links (links)
}
}
+/* Compute INSN_CUID for INSN, which is an insn made by combine. */
+
+static int
+insn_cuid (insn)
+ rtx insn;
+{
+ while (insn != 0 && INSN_UID (insn) > max_uid_cuid
+ && GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == USE)
+ insn = NEXT_INSN (insn);
+
+ if (INSN_UID (insn) > max_uid_cuid)
+ abort ();
+
+ return INSN_CUID (insn);
+}
+
void
dump_combine_stats (file)
FILE *file;
diff --git a/contrib/gcc/conditions.h b/contrib/gcc/conditions.h
index c92226c..80d6047 100644
--- a/contrib/gcc/conditions.h
+++ b/contrib/gcc/conditions.h
@@ -85,6 +85,8 @@ extern CC_STATUS cc_status;
/* This bit means that the current setting of the overflow flag
is bogus and conditional jumps should pretend there is no overflow. */
+/* ??? Note that for most targets this macro is misnamed as it applies
+ to the carry flag, not the overflow flag. */
#define CC_NO_OVERFLOW 010
/* This bit means that what ought to be in the Z bit
diff --git a/contrib/gcc/config.guess b/contrib/gcc/config.guess
index 5508638..fd7602d 100755
--- a/contrib/gcc/config.guess
+++ b/contrib/gcc/config.guess
@@ -1,575 +1,4 @@
-#! /bin/sh
-# Attempt to guess a canonical system name.
-# Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-#
-# This file 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.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# Written by Per Bothner <bothner@cygnus.com>.
-# The master version of this file is at the FSF in /home/gd/gnu/lib.
-#
-# This script attempts to guess a canonical system name similar to
-# config.sub. If it succeeds, it prints the system name on stdout, and
-# exits with 0. Otherwise, it exits with 1.
-#
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit system type (host/target name).
-#
-# Only a few systems have been added to this list; please add others
-# (but try to keep the structure clean).
-#
-
-# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# (ghazi@noc.rutgers.edu 8/24/94.)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
- PATH=$PATH:/.attbin ; export PATH
-fi
-
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-
-trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
-
-# Note: order is significant - the case branches are not exclusive.
-
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
- alpha:OSF1:V*:*)
- # After 1.2, OSF1 uses "V1.3" for uname -r.
- echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^V//'`
- exit 0 ;;
- alpha:OSF1:*:*)
- # 1.2 uses "1.2" for uname -r.
- echo alpha-dec-osf${UNAME_RELEASE}
- exit 0 ;;
- 21064:Windows_NT:50:3)
- echo alpha-dec-winnt3.5
- exit 0 ;;
- amiga:NetBSD:*:*)
- echo m68k-cbm-netbsd${UNAME_RELEASE}
- exit 0 ;;
- arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
- echo arm-acorn-riscix${UNAME_RELEASE}
- exit 0;;
- Pyramid*:OSx*:*:*)
- if test "`(/bin/universe) 2>/dev/null`" = att ; then
- echo pyramid-pyramid-sysv3
- else
- echo pyramid-pyramid-bsd
- fi
- exit 0 ;;
- sun4*:SunOS:5.*:*)
- echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- i86pc:SunOS:5.*:*)
- echo i386-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- sun4*:SunOS:6*:*)
- # According to config.sub, this is the proper way to canonicalize
- # SunOS6. Hard to guess exactly what SunOS6 will be like, but
- # it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit 0 ;;
- sun4*:SunOS:*:*)
- case "`/usr/bin/arch -k`" in
- Series*|S4*)
- UNAME_RELEASE=`uname -v`
- ;;
- esac
- # Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
- exit 0 ;;
- sun3*:SunOS:*:*)
- echo m68k-sun-sunos${UNAME_RELEASE}
- exit 0 ;;
- atari*:NetBSD:*:*)
- echo m68k-atari-netbsd${UNAME_RELEASE}
- exit 0 ;;
- sun3*:NetBSD:*:*)
- echo m68k-sun-netbsd${UNAME_RELEASE}
- exit 0 ;;
- mac68k:NetBSD:*:*)
- echo m68k-apple-netbsd${UNAME_RELEASE}
- exit 0 ;;
- RISC*:ULTRIX:*:*)
- echo mips-dec-ultrix${UNAME_RELEASE}
- exit 0 ;;
- VAX*:ULTRIX*:*:*)
- echo vax-dec-ultrix${UNAME_RELEASE}
- exit 0 ;;
- mips:*:4*:UMIPS)
- echo mips-mips-riscos4sysv
- exit 0 ;;
- mips:*:5*:RISCos)
- echo mips-mips-riscos${UNAME_RELEASE}
- exit 0 ;;
- m88k:CX/UX:7*:*)
- echo m88k-harris-cxux7
- exit 0 ;;
- m88k:*:4*:R4*)
- echo m88k-motorola-sysv4
- exit 0 ;;
- m88k:*:3*:R3*)
- echo m88k-motorola-sysv3
- exit 0 ;;
- AViiON:dgux:*:*)
- if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
- -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
- echo m88k-dg-dgux${UNAME_RELEASE}
- else
- echo m88k-dg-dguxbcs${UNAME_RELEASE}
- fi
- exit 0 ;;
- M88*:DolphinOS:*:*) # DolphinOS (SVR3)
- echo m88k-dolphin-sysv3
- exit 0 ;;
- M88*:*:R3*:*)
- # Delta 88k system running SVR3
- echo m88k-motorola-sysv3
- exit 0 ;;
- XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
- echo m88k-tektronix-sysv3
- exit 0 ;;
- Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
- echo m68k-tektronix-bsd
- exit 0 ;;
- *:IRIX*:*:*)
- echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
- exit 0 ;;
- ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
- i[34]86:AIX:*:*)
- echo i386-ibm-aix
- exit 0 ;;
- *:AIX:2:3)
- if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
- sed 's/^ //' << EOF >dummy.c
- #include <sys/systemcfg.h>
-
- main()
- {
- if (!__power_pc())
- exit(1);
- puts("powerpc-ibm-aix3.2.5");
- exit(0);
- }
-EOF
- ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
- rm -f dummy.c dummy
- echo rs6000-ibm-aix3.2.5
- elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
- echo rs6000-ibm-aix3.2.4
- else
- echo rs6000-ibm-aix3.2
- fi
- exit 0 ;;
- *:AIX:*:4)
- if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
- IBM_ARCH=rs6000
- else
- IBM_ARCH=powerpc
- fi
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
- else
- IBM_REV=4.${UNAME_RELEASE}
- fi
- echo ${IBM_ARCH}-ibm-aix${IBM_REV}
- exit 0 ;;
- *:AIX:*:*)
- echo rs6000-ibm-aix
- exit 0 ;;
- ibmrt:4.4BSD:*|romp-ibm:BSD:*)
- echo romp-ibm-bsd4.4
- exit 0 ;;
- ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
- echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
- exit 0 ;; # report: romp-ibm BSD 4.3
- *:BOSX:*:*)
- echo rs6000-bull-bosx
- exit 0 ;;
- DPX/2?00:B.O.S.:*:*)
- echo m68k-bull-sysv3
- exit 0 ;;
- 9000/[34]??:4.3bsd:1.*:*)
- echo m68k-hp-bsd
- exit 0 ;;
- hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
- echo m68k-hp-bsd4.4
- exit 0 ;;
- 9000/[3478]??:HP-UX:*:*)
- case "${UNAME_MACHINE}" in
- 9000/31? ) HP_ARCH=m68000 ;;
- 9000/[34]?? ) HP_ARCH=m68k ;;
- 9000/7?? | 9000/8?[79] ) HP_ARCH=hppa1.1 ;;
- 9000/8?? ) HP_ARCH=hppa1.0 ;;
- esac
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- echo ${HP_ARCH}-hp-hpux${HPUX_REV}
- exit 0 ;;
- 3050*:HI-UX:*:*)
- sed 's/^ //' << EOF >dummy.c
- #include <unistd.h>
- int
- main ()
- {
- long cpu = sysconf (_SC_CPU_VERSION);
- /* The order matters, because CPU_IS_HP_MC68K erroneously returns
- true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
- results, however. */
- if (CPU_IS_PA_RISC (cpu))
- {
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
- default: puts ("hppa-hitachi-hiuxwe2"); break;
- }
- }
- else if (CPU_IS_HP_MC68K (cpu))
- puts ("m68k-hitachi-hiuxwe2");
- else puts ("unknown-hitachi-hiuxwe2");
- exit (0);
- }
-EOF
- ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
- rm -f dummy.c dummy
- echo unknown-hitachi-hiuxwe2
- exit 0 ;;
- 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
- echo hppa1.1-hp-bsd
- exit 0 ;;
- 9000/8??:4.3bsd:*:*)
- echo hppa1.0-hp-bsd
- exit 0 ;;
- hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
- echo hppa1.1-hp-osf
- exit 0 ;;
- hp8??:OSF1:*:*)
- echo hppa1.0-hp-osf
- exit 0 ;;
- parisc*:Lites*:*:*)
- echo hppa1.1-hp-lites
- exit 0 ;;
- C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
- echo c1-convex-bsd
- exit 0 ;;
- C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit 0 ;;
- C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
- echo c34-convex-bsd
- exit 0 ;;
- C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
- echo c38-convex-bsd
- exit 0 ;;
- C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
- echo c4-convex-bsd
- exit 0 ;;
- CRAY*X-MP:*:*:*)
- echo xmp-cray-unicos
- exit 0 ;;
- CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos${UNAME_RELEASE}
- exit 0 ;;
- CRAY*C90:*:*:*)
- echo c90-cray-unicos${UNAME_RELEASE}
- exit 0 ;;
- CRAY-2:*:*:*)
- echo cray2-cray-unicos
- exit 0 ;;
- hp3[0-9][05]:NetBSD:*:*)
- echo m68k-hp-netbsd${UNAME_RELEASE}
- exit 0 ;;
- i[34]86:BSD/386:*:* | *:BSD/OS:*:*)
- echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
- exit 0 ;;
- *:FreeBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
- exit 0 ;;
- *:NetBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
- exit 0 ;;
- *:GNU:*:*)
- echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
- exit 0 ;;
- *:Linux:*:*)
- # The BFD linker knows what the default object file format is, so
- # first see if it will tell us.
- ld_help_string=`ld --help 2>&1`
-# if echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: elf_i[345]86"; then
-# echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
- if echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: i[345]86linux"; then
- echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
- elif echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: i[345]86coff"; then
- echo "${UNAME_MACHINE}-unknown-linuxcoff" ; exit 0
- elif test "${UNAME_MACHINE}" = "alpha" ; then
- echo alpha-unknown-linux ; exit 0
- else
- # Either a pre-BFD a.out linker (linuxoldld) or one that does not give us
- # useful --help. Gcc wants to distinguish between linuxoldld and linuxaout,
- # and between different C library versions.
- echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:"
- test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0
- # Determine whether the default compiler is a.out or elf
- cat >dummy.c <<EOF
-#include <features.h>
-main(argc, argv)
-int argc;
-char *argv[];
-{
-#ifdef __ELF__
-# ifdef __GLIBC__
-# if __GLIBC__ >= 2
- printf ("%s-unknown-linux\n", argv[1]);
-# else
- printf ("%s-unknown-linux-gnulibc1\n", argv[1]);
-# endif
-# else
- printf ("%s-unknown-linux-gnulibc1\n", argv[1]);
-# endif
-#else
- printf ("%s-unknown-linuxaout\n", argv[1]);
-#endif
- return 0;
-}
-EOF
- ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
- rm -f dummy.c dummy
- fi ;;
-# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
-# are messed up and put the nodename in both sysname and nodename.
- i[34]86:DYNIX/ptx:4*:*)
- echo i386-sequent-sysv4
- exit 0 ;;
- i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
- if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
- echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
- else
- echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
- fi
- exit 0 ;;
- i[34]86:*:3.2:*)
- if test -f /usr/options/cb.name; then
- UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
- echo ${UNAME_MACHINE}-unknown-isc$UNAME_REL
- elif /bin/uname -X 2>/dev/null >/dev/null ; then
- UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
- (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
- echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
- else
- echo ${UNAME_MACHINE}-unknown-sysv32
- fi
- exit 0 ;;
- Intel:Mach:3*:*)
- echo i386-unknown-mach3
- exit 0 ;;
- paragon:*:*:*)
- echo i860-intel-osf1
- exit 0 ;;
- i860:*:4.*:*) # i860-SVR4
- if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
- echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
- else # Add other i860-SVR4 vendors below as they are discovered.
- echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
- fi
- exit 0 ;;
- mini*:CTIX:SYS*5:*)
- # "miniframe"
- echo m68010-convergent-sysv
- exit 0 ;;
- M680[234]0:*:R3V[567]*:*)
- test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
- 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
- uname -p 2>/dev/null | grep 86 >/dev/null \
- && echo i486-ncr-sysv4.3 && exit 0 ;;
- 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
- uname -p 2>/dev/null | grep 86 >/dev/null \
- && echo i486-ncr-sysv4 && exit 0 ;;
- m680[234]0:LynxOS:2.[23]*:*)
- echo m68k-lynx-lynxos${UNAME_RELEASE}
- exit 0 ;;
- mc68030:UNIX_System_V:4.*:*)
- echo m68k-atari-sysv4
- exit 0 ;;
- i[34]86:LynxOS:2.[23]*:*)
- echo i386-lynx-lynxos${UNAME_RELEASE}
- exit 0 ;;
- TSUNAMI:LynxOS:2.[23]*:*)
- echo sparc-lynx-lynxos${UNAME_RELEASE}
- exit 0 ;;
- rs6000:LynxOS:2.[23]*:*)
- echo rs6000-lynx-lynxos${UNAME_RELEASE}
- exit 0 ;;
- RM*:SINIX-*:*:*)
- echo mips-sni-sysv4
- exit 0 ;;
- *:SINIX-*:*:*)
- if uname -p 2>/dev/null >/dev/null ; then
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
- echo ${UNAME_MACHINE}-sni-sysv4
- else
- echo ns32k-sni-sysv
- fi
- exit 0 ;;
-esac
-
-#echo '(No uname command or uname output not recognized.)' 1>&2
-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
-
-cat >dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
- /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
- I don't know.... */
- printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
- printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
- "4"
-#else
- ""
-#endif
- ); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
- printf ("arm-acorn-riscix"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
- printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
- int version;
- version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
- printf ("%s-next-nextstep%s\n", __ARCHITECTURE__, version==2 ? "2" : "3");
- exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
- printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
- printf ("ns32k-encore-mach\n"); exit (0);
-#else
- printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
- printf ("i386-unknown-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
- printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
- printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
- struct utsname un;
-
- uname(&un);
-
- if (strncmp(un.version, "V2", 2) == 0) {
- printf ("i386-sequent-ptx2\n"); exit (0);
- }
- if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
- printf ("i386-sequent-ptx1\n"); exit (0);
- }
- printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-#if !defined (ultrix)
- printf ("vax-dec-bsd\n"); exit (0);
-#else
- printf ("vax-dec-ultrix\n"); exit (0);
-#endif
-#endif
-
-#if defined (alliant) && defined (i860)
- printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
- exit (1);
-}
-EOF
-
-${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
-rm -f dummy.c dummy
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
- case `getsysinfo -f cpu_type` in
- c1*)
- echo c1-convex-bsd
- exit 0 ;;
- c2*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit 0 ;;
- c34*)
- echo c34-convex-bsd
- exit 0 ;;
- c38*)
- echo c38-convex-bsd
- exit 0 ;;
- c4*)
- echo c4-convex-bsd
- exit 0 ;;
- esac
-fi
-
-#echo '(Unable to guess system type)' 1>&2
-
-exit 1
+#!/bin/sh
+# Use the top-level config.guess so that we don't have two of them.
+guesssys=`echo $0 | sed 's|config.guess|../config.guess|'`
+exec ${guesssys} "$@"
diff --git a/contrib/gcc/config.in b/contrib/gcc/config.in
new file mode 100644
index 0000000..b4e9898
--- /dev/null
+++ b/contrib/gcc/config.in
@@ -0,0 +1,202 @@
+/* config.in. Generated automatically from configure.in by autoheader. */
+/* Define if printf supports "%p". */
+#undef HAVE_PRINTF_PTR
+
+/* Define if you want expensive run-time checks. */
+#undef ENABLE_CHECKING
+
+/* Define if your cpp understands the stringify operator. */
+#undef HAVE_CPP_STRINGIFY
+
+/* Define if your compiler understands volatile. */
+#undef HAVE_VOLATILE
+
+/* Define if your assembler supports specifying the maximum number
+ of bytes to skip when using the GAS .p2align command. */
+#undef HAVE_GAS_MAX_SKIP_P2ALIGN
+
+/* Define if your assembler supports .balign and .p2align. */
+#undef HAVE_GAS_BALIGN_AND_P2ALIGN
+
+/* Define if you have a working <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Whether malloc must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_MALLOC
+
+/* Whether realloc must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_REALLOC
+
+/* Whether calloc must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_CALLOC
+
+/* Whether free must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_FREE
+
+/* Whether bcopy must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_BCOPY
+
+/* Whether bcmp must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_BCMP
+
+/* Whether bzero must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_BZERO
+
+/* Whether index must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_INDEX
+
+/* Whether rindex must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_RINDEX
+
+/* Whether getenv must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_GETENV
+
+/* Whether atol must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_ATOL
+
+/* Whether sbrk must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_SBRK
+
+/* Whether abort must be declared even if <stdlib.h> is included. */
+#undef NEED_DECLARATION_ABORT
+
+/* Whether strerror must be declared even if <string.h> is included. */
+#undef NEED_DECLARATION_STRERROR
+
+/* Whether getcwd must be declared even if <unistd.h> is included. */
+#undef NEED_DECLARATION_GETCWD
+
+/* Whether getwd must be declared even if <unistd.h> is included. */
+#undef NEED_DECLARATION_GETWD
+
+/* Whether getrlimit must be declared even if <sys/resource.h> is included. */
+#undef NEED_DECLARATION_GETRLIMIT
+
+/* Whether setrlimit must be declared even if <sys/resource.h> is included. */
+#undef NEED_DECLARATION_SETRLIMIT
+
+/* Define if you want expensive run-time checks. */
+#undef ENABLE_CHECKING
+
+/* Define if you don't have vprintf but do have _doprnt. */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function. */
+#undef HAVE_VPRINTF
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if `sys_siglist' is declared by <signal.h>. */
+#undef SYS_SIGLIST_DECLARED
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define if you have the atoll function. */
+#undef HAVE_ATOLL
+
+/* Define if you have the atoq function. */
+#undef HAVE_ATOQ
+
+/* Define if you have the bcmp function. */
+#undef HAVE_BCMP
+
+/* Define if you have the bcopy function. */
+#undef HAVE_BCOPY
+
+/* Define if you have the bsearch function. */
+#undef HAVE_BSEARCH
+
+/* Define if you have the bzero function. */
+#undef HAVE_BZERO
+
+/* Define if you have the getrlimit function. */
+#undef HAVE_GETRLIMIT
+
+/* Define if you have the gettimeofday function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define if you have the index function. */
+#undef HAVE_INDEX
+
+/* Define if you have the isascii function. */
+#undef HAVE_ISASCII
+
+/* Define if you have the kill function. */
+#undef HAVE_KILL
+
+/* Define if you have the popen function. */
+#undef HAVE_POPEN
+
+/* Define if you have the putenv function. */
+#undef HAVE_PUTENV
+
+/* Define if you have the rindex function. */
+#undef HAVE_RINDEX
+
+/* Define if you have the setrlimit function. */
+#undef HAVE_SETRLIMIT
+
+/* Define if you have the strchr function. */
+#undef HAVE_STRCHR
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strrchr function. */
+#undef HAVE_STRRCHR
+
+/* Define if you have the strtoul function. */
+#undef HAVE_STRTOUL
+
+/* Define if you have the sysconf function. */
+#undef HAVE_SYSCONF
+
+/* Define if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <stab.h> header file. */
+#undef HAVE_STAB_H
+
+/* Define if you have the <stddef.h> header file. */
+#undef HAVE_STDDEF_H
+
+/* Define if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/times.h> header file. */
+#undef HAVE_SYS_TIMES_H
+
+/* Define if you have the <sys/wait.h> header file. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the <wait.h> header file. */
+#undef HAVE_WAIT_H
diff --git a/contrib/gcc/config.sub b/contrib/gcc/config.sub
index 9bb45e9..b491c9f 100755
--- a/contrib/gcc/config.sub
+++ b/contrib/gcc/config.sub
@@ -1,9 +1,9 @@
#! /bin/sh
# Configuration validation subroutine script, version 1.1.
-# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+# Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc.
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
-# can handle that machine. It does not imply ALL GNU software can.
+# can handle that machine. It does not imply ALL GNU software can.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -41,6 +41,8 @@
# The goal of this file is to map all the various variations of a given
# machine specification into a single specification in the form:
# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.
if [ x$1 = x ]
@@ -62,7 +64,7 @@ case $1 in
;;
esac
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
@@ -91,38 +93,43 @@ case $os in
-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
- -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp )
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple)
os=
basic_machine=$1
;;
-hiux*)
os=-hiuxwe2
;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
-sco4)
os=-sco3.2v4
- basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco3.2.[4-9]*)
os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
- basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco3.2v[4-9]*)
# Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-sco*)
os=-sco3.2v2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-isc)
os=-isc2.2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-clix*)
basic_machine=clipper-intergraph
;;
-isc*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
;;
-lynx*)
os=-lynxos
@@ -133,35 +140,52 @@ case $os in
-windowsnt*)
os=`echo $os | sed -e 's/windowsnt/winnt/'`
;;
+ -psos*)
+ os=-psos
+ ;;
esac
# Decode aliases for certain CPU-COMPANY combinations.
case $basic_machine in
# Recognize the basic CPU types without company name.
# Some are omitted here because they have special meanings below.
- tahoe | i[3456]86 | i860 | m68k | m68000 | m88k | ns32k | arm \
- | arme[lb] | pyramid \
- | tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
- | alpha | we32k | ns16k | clipper | sparclite | i370 | sh \
- | powerpc | powerpcle | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
- | pdp11 | mips64el | mips64orion | mips64orionel \
- | sparc)
+ tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \
+ | arme[lb] | pyramid | mn10200 | mn10300 \
+ | tron | a29k | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 \
+ | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \
+ | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \
+ | mips64 | mipsel | mips64el | mips64orion | mips64orionel \
+ | mipstx39 | mipstx39el \
+ | sparc | sparclet | sparclite | sparc64 | v850)
basic_machine=$basic_machine-unknown
;;
+ thumb | thumbel)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i[34567]86)
+ basic_machine=$basic_machine-pc
+ ;;
# Object if more than one company name word.
*-*-*)
echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
exit 1
;;
# Recognize the basic CPU types with company name.
- vax-* | tahoe-* | i[3456]86-* | i860-* | m68k-* | m68000-* | m88k-* \
- | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
- | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \
- | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
- | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
- | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
- | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \
- | mips64el-* | mips64orion-* | mips64orionel-*)
+ vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \
+ | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \
+ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \
+ | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \
+ | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* \
+ | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \
+ | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \
+ | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \
+ | sparc64-* | mips64-* | mipsel-* \
+ | mips64el-* | mips64orion-* | mips64orionel-* \
+ | mipstx39-* | mipstx39el-* \
+ | f301-*)
;;
# Recognize the various machine names and aliases which stand
# for a CPU type and a company and sometimes even an OS.
@@ -188,9 +212,9 @@ case $basic_machine in
amiga | amiga-*)
basic_machine=m68k-cbm
;;
- amigados)
+ amigaos | amigados)
basic_machine=m68k-cbm
- os=-amigados
+ os=-amigaos
;;
amigaunix | amix)
basic_machine=m68k-cbm
@@ -200,6 +224,10 @@ case $basic_machine in
basic_machine=m68k-apollo
os=-sysv
;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
balance)
basic_machine=ns32k-sequent
os=-dynix
@@ -232,6 +260,10 @@ case $basic_machine in
basic_machine=cray2-cray
os=-unicos
;;
+ [ctj]90-cray)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
crds | unos)
basic_machine=m68k-crds
;;
@@ -307,31 +339,49 @@ case $basic_machine in
hp9k3[2-9][0-9])
basic_machine=m68k-hp
;;
- hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+ hp9k6[0-9][0-9] | hp6[0-9][0-9] )
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9] )
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9] )
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | \
+ hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893 )
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679] )
basic_machine=hppa1.1-hp
;;
hp9k8[0-9][0-9] | hp8[0-9][0-9])
basic_machine=hppa1.0-hp
;;
+ hppa-next)
+ os=-nextstep3
+ ;;
i370-ibm* | ibm*)
basic_machine=i370-ibm
os=-mvs
;;
# I'm not sure what "Sysv32" means. Should this be sysv3.2?
- i[3456]86v32)
- basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ i[34567]86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv32
;;
- i[3456]86v4*)
- basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ i[34567]86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv4
;;
- i[3456]86v)
- basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ i[34567]86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-sysv
;;
- i[3456]86sol2)
- basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ i[34567]86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
os=-solaris2
;;
iris | iris4d)
@@ -362,6 +412,14 @@ case $basic_machine in
miniframe)
basic_machine=m68000-convergent
;;
+ mipsel*-linux*)
+ basic_machine=mipsel-unknown
+ os=-linux-gnu
+ ;;
+ mips*-linux*)
+ basic_machine=mips-unknown
+ os=-linux-gnu
+ ;;
mips3*-*)
basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
;;
@@ -429,21 +487,23 @@ case $basic_machine in
pc532 | pc532-*)
basic_machine=ns32k-pc532
;;
- pentium | p5 | p6)
- # We don't have specific support for the Intel Pentium (p6) followon yet, so just call it a Pentium
- basic_machine=i586-intel
+ pentium | p5 | k5 | nexen)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | k6 | 6x86)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2)
+ basic_machine=i786-pc
;;
- pentium-* | p5-* | p6-*)
- # We don't have specific support for the Intel Pentium (p6) followon yet, so just call it a Pentium
+ pentium-* | p5-* | k5-* | nexen-*)
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
- k5)
- # We don't have specific support for AMD's K5 yet, so just call it a Pentium
- basic_machine=i586-amd
+ pentiumpro-* | p6-* | k6-* | 6x86-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
- nexen)
- # We don't have specific support for Nexgen yet, so just call it a Pentium
- basic_machine=i586-nexgen
+ pentiumii-* | pentium2-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
pn)
basic_machine=pn-gould
@@ -527,6 +587,12 @@ case $basic_machine in
basic_machine=i386-sequent
os=-dynix
;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
tower | tower-32)
basic_machine=m68k-ncr
;;
@@ -546,6 +612,9 @@ case $basic_machine in
basic_machine=vax-dec
os=-vms
;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
vxworks960)
basic_machine=i960-wrs
os=-vxworks
@@ -573,7 +642,11 @@ case $basic_machine in
# Here we handle the default manufacturer of certain CPU types. It is in
# some cases the only manufacturer, in others, it is the most popular.
mips)
- basic_machine=mips-mips
+ if [ x$os = x-linux-gnu ]; then
+ basic_machine=mips-unknown
+ else
+ basic_machine=mips-mips
+ fi
;;
romp)
basic_machine=romp-ibm
@@ -625,6 +698,8 @@ esac
if [ x"$os" != x"" ]
then
case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
# -solaris* is a basic system type, with this one exception.
-solaris1 | -solaris1.*)
os=`echo $os | sed -e 's|solaris1|sunos4|'`
@@ -632,28 +707,37 @@ case $os in
-solaris)
os=-solaris2
;;
- -unixware* | svr4*)
+ -svr4*)
os=-sysv4
;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
-gnu/linux*)
- os=`echo $os | sed -e 's|gnu/linux|linux|'`
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
;;
# First accept the basic system types.
# The portable systems comes first.
# Each alternative MUST END IN A *, to match a version number.
# -sysv* is not here because it comes later, after sysvr4.
-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
- | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[345]* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\
| -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
- | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
- | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
- | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
- | -udi* | -eabi* | -lites* )
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -cygwin32* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -uxpv* | -beos* )
# Remember, each alternative MUST END IN *, to match a version number.
;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
-sunos5*)
os=`echo $os | sed -e 's|sunos5|solaris2|'`
;;
@@ -678,6 +762,9 @@ case $os in
-ctix* | -uts*)
os=-sysv
;;
+ -ns2 )
+ os=-nextstep2
+ ;;
# Preserve the version number of sinix5.
-sinix5.*)
os=`echo $os | sed -e 's|sinix|sysv|'`
@@ -771,7 +858,7 @@ case $basic_machine in
os=-sysv
;;
*-cbm)
- os=-amigados
+ os=-amigaos
;;
*-dg)
os=-dgux
@@ -785,6 +872,9 @@ case $basic_machine in
m88k-omron*)
os=-luna
;;
+ *-next )
+ os=-nextstep
+ ;;
*-sequent)
os=-ptx
;;
@@ -818,6 +908,12 @@ case $basic_machine in
*-masscomp)
os=-rtu
;;
+ f301-fujitsu)
+ os=-uxpv
+ ;;
+ *-be)
+ os=-beos
+ ;;
*)
os=-none
;;
@@ -836,9 +932,6 @@ case $basic_machine in
-sunos*)
vendor=sun
;;
- -lynxos*)
- vendor=lynx
- ;;
-aix*)
vendor=ibm
;;
@@ -866,9 +959,15 @@ case $basic_machine in
-ptx*)
vendor=sequent
;;
- -vxworks*)
+ -vxsim* | -vxworks*)
vendor=wrs
;;
+ -aux*)
+ vendor=apple
+ ;;
+ -beos*)
+ vendor=be
+ ;;
esac
basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
;;
diff --git a/contrib/gcc/config/alpha/alpha.c b/contrib/gcc/config/alpha/alpha.c
index b77dc14..0b72289 100644
--- a/contrib/gcc/config/alpha/alpha.c
+++ b/contrib/gcc/config/alpha/alpha.c
@@ -1,5 +1,5 @@
/* Subroutines used for code generation on the DEC Alpha.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GNU CC.
@@ -20,8 +20,8 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
@@ -34,9 +34,44 @@ Boston, MA 02111-1307, USA. */
#include "flags.h"
#include "recog.h"
#include "reload.h"
+#include "tree.h"
#include "expr.h"
#include "obstack.h"
-#include "tree.h"
+#include "except.h"
+#include "function.h"
+#include "toplev.h"
+
+/* External data. */
+extern char *version_string;
+extern int rtx_equal_function_value_matters;
+
+/* Specify which cpu to schedule for. */
+
+enum processor_type alpha_cpu;
+static char* const alpha_cpu_name[] =
+{
+ "ev4", "ev5", "ev6"
+};
+
+/* Specify how accurate floating-point traps need to be. */
+
+enum alpha_trap_precision alpha_tp;
+
+/* Specify the floating-point rounding mode. */
+
+enum alpha_fp_rounding_mode alpha_fprm;
+
+/* Specify which things cause traps. */
+
+enum alpha_fp_trap_mode alpha_fptm;
+
+/* Strings decoded into the above options. */
+
+char *alpha_cpu_string; /* -mcpu= */
+char *alpha_tp_string; /* -mtrap-precision=[p|s|i] */
+char *alpha_fprm_string; /* -mfp-rounding-mode=[n|m|c|d] */
+char *alpha_fptm_string; /* -mfp-trap-mode=[n|u|su|sui] */
+char *alpha_mlat_string; /* -mmemory-latency= */
/* Save information from a "cmpxx" operation until the branch or scc is
emitted. */
@@ -44,26 +79,226 @@ Boston, MA 02111-1307, USA. */
rtx alpha_compare_op0, alpha_compare_op1;
int alpha_compare_fp_p;
-/* Save the name of the current function as used by the assembler. This
- is used by the epilogue. */
-
-char *alpha_function_name;
-
/* Non-zero if inside of a function, because the Alpha asm can't
handle .files inside of functions. */
static int inside_function = FALSE;
-/* Nonzero if the current function needs gp. */
+/* If non-null, this rtx holds the return address for the function. */
-int alpha_function_needs_gp;
+static rtx alpha_return_addr_rtx;
-extern char *version_string;
-extern int rtx_equal_function_value_matters;
+/* The number of cycles of latency we should assume on memory reads. */
+
+int alpha_memory_latency = 3;
+
+/* Whether the function needs the GP. */
+
+static int alpha_function_needs_gp;
/* Declarations of static functions. */
-static void alpha_set_memflags_1 PROTO((rtx, int, int, int));
-static void add_long_const PROTO((FILE *, HOST_WIDE_INT, int, int, int));
+static void alpha_set_memflags_1
+ PROTO((rtx, int, int, int));
+static rtx alpha_emit_set_const_1
+ PROTO((rtx, enum machine_mode, HOST_WIDE_INT, int));
+static void alpha_expand_unaligned_load_words
+ PROTO((rtx *out_regs, rtx smem, HOST_WIDE_INT words, HOST_WIDE_INT ofs));
+static void alpha_expand_unaligned_store_words
+ PROTO((rtx *out_regs, rtx smem, HOST_WIDE_INT words, HOST_WIDE_INT ofs));
+static void alpha_sa_mask
+ PROTO((unsigned long *imaskP, unsigned long *fmaskP));
+static int alpha_does_function_need_gp
+ PROTO((void));
+
+
+/* Get the number of args of a function in one of two ways. */
+#ifdef OPEN_VMS
+#define NUM_ARGS current_function_args_info.num_args
+#else
+#define NUM_ARGS current_function_args_info
+#endif
+
+#define REG_PV 27
+#define REG_RA 26
+
+/* Parse target option strings. */
+
+void
+override_options ()
+{
+ alpha_cpu
+ = TARGET_CPU_DEFAULT & MASK_CPU_EV6 ? PROCESSOR_EV6
+ : (TARGET_CPU_DEFAULT & MASK_CPU_EV5 ? PROCESSOR_EV5 : PROCESSOR_EV4);
+
+ if (alpha_cpu_string)
+ {
+ if (! strcmp (alpha_cpu_string, "ev4")
+ || ! strcmp (alpha_cpu_string, "21064"))
+ {
+ alpha_cpu = PROCESSOR_EV4;
+ target_flags &= ~ (MASK_BWX | MASK_CIX | MASK_MAX);
+ }
+ else if (! strcmp (alpha_cpu_string, "ev5")
+ || ! strcmp (alpha_cpu_string, "21164"))
+ {
+ alpha_cpu = PROCESSOR_EV5;
+ target_flags &= ~ (MASK_BWX | MASK_CIX | MASK_MAX);
+ }
+ else if (! strcmp (alpha_cpu_string, "ev56")
+ || ! strcmp (alpha_cpu_string, "21164a"))
+ {
+ alpha_cpu = PROCESSOR_EV5;
+ target_flags |= MASK_BWX;
+ target_flags &= ~ (MASK_CIX | MASK_MAX);
+ }
+ else if (! strcmp (alpha_cpu_string, "pca56")
+ || ! strcmp (alpha_cpu_string, "21164PC")
+ || ! strcmp (alpha_cpu_string, "21164pc"))
+ {
+ alpha_cpu = PROCESSOR_EV5;
+ target_flags |= MASK_BWX | MASK_MAX;
+ target_flags &= ~ MASK_CIX;
+ }
+ else if (! strcmp (alpha_cpu_string, "ev6")
+ || ! strcmp (alpha_cpu_string, "21264"))
+ {
+ alpha_cpu = PROCESSOR_EV6;
+ target_flags |= MASK_BWX | MASK_CIX | MASK_MAX;
+ }
+ else
+ error ("bad value `%s' for -mcpu switch", alpha_cpu_string);
+ }
+
+ alpha_tp = ALPHA_TP_PROG;
+ alpha_fprm = ALPHA_FPRM_NORM;
+ alpha_fptm = ALPHA_FPTM_N;
+
+ if (TARGET_IEEE)
+ {
+ alpha_tp = ALPHA_TP_INSN;
+ alpha_fptm = ALPHA_FPTM_SU;
+ }
+
+ if (TARGET_IEEE_WITH_INEXACT)
+ {
+ alpha_tp = ALPHA_TP_INSN;
+ alpha_fptm = ALPHA_FPTM_SUI;
+ }
+
+ if (alpha_tp_string)
+ {
+ if (! strcmp (alpha_tp_string, "p"))
+ alpha_tp = ALPHA_TP_PROG;
+ else if (! strcmp (alpha_tp_string, "f"))
+ alpha_tp = ALPHA_TP_FUNC;
+ else if (! strcmp (alpha_tp_string, "i"))
+ alpha_tp = ALPHA_TP_INSN;
+ else
+ error ("bad value `%s' for -mtrap-precision switch", alpha_tp_string);
+ }
+
+ if (alpha_fprm_string)
+ {
+ if (! strcmp (alpha_fprm_string, "n"))
+ alpha_fprm = ALPHA_FPRM_NORM;
+ else if (! strcmp (alpha_fprm_string, "m"))
+ alpha_fprm = ALPHA_FPRM_MINF;
+ else if (! strcmp (alpha_fprm_string, "c"))
+ alpha_fprm = ALPHA_FPRM_CHOP;
+ else if (! strcmp (alpha_fprm_string,"d"))
+ alpha_fprm = ALPHA_FPRM_DYN;
+ else
+ error ("bad value `%s' for -mfp-rounding-mode switch",
+ alpha_fprm_string);
+ }
+
+ if (alpha_fptm_string)
+ {
+ if (strcmp (alpha_fptm_string, "n") == 0)
+ alpha_fptm = ALPHA_FPTM_N;
+ else if (strcmp (alpha_fptm_string, "u") == 0)
+ alpha_fptm = ALPHA_FPTM_U;
+ else if (strcmp (alpha_fptm_string, "su") == 0)
+ alpha_fptm = ALPHA_FPTM_SU;
+ else if (strcmp (alpha_fptm_string, "sui") == 0)
+ alpha_fptm = ALPHA_FPTM_SUI;
+ else
+ error ("bad value `%s' for -mfp-trap-mode switch", alpha_fptm_string);
+ }
+
+ /* Do some sanity checks on the above option. */
+
+ if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI)
+ && alpha_tp != ALPHA_TP_INSN)
+ {
+ warning ("fp software completion requires -mtrap-precision=i");
+ alpha_tp = ALPHA_TP_INSN;
+ }
+
+ if (TARGET_FLOAT_VAX)
+ {
+ if (alpha_fprm == ALPHA_FPRM_MINF || alpha_fprm == ALPHA_FPRM_DYN)
+ {
+ warning ("rounding mode not supported for VAX floats");
+ alpha_fprm = ALPHA_FPRM_NORM;
+ }
+ if (alpha_fptm == ALPHA_FPTM_SUI)
+ {
+ warning ("trap mode not supported for VAX floats");
+ alpha_fptm = ALPHA_FPTM_SU;
+ }
+ }
+
+ {
+ char *end;
+ int lat;
+
+ if (!alpha_mlat_string)
+ alpha_mlat_string = "L1";
+
+ if (isdigit (alpha_mlat_string[0])
+ && (lat = strtol (alpha_mlat_string, &end, 10), *end == '\0'))
+ ;
+ else if ((alpha_mlat_string[0] == 'L' || alpha_mlat_string[0] == 'l')
+ && isdigit (alpha_mlat_string[1])
+ && alpha_mlat_string[2] == '\0')
+ {
+ static int const cache_latency[][4] =
+ {
+ { 3, 30, -1 }, /* ev4 -- Bcache is a guess */
+ { 2, 12, 38 }, /* ev5 -- Bcache from PC164 LMbench numbers */
+ { 3, 13, -1 }, /* ev6 -- Ho hum, doesn't exist yet */
+ };
+
+ lat = alpha_mlat_string[1] - '0';
+ if (lat < 0 || lat > 3 || cache_latency[alpha_cpu][lat-1] == -1)
+ {
+ warning ("L%d cache latency unknown for %s",
+ lat, alpha_cpu_name[alpha_cpu]);
+ lat = 3;
+ }
+ else
+ lat = cache_latency[alpha_cpu][lat-1];
+ }
+ else if (! strcmp (alpha_mlat_string, "main"))
+ {
+ /* Most current memories have about 370ns latency. This is
+ a reasonable guess for a fast cpu. */
+ lat = 150;
+ }
+ else
+ {
+ warning ("bad value `%s' for -mmemory-latency", alpha_mlat_string);
+ lat = 3;
+ }
+
+ alpha_memory_latency = lat;
+ }
+
+ /* Default the definition of "small data" to 8 bytes. */
+ if (!g_switch_set)
+ g_switch_value = 8;
+}
/* Returns 1 if VALUE is a mask that contains full bytes of zero or ones. */
@@ -102,6 +337,7 @@ reg_or_6bit_operand (op, mode)
{
return ((GET_CODE (op) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op) < 64)
+ || GET_CODE (op) == CONSTANT_P_RTX
|| register_operand (op, mode));
}
@@ -115,6 +351,7 @@ reg_or_8bit_operand (op, mode)
{
return ((GET_CODE (op) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100)
+ || GET_CODE (op) == CONSTANT_P_RTX
|| register_operand (op, mode));
}
@@ -123,10 +360,11 @@ reg_or_8bit_operand (op, mode)
int
cint8_operand (op, mode)
register rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
- return (GET_CODE (op) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100);
+ return ((GET_CODE (op) == CONST_INT
+ && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100)
+ || GET_CODE (op) == CONSTANT_P_RTX);
}
/* Return 1 if the operand is a valid second operand to an add insn. */
@@ -140,6 +378,8 @@ add_operand (op, mode)
return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K')
|| CONST_OK_FOR_LETTER_P (INTVAL (op), 'L')
|| CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'));
+ else if (GET_CODE (op) == CONSTANT_P_RTX)
+ return 1;
return register_operand (op, mode);
}
@@ -155,6 +395,8 @@ sext_add_operand (op, mode)
if (GET_CODE (op) == CONST_INT)
return ((unsigned HOST_WIDE_INT) INTVAL (op) < 255
|| (unsigned HOST_WIDE_INT) (- INTVAL (op)) < 255);
+ else if (GET_CODE (op) == CONSTANT_P_RTX)
+ return 1;
return register_operand (op, mode);
}
@@ -164,7 +406,7 @@ sext_add_operand (op, mode)
int
const48_operand (op, mode)
register rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) == 4 || INTVAL (op) == 8));
@@ -185,6 +427,8 @@ and_operand (op, mode)
return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
|| (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100
|| zap_mask (INTVAL (op)));
+ else if (GET_CODE (op) == CONSTANT_P_RTX)
+ return 1;
return register_operand (op, mode);
}
@@ -199,6 +443,8 @@ or_operand (op, mode)
if (GET_CODE (op) == CONST_INT)
return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
|| (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100);
+ else if (GET_CODE (op) == CONSTANT_P_RTX)
+ return 1;
return register_operand (op, mode);
}
@@ -209,10 +455,11 @@ or_operand (op, mode)
int
mode_width_operand (op, mode)
register rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == CONST_INT
- && (INTVAL (op) == 8 || INTVAL (op) == 16 || INTVAL (op) == 32));
+ && (INTVAL (op) == 8 || INTVAL (op) == 16
+ || INTVAL (op) == 32 || INTVAL (op) == 64));
}
/* Return 1 if OP is a constant that is the width of an integral machine mode
@@ -221,18 +468,24 @@ mode_width_operand (op, mode)
int
mode_mask_operand (op, mode)
register rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
#if HOST_BITS_PER_WIDE_INT == 32
if (GET_CODE (op) == CONST_DOUBLE)
- return CONST_DOUBLE_HIGH (op) == 0 && CONST_DOUBLE_LOW (op) == -1;
+ return (CONST_DOUBLE_LOW (op) == -1
+ && (CONST_DOUBLE_HIGH (op) == -1
+ || CONST_DOUBLE_HIGH (op) == 0));
+#else
+ if (GET_CODE (op) == CONST_DOUBLE)
+ return (CONST_DOUBLE_LOW (op) == -1 && CONST_DOUBLE_HIGH (op) == 0);
#endif
return (GET_CODE (op) == CONST_INT
&& (INTVAL (op) == 0xff
|| INTVAL (op) == 0xffff
-#if HOST_BITS_PER_WIDE_INT == 64
|| INTVAL (op) == 0xffffffff
+#if HOST_BITS_PER_WIDE_INT == 64
+ || INTVAL (op) == 0xffffffffffffffff
#endif
));
}
@@ -242,7 +495,7 @@ mode_mask_operand (op, mode)
int
mul8_operand (op, mode)
register rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (op) < 64
@@ -270,6 +523,18 @@ reg_or_fp0_operand (op, mode)
return fp0_operand (op, mode) || register_operand (op, mode);
}
+/* Return 1 if OP is a hard floating-point register. */
+
+int
+hard_fp_register_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ return ((GET_CODE (op) == REG && REGNO_REG_CLASS (REGNO (op)) == FLOAT_REGS)
+ || (GET_CODE (op) == SUBREG
+ && hard_fp_register_operand (SUBREG_REG (op), mode)));
+}
+
/* Return 1 if OP is a register or a constant integer. */
@@ -278,7 +543,9 @@ reg_or_cint_operand (op, mode)
register rtx op;
enum machine_mode mode;
{
- return GET_CODE (op) == CONST_INT || register_operand (op, mode);
+ return (GET_CODE (op) == CONST_INT
+ || GET_CODE (op) == CONSTANT_P_RTX
+ || register_operand (op, mode));
}
/* Return 1 if OP is something that can be reloaded into a register;
@@ -294,12 +561,15 @@ some_operand (op, mode)
switch (GET_CODE (op))
{
- case REG: case MEM: case CONST_DOUBLE:
- case CONST_INT: case LABEL_REF: case SYMBOL_REF: case CONST:
+ case REG: case MEM: case CONST_DOUBLE: case CONST_INT: case LABEL_REF:
+ case SYMBOL_REF: case CONST: case CONSTANT_P_RTX:
return 1;
case SUBREG:
return some_operand (SUBREG_REG (op), VOIDmode);
+
+ default:
+ break;
}
return 0;
@@ -323,7 +593,7 @@ input_operand (op, mode)
case LABEL_REF:
case SYMBOL_REF:
case CONST:
- /* This handles both the Windows/NT and OSF cases. */
+ /* This handles both the Windows/NT and OSF cases. */
return mode == ptr_mode || mode == DImode;
case REG:
@@ -334,13 +604,18 @@ input_operand (op, mode)
return 1;
/* ... fall through ... */
case MEM:
- return mode != HImode && mode != QImode && general_operand (op, mode);
+ return ((TARGET_BWX || (mode != HImode && mode != QImode))
+ && general_operand (op, mode));
case CONST_DOUBLE:
return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);
case CONST_INT:
+ case CONSTANT_P_RTX:
return mode == QImode || mode == HImode || add_operand (op, mode);
+
+ default:
+ break;
}
return 0;
@@ -352,7 +627,7 @@ input_operand (op, mode)
int
current_file_function_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == SYMBOL_REF
&& ! profile_flag && ! profile_block_flag
@@ -370,7 +645,9 @@ call_operand (op, mode)
if (mode != Pmode)
return 0;
- return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG);
+ return (GET_CODE (op) == SYMBOL_REF
+ || (GET_CODE (op) == REG
+ && (TARGET_OPEN_VMS || TARGET_WINDOWS_NT || REGNO (op) == 27)));
}
/* Return 1 if OP is a valid Alpha comparison operator. Here we know which
@@ -390,17 +667,37 @@ alpha_comparison_operator (op, mode)
|| (mode == DImode && (code == LEU || code == LTU)));
}
+/* Return 1 if OP is a valid Alpha swapped comparison operator. */
+
+int
+alpha_swapped_comparison_operator (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ enum rtx_code code = GET_CODE (op);
+
+ if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<')
+ return 0;
+
+ code = swap_condition (code);
+ return (code == EQ || code == LE || code == LT
+ || (mode == DImode && (code == LEU || code == LTU)));
+}
+
/* Return 1 if OP is a signed comparison operation. */
int
signed_comparison_operator (op, mode)
register rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
case EQ: case NE: case LE: case LT: case GE: case GT:
return 1;
+
+ default:
+ break;
}
return 0;
@@ -411,12 +708,15 @@ signed_comparison_operator (op, mode)
int
divmod_operator (op, mode)
register rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
case DIV: case MOD: case UDIV: case UMOD:
return 1;
+
+ default:
+ break;
}
return 0;
@@ -459,10 +759,7 @@ aligned_memory_operand (op, mode)
op = XEXP (op, 0);
return (GET_CODE (op) == REG
- && (REGNO (op) == STACK_POINTER_REGNUM
- || op == hard_frame_pointer_rtx
- || (REGNO (op) >= FIRST_VIRTUAL_REGISTER
- && REGNO (op) <= LAST_VIRTUAL_REGISTER)));
+ && REGNO_POINTER_ALIGN (REGNO (op)) >= 4);
}
/* Similar, but return 1 if OP is a MEM which is not alignable. */
@@ -496,10 +793,17 @@ unaligned_memory_operand (op, mode)
op = XEXP (op, 0);
return (GET_CODE (op) != REG
- || (REGNO (op) != STACK_POINTER_REGNUM
- && op != hard_frame_pointer_rtx
- && (REGNO (op) < FIRST_VIRTUAL_REGISTER
- || REGNO (op) > LAST_VIRTUAL_REGISTER)));
+ || REGNO_POINTER_ALIGN (REGNO (op)) < 4);
+}
+
+/* Return 1 if OP is either a register or an unaligned memory location. */
+
+int
+reg_or_unaligned_mem_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return register_operand (op, mode) || unaligned_memory_operand (op, mode);
}
/* Return 1 if OP is any memory location. During reload a pseudo matches. */
@@ -507,7 +811,7 @@ unaligned_memory_operand (op, mode)
int
any_memory_operand (op, mode)
register rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == MEM
|| (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
@@ -518,6 +822,17 @@ any_memory_operand (op, mode)
&& REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER));
}
+/* Return 1 if this function can directly return via $26. */
+
+int
+direct_return ()
+{
+ return (! TARGET_OPEN_VMS && reload_completed && alpha_sa_size () == 0
+ && get_frame_size () == 0
+ && current_function_outgoing_args_size == 0
+ && current_function_pretend_args_size == 0);
+}
+
/* REF is an alignable memory location. Place an aligned SImode
reference into *PALIGNED_MEM and the number of bits to shift into
*PBITNUM. */
@@ -551,7 +866,7 @@ get_aligned_mem (ref, paligned_mem, pbitnum)
if (GET_CODE (base) == PLUS)
offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
- *paligned_mem = gen_rtx (MEM, SImode,
+ *paligned_mem = gen_rtx_MEM (SImode,
plus_constant (base, offset & ~3));
MEM_IN_STRUCT_P (*paligned_mem) = MEM_IN_STRUCT_P (ref);
MEM_VOLATILE_P (*paligned_mem) = MEM_VOLATILE_P (ref);
@@ -560,11 +875,13 @@ get_aligned_mem (ref, paligned_mem, pbitnum)
*pbitnum = GEN_INT ((offset & 3) * 8);
}
-/* Similar, but just get the address. Handle the two reload cases. */
+/* Similar, but just get the address. Handle the two reload cases.
+ Add EXTRA_OFFSET to the address we return. */
rtx
-get_unaligned_address (ref)
+get_unaligned_address (ref, extra_offset)
rtx ref;
+ int extra_offset;
{
rtx base;
HOST_WIDE_INT offset = 0;
@@ -590,7 +907,7 @@ get_unaligned_address (ref)
if (GET_CODE (base) == PLUS)
offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
- return plus_constant (base, offset);
+ return plus_constant (base, offset + extra_offset);
}
/* Subfunction of the following function. Update the flags of any MEM
@@ -629,6 +946,9 @@ alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p)
MEM_VOLATILE_P (x) = volatile_p;
RTX_UNCHANGING_P (x) = unchanging_p;
break;
+
+ default:
+ break;
}
}
@@ -669,6 +989,26 @@ alpha_emit_set_const (target, mode, c, n)
HOST_WIDE_INT c;
int n;
{
+ rtx pat;
+ int i;
+
+ /* Try 1 insn, then 2, then up to N. */
+ for (i = 1; i <= n; i++)
+ if ((pat = alpha_emit_set_const_1 (target, mode, c, i)) != 0)
+ return pat;
+
+ return 0;
+}
+
+/* Internal routine for the above to check for N or below insns. */
+
+static rtx
+alpha_emit_set_const_1 (target, mode, c, n)
+ rtx target;
+ enum machine_mode mode;
+ HOST_WIDE_INT c;
+ int n;
+{
HOST_WIDE_INT new = c;
int i, bits;
/* Use a pseudo if highly optimizing and still generating RTL. */
@@ -688,12 +1028,10 @@ alpha_emit_set_const (target, mode, c, n)
/* If this is a sign-extended 32-bit constant, we can do this in at most
three insns, so do it if we have enough insns left. We always have
- a sign-extended 32-bit constant when compiling on a narrow machine.
- Note that we cannot handle the constant 0x80000000. */
+ a sign-extended 32-bit constant when compiling on a narrow machine. */
- if ((HOST_BITS_PER_WIDE_INT != 64
- || c >> 31 == -1 || c >> 31 == 0)
- && c != 0x80000000U)
+ if (HOST_BITS_PER_WIDE_INT != 64
+ || c >> 31 == -1 || c >> 31 == 0)
{
HOST_WIDE_INT low = (c & 0xffff) - 2 * (c & 0x8000);
HOST_WIDE_INT tmp1 = c - low;
@@ -712,13 +1050,19 @@ alpha_emit_set_const (target, mode, c, n)
}
if (c == low || (low == 0 && extra == 0))
- return copy_to_suggested_reg (GEN_INT (c), target, mode);
- else if (n >= 2 + (extra != 0)
- /* We can't do this when SImode if HIGH required adjustment.
- This is because the code relies on an implicit overflow
- which is invisible to the RTL. We can thus get incorrect
- code if the two ldah instructions are combined. */
- && ! (mode == SImode && extra != 0))
+ {
+ /* We used to use copy_to_suggested_reg (GEN_INT (c), target, mode)
+ but that meant that we can't handle INT_MIN on 32-bit machines
+ (like NT/Alpha), because we recurse indefinitely through
+ emit_move_insn to gen_movdi. So instead, since we know exactly
+ what we want, create it explicitly. */
+
+ if (target == NULL)
+ target = gen_reg_rtx (mode);
+ emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (c)));
+ return target;
+ }
+ else if (n >= 2 + (extra != 0))
{
temp = copy_to_suggested_reg (GEN_INT (low), subtarget, mode);
@@ -795,9 +1139,11 @@ alpha_emit_set_const (target, mode, c, n)
/* Now try high-order zero bits. Here we try the shifted-in bits as
all zero and all ones. Be careful to avoid shifting outside the
mode and to avoid shifting outside the host wide int size. */
+ /* On narrow hosts, don't shift a 1 into the high bit, since we'll
+ confuse the recursive call and set all of the high 32 bits. */
if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
- - floor_log2 (c) - 1)) > 0)
+ - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64))) > 0)
for (; bits > 0; bits--)
if ((temp = alpha_emit_set_const (subtarget, mode,
c << bits, i)) != 0
@@ -829,6 +1175,1077 @@ alpha_emit_set_const (target, mode, c, n)
return 0;
}
+
+#if HOST_BITS_PER_WIDE_INT == 64
+/* Having failed to find a 3 insn sequence in alpha_emit_set_const,
+ fall back to a straight forward decomposition. We do this to avoid
+ exponential run times encountered when looking for longer sequences
+ with alpha_emit_set_const. */
+
+rtx
+alpha_emit_set_long_const (target, c)
+ rtx target;
+ HOST_WIDE_INT c;
+{
+ /* Use a pseudo if highly optimizing and still generating RTL. */
+ rtx subtarget
+ = (flag_expensive_optimizations && rtx_equal_function_value_matters
+ ? 0 : target);
+ HOST_WIDE_INT d1, d2, d3, d4;
+ rtx r1, r2;
+
+ /* Decompose the entire word */
+ d1 = ((c & 0xffff) ^ 0x8000) - 0x8000;
+ c -= d1;
+ d2 = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000;
+ c = (c - d2) >> 32;
+ d3 = ((c & 0xffff) ^ 0x8000) - 0x8000;
+ c -= d3;
+ d4 = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000;
+
+ if (c - d4 != 0)
+ abort();
+
+ /* Construct the high word */
+ if (d3 == 0)
+ r1 = copy_to_suggested_reg (GEN_INT (d4), subtarget, DImode);
+ else if (d4 == 0)
+ r1 = copy_to_suggested_reg (GEN_INT (d3), subtarget, DImode);
+ else
+ r1 = expand_binop (DImode, add_optab, GEN_INT (d3), GEN_INT (d4),
+ subtarget, 0, OPTAB_WIDEN);
+
+ /* Shift it into place */
+ r2 = expand_binop (DImode, ashl_optab, r1, GEN_INT (32),
+ subtarget, 0, OPTAB_WIDEN);
+
+ if (subtarget == 0 && d1 == d3 && d2 == d4)
+ r1 = expand_binop (DImode, add_optab, r1, r2, subtarget, 0, OPTAB_WIDEN);
+ else
+ {
+ r1 = r2;
+
+ /* Add in the low word */
+ if (d2 != 0)
+ r1 = expand_binop (DImode, add_optab, r1, GEN_INT (d2),
+ subtarget, 0, OPTAB_WIDEN);
+ if (d1 != 0)
+ r1 = expand_binop (DImode, add_optab, r1, GEN_INT (d1),
+ subtarget, 0, OPTAB_WIDEN);
+ }
+
+ if (subtarget == 0)
+ r1 = copy_to_suggested_reg(r1, target, DImode);
+
+ return r1;
+}
+#endif /* HOST_BITS_PER_WIDE_INT == 64 */
+
+/* Generate the comparison for a conditional branch. */
+
+rtx
+alpha_emit_conditional_branch (code)
+ enum rtx_code code;
+{
+ enum rtx_code cmp_code, branch_code;
+ enum machine_mode cmp_mode, branch_mode = VOIDmode;
+ rtx op0 = alpha_compare_op0, op1 = alpha_compare_op1;
+ rtx tem;
+
+ /* The general case: fold the comparison code to the types of compares
+ that we have, choosing the branch as necessary. */
+ switch (code)
+ {
+ case EQ: case LE: case LT: case LEU: case LTU:
+ /* We have these compares: */
+ cmp_code = code, branch_code = NE;
+ break;
+
+ case NE:
+ /* This must be reversed. */
+ cmp_code = EQ, branch_code = EQ;
+ break;
+
+ case GE: case GT: case GEU: case GTU:
+ /* For FP, we swap them, for INT, we reverse them. */
+ if (alpha_compare_fp_p)
+ {
+ cmp_code = swap_condition (code);
+ branch_code = NE;
+ tem = op0, op0 = op1, op1 = tem;
+ }
+ else
+ {
+ cmp_code = reverse_condition (code);
+ branch_code = EQ;
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (alpha_compare_fp_p)
+ {
+ cmp_mode = DFmode;
+ if (flag_fast_math)
+ {
+ /* When we are not as concerned about non-finite values, and we
+ are comparing against zero, we can branch directly. */
+ if (op1 == CONST0_RTX (DFmode))
+ cmp_code = NIL, branch_code = code;
+ else if (op0 == CONST0_RTX (DFmode))
+ {
+ /* Undo the swap we probably did just above. */
+ tem = op0, op0 = op1, op1 = tem;
+ branch_code = swap_condition (cmp_code);
+ cmp_code = NIL;
+ }
+ }
+ else
+ {
+ /* ??? We mark the the branch mode to be CCmode to prevent the
+ compare and branch from being combined, since the compare
+ insn follows IEEE rules that the branch does not. */
+ branch_mode = CCmode;
+ }
+ }
+ else
+ {
+ cmp_mode = DImode;
+
+ /* The following optimizations are only for signed compares. */
+ if (code != LEU && code != LTU && code != GEU && code != GTU)
+ {
+ /* Whee. Compare and branch against 0 directly. */
+ if (op1 == const0_rtx)
+ cmp_code = NIL, branch_code = code;
+
+ /* We want to use cmpcc/bcc when we can, since there is a zero delay
+ bypass between logicals and br/cmov on EV5. But we don't want to
+ force valid immediate constants into registers needlessly. */
+ else if (GET_CODE (op1) == CONST_INT)
+ {
+ HOST_WIDE_INT v = INTVAL (op1), n = -v;
+
+ if (! CONST_OK_FOR_LETTER_P (v, 'I')
+ && (CONST_OK_FOR_LETTER_P (n, 'K')
+ || CONST_OK_FOR_LETTER_P (n, 'L')))
+ {
+ cmp_code = PLUS, branch_code = code;
+ op1 = GEN_INT (n);
+ }
+ }
+ }
+ }
+
+ /* Force op0 into a register. */
+ if (GET_CODE (op0) != REG)
+ op0 = force_reg (cmp_mode, op0);
+
+ /* Emit an initial compare instruction, if necessary. */
+ tem = op0;
+ if (cmp_code != NIL)
+ {
+ tem = gen_reg_rtx (cmp_mode);
+ emit_move_insn (tem, gen_rtx_fmt_ee (cmp_code, cmp_mode, op0, op1));
+ }
+
+ /* Return the branch comparison. */
+ return gen_rtx_fmt_ee (branch_code, branch_mode, tem, CONST0_RTX (cmp_mode));
+}
+
+
+/* Rewrite a comparison against zero CMP of the form
+ (CODE (cc0) (const_int 0)) so it can be written validly in
+ a conditional move (if_then_else CMP ...).
+ If both of the operands that set cc0 are non-zero we must emit
+ an insn to perform the compare (it can't be done within
+ the conditional move). */
+rtx
+alpha_emit_conditional_move (cmp, mode)
+ rtx cmp;
+ enum machine_mode mode;
+{
+ enum rtx_code code = GET_CODE (cmp);
+ enum rtx_code cmov_code = NE;
+ rtx op0 = alpha_compare_op0;
+ rtx op1 = alpha_compare_op1;
+ enum machine_mode cmp_mode
+ = (GET_MODE (op0) == VOIDmode ? DImode : GET_MODE (op0));
+ enum machine_mode cmp_op_mode = alpha_compare_fp_p ? DFmode : DImode;
+ enum machine_mode cmov_mode = VOIDmode;
+ rtx tem;
+
+ if (alpha_compare_fp_p != FLOAT_MODE_P (mode))
+ return 0;
+
+ /* We may be able to use a conditional move directly.
+ This avoids emitting spurious compares. */
+ if (signed_comparison_operator (cmp, cmp_op_mode)
+ && (!alpha_compare_fp_p || flag_fast_math)
+ && (op0 == CONST0_RTX (cmp_mode) || op1 == CONST0_RTX (cmp_mode)))
+ return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
+
+ /* We can't put the comparison insides a conditional move;
+ emit a compare instruction and put that inside the
+ conditional move. Make sure we emit only comparisons we have;
+ swap or reverse as necessary. */
+
+ switch (code)
+ {
+ case EQ: case LE: case LT: case LEU: case LTU:
+ /* We have these compares: */
+ break;
+
+ case NE:
+ /* This must be reversed. */
+ code = reverse_condition (code);
+ cmov_code = EQ;
+ break;
+
+ case GE: case GT: case GEU: case GTU:
+ /* These must be swapped. Make sure the new first operand is in
+ a register. */
+ code = swap_condition (code);
+ tem = op0, op0 = op1, op1 = tem;
+ op0 = force_reg (cmp_mode, op0);
+ break;
+
+ default:
+ abort ();
+ }
+
+ /* ??? We mark the the branch mode to be CCmode to prevent the compare
+ and cmov from being combined, since the compare insn follows IEEE
+ rules that the cmov does not. */
+ if (alpha_compare_fp_p && !flag_fast_math)
+ cmov_mode = CCmode;
+
+ tem = gen_reg_rtx (cmp_op_mode);
+ emit_move_insn (tem, gen_rtx_fmt_ee (code, cmp_op_mode, op0, op1));
+ return gen_rtx_fmt_ee (cmov_code, cmov_mode, tem, CONST0_RTX (cmp_op_mode));
+}
+
+/* Use ext[wlq][lh] as the Architecture Handbook describes for extracting
+ unaligned data:
+
+ unsigned: signed:
+ word: ldq_u r1,X(r11) ldq_u r1,X(r11)
+ ldq_u r2,X+1(r11) ldq_u r2,X+1(r11)
+ lda r3,X(r11) lda r3,X+2(r11)
+ extwl r1,r3,r1 extql r1,r3,r1
+ extwh r2,r3,r2 extqh r2,r3,r2
+ or r1.r2.r1 or r1,r2,r1
+ sra r1,48,r1
+
+ long: ldq_u r1,X(r11) ldq_u r1,X(r11)
+ ldq_u r2,X+3(r11) ldq_u r2,X+3(r11)
+ lda r3,X(r11) lda r3,X(r11)
+ extll r1,r3,r1 extll r1,r3,r1
+ extlh r2,r3,r2 extlh r2,r3,r2
+ or r1.r2.r1 addl r1,r2,r1
+
+ quad: ldq_u r1,X(r11)
+ ldq_u r2,X+7(r11)
+ lda r3,X(r11)
+ extql r1,r3,r1
+ extqh r2,r3,r2
+ or r1.r2.r1
+*/
+
+void
+alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
+ rtx tgt, mem;
+ HOST_WIDE_INT size, ofs;
+ int sign;
+{
+ rtx meml, memh, addr, extl, exth;
+ enum machine_mode mode;
+
+ meml = gen_reg_rtx (DImode);
+ memh = gen_reg_rtx (DImode);
+ addr = gen_reg_rtx (DImode);
+ extl = gen_reg_rtx (DImode);
+ exth = gen_reg_rtx (DImode);
+
+ emit_move_insn (meml,
+ change_address (mem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (XEXP (mem, 0),
+ ofs),
+ GEN_INT (-8))));
+
+ emit_move_insn (memh,
+ change_address (mem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (XEXP (mem, 0),
+ ofs + size - 1),
+ GEN_INT (-8))));
+
+ if (sign && size == 2)
+ {
+ emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs+2));
+
+ emit_insn (gen_extxl (extl, meml, GEN_INT (64), addr));
+ emit_insn (gen_extqh (exth, memh, addr));
+
+ /* We must use tgt here for the target. Alpha-vms port fails if we use
+ addr for the target, because addr is marked as a pointer and combine
+ knows that pointers are always sign-extended 32 bit values. */
+ addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN);
+ addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (48),
+ addr, 1, OPTAB_WIDEN);
+ }
+ else
+ {
+ emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs));
+ emit_insn (gen_extxl (extl, meml, GEN_INT (size*8), addr));
+ switch (size)
+ {
+ case 2:
+ emit_insn (gen_extwh (exth, memh, addr));
+ mode = HImode;
+ break;
+
+ case 4:
+ emit_insn (gen_extlh (exth, memh, addr));
+ mode = SImode;
+ break;
+
+ case 8:
+ emit_insn (gen_extqh (exth, memh, addr));
+ mode = DImode;
+ break;
+ }
+
+ addr = expand_binop (mode, ior_optab, gen_lowpart (mode, extl),
+ gen_lowpart (mode, exth), gen_lowpart (mode, tgt),
+ sign, OPTAB_WIDEN);
+ }
+
+ if (addr != tgt)
+ emit_move_insn (tgt, gen_lowpart(GET_MODE (tgt), addr));
+}
+
+/* Similarly, use ins and msk instructions to perform unaligned stores. */
+
+void
+alpha_expand_unaligned_store (dst, src, size, ofs)
+ rtx dst, src;
+ HOST_WIDE_INT size, ofs;
+{
+ rtx dstl, dsth, addr, insl, insh, meml, memh;
+
+ dstl = gen_reg_rtx (DImode);
+ dsth = gen_reg_rtx (DImode);
+ insl = gen_reg_rtx (DImode);
+ insh = gen_reg_rtx (DImode);
+
+ meml = change_address (dst, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (XEXP (dst, 0), ofs),
+ GEN_INT (-8)));
+ memh = change_address (dst, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (XEXP (dst, 0),
+ ofs+size-1),
+ GEN_INT (-8)));
+
+ emit_move_insn (dsth, memh);
+ emit_move_insn (dstl, meml);
+ addr = copy_addr_to_reg (plus_constant (XEXP (dst, 0), ofs));
+
+ if (src != const0_rtx)
+ {
+ emit_insn (gen_insxh (insh, gen_lowpart (DImode, src),
+ GEN_INT (size*8), addr));
+
+ switch (size)
+ {
+ case 2:
+ emit_insn (gen_inswl (insl, gen_lowpart (HImode, src), addr));
+ break;
+ case 4:
+ emit_insn (gen_insll (insl, gen_lowpart (SImode, src), addr));
+ break;
+ case 8:
+ emit_insn (gen_insql (insl, src, addr));
+ break;
+ }
+ }
+
+ emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr));
+
+ switch (size)
+ {
+ case 2:
+ emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffff), addr));
+ break;
+ case 4:
+ emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffffffff), addr));
+ break;
+ case 8:
+ {
+#if HOST_BITS_PER_WIDE_INT == 32
+ rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode);
+#else
+ rtx msk = immed_double_const (0xffffffffffffffff, 0, DImode);
+#endif
+ emit_insn (gen_mskxl (dstl, dstl, msk, addr));
+ }
+ break;
+ }
+
+ if (src != const0_rtx)
+ {
+ dsth = expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN);
+ dstl = expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN);
+ }
+
+ /* Must store high before low for degenerate case of aligned. */
+ emit_move_insn (memh, dsth);
+ emit_move_insn (meml, dstl);
+}
+
+/* The block move code tries to maximize speed by separating loads and
+ stores at the expense of register pressure: we load all of the data
+ before we store it back out. There are two secondary effects worth
+ mentioning, that this speeds copying to/from aligned and unaligned
+ buffers, and that it makes the code significantly easier to write. */
+
+#define MAX_MOVE_WORDS 8
+
+/* Load an integral number of consecutive unaligned quadwords. */
+
+static void
+alpha_expand_unaligned_load_words (out_regs, smem, words, ofs)
+ rtx *out_regs;
+ rtx smem;
+ HOST_WIDE_INT words, ofs;
+{
+ rtx const im8 = GEN_INT (-8);
+ rtx const i64 = GEN_INT (64);
+ rtx ext_tmps[MAX_MOVE_WORDS], data_regs[MAX_MOVE_WORDS+1];
+ rtx sreg, areg;
+ HOST_WIDE_INT i;
+
+ /* Generate all the tmp registers we need. */
+ for (i = 0; i < words; ++i)
+ {
+ data_regs[i] = out_regs[i];
+ ext_tmps[i] = gen_reg_rtx (DImode);
+ }
+ data_regs[words] = gen_reg_rtx (DImode);
+
+ if (ofs != 0)
+ smem = change_address (smem, GET_MODE (smem),
+ plus_constant (XEXP (smem, 0), ofs));
+
+ /* Load up all of the source data. */
+ for (i = 0; i < words; ++i)
+ {
+ emit_move_insn (data_regs[i],
+ change_address (smem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (XEXP(smem,0),
+ 8*i),
+ im8)));
+ }
+ emit_move_insn (data_regs[words],
+ change_address (smem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (XEXP(smem,0),
+ 8*words - 1),
+ im8)));
+
+ /* Extract the half-word fragments. Unfortunately DEC decided to make
+ extxh with offset zero a noop instead of zeroing the register, so
+ we must take care of that edge condition ourselves with cmov. */
+
+ sreg = copy_addr_to_reg (XEXP (smem, 0));
+ areg = expand_binop (DImode, and_optab, sreg, GEN_INT (7), NULL,
+ 1, OPTAB_WIDEN);
+ for (i = 0; i < words; ++i)
+ {
+ emit_insn (gen_extxl (data_regs[i], data_regs[i], i64, sreg));
+
+ emit_insn (gen_extqh (ext_tmps[i], data_regs[i+1], sreg));
+ emit_insn (gen_rtx_SET (VOIDmode, ext_tmps[i],
+ gen_rtx_IF_THEN_ELSE (DImode,
+ gen_rtx_EQ (DImode, areg,
+ const0_rtx),
+ const0_rtx, ext_tmps[i])));
+ }
+
+ /* Merge the half-words into whole words. */
+ for (i = 0; i < words; ++i)
+ {
+ out_regs[i] = expand_binop (DImode, ior_optab, data_regs[i],
+ ext_tmps[i], data_regs[i], 1, OPTAB_WIDEN);
+ }
+}
+
+/* Store an integral number of consecutive unaligned quadwords. DATA_REGS
+ may be NULL to store zeros. */
+
+static void
+alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
+ rtx *data_regs;
+ rtx dmem;
+ HOST_WIDE_INT words, ofs;
+{
+ rtx const im8 = GEN_INT (-8);
+ rtx const i64 = GEN_INT (64);
+#if HOST_BITS_PER_WIDE_INT == 32
+ rtx const im1 = immed_double_const (0xffffffff, 0xffffffff, DImode);
+#else
+ rtx const im1 = immed_double_const (0xffffffffffffffff, 0, DImode);
+#endif
+ rtx ins_tmps[MAX_MOVE_WORDS];
+ rtx st_tmp_1, st_tmp_2, dreg;
+ rtx st_addr_1, st_addr_2;
+ HOST_WIDE_INT i;
+
+ /* Generate all the tmp registers we need. */
+ if (data_regs != NULL)
+ for (i = 0; i < words; ++i)
+ ins_tmps[i] = gen_reg_rtx(DImode);
+ st_tmp_1 = gen_reg_rtx(DImode);
+ st_tmp_2 = gen_reg_rtx(DImode);
+
+ if (ofs != 0)
+ dmem = change_address (dmem, GET_MODE (dmem),
+ plus_constant (XEXP (dmem, 0), ofs));
+
+
+ st_addr_2 = change_address (dmem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant (XEXP(dmem,0),
+ words*8 - 1),
+ im8));
+ st_addr_1 = change_address (dmem, DImode,
+ gen_rtx_AND (DImode,
+ XEXP (dmem, 0),
+ im8));
+
+ /* Load up the destination end bits. */
+ emit_move_insn (st_tmp_2, st_addr_2);
+ emit_move_insn (st_tmp_1, st_addr_1);
+
+ /* Shift the input data into place. */
+ dreg = copy_addr_to_reg (XEXP (dmem, 0));
+ if (data_regs != NULL)
+ {
+ for (i = words-1; i >= 0; --i)
+ {
+ emit_insn (gen_insxh (ins_tmps[i], data_regs[i], i64, dreg));
+ emit_insn (gen_insql (data_regs[i], data_regs[i], dreg));
+ }
+ for (i = words-1; i > 0; --i)
+ {
+ ins_tmps[i-1] = expand_binop (DImode, ior_optab, data_regs[i],
+ ins_tmps[i-1], ins_tmps[i-1], 1,
+ OPTAB_WIDEN);
+ }
+ }
+
+ /* Split and merge the ends with the destination data. */
+ emit_insn (gen_mskxh (st_tmp_2, st_tmp_2, i64, dreg));
+ emit_insn (gen_mskxl (st_tmp_1, st_tmp_1, im1, dreg));
+
+ if (data_regs != NULL)
+ {
+ st_tmp_2 = expand_binop (DImode, ior_optab, st_tmp_2, ins_tmps[words-1],
+ st_tmp_2, 1, OPTAB_WIDEN);
+ st_tmp_1 = expand_binop (DImode, ior_optab, st_tmp_1, data_regs[0],
+ st_tmp_1, 1, OPTAB_WIDEN);
+ }
+
+ /* Store it all. */
+ emit_move_insn (st_addr_2, st_tmp_2);
+ for (i = words-1; i > 0; --i)
+ {
+ emit_move_insn (change_address (dmem, DImode,
+ gen_rtx_AND (DImode,
+ plus_constant(XEXP (dmem,0),
+ i*8),
+ im8)),
+ data_regs ? ins_tmps[i-1] : const0_rtx);
+ }
+ emit_move_insn (st_addr_1, st_tmp_1);
+}
+
+
+/* Expand string/block move operations.
+
+ operands[0] is the pointer to the destination.
+ operands[1] is the pointer to the source.
+ operands[2] is the number of bytes to move.
+ operands[3] is the alignment. */
+
+int
+alpha_expand_block_move (operands)
+ rtx operands[];
+{
+ rtx bytes_rtx = operands[2];
+ rtx align_rtx = operands[3];
+ HOST_WIDE_INT bytes = INTVAL (bytes_rtx);
+ HOST_WIDE_INT src_align = INTVAL (align_rtx);
+ HOST_WIDE_INT dst_align = src_align;
+ rtx orig_src = operands[1];
+ rtx orig_dst = operands[0];
+ rtx data_regs[2*MAX_MOVE_WORDS+16];
+ rtx tmp;
+ int i, words, ofs, nregs = 0;
+
+ if (bytes <= 0)
+ return 1;
+ if (bytes > MAX_MOVE_WORDS*8)
+ return 0;
+
+ /* Look for additional alignment information from recorded register info. */
+
+ tmp = XEXP (orig_src, 0);
+ if (GET_CODE (tmp) == REG)
+ {
+ if (REGNO_POINTER_ALIGN (REGNO (tmp)) > src_align)
+ src_align = REGNO_POINTER_ALIGN (REGNO (tmp));
+ }
+ else if (GET_CODE (tmp) == PLUS
+ && GET_CODE (XEXP (tmp, 0)) == REG
+ && GET_CODE (XEXP (tmp, 1)) == CONST_INT)
+ {
+ HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1));
+ int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0)));
+
+ if (a > src_align)
+ {
+ if (a >= 8 && c % 8 == 0)
+ src_align = 8;
+ else if (a >= 4 && c % 4 == 0)
+ src_align = 4;
+ else if (a >= 2 && c % 2 == 0)
+ src_align = 2;
+ }
+ }
+
+ tmp = XEXP (orig_dst, 0);
+ if (GET_CODE (tmp) == REG)
+ {
+ if (REGNO_POINTER_ALIGN (REGNO (tmp)) > dst_align)
+ dst_align = REGNO_POINTER_ALIGN (REGNO (tmp));
+ }
+ else if (GET_CODE (tmp) == PLUS
+ && GET_CODE (XEXP (tmp, 0)) == REG
+ && GET_CODE (XEXP (tmp, 1)) == CONST_INT)
+ {
+ HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1));
+ int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0)));
+
+ if (a > dst_align)
+ {
+ if (a >= 8 && c % 8 == 0)
+ dst_align = 8;
+ else if (a >= 4 && c % 4 == 0)
+ dst_align = 4;
+ else if (a >= 2 && c % 2 == 0)
+ dst_align = 2;
+ }
+ }
+
+ /*
+ * Load the entire block into registers.
+ */
+
+ if (GET_CODE (XEXP (orig_src, 0)) == ADDRESSOF)
+ {
+ enum machine_mode mode;
+ tmp = XEXP (XEXP (orig_src, 0), 0);
+
+ mode = mode_for_size (bytes, MODE_INT, 1);
+ if (mode != BLKmode
+ && GET_MODE_SIZE (GET_MODE (tmp)) <= bytes)
+ {
+ /* Whee! Optimize the load to use the existing register. */
+ data_regs[nregs++] = gen_lowpart (mode, tmp);
+ goto src_done;
+ }
+
+ /* ??? We could potentially be copying 3 bytes or whatnot from
+ a wider reg. Probably not worth worrying about. */
+ /* No appropriate mode; fall back on memory. */
+ orig_src = change_address (orig_src, GET_MODE (orig_src),
+ copy_addr_to_reg (XEXP (orig_src, 0)));
+ }
+
+ ofs = 0;
+ if (src_align >= 8 && bytes >= 8)
+ {
+ words = bytes / 8;
+
+ for (i = 0; i < words; ++i)
+ data_regs[nregs+i] = gen_reg_rtx(DImode);
+
+ for (i = 0; i < words; ++i)
+ {
+ emit_move_insn (data_regs[nregs+i],
+ change_address(orig_src, DImode,
+ plus_constant (XEXP (orig_src, 0),
+ ofs + i*8)));
+ }
+
+ nregs += words;
+ bytes -= words * 8;
+ ofs += words * 8;
+ }
+ if (src_align >= 4 && bytes >= 4)
+ {
+ words = bytes / 4;
+
+ for (i = 0; i < words; ++i)
+ data_regs[nregs+i] = gen_reg_rtx(SImode);
+
+ for (i = 0; i < words; ++i)
+ {
+ emit_move_insn (data_regs[nregs+i],
+ change_address(orig_src, SImode,
+ plus_constant (XEXP (orig_src, 0),
+ ofs + i*4)));
+ }
+
+ nregs += words;
+ bytes -= words * 4;
+ ofs += words * 4;
+ }
+ if (bytes >= 16)
+ {
+ words = bytes / 8;
+
+ for (i = 0; i < words+1; ++i)
+ data_regs[nregs+i] = gen_reg_rtx(DImode);
+
+ alpha_expand_unaligned_load_words(data_regs+nregs, orig_src, words, ofs);
+
+ nregs += words;
+ bytes -= words * 8;
+ ofs += words * 8;
+ }
+ if (!TARGET_BWX && bytes >= 8)
+ {
+ data_regs[nregs++] = tmp = gen_reg_rtx (DImode);
+ alpha_expand_unaligned_load (tmp, orig_src, 8, ofs, 0);
+ bytes -= 8;
+ ofs += 8;
+ }
+ if (!TARGET_BWX && bytes >= 4)
+ {
+ data_regs[nregs++] = tmp = gen_reg_rtx (SImode);
+ alpha_expand_unaligned_load (tmp, orig_src, 4, ofs, 0);
+ bytes -= 4;
+ ofs += 4;
+ }
+ if (bytes >= 2)
+ {
+ if (src_align >= 2)
+ {
+ do {
+ data_regs[nregs++] = tmp = gen_reg_rtx (HImode);
+ emit_move_insn (tmp,
+ change_address (orig_src, HImode,
+ plus_constant (XEXP (orig_src, 0),
+ ofs)));
+ bytes -= 2;
+ ofs += 2;
+ } while (bytes >= 2);
+ }
+ else if (!TARGET_BWX)
+ {
+ data_regs[nregs++] = tmp = gen_reg_rtx (HImode);
+ alpha_expand_unaligned_load (tmp, orig_src, 2, ofs, 0);
+ bytes -= 2;
+ ofs += 2;
+ }
+ }
+ while (bytes > 0)
+ {
+ data_regs[nregs++] = tmp = gen_reg_rtx (QImode);
+ emit_move_insn (tmp,
+ change_address (orig_src, QImode,
+ plus_constant (XEXP (orig_src, 0),
+ ofs)));
+ bytes -= 1;
+ ofs += 1;
+ }
+ src_done:
+
+ if (nregs > sizeof(data_regs)/sizeof(*data_regs))
+ abort();
+
+ /*
+ * Now save it back out again.
+ */
+
+ i = 0, ofs = 0;
+
+ if (GET_CODE (XEXP (orig_dst, 0)) == ADDRESSOF)
+ {
+ enum machine_mode mode;
+ tmp = XEXP (XEXP (orig_dst, 0), 0);
+
+ mode = mode_for_size (bytes, MODE_INT, 1);
+ if (GET_MODE (tmp) == mode && nregs == 1)
+ {
+ emit_move_insn (tmp, data_regs[0]);
+ i = 1;
+ goto dst_done;
+ }
+
+ /* ??? If nregs > 1, consider reconstructing the word in regs. */
+ /* ??? Optimize mode < dst_mode with strict_low_part. */
+ /* No appropriate mode; fall back on memory. */
+ orig_dst = change_address (orig_dst, GET_MODE (orig_dst),
+ copy_addr_to_reg (XEXP (orig_dst, 0)));
+ }
+
+ /* Write out the data in whatever chunks reading the source allowed. */
+ if (dst_align >= 8)
+ {
+ while (i < nregs && GET_MODE (data_regs[i]) == DImode)
+ {
+ emit_move_insn (change_address(orig_dst, DImode,
+ plus_constant (XEXP (orig_dst, 0),
+ ofs)),
+ data_regs[i]);
+ ofs += 8;
+ i++;
+ }
+ }
+ if (dst_align >= 4)
+ {
+ /* If the source has remaining DImode regs, write them out in
+ two pieces. */
+ while (i < nregs && GET_MODE (data_regs[i]) == DImode)
+ {
+ tmp = expand_binop (DImode, lshr_optab, data_regs[i], GEN_INT (32),
+ NULL_RTX, 1, OPTAB_WIDEN);
+
+ emit_move_insn (change_address(orig_dst, SImode,
+ plus_constant (XEXP (orig_dst, 0),
+ ofs)),
+ gen_lowpart (SImode, data_regs[i]));
+ emit_move_insn (change_address(orig_dst, SImode,
+ plus_constant (XEXP (orig_dst, 0),
+ ofs+4)),
+ gen_lowpart (SImode, tmp));
+ ofs += 8;
+ i++;
+ }
+
+ while (i < nregs && GET_MODE (data_regs[i]) == SImode)
+ {
+ emit_move_insn (change_address(orig_dst, SImode,
+ plus_constant (XEXP (orig_dst, 0),
+ ofs)),
+ data_regs[i]);
+ ofs += 4;
+ i++;
+ }
+ }
+ if (i < nregs && GET_MODE (data_regs[i]) == DImode)
+ {
+ /* Write out a remaining block of words using unaligned methods. */
+
+ for (words = 1; i+words < nregs ; ++words)
+ if (GET_MODE (data_regs[i+words]) != DImode)
+ break;
+
+ if (words == 1)
+ alpha_expand_unaligned_store (orig_dst, data_regs[i], 8, ofs);
+ else
+ alpha_expand_unaligned_store_words (data_regs+i, orig_dst, words, ofs);
+
+ i += words;
+ ofs += words * 8;
+ }
+
+ /* Due to the above, this won't be aligned. */
+ /* ??? If we have more than one of these, consider constructing full
+ words in registers and using alpha_expand_unaligned_store_words. */
+ while (i < nregs && GET_MODE (data_regs[i]) == SImode)
+ {
+ alpha_expand_unaligned_store (orig_dst, data_regs[i], 4, ofs);
+ ofs += 4;
+ i++;
+ }
+
+ if (dst_align >= 2)
+ while (i < nregs && GET_MODE (data_regs[i]) == HImode)
+ {
+ emit_move_insn (change_address (orig_dst, HImode,
+ plus_constant (XEXP (orig_dst, 0),
+ ofs)),
+ data_regs[i]);
+ i++;
+ ofs += 2;
+ }
+ else
+ while (i < nregs && GET_MODE (data_regs[i]) == HImode)
+ {
+ alpha_expand_unaligned_store (orig_dst, data_regs[i], 2, ofs);
+ i++;
+ ofs += 2;
+ }
+ while (i < nregs && GET_MODE (data_regs[i]) == QImode)
+ {
+ emit_move_insn (change_address (orig_dst, QImode,
+ plus_constant (XEXP (orig_dst, 0),
+ ofs)),
+ data_regs[i]);
+ i++;
+ ofs += 1;
+ }
+ dst_done:
+
+ if (i != nregs)
+ abort();
+
+ return 1;
+}
+
+int
+alpha_expand_block_clear (operands)
+ rtx operands[];
+{
+ rtx bytes_rtx = operands[1];
+ rtx align_rtx = operands[2];
+ HOST_WIDE_INT bytes = INTVAL (bytes_rtx);
+ HOST_WIDE_INT align = INTVAL (align_rtx);
+ rtx orig_dst = operands[0];
+ rtx tmp;
+ HOST_WIDE_INT i, words, ofs = 0;
+
+ if (bytes <= 0)
+ return 1;
+ if (bytes > MAX_MOVE_WORDS*8)
+ return 0;
+
+ /* Look for stricter alignment. */
+
+ tmp = XEXP (orig_dst, 0);
+ if (GET_CODE (tmp) == REG)
+ {
+ if (REGNO_POINTER_ALIGN (REGNO (tmp)) > align)
+ align = REGNO_POINTER_ALIGN (REGNO (tmp));
+ }
+ else if (GET_CODE (tmp) == PLUS
+ && GET_CODE (XEXP (tmp, 0)) == REG
+ && GET_CODE (XEXP (tmp, 1)) == CONST_INT)
+ {
+ HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1));
+ int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0)));
+
+ if (a > align)
+ {
+ if (a >= 8 && c % 8 == 0)
+ align = 8;
+ else if (a >= 4 && c % 4 == 0)
+ align = 4;
+ else if (a >= 2 && c % 2 == 0)
+ align = 2;
+ }
+ }
+
+ /* Handle a block of contiguous words first. */
+
+ if (align >= 8 && bytes >= 8)
+ {
+ words = bytes / 8;
+
+ for (i = 0; i < words; ++i)
+ {
+ emit_move_insn (change_address(orig_dst, DImode,
+ plus_constant (XEXP (orig_dst, 0),
+ ofs + i*8)),
+ const0_rtx);
+ }
+
+ bytes -= words * 8;
+ ofs += words * 8;
+ }
+ if (align >= 4 && bytes >= 4)
+ {
+ words = bytes / 4;
+
+ for (i = 0; i < words; ++i)
+ {
+ emit_move_insn (change_address(orig_dst, SImode,
+ plus_constant (XEXP (orig_dst, 0),
+ ofs + i*4)),
+ const0_rtx);
+ }
+
+ bytes -= words * 4;
+ ofs += words * 4;
+ }
+ if (bytes >= 16)
+ {
+ words = bytes / 8;
+
+ alpha_expand_unaligned_store_words (NULL, orig_dst, words, ofs);
+
+ bytes -= words * 8;
+ ofs += words * 8;
+ }
+
+ /* Next clean up any trailing pieces. We know from the contiguous
+ block move that there are no aligned SImode or DImode hunks left. */
+
+ if (!TARGET_BWX && bytes >= 8)
+ {
+ alpha_expand_unaligned_store (orig_dst, const0_rtx, 8, ofs);
+ bytes -= 8;
+ ofs += 8;
+ }
+ if (!TARGET_BWX && bytes >= 4)
+ {
+ alpha_expand_unaligned_store (orig_dst, const0_rtx, 4, ofs);
+ bytes -= 4;
+ ofs += 4;
+ }
+ if (bytes >= 2)
+ {
+ if (align >= 2)
+ {
+ do {
+ emit_move_insn (change_address (orig_dst, HImode,
+ plus_constant (XEXP (orig_dst, 0),
+ ofs)),
+ const0_rtx);
+ bytes -= 2;
+ ofs += 2;
+ } while (bytes >= 2);
+ }
+ else if (!TARGET_BWX)
+ {
+ alpha_expand_unaligned_store (orig_dst, const0_rtx, 2, ofs);
+ bytes -= 2;
+ ofs += 2;
+ }
+ }
+ while (bytes > 0)
+ {
+ emit_move_insn (change_address (orig_dst, QImode,
+ plus_constant (XEXP (orig_dst, 0),
+ ofs)),
+ const0_rtx);
+ bytes -= 1;
+ ofs += 1;
+ }
+
+ return 1;
+}
+
/* Adjust the cost of a scheduling dependency. Return the new cost of
a dependency LINK or INSN on DEP_INSN. COST is the current cost. */
@@ -840,7 +2257,8 @@ alpha_adjust_cost (insn, link, dep_insn, cost)
rtx dep_insn;
int cost;
{
- rtx set;
+ rtx set, set_src;
+ enum attr_type insn_type, dep_insn_type;
/* If the dependence is an anti-dependence, there is no cost. For an
output dependence, there is sometimes a cost, but it doesn't seem
@@ -849,60 +2267,224 @@ alpha_adjust_cost (insn, link, dep_insn, cost)
if (REG_NOTE_KIND (link) != 0)
return 0;
- /* If INSN is a store insn and DEP_INSN is setting the data being stored,
- we can sometimes lower the cost. */
+ /* If we can't recognize the insns, we can't really do anything. */
+ if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
+ return cost;
- if (recog_memoized (insn) >= 0 && get_attr_type (insn) == TYPE_ST
- && (set = single_set (dep_insn)) != 0
- && GET_CODE (PATTERN (insn)) == SET
- && rtx_equal_p (SET_DEST (set), SET_SRC (PATTERN (insn))))
- switch (get_attr_type (dep_insn))
- {
- case TYPE_LD:
- /* No savings here. */
- return cost;
-
- case TYPE_IMULL:
- case TYPE_IMULQ:
- /* In these cases, we save one cycle. */
- return cost - 2;
-
- default:
- /* In all other cases, we save two cycles. */
- return MAX (0, cost - 4);
- }
+ insn_type = get_attr_type (insn);
+ dep_insn_type = get_attr_type (dep_insn);
- /* Another case that needs adjustment is an arithmetic or logical
- operation. It's cost is usually one cycle, but we default it to
- two in the MD file. The only case that it is actually two is
- for the address in loads and stores. */
+ /* Bring in the user-defined memory latency. */
+ if (dep_insn_type == TYPE_ILD
+ || dep_insn_type == TYPE_FLD
+ || dep_insn_type == TYPE_LDSYM)
+ cost += alpha_memory_latency-1;
- if (recog_memoized (dep_insn) >= 0
- && get_attr_type (dep_insn) == TYPE_IADDLOG)
- switch (get_attr_type (insn))
- {
- case TYPE_LD:
- case TYPE_ST:
- return cost;
+ switch (alpha_cpu)
+ {
+ case PROCESSOR_EV4:
+ /* On EV4, if INSN is a store insn and DEP_INSN is setting the data
+ being stored, we can sometimes lower the cost. */
+
+ if ((insn_type == TYPE_IST || insn_type == TYPE_FST)
+ && (set = single_set (dep_insn)) != 0
+ && GET_CODE (PATTERN (insn)) == SET
+ && rtx_equal_p (SET_DEST (set), SET_SRC (PATTERN (insn))))
+ {
+ switch (dep_insn_type)
+ {
+ case TYPE_ILD:
+ case TYPE_FLD:
+ /* No savings here. */
+ return cost;
+
+ case TYPE_IMUL:
+ /* In these cases, we save one cycle. */
+ return cost - 1;
+
+ default:
+ /* In all other cases, we save two cycles. */
+ return MAX (0, cost - 2);
+ }
+ }
- default:
- return 2;
- }
+ /* Another case that needs adjustment is an arithmetic or logical
+ operation. It's cost is usually one cycle, but we default it to
+ two in the MD file. The only case that it is actually two is
+ for the address in loads, stores, and jumps. */
- /* The final case is when a compare feeds into an integer branch. The cost
- is only one cycle in that case. */
+ if (dep_insn_type == TYPE_IADD || dep_insn_type == TYPE_ILOG)
+ {
+ switch (insn_type)
+ {
+ case TYPE_ILD:
+ case TYPE_IST:
+ case TYPE_FLD:
+ case TYPE_FST:
+ case TYPE_JSR:
+ return cost;
+ default:
+ return 1;
+ }
+ }
- if (recog_memoized (dep_insn) >= 0
- && get_attr_type (dep_insn) == TYPE_ICMP
- && recog_memoized (insn) >= 0
- && get_attr_type (insn) == TYPE_IBR)
- return 2;
+ /* The final case is when a compare feeds into an integer branch;
+ the cost is only one cycle in that case. */
- /* Otherwise, return the default cost. */
+ if (dep_insn_type == TYPE_ICMP && insn_type == TYPE_IBR)
+ return 1;
+ break;
+
+ case PROCESSOR_EV5:
+ /* And the lord DEC saith: "A special bypass provides an effective
+ latency of 0 cycles for an ICMP or ILOG insn producing the test
+ operand of an IBR or ICMOV insn." */
+
+ if ((dep_insn_type == TYPE_ICMP || dep_insn_type == TYPE_ILOG)
+ && (set = single_set (dep_insn)) != 0)
+ {
+ /* A branch only has one input. This must be it. */
+ if (insn_type == TYPE_IBR)
+ return 0;
+ /* A conditional move has three, make sure it is the test. */
+ if (insn_type == TYPE_ICMOV
+ && GET_CODE (set_src = PATTERN (insn)) == SET
+ && GET_CODE (set_src = SET_SRC (set_src)) == IF_THEN_ELSE
+ && rtx_equal_p (SET_DEST (set), XEXP (set_src, 0)))
+ return 0;
+ }
+
+ /* "The multiplier is unable to receive data from IEU bypass paths.
+ The instruction issues at the expected time, but its latency is
+ increased by the time it takes for the input data to become
+ available to the multiplier" -- which happens in pipeline stage
+ six, when results are comitted to the register file. */
+ if (insn_type == TYPE_IMUL)
+ {
+ switch (dep_insn_type)
+ {
+ /* These insns produce their results in pipeline stage five. */
+ case TYPE_ILD:
+ case TYPE_ICMOV:
+ case TYPE_IMUL:
+ case TYPE_MVI:
+ return cost + 1;
+
+ /* Other integer insns produce results in pipeline stage four. */
+ default:
+ return cost + 2;
+ }
+ }
+ break;
+
+ case PROCESSOR_EV6:
+ /* There is additional latency to move the result of (most) FP
+ operations anywhere but the FP register file. */
+
+ if ((insn_type == TYPE_FST || insn_type == TYPE_FTOI)
+ && (dep_insn_type == TYPE_FADD ||
+ dep_insn_type == TYPE_FMUL ||
+ dep_insn_type == TYPE_FCMOV))
+ return cost + 2;
+
+ break;
+ }
+
+ /* Otherwise, return the default cost. */
return cost;
}
+/* Functions to save and restore alpha_return_addr_rtx. */
+
+struct machine_function
+{
+ rtx ra_rtx;
+};
+
+static void
+alpha_save_machine_status (p)
+ struct function *p;
+{
+ struct machine_function *machine =
+ (struct machine_function *) xmalloc (sizeof (struct machine_function));
+
+ p->machine = machine;
+ machine->ra_rtx = alpha_return_addr_rtx;
+}
+
+static void
+alpha_restore_machine_status (p)
+ struct function *p;
+{
+ struct machine_function *machine = p->machine;
+
+ alpha_return_addr_rtx = machine->ra_rtx;
+
+ free (machine);
+ p->machine = (struct machine_function *)0;
+}
+
+/* Do anything needed before RTL is emitted for each function. */
+
+void
+alpha_init_expanders ()
+{
+ alpha_return_addr_rtx = NULL_RTX;
+
+ /* Arrange to save and restore machine status around nested functions. */
+ save_machine_status = alpha_save_machine_status;
+ restore_machine_status = alpha_restore_machine_status;
+}
+
+/* Start the ball rolling with RETURN_ADDR_RTX. */
+
+rtx
+alpha_return_addr (count, frame)
+ int count;
+ rtx frame ATTRIBUTE_UNUSED;
+{
+ rtx init;
+
+ if (count != 0)
+ return const0_rtx;
+
+ if (alpha_return_addr_rtx)
+ return alpha_return_addr_rtx;
+
+ /* No rtx yet. Invent one, and initialize it from $26 in the prologue. */
+ alpha_return_addr_rtx = gen_reg_rtx (Pmode);
+ init = gen_rtx_SET (Pmode, alpha_return_addr_rtx,
+ gen_rtx_REG (Pmode, REG_RA));
+
+ /* Emit the insn to the prologue with the other argument copies. */
+ push_topmost_sequence ();
+ emit_insn_after (init, get_insns ());
+ pop_topmost_sequence ();
+
+ return alpha_return_addr_rtx;
+}
+
+static int
+alpha_ra_ever_killed ()
+{
+ rtx top;
+
+#ifdef ASM_OUTPUT_MI_THUNK
+ if (current_function_is_thunk)
+ return 0;
+#endif
+ if (!alpha_return_addr_rtx)
+ return regs_ever_live[REG_RA];
+
+ push_topmost_sequence ();
+ top = get_insns();
+ pop_topmost_sequence ();
+
+ return reg_set_between_p (gen_rtx_REG (Pmode, REG_RA), top, NULL_RTX);
+}
+
+
/* Print an operand. Recognize special options, documented below. */
void
@@ -915,6 +2497,115 @@ print_operand (file, x, code)
switch (code)
{
+ case '&':
+ /* Generates fp-rounding mode suffix: nothing for normal, 'c' for
+ chopped, 'm' for minus-infinity, and 'd' for dynamic rounding
+ mode. alpha_fprm controls which suffix is generated. */
+ switch (alpha_fprm)
+ {
+ case ALPHA_FPRM_NORM:
+ break;
+ case ALPHA_FPRM_MINF:
+ fputc ('m', file);
+ break;
+ case ALPHA_FPRM_CHOP:
+ fputc ('c', file);
+ break;
+ case ALPHA_FPRM_DYN:
+ fputc ('d', file);
+ break;
+ }
+ break;
+
+ case '\'':
+ /* Generates trap-mode suffix for instructions that accept the su
+ suffix only (cmpt et al). */
+ if (alpha_tp == ALPHA_TP_INSN)
+ fputs ("su", file);
+ break;
+
+ case '`':
+ /* Generates trap-mode suffix for instructions that accept the
+ v and sv suffix. The only instruction that needs this is cvtql. */
+ switch (alpha_fptm)
+ {
+ case ALPHA_FPTM_N:
+ break;
+ case ALPHA_FPTM_U:
+ fputs ("v", file);
+ break;
+ case ALPHA_FPTM_SU:
+ case ALPHA_FPTM_SUI:
+ fputs ("sv", file);
+ break;
+ }
+ break;
+
+ case '(':
+ /* Generates trap-mode suffix for instructions that accept the
+ v, sv, and svi suffix. The only instruction that needs this
+ is cvttq. */
+ switch (alpha_fptm)
+ {
+ case ALPHA_FPTM_N:
+ break;
+ case ALPHA_FPTM_U:
+ fputs ("v", file);
+ break;
+ case ALPHA_FPTM_SU:
+ fputs ("sv", file);
+ break;
+ case ALPHA_FPTM_SUI:
+ fputs ("svi", file);
+ break;
+ }
+ break;
+
+ case ')':
+ /* Generates trap-mode suffix for instructions that accept the u, su,
+ and sui suffix. This is the bulk of the IEEE floating point
+ instructions (addt et al). */
+ switch (alpha_fptm)
+ {
+ case ALPHA_FPTM_N:
+ break;
+ case ALPHA_FPTM_U:
+ fputc ('u', file);
+ break;
+ case ALPHA_FPTM_SU:
+ fputs ("su", file);
+ break;
+ case ALPHA_FPTM_SUI:
+ fputs ("sui", file);
+ break;
+ }
+ break;
+
+ case '+':
+ /* Generates trap-mode suffix for instructions that accept the sui
+ suffix (cvtqt and cvtqs). */
+ switch (alpha_fptm)
+ {
+ case ALPHA_FPTM_N:
+ case ALPHA_FPTM_U:
+ case ALPHA_FPTM_SU: /* cvtqt/cvtqs can't cause underflow */
+ break;
+ case ALPHA_FPTM_SUI:
+ fputs ("sui", file);
+ break;
+ }
+ break;
+
+ case ',':
+ /* Generates single precision instruction suffix. */
+ fprintf (file, "%c", (TARGET_FLOAT_VAX ? 'f' : 's'));
+ break;
+
+ case '-':
+ /* Generates double precision instruction suffix. */
+ fprintf (file, "%c", (TARGET_FLOAT_VAX ? 'g' : 't'));
+ break;
+
case 'r':
/* If this operand is the constant zero, write it as "$31". */
if (GET_CODE (x) == REG)
@@ -942,7 +2633,7 @@ print_operand (file, x, code)
if (GET_CODE (x) != CONST_INT)
output_operand_lossage ("invalid %%N value");
- fprintf (file, "%ld", ~ INTVAL (x));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INTVAL (x));
break;
case 'P':
@@ -950,7 +2641,7 @@ print_operand (file, x, code)
if (GET_CODE (x) != CONST_INT)
output_operand_lossage ("invalid %%P value");
- fprintf (file, "%ld", (HOST_WIDE_INT) 1 << INTVAL (x));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT) 1 << INTVAL (x));
break;
case 'h':
@@ -958,7 +2649,7 @@ print_operand (file, x, code)
if (GET_CODE (x) != CONST_INT)
output_operand_lossage ("invalid %%h value");
- fprintf (file, "%ld", INTVAL (x) >> 16);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) >> 16);
break;
case 'L':
@@ -966,7 +2657,8 @@ print_operand (file, x, code)
if (GET_CODE (x) != CONST_INT)
output_operand_lossage ("invalid %%L value");
- fprintf (file, "%ld", (INTVAL (x) & 0xffff) - 2 * (INTVAL (x) & 0x8000));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ (INTVAL (x) & 0xffff) - 2 * (INTVAL (x) & 0x8000));
break;
case 'm':
@@ -988,7 +2680,7 @@ print_operand (file, x, code)
if (value & 0xff)
mask |= (1 << (i + sizeof (int)));
- fprintf (file, "%ld", mask & 0xff);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask & 0xff);
}
else if (GET_CODE (x) == CONST_INT)
@@ -999,20 +2691,24 @@ print_operand (file, x, code)
if (value & 0xff)
mask |= (1 << i);
- fprintf (file, "%ld", mask);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask);
}
else
output_operand_lossage ("invalid %%m value");
break;
case 'M':
- /* 'b', 'w', or 'l' as the value of the constant. */
+ /* 'b', 'w', 'l', or 'q' as the value of the constant. */
if (GET_CODE (x) != CONST_INT
- || (INTVAL (x) != 8 && INTVAL (x) != 16 && INTVAL (x) != 32))
+ || (INTVAL (x) != 8 && INTVAL (x) != 16
+ && INTVAL (x) != 32 && INTVAL (x) != 64))
output_operand_lossage ("invalid %%M value");
fprintf (file, "%s",
- INTVAL (x) == 8 ? "b" : INTVAL (x) == 16 ? "w" : "l");
+ (INTVAL (x) == 8 ? "b"
+ : INTVAL (x) == 16 ? "w"
+ : INTVAL (x) == 32 ? "l"
+ : "q"));
break;
case 'U':
@@ -1021,14 +2717,24 @@ print_operand (file, x, code)
fprintf (file, "b");
else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffff)
fprintf (file, "w");
+ else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffff)
+ fprintf (file, "l");
#if HOST_BITS_PER_WIDE_INT == 32
else if (GET_CODE (x) == CONST_DOUBLE
&& CONST_DOUBLE_HIGH (x) == 0
&& CONST_DOUBLE_LOW (x) == -1)
fprintf (file, "l");
+ else if (GET_CODE (x) == CONST_DOUBLE
+ && CONST_DOUBLE_HIGH (x) == -1
+ && CONST_DOUBLE_LOW (x) == -1)
+ fprintf (file, "q");
#else
- else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffff)
- fprintf (file, "l");
+ else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffffffffffff)
+ fprintf (file, "q");
+ else if (GET_CODE (x) == CONST_DOUBLE
+ && CONST_DOUBLE_HIGH (x) == 0
+ && CONST_DOUBLE_LOW (x) == -1)
+ fprintf (file, "q");
#endif
else
output_operand_lossage ("invalid %%U value");
@@ -1041,7 +2747,7 @@ print_operand (file, x, code)
&& (INTVAL (x) & 7) != 8)
output_operand_lossage ("invalid %%s value");
- fprintf (file, "%ld", INTVAL (x) / 8);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) / 8);
break;
case 'S':
@@ -1052,46 +2758,31 @@ print_operand (file, x, code)
&& (INTVAL (x) & 7) != 8)
output_operand_lossage ("invalid %%s value");
- fprintf (file, "%ld", (64 - INTVAL (x)) / 8);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, (64 - INTVAL (x)) / 8);
break;
- case 'C':
+ case 'C': case 'D': case 'c': case 'd':
/* Write out comparison name. */
- if (GET_RTX_CLASS (GET_CODE (x)) != '<')
- output_operand_lossage ("invalid %%C value");
-
- if (GET_CODE (x) == LEU)
- fprintf (file, "ule");
- else if (GET_CODE (x) == LTU)
- fprintf (file, "ult");
- else
- fprintf (file, "%s", GET_RTX_NAME (GET_CODE (x)));
- break;
-
- case 'D':
- /* Similar, but write reversed code. We can't get an unsigned code
- here. */
- if (GET_RTX_CLASS (GET_CODE (x)) != '<')
- output_operand_lossage ("invalid %%D value");
-
- fprintf (file, "%s", GET_RTX_NAME (reverse_condition (GET_CODE (x))));
- break;
-
- case 'c':
- /* Similar to `c', but swap. We can't get unsigned here either. */
- if (GET_RTX_CLASS (GET_CODE (x)) != '<')
- output_operand_lossage ("invalid %%D value");
-
- fprintf (file, "%s", GET_RTX_NAME (swap_condition (GET_CODE (x))));
- break;
-
- case 'd':
- /* Similar, but reverse and swap. We can't get unsigned here either. */
- if (GET_RTX_CLASS (GET_CODE (x)) != '<')
- output_operand_lossage ("invalid %%D value");
-
- fprintf (file, "%s",
- GET_RTX_NAME (swap_condition (reverse_condition ((GET_CODE (x))))));
+ {
+ enum rtx_code c = GET_CODE (x);
+
+ if (GET_RTX_CLASS (c) != '<')
+ output_operand_lossage ("invalid %%C value");
+
+ if (code == 'D')
+ c = reverse_condition (c);
+ else if (code == 'c')
+ c = swap_condition (c);
+ else if (code == 'd')
+ c = swap_condition (reverse_condition (c));
+
+ if (c == LEU)
+ fprintf (file, "ule");
+ else if (c == LTU)
+ fprintf (file, "ult");
+ else
+ fprintf (file, "%s", GET_RTX_NAME (c));
+ }
break;
case 'E':
@@ -1136,6 +2827,65 @@ print_operand (file, x, code)
}
}
+/* Emit RTL insns to initialize the variable parts of a trampoline at
+ TRAMP. FNADDR is an RTX for the address of the function's pure
+ code. CXT is an RTX for the static chain value for the function.
+
+ The three offset parameters are for the individual template's
+ layout. A JMPOFS < 0 indicates that the trampoline does not
+ contain instructions at all.
+
+ We assume here that a function will be called many more times than
+ its address is taken (e.g., it might be passed to qsort), so we
+ take the trouble to initialize the "hint" field in the JMP insn.
+ Note that the hint field is PC (new) + 4 * bits 13:0. */
+
+void
+alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
+ rtx tramp, fnaddr, cxt;
+ int fnofs, cxtofs, jmpofs;
+{
+ rtx temp, temp1, addr;
+ /* ??? Something is wrong with VMS codegen in that we get aborts when
+ using ptr_mode. Hack around it for now. */
+ enum machine_mode mode = TARGET_OPEN_VMS ? Pmode : ptr_mode;
+
+ /* Store function address and CXT. */
+ addr = memory_address (mode, plus_constant (tramp, fnofs));
+ emit_move_insn (gen_rtx (MEM, mode, addr), fnaddr);
+ addr = memory_address (mode, plus_constant (tramp, cxtofs));
+ emit_move_insn (gen_rtx (MEM, mode, addr), cxt);
+
+ /* This has been disabled since the hint only has a 32k range, and in
+ no existing OS is the stack within 32k of the text segment. */
+ if (0 && jmpofs >= 0)
+ {
+ /* Compute hint value. */
+ temp = force_operand (plus_constant (tramp, jmpofs+4), NULL_RTX);
+ temp = expand_binop (DImode, sub_optab, fnaddr, temp, temp, 1,
+ OPTAB_WIDEN);
+ temp = expand_shift (RSHIFT_EXPR, Pmode, temp,
+ build_int_2 (2, 0), NULL_RTX, 1);
+ temp = expand_and (gen_lowpart (SImode, temp), GEN_INT (0x3fff), 0);
+
+ /* Merge in the hint. */
+ addr = memory_address (SImode, plus_constant (tramp, jmpofs));
+ temp1 = force_reg (SImode, gen_rtx (MEM, SImode, addr));
+ temp1 = expand_and (temp1, GEN_INT (0xffffc000), NULL_RTX);
+ temp1 = expand_binop (SImode, ior_optab, temp1, temp, temp1, 1,
+ OPTAB_WIDEN);
+ emit_move_insn (gen_rtx (MEM, SImode, addr), temp1);
+ }
+
+#ifdef TRANSFER_FROM_TRAMPOLINE
+ emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
+ 0, VOIDmode, 1, addr, Pmode);
+#endif
+
+ if (jmpofs >= 0)
+ emit_insn (gen_imb ());
+}
+
/* Do what is necessary for `va_start'. The argument is ignored;
We look at the current function to determine if stdarg or varargs
is used and fill in an initial va_list. A pointer to this constructor
@@ -1143,9 +2893,9 @@ print_operand (file, x, code)
struct rtx_def *
alpha_builtin_saveregs (arglist)
- tree arglist;
+ tree arglist ATTRIBUTE_UNUSED;
{
- rtx block, addr, argsize;
+ rtx block, addr, dest, argsize;
tree fntype = TREE_TYPE (current_function_decl);
int stdarg = (TYPE_ARG_TYPES (fntype) != 0
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
@@ -1153,11 +2903,11 @@ alpha_builtin_saveregs (arglist)
/* Compute the current position into the args, taking into account
both registers and memory. Both of these are already included in
- current_function_args_info. */
+ NUM_ARGS. */
- argsize = GEN_INT (current_function_args_info * UNITS_PER_WORD);
+ argsize = GEN_INT (NUM_ARGS * UNITS_PER_WORD);
- /* SETUP_INCOMING_VARARGS moves the starting address base up by 48,
+ /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base up by 48,
storing fp arg registers in the first 48 bytes, and the integer arg
registers in the next 48 bytes. This is only done, however, if any
integer registers need to be stored.
@@ -1166,35 +2916,71 @@ alpha_builtin_saveregs (arglist)
order to account for the integer arg registers which are counted in
argsize above, but which are not actually stored on the stack. */
- addr = (current_function_args_info <= 5 + stdarg
- ? plus_constant (virtual_incoming_args_rtx, 6 * UNITS_PER_WORD)
- : plus_constant (virtual_incoming_args_rtx, - (6 * UNITS_PER_WORD)));
-
- addr = force_operand (addr, NULL_RTX);
+ if (TARGET_OPEN_VMS)
+ addr = plus_constant (virtual_incoming_args_rtx,
+ NUM_ARGS <= 5 + stdarg
+ ? UNITS_PER_WORD : - 6 * UNITS_PER_WORD);
+ else
+ addr = (NUM_ARGS <= 5 + stdarg
+ ? plus_constant (virtual_incoming_args_rtx,
+ 6 * UNITS_PER_WORD)
+ : plus_constant (virtual_incoming_args_rtx,
+ - (6 * UNITS_PER_WORD)));
- /* Allocate the va_list constructor */
- block = assign_stack_local (BLKmode, 2 * UNITS_PER_WORD, BITS_PER_WORD);
- RTX_UNCHANGING_P (block) = 1;
- RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
+ /* For VMS, we include the argsize, while on Unix, it's handled as
+ a separate field. */
+ if (TARGET_OPEN_VMS)
+ addr = plus_constant (addr, INTVAL (argsize));
- /* Store the address of the first integer register in the __base member. */
+ addr = force_operand (addr, NULL_RTX);
#ifdef POINTERS_EXTEND_UNSIGNED
addr = convert_memory_address (ptr_mode, addr);
#endif
- emit_move_insn (change_address (block, ptr_mode, XEXP (block, 0)), addr);
-
- /* Store the argsize as the __va_offset member. */
- emit_move_insn (change_address (block, TYPE_MODE (integer_type_node),
- plus_constant (XEXP (block, 0),
- POINTER_SIZE/BITS_PER_UNIT)),
- argsize);
-
- /* Return the address of the va_list constructor, but don't put it in a
- register. Doing so would fail when not optimizing and produce worse
- code when optimizing. */
- return XEXP (block, 0);
+ if (TARGET_OPEN_VMS)
+ return addr;
+ else
+ {
+ /* Allocate the va_list constructor */
+ block = assign_stack_local (BLKmode, 2 * UNITS_PER_WORD, BITS_PER_WORD);
+ RTX_UNCHANGING_P (block) = 1;
+ RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
+
+ /* Store the address of the first integer register in the __base
+ member. */
+
+ dest = change_address (block, ptr_mode, XEXP (block, 0));
+ emit_move_insn (dest, addr);
+
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ dest, ptr_mode,
+ GEN_INT (GET_MODE_SIZE (ptr_mode)),
+ TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_RW),
+ TYPE_MODE (integer_type_node));
+
+ /* Store the argsize as the __va_offset member. */
+ dest = change_address (block, TYPE_MODE (integer_type_node),
+ plus_constant (XEXP (block, 0),
+ POINTER_SIZE/BITS_PER_UNIT));
+ emit_move_insn (dest, argsize);
+
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ dest, ptr_mode,
+ GEN_INT (GET_MODE_SIZE
+ (TYPE_MODE (integer_type_node))),
+ TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_RW),
+ TYPE_MODE (integer_type_node));
+
+ /* Return the address of the va_list constructor, but don't put it in a
+ register. Doing so would fail when not optimizing and produce worse
+ code when optimizing. */
+ return XEXP (block, 0);
+ }
}
/* This page contains routines that are used to determine what the function
@@ -1202,43 +2988,203 @@ alpha_builtin_saveregs (arglist)
/* Compute the size of the save area in the stack. */
+/* These variables are used for communication between the following functions.
+ They indicate various things about the current function being compiled
+ that are used to tell what kind of prologue, epilogue and procedure
+ descriptior to generate. */
+
+/* Nonzero if we need a stack procedure. */
+static int vms_is_stack_procedure;
+
+/* Register number (either FP or SP) that is used to unwind the frame. */
+static int vms_unwind_regno;
+
+/* Register number used to save FP. We need not have one for RA since
+ we don't modify it for register procedures. This is only defined
+ for register frame procedures. */
+static int vms_save_fp_regno;
+
+/* Register number used to reference objects off our PV. */
+static int vms_base_regno;
+
+/* Compute register masks for saved registers. */
+
+static void
+alpha_sa_mask (imaskP, fmaskP)
+ unsigned long *imaskP;
+ unsigned long *fmaskP;
+{
+ unsigned long imask = 0;
+ unsigned long fmask = 0;
+ int i;
+
+#ifdef ASM_OUTPUT_MI_THUNK
+ if (!current_function_is_thunk)
+#endif
+ {
+ if (TARGET_OPEN_VMS && vms_is_stack_procedure)
+ imask |= (1L << HARD_FRAME_POINTER_REGNUM);
+
+ /* One for every register we have to save. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (! fixed_regs[i] && ! call_used_regs[i]
+ && regs_ever_live[i] && i != REG_RA)
+ {
+ if (i < 32)
+ imask |= (1L << i);
+ else
+ fmask |= (1L << (i - 32));
+ }
+
+ if (imask || fmask || alpha_ra_ever_killed ())
+ imask |= (1L << REG_RA);
+ }
+
+ *imaskP = imask;
+ *fmaskP = fmask;
+}
+
int
alpha_sa_size ()
{
- int size = 0;
+ int sa_size = 0;
int i;
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i])
- size++;
+#ifdef ASM_OUTPUT_MI_THUNK
+ if (current_function_is_thunk)
+ sa_size = 0;
+ else
+#endif
+ {
+ /* One for every register we have to save. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (! fixed_regs[i] && ! call_used_regs[i]
+ && regs_ever_live[i] && i != REG_RA)
+ sa_size++;
+ }
- /* If some registers were saved but not reg 26, reg 26 must also
- be saved, so leave space for it. */
- if (size != 0 && ! regs_ever_live[26])
- size++;
+ if (TARGET_OPEN_VMS)
+ {
+ /* Start by assuming we can use a register procedure if we don't
+ make any calls (REG_RA not used) or need to save any
+ registers and a stack procedure if we do. */
+ vms_is_stack_procedure = sa_size != 0 || alpha_ra_ever_killed ();
+
+ /* Decide whether to refer to objects off our PV via FP or PV.
+ If we need FP for something else or if we receive a nonlocal
+ goto (which expects PV to contain the value), we must use PV.
+ Otherwise, start by assuming we can use FP. */
+ vms_base_regno = (frame_pointer_needed
+ || current_function_has_nonlocal_label
+ || vms_is_stack_procedure
+ || current_function_outgoing_args_size
+ ? REG_PV : HARD_FRAME_POINTER_REGNUM);
+
+ /* If we want to copy PV into FP, we need to find some register
+ in which to save FP. */
+
+ vms_save_fp_regno = -1;
+ if (vms_base_regno == HARD_FRAME_POINTER_REGNUM)
+ for (i = 0; i < 32; i++)
+ if (! fixed_regs[i] && call_used_regs[i] && ! regs_ever_live[i])
+ vms_save_fp_regno = i;
+
+ if (vms_save_fp_regno == -1)
+ vms_base_regno = REG_PV, vms_is_stack_procedure = 1;
+
+ /* Stack unwinding should be done via FP unless we use it for PV. */
+ vms_unwind_regno = (vms_base_regno == REG_PV
+ ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
+
+ /* If this is a stack procedure, allow space for saving FP and RA. */
+ if (vms_is_stack_procedure)
+ sa_size += 2;
+ }
+ else
+ {
+ /* If some registers were saved but not RA, RA must also be saved,
+ so leave space for it. */
+ if (sa_size != 0 || alpha_ra_ever_killed ())
+ sa_size++;
+
+ /* Our size must be even (multiple of 16 bytes). */
+ if (sa_size & 1)
+ sa_size++;
+ }
- /* Our size must be even (multiple of 16 bytes). */
- if (size & 1)
- size ++;
+ return sa_size * 8;
+}
- return size * 8;
+int
+alpha_pv_save_size ()
+{
+ alpha_sa_size ();
+ return vms_is_stack_procedure ? 8 : 0;
}
-/* Return 1 if this function can directly return via $26. */
+int
+alpha_using_fp ()
+{
+ alpha_sa_size ();
+ return vms_unwind_regno == HARD_FRAME_POINTER_REGNUM;
+}
int
-direct_return ()
+vms_valid_decl_attribute_p (decl, attributes, identifier, args)
+ tree decl ATTRIBUTE_UNUSED;
+ tree attributes ATTRIBUTE_UNUSED;
+ tree identifier;
+ tree args;
{
- return (reload_completed && alpha_sa_size () == 0
- && get_frame_size () == 0
- && current_function_outgoing_args_size == 0
- && current_function_pretend_args_size == 0);
+ if (is_attribute_p ("overlaid", identifier))
+ return (args == NULL_TREE);
+ return 0;
+}
+
+static int
+alpha_does_function_need_gp ()
+{
+ rtx insn;
+
+ /* We never need a GP for Windows/NT or VMS. */
+ if (TARGET_WINDOWS_NT || TARGET_OPEN_VMS)
+ return 0;
+
+#ifdef TARGET_PROFILING_NEEDS_GP
+ if (profile_flag)
+ return 1;
+#endif
+
+#ifdef ASM_OUTPUT_MI_THUNK
+ if (current_function_is_thunk)
+ return 1;
+#endif
+
+ /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first.
+ Even if we are a static function, we still need to do this in case
+ our address is taken and passed to something like qsort. */
+
+ push_topmost_sequence ();
+ insn = get_insns ();
+ pop_topmost_sequence ();
+
+ for (; insn; insn = NEXT_INSN (insn))
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && GET_CODE (PATTERN (insn)) != USE
+ && GET_CODE (PATTERN (insn)) != CLOBBER)
+ {
+ enum attr_type type = get_attr_type (insn);
+ if (type == TYPE_LDSYM || type == TYPE_JSR)
+ return 1;
+ }
+
+ return 0;
}
/* Write a version stamp. Don't write anything if we are running as a
cross-compiler. Otherwise, use the versions in /usr/include/stamp.h. */
-#if !defined(CROSS_COMPILE) && !defined(_WIN32)
+#ifdef HAVE_STAMP_H
#include <stamp.h>
#endif
@@ -1251,145 +3197,58 @@ alpha_write_verstamp (file)
#endif
}
-/* Write code to add constant C to register number IN_REG (possibly 31)
- and put the result into OUT_REG. Use TEMP_REG as a scratch register;
- usually this will be OUT_REG, but should not be if OUT_REG is
- STACK_POINTER_REGNUM, since it must be updated in a single instruction.
- Write the code to FILE. */
-
-static void
-add_long_const (file, c, in_reg, out_reg, temp_reg)
- FILE *file;
- HOST_WIDE_INT c;
- int in_reg, out_reg, temp_reg;
-{
- HOST_WIDE_INT low = (c & 0xffff) - 2 * (c & 0x8000);
- HOST_WIDE_INT tmp1 = c - low;
- HOST_WIDE_INT high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000);
- HOST_WIDE_INT extra = 0;
-
- /* We don't have code to write out constants larger than 32 bits. */
-#if HOST_BITS_PER_LONG_INT == 64
- if ((unsigned HOST_WIDE_INT) c >> 32 != 0)
- abort ();
-#endif
-
- /* If HIGH will be interpreted as negative, we must adjust it to do two
- ldha insns. Note that we will never be building a negative constant
- here. */
-
- if (high & 0x8000)
- {
- extra = 0x4000;
- tmp1 -= 0x40000000;
- high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000);
- }
-
- if (low != 0)
- {
- int result_reg = (extra == 0 && high == 0) ? out_reg : temp_reg;
-
- if (low >= 0 && low < 255)
- fprintf (file, "\taddq $%d,%d,$%d\n", in_reg, low, result_reg);
- else
- fprintf (file, "\tlda $%d,%d($%d)\n", result_reg, low, in_reg);
-
- in_reg = result_reg;
- }
+/* Write function prologue. */
- if (extra)
- {
- int result_reg = (high == 0) ? out_reg : temp_reg;
+/* On vms we have two kinds of functions:
- fprintf (file, "\tldah $%d,%d($%d)\n", result_reg, extra, in_reg);
- in_reg = result_reg;
- }
+ - stack frame (PROC_STACK)
+ these are 'normal' functions with local vars and which are
+ calling other functions
+ - register frame (PROC_REGISTER)
+ keeps all data in registers, needs no stack
- if (high)
- fprintf (file, "\tldah $%d,%d($%d)\n", out_reg, high, in_reg);
-}
+ We must pass this to the assembler so it can generate the
+ proper pdsc (procedure descriptor)
+ This is done with the '.pdesc' command.
-/* Write function prologue. */
+ On not-vms, we don't really differentiate between the two, as we can
+ simply allocate stack without saving registers. */
void
-output_prolog (file, size)
- FILE *file;
- int size;
-{
- HOST_WIDE_INT out_args_size
- = ALPHA_ROUND (current_function_outgoing_args_size);
- HOST_WIDE_INT sa_size = alpha_sa_size ();
- HOST_WIDE_INT frame_size
- = (out_args_size + sa_size
- + ALPHA_ROUND (size + current_function_pretend_args_size));
- HOST_WIDE_INT reg_offset = out_args_size;
- HOST_WIDE_INT start_reg_offset = reg_offset;
- HOST_WIDE_INT actual_start_reg_offset = start_reg_offset;
- int int_reg_save_area_size = 0;
- rtx insn;
- unsigned reg_mask = 0;
+alpha_expand_prologue ()
+{
+ /* Registers to save. */
+ unsigned long imask = 0;
+ unsigned long fmask = 0;
+ /* Stack space needed for pushing registers clobbered by us. */
+ HOST_WIDE_INT sa_size;
+ /* Complete stack size needed. */
+ HOST_WIDE_INT frame_size;
+ /* Offset from base reg to register save area. */
+ HOST_WIDE_INT reg_offset;
+ rtx sa_reg;
int i;
- /* Ecoff can handle multiple .file directives, so put out file and lineno.
- We have to do that before the .ent directive as we cannot switch
- files within procedures with native ecoff because line numbers are
- linked to procedure descriptors.
- Outputting the lineno helps debugging of one line functions as they
- would otherwise get no line number at all. Please note that we would
- like to put out last_linenum from final.c, but it is not accessible. */
-
- if (write_symbols == SDB_DEBUG)
- {
- ASM_OUTPUT_SOURCE_FILENAME (file,
- DECL_SOURCE_FILE (current_function_decl));
- if (debug_info_level != DINFO_LEVEL_TERSE)
- ASM_OUTPUT_SOURCE_LINE (file,
- DECL_SOURCE_LINE (current_function_decl));
- }
-
- /* The assembly language programmer's guide states that the second argument
- to the .ent directive, the lex_level, is ignored by the assembler,
- so we might as well omit it. */
-
- fprintf (file, "\t.ent ");
- assemble_name (file, alpha_function_name);
- fprintf (file, "\n");
- ASM_OUTPUT_LABEL (file, alpha_function_name);
- inside_function = TRUE;
-
- /* Set up offsets to alpha virtual arg/local debugging pointer. */
+ sa_size = alpha_sa_size ();
- alpha_auto_offset = -frame_size + current_function_pretend_args_size;
- alpha_arg_offset = -frame_size + 48;
-
- /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first.
- Even if we are a static function, we still need to do this in case
- our address is taken and passed to something like qsort.
-
- We never need a GP for Windows/NT. */
-
- alpha_function_needs_gp = 0;
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if ((GET_CODE (insn) == CALL_INSN)
- || (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- && GET_CODE (PATTERN (insn)) != USE
- && GET_CODE (PATTERN (insn)) != CLOBBER
- && (get_attr_type (insn) == TYPE_LDSYM
- || get_attr_type (insn) == TYPE_ISUBR)))
- {
- alpha_function_needs_gp = 1;
- break;
- }
+ frame_size = get_frame_size ();
+ if (TARGET_OPEN_VMS)
+ frame_size = ALPHA_ROUND (sa_size
+ + (vms_is_stack_procedure ? 8 : 0)
+ + frame_size
+ + current_function_pretend_args_size);
+ else
+ frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
+ + sa_size
+ + ALPHA_ROUND (frame_size
+ + current_function_pretend_args_size));
- if (WINDOWS_NT == 0)
- {
- if (alpha_function_needs_gp)
- fprintf (file, "\tldgp $29,0($27)\n");
+ if (TARGET_OPEN_VMS)
+ reg_offset = 8;
+ else
+ reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
- /* Put a label after the GP load so we can enter the function at it. */
- assemble_name (file, alpha_function_name);
- fprintf (file, "..ng:\n");
- }
+ alpha_sa_mask (&imask, &fmask);
/* Adjust the stack by the frame size. If the frame size is > 4096
bytes, we need to be sure we probe somewhere in the first and last
@@ -1400,28 +3259,30 @@ output_prolog (file, size)
Note that we are only allowed to adjust sp once in the prologue. */
- if (frame_size < 32768)
+ if (frame_size <= 32768)
{
if (frame_size > 4096)
{
int probed = 4096;
- fprintf (file, "\tstq $31,-%d($30)\n", probed);
-
- while (probed + 8192 < frame_size)
- fprintf (file, "\tstq $31,-%d($30)\n", probed += 8192);
+ do
+ emit_insn (gen_probe_stack (GEN_INT (-probed)));
+ while ((probed += 8192) < frame_size);
/* We only have to do this probe if we aren't saving registers. */
if (sa_size == 0 && probed + 4096 < frame_size)
- fprintf (file, "\tstq $31,-%d($30)\n", frame_size);
+ emit_insn (gen_probe_stack (GEN_INT (-frame_size)));
}
if (frame_size != 0)
- fprintf (file, "\tlda $30,-%d($30)\n", frame_size);
+ {
+ emit_move_insn (stack_pointer_rtx,
+ plus_constant (stack_pointer_rtx, -frame_size));
+ }
}
else
{
- /* Here we generate code to set R4 to SP + 4096 and set R5 to the
+ /* Here we generate code to set R22 to SP + 4096 and set R23 to the
number of 8192 byte blocks to probe. We then probe each block
in the loop and then set SP to the proper location. If the
amount remaining is > 4096, we have to do one more probe if we
@@ -1429,182 +3290,538 @@ output_prolog (file, size)
HOST_WIDE_INT blocks = (frame_size + 4096) / 8192;
HOST_WIDE_INT leftover = frame_size + 4096 - blocks * 8192;
+ rtx ptr = gen_rtx_REG (DImode, 22);
+ rtx count = gen_rtx_REG (DImode, 23);
- add_long_const (file, blocks, 31, 5, 5);
+ emit_move_insn (count, GEN_INT (blocks));
+ emit_move_insn (ptr, plus_constant (stack_pointer_rtx, 4096));
- fprintf (file, "\tlda $4,4096($30)\n");
+ /* Because of the difficulty in emitting a new basic block this
+ late in the compilation, generate the loop as a single insn. */
+ emit_insn (gen_prologue_stack_probe_loop (count, ptr));
- assemble_name (file, alpha_function_name);
- fprintf (file, "..sc:\n");
+ if (leftover > 4096 && sa_size == 0)
+ {
+ rtx last = gen_rtx_MEM (DImode, plus_constant (ptr, -leftover));
+ MEM_VOLATILE_P (last) = 1;
+ emit_move_insn (last, const0_rtx);
+ }
- fprintf (file, "\tstq $31,-8192($4)\n");
- fprintf (file, "\tsubq $5,1,$5\n");
- fprintf (file, "\tlda $4,-8192($4)\n");
+ emit_move_insn (stack_pointer_rtx, plus_constant (ptr, -leftover));
+ }
- fprintf (file, "\tbne $5,");
- assemble_name (file, alpha_function_name);
- fprintf (file, "..sc\n");
+ /* Cope with very large offsets to the register save area. */
+ sa_reg = stack_pointer_rtx;
+ if (reg_offset + sa_size > 0x8000)
+ {
+ int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000;
+ HOST_WIDE_INT bias;
- if (leftover > 4096 && sa_size == 0)
- fprintf (file, "\tstq $31,-%d($4)\n", leftover);
+ if (low + sa_size <= 0x8000)
+ bias = reg_offset - low, reg_offset = low;
+ else
+ bias = reg_offset, reg_offset = 0;
- fprintf (file, "\tlda $30,-%d($4)\n", leftover);
+ sa_reg = gen_rtx_REG (DImode, 24);
+ emit_move_insn (sa_reg, plus_constant (stack_pointer_rtx, bias));
}
-
- /* Describe our frame. */
- fprintf (file, "\t.frame $%d,%d,$26,%d\n",
- (frame_pointer_needed
- ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM),
- frame_size, current_function_pretend_args_size);
- /* Save register 26 if any other register needs to be saved. */
- if (sa_size != 0)
+ /* Save regs in stack order. Beginning with VMS PV. */
+ if (TARGET_OPEN_VMS && vms_is_stack_procedure)
{
- reg_mask |= 1 << 26;
- fprintf (file, "\tstq $26,%d($30)\n", reg_offset);
+ emit_move_insn (gen_rtx_MEM (DImode, stack_pointer_rtx),
+ gen_rtx_REG (DImode, REG_PV));
+ }
+
+ /* Save register RA next. */
+ if (imask & (1L << REG_RA))
+ {
+ emit_move_insn (gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)),
+ gen_rtx_REG (DImode, REG_RA));
+ imask &= ~(1L << REG_RA);
reg_offset += 8;
- int_reg_save_area_size += 8;
}
- /* Now save any other used integer registers required to be saved. */
+ /* Now save any other registers required to be saved. */
for (i = 0; i < 32; i++)
- if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i] && i != 26)
+ if (imask & (1L << i))
{
- reg_mask |= 1 << i;
- fprintf (file, "\tstq $%d,%d($30)\n", i, reg_offset);
+ emit_move_insn (gen_rtx_MEM (DImode,
+ plus_constant (sa_reg, reg_offset)),
+ gen_rtx_REG (DImode, i));
reg_offset += 8;
- int_reg_save_area_size += 8;
}
- /* Print the register mask and do floating-point saves. */
- if (reg_mask)
- fprintf (file, "\t.mask 0x%x,%d\n", reg_mask,
- actual_start_reg_offset - frame_size);
-
- start_reg_offset = reg_offset;
- reg_mask = 0;
-
for (i = 0; i < 32; i++)
- if (! fixed_regs[i + 32] && ! call_used_regs[i + 32]
- && regs_ever_live[i + 32])
+ if (fmask & (1L << i))
{
- reg_mask |= 1 << i;
- fprintf (file, "\tstt $f%d,%d($30)\n", i, reg_offset);
+ emit_move_insn (gen_rtx_MEM (DFmode,
+ plus_constant (sa_reg, reg_offset)),
+ gen_rtx_REG (DFmode, i+32));
reg_offset += 8;
}
- /* Print the floating-point mask, if we've saved any fp register. */
- if (reg_mask)
- fprintf (file, "\t.fmask 0x%x,%d\n", reg_mask,
- actual_start_reg_offset - frame_size + int_reg_save_area_size);
+ if (TARGET_OPEN_VMS)
+ {
+ if (!vms_is_stack_procedure)
+ {
+ /* Register frame procedures fave the fp. */
+ emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
+ hard_frame_pointer_rtx);
+ }
+
+ if (vms_base_regno != REG_PV)
+ emit_move_insn (gen_rtx_REG (DImode, vms_base_regno),
+ gen_rtx_REG (DImode, REG_PV));
- /* If we need a frame pointer, set it from the stack pointer. Note that
- this must always be the last instruction in the prologue. */
- if (frame_pointer_needed)
- fprintf (file, "\tbis $30,$30,$15\n");
+ if (vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
+ {
+ emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
+ }
- /* End the prologue and say if we used gp. */
- fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp);
+ /* If we have to allocate space for outgoing args, do it now. */
+ if (current_function_outgoing_args_size != 0)
+ {
+ emit_move_insn (stack_pointer_rtx,
+ plus_constant (hard_frame_pointer_rtx,
+ - ALPHA_ROUND (current_function_outgoing_args_size)));
+ }
+ }
+ else
+ {
+ /* If we need a frame pointer, set it from the stack pointer. */
+ if (frame_pointer_needed)
+ {
+ if (TARGET_CAN_FAULT_IN_PROLOGUE)
+ emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx);
+ else
+ {
+ /* This must always be the last instruction in the
+ prologue, thus we emit a special move + clobber. */
+ emit_insn (gen_init_fp (hard_frame_pointer_rtx,
+ stack_pointer_rtx, sa_reg));
+ }
+ }
+ }
+
+ /* The ABIs for VMS and OSF/1 say that while we can schedule insns into
+ the prologue, for exception handling reasons, we cannot do this for
+ any insn that might fault. We could prevent this for mems with a
+ (clobber:BLK (scratch)), but this doesn't work for fp insns. So we
+ have to prevent all such scheduling with a blockage.
+
+ Linux, on the other hand, never bothered to implement OSF/1's
+ exception handling, and so doesn't care about such things. Anyone
+ planning to use dwarf2 frame-unwind info can also omit the blockage. */
+
+ if (! TARGET_CAN_FAULT_IN_PROLOGUE)
+ emit_insn (gen_blockage ());
}
-/* Write function epilogue. */
+/* Output the textual info surrounding the prologue. */
void
-output_epilog (file, size)
+alpha_start_function (file, fnname, decl)
FILE *file;
- int size;
-{
- rtx insn = get_last_insn ();
- HOST_WIDE_INT out_args_size
- = ALPHA_ROUND (current_function_outgoing_args_size);
- HOST_WIDE_INT sa_size = alpha_sa_size ();
- HOST_WIDE_INT frame_size
- = (out_args_size + sa_size
- + ALPHA_ROUND (size + current_function_pretend_args_size));
- HOST_WIDE_INT reg_offset = out_args_size;
- HOST_WIDE_INT frame_size_from_reg_save = frame_size - reg_offset;
- int restore_fp
- = frame_pointer_needed && regs_ever_live[HARD_FRAME_POINTER_REGNUM];
+ char *fnname;
+ tree decl ATTRIBUTE_UNUSED;
+{
+ unsigned long imask = 0;
+ unsigned long fmask = 0;
+ /* Stack space needed for pushing registers clobbered by us. */
+ HOST_WIDE_INT sa_size;
+ /* Complete stack size needed. */
+ HOST_WIDE_INT frame_size;
+ /* Offset from base reg to register save area. */
+ HOST_WIDE_INT reg_offset;
+ char *entry_label = (char *) alloca (strlen (fnname) + 6);
int i;
- /* If the last insn was a BARRIER, we don't have to write anything except
- the .end pseudo-op. */
- if (GET_CODE (insn) == NOTE)
- insn = prev_nonnote_insn (insn);
- if (insn == 0 || GET_CODE (insn) != BARRIER)
+ sa_size = alpha_sa_size ();
+
+ frame_size = get_frame_size ();
+ if (TARGET_OPEN_VMS)
+ frame_size = ALPHA_ROUND (sa_size
+ + (vms_is_stack_procedure ? 8 : 0)
+ + frame_size
+ + current_function_pretend_args_size);
+ else
+ frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
+ + sa_size
+ + ALPHA_ROUND (frame_size
+ + current_function_pretend_args_size));
+
+ if (TARGET_OPEN_VMS)
+ reg_offset = 8;
+ else
+ reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
+
+ alpha_sa_mask (&imask, &fmask);
+
+ /* Ecoff can handle multiple .file directives, so put out file and lineno.
+ We have to do that before the .ent directive as we cannot switch
+ files within procedures with native ecoff because line numbers are
+ linked to procedure descriptors.
+ Outputting the lineno helps debugging of one line functions as they
+ would otherwise get no line number at all. Please note that we would
+ like to put out last_linenum from final.c, but it is not accessible. */
+
+ if (write_symbols == SDB_DEBUG)
+ {
+ ASM_OUTPUT_SOURCE_FILENAME (file,
+ DECL_SOURCE_FILE (current_function_decl));
+ if (debug_info_level != DINFO_LEVEL_TERSE)
+ ASM_OUTPUT_SOURCE_LINE (file,
+ DECL_SOURCE_LINE (current_function_decl));
+ }
+
+ /* Issue function start and label. */
+ if (TARGET_OPEN_VMS || !flag_inhibit_size_directive)
+ {
+ fputs ("\t.ent ", file);
+ assemble_name (file, fnname);
+ putc ('\n', file);
+ }
+
+ strcpy (entry_label, fnname);
+ if (TARGET_OPEN_VMS)
+ strcat (entry_label, "..en");
+ ASM_OUTPUT_LABEL (file, entry_label);
+ inside_function = TRUE;
+
+ if (TARGET_OPEN_VMS)
+ fprintf (file, "\t.base $%d\n", vms_base_regno);
+
+ if (!TARGET_OPEN_VMS && TARGET_IEEE_CONFORMANT
+ && !flag_inhibit_size_directive)
+ {
+ /* Set flags in procedure descriptor to request IEEE-conformant
+ math-library routines. The value we set it to is PDSC_EXC_IEEE
+ (/usr/include/pdsc.h). */
+ fputs ("\t.eflag 48\n", file);
+ }
+
+ /* Set up offsets to alpha virtual arg/local debugging pointer. */
+ alpha_auto_offset = -frame_size + current_function_pretend_args_size;
+ alpha_arg_offset = -frame_size + 48;
+
+ /* Describe our frame. If the frame size is larger than an integer,
+ print it as zero to avoid an assembler error. We won't be
+ properly describing such a frame, but that's the best we can do. */
+ if (TARGET_OPEN_VMS)
{
- int fp_offset = 0;
+ fprintf (file, "\t.frame $%d,", vms_unwind_regno);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ frame_size >= (1l << 31) ? 0 : frame_size);
+ fputs (",$26,", file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, reg_offset);
+ fputs ("\n", file);
+ }
+ else if (!flag_inhibit_size_directive)
+ {
+ fprintf (file, "\t.frame $%d,",
+ (frame_pointer_needed
+ ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ frame_size >= (1l << 31) ? 0 : frame_size);
+ fprintf (file, ",$26,%d\n", current_function_pretend_args_size);
+ }
+
+ /* Describe which registers were spilled. */
+ if (TARGET_OPEN_VMS)
+ {
+ if (imask)
+ /* ??? Does VMS care if mask contains ra? The old code did'nt
+ set it, so I don't here. */
+ fprintf (file, "\t.mask 0x%lx,0\n", imask & ~(1L << REG_RA));
+ if (fmask)
+ fprintf (file, "\t.fmask 0x%lx,0\n", fmask);
+ if (!vms_is_stack_procedure)
+ fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno);
+ }
+ else if (!flag_inhibit_size_directive)
+ {
+ if (imask)
+ {
+ fprintf (file, "\t.mask 0x%lx,", imask);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ frame_size >= (1l << 31) ? 0 : reg_offset - frame_size);
+ putc ('\n', file);
+
+ for (i = 0; i < 32; ++i)
+ if (imask & (1L << i))
+ reg_offset += 8;
+ }
+
+ if (fmask)
+ {
+ fprintf (file, "\t.fmask 0x%lx,", fmask);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+ frame_size >= (1l << 31) ? 0 : reg_offset - frame_size);
+ putc ('\n', file);
+ }
+ }
+
+ /* Emit GP related things. It is rather unfortunate about the alignment
+ issues surrounding a CODE_LABEL that forces us to do the label in
+ plain text. */
+ if (!TARGET_OPEN_VMS && !TARGET_WINDOWS_NT)
+ {
+ alpha_function_needs_gp = alpha_does_function_need_gp ();
+ if (alpha_function_needs_gp)
+ fputs ("\tldgp $29,0($27)\n", file);
+
+ putc ('$', file);
+ assemble_name (file, fnname);
+ fputs ("..ng:\n", file);
+ }
+
+#ifdef OPEN_VMS
+ /* Ifdef'ed cause readonly_section and link_section are only
+ available then. */
+ readonly_section ();
+ fprintf (file, "\t.align 3\n");
+ assemble_name (file, fnname); fputs ("..na:\n", file);
+ fputs ("\t.ascii \"", file);
+ assemble_name (file, fnname);
+ fputs ("\\0\"\n", file);
+
+ link_section ();
+ fprintf (file, "\t.align 3\n");
+ fputs ("\t.name ", file);
+ assemble_name (file, fnname);
+ fputs ("..na\n", file);
+ ASM_OUTPUT_LABEL (file, fnname);
+ fprintf (file, "\t.pdesc ");
+ assemble_name (file, fnname);
+ fprintf (file, "..en,%s\n", vms_is_stack_procedure ? "stack" : "reg");
+ alpha_need_linkage (fnname, 1);
+ text_section ();
+#endif
+}
+
+/* Emit the .prologue note at the scheduled end of the prologue. */
+
+void
+output_end_prologue (file)
+ FILE *file;
+{
+ if (TARGET_OPEN_VMS)
+ fputs ("\t.prologue\n", file);
+ else if (TARGET_WINDOWS_NT)
+ fputs ("\t.prologue 0\n", file);
+ else if (!flag_inhibit_size_directive)
+ fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp);
+}
+
+/* Write function epilogue. */
+
+void
+alpha_expand_epilogue ()
+{
+ /* Registers to save. */
+ unsigned long imask = 0;
+ unsigned long fmask = 0;
+ /* Stack space needed for pushing registers clobbered by us. */
+ HOST_WIDE_INT sa_size;
+ /* Complete stack size needed. */
+ HOST_WIDE_INT frame_size;
+ /* Offset from base reg to register save area. */
+ HOST_WIDE_INT reg_offset;
+ int fp_is_frame_pointer, fp_offset;
+ rtx sa_reg, sa_reg_exp = NULL;
+ rtx sp_adj1, sp_adj2;
+ int i;
+
+ sa_size = alpha_sa_size ();
+
+ frame_size = get_frame_size ();
+ if (TARGET_OPEN_VMS)
+ frame_size = ALPHA_ROUND (sa_size
+ + (vms_is_stack_procedure ? 8 : 0)
+ + frame_size
+ + current_function_pretend_args_size);
+ else
+ frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
+ + sa_size
+ + ALPHA_ROUND (frame_size
+ + current_function_pretend_args_size));
+
+ if (TARGET_OPEN_VMS)
+ reg_offset = 8;
+ else
+ reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
+ alpha_sa_mask (&imask, &fmask);
+
+ fp_is_frame_pointer = ((TARGET_OPEN_VMS && vms_is_stack_procedure)
+ || (!TARGET_OPEN_VMS && frame_pointer_needed));
+
+ if (sa_size)
+ {
/* If we have a frame pointer, restore SP from it. */
- if (frame_pointer_needed)
- fprintf (file, "\tbis $15,$15,$30\n");
+ if ((TARGET_OPEN_VMS
+ && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
+ || (!TARGET_OPEN_VMS && frame_pointer_needed))
+ {
+ emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx);
+ }
- /* Restore all the registers, starting with the return address
- register. */
- if (sa_size != 0)
+ /* Cope with very large offsets to the register save area. */
+ sa_reg = stack_pointer_rtx;
+ if (reg_offset + sa_size > 0x8000)
{
- fprintf (file, "\tldq $26,%d($30)\n", reg_offset);
- reg_offset += 8;
+ int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000;
+ HOST_WIDE_INT bias;
+
+ if (low + sa_size <= 0x8000)
+ bias = reg_offset - low, reg_offset = low;
+ else
+ bias = reg_offset, reg_offset = 0;
+
+ sa_reg = gen_rtx_REG (DImode, 22);
+ sa_reg_exp = plus_constant (stack_pointer_rtx, bias);
+
+ emit_move_insn (sa_reg, sa_reg_exp);
}
+
+ /* Restore registers in order, excepting a true frame pointer. */
- /* Now restore any other used integer registers that that we saved,
- except for FP if it is being used as FP, since it must be
- restored last. */
+ emit_move_insn (gen_rtx_REG (DImode, REG_RA),
+ gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset)));
+ reg_offset += 8;
+ imask &= ~(1L << REG_RA);
- for (i = 0; i < 32; i++)
- if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i]
- && i != 26)
+ for (i = 0; i < 32; ++i)
+ if (imask & (1L << i))
{
- if (i == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
+ if (i == HARD_FRAME_POINTER_REGNUM && fp_is_frame_pointer)
fp_offset = reg_offset;
else
- fprintf (file, "\tldq $%d,%d($30)\n", i, reg_offset);
+ {
+ emit_move_insn (gen_rtx_REG (DImode, i),
+ gen_rtx_MEM (DImode,
+ plus_constant(sa_reg,
+ reg_offset)));
+ }
reg_offset += 8;
}
- for (i = 0; i < 32; i++)
- if (! fixed_regs[i + 32] && ! call_used_regs[i + 32]
- && regs_ever_live[i + 32])
+ for (i = 0; i < 32; ++i)
+ if (fmask & (1L << i))
{
- fprintf (file, "\tldt $f%d,%d($30)\n", i, reg_offset);
+ emit_move_insn (gen_rtx_REG (DFmode, i+32),
+ gen_rtx_MEM (DFmode,
+ plus_constant(sa_reg, reg_offset)));
reg_offset += 8;
}
+ }
- /* If the stack size is large and we have a frame pointer, compute the
- size of the stack into a register because the old FP restore, stack
- pointer adjust, and return are required to be consecutive
- instructions. */
- if (frame_size > 32767 && restore_fp)
- add_long_const (file, frame_size, 31, 1, 1);
-
- /* If we needed a frame pointer and we have to restore it, do it
- now. This must be done in one instruction immediately
- before the SP update. */
- if (restore_fp && fp_offset)
- fprintf (file, "\tldq $15,%d($30)\n", fp_offset);
-
- /* Now update the stack pointer, if needed. Only one instruction must
- modify the stack pointer. It must be the last instruction in the
- sequence and must be an ADDQ or LDA instruction. If the frame
- pointer was loaded above, we may only put one instruction here. */
-
- if (frame_size > 32768 && restore_fp)
- fprintf (file, "\taddq $1,$30,$30\n");
+ if (frame_size)
+ {
+ /* If the stack size is large, begin computation into a temporary
+ register so as not to interfere with a potential fp restore,
+ which must be consecutive with an SP restore. */
+ if (frame_size < 32768)
+ {
+ sp_adj1 = stack_pointer_rtx;
+ sp_adj2 = GEN_INT (frame_size);
+ }
+ else if (frame_size < 0x40007fffL)
+ {
+ int low = ((frame_size & 0xffff) ^ 0x8000) - 0x8000;
+
+ sp_adj2 = plus_constant (stack_pointer_rtx, frame_size - low);
+ if (sa_reg_exp && rtx_equal_p (sa_reg_exp, sp_adj2))
+ sp_adj1 = sa_reg;
+ else
+ {
+ sp_adj1 = gen_rtx_REG (DImode, 23);
+ emit_move_insn (sp_adj1, sp_adj2);
+ }
+ sp_adj2 = GEN_INT (low);
+ }
else
- add_long_const (file, frame_size, 30, 30, 1);
+ {
+ sp_adj2 = gen_rtx_REG (DImode, 23);
+ sp_adj1 = alpha_emit_set_const (sp_adj2, DImode, frame_size, 3);
+ if (!sp_adj1)
+ {
+ /* We can't drop new things to memory this late, afaik,
+ so build it up by pieces. */
+#if HOST_BITS_PER_WIDE_INT == 64
+ sp_adj1 = alpha_emit_set_long_const (sp_adj2, frame_size);
+ if (!sp_adj1)
+ abort ();
+#else
+ abort ();
+#endif
+ }
+ sp_adj2 = stack_pointer_rtx;
+ }
+
+ /* From now on, things must be in order. So emit blockages. */
+
+ /* Restore the frame pointer. */
+ if (fp_is_frame_pointer)
+ {
+ emit_insn (gen_blockage ());
+ emit_move_insn (hard_frame_pointer_rtx,
+ gen_rtx_MEM (DImode,
+ plus_constant(sa_reg, fp_offset)));
+ }
+ else if (TARGET_OPEN_VMS)
+ {
+ emit_insn (gen_blockage ());
+ emit_move_insn (hard_frame_pointer_rtx,
+ gen_rtx_REG (DImode, vms_save_fp_regno));
+ }
- /* Finally return to the caller. */
- fprintf (file, "\tret $31,($26),1\n");
+ /* Restore the stack pointer. */
+ emit_insn (gen_blockage ());
+ emit_move_insn (stack_pointer_rtx,
+ gen_rtx_PLUS (DImode, sp_adj1, sp_adj2));
+ }
+ else
+ {
+ if (TARGET_OPEN_VMS && !vms_is_stack_procedure)
+ {
+ emit_insn (gen_blockage ());
+ emit_move_insn (hard_frame_pointer_rtx,
+ gen_rtx_REG (DImode, vms_save_fp_regno));
+ }
}
+ /* Return. */
+ emit_jump_insn (gen_return_internal ());
+}
+
+/* Output the rest of the textual info surrounding the epilogue. */
+
+void
+alpha_end_function (file, fnname, decl)
+ FILE *file;
+ char *fnname;
+ tree decl ATTRIBUTE_UNUSED;
+{
/* End the function. */
- fprintf (file, "\t.end ");
- assemble_name (file, alpha_function_name);
- fprintf (file, "\n");
+ if (!flag_inhibit_size_directive)
+ {
+ fputs ("\t.end ", file);
+ assemble_name (file, fnname);
+ putc ('\n', file);
+ }
inside_function = FALSE;
- /* Show that we know this function if it is called again. */
- SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1;
+ /* Show that we know this function if it is called again.
+
+ Don't do this for global functions in object files destined for a
+ shared library because the function may be overridden by the application
+ or other libraries.
+ ??? Is this just ELF? */
+
+ if (!flag_pic || !TREE_PUBLIC (current_function_decl))
+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1;
}
/* Debugging support. */
@@ -1655,7 +3872,7 @@ alpha_output_filename (stream, name)
fprintf (stream, "\t#@stabs\n");
}
- else if (!TARGET_GAS && write_symbols == DBX_DEBUG)
+ else if (write_symbols == DBX_DEBUG)
{
ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
fprintf (stream, "%s ", ASM_STABS_OP);
@@ -1664,7 +3881,7 @@ alpha_output_filename (stream, name)
}
else if (name != current_function_file
- && strcmp (name, current_function_file) != 0)
+ && strcmp (name, current_function_file) != 0)
{
if (inside_function && ! TARGET_GAS)
fprintf (stream, "\t#.file\t%d ", num_source_filenames);
@@ -1687,7 +3904,7 @@ alpha_output_lineno (stream, line)
FILE *stream;
int line;
{
- if (! TARGET_GAS && write_symbols == DBX_DEBUG)
+ if (write_symbols == DBX_DEBUG)
{
/* mips-tfile doesn't understand .stabd directives. */
++sym_lineno;
@@ -1697,3 +3914,543 @@ alpha_output_lineno (stream, line)
else
fprintf (stream, "\n\t.loc\t%d %d\n", num_source_filenames, line);
}
+
+/* Structure to show the current status of registers and memory. */
+
+struct shadow_summary
+{
+ struct {
+ unsigned long i : 31; /* Mask of int regs */
+ unsigned long fp : 31; /* Mask of fp regs */
+ unsigned long mem : 1; /* mem == imem | fpmem */
+ } used, defd;
+};
+
+static void summarize_insn PROTO((rtx, struct shadow_summary *, int));
+static void alpha_handle_trap_shadows PROTO((rtx));
+
+/* Summary the effects of expression X on the machine. Update SUM, a pointer
+ to the summary structure. SET is nonzero if the insn is setting the
+ object, otherwise zero. */
+
+static void
+summarize_insn (x, sum, set)
+ rtx x;
+ struct shadow_summary *sum;
+ int set;
+{
+ char *format_ptr;
+ int i, j;
+
+ if (x == 0)
+ return;
+
+ switch (GET_CODE (x))
+ {
+ /* ??? Note that this case would be incorrect if the Alpha had a
+ ZERO_EXTRACT in SET_DEST. */
+ case SET:
+ summarize_insn (SET_SRC (x), sum, 0);
+ summarize_insn (SET_DEST (x), sum, 1);
+ break;
+
+ case CLOBBER:
+ summarize_insn (XEXP (x, 0), sum, 1);
+ break;
+
+ case USE:
+ summarize_insn (XEXP (x, 0), sum, 0);
+ break;
+
+ case ASM_OPERANDS:
+ for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
+ summarize_insn (ASM_OPERANDS_INPUT (x, i), sum, 0);
+ break;
+
+ case PARALLEL:
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ summarize_insn (XVECEXP (x, 0, i), sum, 0);
+ break;
+
+ case SUBREG:
+ summarize_insn (SUBREG_REG (x), sum, 0);
+ break;
+
+ case REG:
+ {
+ int regno = REGNO (x);
+ unsigned long mask = 1UL << (regno % 32);
+
+ if (regno == 31 || regno == 63)
+ break;
+
+ if (set)
+ {
+ if (regno < 32)
+ sum->defd.i |= mask;
+ else
+ sum->defd.fp |= mask;
+ }
+ else
+ {
+ if (regno < 32)
+ sum->used.i |= mask;
+ else
+ sum->used.fp |= mask;
+ }
+ }
+ break;
+
+ case MEM:
+ if (set)
+ sum->defd.mem = 1;
+ else
+ sum->used.mem = 1;
+
+ /* Find the regs used in memory address computation: */
+ summarize_insn (XEXP (x, 0), sum, 0);
+ break;
+
+ case CONST_INT: case CONST_DOUBLE:
+ case SYMBOL_REF: case LABEL_REF: case CONST:
+ break;
+
+ /* Handle common unary and binary ops for efficiency. */
+ case COMPARE: case PLUS: case MINUS: case MULT: case DIV:
+ case MOD: case UDIV: case UMOD: case AND: case IOR:
+ case XOR: case ASHIFT: case ROTATE: case ASHIFTRT: case LSHIFTRT:
+ case ROTATERT: case SMIN: case SMAX: case UMIN: case UMAX:
+ case NE: case EQ: case GE: case GT: case LE:
+ case LT: case GEU: case GTU: case LEU: case LTU:
+ summarize_insn (XEXP (x, 0), sum, 0);
+ summarize_insn (XEXP (x, 1), sum, 0);
+ break;
+
+ case NEG: case NOT: case SIGN_EXTEND: case ZERO_EXTEND:
+ case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: case FLOAT:
+ case FIX: case UNSIGNED_FLOAT: case UNSIGNED_FIX: case ABS:
+ case SQRT: case FFS:
+ summarize_insn (XEXP (x, 0), sum, 0);
+ break;
+
+ default:
+ format_ptr = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ switch (format_ptr[i])
+ {
+ case 'e':
+ summarize_insn (XEXP (x, i), sum, 0);
+ break;
+
+ case 'E':
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ summarize_insn (XVECEXP (x, i, j), sum, 0);
+ break;
+
+ case 'i':
+ break;
+
+ default:
+ abort ();
+ }
+ }
+}
+
+/* Ensure a sufficient number of `trapb' insns are in the code when
+ the user requests code with a trap precision of functions or
+ instructions.
+
+ In naive mode, when the user requests a trap-precision of
+ "instruction", a trapb is needed after every instruction that may
+ generate a trap. This ensures that the code is resumption safe but
+ it is also slow.
+
+ When optimizations are turned on, we delay issuing a trapb as long
+ as possible. In this context, a trap shadow is the sequence of
+ instructions that starts with a (potentially) trap generating
+ instruction and extends to the next trapb or call_pal instruction
+ (but GCC never generates call_pal by itself). We can delay (and
+ therefore sometimes omit) a trapb subject to the following
+ conditions:
+
+ (a) On entry to the trap shadow, if any Alpha register or memory
+ location contains a value that is used as an operand value by some
+ instruction in the trap shadow (live on entry), then no instruction
+ in the trap shadow may modify the register or memory location.
+
+ (b) Within the trap shadow, the computation of the base register
+ for a memory load or store instruction may not involve using the
+ result of an instruction that might generate an UNPREDICTABLE
+ result.
+
+ (c) Within the trap shadow, no register may be used more than once
+ as a destination register. (This is to make life easier for the
+ trap-handler.)
+
+ (d) The trap shadow may not include any branch instructions. */
+
+static void
+alpha_handle_trap_shadows (insns)
+ rtx insns;
+{
+ struct shadow_summary shadow;
+ int trap_pending, exception_nesting;
+ rtx i;
+
+ if (alpha_tp == ALPHA_TP_PROG && !flag_exceptions)
+ return;
+
+ trap_pending = 0;
+ exception_nesting = 0;
+ shadow.used.i = 0;
+ shadow.used.fp = 0;
+ shadow.used.mem = 0;
+ shadow.defd = shadow.used;
+
+ for (i = insns; i ; i = NEXT_INSN (i))
+ {
+ if (GET_CODE (i) == NOTE)
+ {
+ switch (NOTE_LINE_NUMBER (i))
+ {
+ case NOTE_INSN_EH_REGION_BEG:
+ exception_nesting++;
+ if (trap_pending)
+ goto close_shadow;
+ break;
+
+ case NOTE_INSN_EH_REGION_END:
+ exception_nesting--;
+ if (trap_pending)
+ goto close_shadow;
+ break;
+
+ case NOTE_INSN_EPILOGUE_BEG:
+ if (trap_pending && alpha_tp >= ALPHA_TP_FUNC)
+ goto close_shadow;
+ break;
+ }
+ }
+ else if (trap_pending)
+ {
+ if (alpha_tp == ALPHA_TP_FUNC)
+ {
+ if (GET_CODE (i) == JUMP_INSN
+ && GET_CODE (PATTERN (i)) == RETURN)
+ goto close_shadow;
+ }
+ else if (alpha_tp == ALPHA_TP_INSN)
+ {
+ if (optimize > 0)
+ {
+ struct shadow_summary sum;
+
+ sum.used.i = 0;
+ sum.used.fp = 0;
+ sum.used.mem = 0;
+ sum.defd = sum.used;
+
+ switch (GET_CODE (i))
+ {
+ case INSN:
+ /* Annoyingly, get_attr_trap will abort on these. */
+ if (GET_CODE (PATTERN (i)) == USE
+ || GET_CODE (PATTERN (i)) == CLOBBER)
+ break;
+
+ summarize_insn (PATTERN (i), &sum, 0);
+
+ if ((sum.defd.i & shadow.defd.i)
+ || (sum.defd.fp & shadow.defd.fp))
+ {
+ /* (c) would be violated */
+ goto close_shadow;
+ }
+
+ /* Combine shadow with summary of current insn: */
+ shadow.used.i |= sum.used.i;
+ shadow.used.fp |= sum.used.fp;
+ shadow.used.mem |= sum.used.mem;
+ shadow.defd.i |= sum.defd.i;
+ shadow.defd.fp |= sum.defd.fp;
+ shadow.defd.mem |= sum.defd.mem;
+
+ if ((sum.defd.i & shadow.used.i)
+ || (sum.defd.fp & shadow.used.fp)
+ || (sum.defd.mem & shadow.used.mem))
+ {
+ /* (a) would be violated (also takes care of (b)) */
+ if (get_attr_trap (i) == TRAP_YES
+ && ((sum.defd.i & sum.used.i)
+ || (sum.defd.fp & sum.used.fp)))
+ abort ();
+
+ goto close_shadow;
+ }
+ break;
+
+ case JUMP_INSN:
+ case CALL_INSN:
+ case CODE_LABEL:
+ goto close_shadow;
+
+ default:
+ abort ();
+ }
+ }
+ else
+ {
+ close_shadow:
+ emit_insn_before (gen_trapb (), i);
+ trap_pending = 0;
+ shadow.used.i = 0;
+ shadow.used.fp = 0;
+ shadow.used.mem = 0;
+ shadow.defd = shadow.used;
+ }
+ }
+ }
+
+ if ((exception_nesting > 0 || alpha_tp >= ALPHA_TP_FUNC)
+ && GET_CODE (i) == INSN
+ && GET_CODE (PATTERN (i)) != USE
+ && GET_CODE (PATTERN (i)) != CLOBBER
+ && get_attr_trap (i) == TRAP_YES)
+ {
+ if (optimize && !trap_pending)
+ summarize_insn (PATTERN (i), &shadow, 0);
+ trap_pending = 1;
+ }
+ }
+}
+
+/* Machine dependant reorg pass. */
+
+void
+alpha_reorg (insns)
+ rtx insns;
+{
+ alpha_handle_trap_shadows (insns);
+}
+
+
+/* Check a floating-point value for validity for a particular machine mode. */
+
+static char * const float_strings[] =
+{
+ /* These are for FLOAT_VAX. */
+ "1.70141173319264430e+38", /* 2^127 (2^24 - 1) / 2^24 */
+ "-1.70141173319264430e+38",
+ "2.93873587705571877e-39", /* 2^-128 */
+ "-2.93873587705571877e-39",
+ /* These are for the default broken IEEE mode, which traps
+ on infinity or denormal numbers. */
+ "3.402823466385288598117e+38", /* 2^128 (1 - 2^-24) */
+ "-3.402823466385288598117e+38",
+ "1.1754943508222875079687e-38", /* 2^-126 */
+ "-1.1754943508222875079687e-38",
+};
+
+static REAL_VALUE_TYPE float_values[8];
+static int inited_float_values = 0;
+
+int
+check_float_value (mode, d, overflow)
+ enum machine_mode mode;
+ REAL_VALUE_TYPE *d;
+ int overflow ATTRIBUTE_UNUSED;
+{
+
+ if (TARGET_IEEE || TARGET_IEEE_CONFORMANT || TARGET_IEEE_WITH_INEXACT)
+ return 0;
+
+ if (inited_float_values == 0)
+ {
+ int i;
+ for (i = 0; i < 8; i++)
+ float_values[i] = REAL_VALUE_ATOF (float_strings[i], DFmode);
+
+ inited_float_values = 1;
+ }
+
+ if (mode == SFmode)
+ {
+ REAL_VALUE_TYPE r;
+ REAL_VALUE_TYPE *fvptr;
+
+ if (TARGET_FLOAT_VAX)
+ fvptr = &float_values[0];
+ else
+ fvptr = &float_values[4];
+
+ bcopy ((char *) d, (char *) &r, sizeof (REAL_VALUE_TYPE));
+ if (REAL_VALUES_LESS (fvptr[0], r))
+ {
+ bcopy ((char *) &fvptr[0], (char *) d,
+ sizeof (REAL_VALUE_TYPE));
+ return 1;
+ }
+ else if (REAL_VALUES_LESS (r, fvptr[1]))
+ {
+ bcopy ((char *) &fvptr[1], (char *) d,
+ sizeof (REAL_VALUE_TYPE));
+ return 1;
+ }
+ else if (REAL_VALUES_LESS (dconst0, r)
+ && REAL_VALUES_LESS (r, fvptr[2]))
+ {
+ bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE));
+ return 1;
+ }
+ else if (REAL_VALUES_LESS (r, dconst0)
+ && REAL_VALUES_LESS (fvptr[3], r))
+ {
+ bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#if OPEN_VMS
+
+/* Return the VMS argument type corresponding to MODE. */
+
+enum avms_arg_type
+alpha_arg_type (mode)
+ enum machine_mode mode;
+{
+ switch (mode)
+ {
+ case SFmode:
+ return TARGET_FLOAT_VAX ? FF : FS;
+ case DFmode:
+ return TARGET_FLOAT_VAX ? FD : FT;
+ default:
+ return I64;
+ }
+}
+
+/* Return an rtx for an integer representing the VMS Argument Information
+ register value. */
+
+struct rtx_def *
+alpha_arg_info_reg_val (cum)
+ CUMULATIVE_ARGS cum;
+{
+ unsigned HOST_WIDE_INT regval = cum.num_args;
+ int i;
+
+ for (i = 0; i < 6; i++)
+ regval |= ((int) cum.atypes[i]) << (i * 3 + 8);
+
+ return GEN_INT (regval);
+}
+
+/* Structure to collect function names for final output
+ in link section. */
+
+enum links_kind {KIND_UNUSED, KIND_LOCAL, KIND_EXTERN};
+
+
+struct alpha_links {
+ struct alpha_links *next;
+ char *name;
+ enum links_kind kind;
+};
+
+static struct alpha_links *alpha_links_base = 0;
+
+/* Make (or fake) .linkage entry for function call.
+
+ IS_LOCAL is 0 if name is used in call, 1 if name is used in definition. */
+
+void
+alpha_need_linkage (name, is_local)
+ char *name;
+ int is_local;
+{
+ rtx x;
+ struct alpha_links *lptr, *nptr;
+
+ if (name[0] == '*')
+ name++;
+
+ /* Is this name already defined ? */
+
+ for (lptr = alpha_links_base; lptr; lptr = lptr->next)
+ if (strcmp (lptr->name, name) == 0)
+ {
+ if (is_local)
+ {
+ /* Defined here but external assumed. */
+ if (lptr->kind == KIND_EXTERN)
+ lptr->kind = KIND_LOCAL;
+ }
+ else
+ {
+ /* Used here but unused assumed. */
+ if (lptr->kind == KIND_UNUSED)
+ lptr->kind = KIND_LOCAL;
+ }
+ return;
+ }
+
+ nptr = (struct alpha_links *) xmalloc (sizeof (struct alpha_links));
+ nptr->next = alpha_links_base;
+ nptr->name = xstrdup (name);
+
+ /* Assume external if no definition. */
+ nptr->kind = (is_local ? KIND_UNUSED : KIND_EXTERN);
+
+ /* Ensure we have an IDENTIFIER so assemble_name can mark is used. */
+ get_identifier (name);
+
+ alpha_links_base = nptr;
+
+ return;
+}
+
+
+void
+alpha_write_linkage (stream)
+ FILE *stream;
+{
+ struct alpha_links *lptr, *nptr;
+
+ readonly_section ();
+
+ fprintf (stream, "\t.align 3\n");
+
+ for (lptr = alpha_links_base; lptr; lptr = nptr)
+ {
+ nptr = lptr->next;
+
+ if (lptr->kind == KIND_UNUSED
+ || ! TREE_SYMBOL_REFERENCED (get_identifier (lptr->name)))
+ continue;
+
+ fprintf (stream, "$%s..lk:\n", lptr->name);
+ if (lptr->kind == KIND_LOCAL)
+ {
+ /* Local and used, build linkage pair. */
+ fprintf (stream, "\t.quad %s..en\n", lptr->name);
+ fprintf (stream, "\t.quad %s\n", lptr->name);
+ }
+ else
+ /* External and used, request linkage pair. */
+ fprintf (stream, "\t.linkage %s\n", lptr->name);
+ }
+}
+
+#else
+
+void
+alpha_need_linkage (name, is_local)
+ char *name ATTRIBUTE_UNUSED;
+ int is_local ATTRIBUTE_UNUSED;
+{
+}
+
+#endif /* OPEN_VMS */
diff --git a/contrib/gcc/config/alpha/alpha.h b/contrib/gcc/config/alpha/alpha.h
index 9504c09..43b0dee 100644
--- a/contrib/gcc/config/alpha/alpha.h
+++ b/contrib/gcc/config/alpha/alpha.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for DEC Alpha.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GNU CC.
@@ -20,21 +20,21 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* Names to predefine in the preprocessor for this target machine. */
-
-#define CPP_PREDEFINES "\
--Dunix -D__osf__ -D__alpha -D__alpha__ -D_LONGLONG -DSYSTYPE_BSD \
--D_SYSTYPE_BSD -Asystem(unix) -Asystem(xpg4) -Acpu(alpha) -Amachine(alpha)"
-
/* Write out the correct language type definition for the header files.
Unless we have assembler language, write out the symbols for C. */
#define CPP_SPEC "\
-%{!.S: -D__LANGUAGE_C__ -D__LANGUAGE_C %{!ansi:-DLANGUAGE_C}} \
-%{.S: -D__LANGUAGE_ASSEMBLY__ -D__LANGUAGE_ASSEMBLY %{!ansi:-DLANGUAGE_ASSEMBLY}} \
-%{.cc: -D__LANGUAGE_C_PLUS_PLUS__ -D__LANGUAGE_C_PLUS_PLUS -D__cplusplus} \
-%{.cxx: -D__LANGUAGE_C_PLUS_PLUS__ -D__LANGUAGE_C_PLUS_PLUS -D__cplusplus} \
-%{.C: -D__LANGUAGE_C_PLUS_PLUS__ -D__LANGUAGE_C_PLUS_PLUS -D__cplusplus} \
-%{.m: -D__LANGUAGE_OBJECTIVE_C__ -D__LANGUAGE_OBJECTIVE_C}"
+%{!undef:\
+%{.S:-D__LANGUAGE_ASSEMBLY__ -D__LANGUAGE_ASSEMBLY %{!ansi:-DLANGUAGE_ASSEMBLY }}\
+%{.cc|.cxx|.C:-D__LANGUAGE_C_PLUS_PLUS__ -D__LANGUAGE_C_PLUS_PLUS -D__cplusplus }\
+%{.m:-D__LANGUAGE_OBJECTIVE_C__ -D__LANGUAGE_OBJECTIVE_C }\
+%{!.S:%{!.cc:%{!.cxx:%{!.C:%{!.m:-D__LANGUAGE_C__ -D__LANGUAGE_C %{!ansi:-DLANGUAGE_C }}}}}}\
+%{mieee:-D_IEEE_FP }\
+%{mieee-with-inexact:-D_IEEE_FP -D_IEEE_FP_INEXACT }}\
+%(cpp_cpu) %(cpp_subtarget)"
+
+#ifndef CPP_SUBTARGET_SPEC
+#define CPP_SUBTARGET_SPEC ""
+#endif
/* Set the spec to use for signed char. The default tests the above macro
but DEC's compiler can't handle the conditional in a "constant"
@@ -42,18 +42,6 @@ Boston, MA 02111-1307, USA. */
#define SIGNED_CHAR_SPEC "%{funsigned-char:-D__CHAR_UNSIGNED__}"
-/* Under OSF/1, -p and -pg require -lprof1. */
-
-#define LIB_SPEC "%{p:-lprof1} %{pg:-lprof1} %{a:-lprof2} -lc"
-
-/* Pass "-G 8" to ld because Alpha's CC does. Pass -O3 if we are
- optimizing, -O1 if we are not. Pass -shared, -non_shared or
- -call_shared as appropriate. Also pass -pg. */
-#define LINK_SPEC \
- "-G 8 %{O*:-O3} %{!O*:-O1} %{static:-non_shared} \
- %{!static:%{shared:-shared} %{!shared:-call_shared}} %{pg} %{taso} \
- %{rpath*}"
-
#define WORD_SWITCH_TAKES_ARG(STR) \
(!strcmp (STR, "rpath") || !strcmp (STR, "include") \
|| !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
@@ -61,62 +49,296 @@ Boston, MA 02111-1307, USA. */
|| !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
|| !strcmp (STR, "isystem"))
-#define STARTFILE_SPEC \
- "%{!shared:%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}"
-
/* Print subsidiary information on the compiler version in use. */
#define TARGET_VERSION
-/* Default this to not be compiling for Windows/NT. */
-#ifndef WINDOWS_NT
-#define WINDOWS_NT 0
-#endif
-
-/* Define the location for the startup file on OSF/1 for Alpha. */
-
-#define MD_STARTFILE_PREFIX "/usr/lib/cmplrs/cc/"
-
/* Run-time compilation parameters selecting different hardware subsets. */
+/* Which processor to schedule for. The cpu attribute defines a list that
+ mirrors this list, so changes to alpha.md must be made at the same time. */
+
+enum processor_type
+ {PROCESSOR_EV4, /* 2106[46]{a,} */
+ PROCESSOR_EV5, /* 21164{a,pc,} */
+ PROCESSOR_EV6}; /* 21264 */
+
+extern enum processor_type alpha_cpu;
+
+enum alpha_trap_precision
+{
+ ALPHA_TP_PROG, /* No precision (default). */
+ ALPHA_TP_FUNC, /* Trap contained within originating function. */
+ ALPHA_TP_INSN /* Instruction accuracy and code is resumption safe. */
+};
+
+enum alpha_fp_rounding_mode
+{
+ ALPHA_FPRM_NORM, /* Normal rounding mode. */
+ ALPHA_FPRM_MINF, /* Round towards minus-infinity. */
+ ALPHA_FPRM_CHOP, /* Chopped rounding mode (towards 0). */
+ ALPHA_FPRM_DYN /* Dynamic rounding mode. */
+};
+
+enum alpha_fp_trap_mode
+{
+ ALPHA_FPTM_N, /* Normal trap mode. */
+ ALPHA_FPTM_U, /* Underflow traps enabled. */
+ ALPHA_FPTM_SU, /* Software completion, w/underflow traps */
+ ALPHA_FPTM_SUI /* Software completion, w/underflow & inexact traps */
+};
+
extern int target_flags;
+extern enum alpha_trap_precision alpha_tp;
+extern enum alpha_fp_rounding_mode alpha_fprm;
+extern enum alpha_fp_trap_mode alpha_fptm;
+
/* This means that floating-point support exists in the target implementation
of the Alpha architecture. This is usually the default. */
-#define TARGET_FP (target_flags & 1)
+#define MASK_FP 1
+#define TARGET_FP (target_flags & MASK_FP)
/* This means that floating-point registers are allowed to be used. Note
that Alpha implementations without FP operations are required to
provide the FP registers. */
-#define TARGET_FPREGS (target_flags & 2)
+#define MASK_FPREGS 2
+#define TARGET_FPREGS (target_flags & MASK_FPREGS)
/* This means that gas is used to process the assembler file. */
#define MASK_GAS 4
#define TARGET_GAS (target_flags & MASK_GAS)
+/* This means that we should mark procedures as IEEE conformant. */
+
+#define MASK_IEEE_CONFORMANT 8
+#define TARGET_IEEE_CONFORMANT (target_flags & MASK_IEEE_CONFORMANT)
+
+/* This means we should be IEEE-compliant except for inexact. */
+
+#define MASK_IEEE 16
+#define TARGET_IEEE (target_flags & MASK_IEEE)
+
+/* This means we should be fully IEEE-compliant. */
+
+#define MASK_IEEE_WITH_INEXACT 32
+#define TARGET_IEEE_WITH_INEXACT (target_flags & MASK_IEEE_WITH_INEXACT)
+
+/* This means we must construct all constants rather than emitting
+ them as literal data. */
+
+#define MASK_BUILD_CONSTANTS 128
+#define TARGET_BUILD_CONSTANTS (target_flags & MASK_BUILD_CONSTANTS)
+
+/* This means we handle floating points in VAX F- (float)
+ or G- (double) Format. */
+
+#define MASK_FLOAT_VAX 512
+#define TARGET_FLOAT_VAX (target_flags & MASK_FLOAT_VAX)
+
+/* This means that the processor has byte and half word loads and stores
+ (the BWX extension). */
+
+#define MASK_BWX 1024
+#define TARGET_BWX (target_flags & MASK_BWX)
+
+/* This means that the processor has the CIX extension. */
+#define MASK_CIX 2048
+#define TARGET_CIX (target_flags & MASK_CIX)
+
+/* This means that the processor has the MAX extension. */
+#define MASK_MAX 4096
+#define TARGET_MAX (target_flags & MASK_MAX)
+
+/* This means that the processor is an EV5, EV56, or PCA56. This is defined
+ only in TARGET_CPU_DEFAULT. */
+#define MASK_CPU_EV5 8192
+
+/* Likewise for EV6. */
+#define MASK_CPU_EV6 16384
+
+/* This means we support the .arch directive in the assembler. Only
+ defined in TARGET_CPU_DEFAULT. */
+#define MASK_SUPPORT_ARCH 32768
+#define TARGET_SUPPORT_ARCH (target_flags & MASK_SUPPORT_ARCH)
+
+/* These are for target os support and cannot be changed at runtime. */
+#ifndef TARGET_WINDOWS_NT
+#define TARGET_WINDOWS_NT 0
+#endif
+#ifndef TARGET_OPEN_VMS
+#define TARGET_OPEN_VMS 0
+#endif
+
+#ifndef TARGET_AS_CAN_SUBTRACT_LABELS
+#define TARGET_AS_CAN_SUBTRACT_LABELS TARGET_GAS
+#endif
+#ifndef TARGET_CAN_FAULT_IN_PROLOGUE
+#define TARGET_CAN_FAULT_IN_PROLOGUE 0
+#endif
+
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
each pair being { "NAME", VALUE }
where VALUE is the bits to set or minus the bits to clear.
An empty string NAME is used to identify the default VALUE. */
-#define TARGET_SWITCHES \
- { {"no-soft-float", 1}, \
- {"soft-float", -1}, \
- {"fp-regs", 2}, \
- {"no-fp-regs", -3}, \
- {"alpha-as", -MASK_GAS}, \
- {"gas", MASK_GAS}, \
+#define TARGET_SWITCHES \
+ { {"no-soft-float", MASK_FP}, \
+ {"soft-float", - MASK_FP}, \
+ {"fp-regs", MASK_FPREGS}, \
+ {"no-fp-regs", - (MASK_FP|MASK_FPREGS)}, \
+ {"alpha-as", -MASK_GAS}, \
+ {"gas", MASK_GAS}, \
+ {"ieee-conformant", MASK_IEEE_CONFORMANT}, \
+ {"ieee", MASK_IEEE|MASK_IEEE_CONFORMANT}, \
+ {"ieee-with-inexact", MASK_IEEE_WITH_INEXACT|MASK_IEEE_CONFORMANT}, \
+ {"build-constants", MASK_BUILD_CONSTANTS}, \
+ {"float-vax", MASK_FLOAT_VAX}, \
+ {"float-ieee", -MASK_FLOAT_VAX}, \
+ {"bwx", MASK_BWX}, \
+ {"no-bwx", -MASK_BWX}, \
+ {"cix", MASK_CIX}, \
+ {"no-cix", -MASK_CIX}, \
+ {"max", MASK_MAX}, \
+ {"no-max", -MASK_MAX}, \
{"", TARGET_DEFAULT | TARGET_CPU_DEFAULT} }
-#define TARGET_DEFAULT 3
+#define TARGET_DEFAULT MASK_FP|MASK_FPREGS
#ifndef TARGET_CPU_DEFAULT
#define TARGET_CPU_DEFAULT 0
#endif
+/* This macro is similar to `TARGET_SWITCHES' but defines names of
+ command options that have values. Its definition is an initializer
+ with a subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the fixed
+ part of the option name, and the address of a variable. The
+ variable, type `char *', is set to the variable part of the given
+ option if the fixed part matches. The actual option name is made
+ by appending `-m' to the specified name.
+
+ Here is an example which defines `-mshort-data-NUMBER'. If the
+ given option is `-mshort-data-512', the variable `m88k_short_data'
+ will be set to the string `"512"'.
+
+ extern char *m88k_short_data;
+ #define TARGET_OPTIONS { { "short-data-", &m88k_short_data } } */
+
+extern char *alpha_cpu_string; /* For -mcpu= */
+extern char *alpha_fprm_string; /* For -mfp-rounding-mode=[n|m|c|d] */
+extern char *alpha_fptm_string; /* For -mfp-trap-mode=[n|u|su|sui] */
+extern char *alpha_tp_string; /* For -mtrap-precision=[p|f|i] */
+extern char *alpha_mlat_string; /* For -mmemory-latency= */
+
+#define TARGET_OPTIONS \
+{ \
+ {"cpu=", &alpha_cpu_string}, \
+ {"fp-rounding-mode=", &alpha_fprm_string}, \
+ {"fp-trap-mode=", &alpha_fptm_string}, \
+ {"trap-precision=", &alpha_tp_string}, \
+ {"memory-latency=", &alpha_mlat_string}, \
+}
+
+/* Attempt to describe CPU characteristics to the preprocessor. */
+
+/* Corresponding to amask... */
+#define CPP_AM_BWX_SPEC "-D__alpha_bwx__ -Acpu(bwx)"
+#define CPP_AM_MAX_SPEC "-D__alpha_max__ -Acpu(max)"
+#define CPP_AM_CIX_SPEC "-D__alpha_cix__ -Acpu(cix)"
+
+/* Corresponding to implver... */
+#define CPP_IM_EV4_SPEC "-D__alpha_ev4__ -Acpu(ev4)"
+#define CPP_IM_EV5_SPEC "-D__alpha_ev5__ -Acpu(ev5)"
+#define CPP_IM_EV6_SPEC "-D__alpha_ev6__ -Acpu(ev6)"
+
+/* Common combinations. */
+#define CPP_CPU_EV4_SPEC "%(cpp_im_ev4)"
+#define CPP_CPU_EV5_SPEC "%(cpp_im_ev5)"
+#define CPP_CPU_EV56_SPEC "%(cpp_im_ev5) %(cpp_am_bwx)"
+#define CPP_CPU_PCA56_SPEC "%(cpp_im_ev5) %(cpp_am_bwx) %(cpp_am_max)"
+#define CPP_CPU_EV6_SPEC "%(cpp_im_ev6) %(cpp_am_bwx) %(cpp_am_max) %(cpp_am_cix)"
+
+#ifndef CPP_CPU_DEFAULT_SPEC
+# if TARGET_CPU_DEFAULT & MASK_CPU_EV6
+# define CPP_CPU_DEFAULT_SPEC CPP_CPU_EV6_SPEC
+# else
+# if TARGET_CPU_DEFAULT & MASK_CPU_EV5
+# if TARGET_CPU_DEFAULT & MASK_MAX
+# define CPP_CPU_DEFAULT_SPEC CPP_CPU_PCA56_SPEC
+# else
+# if TARGET_CPU_DEFAULT & MASK_BWX
+# define CPP_CPU_DEFAULT_SPEC CPP_CPU_EV56_SPEC
+# else
+# define CPP_CPU_DEFAULT_SPEC CPP_CPU_EV5_SPEC
+# endif
+# endif
+# else
+# define CPP_CPU_DEFAULT_SPEC CPP_CPU_EV4_SPEC
+# endif
+# endif
+#endif /* CPP_CPU_DEFAULT_SPEC */
+
+#ifndef CPP_CPU_SPEC
+#define CPP_CPU_SPEC "\
+%{!undef:-Acpu(alpha) -Amachine(alpha) -D__alpha -D__alpha__ \
+%{mcpu=ev4|mcpu=21064:%(cpp_cpu_ev4) }\
+%{mcpu=ev5|mcpu=21164:%(cpp_cpu_ev5) }\
+%{mcpu=ev56|mcpu=21164a:%(cpp_cpu_ev56) }\
+%{mcpu=pca56|mcpu=21164pc|mcpu=21164PC:%(cpp_cpu_pca56) }\
+%{mcpu=ev6|mcpu=21264:%(cpp_cpu_ev6) }\
+%{!mcpu*:%(cpp_cpu_default) }}"
+#endif
+
+/* This macro defines names of additional specifications to put in the
+ specs that can be used in various specifications like CC1_SPEC. Its
+ definition is an initializer with a subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the
+ specification name, and a string constant that used by the GNU CC driver
+ program.
+
+ Do not define this macro if it does not need to do anything. */
+
+#ifndef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS
+#endif
+
+#define EXTRA_SPECS \
+ { "cpp_am_bwx", CPP_AM_BWX_SPEC }, \
+ { "cpp_am_max", CPP_AM_MAX_SPEC }, \
+ { "cpp_am_cix", CPP_AM_CIX_SPEC }, \
+ { "cpp_im_ev4", CPP_IM_EV4_SPEC }, \
+ { "cpp_im_ev5", CPP_IM_EV5_SPEC }, \
+ { "cpp_im_ev6", CPP_IM_EV6_SPEC }, \
+ { "cpp_cpu_ev4", CPP_CPU_EV4_SPEC }, \
+ { "cpp_cpu_ev5", CPP_CPU_EV5_SPEC }, \
+ { "cpp_cpu_ev56", CPP_CPU_EV56_SPEC }, \
+ { "cpp_cpu_pca56", CPP_CPU_PCA56_SPEC }, \
+ { "cpp_cpu_ev6", CPP_CPU_EV6_SPEC }, \
+ { "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \
+ { "cpp_cpu", CPP_CPU_SPEC }, \
+ { "cpp_subtarget", CPP_SUBTARGET_SPEC }, \
+ SUBTARGET_EXTRA_SPECS
+
+
+/* Sometimes certain combinations of command options do not make sense
+ on a particular target machine. You can define a macro
+ `OVERRIDE_OPTIONS' to take account of this. This macro, if
+ defined, is executed once just after all the command options have
+ been parsed.
+
+ On the Alpha, it is used to translate target-option strings into
+ numeric values. */
+
+extern void override_options ();
+#define OVERRIDE_OPTIONS override_options ()
+
+
/* Define this macro to change register usage conditional on target flags.
On the Alpha, we use this to disable the floating-point registers when
@@ -135,6 +357,23 @@ extern int target_flags;
/* Define to enable software floating point emulation. */
#define REAL_ARITHMETIC
+/* The following #defines are used when compiling the routines in
+ libgcc1.c. Since the Alpha calling conventions require single
+ precision floats to be passed in the floating-point registers
+ (rather than in the general registers) we have to build the
+ libgcc1.c routines in such a way that they know the actual types
+ of their formal arguments and the actual types of their return
+ values. Otherwise, gcc will generate calls to the libgcc1.c
+ routines, passing arguments in the floating-point registers,
+ but the libgcc1.c routines will expect their arguments on the
+ stack (where the Alpha calling conventions require structs &
+ unions to be passed). */
+
+#define FLOAT_VALUE_TYPE double
+#define INTIFY(FLOATVAL) (FLOATVAL)
+#define FLOATIFY(INTVAL) (INTVAL)
+#define FLOAT_ARG_TYPE double
+
/* Define the size of `int'. The default is the same as the word size. */
#define INT_TYPE_SIZE 32
@@ -149,8 +388,8 @@ extern int target_flags;
#define DOUBLE_TYPE_SIZE 64
#define LONG_DOUBLE_TYPE_SIZE 64
-#define WCHAR_TYPE "short unsigned int"
-#define WCHAR_TYPE_SIZE 16
+#define WCHAR_TYPE "unsigned int"
+#define WCHAR_TYPE_SIZE 32
/* Define this macro if it is advisable to hold scalars in registers
in a wider mode than that declared by the program. In such cases,
@@ -220,7 +459,7 @@ extern int target_flags;
#define STACK_BOUNDARY 64
/* Allocation boundary (in *bits*) for the code of a function. */
-#define FUNCTION_BOUNDARY 64
+#define FUNCTION_BOUNDARY 256
/* Alignment of field after `int : 0' in a structure. */
#define EMPTY_FIELD_BOUNDARY 64
@@ -237,31 +476,31 @@ extern int target_flags;
we don't optimize and also if we are writing ECOFF symbols to work around
a bug in DEC's assembler. */
-#define ASM_OUTPUT_LOOP_ALIGN(FILE) \
- if (optimize > 0 && write_symbols != SDB_DEBUG) \
- ASM_OUTPUT_ALIGN (FILE, 5)
+#define LOOP_ALIGN(LABEL) \
+ (optimize > 0 && write_symbols != SDB_DEBUG ? 4 : 0)
-/* This is how to align an instruction for optimal branching.
- On Alpha we'll get better performance by aligning on a quadword
+/* This is how to align an instruction for optimal branching. On
+ Alpha we'll get better performance by aligning on an octaword
boundary. */
-#define ASM_OUTPUT_ALIGN_CODE(FILE) \
- if (optimize > 0 && write_symbols != SDB_DEBUG) \
- ASM_OUTPUT_ALIGN ((FILE), 4)
+#define ALIGN_LABEL_AFTER_BARRIER(FILE) \
+ (optimize > 0 && write_symbols != SDB_DEBUG ? 4 : 0)
/* No data type wants to be aligned rounder than this. */
#define BIGGEST_ALIGNMENT 64
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
-/* Make arrays of chars word-aligned for the same reasons. */
-#define DATA_ALIGNMENT(TYPE, ALIGN) \
- (TREE_CODE (TYPE) == ARRAY_TYPE \
- && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+/* For atomic access to objects, must have at least 32-bit alignment
+ unless the machine has byte operations. */
+#define MINIMUM_ATOMIC_ALIGNMENT (TARGET_BWX ? 8 : 32)
+
+/* Align all constants and variables to at least a word boundary so
+ we can pick up pieces of them faster. */
+/* ??? Only if block-move stuff knows about different source/destination
+ alignment. */
+#if 0
+#define CONSTANT_ALIGNMENT(EXP, ALIGN) MAX ((ALIGN), BITS_PER_WORD)
+#define DATA_ALIGNMENT(EXP, ALIGN) MAX ((ALIGN), BITS_PER_WORD)
+#endif
/* Set this non-zero if move instructions will actually fail to work
when given unaligned data.
@@ -325,11 +564,11 @@ extern int target_flags;
listed once, even those in FIXED_REGISTERS.
We allocate in the following order:
- $f1 (nonsaved floating-point register)
- $f10-$f15 (likewise)
+ $f10-$f15 (nonsaved floating-point register)
$f22-$f30 (likewise)
$f21-$f16 (likewise, but input args)
$f0 (nonsaved, but return value)
+ $f1 (nonsaved, but immediate before saved)
$f2-$f9 (saved floating-point registers)
$1-$8 (nonsaved integer registers)
$22-$25 (likewise)
@@ -344,11 +583,10 @@ extern int target_flags;
$30, $31, $f31 (stack pointer and always zero/ap & fp) */
#define REG_ALLOC_ORDER \
- {33, \
- 42, 43, 44, 45, 46, 47, \
+ {42, 43, 44, 45, 46, 47, \
54, 55, 56, 57, 58, 59, 60, 61, 62, \
53, 52, 51, 50, 49, 48, \
- 32, \
+ 32, 33, \
34, 35, 36, 37, 38, 39, 40, 41, \
1, 2, 3, 4, 5, 6, 7, 8, \
22, 23, 24, 25, \
@@ -373,18 +611,20 @@ extern int target_flags;
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
On Alpha, the integer registers can hold any mode. The floating-point
registers can hold 32-bit and 64-bit integers as well, but not 16-bit
- or 8-bit values. If we only allowed the larger integers into FP registers,
- we'd have to say that QImode and SImode aren't tiable, which is a
- pain. So say all registers can hold everything and see how that works. */
+ or 8-bit values. */
-#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ ((REGNO) < 32 || ((MODE) != QImode && (MODE) != HImode))
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
for any hard reg, then this must be 0 for correct output. */
-#define MODES_TIEABLE_P(MODE1, MODE2) 1
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ ((MODE1) == QImode || (MODE1) == HImode \
+ ? (MODE2) == QImode || (MODE2) == HImode \
+ : 1)
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
@@ -499,9 +739,7 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
: (C) == 'J' ? (VALUE) == 0 \
: (C) == 'K' ? (unsigned HOST_WIDE_INT) ((VALUE) + 0x8000) < 0x10000 \
: (C) == 'L' ? (((VALUE) & 0xffff) == 0 \
- && (((VALUE)) >> 31 == -1 || (VALUE) >> 31 == 0) \
- && ((HOST_BITS_PER_WIDE_INT == 64 \
- || (unsigned) (VALUE) != 0x80000000U))) \
+ && (((VALUE)) >> 31 == -1 || (VALUE) >> 31 == 0)) \
: (C) == 'M' ? zap_mask (VALUE) \
: (C) == 'N' ? (unsigned HOST_WIDE_INT) (~ (VALUE)) < 0x100 \
: (C) == 'O' ? (unsigned HOST_WIDE_INT) (- (VALUE)) < 0x100 \
@@ -526,12 +764,17 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
For the Alpha, `Q' means that this is a memory operand but not a
reference to an unaligned location.
+
`R' is a SYMBOL_REF that has SYMBOL_REF_FLAG set or is the current
- function. */
+ function.
+
+ 'S' is a 6-bit constant (valid for a shift insn). */
#define EXTRA_CONSTRAINT(OP, C) \
- ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) != AND \
- : (C) == 'R' ? current_file_function_operand (OP, Pmode) \
+ ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) != AND \
+ : (C) == 'R' ? current_file_function_operand (OP, Pmode) \
+ : (C) == 'S' ? (GET_CODE (OP) == CONST_INT \
+ && (unsigned HOST_WIDE_INT) INTVAL (OP) < 64) \
: 0)
/* Given an rtx X being reloaded into a reg required to be
@@ -544,12 +787,13 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
#define PREFERRED_RELOAD_CLASS(X, CLASS) \
(CONSTANT_P (X) && (X) != const0_rtx && (X) != CONST0_RTX (GET_MODE (X)) \
- ? ((CLASS) == FLOAT_REGS ? NO_REGS : GENERAL_REGS) \
+ ? ((CLASS) == FLOAT_REGS || (CLASS) == NO_REGS ? NO_REGS : GENERAL_REGS)\
: (CLASS))
/* Loading and storing HImode or QImode values to and from memory
usually requires a scratch register. The exceptions are loading
- QImode and HImode from an aligned address to a general register.
+ QImode and HImode from an aligned address to a general register
+ unless byte instructions are permitted.
We also cannot load an unaligned address or a paradoxical SUBREG into an
FP register. */
@@ -563,7 +807,7 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
&& (((CLASS) == FLOAT_REGS \
&& ((MODE) == SImode || (MODE) == HImode || (MODE) == QImode)) \
|| (((MODE) == QImode || (MODE) == HImode) \
- && unaligned_memory_operand (IN, MODE)))) \
+ && ! TARGET_BWX && unaligned_memory_operand (IN, MODE)))) \
? GENERAL_REGS \
: ((CLASS) == FLOAT_REGS && GET_CODE (IN) == MEM \
&& GET_CODE (XEXP (IN, 0)) == AND) ? GENERAL_REGS \
@@ -579,8 +823,9 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
&& (GET_CODE (SUBREG_REG (OUT)) == MEM \
|| (GET_CODE (SUBREG_REG (OUT)) == REG \
&& REGNO (SUBREG_REG (OUT)) >= FIRST_PSEUDO_REGISTER)))) \
- && (((MODE) == HImode || (MODE) == QImode \
- || ((MODE) == SImode && (CLASS) == FLOAT_REGS)))) \
+ && ((((MODE) == HImode || (MODE) == QImode) \
+ && (! TARGET_BWX || (CLASS) == FLOAT_REGS)) \
+ || ((MODE) == SImode && (CLASS) == FLOAT_REGS))) \
? GENERAL_REGS \
: ((CLASS) == FLOAT_REGS && GET_CODE (OUT) == MEM \
&& GET_CODE (XEXP (OUT, 0)) == AND) ? GENERAL_REGS \
@@ -590,9 +835,10 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
: NO_REGS)
/* If we are copying between general and FP registers, we need a memory
- location. */
+ location unless the CIX extension is available. */
-#define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) ((CLASS1) != (CLASS2))
+#define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \
+ (! TARGET_CIX && (CLASS1) != (CLASS2))
/* Specify the mode to be used for memory when a secondary memory
location is needed. If MODE is floating-point, use it. Otherwise,
@@ -622,15 +868,18 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
reduce the impact of not being able to allocate a pseudo to a
hard register. */
-#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
- (((CLASS1) == FLOAT_REGS) == ((CLASS2) == FLOAT_REGS) ? 2 : 20)
+#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
+ (((CLASS1) == FLOAT_REGS) == ((CLASS2) == FLOAT_REGS) \
+ ? 2 \
+ : TARGET_CIX ? 3 : 4+2*alpha_memory_latency)
/* A C expressions returning the cost of moving data of MODE from a register to
or from memory.
On the Alpha, bump this up a bit. */
-#define MEMORY_MOVE_COST(MODE) 6
+extern int alpha_memory_latency;
+#define MEMORY_MOVE_COST(MODE,CLASS,IN) (2*alpha_memory_latency)
/* Provide the cost of a branch. Exact meaning under development. */
#define BRANCH_COST 5
@@ -664,6 +913,9 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
On Alpha, don't define this because there are no push insns. */
/* #define PUSH_ROUNDING(BYTES) */
+/* Define this to be nonzero if stack checking is built into the ABI. */
+#define STACK_CHECK_BUILTIN 1
+
/* Define this if the maximum size of all the outgoing args is to be
accumulated and pushed during the prologue. The amount can be
found in the variable current_function_outgoing_args_size. */
@@ -738,18 +990,25 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
$f0 for floating-point functions. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
- gen_rtx (REG, \
- (INTEGRAL_MODE_P (TYPE_MODE (VALTYPE)) \
- && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
- ? word_mode : TYPE_MODE (VALTYPE), \
- TARGET_FPREGS && TREE_CODE (VALTYPE) == REAL_TYPE ? 32 : 0)
+ gen_rtx (REG, \
+ ((INTEGRAL_TYPE_P (VALTYPE) \
+ && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
+ || POINTER_TYPE_P (VALTYPE)) \
+ ? word_mode : TYPE_MODE (VALTYPE), \
+ ((TARGET_FPREGS \
+ && (TREE_CODE (VALTYPE) == REAL_TYPE \
+ || TREE_CODE (VALTYPE) == COMPLEX_TYPE)) \
+ ? 32 : 0))
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
#define LIBCALL_VALUE(MODE) \
- gen_rtx (REG, MODE, \
- TARGET_FPREGS && GET_MODE_CLASS (MODE) == MODE_FLOAT ? 32 : 0)
+ gen_rtx (REG, MODE, \
+ (TARGET_FPREGS \
+ && (GET_MODE_CLASS (MODE) == MODE_FLOAT \
+ || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \
+ ? 32 : 0))
/* The definition of this macro implies that there are cases where
a scalar value cannot be returned in registers.
@@ -764,7 +1023,8 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
/* 1 if N is a possible register number for a function value
as seen by the caller. */
-#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0 || (N) == 32)
+#define FUNCTION_VALUE_REGNO_P(N) \
+ ((N) == 0 || (N) == 1 || (N) == 32 || (N) == 33)
/* 1 if N is a possible register number for function argument passing.
On Alpha, these are $16-$21 and $f16-$f21. */
@@ -788,7 +1048,7 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0. */
-#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME) (CUM) = 0
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) (CUM) = 0
/* Define intermediate macro to compute the size (in registers) of an argument
for the Alpha. */
@@ -894,6 +1154,7 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
plus_constant (virtual_incoming_args_rtx, \
(CUM) * UNITS_PER_WORD)), \
6 - (CUM), (6 - (CUM)) * UNITS_PER_WORD); \
+ emit_insn (gen_blockage ()); \
} \
PRETEND_SIZE = 12 * UNITS_PER_WORD; \
} \
@@ -905,6 +1166,9 @@ enum reg_class { NO_REGS, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
emitted. If it would take more than N insns, zero is returned and no
insns and emitted. */
extern struct rtx_def *alpha_emit_set_const ();
+extern struct rtx_def *alpha_emit_set_long_const ();
+extern struct rtx_def *alpha_emit_conditional_branch ();
+extern struct rtx_def *alpha_emit_conditional_move ();
/* Generate necessary RTL for __builtin_saveregs().
ARGLIST is the argument list; see expr.c. */
@@ -918,25 +1182,34 @@ extern struct rtx_def *alpha_builtin_saveregs ();
extern struct rtx_def *alpha_compare_op0, *alpha_compare_op1;
extern int alpha_compare_fp_p;
-/* This macro produces the initial definition of a function name. On the
- Alpha, we need to save the function name for the prologue and epilogue. */
+/* Make (or fake) .linkage entry for function call.
+ IS_LOCAL is 0 if name is used in call, 1 if name is used in definition. */
+extern void alpha_need_linkage ();
-extern char *alpha_function_name;
+/* This macro defines the start of an assembly comment. */
-#define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \
-{ \
- alpha_function_name = NAME; \
-}
+#define ASM_COMMENT_START " #"
+
+/* This macro produces the initial definition of a function. */
+
+#define ASM_DECLARE_FUNCTION_NAME(FILE,NAME,DECL) \
+ alpha_start_function(FILE,NAME,DECL);
+extern void alpha_start_function ();
+
+/* This macro closes up a function definition for the assembler. */
+
+#define ASM_DECLARE_FUNCTION_SIZE(FILE,NAME,DECL) \
+ alpha_end_function(FILE,NAME,DECL)
+extern void alpha_end_function ();
-/* This macro generates the assembly code for function entry.
- FILE is a stdio stream to output the code to.
- SIZE is an int: how many units of temporary storage to allocate.
- Refer to the array `regs_ever_live' to determine which registers
- to save; `regs_ever_live[I]' is nonzero if register number I
- is ever used in the function. This macro is responsible for
- knowing which registers should not be saved even if used. */
+/* This macro notes the end of the prologue. */
-#define FUNCTION_PROLOGUE(FILE, SIZE) output_prolog (FILE, SIZE)
+#define FUNCTION_END_PROLOGUE(FILE) output_end_prologue (FILE)
+extern void output_end_prologue ();
+
+/* Output any profiling code before the prologue. */
+
+#define PROFILE_BEFORE_PROLOGUE 1
/* Output assembler code to FILE to increment profiler label # LABELNO
for profiling a function entry. Under OSF/1, profiling is enabled
@@ -986,19 +1259,6 @@ extern char *alpha_function_name;
No definition is equivalent to always zero. */
#define EXIT_IGNORE_STACK 1
-
-/* This macro generates the assembly code for function exit,
- on machines that need it. If FUNCTION_EPILOGUE is not defined
- then individual return instructions are generated for each
- return statement. Args are same as for FUNCTION_PROLOGUE.
-
- The function epilogue should not depend on the current stack pointer!
- It should use the frame pointer only. This is mandatory because
- of alloca; we also take advantage of it to omit stack adjustments
- before returning. */
-
-#define FUNCTION_EPILOGUE(FILE, SIZE) output_epilog (FILE, SIZE)
-
/* Output assembler code for a block containing the constant parts
of a trampoline, leaving space for the variable parts.
@@ -1010,13 +1270,13 @@ extern char *alpha_function_name;
aligned to FUNCTION_BOUNDARY, which is 64 bits. */
#define TRAMPOLINE_TEMPLATE(FILE) \
-{ \
+do { \
fprintf (FILE, "\tldq $1,24($27)\n"); \
fprintf (FILE, "\tldq $27,16($27)\n"); \
fprintf (FILE, "\tjmp $31,($27),0\n"); \
fprintf (FILE, "\tnop\n"); \
fprintf (FILE, "\t.quad 0,0\n"); \
-}
+} while (0)
/* Section in which to place the trampoline. On Alpha, instructions
may only be placed in a text segment. */
@@ -1029,76 +1289,24 @@ extern char *alpha_function_name;
/* Emit RTL insns to initialize the variable parts of a trampoline.
FNADDR is an RTX for the address of the function's pure code.
- CXT is an RTX for the static chain value for the function. We assume
- here that a function will be called many more times than its address
- is taken (e.g., it might be passed to qsort), so we take the trouble
- to initialize the "hint" field in the JMP insn. Note that the hint
- field is PC (new) + 4 * bits 13:0. */
-
-#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
-{ \
- rtx _temp, _temp1, _addr; \
- \
- _addr = memory_address (Pmode, plus_constant ((TRAMP), 16)); \
- emit_move_insn (gen_rtx (MEM, Pmode, _addr), (FNADDR)); \
- _addr = memory_address (Pmode, plus_constant ((TRAMP), 24)); \
- emit_move_insn (gen_rtx (MEM, Pmode, _addr), (CXT)); \
- \
- _temp = force_operand (plus_constant ((TRAMP), 12), NULL_RTX); \
- _temp = expand_binop (DImode, sub_optab, (FNADDR), _temp, _temp, 1, \
- OPTAB_WIDEN); \
- _temp = expand_shift (RSHIFT_EXPR, Pmode, _temp, \
- build_int_2 (2, 0), NULL_RTX, 1); \
- _temp = expand_and (gen_lowpart (SImode, _temp), \
- GEN_INT (0x3fff), 0); \
- \
- _addr = memory_address (SImode, plus_constant ((TRAMP), 8)); \
- _temp1 = force_reg (SImode, gen_rtx (MEM, SImode, _addr)); \
- _temp1 = expand_and (_temp1, GEN_INT (0xffffc000), NULL_RTX); \
- _temp1 = expand_binop (SImode, ior_optab, _temp1, _temp, _temp1, 1, \
- OPTAB_WIDEN); \
- \
- emit_move_insn (gen_rtx (MEM, SImode, _addr), _temp1); \
- \
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, \
- "__enable_execute_stack"), \
- 0, VOIDmode, 1,_addr, Pmode); \
- \
- emit_insn (gen_rtx (UNSPEC_VOLATILE, VOIDmode, \
- gen_rtvec (1, const0_rtx), 0)); \
-}
+ CXT is an RTX for the static chain value for the function. */
-/* Attempt to turn on access permissions for the stack. */
-
-#define TRANSFER_FROM_TRAMPOLINE \
- \
-void \
-__enable_execute_stack (addr) \
- void *addr; \
-{ \
- long size = getpagesize (); \
- long mask = ~(size-1); \
- char *page = (char *) (((long) addr) & mask); \
- char *end = (char *) ((((long) (addr + TRAMPOLINE_SIZE)) & mask) + size); \
- \
- /* 7 is PROT_READ | PROT_WRITE | PROT_EXEC */ \
- if (mprotect (page, end - page, 7) < 0) \
- perror ("mprotect of trampoline code"); \
-}
+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
+ alpha_initialize_trampoline (TRAMP, FNADDR, CXT, 16, 24, 8)
/* A C expression whose value is RTL representing the value of the return
address for the frame COUNT steps up from the current frame.
FRAMEADDR is the frame pointer of the COUNT frame, or the frame pointer of
- the COUNT-1 frame if RETURN_ADDR_IN_PREVIOUS_FRAME} is defined.
+ the COUNT-1 frame if RETURN_ADDR_IN_PREVIOUS_FRAME is defined. */
+
+#define RETURN_ADDR_RTX alpha_return_addr
+extern struct rtx_def *alpha_return_addr ();
- This definition for Alpha is broken, but is put in at the request of
- Mike Stump. */
+/* Initialize data used by insn expanders. This is called from insn_emit,
+ once for every function before code is generated. */
-#define RETURN_ADDR_RTX(COUNT, FRAME) \
-((COUNT == 0 && alpha_sa_size () == 0 && 0 /* not right. */) \
- ? gen_rtx (REG, Pmode, 26) \
- : gen_rtx (MEM, Pmode, \
- memory_address (Pmode, FRAME)))
+#define INIT_EXPANDERS alpha_init_expanders ()
+extern void alpha_init_expanders ();
/* Addressing modes, and classification of registers for them. */
@@ -1284,6 +1492,58 @@ __enable_execute_stack (addr) \
} \
}
+/* Try a machine-dependent way of reloading an illegitimate address
+ operand. If we find one, push the reload and jump to WIN. This
+ macro is used in only one place: `find_reloads_address' in reload.c.
+
+ For the Alpha, we wish to handle large displacements off a base
+ register by splitting the addend across an ldah and the mem insn.
+ This cuts number of extra insns needed from 3 to 1. */
+
+#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND_LEVELS,WIN) \
+do { \
+ /* We must recognize output that we have already generated ourselves. */ \
+ if (GET_CODE (X) == PLUS \
+ && GET_CODE (XEXP (X, 0)) == PLUS \
+ && GET_CODE (XEXP (XEXP (X, 0), 0)) == REG \
+ && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ { \
+ push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \
+ BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \
+ OPNUM, TYPE); \
+ goto WIN; \
+ } \
+ if (GET_CODE (X) == PLUS \
+ && GET_CODE (XEXP (X, 0)) == REG \
+ && REGNO (XEXP (X, 0)) < FIRST_PSEUDO_REGISTER \
+ && REG_MODE_OK_FOR_BASE_P (XEXP (X, 0), MODE) \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ { \
+ HOST_WIDE_INT val = INTVAL (XEXP (X, 1)); \
+ HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000; \
+ HOST_WIDE_INT high \
+ = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000; \
+ \
+ /* Check for 32-bit overflow. */ \
+ if (high + low != val) \
+ break; \
+ \
+ /* Reload the high part into a base reg; leave the low part \
+ in the mem directly. */ \
+ \
+ X = gen_rtx_PLUS (GET_MODE (X), \
+ gen_rtx_PLUS (GET_MODE (X), XEXP (X, 0), \
+ GEN_INT (high)), \
+ GEN_INT (low)); \
+ \
+ push_reload (XEXP (X, 0), NULL_RTX, &XEXP (X, 0), NULL_PTR, \
+ BASE_REG_CLASS, GET_MODE (X), VOIDmode, 0, 0, \
+ OPNUM, TYPE); \
+ goto WIN; \
+ } \
+} while (0)
+
/* Go to LABEL if ADDR (a legitimate address expression)
has an effect that depends on the machine mode it is used for.
On the Alpha this is true only for the unaligned modes. We can
@@ -1297,22 +1557,22 @@ __enable_execute_stack (addr) \
#define ADDRESS_COST(X) 0
-/* Define this if some processing needs to be done immediately before
- emitting code for an insn. */
-
-/* #define FINAL_PRESCAN_INSN(INSN,OPERANDS,NOPERANDS) */
+/* Machine-dependent reorg pass. */
+#define MACHINE_DEPENDENT_REORG(X) alpha_reorg(X)
/* Specify the machine mode that this machine uses
for the index in the tablejump instruction. */
#define CASE_VECTOR_MODE SImode
-/* Define this if the tablejump instruction expects the table
- to contain offsets from the address of the table.
+/* Define as C expression which evaluates to nonzero if the tablejump
+ instruction expects the table to contain offsets from the address of the
+ table.
+
Do not define this if the table should contain absolute addresses.
On the Alpha, the table is really GP-relative, not relative to the PC
of the table, but we pretend that it is PC-relative; this should be OK,
but we should try to find some better way sometime. */
-#define CASE_VECTOR_PC_RELATIVE
+#define CASE_VECTOR_PC_RELATIVE 1
/* Specify the tree operation to be used to convert reals to integers. */
#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
@@ -1336,6 +1596,12 @@ __enable_execute_stack (addr) \
#define MOVE_MAX 8
+/* Controls how many units are moved by expr.c before resorting to movstr.
+ Without byte/word accesses, we want no more than one; with, several single
+ byte accesses are better. */
+
+#define MOVE_RATIO (TARGET_BWX ? 7 : 2)
+
/* Largest number of bytes of an object that can be placed in a register.
On the Alpha we have plenty of registers, so use TImode. */
#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (TImode)
@@ -1357,7 +1623,7 @@ __enable_execute_stack (addr) \
will either zero-extend or sign-extend. The value of this macro should
be the code that says which one of the two operations is implicitly
done, NIL if none. */
-#define LOAD_EXTEND_OP(MODE) SIGN_EXTEND
+#define LOAD_EXTEND_OP(MODE) ((MODE) == SImode ? SIGN_EXTEND : ZERO_EXTEND)
/* Define if loading short immediate values into registers sign extends. */
#define SHORT_IMMEDIATES_SIGN_EXTEND
@@ -1373,7 +1639,7 @@ __enable_execute_stack (addr) \
/* Define the value returned by a floating-point comparison instruction. */
-#define FLOAT_STORE_FLAG_VALUE 0.5
+#define FLOAT_STORE_FLAG_VALUE (TARGET_FLOAT_VAX ? 0.5 : 2.0)
/* Canonicalize a comparison from one we don't have to one we do have. */
@@ -1424,6 +1690,9 @@ __enable_execute_stack (addr) \
our own exit function. */
#define HAVE_ATEXIT
+/* The EV4 is dual issue; EV5/EV6 are quad issue. */
+#define ISSUE_RATE (alpha_cpu == PROCESSOR_EV4 ? 2 : 4)
+
/* Compute the cost of computing a constant rtl expression RTX
whose rtx-code is CODE. The body of this macro is a portion
of a switch statement. If the code is computed here,
@@ -1440,7 +1709,9 @@ __enable_execute_stack (addr) \
if (INTVAL (RTX) >= 0 && INTVAL (RTX) < 256) \
return 0; \
case CONST_DOUBLE: \
- if (((OUTER_CODE) == PLUS && add_operand (RTX, VOIDmode)) \
+ if ((RTX) == CONST0_RTX (GET_MODE (RTX))) \
+ return 0; \
+ else if (((OUTER_CODE) == PLUS && add_operand (RTX, VOIDmode)) \
|| ((OUTER_CODE) == AND && and_operand (RTX, VOIDmode))) \
return 0; \
else if (add_operand (RTX, VOIDmode) || and_operand (RTX, VOIDmode)) \
@@ -1450,7 +1721,15 @@ __enable_execute_stack (addr) \
case CONST: \
case SYMBOL_REF: \
case LABEL_REF: \
- return COSTS_N_INSNS (3);
+ switch (alpha_cpu) \
+ { \
+ case PROCESSOR_EV4: \
+ return COSTS_N_INSNS (3); \
+ case PROCESSOR_EV5: \
+ case PROCESSOR_EV6: \
+ return COSTS_N_INSNS (2); \
+ default: abort(); \
+ }
/* Provide the costs of a rtl expression. This is in the body of a
switch on CODE. */
@@ -1458,52 +1737,128 @@ __enable_execute_stack (addr) \
#define RTX_COSTS(X,CODE,OUTER_CODE) \
case PLUS: case MINUS: \
if (FLOAT_MODE_P (GET_MODE (X))) \
- return COSTS_N_INSNS (6); \
+ switch (alpha_cpu) \
+ { \
+ case PROCESSOR_EV4: \
+ return COSTS_N_INSNS (6); \
+ case PROCESSOR_EV5: \
+ case PROCESSOR_EV6: \
+ return COSTS_N_INSNS (4); \
+ default: abort(); \
+ } \
else if (GET_CODE (XEXP (X, 0)) == MULT \
&& const48_operand (XEXP (XEXP (X, 0), 1), VOIDmode)) \
return (2 + rtx_cost (XEXP (XEXP (X, 0), 0), OUTER_CODE) \
+ rtx_cost (XEXP (X, 1), OUTER_CODE)); \
break; \
case MULT: \
- if (FLOAT_MODE_P (GET_MODE (X))) \
- return COSTS_N_INSNS (6); \
- return COSTS_N_INSNS (23); \
+ switch (alpha_cpu) \
+ { \
+ case PROCESSOR_EV4: \
+ if (FLOAT_MODE_P (GET_MODE (X))) \
+ return COSTS_N_INSNS (6); \
+ return COSTS_N_INSNS (23); \
+ case PROCESSOR_EV5: \
+ if (FLOAT_MODE_P (GET_MODE (X))) \
+ return COSTS_N_INSNS (4); \
+ else if (GET_MODE (X) == DImode) \
+ return COSTS_N_INSNS (12); \
+ else \
+ return COSTS_N_INSNS (8); \
+ case PROCESSOR_EV6: \
+ if (FLOAT_MODE_P (GET_MODE (X))) \
+ return COSTS_N_INSNS (4); \
+ else \
+ return COSTS_N_INSNS (7); \
+ default: abort(); \
+ } \
case ASHIFT: \
if (GET_CODE (XEXP (X, 1)) == CONST_INT \
&& INTVAL (XEXP (X, 1)) <= 3) \
break; \
/* ... fall through ... */ \
- case ASHIFTRT: case LSHIFTRT: case IF_THEN_ELSE: \
- return COSTS_N_INSNS (2); \
+ case ASHIFTRT: case LSHIFTRT: \
+ switch (alpha_cpu) \
+ { \
+ case PROCESSOR_EV4: \
+ return COSTS_N_INSNS (2); \
+ case PROCESSOR_EV5: \
+ case PROCESSOR_EV6: \
+ return COSTS_N_INSNS (1); \
+ default: abort(); \
+ } \
+ case IF_THEN_ELSE: \
+ switch (alpha_cpu) \
+ { \
+ case PROCESSOR_EV4: \
+ case PROCESSOR_EV6: \
+ return COSTS_N_INSNS (2); \
+ case PROCESSOR_EV5: \
+ return COSTS_N_INSNS (1); \
+ default: abort(); \
+ } \
case DIV: case UDIV: case MOD: case UMOD: \
- if (GET_MODE (X) == SFmode) \
- return COSTS_N_INSNS (34); \
- else if (GET_MODE (X) == DFmode) \
- return COSTS_N_INSNS (63); \
- else \
- return COSTS_N_INSNS (70); \
+ switch (alpha_cpu) \
+ { \
+ case PROCESSOR_EV4: \
+ if (GET_MODE (X) == SFmode) \
+ return COSTS_N_INSNS (34); \
+ else if (GET_MODE (X) == DFmode) \
+ return COSTS_N_INSNS (63); \
+ else \
+ return COSTS_N_INSNS (70); \
+ case PROCESSOR_EV5: \
+ if (GET_MODE (X) == SFmode) \
+ return COSTS_N_INSNS (15); \
+ else if (GET_MODE (X) == DFmode) \
+ return COSTS_N_INSNS (22); \
+ else \
+ return COSTS_N_INSNS (70); /* ??? */ \
+ case PROCESSOR_EV6: \
+ if (GET_MODE (X) == SFmode) \
+ return COSTS_N_INSNS (12); \
+ else if (GET_MODE (X) == DFmode) \
+ return COSTS_N_INSNS (15); \
+ else \
+ return COSTS_N_INSNS (70); /* ??? */ \
+ default: abort(); \
+ } \
case MEM: \
- return COSTS_N_INSNS (3); \
+ switch (alpha_cpu) \
+ { \
+ case PROCESSOR_EV4: \
+ case PROCESSOR_EV6: \
+ return COSTS_N_INSNS (3); \
+ case PROCESSOR_EV5: \
+ return COSTS_N_INSNS (2); \
+ default: abort(); \
+ } \
+ case NEG: case ABS: \
+ if (! FLOAT_MODE_P (GET_MODE (X))) \
+ break; \
+ /* ... fall through ... */ \
case FLOAT: case UNSIGNED_FLOAT: case FIX: case UNSIGNED_FIX: \
case FLOAT_EXTEND: case FLOAT_TRUNCATE: \
- return COSTS_N_INSNS (6); \
- case NEG: case ABS: \
- if (FLOAT_MODE_P (GET_MODE (X))) \
- return COSTS_N_INSNS (6); \
- break;
+ switch (alpha_cpu) \
+ { \
+ case PROCESSOR_EV4: \
+ return COSTS_N_INSNS (6); \
+ case PROCESSOR_EV5: \
+ case PROCESSOR_EV6: \
+ return COSTS_N_INSNS (4); \
+ default: abort(); \
+ }
/* Control the assembler format that we output. */
-/* Output at beginning of assembler file. */
-
-#define ASM_FILE_START(FILE) \
-{ \
- alpha_write_verstamp (FILE); \
- fprintf (FILE, "\t.set noreorder\n"); \
- fprintf (FILE, "\t.set volatile\n"); \
- fprintf (FILE, "\t.set noat\n"); \
- ASM_OUTPUT_SOURCE_FILENAME (FILE, main_input_filename); \
-}
+/* We don't emit these labels, so as to avoid getting linker errors about
+ missing exception handling info. If we emit a gcc_compiled. label into
+ text, and the file has no code, then the DEC assembler gives us a zero
+ sized text section with no associated exception handling info. The
+ DEC linker sees this text section, and gives a warning saying that
+ the exception handling info is missing. */
+#define ASM_IDENTIFY_GCC(x)
+#define ASM_IDENTIFY_LANGUAGE(x)
/* Output to assembler file text saying following lines
may contain character constants, extra white space, comments, etc. */
@@ -1592,20 +1947,15 @@ literal_section () \
#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
do { fputs ("\t.globl ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0)
-/* This is how to output a reference to a user-level label named NAME.
- `assemble_name' uses this. */
+/* The prefix to add to user-visible assembler symbols. */
-#define ASM_OUTPUT_LABELREF(FILE,NAME) \
- fprintf (FILE, "%s", NAME)
+#define USER_LABEL_PREFIX ""
/* This is how to output an internal numbered label where
PREFIX is the class of label and NUM is the number within the class. */
#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
- if ((PREFIX)[0] == 'L') \
- fprintf (FILE, "$%s%d:\n", & (PREFIX)[1], NUM + 32); \
- else \
- fprintf (FILE, "%s%d:\n", PREFIX, NUM);
+ fprintf (FILE, "$%s%d:\n", PREFIX, NUM)
/* This is how to output a label for a jump table. Arguments are the same as
for ASM_OUTPUT_INTERNAL_LABEL, except the insn for the jump table is
@@ -1620,10 +1970,12 @@ literal_section () \
This is suitable for output with `assemble_name'. */
#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
- if ((PREFIX)[0] == 'L') \
- sprintf (LABEL, "*$%s%d", & (PREFIX)[1], NUM + 32); \
- else \
- sprintf (LABEL, "*%s%d", PREFIX, NUM)
+ sprintf (LABEL, "*$%s%d", PREFIX, NUM)
+
+/* Check a floating-point value for validity for a particular machine mode. */
+
+#define CHECK_FLOAT_VALUE(MODE, D, OVERFLOW) \
+ ((OVERFLOW) = check_float_value (MODE, &D, OVERFLOW))
/* This is how to output an assembler line defining a `double' constant. */
@@ -1642,29 +1994,18 @@ literal_section () \
{ \
char str[30]; \
REAL_VALUE_TO_DECIMAL (VALUE, "%.20e", str); \
- fprintf (FILE, "\t.t_floating %s\n", str); \
+ fprintf (FILE, "\t.%c_floating %s\n", (TARGET_FLOAT_VAX)?'g':'t', str); \
} \
}
/* This is how to output an assembler line defining a `float' constant. */
-#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
- { \
- if (REAL_VALUE_ISINF (VALUE) \
- || REAL_VALUE_ISNAN (VALUE) \
- || REAL_VALUE_MINUS_ZERO (VALUE)) \
- { \
- long t; \
- REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
- fprintf (FILE, "\t.long 0x%lx\n", t & 0xffffffff); \
- } \
- else \
- { \
- char str[30]; \
- REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \
- fprintf (FILE, "\t.s_floating %s\n", str); \
- } \
- }
+#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
+ do { \
+ long t; \
+ REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
+ fprintf (FILE, "\t.long 0x%lx\n", t & 0xffffffff); \
+} while (0)
/* This is how to output an assembler line defining an `int' constant. */
@@ -1684,12 +2025,12 @@ literal_section () \
#define ASM_OUTPUT_SHORT(FILE,VALUE) \
fprintf (FILE, "\t.word %d\n", \
- (GET_CODE (VALUE) == CONST_INT \
+ (int)(GET_CODE (VALUE) == CONST_INT \
? INTVAL (VALUE) & 0xffff : (abort (), 0)))
#define ASM_OUTPUT_CHAR(FILE,VALUE) \
fprintf (FILE, "\t.byte %d\n", \
- (GET_CODE (VALUE) == CONST_INT \
+ (int)(GET_CODE (VALUE) == CONST_INT \
? INTVAL (VALUE) & 0xff : (abort (), 0)))
/* We use the default ASCII-output routine, except that we don't write more
@@ -1756,7 +2097,7 @@ literal_section () \
/* This is how to output an assembler line for a numeric constant byte. */
#define ASM_OUTPUT_BYTE(FILE,VALUE) \
- fprintf (FILE, "\t.byte 0x%x\n", (VALUE) & 0xff)
+ fprintf (FILE, "\t.byte 0x%x\n", (int) ((VALUE) & 0xff))
/* This is how to output an element of a case-vector that is absolute.
(Alpha does not use such vectors, but we must define this macro anyway.) */
@@ -1765,13 +2106,9 @@ literal_section () \
/* This is how to output an element of a case-vector that is relative. */
-#if WINDOWS_NT
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
- fprintf (FILE, "\t.long $%d\n", (VALUE) + 32)
-#else
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
- fprintf (FILE, "\t.gprel32 $%d\n", (VALUE) + 32)
-#endif
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+ fprintf (FILE, "\t.%s $L%d\n", TARGET_WINDOWS_NT ? "long" : "gprel32", \
+ (VALUE))
/* This is how to output an assembler line
that says to advance the location counter
@@ -1816,6 +2153,36 @@ literal_section () \
#define ASM_OPEN_PAREN "("
#define ASM_CLOSE_PAREN ")"
+/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
+ Used for C++ multiple inheritance. */
+
+#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
+do { \
+ char *fn_name = XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0); \
+ int reg; \
+ \
+ /* Mark end of prologue. */ \
+ output_end_prologue (FILE); \
+ \
+ /* Rely on the assembler to macro expand a large delta. */ \
+ reg = aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) ? 17 : 16; \
+ fprintf (FILE, "\tlda $%d,%ld($%d)\n", reg, (long)(DELTA), reg); \
+ \
+ if (current_file_function_operand (XEXP (DECL_RTL (FUNCTION), 0))) \
+ { \
+ fprintf (FILE, "\tbr $31,$"); \
+ assemble_name (FILE, fn_name); \
+ fprintf (FILE, "..ng\n"); \
+ } \
+ else \
+ { \
+ fprintf (FILE, "\tjmp $31,"); \
+ assemble_name (FILE, fn_name); \
+ fputc ('\n', FILE); \
+ } \
+} while (0)
+
+
/* Define results of standard character escape sequences. */
#define TARGET_BELL 007
#define TARGET_BS 010
@@ -1832,9 +2199,41 @@ literal_section () \
#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
/* Determine which codes are valid without a following integer. These must
- not be alphabetic. */
+ not be alphabetic (the characters are chosen so that
+ PRINT_OPERAND_PUNCT_VALID_P translates into a simple range change when
+ using ASCII).
+
+ & Generates fp-rounding mode suffix: nothing for normal, 'c' for
+ chopped, 'm' for minus-infinity, and 'd' for dynamic rounding
+ mode. alpha_fprm controls which suffix is generated.
+
+ ' Generates trap-mode suffix for instructions that accept the
+ su suffix only (cmpt et al).
+
+ ` Generates trap-mode suffix for instructions that accept the
+ v and sv suffix. The only instruction that needs this is cvtql.
+
+ ( Generates trap-mode suffix for instructions that accept the
+ v, sv, and svi suffix. The only instruction that needs this
+ is cvttq.
-#define PRINT_OPERAND_PUNCT_VALID_P(CODE) 0
+ ) Generates trap-mode suffix for instructions that accept the
+ u, su, and sui suffix. This is the bulk of the IEEE floating
+ point instructions (addt et al).
+
+ + Generates trap-mode suffix for instructions that accept the
+ sui suffix (cvtqt and cvtqs).
+
+ , Generates single precision suffix for floating point
+ instructions (s for IEEE, f for VAX)
+
+ - Generates double precision suffix for floating point
+ instructions (t for IEEE, g for VAX)
+ */
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
+ ((CODE) == '&' || (CODE) == '`' || (CODE) == '\'' || (CODE) == '(' \
+ || (CODE) == ')' || (CODE) == '+' || (CODE) == ',' || (CODE) == '-')
/* Print a memory address as an operand to reference that memory location. */
@@ -1857,38 +2256,42 @@ literal_section () \
else \
abort (); \
\
- fprintf (FILE, "%d($%d)", offset, basereg); \
+ fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, offset); \
+ fprintf (FILE, "($%d)", basereg); \
}
/* Define the codes that are matched by predicates in alpha.c. */
-#define PREDICATE_CODES \
- {"reg_or_0_operand", {SUBREG, REG, CONST_INT}}, \
- {"reg_or_6bit_operand", {SUBREG, REG, CONST_INT}}, \
- {"reg_or_8bit_operand", {SUBREG, REG, CONST_INT}}, \
- {"cint8_operand", {CONST_INT}}, \
- {"reg_or_cint_operand", {SUBREG, REG, CONST_INT}}, \
- {"add_operand", {SUBREG, REG, CONST_INT}}, \
- {"sext_add_operand", {SUBREG, REG, CONST_INT}}, \
- {"const48_operand", {CONST_INT}}, \
- {"and_operand", {SUBREG, REG, CONST_INT}}, \
- {"or_operand", {SUBREG, REG, CONST_INT}}, \
- {"mode_mask_operand", {CONST_INT}}, \
- {"mul8_operand", {CONST_INT}}, \
- {"mode_width_operand", {CONST_INT}}, \
- {"reg_or_fp0_operand", {SUBREG, REG, CONST_DOUBLE}}, \
- {"alpha_comparison_operator", {EQ, LE, LT, LEU, LTU}}, \
- {"signed_comparison_operator", {EQ, NE, LE, LT, GE, GT}}, \
- {"divmod_operator", {DIV, MOD, UDIV, UMOD}}, \
- {"fp0_operand", {CONST_DOUBLE}}, \
- {"current_file_function_operand", {SYMBOL_REF}}, \
- {"call_operand", {REG, SYMBOL_REF}}, \
- {"input_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \
- SYMBOL_REF, CONST, LABEL_REF}}, \
- {"some_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \
- SYMBOL_REF, CONST, LABEL_REF}}, \
- {"aligned_memory_operand", {MEM}}, \
- {"unaligned_memory_operand", {MEM}}, \
- {"any_memory_operand", {MEM}},
+#define PREDICATE_CODES \
+ {"reg_or_0_operand", {SUBREG, REG, CONST_INT}}, \
+ {"reg_or_6bit_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"reg_or_8bit_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"cint8_operand", {CONST_INT, CONSTANT_P_RTX}}, \
+ {"reg_or_cint_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"add_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"sext_add_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"const48_operand", {CONST_INT}}, \
+ {"and_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"or_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+ {"mode_mask_operand", {CONST_INT}}, \
+ {"mul8_operand", {CONST_INT}}, \
+ {"mode_width_operand", {CONST_INT}}, \
+ {"reg_or_fp0_operand", {SUBREG, REG, CONST_DOUBLE}}, \
+ {"alpha_comparison_operator", {EQ, LE, LT, LEU, LTU}}, \
+ {"alpha_swapped_comparison_operator", {EQ, GE, GT, GEU, GTU}}, \
+ {"signed_comparison_operator", {EQ, NE, LE, LT, GE, GT}}, \
+ {"divmod_operator", {DIV, MOD, UDIV, UMOD}}, \
+ {"fp0_operand", {CONST_DOUBLE}}, \
+ {"current_file_function_operand", {SYMBOL_REF}}, \
+ {"call_operand", {REG, SYMBOL_REF}}, \
+ {"input_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \
+ SYMBOL_REF, CONST, LABEL_REF, CONSTANT_P_RTX}}, \
+ {"some_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE, \
+ SYMBOL_REF, CONST, LABEL_REF, CONSTANT_P_RTX}}, \
+ {"aligned_memory_operand", {MEM}}, \
+ {"unaligned_memory_operand", {MEM}}, \
+ {"reg_or_unaligned_mem_operand", {SUBREG, REG, MEM}}, \
+ {"any_memory_operand", {MEM}}, \
+ {"hard_fp_register_operand", {SUBREG, REG}},
/* Tell collect that the object format is ECOFF. */
#define OBJECT_FORMAT_COFF
@@ -1904,8 +2307,7 @@ literal_section () \
#define MIPS_DEBUGGING_INFO /* MIPS specific debugging info */
#ifndef PREFERRED_DEBUGGING_TYPE /* assume SDB_DEBUGGING_INFO */
-#define PREFERRED_DEBUGGING_TYPE \
- ((len > 1 && !strncmp (str, "ggdb", len)) ? DBX_DEBUG : SDB_DEBUG)
+#define PREFERRED_DEBUGGING_TYPE SDB_DEBUG
#endif
@@ -1937,13 +2339,17 @@ extern void alpha_output_lineno ();
alpha_output_filename (STREAM, NAME)
extern void alpha_output_filename ();
-
-/* mips-tfile.c limits us to strings of one page. */
-#define DBX_CONTIN_LENGTH 4000
+/* mips-tfile.c limits us to strings of one page. We must underestimate this
+ number, because the real length runs past this up to the next
+ continuation point. This is really a dbxout.c bug. */
+#define DBX_CONTIN_LENGTH 3000
/* By default, turn on GDB extensions. */
#define DEFAULT_GDB_EXTENSIONS 1
+/* Stabs-in-ECOFF can't handle dbxout_function_end(). */
+#define NO_DBX_FUNCTION_END 1
+
/* If we are smuggling stabs through the ALPHA ECOFF object
format, put a comment in front of the .stab<x> operation so
that the ALPHA assembler does not choke. The mips-tfile program
@@ -2011,47 +2417,7 @@ do { \
#define PUT_SDB_FUNCTION_END(LINE)
-#define PUT_SDB_EPILOGUE_END(NAME)
-
-/* No point in running CPP on our assembler output. */
-#if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_GAS) != 0
-/* Don't pass -g to GNU as, because some versions don't accept this option. */
-#define ASM_SPEC "%{malpha-as:-g} -nocpp %{pg}"
-#else
-/* In OSF/1 v3.2c, the assembler by default does not output file names which
- causes mips-tfile to fail. Passing -g to the assembler fixes this problem.
- ??? Stricly speaking, we only need -g if the user specifies -g. Passing
- it always means that we get slightly larger than necessary object files
- if the user does not specify -g. If we don't pass -g, then mips-tfile
- will need to be fixed to work in this case. */
-#define ASM_SPEC "%{!mgas:-g} -nocpp %{pg}"
-#endif
-
-/* Specify to run a post-processor, mips-tfile after the assembler
- has run to stuff the ecoff debug information into the object file.
- This is needed because the Alpha assembler provides no way
- of specifying such information in the assembly file. */
-
-#if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_GAS) != 0
-
-#define ASM_FINAL_SPEC "\
-%{malpha-as: %{!mno-mips-tfile: \
- \n mips-tfile %{v*: -v} \
- %{K: -I %b.o~} \
- %{!K: %{save-temps: -I %b.o~}} \
- %{c:%W{o*}%{!o*:-o %b.o}}%{!c:-o %U.o} \
- %{.s:%i} %{!.s:%g.s}}}"
-
-#else
-#define ASM_FINAL_SPEC "\
-%{!mgas: %{!mno-mips-tfile: \
- \n mips-tfile %{v*: -v} \
- %{K: -I %b.o~} \
- %{!K: %{save-temps: -I %b.o~}} \
- %{c:%W{o*}%{!o*:-o %b.o}}%{!c:-o %U.o} \
- %{.s:%i} %{!.s:%g.s}}}"
-
-#endif
+#define PUT_SDB_EPILOGUE_END(NAME) ((void)(NAME))
/* Macros for mips-tfile.c to encapsulate stabs in ECOFF, and for
mips-tdump.c to print them out.
@@ -2073,16 +2439,55 @@ do { \
#define ALIGN_SYMTABLE_OFFSET(OFFSET) (((OFFSET) + 7) & ~7)
-/* The system headers under OSF/1 are C++-aware. */
-#define NO_IMPLICIT_EXTERN_C
-
-/* Also define __LANGUAGE_C__ when running fix-header. */
-#define FIXPROTO_INIT(CPPFILE) cpp_define (CPPFILE, "__LANGUAGE_C__")
-
/* The linker will stick __main into the .init section. */
#define HAS_INIT_SECTION
#define LD_INIT_SWITCH "-init"
#define LD_FINI_SWITCH "-fini"
-/* We do want to link in libgcc when building shared libraries under OSF/1. */
-#define LIBGCC_SPEC "-lgcc"
+/* The system headers under Alpha systems are generally C++-aware. */
+#define NO_IMPLICIT_EXTERN_C
+
+/* Prototypes for alpha.c functions used in the md file & elsewhere. */
+extern struct rtx_def *get_unaligned_address ();
+extern void alpha_write_verstamp ();
+extern void alpha_reorg ();
+extern int check_float_value ();
+extern int direct_return ();
+extern int const48_operand ();
+extern int add_operand ();
+extern int and_operand ();
+extern int unaligned_memory_operand ();
+extern int zap_mask ();
+extern int current_file_function_operand ();
+extern int alpha_sa_size ();
+extern int alpha_adjust_cost ();
+extern void print_operand ();
+extern int reg_or_0_operand ();
+extern int reg_or_8bit_operand ();
+extern int mul8_operand ();
+extern int reg_or_6bit_operand ();
+extern int alpha_comparison_operator ();
+extern int alpha_swapped_comparison_operator ();
+extern int sext_add_operand ();
+extern int cint8_operand ();
+extern int mode_mask_operand ();
+extern int or_operand ();
+extern int mode_width_operand ();
+extern int reg_or_fp0_operand ();
+extern int signed_comparison_operator ();
+extern int fp0_operand ();
+extern int some_operand ();
+extern int input_operand ();
+extern int divmod_operator ();
+extern int call_operand ();
+extern int reg_or_cint_operand ();
+extern int hard_fp_register_operand ();
+extern void alpha_set_memflags ();
+extern int aligned_memory_operand ();
+extern void get_aligned_mem ();
+extern void alpha_expand_unaligned_load ();
+extern void alpha_expand_unaligned_store ();
+extern int alpha_expand_block_move ();
+extern int alpha_expand_block_clear ();
+extern void alpha_expand_prologue ();
+extern void alpha_expand_epilogue ();
diff --git a/contrib/gcc/config/alpha/alpha.md b/contrib/gcc/config/alpha/alpha.md
index 72c54ee..87ebf95 100644
--- a/contrib/gcc/config/alpha/alpha.md
+++ b/contrib/gcc/config/alpha/alpha.md
@@ -1,5 +1,5 @@
;; Machine description for DEC Alpha for GNU C compiler
-;; Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+;; Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
;; This file is part of GNU CC.
@@ -20,71 +20,396 @@
;; Boston, MA 02111-1307, USA.
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+;; Uses of UNSPEC in this file:
+;;
+;; 0 arg_home
+;; 1 cttz
+;; 2 insxh
+;; 3 mskxh
+;; 4 cvtlq
+;; 5 cvtql
+;;
+;; UNSPEC_VOLATILE:
+;;
+;; 0 imb
+;; 1 blockage
+;; 2 builtin_setjmp_receiver
+;; 3 builtin_longjmp
+;; 4 trapb
+;; 5 prologue_stack_probe_loop
+;; Processor type -- this attribute must exactly match the processor_type
+;; enumeration in alpha.h.
+
+(define_attr "cpu" "ev4,ev5,ev6"
+ (const (symbol_ref "alpha_cpu")))
+
;; Define an insn type attribute. This is used in function unit delay
;; computations, among other purposes. For the most part, we use the names
;; defined in the EV4 documentation, but add a few that we have to know about
;; separately.
(define_attr "type"
- "ld,st,ibr,fbr,jsr,iaddlog,shiftcm,icmp,imull,imulq,fpop,fdivs,fdivt,ldsym,isubr"
- (const_string "shiftcm"))
-
-;; We include four function units: ABOX, which computes the address,
-;; BBOX, used for branches, EBOX, used for integer operations, and FBOX,
-;; used for FP operations.
-;;
-;; We assume that we have been successful in getting double issues and
-;; hence multiply all costs by two insns per cycle. The minimum time in
-;; a function unit is 2 cycle, which will tend to produce the double
-;; issues.
+ "ild,fld,ldsym,ist,fst,ibr,fbr,jsr,iadd,ilog,shift,icmov,fcmov,icmp,imul,fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof"
+ (const_string "iadd"))
-;; Memory delivers its result in three cycles.
-(define_function_unit "abox" 1 0 (eq_attr "type" "ld,ldsym,st") 6 2)
+;; Define the operand size an insn operates on. Used primarily by mul
+;; and div operations that have size dependant timings.
-;; Branches have no delay cost, but do tie up the unit for two cycles.
-(define_function_unit "bbox" 1 1 (eq_attr "type" "ibr,fbr,jsr") 4 4)
+(define_attr "opsize" "si,di,udi" (const_string "di"))
-;; Arithmetic insns are normally have their results available after two
-;; cycles. There are a number of exceptions. They are encoded in
-;; ADJUST_COST. Some of the other insns have similar exceptions.
+;; The TRAP_TYPE attribute marks instructions that may generate traps
+;; (which are imprecise and may need a trapb if software completion
+;; is desired).
-(define_function_unit "ebox" 1 0 (eq_attr "type" "iaddlog,shiftcm,icmp") 4 2)
+(define_attr "trap" "no,yes" (const_string "no"))
-;; These really don't take up the integer pipeline, but they do occupy
-;; IBOX1; we approximate here.
+;; The length of an instruction sequence in bytes.
-(define_function_unit "ebox" 1 0 (eq_attr "type" "imull") 42 2)
-(define_function_unit "ebox" 1 0 (eq_attr "type" "imulq") 46 2)
-
-(define_function_unit "imult" 1 0 (eq_attr "type" "imull") 42 38)
-(define_function_unit "imult" 1 0 (eq_attr "type" "imulq") 46 42)
-
-(define_function_unit "fbox" 1 0 (eq_attr "type" "fpop") 12 2)
-
-(define_function_unit "fbox" 1 0 (eq_attr "type" "fdivs") 68 0)
-(define_function_unit "fbox" 1 0 (eq_attr "type" "fdivt") 126 0)
+(define_attr "length" "" (const_int 4))
+
+;; On EV4 there are two classes of resources to consider: resources needed
+;; to issue, and resources needed to execute. IBUS[01] are in the first
+;; category. ABOX, BBOX, EBOX, FBOX, IMUL & FDIV make up the second.
+;; (There are a few other register-like resources, but ...)
+
+; First, describe all of the issue constraints with single cycle delays.
+; All insns need a bus, but all except loads require one or the other.
+(define_function_unit "ev4_ibus0" 1 0
+ (and (eq_attr "cpu" "ev4")
+ (eq_attr "type" "fst,fbr,iadd,imul,ilog,shift,icmov,icmp"))
+ 1 1)
+
+(define_function_unit "ev4_ibus1" 1 0
+ (and (eq_attr "cpu" "ev4")
+ (eq_attr "type" "ist,ibr,jsr,fadd,fcmov,fcpys,fmul,fdiv,misc"))
+ 1 1)
+
+; Memory delivers its result in three cycles. Actually return one and
+; take care of this in adjust_cost, since we want to handle user-defined
+; memory latencies.
+(define_function_unit "ev4_abox" 1 0
+ (and (eq_attr "cpu" "ev4")
+ (eq_attr "type" "ild,fld,ldsym,ist,fst"))
+ 1 1)
+
+; Branches have no delay cost, but do tie up the unit for two cycles.
+(define_function_unit "ev4_bbox" 1 1
+ (and (eq_attr "cpu" "ev4")
+ (eq_attr "type" "ibr,fbr,jsr"))
+ 2 2)
+
+; Arithmetic insns are normally have their results available after
+; two cycles. There are a number of exceptions. They are encoded in
+; ADJUST_COST. Some of the other insns have similar exceptions.
+(define_function_unit "ev4_ebox" 1 0
+ (and (eq_attr "cpu" "ev4")
+ (eq_attr "type" "iadd,ilog,shift,icmov,icmp,misc"))
+ 2 1)
+
+(define_function_unit "imul" 1 0
+ (and (eq_attr "cpu" "ev4")
+ (and (eq_attr "type" "imul")
+ (eq_attr "opsize" "si")))
+ 21 19)
+
+(define_function_unit "imul" 1 0
+ (and (eq_attr "cpu" "ev4")
+ (and (eq_attr "type" "imul")
+ (eq_attr "opsize" "!si")))
+ 23 21)
+
+(define_function_unit "ev4_fbox" 1 0
+ (and (eq_attr "cpu" "ev4")
+ (eq_attr "type" "fadd,fmul,fcpys,fcmov"))
+ 6 1)
+
+(define_function_unit "fdiv" 1 0
+ (and (eq_attr "cpu" "ev4")
+ (and (eq_attr "type" "fdiv")
+ (eq_attr "opsize" "si")))
+ 34 30)
+
+(define_function_unit "fdiv" 1 0
+ (and (eq_attr "cpu" "ev4")
+ (and (eq_attr "type" "fdiv")
+ (eq_attr "opsize" "di")))
+ 63 59)
+
+;; EV5 scheduling. EV5 can issue 4 insns per clock.
+;;
+;; EV5 has two asymetric integer units. Model this with E0 & E1 along
+;; with the combined resource EBOX.
+
+(define_function_unit "ev5_ebox" 2 0
+ (and (eq_attr "cpu" "ev5")
+ (eq_attr "type" "!fbr,fcmov,fadd,fmul,fcpys,fdiv"))
+ 1 1)
+
+; Memory takes at least 2 clocks. Return one from here and fix up with
+; user-defined latencies in adjust_cost.
+; ??? How to: "An instruction of class LD cannot be issued in the _second_
+; cycle after an instruction of class ST is issued."
+(define_function_unit "ev5_ebox" 2 0
+ (and (eq_attr "cpu" "ev5")
+ (eq_attr "type" "ild,fld,ldsym"))
+ 1 1)
+
+; Stores, shifts, multiplies can only issue to E0
+(define_function_unit "ev5_e0" 1 0
+ (and (eq_attr "cpu" "ev5")
+ (eq_attr "type" "ist,fst,shift,imul"))
+ 1 1)
+
+; Motion video insns also issue only to E0, and take two ticks.
+(define_function_unit "ev5_e0" 1 0
+ (and (eq_attr "cpu" "ev5")
+ (eq_attr "type" "mvi"))
+ 2 1)
+
+; Conditional moves always take 2 ticks.
+(define_function_unit "ev5_ebox" 2 0
+ (and (eq_attr "cpu" "ev5")
+ (eq_attr "type" "icmov"))
+ 2 1)
+
+; Branches can only issue to E1
+(define_function_unit "ev5_e1" 1 0
+ (and (eq_attr "cpu" "ev5")
+ (eq_attr "type" "ibr,jsr"))
+ 1 1)
+
+; Multiplies also use the integer multiplier.
+; ??? How to: "No instruction can be issued to pipe E0 exactly two
+; cycles before an integer multiplication completes."
+(define_function_unit "imul" 1 0
+ (and (eq_attr "cpu" "ev5")
+ (and (eq_attr "type" "imul")
+ (eq_attr "opsize" "si")))
+ 8 4)
+
+(define_function_unit "imul" 1 0
+ (and (eq_attr "cpu" "ev5")
+ (and (eq_attr "type" "imul")
+ (eq_attr "opsize" "di")))
+ 12 8)
+
+(define_function_unit "imul" 1 0
+ (and (eq_attr "cpu" "ev5")
+ (and (eq_attr "type" "imul")
+ (eq_attr "opsize" "udi")))
+ 14 8)
+
+;; Similarly for the FPU we have two asymetric units. But fcpys can issue
+;; on either so we have to play the game again.
+
+(define_function_unit "ev5_fbox" 2 0
+ (and (eq_attr "cpu" "ev5")
+ (eq_attr "type" "fadd,fcmov,fmul,fcpys,fbr,fdiv"))
+ 4 1)
+
+(define_function_unit "ev5_fm" 1 0
+ (and (eq_attr "cpu" "ev5")
+ (eq_attr "type" "fmul"))
+ 4 1)
+
+; Add and cmov as you would expect; fbr never produces a result;
+; fdiv issues through fa to the divider,
+(define_function_unit "ev5_fa" 1 0
+ (and (eq_attr "cpu" "ev5")
+ (eq_attr "type" "fadd,fcmov,fbr,fdiv"))
+ 4 1)
+
+; ??? How to: "No instruction can be issued to pipe FA exactly five
+; cycles before a floating point divide completes."
+(define_function_unit "fdiv" 1 0
+ (and (eq_attr "cpu" "ev5")
+ (and (eq_attr "type" "fdiv")
+ (eq_attr "opsize" "si")))
+ 15 15) ; 15 to 31 data dependant
+
+(define_function_unit "fdiv" 1 0
+ (and (eq_attr "cpu" "ev5")
+ (and (eq_attr "type" "fdiv")
+ (eq_attr "opsize" "di")))
+ 22 22) ; 22 to 60 data dependant
+
+;; EV6 scheduling. EV6 can issue 4 insns per clock.
+;;
+;; EV6 has two symmetric pairs ("clusters") of two asymetric integer units
+;; ("upper" and "lower"), yielding pipe names U0, U1, L0, L1.
+
+;; Conditional moves decompose into two independant primitives, each
+;; taking one cycle. Since ev6 is out-of-order, we can't see anything
+;; but two cycles.
+(define_function_unit "ev6_ebox" 4 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "icmov"))
+ 2 1)
+
+(define_function_unit "ev6_ebox" 4 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "!fbr,fcmov,fadd,fmul,fcpys,fdiv,fsqrt"))
+ 1 1)
+
+;; Integer loads take at least 3 clocks, and only issue to lower units.
+;; Return one from here and fix up with user-defined latencies in adjust_cost.
+(define_function_unit "ev6_l" 2 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "ild,ldsym,ist,fst"))
+ 1 1)
+
+;; FP loads take at least 4 clocks. Return two from here...
+(define_function_unit "ev6_l" 2 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "fld"))
+ 2 1)
+
+;; Motion video insns also issue only to U0, and take three ticks.
+(define_function_unit "ev6_u0" 1 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "mvi"))
+ 3 1)
+
+(define_function_unit "ev6_u" 2 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "mvi"))
+ 3 1)
+
+;; Shifts issue to either upper pipe.
+(define_function_unit "ev6_u" 2 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "shift"))
+ 1 1)
+
+;; Multiplies issue only to U1, and all take 7 ticks.
+;; Rather than create a new function unit just for U1, reuse IMUL
+(define_function_unit "imul" 1 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "imul"))
+ 7 1)
+
+(define_function_unit "ev6_u" 2 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "imul"))
+ 7 1)
+
+;; Branches issue to either upper pipe
+(define_function_unit "ev6_u" 2 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "ibr"))
+ 3 1)
+
+;; Calls only issue to L0.
+(define_function_unit "ev6_l0" 1 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "jsr"))
+ 1 1)
+
+(define_function_unit "ev6_l" 2 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "jsr"))
+ 1 1)
+
+;; Ftoi/itof only issue to lower pipes
+(define_function_unit "ev6_l" 2 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "ftoi"))
+ 3 1)
+
+(define_function_unit "ev6_l" 2 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "itof"))
+ 4 1)
+
+;; For the FPU we are very similar to EV5, except there's no insn that
+;; can issue to fm & fa, so we get to leave that out.
+
+(define_function_unit "ev6_fm" 1 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "fmul"))
+ 4 1)
+
+(define_function_unit "ev6_fa" 1 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "fadd,fcpys,fbr,fdiv,fsqrt"))
+ 4 1)
+
+(define_function_unit "ev6_fa" 1 0
+ (and (eq_attr "cpu" "ev6")
+ (eq_attr "type" "fcmov"))
+ 8 1)
+
+(define_function_unit "fdiv" 1 0
+ (and (eq_attr "cpu" "ev6")
+ (and (eq_attr "type" "fdiv")
+ (eq_attr "opsize" "si")))
+ 12 10)
+
+(define_function_unit "fdiv" 1 0
+ (and (eq_attr "cpu" "ev6")
+ (and (eq_attr "type" "fdiv")
+ (eq_attr "opsize" "di")))
+ 15 13)
+
+(define_function_unit "fsqrt" 1 0
+ (and (eq_attr "cpu" "ev6")
+ (and (eq_attr "type" "fsqrt")
+ (eq_attr "opsize" "si")))
+ 16 14)
+
+(define_function_unit "fsqrt" 1 0
+ (and (eq_attr "cpu" "ev6")
+ (and (eq_attr "type" "fsqrt")
+ (eq_attr "opsize" "di")))
+ 32 30)
+
+; ??? The FPU communicates with memory and the integer register file
+; via two fp store units. We need a slot in the fst immediately, and
+; a slot in LOW after the operand data is ready. At which point the
+; data may be moved either to the store queue or the integer register
+; file and the insn retired.
-(define_function_unit "divider" 1 0 (eq_attr "type" "fdivs") 68 60)
-(define_function_unit "divider" 1 0 (eq_attr "type" "fdivt") 126 118)
;; First define the arithmetic insns. Note that the 32-bit forms also
;; sign-extend.
-;; Note that we can do sign extensions in both FP and integer registers.
-;; However, the result must be in the same type of register as the input.
-;; The register preferencing code can't handle this case very well, so, for
-;; now, don't let the FP case show up here for preferencing. Also,
-;; sign-extends in FP registers take two instructions.
+;; Handle 32-64 bit extension from memory to a floating point register
+;; specially, since this ocurrs frequently in int->double conversions.
+;; This is done with a define_split after reload converting the plain
+;; sign-extension into a load+unspec, which of course results in lds+cvtlq.
+;;
+;; Note that while we must retain the =f case in the insn for reload's
+;; benefit, it should be eliminated after reload, so we should never emit
+;; code for that case. But we don't reject the possibility.
+
(define_insn "extendsidi2"
- [(set (match_operand:DI 0 "register_operand" "=r,r,*f")
- (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,*f")))]
+ [(set (match_operand:DI 0 "register_operand" "=r,r,?f")
+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "r,m,m")))]
""
"@
addl %1,$31,%0
ldl %0,%1
- cvtql %1,%0\;cvtlq %0,%0"
- [(set_attr "type" "iaddlog,ld,fpop")])
+ lds %0,%1\;cvtlq %0,%0"
+ [(set_attr "type" "iadd,ild,fld")
+ (set_attr "length" "*,*,8")])
+
+;; Due to issues with CLASS_CANNOT_CHANGE_SIZE, we cannot use a subreg here.
+(define_split
+ [(set (match_operand:DI 0 "hard_fp_register_operand" "")
+ (sign_extend:DI (match_operand:SI 1 "memory_operand" "")))]
+ "reload_completed"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (unspec:DI [(match_dup 2)] 4))]
+ "operands[2] = gen_rtx_REG (SImode, REGNO (operands[0]));")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=f")
+ (unspec:DI [(match_operand:SI 1 "register_operand" "f")] 4))]
+ ""
+ "cvtlq %1,%0"
+ [(set_attr "type" "fadd")])
;; Do addsi3 the way expand_binop would do if we didn't have one. This
;; generates better code. We have the anonymous addsi3 pattern below in
@@ -95,10 +420,10 @@
(match_operand:SI 2 "add_operand" "")))]
""
"
-{ emit_insn (gen_rtx (SET, VOIDmode, gen_lowpart (DImode, operands[0]),
- gen_rtx (PLUS, DImode,
- gen_lowpart (DImode, operands[1]),
- gen_lowpart (DImode, operands[2]))));
+{ emit_insn (gen_rtx_SET (VOIDmode, gen_lowpart (DImode, operands[0]),
+ gen_rtx_PLUS (DImode,
+ gen_lowpart (DImode, operands[1]),
+ gen_lowpart (DImode, operands[2]))));
DONE;
} ")
@@ -111,8 +436,7 @@
addl %r1,%2,%0
subl %r1,%n2,%0
lda %0,%2(%r1)
- ldah %0,%h2(%r1)"
- [(set_attr "type" "iaddlog")])
+ ldah %0,%h2(%r1)")
(define_split
[(set (match_operand:SI 0 "register_operand" "")
@@ -139,8 +463,7 @@
""
"@
addl %r1,%2,%0
- subl %r1,%n2,%0"
- [(set_attr "type" "iaddlog")])
+ subl %r1,%n2,%0")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -179,8 +502,8 @@
(set (match_dup 0) (sign_extend:DI (plus:SI (match_dup 7) (match_dup 4))))]
"
{
- operands[6] = gen_rtx (GET_CODE (operands[1]), DImode,
- operands[2], operands[3]);
+ operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]), DImode,
+ operands[2], operands[3]);
operands[7] = gen_lowpart (SImode, operands[5]);
}")
@@ -193,8 +516,7 @@
addq %r1,%2,%0
subq %r1,%n2,%0
lda %0,%2(%r1)
- ldah %0,%h2(%r1)"
- [(set_attr "type" "iaddlog")])
+ ldah %0,%h2(%r1)")
;; Don't do this if we are adjusting SP since we don't want to do
;; it in two steps.
@@ -224,8 +546,7 @@
""
"@
s%2addl %r1,%3,%0
- s%2subl %r1,%n3,%0"
- [(set_attr "type" "iaddlog")])
+ s%2subl %r1,%n3,%0")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r,r")
@@ -236,8 +557,7 @@
""
"@
s%2addl %r1,%3,%0
- s%2subl %r1,%n3,%0"
- [(set_attr "type" "iaddlog")])
+ s%2subl %r1,%n3,%0")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -255,8 +575,8 @@
(match_dup 5))))]
"
{
- operands[7] = gen_rtx (GET_CODE (operands[1]), DImode,
- operands[2], operands[3]);
+ operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[1]), DImode,
+ operands[2], operands[3]);
operands[8] = gen_lowpart (SImode, operands[6]);
}")
@@ -268,8 +588,7 @@
""
"@
s%2addq %r1,%3,%0
- s%2subq %1,%n3,%0"
- [(set_attr "type" "iaddlog")])
+ s%2subq %1,%n3,%0")
;; These variants of the above insns can occur if the third operand
;; is the frame pointer. This is a kludge, but there doesn't
@@ -281,8 +600,7 @@
(match_operand:DI 2 "some_operand" "r"))
(match_operand:DI 3 "some_operand" "rIOKL")))]
"reload_in_progress"
- "#"
- [(set_attr "type" "iaddlog")])
+ "#")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -301,8 +619,7 @@
(match_operand:SI 3 "some_operand" "r"))
(match_operand:SI 4 "some_operand" "rIOKL")))]
"reload_in_progress"
- "#"
- [(set_attr "type" "iaddlog")])
+ "#")
(define_split
[(set (match_operand:SI 0 "register_operand" "r")
@@ -325,8 +642,7 @@
(match_operand:SI 3 "some_operand" "r"))
(match_operand:SI 4 "some_operand" "rIOKL"))))]
"reload_in_progress"
- "#"
- [(set_attr "type" "iaddlog")])
+ "#")
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -351,8 +667,7 @@
(match_operand:DI 3 "some_operand" "r"))
(match_operand:DI 4 "some_operand" "rIOKL")))]
"reload_in_progress"
- "#"
- [(set_attr "type" "iaddlog")])
+ "#")
(define_split
[(set (match_operand:DI 0 "register_operand" "=")
@@ -370,23 +685,20 @@
[(set (match_operand:SI 0 "register_operand" "=r")
(neg:SI (match_operand:SI 1 "reg_or_8bit_operand" "rI")))]
""
- "subl $31,%1,%0"
- [(set_attr "type" "iaddlog")])
+ "subl $31,%1,%0")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI (neg:SI
(match_operand:SI 1 "reg_or_8bit_operand" "rI"))))]
""
- "subl $31,%1,%0"
- [(set_attr "type" "iaddlog")])
+ "subl $31,%1,%0")
(define_insn "negdi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(neg:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI")))]
""
- "subq $31,%1,%0"
- [(set_attr "type" "iaddlog")])
+ "subq $31,%1,%0")
(define_expand "subsi3"
[(set (match_operand:SI 0 "register_operand" "")
@@ -394,12 +706,11 @@
(match_operand:SI 2 "reg_or_8bit_operand" "")))]
""
"
-{ emit_insn (gen_rtx (SET, VOIDmode, gen_lowpart (DImode, operands[0]),
- gen_rtx (MINUS, DImode,
- gen_lowpart (DImode, operands[1]),
- gen_lowpart (DImode, operands[2]))));
+{ emit_insn (gen_rtx_SET (VOIDmode, gen_lowpart (DImode, operands[0]),
+ gen_rtx_MINUS (DImode,
+ gen_lowpart (DImode, operands[1]),
+ gen_lowpart (DImode, operands[2]))));
DONE;
-
} ")
(define_insn ""
@@ -407,24 +718,21 @@
(minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
(match_operand:SI 2 "reg_or_8bit_operand" "rI")))]
""
- "subl %r1,%2,%0"
- [(set_attr "type" "iaddlog")])
+ "subl %r1,%2,%0")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(sign_extend:DI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
(match_operand:SI 2 "reg_or_8bit_operand" "rI"))))]
""
- "subl %r1,%2,%0"
- [(set_attr "type" "iaddlog")])
+ "subl %r1,%2,%0")
(define_insn "subdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
(match_operand:DI 2 "reg_or_8bit_operand" "rI")))]
""
- "subq %r1,%2,%0"
- [(set_attr "type" "iaddlog")])
+ "subq %r1,%2,%0")
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
@@ -432,8 +740,7 @@
(match_operand:SI 2 "const48_operand" "I"))
(match_operand:SI 3 "reg_or_8bit_operand" "rI")))]
""
- "s%2subl %r1,%3,%0"
- [(set_attr "type" "iaddlog")])
+ "s%2subl %r1,%3,%0")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -442,8 +749,7 @@
(match_operand:SI 2 "const48_operand" "I"))
(match_operand:SI 3 "reg_or_8bit_operand" "rI"))))]
""
- "s%2subl %r1,%3,%0"
- [(set_attr "type" "iaddlog")])
+ "s%2subl %r1,%3,%0")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -451,8 +757,7 @@
(match_operand:DI 2 "const48_operand" "I"))
(match_operand:DI 3 "reg_or_8bit_operand" "rI")))]
""
- "s%2subq %r1,%3,%0"
- [(set_attr "type" "iaddlog")])
+ "s%2subq %r1,%3,%0")
(define_insn "mulsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
@@ -460,7 +765,8 @@
(match_operand:SI 2 "reg_or_0_operand" "rJ")))]
""
"mull %r1,%r2,%0"
- [(set_attr "type" "imull")])
+ [(set_attr "type" "imul")
+ (set_attr "opsize" "si")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -468,7 +774,8 @@
(match_operand:SI 2 "reg_or_0_operand" "rJ"))))]
""
"mull %r1,%r2,%0"
- [(set_attr "type" "imull")])
+ [(set_attr "type" "imul")
+ (set_attr "opsize" "si")])
(define_insn "muldi3"
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -476,7 +783,7 @@
(match_operand:DI 2 "reg_or_0_operand" "rJ")))]
""
"mulq %r1,%r2,%0"
- [(set_attr "type" "imulq")])
+ [(set_attr "type" "imul")])
(define_insn "umuldi3_highpart"
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -487,7 +794,8 @@
(const_int 64))))]
""
"umulh %1,%2,%0"
- [(set_attr "type" "imulq")])
+ [(set_attr "type" "imul")
+ (set_attr "opsize" "udi")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -498,61 +806,71 @@
(const_int 64))))]
""
"umulh %1,%2,%0"
- [(set_attr "type" "imulq")])
+ [(set_attr "type" "imul")
+ (set_attr "opsize" "udi")])
;; The divide and remainder operations always take their inputs from
;; r24 and r25, put their output in r27, and clobber r23 and r28.
+;; ??? Force sign-extension here because some versions of OSF/1 don't
+;; do the right thing if the inputs are not properly sign-extended.
+;; But Linux, for instance, does not have this problem. Is it worth
+;; the complication here to eliminate the sign extension?
+
(define_expand "divsi3"
- [(set (reg:SI 24) (match_operand:SI 1 "input_operand" ""))
- (set (reg:SI 25) (match_operand:SI 2 "input_operand" ""))
- (parallel [(set (reg:SI 27)
- (div:SI (reg:SI 24)
- (reg:SI 25)))
+ [(set (reg:DI 24)
+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
+ (set (reg:DI 25)
+ (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "")))
+ (parallel [(set (reg:DI 27)
+ (sign_extend:DI (div:SI (reg:DI 24) (reg:DI 25))))
(clobber (reg:DI 23))
(clobber (reg:DI 28))])
(set (match_operand:SI 0 "general_operand" "")
- (reg:SI 27))]
- ""
+ (subreg:SI (reg:DI 27) 0))]
+ "!TARGET_OPEN_VMS"
"")
(define_expand "udivsi3"
- [(set (reg:SI 24) (match_operand:SI 1 "input_operand" ""))
- (set (reg:SI 25) (match_operand:SI 2 "input_operand" ""))
- (parallel [(set (reg:SI 27)
- (udiv:SI (reg:SI 24)
- (reg:SI 25)))
+ [(set (reg:DI 24)
+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
+ (set (reg:DI 25)
+ (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "")))
+ (parallel [(set (reg:DI 27)
+ (sign_extend:DI (udiv:SI (reg:DI 24) (reg:DI 25))))
(clobber (reg:DI 23))
(clobber (reg:DI 28))])
(set (match_operand:SI 0 "general_operand" "")
- (reg:SI 27))]
- ""
+ (subreg:SI (reg:DI 27) 0))]
+ "!TARGET_OPEN_VMS"
"")
(define_expand "modsi3"
- [(set (reg:SI 24) (match_operand:SI 1 "input_operand" ""))
- (set (reg:SI 25) (match_operand:SI 2 "input_operand" ""))
- (parallel [(set (reg:SI 27)
- (mod:SI (reg:SI 24)
- (reg:SI 25)))
+ [(set (reg:DI 24)
+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
+ (set (reg:DI 25)
+ (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "")))
+ (parallel [(set (reg:DI 27)
+ (sign_extend:DI (mod:SI (reg:DI 24) (reg:DI 25))))
(clobber (reg:DI 23))
(clobber (reg:DI 28))])
(set (match_operand:SI 0 "general_operand" "")
- (reg:SI 27))]
- ""
+ (subreg:SI (reg:DI 27) 0))]
+ "!TARGET_OPEN_VMS"
"")
(define_expand "umodsi3"
- [(set (reg:SI 24) (match_operand:SI 1 "input_operand" ""))
- (set (reg:SI 25) (match_operand:SI 2 "input_operand" ""))
- (parallel [(set (reg:SI 27)
- (umod:SI (reg:SI 24)
- (reg:SI 25)))
+ [(set (reg:DI 24)
+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "")))
+ (set (reg:DI 25)
+ (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "")))
+ (parallel [(set (reg:DI 27)
+ (sign_extend:DI (umod:SI (reg:DI 24) (reg:DI 25))))
(clobber (reg:DI 23))
(clobber (reg:DI 28))])
(set (match_operand:SI 0 "general_operand" "")
- (reg:SI 27))]
- ""
+ (subreg:SI (reg:DI 27) 0))]
+ "!TARGET_OPEN_VMS"
"")
(define_expand "divdi3"
@@ -565,7 +883,7 @@
(clobber (reg:DI 28))])
(set (match_operand:DI 0 "general_operand" "")
(reg:DI 27))]
- ""
+ "!TARGET_OPEN_VMS"
"")
(define_expand "udivdi3"
@@ -578,7 +896,7 @@
(clobber (reg:DI 28))])
(set (match_operand:DI 0 "general_operand" "")
(reg:DI 27))]
- ""
+ "!TARGET_OPEN_VMS"
"")
(define_expand "moddi3"
@@ -591,7 +909,7 @@
(clobber (reg:DI 28))])
(set (match_operand:DI 0 "general_operand" "")
(reg:DI 27))]
- ""
+ "!TARGET_OPEN_VMS"
"")
(define_expand "umoddi3"
@@ -604,18 +922,21 @@
(clobber (reg:DI 28))])
(set (match_operand:DI 0 "general_operand" "")
(reg:DI 27))]
- ""
+ "!TARGET_OPEN_VMS"
"")
+;; Lengths of 8 for ldq $t12,__divq($gp); jsr $t9,($t12),__divq as
+;; expanded by the assembler.
(define_insn ""
- [(set (reg:SI 27)
- (match_operator:SI 1 "divmod_operator"
- [(reg:SI 24) (reg:SI 25)]))
+ [(set (reg:DI 27)
+ (sign_extend:DI (match_operator:SI 1 "divmod_operator"
+ [(reg:DI 24) (reg:DI 25)])))
(clobber (reg:DI 23))
(clobber (reg:DI 28))]
- ""
+ "!TARGET_OPEN_VMS"
"%E1 $24,$25,$27"
- [(set_attr "type" "isubr")])
+ [(set_attr "type" "jsr")
+ (set_attr "length" "8")])
(define_insn ""
[(set (reg:DI 27)
@@ -623,9 +944,10 @@
[(reg:DI 24) (reg:DI 25)]))
(clobber (reg:DI 23))
(clobber (reg:DI 28))]
- ""
+ "!TARGET_OPEN_VMS"
"%E1 $24,$25,$27"
- [(set_attr "type" "isubr")])
+ [(set_attr "type" "jsr")
+ (set_attr "length" "8")])
;; Next are the basic logical operations. These only exist in DImode.
@@ -638,12 +960,12 @@
and %r1,%2,%0
bic %r1,%N2,%0
zapnot %r1,%m2,%0"
- [(set_attr "type" "iaddlog,iaddlog,shiftcm")])
+ [(set_attr "type" "ilog,ilog,shift")])
-;; There are times when we can split and AND into two AND insns. This occurs
+;; There are times when we can split an AND into two AND insns. This occurs
;; when we can first clear any bytes and then clear anything else. For
;; example "I & 0xffff07" is "(I & 0xffffff) & 0xffffffffffffff07".
-;; Only to this when running on 64-bit host since the computations are
+;; Only do this when running on 64-bit host since the computations are
;; too messy otherwise.
(define_split
@@ -675,43 +997,103 @@
[(set (match_operand:HI 0 "register_operand" "=r")
(zero_extend:HI (match_operand:QI 1 "register_operand" "r")))]
""
- "zapnot %1,1,%0"
- [(set_attr "type" "iaddlog")])
+ "and %1,0xff,%0"
+ [(set_attr "type" "ilog")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ "TARGET_BWX"
+ "@
+ and %1,0xff,%0
+ ldbu %0,%1"
+ [(set_attr "type" "ilog,ild")])
-(define_insn "zero_extendqisi2"
+(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:QI 1 "register_operand" "r")))]
+ "! TARGET_BWX"
+ "and %1,0xff,%0"
+ [(set_attr "type" "ilog")])
+
+(define_expand "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:QI 1 "register_operand" "")))]
""
- "zapnot %1,1,%0"
- [(set_attr "type" "iaddlog")])
+ "")
-(define_insn "zero_extendqidi2"
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (zero_extend:DI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ "TARGET_BWX"
+ "@
+ and %1,0xff,%0
+ ldbu %0,%1"
+ [(set_attr "type" "ilog,ild")])
+
+(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (match_operand:QI 1 "register_operand" "r")))]
+ "! TARGET_BWX"
+ "and %1,0xff,%0"
+ [(set_attr "type" "ilog")])
+
+(define_expand "zero_extendqidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI (match_operand:QI 1 "register_operand" "")))]
""
- "zapnot %1,1,%0"
- [(set_attr "type" "iaddlog")])
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
+ "TARGET_BWX"
+ "@
+ zapnot %1,3,%0
+ ldwu %0,%1"
+ [(set_attr "type" "shift,ild")])
-(define_insn "zero_extendhisi2"
+(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(zero_extend:SI (match_operand:HI 1 "register_operand" "r")))]
- ""
+ "! TARGET_BWX"
"zapnot %1,3,%0"
- [(set_attr "type" "iaddlog")])
+ [(set_attr "type" "shift")])
+
+(define_expand "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:HI 1 "register_operand" "")))]
+ ""
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (zero_extend:DI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
+ "TARGET_BWX"
+ "@
+ zapnot %1,3,%0
+ ldwu %0,%1"
+ [(set_attr "type" "shift,ild")])
-(define_insn "zero_extendhidi2"
+(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (match_operand:HI 1 "register_operand" "r")))]
""
"zapnot %1,3,%0"
- [(set_attr "type" "iaddlog")])
+ [(set_attr "type" "shift")])
+
+(define_expand "zero_extendhidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI (match_operand:HI 1 "register_operand" "")))]
+ ""
+ "")
(define_insn "zero_extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (match_operand:SI 1 "register_operand" "r")))]
""
"zapnot %1,15,%0"
- [(set_attr "type" "iaddlog")])
+ [(set_attr "type" "shift")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -719,7 +1101,7 @@
(match_operand:DI 2 "reg_or_0_operand" "rJ")))]
""
"bic %r2,%1,%0"
- [(set_attr "type" "iaddlog")])
+ [(set_attr "type" "ilog")])
(define_insn "iordi3"
[(set (match_operand:DI 0 "register_operand" "=r,r")
@@ -729,14 +1111,14 @@
"@
bis %r1,%2,%0
ornot %r1,%N2,%0"
- [(set_attr "type" "iaddlog")])
+ [(set_attr "type" "ilog")])
(define_insn "one_cmpldi2"
[(set (match_operand:DI 0 "register_operand" "=r")
(not:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI")))]
""
"ornot $31,%1,%0"
- [(set_attr "type" "iaddlog")])
+ [(set_attr "type" "ilog")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -744,7 +1126,7 @@
(match_operand:DI 2 "reg_or_0_operand" "rJ")))]
""
"ornot %r2,%1,%0"
- [(set_attr "type" "iaddlog")])
+ [(set_attr "type" "ilog")])
(define_insn "xordi3"
[(set (match_operand:DI 0 "register_operand" "=r,r")
@@ -754,7 +1136,7 @@
"@
xor %r1,%2,%0
eqv %r1,%N2,%0"
- [(set_attr "type" "iaddlog")])
+ [(set_attr "type" "ilog")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -762,14 +1144,40 @@
(match_operand:DI 2 "register_operand" "rI"))))]
""
"eqv %r1,%2,%0"
- [(set_attr "type" "iaddlog")])
+ [(set_attr "type" "ilog")])
+
+;; Handle the FFS insn if we support CIX.
+
+(define_expand "ffsdi2"
+ [(set (match_dup 2)
+ (unspec [(match_operand:DI 1 "register_operand" "")] 1))
+ (set (match_dup 3)
+ (plus:DI (match_dup 2) (const_int 1)))
+ (set (match_operand:DI 0 "register_operand" "")
+ (if_then_else:DI (eq (match_dup 1) (const_int 0))
+ (const_int 0) (match_dup 3)))]
+ "TARGET_CIX"
+ "
+{
+ operands[2] = gen_reg_rtx (DImode);
+ operands[3] = gen_reg_rtx (DImode);
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec [(match_operand:DI 1 "register_operand" "r")] 1))]
+ "TARGET_CIX"
+ "cttz %1,%0"
+ ; ev6 calls all mvi and cttz/ctlz/popc class imisc, so just
+ ; reuse the existing type name.
+ [(set_attr "type" "mvi")])
;; Next come the shifts and the various extract and insert operations.
(define_insn "ashldi3"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(ashift:DI (match_operand:DI 1 "reg_or_0_operand" "rJ,rJ")
- (match_operand:DI 2 "reg_or_6bit_operand" "P,rI")))]
+ (match_operand:DI 2 "reg_or_6bit_operand" "P,rS")))]
""
"*
{
@@ -782,9 +1190,11 @@
return \"s%P2addq %r1,0,%0\";
case 1:
return \"sll %r1,%2,%0\";
+ default:
+ abort();
}
}"
- [(set_attr "type" "iaddlog,shiftcm")])
+ [(set_attr "type" "iadd,shift")])
;; ??? The following pattern is made by combine, but earlier phases
;; (specifically flow) can't handle it. This occurs in jump.c. Deal
@@ -803,224 +1213,469 @@
;; else
;; return \"s%P2addl %r1,0,%0\";
;; }"
-;; [(set_attr "type" "iaddlog")])
+;; [(set_attr "type" "iadd")])
(define_insn "lshrdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
- (match_operand:DI 2 "reg_or_6bit_operand" "rI")))]
+ (match_operand:DI 2 "reg_or_6bit_operand" "rS")))]
""
- "srl %r1,%2,%0")
+ "srl %r1,%2,%0"
+ [(set_attr "type" "shift")])
(define_insn "ashrdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
- (match_operand:DI 2 "reg_or_6bit_operand" "rI")))]
+ (match_operand:DI 2 "reg_or_6bit_operand" "rS")))]
""
- "sra %r1,%2,%0")
+ "sra %r1,%2,%0"
+ [(set_attr "type" "shift")])
(define_expand "extendqihi2"
[(set (match_dup 2)
- (ashift:DI (match_operand:QI 1 "register_operand" "")
+ (ashift:DI (match_operand:QI 1 "some_operand" "")
(const_int 56)))
(set (match_operand:HI 0 "register_operand" "")
(ashiftrt:DI (match_dup 2)
(const_int 56)))]
""
"
-{ operands[0] = gen_lowpart (DImode, operands[0]);
- operands[1] = gen_lowpart (DImode, operands[1]);
+{
+ if (TARGET_BWX)
+ {
+ emit_insn (gen_extendqihi2x (operands[0],
+ force_reg (QImode, operands[1])));
+ DONE;
+ }
+
+ /* If we have an unaligned MEM, extend to DImode (which we do
+ specially) and then copy to the result. */
+ if (unaligned_memory_operand (operands[1], HImode))
+ {
+ rtx temp = gen_reg_rtx (DImode);
+
+ emit_insn (gen_extendqidi2 (temp, operands[1]));
+ emit_move_insn (operands[0], gen_lowpart (HImode, temp));
+ DONE;
+ }
+
+ operands[0] = gen_lowpart (DImode, operands[0]);
+ operands[1] = gen_lowpart (DImode, force_reg (QImode, operands[1]));
operands[2] = gen_reg_rtx (DImode);
}")
+(define_insn "extendqidi2x"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (match_operand:QI 1 "register_operand" "r")))]
+ "TARGET_BWX"
+ "sextb %1,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "extendhidi2x"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (match_operand:HI 1 "register_operand" "r")))]
+ "TARGET_BWX"
+ "sextw %1,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "extendqisi2x"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))]
+ "TARGET_BWX"
+ "sextb %1,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "extendhisi2x"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))]
+ "TARGET_BWX"
+ "sextw %1,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "extendqihi2x"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))]
+ "TARGET_BWX"
+ "sextb %1,%0"
+ [(set_attr "type" "shift")])
+
(define_expand "extendqisi2"
[(set (match_dup 2)
- (ashift:DI (match_operand:QI 1 "register_operand" "")
+ (ashift:DI (match_operand:QI 1 "some_operand" "")
(const_int 56)))
(set (match_operand:SI 0 "register_operand" "")
(ashiftrt:DI (match_dup 2)
(const_int 56)))]
""
"
-{ operands[0] = gen_lowpart (DImode, operands[0]);
- operands[1] = gen_lowpart (DImode, operands[1]);
+{
+ if (TARGET_BWX)
+ {
+ emit_insn (gen_extendqisi2x (operands[0],
+ force_reg (QImode, operands[1])));
+ DONE;
+ }
+
+ /* If we have an unaligned MEM, extend to a DImode form of
+ the result (which we do specially). */
+ if (unaligned_memory_operand (operands[1], QImode))
+ {
+ rtx temp = gen_reg_rtx (DImode);
+
+ emit_insn (gen_extendqidi2 (temp, operands[1]));
+ emit_move_insn (operands[0], gen_lowpart (SImode, temp));
+ DONE;
+ }
+
+ operands[0] = gen_lowpart (DImode, operands[0]);
+ operands[1] = gen_lowpart (DImode, force_reg (QImode, operands[1]));
operands[2] = gen_reg_rtx (DImode);
}")
(define_expand "extendqidi2"
[(set (match_dup 2)
- (ashift:DI (match_operand:QI 1 "register_operand" "")
+ (ashift:DI (match_operand:QI 1 "some_operand" "")
(const_int 56)))
(set (match_operand:DI 0 "register_operand" "")
(ashiftrt:DI (match_dup 2)
(const_int 56)))]
""
"
-{ operands[1] = gen_lowpart (DImode, operands[1]);
+{
+ if (TARGET_BWX)
+ {
+ emit_insn (gen_extendqidi2x (operands[0],
+ force_reg (QImode, operands[1])));
+ DONE;
+ }
+
+ if (unaligned_memory_operand (operands[1], QImode))
+ {
+ rtx seq
+ = gen_unaligned_extendqidi (operands[0],
+ get_unaligned_address (operands[1], 1));
+
+ alpha_set_memflags (seq, operands[1]);
+ emit_insn (seq);
+ DONE;
+ }
+
+ operands[1] = gen_lowpart (DImode, force_reg (QImode, operands[1]));
operands[2] = gen_reg_rtx (DImode);
}")
(define_expand "extendhisi2"
[(set (match_dup 2)
- (ashift:DI (match_operand:HI 1 "register_operand" "")
+ (ashift:DI (match_operand:HI 1 "some_operand" "")
(const_int 48)))
(set (match_operand:SI 0 "register_operand" "")
(ashiftrt:DI (match_dup 2)
(const_int 48)))]
""
"
-{ operands[0] = gen_lowpart (DImode, operands[0]);
- operands[1] = gen_lowpart (DImode, operands[1]);
+{
+ if (TARGET_BWX)
+ {
+ emit_insn (gen_extendhisi2x (operands[0],
+ force_reg (HImode, operands[1])));
+ DONE;
+ }
+
+ /* If we have an unaligned MEM, extend to a DImode form of
+ the result (which we do specially). */
+ if (unaligned_memory_operand (operands[1], HImode))
+ {
+ rtx temp = gen_reg_rtx (DImode);
+
+ emit_insn (gen_extendhidi2 (temp, operands[1]));
+ emit_move_insn (operands[0], gen_lowpart (SImode, temp));
+ DONE;
+ }
+
+ operands[0] = gen_lowpart (DImode, operands[0]);
+ operands[1] = gen_lowpart (DImode, force_reg (HImode, operands[1]));
operands[2] = gen_reg_rtx (DImode);
}")
(define_expand "extendhidi2"
[(set (match_dup 2)
- (ashift:DI (match_operand:HI 1 "register_operand" "")
+ (ashift:DI (match_operand:HI 1 "some_operand" "")
(const_int 48)))
(set (match_operand:DI 0 "register_operand" "")
(ashiftrt:DI (match_dup 2)
(const_int 48)))]
""
"
-{ operands[1] = gen_lowpart (DImode, operands[1]);
+{
+ if (TARGET_BWX)
+ {
+ emit_insn (gen_extendhidi2x (operands[0],
+ force_reg (HImode, operands[1])));
+ DONE;
+ }
+
+ if (unaligned_memory_operand (operands[1], HImode))
+ {
+ rtx seq
+ = gen_unaligned_extendhidi (operands[0],
+ get_unaligned_address (operands[1], 2));
+
+ alpha_set_memflags (seq, operands[1]);
+ emit_insn (seq);
+ DONE;
+ }
+
+ operands[1] = gen_lowpart (DImode, force_reg (HImode, operands[1]));
operands[2] = gen_reg_rtx (DImode);
}")
+;; Here's how we sign extend an unaligned byte and halfword. Doing this
+;; as a pattern saves one instruction. The code is similar to that for
+;; the unaligned loads (see below).
+;;
+;; Operand 1 is the address + 1 (+2 for HI), operand 0 is the result.
+(define_expand "unaligned_extendqidi"
+ [(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
+ (set (match_dup 3)
+ (mem:DI (and:DI (plus:DI (match_dup 2) (const_int -1))
+ (const_int -8))))
+ (set (match_dup 4)
+ (ashift:DI (match_dup 3)
+ (minus:DI (const_int 56)
+ (ashift:DI
+ (and:DI (plus:DI (match_dup 2) (const_int -1))
+ (const_int 7))
+ (const_int 3)))))
+ (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+ (ashiftrt:DI (match_dup 4) (const_int 56)))]
+ ""
+ "
+{ operands[2] = gen_reg_rtx (DImode);
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (DImode);
+}")
+
+(define_expand "unaligned_extendhidi"
+ [(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
+ (set (match_dup 3)
+ (mem:DI (and:DI (plus:DI (match_dup 2) (const_int -2))
+ (const_int -8))))
+ (set (match_dup 4)
+ (ashift:DI (match_dup 3)
+ (minus:DI (const_int 56)
+ (ashift:DI
+ (and:DI (plus:DI (match_dup 2) (const_int -1))
+ (const_int 7))
+ (const_int 3)))))
+ (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+ (ashiftrt:DI (match_dup 4) (const_int 48)))]
+ ""
+ "
+{ operands[2] = gen_reg_rtx (DImode);
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (DImode);
+}")
+
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
(match_operand:DI 2 "mode_width_operand" "n")
(match_operand:DI 3 "mul8_operand" "I")))]
""
- "ext%M2l %r1,%s3,%0")
+ "ext%M2l %r1,%s3,%0"
+ [(set_attr "type" "shift")])
-(define_insn ""
+(define_insn "extxl"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
(match_operand:DI 2 "mode_width_operand" "n")
(ashift:DI (match_operand:DI 3 "reg_or_8bit_operand" "rI")
(const_int 3))))]
""
- "ext%M2l %r1,%3,%0")
+ "ext%M2l %r1,%3,%0"
+ [(set_attr "type" "shift")])
-(define_insn ""
+(define_insn "extqh"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI
- (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
- (const_int 8)
- (ashift:DI
- (plus:DI
- (match_operand:DI 2 "reg_or_8bit_operand" "rI")
- (const_int -1))
- (const_int 3)))
- (const_int 56)))]
- ""
- "extqh %r1,%2,%0")
-
-(define_insn ""
+ (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (minus:DI (const_int 56)
+ (ashift:DI
+ (and:DI
+ (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int -1))
+ (const_int 7))
+ (const_int 3)))))]
+ ""
+ "extqh %r1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "extlh"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI
- (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
- (const_int 16)
- (ashift:DI
- (plus:DI
- (match_operand:DI 2 "reg_or_8bit_operand" "rI")
- (const_int -2))
- (const_int 3)))
- (const_int 48)))]
- ""
- "extwh %r1,%2,%0")
-
-(define_insn ""
+ (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (const_int 2147483647))
+ (minus:DI (const_int 56)
+ (ashift:DI
+ (and:DI
+ (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int -1))
+ (const_int 7))
+ (const_int 3)))))]
+ ""
+ "extlh %r1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "extwh"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI
- (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
- (const_int 32)
- (ashift:DI
- (plus:DI
- (match_operand:DI 2 "reg_or_8bit_operand" "rI")
- (const_int -4))
- (const_int 3)))
- (const_int 32)))]
- ""
- "extlh %r1,%2,%0")
+ (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (const_int 65535))
+ (minus:DI (const_int 56)
+ (ashift:DI
+ (and:DI
+ (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int -1))
+ (const_int 7))
+ (const_int 3)))))]
+ ""
+ "extwh %r1,%2,%0"
+ [(set_attr "type" "shift")])
;; This converts an extXl into an extXh with an appropriate adjustment
;; to the address calculation.
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (ashift:DI (zero_extract:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:DI 2 "mode_width_operand" "")
- (ashift:DI (match_operand:DI 3 "" "")
- (const_int 3)))
- (match_operand:DI 4 "const_int_operand" "")))
- (clobber (match_operand:DI 5 "register_operand" ""))]
- "INTVAL (operands[4]) == 64 - INTVAL (operands[2])"
- [(set (match_dup 5) (match_dup 6))
- (set (match_dup 0)
- (ashift:DI (zero_extract:DI (match_dup 1) (match_dup 2)
- (ashift:DI (plus:DI (match_dup 5)
- (match_dup 7))
- (const_int 3)))
- (match_dup 4)))]
- "
-{
- operands[6] = plus_constant (operands[3],
- INTVAL (operands[2]) / BITS_PER_UNIT);
- operands[7] = GEN_INT (- INTVAL (operands[2]) / BITS_PER_UNIT);
-}")
+;;(define_split
+;; [(set (match_operand:DI 0 "register_operand" "")
+;; (ashift:DI (zero_extract:DI (match_operand:DI 1 "register_operand" "")
+;; (match_operand:DI 2 "mode_width_operand" "")
+;; (ashift:DI (match_operand:DI 3 "" "")
+;; (const_int 3)))
+;; (match_operand:DI 4 "const_int_operand" "")))
+;; (clobber (match_operand:DI 5 "register_operand" ""))]
+;; "INTVAL (operands[4]) == 64 - INTVAL (operands[2])"
+;; [(set (match_dup 5) (match_dup 6))
+;; (set (match_dup 0)
+;; (ashift:DI (zero_extract:DI (match_dup 1) (match_dup 2)
+;; (ashift:DI (plus:DI (match_dup 5)
+;; (match_dup 7))
+;; (const_int 3)))
+;; (match_dup 4)))]
+;; "
+;;{
+;; operands[6] = plus_constant (operands[3],
+;; INTVAL (operands[2]) / BITS_PER_UNIT);
+;; operands[7] = GEN_INT (- INTVAL (operands[2]) / BITS_PER_UNIT);
+;;}")
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r"))
(match_operand:DI 2 "mul8_operand" "I")))]
""
- "insbl %1,%s2,%0")
+ "insbl %1,%s2,%0"
+ [(set_attr "type" "shift")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r"))
(match_operand:DI 2 "mul8_operand" "I")))]
""
- "inswl %1,%s2,%0")
+ "inswl %1,%s2,%0"
+ [(set_attr "type" "shift")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
(match_operand:DI 2 "mul8_operand" "I")))]
""
- "insll %1,%s2,%0")
+ "insll %1,%s2,%0"
+ [(set_attr "type" "shift")])
-(define_insn ""
+(define_insn "insbl"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r"))
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 3))))]
""
- "insbl %1,%2,%0")
+ "insbl %1,%2,%0"
+ [(set_attr "type" "shift")])
-(define_insn ""
+(define_insn "inswl"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r"))
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 3))))]
""
- "inswl %1,%2,%0")
+ "inswl %1,%2,%0"
+ [(set_attr "type" "shift")])
-(define_insn ""
+(define_insn "insll"
[(set (match_operand:DI 0 "register_operand" "=r")
(ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
(ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
(const_int 3))))]
""
- "insll %1,%2,%0")
+ "insll %1,%2,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "insql"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (match_operand:DI 1 "register_operand" "r")
+ (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (const_int 3))))]
+ ""
+ "insql %1,%2,%0"
+ [(set_attr "type" "shift")])
+
+;; Combine has this sometimes habit of moving the and outside of the
+;; shift, making life more interesting.
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI (ashift:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "mul8_operand" "I"))
+ (match_operand:DI 3 "immediate_operand" "i")))]
+ "HOST_BITS_PER_WIDE_INT == 64
+ && GET_CODE (operands[3]) == CONST_INT
+ && (((unsigned HOST_WIDE_INT) 0xff << INTVAL (operands[2])
+ == INTVAL (operands[3]))
+ || ((unsigned HOST_WIDE_INT) 0xffff << INTVAL (operands[2])
+ == INTVAL (operands[3]))
+ || ((unsigned HOST_WIDE_INT) 0xffffffff << INTVAL (operands[2])
+ == INTVAL (operands[3])))"
+ "*
+{
+#if HOST_BITS_PER_WIDE_INT == 64
+ if ((unsigned HOST_WIDE_INT) 0xff << INTVAL (operands[2])
+ == INTVAL (operands[3]))
+ return \"insbl %1,%s2,%0\";
+ if ((unsigned HOST_WIDE_INT) 0xffff << INTVAL (operands[2])
+ == INTVAL (operands[3]))
+ return \"inswl %1,%s2,%0\";
+ if ((unsigned HOST_WIDE_INT) 0xffffffff << INTVAL (operands[2])
+ == INTVAL (operands[3]))
+ return \"insll %1,%s2,%0\";
+#endif
+ abort();
+}"
+ [(set_attr "type" "shift")])
;; We do not include the insXh insns because they are complex to express
;; and it does not appear that we would ever want to generate them.
+;;
+;; Since we need them for block moves, though, cop out and use unspec.
-(define_insn ""
+(define_insn "insxh"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec [(match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "mode_width_operand" "n")
+ (match_operand:DI 3 "reg_or_8bit_operand" "rI")] 2))]
+ ""
+ "ins%M2h %1,%3,%0"
+ [(set_attr "type" "shift")])
+
+(define_insn "mskxl"
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (not:DI (ashift:DI
(match_operand:DI 2 "mode_mask_operand" "n")
@@ -1029,10 +1684,22 @@
(const_int 3))))
(match_operand:DI 1 "reg_or_0_operand" "rJ")))]
""
- "msk%U2l %r1,%3,%0")
+ "msk%U2l %r1,%3,%0"
+ [(set_attr "type" "shift")])
-;; We do not include the mskXh insns because it does not appear we would ever
-;; generate one.
+;; We do not include the mskXh insns because it does not appear we would
+;; ever generate one.
+;;
+;; Again, we do for block moves and we use unspec again.
+
+(define_insn "mskxh"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (unspec [(match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "mode_width_operand" "n")
+ (match_operand:DI 3 "reg_or_8bit_operand" "rI")] 3))]
+ ""
+ "msk%M2h %1,%3,%0"
+ [(set_attr "type" "shift")])
;; Floating-point operations. All the double-precision insns can extend
;; from single, so indicate that. The exception are the ones that simply
@@ -1043,53 +1710,74 @@
(abs:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
"cpys $f31,%R1,%0"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fcpys")])
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(abs:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
"cpys $f31,%R1,%0"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fcpys")])
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(neg:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
"cpysn %R1,%R1,%0"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fadd")])
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(neg:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
"cpysn %R1,%R1,%0"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fadd")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=&f")
+ (plus:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG")
+ (match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "add%,%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn "addsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(plus:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "adds %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "add%,%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (plus:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG")
+ (match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "add%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn "adddf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(plus:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "addt %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "add%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(plus:DF (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP"
- "addt %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "add%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -1097,120 +1785,344 @@
(match_operand:SF 1 "reg_or_fp0_operand" "%fG"))
(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "add%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+;; Define conversion operators between DFmode and SImode, using the cvtql
+;; instruction. To allow combine et al to do useful things, we keep the
+;; operation as a unit until after reload, at which point we split the
+;; instructions.
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (fix:SI (match_operand:DF 1 "reg_or_fp0_operand" "")))
+ (clobber (match_scratch:DI 2 ""))]
+ "TARGET_FP && reload_completed"
+ [(set (match_dup 2) (fix:DI (match_dup 1)))
+ (set (match_dup 0) (unspec:SI [(match_dup 2)] 5))]
+ "")
+
+;; Due to issues with CLASS_CANNOT_CHANGE_SIZE, we cannot use a subreg here.
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (fix:SI (match_operand:DF 1 "reg_or_fp0_operand" "")))]
+ "TARGET_FP && reload_completed"
+ [(set (match_dup 2) (fix:DI (match_dup 1)))
+ (set (match_dup 0) (unspec:SI [(match_dup 2)] 5))]
+ "operands[2] = gen_rtx_REG (DImode, REGNO (operands[0]));")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (unspec:SI [(match_operand:DI 1 "reg_or_fp0_operand" "fG")] 5))]
"TARGET_FP"
- "addt %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "cvtql%` %R1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn "fix_truncdfsi2_tp"
+ [(set (match_operand:SI 0 "register_operand" "=&f")
+ (fix:SI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))
+ (clobber (match_scratch:DI 2 "=&f"))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "#"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (fix:SI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "#"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_expand "fix_truncdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (fix:SI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP"
+ "{ if (alpha_tp == ALPHA_TP_INSN)
+ { emit_insn(gen_fix_truncdfsi2_tp(operands[0], operands[1])); DONE; }
+ }")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=&f")
+ (fix:DI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "cvt%-q%(c %R1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn "fix_truncdfdi2"
[(set (match_operand:DI 0 "register_operand" "=f")
(fix:DI (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "cvttqc %R1,%0"
- [(set_attr "type" "fpop")])
+ "cvt%-q%(c %R1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+;; Likewise between SFmode and SImode.
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (fix:SI (float_extend:DF
+ (match_operand:SF 1 "reg_or_fp0_operand" ""))))
+ (clobber (match_scratch:DI 2 ""))]
+ "TARGET_FP && reload_completed"
+ [(set (match_dup 2) (fix:DI (float_extend:DF (match_dup 1))))
+ (set (match_dup 0) (unspec:SI [(match_dup 2)] 5))]
+ "")
+
+;; Due to issues with CLASS_CANNOT_CHANGE_SIZE, we cannot use a subreg here.
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (fix:SI (float_extend:DF
+ (match_operand:SF 1 "reg_or_fp0_operand" ""))))]
+ "TARGET_FP && reload_completed"
+ [(set (match_dup 2) (fix:DI (float_extend:DF (match_dup 1))))
+ (set (match_dup 0) (unspec:SI [(match_dup 2)] 5))]
+ "operands[2] = gen_rtx_REG (DImode, REGNO (operands[0]));")
+
+(define_insn "fix_truncsfsi2_tp"
+ [(set (match_operand:SI 0 "register_operand" "=&f")
+ (fix:SI (float_extend:DF
+ (match_operand:SF 1 "reg_or_fp0_operand" "fG"))))
+ (clobber (match_scratch:DI 2 "=&f"))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "#"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (fix:SI (float_extend:DF
+ (match_operand:SF 1 "reg_or_fp0_operand" "fG"))))]
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "#"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_expand "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (fix:SI (float_extend:DF
+ (match_operand:SF 1 "reg_or_fp0_operand" "fG"))))]
+ "TARGET_FP"
+ "{ if (alpha_tp == ALPHA_TP_INSN)
+ { emit_insn(gen_fix_truncsfsi2_tp(operands[0], operands[1])); DONE; }
+ }")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=&f")
+ (fix:DI (float_extend:DF
+ (match_operand:SF 1 "reg_or_fp0_operand" "fG"))))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "cvt%-q%(c %R1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn "fix_truncsfdi2"
[(set (match_operand:DI 0 "register_operand" "=f")
(fix:DI (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))))]
"TARGET_FP"
- "cvttqc %R1,%0"
- [(set_attr "type" "fpop")])
+ "cvt%-q%(c %R1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=&f")
+ (float:SF (match_operand:DI 1 "register_operand" "f")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "cvtq%,%+%& %1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn "floatdisf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float:SF (match_operand:DI 1 "register_operand" "f")))]
"TARGET_FP"
- "cvtqs %1,%0"
- [(set_attr "type" "fpop")])
+ "cvtq%,%+%& %1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (float:DF (match_operand:DI 1 "register_operand" "f")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "cvtq%-%+%& %1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn "floatdidf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(float:DF (match_operand:DI 1 "register_operand" "f")))]
"TARGET_FP"
- "cvtqt %1,%0"
- [(set_attr "type" "fpop")])
+ "cvtq%-%+%& %1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
-(define_insn "extendsfdf2"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,m")))]
+(define_expand "extendsfdf2"
+ [(use (match_operand:DF 0 "register_operand" ""))
+ (use (match_operand:SF 1 "nonimmediate_operand" ""))]
"TARGET_FP"
+"
+{
+ if (alpha_tp == ALPHA_TP_INSN)
+ emit_insn (gen_extendsfdf2_tp (operands[0],
+ force_reg (SFmode, operands[1])));
+ else
+ emit_insn (gen_extendsfdf2_no_tp (operands[0], operands[1]));
+
+ DONE;
+}")
+;; FIXME
+(define_insn "extendsfdf2_tp"
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "cvtsts %1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn "extendsfdf2_no_tp"
+ [(set (match_operand:DF 0 "register_operand" "=f,f,m")
+ (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,m,f")))]
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
"@
- addt $f31,%1,%0
- lds %0,%1"
- [(set_attr "type" "fpop,ld")])
+ cpys %1,%1,%0
+ ld%, %0,%1
+ st%- %1,%0"
+ [(set_attr "type" "fcpys,fld,fst")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=&f")
+ (float_truncate:SF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "cvt%-%,%)%& %R1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(float_truncate:SF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "cvtts %R1,%0"
- [(set_attr "type" "fpop")])
+ "cvt%-%,%)%& %R1,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=&f")
+ (div:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")
+ (match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "div%,%)%& %R1,%R2,%0"
+ [(set_attr "type" "fdiv")
+ (set_attr "opsize" "si")
+ (set_attr "trap" "yes")])
(define_insn "divsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(div:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "divs %R1,%R2,%0"
- [(set_attr "type" "fdivs")])
+ "div%,%)%& %R1,%R2,%0"
+ [(set_attr "type" "fdiv")
+ (set_attr "opsize" "si")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (div:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
+ (match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "div%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fdiv")
+ (set_attr "trap" "yes")])
(define_insn "divdf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "divt %R1,%R2,%0"
- [(set_attr "type" "fdivt")])
+ "div%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fdiv")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP"
- "divt %R1,%R2,%0"
- [(set_attr "type" "fdivt")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "div%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fdiv")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP"
- "divt %R1,%R2,%0"
- [(set_attr "type" "fdivt")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "div%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fdiv")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(div:DF (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(float_extend:DF (match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP"
- "divt %R1,%R2,%0"
- [(set_attr "type" "fdivt")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "div%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fdiv")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=&f")
+ (mult:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG")
+ (match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "mul%,%)%& %R1,%R2,%0"
+ [(set_attr "type" "fmul")
+ (set_attr "trap" "yes")])
(define_insn "mulsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(mult:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "muls %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "mul%,%)%& %R1,%R2,%0"
+ [(set_attr "type" "fmul")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (mult:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG")
+ (match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "mul%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fmul")
+ (set_attr "trap" "yes")])
(define_insn "muldf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(mult:DF (match_operand:DF 1 "reg_or_fp0_operand" "%fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "mult %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "mul%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fmul")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(mult:DF (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP"
- "mult %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "mul%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fmul")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -1218,43 +2130,66 @@
(match_operand:SF 1 "reg_or_fp0_operand" "%fG"))
(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP"
- "mult %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "mul%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fmul")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=&f")
+ (minus:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")
+ (match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "sub%,%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn "subsf3"
[(set (match_operand:SF 0 "register_operand" "=f")
(minus:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")
(match_operand:SF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "subs %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "sub%,%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (minus:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
+ (match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "sub%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn "subdf3"
[(set (match_operand:DF 0 "register_operand" "=f")
(minus:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
"TARGET_FP"
- "subt %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "sub%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(minus:DF (float_extend:DF
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(match_operand:DF 2 "reg_or_fp0_operand" "fG")))]
- "TARGET_FP"
- "subt %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "sub%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(minus:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")
(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP"
- "subt %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "sub%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -1262,9 +2197,44 @@
(match_operand:SF 1 "reg_or_fp0_operand" "fG"))
(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))))]
- "TARGET_FP"
- "subt %R1,%R2,%0"
- [(set_attr "type" "fpop")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "sub%-%)%& %R1,%R2,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=&f")
+ (sqrt:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && TARGET_CIX && alpha_tp == ALPHA_TP_INSN"
+ "sqrt%,%)%& %R1,%0"
+ [(set_attr "type" "fsqrt")
+ (set_attr "opsize" "si")
+ (set_attr "trap" "yes")])
+
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (sqrt:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && TARGET_CIX"
+ "sqrt%,%)%& %R1,%0"
+ [(set_attr "type" "fsqrt")
+ (set_attr "opsize" "si")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (sqrt:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && TARGET_CIX && alpha_tp == ALPHA_TP_INSN"
+ "sqrt%-%)%& %R1,%0"
+ [(set_attr "type" "fsqrt")
+ (set_attr "trap" "yes")])
+
+(define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "register_operand" "=f")
+ (sqrt:DF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
+ "TARGET_FP && TARGET_CIX"
+ "sqrt%-%)%& %1,%0"
+ [(set_attr "type" "fsqrt")
+ (set_attr "trap" "yes")])
;; Next are all the integer comparisons, and conditional moves and branches
;; and some of the related define_expand's and define_split's.
@@ -1278,31 +2248,13 @@
"cmp%C1 %r2,%3,%0"
[(set_attr "type" "icmp")])
-;; There are three important special-case that don't fit the above pattern
-;; but which we want to handle here.
-
-(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=r")
- (ne:DI (match_operand:DI 1 "register_operand" "r")
- (const_int 0)))]
- ""
- "cmpult $31,%1,%0"
- [(set_attr "type" "icmp")])
-
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r")
- (gt:DI (match_operand:DI 1 "register_operand" "r")
- (const_int 0)))]
+ (match_operator:DI 1 "alpha_swapped_comparison_operator"
+ [(match_operand:DI 2 "reg_or_8bit_operand" "rI")
+ (match_operand:DI 3 "reg_or_0_operand" "rJ")]))]
""
- "cmplt $31,%1,%0"
- [(set_attr "type" "icmp")])
-
-(define_insn ""
- [(set (match_operand:DI 0 "register_operand" "=r")
- (ge:DI (match_operand:DI 1 "register_operand" "r")
- (const_int 0)))]
- ""
- "cmple $31,%1,%0"
+ "cmp%c1 %r3,%2,%0"
[(set_attr "type" "icmp")])
;; This pattern exists so conditional moves of SImode values are handled.
@@ -1321,7 +2273,8 @@
cmov%C2 %r3,%1,%0
cmov%D2 %r3,%5,%0
cmov%c2 %r4,%1,%0
- cmov%d2 %r4,%5,%0")
+ cmov%d2 %r4,%5,%0"
+ [(set_attr "type" "icmov")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
@@ -1336,7 +2289,8 @@
cmov%C2 %r3,%1,%0
cmov%D2 %r3,%5,%0
cmov%c2 %r4,%1,%0
- cmov%d2 %r4,%5,%0")
+ cmov%d2 %r4,%5,%0"
+ [(set_attr "type" "icmov")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r,r")
@@ -1350,7 +2304,8 @@
""
"@
cmovlbc %r2,%1,%0
- cmovlbs %r2,%3,%0")
+ cmovlbs %r2,%3,%0"
+ [(set_attr "type" "icmov")])
(define_insn ""
[(set (match_operand:DI 0 "register_operand" "=r,r")
@@ -1364,7 +2319,8 @@
""
"@
cmovlbs %r2,%1,%0
- cmovlbc %r2,%3,%0")
+ cmovlbc %r2,%3,%0"
+ [(set_attr "type" "icmov")])
;; This form is added since combine thinks that an IF_THEN_ELSE with both
;; arms constant is a single insn, so it won't try to form it if combine
@@ -1382,7 +2338,9 @@
(match_dup 0)))
(clobber (match_scratch:DI 4 "=&r"))]
""
- "addq %0,%1,%4\;cmov%C2 %r3,%4,%0")
+ "addq %0,%1,%4\;cmov%C2 %r3,%4,%0"
+ [(set_attr "type" "icmov")
+ (set_attr "length" "8")])
(define_split
[(set (match_operand:DI 0 "register_operand" "")
@@ -1500,6 +2458,70 @@
(match_dup 0) (match_dup 1)))]
"")
+(define_insn "sminqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (smin:SI (match_operand:QI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:QI 2 "reg_or_8bit_operand" "rI")))]
+ "TARGET_MAX"
+ "minsb8 %r1,%2,%0"
+ [(set_attr "type" "mvi")])
+
+(define_insn "uminqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (umin:SI (match_operand:QI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:QI 2 "reg_or_8bit_operand" "rI")))]
+ "TARGET_MAX"
+ "minub8 %r1,%2,%0"
+ [(set_attr "type" "mvi")])
+
+(define_insn "smaxqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (smax:SI (match_operand:QI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:QI 2 "reg_or_8bit_operand" "rI")))]
+ "TARGET_MAX"
+ "maxsb8 %r1,%2,%0"
+ [(set_attr "type" "mvi")])
+
+(define_insn "umaxqi3"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (umax:SI (match_operand:QI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:QI 2 "reg_or_8bit_operand" "rI")))]
+ "TARGET_MAX"
+ "maxub8 %r1,%2,%0"
+ [(set_attr "type" "mvi")])
+
+(define_insn "sminhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (smin:SI (match_operand:HI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:HI 2 "reg_or_8bit_operand" "rI")))]
+ "TARGET_MAX"
+ "minsw4 %r1,%2,%0"
+ [(set_attr "type" "mvi")])
+
+(define_insn "uminhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (umin:SI (match_operand:HI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:HI 2 "reg_or_8bit_operand" "rI")))]
+ "TARGET_MAX"
+ "minuw4 %r1,%2,%0"
+ [(set_attr "type" "mvi")])
+
+(define_insn "smaxhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (smax:SI (match_operand:HI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:HI 2 "reg_or_8bit_operand" "rI")))]
+ "TARGET_MAX"
+ "maxsw4 %r1,%2,%0"
+ [(set_attr "type" "mvi")])
+
+(define_insn "umaxhi3"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (umax:SI (match_operand:HI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:HI 2 "reg_or_8bit_operand" "rI")))]
+ "TARGET_MAX"
+ "maxuw4 %r1,%2,%0"
+ [(set_attr "type" "shift")])
+
(define_expand "smaxdi3"
[(set (match_dup 3)
(le:DI (match_operand:DI 1 "reg_or_0_operand" "")
@@ -1528,7 +2550,8 @@
(smax:DI (match_operand:DI 1 "register_operand" "0")
(const_int 0)))]
""
- "cmovlt %0,0,%0")
+ "cmovlt %0,0,%0"
+ [(set_attr "type" "icmov")])
(define_expand "smindi3"
[(set (match_dup 3)
@@ -1558,7 +2581,8 @@
(smin:DI (match_operand:DI 1 "register_operand" "0")
(const_int 0)))]
""
- "cmovgt %0,0,%0")
+ "cmovgt %0,0,%0"
+ [(set_attr "type" "icmov")])
(define_expand "umaxdi3"
[(set (match_dup 3)
@@ -1621,6 +2645,18 @@
(define_insn ""
[(set (pc)
(if_then_else
+ (match_operator 1 "signed_comparison_operator"
+ [(const_int 0)
+ (match_operand:DI 2 "register_operand" "r")])
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "b%c1 %2,%0"
+ [(set_attr "type" "ibr")])
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else
(ne (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
(const_int 1)
(const_int 0))
@@ -1674,13 +2710,35 @@
;; to DFmode.
(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (match_operator:DF 1 "alpha_comparison_operator"
+ [(match_operand:DF 2 "reg_or_fp0_operand" "fG")
+ (match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "cmp%-%C1%' %R2,%R3,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(match_operator:DF 1 "alpha_comparison_operator"
[(match_operand:DF 2 "reg_or_fp0_operand" "fG")
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
- "TARGET_FP"
- "cmpt%C1 %R2,%R3,%0"
- [(set_attr "type" "fpop")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "cmp%-%C1%' %R2,%R3,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (match_operator:DF 1 "alpha_comparison_operator"
+ [(float_extend:DF
+ (match_operand:SF 2 "reg_or_fp0_operand" "fG"))
+ (match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "cmp%-%C1%' %R2,%R3,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -1688,9 +2746,21 @@
[(float_extend:DF
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(match_operand:DF 3 "reg_or_fp0_operand" "fG")]))]
- "TARGET_FP"
- "cmpt%C1 %R2,%R3,%0"
- [(set_attr "type" "fpop")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "cmp%-%C1%' %R2,%R3,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (match_operator:DF 1 "alpha_comparison_operator"
+ [(match_operand:DF 2 "reg_or_fp0_operand" "fG")
+ (float_extend:DF
+ (match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "cmp%-%C1%' %R2,%R3,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -1698,9 +2768,22 @@
[(match_operand:DF 2 "reg_or_fp0_operand" "fG")
(float_extend:DF
(match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
- "TARGET_FP"
- "cmpt%C1 %R2,%R3,%0"
- [(set_attr "type" "fpop")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "cmp%-%C1%' %R2,%R3,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=&f")
+ (match_operator:DF 1 "alpha_comparison_operator"
+ [(float_extend:DF
+ (match_operand:SF 2 "reg_or_fp0_operand" "fG"))
+ (float_extend:DF
+ (match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
+ "TARGET_FP && alpha_tp == ALPHA_TP_INSN"
+ "cmp%-%C1%' %R2,%R3,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
@@ -1709,9 +2792,10 @@
(match_operand:SF 2 "reg_or_fp0_operand" "fG"))
(float_extend:DF
(match_operand:SF 3 "reg_or_fp0_operand" "fG"))]))]
- "TARGET_FP"
- "cmpt%C1 %R2,%R3,%0"
- [(set_attr "type" "fpop")])
+ "TARGET_FP && alpha_tp != ALPHA_TP_INSN"
+ "cmp%-%C1%' %R2,%R3,%0"
+ [(set_attr "type" "fadd")
+ (set_attr "trap" "yes")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f,f")
@@ -1725,7 +2809,7 @@
"@
fcmov%C3 %R4,%R1,%0
fcmov%D3 %R4,%R5,%0"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fcmov")])
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=f,f")
@@ -1739,21 +2823,21 @@
"@
fcmov%C3 %R4,%R1,%0
fcmov%D3 %R4,%R5,%0"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fcmov")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f,f")
(if_then_else:DF
(match_operator 3 "signed_comparison_operator"
- [(match_operand:DF 1 "reg_or_fp0_operand" "fG,fG")
+ [(match_operand:DF 4 "reg_or_fp0_operand" "fG,fG")
(match_operand:DF 2 "fp0_operand" "G,G")])
- (float_extend:DF (match_operand:SF 4 "reg_or_fp0_operand" "fG,0"))
+ (float_extend:DF (match_operand:SF 1 "reg_or_fp0_operand" "fG,0"))
(match_operand:DF 5 "reg_or_fp0_operand" "0,fG")))]
"TARGET_FP"
"@
fcmov%C3 %R4,%R1,%0
fcmov%D3 %R4,%R5,%0"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fcmov")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f,f")
@@ -1768,7 +2852,7 @@
"@
fcmov%C3 %R4,%R1,%0
fcmov%D3 %R4,%R5,%0"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fcmov")])
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=f,f")
@@ -1783,7 +2867,7 @@
"@
fcmov%C3 %R4,%R1,%0
fcmov%D3 %R4,%R5,%0"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fcmov")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f,f")
@@ -1798,7 +2882,7 @@
"@
fcmov%C3 %R4,%R1,%0
fcmov%D3 %R4,%R5,%0"
- [(set_attr "type" "fpop")])
+ [(set_attr "type" "fcmov")])
(define_expand "maxdf3"
[(set (match_dup 3)
@@ -1905,198 +2989,84 @@
}")
(define_expand "beq"
- [(set (match_dup 1) (match_dup 2))
- (set (pc)
- (if_then_else (match_dup 3)
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- enum machine_mode mode;
- enum rtx_code compare_code, branch_code;
-
- if (alpha_compare_fp_p)
- mode = DFmode, compare_code = EQ, branch_code = NE;
- else
- {
- mode = DImode, compare_code = MINUS, branch_code = EQ;
- if (GET_CODE (alpha_compare_op1) == CONST_INT)
- {
- compare_code = PLUS;
- alpha_compare_op1 = GEN_INT (- INTVAL (alpha_compare_op1));
- }
- }
-
- operands[1] = gen_reg_rtx (mode);
- operands[2] = gen_rtx (compare_code, mode,
- alpha_compare_op0, alpha_compare_op1);
- operands[3] = gen_rtx (branch_code, VOIDmode,
- operands[1], CONST0_RTX (mode));
-}")
+ "{ operands[1] = alpha_emit_conditional_branch (EQ); }")
(define_expand "bne"
- [(set (match_dup 1) (match_dup 2))
- (set (pc)
- (if_then_else (match_dup 3)
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- enum machine_mode mode;
- enum rtx_code compare_code, branch_code;
-
- if (alpha_compare_fp_p)
- mode = DFmode, compare_code = EQ, branch_code = EQ;
- else
- {
- mode = DImode, compare_code = MINUS, branch_code = NE;
- if (GET_CODE (alpha_compare_op1) == CONST_INT)
- {
- compare_code = PLUS;
- alpha_compare_op1 = GEN_INT (- INTVAL (alpha_compare_op1));
- }
- }
-
- operands[1] = gen_reg_rtx (mode);
- operands[2] = gen_rtx (compare_code, mode,
- alpha_compare_op0, alpha_compare_op1);
- operands[3] = gen_rtx (branch_code, VOIDmode,
- operands[1], CONST0_RTX (mode));
-}")
+ "{ operands[1] = alpha_emit_conditional_branch (NE); }")
(define_expand "blt"
- [(set (match_dup 1) (match_dup 2))
- (set (pc)
- (if_then_else (match_dup 3)
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- enum machine_mode mode = alpha_compare_fp_p ? DFmode : DImode;
- operands[1] = gen_reg_rtx (mode);
- operands[2] = gen_rtx (LT, mode, alpha_compare_op0, alpha_compare_op1);
- operands[3] = gen_rtx (NE, VOIDmode, operands[1], CONST0_RTX (mode));
-}")
+ "{ operands[1] = alpha_emit_conditional_branch (LT); }")
(define_expand "ble"
- [(set (match_dup 1) (match_dup 2))
- (set (pc)
- (if_then_else (match_dup 3)
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- enum machine_mode mode = alpha_compare_fp_p ? DFmode : DImode;
- operands[1] = gen_reg_rtx (mode);
- operands[2] = gen_rtx (LE, mode, alpha_compare_op0, alpha_compare_op1);
- operands[3] = gen_rtx (NE, VOIDmode, operands[1], CONST0_RTX (mode));
-}")
+ "{ operands[1] = alpha_emit_conditional_branch (LE); }")
(define_expand "bgt"
- [(set (match_dup 1) (match_dup 2))
- (set (pc)
- (if_then_else (match_dup 3)
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- if (alpha_compare_fp_p)
- {
- operands[1] = gen_reg_rtx (DFmode);
- operands[2] = gen_rtx (LT, DFmode, alpha_compare_op1, alpha_compare_op0);
- operands[3] = gen_rtx (NE, VOIDmode, operands[1], CONST0_RTX (DFmode));
- }
- else
- {
- operands[1] = gen_reg_rtx (DImode);
- operands[2] = gen_rtx (LE, DImode, alpha_compare_op0, alpha_compare_op1);
- operands[3] = gen_rtx (EQ, VOIDmode, operands[1], const0_rtx);
- }
-}")
+ "{ operands[1] = alpha_emit_conditional_branch (GT); }")
(define_expand "bge"
- [(set (match_dup 1) (match_dup 2))
- (set (pc)
- (if_then_else (match_dup 3)
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- if (alpha_compare_fp_p)
- {
- operands[1] = gen_reg_rtx (DFmode);
- operands[2] = gen_rtx (LE, DFmode, alpha_compare_op1, alpha_compare_op0);
- operands[3] = gen_rtx (NE, VOIDmode, operands[1], CONST0_RTX (DFmode));
- }
- else
- {
- operands[1] = gen_reg_rtx (DImode);
- operands[2] = gen_rtx (LT, DImode, alpha_compare_op0, alpha_compare_op1);
- operands[3] = gen_rtx (EQ, VOIDmode, operands[1], const0_rtx);
- }
-}")
+ "{ operands[1] = alpha_emit_conditional_branch (GE); }")
(define_expand "bltu"
- [(set (match_dup 1) (match_dup 2))
- (set (pc)
- (if_then_else (match_dup 3)
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- operands[1] = gen_reg_rtx (DImode);
- operands[2] = gen_rtx (LTU, DImode, alpha_compare_op0, alpha_compare_op1);
- operands[3] = gen_rtx (NE, VOIDmode, operands[1], const0_rtx);
-}")
+ "{ operands[1] = alpha_emit_conditional_branch (LTU); }")
(define_expand "bleu"
- [(set (match_dup 1) (match_dup 2))
- (set (pc)
- (if_then_else (match_dup 3)
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- operands[1] = gen_reg_rtx (DImode);
- operands[2] = gen_rtx (LEU, DImode, alpha_compare_op0, alpha_compare_op1);
- operands[3] = gen_rtx (NE, VOIDmode, operands[1], const0_rtx);
-}")
+ "{ operands[1] = alpha_emit_conditional_branch (LEU); }")
(define_expand "bgtu"
- [(set (match_dup 1) (match_dup 2))
- (set (pc)
- (if_then_else (match_dup 3)
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- operands[1] = gen_reg_rtx (DImode);
- operands[2] = gen_rtx (LEU, DImode, alpha_compare_op0, alpha_compare_op1);
- operands[3] = gen_rtx (EQ, VOIDmode, operands[1], const0_rtx);
-}")
+ "{ operands[1] = alpha_emit_conditional_branch (GTU); }")
(define_expand "bgeu"
- [(set (match_dup 1) (match_dup 2))
- (set (pc)
- (if_then_else (match_dup 3)
+ [(set (pc)
+ (if_then_else (match_dup 1)
(label_ref (match_operand 0 "" ""))
(pc)))]
""
- "
-{
- operands[1] = gen_reg_rtx (DImode);
- operands[2] = gen_rtx (LTU, DImode, alpha_compare_op0, alpha_compare_op1);
- operands[3] = gen_rtx (EQ, VOIDmode, operands[1], const0_rtx);
-}")
+ "{ operands[1] = alpha_emit_conditional_branch (GEU); }")
(define_expand "seq"
[(set (match_operand:DI 0 "register_operand" "")
@@ -2107,7 +3077,7 @@
if (alpha_compare_fp_p)
FAIL;
- operands[1] = gen_rtx (EQ, DImode, alpha_compare_op0, alpha_compare_op1);
+ operands[1] = gen_rtx_EQ (DImode, alpha_compare_op0, alpha_compare_op1);
}")
(define_expand "sne"
@@ -2120,7 +3090,7 @@
if (alpha_compare_fp_p)
FAIL;
- operands[1] = gen_rtx (EQ, DImode, alpha_compare_op0, alpha_compare_op1);
+ operands[1] = gen_rtx_EQ (DImode, alpha_compare_op0, alpha_compare_op1);
}")
(define_expand "slt"
@@ -2132,7 +3102,7 @@
if (alpha_compare_fp_p)
FAIL;
- operands[1] = gen_rtx (LT, DImode, alpha_compare_op0, alpha_compare_op1);
+ operands[1] = gen_rtx_LT (DImode, alpha_compare_op0, alpha_compare_op1);
}")
(define_expand "sle"
@@ -2144,7 +3114,7 @@
if (alpha_compare_fp_p)
FAIL;
- operands[1] = gen_rtx (LE, DImode, alpha_compare_op0, alpha_compare_op1);
+ operands[1] = gen_rtx_LE (DImode, alpha_compare_op0, alpha_compare_op1);
}")
(define_expand "sgt"
@@ -2156,8 +3126,8 @@
if (alpha_compare_fp_p)
FAIL;
- operands[1] = gen_rtx (LT, DImode, force_reg (DImode, alpha_compare_op1),
- alpha_compare_op0);
+ operands[1] = gen_rtx_LT (DImode, force_reg (DImode, alpha_compare_op1),
+ alpha_compare_op0);
}")
(define_expand "sge"
@@ -2169,8 +3139,8 @@
if (alpha_compare_fp_p)
FAIL;
- operands[1] = gen_rtx (LE, DImode, force_reg (DImode, alpha_compare_op1),
- alpha_compare_op0);
+ operands[1] = gen_rtx_LE (DImode, force_reg (DImode, alpha_compare_op1),
+ alpha_compare_op0);
}")
(define_expand "sltu"
@@ -2182,7 +3152,7 @@
if (alpha_compare_fp_p)
FAIL;
- operands[1] = gen_rtx (LTU, DImode, alpha_compare_op0, alpha_compare_op1);
+ operands[1] = gen_rtx_LTU (DImode, alpha_compare_op0, alpha_compare_op1);
}")
(define_expand "sleu"
@@ -2194,7 +3164,7 @@
if (alpha_compare_fp_p)
FAIL;
- operands[1] = gen_rtx (LEU, DImode, alpha_compare_op0, alpha_compare_op1);
+ operands[1] = gen_rtx_LEU (DImode, alpha_compare_op0, alpha_compare_op1);
}")
(define_expand "sgtu"
@@ -2206,8 +3176,8 @@
if (alpha_compare_fp_p)
FAIL;
- operands[1] = gen_rtx (LTU, DImode, force_reg (DImode, alpha_compare_op1),
- alpha_compare_op0);
+ operands[1] = gen_rtx_LTU (DImode, force_reg (DImode, alpha_compare_op1),
+ alpha_compare_op0);
}")
(define_expand "sgeu"
@@ -2219,184 +3189,58 @@
if (alpha_compare_fp_p)
FAIL;
- operands[1] = gen_rtx (LEU, DImode, force_reg (DImode, alpha_compare_op1),
- alpha_compare_op0);
+ operands[1] = gen_rtx_LEU (DImode, force_reg (DImode, alpha_compare_op1),
+ alpha_compare_op0);
}")
;; These are the main define_expand's used to make conditional moves.
(define_expand "movsicc"
- [(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
- (set (match_operand:SI 0 "register_operand" "")
- (if_then_else:DI (match_dup 5)
+ [(set (match_operand:SI 0 "register_operand" "")
+ (if_then_else:DI (match_operand 1 "comparison_operator" "")
(match_operand:SI 2 "reg_or_8bit_operand" "")
(match_operand:SI 3 "reg_or_8bit_operand" "")))]
""
"
{
- rtx op0,op1;
- enum rtx_code code = GET_CODE (operands[1]), code2 = NE;
-
- if (alpha_compare_fp_p)
+ if ((operands[1] = alpha_emit_conditional_move (operands[1], SImode)) == 0)
FAIL;
- switch (code)
- {
- case EQ: case LE: case LT:
- op0 = alpha_compare_op0;
- op1 = alpha_compare_op1;
- break;
- case NE:
- code = code2 = EQ;
- op0 = alpha_compare_op0;
- op1 = alpha_compare_op1;
- break;
- case GE:
- code = LE;
- op0 = force_reg (DImode, alpha_compare_op1);
- op1 = alpha_compare_op0;
- break;
- case GT:
- code = LT;
- op0 = force_reg (DImode, alpha_compare_op1);
- op1 = alpha_compare_op0;
- break;
- default:
- FAIL;
- }
- operands[1] = gen_rtx (code, DImode, op0, op1);
- operands[4] = gen_reg_rtx (DImode);
- operands[5] = gen_rtx (code2, VOIDmode, operands[4], CONST0_RTX (DImode));
}")
(define_expand "movdicc"
- [(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
- (set (match_operand:DI 0 "register_operand" "")
- (if_then_else:DI (match_dup 5)
+ [(set (match_operand:DI 0 "register_operand" "")
+ (if_then_else:DI (match_operand 1 "comparison_operator" "")
(match_operand:DI 2 "reg_or_8bit_operand" "")
(match_operand:DI 3 "reg_or_8bit_operand" "")))]
""
"
{
- rtx op0,op1;
- enum rtx_code code = GET_CODE (operands[1]), code2 = NE;
-
- if (alpha_compare_fp_p)
+ if ((operands[1] = alpha_emit_conditional_move (operands[1], DImode)) == 0)
FAIL;
- switch (code)
- {
- case EQ: case LE: case LT:
- op0 = alpha_compare_op0;
- op1 = alpha_compare_op1;
- break;
- case NE:
- code = code2 = EQ;
- op0 = alpha_compare_op0;
- op1 = alpha_compare_op1;
- break;
- case GE:
- code = LE;
- op0 = force_reg (DImode, alpha_compare_op1);
- op1 = alpha_compare_op0;
- break;
- case GT:
- code = LT;
- op0 = force_reg (DImode, alpha_compare_op1);
- op1 = alpha_compare_op0;
- break;
- default:
- FAIL;
- }
- operands[1] = gen_rtx (code, DImode, op0, op1);
- operands[4] = gen_reg_rtx (DImode);
- operands[5] = gen_rtx (code2, VOIDmode, operands[4], CONST0_RTX (DImode));
}")
(define_expand "movsfcc"
- [(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
- (set (match_operand:SF 0 "register_operand" "")
- (if_then_else:SF (match_dup 5)
- (match_operand:SF 2 "reg_or_fp0_operand" "")
- (match_operand:SF 3 "reg_or_fp0_operand" "")))]
+ [(set (match_operand:SF 0 "register_operand" "")
+ (if_then_else:SF (match_operand 1 "comparison_operator" "")
+ (match_operand:SF 2 "reg_or_8bit_operand" "")
+ (match_operand:SF 3 "reg_or_8bit_operand" "")))]
""
"
{
- rtx op0,op1;
- enum rtx_code code = GET_CODE (operands[1]), code2 = NE;
-
- if (!alpha_compare_fp_p)
+ if ((operands[1] = alpha_emit_conditional_move (operands[1], SFmode)) == 0)
FAIL;
- switch (code)
- {
- case EQ: case LE: case LT:
- op0 = alpha_compare_op0;
- op1 = alpha_compare_op1;
- break;
- case NE:
- /* There isn't a cmptne insn. */
- code = code2 = EQ;
- op0 = alpha_compare_op0;
- op1 = alpha_compare_op1;
- break;
- case GE:
- code = LE;
- op0 = force_reg (DFmode, alpha_compare_op1);
- op1 = alpha_compare_op0;
- break;
- case GT:
- code = LT;
- op0 = force_reg (DFmode, alpha_compare_op1);
- op1 = alpha_compare_op0;
- break;
- default:
- FAIL;
- }
- operands[1] = gen_rtx (code, DFmode, op0, op1);
- operands[4] = gen_reg_rtx (DFmode);
- operands[5] = gen_rtx (code2, VOIDmode, operands[4], CONST0_RTX (DFmode));
}")
(define_expand "movdfcc"
- [(set (match_dup 4) (match_operand 1 "comparison_operator" ""))
- (set (match_operand:DF 0 "register_operand" "")
- (if_then_else:DF (match_dup 5)
- (match_operand:DF 2 "reg_or_fp0_operand" "")
- (match_operand:DF 3 "reg_or_fp0_operand" "")))]
+ [(set (match_operand:DF 0 "register_operand" "")
+ (if_then_else:DF (match_operand 1 "comparison_operator" "")
+ (match_operand:DF 2 "reg_or_8bit_operand" "")
+ (match_operand:DF 3 "reg_or_8bit_operand" "")))]
""
"
{
- rtx op0,op1;
- enum rtx_code code = GET_CODE (operands[1]), code2 = NE;
-
- if (!alpha_compare_fp_p)
+ if ((operands[1] = alpha_emit_conditional_move (operands[1], DFmode)) == 0)
FAIL;
- switch (code)
- {
- case EQ: case LE: case LT:
- op0 = alpha_compare_op0;
- op1 = alpha_compare_op1;
- break;
- case NE:
- /* There isn't a cmptne insn. */
- code = code2 = EQ;
- op0 = alpha_compare_op0;
- op1 = alpha_compare_op1;
- break;
- case GE:
- code = LE;
- op0 = force_reg (DFmode, alpha_compare_op1);
- op1 = alpha_compare_op0;
- break;
- case GT:
- code = LT;
- op0 = force_reg (DFmode, alpha_compare_op1);
- op1 = alpha_compare_op0;
- break;
- default:
- FAIL;
- }
- operands[1] = gen_rtx (code, DFmode, op0, op1);
- operands[4] = gen_reg_rtx (DFmode);
- operands[5] = gen_rtx (code2, VOIDmode, operands[4], CONST0_RTX (DFmode));
}")
;; These define_split definitions are used in cases when comparisons have
@@ -2451,25 +3295,25 @@
&& extended_count (operands[3], DImode, unsignedp) >= 1))
{
if (GET_CODE (operands[3]) == CONST_INT)
- operands[7] = gen_rtx (PLUS, DImode, operands[2],
- GEN_INT (- INTVAL (operands[3])));
+ operands[7] = gen_rtx_PLUS (DImode, operands[2],
+ GEN_INT (- INTVAL (operands[3])));
else
- operands[7] = gen_rtx (MINUS, DImode, operands[2], operands[3]);
+ operands[7] = gen_rtx_MINUS (DImode, operands[2], operands[3]);
- operands[8] = gen_rtx (code, VOIDmode, operands[6], const0_rtx);
+ operands[8] = gen_rtx_fmt_ee (code, VOIDmode, operands[6], const0_rtx);
}
else if (code == EQ || code == LE || code == LT
|| code == LEU || code == LTU)
{
- operands[7] = gen_rtx (code, DImode, operands[2], operands[3]);
- operands[8] = gen_rtx (NE, VOIDmode, operands[6], const0_rtx);
+ operands[7] = gen_rtx_fmt_ee (code, DImode, operands[2], operands[3]);
+ operands[8] = gen_rtx_NE (VOIDmode, operands[6], const0_rtx);
}
else
{
- operands[7] = gen_rtx (reverse_condition (code), DImode, operands[2],
- operands[3]);
- operands[8] = gen_rtx (EQ, VOIDmode, operands[6], const0_rtx);
+ operands[7] = gen_rtx_fmt_ee (reverse_condition (code), DImode,
+ operands[2], operands[3]);
+ operands[8] = gen_rtx_EQ (VOIDmode, operands[6], const0_rtx);
}
}")
@@ -2498,14 +3342,14 @@
FAIL;
if (GET_CODE (operands[3]) == CONST_INT)
- tem = gen_rtx (PLUS, SImode, operands[2],
- GEN_INT (- INTVAL (operands[3])));
+ tem = gen_rtx_PLUS (SImode, operands[2],
+ GEN_INT (- INTVAL (operands[3])));
else
- tem = gen_rtx (MINUS, SImode, operands[2], operands[3]);
+ tem = gen_rtx_MINUS (SImode, operands[2], operands[3]);
- operands[7] = gen_rtx (SIGN_EXTEND, DImode, tem);
- operands[8] = gen_rtx (GET_CODE (operands[1]), VOIDmode, operands[6],
- const0_rtx);
+ operands[7] = gen_rtx_SIGN_EXTEND (DImode, tem);
+ operands[8] = gen_rtx_fmt_ee (GET_CODE (operands[1]), VOIDmode,
+ operands[6], const0_rtx);
}")
(define_split
@@ -2529,25 +3373,25 @@
&& extended_count (operands[3], DImode, unsignedp) >= 1))
{
if (GET_CODE (operands[3]) == CONST_INT)
- operands[5] = gen_rtx (PLUS, DImode, operands[2],
- GEN_INT (- INTVAL (operands[3])));
+ operands[5] = gen_rtx_PLUS (DImode, operands[2],
+ GEN_INT (- INTVAL (operands[3])));
else
- operands[5] = gen_rtx (MINUS, DImode, operands[2], operands[3]);
+ operands[5] = gen_rtx_MINUS (DImode, operands[2], operands[3]);
- operands[6] = gen_rtx (code, VOIDmode, operands[4], const0_rtx);
+ operands[6] = gen_rtx_fmt_ee (code, VOIDmode, operands[4], const0_rtx);
}
else if (code == EQ || code == LE || code == LT
|| code == LEU || code == LTU)
{
- operands[5] = gen_rtx (code, DImode, operands[2], operands[3]);
- operands[6] = gen_rtx (NE, VOIDmode, operands[4], const0_rtx);
+ operands[5] = gen_rtx_fmt_ee (code, DImode, operands[2], operands[3]);
+ operands[6] = gen_rtx_NE (VOIDmode, operands[4], const0_rtx);
}
else
{
- operands[5] = gen_rtx (reverse_condition (code), DImode, operands[2],
- operands[3]);
- operands[6] = gen_rtx (EQ, VOIDmode, operands[4], const0_rtx);
+ operands[5] = gen_rtx_fmt_ee (reverse_condition (code), DImode,
+ operands[2], operands[3]);
+ operands[6] = gen_rtx_EQ (VOIDmode, operands[4], const0_rtx);
}
}")
@@ -2568,14 +3412,14 @@
{ rtx tem;
if (GET_CODE (operands[3]) == CONST_INT)
- tem = gen_rtx (PLUS, SImode, operands[2],
- GEN_INT (- INTVAL (operands[3])));
+ tem = gen_rtx_PLUS (SImode, operands[2],
+ GEN_INT (- INTVAL (operands[3])));
else
- tem = gen_rtx (MINUS, SImode, operands[2], operands[3]);
+ tem = gen_rtx_MINUS (SImode, operands[2], operands[3]);
- operands[5] = gen_rtx (SIGN_EXTEND, DImode, tem);
- operands[6] = gen_rtx (GET_CODE (operands[1]), VOIDmode,
- operands[4], const0_rtx);
+ operands[5] = gen_rtx_SIGN_EXTEND (DImode, tem);
+ operands[6] = gen_rtx_fmt_ee (GET_CODE (operands[1]), VOIDmode,
+ operands[4], const0_rtx);
}")
;; We can convert such things as "a > 0xffff" to "t = a & ~ 0xffff; t != 0".
@@ -2597,10 +3441,10 @@
"
{
operands[5] = GEN_INT (~ INTVAL (operands[3]));
- operands[6] = gen_rtx (((GET_CODE (operands[1]) == GTU
- || GET_CODE (operands[1]) == GT)
- ? NE : EQ),
- DImode, operands[4], const0_rtx);
+ operands[6] = gen_rtx_fmt_ee (((GET_CODE (operands[1]) == GTU
+ || GET_CODE (operands[1]) == GT)
+ ? NE : EQ),
+ DImode, operands[4], const0_rtx);
}")
;; Here are the CALL and unconditional branch insns. Calls on NT and OSF
@@ -2608,11 +3452,15 @@
(define_expand "call"
[(use (match_operand:DI 0 "" ""))
- (use (match_operand 1 "" ""))]
+ (use (match_operand 1 "" ""))
+ (use (match_operand 2 "" ""))
+ (use (match_operand 3 "" ""))]
""
"
-{ if (WINDOWS_NT)
+{ if (TARGET_WINDOWS_NT)
emit_call_insn (gen_call_nt (operands[0], operands[1]));
+ else if (TARGET_OPEN_VMS)
+ emit_call_insn (gen_call_vms (operands[0], operands[2]));
else
emit_call_insn (gen_call_osf (operands[0], operands[1]));
@@ -2634,39 +3482,95 @@
if (GET_CODE (operands[0]) != SYMBOL_REF
&& ! (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 27))
{
- rtx tem = gen_rtx (REG, DImode, 27);
+ rtx tem = gen_rtx_REG (DImode, 27);
emit_move_insn (tem, operands[0]);
operands[0] = tem;
}
}")
(define_expand "call_nt"
- [(parallel [(call (mem:DI (match_operand:DI 0 "" ""))
+ [(parallel [(call (mem:DI (match_operand 0 "" ""))
(match_operand 1 "" ""))
(clobber (reg:DI 26))])]
""
"
{ if (GET_CODE (operands[0]) != MEM)
abort ();
+
operands[0] = XEXP (operands[0], 0);
+ if (GET_CODE (operands[0]) != SYMBOL_REF && GET_CODE (operands[0]) != REG)
+ operands[0] = force_reg (DImode, operands[0]);
+}")
- if (GET_CODE (operands[1]) != SYMBOL_REF
- && ! (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 27))
+;;
+;; call openvms/alpha
+;; op 0: symbol ref for called function
+;; op 1: next_arg_reg (argument information value for R25)
+;;
+(define_expand "call_vms"
+ [(parallel [(call (mem:DI (match_operand 0 "" ""))
+ (match_operand 1 "" ""))
+ (use (match_dup 2))
+ (use (reg:DI 25))
+ (use (reg:DI 26))
+ (clobber (reg:DI 27))])]
+ ""
+ "
+{ if (GET_CODE (operands[0]) != MEM)
+ abort ();
+
+ operands[0] = XEXP (operands[0], 0);
+
+ /* Always load AI with argument information, then handle symbolic and
+ indirect call differently. Load RA and set operands[2] to PV in
+ both cases. */
+
+ emit_move_insn (gen_rtx_REG (DImode, 25), operands[1]);
+ if (GET_CODE (operands[0]) == SYMBOL_REF)
{
- rtx tem = gen_rtx (REG, DImode, 27);
- emit_move_insn (tem, operands[1]);
- operands[1] = tem;
+ extern char *savealloc ();
+ char *linksym, *symbol = XSTR (operands[0], 0);
+ rtx linkage;
+
+ if (*symbol == '*')
+ symbol++;
+ linksym = savealloc (strlen (symbol) + 6);
+
+ alpha_need_linkage (symbol, 0);
+
+ linksym[0] = '$';
+ strcpy (linksym+1, symbol);
+ strcat (linksym, \"..lk\");
+ linkage = gen_rtx_SYMBOL_REF (Pmode, linksym);
+
+ emit_move_insn (gen_rtx_REG (Pmode, 26), gen_rtx_MEM (Pmode, linkage));
+
+ operands[2]
+ = validize_mem (gen_rtx_MEM (Pmode, plus_constant (linkage, 8)));
}
+ else
+ {
+ emit_move_insn (gen_rtx_REG (Pmode, 26),
+ gen_rtx_MEM (Pmode, plus_constant (operands[0], 8)));
+
+ operands[2] = operands[0];
+ }
+
}")
(define_expand "call_value"
[(use (match_operand 0 "" ""))
(use (match_operand:DI 1 "" ""))
- (use (match_operand 2 "" ""))]
+ (use (match_operand 2 "" ""))
+ (use (match_operand 3 "" ""))
+ (use (match_operand 4 "" ""))]
""
"
-{ if (WINDOWS_NT)
+{ if (TARGET_WINDOWS_NT)
emit_call_insn (gen_call_value_nt (operands[0], operands[1], operands[2]));
+ else if (TARGET_OPEN_VMS)
+ emit_call_insn (gen_call_value_vms (operands[0], operands[1],
+ operands[3]));
else
emit_call_insn (gen_call_value_osf (operands[0], operands[1],
operands[2]));
@@ -2689,7 +3593,7 @@
if (GET_CODE (operands[1]) != SYMBOL_REF
&& ! (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 27))
{
- rtx tem = gen_rtx (REG, DImode, 27);
+ rtx tem = gen_rtx_REG (DImode, 27);
emit_move_insn (tem, operands[1]);
operands[1] = tem;
}
@@ -2697,7 +3601,7 @@
(define_expand "call_value_nt"
[(parallel [(set (match_operand 0 "" "")
- (call (mem:DI (match_operand:DI 1 "" ""))
+ (call (mem:DI (match_operand 1 "" ""))
(match_operand 2 "" "")))
(clobber (reg:DI 26))])]
""
@@ -2706,12 +3610,57 @@
abort ();
operands[1] = XEXP (operands[1], 0);
- if (GET_CODE (operands[1]) != SYMBOL_REF
- && ! (GET_CODE (operands[1]) == REG && REGNO (operands[1]) == 27))
+ if (GET_CODE (operands[0]) != SYMBOL_REF && GET_CODE (operands[0]) != REG)
+ operands[1] = force_reg (DImode, operands[1]);
+}")
+
+(define_expand "call_value_vms"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:DI (match_operand:DI 1 "" ""))
+ (match_operand 2 "" "")))
+ (use (match_dup 3))
+ (use (reg:DI 25))
+ (use (reg:DI 26))
+ (clobber (reg:DI 27))])]
+ ""
+ "
+{ if (GET_CODE (operands[1]) != MEM)
+ abort ();
+
+ operands[1] = XEXP (operands[1], 0);
+
+ /* Always load AI with argument information, then handle symbolic and
+ indirect call differently. Load RA and set operands[3] to PV in
+ both cases. */
+
+ emit_move_insn (gen_rtx_REG (DImode, 25), operands[2]);
+ if (GET_CODE (operands[1]) == SYMBOL_REF)
{
- rtx tem = gen_rtx (REG, DImode, 27);
- emit_move_insn (tem, operands[1]);
- operands[1] = tem;
+ extern char *savealloc ();
+ char *linksym, *symbol = XSTR (operands[1], 0);
+ rtx linkage;
+
+ if (*symbol == '*')
+ symbol++;
+ linksym = savealloc (strlen (symbol) + 6);
+
+ alpha_need_linkage (symbol, 0);
+ linksym[0] = '$';
+ strcpy (linksym+1, symbol);
+ strcat (linksym, \"..lk\");
+ linkage = gen_rtx_SYMBOL_REF (Pmode, linksym);
+
+ emit_move_insn (gen_rtx_REG (Pmode, 26), gen_rtx_MEM (Pmode, linkage));
+
+ operands[3]
+ = validize_mem (gen_rtx_MEM (Pmode, plus_constant (linkage, 8)));
+ }
+ else
+ {
+ emit_move_insn (gen_rtx_REG (Pmode, 26),
+ gen_rtx_MEM (Pmode, plus_constant (operands[1], 8)));
+
+ operands[3] = operands[1];
}
}")
@@ -2720,46 +3669,81 @@
(match_operand 1 "" ""))
(clobber (reg:DI 27))
(clobber (reg:DI 26))]
- "! WINDOWS_NT"
+ "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS"
"@
jsr $26,($27),0\;ldgp $29,0($26)
- bsr $26,%0..ng
+ bsr $26,$%0..ng
jsr $26,%0\;ldgp $29,0($26)"
- [(set_attr "type" "jsr,jsr,ibr")])
+ [(set_attr "type" "jsr")
+ (set_attr "length" "12,*,12")])
(define_insn ""
- [(call (mem:DI (match_operand:DI 0 "call_operand" "r,i"))
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "r,R,i"))
(match_operand 1 "" ""))
(clobber (reg:DI 26))]
- "WINDOWS_NT"
+ "TARGET_WINDOWS_NT"
"@
jsr $26,(%0)
- bsr $26,%0"
- [(set_attr "type" "jsr")])
+ bsr $26,%0
+ jsr $26,%0"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "*,*,12")])
(define_insn ""
+ [(call (mem:DI (match_operand:DI 0 "call_operand" "r,i"))
+ (match_operand 1 "" ""))
+ (use (match_operand:DI 2 "general_operand" "r,m"))
+ (use (reg:DI 25))
+ (use (reg:DI 26))
+ (clobber (reg:DI 27))]
+ "TARGET_OPEN_VMS"
+ "@
+ bis %2,%2,$27\;jsr $26,0\;ldq $27,0($29)
+ ldq $27,%2\;jsr $26,%0\;ldq $27,0($29)"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "12,16")])
+
+(define_insn ""
[(set (match_operand 0 "register_operand" "=rf,rf,rf")
(call (mem:DI (match_operand:DI 1 "call_operand" "r,R,i"))
(match_operand 2 "" "")))
(clobber (reg:DI 27))
(clobber (reg:DI 26))]
- "! WINDOWS_NT"
+ "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS"
"@
jsr $26,($27),0\;ldgp $29,0($26)
- bsr $26,%1..ng
+ bsr $26,$%1..ng
jsr $26,%1\;ldgp $29,0($26)"
- [(set_attr "type" "jsr,jsr,ibr")])
+ [(set_attr "type" "jsr")
+ (set_attr "length" "12,*,12")])
(define_insn ""
- [(set (match_operand 0 "register_operand" "=rf,rf")
- (call (mem:DI (match_operand:DI 1 "call_operand" "r,i"))
+ [(set (match_operand 0 "register_operand" "=rf,rf,rf")
+ (call (mem:DI (match_operand:DI 1 "call_operand" "r,R,i"))
(match_operand 2 "" "")))
(clobber (reg:DI 26))]
- "WINDOWS_NT"
+ "TARGET_WINDOWS_NT"
"@
jsr $26,(%1)
- bsr $26,%1"
- [(set_attr "type" "jsr")])
+ bsr $26,%1
+ jsr $26,%1"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "*,*,12")])
+
+(define_insn ""
+ [(set (match_operand 0 "register_operand" "")
+ (call (mem:DI (match_operand:DI 1 "call_operand" "r,i"))
+ (match_operand 2 "" "")))
+ (use (match_operand:DI 3 "general_operand" "r,m"))
+ (use (reg:DI 25))
+ (use (reg:DI 26))
+ (clobber (reg:DI 27))]
+ "TARGET_OPEN_VMS"
+ "@
+ bis %3,%3,$27\;jsr $26,0\;ldq $27,0($29)
+ ldq $27,%3\;jsr $26,%1\;ldq $27,0($29)"
+ [(set_attr "type" "jsr")
+ (set_attr "length" "12,16")])
;; Call subroutine returning any type.
@@ -2796,7 +3780,8 @@
(define_insn "blockage"
[(unspec_volatile [(const_int 0)] 1)]
""
- "")
+ ""
+ [(set_attr "length" "0")])
(define_insn "jump"
[(set (pc)
@@ -2811,6 +3796,15 @@
"ret $31,($26),1"
[(set_attr "type" "ibr")])
+;; Use a different pattern for functions which have non-trivial
+;; epilogues so as not to confuse jump and reorg.
+(define_insn "return_internal"
+ [(use (reg:DI 26))
+ (return)]
+ ""
+ "ret $31,($26),1"
+ [(set_attr "type" "ibr")])
+
(define_insn "indirect_jump"
[(set (pc) (match_operand:DI 0 "register_operand" "r"))]
""
@@ -2820,8 +3814,8 @@
(define_insn "nop"
[(const_int 0)]
""
- "bis $31,$31,$31"
- [(set_attr "type" "iaddlog")])
+ "nop"
+ [(set_attr "type" "ilog")])
(define_expand "tablejump"
[(use (match_operand:SI 0 "register_operand" ""))
@@ -2829,8 +3823,10 @@
""
"
{
- if (WINDOWS_NT)
+ if (TARGET_WINDOWS_NT)
emit_jump_insn (gen_tablejump_nt (operands[0], operands[1]));
+ else if (TARGET_OPEN_VMS)
+ emit_jump_insn (gen_tablejump_vms (operands[0], operands[1]));
else
emit_jump_insn (gen_tablejump_osf (operands[0], operands[1]));
@@ -2858,12 +3854,27 @@
"
{ operands[3] = gen_reg_rtx (DImode); }")
+;;
+;; tablejump, openVMS way
+;; op 0: offset
+;; op 1: label preceding jump-table
+;;
+(define_expand "tablejump_vms"
+ [(set (match_dup 2)
+ (match_operand:DI 0 "register_operand" ""))
+ (set (pc)
+ (plus:DI (match_dup 2)
+ (label_ref:DI (match_operand 1 "" ""))))]
+ ""
+ "
+{ operands[2] = gen_reg_rtx (DImode); }")
+
(define_insn ""
[(set (pc)
(plus:DI (match_operand:DI 0 "register_operand" "r")
(label_ref:DI (match_operand 1 "" ""))))
(clobber (match_scratch:DI 2 "=r"))]
- "! WINDOWS_NT && next_active_insn (insn) != 0
+ "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && next_active_insn (insn) != 0
&& GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
&& PREV_INSN (next_active_insn (insn)) == operands[1]"
"*
@@ -2900,13 +3911,14 @@
else
return \"addq %0,$29,%2\;jmp $31,(%2),0\";
}"
- [(set_attr "type" "ibr")])
+ [(set_attr "type" "ibr")
+ (set_attr "length" "8")])
(define_insn ""
[(set (pc)
(match_operand:DI 0 "register_operand" "r"))
(use (label_ref (match_operand 1 "" "")))]
- "WINDOWS_NT && next_active_insn (insn) != 0
+ "TARGET_WINDOWS_NT && next_active_insn (insn) != 0
&& GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
&& PREV_INSN (next_active_insn (insn)) == operands[1]"
"*
@@ -2945,12 +3957,30 @@
}"
[(set_attr "type" "ibr")])
+;;
+;; op 0 is table offset
+;; op 1 is table label
+;;
+
+(define_insn ""
+ [(set (pc)
+ (plus:DI (match_operand 0 "register_operand" "r")
+ (label_ref (match_operand 1 "" ""))))]
+ "TARGET_OPEN_VMS"
+ "jmp $31,(%0),0"
+ [(set_attr "type" "ibr")])
+
;; Cache flush. Used by INITIALIZE_TRAMPOLINE. 0x86 is PAL_imb, but we don't
;; want to have to include pal.h in our .s file.
-(define_insn ""
+;;
+;; Technically the type for call_pal is jsr, but we use that for determining
+;; if we need a GP. Use ibr instead since it has the same EV5 scheduling
+;; characteristics.
+(define_insn "imb"
[(unspec_volatile [(const_int 0)] 0)]
""
- "call_pal 0x86")
+ "call_pal 0x86"
+ [(set_attr "type" "ibr")])
;; Finally, we have the basic data motion insns. The byte and word insns
;; are done via define_expand. Start with the floating-point insns, since
@@ -2959,32 +3989,70 @@
(define_insn ""
[(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m,f,f,f,m")
(match_operand:SF 1 "input_operand" "rG,m,rG,f,G,m,fG"))]
- "register_operand (operands[0], SFmode)
- || reg_or_fp0_operand (operands[1], SFmode)"
+ "! TARGET_CIX
+ && (register_operand (operands[0], SFmode)
+ || reg_or_fp0_operand (operands[1], SFmode))"
+ "@
+ bis %r1,%r1,%0
+ ldl %0,%1
+ stl %r1,%0
+ cpys %1,%1,%0
+ cpys $f31,$f31,%0
+ ld%, %0,%1
+ st%, %R1,%0"
+ [(set_attr "type" "ilog,ild,ist,fcpys,fcpys,fld,fst")])
+
+(define_insn ""
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m,f,f,f,m,f,*r")
+ (match_operand:SF 1 "input_operand" "rG,m,rG,f,G,m,fG,r,*f"))]
+ "TARGET_CIX
+ && (register_operand (operands[0], SFmode)
+ || reg_or_fp0_operand (operands[1], SFmode))"
"@
bis %r1,%r1,%0
ldl %0,%1
stl %r1,%0
cpys %1,%1,%0
cpys $f31,$f31,%0
- lds %0,%1
- sts %R1,%0"
- [(set_attr "type" "iaddlog,ld,st,fpop,fpop,ld,st")])
+ ld%, %0,%1
+ st%, %R1,%0
+ itofs %1,%0
+ ftois %1,%0"
+ [(set_attr "type" "ilog,ild,ist,fcpys,fcpys,fld,fst,itof,ftoi")])
(define_insn ""
[(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,f,f,f,m")
(match_operand:DF 1 "input_operand" "rG,m,rG,f,G,m,fG"))]
- "register_operand (operands[0], DFmode)
- || reg_or_fp0_operand (operands[1], DFmode)"
+ "! TARGET_CIX
+ && (register_operand (operands[0], DFmode)
+ || reg_or_fp0_operand (operands[1], DFmode))"
"@
bis %r1,%r1,%0
ldq %0,%1
stq %r1,%0
cpys %1,%1,%0
cpys $f31,$f31,%0
- ldt %0,%1
- stt %R1,%0"
- [(set_attr "type" "iaddlog,ld,st,fpop,fpop,ld,st")])
+ ld%- %0,%1
+ st%- %R1,%0"
+ [(set_attr "type" "ilog,ild,ist,fcpys,fcpys,fld,fst")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,f,f,f,m,f,*r")
+ (match_operand:DF 1 "input_operand" "rG,m,rG,f,G,m,fG,r,*f"))]
+ "TARGET_CIX
+ && (register_operand (operands[0], DFmode)
+ || reg_or_fp0_operand (operands[1], DFmode))"
+ "@
+ bis %r1,%r1,%0
+ ldq %0,%1
+ stq %r1,%0
+ cpys %1,%1,%0
+ cpys $f31,$f31,%0
+ ld%- %0,%1
+ st%- %R1,%0
+ itoft %1,%0
+ ftoit %1,%0"
+ [(set_attr "type" "ilog,ild,ist,fcpys,fcpys,fld,fst,itof,ftoi")])
(define_expand "movsf"
[(set (match_operand:SF 0 "nonimmediate_operand" "")
@@ -3011,8 +4079,9 @@
(define_insn ""
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,f,f,f,m")
(match_operand:SI 1 "input_operand" "r,J,I,K,L,m,rJ,f,J,m,fG"))]
- "! WINDOWS_NT && (register_operand (operands[0], SImode)
- || reg_or_0_operand (operands[1], SImode))"
+ "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && ! TARGET_CIX
+ && (register_operand (operands[0], SImode)
+ || reg_or_0_operand (operands[1], SImode))"
"@
bis %1,%1,%0
bis $31,$31,%0
@@ -3023,15 +4092,38 @@
stl %r1,%0
cpys %1,%1,%0
cpys $f31,$f31,%0
- lds %0,%1
- sts %R1,%0"
- [(set_attr "type" "iaddlog,iaddlog,iaddlog,iaddlog,iaddlog,ld,st,fpop,fpop,ld,st")])
+ ld%, %0,%1
+ st%, %R1,%0"
+ [(set_attr "type" "ilog,ilog,ilog,iadd,iadd,ild,ist,fcpys,fcpys,fld,fst")])
+
+(define_insn ""
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,f,f,f,m,r,*f")
+ (match_operand:SI 1 "input_operand" "r,J,I,K,L,m,rJ,f,J,m,fG,f,*r"))]
+ "! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && TARGET_CIX
+ && (register_operand (operands[0], SImode)
+ || reg_or_0_operand (operands[1], SImode))"
+ "@
+ bis %1,%1,%0
+ bis $31,$31,%0
+ bis $31,%1,%0
+ lda %0,%1
+ ldah %0,%h1
+ ldl %0,%1
+ stl %r1,%0
+ cpys %1,%1,%0
+ cpys $f31,$f31,%0
+ ld%, %0,%1
+ st%, %R1,%0
+ ftois %1,%0
+ itofs %1,%0"
+ [(set_attr "type" "ilog,ilog,ilog,iadd,iadd,ild,ist,fcpys,fcpys,fld,fst,ftoi,itof")])
(define_insn ""
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,r,r,m,f,f,f,m")
(match_operand:SI 1 "input_operand" "r,J,I,K,L,s,m,rJ,f,J,m,fG"))]
- "WINDOWS_NT && (register_operand (operands[0], SImode)
- || reg_or_0_operand (operands[1], SImode))"
+ "(TARGET_WINDOWS_NT || TARGET_OPEN_VMS)
+ && (register_operand (operands[0], SImode)
+ || reg_or_0_operand (operands[1], SImode))"
"@
bis %1,%1,%0
bis $31,$31,%0
@@ -3043,15 +4135,16 @@
stl %r1,%0
cpys %1,%1,%0
cpys $f31,$f31,%0
- lds %0,%1
- sts %R1,%0"
- [(set_attr "type" "iaddlog,iaddlog,iaddlog,iaddlog,iaddlog,ldsym,ld,st,fpop,fpop,ld,st")])
+ ld%, %0,%1
+ st%, %R1,%0"
+ [(set_attr "type" "ilog,ilog,ilog,iadd,iadd,ldsym,ild,ist,fcpys,fcpys,fld,fst")])
(define_insn ""
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,f,f")
(match_operand:HI 1 "input_operand" "r,J,I,n,f,J"))]
- "register_operand (operands[0], HImode)
- || register_operand (operands[1], HImode)"
+ "! TARGET_BWX
+ && (register_operand (operands[0], HImode)
+ || register_operand (operands[1], HImode))"
"@
bis %1,%1,%0
bis $31,$31,%0
@@ -3059,21 +4152,56 @@
lda %0,%L1
cpys %1,%1,%0
cpys $f31,$f31,%0"
- [(set_attr "type" "iaddlog,iaddlog,iaddlog,iaddlog,fpop,fpop")])
+ [(set_attr "type" "ilog,ilog,ilog,iadd,fcpys,fcpys")])
+
+(define_insn ""
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,r,r,m,f,f")
+ (match_operand:HI 1 "input_operand" "r,J,I,n,m,rJ,f,J"))]
+ "TARGET_BWX
+ && (register_operand (operands[0], HImode)
+ || reg_or_0_operand (operands[1], HImode))"
+ "@
+ bis %1,%1,%0
+ bis $31,$31,%0
+ bis $31,%1,%0
+ lda %0,%L1
+ ldwu %0,%1
+ stw %r1,%0
+ cpys %1,%1,%0
+ cpys $f31,$f31,%0"
+ [(set_attr "type" "ilog,ilog,ilog,iadd,ild,ist,fcpys,fcpys")])
(define_insn ""
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,r,f,f")
(match_operand:QI 1 "input_operand" "r,J,I,n,f,J"))]
- "register_operand (operands[0], QImode)
- || register_operand (operands[1], QImode)"
+ "! TARGET_BWX
+ && (register_operand (operands[0], QImode)
+ || register_operand (operands[1], QImode))"
+ "@
+ bis %1,%1,%0
+ bis $31,$31,%0
+ bis $31,%1,%0
+ lda %0,%L1
+ cpys %1,%1,%0
+ cpys $f31,$f31,%0"
+ [(set_attr "type" "ilog,ilog,ilog,iadd,fcpys,fcpys")])
+
+(define_insn ""
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,r,r,r,m,f,f")
+ (match_operand:QI 1 "input_operand" "r,J,I,n,m,rJ,f,J"))]
+ "TARGET_BWX
+ && (register_operand (operands[0], QImode)
+ || reg_or_0_operand (operands[1], QImode))"
"@
bis %1,%1,%0
bis $31,$31,%0
bis $31,%1,%0
lda %0,%L1
+ ldbu %0,%1
+ stb %r1,%0
cpys %1,%1,%0
cpys $f31,$f31,%0"
- [(set_attr "type" "iaddlog,iaddlog,iaddlog,iaddlog,fpop,fpop")])
+ [(set_attr "type" "ilog,ilog,ilog,iadd,ild,ist,fcpys,fcpys")])
;; We do two major things here: handle mem->mem and construct long
;; constants.
@@ -3121,8 +4249,9 @@
(define_insn ""
[(set (match_operand:DI 0 "general_operand" "=r,r,r,r,r,r,r,m,f,f,f,Q")
(match_operand:DI 1 "input_operand" "r,J,I,K,L,s,m,rJ,f,J,Q,fG"))]
- "register_operand (operands[0], DImode)
- || reg_or_0_operand (operands[1], DImode)"
+ "! TARGET_CIX
+ && (register_operand (operands[0], DImode)
+ || reg_or_0_operand (operands[1], DImode))"
"@
bis %1,%1,%0
bis $31,$31,%0
@@ -3136,7 +4265,30 @@
cpys $f31,$f31,%0
ldt %0,%1
stt %R1,%0"
- [(set_attr "type" "iaddlog,iaddlog,iaddlog,iaddlog,iaddlog,ldsym,ld,st,fpop,fpop,ld,st")])
+ [(set_attr "type" "ilog,ilog,ilog,iadd,iadd,ldsym,ild,ist,fcpys,fcpys,fld,fst")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "general_operand" "=r,r,r,r,r,r,r,m,f,f,f,Q,r,*f")
+ (match_operand:DI 1 "input_operand" "r,J,I,K,L,s,m,rJ,f,J,Q,fG,f,*r"))]
+ "TARGET_CIX
+ && (register_operand (operands[0], DImode)
+ || reg_or_0_operand (operands[1], DImode))"
+ "@
+ bis %1,%1,%0
+ bis $31,$31,%0
+ bis $31,%1,%0
+ lda %0,%1
+ ldah %0,%h1
+ lda %0,%1
+ ldq%A1 %0,%1
+ stq%A0 %r1,%0
+ cpys %1,%1,%0
+ cpys $f31,$f31,%0
+ ldt %0,%1
+ stt %R1,%0
+ ftoit %1,%0
+ itoft %1,%0"
+ [(set_attr "type" "ilog,ilog,ilog,iadd,iadd,ldsym,ild,ist,fcpys,fcpys,fld,fst,ftoi,itof")])
;; We do three major things here: handle mem->mem, put 64-bit constants in
;; memory, and construct long 32-bit constants.
@@ -3166,15 +4318,39 @@
}
else if (CONSTANT_P (operands[1]))
{
- operands[1] = force_const_mem (DImode, operands[1]);
- if (reload_in_progress)
+ if (TARGET_BUILD_CONSTANTS)
{
- emit_move_insn (operands[0], XEXP (operands[1], 0));
- operands[1] = copy_rtx (operands[1]);
- XEXP (operands[1], 0) = operands[0];
+#if HOST_BITS_PER_WIDE_INT == 64
+ HOST_WIDE_INT i;
+
+ if (GET_CODE (operands[1]) == CONST_INT)
+ i = INTVAL (operands[1]);
+ else if (GET_CODE (operands[1]) == CONST_DOUBLE)
+ i = CONST_DOUBLE_LOW (operands[1]);
+ else
+ abort();
+
+ tem = alpha_emit_set_long_const (operands[0], i);
+ if (rtx_equal_p (tem, operands[0]))
+ DONE;
+ else
+ operands[1] = tem;
+#else
+ abort();
+#endif
}
else
- operands[1] = validize_mem (operands[1]);
+ {
+ operands[1] = force_const_mem (DImode, operands[1]);
+ if (reload_in_progress)
+ {
+ emit_move_insn (operands[0], XEXP (operands[1], 0));
+ operands[1] = copy_rtx (operands[1]);
+ XEXP (operands[1], 0) = operands[0];
+ }
+ else
+ operands[1] = validize_mem (operands[1]);
+ }
}
else
abort ();
@@ -3230,16 +4406,10 @@
""
"")
-;; Similar for unaligned loads. For QImode, we use the sequence from the
-;; Alpha Architecture manual. However, for HImode, we do not. HImode pointers
-;; are normally aligned to the byte boundary, so an HImode object cannot
-;; cross a longword boundary. We could use a sequence similar to that for
-;; QImode, but that would fail if the pointer, was, in fact, not aligned.
-;; Instead, we clear bit 1 in the address and do an ldl. If the low-order
-;; bit was not aligned, this will trap and the trap handler will do what is
-;; needed.
+;; Similar for unaligned loads, where we use the sequence from the
+;; Alpha Architecture manual.
;;
-;; Here operand 1 is the address. Operands 2 and 3 are temporaries, where
+;; Operand 1 is the address. Operands 2 and 3 are temporaries, where
;; operand 3 can overlap the input and output registers.
(define_expand "unaligned_loadqi"
@@ -3255,26 +4425,19 @@
""
"")
-;; For this, the address must already be in a register. We also need two
-;; DImode temporaries, neither of which may overlap the input (and hence the
-;; output, since they might be the same register), but both of which may
-;; be the same.
-
(define_expand "unaligned_loadhi"
[(set (match_operand:DI 2 "register_operand" "")
- (and:DI (match_operand:DI 1 "register_operand" "")
- (const_int -7)))
+ (mem:DI (and:DI (match_operand:DI 1 "address_operand" "")
+ (const_int -8))))
(set (match_operand:DI 3 "register_operand" "")
- (mem:DI (match_dup 2)))
- (set (match_operand:DI 4 "register_operand" "")
- (and:DI (match_dup 1) (const_int -2)))
- (set (subreg:DI (match_operand:HI 0 "register_operand" "") 0)
- (zero_extract:DI (match_dup 3)
+ (match_dup 1))
+ (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+ (zero_extract:DI (match_dup 2)
(const_int 16)
- (ashift:DI (match_dup 4) (const_int 3))))]
+ (ashift:DI (match_dup 3) (const_int 3))))]
""
"")
-
+
;; Storing an aligned byte or word requires two temporaries. Operand 0 is the
;; aligned SImode MEM. Operand 1 is the register containing the
;; byte or word to store. Operand 2 is the number of bits within the word that
@@ -3297,8 +4460,8 @@
<< INTVAL (operands[2])));
}")
-;; For the unaligned byte case, we use code similar to that in the
-;; Architecture book, but reordered to lower the number of registers
+;; For the unaligned byte and halfword cases, we use code similar to that
+;; in the ;; Architecture book, but reordered to lower the number of registers
;; required. Operand 0 is the address. Operand 1 is the data to store.
;; Operands 2, 3, and 4 are DImode temporaries, where operands 2 and 4 may
;; be the same temporary, if desired. If the address is in a register,
@@ -3323,42 +4486,22 @@
""
"")
-;; This is the code for storing into an unaligned short. It uses the same
-;; trick as loading from an unaligned short. It needs lots of temporaries.
-;; However, during reload, we only have two registers available. So we
-;; repeat code so that only two temporaries are available. During RTL
-;; generation, we can use different pseudos for each temporary and CSE
-;; will remove the redundancies. During reload, we have to settle with
-;; what we get. Luckily, unaligned accesses of this kind produced during
-;; reload are quite rare.
-;;
-;; Operand 0 is the address of the memory location. Operand 1 contains the
-;; data to store. The rest of the operands are all temporaries, with
-;; various overlap possibilities during reload. See reload_outhi for
-;; details of this use.
-
(define_expand "unaligned_storehi"
- [(set (match_operand:DI 2 "register_operand" "")
- (match_operand:DI 0 "address_operand" ""))
- (set (match_operand:DI 3 "register_operand" "")
- (and:DI (match_dup 2) (const_int -7)))
- (set (match_operand:DI 4 "register_operand" "")
- (mem:DI (match_dup 3)))
- (set (match_operand:DI 10 "register_operand" "")
- (and:DI (match_dup 2) (const_int -2)))
- (set (match_operand:DI 5 "register_operand" "")
+ [(set (match_operand:DI 3 "register_operand" "")
+ (mem:DI (and:DI (match_operand:DI 0 "address_operand" "")
+ (const_int -8))))
+ (set (match_operand:DI 2 "register_operand" "")
+ (match_dup 0))
+ (set (match_dup 3)
(and:DI (not:DI (ashift:DI (const_int 65535)
- (ashift:DI (match_dup 10) (const_int 3))))
- (match_dup 4)))
- (set (match_operand:DI 6 "register_operand" "")
+ (ashift:DI (match_dup 2) (const_int 3))))
+ (match_dup 3)))
+ (set (match_operand:DI 4 "register_operand" "")
(ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" ""))
- (ashift:DI (match_dup 10) (const_int 3))))
- (set (match_operand:DI 7 "register_operand" "")
- (ior:DI (match_dup 5) (match_dup 6)))
- (set (match_operand:DI 8 "register_operand" "") (match_dup 0))
- (set (match_operand:DI 9 "register_operand" "")
- (and:DI (match_dup 8) (const_int -7)))
- (set (mem:DI (match_dup 9)) (match_dup 7))]
+ (ashift:DI (match_dup 2) (const_int 3))))
+ (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3)))
+ (set (mem:DI (and:DI (match_dup 0) (const_int -8)))
+ (match_dup 4))]
""
"")
@@ -3371,7 +4514,25 @@
(match_operand:QI 1 "general_operand" ""))]
""
"
-{ extern rtx get_unaligned_address ();
+{
+ if (TARGET_BWX)
+ {
+ if (GET_CODE (operands[0]) == MEM
+ && ! reg_or_0_operand (operands[1], QImode))
+ operands[1] = force_reg (QImode, operands[1]);
+
+ if (GET_CODE (operands[1]) == CONST_INT
+ && ! input_operand (operands[1], QImode))
+ {
+ operands[1] = alpha_emit_set_const (operands[0], QImode,
+ INTVAL (operands[1]), 3);
+
+ if (rtx_equal_p (operands[0], operands[1]))
+ DONE;
+ }
+
+ goto def;
+ }
/* If the output is not a register, the input must be. */
if (GET_CODE (operands[0]) == MEM)
@@ -3394,7 +4555,7 @@
{
rtx aligned_mem, bitnum;
rtx scratch = (reload_in_progress
- ? gen_rtx (REG, SImode, REGNO (operands[0]))
+ ? gen_rtx_REG (SImode, REGNO (operands[0]))
: gen_reg_rtx (SImode));
get_aligned_mem (operands[1], &aligned_mem, &bitnum);
@@ -3410,9 +4571,10 @@
rtx temp1 = gen_reg_rtx (DImode);
rtx temp2 = gen_reg_rtx (DImode);
- rtx seq = gen_unaligned_loadqi (operands[0],
- get_unaligned_address (operands[1]),
- temp1, temp2);
+ rtx seq
+ = gen_unaligned_loadqi (operands[0],
+ get_unaligned_address (operands[1], 0),
+ temp1, temp2);
alpha_set_memflags (seq, operands[1]);
emit_insn (seq);
@@ -3446,7 +4608,8 @@
rtx temp1 = gen_reg_rtx (DImode);
rtx temp2 = gen_reg_rtx (DImode);
rtx temp3 = gen_reg_rtx (DImode);
- rtx seq = gen_unaligned_storeqi (get_unaligned_address (operands[0]),
+ rtx seq
+ = gen_unaligned_storeqi (get_unaligned_address (operands[0], 0),
operands[1], temp1, temp2, temp3);
alpha_set_memflags (seq, operands[0]);
@@ -3454,6 +4617,7 @@
}
DONE;
}
+ def:;
}")
(define_expand "movhi"
@@ -3461,7 +4625,25 @@
(match_operand:HI 1 "general_operand" ""))]
""
"
-{ extern rtx get_unaligned_address ();
+{
+ if (TARGET_BWX)
+ {
+ if (GET_CODE (operands[0]) == MEM
+ && ! reg_or_0_operand (operands[1], HImode))
+ operands[1] = force_reg (HImode, operands[1]);
+
+ if (GET_CODE (operands[1]) == CONST_INT
+ && ! input_operand (operands[1], HImode))
+ {
+ operands[1] = alpha_emit_set_const (operands[0], HImode,
+ INTVAL (operands[1]), 3);
+
+ if (rtx_equal_p (operands[0], operands[1]))
+ DONE;
+ }
+
+ goto def;
+ }
/* If the output is not a register, the input must be. */
if (GET_CODE (operands[0]) == MEM)
@@ -3484,7 +4666,7 @@
{
rtx aligned_mem, bitnum;
rtx scratch = (reload_in_progress
- ? gen_rtx (REG, SImode, REGNO (operands[0]))
+ ? gen_rtx_REG (SImode, REGNO (operands[0]))
: gen_reg_rtx (SImode));
get_aligned_mem (operands[1], &aligned_mem, &bitnum);
@@ -3494,16 +4676,16 @@
}
else
{
- rtx addr
- = force_reg (DImode,
- force_operand (get_unaligned_address (operands[1]),
- NULL_RTX));
- rtx scratch1 = gen_reg_rtx (DImode);
- rtx scratch2 = gen_reg_rtx (DImode);
- rtx scratch3 = gen_reg_rtx (DImode);
+ /* Don't pass these as parameters since that makes the generated
+ code depend on parameter evaluation order which will cause
+ bootstrap failures. */
- rtx seq = gen_unaligned_loadhi (operands[0], addr, scratch1,
- scratch2, scratch3);
+ rtx temp1 = gen_reg_rtx (DImode);
+ rtx temp2 = gen_reg_rtx (DImode);
+ rtx seq
+ = gen_unaligned_loadhi (operands[0],
+ get_unaligned_address (operands[1], 0),
+ temp1, temp2);
alpha_set_memflags (seq, operands[1]);
emit_insn (seq);
@@ -3537,17 +4719,9 @@
rtx temp1 = gen_reg_rtx (DImode);
rtx temp2 = gen_reg_rtx (DImode);
rtx temp3 = gen_reg_rtx (DImode);
- rtx temp4 = gen_reg_rtx (DImode);
- rtx temp5 = gen_reg_rtx (DImode);
- rtx temp6 = gen_reg_rtx (DImode);
- rtx temp7 = gen_reg_rtx (DImode);
- rtx temp8 = gen_reg_rtx (DImode);
- rtx temp9 = gen_reg_rtx (DImode);
-
- rtx seq = gen_unaligned_storehi (get_unaligned_address (operands[0]),
- operands[1], temp1, temp2,temp3,
- temp4, temp5, temp6,temp7,
- temp8, temp9);
+ rtx seq
+ = gen_unaligned_storehi (get_unaligned_address (operands[0], 0),
+ operands[1], temp1, temp2, temp3);
alpha_set_memflags (seq, operands[0]);
emit_insn (seq);
@@ -3555,6 +4729,7 @@
DONE;
}
+ def:;
}")
;; Here are the versions for reload. Note that in the unaligned cases
@@ -3565,18 +4740,20 @@
[(parallel [(match_operand:QI 0 "register_operand" "=r")
(match_operand:QI 1 "unaligned_memory_operand" "m")
(match_operand:TI 2 "register_operand" "=&r")])]
- ""
+ "! TARGET_BWX"
"
-{ extern rtx get_unaligned_address ();
- rtx addr = get_unaligned_address (operands[1]);
+{
+ rtx addr = get_unaligned_address (operands[1], 0);
+
/* It is possible that one of the registers we got for operands[2]
might coincide with that of operands[0] (which is why we made
it TImode). Pick the other one to use as our scratch. */
- rtx scratch = gen_rtx (REG, DImode,
- REGNO (operands[0]) == REGNO (operands[2])
- ? REGNO (operands[2]) + 1 : REGNO (operands[2]));
+ rtx scratch = gen_rtx_REG (DImode,
+ REGNO (operands[0]) == REGNO (operands[2])
+ ? REGNO (operands[2]) + 1 : REGNO (operands[2]));
+
rtx seq = gen_unaligned_loadqi (operands[0], addr, scratch,
- gen_rtx (REG, DImode, REGNO (operands[0])));
+ gen_rtx_REG (DImode, REGNO (operands[0])));
alpha_set_memflags (seq, operands[1]);
emit_insn (seq);
@@ -3587,21 +4764,21 @@
[(parallel [(match_operand:HI 0 "register_operand" "=r")
(match_operand:HI 1 "unaligned_memory_operand" "m")
(match_operand:TI 2 "register_operand" "=&r")])]
- ""
+ "! TARGET_BWX"
"
-{ extern rtx get_unaligned_address ();
- rtx addr = get_unaligned_address (operands[1]);
- rtx scratch1 = gen_rtx (REG, DImode, REGNO (operands[2]));
- rtx scratch2 = gen_rtx (REG, DImode, REGNO (operands[2]) + 1);
- rtx seq;
+{
+ rtx addr = get_unaligned_address (operands[1], 0);
+
+ /* It is possible that one of the registers we got for operands[2]
+ might coincide with that of operands[0] (which is why we made
+ it TImode). Pick the other one to use as our scratch. */
+ rtx scratch = gen_rtx_REG (DImode,
+ REGNO (operands[0]) == REGNO (operands[2])
+ ? REGNO (operands[2]) + 1 : REGNO (operands[2]));
+
+ rtx seq = gen_unaligned_loadhi (operands[0], addr, scratch,
+ gen_rtx_REG (DImode, REGNO (operands[0])));
- if (GET_CODE (addr) != REG)
- {
- emit_insn (gen_rtx (SET, VOIDmode, scratch2, addr));
- addr = scratch2;
- }
-
- seq = gen_unaligned_loadhi (operands[0], addr, scratch1, scratch1, scratch2);
alpha_set_memflags (seq, operands[1]);
emit_insn (seq);
DONE;
@@ -3611,10 +4788,9 @@
[(parallel [(match_operand:QI 0 "any_memory_operand" "=m")
(match_operand:QI 1 "register_operand" "r")
(match_operand:TI 2 "register_operand" "=&r")])]
- ""
+ "! TARGET_BWX"
"
-{ extern rtx get_unaligned_address ();
-
+{
if (aligned_memory_operand (operands[0], QImode))
{
rtx aligned_mem, bitnum;
@@ -3622,15 +4798,15 @@
get_aligned_mem (operands[0], &aligned_mem, &bitnum);
emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum,
- gen_rtx (REG, SImode, REGNO (operands[2])),
- gen_rtx (REG, SImode,
- REGNO (operands[2]) + 1)));
+ gen_rtx_REG (SImode, REGNO (operands[2])),
+ gen_rtx_REG (SImode,
+ REGNO (operands[2]) + 1)));
}
else
{
- rtx addr = get_unaligned_address (operands[0]);
- rtx scratch1 = gen_rtx (REG, DImode, REGNO (operands[2]));
- rtx scratch2 = gen_rtx (REG, DImode, REGNO (operands[2]) + 1);
+ rtx addr = get_unaligned_address (operands[0], 0);
+ rtx scratch1 = gen_rtx_REG (DImode, REGNO (operands[2]));
+ rtx scratch2 = gen_rtx_REG (DImode, REGNO (operands[2]) + 1);
rtx scratch3 = scratch1;
rtx seq;
@@ -3650,10 +4826,9 @@
[(parallel [(match_operand:HI 0 "any_memory_operand" "=m")
(match_operand:HI 1 "register_operand" "r")
(match_operand:TI 2 "register_operand" "=&r")])]
- ""
+ "! TARGET_BWX"
"
-{ extern rtx get_unaligned_address ();
-
+{
if (aligned_memory_operand (operands[0], HImode))
{
rtx aligned_mem, bitnum;
@@ -3661,22 +4836,23 @@
get_aligned_mem (operands[0], &aligned_mem, &bitnum);
emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum,
- gen_rtx (REG, SImode, REGNO (operands[2])),
- gen_rtx (REG, SImode,
- REGNO (operands[2]) + 1)));
+ gen_rtx_REG (SImode, REGNO (operands[2])),
+ gen_rtx_REG (SImode,
+ REGNO (operands[2]) + 1)));
}
else
{
- rtx addr = get_unaligned_address (operands[0]);
- rtx scratch1 = gen_rtx (REG, DImode, REGNO (operands[2]));
- rtx scratch2 = gen_rtx (REG, DImode, REGNO (operands[2]) + 1);
- rtx scratch_a = GET_CODE (addr) == REG ? addr : scratch1;
+ rtx addr = get_unaligned_address (operands[0], 0);
+ rtx scratch1 = gen_rtx_REG (DImode, REGNO (operands[2]));
+ rtx scratch2 = gen_rtx_REG (DImode, REGNO (operands[2]) + 1);
+ rtx scratch3 = scratch1;
rtx seq;
- seq = gen_unaligned_storehi (addr, operands[1], scratch_a,
- scratch2, scratch2, scratch2,
- scratch1, scratch2, scratch_a,
- scratch1, scratch_a);
+ if (GET_CODE (addr) == REG)
+ scratch1 = addr;
+
+ seq = gen_unaligned_storehi (addr, operands[1], scratch1,
+ scratch2, scratch3);
alpha_set_memflags (seq, operands[0]);
emit_insn (seq);
}
@@ -3684,14 +4860,133 @@
DONE;
}")
+;; Bit field extract patterns which use ext[wlq][lh]
+
+(define_expand "extv"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (sign_extract:DI (match_operand:QI 1 "memory_operand" "")
+ (match_operand:DI 2 "immediate_operand" "")
+ (match_operand:DI 3 "immediate_operand" "")))]
+ ""
+ "
+{
+ /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */
+ if (INTVAL (operands[3]) % 8 != 0
+ || (INTVAL (operands[2]) != 16
+ && INTVAL (operands[2]) != 32
+ && INTVAL (operands[2]) != 64))
+ FAIL;
+
+ /* From mips.md: extract_bit_field doesn't verify that our source
+ matches the predicate, so we force it to be a MEM here. */
+ if (GET_CODE (operands[1]) != MEM)
+ FAIL;
+
+ alpha_expand_unaligned_load (operands[0], operands[1],
+ INTVAL (operands[2]) / 8,
+ INTVAL (operands[3]) / 8, 1);
+ DONE;
+}")
+
+(define_expand "extzv"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extract:DI (match_operand:DI 1 "general_operand" "")
+ (match_operand:DI 2 "immediate_operand" "")
+ (match_operand:DI 3 "immediate_operand" "")))]
+ ""
+ "
+{
+ /* We can do 8, 16, 32 and 64 bit fields, if aligned on byte boundaries. */
+ if (INTVAL (operands[3]) % 8 != 0
+ || (INTVAL (operands[2]) != 8
+ && INTVAL (operands[2]) != 16
+ && INTVAL (operands[2]) != 32
+ && INTVAL (operands[2]) != 64))
+ FAIL;
+
+ if (GET_CODE (operands[1]) == MEM)
+ {
+ /* Fail 8 bit fields, falling back on a simple byte load. */
+ if (INTVAL (operands[2]) == 8)
+ FAIL;
+
+ alpha_expand_unaligned_load (operands[0], operands[1],
+ INTVAL (operands[2]) / 8,
+ INTVAL (operands[3]) / 8, 0);
+ DONE;
+ }
+}")
+
+(define_expand "insv"
+ [(set (zero_extract:DI (match_operand:QI 0 "memory_operand" "")
+ (match_operand:DI 1 "immediate_operand" "")
+ (match_operand:DI 2 "immediate_operand" ""))
+ (match_operand:DI 3 "register_operand" ""))]
+ ""
+ "
+{
+ /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries. */
+ if (INTVAL (operands[2]) % 8 != 0
+ || (INTVAL (operands[1]) != 16
+ && INTVAL (operands[1]) != 32
+ && INTVAL (operands[1]) != 64))
+ FAIL;
+
+ /* From mips.md: store_bit_field doesn't verify that our source
+ matches the predicate, so we force it to be a MEM here. */
+ if (GET_CODE (operands[0]) != MEM)
+ FAIL;
+
+ alpha_expand_unaligned_store (operands[0], operands[3],
+ INTVAL (operands[1]) / 8,
+ INTVAL (operands[2]) / 8);
+ DONE;
+}")
+
+
+
+;; Block move/clear, see alpha.c for more details.
+;; Argument 0 is the destination
+;; Argument 1 is the source
+;; Argument 2 is the length
+;; Argument 3 is the alignment
+
+(define_expand "movstrqi"
+ [(parallel [(set (match_operand:BLK 0 "general_operand" "")
+ (match_operand:BLK 1 "general_operand" ""))
+ (use (match_operand:DI 2 "immediate_operand" ""))
+ (use (match_operand:DI 3 "immediate_operand" ""))])]
+ ""
+ "
+{
+ if (alpha_expand_block_move (operands))
+ DONE;
+ else
+ FAIL;
+}")
+
+(define_expand "clrstrqi"
+ [(parallel [(set (match_operand:BLK 0 "general_operand" "")
+ (const_int 0))
+ (use (match_operand:DI 1 "immediate_operand" ""))
+ (use (match_operand:DI 2 "immediate_operand" ""))])]
+ ""
+ "
+{
+ if (alpha_expand_block_clear (operands))
+ DONE;
+ else
+ FAIL;
+}")
+
;; Subroutine of stack space allocation. Perform a stack probe.
(define_expand "probe_stack"
[(set (match_dup 1) (match_operand:DI 0 "const_int_operand" ""))]
""
"
{
- operands[1] = gen_rtx (MEM, DImode, plus_constant (stack_pointer_rtx,
- INTVAL (operands[0])));
+ operands[1] = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx,
+ INTVAL (operands[0])));
MEM_VOLATILE_P (operands[1]) = 1;
operands[0] = const0_rtx;
@@ -3706,14 +5001,16 @@
(define_expand "allocate_stack"
[(set (reg:DI 30)
(plus:DI (reg:DI 30)
- (match_operand:DI 0 "reg_or_cint_operand" "")))]
+ (match_operand:DI 1 "reg_or_cint_operand" "")))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (match_dup 2))]
""
"
{
- if (GET_CODE (operands[0]) == CONST_INT
- && INTVAL (operands[0]) < 32768)
+ if (GET_CODE (operands[1]) == CONST_INT
+ && INTVAL (operands[1]) < 32768)
{
- if (INTVAL (operands[0]) >= 4096)
+ if (INTVAL (operands[1]) >= 4096)
{
/* We do this the same way as in the prologue and generate explicit
probes. Then we update the stack by the constant. */
@@ -3721,14 +5018,15 @@
int probed = 4096;
emit_insn (gen_probe_stack (GEN_INT (- probed)));
- while (probed + 8192 < INTVAL (operands[0]))
+ while (probed + 8192 < INTVAL (operands[1]))
emit_insn (gen_probe_stack (GEN_INT (- (probed += 8192))));
- if (probed + 4096 < INTVAL (operands[0]))
- emit_insn (gen_probe_stack (GEN_INT (- INTVAL(operands[0]))));
+ if (probed + 4096 < INTVAL (operands[1]))
+ emit_insn (gen_probe_stack (GEN_INT (- INTVAL(operands[1]))));
}
- operands[0] = GEN_INT (- INTVAL (operands[0]));
+ operands[1] = GEN_INT (- INTVAL (operands[1]));
+ operands[2] = virtual_stack_dynamic_rtx;
}
else
{
@@ -3739,10 +5037,10 @@
rtx memref;
emit_insn (gen_subdi3 (want, stack_pointer_rtx,
- force_reg (Pmode, operands[0])));
+ force_reg (Pmode, operands[1])));
emit_insn (gen_adddi3 (tmp, stack_pointer_rtx, GEN_INT (-4096)));
- if (GET_CODE (operands[0]) != CONST_INT)
+ if (GET_CODE (operands[1]) != CONST_INT)
{
out_label = gen_label_rtx ();
emit_insn (gen_cmpdi (want, tmp));
@@ -3750,13 +5048,16 @@
}
emit_label (loop_label);
- memref = gen_rtx (MEM, DImode, tmp);
+ memref = gen_rtx_MEM (DImode, tmp);
MEM_VOLATILE_P (memref) = 1;
emit_move_insn (memref, const0_rtx);
emit_insn (gen_adddi3 (tmp, tmp, GEN_INT(-8192)));
emit_insn (gen_cmpdi (tmp, want));
emit_jump_insn (gen_bgtu (loop_label));
- memref = gen_rtx (MEM, DImode, want);
+ if (obey_regdecls)
+ gen_rtx_USE (VOIDmode, tmp);
+
+ memref = gen_rtx_MEM (DImode, want);
MEM_VOLATILE_P (memref) = 1;
emit_move_insn (memref, const0_rtx);
@@ -3764,7 +5065,160 @@
emit_label (out_label);
emit_move_insn (stack_pointer_rtx, want);
-
+ emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
DONE;
}
}")
+
+;; This is used by alpha_expand_prolog to do the same thing as above,
+;; except we cannot at that time generate new basic blocks, so we hide
+;; the loop in this one insn.
+
+(define_insn "prologue_stack_probe_loop"
+ [(unspec_volatile [(match_operand 0 "register_operand" "r")
+ (match_operand 1 "register_operand" "r")] 5)]
+ ""
+ "*
+{
+ static int label_no;
+ int count_regno = REGNO (operands[0]);
+ int ptr_regno = REGNO (operands[1]);
+ char label[64];
+
+ /* Ho hum, output the hard way to get the label at the beginning of
+ the line. Wish there were a magic char you could get
+ asm_output_printf to do that. Then we could use %= as well and
+ get rid of the label_no bits here too. */
+
+ ASM_GENERATE_INTERNAL_LABEL (label, \"LSC\", label_no);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"LSC\", label_no++);
+
+ fprintf (asm_out_file, \"\\tstq $31,-8192($%d)\\n\", ptr_regno);
+ fprintf (asm_out_file, \"\\tsubq $%d,1,$%d\\n\", count_regno, count_regno);
+ fprintf (asm_out_file, \"\\tlda $%d,-8192($%d)\\n\", ptr_regno, ptr_regno);
+ fprintf (asm_out_file, \"\\tbne $%d,\", count_regno);
+ assemble_name (asm_out_file, label);
+ putc ('\\n', asm_out_file);
+
+ return \"\";
+}"
+ [(set_attr "length" "16")])
+
+(define_expand "prologue"
+ [(clobber (const_int 0))]
+ ""
+ "alpha_expand_prologue (); DONE;")
+
+(define_insn "init_fp"
+ [(set (match_operand:DI 0 "register_operand" "r")
+ (match_operand:DI 1 "register_operand" "r"))
+ (clobber (mem:BLK (match_operand:DI 2 "register_operand" "r")))]
+ ""
+ "bis %1,%1,%0")
+
+(define_expand "epilogue"
+ [(clobber (const_int 0))]
+ ""
+ "alpha_expand_epilogue (); DONE;")
+
+(define_expand "builtin_longjmp"
+ [(unspec_volatile [(match_operand 0 "register_operand" "r")] 3)]
+ "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT"
+ "
+{
+ /* The elements of the buffer are, in order: */
+ rtx fp = gen_rtx_MEM (Pmode, operands[0]);
+ rtx lab = gen_rtx_MEM (Pmode, plus_constant (operands[0], 8));
+ rtx stack = gen_rtx_MEM (Pmode, plus_constant (operands[0], 16));
+ rtx pv = gen_rtx_REG (Pmode, 27);
+
+ /* This bit is the same as expand_builtin_longjmp. */
+ emit_move_insn (hard_frame_pointer_rtx, fp);
+ emit_move_insn (pv, lab);
+ emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
+ emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
+ emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
+
+ /* Load the label we are jumping through into $27 so that we know
+ where to look for it when we get back to setjmp's function for
+ restoring the gp. */
+ emit_indirect_jump (pv);
+}")
+
+(define_insn "builtin_setjmp_receiver"
+ [(unspec_volatile [(match_operand 0 "" "")] 2)]
+ "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT && TARGET_AS_CAN_SUBTRACT_LABELS"
+ "\\n$LSJ%=:\;ldgp $29,$LSJ%=-%l0($27)"
+ [(set_attr "length" "8")])
+
+(define_insn ""
+ [(unspec_volatile [(match_operand 0 "" "")] 2)]
+ "! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT"
+ "br $27,$LSJ%=\\n$LSJ%=:\;ldgp $29,0($27)"
+ [(set_attr "length" "12")])
+
+(define_expand "nonlocal_goto_receiver"
+ [(unspec_volatile [(const_int 0)] 1)
+ (set (reg:DI 27) (mem:DI (reg:DI 29)))
+ (unspec_volatile [(const_int 0)] 1)
+ (use (reg:DI 27))]
+ "TARGET_OPEN_VMS"
+ "")
+
+(define_insn "arg_home"
+ [(unspec [(const_int 0)] 0)
+ (use (reg:DI 1))
+ (use (reg:DI 25))
+ (use (reg:DI 16))
+ (use (reg:DI 17))
+ (use (reg:DI 18))
+ (use (reg:DI 19))
+ (use (reg:DI 20))
+ (use (reg:DI 21))
+ (use (reg:DI 48))
+ (use (reg:DI 49))
+ (use (reg:DI 50))
+ (use (reg:DI 51))
+ (use (reg:DI 52))
+ (use (reg:DI 53))
+ (clobber (mem:BLK (const_int 0)))
+ (clobber (reg:DI 24))
+ (clobber (reg:DI 25))
+ (clobber (reg:DI 0))]
+ "TARGET_OPEN_VMS"
+ "lda $0,OTS$HOME_ARGS\;ldq $0,8($0)\;jsr $0,OTS$HOME_ARGS"
+ [(set_attr "length" "16")])
+
+;; Close the trap shadow of preceeding instructions. This is generated
+;; by alpha_reorg.
+
+(define_insn "trapb"
+ [(unspec_volatile [(const_int 0)] 4)]
+ ""
+ "trapb"
+ [(set_attr "type" "misc")])
+
+;; Peepholes go at the end.
+
+;; Optimize sign-extension of SImode loads. This shows up in the wake of
+;; reload when converting fp->int.
+;;
+;; ??? What to do now that we actually care about the packing and
+;; alignment of instructions? Perhaps reload can be enlightened, or
+;; the peephole pass moved up after reload but before sched2?
+;
+;(define_peephole
+; [(set (match_operand:SI 0 "register_operand" "=r")
+; (match_operand:SI 1 "memory_operand" "m"))
+; (set (match_operand:DI 2 "register_operand" "=r")
+; (sign_extend:DI (match_dup 0)))]
+; "dead_or_set_p (insn, operands[0])"
+; "ldl %2,%1")
+;
+;(define_peephole
+; [(set (match_operand:SI 0 "register_operand" "=r")
+; (match_operand:SI 1 "hard_fp_register_operand" "f"))
+; (set (match_operand:DI 2 "register_operand" "=r")
+; (sign_extend:DI (match_dup 0)))]
+; "TARGET_CIX && dead_or_set_p (insn, operands[0])"
+; "ftois %1,%2")
diff --git a/contrib/gcc/config/alpha/crtbegin.asm b/contrib/gcc/config/alpha/crtbegin.asm
new file mode 100644
index 0000000..c28440d
--- /dev/null
+++ b/contrib/gcc/config/alpha/crtbegin.asm
@@ -0,0 +1,111 @@
+ # Copyright (C) 1996, 1998 Free Software Foundation, Inc.
+ # Contributed by Richard Henderson (rth@tamu.edu)
+ #
+ # This file 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, or (at your option) any
+ # later version.
+ #
+ # In addition to the permissions in the GNU General Public License, the
+ # Free Software Foundation gives you unlimited permission to link the
+ # compiled version of this file with other programs, and to distribute
+ # those programs without any restriction coming from the use of this
+ # file. (The General Public License restrictions do apply in other
+ # respects; for example, they cover modification of the file, and
+ # distribution when not linked into another program.)
+ #
+ # This file 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; see the file COPYING. If not, write to
+ # the Free Software Foundation, 59 Temple Place - Suite 330,
+ # Boston, MA 02111-1307, USA.
+ #
+ # As a special exception, if you link this library with files
+ # compiled with GCC to produce an executable, this does not cause
+ # the resulting executable to be covered by the GNU General Public License.
+ # This exception does not however invalidate any other reasons why
+ # the executable file might be covered by the GNU General Public License.
+
+ #
+ # Heads of the constructor/destructor lists.
+ #
+
+ # The __*TOR_LIST__ symbols are not global because when this file is used
+ # in a shared library, we do not want the symbol to fall over to the
+ # application's lists.
+
+.section .ctors,"aw"
+
+ .align 3
+__CTOR_LIST__:
+ .quad -1
+
+.section .dtors,"aw"
+
+ .align 3
+__DTOR_LIST__:
+ .quad -1
+
+
+ #
+ # Fragment of the ELF _fini routine that invokes our dtor cleanup.
+ #
+
+.section .fini,"ax"
+
+ # Since the bits of the _fini function are spread across many
+ # object files, each potentially with its own GP, we must
+ # assume we need to load ours. Further, our .fini section
+ # can easily be more than 4MB away from our .text bits so we
+ # can't use bsr.
+
+ br $29,1f
+1: ldgp $29,0($29)
+ jsr $26,__do_global_dtors_aux
+
+ # Must match the alignment we got from crti.o else we get
+ # zero-filled holes in our _fini function and then SIGILL.
+ .align 3
+
+ #
+ # Invoke our destructors in order.
+ #
+
+.data
+
+ # Support recursive calls to exit.
+9: .quad __DTOR_LIST__
+
+.text
+
+ .align 3
+ .ent __do_global_dtors_aux
+
+__do_global_dtors_aux:
+ ldgp $29,0($27)
+ lda $30,-16($30)
+ .frame $30,16,$26,0
+ stq $9,8($30)
+ stq $26,0($30)
+ .mask 0x4000200,-16
+ .prologue 1
+
+ lda $9,9b
+ br 1f
+0: stq $1,0($9)
+ jsr $26,($27)
+1: ldq $1,0($9)
+ ldq $27,8($1)
+ addq $1,8,$1
+ bne $27,0b
+
+ ldq $26,0($30)
+ ldq $9,8($30)
+ lda $30,16($30)
+ ret
+
+ .end __do_global_dtors_aux
diff --git a/contrib/gcc/config/alpha/crtend.asm b/contrib/gcc/config/alpha/crtend.asm
new file mode 100644
index 0000000..36f11b9
--- /dev/null
+++ b/contrib/gcc/config/alpha/crtend.asm
@@ -0,0 +1,105 @@
+ # Copyright (C) 1996 Free Software Foundation, Inc.
+ # Contributed by Richard Henderson (rth@tamu.edu)
+ #
+ # This file 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, or (at your option) any
+ # later version.
+ #
+ # In addition to the permissions in the GNU General Public License, the
+ # Free Software Foundation gives you unlimited permission to link the
+ # compiled version of this file with other programs, and to distribute
+ # those programs without any restriction coming from the use of this
+ # file. (The General Public License restrictions do apply in other
+ # respects; for example, they cover modification of the file, and
+ # distribution when not linked into another program.)
+ #
+ # This file 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; see the file COPYING. If not, write to
+ # the Free Software Foundation, 59 Temple Place - Suite 330,
+ # Boston, MA 02111-1307, USA.
+ #
+ # As a special exception, if you link this library with files
+ # compiled with GCC to produce an executable, this does not cause
+ # the resulting executable to be covered by the GNU General Public License.
+ # This exception does not however invalidate any other reasons why
+ # the executable file might be covered by the GNU General Public License.
+
+ #
+ # Tails of the constructor/destructor lists.
+ #
+
+ # The __*TOR_END__ symbols are not global because when this file is used
+ # in a shared library, we do not want the symbol to fall over to the
+ # application's lists.
+
+.section .ctors,"aw"
+
+ .align 3
+__CTOR_END__:
+ .quad 0
+
+.section .dtors,"aw"
+
+ .align 3
+__DTOR_END__:
+ .quad 0
+
+
+ #
+ # Fragment of the ELF _init routine that invokes our ctor startup
+ #
+
+.section .init,"ax"
+
+ # Since the bits of the _init function are spread across many
+ # object files, each potentially with its own GP, we must
+ # assume we need to load ours. Further, our .init section
+ # can easily be more than 4MB away from our .text bits so we
+ # can't use bsr.
+
+ br $29,1f
+1: ldgp $29,0($29)
+ jsr $26,__do_global_ctors_aux
+
+ # Must match the alignment we got from crti.o else we get
+ # zero-filled holes in our _init function and thense SIGILL.
+ .align 3
+
+ #
+ # Invoke our destructors in order.
+ #
+
+.text
+
+ .align 3
+ .ent __do_global_ctors_aux
+
+__do_global_ctors_aux:
+ ldgp $29,0($27)
+ lda $30,-16($30)
+ .frame $30,16,$26,0
+ stq $9,8($30)
+ stq $26,0($30)
+ .mask 0x4000200,-16
+ .prologue 1
+
+ lda $9,__CTOR_END__
+ br 1f
+0: jsr $26,($27)
+1: ldq $27,-8($9)
+ subq $9,8,$9
+ not $27,$0
+ bne $0,0b
+
+ ldq $26,0($30)
+ ldq $9,8($30)
+ lda $30,16($30)
+ ret
+
+ .end __do_global_ctors_aux
diff --git a/contrib/gcc/config/alpha/elf.h b/contrib/gcc/config/alpha/elf.h
index 82f0410..4f4703c 100644
--- a/contrib/gcc/config/alpha/elf.h
+++ b/contrib/gcc/config/alpha/elf.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for DEC Alpha w/ELF.
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Richard Henderson (rth@tamu.edu).
This file is part of GNU CC.
@@ -19,53 +19,49 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* This is used on Alpha platforms that use the ELF format.
-Currently only Linux uses this. */
-
-#if 0
-#include "alpha/linux.h"
-#endif
-
-#undef TARGET_VERSION
-#define TARGET_VERSION fprintf (stderr, " (Alpha Linux/ELF)");
-
#undef OBJECT_FORMAT_COFF
#undef EXTENDED_COFF
#define OBJECT_FORMAT_ELF
-#define SDB_DEBUGGING_INFO
+#define DBX_DEBUGGING_INFO
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
#undef ASM_FINAL_SPEC
-#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "\
--D__alpha -D__alpha__ -D__linux__ -D__linux -D_LONGLONG -Dlinux -Dunix \
--Asystem(linux) -Acpu(alpha) -Amachine(alpha) -D__ELF__"
+#undef CC1_SPEC
+#define CC1_SPEC "%{G*}"
+
+#undef ASM_SPEC
+#define ASM_SPEC "%{G*} %{relax:-relax}"
#undef LINK_SPEC
-#define LINK_SPEC "-m elf64alpha -G 8 %{O*:-O3} %{!O*:-O1} \
+#define LINK_SPEC "-m elf64alpha %{G*} %{relax:-relax} \
+ %{O*:-O3} %{!O*:-O1} \
%{shared:-shared} \
%{!shared: \
%{!static: \
%{rdynamic:-export-dynamic} \
- %{!dynamic-linker:-dynamic-linker /lib/ld.so.1}} \
+ %{!dynamic-linker:-dynamic-linker %(elf_dynamic_linker)}} \
%{static:-static}}"
/* Output at beginning of assembler file. */
-
#undef ASM_FILE_START
#define ASM_FILE_START(FILE) \
{ \
alpha_write_verstamp (FILE); \
output_file_directive (FILE, main_input_filename); \
- fprintf (FILE, "\t.version\t\"01.01\"\n"); \
fprintf (FILE, "\t.set noat\n"); \
+ fprintf (FILE, "\t.set noreorder\n"); \
+ if (TARGET_BWX | TARGET_MAX | TARGET_CIX) \
+ { \
+ fprintf (FILE, "\t.arch %s\n", \
+ (alpha_cpu == PROCESSOR_EV6 ? "ev6" \
+ : TARGET_MAX ? "pca56" : "ev56")); \
+ } \
}
-#define ASM_OUTPUT_SOURCE_LINE(STREAM, LINE) \
- alpha_output_lineno (STREAM, LINE)
-extern void alpha_output_lineno ();
-
extern void output_file_directive ();
/* Attach a special .ident directive to the end of the file to identify
@@ -77,8 +73,8 @@ extern void output_file_directive ();
#ifdef IDENTIFY_WITH_IDENT
#define ASM_IDENTIFY_GCC(FILE) /* nothing */
-#define ASM_IDENTIFY_LANGUAGE(FILE) \
- fprintf(FILE, "\t%s \"GCC (%s) %s\"\n", IDENT_ASM_OP, \
+#define ASM_IDENTIFY_LANGUAGE(FILE) \
+ fprintf(FILE, "\t%s \"GCC (%s) %s\"\n", IDENT_ASM_OP, \
lang_identify(), version_string)
#else
#define ASM_FILE_END(FILE) \
@@ -89,11 +85,9 @@ do { \
#endif
/* Allow #sccs in preprocessor. */
-
#define SCCS_DIRECTIVE
/* Output #ident as a .ident. */
-
#define ASM_OUTPUT_IDENT(FILE, NAME) \
fprintf (FILE, "\t%s\t\"%s\"\n", IDENT_ASM_OP, NAME);
@@ -155,22 +149,46 @@ do { \
the linker seems to want the alignment of data objects
to depend on their types. We do exactly that here. */
-#define LOCAL_ASM_OP ".local"
-
#undef ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
do { \
- fprintf ((FILE), "\t%s\t", LOCAL_ASM_OP); \
- assemble_name ((FILE), (NAME)); \
- fprintf ((FILE), "\n"); \
- ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN); \
+ if ((SIZE) <= g_switch_value) \
+ sbss_section(); \
+ else \
+ bss_section(); \
+ fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ putc (',', FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
+ putc ('\n', FILE); \
+ if (!flag_inhibit_size_directive) \
+ { \
+ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ",%d\n", (SIZE)); \
+ } \
+ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \
+ ASM_OUTPUT_LABEL(FILE, NAME); \
+ ASM_OUTPUT_SKIP((FILE), (SIZE)); \
} while (0)
/* This is the pseudo-op used to generate a 64-bit word of data with a
- specific value in some section. */
+ specific value in some section. */
#define INT_ASM_OP ".quad"
+/* Biggest alignment supported by the object file format of this
+ machine. Use this macro to limit the alignment which can be
+ specified using the `__attribute__ ((aligned (N)))' construct. If
+ not defined, the default value is `BIGGEST_ALIGNMENT'.
+
+ This value is really 2^63. Since gcc figures the alignment in bits,
+ we could only potentially get to 2^60 on suitible hosts. Due to other
+ considerations in varasm, we must restrict this to what fits in an int. */
+
+#define MAX_OFILE_ALIGNMENT \
+ (1 << (HOST_BITS_PER_INT < 64 ? HOST_BITS_PER_INT - 2 : 62))
+
/* This is the pseudo-op used to generate a contiguous sequence of byte
values from a double-quoted string WITHOUT HAVING A TERMINATING NUL
AUTOMATICALLY APPENDED. This is the same for most svr4 assemblers. */
@@ -208,6 +226,11 @@ do { \
#define CTORS_SECTION_ASM_OP ".section\t.ctors,\"aw\""
#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"aw\""
+/* Handle the small data sections. */
+#define BSS_SECTION_ASM_OP ".section\t.bss"
+#define SBSS_SECTION_ASM_OP ".section\t.sbss,\"aw\""
+#define SDATA_SECTION_ASM_OP ".section\t.sdata,\"aw\""
+
/* On svr4, we *do* have support for the .init and .fini sections, and we
can put stuff in there to be executed before and after `main'. We let
crtstuff.c and other files know this by defining the following symbols.
@@ -217,17 +240,13 @@ do { \
#define INIT_SECTION_ASM_OP ".section\t.init"
#define FINI_SECTION_ASM_OP ".section\t.fini"
-/* Support non-common, uninitialized data in the .bss section. */
-
-#define BSS_SECTION_ASM_OP ".section\t.bss"
-
/* A default list of other sections which we might be "in" at any given
time. For targets that use additional sections (e.g. .tdesc) you
should override this definition in the target-specific file which
includes this file. */
#undef EXTRA_SECTIONS
-#define EXTRA_SECTIONS in_const, in_ctors, in_dtors, in_bss
+#define EXTRA_SECTIONS in_const, in_ctors, in_dtors, in_sbss, in_sdata
/* A default list of extra section function definitions. For targets
that use additional sections (e.g. .tdesc) you should override this
@@ -236,9 +255,10 @@ do { \
#undef EXTRA_SECTION_FUNCTIONS
#define EXTRA_SECTION_FUNCTIONS \
CONST_SECTION_FUNCTION \
- CTORS_SECTION_FUNCTION \
- DTORS_SECTION_FUNCTION \
- BSS_SECTION_FUNCTION
+ SECTION_FUNCTION_TEMPLATE(ctors_section, in_ctors, CTORS_SECTION_ASM_OP) \
+ SECTION_FUNCTION_TEMPLATE(dtors_section, in_dtors, DTORS_SECTION_ASM_OP) \
+ SECTION_FUNCTION_TEMPLATE(sbss_section, in_sbss, SBSS_SECTION_ASM_OP) \
+ SECTION_FUNCTION_TEMPLATE(sdata_section, in_sdata, SDATA_SECTION_ASM_OP)
#undef READONLY_DATA_SECTION
#define READONLY_DATA_SECTION() const_section ()
@@ -258,36 +278,13 @@ const_section () \
} \
}
-#define CTORS_SECTION_FUNCTION \
-void \
-ctors_section () \
+#define SECTION_FUNCTION_TEMPLATE(FN, ENUM, OP) \
+void FN () \
{ \
- if (in_section != in_ctors) \
+ if (in_section != ENUM) \
{ \
- fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \
- in_section = in_ctors; \
- } \
-}
-
-#define DTORS_SECTION_FUNCTION \
-void \
-dtors_section () \
-{ \
- if (in_section != in_dtors) \
- { \
- fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \
- in_section = in_dtors; \
- } \
-}
-
-#define BSS_SECTION_FUNCTION \
-void \
-bss_section () \
-{ \
- if (in_section != in_bss) \
- { \
- fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP); \
- in_section = in_bss; \
+ fprintf (asm_out_file, "%s\n", OP); \
+ in_section = ENUM; \
} \
}
@@ -297,10 +294,10 @@ bss_section () \
We make the section read-only and executable for a function decl,
read-only for a const data decl, and writable for a non-const data decl. */
-#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME) \
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
fprintf (FILE, ".section\t%s,\"%s\",@progbits\n", NAME, \
(DECL) && TREE_CODE (DECL) == FUNCTION_DECL ? "ax" : \
- (DECL) && TREE_READONLY (DECL) ? "a" : "aw")
+ (DECL) && DECL_READONLY_SECTION (DECL, RELOC) ? "a" : "aw")
/* A C statement (sans semicolon) to output an element in the table of
@@ -344,11 +341,10 @@ bss_section () \
|| !DECL_INITIAL (DECL) \
|| (DECL_INITIAL (DECL) != error_mark_node \
&& !TREE_CONSTANT (DECL_INITIAL (DECL)))) \
- { \
- if (DECL_COMMON (DECL) \
- && !DECL_INITIAL (DECL)) \
- /* || DECL_INITIAL (DECL) == error_mark_node)) */ \
- bss_section(); \
+ { \
+ int size = int_size_in_bytes (TREE_TYPE (DECL)); \
+ if (size >= 0 && size <= g_switch_value) \
+ sdata_section (); \
else \
data_section (); \
} \
@@ -486,39 +482,39 @@ do { \
escape sequence like \377 would count as four bytes.
If your target assembler doesn't support the .string directive, you
- should define this to zero.
-*/
+ should define this to zero. */
#define STRING_LIMIT ((unsigned) 256)
-
#define STRING_ASM_OP ".string"
-/*
- * We always use gas here, so we don't worry about ECOFF assembler problems.
- */
+/* GAS is the only Alpha/ELF assembler. */
#undef TARGET_GAS
#define TARGET_GAS (1)
-#undef PREFERRED_DEBUGGING_TYPE
-#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+/* Provide a STARTFILE_SPEC appropriate for ELF. Here we add the
+ (even more) magical crtbegin.o file which provides part of the
+ support for getting C++ file-scope static object constructed before
+ entering `main'.
-/* Provide a STARTFILE_SPEC appropriate for Linux. Here we add
- the Linux magical crtbegin.o file (see crtstuff.c) which
- provides part of the support for getting C++ file-scope static
- object constructed before entering `main'. */
+ Don't bother seeing crtstuff.c -- there is absolutely no hope of
+ getting that file to understand multiple GPs. GNU Libc provides a
+ hand-coded version that is used on Linux; it could be copied here
+ if there is ever a need. */
#undef STARTFILE_SPEC
#define STARTFILE_SPEC \
"%{!shared: \
%{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}}\
- crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}"
+ crti.o%s crtbegin.o%s"
-/* Provide a ENDFILE_SPEC appropriate for Linux. Here we tack on
- the Linux magical crtend.o file (see crtstuff.c) which
- provides part of the support for getting C++ file-scope static
- object constructed before entering `main', followed by a normal
- Linux "finalizer" file, `crtn.o'. */
+/* Provide a ENDFILE_SPEC appropriate for ELF. Here we tack on the
+ magical crtend.o file which provides part of the support for
+ getting C++ file-scope static object constructed before entering
+ `main', followed by a normal ELF "finalizer" file, `crtn.o'. */
#undef ENDFILE_SPEC
#define ENDFILE_SPEC \
- "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s"
+ "crtend.o%s crtn.o%s"
+
+/* We support #pragma. */
+#define HANDLE_SYSV_PRAGMA
diff --git a/contrib/gcc/config/alpha/linux-ecoff.h b/contrib/gcc/config/alpha/linux-ecoff.h
new file mode 100644
index 0000000..a6cd5b2
--- /dev/null
+++ b/contrib/gcc/config/alpha/linux-ecoff.h
@@ -0,0 +1,36 @@
+/* Definitions of target machine for GNU compiler
+ for Alpha Linux-based GNU systems using ECOFF.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Bob Manson.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (Alpha GNU/Linux for ECOFF)");
+
+#undef SUB_CPP_PREDEFINES
+#define SUB_CPP_PREDEFINES "-D__ECOFF__"
+
+#undef LINK_SPEC
+#define LINK_SPEC "-G 8 %{O*:-O3} %{!O*:-O1}"
+
+/* stabs get slurped by the assembler into a queer ecoff format. */
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+/* We support #pragma. */
+#define HANDLE_SYSV_PRAGMA
diff --git a/contrib/gcc/config/alpha/linux-elf.h b/contrib/gcc/config/alpha/linux-elf.h
new file mode 100644
index 0000000..90009f1
--- /dev/null
+++ b/contrib/gcc/config/alpha/linux-elf.h
@@ -0,0 +1,47 @@
+/* Definitions of target machine for GNU compiler
+ for Alpha Linux-based GNU systems using ELF.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Richard Henderson.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (Alpha GNU/Linux for ELF)");
+
+#undef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS \
+{ "elf_dynamic_linker", ELF_DYNAMIC_LINKER },
+
+#undef SUB_CPP_PREDEFINES
+#define SUB_CPP_PREDEFINES "-D__ELF__"
+
+#ifdef USE_GNULIBC_1
+#define ELF_DYNAMIC_LINKER "/lib/ld.so.1"
+#else
+#define ELF_DYNAMIC_LINKER "/lib/ld-linux.so.2"
+#endif
+
+#ifndef USE_GNULIBC_1
+#undef DEFAULT_VTABLE_THUNKS
+#define DEFAULT_VTABLE_THUNKS 1
+#endif
+
+#ifndef USE_GNULIBC_1
+#undef LIB_SPEC
+#define LIB_SPEC \
+"%{shared:-lc}%{!shared:%{pthread:-lpthread }%{profile:-lc_p}%{!profile:-lc}} "
+#endif
diff --git a/contrib/gcc/config/alpha/linux.h b/contrib/gcc/config/alpha/linux.h
new file mode 100644
index 0000000..3791c89
--- /dev/null
+++ b/contrib/gcc/config/alpha/linux.h
@@ -0,0 +1,44 @@
+/* Definitions of target machine for GNU compiler,
+ for Alpha Linux-based GNU systems.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Richard Henderson.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_FP | MASK_FPREGS | MASK_GAS)
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+"-Dlinux -Dunix -Asystem(linux) -D_LONGLONG -D__alpha__ " SUB_CPP_PREDEFINES
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{pg:-lgmon} %{pg:-lc_p} %{!pg:-lc}"
+
+/* Generate calls to memcpy, etc., not bcopy, etc. */
+#define TARGET_MEM_FUNCTIONS 1
+
+#undef FUNCTION_PROFILER
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ fputs ("\tlda $28,_mcount\n\tjsr $28,($28),_mcount\n", (FILE))
+
+/* Show that we need a GP when profiling. */
+#define TARGET_PROFILING_NEEDS_GP 1
+
+/* Don't care about faults in the prologue. */
+#undef TARGET_CAN_FAULT_IN_PROLOGUE
+#define TARGET_CAN_FAULT_IN_PROLOGUE 1
diff --git a/contrib/gcc/config/alpha/netbsd-elf.h b/contrib/gcc/config/alpha/netbsd-elf.h
new file mode 100644
index 0000000..17d7bb0
--- /dev/null
+++ b/contrib/gcc/config/alpha/netbsd-elf.h
@@ -0,0 +1,31 @@
+/* Definitions of target machine for GNU compiler
+ for Alpha NetBSD systems using ELF.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (Alpha NetBSD/ELF)");
+
+#undef SUB_CPP_PREDEFINES
+#define SUB_CPP_PREDEFINES "-D__ELF__"
+
+#undef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS \
+{ "elf_dynamic_linker", ELF_DYNAMIC_LINKER },
+
+#define ELF_DYNAMIC_LINKER "/usr/libexec/ld.elf_so"
diff --git a/contrib/gcc/config/alpha/netbsd.h b/contrib/gcc/config/alpha/netbsd.h
new file mode 100644
index 0000000..054e9e0
--- /dev/null
+++ b/contrib/gcc/config/alpha/netbsd.h
@@ -0,0 +1,38 @@
+/* Definitions of target machine for GNU compiler,
+ for Alpha NetBSD systems.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_FP | MASK_FPREGS | MASK_GAS)
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-D_LONGLONG -Dnetbsd -Dunix " SUB_CPP_PREDEFINES
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{pg:-lgmon} %{pg:-lc_p} %{!pg:-lc}"
+
+/* Generate calls to memcpy, etc., not bcopy, etc. */
+#define TARGET_MEM_FUNCTIONS
+
+#undef FUNCTION_PROFILER
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ fputs ("\tlda $28,_mcount\n\tjsr $28,($28),_mcount\n", (FILE))
+
+/* Show that we need a GP when profiling. */
+#define TARGET_PROFILING_NEEDS_GP
diff --git a/contrib/gcc/config/alpha/openbsd.h b/contrib/gcc/config/alpha/openbsd.h
new file mode 100644
index 0000000..60591d5
--- /dev/null
+++ b/contrib/gcc/config/alpha/openbsd.h
@@ -0,0 +1,126 @@
+/* Configuration file for an alpha OpenBSD target.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* We settle for little endian for now. */
+#define TARGET_ENDIAN_DEFAULT 0
+
+#include <alpha/alpha.h>
+
+#define OBSD_NO_DYNAMIC_LIBRARIES
+#define OBSD_HAS_DECLARE_FUNCTION_NAME
+#define OBSD_HAS_DECLARE_FUNCTION_SIZE
+#define OBSD_HAS_DECLARE_OBJECT
+
+/* alpha ecoff supports only weak aliases, see below. */
+#define ASM_WEAKEN_LABEL(FILE,NAME) ASM_OUTPUT_WEAK_ALIAS (FILE,NAME,0)
+
+#include <openbsd.h>
+
+/* Controlling the compilation driver. */
+
+/* alpha needs __start. */
+#undef LINK_SPEC
+#define LINK_SPEC \
+ "%{!nostdlib:%{!r*:%{!e*:-e __start}}} -dc -dp %{assert*}"
+
+/* run-time target specifications */
+#define CPP_PREDEFINES "-D__unix__ -D__ANSI_COMPAT -Asystem(unix) \
+-D__OpenBSD__ -D__alpha__ -D__alpha"
+
+/* Layout of source language data types. */
+
+/* This must agree with <machine/ansi.h> */
+#undef SIZE_TYPE
+#define SIZE_TYPE "long unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "long int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 32
+
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+#define LOCAL_LABEL_PREFIX "."
+
+/* We don't have an init section yet. */
+#undef HAS_INIT_SECTION
+
+/* collect2 support (assembler format: macros for initialization). */
+
+/* Don't tell collect2 we use COFF as we don't have (yet ?) a dynamic ld
+ library with the proper functions to handle this -> collect2 will
+ default to using nm. */
+#undef OBJECT_FORMAT_COFF
+#undef EXTENDED_COFF
+
+/* Assembler format: exception region output. */
+
+/* All configurations that don't use elf must be explicit about not using
+ dwarf unwind information. egcs doesn't try too hard to check internal
+ configuration files... */
+#ifdef INCOMING_RETURN_ADDR_RTX
+#undef DWARF2_UNWIND_INFO
+#define DWARF2_UNWIND_INFO 0
+#endif
+
+/* Assembler format: file framework. */
+
+/* Taken from alpha/osf.h. This used to be common to all alpha
+ configurations, but elf has departed from it.
+ Check alpha/alpha.h, alpha/osf.h for it when egcs is upgraded. */
+#ifndef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+{ \
+ alpha_write_verstamp (FILE); \
+ fprintf (FILE, "\t.set noreorder\n"); \
+ fprintf (FILE, "\t.set volatile\n"); \
+ fprintf (FILE, "\t.set noat\n"); \
+ if (TARGET_SUPPORT_ARCH) \
+ fprintf (FILE, "\t.arch %s\n", \
+ alpha_cpu == PROCESSOR_EV6 ? "ev6" \
+ : (alpha_cpu == PROCESSOR_EV5 \
+ ? (TARGET_MAX ? "pca56" : TARGET_BWX ? "ev56" : "ev5") \
+ : "ev4")); \
+ \
+ ASM_OUTPUT_SOURCE_FILENAME (FILE, main_input_filename); \
+}
+#endif
+
+/* Assembler format: label output. */
+
+#define ASM_OUTPUT_WEAK_ALIAS(FILE,NAME,VALUE) \
+ do { \
+ fputs ("\t.weakext\t", FILE); \
+ assemble_name (FILE, NAME); \
+ if (VALUE) \
+ { \
+ fputs (" , ", FILE); \
+ assemble_name (FILE, VALUE); \
+ } \
+ fputc ('\n', FILE); \
+ } while (0)
+
+
diff --git a/contrib/gcc/config/alpha/osf.h b/contrib/gcc/config/alpha/osf.h
new file mode 100644
index 0000000..956961f
--- /dev/null
+++ b/contrib/gcc/config/alpha/osf.h
@@ -0,0 +1,127 @@
+/* Definitions of target machine for GNU compiler, for DEC Alpha on OSF/1.
+ Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+ Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As of OSF 4.0, as can subtract adjacent labels. */
+
+#undef TARGET_AS_CAN_SUBTRACT_LABELS
+#define TARGET_AS_CAN_SUBTRACT_LABELS 1
+
+/* Names to predefine in the preprocessor for this target machine. */
+
+#define CPP_PREDEFINES "\
+-Dunix -D__osf__ -D_LONGLONG -DSYSTYPE_BSD \
+-D_SYSTYPE_BSD -Asystem(unix) -Asystem(xpg4)"
+
+/* Under OSF4, -p and -pg require -lprof1, and -lprof1 requires -lpdf. */
+
+#define LIB_SPEC "%{p:-lprof1 -lpdf} %{pg:-lprof1 -lpdf} %{a:-lprof2} -lc"
+
+/* Pass "-G 8" to ld because Alpha's CC does. Pass -O3 if we are
+ optimizing, -O1 if we are not. Pass -shared, -non_shared or
+ -call_shared as appropriate. Also pass -pg. */
+#define LINK_SPEC \
+ "-G 8 %{O*:-O3} %{!O*:-O1} %{static:-non_shared} \
+ %{!static:%{shared:-shared} %{!shared:-call_shared}} %{pg} %{taso} \
+ %{rpath*}"
+
+#define STARTFILE_SPEC \
+ "%{!shared:%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}"
+
+#define MD_STARTFILE_PREFIX "/usr/lib/cmplrs/cc/"
+
+#define ASM_FILE_START(FILE) \
+{ \
+ alpha_write_verstamp (FILE); \
+ fprintf (FILE, "\t.set noreorder\n"); \
+ fprintf (FILE, "\t.set volatile\n"); \
+ fprintf (FILE, "\t.set noat\n"); \
+ if (TARGET_SUPPORT_ARCH) \
+ fprintf (FILE, "\t.arch %s\n", \
+ alpha_cpu == PROCESSOR_EV6 ? "ev6" \
+ : (alpha_cpu == PROCESSOR_EV5 \
+ ? (TARGET_MAX ? "pca56" : TARGET_BWX ? "ev56" : "ev5") \
+ : "ev4")); \
+ \
+ ASM_OUTPUT_SOURCE_FILENAME (FILE, main_input_filename); \
+}
+
+/* No point in running CPP on our assembler output. */
+#if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_GAS) != 0
+/* Don't pass -g to GNU as, because some versions don't accept this option. */
+#define ASM_SPEC "%{malpha-as:-g} -nocpp %{pg}"
+#else
+/* In OSF/1 v3.2c, the assembler by default does not output file names which
+ causes mips-tfile to fail. Passing -g to the assembler fixes this problem.
+ ??? Strictly speaking, we need -g only if the user specifies -g. Passing
+ it always means that we get slightly larger than necessary object files
+ if the user does not specify -g. If we don't pass -g, then mips-tfile
+ will need to be fixed to work in this case. Pass -O0 since some
+ optimization are broken and don't help us anyway. */
+#define ASM_SPEC "%{!mgas:-g} -nocpp %{pg} -O0"
+#endif
+
+/* Specify to run a post-processor, mips-tfile after the assembler
+ has run to stuff the ecoff debug information into the object file.
+ This is needed because the Alpha assembler provides no way
+ of specifying such information in the assembly file. */
+
+#if ((TARGET_DEFAULT | TARGET_CPU_DEFAULT) & MASK_GAS) != 0
+
+#define ASM_FINAL_SPEC "\
+%{malpha-as: %{!mno-mips-tfile: \
+ \n mips-tfile %{v*: -v} \
+ %{K: -I %b.o~} \
+ %{!K: %{save-temps: -I %b.o~}} \
+ %{c:%W{o*}%{!o*:-o %b.o}}%{!c:-o %U.o} \
+ %{.s:%i} %{!.s:%g.s}}}"
+
+#else
+#define ASM_FINAL_SPEC "\
+%{!mgas: %{!mno-mips-tfile: \
+ \n mips-tfile %{v*: -v} \
+ %{K: -I %b.o~} \
+ %{!K: %{save-temps: -I %b.o~}} \
+ %{c:%W{o*}%{!o*:-o %b.o}}%{!c:-o %U.o} \
+ %{.s:%i} %{!.s:%g.s}}}"
+
+#endif
+
+/* Indicate that we have a stamp.h to use. */
+#ifndef CROSS_COMPILE
+#define HAVE_STAMP_H 1
+#endif
+
+/* Attempt to turn on access permissions for the stack. */
+
+#define TRANSFER_FROM_TRAMPOLINE \
+void \
+__enable_execute_stack (addr) \
+ void *addr; \
+{ \
+ long size = getpagesize (); \
+ long mask = ~(size-1); \
+ char *page = (char *) (((long) addr) & mask); \
+ char *end = (char *) ((((long) (addr + TRAMPOLINE_SIZE)) & mask) + size); \
+ \
+ /* 7 is PROT_READ | PROT_WRITE | PROT_EXEC */ \
+ if (mprotect (page, end - page, 7) < 0) \
+ perror ("mprotect of trampoline code"); \
+}
diff --git a/contrib/gcc/config/alpha/osf12.h b/contrib/gcc/config/alpha/osf12.h
index fe9112c..87e2111 100644
--- a/contrib/gcc/config/alpha/osf12.h
+++ b/contrib/gcc/config/alpha/osf12.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GNU compiler, for DEC Alpha.
- Copyright (C) 1992, 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1993, 1995, 1996 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@nyu.edu)
This file is part of GNU CC.
@@ -19,9 +19,6 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-
-#include "alpha/alpha.h"
-
/* In OSF 1.2, there is a linker bug that prevents use of -O3 to
the linker. */
@@ -29,3 +26,8 @@ Boston, MA 02111-1307, USA. */
#define LINK_SPEC \
"-G 8 -O1 %{static:-non_shared} %{rpath*} \
%{!static:%{shared:-shared} %{!shared:-call_shared}} %{taso}"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "short unsigned int"
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 16
diff --git a/contrib/gcc/config/alpha/osf2or3.h b/contrib/gcc/config/alpha/osf2or3.h
new file mode 100644
index 0000000..5abdb0e
--- /dev/null
+++ b/contrib/gcc/config/alpha/osf2or3.h
@@ -0,0 +1,30 @@
+/* Definitions of target machine for GNU compiler, for DEC Alpha, osf[23].
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* In OSF 2 or 3, linking with -lprof1 doesn't require -lpdf. */
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{p:-lprof1} %{pg:-lprof1} %{a:-lprof2} -lc"
+
+/* As of OSF 3.2, as still can't subtract adjacent labels. */
+
+#undef TARGET_AS_CAN_SUBTRACT_LABELS
+#define TARGET_AS_CAN_SUBTRACT_LABELS 0
+
diff --git a/contrib/gcc/config/alpha/t-crtbe b/contrib/gcc/config/alpha/t-crtbe
new file mode 100644
index 0000000..5e82b92
--- /dev/null
+++ b/contrib/gcc/config/alpha/t-crtbe
@@ -0,0 +1,9 @@
+# Effectively disable the crtbegin/end rules using crtstuff.c
+T = disable
+
+# Assemble startup files.
+crtbegin.o: $(srcdir)/config/alpha/crtbegin.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) -c -o crtbegin.o -x assembler $(srcdir)/config/alpha/crtbegin.asm
+
+crtend.o: $(srcdir)/config/alpha/crtend.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) -c -o crtend.o -x assembler $(srcdir)/config/alpha/crtend.asm
diff --git a/contrib/gcc/config/alpha/t-vms b/contrib/gcc/config/alpha/t-vms
new file mode 100644
index 0000000..12ac240
--- /dev/null
+++ b/contrib/gcc/config/alpha/t-vms
@@ -0,0 +1,6 @@
+# Do not build libgcc1.
+LIBGCC1 =
+CROSS_LIBGCC1 =
+
+LIB2FUNCS_EXTRA = tramp.s
+
diff --git a/contrib/gcc/config/alpha/va_list.h b/contrib/gcc/config/alpha/va_list.h
new file mode 100644
index 0000000..c9ab2b0
--- /dev/null
+++ b/contrib/gcc/config/alpha/va_list.h
@@ -0,0 +1,16 @@
+/* A replacement for Digital Unix's <va_list.h>. */
+
+#include <va-alpha.h>
+
+#if !defined(_VA_LIST) && !defined(_HIDDEN_VA_LIST)
+#define _VA_LIST
+typedef __gnuc_va_list va_list;
+
+#elif defined(_HIDDEN_VA_LIST) && !defined(_HIDDEN_VA_LIST_DONE)
+#define _HIDDEN_VA_LIST_DONE
+typedef __gnuc_va_list __va_list;
+
+#elif defined(_HIDDEN_VA_LIST) && defined(_VA_LIST)
+#undef _HIDDEN_VA_LIST
+
+#endif
diff --git a/contrib/gcc/config/alpha/vms-tramp.asm b/contrib/gcc/config/alpha/vms-tramp.asm
new file mode 100644
index 0000000..fce9ec5
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms-tramp.asm
@@ -0,0 +1,22 @@
+;# New Alpha OpenVMS trampoline
+;#
+ .set noreorder
+ .set volatile
+ .set noat
+ .file 1 "tramp.s"
+.text
+ .align 3
+ .globl __tramp
+ .ent __tramp
+__tramp..en:
+
+.link
+ .align 3
+__tramp:
+ .pdesc __tramp..en,null
+.text
+ ldq $1,24($27)
+ ldq $27,16($27)
+ ldq $28,8($27)
+ jmp $31,($28),0
+ .end __tramp
diff --git a/contrib/gcc/config/alpha/vms.h b/contrib/gcc/config/alpha/vms.h
new file mode 100644
index 0000000..44cf5bf
--- /dev/null
+++ b/contrib/gcc/config/alpha/vms.h
@@ -0,0 +1,510 @@
+/* Output variables, constants and external declarations, for GNU compiler.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#define OPEN_VMS 1
+
+/* This enables certain macros in alpha.h, which will make an indirect
+ reference to an external symbol an invalid address. This needs to be
+ defined before we include alpha.h, since it determines which macros
+ are used for GO_IF_*. */
+
+#define NO_EXTERNAL_INDIRECT_ADDRESS
+
+#include "alpha/alpha.h"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+"-D__ALPHA -Dvms -DVMS -D__vms__ -D__VMS__ -Asystem(vms)"
+
+#undef CPP_SUBTARGET_SPEC
+#define CPP_SUBTARGET_SPEC "\
+%{mfloat-ieee:-D__IEEE_FLOAT} \
+%{mfloat-vax:-D__G_FLOAT} \
+%{!mfloat-vax:-D__IEEE_FLOAT}"
+
+/* Under OSF4, -p and -pg require -lprof1, and -lprof1 requires -lpdf. */
+
+#define LIB_SPEC "%{p:-lprof1 -lpdf} %{pg:-lprof1 -lpdf} %{a:-lprof2} -lc"
+
+/* Pass "-G 8" to ld because Alpha's CC does. Pass -O3 if we are
+ optimizing, -O1 if we are not. Pass -shared, -non_shared or
+ -call_shared as appropriate. Also pass -pg. */
+#define LINK_SPEC \
+ "-G 8 %{O*:-O3} %{!O*:-O1} %{static:-non_shared} \
+ %{!static:%{shared:-shared} %{!shared:-call_shared}} %{pg} %{taso} \
+ %{rpath*}"
+
+/* We allow $'s in identifiers unless -ansi is used .. */
+
+#define DOLLARS_IN_IDENTIFIERS 2
+
+/* These match the definitions used in DECCRTL, the VMS C run-time library
+
+#define SIZE_TYPE "unsigned int"
+#define PTRDIFF_TYPE "int"
+*/
+
+/* Use memcpy for structure copying, and so forth. */
+#define TARGET_MEM_FUNCTIONS
+
+/* By default, allow $ to be part of an identifier. */
+#define DOLLARS_IN_IDENTIFIERS 2
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_FP|MASK_FPREGS|MASK_GAS)
+#undef TARGET_OPEN_VMS
+#define TARGET_OPEN_VMS 1
+
+#undef TARGET_NAME
+#define TARGET_NAME "OpenVMS/Alpha"
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (%s)", TARGET_NAME);
+
+/* The structure return address arrives as an "argument" on VMS. */
+#undef STRUCT_VALUE_REGNUM
+#define STRUCT_VALUE 0
+#undef PCC_STATIC_STRUCT_RETURN
+
+/* no floating emulation. */
+#undef REAL_ARITHMETIC
+
+/* "long" is 32 bits. */
+#undef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE 32
+
+/* Pointer is 32 bits but the hardware has 64-bit addresses, sign extended. */
+#undef POINTER_SIZE
+#define POINTER_SIZE 32
+#define POINTERS_EXTEND_UNSIGNED 0
+
+#define MAX_OFILE_ALIGNMENT 524288 /* 8 x 2^16 by DEC Ada Test CD40VRA */
+
+#undef FIXED_REGISTERS
+#define FIXED_REGISTERS \
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }
+
+#undef CALL_USED_REGISTERS
+#define CALL_USED_REGISTERS \
+ {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
+
+#undef HARD_FRAME_POINTER_REGNUM
+#define HARD_FRAME_POINTER_REGNUM 29
+
+#undef CAN_ELIMINATE
+#define CAN_ELIMINATE(FROM, TO) \
+((TO) != STACK_POINTER_REGNUM || ! alpha_using_fp ())
+
+#undef INITIAL_ELIMINATION_OFFSET
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+{ if ((FROM) == FRAME_POINTER_REGNUM) \
+ (OFFSET) = alpha_sa_size () + alpha_pv_save_size (); \
+ else if ((FROM) == ARG_POINTER_REGNUM) \
+ (OFFSET) = (ALPHA_ROUND (alpha_sa_size () + alpha_pv_save_size () \
+ + get_frame_size () \
+ + current_function_pretend_args_size) \
+ - current_function_pretend_args_size); \
+ if ((TO) == STACK_POINTER_REGNUM) \
+ (OFFSET) += ALPHA_ROUND (current_function_outgoing_args_size); \
+}
+
+/* Define a data type for recording info about an argument list
+ during the scan of that argument list. This data type should
+ hold all necessary information about the function itself
+ and about the args processed so far, enough to enable macros
+ such as FUNCTION_ARG to determine where the next arg should go.
+
+ On Alpha/VMS, this is a structure that contains the number of
+ arguments and, for each argument, the datatype of that argument.
+
+ The number of arguments is a number of words of arguments scanned so far.
+ Thus 6 or more means all following args should go on the stack. */
+
+enum avms_arg_type {I64, FF, FD, FG, FS, FT};
+typedef struct {char num_args; enum avms_arg_type atypes[6];} avms_arg_info;
+
+#undef CUMULATIVE_ARGS
+#define CUMULATIVE_ARGS avms_arg_info
+
+/* Initialize a variable CUM of type CUMULATIVE_ARGS
+ for a call to a function whose data type is FNTYPE.
+ For a library call, FNTYPE is 0. */
+
+#undef INIT_CUMULATIVE_ARGS
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
+ (CUM).num_args = 0; \
+ (CUM).atypes[0] = (CUM).atypes[1] = (CUM).atypes[2] = I64; \
+ (CUM).atypes[3] = (CUM).atypes[4] = (CUM).atypes[5] = I64;
+
+/* Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ (TYPE is null for libcalls where that information may not be available.) */
+
+extern enum avms_arg_type alpha_arg_type ();
+
+/* Determine where to put an argument to a function.
+ Value is zero to push the argument on the stack,
+ or a hard register in which to store the argument.
+
+ MODE is the argument's machine mode (or VOIDmode for no more args).
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis).
+
+ On Alpha the first 6 words of args are normally in registers
+ and the rest are pushed. */
+
+extern struct rtx_def *alpha_arg_info_reg_val ();
+#undef FUNCTION_ARG
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+((MODE) == VOIDmode ? alpha_arg_info_reg_val (CUM) \
+ : ((CUM.num_args) < 6 && ! MUST_PASS_IN_STACK (MODE, TYPE) \
+ ? gen_rtx(REG, (MODE), \
+ ((CUM).num_args + 16 \
+ + ((TARGET_FPREGS \
+ && (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT \
+ || GET_MODE_CLASS (MODE) == MODE_FLOAT)) \
+ * 32))) \
+ : 0))
+
+#undef FUNCTION_ARG_ADVANCE
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+ if (MUST_PASS_IN_STACK (MODE, TYPE)) \
+ (CUM).num_args += 6; \
+ else \
+ { \
+ if ((CUM).num_args < 6) \
+ (CUM).atypes[(CUM).num_args] = alpha_arg_type (MODE); \
+ \
+ (CUM).num_args += ALPHA_ARG_SIZE (MODE, TYPE, NAMED); \
+ }
+
+/* For an arg passed partly in registers and partly in memory,
+ this is the number of registers used.
+ For args passed entirely in registers or entirely in memory, zero. */
+
+#undef FUNCTION_ARG_PARTIAL_NREGS
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
+((CUM).num_args < 6 && 6 < (CUM).num_args \
+ + ALPHA_ARG_SIZE (MODE, TYPE, NAMED) \
+ ? 6 - (CUM).num_args : 0)
+
+/* Perform any needed actions needed for a function that is receiving a
+ variable number of arguments.
+
+ CUM is as for INIT_CUMULATIVE_ARGS.
+
+ MODE and TYPE are the mode and type of the current parameter.
+
+ PRETEND_SIZE is a variable that should be set to the amount of stack
+ that must be pushed by the prolog to pretend that our caller pushed
+ it.
+
+ Normally, this macro will push all remaining incoming registers on the
+ stack and set PRETEND_SIZE to the length of the registers pushed.
+
+ For VMS, we allocate space for all 6 arg registers plus a count.
+
+ However, if NO registers need to be saved, don't allocate any space.
+ This is not only because we won't need the space, but because AP includes
+ the current_pretend_args_size and we don't want to mess up any
+ ap-relative addresses already made. */
+
+#undef SETUP_INCOMING_VARARGS
+#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
+{ if ((CUM).num_args < 6) \
+ { \
+ if (! (NO_RTL)) \
+ { \
+ emit_move_insn (gen_rtx (REG, DImode, 1), \
+ virtual_incoming_args_rtx); \
+ emit_insn (gen_arg_home ()); \
+ } \
+ \
+ PRETEND_SIZE = 7 * UNITS_PER_WORD; \
+ } \
+}
+
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+{ \
+ alpha_write_verstamp (FILE); \
+ fprintf (FILE, "\t.set noreorder\n"); \
+ fprintf (FILE, "\t.set volatile\n"); \
+ ASM_OUTPUT_SOURCE_FILENAME (FILE, main_input_filename); \
+}
+
+#undef ASM_OUTPUT_FLOAT
+#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
+ { \
+ if (REAL_VALUE_ISINF (VALUE) \
+ || REAL_VALUE_ISNAN (VALUE) \
+ || REAL_VALUE_MINUS_ZERO (VALUE)) \
+ { \
+ long t; \
+ REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
+ fprintf (FILE, "\t.long 0x%lx\n", t & 0xffffffff); \
+ } \
+ else \
+ { \
+ char str[30]; \
+ REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \
+ fprintf (FILE, "\t.%c_floating %s\n", (TARGET_FLOAT_VAX)?'f':'s', str); \
+ } \
+ }
+
+#define LINK_SECTION_ASM_OP ".link"
+#define READONLY_SECTION_ASM_OP ".rdata"
+#define LITERALS_SECTION_ASM_OP ".literals"
+#define CTORS_SECTION_ASM_OP ".ctors"
+#define DTORS_SECTION_ASM_OP ".dtors"
+
+#undef EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_link, in_rdata, in_literals, in_ctors, in_dtors
+
+#undef EXTRA_SECTION_FUNCTIONS
+#define EXTRA_SECTION_FUNCTIONS \
+void \
+readonly_section () \
+{ \
+ if (in_section != in_rdata) \
+ { \
+ fprintf (asm_out_file, "%s\n", READONLY_SECTION_ASM_OP); \
+ in_section = in_rdata; \
+ } \
+} \
+void \
+link_section () \
+{ \
+ if (in_section != in_link) \
+ { \
+ fprintf (asm_out_file, "%s\n", LINK_SECTION_ASM_OP); \
+ in_section = in_link; \
+ } \
+} \
+void \
+literals_section () \
+{ \
+ if (in_section != in_literals) \
+ { \
+ fprintf (asm_out_file, "%s\n", LITERALS_SECTION_ASM_OP); \
+ in_section = in_literals; \
+ } \
+} \
+void \
+ctors_section () \
+{ \
+ if (in_section != in_ctors) \
+ { \
+ fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \
+ in_section = in_ctors; \
+ } \
+} \
+void \
+dtors_section () \
+{ \
+ if (in_section != in_dtors) \
+ { \
+ fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \
+ in_section = in_dtors; \
+ } \
+}
+
+#undef ASM_OUTPUT_ADDR_DIFF_ELT
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) abort ()
+
+#undef ASM_OUTPUT_ADDR_VEC_ELT
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+ fprintf (FILE, "\t.quad $L%d\n", (VALUE))
+
+#undef READONLY_DATA_SECTION
+#define READONLY_DATA_SECTION readonly_section
+
+#define ASM_FILE_END(FILE) alpha_write_linkage (FILE);
+
+#undef CASE_VECTOR_MODE
+#define CASE_VECTOR_MODE DImode
+#undef CASE_VECTOR_PC_RELATIVE
+
+#undef ASM_OUTPUT_CASE_LABEL
+#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLEINSN) \
+{ ASM_OUTPUT_ALIGN (FILE, 3); ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); }
+
+/* This says how to output assembler code to declare an
+ uninitialized external linkage data object. */
+
+#define COMMON_ASM_OP ".comm"
+
+#undef ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
+do { \
+ fprintf ((FILE), "\t%s\t", COMMON_ASM_OP); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), ",%u,%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \
+} while (0)
+
+#define NO_MD_PROTOTYPES
+
+/* Output assembler code for a block containing the constant parts
+ of a trampoline, leaving space for the variable parts.
+
+ The trampoline should set the static chain pointer to value placed
+ into the trampoline and should branch to the specified routine.
+ Note that $27 has been set to the address of the trampoline, so we can
+ use it for addressability of the two data items. Trampolines are always
+ aligned to FUNCTION_BOUNDARY, which is 64 bits. */
+
+#undef TRAMPOLINE_TEMPLATE
+#define TRAMPOLINE_TEMPLATE(FILE) \
+{ \
+ fprintf (FILE, "\t.quad 0\n"); \
+ fprintf (FILE, "\t.linkage __tramp\n"); \
+ fprintf (FILE, "\t.quad 0\n"); \
+}
+
+/* Length in units of the trampoline for entering a nested function. */
+
+#undef TRAMPOLINE_SIZE
+#define TRAMPOLINE_SIZE 32
+
+/* Emit RTL insns to initialize the variable parts of a trampoline.
+ FNADDR is an RTX for the address of the function's pure code.
+ CXT is an RTX for the static chain value for the function. */
+
+#undef INITIALIZE_TRAMPOLINE
+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
+ alpha_initialize_trampoline (TRAMP, FNADDR, CXT, 16, 24, -1)
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global constructors. */
+#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
+ do { \
+ ctors_section (); \
+ fprintf (FILE, "\t.quad "); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global destructors. */
+#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
+ do { \
+ dtors_section (); \
+ fprintf (FILE, "\t.quad "); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, NAME, ARGS) \
+ (vms_valid_decl_attribute_p (DECL, ATTRIBUTES, NAME, ARGS))
+extern int vms_valid_decl_attribute_p ();
+
+#undef SDB_DEBUGGING_INFO
+#undef MIPS_DEBUGGING_INFO
+#undef DBX_DEBUGGING_INFO
+
+#define DWARF2_DEBUGGING_INFO
+
+/* This is how to output an assembler line
+ that says to advance the location counter
+ to a multiple of 2**LOG bytes. */
+
+#undef ASM_OUTPUT_ALIGN
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ fprintf (FILE, "\t.align %d\n", LOG);
+
+#define UNALIGNED_SHORT_ASM_OP ".word"
+#define UNALIGNED_INT_ASM_OP ".long"
+#define UNALIGNED_DOUBLE_INT_ASM_OP ".quad"
+
+#define ASM_OUTPUT_SECTION(FILE,SECTION) \
+ (strcmp (SECTION, ".text") == 0) \
+ ? text_section () \
+ : named_section (NULL_TREE, SECTION, 0), \
+ ASM_OUTPUT_ALIGN (FILE, 0) \
+
+#define ASM_OUTPUT_SECTION_NAME(FILE,DECL,NAME,RELOC) \
+ do \
+ { \
+ char *flags; \
+ int ovr = 0; \
+ if (DECL && DECL_MACHINE_ATTRIBUTES (DECL) \
+ && lookup_attribute \
+ ("overlaid", DECL_MACHINE_ATTRIBUTES (DECL))) \
+ flags = ",OVR", ovr = 1; \
+ else if (strncmp (NAME,".debug", 6) == 0) \
+ flags = ",NOWRT"; \
+ else \
+ flags = ""; \
+ fputc ('\n', (FILE)); \
+ fprintf (FILE, ".section\t%s%s\n", NAME, flags); \
+ if (ovr) \
+ (NAME) = ""; \
+ } while (0)
+
+#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \
+ do { literals_section(); \
+ fprintf ((FILE), "\t"); \
+ assemble_name (FILE, LABEL1); \
+ fprintf (FILE, " = "); \
+ assemble_name (FILE, LABEL2); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+#undef ASM_FORMAT_PRIVATE_NAME
+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
+( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 12), \
+ sprintf ((OUTPUT), "%s___%d", (NAME), (LABELNO)))
+
+/* ??? VMS uses different linkage. */
+#undef ASM_OUTPUT_MI_THUNK
+
+#undef ASM_SPEC
+#undef ASM_FINAL_SPEC
+#undef LINK_SPEC
+#undef STARTFILE_SPEC
+#define ASM_SPEC "-nocpp %{pg}"
+#define LINK_SPEC "%{g3:-g3} %{g0:-g0} %{shared:-shared} %{v:-v}"
+
+/* Define the names of the division and modulus functions. */
+#define DIVSI3_LIBCALL "OTS$DIV_I"
+#define DIVDI3_LIBCALL "OTS$DIV_L"
+#define UDIVSI3_LIBCALL "OTS$DIV_UI"
+#define UDIVDI3_LIBCALL "OTS$DIV_UL"
+#define MODSI3_LIBCALL "OTS$REM_I"
+#define MODDI3_LIBCALL "OTS$REM_L"
+#define UMODSI3_LIBCALL "OTS$REM_UI"
+#define UMODDI3_LIBCALL "OTS$REM_UL"
+
+#define DIR_SEPARATOR ']'
+
+#define PREFIX "GNU_ROOT:"
diff --git a/contrib/gcc/config/alpha/vxworks.h b/contrib/gcc/config/alpha/vxworks.h
new file mode 100644
index 0000000..6dee4b3
--- /dev/null
+++ b/contrib/gcc/config/alpha/vxworks.h
@@ -0,0 +1,51 @@
+/* Definitions of target machine for GNU compiler. Vxworks Alpha version.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file just exists to give specs for the Alpha running on VxWorks. */
+
+#undef CPP_SUBTARGET_SPEC
+#define CPP_SUBTARGET_SPEC "\
+%{mvxsim:-DCPU=SIMALPHADUNIX} \
+%{!mvxsim: %{!mcpu*|mcpu=21064:-DCPU=21064} %{mcpu=21164:-DCPU=21164}} \
+%{posix: -D_POSIX_SOURCE}"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "\
+-D__vxworks -D__alpha_vxworks -Asystem(vxworks) \
+-Asystem(embedded) -D_LONGLONG"
+
+/* VxWorks does all the library stuff itself. */
+
+#undef LIB_SPEC
+#define LIB_SPEC ""
+
+/* VxWorks uses object files, not loadable images. make linker just
+ combine objects. */
+
+#undef LINK_SPEC
+#define LINK_SPEC "-r"
+
+/* VxWorks provides the functionality of crt0.o and friends itself. */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC ""
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC ""
diff --git a/contrib/gcc/config/alpha/x-alpha b/contrib/gcc/config/alpha/x-alpha
index 9919747..9686ab9 100644
--- a/contrib/gcc/config/alpha/x-alpha
+++ b/contrib/gcc/config/alpha/x-alpha
@@ -1 +1,2 @@
CLIB=-lmld
+EXTRA_HEADERS = $(srcdir)/config/alpha/va_list.h
diff --git a/contrib/gcc/config/alpha/xm-alpha.h b/contrib/gcc/config/alpha/xm-alpha.h
index 642e1cf..7665127 100644
--- a/contrib/gcc/config/alpha/xm-alpha.h
+++ b/contrib/gcc/config/alpha/xm-alpha.h
@@ -41,12 +41,18 @@ Boston, MA 02111-1307, USA. */
#define SUCCESS_EXIT_CODE 0
#define FATAL_EXIT_CODE 33
-/* If not compiled with GNU C, use the builtin alloca. */
-#if !defined(__GNUC__) && !defined(_WIN32)
+/* If compiled with GNU C, use the builtin alloca. */
+#ifndef alloca
+#if defined(__GNUC__) && !defined(USE_C_ALLOCA)
+#define alloca __builtin_alloca
+#else
+#if !defined(_WIN32) && !defined(USE_C_ALLOCA) && !defined(OPEN_VMS)
#include <alloca.h>
#else
extern void *alloca ();
#endif
+#endif
+#endif
/* The host compiler has problems with enum bitfields since it makes
them signed so we can't fit all our codes in. */
@@ -65,14 +71,6 @@ extern void *malloc (), *realloc (), *calloc ();
#include "string.h"
#endif
-/* OSF/1 has vprintf. */
-
-#define HAVE_VPRINTF
-
-/* OSF/1 has putenv. */
-
-#define HAVE_PUTENV
-
/* OSF/1 is POSIX.1 compliant. */
#define POSIX
diff --git a/contrib/gcc/config/alpha/xm-openbsd.h b/contrib/gcc/config/alpha/xm-openbsd.h
new file mode 100644
index 0000000..50f4366
--- /dev/null
+++ b/contrib/gcc/config/alpha/xm-openbsd.h
@@ -0,0 +1,23 @@
+/* Configuration file for an host running alpha OpenBSD.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <xm-openbsd.h>
+#include <alpha/xm-alpha.h>
+
diff --git a/contrib/gcc/config/alpha/xm-vms.h b/contrib/gcc/config/alpha/xm-vms.h
new file mode 100644
index 0000000..472a225
--- /dev/null
+++ b/contrib/gcc/config/alpha/xm-vms.h
@@ -0,0 +1,93 @@
+/* Configuration for GNU C-compiler for openVMS/Alpha.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Klaus Kaempf (kkaempf@progis.de).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* If compiling with DECC, need to fix problem with <stdio.h>
+ which defines a macro called FILE_TYPE that breaks "tree.h".
+ Fortunately it uses #ifndef to suppress multiple inclusions.
+ Three possible cases:
+ 1) <stdio.h> has already been included -- ours will be no-op;
+ 2) <stdio.h> will be included after us -- "theirs" will be no-op;
+ 3) <stdio.h> isn't needed -- including it here shouldn't hurt.
+ In all three cases, the problem macro will be removed here. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __DECC
+#undef FILE_TYPE
+#endif
+
+#undef HOST_BITS_PER_LONG
+#define HOST_BITS_PER_LONG 32
+
+#define HOST_WIDE_INT long long
+#define HOST_BITS_PER_WIDE_INT 64
+
+#undef SUCCESS_EXIT_CODE
+#define SUCCESS_EXIT_CODE 1
+#undef FATAL_EXIT_CODE
+#define FATAL_EXIT_CODE (44 | 0x10000000) /* Abort, and no DCL message. */
+
+/* A couple of conditionals for execution machine are controlled here. */
+#ifndef VMS
+#define VMS
+#endif
+
+#define GCC_INCLUDE_DIR ""
+/* Specify the list of include file directories. */
+#define INCLUDE_DEFAULTS \
+{ \
+ { "GNU_GXX_INCLUDE:", "G++", 1, 1 }, \
+ { "GNU_CC_INCLUDE:", "GCC", 0, 0 }, \
+ { ".", 0, 0, 1 }, \
+ { 0, 0, 0, 0 } \
+}
+
+/* Define a local equivalent (sort of) for unlink */
+#define unlink remove
+
+#define NEED_ATEXIT
+#define HAVE_VPRINTF
+#define HAVE_PUTENV
+#define HAVE_STRERROR
+#define HAVE_ATOLL
+
+#define NO_SYS_PARAMS_H /* Don't have <sys/params.h> */
+#define USE_C_ALLOCA /* Using alloca.c */
+
+#define HAVE_FCNTL_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_STRING_H 1
+#define HAVE_LIMITS_H 1
+#define HAVE_STDDEF_H 1
+#define HAVE_TIME_H 1
+#define STDC_HEADERS 1
+#define HAVE_CPP_STRINGIFY 1
+
+#if __STDC__
+extern void *alloca (size_t);
+#else
+extern char *alloca (unsigned int);
+#endif
+
+#define OBJECT_SUFFIX ".obj"
+#define EXECUTABLE_SUFFIX ".exe"
diff --git a/contrib/gcc/config/aoutos.h b/contrib/gcc/config/aoutos.h
index e9caa71..6f4e262 100644
--- a/contrib/gcc/config/aoutos.h
+++ b/contrib/gcc/config/aoutos.h
@@ -39,50 +39,3 @@ Boston, MA 02111-1307, USA. */
/* Define a symbol indicating that we are using aoutos.h. */
#define USING_AOUTOS_H
-
-/* A C statement (sans semicolon) to output an element in the table of
- global constructors.
- If using GNU LD, tell it that this is part of the static destructor set.
- This code works for any machine provided you use GNU as/ld.
- If not using GNU LD, rely on a "collect" program to look for names defined
- in the particular form we choose as global constructor function names. */
-
-#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
- do { \
- if (flag_gnu_linker) \
- { \
- /* Output an N_SETT (0x16, 22.) for the name. */ \
- fprintf (FILE, "%s \"___CTOR_LIST__\",22,0,0,", ASM_STABS_OP); \
- assemble_name (FILE, NAME); \
- fputc ('\n', FILE); \
- } \
- } while (0)
-
-
-/* A C statement (sans semicolon) to output an element in the table of
- global destructors. */
-
-#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
- do { \
- if (flag_gnu_linker) \
- { \
- /* Output an N_SETT (0x16, 22.) for the name. */ \
- fprintf (FILE, "%s \"___DTOR_LIST__\",22,0,0,", ASM_STABS_OP); \
- assemble_name (FILE, NAME); \
- fputc ('\n', FILE); \
- } \
- } while (0)
-
-/* Likewise for entries we want to record for garbage collection.
- Garbage collection is still under development. */
-
-#define ASM_OUTPUT_GC_ENTRY(FILE,NAME) \
- do { \
- if (flag_gnu_linker) \
- { \
- /* Output an N_SETT (0x16, 22.) for the name. */ \
- fprintf (FILE, "%s \"___PTR_LIST__\",22,0,0,", ASM_STABS_OP); \
- assemble_name (FILE, NAME); \
- fputc ('\n', FILE); \
- } \
- } while (0)
diff --git a/contrib/gcc/config/dbx.h b/contrib/gcc/config/dbx.h
new file mode 100644
index 0000000..c5cd3b5
--- /dev/null
+++ b/contrib/gcc/config/dbx.h
@@ -0,0 +1,30 @@
+/* Prefer DBX (stabs) debugging information.
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file causes gcc to prefer using DBX (stabs) debugging
+ information. The configure script will add a #include of this file
+ to tm.h when --with-stabs is used for certain targets. */
+
+#ifndef DBX_DEBUGGING_INFO
+#define DBX_DEBUGGING_INFO
+#endif
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
diff --git a/contrib/gcc/config/dbxcoff.h b/contrib/gcc/config/dbxcoff.h
new file mode 100644
index 0000000..9497a70
--- /dev/null
+++ b/contrib/gcc/config/dbxcoff.h
@@ -0,0 +1,87 @@
+/* Definitions needed when using stabs embedded in COFF sections.
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file may be included by any COFF target which wishes to
+ support -gstabs generating stabs in sections, as produced by gas
+ and understood by gdb. */
+
+/* Output DBX (stabs) debugging information if doing -gstabs. */
+
+#undef DBX_DEBUGGING_INFO
+#define DBX_DEBUGGING_INFO
+
+/* Generate SDB debugging information by default. */
+
+#ifndef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE SDB_DEBUG
+#endif
+
+/* Be function-relative for block and source line stab directives. */
+
+#undef DBX_BLOCKS_FUNCTION_RELATIVE
+#define DBX_BLOCKS_FUNCTION_RELATIVE 1
+
+/* but, to make this work, functions must appear prior to line info. */
+
+#undef DBX_FUNCTION_FIRST
+#define DBX_FUNCTION_FIRST
+
+/* Generate a blank trailing N_SO to mark the end of the .o file, since
+ we can't depend upon the linker to mark .o file boundaries with
+ embedded stabs. */
+
+#undef DBX_OUTPUT_MAIN_SOURCE_FILE_END
+#define DBX_OUTPUT_MAIN_SOURCE_FILE_END(FILE, FILENAME) \
+ fprintf (FILE, \
+ "\t.text\n\t.stabs \"\",%d,0,0,Letext\nLetext:\n", N_SO)
+
+/* Like block addresses, stabs line numbers are relative to the
+ current function. */
+
+#undef ASM_OUTPUT_SOURCE_LINE
+#define ASM_OUTPUT_SOURCE_LINE(FILE, LINE) \
+{ if (write_symbols == SDB_DEBUG) { \
+ fprintf ((FILE), "\t.ln\t%d\n", \
+ ((sdb_begin_function_line > -1) \
+ ? (LINE) - sdb_begin_function_line : 1)); \
+ } else if (write_symbols == DBX_DEBUG) { \
+ static int sym_lineno = 1; \
+ char buffer[256]; \
+ ASM_GENERATE_INTERNAL_LABEL (buffer, "LM", sym_lineno); \
+ fprintf (FILE, ".stabn 68,0,%d,", LINE); \
+ assemble_name (FILE, buffer); \
+ putc ('-', FILE); \
+ assemble_name (FILE, \
+ XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); \
+ putc ('\n', FILE); \
+ ASM_OUTPUT_INTERNAL_LABEL (FILE, "LM", sym_lineno); \
+ sym_lineno++; \
+ } }
+
+/* When generating stabs debugging, use N_BINCL entries. */
+
+#undef DBX_USE_BINCL
+#define DBX_USE_BINCL
+
+/* There is no limit to the length of stabs strings. */
+
+#ifndef DBX_CONTIN_LENGTH
+#define DBX_CONTIN_LENGTH 0
+#endif
diff --git a/contrib/gcc/config/float-i128.h b/contrib/gcc/config/float-i128.h
new file mode 100644
index 0000000..6a9dd48
--- /dev/null
+++ b/contrib/gcc/config/float-i128.h
@@ -0,0 +1,96 @@
+/* float.h for target with IEEE 32, 64 and 128 bit floating point formats */
+#ifndef _FLOAT_H_
+#define _FLOAT_H_
+/* Produced by enquire version 4.3, CWI, Amsterdam */
+
+ /* Radix of exponent representation */
+#undef FLT_RADIX
+#define FLT_RADIX 2
+ /* Number of base-FLT_RADIX digits in the significand of a float */
+#undef FLT_MANT_DIG
+#define FLT_MANT_DIG 24
+ /* Number of decimal digits of precision in a float */
+#undef FLT_DIG
+#define FLT_DIG 6
+ /* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown */
+#undef FLT_ROUNDS
+#define FLT_ROUNDS 1
+ /* Difference between 1.0 and the minimum float greater than 1.0 */
+#undef FLT_EPSILON
+#define FLT_EPSILON 1.19209290e-07F
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */
+#undef FLT_MIN_EXP
+#define FLT_MIN_EXP (-125)
+ /* Minimum normalised float */
+#undef FLT_MIN
+#define FLT_MIN 1.17549435e-38F
+ /* Minimum int x such that 10**x is a normalised float */
+#undef FLT_MIN_10_EXP
+#define FLT_MIN_10_EXP (-37)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable float */
+#undef FLT_MAX_EXP
+#define FLT_MAX_EXP 128
+ /* Maximum float */
+#undef FLT_MAX
+#define FLT_MAX 3.40282347e+38F
+ /* Maximum int x such that 10**x is a representable float */
+#undef FLT_MAX_10_EXP
+#define FLT_MAX_10_EXP 38
+
+ /* Number of base-FLT_RADIX digits in the significand of a double */
+#undef DBL_MANT_DIG
+#define DBL_MANT_DIG 53
+ /* Number of decimal digits of precision in a double */
+#undef DBL_DIG
+#define DBL_DIG 15
+ /* Difference between 1.0 and the minimum double greater than 1.0 */
+#undef DBL_EPSILON
+#define DBL_EPSILON 2.2204460492503131e-16
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */
+#undef DBL_MIN_EXP
+#define DBL_MIN_EXP (-1021)
+ /* Minimum normalised double */
+#undef DBL_MIN
+#define DBL_MIN 2.2250738585072014e-308
+ /* Minimum int x such that 10**x is a normalised double */
+#undef DBL_MIN_10_EXP
+#define DBL_MIN_10_EXP (-307)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */
+#undef DBL_MAX_EXP
+#define DBL_MAX_EXP 1024
+ /* Maximum double */
+#undef DBL_MAX
+#define DBL_MAX 1.7976931348623157e+308
+ /* Maximum int x such that 10**x is a representable double */
+#undef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP 308
+
+ /* Number of base-FLT_RADIX digits in the significand of a long double */
+#undef LDBL_MANT_DIG
+#define LDBL_MANT_DIG 113
+ /* Number of decimal digits of precision in a long double */
+#undef LDBL_DIG
+#define LDBL_DIG 33
+ /* Difference between 1.0 and the minimum long double greater than 1.0 */
+#undef LDBL_EPSILON
+#define LDBL_EPSILON 1.925929944387235853055977942584927319E-34L
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */
+#undef LDBL_MIN_EXP
+#define LDBL_MIN_EXP (-16381)
+ /* Minimum normalised long double */
+#undef LDBL_MIN
+#define LDBL_MIN 3.362103143112093506262677817321752603E-4932L
+ /* Minimum int x such that 10**x is a normalised long double */
+#undef LDBL_MIN_10_EXP
+#define LDBL_MIN_10_EXP (-4931)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */
+#undef LDBL_MAX_EXP
+#define LDBL_MAX_EXP 16384
+ /* Maximum long double */
+#undef LDBL_MAX
+#define LDBL_MAX 1.189731495357231765085759326628007016E+4932L
+ /* Maximum int x such that 10**x is a representable long double */
+#undef LDBL_MAX_10_EXP
+#define LDBL_MAX_10_EXP 4932
+
+#endif /* _FLOAT_H_ */
diff --git a/contrib/gcc/config/float-i32.h b/contrib/gcc/config/float-i32.h
new file mode 100644
index 0000000..c834926
--- /dev/null
+++ b/contrib/gcc/config/float-i32.h
@@ -0,0 +1,96 @@
+/* float.h for target with only IEEE 32 bit floating point format */
+#ifndef _FLOAT_H_
+#define _FLOAT_H_
+/* Produced by enquire version 4.3, CWI, Amsterdam */
+
+ /* Radix of exponent representation */
+#undef FLT_RADIX
+#define FLT_RADIX 2
+ /* Number of base-FLT_RADIX digits in the significand of a float */
+#undef FLT_MANT_DIG
+#define FLT_MANT_DIG 24
+ /* Number of decimal digits of precision in a float */
+#undef FLT_DIG
+#define FLT_DIG 6
+ /* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown */
+#undef FLT_ROUNDS
+#define FLT_ROUNDS 1
+ /* Difference between 1.0 and the minimum float greater than 1.0 */
+#undef FLT_EPSILON
+#define FLT_EPSILON 1.19209290e-07F
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */
+#undef FLT_MIN_EXP
+#define FLT_MIN_EXP (-125)
+ /* Minimum normalised float */
+#undef FLT_MIN
+#define FLT_MIN 1.17549435e-38F
+ /* Minimum int x such that 10**x is a normalised float */
+#undef FLT_MIN_10_EXP
+#define FLT_MIN_10_EXP (-37)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable float */
+#undef FLT_MAX_EXP
+#define FLT_MAX_EXP 128
+ /* Maximum float */
+#undef FLT_MAX
+#define FLT_MAX 3.40282347e+38F
+ /* Maximum int x such that 10**x is a representable float */
+#undef FLT_MAX_10_EXP
+#define FLT_MAX_10_EXP 38
+
+ /* Number of base-FLT_RADIX digits in the significand of a double */
+#undef DBL_MANT_DIG
+#define DBL_MANT_DIG 24
+ /* Number of decimal digits of precision in a double */
+#undef DBL_DIG
+#define DBL_DIG 6
+ /* Difference between 1.0 and the minimum double greater than 1.0 */
+#undef DBL_EPSILON
+#define DBL_EPSILON 1.19209290e-07F
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */
+#undef DBL_MIN_EXP
+#define DBL_MIN_EXP (-125)
+ /* Minimum normalised double */
+#undef DBL_MIN
+#define DBL_MIN 1.17549435e-38F
+ /* Minimum int x such that 10**x is a normalised double */
+#undef DBL_MIN_10_EXP
+#define DBL_MIN_10_EXP (-37)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */
+#undef DBL_MAX_EXP
+#define DBL_MAX_EXP 128
+ /* Maximum double */
+#undef DBL_MAX
+#define DBL_MAX 3.40282347e+38F
+ /* Maximum int x such that 10**x is a representable double */
+#undef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP 38
+
+ /* Number of base-FLT_RADIX digits in the significand of a long double */
+#undef LDBL_MANT_DIG
+#define LDBL_MANT_DIG 24
+ /* Number of decimal digits of precision in a long double */
+#undef LDBL_DIG
+#define LDBL_DIG 6
+ /* Difference between 1.0 and the minimum long double greater than 1.0 */
+#undef LDBL_EPSILON
+#define LDBL_EPSILON 1.19209290e-07F
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */
+#undef LDBL_MIN_EXP
+#define LDBL_MIN_EXP (-125)
+ /* Minimum normalised long double */
+#undef LDBL_MIN
+#define LDBL_MIN 1.17549435e-38F
+ /* Minimum int x such that 10**x is a normalised long double */
+#undef LDBL_MIN_10_EXP
+#define LDBL_MIN_10_EXP (-37)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */
+#undef LDBL_MAX_EXP
+#define LDBL_MAX_EXP 128
+ /* Maximum long double */
+#undef LDBL_MAX
+#define LDBL_MAX 3.40282347e+38F
+ /* Maximum int x such that 10**x is a representable long double */
+#undef LDBL_MAX_10_EXP
+#define LDBL_MAX_10_EXP 38
+
+#endif /* _FLOAT_H_ */
diff --git a/contrib/gcc/config/float-i386.h b/contrib/gcc/config/float-i386.h
new file mode 100644
index 0000000..2d14f70
--- /dev/null
+++ b/contrib/gcc/config/float-i386.h
@@ -0,0 +1,104 @@
+/* float.h for target with IEEE 32/64 bit and Intel 386 style 80 bit
+ floating point formats */
+#ifndef _FLOAT_H_
+#define _FLOAT_H_
+/* Produced by enquire version 4.3, CWI, Amsterdam */
+
+ /* Radix of exponent representation */
+#undef FLT_RADIX
+#define FLT_RADIX 2
+ /* Number of base-FLT_RADIX digits in the significand of a float */
+#undef FLT_MANT_DIG
+#define FLT_MANT_DIG 24
+ /* Number of decimal digits of precision in a float */
+#undef FLT_DIG
+#define FLT_DIG 6
+ /* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown */
+#undef FLT_ROUNDS
+#define FLT_ROUNDS 1
+ /* Difference between 1.0 and the minimum float greater than 1.0 */
+#undef FLT_EPSILON
+#define FLT_EPSILON 1.19209290e-07F
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */
+#undef FLT_MIN_EXP
+#define FLT_MIN_EXP (-125)
+ /* Minimum normalised float */
+#undef FLT_MIN
+#define FLT_MIN 1.17549435e-38F
+ /* Minimum int x such that 10**x is a normalised float */
+#undef FLT_MIN_10_EXP
+#define FLT_MIN_10_EXP (-37)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable float */
+#undef FLT_MAX_EXP
+#define FLT_MAX_EXP 128
+ /* Maximum float */
+#undef FLT_MAX
+#define FLT_MAX 3.40282347e+38F
+ /* Maximum int x such that 10**x is a representable float */
+#undef FLT_MAX_10_EXP
+#define FLT_MAX_10_EXP 38
+
+ /* Number of base-FLT_RADIX digits in the significand of a double */
+#undef DBL_MANT_DIG
+#define DBL_MANT_DIG 53
+ /* Number of decimal digits of precision in a double */
+#undef DBL_DIG
+#define DBL_DIG 15
+ /* Difference between 1.0 and the minimum double greater than 1.0 */
+#undef DBL_EPSILON
+#define DBL_EPSILON 2.2204460492503131e-16
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */
+#undef DBL_MIN_EXP
+#define DBL_MIN_EXP (-1021)
+ /* Minimum normalised double */
+#undef DBL_MIN
+#define DBL_MIN 2.2250738585072014e-308
+ /* Minimum int x such that 10**x is a normalised double */
+#undef DBL_MIN_10_EXP
+#define DBL_MIN_10_EXP (-307)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */
+#undef DBL_MAX_EXP
+#define DBL_MAX_EXP 1024
+ /* Maximum double */
+#undef DBL_MAX
+#define DBL_MAX 1.7976931348623157e+308
+ /* Maximum int x such that 10**x is a representable double */
+#undef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP 308
+
+ /* Number of base-FLT_RADIX digits in the significand of a long double */
+#undef LDBL_MANT_DIG
+#define LDBL_MANT_DIG 64
+ /* Number of decimal digits of precision in a long double */
+#undef LDBL_DIG
+#define LDBL_DIG 18
+ /* Difference between 1.0 and the minimum long double greater than 1.0 */
+#undef LDBL_EPSILON
+#ifndef __LDBL_UNION__
+#define __LDBL_UNION__
+union __convert_long_double {
+ unsigned __convert_long_double_i[4];
+ long double __convert_long_double_d;
+};
+#endif
+#define LDBL_EPSILON (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x3fc0, 0x0}}).__convert_long_double_d)
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */
+#undef LDBL_MIN_EXP
+#define LDBL_MIN_EXP (-16381)
+ /* Minimum normalised long double */
+#undef LDBL_MIN
+#define LDBL_MIN (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x0, 0x80000000, 0x1, 0x0}}).__convert_long_double_d)
+ /* Minimum int x such that 10**x is a normalised long double */
+#undef LDBL_MIN_10_EXP
+#define LDBL_MIN_10_EXP (-4931)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */
+#undef LDBL_MAX_EXP
+#define LDBL_MAX_EXP 16384
+ /* Maximum long double */
+#undef LDBL_MAX
+#define LDBL_MAX (__extension__ ((union __convert_long_double) {__convert_long_double_i: {0xffffffff, 0xffffffff, 0x107ffe, 0x0}}).__convert_long_double_d)
+ /* Maximum int x such that 10**x is a representable long double */
+#undef LDBL_MAX_10_EXP
+#define LDBL_MAX_10_EXP 4932
+
+#endif /* _FLOAT_H___ */
diff --git a/contrib/gcc/config/float-i64.h b/contrib/gcc/config/float-i64.h
new file mode 100644
index 0000000..7dbe4e9
--- /dev/null
+++ b/contrib/gcc/config/float-i64.h
@@ -0,0 +1,96 @@
+/* float.h for target with IEEE 32 bit and 64 bit floating point formats */
+#ifndef _FLOAT_H_
+#define _FLOAT_H_
+/* Produced by enquire version 4.3, CWI, Amsterdam */
+
+ /* Radix of exponent representation */
+#undef FLT_RADIX
+#define FLT_RADIX 2
+ /* Number of base-FLT_RADIX digits in the significand of a float */
+#undef FLT_MANT_DIG
+#define FLT_MANT_DIG 24
+ /* Number of decimal digits of precision in a float */
+#undef FLT_DIG
+#define FLT_DIG 6
+ /* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown */
+#undef FLT_ROUNDS
+#define FLT_ROUNDS 1
+ /* Difference between 1.0 and the minimum float greater than 1.0 */
+#undef FLT_EPSILON
+#define FLT_EPSILON 1.19209290e-07F
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */
+#undef FLT_MIN_EXP
+#define FLT_MIN_EXP (-125)
+ /* Minimum normalised float */
+#undef FLT_MIN
+#define FLT_MIN 1.17549435e-38F
+ /* Minimum int x such that 10**x is a normalised float */
+#undef FLT_MIN_10_EXP
+#define FLT_MIN_10_EXP (-37)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable float */
+#undef FLT_MAX_EXP
+#define FLT_MAX_EXP 128
+ /* Maximum float */
+#undef FLT_MAX
+#define FLT_MAX 3.40282347e+38F
+ /* Maximum int x such that 10**x is a representable float */
+#undef FLT_MAX_10_EXP
+#define FLT_MAX_10_EXP 38
+
+ /* Number of base-FLT_RADIX digits in the significand of a double */
+#undef DBL_MANT_DIG
+#define DBL_MANT_DIG 53
+ /* Number of decimal digits of precision in a double */
+#undef DBL_DIG
+#define DBL_DIG 15
+ /* Difference between 1.0 and the minimum double greater than 1.0 */
+#undef DBL_EPSILON
+#define DBL_EPSILON 2.2204460492503131e-16
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */
+#undef DBL_MIN_EXP
+#define DBL_MIN_EXP (-1021)
+ /* Minimum normalised double */
+#undef DBL_MIN
+#define DBL_MIN 2.2250738585072014e-308
+ /* Minimum int x such that 10**x is a normalised double */
+#undef DBL_MIN_10_EXP
+#define DBL_MIN_10_EXP (-307)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */
+#undef DBL_MAX_EXP
+#define DBL_MAX_EXP 1024
+ /* Maximum double */
+#undef DBL_MAX
+#define DBL_MAX 1.7976931348623157e+308
+ /* Maximum int x such that 10**x is a representable double */
+#undef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP 308
+
+ /* Number of base-FLT_RADIX digits in the significand of a long double */
+#undef LDBL_MANT_DIG
+#define LDBL_MANT_DIG 53
+ /* Number of decimal digits of precision in a long double */
+#undef LDBL_DIG
+#define LDBL_DIG 15
+ /* Difference between 1.0 and the minimum long double greater than 1.0 */
+#undef LDBL_EPSILON
+#define LDBL_EPSILON 2.2204460492503131e-16L
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */
+#undef LDBL_MIN_EXP
+#define LDBL_MIN_EXP (-1021)
+ /* Minimum normalised long double */
+#undef LDBL_MIN
+#define LDBL_MIN 2.2250738585072014e-308L
+ /* Minimum int x such that 10**x is a normalised long double */
+#undef LDBL_MIN_10_EXP
+#define LDBL_MIN_10_EXP (-307)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */
+#undef LDBL_MAX_EXP
+#define LDBL_MAX_EXP 1024
+ /* Maximum long double */
+#undef LDBL_MAX
+#define LDBL_MAX 1.7976931348623157e+308L
+ /* Maximum int x such that 10**x is a representable long double */
+#undef LDBL_MAX_10_EXP
+#define LDBL_MAX_10_EXP 308
+
+#endif /* _FLOAT_H_ */
diff --git a/contrib/gcc/config/float-m68k.h b/contrib/gcc/config/float-m68k.h
new file mode 100644
index 0000000..b36d447
--- /dev/null
+++ b/contrib/gcc/config/float-m68k.h
@@ -0,0 +1,97 @@
+/* float.h for target with IEEE 32 bit and 64 bit and Motorola style 96 bit
+ floating point formats */
+#ifndef _FLOAT_H_
+#define _FLOAT_H_
+/* Produced by enquire version 4.3, CWI, Amsterdam */
+
+ /* Radix of exponent representation */
+#undef FLT_RADIX
+#define FLT_RADIX 2
+ /* Number of base-FLT_RADIX digits in the significand of a float */
+#undef FLT_MANT_DIG
+#define FLT_MANT_DIG 24
+ /* Number of decimal digits of precision in a float */
+#undef FLT_DIG
+#define FLT_DIG 6
+ /* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown */
+#undef FLT_ROUNDS
+#define FLT_ROUNDS 1
+ /* Difference between 1.0 and the minimum float greater than 1.0 */
+#undef FLT_EPSILON
+#define FLT_EPSILON 1.19209290e-07F
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */
+#undef FLT_MIN_EXP
+#define FLT_MIN_EXP (-125)
+ /* Minimum normalised float */
+#undef FLT_MIN
+#define FLT_MIN 1.17549435e-38F
+ /* Minimum int x such that 10**x is a normalised float */
+#undef FLT_MIN_10_EXP
+#define FLT_MIN_10_EXP (-37)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable float */
+#undef FLT_MAX_EXP
+#define FLT_MAX_EXP 128
+ /* Maximum float */
+#undef FLT_MAX
+#define FLT_MAX 3.40282347e+38F
+ /* Maximum int x such that 10**x is a representable float */
+#undef FLT_MAX_10_EXP
+#define FLT_MAX_10_EXP 38
+
+ /* Number of base-FLT_RADIX digits in the significand of a double */
+#undef DBL_MANT_DIG
+#define DBL_MANT_DIG 53
+ /* Number of decimal digits of precision in a double */
+#undef DBL_DIG
+#define DBL_DIG 15
+ /* Difference between 1.0 and the minimum double greater than 1.0 */
+#undef DBL_EPSILON
+#define DBL_EPSILON 2.2204460492503131e-16
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */
+#undef DBL_MIN_EXP
+#define DBL_MIN_EXP (-1021)
+ /* Minimum normalised double */
+#undef DBL_MIN
+#define DBL_MIN 2.2250738585072014e-308
+ /* Minimum int x such that 10**x is a normalised double */
+#undef DBL_MIN_10_EXP
+#define DBL_MIN_10_EXP (-307)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */
+#undef DBL_MAX_EXP
+#define DBL_MAX_EXP 1024
+ /* Maximum double */
+#undef DBL_MAX
+#define DBL_MAX 1.7976931348623157e+308
+ /* Maximum int x such that 10**x is a representable double */
+#undef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP 308
+
+ /* Number of base-FLT_RADIX digits in the significand of a long double */
+#undef LDBL_MANT_DIG
+#define LDBL_MANT_DIG 64
+ /* Number of decimal digits of precision in a long double */
+#undef LDBL_DIG
+#define LDBL_DIG 18
+ /* Difference between 1.0 and the minimum long double greater than 1.0 */
+#undef LDBL_EPSILON
+#define LDBL_EPSILON 1.08420217248550443401e-19L
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */
+#undef LDBL_MIN_EXP
+#define LDBL_MIN_EXP (-16382)
+ /* Minimum normalised long double */
+#undef LDBL_MIN
+#define LDBL_MIN 1.68105157155604675313e-4932L
+ /* Minimum int x such that 10**x is a normalised long double */
+#undef LDBL_MIN_10_EXP
+#define LDBL_MIN_10_EXP (-4931)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */
+#undef LDBL_MAX_EXP
+#define LDBL_MAX_EXP 16384
+ /* Maximum long double */
+#undef LDBL_MAX
+#define LDBL_MAX 1.18973149535723176502e+4932L
+ /* Maximum int x such that 10**x is a representable long double */
+#undef LDBL_MAX_10_EXP
+#define LDBL_MAX_10_EXP 4932
+
+#endif /* _FLOAT_H_ */
diff --git a/contrib/gcc/config/float-sh.h b/contrib/gcc/config/float-sh.h
new file mode 100644
index 0000000..9a94298
--- /dev/null
+++ b/contrib/gcc/config/float-sh.h
@@ -0,0 +1,130 @@
+/* float.h for target sh3e with optional IEEE 32 bit double format */
+#ifndef _FLOAT_H_
+#define _FLOAT_H_
+/* Produced by enquire version 4.3, CWI, Amsterdam */
+
+ /* Radix of exponent representation */
+#undef FLT_RADIX
+#define FLT_RADIX 2
+ /* Number of base-FLT_RADIX digits in the significand of a float */
+#undef FLT_MANT_DIG
+#define FLT_MANT_DIG 24
+ /* Number of decimal digits of precision in a float */
+#undef FLT_DIG
+#define FLT_DIG 6
+ /* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown */
+#undef FLT_ROUNDS
+#define FLT_ROUNDS 1
+ /* Difference between 1.0 and the minimum float greater than 1.0 */
+#undef FLT_EPSILON
+#define FLT_EPSILON 1.19209290e-07F
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */
+#undef FLT_MIN_EXP
+#define FLT_MIN_EXP (-125)
+ /* Minimum normalised float */
+#undef FLT_MIN
+#define FLT_MIN 1.17549435e-38F
+ /* Minimum int x such that 10**x is a normalised float */
+#undef FLT_MIN_10_EXP
+#define FLT_MIN_10_EXP (-37)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable float */
+#undef FLT_MAX_EXP
+#define FLT_MAX_EXP 128
+ /* Maximum float */
+#undef FLT_MAX
+#define FLT_MAX 3.40282347e+38F
+ /* Maximum int x such that 10**x is a representable float */
+#undef FLT_MAX_10_EXP
+#define FLT_MAX_10_EXP 38
+
+#ifdef __SH3E__
+
+ /* Number of base-FLT_RADIX digits in the significand of a double */
+#undef DBL_MANT_DIG
+#define DBL_MANT_DIG 24
+ /* Number of decimal digits of precision in a double */
+#undef DBL_DIG
+#define DBL_DIG 6
+ /* Difference between 1.0 and the minimum double greater than 1.0 */
+#undef DBL_EPSILON
+#define DBL_EPSILON 1.19209290e-07F
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */
+#undef DBL_MIN_EXP
+#define DBL_MIN_EXP (-125)
+ /* Minimum normalised double */
+#undef DBL_MIN
+#define DBL_MIN 1.17549435e-38F
+ /* Minimum int x such that 10**x is a normalised double */
+#undef DBL_MIN_10_EXP
+#define DBL_MIN_10_EXP (-37)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */
+#undef DBL_MAX_EXP
+#define DBL_MAX_EXP 128
+ /* Maximum double */
+#undef DBL_MAX
+#define DBL_MAX 3.40282347e+38F
+ /* Maximum int x such that 10**x is a representable double */
+#undef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP 38
+
+#else
+
+ /* Number of base-FLT_RADIX digits in the significand of a double */
+#undef DBL_MANT_DIG
+#define DBL_MANT_DIG 53
+ /* Number of decimal digits of precision in a double */
+#undef DBL_DIG
+#define DBL_DIG 15
+ /* Difference between 1.0 and the minimum double greater than 1.0 */
+#undef DBL_EPSILON
+#define DBL_EPSILON 2.2204460492503131e-16
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */
+#undef DBL_MIN_EXP
+#define DBL_MIN_EXP (-1021)
+ /* Minimum normalised double */
+#undef DBL_MIN
+#define DBL_MIN 2.2250738585072014e-308
+ /* Minimum int x such that 10**x is a normalised double */
+#undef DBL_MIN_10_EXP
+#define DBL_MIN_10_EXP (-307)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */
+#undef DBL_MAX_EXP
+#define DBL_MAX_EXP 1024
+ /* Maximum double */
+#undef DBL_MAX
+#define DBL_MAX 1.7976931348623157e+308
+ /* Maximum int x such that 10**x is a representable double */
+#undef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP 308
+
+#endif
+
+ /* Number of base-FLT_RADIX digits in the significand of a long double */
+#undef LDBL_MANT_DIG
+#define LDBL_MANT_DIG 53
+ /* Number of decimal digits of precision in a long double */
+#undef LDBL_DIG
+#define LDBL_DIG 15
+ /* Difference between 1.0 and the minimum long double greater than 1.0 */
+#undef LDBL_EPSILON
+#define LDBL_EPSILON 2.2204460492503131e-16
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */
+#undef LDBL_MIN_EXP
+#define LDBL_MIN_EXP (-1021)
+ /* Minimum normalised long double */
+#undef LDBL_MIN
+#define LDBL_MIN 2.2250738585072014e-308
+ /* Minimum int x such that 10**x is a normalised long double */
+#undef LDBL_MIN_10_EXP
+#define LDBL_MIN_10_EXP (-307)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */
+#undef LDBL_MAX_EXP
+#define LDBL_MAX_EXP 1024
+ /* Maximum long double */
+#undef LDBL_MAX
+#define LDBL_MAX 1.7976931348623157e+308
+ /* Maximum int x such that 10**x is a representable long double */
+#undef LDBL_MAX_10_EXP
+#define LDBL_MAX_10_EXP 308
+
+#endif /* _FLOAT_H_ */
diff --git a/contrib/gcc/config/float-vax.h b/contrib/gcc/config/float-vax.h
new file mode 100644
index 0000000..3c87f79
--- /dev/null
+++ b/contrib/gcc/config/float-vax.h
@@ -0,0 +1,96 @@
+/* float.h for target with VAX floating point formats */
+#ifndef _FLOAT_H_
+#define _FLOAT_H_
+/* Produced by enquire version 4.3, CWI, Amsterdam */
+
+ /* Radix of exponent representation */
+#undef FLT_RADIX
+#define FLT_RADIX 2
+ /* Number of base-FLT_RADIX digits in the significand of a float */
+#undef FLT_MANT_DIG
+#define FLT_MANT_DIG 24
+ /* Number of decimal digits of precision in a float */
+#undef FLT_DIG
+#define FLT_DIG 6
+ /* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown */
+#undef FLT_ROUNDS
+#define FLT_ROUNDS 1
+ /* Difference between 1.0 and the minimum float greater than 1.0 */
+#undef FLT_EPSILON
+#define FLT_EPSILON 1.19209290e-07F
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised float */
+#undef FLT_MIN_EXP
+#define FLT_MIN_EXP (-127)
+ /* Minimum normalised float */
+#undef FLT_MIN
+#define FLT_MIN 2.93873588e-39F
+ /* Minimum int x such that 10**x is a normalised float */
+#undef FLT_MIN_10_EXP
+#define FLT_MIN_10_EXP (-38)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable float */
+#undef FLT_MAX_EXP
+#define FLT_MAX_EXP 127
+ /* Maximum float */
+#undef FLT_MAX
+#define FLT_MAX 1.70141173e+38F
+ /* Maximum int x such that 10**x is a representable float */
+#undef FLT_MAX_10_EXP
+#define FLT_MAX_10_EXP 38
+
+ /* Number of base-FLT_RADIX digits in the significand of a double */
+#undef DBL_MANT_DIG
+#define DBL_MANT_DIG 56
+ /* Number of decimal digits of precision in a double */
+#undef DBL_DIG
+#define DBL_DIG 16
+ /* Difference between 1.0 and the minimum double greater than 1.0 */
+#undef DBL_EPSILON
+#define DBL_EPSILON 2.77555756156289135e-17
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised double */
+#undef DBL_MIN_EXP
+#define DBL_MIN_EXP (-127)
+ /* Minimum normalised double */
+#undef DBL_MIN
+#define DBL_MIN 2.93873587705571877e-39
+ /* Minimum int x such that 10**x is a normalised double */
+#undef DBL_MIN_10_EXP
+#define DBL_MIN_10_EXP (-38)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable double */
+#undef DBL_MAX_EXP
+#define DBL_MAX_EXP 127
+ /* Maximum double */
+#undef DBL_MAX
+#define DBL_MAX 1.70141183460469229e+38
+ /* Maximum int x such that 10**x is a representable double */
+#undef DBL_MAX_10_EXP
+#define DBL_MAX_10_EXP 38
+
+ /* Number of base-FLT_RADIX digits in the significand of a long double */
+#undef LDBL_MANT_DIG
+#define LDBL_MANT_DIG 56
+ /* Number of decimal digits of precision in a long double */
+#undef LDBL_DIG
+#define LDBL_DIG 16
+ /* Difference between 1.0 and the minimum long double greater than 1.0 */
+#undef LDBL_EPSILON
+#define LDBL_EPSILON 2.77555756156289135e-17
+ /* Minimum int x such that FLT_RADIX**(x-1) is a normalised long double */
+#undef LDBL_MIN_EXP
+#define LDBL_MIN_EXP (-127)
+ /* Minimum normalised long double */
+#undef LDBL_MIN
+#define LDBL_MIN 2.93873587705571877e-39
+ /* Minimum int x such that 10**x is a normalised long double */
+#undef LDBL_MIN_10_EXP
+#define LDBL_MIN_10_EXP (-38)
+ /* Maximum int x such that FLT_RADIX**(x-1) is a representable long double */
+#undef LDBL_MAX_EXP
+#define LDBL_MAX_EXP 127
+ /* Maximum long double */
+#undef LDBL_MAX
+#define LDBL_MAX 1.70141183460469229e+38
+ /* Maximum int x such that 10**x is a representable long double */
+#undef LDBL_MAX_10_EXP
+#define LDBL_MAX_10_EXP 38
+
+#endif /* _FLOAT_H_ */
diff --git a/contrib/gcc/config/fp-bit.c b/contrib/gcc/config/fp-bit.c
index 4ee08f1..f4a1e2a 100644
--- a/contrib/gcc/config/fp-bit.c
+++ b/contrib/gcc/config/fp-bit.c
@@ -1,8 +1,7 @@
/* This is a software floating point library which can be used instead of
the floating point routines in libgcc1.c for targets without hardware
- floating point. */
-
-/* Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ floating point.
+ Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@@ -44,6 +43,55 @@ Boston, MA 02111-1307, USA. */
/* The intended way to use this file is to make two copies, add `#define FLOAT'
to one copy, then compile both copies and add them to libgcc.a. */
+/* Defining FINE_GRAINED_LIBRARIES allows one to select which routines
+ from this file are compiled via additional -D options.
+
+ This avoids the need to pull in the entire fp emulation library
+ when only a small number of functions are needed.
+
+ If FINE_GRAINED_LIBRARIES is not defined, then compile every
+ suitable routine. */
+#ifndef FINE_GRAINED_LIBRARIES
+#define L_pack_df
+#define L_unpack_df
+#define L_pack_sf
+#define L_unpack_sf
+#define L_addsub_sf
+#define L_addsub_df
+#define L_mul_sf
+#define L_mul_df
+#define L_div_sf
+#define L_div_df
+#define L_fpcmp_parts_sf
+#define L_fpcmp_parts_df
+#define L_compare_sf
+#define L_compare_df
+#define L_eq_sf
+#define L_eq_df
+#define L_ne_sf
+#define L_ne_df
+#define L_gt_sf
+#define L_gt_df
+#define L_ge_sf
+#define L_ge_df
+#define L_lt_sf
+#define L_lt_df
+#define L_le_sf
+#define L_le_df
+#define L_si_to_sf
+#define L_si_to_df
+#define L_sf_to_si
+#define L_df_to_si
+#define L_f_to_usi
+#define L_df_to_usi
+#define L_negate_sf
+#define L_negate_df
+#define L_make_sf
+#define L_make_df
+#define L_sf_to_df
+#define L_df_to_sf
+#endif
+
/* The following macros can be defined to change the behaviour of this file:
FLOAT: Implement a `float', aka SFmode, fp library. If this is not
defined, then this file implements a `double', aka DFmode, fp library.
@@ -62,6 +110,52 @@ Boston, MA 02111-1307, USA. */
SMALL_MACHINE: Useful when operations on QIs and HIs are faster
than on an SI */
+/* We don't currently support extended floats (long doubles) on machines
+ without hardware to deal with them.
+
+ These stubs are just to keep the linker from complaining about unresolved
+ references which can be pulled in from libio & libstdc++, even if the
+ user isn't using long doubles. However, they may generate an unresolved
+ external to abort if abort is not used by the function, and the stubs
+ are referenced from within libc, since libgcc goes before and after the
+ system library. */
+
+#ifdef EXTENDED_FLOAT_STUBS
+__truncxfsf2 (){ abort(); }
+__extendsfxf2 (){ abort(); }
+__addxf3 (){ abort(); }
+__divxf3 (){ abort(); }
+__eqxf2 (){ abort(); }
+__extenddfxf2 (){ abort(); }
+__gtxf2 (){ abort(); }
+__lexf2 (){ abort(); }
+__ltxf2 (){ abort(); }
+__mulxf3 (){ abort(); }
+__negxf2 (){ abort(); }
+__nexf2 (){ abort(); }
+__subxf3 (){ abort(); }
+__truncxfdf2 (){ abort(); }
+
+__trunctfsf2 (){ abort(); }
+__extendsftf2 (){ abort(); }
+__addtf3 (){ abort(); }
+__divtf3 (){ abort(); }
+__eqtf2 (){ abort(); }
+__extenddftf2 (){ abort(); }
+__gttf2 (){ abort(); }
+__letf2 (){ abort(); }
+__lttf2 (){ abort(); }
+__multf3 (){ abort(); }
+__negtf2 (){ abort(); }
+__netf2 (){ abort(); }
+__subtf3 (){ abort(); }
+__trunctfdf2 (){ abort(); }
+__gexf2 (){ abort(); }
+__fixxfsi (){ abort(); }
+__floatsixf (){ abort(); }
+#else /* !EXTENDED_FLOAT_STUBS, rest of file */
+
+
typedef SFtype __attribute__ ((mode (SF)));
typedef DFtype __attribute__ ((mode (DF)));
@@ -99,8 +193,9 @@ typedef unsigned int UDItype __attribute__ ((mode (DI)));
# define FRAC_NBITS 32
# define FRACHIGH 0x80000000L
# define FRACHIGH2 0xc0000000L
-# define pack_d pack_f
-# define unpack_d unpack_f
+# define pack_d __pack_f
+# define unpack_d __unpack_f
+# define __fpcmp_parts __fpcmp_parts_f
typedef USItype fractype;
typedef UHItype halffractype;
typedef SFtype FLO_type;
@@ -121,6 +216,9 @@ typedef unsigned int UDItype __attribute__ ((mode (DI)));
# define FRAC_NBITS 64
# define FRACHIGH 0x8000000000000000LL
# define FRACHIGH2 0xc000000000000000LL
+# define pack_d __pack_d
+# define unpack_d __unpack_d
+# define __fpcmp_parts __fpcmp_parts_d
typedef UDItype fractype;
typedef USItype halffractype;
typedef DFtype FLO_type;
@@ -191,7 +289,9 @@ typedef unsigned int UDItype __attribute__ ((mode (DI)));
#endif
+#ifndef INLINE
#define INLINE __inline__
+#endif
/* Preserve the sticky-bit when shifting fractions to the right. */
#define LSHIFT(a) { a = (a & 1) | (a >> 1); }
@@ -199,7 +299,7 @@ typedef unsigned int UDItype __attribute__ ((mode (DI)));
/* numeric parameters */
/* F_D_BITOFF is the number of bits offset between the MSB of the mantissa
of a float and of a double. Assumes there are only two float types.
- (double::FRAC_BITS+double::NGARGS-(float::FRAC_BITS-float::NGARDS))
+ (double::FRAC_BITS+double::NGARDS-(float::FRAC_BITS-float::NGARDS))
*/
#define F_D_BITOFF (52+8-(23+7))
@@ -328,7 +428,10 @@ flip_sign ( fp_number_type * x)
x->sign = !x->sign;
}
-static FLO_type
+extern FLO_type pack_d ( fp_number_type * );
+
+#if defined(L_pack_df) || defined(L_pack_sf)
+FLO_type
pack_d ( fp_number_type * src)
{
FLO_union_type dst;
@@ -414,7 +517,7 @@ pack_d ( fp_number_type * src)
}
/* We previously used bitfields to store the number, but this doesn't
- handle little/big endian systems conviently, so use shifts and
+ handle little/big endian systems conveniently, so use shifts and
masks */
#ifdef FLOAT_BIT_ORDER_MISMATCH
dst.bits.fraction = fraction;
@@ -436,12 +539,16 @@ pack_d ( fp_number_type * src)
return dst.value;
}
+#endif
-static void
+extern void unpack_d (FLO_union_type *, fp_number_type *);
+
+#if defined(L_unpack_df) || defined(L_unpack_sf)
+void
unpack_d (FLO_union_type * src, fp_number_type * dst)
{
/* We previously used bitfields to store the number, but this doesn't
- handle little/big endian systems conviently, so use shifts and
+ handle little/big endian systems conveniently, so use shifts and
masks */
fractype fraction;
int exp;
@@ -504,13 +611,13 @@ unpack_d (FLO_union_type * src, fp_number_type * dst)
else
{
/* Non zero fraction, means nan */
- if (sign)
+ if (fraction & QUIET_NAN)
{
- dst->class = CLASS_SNAN;
+ dst->class = CLASS_QNAN;
}
else
{
- dst->class = CLASS_QNAN;
+ dst->class = CLASS_SNAN;
}
/* Keep the fraction part as the nan number */
dst->fraction.ll = fraction;
@@ -524,7 +631,9 @@ unpack_d (FLO_union_type * src, fp_number_type * dst)
dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1;
}
}
+#endif
+#if defined(L_addsub_sf) || defined(L_addsub_df)
static fp_number_type *
_fpadd_parts (fp_number_type * a,
fp_number_type * b,
@@ -559,6 +668,12 @@ _fpadd_parts (fp_number_type * a,
}
if (iszero (b))
{
+ if (iszero (a))
+ {
+ *tmp = *a;
+ tmp->sign = a->sign & b->sign;
+ return tmp;
+ }
return a;
}
if (iszero (a))
@@ -692,8 +807,10 @@ sub (FLO_type arg_a, FLO_type arg_b)
return pack_d (res);
}
+#endif
-static fp_number_type *
+#if defined(L_mul_sf) || defined(L_mul_df)
+static INLINE fp_number_type *
_fpmul_parts ( fp_number_type * a,
fp_number_type * b,
fp_number_type * tmp)
@@ -741,13 +858,13 @@ _fpmul_parts ( fp_number_type * a,
/* Calculate the mantissa by multiplying both 64bit numbers to get a
128 bit number */
{
- fractype x = a->fraction.ll;
- fractype ylow = b->fraction.ll;
- fractype yhigh = 0;
- int bit;
-
#if defined(NO_DI_MODE)
{
+ fractype x = a->fraction.ll;
+ fractype ylow = b->fraction.ll;
+ fractype yhigh = 0;
+ int bit;
+
/* ??? This does multiplies one bit at a time. Optimize. */
for (bit = 0; bit < FRAC_NBITS; bit++)
{
@@ -878,20 +995,18 @@ multiply (FLO_type arg_a, FLO_type arg_b)
return pack_d (res);
}
+#endif
-static fp_number_type *
+#if defined(L_div_sf) || defined(L_div_df)
+static INLINE fp_number_type *
_fpdiv_parts (fp_number_type * a,
fp_number_type * b,
fp_number_type * tmp)
{
- fractype low = 0;
- fractype high = 0;
- fractype r0, r1, y0, y1, bit;
- fractype q;
+ fractype bit;
fractype numerator;
fractype denominator;
fractype quotient;
- fractype remainder;
if (isnan (a))
{
@@ -901,13 +1016,15 @@ _fpdiv_parts (fp_number_type * a,
{
return b;
}
+
+ a->sign = a->sign ^ b->sign;
+
if (isinf (a) || iszero (a))
{
if (a->class == b->class)
return nan ();
return a;
}
- a->sign = a->sign ^ b->sign;
if (isinf (b))
{
@@ -918,15 +1035,12 @@ _fpdiv_parts (fp_number_type * a,
if (iszero (b))
{
a->class = CLASS_INFINITY;
- return b;
+ return a;
}
/* Calculate the mantissa by multiplying both 64bit numbers to get a
128 bit number */
{
- int carry;
- intfrac d0, d1; /* weren't unsigned before ??? */
-
/* quotient =
( numerator / denominator) * 2^(numerator exponent - denominator exponent)
*/
@@ -989,15 +1103,19 @@ divide (FLO_type arg_a, FLO_type arg_b)
return pack_d (res);
}
+#endif
+int __fpcmp_parts (fp_number_type * a, fp_number_type *b);
+
+#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df)
/* according to the demo, fpcmp returns a comparison with 0... thus
a<b -> -1
a==b -> 0
a>b -> +1
*/
-static int
-_fpcmp_parts (fp_number_type * a, fp_number_type * b)
+int
+__fpcmp_parts (fp_number_type * a, fp_number_type * b)
{
#if 0
/* either nan -> unordered. Must be checked outside of this routine. */
@@ -1072,7 +1190,9 @@ _fpcmp_parts (fp_number_type * a, fp_number_type * b)
/* after all that, they're equal. */
return 0;
}
+#endif
+#if defined(L_compare_sf) || defined(L_compare_df)
CMPtype
compare (FLO_type arg_a, FLO_type arg_b)
{
@@ -1082,13 +1202,15 @@ compare (FLO_type arg_a, FLO_type arg_b)
unpack_d ((FLO_union_type *) & arg_a, &a);
unpack_d ((FLO_union_type *) & arg_b, &b);
- return _fpcmp_parts (&a, &b);
+ return __fpcmp_parts (&a, &b);
}
+#endif
#ifndef US_SOFTWARE_GOFAST
/* These should be optimized for their specific tasks someday. */
+#if defined(L_eq_sf) || defined(L_eq_df)
CMPtype
_eq_f2 (FLO_type arg_a, FLO_type arg_b)
{
@@ -1101,9 +1223,11 @@ _eq_f2 (FLO_type arg_a, FLO_type arg_b)
if (isnan (&a) || isnan (&b))
return 1; /* false, truth == 0 */
- return _fpcmp_parts (&a, &b) ;
+ return __fpcmp_parts (&a, &b) ;
}
+#endif
+#if defined(L_ne_sf) || defined(L_ne_df)
CMPtype
_ne_f2 (FLO_type arg_a, FLO_type arg_b)
{
@@ -1116,9 +1240,11 @@ _ne_f2 (FLO_type arg_a, FLO_type arg_b)
if (isnan (&a) || isnan (&b))
return 1; /* true, truth != 0 */
- return _fpcmp_parts (&a, &b) ;
+ return __fpcmp_parts (&a, &b) ;
}
+#endif
+#if defined(L_gt_sf) || defined(L_gt_df)
CMPtype
_gt_f2 (FLO_type arg_a, FLO_type arg_b)
{
@@ -1131,9 +1257,11 @@ _gt_f2 (FLO_type arg_a, FLO_type arg_b)
if (isnan (&a) || isnan (&b))
return -1; /* false, truth > 0 */
- return _fpcmp_parts (&a, &b);
+ return __fpcmp_parts (&a, &b);
}
+#endif
+#if defined(L_ge_sf) || defined(L_ge_df)
CMPtype
_ge_f2 (FLO_type arg_a, FLO_type arg_b)
{
@@ -1145,9 +1273,11 @@ _ge_f2 (FLO_type arg_a, FLO_type arg_b)
if (isnan (&a) || isnan (&b))
return -1; /* false, truth >= 0 */
- return _fpcmp_parts (&a, &b) ;
+ return __fpcmp_parts (&a, &b) ;
}
+#endif
+#if defined(L_lt_sf) || defined(L_lt_df)
CMPtype
_lt_f2 (FLO_type arg_a, FLO_type arg_b)
{
@@ -1160,9 +1290,11 @@ _lt_f2 (FLO_type arg_a, FLO_type arg_b)
if (isnan (&a) || isnan (&b))
return 1; /* false, truth < 0 */
- return _fpcmp_parts (&a, &b);
+ return __fpcmp_parts (&a, &b);
}
+#endif
+#if defined(L_le_sf) || defined(L_le_df)
CMPtype
_le_f2 (FLO_type arg_a, FLO_type arg_b)
{
@@ -1175,11 +1307,13 @@ _le_f2 (FLO_type arg_a, FLO_type arg_b)
if (isnan (&a) || isnan (&b))
return 1; /* false, truth <= 0 */
- return _fpcmp_parts (&a, &b) ;
+ return __fpcmp_parts (&a, &b) ;
}
+#endif
#endif /* ! US_SOFTWARE_GOFAST */
+#if defined(L_si_to_sf) || defined(L_si_to_df)
FLO_type
si_to_float (SItype arg_a)
{
@@ -1215,7 +1349,9 @@ si_to_float (SItype arg_a)
}
return pack_d (&in);
}
+#endif
+#if defined(L_sf_to_si) || defined(L_df_to_si)
SItype
float_to_si (FLO_type arg_a)
{
@@ -1229,7 +1365,7 @@ float_to_si (FLO_type arg_a)
return 0;
/* get reasonable MAX_SI_INT... */
if (isinf (&a))
- return a.sign ? MAX_SI_INT : (-MAX_SI_INT)-1;
+ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
/* it is a number, but a small one */
if (a.normal_exp < 0)
return 0;
@@ -1238,7 +1374,9 @@ float_to_si (FLO_type arg_a)
tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
return a.sign ? (-tmp) : (tmp);
}
+#endif
+#if defined(L_sf_to_usi) || defined(L_df_to_usi)
#ifdef US_SOFTWARE_GOFAST
/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines,
we also define them for GOFAST because the ones in libgcc2.c have the
@@ -1256,24 +1394,26 @@ float_to_usi (FLO_type arg_a)
return 0;
if (isnan (&a))
return 0;
- /* get reasonable MAX_USI_INT... */
- if (isinf (&a))
- return a.sign ? MAX_USI_INT : 0;
/* it is a negative number */
if (a.sign)
return 0;
+ /* get reasonable MAX_USI_INT... */
+ if (isinf (&a))
+ return MAX_USI_INT;
/* it is a number, but a small one */
if (a.normal_exp < 0)
return 0;
if (a.normal_exp > 31)
return MAX_USI_INT;
else if (a.normal_exp > (FRACBITS + NGARDS))
- return a.fraction.ll << ((FRACBITS + NGARDS) - a.normal_exp);
+ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS));
else
return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
}
#endif
+#endif
+#if defined(L_negate_sf) || defined(L_negate_df)
FLO_type
negate (FLO_type arg_a)
{
@@ -1283,9 +1423,11 @@ negate (FLO_type arg_a)
flip_sign (&a);
return pack_d (&a);
}
+#endif
#ifdef FLOAT
+#if defined(L_make_sf)
SFtype
__make_fp(fp_class_type class,
unsigned int sign,
@@ -1300,6 +1442,7 @@ __make_fp(fp_class_type class,
in.fraction.ll = frac;
return pack_d (&in);
}
+#endif
#ifndef FLOAT_ONLY
@@ -1310,6 +1453,7 @@ __make_fp(fp_class_type class,
extern DFtype __make_dp (fp_class_type, unsigned int, int, UDItype frac);
+#if defined(L_sf_to_df)
DFtype
sf_to_df (SFtype arg_a)
{
@@ -1319,6 +1463,7 @@ sf_to_df (SFtype arg_a)
return __make_dp (in.class, in.sign, in.normal_exp,
((UDItype) in.fraction.ll) << F_D_BITOFF);
}
+#endif
#endif
#endif
@@ -1327,6 +1472,7 @@ sf_to_df (SFtype arg_a)
extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype);
+#if defined(L_make_df)
DFtype
__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
{
@@ -1338,15 +1484,27 @@ __make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
in.fraction.ll = frac;
return pack_d (&in);
}
+#endif
+#if defined(L_df_to_sf)
SFtype
df_to_sf (DFtype arg_a)
{
fp_number_type in;
+ USItype sffrac;
unpack_d ((FLO_union_type *) & arg_a, &in);
- return __make_fp (in.class, in.sign, in.normal_exp,
- in.fraction.ll >> F_D_BITOFF);
+
+ sffrac = in.fraction.ll >> F_D_BITOFF;
+
+ /* We set the lowest guard bit in SFFRAC if we discarded any non
+ zero bits. */
+ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0)
+ sffrac |= 1;
+
+ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
}
+#endif
#endif
+#endif /* !EXTENDED_FLOAT_STUBS */
diff --git a/contrib/gcc/config/gnu.h b/contrib/gcc/config/gnu.h
index 8ea3ead..d169164 100644
--- a/contrib/gcc/config/gnu.h
+++ b/contrib/gcc/config/gnu.h
@@ -1,12 +1,5 @@
/* Configuration common to all targets running the GNU system. */
-/* Macro to produce CPP_PREDEFINES for GNU on a given machine. */
-#define GNU_CPP_PREDEFINES(machine) \
-"-D" machine " -Acpu(" machine ") -Amachine(" machine ")" \
-"-Dunix -Asystem(unix) \
--DMACH -Asystem(mach) \
--D__GNU__ -Asystem(gnu)"
-
/* Provide GCC options for standard feature-test macros. */
#undef CPP_SPEC
#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{bsd:-D_BSD_SOURCE}"
diff --git a/contrib/gcc/config/i386/386bsd.h b/contrib/gcc/config/i386/386bsd.h
index cdab5f5..7962321 100644
--- a/contrib/gcc/config/i386/386bsd.h
+++ b/contrib/gcc/config/i386/386bsd.h
@@ -49,11 +49,6 @@
} \
}
-/* There are conflicting reports about whether this system uses
- a different assembler syntax. wilson@cygnus.com says # is right. */
-#undef COMMENT_BEGIN
-#define COMMENT_BEGIN "#"
-
#undef ASM_APP_ON
#define ASM_APP_ON "#APP\n"
@@ -68,13 +63,13 @@
i386.md for an explanation of the expression this outputs. */
#undef ASM_OUTPUT_ADDR_DIFF_ELT
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
/* Indicate that jump tables go in the text section. This is
necessary when compiling PIC code. */
-#define JUMP_TABLES_IN_TEXT_SECTION
+#define JUMP_TABLES_IN_TEXT_SECTION 1
/* Don't default to pcc-struct-return, because gcc is the only compiler, and
we want to retain compatibility with older gcc versions. */
diff --git a/contrib/gcc/config/i386/aix386ng.h b/contrib/gcc/config/i386/aix386ng.h
index 5d09fc3..a177b69 100644
--- a/contrib/gcc/config/i386/aix386ng.h
+++ b/contrib/gcc/config/i386/aix386ng.h
@@ -1,6 +1,6 @@
/* Definitions for IBM PS2 running AIX/386.
- From: Minh Tran-Le <TRANLE@intellicorp.com>
- Copyright (C) 1988 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1996 Free Software Foundation, Inc.
+ Contributed by Minh Tran-Le <TRANLE@intellicorp.com>.
This file is part of GNU CC.
@@ -27,7 +27,7 @@ Boston, MA 02111-1307, USA. */
#include "svr3.h"
/* Use the ATT assembler syntax.
- This overrides at least one macro (ASM_OUTPUT_LABELREF) from svr3.h. */
+ This overrides at least one macro (USER_LABEL_PREFIX) from svr3.h. */
#include "i386/att.h"
@@ -44,10 +44,10 @@ Boston, MA 02111-1307, USA. */
/* Specify predefined symbols in preprocessor. */
-#define CPP_PREDEFINES "-Dps2 -Dunix -Di386 -Asystem(unix) -Asystem(aix) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-Dps2 -Dunix -Asystem(aix)"
-#define CPP_SPEC \
- "%{posix:-D_POSIX_SOURCE}%{!posix:-DAIX} -D_I386 -D_AIX -D_MBCS"
+#define CPP_SPEC "%(cpp_cpu) \
+ %{posix:-D_POSIX_SOURCE}%{!posix:-DAIX} -D_I386 -D_AIX -D_MBCS"
/* special flags for the aix assembler to generate the short form for all
qualifying forward reference */
@@ -132,8 +132,7 @@ const_section () \
# undef EXTRA_SECTION_FUNCTIONS
# define EXTRA_SECTION_FUNCTIONS \
- CONST_SECTION_FUNCTION \
- BSS_SECTION_FUNCTION
+ CONST_SECTION_FUNCTION
/* for collect2 */
# define OBJECT_FORMAT_COFF
diff --git a/contrib/gcc/config/i386/att.h b/contrib/gcc/config/i386/att.h
index f8bbb76..e5c2d9c 100644
--- a/contrib/gcc/config/i386/att.h
+++ b/contrib/gcc/config/i386/att.h
@@ -1,5 +1,5 @@
/* Definitions for AT&T assembler syntax for the Intel 80386.
- Copyright (C) 1988 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -68,18 +68,6 @@ do \
/* Can't use ASM_OUTPUT_SKIP in text section; it doesn't leave 0s. */
#define ASM_NO_SKIP_IN_TEXT 1
-
-#undef BSS_SECTION_FUNCTION /* Override the definition from svr3.h. */
-#define BSS_SECTION_FUNCTION \
-void \
-bss_section () \
-{ \
- if (in_section != in_bss) \
- { \
- fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP); \
- in_section = in_bss; \
- } \
-}
/* Define the syntax of labels and symbol definitions/declarations. */
@@ -99,8 +87,7 @@ bss_section () \
#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
fprintf (FILE, ".%s%d:\n", PREFIX, NUM)
-/* This is how to output a reference to a user-level label named NAME. */
+/* The prefix to add to user-visible assembler symbols. */
-#undef ASM_OUTPUT_LABELREF
-#define ASM_OUTPUT_LABELREF(FILE,NAME) \
- fprintf (FILE, "%s", NAME)
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
diff --git a/contrib/gcc/config/i386/bsd.h b/contrib/gcc/config/i386/bsd.h
index 6bf7399..d50be36 100644
--- a/contrib/gcc/config/i386/bsd.h
+++ b/contrib/gcc/config/i386/bsd.h
@@ -1,7 +1,7 @@
/* Definitions for BSD assembler syntax for Intel 386
(actually AT&T syntax for insns and operands,
adapted to BSD conventions for symbol names and debugging.)
- Copyright (C) 1988 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -115,12 +115,12 @@ Boston, MA 02111-1307, USA. */
fprintf (FILE, "%s%d:\n", PREFIX, NUM)
#endif
-/* This is how to output a reference to a user-level label named NAME. */
+/* The prefix to add to user-visible assembler symbols. */
#ifdef NO_UNDERSCORES
-#define ASM_OUTPUT_LABELREF(FILE,NAME) fprintf (FILE, "%s", NAME)
+#define USER_LABEL_PREFIX ""
#else
-#define ASM_OUTPUT_LABELREF(FILE,NAME) fprintf (FILE, "_%s", NAME)
+#define USER_LABEL_PREFIX "_"
#endif /* not NO_UNDERSCORES */
/* Sequent has some changes in the format of DBX symbols. */
diff --git a/contrib/gcc/config/i386/bsd386.h b/contrib/gcc/config/i386/bsd386.h
index 935a2e0..c0dcf87 100644
--- a/contrib/gcc/config/i386/bsd386.h
+++ b/contrib/gcc/config/i386/bsd386.h
@@ -1,5 +1,5 @@
-/* Configuration for an i386 running BSDI's BSD/386 1.1 as the target
- machine. */
+/* Configuration for an i386 running BSDI's BSD/OS (formerly known as BSD/386)
+ as the target machine. */
#include "i386/386bsd.h"
@@ -16,3 +16,18 @@
#undef WCHAR_TYPE_SIZE
#define WCHAR_TYPE_SIZE 32
+
+/* This is suitable for BSD/OS 3.0; we don't know about earlier releases. */
+#undef ASM_COMMENT_START
+#define ASM_COMMENT_START " #"
+
+/* Until they use ELF or something that handles dwarf2 unwinds
+ and initialization stuff better. */
+#define DWARF2_UNWIND_INFO 0
+
+/* BSD/OS still uses old binutils that don't insert nops by default
+ when the .align directive demands to insert extra space in the text
+ segment. */
+#undef ASM_OUTPUT_ALIGN
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ if ((LOG)!=0) fprintf ((FILE), "\t.align %d,0x90\n", (LOG))
diff --git a/contrib/gcc/config/i386/crtdll.h b/contrib/gcc/config/i386/crtdll.h
new file mode 100644
index 0000000..f7eaf2b
--- /dev/null
+++ b/contrib/gcc/config/i386/crtdll.h
@@ -0,0 +1,42 @@
+/* Operating system specific defines to be used when targeting GCC for
+ hosting on Windows32, using GNU tools and the Windows32 API Library,
+ as distinct from winnt.h, which is used to build GCC for use with a
+ windows style library and tool set and uses the Microsoft tools.
+ This variant uses CRTDLL.DLL insted of MSVCRTDLL.DLL.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Di386 -D_WIN32 -DWIN32 -D__WIN32__ \
+ -D__MINGW32__ -DWINNT -D_X86_=1 -D__STDC__=1\
+ -D__stdcall=__attribute__((__stdcall__)) \
+ -D_stdcall=__attribute__((__stdcall__)) \
+ -D__cdecl=__attribute__((__cdecl__)) \
+ -D__declspec(x)=__attribute__((x)) \
+ -Asystem(winnt) -Acpu(i386) -Amachine(i386)"
+
+#undef LIBGCC_SPEC
+#define LIBGCC_SPEC "-lmingw32 -lgcc -lmoldname -lcrtdll"
+
+/* Specify a different entry point when linking a DLL */
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{mdll:dllcrt1%O%s} %{!mdll:crt1%O%s}"
+
+#undef MATH_LIBRARY
+#define MATH_LIBRARY "-lcrtdll"
diff --git a/contrib/gcc/config/i386/dgux.c b/contrib/gcc/config/i386/dgux.c
new file mode 100644
index 0000000..ff36135
--- /dev/null
+++ b/contrib/gcc/config/i386/dgux.c
@@ -0,0 +1,190 @@
+/* Subroutines for GNU compiler for Intel 80x86 running DG/ux
+ Copyright (C) 1993, 1995, 1997 Free Software Foundation, Inc.
+ Currently maintained by (gcc@dg-rtp.dg.com)
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <time.h>
+#include "i386/i386.c"
+
+
+extern char *version_string;
+
+struct option
+{
+ char *string;
+ int *variable;
+ int on_value;
+};
+
+static int
+output_option (file, sep, type, name, indent, pos, max)
+ FILE *file;
+ char *sep;
+ char *type;
+ char *name;
+ char *indent;
+ int pos;
+ int max;
+{
+ if (strlen (sep) + strlen (type) + strlen (name) + pos > max)
+ {
+ fprintf (file, indent);
+ return fprintf (file, "%s%s", type, name);
+ }
+ return pos + fprintf (file, "%s%s%s", sep, type, name);
+}
+
+static struct { char *name; int value; } m_options[] = TARGET_SWITCHES;
+
+static void
+output_options (file, f_options, f_len, W_options, W_len,
+ pos, max, sep, indent, term)
+ FILE *file;
+ struct option *f_options;
+ struct option *W_options;
+ int f_len, W_len;
+ int pos;
+ int max;
+ char *indent;
+ char *term;
+{
+ register int j;
+
+ if (optimize)
+ pos = output_option (file, sep, "-O", "", indent, pos, max);
+ if (write_symbols != NO_DEBUG)
+ pos = output_option (file, sep, "-g", "", indent, pos, max);
+/* if (flag_traditional)
+ pos = output_option (file, sep, "-traditional", "", indent, pos, max);*/
+ if (profile_flag)
+ pos = output_option (file, sep, "-p", "", indent, pos, max);
+ if (profile_block_flag)
+ pos = output_option (file, sep, "-a", "", indent, pos, max);
+
+ for (j = 0; j < f_len; j++)
+ if (*f_options[j].variable == f_options[j].on_value)
+ pos = output_option (file, sep, "-f", f_options[j].string,
+ indent, pos, max);
+
+ for (j = 0; j < W_len; j++)
+ if (*W_options[j].variable == W_options[j].on_value)
+ pos = output_option (file, sep, "-W", W_options[j].string,
+ indent, pos, max);
+
+ for (j = 0; j < sizeof m_options / sizeof m_options[0]; j++)
+ if (m_options[j].name[0] != '\0'
+ && m_options[j].value > 0
+ && ((m_options[j].value & target_flags)
+ == m_options[j].value))
+ pos = output_option (file, sep, "-m", m_options[j].name,
+ indent, pos, max);
+
+ pos = output_option (file, sep, "-mcpu=", ix86_cpu_string, indent, pos, max);
+ pos = output_option (file, sep, "-march=", ix86_arch_string, indent, pos, max);
+ fprintf (file, term);
+}
+
+/* Output to FILE the start of the assembler file. */
+
+void
+output_file_start (file, f_options, f_len, W_options, W_len)
+ FILE *file;
+ struct option *f_options;
+ struct option *W_options;
+ int f_len, W_len;
+{
+ register int pos;
+
+ output_file_directive (file, main_input_filename);
+ fprintf (file, "\t.version\t\"01.01\"\n"); \
+ /* Switch to the data section so that the coffsem symbol and the
+ gcc2_compiled. symbol aren't in the text section. */
+ data_section ();
+
+ pos = fprintf (file, "\n// cc1 (%s) arguments:", VERSION_STRING);
+ output_options (file, f_options, f_len, W_options, W_len,
+ pos, 75, " ", "\n// ", "\n\n");
+
+#ifdef TARGET_IDENTIFY_REVISION
+ if (TARGET_IDENTIFY_REVISION)
+ {
+ char indent[256];
+
+ time_t now = time ((time_t *)0);
+ sprintf (indent, "]\"\n\t%s\t \"@(#)%s [", IDENT_ASM_OP, main_input_filename);
+ fprintf (file, indent+3);
+ pos = fprintf (file, "gcc %s, %.24s,", VERSION_STRING, ctime (&now));
+ output_options (file, f_options, f_len, W_options, W_len,
+ pos, 150 - strlen (indent), " ", indent, "]\"\n\n");
+ }
+#endif /* TARGET_IDENTIFY_REVISION */
+}
+
+#ifndef CROSS_COMPILE
+#if defined (_abort_aux)
+/* Debugging aid to be registered via `atexit'. See the definition
+ of abort in dgux.h. */
+void
+abort_aux ()
+{
+ extern int insn_;
+ extern char * file_;
+ extern int line_;
+ static int done;
+ rtx line_note;
+
+ if (done++)
+ return;
+ if (file_ || line_)
+ {
+ if (write_symbols != NO_DEBUG)
+ {
+ for (line_note = (rtx) insn_ ; line_note != 0 ; line_note = PREV_INSN (line_note))
+ if (GET_CODE (line_note) == NOTE && NOTE_LINE_NUMBER (line_note) > 0)
+ break;
+ if (line_note != 0)
+ {
+ error_with_file_and_line (NOTE_SOURCE_FILE (line_note),
+ NOTE_LINE_NUMBER (line_note),
+ "Internal gcc abort from %s:%d",
+ file_ ? file_ : "<nofile>", line_);
+ if (insn_ && file_ && strcmp (file_, "toplev.c"))
+ {
+ error_with_file_and_line (NOTE_SOURCE_FILE (line_note),
+ NOTE_LINE_NUMBER (line_note),
+ "The local variable `insn' has the value:", 0);
+ debug_rtx ((rtx) insn_);
+ }
+ }
+ }
+ if (write_symbols == NO_DEBUG || line_note == 0)
+ {
+ error ("Internal gcc abort from %s:%d",
+ file_ ? file_ : "<nofile>", line_);
+ if (insn_ && file_ && strcmp (file_, "toplev.c"))
+ {
+ error ("The local variable `insn' has the value:", 0);
+ debug_rtx ((rtx) insn_);
+ }
+ }
+ }
+}
+#endif
+#endif
+
+
diff --git a/contrib/gcc/config/i386/dgux.h b/contrib/gcc/config/i386/dgux.h
new file mode 100644
index 0000000..dae050f
--- /dev/null
+++ b/contrib/gcc/config/i386/dgux.h
@@ -0,0 +1,265 @@
+/* Target definitions for GNU compiler for Intel 80x86 running DG/ux
+ Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Currently maintained by gcc@dg-rtp.dg.com.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* for now, we are just like the sysv4 version with a
+ few hacks
+*/
+
+#include "i386/sysv4.h"
+
+#ifndef VERSION_INFO2
+#define VERSION_INFO2 "$Revision: 1.3 $"
+#endif
+
+#ifndef VERSION_STRING
+#define VERSION_STRING version_string
+#endif
+
+/* Identify the compiler. */
+/* TARGET_VERSION used by toplev.c VERSION_STRING used by -midentify-revision */
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (%s%s, %s)", \
+ VERSION_INFO1, VERSION_INFO2, __DATE__)
+#undef VERSION_INFO1
+#define VERSION_INFO1 "ix86 DG/ux, "
+
+/* Augment TARGET_SWITCHES with the MXDB options. */
+#define MASK_STANDARD 0x40000000 /* Retain standard information */
+#define MASK_NOLEGEND 0x20000000 /* Discard legend information */
+#define MASK_EXTERNAL_LEGEND 0x10000000 /* Make external legends */
+#define MASK_IDENTIFY_REVISION 0x08000000 /* Emit 'ident' to .s */
+#define MASK_WARN_PASS_STRUCT 0x04000000 /* Emit 'ident' to .s */
+
+#define TARGET_STANDARD (target_flags & MASK_STANDARD)
+#define TARGET_NOLEGEND (target_flags & MASK_NOLEGEND)
+#define TARGET_EXTERNAL_LEGEND (target_flags & MASK_EXTERNAL_LEGEND)
+#define TARGET_IDENTIFY_REVISION (target_flags & MASK_IDENTIFY_REVISION)
+#define TARGET_WARN_PASS_STRUCT (target_flags & MASK_WARN_PASS_STRUCT)
+
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ { "standard", MASK_STANDARD }, \
+ { "legend", -MASK_NOLEGEND }, \
+ { "no-legend", MASK_NOLEGEND }, \
+ { "external-legend", MASK_EXTERNAL_LEGEND }, \
+ { "identify-revision", MASK_IDENTIFY_REVISION }, \
+ { "warn-passed-structs", MASK_WARN_PASS_STRUCT },
+
+#undef DWARF_DEBUGGING_INFO
+#define DWARF_DEBUGGING_INFO
+
+/*
+ allow -gstabs so that those who have gnu-as installed
+ can debug c++ programs.
+*/
+#undef DBX_DEBUGGING_INFO
+#define DBX_DEBUGGING_INFO
+
+#define PREFERRED_DEBUGGING_TYPE DWARF_DEBUG
+
+/* Override svr[34].h. */
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+ output_file_start (FILE, f_options, sizeof f_options / sizeof f_options[0], \
+ W_options, sizeof W_options / sizeof W_options[0])
+
+/* ix86 abi specified type for wchar_t */
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+
+/* Some machines may desire to change what optimizations are performed for
+ various optimization levels. This macro, if defined, is executed once
+ just after the optimization level is determined and before the remainder
+ of the command options have been parsed. Values set in this macro are
+ used as the default values for the other command line options.
+
+ LEVEL is the optimization level specified; 2 if -O2 is specified,
+ 1 if -O is specified, and 0 if neither is specified. */
+
+/* This macro used to store 0 in flag_signed_bitfields.
+ Not only is that misuse of this macro; the whole idea is wrong.
+
+ The GNU C dialect makes bitfields signed by default,
+ regardless of machine type. Making any machine inconsistent in this
+ regard is bad for portability.
+
+ I chose to make bitfields signed by default because this is consistent
+ with the way ordinary variables are handled: `int' equals `signed int'.
+ If there is a good reason to prefer making bitfields unsigned by default,
+ it cannot have anything to do with the choice of machine.
+ If the reason is good enough, we should change the convention for all machines.
+
+ -- rms, 20 July 1991. */
+
+/*
+ this really should go into dgux-local.h
+*/
+
+#undef OPTIMIZATION_OPTIONS
+#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) \
+ do { \
+ extern int flag_signed_bitfields; \
+ flag_signed_bitfields = 0; \
+ abort_helper (); \
+ optimization_options (LEVEL,SIZE); \
+ } while (0)
+
+
+/* The normal location of the `ld' and `as' programs */
+
+#undef MD_EXEC_PREFIX
+#define MD_EXEC_PREFIX "/usr/bin/"
+
+/* The normal location of the various *crt*.o files is the */
+
+#undef MD_STARTFILE_PREFIX
+#define MD_STARTFILE_PREFIX "/usr/lib/"
+
+/* Macros to be automatically defined.
+ __CLASSIFY_TYPE__ is used in the <varargs.h> and <stdarg.h> header
+ files with DG/UX revision 5.40 and later. This allows GNU CC to
+ operate without installing the header files. */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Di386 -D__ix86 -Dunix -DDGUX -D__CLASSIFY_TYPE__=2\
+ -Asystem(unix) -Asystem(svr4) -Acpu(i386) -Amachine(i386)"
+
+ /*
+ If not -ansi, -traditional, or restricting include files to one
+ specific source target, specify full DG/UX features.
+ */
+#undef CPP_SPEC
+#define CPP_SPEC "%{!ansi:%{!traditional:-D__OPEN_NAMESPACE__}}"
+
+/* Assembler support (legends for mxdb). */
+#undef ASM_SPEC
+#define ASM_SPEC "\
+%{mno-legend:%{mstandard:-Wc,off}}\
+%{g:%{!mno-legend:-Wc,-fix-bb,-s\"%i\"\
+%{traditional:,-lc}%{!traditional:,-lansi-c}\
+%{mstandard:,-keep-std}\
+%{mexternal-legend:,-external}}}"
+
+/* Override svr4.h. */
+
+/* hassey 3/12/94 keep svr4 ASM_FINAL_SPEC allows -pipe to work */
+
+/* Linker and library spec's.
+ -static, -shared, -symbolic, -h* and -z* access AT&T V.4 link options.
+ -svr4 instructs gcc to place /usr/lib/values-X[cat].o on link the line.
+ The absence of -msvr4 indicates linking done in a COFF environment and
+ adds the link script to the link line. In all environments, the first
+ and last objects are crtbegin.o and crtend.o.
+ When the -G link option is used (-shared and -symbolic) a final link is
+ not being done. */
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+"%{!shared:%{!symbolic:-lc}}"
+
+#undef LINK_SPEC
+#define LINK_SPEC "%{z*} %{h*} %{v:-V} \
+ %{static:-dn -Bstatic} \
+ %{shared:-G -dy} \
+ %{symbolic:-Bsymbolic -G -dy} \
+ %{pg:-L/usr/lib/libp}%{p:-L/usr/lib/libp}"
+
+#ifdef CROSS_COMPILE
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared:%{!symbolic:%{pg:gcrt1.o%s} \
+ %{!pg:%{p:mcrt1.o%s} \
+ %{!p:crt1.o%s}}}} \
+ %{pg:gcrti.o%s}%{!pg:crti.o%s} \
+ crtbegin.o%s \
+ %{ansi:values-Xc.o%s} \
+ %{!ansi:%{traditional:values-Xt.o%s} \
+ %{!traditional:values-Xa.o%s}}"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s %{pg:gcrtn.o}%{!pg:crtn.o%s}"
+
+#else
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared:%{!symbolic:%{pg:gcrt1.o%s} \
+ %{!pg:%{p:/lib/mcrt1.o%s} \
+ %{!p:/lib/crt1.o%s}}} \
+ %{pg:gcrti.o%s}%{!pg:/lib/crti.o%s}} \
+ crtbegin.o%s \
+ %{ansi:/lib/values-Xc.o%s} \
+ %{!ansi:%{traditional:/lib/values-Xt.o%s} \
+ %{!traditional:/lib/values-Xa.o%s}}"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s %{pg:gcrtn.o}%{!pg:/lib/crtn.o}"
+
+#endif /* CROSS_COMPILE */
+
+#if !defined (no_abort) || defined (CRT_BEGIN) || defined (CRT_END)
+#undef abort
+
+char insn; int insn_; char * file_; int line_;
+#define abort() \
+ (insn_ = (int) insn, \
+ file_ = __FILE__, \
+ line_ = __LINE__, \
+ fancy_abort ())
+#define abort_helper() \
+ do { \
+ extern void abort_aux (); \
+ atexit (abort_aux); \
+ } while (0)
+#define _abort_aux
+#endif /* no abort */
+
+/* The maximum alignment which the object file format can support.
+ page alignment would seem to be enough */
+#undef MAX_OFILE_ALIGNMENT
+#define MAX_OFILE_ALIGNMENT 0x1000
+
+/* Must use data section for relocatable constants when pic. */
+#undef SELECT_RTX_SECTION
+#define SELECT_RTX_SECTION(MODE,RTX) \
+{ \
+ if (flag_pic && symbolic_operand (RTX)) \
+ data_section (); \
+ else \
+ const_section (); \
+}
+
+/* This supplements FUNCTION_ARG's definition in i386.h to check
+ TARGET_WARN_PASS_STRUCT */
+
+#undef FUNCTION_ARG
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+((((MODE) == BLKmode && TARGET_WARN_PASS_STRUCT) ? \
+ warning ("argument is a structure"),0 : 0), \
+ (function_arg (&CUM, MODE, TYPE, NAMED)))
+
+/* Add .align 1 to avoid .backalign bug in assembler */
+#undef CONST_SECTION_ASM_OP
+#define CONST_SECTION_ASM_OP ".section\t.rodata\n\t.align 1"
diff --git a/contrib/gcc/config/i386/freebsd-elf.h b/contrib/gcc/config/i386/freebsd-elf.h
index 393ede7..0a556fe 100644
--- a/contrib/gcc/config/i386/freebsd-elf.h
+++ b/contrib/gcc/config/i386/freebsd-elf.h
@@ -1,8 +1,8 @@
/* Definitions for Intel 386 running FreeBSD with ELF format
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1996 Free Software Foundation, Inc.
Contributed by Eric Youngdale.
Modified for stabs-in-ELF by H.J. Lu.
- Adapted from Linux version by John Polstra.
+ Adapted from GNU/Linux version by John Polstra.
This file is part of GNU CC.
@@ -21,31 +21,29 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* A lie, I guess, but the general idea behind FreeBSD/ELF is that we are
- supposed to be outputting something that will assemble under SVr4.
- This gets us pretty close. */
-#include <i386/i386.h> /* Base i386 target machine definitions */
-#include <i386/att.h> /* Use the i386 AT&T assembler syntax */
-#include <linux.h> /* some common stuff */
-
#undef TARGET_VERSION
#define TARGET_VERSION fprintf (stderr, " (i386 FreeBSD/ELF)");
/* The svr4 ABI for the i386 says that records and unions are returned
in memory. */
+/* On FreeBSD, we do not. */
#undef DEFAULT_PCC_STRUCT_RETURN
-#define DEFAULT_PCC_STRUCT_RETURN 1
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* This gets defined in tm.h->linux.h->svr4.h, and keeps us from using
+ libraries compiled with the native cc, so undef it. */
+#undef NO_DOLLAR_IN_LABEL
/* This is how to output an element of a case-vector that is relative.
This is only used for PIC code. See comments by the `casesi' insn in
i386.md for an explanation of the expression this outputs. */
#undef ASM_OUTPUT_ADDR_DIFF_ELT
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
/* Indicate that jump tables go in the text section. This is
necessary when compiling PIC code. */
-#define JUMP_TABLES_IN_TEXT_SECTION
+#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic)
/* Copy this from the svr4 specifications... */
/* Define the register numbers to be used in Dwarf debugging information.
@@ -147,14 +145,10 @@ Boston, MA 02111-1307, USA. */
#define WCHAR_TYPE_SIZE BITS_PER_WORD
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-Dunix -Di386 -D__ELF__ -D__FreeBSD__=2 -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-Di386 -Dunix -D__ELF__ -D__FreeBSD__ -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)"
#undef CPP_SPEC
-#if TARGET_CPU_DEFAULT == 2
-#define CPP_SPEC "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{!m386:-D__i486__} %{posix:-D_POSIX_SOURCE}"
-#else
-#define CPP_SPEC "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{m486:-D__i486__} %{posix:-D_POSIX_SOURCE}"
-#endif
+#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}"
#undef LIB_SPEC
#if 1
@@ -196,4 +190,16 @@ Boston, MA 02111-1307, USA. */
%{static:-static}}}"
/* Get perform_* macros to build libgcc.a. */
-#include "i386/perform.h"
+
+/* A C statement to output to the stdio stream FILE an assembler
+ command to advance the location counter to a multiple of 1<<LOG
+ bytes if it is within MAX_SKIP bytes.
+
+ This is used to align code labels according to Intel recommendations. */
+
+#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \
+ if ((LOG)!=0) \
+ if ((MAX_SKIP)==0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \
+ else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP))
+#endif
diff --git a/contrib/gcc/config/i386/freebsd.h b/contrib/gcc/config/i386/freebsd.h
index c4e9991..0a556fe 100644
--- a/contrib/gcc/config/i386/freebsd.h
+++ b/contrib/gcc/config/i386/freebsd.h
@@ -1,7 +1,8 @@
-/* Definitions of target machine for GNU compiler for Intel 80386
- running FreeBSD.
- Copyright (C) 1988, 1992, 1994 Free Software Foundation, Inc.
- Contributed by Poul-Henning Kamp <phk@login.dkuug.dk>
+/* Definitions for Intel 386 running FreeBSD with ELF format
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Contributed by Eric Youngdale.
+ Modified for stabs-in-ELF by H.J. Lu.
+ Adapted from GNU/Linux version by John Polstra.
This file is part of GNU CC.
@@ -20,231 +21,185 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* This goes away when the math-emulator is fixed */
-#define TARGET_CPU_DEFAULT 0400 /* TARGET_NO_FANCY_MATH_387 */
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (i386 FreeBSD/ELF)");
-/* This is tested by i386gas.h. */
-#define YES_UNDERSCORES
-
-/* Don't assume anything about the header files. */
-#define NO_IMPLICIT_EXTERN_C
-
-#include "i386/gstabs.h"
-
-/* Get perform_* macros to build libgcc.a. */
-#include "i386/perform.h"
-
-#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-Dunix -Di386 -D__FreeBSD__ -D__386BSD__ -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)"
-
-/* Like the default, except no -lg. */
-#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}"
-
-#undef SIZE_TYPE
-#define SIZE_TYPE "unsigned int"
-
-#undef PTRDIFF_TYPE
-#define PTRDIFF_TYPE "int"
-
-#undef WCHAR_TYPE
-#define WCHAR_TYPE "short unsigned int"
-
-#define WCHAR_UNSIGNED 1
-
-#undef WCHAR_TYPE_SIZE
-#define WCHAR_TYPE_SIZE 16
-
-#define HAVE_ATEXIT
-
-/* There are conflicting reports about whether this system uses
- a different assembler syntax. wilson@cygnus.com says # is right. */
-#undef COMMENT_BEGIN
-#define COMMENT_BEGIN "#"
-
-#undef ASM_APP_ON
-#define ASM_APP_ON "#APP\n"
+/* The svr4 ABI for the i386 says that records and unions are returned
+ in memory. */
+/* On FreeBSD, we do not. */
+#undef DEFAULT_PCC_STRUCT_RETURN
+#define DEFAULT_PCC_STRUCT_RETURN 0
-#undef ASM_APP_OFF
-#define ASM_APP_OFF "#NO_APP\n"
-
-/* The following macros are stolen from i386v4.h */
-/* These have to be defined to get PIC code correct */
+/* This gets defined in tm.h->linux.h->svr4.h, and keeps us from using
+ libraries compiled with the native cc, so undef it. */
+#undef NO_DOLLAR_IN_LABEL
/* This is how to output an element of a case-vector that is relative.
This is only used for PIC code. See comments by the `casesi' insn in
i386.md for an explanation of the expression this outputs. */
-
#undef ASM_OUTPUT_ADDR_DIFF_ELT
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
/* Indicate that jump tables go in the text section. This is
necessary when compiling PIC code. */
+#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic)
+
+/* Copy this from the svr4 specifications... */
+/* Define the register numbers to be used in Dwarf debugging information.
+ The SVR4 reference port C compiler uses the following register numbers
+ in its Dwarf output code:
+ 0 for %eax (gnu regno = 0)
+ 1 for %ecx (gnu regno = 2)
+ 2 for %edx (gnu regno = 1)
+ 3 for %ebx (gnu regno = 3)
+ 4 for %esp (gnu regno = 7)
+ 5 for %ebp (gnu regno = 6)
+ 6 for %esi (gnu regno = 4)
+ 7 for %edi (gnu regno = 5)
+ The following three DWARF register numbers are never generated by
+ the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4
+ believes these numbers have these meanings.
+ 8 for %eip (no gnu equivalent)
+ 9 for %eflags (no gnu equivalent)
+ 10 for %trapno (no gnu equivalent)
+ It is not at all clear how we should number the FP stack registers
+ for the x86 architecture. If the version of SDB on x86/svr4 were
+ a bit less brain dead with respect to floating-point then we would
+ have a precedent to follow with respect to DWARF register numbers
+ for x86 FP registers, but the SDB on x86/svr4 is so completely
+ broken with respect to FP registers that it is hardly worth thinking
+ of it as something to strive for compatibility with.
+ The version of x86/svr4 SDB I have at the moment does (partially)
+ seem to believe that DWARF register number 11 is associated with
+ the x86 register %st(0), but that's about all. Higher DWARF
+ register numbers don't seem to be associated with anything in
+ particular, and even for DWARF regno 11, SDB only seems to under-
+ stand that it should say that a variable lives in %st(0) (when
+ asked via an `=' command) if we said it was in DWARF regno 11,
+ but SDB still prints garbage when asked for the value of the
+ variable in question (via a `/' command).
+ (Also note that the labels SDB prints for various FP stack regs
+ when doing an `x' command are all wrong.)
+ Note that these problems generally don't affect the native SVR4
+ C compiler because it doesn't allow the use of -O with -g and
+ because when it is *not* optimizing, it allocates a memory
+ location for each floating-point variable, and the memory
+ location is what gets described in the DWARF AT_location
+ attribute for the variable in question.
+ Regardless of the severe mental illness of the x86/svr4 SDB, we
+ do something sensible here and we use the following DWARF
+ register numbers. Note that these are all stack-top-relative
+ numbers.
+ 11 for %st(0) (gnu regno = 8)
+ 12 for %st(1) (gnu regno = 9)
+ 13 for %st(2) (gnu regno = 10)
+ 14 for %st(3) (gnu regno = 11)
+ 15 for %st(4) (gnu regno = 12)
+ 16 for %st(5) (gnu regno = 13)
+ 17 for %st(6) (gnu regno = 14)
+ 18 for %st(7) (gnu regno = 15)
+*/
+#undef DBX_REGISTER_NUMBER
+#define DBX_REGISTER_NUMBER(n) \
+((n) == 0 ? 0 \
+ : (n) == 1 ? 2 \
+ : (n) == 2 ? 1 \
+ : (n) == 3 ? 3 \
+ : (n) == 4 ? 6 \
+ : (n) == 5 ? 7 \
+ : (n) == 6 ? 5 \
+ : (n) == 7 ? 4 \
+ : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \
+ : (-1))
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry. */
-#define JUMP_TABLES_IN_TEXT_SECTION
-
-/* Don't default to pcc-struct-return, because gcc is the only compiler, and
- we want to retain compatibility with older gcc versions. */
-#define DEFAULT_PCC_STRUCT_RETURN 0
-
-/* Profiling routines, partially copied from i386/osfrose.h. */
-
-/* Redefine this to use %eax instead of %edx. */
#undef FUNCTION_PROFILER
#define FUNCTION_PROFILER(FILE, LABELNO) \
{ \
if (flag_pic) \
{ \
- fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%eax\n", \
+ fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \
LPREFIX, (LABELNO)); \
fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n"); \
} \
else \
{ \
- fprintf (FILE, "\tmovl $%sP%d,%%eax\n", LPREFIX, (LABELNO)); \
+ fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \
fprintf (FILE, "\tcall mcount\n"); \
} \
}
-/*
- * Some imports from svr4.h in support of shared libraries.
- * Currently, we need the DECLARE_OBJECT_SIZE stuff.
- */
-
-/* Define the strings used for the special svr4 .type and .size directives.
- These strings generally do not vary from one system running svr4 to
- another, but if a given system (e.g. m88k running svr) needs to use
- different pseudo-op names for these, they may be overridden in the
- file which includes this one. */
-
-#define TYPE_ASM_OP ".type"
-#define SIZE_ASM_OP ".size"
-
-/* The following macro defines the format used to output the second
- operand of the .type assembler directive. Different svr4 assemblers
- expect various different forms for this operand. The one given here
- is just a default. You may need to override it in your machine-
- specific tm.h file (depending upon the particulars of your assembler). */
-
-#define TYPE_OPERAND_FMT "@%s"
-
-/* Write the extra assembler code needed to declare a function's result.
- Most svr4 assemblers don't require any special declaration of the
- result value, but there are exceptions. */
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Di386 -Dunix -D__ELF__ -D__FreeBSD__ -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)"
-#ifndef ASM_DECLARE_RESULT
-#define ASM_DECLARE_RESULT(FILE, RESULT)
-#endif
+#undef CPP_SPEC
+#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}"
-/* These macros generate the special .type and .size directives which
- are used to set the corresponding fields of the linker symbol table
- entries in an ELF object file under SVR4. These macros also output
- the starting labels for the relevant functions/objects. */
-
-/* Write the extra assembler code needed to declare a function properly.
- Some svr4 assemblers need to also have something extra said about the
- function's return value. We allow for that here. */
-
-#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
- do { \
- fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
- assemble_name (FILE, NAME); \
- putc (',', FILE); \
- fprintf (FILE, TYPE_OPERAND_FMT, "function"); \
- putc ('\n', FILE); \
- ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
- ASM_OUTPUT_LABEL(FILE, NAME); \
- } while (0)
-
-/* Write the extra assembler code needed to declare an object properly. */
-
-#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \
- do { \
- fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
- assemble_name (FILE, NAME); \
- putc (',', FILE); \
- fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
- putc ('\n', FILE); \
- size_directive_output = 0; \
- if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \
- { \
- size_directive_output = 1; \
- fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
- assemble_name (FILE, NAME); \
- fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
- } \
- ASM_OUTPUT_LABEL(FILE, NAME); \
- } while (0)
-
-/* Output the size directive for a decl in rest_of_decl_compilation
- in the case where we did not do so before the initializer.
- Once we find the error_mark_node, we know that the value of
- size_directive_output was set
- by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */
-
-#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
-do { \
- char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
- if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
- && ! AT_END && TOP_LEVEL \
- && DECL_INITIAL (DECL) == error_mark_node \
- && !size_directive_output) \
- { \
- fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
- assemble_name (FILE, name); \
- fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL)));\
- } \
- } while (0)
-
-
-/* This is how to declare the size of a function. */
-
-#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
- do { \
- if (!flag_inhibit_size_directive) \
- { \
- char label[256]; \
- static int labelno; \
- labelno++; \
- ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \
- ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \
- fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
- assemble_name (FILE, (FNAME)); \
- fprintf (FILE, ","); \
- assemble_name (FILE, label); \
- fprintf (FILE, "-"); \
- assemble_name (FILE, (FNAME)); \
- putc ('\n', FILE); \
- } \
- } while (0)
-
-#define ASM_SPEC " %| %{fpic:-k} %{fPIC:-k}"
-#define LINK_SPEC \
- "%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{static:-Bstatic} %{assert*}"
-
-/* This is defined when gcc is compiled in the BSD-directory-tree, and must
- * make up for the gap to all the stuff done in the GNU-makefiles.
+#undef LIB_SPEC
+#if 1
+/* We no longer link with libc_p.a or libg.a by default. If you
+ * want to profile or debug the C library, please add
+ * -lc_p or -ggdb to LDFLAGS at the link time, respectively.
*/
+#define LIB_SPEC \
+ "%{!shared: %{mieee-fp:-lieee} %{p:-lgmon} %{pg:-lgmon} \
+ %{!ggdb:-lc} %{ggdb:-lg}}"
+#else
+#define LIB_SPEC \
+ "%{!shared: \
+ %{mieee-fp:-lieee} %{p:-lgmon -lc_p} %{pg:-lgmon -lc_p} \
+ %{!p:%{!pg:%{!g*:-lc} %{g*:-lg}}}}"
+#endif
-#ifdef FREEBSD_NATIVE
+/* Provide a LINK_SPEC appropriate for FreeBSD. Here we provide support
+ for the special GCC options -static and -shared, which allow us to
+ link things in one of these three modes by applying the appropriate
+ combinations of options at link-time. We like to support here for
+ as many of the other GNU linker options as possible. But I don't
+ have the time to search for those flags. I am sure how to add
+ support for -soname shared_object_name. H.J.
+
+ I took out %{v:%{!V:-V}}. It is too much :-(. They can use
+ -Wl,-V.
+
+ When the -shared link option is used a final link is not being
+ done. */
+
+#undef LINK_SPEC
+#define LINK_SPEC "-m elf_i386 %{shared:-shared} \
+ %{!shared: \
+ %{!ibcs: \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /usr/libexec/ld-elf.so.1}} \
+ %{static:-static}}}"
-#define INCLUDE_DEFAULTS { \
- { "/usr/include", 0 }, \
- { "/usr/include/g++", 1 }, \
- { 0, 0} \
- }
+/* Get perform_* macros to build libgcc.a. */
-#undef MD_EXEC_PREFIX
-#define MD_EXEC_PREFIX "/usr/libexec/"
+/* A C statement to output to the stdio stream FILE an assembler
+ command to advance the location counter to a multiple of 1<<LOG
+ bytes if it is within MAX_SKIP bytes.
-#undef STANDARD_STARTFILE_PREFIX
-#define STANDARD_STARTFILE_PREFIX "/usr/lib"
+ This is used to align code labels according to Intel recommendations. */
-#if 0 /* This is very wrong!!! */
-#define DEFAULT_TARGET_MACHINE "i386-unknown-freebsd_1.0"
-#define GPLUSPLUS_INCLUDE_DIR "/usr/local/lib/gcc-lib/i386-unknown-freebsd_1.0/2.5.8/include"
-#define TOOL_INCLUDE_DIR "/usr/local/i386-unknown-freebsd_1.0/include"
-#define GCC_INCLUDE_DIR "/usr/local/lib/gcc-lib/i386-unknown-freebsd_1.0/2.5.8/include"
+#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \
+ if ((LOG)!=0) \
+ if ((MAX_SKIP)==0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \
+ else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP))
#endif
-
-#endif /* FREEBSD_NATIVE */
diff --git a/contrib/gcc/config/i386/freebsd.h.fixed b/contrib/gcc/config/i386/freebsd.h.fixed
index c4e9991..0a556fe 100644
--- a/contrib/gcc/config/i386/freebsd.h.fixed
+++ b/contrib/gcc/config/i386/freebsd.h.fixed
@@ -1,7 +1,8 @@
-/* Definitions of target machine for GNU compiler for Intel 80386
- running FreeBSD.
- Copyright (C) 1988, 1992, 1994 Free Software Foundation, Inc.
- Contributed by Poul-Henning Kamp <phk@login.dkuug.dk>
+/* Definitions for Intel 386 running FreeBSD with ELF format
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Contributed by Eric Youngdale.
+ Modified for stabs-in-ELF by H.J. Lu.
+ Adapted from GNU/Linux version by John Polstra.
This file is part of GNU CC.
@@ -20,231 +21,185 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* This goes away when the math-emulator is fixed */
-#define TARGET_CPU_DEFAULT 0400 /* TARGET_NO_FANCY_MATH_387 */
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (i386 FreeBSD/ELF)");
-/* This is tested by i386gas.h. */
-#define YES_UNDERSCORES
-
-/* Don't assume anything about the header files. */
-#define NO_IMPLICIT_EXTERN_C
-
-#include "i386/gstabs.h"
-
-/* Get perform_* macros to build libgcc.a. */
-#include "i386/perform.h"
-
-#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-Dunix -Di386 -D__FreeBSD__ -D__386BSD__ -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)"
-
-/* Like the default, except no -lg. */
-#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}"
-
-#undef SIZE_TYPE
-#define SIZE_TYPE "unsigned int"
-
-#undef PTRDIFF_TYPE
-#define PTRDIFF_TYPE "int"
-
-#undef WCHAR_TYPE
-#define WCHAR_TYPE "short unsigned int"
-
-#define WCHAR_UNSIGNED 1
-
-#undef WCHAR_TYPE_SIZE
-#define WCHAR_TYPE_SIZE 16
-
-#define HAVE_ATEXIT
-
-/* There are conflicting reports about whether this system uses
- a different assembler syntax. wilson@cygnus.com says # is right. */
-#undef COMMENT_BEGIN
-#define COMMENT_BEGIN "#"
-
-#undef ASM_APP_ON
-#define ASM_APP_ON "#APP\n"
+/* The svr4 ABI for the i386 says that records and unions are returned
+ in memory. */
+/* On FreeBSD, we do not. */
+#undef DEFAULT_PCC_STRUCT_RETURN
+#define DEFAULT_PCC_STRUCT_RETURN 0
-#undef ASM_APP_OFF
-#define ASM_APP_OFF "#NO_APP\n"
-
-/* The following macros are stolen from i386v4.h */
-/* These have to be defined to get PIC code correct */
+/* This gets defined in tm.h->linux.h->svr4.h, and keeps us from using
+ libraries compiled with the native cc, so undef it. */
+#undef NO_DOLLAR_IN_LABEL
/* This is how to output an element of a case-vector that is relative.
This is only used for PIC code. See comments by the `casesi' insn in
i386.md for an explanation of the expression this outputs. */
-
#undef ASM_OUTPUT_ADDR_DIFF_ELT
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
/* Indicate that jump tables go in the text section. This is
necessary when compiling PIC code. */
+#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic)
+
+/* Copy this from the svr4 specifications... */
+/* Define the register numbers to be used in Dwarf debugging information.
+ The SVR4 reference port C compiler uses the following register numbers
+ in its Dwarf output code:
+ 0 for %eax (gnu regno = 0)
+ 1 for %ecx (gnu regno = 2)
+ 2 for %edx (gnu regno = 1)
+ 3 for %ebx (gnu regno = 3)
+ 4 for %esp (gnu regno = 7)
+ 5 for %ebp (gnu regno = 6)
+ 6 for %esi (gnu regno = 4)
+ 7 for %edi (gnu regno = 5)
+ The following three DWARF register numbers are never generated by
+ the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4
+ believes these numbers have these meanings.
+ 8 for %eip (no gnu equivalent)
+ 9 for %eflags (no gnu equivalent)
+ 10 for %trapno (no gnu equivalent)
+ It is not at all clear how we should number the FP stack registers
+ for the x86 architecture. If the version of SDB on x86/svr4 were
+ a bit less brain dead with respect to floating-point then we would
+ have a precedent to follow with respect to DWARF register numbers
+ for x86 FP registers, but the SDB on x86/svr4 is so completely
+ broken with respect to FP registers that it is hardly worth thinking
+ of it as something to strive for compatibility with.
+ The version of x86/svr4 SDB I have at the moment does (partially)
+ seem to believe that DWARF register number 11 is associated with
+ the x86 register %st(0), but that's about all. Higher DWARF
+ register numbers don't seem to be associated with anything in
+ particular, and even for DWARF regno 11, SDB only seems to under-
+ stand that it should say that a variable lives in %st(0) (when
+ asked via an `=' command) if we said it was in DWARF regno 11,
+ but SDB still prints garbage when asked for the value of the
+ variable in question (via a `/' command).
+ (Also note that the labels SDB prints for various FP stack regs
+ when doing an `x' command are all wrong.)
+ Note that these problems generally don't affect the native SVR4
+ C compiler because it doesn't allow the use of -O with -g and
+ because when it is *not* optimizing, it allocates a memory
+ location for each floating-point variable, and the memory
+ location is what gets described in the DWARF AT_location
+ attribute for the variable in question.
+ Regardless of the severe mental illness of the x86/svr4 SDB, we
+ do something sensible here and we use the following DWARF
+ register numbers. Note that these are all stack-top-relative
+ numbers.
+ 11 for %st(0) (gnu regno = 8)
+ 12 for %st(1) (gnu regno = 9)
+ 13 for %st(2) (gnu regno = 10)
+ 14 for %st(3) (gnu regno = 11)
+ 15 for %st(4) (gnu regno = 12)
+ 16 for %st(5) (gnu regno = 13)
+ 17 for %st(6) (gnu regno = 14)
+ 18 for %st(7) (gnu regno = 15)
+*/
+#undef DBX_REGISTER_NUMBER
+#define DBX_REGISTER_NUMBER(n) \
+((n) == 0 ? 0 \
+ : (n) == 1 ? 2 \
+ : (n) == 2 ? 1 \
+ : (n) == 3 ? 3 \
+ : (n) == 4 ? 6 \
+ : (n) == 5 ? 7 \
+ : (n) == 6 ? 5 \
+ : (n) == 7 ? 4 \
+ : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \
+ : (-1))
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry. */
-#define JUMP_TABLES_IN_TEXT_SECTION
-
-/* Don't default to pcc-struct-return, because gcc is the only compiler, and
- we want to retain compatibility with older gcc versions. */
-#define DEFAULT_PCC_STRUCT_RETURN 0
-
-/* Profiling routines, partially copied from i386/osfrose.h. */
-
-/* Redefine this to use %eax instead of %edx. */
#undef FUNCTION_PROFILER
#define FUNCTION_PROFILER(FILE, LABELNO) \
{ \
if (flag_pic) \
{ \
- fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%eax\n", \
+ fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \
LPREFIX, (LABELNO)); \
fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n"); \
} \
else \
{ \
- fprintf (FILE, "\tmovl $%sP%d,%%eax\n", LPREFIX, (LABELNO)); \
+ fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \
fprintf (FILE, "\tcall mcount\n"); \
} \
}
-/*
- * Some imports from svr4.h in support of shared libraries.
- * Currently, we need the DECLARE_OBJECT_SIZE stuff.
- */
-
-/* Define the strings used for the special svr4 .type and .size directives.
- These strings generally do not vary from one system running svr4 to
- another, but if a given system (e.g. m88k running svr) needs to use
- different pseudo-op names for these, they may be overridden in the
- file which includes this one. */
-
-#define TYPE_ASM_OP ".type"
-#define SIZE_ASM_OP ".size"
-
-/* The following macro defines the format used to output the second
- operand of the .type assembler directive. Different svr4 assemblers
- expect various different forms for this operand. The one given here
- is just a default. You may need to override it in your machine-
- specific tm.h file (depending upon the particulars of your assembler). */
-
-#define TYPE_OPERAND_FMT "@%s"
-
-/* Write the extra assembler code needed to declare a function's result.
- Most svr4 assemblers don't require any special declaration of the
- result value, but there are exceptions. */
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Di386 -Dunix -D__ELF__ -D__FreeBSD__ -Asystem(unix) -Asystem(FreeBSD) -Acpu(i386) -Amachine(i386)"
-#ifndef ASM_DECLARE_RESULT
-#define ASM_DECLARE_RESULT(FILE, RESULT)
-#endif
+#undef CPP_SPEC
+#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}"
-/* These macros generate the special .type and .size directives which
- are used to set the corresponding fields of the linker symbol table
- entries in an ELF object file under SVR4. These macros also output
- the starting labels for the relevant functions/objects. */
-
-/* Write the extra assembler code needed to declare a function properly.
- Some svr4 assemblers need to also have something extra said about the
- function's return value. We allow for that here. */
-
-#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
- do { \
- fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
- assemble_name (FILE, NAME); \
- putc (',', FILE); \
- fprintf (FILE, TYPE_OPERAND_FMT, "function"); \
- putc ('\n', FILE); \
- ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
- ASM_OUTPUT_LABEL(FILE, NAME); \
- } while (0)
-
-/* Write the extra assembler code needed to declare an object properly. */
-
-#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \
- do { \
- fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
- assemble_name (FILE, NAME); \
- putc (',', FILE); \
- fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
- putc ('\n', FILE); \
- size_directive_output = 0; \
- if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \
- { \
- size_directive_output = 1; \
- fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
- assemble_name (FILE, NAME); \
- fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
- } \
- ASM_OUTPUT_LABEL(FILE, NAME); \
- } while (0)
-
-/* Output the size directive for a decl in rest_of_decl_compilation
- in the case where we did not do so before the initializer.
- Once we find the error_mark_node, we know that the value of
- size_directive_output was set
- by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */
-
-#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
-do { \
- char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
- if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
- && ! AT_END && TOP_LEVEL \
- && DECL_INITIAL (DECL) == error_mark_node \
- && !size_directive_output) \
- { \
- fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
- assemble_name (FILE, name); \
- fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL)));\
- } \
- } while (0)
-
-
-/* This is how to declare the size of a function. */
-
-#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
- do { \
- if (!flag_inhibit_size_directive) \
- { \
- char label[256]; \
- static int labelno; \
- labelno++; \
- ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \
- ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \
- fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
- assemble_name (FILE, (FNAME)); \
- fprintf (FILE, ","); \
- assemble_name (FILE, label); \
- fprintf (FILE, "-"); \
- assemble_name (FILE, (FNAME)); \
- putc ('\n', FILE); \
- } \
- } while (0)
-
-#define ASM_SPEC " %| %{fpic:-k} %{fPIC:-k}"
-#define LINK_SPEC \
- "%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{static:-Bstatic} %{assert*}"
-
-/* This is defined when gcc is compiled in the BSD-directory-tree, and must
- * make up for the gap to all the stuff done in the GNU-makefiles.
+#undef LIB_SPEC
+#if 1
+/* We no longer link with libc_p.a or libg.a by default. If you
+ * want to profile or debug the C library, please add
+ * -lc_p or -ggdb to LDFLAGS at the link time, respectively.
*/
+#define LIB_SPEC \
+ "%{!shared: %{mieee-fp:-lieee} %{p:-lgmon} %{pg:-lgmon} \
+ %{!ggdb:-lc} %{ggdb:-lg}}"
+#else
+#define LIB_SPEC \
+ "%{!shared: \
+ %{mieee-fp:-lieee} %{p:-lgmon -lc_p} %{pg:-lgmon -lc_p} \
+ %{!p:%{!pg:%{!g*:-lc} %{g*:-lg}}}}"
+#endif
-#ifdef FREEBSD_NATIVE
+/* Provide a LINK_SPEC appropriate for FreeBSD. Here we provide support
+ for the special GCC options -static and -shared, which allow us to
+ link things in one of these three modes by applying the appropriate
+ combinations of options at link-time. We like to support here for
+ as many of the other GNU linker options as possible. But I don't
+ have the time to search for those flags. I am sure how to add
+ support for -soname shared_object_name. H.J.
+
+ I took out %{v:%{!V:-V}}. It is too much :-(. They can use
+ -Wl,-V.
+
+ When the -shared link option is used a final link is not being
+ done. */
+
+#undef LINK_SPEC
+#define LINK_SPEC "-m elf_i386 %{shared:-shared} \
+ %{!shared: \
+ %{!ibcs: \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /usr/libexec/ld-elf.so.1}} \
+ %{static:-static}}}"
-#define INCLUDE_DEFAULTS { \
- { "/usr/include", 0 }, \
- { "/usr/include/g++", 1 }, \
- { 0, 0} \
- }
+/* Get perform_* macros to build libgcc.a. */
-#undef MD_EXEC_PREFIX
-#define MD_EXEC_PREFIX "/usr/libexec/"
+/* A C statement to output to the stdio stream FILE an assembler
+ command to advance the location counter to a multiple of 1<<LOG
+ bytes if it is within MAX_SKIP bytes.
-#undef STANDARD_STARTFILE_PREFIX
-#define STANDARD_STARTFILE_PREFIX "/usr/lib"
+ This is used to align code labels according to Intel recommendations. */
-#if 0 /* This is very wrong!!! */
-#define DEFAULT_TARGET_MACHINE "i386-unknown-freebsd_1.0"
-#define GPLUSPLUS_INCLUDE_DIR "/usr/local/lib/gcc-lib/i386-unknown-freebsd_1.0/2.5.8/include"
-#define TOOL_INCLUDE_DIR "/usr/local/i386-unknown-freebsd_1.0/include"
-#define GCC_INCLUDE_DIR "/usr/local/lib/gcc-lib/i386-unknown-freebsd_1.0/2.5.8/include"
+#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \
+ if ((LOG)!=0) \
+ if ((MAX_SKIP)==0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \
+ else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP))
#endif
-
-#endif /* FREEBSD_NATIVE */
diff --git a/contrib/gcc/config/i386/gas.h b/contrib/gcc/config/i386/gas.h
index d020157..173bf19 100644
--- a/contrib/gcc/config/i386/gas.h
+++ b/contrib/gcc/config/i386/gas.h
@@ -1,5 +1,5 @@
-/* Definitions for Intel 386 running system V with gnu tools
- Copyright (C) 1988, 1993, 1994 Free Software Foundation, Inc.
+/* Definitions for Intel 386 using GAS.
+ Copyright (C) 1988, 1993, 1994, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -56,8 +56,8 @@ Boston, MA 02111-1307, USA. */
/* Specify predefined symbols in preprocessor. */
-#define CPP_PREDEFINES "-Dunix -Di386 -Asystem(unix) -Acpu(i386) -Amachine(i386)"
-#define CPP_SPEC "%{posix:-D_POSIX_SOURCE}"
+#define CPP_PREDEFINES "-Dunix"
+#define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE}"
/* Allow #sccs in preprocessor. */
@@ -71,27 +71,33 @@ Boston, MA 02111-1307, USA. */
#define TARGET_MEM_FUNCTIONS
-#if 0 /* People say gas uses the log as the arg to .align. */
-/* When using gas, .align N aligns to an N-byte boundary. */
+/* In the past there was confusion as to what the argument to .align was
+ in GAS. For the last several years the rule has been this: for a.out
+ file formats that argument is LOG, and for all other file formats the
+ argument is 1<<LOG.
+ However, GAS now has .p2align and .balign pseudo-ops so to remove any
+ doubt or guess work, and since this file is used for both a.out and other
+ file formats, we use one of them. */
+
+#ifdef HAVE_GAS_BALIGN_AND_P2ALIGN
#undef ASM_OUTPUT_ALIGN
-#define ASM_OUTPUT_ALIGN(FILE,LOG) \
- if ((LOG)!=0) fprintf ((FILE), "\t.align %d\n", 1<<(LOG))
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ if ((LOG)!=0) fprintf ((FILE), "\t.balign %d\n", 1<<(LOG))
#endif
-/* Align labels, etc. at 4-byte boundaries.
- For the 486, align to 16-byte boundary for sake of cache. */
-
-#undef ASM_OUTPUT_ALIGN_CODE
-#define ASM_OUTPUT_ALIGN_CODE(FILE) \
- fprintf ((FILE), "\t.align %d,0x90\n", i386_align_jumps)
+/* A C statement to output to the stdio stream FILE an assembler
+ command to advance the location counter to a multiple of 1<<LOG
+ bytes if it is within MAX_SKIP bytes.
-/* Align start of loop at 4-byte boundary. */
-
-#undef ASM_OUTPUT_LOOP_ALIGN
-#define ASM_OUTPUT_LOOP_ALIGN(FILE) \
- fprintf ((FILE), "\t.align %d,0x90\n", i386_align_loops)
+ This is used to align code labels according to Intel recommendations. */
+#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN
+# define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \
+ if ((LOG)!=0) \
+ if ((MAX_SKIP)==0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \
+ else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP))
+#endif
/* A C statement or statements which output an assembler instruction
opcode to the stdio stream STREAM. The macro-operand PTR is a
@@ -126,8 +132,8 @@ Boston, MA 02111-1307, USA. */
GAS requires the %cl argument, so override i386/unix.h. */
-#undef AS3_SHIFT_DOUBLE
-#define AS3_SHIFT_DOUBLE(a,b,c,d) AS3 (a,b,c,d)
+#undef SHIFT_DOUBLE_OMITS_COUNT
+#define SHIFT_DOUBLE_OMITS_COUNT 0
/* Print opcodes the way that GAS expects them. */
#define GAS_MNEMONICS 1
diff --git a/contrib/gcc/config/i386/gmon-sol2.c b/contrib/gcc/config/i386/gmon-sol2.c
new file mode 100644
index 0000000..35ac1c9
--- /dev/null
+++ b/contrib/gcc/config/i386/gmon-sol2.c
@@ -0,0 +1,409 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This is a modified gmon.c by J.W.Hawtin <oolon@ankh.org>,
+ * 14/8/96 based on the original gmon.c in GCC and the hacked version
+ * solaris 2 sparc version (config/sparc/gmon-sol.c) by Mark Eichin. To do
+ * process profiling on solaris 2.X X86
+ *
+ * It must be used in conjunction with sol2-gc1.asm, which is used to start
+ * and stop process monitoring.
+ *
+ * Differences.
+ *
+ * On Solaris 2 _mcount is called by library functions not mcount, so support
+ * has been added for both.
+ *
+ * Also the prototype for profil() is different
+ *
+ * Solaris 2 does not seem to have char *minbrk whcih allows the setting of
+ * the minimum SBRK region so this code has been removed and lets pray malloc
+ * does not mess it up.
+ *
+ * Notes
+ *
+ * This code could easily be integrated with the original gmon.c and perhaps
+ * should be.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)gmon.c 5.3 (Berkeley) 5/22/91";
+#endif /* not lint */
+
+#if 0
+#include <unistd.h>
+
+#endif
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#if 0
+#include "i386/gmon.h"
+#else
+
+struct phdr {
+ char *lpc;
+ char *hpc;
+ int ncnt;
+};
+
+
+#define HISTFRACTION 2
+#define HISTCOUNTER unsigned short
+#define HASHFRACTION 1
+#define ARCDENSITY 2
+#define MINARCS 50
+#define BASEADDRESS 0x8000000 /* On Solaris 2 X86 all executables start here
+ and not at 0 */
+
+struct tostruct {
+ char *selfpc;
+ long count;
+ unsigned short link;
+};
+struct rawarc {
+ unsigned long raw_frompc;
+ unsigned long raw_selfpc;
+ long raw_count;
+};
+#define ROUNDDOWN(x,y) (((x)/(y))*(y))
+#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y))
+#endif
+
+/* char *minbrk; */
+
+#ifdef __alpha
+extern char *sbrk ();
+#endif
+
+ /*
+ * froms is actually a bunch of unsigned shorts indexing tos
+ */
+static int profiling = 3;
+static unsigned short *froms;
+static struct tostruct *tos = 0;
+static long tolimit = 0;
+static char *s_lowpc = 0;
+static char *s_highpc = 0;
+static unsigned long s_textsize = 0;
+
+static int ssiz;
+static char *sbuf;
+static int s_scale;
+ /* see profil(2) where this is describe (incorrectly) */
+#define SCALE_1_TO_1 0x10000L
+
+#define MSG "No space for profiling buffer(s)\n"
+
+extern int errno;
+
+monstartup(lowpc, highpc)
+ char *lowpc;
+ char *highpc;
+{
+ int monsize;
+ char *buffer;
+ register int o;
+
+ /*
+ * round lowpc and highpc to multiples of the density we're using
+ * so the rest of the scaling (here and in gprof) stays in ints.
+ */
+ lowpc = (char *)
+ ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
+ s_lowpc = lowpc;
+ highpc = (char *)
+ ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
+ s_highpc = highpc;
+ s_textsize = highpc - lowpc;
+ monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
+ buffer = (char *) sbrk( monsize );
+ if ( buffer == (char *) -1 ) {
+ write( 2 , MSG , sizeof(MSG) );
+ return;
+ }
+ froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
+ if ( froms == (unsigned short *) -1 ) {
+ write( 2 , MSG , sizeof(MSG) );
+ froms = 0;
+ return;
+ }
+ tolimit = s_textsize * ARCDENSITY / 100;
+ if ( tolimit < MINARCS ) {
+ tolimit = MINARCS;
+ } else if ( tolimit > 65534 ) {
+ tolimit = 65534;
+ }
+ tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
+ if ( tos == (struct tostruct *) -1 ) {
+ write( 2 , MSG , sizeof(MSG) );
+ froms = 0;
+ tos = 0;
+ return;
+ }
+/* minbrk = (char *) sbrk(0);*/
+ tos[0].link = 0;
+ sbuf = buffer;
+ ssiz = monsize;
+ ( (struct phdr *) buffer ) -> lpc = lowpc;
+ ( (struct phdr *) buffer ) -> hpc = highpc;
+ ( (struct phdr *) buffer ) -> ncnt = ssiz;
+ monsize -= sizeof(struct phdr);
+ if ( monsize <= 0 )
+ return;
+ o = highpc - lowpc;
+ if( monsize < o )
+#ifndef hp300
+ s_scale = ( (float) monsize / o ) * SCALE_1_TO_1;
+#else /* avoid floating point */
+ {
+ int quot = o / monsize;
+
+ if (quot >= 0x10000)
+ s_scale = 1;
+ else if (quot >= 0x100)
+ s_scale = 0x10000 / quot;
+ else if (o >= 0x800000)
+ s_scale = 0x1000000 / (o / (monsize >> 8));
+ else
+ s_scale = 0x1000000 / ((o << 8) / monsize);
+ }
+#endif
+ else
+ s_scale = SCALE_1_TO_1;
+ moncontrol(1);
+}
+
+_mcleanup()
+{
+ int fd;
+ int fromindex;
+ int endfrom;
+ char *frompc;
+ int toindex;
+ struct rawarc rawarc;
+
+ moncontrol(0);
+ fd = creat( "gmon.out" , 0666 );
+ if ( fd < 0 ) {
+ perror( "mcount: gmon.out" );
+ return;
+ }
+# ifdef DEBUG
+ fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
+# endif DEBUG
+
+ write( fd , sbuf , ssiz );
+ endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
+ for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
+ if ( froms[fromindex] == 0 ) {
+ continue;
+ }
+ frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
+ for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
+# ifdef DEBUG
+ fprintf( stderr ,
+ "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
+ frompc , tos[toindex].selfpc , tos[toindex].count );
+# endif DEBUG
+ rawarc.raw_frompc = (unsigned long) frompc;
+ rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
+ rawarc.raw_count = tos[toindex].count;
+ write( fd , &rawarc , sizeof rawarc );
+ }
+ }
+ close( fd );
+}
+
+/* Solaris 2 libraries use _mcount. */
+asm(".globl _mcount; _mcount: jmp internal_mcount");
+/* This is for compatibility with old versions of gcc which used mcount. */
+asm(".globl mcount; mcount: jmp internal_mcount");
+
+internal_mcount()
+{
+ register char *selfpc;
+ register unsigned short *frompcindex;
+ register struct tostruct *top;
+ register struct tostruct *prevtop;
+ register long toindex;
+ static char already_setup;
+
+ /*
+ * find the return address for mcount,
+ * and the return address for mcount's caller.
+ */
+
+ /* selfpc = pc pushed by mcount call.
+ This identifies the function that was just entered. */
+ selfpc = (void *) __builtin_return_address (0);
+ /* frompcindex = pc in preceding frame.
+ This identifies the caller of the function just entered. */
+ frompcindex = (void *) __builtin_return_address (1);
+
+ if(!already_setup) {
+ extern etext();
+ already_setup = 1;
+/* monstartup(0, etext); */
+ monstartup(0x08040000, etext);
+#ifdef USE_ONEXIT
+ on_exit(_mcleanup, 0);
+#else
+ atexit(_mcleanup);
+#endif
+ }
+ /*
+ * check that we are profiling
+ * and that we aren't recursively invoked.
+ */
+ if (profiling) {
+ goto out;
+ }
+ profiling++;
+ /*
+ * check that frompcindex is a reasonable pc value.
+ * for example: signal catchers get called from the stack,
+ * not from text space. too bad.
+ */
+ frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
+ if ((unsigned long)frompcindex > s_textsize) {
+ goto done;
+ }
+ frompcindex =
+ &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
+ toindex = *frompcindex;
+ if (toindex == 0) {
+ /*
+ * first time traversing this arc
+ */
+ toindex = ++tos[0].link;
+ if (toindex >= tolimit) {
+ goto overflow;
+ }
+ *frompcindex = toindex;
+ top = &tos[toindex];
+ top->selfpc = selfpc;
+ top->count = 1;
+ top->link = 0;
+ goto done;
+ }
+ top = &tos[toindex];
+ if (top->selfpc == selfpc) {
+ /*
+ * arc at front of chain; usual case.
+ */
+ top->count++;
+ goto done;
+ }
+ /*
+ * have to go looking down chain for it.
+ * top points to what we are looking at,
+ * prevtop points to previous top.
+ * we know it is not at the head of the chain.
+ */
+ for (; /* goto done */; ) {
+ if (top->link == 0) {
+ /*
+ * top is end of the chain and none of the chain
+ * had top->selfpc == selfpc.
+ * so we allocate a new tostruct
+ * and link it to the head of the chain.
+ */
+ toindex = ++tos[0].link;
+ if (toindex >= tolimit) {
+ goto overflow;
+ }
+ top = &tos[toindex];
+ top->selfpc = selfpc;
+ top->count = 1;
+ top->link = *frompcindex;
+ *frompcindex = toindex;
+ goto done;
+ }
+ /*
+ * otherwise, check the next arc on the chain.
+ */
+ prevtop = top;
+ top = &tos[top->link];
+ if (top->selfpc == selfpc) {
+ /*
+ * there it is.
+ * increment its count
+ * move it to the head of the chain.
+ */
+ top->count++;
+ toindex = prevtop->link;
+ prevtop->link = top->link;
+ top->link = *frompcindex;
+ *frompcindex = toindex;
+ goto done;
+ }
+
+ }
+done:
+ profiling--;
+ /* and fall through */
+out:
+ return; /* normal return restores saved registers */
+
+overflow:
+ profiling++; /* halt further profiling */
+# define TOLIMIT "mcount: tos overflow\n"
+ write(2, TOLIMIT, sizeof(TOLIMIT));
+ goto out;
+}
+
+/*
+ * Control profiling
+ * profiling is what mcount checks to see if
+ * all the data structures are ready.
+ */
+moncontrol(mode)
+ int mode;
+{
+ if (mode)
+ {
+ /* start */
+ profil((unsigned short *)(sbuf + sizeof(struct phdr)),
+ ssiz - sizeof(struct phdr),
+ (int)s_lowpc, s_scale);
+
+ profiling = 0;
+ } else {
+ /* stop */
+ profil((unsigned short *)0, 0, 0, 0);
+ profiling = 3;
+ }
+}
diff --git a/contrib/gcc/config/i386/gnu.h b/contrib/gcc/config/i386/gnu.h
index 1ad5df9..971a5f8 100644
--- a/contrib/gcc/config/i386/gnu.h
+++ b/contrib/gcc/config/i386/gnu.h
@@ -4,16 +4,19 @@
#include <i386/linux.h>
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES GNU_CPP_PREDEFINES("i386")
+#define CPP_PREDEFINES "-Di386 -Acpu(i386) -Amachine(i386) \
+-Dunix -Asystem(unix) -DMACH -Asystem(mach) -D__GNU__ -Asystem(gnu)"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (i386 GNU)");
#undef LINK_SPEC
#define LINK_SPEC "-m elf_i386 %{shared:-shared} \
%{!shared: \
- %{!ibcs: \
- %{!static: \
- %{rdynamic:-export-dynamic} \
- %{!dynamic-linker:-dynamic-linker /lib/ld.so} \
- %{!rpath:-rpath /lib/}} %{static:-static}}}"
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /lib/ld.so}} \
+ %{static:-static}}"
/* Get machine-independent configuration parameters for the GNU system. */
diff --git a/contrib/gcc/config/i386/go32.h b/contrib/gcc/config/i386/go32.h
index 5618a0d..dd03cc8 100644
--- a/contrib/gcc/config/i386/go32.h
+++ b/contrib/gcc/config/i386/go32.h
@@ -1,5 +1,7 @@
/* Configuration for an i386 running MS-DOS with djgpp/go32. */
+#include "dbxcoff.h"
+
/* Don't assume anything about the header files. */
#define NO_IMPLICIT_EXTERN_C
@@ -53,7 +55,13 @@ dtor_section () \
fprintf (FILE, "\n"); \
} while (0)
-#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
+/* Allow (eg) __attribute__((section "locked")) to work */
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC)\
+ do { \
+ fprintf (FILE, "\t.section %s\n", NAME); \
+ } while (0)
+
+#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
do { \
dtor_section (); \
fprintf (FILE, "%s\t", ASM_LONG); \
@@ -61,4 +69,28 @@ dtor_section () \
fprintf (FILE, "\n"); \
} while (0)
+/* Output at beginning of assembler file. */
+/* The .file command should always begin the output. */
+/* Use the main_input_filename instead of dump_base_name */
+
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+ do { \
+ output_file_directive (FILE, main_input_filename); \
+ } while (0)
+
+/* This is how to output an assembler line
+ that says to advance the location counter
+ to a multiple of 2**LOG bytes. */
+
+#undef ASM_OUTPUT_ALIGN
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ if ((LOG) != 0) fprintf ((FILE), "\t.p2align %d\n", LOG)
+
+/* djgpp has atexit (). */
+#undef HAVE_ATEXIT
+#define HAVE_ATEXIT
+/* djgpp automatically calls its own version of __main, so don't define one
+ in libgcc, nor call one in main(). */
+#define HAS_INIT_SECTION
diff --git a/contrib/gcc/config/i386/i386.c b/contrib/gcc/config/i386/i386.c
index 48c58a0..b2512a0 100644
--- a/contrib/gcc/config/i386/i386.c
+++ b/contrib/gcc/config/i386/i386.c
@@ -1,5 +1,5 @@
/* Subroutines for insn-output.c for Intel X86.
- Copyright (C) 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1988, 92, 94-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -16,12 +16,11 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include <setjmp.h>
-#include <ctype.h>
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
@@ -33,7 +32,11 @@ Boston, MA 02111-1307, USA. */
#include "insn-attr.h"
#include "tree.h"
#include "flags.h"
+#include "except.h"
#include "function.h"
+#include "recog.h"
+#include "expr.h"
+#include "toplev.h"
#ifdef EXTRA_CONSTRAINT
/* If EXTRA_CONSTRAINT is defined, then the 'S'
@@ -44,11 +47,69 @@ Boston, MA 02111-1307, USA. */
even if the conditional was untrue. */
#endif
-#define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
+#ifndef CHECK_STACK_LIMIT
+#define CHECK_STACK_LIMIT -1
+#endif
+
+/* Type of an operand for ix86_{binary,unary}_operator_ok */
+enum reg_mem
+{
+ reg_p,
+ mem_p,
+ imm_p
+};
+
+/* Processor costs (relative to an add) */
+struct processor_costs i386_cost = { /* 386 specific costs */
+ 1, /* cost of an add instruction */
+ 1, /* cost of a lea instruction */
+ 3, /* variable shift costs */
+ 2, /* constant shift costs */
+ 6, /* cost of starting a multiply */
+ 1, /* cost of multiply per each bit set */
+ 23 /* cost of a divide/mod */
+};
+
+struct processor_costs i486_cost = { /* 486 specific costs */
+ 1, /* cost of an add instruction */
+ 1, /* cost of a lea instruction */
+ 3, /* variable shift costs */
+ 2, /* constant shift costs */
+ 12, /* cost of starting a multiply */
+ 1, /* cost of multiply per each bit set */
+ 40 /* cost of a divide/mod */
+};
+
+struct processor_costs pentium_cost = {
+ 1, /* cost of an add instruction */
+ 1, /* cost of a lea instruction */
+ 4, /* variable shift costs */
+ 1, /* constant shift costs */
+ 11, /* cost of starting a multiply */
+ 0, /* cost of multiply per each bit set */
+ 25 /* cost of a divide/mod */
+};
+
+struct processor_costs pentiumpro_cost = {
+ 1, /* cost of an add instruction */
+ 1, /* cost of a lea instruction */
+ 3, /* variable shift costs */
+ 1, /* constant shift costs */
+ 4, /* cost of starting a multiply */
+ 0, /* cost of multiply per each bit set */
+ 17 /* cost of a divide/mod */
+};
+
+struct processor_costs *ix86_cost = &pentium_cost;
+
+#define AT_BP(mode) (gen_rtx_MEM ((mode), frame_pointer_rtx))
extern FILE *asm_out_file;
extern char *strcat ();
+static void ix86_epilogue PROTO((int));
+static void ix86_prologue PROTO((int));
+
char *singlemove_string ();
char *output_move_const_single ();
char *output_fp_cc0_set ();
@@ -68,7 +129,7 @@ enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
SIREG, DIREG, INDEX_REGS, GENERAL_REGS,
/* FP registers */
FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
- FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
+ FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
/* arg pointer */
INDEX_REGS
};
@@ -80,24 +141,48 @@ struct rtx_def *i386_compare_op0 = NULL_RTX;
struct rtx_def *i386_compare_op1 = NULL_RTX;
struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
+/* which cpu are we scheduling for */
+enum processor_type ix86_cpu;
+
+/* which instruction set architecture to use. */
+int ix86_arch;
+
+/* Strings to hold which cpu and instruction set architecture to use. */
+char *ix86_cpu_string; /* for -mcpu=<xxx> */
+char *ix86_arch_string; /* for -march=<xxx> */
+
/* Register allocation order */
char *i386_reg_alloc_order;
static char regs_allocated[FIRST_PSEUDO_REGISTER];
/* # of registers to use to pass arguments. */
-char *i386_regparm_string; /* # registers to use to pass args */
-int i386_regparm; /* i386_regparm_string as a number */
+char *i386_regparm_string;
-/* Alignment to use for loops and jumps */
-char *i386_align_loops_string; /* power of two alignment for loops */
-char *i386_align_jumps_string; /* power of two alignment for non-loop jumps */
-char *i386_align_funcs_string; /* power of two alignment for functions */
+/* i386_regparm_string as a number */
+int i386_regparm;
-int i386_align_loops; /* power of two alignment for loops */
-int i386_align_jumps; /* power of two alignment for non-loop jumps */
-int i386_align_funcs; /* power of two alignment for functions */
+/* Alignment to use for loops and jumps: */
+
+/* Power of two alignment for loops. */
+char *i386_align_loops_string;
+
+/* Power of two alignment for non-loop jumps. */
+char *i386_align_jumps_string;
+
+/* Values 1-5: see jump.c */
+int i386_branch_cost;
+char *i386_branch_cost_string;
+
+/* Power of two alignment for functions. */
+int i386_align_funcs;
+char *i386_align_funcs_string;
+
+/* Power of two alignment for loops. */
+int i386_align_loops;
+
+/* Power of two alignment for non-loop jumps. */
+int i386_align_jumps;
-
/* Sometimes certain combinations of command options do not make
sense on a particular target machine. You can define a macro
`OVERRIDE_OPTIONS' to take account of this. This macro, if
@@ -110,19 +195,39 @@ int i386_align_funcs; /* power of two alignment for functions */
void
override_options ()
{
- int ch, i, regno;
- char *p;
+ int ch, i, j;
int def_align;
+ static struct ptt
+ {
+ char *name; /* Canonical processor name. */
+ enum processor_type processor; /* Processor type enum value. */
+ struct processor_costs *cost; /* Processor costs */
+ int target_enable; /* Target flags to enable. */
+ int target_disable; /* Target flags to disable. */
+ } processor_target_table[]
+ = {{PROCESSOR_I386_STRING, PROCESSOR_I386, &i386_cost, 0, 0},
+ {PROCESSOR_I486_STRING, PROCESSOR_I486, &i486_cost, 0, 0},
+ {PROCESSOR_I586_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},
+ {PROCESSOR_PENTIUM_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},
+ {PROCESSOR_I686_STRING, PROCESSOR_PENTIUMPRO, &pentiumpro_cost,
+ 0, 0},
+ {PROCESSOR_PENTIUMPRO_STRING, PROCESSOR_PENTIUMPRO,
+ &pentiumpro_cost, 0, 0}};
+
+ int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);
+
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
#endif
- /* Validate registers in register allocation order */
+ /* Validate registers in register allocation order. */
if (i386_reg_alloc_order)
{
for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
{
+ int regno = 0;
+
switch (ch)
{
case 'a': regno = 0; break;
@@ -137,23 +242,75 @@ override_options ()
}
if (regs_allocated[regno])
- fatal ("Register '%c' was already specified in the allocation order", ch);
+ fatal ("Register '%c' already specified in allocation order", ch);
regs_allocated[regno] = 1;
}
}
- /* Validate -mregparm= value */
+ if (ix86_arch_string == 0)
+ {
+ ix86_arch_string = PROCESSOR_PENTIUM_STRING;
+ if (ix86_cpu_string == 0)
+ ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
+ }
+
+ for (i = 0; i < ptt_size; i++)
+ if (! strcmp (ix86_arch_string, processor_target_table[i].name))
+ {
+ ix86_arch = processor_target_table[i].processor;
+ if (ix86_cpu_string == 0)
+ ix86_cpu_string = processor_target_table[i].name;
+ break;
+ }
+
+ if (i == ptt_size)
+ {
+ error ("bad value (%s) for -march= switch", ix86_arch_string);
+ ix86_arch_string = PROCESSOR_PENTIUM_STRING;
+ ix86_arch = PROCESSOR_DEFAULT;
+ }
+
+ if (ix86_cpu_string == 0)
+ ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
+
+ for (j = 0; j < ptt_size; j++)
+ if (! strcmp (ix86_cpu_string, processor_target_table[j].name))
+ {
+ ix86_cpu = processor_target_table[j].processor;
+ ix86_cost = processor_target_table[j].cost;
+ if (i > j && (int) ix86_arch >= (int) PROCESSOR_PENTIUMPRO)
+ error ("-mcpu=%s does not support -march=%s",
+ ix86_cpu_string, ix86_arch_string);
+
+ target_flags |= processor_target_table[j].target_enable;
+ target_flags &= ~processor_target_table[j].target_disable;
+ break;
+ }
+
+ if (j == ptt_size)
+ {
+ error ("bad value (%s) for -mcpu= switch", ix86_cpu_string);
+ ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
+ ix86_cpu = PROCESSOR_DEFAULT;
+ }
+
+ /* Validate -mregparm= value. */
if (i386_regparm_string)
{
i386_regparm = atoi (i386_regparm_string);
if (i386_regparm < 0 || i386_regparm > REGPARM_MAX)
- fatal ("-mregparm=%d is not between 0 and %d", i386_regparm, REGPARM_MAX);
+ fatal ("-mregparm=%d is not between 0 and %d",
+ i386_regparm, REGPARM_MAX);
}
- def_align = (TARGET_386) ? 2 : 4;
+ /* The 486 suffers more from non-aligned cache line fills, and the
+ larger code size results in a larger cache foot-print and more misses.
+ The 486 has a 16 byte cache line, pentium and pentiumpro have a 32 byte
+ cache line. */
+ def_align = (TARGET_486) ? 4 : 2;
- /* Validate -malign-loops= value, or provide default */
+ /* Validate -malign-loops= value, or provide default. */
if (i386_align_loops_string)
{
i386_align_loops = atoi (i386_align_loops_string);
@@ -162,9 +319,13 @@ override_options ()
i386_align_loops, MAX_CODE_ALIGN);
}
else
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
+ i386_align_loops = 4;
+#else
i386_align_loops = 2;
+#endif
- /* Validate -malign-jumps= value, or provide default */
+ /* Validate -malign-jumps= value, or provide default. */
if (i386_align_jumps_string)
{
i386_align_jumps = atoi (i386_align_jumps_string);
@@ -173,9 +334,13 @@ override_options ()
i386_align_jumps, MAX_CODE_ALIGN);
}
else
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
+ i386_align_jumps = 4;
+#else
i386_align_jumps = def_align;
+#endif
- /* Validate -malign-functions= value, or provide default */
+ /* Validate -malign-functions= value, or provide default. */
if (i386_align_funcs_string)
{
i386_align_funcs = atoi (i386_align_funcs_string);
@@ -185,6 +350,21 @@ override_options ()
}
else
i386_align_funcs = def_align;
+
+ /* Validate -mbranch-cost= value, or provide default. */
+ if (i386_branch_cost_string)
+ {
+ i386_branch_cost = atoi (i386_branch_cost_string);
+ if (i386_branch_cost < 0 || i386_branch_cost > 5)
+ fatal ("-mbranch-cost=%d is not between 0 and 5",
+ i386_branch_cost);
+ }
+ else
+ i386_branch_cost = 1;
+
+ /* Keep nonleaf frame pointers. */
+ if (TARGET_OMIT_LEAF_FRAME_POINTER)
+ flag_omit_frame_pointer = 1;
}
/* A C statement (sans semicolon) to choose the order in which to
@@ -203,13 +383,16 @@ override_options ()
void
order_regs_for_local_alloc ()
{
- int i, ch, order, regno;
+ int i, ch, order;
+
+ /* User specified the register allocation order. */
- /* User specified the register allocation order */
if (i386_reg_alloc_order)
{
for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
{
+ int regno = 0;
+
switch (ch)
{
case 'a': regno = 0; break;
@@ -226,59 +409,116 @@ order_regs_for_local_alloc ()
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
- if (!regs_allocated[i])
+ if (! regs_allocated[i])
reg_alloc_order[order++] = i;
}
}
- /* If users did not specify a register allocation order, favor eax
- normally except if DImode variables are used, in which case
- favor edx before eax, which seems to cause less spill register
- not found messages. */
+ /* If user did not specify a register allocation order, use natural order. */
else
{
- rtx insn;
-
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
reg_alloc_order[i] = i;
+ }
+}
+
+void
+optimization_options (level, size)
+ int level;
+ int size ATTRIBUTE_UNUSED;
+{
+ /* For -O2 and beyond, turn off -fschedule-insns by default. It tends to
+ make the problem with not enough registers even worse. */
+#ifdef INSN_SCHEDULING
+ if (level > 1)
+ flag_schedule_insns = 0;
+#endif
+}
+
+/* Sign-extend a 16-bit constant */
- if (optimize)
- {
- int use_dca = FALSE;
+struct rtx_def *
+i386_sext16_if_const (op)
+ struct rtx_def *op;
+{
+ if (GET_CODE (op) == CONST_INT)
+ {
+ HOST_WIDE_INT val = INTVAL (op);
+ HOST_WIDE_INT sext_val;
+ if (val & 0x8000)
+ sext_val = val | ~0xffff;
+ else
+ sext_val = val & 0xffff;
+ if (sext_val != val)
+ op = GEN_INT (sext_val);
+ }
+ return op;
+}
+
+/* Return nonzero if the rtx is aligned */
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == INSN)
- {
- rtx set = NULL_RTX;
- rtx pattern = PATTERN (insn);
-
- if (GET_CODE (pattern) == SET)
- set = pattern;
-
- else if ((GET_CODE (pattern) == PARALLEL
- || GET_CODE (pattern) == SEQUENCE)
- && GET_CODE (XVECEXP (pattern, 0, 0)) == SET)
- set = XVECEXP (pattern, 0, 0);
-
- if (set && GET_MODE (SET_SRC (set)) == DImode)
- {
- use_dca = TRUE;
- break;
- }
- }
- }
+static int
+i386_aligned_reg_p (regno)
+ int regno;
+{
+ return (regno == STACK_POINTER_REGNUM
+ || (! flag_omit_frame_pointer && regno == FRAME_POINTER_REGNUM));
+}
- if (use_dca)
- {
- reg_alloc_order[0] = 1; /* edx */
- reg_alloc_order[1] = 2; /* ecx */
- reg_alloc_order[2] = 0; /* eax */
- }
- }
+int
+i386_aligned_p (op)
+ rtx op;
+{
+ /* Registers and immediate operands are always "aligned". */
+ if (GET_CODE (op) != MEM)
+ return 1;
+
+ /* Don't even try to do any aligned optimizations with volatiles. */
+ if (MEM_VOLATILE_P (op))
+ return 0;
+
+ /* Get address of memory operand. */
+ op = XEXP (op, 0);
+
+ switch (GET_CODE (op))
+ {
+ case CONST_INT:
+ if (INTVAL (op) & 3)
+ break;
+ return 1;
+
+ /* Match "reg + offset" */
+ case PLUS:
+ if (GET_CODE (XEXP (op, 1)) != CONST_INT)
+ break;
+ if (INTVAL (XEXP (op, 1)) & 3)
+ break;
+
+ op = XEXP (op, 0);
+ if (GET_CODE (op) != REG)
+ break;
+
+ /* ... fall through ... */
+
+ case REG:
+ return i386_aligned_reg_p (REGNO (op));
+
+ default:
+ break;
}
+
+ return 0;
}
+
+/* Return nonzero if INSN looks like it won't compute useful cc bits
+ as a side effect. This information is only a hint. */
+int
+i386_cc_probably_useless_p (insn)
+ rtx insn;
+{
+ return ! next_cc0_user (insn);
+}
/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
attribute for DECL. The attributes in ATTRIBUTES have previously been
@@ -286,10 +526,10 @@ order_regs_for_local_alloc ()
int
i386_valid_decl_attribute_p (decl, attributes, identifier, args)
- tree decl;
- tree attributes;
- tree identifier;
- tree args;
+ tree decl ATTRIBUTE_UNUSED;
+ tree attributes ATTRIBUTE_UNUSED;
+ tree identifier ATTRIBUTE_UNUSED;
+ tree args ATTRIBUTE_UNUSED;
{
return 0;
}
@@ -301,11 +541,12 @@ i386_valid_decl_attribute_p (decl, attributes, identifier, args)
int
i386_valid_type_attribute_p (type, attributes, identifier, args)
tree type;
- tree attributes;
+ tree attributes ATTRIBUTE_UNUSED;
tree identifier;
tree args;
{
if (TREE_CODE (type) != FUNCTION_TYPE
+ && TREE_CODE (type) != METHOD_TYPE
&& TREE_CODE (type) != FIELD_DECL
&& TREE_CODE (type) != TYPE_DECL)
return 0;
@@ -315,17 +556,17 @@ i386_valid_type_attribute_p (type, attributes, identifier, args)
if (is_attribute_p ("stdcall", identifier))
return (args == NULL_TREE);
- /* Cdecl attribute says the callee is a normal C declaration */
+ /* Cdecl attribute says the callee is a normal C declaration. */
if (is_attribute_p ("cdecl", identifier))
return (args == NULL_TREE);
/* Regparm attribute specifies how many integer arguments are to be
- passed in registers */
+ passed in registers. */
if (is_attribute_p ("regparm", identifier))
{
tree cst;
- if (!args || TREE_CODE (args) != TREE_LIST
+ if (! args || TREE_CODE (args) != TREE_LIST
|| TREE_CHAIN (args) != NULL_TREE
|| TREE_VALUE (args) == NULL_TREE)
return 0;
@@ -351,8 +592,8 @@ i386_valid_type_attribute_p (type, attributes, identifier, args)
int
i386_comp_type_attributes (type1, type2)
- tree type1;
- tree type2;
+ tree type1 ATTRIBUTE_UNUSED;
+ tree type2 ATTRIBUTE_UNUSED;
{
return 1;
}
@@ -381,30 +622,27 @@ i386_return_pops_args (fundecl, funtype, size)
tree funtype;
int size;
{
- int rtd = TARGET_RTD;
-
- if (TREE_CODE (funtype) == IDENTIFIER_NODE)
- return 0;
+ int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE);
- /* Cdecl functions override -mrtd, and never pop the stack */
- if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
- return 0;
+ /* Cdecl functions override -mrtd, and never pop the stack. */
+ if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) {
- /* Stdcall functions will pop the stack if not variable args */
- if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
- rtd = 1;
+ /* Stdcall functions will pop the stack if not variable args. */
+ if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
+ rtd = 1;
- if (rtd)
- {
- if (TYPE_ARG_TYPES (funtype) == NULL_TREE
- || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
- return size;
+ if (rtd
+ && (TYPE_ARG_TYPES (funtype) == NULL_TREE
+ || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype)))
+ == void_type_node)))
+ return size;
+ }
- if (aggregate_value_p (TREE_TYPE (funtype)))
- return GET_MODE_SIZE (Pmode);
- }
+ /* Lose any fake structure return argument. */
+ if (aggregate_value_p (TREE_TYPE (funtype)))
+ return GET_MODE_SIZE (Pmode);
- return 0;
+ return 0;
}
@@ -416,7 +654,7 @@ i386_return_pops_args (fundecl, funtype, size)
void
init_cumulative_args (cum, fntype, libname)
- CUMULATIVE_ARGS *cum; /* argument info to initialize */
+ CUMULATIVE_ARGS *cum; /* Argument info to initialize */
tree fntype; /* tree ptr for function decl */
rtx libname; /* SYMBOL_REF of library name or 0 */
{
@@ -427,12 +665,9 @@ init_cumulative_args (cum, fntype, libname)
{
fprintf (stderr, "\ninit_cumulative_args (");
if (fntype)
- {
- tree ret_type = TREE_TYPE (fntype);
- fprintf (stderr, "fntype code = %s, ret code = %s",
- tree_code_name[ (int)TREE_CODE (fntype) ],
- tree_code_name[ (int)TREE_CODE (ret_type) ]);
- }
+ fprintf (stderr, "fntype code = %s, ret code = %s",
+ tree_code_name[(int) TREE_CODE (fntype)],
+ tree_code_name[(int) TREE_CODE (TREE_TYPE (fntype))]);
else
fprintf (stderr, "no fntype");
@@ -447,6 +682,7 @@ init_cumulative_args (cum, fntype, libname)
if (fntype)
{
tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype));
+
if (attr)
cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
}
@@ -459,11 +695,10 @@ init_cumulative_args (cum, fntype, libname)
if (cum->nregs)
{
for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
- param != (tree)0;
- param = next_param)
+ param != 0; param = next_param)
{
next_param = TREE_CHAIN (param);
- if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node)
+ if (next_param == 0 && TREE_VALUE (param) != void_type_node)
cum->nregs = 0;
}
}
@@ -485,12 +720,13 @@ function_arg_advance (cum, mode, type, named)
tree type; /* type of the argument or 0 if lib support */
int named; /* whether or not the argument was named */
{
- int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
+ int bytes
+ = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
if (TARGET_DEBUG_ARG)
fprintf (stderr,
- "function_adv( size=%d, words=%2d, nregs=%d, mode=%4s, named=%d )\n\n",
+ "function_adv (sz=%d, wds=%2d, nregs=%d, mode=%s, named=%d)\n\n",
words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
cum->words += words;
@@ -527,12 +763,14 @@ function_arg (cum, mode, type, named)
int named; /* != 0 for normal args, == 0 for ... args */
{
rtx ret = NULL_RTX;
- int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
+ int bytes
+ = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
switch (mode)
{
- default: /* for now, pass fp/complex values on the stack */
+ /* For now, pass fp/complex values on the stack. */
+ default:
break;
case BLKmode:
@@ -541,14 +779,14 @@ function_arg (cum, mode, type, named)
case HImode:
case QImode:
if (words <= cum->nregs)
- ret = gen_rtx (REG, mode, cum->regno);
+ ret = gen_rtx_REG (mode, cum->regno);
break;
}
if (TARGET_DEBUG_ARG)
{
fprintf (stderr,
- "function_arg( size=%d, words=%2d, nregs=%d, mode=%4s, named=%d",
+ "function_arg (size=%d, wds=%2d, nregs=%d, mode=%4s, named=%d",
words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
if (ret)
@@ -568,14 +806,13 @@ function_arg (cum, mode, type, named)
int
function_arg_partial_nregs (cum, mode, type, named)
- CUMULATIVE_ARGS *cum; /* current arg information */
- enum machine_mode mode; /* current arg mode */
- tree type; /* type of the argument or 0 if lib support */
- int named; /* != 0 for normal args, == 0 for ... args */
+ CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED; /* current arg information */
+ enum machine_mode mode ATTRIBUTE_UNUSED; /* current arg mode */
+ tree type ATTRIBUTE_UNUSED; /* type of the argument or 0 if lib support */
+ int named ATTRIBUTE_UNUSED; /* != 0 for normal args, == 0 for ... args */
{
return 0;
}
-
/* Output an insn whose source is a 386 integer register. SRC is the
rtx for the register, and TEMPLATE is the op-code template. SRC may
@@ -609,18 +846,19 @@ output_op_from_reg (src, template)
if (size > UNITS_PER_WORD)
{
rtx high;
+
if (size > 2 * UNITS_PER_WORD)
{
- high = gen_rtx (REG, SImode, REGNO (src) + 2);
+ high = gen_rtx_REG (SImode, REGNO (src) + 2);
output_asm_insn (AS1 (push%L0,%0), &high);
}
- high = gen_rtx (REG, SImode, REGNO (src) + 1);
+
+ high = gen_rtx_REG (SImode, REGNO (src) + 1);
output_asm_insn (AS1 (push%L0,%0), &high);
}
- output_asm_insn (AS1 (push%L0,%0), &src);
+ output_asm_insn (AS1 (push%L0,%0), &src);
output_asm_insn (template, xops);
-
output_asm_insn (AS2 (add%L3,%2,%3), xops);
}
@@ -630,27 +868,45 @@ output_op_from_reg (src, template)
otherwise a `fst' float store is done. */
void
-output_to_reg (dest, dies)
+output_to_reg (dest, dies, scratch_mem)
rtx dest;
int dies;
+ rtx scratch_mem;
{
rtx xops[4];
int size = GET_MODE_SIZE (GET_MODE (dest));
- xops[0] = AT_SP (Pmode);
+ if (! scratch_mem)
+ xops[0] = AT_SP (Pmode);
+ else
+ xops[0] = scratch_mem;
+
xops[1] = stack_pointer_rtx;
xops[2] = GEN_INT (size);
xops[3] = dest;
- output_asm_insn (AS2 (sub%L1,%2,%1), xops);
+ if (! scratch_mem)
+ output_asm_insn (AS2 (sub%L1,%2,%1), xops);
if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT)
{
if (dies)
output_asm_insn (AS1 (fistp%z3,%y0), xops);
+ else if (GET_MODE (xops[3]) == DImode && ! dies)
+ {
+ /* There is no DImode version of this without a stack pop, so
+ we must emulate it. It doesn't matter much what the second
+ instruction is, because the value being pushed on the FP stack
+ is not used except for the following stack popping store.
+ This case can only happen without optimization, so it doesn't
+ matter that it is inefficient. */
+ output_asm_insn (AS1 (fistp%z3,%0), xops);
+ output_asm_insn (AS1 (fild%z3,%0), xops);
+ }
else
output_asm_insn (AS1 (fist%z3,%y0), xops);
}
+
else if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_FLOAT)
{
if (dies)
@@ -666,19 +922,38 @@ output_to_reg (dest, dies)
output_asm_insn (AS1 (fst%z3,%y0), xops);
}
}
+
else
abort ();
- output_asm_insn (AS1 (pop%L0,%0), &dest);
+ if (! scratch_mem)
+ output_asm_insn (AS1 (pop%L0,%0), &dest);
+ else
+ output_asm_insn (AS2 (mov%L0,%0,%3), xops);
+
if (size > UNITS_PER_WORD)
{
- dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
- output_asm_insn (AS1 (pop%L0,%0), &dest);
+ dest = gen_rtx_REG (SImode, REGNO (dest) + 1);
+ if (! scratch_mem)
+ output_asm_insn (AS1 (pop%L0,%0), &dest);
+ else
+ {
+ xops[0] = adj_offsettable_operand (xops[0], 4);
+ xops[3] = dest;
+ output_asm_insn (AS2 (mov%L0,%0,%3), xops);
+ }
+
if (size > 2 * UNITS_PER_WORD)
{
- dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
- output_asm_insn (AS1 (pop%L0,%0), &dest);
+ dest = gen_rtx_REG (SImode, REGNO (dest) + 1);
+ if (! scratch_mem)
+ output_asm_insn (AS1 (pop%L0,%0), &dest);
+ else
+ {
+ xops[0] = adj_offsettable_operand (xops[0], 4);
+ output_asm_insn (AS2 (mov%L0,%0,%3), xops);
+ }
}
}
}
@@ -696,9 +971,7 @@ singlemove_string (operands)
return "push%L1 %1";
}
else if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- return output_move_const_single (operands);
- }
+ return output_move_const_single (operands);
else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
return AS2 (mov%L0,%1,%0);
else if (CONSTANT_P (operands[1]))
@@ -730,11 +1003,11 @@ find_addr_reg (addr)
else
abort ();
}
+
if (GET_CODE (addr) == REG)
return addr;
abort ();
}
-
/* Output an insn to add the constant N to the register X. */
@@ -750,7 +1023,7 @@ asm_add (n, x)
output_asm_insn (AS1 (dec%L0,%0), xops);
else if (n == 1)
output_asm_insn (AS1 (inc%L0,%0), xops);
- else if (n < 0)
+ else if (n < 0 || n == 128)
{
xops[1] = GEN_INT (-n);
output_asm_insn (AS2 (sub%L0,%1,%0), xops);
@@ -761,7 +1034,6 @@ asm_add (n, x)
output_asm_insn (AS2 (add%L0,%1,%0), xops);
}
}
-
/* Output assembler code to perform a doubleword move insn
with operands OPERANDS. */
@@ -828,11 +1100,11 @@ output_move_double (operands)
operands[0] = XEXP (XEXP (operands[0], 0), 0);
asm_add (-size, operands[0]);
if (GET_MODE (operands[1]) == XFmode)
- operands[0] = gen_rtx (MEM, XFmode, operands[0]);
+ operands[0] = gen_rtx_MEM (XFmode, operands[0]);
else if (GET_MODE (operands[0]) == DFmode)
- operands[0] = gen_rtx (MEM, DFmode, operands[0]);
+ operands[0] = gen_rtx_MEM (DFmode, operands[0]);
else
- operands[0] = gen_rtx (MEM, DImode, operands[0]);
+ operands[0] = gen_rtx_MEM (DImode, operands[0]);
optype0 = OFFSOP;
}
@@ -842,11 +1114,11 @@ output_move_double (operands)
operands[1] = XEXP (XEXP (operands[1], 0), 0);
asm_add (-size, operands[1]);
if (GET_MODE (operands[1]) == XFmode)
- operands[1] = gen_rtx (MEM, XFmode, operands[1]);
+ operands[1] = gen_rtx_MEM (XFmode, operands[1]);
else if (GET_MODE (operands[1]) == DFmode)
- operands[1] = gen_rtx (MEM, DFmode, operands[1]);
+ operands[1] = gen_rtx_MEM (DFmode, operands[1]);
else
- operands[1] = gen_rtx (MEM, DImode, operands[1]);
+ operands[1] = gen_rtx_MEM (DImode, operands[1]);
optype1 = OFFSOP;
}
@@ -872,8 +1144,8 @@ output_move_double (operands)
{
if (optype0 == REGOP)
{
- middlehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
- latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
+ middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
+ latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
}
else if (optype0 == OFFSOP)
{
@@ -885,11 +1157,11 @@ output_move_double (operands)
middlehalf[0] = operands[0];
latehalf[0] = operands[0];
}
-
+
if (optype1 == REGOP)
{
- middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
- latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
+ middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
+ latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
}
else if (optype1 == OFFSOP)
{
@@ -918,17 +1190,20 @@ output_move_double (operands)
latehalf[1] = operands[1];
}
}
- else /* size is not 12: */
+
+ else
{
+ /* Size is not 12. */
+
if (optype0 == REGOP)
- latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
+ latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
else if (optype0 == OFFSOP)
latehalf[0] = adj_offsettable_operand (operands[0], 4);
else
latehalf[0] = operands[0];
if (optype1 == REGOP)
- latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
+ latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
else if (optype1 == OFFSOP)
latehalf[1] = adj_offsettable_operand (operands[1], 4);
else if (optype1 == CNSTOP)
@@ -960,34 +1235,34 @@ output_move_double (operands)
{
/* If both halves of dest are used in the src memory address,
compute the address into latehalf of dest. */
-compadr:
+ compadr:
xops[0] = latehalf[0];
xops[1] = XEXP (operands[1], 0);
output_asm_insn (AS2 (lea%L0,%a1,%0), xops);
- if( GET_MODE (operands[1]) == XFmode )
+ if (GET_MODE (operands[1]) == XFmode)
{
-/* abort (); */
- operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);
+ operands[1] = gen_rtx_MEM (XFmode, latehalf[0]);
middlehalf[1] = adj_offsettable_operand (operands[1], size-8);
latehalf[1] = adj_offsettable_operand (operands[1], size-4);
}
else
{
- operands[1] = gen_rtx (MEM, DImode, latehalf[0]);
+ operands[1] = gen_rtx_MEM (DImode, latehalf[0]);
latehalf[1] = adj_offsettable_operand (operands[1], size-4);
}
}
+
else if (size == 12
&& reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0)))
{
/* Check for two regs used by both source and dest. */
if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
|| reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
- goto compadr;
+ goto compadr;
/* JRV says this can't happen: */
if (addreg0 || addreg1)
- abort();
+ abort ();
/* Only the middle reg conflicts; simply put it last. */
output_asm_insn (singlemove_string (operands), operands);
@@ -995,6 +1270,7 @@ compadr:
output_asm_insn (singlemove_string (middlehalf), middlehalf);
return "";
}
+
else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
/* If the low half of dest is mentioned in the source memory
address, the arrange to emit the move late half first. */
@@ -1009,12 +1285,13 @@ compadr:
such overlap can't happen in memory unless the user explicitly
sets it up, and that is an undefined circumstance. */
-/*
+#if 0
if (optype0 == PUSHOP || optype1 == PUSHOP
|| (optype0 == REGOP && optype1 == REGOP
&& REGNO (operands[0]) == REGNO (latehalf[1]))
|| dest_overlapped_low)
-*/
+#endif
+
if (optype0 == PUSHOP || optype1 == PUSHOP
|| (optype0 == REGOP && optype1 == REGOP
&& ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))
@@ -1032,17 +1309,17 @@ compadr:
/* Undo the adds we just did. */
if (addreg0)
- asm_add (-4, addreg0);
+ asm_add (-4, addreg0);
if (addreg1)
asm_add (-4, addreg1);
if (size == 12)
{
- output_asm_insn (singlemove_string (middlehalf), middlehalf);
- if (addreg0)
- asm_add (-4, addreg0);
- if (addreg1)
- asm_add (-4, addreg1);
+ output_asm_insn (singlemove_string (middlehalf), middlehalf);
+ if (addreg0)
+ asm_add (-4, addreg0);
+ if (addreg1)
+ asm_add (-4, addreg1);
}
/* Do low-numbered word. */
@@ -1081,7 +1358,6 @@ compadr:
return "";
}
-
#define MAX_TMPS 2 /* max temporary registers used */
@@ -1095,12 +1371,12 @@ output_move_pushmem (operands, insn, length, tmp_start, n_operands)
int tmp_start;
int n_operands;
{
-
- struct {
- char *load;
- char *push;
- rtx xops[2];
- } tmp_info[MAX_TMPS];
+ struct
+ {
+ char *load;
+ char *push;
+ rtx xops[2];
+ } tmp_info[MAX_TMPS];
rtx src = operands[1];
int max_tmps = 0;
@@ -1110,7 +1386,7 @@ output_move_pushmem (operands, insn, length, tmp_start, n_operands)
int i, num_tmps;
rtx xops[1];
- if (!offsettable_memref_p (src))
+ if (! offsettable_memref_p (src))
fatal_insn ("Source is not offsettable", insn);
if ((length & 3) != 0)
@@ -1146,7 +1422,8 @@ output_move_pushmem (operands, insn, length, tmp_start, n_operands)
{
tmp_info[num_tmps].load = AS2(mov%L0,%0,%1);
tmp_info[num_tmps].push = AS1(push%L0,%1);
- tmp_info[num_tmps].xops[0] = adj_offsettable_operand (src, offset + stack_offset);
+ tmp_info[num_tmps].xops[0]
+ = adj_offsettable_operand (src, offset + stack_offset);
offset -= 4;
}
@@ -1162,9 +1439,7 @@ output_move_pushmem (operands, insn, length, tmp_start, n_operands)
return "";
}
-
-
/* Output the appropriate code to move data between two memory locations */
char *
@@ -1175,11 +1450,12 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
int tmp_start;
int n_operands;
{
- struct {
- char *load;
- char *store;
- rtx xops[3];
- } tmp_info[MAX_TMPS];
+ struct
+ {
+ char *load;
+ char *store;
+ rtx xops[3];
+ } tmp_info[MAX_TMPS];
rtx dest = operands[0];
rtx src = operands[1];
@@ -1194,10 +1470,10 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
&& XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
return output_move_pushmem (operands, insn, length, tmp_start, n_operands);
- if (!offsettable_memref_p (src))
+ if (! offsettable_memref_p (src))
fatal_insn ("Source is not offsettable", insn);
- if (!offsettable_memref_p (dest))
+ if (! offsettable_memref_p (dest))
fatal_insn ("Destination is not offsettable", insn);
/* Figure out which temporary registers we have available */
@@ -1205,7 +1481,7 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
{
if (GET_CODE (operands[i]) == REG)
{
- if ((length & 1) != 0 && !qi_tmp && QI_REG_P (operands[i]))
+ if ((length & 1) != 0 && qi_tmp == 0 && QI_REG_P (operands[i]))
qi_tmp = operands[i];
if (reg_overlap_mentioned_p (operands[i], dest))
@@ -1214,19 +1490,21 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
if (reg_overlap_mentioned_p (operands[i], src))
fatal_insn ("Temporary register overlaps the source", insn);
- tmp_info[ max_tmps++ ].xops[2] = operands[i];
+ tmp_info[max_tmps++].xops[2] = operands[i];
if (max_tmps == MAX_TMPS)
break;
}
}
if (max_tmps == 0)
- fatal_insn ("No scratch registers were found to do memory->memory moves", insn);
+ fatal_insn ("No scratch registers were found to do memory->memory moves",
+ insn);
if ((length & 1) != 0)
{
- if (!qi_tmp)
- fatal_insn ("No byte register found when moving odd # of bytes.", insn);
+ if (qi_tmp == 0)
+ fatal_insn ("No byte register found when moving odd # of bytes.",
+ insn);
}
while (length > 1)
@@ -1237,17 +1515,24 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
{
tmp_info[num_tmps].load = AS2(mov%L0,%1,%2);
tmp_info[num_tmps].store = AS2(mov%L0,%2,%0);
- tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
- tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
+ tmp_info[num_tmps].xops[0]
+ = adj_offsettable_operand (dest, offset);
+ tmp_info[num_tmps].xops[1]
+ = adj_offsettable_operand (src, offset);
+
offset += 4;
length -= 4;
}
+
else if (length >= 2)
{
tmp_info[num_tmps].load = AS2(mov%W0,%1,%2);
tmp_info[num_tmps].store = AS2(mov%W0,%2,%0);
- tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
- tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
+ tmp_info[num_tmps].xops[0]
+ = adj_offsettable_operand (dest, offset);
+ tmp_info[num_tmps].xops[1]
+ = adj_offsettable_operand (src, offset);
+
offset += 2;
length -= 2;
}
@@ -1273,7 +1558,6 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
return "";
}
-
int
standard_80387_constant_p (x)
@@ -1289,7 +1573,7 @@ standard_80387_constant_p (x)
set_float_handler (handler);
REAL_VALUE_FROM_CONST_DOUBLE (d, x);
- is0 = REAL_VALUES_EQUAL (d, dconst0);
+ is0 = REAL_VALUES_EQUAL (d, dconst0) && !REAL_VALUE_MINUS_ZERO (d);
is1 = REAL_VALUES_EQUAL (d, dconst1);
set_float_handler (NULL_PTR);
@@ -1321,6 +1605,7 @@ output_move_const_single (operands)
if (conval == 2)
return "fld1";
}
+
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r; long l;
@@ -1332,6 +1617,7 @@ output_move_const_single (operands)
REAL_VALUE_TO_TARGET_SINGLE (r, l);
operands[1] = GEN_INT (l);
}
+
return singlemove_string (operands);
}
@@ -1341,18 +1627,20 @@ output_move_const_single (operands)
int
symbolic_operand (op, mode)
register rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
return 1;
+
case CONST:
op = XEXP (op, 0);
return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
+
default:
return 0;
}
@@ -1366,7 +1654,7 @@ symbolic_operand (op, mode)
int
call_insn_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == MEM
&& ((CONSTANT_ADDRESS_P (XEXP (op, 0))
@@ -1374,9 +1662,10 @@ call_insn_operand (op, mode)
&& general_operand (XEXP (op, 0), Pmode))
|| (GET_CODE (XEXP (op, 0)) == REG
&& XEXP (op, 0) != arg_pointer_rtx
- && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
- && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
+ && ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
+ && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
return 1;
+
return 0;
}
@@ -1386,15 +1675,16 @@ call_insn_operand (op, mode)
int
expander_call_insn_operand (op, mode)
rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == MEM
&& (CONSTANT_ADDRESS_P (XEXP (op, 0))
|| (GET_CODE (XEXP (op, 0)) == REG
&& XEXP (op, 0) != arg_pointer_rtx
- && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
- && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
+ && ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
+ && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
return 1;
+
return 0;
}
@@ -1410,12 +1700,22 @@ arithmetic_comparison_operator (op, mode)
if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
+
code = GET_CODE (op);
if (GET_RTX_CLASS (code) != '<')
return 0;
return (code != GT && code != LE);
}
+
+int
+ix86_logical_operator (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
+}
+
/* Returns 1 if OP contains a symbol reference */
@@ -1440,6 +1740,7 @@ symbolic_reference_mentioned_p (op)
if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
return 1;
}
+
else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
return 1;
}
@@ -1447,32 +1748,390 @@ symbolic_reference_mentioned_p (op)
return 0;
}
-/* This function generates the assembly code for function entry.
+/* Attempt to expand a binary operator. Make the expansion closer to the
+ actual machine, then just general_operand, which will allow 3 separate
+ memory references (one output, two input) in a single insn. Return
+ whether the insn fails, or succeeds. */
+
+int
+ix86_expand_binary_operator (code, mode, operands)
+ enum rtx_code code;
+ enum machine_mode mode;
+ rtx operands[];
+{
+ int modified;
+
+ /* Recognize <var1> = <value> <op> <var1> for commutative operators */
+ if (GET_RTX_CLASS (code) == 'c'
+ && (rtx_equal_p (operands[0], operands[2])
+ || immediate_operand (operands[1], mode)))
+ {
+ rtx temp = operands[1];
+ operands[1] = operands[2];
+ operands[2] = temp;
+ }
+
+ /* If optimizing, copy to regs to improve CSE */
+ if (TARGET_PSEUDO && optimize
+ && ((reload_in_progress | reload_completed) == 0))
+ {
+ if (GET_CODE (operands[1]) == MEM
+ && ! rtx_equal_p (operands[0], operands[1]))
+ operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+
+ if (GET_CODE (operands[2]) == MEM)
+ operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
+
+ if (GET_CODE (operands[1]) == CONST_INT && code == MINUS)
+ {
+ rtx temp = gen_reg_rtx (GET_MODE (operands[0]));
+
+ emit_move_insn (temp, operands[1]);
+ operands[1] = temp;
+ return TRUE;
+ }
+ }
+
+ if (!ix86_binary_operator_ok (code, mode, operands))
+ {
+ /* If not optimizing, try to make a valid insn (optimize code
+ previously did this above to improve chances of CSE) */
+
+ if ((! TARGET_PSEUDO || !optimize)
+ && ((reload_in_progress | reload_completed) == 0)
+ && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM))
+ {
+ modified = FALSE;
+ if (GET_CODE (operands[1]) == MEM
+ && ! rtx_equal_p (operands[0], operands[1]))
+ {
+ operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+ modified = TRUE;
+ }
+
+ if (GET_CODE (operands[2]) == MEM)
+ {
+ operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
+ modified = TRUE;
+ }
+
+ if (GET_CODE (operands[1]) == CONST_INT && code == MINUS)
+ {
+ rtx temp = gen_reg_rtx (GET_MODE (operands[0]));
+
+ emit_move_insn (temp, operands[1]);
+ operands[1] = temp;
+ return TRUE;
+ }
+
+ if (modified && ! ix86_binary_operator_ok (code, mode, operands))
+ return FALSE;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Return TRUE or FALSE depending on whether the binary operator meets the
+ appropriate constraints. */
+
+int
+ix86_binary_operator_ok (code, mode, operands)
+ enum rtx_code code;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ rtx operands[3];
+{
+ return (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)
+ && (GET_CODE (operands[1]) != CONST_INT || GET_RTX_CLASS (code) == 'c');
+}
+
+/* Attempt to expand a unary operator. Make the expansion closer to the
+ actual machine, then just general_operand, which will allow 2 separate
+ memory references (one output, one input) in a single insn. Return
+ whether the insn fails, or succeeds. */
+
+int
+ix86_expand_unary_operator (code, mode, operands)
+ enum rtx_code code;
+ enum machine_mode mode;
+ rtx operands[];
+{
+ /* If optimizing, copy to regs to improve CSE */
+ if (TARGET_PSEUDO
+ && optimize
+ && ((reload_in_progress | reload_completed) == 0)
+ && GET_CODE (operands[1]) == MEM)
+ operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+
+ if (! ix86_unary_operator_ok (code, mode, operands))
+ {
+ if ((! TARGET_PSEUDO || optimize == 0)
+ && ((reload_in_progress | reload_completed) == 0)
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+ if (! ix86_unary_operator_ok (code, mode, operands))
+ return FALSE;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Return TRUE or FALSE depending on whether the unary operator meets the
+ appropriate constraints. */
+
+int
+ix86_unary_operator_ok (code, mode, operands)
+ enum rtx_code code ATTRIBUTE_UNUSED;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ rtx operands[2] ATTRIBUTE_UNUSED;
+{
+ return TRUE;
+}
+
+static rtx pic_label_rtx;
+static char pic_label_name [256];
+static int pic_label_no = 0;
+
+/* This function generates code for -fpic that loads %ebx with
+ the return address of the caller and then returns. */
+
+void
+asm_output_function_prefix (file, name)
+ FILE *file;
+ char *name ATTRIBUTE_UNUSED;
+{
+ rtx xops[2];
+ int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+ || current_function_uses_const_pool);
+ xops[0] = pic_offset_table_rtx;
+ xops[1] = stack_pointer_rtx;
+
+ /* Deep branch prediction favors having a return for every call. */
+ if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION)
+ {
+ tree prologue_node;
+
+ if (pic_label_rtx == 0)
+ {
+ pic_label_rtx = gen_label_rtx ();
+ ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++);
+ LABEL_NAME (pic_label_rtx) = pic_label_name;
+ }
+
+ prologue_node = make_node (FUNCTION_DECL);
+ DECL_RESULT (prologue_node) = 0;
+
+ /* This used to call ASM_DECLARE_FUNCTION_NAME() but since it's an
+ internal (non-global) label that's being emitted, it didn't make
+ sense to have .type information for local labels. This caused
+ the SCO OpenServer 5.0.4 ELF assembler grief (why are you giving
+ me debug info for a label that you're declaring non-global?) this
+ was changed to call ASM_OUTPUT_LABEL() instead. */
+
+
+ ASM_OUTPUT_LABEL (file, pic_label_name);
+ output_asm_insn ("movl (%1),%0", xops);
+ output_asm_insn ("ret", xops);
+ }
+}
+
+/* Generate the assembly code for function entry.
FILE is an stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to allocate. */
void
function_prologue (file, size)
- FILE *file;
- int size;
+ FILE *file ATTRIBUTE_UNUSED;
+ int size ATTRIBUTE_UNUSED;
+{
+ if (TARGET_SCHEDULE_PROLOGUE)
+ {
+ pic_label_rtx = 0;
+ return;
+ }
+
+ ix86_prologue (0);
+}
+
+/* Expand the prologue into a bunch of separate insns. */
+
+void
+ix86_expand_prologue ()
+{
+ if (! TARGET_SCHEDULE_PROLOGUE)
+ return;
+
+ ix86_prologue (1);
+}
+
+void
+load_pic_register (do_rtl)
+ int do_rtl;
+{
+ rtx xops[4];
+
+ if (TARGET_DEEP_BRANCH_PREDICTION)
+ {
+ xops[0] = pic_offset_table_rtx;
+ if (pic_label_rtx == 0)
+ {
+ pic_label_rtx = gen_label_rtx ();
+ ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++);
+ LABEL_NAME (pic_label_rtx) = pic_label_name;
+ }
+
+ xops[1] = gen_rtx_MEM (QImode,
+ gen_rtx (SYMBOL_REF, Pmode,
+ LABEL_NAME (pic_label_rtx)));
+
+ if (do_rtl)
+ {
+ emit_insn (gen_prologue_get_pc (xops[0], xops[1]));
+ emit_insn (gen_prologue_set_got (xops[0],
+ gen_rtx (SYMBOL_REF, Pmode,
+ "$_GLOBAL_OFFSET_TABLE_"),
+ xops[1]));
+ }
+ else
+ {
+ output_asm_insn (AS1 (call,%X1), xops);
+ output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_,%0", xops);
+ pic_label_rtx = 0;
+ }
+ }
+
+ else
+ {
+ xops[0] = pic_offset_table_rtx;
+ xops[1] = gen_label_rtx ();
+
+ if (do_rtl)
+ {
+ /* We can't put a raw CODE_LABEL into the RTL, and we can't emit
+ a new CODE_LABEL after reload, so we need a single pattern to
+ emit the 3 necessary instructions. */
+ emit_insn (gen_prologue_get_pc_and_set_got (xops[0]));
+ }
+ else
+ {
+ output_asm_insn (AS1 (call,%P1), xops);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (xops[1]));
+ output_asm_insn (AS1 (pop%L0,%0), xops);
+ output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);
+ }
+ }
+
+ /* When -fpic, we must emit a scheduling barrier, so that the instruction
+ that restores %ebx (which is PIC_OFFSET_TABLE_REGNUM), does not get
+ moved before any instruction which implicitly uses the got. */
+
+ if (do_rtl)
+ emit_insn (gen_blockage ());
+}
+
+static void
+ix86_prologue (do_rtl)
+ int do_rtl;
{
register int regno;
int limit;
rtx xops[4];
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|| current_function_uses_const_pool);
+ long tsize = get_frame_size ();
+ rtx insn;
+ int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset;
xops[0] = stack_pointer_rtx;
xops[1] = frame_pointer_rtx;
- xops[2] = GEN_INT (size);
+ xops[2] = GEN_INT (tsize);
+
if (frame_pointer_needed)
{
- output_asm_insn ("push%L1 %1", xops);
- output_asm_insn (AS2 (mov%L0,%0,%1), xops);
+ if (do_rtl)
+ {
+ insn = emit_insn (gen_rtx (SET, VOIDmode,
+ gen_rtx_MEM (SImode,
+ gen_rtx (PRE_DEC, SImode,
+ stack_pointer_rtx)),
+ frame_pointer_rtx));
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+ insn = emit_move_insn (xops[1], xops[0]);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ else
+ {
+ output_asm_insn ("push%L1 %1", xops);
+#ifdef INCOMING_RETURN_ADDR_RTX
+ if (dwarf2out_do_frame ())
+ {
+ char *l = dwarf2out_cfi_label ();
+
+ cfa_store_offset += 4;
+ cfa_offset = cfa_store_offset;
+ dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
+ dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, - cfa_store_offset);
+ }
+#endif
+
+ output_asm_insn (AS2 (mov%L0,%0,%1), xops);
+#ifdef INCOMING_RETURN_ADDR_RTX
+ if (dwarf2out_do_frame ())
+ dwarf2out_def_cfa ("", FRAME_POINTER_REGNUM, cfa_offset);
+#endif
+ }
+ }
+
+ if (tsize == 0)
+ ;
+ else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
+ {
+ if (do_rtl)
+ {
+ insn = emit_insn (gen_prologue_set_stack_ptr (xops[2]));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else
+ {
+ output_asm_insn (AS2 (sub%L0,%2,%0), xops);
+#ifdef INCOMING_RETURN_ADDR_RTX
+ if (dwarf2out_do_frame ())
+ {
+ cfa_store_offset += tsize;
+ if (! frame_pointer_needed)
+ {
+ cfa_offset = cfa_store_offset;
+ dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset);
+ }
+ }
+#endif
+ }
}
+ else
+ {
+ xops[3] = gen_rtx_REG (SImode, 0);
+ if (do_rtl)
+ emit_move_insn (xops[3], xops[2]);
+ else
+ output_asm_insn (AS2 (mov%L0,%2,%3), xops);
- if (size)
- output_asm_insn (AS2 (sub%L0,%2,%0), xops);
+ xops[3] = gen_rtx_MEM (FUNCTION_MODE,
+ gen_rtx (SYMBOL_REF, Pmode, "_alloca"));
+
+ if (do_rtl)
+ emit_call_insn (gen_rtx (CALL, VOIDmode, xops[3], const0_rtx));
+ else
+ output_asm_insn (AS1 (call,%P3), xops);
+ }
/* Note If use enter it is NOT reversed args.
This one is not reversed from intel!!
@@ -1483,39 +2142,69 @@ function_prologue (file, size)
output_asm_insn ("enter %2,%3", xops);
}
*/
+
limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
for (regno = limit - 1; regno >= 0; regno--)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
{
- xops[0] = gen_rtx (REG, SImode, regno);
- output_asm_insn ("push%L0 %0", xops);
+ xops[0] = gen_rtx_REG (SImode, regno);
+ if (do_rtl)
+ {
+ insn = emit_insn (gen_rtx (SET, VOIDmode,
+ gen_rtx_MEM (SImode,
+ gen_rtx (PRE_DEC, SImode,
+ stack_pointer_rtx)),
+ xops[0]));
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else
+ {
+ output_asm_insn ("push%L0 %0", xops);
+#ifdef INCOMING_RETURN_ADDR_RTX
+ if (dwarf2out_do_frame ())
+ {
+ char *l = dwarf2out_cfi_label ();
+
+ cfa_store_offset += 4;
+ if (! frame_pointer_needed)
+ {
+ cfa_offset = cfa_store_offset;
+ dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
+ }
+
+ dwarf2out_reg_save (l, regno, - cfa_store_offset);
+ }
+#endif
+ }
}
if (pic_reg_used)
- {
- xops[0] = pic_offset_table_rtx;
- xops[1] = (rtx) gen_label_rtx ();
-
- output_asm_insn (AS1 (call,%P1), xops);
- ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (xops[1]));
- output_asm_insn (AS1 (pop%L0,%0), xops);
- output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);
- }
+ load_pic_register (do_rtl);
+
+ /* If we are profiling, make sure no instructions are scheduled before
+ the call to mcount. However, if -fpic, the above call will have
+ done that. */
+ if ((profile_flag || profile_block_flag)
+ && ! pic_reg_used && do_rtl)
+ emit_insn (gen_blockage ());
}
/* Return 1 if it is appropriate to emit `ret' instructions in the
body of a function. Do this only if the epilogue is simple, needing a
couple of insns. Prior to reloading, we can't tell how many registers
- must be saved, so return 0 then.
+ must be saved, so return 0 then. Return 0 if there is no frame
+ marker to de-allocate.
If NON_SAVING_SETJMP is defined and true, then it is not possible
for the epilogue to be simple, so return 0. This is a special case
- since NON_SAVING_SETJMP will not cause regs_ever_live to change until
- final, but jump_optimize may need to know sooner if a `return' is OK. */
+ since NON_SAVING_SETJMP will not cause regs_ever_live to change
+ until final, but jump_optimize may need to know sooner if a
+ `return' is OK. */
int
-simple_386_epilogue ()
+ix86_can_use_return_insn_p ()
{
int regno;
int nregs = 0;
@@ -1540,15 +2229,29 @@ simple_386_epilogue ()
return nregs == 0 || ! frame_pointer_needed;
}
-
/* This function generates the assembly code for function exit.
FILE is an stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to deallocate. */
void
function_epilogue (file, size)
- FILE *file;
- int size;
+ FILE *file ATTRIBUTE_UNUSED;
+ int size ATTRIBUTE_UNUSED;
+{
+ return;
+}
+
+/* Restore function stack, frame, and registers. */
+
+void
+ix86_expand_epilogue ()
+{
+ ix86_epilogue (1);
+}
+
+static void
+ix86_epilogue (do_rtl)
+ int do_rtl;
{
register int regno;
register int nregs, limit;
@@ -1556,12 +2259,11 @@ function_epilogue (file, size)
rtx xops[3];
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|| current_function_uses_const_pool);
+ long tsize = get_frame_size ();
/* Compute the number of registers to pop */
- limit = (frame_pointer_needed
- ? FRAME_POINTER_REGNUM
- : STACK_POINTER_REGNUM);
+ limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
nregs = 0;
@@ -1570,67 +2272,159 @@ function_epilogue (file, size)
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
nregs++;
- /* sp is often unreliable so we must go off the frame pointer,
- */
+ /* sp is often unreliable so we must go off the frame pointer.
- /* In reality, we may not care if sp is unreliable, because we can
- restore the register relative to the frame pointer. In theory,
- since each move is the same speed as a pop, and we don't need the
- leal, this is faster. For now restore multiple registers the old
- way. */
+ In reality, we may not care if sp is unreliable, because we can restore
+ the register relative to the frame pointer. In theory, since each move
+ is the same speed as a pop, and we don't need the leal, this is faster.
+ For now restore multiple registers the old way. */
- offset = -size - (nregs * UNITS_PER_WORD);
+ offset = - tsize - (nregs * UNITS_PER_WORD);
xops[2] = stack_pointer_rtx;
+ /* When -fpic, we must emit a scheduling barrier, so that the instruction
+ that restores %ebx (which is PIC_OFFSET_TABLE_REGNUM), does not get
+ moved before any instruction which implicitly uses the got. This
+ includes any instruction which uses a SYMBOL_REF or a LABEL_REF.
+
+ Alternatively, this could be fixed by making the dependence on the
+ PIC_OFFSET_TABLE_REGNUM explicit in the RTL. */
+
+ if (flag_pic || profile_flag || profile_block_flag)
+ emit_insn (gen_blockage ());
+
if (nregs > 1 || ! frame_pointer_needed)
{
if (frame_pointer_needed)
{
- xops[0] = adj_offsettable_operand (AT_BP (Pmode), offset);
- output_asm_insn (AS2 (lea%L2,%0,%2), xops);
+ xops[0] = adj_offsettable_operand (AT_BP (QImode), offset);
+ if (do_rtl)
+ emit_insn (gen_movsi_lea (xops[2], XEXP (xops[0], 0)));
+ else
+ output_asm_insn (AS2 (lea%L2,%0,%2), xops);
}
for (regno = 0; regno < limit; regno++)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
{
- xops[0] = gen_rtx (REG, SImode, regno);
- output_asm_insn ("pop%L0 %0", xops);
+ xops[0] = gen_rtx_REG (SImode, regno);
+
+ if (do_rtl)
+ emit_insn (gen_pop (xops[0]));
+ else
+ output_asm_insn ("pop%L0 %0", xops);
}
}
+
else
for (regno = 0; regno < limit; regno++)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
{
- xops[0] = gen_rtx (REG, SImode, regno);
+ xops[0] = gen_rtx_REG (SImode, regno);
xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset);
- output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
+ if (do_rtl)
+ emit_move_insn (xops[0], xops[1]);
+ else
+ output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
offset += 4;
}
if (frame_pointer_needed)
{
- /* On i486, mov & pop is faster than "leave". */
+ /* If not an i386, mov & pop is faster than "leave". */
- if (!TARGET_386)
+ if (TARGET_USE_LEAVE)
{
- xops[0] = frame_pointer_rtx;
- output_asm_insn (AS2 (mov%L2,%0,%2), xops);
- output_asm_insn ("pop%L0 %0", xops);
+ if (do_rtl)
+ emit_insn (gen_leave());
+ else
+ output_asm_insn ("leave", xops);
}
else
- output_asm_insn ("leave", xops);
+ {
+ xops[0] = frame_pointer_rtx;
+ xops[1] = stack_pointer_rtx;
+
+ if (do_rtl)
+ {
+ emit_insn (gen_epilogue_set_stack_ptr());
+ emit_insn (gen_pop (xops[0]));
+ }
+ else
+ {
+ output_asm_insn (AS2 (mov%L2,%0,%2), xops);
+ output_asm_insn ("pop%L0 %0", xops);
+ }
+ }
}
- else if (size)
+
+ else if (tsize)
{
- /* If there is no frame pointer, we must still release the frame. */
+ /* Intel's docs say that for 4 or 8 bytes of stack frame one should
+ use `pop' and not `add'. */
+ int use_pop = tsize == 4;
+
+ /* Use two pops only for the Pentium processors. */
+ if (tsize == 8 && !TARGET_386 && !TARGET_486)
+ {
+ rtx retval = current_function_return_rtx;
+
+ xops[1] = gen_rtx_REG (SImode, 1); /* %edx */
- xops[0] = GEN_INT (size);
- output_asm_insn (AS2 (add%L2,%0,%2), xops);
+ /* This case is a bit more complex. Since we cannot pop into
+ %ecx twice we need a second register. But this is only
+ available if the return value is not of DImode in which
+ case the %edx register is not available. */
+ use_pop = (retval == NULL
+ || ! reg_overlap_mentioned_p (xops[1], retval));
+ }
+
+ if (use_pop)
+ {
+ xops[0] = gen_rtx_REG (SImode, 2); /* %ecx */
+
+ if (do_rtl)
+ {
+ /* We have to prevent the two pops here from being scheduled.
+ GCC otherwise would try in some situation to put other
+ instructions in between them which has a bad effect. */
+ emit_insn (gen_blockage ());
+ emit_insn (gen_pop (xops[0]));
+ if (tsize == 8)
+ emit_insn (gen_pop (xops[1]));
+ }
+ else
+ {
+ output_asm_insn ("pop%L0 %0", xops);
+ if (tsize == 8)
+ output_asm_insn ("pop%L1 %1", xops);
+ }
+ }
+ else
+ {
+ /* If there is no frame pointer, we must still release the frame. */
+ xops[0] = GEN_INT (tsize);
+
+ if (do_rtl)
+ emit_insn (gen_rtx (SET, VOIDmode, xops[2],
+ gen_rtx (PLUS, SImode, xops[2], xops[0])));
+ else
+ output_asm_insn (AS2 (add%L2,%0,%2), xops);
+ }
}
+#ifdef FUNCTION_BLOCK_PROFILER_EXIT
+ if (profile_block_flag == 2)
+ {
+ FUNCTION_BLOCK_PROFILER_EXIT(file);
+ }
+#endif
+
if (current_function_pops_args && current_function_args_size)
{
xops[1] = GEN_INT (current_function_pops_args);
@@ -1642,18 +2436,38 @@ function_epilogue (file, size)
if (current_function_pops_args >= 32768)
{
/* ??? Which register to use here? */
- xops[0] = gen_rtx (REG, SImode, 2);
- output_asm_insn ("pop%L0 %0", xops);
- output_asm_insn (AS2 (add%L2,%1,%2), xops);
- output_asm_insn ("jmp %*%0", xops);
+ xops[0] = gen_rtx_REG (SImode, 2);
+
+ if (do_rtl)
+ {
+ emit_insn (gen_pop (xops[0]));
+ emit_insn (gen_rtx (SET, VOIDmode, xops[2],
+ gen_rtx (PLUS, SImode, xops[1], xops[2])));
+ emit_jump_insn (xops[0]);
+ }
+ else
+ {
+ output_asm_insn ("pop%L0 %0", xops);
+ output_asm_insn (AS2 (add%L2,%1,%2), xops);
+ output_asm_insn ("jmp %*%0", xops);
+ }
}
else
- output_asm_insn ("ret %1", xops);
+ {
+ if (do_rtl)
+ emit_jump_insn (gen_return_pop_internal (xops[1]));
+ else
+ output_asm_insn ("ret %1", xops);
+ }
}
else
- output_asm_insn ("ret", xops);
+ {
+ if (do_rtl)
+ emit_jump_insn (gen_return_internal ());
+ else
+ output_asm_insn ("ret", xops);
+ }
}
-
/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
that is a valid memory address for an instruction.
@@ -1703,14 +2517,14 @@ legitimate_address_p (mode, addr, strict)
if (TARGET_DEBUG_ADDR)
{
fprintf (stderr,
- "\n==========\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
+ "\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
GET_MODE_NAME (mode), strict);
debug_rtx (addr);
}
if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)
- base = addr; /* base reg */
+ base = addr;
else if (GET_CODE (addr) == PLUS)
{
@@ -1723,13 +2537,13 @@ legitimate_address_p (mode, addr, strict)
{
if (code1 == REG || code1 == SUBREG)
{
- indx = op0; /* index + base */
+ indx = op0; /* index + base */
base = op1;
}
else
{
- base = op0; /* base + displacement */
+ base = op0; /* base + displacement */
disp = op1;
}
}
@@ -1740,10 +2554,10 @@ legitimate_address_p (mode, addr, strict)
scale = XEXP (op0, 1);
if (code1 == REG || code1 == SUBREG)
- base = op1; /* index*scale + base */
+ base = op1; /* index*scale + base */
else
- disp = op1; /* index*scale + disp */
+ disp = op1; /* index*scale + disp */
}
else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
@@ -1756,7 +2570,7 @@ legitimate_address_p (mode, addr, strict)
else if (code0 == PLUS)
{
- indx = XEXP (op0, 0); /* index + base + disp */
+ indx = XEXP (op0, 0); /* index + base + disp */
base = XEXP (op0, 1);
disp = op1;
}
@@ -1770,12 +2584,12 @@ legitimate_address_p (mode, addr, strict)
else if (GET_CODE (addr) == MULT)
{
- indx = XEXP (addr, 0); /* index*scale */
+ indx = XEXP (addr, 0); /* index*scale */
scale = XEXP (addr, 1);
}
else
- disp = addr; /* displacement */
+ disp = addr; /* displacement */
/* Allow arg pointer and stack pointer as index if there is not scaling */
if (base && indx && !scale
@@ -1786,10 +2600,12 @@ legitimate_address_p (mode, addr, strict)
indx = tmp;
}
- /* Validate base register */
- /* Don't allow SUBREG's here, it can lead to spill failures when the base
+ /* Validate base register:
+
+ Don't allow SUBREG's here, it can lead to spill failures when the base
is one word out of a two word structure, which is represented internally
as a DImode int. */
+
if (base)
{
if (GET_CODE (base) != REG)
@@ -1798,16 +2614,17 @@ legitimate_address_p (mode, addr, strict)
return FALSE;
}
- if ((strict && !REG_OK_FOR_BASE_STRICT_P (base))
- || (!strict && !REG_OK_FOR_BASE_NONSTRICT_P (base)))
+ if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base))
+ || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base)))
{
ADDR_INVALID ("Base is not valid.\n", base);
return FALSE;
}
}
- /* Validate index register */
- /* Don't allow SUBREG's here, it can lead to spill failures when the index
+ /* Validate index register:
+
+ Don't allow SUBREG's here, it can lead to spill failures when the index
is one word out of a two word structure, which is represented internally
as a DImode int. */
if (indx)
@@ -1818,17 +2635,17 @@ legitimate_address_p (mode, addr, strict)
return FALSE;
}
- if ((strict && !REG_OK_FOR_INDEX_STRICT_P (indx))
- || (!strict && !REG_OK_FOR_INDEX_NONSTRICT_P (indx)))
+ if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (indx))
+ || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (indx)))
{
ADDR_INVALID ("Index is not valid.\n", indx);
return FALSE;
}
}
else if (scale)
- abort (); /* scale w/o index invalid */
+ abort (); /* scale w/o index invalid */
- /* Validate scale factor */
+ /* Validate scale factor: */
if (scale)
{
HOST_WIDE_INT value;
@@ -1847,32 +2664,44 @@ legitimate_address_p (mode, addr, strict)
}
}
- /* Validate displacement */
+ /* Validate displacement
+ Constant pool addresses must be handled special. They are
+ considered legitimate addresses, but only if not used with regs.
+ When printed, the output routines know to print the reference with the
+ PIC reg, even though the PIC reg doesn't appear in the RTL. */
if (disp)
{
- if (!CONSTANT_ADDRESS_P (disp))
+ if (GET_CODE (disp) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (disp)
+ && base == 0
+ && indx == 0)
+ ;
+
+ else if (!CONSTANT_ADDRESS_P (disp))
{
ADDR_INVALID ("Displacement is not valid.\n", disp);
return FALSE;
}
- if (GET_CODE (disp) == CONST_DOUBLE)
+ else if (GET_CODE (disp) == CONST_DOUBLE)
{
ADDR_INVALID ("Displacement is a const_double.\n", disp);
return FALSE;
}
- if (flag_pic && SYMBOLIC_CONST (disp) && base != pic_offset_table_rtx
- && (indx != pic_offset_table_rtx || scale != NULL_RTX))
+ else if (flag_pic && SYMBOLIC_CONST (disp)
+ && base != pic_offset_table_rtx
+ && (indx != pic_offset_table_rtx || scale != NULL_RTX))
{
ADDR_INVALID ("Displacement is an invalid pic reference.\n", disp);
return FALSE;
}
- if (HALF_PIC_P () && HALF_PIC_ADDRESS_P (disp)
- && (base != NULL_RTX || indx != NULL_RTX))
+ else if (HALF_PIC_P () && HALF_PIC_ADDRESS_P (disp)
+ && (base != NULL_RTX || indx != NULL_RTX))
{
- ADDR_INVALID ("Displacement is an invalid half-pic reference.\n", disp);
+ ADDR_INVALID ("Displacement is an invalid half-pic reference.\n",
+ disp);
return FALSE;
}
}
@@ -1883,7 +2712,6 @@ legitimate_address_p (mode, addr, strict)
/* Everything looks valid, return true */
return TRUE;
}
-
/* Return a legitimate reference for ORIG (an address) using the
register REG. If REG is 0, a new pseudo is generated.
@@ -1933,15 +2761,15 @@ legitimize_pic_address (orig, reg)
|| GET_CODE (addr) == LABEL_REF)
new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig);
else
- new = gen_rtx (MEM, Pmode,
- gen_rtx (PLUS, Pmode,
- pic_offset_table_rtx, orig));
+ new = gen_rtx_MEM (Pmode,
+ gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig));
emit_move_insn (reg, new);
}
current_function_uses_pic_offset_table = 1;
return reg;
}
+
else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
{
rtx base;
@@ -1971,27 +2799,26 @@ legitimize_pic_address (orig, reg)
base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
addr = XEXP (addr, 1);
}
- return gen_rtx (PLUS, Pmode, base, addr);
+
+ return gen_rtx (PLUS, Pmode, base, addr);
}
return new;
}
-
/* Emit insns to move operands[1] into operands[0]. */
void
emit_pic_move (operands, mode)
rtx *operands;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
- operands[1] = (rtx) force_reg (SImode, operands[1]);
+ operands[1] = force_reg (SImode, operands[1]);
else
operands[1] = legitimize_pic_address (operands[1], temp);
}
-
/* Try machine-dependent ways of modifying an illegitimate address
to be legitimate. If we find one, return the new, valid address.
@@ -2017,7 +2844,7 @@ emit_pic_move (operands, mode)
rtx
legitimize_address (x, oldx, mode)
register rtx x;
- register rtx oldx;
+ register rtx oldx ATTRIBUTE_UNUSED;
enum machine_mode mode;
{
int changed = 0;
@@ -2025,7 +2852,8 @@ legitimize_address (x, oldx, mode)
if (TARGET_DEBUG_ADDR)
{
- fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n", GET_MODE_NAME (mode));
+ fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n",
+ GET_MODE_NAME (mode));
debug_rtx (x);
}
@@ -2038,14 +2866,14 @@ legitimize_address (x, oldx, mode)
&& (log = (unsigned)exact_log2 (INTVAL (XEXP (x, 1)))) < 4)
{
changed = 1;
- x = gen_rtx (MULT, Pmode,
- force_reg (Pmode, XEXP (x, 0)),
+ x = gen_rtx (MULT, Pmode, force_reg (Pmode, XEXP (x, 0)),
GEN_INT (1 << log));
}
if (GET_CODE (x) == PLUS)
{
- /* Canonicalize shifts by 0, 1, 2, 3 into multiply */
+ /* Canonicalize shifts by 0, 1, 2, 3 into multiply. */
+
if (GET_CODE (XEXP (x, 0)) == ASHIFT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) < 4)
@@ -2066,7 +2894,7 @@ legitimize_address (x, oldx, mode)
GEN_INT (1 << log));
}
- /* Put multiply first if it isn't already */
+ /* Put multiply first if it isn't already. */
if (GET_CODE (XEXP (x, 1)) == MULT)
{
rtx tmp = XEXP (x, 0);
@@ -2083,18 +2911,21 @@ legitimize_address (x, oldx, mode)
{
changed = 1;
x = gen_rtx (PLUS, Pmode,
- gen_rtx (PLUS, Pmode, XEXP (x, 0), XEXP (XEXP (x, 1), 0)),
+ gen_rtx (PLUS, Pmode, XEXP (x, 0),
+ XEXP (XEXP (x, 1), 0)),
XEXP (XEXP (x, 1), 1));
}
- /* Canonicalize (plus (plus (mult (reg) (const)) (plus (reg) (const))) const)
+ /* Canonicalize
+ (plus (plus (mult (reg) (const)) (plus (reg) (const))) const)
into (plus (plus (mult (reg) (const)) (reg)) (const)). */
else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS
&& CONSTANT_P (XEXP (x, 1)))
{
- rtx constant, other;
+ rtx constant;
+ rtx other = NULL_RTX;
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
@@ -2173,7 +3004,6 @@ legitimize_address (x, oldx, mode)
return x;
}
-
/* Print an integer constant expression in assembler syntax. Addition
and subtraction are the only arithmetic that may appear in these
@@ -2208,7 +3038,9 @@ output_pic_addr_const (file, x, code)
assemble_name (asm_out_file, buf);
}
- if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
+ if (code == 'X')
+ ; /* No suffix, dammit. */
+ else if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
fprintf (file, "@GOTOFF(%%ebx)");
else if (code == 'P')
fprintf (file, "@PLT");
@@ -2227,7 +3059,7 @@ output_pic_addr_const (file, x, code)
break;
case CONST_INT:
- fprintf (file, "%d", INTVAL (x));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
break;
case CONST:
@@ -2241,10 +3073,11 @@ output_pic_addr_const (file, x, code)
{
/* We can use %d if the number is <32 bits and positive. */
if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
- fprintf (file, "0x%x%08x",
- CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
+ fprintf (file, "0x%lx%08lx",
+ (unsigned long) CONST_DOUBLE_HIGH (x),
+ (unsigned long) CONST_DOUBLE_LOW (x));
else
- fprintf (file, "%d", CONST_DOUBLE_LOW (x));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
}
else
/* We can't handle floating point constants;
@@ -2253,20 +3086,20 @@ output_pic_addr_const (file, x, code)
break;
case PLUS:
- /* Some assemblers need integer constants to appear last (eg masm). */
+ /* Some assemblers need integer constants to appear first. */
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
{
- output_pic_addr_const (file, XEXP (x, 1), code);
- if (INTVAL (XEXP (x, 0)) >= 0)
- fprintf (file, "+");
output_pic_addr_const (file, XEXP (x, 0), code);
+ if (INTVAL (XEXP (x, 1)) >= 0)
+ fprintf (file, "+");
+ output_pic_addr_const (file, XEXP (x, 1), code);
}
else
{
- output_pic_addr_const (file, XEXP (x, 0), code);
- if (INTVAL (XEXP (x, 1)) >= 0)
- fprintf (file, "+");
output_pic_addr_const (file, XEXP (x, 1), code);
+ if (INTVAL (XEXP (x, 0)) >= 0)
+ fprintf (file, "+");
+ output_pic_addr_const (file, XEXP (x, 0), code);
}
break;
@@ -2281,16 +3114,138 @@ output_pic_addr_const (file, x, code)
}
}
+/* Append the correct conditional move suffix which corresponds to CODE. */
+
+static void
+put_condition_code (code, reverse_cc, mode, file)
+ enum rtx_code code;
+ int reverse_cc;
+ enum mode_class mode;
+ FILE * file;
+{
+ int ieee = (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI));
+ if (reverse_cc && ! ieee)
+ code = reverse_condition (code);
+
+ if (mode == MODE_INT)
+ switch (code)
+ {
+ case NE:
+ if (cc_prev_status.flags & CC_Z_IN_NOT_C)
+ fputs ("b", file);
+ else
+ fputs ("ne", file);
+ return;
+
+ case EQ:
+ if (cc_prev_status.flags & CC_Z_IN_NOT_C)
+ fputs ("ae", file);
+ else
+ fputs ("e", file);
+ return;
+
+ case GE:
+ if (cc_prev_status.flags & CC_NO_OVERFLOW)
+ fputs ("ns", file);
+ else
+ fputs ("ge", file);
+ return;
+
+ case GT:
+ fputs ("g", file);
+ return;
+
+ case LE:
+ fputs ("le", file);
+ return;
+
+ case LT:
+ if (cc_prev_status.flags & CC_NO_OVERFLOW)
+ fputs ("s", file);
+ else
+ fputs ("l", file);
+ return;
+
+ case GEU:
+ fputs ("ae", file);
+ return;
+
+ case GTU:
+ fputs ("a", file);
+ return;
+
+ case LEU:
+ fputs ("be", file);
+ return;
+
+ case LTU:
+ fputs ("b", file);
+ return;
+
+ default:
+ output_operand_lossage ("Invalid %%C operand");
+ }
+
+ else if (mode == MODE_FLOAT)
+ switch (code)
+ {
+ case NE:
+ fputs (ieee ? (reverse_cc ? "ne" : "e") : "ne", file);
+ return;
+ case EQ:
+ fputs (ieee ? (reverse_cc ? "ne" : "e") : "e", file);
+ return;
+ case GE:
+ fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file);
+ return;
+ case GT:
+ fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file);
+ return;
+ case LE:
+ fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file);
+ return;
+ case LT:
+ fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file);
+ return;
+ case GEU:
+ fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file);
+ return;
+ case GTU:
+ fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file);
+ return;
+ case LEU:
+ fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file);
+ return;
+ case LTU:
+ fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file);
+ return;
+ default:
+ output_operand_lossage ("Invalid %%C operand");
+ }
+}
+
/* Meaning of CODE:
- f -- float insn (print a CONST_DOUBLE as a float rather than in hex).
- D,L,W,B,Q,S -- print the opcode suffix for specified size of operand.
+ L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
+ C -- print opcode suffix for set/cmov insn.
+ c -- like C, but print reversed condition
+ F -- print opcode suffix for fcmov insn.
+ f -- like C, but print reversed condition
R -- print the prefix for register names.
z -- print the opcode suffix for the size of the current operand.
* -- print a star (in certain assembler syntax)
w -- print the operand as if it's a "word" (HImode) even if it isn't.
c -- don't print special prefixes before constant operands.
J -- print the appropriate jump operand.
-*/
+ s -- print a shift double count, followed by the assemblers argument
+ delimiter.
+ b -- print the QImode name of the register for the indicated operand.
+ %b0 would print %al if operands[0] is reg 0.
+ w -- likewise, print the HImode name of the register.
+ k -- likewise, print the SImode name of the register.
+ h -- print the QImode name for a "high" register, either ah, bh, ch or dh.
+ y -- print "st(0)" instead of "st" as a register.
+ P -- print as a PIC constant */
void
print_operand (file, x, code)
@@ -2384,6 +3339,7 @@ print_operand (file, x, code)
case 'h':
case 'y':
case 'P':
+ case 'X':
break;
case 'J':
@@ -2403,8 +3359,37 @@ print_operand (file, x, code)
case LTU: fputs ("#branch never", file); return;
/* no matching branches for GT nor LE */
+
+ default:
+ abort ();
+ }
+
+ case 's':
+ if (GET_CODE (x) == CONST_INT || ! SHIFT_DOUBLE_OMITS_COUNT)
+ {
+ PRINT_OPERAND (file, x, 0);
+ fputs (AS2C (,) + 1, file);
}
- abort ();
+
+ return;
+
+ /* This is used by the conditional move instructions. */
+ case 'C':
+ put_condition_code (GET_CODE (x), 0, MODE_INT, file);
+ return;
+
+ /* Like above, but reverse condition */
+ case 'c':
+ put_condition_code (GET_CODE (x), 1, MODE_INT, file); return;
+
+ case 'F':
+ put_condition_code (GET_CODE (x), 0, MODE_FLOAT, file);
+ return;
+
+ /* Like above, but reverse condition */
+ case 'f':
+ put_condition_code (GET_CODE (x), 1, MODE_FLOAT, file);
+ return;
default:
{
@@ -2415,10 +3400,12 @@ print_operand (file, x, code)
}
}
}
+
if (GET_CODE (x) == REG)
{
PRINT_REG (x, code, file);
}
+
else if (GET_CODE (x) == MEM)
{
PRINT_PTR (x, file);
@@ -2432,30 +3419,39 @@ print_operand (file, x, code)
else
output_address (XEXP (x, 0));
}
+
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
{
- REAL_VALUE_TYPE r; long l;
+ REAL_VALUE_TYPE r;
+ long l;
+
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
REAL_VALUE_TO_TARGET_SINGLE (r, l);
PRINT_IMMED_PREFIX (file);
- fprintf (file, "0x%x", l);
+ fprintf (file, "0x%lx", l);
}
+
/* These float cases don't actually occur as immediate operands. */
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
{
- REAL_VALUE_TYPE r; char dstr[30];
+ REAL_VALUE_TYPE r;
+ char dstr[30];
+
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
fprintf (file, "%s", dstr);
}
+
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode)
{
- REAL_VALUE_TYPE r; char dstr[30];
+ REAL_VALUE_TYPE r;
+ char dstr[30];
+
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
fprintf (file, "%s", dstr);
}
- else
+ else
{
if (code != 'P')
{
@@ -2507,38 +3503,35 @@ print_operand_address (file, addr)
offset = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
- if (GET_CODE (addr) != PLUS) ;
+
+ if (GET_CODE (addr) != PLUS)
+ ;
else if (GET_CODE (XEXP (addr, 0)) == MULT)
- {
- reg1 = XEXP (addr, 0);
- addr = XEXP (addr, 1);
- }
+ reg1 = XEXP (addr, 0), addr = XEXP (addr, 1);
else if (GET_CODE (XEXP (addr, 1)) == MULT)
- {
- reg1 = XEXP (addr, 1);
- addr = XEXP (addr, 0);
- }
+ reg1 = XEXP (addr, 1), addr = XEXP (addr, 0);
else if (GET_CODE (XEXP (addr, 0)) == REG)
- {
- reg1 = XEXP (addr, 0);
- addr = XEXP (addr, 1);
- }
+ reg1 = XEXP (addr, 0), addr = XEXP (addr, 1);
else if (GET_CODE (XEXP (addr, 1)) == REG)
- {
- reg1 = XEXP (addr, 1);
- addr = XEXP (addr, 0);
- }
+ reg1 = XEXP (addr, 1), addr = XEXP (addr, 0);
+
if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
{
- if (reg1 == 0) reg1 = addr;
- else reg2 = addr;
+ if (reg1 == 0)
+ reg1 = addr;
+ else
+ reg2 = addr;
+
addr = 0;
}
+
if (offset != 0)
{
- if (addr != 0) abort ();
+ if (addr != 0)
+ abort ();
addr = offset;
}
+
if ((reg1 && GET_CODE (reg1) == MULT)
|| (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
{
@@ -2559,10 +3552,8 @@ print_operand_address (file, addr)
{
if (flag_pic)
output_pic_addr_const (file, addr, 0);
-
else if (GET_CODE (addr) == LABEL_REF)
output_asm_label (addr);
-
else
output_addr_const (file, addr);
}
@@ -2593,6 +3584,7 @@ print_operand_address (file, addr)
case MULT:
{
int scale;
+
if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
{
scale = INTVAL (XEXP (addr, 0));
@@ -2603,8 +3595,9 @@ print_operand_address (file, addr)
scale = INTVAL (XEXP (addr, 1));
ireg = XEXP (addr, 0);
}
+
output_addr_const (file, const0_rtx);
- PRINT_B_I_S ((rtx) 0, ireg, scale, file);
+ PRINT_B_I_S (NULL_RTX, ireg, scale, file);
}
break;
@@ -2612,7 +3605,7 @@ print_operand_address (file, addr)
if (GET_CODE (addr) == CONST_INT
&& INTVAL (addr) < 0x8000
&& INTVAL (addr) >= -0x8000)
- fprintf (file, "%d", INTVAL (addr));
+ fprintf (file, "%d", (int) INTVAL (addr));
else
{
if (flag_pic)
@@ -2625,7 +3618,7 @@ print_operand_address (file, addr)
/* Set the cc_status for the results of an insn whose pattern is EXP.
On the 80386, we assume that only test and compare insns, as well
- as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT,
+ as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, BSF, ASHIFT,
ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully.
Also, we assume that jumps, moves and sCOND don't affect the condition
codes. All else clobbers the condition codes, by assumption.
@@ -2645,40 +3638,51 @@ notice_update_cc (exp)
/* Jumps do not alter the cc's. */
if (SET_DEST (exp) == pc_rtx)
return;
+
/* Moving register or memory into a register:
it doesn't alter the cc's, but it might invalidate
the RTX's which we remember the cc's came from.
(Note that moving a constant 0 or 1 MAY set the cc's). */
if (REG_P (SET_DEST (exp))
&& (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM
- || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
+ || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'
+ || (GET_CODE (SET_SRC (exp)) == IF_THEN_ELSE
+ && GET_MODE_CLASS (GET_MODE (SET_DEST (exp))) == MODE_INT)))
{
if (cc_status.value1
&& reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
cc_status.value1 = 0;
+
if (cc_status.value2
&& reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
cc_status.value2 = 0;
+
return;
}
+
/* Moving register into memory doesn't alter the cc's.
It may invalidate the RTX's which we remember the cc's came from. */
if (GET_CODE (SET_DEST (exp)) == MEM
&& (REG_P (SET_SRC (exp))
|| GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
{
- if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM)
+ if (cc_status.value1
+ && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
cc_status.value1 = 0;
- if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM)
+ if (cc_status.value2
+ && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
cc_status.value2 = 0;
+
return;
}
+
/* Function calls clobber the cc's. */
else if (GET_CODE (SET_SRC (exp)) == CALL)
{
CC_STATUS_INIT;
return;
}
+
/* Tests and compares set the cc's in predictable ways. */
else if (SET_DEST (exp) == cc0_rtx)
{
@@ -2686,14 +3690,14 @@ notice_update_cc (exp)
cc_status.value1 = SET_SRC (exp);
return;
}
+
/* Certain instructions effect the condition codes. */
else if (GET_MODE (SET_SRC (exp)) == SImode
|| GET_MODE (SET_SRC (exp)) == HImode
|| GET_MODE (SET_SRC (exp)) == QImode)
switch (GET_CODE (SET_SRC (exp)))
{
- case ASHIFTRT: case LSHIFTRT:
- case ASHIFT:
+ case ASHIFTRT: case LSHIFTRT: case ASHIFT:
/* Shifts on the 386 don't set the condition codes if the
shift count is zero. */
if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
@@ -2701,6 +3705,7 @@ notice_update_cc (exp)
CC_STATUS_INIT;
break;
}
+
/* We assume that the CONST_INT is non-zero (this rtx would
have been deleted if it were zero. */
@@ -2711,6 +3716,19 @@ notice_update_cc (exp)
cc_status.value2 = SET_DEST (exp);
break;
+ /* This is the bsf pattern used by ffs. */
+ case UNSPEC:
+ if (XINT (SET_SRC (exp), 1) == 5)
+ {
+ /* Only the Z flag is defined after bsf. */
+ cc_status.flags
+ = CC_NOT_POSITIVE | CC_NOT_NEGATIVE | CC_NO_OVERFLOW;
+ cc_status.value1 = XVECEXP (SET_SRC (exp), 0, 0);
+ cc_status.value2 = 0;
+ break;
+ }
+ /* FALLTHRU */
+
default:
CC_STATUS_INIT;
}
@@ -2725,14 +3743,21 @@ notice_update_cc (exp)
if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
return;
if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
+
{
CC_STATUS_INIT;
- if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
- cc_status.flags |= CC_IN_80387;
+ if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
+ {
+ cc_status.flags |= CC_IN_80387;
+ if (0 && TARGET_CMOVE && stack_regs_mentioned_p
+ (XEXP (SET_SRC (XVECEXP (exp, 0, 0)), 1)))
+ cc_status.flags |= CC_FCOMI;
+ }
else
cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
return;
}
+
CC_STATUS_INIT;
}
else
@@ -2755,19 +3780,20 @@ split_di (operands, num, lo_half, hi_half)
{
while (num--)
{
- if (GET_CODE (operands[num]) == REG)
- {
- lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]));
- hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1);
- }
- else if (CONSTANT_P (operands[num]))
+ rtx op = operands[num];
+ if (GET_CODE (op) == REG)
{
- split_double (operands[num], &lo_half[num], &hi_half[num]);
+ lo_half[num] = gen_rtx_REG (SImode, REGNO (op));
+ hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1);
}
- else if (offsettable_memref_p (operands[num]))
+ else if (CONSTANT_P (op))
+ split_double (op, &lo_half[num], &hi_half[num]);
+ else if (offsettable_memref_p (op))
{
- lo_half[num] = operands[num];
- hi_half[num] = adj_offsettable_operand (operands[num], 4);
+ rtx lo_addr = XEXP (op, 0);
+ rtx hi_addr = XEXP (adj_offsettable_operand (op, 4), 0);
+ lo_half[num] = change_address (op, SImode, lo_addr);
+ hi_half[num] = change_address (op, SImode, hi_addr);
}
else
abort();
@@ -2797,7 +3823,6 @@ binary_387_op (op, mode)
return 0;
}
}
-
/* Return 1 if this is a valid shift or rotate operation on a 386.
OP is the expression matched, and MODE is its mode. */
@@ -2829,7 +3854,7 @@ shift_op (op, mode)
int
VOIDmode_compare_op (op, mode)
register rtx op;
- enum machine_mode mode;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
{
return GET_CODE (op) == COMPARE && GET_MODE (op) == VOIDmode;
}
@@ -2908,16 +3933,22 @@ output_387_binary_op (insn, operands)
if (NON_STACK_REG_P (operands[1]))
{
output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
- RET;
+ return "";
}
+
else if (NON_STACK_REG_P (operands[2]))
{
output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
- RET;
+ return "";
}
if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
- return strcat (buf, AS2 (p,%2,%0));
+ {
+ if (STACK_TOP_P (operands[0]))
+ return strcat (buf, AS2 (p,%0,%2));
+ else
+ return strcat (buf, AS2 (p,%2,%0));
+ }
if (STACK_TOP_P (operands[0]))
return strcat (buf, AS2C (%y2,%0));
@@ -2935,22 +3966,33 @@ output_387_binary_op (insn, operands)
if (NON_STACK_REG_P (operands[1]))
{
output_op_from_reg (operands[1], strcat (buf, AS1 (r%z0,%1)));
- RET;
+ return "";
}
+
else if (NON_STACK_REG_P (operands[2]))
{
output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
- RET;
+ return "";
}
if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
abort ();
if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
- return strcat (buf, AS2 (rp,%2,%0));
+ {
+ if (STACK_TOP_P (operands[0]))
+ return strcat (buf, AS2 (p,%0,%2));
+ else
+ return strcat (buf, AS2 (rp,%2,%0));
+ }
if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
- return strcat (buf, AS2 (p,%1,%0));
+ {
+ if (STACK_TOP_P (operands[0]))
+ return strcat (buf, AS2 (rp,%0,%1));
+ else
+ return strcat (buf, AS2 (p,%1,%0));
+ }
if (STACK_TOP_P (operands[0]))
{
@@ -2983,8 +4025,7 @@ output_fix_trunc (insn, operands)
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
rtx xops[2];
- if (! STACK_TOP_P (operands[1]) ||
- (GET_MODE (operands[0]) == DImode && ! stack_top_dies))
+ if (! STACK_TOP_P (operands[1]))
abort ();
xops[0] = GEN_INT (12);
@@ -2997,11 +4038,23 @@ output_fix_trunc (insn, operands)
output_asm_insn (AS1 (fldc%W3,%3), operands);
if (NON_STACK_REG_P (operands[0]))
- output_to_reg (operands[0], stack_top_dies);
+ output_to_reg (operands[0], stack_top_dies, operands[3]);
+
else if (GET_CODE (operands[0]) == MEM)
{
if (stack_top_dies)
output_asm_insn (AS1 (fistp%z0,%0), operands);
+ else if (GET_MODE (operands[0]) == DImode && ! stack_top_dies)
+ {
+ /* There is no DImode version of this without a stack pop, so
+ we must emulate it. It doesn't matter much what the second
+ instruction is, because the value being pushed on the FP stack
+ is not used except for the following stack popping store.
+ This case can only happen without optimization, so it doesn't
+ matter that it is inefficient. */
+ output_asm_insn (AS1 (fistp%z0,%0), operands);
+ output_asm_insn (AS1 (fild%z0,%0), operands);
+ }
else
output_asm_insn (AS1 (fist%z0,%0), operands);
}
@@ -3024,6 +4077,21 @@ output_float_compare (insn, operands)
int stack_top_dies;
rtx body = XVECEXP (PATTERN (insn), 0, 0);
int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
+ rtx tmp;
+
+ if (0 && TARGET_CMOVE && STACK_REG_P (operands[1]))
+ {
+ cc_status.flags |= CC_FCOMI;
+ cc_prev_status.flags &= ~CC_TEST_AX;
+ }
+
+ if (! STACK_TOP_P (operands[0]))
+ {
+ tmp = operands[0];
+ operands[0] = operands[1];
+ operands[1] = tmp;
+ cc_status.flags |= CC_REVERSED;
+ }
if (! STACK_TOP_P (operands[0]))
abort ();
@@ -3040,9 +4108,27 @@ output_float_compare (insn, operands)
`fcompp' float compare */
if (unordered_compare)
- output_asm_insn ("fucompp", operands);
+ {
+ if (cc_status.flags & CC_FCOMI)
+ {
+ output_asm_insn (AS2 (fucomip,%y1,%0), operands);
+ output_asm_insn (AS1 (fstp, %y0), operands);
+ return "";
+ }
+ else
+ output_asm_insn ("fucompp", operands);
+ }
else
- output_asm_insn ("fcompp", operands);
+ {
+ if (cc_status.flags & CC_FCOMI)
+ {
+ output_asm_insn (AS2 (fcomip, %y1,%0), operands);
+ output_asm_insn (AS1 (fstp, %y0), operands);
+ return "";
+ }
+ else
+ output_asm_insn ("fcompp", operands);
+ }
}
else
{
@@ -3052,9 +4138,9 @@ output_float_compare (insn, operands)
unordered float compare. */
if (unordered_compare)
- strcpy (buf, "fucom");
+ strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fucomi" : "fucom");
else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
- strcpy (buf, "fcom");
+ strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fcomi" : "fcom");
else
strcpy (buf, "ficom");
@@ -3065,6 +4151,11 @@ output_float_compare (insn, operands)
if (NON_STACK_REG_P (operands[1]))
output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
+ else if (cc_status.flags & CC_FCOMI)
+ {
+ output_asm_insn (strcat (buf, AS2 (%z1,%y1,%0)), operands);
+ return "";
+ }
else
output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands);
}
@@ -3084,15 +4175,39 @@ output_fp_cc0_set (insn)
rtx insn;
{
rtx xops[3];
- rtx unordered_label;
rtx next;
enum rtx_code code;
- xops[0] = gen_rtx (REG, HImode, 0);
+ xops[0] = gen_rtx_REG (HImode, 0);
output_asm_insn (AS1 (fnsts%W0,%0), xops);
if (! TARGET_IEEE_FP)
- return "sahf";
+ {
+ if (!(cc_status.flags & CC_REVERSED))
+ {
+ next = next_cc0_user (insn);
+
+ if (GET_CODE (next) == JUMP_INSN
+ && GET_CODE (PATTERN (next)) == SET
+ && SET_DEST (PATTERN (next)) == pc_rtx
+ && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
+ code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
+ else if (GET_CODE (PATTERN (next)) == SET)
+ code = GET_CODE (SET_SRC (PATTERN (next)));
+ else
+ return "sahf";
+
+ if (code == GT || code == LT || code == EQ || code == NE
+ || code == LE || code == GE)
+ {
+ /* We will test eax directly. */
+ cc_status.flags |= CC_TEST_AX;
+ return "";
+ }
+ }
+
+ return "sahf";
+ }
next = next_cc0_user (insn);
if (next == NULL_RTX)
@@ -3102,17 +4217,27 @@ output_fp_cc0_set (insn)
&& GET_CODE (PATTERN (next)) == SET
&& SET_DEST (PATTERN (next)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
+ code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
+ else if (GET_CODE (PATTERN (next)) == SET)
{
- code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
+ if (GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
+ code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
+ else
+ code = GET_CODE (SET_SRC (PATTERN (next)));
}
- else if (GET_CODE (PATTERN (next)) == SET)
+
+ else if (GET_CODE (PATTERN (next)) == PARALLEL
+ && GET_CODE (XVECEXP (PATTERN (next), 0, 0)) == SET)
{
- code = GET_CODE (SET_SRC (PATTERN (next)));
+ if (GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0))) == IF_THEN_ELSE)
+ code = GET_CODE (XEXP (SET_SRC (XVECEXP (PATTERN (next), 0, 0)), 0));
+ else
+ code = GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0)));
}
else
abort ();
- xops[0] = gen_rtx (REG, QImode, 0);
+ xops[0] = gen_rtx_REG (QImode, 0);
switch (code)
{
@@ -3168,7 +4293,8 @@ output_fp_cc0_set (insn)
default:
abort ();
}
- RET;
+
+ return "";
}
#define MAX_386_STACK_LOCALS 2
@@ -3179,6 +4305,8 @@ static rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
struct machine_function
{
rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
+ rtx pic_label_rtx;
+ char pic_label_name[256];
};
/* Functions to save and restore i386_stack_locals.
@@ -3189,9 +4317,12 @@ void
save_386_machine_status (p)
struct function *p;
{
- p->machine = (struct machine_function *) xmalloc (sizeof i386_stack_locals);
+ p->machine
+ = (struct machine_function *) xmalloc (sizeof (struct machine_function));
bcopy ((char *) i386_stack_locals, (char *) p->machine->i386_stack_locals,
sizeof i386_stack_locals);
+ p->machine->pic_label_rtx = pic_label_rtx;
+ bcopy (pic_label_name, p->machine->pic_label_name, 256);
}
void
@@ -3200,7 +4331,10 @@ restore_386_machine_status (p)
{
bcopy ((char *) p->machine->i386_stack_locals, (char *) i386_stack_locals,
sizeof i386_stack_locals);
+ pic_label_rtx = p->machine->pic_label_rtx;
+ bcopy (p->machine->pic_label_name, pic_label_name, 256);
free (p->machine);
+ p->machine = NULL;
}
/* Clear stack slot assignments remembered from previous functions.
@@ -3218,6 +4352,8 @@ clear_386_stack_locals ()
for (n = 0; n < MAX_386_STACK_LOCALS; n++)
i386_stack_locals[(int) mode][n] = NULL_RTX;
+ pic_label_rtx = NULL_RTX;
+ bzero (pic_label_name, 256);
/* Arrange to save and restore i386_stack_locals around nested functions. */
save_machine_status = save_386_machine_status;
restore_machine_status = restore_386_machine_status;
@@ -3243,3 +4379,897 @@ assign_386_stack_local (mode, n)
return i386_stack_locals[(int) mode][n];
}
+
+int is_mul(op,mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == MULT);
+}
+
+int is_div(op,mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == DIV);
+}
+
+#ifdef NOTYET
+/* Create a new copy of an rtx.
+ Recursively copies the operands of the rtx,
+ except for those few rtx codes that are sharable.
+ Doesn't share CONST */
+
+rtx
+copy_all_rtx (orig)
+ register rtx orig;
+{
+ register rtx copy;
+ register int i, j;
+ register RTX_CODE code;
+ register char *format_ptr;
+
+ code = GET_CODE (orig);
+
+ switch (code)
+ {
+ case REG:
+ case QUEUED:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case SCRATCH:
+ /* SCRATCH must be shared because they represent distinct values. */
+ return orig;
+
+#if 0
+ case CONST:
+ /* CONST can be shared if it contains a SYMBOL_REF. If it contains
+ a LABEL_REF, it isn't sharable. */
+ if (GET_CODE (XEXP (orig, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
+ return orig;
+ break;
+#endif
+ /* A MEM with a constant address is not sharable. The problem is that
+ the constant address may need to be reloaded. If the mem is shared,
+ then reloading one copy of this mem will cause all copies to appear
+ to have been reloaded. */
+ }
+
+ copy = rtx_alloc (code);
+ PUT_MODE (copy, GET_MODE (orig));
+ copy->in_struct = orig->in_struct;
+ copy->volatil = orig->volatil;
+ copy->unchanging = orig->unchanging;
+ copy->integrated = orig->integrated;
+ /* intel1 */
+ copy->is_spill_rtx = orig->is_spill_rtx;
+
+ format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
+
+ for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
+ {
+ switch (*format_ptr++)
+ {
+ case 'e':
+ XEXP (copy, i) = XEXP (orig, i);
+ if (XEXP (orig, i) != NULL)
+ XEXP (copy, i) = copy_rtx (XEXP (orig, i));
+ break;
+
+ case '0':
+ case 'u':
+ XEXP (copy, i) = XEXP (orig, i);
+ break;
+
+ case 'E':
+ case 'V':
+ XVEC (copy, i) = XVEC (orig, i);
+ if (XVEC (orig, i) != NULL)
+ {
+ XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
+ for (j = 0; j < XVECLEN (copy, i); j++)
+ XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
+ }
+ break;
+
+ case 'w':
+ XWINT (copy, i) = XWINT (orig, i);
+ break;
+
+ case 'i':
+ XINT (copy, i) = XINT (orig, i);
+ break;
+
+ case 's':
+ case 'S':
+ XSTR (copy, i) = XSTR (orig, i);
+ break;
+
+ default:
+ abort ();
+ }
+ }
+ return copy;
+}
+
+
+/* Try to rewrite a memory address to make it valid */
+
+void
+rewrite_address (mem_rtx)
+ rtx mem_rtx;
+{
+ rtx index_rtx, base_rtx, offset_rtx, scale_rtx, ret_rtx;
+ int scale = 1;
+ int offset_adjust = 0;
+ int was_only_offset = 0;
+ rtx mem_addr = XEXP (mem_rtx, 0);
+ char *storage = oballoc (0);
+ int in_struct = 0;
+ int is_spill_rtx = 0;
+
+ in_struct = MEM_IN_STRUCT_P (mem_rtx);
+ is_spill_rtx = RTX_IS_SPILL_P (mem_rtx);
+
+ if (GET_CODE (mem_addr) == PLUS
+ && GET_CODE (XEXP (mem_addr, 1)) == PLUS
+ && GET_CODE (XEXP (XEXP (mem_addr, 1), 0)) == REG)
+ {
+ /* This part is utilized by the combiner. */
+ ret_rtx
+ = gen_rtx (PLUS, GET_MODE (mem_addr),
+ gen_rtx (PLUS, GET_MODE (XEXP (mem_addr, 1)),
+ XEXP (mem_addr, 0), XEXP (XEXP (mem_addr, 1), 0)),
+ XEXP (XEXP (mem_addr, 1), 1));
+
+ if (memory_address_p (GET_MODE (mem_rtx), ret_rtx))
+ {
+ XEXP (mem_rtx, 0) = ret_rtx;
+ RTX_IS_SPILL_P (ret_rtx) = is_spill_rtx;
+ return;
+ }
+
+ obfree (storage);
+ }
+
+ /* This part is utilized by loop.c.
+ If the address contains PLUS (reg,const) and this pattern is invalid
+ in this case - try to rewrite the address to make it valid. */
+ storage = oballoc (0);
+ index_rtx = base_rtx = offset_rtx = NULL;
+
+ /* Find the base index and offset elements of the memory address. */
+ if (GET_CODE (mem_addr) == PLUS)
+ {
+ if (GET_CODE (XEXP (mem_addr, 0)) == REG)
+ {
+ if (GET_CODE (XEXP (mem_addr, 1)) == REG)
+ base_rtx = XEXP (mem_addr, 1), index_rtx = XEXP (mem_addr, 0);
+ else
+ base_rtx = XEXP (mem_addr, 0), offset_rtx = XEXP (mem_addr, 1);
+ }
+
+ else if (GET_CODE (XEXP (mem_addr, 0)) == MULT)
+ {
+ index_rtx = XEXP (mem_addr, 0);
+ if (GET_CODE (XEXP (mem_addr, 1)) == REG)
+ base_rtx = XEXP (mem_addr, 1);
+ else
+ offset_rtx = XEXP (mem_addr, 1);
+ }
+
+ else if (GET_CODE (XEXP (mem_addr, 0)) == PLUS)
+ {
+ if (GET_CODE (XEXP (XEXP (mem_addr, 0), 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0)) == MULT
+ && (GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 0))
+ == REG)
+ && (GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 1))
+ == CONST_INT)
+ && (GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1))
+ == CONST_INT)
+ && GET_CODE (XEXP (XEXP (mem_addr, 0), 1)) == REG
+ && GET_CODE (XEXP (mem_addr, 1)) == SYMBOL_REF)
+ {
+ index_rtx = XEXP (XEXP (XEXP (mem_addr, 0), 0), 0);
+ offset_rtx = XEXP (mem_addr, 1);
+ base_rtx = XEXP (XEXP (mem_addr, 0), 1);
+ offset_adjust = INTVAL (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1));
+ }
+ else
+ {
+ offset_rtx = XEXP (mem_addr, 1);
+ index_rtx = XEXP (XEXP (mem_addr, 0), 0);
+ base_rtx = XEXP (XEXP (mem_addr, 0), 1);
+ }
+ }
+
+ else if (GET_CODE (XEXP (mem_addr, 0)) == CONST_INT)
+ {
+ was_only_offset = 1;
+ index_rtx = NULL;
+ base_rtx = NULL;
+ offset_rtx = XEXP (mem_addr, 1);
+ offset_adjust = INTVAL (XEXP (mem_addr, 0));
+ if (offset_adjust == 0)
+ {
+ XEXP (mem_rtx, 0) = offset_rtx;
+ RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
+ return;
+ }
+ }
+ else
+ {
+ obfree (storage);
+ return;
+ }
+ }
+ else if (GET_CODE (mem_addr) == MULT)
+ index_rtx = mem_addr;
+ else
+ {
+ obfree (storage);
+ return;
+ }
+
+ if (index_rtx != 0 && GET_CODE (index_rtx) == MULT)
+ {
+ if (GET_CODE (XEXP (index_rtx, 1)) != CONST_INT)
+ {
+ obfree (storage);
+ return;
+ }
+
+ scale_rtx = XEXP (index_rtx, 1);
+ scale = INTVAL (scale_rtx);
+ index_rtx = copy_all_rtx (XEXP (index_rtx, 0));
+ }
+
+ /* Now find which of the elements are invalid and try to fix them. */
+ if (index_rtx && GET_CODE (index_rtx) == CONST_INT && base_rtx == NULL)
+ {
+ offset_adjust = INTVAL (index_rtx) * scale;
+
+ if (offset_rtx != 0 && CONSTANT_P (offset_rtx))
+ offset_rtx = plus_constant (offset_rtx, offset_adjust);
+ else if (offset_rtx == 0)
+ offset_rtx = const0_rtx;
+
+ RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
+ XEXP (mem_rtx, 0) = offset_rtx;
+ return;
+ }
+
+ if (base_rtx && GET_CODE (base_rtx) == PLUS
+ && GET_CODE (XEXP (base_rtx, 0)) == REG
+ && GET_CODE (XEXP (base_rtx, 1)) == CONST_INT)
+ {
+ offset_adjust += INTVAL (XEXP (base_rtx, 1));
+ base_rtx = copy_all_rtx (XEXP (base_rtx, 0));
+ }
+
+ else if (base_rtx && GET_CODE (base_rtx) == CONST_INT)
+ {
+ offset_adjust += INTVAL (base_rtx);
+ base_rtx = NULL;
+ }
+
+ if (index_rtx && GET_CODE (index_rtx) == PLUS
+ && GET_CODE (XEXP (index_rtx, 0)) == REG
+ && GET_CODE (XEXP (index_rtx, 1)) == CONST_INT)
+ {
+ offset_adjust += INTVAL (XEXP (index_rtx, 1)) * scale;
+ index_rtx = copy_all_rtx (XEXP (index_rtx, 0));
+ }
+
+ if (index_rtx)
+ {
+ if (! LEGITIMATE_INDEX_P (index_rtx)
+ && ! (index_rtx == stack_pointer_rtx && scale == 1
+ && base_rtx == NULL))
+ {
+ obfree (storage);
+ return;
+ }
+ }
+
+ if (base_rtx)
+ {
+ if (! LEGITIMATE_INDEX_P (base_rtx) && GET_CODE (base_rtx) != REG)
+ {
+ obfree (storage);
+ return;
+ }
+ }
+
+ if (offset_adjust != 0)
+ {
+ if (offset_rtx != 0 && CONSTANT_P (offset_rtx))
+ offset_rtx = plus_constant (offset_rtx, offset_adjust);
+ else
+ offset_rtx = const0_rtx;
+
+ if (index_rtx)
+ {
+ if (base_rtx)
+ {
+ if (scale != 1)
+ {
+ ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx),
+ gen_rtx (MULT, GET_MODE (index_rtx),
+ index_rtx, scale_rtx),
+ base_rtx);
+
+ if (GET_CODE (offset_rtx) != CONST_INT
+ || INTVAL (offset_rtx) != 0)
+ ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
+ ret_rtx, offset_rtx);
+ }
+ else
+ {
+ ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx),
+ index_rtx, base_rtx);
+
+ if (GET_CODE (offset_rtx) != CONST_INT
+ || INTVAL (offset_rtx) != 0)
+ ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
+ ret_rtx, offset_rtx);
+ }
+ }
+ else
+ {
+ if (scale != 1)
+ {
+ ret_rtx = gen_rtx (MULT, GET_MODE (index_rtx),
+ index_rtx, scale_rtx);
+
+ if (GET_CODE (offset_rtx) != CONST_INT
+ || INTVAL (offset_rtx) != 0)
+ ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
+ ret_rtx, offset_rtx);
+ }
+ else
+ {
+ if (GET_CODE (offset_rtx) == CONST_INT
+ && INTVAL (offset_rtx) == 0)
+ ret_rtx = index_rtx;
+ else
+ ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx),
+ index_rtx, offset_rtx);
+ }
+ }
+ }
+ else
+ {
+ if (base_rtx)
+ {
+ if (GET_CODE (offset_rtx) == CONST_INT
+ && INTVAL (offset_rtx) == 0)
+ ret_rtx = base_rtx;
+ else
+ ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx), base_rtx,
+ offset_rtx);
+ }
+ else if (was_only_offset)
+ ret_rtx = offset_rtx;
+ else
+ {
+ obfree (storage);
+ return;
+ }
+ }
+
+ XEXP (mem_rtx, 0) = ret_rtx;
+ RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
+ return;
+ }
+ else
+ {
+ obfree (storage);
+ return;
+ }
+}
+#endif /* NOTYET */
+
+/* Return 1 if the first insn to set cc before INSN also sets the register
+ REG_RTX; otherwise return 0. */
+int
+last_to_set_cc (reg_rtx, insn)
+ rtx reg_rtx, insn;
+{
+ rtx prev_insn = PREV_INSN (insn);
+
+ while (prev_insn)
+ {
+ if (GET_CODE (prev_insn) == NOTE)
+ ;
+
+ else if (GET_CODE (prev_insn) == INSN)
+ {
+ if (GET_CODE (PATTERN (prev_insn)) != SET)
+ return (0);
+
+ if (rtx_equal_p (SET_DEST (PATTERN (prev_insn)), reg_rtx))
+ {
+ if (sets_condition_code (SET_SRC (PATTERN (prev_insn))))
+ return (1);
+
+ return (0);
+ }
+
+ else if (! doesnt_set_condition_code (SET_SRC (PATTERN (prev_insn))))
+ return (0);
+ }
+
+ else
+ return (0);
+
+ prev_insn = PREV_INSN (prev_insn);
+ }
+
+ return (0);
+}
+
+int
+doesnt_set_condition_code (pat)
+ rtx pat;
+{
+ switch (GET_CODE (pat))
+ {
+ case MEM:
+ case REG:
+ return 1;
+
+ default:
+ return 0;
+
+ }
+}
+
+int
+sets_condition_code (pat)
+ rtx pat;
+{
+ switch (GET_CODE (pat))
+ {
+ case PLUS:
+ case MINUS:
+ case AND:
+ case IOR:
+ case XOR:
+ case NOT:
+ case NEG:
+ case MULT:
+ case DIV:
+ case MOD:
+ case UDIV:
+ case UMOD:
+ return 1;
+
+ default:
+ return (0);
+ }
+}
+
+int
+str_immediate_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) == CONST_INT && INTVAL (op) <= 32 && INTVAL (op) >= 0)
+ return 1;
+
+ return 0;
+}
+
+int
+is_fp_insn (insn)
+ rtx insn;
+{
+ if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
+ && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
+ || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
+ || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode))
+ return 1;
+
+ return 0;
+}
+
+/* Return 1 if the mode of the SET_DEST of insn is floating point
+ and it is not an fld or a move from memory to memory.
+ Otherwise return 0 */
+
+int
+is_fp_dest (insn)
+ rtx insn;
+{
+ if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
+ && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
+ || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
+ || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)
+ && GET_CODE (SET_DEST (PATTERN (insn))) == REG
+ && REGNO (SET_DEST (PATTERN (insn))) >= FIRST_FLOAT_REG
+ && GET_CODE (SET_SRC (PATTERN (insn))) != MEM)
+ return 1;
+
+ return 0;
+}
+
+/* Return 1 if the mode of the SET_DEST of INSN is floating point and is
+ memory and the source is a register. */
+
+int
+is_fp_store (insn)
+ rtx insn;
+{
+ if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
+ && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
+ || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
+ || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)
+ && GET_CODE (SET_DEST (PATTERN (insn))) == MEM
+ && GET_CODE (SET_SRC (PATTERN (insn))) == REG)
+ return 1;
+
+ return 0;
+}
+
+/* Return 1 if DEP_INSN sets a register which INSN uses as a base
+ or index to reference memory.
+ otherwise return 0 */
+
+int
+agi_dependent (insn, dep_insn)
+ rtx insn, dep_insn;
+{
+ if (GET_CODE (dep_insn) == INSN
+ && GET_CODE (PATTERN (dep_insn)) == SET
+ && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG)
+ return reg_mentioned_in_mem (SET_DEST (PATTERN (dep_insn)), insn);
+
+ if (GET_CODE (dep_insn) == INSN && GET_CODE (PATTERN (dep_insn)) == SET
+ && GET_CODE (SET_DEST (PATTERN (dep_insn))) == MEM
+ && push_operand (SET_DEST (PATTERN (dep_insn)),
+ GET_MODE (SET_DEST (PATTERN (dep_insn)))))
+ return reg_mentioned_in_mem (stack_pointer_rtx, insn);
+
+ return 0;
+}
+
+/* Return 1 if reg is used in rtl as a base or index for a memory ref
+ otherwise return 0. */
+
+int
+reg_mentioned_in_mem (reg, rtl)
+ rtx reg, rtl;
+{
+ register char *fmt;
+ register int i, j;
+ register enum rtx_code code;
+
+ if (rtl == NULL)
+ return 0;
+
+ code = GET_CODE (rtl);
+
+ switch (code)
+ {
+ case HIGH:
+ case CONST_INT:
+ case CONST:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case PC:
+ case CC0:
+ case SUBREG:
+ return 0;
+ default:
+ break;
+ }
+
+ if (code == MEM && reg_mentioned_p (reg, rtl))
+ return 1;
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'E')
+ {
+ for (j = XVECLEN (rtl, i) - 1; j >= 0; j--)
+ if (reg_mentioned_in_mem (reg, XVECEXP (rtl, i, j)))
+ return 1;
+ }
+
+ else if (fmt[i] == 'e' && reg_mentioned_in_mem (reg, XEXP (rtl, i)))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Output the appropriate insns for doing strlen if not just doing repnz; scasb
+
+ operands[0] = result, initialized with the startaddress
+ operands[1] = alignment of the address.
+ operands[2] = scratch register, initialized with the startaddress when
+ not aligned, otherwise undefined
+
+ This is just the body. It needs the initialisations mentioned above and
+ some address computing at the end. These things are done in i386.md. */
+
+char *
+output_strlen_unroll (operands)
+ rtx operands[];
+{
+ rtx xops[18];
+
+ xops[0] = operands[0]; /* Result */
+ /* operands[1]; * Alignment */
+ xops[1] = operands[2]; /* Scratch */
+ xops[2] = GEN_INT (0);
+ xops[3] = GEN_INT (2);
+ xops[4] = GEN_INT (3);
+ xops[5] = GEN_INT (4);
+ /* xops[6] = gen_label_rtx (); * label when aligned to 3-byte */
+ /* xops[7] = gen_label_rtx (); * label when aligned to 2-byte */
+ xops[8] = gen_label_rtx (); /* label of main loop */
+
+ if (TARGET_USE_Q_REG && QI_REG_P (xops[1]))
+ xops[9] = gen_label_rtx (); /* pentium optimisation */
+
+ xops[10] = gen_label_rtx (); /* end label 2 */
+ xops[11] = gen_label_rtx (); /* end label 1 */
+ xops[12] = gen_label_rtx (); /* end label */
+ /* xops[13] * Temporary used */
+ xops[14] = GEN_INT (0xff);
+ xops[15] = GEN_INT (0xff00);
+ xops[16] = GEN_INT (0xff0000);
+ xops[17] = GEN_INT (0xff000000);
+
+ /* Loop to check 1..3 bytes for null to get an aligned pointer. */
+
+ /* Is there a known alignment and is it less than 4? */
+ if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) < 4)
+ {
+ /* Is there a known alignment and is it not 2? */
+ if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
+ {
+ xops[6] = gen_label_rtx (); /* Label when aligned to 3-byte */
+ xops[7] = gen_label_rtx (); /* Label when aligned to 2-byte */
+
+ /* Leave just the 3 lower bits.
+ If this is a q-register, then the high part is used later
+ therefore use andl rather than andb. */
+ output_asm_insn (AS2 (and%L1,%4,%1), xops);
+
+ /* Is aligned to 4-byte address when zero */
+ output_asm_insn (AS1 (je,%l8), xops);
+
+ /* Side-effect even Parity when %eax == 3 */
+ output_asm_insn (AS1 (jp,%6), xops);
+
+ /* Is it aligned to 2 bytes ? */
+ if (QI_REG_P (xops[1]))
+ output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
+ else
+ output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
+
+ output_asm_insn (AS1 (je,%7), xops);
+ }
+ else
+ {
+ /* Since the alignment is 2, we have to check 2 or 0 bytes;
+ check if is aligned to 4 - byte. */
+ output_asm_insn (AS2 (and%L1,%3,%1), xops);
+
+ /* Is aligned to 4-byte address when zero */
+ output_asm_insn (AS1 (je,%l8), xops);
+ }
+
+ xops[13] = gen_rtx_MEM (QImode, xops[0]);
+
+ /* Now compare the bytes; compare with the high part of a q-reg
+ gives shorter code. */
+ if (QI_REG_P (xops[1]))
+ {
+ /* Compare the first n unaligned byte on a byte per byte basis. */
+ output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
+
+ /* When zero we reached the end. */
+ output_asm_insn (AS1 (je,%l12), xops);
+
+ /* Increment the address. */
+ output_asm_insn (AS1 (inc%L0,%0), xops);
+
+ /* Not needed with an alignment of 2 */
+ if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
+ {
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (xops[7]));
+ output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
+ output_asm_insn (AS1 (je,%l12), xops);
+ output_asm_insn (AS1 (inc%L0,%0), xops);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (xops[6]));
+ }
+
+ output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
+ }
+ else
+ {
+ output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
+ output_asm_insn (AS1 (je,%l12), xops);
+ output_asm_insn (AS1 (inc%L0,%0), xops);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (xops[7]));
+ output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
+ output_asm_insn (AS1 (je,%l12), xops);
+ output_asm_insn (AS1 (inc%L0,%0), xops);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (xops[6]));
+ output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
+ }
+
+ output_asm_insn (AS1 (je,%l12), xops);
+ output_asm_insn (AS1 (inc%L0,%0), xops);
+ }
+
+ /* Generate loop to check 4 bytes at a time. It is not a good idea to
+ align this loop. It gives only huge programs, but does not help to
+ speed up. */
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[8]));
+
+ xops[13] = gen_rtx_MEM (SImode, xops[0]);
+ output_asm_insn (AS2 (mov%L1,%13,%1), xops);
+
+ if (QI_REG_P (xops[1]))
+ {
+ /* On i586 it is faster to combine the hi- and lo- part as
+ a kind of lookahead. If anding both yields zero, then one
+ of both *could* be zero, otherwise none of both is zero;
+ this saves one instruction, on i486 this is slower
+ tested with P-90, i486DX2-66, AMD486DX2-66 */
+ if (TARGET_PENTIUM)
+ {
+ output_asm_insn (AS2 (test%B1,%h1,%b1), xops);
+ output_asm_insn (AS1 (jne,%l9), xops);
+ }
+
+ /* Check first byte. */
+ output_asm_insn (AS2 (test%B1,%b1,%b1), xops);
+ output_asm_insn (AS1 (je,%l12), xops);
+
+ /* Check second byte. */
+ output_asm_insn (AS2 (test%B1,%h1,%h1), xops);
+ output_asm_insn (AS1 (je,%l11), xops);
+
+ if (TARGET_PENTIUM)
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+ CODE_LABEL_NUMBER (xops[9]));
+ }
+
+ else
+ {
+ /* Check first byte. */
+ output_asm_insn (AS2 (test%L1,%14,%1), xops);
+ output_asm_insn (AS1 (je,%l12), xops);
+
+ /* Check second byte. */
+ output_asm_insn (AS2 (test%L1,%15,%1), xops);
+ output_asm_insn (AS1 (je,%l11), xops);
+ }
+
+ /* Check third byte. */
+ output_asm_insn (AS2 (test%L1,%16,%1), xops);
+ output_asm_insn (AS1 (je,%l10), xops);
+
+ /* Check fourth byte and increment address. */
+ output_asm_insn (AS2 (add%L0,%5,%0), xops);
+ output_asm_insn (AS2 (test%L1,%17,%1), xops);
+ output_asm_insn (AS1 (jne,%l8), xops);
+
+ /* Now generate fixups when the compare stops within a 4-byte word. */
+ output_asm_insn (AS2 (sub%L0,%4,%0), xops);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[10]));
+ output_asm_insn (AS1 (inc%L0,%0), xops);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[11]));
+ output_asm_insn (AS1 (inc%L0,%0), xops);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[12]));
+
+ return "";
+}
+
+char *
+output_fp_conditional_move (which_alternative, operands)
+ int which_alternative;
+ rtx operands[];
+{
+ switch (which_alternative)
+ {
+ case 0:
+ /* r <- cond ? arg : r */
+ output_asm_insn (AS2 (fcmov%F1,%2,%0), operands);
+ break;
+
+ case 1:
+ /* r <- cond ? r : arg */
+ output_asm_insn (AS2 (fcmov%f1,%3,%0), operands);
+ break;
+
+ default:
+ abort ();
+ }
+
+ return "";
+}
+
+char *
+output_int_conditional_move (which_alternative, operands)
+ int which_alternative;
+ rtx operands[];
+{
+ int code = GET_CODE (operands[1]);
+ enum machine_mode mode;
+ rtx xops[4];
+
+ /* This is very tricky. We have to do it right. For a code segement
+ like:
+
+ int foo, bar;
+ ....
+ foo = foo - x;
+ if (foo >= 0)
+ bar = y;
+
+ final_scan_insn () may delete the insn which sets CC. We have to
+ tell final_scan_insn () if it should be reinserted. When CODE is
+ GT or LE, we have to check the CC_NO_OVERFLOW bit and return
+ NULL_PTR to tell final to reinsert the test insn because the
+ conditional move cannot be handled properly without it. */
+ if ((code == GT || code == LE)
+ && (cc_prev_status.flags & CC_NO_OVERFLOW))
+ return NULL_PTR;
+
+ mode = GET_MODE (operands [0]);
+ if (mode == DImode)
+ {
+ xops [0] = gen_rtx_SUBREG (SImode, operands [0], 1);
+ xops [1] = operands [1];
+ xops [2] = gen_rtx_SUBREG (SImode, operands [2], 1);
+ xops [3] = gen_rtx_SUBREG (SImode, operands [3], 1);
+ }
+
+ switch (which_alternative)
+ {
+ case 0:
+ /* r <- cond ? arg : r */
+ output_asm_insn (AS2 (cmov%C1,%2,%0), operands);
+ if (mode == DImode)
+ output_asm_insn (AS2 (cmov%C1,%2,%0), xops);
+ break;
+
+ case 1:
+ /* r <- cond ? r : arg */
+ output_asm_insn (AS2 (cmov%c1,%3,%0), operands);
+ if (mode == DImode)
+ output_asm_insn (AS2 (cmov%c1,%3,%0), xops);
+ break;
+
+ default:
+ abort ();
+ }
+
+ return "";
+}
diff --git a/contrib/gcc/config/i386/i386.h b/contrib/gcc/config/i386/i386.h
index b00b0e5..b8fef11 100644
--- a/contrib/gcc/config/i386/i386.h
+++ b/contrib/gcc/config/i386/i386.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler for Intel X86
(386, 486, Pentium).
- Copyright (C) 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1988, 92, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -17,8 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
+Boston, MA 02111-1307, USA. */
/* The purpose of this file is to define the characteristics of the i386,
independent of assembler syntax or operating system.
@@ -53,6 +52,20 @@ Boston, MA 02111-1307, USA. */
#define HALF_PIC_FINISH(STREAM)
#endif
+/* Define the specific costs for a given cpu */
+
+struct processor_costs {
+ int add; /* cost of an add instruction */
+ int lea; /* cost of a lea instruction */
+ int shift_var; /* variable shift costs */
+ int shift_const; /* constant shift costs */
+ int mult_init; /* cost of starting a multiply */
+ int mult_bit; /* cost of multiply per each bit set */
+ int divide; /* cost of a divide/mod */
+};
+
+extern struct processor_costs *ix86_cost;
+
/* Run-time compilation parameters selecting different hardware subsets. */
extern int target_flags;
@@ -66,20 +79,23 @@ extern int target_flags;
/* Masks for the -m switches */
#define MASK_80387 000000000001 /* Hardware floating point */
-#define MASK_486 000000000002 /* 80486 specific */
-#define MASK_NOTUSED1 000000000004 /* bit not currently used */
+#define MASK_NOTUSED1 000000000002 /* bit not currently used */
+#define MASK_NOTUSED2 000000000004 /* bit not currently used */
#define MASK_RTD 000000000010 /* Use ret that pops args */
#define MASK_ALIGN_DOUBLE 000000000020 /* align doubles to 2 word boundary */
#define MASK_SVR3_SHLIB 000000000040 /* Uninit locals into bss */
#define MASK_IEEE_FP 000000000100 /* IEEE fp comparisons */
#define MASK_FLOAT_RETURNS 000000000200 /* Return float in st(0) */
#define MASK_NO_FANCY_MATH_387 000000000400 /* Disable sin, cos, sqrt */
-
+#define MASK_OMIT_LEAF_FRAME_POINTER 0x00000800 /* omit leaf frame pointers */
/* Temporary codegen switches */
#define MASK_DEBUG_ADDR 000001000000 /* Debug GO_IF_LEGITIMATE_ADDRESS */
#define MASK_NO_WIDE_MULTIPLY 000002000000 /* Disable 32x32->64 multiplies */
#define MASK_NO_MOVE 000004000000 /* Don't generate mem->mem */
-#define MASK_DEBUG_ARG 000010000000 /* Debug function_arg */
+#define MASK_NO_PSEUDO 000010000000 /* Move op's args -> pseudos */
+#define MASK_DEBUG_ARG 000020000000 /* Debug function_arg */
+#define MASK_SCHEDULE_PROLOGUE 000040000000 /* Emit prologue as rtl */
+#define MASK_STACK_PROBE 000100000000 /* Enable stack probing */
/* Use the floating point instructions */
#define TARGET_80387 (target_flags & MASK_80387)
@@ -112,6 +128,9 @@ extern int target_flags;
This is because FreeBSD lacks these in the math-emulator-code */
#define TARGET_NO_FANCY_MATH_387 (target_flags & MASK_NO_FANCY_MATH_387)
+/* Don't create frame pointers for leaf functions */
+#define TARGET_OMIT_LEAF_FRAME_POINTER (target_flags & MASK_OMIT_LEAF_FRAME_POINTER)
+
/* Temporary switches for tuning code generation */
/* Disable 32x32->64 bit multiplies that are used for long long multiplies
@@ -119,6 +138,9 @@ extern int target_flags;
#define TARGET_NO_WIDE_MULTIPLY (target_flags & MASK_NO_WIDE_MULTIPLY)
#define TARGET_WIDE_MULTIPLY (!TARGET_NO_WIDE_MULTIPLY)
+/* Emit/Don't emit prologue as rtl */
+#define TARGET_SCHEDULE_PROLOGUE (target_flags & MASK_SCHEDULE_PROLOGUE)
+
/* Debug GO_IF_LEGITIMATE_ADDRESS */
#define TARGET_DEBUG_ADDR (target_flags & MASK_DEBUG_ADDR)
@@ -127,10 +149,25 @@ extern int target_flags;
/* Hack macros for tuning code generation */
#define TARGET_MOVE ((target_flags & MASK_NO_MOVE) == 0) /* Don't generate memory->memory */
-
-/* Specific hardware switches */
-#define TARGET_486 (target_flags & MASK_486) /* 80486DX, 80486SX, 80486DX[24] */
-#define TARGET_386 (!TARGET_486) /* 80386 */
+#define TARGET_PSEUDO ((target_flags & MASK_NO_PSEUDO) == 0) /* Move op's args into pseudos */
+
+#define TARGET_386 (ix86_cpu == PROCESSOR_I386)
+#define TARGET_486 (ix86_cpu == PROCESSOR_I486)
+#define TARGET_PENTIUM (ix86_cpu == PROCESSOR_PENTIUM)
+#define TARGET_PENTIUMPRO (ix86_cpu == PROCESSOR_PENTIUMPRO)
+#define TARGET_USE_LEAVE (ix86_cpu == PROCESSOR_I386)
+#define TARGET_PUSH_MEMORY (ix86_cpu == PROCESSOR_I386)
+#define TARGET_ZERO_EXTEND_WITH_AND (ix86_cpu != PROCESSOR_I386 \
+ && ix86_cpu != PROCESSOR_PENTIUMPRO)
+#define TARGET_DOUBLE_WITH_ADD (ix86_cpu != PROCESSOR_I386)
+#define TARGET_USE_BIT_TEST (ix86_cpu == PROCESSOR_I386)
+#define TARGET_UNROLL_STRLEN (ix86_cpu != PROCESSOR_I386)
+#define TARGET_USE_Q_REG (ix86_cpu == PROCESSOR_PENTIUM \
+ || ix86_cpu == PROCESSOR_PENTIUMPRO)
+#define TARGET_USE_ANY_REG (ix86_cpu == PROCESSOR_I486)
+#define TARGET_CMOVE (ix86_arch == PROCESSOR_PENTIUMPRO)
+#define TARGET_DEEP_BRANCH_PREDICTION (ix86_cpu == PROCESSOR_PENTIUMPRO)
+#define TARGET_STACK_PROBE (target_flags & MASK_STACK_PROBE)
#define TARGET_SWITCHES \
{ { "80387", MASK_80387 }, \
@@ -138,10 +175,12 @@ extern int target_flags;
{ "hard-float", MASK_80387 }, \
{ "soft-float", -MASK_80387 }, \
{ "no-soft-float", MASK_80387 }, \
- { "386", -MASK_486 }, \
- { "no-386", MASK_486 }, \
- { "486", MASK_486 }, \
- { "no-486", -MASK_486 }, \
+ { "386", 0 }, \
+ { "no-386", 0 }, \
+ { "486", 0 }, \
+ { "no-486", 0 }, \
+ { "pentium", 0 }, \
+ { "pentiumpro", 0 }, \
{ "rtd", MASK_RTD }, \
{ "no-rtd", -MASK_RTD }, \
{ "align-double", MASK_ALIGN_DOUBLE }, \
@@ -154,16 +193,62 @@ extern int target_flags;
{ "no-fp-ret-in-387", -MASK_FLOAT_RETURNS }, \
{ "no-fancy-math-387", MASK_NO_FANCY_MATH_387 }, \
{ "fancy-math-387", -MASK_NO_FANCY_MATH_387 }, \
+ { "omit-leaf-frame-pointer", MASK_OMIT_LEAF_FRAME_POINTER }, \
+ { "no-omit-leaf-frame-pointer",-MASK_OMIT_LEAF_FRAME_POINTER }, \
{ "no-wide-multiply", MASK_NO_WIDE_MULTIPLY }, \
{ "wide-multiply", -MASK_NO_WIDE_MULTIPLY }, \
+ { "schedule-prologue", MASK_SCHEDULE_PROLOGUE }, \
+ { "no-schedule-prologue", -MASK_SCHEDULE_PROLOGUE }, \
{ "debug-addr", MASK_DEBUG_ADDR }, \
{ "no-debug-addr", -MASK_DEBUG_ADDR }, \
{ "move", -MASK_NO_MOVE }, \
{ "no-move", MASK_NO_MOVE }, \
{ "debug-arg", MASK_DEBUG_ARG }, \
{ "no-debug-arg", -MASK_DEBUG_ARG }, \
+ { "stack-arg-probe", MASK_STACK_PROBE }, \
+ { "no-stack-arg-probe", -MASK_STACK_PROBE }, \
+ { "windows", 0 }, \
+ { "dll", 0 }, \
SUBTARGET_SWITCHES \
- { "", TARGET_DEFAULT | TARGET_CPU_DEFAULT}}
+ { "", MASK_SCHEDULE_PROLOGUE | TARGET_DEFAULT}}
+
+/* Which processor to schedule for. The cpu attribute defines a list that
+ mirrors this list, so changes to i386.md must be made at the same time. */
+
+enum processor_type
+ {PROCESSOR_I386, /* 80386 */
+ PROCESSOR_I486, /* 80486DX, 80486SX, 80486DX[24] */
+ PROCESSOR_PENTIUM,
+ PROCESSOR_PENTIUMPRO};
+
+#define PROCESSOR_I386_STRING "i386"
+#define PROCESSOR_I486_STRING "i486"
+#define PROCESSOR_I586_STRING "i586"
+#define PROCESSOR_PENTIUM_STRING "pentium"
+#define PROCESSOR_I686_STRING "i686"
+#define PROCESSOR_PENTIUMPRO_STRING "pentiumpro"
+
+extern enum processor_type ix86_cpu;
+
+extern int ix86_arch;
+
+/* Define the default processor. This is overridden by other tm.h files. */
+#define PROCESSOR_DEFAULT \
+ ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_I486) \
+ ? PROCESSOR_I486 \
+ : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUM) \
+ ? PROCESSOR_PENTIUM \
+ : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUMPRO) \
+ ? PROCESSOR_PENTIUMPRO \
+ : PROCESSOR_I386
+#define PROCESSOR_DEFAULT_STRING \
+ ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_I486) \
+ ? PROCESSOR_I486_STRING \
+ : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUM) \
+ ? PROCESSOR_PENTIUM_STRING \
+ : ((enum processor_type) TARGET_CPU_DEFAULT == PROCESSOR_PENTIUMPRO) \
+ ? PROCESSOR_PENTIUMPRO_STRING \
+ : PROCESSOR_I386_STRING
/* This macro is similar to `TARGET_SWITCHES' but defines names of
command options that have values. Its definition is an
@@ -175,11 +260,14 @@ extern int target_flags;
option if the fixed part matches. The actual option name is made
by appending `-m' to the specified name. */
#define TARGET_OPTIONS \
-{ { "reg-alloc=", &i386_reg_alloc_order }, \
+{ { "cpu=", &ix86_cpu_string}, \
+ { "arch=", &ix86_arch_string}, \
+ { "reg-alloc=", &i386_reg_alloc_order }, \
{ "regparm=", &i386_regparm_string }, \
{ "align-loops=", &i386_align_loops_string }, \
{ "align-jumps=", &i386_align_jumps_string }, \
{ "align-functions=", &i386_align_funcs_string }, \
+ { "branch-cost=", &i386_branch_cost_string }, \
SUBTARGET_OPTIONS \
}
@@ -198,6 +286,82 @@ extern int target_flags;
#define SUBTARGET_SWITCHES
#define SUBTARGET_OPTIONS
+/* Define this to change the optimizations performed by default. */
+#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) optimization_options(LEVEL,SIZE)
+
+/* Specs for the compiler proper */
+
+#ifndef CC1_CPU_SPEC
+#define CC1_CPU_SPEC "\
+%{!mcpu*: \
+%{m386:-mcpu=i386 -march=i386} \
+%{mno-486:-mcpu=i386 -march=i386} \
+%{m486:-mcpu=i486 -march=i486} \
+%{mno-386:-mcpu=i486 -march=i486} \
+%{mno-pentium:-mcpu=i486 -march=i486} \
+%{mpentium:-mcpu=pentium} \
+%{mno-pentiumpro:-mcpu=pentium} \
+%{mpentiumpro:-mcpu=pentiumpro}}"
+#endif
+
+#define CPP_486_SPEC "%{!ansi:-Di486} -D__i486 -D__i486__"
+#define CPP_586_SPEC "%{!ansi:-Di586 -Dpentium} \
+ -D__i586 -D__i586__ -D__pentium -D__pentium__"
+#define CPP_686_SPEC "%{!ansi:-Di686 -Dpentiumpro} \
+ -D__i686 -D__i686__ -D__pentiumpro -D__pentiumpro__"
+
+#ifndef CPP_CPU_DEFAULT_SPEC
+#if TARGET_CPU_DEFAULT == 1
+#define CPP_CPU_DEFAULT_SPEC "%(cpp_486)"
+#else
+#if TARGET_CPU_DEFAULT == 2
+#define CPP_CPU_DEFAULT_SPEC "%(cpp_586)"
+#else
+#if TARGET_CPU_DEFAULT == 3
+#define CPP_CPU_DEFAULT_SPEC "%(cpp_686)"
+#else
+#define CPP_CPU_DEFAULT_SPEC ""
+#endif
+#endif
+#endif
+#endif /* CPP_CPU_DEFAULT_SPEC */
+
+#ifndef CPP_CPU_SPEC
+#define CPP_CPU_SPEC "\
+-Asystem(unix) -Acpu(i386) -Amachine(i386) \
+%{!ansi:-Di386} -D__i386 -D__i386__ \
+%{mcpu=i486:%(cpp_486)} %{m486:%(cpp_486)} \
+%{mpentium:%(cpp_586)} %{mcpu=pentium:%(cpp_586)} \
+%{mpentiumpro:%(cpp_686)} %{mcpu=pentiumpro:%(cpp_686)} \
+%{!mcpu*:%{!m486:%{!mpentium*:%(cpp_cpu_default)}}}"
+#endif
+
+#ifndef CC1_SPEC
+#define CC1_SPEC "%(cc1_spec) "
+#endif
+
+/* This macro defines names of additional specifications to put in the
+ specs that can be used in various specifications like CC1_SPEC. Its
+ definition is an initializer with a subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the
+ specification name, and a string constant that used by the GNU CC driver
+ program.
+
+ Do not define this macro if it does not need to do anything. */
+
+#ifndef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS
+#endif
+
+#define EXTRA_SPECS \
+ { "cpp_486", CPP_486_SPEC}, \
+ { "cpp_586", CPP_586_SPEC}, \
+ { "cpp_686", CPP_686_SPEC}, \
+ { "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \
+ { "cpp_cpu", CPP_CPU_SPEC }, \
+ { "cc1_cpu", CC1_CPU_SPEC }, \
+ SUBTARGET_EXTRA_SPECS
/* target machine storage layout */
@@ -265,6 +429,79 @@ extern int target_flags;
aligned on 64 bit boundaries. */
#define BIGGEST_ALIGNMENT (TARGET_ALIGN_DOUBLE ? 64 : 32)
+/* If defined, a C expression to compute the alignment given to a
+ constant that is being placed in memory. CONSTANT is the constant
+ and ALIGN is the alignment that the object would ordinarily have.
+ The value of this macro is used instead of that alignment to align
+ the object.
+
+ If this macro is not defined, then ALIGN is used.
+
+ The typical use of this macro is to increase alignment for string
+ constants to be word aligned so that `strcpy' calls that copy
+ constants can be done inline. */
+
+#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
+ (TREE_CODE (EXP) == REAL_CST \
+ ? ((TYPE_MODE (TREE_TYPE (EXP)) == DFmode && (ALIGN) < 64) \
+ ? 64 \
+ : (TYPE_MODE (TREE_TYPE (EXP)) == XFmode && (ALIGN) < 128) \
+ ? 128 \
+ : (ALIGN)) \
+ : TREE_CODE (EXP) == STRING_CST \
+ ? ((TREE_STRING_LENGTH (EXP) >= 31 && (ALIGN) < 256) \
+ ? 256 \
+ : (ALIGN)) \
+ : (ALIGN))
+
+/* If defined, a C expression to compute the alignment for a static
+ variable. TYPE is the data type, and ALIGN is the alignment that
+ the object would ordinarily have. The value of this macro is used
+ instead of that alignment to align the object.
+
+ If this macro is not defined, then ALIGN is used.
+
+ One use of this macro is to increase alignment of medium-size
+ data to make it all fit in fewer cache lines. Another is to
+ cause character arrays to be word-aligned so that `strcpy' calls
+ that copy constants to character arrays can be done inline. */
+
+#define DATA_ALIGNMENT(TYPE, ALIGN) \
+ ((AGGREGATE_TYPE_P (TYPE) \
+ && TYPE_SIZE (TYPE) \
+ && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \
+ && (TREE_INT_CST_LOW (TYPE_SIZE (TYPE)) >= 256 \
+ || TREE_INT_CST_HIGH (TYPE_SIZE (TYPE))) && (ALIGN) < 256) \
+ ? 256 \
+ : TREE_CODE (TYPE) == ARRAY_TYPE \
+ ? ((TYPE_MODE (TREE_TYPE (TYPE)) == DFmode && (ALIGN) < 64) \
+ ? 64 \
+ : (TYPE_MODE (TREE_TYPE (TYPE)) == XFmode && (ALIGN) < 128) \
+ ? 128 \
+ : (ALIGN)) \
+ : TREE_CODE (TYPE) == COMPLEX_TYPE \
+ ? ((TYPE_MODE (TYPE) == DCmode && (ALIGN) < 64) \
+ ? 64 \
+ : (TYPE_MODE (TYPE) == XCmode && (ALIGN) < 128) \
+ ? 128 \
+ : (ALIGN)) \
+ : ((TREE_CODE (TYPE) == RECORD_TYPE \
+ || TREE_CODE (TYPE) == UNION_TYPE \
+ || TREE_CODE (TYPE) == QUAL_UNION_TYPE) \
+ && TYPE_FIELDS (TYPE)) \
+ ? ((DECL_MODE (TYPE_FIELDS (TYPE)) == DFmode && (ALIGN) < 64) \
+ ? 64 \
+ : (DECL_MODE (TYPE_FIELDS (TYPE)) == XFmode && (ALIGN) < 128) \
+ ? 128 \
+ : (ALIGN)) \
+ : TREE_CODE (TYPE) == REAL_TYPE \
+ ? ((TYPE_MODE (TYPE) == DFmode && (ALIGN) < 64) \
+ ? 64 \
+ : (TYPE_MODE (TYPE) == XFmode && (ALIGN) < 128) \
+ ? 128 \
+ : (ALIGN)) \
+ : (ALIGN))
+
/* Set this non-zero if move instructions will actually fail to work
when given unaligned data. */
#define STRICT_ALIGNMENT 0
@@ -278,12 +515,14 @@ extern int target_flags;
#define MAX_CODE_ALIGN 6 /* 64 byte alignment */
/* Align loop starts for optimal branching. */
-#define ASM_OUTPUT_LOOP_ALIGN(FILE) ASM_OUTPUT_ALIGN (FILE, i386_align_loops)
+#define LOOP_ALIGN(LABEL) (i386_align_loops)
+#define LOOP_ALIGN_MAX_SKIP (i386_align_loops_string ? 0 : 7)
/* This is how to align an instruction for optimal branching.
On i486 we'll get better performance by aligning on a
cache line (i.e. 16 byte) boundary. */
-#define ASM_OUTPUT_ALIGN_CODE(FILE) ASM_OUTPUT_ALIGN ((FILE), i386_align_jumps)
+#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (i386_align_jumps)
+#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP (i386_align_jumps_string ? 0 : 7)
/* Standard register usage. */
@@ -292,6 +531,7 @@ extern int target_flags;
for details. */
#define STACK_REGS
+#define IS_STACK_MODE(mode) (mode==DFmode || mode==SFmode || mode==XFmode)
/* Number of actual hardware registers.
The hardware registers are assigned numbers for the compiler
@@ -409,31 +649,23 @@ extern int target_flags;
for cross-compiler testing. */
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
- ((REGNO) < 2 ? 1 \
- : (REGNO) < 4 ? 1 \
+ ((REGNO) < 4 ? 1 \
: FP_REGNO_P (REGNO) \
? (((int) GET_MODE_CLASS (MODE) == (int) MODE_FLOAT \
|| (int) GET_MODE_CLASS (MODE) == (int) MODE_COMPLEX_FLOAT) \
- && GET_MODE_UNIT_SIZE (MODE) <= 12) \
- : (int) (MODE) != (int) QImode)
+ && GET_MODE_UNIT_SIZE (MODE) <= (LONG_DOUBLE_TYPE_SIZE == 96 ? 12 : 8))\
+ : (int) (MODE) != (int) QImode ? 1 \
+ : (reload_in_progress | reload_completed) == 1)
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
for any hard reg, then this must be 0 for correct output. */
-#define MODES_TIEABLE_P(MODE1, MODE2) ((MODE1) == (MODE2))
-
-/* A C expression returning the cost of moving data from a register of class
- CLASS1 to one of CLASS2.
-
- On the i386, copying between floating-point and fixed-point
- registers is expensive. */
-
-#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
- (((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2)) \
- || (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2))) ? 10 \
- : 2)
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ ((MODE1) == (MODE2) \
+ || ((MODE1) == SImode && (MODE2) == HImode \
+ || (MODE1) == HImode && (MODE2) == SImode))
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
@@ -459,7 +691,7 @@ extern int target_flags;
Zero means the frame pointer need not be set up (and parms
may be accessed via the stack pointer) in functions that seem suitable.
This is computed in `reload', in reload1.c. */
-#define FRAME_POINTER_REQUIRED 0
+#define FRAME_POINTER_REQUIRED (TARGET_OMIT_LEAF_FRAME_POINTER && !leaf_function_p ())
/* Base register for access to arguments of the function. */
#define ARG_POINTER_REGNUM 16
@@ -562,16 +794,16 @@ enum reg_class
of length N_REG_CLASSES. */
#define REG_CLASS_CONTENTS \
-{ 0, \
- 0x1, 0x2, 0x4, 0x8, /* AREG, DREG, CREG, BREG */ \
- 0x3, /* AD_REGS */ \
- 0xf, /* Q_REGS */ \
- 0x10, 0x20, /* SIREG, DIREG */ \
- 0x07f, /* INDEX_REGS */ \
- 0x100ff, /* GENERAL_REGS */ \
- 0x0100, 0x0200, /* FP_TOP_REG, FP_SECOND_REG */ \
- 0xff00, /* FLOAT_REGS */ \
- 0x1ffff }
+{ {0}, \
+ {0x1}, {0x2}, {0x4}, {0x8}, /* AREG, DREG, CREG, BREG */ \
+ {0x3}, /* AD_REGS */ \
+ {0xf}, /* Q_REGS */ \
+ {0x10}, {0x20}, /* SIREG, DIREG */ \
+ {0x7f}, /* INDEX_REGS */ \
+ {0x100ff}, /* GENERAL_REGS */ \
+ {0x0100}, {0x0200}, /* FP_TOP_REG, FP_SECOND_REG */ \
+ {0xff00}, /* FLOAT_REGS */ \
+ {0x1ffff}}
/* The same information, inverted:
Return the class number of the smallest class containing
@@ -584,7 +816,7 @@ enum reg_class
rtl to be used as spill registers but prevents the compiler from
extending the lifetime of these registers. */
-#define SMALL_REGISTER_CLASSES
+#define SMALL_REGISTER_CLASSES 1
#define QI_REG_P(X) \
(REG_P (X) && REGNO (X) < 4)
@@ -658,15 +890,25 @@ enum reg_class
(C) == 'L' ? (VALUE) == 0xffff : \
(C) == 'M' ? (VALUE) >= 0 && (VALUE) <= 3 : \
(C) == 'N' ? (VALUE) >= 0 && (VALUE) <= 255 :\
+ (C) == 'O' ? (VALUE) >= 0 && (VALUE) <= 32 : \
0)
/* Similar, but for floating constants, and defining letters G and H.
Here VALUE is the CONST_DOUBLE rtx itself. We allow constants even if
TARGET_387 isn't set, because the stack register converter may need to
- load 0.0 into the function value register. */
+ load 0.0 into the function value register.
+
+ We disallow these constants when -fomit-frame-pointer and compiling
+ PIC code since reload might need to force the constant to memory.
+ Forcing the constant to memory changes the elimination offsets after
+ the point where they must stay constant.
+
+ However, we must allow them after reload as completed as reg-stack.c
+ will create insns which use these constants. */
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
- ((C) == 'G' ? standard_80387_constant_p (VALUE) : 0)
+ (((reload_completed || !flag_pic || !flag_omit_frame_pointer) && (C) == 'G') \
+ ? standard_80387_constant_p (VALUE) : 0)
/* Place additional restrictions on the register class to use when it
is necessary to be able to hold a value of mode MODE in a reload
@@ -791,14 +1033,14 @@ enum reg_class
If the precise function being called is known, FUNC is its FUNCTION_DECL;
otherwise, FUNC is 0. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
- gen_rtx (REG, TYPE_MODE (VALTYPE), \
+ gen_rtx_REG (TYPE_MODE (VALTYPE), \
VALUE_REGNO (TYPE_MODE (VALTYPE)))
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
#define LIBCALL_VALUE(MODE) \
- gen_rtx (REG, MODE, VALUE_REGNO (MODE))
+ gen_rtx_REG (MODE, VALUE_REGNO (MODE))
/* Define the size of the result block used for communication between
untyped_call and untyped_return. The block contains a DImode value
@@ -825,7 +1067,7 @@ typedef struct i386_args {
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0. */
-#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME) \
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT) \
(init_cumulative_args (&CUM, FNTYPE, LIBNAME))
/* Update the data in CUM to advance over an argument
@@ -858,6 +1100,14 @@ typedef struct i386_args {
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
(function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED))
+/* This macro is invoked just before the start of a function.
+ It is used here to output code for -fpic that will load the
+ return address into %ebx. */
+
+#undef ASM_OUTPUT_FUNCTION_PREFIX
+#define ASM_OUTPUT_FUNCTION_PREFIX(FILE, FNNAME) \
+ asm_output_function_prefix (FILE, FNNAME)
+
/* This macro generates the assembly code for function entry.
FILE is a stdio stream to output the code to.
SIZE is an int: how many units of temporary storage to allocate.
@@ -887,27 +1137,94 @@ typedef struct i386_args {
} \
}
-/* A C statement or compound statement to output to FILE some
- assembler code to initialize basic-block profiling for the current
- object module. This code should call the subroutine
- `__bb_init_func' once per object module, passing it as its sole
- argument the address of a block allocated in the object module.
- The name of the block is a local symbol made with this statement:
+/* There are three profiling modes for basic blocks available.
+ The modes are selected at compile time by using the options
+ -a or -ax of the gnu compiler.
+ The variable `profile_block_flag' will be set according to the
+ selected option.
+
+ profile_block_flag == 0, no option used:
+
+ No profiling done.
+
+ profile_block_flag == 1, -a option used.
+
+ Count frequency of execution of every basic block.
+
+ profile_block_flag == 2, -ax option used.
+
+ Generate code to allow several different profiling modes at run time.
+ Available modes are:
+ Produce a trace of all basic blocks.
+ Count frequency of jump instructions executed.
+ In every mode it is possible to start profiling upon entering
+ certain functions and to disable profiling of some other functions.
+
+ The result of basic-block profiling will be written to a file `bb.out'.
+ If the -ax option is used parameters for the profiling will be read
+ from file `bb.in'.
+
+*/
+
+/* The following macro shall output assembler code to FILE
+ to initialize basic-block profiling.
+
+ If profile_block_flag == 2
+
+ Output code to call the subroutine `__bb_init_trace_func'
+ and pass two parameters to it. The first parameter is
+ the address of a block allocated in the object module.
+ The second parameter is the number of the first basic block
+ of the function.
+
+ The name of the block is a local symbol made with this statement:
+
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result.
+
+ The number of the first basic block of the function is
+ passed to the macro in BLOCK_OR_LABEL.
+
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ parameter1 <- LPBX0
+ parameter2 <- BLOCK_OR_LABEL
+ call __bb_init_trace_func
+
+ else if profile_block_flag != 0
+
+ Output code to call the subroutine `__bb_init_func'
+ and pass one single parameter to it, which is the same
+ as the first parameter to `__bb_init_trace_func'.
- ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+ The first word of this parameter is a flag which will be nonzero if
+ the object module has already been initialized. So test this word
+ first, and do not call `__bb_init_func' if the flag is nonzero.
+ Note: When profile_block_flag == 2 the test need not be done
+ but `__bb_init_trace_func' *must* be called.
- Of course, since you are writing the definition of
- `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
- can take a short cut in the definition of this macro and use the
- name that you know will result.
+ BLOCK_OR_LABEL may be used to generate a label number as a
+ branch destination in case `__bb_init_func' will not be called.
- The first word of this block is a flag which will be nonzero if the
- object module has already been initialized. So test this word
- first, and do not call `__bb_init_func' if the flag is nonzero. */
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ cmp (LPBX0),0
+ jne local_label
+ parameter1 <- LPBX0
+ call __bb_init_func
+local_label:
+
+*/
#undef FUNCTION_BLOCK_PROFILER
-#define FUNCTION_BLOCK_PROFILER(STREAM, LABELNO) \
+#define FUNCTION_BLOCK_PROFILER(FILE, BLOCK_OR_LABEL) \
do \
{ \
static int num_func = 0; \
@@ -915,74 +1232,264 @@ do \
char block_table[80], false_label[80]; \
\
ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); \
- ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func); \
\
- xops[0] = const0_rtx; \
- xops[1] = gen_rtx (SYMBOL_REF, VOIDmode, block_table); \
- xops[2] = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, VOIDmode, false_label)); \
- xops[3] = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, VOIDmode, "__bb_init_func")); \
- xops[4] = gen_rtx (MEM, Pmode, xops[1]); \
+ xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table); \
xops[5] = stack_pointer_rtx; \
- xops[6] = GEN_INT (4); \
- xops[7] = gen_rtx (REG, Pmode, 0); /* eax */ \
+ xops[7] = gen_rtx_REG (Pmode, 0); /* eax */ \
\
CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; \
- CONSTANT_POOL_ADDRESS_P (xops[2]) = TRUE; \
- \
- output_asm_insn (AS2(cmp%L4,%0,%4), xops); \
- output_asm_insn (AS1(jne,%2), xops); \
\
- if (!flag_pic) \
- output_asm_insn (AS1(push%L1,%1), xops); \
- else \
+ switch (profile_block_flag) \
{ \
- output_asm_insn (AS2 (lea%L7,%a1,%7), xops); \
- output_asm_insn (AS1 (push%L7,%7), xops); \
- } \
\
- output_asm_insn (AS1(call,%P3), xops); \
- output_asm_insn (AS2(add%L0,%6,%5), xops); \
- ASM_OUTPUT_INTERNAL_LABEL (STREAM, "LPBZ", num_func); \
- num_func++; \
+ case 2: \
+ \
+ xops[2] = GEN_INT ((BLOCK_OR_LABEL)); \
+ xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_trace_func")); \
+ xops[6] = GEN_INT (8); \
+ \
+ output_asm_insn (AS1(push%L2,%2), xops); \
+ if (!flag_pic) \
+ output_asm_insn (AS1(push%L1,%1), xops); \
+ else \
+ { \
+ output_asm_insn (AS2 (lea%L7,%a1,%7), xops); \
+ output_asm_insn (AS1 (push%L7,%7), xops); \
+ } \
+ \
+ output_asm_insn (AS1(call,%P3), xops); \
+ output_asm_insn (AS2(add%L0,%6,%5), xops); \
+ \
+ break; \
+ \
+ default: \
+ \
+ ASM_GENERATE_INTERNAL_LABEL (false_label, "LPBZ", num_func); \
+ \
+ xops[0] = const0_rtx; \
+ xops[2] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, false_label)); \
+ xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_init_func")); \
+ xops[4] = gen_rtx_MEM (Pmode, xops[1]); \
+ xops[6] = GEN_INT (4); \
+ \
+ CONSTANT_POOL_ADDRESS_P (xops[2]) = TRUE; \
+ \
+ output_asm_insn (AS2(cmp%L4,%0,%4), xops); \
+ output_asm_insn (AS1(jne,%2), xops); \
+ \
+ if (!flag_pic) \
+ output_asm_insn (AS1(push%L1,%1), xops); \
+ else \
+ { \
+ output_asm_insn (AS2 (lea%L7,%a1,%7), xops); \
+ output_asm_insn (AS1 (push%L7,%7), xops); \
+ } \
+ \
+ output_asm_insn (AS1(call,%P3), xops); \
+ output_asm_insn (AS2(add%L0,%6,%5), xops); \
+ ASM_OUTPUT_INTERNAL_LABEL (FILE, "LPBZ", num_func); \
+ num_func++; \
+ \
+ break; \
+ \
+ } \
} \
while (0)
+/* The following macro shall output assembler code to FILE
+ to increment a counter associated with basic block number BLOCKNO.
+
+ If profile_block_flag == 2
+
+ Output code to initialize the global structure `__bb' and
+ call the function `__bb_trace_func' which will increment the
+ counter.
-/* A C statement or compound statement to increment the count
- associated with the basic block number BLOCKNO. Basic blocks are
- numbered separately from zero within each compilation. The count
- associated with block number BLOCKNO is at index BLOCKNO in a
- vector of words; the name of this array is a local symbol made
- with this statement:
+ `__bb' consists of two words. In the first word the number
+ of the basic block has to be stored. In the second word
+ the address of a block allocated in the object module
+ has to be stored.
- ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
+ The basic block number is given by BLOCKNO.
- Of course, since you are writing the definition of
- `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
- can take a short cut in the definition of this macro and use the
- name that you know will result. */
+ The address of the block is given by the label created with
+
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+
+ by FUNCTION_BLOCK_PROFILER.
+
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result.
+
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ move BLOCKNO -> (__bb)
+ move LPBX0 -> (__bb+4)
+ call __bb_trace_func
+
+ Note that function `__bb_trace_func' must not change the
+ machine state, especially the flag register. To grant
+ this, you must output code to save and restore registers
+ either in this macro or in the macros MACHINE_STATE_SAVE
+ and MACHINE_STATE_RESTORE. The last two macros will be
+ used in the function `__bb_trace_func', so you must make
+ sure that the function prologue does not change any
+ register prior to saving it with MACHINE_STATE_SAVE.
+
+ else if profile_block_flag != 0
+
+ Output code to increment the counter directly.
+ Basic blocks are numbered separately from zero within each
+ compiled object module. The count associated with block number
+ BLOCKNO is at index BLOCKNO in an array of words; the name of
+ this array is a local symbol made with this statement:
+
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
+
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result.
+
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ inc (LPBX2+4*BLOCKNO)
+
+*/
-#define BLOCK_PROFILER(STREAM, BLOCKNO) \
+#define BLOCK_PROFILER(FILE, BLOCKNO) \
do \
{ \
- rtx xops[1], cnt_rtx; \
+ rtx xops[8], cnt_rtx; \
char counts[80]; \
+ char *block_table = counts; \
\
- ASM_GENERATE_INTERNAL_LABEL (counts, "LPBX", 2); \
- cnt_rtx = gen_rtx (SYMBOL_REF, VOIDmode, counts); \
- SYMBOL_REF_FLAG (cnt_rtx) = TRUE; \
+ switch (profile_block_flag) \
+ { \
\
- if (BLOCKNO) \
- cnt_rtx = plus_constant (cnt_rtx, (BLOCKNO)*4); \
+ case 2: \
\
- if (flag_pic) \
- cnt_rtx = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, cnt_rtx); \
+ ASM_GENERATE_INTERNAL_LABEL (block_table, "LPBX", 0); \
+ \
+ xops[1] = gen_rtx_SYMBOL_REF (VOIDmode, block_table); \
+ xops[2] = GEN_INT ((BLOCKNO)); \
+ xops[3] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_func")); \
+ xops[4] = gen_rtx_SYMBOL_REF (VOIDmode, "__bb"); \
+ xops[5] = plus_constant (xops[4], 4); \
+ xops[0] = gen_rtx_MEM (SImode, xops[4]); \
+ xops[6] = gen_rtx_MEM (SImode, xops[5]); \
+ \
+ CONSTANT_POOL_ADDRESS_P (xops[1]) = TRUE; \
+ \
+ fprintf(FILE, "\tpushf\n"); \
+ output_asm_insn (AS2(mov%L0,%2,%0), xops); \
+ if (flag_pic) \
+ { \
+ xops[7] = gen_rtx_REG (Pmode, 0); /* eax */ \
+ output_asm_insn (AS1(push%L7,%7), xops); \
+ output_asm_insn (AS2(lea%L7,%a1,%7), xops); \
+ output_asm_insn (AS2(mov%L6,%7,%6), xops); \
+ output_asm_insn (AS1(pop%L7,%7), xops); \
+ } \
+ else \
+ output_asm_insn (AS2(mov%L6,%1,%6), xops); \
+ output_asm_insn (AS1(call,%P3), xops); \
+ fprintf(FILE, "\tpopf\n"); \
+ \
+ break; \
+ \
+ default: \
+ \
+ ASM_GENERATE_INTERNAL_LABEL (counts, "LPBX", 2); \
+ cnt_rtx = gen_rtx_SYMBOL_REF (VOIDmode, counts); \
+ SYMBOL_REF_FLAG (cnt_rtx) = TRUE; \
\
- xops[0] = gen_rtx (MEM, SImode, cnt_rtx); \
- output_asm_insn (AS1(inc%L0,%0), xops); \
+ if (BLOCKNO) \
+ cnt_rtx = plus_constant (cnt_rtx, (BLOCKNO)*4); \
+ \
+ if (flag_pic) \
+ cnt_rtx = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, cnt_rtx); \
+ \
+ xops[0] = gen_rtx_MEM (SImode, cnt_rtx); \
+ output_asm_insn (AS1(inc%L0,%0), xops); \
+ \
+ break; \
+ \
+ } \
} \
while (0)
+/* The following macro shall output assembler code to FILE
+ to indicate a return from function during basic-block profiling.
+
+ If profiling_block_flag == 2:
+
+ Output assembler code to call function `__bb_trace_ret'.
+
+ Note that function `__bb_trace_ret' must not change the
+ machine state, especially the flag register. To grant
+ this, you must output code to save and restore registers
+ either in this macro or in the macros MACHINE_STATE_SAVE_RET
+ and MACHINE_STATE_RESTORE_RET. The last two macros will be
+ used in the function `__bb_trace_ret', so you must make
+ sure that the function prologue does not change any
+ register prior to saving it with MACHINE_STATE_SAVE_RET.
+
+ else if profiling_block_flag != 0:
+
+ The macro will not be used, so it need not distinguish
+ these cases.
+*/
+
+#define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \
+do \
+ { \
+ rtx xops[1]; \
+ \
+ xops[0] = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (VOIDmode, "__bb_trace_ret")); \
+ \
+ output_asm_insn (AS1(call,%P0), xops); \
+ \
+ } \
+while (0)
+
+/* The function `__bb_trace_func' is called in every basic block
+ and is not allowed to change the machine state. Saving (restoring)
+ the state can either be done in the BLOCK_PROFILER macro,
+ before calling function (rsp. after returning from function)
+ `__bb_trace_func', or it can be done inside the function by
+ defining the macros:
+
+ MACHINE_STATE_SAVE(ID)
+ MACHINE_STATE_RESTORE(ID)
+
+ In the latter case care must be taken, that the prologue code
+ of function `__bb_trace_func' does not already change the
+ state prior to saving it with MACHINE_STATE_SAVE.
+
+ The parameter `ID' is a string identifying a unique macro use.
+
+ On the i386 the initialization code at the begin of
+ function `__bb_trace_func' contains a `sub' instruction
+ therefore we handle save and restore of the flag register
+ in the BLOCK_PROFILER macro. */
+
+#define MACHINE_STATE_SAVE(ID) \
+ asm (" pushl %eax"); \
+ asm (" pushl %ecx"); \
+ asm (" pushl %edx"); \
+ asm (" pushl %esi");
+
+#define MACHINE_STATE_RESTORE(ID) \
+ asm (" popl %esi"); \
+ asm (" popl %edx"); \
+ asm (" popl %ecx"); \
+ asm (" popl %eax");
+
/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
the stack pointer does not matter. The value is tested only in
functions that have frame pointers.
@@ -1008,14 +1515,19 @@ while (0)
off the end. This happens if the function ends in an "exit" call, or
if a `return' insn is emitted directly into the function. */
-#define FUNCTION_EPILOGUE(FILE, SIZE) \
+#if 0
+#define FUNCTION_BEGIN_EPILOGUE(FILE) \
do { \
rtx last = get_last_insn (); \
if (last && GET_CODE (last) == NOTE) \
last = prev_nonnote_insn (last); \
- if (! last || GET_CODE (last) != BARRIER) \
- function_epilogue (FILE, SIZE); \
+/* if (! last || GET_CODE (last) != BARRIER) \
+ function_epilogue (FILE, SIZE);*/ \
} while (0)
+#endif
+
+#define FUNCTION_EPILOGUE(FILE, SIZE) \
+ function_epilogue (FILE, SIZE)
/* Output assembler code for a block containing the constant parts
of a trampoline, leaving space for the variable parts. */
@@ -1046,8 +1558,8 @@ do { \
#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
{ \
- emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 1)), CXT); \
- emit_move_insn (gen_rtx (MEM, SImode, plus_constant (TRAMP, 6)), FNADDR); \
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (TRAMP, 1)), CXT); \
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (TRAMP, 6)), FNADDR); \
}
/* Definitions for register eliminations.
@@ -1094,8 +1606,9 @@ do { \
\
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \
if ((regs_ever_live[regno] && ! call_used_regs[regno]) \
- || (current_function_uses_pic_offset_table \
- && regno == PIC_OFFSET_TABLE_REGNUM)) \
+ || ((current_function_uses_pic_offset_table \
+ || current_function_uses_const_pool) \
+ && flag_pic && regno == PIC_OFFSET_TABLE_REGNUM)) \
offset += 4; \
\
(OFFSET) = offset + get_frame_size (); \
@@ -1239,12 +1752,13 @@ do { \
#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
{ \
- rtx orig_x = (X); \
(X) = legitimize_address (X, OLDX, MODE); \
if (memory_address_p (MODE, X)) \
goto WIN; \
}
+#define REWRITE_ADDRESS(x) rewrite_address(x)
+
/* Nonzero if the constant value X is a legitimate general operand
when generating PIC code. It is given that flag_pic is on and
that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
@@ -1279,6 +1793,15 @@ do \
{ \
rtx rtl = (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
? TREE_CST_RTL (DECL) : DECL_RTL (DECL)); \
+ \
+ if (TARGET_DEBUG_ADDR \
+ && TREE_CODE_CLASS (TREE_CODE (DECL)) == 'd') \
+ { \
+ fprintf (stderr, "Encode %s, public = %d\n", \
+ IDENTIFIER_POINTER (DECL_NAME (DECL)), \
+ TREE_PUBLIC (DECL)); \
+ } \
+ \
SYMBOL_REF_FLAG (XEXP (rtl, 0)) \
= (TREE_CODE_CLASS (TREE_CODE (DECL)) != 'd' \
|| ! TREE_PUBLIC (DECL)); \
@@ -1349,10 +1872,11 @@ while (0)
for the index in the tablejump instruction. */
#define CASE_VECTOR_MODE Pmode
-/* Define this if the tablejump instruction expects the table
- to contain offsets from the address of the table.
- Do not define this if the table should contain absolute addresses. */
-/* #define CASE_VECTOR_PC_RELATIVE */
+/* Define as C expression which evaluates to nonzero if the tablejump
+ instruction expects the table to contain offsets from the address of the
+ table.
+ Do not define this if the table should contain absolute addresses. */
+/* #define CASE_VECTOR_PC_RELATIVE 1 */
/* Specify the tree operation to be used to convert reals to integers.
This should be changed to take advantage of fist --wfs ??
@@ -1369,22 +1893,23 @@ while (0)
in one reasonably fast instruction. */
#define MOVE_MAX 4
-/* MOVE_RATIO is the number of move instructions that is better than a
- block move. Make this large on i386, since the block move is very
- inefficient with small blocks, and the hard register needs of the
- block move require much reload work. */
-#define MOVE_RATIO 5
+/* The number of scalar move insns which should be generated instead
+ of a string move insn or a library call. Increasing the value
+ will always make code faster, but eventually incurs high cost in
+ increased code size.
-/* Define this if zero-extension is slow (more than one real instruction). */
-/* #define SLOW_ZERO_EXTEND */
+ If you don't define this, a reasonable default is used.
-/* Nonzero if access to memory by bytes is slow and undesirable. */
-#define SLOW_BYTE_ACCESS 0
+ Make this large on i386, since the block move is very inefficient with small
+ blocks, and the hard register needs of the block move require much reload
+ work. */
+
+#define MOVE_RATIO 5
/* Define if shifts truncate the shift count
which implies one can omit a sign-extension or zero-extension
of a shift count. */
-/* One i386, shifts do truncate the count. But bit opcodes don't. */
+/* On i386, shifts do truncate the count. But bit opcodes don't. */
/* #define SHIFT_COUNT_TRUNCATED */
@@ -1411,70 +1936,194 @@ while (0)
is a byte address (for indexing purposes)
so give the MEM rtx a byte's mode. */
#define FUNCTION_MODE QImode
-
-/* Define this if addresses of constant functions
- shouldn't be put through pseudo regs where they can be cse'd.
- Desirable on the 386 because a CALL with a constant address is
- not much slower than one with a register address. On a 486,
- it is faster to call with a constant address than indirect. */
-#define NO_FUNCTION_CSE
-
-/* Provide the costs of a rtl expression. This is in the body of a
- switch on CODE. */
-
-#define RTX_COSTS(X,CODE,OUTER_CODE) \
- case MULT: \
- return COSTS_N_INSNS (20); \
- case DIV: \
- case UDIV: \
- case MOD: \
- case UMOD: \
- return COSTS_N_INSNS (20); \
- case ASHIFTRT: \
- case LSHIFTRT: \
- case ASHIFT: \
- return (4 + rtx_cost (XEXP (X, 0), OUTER_CODE) \
- + rtx_cost (XEXP (X, 1), OUTER_CODE)); \
- case PLUS: \
- if (GET_CODE (XEXP (X, 0)) == MULT \
- && GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \
- && (INTVAL (XEXP (XEXP (X, 0), 1)) == 2 \
- || INTVAL (XEXP (XEXP (X, 0), 1)) == 4 \
- || INTVAL (XEXP (XEXP (X, 0), 1)) == 8)) \
- return (2 + rtx_cost (XEXP (XEXP (X, 0), 0), OUTER_CODE) \
- + rtx_cost (XEXP (X, 1), OUTER_CODE)); \
- break;
-
-
-/* Compute the cost of computing a constant rtl expression RTX
- whose rtx-code is CODE. The body of this macro is a portion
- of a switch statement. If the code is computed here,
- return it with a return statement. Otherwise, break from the switch. */
+
+/* A part of a C `switch' statement that describes the relative costs
+ of constant RTL expressions. It must contain `case' labels for
+ expression codes `const_int', `const', `symbol_ref', `label_ref'
+ and `const_double'. Each case must ultimately reach a `return'
+ statement to return the relative cost of the use of that kind of
+ constant value in an expression. The cost may depend on the
+ precise value of the constant, which is available for examination
+ in X, and the rtx code of the expression in which it is contained,
+ found in OUTER_CODE.
+
+ CODE is the expression code--redundant, since it can be obtained
+ with `GET_CODE (X)'. */
#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
case CONST_INT: \
+ return (unsigned) INTVAL (RTX) < 256 ? 0 : 1; \
case CONST: \
case LABEL_REF: \
case SYMBOL_REF: \
- return flag_pic && SYMBOLIC_CONST (RTX) ? 2 : 0; \
+ return flag_pic && SYMBOLIC_CONST (RTX) ? 2 : 1; \
+ \
case CONST_DOUBLE: \
{ \
int code; \
if (GET_MODE (RTX) == VOIDmode) \
return 2; \
+ \
code = standard_80387_constant_p (RTX); \
return code == 1 ? 0 : \
code == 2 ? 1 : \
2; \
}
-/* Compute the cost of an address. This is meant to approximate the size
- and/or execution delay of an insn using that address. If the cost is
- approximated by the RTL complexity, including CONST_COSTS above, as
- is usually the case for CISC machines, this macro should not be defined.
- For aggressively RISCy machines, only one insn format is allowed, so
- this macro should be a constant. The value of this macro only matters
- for valid addresses.
+/* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */
+#define TOPLEVEL_COSTS_N_INSNS(N) {total = COSTS_N_INSNS (N); break;}
+
+/* Like `CONST_COSTS' but applies to nonconstant RTL expressions.
+ This can be used, for example, to indicate how costly a multiply
+ instruction is. In writing this macro, you can use the construct
+ `COSTS_N_INSNS (N)' to specify a cost equal to N fast
+ instructions. OUTER_CODE is the code of the expression in which X
+ is contained.
+
+ This macro is optional; do not define it if the default cost
+ assumptions are adequate for the target machine. */
+
+#define RTX_COSTS(X,CODE,OUTER_CODE) \
+ case ASHIFT: \
+ if (GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && GET_MODE (XEXP (X, 0)) == SImode) \
+ { \
+ HOST_WIDE_INT value = INTVAL (XEXP (X, 1)); \
+ \
+ if (value == 1) \
+ return COSTS_N_INSNS (ix86_cost->add) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ \
+ if (value == 2 || value == 3) \
+ return COSTS_N_INSNS (ix86_cost->lea) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ } \
+ /* fall through */ \
+ \
+ case ROTATE: \
+ case ASHIFTRT: \
+ case LSHIFTRT: \
+ case ROTATERT: \
+ if (GET_MODE (XEXP (X, 0)) == DImode) \
+ { \
+ if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ { \
+ if (INTVAL (XEXP (X, 1)) > 32) \
+ return COSTS_N_INSNS(ix86_cost->shift_const + 2); \
+ return COSTS_N_INSNS(ix86_cost->shift_const * 2); \
+ } \
+ return ((GET_CODE (XEXP (X, 1)) == AND \
+ ? COSTS_N_INSNS(ix86_cost->shift_var * 2) \
+ : COSTS_N_INSNS(ix86_cost->shift_var * 6 + 2)) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE)); \
+ } \
+ return COSTS_N_INSNS (GET_CODE (XEXP (X, 1)) == CONST_INT \
+ ? ix86_cost->shift_const \
+ : ix86_cost->shift_var) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ \
+ case MULT: \
+ if (GET_CODE (XEXP (X, 1)) == CONST_INT) \
+ { \
+ unsigned HOST_WIDE_INT value = INTVAL (XEXP (X, 1)); \
+ int nbits = 0; \
+ \
+ if (value == 2) \
+ return COSTS_N_INSNS (ix86_cost->add) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ if (value == 4 || value == 8) \
+ return COSTS_N_INSNS (ix86_cost->lea) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ \
+ while (value != 0) \
+ { \
+ nbits++; \
+ value >>= 1; \
+ } \
+ \
+ if (nbits == 1) \
+ return COSTS_N_INSNS (ix86_cost->shift_const) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ \
+ return COSTS_N_INSNS (ix86_cost->mult_init \
+ + nbits * ix86_cost->mult_bit) \
+ + rtx_cost(XEXP (X, 0), OUTER_CODE); \
+ } \
+ \
+ else /* This is arbitrary */ \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->mult_init \
+ + 7 * ix86_cost->mult_bit); \
+ \
+ case DIV: \
+ case UDIV: \
+ case MOD: \
+ case UMOD: \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->divide); \
+ \
+ case PLUS: \
+ if (GET_CODE (XEXP (X, 0)) == REG \
+ && GET_MODE (XEXP (X, 0)) == SImode \
+ && GET_CODE (XEXP (X, 1)) == PLUS) \
+ return COSTS_N_INSNS (ix86_cost->lea); \
+ \
+ /* fall through */ \
+ case AND: \
+ case IOR: \
+ case XOR: \
+ case MINUS: \
+ if (GET_MODE (X) == DImode) \
+ return COSTS_N_INSNS (ix86_cost->add) * 2 \
+ + (rtx_cost (XEXP (X, 0), OUTER_CODE) \
+ << (GET_MODE (XEXP (X, 0)) != DImode)) \
+ + (rtx_cost (XEXP (X, 1), OUTER_CODE) \
+ << (GET_MODE (XEXP (X, 1)) != DImode)); \
+ case NEG: \
+ case NOT: \
+ if (GET_MODE (X) == DImode) \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2) \
+ TOPLEVEL_COSTS_N_INSNS (ix86_cost->add)
+
+
+/* An expression giving the cost of an addressing mode that contains
+ ADDRESS. If not defined, the cost is computed from the ADDRESS
+ expression and the `CONST_COSTS' values.
+
+ For most CISC machines, the default cost is a good approximation
+ of the true cost of the addressing mode. However, on RISC
+ machines, all instructions normally have the same length and
+ execution time. Hence all addresses will have equal costs.
+
+ In cases where more than one form of an address is known, the form
+ with the lowest cost will be used. If multiple forms have the
+ same, lowest, cost, the one that is the most complex will be used.
+
+ For example, suppose an address that is equal to the sum of a
+ register and a constant is used twice in the same basic block.
+ When this macro is not defined, the address will be computed in a
+ register and memory references will be indirect through that
+ register. On machines where the cost of the addressing mode
+ containing the sum is no higher than that of a simple indirect
+ reference, this will produce an additional instruction and
+ possibly require an additional register. Proper specification of
+ this macro eliminates this overhead for such machines.
+
+ Similar use of this macro is made in strength reduction of loops.
+
+ ADDRESS need not be valid as an address. In such a case, the cost
+ is not relevant and can be any value; invalid addresses need not be
+ assigned a different cost.
+
+ On machines where an address involving more than one register is as
+ cheap as an address computation involving only one register,
+ defining `ADDRESS_COST' to reflect this can cause two registers to
+ be live over a region of code where only one would have been if
+ `ADDRESS_COST' were not defined in that manner. This effect should
+ be considered in the definition of this macro. Equivalent costs
+ should probably only be given to addresses with different numbers
+ of registers on machines with lots of registers.
+
+ This macro will normally either not be defined or be defined as a
+ constant.
For i386, it is better to use a complex address than let gcc copy
the address into a reg and make a new pseudo. But not if the address
@@ -1487,6 +2136,193 @@ while (0)
&& REG_P (XEXP (RTX, 0)))) ? 0 \
: REG_P (RTX) ? 1 \
: 2)
+
+/* A C expression for the cost of moving data of mode M between a
+ register and memory. A value of 2 is the default; this cost is
+ relative to those in `REGISTER_MOVE_COST'.
+
+ If moving between registers and memory is more expensive than
+ between two registers, you should define this macro to express the
+ relative cost.
+
+ On the i386, copying between floating-point and fixed-point
+ registers is expensive. */
+
+#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
+ (((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2)) \
+ || (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2))) ? 10 \
+ : 2)
+
+
+/* A C expression for the cost of moving data of mode M between a
+ register and memory. A value of 2 is the default; this cost is
+ relative to those in `REGISTER_MOVE_COST'.
+
+ If moving between registers and memory is more expensive than
+ between two registers, you should define this macro to express the
+ relative cost. */
+
+/* #define MEMORY_MOVE_COST(M,C,I) 2 */
+
+/* A C expression for the cost of a branch instruction. A value of 1
+ is the default; other values are interpreted relative to that. */
+
+#define BRANCH_COST i386_branch_cost
+
+/* Define this macro as a C expression which is nonzero if accessing
+ less than a word of memory (i.e. a `char' or a `short') is no
+ faster than accessing a word of memory, i.e., if such access
+ require more than one instruction or if there is no difference in
+ cost between byte and (aligned) word loads.
+
+ When this macro is not defined, the compiler will access a field by
+ finding the smallest containing object; when it is defined, a
+ fullword load will be used if alignment permits. Unless bytes
+ accesses are faster than word accesses, using word accesses is
+ preferable since it may eliminate subsequent memory access if
+ subsequent accesses occur to other fields in the same word of the
+ structure, but to different bytes. */
+
+#define SLOW_BYTE_ACCESS 0
+
+/* Nonzero if access to memory by shorts is slow and undesirable. */
+#define SLOW_SHORT_ACCESS 0
+
+/* Define this macro if zero-extension (of a `char' or `short' to an
+ `int') can be done faster if the destination is a register that is
+ known to be zero.
+
+ If you define this macro, you must have instruction patterns that
+ recognize RTL structures like this:
+
+ (set (strict_low_part (subreg:QI (reg:SI ...) 0)) ...)
+
+ and likewise for `HImode'. */
+
+/* #define SLOW_ZERO_EXTEND */
+
+/* Define this macro to be the value 1 if unaligned accesses have a
+ cost many times greater than aligned accesses, for example if they
+ are emulated in a trap handler.
+
+ When this macro is non-zero, the compiler will act as if
+ `STRICT_ALIGNMENT' were non-zero when generating code for block
+ moves. This can cause significantly more instructions to be
+ produced. Therefore, do not set this macro non-zero if unaligned
+ accesses only add a cycle or two to the time for a memory access.
+
+ If the value of this macro is always zero, it need not be defined. */
+
+/* #define SLOW_UNALIGNED_ACCESS 0 */
+
+/* Define this macro to inhibit strength reduction of memory
+ addresses. (On some machines, such strength reduction seems to do
+ harm rather than good.) */
+
+/* #define DONT_REDUCE_ADDR */
+
+/* Define this macro if it is as good or better to call a constant
+ function address than to call an address kept in a register.
+
+ Desirable on the 386 because a CALL with a constant address is
+ faster than one with a register address. */
+
+#define NO_FUNCTION_CSE
+
+/* Define this macro if it is as good or better for a function to call
+ itself with an explicit address than to call an address kept in a
+ register. */
+
+#define NO_RECURSIVE_FUNCTION_CSE
+
+/* A C statement (sans semicolon) to update the integer variable COST
+ based on the relationship between INSN that is dependent on
+ DEP_INSN through the dependence LINK. The default is to make no
+ adjustment to COST. This can be used for example to specify to
+ the scheduler that an output- or anti-dependence does not incur
+ the same cost as a data-dependence. */
+
+#define ADJUST_COST(insn,link,dep_insn,cost) \
+ { \
+ rtx next_inst; \
+ if (GET_CODE (dep_insn) == CALL_INSN) \
+ (cost) = 0; \
+ \
+ else if (GET_CODE (dep_insn) == INSN \
+ && GET_CODE (PATTERN (dep_insn)) == SET \
+ && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG \
+ && GET_CODE (insn) == INSN \
+ && GET_CODE (PATTERN (insn)) == SET \
+ && !reg_overlap_mentioned_p (SET_DEST (PATTERN (dep_insn)), \
+ SET_SRC (PATTERN (insn)))) \
+ { \
+ (cost) = 0; \
+ } \
+ \
+ else if (GET_CODE (insn) == JUMP_INSN) \
+ { \
+ (cost) = 0; \
+ } \
+ \
+ if (TARGET_PENTIUM) \
+ { \
+ if (cost !=0 && is_fp_insn (insn) && is_fp_insn (dep_insn) \
+ && !is_fp_dest (dep_insn)) \
+ { \
+ (cost) = 0; \
+ } \
+ \
+ if (agi_dependent (insn, dep_insn)) \
+ { \
+ (cost) = 3; \
+ } \
+ else if (GET_CODE (insn) == INSN \
+ && GET_CODE (PATTERN (insn)) == SET \
+ && SET_DEST (PATTERN (insn)) == cc0_rtx \
+ && (next_inst = next_nonnote_insn (insn)) \
+ && GET_CODE (next_inst) == JUMP_INSN) \
+ { /* compare probably paired with jump */ \
+ (cost) = 0; \
+ } \
+ } \
+ else \
+ if (!is_fp_dest (dep_insn)) \
+ { \
+ if(!agi_dependent (insn, dep_insn)) \
+ (cost) = 0; \
+ else if (TARGET_486) \
+ (cost) = 2; \
+ } \
+ else \
+ if (is_fp_store (insn) && is_fp_insn (dep_insn) \
+ && NEXT_INSN (insn) && NEXT_INSN (NEXT_INSN (insn)) \
+ && NEXT_INSN (NEXT_INSN (NEXT_INSN (insn))) \
+ && (GET_CODE (NEXT_INSN (insn)) == INSN) \
+ && (GET_CODE (NEXT_INSN (NEXT_INSN (insn))) == JUMP_INSN) \
+ && (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) == NOTE) \
+ && (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) \
+ == NOTE_INSN_LOOP_END)) \
+ { \
+ (cost) = 3; \
+ } \
+ }
+
+
+#define ADJUST_BLOCKAGE(last_insn,insn,blockage) \
+{ \
+ if (is_fp_store (last_insn) && is_fp_insn (insn) \
+ && NEXT_INSN (last_insn) && NEXT_INSN (NEXT_INSN (last_insn)) \
+ && NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn))) \
+ && (GET_CODE (NEXT_INSN (last_insn)) == INSN) \
+ && (GET_CODE (NEXT_INSN (NEXT_INSN (last_insn))) == JUMP_INSN) \
+ && (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn)))) == NOTE) \
+ && (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (last_insn)))) \
+ == NOTE_INSN_LOOP_END)) \
+ { \
+ (blockage) = 3; \
+ } \
+}
+
/* Add any extra modes needed to represent the condition code.
@@ -1519,6 +2355,10 @@ extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
/* Here we define machine-dependent flags and fields in cc_status
(see `conditions.h'). */
+/* Set if the cc value was actually from the 80387 and
+ we are testing eax directly (i.e. no sahf) */
+#define CC_TEST_AX 020000
+
/* Set if the cc value is actually in the 80387, so a floating point
conditional branch must be output. */
#define CC_IN_80387 04000
@@ -1527,6 +2367,10 @@ extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
the state of equality is indicated by zero in the carry bit. */
#define CC_Z_IN_NOT_C 010000
+/* Set if the CC value was actually from the 80387 and loaded directly
+ into the eflags instead of via eax/sahf. */
+#define CC_FCOMI 040000
+
/* Store in cc_status the expressions
that the condition codes will describe
after execution of an instruction whose pattern is EXP.
@@ -1572,10 +2416,10 @@ extern struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
/* Table of additional register names to use in user input. */
#define ADDITIONAL_REGISTER_NAMES \
-{ "eax", 0, "edx", 1, "ecx", 2, "ebx", 3, \
- "esi", 4, "edi", 5, "ebp", 6, "esp", 7, \
- "al", 0, "dl", 1, "cl", 2, "bl", 3, \
- "ah", 0, "dh", 1, "ch", 2, "bh", 3 }
+{ { "eax", 0 }, { "edx", 1 }, { "ecx", 2 }, { "ebx", 3 }, \
+ { "esi", 4 }, { "edi", 5 }, { "ebp", 6 }, { "esp", 7 }, \
+ { "al", 0 }, { "dl", 1 }, { "cl", 2 }, { "bl", 3 }, \
+ { "ah", 0 }, { "dh", 1 }, { "ch", 2 }, { "bh", 3 } }
/* Note we are omitting these since currently I don't know how
to get gcc to use these, since they want the same but different
@@ -1609,6 +2453,22 @@ number as al, and ax.
(n) == 7 ? 5 : \
(n) + 4)
+/* Before the prologue, RA is at 0(%esp). */
+#define INCOMING_RETURN_ADDR_RTX \
+ gen_rtx_MEM (VOIDmode, gen_rtx_REG (VOIDmode, STACK_POINTER_REGNUM))
+
+/* After the prologue, RA is at -4(AP) in the current frame. */
+#define RETURN_ADDR_RTX(COUNT, FRAME) \
+ ((COUNT) == 0 \
+ ? gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT(-4)))\
+ : gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, (FRAME), GEN_INT(4))))
+
+/* PC is dbx register 8; let's use that column for RA. */
+#define DWARF_FRAME_RETURN_COLUMN 8
+
+/* Before the prologue, the top of the frame is at 4(%esp). */
+#define INCOMING_FRAME_SP_OFFSET 4
+
/* This is how to output the definition of a user-level label named NAME,
such as the label on a static function or variable NAME. */
@@ -1620,10 +2480,7 @@ number as al, and ax.
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
do { long l[2]; \
REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \
- if (sizeof (int) == sizeof (long)) \
- fprintf (FILE, "%s 0x%x,0x%x\n", ASM_LONG, l[0], l[1]); \
- else \
- fprintf (FILE, "%s 0x%lx,0x%lx\n", ASM_LONG, l[0], l[1]); \
+ fprintf (FILE, "%s 0x%lx,0x%lx\n", ASM_LONG, l[0], l[1]); \
} while (0)
/* This is how to output a `long double' extended real constant. */
@@ -1632,10 +2489,7 @@ do { long l[2]; \
#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \
do { long l[3]; \
REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \
- if (sizeof (int) == sizeof (long)) \
- fprintf (FILE, "%s 0x%x,0x%x,0x%x\n", ASM_LONG, l[0], l[1], l[2]); \
- else \
- fprintf (FILE, "%s 0x%lx,0x%lx,0x%lx\n", ASM_LONG, l[0], l[1], l[2]); \
+ fprintf (FILE, "%s 0x%lx,0x%lx,0x%lx\n", ASM_LONG, l[0], l[1], l[2]); \
} while (0)
/* This is how to output an assembler line defining a `float' constant. */
@@ -1643,10 +2497,7 @@ do { long l[3]; \
#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
do { long l; \
REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \
- if (sizeof (int) == sizeof (long)) \
- fprintf ((FILE), "%s 0x%x\n", ASM_LONG, l); \
- else \
- fprintf ((FILE), "%s 0x%lx\n", ASM_LONG, l); \
+ fprintf ((FILE), "%s 0x%lx\n", ASM_LONG, l); \
} while (0)
/* Store in OUTPUT a string (made with alloca) containing
@@ -1698,13 +2549,13 @@ do { long l; \
It need not be very fast code. */
#define ASM_OUTPUT_REG_PUSH(FILE,REGNO) \
- fprintf (FILE, "\tpushl e%s\n", reg_names[REGNO])
+ fprintf (FILE, "\tpushl %%e%s\n", reg_names[REGNO])
/* This is how to output an insn to pop a register from the stack.
It need not be very fast code. */
#define ASM_OUTPUT_REG_POP(FILE,REGNO) \
- fprintf (FILE, "\tpopl e%s\n", reg_names[REGNO])
+ fprintf (FILE, "\tpopl %%e%s\n", reg_names[REGNO])
/* This is how to output an element of a case-vector that is absolute.
*/
@@ -1717,7 +2568,7 @@ do { long l; \
forward reference the differences.
*/
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.word %s%d-%s%d\n",LPREFIX, VALUE,LPREFIX, REL)
/* Define the parentheses used to group arithmetic operations
@@ -1746,9 +2597,13 @@ do { long l; \
R -- print the prefix for register names.
z -- print the opcode suffix for the size of the current operand.
* -- print a star (in certain assembler syntax)
- w -- print the operand as if it's a "word" (HImode) even if it isn't.
- b -- print the operand as if it's a byte (QImode) even if it isn't.
- c -- don't print special prefixes before constant operands. */
+ P -- if PIC, print an @PLT suffix.
+ X -- don't print any sort of PIC '@' suffix for a symbol.
+ J -- print jump insn for arithmetic_comparison_operator.
+ s -- ??? something to do with double shifts. not actually used, afaik.
+ C -- print a conditional move suffix corresponding to the op code.
+ c -- likewise, but reverse the condition.
+ F,f -- likewise, but for floating-point. */
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
((CODE) == '*')
@@ -1853,13 +2708,30 @@ extern char *qi_high_reg_name[];
we can use for operand syntax in the extended asm */
#define ASM_OPERAND_LETTER '#'
-
#define RET return ""
-#define AT_SP(mode) (gen_rtx (MEM, (mode), stack_pointer_rtx))
+#define AT_SP(mode) (gen_rtx_MEM ((mode), stack_pointer_rtx))
+
+/* Helper macros to expand a binary/unary operator if needed */
+#define IX86_EXPAND_BINARY_OPERATOR(OP, MODE, OPERANDS) \
+do { \
+ if (!ix86_expand_binary_operator (OP, MODE, OPERANDS)) \
+ FAIL; \
+} while (0)
+
+#define IX86_EXPAND_UNARY_OPERATOR(OP, MODE, OPERANDS) \
+do { \
+ if (!ix86_expand_unary_operator (OP, MODE, OPERANDS,)) \
+ FAIL; \
+} while (0)
+
/* Functions in i386.c */
extern void override_options ();
extern void order_regs_for_local_alloc ();
+extern char *output_strlen_unroll ();
+extern struct rtx_def *i386_sext16_if_const ();
+extern int i386_aligned_p ();
+extern int i386_cc_probably_useless_p ();
extern int i386_valid_decl_attribute_p ();
extern int i386_valid_type_attribute_p ();
extern int i386_return_pops_args ();
@@ -1868,6 +2740,7 @@ extern void init_cumulative_args ();
extern void function_arg_advance ();
extern struct rtx_def *function_arg ();
extern int function_arg_partial_nregs ();
+extern char *output_strlen_unroll ();
extern void output_op_from_reg ();
extern void output_to_reg ();
extern char *singlemove_string ();
@@ -1880,6 +2753,10 @@ extern int symbolic_operand ();
extern int call_insn_operand ();
extern int expander_call_insn_operand ();
extern int symbolic_reference_mentioned_p ();
+extern int ix86_expand_binary_operator ();
+extern int ix86_binary_operator_ok ();
+extern int ix86_expand_unary_operator ();
+extern int ix86_unary_operator_ok ();
extern void emit_pic_move ();
extern void function_prologue ();
extern int simple_386_epilogue ();
@@ -1902,17 +2779,40 @@ extern void save_386_machine_status ();
extern void restore_386_machine_status ();
extern void clear_386_stack_locals ();
extern struct rtx_def *assign_386_stack_local ();
+extern int is_mul ();
+extern int is_div ();
+extern int last_to_set_cc ();
+extern int doesnt_set_condition_code ();
+extern int sets_condition_code ();
+extern int str_immediate_operand ();
+extern int is_fp_insn ();
+extern int is_fp_dest ();
+extern int is_fp_store ();
+extern int agi_dependent ();
+extern int reg_mentioned_in_mem ();
+extern char *output_int_conditional_move ();
+extern char *output_fp_conditional_move ();
+extern int ix86_can_use_return_insn_p ();
+
+#ifdef NOTYET
+extern struct rtx_def *copy_all_rtx ();
+extern void rewrite_address ();
+#endif
/* Variables in i386.c */
+extern char *ix86_cpu_string; /* for -mcpu=<xxx> */
+extern char *ix86_arch_string; /* for -march=<xxx> */
extern char *i386_reg_alloc_order; /* register allocation order */
extern char *i386_regparm_string; /* # registers to use to pass args */
extern char *i386_align_loops_string; /* power of two alignment for loops */
extern char *i386_align_jumps_string; /* power of two alignment for non-loop jumps */
extern char *i386_align_funcs_string; /* power of two alignment for functions */
+extern char *i386_branch_cost_string; /* values 1-5: see jump.c */
extern int i386_regparm; /* i386_regparm_string as a number */
extern int i386_align_loops; /* power of two alignment for loops */
extern int i386_align_jumps; /* power of two alignment for non-loop jumps */
extern int i386_align_funcs; /* power of two alignment for functions */
+extern int i386_branch_cost; /* values 1-5: see jump.c */
extern char *hi_reg_name[]; /* names for 16 bit regs */
extern char *qi_reg_name[]; /* names for 8 bit regs (low) */
extern char *qi_high_reg_name[]; /* names for 8 bit regs (high) */
@@ -1921,11 +2821,12 @@ extern struct rtx_def *i386_compare_op0; /* operand 0 for comparisons */
extern struct rtx_def *i386_compare_op1; /* operand 1 for comparisons */
/* External variables used */
-extern int optimize; /* optimization level */
-extern int obey_regdecls; /* TRUE if stupid register allocation */
+extern int optimize; /* optimization level */
+extern int obey_regdecls; /* TRUE if stupid register allocation */
/* External functions used */
extern struct rtx_def *force_operand ();
+
/*
Local variables:
diff --git a/contrib/gcc/config/i386/i386.md b/contrib/gcc/config/i386/i386.md
index ff01196..f85992f 100644
--- a/contrib/gcc/config/i386/i386.md
+++ b/contrib/gcc/config/i386/i386.md
@@ -1,5 +1,5 @@
-;; GCC machine description for Intel X86.
-;; Copyright (C) 1988, 1994, 1995 Free Software Foundation, Inc.
+; GCC machine description for Intel X86.
+;; Copyright (C) 1988, 94, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
;; Mostly by William Schelter.
;; This file is part of GNU CC.
@@ -17,8 +17,7 @@
;; You should have received a copy of the GNU General Public License
;; along with GNU CC; see the file COPYING. If not, write to
;; the Free Software Foundation, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
+;; Boston, MA 02111-1307, USA. */
;; The original PO technology requires these to be ordered by speed,
;; so that assigner will pick the fastest.
@@ -37,8 +36,8 @@
;; 'L' Print the opcode suffix for a 32-bit integer opcode.
;; 'W' Print the opcode suffix for a 16-bit integer opcode.
;; 'B' Print the opcode suffix for an 8-bit integer opcode.
-;; 'S' Print the opcode suffix for a 32-bit float opcode.
;; 'Q' Print the opcode suffix for a 64-bit float opcode.
+;; 'S' Print the opcode suffix for a 32-bit float opcode.
;; 'T' Print the opcode suffix for an 80-bit extended real XFmode float opcode.
;; 'J' Print the appropriate jump operand.
@@ -59,6 +58,72 @@
;; operand 0 is the argument for `sin'.
;; 2 This is a `cos' operation. The mode of the UNSPEC is MODE_FLOAT.
;; operand 0 is the argument for `cos'.
+;; 3 This is part of a `stack probe' operation. The mode of the UNSPEC is
+;; always SImode. operand 0 is the size of the stack allocation.
+;; 4 This is the source of a fake SET of the frame pointer which is used to
+;; prevent insns referencing it being scheduled across the initial
+;; decrement of the stack pointer.
+;; 5 This is a `bsf' operation.
+
+;; This shadows the processor_type enumeration, so changes must be made
+;; to i386.h at the same time.
+
+(define_attr "type" "integer,idiv,imul,fld,fpop,fpdiv,fpmul"
+ (const_string "integer"))
+
+;; Functional units
+
+; (define_function_unit NAME MULTIPLICITY SIMULTANEITY
+; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST])
+
+; pentiumpro has a reservation station with 5 ports
+; port 0 has integer, float add, integer divide, float divide, float
+; multiply, and shifter units.
+; port 1 has integer, and jump units.
+; port 2 has the load address generation unit
+; ports 3 and 4 have the store address generation units
+
+; pentium has two integer pipelines, the main u pipe and the secondary v pipe.
+; and a float pipeline
+
+;; Floating point
+
+(define_function_unit "fp" 1 0
+ (and (eq_attr "type" "fpop") (eq_attr "cpu" "i386,i486"))
+ 5 5)
+
+(define_function_unit "fp" 1 0
+ (and (eq_attr "type" "fpop") (eq_attr "cpu" "pentium,pentiumpro"))
+ 3 0)
+
+(define_function_unit "fp" 1 0
+ (and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentium"))
+ 7 0)
+
+(define_function_unit "fp" 1 0
+ (and (eq_attr "type" "fpmul") (eq_attr "cpu" "pentiumpro"))
+ 5 0)
+
+(define_function_unit "fp" 1 0
+ (and (eq_attr "type" "idiv") (eq_attr "cpu" "pentiumpro"))
+ 10 10)
+
+(define_function_unit "fp" 1 0
+ (and (eq_attr "type" "imul") (eq_attr "cpu" "pentiumpro"))
+ 6 0)
+
+(define_function_unit "fp" 1 0
+ (eq_attr "type" "fpdiv")
+ 10 10)
+
+(define_function_unit "fp" 1 0
+ (eq_attr "type" "fld")
+ 1 0)
+
+(define_function_unit "integer" 1 0
+ (and (eq_attr "type" "integer") (eq_attr "cpu" "!i386"))
+ 2 0)
+
;; "movl MEM,REG / testl REG,REG" is faster on a 486 than "cmpl $0,MEM".
;; But restricting MEM here would mean that gcc could not remove a redundant
@@ -72,6 +137,12 @@
;; actually generating RTL. The bCOND or sCOND (emitted immediately
;; after the tstM or cmp) will actually emit the tstM or cmpM.
+;; Processor type -- this attribute must exactly match the processor_type
+;; enumeration in i386.h.
+
+(define_attr "cpu" "i386,i486,pentium,pentiumpro"
+ (const (symbol_ref "ix86_cpu")))
+
(define_insn "tstsi_1"
[(set (cc0)
(match_operand:SI 0 "nonimmediate_operand" "rm"))]
@@ -93,6 +164,7 @@
{
i386_compare_gen = gen_tstsi_1;
i386_compare_op0 = operands[0];
+ i386_compare_op1 = const0_rtx;
DONE;
}")
@@ -117,6 +189,7 @@
{
i386_compare_gen = gen_tsthi_1;
i386_compare_op0 = operands[0];
+ i386_compare_op1 = const0_rtx;
DONE;
}")
@@ -141,6 +214,7 @@
{
i386_compare_gen = gen_tstqi_1;
i386_compare_op0 = operands[0];
+ i386_compare_op1 = const0_rtx;
DONE;
}")
@@ -174,6 +248,7 @@
{
i386_compare_gen = gen_tstsf_cc;
i386_compare_op0 = operands[0];
+ i386_compare_op1 = const0_rtx;
DONE;
}")
@@ -207,6 +282,7 @@
{
i386_compare_gen = gen_tstdf_cc;
i386_compare_op0 = operands[0];
+ i386_compare_op1 = const0_rtx;
DONE;
}")
@@ -228,7 +304,7 @@
return output_fp_cc0_set (insn);
}")
-;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode
+;; Don't generate tstxf if generating IEEE code, since the `ftst' opcode
;; isn't IEEE compliant.
(define_expand "tstxf"
@@ -240,6 +316,7 @@
{
i386_compare_gen = gen_tstxf_cc;
i386_compare_op0 = operands[0];
+ i386_compare_op1 = const0_rtx;
DONE;
}")
@@ -251,15 +328,7 @@
(compare (match_operand:SI 0 "nonimmediate_operand" "mr,r")
(match_operand:SI 1 "general_operand" "ri,mr")))]
"GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
- "*
-{
- if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM)
- {
- cc_status.flags |= CC_REVERSED;
- return AS2 (cmp%L0,%0,%1);
- }
- return AS2 (cmp%L0,%1,%0);
-}")
+ "* return AS2 (cmp%L0,%1,%0);")
(define_expand "cmpsi"
[(set (cc0)
@@ -282,15 +351,7 @@
(compare (match_operand:HI 0 "nonimmediate_operand" "mr,r")
(match_operand:HI 1 "general_operand" "ri,mr")))]
"GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
- "*
-{
- if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM)
- {
- cc_status.flags |= CC_REVERSED;
- return AS2 (cmp%W0,%0,%1);
- }
- return AS2 (cmp%W0,%1,%0);
-}")
+ "* return AS2 (cmp%W0,%1,%0);")
(define_expand "cmphi"
[(set (cc0)
@@ -313,15 +374,7 @@
(compare (match_operand:QI 0 "nonimmediate_operand" "q,mq")
(match_operand:QI 1 "general_operand" "qm,nq")))]
"GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
- "*
-{
- if (CONSTANT_P (operands[0]) || GET_CODE (operands[1]) == MEM)
- {
- cc_status.flags |= CC_REVERSED;
- return AS2 (cmp%B0,%0,%1);
- }
- return AS2 (cmp%B0,%1,%0);
-}")
+ "* return AS2 (cmp%B0,%1,%0);")
(define_expand "cmpqi"
[(set (cc0)
@@ -346,11 +399,10 @@
(define_insn ""
[(set (cc0)
(match_operator 2 "VOIDmode_compare_op"
- [(match_operand:XF 0 "nonimmediate_operand" "f")
- (match_operand:XF 1 "nonimmediate_operand" "f")]))
+ [(match_operand:XF 0 "register_operand" "f")
+ (match_operand:XF 1 "register_operand" "f")]))
(clobber (match_scratch:HI 3 "=a"))]
- "TARGET_80387
- && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+ "TARGET_80387"
"* return output_float_compare (insn, operands);")
(define_insn ""
@@ -386,6 +438,16 @@
(define_insn ""
[(set (cc0)
(match_operator 2 "VOIDmode_compare_op"
+ [(float_extend:XF
+ (match_operand:DF 0 "nonimmediate_operand" "fm"))
+ (match_operand:XF 1 "register_operand" "f")]))
+ (clobber (match_scratch:HI 3 "=a"))]
+ "TARGET_80387"
+ "* return output_float_compare (insn, operands);")
+
+(define_insn ""
+ [(set (cc0)
+ (match_operator 2 "VOIDmode_compare_op"
[(match_operand:XF 0 "register_operand" "f")
(float_extend:XF
(match_operand:SF 1 "nonimmediate_operand" "fm"))]))
@@ -395,6 +457,16 @@
(define_insn ""
[(set (cc0)
+ (match_operator 2 "VOIDmode_compare_op"
+ [(float_extend:XF
+ (match_operand:SF 0 "nonimmediate_operand" "fm"))
+ (match_operand:XF 1 "register_operand" "f")]))
+ (clobber (match_scratch:HI 3 "=a"))]
+ "TARGET_80387"
+ "* return output_float_compare (insn, operands);")
+
+(define_insn ""
+ [(set (cc0)
(compare:CCFPEQ (match_operand:XF 0 "register_operand" "f")
(match_operand:XF 1 "register_operand" "f")))
(clobber (match_scratch:HI 2 "=a"))]
@@ -453,6 +525,16 @@
(define_insn ""
[(set (cc0)
+ (match_operator 2 "VOIDmode_compare_op"
+ [(float_extend:DF
+ (match_operand:SF 0 "register_operand" "f"))
+ (match_operand:DF 1 "nonimmediate_operand" "fm")]))
+ (clobber (match_scratch:HI 3 "=a"))]
+ "TARGET_80387"
+ "* return output_float_compare (insn, operands);")
+
+(define_insn ""
+ [(set (cc0)
(compare:CCFPEQ (match_operand:DF 0 "register_operand" "f")
(match_operand:DF 1 "register_operand" "f")))
(clobber (match_scratch:HI 2 "=a"))]
@@ -520,7 +602,7 @@
(define_expand "cmpxf"
[(set (cc0)
(compare (match_operand:XF 0 "register_operand" "")
- (match_operand:XF 1 "nonimmediate_operand" "")))]
+ (match_operand:XF 1 "register_operand" "")))]
"TARGET_80387"
"
{
@@ -534,28 +616,30 @@
(define_expand "cmpdf"
[(set (cc0)
(compare (match_operand:DF 0 "register_operand" "")
- (match_operand:DF 1 "nonimmediate_operand" "")))]
+ (match_operand:DF 1 "general_operand" "")))]
"TARGET_80387"
"
{
i386_compare_gen = gen_cmpdf_cc;
i386_compare_gen_eq = gen_cmpdf_ccfpeq;
i386_compare_op0 = operands[0];
- i386_compare_op1 = operands[1];
+ i386_compare_op1 = (immediate_operand (operands[1], DFmode))
+ ? copy_to_mode_reg (DFmode, operands[1]) : operands[1];
DONE;
}")
(define_expand "cmpsf"
[(set (cc0)
(compare (match_operand:SF 0 "register_operand" "")
- (match_operand:SF 1 "nonimmediate_operand" "")))]
+ (match_operand:SF 1 "general_operand" "")))]
"TARGET_80387"
"
{
i386_compare_gen = gen_cmpsf_cc;
i386_compare_gen_eq = gen_cmpsf_ccfpeq;
i386_compare_op0 = operands[0];
- i386_compare_op1 = operands[1];
+ i386_compare_op1 = (immediate_operand (operands[1], SFmode))
+ ? copy_to_mode_reg (SFmode, operands[1]) : operands[1];
DONE;
}")
@@ -573,11 +657,7 @@
(match_operand:XF 1 "register_operand" "")))
(clobber (match_scratch:HI 2 ""))])]
"TARGET_80387"
- "
-{
- if (! register_operand (operands[1], XFmode))
- operands[1] = copy_to_mode_reg (XFmode, operands[1]);
-}")
+ "")
(define_expand "cmpdf_cc"
[(parallel [(set (cc0)
@@ -624,7 +704,7 @@
(define_insn ""
[(set (cc0)
(and:SI (match_operand:SI 0 "general_operand" "%ro")
- (match_operand:SI 1 "general_operand" "ri")))]
+ (match_operand:SI 1 "nonmemory_operand" "ri")))]
""
"*
{
@@ -682,7 +762,7 @@
(define_insn ""
[(set (cc0)
(and:HI (match_operand:HI 0 "general_operand" "%ro")
- (match_operand:HI 1 "general_operand" "ri")))]
+ (match_operand:HI 1 "nonmemory_operand" "ri")))]
""
"*
{
@@ -715,6 +795,12 @@
}
}
+ /* use 32-bit test instruction if there are no sign issues */
+ if (GET_CODE (operands[1]) == CONST_INT
+ && !(INTVAL (operands[1]) & ~0x7fff)
+ && i386_aligned_p (operands[0]))
+ return AS2 (test%L0,%1,%k0);
+
if (CONSTANT_P (operands[1]) || GET_CODE (operands[0]) == MEM)
return AS2 (test%W0,%1,%0);
@@ -723,8 +809,8 @@
(define_insn ""
[(set (cc0)
- (and:QI (match_operand:QI 0 "general_operand" "%qm")
- (match_operand:QI 1 "general_operand" "qi")))]
+ (and:QI (match_operand:QI 0 "nonimmediate_operand" "%qm")
+ (match_operand:QI 1 "nonmemory_operand" "qi")))]
""
"*
{
@@ -741,24 +827,23 @@
(define_insn ""
[(set (match_operand:SI 0 "push_operand" "=<")
- (match_operand:SI 1 "general_operand" "g"))]
- "TARGET_386"
- "push%L0 %1")
-
-;; On a 486, it is faster to move MEM to a REG and then push, rather than
-;; push MEM directly.
+ (match_operand:SI 1 "nonmemory_operand" "rn"))]
+ "flag_pic"
+ "* return AS1 (push%L0,%1);")
(define_insn ""
[(set (match_operand:SI 0 "push_operand" "=<")
(match_operand:SI 1 "nonmemory_operand" "ri"))]
- "!TARGET_386 && TARGET_MOVE"
- "push%L0 %1")
+ "!flag_pic"
+ "* return AS1 (push%L0,%1);")
+
+;; On a 386, it is faster to push MEM directly.
(define_insn ""
[(set (match_operand:SI 0 "push_operand" "=<")
- (match_operand:SI 1 "general_operand" "ri"))]
- "!TARGET_386 && !TARGET_MOVE"
- "push%L0 %1")
+ (match_operand:SI 1 "memory_operand" "m"))]
+ "TARGET_PUSH_MEMORY"
+ "* return AS1 (push%L0,%1);")
;; General case of fullword move.
@@ -790,8 +875,10 @@
(define_insn ""
[(set (match_operand:SI 0 "general_operand" "=g,r")
- (match_operand:SI 1 "general_operand" "ri,m"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+ (match_operand:SI 1 "general_operand" "rn,im"))]
+ "((!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
+ || (GET_CODE (operands[1]) != MEM))
+ && flag_pic"
"*
{
rtx link;
@@ -810,29 +897,50 @@
/* Fastest way to change a 0 to a 1. */
return AS1 (inc%L0,%0);
- if (flag_pic && SYMBOLIC_CONST (operands[1]))
+ if (SYMBOLIC_CONST (operands[1]))
return AS2 (lea%L0,%a1,%0);
return AS2 (mov%L0,%1,%0);
}")
(define_insn ""
- [(set (match_operand:HI 0 "push_operand" "=<")
- (match_operand:HI 1 "general_operand" "g"))]
- "TARGET_386"
- "push%W0 %1")
+ [(set (match_operand:SI 0 "general_operand" "=g,r")
+ (match_operand:SI 1 "general_operand" "ri,m"))]
+ "((!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
+ || (GET_CODE (operands[1]) != MEM))
+ && !flag_pic"
+ "*
+{
+ rtx link;
+ if (operands[1] == const0_rtx && REG_P (operands[0]))
+ return AS2 (xor%L0,%0,%0);
+
+ if (operands[1] == const1_rtx
+ && (link = find_reg_note (insn, REG_WAS_0, 0))
+ /* Make sure the insn that stored the 0 is still present. */
+ && ! INSN_DELETED_P (XEXP (link, 0))
+ && GET_CODE (XEXP (link, 0)) != NOTE
+ /* Make sure cross jumping didn't happen here. */
+ && no_labels_between_p (XEXP (link, 0), insn)
+ /* Make sure the reg hasn't been clobbered. */
+ && ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
+ /* Fastest way to change a 0 to a 1. */
+ return AS1 (inc%L0,%0);
+
+ return AS2 (mov%L0,%1,%0);
+}")
(define_insn ""
[(set (match_operand:HI 0 "push_operand" "=<")
(match_operand:HI 1 "nonmemory_operand" "ri"))]
- "!TARGET_386 && TARGET_MOVE"
- "push%W0 %1")
+ ""
+ "* return AS1 (push%W0,%1);")
(define_insn ""
[(set (match_operand:HI 0 "push_operand" "=<")
- (match_operand:HI 1 "general_operand" "ri"))]
- "!TARGET_386 && !TARGET_MOVE"
- "push%W0 %1")
+ (match_operand:HI 1 "memory_operand" "m"))]
+ "TARGET_PUSH_MEMORY"
+ "* return AS1 (push%W0,%1);")
;; On i486, an incl and movl are both faster than incw and movw.
@@ -876,10 +984,21 @@
if (REG_P (operands[0]))
{
- if (REG_P (operands[1]))
- return AS2 (mov%L0,%k1,%k0);
- else if (CONSTANT_P (operands[1]))
- return AS2 (mov%L0,%1,%k0);
+ if (i386_aligned_p (operands[1]))
+ {
+ operands[1] = i386_sext16_if_const (operands[1]);
+ return AS2 (mov%L0,%k1,%k0);
+ }
+ if (TARGET_PENTIUMPRO)
+ {
+ /* movzwl is faster than movw on the Pentium Pro,
+ * although not as fast as an aligned movl. */
+#ifdef INTEL_SYNTAX
+ return AS2 (movzx,%1,%k0);
+#else
+ return AS2 (movz%W0%L0,%1,%k0);
+#endif
+ }
}
return AS2 (mov%W0,%1,%0);
@@ -932,27 +1051,17 @@
;; the amount pushed up to a halfword.
(define_insn ""
[(set (match_operand:QI 0 "push_operand" "=<")
- (match_operand:QI 1 "immediate_operand" "n"))]
+ (match_operand:QI 1 "const_int_operand" "n"))]
""
- "* return AS1 (push%W0,%1);")
-
-(define_insn ""
- [(set (match_operand:QI 0 "push_operand" "=<")
- (match_operand:QI 1 "nonimmediate_operand" "q"))]
- "!TARGET_MOVE"
- "*
-{
- operands[1] = gen_rtx (REG, HImode, REGNO (operands[1]));
- return AS1 (push%W0,%1);
-}")
+ "* return AS1(push%W0,%1);")
(define_insn ""
[(set (match_operand:QI 0 "push_operand" "=<")
(match_operand:QI 1 "register_operand" "q"))]
- "TARGET_MOVE"
+ ""
"*
{
- operands[1] = gen_rtx (REG, HImode, REGNO (operands[1]));
+ operands[1] = gen_rtx_REG (HImode, REGNO (operands[1]));
return AS1 (push%W0,%1);
}")
@@ -978,14 +1087,14 @@
}")
(define_insn ""
- [(set (match_operand:QI 0 "general_operand" "=q,*r,qm")
- (match_operand:QI 1 "general_operand" "*g,q,qn"))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=q,*r,qm")
+ (match_operand:QI 1 "general_operand" "*g,*rn,qn"))]
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
{
rtx link;
if (operands[1] == const0_rtx && REG_P (operands[0]))
- return AS2 (xor%B0,%0,%0);
+ return AS2 (xor%L0,%k0,%k0);
if (operands[1] == const1_rtx
&& (link = find_reg_note (insn, REG_WAS_0, 0))
@@ -996,8 +1105,14 @@
&& no_labels_between_p (XEXP (link, 0), insn)
/* Make sure the reg hasn't been clobbered. */
&& ! reg_set_between_p (operands[0], XEXP (link, 0), insn))
- /* Fastest way to change a 0 to a 1. */
- return AS1 (inc%B0,%0);
+ {
+ /* Fastest way to change a 0 to a 1.
+ If inc%B0 isn't allowed, use inc%L0. */
+ if (NON_QI_REG_P (operands[0]))
+ return AS1 (inc%L0,%k0);
+ else
+ return AS1 (inc%B0,%0);
+ }
/* If mov%B0 isn't allowed for one of these regs, use mov%L0. */
if (NON_QI_REG_P (operands[0]) || NON_QI_REG_P (operands[1]))
@@ -1032,7 +1147,7 @@
}")
(define_insn ""
- [(set (strict_low_part (match_operand:QI 0 "general_operand" "+qm,q"))
+ [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q"))
(match_operand:QI 1 "general_operand" "*qn,m"))]
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
@@ -1042,6 +1157,7 @@
return AS2 (xor%B0,%0,%0);
if (operands[1] == const1_rtx
+ && ! NON_QI_REG_P (operands[0])
&& (link = find_reg_note (insn, REG_WAS_0, 0))
/* Make sure the insn that stored the 0 is still present. */
&& ! INSN_DELETED_P (XEXP (link, 0))
@@ -1063,43 +1179,10 @@
return AS2 (mov%B0,%1,%0);
}")
-(define_expand "movsf"
- [(set (match_operand:SF 0 "general_operand" "")
- (match_operand:SF 1 "general_operand" ""))]
- ""
- "
-{
- /* Special case memory->memory moves and pushes */
- if (TARGET_MOVE
- && (reload_in_progress | reload_completed) == 0
- && GET_CODE (operands[0]) == MEM
- && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], SFmode)))
- {
- rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], SFmode))
- ? gen_movsf_push
- : gen_movsf_mem;
-
- emit_insn ((*genfunc) (operands[0], operands[1]));
- DONE;
- }
-
- /* If we are loading a floating point constant that isn't 0 or 1 into a register,
- indicate we need the pic register loaded. This could be optimized into stores
- of constants if the target eventually moves to memory, but better safe than
- sorry. */
- if (flag_pic
- && GET_CODE (operands[0]) != MEM
- && GET_CODE (operands[1]) == CONST_DOUBLE
- && !standard_80387_constant_p (operands[1]))
- {
- current_function_uses_pic_offset_table = 1;
- }
-}")
-
-(define_insn "movsf_push_nomove"
+(define_insn "movsf_push"
[(set (match_operand:SF 0 "push_operand" "=<,<")
- (match_operand:SF 1 "general_operand" "gF,f"))]
- "!TARGET_MOVE"
+ (match_operand:SF 1 "general_operand" "*rfF,m"))]
+ "GET_CODE (operands[1]) != MEM || reload_in_progress || reload_completed"
"*
{
if (STACK_REG_P (operands[1]))
@@ -1119,64 +1202,62 @@
output_asm_insn (AS1 (fstp%S0,%0), xops);
else
output_asm_insn (AS1 (fst%S0,%0), xops);
+
RET;
}
- return AS1 (push%L1,%1);
+
+ return AS1 (push%L0,%1);
}")
-(define_insn "movsf_push"
- [(set (match_operand:SF 0 "push_operand" "=<,<,<,<")
- (match_operand:SF 1 "general_operand" "rF,f,m,m"))
- (clobber (match_scratch:SI 2 "=X,X,r,X"))]
+(define_insn "movsf_push_memory"
+ [(set (match_operand:SF 0 "push_operand" "=<")
+ (match_operand:SF 1 "memory_operand" "m"))]
+ "TARGET_PUSH_MEMORY"
+ "* return AS1 (push%L0,%1);")
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "general_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
""
- "*
+ "
{
- if (STACK_REG_P (operands[1]))
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
{
- rtx xops[3];
+ operands[1] = force_reg (SFmode, operands[1]);
+ }
- if (! STACK_TOP_P (operands[1]))
- abort ();
+ /* If we are loading a floating point constant that isn't 0 or 1
+ into a register, indicate we need the pic register loaded. This could
+ be optimized into stores of constants if the target eventually moves
+ to memory, but better safe than sorry. */
+ else if ((reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) != MEM
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && !standard_80387_constant_p (operands[1]))
+ {
+ rtx insn, note, fp_const;
- xops[0] = AT_SP (SFmode);
- xops[1] = GEN_INT (4);
- xops[2] = stack_pointer_rtx;
+ fp_const = force_const_mem (SFmode, operands[1]);
+ if (flag_pic)
+ current_function_uses_pic_offset_table = 1;
- output_asm_insn (AS2 (sub%L2,%1,%2), xops);
+ insn = emit_insn (gen_rtx_SET (SFmode, operands[0], fp_const));
+ note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
- output_asm_insn (AS1 (fstp%S0,%0), xops);
+ if (note)
+ XEXP (note, 0) = operands[1];
else
- output_asm_insn (AS1 (fst%S0,%0), xops);
- RET;
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1], REG_NOTES (insn));
}
-
- else if (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != REG)
- return AS1 (push%L1,%1);
-
- else
- {
- output_asm_insn (AS2 (mov%L2,%1,%2), operands);
- return AS1 (push%L2,%2);
- }
-}")
-
-;; Special memory<->memory pattern that combine will recreate from the
-;; moves to pseudos.
-(define_insn "movsf_mem"
- [(set (match_operand:SF 0 "memory_operand" "=m")
- (match_operand:SF 1 "memory_operand" "m"))
- (clobber (match_scratch:SI 2 "=&r"))]
- ""
- "*
-{
- output_asm_insn (AS2 (mov%L2,%1,%2), operands);
- return AS2 (mov%L0,%2,%0);
}")
;; For the purposes of regclass, prefer FLOAT_REGS.
-(define_insn "movsf_normal"
- [(set (match_operand:SF 0 "general_operand" "=*rfm,*rf,f,!*rm")
+(define_insn ""
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=*rfm,*rf,f,!*rm")
(match_operand:SF 1 "general_operand" "*rf,*rfm,fG,fF"))]
"(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
"*
@@ -1203,7 +1284,7 @@
if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0]))
{
- output_to_reg (operands[0], stack_top_dies);
+ output_to_reg (operands[0], stack_top_dies, 0);
RET;
}
@@ -1228,7 +1309,9 @@
/* Handle all SFmode moves not involving the 387 */
return singlemove_string (operands);
-}")
+}"
+ [(set_attr "type" "fld")])
+
(define_insn "swapsf"
[(set (match_operand:SF 0 "register_operand" "f")
@@ -1244,50 +1327,17 @@
return AS1 (fxch,%0);
}")
-(define_expand "movdf"
- [(set (match_operand:DF 0 "general_operand" "")
- (match_operand:DF 1 "general_operand" ""))]
- ""
- "
-{
- /* Special case memory->memory moves and pushes */
- if (TARGET_MOVE
- && (reload_in_progress | reload_completed) == 0
- && GET_CODE (operands[0]) == MEM
- && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], DFmode)))
- {
- rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], DFmode))
- ? gen_movdf_push
- : gen_movdf_mem;
-
- emit_insn ((*genfunc) (operands[0], operands[1]));
- DONE;
- }
-
- /* If we are loading a floating point constant that isn't 0 or 1 into a register,
- indicate we need the pic register loaded. This could be optimized into stores
- of constants if the target eventually moves to memory, but better safe than
- sorry. */
- if (flag_pic
- && GET_CODE (operands[0]) != MEM
- && GET_CODE (operands[1]) == CONST_DOUBLE
- && !standard_80387_constant_p (operands[1]))
- {
- current_function_uses_pic_offset_table = 1;
- }
-}")
-
-(define_insn "movdf_push_nomove"
+(define_insn "movdf_push"
[(set (match_operand:DF 0 "push_operand" "=<,<")
- (match_operand:DF 1 "general_operand" "gF,f"))]
- "!TARGET_MOVE"
+ (match_operand:DF 1 "general_operand" "*rfF,o"))]
+ "GET_CODE (operands[1]) != MEM || reload_in_progress || reload_completed"
"*
{
if (STACK_REG_P (operands[1]))
{
rtx xops[3];
- xops[0] = AT_SP (SFmode);
+ xops[0] = AT_SP (DFmode);
xops[1] = GEN_INT (8);
xops[2] = stack_pointer_rtx;
@@ -1300,56 +1350,65 @@
RET;
}
- else
- return output_move_double (operands);
+
+ if (which_alternative == 1)
+ return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 0, 0);
+
+ return output_move_double (operands);
}")
-(define_insn "movdf_push"
- [(set (match_operand:DF 0 "push_operand" "=<,<,<,<,<")
- (match_operand:DF 1 "general_operand" "rF,f,o,o,o"))
- (clobber (match_scratch:SI 2 "=X,X,&r,&r,X"))
- (clobber (match_scratch:SI 3 "=X,X,&r,X,X"))]
+(define_insn "movdf_push_memory"
+ [(set (match_operand:DF 0 "push_operand" "=<")
+ (match_operand:DF 1 "memory_operand" "o"))]
+ "TARGET_PUSH_MEMORY"
+ "* return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode),0,0);")
+
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "general_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
""
- "*
+ "
{
- if (STACK_REG_P (operands[1]))
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
{
- rtx xops[3];
+ operands[1] = force_reg (DFmode, operands[1]);
+ }
- xops[0] = AT_SP (SFmode);
- xops[1] = GEN_INT (8);
- xops[2] = stack_pointer_rtx;
+ /* If we are loading a floating point constant that isn't 0 or 1 into a
+ register, indicate we need the pic register loaded. This could be
+ optimized into stores of constants if the target eventually moves to
+ memory, but better safe than sorry. */
+ else if ((reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) != MEM
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && !standard_80387_constant_p (operands[1]))
+ {
+ rtx insn, note, fp_const;
- output_asm_insn (AS2 (sub%L2,%1,%2), xops);
+ fp_const = force_const_mem (DFmode, operands[1]);
+ if (flag_pic)
+ current_function_uses_pic_offset_table = 1;
- if (find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
- output_asm_insn (AS1 (fstp%Q0,%0), xops);
- else
- output_asm_insn (AS1 (fst%Q0,%0), xops);
+ insn = emit_insn (gen_rtx_SET (DFmode, operands[0], fp_const));
+ note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- RET;
+ if (note)
+ XEXP (note, 0) = operands[1];
+ else
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1], REG_NOTES (insn));
}
-
- else if (GET_CODE (operands[1]) != MEM)
- return output_move_double (operands);
-
- else
- return output_move_pushmem (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);
}")
-(define_insn "movdf_mem"
- [(set (match_operand:DF 0 "memory_operand" "=o,o")
- (match_operand:DF 1 "memory_operand" "o,o"))
- (clobber (match_scratch:SI 2 "=&r,&r"))
- (clobber (match_scratch:SI 3 "=&r,X"))]
- ""
- "* return output_move_memory (operands, insn, GET_MODE_SIZE (DFmode), 2, 4);")
-
;; For the purposes of regclass, prefer FLOAT_REGS.
-(define_insn "movdf_normal"
- [(set (match_operand:DF 0 "general_operand" "=f,fm,!*rf,!*rm")
+(define_insn ""
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,fm,!*rf,!*rm")
(match_operand:DF 1 "general_operand" "fmG,f,*rfm,*rfF"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
+ || (GET_CODE (operands[1]) != MEM)"
"*
{
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
@@ -1374,7 +1433,7 @@
if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0]))
{
- output_to_reg (operands[0], stack_top_dies);
+ output_to_reg (operands[0], stack_top_dies, 0);
RET;
}
@@ -1399,7 +1458,10 @@
/* Handle all DFmode moves not involving the 387 */
return output_move_double (operands);
-}")
+}"
+ [(set_attr "type" "fld")])
+
+
(define_insn "swapdf"
[(set (match_operand:DF 0 "register_operand" "f")
@@ -1415,109 +1477,87 @@
return AS1 (fxch,%0);
}")
-(define_expand "movxf"
- [(set (match_operand:XF 0 "general_operand" "")
- (match_operand:XF 1 "general_operand" ""))]
- ""
- "
-{
- /* Special case memory->memory moves and pushes */
- if (TARGET_MOVE
- && (reload_in_progress | reload_completed) == 0
- && GET_CODE (operands[0]) == MEM
- && (GET_CODE (operands[1]) == MEM || push_operand (operands[0], XFmode)))
- {
- rtx (*genfunc) PROTO((rtx, rtx)) = (push_operand (operands[0], XFmode))
- ? gen_movxf_push
- : gen_movxf_mem;
-
- emit_insn ((*genfunc) (operands[0], operands[1]));
- DONE;
- }
-
- /* If we are loading a floating point constant that isn't 0 or 1 into a register,
- indicate we need the pic register loaded. This could be optimized into stores
- of constants if the target eventually moves to memory, but better safe than
- sorry. */
- if (flag_pic
- && GET_CODE (operands[0]) != MEM
- && GET_CODE (operands[1]) == CONST_DOUBLE
- && !standard_80387_constant_p (operands[1]))
- {
- current_function_uses_pic_offset_table = 1;
- }
-}")
-
-
-(define_insn "movxf_push_nomove"
+(define_insn "movxf_push"
[(set (match_operand:XF 0 "push_operand" "=<,<")
- (match_operand:XF 1 "general_operand" "gF,f"))]
- "!TARGET_MOVE"
+ (match_operand:XF 1 "general_operand" "*rfF,o"))]
+ "GET_CODE (operands[1]) != MEM || reload_in_progress || reload_completed"
"*
{
if (STACK_REG_P (operands[1]))
{
rtx xops[3];
- xops[0] = AT_SP (SFmode);
+ xops[0] = AT_SP (XFmode);
xops[1] = GEN_INT (12);
xops[2] = stack_pointer_rtx;
output_asm_insn (AS2 (sub%L2,%1,%2), xops);
+
output_asm_insn (AS1 (fstp%T0,%0), xops);
if (! find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
output_asm_insn (AS1 (fld%T0,%0), xops);
RET;
}
- else
- return output_move_double (operands);
+
+ if (which_alternative == 1)
+ return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 0, 0);
+
+ return output_move_double (operands);
}")
-(define_insn "movxf_push"
- [(set (match_operand:XF 0 "push_operand" "=<,<,<,<,<")
- (match_operand:XF 1 "general_operand" "rF,f,o,o,o"))
- (clobber (match_scratch:SI 2 "=X,X,&r,&r,X"))
- (clobber (match_scratch:SI 3 "=X,X,&r,X,X"))]
+(define_insn "movxf_push_memory"
+ [(set (match_operand:XF 0 "push_operand" "=<")
+ (match_operand:XF 1 "memory_operand" "o"))]
+ "TARGET_PUSH_MEMORY"
+ "* return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode),0,0);")
+
+(define_expand "movxf"
+ [(set (match_operand:XF 0 "general_operand" "")
+ (match_operand:XF 1 "general_operand" ""))]
""
- "*
+ "
{
- if (STACK_REG_P (operands[1]))
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
{
- rtx xops[3];
-
- xops[0] = AT_SP (SFmode);
- xops[1] = GEN_INT (12);
- xops[2] = stack_pointer_rtx;
+ operands[1] = force_reg (XFmode, operands[1]);
+ }
- output_asm_insn (AS2 (sub%L2,%1,%2), xops);
- output_asm_insn (AS1 (fstp%T0,%0), xops);
- if (! find_regno_note (insn, REG_DEAD, FIRST_STACK_REG))
- output_asm_insn (AS1 (fld%T0,%0), xops);
+ /* If we are loading a floating point constant that isn't 0 or 1
+ into a register, indicate we need the pic register loaded. This could
+ be optimized into stores of constants if the target eventually moves
+ to memory, but better safe than sorry. */
+ else if ((reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) != MEM
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && !standard_80387_constant_p (operands[1]))
+ {
+ rtx insn, note, fp_const;
- RET;
- }
+ fp_const = force_const_mem (XFmode, operands[1]);
+ if (flag_pic)
+ current_function_uses_pic_offset_table = 1;
- else if (GET_CODE (operands[1]) != MEM
- || GET_CODE (operands[2]) != REG)
- return output_move_double (operands);
+ insn = emit_insn (gen_rtx_SET (XFmode, operands[0], fp_const));
+ note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- else
- return output_move_pushmem (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);
+ if (note)
+ XEXP (note, 0) = operands[1];
+ else
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1], REG_NOTES (insn));
+ }
}")
-(define_insn "movxf_mem"
- [(set (match_operand:XF 0 "memory_operand" "=o,o")
- (match_operand:XF 1 "memory_operand" "o,o"))
- (clobber (match_scratch:SI 2 "=&r,&r"))
- (clobber (match_scratch:SI 3 "=&r,X"))]
- ""
- "* return output_move_memory (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);")
-(define_insn "movxf_normal"
- [(set (match_operand:XF 0 "general_operand" "=f,fm,!*rf,!*rm")
+(define_insn ""
+ [(set (match_operand:XF 0 "nonimmediate_operand" "=f,fm,!*rf,!*rm")
(match_operand:XF 1 "general_operand" "fmG,f,*rfm,*rfF"))]
- "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
+ || (GET_CODE (operands[1]) != MEM)"
"*
{
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
@@ -1542,7 +1582,7 @@
if (STACK_TOP_P (operands[1]) && NON_STACK_REG_P (operands[0]))
{
- output_to_reg (operands[0], stack_top_dies);
+ output_to_reg (operands[0], stack_top_dies, 0);
RET;
}
@@ -1570,7 +1610,7 @@
return output_move_double (operands);
}")
-(define_insn "swapxf"
+(define_insn "swapxf"
[(set (match_operand:XF 0 "register_operand" "f")
(match_operand:XF 1 "register_operand" "f"))
(set (match_dup 1)
@@ -1585,36 +1625,40 @@
}")
(define_insn ""
- [(set (match_operand:DI 0 "push_operand" "=<,<,<,<")
- (match_operand:DI 1 "general_operand" "riF,o,o,o"))
- (clobber (match_scratch:SI 2 "=X,&r,&r,X"))
- (clobber (match_scratch:SI 3 "=X,&r,X,X"))]
+ [(set (match_operand:DI 0 "push_operand" "=<")
+ (match_operand:DI 1 "general_operand" "riF"))]
""
- "*
-{
- if (GET_CODE (operands[1]) != MEM)
- return output_move_double (operands);
+ "* return output_move_double (operands);")
- else
- return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode), 2, 4);
-}")
+(define_insn ""
+ [(set (match_operand:DI 0 "push_operand" "=<")
+ (match_operand:DI 1 "memory_operand" "o"))]
+ "TARGET_PUSH_MEMORY"
+ "* return output_move_pushmem (operands, insn, GET_MODE_SIZE (DImode),0,0);")
-(define_insn "movdi"
- [(set (match_operand:DI 0 "general_operand" "=o,o,r,rm")
- (match_operand:DI 1 "general_operand" "o,o,m,riF"))
- (clobber (match_scratch:SI 2 "=&r,&r,X,X"))
- (clobber (match_scratch:SI 3 "=&r,X,X,X"))]
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "general_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
""
- "*
+ "
{
- rtx low[2], high[2], xop[6];
-
- if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
- return output_move_double (operands);
- else
- return output_move_memory (operands, insn, GET_MODE_SIZE (DImode), 2, 4);
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ operands[1] = force_reg (DImode, operands[1]);
+ }
}")
+(define_insn ""
+ [(set (match_operand:DI 0 "general_operand" "=g,r")
+ (match_operand:DI 1 "general_operand" "riF,m"))]
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM)
+ || (GET_CODE (operands[1]) != MEM)"
+ "* return output_move_double (operands);")
+
;;- conversion instructions
;;- NONE
@@ -1623,21 +1667,39 @@
;; See comments by `andsi' for when andl is faster than movzx.
(define_insn "zero_extendhisi2"
- [(set (match_operand:SI 0 "general_operand" "=r")
- (zero_extend:SI
- (match_operand:HI 1 "nonimmediate_operand" "rm")))]
+ [(set (match_operand:SI 0 "register_operand" "=r,&r,?r")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,rm,rm")))]
""
"*
-{
- if ((!TARGET_386 || REGNO (operands[0]) == 0)
+ {
+ rtx xops[2];
+
+ if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
&& REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
{
- rtx xops[2];
xops[0] = operands[0];
xops[1] = GEN_INT (0xffff);
output_asm_insn (AS2 (and%L0,%1,%k0), xops);
RET;
}
+ if (TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1]))
+ {
+ output_asm_insn (AS2 (xor%L0,%0,%0),operands);
+ output_asm_insn (AS2 (mov%W0,%1,%w0),operands);
+ RET;
+ }
+
+ if (TARGET_ZERO_EXTEND_WITH_AND)
+ {
+ xops[0] = operands[0];
+ xops[1] = GEN_INT (0xffff);
+ if (i386_aligned_p (operands[1]))
+ output_asm_insn (AS2 (mov%L0,%k1,%k0),operands);
+ else
+ output_asm_insn (AS2 (mov%W0,%1,%w0),operands);
+ output_asm_insn (AS2 (and%L0,%1,%k0), xops);
+ RET;
+ }
#ifdef INTEL_SYNTAX
return AS2 (movzx,%1,%0);
@@ -1646,23 +1708,62 @@
#endif
}")
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
+ "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (match_dup 0)
+ (const_int 0))
+ (set (strict_low_part (match_dup 2))
+ (match_dup 1))]
+ "operands[2] = gen_rtx_REG (HImode, true_regnum (operands[0]));")
+
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:HI 1 "memory_operand" "")))]
+ "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (strict_low_part (match_dup 2))
+ (match_dup 1))
+ (set (match_dup 0)
+ (and:SI (match_dup 0)
+ (const_int 65535)))]
+ "operands[2] = gen_rtx_REG (HImode, true_regnum (operands[0]));")
+
(define_insn "zero_extendqihi2"
- [(set (match_operand:HI 0 "general_operand" "=r")
- (zero_extend:HI
- (match_operand:QI 1 "nonimmediate_operand" "qm")))]
+ [(set (match_operand:HI 0 "register_operand" "=q,&q,?r")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))]
""
"*
-{
- if ((!TARGET_386 || REGNO (operands[0]) == 0)
- && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
+ {
+ rtx xops[2];
+
+ if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
+ && REG_P (operands[1])
+ && REGNO (operands[0]) == REGNO (operands[1]))
{
- rtx xops[2];
xops[0] = operands[0];
xops[1] = GEN_INT (0xff);
output_asm_insn (AS2 (and%L0,%1,%k0), xops);
RET;
}
-
+ if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0]))
+ {
+ if(!reg_overlap_mentioned_p(operands[0],operands[1]))
+ {
+ output_asm_insn (AS2 (xor%L0,%k0,%k0), operands);
+ output_asm_insn (AS2 (mov%B0,%1,%b0), operands);
+ }
+ else
+ {
+ xops[0] = operands[0];
+ xops[1] = GEN_INT (0xff);
+ output_asm_insn (AS2 (mov%B0,%1,%b0),operands);
+ output_asm_insn (AS2 (and%L0,%1,%k0), xops);
+ }
+ RET;
+ }
+
#ifdef INTEL_SYNTAX
return AS2 (movzx,%1,%0);
#else
@@ -1670,22 +1771,89 @@
#endif
}")
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
+ "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
+ && !reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (match_dup 0)
+ (const_int 0))
+ (set (strict_low_part (match_dup 2))
+ (match_dup 1))]
+ "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
+
+
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (zero_extend:HI (match_operand:QI 1 "memory_operand" "")))]
+ "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
+ && reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (strict_low_part (match_dup 2))
+ (match_dup 1))
+ (set (match_dup 0)
+ (and:HI (match_dup 0)
+ (const_int 255)))]
+ "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
+
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (zero_extend:HI (match_operand:QI 1 "register_operand" "")))]
+ "reload_completed && TARGET_ZERO_EXTEND_WITH_AND"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (and:HI (match_dup 0)
+ (const_int 255)))]
+ "if (GET_CODE (operands[1]) == SUBREG && SUBREG_WORD (operands[1]) == 0)
+ operands[1] = SUBREG_REG (operands[1]);
+ if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG
+ || REGNO (operands[0]) == REGNO (operands[1]))
+ FAIL;
+ operands[2] = gen_rtx_REG (HImode, REGNO (operands[1]));")
+
(define_insn "zero_extendqisi2"
- [(set (match_operand:SI 0 "general_operand" "=r")
- (zero_extend:SI
- (match_operand:QI 1 "nonimmediate_operand" "qm")))]
+ [(set (match_operand:SI 0 "register_operand" "=q,&q,?r")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))]
""
"*
-{
- if ((!TARGET_386 || REGNO (operands[0]) == 0)
- && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
+ {
+ rtx xops[2];
+
+ if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
+ && REG_P (operands[1])
+ && REGNO (operands[0]) == REGNO (operands[1]))
{
- rtx xops[2];
xops[0] = operands[0];
xops[1] = GEN_INT (0xff);
output_asm_insn (AS2 (and%L0,%1,%k0), xops);
RET;
}
+ if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0]))
+ {
+ if(!reg_overlap_mentioned_p (operands[0], operands[1]))
+ {
+ output_asm_insn (AS2 (xor%L0,%0,%0),operands);
+ output_asm_insn (AS2 (mov%B0,%1,%b0),operands);
+ }
+ else
+ {
+ xops[0] = operands[0];
+ xops[1] = GEN_INT (0xff);
+ output_asm_insn (AS2 (mov%B0,%1,%b0), operands);
+ output_asm_insn (AS2 (and%L0,%1,%k0), xops);
+ }
+ RET;
+ }
+
+ if (TARGET_ZERO_EXTEND_WITH_AND && GET_CODE (operands[1]) == REG)
+ {
+ xops[0] = operands[0];
+ xops[1] = GEN_INT (0xff);
+ operands[1] = gen_rtx_REG (SImode, REGNO (operands[1]));
+ output_asm_insn (AS2 (mov%L0,%1,%0), operands);
+ output_asm_insn (AS2 (and%L0,%1,%k0), xops);
+ RET;
+ }
#ifdef INTEL_SYNTAX
return AS2 (movzx,%1,%0);
@@ -1694,23 +1862,77 @@
#endif
}")
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
+ "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
+ && !reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (match_dup 0)
+ (const_int 0))
+ (set (strict_low_part (match_dup 2))
+ (match_dup 1))]
+ "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
+
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:QI 1 "memory_operand" "")))]
+ "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
+ && reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (strict_low_part (match_dup 2))
+ (match_dup 1))
+ (set (match_dup 0)
+ (and:SI (match_dup 0)
+ (const_int 255)))]
+ "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:QI 1 "register_operand" "")))]
+ "reload_completed && TARGET_ZERO_EXTEND_WITH_AND
+ && ! reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (match_dup 0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (and:SI (match_dup 0)
+ (const_int 255)))]
+ "operands[2] = gen_rtx_REG (SImode, true_regnum (operands[1]));")
+
(define_insn "zero_extendsidi2"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (zero_extend:DI
- (match_operand:SI 1 "register_operand" "0")))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?m")
+ (zero_extend:DI (match_operand:SI 1 "register_operand" "0,rm,r")))]
""
"*
-{
- operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
- return AS2 (xor%L0,%0,%0);
+ {
+ rtx high[2], low[2], xops[4];
+
+ if (REG_P (operands[0]) && REG_P (operands[1])
+ && REGNO (operands[0]) == REGNO (operands[1]))
+ {
+ operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
+ return AS2 (xor%L0,%0,%0);
+ }
+
+ split_di (operands, 1, low, high);
+ xops[0] = low[0];
+ xops[1] = operands[1];
+ xops[2] = high[0];
+ xops[3] = const0_rtx;
+
+ output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+ if (GET_CODE (low[0]) == MEM)
+ output_asm_insn (AS2 (mov%L2,%3,%2), xops);
+ else
+ output_asm_insn (AS2 (xor%L2,%2,%2), xops);
+
+ RET;
}")
;;- sign extension instructions
(define_insn "extendsidi2"
[(set (match_operand:DI 0 "register_operand" "=r")
- (sign_extend:DI
- (match_operand:SI 1 "register_operand" "0")))]
+ (sign_extend:DI (match_operand:SI 1 "register_operand" "0")))]
""
"*
{
@@ -1724,7 +1946,7 @@
#endif
}
- operands[1] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
+ operands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
output_asm_insn (AS2 (mov%L0,%0,%1), operands);
operands[0] = GEN_INT (31);
@@ -1736,9 +1958,8 @@
;; We use what the Unix assembler expects.
(define_insn "extendhisi2"
- [(set (match_operand:SI 0 "general_operand" "=r")
- (sign_extend:SI
- (match_operand:HI 1 "nonimmediate_operand" "rm")))]
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
""
"*
{
@@ -1758,9 +1979,8 @@
}")
(define_insn "extendqihi2"
- [(set (match_operand:HI 0 "general_operand" "=r")
- (sign_extend:HI
- (match_operand:QI 1 "nonimmediate_operand" "qm")))]
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
""
"*
{
@@ -1776,9 +1996,8 @@
}")
(define_insn "extendqisi2"
- [(set (match_operand:SI 0 "general_operand" "=r")
- (sign_extend:SI
- (match_operand:QI 1 "nonimmediate_operand" "qm")))]
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
""
"*
{
@@ -1788,13 +2007,72 @@
return AS2 (movs%B0%L0,%1,%0);
#endif
}")
+
+
+;; Truncation of long long -> 32 bit
+
+(define_expand "truncdisi2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
+ (truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))]
+ ""
+ "
+{
+ /* Don't generate memory->memory moves, go through a register */
+ if (TARGET_MOVE
+ && (reload_in_progress | reload_completed) == 0
+ && GET_CODE (operands[0]) == MEM
+ && GET_CODE (operands[1]) == MEM)
+ {
+ rtx target = gen_reg_rtx (SImode);
+ emit_insn (gen_truncdisi2 (target, operands[1]));
+ emit_move_insn (operands[0], target);
+ DONE;
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
+ (truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))]
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+ "*
+{
+ rtx low[2], high[2], xops[2];
+
+ split_di (&operands[1], 1, low, high);
+ xops[0] = operands[0];
+ xops[1] = low[0];
+ if (!rtx_equal_p (xops[0], xops[1]))
+ output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
+ RET;
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
+ (truncate:SI (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
+ (const_int 32))))]
+ "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+ "*
+{
+ rtx low[2], high[2], xops[2];
+
+ split_di (&operands[1], 1, low, high);
+ xops[0] = operands[0];
+ xops[1] = high[0];
+ if (!rtx_equal_p (xops[0], xops[1]))
+ output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
+ RET;
+}")
+
+
;; Conversions between float and double.
(define_insn "extendsfdf2"
- [(set (match_operand:DF 0 "general_operand" "=fm,f")
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=fm,f")
(float_extend:DF
- (match_operand:SF 1 "general_operand" "f,fm")))]
+ (match_operand:SF 1 "nonimmediate_operand" "f,fm")))]
"TARGET_80387"
"*
{
@@ -1808,7 +2086,7 @@
if (NON_STACK_REG_P (operands[0]))
{
- output_to_reg (operands[0], stack_top_dies);
+ output_to_reg (operands[0], stack_top_dies, 0);
RET;
}
@@ -1827,9 +2105,9 @@
}")
(define_insn "extenddfxf2"
- [(set (match_operand:XF 0 "general_operand" "=fm,f,f,!*r")
+ [(set (match_operand:XF 0 "nonimmediate_operand" "=fm,f,f,!*r")
(float_extend:XF
- (match_operand:DF 1 "general_operand" "f,fm,!*r,f")))]
+ (match_operand:DF 1 "nonimmediate_operand" "f,fm,!*r,f")))]
"TARGET_80387"
"*
{
@@ -1843,7 +2121,7 @@
if (NON_STACK_REG_P (operands[0]))
{
- output_to_reg (operands[0], stack_top_dies);
+ output_to_reg (operands[0], stack_top_dies, 0);
RET;
}
@@ -1862,9 +2140,9 @@
}")
(define_insn "extendsfxf2"
- [(set (match_operand:XF 0 "general_operand" "=fm,f,f,!*r")
+ [(set (match_operand:XF 0 "nonimmediate_operand" "=fm,f,f,!*r")
(float_extend:XF
- (match_operand:SF 1 "general_operand" "f,fm,!*r,f")))]
+ (match_operand:SF 1 "nonimmediate_operand" "f,fm,!*r,f")))]
"TARGET_80387"
"*
{
@@ -1878,7 +2156,7 @@
if (NON_STACK_REG_P (operands[0]))
{
- output_to_reg (operands[0], stack_top_dies);
+ output_to_reg (operands[0], stack_top_dies, 0);
RET;
}
@@ -1939,7 +2217,7 @@
}")
(define_insn "truncxfsf2"
- [(set (match_operand:SF 0 "general_operand" "=m,!*r")
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=m,!*r")
(float_truncate:SF
(match_operand:XF 1 "register_operand" "f,f")))]
"TARGET_80387"
@@ -1954,7 +2232,7 @@
output_asm_insn (AS1 (fld,%y1), operands);
stack_top_dies = 1;
}
- output_to_reg (operands[0], stack_top_dies);
+ output_to_reg (operands[0], stack_top_dies, 0);
RET;
}
else if (GET_CODE (operands[0]) == MEM)
@@ -1972,7 +2250,7 @@
}")
(define_insn "truncxfdf2"
- [(set (match_operand:DF 0 "general_operand" "=m,!*r")
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=m,!*r")
(float_truncate:DF
(match_operand:XF 1 "register_operand" "f,f")))]
"TARGET_80387"
@@ -1987,7 +2265,7 @@
output_asm_insn (AS1 (fld,%y1), operands);
stack_top_dies = 1;
}
- output_to_reg (operands[0], stack_top_dies);
+ output_to_reg (operands[0], stack_top_dies, 0);
RET;
}
else if (GET_CODE (operands[0]) == MEM)
@@ -2029,7 +2307,7 @@
operands[3] = gen_lowpart (SImode, operands[2]);
operands[4] = gen_reg_rtx (XFmode);
operands[5] = (rtx) assign_386_stack_local (SImode, 0);
- operands[6] = (rtx) assign_386_stack_local (SImode, 1);
+ operands[6] = (rtx) assign_386_stack_local (DImode, 1);
}")
(define_expand "fixuns_truncdfsi2"
@@ -2050,7 +2328,7 @@
operands[3] = gen_lowpart (SImode, operands[2]);
operands[4] = gen_reg_rtx (DFmode);
operands[5] = (rtx) assign_386_stack_local (SImode, 0);
- operands[6] = (rtx) assign_386_stack_local (SImode, 1);
+ operands[6] = (rtx) assign_386_stack_local (DImode, 1);
}")
(define_expand "fixuns_truncsfsi2"
@@ -2071,7 +2349,7 @@
operands[3] = gen_lowpart (SImode, operands[2]);
operands[4] = gen_reg_rtx (SFmode);
operands[5] = (rtx) assign_386_stack_local (SImode, 0);
- operands[6] = (rtx) assign_386_stack_local (SImode, 1);
+ operands[6] = (rtx) assign_386_stack_local (DImode, 1);
}")
;; Signed conversion to DImode.
@@ -2091,7 +2369,7 @@
operands[1] = copy_to_mode_reg (XFmode, operands[1]);
operands[2] = gen_reg_rtx (XFmode);
operands[3] = (rtx) assign_386_stack_local (SImode, 0);
- operands[4] = (rtx) assign_386_stack_local (SImode, 1);
+ operands[4] = (rtx) assign_386_stack_local (DImode, 1);
}")
(define_expand "fix_truncdfdi2"
@@ -2109,7 +2387,7 @@
operands[1] = copy_to_mode_reg (DFmode, operands[1]);
operands[2] = gen_reg_rtx (DFmode);
operands[3] = (rtx) assign_386_stack_local (SImode, 0);
- operands[4] = (rtx) assign_386_stack_local (SImode, 1);
+ operands[4] = (rtx) assign_386_stack_local (DImode, 1);
}")
(define_expand "fix_truncsfdi2"
@@ -2127,37 +2405,37 @@
operands[1] = copy_to_mode_reg (SFmode, operands[1]);
operands[2] = gen_reg_rtx (SFmode);
operands[3] = (rtx) assign_386_stack_local (SImode, 0);
- operands[4] = (rtx) assign_386_stack_local (SImode, 1);
+ operands[4] = (rtx) assign_386_stack_local (DImode, 1);
}")
;; These match a signed conversion of either DFmode or SFmode to DImode.
(define_insn ""
- [(set (match_operand:DI 0 "general_operand" "=rm")
- (fix:DI (fix:XF (match_operand:XF 1 "register_operand" "f"))))
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
+ (fix:DI (fix:XF (match_operand:XF 1 "register_operand" "+f"))))
(clobber (match_dup 1))
(clobber (match_operand:SI 2 "memory_operand" "m"))
- (clobber (match_operand:SI 3 "memory_operand" "m"))
+ (clobber (match_operand:DI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
"* return output_fix_trunc (insn, operands);")
(define_insn ""
- [(set (match_operand:DI 0 "general_operand" "=rm")
- (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f"))))
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
+ (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "+f"))))
(clobber (match_dup 1))
(clobber (match_operand:SI 2 "memory_operand" "m"))
- (clobber (match_operand:SI 3 "memory_operand" "m"))
+ (clobber (match_operand:DI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
"* return output_fix_trunc (insn, operands);")
(define_insn ""
- [(set (match_operand:DI 0 "general_operand" "=rm")
- (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
+ (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "+f"))))
(clobber (match_dup 1))
(clobber (match_operand:SI 2 "memory_operand" "m"))
- (clobber (match_operand:SI 3 "memory_operand" "m"))
+ (clobber (match_operand:DI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
"* return output_fix_trunc (insn, operands);")
@@ -2175,7 +2453,7 @@
"
{
operands[2] = (rtx) assign_386_stack_local (SImode, 0);
- operands[3] = (rtx) assign_386_stack_local (SImode, 1);
+ operands[3] = (rtx) assign_386_stack_local (DImode, 1);
}")
(define_expand "fix_truncdfsi2"
@@ -2189,7 +2467,7 @@
"
{
operands[2] = (rtx) assign_386_stack_local (SImode, 0);
- operands[3] = (rtx) assign_386_stack_local (SImode, 1);
+ operands[3] = (rtx) assign_386_stack_local (DImode, 1);
}")
(define_expand "fix_truncsfsi2"
@@ -2203,32 +2481,32 @@
"
{
operands[2] = (rtx) assign_386_stack_local (SImode, 0);
- operands[3] = (rtx) assign_386_stack_local (SImode, 1);
+ operands[3] = (rtx) assign_386_stack_local (DImode, 1);
}")
(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=rm")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(fix:SI (fix:XF (match_operand:XF 1 "register_operand" "f"))))
(clobber (match_operand:SI 2 "memory_operand" "m"))
- (clobber (match_operand:SI 3 "memory_operand" "m"))
+ (clobber (match_operand:DI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
"* return output_fix_trunc (insn, operands);")
(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=rm")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))
(clobber (match_operand:SI 2 "memory_operand" "m"))
- (clobber (match_operand:SI 3 "memory_operand" "m"))
+ (clobber (match_operand:DI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
"* return output_fix_trunc (insn, operands);")
(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=rm")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))
(clobber (match_operand:SI 2 "memory_operand" "m"))
- (clobber (match_operand:SI 3 "memory_operand" "m"))
+ (clobber (match_operand:DI 3 "memory_operand" "m"))
(clobber (match_scratch:SI 4 "=&q"))]
"TARGET_80387"
"* return output_fix_trunc (insn, operands);")
@@ -2271,14 +2549,14 @@
(define_expand "floatdixf2"
[(set (match_operand:XF 0 "register_operand" "")
(float:XF (match_operand:DI 1 "nonimmediate_operand" "")))]
- "TARGET_80387"
+ "TARGET_80387 && LONG_DOUBLE_TYPE_SIZE == 96"
"")
;; This will convert from SImode or DImode to MODE_FLOAT.
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
- (float:XF (match_operand:DI 1 "general_operand" "rm")))]
+ (float:XF (match_operand:DI 1 "nonimmediate_operand" "rm")))]
"TARGET_80387"
"*
{
@@ -2346,7 +2624,7 @@
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f,f")
- (float:XF (match_operand:SI 1 "general_operand" "m,!*r")))]
+ (float:XF (match_operand:SI 1 "nonimmediate_operand" "m,!*r")))]
"TARGET_80387"
"*
{
@@ -2380,11 +2658,137 @@
;;- add instructions
+(define_insn "addsidi3_1"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,!&r,!r,o,!o")
+ (plus:DI (match_operand:DI 1 "general_operand" "0,0,0,o,riF,riF,o")
+ (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,roi,roi,ri,ri"))))
+ (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,&r"))]
+ ""
+ "*
+{
+ rtx low[3], high[3], xops[7], temp;
+
+ CC_STATUS_INIT;
+
+ split_di (operands, 2, low, high);
+ high[2] = const0_rtx;
+ low[2] = operands[2];
+
+ if (!rtx_equal_p (operands[0], operands[1]))
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[1];
+ xops[3] = low[1];
+
+ if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ {
+ output_asm_insn (AS2 (mov%L1,%3,%1), xops);
+ output_asm_insn (AS2 (mov%L0,%2,%0), xops);
+ }
+ else
+ {
+ xops[4] = high[2];
+ xops[5] = low[2];
+ xops[6] = operands[3];
+ output_asm_insn (AS2 (mov%L6,%3,%6), xops);
+ output_asm_insn (AS2 (add%L6,%5,%6), xops);
+ output_asm_insn (AS2 (mov%L1,%6,%1), xops);
+ output_asm_insn (AS2 (mov%L6,%2,%6), xops);
+ output_asm_insn (AS2 (adc%L6,%4,%6), xops);
+ output_asm_insn (AS2 (mov%L0,%6,%0), xops);
+ RET;
+ }
+ }
+
+ output_asm_insn (AS2 (add%L0,%2,%0), low);
+ output_asm_insn (AS2 (adc%L0,%2,%0), high);
+ RET;
+}")
+
+(define_insn "addsidi3_2"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,&r,!&r,&r,o,o,!o")
+ (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,o,ri,ri,i,r"))
+ (match_operand:DI 1 "general_operand" "0,0,0,iF,ro,roiF,riF,o,o")))
+ (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,X,&r,&r"))]
+ ""
+ "*
+{
+ rtx low[3], high[3], xops[7], temp;
+
+ CC_STATUS_INIT;
+
+ split_di (operands, 2, low, high);
+ high[2] = const0_rtx;
+ low[2] = operands[2];
+
+ if (!rtx_equal_p (operands[0], operands[1]))
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[1];
+ xops[3] = low[1];
+
+ if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ {
+ if (rtx_equal_p (low[0], operands[2]))
+ {
+ output_asm_insn (AS2 (mov%L0,%2,%0), high);
+ output_asm_insn (AS2 (add%L0,%1,%0), low);
+ output_asm_insn (AS2 (adc%L0,%1,%0), high);
+ RET;
+ }
+ if (rtx_equal_p (high[0], operands[2]))
+ {
+ if (GET_CODE (operands[0]) != MEM)
+ {
+ output_asm_insn (AS2 (mov%L0,%2,%0), low);
+ output_asm_insn (AS2 (mov%L0,%2,%0), high);
+ output_asm_insn (AS2 (add%L0,%1,%0), low);
+ output_asm_insn (AS2 (adc%L0,%1,%0), high);
+ }
+ else
+ {
+ /* It's too late to ask for a scratch now - but this
+ will probably not happen too often. */
+ output_asm_insn (AS2 (add%L1,%2,%1), low);
+ output_asm_insn (AS2 (mov%L0,%1,%0), low);
+ output_asm_insn (AS2 (mov%L1,%2,%1), low);
+ output_asm_insn (AS2 (mov%L0,%2,%0), high);
+ output_asm_insn (AS2 (adc%L0,%1,%0), high);
+ output_asm_insn (AS2 (sub%L1,%0,%1), low);
+ output_asm_insn (AS1 (neg%L1,%1), low);
+ }
+ RET;
+ }
+ output_asm_insn (AS2 (mov%L1,%3,%1), xops);
+ output_asm_insn (AS2 (mov%L0,%2,%0), xops);
+ }
+ else
+ {
+ xops[4] = high[2];
+ xops[5] = low[2];
+ xops[6] = operands[3];
+ output_asm_insn (AS2 (mov%L6,%3,%6), xops);
+ output_asm_insn (AS2 (add%L6,%5,%6), xops);
+ output_asm_insn (AS2 (mov%L1,%6,%1), xops);
+ output_asm_insn (AS2 (mov%L6,%2,%6), xops);
+ output_asm_insn (AS2 (adc%L6,%4,%6), xops);
+ output_asm_insn (AS2 (mov%L0,%6,%0), xops);
+ RET;
+ }
+ }
+
+ output_asm_insn (AS2 (add%L0,%2,%0), low);
+ output_asm_insn (AS2 (adc%L0,%2,%0), high);
+ RET;
+}")
+
(define_insn "adddi3"
- [(set (match_operand:DI 0 "general_operand" "=&r,ro,o,&r,ro,o,&r,o,o,o")
- (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,o,riF,o,or,riF,riF,o")
- (match_operand:DI 2 "general_operand" "o,riF,o,0,0,0,oriF,riF,o,o")))
- (clobber (match_scratch:SI 3 "=X,X,&r,X,&r,&r,X,&r,&r,&r"))]
+ [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o")
+ (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o")
+ (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o")))
+ (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))]
""
"*
{
@@ -2456,14 +2860,23 @@
;; On a 486, it is faster to do movl/addl than to do a single leal if
;; operands[1] and operands[2] are both registers.
-(define_insn "addsi3"
- [(set (match_operand:SI 0 "general_operand" "=?r,rm,r")
- (plus:SI (match_operand:SI 1 "general_operand" "%r,0,0")
- (match_operand:SI 2 "general_operand" "ri,ri,rm")))]
+(define_expand "addsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "")
+ (match_operand:SI 2 "general_operand" "")))]
""
+ "IX86_EXPAND_BINARY_OPERATOR (PLUS, SImode, operands);")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r")
+ (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,r")
+ (match_operand:SI 2 "general_operand" "rmi,ri,ri")))]
+ "ix86_binary_operator_ok (PLUS, SImode, operands)"
"*
{
- if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
+ if (REG_P (operands[0]) && REG_P (operands[1])
+ && (REG_P (operands[2]) || GET_CODE (operands[2]) == CONST_INT)
+ && REGNO (operands[0]) != REGNO (operands[1]))
{
if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
return AS2 (add%L0,%1,%0);
@@ -2483,34 +2896,85 @@
operands[1] = SET_SRC (PATTERN (insn));
return AS2 (lea%L0,%a1,%0);
}
-
- output_asm_insn (AS2 (mov%L0,%1,%0), operands);
}
+ if (!rtx_equal_p (operands[0], operands[1]))
+ output_asm_insn (AS2 (mov%L0,%1,%0), operands);
+
if (operands[2] == const1_rtx)
return AS1 (inc%L0,%0);
if (operands[2] == constm1_rtx)
return AS1 (dec%L0,%0);
+ /* subl $-128,%ebx is smaller than addl $128,%ebx. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 128)
+ {
+ /* This doesn't compute the carry bit in the same way
+ * as add%L0, but we use inc and dec above and they
+ * don't set the carry bit at all. If inc/dec don't need
+ * a CC_STATUS_INIT, this doesn't either... */
+ operands[2] = GEN_INT (-128);
+ return AS2 (sub%L0,%2,%0);
+ }
+
return AS2 (add%L0,%2,%0);
}")
+;; addsi3 is faster, so put this after.
+
+(define_insn "movsi_lea"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operand:QI 1 "address_operand" "p"))]
+ ""
+ "*
+{
+ /* Adding a constant to a register is faster with an add. */
+ /* ??? can this ever happen? */
+ if (GET_CODE (operands[1]) == PLUS
+ && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
+ && rtx_equal_p (operands[0], XEXP (operands[1], 0)))
+ {
+ operands[1] = XEXP (operands[1], 1);
+
+ if (operands[1] == const1_rtx)
+ return AS1 (inc%L0,%0);
+
+ if (operands[1] == constm1_rtx)
+ return AS1 (dec%L0,%0);
+
+ return AS2 (add%L0,%1,%0);
+ }
+
+ CC_STATUS_INIT;
+ return AS2 (lea%L0,%a1,%0);
+}")
+
;; ??? `lea' here, for three operand add? If leaw is used, only %bx,
;; %si and %di can appear in SET_SRC, and output_asm_insn might not be
;; able to handle the operand. But leal always works?
-(define_insn "addhi3"
- [(set (match_operand:HI 0 "general_operand" "=rm,r")
- (plus:HI (match_operand:HI 1 "general_operand" "%0,0")
- (match_operand:HI 2 "general_operand" "ri,rm")))]
+(define_expand "addhi3"
+ [(set (match_operand:HI 0 "general_operand" "")
+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "")
+ (match_operand:HI 2 "general_operand" "")))]
""
+ "IX86_EXPAND_BINARY_OPERATOR (PLUS, HImode, operands);")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:HI 2 "general_operand" "ri,rm")))]
+ "ix86_binary_operator_ok (PLUS, HImode, operands)"
"*
{
/* ??? what about offsettable memory references? */
- if (QI_REG_P (operands[0])
+ if (!TARGET_PENTIUMPRO /* partial stalls are just too painful to risk. */
+ && QI_REG_P (operands[0])
&& GET_CODE (operands[2]) == CONST_INT
- && (INTVAL (operands[2]) & 0xff) == 0)
+ && (INTVAL (operands[2]) & 0xff) == 0
+ && i386_cc_probably_useless_p (insn))
{
int byteval = (INTVAL (operands[2]) >> 8) & 0xff;
CC_STATUS_INIT;
@@ -2524,6 +2988,28 @@
return AS2 (add%B0,%2,%h0);
}
+ /* Use a 32-bit operation when possible, to avoid the prefix penalty. */
+ if (REG_P (operands[0])
+ && i386_aligned_p (operands[2])
+ && i386_cc_probably_useless_p (insn))
+ {
+ CC_STATUS_INIT;
+
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ HOST_WIDE_INT intval = 0xffff & INTVAL (operands[2]);
+
+ if (intval == 1)
+ return AS1 (inc%L0,%k0);
+
+ if (intval == 0xffff)
+ return AS1 (dec%L0,%k0);
+
+ operands[2] = i386_sext16_if_const (operands[2]);
+ }
+ return AS2 (add%L0,%k2,%k0);
+ }
+
if (operands[2] == const1_rtx)
return AS1 (inc%W0,%0);
@@ -2535,11 +3021,18 @@
return AS2 (add%W0,%2,%0);
}")
-(define_insn "addqi3"
- [(set (match_operand:QI 0 "general_operand" "=qm,q")
- (plus:QI (match_operand:QI 1 "general_operand" "%0,0")
- (match_operand:QI 2 "general_operand" "qn,qmn")))]
+(define_expand "addqi3"
+ [(set (match_operand:QI 0 "general_operand" "")
+ (plus:QI (match_operand:QI 1 "general_operand" "")
+ (match_operand:QI 2 "general_operand" "")))]
""
+ "IX86_EXPAND_BINARY_OPERATOR (PLUS, QImode, operands);")
+
+(define_insn ""
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+ (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:QI 2 "general_operand" "qn,qmn")))]
+ "ix86_binary_operator_ok (PLUS, QImode, operands)"
"*
{
if (operands[2] == const1_rtx)
@@ -2563,8 +3056,8 @@
;
;(define_insn ""
; [(set (match_operand:SI 0 "push_operand" "=<")
-; (plus:SI (match_operand:SI 1 "general_operand" "%r")
-; (match_operand:SI 2 "general_operand" "ri")))]
+; (plus:SI (match_operand:SI 1 "register_operand" "%r")
+; (match_operand:SI 2 "nonmemory_operand" "ri")))]
; ""
; "*
;{
@@ -2572,46 +3065,18 @@
; xops[0] = operands[0];
; xops[1] = operands[1];
; xops[2] = operands[2];
-; xops[3] = gen_rtx (MEM, SImode, stack_pointer_rtx);
+; xops[3] = gen_rtx_MEM (SImode, stack_pointer_rtx);
; output_asm_insn (\"push%z1 %1\", xops);
; output_asm_insn (AS2 (add%z3,%2,%3), xops);
; RET;
;}")
-;; addsi3 is faster, so put this after.
-
-(define_insn "movsi_lea"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (match_operand:QI 1 "address_operand" "p"))]
- ""
- "*
-{
- CC_STATUS_INIT;
- /* Adding a constant to a register is faster with an add. */
- /* ??? can this ever happen? */
- if (GET_CODE (operands[1]) == PLUS
- && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
- && rtx_equal_p (operands[0], XEXP (operands[1], 0)))
- {
- operands[1] = XEXP (operands[1], 1);
-
- if (operands[1] == const1_rtx)
- return AS1 (inc%L0,%0);
-
- if (operands[1] == constm1_rtx)
- return AS1 (dec%L0,%0);
-
- return AS2 (add%L0,%1,%0);
- }
- return AS2 (lea%L0,%a1,%0);
-}")
-
;; The patterns that match these are at the end of this file.
(define_expand "addxf3"
[(set (match_operand:XF 0 "register_operand" "")
- (plus:XF (match_operand:XF 1 "nonimmediate_operand" "")
- (match_operand:XF 2 "nonimmediate_operand" "")))]
+ (plus:XF (match_operand:XF 1 "register_operand" "")
+ (match_operand:XF 2 "register_operand" "")))]
"TARGET_80387"
"")
@@ -2631,11 +3096,59 @@
;;- subtract instructions
+(define_insn "subsidi3"
+ [(set (match_operand:DI 0 "general_operand" "=&r,&ro,&r,!&r,o,o,!o")
+ (minus:DI (match_operand:DI 1 "general_operand" "0iF,0,roiF,roiF,riF,o,o")
+ (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,ri,i,r"))))
+ (clobber (match_scratch:SI 3 "=X,X,X,X,X,&r,&r"))]
+ ""
+ "*
+{
+ rtx low[3], high[3], xops[7];
+
+ CC_STATUS_INIT;
+
+ split_di (operands, 2, low, high);
+ high[2] = const0_rtx;
+ low[2] = operands[2];
+
+ if (!rtx_equal_p (operands[0], operands[1]))
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[1];
+ xops[3] = low[1];
+
+ if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+ {
+ output_asm_insn (AS2 (mov%L1,%3,%1), xops);
+ output_asm_insn (AS2 (mov%L0,%2,%0), xops);
+ }
+ else
+ {
+ xops[4] = high[2];
+ xops[5] = low[2];
+ xops[6] = operands[3];
+ output_asm_insn (AS2 (mov%L6,%3,%6), xops);
+ output_asm_insn (AS2 (sub%L6,%5,%6), xops);
+ output_asm_insn (AS2 (mov%L1,%6,%1), xops);
+ output_asm_insn (AS2 (mov%L6,%2,%6), xops);
+ output_asm_insn (AS2 (sbb%L6,%4,%6), xops);
+ output_asm_insn (AS2 (mov%L0,%6,%0), xops);
+ RET;
+ }
+ }
+
+ output_asm_insn (AS2 (sub%L0,%2,%0), low);
+ output_asm_insn (AS2 (sbb%L0,%2,%0), high);
+ RET;
+}")
+
(define_insn "subdi3"
- [(set (match_operand:DI 0 "general_operand" "=&r,ro,&r,o,o")
- (minus:DI (match_operand:DI 1 "general_operand" "0,0,roiF,riF,o")
- (match_operand:DI 2 "general_operand" "o,riF,roiF,riF,o")))
- (clobber (match_scratch:SI 3 "=X,X,X,&r,&r"))]
+ [(set (match_operand:DI 0 "general_operand" "=&r,&ro,o,o,!&r,!o")
+ (minus:DI (match_operand:DI 1 "general_operand" "0,0,0iF,or,roiF,roiF")
+ (match_operand:DI 2 "general_operand" "or,riF,or,iF,roiF,roiF")))
+ (clobber (match_scratch:SI 3 "=X,X,&r,&r,X,&r"))]
""
"*
{
@@ -2698,33 +3211,65 @@
RET;
}")
-(define_insn "subsi3"
- [(set (match_operand:SI 0 "general_operand" "=rm,r")
- (minus:SI (match_operand:SI 1 "general_operand" "0,0")
- (match_operand:SI 2 "general_operand" "ri,rm")))]
+(define_expand "subsi3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "")
+ (match_operand:SI 2 "general_operand" "")))]
""
+ "IX86_EXPAND_BINARY_OPERATOR (MINUS, SImode, operands);")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm")))]
+ "ix86_binary_operator_ok (MINUS, SImode, operands)"
"* return AS2 (sub%L0,%2,%0);")
-(define_insn "subhi3"
- [(set (match_operand:HI 0 "general_operand" "=rm,r")
- (minus:HI (match_operand:HI 1 "general_operand" "0,0")
+(define_expand "subhi3"
+ [(set (match_operand:HI 0 "general_operand" "")
+ (minus:HI (match_operand:HI 1 "nonimmediate_operand" "")
+ (match_operand:HI 2 "general_operand" "")))]
+ ""
+ "IX86_EXPAND_BINARY_OPERATOR (MINUS, HImode, operands);")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+ (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
(match_operand:HI 2 "general_operand" "ri,rm")))]
+ "ix86_binary_operator_ok (MINUS, HImode, operands)"
+ "*
+{
+ if (REG_P (operands[0])
+ && i386_aligned_p (operands[2])
+ && i386_cc_probably_useless_p (insn))
+ {
+ CC_STATUS_INIT;
+ operands[2] = i386_sext16_if_const (operands[2]);
+ return AS2 (sub%L0,%k2,%k0);
+ }
+ return AS2 (sub%W0,%2,%0);
+}")
+
+(define_expand "subqi3"
+ [(set (match_operand:QI 0 "general_operand" "")
+ (minus:QI (match_operand:QI 1 "general_operand" "")
+ (match_operand:QI 2 "general_operand" "")))]
""
- "* return AS2 (sub%W0,%2,%0);")
+ "IX86_EXPAND_BINARY_OPERATOR (MINUS, QImode, operands);")
-(define_insn "subqi3"
- [(set (match_operand:QI 0 "general_operand" "=qm,q")
- (minus:QI (match_operand:QI 1 "general_operand" "0,0")
+(define_insn ""
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+ (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
(match_operand:QI 2 "general_operand" "qn,qmn")))]
- ""
+ "ix86_binary_operator_ok (MINUS, QImode, operands)"
"* return AS2 (sub%B0,%2,%0);")
;; The patterns that match these are at the end of this file.
(define_expand "subxf3"
[(set (match_operand:XF 0 "register_operand" "")
- (minus:XF (match_operand:XF 1 "nonimmediate_operand" "")
- (match_operand:XF 2 "nonimmediate_operand" "")))]
+ (minus:XF (match_operand:XF 1 "register_operand" "")
+ (match_operand:XF 2 "register_operand" "")))]
"TARGET_80387"
"")
@@ -2745,22 +3290,15 @@
;;- multiply instructions
;(define_insn "mulqi3"
-; [(set (match_operand:QI 0 "general_operand" "=a")
-; (mult:QI (match_operand:QI 1 "general_operand" "%0")
-; (match_operand:QI 2 "general_operand" "qm")))]
+; [(set (match_operand:QI 0 "register_operand" "=a")
+; (mult:QI (match_operand:QI 1 "register_operand" "%0")
+; (match_operand:QI 2 "nonimmediate_operand" "qm")))]
; ""
; "imul%B0 %2,%0")
-(define_insn ""
- [(set (match_operand:HI 0 "general_operand" "=r")
- (mult:HI (match_operand:HI 1 "general_operand" "%0")
- (match_operand:HI 2 "general_operand" "r")))]
- "GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80"
- "* return AS2 (imul%W0,%2,%0);")
-
(define_insn "mulhi3"
- [(set (match_operand:HI 0 "general_operand" "=r,r")
- (mult:HI (match_operand:HI 1 "general_operand" "%0,rm")
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (mult:HI (match_operand:HI 1 "nonimmediate_operand" "%0,rm")
(match_operand:HI 2 "general_operand" "g,i")))]
""
"*
@@ -2771,18 +3309,12 @@
/* Assembler has weird restrictions. */
return AS2 (imul%W0,%2,%0);
return AS3 (imul%W0,%2,%1,%0);
-}")
-
-(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=r")
- (mult:SI (match_operand:SI 1 "general_operand" "%0")
- (match_operand:SI 2 "general_operand" "r")))]
- "GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80"
- "* return AS2 (imul%L0,%2,%0);")
+}"
+ [(set_attr "type" "imul")])
(define_insn "mulsi3"
- [(set (match_operand:SI 0 "general_operand" "=r,r")
- (mult:SI (match_operand:SI 1 "general_operand" "%0,rm")
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,rm")
(match_operand:SI 2 "general_operand" "g,i")))]
""
"*
@@ -2793,35 +3325,40 @@
/* Assembler has weird restrictions. */
return AS2 (imul%L0,%2,%0);
return AS3 (imul%L0,%2,%1,%0);
-}")
+}"
+ [(set_attr "type" "imul")])
(define_insn "umulqihi3"
- [(set (match_operand:HI 0 "general_operand" "=a")
- (mult:HI (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0"))
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
(zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))]
""
- "mul%B0 %2")
+ "mul%B0 %2"
+ [(set_attr "type" "imul")])
(define_insn "mulqihi3"
- [(set (match_operand:HI 0 "general_operand" "=a")
- (mult:HI (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0"))
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
(sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))]
""
- "imul%B0 %2")
+ "imul%B0 %2"
+ [(set_attr "type" "imul")])
(define_insn "umulsidi3"
[(set (match_operand:DI 0 "register_operand" "=A")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
(zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))]
"TARGET_WIDE_MULTIPLY"
- "mul%L0 %2")
+ "mul%L0 %2"
+ [(set_attr "type" "imul")])
(define_insn "mulsidi3"
[(set (match_operand:DI 0 "register_operand" "=A")
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
(sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))]
"TARGET_WIDE_MULTIPLY"
- "imul%L0 %2")
+ "imul%L0 %2"
+ [(set_attr "type" "imul")])
(define_insn "umulsi3_highpart"
[(set (match_operand:SI 0 "register_operand" "=d")
@@ -2830,7 +3367,8 @@
(const_int 32))))
(clobber (match_scratch:SI 3 "=a"))]
"TARGET_WIDE_MULTIPLY"
- "mul%L0 %2")
+ "mul%L0 %2"
+ [(set_attr "type" "imul")])
(define_insn "smulsi3_highpart"
[(set (match_operand:SI 0 "register_operand" "=d")
@@ -2839,27 +3377,28 @@
(const_int 32))))
(clobber (match_scratch:SI 3 "=a"))]
"TARGET_WIDE_MULTIPLY"
- "imul%L0 %2")
+ "imul%L0 %2"
+ [(set_attr "type" "imul")])
;; The patterns that match these are at the end of this file.
(define_expand "mulxf3"
[(set (match_operand:XF 0 "register_operand" "")
- (mult:XF (match_operand:XF 1 "nonimmediate_operand" "")
- (match_operand:XF 2 "nonimmediate_operand" "")))]
+ (mult:XF (match_operand:XF 1 "register_operand" "")
+ (match_operand:XF 2 "register_operand" "")))]
"TARGET_80387"
"")
(define_expand "muldf3"
[(set (match_operand:DF 0 "register_operand" "")
- (mult:DF (match_operand:DF 1 "nonimmediate_operand" "")
+ (mult:DF (match_operand:DF 1 "register_operand" "")
(match_operand:DF 2 "nonimmediate_operand" "")))]
"TARGET_80387"
"")
(define_expand "mulsf3"
[(set (match_operand:SF 0 "register_operand" "")
- (mult:SF (match_operand:SF 1 "nonimmediate_operand" "")
+ (mult:SF (match_operand:SF 1 "register_operand" "")
(match_operand:SF 2 "nonimmediate_operand" "")))]
"TARGET_80387"
"")
@@ -2867,38 +3406,39 @@
;;- divide instructions
(define_insn "divqi3"
- [(set (match_operand:QI 0 "general_operand" "=a")
- (div:QI (match_operand:HI 1 "general_operand" "0")
- (match_operand:QI 2 "general_operand" "qm")))]
+ [(set (match_operand:QI 0 "register_operand" "=a")
+ (div:QI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:QI 2 "nonimmediate_operand" "qm")))]
""
"idiv%B0 %2")
(define_insn "udivqi3"
- [(set (match_operand:QI 0 "general_operand" "=a")
- (udiv:QI (match_operand:HI 1 "general_operand" "0")
- (match_operand:QI 2 "general_operand" "qm")))]
+ [(set (match_operand:QI 0 "register_operand" "=a")
+ (udiv:QI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:QI 2 "nonimmediate_operand" "qm")))]
""
- "div%B0 %2")
+ "div%B0 %2"
+ [(set_attr "type" "idiv")])
;; The patterns that match these are at the end of this file.
(define_expand "divxf3"
[(set (match_operand:XF 0 "register_operand" "")
- (div:XF (match_operand:XF 1 "nonimmediate_operand" "")
- (match_operand:XF 2 "nonimmediate_operand" "")))]
+ (div:XF (match_operand:XF 1 "register_operand" "")
+ (match_operand:XF 2 "register_operand" "")))]
"TARGET_80387"
"")
(define_expand "divdf3"
[(set (match_operand:DF 0 "register_operand" "")
- (div:DF (match_operand:DF 1 "nonimmediate_operand" "")
- (match_operand:DF 2 "nonimmediate_operand" "")))]
- "TARGET_80387"
- "")
-
+ (div:DF (match_operand:DF 1 "register_operand" "")
+ (match_operand:DF 2 "nonimmediate_operand" "")))]
+ "TARGET_80387"
+ "")
+
(define_expand "divsf3"
[(set (match_operand:SF 0 "register_operand" "")
- (div:SF (match_operand:SF 1 "nonimmediate_operand" "")
+ (div:SF (match_operand:SF 1 "register_operand" "")
(match_operand:SF 2 "nonimmediate_operand" "")))]
"TARGET_80387"
"")
@@ -2908,7 +3448,7 @@
(define_insn "divmodsi4"
[(set (match_operand:SI 0 "register_operand" "=a")
(div:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "general_operand" "rm")))
+ (match_operand:SI 2 "nonimmediate_operand" "rm")))
(set (match_operand:SI 3 "register_operand" "=&d")
(mod:SI (match_dup 1) (match_dup 2)))]
""
@@ -2920,22 +3460,24 @@
output_asm_insn (\"cltd\", operands);
#endif
return AS1 (idiv%L0,%2);
-}")
+}"
+ [(set_attr "type" "idiv")])
(define_insn "divmodhi4"
[(set (match_operand:HI 0 "register_operand" "=a")
(div:HI (match_operand:HI 1 "register_operand" "0")
- (match_operand:HI 2 "general_operand" "rm")))
+ (match_operand:HI 2 "nonimmediate_operand" "rm")))
(set (match_operand:HI 3 "register_operand" "=&d")
(mod:HI (match_dup 1) (match_dup 2)))]
""
- "cwtd\;idiv%W0 %2")
+ "cwtd\;idiv%W0 %2"
+ [(set_attr "type" "idiv")])
;; ??? Can we make gcc zero extend operand[0]?
(define_insn "udivmodsi4"
[(set (match_operand:SI 0 "register_operand" "=a")
(udiv:SI (match_operand:SI 1 "register_operand" "0")
- (match_operand:SI 2 "general_operand" "rm")))
+ (match_operand:SI 2 "nonimmediate_operand" "rm")))
(set (match_operand:SI 3 "register_operand" "=&d")
(umod:SI (match_dup 1) (match_dup 2)))]
""
@@ -2943,13 +3485,14 @@
{
output_asm_insn (AS2 (xor%L3,%3,%3), operands);
return AS1 (div%L0,%2);
-}")
+}"
+ [(set_attr "type" "idiv")])
;; ??? Can we make gcc zero extend operand[0]?
(define_insn "udivmodhi4"
[(set (match_operand:HI 0 "register_operand" "=a")
(udiv:HI (match_operand:HI 1 "register_operand" "0")
- (match_operand:HI 2 "general_operand" "rm")))
+ (match_operand:HI 2 "nonimmediate_operand" "rm")))
(set (match_operand:HI 3 "register_operand" "=&d")
(umod:HI (match_dup 1) (match_dup 2)))]
""
@@ -2957,7 +3500,8 @@
{
output_asm_insn (AS2 (xor%W0,%3,%3), operands);
return AS1 (div%W0,%2);
-}")
+}"
+ [(set_attr "type" "idiv")])
/*
;;this should be a valid double division which we may want to add
@@ -2965,11 +3509,12 @@
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=a")
(udiv:DI (match_operand:DI 1 "register_operand" "a")
- (match_operand:SI 2 "general_operand" "rm")))
+ (match_operand:SI 2 "nonimmediate_operand" "rm")))
(set (match_operand:SI 3 "register_operand" "=d")
(umod:SI (match_dup 1) (match_dup 2)))]
""
- "div%L0 %2,%0")
+ "div%L0 %2,%0"
+ [(set_attr "type" "idiv")])
*/
;;- and instructions
@@ -2989,21 +3534,33 @@
;; The `r' in `rm' for operand 3 looks redundant, but it causes
;; optional reloads to be generated if op 3 is a pseudo in a stack slot.
-;; ??? What if we only change one byte of an offsettable memory reference?
(define_insn "andsi3"
- [(set (match_operand:SI 0 "general_operand" "=r,r,rm,r")
- (and:SI (match_operand:SI 1 "general_operand" "%rm,qm,0,0")
- (match_operand:SI 2 "general_operand" "L,K,ri,rm")))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+ (match_operand:SI 2 "general_operand" "ri,rm")))]
""
"*
{
- if (GET_CODE (operands[2]) == CONST_INT
- && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
+ HOST_WIDE_INT intval;
+ if (!rtx_equal_p (operands[0], operands[1])
+ && rtx_equal_p (operands[0], operands[2]))
{
- if (INTVAL (operands[2]) == 0xffff && REG_P (operands[0])
+ rtx tmp;
+ tmp = operands[1];
+ operands[1] = operands[2];
+ operands[2] = tmp;
+ }
+ switch (GET_CODE (operands[2]))
+ {
+ case CONST_INT:
+ if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
+ break;
+ intval = INTVAL (operands[2]);
+ /* zero-extend 16->32? */
+ if (intval == 0xffff && REG_P (operands[0])
&& (! REG_P (operands[1])
|| REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
- && (TARGET_386 || ! rtx_equal_p (operands[0], operands[1])))
+ && (!TARGET_ZERO_EXTEND_WITH_AND || ! rtx_equal_p (operands[0], operands[1])))
{
/* ??? tege: Should forget CC_STATUS only if we clobber a
remembered operand. Fix that later. */
@@ -3015,11 +3572,12 @@
#endif
}
- if (INTVAL (operands[2]) == 0xff && REG_P (operands[0])
+ /* zero extend 8->32? */
+ if (intval == 0xff && REG_P (operands[0])
&& !(REG_P (operands[1]) && NON_QI_REG_P (operands[1]))
&& (! REG_P (operands[1])
|| REGNO (operands[0]) != 0 || REGNO (operands[1]) != 0)
- && (TARGET_386 || ! rtx_equal_p (operands[0], operands[1])))
+ && (!TARGET_ZERO_EXTEND_WITH_AND || ! rtx_equal_p (operands[0], operands[1])))
{
/* ??? tege: Should forget CC_STATUS only if we clobber a
remembered operand. Fix that later. */
@@ -3031,47 +3589,110 @@
#endif
}
- if (QI_REG_P (operands[0]) && ~(INTVAL (operands[2]) | 0xff) == 0)
- {
- CC_STATUS_INIT;
+ /* Check partial bytes.. non-QI-regs are not available */
+ if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
+ break;
- if (INTVAL (operands[2]) == 0xffffff00)
+ /* only low byte has zero bits? */
+ if (~(intval | 0xff) == 0)
+ {
+ intval &= 0xff;
+ if (REG_P (operands[0]))
{
- operands[2] = const0_rtx;
- return AS2 (mov%B0,%2,%b0);
+ if (intval == 0)
+ {
+ CC_STATUS_INIT;
+ return AS2 (xor%B0,%b0,%b0);
+ }
+
+ /* we're better off with the 32-bit version if reg != EAX */
+ /* the value is sign-extended in 8 bits */
+ if (REGNO (operands[0]) != 0 && (intval & 0x80))
+ break;
}
- operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff);
+ CC_STATUS_INIT;
+
+ operands[2] = GEN_INT (intval);
+
+ if (intval == 0)
+ return AS2 (mov%B0,%2,%b0);
+
return AS2 (and%B0,%2,%b0);
}
- if (QI_REG_P (operands[0]) && ~(INTVAL (operands[2]) | 0xff00) == 0)
+ /* only second byte has zero? */
+ if (~(intval | 0xff00) == 0)
{
CC_STATUS_INIT;
- if (INTVAL (operands[2]) == 0xffff00ff)
+ intval = (intval >> 8) & 0xff;
+ operands[2] = GEN_INT (intval);
+ if (intval == 0)
{
- operands[2] = const0_rtx;
- return AS2 (mov%B0,%2,%h0);
+ if (REG_P (operands[0]))
+ return AS2 (xor%B0,%h0,%h0);
+ operands[0] = adj_offsettable_operand (operands[0], 1);
+ return AS2 (mov%B0,%2,%b0);
}
- operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
- return AS2 (and%B0,%2,%h0);
+ if (REG_P (operands[0]))
+ return AS2 (and%B0,%2,%h0);
+
+ operands[0] = adj_offsettable_operand (operands[0], 1);
+ return AS2 (and%B0,%2,%b0);
+ }
+
+ if (REG_P (operands[0]))
+ break;
+
+ /* third byte has zero bits? */
+ if (~(intval | 0xff0000) == 0)
+ {
+ intval = (intval >> 16) & 0xff;
+ operands[0] = adj_offsettable_operand (operands[0], 2);
+byte_and_operation:
+ CC_STATUS_INIT;
+ operands[2] = GEN_INT (intval);
+ if (intval == 0)
+ return AS2 (mov%B0,%2,%b0);
+ return AS2 (and%B0,%2,%b0);
+ }
+
+ /* fourth byte has zero bits? */
+ if (~(intval | 0xff000000) == 0)
+ {
+ intval = (intval >> 24) & 0xff;
+ operands[0] = adj_offsettable_operand (operands[0], 3);
+ goto byte_and_operation;
}
- if (GET_CODE (operands[0]) == MEM && INTVAL (operands[2]) == 0xffff0000)
+ /* Low word is zero? */
+ if (intval == 0xffff0000)
{
+word_zero_and_operation:
+ CC_STATUS_INIT;
operands[2] = const0_rtx;
return AS2 (mov%W0,%2,%w0);
}
+
+ /* High word is zero? */
+ if (intval == 0x0000ffff)
+ {
+ operands[0] = adj_offsettable_operand (operands[0], 2);
+ goto word_zero_and_operation;
+ }
+
+ default:
+ break;
}
return AS2 (and%L0,%2,%0);
}")
(define_insn "andhi3"
- [(set (match_operand:HI 0 "general_operand" "=rm,r")
- (and:HI (match_operand:HI 1 "general_operand" "%0,0")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+ (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
(match_operand:HI 2 "general_operand" "ri,rm")))]
""
"*
@@ -3110,14 +3731,46 @@
operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
return AS2 (and%B0,%2,%h0);
}
+
+ /* use 32-bit ops on registers when there are no sign issues.. */
+ if (REG_P (operands[0]))
+ {
+ if (!(INTVAL (operands[2]) & ~0x7fff))
+ return AS2 (and%L0,%2,%k0);
+ }
+ }
+
+ if (REG_P (operands[0])
+ && i386_aligned_p (operands[2]))
+ {
+ CC_STATUS_INIT;
+ /* If op[2] is constant, we should zero-extend it and */
+ /* make a note that op[0] has been zero-extended, so */
+ /* that we could use 32-bit ops on it forthwith, but */
+ /* there is no such reg-note available. Instead we do */
+ /* a sign extension as that can result in shorter asm */
+ operands[2] = i386_sext16_if_const (operands[2]);
+ return AS2 (and%L0,%k2,%k0);
+ }
+
+ /* Use a 32-bit word with the upper bits set, invalidate CC */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && i386_aligned_p (operands[0]))
+ {
+ HOST_WIDE_INT val = INTVAL (operands[2]);
+ CC_STATUS_INIT;
+ val |= ~0xffff;
+ if (val != INTVAL (operands[2]))
+ operands[2] = GEN_INT (val);
+ return AS2 (and%L0,%k2,%k0);
}
return AS2 (and%W0,%2,%0);
}")
(define_insn "andqi3"
- [(set (match_operand:QI 0 "general_operand" "=qm,q")
- (and:QI (match_operand:QI 1 "general_operand" "%0,0")
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+ (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
(match_operand:QI 2 "general_operand" "qn,qmn")))]
""
"* return AS2 (and%B0,%2,%0);")
@@ -3136,10 +3789,10 @@
"and%W0 %1,%0")
(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=q")
+ [(set (match_operand:SI 0 "register_operand" "=q")
(and:SI
(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm"))
- (match_operand:SI 2 "general_operand" "0")))]
+ (match_operand:SI 2 "register_operand" "0")))]
"GET_CODE (operands[2]) == CONST_INT
&& (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))"
"and%L0 %1,%0")
@@ -3148,134 +3801,278 @@
;;- Bit set (inclusive or) instructions
-;; ??? What if we only change one byte of an offsettable memory reference?
+;; This optimizes known byte-wide operations to memory, and in some cases
+;; to QI registers.. Note that we don't want to use the QI registers too
+;; aggressively, because often the 32-bit register instruction is the same
+;; size, and likely to be faster on PentiumPro.
(define_insn "iorsi3"
- [(set (match_operand:SI 0 "general_operand" "=rm,r")
- (ior:SI (match_operand:SI 1 "general_operand" "%0,0")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "ri,rm")))]
""
"*
{
- if (GET_CODE (operands[2]) == CONST_INT
- && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
+ HOST_WIDE_INT intval;
+ switch (GET_CODE (operands[2]))
{
- if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
- && (INTVAL (operands[2]) & ~0xff) == 0)
- {
- CC_STATUS_INIT;
+ case CONST_INT:
- if (INTVAL (operands[2]) == 0xff)
- return AS2 (mov%B0,%2,%b0);
+ if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
+ break;
- return AS2 (or%B0,%2,%b0);
+ /* don't try to optimize volatile accesses */
+ if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
+ break;
+
+ intval = INTVAL (operands[2]);
+ if ((intval & ~0xff) == 0)
+ {
+ if (REG_P (operands[0]))
+ {
+ /* Do low byte access only for %eax or when high bit is set */
+ if (REGNO (operands[0]) != 0 && !(intval & 0x80))
+ break;
+ }
+
+byte_or_operation:
+ CC_STATUS_INIT;
+
+ if (intval != INTVAL (operands[2]))
+ operands[2] = GEN_INT (intval);
+
+ if (intval == 0xff)
+ return AS2 (mov%B0,%2,%b0);
+
+ return AS2 (or%B0,%2,%b0);
}
- if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff00) == 0)
+ /* second byte? */
+ if ((intval & ~0xff00) == 0)
{
- CC_STATUS_INIT;
- operands[2] = GEN_INT (INTVAL (operands[2]) >> 8);
+ intval >>= 8;
- if (INTVAL (operands[2]) == 0xff)
- return AS2 (mov%B0,%2,%h0);
+ if (REG_P (operands[0]))
+ {
+ CC_STATUS_INIT;
+ operands[2] = GEN_INT (intval);
+ if (intval == 0xff)
+ return AS2 (mov%B0,%2,%h0);
- return AS2 (or%B0,%2,%h0);
+ return AS2 (or%B0,%2,%h0);
+ }
+
+ operands[0] = adj_offsettable_operand (operands[0], 1);
+ goto byte_or_operation;
+ }
+
+ if (REG_P (operands[0]))
+ break;
+
+ /* third byte? */
+ if ((intval & ~0xff0000) == 0)
+ {
+ intval >>= 16;
+ operands[0] = adj_offsettable_operand (operands[0], 2);
+ goto byte_or_operation;
+ }
+
+ /* fourth byte? */
+ if ((intval & ~0xff000000) == 0)
+ {
+ intval = (intval >> 24) & 0xff;
+ operands[0] = adj_offsettable_operand (operands[0], 3);
+ goto byte_or_operation;
}
+
+ default:
+ break;
}
return AS2 (or%L0,%2,%0);
}")
(define_insn "iorhi3"
- [(set (match_operand:HI 0 "general_operand" "=rm,r")
- (ior:HI (match_operand:HI 1 "general_operand" "%0,0")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+ (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
(match_operand:HI 2 "general_operand" "ri,rm")))]
""
"*
{
- if (GET_CODE (operands[2]) == CONST_INT
- && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
+ HOST_WIDE_INT intval;
+ switch (GET_CODE (operands[2]))
{
- /* Can we ignore the upper byte? */
- if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
- && (INTVAL (operands[2]) & 0xff00) == 0)
- {
- CC_STATUS_INIT;
- if (INTVAL (operands[2]) & 0xffff0000)
- operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffff);
+ case CONST_INT:
- if (INTVAL (operands[2]) == 0xff)
- return AS2 (mov%B0,%2,%b0);
+ if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
+ break;
+
+ /* don't try to optimize volatile accesses */
+ if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
+ break;
+
+ intval = 0xffff & INTVAL (operands[2]);
- return AS2 (or%B0,%2,%b0);
+ if ((intval & 0xff00) == 0)
+ {
+ if (REG_P (operands[0]))
+ {
+ /* Do low byte access only for %eax or when high bit is set */
+ if (REGNO (operands[0]) != 0 && !(intval & 0x80))
+ break;
+ }
+
+byte_or_operation:
+ CC_STATUS_INIT;
+
+ if (intval == 0xff)
+ return AS2 (mov%B0,%2,%b0);
+
+ return AS2 (or%B0,%2,%b0);
}
- /* Can we ignore the lower byte? */
- /* ??? what about offsettable memory references? */
- if (QI_REG_P (operands[0])
- && (INTVAL (operands[2]) & 0xff) == 0)
+ /* high byte? */
+ if ((intval & 0xff) == 0)
{
- CC_STATUS_INIT;
- operands[2] = GEN_INT ((INTVAL (operands[2]) >> 8) & 0xff);
+ intval >>= 8;
+ operands[2] = GEN_INT (intval);
- if (INTVAL (operands[2]) == 0xff)
- return AS2 (mov%B0,%2,%h0);
+ if (REG_P (operands[0]))
+ {
+ CC_STATUS_INIT;
+ if (intval == 0xff)
+ return AS2 (mov%B0,%2,%h0);
+
+ return AS2 (or%B0,%2,%h0);
+ }
- return AS2 (or%B0,%2,%h0);
+ operands[0] = adj_offsettable_operand (operands[0], 1);
+
+ goto byte_or_operation;
}
+
+ default:
+ break;
+ }
+
+ if (REG_P (operands[0])
+ && i386_aligned_p (operands[2]))
+ {
+ CC_STATUS_INIT;
+ operands[2] = i386_sext16_if_const (operands[2]);
+ return AS2 (or%L0,%k2,%k0);
+ }
+
+ if (GET_CODE (operands[2]) == CONST_INT
+ && i386_aligned_p (operands[0]))
+ {
+ CC_STATUS_INIT;
+ intval = 0xffff & INTVAL (operands[2]);
+ if (intval != INTVAL (operands[2]))
+ operands[2] = GEN_INT (intval);
+ return AS2 (or%L0,%2,%k0);
}
return AS2 (or%W0,%2,%0);
}")
(define_insn "iorqi3"
- [(set (match_operand:QI 0 "general_operand" "=qm,q")
- (ior:QI (match_operand:QI 1 "general_operand" "%0,0")
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+ (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
(match_operand:QI 2 "general_operand" "qn,qmn")))]
""
"* return AS2 (or%B0,%2,%0);")
;;- xor instructions
-;; ??? What if we only change one byte of an offsettable memory reference?
(define_insn "xorsi3"
- [(set (match_operand:SI 0 "general_operand" "=rm,r")
- (xor:SI (match_operand:SI 1 "general_operand" "%0,0")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
(match_operand:SI 2 "general_operand" "ri,rm")))]
""
"*
{
- if (GET_CODE (operands[2]) == CONST_INT
- && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
+ HOST_WIDE_INT intval;
+ switch (GET_CODE (operands[2]))
{
- if ((! REG_P (operands[0]) || QI_REG_P (operands[0]))
- && (INTVAL (operands[2]) & ~0xff) == 0)
- {
- CC_STATUS_INIT;
+ case CONST_INT:
- if (INTVAL (operands[2]) == 0xff)
- return AS1 (not%B0,%b0);
+ if (REG_P (operands[0]) && ! QI_REG_P (operands[0]))
+ break;
- return AS2 (xor%B0,%2,%b0);
+ /* don't try to optimize volatile accesses */
+ if (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0]))
+ break;
+
+ intval = INTVAL (operands[2]);
+ if ((intval & ~0xff) == 0)
+ {
+ if (REG_P (operands[0]))
+ {
+ /* Do low byte access only for %eax or when high bit is set */
+ if (REGNO (operands[0]) != 0 && !(intval & 0x80))
+ break;
+ }
+
+byte_xor_operation:
+ CC_STATUS_INIT;
+
+ if (intval == 0xff)
+ return AS1 (not%B0,%b0);
+
+ if (intval != INTVAL (operands[2]))
+ operands[2] = GEN_INT (intval);
+ return AS2 (xor%B0,%2,%b0);
}
- if (QI_REG_P (operands[0]) && (INTVAL (operands[2]) & ~0xff00) == 0)
+ /* second byte? */
+ if ((intval & ~0xff00) == 0)
{
- CC_STATUS_INIT;
- operands[2] = GEN_INT (INTVAL (operands[2]) >> 8);
+ intval >>= 8;
- if (INTVAL (operands[2]) == 0xff)
- return AS1 (not%B0,%h0);
+ if (REG_P (operands[0]))
+ {
+ CC_STATUS_INIT;
+ if (intval == 0xff)
+ return AS1 (not%B0,%h0);
- return AS2 (xor%B0,%2,%h0);
+ operands[2] = GEN_INT (intval);
+ return AS2 (xor%B0,%2,%h0);
+ }
+
+ operands[0] = adj_offsettable_operand (operands[0], 1);
+
+ goto byte_xor_operation;
}
+
+ if (REG_P (operands[0]))
+ break;
+
+ /* third byte? */
+ if ((intval & ~0xff0000) == 0)
+ {
+ intval >>= 16;
+ operands[0] = adj_offsettable_operand (operands[0], 2);
+ goto byte_xor_operation;
+ }
+
+ /* fourth byte? */
+ if ((intval & ~0xff000000) == 0)
+ {
+ intval = (intval >> 24) & 0xff;
+ operands[0] = adj_offsettable_operand (operands[0], 3);
+ goto byte_xor_operation;
+ }
+
+ default:
+ break;
}
return AS2 (xor%L0,%2,%0);
}")
(define_insn "xorhi3"
- [(set (match_operand:HI 0 "general_operand" "=rm,r")
- (xor:HI (match_operand:HI 1 "general_operand" "%0,0")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+ (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
(match_operand:HI 2 "general_operand" "ri,rm")))]
""
"*
@@ -3312,16 +4109,136 @@
}
}
+ if (REG_P (operands[0])
+ && i386_aligned_p (operands[2]))
+ {
+ CC_STATUS_INIT;
+ operands[2] = i386_sext16_if_const (operands[2]);
+ return AS2 (xor%L0,%k2,%k0);
+ }
+
+ if (GET_CODE (operands[2]) == CONST_INT
+ && i386_aligned_p (operands[0]))
+ {
+ HOST_WIDE_INT intval;
+ CC_STATUS_INIT;
+ intval = 0xffff & INTVAL (operands[2]);
+ if (intval != INTVAL (operands[2]))
+ operands[2] = GEN_INT (intval);
+ return AS2 (xor%L0,%2,%k0);
+ }
+
return AS2 (xor%W0,%2,%0);
}")
(define_insn "xorqi3"
- [(set (match_operand:QI 0 "general_operand" "=qm,q")
- (xor:QI (match_operand:QI 1 "general_operand" "%0,0")
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+ (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
(match_operand:QI 2 "general_operand" "qn,qm")))]
""
"* return AS2 (xor%B0,%2,%0);")
+;; logical operations for DImode
+
+
+(define_insn "anddi3"
+ [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o")
+ (and:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o")
+ (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o")))
+ (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))]
+ ""
+ "#")
+
+(define_insn "iordi3"
+ [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o")
+ (ior:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o")
+ (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o")))
+ (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))]
+ ""
+ "#")
+
+(define_insn "xordi3"
+ [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o")
+ (xor:DI (match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o")
+ (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o")))
+ (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))]
+ ""
+ "#")
+
+(define_split
+ [(set (match_operand:DI 0 "general_operand" "=&r,&ro,!r,o,!&r,!o,!o")
+ (match_operator:DI 4 "ix86_logical_operator"
+ [(match_operand:DI 1 "general_operand" "%0,0,0,0iF,or,riF,o")
+ (match_operand:DI 2 "general_operand" "o,riF,0,or,or,oriF,o")]))
+ (clobber (match_scratch:SI 3 "=X,X,X,&r,X,&r,&r"))]
+ "reload_completed"
+ [(const_int 0)]
+ "
+{
+ rtx low[3], high[3], xops[7], temp;
+ rtx (*genfunc)() = (GET_CODE (operands[4]) == AND ? gen_andsi3
+ : GET_CODE (operands[4]) == IOR ? gen_iorsi3
+ : GET_CODE (operands[4]) == XOR ? gen_xorsi3
+ : 0);
+
+ if (rtx_equal_p (operands[0], operands[2]))
+ {
+ temp = operands[1];
+ operands[1] = operands[2];
+ operands[2] = temp;
+ }
+
+ split_di (operands, 3, low, high);
+ if (!rtx_equal_p (operands[0], operands[1]))
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[1];
+ xops[3] = low[1];
+
+ if (GET_CODE (operands[0]) != MEM)
+ {
+ emit_insn (gen_movsi (xops[1], xops[3]));
+ emit_insn (gen_movsi (xops[0], xops[2]));
+ }
+ else
+ {
+ xops[4] = high[2];
+ xops[5] = low[2];
+ xops[6] = operands[3];
+ emit_insn (gen_movsi (xops[6], xops[3]));
+ emit_insn ((*genfunc) (xops[6], xops[6], xops[5]));
+ emit_insn (gen_movsi (xops[1], xops[6]));
+ emit_insn (gen_movsi (xops[6], xops[2]));
+ emit_insn ((*genfunc) (xops[6], xops[6], xops[4]));
+ emit_insn (gen_movsi (xops[0], xops[6]));
+ DONE;
+ }
+ }
+
+ if (GET_CODE (operands[3]) == REG && GET_CODE (operands[2]) != REG)
+ {
+ xops[0] = high[0];
+ xops[1] = low[0];
+ xops[2] = high[2];
+ xops[3] = low[2];
+ xops[4] = operands[3];
+
+ emit_insn (gen_movsi (xops[4], xops[3]));
+ emit_insn ((*genfunc) (xops[1], xops[1], xops[4]));
+ emit_insn (gen_movsi (xops[4], xops[2]));
+ emit_insn ((*genfunc) (xops[0], xops[0], xops[4]));
+ }
+
+ else
+ {
+ emit_insn ((*genfunc) (low[0], low[0], low[2]));
+ emit_insn ((*genfunc) (high[0], high[0], high[2]));
+ }
+
+ DONE;
+}")
+
;;- negation instructions
(define_insn "negdi2"
@@ -3345,50 +4262,50 @@
}")
(define_insn "negsi2"
- [(set (match_operand:SI 0 "general_operand" "=rm")
- (neg:SI (match_operand:SI 1 "general_operand" "0")))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
""
"neg%L0 %0")
(define_insn "neghi2"
- [(set (match_operand:HI 0 "general_operand" "=rm")
- (neg:HI (match_operand:HI 1 "general_operand" "0")))]
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
""
"neg%W0 %0")
(define_insn "negqi2"
- [(set (match_operand:QI 0 "general_operand" "=qm")
- (neg:QI (match_operand:QI 1 "general_operand" "0")))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
""
"neg%B0 %0")
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
- (neg:SF (match_operand:SF 1 "general_operand" "0")))]
+ (neg:SF (match_operand:SF 1 "register_operand" "0")))]
"TARGET_80387"
"fchs")
(define_insn "negdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
- (neg:DF (match_operand:DF 1 "general_operand" "0")))]
+ (neg:DF (match_operand:DF 1 "register_operand" "0")))]
"TARGET_80387"
"fchs")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
- (neg:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))]
+ (neg:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))]
"TARGET_80387"
"fchs")
(define_insn "negxf2"
[(set (match_operand:XF 0 "register_operand" "=f")
- (neg:XF (match_operand:XF 1 "general_operand" "0")))]
+ (neg:XF (match_operand:XF 1 "register_operand" "0")))]
"TARGET_80387"
"fchs")
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
- (neg:XF (float_extend:XF (match_operand:DF 1 "general_operand" "0"))))]
+ (neg:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))]
"TARGET_80387"
"fchs")
@@ -3396,44 +4313,48 @@
(define_insn "abssf2"
[(set (match_operand:SF 0 "register_operand" "=f")
- (abs:SF (match_operand:SF 1 "general_operand" "0")))]
+ (abs:SF (match_operand:SF 1 "register_operand" "0")))]
"TARGET_80387"
- "fabs")
+ "fabs"
+ [(set_attr "type" "fpop")])
(define_insn "absdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
- (abs:DF (match_operand:DF 1 "general_operand" "0")))]
+ (abs:DF (match_operand:DF 1 "register_operand" "0")))]
"TARGET_80387"
- "fabs")
+ "fabs"
+ [(set_attr "type" "fpop")])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
- (abs:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))]
+ (abs:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))]
"TARGET_80387"
- "fabs")
+ "fabs"
+ [(set_attr "type" "fpop")])
(define_insn "absxf2"
[(set (match_operand:XF 0 "register_operand" "=f")
- (abs:XF (match_operand:XF 1 "general_operand" "0")))]
+ (abs:XF (match_operand:XF 1 "register_operand" "0")))]
"TARGET_80387"
- "fabs")
+ "fabs"
+ [(set_attr "type" "fpop")])
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
- (abs:XF (float_extend:XF (match_operand:DF 1 "general_operand" "0"))))]
+ (abs:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))]
"TARGET_80387"
- "fabs")
+ "fabs"
+ [(set_attr "type" "fpop")])
(define_insn "sqrtsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
- (sqrt:SF (match_operand:SF 1 "general_operand" "0")))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ (sqrt:SF (match_operand:SF 1 "register_operand" "0")))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
"fsqrt")
(define_insn "sqrtdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
- (sqrt:DF (match_operand:DF 1 "general_operand" "0")))]
+ (sqrt:DF (match_operand:DF 1 "register_operand" "0")))]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) "
"fsqrt")
@@ -3441,14 +4362,13 @@
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(sqrt:DF (float_extend:DF
- (match_operand:SF 1 "general_operand" "0"))))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ (match_operand:SF 1 "register_operand" "0"))))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
"fsqrt")
(define_insn "sqrtxf2"
[(set (match_operand:XF 0 "register_operand" "=f")
- (sqrt:XF (match_operand:XF 1 "general_operand" "0")))]
+ (sqrt:XF (match_operand:XF 1 "register_operand" "0")))]
"! TARGET_NO_FANCY_MATH_387 && TARGET_80387
&& (TARGET_IEEE_FP || flag_fast_math) "
"fsqrt")
@@ -3456,94 +4376,84 @@
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
(sqrt:XF (float_extend:XF
- (match_operand:DF 1 "general_operand" "0"))))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ (match_operand:DF 1 "register_operand" "0"))))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
"fsqrt")
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
(sqrt:XF (float_extend:XF
- (match_operand:SF 1 "general_operand" "0"))))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ (match_operand:SF 1 "register_operand" "0"))))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
"fsqrt")
(define_insn "sindf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
"fsin")
(define_insn "sinsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
"fsin")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(unspec:DF [(float_extend:DF
(match_operand:SF 1 "register_operand" "0"))] 1))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
"fsin")
(define_insn "sinxf2"
[(set (match_operand:XF 0 "register_operand" "=f")
(unspec:XF [(match_operand:XF 1 "register_operand" "0")] 1))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
"fsin")
(define_insn "cosdf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
"fcos")
(define_insn "cossf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
"fcos")
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(unspec:DF [(float_extend:DF
(match_operand:SF 1 "register_operand" "0"))] 2))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
"fcos")
(define_insn "cosxf2"
[(set (match_operand:XF 0 "register_operand" "=f")
(unspec:XF [(match_operand:XF 1 "register_operand" "0")] 2))]
- "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
- && (TARGET_IEEE_FP || flag_fast_math) "
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
"fcos")
;;- one complement instructions
(define_insn "one_cmplsi2"
- [(set (match_operand:SI 0 "general_operand" "=rm")
- (not:SI (match_operand:SI 1 "general_operand" "0")))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
""
"not%L0 %0")
(define_insn "one_cmplhi2"
- [(set (match_operand:HI 0 "general_operand" "=rm")
- (not:HI (match_operand:HI 1 "general_operand" "0")))]
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
""
"not%W0 %0")
(define_insn "one_cmplqi2"
- [(set (match_operand:QI 0 "general_operand" "=qm")
- (not:QI (match_operand:QI 1 "general_operand" "0")))]
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (not:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
""
"not%B0 %0")
@@ -3565,8 +4475,7 @@
;; separately, making all shifts emit pairs of shift double and normal
;; shift. Since sh[lr]d does not shift more than 31 bits, and we wish to
;; support a 63 bit shift, each shift where the count is in a reg expands
-;; to three pairs. If the overall shift is by N bits, then the first two
-;; pairs shift by N / 2 and the last pair by N & 1.
+;; to a pair of shifts, a branch, a shift by 32 and a label.
;; If the shift count is a constant, we need never emit more than one
;; shift pair, instead using moves and sign extension for counts greater
@@ -3596,7 +4505,7 @@
[(set (match_operand:DI 0 "register_operand" "=&r")
(ashift:DI (match_operand:DI 1 "register_operand" "0")
(match_operand:QI 2 "const_int_operand" "J")))]
- ""
+ "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')"
"*
{
rtx xops[4], low[1], high[1];
@@ -3631,35 +4540,29 @@
(define_insn "ashldi3_non_const_int"
[(set (match_operand:DI 0 "register_operand" "=&r")
(ashift:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:QI 2 "register_operand" "c")))
- (clobber (match_dup 2))]
+ (match_operand:QI 2 "register_operand" "c")))]
""
"*
{
- rtx xops[4], low[1], high[1];
+ rtx xops[5], low[1], high[1];
CC_STATUS_INIT;
split_di (operands, 1, low, high);
xops[0] = operands[2];
- xops[1] = const1_rtx;
+ xops[1] = GEN_INT (32);
xops[2] = low[0];
xops[3] = high[0];
-
- output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */
+ xops[4] = gen_label_rtx ();
output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops);
output_asm_insn (AS2 (sal%L2,%0,%2), xops);
- output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops);
- output_asm_insn (AS2 (sal%L2,%0,%2), xops);
-
- xops[1] = GEN_INT (7); /* shift count & 1 */
-
- output_asm_insn (AS2 (shr%B0,%1,%0), xops);
-
- output_asm_insn (AS3_SHIFT_DOUBLE (shld%L3,%0,%2,%3), xops);
- output_asm_insn (AS2 (sal%L2,%0,%2), xops);
-
+ output_asm_insn (AS2 (test%B0,%1,%b0), xops);
+ output_asm_insn (AS1 (je,%X4), xops);
+ output_asm_insn (AS2 (mov%L3,%2,%3), xops); /* Fast shift by 32 */
+ output_asm_insn (AS2 (xor%L2,%2,%2), xops);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (xops[4]));
RET;
}")
@@ -3668,15 +4571,15 @@
;; is smaller - use leal for now unless the shift count is 1.
(define_insn "ashlsi3"
- [(set (match_operand:SI 0 "general_operand" "=r,rm")
- (ashift:SI (match_operand:SI 1 "general_operand" "r,0")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
+ (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "r,0")
(match_operand:SI 2 "nonmemory_operand" "M,cI")))]
""
"*
{
if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
{
- if (!TARGET_386 && INTVAL (operands[2]) == 1)
+ if (TARGET_DOUBLE_WITH_ADD && INTVAL (operands[2]) == 1)
{
output_asm_insn (AS2 (mov%L0,%1,%0), operands);
return AS2 (add%L0,%1,%0);
@@ -3690,8 +4593,8 @@
output_asm_insn (AS2 (mov%L0,%1,%0), operands);
operands[1] = operands[0];
}
- operands[1] = gen_rtx (MULT, SImode, operands[1],
- GEN_INT (1 << INTVAL (operands[2])));
+ operands[1] = gen_rtx_MULT (SImode, operands[1],
+ GEN_INT (1 << INTVAL (operands[2])));
return AS2 (lea%L0,%a1,%0);
}
}
@@ -3706,8 +4609,8 @@
}")
(define_insn "ashlhi3"
- [(set (match_operand:HI 0 "general_operand" "=rm")
- (ashift:HI (match_operand:HI 1 "general_operand" "0")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
(match_operand:HI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -3722,8 +4625,8 @@
}")
(define_insn "ashlqi3"
- [(set (match_operand:QI 0 "general_operand" "=qm")
- (ashift:QI (match_operand:QI 1 "general_operand" "0")
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0")
(match_operand:QI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -3759,11 +4662,36 @@
DONE;
}")
+(define_insn "ashldi3_32"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,m")
+ (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
+ (const_int 32)))]
+ ""
+ "*
+{
+ rtx low[2], high[2], xops[4];
+
+ split_di (operands, 2, low, high);
+ xops[0] = high[0];
+ xops[1] = low[1];
+ xops[2] = low[0];
+ xops[3] = const0_rtx;
+ if (!rtx_equal_p (xops[0], xops[1]))
+ output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
+ if (GET_CODE (low[0]) == MEM)
+ output_asm_insn (AS2 (mov%L2,%3,%2), xops);
+ else
+ output_asm_insn (AS2 (xor%L2,%2,%2), xops);
+
+ RET;
+}")
+
(define_insn "ashrdi3_const_int"
[(set (match_operand:DI 0 "register_operand" "=&r")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
(match_operand:QI 2 "const_int_operand" "J")))]
- ""
+ "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')"
"*
{
rtx xops[4], low[1], high[1];
@@ -3800,41 +4728,36 @@
(define_insn "ashrdi3_non_const_int"
[(set (match_operand:DI 0 "register_operand" "=&r")
(ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:QI 2 "register_operand" "c")))
- (clobber (match_dup 2))]
+ (match_operand:QI 2 "register_operand" "c")))]
""
"*
{
- rtx xops[4], low[1], high[1];
+ rtx xops[5], low[1], high[1];
CC_STATUS_INIT;
split_di (operands, 1, low, high);
xops[0] = operands[2];
- xops[1] = const1_rtx;
+ xops[1] = GEN_INT (32);
xops[2] = low[0];
xops[3] = high[0];
-
- output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */
+ xops[4] = gen_label_rtx ();
output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
output_asm_insn (AS2 (sar%L3,%0,%3), xops);
- output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
- output_asm_insn (AS2 (sar%L3,%0,%3), xops);
-
- xops[1] = GEN_INT (7); /* shift count & 1 */
-
- output_asm_insn (AS2 (shr%B0,%1,%0), xops);
-
- output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
- output_asm_insn (AS2 (sar%L3,%0,%3), xops);
-
+ output_asm_insn (AS2 (test%B0,%1,%b0), xops);
+ output_asm_insn (AS1 (je,%X4), xops);
+ xops[1] = GEN_INT (31);
+ output_asm_insn (AS2 (mov%L2,%3,%2), xops);
+ output_asm_insn (AS2 (sar%L3,%1,%3), xops); /* shift by 32 */
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (xops[4]));
RET;
}")
(define_insn "ashrsi3"
- [(set (match_operand:SI 0 "general_operand" "=rm")
- (ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
(match_operand:SI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -3846,8 +4769,8 @@
}")
(define_insn "ashrhi3"
- [(set (match_operand:HI 0 "general_operand" "=rm")
- (ashiftrt:HI (match_operand:HI 1 "general_operand" "0")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
(match_operand:HI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -3859,8 +4782,8 @@
}")
(define_insn "ashrqi3"
- [(set (match_operand:QI 0 "general_operand" "=qm")
- (ashiftrt:QI (match_operand:QI 1 "general_operand" "0")
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
(match_operand:QI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -3895,11 +4818,36 @@
DONE;
}")
+(define_insn "lshrdi3_32"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,m")
+ (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
+ (const_int 32)))]
+ ""
+ "*
+{
+ rtx low[2], high[2], xops[4];
+
+ split_di (operands, 2, low, high);
+ xops[0] = low[0];
+ xops[1] = high[1];
+ xops[2] = high[0];
+ xops[3] = const0_rtx;
+ if (!rtx_equal_p (xops[0], xops[1]))
+ output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
+ if (GET_CODE (low[0]) == MEM)
+ output_asm_insn (AS2 (mov%L2,%3,%2), xops);
+ else
+ output_asm_insn (AS2 (xor%L2,%2,%2), xops);
+
+ RET;
+}")
+
(define_insn "lshrdi3_const_int"
[(set (match_operand:DI 0 "register_operand" "=&r")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
(match_operand:QI 2 "const_int_operand" "J")))]
- ""
+ "CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'J')"
"*
{
rtx xops[4], low[1], high[1];
@@ -3935,41 +4883,35 @@
(define_insn "lshrdi3_non_const_int"
[(set (match_operand:DI 0 "register_operand" "=&r")
(lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
- (match_operand:QI 2 "register_operand" "c")))
- (clobber (match_dup 2))]
+ (match_operand:QI 2 "register_operand" "c")))]
""
"*
{
- rtx xops[4], low[1], high[1];
+ rtx xops[5], low[1], high[1];
CC_STATUS_INIT;
split_di (operands, 1, low, high);
xops[0] = operands[2];
- xops[1] = const1_rtx;
+ xops[1] = GEN_INT (32);
xops[2] = low[0];
xops[3] = high[0];
-
- output_asm_insn (AS2 (ror%B0,%1,%0), xops); /* shift count / 2 */
-
- output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
- output_asm_insn (AS2 (shr%L3,%0,%3), xops);
- output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
- output_asm_insn (AS2 (shr%L3,%0,%3), xops);
-
- xops[1] = GEN_INT (7); /* shift count & 1 */
-
- output_asm_insn (AS2 (shr%B0,%1,%0), xops);
+ xops[4] = gen_label_rtx ();
output_asm_insn (AS3_SHIFT_DOUBLE (shrd%L2,%0,%3,%2), xops);
output_asm_insn (AS2 (shr%L3,%0,%3), xops);
-
+ output_asm_insn (AS2 (test%B0,%1,%b0), xops);
+ output_asm_insn (AS1 (je,%X4), xops);
+ output_asm_insn (AS2 (mov%L2,%3,%2), xops); /* Fast shift by 32 */
+ output_asm_insn (AS2 (xor%L3,%3,%3), xops);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (xops[4]));
RET;
}")
(define_insn "lshrsi3"
- [(set (match_operand:SI 0 "general_operand" "=rm")
- (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
(match_operand:SI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -3981,8 +4923,8 @@
}")
(define_insn "lshrhi3"
- [(set (match_operand:HI 0 "general_operand" "=rm")
- (lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
(match_operand:HI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -3994,8 +4936,8 @@
}")
(define_insn "lshrqi3"
- [(set (match_operand:QI 0 "general_operand" "=qm")
- (lshiftrt:QI (match_operand:QI 1 "general_operand" "0")
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
(match_operand:QI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -4009,8 +4951,8 @@
;;- rotate instructions
(define_insn "rotlsi3"
- [(set (match_operand:SI 0 "general_operand" "=rm")
- (rotate:SI (match_operand:SI 1 "general_operand" "0")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0")
(match_operand:SI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -4022,8 +4964,8 @@
}")
(define_insn "rotlhi3"
- [(set (match_operand:HI 0 "general_operand" "=rm")
- (rotate:HI (match_operand:HI 1 "general_operand" "0")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0")
(match_operand:HI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -4035,8 +4977,8 @@
}")
(define_insn "rotlqi3"
- [(set (match_operand:QI 0 "general_operand" "=qm")
- (rotate:QI (match_operand:QI 1 "general_operand" "0")
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0")
(match_operand:QI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -4048,8 +4990,8 @@
}")
(define_insn "rotrsi3"
- [(set (match_operand:SI 0 "general_operand" "=rm")
- (rotatert:SI (match_operand:SI 1 "general_operand" "0")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0")
(match_operand:SI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -4061,8 +5003,8 @@
}")
(define_insn "rotrhi3"
- [(set (match_operand:HI 0 "general_operand" "=rm")
- (rotatert:HI (match_operand:HI 1 "general_operand" "0")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+ (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0")
(match_operand:HI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -4074,8 +5016,8 @@
}")
(define_insn "rotrqi3"
- [(set (match_operand:QI 0 "general_operand" "=qm")
- (rotatert:QI (match_operand:QI 1 "general_operand" "0")
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+ (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0")
(match_operand:QI 2 "nonmemory_operand" "cI")))]
""
"*
@@ -4090,11 +5032,13 @@
;; This usually looses. But try a define_expand to recognize a few case
;; we can do efficiently, such as accessing the "high" QImode registers,
;; %ah, %bh, %ch, %dh.
+;; ??? Note this has a botch on the mode of operand 0, which needs to be
+;; fixed if this is ever enabled.
(define_insn "insv"
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+&r")
- (match_operand:SI 1 "general_operand" "i")
- (match_operand:SI 2 "general_operand" "i"))
- (match_operand:SI 3 "general_operand" "ri"))]
+ (match_operand:SI 1 "immediate_operand" "i")
+ (match_operand:SI 2 "immediate_operand" "i"))
+ (match_operand:SI 3 "nonmemory_operand" "ri"))]
""
"*
{
@@ -4110,7 +5054,7 @@
}
else
{
- operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]));
+ operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
if (INTVAL (operands[2]))
output_asm_insn (AS2 (ror%L0,%2,%0), operands);
output_asm_insn (AS3 (shrd%L0,%1,%3,%0), operands);
@@ -4130,7 +5074,7 @@
[(set (zero_extract:SI (match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "immediate_operand" "")
(match_operand:SI 2 "immediate_operand" ""))
- (match_operand:QI 3 "general_operand" "ri"))]
+ (match_operand:QI 3 "nonmemory_operand" "ri"))]
""
"
{
@@ -4143,22 +5087,6 @@
&& ! INTVAL (operands[1]) == 1)
FAIL;
}")
-
-;; ??? Are these constraints right?
-(define_insn ""
- [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+&qo")
- (const_int 8)
- (const_int 8))
- (match_operand:QI 1 "general_operand" "qn"))]
- ""
- "*
-{
- if (REG_P (operands[0]))
- return AS2 (mov%B0,%1,%h0);
-
- operands[0] = adj_offsettable_operand (operands[0], 1);
- return AS2 (mov%B0,%1,%0);
-}")
*/
;; On i386, the register count for a bit operation is *not* truncated,
@@ -4173,11 +5101,11 @@
;; General bit set and clear.
(define_insn ""
- [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+rm")
+ [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+rm")
(const_int 1)
- (match_operand:SI 2 "general_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
(match_operand:SI 3 "const_int_operand" "n"))]
- "TARGET_386 && GET_CODE (operands[2]) != CONST_INT"
+ "TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT"
"*
{
CC_STATUS_INIT;
@@ -4191,11 +5119,11 @@
;; Bit complement. See comments on previous pattern.
;; ??? Is this really worthwhile?
(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=rm")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(xor:SI (ashift:SI (const_int 1)
- (match_operand:SI 1 "general_operand" "r"))
- (match_operand:SI 2 "general_operand" "0")))]
- "TARGET_386 && GET_CODE (operands[1]) != CONST_INT"
+ (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "nonimmediate_operand" "0")))]
+ "TARGET_USE_BIT_TEST && GET_CODE (operands[1]) != CONST_INT"
"*
{
CC_STATUS_INIT;
@@ -4204,11 +5132,11 @@
}")
(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=rm")
- (xor:SI (match_operand:SI 1 "general_operand" "0")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+ (xor:SI (match_operand:SI 1 "nonimmediate_operand" "0")
(ashift:SI (const_int 1)
- (match_operand:SI 2 "general_operand" "r"))))]
- "TARGET_386 && GET_CODE (operands[2]) != CONST_INT"
+ (match_operand:SI 2 "register_operand" "r"))))]
+ "TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT"
"*
{
CC_STATUS_INIT;
@@ -4229,7 +5157,7 @@
(define_insn ""
[(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r")
(const_int 1)
- (match_operand:SI 1 "general_operand" "r")))]
+ (match_operand:SI 1 "register_operand" "r")))]
"GET_CODE (operands[1]) != CONST_INT"
"*
{
@@ -4272,7 +5200,7 @@
;; The CPU may access unspecified bytes around the actual target byte.
(define_insn ""
- [(set (cc0) (zero_extract (match_operand:QI 0 "general_operand" "rm")
+ [(set (cc0) (zero_extract (match_operand:QI 0 "memory_operand" "m")
(match_operand:SI 1 "const_int_operand" "n")
(match_operand:SI 2 "const_int_operand" "n")))]
"GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0])"
@@ -4403,7 +5331,8 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (sete,%0);
OUTPUT_JUMP (\"setg %0\", \"seta %0\", NULL_PTR);
@@ -4435,7 +5364,8 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (sete,%0);
OUTPUT_JUMP (\"setl %0\", \"setb %0\", \"sets %0\");
@@ -4467,7 +5397,8 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (sete,%0);
OUTPUT_JUMP (\"setge %0\", \"setae %0\", \"setns %0\");
@@ -4499,7 +5430,8 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (setb,%0);
OUTPUT_JUMP (\"setle %0\", \"setbe %0\", NULL_PTR);
@@ -4553,6 +5485,14 @@
if (cc_prev_status.flags & CC_Z_IN_NOT_C)
return \"jnc %l0\";
else
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x4000);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (jne,%l0);
+ }
+
return \"je %l0\";
}")
@@ -4585,6 +5525,14 @@
if (cc_prev_status.flags & CC_Z_IN_NOT_C)
return \"jc %l0\";
else
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x4000);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (je,%l0);
+ }
+
return \"jne %l0\";
}")
@@ -4607,9 +5555,17 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (je,%l0);
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x4100);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (je,%l0);
+ }
OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", NULL_PTR);
}")
@@ -4651,9 +5607,17 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (je,%l0);
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x100);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (jne,%l0);
+ }
OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\");
}")
@@ -4695,9 +5659,16 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (je,%l0);
-
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x100);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (je,%l0);
+ }
OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\");
}")
@@ -4739,8 +5710,16 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (jb,%l0);
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x4100);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (jne,%l0);
+ }
OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", NULL_PTR);
}")
@@ -4778,6 +5757,13 @@
if (cc_prev_status.flags & CC_Z_IN_NOT_C)
return \"jc %l0\";
else
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x4000);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (je,%l0);
+ }
return \"jne %l0\";
}")
@@ -4793,6 +5779,13 @@
if (cc_prev_status.flags & CC_Z_IN_NOT_C)
return \"jnc %l0\";
else
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x4000);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (jne,%l0);
+ }
return \"je %l0\";
}")
@@ -4805,9 +5798,16 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (jne,%l0);
-
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x4100);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (jne,%l0);
+ }
OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", NULL_PTR);
}")
@@ -4829,8 +5829,16 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (jne,%l0);
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x100);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (je,%l0);
+ }
OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\");
}")
@@ -4853,9 +5861,16 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (jne,%l0);
-
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x100);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (jne,%l0);
+ }
OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\");
}")
@@ -4877,9 +5892,17 @@
""
"*
{
- if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
+ if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+ && ! (cc_prev_status.flags & CC_FCOMI))
return AS1 (jae,%l0);
+ if (cc_prev_status.flags & CC_TEST_AX)
+ {
+ operands[1] = gen_rtx_REG (SImode, 0);
+ operands[2] = GEN_INT (0x4100);
+ output_asm_insn (AS2 (testl,%2,%1), operands);
+ return AS1 (je,%l0);
+ }
OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", NULL_PTR);
}")
@@ -4901,7 +5924,7 @@
"jmp %l0")
(define_insn "indirect_jump"
- [(set (pc) (match_operand:SI 0 "general_operand" "rm"))]
+ [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
""
"*
{
@@ -4929,7 +5952,7 @@
(define_insn ""
[(set (pc)
(if_then_else (match_operator 0 "arithmetic_comparison_operator"
- [(plus:SI (match_operand:SI 1 "general_operand" "+r,m")
+ [(plus:SI (match_operand:SI 1 "nonimmediate_operand" "+r,m")
(match_operand:SI 2 "general_operand" "rmi,ri"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
@@ -4944,7 +5967,7 @@
if (operands[2] == constm1_rtx)
output_asm_insn (AS1 (dec%L1,%1), operands);
- else if (operands[1] == const1_rtx)
+ else if (operands[2] == const1_rtx)
output_asm_insn (AS1 (inc%L1,%1), operands);
else
@@ -4956,7 +5979,7 @@
(define_insn ""
[(set (pc)
(if_then_else (match_operator 0 "arithmetic_comparison_operator"
- [(minus:SI (match_operand:SI 1 "general_operand" "+r,m")
+ [(minus:SI (match_operand:SI 1 "nonimmediate_operand" "+r,m")
(match_operand:SI 2 "general_operand" "rmi,ri"))
(const_int 0)])
(label_ref (match_operand 3 "" ""))
@@ -4980,6 +6003,110 @@
return AS1 (%J0,%l3);
}")
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 0 "general_operand" "+g")
+ (const_int 0))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int -1)))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ operands[2] = const1_rtx;
+ output_asm_insn (AS2 (sub%L0,%2,%0), operands);
+ return \"jnc %l1\";
+}")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (eq (match_operand:SI 0 "general_operand" "+g")
+ (const_int 0))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int -1)))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ operands[2] = const1_rtx;
+ output_asm_insn (AS2 (sub%L0,%2,%0), operands);
+ return \"jc %l1\";
+}")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 0 "general_operand" "+g")
+ (const_int 1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int -1)))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ output_asm_insn (AS1 (dec%L0,%0), operands);
+ return \"jnz %l1\";
+}")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (eq (match_operand:SI 0 "general_operand" "+g")
+ (const_int 1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int -1)))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ output_asm_insn (AS1 (dec%L0,%0), operands);
+ return \"jz %l1\";
+}")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (ne (match_operand:SI 0 "general_operand" "+g")
+ (const_int -1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int 1)))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ output_asm_insn (AS1 (inc%L0,%0), operands);
+ return \"jnz %l1\";
+}")
+
+(define_insn ""
+ [(set (pc)
+ (if_then_else (eq (match_operand:SI 0 "general_operand" "+g")
+ (const_int -1))
+ (label_ref (match_operand 1 "" ""))
+ (pc)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0)
+ (const_int 1)))]
+ ""
+ "*
+{
+ CC_STATUS_INIT;
+ output_asm_insn (AS1 (inc%L0,%0), operands);
+ return \"jz %l1\";
+}")
+
;; Implement switch statements when generating PIC code. Switches are
;; implemented by `tablejump' when not using -fpic.
@@ -4987,10 +6114,12 @@
(define_expand "casesi"
[(set (match_dup 5)
- (minus:SI (match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 0 "general_operand" ""))
+ (set (match_dup 6)
+ (minus:SI (match_dup 5)
(match_operand:SI 1 "general_operand" "")))
(set (cc0)
- (compare:CC (match_dup 5)
+ (compare:CC (match_dup 6)
(match_operand:SI 2 "general_operand" "")))
(set (pc)
(if_then_else (gtu (cc0)
@@ -5000,14 +6129,15 @@
(parallel
[(set (pc)
(minus:SI (reg:SI 3)
- (mem:SI (plus:SI (mult:SI (match_dup 5)
+ (mem:SI (plus:SI (mult:SI (match_dup 6)
(const_int 4))
(label_ref (match_operand 3 "" ""))))))
- (clobber (match_scratch:SI 6 ""))])]
+ (clobber (match_scratch:SI 7 ""))])]
"flag_pic"
"
{
operands[5] = gen_reg_rtx (SImode);
+ operands[6] = gen_reg_rtx (SImode);
current_function_uses_pic_offset_table = 1;
}")
@@ -5061,12 +6191,12 @@
output_asm_insn (AS2 (mov%L2,%3,%2), xops);
output_asm_insn (\"sub%L2 %l1@GOTOFF(%3,%0,4),%2\", xops);
output_asm_insn (AS1 (jmp,%*%2), xops);
- ASM_OUTPUT_ALIGN_CODE (asm_out_file);
+ ASM_OUTPUT_ALIGN (asm_out_file, i386_align_jumps);
RET;
}")
(define_insn "tablejump"
- [(set (pc) (match_operand:SI 0 "general_operand" "rm"))
+ [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))
(use (label_ref (match_operand 1 "" "")))]
""
"*
@@ -5312,9 +6442,10 @@
coprocessor registers as containing a possible return value,
simply pretend the untyped call returns a complex long double
value. */
+
emit_call_insn (TARGET_80387
- ? gen_call_value (gen_rtx (REG, XCmode, FIRST_FLOAT_REG),
- operands[0], const0_rtx)
+ ? gen_call_value (gen_rtx_REG (XCmode, FIRST_FLOAT_REG),
+ operands[0], const0_rtx)
: gen_call (operands[0], const0_rtx));
for (i = 0; i < XVECLEN (operands[2], 0); i++)
@@ -5344,19 +6475,148 @@
;; This is only done if the function's epilogue is known to be simple.
;; See comments for simple_386_epilogue in i386.c.
-(define_insn "return"
+(define_expand "return"
[(return)]
- "simple_386_epilogue ()"
+ "ix86_can_use_return_insn_p ()"
+ "")
+
+(define_insn "return_internal"
+ [(return)]
+ "reload_completed"
+ "ret")
+
+(define_insn "return_pop_internal"
+ [(return)
+ (use (match_operand:SI 0 "const_int_operand" ""))]
+ "reload_completed"
+ "ret %0")
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop")
+
+(define_expand "prologue"
+ [(const_int 1)]
+ ""
+ "
+{
+ ix86_expand_prologue ();
+ DONE;
+}")
+
+;; The use of UNSPEC here is currently not necessary - a simple SET of ebp
+;; to itself would be enough. But this way we are safe even if some optimizer
+;; becomes too clever in the future.
+(define_insn "prologue_set_stack_ptr"
+ [(set (reg:SI 7)
+ (minus:SI (reg:SI 7) (match_operand:SI 0 "immediate_operand" "i")))
+ (set (reg:SI 6) (unspec:SI [(reg:SI 6)] 4))]
+ ""
"*
{
- function_epilogue (asm_out_file, get_frame_size ());
+ rtx xops [2];
+
+ xops[0] = operands[0];
+ xops[1] = stack_pointer_rtx;
+ output_asm_insn (AS2 (sub%L1,%0,%1), xops);
RET;
}")
-(define_insn "nop"
- [(const_int 0)]
+(define_insn "prologue_set_got"
+ [(set (match_operand:SI 0 "" "")
+ (unspec_volatile
+ [(plus:SI (match_dup 0)
+ (plus:SI (match_operand:SI 1 "symbolic_operand" "")
+ (minus:SI (pc) (match_operand 2 "" ""))))] 1))]
""
- "nop")
+ "*
+{
+ char buffer[64];
+
+ if (TARGET_DEEP_BRANCH_PREDICTION)
+ {
+ sprintf (buffer, \"addl %s,%%0\", XSTR (operands[1], 0));
+ output_asm_insn (buffer, operands);
+ }
+ else
+ {
+ sprintf (buffer, \"addl %s+[.-%%X2],%%0\", XSTR (operands[1], 0));
+ output_asm_insn (buffer, operands);
+ }
+ RET;
+}")
+
+(define_insn "prologue_get_pc"
+ [(set (match_operand:SI 0 "" "")
+ (unspec_volatile [(plus:SI (pc) (match_operand 1 "" ""))] 2))]
+ ""
+ "*
+{
+ char buffer[64];
+
+ output_asm_insn (AS1 (call,%X1), operands);
+ if (! TARGET_DEEP_BRANCH_PREDICTION)
+ {
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (operands[1]));
+ }
+ RET;
+}")
+
+(define_insn "prologue_get_pc_and_set_got"
+ [(unspec_volatile [(match_operand:SI 0 "" "")] 3)]
+ ""
+ "*
+{
+ operands[1] = gen_label_rtx ();
+ output_asm_insn (AS1 (call,%X1), operands);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
+ CODE_LABEL_NUMBER (operands[1]));
+ output_asm_insn (AS1 (pop%L0,%0), operands);
+ output_asm_insn (\"addl $_GLOBAL_OFFSET_TABLE_+[.-%X1],%0\", operands);
+ RET;
+}")
+
+(define_expand "epilogue"
+ [(const_int 1)]
+ ""
+ "
+{
+ ix86_expand_epilogue ();
+ DONE;
+}")
+
+(define_insn "epilogue_set_stack_ptr"
+ [(set (reg:SI 7) (reg:SI 6))
+ (clobber (reg:SI 6))]
+ ""
+ "*
+{
+ rtx xops [2];
+
+ xops[0] = frame_pointer_rtx;
+ xops[1] = stack_pointer_rtx;
+ output_asm_insn (AS2 (mov%L0,%0,%1), xops);
+ RET;
+}")
+
+(define_insn "leave"
+ [(const_int 2)
+ (clobber (reg:SI 6))
+ (clobber (reg:SI 7))]
+ ""
+ "leave")
+
+(define_insn "pop"
+ [(set (match_operand:SI 0 "register_operand" "r")
+ (mem:SI (reg:SI 7)))
+ (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))]
+ ""
+ "*
+{
+ output_asm_insn (AS1 (pop%L0,%P0), operands);
+ RET;
+}")
(define_expand "movstrsi"
[(parallel [(set (match_operand:BLK 0 "memory_operand" "")
@@ -5380,8 +6640,8 @@
operands[5] = addr0;
operands[6] = addr1;
- operands[0] = gen_rtx (MEM, BLKmode, addr0);
- operands[1] = gen_rtx (MEM, BLKmode, addr1);
+ operands[0] = change_address (operands[0], VOIDmode, addr0);
+ operands[1] = change_address (operands[1], VOIDmode, addr1);
}")
;; It might seem that operands 0 & 1 could use predicate register_operand.
@@ -5426,6 +6686,73 @@
RET;
}")
+(define_expand "clrstrsi"
+ [(set (match_dup 3) (const_int 0))
+ (parallel [(set (match_operand:BLK 0 "memory_operand" "")
+ (const_int 0))
+ (use (match_operand:SI 1 "const_int_operand" ""))
+ (use (match_operand:SI 2 "const_int_operand" ""))
+ (use (match_dup 3))
+ (clobber (match_scratch:SI 4 ""))
+ (clobber (match_dup 5))])]
+ ""
+ "
+{
+ rtx addr0, addr1;
+
+ if (GET_CODE (operands[1]) != CONST_INT)
+ FAIL;
+
+ addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
+
+ operands[3] = gen_reg_rtx (SImode);
+ operands[5] = addr0;
+
+ operands[0] = gen_rtx_MEM (BLKmode, addr0);
+}")
+
+;; It might seem that operand 0 could use predicate register_operand.
+;; But strength reduction might offset the MEM expression. So we let
+;; reload put the address into %edi.
+
+(define_insn ""
+ [(set (mem:BLK (match_operand:SI 0 "address_operand" "D"))
+ (const_int 0))
+ (use (match_operand:SI 1 "const_int_operand" "n"))
+ (use (match_operand:SI 2 "immediate_operand" "i"))
+ (use (match_operand:SI 3 "register_operand" "a"))
+ (clobber (match_scratch:SI 4 "=&c"))
+ (clobber (match_dup 0))]
+ ""
+ "*
+{
+ rtx xops[2];
+
+ output_asm_insn (\"cld\", operands);
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ if (INTVAL (operands[1]) & ~0x03)
+ {
+ xops[0] = GEN_INT ((INTVAL (operands[1]) >> 2) & 0x3fffffff);
+ xops[1] = operands[4];
+
+ output_asm_insn (AS2 (mov%L1,%0,%1), xops);
+#ifdef INTEL_SYNTAX
+ output_asm_insn (\"rep stosd\", xops);
+#else
+ output_asm_insn (\"rep\;stosl\", xops);
+#endif
+ }
+ if (INTVAL (operands[1]) & 0x02)
+ output_asm_insn (\"stosw\", operands);
+ if (INTVAL (operands[1]) & 0x01)
+ output_asm_insn (\"stosb\", operands);
+ }
+ else
+ abort ();
+ RET;
+}")
+
(define_expand "cmpstrsi"
[(parallel [(set (match_operand:SI 0 "general_operand" "")
(compare:SI (match_operand:BLK 1 "general_operand" "")
@@ -5447,8 +6774,8 @@
operands[5] = addr1;
operands[6] = addr2;
- operands[1] = gen_rtx (MEM, BLKmode, addr1);
- operands[2] = gen_rtx (MEM, BLKmode, addr2);
+ operands[1] = gen_rtx_MEM (BLKmode, addr1);
+ operands[2] = gen_rtx_MEM (BLKmode, addr2);
}")
@@ -5464,7 +6791,7 @@
;; code to handle zero-length compares.
(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=&r")
+ [(set (match_operand:SI 0 "register_operand" "=&r")
(compare:SI (mem:BLK (match_operand:SI 1 "address_operand" "S"))
(mem:BLK (match_operand:SI 2 "address_operand" "D"))))
(use (match_operand:SI 3 "register_operand" "c"))
@@ -5475,7 +6802,7 @@
""
"*
{
- rtx xops[4], label;
+ rtx xops[2], label;
label = gen_label_rtx ();
@@ -5485,16 +6812,13 @@
output_asm_insn (\"je %l0\", &label);
xops[0] = operands[0];
- xops[1] = gen_rtx (MEM, QImode,
- gen_rtx (PLUS, SImode, operands[1], constm1_rtx));
- xops[2] = gen_rtx (MEM, QImode,
- gen_rtx (PLUS, SImode, operands[2], constm1_rtx));
- xops[3] = operands[3];
-
- output_asm_insn (AS2 (movz%B1%L0,%1,%0), xops);
- output_asm_insn (AS2 (movz%B2%L3,%2,%3), xops);
-
- output_asm_insn (AS2 (sub%L0,%3,%0), xops);
+ xops[1] = const1_rtx;
+ output_asm_insn (AS2 (sbb%L0,%0,%0), xops);
+ if (QI_REG_P (xops[0]))
+ output_asm_insn (AS2 (or%B0,%1,%b0), xops);
+ else
+ output_asm_insn (AS2 (or%L0,%1,%0), xops);
+
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label));
RET;
}")
@@ -5515,7 +6839,7 @@
cc_status.flags |= CC_NOT_SIGNED;
- xops[0] = gen_rtx (REG, QImode, 0);
+ xops[0] = gen_rtx_REG (QImode, 0);
xops[1] = CONST0_RTX (QImode);
output_asm_insn (\"cld\", operands);
@@ -5523,101 +6847,64 @@
return \"repz\;cmps%B2\";
}")
-(define_expand "ffssi2"
- [(set (match_dup 2)
- (plus:SI (ffs:SI (match_operand:SI 1 "general_operand" ""))
- (const_int -1)))
- (set (match_operand:SI 0 "general_operand" "")
- (plus:SI (match_dup 2) (const_int 1)))]
- ""
- "operands[2] = gen_reg_rtx (SImode);")
-
+
;; Note, you cannot optimize away the branch following the bsfl by assuming
;; that the destination is not modified if the input is 0, since not all
;; x86 implementations do this.
-(define_insn ""
- [(set (match_operand:SI 0 "general_operand" "=&r")
- (plus:SI (ffs:SI (match_operand:SI 1 "general_operand" "rm"))
- (const_int -1)))]
+(define_expand "ffssi2"
+ [(set (match_operand:SI 0 "general_operand" "")
+ (ffs:SI (match_operand:SI 1 "general_operand" "")))]
""
- "*
+ "
{
- rtx xops[3];
- static int ffssi_label_number;
- char buffer[30];
+ rtx label = gen_label_rtx (), temp = gen_reg_rtx (SImode);
- xops[0] = operands[0];
- xops[1] = operands[1];
- xops[2] = constm1_rtx;
- output_asm_insn (AS2 (bsf%L0,%1,%0), xops);
-#ifdef LOCAL_LABEL_PREFIX
- sprintf (buffer, \"jnz %sLFFSSI%d\",
- LOCAL_LABEL_PREFIX, ffssi_label_number);
-#else
- sprintf (buffer, \"jnz %sLFFSSI%d\",
- \"\", ffssi_label_number);
-#endif
- output_asm_insn (buffer, xops);
- output_asm_insn (AS2 (mov%L0,%2,%0), xops);
-#ifdef LOCAL_LABEL_PREFIX
- sprintf (buffer, \"%sLFFSSI%d:\",
- LOCAL_LABEL_PREFIX, ffssi_label_number);
-#else
- sprintf (buffer, \"%sLFFSSI%d:\",
- \"\", ffssi_label_number);
-#endif
- output_asm_insn (buffer, xops);
+ emit_insn (gen_ffssi_1 (temp, operands[1]));
+ emit_cmp_insn (operands[1], const0_rtx, NE, NULL_RTX, SImode, 0, 0);
+ emit_jump_insn (gen_bne (label));
+ emit_move_insn (temp, constm1_rtx);
+ emit_label (label);
+ temp = expand_binop (SImode, add_optab, temp, const1_rtx,
+ operands[0], 0, OPTAB_WIDEN);
- ffssi_label_number++;
- return \"\";
+ if (temp != operands[0])
+ emit_move_insn (operands[0], temp);
+ DONE;
}")
-(define_expand "ffshi2"
- [(set (match_dup 2)
- (plus:HI (ffs:HI (match_operand:HI 1 "general_operand" ""))
- (const_int -1)))
- (set (match_operand:HI 0 "general_operand" "")
- (plus:HI (match_dup 2) (const_int 1)))]
+(define_insn "ffssi_1"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand:SI 1 "nonimmediate_operand" "rm")] 5))]
""
- "operands[2] = gen_reg_rtx (HImode);")
+ "* return AS2 (bsf%L0,%1,%0);")
-(define_insn ""
- [(set (match_operand:HI 0 "general_operand" "=&r")
- (plus:HI (ffs:HI (match_operand:SI 1 "general_operand" "rm"))
- (const_int -1)))]
+(define_expand "ffshi2"
+ [(set (match_operand:SI 0 "general_operand" "")
+ (ffs:HI (match_operand:HI 1 "general_operand" "")))]
""
- "*
+ "
{
- rtx xops[3];
- static int ffshi_label_number;
- char buffer[30];
+ rtx label = gen_label_rtx (), temp = gen_reg_rtx (HImode);
- xops[0] = operands[0];
- xops[1] = operands[1];
- xops[2] = constm1_rtx;
- output_asm_insn (AS2 (bsf%W0,%1,%0), xops);
-#ifdef LOCAL_LABEL_PREFIX
- sprintf (buffer, \"jnz %sLFFSHI%d\",
- LOCAL_LABEL_PREFIX, ffshi_label_number);
-#else
- sprintf (buffer, \"jnz %sLFFSHI%d\",
- \"\", ffshi_label_number);
-#endif
- output_asm_insn (buffer, xops);
- output_asm_insn (AS2 (mov%W0,%2,%0), xops);
-#ifdef LOCAL_LABEL_PREFIX
- sprintf (buffer, \"%sLFFSHI%d:\",
- LOCAL_LABEL_PREFIX, ffshi_label_number);
-#else
- sprintf (buffer, \"%sLFFSHI%d:\",
- \"\", ffshi_label_number);
-#endif
- output_asm_insn (buffer, xops);
+ emit_insn (gen_ffshi_1 (temp, operands[1]));
+ emit_cmp_insn (operands[1], const0_rtx, NE, NULL_RTX, HImode, 0, 0);
+ emit_jump_insn (gen_bne (label));
+ emit_move_insn (temp, constm1_rtx);
+ emit_label (label);
+ temp = expand_binop (HImode, add_optab, temp, const1_rtx,
+ operands[0], 0, OPTAB_WIDEN);
- ffshi_label_number++;
- return \"\";
+ if (temp != operands[0])
+ emit_move_insn (operands[0], temp);
+ DONE;
}")
+
+(define_insn "ffshi_1"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (unspec:HI [(match_operand:SI 1 "nonimmediate_operand" "rm")] 5))]
+ ""
+ "* return AS2 (bsf%W0,%1,%0);")
;; These patterns match the binary 387 instructions for addM3, subM3,
;; mulM3 and divM3. There are three patterns for each of DFmode and
@@ -5633,81 +6920,171 @@
[(match_operand:DF 1 "nonimmediate_operand" "0,fm")
(match_operand:DF 2 "nonimmediate_operand" "fm,0")]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(match_operator:DF 3 "binary_387_op"
- [(float:DF (match_operand:SI 1 "general_operand" "rm"))
- (match_operand:DF 2 "general_operand" "0")]))]
+ [(float:DF (match_operand:SI 1 "nonimmediate_operand" "rm"))
+ (match_operand:DF 2 "register_operand" "0")]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f,f")
(match_operator:XF 3 "binary_387_op"
- [(match_operand:XF 1 "nonimmediate_operand" "0,f")
- (match_operand:XF 2 "nonimmediate_operand" "f,0")]))]
+ [(match_operand:XF 1 "register_operand" "0,f")
+ (match_operand:XF 2 "register_operand" "f,0")]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
(match_operator:XF 3 "binary_387_op"
- [(float:XF (match_operand:SI 1 "general_operand" "rm"))
- (match_operand:XF 2 "general_operand" "0")]))]
+ [(float:XF (match_operand:SI 1 "nonimmediate_operand" "rm"))
+ (match_operand:XF 2 "register_operand" "0")]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f,f")
(match_operator:XF 3 "binary_387_op"
- [(float_extend:XF (match_operand:SF 1 "general_operand" "fm,0"))
- (match_operand:XF 2 "general_operand" "0,f")]))]
+ [(float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
+ (match_operand:XF 2 "register_operand" "0,f")]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f")
(match_operator:XF 3 "binary_387_op"
- [(match_operand:XF 1 "general_operand" "0")
- (float:XF (match_operand:SI 2 "general_operand" "rm"))]))]
+ [(match_operand:XF 1 "register_operand" "0")
+ (float:XF (match_operand:SI 2 "nonimmediate_operand" "rm"))]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:XF 0 "register_operand" "=f,f")
(match_operator:XF 3 "binary_387_op"
- [(match_operand:XF 1 "general_operand" "0,f")
+ [(match_operand:XF 1 "register_operand" "0,f")
(float_extend:XF
- (match_operand:SF 2 "general_operand" "fm,0"))]))]
+ (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f,f")
(match_operator:DF 3 "binary_387_op"
- [(float_extend:DF (match_operand:SF 1 "general_operand" "fm,0"))
- (match_operand:DF 2 "general_operand" "0,f")]))]
+ [(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
+ (match_operand:DF 2 "register_operand" "0,f")]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f")
(match_operator:DF 3 "binary_387_op"
- [(match_operand:DF 1 "general_operand" "0")
- (float:DF (match_operand:SI 2 "general_operand" "rm"))]))]
+ [(match_operand:DF 1 "register_operand" "0")
+ (float:DF (match_operand:SI 2 "nonimmediate_operand" "rm"))]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:DF 0 "register_operand" "=f,f")
(match_operator:DF 3 "binary_387_op"
- [(match_operand:DF 1 "general_operand" "0,f")
+ [(match_operand:DF 1 "register_operand" "0,f")
(float_extend:DF
- (match_operand:SF 2 "general_operand" "fm,0"))]))]
+ (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=f,f")
@@ -5715,38 +7092,106 @@
[(match_operand:SF 1 "nonimmediate_operand" "0,fm")
(match_operand:SF 2 "nonimmediate_operand" "fm,0")]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=f")
(match_operator:SF 3 "binary_387_op"
- [(float:SF (match_operand:SI 1 "general_operand" "rm"))
- (match_operand:SF 2 "general_operand" "0")]))]
+ [(float:SF (match_operand:SI 1 "nonimmediate_operand" "rm"))
+ (match_operand:SF 2 "register_operand" "0")]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=f")
(match_operator:SF 3 "binary_387_op"
- [(match_operand:SF 1 "general_operand" "0")
- (float:SF (match_operand:SI 2 "general_operand" "rm"))]))]
+ [(match_operand:SF 1 "register_operand" "0")
+ (float:SF (match_operand:SI 2 "nonimmediate_operand" "rm"))]))]
"TARGET_80387"
- "* return output_387_binary_op (insn, operands);")
+ "* return output_387_binary_op (insn, operands);"
+ [(set (attr "type")
+ (cond [(match_operand:DF 3 "is_mul" "")
+ (const_string "fpmul")
+ (match_operand:DF 3 "is_div" "")
+ (const_string "fpdiv")
+ ]
+ (const_string "fpop")
+ )
+ )])
(define_expand "strlensi"
[(parallel [(set (match_dup 4)
(unspec:SI [(mem:BLK (match_operand:BLK 1 "general_operand" ""))
- (match_operand:QI 2 "register_operand" "")
+ (match_operand:QI 2 "immediate_operand" "")
(match_operand:SI 3 "immediate_operand" "")] 0))
(clobber (match_dup 1))])
(set (match_dup 5)
(not:SI (match_dup 4)))
(set (match_operand:SI 0 "register_operand" "")
- (minus:SI (match_dup 5)
- (const_int 1)))]
+ (plus:SI (match_dup 5)
+ (const_int -1)))]
""
"
{
+ if (TARGET_UNROLL_STRLEN && operands[2] == const0_rtx && optimize > 1)
+ {
+ rtx address;
+ rtx scratch;
+
+ /* well it seems that some optimizer does not combine a call like
+ foo(strlen(bar), strlen(bar));
+ when the move and the subtraction is done here. It does calculate
+ the length just once when these instructions are done inside of
+ output_strlen_unroll(). But I think since &bar[strlen(bar)] is
+ often used and I use one fewer register for the lifetime of
+ output_strlen_unroll() this is better. */
+ scratch = gen_reg_rtx (SImode);
+ address = force_reg (SImode, XEXP (operands[1], 0));
+
+ /* move address to scratch-register
+ this is done here because the i586 can do the following and
+ in the same cycle with the following move. */
+ if (GET_CODE (operands[3]) != CONST_INT || INTVAL (operands[3]) < 4)
+ emit_insn (gen_movsi (scratch, address));
+
+ emit_insn (gen_movsi (operands[0], address));
+
+ if(TARGET_USE_Q_REG)
+ emit_insn (gen_strlensi_unroll5 (operands[0],
+ operands[3],
+ scratch,
+ operands[0]));
+ else
+ emit_insn (gen_strlensi_unroll4 (operands[0],
+ operands[3],
+ scratch,
+ operands[0]));
+
+ /* gen_strlensi_unroll[45] returns the address of the zero
+ at the end of the string, like memchr(), so compute the
+ length by subtracting the startaddress. */
+ emit_insn (gen_subsi3 (operands[0], operands[0], address));
+ DONE;
+ }
+
operands[1] = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
operands[4] = gen_reg_rtx (SImode);
operands[5] = gen_reg_rtx (SImode);
@@ -5759,7 +7204,7 @@
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=&c")
(unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "D"))
- (match_operand:QI 2 "register_operand" "a")
+ (match_operand:QI 2 "immediate_operand" "a")
(match_operand:SI 3 "immediate_operand" "i")] 0))
(clobber (match_dup 1))]
""
@@ -5773,3 +7218,601 @@
output_asm_insn (AS2 (mov%L0,%1,%0), xops);
return \"repnz\;scas%B2\";
}")
+
+/* Conditional move define_insns. */
+
+(define_expand "movsicc"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (if_then_else:SI (match_operand 1 "comparison_operator" "")
+ (match_operand:SI 2 "nonimmediate_operand" "")
+ (match_operand:SI 3 "nonimmediate_operand" "")))]
+ "TARGET_CMOVE"
+ "
+{
+ if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
+ FAIL;
+
+ operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
+ GET_MODE (i386_compare_op0),
+ i386_compare_op0, i386_compare_op1);
+}")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (if_then_else:SI (match_operator 1 "comparison_operator"
+ [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
+ (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
+ (match_operand:SI 4 "nonimmediate_operand" "rm,rm,0,0")
+ (match_operand:SI 5 "nonimmediate_operand" "0,0,rm,rm")))]
+ "TARGET_CMOVE"
+ "#")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (if_then_else:SI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
+ (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
+ (match_operand:SI 4 "nonimmediate_operand" "rm,rm,0,0")
+ (match_operand:SI 5 "nonimmediate_operand" "0,0,rm,rm")))]
+ "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT"
+ "#")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (const_int 0)])
+ (match_operand:SI 3 "nonimmediate_operand" "rm,0")
+ (match_operand:SI 4 "nonimmediate_operand" "0,rm")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 3) (match_dup 4)))]
+ "")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (match_operand 3 "general_operand" "")])
+ (match_operand:SI 4 "nonimmediate_operand" "rm,0")
+ (match_operand:SI 5 "nonimmediate_operand" "0,rm")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0) (compare (match_dup 2) (match_dup 3)))
+ (set (match_dup 0)
+ (if_then_else:SI (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 4) (match_dup 5)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI (match_operator 1 "comparison_operator"
+ [(cc0) (const_int 0)])
+ (match_operand:SI 2 "nonimmediate_operand" "rm,0")
+ (match_operand:SI 3 "nonimmediate_operand" "0,rm")))]
+ "TARGET_CMOVE && reload_completed"
+ "* return output_int_conditional_move (which_alternative, operands);")
+
+(define_expand "movhicc"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (if_then_else:HI (match_operand 1 "comparison_operator" "")
+ (match_operand:HI 2 "nonimmediate_operand" "")
+ (match_operand:HI 3 "nonimmediate_operand" "")))]
+ "TARGET_CMOVE"
+ "
+{
+ if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
+ FAIL;
+
+ operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
+ GET_MODE (i386_compare_op0),
+ i386_compare_op0, i386_compare_op1);
+}")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
+ (if_then_else:HI (match_operator 1 "comparison_operator"
+ [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
+ (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
+ (match_operand:HI 4 "nonimmediate_operand" "rm,rm,0,0")
+ (match_operand:HI 5 "nonimmediate_operand" "0,0,rm,rm")))]
+ "TARGET_CMOVE"
+ "#")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r,r,r,r")
+ (if_then_else:HI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
+ (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
+ (match_operand:HI 4 "nonimmediate_operand" "rm,rm,0,0")
+ (match_operand:HI 5 "nonimmediate_operand" "0,0,rm,rm")))]
+ "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT"
+ "#")
+
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (if_then_else:HI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (const_int 0)])
+ (match_operand:HI 3 "nonimmediate_operand" "rm,0")
+ (match_operand:HI 4 "nonimmediate_operand" "0,rm")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (if_then_else:HI (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 3) (match_dup 4)))]
+ "")
+
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (if_then_else:HI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (match_operand 3 "general_operand" "")])
+ (match_operand:HI 4 "nonimmediate_operand" "rm,0")
+ (match_operand:HI 5 "nonimmediate_operand" "0,rm")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0)
+ (compare (match_dup 2) (match_dup 3)))
+ (set (match_dup 0)
+ (if_then_else:HI (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 4) (match_dup 5)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (if_then_else:HI (match_operator 1 "comparison_operator"
+ [(cc0) (const_int 0)])
+ (match_operand:HI 2 "nonimmediate_operand" "rm,0")
+ (match_operand:HI 3 "nonimmediate_operand" "0,rm")))]
+ "TARGET_CMOVE && reload_completed"
+ "* return output_int_conditional_move (which_alternative, operands);")
+
+(define_expand "movsfcc"
+ [(set (match_operand:SF 0 "register_operand" "")
+ (if_then_else:SF (match_operand 1 "comparison_operator" "")
+ (match_operand:SF 2 "register_operand" "")
+ (match_operand:SF 3 "register_operand" "")))]
+ "TARGET_CMOVE"
+ "
+{
+ rtx temp;
+
+ if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
+ FAIL;
+
+ /* The floating point conditional move instructions don't directly
+ support conditions resulting from a signed integer comparison. */
+
+ switch (GET_CODE (operands[1]))
+ {
+ case LT:
+ case LE:
+ case GE:
+ case GT:
+ temp = emit_store_flag (gen_reg_rtx (QImode),
+ GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1,
+ VOIDmode, 0, 0);
+
+ if (!temp)
+ FAIL;
+
+ operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx);
+ break;
+
+ default:
+ operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
+ GET_MODE (i386_compare_op0),
+ i386_compare_op0, i386_compare_op1);
+ break;
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=f,f,f,f")
+ (if_then_else:SF (match_operator 1 "comparison_operator"
+ [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
+ (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
+ (match_operand:SF 4 "register_operand" "f,f,0,0")
+ (match_operand:SF 5 "register_operand" "0,0,f,f")))]
+ "TARGET_CMOVE
+ && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
+ && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
+ "#")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=f,f,f,f")
+ (if_then_else:SF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
+ (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
+ (match_operand:SF 4 "register_operand" "f,f,0,0")
+ (match_operand:SF 5 "register_operand" "0,0,f,f")))]
+ "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT
+ && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
+ && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
+ "#")
+
+(define_split
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (if_then_else:SF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (const_int 0)])
+ (match_operand:SF 3 "register_operand" "f,0")
+ (match_operand:SF 4 "register_operand" "0,f")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 3) (match_dup 4)))]
+ "")
+
+(define_split
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (if_then_else:SF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (match_operand 3 "general_operand" "")])
+ (match_operand:SF 4 "register_operand" "f,0")
+ (match_operand:SF 5 "register_operand" "0,f")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0) (compare (match_dup 2) (match_dup 3)))
+ (set (match_dup 0)
+ (if_then_else:SF (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 4) (match_dup 5)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (if_then_else:SF (match_operator 1 "comparison_operator"
+ [(cc0) (const_int 0)])
+ (match_operand:SF 2 "register_operand" "f,0")
+ (match_operand:SF 3 "register_operand" "0,f")))]
+ "TARGET_CMOVE && reload_completed"
+ "* return output_fp_conditional_move (which_alternative, operands);")
+
+(define_expand "movdfcc"
+ [(set (match_operand:DF 0 "register_operand" "")
+ (if_then_else:DF (match_operand 1 "comparison_operator" "")
+ (match_operand:DF 2 "register_operand" "")
+ (match_operand:DF 3 "register_operand" "")))]
+ "TARGET_CMOVE"
+ "
+{
+ rtx temp;
+
+ if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
+ FAIL;
+
+ /* The floating point conditional move instructions don't directly
+ support conditions resulting from a signed integer comparison. */
+
+ switch (GET_CODE (operands[1]))
+ {
+ case LT:
+ case LE:
+ case GE:
+ case GT:
+ temp = emit_store_flag (gen_reg_rtx (QImode),
+ GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1,
+ VOIDmode, 0, 0);
+
+ if (!temp)
+ FAIL;
+
+ operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx);
+ break;
+
+ default:
+ operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
+ GET_MODE (i386_compare_op0),
+ i386_compare_op0, i386_compare_op1);
+ break;
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f,f,f,f")
+ (if_then_else:DF (match_operator 1 "comparison_operator"
+ [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
+ (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
+ (match_operand:DF 4 "register_operand" "f,f,0,0")
+ (match_operand:DF 5 "register_operand" "0,0,f,f")))]
+ "TARGET_CMOVE
+ && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
+ && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
+ "#")
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f,f,f,f")
+ (if_then_else:DF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
+ (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
+ (match_operand:DF 4 "register_operand" "f,f,0,0")
+ (match_operand:DF 5 "register_operand" "0,0,f,f")))]
+ "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT
+ && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
+ && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
+ "#")
+
+(define_split
+ [(set (match_operand:DF 0 "register_operand" "=f,f")
+ (if_then_else:DF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (const_int 0)])
+ (match_operand:DF 3 "register_operand" "f,0")
+ (match_operand:DF 4 "register_operand" "0,f")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (if_then_else:DF (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 3) (match_dup 4)))]
+ "")
+
+(define_split
+ [(set (match_operand:DF 0 "register_operand" "=f,f")
+ (if_then_else:DF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (match_operand 3 "general_operand" "")])
+ (match_operand:DF 4 "register_operand" "f,0")
+ (match_operand:DF 5 "register_operand" "0,f")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0) (compare (match_dup 2) (match_dup 3)))
+ (set (match_dup 0)
+ (if_then_else:DF (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 4) (match_dup 5)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:DF 0 "register_operand" "=f,f")
+ (if_then_else:DF (match_operator 1 "comparison_operator"
+ [(cc0) (const_int 0)])
+ (match_operand:DF 2 "register_operand" "f,0")
+ (match_operand:DF 3 "register_operand" "0,f")))]
+ "TARGET_CMOVE && reload_completed"
+ "* return output_fp_conditional_move (which_alternative, operands);")
+
+(define_expand "movxfcc"
+ [(set (match_operand:XF 0 "register_operand" "")
+ (if_then_else:XF (match_operand 1 "comparison_operator" "")
+ (match_operand:XF 2 "register_operand" "")
+ (match_operand:XF 3 "register_operand" "")))]
+ "TARGET_CMOVE"
+ "
+{
+ rtx temp;
+
+ if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
+ FAIL;
+
+ /* The floating point conditional move instructions don't directly
+ support conditions resulting from a signed integer comparison. */
+
+ switch (GET_CODE (operands[1]))
+ {
+ case LT:
+ case LE:
+ case GE:
+ case GT:
+ temp = emit_store_flag (gen_reg_rtx (QImode),
+ GET_CODE (operands[1]), i386_compare_op0, i386_compare_op1,
+ VOIDmode, 0, 0);
+
+ if (!temp)
+ FAIL;
+
+ operands[1] = gen_rtx_fmt_ee (NE, QImode, temp, const0_rtx);
+ break;
+
+ default:
+ operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
+ GET_MODE (i386_compare_op0),
+ i386_compare_op0, i386_compare_op1);
+ break;
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:XF 0 "register_operand" "=f,f,f,f")
+ (if_then_else:XF (match_operator 1 "comparison_operator"
+ [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
+ (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
+ (match_operand:XF 4 "register_operand" "f,f,0,0")
+ (match_operand:XF 5 "register_operand" "0,0,f,f")))]
+ "TARGET_CMOVE
+ && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
+ && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
+ "#")
+
+(define_insn ""
+ [(set (match_operand:XF 0 "register_operand" "=f,f,f,f")
+ (if_then_else:XF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
+ (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
+ (match_operand:XF 4 "register_operand" "f,f,0,0")
+ (match_operand:XF 5 "register_operand" "0,0,f,f")))]
+ "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT
+ && GET_CODE (operands[1]) != LT && GET_CODE (operands[1]) != LE
+ && GET_CODE (operands[1]) != GE && GET_CODE (operands[1]) != GT"
+ "#")
+
+(define_split
+ [(set (match_operand:XF 0 "register_operand" "=f,f")
+ (if_then_else:XF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (const_int 0)])
+ (match_operand:XF 3 "register_operand" "f,0")
+ (match_operand:XF 4 "register_operand" "0,f")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (if_then_else:XF (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 3) (match_dup 4)))]
+ "")
+
+(define_split
+ [(set (match_operand:XF 0 "register_operand" "=f,f")
+ (if_then_else:XF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (match_operand 3 "general_operand" "")])
+ (match_operand:XF 4 "register_operand" "f,0")
+ (match_operand:XF 5 "register_operand" "0,f")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0) (compare (match_dup 2) (match_dup 3)))
+ (set (match_dup 0)
+ (if_then_else:XF (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 4) (match_dup 5)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:XF 0 "register_operand" "=f,f")
+ (if_then_else:XF (match_operator 1 "comparison_operator"
+ [(cc0) (const_int 0)])
+ (match_operand:XF 2 "register_operand" "f,0")
+ (match_operand:XF 3 "register_operand" "0,f")))]
+ "TARGET_CMOVE && reload_completed"
+ "* return output_fp_conditional_move (which_alternative, operands);")
+
+(define_expand "movdicc"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (if_then_else:DI (match_operand 1 "comparison_operator" "")
+ (match_operand:DI 2 "nonimmediate_operand" "")
+ (match_operand:DI 3 "nonimmediate_operand" "")))]
+ "TARGET_CMOVE"
+ "
+{
+ if (GET_MODE_CLASS (GET_MODE (i386_compare_op0)) != MODE_INT)
+ FAIL;
+
+ operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]),
+ GET_MODE (i386_compare_op0),
+ i386_compare_op0, i386_compare_op1);
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=&r,&r,&r,&r")
+ (if_then_else:DI (match_operator 1 "comparison_operator"
+ [(match_operand:QI 2 "nonimmediate_operand" "q,m,q,m")
+ (match_operand:QI 3 "general_operand" "qmn,qn,qmn,qn")])
+ (match_operand:DI 4 "nonimmediate_operand" "ro,ro,0,0")
+ (match_operand:DI 5 "nonimmediate_operand" "0,0,ro,ro")))]
+ "TARGET_CMOVE"
+ "#")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=&r,&r,&r,&r")
+ (if_then_else:DI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "r,m,r,m")
+ (match_operand 3 "general_operand" "rmi,ri,rmi,ri")])
+ (match_operand:DI 4 "nonimmediate_operand" "ro,ro,0,0")
+ (match_operand:DI 5 "nonimmediate_operand" "0,0,ro,ro")))]
+ "TARGET_CMOVE && GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT"
+ "#")
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "=&r,&r")
+ (if_then_else:DI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (const_int 0)])
+ (match_operand:DI 3 "nonimmediate_operand" "ro,0")
+ (match_operand:DI 4 "nonimmediate_operand" "0,ro")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0)
+ (match_dup 2))
+ (set (match_dup 0)
+ (if_then_else:DI (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 3) (match_dup 4)))]
+ "")
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "=&r,&r")
+ (if_then_else:DI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "nonimmediate_operand" "")
+ (match_operand 3 "general_operand" "")])
+ (match_operand:DI 4 "nonimmediate_operand" "ro,0")
+ (match_operand:DI 5 "nonimmediate_operand" "0,ro")))]
+ "TARGET_CMOVE && reload_completed"
+ [(set (cc0) (compare (match_dup 2) (match_dup 3)))
+ (set (match_dup 0)
+ (if_then_else:DI (match_op_dup 1 [(cc0) (const_int 0)])
+ (match_dup 4) (match_dup 5)))]
+ "")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=&r,&r")
+ (if_then_else:DI (match_operator 1 "comparison_operator"
+ [(cc0) (const_int 0)])
+ (match_operand:DI 2 "nonimmediate_operand" "ro,0")
+ (match_operand:DI 3 "nonimmediate_operand" "0,ro")))]
+ "TARGET_CMOVE && reload_completed"
+ "* return output_int_conditional_move (which_alternative, operands);")
+
+(define_insn "strlensi_unroll"
+ [(set (match_operand:SI 0 "register_operand" "=&r,&r")
+ (unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "r,r"))
+ (match_operand:SI 2 "immediate_operand" "i,i")] 0))
+ (clobber (match_scratch:SI 3 "=&q,&r"))]
+ "optimize > 1"
+ "* return output_strlen_unroll (operands);")
+
+;; the only difference between the following patterns is the register preference
+;; on a pentium using a q-register saves one clock cycle per 4 characters
+
+(define_insn "strlensi_unroll4"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0,0"))
+ (match_operand:SI 1 "immediate_operand" "i,i")
+ (match_operand:SI 2 "register_operand" "+q,!r")] 0))
+ (clobber (match_dup 2))]
+ "(TARGET_USE_ANY_REG && optimize > 1)"
+ "* return output_strlen_unroll (operands);")
+
+(define_insn "strlensi_unroll5"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(mem:BLK (match_operand:SI 3 "register_operand" "0"))
+ (match_operand:SI 1 "immediate_operand" "i")
+ (match_operand:SI 2 "register_operand" "+q")] 0))
+ (clobber (match_dup 2))]
+ "(TARGET_USE_Q_REG && optimize > 1)"
+ "* return output_strlen_unroll (operands);"
+)
+
+(define_insn "allocate_stack_worker"
+ [(unspec:SI [(match_operand:SI 0 "register_operand" "a")] 3)
+ (set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 0)))
+ (clobber (match_dup 0))]
+ "TARGET_STACK_PROBE"
+ "* return AS1(call,__alloca);")
+
+(define_expand "allocate_stack"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (reg:SI 7) (match_operand:SI 1 "general_operand" "")))
+ (set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 1)))]
+ "TARGET_STACK_PROBE"
+ "
+{
+#ifdef CHECK_STACK_LIMIT
+ if (GET_CODE (operands[1]) == CONST_INT
+ && INTVAL (operands[1]) < CHECK_STACK_LIMIT)
+ emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ operands[1]));
+ else
+#endif
+ emit_insn (gen_allocate_stack_worker (copy_to_mode_reg (SImode,
+ operands[1])));
+
+ emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
+ DONE;
+}")
+
+(define_expand "exception_receiver"
+ [(const_int 0)]
+ "flag_pic"
+ "
+{
+ load_pic_register (1);
+ DONE;
+}")
diff --git a/contrib/gcc/config/i386/isc.h b/contrib/gcc/config/i386/isc.h
index cf8c5f6..5c39896 100644
--- a/contrib/gcc/config/i386/isc.h
+++ b/contrib/gcc/config/i386/isc.h
@@ -19,7 +19,7 @@
#define LIB_SPEC "%{shlib:-lc_s} %{posix:-lcposix} %{Xp:-lcposix} -lc -lg"
#undef CPP_SPEC
-#define CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{Xp:-D_POSIX_SOURCE}"
+#define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE} %{Xp:-D_POSIX_SOURCE}"
/* ISC 2.2 uses `char' for `wchar_t'. */
#undef WCHAR_TYPE
@@ -37,7 +37,7 @@
#undef RETURN_POPS_ARGS
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
- (TREE_CODE (FUNTYPE) == IDENTIFIER_NODE ? 0 \
+ ((FUNDECL) && TREE_CODE (FUNDECL) == IDENTIFIER_NODE ? 0 \
: (TARGET_RTD \
&& (TYPE_ARG_TYPES (FUNTYPE) == 0 \
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \
@@ -87,3 +87,7 @@
} \
fputs ("\"\n", FILE); \
} while (0)
+
+/* Work around assembler forward label references generated in exception
+ handling code. */
+#define DWARF2_UNWIND_INFO 0
diff --git a/contrib/gcc/config/i386/linux-aout.h b/contrib/gcc/config/i386/linux-aout.h
index 7e46c68..de81d87 100644
--- a/contrib/gcc/config/i386/linux-aout.h
+++ b/contrib/gcc/config/i386/linux-aout.h
@@ -1,5 +1,5 @@
-/* Definitions for Intel 386 running Linux
- Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+/* Definitions for Intel 386 running Linux-based GNU systems using a.out.
+ Copyright (C) 1992, 1994, 1995, 1997, 1998 Free Software Foundation, Inc.
Contributed by H.J. Lu (hjl@nynexst.com)
This file is part of GNU CC.
@@ -25,17 +25,16 @@ Boston, MA 02111-1307, USA. */
#include <i386/gstabs.h>
#include <linux-aout.h> /* some common stuff */
+#undef ASM_COMMENT_START
+#define ASM_COMMENT_START "#"
+
/* Specify predefined symbols in preprocessor. */
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-Dunix -Di386 -Dlinux -Asystem(unix) -Asystem(posix) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-Dunix -Dlinux -Asystem(posix)"
#undef CPP_SPEC
-#if TARGET_CPU_DEFAULT == 2
-#define CPP_SPEC "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{!m386:-D__i486__} %{posix:-D_POSIX_SOURCE}"
-#else
-#define CPP_SPEC "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{m486:-D__i486__} %{posix:-D_POSIX_SOURCE}"
-#endif
+#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}"
#undef SIZE_TYPE
#define SIZE_TYPE "unsigned int"
@@ -57,9 +56,8 @@ Boston, MA 02111-1307, USA. */
#if 1
/* We no longer link with libc_p.a or libg.a by default. If you
- * want to profile or debug the Linux C library, please add
- * -lc_p or -ggdb to LDFLAGS at the link time, respectively.
- */
+ want to profile or debug the GNU/Linux C library, please add
+ -lc_p or -ggdb to LDFLAGS at the link time, respectively. */
#define LIB_SPEC \
"%{mieee-fp:-lieee} %{p:-lgmon} %{pg:-lgmon} %{!ggdb:-lc} %{ggdb:-lg}"
#else
diff --git a/contrib/gcc/config/i386/linux-oldld.h b/contrib/gcc/config/i386/linux-oldld.h
index c3066ba..4e3085b 100644
--- a/contrib/gcc/config/i386/linux-oldld.h
+++ b/contrib/gcc/config/i386/linux-oldld.h
@@ -1,5 +1,6 @@
-/* Definitions for Intel 386 running Linux with pre-BFD a.out linkers
- Copyright (C) 1995 Free Software Foundation, Inc.
+/* Definitions for Intel 386 running Linux-based GNU systems with pre-BFD
+ a.out linkers.
+ Copyright (C) 1995, 1997, 1998 Free Software Foundation, Inc.
Contributed by Michael Meissner (meissner@cygnus.com)
This file is part of GNU CC.
@@ -25,17 +26,16 @@ Boston, MA 02111-1307, USA. */
#include <i386/gstabs.h>
#include <linux-aout.h> /* some common stuff */
+#undef ASM_COMMENT_START
+#define ASM_COMMENT_START "#"
+
/* Specify predefined symbols in preprocessor. */
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-Dunix -Di386 -Dlinux -Asystem(unix) -Asystem(posix) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-Dunix -Dlinux -Asystem(posix)"
#undef CPP_SPEC
-#if TARGET_CPU_DEFAULT == 2
-#define CPP_SPEC "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{!m386:-D__i486__} %{posix:-D_POSIX_SOURCE}"
-#else
-#define CPP_SPEC "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{m486:-D__i486__} %{posix:-D_POSIX_SOURCE}"
-#endif
+#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}"
#undef SIZE_TYPE
#define SIZE_TYPE "unsigned int"
@@ -57,9 +57,8 @@ Boston, MA 02111-1307, USA. */
#if 1
/* We no longer link with libc_p.a or libg.a by default. If you
- * want to profile or debug the Linux C library, please add
- * -lc_p or -ggdb to LDFLAGS at the link time, respectively.
- */
+ want to profile or debug the GNU/Linux C library, please add
+ lc_p or -ggdb to LDFLAGS at the link time, respectively. */
#define LIB_SPEC \
"%{mieee-fp:-lieee} %{p:-lgmon} %{pg:-lgmon} %{!ggdb:-lc} %{ggdb:-lg}"
#else
diff --git a/contrib/gcc/config/i386/linux.h b/contrib/gcc/config/i386/linux.h
index a0b49ba..8e84bb5 100644
--- a/contrib/gcc/config/i386/linux.h
+++ b/contrib/gcc/config/i386/linux.h
@@ -1,5 +1,5 @@
-/* Definitions for Intel 386 running Linux with ELF format
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+/* Definitions for Intel 386 running Linux-based GNU systems with ELF format.
+ Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Eric Youngdale.
Modified for stabs-in-ELF by H.J. Lu.
@@ -37,16 +37,19 @@ Boston, MA 02111-1307, USA. */
#undef DEFAULT_PCC_STRUCT_RETURN
#define DEFAULT_PCC_STRUCT_RETURN 1
+#undef ASM_COMMENT_START
+#define ASM_COMMENT_START "#"
+
/* This is how to output an element of a case-vector that is relative.
This is only used for PIC code. See comments by the `casesi' insn in
i386.md for an explanation of the expression this outputs. */
#undef ASM_OUTPUT_ADDR_DIFF_ELT
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
/* Indicate that jump tables go in the text section. This is
necessary when compiling PIC code. */
-#define JUMP_TABLES_IN_TEXT_SECTION
+#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic)
/* Copy this from the svr4 specifications... */
/* Define the register numbers to be used in Dwarf debugging information.
@@ -147,44 +150,19 @@ Boston, MA 02111-1307, USA. */
#undef WCHAR_TYPE_SIZE
#define WCHAR_TYPE_SIZE BITS_PER_WORD
+/* The egcs-1.1 branch is the last time we will have -Di386. -D__i386__ is the thing to use. */
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-D__ELF__ -Dunix -Di386 -Dlinux -Asystem(unix) -Asystem(posix) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-D__ELF__ -Dunix -Di386 -D__i386__ -Dlinux -Asystem(posix)"
#undef CPP_SPEC
#ifdef USE_GNULIBC_1
-#if TARGET_CPU_DEFAULT == 2
-#define CPP_SPEC "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{!m386:-D__i486__} %{posix:-D_POSIX_SOURCE}"
+#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}"
#else
-#define CPP_SPEC "%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{m486:-D__i486__} %{posix:-D_POSIX_SOURCE}"
+#define CPP_SPEC "%(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
#endif
-#else /* not USE_GNULIBC_1 */
-#define CPP_SPEC "%(cpp_cpu) %[cpp_cpu] %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
-#endif /* not USE_GNULIBC_1 */
-#undef LIBGCC_SPEC
-#define LIBGCC_SPEC "-lgcc"
-
-#undef LIB_SPEC
-#ifdef USE_GNULIBC_1
-#if 1
-/* We no longer link with libc_p.a or libg.a by default. If you
- * want to profile or debug the Linux C library, please add
- * -lc_p or -ggdb to LDFLAGS at the link time, respectively.
- */
-#define LIB_SPEC \
- "%{!shared: %{mieee-fp:-lieee} %{p:-lgmon} %{pg:-lgmon} \
- %{!ggdb:-lc} %{ggdb:-lg}}"
-#else
-#define LIB_SPEC \
- "%{!shared: \
- %{mieee-fp:-lieee} %{p:-lgmon -lc_p} %{pg:-lgmon -lc_p} \
- %{!p:%{!pg:%{!g*:-lc} %{g*:-lg}}}}"
-#endif
-#else
-#define LIB_SPEC \
- "%{!shared: %{mieee-fp:-lieee} %{pthread:-lpthread} \
- %{profile:-lc_p} %{!profile: -lc}}"
-#endif /* not USE_GNULIBC_1 */
+#undef CC1_SPEC
+#define CC1_SPEC "%(cc1_cpu) %{profile:-p}"
/* Provide a LINK_SPEC appropriate for Linux. Here we provide support
for the special GCC options -static and -shared, which allow us to
@@ -221,7 +199,7 @@ Boston, MA 02111-1307, USA. */
%{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.1}} \
%{static:-static}}}"
#endif
-#else /* not USE_GNULIBC_1 */
+#else
#define LINK_SPEC "-m elf_i386 %{shared:-shared} \
%{!shared: \
%{!ibcs: \
@@ -229,7 +207,28 @@ Boston, MA 02111-1307, USA. */
%{rdynamic:-export-dynamic} \
%{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2}} \
%{static:-static}}}"
-#endif /* not USE_GNULIBC_1 */
+#endif
/* Get perform_* macros to build libgcc.a. */
#include "i386/perform.h"
+
+/* A C statement (sans semicolon) to output to the stdio stream
+ FILE the assembler definition of uninitialized global DECL named
+ NAME whose size is SIZE bytes and alignment is ALIGN bytes.
+ Try to use asm_output_aligned_bss to implement this macro. */
+
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+ asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN)
+
+/* A C statement to output to the stdio stream FILE an assembler
+ command to advance the location counter to a multiple of 1<<LOG
+ bytes if it is within MAX_SKIP bytes.
+
+ This is used to align code labels according to Intel recommendations. */
+
+#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \
+ if ((LOG)!=0) \
+ if ((MAX_SKIP)==0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \
+ else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP))
+#endif
diff --git a/contrib/gcc/config/i386/lynx.h b/contrib/gcc/config/i386/lynx.h
index 4ac00a0..73111f9 100644
--- a/contrib/gcc/config/i386/lynx.h
+++ b/contrib/gcc/config/i386/lynx.h
@@ -1,5 +1,5 @@
/* Definitions for Intel 386 running LynxOS.
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -24,12 +24,12 @@ Boston, MA 02111-1307, USA. */
#undef CPP_PREDEFINES
#define CPP_PREDEFINES "-Dunix -Di386 -DI386 -DLynx -DIBITS32 -Asystem(unix) -Asystem(lynx) -Acpu(i386) -Amachine(i386)"
-/* This is how to output a reference to a user-level label named NAME. */
+/* The prefix to add to user-visible assembler symbols. */
/* Override the svr3 convention of adding a leading underscore. */
-#undef ASM_OUTPUT_LABELREF
-#define ASM_OUTPUT_LABELREF(FILE,NAME) fprintf (FILE, "%s", NAME)
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
/* Apparently LynxOS clobbers ebx when you call into the OS. */
diff --git a/contrib/gcc/config/i386/mingw32.h b/contrib/gcc/config/i386/mingw32.h
new file mode 100644
index 0000000..cd4d3e6
--- /dev/null
+++ b/contrib/gcc/config/i386/mingw32.h
@@ -0,0 +1,95 @@
+/* Operating system specific defines to be used when targeting GCC for
+ hosting on Windows32, using GNU tools and the Windows32 API Library,
+ as distinct from winnt.h, which is used to build GCC for use with a
+ windows style library and tool set and uses the Microsoft tools.
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Most of this is the same as for Cygwin32, except for changing some
+ specs. */
+
+#include "i386/cygwin32.h"
+
+/* Please keep changes to CPP_PREDEFINES in sync with i386/crtdll. The
+ only difference between the two should be __MSVCRT__ needed to
+ distinguish MSVC from CRTDLL runtime in mingw headers. */
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Di386 -D_WIN32 -DWIN32 -D__WIN32__ \
+ -D__MINGW32__ -D__MSVCRT__ -DWINNT -D_X86_=1 -D__STDC__=1\
+ -D__stdcall=__attribute__((__stdcall__)) \
+ -D_stdcall=__attribute__((__stdcall__)) \
+ -D__cdecl=__attribute__((__cdecl__)) \
+ -D__declspec(x)=__attribute__((x)) \
+ -Asystem(winnt) -Acpu(i386) -Amachine(i386)"
+
+/* Specific a different directory for the standard include files. */
+#undef STANDARD_INCLUDE_DIR
+#define STANDARD_INCLUDE_DIR "/usr/local/i386-mingw32/include"
+
+#define STANDARD_INCLUDE_COMPONENT "MINGW32"
+
+/* For Windows applications, include more libraries, but always include
+ kernel32. */
+#undef LIB_SPEC
+#define LIB_SPEC \
+"%{mwindows:-luser32 -lgdi32 -lcomdlg32} -lkernel32 -ladvapi32 -lshell32"
+
+/* Include in the mingw32 libraries with libgcc */
+#undef LIBGCC_SPEC
+#define LIBGCC_SPEC "-lmingw32 -lgcc -lmoldname -lmsvcrt"
+
+/* Specify a different entry point when linking a DLL */
+#undef LINK_SPEC
+#define LINK_SPEC \
+"%{mwindows:--subsystem windows} %{mdll:--dll -e _DllMainCRTStartup@12}"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{mdll:dllcrt2%O%s} %{!mdll:crt2%O%s}"
+
+#define MATH_LIBRARY "-lmsvcrt"
+
+/* Output STRING, a string representing a filename, to FILE. We canonicalize
+ it to be in MS-DOS format. */
+#define OUTPUT_QUOTED_STRING(FILE, STRING) \
+do { \
+ char c; \
+ \
+ putc ('\"', asm_file); \
+ if (STRING[1] == ':' \
+ && (STRING[2] == '/' || STRING[2] == '\\')) \
+ { \
+ putc ('/', asm_file); \
+ putc ('/', asm_file); \
+ putc (*string, asm_file); \
+ string += 2; \
+ } \
+ \
+ while ((c = *string++) != 0) \
+ { \
+ if (c == '\\') \
+ c = '/'; \
+ \
+ if (c == '\"') \
+ putc ('\\', asm_file); \
+ putc (c, asm_file); \
+ } \
+ \
+ putc ('\"', asm_file); \
+} while (0)
+
diff --git a/contrib/gcc/config/i386/moss.h b/contrib/gcc/config/i386/moss.h
new file mode 100644
index 0000000..dadf3d8
--- /dev/null
+++ b/contrib/gcc/config/i386/moss.h
@@ -0,0 +1,34 @@
+/* Definitions for Intel 386 running MOSS
+ Copyright (C) 1996 Free Software Foundation, Inc.
+ Contributed by Bryan Ford <baford@cs.utah.edu>
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* I believe in reuse... */
+#include "i386/linux.h"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-D__ELF__ -Di386 -Dmoss -Asystem(posix) -Acpu(i386) -Amachine(i386)"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "crt0.o%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtn.o%s"
+
+#undef LINK_SPEC
+
diff --git a/contrib/gcc/config/i386/netbsd.h b/contrib/gcc/config/i386/netbsd.h
index 180ff35..5978aec 100644
--- a/contrib/gcc/config/i386/netbsd.h
+++ b/contrib/gcc/config/i386/netbsd.h
@@ -30,13 +30,6 @@
#undef WCHAR_TYPE_SIZE
#define WCHAR_TYPE_SIZE 32
-#define HANDLE_SYSV_PRAGMA
-
-/* There are conflicting reports about whether this system uses
- a different assembler syntax. wilson@cygnus.com says # is right. */
-#undef COMMENT_BEGIN
-#define COMMENT_BEGIN "#"
-
#undef ASM_APP_ON
#define ASM_APP_ON "#APP\n"
@@ -51,18 +44,25 @@
i386.md for an explanation of the expression this outputs. */
#undef ASM_OUTPUT_ADDR_DIFF_ELT
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
/* Indicate that jump tables go in the text section. This is
necessary when compiling PIC code. */
-#define JUMP_TABLES_IN_TEXT_SECTION
+#define JUMP_TABLES_IN_TEXT_SECTION 1
/* Don't default to pcc-struct-return, because gcc is the only compiler, and
we want to retain compatibility with older gcc versions. */
#define DEFAULT_PCC_STRUCT_RETURN 0
+/* i386 netbsd still uses old binutils that don't insert nops by default
+ when the .align directive demands to insert extra space in the text
+ segment. */
+#undef ASM_OUTPUT_ALIGN
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ if ((LOG)!=0) fprintf ((FILE), "\t.align %d,0x90\n", (LOG))
+
/* Profiling routines, partially copied from i386/osfrose.h. */
/* Redefine this to use %eax instead of %edx. */
@@ -78,3 +78,8 @@
fprintf (FILE, "\tcall mcount\n"); \
} \
}
+
+/* Until they use ELF or something that handles dwarf2 unwinds
+ and initialization stuff better. */
+#define DWARF2_UNWIND_INFO 0
+
diff --git a/contrib/gcc/config/i386/next.h b/contrib/gcc/config/i386/next.h
index c0d6d72..65f7402 100644
--- a/contrib/gcc/config/i386/next.h
+++ b/contrib/gcc/config/i386/next.h
@@ -1,5 +1,5 @@
/* Target definitions for GNU compiler for Intel x86 CPU running NeXTSTEP
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -124,8 +124,8 @@ Boston, MA 02111-1307, USA. */
GAS requires the %cl argument, so override unx386.h. */
-#undef AS3_SHIFT_DOUBLE
-#define AS3_SHIFT_DOUBLE(a,b,c,d) AS3 (a,b,c,d)
+#undef SHIFT_DOUBLE_OMITS_COUNT
+#define SHIFT_DOUBLE_OMITS_COUNT 0
/* Print opcodes the way that GAS expects them. */
#define GAS_MNEMONICS 1
@@ -216,7 +216,7 @@ Boston, MA 02111-1307, USA. */
#undef RETURN_POPS_ARGS
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
- (TREE_CODE (FUNTYPE) == IDENTIFIER_NODE \
+ ((FUNDECL) && TREE_CODE (FUNDECL) == IDENTIFIER_NODE \
? 0 \
: (TARGET_RTD \
&& (TYPE_ARG_TYPES (FUNTYPE) == 0 \
@@ -224,3 +224,10 @@ Boston, MA 02111-1307, USA. */
== void_type_node))) ? (SIZE) : 0)
/* END Calling Convention CHANGES */
+
+/* NeXT still uses old binutils that don't insert nops by default
+ when the .align directive demands to insert extra space in the text
+ segment. */
+#undef ASM_OUTPUT_ALIGN
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ if ((LOG)!=0) fprintf ((FILE), "\t.align %d,0x90\n", (LOG))
diff --git a/contrib/gcc/config/i386/openbsd.h b/contrib/gcc/config/i386/openbsd.h
new file mode 100644
index 0000000..1b56262
--- /dev/null
+++ b/contrib/gcc/config/i386/openbsd.h
@@ -0,0 +1,130 @@
+/* Configuration for an OpenBSD i386 target.
+
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This is tested by i386gas.h. */
+#define YES_UNDERSCORES
+
+#include <i386/gstabs.h>
+
+/* Get perform_* macros to build libgcc.a. */
+#include <i386/perform.h>
+
+/* Get generic OpenBSD definitions. */
+#define OBSD_OLD_GAS
+#include <openbsd.h>
+
+/* Run-time target specifications */
+#define CPP_PREDEFINES "-D__unix__ -D__i386__ -D__OpenBSD__ -Asystem(unix) -Asystem(OpenBSD) -Acpu(i386) -Amachine(i386)"
+
+/* Layout of source language data types. */
+
+/* This must agree with <machine/ansi.h> */
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 32
+
+/* Assembler format: overall framework. */
+
+#undef ASM_APP_ON
+#define ASM_APP_ON "#APP\n"
+
+#undef ASM_APP_OFF
+#define ASM_APP_OFF "#NO_APP\n"
+
+/* The following macros were originally stolen from i386v4.h.
+ These have to be defined to get PIC code correct. */
+
+/* Assembler format: dispatch tables. */
+
+/* How to output an element of a case-vector that is relative.
+ This is only used for PIC code. See comments by the `casesi' insn in
+ i386.md for an explanation of the expression this outputs. */
+#undef ASM_OUTPUT_ADDR_DIFF_ELT
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+ fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
+
+/* Assembler format: sections. */
+
+/* Indicate when jump tables go in the text section. This is
+ necessary when compiling PIC code. */
+#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic)
+
+/* Stack & calling: aggregate returns. */
+
+/* Don't default to pcc-struct-return, because gcc is the only compiler, and
+ we want to retain compatibility with older gcc versions. */
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* Assembler format: alignment output. */
+
+/* Kludgy test: when gas is upgraded, it will have p2align, and no problems
+ with nops. */
+#ifndef HAVE_GAS_MAX_SKIP_P2ALIGN
+/* i386 OpenBSD still uses an older gas that doesn't insert nops by default
+ when the .align directive demands to insert extra space in the text
+ segment. */
+#undef ASM_OUTPUT_ALIGN
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ if ((LOG)!=0) fprintf ((FILE), "\t.align %d,0x90\n", (LOG))
+#endif
+
+/* Stack & calling: profiling. */
+
+/* OpenBSD's profiler recovers all information from the stack pointer.
+ The icky part is not here, but in machine/profile.h. */
+#undef FUNCTION_PROFILER
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ fputs (flag_pic ? "\tcall mcount@PLT\n": "\tcall mcount\n", FILE);
+
+/* Assembler format: exception region output. */
+
+/* All configurations that don't use elf must be explicit about not using
+ dwarf unwind information. egcs doesn't try too hard to check internal
+ configuration files... */
+#define DWARF2_UNWIND_INFO 0
+
+/* Assembler format: alignment output. */
+
+/* A C statement to output to the stdio stream FILE an assembler
+ command to advance the location counter to a multiple of 1<<LOG
+ bytes if it is within MAX_SKIP bytes.
+
+ This will be used to align code labels according to Intel
+ recommendations, in prevision of binutils upgrade. */
+#ifdef HAVE_GAS_MAX_SKIP_P2ALIGN
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(FILE,LOG,MAX_SKIP) \
+ do { \
+ if ((LOG) != 0) \
+ if ((MAX_SKIP) == 0) fprintf ((FILE), "\t.p2align %d\n", (LOG)); \
+ else fprintf ((FILE), "\t.p2align %d,,%d\n", (LOG), (MAX_SKIP)); \
+ } while (0)
+#endif
+
+/* Note that we pick up ASM_OUTPUT_MI_THUNK from unix.h. */
+
diff --git a/contrib/gcc/config/i386/osf1-ci.asm b/contrib/gcc/config/i386/osf1-ci.asm
new file mode 100644
index 0000000..a0f0773
--- /dev/null
+++ b/contrib/gcc/config/i386/osf1-ci.asm
@@ -0,0 +1,65 @@
+! crti.s for OSF/1, x86; derived from sol2-ci.asm.
+
+! Copyright (C) 1993, 1998 Free Software Foundation, Inc.
+! Written By Fred Fish, Nov 1992
+!
+! This file 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, or (at your option) any
+! later version.
+!
+! In addition to the permissions in the GNU General Public License, the
+! Free Software Foundation gives you unlimited permission to link the
+! compiled version of this file with other programs, and to distribute
+! those programs without any restriction coming from the use of this
+! file. (The General Public License restrictions do apply in other
+! respects; for example, they cover modification of the file, and
+! distribution when not linked into another program.)
+!
+! This file 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; see the file COPYING. If not, write to
+! the Free Software Foundation, 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+!
+! As a special exception, if you link this library with files
+! compiled with GCC to produce an executable, this does not cause
+! the resulting executable to be covered by the GNU General Public License.
+! This exception does not however invalidate any other reasons why
+! the executable file might be covered by the GNU General Public License.
+!
+
+! This file just supplies labeled starting points for the .init and .fini
+! sections. It is linked in before the values-Xx.o files and also before
+! crtbegin.o.
+
+ .file "crti.s"
+ .ident "GNU C crti.s"
+
+ .section .init
+ .globl _init
+ .type _init,@function
+_init:
+
+ .section .fini
+ .globl _fini
+ .type _fini,@function
+_fini:
+
+.globl _init_init_routine
+.data
+ .align 4
+ .type _init_init_routine,@object
+ .size _init_init_routine,4
+_init_init_routine:
+ .long _init
+.globl _init_fini_routine
+ .align 4
+ .type _init_fini_routine,@object
+ .size _init_fini_routine,4
+_init_fini_routine:
+ .long _fini
diff --git a/contrib/gcc/config/i386/osf1-cn.asm b/contrib/gcc/config/i386/osf1-cn.asm
new file mode 100644
index 0000000..a10298f
--- /dev/null
+++ b/contrib/gcc/config/i386/osf1-cn.asm
@@ -0,0 +1,46 @@
+! crtn.s for OSF/1, x86; derived from sol2-cn.asm.
+
+! Copyright (C) 1993, 1998 Free Software Foundation, Inc.
+! Written By Fred Fish, Nov 1992
+!
+! This file 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, or (at your option) any
+! later version.
+!
+! In addition to the permissions in the GNU General Public License, the
+! Free Software Foundation gives you unlimited permission to link the
+! compiled version of this file with other programs, and to distribute
+! those programs without any restriction coming from the use of this
+! file. (The General Public License restrictions do apply in other
+! respects; for example, they cover modification of the file, and
+! distribution when not linked into another program.)
+!
+! This file 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; see the file COPYING. If not, write to
+! the Free Software Foundation, 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+!
+! As a special exception, if you link this library with files
+! compiled with GCC to produce an executable, this does not cause
+! the resulting executable to be covered by the GNU General Public License.
+! This exception does not however invalidate any other reasons why
+! the executable file might be covered by the GNU General Public License.
+!
+
+! This file just supplies returns for the .init and .fini sections. It is
+! linked in after all other files.
+
+ .file "crtn.o"
+ .ident "GNU C crtn.o"
+
+ .section .init
+ ret $0x0
+
+ .section .fini
+ ret $0x0
diff --git a/contrib/gcc/config/i386/osf1elf.h b/contrib/gcc/config/i386/osf1elf.h
new file mode 100644
index 0000000..da61e8b
--- /dev/null
+++ b/contrib/gcc/config/i386/osf1elf.h
@@ -0,0 +1,260 @@
+/* OSF/1 1.3 now is compitable with SVR4, so include sysv4.h, and
+ put difference here. */
+
+#include <stdio.h>
+#include "i386/sysv4.h" /* Base i386 target machine definitions */
+#define _sys_siglist sys_siglist
+extern char *sys_siglist[];
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (i386 OSF/1)");
+
+/* WORD_SWITCH_TAKES_ARG defined in svr4 is not correct. We also
+ need an extra -soname */
+#undef WORD_SWITCH_TAKES_ARG
+#define WORD_SWITCH_TAKES_ARG(STR) \
+ (DEFAULT_WORD_SWITCH_TAKES_ARG (STR) \
+ || !strcmp (STR, "Tdata") || !strcmp (STR, "Ttext") \
+ || !strcmp (STR, "Tbss") || !strcmp (STR, "soname"))
+
+/* Note, -fpic and -fPIC are equivalent */
+#undef CPP_SPEC
+#define CPP_SPEC "\
+%{fpic: -D__SHARED__} %{fPIC: %{!fpic: -D__SHARED__}} \
+%{.S: %{!ansi:%{!traditional:%{!traditional-cpp:%{!ftraditional: -traditional}}}}} \
+%{.S: -D__LANGUAGE_ASSEMBLY %{!ansi:-DLANGUAGE_ASSEMBLY}} \
+%{.cc: -D__LANGUAGE_C_PLUS_PLUS} \
+%{.cxx: -D__LANGUAGE_C_PLUS_PLUS} \
+%{.C: -D__LANGUAGE_C_PLUS_PLUS} \
+%{.m: -D__LANGUAGE_OBJECTIVE_C} \
+%{!.S: -D__LANGUAGE_C %{!ansi:-DLANGUAGE_C}}"
+
+/* -mmcount or -mno-mcount should be used with -pg or -p */
+#undef CC1_SPEC
+#define CC1_SPEC "%{p: %{!mmcount: %{!mno-mcount: -mno-mcount }}} \
+%{!p: %{pg: %{!mmcount: %{!mno-mcount: -mno-mcount }}}}"
+
+/* Note, -D__NO_UNDERSCORES__ -D__ELF__ are provided in the older version of
+ OSF/1 gcc. We keep them here, so that old /usr/include/i386/asm.h works.
+ */
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+ "-D__NO_UNDERSCORES__ -D__ELF__ -DOSF -DOSF1 -Di386 -Dunix -Asystem(xpg4) -Asystem(osf1) -Acpu(i386) -Amachine(i386)"
+
+/* current OSF/1 doesn't provide separate crti.o and gcrti.o (and also, crtn.o
+ and gcrtn.o) for profile. */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared: \
+ %{!symbolic: \
+ %{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}}}\
+ crti.o%s \
+ crtbegin.o%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
+
+#undef ASM_SPEC
+#define ASM_SPEC "%{v*: -v}"
+
+#undef LINK_SPEC
+#define LINK_SPEC "%{v*: -v} \
+ %{h*} %{z*} \
+ %{dy:-call_shared} %{dn:-static} \
+ %{static:-static} \
+ %{shared:-shared} \
+ %{call_shared:-call_shared} \
+ %{symbolic:-Bsymbolic -shared -call_shared} \
+ %{!dy: %{!dn: %{!static: %{!shared: %{!symbolic: \
+ %{noshrlib: -static } \
+ %{!noshrlib: -call_shared}}}}}}"
+
+#undef MD_EXEC_PREFIX
+#define MD_EXEC_PREFIX "/usr/ccs/gcc/"
+
+#undef MD_STARTFILE_PREFIX
+#define MD_STARTFILE_PREFIX "/usr/ccs/lib/"
+
+/* Define this macro meaning that gcc should find the library 'libgcc.a'
+ by hand, rather than passing the argument '-lgcc' to tell the linker
+ to do the search */
+#define LINK_LIBGCC_SPECIAL
+
+/* This goes with LINK_LIBGCC_SPECIAL, we need tell libgcc.a differently */
+#undef LIBGCC_SPEC
+#define LIBGCC_SPEC "%{!shared:%{!symbolic:libgcc.a%s}}"
+
+/* A C statement to output assembler commands which will identify the object
+ file as having been compile with GNU CC. We don't need or want this for
+ OSF1. */
+#undef ASM_IDENTIFY_GCC
+#define ASM_IDENTIFY_GCC(FILE)
+
+/* Identify the front-end which produced this file. To keep symbol
+ space down, and not confuse kdb, only do this if the language is
+ not C. */
+#define ASM_IDENTIFY_LANGUAGE(STREAM) \
+{ \
+ if (strcmp (lang_identify (), "c") != 0) \
+ output_lang_identify (STREAM); \
+}
+
+/* Specify size_t, ptrdiff_t, and wchar_t types. */
+#undef SIZE_TYPE
+#undef PTRDIFF_TYPE
+#undef WCHAR_TYPE
+#undef WCHAR_TYPE_SIZE
+
+#define SIZE_TYPE "long unsigned int"
+#define PTRDIFF_TYPE "int"
+#define WCHAR_TYPE "unsigned int"
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+/* Turn off long double being 96 bits. */
+#undef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE 64
+
+/* Work with OSF/1 profile */
+#define MASK_NO_MCOUNT 000200000000 /* profiling uses mcount_ptr */
+
+#define TARGET_MCOUNT ((target_flags & MASK_NO_MCOUNT) == 0)
+
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ { "mcount", -MASK_NO_MCOUNT}, \
+ { "no-mcount", MASK_NO_MCOUNT},
+
+/* This macro generates the assembly code for function entry.
+ FILE is a stdio stream to output the code to.
+ SIZE is an int: how many units of temporary storage to allocate.
+ Refer to the array `regs_ever_live' to determine which registers
+ to save; `regs_ever_live[I]' is nonzero if register number I
+ is ever used in the function. This macro is responsible for
+ knowing which registers should not be saved even if used.
+
+ We override it here to allow for the new profiling code to go before
+ the prologue and the old mcount code to go after the prologue (and
+ after %ebx has been set up for ELF shared library support). */
+#if 0
+#define OSF_PROFILE_BEFORE_PROLOGUE \
+ (!TARGET_MCOUNT \
+ && !current_function_needs_context \
+ && (!flag_pic \
+ || !frame_pointer_needed \
+ || (!current_function_uses_pic_offset_table \
+ && !current_function_uses_const_pool)))
+#else
+#define OSF_PROFILE_BEFORE_PROLOGUE 0
+#endif
+#undef FUNCTION_PROLOGUE
+#define FUNCTION_PROLOGUE(FILE, SIZE) \
+do \
+ { \
+ char *prefix = ""; \
+ char *lprefix = LPREFIX; \
+ int labelno = profile_label_no; \
+ \
+ if (profile_flag && OSF_PROFILE_BEFORE_PROLOGUE) \
+ { \
+ if (!flag_pic) \
+ { \
+ fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \
+ fprintf (FILE, "\tcall *%s_mcount_ptr\n", prefix); \
+ } \
+ \
+ else \
+ { \
+ static int call_no = 0; \
+ \
+ fprintf (FILE, "\tcall %sPc%d\n", lprefix, call_no); \
+ fprintf (FILE, "%sPc%d:\tpopl %%eax\n", lprefix, call_no); \
+ fprintf (FILE, "\taddl $_GLOBAL_OFFSET_TABLE_+[.-%sPc%d],%%eax\n", \
+ lprefix, call_no++); \
+ fprintf (FILE, "\tleal %sP%d@GOTOFF(%%eax),%%edx\n", \
+ lprefix, labelno); \
+ fprintf (FILE, "\tmovl %s_mcount_ptr@GOT(%%eax),%%eax\n", \
+ prefix); \
+ fprintf (FILE, "\tcall *(%%eax)\n"); \
+ } \
+ } \
+ \
+ function_prologue (FILE, SIZE); \
+ } \
+while (0)
+
+/* A C statement or compound statement to output to FILE some assembler code to
+ call the profiling subroutine `mcount'. Before calling, the assembler code
+ must load the address of a counter variable into a register where `mcount'
+ expects to find the address. The name of this variable is `LP' followed by
+ the number LABELNO, so you would generate the name using `LP%d' in a
+ `fprintf'.
+
+ The details of how the address should be passed to `mcount' are determined
+ by your operating system environment, not by GNU CC. To figure them out,
+ compile a small program for profiling using the system's installed C
+ compiler and look at the assembler code that results. */
+
+#undef FUNCTION_PROFILER
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+do \
+ { \
+ if (!OSF_PROFILE_BEFORE_PROLOGUE) \
+ { \
+ char *prefix = ""; \
+ char *lprefix = LPREFIX; \
+ int labelno = LABELNO; \
+ \
+ /* Note that OSF/rose blew it in terms of calling mcount, \
+ since OSF/rose prepends a leading underscore, but mcount's \
+ doesn't. At present, we keep this kludge for ELF as well \
+ to allow old kernels to build profiling. */ \
+ \
+ if (flag_pic \
+ && !current_function_uses_pic_offset_table \
+ && !current_function_uses_const_pool) \
+ abort (); \
+ \
+ if (TARGET_MCOUNT && flag_pic) \
+ { \
+ fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \
+ lprefix, labelno); \
+ fprintf (FILE, "\tcall *%smcount@GOT(%%ebx)\n", prefix); \
+ } \
+ \
+ else if (TARGET_MCOUNT) \
+ { \
+ fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \
+ fprintf (FILE, "\tcall %smcount\n", prefix); \
+ } \
+ \
+ else if (flag_pic && frame_pointer_needed) \
+ { \
+ fprintf (FILE, "\tmovl 4(%%ebp),%%ecx\n"); \
+ fprintf (FILE, "\tpushl %%ecx\n"); \
+ fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \
+ lprefix, labelno); \
+ fprintf (FILE, "\tmovl _mcount_ptr@GOT(%%ebx),%%eax\n"); \
+ fprintf (FILE, "\tcall *(%%eax)\n"); \
+ fprintf (FILE, "\tpopl %%eax\n"); \
+ } \
+ \
+ else if (frame_pointer_needed) \
+ { \
+ fprintf (FILE, "\tmovl 4(%%ebp),%%ecx\n"); \
+ fprintf (FILE, "\tpushl %%ecx\n"); \
+ fprintf (FILE, "\tmovl $%sP%d,%%edx\n", lprefix, labelno); \
+ fprintf (FILE, "\tcall *_mcount_ptr\n"); \
+ fprintf (FILE, "\tpopl %%eax\n"); \
+ } \
+ \
+ else \
+ abort (); \
+ } \
+ } \
+while (0)
+
+#if defined (CROSS_COMPILE) && defined (HOST_BITS_PER_INT) && defined (HOST_BITS_PER_LONG) && defined (HOST_BITS_PER_LONGLONG)
+#if (HOST_BITS_PER_INT==32) && (HOST_BITS_PER_LONG==64) && (HOST_BITS_PER_LONGLONG==64)
+#define REAL_ARITHMETIC
+#endif
+#endif
diff --git a/contrib/gcc/config/i386/osf1elfgdb.h b/contrib/gcc/config/i386/osf1elfgdb.h
new file mode 100644
index 0000000..af6efa2
--- /dev/null
+++ b/contrib/gcc/config/i386/osf1elfgdb.h
@@ -0,0 +1,7 @@
+/* Target definitions for GNU compiler for Intel 80386 running OSF/1 1.3+
+ with gas and gdb. */
+
+/* Use stabs instead of DWARF debug format. */
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+#include "i386/osf1elf.h"
diff --git a/contrib/gcc/config/i386/osfelf.h b/contrib/gcc/config/i386/osfelf.h
index 7e71fe9..381ffc2 100644
--- a/contrib/gcc/config/i386/osfelf.h
+++ b/contrib/gcc/config/i386/osfelf.h
@@ -22,10 +22,10 @@ Boston, MA 02111-1307, USA. */
#include "config/i386/osfrose.h"
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-DOSF -DOSF1 -Dunix -Di386 -Asystem(unix) -Asystem(xpg4) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-DOSF -DOSF1 -Dunix -Asystem(xpg4)"
#undef CPP_SPEC
-#define CPP_SPEC "\
+#define CPP_SPEC "%(cpp_cpu) \
%{mrose: -D__ROSE__ %{!pic-none: -D__SHARED__}} \
%{!mrose: -D__ELF__ %{fpic: -D__SHARED__}} \
%{mno-underscores: -D__NO_UNDERSCORES__} \
diff --git a/contrib/gcc/config/i386/osfrose.h b/contrib/gcc/config/i386/osfrose.h
index 3aae1e1..9cfe187 100644
--- a/contrib/gcc/config/i386/osfrose.h
+++ b/contrib/gcc/config/i386/osfrose.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler.
Intel 386 (OSF/1 with OSF/rose) version.
- Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1992, 1993, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -36,16 +36,7 @@ Boston, MA 02111-1307, USA. */
-z* options (for the linker). */
#define SWITCH_TAKES_ARG(CHAR) \
- ( (CHAR) == 'D' \
- || (CHAR) == 'U' \
- || (CHAR) == 'o' \
- || (CHAR) == 'e' \
- || (CHAR) == 'T' \
- || (CHAR) == 'u' \
- || (CHAR) == 'I' \
- || (CHAR) == 'm' \
- || (CHAR) == 'L' \
- || (CHAR) == 'A' \
+ (DEFAULT_SWITCH_TAKES_ARG(CHAR) \
|| (CHAR) == 'h' \
|| (CHAR) == 'z')
@@ -99,10 +90,10 @@ Boston, MA 02111-1307, USA. */
/* Change default predefines. */
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-DOSF -DOSF1 -Dunix -Di386 -Asystem(unix) -Asystem(xpg4) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-DOSF -DOSF1 -Dunix -Asystem(xpg4)"
#undef CPP_SPEC
-#define CPP_SPEC "\
+#define CPP_SPEC "%(cpp_cpu) \
%{!melf: -D__ROSE__ %{!pic-none: -D__SHARED__}} \
%{melf: -D__ELF__ %{fpic: -D__SHARED__}} \
%{mno-underscores: -D__NO_UNDERSCORES__} \
@@ -373,6 +364,12 @@ while (0)
fprintf (FILE, "%s%s%d:\n", (TARGET_UNDERSCORES) ? "" : ".", \
PREFIX, NUM)
+/* The prefix to add to user-visible assembler symbols. */
+
+/* target_flags is not accessible by the preprocessor */
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX "_"
+
/* This is how to output a reference to a user-level label named NAME. */
#undef ASM_OUTPUT_LABELREF
@@ -384,7 +381,7 @@ while (0)
i386.md for an explanation of the expression this outputs. */
#undef ASM_OUTPUT_ADDR_DIFF_ELT
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
/* Output a definition */
@@ -407,10 +404,9 @@ while (0)
alignment to be done at such a time. Most machine descriptions do
not currently define the macro. */
-#undef ASM_OUTPUT_ALIGN_CODE
-#define ASM_OUTPUT_ALIGN_CODE(STREAM) \
- fprintf (STREAM, "\t.align\t%d\n", \
- (!TARGET_LARGE_ALIGN && i386_align_jumps > 2) ? 2 : i386_align_jumps)
+#undef LABEL_ALIGN_AFTER_BARRIER
+#define LABEL_ALIGN_AFTER_BARRIER(LABEL) \
+ ((!TARGET_LARGE_ALIGN && i386_align_jumps > 2) ? 2 : i386_align_jumps)
/* A C expression to output text to align the location counter in the
way that is desirable at the beginning of a loop.
@@ -419,9 +415,8 @@ while (0)
alignment to be done at such a time. Most machine descriptions do
not currently define the macro. */
-#undef ASM_OUTPUT_LOOP_ALIGN
-#define ASM_OUTPUT_LOOP_ALIGN(STREAM) \
- fprintf (STREAM, "\t.align\t%d\n", i386_align_loops)
+#undef LOOP_ALIGN
+#define LOOP_ALIGN(LABEL) (i386_align_loops)
/* A C statement to output to the stdio stream STREAM an assembler
command to advance the location counter to a multiple of 2 to the
diff --git a/contrib/gcc/config/i386/ptx4-i.h b/contrib/gcc/config/i386/ptx4-i.h
new file mode 100644
index 0000000..1537b4a
--- /dev/null
+++ b/contrib/gcc/config/i386/ptx4-i.h
@@ -0,0 +1,247 @@
+/* Target definitions for GNU compiler for Intel 80386 running Dynix/ptx v4
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+ Modified from sysv4.h
+ Originally written by Ron Guilmette (rfg@netcom.com).
+ Modified by Tim Wright (timw@sequent.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "i386/i386.h" /* Base i386 target machine definitions */
+#include "i386/att.h" /* Use the i386 AT&T assembler syntax */
+#include "ptx4.h" /* Rest of definitions (non architecture dependent) */
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (i386 Sequent Dynix/ptx Version 4)");
+
+/* The svr4 ABI for the i386 says that records and unions are returned
+ in memory. */
+
+#undef RETURN_IN_MEMORY
+#define RETURN_IN_MEMORY(TYPE) \
+ (TYPE_MODE (TYPE) == BLKmode)
+
+/* Define which macros to predefine. _SEQUENT_ is our extension. */
+/* This used to define X86, but james@bigtex.cactus.org says that
+ is supposed to be defined optionally by user programs--not by default. */
+#define CPP_PREDEFINES \
+ "-Di386 -Dunix -D_SEQUENT_ -Asystem(unix) -Asystem(ptx4) -Acpu(i386) -Amachine(i386)"
+
+/* This is how to output assembly code to define a `float' constant.
+ We always have to use a .long pseudo-op to do this because the native
+ SVR4 ELF assembler is buggy and it generates incorrect values when we
+ try to use the .float pseudo-op instead. */
+
+#undef ASM_OUTPUT_FLOAT
+#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
+do { long value; \
+ REAL_VALUE_TO_TARGET_SINGLE ((VALUE), value); \
+ if (sizeof (int) == sizeof (long)) \
+ fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value); \
+ else \
+ fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value); \
+ } while (0)
+
+/* This is how to output assembly code to define a `double' constant.
+ We always have to use a pair of .long pseudo-ops to do this because
+ the native SVR4 ELF assembler is buggy and it generates incorrect
+ values when we try to use the .double pseudo-op instead. */
+
+#undef ASM_OUTPUT_DOUBLE
+#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
+do { long value[2]; \
+ REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), value); \
+ if (sizeof (int) == sizeof (long)) \
+ { \
+ fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[0]); \
+ fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[1]); \
+ } \
+ else \
+ { \
+ fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[0]); \
+ fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[1]); \
+ } \
+ } while (0)
+
+
+#undef ASM_OUTPUT_LONG_DOUBLE
+#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \
+do { long value[3]; \
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE ((VALUE), value); \
+ if (sizeof (int) == sizeof (long)) \
+ { \
+ fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[0]); \
+ fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[1]); \
+ fprintf((FILE), "%s\t0x%x\n", ASM_LONG, value[2]); \
+ } \
+ else \
+ { \
+ fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[0]); \
+ fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[1]); \
+ fprintf((FILE), "%s\t0x%lx\n", ASM_LONG, value[2]); \
+ } \
+ } while (0)
+
+/* Output at beginning of assembler file. */
+/* The .file command should always begin the output. */
+
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+ do { \
+ output_file_directive (FILE, main_input_filename); \
+ fprintf (FILE, "\t.version\t\"01.01\"\n"); \
+ } while (0)
+
+/* Define the register numbers to be used in Dwarf debugging information.
+ The SVR4 reference port C compiler uses the following register numbers
+ in its Dwarf output code:
+
+ 0 for %eax (gnu regno = 0)
+ 1 for %ecx (gnu regno = 2)
+ 2 for %edx (gnu regno = 1)
+ 3 for %ebx (gnu regno = 3)
+ 4 for %esp (gnu regno = 7)
+ 5 for %ebp (gnu regno = 6)
+ 6 for %esi (gnu regno = 4)
+ 7 for %edi (gnu regno = 5)
+
+ The following three DWARF register numbers are never generated by
+ the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4
+ believes these numbers have these meanings.
+
+ 8 for %eip (no gnu equivalent)
+ 9 for %eflags (no gnu equivalent)
+ 10 for %trapno (no gnu equivalent)
+
+ It is not at all clear how we should number the FP stack registers
+ for the x86 architecture. If the version of SDB on x86/svr4 were
+ a bit less brain dead with respect to floating-point then we would
+ have a precedent to follow with respect to DWARF register numbers
+ for x86 FP registers, but the SDB on x86/svr4 is so completely
+ broken with respect to FP registers that it is hardly worth thinking
+ of it as something to strive for compatibility with.
+
+ The version of x86/svr4 SDB I have at the moment does (partially)
+ seem to believe that DWARF register number 11 is associated with
+ the x86 register %st(0), but that's about all. Higher DWARF
+ register numbers don't seem to be associated with anything in
+ particular, and even for DWARF regno 11, SDB only seems to under-
+ stand that it should say that a variable lives in %st(0) (when
+ asked via an `=' command) if we said it was in DWARF regno 11,
+ but SDB still prints garbage when asked for the value of the
+ variable in question (via a `/' command).
+
+ (Also note that the labels SDB prints for various FP stack regs
+ when doing an `x' command are all wrong.)
+
+ Note that these problems generally don't affect the native SVR4
+ C compiler because it doesn't allow the use of -O with -g and
+ because when it is *not* optimizing, it allocates a memory
+ location for each floating-point variable, and the memory
+ location is what gets described in the DWARF AT_location
+ attribute for the variable in question.
+
+ Regardless of the severe mental illness of the x86/svr4 SDB, we
+ do something sensible here and we use the following DWARF
+ register numbers. Note that these are all stack-top-relative
+ numbers.
+
+ 11 for %st(0) (gnu regno = 8)
+ 12 for %st(1) (gnu regno = 9)
+ 13 for %st(2) (gnu regno = 10)
+ 14 for %st(3) (gnu regno = 11)
+ 15 for %st(4) (gnu regno = 12)
+ 16 for %st(5) (gnu regno = 13)
+ 17 for %st(6) (gnu regno = 14)
+ 18 for %st(7) (gnu regno = 15)
+*/
+
+#undef DBX_REGISTER_NUMBER
+#define DBX_REGISTER_NUMBER(n) \
+((n) == 0 ? 0 \
+ : (n) == 1 ? 2 \
+ : (n) == 2 ? 1 \
+ : (n) == 3 ? 3 \
+ : (n) == 4 ? 6 \
+ : (n) == 5 ? 7 \
+ : (n) == 6 ? 5 \
+ : (n) == 7 ? 4 \
+ : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \
+ : (-1))
+
+/* The routine used to output sequences of byte values. We use a special
+ version of this for most svr4 targets because doing so makes the
+ generated assembly code more compact (and thus faster to assemble)
+ as well as more readable. Note that if we find subparts of the
+ character sequence which end with NUL (and which are shorter than
+ STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING. */
+
+#undef ASM_OUTPUT_ASCII
+#define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \
+ do \
+ { \
+ register unsigned char *_ascii_bytes = (unsigned char *) (STR); \
+ register unsigned char *limit = _ascii_bytes + (LENGTH); \
+ register unsigned bytes_in_chunk = 0; \
+ for (; _ascii_bytes < limit; _ascii_bytes++) \
+ { \
+ register unsigned char *p; \
+ if (bytes_in_chunk >= 64) \
+ { \
+ fputc ('\n', (FILE)); \
+ bytes_in_chunk = 0; \
+ } \
+ for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \
+ continue; \
+ if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \
+ { \
+ if (bytes_in_chunk > 0) \
+ { \
+ fputc ('\n', (FILE)); \
+ bytes_in_chunk = 0; \
+ } \
+ ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes); \
+ _ascii_bytes = p; \
+ } \
+ else \
+ { \
+ if (bytes_in_chunk == 0) \
+ fprintf ((FILE), "\t.byte\t"); \
+ else \
+ fputc (',', (FILE)); \
+ fprintf ((FILE), "0x%02x", *_ascii_bytes); \
+ bytes_in_chunk += 5; \
+ } \
+ } \
+ if (bytes_in_chunk > 0) \
+ fprintf ((FILE), "\n"); \
+ } \
+ while (0)
+
+/* This is how to output an element of a case-vector that is relative.
+ This is only used for PIC code. See comments by the `casesi' insn in
+ i386.md for an explanation of the expression this outputs. */
+
+#undef ASM_OUTPUT_ADDR_DIFF_ELT
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+ fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
+
+/* Indicate that jump tables go in the text section. This is
+ necessary when compiling PIC code. */
+
+#define JUMP_TABLES_IN_TEXT_SECTION 1
diff --git a/contrib/gcc/config/i386/rtems.h b/contrib/gcc/config/i386/rtems.h
new file mode 100644
index 0000000..60e6dc7
--- /dev/null
+++ b/contrib/gcc/config/i386/rtems.h
@@ -0,0 +1,34 @@
+/* Definitions for rtems targeting an Intel i386 using coff.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Joel Sherrill (joel@OARcorp.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "i386/i386-coff.h"
+
+/* Specify predefined symbols in preprocessor. */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Di386 -Drtems -D__rtems__ \
+ -Asystem(rtems) -Acpu(i386) -Amachine(i386)"
+
+/* Generate calls to memcpy, memcmp and memset. */
+#ifndef TARGET_MEM_FUNCTIONS
+#define TARGET_MEM_FUNCTIONS
+#endif
+
diff --git a/contrib/gcc/config/i386/rtemself.h b/contrib/gcc/config/i386/rtemself.h
new file mode 100644
index 0000000..d9d9733
--- /dev/null
+++ b/contrib/gcc/config/i386/rtemself.h
@@ -0,0 +1,169 @@
+/* Definitions for Intel 386 running Linux-based GNU systems with ELF format.
+ Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Eric Youngdale.
+ Modified for stabs-in-ELF by H.J. Lu.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#define LINUX_DEFAULT_ELF
+
+/* A lie, I guess, but the general idea behind linux/ELF is that we are
+ supposed to be outputting something that will assemble under SVr4.
+ This gets us pretty close. */
+#include <i386/i386.h> /* Base i386 target machine definitions */
+#include <i386/att.h> /* Use the i386 AT&T assembler syntax */
+#include <linux.h> /* some common stuff */
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (i386 RTEMS with ELF)");
+
+/* The svr4 ABI for the i386 says that records and unions are returned
+ in memory. */
+#undef DEFAULT_PCC_STRUCT_RETURN
+#define DEFAULT_PCC_STRUCT_RETURN 1
+
+/* This is how to output an element of a case-vector that is relative.
+ This is only used for PIC code. See comments by the `casesi' insn in
+ i386.md for an explanation of the expression this outputs. */
+#undef ASM_OUTPUT_ADDR_DIFF_ELT
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+ fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
+
+/* Indicate that jump tables go in the text section. This is
+ necessary when compiling PIC code. */
+#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic)
+
+/* Copy this from the svr4 specifications... */
+/* Define the register numbers to be used in Dwarf debugging information.
+ The SVR4 reference port C compiler uses the following register numbers
+ in its Dwarf output code:
+ 0 for %eax (gnu regno = 0)
+ 1 for %ecx (gnu regno = 2)
+ 2 for %edx (gnu regno = 1)
+ 3 for %ebx (gnu regno = 3)
+ 4 for %esp (gnu regno = 7)
+ 5 for %ebp (gnu regno = 6)
+ 6 for %esi (gnu regno = 4)
+ 7 for %edi (gnu regno = 5)
+ The following three DWARF register numbers are never generated by
+ the SVR4 C compiler or by the GNU compilers, but SDB on x86/svr4
+ believes these numbers have these meanings.
+ 8 for %eip (no gnu equivalent)
+ 9 for %eflags (no gnu equivalent)
+ 10 for %trapno (no gnu equivalent)
+ It is not at all clear how we should number the FP stack registers
+ for the x86 architecture. If the version of SDB on x86/svr4 were
+ a bit less brain dead with respect to floating-point then we would
+ have a precedent to follow with respect to DWARF register numbers
+ for x86 FP registers, but the SDB on x86/svr4 is so completely
+ broken with respect to FP registers that it is hardly worth thinking
+ of it as something to strive for compatibility with.
+ The version of x86/svr4 SDB I have at the moment does (partially)
+ seem to believe that DWARF register number 11 is associated with
+ the x86 register %st(0), but that's about all. Higher DWARF
+ register numbers don't seem to be associated with anything in
+ particular, and even for DWARF regno 11, SDB only seems to under-
+ stand that it should say that a variable lives in %st(0) (when
+ asked via an `=' command) if we said it was in DWARF regno 11,
+ but SDB still prints garbage when asked for the value of the
+ variable in question (via a `/' command).
+ (Also note that the labels SDB prints for various FP stack regs
+ when doing an `x' command are all wrong.)
+ Note that these problems generally don't affect the native SVR4
+ C compiler because it doesn't allow the use of -O with -g and
+ because when it is *not* optimizing, it allocates a memory
+ location for each floating-point variable, and the memory
+ location is what gets described in the DWARF AT_location
+ attribute for the variable in question.
+ Regardless of the severe mental illness of the x86/svr4 SDB, we
+ do something sensible here and we use the following DWARF
+ register numbers. Note that these are all stack-top-relative
+ numbers.
+ 11 for %st(0) (gnu regno = 8)
+ 12 for %st(1) (gnu regno = 9)
+ 13 for %st(2) (gnu regno = 10)
+ 14 for %st(3) (gnu regno = 11)
+ 15 for %st(4) (gnu regno = 12)
+ 16 for %st(5) (gnu regno = 13)
+ 17 for %st(6) (gnu regno = 14)
+ 18 for %st(7) (gnu regno = 15)
+*/
+#undef DBX_REGISTER_NUMBER
+#define DBX_REGISTER_NUMBER(n) \
+((n) == 0 ? 0 \
+ : (n) == 1 ? 2 \
+ : (n) == 2 ? 1 \
+ : (n) == 3 ? 3 \
+ : (n) == 4 ? 6 \
+ : (n) == 5 ? 7 \
+ : (n) == 6 ? 5 \
+ : (n) == 7 ? 4 \
+ : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \
+ : (-1))
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry. */
+
+#undef FUNCTION_PROFILER
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+{ \
+ if (flag_pic) \
+ { \
+ fprintf (FILE, "\tleal %sP%d@GOTOFF(%%ebx),%%edx\n", \
+ LPREFIX, (LABELNO)); \
+ fprintf (FILE, "\tcall *mcount@GOT(%%ebx)\n"); \
+ } \
+ else \
+ { \
+ fprintf (FILE, "\tmovl $%sP%d,%%edx\n", LPREFIX, (LABELNO)); \
+ fprintf (FILE, "\tcall mcount\n"); \
+ } \
+}
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Di386 -Drtems -D__rtems__ \
+ -Asystem(rtems) -Acpu(i386) -Amachine(i386)"
+
+/* Get perform_* macros to build libgcc.a. */
+#include "i386/perform.h"
+
+/* A C statement (sans semicolon) to output to the stdio stream
+ FILE the assembler definition of uninitialized global DECL named
+ NAME whose size is SIZE bytes and alignment is ALIGN bytes.
+ Try to use asm_output_aligned_bss to implement this macro. */
+
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+ asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN)
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "crt0.o%s"
+
+#undef ENDFILE_SPEC
+
diff --git a/contrib/gcc/config/i386/sco.h b/contrib/gcc/config/i386/sco.h
index 37dc032..016e0a0 100644
--- a/contrib/gcc/config/i386/sco.h
+++ b/contrib/gcc/config/i386/sco.h
@@ -1,5 +1,5 @@
/* Definitions for Intel 386 running SCO Unix System V.
- Copyright (C) 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1992, 1994, 1995 Free, 1996 Software Foundation, Inc.
This file is part of GNU CC.
@@ -55,10 +55,10 @@ Boston, MA 02111-1307, USA. */
/* Specify predefined symbols in preprocessor. */
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-Dunix -Di386 -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP -Asystem(unix) -Asystem(svr3) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-Dunix -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP -Asystem(svr3)"
#undef CPP_SPEC
-#define CPP_SPEC "%{scointl:-DM_INTERNAT}"
+#define CPP_SPEC "%(cpp_cpu) %{scointl:-DM_INTERNAT}"
/* This spec is used for telling cpp whether char is signed or not. */
@@ -104,7 +104,7 @@ Boston, MA 02111-1307, USA. */
#undef RETURN_POPS_ARGS
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
- (TREE_CODE (FUNTYPE) == IDENTIFIER_NODE ? 0 \
+ ((FUNDECL) && TREE_CODE (FUNDECL) == IDENTIFIER_NODE ? 0 \
: (TARGET_RTD \
&& (TYPE_ARG_TYPES (FUNTYPE) == 0 \
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \
diff --git a/contrib/gcc/config/i386/sco4.h b/contrib/gcc/config/i386/sco4.h
index fc389b4..5d1ea47 100644
--- a/contrib/gcc/config/i386/sco4.h
+++ b/contrib/gcc/config/i386/sco4.h
@@ -63,11 +63,11 @@ Boston, MA 02111-1307, USA. */
#undef CPP_PREDEFINES
#define CPP_PREDEFINES \
- "-Asystem(unix) -Asystem(svr3) -Acpu(i386) -Amachine(i386)"
+ "-Asystem(svr3)"
#undef CPP_SPEC
-#define CPP_SPEC \
- "-D_i386 -D_M_I386 -D_M_I86 -D_M_I86SM -D_M_SDATA -D_M_STEXT \
+#define CPP_SPEC "%(cpp_cpu) \
+ -D_i386 -D_M_I386 -D_M_I86 -D_M_I86SM -D_M_SDATA -D_M_STEXT \
-D_unix -D_M_UNIX -D_M_XENIX \
-D_M_SYS5 -D_M_SYSV -D_M_SYS3 -D_M_SYSIII \
-D_M_COFF -D_M_BITFIELDS -D_M_WORDSWAP \
diff --git a/contrib/gcc/config/i386/sco4dbx.h b/contrib/gcc/config/i386/sco4dbx.h
index 0387c24..3d075b6 100644
--- a/contrib/gcc/config/i386/sco4dbx.h
+++ b/contrib/gcc/config/i386/sco4dbx.h
@@ -61,11 +61,11 @@ Boston, MA 02111-1307, USA. */
Specify predefined symbols in preprocessor. */
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-Di386 -Dunix -Asystem(unix) -Asystem(svr3) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-Dunix -Asystem(svr3)"
#undef CPP_SPEC
-#define CPP_SPEC \
- "-D_M_I386 -D_M_I86 -D_M_I86SM -D_M_SDATA -D_M_STEXT \
+#define CPP_SPEC "%(cpp_cpu) \
+ -D_M_I386 -D_M_I86 -D_M_I86SM -D_M_SDATA -D_M_STEXT \
-D_M_UNIX -D_M_XENIX \
-D_M_SYS5 -D_M_SYSV -D_M_SYS3 -D_M_SYSIII \
-D_M_COFF -D_M_BITFIELDS -D_M_WORDSWAP \
diff --git a/contrib/gcc/config/i386/sco5.h b/contrib/gcc/config/i386/sco5.h
new file mode 100644
index 0000000..74fb891
--- /dev/null
+++ b/contrib/gcc/config/i386/sco5.h
@@ -0,0 +1,957 @@
+/* Definitions for Intel 386 running SCO Unix System V 3.2 Version 5.
+ Copyright (C) 1992, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Kean Johnston (hug@netcom.com)
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "i386/i386.h" /* Base i386 target definitions */
+#include "i386/att.h" /* Use AT&T i386 assembler syntax */
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (i386, SCO OpenServer 5 Syntax)");
+
+#undef LPREFIX
+#define LPREFIX ".L"
+
+#undef ALIGN_ASM_OP
+#define ALIGN_ASM_OP "\t.align"
+
+#undef ASCII_DATA_ASM_OP
+#define ASCII_DATA_ASM_OP "\t.ascii"
+
+#undef ASM_BYTE_OP
+#define ASM_BYTE_OP "\t.byte"
+
+#undef IDENT_ASM_OP
+#define IDENT_ASM_OP "\t.ident"
+
+#undef COMMON_ASM_OP
+#define COMMON_ASM_OP "\t.comm"
+
+#undef SET_ASM_OP
+#define SET_ASM_OP "\t.set"
+
+#undef LOCAL_ASM_OP
+#define LOCAL_ASM_OP "\t.local"
+
+#undef INT_ASM_OP
+#define INT_ASM_OP "\t.long"
+
+#undef ASM_SHORT
+#define ASM_SHORT "\t.value"
+
+#undef ASM_LONG
+#define ASM_LONG "\t.long"
+
+#undef ASM_DOUBLE
+#define ASM_DOUBLE "\t.double"
+
+#undef TYPE_ASM_OP
+#define TYPE_ASM_OP "\t.type"
+
+#undef SIZE_ASM_OP
+#define SIZE_ASM_OP "\t.size"
+
+#undef STRING_ASM_OP
+#define STRING_ASM_OP "\t.string"
+
+#undef SKIP_ASM_OP
+#define SKIP_ASM_OP "\t.zero"
+
+#undef GLOBAL_ASM_OP
+#define GLOBAL_ASM_OP "\t.globl"
+
+#undef EH_FRAME_SECTION_ASM_OP
+#define EH_FRAME_SECTION_ASM_OP_COFF "\t.section\t.ehfram, \"x\""
+#define EH_FRAME_SECTION_ASM_OP_ELF "\t.section\t.eh_frame, \"aw\""
+#define EH_FRAME_SECTION_ASM_OP \
+ ((TARGET_ELF) ? EH_FRAME_SECTION_ASM_OP_ELF : EH_FRAME_SECTION_ASM_OP_COFF)
+
+/* Avoid problems (long sectino names, forward assembler refs) with DWARF
+ exception unwinding when we're generating COFF */
+#define DWARF2_UNWIND_INFO \
+ ((TARGET_ELF) ? 1 : 0 )
+
+#undef CONST_SECTION_ASM_OP
+#define CONST_SECTION_ASM_OP_COFF "\t.section\t.rodata, \"x\""
+#define CONST_SECTION_ASM_OP_ELF "\t.section\t.rodata"
+#define CONST_SECTION_ASM_OP \
+ ((TARGET_ELF) ? CONST_SECTION_ASM_OP_ELF : CONST_SECTION_ASM_OP_COFF)
+
+#undef USE_CONST_SECTION
+#define USE_CONST_SECTION_ELF 1
+#define USE_CONST_SECTION_COFF 0
+#define USE_CONST_SECTION \
+ ((TARGET_ELF) ? USE_CONST_SECTION_ELF : USE_CONST_SECTION_COFF)
+
+#undef INIT_SECTION_ASM_OP
+#define INIT_SECTION_ASM_OP_ELF "\t.section\t.init"
+#define INIT_SECTION_ASM_OP_COFF "\t.section\t.init ,\"x\""
+#define INIT_SECTION_ASM_OP \
+ ((TARGET_ELF) ? INIT_SECTION_ASM_OP_ELF : INIT_SECTION_ASM_OP_COFF)
+
+#undef CTORS_SECTION_ASM_OP
+#define CTORS_SECTION_ASM_OP_ELF "\t.section\t.ctors,\"aw\""
+#define CTORS_SECTION_ASM_OP_COFF INIT_SECTION_ASM_OP_COFF
+#define CTORS_SECTION_ASM_OP \
+ ((TARGET_ELF) ? CTORS_SECTION_ASM_OP_ELF : CTORS_SECTION_ASM_OP_COFF)
+
+#undef DTORS_SECTION_ASM_OP
+#define DTORS_SECTION_ASM_OP_ELF "\t.section\t.dtors, \"aw\""
+#define DTORS_SECTION_ASM_OP_COFF FINI_SECTION_ASM_OP_COFF
+#define DTORS_SECTION_ASM_OP \
+ ((TARGET_ELF) ? DTORS_SECTION_ASM_OP_ELF : DTORS_SECTION_ASM_OP_COFF)
+
+#undef FINI_SECTION_ASM_OP
+#define FINI_SECTION_ASM_OP_ELF "\t.section\t.fini"
+#define FINI_SECTION_ASM_OP_COFF "\t.section\t.fini, \"x\""
+#define FINI_SECTION_ASM_OP \
+ ((TARGET_ELF) ? FINI_SECTION_ASM_OP_ELF : FINI_SECTION_ASM_OP_COFF)
+
+#undef BSS_SECTION_ASM_OP
+#define BSS_SECTION_ASM_OP "\t.data"
+
+#undef TEXT_SECTION_ASM_OP
+#define TEXT_SECTION_ASM_OP "\t.text"
+
+#undef DATA_SECTION_ASM_OP
+#define DATA_SECTION_ASM_OP "\t.data"
+
+#undef TYPE_OPERAND_FMT
+#define TYPE_OPERAND_FMT "@%s"
+
+#undef APPLY_RESULT_SIZE
+#define APPLY_RESULT_SIZE \
+(TARGET_ELF) ? size : 116
+
+#ifndef ASM_DECLARE_RESULT
+#define ASM_DECLARE_RESULT(FILE, RESULT)
+#endif
+
+#define SCO_DEFAULT_ASM_COFF(FILE,NAME) \
+do { \
+ ASM_OUTPUT_LABEL (FILE, NAME); \
+ } while (0)
+
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
+ do { \
+ if (TARGET_ELF) { \
+ fprintf (FILE, "%s\t ", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ putc (',', FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "function"); \
+ putc ('\n', FILE); \
+ ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
+ ASM_OUTPUT_LABEL(FILE, NAME); \
+ } else \
+ SCO_DEFAULT_ASM_COFF(FILE, NAME); \
+} while (0)
+
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
+ do { \
+ if (TARGET_ELF) { if (!flag_inhibit_size_directive) \
+ { \
+ fprintf (FILE, "%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, (FNAME)); \
+ fprintf (FILE, ",.-"); \
+ assemble_name (FILE, (FNAME)); \
+ putc ('\n', FILE); \
+ } } \
+ } while (0)
+
+#undef ASM_DECLARE_OBJECT_NAME
+#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \
+ do { \
+ if (TARGET_ELF) { \
+ fprintf (FILE, "%s\t ", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ putc (',', FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
+ putc ('\n', FILE); \
+ size_directive_output = 0; \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
+ } \
+ ASM_OUTPUT_LABEL(FILE, NAME); \
+ } else \
+ SCO_DEFAULT_ASM_COFF(FILE, NAME); \
+ } while (0)
+
+#undef ASM_FILE_START_1
+#define ASM_FILE_START_1(FILE)
+
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+do { \
+ output_file_directive((FILE),main_input_filename); \
+ fprintf ((FILE), "\t.version\t\"01.01\"\n"); \
+} while (0)
+
+#undef ASM_FILE_END
+#define ASM_FILE_END(FILE) \
+do { \
+ fprintf ((FILE), "%s\t\"GCC: (GNU) %s\"\n", \
+ IDENT_ASM_OP, version_string); \
+} while (0)
+
+#undef ASM_FINISH_DECLARE_OBJECT
+#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
+do { \
+ if (TARGET_ELF) { \
+ char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
+ && ! AT_END && TOP_LEVEL \
+ && DECL_INITIAL (DECL) == error_mark_node \
+ && !size_directive_output) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, name); \
+ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
+ } \
+ } \
+} while (0)
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \
+do { \
+ if (TARGET_ELF) \
+ sprintf (LABEL, "*.%s%d", (PREFIX), (NUM)); \
+ else \
+ sprintf (LABEL, ".%s%d", (PREFIX), (NUM)); \
+} while (0)
+
+#undef ASM_OUTPUT_ADDR_DIFF_ELT
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+do { \
+ if (TARGET_ELF) \
+ fprintf (FILE, "%s _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", ASM_LONG, LPREFIX, VALUE); \
+ else \
+ fprintf (FILE, "\t.word %s%d-%s%d\n", LPREFIX,VALUE,LPREFIX,REL); \
+} while (0)
+
+#undef ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
+do { \
+ fprintf ((FILE), "%s\t", COMMON_ASM_OP); \
+ assemble_name ((FILE), (NAME)); \
+ if (TARGET_ELF) \
+ fprintf ((FILE), ",%u,%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \
+ else \
+ fprintf ((FILE), ",%u\n", (SIZE)); \
+} while (0)
+
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+do { \
+ if (TARGET_ELF) { \
+ fprintf ((FILE), "%s\t", LOCAL_ASM_OP); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), "\n"); \
+ ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN); \
+ } else { \
+ int align = exact_log2 (ALIGN); \
+ if (align > 2) align = 2; \
+ if (TARGET_SVR3_SHLIB) \
+ data_section (); \
+ else \
+ bss_section (); \
+ ASM_OUTPUT_ALIGN ((FILE), align == -1 ? 2 : align); \
+ fprintf ((FILE), "%s\t", "\t.lcomm"); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), ",%u\n", (SIZE)); \
+ } \
+} while (0)
+
+/* A C statement (sans semicolon) to output to the stdio stream
+ FILE the assembler definition of uninitialized global DECL named
+ NAME whose size is SIZE bytes and alignment is ALIGN bytes.
+ Try to use asm_output_aligned_bss to implement this macro. */
+
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN)
+
+#undef ESCAPES
+#define ESCAPES \
+"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
+
+#undef STRING_LIMIT
+#define STRING_LIMIT ((unsigned) 256)
+
+#undef ASM_OUTPUT_LIMITED_STRING
+#define ASM_OUTPUT_LIMITED_STRING(FILE, STR) \
+ do \
+ { \
+ register unsigned char *_limited_str = (unsigned char *) (STR); \
+ register unsigned ch; \
+ fprintf ((FILE), "%s\t\"", STRING_ASM_OP); \
+ for (; (ch = *_limited_str); _limited_str++) \
+ { \
+ register int escape; \
+ switch (escape = ESCAPES[ch]) \
+ { \
+ case 0: \
+ putc (ch, (FILE)); \
+ break; \
+ case 1: \
+ fprintf ((FILE), "\\%03o", ch); \
+ break; \
+ default: \
+ putc ('\\', (FILE)); \
+ putc (escape, (FILE)); \
+ break; \
+ } \
+ } \
+ fprintf ((FILE), "\"\n"); \
+ } \
+ while (0)
+
+
+#undef ASM_OUTPUT_ASCII
+#define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \
+do { \
+ register unsigned char *_ascii_bytes = (unsigned char *) (STR); \
+ register unsigned char *limit = _ascii_bytes + (LENGTH); \
+ register unsigned bytes_in_chunk = 0; \
+ for (; _ascii_bytes < limit; _ascii_bytes++) \
+ { \
+ register unsigned char *p; \
+ if (bytes_in_chunk >= 64) \
+ { \
+ fputc ('\n', (FILE)); \
+ bytes_in_chunk = 0; \
+ } \
+ for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \
+ continue; \
+ if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \
+ { \
+ if (bytes_in_chunk > 0) \
+ { \
+ fputc ('\n', (FILE)); \
+ bytes_in_chunk = 0; \
+ } \
+ ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes); \
+ _ascii_bytes = p; \
+ } \
+ else \
+ { \
+ if (bytes_in_chunk == 0) \
+ fprintf ((FILE), "%s\t", ASM_BYTE_OP); \
+ else \
+ fputc (',', (FILE)); \
+ fprintf ((FILE), "0x%02x", *_ascii_bytes); \
+ bytes_in_chunk += 5; \
+ } \
+ } \
+ if (bytes_in_chunk > 0) \
+ fprintf ((FILE), "\n"); \
+} while (0)
+
+/* Must use data section for relocatable constants when pic. */
+#undef SELECT_RTX_SECTION
+#define SELECT_RTX_SECTION(MODE,RTX) \
+{ \
+ if (TARGET_ELF) { \
+ if (flag_pic && symbolic_operand (RTX)) \
+ data_section (); \
+ else \
+ const_section (); \
+ } else \
+ readonly_data_section(); \
+}
+
+#undef ASM_OUTPUT_CASE_LABEL
+#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \
+do { \
+ if (TARGET_ELF) \
+ ASM_OUTPUT_ALIGN ((FILE), 2); \
+ ASM_OUTPUT_INTERNAL_LABEL((FILE),(PREFIX),(NUM)); \
+} while (0)
+
+
+#undef ASM_OUTPUT_CONSTRUCTOR
+#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
+do { \
+ if (TARGET_ELF) { \
+ ctors_section (); \
+ fprintf (FILE, "%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } else { \
+ init_section (); \
+ fprintf (FILE, "\tpushl $"); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); } \
+ } while (0)
+
+#undef ASM_OUTPUT_DESTRUCTOR
+#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
+do { \
+ if (TARGET_ELF) { \
+ dtors_section (); \
+ fprintf (FILE, "%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } else { \
+ fini_section (); \
+ fprintf (FILE, "%s\t ", ASM_LONG); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); } \
+ } while (0)
+
+
+#undef ASM_OUTPUT_IDENT
+#define ASM_OUTPUT_IDENT(FILE, NAME) \
+ fprintf (FILE, "%s\t\"%s\"\n", IDENT_ASM_OP, NAME);
+
+#undef ASM_GLOBALIZE_LABEL
+#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
+ (fprintf ((FILE), "%s ", GLOBAL_ASM_OP), assemble_name (FILE, NAME), fputs ("\n", FILE))
+
+#undef ASM_OUTPUT_EXTERNAL_LIBCALL
+#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \
+ if (TARGET_ELF) ASM_GLOBALIZE_LABEL (FILE, XSTR (FUN, 0))
+
+#undef ASM_OUTPUT_INTERNAL_LABEL
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
+ fprintf (FILE, ".%s%d:\n", PREFIX, NUM)
+
+/* The prefix to add to user-visible assembler symbols. */
+
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
+
+/*
+ * Compensate for the difference between ELF and COFF assembler syntax.
+ * Otherwise, this is cribbed from ../svr4.h.
+ * We rename 'gcc_except_table' to the shorter name in preparation
+ * for the day when we're ready to do DWARF2 eh unwinding under COFF
+ */
+#undef ASM_OUTPUT_SECTION_NAME
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
+do { \
+ static struct section_info \
+ { \
+ struct section_info *next; \
+ char *name; \
+ enum sect_enum {SECT_RW, SECT_RO, SECT_EXEC} type; \
+ } *sections; \
+ struct section_info *s; \
+ char *mode; \
+ enum sect_enum type; \
+ char *sname = NAME ; \
+ if (strcmp(NAME, ".gcc_except_table") == 0) sname = ".gccexc" ; \
+ \
+ for (s = sections; s; s = s->next) \
+ if (!strcmp (NAME, s->name)) \
+ break; \
+ \
+ if (DECL && TREE_CODE (DECL) == FUNCTION_DECL) \
+ type = SECT_EXEC, mode = (TARGET_ELF) ? "ax" : "x" ; \
+ else if (DECL && DECL_READONLY_SECTION (DECL, RELOC)) \
+ type = SECT_RO, mode = "a"; \
+ else \
+ type = SECT_RW, mode = (TARGET_ELF) ? "aw" : "w" ; \
+ \
+ if (s == 0) \
+ { \
+ s = (struct section_info *) xmalloc (sizeof (struct section_info)); \
+ s->name = xmalloc ((strlen (NAME) + 1) * sizeof (*NAME)); \
+ strcpy (s->name, NAME); \
+ s->type = type; \
+ s->next = sections; \
+ sections = s; \
+ fprintf (FILE, ".section\t%s,\"%s\"%s\n", sname, mode, \
+ (TARGET_ELF) ? ",@progbits" : "" ); \
+ } \
+ else \
+ { \
+ if (DECL && s->type != type) \
+ error_with_decl (DECL, "%s causes a section type conflict"); \
+ \
+ fprintf (FILE, ".section\t%s\n", sname); \
+ } \
+} while (0)
+
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(FILE,SIZE) \
+do { \
+ if (TARGET_ELF) \
+ fprintf (FILE, "%s\t%u\n", SKIP_ASM_OP, (SIZE)); \
+ else \
+ fprintf ((FILE), "%s\t.,.+%u\n", SET_ASM_OP, (SIZE)); \
+} while (0)
+
+
+#undef CTOR_LIST_BEGIN
+#define CTOR_LIST_BEGIN \
+do { \
+ asm (CTORS_SECTION_ASM_OP); \
+ if (TARGET_ELF) \
+ STATIC func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) }; \
+ else \
+ asm ("pushl $0"); \
+} while (0)
+
+#undef CTOR_LIST_END
+#define CTOR_LIST_END \
+do { \
+ if (TARGET_ELF) { \
+ asm (CTORS_SECTION_ASM_OP); \
+ STATIC func_ptr __CTOR_LIST__[1] = { (func_ptr) (0) }; \
+ } else { \
+ CTOR_LIST_BEGIN; \
+ } \
+} while (0)
+
+#undef DBX_BLOCKS_FUNCTION_RELATIVE
+#define DBX_BLOCKS_FUNCTION_RELATIVE 1
+
+#undef DBX_FUNCTION_FIRST
+#define DBX_FUNCTION_FIRST 1
+
+#undef DBX_REGISTER_NUMBER
+#define DBX_REGISTER_NUMBER(n) \
+((TARGET_ELF) ? \
+ ((n) == 0 ? 0 \
+ : (n) == 1 ? 2 \
+ : (n) == 2 ? 1 \
+ : (n) == 3 ? 3 \
+ : (n) == 4 ? 6 \
+ : (n) == 5 ? 7 \
+ : (n) == 6 ? 5 \
+ : (n) == 7 ? 4 \
+ : ((n) >= FIRST_STACK_REG && (n) <= LAST_STACK_REG) ? (n)+3 \
+ : (-1)) \
+ : \
+ ((n) == 0 ? 0 : \
+ (n) == 1 ? 2 : \
+ (n) == 2 ? 1 : \
+ (n) == 3 ? 3 : \
+ (n) == 4 ? 6 : \
+ (n) == 5 ? 7 : \
+ (n) == 6 ? 4 : \
+ (n) == 7 ? 5 : \
+ (n) + 4))
+
+#undef DWARF_DEBUGGING_INFO
+#undef SDB_DEBUGGING_INFO
+#undef DBX_DEBUGGING_INFO
+#undef PREFERRED_DEBUGGING_TYPE
+
+#define DWARF_DEBUGGING_INFO 1
+#define SDB_DEBUGGING_INFO 1
+#define DBX_DEBUGGING_INFO 1
+#define PREFERRED_DEBUGGING_TYPE \
+ ((TARGET_ELF) ? DWARF_DEBUG: SDB_DEBUG)
+
+#undef EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_const, in_init, in_fini, in_ctors, in_dtors
+
+#undef EXTRA_SECTION_FUNCTIONS
+#define EXTRA_SECTION_FUNCTIONS \
+ CONST_SECTION_FUNCTION \
+ INIT_SECTION_FUNCTION \
+ FINI_SECTION_FUNCTION \
+ CTORS_SECTION_FUNCTION \
+ DTORS_SECTION_FUNCTION
+
+#undef CONST_SECTION_FUNCTION
+#define CONST_SECTION_FUNCTION \
+void \
+const_section () \
+{ \
+ extern void text_section(); \
+ if (!USE_CONST_SECTION) \
+ text_section(); \
+ else if (in_section != in_const) \
+ { \
+ fprintf (asm_out_file, "%s\n", CONST_SECTION_ASM_OP); \
+ in_section = in_const; \
+ } \
+}
+
+#undef FINI_SECTION_FUNCTION
+#define FINI_SECTION_FUNCTION \
+void \
+fini_section () \
+{ \
+ if ((!TARGET_ELF) && in_section != in_fini) \
+ { \
+ fprintf (asm_out_file, "%s\n", FINI_SECTION_ASM_OP); \
+ in_section = in_fini; \
+ } \
+}
+
+#undef INIT_SECTION_FUNCTION
+#define INIT_SECTION_FUNCTION \
+void \
+init_section () \
+{ \
+ if ((!TARGET_ELF) && in_section != in_init) \
+ { \
+ fprintf (asm_out_file, "%s\n", INIT_SECTION_ASM_OP); \
+ in_section = in_init; \
+ } \
+}
+
+#undef CTORS_SECTION_FUNCTION
+#define CTORS_SECTION_FUNCTION \
+void \
+ctors_section () \
+{ \
+ if (in_section != in_ctors) \
+ { \
+ fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \
+ in_section = in_ctors; \
+ } \
+}
+
+#undef DTORS_SECTION_FUNCTION
+#define DTORS_SECTION_FUNCTION \
+void \
+dtors_section () \
+{ \
+ if (in_section != in_dtors) \
+ { \
+ fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \
+ in_section = in_dtors; \
+ } \
+}
+
+#undef FRAME_POINTER_REQUIRED
+#define FRAME_POINTER_REQUIRED \
+ ((TARGET_ELF) ? 0 : \
+ (current_function_calls_setjmp || current_function_calls_longjmp))
+
+#undef JUMP_TABLES_IN_TEXT_SECTION
+#define JUMP_TABLES_IN_TEXT_SECTION (TARGET_ELF && flag_pic)
+
+#undef LOCAL_LABEL_PREFIX
+#define LOCAL_LABEL_PREFIX \
+ ((TARGET_ELF) ? "" : ".")
+
+#undef MD_EXEC_PREFIX
+#undef MD_STARTFILE_PREFIX
+#define MD_EXEC_PREFIX "/usr/ccs/bin/"
+#define MD_STARTFILE_PREFIX "/usr/ccs/lib/"
+
+#undef NON_SAVING_SETJMP
+#define NON_SAVING_SETJMP \
+ ((TARGET_ELF) ? 0 : \
+ (current_function_calls_setjmp && current_function_calls_longjmp))
+
+#undef NO_IMPLICIT_EXTERN_C
+#define NO_IMPLICIT_EXTERN_C 1
+
+/* JKJ FIXME - examine the ramifications of RETURN_IN_MEMORY and
+ RETURN_POPS_ARGS */
+
+#undef RETURN_POPS_ARGS
+#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
+ ((TARGET_ELF) ? \
+ (i386_return_pops_args (FUNDECL, FUNTYPE, SIZE)) : \
+ (((FUNDECL) && (TREE_CODE (FUNDECL) == IDENTIFIER_NODE)) ? 0 \
+ : (TARGET_RTD \
+ && (TYPE_ARG_TYPES (FUNTYPE) == 0 \
+ || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \
+ == void_type_node))) ? (SIZE) \
+ : 0))
+
+#undef SELECT_SECTION
+#define SELECT_SECTION(DECL,RELOC) \
+{ \
+ if (TREE_CODE (DECL) == STRING_CST) \
+ { \
+ if (! flag_writable_strings) \
+ const_section (); \
+ else \
+ data_section (); \
+ } \
+ else if (TREE_CODE (DECL) == VAR_DECL) \
+ { \
+ if ((TARGET_ELF && flag_pic && RELOC) \
+ || !TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \
+ || !DECL_INITIAL (DECL) \
+ || (DECL_INITIAL (DECL) != error_mark_node \
+ && !TREE_CONSTANT (DECL_INITIAL (DECL)))) \
+ data_section (); \
+ else \
+ const_section (); \
+ } \
+ else \
+ const_section (); \
+}
+
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ (DEFAULT_SWITCH_TAKES_ARG(CHAR) \
+ || (CHAR) == 'h' \
+ || (CHAR) == 'R' \
+ || (CHAR) == 'Y' \
+ || (CHAR) == 'z')
+
+#undef WORD_SWITCH_TAKES_ARG
+#define WORD_SWITCH_TAKES_ARG(STR) \
+ (DEFAULT_WORD_SWITCH_TAKES_ARG (STR) \
+ && strcmp (STR, "Tdata") && strcmp (STR, "Ttext") \
+ && strcmp (STR, "Tbss"))
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT 0301
+
+#undef HANDLE_SYSV_PRAGMA
+#define HANDLE_SYSV_PRAGMA 1
+
+#undef SCCS_DIRECTIVE
+#define SCCS_DIRECTIVE 1
+
+/*
+ * Define sizes and types
+ */
+#undef SIZE_TYPE
+#undef PTRDIFF_TYPE
+#undef WCHAR_TYPE
+#undef WCHAR_TYPE_SIZE
+#undef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE 96
+#define SIZE_TYPE "unsigned int"
+#define PTRDIFF_TYPE "int"
+#define WCHAR_TYPE "long int"
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+/*
+ * New for multilib support. Set the default switches for multilib,
+ * which is -melf.
+ */
+#define MULTILIB_DEFAULTS { "melf" }
+
+
+/* Please note that these specs may look messy but they are required in
+ order to emulate the SCO Development system as closely as possible.
+ With SCO Open Server 5.0, you now get the linker and assembler free,
+ so that is what these specs are targeted for. These utilities are
+ very argument sensitive: a space in the wrong place breaks everything.
+ So RMS, please forgive this mess. It works.
+
+ Parameters which can be passed to gcc, and their SCO equivalents:
+ GCC Parameter SCO Equivalent
+ -ansi -a ansi
+ -posix -a posix
+ -Xpg4 -a xpg4
+ -Xpg4plus -a xpg4plus
+ -Xods30 -a ods30
+
+ As with SCO, the default is XPG4 plus mode. SCO also allows you to
+ specify a C dialect with -Xt, -Xa, -Xc, -Xk and -Xm. These are passed
+ on to the assembler and linker in the same way that the SCO compiler
+ does.
+
+ SCO also allows you to compile, link and generate either ELF or COFF
+ binaries. With gcc, unlike the SCO compiler, the default is ELF.
+ Specify -mcoff to gcc to produce COFF binaries. -fpic will get the
+ assembler and linker to produce PIC code.
+*/
+
+/* Set up assembler flags for PIC and ELF compilations */
+#undef ASM_SPEC
+
+#if USE_GAS
+ /* Leave ASM_SPEC undefined so we pick up the master copy from gcc.c
+ * Undef MD_EXEC_PREFIX becuase we don't know where GAS is, but it's not
+ * likely in /usr/ccs/bin/
+ */
+#undef MD_EXEC_PREFIX
+#else
+
+#define ASM_SPEC \
+ "-b %{!mcoff:elf}%{mcoff:coff \
+ %{static:%e-static not valid with -mcoff} \
+ %{shared:%e-shared not valid with -mcoff} \
+ %{symbolic:%e-symbolic not valid with -mcoff}} \
+ %{Ym,*} %{Yd,*} %{Wa,*:%*} \
+ %{!mcoff:-E%{Xa:a}%{!Xa:%{Xc:c}%{!Xc:%{Xk:k}%{!Xk:%{Xt:t}%{!Xt:a}}}},%{ansi:ansi}%{!ansi:%{posix:posix}%{!posix:%{Xpg4:xpg4}%{!Xpg4:%{Xpg4plus:XPG4PLUS}%{!Xpg4plus:%{Xods30:ods30}%{!Xods30:XPG4PLUS}}}}},ELF %{Qn:} %{!Qy:-Qn}}"
+#endif
+
+/* Use crt1.o as a startup file and crtn.o as a closing file. */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "%{shared: %{!mcoff: crti.o%s}} \
+ %{!shared:\
+ %{!symbolic: \
+ %{pg:gcrt.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}}} \
+ %{ansi:values-Xc.o%s} \
+ %{!ansi: \
+ %{traditional:values-Xt.o%s} \
+ %{!traditional: \
+ %{Xa:values-Xa.o%s} \
+ %{!Xa:%{Xc:values-Xc.o%s} \
+ %{!Xc:%{Xk:values-Xk.o%s} \
+ %{!Xk:%{Xt:values-Xt.o%s} \
+ %{!Xt:values-Xa.o%s}}}}}} \
+ %{mcoff:crtbeginS.o%s} %{!mcoff:crtbegin.o%s}"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ "%{!mcoff:crtend.o%s} \
+ %{mcoff:crtendS.o%s} \
+ %{pg:gcrtn.o%s}%{!pg:crtn.o%s}"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+ "-Asystem(svr3)"
+
+/* You are in a maze of GCC specs ... all alike */
+
+#undef CPP_SPEC
+#define CPP_SPEC "%(cpp_cpu) \
+ %{fpic:%{mcoff:%e-fpic is not valid with -mcoff}} \
+ %{fPIC:%{mcoff:%e-fPIC is not valid with -mcoff}} \
+ -D__i386 -D__unix -D_SCO_DS=1 -D_M_I386 -D_M_XENIX -D_M_UNIX \
+ %{!Xods30:-D_STRICT_NAMES} \
+ %{!ansi:%{!posix:%{!Xods30:-D_SCO_XPG_VERS=4}}} \
+ %{ansi:-isystem include/ansi%s -isystem /usr/include/ansi -D_STRICT_ANSI} \
+ %{!ansi: \
+ %{posix:-isystem include/posix%s -isystem /usr/include/posix \
+ -D_POSIX_C_SOURCE=2 -D_POSIX_SOURCE=1} \
+ %{!posix:%{Xpg4:-isystem include/xpg4%s -isystem /usr/include/xpg4 \
+ -D_XOPEN_SOURCE=1} \
+ %{!Xpg4:-D_M_I86 -D_M_I86SM -D_M_INTERNAT -D_M_SDATA -D_M_STEXT \
+ -D_M_BITFIELDS -D_M_SYS5 -D_M_SYSV -D_M_SYSIII \
+ -D_M_WORDSWAP -Dunix -DM_I386 -DM_UNIX -DM_XENIX \
+ %{Xods30:-isystem include/ods_30_compat%s \
+ -isystem /usr/include/ods_30_compat \
+ -D_SCO_ODS_30 -DM_I86 -DM_I86SM -DM_SDATA -DM_STEXT \
+ -DM_BITFIELDS -DM_SYS5 -DM_SYSV -DM_INTERNAT -DM_SYSIII \
+ -DM_WORDSWAP}}}} \
+ %{scointl:-DM_INTERNAT -D_M_INTERNAT} \
+ %{traditional:-D_KR -D_SVID -D_NO_PROTOTYPE} \
+ %{!mcoff:-D_SCO_ELF} \
+ %{mcoff:-D_M_COFF -D_SCO_COFF} \
+ %{!mcoff:%{fpic:-D__PIC__ -D__pic__} \
+ %{fPIC:%{!fpic:-D__PIC__ -D__pic__}}} \
+ %{Xa:-D_SCO_C_DIALECT=1} \
+ %{!Xa:%{Xc:-D_SCO_C_DIALECT=3} \
+ %{!Xc:%{Xk:-D_SCO_C_DIALECT=4} \
+ %{!Xk:%{Xt:-D_SCO_C_DIALECT=2} \
+ %{!Xt:-D_SCO_C_DIALECT=1}}}} \
+ %{traditional:-traditional -D_KR -D_NO_PROTOTYPE}"
+
+#undef LINK_SPEC
+#define LINK_SPEC \
+ "-b %{!mcoff:elf}%{mcoff:coff \
+ %{static:%e-static not valid with -mcoff} \
+ %{shared:%e-shared not valid with -mcoff} \
+ %{symbolic:%e-symbolic not valid with -mcoff} \
+ %{fpic:%e-fpic not valid with -mcoff} \
+ %{fPIC:%e-fPIC not valid with -mcoff}} \
+ -R%{Xa:a}%{!Xa:%{Xc:c}%{!Xc:%{Xk:k}%{!Xk:%{Xt:t}%{!Xt:a}}}},%{ansi:ansi}%{!ansi:%{posix:posix}%{!posix:%{Xpg4:xpg4}%{!Xpg4:%{Xpg4plus:XPG4PLUS}%{!Xpg4plus:%{Xods30:ods30}%{!Xods30:XPG4PLUS}}}}},%{mcoff:COFF}%{!mcoff:ELF} \
+ %{Wl,*%*} %{YP,*} %{YL,*} %{YU,*} \
+ %{!YP,*:%{p:-YP,/usr/ccs/libp:/lib/libp:/usr/lib/libp:/usr/ccs/lib:/lib:/usr/lib} \
+ %{!p:-YP,/usr/ccs/lib:/lib:/usr/lib}} \
+ %{h*} %{static:-dn -Bstatic} %{shared:-G -dy %{!z*:-z text}} \
+ %{symbolic:-Bsymbolic -G -dy %{!z*:-z text}} %{z*} %{R*} %{Y*} \
+ %{G:-G} %{!mcoff:%{Qn:} %{!Qy:-Qn}}"
+
+/* The SCO COFF linker gets confused on the difference between "-ofoo"
+ and "-o foo". So we just always force a single space. */
+
+#define SWITCHES_NEED_SPACES "o"
+
+/* Library spec. If we are not building a shared library, provide the
+ standard libraries, as per the SCO compiler. */
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+ "%{shared:pic/libgcc.a%s}%{!shared:%{!symbolic:-lcrypt -lgen -lc}}"
+
+#undef LIBGCC_SPEC
+#define LIBGCC_SPEC \
+ "%{!shared:-lgcc}"
+
+#define MASK_COFF 010000000000 /* Mask for elf generation */
+#define TARGET_COFF (target_flags & MASK_COFF)
+#define TARGET_ELF (!(target_flags & MASK_COFF))
+
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+ { "coff", MASK_COFF }, \
+ { "elf", -MASK_COFF },
+
+#define NO_DOLLAR_IN_LABEL
+
+/*
+Here comes some major hackery to get the crt stuff to compile properly.
+Since we can (and do) compile for both COFF and ELF environments, we
+set things up accordingly, based on the pre-processor defines for ELF
+and COFF. This is insane, but then I guess having one compiler with a
+single back-end supporting two vastly different file format types is
+a little insane too. But it is not impossible and we get a useful
+compiler at the end of the day. Onward we go ...
+*/
+
+#if defined(CRT_BEGIN) || defined(CRT_END) || defined(IN_LIBGCC2)
+# undef OBJECT_FORMAT_ELF
+# undef HAVE_ATEXIT
+# undef INIT_SECTION_ASM_OP
+# undef FINI_SECTION_ASM_OP
+# undef CTORS_SECTION_ASM_OP
+# undef DTORS_SECTION_ASM_OP
+# undef EH_FRAME_SECTION_ASM_OP
+# undef CTOR_LIST_BEGIN
+# undef CTOR_LIST_END
+# undef DO_GLOBAL_CTORS_BODY
+
+# if defined (_SCO_ELF)
+# define OBJECT_FORMAT_ELF
+# define HAVE_ATEXIT 1
+# define INIT_SECTION_ASM_OP INIT_SECTION_ASM_OP_ELF
+# define FINI_SECTION_ASM_OP FINI_SECTION_ASM_OP_ELF
+# define DTORS_SECTION_ASM_OP DTORS_SECTION_ASM_OP_ELF
+# define CTORS_SECTION_ASM_OP CTORS_SECTION_ASM_OP_ELF
+# define EH_FRAME_SECTION_ASM_OP EH_FRAME_SECTION_ASM_OP_ELF
+# else /* ! _SCO_ELF */
+# define INIT_SECTION_ASM_OP INIT_SECTION_ASM_OP_COFF
+# define FINI_SECTION_ASM_OP FINI_SECTION_ASM_OP_COFF
+# define DTORS_SECTION_ASM_OP DTORS_SECTION_ASM_OP_COFF
+# define CTORS_SECTION_ASM_OP CTORS_SECTION_ASM_OP_COFF
+# define EH_FRAME_SECTION_ASM_OP ""
+# define CTOR_LIST_BEGIN asm (INIT_SECTION_ASM_OP); asm ("pushl $0")
+# define CTOR_LIST_END CTOR_LIST_BEGIN
+# define DO_GLOBAL_CTORS_BODY \
+do { \
+ func_ptr *p, *beg = alloca(0); \
+ for (p = beg; *p;) \
+ (*p++) (); \
+} while (0)
+# endif /* ! _SCO_ELF */
+#endif /* CRT_BEGIN !! CRT_END */
diff --git a/contrib/gcc/config/i386/sco5gas.h b/contrib/gcc/config/i386/sco5gas.h
new file mode 100644
index 0000000..de3e5d5
--- /dev/null
+++ b/contrib/gcc/config/i386/sco5gas.h
@@ -0,0 +1,24 @@
+/* Definitions for Intel x86 running SCO OpenServer, running GNU assembler
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Just set a single flag we can test for inside of sco5.h and include it. */
+
+#define USE_GAS 1
diff --git a/contrib/gcc/config/i386/scodbx.h b/contrib/gcc/config/i386/scodbx.h
index 1309735..a2581d4 100644
--- a/contrib/gcc/config/i386/scodbx.h
+++ b/contrib/gcc/config/i386/scodbx.h
@@ -1,6 +1,6 @@
/* Definitions for Intel 386 running SCO Unix System V,
using dbx-in-coff encapsulation.
- Copyright (C) 1992, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -50,10 +50,10 @@ Boston, MA 02111-1307, USA. */
/* Specify predefined symbols in preprocessor. */
#undef CPP_PREDEFINES
-#define CPP_PREDEFINES "-Dunix -Di386 -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP -Asystem(unix) -Asystem(svr3) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-Dunix -DM_UNIX -DM_I386 -DM_COFF -DM_WORDSWAP -Asystem(svr3)"
#undef CPP_SPEC
-#define CPP_SPEC "%{scointl:-DM_INTERNAT}"
+#define CPP_SPEC " -Acpu(i386) -Amachine(i386) %{scointl:-DM_INTERNAT}"
/* This spec is used for telling cpp whether char is signed or not. */
@@ -75,7 +75,7 @@ Boston, MA 02111-1307, USA. */
#undef RETURN_POPS_ARGS
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
- (TREE_CODE (FUNTYPE) == IDENTIFIER_NODE ? 0 \
+ ((FUNDECL) && TREE_CODE (FUNDECL) == IDENTIFIER_NODE ? 0 \
: (TARGET_RTD \
&& (TYPE_ARG_TYPES (FUNTYPE) == 0 \
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (FUNTYPE))) \
diff --git a/contrib/gcc/config/i386/seq-gas.h b/contrib/gcc/config/i386/seq-gas.h
index 2ee0719..796eaa2 100644
--- a/contrib/gcc/config/i386/seq-gas.h
+++ b/contrib/gcc/config/i386/seq-gas.h
@@ -39,8 +39,8 @@
GAS requires the %cl argument, so override i386/unix.h. */
-#undef AS3_SHIFT_DOUBLE
-#define AS3_SHIFT_DOUBLE(a,b,c,d) AS3 (a,b,c,d)
+#undef SHIFT_DOUBLE_OMITS_COUNT
+#define SHIFT_DOUBLE_OMITS_COUNT 0
/* Print opcodes the way that GAS expects them. */
#define GAS_MNEMONICS 1
diff --git a/contrib/gcc/config/i386/seq-sysv3.h b/contrib/gcc/config/i386/seq-sysv3.h
index e3182ee..9e8388d 100644
--- a/contrib/gcc/config/i386/seq-sysv3.h
+++ b/contrib/gcc/config/i386/seq-sysv3.h
@@ -40,17 +40,3 @@
/* Assembler pseudo-op for uninitialized shared local variables (.shbss). */
#undef SHARED_BSS_SECTION_ASM_OP
#define SHARED_BSS_SECTION_ASM_OP ".section .shbss, \"bs\""
-#undef BSS_SECTION_FUNCTION
-#define BSS_SECTION_FUNCTION \
-void \
-bss_section () \
-{ \
- if (in_section != in_bss) \
- { \
- if (flag_shared_data) \
- fprintf (asm_out_file, "%s\n", SHARED_BSS_SECTION_ASM_OP); \
- else \
- fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP); \
- in_section = in_bss; \
- } \
-}
diff --git a/contrib/gcc/config/i386/sol2-c1.asm b/contrib/gcc/config/i386/sol2-c1.asm
index 72fdfb8..d08bcbd 100644
--- a/contrib/gcc/config/i386/sol2-c1.asm
+++ b/contrib/gcc/config/i386/sol2-c1.asm
@@ -1,6 +1,6 @@
! crt1.s for Solaris 2, x86
-! Copyright (C) 1993 Free Software Foundation, Inc.
+! Copyright (C) 1993, 1998 Free Software Foundation, Inc.
! Written By Fred Fish, Nov 1992
!
! This file is free software; you can redistribute it and/or modify it
@@ -149,7 +149,7 @@ _start:
! A dummy profiling support routine for non-profiling executables,
! in case we link in some objects that have been compiled for profiling.
- .globl _mcount
+ .weak _mcount
_mcount:
ret
.type _mcount,@function
diff --git a/contrib/gcc/config/i386/sol2-gc1.asm b/contrib/gcc/config/i386/sol2-gc1.asm
new file mode 100644
index 0000000..24a1965
--- /dev/null
+++ b/contrib/gcc/config/i386/sol2-gc1.asm
@@ -0,0 +1,160 @@
+! gcrt1.s for Solaris 2, x86
+
+! Copyright (C) 1993 Free Software Foundation, Inc.
+! Written By Fred Fish, Nov 1992
+!
+! This file 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, or (at your option) any
+! later version.
+!
+! In addition to the permissions in the GNU General Public License, the
+! Free Software Foundation gives you unlimited permission to link the
+! compiled version of this file with other programs, and to distribute
+! those programs without any restriction coming from the use of this
+! file. (The General Public License restrictions do apply in other
+! respects; for example, they cover modification of the file, and
+! distribution when not linked into another program.)
+!
+! This file 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; see the file COPYING. If not, write to
+! the Free Software Foundation, 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+!
+! As a special exception, if you link this library with files
+! compiled with GCC to produce an executable, this does not cause
+! the resulting executable to be covered by the GNU General Public License.
+! This exception does not however invalidate any other reasons why
+! the executable file might be covered by the GNU General Public License.
+!
+
+! This file takes control of the process from the kernel, as specified
+! in section 3 of the System V Application Binary Interface, Intel386
+! Processor Supplement. It has been constructed from information obtained
+! from the ABI, information obtained from single stepping existing
+! Solaris executables through their startup code with gdb, and from
+! information obtained by single stepping executables on other i386 SVR4
+! implementations. This file is the first thing linked into any executable.
+
+! This is a modified crt1.s by J.W.Hawtin <oolon@ankh.org> 15/8/96,
+! to allow program profiling, by calling monstartup on entry and _mcleanup
+! on exit
+
+ .file "gcrt1.s"
+ .ident "GNU C gcrt1.s"
+ .weak _DYNAMIC
+ .text
+
+! Start creating the initial frame by pushing a NULL value for the return
+! address of the initial frame, and mark the end of the stack frame chain
+! (the innermost stack frame) with a NULL value, per page 3-32 of the ABI.
+! Initialize the first stack frame pointer in %ebp (the contents of which
+! are unspecified at process initialization).
+
+ .globl _start
+_start:
+ pushl $0x0
+ pushl $0x0
+ movl %esp,%ebp
+
+! As specified per page 3-32 of the ABI, %edx contains a function
+! pointer that should be registered with atexit(), for proper
+! shared object termination. Just push it onto the stack for now
+! to preserve it. We want to register _cleanup() first.
+
+ pushl %edx
+
+! Check to see if there is an _cleanup() function linked in, and if
+! so, register it with atexit() as the last thing to be run by
+! atexit().
+
+ movl $_mcleanup,%eax
+ testl %eax,%eax
+ je .L1
+ pushl $_mcleanup
+ call atexit
+ addl $0x4,%esp
+.L1:
+
+! Now check to see if we have an _DYNAMIC table, and if so then
+! we need to register the function pointer previously in %edx, but
+! now conveniently saved on the stack as the argument to pass to
+! atexit().
+
+ movl $_DYNAMIC,%eax
+ testl %eax,%eax
+ je .L2
+ call atexit
+.L2:
+
+! Register _fini() with atexit(). We will take care of calling _init()
+! directly.
+
+ pushl $_fini
+ call atexit
+
+! Start profiling
+
+ pushl %ebp
+ movl %esp,%ebp
+ pushl $_etext
+ pushl $_start
+ call monstartup
+ addl $8,%esp
+ popl %ebp
+
+! Compute the address of the environment vector on the stack and load
+! it into the global variable _environ. Currently argc is at 8 off
+! the frame pointer. Fetch the argument count into %eax, scale by the
+! size of each arg (4 bytes) and compute the address of the environment
+! vector which is 16 bytes (the two zero words we pushed, plus argc,
+! plus the null word terminating the arg vector) further up the stack,
+! off the frame pointer (whew!).
+
+ movl 8(%ebp),%eax
+ leal 16(%ebp,%eax,4),%edx
+ movl %edx,_environ
+
+! Push the environment vector pointer, the argument vector pointer,
+! and the argument count on to the stack to set up the arguments
+! for _init(), _fpstart(), and main(). Note that the environment
+! vector pointer and the arg count were previously loaded into
+! %edx and %eax respectively. The only new value we need to compute
+! is the argument vector pointer, which is at a fixed address off
+! the initial frame pointer.
+
+ pushl %edx
+ leal 12(%ebp),%edx
+ pushl %edx
+ pushl %eax
+
+! Call _init(argc, argv, environ), _fpstart(argc, argv, environ), and
+! main(argc, argv, environ).
+
+ call _init
+ call __fpstart
+ call main
+
+! Pop the argc, argv, and environ arguments off the stack, push the
+! value returned from main(), and call exit().
+
+ addl $12,%esp
+ pushl %eax
+ call exit
+
+! An inline equivalent of _exit, as specified in Figure 3-26 of the ABI.
+
+ pushl $0x0
+ movl $0x1,%eax
+ lcall $7,$0
+
+! If all else fails, just try a halt!
+
+ hlt
+ .type _start,@function
+ .size _start,.-_start
diff --git a/contrib/gcc/config/i386/sol2.h b/contrib/gcc/config/i386/sol2.h
index cc5ebca..8fc3e61 100644
--- a/contrib/gcc/config/i386/sol2.h
+++ b/contrib/gcc/config/i386/sol2.h
@@ -1,7 +1,6 @@
/* Target definitions for GNU compiler for Intel 80386 running Solaris 2
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
-
- Written by Fred Fish (fnf@cygnus.com).
+ Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Fred Fish (fnf@cygnus.com).
This file is part of GNU CC.
@@ -31,17 +30,16 @@ Boston, MA 02111-1307, USA. */
executed. This macro forces the assembler to do the padding, since
it knows what it is doing. */
-#define FORCE_INIT_SECTION_ALIGN do { asm (ALIGN_ASM_OP ## " 16"); } while (0)
+#define FORCE_INIT_SECTION_ALIGN asm (ALIGN_ASM_OP ## " 16")
#define FORCE_FINI_SECTION_ALIGN FORCE_INIT_SECTION_ALIGN
/* Add "sun" to the list of symbols defined for SVR4. */
#undef CPP_PREDEFINES
#define CPP_PREDEFINES \
- "-Di386 -Dunix -D__svr4__ -D__SVR4 -Dsun \
- -Asystem(unix) -Asystem(svr4) -Acpu(i386) -Amachine(i386)"
+ "-Dunix -D__svr4__ -D__SVR4 -Dsun -Asystem(svr4)"
#undef CPP_SPEC
-#define CPP_SPEC "\
+#define CPP_SPEC "%(cpp_cpu) \
%{compat-bsd:-iwithprefixbefore ucbinclude -I/usr/ucbinclude}"
#undef LIB_SPEC
@@ -51,10 +49,21 @@ Boston, MA 02111-1307, USA. */
#undef ENDFILE_SPEC
#define ENDFILE_SPEC "crtend.o%s %{pg:crtn.o%s}%{!pg:crtn.o%s}"
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared: \
+ %{!symbolic: \
+ %{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}}}\
+ %{pg:gmon.o%s} crti.o%s \
+ %{ansi:values-Xc.o%s} \
+ %{!ansi: \
+ %{traditional:values-Xt.o%s} \
+ %{!traditional:values-Xa.o%s}} \
+ crtbegin.o%s"
+
/* This should be the same as in svr4.h, except with -R added. */
#undef LINK_SPEC
#define LINK_SPEC \
- "%{h*} %{V} %{v:%{!V:-V}} \
+ "%{h*} %{v:-V} \
%{b} %{Wl,*:%*} \
%{static:-dn -Bstatic} \
%{shared:-G -dy -z text} \
@@ -63,12 +72,14 @@ Boston, MA 02111-1307, USA. */
%{YP,*} \
%{R*} \
%{compat-bsd: \
- %{!YP,*:%{p:-Y P,/usr/ucblib:/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
- %{!p:-Y P,/usr/ucblib:/usr/ccs/lib:/usr/lib}} \
+ %{!YP,*:%{pg:-Y P,/usr/ucblib:/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
+ %{!pg:%{p:-Y P,/usr/ucblib:/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
+ %{!p:-Y P,/usr/ucblib:/usr/ccs/lib:/usr/lib}}} \
-R /usr/ucblib} \
%{!compat-bsd: \
- %{!YP,*:%{p:-Y P,/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
- %{!p:-Y P,/usr/ccs/lib:/usr/lib}}} \
+ %{!YP,*:%{pg:-Y P,/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
+ %{!pg:%{p:-Y P,/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
+ %{!p:-Y P,/usr/ccs/lib:/usr/lib}}}} \
%{Qy:} %{!Qn:-Qy}"
/* This defines which switch letters take arguments.
@@ -76,16 +87,9 @@ Boston, MA 02111-1307, USA. */
#undef SWITCH_TAKES_ARG
#define SWITCH_TAKES_ARG(CHAR) \
- ( (CHAR) == 'D' \
- || (CHAR) == 'U' \
- || (CHAR) == 'o' \
- || (CHAR) == 'e' \
- || (CHAR) == 'u' \
- || (CHAR) == 'I' \
- || (CHAR) == 'm' \
- || (CHAR) == 'L' \
+ (DEFAULT_SWITCH_TAKES_ARG(CHAR) \
|| (CHAR) == 'R' \
- || (CHAR) == 'A' \
|| (CHAR) == 'h' \
|| (CHAR) == 'z')
+#define STDC_0_IN_SYSTEM_HEADERS
diff --git a/contrib/gcc/config/i386/sun386.h b/contrib/gcc/config/i386/sun386.h
index 6e26807..4d4d66c 100644
--- a/contrib/gcc/config/i386/sun386.h
+++ b/contrib/gcc/config/i386/sun386.h
@@ -1,5 +1,5 @@
/* Definitions for Sun assembler syntax for the Intel 80386.
- Copyright (C) 1988 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -131,10 +131,9 @@ do \
#define ASM_GENERATE_INTERNAL_LABEL(BUF,PREFIX,NUMBER) \
sprintf ((BUF), "*.%s%d", (PREFIX), (NUMBER))
-/* This is how to output a reference to a user-level label named NAME. */
+/* The prefix to add to user-visible assembler symbols. */
-#define ASM_OUTPUT_LABELREF(FILE,NAME) \
- fprintf (FILE, "%s", NAME)
+#define USER_LABEL_PREFIX ""
/* This is how to output an internal numbered label where
PREFIX is the class of label and NUM is the number within the class. */
diff --git a/contrib/gcc/config/i386/svr3.ifile b/contrib/gcc/config/i386/svr3.ifile
index f0bb3a0..32b3ddc 100644
--- a/contrib/gcc/config/i386/svr3.ifile
+++ b/contrib/gcc/config/i386/svr3.ifile
@@ -28,7 +28,10 @@ SECTIONS
vfork = fork; /* I got tired of editing peoples sloppy code */
*(.fini)
}
- GROUP BIND( NEXT(0x400000) + (ADDR(.text) + (SIZEOF(.text)) % 0x1000)):
+ .stab BIND(ADDR(.text) + SIZEOF(.text)): { }
+ .stabstr BIND(ADDR(.stab) + SIZEOF(.stab)): { }
+ GROUP BIND( NEXT(0x400000) +
+ (ADDR(.stabstr) + (SIZEOF(.stabstr)) % 0x1000)):
{
.data : {
__CTOR_LIST__ = . ;
diff --git a/contrib/gcc/config/i386/svr3dbx.h b/contrib/gcc/config/i386/svr3dbx.h
index d3348d5..36c01cc 100644
--- a/contrib/gcc/config/i386/svr3dbx.h
+++ b/contrib/gcc/config/i386/svr3dbx.h
@@ -46,16 +46,13 @@ Boston, MA 02111-1307, USA. */
/* Align labels, etc. at 4-byte boundaries.
For the 486, align to 16-byte boundary for sake of cache. */
-#undef ASM_OUTPUT_ALIGN_CODE
-#define ASM_OUTPUT_ALIGN_CODE(FILE) \
- fprintf ((FILE), "\t.align %d,0x90\n", \
- 1 << i386_align_jumps)
+#undef LABEL_ALIGN_AFTER_BARRIER
+#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (i386_align_jumps)
/* Align start of loop at 4-byte boundary. */
-#undef ASM_OUTPUT_LOOP_ALIGN
-#define ASM_OUTPUT_LOOP_ALIGN(FILE) \
- fprintf ((FILE), "\t.align %d,0x90\n", 1 << i386_align_loops);
+#undef LOOP_ALIGN
+#define LOOP_ALIGN(LABEL) (i386_align_loops)
/* Additional overrides needed for dbx-in-coff gas, mostly taken from pbb.h */
@@ -66,17 +63,6 @@ Boston, MA 02111-1307, USA. */
*/
#define CTOR_LISTS_DEFINED_EXTERNALLY
-/* similar to default, but allows for the table defined by ld with svr3.ifile.
- nptrs is always 0. So we need to instead check that __DTOR_LIST__[1] != 0.
- The old check is left in so that the same macro can be used if and when
- a future version of gas does support section directives. */
-
-#define DO_GLOBAL_DTORS_BODY {int nptrs = *(int *)__DTOR_LIST__; int i; \
- if (nptrs == -1 || (__DTOR_LIST__[0] == 0 && __DTOR_LIST__[1] != 0)) \
- for (nptrs = 0; __DTOR_LIST__[nptrs + 1] != 0; nptrs++); \
- for (i = nptrs; i >= 1; i--) \
- __DTOR_LIST__[i] (); }
-
/* Use crt1.o as a startup file and crtn.o as a closing file. */
/*
* The loader directive file svr3.ifile defines how to merge the constructor
diff --git a/contrib/gcc/config/i386/svr3gas.h b/contrib/gcc/config/i386/svr3gas.h
index 401c766..a288b84 100644
--- a/contrib/gcc/config/i386/svr3gas.h
+++ b/contrib/gcc/config/i386/svr3gas.h
@@ -1,5 +1,5 @@
/* Definitions for Intel 386 running system V, using gas.
- Copyright (C) 1992 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -139,29 +139,17 @@ do { \
#endif /* STACK_GROWS_DOWNWARD */
-/* Add extra sections .init and .fini, in addition to .bss from att386.h. */
+/* Add extra sections .rodata, .init and .fini. */
#undef EXTRA_SECTIONS
-#define EXTRA_SECTIONS in_const, in_bss, in_init, in_fini
+#define EXTRA_SECTIONS in_const, in_init, in_fini
#undef EXTRA_SECTION_FUNCTIONS
#define EXTRA_SECTION_FUNCTIONS \
CONST_SECTION_FUNCTION \
- BSS_SECTION_FUNCTION \
INIT_SECTION_FUNCTION \
FINI_SECTION_FUNCTION
-#define BSS_SECTION_FUNCTION \
-void \
-bss_section () \
-{ \
- if (in_section != in_bss) \
- { \
- fprintf (asm_out_file, "\t%s\n", BSS_SECTION_ASM_OP); \
- in_section = in_bss; \
- } \
-}
-
#define INIT_SECTION_FUNCTION \
void \
init_section () \
diff --git a/contrib/gcc/config/i386/svr3z.ifile b/contrib/gcc/config/i386/svr3z.ifile
index 4fdbb93..4946051 100644
--- a/contrib/gcc/config/i386/svr3z.ifile
+++ b/contrib/gcc/config/i386/svr3z.ifile
@@ -28,7 +28,10 @@ SECTIONS
vfork = fork; /* I got tired of editing peoples sloppy code */
*(.fini)
}
- GROUP BIND( NEXT(0x400000) + (ADDR(.text) + (SIZEOF(.text)) % 0x1000)):
+ .stab BIND(ADDR(.text) + SIZEOF(.text)): { }
+ .stabstr BIND(ADDR(.stab) + SIZEOF(.stab)): { }
+ GROUP BIND( NEXT(0x400000) +
+ (ADDR(.stabstr) + (SIZEOF(.stabstr)) % 0x1000)):
{
.data : {
__CTOR_LIST__ = . ;
diff --git a/contrib/gcc/config/i386/sysv3.h b/contrib/gcc/config/i386/sysv3.h
index 8c5cfc4..ce89889 100644
--- a/contrib/gcc/config/i386/sysv3.h
+++ b/contrib/gcc/config/i386/sysv3.h
@@ -1,5 +1,5 @@
/* Definitions for Intel 386 running system V.
- Copyright (C) 1988 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -26,7 +26,7 @@ Boston, MA 02111-1307, USA. */
#include "svr3.h"
/* Use the ATT assembler syntax.
- This overrides at least one macro (ASM_OUTPUT_LABELREF) from svr3.h. */
+ This overrides at least one macro (USER_LABEL_PREFIX) from svr3.h. */
#include "i386/att.h"
@@ -42,9 +42,9 @@ Boston, MA 02111-1307, USA. */
/* Specify predefined symbols in preprocessor. */
-#define CPP_PREDEFINES "-Dunix -Di386 -Asystem(unix) -Asystem(svr3) -Acpu(i386) -Amachine(i386)"
+#define CPP_PREDEFINES "-Dunix -Asystem(svr3)"
-#define CPP_SPEC "%{posix:-D_POSIX_SOURCE}"
+#define CPP_SPEC "%(cpp_cpu) %{posix:-D_POSIX_SOURCE}"
/* Writing `int' for a bitfield forces int alignment for the structure. */
diff --git a/contrib/gcc/config/i386/sysv4.h b/contrib/gcc/config/i386/sysv4.h
index 92fcada..e688f7b 100644
--- a/contrib/gcc/config/i386/sysv4.h
+++ b/contrib/gcc/config/i386/sysv4.h
@@ -58,7 +58,7 @@ do { long value; \
/* This is how to output assembly code to define a `double' constant.
We always have to use a pair of .long pseudo-ops to do this because
the native SVR4 ELF assembler is buggy and it generates incorrect
- values when we try to use the the .double pseudo-op instead. */
+ values when we try to use the .double pseudo-op instead. */
#undef ASM_OUTPUT_DOUBLE
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
@@ -236,10 +236,18 @@ do { long value[3]; \
i386.md for an explanation of the expression this outputs. */
#undef ASM_OUTPUT_ADDR_DIFF_ELT
-#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, VALUE, REL) \
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
fprintf (FILE, "\t.long _GLOBAL_OFFSET_TABLE_+[.-%s%d]\n", LPREFIX, VALUE)
/* Indicate that jump tables go in the text section. This is
necessary when compiling PIC code. */
-#define JUMP_TABLES_IN_TEXT_SECTION
+#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic)
+
+/* A C statement (sans semicolon) to output to the stdio stream
+ FILE the assembler definition of uninitialized global DECL named
+ NAME whose size is SIZE bytes and alignment is ALIGN bytes.
+ Try to use asm_output_aligned_bss to implement this macro. */
+
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+ asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN)
diff --git a/contrib/gcc/config/i386/t-crtpic b/contrib/gcc/config/i386/t-crtpic
index f5dd073..ff81a9be 100644
--- a/contrib/gcc/config/i386/t-crtpic
+++ b/contrib/gcc/config/i386/t-crtpic
@@ -7,3 +7,4 @@
# routines in crtstuff.c.
CRTSTUFF_T_CFLAGS = -fPIC -fno-omit-frame-pointer
+TARGET_LIBGCC2_CFLAGS = -fPIC
diff --git a/contrib/gcc/config/i386/t-dgux b/contrib/gcc/config/i386/t-dgux
new file mode 100644
index 0000000..292331f
--- /dev/null
+++ b/contrib/gcc/config/i386/t-dgux
@@ -0,0 +1,4 @@
+#
+# target makefile for dgux
+#
+EXTRA_PARTS=crtbegin.o crtend.o
diff --git a/contrib/gcc/config/i386/t-mingw32 b/contrib/gcc/config/i386/t-mingw32
new file mode 100644
index 0000000..fe948c6
--- /dev/null
+++ b/contrib/gcc/config/i386/t-mingw32
@@ -0,0 +1,4 @@
+#
+# collect2 doesn't work for i386-mingw32* yet.
+#
+USE_COLLECT2=
diff --git a/contrib/gcc/config/i386/t-next b/contrib/gcc/config/i386/t-next
index ec6373f..effa695 100644
--- a/contrib/gcc/config/i386/t-next
+++ b/contrib/gcc/config/i386/t-next
@@ -7,3 +7,6 @@ OTHER_FIXINCLUDES_DIRS= /LocalDeveloper/Headers
# <limits.h> is sometimes in /usr/include/ansi/limits.h.
LIMITS_H_TEST = [ -f $(SYSTEM_HEADER_DIR)/limits.h -o -f $(SYSTEM_HEADER_DIR)/ansi/limits.h ]
+
+nextstep.o: $(srcdir)/config/nextstep.c $(CONFIG_H) flags.h tree.h
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/nextstep.c
diff --git a/contrib/gcc/config/i386/t-osf b/contrib/gcc/config/i386/t-osf
new file mode 100644
index 0000000..c996e0c
--- /dev/null
+++ b/contrib/gcc/config/i386/t-osf
@@ -0,0 +1,2 @@
+# If compiling with the osf gcc, avoid sharing code.
+TCFLAGS = -pic-none
diff --git a/contrib/gcc/config/i386/t-osf1elf b/contrib/gcc/config/i386/t-osf1elf
new file mode 100644
index 0000000..77c7df1
--- /dev/null
+++ b/contrib/gcc/config/i386/t-osf1elf
@@ -0,0 +1,18 @@
+# Assemble startup files.
+crti.o: $(srcdir)/config/i386/osf1-ci.asm $(GCC_PASSES)
+ sed -e '/^!/d' <$(srcdir)/config/i386/osf1-ci.asm >crti.s
+ $(GCC_FOR_TARGET) -c -o crti.o crti.s
+crtn.o: $(srcdir)/config/i386/osf1-cn.asm $(GCC_PASSES)
+ sed -e '/^!/d' <$(srcdir)/config/i386/osf1-cn.asm >crtn.s
+ $(GCC_FOR_TARGET) -c -o crtn.o crtn.s
+
+# The pushl in CTOR initialization interferes with frame pointer elimination.
+
+# We need to use -fPIC when we are using gcc to compile the routines in
+# crtstuff.c. This is only really needed when we are going to use gcc/g++
+# to produce a shared library, but since we don't know ahead of time when
+# we will be doing that, we just always use -fPIC when compiling the
+# routines in crtstuff.c.
+
+CRTSTUFF_T_CFLAGS = -fPIC -fno-omit-frame-pointer
+TARGET_LIBGCC2_CFLAGS = -fPIC
diff --git a/contrib/gcc/config/i386/t-sco5 b/contrib/gcc/config/i386/t-sco5
new file mode 100644
index 0000000..f602066
--- /dev/null
+++ b/contrib/gcc/config/i386/t-sco5
@@ -0,0 +1,20 @@
+# The pushl in CTOR initialization interferes with frame pointer elimination.
+CRTSTUFF_T_CFLAGS = -fPIC -fno-omit-frame-pointer
+CRTSTUFF_T_CFLAGS_S = -mcoff -fno-omit-frame-pointer
+
+#
+# I am still a little unsure of the multilib architecture. The following
+# 4 lines are based on advice from meissner@cygnus.com.
+#
+MULTILIB_OPTIONS = mcoff/fPIC
+MULTILIB_DIRNAMES = coff pic
+MULTILIB_EXCEPTIONS = *mcoff*/*fPIC*
+MULTILIB_MATCHES = fPIC=fpic
+MULTILIB_EXTRA_OPTS =
+
+LIBGCC=stmp-multilib
+INSTALL_LIBGCC=install-multilib
+
+crti.o: $(srcdir)/config/i386/sol2-ci.asm $(GCC_PASSES)
+ sed -e '/^!/d' <$(srcdir)/config/i386/sol2-ci.asm >crti.s
+ $(GCC_FOR_TARGET) -c -o crti.o crti.s
diff --git a/contrib/gcc/config/i386/t-sco5gas b/contrib/gcc/config/i386/t-sco5gas
new file mode 100644
index 0000000..2bca87b
--- /dev/null
+++ b/contrib/gcc/config/i386/t-sco5gas
@@ -0,0 +1,20 @@
+# The pushl in CTOR initialization interferes with frame pointer elimination.
+CRTSTUFF_T_CFLAGS = -fPIC -fno-omit-frame-pointer
+CRTSTUFF_T_CFLAGS_S = -mcoff -fno-omit-frame-pointer
+
+#
+# I am still a little unsure of the multilib architecture. The following
+# 4 lines are based on advice from meissner@cygnus.com.
+#
+MULTILIB_OPTIONS = fPIC
+MULTILIB_DIRNAMES = pic
+MULTILIB_EXCEPTIONS = *fPIC*
+MULTILIB_MATCHES = fPIC=fpic
+MULTILIB_EXTRA_OPTS =
+
+LIBGCC=stmp-multilib
+INSTALL_LIBGCC=install-multilib
+
+crti.o: $(srcdir)/config/i386/sol2-ci.asm $(GCC_PASSES)
+ sed -e '/^!/d' <$(srcdir)/config/i386/sol2-ci.asm >crti.s
+ $(GCC_FOR_TARGET) -c -o crti.o crti.s
diff --git a/contrib/gcc/config/i386/t-sol2 b/contrib/gcc/config/i386/t-sol2
index f79f6ca..5dc59cc 100644
--- a/contrib/gcc/config/i386/t-sol2
+++ b/contrib/gcc/config/i386/t-sol2
@@ -13,20 +13,28 @@ gmon.o: $(srcdir)/config/i386/gmon-sol2.c $(GCC_PASSES) $(CONFIG_H)
# Apparently Sun believes that assembler files don't need comments, because no
# single ASCII character is valid (tried them all). So we manually strip out
# the comments with sed. This bug may only be in the Early Access releases.
-crt1.o: $(srcdir)/config/i386/sol2-c1.asm
+gcrt1.o: $(srcdir)/config/i386/sol2-gc1.asm
+ sed -e '/^!/d' <$(srcdir)/config/i386/sol2-gc1.asm >gcrt1.s
+ $(AS) -o gcrt1.o gcrt1.s
+crt1.o: $(srcdir)/config/i386/sol2-c1.asm $(GCC_PASSES)
sed -e '/^!/d' <$(srcdir)/config/i386/sol2-c1.asm >crt1.s
- $(AS) -o crt1.o crt1.s
-crti.o: $(srcdir)/config/i386/sol2-ci.asm
+ $(GCC_FOR_TARGET) -c -o crt1.o crt1.s
+crti.o: $(srcdir)/config/i386/sol2-ci.asm $(GCC_PASSES)
sed -e '/^!/d' <$(srcdir)/config/i386/sol2-ci.asm >crti.s
- $(AS) -o crti.o crti.s
-crtn.o: $(srcdir)/config/i386/sol2-cn.asm
+ $(GCC_FOR_TARGET) -c -o crti.o crti.s
+crtn.o: $(srcdir)/config/i386/sol2-cn.asm $(GCC_PASSES)
sed -e '/^!/d' <$(srcdir)/config/i386/sol2-cn.asm >crtn.s
- $(AS) -o crtn.o crtn.s
+ $(GCC_FOR_TARGET) -c -o crtn.o crtn.s
# We need to use -fPIC when we are using gcc to compile the routines in
# crtstuff.c. This is only really needed when we are going to use gcc/g++
# to produce a shared library, but since we don't know ahead of time when
# we will be doing that, we just always use -fPIC when compiling the
# routines in crtstuff.c.
+#
+# We must also enable optimization to avoid having any code appear after
+# the call & alignment statement, but before we switch back to the
+# .text section.
-CRTSTUFF_T_CFLAGS = -fPIC
+CRTSTUFF_T_CFLAGS = -fPIC -O2
+TARGET_LIBGCC2_CFLAGS = -fPIC
diff --git a/contrib/gcc/config/i386/t-winnt b/contrib/gcc/config/i386/t-winnt
index e8e1a0a..1e3557c 100644
--- a/contrib/gcc/config/i386/t-winnt
+++ b/contrib/gcc/config/i386/t-winnt
@@ -1,2 +1,6 @@
winnt.o: $(srcdir)/config/i386/winnt.c
- $(CC) -I. -I$(srcdir) -I$(srcdir)/config -c $(srcdir)/config/i386/winnt.c
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/i386/winnt.c
+oldnames.o: $(srcdir)/config/winnt/oldnames.c
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/winnt/oldnames.c
+spawnv.o: $(srcdir)/config/winnt/spawnv.c
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/config/winnt/spawnv.c
diff --git a/contrib/gcc/config/i386/unix.h b/contrib/gcc/config/i386/unix.h
index f38fe27..47440dd 100644
--- a/contrib/gcc/config/i386/unix.h
+++ b/contrib/gcc/config/i386/unix.h
@@ -45,7 +45,9 @@ Boston, MA 02111-1307, USA. */
count is in %cl. Some assemblers require %cl as an argument;
some don't. This macro controls what to do: by default, don't
print %cl. */
-#define AS3_SHIFT_DOUBLE(a,b,c,d) AS2 (a,c,d)
+#define SHIFT_DOUBLE_OMITS_COUNT 1
+#define AS3_SHIFT_DOUBLE(a,b,c,d) \
+ (SHIFT_DOUBLE_OMITS_COUNT ? AS2 (a,c,d) : AS3 (a,b,c,d))
/* Output the size-letter for an opcode.
CODE is the letter used in an operand spec (L, B, W, S or Q).
@@ -99,7 +101,6 @@ Boston, MA 02111-1307, USA. */
/* String containing the assembler's comment-starter. */
#define ASM_COMMENT_START "/"
-#define COMMENT_BEGIN "/"
/* Output to assembler file text saying following lines
may contain character constants, extra white space, comments, etc. */
@@ -146,3 +147,45 @@ Boston, MA 02111-1307, USA. */
#define FUNCTION_VALUE_REGNO_P(N) \
((N) == 0 || ((N)== FIRST_FLOAT_REG && TARGET_FLOAT_RETURNS_IN_80387))
+/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
+ Used for C++ multiple inheritance. */
+#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
+do { \
+ tree parm; \
+ \
+ if (i386_regparm > 0) \
+ parm = TYPE_ARG_TYPES (TREE_TYPE (function)); \
+ else \
+ parm = NULL_TREE; \
+ for (; parm; parm = TREE_CHAIN (parm)) \
+ if (TREE_VALUE (parm) == void_type_node) \
+ break; \
+ fprintf (FILE, "\taddl $%d,%s\n", DELTA, \
+ parm ? "%eax" \
+ : aggregate_value_p (TREE_TYPE (TREE_TYPE (FUNCTION))) ? "8(%esp)" \
+ : "4(%esp)"); \
+ \
+ if (flag_pic) \
+ { \
+ rtx xops[2]; \
+ xops[0] = pic_offset_table_rtx; \
+ xops[1] = (rtx) gen_label_rtx (); \
+ \
+ if (i386_regparm > 2) \
+ abort (); \
+ output_asm_insn ("push%L0 %0", xops); \
+ output_asm_insn (AS1 (call,%P1), xops); \
+ ASM_OUTPUT_INTERNAL_LABEL (FILE, "L", CODE_LABEL_NUMBER (xops[1])); \
+ output_asm_insn (AS1 (pop%L0,%0), xops); \
+ output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops); \
+ fprintf (FILE, "\tmovl "); \
+ assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
+ fprintf (FILE, "@GOT(%%ebx),%%ecx\n\tpopl %%ebx\n\tjmp *%%ecx\n"); \
+ } \
+ else \
+ { \
+ fprintf (FILE, "\tjmp "); \
+ assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
+ fprintf (FILE, "\n"); \
+ } \
+} while (0)
diff --git a/contrib/gcc/config/i386/vxi386.h b/contrib/gcc/config/i386/vxi386.h
new file mode 100644
index 0000000..1044286
--- /dev/null
+++ b/contrib/gcc/config/i386/vxi386.h
@@ -0,0 +1,23 @@
+/* Definitions of target machine for GNU compiler. VxWorks i386 version.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "i386/i386-aout.h"
+
+#define HANDLE_SYSV_PRAGMA
diff --git a/contrib/gcc/config/i386/winnt.c b/contrib/gcc/config/i386/winnt.c
index 3a7ebf1..0058eb7 100644
--- a/contrib/gcc/config/i386/winnt.c
+++ b/contrib/gcc/config/i386/winnt.c
@@ -1,6 +1,6 @@
/* Subroutines for insn-output.c for Windows NT.
Contributed by Douglas Rupp (drupp@cs.washington.edu)
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,8 +19,8 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
@@ -28,6 +28,342 @@ Boston, MA 02111-1307, USA. */
#include "tree.h"
#include "flags.h"
+/* i386/PE specific attribute support.
+
+ i386/PE has two new attributes:
+ dllexport - for exporting a function/variable that will live in a dll
+ dllimport - for importing a function/variable from a dll
+
+ Microsoft allows multiple declspecs in one __declspec, separating
+ them with spaces. We do NOT support this. Instead, use __declspec
+ multiple times.
+*/
+
+/* Return nonzero if ATTR is a valid attribute for DECL.
+ ATTRIBUTES are any existing attributes and ARGS are the arguments
+ supplied with ATTR. */
+
+int
+i386_pe_valid_decl_attribute_p (decl, attributes, attr, args)
+ tree decl;
+ tree attributes;
+ tree attr;
+ tree args;
+{
+ if (args == NULL_TREE)
+ {
+ if (is_attribute_p ("dllexport", attr))
+ return 1;
+ if (is_attribute_p ("dllimport", attr))
+ return 1;
+ }
+
+ return i386_valid_decl_attribute_p (decl, attributes, attr, args);
+}
+
+/* Return nonzero if ATTR is a valid attribute for TYPE.
+ ATTRIBUTES are any existing attributes and ARGS are the arguments
+ supplied with ATTR. */
+
+int
+i386_pe_valid_type_attribute_p (type, attributes, attr, args)
+ tree type;
+ tree attributes;
+ tree attr;
+ tree args;
+{
+ if (args == NULL_TREE
+ && (TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE))
+ {
+ if (is_attribute_p ("dllexport", attr))
+ return 1;
+ if (is_attribute_p ("dllimport", attr))
+ return 1;
+ }
+
+ return i386_valid_type_attribute_p (type, attributes, attr, args);
+}
+
+/* Merge attributes in decls OLD and NEW.
+
+ This handles the following situation:
+
+ __declspec (dllimport) int foo;
+ int foo;
+
+ The second instance of `foo' nullifies the dllimport. */
+
+tree
+i386_pe_merge_decl_attributes (old, new)
+ tree old, new;
+{
+ tree a;
+ int delete_dllimport_p;
+
+ old = DECL_MACHINE_ATTRIBUTES (old);
+ new = DECL_MACHINE_ATTRIBUTES (new);
+
+ /* What we need to do here is remove from `old' dllimport if it doesn't
+ appear in `new'. dllimport behaves like extern: if a declaration is
+ marked dllimport and a definition appears later, then the object
+ is not dllimport'd. */
+
+ if (lookup_attribute ("dllimport", old) != NULL_TREE
+ && lookup_attribute ("dllimport", new) == NULL_TREE)
+ delete_dllimport_p = 1;
+ else
+ delete_dllimport_p = 0;
+
+ a = merge_attributes (old, new);
+
+ if (delete_dllimport_p)
+ {
+ tree prev,t;
+
+ /* Scan the list for dllimport and delete it. */
+ for (prev = NULL_TREE, t = a; t; prev = t, t = TREE_CHAIN (t))
+ {
+ if (is_attribute_p ("dllimport", TREE_PURPOSE (t)))
+ {
+ if (prev == NULL_TREE)
+ a = TREE_CHAIN (a);
+ else
+ TREE_CHAIN (prev) = TREE_CHAIN (t);
+ break;
+ }
+ }
+ }
+
+ return a;
+}
+
+/* Return the type that we should use to determine if DECL is
+ imported or exported. */
+
+static tree
+associated_type (decl)
+ tree decl;
+{
+ tree t = NULL_TREE;
+
+ /* In the C++ frontend, DECL_CONTEXT for a method doesn't actually refer
+ to the containing class. So we look at the 'this' arg. */
+ if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+ {
+ /* Artificial methods are not affected by the import/export status of
+ their class unless they are virtual. */
+ if (! DECL_ARTIFICIAL (decl) || DECL_VINDEX (decl))
+ t = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl))));
+ }
+ else if (DECL_CONTEXT (decl)
+ && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't')
+ t = DECL_CONTEXT (decl);
+
+ return t;
+}
+
+/* Return non-zero if DECL is a dllexport'd object. */
+
+int
+i386_pe_dllexport_p (decl)
+ tree decl;
+{
+ tree exp;
+
+ if (TREE_CODE (decl) != VAR_DECL
+ && TREE_CODE (decl) != FUNCTION_DECL)
+ return 0;
+ exp = lookup_attribute ("dllexport", DECL_MACHINE_ATTRIBUTES (decl));
+ if (exp)
+ return 1;
+
+ /* Class members get the dllexport status of their class. */
+ if (associated_type (decl))
+ {
+ exp = lookup_attribute ("dllexport",
+ TYPE_ATTRIBUTES (associated_type (decl)));
+ if (exp)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return non-zero if DECL is a dllimport'd object. */
+
+int
+i386_pe_dllimport_p (decl)
+ tree decl;
+{
+ tree imp;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && TARGET_NOP_FUN_DLLIMPORT)
+ return 0;
+
+ if (TREE_CODE (decl) != VAR_DECL
+ && TREE_CODE (decl) != FUNCTION_DECL)
+ return 0;
+ imp = lookup_attribute ("dllimport", DECL_MACHINE_ATTRIBUTES (decl));
+ if (imp)
+ return 1;
+
+ /* Class members get the dllimport status of their class. */
+ if (associated_type (decl))
+ {
+ imp = lookup_attribute ("dllimport",
+ TYPE_ATTRIBUTES (associated_type (decl)));
+ if (imp)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return non-zero if SYMBOL is marked as being dllexport'd. */
+
+int
+i386_pe_dllexport_name_p (symbol)
+ char *symbol;
+{
+ return symbol[0] == '@' && symbol[1] == 'e' && symbol[2] == '.';
+}
+
+/* Return non-zero if SYMBOL is marked as being dllimport'd. */
+
+int
+i386_pe_dllimport_name_p (symbol)
+ char *symbol;
+{
+ return symbol[0] == '@' && symbol[1] == 'i' && symbol[2] == '.';
+}
+
+/* Mark a DECL as being dllexport'd.
+ Note that we override the previous setting (eg: dllimport). */
+
+void
+i386_pe_mark_dllexport (decl)
+ tree decl;
+{
+ char *oldname, *newname;
+ rtx rtlname;
+ tree idp;
+
+ rtlname = XEXP (DECL_RTL (decl), 0);
+ if (GET_CODE (rtlname) == SYMBOL_REF)
+ oldname = XSTR (rtlname, 0);
+ else if (GET_CODE (rtlname) == MEM
+ && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
+ oldname = XSTR (XEXP (rtlname, 0), 0);
+ else
+ abort ();
+ if (i386_pe_dllimport_name_p (oldname))
+ oldname += 9;
+ else if (i386_pe_dllexport_name_p (oldname))
+ return; /* already done */
+
+ newname = alloca (strlen (oldname) + 4);
+ sprintf (newname, "@e.%s", oldname);
+
+ /* We pass newname through get_identifier to ensure it has a unique
+ address. RTL processing can sometimes peek inside the symbol ref
+ and compare the string's addresses to see if two symbols are
+ identical. */
+ idp = get_identifier (newname);
+
+ XEXP (DECL_RTL (decl), 0) =
+ gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
+}
+
+/* Mark a DECL as being dllimport'd. */
+
+void
+i386_pe_mark_dllimport (decl)
+ tree decl;
+{
+ char *oldname, *newname;
+ tree idp;
+ rtx rtlname, newrtl;
+
+ rtlname = XEXP (DECL_RTL (decl), 0);
+ if (GET_CODE (rtlname) == SYMBOL_REF)
+ oldname = XSTR (rtlname, 0);
+ else if (GET_CODE (rtlname) == MEM
+ && GET_CODE (XEXP (rtlname, 0)) == SYMBOL_REF)
+ oldname = XSTR (XEXP (rtlname, 0), 0);
+ else
+ abort ();
+ if (i386_pe_dllexport_name_p (oldname))
+ {
+ error ("`%s' declared as both exported to and imported from a DLL.",
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ return;
+ }
+ else if (i386_pe_dllimport_name_p (oldname))
+ {
+ /* Already done, but force correct linkage since the redeclaration
+ might have omitted explicit extern. Sigh. */
+ if (TREE_CODE (decl) == VAR_DECL
+ /* ??? Is this test for vtables needed? */
+ && !DECL_VIRTUAL_P (decl))
+ {
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ }
+ return;
+ }
+
+ /* ??? One can well ask why we're making these checks here,
+ and that would be a good question. */
+
+ /* Imported variables can't be initialized. Note that C++ classes
+ are marked initial, so we need to check. */
+ if (TREE_CODE (decl) == VAR_DECL
+ && !DECL_VIRTUAL_P (decl)
+ && (DECL_INITIAL (decl)
+ && ! TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))))
+ {
+ error_with_decl (decl, "initialized variable `%s' is marked dllimport");
+ return;
+ }
+ /* Nor can they be static. */
+ if (TREE_CODE (decl) == VAR_DECL
+ /* ??? Is this test for vtables needed? */
+ && !DECL_VIRTUAL_P (decl)
+ && 0 /*???*/)
+ {
+ error_with_decl (decl, "static variable `%s' is marked dllimport");
+ return;
+ }
+
+ /* `extern' needn't be specified with dllimport.
+ Specify `extern' now and hope for the best. Sigh. */
+ if (TREE_CODE (decl) == VAR_DECL
+ /* ??? Is this test for vtables needed? */
+ && !DECL_VIRTUAL_P (decl))
+ {
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ }
+
+ newname = alloca (strlen (oldname) + 11);
+ sprintf (newname, "@i._imp__%s", oldname);
+
+ /* We pass newname through get_identifier to ensure it has a unique
+ address. RTL processing can sometimes peek inside the symbol ref
+ and compare the string's addresses to see if two symbols are
+ identical. */
+ idp = get_identifier (newname);
+
+ newrtl = gen_rtx (MEM, Pmode,
+ gen_rtx (SYMBOL_REF, Pmode,
+ IDENTIFIER_POINTER (idp)));
+ XEXP (DECL_RTL (decl), 0) = newrtl;
+
+ /* Can't treat a pointer to this as a constant address */
+ DECL_NON_ADDR_CONST_P (decl) = 1;
+}
+
/* Return string which is the former assembler name modified with a
suffix consisting of an atsign (@) followed by the number of bytes of
arguments */
@@ -37,6 +373,8 @@ gen_stdcall_suffix (decl)
tree decl;
{
int total = 0;
+ /* ??? This probably should use XSTR (XEXP (DECL_RTL (decl), 0), 0) instead
+ of DECL_ASSEMBLER_NAME. */
char *asmname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
char *newsym;
@@ -44,13 +382,19 @@ gen_stdcall_suffix (decl)
if (TREE_VALUE (tree_last (TYPE_ARG_TYPES (TREE_TYPE (decl))))
== void_type_node)
{
- tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ tree formal_type = TYPE_ARG_TYPES (TREE_TYPE (decl));
- while (TREE_VALUE (formal_type) != void_type_node)
- {
- total += TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
- formal_type = TREE_CHAIN (formal_type);
- }
+ while (TREE_VALUE (formal_type) != void_type_node)
+ {
+ int parm_size
+ = TREE_INT_CST_LOW (TYPE_SIZE (TREE_VALUE (formal_type)));
+ /* Must round up to include padding. This is done the same
+ way as in store_one_arg. */
+ parm_size = ((parm_size + PARM_BOUNDARY - 1)
+ / PARM_BOUNDARY * PARM_BOUNDARY);
+ total += parm_size;
+ formal_type = TREE_CHAIN (formal_type);
+ }
}
newsym = xmalloc (strlen (asmname) + 10);
@@ -58,3 +402,169 @@ gen_stdcall_suffix (decl)
return IDENTIFIER_POINTER (get_identifier (newsym));
}
+/* Cover function to implement ENCODE_SECTION_INFO. */
+
+void
+i386_pe_encode_section_info (decl)
+ tree decl;
+{
+ /* This bit is copied from i386.h. */
+ if (optimize > 0 && TREE_CONSTANT (decl)
+ && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
+ {
+ rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
+ ? TREE_CST_RTL (decl) : DECL_RTL (decl));
+ SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
+ }
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ if (lookup_attribute ("stdcall",
+ TYPE_ATTRIBUTES (TREE_TYPE (decl))))
+ XEXP (DECL_RTL (decl), 0) =
+ gen_rtx (SYMBOL_REF, Pmode, gen_stdcall_suffix (decl));
+
+ /* Mark the decl so we can tell from the rtl whether the object is
+ dllexport'd or dllimport'd. */
+
+ if (i386_pe_dllexport_p (decl))
+ i386_pe_mark_dllexport (decl);
+ else if (i386_pe_dllimport_p (decl))
+ i386_pe_mark_dllimport (decl);
+ /* It might be that DECL has already been marked as dllimport, but a
+ subsequent definition nullified that. The attribute is gone but
+ DECL_RTL still has @i._imp__foo. We need to remove that. Ditto
+ for the DECL_NON_ADDR_CONST_P flag. */
+ else if ((TREE_CODE (decl) == FUNCTION_DECL
+ || TREE_CODE (decl) == VAR_DECL)
+ && DECL_RTL (decl) != NULL_RTX
+ && GET_CODE (DECL_RTL (decl)) == MEM
+ && GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
+ && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == SYMBOL_REF
+ && i386_pe_dllimport_name_p (XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0)))
+ {
+ char *oldname = XSTR (XEXP (XEXP (DECL_RTL (decl), 0), 0), 0);
+ tree idp = get_identifier (oldname + 9);
+ rtx newrtl = gen_rtx (SYMBOL_REF, Pmode, IDENTIFIER_POINTER (idp));
+
+ XEXP (DECL_RTL (decl), 0) = newrtl;
+
+ DECL_NON_ADDR_CONST_P (decl) = 0;
+
+ /* We previously set TREE_PUBLIC and DECL_EXTERNAL.
+ We leave these alone for now. */
+ }
+}
+
+/* Cover function for UNIQUE_SECTION. */
+
+void
+i386_pe_unique_section (decl, reloc)
+ tree decl;
+ int reloc;
+{
+ int len;
+ char *name,*string,*prefix;
+
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+ /* Strip off any encoding in fnname. */
+ STRIP_NAME_ENCODING (name, name);
+
+ /* The object is put in, for example, section .text$foo.
+ The linker will then ultimately place them in .text
+ (everything from the $ on is stripped). Don't put
+ read-only data in .rdata section to avoid a PE linker
+ bug when .rdata$* grouped sections are used in code
+ without a .rdata section. */
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ prefix = ".text$";
+ else if (DECL_READONLY_SECTION (decl, reloc))
+#ifdef READONLY_DATA_SECTION
+ prefix = ".rdata$";
+#else
+ prefix = ".text$";
+#endif
+ else
+ prefix = ".data$";
+ len = strlen (name) + strlen (prefix);
+ string = alloca (len + 1);
+ sprintf (string, "%s%s", prefix, name);
+
+ DECL_SECTION_NAME (decl) = build_string (len, string);
+}
+
+/* The Microsoft linker requires that every function be marked as
+ DT_FCN. When using gas on cygwin32, we must emit appropriate .type
+ directives. */
+
+#include "gsyms.h"
+
+/* Mark a function appropriately. This should only be called for
+ functions for which we are not emitting COFF debugging information.
+ FILE is the assembler output file, NAME is the name of the
+ function, and PUBLIC is non-zero if the function is globally
+ visible. */
+
+void
+i386_pe_declare_function_type (file, name, public)
+ FILE *file;
+ char *name;
+ int public;
+{
+ fprintf (file, "\t.def\t");
+ assemble_name (file, name);
+ fprintf (file, ";\t.scl\t%d;\t.type\t%d;\t.endef\n",
+ public ? (int) C_EXT : (int) C_STAT,
+ (int) DT_FCN << N_BTSHFT);
+}
+
+/* Keep a list of external functions. */
+
+struct extern_list
+{
+ struct extern_list *next;
+ char *name;
+};
+
+static struct extern_list *extern_head;
+
+/* Assemble an external function reference. We need to keep a list of
+ these, so that we can output the function types at the end of the
+ assembly. We can't output the types now, because we might see a
+ definition of the function later on and emit debugging information
+ for it then. */
+
+void
+i386_pe_record_external_function (name)
+ char *name;
+{
+ struct extern_list *p;
+
+ p = (struct extern_list *) permalloc (sizeof *p);
+ p->next = extern_head;
+ p->name = name;
+ extern_head = p;
+}
+
+/* This is called at the end of assembly. For each external function
+ which has not been defined, we output a declaration now. */
+
+void
+i386_pe_asm_file_end (file)
+ FILE *file;
+{
+ struct extern_list *p;
+
+ for (p = extern_head; p != NULL; p = p->next)
+ {
+ tree decl;
+
+ decl = get_identifier (p->name);
+
+ /* Positively ensure only one declaration for any given symbol. */
+ if (! TREE_ASM_WRITTEN (decl) && TREE_SYMBOL_REFERENCED (decl))
+ {
+ TREE_ASM_WRITTEN (decl) = 1;
+ i386_pe_declare_function_type (file, p->name, TREE_PUBLIC (decl));
+ }
+ }
+}
diff --git a/contrib/gcc/config/i386/x-dgux b/contrib/gcc/config/i386/x-dgux
new file mode 100644
index 0000000..322bfe3
--- /dev/null
+++ b/contrib/gcc/config/i386/x-dgux
@@ -0,0 +1,11 @@
+#
+# host is ix86 running dgux
+#
+CC = /bin/gcc
+X_CFLAGS = -O -mstandard -mlegend
+BOOT_CFLAGS = -O2 -g -mstandard -mlegend $(CFLAGS)
+CLIB = -lw32
+RANLIB = true
+USER_H = $(EXTRA_HEADERS) $(LANG_EXTRA_HEADERS)
+STMP_FIXPROTO =
+
diff --git a/contrib/gcc/config/i386/x-osf1elf b/contrib/gcc/config/i386/x-osf1elf
new file mode 100644
index 0000000..1467381
--- /dev/null
+++ b/contrib/gcc/config/i386/x-osf1elf
@@ -0,0 +1,8 @@
+# Defaults for OSF/1 1.3+
+CC = $(OLDCC)
+CLIB = -lld
+INSTALL = installbsd -c
+OLDCC = /usr/ccs/gcc/gcc
+X_CFLAGS = -static
+
+# FIXPROTO_DEFINES = -D_XOPEN_SOURCE
diff --git a/contrib/gcc/config/i386/x-osfrose b/contrib/gcc/config/i386/x-osfrose
index a419bdb..2c5e3ba 100644
--- a/contrib/gcc/config/i386/x-osfrose
+++ b/contrib/gcc/config/i386/x-osfrose
@@ -7,8 +7,9 @@
BUILD =
CC = $(OLDCC)
CLIB = -lld
-X_CFLAGS = $(DEB_OPT) $(MSTATS) $(SHLIB) $(X_DEFINES)
-X_CFLAGS_NODEBUG = $(NO_DEBUG) $(MSTATS) $(OPT) $(PROFILE) $(SHLIB) $(X_DEFINES) $(XCFLAGS)
+X_CFLAGS = $(DEB_OPT) $(MSTATS) $(X_DEFINES)
+X_CFLAGS_NODEBUG = $(NO_DEBUG) $(MSTATS) $(OPT) $(PROFILE) $(X_DEFINES) $(XCFLAGS)
+XCFLAGS = $(SHLIB)
CPP_ABORT = # -Dabort=fancy_abort
CPPFLAGS = $(CPP_ABORT) $(SYSTEM_INCLUDES)
DEB_OPT = $(OPT) $(DEBUG) $(PROFILE)
@@ -16,7 +17,6 @@ DEBUG =
DEBUG_COLLECT = # -DDEBUG
CCLIBFLAGS = -O -DNO_HALF_PIC
GCC_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) -B./ -DPOSIX -DNO_HALF_PIC
-INSTALL = installbsd -c
LDFLAGS =
MSTATS = # -mstats
OLDCC = /usr/ccs/gcc/gcc
@@ -25,7 +25,3 @@ PROFILE =
SHLIB = -pic-none
SYSTEM_INCLUDES = # -I${BUILD}/usr/include
X_DEFINES = -Dvfork=fork
-
-libdir = /usr/ccs
-mandir = /usr/ccs/gcc/$(target)/$(version)
-bindir = /usr/ccs/gcc/$(target)/$(version)
diff --git a/contrib/gcc/config/i386/x-sco5 b/contrib/gcc/config/i386/x-sco5
new file mode 100644
index 0000000..e13ed74
--- /dev/null
+++ b/contrib/gcc/config/i386/x-sco5
@@ -0,0 +1,10 @@
+RANLIB = :
+RANLIB_TEST = false
+CC = cc
+OLDCC = cc
+CCLIBFLAGS =
+# We avoid the ALLOCA in -lPW becuase it gives us an evil index()
+ALLOCA = alloca.o
+
+# See all the declarations.
+FIXPROTO_DEFINES = -D_XOPEN_SOURCE -D_POSIX_C_SOURCE=2
diff --git a/contrib/gcc/config/i386/xm-aix.h b/contrib/gcc/config/i386/xm-aix.h
index 5e5d402..4cbd36e 100644
--- a/contrib/gcc/config/i386/xm-aix.h
+++ b/contrib/gcc/config/i386/xm-aix.h
@@ -1,37 +1,2 @@
-/* Configuration for GNU C-compiler for IBM PS/2 running AIX/386.
- Copyright (C) 1988, 1993 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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, or (at your option)
-any later version.
-
-GNU CC 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 GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-#define USG
-
#undef TRUE
#undef FALSE
-
-#include "i386/xm-i386.h"
-
-#define bcopy(a,b,c) memcpy (b,a,c)
-#define bzero(a,b) memset (a,0,b)
-#define bcmp(a,b,c) memcmp (a,b,c)
-
-/* If not compiled with GNU C, use the portable alloca. */
-#ifndef __GNUC__
-#define USE_C_ALLOCA
-#endif
-
-#define HAVE_PUTENV
diff --git a/contrib/gcc/config/i386/xm-bsd386.h b/contrib/gcc/config/i386/xm-bsd386.h
index 9deb7ef..6b8eee7 100644
--- a/contrib/gcc/config/i386/xm-bsd386.h
+++ b/contrib/gcc/config/i386/xm-bsd386.h
@@ -1,6 +1,3 @@
/* Configuration for GCC for Intel i386 running BSDI's BSD/386 as host. */
#include "i386/xm-i386.h"
-
-#define HAVE_STRERROR
-
diff --git a/contrib/gcc/config/i386/xm-dgux.h b/contrib/gcc/config/i386/xm-dgux.h
new file mode 100644
index 0000000..5bdb9be
--- /dev/null
+++ b/contrib/gcc/config/i386/xm-dgux.h
@@ -0,0 +1,12 @@
+
+/* Configuration for GCC for Intel i386 running DG/ux */
+
+/* looks just like sysv4 for now */
+
+#include "i386/xm-i386.h"
+#include "xm-svr4.h"
+
+/* If not compiled with GNU C, use the portable alloca. */
+#ifndef __GNUC__
+#define USE_C_ALLOCA
+#endif
diff --git a/contrib/gcc/config/i386/xm-dos.h b/contrib/gcc/config/i386/xm-dos.h
index 1dd0c01..a734a81 100644
--- a/contrib/gcc/config/i386/xm-dos.h
+++ b/contrib/gcc/config/i386/xm-dos.h
@@ -1,8 +1,5 @@
#include "i386/xm-i386.h"
-/* Inhibit cccp.c's definition of putenv. */
-#define HAVE_PUTENV
-
/* Use semicolons to separate elements of a path. */
#define PATH_SEPARATOR ';'
@@ -15,6 +12,3 @@
#define MKTEMP_EACH_FILE 1
#define NO_PRECOMPILES 1
-
-/* sys_errlist proto in cccp.c doesn't match djgpp */
-#define HAVE_STRERROR
diff --git a/contrib/gcc/config/i386/xm-isc.h b/contrib/gcc/config/i386/xm-isc.h
index 7a0a47c..e686c5e 100644
--- a/contrib/gcc/config/i386/xm-isc.h
+++ b/contrib/gcc/config/i386/xm-isc.h
@@ -1,5 +1,3 @@
-#include "i386/xm-sysv3.h"
-
#ifndef REAL_ARITHMETIC
#define REAL_VALUE_ATOF(x, mode) strtod ((x), (char **)0)
extern double strtod ();
diff --git a/contrib/gcc/config/i386/xm-linux.h b/contrib/gcc/config/i386/xm-linux.h
index 42f097d..713bf3b2 100644
--- a/contrib/gcc/config/i386/xm-linux.h
+++ b/contrib/gcc/config/i386/xm-linux.h
@@ -1,5 +1,5 @@
-/* Configuration for GCC for Intel i386 running Linux.
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+/* Configuration for GCC for Intel i386 running Linux-based GNU systems.
+ Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
Contributed by H.J. Lu (hjl@nynexst.com)
This file is part of GNU CC.
diff --git a/contrib/gcc/config/i386/xm-mingw32.h b/contrib/gcc/config/i386/xm-mingw32.h
new file mode 100644
index 0000000..d818142
--- /dev/null
+++ b/contrib/gcc/config/i386/xm-mingw32.h
@@ -0,0 +1,42 @@
+/* Configuration for GNU C-compiler for hosting on Windows32.
+ using GNU tools and the Windows32 API Library.
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef USG
+#define USG 1
+#endif
+
+#ifndef ONLY_INT_FIELD
+#define ONLY_INT_FIELDS 1
+#endif
+
+#ifndef USE_PROTOTYPES
+#define USE_PROTOTYPES 1
+#endif
+
+#define NO_SYS_SIGLIST 1
+#define environ _environ
+
+/* Even though we support "/", allow "\" since everybody tests both. */
+#define DIR_SEPARATOR '\\'
+#define EXECUTABLE_SUFFIX ".exe"
+
+#undef PATH_SEPARATOR
+#define PATH_SEPARATOR ';'
diff --git a/contrib/gcc/config/i386/xm-openbsd.h b/contrib/gcc/config/i386/xm-openbsd.h
new file mode 100644
index 0000000..1a79e83
--- /dev/null
+++ b/contrib/gcc/config/i386/xm-openbsd.h
@@ -0,0 +1,23 @@
+/* Configuration file for i386 hosts running OpenBSD.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <xm-openbsd.h>
+#include <i386/xm-i386.h>
+
diff --git a/contrib/gcc/config/i386/xm-os2.h b/contrib/gcc/config/i386/xm-os2.h
index 5ff2899..aed925e 100644
--- a/contrib/gcc/config/i386/xm-os2.h
+++ b/contrib/gcc/config/i386/xm-os2.h
@@ -1,7 +1,7 @@
/* Configuration for GNU compiler
for an Intel i386 or later processor running OS/2 2.x.
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
- Contributed by Samuel Figueroa (figueroa@cs.nyu.edu)
+ Copyright (C) 1993, 1994, 1995, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Samuel Figueroa (figueroa@apple.com)
This file is part of GNU CC.
@@ -28,20 +28,24 @@ Boston, MA 02111-1307, USA. */
#include <stdlib.h> /* this defines alloca */
#define USG
#define ONLY_INT_FIELDS
-#define HAVE_PUTENV
#define USE_PROTOTYPES 1
-#define bcmp(a,b,c) memcmp (a,b,c)
-#define bcopy(a,b,c) memcpy (b,a,c)
-#define bzero(a,b) memset (a,0,b)
-#define index strchr
-#define rindex strrchr
#define strcasecmp stricmp
#define kill(a,b) raise(b)
#define mktemp tmpnam
#else
+#ifdef __EMX__
+#define EMX
+#define USG
+#define BSTRING
+#define HAVE_PUTENV
+#define HAVE_VPRINTF
+#define HAVE_STRERROR
+#define strcasecmp stricmp
+#else
#define ____386BSD____
int spawnv (int modeflag, char *path, char *argv[]);
int spawnvp (int modeflag, char *path, char *argv[]);
+#endif /* __EMX__ */
#endif /* __IBMC__ */
#ifndef PATH_SEPARATOR
@@ -52,6 +56,14 @@ int spawnvp (int modeflag, char *path, char *argv[]);
#endif
#define EXECUTABLE_SUFFIX ".exe"
+
+/* The EMX compiler uses regular .o files */
+#ifndef __EMX__
#define OBJECT_SUFFIX ".obj"
+#endif
+
+/* This is required to make temporary file names unique on file
+ systems which severely restrict the length of file names. */
+#define MKTEMP_EACH_FILE
#include "i386/xm-i386.h"
diff --git a/contrib/gcc/config/i386/xm-osf.h b/contrib/gcc/config/i386/xm-osf.h
index fda50d9..4cbd36e 100644
--- a/contrib/gcc/config/i386/xm-osf.h
+++ b/contrib/gcc/config/i386/xm-osf.h
@@ -1,32 +1,2 @@
-/* Configuration for GNU C-compiler for 386 running OSF/1
- Copyright (C) 1994 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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, or (at your option)
-any later version.
-
-GNU CC 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 GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
#undef TRUE
#undef FALSE
-
-#include "i386/xm-i386.h"
-
-#define bcopy(a,b,c) memcpy (b,a,c)
-#define bzero(a,b) memset (a,0,b)
-#define bcmp(a,b,c) memcmp (a,b,c)
-
-#define HAVE_PUTENV
-#define HAVE_VPRINTF
-
diff --git a/contrib/gcc/config/i386/xm-osf1elf.h b/contrib/gcc/config/i386/xm-osf1elf.h
new file mode 100644
index 0000000..69ca9c1
--- /dev/null
+++ b/contrib/gcc/config/i386/xm-osf1elf.h
@@ -0,0 +1,6 @@
+/* Configuration for GCC for Intel i386 running OSF/1 1.3. */
+
+#ifndef HZ
+#include <machine/machtime.h>
+#define HZ DEFAULT_CLK_TCK
+#endif
diff --git a/contrib/gcc/config/i386/xm-sco.h b/contrib/gcc/config/i386/xm-sco.h
index 01a63d90..ad63449 100644
--- a/contrib/gcc/config/i386/xm-sco.h
+++ b/contrib/gcc/config/i386/xm-sco.h
@@ -1,18 +1,9 @@
/* Configuration for GCC for Intel i386 running SCO. */
-#include "i386/xm-sysv3.h"
-
-/* On SCO 3.2.1, ldexp rejects values outside [0.5, 1). */
-
-#define BROKEN_LDEXP
-
/* Big buffers improve performance. */
#define IO_BUFFER_SIZE (0x8000 - 1024)
-/* SCO has a very small ARG_MAX. */
-#define SMALL_ARG_MAX
-
#ifndef __GNUC__
/* The SCO compiler gets it wrong, and treats enumerated bitfields
as signed quantities, making it impossible to use an 8-bit enum
diff --git a/contrib/gcc/config/i386/xm-sco5.h b/contrib/gcc/config/i386/xm-sco5.h
new file mode 100644
index 0000000..6b22b1d
--- /dev/null
+++ b/contrib/gcc/config/i386/xm-sco5.h
@@ -0,0 +1,7 @@
+/* Configuration for GCC for Intel i386 running SCO. */
+
+/* Big buffers improve performance. */
+
+#define IO_BUFFER_SIZE (0x8000 - 1024)
+
+
diff --git a/contrib/gcc/config/i386/xm-sun.h b/contrib/gcc/config/i386/xm-sun.h
index d2e714e..de7c201 100644
--- a/contrib/gcc/config/i386/xm-sun.h
+++ b/contrib/gcc/config/i386/xm-sun.h
@@ -1,5 +1,5 @@
/* Configuration for GNU C-compiler for Intel 80386 running SunOS 4.0.
- Copyright (C) 1988 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -21,7 +21,3 @@ Boston, MA 02111-1307, USA. */
#define USG
#include "i386/xm-i386.h"
-
-#define bcopy(a,b,c) memcpy (b,a,c)
-#define bzero(a,b) memset (a,0,b)
-#define bcmp(a,b,c) memcmp (a,b,c)
diff --git a/contrib/gcc/config/i386/xm-sysv4.h b/contrib/gcc/config/i386/xm-sysv4.h
index 49d52b4..1365064 100644
--- a/contrib/gcc/config/i386/xm-sysv4.h
+++ b/contrib/gcc/config/i386/xm-sysv4.h
@@ -1,16 +1,5 @@
/* Configuration for GCC for Intel i386 running System V Release 4. */
-#include "i386/xm-i386.h"
-#include "xm-svr4.h"
-
-/* If not compiled with GNU C, use the portable alloca. */
-#ifndef __GNUC__
-#define USE_C_ALLOCA
-#endif
#ifdef __HIGHC__
#include <alloca.h> /* for MetaWare High-C on NCR System 3000 */
#endif
-
-/* Univel, at least, has a small ARG_MAX. Defining this is harmless
- except for causing extra stat calls in the driver program. */
-#define SMALL_ARG_MAX
diff --git a/contrib/gcc/config/i386/xm-vsta.h b/contrib/gcc/config/i386/xm-vsta.h
index bb333ae..735d1d5 100644
--- a/contrib/gcc/config/i386/xm-vsta.h
+++ b/contrib/gcc/config/i386/xm-vsta.h
@@ -1,26 +1,2 @@
-/* Configuration for GNU C-compiler for Intel 80386.
- Copyright (C) 1994 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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, or (at your option)
-any later version.
-
-GNU CC 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 GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-#define NO_STAB_H
-
-#include "i386/xm-i386.h"
-
/* Use semicolons to separate elements of a path. */
#define PATH_SEPARATOR ';'
diff --git a/contrib/gcc/config/libgloss.h b/contrib/gcc/config/libgloss.h
new file mode 100644
index 0000000..2f2ba56
--- /dev/null
+++ b/contrib/gcc/config/libgloss.h
@@ -0,0 +1,35 @@
+/* libgloss.h -- operating system specific defines to be used when
+ targeting GCC for Libgloss supported targets.
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* The libgloss standard for crt0.s has the name based on the command line
+ option. */
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared:%{pg:pgcrt0%O%s}%{!pg:%{p:pcrt0%O%s}%{!p:crt0%O%s}}}"
+
+/* This file used to force LINK_SPEC to be the null string, but that is not
+ correct. LINK_SPEC is used to pass machine specific arguments to the
+ linker and hence can not be redefined here. LINK_SPEC is never used to
+ specify startup files or libraries, so it should never conflict with
+ libgloss. */
+
+/* Don't set the target flags, this is done by the linker script */
+#undef LIB_SPEC
+#define LIB_SPEC ""
diff --git a/contrib/gcc/config/linux-aout.h b/contrib/gcc/config/linux-aout.h
index 29fb8e9..ca8a39d 100644
--- a/contrib/gcc/config/linux-aout.h
+++ b/contrib/gcc/config/linux-aout.h
@@ -1,5 +1,5 @@
-/* Definitions for Linux
- Copyright (C) 1995 Free Software Foundation, Inc.
+/* Definitions for Linux-based GNU systems.
+ Copyright (C) 1995, 1997 Free Software Foundation, Inc.
Contributed by H.J. Lu (hjl@nynexst.com)
This file is part of GNU CC.
@@ -25,7 +25,7 @@ Boston, MA 02111-1307, USA. */
#undef HAVE_ATEXIT
#define HAVE_ATEXIT
-/* Linux uses ctype from glibc.a. I am not sure how complete it is.
+/* GNU/Linux uses ctype from glibc.a. I am not sure how complete it is.
For now, we play safe. It may change later. */
#if 0
@@ -36,16 +36,13 @@ Boston, MA 02111-1307, USA. */
#undef STARTFILE_SPEC
#define STARTFILE_SPEC "%{pg:gcrt0.o%s} %{!pg:%{p:gcrt0.o%s} %{!p:crt0.o%s}} %{static:-static}"
-/* There are conflicting reports about whether this system uses
- a different assembler syntax. wilson@cygnus.com says # is right. */
-#undef COMMENT_BEGIN
-#define COMMENT_BEGIN "#"
-
#undef ASM_APP_ON
#define ASM_APP_ON "#APP\n"
#undef ASM_APP_OFF
#define ASM_APP_OFF "#NO_APP\n"
+#define SET_ASM_OP ".set"
+
/* We need that too. */
#define HANDLE_SYSV_PRAGMA
diff --git a/contrib/gcc/config/linux.h b/contrib/gcc/config/linux.h
index c82cfe2..b619d01 100644
--- a/contrib/gcc/config/linux.h
+++ b/contrib/gcc/config/linux.h
@@ -1,7 +1,7 @@
-/* Definitions for Linux with ELF format
- Copyright (C) 1995 Free Software Foundation, Inc.
+/* Definitions for Linux-based GNU systems with ELF format
+ Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Eric Youngdale.
- Modified for stabs-in-ELF by H.J. Lu.
+ Modified for stabs-in-ELF by H.J. Lu (hjl@lucon.org).
This file is part of GNU CC.
@@ -26,7 +26,7 @@ Boston, MA 02111-1307, USA. */
#undef HAVE_ATEXIT
#define HAVE_ATEXIT
-/* Linux uses ctype from glibc.a. I am not sure how complete it is.
+/* GNU/Linux uses ctype from glibc.a. I am not sure how complete it is.
For now, we play safe. It may change later. */
#if 0
@@ -34,18 +34,16 @@ Boston, MA 02111-1307, USA. */
#define MULTIBYTE_CHARS 1
#endif
-/* There are conflicting reports about whether this system uses
- a different assembler syntax. wilson@cygnus.com says # is right. */
-#undef COMMENT_BEGIN
-#define COMMENT_BEGIN "#"
-
#undef ASM_APP_ON
#define ASM_APP_ON "#APP\n"
#undef ASM_APP_OFF
#define ASM_APP_OFF "#NO_APP\n"
+#define SET_ASM_OP ".set"
+
/* Use stabs instead of DWARF debug format. */
+#undef PREFERRED_DEBUGGING_TYPE
#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
#include "svr4.h"
@@ -61,28 +59,57 @@ Boston, MA 02111-1307, USA. */
fprintf (FILE, "\t.version\t\"01.01\"\n"); \
} while (0)
-#undef LIBGCC_SPEC
-#define LIBGCC_SPEC \
- "%{!shared:-lgcc}"
-
-
-/* Provide a STARTFILE_SPEC appropriate for Linux. Here we add
- the Linux magical crtbegin.o file (see crtstuff.c) which
+/* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add
+ the GNU/Linux magical crtbegin.o file (see crtstuff.c) which
provides part of the support for getting C++ file-scope static
object constructed before entering `main'. */
#undef STARTFILE_SPEC
#define STARTFILE_SPEC \
"%{!shared: \
- %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}}\
+ %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} \
+ %{!p:%{profile:gcrt1.o%s} \
+ %{!profile:crt1.o%s}}}} \
crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}"
-/* Provide a ENDFILE_SPEC appropriate for Linux. Here we tack on
- the Linux magical crtend.o file (see crtstuff.c) which
+/* Provide a ENDFILE_SPEC appropriate for GNU/Linux. Here we tack on
+ the GNU/Linux magical crtend.o file (see crtstuff.c) which
provides part of the support for getting C++ file-scope static
object constructed before entering `main', followed by a normal
- Linux "finalizer" file, `crtn.o'. */
+ GNU/Linux "finalizer" file, `crtn.o'. */
#undef ENDFILE_SPEC
#define ENDFILE_SPEC \
"%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s"
+
+/* This is for -profile to use -lc_p instead of -lc. */
+#ifndef CC1_SPEC
+#define CC1_SPEC "%{profile:-p}"
+#endif
+
+#ifndef USE_GNULIBC_1
+#undef DEFAULT_VTABLE_THUNKS
+#define DEFAULT_VTABLE_THUNKS 1
+#endif
+
+#undef LIB_SPEC
+/* We no longer link with libc_p.a or libg.a by default. If you
+ want to profile or debug the GNU/Linux C library, please add
+ -profile or -ggdb to LDFLAGS at the link time, respectively. */
+#if 1
+#ifdef USE_GNULIBC_1
+#define LIB_SPEC \
+ "%{!shared: %{p:-lgmon} %{pg:-lgmon} %{profile:-lgmon -lc_p} \
+ %{!profile:%{!ggdb:-lc} %{ggdb:-lg}}}"
+#else
+#define LIB_SPEC \
+ "%{shared: -lc} \
+ %{!shared: %{mieee-fp:-lieee} %{pthread:-lpthread} \
+ %{profile:-lc_p} %{!profile: -lc}}"
+#endif
+#else
+#define LIB_SPEC \
+ "%{!shared: \
+ %{p:-lgmon -lc_p} %{pg:-lgmon -lc_p} \
+ %{!p:%{!pg:%{!g*:-lc} %{g*:-lg}}}}"
+#endif
diff --git a/contrib/gcc/config/lynx.h b/contrib/gcc/config/lynx.h
index 04919d4..62c790b 100644
--- a/contrib/gcc/config/lynx.h
+++ b/contrib/gcc/config/lynx.h
@@ -1,5 +1,5 @@
/* Target independent definitions for LynxOS.
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -133,12 +133,11 @@ do { \
#undef INIT_SECTION_ASM_OP
#undef EXTRA_SECTIONS
-#define EXTRA_SECTIONS in_const, in_bss, in_ctors, in_dtors, in_fini,
+#define EXTRA_SECTIONS in_const, in_ctors, in_dtors, in_fini
#undef EXTRA_SECTION_FUNCTIONS
#define EXTRA_SECTION_FUNCTIONS \
CONST_SECTION_FUNCTION \
- BSS_SECTION_FUNCTION \
CTORS_SECTION_FUNCTION \
DTORS_SECTION_FUNCTION \
FINI_SECTION_FUNCTION
diff --git a/contrib/gcc/config/netbsd.h b/contrib/gcc/config/netbsd.h
index 8c0974a..0fb4d40 100644
--- a/contrib/gcc/config/netbsd.h
+++ b/contrib/gcc/config/netbsd.h
@@ -13,11 +13,11 @@
#define GCC_INCLUDE_DIR "/usr/include"
#undef INCLUDE_DEFAULTS
-#define INCLUDE_DEFAULTS \
- { \
- { GPLUSPLUS_INCLUDE_DIR, 1, 1 }, \
- { GCC_INCLUDE_DIR, 0, 0 }, \
- { 0, 0, 0 } \
+#define INCLUDE_DEFAULTS \
+ { \
+ { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 }, \
+ { GCC_INCLUDE_DIR, "GCC", 0, 0 }, \
+ { 0, 0, 0, 0 } \
}
/* Under NetBSD, the normal location of the compiler back ends is the
@@ -58,8 +58,13 @@
#undef LINK_SPEC
#define LINK_SPEC \
- "%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{static:-Bstatic} %{assert*}"
+ "%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{R*} %{static:-Bstatic} %{assert*}"
+/* This defines which switch letters take arguments. */
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ (DEFAULT_SWITCH_TAKES_ARG(CHAR) \
+ || (CHAR) == 'R')
/* We have atexit(3). */
@@ -68,28 +73,36 @@
/* Implicit library calls should use memcpy, not bcopy, etc. */
#define TARGET_MEM_FUNCTIONS
+
+/* Handle #pragma weak and #pragma pack. */
+
+#define HANDLE_SYSV_PRAGMA
/*
* Some imports from svr4.h in support of shared libraries.
* Currently, we need the DECLARE_OBJECT_SIZE stuff.
*/
-/* Define the strings used for the special svr4 .type and .size directives.
- These strings generally do not vary from one system running svr4 to
- another, but if a given system (e.g. m88k running svr) needs to use
- different pseudo-op names for these, they may be overridden in the
- file which includes this one. */
+/* Define the strings used for the .type, .size, and .set directives.
+ These strings generally do not vary from one system running netbsd
+ to another, but if a given system needs to use different pseudo-op
+ names for these, they may be overridden in the file which includes
+ this one. */
#undef TYPE_ASM_OP
#undef SIZE_ASM_OP
+#undef SET_ASM_OP
#define TYPE_ASM_OP ".type"
#define SIZE_ASM_OP ".size"
+#define SET_ASM_OP ".set"
/* This is how we tell the assembler that a symbol is weak. */
#undef ASM_WEAKEN_LABEL
#define ASM_WEAKEN_LABEL(FILE,NAME) \
- do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \
+ do { fputs ("\t.globl\t", FILE); assemble_name (FILE, NAME); \
+ fputc ('\n', FILE); \
+ fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \
fputc ('\n', FILE); } while (0)
/* The following macro defines the format used to output the second
diff --git a/contrib/gcc/config/nextstep.c b/contrib/gcc/config/nextstep.c
index 823bcee..e909a94 100644
--- a/contrib/gcc/config/nextstep.c
+++ b/contrib/gcc/config/nextstep.c
@@ -1,5 +1,5 @@
/* Functions for generic NeXT as target machine for GNU C compiler.
- Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1989, 90-93, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -18,6 +18,11 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#include "config.h"
+#include <stdio.h>
+#include "flags.h"
+#include "tree.h"
+
/* Make everything that used to go in the text section really go there. */
int flag_no_mach_text_sections = 0;
@@ -35,14 +40,17 @@ static int initial_optimize_flag;
extern char *get_directive_line ();
/* Called from check_newline via the macro HANDLE_PRAGMA.
- FINPUT is the source file input stream. */
+ FINPUT is the source file input stream.
+ CH is the first character after `#pragma'.
+ The result is 1 if the pragma was handled. */
-void
-handle_pragma (finput, get_line_function)
+int
+handle_pragma (finput, node)
FILE *finput;
- char *(*get_line_function) ();
+ tree node;
{
- register char *p = (*get_line_function) (finput);
+ int retval = 0;
+ register char *pname;
/* Record initial setting of optimize flag, so we can restore it. */
if (!pragma_initialized)
@@ -51,17 +59,24 @@ handle_pragma (finput, get_line_function)
initial_optimize_flag = optimize;
}
- if (OPT_STRCMP ("CC_OPT_ON"))
+ if (TREE_CODE (node) != IDENTIFIER_NODE)
+ return 0;
+
+ pname = IDENTIFIER_POINTER (node);
+
+ if (strcmp (pname, "CC_OPT_ON") == 0)
{
optimize = 1, obey_regdecls = 0;
warning ("optimization turned on");
+ retval = 1;
}
- else if (OPT_STRCMP ("CC_OPT_OFF"))
+ else if (strcmp (pname, "CC_OPT_OFF") == 0)
{
optimize = 0, obey_regdecls = 1;
warning ("optimization turned off");
+ retval = 1;
}
- else if (OPT_STRCMP ("CC_OPT_RESTORE"))
+ else if (strcmp (pname, "CC_OPT_RESTORE") == 0)
{
extern int initial_optimize_flag;
@@ -74,11 +89,14 @@ handle_pragma (finput, get_line_function)
optimize = initial_optimize_flag;
}
warning ("optimization level restored");
+ retval = 1;
}
- else if (OPT_STRCMP ("CC_WRITABLE_STRINGS"))
- flag_writable_strings = 1;
- else if (OPT_STRCMP ("CC_NON_WRITABLE_STRINGS"))
- flag_writable_strings = 0;
- else if (OPT_STRCMP ("CC_NO_MACH_TEXT_SECTIONS"))
- flag_no_mach_text_sections = 1;
+ else if (strcmp (pname, "CC_WRITABLE_STRINGS") == 0)
+ flag_writable_strings = retval = 1;
+ else if (strcmp (pname, "CC_NON_WRITABLE_STRINGS") == 0)
+ flag_writable_strings = 0, retval = 1;
+ else if (strcmp (pname, "CC_NO_MACH_TEXT_SECTIONS") == 0)
+ flag_no_mach_text_sections = retval = 1;
+
+ return retval;
}
diff --git a/contrib/gcc/config/nextstep.h b/contrib/gcc/config/nextstep.h
index 6e2e986..96435fc 100644
--- a/contrib/gcc/config/nextstep.h
+++ b/contrib/gcc/config/nextstep.h
@@ -1,6 +1,6 @@
-/* nextstep.h -- operating system specific defines to be used when
- targeting GCC for NeXTSTEP.
- Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+/* Operating system specific defines to be used when targeting GCC
+ for NeXTSTEP.
+ Copyright (C) 1989, 90-93, 1996, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -27,26 +27,43 @@ Boston, MA 02111-1307, USA. */
#undef INCLUDE_DEFAULTS
#define INCLUDE_DEFAULTS \
{ \
- { GPLUSPLUS_INCLUDE_DIR, 1, 1 }, \
- { LOCAL_INCLUDE_DIR, 0, 1 }, \
- { TOOL_INCLUDE_DIR, 0, 1 }, \
- { GCC_INCLUDE_DIR, 0, 0 }, \
+ { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 }, \
+ { LOCAL_INCLUDE_DIR, 0, 0, 1 }, \
+ { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 }, \
+ { GCC_INCLUDE_DIR, "GCC", 0, 0 }, \
/* These are for fixincludes-fixed ansi/bsd headers \
which wouldn't be found otherwise. \
(The use of string catenation here is OK since \
NeXT's native compiler is derived from GCC.) */ \
- { GCC_INCLUDE_DIR "/ansi", 0, 0 }, \
- { GCC_INCLUDE_DIR "/bsd", 0, 0 }, \
- { "/NextDeveloper/Headers", 0, 0 }, \
- { "/NextDeveloper/Headers/ansi", 0, 0 }, \
- { "/NextDeveloper/Headers/bsd", 0, 0 }, \
- { "/LocalDeveloper/Headers", 0, 0 }, \
- { "/LocalDeveloper/Headers/ansi", 0, 0 }, \
- { "/LocalDeveloper/Headers/bsd", 0, 0 }, \
- { "/NextDeveloper/2.0CompatibleHeaders", 0, 0 }, \
- { STANDARD_INCLUDE_DIR, 0, 0 }, \
- { "/usr/include/bsd", 0, 0 }, \
- { 0, 0, 0 } \
+ { GCC_INCLUDE_DIR "/ansi", 0, 0, 0 }, \
+ { GCC_INCLUDE_DIR "/bsd", 0, 0, 0 }, \
+ { "/NextDeveloper/Headers", 0, 0, 0 }, \
+ { "/NextDeveloper/Headers/ansi", 0, 0, 0 }, \
+ { "/NextDeveloper/Headers/bsd", 0, 0, 0 }, \
+ { "/LocalDeveloper/Headers", 0, 0, 0 }, \
+ { "/LocalDeveloper/Headers/ansi", 0, 0, 0 }, \
+ { "/LocalDeveloper/Headers/bsd", 0, 0, 0 }, \
+ { "/NextDeveloper/2.0CompatibleHeaders", 0, 0, 0 }, \
+ { STANDARD_INCLUDE_DIR, 0, 0, 0 }, \
+ { "/usr/include/bsd", 0, 0, 0 }, \
+ { 0, 0, 0, 0 } \
+ }
+#else /* CROSS_COMPILE */
+#undef INCLUDE_DEFAULTS
+#define INCLUDE_DEFAULTS \
+ { \
+ { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 }, \
+ { GPLUSPLUS_INCLUDE_DIR, 0, 1, 1 }, \
+ { LOCAL_INCLUDE_DIR, 0, 0, 1 }, \
+ { GCC_INCLUDE_DIR, "GCC", 0, 0 }, \
+ { GCC_INCLUDE_DIR "/ansi", 0, 0, 0 }, \
+ { GCC_INCLUDE_DIR "/bsd", 0, 0, 0 }, \
+ { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 }, \
+ { TOOL_INCLUDE_DIR "/ansi", 0, 0, 0 }, \
+ { TOOL_INCLUDE_DIR "/bsd", 0, 0, 0 }, \
+ { STANDARD_INCLUDE_DIR, 0, 0, 0 }, \
+ { "/usr/include/bsd", 0, 0, 0 }, \
+ { 0, 0, 0, 0 } \
}
#endif /* CROSS_COMPILE */
@@ -152,11 +169,6 @@ Boston, MA 02111-1307, USA. */
%{p:%e-p profiling is no longer supported. Use -pg instead.} \
%{!p:-lposixcrt0.o}}}"
-/* Why not? */
-
-#undef DOLLARS_IN_IDENTIFIERS
-#define DOLLARS_IN_IDENTIFIERS 2
-
/* Allow #sscs (but don't do anything). */
#define SCCS_DIRECTIVE
@@ -240,7 +252,7 @@ Boston, MA 02111-1307, USA. */
/* How to parse #pragma's */
#undef HANDLE_PRAGMA
-#define HANDLE_PRAGMA(finput) handle_pragma (finput, &get_directive_line)
+#define HANDLE_PRAGMA(FINPUT, NODE) handle_pragma (FINPUT, NODE)
/* Give methods pretty symbol names on NeXT. */
@@ -254,6 +266,11 @@ Boston, MA 02111-1307, USA. */
(CLASS_NAME), (SEL_NAME)); \
} while (0)
+/* The prefix to add to user-visible assembler symbols. */
+
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX "_"
+
/* Wrap new method names in quotes so the assembler doesn't gag.
Make Objective-C internal symbols local. */
@@ -263,7 +280,7 @@ Boston, MA 02111-1307, USA. */
else if (!strncmp (NAME, "_OBJC_", 6)) fprintf (FILE, "L%s", NAME); \
else if (!strncmp (NAME, ".objc_class_name_", 17)) \
fprintf (FILE, "%s", NAME); \
- else fprintf (FILE, "_%s", NAME); } while (0)
+ else fprintf (FILE, "%s%s", USER_LABEL_PREFIX, NAME); } while (0)
#undef ALIGN_ASM_OP
#define ALIGN_ASM_OP ".align"
@@ -565,3 +582,9 @@ objc_section_init () \
const_section (); \
} \
while (0)
+
+#ifdef ASM_COMMENT_START
+# undef ASM_COMMENT_START
+#endif
+
+#define ASM_COMMENT_START ";#"
diff --git a/contrib/gcc/config/openbsd.h b/contrib/gcc/config/openbsd.h
new file mode 100644
index 0000000..af8358e
--- /dev/null
+++ b/contrib/gcc/config/openbsd.h
@@ -0,0 +1,302 @@
+/* Base configuration file for all OpenBSD targets.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Common OpenBSD configuration.
+ All OpenBSD architectures include this file, which is intended as
+ a repository for common defines.
+
+ Some defines are common to all architectures, a few of them are
+ triggered by OBSD_* guards, so that we won't override architecture
+ defaults by mistakes.
+
+ OBSD_HAS_CORRECT_SPECS:
+ another mechanism provides correct specs already.
+ OBSD_NO_DYNAMIC_LIBRARIES:
+ no implementation of dynamic libraries.
+ OBSD_OLD_GAS:
+ older flavor of gas which needs help for PIC.
+ OBSD_HAS_DECLARE_FUNCTION_NAME, OBSD_HAS_DECLARE_FUNCTION_SIZE,
+ OBSD_HAS_DECLARE_OBJECT:
+ PIC support, FUNCTION_NAME/FUNCTION_SIZE are independent, whereas
+ the corresponding logic for OBJECTS is necessarily coupled.
+
+ There are also a few `default' defines such as ASM_WEAKEN_LABEL,
+ intended as common ground for arch that don't provide
+ anything suitable. */
+
+/* OPENBSD_NATIVE is defined only when gcc is configured as part of
+ the OpenBSD source tree, specifically through Makefile.bsd-wrapper.
+
+ In such a case the include path can be trimmed as there is no
+ distinction between system includes and gcc includes. */
+
+/* This configuration method, namely Makefile.bsd-wrapper and
+ OPENBSD_NATIVE is NOT recommended for building cross-compilers. */
+
+#ifdef OPENBSD_NATIVE
+
+#undef GCC_INCLUDE_DIR
+#define GCC_INCLUDE_DIR "/usr/include"
+
+/* The compiler is configured with ONLY the gcc/g++ standard headers. */
+#undef INCLUDE_DEFAULTS
+#define INCLUDE_DEFAULTS \
+ { \
+ { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 }, \
+ { GCC_INCLUDE_DIR, "GCC", 0, 0 }, \
+ { 0, 0, 0, 0 } \
+ }
+
+/* Under OpenBSD, the normal location of the various *crt*.o files is the
+ /usr/lib directory. */
+#define STANDARD_STARTFILE_PREFIX "/usr/lib/"
+
+#endif
+
+
+/* Controlling the compilation driver. */
+
+/* CPP_SPEC appropriate for OpenBSD. We deal with -posix and -pthread.
+ XXX the way threads are handling currently is not very satisfying,
+ since all code must be compiled with -pthread to work.
+ This two-stage defines makes it easy to pick that for targets that
+ have subspecs. */
+#define OBSD_CPP_SPEC "%{posix:-D_POSIX_SOURCE} %{pthread:-D_POSIX_THREADS}"
+
+/* LIB_SPEC appropriate for OpenBSD. Select the appropriate libc,
+ depending on profiling and threads. Basically,
+ -lc(_r)?(_p)?, select _r for threads, and _p for p or pg. */
+#define OBSD_LIB_SPEC "-lc%{pthread:_r}%{p:_p}%{!p:%{pg:_p}}"
+
+#ifndef OBSD_HAS_CORRECT_SPECS
+
+#ifndef OBSD_NO_DYNAMIC_LIBRARIES
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ (DEFAULT_SWITCH_TAKES_ARG (CHAR) \
+ || (CHAR) == 'R')
+#endif
+
+#undef CPP_SPEC
+#define CPP_SPEC OBSD_CPP_SPEC
+
+#ifdef OBSD_OLD_GAS
+/* ASM_SPEC appropriate for OpenBSD. For some architectures, OpenBSD
+ still uses a special flavor of gas that needs to be told when generating
+ pic code. */
+#undef ASM_SPEC
+#define ASM_SPEC "%{fpic:-k} %{fPIC:-k -K} %|"
+#else
+/* Since we use gas, stdin -> - is a good idea, but we don't want to
+ override native specs just for that. */
+#ifndef ASM_SPEC
+#define ASM_SPEC "%|"
+#endif
+#endif
+
+/* LINK_SPEC appropriate for OpenBSD. Support for GCC options
+ -static, -assert, and -nostdlib. */
+#undef LINK_SPEC
+#ifdef OBSD_NO_DYNAMIC_LIBRARIES
+#define LINK_SPEC \
+ "%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{assert*}"
+#else
+#define LINK_SPEC \
+ "%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp %{R*} %{static:-Bstatic} %{assert*}"
+#endif
+
+#undef LIB_SPEC
+#define LIB_SPEC OBSD_LIB_SPEC
+#endif
+
+
+/* Runtime target specification. */
+
+/* You must redefine CPP_PREDEFINES in any arch specific file. */
+#undef CPP_PREDEFINES
+
+/* Implicit calls to library routines. */
+
+/* Use memcpy and memset instead of bcopy and bzero. */
+#define TARGET_MEM_FUNCTIONS
+
+/* Miscellaneous parameters. */
+
+/* Tell libgcc2.c that OpenBSD targets support atexit. */
+#define HAVE_ATEXIT
+
+/* Controlling debugging info: dbx options. */
+
+/* Don't use the `xsTAG;' construct in DBX output; OpenBSD systems that
+ use DBX don't support it. */
+#define DBX_NO_XREFS
+
+
+/* Support of shared libraries, mostly imported from svr4.h through netbsd. */
+/* Two differences from svr4.h:
+ - we use . - _func instead of a local label,
+ - we put extra spaces in expressions such as
+ .type _func , @function
+ This is more readable for a human being and confuses c++filt less. */
+
+/* Assembler format: output and generation of labels. */
+
+/* Define the strings used for the .type and .size directives.
+ These strings generally do not vary from one system running OpenBSD
+ to another, but if a given system needs to use different pseudo-op
+ names for these, they may be overridden in the arch specific file. */
+
+/* OpenBSD assembler is hacked to have .type & .size support even in a.out
+ format object files. Functions size are supported but not activated
+ yet (look for GRACE_PERIOD_EXPIRED in gas/config/obj-aout.c). */
+
+#undef TYPE_ASM_OP
+#undef SIZE_ASM_OP
+
+#define TYPE_ASM_OP ".type"
+#define SIZE_ASM_OP ".size"
+
+/* The following macro defines the format used to output the second
+ operand of the .type assembler directive. */
+#undef TYPE_OPERAND_FMT
+#define TYPE_OPERAND_FMT "@%s"
+
+/* Provision if extra assembler code is needed to declare a function's result
+ (taken from svr4, not needed yet actually). */
+#ifndef ASM_DECLARE_RESULT
+#define ASM_DECLARE_RESULT(FILE, RESULT)
+#endif
+
+/* These macros generate the special .type and .size directives which
+ are used to set the corresponding fields of the linker symbol table
+ entries under OpenBSD. These macros also have to output the starting
+ labels for the relevant functions/objects. */
+
+#ifndef OBSD_HAS_DECLARE_FUNCTION_NAME
+/* Extra assembler code needed to declare a function properly.
+ Some assemblers may also need to also have something extra said
+ about the function's return value. We allow for that here. */
+#undef ASM_DECLARE_FUNCTION_NAME
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
+ do { \
+ fprintf (FILE, "\t%s\t", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fputs (" , ", FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "function"); \
+ putc ('\n', FILE); \
+ ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
+ ASM_OUTPUT_LABEL(FILE, NAME); \
+ } while (0)
+#endif
+
+#ifndef OBSD_HAS_DECLARE_FUNCTION_SIZE
+/* Declare the size of a function. */
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
+ do { \
+ if (!flag_inhibit_size_directive) \
+ { \
+ fprintf (FILE, "\t%s\t", SIZE_ASM_OP); \
+ assemble_name (FILE, (FNAME)); \
+ fputs (" , . - ", FILE); \
+ assemble_name (FILE, (FNAME)); \
+ putc ('\n', FILE); \
+ } \
+ } while (0)
+#endif
+
+#ifndef OBSD_HAS_DECLARE_OBJECT
+/* Extra assembler code needed to declare an object properly. */
+#undef ASM_DECLARE_OBJECT_NAME
+#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \
+ do { \
+ fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fputs (" , ", FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
+ putc ('\n', FILE); \
+ size_directive_output = 0; \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "\t%s\t", SIZE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, " , %d\n", int_size_in_bytes (TREE_TYPE (DECL)));\
+ } \
+ ASM_OUTPUT_LABEL (FILE, NAME); \
+ } while (0)
+
+/* Output the size directive for a decl in rest_of_decl_compilation
+ in the case where we did not do so before the initializer.
+ Once we find the error_mark_node, we know that the value of
+ size_directive_output was set by ASM_DECLARE_OBJECT_NAME
+ when it was run for the same decl. */
+#undef ASM_FINISH_DECLARE_OBJECT
+#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
+do { \
+ char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
+ && ! AT_END && TOP_LEVEL \
+ && DECL_INITIAL (DECL) == error_mark_node \
+ && !size_directive_output) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "\t%s\t", SIZE_ASM_OP); \
+ assemble_name (FILE, name); \
+ fprintf (FILE, " , %d\n", int_size_in_bytes (TREE_TYPE (DECL)));\
+ } \
+ } while (0)
+#endif
+
+
+/* Those are `generic' ways to weaken/globalize a label. We shouldn't need
+ to override a processor specific definition. Hence, #ifndef ASM_*
+ In case overriding turns out to be needed, one can always #undef ASM_*
+ before including this file. */
+
+/* Tell the assembler that a symbol is weak. */
+/* Note: netbsd arm32 assembler needs a .globl here. An override may
+ be needed when/if we go for arm32 support. */
+#ifndef ASM_WEAKEN_LABEL
+#define ASM_WEAKEN_LABEL(FILE,NAME) \
+ do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \
+ fputc ('\n', FILE); } while (0)
+#endif
+
+/* Tell the assembler that a symbol is global. */
+#ifndef ASM_GLOBALIZE_LABEL
+#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
+ do { fputs ("\t.globl\t", FILE); assemble_name (FILE, NAME); \
+ fputc ('\n', FILE); } while(0)
+#endif
+
+
+/* Storage layout. */
+
+/* We don't have to worry about binary compatibility with older C++ code,
+ but there is a big known bug with vtable thunks which has not been
+ fixed yet, so DON'T activate it by default. */
+/* #define DEFAULT_VTABLE_THUNKS 1 */
+
+
+/* Otherwise, since we support weak, gthr.h erroneously tries to use
+ #pragma weak. */
+#define GTHREAD_USE_WEAK 0
+
diff --git a/contrib/gcc/config/psos.h b/contrib/gcc/config/psos.h
new file mode 100644
index 0000000..d404300
--- /dev/null
+++ b/contrib/gcc/config/psos.h
@@ -0,0 +1,183 @@
+/* Operating system specific defines to be used when targeting GCC for some
+ embedded system running pSOS. We assume GNU tools with ELF, but
+ try to maintain compatibility with the MRI tools. Based on svr4.h.
+ Copyright (C) 1996 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+ To use this file, make up a file with a name like:
+
+ ?????-psos.h
+
+ where ????? is replaced by the name of the basic hardware that you
+ are targeting for. Then, in the file ?????-psos.h, put something
+ like:
+
+ #include "?????.h"
+ #include "psos.h"
+
+ followed by any really system-specific defines (or overrides of
+ defines) which you find that you need.
+*/
+
+
+/* Define a symbol indicating that we are using psos.h. */
+
+#define USING_PSOS_H
+
+
+/* All pSOS targets currently use the ELF object file format. */
+
+#define OBJECT_FORMAT_ELF
+
+
+/* Provide a NULL STARTFILE_SPEC. The startfile cannot be specified
+ here because it depends on the architecture (e.g. 68K), the
+ board-support package (e.g. M162) and the run-time configuration
+ (e.g. application vs. ram-image vs. rom-image). Specify the
+ startfile in a linker-script created from the generic
+ architecture-specific linker-scripts. */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC ""
+
+
+/* Predefined macros (independent of processor type). */
+
+#define CPP_PREDEFINES "-Dpsos"
+
+
+/* Implicit library calls should use ANSI memcpy rather than BSD
+ bcopy, etc. */
+
+#define TARGET_MEM_FUNCTIONS
+
+
+/* When using stabs, gcc2_compiled must be a stabs entry, not an
+ ordinary symbol, or gdb won't see it. The stabs entry must be
+ before the N_SO in order for gdb to find it. */
+
+#define ASM_IDENTIFY_GCC(FILE) \
+do \
+ { \
+ fputs (".stabs \"gcc2_compiled.\", 0x3c, 0, 0, 0\n", FILE); \
+ } \
+while (0)
+
+/* This is how we tell the assembler that a symbol is weak. */
+
+#define ASM_WEAKEN_LABEL(FILE,NAME) \
+ do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \
+ fputc ('\n', FILE); } while (0)
+
+/* Switch into a generic section. */
+
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
+ fprintf (FILE, ".section\t%s,\"%s\",@progbits\n", NAME, \
+ (DECL) && TREE_CODE (DECL) == FUNCTION_DECL ? "ax" : \
+ (DECL) && DECL_READONLY_SECTION (DECL, RELOC) ? "a" : "aw")
+
+
+/* Define the pseudo-ops used to switch to the .ctors and .dtors
+ sections. */
+
+#define CTORS_SECTION_ASM_OP ".section\t.ctors,\"aw\""
+#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"aw\""
+
+/* A default list of other sections which we might be "in" at any given
+ time. For targets that use additional sections (e.g. .tdesc) you
+ should override this definition in the target-specific file which
+ includes this file. */
+
+#undef EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_ctors, in_dtors
+
+/* A default list of extra section function definitions. For targets
+ that use additional sections (e.g. .tdesc) you should override this
+ definition in the target-specific file which includes this file. */
+
+#undef EXTRA_SECTION_FUNCTIONS
+#define EXTRA_SECTION_FUNCTIONS \
+ CTORS_SECTION_FUNCTION \
+ DTORS_SECTION_FUNCTION
+
+extern void text_section ();
+
+#define CTORS_SECTION_FUNCTION \
+void \
+ctors_section () \
+{ \
+ if (in_section != in_ctors) \
+ { \
+ fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \
+ in_section = in_ctors; \
+ } \
+}
+
+#define DTORS_SECTION_FUNCTION \
+void \
+dtors_section () \
+{ \
+ if (in_section != in_dtors) \
+ { \
+ fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \
+ in_section = in_dtors; \
+ } \
+}
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global constructors. */
+
+#ifndef INT_ASM_OP
+#define INT_ASM_OP ".long"
+#endif
+#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
+ do { \
+ ctors_section (); \
+ fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global destructors. */
+
+#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
+ do { \
+ dtors_section (); \
+ fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+
+/* Use DBX debugging info by default. */
+
+#ifndef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+#endif
+
+/* For pSOS we use DBX debugging info. */
+
+#define DBX_DEBUGGING_INFO
+
+
+/* Prevent generation of an exit function. */
+
+#define HAVE_ATEXIT
+
diff --git a/contrib/gcc/config/ptx4.h b/contrib/gcc/config/ptx4.h
new file mode 100644
index 0000000..aa31924
--- /dev/null
+++ b/contrib/gcc/config/ptx4.h
@@ -0,0 +1,859 @@
+/* Operating system specific defines to be used when targeting GCC for some
+ generic System V Release 4 system.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Ron Guilmette (rfg@monkeys.com).
+ Renamed and changed to suit Dynix/ptx v4 and later.
+ Modified by Tim Wright (timw@sequent.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+*/
+
+/* Define a symbol indicating that we are using svr4.h. */
+#define USING_SVR4_H
+
+/* For the sake of libgcc2.c, indicate target supports atexit. */
+#define HAVE_ATEXIT
+
+/* Cpp, assembler, linker, library, and startfile spec's. */
+
+/* This defines which switch letters take arguments. On svr4, most of
+ the normal cases (defined in gcc.c) apply, and we also have -h* and
+ -z* options (for the linker). Note however that there is no such
+ thing as a -T option for svr4. */
+
+#define SWITCH_TAKES_ARG(CHAR) \
+ ( (CHAR) == 'D' \
+ || (CHAR) == 'U' \
+ || (CHAR) == 'o' \
+ || (CHAR) == 'e' \
+ || (CHAR) == 'u' \
+ || (CHAR) == 'I' \
+ || (CHAR) == 'm' \
+ || (CHAR) == 'L' \
+ || (CHAR) == 'A' \
+ || (CHAR) == 'h' \
+ || (CHAR) == 'z')
+
+/* This defines which multi-letter switches take arguments. On svr4,
+ there are no such switches except those implemented by GCC itself. */
+
+#define WORD_SWITCH_TAKES_ARG(STR) \
+ (DEFAULT_WORD_SWITCH_TAKES_ARG (STR) \
+ && strcmp (STR, "Tdata") && strcmp (STR, "Ttext") \
+ && strcmp (STR, "Tbss"))
+
+/* You should redefine CPP_PREDEFINES in any file which includes this one.
+ The definition should be appropriate for the type of target system
+ involved, and it should include any -A (assertion) options which are
+ appropriate for the given target system. */
+#undef CPP_PREDEFINES
+
+/* Provide an ASM_SPEC appropriate for svr4. Here we try to support as
+ many of the specialized svr4 assembler options as seems reasonable,
+ given that there are certain options which we can't (or shouldn't)
+ support directly due to the fact that they conflict with other options
+ for other svr4 tools (e.g. ld) or with other options for GCC itself.
+ For example, we don't support the -o (output file) or -R (remove
+ input file) options because GCC already handles these things. We
+ also don't support the -m (run m4) option for the assembler because
+ that conflicts with the -m (produce load map) option of the svr4
+ linker. We do however allow passing arbitrary options to the svr4
+ assembler via the -Wa, option.
+
+ Note that gcc doesn't allow a space to follow -Y in a -Ym,* or -Yd,*
+ option.
+*/
+
+#undef ASM_SPEC
+#define ASM_SPEC \
+ "-no_0f_fix %{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*}"
+
+/* svr4 assemblers need the `-' (indicating input from stdin) to come after
+ the -o option (and its argument) for some reason. If we try to put it
+ before the -o option, the assembler will try to read the file named as
+ the output file in the -o option as an input file (after it has already
+ written some stuff to it) and the binary stuff contained therein will
+ cause totally confuse the assembler, resulting in many spurious error
+ messages. */
+
+#undef ASM_FINAL_SPEC
+#define ASM_FINAL_SPEC "%{pipe:-}"
+
+/* Provide a LIB_SPEC appropriate for svr4. Here we tack on the default
+ standard C library (unless we are building a shared library). */
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{!shared:%{!symbolic:-lc}}"
+
+/* Provide a LIBGCC_SPEC appropriate for svr4. We also want to exclude
+ libgcc when -symbolic. */
+
+#undef LIBGCC_SPEC
+#define LIBGCC_SPEC "%{!shared:%{!symbolic:-lgcc}}"
+
+/* Provide an ENDFILE_SPEC appropriate for svr4. Here we tack on our own
+ magical crtend.o file (see crtstuff.c) which provides part of the
+ support for getting C++ file-scope static object constructed before
+ entering `main', followed by the normal svr3/svr4 "finalizer" file,
+ which is either `gcrtn.o' or `crtn.o'. */
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s %{pg:gcrtn.o}%{!pg:crtn.o%s}"
+
+/* Provide a LINK_SPEC appropriate for svr4. Here we provide support
+ for the special GCC options -static, -shared, and -symbolic which
+ allow us to link things in one of these three modes by applying the
+ appropriate combinations of options at link-time. We also provide
+ support here for as many of the other svr4 linker options as seems
+ reasonable, given that some of them conflict with options for other
+ svr4 tools (e.g. the assembler). In particular, we do support the
+ -z*, -V, -b, -t, -Qy, -Qn, and -YP* options here, and the -e*,
+ -l*, -o*, -r, -s, -u*, and -L* options are directly supported
+ by gcc.c itself. We don't directly support the -m (generate load
+ map) option because that conflicts with the -m (run m4) option of
+ the svr4 assembler. We also don't directly support the svr4 linker's
+ -I* or -M* options because these conflict with existing GCC options.
+ We do however allow passing arbitrary options to the svr4 linker
+ via the -Wl, option. We don't support the svr4 linker's -a option
+ at all because it is totally useless and because it conflicts with
+ GCC's own -a option.
+
+ Note that gcc doesn't allow a space to follow -Y in a -YP,* option.
+
+ When the -G link option is used (-shared and -symbolic) a final link is
+ not being done. */
+
+#undef LINK_SPEC
+#define LINK_SPEC "%{h*} %{v:-V} \
+ %{b} %{Wl,*:%*} \
+ %{static:-dn -Bstatic} \
+ %{shared:-G -dy -z text} \
+ %{symbolic:-Bsymbolic -G -dy -z text} \
+ %{G:-G} \
+ %{YP,*} \
+ %{!YP,*:%{p:-Y P,/lib/libp:/usr/lib/libp:/lib:/usr/lib} \
+ %{!p:-Y P,/lib:/usr/lib}} \
+ %{Qy:} %{!Qn:-Qy}"
+
+/* Gcc automatically adds in one of the files /lib/values-Xc.o,
+ /lib/values-Xa.o, or /lib/values-Xt.o for each final link
+ step (depending upon the other gcc options selected, such as
+ -traditional and -ansi). These files each contain one (initialized)
+ copy of a special variable called `_lib_version'. Each one of these
+ files has `_lib_version' initialized to a different (enum) value.
+ The SVR4 library routines query the value of `_lib_version' at run
+ to decide how they should behave. Specifically, they decide (based
+ upon the value of `_lib_version') if they will act in a strictly ANSI
+ conforming manner or not.
+*/
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared: \
+ %{!symbolic: \
+ %{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}}}\
+ %{pg:gcrti.o%s}%{!pg:crti.o%s} \
+ %{ansi:values-Xc.o%s} \
+ %{!ansi: \
+ %{traditional:values-Xt.o%s} \
+ %{!traditional:values-Xa.o%s}} \
+ crtbegin.o%s"
+
+/* Attach a special .ident directive to the end of the file to identify
+ the version of GCC which compiled this code. The format of the
+ .ident string is patterned after the ones produced by native svr4
+ C compilers. */
+
+#define IDENT_ASM_OP ".ident"
+
+#define ASM_FILE_END(FILE) \
+do { \
+ fprintf ((FILE), "\t%s\t\"GCC: (GNU) %s\"\n", \
+ IDENT_ASM_OP, version_string); \
+ } while (0)
+
+/* Allow #sccs in preprocessor. */
+
+#define SCCS_DIRECTIVE
+
+/* Output #ident as a .ident. */
+
+#define ASM_OUTPUT_IDENT(FILE, NAME) \
+ fprintf (FILE, "\t%s\t\"%s\"\n", IDENT_ASM_OP, NAME);
+
+/* Use periods rather than dollar signs in special g++ assembler names. */
+
+#define NO_DOLLAR_IN_LABEL
+
+/* Writing `int' for a bitfield forces int alignment for the structure. */
+
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/* Implicit library calls should use memcpy, not bcopy, etc. */
+
+#define TARGET_MEM_FUNCTIONS
+
+/* Handle #pragma weak and #pragma pack. */
+
+#define HANDLE_SYSV_PRAGMA
+
+/* System V Release 4 uses DWARF debugging info. */
+
+#define DWARF_DEBUGGING_INFO
+
+/* The numbers used to denote specific machine registers in the System V
+ Release 4 DWARF debugging information are quite likely to be totally
+ different from the numbers used in BSD stabs debugging information
+ for the same kind of target machine. Thus, we undefine the macro
+ DBX_REGISTER_NUMBER here as an extra inducement to get people to
+ provide proper machine-specific definitions of DBX_REGISTER_NUMBER
+ (which is also used to provide DWARF registers numbers in dwarfout.c)
+ in their tm.h files which include this file. */
+
+#undef DBX_REGISTER_NUMBER
+
+/* gas on SVR4 supports the use of .stabs. Permit -gstabs to be used
+ in general, although it will only work when using gas. */
+
+#define DBX_DEBUGGING_INFO
+
+/* Use DWARF debugging info by default. */
+
+#ifndef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF_DEBUG
+#endif
+
+/* Make LBRAC and RBRAC addresses relative to the start of the
+ function. The native Solaris stabs debugging format works this
+ way, gdb expects it, and it reduces the number of relocation
+ entries. */
+
+#define DBX_BLOCKS_FUNCTION_RELATIVE 1
+
+/* When using stabs, gcc2_compiled must be a stabs entry, not an
+ ordinary symbol, or gdb won't see it. The stabs entry must be
+ before the N_SO in order for gdb to find it. */
+
+#define ASM_IDENTIFY_GCC(FILE) \
+do \
+ { \
+ if (write_symbols != DBX_DEBUG) \
+ fputs ("gcc2_compiled.:\n", FILE); \
+ else \
+ fputs ("\t.stabs\t\"gcc2_compiled.\", 0x3c, 0, 0, 0\n", FILE); \
+ } \
+while (0)
+
+/* Like block addresses, stabs line numbers are relative to the
+ current function. */
+
+#define ASM_OUTPUT_SOURCE_LINE(file, line) \
+do \
+ { \
+ static int sym_lineno = 1; \
+ fprintf (file, ".stabn 68,0,%d,.LM%d-", \
+ line, sym_lineno); \
+ assemble_name (file, \
+ XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));\
+ fprintf (file, "\n.LM%d:\n", sym_lineno); \
+ sym_lineno += 1; \
+ } \
+while (0)
+
+/* In order for relative line numbers to work, we must output the
+ stabs entry for the function name first. */
+
+#define DBX_FUNCTION_FIRST
+
+/* Generate a blank trailing N_SO to mark the end of the .o file, since
+ we can't depend upon the linker to mark .o file boundaries with
+ embedded stabs. */
+
+#define DBX_OUTPUT_MAIN_SOURCE_FILE_END(FILE, FILENAME) \
+ fprintf (FILE, \
+ "\t.text\n\t.stabs \"\",%d,0,0,.Letext\n.Letext:\n", N_SO)
+
+/* Define the actual types of some ANSI-mandated types. (These
+ definitions should work for most SVR4 systems). */
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+/* This causes trouble, because it requires the host machine
+ to support ANSI C. */
+/* #define MULTIBYTE_CHARS */
+
+#undef ASM_BYTE_OP
+#define ASM_BYTE_OP ".byte"
+
+#undef SET_ASM_OP
+#define SET_ASM_OP ".set"
+
+/* This is how to begin an assembly language file. Most svr4 assemblers want
+ at least a .file directive to come first, and some want to see a .version
+ directive come right after that. Here we just establish a default
+ which generates only the .file directive. If you need a .version
+ directive for any specific target, you should override this definition
+ in the target-specific file which includes this one. */
+
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+ output_file_directive ((FILE), main_input_filename)
+
+/* This is how to allocate empty space in some section. The .zero
+ pseudo-op is used for this on most svr4 assemblers. */
+
+#define SKIP_ASM_OP ".zero"
+
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(FILE,SIZE) \
+ fprintf (FILE, "\t%s\t%u\n", SKIP_ASM_OP, (SIZE))
+
+/* The prefix to add to user-visible assembler symbols.
+
+ For System V Release 4 the convention is *not* to prepend a leading
+ underscore onto user-level symbol names. */
+
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
+
+/* This is how to output an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class.
+
+ For most svr4 systems, the convention is that any symbol which begins
+ with a period is not put into the linker symbol table by the assembler. */
+
+#undef ASM_OUTPUT_INTERNAL_LABEL
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE, PREFIX, NUM) \
+do { \
+ fprintf (FILE, ".%s%d:\n", PREFIX, NUM); \
+} while (0)
+
+/* This is how to store into the string LABEL
+ the symbol_ref name of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class.
+ This is suitable for output with `assemble_name'.
+
+ For most svr4 systems, the convention is that any symbol which begins
+ with a period is not put into the linker symbol table by the assembler. */
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \
+do { \
+ sprintf (LABEL, "*.%s%d", PREFIX, NUM); \
+} while (0)
+
+/* Output the label which precedes a jumptable. Note that for all svr4
+ systems where we actually generate jumptables (which is to say every
+ svr4 target except i386, where we use casesi instead) we put the jump-
+ tables into the .rodata section and since other stuff could have been
+ put into the .rodata section prior to any given jumptable, we have to
+ make sure that the location counter for the .rodata section gets pro-
+ perly re-aligned prior to the actual beginning of the jump table. */
+
+#define ALIGN_ASM_OP ".align"
+
+#ifndef ASM_OUTPUT_BEFORE_CASE_LABEL
+#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE,PREFIX,NUM,TABLE) \
+ ASM_OUTPUT_ALIGN ((FILE), 2);
+#endif
+
+#undef ASM_OUTPUT_CASE_LABEL
+#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,JUMPTABLE) \
+ do { \
+ ASM_OUTPUT_BEFORE_CASE_LABEL (FILE, PREFIX, NUM, JUMPTABLE) \
+ ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \
+ } while (0)
+
+/* The standard SVR4 assembler seems to require that certain builtin
+ library routines (e.g. .udiv) be explicitly declared as .globl
+ in each assembly file where they are referenced. */
+
+#define ASM_OUTPUT_EXTERNAL_LIBCALL(FILE, FUN) \
+ ASM_GLOBALIZE_LABEL (FILE, XSTR (FUN, 0))
+
+/* This says how to output assembler code to declare an
+ uninitialized external linkage data object. Under SVR4,
+ the linker seems to want the alignment of data objects
+ to depend on their types. We do exactly that here. */
+
+#define COMMON_ASM_OP ".comm"
+
+#undef ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
+do { \
+ fprintf ((FILE), "\t%s\t", COMMON_ASM_OP); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), ",%u,%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \
+} while (0)
+
+/* This says how to output assembler code to declare an
+ uninitialized internal linkage data object. Under SVR4,
+ the linker seems to want the alignment of data objects
+ to depend on their types. We do exactly that here. */
+
+#define LOCAL_ASM_OP ".local"
+
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+do { \
+ fprintf ((FILE), "\t%s\t", LOCAL_ASM_OP); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), "\n"); \
+ ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN); \
+} while (0)
+
+/* This is the pseudo-op used to generate a 32-bit word of data with a
+ specific value in some section. This is the same for all known svr4
+ assemblers. */
+
+#define INT_ASM_OP ".long"
+
+/* This is the pseudo-op used to generate a contiguous sequence of byte
+ values from a double-quoted string WITHOUT HAVING A TERMINATING NUL
+ AUTOMATICALLY APPENDED. This is the same for most svr4 assemblers. */
+
+#undef ASCII_DATA_ASM_OP
+#define ASCII_DATA_ASM_OP ".ascii"
+
+/* Support const sections and the ctors and dtors sections for g++.
+ Note that there appears to be two different ways to support const
+ sections at the moment. You can either #define the symbol
+ READONLY_DATA_SECTION (giving it some code which switches to the
+ readonly data section) or else you can #define the symbols
+ EXTRA_SECTIONS, EXTRA_SECTION_FUNCTIONS, SELECT_SECTION, and
+ SELECT_RTX_SECTION. We do both here just to be on the safe side. */
+
+#define USE_CONST_SECTION 1
+
+#define CONST_SECTION_ASM_OP ".section\t.rodata"
+
+/* Define the pseudo-ops used to switch to the .ctors and .dtors sections.
+
+ Note that we want to give these sections the SHF_WRITE attribute
+ because these sections will actually contain data (i.e. tables of
+ addresses of functions in the current root executable or shared library
+ file) and, in the case of a shared library, the relocatable addresses
+ will have to be properly resolved/relocated (and then written into) by
+ the dynamic linker when it actually attaches the given shared library
+ to the executing process. (Note that on SVR4, you may wish to use the
+ `-z text' option to the ELF linker, when building a shared library, as
+ an additional check that you are doing everything right. But if you do
+ use the `-z text' option when building a shared library, you will get
+ errors unless the .ctors and .dtors sections are marked as writable
+ via the SHF_WRITE attribute.) */
+
+#define CTORS_SECTION_ASM_OP ".section\t.ctors,\"aw\""
+#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"aw\""
+
+/* On svr4, we *do* have support for the .init and .fini sections, and we
+ can put stuff in there to be executed before and after `main'. We let
+ crtstuff.c and other files know this by defining the following symbols.
+ The definitions say how to change sections to the .init and .fini
+ sections. This is the same for all known svr4 assemblers. */
+
+#define INIT_SECTION_ASM_OP ".section\t.init"
+#define FINI_SECTION_ASM_OP ".section\t.fini"
+
+/* A default list of other sections which we might be "in" at any given
+ time. For targets that use additional sections (e.g. .tdesc) you
+ should override this definition in the target-specific file which
+ includes this file. */
+
+#undef EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_const, in_ctors, in_dtors
+
+/* A default list of extra section function definitions. For targets
+ that use additional sections (e.g. .tdesc) you should override this
+ definition in the target-specific file which includes this file. */
+
+#undef EXTRA_SECTION_FUNCTIONS
+#define EXTRA_SECTION_FUNCTIONS \
+ CONST_SECTION_FUNCTION \
+ CTORS_SECTION_FUNCTION \
+ DTORS_SECTION_FUNCTION
+
+#define READONLY_DATA_SECTION() const_section ()
+
+extern void text_section ();
+
+#define CONST_SECTION_FUNCTION \
+void \
+const_section () \
+{ \
+ if (!USE_CONST_SECTION) \
+ text_section(); \
+ else if (in_section != in_const) \
+ { \
+ fprintf (asm_out_file, "%s\n", CONST_SECTION_ASM_OP); \
+ in_section = in_const; \
+ } \
+}
+
+#define CTORS_SECTION_FUNCTION \
+void \
+ctors_section () \
+{ \
+ if (in_section != in_ctors) \
+ { \
+ fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \
+ in_section = in_ctors; \
+ } \
+}
+
+#define DTORS_SECTION_FUNCTION \
+void \
+dtors_section () \
+{ \
+ if (in_section != in_dtors) \
+ { \
+ fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \
+ in_section = in_dtors; \
+ } \
+}
+
+/* Switch into a generic section.
+ This is currently only used to support section attributes.
+
+ We make the section read-only and executable for a function decl,
+ read-only for a const data decl, and writable for a non-const data decl. */
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
+ fprintf (FILE, ".section\t%s,\"%s\",@progbits\n", NAME, \
+ (DECL) && TREE_CODE (DECL) == FUNCTION_DECL ? "ax" : \
+ (DECL) && DECL_READONLY_SECTION (DECL, RELOC) ? "a" : "aw")
+
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global constructors. */
+#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
+ do { \
+ ctors_section (); \
+ fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global destructors. */
+#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
+ do { \
+ dtors_section (); \
+ fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+/* A C statement or statements to switch to the appropriate
+ section for output of DECL. DECL is either a `VAR_DECL' node
+ or a constant of some sort. RELOC indicates whether forming
+ the initial value of DECL requires link-time relocations. */
+
+#define SELECT_SECTION(DECL,RELOC) \
+{ \
+ if (TREE_CODE (DECL) == STRING_CST) \
+ { \
+ if (! flag_writable_strings) \
+ const_section (); \
+ else \
+ data_section (); \
+ } \
+ else if (TREE_CODE (DECL) == VAR_DECL) \
+ { \
+ if ((flag_pic && RELOC) \
+ || !TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \
+ || !DECL_INITIAL (DECL) \
+ || (DECL_INITIAL (DECL) != error_mark_node \
+ && !TREE_CONSTANT (DECL_INITIAL (DECL)))) \
+ data_section (); \
+ else \
+ const_section (); \
+ } \
+ else \
+ const_section (); \
+}
+
+/* A C statement or statements to switch to the appropriate
+ section for output of RTX in mode MODE. RTX is some kind
+ of constant in RTL. The argument MODE is redundant except
+ in the case of a `const_int' rtx. Currently, these always
+ go into the const section. */
+
+#undef SELECT_RTX_SECTION
+#define SELECT_RTX_SECTION(MODE,RTX) const_section()
+
+/* Define the strings used for the special svr4 .type and .size directives.
+ These strings generally do not vary from one system running svr4 to
+ another, but if a given system (e.g. m88k running svr) needs to use
+ different pseudo-op names for these, they may be overridden in the
+ file which includes this one. */
+
+#define TYPE_ASM_OP ".type"
+#define SIZE_ASM_OP ".size"
+
+/* This is how we tell the assembler that a symbol is weak. */
+
+#define ASM_WEAKEN_LABEL(FILE,NAME) \
+ do { fputs ("\t.weak\t", FILE); assemble_name (FILE, NAME); \
+ fputc ('\n', FILE); } while (0)
+
+/* The following macro defines the format used to output the second
+ operand of the .type assembler directive. Different svr4 assemblers
+ expect various different forms for this operand. The one given here
+ is just a default. You may need to override it in your machine-
+ specific tm.h file (depending upon the particulars of your assembler). */
+
+#define TYPE_OPERAND_FMT "@%s"
+
+/* Write the extra assembler code needed to declare a function's result.
+ Most svr4 assemblers don't require any special declaration of the
+ result value, but there are exceptions. */
+
+#ifndef ASM_DECLARE_RESULT
+#define ASM_DECLARE_RESULT(FILE, RESULT)
+#endif
+
+/* These macros generate the special .type and .size directives which
+ are used to set the corresponding fields of the linker symbol table
+ entries in an ELF object file under SVR4. These macros also output
+ the starting labels for the relevant functions/objects. */
+
+/* Write the extra assembler code needed to declare a function properly.
+ Some svr4 assemblers need to also have something extra said about the
+ function's return value. We allow for that here. */
+
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
+ do { \
+ fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ putc (',', FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "function"); \
+ putc ('\n', FILE); \
+ ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
+ ASM_OUTPUT_LABEL(FILE, NAME); \
+ } while (0)
+
+/* Write the extra assembler code needed to declare an object properly. */
+
+#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \
+ do { \
+ fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ putc (',', FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
+ putc ('\n', FILE); \
+ size_directive_output = 0; \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
+ } \
+ ASM_OUTPUT_LABEL(FILE, NAME); \
+ } while (0)
+
+/* Output the size directive for a decl in rest_of_decl_compilation
+ in the case where we did not do so before the initializer.
+ Once we find the error_mark_node, we know that the value of
+ size_directive_output was set
+ by ASM_DECLARE_OBJECT_NAME when it was run for the same decl. */
+
+#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
+do { \
+ char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
+ && ! AT_END && TOP_LEVEL \
+ && DECL_INITIAL (DECL) == error_mark_node \
+ && !size_directive_output) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, name); \
+ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
+ } \
+ } while (0)
+
+/* This is how to declare the size of a function. */
+
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
+ do { \
+ if (!flag_inhibit_size_directive) \
+ { \
+ char label[256]; \
+ static int labelno; \
+ labelno++; \
+ ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \
+ ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \
+ fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
+ assemble_name (FILE, (FNAME)); \
+ fprintf (FILE, ","); \
+ assemble_name (FILE, label); \
+ fprintf (FILE, "-"); \
+ assemble_name (FILE, (FNAME)); \
+ putc ('\n', FILE); \
+ } \
+ } while (0)
+
+/* A table of bytes codes used by the ASM_OUTPUT_ASCII and
+ ASM_OUTPUT_LIMITED_STRING macros. Each byte in the table
+ corresponds to a particular byte value [0..255]. For any
+ given byte value, if the value in the corresponding table
+ position is zero, the given character can be output directly.
+ If the table value is 1, the byte must be output as a \ooo
+ octal escape. If the tables value is anything else, then the
+ byte value should be output as a \ followed by the value
+ in the table. Note that we can use standard UN*X escape
+ sequences for many control characters, but we don't use
+ \a to represent BEL because some svr4 assemblers (e.g. on
+ the i386) don't know about that. Also, we don't use \v
+ since some versions of gas, such as 2.2 did not accept it. */
+
+#define ESCAPES \
+"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0\
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
+\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
+
+/* Some svr4 assemblers have a limit on the number of characters which
+ can appear in the operand of a .string directive. If your assembler
+ has such a limitation, you should define STRING_LIMIT to reflect that
+ limit. Note that at least some svr4 assemblers have a limit on the
+ actual number of bytes in the double-quoted string, and that they
+ count each character in an escape sequence as one byte. Thus, an
+ escape sequence like \377 would count as four bytes.
+
+ If your target assembler doesn't support the .string directive, you
+ should define this to zero.
+*/
+
+#define STRING_LIMIT ((unsigned) 256)
+
+#define STRING_ASM_OP ".string"
+
+/* The routine used to output NUL terminated strings. We use a special
+ version of this for most svr4 targets because doing so makes the
+ generated assembly code more compact (and thus faster to assemble)
+ as well as more readable, especially for targets like the i386
+ (where the only alternative is to output character sequences as
+ comma separated lists of numbers). */
+
+#define ASM_OUTPUT_LIMITED_STRING(FILE, STR) \
+ do \
+ { \
+ register unsigned char *_limited_str = (unsigned char *) (STR); \
+ register unsigned ch; \
+ fprintf ((FILE), "\t%s\t\"", STRING_ASM_OP); \
+ for (; ch = *_limited_str; _limited_str++) \
+ { \
+ register int escape; \
+ switch (escape = ESCAPES[ch]) \
+ { \
+ case 0: \
+ putc (ch, (FILE)); \
+ break; \
+ case 1: \
+ fprintf ((FILE), "\\%03o", ch); \
+ break; \
+ default: \
+ putc ('\\', (FILE)); \
+ putc (escape, (FILE)); \
+ break; \
+ } \
+ } \
+ fprintf ((FILE), "\"\n"); \
+ } \
+ while (0)
+
+/* The routine used to output sequences of byte values. We use a special
+ version of this for most svr4 targets because doing so makes the
+ generated assembly code more compact (and thus faster to assemble)
+ as well as more readable. Note that if we find subparts of the
+ character sequence which end with NUL (and which are shorter than
+ STRING_LIMIT) we output those using ASM_OUTPUT_LIMITED_STRING. */
+
+#undef ASM_OUTPUT_ASCII
+#define ASM_OUTPUT_ASCII(FILE, STR, LENGTH) \
+ do \
+ { \
+ register unsigned char *_ascii_bytes = (unsigned char *) (STR); \
+ register unsigned char *limit = _ascii_bytes + (LENGTH); \
+ register unsigned bytes_in_chunk = 0; \
+ for (; _ascii_bytes < limit; _ascii_bytes++) \
+ { \
+ register unsigned char *p; \
+ if (bytes_in_chunk >= 60) \
+ { \
+ fprintf ((FILE), "\"\n"); \
+ bytes_in_chunk = 0; \
+ } \
+ for (p = _ascii_bytes; p < limit && *p != '\0'; p++) \
+ continue; \
+ if (p < limit && (p - _ascii_bytes) <= STRING_LIMIT) \
+ { \
+ if (bytes_in_chunk > 0) \
+ { \
+ fprintf ((FILE), "\"\n"); \
+ bytes_in_chunk = 0; \
+ } \
+ ASM_OUTPUT_LIMITED_STRING ((FILE), _ascii_bytes); \
+ _ascii_bytes = p; \
+ } \
+ else \
+ { \
+ register int escape; \
+ register unsigned ch; \
+ if (bytes_in_chunk == 0) \
+ fprintf ((FILE), "\t%s\t\"", ASCII_DATA_ASM_OP); \
+ switch (escape = ESCAPES[ch = *_ascii_bytes]) \
+ { \
+ case 0: \
+ putc (ch, (FILE)); \
+ bytes_in_chunk++; \
+ break; \
+ case 1: \
+ fprintf ((FILE), "\\%03o", ch); \
+ bytes_in_chunk += 4; \
+ break; \
+ default: \
+ putc ('\\', (FILE)); \
+ putc (escape, (FILE)); \
+ bytes_in_chunk += 2; \
+ break; \
+ } \
+ } \
+ } \
+ if (bytes_in_chunk > 0) \
+ fprintf ((FILE), "\"\n"); \
+ } \
+ while (0)
+
+/* All SVR4 targets use the ELF object file format. */
+#define OBJECT_FORMAT_ELF
diff --git a/contrib/gcc/config/sparc/aout.h b/contrib/gcc/config/sparc/aout.h
new file mode 100644
index 0000000..478d710
--- /dev/null
+++ b/contrib/gcc/config/sparc/aout.h
@@ -0,0 +1,26 @@
+/* Definitions of target machine for GNU compiler, for SPARC using a.out.
+ Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann (tiemann@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "sparc/sparc.h" /* SPARC definitions */
+#include "aoutos.h" /* A.out definitions */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dsparc -Acpu(sparc) -Amachine(sparc)"
diff --git a/contrib/gcc/config/sparc/bsd.h b/contrib/gcc/config/sparc/bsd.h
new file mode 100644
index 0000000..761abe2
--- /dev/null
+++ b/contrib/gcc/config/sparc/bsd.h
@@ -0,0 +1,7 @@
+#include "sparc/sparc.h"
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p}"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:%{p:gcrt0.o%s}%{!p:crt0.o%s}}"
diff --git a/contrib/gcc/config/sparc/elf.h b/contrib/gcc/config/sparc/elf.h
new file mode 100644
index 0000000..70cb26a
--- /dev/null
+++ b/contrib/gcc/config/sparc/elf.h
@@ -0,0 +1,42 @@
+/* Definitions of target machine for GNU compiler,
+ for SPARC running in an embedded environment using the ELF file format.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "sol2.h"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dsparc -D__elf__ -Acpu(sparc) -Amachine(sparc)"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "crt0.o%s crti.o%s crtbegin.o%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
+
+/* Use the default. */
+#undef LINK_SPEC
+
+/* Don't set the target flags, this is done by the linker script */
+#undef LIB_SPEC
+#define LIB_SPEC ""
+
+/* FIXME: until fixed */
+#undef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE 64
diff --git a/contrib/gcc/config/sparc/gmon-sol2.c b/contrib/gcc/config/sparc/gmon-sol2.c
new file mode 100644
index 0000000..2a5b898
--- /dev/null
+++ b/contrib/gcc/config/sparc/gmon-sol2.c
@@ -0,0 +1,429 @@
+/*-
+ * Copyright (c) 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Mangled into a form that works on Sparc Solaris 2 by Mark Eichin
+ * for Cygnus Support, July 1992.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)gmon.c 5.3 (Berkeley) 5/22/91";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#if 0
+#include "sparc/gmon.h"
+#else
+struct phdr {
+ char *lpc;
+ char *hpc;
+ int ncnt;
+};
+#define HISTFRACTION 2
+#define HISTCOUNTER unsigned short
+#define HASHFRACTION 1
+#define ARCDENSITY 2
+#define MINARCS 50
+struct tostruct {
+ char *selfpc;
+ long count;
+ unsigned short link;
+};
+struct rawarc {
+ unsigned long raw_frompc;
+ unsigned long raw_selfpc;
+ long raw_count;
+};
+#define ROUNDDOWN(x,y) (((x)/(y))*(y))
+#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y))
+
+#endif
+
+/* extern mcount() asm ("mcount"); */
+/*extern*/ char *minbrk /* asm ("minbrk") */;
+
+ /*
+ * froms is actually a bunch of unsigned shorts indexing tos
+ */
+static int profiling = 3;
+static unsigned short *froms;
+static struct tostruct *tos = 0;
+static long tolimit = 0;
+static char *s_lowpc = 0;
+static char *s_highpc = 0;
+static unsigned long s_textsize = 0;
+
+static int ssiz;
+static char *sbuf;
+static int s_scale;
+ /* see profil(2) where this is describe (incorrectly) */
+#define SCALE_1_TO_1 0x10000L
+
+#define MSG "No space for profiling buffer(s)\n"
+
+static void moncontrol();
+
+void monstartup(lowpc, highpc)
+ char *lowpc;
+ char *highpc;
+{
+ int monsize;
+ char *buffer;
+ register int o;
+
+ /*
+ * round lowpc and highpc to multiples of the density we're using
+ * so the rest of the scaling (here and in gprof) stays in ints.
+ */
+ lowpc = (char *)
+ ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
+ s_lowpc = lowpc;
+ highpc = (char *)
+ ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
+ s_highpc = highpc;
+ s_textsize = highpc - lowpc;
+ monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
+ buffer = sbrk( monsize );
+ if ( buffer == (char *) -1 ) {
+ write( 2 , MSG , sizeof(MSG) );
+ return;
+ }
+ froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
+ if ( froms == (unsigned short *) -1 ) {
+ write( 2 , MSG , sizeof(MSG) );
+ froms = 0;
+ return;
+ }
+ tolimit = s_textsize * ARCDENSITY / 100;
+ if ( tolimit < MINARCS ) {
+ tolimit = MINARCS;
+ } else if ( tolimit > 65534 ) {
+ tolimit = 65534;
+ }
+ tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) );
+ if ( tos == (struct tostruct *) -1 ) {
+ write( 2 , MSG , sizeof(MSG) );
+ froms = 0;
+ tos = 0;
+ return;
+ }
+ minbrk = sbrk(0);
+ tos[0].link = 0;
+ sbuf = buffer;
+ ssiz = monsize;
+ ( (struct phdr *) buffer ) -> lpc = lowpc;
+ ( (struct phdr *) buffer ) -> hpc = highpc;
+ ( (struct phdr *) buffer ) -> ncnt = ssiz;
+ monsize -= sizeof(struct phdr);
+ if ( monsize <= 0 )
+ return;
+ o = highpc - lowpc;
+ if( monsize < o )
+#ifndef hp300
+ s_scale = ( (float) monsize / o ) * SCALE_1_TO_1;
+#else /* avoid floating point */
+ {
+ int quot = o / monsize;
+
+ if (quot >= 0x10000)
+ s_scale = 1;
+ else if (quot >= 0x100)
+ s_scale = 0x10000 / quot;
+ else if (o >= 0x800000)
+ s_scale = 0x1000000 / (o / (monsize >> 8));
+ else
+ s_scale = 0x1000000 / ((o << 8) / monsize);
+ }
+#endif
+ else
+ s_scale = SCALE_1_TO_1;
+ moncontrol(1);
+}
+
+void
+_mcleanup()
+{
+ int fd;
+ int fromindex;
+ int endfrom;
+ char *frompc;
+ int toindex;
+ struct rawarc rawarc;
+ char *profdir;
+ char *proffile;
+ char *progname;
+ char buf[PATH_MAX];
+ extern char **___Argv;
+
+ moncontrol(0);
+
+ if ((profdir = getenv("PROFDIR")) != NULL) {
+ /* If PROFDIR contains a null value, no profiling output is produced */
+ if (*profdir == '\0') {
+ return;
+ }
+
+ progname=strrchr(___Argv[0], '/');
+ if (progname == NULL)
+ progname=___Argv[0];
+ else
+ progname++;
+
+ sprintf(buf, "%s/%ld.%s", profdir, getpid(), progname);
+ proffile = buf;
+ } else {
+ proffile = "gmon.out";
+ }
+
+ fd = creat( proffile, 0666 );
+ if ( fd < 0 ) {
+ perror( proffile );
+ return;
+ }
+# ifdef DEBUG
+ fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
+# endif DEBUG
+ write( fd , sbuf , ssiz );
+ endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
+ for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
+ if ( froms[fromindex] == 0 ) {
+ continue;
+ }
+ frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
+ for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
+# ifdef DEBUG
+ fprintf( stderr ,
+ "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
+ frompc , tos[toindex].selfpc , tos[toindex].count );
+# endif DEBUG
+ rawarc.raw_frompc = (unsigned long) frompc;
+ rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc;
+ rawarc.raw_count = tos[toindex].count;
+ write( fd , &rawarc , sizeof rawarc );
+ }
+ }
+ close( fd );
+}
+
+/*
+ * The Sparc stack frame is only held together by the frame pointers
+ * in the register windows. According to the SVR4 SPARC ABI
+ * Supplement, Low Level System Information/Operating System
+ * Interface/Software Trap Types, a type 3 trap will flush all of the
+ * register windows to the stack, which will make it possible to walk
+ * the frames and find the return addresses.
+ * However, it seems awfully expensive to incur a trap (system
+ * call) for every function call. It turns out that "call" simply puts
+ * the return address in %o7 expecting the "save" in the procedure to
+ * shift it into %i7; this means that before the "save" occurs, %o7
+ * contains the address of the call to mcount, and %i7 still contains
+ * the caller above that. The asm mcount here simply saves those
+ * registers in argument registers and branches to internal_mcount,
+ * simulating a call with arguments.
+ * Kludges:
+ * 1) the branch to internal_mcount is hard coded; it should be
+ * possible to tell asm to use the assembler-name of a symbol.
+ * 2) in theory, the function calling mcount could have saved %i7
+ * somewhere and reused the register; in practice, I *think* this will
+ * break longjmp (and maybe the debugger) but I'm not certain. (I take
+ * some comfort in the knowledge that it will break the native mcount
+ * as well.)
+ * 3) if builtin_return_address worked, this could be portable.
+ * However, it would really have to be optimized for arguments of 0
+ * and 1 and do something like what we have here in order to avoid the
+ * trap per function call performance hit.
+ * 4) the atexit and monsetup calls prevent this from simply
+ * being a leaf routine that doesn't do a "save" (and would thus have
+ * access to %o7 and %i7 directly) but the call to write() at the end
+ * would have also prevented this.
+ *
+ * -- [eichin:19920702.1107EST]
+ */
+
+/* i7 == last ret, -> frompcindex */
+/* o7 == current ret, -> selfpc */
+/* Solaris 2 libraries use _mcount. */
+asm(".global _mcount; _mcount: mov %i7,%o1; mov %o7,%o0;b,a internal_mcount");
+/* This is for compatibility with old versions of gcc which used mcount. */
+asm(".global mcount; mcount: mov %i7,%o1; mov %o7,%o0;b,a internal_mcount");
+
+static void internal_mcount(selfpc, frompcindex)
+ register char *selfpc;
+ register unsigned short *frompcindex;
+{
+ register struct tostruct *top;
+ register struct tostruct *prevtop;
+ register long toindex;
+ static char already_setup;
+
+ /*
+ * find the return address for mcount,
+ * and the return address for mcount's caller.
+ */
+
+ if(!already_setup) {
+ extern etext();
+ already_setup = 1;
+ monstartup(0, etext);
+#ifdef USE_ONEXIT
+ on_exit(_mcleanup, 0);
+#else
+ atexit(_mcleanup);
+#endif
+ }
+ /*
+ * check that we are profiling
+ * and that we aren't recursively invoked.
+ */
+ if (profiling) {
+ goto out;
+ }
+ profiling++;
+ /*
+ * check that frompcindex is a reasonable pc value.
+ * for example: signal catchers get called from the stack,
+ * not from text space. too bad.
+ */
+ frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
+ if ((unsigned long)frompcindex > s_textsize) {
+ goto done;
+ }
+ frompcindex =
+ &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
+ toindex = *frompcindex;
+ if (toindex == 0) {
+ /*
+ * first time traversing this arc
+ */
+ toindex = ++tos[0].link;
+ if (toindex >= tolimit) {
+ goto overflow;
+ }
+ *frompcindex = toindex;
+ top = &tos[toindex];
+ top->selfpc = selfpc;
+ top->count = 1;
+ top->link = 0;
+ goto done;
+ }
+ top = &tos[toindex];
+ if (top->selfpc == selfpc) {
+ /*
+ * arc at front of chain; usual case.
+ */
+ top->count++;
+ goto done;
+ }
+ /*
+ * have to go looking down chain for it.
+ * top points to what we are looking at,
+ * prevtop points to previous top.
+ * we know it is not at the head of the chain.
+ */
+ for (; /* goto done */; ) {
+ if (top->link == 0) {
+ /*
+ * top is end of the chain and none of the chain
+ * had top->selfpc == selfpc.
+ * so we allocate a new tostruct
+ * and link it to the head of the chain.
+ */
+ toindex = ++tos[0].link;
+ if (toindex >= tolimit) {
+ goto overflow;
+ }
+ top = &tos[toindex];
+ top->selfpc = selfpc;
+ top->count = 1;
+ top->link = *frompcindex;
+ *frompcindex = toindex;
+ goto done;
+ }
+ /*
+ * otherwise, check the next arc on the chain.
+ */
+ prevtop = top;
+ top = &tos[top->link];
+ if (top->selfpc == selfpc) {
+ /*
+ * there it is.
+ * increment its count
+ * move it to the head of the chain.
+ */
+ top->count++;
+ toindex = prevtop->link;
+ prevtop->link = top->link;
+ top->link = *frompcindex;
+ *frompcindex = toindex;
+ goto done;
+ }
+
+ }
+done:
+ profiling--;
+ /* and fall through */
+out:
+ return; /* normal return restores saved registers */
+
+overflow:
+ profiling++; /* halt further profiling */
+# define TOLIMIT "mcount: tos overflow\n"
+ write(2, TOLIMIT, sizeof(TOLIMIT));
+ goto out;
+}
+
+/*
+ * Control profiling
+ * profiling is what mcount checks to see if
+ * all the data structures are ready.
+ */
+static void moncontrol(mode)
+ int mode;
+{
+ if (mode) {
+ /* start */
+ profil((unsigned short *)(sbuf + sizeof(struct phdr)),
+ ssiz - sizeof(struct phdr),
+ (int)s_lowpc, s_scale);
+ profiling = 0;
+ } else {
+ /* stop */
+ profil((unsigned short *)0, 0, 0, 0);
+ profiling = 3;
+ }
+}
diff --git a/contrib/gcc/config/sparc/lb1spc.asm b/contrib/gcc/config/sparc/lb1spc.asm
new file mode 100644
index 0000000..831f33a
--- /dev/null
+++ b/contrib/gcc/config/sparc/lb1spc.asm
@@ -0,0 +1,784 @@
+/* This is an assembly language implementation of libgcc1.c for the sparc
+ processor.
+
+ These routines are derived from the Sparc Architecture Manual, version 8,
+ slightly edited to match the desired calling convention, and also to
+ optimize them for our purposes. */
+
+#ifdef L_mulsi3
+.text
+ .align 4
+ .global .umul
+ .proc 4
+.umul:
+ or %o0, %o1, %o4 ! logical or of multiplier and multiplicand
+ mov %o0, %y ! multiplier to Y register
+ andncc %o4, 0xfff, %o5 ! mask out lower 12 bits
+ be mul_shortway ! can do it the short way
+ andcc %g0, %g0, %o4 ! zero the partial product and clear NV cc
+ !
+ ! long multiply
+ !
+ mulscc %o4, %o1, %o4 ! first iteration of 33
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4 ! 32nd iteration
+ mulscc %o4, %g0, %o4 ! last iteration only shifts
+ ! the upper 32 bits of product are wrong, but we do not care
+ retl
+ rd %y, %o0
+ !
+ ! short multiply
+ !
+mul_shortway:
+ mulscc %o4, %o1, %o4 ! first iteration of 13
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4
+ mulscc %o4, %o1, %o4 ! 12th iteration
+ mulscc %o4, %g0, %o4 ! last iteration only shifts
+ rd %y, %o5
+ sll %o4, 12, %o4 ! left shift partial product by 12 bits
+ srl %o5, 20, %o5 ! right shift partial product by 20 bits
+ retl
+ or %o5, %o4, %o0 ! merge for true product
+#endif
+
+#ifdef L_divsi3
+/*
+ * Division and remainder, from Appendix E of the Sparc Version 8
+ * Architecture Manual, with fixes from Gordon Irlam.
+ */
+
+/*
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * m4 parameters:
+ * .div name of function to generate
+ * div div=div => %o0 / %o1; div=rem => %o0 % %o1
+ * true true=true => signed; true=false => unsigned
+ *
+ * Algorithm parameters:
+ * N how many bits per iteration we try to get (4)
+ * WORDSIZE total number of bits (32)
+ *
+ * Derived constants:
+ * TOPBITS number of bits in the top decade of a number
+ *
+ * Important variables:
+ * Q the partial quotient under development (initially 0)
+ * R the remainder so far, initially the dividend
+ * ITER number of main division loop iterations required;
+ * equal to ceil(log2(quotient) / N). Note that this
+ * is the log base (2^N) of the quotient.
+ * V the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ * Current estimate for non-large dividend is
+ * ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ * A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ * different path, as the upper bits of the quotient must be developed
+ * one bit at a time.
+ */
+ .global .udiv
+ .align 4
+ .proc 4
+ .text
+.udiv:
+ b ready_to_divide
+ mov 0, %g3 ! result is always positive
+
+ .global .div
+ .align 4
+ .proc 4
+ .text
+.div:
+ ! compute sign of result; if neither is negative, no problem
+ orcc %o1, %o0, %g0 ! either negative?
+ bge ready_to_divide ! no, go do the divide
+ xor %o1, %o0, %g3 ! compute sign in any case
+ tst %o1
+ bge 1f
+ tst %o0
+ ! %o1 is definitely negative; %o0 might also be negative
+ bge ready_to_divide ! if %o0 not negative...
+ sub %g0, %o1, %o1 ! in any case, make %o1 nonneg
+1: ! %o0 is negative, %o1 is nonnegative
+ sub %g0, %o0, %o0 ! make %o0 nonnegative
+
+
+ready_to_divide:
+
+ ! Ready to divide. Compute size of quotient; scale comparand.
+ orcc %o1, %g0, %o5
+ bne 1f
+ mov %o0, %o3
+
+ ! Divide by zero trap. If it returns, return 0 (about as
+ ! wrong as possible, but that is what SunOS does...).
+ ta 0x2 ! ST_DIV0
+ retl
+ clr %o0
+
+1:
+ cmp %o3, %o5 ! if %o1 exceeds %o0, done
+ blu got_result ! (and algorithm fails otherwise)
+ clr %o2
+ sethi %hi(1 << (32 - 4 - 1)), %g1
+ cmp %o3, %g1
+ blu not_really_big
+ clr %o4
+
+ ! Here the dividend is >= 2**(31-N) or so. We must be careful here,
+ ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+ ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+ ! Compute ITER in an unorthodox manner: know we need to shift V into
+ ! the top decade: so do not even bother to compare to R.
+ 1:
+ cmp %o5, %g1
+ bgeu 3f
+ mov 1, %g2
+ sll %o5, 4, %o5
+ b 1b
+ add %o4, 1, %o4
+
+ ! Now compute %g2.
+ 2: addcc %o5, %o5, %o5
+ bcc not_too_big
+ add %g2, 1, %g2
+
+ ! We get here if the %o1 overflowed while shifting.
+ ! This means that %o3 has the high-order bit set.
+ ! Restore %o5 and subtract from %o3.
+ sll %g1, 4, %g1 ! high order bit
+ srl %o5, 1, %o5 ! rest of %o5
+ add %o5, %g1, %o5
+ b do_single_div
+ sub %g2, 1, %g2
+
+ not_too_big:
+ 3: cmp %o5, %o3
+ blu 2b
+ nop
+ be do_single_div
+ nop
+ /* NB: these are commented out in the V8-Sparc manual as well */
+ /* (I do not understand this) */
+ ! %o5 > %o3: went too far: back up 1 step
+ ! srl %o5, 1, %o5
+ ! dec %g2
+ ! do single-bit divide steps
+ !
+ ! We have to be careful here. We know that %o3 >= %o5, so we can do the
+ ! first divide step without thinking. BUT, the others are conditional,
+ ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
+ ! order bit set in the first step, just falling into the regular
+ ! division loop will mess up the first time around.
+ ! So we unroll slightly...
+ do_single_div:
+ subcc %g2, 1, %g2
+ bl end_regular_divide
+ nop
+ sub %o3, %o5, %o3
+ mov 1, %o2
+ b end_single_divloop
+ nop
+ single_divloop:
+ sll %o2, 1, %o2
+ bl 1f
+ srl %o5, 1, %o5
+ ! %o3 >= 0
+ sub %o3, %o5, %o3
+ b 2f
+ add %o2, 1, %o2
+ 1: ! %o3 < 0
+ add %o3, %o5, %o3
+ sub %o2, 1, %o2
+ 2:
+ end_single_divloop:
+ subcc %g2, 1, %g2
+ bge single_divloop
+ tst %o3
+ b,a end_regular_divide
+
+not_really_big:
+1:
+ sll %o5, 4, %o5
+ cmp %o5, %o3
+ bleu 1b
+ addcc %o4, 1, %o4
+ be got_result
+ sub %o4, 1, %o4
+
+ tst %o3 ! set up for initial iteration
+divloop:
+ sll %o2, 4, %o2
+ ! depth 1, accumulated bits 0
+ bl L1.16
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 2, accumulated bits 1
+ bl L2.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 3
+ bl L3.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 7
+ bl L4.23
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2+1), %o2
+
+L4.23:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2-1), %o2
+
+
+L3.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 5
+ bl L4.21
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2+1), %o2
+
+L4.21:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2-1), %o2
+
+L2.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 1
+ bl L3.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 3
+ bl L4.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2+1), %o2
+
+L4.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2-1), %o2
+
+L3.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 1
+ bl L4.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2+1), %o2
+
+L4.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2-1), %o2
+
+L1.16:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 2, accumulated bits -1
+ bl L2.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -1
+ bl L3.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -1
+ bl L4.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2+1), %o2
+
+L4.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2-1), %o2
+
+L3.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -3
+ bl L4.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2+1), %o2
+
+L4.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2-1), %o2
+
+L2.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -3
+ bl L3.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -5
+ bl L4.11
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2+1), %o2
+
+L4.11:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2-1), %o2
+
+L3.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -7
+ bl L4.9
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2+1), %o2
+
+L4.9:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2-1), %o2
+
+ 9:
+end_regular_divide:
+ subcc %o4, 1, %o4
+ bge divloop
+ tst %o3
+ bl,a got_result
+ ! non-restoring fixup here (one instruction only!)
+ sub %o2, 1, %o2
+
+
+got_result:
+ ! check to see if answer should be < 0
+ tst %g3
+ bl,a 1f
+ sub %g0, %o2, %o2
+1:
+ retl
+ mov %o2, %o0
+#endif
+
+#ifdef L_modsi3
+/* This implementation was taken from glibc:
+ *
+ * Input: dividend and divisor in %o0 and %o1 respectively.
+ *
+ * Algorithm parameters:
+ * N how many bits per iteration we try to get (4)
+ * WORDSIZE total number of bits (32)
+ *
+ * Derived constants:
+ * TOPBITS number of bits in the top decade of a number
+ *
+ * Important variables:
+ * Q the partial quotient under development (initially 0)
+ * R the remainder so far, initially the dividend
+ * ITER number of main division loop iterations required;
+ * equal to ceil(log2(quotient) / N). Note that this
+ * is the log base (2^N) of the quotient.
+ * V the current comparand, initially divisor*2^(ITER*N-1)
+ *
+ * Cost:
+ * Current estimate for non-large dividend is
+ * ceil(log2(quotient) / N) * (10 + 7N/2) + C
+ * A large dividend is one greater than 2^(31-TOPBITS) and takes a
+ * different path, as the upper bits of the quotient must be developed
+ * one bit at a time.
+ */
+.text
+ .align 4
+ .global .urem
+ .proc 4
+.urem:
+ b divide
+ mov 0, %g3 ! result always positive
+
+ .align 4
+ .global .rem
+ .proc 4
+.rem:
+ ! compute sign of result; if neither is negative, no problem
+ orcc %o1, %o0, %g0 ! either negative?
+ bge 2f ! no, go do the divide
+ mov %o0, %g3 ! sign of remainder matches %o0
+ tst %o1
+ bge 1f
+ tst %o0
+ ! %o1 is definitely negative; %o0 might also be negative
+ bge 2f ! if %o0 not negative...
+ sub %g0, %o1, %o1 ! in any case, make %o1 nonneg
+1: ! %o0 is negative, %o1 is nonnegative
+ sub %g0, %o0, %o0 ! make %o0 nonnegative
+2:
+
+ ! Ready to divide. Compute size of quotient; scale comparand.
+divide:
+ orcc %o1, %g0, %o5
+ bne 1f
+ mov %o0, %o3
+
+ ! Divide by zero trap. If it returns, return 0 (about as
+ ! wrong as possible, but that is what SunOS does...).
+ ta 0x2 !ST_DIV0
+ retl
+ clr %o0
+
+1:
+ cmp %o3, %o5 ! if %o1 exceeds %o0, done
+ blu got_result ! (and algorithm fails otherwise)
+ clr %o2
+ sethi %hi(1 << (32 - 4 - 1)), %g1
+ cmp %o3, %g1
+ blu not_really_big
+ clr %o4
+
+ ! Here the dividend is >= 2**(31-N) or so. We must be careful here,
+ ! as our usual N-at-a-shot divide step will cause overflow and havoc.
+ ! The number of bits in the result here is N*ITER+SC, where SC <= N.
+ ! Compute ITER in an unorthodox manner: know we need to shift V into
+ ! the top decade: so do not even bother to compare to R.
+ 1:
+ cmp %o5, %g1
+ bgeu 3f
+ mov 1, %g2
+ sll %o5, 4, %o5
+ b 1b
+ add %o4, 1, %o4
+
+ ! Now compute %g2.
+ 2: addcc %o5, %o5, %o5
+ bcc not_too_big
+ add %g2, 1, %g2
+
+ ! We get here if the %o1 overflowed while shifting.
+ ! This means that %o3 has the high-order bit set.
+ ! Restore %o5 and subtract from %o3.
+ sll %g1, 4, %g1 ! high order bit
+ srl %o5, 1, %o5 ! rest of %o5
+ add %o5, %g1, %o5
+ b do_single_div
+ sub %g2, 1, %g2
+
+ not_too_big:
+ 3: cmp %o5, %o3
+ blu 2b
+ nop
+ be do_single_div
+ nop
+ /* NB: these are commented out in the V8-Sparc manual as well */
+ /* (I do not understand this) */
+ ! %o5 > %o3: went too far: back up 1 step
+ ! srl %o5, 1, %o5
+ ! dec %g2
+ ! do single-bit divide steps
+ !
+ ! We have to be careful here. We know that %o3 >= %o5, so we can do the
+ ! first divide step without thinking. BUT, the others are conditional,
+ ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high-
+ ! order bit set in the first step, just falling into the regular
+ ! division loop will mess up the first time around.
+ ! So we unroll slightly...
+ do_single_div:
+ subcc %g2, 1, %g2
+ bl end_regular_divide
+ nop
+ sub %o3, %o5, %o3
+ mov 1, %o2
+ b end_single_divloop
+ nop
+ single_divloop:
+ sll %o2, 1, %o2
+ bl 1f
+ srl %o5, 1, %o5
+ ! %o3 >= 0
+ sub %o3, %o5, %o3
+ b 2f
+ add %o2, 1, %o2
+ 1: ! %o3 < 0
+ add %o3, %o5, %o3
+ sub %o2, 1, %o2
+ 2:
+ end_single_divloop:
+ subcc %g2, 1, %g2
+ bge single_divloop
+ tst %o3
+ b,a end_regular_divide
+
+not_really_big:
+1:
+ sll %o5, 4, %o5
+ cmp %o5, %o3
+ bleu 1b
+ addcc %o4, 1, %o4
+ be got_result
+ sub %o4, 1, %o4
+
+ tst %o3 ! set up for initial iteration
+divloop:
+ sll %o2, 4, %o2
+ ! depth 1, accumulated bits 0
+ bl L1.16
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 2, accumulated bits 1
+ bl L2.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 3
+ bl L3.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 7
+ bl L4.23
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2+1), %o2
+L4.23:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (7*2-1), %o2
+
+L3.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 5
+ bl L4.21
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2+1), %o2
+
+L4.21:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (5*2-1), %o2
+
+L2.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits 1
+ bl L3.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 3
+ bl L4.19
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2+1), %o2
+
+L4.19:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (3*2-1), %o2
+
+L3.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits 1
+ bl L4.17
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2+1), %o2
+
+L4.17:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (1*2-1), %o2
+
+L1.16:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 2, accumulated bits -1
+ bl L2.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -1
+ bl L3.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -1
+ bl L4.15
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2+1), %o2
+
+L4.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-1*2-1), %o2
+
+L3.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -3
+ bl L4.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2+1), %o2
+
+L4.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-3*2-1), %o2
+
+L2.15:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 3, accumulated bits -3
+ bl L3.13
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -5
+ bl L4.11
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2+1), %o2
+
+L4.11:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-5*2-1), %o2
+
+L3.13:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ ! depth 4, accumulated bits -7
+ bl L4.9
+ srl %o5,1,%o5
+ ! remainder is positive
+ subcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2+1), %o2
+
+L4.9:
+ ! remainder is negative
+ addcc %o3,%o5,%o3
+ b 9f
+ add %o2, (-7*2-1), %o2
+
+ 9:
+end_regular_divide:
+ subcc %o4, 1, %o4
+ bge divloop
+ tst %o3
+ bl,a got_result
+ ! non-restoring fixup here (one instruction only!)
+ add %o3, %o1, %o3
+
+got_result:
+ ! check to see if answer should be < 0
+ tst %g3
+ bl,a 1f
+ sub %g0, %o3, %o3
+1:
+ retl
+ mov %o3, %o0
+
+#endif
+
diff --git a/contrib/gcc/config/sparc/lb1spl.asm b/contrib/gcc/config/sparc/lb1spl.asm
new file mode 100644
index 0000000..4c8bc30
--- /dev/null
+++ b/contrib/gcc/config/sparc/lb1spl.asm
@@ -0,0 +1,246 @@
+/* This is an assembly language implementation of libgcc1.c for the sparclite
+ processor.
+
+ These routines are all from the Sparclite User's Guide, slightly edited
+ to match the desired calling convention, and also to optimize them. */
+
+#ifdef L_udivsi3
+.text
+ .align 4
+ .global .udiv
+ .proc 04
+.udiv:
+ wr %g0,%g0,%y ! Not a delayed write for sparclite
+ tst %g0
+ divscc %o0,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ retl
+ divscc %g1,%o1,%o0
+#endif
+
+#ifdef L_umodsi3
+.text
+ .align 4
+ .global .urem
+ .proc 04
+.urem:
+ wr %g0,%g0,%y ! Not a delayed write for sparclite
+ tst %g0
+ divscc %o0,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ divscc %g1,%o1,%g1
+ bl 1f
+ rd %y,%o0
+ retl
+ nop
+1: retl
+ add %o0,%o1,%o0
+#endif
+
+#ifdef L_divsi3
+.text
+ .align 4
+ .global .div
+ .proc 04
+! ??? This routine could be made faster if was optimized, and if it was
+! rewritten to only calculate the quotient.
+.div:
+ wr %g0,%g0,%y ! Not a delayed write for sparclite
+ mov %o1,%o4
+ tst %o1
+ bl,a 1f
+ sub %g0,%o4,%o4
+1: tst %o0
+ bl,a 2f
+ mov -1,%y
+2: divscc %o0,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ be 6f
+ mov %y,%o3
+ bg 4f
+ addcc %o3,%o4,%g0
+ be,a 6f
+ mov %g0,%o3
+ tst %o0
+ bl 5f
+ tst %g1
+ ba 5f
+ add %o3,%o4,%o3
+4: subcc %o3,%o4,%g0
+ be,a 6f
+ mov %g0,%o3
+ tst %o0
+ bge 5f
+ tst %g1
+ sub %o3,%o4,%o3
+5: bl,a 6f
+ add %g1,1,%g1
+6: tst %o1
+ bl,a 7f
+ sub %g0,%g1,%g1
+7: retl
+ mov %g1,%o0 ! Quotient is in %g1.
+#endif
+
+#ifdef L_modsi3
+.text
+ .align 4
+ .global .rem
+ .proc 04
+! ??? This routine could be made faster if was optimized, and if it was
+! rewritten to only calculate the remainder.
+.rem:
+ wr %g0,%g0,%y ! Not a delayed write for sparclite
+ mov %o1,%o4
+ tst %o1
+ bl,a 1f
+ sub %g0,%o4,%o4
+1: tst %o0
+ bl,a 2f
+ mov -1,%y
+2: divscc %o0,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ divscc %g1,%o4,%g1
+ be 6f
+ mov %y,%o3
+ bg 4f
+ addcc %o3,%o4,%g0
+ be,a 6f
+ mov %g0,%o3
+ tst %o0
+ bl 5f
+ tst %g1
+ ba 5f
+ add %o3,%o4,%o3
+4: subcc %o3,%o4,%g0
+ be,a 6f
+ mov %g0,%o3
+ tst %o0
+ bge 5f
+ tst %g1
+ sub %o3,%o4,%o3
+5: bl,a 6f
+ add %g1,1,%g1
+6: tst %o1
+ bl,a 7f
+ sub %g0,%g1,%g1
+7: retl
+ mov %o3,%o0 ! Remainder is in %o3.
+#endif
diff --git a/contrib/gcc/config/sparc/linux-aout.h b/contrib/gcc/config/sparc/linux-aout.h
new file mode 100644
index 0000000..76d7653
--- /dev/null
+++ b/contrib/gcc/config/sparc/linux-aout.h
@@ -0,0 +1,130 @@
+/* Definitions for SPARC running Linux-based GNU systems with a.out.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Eddie C. Dost (ecd@skynet.be)
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <aoutos.h>
+#include <sparc/sparc.h>
+
+/* Don't assume anything about the header files. */
+#define NO_IMPLICIT_EXTERN_C
+
+#undef HAVE_ATEXIT
+#define HAVE_ATEXIT
+
+/* GNU/Linux uses ctype from glibc.a. I am not sure how complete it is.
+ For now, we play safe. It may change later. */
+
+#if 0
+#undef MULTIBYTE_CHARS
+#define MULTIBYTE_CHARS 1
+#endif
+
+/* We need that too. */
+#define HANDLE_SYSV_PRAGMA
+
+#undef MD_EXEC_PREFIX
+#undef MD_STARTFILE_PREFIX
+
+/* Output at beginning of assembler file. */
+/* The .file command should always begin the output. */
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+ do { \
+ output_file_directive (FILE, main_input_filename); \
+ fprintf (FILE, "\t.version\t\"01.01\"\n"); \
+ } while (0)
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{pg:gcrt0.o%s} %{!pg:%{p:gcrt0.o%s} %{!p:crt0.o%s}} %{static:-static}"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (sparc GNU/Linux with a.out)");
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dunix -Dsparc -Dlinux -Asystem(unix) -Asystem(posix)"
+
+#undef CPP_SUBTARGET_SPEC
+#define CPP_SUBTARGET_SPEC \
+"%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}"
+
+/* Don't default to pcc-struct-return, because gcc is the only compiler,
+ and we want to retain compatibility with older gcc versions. */
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+#undef LIB_SPEC
+
+#if 1
+/* We no longer link with libc_p.a or libg.a by default. If you
+ want to profile or debug the GNU/Linux C library, please add
+ -lc_p or -ggdb to LDFLAGS at the link time, respectively. */
+#define LIB_SPEC \
+"%{mieee-fp:-lieee} %{p:-lgmon} %{pg:-lgmon} %{!ggdb:-lc} %{ggdb:-lg}"
+#else
+#define LIB_SPEC \
+"%{mieee-fp:-lieee} %{p:-lgmon -lc_p} %{pg:-lgmon -lc_p} \
+ %{!p:%{!pg:%{!g*:-lc} %{g*:-lg -static}}}"
+#endif
+
+#undef LINK_SPEC
+#define LINK_SPEC "-m sparclinux"
+
+/* The sun bundled assembler doesn't accept -Yd, (and neither does gas).
+ It's safe to pass -s always, even if -g is not used. */
+#undef ASM_SPEC
+#define ASM_SPEC \
+ "%{V} %{v:%{!V:-V}} %{n} %{T} %{Ym,*} %{Wa,*:%*} -s %{fpic:-K PIC} %{fPIC:-K PIC}"
+
+#if 0
+/* Define for support of TFmode long double and REAL_ARITHMETIC.
+ Sparc ABI says that long double is 4 words. GNU/Linux does not support
+ long double yet. */
+#define LONG_DOUBLE_TYPE_SIZE 128
+#endif
+
+/* Override MACHINE_STATE_{SAVE,RESTORE} because we have special
+ traps available which can get and set the condition codes
+ reliably. */
+#undef MACHINE_STATE_SAVE
+#define MACHINE_STATE_SAVE(ID) \
+ unsigned long int ms_flags, ms_saveret; \
+ asm volatile("ta 0x20\n\t" \
+ "mov %%g1, %0\n\t" \
+ "mov %%g2, %1\n\t" \
+ : "=r" (ms_flags), "=r" (ms_saveret));
+
+#undef MACHINE_STATE_RESTORE
+#define MACHINE_STATE_RESTORE(ID) \
+ asm volatile("mov %0, %%g1\n\t" \
+ "mov %1, %%g2\n\t" \
+ "ta 0x21\n\t" \
+ : /* no outputs */ \
+ : "r" (ms_flags), "r" (ms_saveret));
diff --git a/contrib/gcc/config/sparc/linux.h b/contrib/gcc/config/sparc/linux.h
new file mode 100644
index 0000000..7bbbfa4
--- /dev/null
+++ b/contrib/gcc/config/sparc/linux.h
@@ -0,0 +1,259 @@
+/* Definitions for SPARC running Linux-based GNU systems with ELF.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Eddie C. Dost (ecd@skynet.be)
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#define LINUX_DEFAULT_ELF
+
+/* Don't assume anything about the header files. */
+#define NO_IMPLICIT_EXTERN_C
+
+#undef HAVE_ATEXIT
+#define HAVE_ATEXIT
+
+/* GNU/Linux uses ctype from glibc.a. I am not sure how complete it is.
+ For now, we play safe. It may change later. */
+
+#if 0
+#undef MULTIBYTE_CHARS
+#define MULTIBYTE_CHARS 1
+#endif
+
+#ifndef USE_GNULIBC_1
+#undef DEFAULT_VTABLE_THUNKS
+#define DEFAULT_VTABLE_THUNKS 1
+#endif
+
+/* Use stabs instead of DWARF debug format. */
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+#include <sparc/sysv4.h>
+
+#undef MD_EXEC_PREFIX
+#undef MD_STARTFILE_PREFIX
+
+/* Output at beginning of assembler file. */
+/* The .file command should always begin the output. */
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+ do { \
+ output_file_directive (FILE, main_input_filename); \
+ fprintf (FILE, "\t.version\t\"01.01\"\n"); \
+ } while (0)
+
+/* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add
+ the GNU/Linux magical crtbegin.o file (see crtstuff.c) which
+ provides part of the support for getting C++ file-scope static
+ object constructed before entering `main'. */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "%{!shared: \
+ %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}}\
+ crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}"
+
+/* Provide a ENDFILE_SPEC appropriate for GNU/Linux. Here we tack on
+ the GNU/Linux magical crtend.o file (see crtstuff.c) which
+ provides part of the support for getting C++ file-scope static
+ object constructed before entering `main', followed by a normal
+ GNU/Linux "finalizer" file, `crtn.o'. */
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s"
+
+/* This is for -profile to use -lc_p instead of -lc. */
+#undef CC1_SPEC
+#define CC1_SPEC "%{profile:-p} \
+%{sun4:} %{target:} \
+%{mcypress:-mcpu=cypress} \
+%{msparclite:-mcpu=sparclite} %{mf930:-mcpu=f930} %{mf934:-mcpu=f934} \
+%{mv8:-mcpu=v8} %{msupersparc:-mcpu=supersparc} \
+"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (sparc GNU/Linux with ELF)");
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-D__ELF__ -Dunix -Dsparc -D__sparc__ -Dlinux -Asystem(unix) -Asystem(posix)"
+
+#undef CPP_SUBTARGET_SPEC
+#ifdef USE_GNULIBC_1
+#define CPP_SUBTARGET_SPEC \
+"%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE}"
+#else
+#define CPP_SUBTARGET_SPEC \
+"%{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
+#endif
+
+#undef LIB_SPEC
+/* We no longer link with libc_p.a or libg.a by default. If you
+ want to profile or debug the GNU/Linux C library, please add
+ -lc_p or -ggdb to LDFLAGS at the link time, respectively. */
+#if 1
+#ifdef USE_GNULIBC_1
+#define LIB_SPEC \
+ "%{!shared: %{p:-lgmon} %{pg:-lgmon} %{profile:-lgmon -lc_p} \
+ %{!profile:%{!ggdb:-lc} %{ggdb:-lg}}}"
+#else
+#define LIB_SPEC \
+ "%{shared: -lc} \
+ %{!shared: %{mieee-fp:-lieee} %{pthread:-lpthread} \
+ %{profile:-lc_p} %{!profile: -lc}}"
+#endif
+#else
+#define LIB_SPEC \
+ "%{!shared: \
+ %{mieee-fp:-lieee} %{p:-lgmon -lc_p} %{pg:-lgmon -lc_p} \
+ %{!p:%{!pg:%{!g*:-lc} %{g*:-lg}}}}"
+#endif
+
+/* Provide a LINK_SPEC appropriate for GNU/Linux. Here we provide support
+ for the special GCC options -static and -shared, which allow us to
+ link things in one of these three modes by applying the appropriate
+ combinations of options at link-time. We like to support here for
+ as many of the other GNU linker options as possible. But I don't
+ have the time to search for those flags. I am sure how to add
+ support for -soname shared_object_name. H.J.
+
+ I took out %{v:%{!V:-V}}. It is too much :-(. They can use
+ -Wl,-V.
+
+ When the -shared link option is used a final link is not being
+ done. */
+
+/* If ELF is the default format, we should not use /lib/elf. */
+
+#undef LINK_SPEC
+#ifdef USE_GNULIBC_1
+#ifndef LINUX_DEFAULT_ELF
+#define LINK_SPEC "-m elf32_sparc -Y P,/usr/lib %{shared:-shared} \
+ %{!shared: \
+ %{!ibcs: \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /lib/elf/ld-linux.so.1} \
+ %{!rpath:-rpath /lib/elf/}} %{static:-static}}}"
+#else
+#define LINK_SPEC "-m elf32_sparc -Y P,/usr/lib %{shared:-shared} \
+ %{!shared: \
+ %{!ibcs: \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.1}} \
+ %{static:-static}}}"
+#endif
+#else
+#define LINK_SPEC "-m elf32_sparc -Y P,/usr/lib %{shared:-shared} \
+ %{!shared: \
+ %{!ibcs: \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2}} \
+ %{static:-static}}}"
+#endif
+
+/* The sun bundled assembler doesn't accept -Yd, (and neither does gas).
+ It's safe to pass -s always, even if -g is not used. */
+#undef ASM_SPEC
+#define ASM_SPEC \
+ "%{V} %{v:%{!V:-V}} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Wa,*:%*} -s %{fpic:-K PIC} %{fPIC:-K PIC}"
+
+/* Same as sparc.h */
+#undef DBX_REGISTER_NUMBER
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+/* We use stabs-in-elf for debugging, because that is what the native
+ toolchain uses. XXX */
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+do { \
+ fputs ("\t.local\t", (FILE)); \
+ assemble_name ((FILE), (NAME)); \
+ putc ('\n', (FILE)); \
+ ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN); \
+} while (0)
+
+#undef COMMON_ASM_OP
+#define COMMON_ASM_OP "\t.common"
+
+/* This is how to output a definition of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#undef ASM_OUTPUT_INTERNAL_LABEL
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
+ fprintf (FILE, ".L%s%d:\n", PREFIX, NUM)
+
+/* This is how to output a reference to an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#undef ASM_OUTPUT_INTERNAL_LABELREF
+#define ASM_OUTPUT_INTERNAL_LABELREF(FILE,PREFIX,NUM) \
+ fprintf (FILE, ".L%s%d", PREFIX, NUM)
+
+/* This is how to store into the string LABEL
+ the symbol_ref name of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class.
+ This is suitable for output with `assemble_name'. */
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf (LABEL, "*.L%s%d", PREFIX, NUM)
+
+
+#if 0
+/* Define for support of TFmode long double and REAL_ARITHMETIC.
+ Sparc ABI says that long double is 4 words. GNU/Linux does not support
+ long double yet. */
+#define LONG_DOUBLE_TYPE_SIZE 128
+#endif
+
+/* Override MACHINE_STATE_{SAVE,RESTORE} because we have special
+ traps available which can get and set the condition codes
+ reliably. */
+#undef MACHINE_STATE_SAVE
+#define MACHINE_STATE_SAVE(ID) \
+ unsigned long int ms_flags, ms_saveret; \
+ asm volatile("ta 0x20\n\t" \
+ "mov %%g1, %0\n\t" \
+ "mov %%g2, %1\n\t" \
+ : "=r" (ms_flags), "=r" (ms_saveret));
+
+#undef MACHINE_STATE_RESTORE
+#define MACHINE_STATE_RESTORE(ID) \
+ asm volatile("mov %0, %%g1\n\t" \
+ "mov %1, %%g2\n\t" \
+ "ta 0x21\n\t" \
+ : /* no outputs */ \
+ : "r" (ms_flags), "r" (ms_saveret));
diff --git a/contrib/gcc/config/sparc/linux64.h b/contrib/gcc/config/sparc/linux64.h
new file mode 100644
index 0000000..77bc668
--- /dev/null
+++ b/contrib/gcc/config/sparc/linux64.h
@@ -0,0 +1,245 @@
+/* Definitions for 64-bit SPARC running Linux-based GNU systems with ELF.
+ Copyright 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by David S. Miller (davem@caip.rutgers.edu)
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* ??? bi-architecture support will require changes to the linker
+ related specs, among perhaps other things (multilibs). */
+/* #define SPARC_BI_ARCH */
+
+#define LINUX_DEFAULT_ELF
+
+/* Don't assume anything about the header files. */
+#define NO_IMPLICIT_EXTERN_C
+
+#undef HAVE_ATEXIT
+#define HAVE_ATEXIT
+
+#include <sparc/sysv4.h>
+
+#undef MD_EXEC_PREFIX
+#undef MD_STARTFILE_PREFIX
+
+/* Output at beginning of assembler file. */
+/* The .file command should always begin the output. */
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE) \
+ do { \
+ output_file_directive (FILE, main_input_filename); \
+ fprintf (FILE, "\t.version\t\"01.01\"\n"); \
+ } while (0)
+
+#undef ASM_CPU_DEFAULT_SPEC
+#define ASM_CPU_DEFAULT_SPEC "-Av9a"
+
+/* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add
+ the GNU/Linux magical crtbegin.o file (see crtstuff.c) which
+ provides part of the support for getting C++ file-scope static
+ object constructed before entering `main'. */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+ "%{!shared: \
+ %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}}\
+ crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}"
+
+/* Provide a ENDFILE_SPEC appropriate for GNU/Linux. Here we tack on
+ the GNU/Linux magical crtend.o file (see crtstuff.c) which
+ provides part of the support for getting C++ file-scope static
+ object constructed before entering `main', followed by a normal
+ GNU/Linux "finalizer" file, `crtn.o'. */
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (sparc64 GNU/Linux with ELF)");
+
+/* A 64 bit v9 compiler with stack-bias,
+ in a Medium/Anywhere code model environment. */
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT \
+ (MASK_V9 + MASK_PTR64 + MASK_64BIT /* + MASK_HARD_QUAD */ \
+ + MASK_STACK_BIAS + MASK_APP_REGS + MASK_EPILOGUE + MASK_FPU)
+
+/* The default code model. */
+#undef SPARC_DEFAULT_CMODEL
+#define SPARC_DEFAULT_CMODEL CM_MEDANY
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+#undef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE 128
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-D__ELF__ -Dunix -D_LONGLONG -Dsparc -D__sparc__ -Dlinux -Asystem(unix) -Asystem(posix)"
+
+#undef CPP_SUBTARGET_SPEC
+#define CPP_SUBTARGET_SPEC "\
+%{fPIC:-D__PIC__ -D__pic__} \
+%{fpic:-D__PIC__ -D__pic__} \
+%{posix:-D_POSIX_SOURCE} \
+%{pthread:-D_REENTRANT} \
+"
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+ "%{shared: -lc} \
+ %{!shared: %{mieee-fp:-lieee} %{pthread:-lpthread} \
+ %{profile:-lc_p} %{!profile: -lc}}"
+
+/* Provide a LINK_SPEC appropriate for GNU/Linux. Here we provide support
+ for the special GCC options -static and -shared, which allow us to
+ link things in one of these three modes by applying the appropriate
+ combinations of options at link-time. We like to support here for
+ as many of the other GNU linker options as possible. But I don't
+ have the time to search for those flags. I am sure how to add
+ support for -soname shared_object_name. H.J.
+
+ I took out %{v:%{!V:-V}}. It is too much :-(. They can use
+ -Wl,-V.
+
+ When the -shared link option is used a final link is not being
+ done. */
+
+/* If ELF is the default format, we should not use /lib/elf. */
+
+#undef LINK_SPEC
+#define LINK_SPEC "-m elf64_sparc -Y P,/usr/lib %{shared:-shared} \
+ %{!shared: \
+ %{!ibcs: \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker /lib/ld-linux64.so.2}} \
+ %{static:-static}}} \
+%{mlittle-endian:-EL} \
+"
+
+/* The sun bundled assembler doesn't accept -Yd, (and neither does gas).
+ It's safe to pass -s always, even if -g is not used. */
+#undef ASM_SPEC
+#define ASM_SPEC "\
+%{V} \
+%{v:%{!V:-V}} \
+%{!Qn:-Qy} \
+%{n} \
+%{T} \
+%{Ym,*} \
+%{Wa,*:%*} \
+-s %{fpic:-K PIC} %{fPIC:-K PIC} \
+%{mlittle-endian:-EL} \
+%(asm_cpu) %(asm_arch) \
+"
+
+/* Same as sparc.h */
+#undef DBX_REGISTER_NUMBER
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+/* System V Release 4 uses DWARF debugging info. Buf DWARF1 doesn't do
+ 64-bit anything, so we use DWARF2. */
+
+#undef DWARF2_DEBUGGING_INFO
+#undef DWARF_DEBUGGING_INFO
+#undef DBX_DEBUGGING_INFO
+#define DWARF2_DEBUGGING_INFO
+#define DBX_DEBUGGING_INFO
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+do { \
+ fputs ("\t.local\t", (FILE)); \
+ assemble_name ((FILE), (NAME)); \
+ putc ('\n', (FILE)); \
+ ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN); \
+} while (0)
+
+#undef COMMON_ASM_OP
+#define COMMON_ASM_OP "\t.common"
+
+/* This is how to output a definition of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#undef ASM_OUTPUT_INTERNAL_LABEL
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
+ fprintf (FILE, ".L%s%d:\n", PREFIX, NUM)
+
+/* This is how to output a reference to an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#undef ASM_OUTPUT_INTERNAL_LABELREF
+#define ASM_OUTPUT_INTERNAL_LABELREF(FILE,PREFIX,NUM) \
+ fprintf (FILE, ".L%s%d", PREFIX, NUM)
+
+/* This is how to store into the string LABEL
+ the symbol_ref name of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class.
+ This is suitable for output with `assemble_name'. */
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf (LABEL, "*.L%s%d", PREFIX, NUM)
+
+/* Stabs doesn't use this, and it confuses a simulator. */
+/* ??? Need to see what DWARF needs, if anything. */
+#undef ASM_IDENTIFY_GCC
+#define ASM_IDENTIFY_GCC(FILE)
+
+/* Define the names of various pseudo-ops used by the Sparc/svr4 assembler.
+ ??? If ints are 64 bits then UNALIGNED_INT_ASM_OP (defined elsewhere) is
+ misnamed. These should all refer to explicit sizes (half/word/xword?),
+ anything other than short/int/long/etc. */
+
+#define UNALIGNED_DOUBLE_INT_ASM_OP ".uaxword"
+
+/* DWARF bits. */
+
+/* Follow Irix 6 and not the Dwarf2 draft in using 64-bit offsets.
+ Obviously the Dwarf2 folks havn't tried to actually build systems
+ with their spec. On a 64-bit system, only 64-bit relocs become
+ RELATIVE relocations. */
+
+/* #define DWARF_OFFSET_SIZE PTR_SIZE */
+
+/* Override MACHINE_STATE_{SAVE,RESTORE} because we have special
+ traps available which can get and set the condition codes
+ reliably. */
+#undef MACHINE_STATE_SAVE
+#define MACHINE_STATE_SAVE(ID) \
+ unsigned long int ms_flags, ms_saveret; \
+ asm volatile("ta 0x20\n\t" \
+ "mov %%g1, %0\n\t" \
+ "mov %%g2, %1\n\t" \
+ : "=r" (ms_flags), "=r" (ms_saveret));
+
+#undef MACHINE_STATE_RESTORE
+#define MACHINE_STATE_RESTORE(ID) \
+ asm volatile("mov %0, %%g1\n\t" \
+ "mov %1, %%g2\n\t" \
+ "ta 0x21\n\t" \
+ : /* no outputs */ \
+ : "r" (ms_flags), "r" (ms_saveret));
diff --git a/contrib/gcc/config/sparc/lite.h b/contrib/gcc/config/sparc/lite.h
new file mode 100644
index 0000000..55c232a
--- /dev/null
+++ b/contrib/gcc/config/sparc/lite.h
@@ -0,0 +1,38 @@
+/* Definitions of target machine for GNU compiler, for SPARClite w/o FPU.
+ Copyright (C) 1993, 1996 Free Software Foundation, Inc.
+ Contributed by Jim Wilson (wilson@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "sparc/sparc.h"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dsparc -Dsparclite -Acpu(sparc) -Amachine(sparc)"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (sparclite)");
+
+/* Enable app-regs and epilogue options. Do not enable the fpu. */
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_APP_REGS + MASK_EPILOGUE)
+
+/* US Software GOFAST library support. */
+#include "gofast.h"
+#undef INIT_SUBTARGET_OPTABS
+#define INIT_SUBTARGET_OPTABS INIT_GOFAST_OPTABS
diff --git a/contrib/gcc/config/sparc/litecoff.h b/contrib/gcc/config/sparc/litecoff.h
new file mode 100644
index 0000000..bd89e1b
--- /dev/null
+++ b/contrib/gcc/config/sparc/litecoff.h
@@ -0,0 +1,113 @@
+/* Definitions of target machine for GNU compiler, for SPARClite w/o FPU, COFF.
+ Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ Written by Ken Raeburn (raeburn@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "sparc/lite.h"
+
+#undef ASM_OUTPUT_IDENT
+
+#undef SELECT_SECTION
+#undef SELECT_RTX_SECTION
+#define BSS_SECTION_ASM_OP ".section\t\".bss\""
+
+#include "svr3.h"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dsparc -Dsparclite -Acpu(sparc) -Amachine(sparc)"
+
+/* Default to stabs in COFF. */
+
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+#include "dbxcoff.h"
+
+/* Support the ctors and dtors sections for g++. */
+
+#undef INIT_SECTION_ASM_OP
+
+/* Support the ctors and dtors sections for g++. */
+
+#undef CTORS_SECTION_ASM_OP
+#define CTORS_SECTION_ASM_OP ".section\t.ctors,\"x\""
+#undef DTORS_SECTION_ASM_OP
+#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"x\""
+
+/* A list of other sections which the compiler might be "in" at any
+ given time. */
+
+#undef EXTRA_SECTIONS
+#define EXTRA_SECTIONS in_const, in_ctors, in_dtors
+
+/* A list of extra section function definitions. */
+
+#undef EXTRA_SECTION_FUNCTIONS
+#define EXTRA_SECTION_FUNCTIONS \
+ CONST_SECTION_FUNCTION \
+ CTORS_SECTION_FUNCTION \
+ DTORS_SECTION_FUNCTION
+
+#define CTORS_SECTION_FUNCTION \
+void \
+ctors_section () \
+{ \
+ if (in_section != in_ctors) \
+ { \
+ fprintf (asm_out_file, "%s\n", CTORS_SECTION_ASM_OP); \
+ in_section = in_ctors; \
+ } \
+}
+
+#define DTORS_SECTION_FUNCTION \
+void \
+dtors_section () \
+{ \
+ if (in_section != in_dtors) \
+ { \
+ fprintf (asm_out_file, "%s\n", DTORS_SECTION_ASM_OP); \
+ in_section = in_dtors; \
+ } \
+}
+
+#define INT_ASM_OP ".long"
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global constructors. */
+#undef ASM_OUTPUT_CONSTRUCTOR
+#define ASM_OUTPUT_CONSTRUCTOR(FILE,NAME) \
+ do { \
+ ctors_section (); \
+ fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+/* A C statement (sans semicolon) to output an element in the table of
+ global destructors. */
+#undef ASM_OUTPUT_DESTRUCTOR
+#define ASM_OUTPUT_DESTRUCTOR(FILE,NAME) \
+ do { \
+ dtors_section (); \
+ fprintf (FILE, "\t%s\t ", INT_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+#undef DO_GLOBAL_CTORS_BODY
+#undef DO_GLOBAL_DTORS_BODY
diff --git a/contrib/gcc/config/sparc/lynx-ng.h b/contrib/gcc/config/sparc/lynx-ng.h
new file mode 100644
index 0000000..9e9f82c
--- /dev/null
+++ b/contrib/gcc/config/sparc/lynx-ng.h
@@ -0,0 +1,41 @@
+/* Definitions for SPARC running LynxOS, using Lynx's old as and ld.
+ Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <sparc/sparc.h>
+#include <lynx-ng.h>
+
+/* ??? Must redefine to get sparclite and v8 defines. Can this be done
+ differently? */
+
+#undef CPP_SPEC
+#define CPP_SPEC "%{mthreads:-D_MULTITHREADED} \
+ %{mposix:-D_POSIX_SOURCE} \
+ %{msystem-v:-I/usr/include_v} \
+ %(cpp_cpu)"
+
+/* Names to predefine in the preprocessor for this target machine. */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dunix -Dsparc -DLynx -DIBITS32 -Asystem(unix) -Asystem(lynx) -Acpu(sparc) -Amachine(sparc)"
+
+/* Provide required defaults for linker switches. */
+
+#undef LINK_SPEC
+#define LINK_SPEC "-e __main -T 0 %{msystem-v:-V} %{mcoff:-k}"
diff --git a/contrib/gcc/config/sparc/lynx.h b/contrib/gcc/config/sparc/lynx.h
new file mode 100644
index 0000000..99b319a
--- /dev/null
+++ b/contrib/gcc/config/sparc/lynx.h
@@ -0,0 +1,53 @@
+/* Definitions for SPARC running LynxOS.
+ Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <sparc/sparc.h>
+
+#undef ASM_OUTPUT_IDENT
+#undef SELECT_SECTION
+#undef SELECT_RTX_SECTION
+
+#define BSS_SECTION_ASM_OP ".section\t\".bss\""
+
+#include <lynx.h>
+
+/* ??? Must redefine to get sparclite and v8 defines. Can this be done
+ differently? */
+
+#undef CPP_SPEC
+#define CPP_SPEC "%{mthreads:-D_MULTITHREADED} \
+ %{mposix:-D_POSIX_SOURCE} \
+ %{msystem-v:-I/usr/include_v} \
+ %(cpp_cpu)"
+
+/* Names to predefine in the preprocessor for this target machine. */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dunix -Dsparc -DSPARC -DLynx -DLYNX -DIBITS32 -Asystem(unix) -Asystem(lynx) -Acpu(sparc) -Amachine(sparc)"
+
+#undef LINK_SPEC
+
+/* Sparc version of libc.a has references to libm.a (printf calls pow for
+ instance), so we must always link both. */
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{mthreads:-L/lib/thread/} \
+ %{msystem-v:-lc_v -lm_v -lc_v} \
+ %{!msystem-v:%{mposix:-lc_p} -lc -lm -lc}"
diff --git a/contrib/gcc/config/sparc/netbsd.h b/contrib/gcc/config/sparc/netbsd.h
new file mode 100644
index 0000000..a512f41
--- /dev/null
+++ b/contrib/gcc/config/sparc/netbsd.h
@@ -0,0 +1,46 @@
+#include <sparc/sparc.h>
+
+/* Get generic NetBSD definitions. */
+
+#include <netbsd.h>
+
+/* Names to predefine in the preprocessor for this target machine. */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dunix -Dsparc -D__NetBSD__ -Asystem(unix) -Asystem(NetBSD) -Acpu(sparc) -Amachine(sparc)"
+
+/* Make gcc agree with <machine/ansi.h> */
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+
+#undef WCHAR_UNSIGNED
+#define WCHAR_UNSIGNED 0
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 32
+
+/* This is BSD, so it wants DBX format. */
+
+#define DBX_DEBUGGING_INFO
+
+/* This is the char to use for continuation (in case we need to turn
+ continuation back on). */
+
+#define DBX_CONTIN_CHAR '?'
+
+/* Don't default to pcc-struct-return, because gcc is the only compiler, and
+ we want to retain compatibility with older gcc versions. */
+#undef DEFAULT_PCC_STRUCT_RETURN
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* Until they use ELF or something that handles dwarf2 unwinds
+ and initialization stuff better. */
+#define DWARF2_UNWIND_INFO 0
+
diff --git a/contrib/gcc/config/sparc/openbsd.h b/contrib/gcc/config/sparc/openbsd.h
new file mode 100644
index 0000000..19ece97
--- /dev/null
+++ b/contrib/gcc/config/sparc/openbsd.h
@@ -0,0 +1,68 @@
+/* Configuration file for sparc OpenBSD target.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <sparc/sparc.h>
+
+/* Get generic OpenBSD definitions. */
+#define OBSD_OLD_GAS
+#include <openbsd.h>
+
+/* Run-time target specifications. */
+#define CPP_PREDEFINES "-D__unix__ -D__sparc__ -D__OpenBSD__ -Asystem(unix) -Asystem(OpenBSD) -Acpu(sparc) -Amachine(sparc)"
+
+/* Layout of source language data types */
+
+/* This must agree with <machine/ansi.h> */
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 32
+
+/* Specific options for DBX Output. */
+
+/* This is BSD, so it wants DBX format. */
+#define DBX_DEBUGGING_INFO
+
+/* This is the char to use for continuation */
+#define DBX_CONTIN_CHAR '?'
+
+/* Stack & calling: aggregate returns. */
+
+/* Don't default to pcc-struct-return, because gcc is the only compiler, and
+ we want to retain compatibility with older gcc versions. */
+#undef DEFAULT_PCC_STRUCT_RETURN
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* Assembler format: exception region output. */
+
+/* All configurations that don't use elf must be explicit about not using
+ dwarf unwind information. egcs doesn't try too hard to check internal
+ configuration files... */
+#define DWARF2_UNWIND_INFO 0
+
+/* Default sparc.h does already define ASM_OUTPUT_MI_THUNK */
+
diff --git a/contrib/gcc/config/sparc/pbd.h b/contrib/gcc/config/sparc/pbd.h
new file mode 100644
index 0000000..459bffd
--- /dev/null
+++ b/contrib/gcc/config/sparc/pbd.h
@@ -0,0 +1,184 @@
+/* Definitions of target machine for GNU compiler, Citicorp/TTI Unicom PBD
+ version (using GAS and COFF (encapsulated is unacceptable) )
+ Copyright (C) 1990, 1996 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "sparc/sparc.h"
+
+/* Names to predefine in the preprocessor for this target machine. */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dsparc -DUnicomPBD -Dunix -D__GCC_NEW_VARARGS__ -Asystem(unix) -Acpu(sparc) -Amachine(sparc)"
+
+/* We want DBX format for use with gdb under COFF. */
+
+#define DBX_DEBUGGING_INFO
+
+/* Generate calls to memcpy, memcmp and memset. */
+
+#define TARGET_MEM_FUNCTIONS
+
+/* we use /lib/libp/lib* when profiling */
+
+#undef LIB_SPEC
+#define LIB_SPEC "%{p:-L/usr/lib/libp} %{pg:-L/usr/lib/libp} -lc"
+
+
+/* Use crt1.o as a startup file and crtn.o as a closing file. */
+/*
+ * The loader directive file gcc.ifile defines how to merge the constructor
+ * sections into the data section. Also, since gas only puts out those
+ * sections in response to N_SETT stabs, and does not (yet) have a
+ * ".sections" directive, gcc.ifile also defines the list symbols
+ * __DTOR_LIST__ and __CTOR_LIST__.
+ *
+ * Finally, we must explicitly specify the file from libgcc.a that defines
+ * exit(), otherwise if the user specifies (for example) "-lc_s" on the
+ * command line, the wrong exit() will be used and global destructors will
+ * not get called .
+ */
+
+#define STARTFILE_SPEC \
+"%{!r: gcc.ifile%s} %{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}} \
+%{!r:_exit.o%s}"
+
+#define ENDFILE_SPEC "crtn.o%s"
+
+/* cpp has to support a #sccs directive for the /usr/include files */
+
+#define SCCS_DIRECTIVE
+
+/* LINK_SPEC is needed only for SunOS 4. */
+
+#undef LINK_SPEC
+
+/* Although the gas we use can create .ctor and .dtor sections from N_SETT
+ stabs, it does not support section directives, so we need to have the loader
+ define the lists.
+ */
+#define CTOR_LISTS_DEFINED_EXTERNALLY
+
+/* similar to default, but allows for the table defined by ld with gcc.ifile.
+ nptrs is always 0. So we need to instead check that __DTOR_LIST__[1] != 0.
+ The old check is left in so that the same macro can be used if and when
+ a future version of gas does support section directives. */
+
+#define DO_GLOBAL_DTORS_BODY {int nptrs = *(int *)__DTOR_LIST__; int i; \
+ if (nptrs == -1 || (__DTOR_LIST__[0] == 0 && __DTOR_LIST__[1] != 0)) \
+ for (nptrs = 0; __DTOR_LIST__[nptrs + 1] != 0; nptrs++); \
+ for (i = nptrs; i >= 1; i--) \
+ __DTOR_LIST__[i] (); }
+
+/*
+ * Here is an example gcc.ifile. I've tested it on PBD sparc
+ * systems. The NEXT(0x200000) works on just about all 386 and m68k systems,
+ * but can be reduced to any power of 2 that is >= NBPS (0x40000 on a pbd).
+
+ SECTIONS {
+ .text BIND(0x41000200) BLOCK (0x200) :
+ { *(.init) *(.text) vfork = fork; *(.fini) }
+
+ GROUP BIND( NEXT(0x200000) + ADDR(.text) + SIZEOF(.text)):
+ { .data : { __CTOR_LIST__ = . ; . += 4; *(.ctor) . += 4 ;
+ __DTOR_LIST__ = . ; . += 4; *(.dtor) . += 4 ; }
+ .bss : { }
+ }
+ }
+ */
+
+/* The prefix to add to user-visible assembler symbols. */
+
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
+
+/* fixes: */
+/*
+ * Internal labels are prefixed with a period.
+ */
+
+/* This is how to store into the string LABEL
+ the symbol_ref name of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class.
+ This is suitable for output with `assemble_name'. */
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf (LABEL, "*.%s%d", PREFIX, NUM)
+
+
+/* This is how to output an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#undef ASM_OUTPUT_INTERNAL_LABEL
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
+ fprintf (FILE, ".%s%d:\n", PREFIX, NUM)
+
+/* This is how to output an element of a case-vector that is relative. */
+
+#undef ASM_OUTPUT_ADDR_DIFF_ELT
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+ fprintf (FILE, "\t.word .L%d-.L%d\n", VALUE, REL)
+
+/* This is how to output an element of a case-vector that is absolute.
+ (The 68000 does not use such vectors,
+ but we must define this macro anyway.) */
+
+#undef ASM_OUTPUT_ADDR_VEC_ELT
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+ fprintf (FILE, "\t.word .L%d\n", VALUE)
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry. */
+
+#undef FUNCTION_PROFILER
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ fprintf (FILE, "\tsethi %%hi(.LP%d),%%o0\n\tcall mcount\n\tor %%lo(.LP%d),%%o0,%%o0\n", \
+ (LABELNO), (LABELNO))
+
+/* Output assembler code to FILE to initialize this source file's
+ basic block profiling info, if that has not already been done. */
+
+#undef FUNCTION_BLOCK_PROFILER
+#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \
+ fprintf (FILE, "\tsethi %%hi(.LPBX0),%%o0\n\tld [%%lo(.LPBX0)+%%o0],%%o1\n\ttst %%o1\n\tbne .LPY%d\n\tnop\n\tcall ___bb_init_func\n\tnop\n.LPY%d:\n", \
+ (LABELNO), (LABELNO))
+
+/* Output assembler code to FILE to increment the entry-count for
+ the BLOCKNO'th basic block in this source file. */
+
+#undef BLOCK_PROFILER
+#define BLOCK_PROFILER(FILE, BLOCKNO) \
+{ \
+ int blockn = (BLOCKNO); \
+ fprintf (FILE, "\tsethi %%hi(.LPBX2+%d),%%g1\n\tld [%%lo(.LPBX2+%d)+%%g1],%%g2\n\
+\tadd %%g2,1,%%g2\n\tst %%g2,[%%lo(.LPBX2+%d)+%%g1]\n", \
+ 4 * blockn, 4 * blockn, 4 * blockn); \
+ CC_STATUS_INIT; /* We have clobbered %g1. Also %g2. */ \
+}
+/* This is needed for SunOS 4.0, and should not hurt for 3.2
+ versions either. */
+#undef ASM_OUTPUT_SOURCE_LINE(file, line)
+#define ASM_OUTPUT_SOURCE_LINE(file, line) \
+ { static int sym_lineno = 1; \
+ fprintf (file, ".stabn 68,0,%d,.LM%d\n.LM%d:\n", \
+ line, sym_lineno, sym_lineno); \
+ sym_lineno += 1; }
+
+#define ASM_INT_OP ".long "
diff --git a/contrib/gcc/config/sparc/rtems.h b/contrib/gcc/config/sparc/rtems.h
new file mode 100644
index 0000000..1ab0a42
--- /dev/null
+++ b/contrib/gcc/config/sparc/rtems.h
@@ -0,0 +1,35 @@
+/* Definitions for rtems targeting a SPARC using a.out.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Joel Sherrill (joel@OARcorp.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "sparc/aout.h"
+
+/* Specify predefined symbols in preprocessor. */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dsparc -D__GCC_NEW_VARARGS__ -Drtems -D__rtems__ \
+ -Asystem(rtems) -Acpu(sparc) -Amachine(sparc)"
+
+/* Generate calls to memcpy, memcmp and memset. */
+#ifndef TARGET_MEM_FUNCTIONS
+#define TARGET_MEM_FUNCTIONS
+#endif
+
+/* end of sparc/rtems.h */
diff --git a/contrib/gcc/config/sparc/sol2-c1.asm b/contrib/gcc/config/sparc/sol2-c1.asm
new file mode 100644
index 0000000..618d698
--- /dev/null
+++ b/contrib/gcc/config/sparc/sol2-c1.asm
@@ -0,0 +1,86 @@
+! crt1.s for solaris 2.0.
+
+! Copyright (C) 1992 Free Software Foundation, Inc.
+! Written By David Vinayak Henkel-Wallace, June 1992
+!
+! This file 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, or (at your option) any
+! later version.
+!
+! In addition to the permissions in the GNU General Public License, the
+! Free Software Foundation gives you unlimited permission to link the
+! compiled version of this file with other programs, and to distribute
+! those programs without any restriction coming from the use of this
+! file. (The General Public License restrictions do apply in other
+! respects; for example, they cover modification of the file, and
+! distribution when not linked into another program.)
+!
+! This file 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; see the file COPYING. If not, write to
+! the Free Software Foundation, 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+!
+! As a special exception, if you link this library with files
+! compiled with GCC to produce an executable, this does not cause
+! the resulting executable to be covered by the GNU General Public License.
+! This exception does not however invalidate any other reasons why
+! the executable file might be covered by the GNU General Public License.
+!
+
+! This file takes control of the process from the kernel, as specified
+! in section 3 of the SVr4 ABI.
+! This file is the first thing linked into any executable.
+
+ .section ".text"
+ .proc 022
+ .global _start
+
+_start:
+ mov 0, %fp ! Mark bottom frame pointer
+ ld [%sp + 64], %l0 ! argc
+ add %sp, 68, %l1 ! argv
+
+ ! Leave some room for a call. Sun leaves 32 octets (to sit on
+ ! a cache line?) so we do too.
+ sub %sp, 32, %sp
+
+ ! %g1 may contain a function to be registered w/atexit
+ orcc %g0, %g1, %g0
+ be .nope
+ mov %g1, %o0
+ call atexit
+ nop
+.nope:
+ ! Now make sure constructors and destructors are handled.
+ set _fini, %o0
+ call atexit, 1
+ nop
+ call _init, 0
+ nop
+
+ ! We ignore the auxiliary vector; there's no defined way to
+ ! access those data anyway. Instead, go straight to main:
+ mov %l0, %o0 ! argc
+ mov %l1, %o1 ! argv
+ ! Skip argc words past argv, to env:
+ sll %l0, 2, %o2
+ add %o2, 4, %o2
+ add %l1, %o2, %o2 ! env
+ set _environ, %o3
+ st %o2, [%o3] ! *_environ
+ call main, 4
+ nop
+ call exit, 0
+ nop
+ call _exit, 0
+ nop
+ ! We should never get here.
+
+ .type _start,#function
+ .size _start,.-_start
diff --git a/contrib/gcc/config/sparc/sol2-ci.asm b/contrib/gcc/config/sparc/sol2-ci.asm
new file mode 100644
index 0000000..dd09a34
--- /dev/null
+++ b/contrib/gcc/config/sparc/sol2-ci.asm
@@ -0,0 +1,60 @@
+! crti.s for solaris 2.0.
+
+! Copyright (C) 1992 Free Software Foundation, Inc.
+! Written By David Vinayak Henkel-Wallace, June 1992
+!
+! This file 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, or (at your option) any
+! later version.
+!
+! In addition to the permissions in the GNU General Public License, the
+! Free Software Foundation gives you unlimited permission to link the
+! compiled version of this file with other programs, and to distribute
+! those programs without any restriction coming from the use of this
+! file. (The General Public License restrictions do apply in other
+! respects; for example, they cover modification of the file, and
+! distribution when not linked into another program.)
+!
+! This file 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; see the file COPYING. If not, write to
+! the Free Software Foundation, 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+!
+! As a special exception, if you link this library with files
+! compiled with GCC to produce an executable, this does not cause
+! the resulting executable to be covered by the GNU General Public License.
+! This exception does not however invalidate any other reasons why
+! the executable file might be covered by the GNU General Public License.
+!
+
+! This file just make a stack frame for the contents of the .fini and
+! .init sections. Users may put any desired instructions in those
+! sections.
+
+! This file is linked in before the Values-Xx.o files and also before
+! crtbegin, with which perhaps it should be merged.
+
+ .file "crti.s"
+
+ .section ".init"
+ .proc 022
+ .global _init
+ .type _init,#function
+ .align 4
+_init:
+ save %sp, -96, %sp
+
+
+ .section ".fini"
+ .proc 022
+ .global _fini
+ .type _fini,#function
+ .align 4
+_fini:
+ save %sp, -96, %sp
diff --git a/contrib/gcc/config/sparc/sol2-cn.asm b/contrib/gcc/config/sparc/sol2-cn.asm
new file mode 100644
index 0000000..3c5d508
--- /dev/null
+++ b/contrib/gcc/config/sparc/sol2-cn.asm
@@ -0,0 +1,54 @@
+! crtn.s for solaris 2.0.
+
+! Copyright (C) 1992 Free Software Foundation, Inc.
+! Written By David Vinayak Henkel-Wallace, June 1992
+!
+! This file 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, or (at your option) any
+! later version.
+!
+! In addition to the permissions in the GNU General Public License, the
+! Free Software Foundation gives you unlimited permission to link the
+! compiled version of this file with other programs, and to distribute
+! those programs without any restriction coming from the use of this
+! file. (The General Public License restrictions do apply in other
+! respects; for example, they cover modification of the file, and
+! distribution when not linked into another program.)
+!
+! This file 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; see the file COPYING. If not, write to
+! the Free Software Foundation, 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+!
+! As a special exception, if you link this library with files
+! compiled with GCC to produce an executable, this does not cause
+! the resulting executable to be covered by the GNU General Public License.
+! This exception does not however invalidate any other reasons why
+! the executable file might be covered by the GNU General Public License.
+!
+
+! This file just makes sure that the .fini and .init sections do in
+! fact return. Users may put any desired instructions in those sections.
+! This file is the last thing linked into any executable.
+
+ .file "crtn.s"
+
+ .section ".init"
+ .align 4
+
+ ret
+ restore
+
+ .section ".fini"
+ .align 4
+
+ ret
+ restore
+
+! Th-th-th-that's all folks!
diff --git a/contrib/gcc/config/sparc/sol2-g1.asm b/contrib/gcc/config/sparc/sol2-g1.asm
new file mode 100644
index 0000000..b9d8788
--- /dev/null
+++ b/contrib/gcc/config/sparc/sol2-g1.asm
@@ -0,0 +1,88 @@
+! gcrt1.s for solaris 2.0.
+
+! Copyright (C) 1992 Free Software Foundation, Inc.
+! Written By David Vinayak Henkel-Wallace, June 1992
+!
+! This file 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, or (at your option) any
+! later version.
+!
+! In addition to the permissions in the GNU General Public License, the
+! Free Software Foundation gives you unlimited permission to link the
+! compiled version of this file with other programs, and to distribute
+! those programs without any restriction coming from the use of this
+! file. (The General Public License restrictions do apply in other
+! respects; for example, they cover modification of the file, and
+! distribution when not linked into another program.)
+!
+! This file 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; see the file COPYING. If not, write to
+! the Free Software Foundation, 59 Temple Place - Suite 330,
+! Boston, MA 02111-1307, USA.
+!
+! As a special exception, if you link this library with files
+! compiled with GCC to produce an executable, this does not cause
+! the resulting executable to be covered by the GNU General Public License.
+! This exception does not however invalidate any other reasons why
+! the executable file might be covered by the GNU General Public License.
+!
+
+! This file takes control of the process from the kernel, as specified
+! in section 3 of the SVr4 ABI.
+! This file is the first thing linked into any executable.
+
+ .section ".text"
+ .proc 022
+ .global _start
+
+_start:
+ mov 0, %fp ! Mark bottom frame pointer
+ ld [%sp + 64], %l0 ! argc
+ add %sp, 68, %l1 ! argv
+
+ ! Leave some room for a call. Sun leaves 32 octets (to sit on
+ ! a cache line?) so we do too.
+ sub %sp, 32, %sp
+
+ ! %g1 may contain a function to be registered w/atexit
+ orcc %g0, %g1, %g0
+ be .nope
+ mov %g1, %o0
+ call atexit
+ nop
+.nope:
+ ! Now make sure constructors and destructors are handled.
+ set _fini, %o0
+ call atexit, 1
+ nop
+ call _init, 0
+ nop
+
+ ! We ignore the auxiliary vector; there's no defined way to
+ ! access those data anyway. Instead, go straight to main:
+ mov %l0, %o0 ! argc
+ mov %l1, %o1 ! argv
+ set ___Argv, %o3
+ st %o1, [%o3] ! *___Argv
+ ! Skip argc words past argv, to env:
+ sll %l0, 2, %o2
+ add %o2, 4, %o2
+ add %l1, %o2, %o2 ! env
+ set _environ, %o3
+ st %o2, [%o3] ! *_environ
+ call main, 4
+ nop
+ call exit, 0
+ nop
+ call _exit, 0
+ nop
+ ! We should never get here.
+
+ .type _start,#function
+ .size _start,.-_start
diff --git a/contrib/gcc/config/sparc/sol2-sld.h b/contrib/gcc/config/sparc/sol2-sld.h
new file mode 100644
index 0000000..a824987
--- /dev/null
+++ b/contrib/gcc/config/sparc/sol2-sld.h
@@ -0,0 +1,11 @@
+/* Definitions of target machine for GNU compiler, for SPARC running Solaris 2
+ using the system linker. */
+
+#include "sparc/sol2.h"
+
+/* At least up through Solaris 2.6,
+ the system linker does not work with DWARF or DWARF2,
+ since it does not have working support for relocations
+ to unaligned data. */
+
+#define LINKER_DOES_NOT_WORK_WITH_DWARF2
diff --git a/contrib/gcc/config/sparc/sol2.h b/contrib/gcc/config/sparc/sol2.h
new file mode 100644
index 0000000..a0fa4a8
--- /dev/null
+++ b/contrib/gcc/config/sparc/sol2.h
@@ -0,0 +1,232 @@
+/* Definitions of target machine for GNU compiler, for SPARC running Solaris 2
+ Copyright 1992, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Ron Guilmette (rfg@netcom.com).
+ Additional changes by David V. Henkel-Wallace (gumby@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Supposedly the same as vanilla sparc svr4, except for the stuff below: */
+#include "sparc/sysv4.h"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+"-Dsparc -Dsun -Dunix -D__svr4__ -D__SVR4 \
+-Asystem(unix) -Asystem(svr4)"
+
+#undef CPP_SUBTARGET_SPEC
+#define CPP_SUBTARGET_SPEC "\
+%{pthreads:-D_REENTRANT -D_PTHREADS} \
+%{!pthreads:%{threads:-D_REENTRANT -D_SOLARIS_THREADS}} \
+%{compat-bsd:-iwithprefixbefore ucbinclude -I/usr/ucbinclude} \
+"
+
+/* The sun bundled assembler doesn't accept -Yd, (and neither does gas).
+ It's safe to pass -s always, even if -g is not used. */
+#undef ASM_SPEC
+#define ASM_SPEC "\
+%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Wa,*:%*} -s \
+%{fpic:-K PIC} %{fPIC:-K PIC} \
+%(asm_cpu) \
+"
+
+/* This is here rather than in sparc.h because it's not known what
+ other assemblers will accept. */
+#if TARGET_CPU_DEFAULT == TARGET_CPU_v9
+#undef ASM_CPU_DEFAULT_SPEC
+#define ASM_CPU_DEFAULT_SPEC "-xarch=v8plus"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc
+#undef ASM_CPU_DEFAULT_SPEC
+#define ASM_CPU_DEFAULT_SPEC "-xarch=v8plusa"
+#endif
+#undef ASM_CPU_SPEC
+#define ASM_CPU_SPEC "\
+%{mcpu=v8plus:-xarch=v8plus} \
+%{mcpu=ultrasparc:-xarch=v8plusa} \
+%{!mcpu*:%(asm_cpu_default)} \
+"
+
+/* However it appears that Solaris 2.0 uses the same reg numbering as
+ the old BSD-style system did. */
+
+#undef DBX_REGISTER_NUMBER
+/* Same as sparc.h */
+#define DBX_REGISTER_NUMBER(REGNO) \
+ (TARGET_FLAT && REGNO == FRAME_POINTER_REGNUM ? 31 : REGNO)
+
+/* We use stabs-in-elf for debugging, because that is what the native
+ toolchain uses. */
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+/* The Solaris 2 assembler uses .skip, not .zero, so put this back. */
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(FILE,SIZE) \
+ fprintf (FILE, "\t.skip %u\n", (SIZE))
+
+/* Use .uahalf/.uaword so packed structure members don't generate
+ assembler errors when using the native assembler. */
+#undef ASM_SHORT
+#define ASM_SHORT ".uahalf"
+#undef ASM_LONG
+#define ASM_LONG ".uaword"
+
+/* This is how to output a definition of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#undef ASM_OUTPUT_INTERNAL_LABEL
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
+ fprintf (FILE, ".L%s%d:\n", PREFIX, NUM)
+
+/* This is how to output a reference to an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#undef ASM_OUTPUT_INTERNAL_LABELREF
+#define ASM_OUTPUT_INTERNAL_LABELREF(FILE,PREFIX,NUM) \
+ fprintf (FILE, ".L%s%d", PREFIX, NUM)
+
+/* This is how to store into the string LABEL
+ the symbol_ref name of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class.
+ This is suitable for output with `assemble_name'. */
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf ((LABEL), "*.L%s%ld", (PREFIX), (long)(NUM))
+
+
+/* We don't use the standard svr4 STARTFILE_SPEC because it's wrong for us.
+ We don't use the standard LIB_SPEC only because we don't yet support c++ */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "%{!shared: \
+ %{!symbolic: \
+ %{p:mcrt1.o%s} \
+ %{!p: \
+ %{pg:gcrt1.o%s gmon.o%s} \
+ %{!pg:crt1.o%s}}}} \
+ crti.o%s \
+ %{ansi:values-Xc.o%s} \
+ %{!ansi: \
+ %{traditional:values-Xt.o%s} \
+ %{!traditional:values-Xa.o%s}} \
+ crtbegin.o%s"
+
+/* ??? Note: in order for -compat-bsd to work fully,
+ we must somehow arrange to fixincludes /usr/ucbinclude
+ and put the result in $(libsubdir)/ucbinclude. */
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+ "%{compat-bsd:-lucb -lsocket -lnsl -lelf -laio} \
+ %{!shared:\
+ %{!symbolic:\
+ %{pthreads:-lpthread} \
+ %{!pthreads:%{threads:-lthread}} \
+ -lc}}"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
+
+/* This should be the same as in svr4.h, except with -R added. */
+#undef LINK_SPEC
+#define LINK_SPEC \
+ "%{h*} %{v:-V} \
+ %{b} %{Wl,*:%*} \
+ %{static:-dn -Bstatic} \
+ %{shared:-G -dy %{!mimpure-text:-z text}} \
+ %{symbolic:-Bsymbolic -G -dy -z text} \
+ %{G:-G} \
+ %{YP,*} \
+ %{R*} \
+ %{compat-bsd: \
+ %{!YP,*:%{p:-Y P,/usr/ucblib:/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
+ %{pg:-Y P,/usr/ucblib:/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
+ %{!p:%{!pg:-Y P,/usr/ucblib:/usr/ccs/lib:/usr/lib}}} \
+ -R /usr/ucblib} \
+ %{!compat-bsd: \
+ %{!YP,*:%{p:-Y P,/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
+ %{pg:-Y P,/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
+ %{!p:%{!pg:-Y P,/usr/ccs/lib:/usr/lib}}}} \
+ %{Qy:} %{!Qn:-Qy}"
+
+/* This defines which switch letters take arguments.
+ It is as in svr4.h but with -R added. */
+
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ (DEFAULT_SWITCH_TAKES_ARG(CHAR) \
+ || (CHAR) == 'R' \
+ || (CHAR) == 'h' \
+ || (CHAR) == 'x' \
+ || (CHAR) == 'z')
+
+/* ??? This does not work in SunOS 4.x, so it is not enabled in sparc.h.
+ Instead, it is enabled here, because it does work under Solaris. */
+/* Define for support of TFmode long double and REAL_ARITHMETIC.
+ Sparc ABI says that long double is 4 words. */
+#define LONG_DOUBLE_TYPE_SIZE 128
+
+/* But indicate that it isn't supported by the hardware. */
+#define WIDEST_HARDWARE_FP_SIZE 64
+
+#define STDC_0_IN_SYSTEM_HEADERS
+
+#define MULDI3_LIBCALL "__mul64"
+#define DIVDI3_LIBCALL "__div64"
+#define UDIVDI3_LIBCALL "__udiv64"
+#define MODDI3_LIBCALL "__rem64"
+#define UMODDI3_LIBCALL "__urem64"
+
+#undef INIT_SUBTARGET_OPTABS
+#define INIT_SUBTARGET_OPTABS \
+ fixsfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ftoll"); \
+ fixunssfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ftoull"); \
+ fixdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__dtoll"); \
+ fixunsdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__dtoull")
+
+/* No weird SPARC variants on Solaris */
+#undef TARGET_LIVE_G0
+#define TARGET_LIVE_G0 0
+#undef TARGET_BROKEN_SAVERESTORE
+#define TARGET_BROKEN_SAVERESTORE 0
+
+/* Solaris allows 64 bit out and global registers in 32 bit mode.
+ sparc_override_options will disable V8+ if not generating V9 code. */
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_APP_REGS + MASK_EPILOGUE + MASK_FPU + MASK_V8PLUS)
+
+/* Override MACHINE_STATE_{SAVE,RESTORE} because we have special
+ traps available which can get and set the condition codes
+ reliably. */
+#undef MACHINE_STATE_SAVE
+#define MACHINE_STATE_SAVE(ID) \
+ unsigned long int ms_flags, ms_saveret; \
+ asm volatile("ta 0x20\n\t" \
+ "mov %%g1, %0\n\t" \
+ "mov %%g2, %1\n\t" \
+ : "=r" (ms_flags), "=r" (ms_saveret));
+
+#undef MACHINE_STATE_RESTORE
+#define MACHINE_STATE_RESTORE(ID) \
+ asm volatile("mov %0, %%g1\n\t" \
+ "mov %1, %%g2\n\t" \
+ "ta 0x21\n\t" \
+ : /* no outputs */ \
+ : "r" (ms_flags), "r" (ms_saveret));
+
diff --git a/contrib/gcc/config/sparc/sp64-aout.h b/contrib/gcc/config/sparc/sp64-aout.h
new file mode 100644
index 0000000..e3056df
--- /dev/null
+++ b/contrib/gcc/config/sparc/sp64-aout.h
@@ -0,0 +1,38 @@
+/* Definitions of target machine for GNU compiler, for SPARC64, a.out.
+ Copyright (C) 1994, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Doug Evans, dje@cygnus.com.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "sparc/sparc.h"
+#include "aoutos.h"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (sparc64-aout)")
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT \
+ (MASK_V9 + MASK_PTR64 + MASK_64BIT + MASK_HARD_QUAD \
+ + MASK_APP_REGS + MASK_EPILOGUE + MASK_FPU + MASK_STACK_BIAS)
+
+/* The only code model supported is Medium/Low. */
+#undef SPARC_DEFAULT_CMODEL
+#define SPARC_DEFAULT_CMODEL CM_MEDLOW
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dsparc -Acpu(sparc) -Amachine(sparc)"
diff --git a/contrib/gcc/config/sparc/sp64-elf.h b/contrib/gcc/config/sparc/sp64-elf.h
new file mode 100644
index 0000000..2482866
--- /dev/null
+++ b/contrib/gcc/config/sparc/sp64-elf.h
@@ -0,0 +1,157 @@
+/* Definitions of target machine for GNU compiler, for SPARC64, ELF.
+ Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Contributed by Doug Evans, dje@cygnus.com.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* ??? We're taking the scheme of including another file and then overriding
+ the values we don't like a bit too far here. The alternative is to more or
+ less duplicate all of svr4.h, sparc/sysv4.h, and sparc/sol2.h here
+ (suitably cleaned up). */
+
+#include "sparc/sol2.h"
+
+#undef TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (sparc64-elf)")
+
+/* A 64 bit v9 compiler in a Medium/Anywhere code model environment. */
+
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT \
+(MASK_V9 + MASK_PTR64 + MASK_64BIT + MASK_HARD_QUAD \
+ + MASK_APP_REGS + MASK_EPILOGUE + MASK_FPU + MASK_STACK_BIAS)
+
+#undef SPARC_DEFAULT_CMODEL
+#define SPARC_DEFAULT_CMODEL CM_EMBMEDANY
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dsparc -D__ELF__ -Acpu(sparc) -Amachine(sparc)"
+
+/* __svr4__ is used by the C library (FIXME) */
+#undef CPP_SUBTARGET_SPEC
+#define CPP_SUBTARGET_SPEC "-D__svr4__"
+
+#undef MD_EXEC_PREFIX
+#undef MD_STARTFILE_PREFIX
+
+#undef ASM_SPEC
+#define ASM_SPEC "\
+%{v:-V} -s %{fpic:-K PIC} %{fPIC:-K PIC} \
+%{mlittle-endian:-EL} \
+%(asm_cpu) %(asm_arch) \
+"
+
+/* This is taken from sol2.h. */
+#undef LINK_SPEC
+#define LINK_SPEC "\
+%{v:-V} \
+%{mlittle-endian:-EL} \
+"
+
+/* We need something a little simpler for the embedded environment.
+ Profiling doesn't really work yet so we just copy the default. */
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "\
+%{!shared:%{pg:gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}} \
+crtbegin.o%s \
+"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s"
+
+/* Use the default (for now). */
+#undef LIB_SPEC
+
+/* V9 chips can handle either endianness. */
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+{"big-endian", -MASK_LITTLE_ENDIAN}, \
+{"little-endian", MASK_LITTLE_ENDIAN},
+
+#undef BYTES_BIG_ENDIAN
+#define BYTES_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN)
+
+#undef WORDS_BIG_ENDIAN
+#define WORDS_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN)
+
+/* ??? This should be 32 bits for v9 but what can we do? */
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "short unsigned int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 16
+
+#undef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE 128
+
+/* The medium/anywhere code model practically requires us to put jump tables
+ in the text section as gcc is unable to distinguish LABEL_REF's of jump
+ tables from other label refs (when we need to). */
+/* ??? Revisit this. */
+#undef JUMP_TABLES_IN_TEXT_SECTION
+#define JUMP_TABLES_IN_TEXT_SECTION 1
+
+/* System V Release 4 uses DWARF debugging info.
+ GDB doesn't support 64 bit stabs yet and the desired debug format is DWARF
+ anyway so it is the default. */
+
+#define DWARF_DEBUGGING_INFO
+#define DWARF2_DEBUGGING_INFO
+#define DBX_DEBUGGING_INFO
+
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+/* Stabs doesn't use this, and it confuses a simulator. */
+/* ??? Need to see what DWARF needs, if anything. */
+#undef ASM_IDENTIFY_GCC
+#define ASM_IDENTIFY_GCC(FILE)
+
+/* Define the names of various pseudo-ops used by the Sparc/svr4 assembler.
+ ??? If ints are 64 bits then UNALIGNED_INT_ASM_OP (defined elsewhere) is
+ misnamed. These should all refer to explicit sizes (half/word/xword?),
+ anything other than short/int/long/etc. */
+
+#define UNALIGNED_LONGLONG_ASM_OP ".uaxword"
+
+/* DWARF stuff. */
+
+#define ASM_OUTPUT_DWARF_ADDR(FILE, LABEL) \
+do { \
+ fprintf ((FILE), "\t%s\t", UNALIGNED_LONGLONG_ASM_OP); \
+ assemble_name ((FILE), (LABEL)); \
+ fprintf ((FILE), "\n"); \
+} while (0)
+
+#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE, RTX) \
+do { \
+ fprintf ((FILE), "\t%s\t", UNALIGNED_LONGLONG_ASM_OP); \
+ output_addr_const ((FILE), (RTX)); \
+ fputc ('\n', (FILE)); \
+} while (0)
+
+#define ASM_OUTPUT_DWARF2_ADDR_CONST(FILE, ADDR) \
+ fprintf ((FILE), "\t%s\t%s", UNALIGNED_LONGLONG_ASM_OP, (ADDR))
+
+/* ??? Not sure if this should be 4 or 8 bytes. 4 works for now. */
+#define ASM_OUTPUT_DWARF_REF(FILE, LABEL) \
+do { \
+ fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \
+ assemble_name ((FILE), (LABEL)); \
+ fprintf ((FILE), "\n"); \
+} while (0)
diff --git a/contrib/gcc/config/sparc/sparc.c b/contrib/gcc/config/sparc/sparc.c
new file mode 100644
index 0000000..e350729
--- /dev/null
+++ b/contrib/gcc/config/sparc/sparc.c
@@ -0,0 +1,6461 @@
+/* Subroutines for insn-output.c for Sun SPARC.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann (tiemann@cygnus.com)
+ 64 bit SPARC V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
+ at Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-flags.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "expr.h"
+#include "recog.h"
+#include "toplev.h"
+
+/* 1 if the caller has placed an "unimp" insn immediately after the call.
+ This is used in v8 code when calling a function that returns a structure.
+ v9 doesn't have this. Be careful to have this test be the same as that
+ used on the call. */
+
+#define SKIP_CALLERS_UNIMP_P \
+(!TARGET_ARCH64 && current_function_returns_struct \
+ && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))) \
+ && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl))) \
+ == INTEGER_CST))
+
+/* Global variables for machine-dependent things. */
+
+/* Size of frame. Need to know this to emit return insns from leaf procedures.
+ ACTUAL_FSIZE is set by compute_frame_size() which is called during the
+ reload pass. This is important as the value is later used in insn
+ scheduling (to see what can go in a delay slot).
+ APPARENT_FSIZE is the size of the stack less the register save area and less
+ the outgoing argument area. It is used when saving call preserved regs. */
+static int apparent_fsize;
+static int actual_fsize;
+
+/* Save the operands last given to a compare for use when we
+ generate a scc or bcc insn. */
+
+rtx sparc_compare_op0, sparc_compare_op1;
+
+/* We may need an epilogue if we spill too many registers.
+ If this is non-zero, then we branch here for the epilogue. */
+static rtx leaf_label;
+
+#ifdef LEAF_REGISTERS
+
+/* Vector to say how input registers are mapped to output
+ registers. FRAME_POINTER_REGNUM cannot be remapped by
+ this function to eliminate it. You must use -fomit-frame-pointer
+ to get that. */
+char leaf_reg_remap[] =
+{ 0, 1, 2, 3, 4, 5, 6, 7,
+ -1, -1, -1, -1, -1, -1, 14, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 8, 9, 10, 11, 12, 13, -1, 15,
+
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100};
+
+#endif
+
+/* Name of where we pretend to think the frame pointer points.
+ Normally, this is "%fp", but if we are in a leaf procedure,
+ this is "%sp+something". We record "something" separately as it may be
+ too big for reg+constant addressing. */
+
+static char *frame_base_name;
+static int frame_base_offset;
+
+static rtx pic_setup_code PROTO((void));
+static rtx find_addr_reg PROTO((rtx));
+static void sparc_init_modes PROTO((void));
+static int save_regs PROTO((FILE *, int, int, char *,
+ int, int, int));
+static int restore_regs PROTO((FILE *, int, int, char *, int, int));
+static void build_big_number PROTO((FILE *, int, char *));
+static int function_arg_slotno PROTO((const CUMULATIVE_ARGS *,
+ enum machine_mode, tree, int, int,
+ int *, int *));
+
+#ifdef DWARF2_DEBUGGING_INFO
+extern char *dwarf2out_cfi_label ();
+#endif
+
+/* Option handling. */
+
+/* Code model option as passed by user. */
+char *sparc_cmodel_string;
+/* Parsed value. */
+enum cmodel sparc_cmodel;
+
+/* Record alignment options as passed by user. */
+char *sparc_align_loops_string;
+char *sparc_align_jumps_string;
+char *sparc_align_funcs_string;
+
+/* Parsed values, as a power of two. */
+int sparc_align_loops;
+int sparc_align_jumps;
+int sparc_align_funcs;
+
+struct sparc_cpu_select sparc_select[] =
+{
+ /* switch name, tune arch */
+ { (char *)0, "default", 1, 1 },
+ { (char *)0, "-mcpu=", 1, 1 },
+ { (char *)0, "-mtune=", 1, 0 },
+ { 0, 0, 0, 0 }
+};
+
+/* CPU type. This is set from TARGET_CPU_DEFAULT and -m{cpu,tune}=xxx. */
+enum processor_type sparc_cpu;
+
+/* Validate and override various options, and do some machine dependent
+ initialization. */
+
+void
+sparc_override_options ()
+{
+ static struct code_model {
+ char *name;
+ int value;
+ } cmodels[] = {
+ { "32", CM_32 },
+ { "medlow", CM_MEDLOW },
+ { "medmid", CM_MEDMID },
+ { "medany", CM_MEDANY },
+ { "embmedany", CM_EMBMEDANY },
+ { 0, 0 }
+ };
+ struct code_model *cmodel;
+ /* Map TARGET_CPU_DEFAULT to value for -m{arch,tune}=. */
+ static struct cpu_default {
+ int cpu;
+ char *name;
+ } cpu_default[] = {
+ /* There must be one entry here for each TARGET_CPU value. */
+ { TARGET_CPU_sparc, "cypress" },
+ { TARGET_CPU_sparclet, "tsc701" },
+ { TARGET_CPU_sparclite, "f930" },
+ { TARGET_CPU_v8, "v8" },
+ { TARGET_CPU_supersparc, "supersparc" },
+ { TARGET_CPU_v9, "v9" },
+ { TARGET_CPU_ultrasparc, "ultrasparc" },
+ { 0, 0 }
+ };
+ struct cpu_default *def;
+ /* Table of values for -m{cpu,tune}=. */
+ static struct cpu_table {
+ char *name;
+ enum processor_type processor;
+ int disable;
+ int enable;
+ } cpu_table[] = {
+ { "v7", PROCESSOR_V7, MASK_ISA, 0 },
+ { "cypress", PROCESSOR_CYPRESS, MASK_ISA, 0 },
+ { "v8", PROCESSOR_V8, MASK_ISA, MASK_V8 },
+ /* TI TMS390Z55 supersparc */
+ { "supersparc", PROCESSOR_SUPERSPARC, MASK_ISA, MASK_V8 },
+ { "sparclite", PROCESSOR_SPARCLITE, MASK_ISA, MASK_SPARCLITE },
+ /* The Fujitsu MB86930 is the original sparclite chip, with no fpu.
+ The Fujitsu MB86934 is the recent sparclite chip, with an fpu. */
+ { "f930", PROCESSOR_F930, MASK_ISA|MASK_FPU, MASK_SPARCLITE },
+ { "f934", PROCESSOR_F934, MASK_ISA, MASK_SPARCLITE|MASK_FPU },
+ { "sparclet", PROCESSOR_SPARCLET, MASK_ISA, MASK_SPARCLET },
+ /* TEMIC sparclet */
+ { "tsc701", PROCESSOR_TSC701, MASK_ISA, MASK_SPARCLET },
+ { "v9", PROCESSOR_V9, MASK_ISA, MASK_V9 },
+ /* TI ultrasparc */
+ { "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, MASK_V9 },
+ { 0, 0, 0, 0 }
+ };
+ struct cpu_table *cpu;
+ struct sparc_cpu_select *sel;
+ int fpu;
+
+#ifndef SPARC_BI_ARCH
+ /* Check for unsupported architecture size. */
+ if (! TARGET_64BIT != DEFAULT_ARCH32_P)
+ {
+ error ("%s is not supported by this configuration",
+ DEFAULT_ARCH32_P ? "-m64" : "-m32");
+ }
+#endif
+
+ /* Code model selection. */
+ sparc_cmodel = SPARC_DEFAULT_CMODEL;
+ if (sparc_cmodel_string != NULL)
+ {
+ if (TARGET_ARCH64)
+ {
+ for (cmodel = &cmodels[0]; cmodel->name; cmodel++)
+ if (strcmp (sparc_cmodel_string, cmodel->name) == 0)
+ break;
+ if (cmodel->name == NULL)
+ error ("bad value (%s) for -mcmodel= switch", sparc_cmodel_string);
+ else
+ sparc_cmodel = cmodel->value;
+ }
+ else
+ error ("-mcmodel= is not supported on 32 bit systems");
+ }
+
+ fpu = TARGET_FPU; /* save current -mfpu status */
+
+ /* Set the default CPU. */
+ for (def = &cpu_default[0]; def->name; ++def)
+ if (def->cpu == TARGET_CPU_DEFAULT)
+ break;
+ if (! def->name)
+ abort ();
+ sparc_select[0].string = def->name;
+
+ for (sel = &sparc_select[0]; sel->name; ++sel)
+ {
+ if (sel->string)
+ {
+ for (cpu = &cpu_table[0]; cpu->name; ++cpu)
+ if (! strcmp (sel->string, cpu->name))
+ {
+ if (sel->set_tune_p)
+ sparc_cpu = cpu->processor;
+
+ if (sel->set_arch_p)
+ {
+ target_flags &= ~cpu->disable;
+ target_flags |= cpu->enable;
+ }
+ break;
+ }
+
+ if (! cpu->name)
+ error ("bad value (%s) for %s switch", sel->string, sel->name);
+ }
+ }
+
+ /* If -mfpu or -mno-fpu was explicitly used, don't override with
+ the processor default. */
+ if (TARGET_FPU_SET)
+ target_flags = (target_flags & ~MASK_FPU) | fpu;
+
+ /* Use the deprecated v8 insns for sparc64 in 32 bit mode. */
+ if (TARGET_V9 && TARGET_ARCH32)
+ target_flags |= MASK_DEPRECATED_V8_INSNS;
+
+ /* V8PLUS requires V9 */
+ if (! TARGET_V9)
+ target_flags &= ~MASK_V8PLUS;
+
+ /* Don't use stack biasing in 32 bit mode. */
+ if (TARGET_ARCH32)
+ target_flags &= ~MASK_STACK_BIAS;
+
+ /* Validate -malign-loops= value, or provide default. */
+ if (sparc_align_loops_string)
+ {
+ sparc_align_loops = exact_log2 (atoi (sparc_align_loops_string));
+ if (sparc_align_loops < 2 || sparc_align_loops > 7)
+ fatal ("-malign-loops=%s is not between 4 and 128 or is not a power of two",
+ sparc_align_loops_string);
+ }
+ else
+ {
+ /* ??? This relies on ASM_OUTPUT_ALIGN to not emit the alignment if
+ its 0. This sounds a bit kludgey. */
+ sparc_align_loops = 0;
+ }
+
+ /* Validate -malign-jumps= value, or provide default. */
+ if (sparc_align_jumps_string)
+ {
+ sparc_align_jumps = exact_log2 (atoi (sparc_align_jumps_string));
+ if (sparc_align_jumps < 2 || sparc_align_loops > 7)
+ fatal ("-malign-jumps=%s is not between 4 and 128 or is not a power of two",
+ sparc_align_jumps_string);
+ }
+ else
+ {
+ /* ??? This relies on ASM_OUTPUT_ALIGN to not emit the alignment if
+ its 0. This sounds a bit kludgey. */
+ sparc_align_jumps = 0;
+ }
+
+ /* Validate -malign-functions= value, or provide default. */
+ if (sparc_align_funcs_string)
+ {
+ sparc_align_funcs = exact_log2 (atoi (sparc_align_funcs_string));
+ if (sparc_align_funcs < 2 || sparc_align_loops > 7)
+ fatal ("-malign-functions=%s is not between 4 and 128 or is not a power of two",
+ sparc_align_funcs_string);
+ }
+ else
+ sparc_align_funcs = DEFAULT_SPARC_ALIGN_FUNCS;
+
+ /* Validate PCC_STRUCT_RETURN. */
+ if (flag_pcc_struct_return == DEFAULT_PCC_STRUCT_RETURN)
+ flag_pcc_struct_return = (TARGET_ARCH64 ? 0 : 1);
+
+ /* Do various machine dependent initializations. */
+ sparc_init_modes ();
+}
+
+/* Miscellaneous utilities. */
+
+/* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move
+ or branch on register contents instructions. */
+
+int
+v9_regcmp_p (code)
+ enum rtx_code code;
+{
+ return (code == EQ || code == NE || code == GE || code == LT
+ || code == LE || code == GT);
+}
+
+/* 32 bit registers are zero extended so only zero/non-zero comparisons
+ work. */
+int
+v8plus_regcmp_p (code)
+ enum rtx_code code;
+{
+ return (code == EQ || code == NE);
+}
+
+/* Operand constraints. */
+
+/* Return non-zero only if OP is a register of mode MODE,
+ or const0_rtx. Don't allow const0_rtx if TARGET_LIVE_G0 because
+ %g0 may contain anything. */
+
+int
+reg_or_0_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (register_operand (op, mode))
+ return 1;
+ if (TARGET_LIVE_G0)
+ return 0;
+ if (op == const0_rtx)
+ return 1;
+ if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE
+ && CONST_DOUBLE_HIGH (op) == 0
+ && CONST_DOUBLE_LOW (op) == 0)
+ return 1;
+ if (GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT
+ && GET_CODE (op) == CONST_DOUBLE
+ && fp_zero_operand (op))
+ return 1;
+ return 0;
+}
+
+/* Nonzero if OP is a floating point value with value 0.0. */
+
+int
+fp_zero_operand (op)
+ rtx op;
+{
+ REAL_VALUE_TYPE r;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+ return (REAL_VALUES_EQUAL (r, dconst0) && ! REAL_VALUE_MINUS_ZERO (r));
+}
+
+/* Nonzero if OP is an integer register. */
+
+int
+intreg_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (register_operand (op, SImode)
+ || (TARGET_ARCH64 && register_operand (op, DImode)));
+}
+
+/* Nonzero if OP is a floating point condition code register. */
+
+int
+fcc_reg_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ /* This can happen when recog is called from combine. Op may be a MEM.
+ Fail instead of calling abort in this case. */
+ if (GET_CODE (op) != REG)
+ return 0;
+
+ if (mode != VOIDmode && mode != GET_MODE (op))
+ return 0;
+ if (mode == VOIDmode
+ && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
+ return 0;
+
+#if 0 /* ??? ==> 1 when %fcc0-3 are pseudos first. See gen_compare_reg(). */
+ if (reg_renumber == 0)
+ return REGNO (op) >= FIRST_PSEUDO_REGISTER;
+ return REGNO_OK_FOR_CCFP_P (REGNO (op));
+#else
+ return (unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG < 4;
+#endif
+}
+
+/* Nonzero if OP is an integer or floating point condition code register. */
+
+int
+icc_or_fcc_reg_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) == REG && REGNO (op) == SPARC_ICC_REG)
+ {
+ if (mode != VOIDmode && mode != GET_MODE (op))
+ return 0;
+ if (mode == VOIDmode
+ && GET_MODE (op) != CCmode && GET_MODE (op) != CCXmode)
+ return 0;
+ return 1;
+ }
+
+ return fcc_reg_operand (op, mode);
+}
+
+/* Nonzero if OP can appear as the dest of a RESTORE insn. */
+int
+restore_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (GET_CODE (op) == REG && GET_MODE (op) == mode
+ && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));
+}
+
+/* Call insn on SPARC can take a PC-relative constant address, or any regular
+ memory address. */
+
+int
+call_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) != MEM)
+ abort ();
+ op = XEXP (op, 0);
+ return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
+}
+
+int
+call_operand_address (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
+}
+
+/* Returns 1 if OP is either a symbol reference or a sum of a symbol
+ reference and a constant. */
+
+int
+symbolic_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ switch (GET_CODE (op))
+ {
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return 1;
+
+ case CONST:
+ op = XEXP (op, 0);
+ return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+ || GET_CODE (XEXP (op, 0)) == LABEL_REF)
+ && GET_CODE (XEXP (op, 1)) == CONST_INT);
+
+ /* ??? This clause seems to be irrelevant. */
+ case CONST_DOUBLE:
+ return GET_MODE (op) == mode;
+
+ default:
+ return 0;
+ }
+}
+
+/* Return truth value of statement that OP is a symbolic memory
+ operand of mode MODE. */
+
+int
+symbolic_memory_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+ if (GET_CODE (op) != MEM)
+ return 0;
+ op = XEXP (op, 0);
+ return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
+ || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
+}
+
+/* Return truth value of statement that OP is a LABEL_REF of mode MODE. */
+
+int
+label_ref_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (GET_CODE (op) != LABEL_REF)
+ return 0;
+ if (GET_MODE (op) != mode)
+ return 0;
+ return 1;
+}
+
+/* Return 1 if the operand is an argument used in generating pic references
+ in either the medium/low or medium/anywhere code models of sparc64. */
+
+int
+sp64_medium_pic_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ /* Check for (const (minus (symbol_ref:GOT)
+ (const (minus (label) (pc))))). */
+ if (GET_CODE (op) != CONST)
+ return 0;
+ op = XEXP (op, 0);
+ if (GET_CODE (op) != MINUS)
+ return 0;
+ if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
+ return 0;
+ /* ??? Ensure symbol is GOT. */
+ if (GET_CODE (XEXP (op, 1)) != CONST)
+ return 0;
+ if (GET_CODE (XEXP (XEXP (op, 1), 0)) != MINUS)
+ return 0;
+ return 1;
+}
+
+/* Return 1 if the operand is a data segment reference. This includes
+ the readonly data segment, or in other words anything but the text segment.
+ This is needed in the medium/anywhere code model on v9. These values
+ are accessed with EMBMEDANY_BASE_REG. */
+
+int
+data_segment_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ switch (GET_CODE (op))
+ {
+ case SYMBOL_REF :
+ return ! SYMBOL_REF_FLAG (op);
+ case PLUS :
+ /* Assume canonical format of symbol + constant.
+ Fall through. */
+ case CONST :
+ return data_segment_operand (XEXP (op, 0));
+ default :
+ return 0;
+ }
+}
+
+/* Return 1 if the operand is a text segment reference.
+ This is needed in the medium/anywhere code model on v9. */
+
+int
+text_segment_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ switch (GET_CODE (op))
+ {
+ case LABEL_REF :
+ return 1;
+ case SYMBOL_REF :
+ return SYMBOL_REF_FLAG (op);
+ case PLUS :
+ /* Assume canonical format of symbol + constant.
+ Fall through. */
+ case CONST :
+ return text_segment_operand (XEXP (op, 0));
+ default :
+ return 0;
+ }
+}
+
+/* Return 1 if the operand is either a register or a memory operand that is
+ not symbolic. */
+
+int
+reg_or_nonsymb_mem_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (register_operand (op, mode))
+ return 1;
+
+ if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
+ return 1;
+
+ return 0;
+}
+
+int
+sparc_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (register_operand (op, mode)
+ || GET_CODE (op) == CONSTANT_P_RTX)
+ return 1;
+ if (GET_CODE (op) == CONST_INT)
+ return SMALL_INT (op);
+ if (GET_MODE (op) != mode)
+ return 0;
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+ if (GET_CODE (op) != MEM)
+ return 0;
+
+ op = XEXP (op, 0);
+ if (GET_CODE (op) == LO_SUM)
+ return (GET_CODE (XEXP (op, 0)) == REG
+ && symbolic_operand (XEXP (op, 1), Pmode));
+ return memory_address_p (mode, op);
+}
+
+int
+move_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ if (mode == DImode && arith_double_operand (op, mode))
+ return 1;
+ if (register_operand (op, mode)
+ || GET_CODE (op) == CONSTANT_P_RTX)
+ return 1;
+ if (GET_CODE (op) == CONST_INT)
+ return SMALL_INT (op) || SPARC_SETHI_P (INTVAL (op));
+
+ if (GET_MODE (op) != mode)
+ return 0;
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+ if (GET_CODE (op) != MEM)
+ return 0;
+ op = XEXP (op, 0);
+ if (GET_CODE (op) == LO_SUM)
+ return (register_operand (XEXP (op, 0), Pmode)
+ && CONSTANT_P (XEXP (op, 1)));
+ return memory_address_p (mode, op);
+}
+
+int
+splittable_symbolic_memory_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) != MEM)
+ return 0;
+ if (! symbolic_operand (XEXP (op, 0), Pmode))
+ return 0;
+ return 1;
+}
+
+int
+splittable_immediate_memory_operand (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) != MEM)
+ return 0;
+ if (! immediate_operand (XEXP (op, 0), Pmode))
+ return 0;
+ return 1;
+}
+
+/* Return truth value of whether OP is EQ or NE. */
+
+int
+eq_or_neq (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
+}
+
+/* Return 1 if this is a comparison operator, but not an EQ, NE, GEU,
+ or LTU for non-floating-point. We handle those specially. */
+
+int
+normal_comp_operator (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ enum rtx_code code = GET_CODE (op);
+
+ if (GET_RTX_CLASS (code) != '<')
+ return 0;
+
+ if (GET_MODE (XEXP (op, 0)) == CCFPmode
+ || GET_MODE (XEXP (op, 0)) == CCFPEmode)
+ return 1;
+
+ return (code != NE && code != EQ && code != GEU && code != LTU);
+}
+
+/* Return 1 if this is a comparison operator. This allows the use of
+ MATCH_OPERATOR to recognize all the branch insns. */
+
+int
+noov_compare_op (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ enum rtx_code code = GET_CODE (op);
+
+ if (GET_RTX_CLASS (code) != '<')
+ return 0;
+
+ if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode)
+ /* These are the only branches which work with CC_NOOVmode. */
+ return (code == EQ || code == NE || code == GE || code == LT);
+ return 1;
+}
+
+/* Nonzero if OP is a comparison operator suitable for use in v9
+ conditional move or branch on register contents instructions. */
+
+int
+v9_regcmp_op (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ enum rtx_code code = GET_CODE (op);
+
+ if (GET_RTX_CLASS (code) != '<')
+ return 0;
+
+ return v9_regcmp_p (code);
+}
+
+/* ??? Same as eq_or_neq. */
+int
+v8plus_regcmp_op (op, mode)
+ register rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ enum rtx_code code = GET_CODE (op);
+
+ return (code == EQ || code == NE);
+}
+
+/* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation. */
+
+int
+extend_op (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
+}
+
+/* Return nonzero if OP is an operator of mode MODE which can set
+ the condition codes explicitly. We do not include PLUS and MINUS
+ because these require CC_NOOVmode, which we handle explicitly. */
+
+int
+cc_arithop (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (op) == AND
+ || GET_CODE (op) == IOR
+ || GET_CODE (op) == XOR)
+ return 1;
+
+ return 0;
+}
+
+/* Return nonzero if OP is an operator of mode MODE which can bitwise
+ complement its second operand and set the condition codes explicitly. */
+
+int
+cc_arithopn (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ /* XOR is not here because combine canonicalizes (xor (not ...) ...)
+ and (xor ... (not ...)) to (not (xor ...)). */
+ return (GET_CODE (op) == AND
+ || GET_CODE (op) == IOR);
+}
+
+/* Return true if OP is a register, or is a CONST_INT that can fit in a
+ signed 13 bit immediate field. This is an acceptable SImode operand for
+ most 3 address instructions. */
+
+int
+arith_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ int val;
+ if (register_operand (op, mode)
+ || GET_CODE (op) == CONSTANT_P_RTX)
+ return 1;
+ if (GET_CODE (op) != CONST_INT)
+ return 0;
+ val = INTVAL (op) & 0xffffffff;
+ return SPARC_SIMM13_P (val);
+}
+
+/* Return true if OP is a register, or is a CONST_INT that can fit in a
+ signed 11 bit immediate field. This is an acceptable SImode operand for
+ the movcc instructions. */
+
+int
+arith11_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (register_operand (op, mode)
+ || GET_CODE (op) == CONSTANT_P_RTX
+ || (GET_CODE (op) == CONST_INT && SPARC_SIMM11_P (INTVAL (op))));
+}
+
+/* Return true if OP is a register, or is a CONST_INT that can fit in a
+ signed 10 bit immediate field. This is an acceptable SImode operand for
+ the movrcc instructions. */
+
+int
+arith10_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (register_operand (op, mode)
+ || GET_CODE (op) == CONSTANT_P_RTX
+ || (GET_CODE (op) == CONST_INT && SPARC_SIMM10_P (INTVAL (op))));
+}
+
+/* Return true if OP is a register, is a CONST_INT that fits in a 13 bit
+ immediate field, or is a CONST_DOUBLE whose both parts fit in a 13 bit
+ immediate field.
+ v9: Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
+ can fit in a 13 bit immediate field. This is an acceptable DImode operand
+ for most 3 address instructions. */
+
+int
+arith_double_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (register_operand (op, mode)
+ || GET_CODE (op) == CONSTANT_P_RTX
+ || (GET_CODE (op) == CONST_INT && SMALL_INT (op))
+ || (! TARGET_ARCH64
+ && GET_CODE (op) == CONST_DOUBLE
+ && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
+ && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_HIGH (op) + 0x1000) < 0x2000)
+ || (TARGET_ARCH64
+ && GET_CODE (op) == CONST_DOUBLE
+ && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
+ && ((CONST_DOUBLE_HIGH (op) == -1
+ && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000)
+ || (CONST_DOUBLE_HIGH (op) == 0
+ && (CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
+}
+
+/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
+ can fit in an 11 bit immediate field. This is an acceptable DImode
+ operand for the movcc instructions. */
+/* ??? Replace with arith11_operand? */
+
+int
+arith11_double_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (register_operand (op, mode)
+ || GET_CODE (op) == CONSTANT_P_RTX
+ || (GET_CODE (op) == CONST_DOUBLE
+ && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
+ && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x400) < 0x800
+ && ((CONST_DOUBLE_HIGH (op) == -1
+ && (CONST_DOUBLE_LOW (op) & 0x400) == 0x400)
+ || (CONST_DOUBLE_HIGH (op) == 0
+ && (CONST_DOUBLE_LOW (op) & 0x400) == 0)))
+ || (GET_CODE (op) == CONST_INT
+ && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
+ && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x400) < 0x800));
+}
+
+/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
+ can fit in an 10 bit immediate field. This is an acceptable DImode
+ operand for the movrcc instructions. */
+/* ??? Replace with arith10_operand? */
+
+int
+arith10_double_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return (register_operand (op, mode)
+ || GET_CODE (op) == CONSTANT_P_RTX
+ || (GET_CODE (op) == CONST_DOUBLE
+ && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
+ && (unsigned) (CONST_DOUBLE_LOW (op) + 0x200) < 0x400
+ && ((CONST_DOUBLE_HIGH (op) == -1
+ && (CONST_DOUBLE_LOW (op) & 0x200) == 0x200)
+ || (CONST_DOUBLE_HIGH (op) == 0
+ && (CONST_DOUBLE_LOW (op) & 0x200) == 0)))
+ || (GET_CODE (op) == CONST_INT
+ && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
+ && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x200) < 0x400));
+}
+
+/* Return truth value of whether OP is a integer which fits the
+ range constraining immediate operands in most three-address insns,
+ which have a 13 bit immediate field. */
+
+int
+small_int (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return ((GET_CODE (op) == CONST_INT && SMALL_INT (op))
+ || GET_CODE (op) == CONSTANT_P_RTX);
+}
+
+/* Recognize operand values for the umul instruction. That instruction sign
+ extends immediate values just like all other sparc instructions, but
+ interprets the extended result as an unsigned number. */
+
+int
+uns_small_int (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+#if HOST_BITS_PER_WIDE_INT > 32
+ /* All allowed constants will fit a CONST_INT. */
+ return ((GET_CODE (op) == CONST_INT
+ && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000)
+ || (INTVAL (op) >= 0xFFFFF000 && INTVAL (op) < 0x100000000L)))
+ || GET_CODE (op) == CONSTANT_P_RTX);
+#else
+ return (((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000)
+ || (GET_CODE (op) == CONST_DOUBLE
+ && CONST_DOUBLE_HIGH (op) == 0
+ && (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000))
+ || GET_CODE (op) == CONSTANT_P_RTX);
+#endif
+}
+
+int
+uns_arith_operand (op, mode)
+ rtx op;
+ enum machine_mode mode;
+{
+ return register_operand (op, mode) || uns_small_int (op, mode);
+}
+
+/* Return truth value of statement that OP is a call-clobbered register. */
+int
+clobbered_register (op, mode)
+ rtx op;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+ return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
+}
+
+/* X and Y are two things to compare using CODE. Emit the compare insn and
+ return the rtx for the cc reg in the proper mode. */
+
+rtx
+gen_compare_reg (code, x, y)
+ enum rtx_code code;
+ rtx x, y;
+{
+ enum machine_mode mode = SELECT_CC_MODE (code, x, y);
+ rtx cc_reg;
+
+ /* ??? We don't have movcc patterns so we cannot generate pseudo regs for the
+ fcc regs (cse can't tell they're really call clobbered regs and will
+ remove a duplicate comparison even if there is an intervening function
+ call - it will then try to reload the cc reg via an int reg which is why
+ we need the movcc patterns). It is possible to provide the movcc
+ patterns by using the ldxfsr/stxfsr v9 insns. I tried it: you need two
+ registers (say %g1,%g5) and it takes about 6 insns. A better fix would be
+ to tell cse that CCFPE mode registers (even pseudos) are call
+ clobbered. */
+
+ /* ??? This is an experiment. Rather than making changes to cse which may
+ or may not be easy/clean, we do our own cse. This is possible because
+ we will generate hard registers. Cse knows they're call clobbered (it
+ doesn't know the same thing about pseudos). If we guess wrong, no big
+ deal, but if we win, great! */
+
+ if (TARGET_V9 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+#if 1 /* experiment */
+ {
+ int reg;
+ /* We cycle through the registers to ensure they're all exercised. */
+ static int next_fcc_reg = 0;
+ /* Previous x,y for each fcc reg. */
+ static rtx prev_args[4][2];
+
+ /* Scan prev_args for x,y. */
+ for (reg = 0; reg < 4; reg++)
+ if (prev_args[reg][0] == x && prev_args[reg][1] == y)
+ break;
+ if (reg == 4)
+ {
+ reg = next_fcc_reg;
+ prev_args[reg][0] = x;
+ prev_args[reg][1] = y;
+ next_fcc_reg = (next_fcc_reg + 1) & 3;
+ }
+ cc_reg = gen_rtx_REG (mode, reg + SPARC_FIRST_V9_FCC_REG);
+ }
+#else
+ cc_reg = gen_reg_rtx (mode);
+#endif /* ! experiment */
+ else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
+ cc_reg = gen_rtx_REG (mode, SPARC_FCC_REG);
+ else
+ cc_reg = gen_rtx_REG (mode, SPARC_ICC_REG);
+
+ if (TARGET_V8PLUS && mode == CCXmode)
+ {
+ emit_insn (gen_cmpdi_v8plus (x, y));
+ }
+ else
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
+ gen_rtx_COMPARE (mode, x, y)));
+ }
+
+ return cc_reg;
+}
+
+/* This function is used for v9 only.
+ CODE is the code for an Scc's comparison.
+ OPERANDS[0] is the target of the Scc insn.
+ OPERANDS[1] is the value we compare against const0_rtx (which hasn't
+ been generated yet).
+
+ This function is needed to turn
+
+ (set (reg:SI 110)
+ (gt (reg:CCX 100 %icc)
+ (const_int 0)))
+ into
+ (set (reg:SI 110)
+ (gt:DI (reg:CCX 100 %icc)
+ (const_int 0)))
+
+ IE: The instruction recognizer needs to see the mode of the comparison to
+ find the right instruction. We could use "gt:DI" right in the
+ define_expand, but leaving it out allows us to handle DI, SI, etc.
+
+ We refer to the global sparc compare operands sparc_compare_op0 and
+ sparc_compare_op1. */
+
+int
+gen_v9_scc (compare_code, operands)
+ enum rtx_code compare_code;
+ register rtx *operands;
+{
+ rtx temp, op0, op1;
+
+ if (! TARGET_ARCH64
+ && (GET_MODE (sparc_compare_op0) == DImode
+ || GET_MODE (operands[0]) == DImode))
+ return 0;
+
+ /* Handle the case where operands[0] == sparc_compare_op0.
+ We "early clobber" the result. */
+ if (REGNO (operands[0]) == REGNO (sparc_compare_op0))
+ {
+ op0 = gen_reg_rtx (GET_MODE (sparc_compare_op0));
+ emit_move_insn (op0, sparc_compare_op0);
+ }
+ else
+ op0 = sparc_compare_op0;
+ /* For consistency in the following. */
+ op1 = sparc_compare_op1;
+
+ /* Try to use the movrCC insns. */
+ if (TARGET_ARCH64
+ && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+ && op1 == const0_rtx
+ && v9_regcmp_p (compare_code))
+ {
+ /* Special case for op0 != 0. This can be done with one instruction if
+ operands[0] == sparc_compare_op0. We don't assume they are equal
+ now though. */
+
+ if (compare_code == NE
+ && GET_MODE (operands[0]) == DImode
+ && GET_MODE (op0) == DImode)
+ {
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], op0));
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_IF_THEN_ELSE (DImode,
+ gen_rtx_fmt_ee (compare_code, DImode,
+ op0, const0_rtx),
+ const1_rtx,
+ operands[0])));
+ return 1;
+ }
+
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx));
+ if (GET_MODE (op0) != DImode)
+ {
+ temp = gen_reg_rtx (DImode);
+ convert_move (temp, op0, 0);
+ }
+ else
+ temp = op0;
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+ gen_rtx_fmt_ee (compare_code, DImode,
+ temp, const0_rtx),
+ const1_rtx,
+ operands[0])));
+ return 1;
+ }
+ else
+ {
+ operands[1] = gen_compare_reg (compare_code, op0, op1);
+
+ switch (GET_MODE (operands[1]))
+ {
+ case CCmode :
+ case CCXmode :
+ case CCFPEmode :
+ case CCFPmode :
+ break;
+ default :
+ abort ();
+ }
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx));
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+ gen_rtx_fmt_ee (compare_code,
+ GET_MODE (operands[1]),
+ operands[1], const0_rtx),
+ const1_rtx, operands[0])));
+ return 1;
+ }
+}
+
+/* Emit a conditional jump insn for the v9 architecture using comparison code
+ CODE and jump target LABEL.
+ This function exists to take advantage of the v9 brxx insns. */
+
+void
+emit_v9_brxx_insn (code, op0, label)
+ enum rtx_code code;
+ rtx op0, label;
+{
+ emit_jump_insn (gen_rtx_SET (VOIDmode,
+ pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode,
+ gen_rtx_fmt_ee (code, GET_MODE (op0),
+ op0, const0_rtx),
+ gen_rtx_LABEL_REF (VOIDmode, label),
+ pc_rtx)));
+}
+
+/* Return nonzero if a return peephole merging return with
+ setting of output register is ok. */
+int
+leaf_return_peephole_ok ()
+{
+ return (actual_fsize == 0);
+}
+
+/* Return nonzero if TRIAL can go into the function epilogue's
+ delay slot. SLOT is the slot we are trying to fill. */
+
+int
+eligible_for_epilogue_delay (trial, slot)
+ rtx trial;
+ int slot;
+{
+ rtx pat, src;
+
+ if (slot >= 1)
+ return 0;
+
+ if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
+ return 0;
+
+ if (get_attr_length (trial) != 1)
+ return 0;
+
+ /* If %g0 is live, there are lots of things we can't handle.
+ Rather than trying to find them all now, let's punt and only
+ optimize things as necessary. */
+ if (TARGET_LIVE_G0)
+ return 0;
+
+ /* In the case of a true leaf function, anything can go into the delay slot.
+ A delay slot only exists however if the frame size is zero, otherwise
+ we will put an insn to adjust the stack after the return. */
+ if (leaf_function)
+ {
+ if (leaf_return_peephole_ok ())
+ return ((get_attr_in_uncond_branch_delay (trial)
+ == IN_BRANCH_DELAY_TRUE));
+ return 0;
+ }
+
+ /* If only trivial `restore' insns work, nothing can go in the
+ delay slot. */
+ else if (TARGET_BROKEN_SAVERESTORE)
+ return 0;
+
+ pat = PATTERN (trial);
+
+ /* Otherwise, only operations which can be done in tandem with
+ a `restore' insn can go into the delay slot. */
+ if (GET_CODE (SET_DEST (pat)) != REG
+ || REGNO (SET_DEST (pat)) >= 32
+ || REGNO (SET_DEST (pat)) < 24)
+ return 0;
+
+ /* The set of insns matched here must agree precisely with the set of
+ patterns paired with a RETURN in sparc.md. */
+
+ src = SET_SRC (pat);
+
+ /* This matches "*return_[qhs]i". */
+ if (arith_operand (src, GET_MODE (src)))
+ return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
+
+ /* This matches "*return_di". */
+ else if (arith_double_operand (src, GET_MODE (src)))
+ return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
+
+ /* This matches "*return_sf_no_fpu". */
+ else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode)
+ && register_operand (src, SFmode))
+ return 1;
+
+ /* This matches "*return_addsi". */
+ else if (GET_CODE (src) == PLUS
+ && arith_operand (XEXP (src, 0), SImode)
+ && arith_operand (XEXP (src, 1), SImode)
+ && (register_operand (XEXP (src, 0), SImode)
+ || register_operand (XEXP (src, 1), SImode)))
+ return 1;
+
+ /* This matches "*return_adddi". */
+ else if (GET_CODE (src) == PLUS
+ && arith_double_operand (XEXP (src, 0), DImode)
+ && arith_double_operand (XEXP (src, 1), DImode)
+ && (register_operand (XEXP (src, 0), DImode)
+ || register_operand (XEXP (src, 1), DImode)))
+ return 1;
+
+ return 0;
+}
+
+static int
+check_return_regs (x)
+ rtx x;
+{
+ switch (GET_CODE (x))
+ {
+ case REG:
+ return IN_OR_GLOBAL_P (x);
+
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return 1;
+
+ case SET:
+ case IOR:
+ case AND:
+ case XOR:
+ case PLUS:
+ case MINUS:
+ if (check_return_regs (XEXP (x, 1)) == 0)
+ return 0;
+ case NOT:
+ case NEG:
+ case MEM:
+ return check_return_regs (XEXP (x, 0));
+
+ default:
+ return 0;
+ }
+
+}
+
+/* Return 1 if TRIAL references only in and global registers. */
+int
+eligible_for_return_delay (trial)
+ rtx trial;
+{
+ if (GET_CODE (PATTERN (trial)) != SET)
+ return 0;
+
+ return check_return_regs (PATTERN (trial));
+}
+
+int
+short_branch (uid1, uid2)
+ int uid1, uid2;
+{
+ unsigned int delta = insn_addresses[uid1] - insn_addresses[uid2];
+ if (delta + 1024 < 2048)
+ return 1;
+ /* warning ("long branch, distance %d", delta); */
+ return 0;
+}
+
+/* Return non-zero if REG is not used after INSN.
+ We assume REG is a reload reg, and therefore does
+ not live past labels or calls or jumps. */
+int
+reg_unused_after (reg, insn)
+ rtx reg;
+ rtx insn;
+{
+ enum rtx_code code, prev_code = UNKNOWN;
+
+ while ((insn = NEXT_INSN (insn)))
+ {
+ if (prev_code == CALL_INSN && call_used_regs[REGNO (reg)])
+ return 1;
+
+ code = GET_CODE (insn);
+ if (GET_CODE (insn) == CODE_LABEL)
+ return 1;
+
+ if (GET_RTX_CLASS (code) == 'i')
+ {
+ rtx set = single_set (insn);
+ int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set));
+ if (set && in_src)
+ return 0;
+ if (set && reg_overlap_mentioned_p (reg, SET_DEST (set)))
+ return 1;
+ if (set == 0 && reg_overlap_mentioned_p (reg, PATTERN (insn)))
+ return 0;
+ }
+ prev_code = code;
+ }
+ return 1;
+}
+
+/* The table we use to reference PIC data. */
+static rtx global_offset_table;
+
+/* The function we use to get at it. */
+static rtx get_pc_symbol;
+static char get_pc_symbol_name[256];
+
+/* Ensure that we are not using patterns that are not OK with PIC. */
+
+int
+check_pic (i)
+ int i;
+{
+ switch (flag_pic)
+ {
+ case 1:
+ if (GET_CODE (recog_operand[i]) == SYMBOL_REF
+ || (GET_CODE (recog_operand[i]) == CONST
+ && ! (GET_CODE (XEXP (recog_operand[i], 0)) == MINUS
+ && (XEXP (XEXP (recog_operand[i], 0), 0)
+ == global_offset_table)
+ && (GET_CODE (XEXP (XEXP (recog_operand[i], 0), 1))
+ == CONST))))
+ abort ();
+ case 2:
+ default:
+ return 1;
+ }
+}
+
+/* Return true if X is an address which needs a temporary register when
+ reloaded while generating PIC code. */
+
+int
+pic_address_needs_scratch (x)
+ rtx x;
+{
+ /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
+ if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && ! SMALL_INT (XEXP (XEXP (x, 0), 1)))
+ return 1;
+
+ return 0;
+}
+
+/* Legitimize PIC addresses. If the address is already position-independent,
+ we return ORIG. Newly generated position-independent addresses go into a
+ reg. This is REG if non zero, otherwise we allocate register(s) as
+ necessary. */
+
+rtx
+legitimize_pic_address (orig, mode, reg)
+ rtx orig;
+ enum machine_mode mode ATTRIBUTE_UNUSED;
+ rtx reg;
+{
+ if (GET_CODE (orig) == SYMBOL_REF
+ || GET_CODE (orig) == LABEL_REF)
+ {
+ rtx pic_ref, address;
+ rtx insn;
+
+ if (reg == 0)
+ {
+ if (reload_in_progress || reload_completed)
+ abort ();
+ else
+ reg = gen_reg_rtx (Pmode);
+ }
+
+ if (flag_pic == 2)
+ {
+ /* If not during reload, allocate another temp reg here for loading
+ in the address, so that these instructions can be optimized
+ properly. */
+ rtx temp_reg = ((reload_in_progress || reload_completed)
+ ? reg : gen_reg_rtx (Pmode));
+
+ /* Must put the SYMBOL_REF inside an UNSPEC here so that cse
+ won't get confused into thinking that these two instructions
+ are loading in the true address of the symbol. If in the
+ future a PIC rtx exists, that should be used instead. */
+ emit_insn (gen_pic_sethi_si (temp_reg, orig));
+ emit_insn (gen_pic_lo_sum_si (temp_reg, temp_reg, orig));
+
+ address = temp_reg;
+ }
+ else
+ address = orig;
+
+ pic_ref = gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode,
+ pic_offset_table_rtx, address));
+ current_function_uses_pic_offset_table = 1;
+ RTX_UNCHANGING_P (pic_ref) = 1;
+ insn = emit_move_insn (reg, pic_ref);
+ /* Put a REG_EQUAL note on this insn, so that it can be optimized
+ by loop. */
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
+ REG_NOTES (insn));
+ return reg;
+ }
+ else if (GET_CODE (orig) == CONST)
+ {
+ rtx base, offset;
+
+ if (GET_CODE (XEXP (orig, 0)) == PLUS
+ && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
+ return orig;
+
+ if (reg == 0)
+ {
+ if (reload_in_progress || reload_completed)
+ abort ();
+ else
+ reg = gen_reg_rtx (Pmode);
+ }
+
+ if (GET_CODE (XEXP (orig, 0)) == PLUS)
+ {
+ base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
+ offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
+ base == reg ? 0 : reg);
+ }
+ else
+ abort ();
+
+ if (GET_CODE (offset) == CONST_INT)
+ {
+ if (SMALL_INT (offset))
+ return plus_constant_for_output (base, INTVAL (offset));
+ else if (! reload_in_progress && ! reload_completed)
+ offset = force_reg (Pmode, offset);
+ else
+ /* If we reach here, then something is seriously wrong. */
+ abort ();
+ }
+ return gen_rtx_PLUS (Pmode, base, offset);
+ }
+
+ return orig;
+}
+
+/* Set up PIC-specific rtl. This should not cause any insns
+ to be emitted. */
+
+void
+initialize_pic ()
+{
+}
+
+/* Return the RTX for insns to set the PIC register. */
+
+static rtx
+pic_setup_code ()
+{
+ rtx seq;
+
+ start_sequence ();
+ emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
+ get_pc_symbol));
+ seq = gen_sequence ();
+ end_sequence ();
+
+ return seq;
+}
+
+/* Emit special PIC prologues and epilogues. */
+
+void
+finalize_pic ()
+{
+ /* Labels to get the PC in the prologue of this function. */
+ int orig_flag_pic = flag_pic;
+ rtx insn;
+
+ if (current_function_uses_pic_offset_table == 0)
+ return;
+
+ if (! flag_pic)
+ abort ();
+
+ /* If we havn't emitted the special get_pc helper function, do so now. */
+ if (get_pc_symbol_name[0] == 0)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (get_pc_symbol_name, "LGETPC", 0);
+
+ text_section ();
+ ASM_OUTPUT_ALIGN (asm_out_file, 3);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LGETPC", 0);
+ fputs ("\tretl\n\tadd %o7,%l7,%l7\n", asm_out_file);
+ }
+
+ /* Initialize every time through, since we can't easily
+ know this to be permanent. */
+ global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+ get_pc_symbol = gen_rtx_SYMBOL_REF (Pmode, get_pc_symbol_name);
+ flag_pic = 0;
+
+ emit_insn_after (pic_setup_code (), get_insns ());
+
+ /* Insert the code in each nonlocal goto receiver. */
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == UNSPEC_VOLATILE
+ && XINT (PATTERN (insn), 1) == 4)
+ emit_insn_after (pic_setup_code (), insn);
+
+ flag_pic = orig_flag_pic;
+
+ /* Need to emit this whether or not we obey regdecls,
+ since setjmp/longjmp can cause life info to screw up.
+ ??? In the case where we don't obey regdecls, this is not sufficient
+ since we may not fall out the bottom. */
+ emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+}
+
+/* Emit insns to move operands[1] into operands[0].
+
+ Return 1 if we have written out everything that needs to be done to
+ do the move. Otherwise, return 0 and the caller will emit the move
+ normally. */
+
+int
+emit_move_sequence (operands, mode)
+ rtx *operands;
+ enum machine_mode mode;
+{
+ register rtx operand0 = operands[0];
+ register rtx operand1 = operands[1];
+
+ if (CONSTANT_P (operand1) && flag_pic
+ && pic_address_needs_scratch (operand1))
+ operands[1] = operand1 = legitimize_pic_address (operand1, mode, 0);
+
+ /* Handle most common case first: storing into a register. */
+ if (register_operand (operand0, mode))
+ {
+ /* Integer constant to FP register. */
+ if (GET_CODE (operand0) == REG
+ && REGNO (operand0) >= 32
+ && REGNO (operand0) < FIRST_PSEUDO_REGISTER
+ && CONSTANT_P (operand1))
+ {
+ operand1 = validize_mem (force_const_mem (GET_MODE (operand0), operand1));
+ }
+
+ if (register_operand (operand1, mode)
+ || (GET_CODE (operand1) == CONST_INT && SMALL_INT (operand1))
+ || (GET_CODE (operand1) == CONST_DOUBLE
+ && arith_double_operand (operand1, DImode))
+ || (GET_CODE (operand1) == HIGH && GET_MODE (operand1) != DImode)
+ /* Only `general_operands' can come here, so MEM is ok. */
+ || GET_CODE (operand1) == MEM)
+ {
+ /* Run this case quickly. */
+ emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1));
+ return 1;
+ }
+ }
+ else if (GET_CODE (operand0) == MEM)
+ {
+ if (register_operand (operand1, mode)
+ || (operand1 == const0_rtx && ! TARGET_LIVE_G0))
+ {
+ /* Run this case quickly. */
+ emit_insn (gen_rtx_SET (VOIDmode, operand0, operand1));
+ return 1;
+ }
+ if (! reload_in_progress)
+ {
+ operands[0] = validize_mem (operand0);
+ operands[1] = operand1 = force_reg (mode, operand1);
+ }
+ }
+
+ /* DImode HIGH values in sparc64 need a clobber added. */
+ if (TARGET_ARCH64
+ && GET_CODE (operand1) == HIGH && GET_MODE (operand1) == DImode)
+ {
+ emit_insn (gen_sethi_di_sp64 (operand0, XEXP (operand1, 0)));
+ return 1;
+ }
+ /* Simplify the source if we need to. */
+ else if (GET_CODE (operand1) != HIGH && immediate_operand (operand1, mode))
+ {
+ if (flag_pic && symbolic_operand (operand1, mode))
+ {
+ rtx temp_reg = reload_in_progress ? operand0 : 0;
+
+ operands[1] = legitimize_pic_address (operand1, mode, temp_reg);
+ }
+ else if (GET_CODE (operand1) == CONST_INT
+ ? (! SMALL_INT (operand1)
+ && INTVAL (operand1) != -4096
+ && ! SPARC_SETHI_P (INTVAL (operand1)))
+ : GET_CODE (operand1) == CONST_DOUBLE
+ ? ! arith_double_operand (operand1, DImode)
+ : 1)
+ {
+ /* For DImode values, temp must be operand0 because of the way
+ HI and LO_SUM work. The LO_SUM operator only copies half of
+ the LSW from the dest of the HI operator. If the LO_SUM dest is
+ not the same as the HI dest, then the MSW of the LO_SUM dest will
+ never be set.
+
+ ??? The real problem here is that the ...(HI:DImode pattern emits
+ multiple instructions, and the ...(LO_SUM:DImode pattern emits
+ one instruction. This fails, because the compiler assumes that
+ LO_SUM copies all bits of the first operand to its dest. Better
+ would be to have the HI pattern emit one instruction and the
+ LO_SUM pattern multiple instructions. Even better would be
+ to use four rtl insns. */
+ rtx temp = ((reload_in_progress || mode == DImode)
+ ? operand0 : gen_reg_rtx (mode));
+
+ if (mode == SImode)
+ {
+ if (GET_CODE (operand1) == CONST_INT)
+ operand1 = GEN_INT (INTVAL (operand1) & 0xffffffff);
+ else if (GET_CODE (operand1) == CONST_DOUBLE)
+ operand1 = GEN_INT (CONST_DOUBLE_LOW (operand1) & 0xffffffff);
+ }
+
+ if (TARGET_ARCH64 && mode == DImode)
+ emit_insn (gen_sethi_di_sp64 (temp, operand1));
+ else
+ emit_insn (gen_rtx_SET (VOIDmode, temp,
+ gen_rtx_HIGH (mode, operand1)));
+
+ operands[1] = gen_rtx_LO_SUM (mode, temp, operand1);
+ }
+ }
+
+ /* Now have insn-emit do whatever it normally does. */
+ return 0;
+}
+
+/* Return the best assembler insn template
+ for moving operands[1] into operands[0] as a 4 byte quantity.
+
+ This isn't intended to be very smart. It is up to the caller to
+ choose the best way to do things.
+
+ Note that OPERANDS may be modified to suit the returned string. */
+
+char *
+singlemove_string (operands)
+ rtx *operands;
+{
+ if (GET_CODE (operands[0]) == MEM)
+ {
+ if (GET_CODE (operands[1]) != MEM)
+ return "st %r1,%0";
+ else
+ abort ();
+ }
+ else if (GET_CODE (operands[1]) == MEM)
+ return "ld %1,%0";
+ else if (GET_CODE (operands[1]) == CONST_DOUBLE)
+ {
+ REAL_VALUE_TYPE r;
+ long i;
+
+ /* Must be SFmode, otherwise this doesn't make sense. */
+ if (GET_MODE (operands[1]) != SFmode)
+ abort ();
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
+ REAL_VALUE_TO_TARGET_SINGLE (r, i);
+ operands[1] = GEN_INT (i);
+
+ if (CONST_OK_FOR_LETTER_P (i, 'I'))
+ return "mov %1,%0";
+ else if ((i & 0x000003FF) != 0)
+ return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";
+ else
+ return "sethi %%hi(%a1),%0";
+ }
+ else if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ /* Only consider the low 32 bits of the constant. */
+ int i = INTVAL (operands[1]) & 0xffffffff;
+
+ if (SPARC_SIMM13_P (i))
+ return "mov %1,%0";
+
+ if (i == 4096)
+ return "sub %%g0,-4096,%0";
+
+ /* If all low order 10 bits are clear, then we only need a single
+ sethi insn to load the constant. */
+ /* FIXME: Use SETHI_P. */
+ if ((i & 0x000003FF) != 0)
+ return "sethi %%hi(%a1),%0\n\tor %0,%%lo(%a1),%0";
+ else
+ return "sethi %%hi(%a1),%0";
+ }
+ /* Operand 1 must be a register, or a 'I' type CONST_INT. */
+ return "mov %1,%0";
+}
+
+/* Return the best assembler insn template
+ for moving operands[1] into operands[0] as an 8 byte quantity.
+
+ This isn't intended to be very smart. It is up to the caller to
+ choose the best way to do things.
+
+ Note that OPERANDS may be modified to suit the returned string. */
+
+char *
+doublemove_string (operands)
+ rtx *operands;
+{
+ rtx op0 = operands[0], op1 = operands[1];
+
+ if (GET_CODE (op0) == MEM)
+ {
+ if (GET_CODE (op1) == REG)
+ {
+ if (FP_REG_P (op1))
+ return "std %1,%0";
+ return TARGET_ARCH64 ? "stx %1,%0" : "std %1,%0";
+ }
+ if (TARGET_ARCH64
+ && (op1 == const0_rtx
+ || (GET_MODE (op1) != VOIDmode
+ && op1 == CONST0_RTX (GET_MODE (op1)))))
+ return "stx %r1,%0";
+ abort ();
+ }
+ else if (GET_CODE (op1) == MEM)
+ {
+ if (GET_CODE (op0) != REG)
+ abort ();
+ if (FP_REG_P (op0))
+ return "ldd %1,%0";
+ return TARGET_ARCH64 ? "ldx %1,%0" : "ldd %1,%0";
+ }
+ else if (GET_CODE (operands[1]) == CONST_DOUBLE)
+ {
+ /* ??? Unfinished, and maybe not needed. */
+ abort ();
+ }
+ else if (GET_CODE (operands[1]) == CONST_INT
+ && ! CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'I'))
+ {
+ /* ??? Unfinished, and maybe not needed. */
+ abort ();
+ }
+ /* Operand 1 must be a register, or a 'I' type CONST_INT. */
+ return "mov %1,%0";
+}
+
+/* Return non-zero if it is OK to assume that the given memory operand is
+ aligned at least to a 8-byte boundary. This should only be called
+ for memory accesses whose size is 8 bytes or larger. */
+
+int
+mem_aligned_8 (mem)
+ register rtx mem;
+{
+ register rtx addr;
+ register rtx base;
+ register rtx offset;
+
+ if (GET_CODE (mem) != MEM)
+ return 0; /* It's gotta be a MEM! */
+
+ addr = XEXP (mem, 0);
+
+ /* Now that all misaligned double parms are copied on function entry,
+ we can assume any 64-bit object is 64-bit aligned except those which
+ are at unaligned offsets from the stack or frame pointer. If the
+ TARGET_UNALIGNED_DOUBLES switch is given, we do not make this
+ assumption. */
+
+ /* See what register we use in the address. */
+ base = offset = 0;
+ if (GET_CODE (addr) == PLUS)
+ {
+ if (GET_CODE (XEXP (addr, 0)) == REG
+ && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+ {
+ base = XEXP (addr, 0);
+ offset = XEXP (addr, 1);
+ }
+ }
+ else if (GET_CODE (addr) == REG)
+ {
+ base = addr;
+ offset = const0_rtx;
+ }
+
+ /* If it's the stack or frame pointer, check offset alignment.
+ We can have improper alignment in the function entry code. */
+ if (base
+ && (REGNO (base) == FRAME_POINTER_REGNUM
+ || REGNO (base) == STACK_POINTER_REGNUM))
+ {
+ if (((INTVAL (offset) - SPARC_STACK_BIAS) & 0x7) == 0)
+ return 1;
+ }
+ /* Anything else we know is properly aligned unless TARGET_UNALIGNED_DOUBLES
+ is true, in which case we can only assume that an access is aligned if
+ it is to a constant address, or the address involves a LO_SUM.
+
+ We used to assume an address was aligned if MEM_IN_STRUCT_P was true.
+ That assumption was deleted so that gcc generated code can be used with
+ memory allocators that only guarantee 4 byte alignment. */
+ else if (! TARGET_UNALIGNED_DOUBLES || CONSTANT_P (addr)
+ || GET_CODE (addr) == LO_SUM)
+ return 1;
+
+ /* An obviously unaligned address. */
+ return 0;
+}
+
+enum optype { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP };
+
+/* Output assembler code to perform a doubleword move insn
+ with operands OPERANDS. This is very similar to the following
+ output_move_quad function. */
+
+char *
+output_move_double (operands)
+ rtx *operands;
+{
+ register rtx op0 = operands[0];
+ register rtx op1 = operands[1];
+ register enum optype optype0;
+ register enum optype optype1;
+ rtx latehalf[2];
+ rtx addreg0 = 0;
+ rtx addreg1 = 0;
+ int highest_first = 0;
+ int no_addreg1_decrement = 0;
+
+ /* First classify both operands. */
+
+ if (REG_P (op0))
+ optype0 = REGOP;
+ else if (offsettable_memref_p (op0))
+ optype0 = OFFSOP;
+ else if (GET_CODE (op0) == MEM)
+ optype0 = MEMOP;
+ else
+ optype0 = RNDOP;
+
+ if (REG_P (op1))
+ optype1 = REGOP;
+ else if (CONSTANT_P (op1))
+ optype1 = CNSTOP;
+ else if (offsettable_memref_p (op1))
+ optype1 = OFFSOP;
+ else if (GET_CODE (op1) == MEM)
+ optype1 = MEMOP;
+ else
+ optype1 = RNDOP;
+
+ /* Check for the cases that the operand constraints are not
+ supposed to allow to happen. Abort if we get one,
+ because generating code for these cases is painful. */
+
+ if (optype0 == RNDOP || optype1 == RNDOP
+ || (optype0 == MEM && optype1 == MEM))
+ abort ();
+
+ /* If an operand is an unoffsettable memory ref, find a register
+ we can increment temporarily to make it refer to the second word. */
+
+ if (optype0 == MEMOP)
+ addreg0 = find_addr_reg (XEXP (op0, 0));
+
+ if (optype1 == MEMOP)
+ addreg1 = find_addr_reg (XEXP (op1, 0));
+
+ /* Ok, we can do one word at a time.
+ Set up in LATEHALF the operands to use for the
+ high-numbered (least significant) word and in some cases alter the
+ operands in OPERANDS to be suitable for the low-numbered word. */
+
+ if (optype0 == REGOP)
+ latehalf[0] = gen_rtx_REG (SImode, REGNO (op0) + 1);
+ else if (optype0 == OFFSOP)
+ latehalf[0] = adj_offsettable_operand (op0, 4);
+ else
+ latehalf[0] = op0;
+
+ if (optype1 == REGOP)
+ latehalf[1] = gen_rtx_REG (SImode, REGNO (op1) + 1);
+ else if (optype1 == OFFSOP)
+ latehalf[1] = adj_offsettable_operand (op1, 4);
+ else if (optype1 == CNSTOP)
+ {
+ if (TARGET_ARCH64)
+ {
+ if (arith_double_operand (op1, DImode))
+ {
+ operands[1] = GEN_INT (CONST_DOUBLE_LOW (op1));
+ return "mov %1,%0";
+ }
+ else
+ {
+ /* The only way to handle CONST_DOUBLEs or other 64 bit
+ constants here is to use a temporary, such as is done
+ for the V9 DImode sethi insn pattern. This is not
+ a practical solution, so abort if we reach here.
+ The md file should always force such constants to
+ memory. */
+ abort ();
+ }
+ }
+ else
+ split_double (op1, &operands[1], &latehalf[1]);
+ }
+ else
+ latehalf[1] = op1;
+
+ /* Easy case: try moving both words at once. Check for moving between
+ an even/odd register pair and a memory location. */
+ if ((optype0 == REGOP && optype1 != REGOP && optype1 != CNSTOP
+ && (TARGET_ARCH64 || (REGNO (op0) & 1) == 0))
+ || (optype0 != REGOP && optype0 != CNSTOP && optype1 == REGOP
+ && (TARGET_ARCH64 || (REGNO (op1) & 1) == 0)))
+ {
+ register rtx mem,reg;
+
+ if (optype0 == REGOP)
+ mem = op1, reg = op0;
+ else
+ mem = op0, reg = op1;
+
+ /* In v9, ldd can be used for word aligned addresses, so technically
+ some of this logic is unneeded. We still avoid ldd if the address
+ is obviously unaligned though.
+
+ Integer ldd/std are deprecated in V9 and are slow on UltraSPARC.
+ Use them only if the access is volatile or not offsettable. */
+
+ if ((mem_aligned_8 (mem)
+ && (REGNO (reg) >= 32
+ || MEM_VOLATILE_P (mem)
+ || ! ((optype0 == OFFSOP || optype1 == OFFSOP)
+ && (sparc_cpu == PROCESSOR_ULTRASPARC
+ || sparc_cpu == PROCESSOR_V9))))
+ /* If this is a floating point register higher than %f31,
+ then we *must* use an aligned load, since `ld' will not accept
+ the register number. */
+ || (TARGET_V9 && REGNO (reg) >= 64)
+ /* Even if two instructions would otherwise be better than ldd/std,
+ if this insn was put in a delay slot because reorg thought it
+ was only one machine instruction, make sure it is only one
+ instruction. */
+ || dbr_sequence_length () != 0)
+ {
+ if (FP_REG_P (reg) || ! TARGET_ARCH64)
+ return (mem == op1 ? "ldd %1,%0" : "std %1,%0");
+ else
+ return (mem == op1 ? "ldx %1,%0" : "stx %1,%0");
+ }
+ }
+
+ if (TARGET_ARCH64)
+ {
+ if (optype0 == REGOP && optype1 == REGOP)
+ {
+ if (FP_REG_P (op0))
+ return "fmovd %1,%0";
+ else
+ return "mov %1,%0";
+ }
+ }
+
+ /* If the first move would clobber the source of the second one,
+ do them in the other order. */
+
+ /* Overlapping registers. */
+ if (optype0 == REGOP && optype1 == REGOP
+ && REGNO (op0) == REGNO (latehalf[1]))
+ {
+ /* Do that word. */
+ output_asm_insn (singlemove_string (latehalf), latehalf);
+ /* Do low-numbered word. */
+ return singlemove_string (operands);
+ }
+ /* Loading into a register which overlaps a register used in the address. */
+ else if (optype0 == REGOP && optype1 != REGOP
+ && reg_overlap_mentioned_p (op0, op1))
+ {
+ /* If both halves of dest are used in the src memory address,
+ add the two regs and put them in the low reg (op0).
+ Then it works to load latehalf first. */
+ if (reg_mentioned_p (op0, XEXP (op1, 0))
+ && reg_mentioned_p (latehalf[0], XEXP (op1, 0)))
+ {
+ rtx xops[2];
+ xops[0] = latehalf[0];
+ xops[1] = op0;
+ output_asm_insn ("add %1,%0,%1", xops);
+ operands[1] = gen_rtx_MEM (DImode, op0);
+ latehalf[1] = adj_offsettable_operand (operands[1], 4);
+ addreg1 = 0;
+ highest_first = 1;
+ }
+ /* Only one register in the dest is used in the src memory address,
+ and this is the first register of the dest, so we want to do
+ the late half first here also. */
+ else if (! reg_mentioned_p (latehalf[0], XEXP (op1, 0)))
+ highest_first = 1;
+ /* Only one register in the dest is used in the src memory address,
+ and this is the second register of the dest, so we want to do
+ the late half last. If addreg1 is set, and addreg1 is the same
+ register as latehalf, then we must suppress the trailing decrement,
+ because it would clobber the value just loaded. */
+ else if (addreg1 && reg_mentioned_p (addreg1, latehalf[0]))
+ no_addreg1_decrement = 1;
+ }
+
+ /* Normal case: do the two words, low-numbered first.
+ Overlap case (highest_first set): do high-numbered word first. */
+
+ if (! highest_first)
+ output_asm_insn (singlemove_string (operands), operands);
+
+ /* Make any unoffsettable addresses point at high-numbered word. */
+ if (addreg0)
+ output_asm_insn ("add %0,0x4,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn ("add %0,0x4,%0", &addreg1);
+
+ /* Do that word. */
+ output_asm_insn (singlemove_string (latehalf), latehalf);
+
+ /* Undo the adds we just did. */
+ if (addreg0)
+ output_asm_insn ("add %0,-0x4,%0", &addreg0);
+ if (addreg1 && ! no_addreg1_decrement)
+ output_asm_insn ("add %0,-0x4,%0", &addreg1);
+
+ if (highest_first)
+ output_asm_insn (singlemove_string (operands), operands);
+
+ return "";
+}
+
+/* Output assembler code to perform a quadword move insn
+ with operands OPERANDS. This is very similar to the preceding
+ output_move_double function. */
+
+char *
+output_move_quad (operands)
+ rtx *operands;
+{
+ register rtx op0 = operands[0];
+ register rtx op1 = operands[1];
+ register enum optype optype0;
+ register enum optype optype1;
+ rtx wordpart[4][2];
+ rtx load_late[4];
+ int load_late_half[2];
+ rtx addreg0 = 0;
+ rtx addreg1 = 0;
+
+ load_late_half[0] = 0; load_late_half[1] = 0;
+ load_late[0] = 0; load_late[1] = 0; load_late[2] = 0;
+ load_late[3] = 0;
+
+ wordpart[0][0] = NULL; wordpart[1][0] = NULL; wordpart[2][0] = NULL;
+ wordpart[3][0] = NULL;
+
+ /* First classify both operands. */
+
+ if (REG_P (op0))
+ optype0 = REGOP;
+ else if (offsettable_memref_p (op0))
+ optype0 = OFFSOP;
+ else if (GET_CODE (op0) == MEM)
+ optype0 = MEMOP;
+ else
+ optype0 = RNDOP;
+
+ if (REG_P (op1))
+ optype1 = REGOP;
+ else if (CONSTANT_P (op1))
+ optype1 = CNSTOP;
+ else if (offsettable_memref_p (op1))
+ optype1 = OFFSOP;
+ else if (GET_CODE (op1) == MEM)
+ optype1 = MEMOP;
+ else
+ optype1 = RNDOP;
+
+ /* Check for the cases that the operand constraints are not
+ supposed to allow to happen. Abort if we get one,
+ because generating code for these cases is painful. */
+
+ if (optype0 == RNDOP || optype1 == RNDOP
+ || (optype0 == MEM && optype1 == MEM))
+ abort ();
+
+ if (optype0 == REGOP)
+ {
+ wordpart[0][0] = gen_rtx_REG (word_mode, REGNO (op0) + 0);
+ if (TARGET_ARCH64 && FP_REG_P (op0)
+ && REGNO (op0) < SPARC_FIRST_V9_FP_REG)
+ wordpart[1][0] = gen_rtx_REG (word_mode, REGNO (op0) + 2);
+ else
+ wordpart[1][0] = gen_rtx_REG (word_mode, REGNO (op0) + 1);
+
+ if (TARGET_ARCH32)
+ {
+ wordpart[2][0] = gen_rtx_REG (word_mode, REGNO (op0) + 2);
+ wordpart[3][0] = gen_rtx_REG (word_mode, REGNO (op0) + 3);
+ }
+
+ /* Loading into a register which overlaps a register used in the
+ address. */
+ if (optype1 != REGOP && reg_overlap_mentioned_p (op0, op1))
+ {
+ int i;
+ int count;
+
+ count = 0;
+
+ for (i = 0; i < 4 && wordpart[i][0] != NULL; i++)
+ {
+ if (reg_mentioned_p (wordpart[i][0], op1))
+ {
+ load_late[i] = wordpart[i][0];
+ load_late_half[TARGET_ARCH64 ? i : i/2] = 1;
+ count++;
+ }
+ }
+ if (count > 2)
+ {
+ /* Not sure what to do here. Multiple adds? Can't happen. */
+ abort ();
+ }
+ else if (count == 2)
+ {
+ /* We have a two-address source operand, and both registers
+ overlap with the dest quad. Add them together and
+ store the result into the last register of the quad being
+ loaded, then generate an appropriate MEM insn. */
+ rtx temp[3];
+ int place = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ if (load_late[i])
+ {
+ temp[place++] = load_late[i];
+ load_late[i] = 0;
+ }
+ }
+ temp[2] = wordpart[3][0];
+ output_asm_insn ("add %0, %1, %2", temp);
+ load_late_half[0] = 0;
+ load_late_half[1] = 1;
+ op1 = gen_rtx_MEM (TFmode, wordpart[3][0]);
+ operands[1] = op1;
+ optype1 = OFFSOP;
+ }
+ }
+ }
+
+ /* If an operand is an unoffsettable memory ref, find a register
+ we can increment temporarily to make it refer to the later words. */
+
+ if (optype0 == MEMOP)
+ addreg0 = find_addr_reg (XEXP (op0, 0));
+
+ if (optype1 == MEMOP)
+ addreg1 = find_addr_reg (XEXP (op1, 0));
+
+ /* Ok, we can do one word at a time.
+ Set up in wordpart the operands to use for each word of the arguments. */
+
+ if (optype0 == OFFSOP)
+ {
+ wordpart[0][0] = adj_offsettable_operand (op0, 0);
+ if (TARGET_ARCH32)
+ {
+ wordpart[1][0] = adj_offsettable_operand (op0, 4);
+ wordpart[2][0] = adj_offsettable_operand (op0, 8);
+ wordpart[3][0] = adj_offsettable_operand (op0, 12);
+ }
+ else
+ wordpart[1][0] = adj_offsettable_operand (op0, 8);
+ }
+ else if (optype0 != REGOP)
+ {
+ wordpart[0][0] = op0;
+ wordpart[1][0] = op0;
+ wordpart[2][0] = op0;
+ wordpart[3][0] = op0;
+ }
+
+ if (optype1 == REGOP)
+ {
+ wordpart[0][1] = gen_rtx_REG (word_mode, REGNO (op1) + 0);
+ if (TARGET_ARCH64 && FP_REG_P (op1)
+ && REGNO (op1) < SPARC_FIRST_V9_FP_REG)
+ wordpart[1][1] = gen_rtx_REG (word_mode, REGNO (op1) + 2);
+ else
+ wordpart[1][1] = gen_rtx_REG (word_mode, REGNO (op1) + 1);
+
+ if (TARGET_ARCH32)
+ {
+ wordpart[2][1] = gen_rtx_REG (word_mode, REGNO (op1) + 2);
+ wordpart[3][1] = gen_rtx_REG (word_mode, REGNO (op1) + 3);
+ }
+ }
+ else if (optype1 == OFFSOP)
+ {
+ wordpart[0][1] = adj_offsettable_operand (op1, 0);
+ if (TARGET_ARCH32)
+ {
+ wordpart[1][1] = adj_offsettable_operand (op1, 4);
+ wordpart[2][1] = adj_offsettable_operand (op1, 8);
+ wordpart[3][1] = adj_offsettable_operand (op1, 12);
+ }
+ else
+ wordpart[1][1] = adj_offsettable_operand (op1, 8);
+ }
+ else if (optype1 == CNSTOP)
+ {
+ REAL_VALUE_TYPE r;
+ long l[4];
+
+ /* This only works for TFmode floating point constants. */
+ if (GET_CODE (op1) != CONST_DOUBLE || GET_MODE (op1) != TFmode)
+ abort ();
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, op1);
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
+
+ wordpart[0][1] = GEN_INT (l[0]);
+ wordpart[1][1] = GEN_INT (l[1]);
+ wordpart[2][1] = GEN_INT (l[2]);
+ wordpart[3][1] = GEN_INT (l[3]);
+ }
+ else
+ {
+ wordpart[0][1] = op1;
+ wordpart[1][1] = op1;
+ wordpart[2][1] = op1;
+ wordpart[3][1] = op1;
+ }
+
+ /* Easy case: try moving the quad as two pairs. Check for moving between
+ an even/odd register pair and a memory location.
+ Also handle new v9 fp regs here. */
+ /* ??? Should also handle the case of non-offsettable addresses here.
+ We can at least do the first pair as a ldd/std, and then do the third
+ and fourth words individually. */
+ if ((optype0 == REGOP && optype1 == OFFSOP && (REGNO (op0) & 1) == 0)
+ || (optype0 == OFFSOP && optype1 == REGOP && (REGNO (op1) & 1) == 0))
+ {
+ rtx mem, reg;
+ int use_ldx;
+
+ if (optype0 == REGOP)
+ mem = op1, reg = op0;
+ else
+ mem = op0, reg = op1;
+
+ if (mem_aligned_8 (mem)
+ /* If this is a floating point register higher than %f31,
+ then we *must* use an aligned load, since `ld' will not accept
+ the register number. */
+ || (TARGET_V9 && REGNO (reg) >= SPARC_FIRST_V9_FP_REG))
+ {
+ static char * const mov_by_64[2][2][2] = {
+ { { "std %S1,%2;std %1,%0", "stx %R1,%2;stx %1,%0" },
+ { "ldd %2,%S0;ldd %1,%0", "ldx %2,%R0;ldx %1,%0" } },
+ { { "std %1,%0;std %S1,%2", "stx %1,%0;stx %R1,%2" },
+ { "ldd %1,%0;ldd %2,%S0", "ldx %1,%0;ldx %2,%R0" } }
+ };
+
+ if (TARGET_V9 && FP_REG_P (reg) && TARGET_HARD_QUAD)
+ {
+ /* Only abort if the register # requires that we use ldq. */
+ if ((REGNO (reg) & 3) == 0)
+ {
+ /* ??? Can `mem' have an inappropriate alignment here? */
+ return (mem == op1 ? "ldq %1,%0" : "stq %1,%0");
+ }
+ else
+ {
+ if (REGNO (reg) >= SPARC_FIRST_V9_FP_REG)
+ abort();
+ }
+ }
+ operands[2] = adj_offsettable_operand (mem, 8);
+
+ /* Do the loads in the right order; can't overwrite our address
+ register. */
+ use_ldx = TARGET_ARCH64 && !FP_REG_P (reg);
+ return mov_by_64[!load_late_half[0]][mem == op1][use_ldx];
+ }
+ }
+
+ /* If the first move would clobber the source of the second one,
+ do them in the other order. */
+
+ /* Overlapping registers? */
+ if (TARGET_ARCH32)
+ {
+ if (optype0 == REGOP && optype1 == REGOP
+ && (REGNO (op0) == REGNO (wordpart[1][3])
+ || REGNO (op0) == REGNO (wordpart[1][2])
+ || REGNO (op0) == REGNO (wordpart[1][1])))
+ {
+ /* Do fourth word. */
+ output_asm_insn (singlemove_string (wordpart[3]), wordpart[3]);
+ /* Do the third word. */
+ output_asm_insn (singlemove_string (wordpart[2]), wordpart[2]);
+ /* Do the second word. */
+ output_asm_insn (singlemove_string (wordpart[1]), wordpart[1]);
+ /* Do lowest-numbered word. */
+ output_asm_insn (singlemove_string (wordpart[0]), wordpart[0]);
+ return "";
+ }
+ }
+ else /* TARGET_ARCH64 */
+ {
+ if (optype0 == REGOP && optype1 == REGOP
+ && REGNO (op0) == REGNO (wordpart[1][1]))
+ {
+ output_asm_insn ("mov %1,%0", wordpart[1]);
+ output_asm_insn ("mov %1,%0", wordpart[0]);
+ return "";
+ }
+ }
+
+ /* Normal case: move the words in lowest to highest address order.
+ There may have an overlapping register; in that case, skip and go
+ back. */
+
+ if (TARGET_ARCH32)
+ {
+ int i;
+ int offset = 0xc;
+ rtx temp[2];
+
+ for (i = 0; i < 4; i++)
+ {
+ if (! load_late[i])
+ output_asm_insn (singlemove_string (wordpart[i]), wordpart[i]);
+
+ if (i != 3)
+ {
+ /* Make any unoffsettable addresses point at the next word. */
+ if (addreg0)
+ output_asm_insn ("add %0,0x4,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn ("add %0,0x4,%0", &addreg1);
+ }
+ }
+ for (i = 0; i < 4; i++)
+ {
+ if (load_late[i])
+ {
+ int fix = offset - i * 4;
+
+ /* Back up to the appropriate place. */
+ temp[1] = GEN_INT (-fix);
+ if (addreg0)
+ {
+ temp[0] = addreg0;
+ output_asm_insn ("add %0,%1,%0", temp);
+ }
+ if (addreg1)
+ {
+ temp[0] = addreg1;
+ output_asm_insn ("add %0,%1,%0", temp);
+ }
+ output_asm_insn (singlemove_string (wordpart[i]),
+ wordpart[i]);
+ /* Don't modify the register that's the destination of the
+ move. */
+ temp[0] = GEN_INT (-(offset - fix));
+ if (addreg0 && REGNO (addreg0) != REGNO (wordpart[i][0]))
+ {
+ temp[1] = addreg0;
+ output_asm_insn("add %0,%1,%0", temp);
+ }
+ if (addreg1 && REGNO (addreg1) != REGNO (wordpart[i][0]))
+ {
+ temp[1] = addreg1;
+ output_asm_insn("add %0,%1,%0",temp);
+ }
+ offset = 0;
+ break;
+ }
+ }
+ if (offset)
+ {
+ temp[1] = GEN_INT (-offset);
+ /* Undo the adds we just did. */
+ if (addreg0)
+ {
+ temp[0] = addreg0;
+ output_asm_insn ("add %0,%1,%0", temp);
+ }
+ if (addreg1)
+ {
+ temp[0] = addreg1;
+ output_asm_insn ("add %0,%1,%0", temp);
+ }
+ }
+ }
+ else /* TARGET_ARCH64 */
+ {
+ if (load_late_half[0])
+ {
+ /* Load the second half first. */
+ if (addreg0)
+ output_asm_insn ("add %0,0x8,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn ("add %0,0x8,%0", &addreg1);
+
+ output_asm_insn (doublemove_string (wordpart[1]), wordpart[1]);
+
+ /* Undo the adds we just did. */
+ if (addreg0)
+ output_asm_insn ("add %0,-0x8,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn ("add %0,-0x8,%0", &addreg1);
+
+ output_asm_insn (doublemove_string (wordpart[0]), wordpart[0]);
+ }
+ else
+ {
+ output_asm_insn (doublemove_string (wordpart[0]), wordpart[0]);
+
+ if (addreg0)
+ output_asm_insn ("add %0,0x8,%0", &addreg0);
+ if (addreg1)
+ output_asm_insn ("add %0,0x8,%0", &addreg1);
+
+ /* Do the second word. */
+ output_asm_insn (doublemove_string (wordpart[1]), wordpart[1]);
+
+ /* Undo the adds we just did. But don't modify the dest of
+ the move. */
+ if (addreg0 && REGNO (addreg0) != REGNO (wordpart[1][0]))
+ output_asm_insn ("add %0,-0x8,%0", &addreg0);
+ if (addreg1 && REGNO (addreg1) != REGNO (wordpart[1][0]))
+ output_asm_insn ("add %0,-0x8,%0", &addreg1);
+ }
+ }
+
+ return "";
+}
+
+/* Output assembler code to perform a doubleword move insn with operands
+ OPERANDS, one of which must be a floating point register. */
+
+char *
+output_fp_move_double (operands)
+ rtx *operands;
+{
+ if (FP_REG_P (operands[0]))
+ {
+ if (FP_REG_P (operands[1]))
+ {
+ if (TARGET_V9)
+ return "fmovd %1,%0";
+ else
+ return "fmovs %1,%0\n\tfmovs %R1,%R0";
+ }
+ else if (GET_CODE (operands[1]) == REG)
+ abort ();
+ else
+ return output_move_double (operands);
+ }
+ else if (FP_REG_P (operands[1]))
+ {
+ if (GET_CODE (operands[0]) == REG)
+ abort ();
+ else
+ return output_move_double (operands);
+ }
+ else abort ();
+}
+
+/* When doing a quad-register move, determine the drection in which
+ the move needs to be performed. SRC and DST are the source and
+ destination registers.
+
+ A value of -1 indicates that the move needs to be done from the
+ highest register to the lowest. */
+
+static int
+move_quad_direction (src, dst)
+ rtx src, dst;
+{
+ if ((REGNO (dst) > REGNO (src))
+ && (REGNO (dst) < (REGNO (src) + 4)))
+ return -1;
+ else
+ return 1;
+}
+
+/* Output assembler code to perform a quadword move insn with operands
+ OPERANDS, one of which must be a floating point register. */
+
+char *
+output_fp_move_quad (operands)
+ rtx *operands;
+{
+ register rtx op0 = operands[0];
+ register rtx op1 = operands[1];
+
+ if (FP_REG_P (op0))
+ {
+ if (FP_REG_P (op1))
+ {
+ if (TARGET_V9 && TARGET_HARD_QUAD)
+ return "fmovq %1,%0";
+ else if (TARGET_V9)
+ {
+ int dir = move_quad_direction (op1, op0);
+ if (dir > 0)
+ return "fmovd %1,%0\n\tfmovd %S1,%S0";
+ else
+ return "fmovd %S1,%S0\n\tfmovd %1,%0";
+ }
+ else
+ {
+ int dir = move_quad_direction (op0, op1);
+ if (dir > 0)
+ return "fmovs %1,%0\n\tfmovs %R1,%R0\n\tfmovs %S1,%S0\n\tfmovs %T1,%T0";
+ else
+ return "fmovs %T1,%T0\n\tfmovs %S1,%S0\n\tfmovs %R1,%R0\n\tfmovs %1,%0";
+ }
+ }
+ else if (GET_CODE (op1) == REG)
+ abort ();
+ else
+ return output_move_quad (operands);
+ }
+ else if (FP_REG_P (op1))
+ {
+ if (GET_CODE (op0) == REG)
+ abort ();
+ else
+ return output_move_quad (operands);
+ }
+ else
+ abort ();
+}
+
+/* Return a REG that occurs in ADDR with coefficient 1.
+ ADDR can be effectively incremented by incrementing REG. */
+
+static rtx
+find_addr_reg (addr)
+ rtx addr;
+{
+ while (GET_CODE (addr) == PLUS)
+ {
+ /* We absolutely can not fudge the frame pointer here, because the
+ frame pointer must always be 8 byte aligned. It also confuses
+ debuggers. */
+ if (GET_CODE (XEXP (addr, 0)) == REG
+ && REGNO (XEXP (addr, 0)) != FRAME_POINTER_REGNUM)
+ addr = XEXP (addr, 0);
+ else if (GET_CODE (XEXP (addr, 1)) == REG
+ && REGNO (XEXP (addr, 1)) != FRAME_POINTER_REGNUM)
+ addr = XEXP (addr, 1);
+ else if (CONSTANT_P (XEXP (addr, 0)))
+ addr = XEXP (addr, 1);
+ else if (CONSTANT_P (XEXP (addr, 1)))
+ addr = XEXP (addr, 0);
+ else
+ abort ();
+ }
+ if (GET_CODE (addr) == REG)
+ return addr;
+ abort ();
+}
+
+/* Output reasonable peephole for set-on-condition-code insns.
+ Note that these insns assume a particular way of defining
+ labels. Therefore, *both* sparc.h and this function must
+ be changed if a new syntax is needed. */
+
+char *
+output_scc_insn (operands, insn)
+ rtx operands[];
+ rtx insn;
+{
+ static char string[100];
+ rtx label = 0, next = insn;
+ int need_label = 0;
+
+ /* This code used to be called with final_sequence nonzero (for fpcc
+ delay slots), but that is no longer allowed. */
+ if (final_sequence)
+ abort ();
+
+ /* On UltraSPARC a conditional moves blocks until 3 cycles after prior loads
+ complete. It might be beneficial here to use branches if any recent
+ instructions were loads. */
+ if (TARGET_V9 && REGNO (operands[1]) == SPARC_ICC_REG)
+ return "mov 0,%0\n\tmov%C2 %x1,1,%0";
+
+ /* Try doing a jump optimization which jump.c can't do for us
+ because we did not expose that setcc works by using branches.
+
+ If this scc insn is followed by an unconditional branch, then have
+ the jump insn emitted here jump to that location, instead of to
+ the end of the scc sequence as usual. */
+
+ do
+ {
+ if (GET_CODE (next) == CODE_LABEL)
+ label = next;
+ next = NEXT_INSN (next);
+ }
+ while (next && (GET_CODE (next) == NOTE || GET_CODE (next) == CODE_LABEL));
+
+ if (next && GET_CODE (next) == JUMP_INSN && simplejump_p (next))
+ label = JUMP_LABEL (next);
+
+ /* If not optimizing, jump label fields are not set. To be safe, always
+ check here to whether label is still zero. */
+ if (label == 0)
+ {
+ label = gen_label_rtx ();
+ need_label = 1;
+ }
+
+ LABEL_NUSES (label) += 1;
+
+ /* operands[3] is an unused slot. */
+ operands[3] = label;
+
+ strcpy (string, output_cbranch (operands[2], 3, 0, 1, 0, 0));
+ strcat (string, "\n\tmov 1,%0\n\tmov 0,%0");
+
+ if (need_label)
+ strcat (string, "\n%l3:");
+
+ return string;
+}
+
+/* Vectors to keep interesting information about registers where it can easily
+ be got. We use to use the actual mode value as the bit number, but there
+ are more than 32 modes now. Instead we use two tables: one indexed by
+ hard register number, and one indexed by mode. */
+
+/* The purpose of sparc_mode_class is to shrink the range of modes so that
+ they all fit (as bit numbers) in a 32 bit word (again). Each real mode is
+ mapped into one sparc_mode_class mode. */
+
+enum sparc_mode_class {
+ S_MODE, D_MODE, T_MODE, O_MODE,
+ SF_MODE, DF_MODE, TF_MODE, OF_MODE,
+ CC_MODE, CCFP_MODE
+};
+
+/* Modes for single-word and smaller quantities. */
+#define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE))
+
+/* Modes for double-word and smaller quantities. */
+#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE))
+
+/* Modes for quad-word and smaller quantities. */
+#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
+
+/* Modes for single-float quantities. We must allow any single word or
+ smaller quantity. This is because the fix/float conversion instructions
+ take integer inputs/outputs from the float registers. */
+#define SF_MODES (S_MODES)
+
+/* Modes for double-float and smaller quantities. */
+#define DF_MODES (S_MODES | D_MODES)
+
+#define DF_MODES64 DF_MODES
+
+/* Modes for double-float only quantities. */
+#define DF_ONLY_MODES ((1 << (int) DF_MODE) | (1 << (int) D_MODE))
+
+/* Modes for double-float and larger quantities. */
+#define DF_UP_MODES (DF_ONLY_MODES | TF_ONLY_MODES)
+
+/* Modes for quad-float only quantities. */
+#define TF_ONLY_MODES (1 << (int) TF_MODE)
+
+/* Modes for quad-float and smaller quantities. */
+#define TF_MODES (DF_MODES | TF_ONLY_MODES)
+
+#define TF_MODES64 (DF_MODES64 | TF_ONLY_MODES)
+
+/* Modes for condition codes. */
+#define CC_MODES (1 << (int) CC_MODE)
+#define CCFP_MODES (1 << (int) CCFP_MODE)
+
+/* Value is 1 if register/mode pair is acceptable on sparc.
+ The funny mixture of D and T modes is because integer operations
+ do not specially operate on tetra quantities, so non-quad-aligned
+ registers can hold quadword quantities (except %o4 and %i4 because
+ they cross fixed registers). */
+
+/* This points to either the 32 bit or the 64 bit version. */
+int *hard_regno_mode_classes;
+
+static int hard_32bit_mode_classes[] = {
+ S_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
+ T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
+ T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
+ T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
+
+ TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
+ TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
+ TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
+ TF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
+
+ /* FP regs f32 to f63. Only the even numbered registers actually exist,
+ and none can hold SFmode/SImode values. */
+ DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+ DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+ DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+ DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+
+ /* %fcc[0123] */
+ CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
+
+ /* %icc */
+ CC_MODES
+};
+
+static int hard_64bit_mode_classes[] = {
+ D_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
+ T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
+ T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
+ T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
+
+ TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
+ TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
+ TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
+ TF_MODES64, SF_MODES, DF_MODES64, SF_MODES, TF_MODES64, SF_MODES, DF_MODES64, SF_MODES,
+
+ /* FP regs f32 to f63. Only the even numbered registers actually exist,
+ and none can hold SFmode/SImode values. */
+ DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+ DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+ DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+ DF_UP_MODES, 0, DF_ONLY_MODES, 0, DF_UP_MODES, 0, DF_ONLY_MODES, 0,
+
+ /* %fcc[0123] */
+ CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
+
+ /* %icc */
+ CC_MODES
+};
+
+int sparc_mode_class [NUM_MACHINE_MODES];
+
+enum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER];
+
+static void
+sparc_init_modes ()
+{
+ int i;
+
+ for (i = 0; i < NUM_MACHINE_MODES; i++)
+ {
+ switch (GET_MODE_CLASS (i))
+ {
+ case MODE_INT:
+ case MODE_PARTIAL_INT:
+ case MODE_COMPLEX_INT:
+ if (GET_MODE_SIZE (i) <= 4)
+ sparc_mode_class[i] = 1 << (int) S_MODE;
+ else if (GET_MODE_SIZE (i) == 8)
+ sparc_mode_class[i] = 1 << (int) D_MODE;
+ else if (GET_MODE_SIZE (i) == 16)
+ sparc_mode_class[i] = 1 << (int) T_MODE;
+ else if (GET_MODE_SIZE (i) == 32)
+ sparc_mode_class[i] = 1 << (int) O_MODE;
+ else
+ sparc_mode_class[i] = 0;
+ break;
+ case MODE_FLOAT:
+ case MODE_COMPLEX_FLOAT:
+ if (GET_MODE_SIZE (i) <= 4)
+ sparc_mode_class[i] = 1 << (int) SF_MODE;
+ else if (GET_MODE_SIZE (i) == 8)
+ sparc_mode_class[i] = 1 << (int) DF_MODE;
+ else if (GET_MODE_SIZE (i) == 16)
+ sparc_mode_class[i] = 1 << (int) TF_MODE;
+ else if (GET_MODE_SIZE (i) == 32)
+ sparc_mode_class[i] = 1 << (int) OF_MODE;
+ else
+ sparc_mode_class[i] = 0;
+ break;
+ case MODE_CC:
+ default:
+ /* mode_class hasn't been initialized yet for EXTRA_CC_MODES, so
+ we must explicitly check for them here. */
+ if (i == (int) CCFPmode || i == (int) CCFPEmode)
+ sparc_mode_class[i] = 1 << (int) CCFP_MODE;
+ else if (i == (int) CCmode || i == (int) CC_NOOVmode
+ || i == (int) CCXmode || i == (int) CCX_NOOVmode)
+ sparc_mode_class[i] = 1 << (int) CC_MODE;
+ else
+ sparc_mode_class[i] = 0;
+ break;
+ }
+ }
+
+ if (TARGET_ARCH64)
+ hard_regno_mode_classes = hard_64bit_mode_classes;
+ else
+ hard_regno_mode_classes = hard_32bit_mode_classes;
+
+ /* Initialize the array used by REGNO_REG_CLASS. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (i < 16 && TARGET_V8PLUS)
+ sparc_regno_reg_class[i] = I64_REGS;
+ else if (i < 32)
+ sparc_regno_reg_class[i] = GENERAL_REGS;
+ else if (i < 64)
+ sparc_regno_reg_class[i] = FP_REGS;
+ else if (i < 96)
+ sparc_regno_reg_class[i] = EXTRA_FP_REGS;
+ else if (i < 100)
+ sparc_regno_reg_class[i] = FPCC_REGS;
+ else
+ sparc_regno_reg_class[i] = NO_REGS;
+ }
+}
+
+/* Save non call used registers from LOW to HIGH at BASE+OFFSET.
+ N_REGS is the number of 4-byte regs saved thus far. This applies even to
+ v9 int regs as it simplifies the code. */
+
+static int
+save_regs (file, low, high, base, offset, n_regs, real_offset)
+ FILE *file;
+ int low, high;
+ char *base;
+ int offset;
+ int n_regs;
+ int real_offset;
+{
+ int i;
+
+ if (TARGET_ARCH64 && high <= 32)
+ {
+ for (i = low; i < high; i++)
+ {
+ if (regs_ever_live[i] && ! call_used_regs[i])
+ {
+ fprintf (file, "\tstx %s,[%s+%d]\n",
+ reg_names[i], base, offset + 4 * n_regs);
+ if (dwarf2out_do_frame ())
+ dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
+ n_regs += 2;
+ }
+ }
+ }
+ else
+ {
+ for (i = low; i < high; i += 2)
+ {
+ if (regs_ever_live[i] && ! call_used_regs[i])
+ {
+ if (regs_ever_live[i+1] && ! call_used_regs[i+1])
+ {
+ fprintf (file, "\tstd %s,[%s+%d]\n",
+ reg_names[i], base, offset + 4 * n_regs);
+ if (dwarf2out_do_frame ())
+ {
+ char *l = dwarf2out_cfi_label ();
+ dwarf2out_reg_save (l, i, real_offset + 4 * n_regs);
+ dwarf2out_reg_save (l, i+1, real_offset + 4 * n_regs + 4);
+ }
+ n_regs += 2;
+ }
+ else
+ {
+ fprintf (file, "\tst %s,[%s+%d]\n",
+ reg_names[i], base, offset + 4 * n_regs);
+ if (dwarf2out_do_frame ())
+ dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
+ n_regs += 2;
+ }
+ }
+ else
+ {
+ if (regs_ever_live[i+1] && ! call_used_regs[i+1])
+ {
+ fprintf (file, "\tst %s,[%s+%d]\n",
+ reg_names[i+1], base, offset + 4 * n_regs + 4);
+ if (dwarf2out_do_frame ())
+ dwarf2out_reg_save ("", i + 1, real_offset + 4 * n_regs + 4);
+ n_regs += 2;
+ }
+ }
+ }
+ }
+ return n_regs;
+}
+
+/* Restore non call used registers from LOW to HIGH at BASE+OFFSET.
+
+ N_REGS is the number of 4-byte regs saved thus far. This applies even to
+ v9 int regs as it simplifies the code. */
+
+static int
+restore_regs (file, low, high, base, offset, n_regs)
+ FILE *file;
+ int low, high;
+ char *base;
+ int offset;
+ int n_regs;
+{
+ int i;
+
+ if (TARGET_ARCH64 && high <= 32)
+ {
+ for (i = low; i < high; i++)
+ {
+ if (regs_ever_live[i] && ! call_used_regs[i])
+ fprintf (file, "\tldx [%s+%d], %s\n",
+ base, offset + 4 * n_regs, reg_names[i]),
+ n_regs += 2;
+ }
+ }
+ else
+ {
+ for (i = low; i < high; i += 2)
+ {
+ if (regs_ever_live[i] && ! call_used_regs[i])
+ if (regs_ever_live[i+1] && ! call_used_regs[i+1])
+ fprintf (file, "\tldd [%s+%d], %s\n",
+ base, offset + 4 * n_regs, reg_names[i]),
+ n_regs += 2;
+ else
+ fprintf (file, "\tld [%s+%d],%s\n",
+ base, offset + 4 * n_regs, reg_names[i]),
+ n_regs += 2;
+ else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
+ fprintf (file, "\tld [%s+%d],%s\n",
+ base, offset + 4 * n_regs + 4, reg_names[i+1]),
+ n_regs += 2;
+ }
+ }
+ return n_regs;
+}
+
+/* Static variables we want to share between prologue and epilogue. */
+
+/* Number of live general or floating point registers needed to be saved
+ (as 4-byte quantities). This is only done if TARGET_EPILOGUE. */
+static int num_gfregs;
+
+/* Compute the frame size required by the function. This function is called
+ during the reload pass and also by output_function_prologue(). */
+
+int
+compute_frame_size (size, leaf_function)
+ int size;
+ int leaf_function;
+{
+ int n_regs = 0, i;
+ int outgoing_args_size = (current_function_outgoing_args_size
+ + REG_PARM_STACK_SPACE (current_function_decl));
+
+ if (TARGET_EPILOGUE)
+ {
+ /* N_REGS is the number of 4-byte regs saved thus far. This applies
+ even to v9 int regs to be consistent with save_regs/restore_regs. */
+
+ if (TARGET_ARCH64)
+ {
+ for (i = 0; i < 8; i++)
+ if (regs_ever_live[i] && ! call_used_regs[i])
+ n_regs += 2;
+ }
+ else
+ {
+ for (i = 0; i < 8; i += 2)
+ if ((regs_ever_live[i] && ! call_used_regs[i])
+ || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
+ n_regs += 2;
+ }
+
+ for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2)
+ if ((regs_ever_live[i] && ! call_used_regs[i])
+ || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
+ n_regs += 2;
+ }
+
+ /* Set up values for use in `function_epilogue'. */
+ num_gfregs = n_regs;
+
+ if (leaf_function && n_regs == 0
+ && size == 0 && current_function_outgoing_args_size == 0)
+ {
+ actual_fsize = apparent_fsize = 0;
+ }
+ else
+ {
+ /* We subtract STARTING_FRAME_OFFSET, remember it's negative.
+ The stack bias (if any) is taken out to undo its effects. */
+ apparent_fsize = (size - STARTING_FRAME_OFFSET + SPARC_STACK_BIAS + 7) & -8;
+ apparent_fsize += n_regs * 4;
+ actual_fsize = apparent_fsize + ((outgoing_args_size + 7) & -8);
+ }
+
+ /* Make sure nothing can clobber our register windows.
+ If a SAVE must be done, or there is a stack-local variable,
+ the register window area must be allocated.
+ ??? For v8 we apparently need an additional 8 bytes of reserved space. */
+ if (leaf_function == 0 || size > 0)
+ actual_fsize += (16 * UNITS_PER_WORD) + (TARGET_ARCH64 ? 0 : 8);
+
+ return SPARC_STACK_ALIGN (actual_fsize);
+}
+
+/* Build a (32 bit) big number in a register. */
+/* ??? We may be able to use the set macro here too. */
+
+static void
+build_big_number (file, num, reg)
+ FILE *file;
+ int num;
+ char *reg;
+{
+ if (num >= 0 || ! TARGET_ARCH64)
+ {
+ fprintf (file, "\tsethi %%hi(%d),%s\n", num, reg);
+ if ((num & 0x3ff) != 0)
+ fprintf (file, "\tor %s,%%lo(%d),%s\n", reg, num, reg);
+ }
+ else /* num < 0 && TARGET_ARCH64 */
+ {
+ /* Sethi does not sign extend, so we must use a little trickery
+ to use it for negative numbers. Invert the constant before
+ loading it in, then use xor immediate to invert the loaded bits
+ (along with the upper 32 bits) to the desired constant. This
+ works because the sethi and immediate fields overlap. */
+ int asize = num;
+ int inv = ~asize;
+ int low = -0x400 + (asize & 0x3FF);
+
+ fprintf (file, "\tsethi %%hi(%d),%s\n\txor %s,%d,%s\n",
+ inv, reg, reg, low, reg);
+ }
+}
+
+/* Output code for the function prologue. */
+
+void
+output_function_prologue (file, size, leaf_function)
+ FILE *file;
+ int size;
+ int leaf_function;
+{
+ /* Need to use actual_fsize, since we are also allocating
+ space for our callee (and our own register save area). */
+ actual_fsize = compute_frame_size (size, leaf_function);
+
+ if (leaf_function)
+ {
+ frame_base_name = "%sp";
+ frame_base_offset = actual_fsize + SPARC_STACK_BIAS;
+ }
+ else
+ {
+ frame_base_name = "%fp";
+ frame_base_offset = SPARC_STACK_BIAS;
+ }
+
+ /* This is only for the human reader. */
+ fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START);
+
+ if (actual_fsize == 0)
+ /* do nothing. */ ;
+ else if (! leaf_function && ! TARGET_BROKEN_SAVERESTORE)
+ {
+ if (actual_fsize <= 4096)
+ fprintf (file, "\tsave %%sp,-%d,%%sp\n", actual_fsize);
+ else if (actual_fsize <= 8192)
+ {
+ fprintf (file, "\tsave %%sp,-4096,%%sp\n");
+ fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096);
+ }
+ else
+ {
+ build_big_number (file, -actual_fsize, "%g1");
+ fprintf (file, "\tsave %%sp,%%g1,%%sp\n");
+ }
+ }
+ else if (! leaf_function && TARGET_BROKEN_SAVERESTORE)
+ {
+ /* We assume the environment will properly handle or otherwise avoid
+ trouble associated with an interrupt occurring after the `save' or
+ trap occurring during it. */
+ fprintf (file, "\tsave\n");
+
+ if (actual_fsize <= 4096)
+ fprintf (file, "\tadd %%fp,-%d,%%sp\n", actual_fsize);
+ else if (actual_fsize <= 8192)
+ {
+ fprintf (file, "\tadd %%fp,-4096,%%sp\n");
+ fprintf (file, "\tadd %%fp,-%d,%%sp\n", actual_fsize - 4096);
+ }
+ else
+ {
+ build_big_number (file, -actual_fsize, "%g1");
+ fprintf (file, "\tadd %%fp,%%g1,%%sp\n");
+ }
+ }
+ else /* leaf function */
+ {
+ if (actual_fsize <= 4096)
+ fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize);
+ else if (actual_fsize <= 8192)
+ {
+ fprintf (file, "\tadd %%sp,-4096,%%sp\n");
+ fprintf (file, "\tadd %%sp,-%d,%%sp\n", actual_fsize - 4096);
+ }
+ else
+ {
+ build_big_number (file, -actual_fsize, "%g1");
+ fprintf (file, "\tadd %%sp,%%g1,%%sp\n");
+ }
+ }
+
+ if (dwarf2out_do_frame () && actual_fsize)
+ {
+ char *label = dwarf2out_cfi_label ();
+
+ /* The canonical frame address refers to the top of the frame. */
+ dwarf2out_def_cfa (label, (leaf_function ? STACK_POINTER_REGNUM
+ : FRAME_POINTER_REGNUM),
+ frame_base_offset);
+
+ if (! leaf_function)
+ {
+ /* Note the register window save. This tells the unwinder that
+ it needs to restore the window registers from the previous
+ frame's window save area at 0(cfa). */
+ dwarf2out_window_save (label);
+
+ /* The return address (-8) is now in %i7. */
+ dwarf2out_return_reg (label, 31);
+ }
+ }
+
+ /* If doing anything with PIC, do it now. */
+ if (! flag_pic)
+ fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START);
+
+ /* Call saved registers are saved just above the outgoing argument area. */
+ if (num_gfregs)
+ {
+ int offset, real_offset, n_regs;
+ char *base;
+
+ real_offset = -apparent_fsize;
+ offset = -apparent_fsize + frame_base_offset;
+ if (offset < -4096 || offset + num_gfregs * 4 > 4096)
+ {
+ /* ??? This might be optimized a little as %g1 might already have a
+ value close enough that a single add insn will do. */
+ /* ??? Although, all of this is probably only a temporary fix
+ because if %g1 can hold a function result, then
+ output_function_epilogue will lose (the result will get
+ clobbered). */
+ build_big_number (file, offset, "%g1");
+ fprintf (file, "\tadd %s,%%g1,%%g1\n", frame_base_name);
+ base = "%g1";
+ offset = 0;
+ }
+ else
+ {
+ base = frame_base_name;
+ }
+
+ n_regs = 0;
+ if (TARGET_EPILOGUE && ! leaf_function)
+ /* ??? Originally saved regs 0-15 here. */
+ n_regs = save_regs (file, 0, 8, base, offset, 0, real_offset);
+ else if (leaf_function)
+ /* ??? Originally saved regs 0-31 here. */
+ n_regs = save_regs (file, 0, 8, base, offset, 0, real_offset);
+ if (TARGET_EPILOGUE)
+ save_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs,
+ real_offset);
+ }
+
+ leaf_label = 0;
+ if (leaf_function && actual_fsize != 0)
+ {
+ /* warning ("leaf procedure with frame size %d", actual_fsize); */
+ if (! TARGET_EPILOGUE)
+ leaf_label = gen_label_rtx ();
+ }
+}
+
+/* Output code for the function epilogue. */
+
+void
+output_function_epilogue (file, size, leaf_function)
+ FILE *file;
+ int size ATTRIBUTE_UNUSED;
+ int leaf_function;
+{
+ char *ret;
+
+ if (leaf_label)
+ {
+ emit_label_after (leaf_label, get_last_insn ());
+ final_scan_insn (get_last_insn (), file, 0, 0, 1);
+ }
+
+#ifdef FUNCTION_BLOCK_PROFILER_EXIT
+ else if (profile_block_flag == 2)
+ {
+ FUNCTION_BLOCK_PROFILER_EXIT(file);
+ }
+#endif
+
+ else if (current_function_epilogue_delay_list == 0)
+ {
+ /* If code does not drop into the epilogue, do nothing. */
+ rtx insn = get_last_insn ();
+ if (GET_CODE (insn) == NOTE)
+ insn = prev_nonnote_insn (insn);
+ if (insn && GET_CODE (insn) == BARRIER)
+ return;
+ }
+
+ /* Restore any call saved registers. */
+ if (num_gfregs)
+ {
+ int offset, n_regs;
+ char *base;
+
+ offset = -apparent_fsize + frame_base_offset;
+ if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/)
+ {
+ build_big_number (file, offset, "%g1");
+ fprintf (file, "\tadd %s,%%g1,%%g1\n", frame_base_name);
+ base = "%g1";
+ offset = 0;
+ }
+ else
+ {
+ base = frame_base_name;
+ }
+
+ n_regs = 0;
+ if (TARGET_EPILOGUE && ! leaf_function)
+ /* ??? Originally saved regs 0-15 here. */
+ n_regs = restore_regs (file, 0, 8, base, offset, 0);
+ else if (leaf_function)
+ /* ??? Originally saved regs 0-31 here. */
+ n_regs = restore_regs (file, 0, 8, base, offset, 0);
+ if (TARGET_EPILOGUE)
+ restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs);
+ }
+
+ /* Work out how to skip the caller's unimp instruction if required. */
+ if (leaf_function)
+ ret = (SKIP_CALLERS_UNIMP_P ? "jmp %o7+12" : "retl");
+ else
+ ret = (SKIP_CALLERS_UNIMP_P ? "jmp %i7+12" : "ret");
+
+ if (TARGET_EPILOGUE || leaf_label)
+ {
+ int old_target_epilogue = TARGET_EPILOGUE;
+ target_flags &= ~old_target_epilogue;
+
+ if (! leaf_function)
+ {
+ /* If we wound up with things in our delay slot, flush them here. */
+ if (current_function_epilogue_delay_list)
+ {
+ rtx insn = emit_jump_insn_after (gen_rtx_RETURN (VOIDmode),
+ get_last_insn ());
+ PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2,
+ PATTERN (XEXP (current_function_epilogue_delay_list, 0)),
+ PATTERN (insn)));
+ final_scan_insn (insn, file, 1, 0, 1);
+ }
+ else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P)
+ fputs ("\treturn %i7+8\n\tnop\n", file);
+ else
+ fprintf (file, "\t%s\n\trestore\n", ret);
+ }
+ /* All of the following cases are for leaf functions. */
+ else if (current_function_epilogue_delay_list)
+ {
+ /* eligible_for_epilogue_delay_slot ensures that if this is a
+ leaf function, then we will only have insn in the delay slot
+ if the frame size is zero, thus no adjust for the stack is
+ needed here. */
+ if (actual_fsize != 0)
+ abort ();
+ fprintf (file, "\t%s\n", ret);
+ final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
+ file, 1, 0, 1);
+ }
+ /* Output 'nop' instead of 'sub %sp,-0,%sp' when no frame, so as to
+ avoid generating confusing assembly language output. */
+ else if (actual_fsize == 0)
+ fprintf (file, "\t%s\n\tnop\n", ret);
+ else if (actual_fsize <= 4096)
+ fprintf (file, "\t%s\n\tsub %%sp,-%d,%%sp\n", ret, actual_fsize);
+ else if (actual_fsize <= 8192)
+ fprintf (file, "\tsub %%sp,-4096,%%sp\n\t%s\n\tsub %%sp,-%d,%%sp\n",
+ ret, actual_fsize - 4096);
+ else if ((actual_fsize & 0x3ff) == 0)
+ fprintf (file, "\tsethi %%hi(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n",
+ actual_fsize, ret);
+ else
+ fprintf (file, "\tsethi %%hi(%d),%%g1\n\tor %%g1,%%lo(%d),%%g1\n\t%s\n\tadd %%sp,%%g1,%%sp\n",
+ actual_fsize, actual_fsize, ret);
+ target_flags |= old_target_epilogue;
+ }
+}
+
+/* Functions for handling argument passing.
+
+ For v8 the first six args are normally in registers and the rest are
+ pushed. Any arg that starts within the first 6 words is at least
+ partially passed in a register unless its data type forbids.
+
+ For v9, the argument registers are laid out as an array of 16 elements
+ and arguments are added sequentially. The first 6 int args and up to the
+ first 16 fp args (depending on size) are passed in regs.
+
+ Slot Stack Integral Float Float in structure Double Long Double
+ ---- ----- -------- ----- ------------------ ------ -----------
+ 15 [SP+248] %f31 %f30,%f31 %d30
+ 14 [SP+240] %f29 %f28,%f29 %d28 %q28
+ 13 [SP+232] %f27 %f26,%f27 %d26
+ 12 [SP+224] %f25 %f24,%f25 %d24 %q24
+ 11 [SP+216] %f23 %f22,%f23 %d22
+ 10 [SP+208] %f21 %f20,%f21 %d20 %q20
+ 9 [SP+200] %f19 %f18,%f19 %d18
+ 8 [SP+192] %f17 %f16,%f17 %d16 %q16
+ 7 [SP+184] %f15 %f14,%f15 %d14
+ 6 [SP+176] %f13 %f12,%f13 %d12 %q12
+ 5 [SP+168] %o5 %f11 %f10,%f11 %d10
+ 4 [SP+160] %o4 %f9 %f8,%f9 %d8 %q8
+ 3 [SP+152] %o3 %f7 %f6,%f7 %d6
+ 2 [SP+144] %o2 %f5 %f4,%f5 %d4 %q4
+ 1 [SP+136] %o1 %f3 %f2,%f3 %d2
+ 0 [SP+128] %o0 %f1 %f0,%f1 %d0 %q0
+
+ Here SP = %sp if -mno-stack-bias or %sp+stack_bias otherwise.
+
+ Integral arguments are always passed as 64 bit quantities appropriately
+ extended.
+
+ Passing of floating point values is handled as follows.
+ If a prototype is in scope:
+ If the value is in a named argument (i.e. not a stdarg function or a
+ value not part of the `...') then the value is passed in the appropriate
+ fp reg.
+ If the value is part of the `...' and is passed in one of the first 6
+ slots then the value is passed in the appropriate int reg.
+ If the value is part of the `...' and is not passed in one of the first 6
+ slots then the value is passed in memory.
+ If a prototype is not in scope:
+ If the value is one of the first 6 arguments the value is passed in the
+ appropriate integer reg and the appropriate fp reg.
+ If the value is not one of the first 6 arguments the value is passed in
+ the appropriate fp reg and in memory.
+ */
+
+/* Maximum number of int regs for args. */
+#define SPARC_INT_ARG_MAX 6
+/* Maximum number of fp regs for args. */
+#define SPARC_FP_ARG_MAX 16
+
+#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* Handle the INIT_CUMULATIVE_ARGS macro.
+ Initialize a variable CUM of type CUMULATIVE_ARGS
+ for a call to a function whose data type is FNTYPE.
+ For a library call, FNTYPE is 0. */
+
+void
+init_cumulative_args (cum, fntype, libname, indirect)
+ CUMULATIVE_ARGS *cum;
+ tree fntype;
+ tree libname ATTRIBUTE_UNUSED;
+ int indirect ATTRIBUTE_UNUSED;
+{
+ cum->words = 0;
+ cum->prototype_p = fntype && TYPE_ARG_TYPES (fntype);
+ cum->libcall_p = fntype == 0;
+}
+
+/* Compute the slot number to pass an argument in.
+ Returns the slot number or -1 if passing on the stack.
+
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ MODE is the argument's machine mode.
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis).
+ INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.
+ *PREGNO records the register number to use if scalar type.
+ *PPADDING records the amount of padding needed in words. */
+
+static int
+function_arg_slotno (cum, mode, type, named, incoming_p, pregno, ppadding)
+ const CUMULATIVE_ARGS *cum;
+ enum machine_mode mode;
+ tree type;
+ int named;
+ int incoming_p;
+ int *pregno;
+ int *ppadding;
+{
+ int regbase = (incoming_p
+ ? SPARC_INCOMING_INT_ARG_FIRST
+ : SPARC_OUTGOING_INT_ARG_FIRST);
+ int slotno = cum->words;
+ int regno;
+
+ *ppadding = 0;
+
+ if (type != 0 && TREE_ADDRESSABLE (type))
+ return -1;
+ if (TARGET_ARCH32
+ && type != 0 && mode == BLKmode
+ && TYPE_ALIGN (type) % PARM_BOUNDARY != 0)
+ return -1;
+
+ switch (mode)
+ {
+ case VOIDmode :
+ /* MODE is VOIDmode when generating the actual call.
+ See emit_call_1. */
+ return -1;
+
+ case QImode : case CQImode :
+ case HImode : case CHImode :
+ case SImode : case CSImode :
+ case DImode : case CDImode :
+ if (slotno >= SPARC_INT_ARG_MAX)
+ return -1;
+ regno = regbase + slotno;
+ break;
+
+ case SFmode : case SCmode :
+ case DFmode : case DCmode :
+ case TFmode : case TCmode :
+ if (TARGET_ARCH32)
+ {
+ if (slotno >= SPARC_INT_ARG_MAX)
+ return -1;
+ regno = regbase + slotno;
+ }
+ else
+ {
+ if ((mode == TFmode || mode == TCmode)
+ && (slotno & 1) != 0)
+ slotno++, *ppadding = 1;
+ if (TARGET_FPU && named)
+ {
+ if (slotno >= SPARC_FP_ARG_MAX)
+ return -1;
+ regno = SPARC_FP_ARG_FIRST + slotno * 2;
+ if (mode == SFmode)
+ regno++;
+ }
+ else
+ {
+ if (slotno >= SPARC_INT_ARG_MAX)
+ return -1;
+ regno = regbase + slotno;
+ }
+ }
+ break;
+
+ case BLKmode :
+ /* For sparc64, objects requiring 16 byte alignment get it. */
+ if (TARGET_ARCH64)
+ {
+ if (type && TYPE_ALIGN (type) == 128 && (slotno & 1) != 0)
+ slotno++, *ppadding = 1;
+ }
+
+ if (TARGET_ARCH32
+ || (type && TREE_CODE (type) == UNION_TYPE))
+ {
+ if (slotno >= SPARC_INT_ARG_MAX)
+ return -1;
+ regno = regbase + slotno;
+ }
+ else
+ {
+ tree field;
+ int intregs_p = 0, fpregs_p = 0;
+ /* The ABI obviously doesn't specify how packed
+ structures are passed. These are defined to be passed
+ in int regs if possible, otherwise memory. */
+ int packed_p = 0;
+
+ /* First see what kinds of registers we need. */
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
+ && TARGET_FPU)
+ fpregs_p = 1;
+ else
+ intregs_p = 1;
+ if (DECL_PACKED (field))
+ packed_p = 1;
+ }
+ }
+ if (packed_p || !named)
+ fpregs_p = 0, intregs_p = 1;
+
+ /* If all arg slots are filled, then must pass on stack. */
+ if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
+ return -1;
+ /* If there are only int args and all int arg slots are filled,
+ then must pass on stack. */
+ if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
+ return -1;
+ /* Note that even if all int arg slots are filled, fp members may
+ still be passed in regs if such regs are available.
+ *PREGNO isn't set because there may be more than one, it's up
+ to the caller to compute them. */
+ return slotno;
+ }
+ break;
+
+ default :
+ abort ();
+ }
+
+ *pregno = regno;
+ return slotno;
+}
+
+/* Handle recursive register counting for structure field layout. */
+
+struct function_arg_record_value_parms
+{
+ rtx ret;
+ int slotno, named, regbase;
+ int nregs, intoffset;
+};
+
+static void
+function_arg_record_value_1 (type, startbitpos, parms)
+ tree type;
+ int startbitpos;
+ struct function_arg_record_value_parms *parms;
+{
+ tree field;
+
+ /* The ABI obviously doesn't specify how packed structures are
+ passed. These are defined to be passed in int regs if possible,
+ otherwise memory. */
+ int packed_p = 0;
+
+ /* We need to compute how many registers are needed so we can
+ allocate the PARALLEL but before we can do that we need to know
+ whether there are any packed fields. If there are, int regs are
+ used regardless of whether there are fp values present. */
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
+ {
+ packed_p = 1;
+ break;
+ }
+ }
+
+ /* Compute how many registers we need. */
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ int bitpos = startbitpos;
+ if (DECL_FIELD_BITPOS (field))
+ bitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
+ /* ??? FIXME: else assume zero offset. */
+
+ if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
+ {
+ function_arg_record_value_1 (TREE_TYPE (field), bitpos, parms);
+ }
+ else if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
+ && TARGET_FPU
+ && ! packed_p
+ && parms->named)
+ {
+ if (parms->intoffset != -1)
+ {
+ int intslots, this_slotno;
+
+ intslots = (bitpos - parms->intoffset + BITS_PER_WORD - 1)
+ / BITS_PER_WORD;
+ this_slotno = parms->slotno + parms->intoffset
+ / BITS_PER_WORD;
+
+ intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
+ intslots = MAX (intslots, 0);
+ parms->nregs += intslots;
+ parms->intoffset = -1;
+ }
+
+ /* There's no need to check this_slotno < SPARC_FP_ARG MAX.
+ If it wasn't true we wouldn't be here. */
+ parms->nregs += 1;
+ }
+ else
+ {
+ if (parms->intoffset == -1)
+ parms->intoffset = bitpos;
+ }
+ }
+ }
+}
+
+/* Handle recursive structure field register assignment. */
+
+static void
+function_arg_record_value_3 (bitpos, parms)
+ int bitpos;
+ struct function_arg_record_value_parms *parms;
+{
+ enum machine_mode mode;
+ int regno, this_slotno, intslots, intoffset;
+ rtx reg;
+
+ if (parms->intoffset == -1)
+ return;
+ intoffset = parms->intoffset;
+ parms->intoffset = -1;
+
+ intslots = (bitpos - intoffset + BITS_PER_WORD - 1) / BITS_PER_WORD;
+ this_slotno = parms->slotno + intoffset / BITS_PER_WORD;
+
+ intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
+ if (intslots <= 0)
+ return;
+
+ /* If this is the trailing part of a word, only load that much into
+ the register. Otherwise load the whole register. Note that in
+ the latter case we may pick up unwanted bits. It's not a problem
+ at the moment but may wish to revisit. */
+
+ if (intoffset % BITS_PER_WORD != 0)
+ {
+ mode = mode_for_size (BITS_PER_WORD - intoffset%BITS_PER_WORD,
+ MODE_INT, 0);
+ }
+ else
+ mode = word_mode;
+
+ intoffset /= BITS_PER_UNIT;
+ do
+ {
+ regno = parms->regbase + this_slotno;
+ reg = gen_rtx_REG (mode, regno);
+ XVECEXP (parms->ret, 0, parms->nregs)
+ = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset));
+
+ this_slotno += 1;
+ intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
+ parms->nregs += 1;
+ intslots -= 1;
+ }
+ while (intslots > 0);
+}
+
+static void
+function_arg_record_value_2 (type, startbitpos, parms)
+ tree type;
+ int startbitpos;
+ struct function_arg_record_value_parms *parms;
+{
+ tree field;
+ int packed_p = 0;
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
+ {
+ packed_p = 1;
+ break;
+ }
+ }
+
+ for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+ {
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ int bitpos = startbitpos;
+ if (DECL_FIELD_BITPOS (field))
+ bitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
+ /* ??? FIXME: else assume zero offset. */
+
+ if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
+ {
+ function_arg_record_value_2 (TREE_TYPE (field), bitpos, parms);
+ }
+ else if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
+ && TARGET_FPU
+ && ! packed_p
+ && parms->named)
+ {
+ int this_slotno = parms->slotno + bitpos / BITS_PER_WORD;
+ rtx reg;
+
+ function_arg_record_value_3 (bitpos, parms);
+
+ reg = gen_rtx_REG (DECL_MODE (field),
+ (SPARC_FP_ARG_FIRST + this_slotno * 2
+ + (DECL_MODE (field) == SFmode
+ && (bitpos & 32) != 0)));
+ XVECEXP (parms->ret, 0, parms->nregs)
+ = gen_rtx_EXPR_LIST (VOIDmode, reg,
+ GEN_INT (bitpos / BITS_PER_UNIT));
+ parms->nregs += 1;
+ }
+ else
+ {
+ if (parms->intoffset == -1)
+ parms->intoffset = bitpos;
+ }
+ }
+ }
+}
+
+static rtx
+function_arg_record_value (type, mode, slotno, named, regbase)
+ tree type;
+ enum machine_mode mode;
+ int slotno, named, regbase;
+{
+ HOST_WIDE_INT typesize = int_size_in_bytes (type);
+ struct function_arg_record_value_parms parms;
+ int nregs;
+
+ parms.ret = NULL_RTX;
+ parms.slotno = slotno;
+ parms.named = named;
+ parms.regbase = regbase;
+
+ /* Compute how many registers we need. */
+ parms.nregs = 0;
+ parms.intoffset = 0;
+ function_arg_record_value_1 (type, 0, &parms);
+
+ if (parms.intoffset != -1)
+ {
+ int intslots, this_slotno;
+
+ intslots = (typesize*BITS_PER_UNIT - parms.intoffset + BITS_PER_WORD - 1)
+ / BITS_PER_WORD;
+ this_slotno = slotno + parms.intoffset / BITS_PER_WORD;
+
+ intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
+ intslots = MAX (intslots, 0);
+
+ parms.nregs += intslots;
+ }
+ nregs = parms.nregs;
+
+ /* Allocate the vector and handle some annoying special cases. */
+ if (nregs == 0)
+ {
+ /* ??? Empty structure has no value? Duh? */
+ if (typesize <= 0)
+ {
+ /* Though there's nothing really to store, return a word register
+ anyway so the rest of gcc doesn't go nuts. Returning a PARALLEL
+ leads to breakage due to the fact that there are zero bytes to
+ load. */
+ return gen_rtx_REG (mode, regbase);
+ }
+ else
+ {
+ /* ??? C++ has structures with no fields, and yet a size. Give up
+ for now and pass everything back in integer registers. */
+ nregs = (typesize + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ }
+ if (nregs + slotno > SPARC_INT_ARG_MAX)
+ nregs = SPARC_INT_ARG_MAX - slotno;
+ }
+ if (nregs == 0)
+ abort();
+
+ parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (nregs));
+
+ /* Fill in the entries. */
+ parms.nregs = 0;
+ parms.intoffset = 0;
+ function_arg_record_value_2 (type, 0, &parms);
+ function_arg_record_value_3 (typesize * BITS_PER_UNIT, &parms);
+
+ if (parms.nregs != nregs)
+ abort ();
+
+ return parms.ret;
+}
+
+/* Handle the FUNCTION_ARG macro.
+ Determine where to put an argument to a function.
+ Value is zero to push the argument on the stack,
+ or a hard register in which to store the argument.
+
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ MODE is the argument's machine mode.
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis).
+ INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG. */
+
+rtx
+function_arg (cum, mode, type, named, incoming_p)
+ const CUMULATIVE_ARGS *cum;
+ enum machine_mode mode;
+ tree type;
+ int named;
+ int incoming_p;
+{
+ int regbase = (incoming_p
+ ? SPARC_INCOMING_INT_ARG_FIRST
+ : SPARC_OUTGOING_INT_ARG_FIRST);
+ int slotno, regno, padding;
+ rtx reg;
+
+ slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
+ &regno, &padding);
+
+ if (slotno == -1)
+ return 0;
+
+ if (TARGET_ARCH32)
+ {
+ reg = gen_rtx_REG (mode, regno);
+ return reg;
+ }
+
+ /* v9 fp args in reg slots beyond the int reg slots get passed in regs
+ but also have the slot allocated for them.
+ If no prototype is in scope fp values in register slots get passed
+ in two places, either fp regs and int regs or fp regs and memory. */
+ if ((GET_MODE_CLASS (mode) == MODE_FLOAT
+ || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+ && SPARC_FP_REG_P (regno))
+ {
+ reg = gen_rtx_REG (mode, regno);
+ if (cum->prototype_p || cum->libcall_p)
+ {
+ /* "* 2" because fp reg numbers are recorded in 4 byte
+ quantities. */
+#if 0
+ /* ??? This will cause the value to be passed in the fp reg and
+ in the stack. When a prototype exists we want to pass the
+ value in the reg but reserve space on the stack. That's an
+ optimization, and is deferred [for a bit]. */
+ if ((regno - SPARC_FP_ARG_FIRST) >= SPARC_INT_ARG_MAX * 2)
+ return gen_rtx_PARALLEL (mode,
+ gen_rtvec (2,
+ gen_rtx_EXPR_LIST (VOIDmode,
+ NULL_RTX, const0_rtx),
+ gen_rtx_EXPR_LIST (VOIDmode,
+ reg, const0_rtx)));
+ else
+#else
+ /* ??? It seems that passing back a register even when past
+ the area declared by REG_PARM_STACK_SPACE will allocate
+ space appropriately, and will not copy the data onto the
+ stack, exactly as we desire.
+
+ This is due to locate_and_pad_parm being called in
+ expand_call whenever reg_parm_stack_space > 0, which
+ while benefical to our example here, would seem to be
+ in error from what had been intended. Ho hum... -- r~ */
+#endif
+ return reg;
+ }
+ else
+ {
+ rtx v0, v1;
+
+ if ((regno - SPARC_FP_ARG_FIRST) < SPARC_INT_ARG_MAX * 2)
+ {
+ int intreg;
+
+ /* On incoming, we don't need to know that the value
+ is passed in %f0 and %i0, and it confuses other parts
+ causing needless spillage even on the simplest cases. */
+ if (incoming_p)
+ return reg;
+
+ intreg = (SPARC_OUTGOING_INT_ARG_FIRST
+ + (regno - SPARC_FP_ARG_FIRST) / 2);
+
+ v0 = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
+ v1 = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (mode, intreg),
+ const0_rtx);
+ return gen_rtx_PARALLEL (mode, gen_rtvec (2, v0, v1));
+ }
+ else
+ {
+ v0 = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
+ v1 = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
+ return gen_rtx_PARALLEL (mode, gen_rtvec (2, v0, v1));
+ }
+ }
+ }
+ else if (type && TREE_CODE (type) == RECORD_TYPE)
+ {
+ /* Structures up to 16 bytes in size are passed in arg slots on the
+ stack and are promoted to registers where possible. */
+
+ if (int_size_in_bytes (type) > 16)
+ abort (); /* shouldn't get here */
+
+ return function_arg_record_value (type, mode, slotno, named, regbase);
+ }
+ else if (type && TREE_CODE (type) == UNION_TYPE)
+ {
+ enum machine_mode mode;
+ int bytes = int_size_in_bytes (type);
+
+ if (bytes > 16)
+ abort ();
+
+ mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
+ reg = gen_rtx_REG (mode, regno);
+ }
+ else
+ {
+ /* Scalar or complex int. */
+ reg = gen_rtx_REG (mode, regno);
+ }
+
+ return reg;
+}
+
+/* Handle the FUNCTION_ARG_PARTIAL_NREGS macro.
+ For an arg passed partly in registers and partly in memory,
+ this is the number of registers used.
+ For args passed entirely in registers or entirely in memory, zero.
+
+ Any arg that starts in the first 6 regs but won't entirely fit in them
+ needs partial registers on v8. On v9, structures with integer
+ values in arg slots 5,6 will be passed in %o5 and SP+176, and complex fp
+ values that begin in the last fp reg [where "last fp reg" varies with the
+ mode] will be split between that reg and memory. */
+
+int
+function_arg_partial_nregs (cum, mode, type, named)
+ const CUMULATIVE_ARGS *cum;
+ enum machine_mode mode;
+ tree type;
+ int named;
+{
+ int slotno, regno, padding;
+
+ /* We pass 0 for incoming_p here, it doesn't matter. */
+ slotno = function_arg_slotno (cum, mode, type, named, 0, &regno, &padding);
+
+ if (slotno == -1)
+ return 0;
+
+ if (TARGET_ARCH32)
+ {
+ if ((slotno + (mode == BLKmode
+ ? ROUND_ADVANCE (int_size_in_bytes (type))
+ : ROUND_ADVANCE (GET_MODE_SIZE (mode))))
+ > NPARM_REGS (SImode))
+ return NPARM_REGS (SImode) - slotno;
+ return 0;
+ }
+ else
+ {
+ if (type && AGGREGATE_TYPE_P (type))
+ {
+ int size = int_size_in_bytes (type);
+ int align = TYPE_ALIGN (type);
+
+ if (align == 16)
+ slotno += slotno & 1;
+ if (size > 8 && size <= 16
+ && slotno == SPARC_INT_ARG_MAX - 1)
+ return 1;
+ }
+ else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
+ || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+ && ! TARGET_FPU))
+ {
+ if (GET_MODE_ALIGNMENT (mode) == 128)
+ {
+ slotno += slotno & 1;
+ if (slotno == SPARC_INT_ARG_MAX - 2)
+ return 1;
+ }
+ else
+ {
+ if (slotno == SPARC_INT_ARG_MAX - 1)
+ return 1;
+ }
+ }
+ else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+ {
+ if (GET_MODE_ALIGNMENT (mode) == 128)
+ slotno += slotno & 1;
+ if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD)
+ > SPARC_FP_ARG_MAX)
+ return 1;
+ }
+ return 0;
+ }
+}
+
+/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
+ !v9: The SPARC ABI stipulates passing struct arguments (of any size) and
+ quad-precision floats by invisible reference.
+ v9: Aggregates greater than 16 bytes are passed by reference.
+ For Pascal, also pass arrays by reference. */
+
+int
+function_arg_pass_by_reference (cum, mode, type, named)
+ const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
+ enum machine_mode mode;
+ tree type;
+ int named ATTRIBUTE_UNUSED;
+{
+ if (TARGET_ARCH32)
+ {
+ return ((type && AGGREGATE_TYPE_P (type))
+ || mode == TFmode || mode == TCmode);
+ }
+ else
+ {
+ return ((type && TREE_CODE (type) == ARRAY_TYPE)
+ /* Consider complex values as aggregates, so care for TCmode. */
+ || GET_MODE_SIZE (mode) > 16
+ || (type && AGGREGATE_TYPE_P (type)
+ && int_size_in_bytes (type) > 16));
+ }
+}
+
+/* Handle the FUNCTION_ARG_ADVANCE macro.
+ Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ TYPE is null for libcalls where that information may not be available. */
+
+void
+function_arg_advance (cum, mode, type, named)
+ CUMULATIVE_ARGS *cum;
+ enum machine_mode mode;
+ tree type;
+ int named;
+{
+ int slotno, regno, padding;
+
+ /* We pass 0 for incoming_p here, it doesn't matter. */
+ slotno = function_arg_slotno (cum, mode, type, named, 0, &regno, &padding);
+
+ /* If register required leading padding, add it. */
+ if (slotno != -1)
+ cum->words += padding;
+
+ if (TARGET_ARCH32)
+ {
+ cum->words += (mode != BLKmode
+ ? ROUND_ADVANCE (GET_MODE_SIZE (mode))
+ : ROUND_ADVANCE (int_size_in_bytes (type)));
+ }
+ else
+ {
+ if (type && AGGREGATE_TYPE_P (type))
+ {
+ int size = int_size_in_bytes (type);
+
+ if (size <= 8)
+ ++cum->words;
+ else if (size <= 16)
+ cum->words += 2;
+ else /* passed by reference */
+ ++cum->words;
+ }
+ else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
+ {
+ cum->words += 2;
+ }
+ else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+ {
+ cum->words += GET_MODE_SIZE (mode) / UNITS_PER_WORD;
+ }
+ else
+ {
+ cum->words += (mode != BLKmode
+ ? ROUND_ADVANCE (GET_MODE_SIZE (mode))
+ : ROUND_ADVANCE (int_size_in_bytes (type)));
+ }
+ }
+}
+
+/* Handle the FUNCTION_ARG_PADDING macro.
+ For the 64 bit ABI structs are always stored left shifted in their
+ argument slot. */
+
+enum direction
+function_arg_padding (mode, type)
+ enum machine_mode mode;
+ tree type;
+{
+ if (TARGET_ARCH64 && type != 0 && AGGREGATE_TYPE_P (type))
+ return upward;
+
+ /* This is the default definition. */
+ return (! BYTES_BIG_ENDIAN
+ ? upward
+ : ((mode == BLKmode
+ ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
+ && int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT))
+ : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
+ ? downward : upward));
+}
+
+/* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE macros.
+ For v9, function return values are subject to the same rules as arguments,
+ except that up to 32-bytes may be returned in registers. */
+
+rtx
+function_value (type, mode, incoming_p)
+ tree type;
+ enum machine_mode mode;
+ int incoming_p;
+{
+ int regno;
+ int regbase = (incoming_p
+ ? SPARC_OUTGOING_INT_ARG_FIRST
+ : SPARC_INCOMING_INT_ARG_FIRST);
+
+ if (TARGET_ARCH64 && type)
+ {
+ if (TREE_CODE (type) == RECORD_TYPE)
+ {
+ /* Structures up to 32 bytes in size are passed in registers,
+ promoted to fp registers where possible. */
+
+ if (int_size_in_bytes (type) > 32)
+ abort (); /* shouldn't get here */
+
+ return function_arg_record_value (type, mode, 0, 1, regbase);
+ }
+ else if (TREE_CODE (type) == UNION_TYPE)
+ {
+ int bytes = int_size_in_bytes (type);
+
+ if (bytes > 32)
+ abort ();
+
+ mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
+ }
+ }
+
+ if (incoming_p)
+ regno = BASE_RETURN_VALUE_REG (mode);
+ else
+ regno = BASE_OUTGOING_VALUE_REG (mode);
+
+ return gen_rtx_REG (mode, regno);
+}
+
+/* Do what is necessary for `va_start'. The argument is ignored.
+
+ We look at the current function to determine if stdarg or varargs
+ is used and return the address of the first unnamed parameter. */
+
+rtx
+sparc_builtin_saveregs (arglist)
+ tree arglist ATTRIBUTE_UNUSED;
+{
+ int first_reg = current_function_args_info.words;
+ rtx address;
+ int regno;
+
+ for (regno = first_reg; regno < NPARM_REGS (word_mode); regno++)
+ emit_move_insn (gen_rtx_MEM (word_mode,
+ gen_rtx_PLUS (Pmode,
+ frame_pointer_rtx,
+ GEN_INT (STACK_POINTER_OFFSET
+ + UNITS_PER_WORD * regno))),
+ gen_rtx_REG (word_mode,
+ BASE_INCOMING_ARG_REG (word_mode) + regno));
+
+ address = gen_rtx_PLUS (Pmode,
+ frame_pointer_rtx,
+ GEN_INT (STACK_POINTER_OFFSET
+ + UNITS_PER_WORD * first_reg));
+
+ if (flag_check_memory_usage
+ && first_reg < NPARM_REGS (word_mode))
+ emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ address, ptr_mode,
+ GEN_INT (UNITS_PER_WORD
+ * (NPARM_REGS (word_mode) - first_reg)),
+ TYPE_MODE (sizetype), GEN_INT (MEMORY_USE_RW),
+ TYPE_MODE (integer_type_node));
+
+ return address;
+}
+
+/* Return the string to output a conditional branch to LABEL, which is
+ the operand number of the label. OP is the conditional expression.
+ XEXP (OP, 0) is assumed to be a condition code register (integer or
+ floating point) and its mode specifies what kind of comparison we made.
+
+ REVERSED is non-zero if we should reverse the sense of the comparison.
+
+ ANNUL is non-zero if we should generate an annulling branch.
+
+ NOOP is non-zero if we have to follow this branch by a noop.
+
+ INSN, if set, is the insn. */
+
+char *
+output_cbranch (op, label, reversed, annul, noop, insn)
+ rtx op;
+ int label;
+ int reversed, annul, noop;
+ rtx insn;
+{
+ static char string[20];
+ enum rtx_code code = GET_CODE (op);
+ rtx cc_reg = XEXP (op, 0);
+ enum machine_mode mode = GET_MODE (cc_reg);
+ static char v8_labelno[] = " %lX";
+ static char v9_icc_labelno[] = " %%icc,%lX";
+ static char v9_xcc_labelno[] = " %%xcc,%lX";
+ static char v9_fcc_labelno[] = " %%fccX,%lY";
+ char *labelno;
+ int labeloff;
+
+ /* ??? !v9: FP branches cannot be preceded by another floating point insn.
+ Because there is currently no concept of pre-delay slots, we can fix
+ this only by always emitting a nop before a floating point branch. */
+
+ if ((mode == CCFPmode || mode == CCFPEmode) && ! TARGET_V9)
+ strcpy (string, "nop\n\t");
+ else
+ string[0] = '\0';
+
+ /* If not floating-point or if EQ or NE, we can just reverse the code. */
+ if (reversed
+ && ((mode != CCFPmode && mode != CCFPEmode) || code == EQ || code == NE))
+ code = reverse_condition (code), reversed = 0;
+
+ /* Start by writing the branch condition. */
+ switch (code)
+ {
+ case NE:
+ if (mode == CCFPmode || mode == CCFPEmode)
+ strcat (string, "fbne");
+ else
+ strcpy (string, "bne");
+ break;
+
+ case EQ:
+ if (mode == CCFPmode || mode == CCFPEmode)
+ strcat (string, "fbe");
+ else
+ strcpy (string, "be");
+ break;
+
+ case GE:
+ if (mode == CCFPmode || mode == CCFPEmode)
+ {
+ if (reversed)
+ strcat (string, "fbul");
+ else
+ strcat (string, "fbge");
+ }
+ else if (mode == CC_NOOVmode)
+ strcpy (string, "bpos");
+ else
+ strcpy (string, "bge");
+ break;
+
+ case GT:
+ if (mode == CCFPmode || mode == CCFPEmode)
+ {
+ if (reversed)
+ strcat (string, "fbule");
+ else
+ strcat (string, "fbg");
+ }
+ else
+ strcpy (string, "bg");
+ break;
+
+ case LE:
+ if (mode == CCFPmode || mode == CCFPEmode)
+ {
+ if (reversed)
+ strcat (string, "fbug");
+ else
+ strcat (string, "fble");
+ }
+ else
+ strcpy (string, "ble");
+ break;
+
+ case LT:
+ if (mode == CCFPmode || mode == CCFPEmode)
+ {
+ if (reversed)
+ strcat (string, "fbuge");
+ else
+ strcat (string, "fbl");
+ }
+ else if (mode == CC_NOOVmode)
+ strcpy (string, "bneg");
+ else
+ strcpy (string, "bl");
+ break;
+
+ case GEU:
+ strcpy (string, "bgeu");
+ break;
+
+ case GTU:
+ strcpy (string, "bgu");
+ break;
+
+ case LEU:
+ strcpy (string, "bleu");
+ break;
+
+ case LTU:
+ strcpy (string, "blu");
+ break;
+
+ default:
+ break;
+ }
+
+ /* Now add the annulling, the label, and a possible noop. */
+ if (annul)
+ strcat (string, ",a");
+
+ if (! TARGET_V9)
+ {
+ labeloff = 3;
+ labelno = v8_labelno;
+ }
+ else
+ {
+ rtx note;
+
+ if (insn && (note = find_reg_note (insn, REG_BR_PRED, NULL_RTX)))
+ strcat (string, INTVAL (XEXP (note, 0)) & ATTR_FLAG_likely ? ",pt" : ",pn");
+
+ labeloff = 9;
+ if (mode == CCFPmode || mode == CCFPEmode)
+ {
+ labeloff = 10;
+ labelno = v9_fcc_labelno;
+ /* Set the char indicating the number of the fcc reg to use. */
+ labelno[6] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0';
+ }
+ else if (mode == CCXmode || mode == CCX_NOOVmode)
+ labelno = v9_xcc_labelno;
+ else
+ labelno = v9_icc_labelno;
+ }
+ /* Set the char indicating the number of the operand containing the
+ label_ref. */
+ labelno[labeloff] = label + '0';
+ strcat (string, labelno);
+
+ if (noop)
+ strcat (string, "\n\tnop");
+
+ return string;
+}
+
+/* Return the string to output a conditional branch to LABEL, testing
+ register REG. LABEL is the operand number of the label; REG is the
+ operand number of the reg. OP is the conditional expression. The mode
+ of REG says what kind of comparison we made.
+
+ REVERSED is non-zero if we should reverse the sense of the comparison.
+
+ ANNUL is non-zero if we should generate an annulling branch.
+
+ NOOP is non-zero if we have to follow this branch by a noop. */
+
+char *
+output_v9branch (op, reg, label, reversed, annul, noop)
+ rtx op;
+ int reg, label;
+ int reversed, annul, noop;
+{
+ static char string[20];
+ enum rtx_code code = GET_CODE (op);
+ enum machine_mode mode = GET_MODE (XEXP (op, 0));
+ static char labelno[] = " %X,%lX";
+
+ /* If not floating-point or if EQ or NE, we can just reverse the code. */
+ if (reversed)
+ code = reverse_condition (code), reversed = 0;
+
+ /* Only 64 bit versions of these instructions exist. */
+ if (mode != DImode)
+ abort ();
+
+ /* Start by writing the branch condition. */
+
+ switch (code)
+ {
+ case NE:
+ strcpy (string, "brnz");
+ break;
+
+ case EQ:
+ strcpy (string, "brz");
+ break;
+
+ case GE:
+ strcpy (string, "brgez");
+ break;
+
+ case LT:
+ strcpy (string, "brlz");
+ break;
+
+ case LE:
+ strcpy (string, "brlez");
+ break;
+
+ case GT:
+ strcpy (string, "brgz");
+ break;
+
+ default:
+ abort ();
+ }
+
+ /* Now add the annulling, reg, label, and nop. */
+ if (annul)
+ strcat (string, ",a");
+
+ /* ??? Optional prediction bit ",pt" or ",pf" goes here. */
+
+ labelno[2] = reg + '0';
+ labelno[6] = label + '0';
+ strcat (string, labelno);
+
+ if (noop)
+ strcat (string, "\n\tnop");
+
+ return string;
+}
+
+/* Renumber registers in delay slot. Replace registers instead of
+ renumbering because they may be shared.
+
+ This does not handle instructions other than move. */
+
+static void
+epilogue_renumber (where)
+ rtx *where;
+{
+ rtx x = *where;
+ enum rtx_code code = GET_CODE (x);
+
+ switch (code)
+ {
+ case MEM:
+ *where = x = copy_rtx (x);
+ epilogue_renumber (&XEXP (x, 0));
+ return;
+
+ case REG:
+ {
+ int regno = REGNO (x);
+ if (regno > 8 && regno < 24)
+ abort ();
+ if (regno >= 24 && regno < 32)
+ *where = gen_rtx_REG (GET_MODE (x), regno - 16);
+ return;
+ }
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return;
+
+ case IOR:
+ case AND:
+ case XOR:
+ case PLUS:
+ case MINUS:
+ epilogue_renumber (&XEXP (x, 1));
+ case NEG:
+ case NOT:
+ epilogue_renumber (&XEXP (x, 0));
+ return;
+
+ default:
+ debug_rtx (*where);
+ abort();
+ }
+}
+
+/* Output assembler code to return from a function. */
+
+char *
+output_return (operands)
+ rtx *operands;
+{
+ rtx delay = final_sequence ? XVECEXP (final_sequence, 0, 1) : 0;
+
+ if (leaf_label)
+ {
+ operands[0] = leaf_label;
+ return "b%* %l0%(";
+ }
+ else if (leaf_function)
+ {
+ /* No delay slot in a leaf function. */
+ if (delay)
+ abort ();
+
+ /* If we didn't allocate a frame pointer for the current function,
+ the stack pointer might have been adjusted. Output code to
+ restore it now. */
+
+ operands[0] = GEN_INT (actual_fsize);
+
+ /* Use sub of negated value in first two cases instead of add to
+ allow actual_fsize == 4096. */
+
+ if (actual_fsize <= 4096)
+ {
+ if (SKIP_CALLERS_UNIMP_P)
+ return "jmp %%o7+12\n\tsub %%sp,-%0,%%sp";
+ else
+ return "retl\n\tsub %%sp,-%0,%%sp";
+ }
+ else if (actual_fsize <= 8192)
+ {
+ operands[0] = GEN_INT (actual_fsize - 4096);
+ if (SKIP_CALLERS_UNIMP_P)
+ return "sub %%sp,-4096,%%sp\n\tjmp %%o7+12\n\tsub %%sp,-%0,%%sp";
+ else
+ return "sub %%sp,-4096,%%sp\n\tretl\n\tsub %%sp,-%0,%%sp";
+ }
+ else if (SKIP_CALLERS_UNIMP_P)
+ {
+ if ((actual_fsize & 0x3ff) != 0)
+ return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp";
+ else
+ return "sethi %%hi(%a0),%%g1\n\tjmp %%o7+12\n\tadd %%sp,%%g1,%%sp";
+ }
+ else
+ {
+ if ((actual_fsize & 0x3ff) != 0)
+ return "sethi %%hi(%a0),%%g1\n\tor %%g1,%%lo(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+ else
+ return "sethi %%hi(%a0),%%g1\n\tretl\n\tadd %%sp,%%g1,%%sp";
+ }
+ }
+ else if (TARGET_V9)
+ {
+ if (delay)
+ {
+ epilogue_renumber (&SET_DEST (PATTERN (delay)));
+ epilogue_renumber (&SET_SRC (PATTERN (delay)));
+ }
+ if (SKIP_CALLERS_UNIMP_P)
+ return "return %%i7+12%#";
+ else
+ return "return %%i7+8%#";
+ }
+ else
+ {
+ if (delay)
+ abort ();
+ if (SKIP_CALLERS_UNIMP_P)
+ return "jmp %%i7+12\n\trestore";
+ else
+ return "ret\n\trestore";
+ }
+}
+
+/* Leaf functions and non-leaf functions have different needs. */
+
+static int
+reg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER;
+
+static int
+reg_nonleaf_alloc_order[] = REG_ALLOC_ORDER;
+
+static int *reg_alloc_orders[] = {
+ reg_leaf_alloc_order,
+ reg_nonleaf_alloc_order};
+
+void
+order_regs_for_local_alloc ()
+{
+ static int last_order_nonleaf = 1;
+
+ if (regs_ever_live[15] != last_order_nonleaf)
+ {
+ last_order_nonleaf = !last_order_nonleaf;
+ bcopy ((char *) reg_alloc_orders[last_order_nonleaf],
+ (char *) reg_alloc_order, FIRST_PSEUDO_REGISTER * sizeof (int));
+ }
+}
+
+/* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1.
+ This makes them candidates for using ldd and std insns.
+
+ Note reg1 and reg2 *must* be hard registers. */
+
+int
+registers_ok_for_ldd_peep (reg1, reg2)
+ rtx reg1, reg2;
+{
+ /* We might have been passed a SUBREG. */
+ if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
+ return 0;
+
+ if (REGNO (reg1) % 2 != 0)
+ return 0;
+
+ /* Integer ldd is deprecated in SPARC V9 */
+ if (TARGET_V9 && REGNO (reg1) < 32)
+ return 0;
+
+ return (REGNO (reg1) == REGNO (reg2) - 1);
+}
+
+/* Return 1 if addr1 and addr2 are suitable for use in an ldd or
+ std insn.
+
+ This can only happen when addr1 and addr2 are consecutive memory
+ locations (addr1 + 4 == addr2). addr1 must also be aligned on a
+ 64 bit boundary (addr1 % 8 == 0).
+
+ We know %sp and %fp are kept aligned on a 64 bit boundary. Other
+ registers are assumed to *never* be properly aligned and are
+ rejected.
+
+ Knowing %sp and %fp are kept aligned on a 64 bit boundary, we
+ need only check that the offset for addr1 % 8 == 0. */
+
+int
+addrs_ok_for_ldd_peep (addr1, addr2)
+ rtx addr1, addr2;
+{
+ int reg1, offset1;
+
+ /* Extract a register number and offset (if used) from the first addr. */
+ if (GET_CODE (addr1) == PLUS)
+ {
+ /* If not a REG, return zero. */
+ if (GET_CODE (XEXP (addr1, 0)) != REG)
+ return 0;
+ else
+ {
+ reg1 = REGNO (XEXP (addr1, 0));
+ /* The offset must be constant! */
+ if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
+ return 0;
+ offset1 = INTVAL (XEXP (addr1, 1));
+ }
+ }
+ else if (GET_CODE (addr1) != REG)
+ return 0;
+ else
+ {
+ reg1 = REGNO (addr1);
+ /* This was a simple (mem (reg)) expression. Offset is 0. */
+ offset1 = 0;
+ }
+
+ /* Make sure the second address is a (mem (plus (reg) (const_int). */
+ if (GET_CODE (addr2) != PLUS)
+ return 0;
+
+ if (GET_CODE (XEXP (addr2, 0)) != REG
+ || GET_CODE (XEXP (addr2, 1)) != CONST_INT)
+ return 0;
+
+ /* Only %fp and %sp are allowed. Additionally both addresses must
+ use the same register. */
+ if (reg1 != FRAME_POINTER_REGNUM && reg1 != STACK_POINTER_REGNUM)
+ return 0;
+
+ if (reg1 != REGNO (XEXP (addr2, 0)))
+ return 0;
+
+ /* The first offset must be evenly divisible by 8 to ensure the
+ address is 64 bit aligned. */
+ if (offset1 % 8 != 0)
+ return 0;
+
+ /* The offset for the second addr must be 4 more than the first addr. */
+ if (INTVAL (XEXP (addr2, 1)) != offset1 + 4)
+ return 0;
+
+ /* All the tests passed. addr1 and addr2 are valid for ldd and std
+ instructions. */
+ return 1;
+}
+
+/* Return 1 if reg is a pseudo, or is the first register in
+ a hard register pair. This makes it a candidate for use in
+ ldd and std insns. */
+
+int
+register_ok_for_ldd (reg)
+ rtx reg;
+{
+ /* We might have been passed a SUBREG. */
+ if (GET_CODE (reg) != REG)
+ return 0;
+
+ if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
+ return (REGNO (reg) % 2 == 0);
+ else
+ return 1;
+}
+
+/* Print operand X (an rtx) in assembler syntax to file FILE.
+ CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
+ For `%' followed by punctuation, CODE is the punctuation and X is null. */
+
+void
+print_operand (file, x, code)
+ FILE *file;
+ rtx x;
+ int code;
+{
+ switch (code)
+ {
+ case '#':
+ /* Output a 'nop' if there's nothing for the delay slot. */
+ if (dbr_sequence_length () == 0)
+ fputs ("\n\tnop", file);
+ return;
+ case '*':
+ /* Output an annul flag if there's nothing for the delay slot and we
+ are optimizing. This is always used with '(' below. */
+ /* Sun OS 4.1.1 dbx can't handle an annulled unconditional branch;
+ this is a dbx bug. So, we only do this when optimizing. */
+ /* On UltraSPARC, a branch in a delay slot causes a pipeline flush.
+ Always emit a nop in case the next instruction is a branch. */
+ if (dbr_sequence_length () == 0
+ && (optimize && (int)sparc_cpu < PROCESSOR_V9))
+ fputs (",a", file);
+ return;
+ case '(':
+ /* Output a 'nop' if there's nothing for the delay slot and we are
+ not optimizing. This is always used with '*' above. */
+ if (dbr_sequence_length () == 0
+ && ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
+ fputs ("\n\tnop", file);
+ return;
+ case '_':
+ /* Output the Embedded Medium/Anywhere code model base register. */
+ fputs (EMBMEDANY_BASE_REG, file);
+ return;
+ case '@':
+ /* Print out what we are using as the frame pointer. This might
+ be %fp, or might be %sp+offset. */
+ /* ??? What if offset is too big? Perhaps the caller knows it isn't? */
+ fprintf (file, "%s+%d", frame_base_name, frame_base_offset);
+ return;
+ case 'Y':
+ /* Adjust the operand to take into account a RESTORE operation. */
+ if (GET_CODE (x) == CONST_INT)
+ break;
+ else if (GET_CODE (x) != REG)
+ output_operand_lossage ("Invalid %%Y operand");
+ else if (REGNO (x) < 8)
+ fputs (reg_names[REGNO (x)], file);
+ else if (REGNO (x) >= 24 && REGNO (x) < 32)
+ fputs (reg_names[REGNO (x)-16], file);
+ else
+ output_operand_lossage ("Invalid %%Y operand");
+ return;
+ case 'L':
+ /* Print out the low order register name of a register pair. */
+ if (WORDS_BIG_ENDIAN)
+ fputs (reg_names[REGNO (x)+1], file);
+ else
+ fputs (reg_names[REGNO (x)], file);
+ return;
+ case 'H':
+ /* Print out the high order register name of a register pair. */
+ if (WORDS_BIG_ENDIAN)
+ fputs (reg_names[REGNO (x)], file);
+ else
+ fputs (reg_names[REGNO (x)+1], file);
+ return;
+ case 'R':
+ /* Print out the second register name of a register pair or quad.
+ I.e., R (%o0) => %o1. */
+ fputs (reg_names[REGNO (x)+1], file);
+ return;
+ case 'S':
+ /* Print out the third register name of a register quad.
+ I.e., S (%o0) => %o2. */
+ fputs (reg_names[REGNO (x)+2], file);
+ return;
+ case 'T':
+ /* Print out the fourth register name of a register quad.
+ I.e., T (%o0) => %o3. */
+ fputs (reg_names[REGNO (x)+3], file);
+ return;
+ case 'x':
+ /* Print a condition code register. */
+ if (REGNO (x) == SPARC_ICC_REG)
+ {
+ /* We don't handle CC[X]_NOOVmode because they're not supposed
+ to occur here. */
+ if (GET_MODE (x) == CCmode)
+ fputs ("%icc", file);
+ else if (GET_MODE (x) == CCXmode)
+ fputs ("%xcc", file);
+ else
+ abort ();
+ }
+ else
+ /* %fccN register */
+ fputs (reg_names[REGNO (x)], file);
+ return;
+ case 'm':
+ /* Print the operand's address only. */
+ output_address (XEXP (x, 0));
+ return;
+ case 'r':
+ /* In this case we need a register. Use %g0 if the
+ operand is const0_rtx. */
+ if (x == const0_rtx
+ || (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
+ {
+ fputs ("%g0", file);
+ return;
+ }
+ else
+ break;
+
+ case 'A':
+ switch (GET_CODE (x))
+ {
+ case IOR: fputs ("or", file); break;
+ case AND: fputs ("and", file); break;
+ case XOR: fputs ("xor", file); break;
+ default: output_operand_lossage ("Invalid %%A operand");
+ }
+ return;
+
+ case 'B':
+ switch (GET_CODE (x))
+ {
+ case IOR: fputs ("orn", file); break;
+ case AND: fputs ("andn", file); break;
+ case XOR: fputs ("xnor", file); break;
+ default: output_operand_lossage ("Invalid %%B operand");
+ }
+ return;
+
+ /* These are used by the conditional move instructions. */
+ case 'c' :
+ case 'C':
+ {
+ enum rtx_code rc = (code == 'c'
+ ? reverse_condition (GET_CODE (x))
+ : GET_CODE (x));
+ switch (rc)
+ {
+ case NE: fputs ("ne", file); break;
+ case EQ: fputs ("e", file); break;
+ case GE: fputs ("ge", file); break;
+ case GT: fputs ("g", file); break;
+ case LE: fputs ("le", file); break;
+ case LT: fputs ("l", file); break;
+ case GEU: fputs ("geu", file); break;
+ case GTU: fputs ("gu", file); break;
+ case LEU: fputs ("leu", file); break;
+ case LTU: fputs ("lu", file); break;
+ default: output_operand_lossage (code == 'c'
+ ? "Invalid %%c operand"
+ : "Invalid %%C operand");
+ }
+ return;
+ }
+
+ /* These are used by the movr instruction pattern. */
+ case 'd':
+ case 'D':
+ {
+ enum rtx_code rc = (code == 'd'
+ ? reverse_condition (GET_CODE (x))
+ : GET_CODE (x));
+ switch (rc)
+ {
+ case NE: fputs ("ne", file); break;
+ case EQ: fputs ("e", file); break;
+ case GE: fputs ("gez", file); break;
+ case LT: fputs ("lz", file); break;
+ case LE: fputs ("lez", file); break;
+ case GT: fputs ("gz", file); break;
+ default: output_operand_lossage (code == 'd'
+ ? "Invalid %%d operand"
+ : "Invalid %%D operand");
+ }
+ return;
+ }
+
+ case 'b':
+ {
+ /* Print a sign-extended character. */
+ int i = INTVAL (x) & 0xff;
+ if (i & 0x80)
+ i |= 0xffffff00;
+ fprintf (file, "%d", i);
+ return;
+ }
+
+ case 'f':
+ /* Operand must be a MEM; write its address. */
+ if (GET_CODE (x) != MEM)
+ output_operand_lossage ("Invalid %%f operand");
+ output_address (XEXP (x, 0));
+ return;
+
+ case 0:
+ /* Do nothing special. */
+ break;
+
+ default:
+ /* Undocumented flag. */
+ output_operand_lossage ("invalid operand output code");
+ }
+
+ if (GET_CODE (x) == REG)
+ fputs (reg_names[REGNO (x)], file);
+ else if (GET_CODE (x) == MEM)
+ {
+ fputc ('[', file);
+ /* Poor Sun assembler doesn't understand absolute addressing. */
+ if (CONSTANT_P (XEXP (x, 0))
+ && ! TARGET_LIVE_G0)
+ fputs ("%g0+", file);
+ output_address (XEXP (x, 0));
+ fputc (']', file);
+ }
+ else if (GET_CODE (x) == HIGH)
+ {
+ fputs ("%hi(", file);
+ output_addr_const (file, XEXP (x, 0));
+ fputc (')', file);
+ }
+ else if (GET_CODE (x) == LO_SUM)
+ {
+ print_operand (file, XEXP (x, 0), 0);
+ fputs ("+%lo(", file);
+ output_addr_const (file, XEXP (x, 1));
+ fputc (')', file);
+ }
+ else if (GET_CODE (x) == CONST_DOUBLE
+ && (GET_MODE (x) == VOIDmode
+ || GET_MODE_CLASS (GET_MODE (x)) == MODE_INT))
+ {
+ if (CONST_DOUBLE_HIGH (x) == 0)
+ fprintf (file, "%u", CONST_DOUBLE_LOW (x));
+ else if (CONST_DOUBLE_HIGH (x) == -1
+ && CONST_DOUBLE_LOW (x) < 0)
+ fprintf (file, "%d", CONST_DOUBLE_LOW (x));
+ else
+ output_operand_lossage ("long long constant not a valid immediate operand");
+ }
+ else if (GET_CODE (x) == CONST_DOUBLE)
+ output_operand_lossage ("floating point constant not a valid immediate operand");
+ else { output_addr_const (file, x); }
+}
+
+/* This function outputs assembler code for VALUE to FILE, where VALUE is
+ a 64 bit (DImode) value. */
+
+/* ??? If there is a 64 bit counterpart to .word that the assembler
+ understands, then using that would simply this code greatly. */
+/* ??? We only output .xword's for symbols and only then in environments
+ where the assembler can handle them. */
+
+void
+output_double_int (file, value)
+ FILE *file;
+ rtx value;
+{
+ if (GET_CODE (value) == CONST_INT)
+ {
+ /* ??? This has endianness issues. */
+#if HOST_BITS_PER_WIDE_INT == 64
+ HOST_WIDE_INT xword = INTVAL (value);
+ HOST_WIDE_INT high, low;
+
+ high = (xword >> 32) & 0xffffffff;
+ low = xword & 0xffffffff;
+ ASM_OUTPUT_INT (file, GEN_INT (high));
+ ASM_OUTPUT_INT (file, GEN_INT (low));
+#else
+ if (INTVAL (value) < 0)
+ ASM_OUTPUT_INT (file, constm1_rtx);
+ else
+ ASM_OUTPUT_INT (file, const0_rtx);
+ ASM_OUTPUT_INT (file, value);
+#endif
+ }
+ else if (GET_CODE (value) == CONST_DOUBLE)
+ {
+ ASM_OUTPUT_INT (file, GEN_INT (CONST_DOUBLE_HIGH (value)));
+ ASM_OUTPUT_INT (file, GEN_INT (CONST_DOUBLE_LOW (value)));
+ }
+ else if (GET_CODE (value) == SYMBOL_REF
+ || GET_CODE (value) == CONST
+ || GET_CODE (value) == PLUS
+ || (TARGET_ARCH64 &&
+ (GET_CODE (value) == LABEL_REF
+ || GET_CODE (value) == CODE_LABEL
+ || GET_CODE (value) == MINUS)))
+ {
+ if (!TARGET_V9 || TARGET_CM_MEDLOW)
+ {
+ ASM_OUTPUT_INT (file, const0_rtx);
+ ASM_OUTPUT_INT (file, value);
+ }
+ else
+ {
+ fprintf (file, "\t%s\t", ASM_LONGLONG);
+ output_addr_const (file, value);
+ fprintf (file, "\n");
+ }
+ }
+ else
+ abort ();
+}
+
+/* Return the value of a code used in the .proc pseudo-op that says
+ what kind of result this function returns. For non-C types, we pick
+ the closest C type. */
+
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+
+#ifndef SHORT_TYPE_SIZE
+#define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2)
+#endif
+
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_LONG_TYPE_SIZE
+#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef FLOAT_TYPE_SIZE
+#define FLOAT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef DOUBLE_TYPE_SIZE
+#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+unsigned long
+sparc_type_code (type)
+ register tree type;
+{
+ register unsigned long qualifiers = 0;
+ register unsigned shift;
+
+ /* Only the first 30 bits of the qualifier are valid. We must refrain from
+ setting more, since some assemblers will give an error for this. Also,
+ we must be careful to avoid shifts of 32 bits or more to avoid getting
+ unpredictable results. */
+
+ for (shift = 6; shift < 30; shift += 2, type = TREE_TYPE (type))
+ {
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ return qualifiers;
+
+ case ARRAY_TYPE:
+ qualifiers |= (3 << shift);
+ break;
+
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ qualifiers |= (2 << shift);
+ break;
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case OFFSET_TYPE:
+ qualifiers |= (1 << shift);
+ break;
+
+ case RECORD_TYPE:
+ return (qualifiers | 8);
+
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ return (qualifiers | 9);
+
+ case ENUMERAL_TYPE:
+ return (qualifiers | 10);
+
+ case VOID_TYPE:
+ return (qualifiers | 16);
+
+ case INTEGER_TYPE:
+ /* If this is a range type, consider it to be the underlying
+ type. */
+ if (TREE_TYPE (type) != 0)
+ break;
+
+ /* Carefully distinguish all the standard types of C,
+ without messing up if the language is not C. We do this by
+ testing TYPE_PRECISION and TREE_UNSIGNED. The old code used to
+ look at both the names and the above fields, but that's redundant.
+ Any type whose size is between two C types will be considered
+ to be the wider of the two types. Also, we do not have a
+ special code to use for "long long", so anything wider than
+ long is treated the same. Note that we can't distinguish
+ between "int" and "long" in this code if they are the same
+ size, but that's fine, since neither can the assembler. */
+
+ if (TYPE_PRECISION (type) <= CHAR_TYPE_SIZE)
+ return (qualifiers | (TREE_UNSIGNED (type) ? 12 : 2));
+
+ else if (TYPE_PRECISION (type) <= SHORT_TYPE_SIZE)
+ return (qualifiers | (TREE_UNSIGNED (type) ? 13 : 3));
+
+ else if (TYPE_PRECISION (type) <= INT_TYPE_SIZE)
+ return (qualifiers | (TREE_UNSIGNED (type) ? 14 : 4));
+
+ else
+ return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5));
+
+ case REAL_TYPE:
+ /* If this is a range type, consider it to be the underlying
+ type. */
+ if (TREE_TYPE (type) != 0)
+ break;
+
+ /* Carefully distinguish all the standard types of C,
+ without messing up if the language is not C. */
+
+ if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE)
+ return (qualifiers | 6);
+
+ else
+ return (qualifiers | 7);
+
+ case COMPLEX_TYPE: /* GNU Fortran COMPLEX type. */
+ /* ??? We need to distinguish between double and float complex types,
+ but I don't know how yet because I can't reach this code from
+ existing front-ends. */
+ return (qualifiers | 7); /* Who knows? */
+
+ case CHAR_TYPE: /* GNU Pascal CHAR type. Not used in C. */
+ case BOOLEAN_TYPE: /* GNU Fortran BOOLEAN type. */
+ case FILE_TYPE: /* GNU Pascal FILE type. */
+ case SET_TYPE: /* GNU Pascal SET type. */
+ case LANG_TYPE: /* ? */
+ return qualifiers;
+
+ default:
+ abort (); /* Not a type! */
+ }
+ }
+
+ return qualifiers;
+}
+
+/* Nested function support. */
+
+/* Emit RTL insns to initialize the variable parts of a trampoline.
+ FNADDR is an RTX for the address of the function's pure code.
+ CXT is an RTX for the static chain value for the function.
+
+ This takes 16 insns: 2 shifts & 2 ands (to split up addresses), 4 sethi
+ (to load in opcodes), 4 iors (to merge address and opcodes), and 4 writes
+ (to store insns). This is a bit excessive. Perhaps a different
+ mechanism would be better here.
+
+ Emit enough FLUSH insns to synchronize the data and instruction caches. */
+
+void
+sparc_initialize_trampoline (tramp, fnaddr, cxt)
+ rtx tramp, fnaddr, cxt;
+{
+ /* SPARC 32 bit trampoline:
+
+ sethi %hi(fn),%g1
+ sethi %hi(static),%g2
+ jmp %g1+%lo(fn)
+ or %g2,%lo(static),%g2
+
+ SETHI i,r = 00rr rrr1 00ii iiii iiii iiii iiii iiii
+ JMPL r+i,d = 10dd ddd1 1100 0rrr rr1i iiii iiii iiii
+ */
+
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 0)),
+ expand_binop (SImode, ior_optab,
+ expand_shift (RSHIFT_EXPR, SImode, fnaddr,
+ size_int (10), 0, 1),
+ GEN_INT (0x03000000),
+ NULL_RTX, 1, OPTAB_DIRECT));
+
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
+ expand_binop (SImode, ior_optab,
+ expand_shift (RSHIFT_EXPR, SImode, cxt,
+ size_int (10), 0, 1),
+ GEN_INT (0x05000000),
+ NULL_RTX, 1, OPTAB_DIRECT));
+
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
+ expand_binop (SImode, ior_optab,
+ expand_and (fnaddr, GEN_INT (0x3ff), NULL_RTX),
+ GEN_INT (0x81c06000),
+ NULL_RTX, 1, OPTAB_DIRECT));
+
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
+ expand_binop (SImode, ior_optab,
+ expand_and (cxt, GEN_INT (0x3ff), NULL_RTX),
+ GEN_INT (0x8410a000),
+ NULL_RTX, 1, OPTAB_DIRECT));
+
+ emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp))));
+ /* On UltraSPARC a flush flushes an entire cache line. The trampoline is
+ aligned on a 16 byte boundary so one flush clears it all. */
+ if (sparc_cpu != PROCESSOR_ULTRASPARC)
+ emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode,
+ plus_constant (tramp, 8)))));
+}
+
+/* The 64 bit version is simpler because it makes more sense to load the
+ values as "immediate" data out of the trampoline. It's also easier since
+ we can read the PC without clobbering a register. */
+
+void
+sparc64_initialize_trampoline (tramp, fnaddr, cxt)
+ rtx tramp, fnaddr, cxt;
+{
+ /*
+ rd %pc,%g1
+ ldx [%g1+24],%g5
+ jmp %g5
+ ldx [%g1+16],%g5
+ +16 bytes data
+ */
+
+ emit_move_insn (gen_rtx_MEM (SImode, tramp),
+ GEN_INT (0x83414000));
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
+ GEN_INT (0xca586018));
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
+ GEN_INT (0x81c04000));
+ emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
+ GEN_INT (0xca586010));
+ emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt);
+ emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 20)), fnaddr);
+ emit_insn (gen_flush (validize_mem (gen_rtx_MEM (DImode, tramp))));
+ if (sparc_cpu != PROCESSOR_ULTRASPARC)
+ emit_insn (gen_flush (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
+}
+
+/* Subroutines to support a flat (single) register window calling
+ convention. */
+
+/* Single-register window sparc stack frames look like:
+
+ Before call After call
+ +-----------------------+ +-----------------------+
+ high | | | |
+ mem | caller's temps. | | caller's temps. |
+ | | | |
+ +-----------------------+ +-----------------------+
+ | | | |
+ | arguments on stack. | | arguments on stack. |
+ | | | |
+ +-----------------------+FP+92->+-----------------------+
+ | 6 words to save | | 6 words to save |
+ | arguments passed | | arguments passed |
+ | in registers, even | | in registers, even |
+ | if not passed. | | if not passed. |
+ SP+68->+-----------------------+FP+68->+-----------------------+
+ | 1 word struct addr | | 1 word struct addr |
+ +-----------------------+FP+64->+-----------------------+
+ | | | |
+ | 16 word reg save area | | 16 word reg save area |
+ | | | |
+ SP->+-----------------------+ FP->+-----------------------+
+ | 4 word area for |
+ | fp/alu reg moves |
+ FP-16->+-----------------------+
+ | |
+ | local variables |
+ | |
+ +-----------------------+
+ | |
+ | fp register save |
+ | |
+ +-----------------------+
+ | |
+ | gp register save |
+ | |
+ +-----------------------+
+ | |
+ | alloca allocations |
+ | |
+ +-----------------------+
+ | |
+ | arguments on stack |
+ | |
+ SP+92->+-----------------------+
+ | 6 words to save |
+ | arguments passed |
+ | in registers, even |
+ low | if not passed. |
+ memory SP+68->+-----------------------+
+ | 1 word struct addr |
+ SP+64->+-----------------------+
+ | |
+ I 16 word reg save area |
+ | |
+ SP->+-----------------------+ */
+
+/* Structure to be filled in by sparc_flat_compute_frame_size with register
+ save masks, and offsets for the current function. */
+
+struct sparc_frame_info
+{
+ unsigned long total_size; /* # bytes that the entire frame takes up. */
+ unsigned long var_size; /* # bytes that variables take up. */
+ unsigned long args_size; /* # bytes that outgoing arguments take up. */
+ unsigned long extra_size; /* # bytes of extra gunk. */
+ unsigned int gp_reg_size; /* # bytes needed to store gp regs. */
+ unsigned int fp_reg_size; /* # bytes needed to store fp regs. */
+ unsigned long gmask; /* Mask of saved gp registers. */
+ unsigned long fmask; /* Mask of saved fp registers. */
+ unsigned long reg_offset; /* Offset from new sp to store regs. */
+ int initialized; /* Nonzero if frame size already calculated. */
+};
+
+/* Current frame information calculated by sparc_flat_compute_frame_size. */
+struct sparc_frame_info current_frame_info;
+
+/* Zero structure to initialize current_frame_info. */
+struct sparc_frame_info zero_frame_info;
+
+/* Tell prologue and epilogue if register REGNO should be saved / restored. */
+
+#define RETURN_ADDR_REGNUM 15
+#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
+#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
+
+#define MUST_SAVE_REGISTER(regno) \
+ ((regs_ever_live[regno] && !call_used_regs[regno]) \
+ || (regno == FRAME_POINTER_REGNUM && frame_pointer_needed) \
+ || (regno == RETURN_ADDR_REGNUM && regs_ever_live[RETURN_ADDR_REGNUM]))
+
+/* Return the bytes needed to compute the frame pointer from the current
+ stack pointer. */
+
+unsigned long
+sparc_flat_compute_frame_size (size)
+ int size; /* # of var. bytes allocated. */
+{
+ int regno;
+ unsigned long total_size; /* # bytes that the entire frame takes up. */
+ unsigned long var_size; /* # bytes that variables take up. */
+ unsigned long args_size; /* # bytes that outgoing arguments take up. */
+ unsigned long extra_size; /* # extra bytes. */
+ unsigned int gp_reg_size; /* # bytes needed to store gp regs. */
+ unsigned int fp_reg_size; /* # bytes needed to store fp regs. */
+ unsigned long gmask; /* Mask of saved gp registers. */
+ unsigned long fmask; /* Mask of saved fp registers. */
+ unsigned long reg_offset; /* Offset to register save area. */
+ int need_aligned_p; /* 1 if need the save area 8 byte aligned. */
+
+ /* This is the size of the 16 word reg save area, 1 word struct addr
+ area, and 4 word fp/alu register copy area. */
+ extra_size = -STARTING_FRAME_OFFSET + FIRST_PARM_OFFSET(0);
+ var_size = size;
+ /* Also include the size needed for the 6 parameter registers. */
+ args_size = current_function_outgoing_args_size + 24;
+ total_size = var_size + args_size + extra_size;
+ gp_reg_size = 0;
+ fp_reg_size = 0;
+ gmask = 0;
+ fmask = 0;
+ reg_offset = 0;
+ need_aligned_p = 0;
+
+ /* Calculate space needed for gp registers. */
+ for (regno = 1; regno <= 31; regno++)
+ {
+ if (MUST_SAVE_REGISTER (regno))
+ {
+ /* If we need to save two regs in a row, ensure there's room to bump
+ up the address to align it to a doubleword boundary. */
+ if ((regno & 0x1) == 0 && MUST_SAVE_REGISTER (regno+1))
+ {
+ if (gp_reg_size % 8 != 0)
+ gp_reg_size += 4;
+ gp_reg_size += 2 * UNITS_PER_WORD;
+ gmask |= 3 << regno;
+ regno++;
+ need_aligned_p = 1;
+ }
+ else
+ {
+ gp_reg_size += UNITS_PER_WORD;
+ gmask |= 1 << regno;
+ }
+ }
+ }
+
+ /* Calculate space needed for fp registers. */
+ for (regno = 32; regno <= 63; regno++)
+ {
+ if (regs_ever_live[regno] && !call_used_regs[regno])
+ {
+ fp_reg_size += UNITS_PER_WORD;
+ fmask |= 1 << (regno - 32);
+ }
+ }
+
+ if (gmask || fmask)
+ {
+ int n;
+ reg_offset = FIRST_PARM_OFFSET(0) + args_size;
+ /* Ensure save area is 8 byte aligned if we need it. */
+ n = reg_offset % 8;
+ if (need_aligned_p && n != 0)
+ {
+ total_size += 8 - n;
+ reg_offset += 8 - n;
+ }
+ total_size += gp_reg_size + fp_reg_size;
+ }
+
+ /* ??? This looks a little suspicious. Clarify. */
+ if (total_size == extra_size)
+ total_size = extra_size = 0;
+
+ total_size = SPARC_STACK_ALIGN (total_size);
+
+ /* Save other computed information. */
+ current_frame_info.total_size = total_size;
+ current_frame_info.var_size = var_size;
+ current_frame_info.args_size = args_size;
+ current_frame_info.extra_size = extra_size;
+ current_frame_info.gp_reg_size = gp_reg_size;
+ current_frame_info.fp_reg_size = fp_reg_size;
+ current_frame_info.gmask = gmask;
+ current_frame_info.fmask = fmask;
+ current_frame_info.reg_offset = reg_offset;
+ current_frame_info.initialized = reload_completed;
+
+ /* Ok, we're done. */
+ return total_size;
+}
+
+/* Save/restore registers in GMASK and FMASK at register BASE_REG plus offset
+ OFFSET.
+
+ BASE_REG must be 8 byte aligned. This allows us to test OFFSET for
+ appropriate alignment and use DOUBLEWORD_OP when we can. We assume
+ [BASE_REG+OFFSET] will always be a valid address.
+
+ WORD_OP is either "st" for save, "ld" for restore.
+ DOUBLEWORD_OP is either "std" for save, "ldd" for restore. */
+
+void
+sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op,
+ doubleword_op, base_offset)
+ FILE *file;
+ char *base_reg;
+ unsigned int offset;
+ unsigned long gmask;
+ unsigned long fmask;
+ char *word_op;
+ char *doubleword_op;
+ unsigned long base_offset;
+{
+ int regno;
+
+ if (gmask == 0 && fmask == 0)
+ return;
+
+ /* Save registers starting from high to low. We've already saved the
+ previous frame pointer and previous return address for the debugger's
+ sake. The debugger allows us to not need a nop in the epilog if at least
+ one register is reloaded in addition to return address. */
+
+ if (gmask)
+ {
+ for (regno = 1; regno <= 31; regno++)
+ {
+ if ((gmask & (1L << regno)) != 0)
+ {
+ if ((regno & 0x1) == 0 && ((gmask & (1L << (regno+1))) != 0))
+ {
+ /* We can save two registers in a row. If we're not at a
+ double word boundary, move to one.
+ sparc_flat_compute_frame_size ensures there's room to do
+ this. */
+ if (offset % 8 != 0)
+ offset += UNITS_PER_WORD;
+
+ if (word_op[0] == 's')
+ {
+ fprintf (file, "\t%s %s,[%s+%d]\n",
+ doubleword_op, reg_names[regno],
+ base_reg, offset);
+ if (dwarf2out_do_frame ())
+ {
+ char *l = dwarf2out_cfi_label ();
+ dwarf2out_reg_save (l, regno, offset + base_offset);
+ dwarf2out_reg_save
+ (l, regno+1, offset+base_offset + UNITS_PER_WORD);
+ }
+ }
+ else
+ fprintf (file, "\t%s [%s+%d],%s\n",
+ doubleword_op, base_reg, offset,
+ reg_names[regno]);
+
+ offset += 2 * UNITS_PER_WORD;
+ regno++;
+ }
+ else
+ {
+ if (word_op[0] == 's')
+ {
+ fprintf (file, "\t%s %s,[%s+%d]\n",
+ word_op, reg_names[regno],
+ base_reg, offset);
+ if (dwarf2out_do_frame ())
+ dwarf2out_reg_save ("", regno, offset + base_offset);
+ }
+ else
+ fprintf (file, "\t%s [%s+%d],%s\n",
+ word_op, base_reg, offset, reg_names[regno]);
+
+ offset += UNITS_PER_WORD;
+ }
+ }
+ }
+ }
+
+ if (fmask)
+ {
+ for (regno = 32; regno <= 63; regno++)
+ {
+ if ((fmask & (1L << (regno - 32))) != 0)
+ {
+ if (word_op[0] == 's')
+ {
+ fprintf (file, "\t%s %s,[%s+%d]\n",
+ word_op, reg_names[regno],
+ base_reg, offset);
+ if (dwarf2out_do_frame ())
+ dwarf2out_reg_save ("", regno, offset + base_offset);
+ }
+ else
+ fprintf (file, "\t%s [%s+%d],%s\n",
+ word_op, base_reg, offset, reg_names[regno]);
+
+ offset += UNITS_PER_WORD;
+ }
+ }
+ }
+}
+
+/* Set up the stack and frame (if desired) for the function. */
+
+void
+sparc_flat_output_function_prologue (file, size)
+ FILE *file;
+ int size;
+{
+ char *sp_str = reg_names[STACK_POINTER_REGNUM];
+ unsigned long gmask = current_frame_info.gmask;
+
+ /* This is only for the human reader. */
+ fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START);
+ fprintf (file, "\t%s# vars= %ld, regs= %d/%d, args= %d, extra= %ld\n",
+ ASM_COMMENT_START,
+ current_frame_info.var_size,
+ current_frame_info.gp_reg_size / 4,
+ current_frame_info.fp_reg_size / 4,
+ current_function_outgoing_args_size,
+ current_frame_info.extra_size);
+
+ size = SPARC_STACK_ALIGN (size);
+ size = (! current_frame_info.initialized
+ ? sparc_flat_compute_frame_size (size)
+ : current_frame_info.total_size);
+
+ /* These cases shouldn't happen. Catch them now. */
+ if (size == 0 && (gmask || current_frame_info.fmask))
+ abort ();
+
+ /* Allocate our stack frame by decrementing %sp.
+ At present, the only algorithm gdb can use to determine if this is a
+ flat frame is if we always set %i7 if we set %sp. This can be optimized
+ in the future by putting in some sort of debugging information that says
+ this is a `flat' function. However, there is still the case of debugging
+ code without such debugging information (including cases where most fns
+ have such info, but there is one that doesn't). So, always do this now
+ so we don't get a lot of code out there that gdb can't handle.
+ If the frame pointer isn't needn't then that's ok - gdb won't be able to
+ distinguish us from a non-flat function but there won't (and shouldn't)
+ be any differences anyway. The return pc is saved (if necessary) right
+ after %i7 so gdb won't have to look too far to find it. */
+ if (size > 0)
+ {
+ unsigned int reg_offset = current_frame_info.reg_offset;
+ char *fp_str = reg_names[FRAME_POINTER_REGNUM];
+ char *t1_str = "%g1";
+
+ /* Things get a little tricky if local variables take up more than ~4096
+ bytes and outgoing arguments take up more than ~4096 bytes. When that
+ happens, the register save area can't be accessed from either end of
+ the frame. Handle this by decrementing %sp to the start of the gp
+ register save area, save the regs, update %i7, and then set %sp to its
+ final value. Given that we only have one scratch register to play
+ with it is the cheapest solution, and it helps gdb out as it won't
+ slow down recognition of flat functions.
+ Don't change the order of insns emitted here without checking with
+ the gdb folk first. */
+
+ /* Is the entire register save area offsettable from %sp? */
+ if (reg_offset < 4096 - 64 * UNITS_PER_WORD)
+ {
+ if (size <= 4096)
+ {
+ fprintf (file, "\tadd %s,%d,%s\n",
+ sp_str, -size, sp_str);
+ if (gmask & FRAME_POINTER_MASK)
+ {
+ fprintf (file, "\tst %s,[%s+%d]\n",
+ fp_str, sp_str, reg_offset);
+ fprintf (file, "\tsub %s,%d,%s\t%s# set up frame pointer\n",
+ sp_str, -size, fp_str, ASM_COMMENT_START);
+ reg_offset += 4;
+ }
+ }
+ else
+ {
+ fprintf (file, "\tset %d,%s\n\tsub %s,%s,%s\n",
+ size, t1_str, sp_str, t1_str, sp_str);
+ if (gmask & FRAME_POINTER_MASK)
+ {
+ fprintf (file, "\tst %s,[%s+%d]\n",
+ fp_str, sp_str, reg_offset);
+ fprintf (file, "\tadd %s,%s,%s\t%s# set up frame pointer\n",
+ sp_str, t1_str, fp_str, ASM_COMMENT_START);
+ reg_offset += 4;
+ }
+ }
+ if (dwarf2out_do_frame ())
+ {
+ char *l = dwarf2out_cfi_label ();
+ if (gmask & FRAME_POINTER_MASK)
+ {
+ dwarf2out_reg_save (l, FRAME_POINTER_REGNUM,
+ reg_offset - 4 - size);
+ dwarf2out_def_cfa (l, FRAME_POINTER_REGNUM, 0);
+ }
+ else
+ dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size);
+ }
+ if (gmask & RETURN_ADDR_MASK)
+ {
+ fprintf (file, "\tst %s,[%s+%d]\n",
+ reg_names[RETURN_ADDR_REGNUM], sp_str, reg_offset);
+ if (dwarf2out_do_frame ())
+ dwarf2out_return_save ("", reg_offset - size);
+ reg_offset += 4;
+ }
+ sparc_flat_save_restore (file, sp_str, reg_offset,
+ gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK),
+ current_frame_info.fmask,
+ "st", "std", -size);
+ }
+ else
+ {
+ /* Subtract %sp in two steps, but make sure there is always a
+ 64 byte register save area, and %sp is properly aligned. */
+ /* Amount to decrement %sp by, the first time. */
+ unsigned int size1 = ((size - reg_offset + 64) + 15) & -16;
+ /* Offset to register save area from %sp. */
+ unsigned int offset = size1 - (size - reg_offset);
+
+ if (size1 <= 4096)
+ {
+ fprintf (file, "\tadd %s,%d,%s\n",
+ sp_str, -size1, sp_str);
+ if (gmask & FRAME_POINTER_MASK)
+ {
+ fprintf (file, "\tst %s,[%s+%d]\n\tsub %s,%d,%s\t%s# set up frame pointer\n",
+ fp_str, sp_str, offset, sp_str, -size1, fp_str,
+ ASM_COMMENT_START);
+ offset += 4;
+ }
+ }
+ else
+ {
+ fprintf (file, "\tset %d,%s\n\tsub %s,%s,%s\n",
+ size1, t1_str, sp_str, t1_str, sp_str);
+ if (gmask & FRAME_POINTER_MASK)
+ {
+ fprintf (file, "\tst %s,[%s+%d]\n\tadd %s,%s,%s\t%s# set up frame pointer\n",
+ fp_str, sp_str, offset, sp_str, t1_str, fp_str,
+ ASM_COMMENT_START);
+ offset += 4;
+ }
+ }
+ if (dwarf2out_do_frame ())
+ {
+ char *l = dwarf2out_cfi_label ();
+ if (gmask & FRAME_POINTER_MASK)
+ {
+ dwarf2out_reg_save (l, FRAME_POINTER_REGNUM,
+ offset - 4 - size1);
+ dwarf2out_def_cfa (l, FRAME_POINTER_REGNUM, 0);
+ }
+ else
+ dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size1);
+ }
+ if (gmask & RETURN_ADDR_MASK)
+ {
+ fprintf (file, "\tst %s,[%s+%d]\n",
+ reg_names[RETURN_ADDR_REGNUM], sp_str, offset);
+ if (dwarf2out_do_frame ())
+ /* offset - size1 == reg_offset - size
+ if reg_offset were updated above like offset. */
+ dwarf2out_return_save ("", offset - size1);
+ offset += 4;
+ }
+ sparc_flat_save_restore (file, sp_str, offset,
+ gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK),
+ current_frame_info.fmask,
+ "st", "std", -size1);
+ fprintf (file, "\tset %d,%s\n\tsub %s,%s,%s\n",
+ size - size1, t1_str, sp_str, t1_str, sp_str);
+ if (dwarf2out_do_frame ())
+ if (! (gmask & FRAME_POINTER_MASK))
+ dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, size);
+ }
+ }
+
+ fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START);
+}
+
+/* Do any necessary cleanup after a function to restore stack, frame,
+ and regs. */
+
+void
+sparc_flat_output_function_epilogue (file, size)
+ FILE *file;
+ int size;
+{
+ rtx epilogue_delay = current_function_epilogue_delay_list;
+ int noepilogue = FALSE;
+
+ /* This is only for the human reader. */
+ fprintf (file, "\t%s#EPILOGUE#\n", ASM_COMMENT_START);
+
+ /* The epilogue does not depend on any registers, but the stack
+ registers, so we assume that if we have 1 pending nop, it can be
+ ignored, and 2 it must be filled (2 nops occur for integer
+ multiply and divide). */
+
+ size = SPARC_STACK_ALIGN (size);
+ size = (!current_frame_info.initialized
+ ? sparc_flat_compute_frame_size (size)
+ : current_frame_info.total_size);
+
+ if (size == 0 && epilogue_delay == 0)
+ {
+ rtx insn = get_last_insn ();
+
+ /* If the last insn was a BARRIER, we don't have to write any code
+ because a jump (aka return) was put there. */
+ if (GET_CODE (insn) == NOTE)
+ insn = prev_nonnote_insn (insn);
+ if (insn && GET_CODE (insn) == BARRIER)
+ noepilogue = TRUE;
+ }
+
+ if (!noepilogue)
+ {
+ unsigned int reg_offset = current_frame_info.reg_offset;
+ unsigned int size1;
+ char *sp_str = reg_names[STACK_POINTER_REGNUM];
+ char *fp_str = reg_names[FRAME_POINTER_REGNUM];
+ char *t1_str = "%g1";
+
+ /* In the reload sequence, we don't need to fill the load delay
+ slots for most of the loads, also see if we can fill the final
+ delay slot if not otherwise filled by the reload sequence. */
+
+ if (size > 4095)
+ fprintf (file, "\tset %d,%s\n", size, t1_str);
+
+ if (frame_pointer_needed)
+ {
+ if (size > 4095)
+ fprintf (file,"\tsub %s,%s,%s\t\t%s# sp not trusted here\n",
+ fp_str, t1_str, sp_str, ASM_COMMENT_START);
+ else
+ fprintf (file,"\tsub %s,%d,%s\t\t%s# sp not trusted here\n",
+ fp_str, size, sp_str, ASM_COMMENT_START);
+ }
+
+ /* Is the entire register save area offsettable from %sp? */
+ if (reg_offset < 4096 - 64 * UNITS_PER_WORD)
+ {
+ size1 = 0;
+ }
+ else
+ {
+ /* Restore %sp in two steps, but make sure there is always a
+ 64 byte register save area, and %sp is properly aligned. */
+ /* Amount to increment %sp by, the first time. */
+ size1 = ((reg_offset - 64 - 16) + 15) & -16;
+ /* Offset to register save area from %sp. */
+ reg_offset = size1 - reg_offset;
+
+ fprintf (file, "\tset %d,%s\n\tadd %s,%s,%s\n",
+ size1, t1_str, sp_str, t1_str, sp_str);
+ }
+
+ /* We must restore the frame pointer and return address reg first
+ because they are treated specially by the prologue output code. */
+ if (current_frame_info.gmask & FRAME_POINTER_MASK)
+ {
+ fprintf (file, "\tld [%s+%d],%s\n",
+ sp_str, reg_offset, fp_str);
+ reg_offset += 4;
+ }
+ if (current_frame_info.gmask & RETURN_ADDR_MASK)
+ {
+ fprintf (file, "\tld [%s+%d],%s\n",
+ sp_str, reg_offset, reg_names[RETURN_ADDR_REGNUM]);
+ reg_offset += 4;
+ }
+
+ /* Restore any remaining saved registers. */
+ sparc_flat_save_restore (file, sp_str, reg_offset,
+ current_frame_info.gmask & ~(FRAME_POINTER_MASK | RETURN_ADDR_MASK),
+ current_frame_info.fmask,
+ "ld", "ldd", 0);
+
+ /* If we had to increment %sp in two steps, record it so the second
+ restoration in the epilogue finishes up. */
+ if (size1 > 0)
+ {
+ size -= size1;
+ if (size > 4095)
+ fprintf (file, "\tset %d,%s\n",
+ size, t1_str);
+ }
+
+ if (current_function_returns_struct)
+ fprintf (file, "\tjmp %%o7+12\n");
+ else
+ fprintf (file, "\tretl\n");
+
+ /* If the only register saved is the return address, we need a
+ nop, unless we have an instruction to put into it. Otherwise
+ we don't since reloading multiple registers doesn't reference
+ the register being loaded. */
+
+ if (epilogue_delay)
+ {
+ if (size)
+ abort ();
+ final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1);
+ }
+
+ else if (size > 4095)
+ fprintf (file, "\tadd %s,%s,%s\n", sp_str, t1_str, sp_str);
+
+ else if (size > 0)
+ fprintf (file, "\tadd %s,%d,%s\n", sp_str, size, sp_str);
+
+ else
+ fprintf (file, "\tnop\n");
+ }
+
+ /* Reset state info for each function. */
+ current_frame_info = zero_frame_info;
+}
+
+/* Define the number of delay slots needed for the function epilogue.
+
+ On the sparc, we need a slot if either no stack has been allocated,
+ or the only register saved is the return register. */
+
+int
+sparc_flat_epilogue_delay_slots ()
+{
+ if (!current_frame_info.initialized)
+ (void) sparc_flat_compute_frame_size (get_frame_size ());
+
+ if (current_frame_info.total_size == 0)
+ return 1;
+
+ return 0;
+}
+
+/* Return true is TRIAL is a valid insn for the epilogue delay slot.
+ Any single length instruction which doesn't reference the stack or frame
+ pointer is OK. */
+
+int
+sparc_flat_eligible_for_epilogue_delay (trial, slot)
+ rtx trial;
+ int slot ATTRIBUTE_UNUSED;
+{
+ rtx pat = PATTERN (trial);
+
+ if (get_attr_length (trial) != 1)
+ return 0;
+
+ /* If %g0 is live, there are lots of things we can't handle.
+ Rather than trying to find them all now, let's punt and only
+ optimize things as necessary. */
+ if (TARGET_LIVE_G0)
+ return 0;
+
+ if (! reg_mentioned_p (stack_pointer_rtx, pat)
+ && ! reg_mentioned_p (frame_pointer_rtx, pat))
+ return 1;
+
+ return 0;
+}
+
+/* Adjust the cost of a scheduling dependency. Return the new cost of
+ a dependency LINK or INSN on DEP_INSN. COST is the current cost. */
+
+int
+supersparc_adjust_cost (insn, link, dep_insn, cost)
+ rtx insn;
+ rtx link;
+ rtx dep_insn;
+ int cost;
+{
+ enum attr_type insn_type;
+
+ if (! recog_memoized (insn))
+ return 0;
+
+ insn_type = get_attr_type (insn);
+
+ if (REG_NOTE_KIND (link) == 0)
+ {
+ /* Data dependency; DEP_INSN writes a register that INSN reads some
+ cycles later. */
+
+ /* if a load, then the dependence must be on the memory address;
+ add an extra 'cycle'. Note that the cost could be two cycles
+ if the reg was written late in an instruction group; we can't tell
+ here. */
+ if (insn_type == TYPE_LOAD || insn_type == TYPE_FPLOAD)
+ return cost + 3;
+
+ /* Get the delay only if the address of the store is the dependence. */
+ if (insn_type == TYPE_STORE || insn_type == TYPE_FPSTORE)
+ {
+ rtx pat = PATTERN(insn);
+ rtx dep_pat = PATTERN (dep_insn);
+
+ if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
+ return cost; /* This shouldn't happen! */
+
+ /* The dependency between the two instructions was on the data that
+ is being stored. Assume that this implies that the address of the
+ store is not dependent. */
+ if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
+ return cost;
+
+ return cost + 3; /* An approximation. */
+ }
+
+ /* A shift instruction cannot receive its data from an instruction
+ in the same cycle; add a one cycle penalty. */
+ if (insn_type == TYPE_SHIFT)
+ return cost + 3; /* Split before cascade into shift. */
+ }
+ else
+ {
+ /* Anti- or output- dependency; DEP_INSN reads/writes a register that
+ INSN writes some cycles later. */
+
+ /* These are only significant for the fpu unit; writing a fp reg before
+ the fpu has finished with it stalls the processor. */
+
+ /* Reusing an integer register causes no problems. */
+ if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT)
+ return 0;
+ }
+
+ return cost;
+}
+
+int
+ultrasparc_adjust_cost (insn, link, dep_insn, cost)
+ rtx insn;
+ rtx link;
+ rtx dep_insn;
+ int cost;
+{
+ enum attr_type insn_type, dep_type;
+ rtx pat = PATTERN(insn);
+ rtx dep_pat = PATTERN (dep_insn);
+
+ if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
+ return cost;
+
+ insn_type = get_attr_type (insn);
+ dep_type = get_attr_type (dep_insn);
+
+#define SLOW_FP(dep_type) \
+(dep_type == TYPE_FPSQRT || dep_type == TYPE_FPDIVS || dep_type == TYPE_FPDIVD)
+
+ switch (REG_NOTE_KIND (link))
+ {
+ case 0:
+ /* Data dependency; DEP_INSN writes a register that INSN reads some
+ cycles later. */
+
+ switch (insn_type)
+ {
+ /* UltraSPARC can dual issue a store and an instruction setting
+ the value stored, except for divide and square root. */
+ case TYPE_FPSTORE:
+ if (! SLOW_FP (dep_type))
+ return 0;
+ return cost;
+
+ case TYPE_STORE:
+ if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
+ return cost;
+
+ if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
+ /* The dependency between the two instructions is on the data
+ that is being stored. Assume that the address of the store
+ is not also dependent. */
+ return 0;
+ return cost;
+
+ case TYPE_LOAD:
+ case TYPE_SLOAD:
+ case TYPE_FPLOAD:
+ /* A load does not return data until at least 11 cycles after
+ a store to the same location. 3 cycles are accounted for
+ in the load latency; add the other 8 here. */
+ if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE)
+ {
+ /* If the addresses are not equal this may be a false
+ dependency because pointer aliasing could not be
+ determined. Add only 2 cycles in that case. 2 is
+ an arbitrary compromise between 8, which would cause
+ the scheduler to generate worse code elsewhere to
+ compensate for a dependency which might not really
+ exist, and 0. */
+ if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET
+ || GET_CODE (SET_SRC (pat)) != MEM
+ || GET_CODE (SET_DEST (dep_pat)) != MEM
+ || ! rtx_equal_p (XEXP (SET_SRC (pat), 0),
+ XEXP (SET_DEST (dep_pat), 0)))
+ return cost + 2;
+
+ return cost + 8;
+ }
+ return cost;
+
+ case TYPE_BRANCH:
+ /* Compare to branch latency is 0. There is no benefit from
+ separating compare and branch. */
+ if (dep_type == TYPE_COMPARE)
+ return 0;
+ /* Floating point compare to branch latency is less than
+ compare to conditional move. */
+ if (dep_type == TYPE_FPCMP)
+ return cost - 1;
+ return cost;
+
+ case TYPE_FPCMOVE:
+ /* FMOVR class instructions can not issue in the same cycle
+ or the cycle after an instruction which writes any
+ integer register. Model this as cost 2 for dependent
+ instructions. */
+ if ((dep_type == TYPE_IALU || dep_type == TYPE_UNARY
+ || dep_type == TYPE_BINARY)
+ && cost < 2)
+ return 2;
+ /* Otherwise check as for integer conditional moves. */
+
+ case TYPE_CMOVE:
+ /* Conditional moves involving integer registers wait until
+ 3 cycles after loads return data. The interlock applies
+ to all loads, not just dependent loads, but that is hard
+ to model. */
+ if (dep_type == TYPE_LOAD || dep_type == TYPE_SLOAD)
+ return cost + 3;
+ return cost;
+
+ default:
+ break;
+ }
+ break;
+
+ case REG_DEP_ANTI:
+ /* Divide and square root lock destination registers for full latency. */
+ if (! SLOW_FP (dep_type))
+ return 0;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Other costs not accounted for:
+ - Multiply should be modeled as having no latency because there is
+ nothing the scheduler can do about it.
+ - Single precision floating point loads lock the other half of
+ the even/odd register pair.
+ - Several hazards associated with ldd/std are ignored because these
+ instructions are rarely generated for V9.
+ - A shift following an integer instruction which does not set the
+ condition codes can not issue in the same cycle.
+ - The floating point pipeline can not have both a single and double
+ precision operation active at the same time. Format conversions
+ and graphics instructions are given honorary double precision status.
+ - call and jmpl are always the first instruction in a group. */
+
+ return cost;
+}
+
+int
+sparc_issue_rate ()
+{
+ switch (sparc_cpu)
+ {
+ default:
+ return 1;
+ case PROCESSOR_V9:
+ /* Assume V9 processors are capable of at least dual-issue. */
+ return 2;
+ case PROCESSOR_SUPERSPARC:
+ return 3;
+ case PROCESSOR_ULTRASPARC:
+ return 4;
+ }
+}
+
+static int
+set_extends(x, insn)
+ rtx x, insn;
+{
+ register rtx pat = PATTERN (insn);
+
+ switch (GET_CODE (SET_SRC (pat)))
+ {
+ /* Load and some shift instructions zero extend. */
+ case MEM:
+ case ZERO_EXTEND:
+ /* sethi clears the high bits */
+ case HIGH:
+ /* LO_SUM is used with sethi. sethi cleared the high
+ bits and the values used with lo_sum are positive */
+ case LO_SUM:
+ /* UNSPEC is v8plus_clear_high */
+ case UNSPEC:
+ /* Store flag stores 0 or 1 */
+ case LT: case LTU:
+ case GT: case GTU:
+ case LE: case LEU:
+ case GE: case GEU:
+ case EQ:
+ case NE:
+ return 1;
+ case AND:
+ {
+ rtx op1 = XEXP (SET_SRC (pat), 1);
+ if (GET_CODE (op1) == CONST_INT)
+ return INTVAL (op1) >= 0;
+ if (GET_CODE (XEXP (SET_SRC (pat), 0)) == REG
+ && sparc_check_64 (XEXP (SET_SRC (pat), 0), insn) == 1)
+ return 1;
+ if (GET_CODE (op1) == REG
+ && sparc_check_64 ((op1), insn) == 1)
+ return 1;
+ }
+ case ASHIFT:
+ case LSHIFTRT:
+ return GET_MODE (SET_SRC (pat)) == SImode;
+ /* Positive integers leave the high bits zero. */
+ case CONST_DOUBLE:
+ return ! (CONST_DOUBLE_LOW (x) & 0x80000000);
+ case CONST_INT:
+ return ! (INTVAL (x) & 0x80000000);
+ case ASHIFTRT:
+ case SIGN_EXTEND:
+ return - (GET_MODE (SET_SRC (pat)) == SImode);
+ default:
+ return 0;
+ }
+}
+
+/* Return 0 if the high 32 bits of X (the low word of X, if DImode) are
+ unknown. Return 1 if the high bits are zero, -1 if the register is
+ sign extended. */
+int
+sparc_check_64 (x, insn)
+ rtx x, insn;
+{
+ /* If a register is set only once it is safe to ignore insns this
+ code does not know how to handle. The loop will either recognize
+ the single set and return the correct value or fail to recognize
+ it and return 0. */
+ int set_once = 0;
+
+ if (GET_CODE (x) == REG
+ && flag_expensive_optimizations
+ && REG_N_SETS (REGNO (x)) == 1)
+ set_once = 1;
+
+ if (insn == 0)
+ {
+ if (set_once)
+ insn = get_last_insn_anywhere ();
+ else
+ return 0;
+ }
+
+ while ((insn = PREV_INSN (insn)))
+ {
+ switch (GET_CODE (insn))
+ {
+ case JUMP_INSN:
+ case NOTE:
+ break;
+ case CODE_LABEL:
+ case CALL_INSN:
+ default:
+ if (! set_once)
+ return 0;
+ break;
+ case INSN:
+ {
+ rtx pat = PATTERN (insn);
+ if (GET_CODE (pat) != SET)
+ return 0;
+ if (rtx_equal_p (x, SET_DEST (pat)))
+ return set_extends (x, insn);
+ if (reg_overlap_mentioned_p (SET_DEST (pat), x))
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+char *
+sparc_v8plus_shift (operands, insn, opcode)
+ rtx *operands;
+ rtx insn;
+ char *opcode;
+{
+ static char asm_code[60];
+
+ if (GET_CODE (operands[3]) == SCRATCH)
+ operands[3] = operands[0];
+ if (GET_CODE (operands[1]) == CONST_INT)
+ {
+ output_asm_insn ("mov %1,%3", operands);
+ }
+ else
+ {
+ output_asm_insn ("sllx %H1,32,%3", operands);
+ if (sparc_check_64 (operands[1], insn) <= 0)
+ output_asm_insn ("srl %L1,0,%L1", operands);
+ output_asm_insn ("or %L1,%3,%3", operands);
+ }
+
+ strcpy(asm_code, opcode);
+ if (which_alternative != 2)
+ return strcat (asm_code, " %0,%2,%L0\n\tsrlx %L0,32,%H0");
+ else
+ return strcat (asm_code, " %3,%2,%3\n\tsrlx %3,32,%H0\n\tmov %3,%L0");
+}
+
+
+/* Return 1 if DEST and SRC reference only global and in registers. */
+
+int
+sparc_return_peephole_ok (dest, src)
+ rtx dest, src;
+{
+ if (! TARGET_V9)
+ return 0;
+ if (leaf_function)
+ return 0;
+ if (GET_CODE (src) != CONST_INT
+ && (GET_CODE (src) != REG || ! IN_OR_GLOBAL_P (src)))
+ return 0;
+ return IN_OR_GLOBAL_P (dest);
+}
diff --git a/contrib/gcc/config/sparc/sparc.h b/contrib/gcc/config/sparc/sparc.h
new file mode 100644
index 0000000..e66f5e6
--- /dev/null
+++ b/contrib/gcc/config/sparc/sparc.h
@@ -0,0 +1,3287 @@
+/* Definitions of target machine for GNU compiler, for Sun SPARC.
+ Copyright (C) 1987, 88, 89, 92, 94-97, 1998 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann (tiemann@cygnus.com).
+ 64 bit SPARC V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
+ at Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Note that some other tm.h files include this one and then override
+ whatever definitions are necessary. */
+
+/* Specify this in a cover file to provide bi-architecture (32/64) support. */
+/* #define SPARC_BI_ARCH */
+
+/* Macro used later in this file to determine default architecture. */
+#define DEFAULT_ARCH32_P ((TARGET_DEFAULT & MASK_64BIT) == 0)
+
+/* TARGET_ARCH{32,64} are the main macros to decide which of the two
+ architectures to compile for. We allow targets to choose compile time or
+ runtime selection. */
+#ifdef SPARC_BI_ARCH
+#define TARGET_ARCH32 (! TARGET_64BIT)
+#else
+#define TARGET_ARCH32 (DEFAULT_ARCH32_P)
+#endif
+#define TARGET_ARCH64 (! TARGET_ARCH32)
+
+/* Code model selection.
+ -mcmodel is used to select the v9 code model.
+ Different code models aren't supported for v8 code.
+
+ TARGET_CM_32: 32 bit address space, top 32 bits = 0,
+ pointers are 32 bits. Note that this isn't intended
+ to imply a v8 abi.
+
+ TARGET_CM_MEDLOW: 32 bit address space, top 32 bits = 0,
+ avoid generating %uhi and %ulo terms,
+ pointers are 64 bits.
+
+ TARGET_CM_MEDMID: 64 bit address space.
+ The executable must be in the low 16 TB of memory.
+ This corresponds to the low 44 bits, and the %[hml]44
+ relocs are used.
+
+ TARGET_CM_MEDANY: 64 bit address space.
+ The text and data segments have a maximum size of 31
+ bits and may be located anywhere. The maximum offset
+ from any instruction to the label _GLOBAL_OFFSET_TABLE_
+ is 31 bits.
+
+ TARGET_CM_EMBMEDANY: 64 bit address space.
+ The text and data segments have a maximum size of 31 bits
+ and may be located anywhere. Register %g4 contains
+ the start address of the data segment.
+*/
+
+enum cmodel {
+ CM_32,
+ CM_MEDLOW,
+ CM_MEDMID,
+ CM_MEDANY,
+ CM_EMBMEDANY
+};
+
+/* Value of -mcmodel specified by user. */
+extern char *sparc_cmodel_string;
+/* One of CM_FOO. */
+extern enum cmodel sparc_cmodel;
+
+/* V9 code model selection. */
+#define TARGET_CM_MEDLOW (sparc_cmodel == CM_MEDLOW)
+#define TARGET_CM_MEDMID (sparc_cmodel == CM_MEDMID)
+#define TARGET_CM_MEDANY (sparc_cmodel == CM_MEDANY)
+#define TARGET_CM_EMBMEDANY (sparc_cmodel == CM_EMBMEDANY)
+
+#define SPARC_DEFAULT_CMODEL CM_MEDLOW
+
+/* This is call-clobbered in the normal ABI, but is reserved in the
+ home grown (aka upward compatible) embedded ABI. */
+#define EMBMEDANY_BASE_REG "%g4"
+
+/* Values of TARGET_CPU_DEFAULT, set via -D in the Makefile,
+ and specified by the user via --with-cpu=foo.
+ This specifies the cpu implementation, not the architecture size. */
+#define TARGET_CPU_sparc 0
+#define TARGET_CPU_v7 0 /* alias for previous */
+#define TARGET_CPU_sparclet 1
+#define TARGET_CPU_sparclite 2
+#define TARGET_CPU_v8 3 /* generic v8 implementation */
+#define TARGET_CPU_supersparc 4
+#define TARGET_CPU_v9 5 /* generic v9 implementation */
+#define TARGET_CPU_sparc64 5 /* alias */
+#define TARGET_CPU_ultrasparc 6
+
+#if TARGET_CPU_DEFAULT == TARGET_CPU_sparc || TARGET_CPU_DEFAULT == TARGET_CPU_v8 || TARGET_CPU_DEFAULT == TARGET_CPU_supersparc
+#define CPP_CPU_DEFAULT_SPEC ""
+#define ASM_CPU_DEFAULT_SPEC ""
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_sparclet
+#define CPP_CPU_DEFAULT_SPEC "-D__sparclet__"
+#define ASM_CPU_DEFAULT_SPEC "-Asparclet"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_sparclite
+#define CPP_CPU_DEFAULT_SPEC "-D__sparclite__"
+#define ASM_CPU_DEFAULT_SPEC "-Asparclite"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_v9
+/* ??? What does Sun's CC pass? */
+#define CPP_CPU_DEFAULT_SPEC "-D__sparc_v9__"
+/* ??? It's not clear how other assemblers will handle this, so by default
+ use GAS. Sun's Solaris assembler recognizes -xarch=v8plus, but this case
+ is handled in sol2.h. */
+#define ASM_CPU_DEFAULT_SPEC "-Av9"
+#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc
+#define CPP_CPU_DEFAULT_SPEC "-D__sparc_v9__"
+#define ASM_CPU_DEFAULT_SPEC "-Av9a"
+#endif
+#ifndef CPP_CPU_DEFAULT_SPEC
+Unrecognized value in TARGET_CPU_DEFAULT.
+#endif
+
+/* Names to predefine in the preprocessor for this target machine.
+ ??? It would be nice to not include any subtarget specific values here,
+ however there's no way to portably provide subtarget values to
+ CPP_PREFINES. Also, -D values in CPP_SUBTARGET_SPEC don't get turned into
+ foo, __foo and __foo__. */
+
+#define CPP_PREDEFINES "-Dsparc -Dsun -Dunix -Asystem(unix) -Asystem(bsd)"
+
+/* Define macros to distinguish architectures. */
+
+/* Common CPP definitions used by CPP_SPEC amongst the various targets
+ for handling -mcpu=xxx switches. */
+#define CPP_CPU_SPEC "\
+%{mcypress:} \
+%{msparclite:-D__sparclite__} \
+%{mf930:-D__sparclite__} %{mf934:-D__sparclite__} \
+%{mv8:-D__sparc_v8__} \
+%{msupersparc:-D__supersparc__ -D__sparc_v8__} \
+%{mcpu=sparclet:-D__sparclet__} %{mcpu=tsc701:-D__sparclet__} \
+%{mcpu=sparclite:-D__sparclite__} \
+%{mcpu=f930:-D__sparclite__} %{mcpu=f934:-D__sparclite__} \
+%{mcpu=v8:-D__sparc_v8__} \
+%{mcpu=supersparc:-D__supersparc__ -D__sparc_v8__} \
+%{mcpu=v9:-D__sparc_v9__} \
+%{mcpu=ultrasparc:-D__sparc_v9__} \
+%{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8:%{!msupersparc:%(cpp_cpu_default)}}}}}}} \
+"
+
+/* ??? The GCC_NEW_VARARGS macro is now obsolete, because gcc always uses
+ the right varags.h file when bootstrapping. */
+/* ??? It's not clear what value we want to use for -Acpu/machine for
+ sparc64 in 32 bit environments, so for now we only use `sparc64' in
+ 64 bit environments. */
+
+#define CPP_ARCH32_SPEC "-D__GCC_NEW_VARARGS__ -Acpu(sparc) -Amachine(sparc)"
+#define CPP_ARCH64_SPEC "-D__arch64__ -Acpu(sparc64) -Amachine(sparc64)"
+#define CPP_ARCH_DEFAULT_SPEC \
+(DEFAULT_ARCH32_P ? CPP_ARCH32_SPEC : CPP_ARCH64_SPEC)
+
+#define CPP_ARCH_SPEC "\
+%{m32:%(cpp_arch32)} \
+%{m64:%(cpp_arch64)} \
+%{!m32:%{!m64:%(cpp_arch_default)}} \
+"
+
+/* Macros to distinguish endianness. */
+#define CPP_ENDIAN_SPEC "%{mlittle-endian:-D__LITTLE_ENDIAN__}"
+
+/* Macros to distinguish the particular subtarget. */
+#define CPP_SUBTARGET_SPEC ""
+
+#define CPP_SPEC "%(cpp_cpu) %(cpp_arch) %(cpp_endian) %(cpp_subtarget)"
+
+/* Prevent error on `-sun4' and `-target sun4' options. */
+/* This used to translate -dalign to -malign, but that is no good
+ because it can't turn off the usual meaning of making debugging dumps. */
+/* Translate old style -m<cpu> into new style -mcpu=<cpu>.
+ ??? Delete support for -m<cpu> for 2.9. */
+
+#define CC1_SPEC "\
+%{sun4:} %{target:} \
+%{mcypress:-mcpu=cypress} \
+%{msparclite:-mcpu=sparclite} %{mf930:-mcpu=f930} %{mf934:-mcpu=f934} \
+%{mv8:-mcpu=v8} %{msupersparc:-mcpu=supersparc} \
+"
+
+/* Override in target specific files. */
+#define ASM_CPU_SPEC "\
+%{mcpu=sparclet:-Asparclet} %{mcpu=tsc701:-Asparclet} \
+%{msparclite:-Asparclite} \
+%{mf930:-Asparclite} %{mf934:-Asparclite} \
+%{mcpu=sparclite:-Asparclite} \
+%{mcpu=f930:-Asparclite} %{mcpu=f934:-Asparclite} \
+%{mv8plus:-Av8plus} \
+%{mcpu=v9:-Av9} \
+%{mcpu=ultrasparc:%{!mv8plus:-Av9a}} \
+%{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8:%{!msupersparc:%(asm_cpu_default)}}}}}}} \
+"
+
+/* Word size selection, among other things.
+ This is what GAS uses. Add %(asm_arch) to ASM_SPEC to enable. */
+
+#define ASM_ARCH32_SPEC "-32"
+#define ASM_ARCH64_SPEC "-64"
+#define ASM_ARCH_DEFAULT_SPEC \
+(DEFAULT_ARCH32_P ? ASM_ARCH32_SPEC : ASM_ARCH64_SPEC)
+
+#define ASM_ARCH_SPEC "\
+%{m32:%(asm_arch32)} \
+%{m64:%(asm_arch64)} \
+%{!m32:%{!m64:%(asm_arch_default)}} \
+"
+
+/* Special flags to the Sun-4 assembler when using pipe for input. */
+
+#define ASM_SPEC "\
+%| %{R} %{!pg:%{!p:%{fpic:-k} %{fPIC:-k}}} %{keep-local-as-symbols:-L} \
+%(asm_cpu) \
+"
+
+#define LIB_SPEC "%{!shared:%{!p:%{!pg:-lc}}%{p:-lc_p}%{pg:-lc_p} %{g:-lg}}"
+
+/* Provide required defaults for linker -e and -d switches. */
+
+#define LINK_SPEC \
+ "%{!shared:%{!nostdlib:%{!r*:%{!e*:-e start}}} -dc -dp} %{static:-Bstatic} \
+ %{assert*} %{shared:%{!mimpure-text:-assert pure-text}}"
+
+/* This macro defines names of additional specifications to put in the specs
+ that can be used in various specifications like CC1_SPEC. Its definition
+ is an initializer with a subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the
+ specification name, and a string constant that used by the GNU CC driver
+ program.
+
+ Do not define this macro if it does not need to do anything. */
+
+#define EXTRA_SPECS \
+ { "cpp_cpu", CPP_CPU_SPEC }, \
+ { "cpp_cpu_default", CPP_CPU_DEFAULT_SPEC }, \
+ { "cpp_arch32", CPP_ARCH32_SPEC }, \
+ { "cpp_arch64", CPP_ARCH64_SPEC }, \
+ { "cpp_arch_default", CPP_ARCH_DEFAULT_SPEC }, \
+ { "cpp_arch", CPP_ARCH_SPEC }, \
+ { "cpp_endian", CPP_ENDIAN_SPEC }, \
+ { "cpp_subtarget", CPP_SUBTARGET_SPEC }, \
+ { "asm_cpu", ASM_CPU_SPEC }, \
+ { "asm_cpu_default", ASM_CPU_DEFAULT_SPEC }, \
+ { "asm_arch32", ASM_ARCH32_SPEC }, \
+ { "asm_arch64", ASM_ARCH64_SPEC }, \
+ { "asm_arch_default", ASM_ARCH_DEFAULT_SPEC }, \
+ { "asm_arch", ASM_ARCH_SPEC }, \
+ SUBTARGET_EXTRA_SPECS
+
+#define SUBTARGET_EXTRA_SPECS
+
+#ifdef SPARC_BI_ARCH
+#define NO_BUILTIN_PTRDIFF_TYPE
+#define NO_BUILTIN_SIZE_TYPE
+#endif
+#define PTRDIFF_TYPE (TARGET_ARCH64 ? "long int" : "int")
+#define SIZE_TYPE (TARGET_ARCH64 ? "long unsigned int" : "unsigned int")
+
+/* ??? This should be 32 bits for v9 but what can we do? */
+#define WCHAR_TYPE "short unsigned int"
+#define WCHAR_TYPE_SIZE 16
+#define MAX_WCHAR_TYPE_SIZE 16
+
+/* Show we can debug even without a frame pointer. */
+#define CAN_DEBUG_WITHOUT_FP
+
+/* To make profiling work with -f{pic,PIC}, we need to emit the profiling
+ code into the rtl. Also, if we are profiling, we cannot eliminate
+ the frame pointer (because the return address will get smashed). */
+
+void sparc_override_options ();
+
+#define OVERRIDE_OPTIONS \
+ do { \
+ if (profile_flag || profile_block_flag || profile_arc_flag) \
+ { \
+ if (flag_pic) \
+ { \
+ char *pic_string = (flag_pic == 1) ? "-fpic" : "-fPIC"; \
+ warning ("%s and profiling conflict: disabling %s", \
+ pic_string, pic_string); \
+ flag_pic = 0; \
+ } \
+ flag_omit_frame_pointer = 0; \
+ } \
+ sparc_override_options (); \
+ SUBTARGET_OVERRIDE_OPTIONS; \
+ } while (0)
+
+/* This is meant to be redefined in the host dependent files. */
+#define SUBTARGET_OVERRIDE_OPTIONS
+
+/* These compiler options take an argument. We ignore -target for now. */
+
+#define WORD_SWITCH_TAKES_ARG(STR) \
+ (DEFAULT_WORD_SWITCH_TAKES_ARG (STR) \
+ || !strcmp (STR, "target") || !strcmp (STR, "assert"))
+
+/* Print subsidiary information on the compiler version in use. */
+
+#define TARGET_VERSION fprintf (stderr, " (sparc)");
+
+/* Generate DBX debugging information. */
+
+#define DBX_DEBUGGING_INFO
+
+/* Run-time compilation parameters selecting different hardware subsets. */
+
+extern int target_flags;
+
+/* Nonzero if we should generate code to use the fpu. */
+#define MASK_FPU 1
+#define TARGET_FPU (target_flags & MASK_FPU)
+
+/* Nonzero if we should use FUNCTION_EPILOGUE. Otherwise, we
+ use fast return insns, but lose some generality. */
+#define MASK_EPILOGUE 2
+#define TARGET_EPILOGUE (target_flags & MASK_EPILOGUE)
+
+/* Nonzero if we should assume that double pointers might be unaligned.
+ This can happen when linking gcc compiled code with other compilers,
+ because the ABI only guarantees 4 byte alignment. */
+#define MASK_UNALIGNED_DOUBLES 4
+#define TARGET_UNALIGNED_DOUBLES (target_flags & MASK_UNALIGNED_DOUBLES)
+
+/* Nonzero means that we should generate code for a v8 sparc. */
+#define MASK_V8 0x8
+#define TARGET_V8 (target_flags & MASK_V8)
+
+/* Nonzero means that we should generate code for a sparclite.
+ This enables the sparclite specific instructions, but does not affect
+ whether FPU instructions are emitted. */
+#define MASK_SPARCLITE 0x10
+#define TARGET_SPARCLITE (target_flags & MASK_SPARCLITE)
+
+/* Nonzero if we're compiling for the sparclet. */
+#define MASK_SPARCLET 0x20
+#define TARGET_SPARCLET (target_flags & MASK_SPARCLET)
+
+/* Nonzero if we're compiling for v9 sparc.
+ Note that v9's can run in 32 bit mode so this doesn't necessarily mean
+ the word size is 64. */
+#define MASK_V9 0x40
+#define TARGET_V9 (target_flags & MASK_V9)
+
+/* Non-zero to generate code that uses the instructions deprecated in
+ the v9 architecture. This option only applies to v9 systems. */
+/* ??? This isn't user selectable yet. It's used to enable such insns
+ on 32 bit v9 systems and for the moment they're permanently disabled
+ on 64 bit v9 systems. */
+#define MASK_DEPRECATED_V8_INSNS 0x80
+#define TARGET_DEPRECATED_V8_INSNS (target_flags & MASK_DEPRECATED_V8_INSNS)
+
+/* Mask of all CPU selection flags. */
+#define MASK_ISA \
+(MASK_V8 + MASK_SPARCLITE + MASK_SPARCLET + MASK_V9 + MASK_DEPRECATED_V8_INSNS)
+
+/* Non-zero means don't pass `-assert pure-text' to the linker. */
+#define MASK_IMPURE_TEXT 0x100
+#define TARGET_IMPURE_TEXT (target_flags & MASK_IMPURE_TEXT)
+
+/* Nonzero means that we should generate code using a flat register window
+ model, i.e. no save/restore instructions are generated, which is
+ compatible with normal sparc code.
+ The frame pointer is %i7 instead of %fp. */
+#define MASK_FLAT 0x200
+#define TARGET_FLAT (target_flags & MASK_FLAT)
+
+/* Nonzero means use the registers that the Sparc ABI reserves for
+ application software. This must be the default to coincide with the
+ setting in FIXED_REGISTERS. */
+#define MASK_APP_REGS 0x400
+#define TARGET_APP_REGS (target_flags & MASK_APP_REGS)
+
+/* Option to select how quad word floating point is implemented.
+ When TARGET_HARD_QUAD is true, we use the hardware quad instructions.
+ Otherwise, we use the SPARC ABI quad library functions. */
+#define MASK_HARD_QUAD 0x800
+#define TARGET_HARD_QUAD (target_flags & MASK_HARD_QUAD)
+
+/* Non-zero on little-endian machines. */
+/* ??? Little endian support currently only exists for sparclet-aout and
+ sparc64-elf configurations. May eventually want to expand the support
+ to all targets, but for now it's kept local to only those two. */
+#define MASK_LITTLE_ENDIAN 0x1000
+#define TARGET_LITTLE_ENDIAN (target_flags & MASK_LITTLE_ENDIAN)
+
+/* 0x2000, 0x4000 are unused */
+
+/* Nonzero if pointers are 64 bits.
+ This is not a user selectable option, though it may be one day -
+ so it is used to determine pointer size instead of an architecture flag. */
+#define MASK_PTR64 0x8000
+#define TARGET_PTR64 (target_flags & MASK_PTR64)
+
+/* Nonzero if generating code to run in a 64 bit environment.
+ This is intended to only be used by TARGET_ARCH{32,64} as they are the
+ mechanism used to control compile time or run time selection. */
+#define MASK_64BIT 0x10000
+#define TARGET_64BIT (target_flags & MASK_64BIT)
+
+/* 0x20000,0x40000 unused */
+
+/* Non-zero means use a stack bias of 2047. Stack offsets are obtained by
+ adding 2047 to %sp. This option is for v9 only and is the default. */
+#define MASK_STACK_BIAS 0x80000
+#define TARGET_STACK_BIAS (target_flags & MASK_STACK_BIAS)
+
+/* Non-zero means %g0 is a normal register.
+ We still clobber it as necessary, but we can't rely on it always having
+ a zero value.
+ We don't bother to support this in true 64 bit mode. */
+#define MASK_LIVE_G0 0x100000
+#define TARGET_LIVE_G0 (target_flags & MASK_LIVE_G0)
+
+/* Non-zero means the cpu has broken `save' and `restore' insns, only
+ the trivial versions work (save %g0,%g0,%g0; restore %g0,%g0,%g0).
+ We assume the environment will properly handle or otherwise avoid
+ trouble associated with an interrupt occurring after the `save' or trap
+ occurring during it. */
+#define MASK_BROKEN_SAVERESTORE 0x200000
+#define TARGET_BROKEN_SAVERESTORE (target_flags & MASK_BROKEN_SAVERESTORE)
+
+/* Non-zero means -m{,no-}fpu was passed on the command line. */
+#define MASK_FPU_SET 0x400000
+#define TARGET_FPU_SET (target_flags & MASK_FPU_SET)
+
+/* Use the UltraSPARC Visual Instruction Set extensions. */
+#define MASK_VIS 0x1000000
+#define TARGET_VIS (target_flags & MASK_VIS)
+
+/* Compile for Solaris V8+. 32 bit Solaris preserves the high bits of
+ the current out and global registers. Linux saves the high bits on
+ context switches but not signals. */
+#define MASK_V8PLUS 0x2000000
+#define TARGET_V8PLUS (target_flags & MASK_V8PLUS)
+
+/* TARGET_HARD_MUL: Use hardware multiply instructions but not %y.
+ TARGET_HARD_MUL32: Use hardware multiply instructions with rd %y
+ to get high 32 bits. False in V8+ or V9 because multiply stores
+ a 64 bit result in a register. */
+
+#define TARGET_HARD_MUL32 \
+ ((TARGET_V8 || TARGET_SPARCLITE \
+ || TARGET_SPARCLET || TARGET_DEPRECATED_V8_INSNS) \
+ && ! TARGET_V8PLUS)
+
+#define TARGET_HARD_MUL \
+ (TARGET_V8 || TARGET_SPARCLITE || TARGET_SPARCLET \
+ || TARGET_DEPRECATED_V8_INSNS || TARGET_V8PLUS)
+
+
+/* Macro to define tables used to set the flags.
+ This is a list in braces of pairs in braces,
+ each pair being { "NAME", VALUE }
+ where VALUE is the bits to set or minus the bits to clear.
+ An empty string NAME is used to identify the default VALUE. */
+
+#define TARGET_SWITCHES \
+ { {"fpu", MASK_FPU | MASK_FPU_SET}, \
+ {"no-fpu", -MASK_FPU}, \
+ {"no-fpu", MASK_FPU_SET}, \
+ {"hard-float", MASK_FPU | MASK_FPU_SET}, \
+ {"soft-float", -MASK_FPU}, \
+ {"soft-float", MASK_FPU_SET}, \
+ {"epilogue", MASK_EPILOGUE}, \
+ {"no-epilogue", -MASK_EPILOGUE}, \
+ {"unaligned-doubles", MASK_UNALIGNED_DOUBLES}, \
+ {"no-unaligned-doubles", -MASK_UNALIGNED_DOUBLES}, \
+ {"impure-text", MASK_IMPURE_TEXT}, \
+ {"no-impure-text", -MASK_IMPURE_TEXT}, \
+ {"flat", MASK_FLAT}, \
+ {"no-flat", -MASK_FLAT}, \
+ {"app-regs", MASK_APP_REGS}, \
+ {"no-app-regs", -MASK_APP_REGS}, \
+ {"hard-quad-float", MASK_HARD_QUAD}, \
+ {"soft-quad-float", -MASK_HARD_QUAD}, \
+ {"v8plus", MASK_V8PLUS}, \
+ {"no-v8plus", -MASK_V8PLUS}, \
+ {"vis", MASK_VIS}, \
+ /* ??? These are deprecated, coerced to -mcpu=. Delete in 2.9. */ \
+ {"cypress", 0}, \
+ {"sparclite", 0}, \
+ {"f930", 0}, \
+ {"f934", 0}, \
+ {"v8", 0}, \
+ {"supersparc", 0}, \
+ /* End of deprecated options. */ \
+ /* -mptrNN exists for *experimental* purposes. */ \
+/* {"ptr64", MASK_PTR64}, */ \
+/* {"ptr32", -MASK_PTR64}, */ \
+ {"32", -MASK_64BIT}, \
+ {"64", MASK_64BIT}, \
+ {"stack-bias", MASK_STACK_BIAS}, \
+ {"no-stack-bias", -MASK_STACK_BIAS}, \
+ SUBTARGET_SWITCHES \
+ { "", TARGET_DEFAULT}}
+
+/* MASK_APP_REGS must always be the default because that's what
+ FIXED_REGISTERS is set to and -ffixed- is processed before
+ CONDITIONAL_REGISTER_USAGE is called (where we process -mno-app-regs). */
+#define TARGET_DEFAULT (MASK_APP_REGS + MASK_EPILOGUE + MASK_FPU)
+
+/* This is meant to be redefined in target specific files. */
+#define SUBTARGET_SWITCHES
+
+/* Processor type.
+ These must match the values for the cpu attribute in sparc.md. */
+enum processor_type {
+ PROCESSOR_V7,
+ PROCESSOR_CYPRESS,
+ PROCESSOR_V8,
+ PROCESSOR_SUPERSPARC,
+ PROCESSOR_SPARCLITE,
+ PROCESSOR_F930,
+ PROCESSOR_F934,
+ PROCESSOR_SPARCLET,
+ PROCESSOR_TSC701,
+ PROCESSOR_V9,
+ PROCESSOR_ULTRASPARC
+};
+
+/* This is set from -m{cpu,tune}=xxx. */
+extern enum processor_type sparc_cpu;
+
+/* Recast the cpu class to be the cpu attribute.
+ Every file includes us, but not every file includes insn-attr.h. */
+#define sparc_cpu_attr ((enum attr_cpu) sparc_cpu)
+
+/* This macro is similar to `TARGET_SWITCHES' but defines names of
+ command options that have values. Its definition is an
+ initializer with a subgrouping for each command option.
+
+ Each subgrouping contains a string constant, that defines the
+ fixed part of the option name, and the address of a variable.
+ The variable, type `char *', is set to the variable part of the
+ given option if the fixed part matches. The actual option name
+ is made by appending `-m' to the specified name.
+
+ Here is an example which defines `-mshort-data-NUMBER'. If the
+ given option is `-mshort-data-512', the variable `m88k_short_data'
+ will be set to the string `"512"'.
+
+ extern char *m88k_short_data;
+ #define TARGET_OPTIONS { { "short-data-", &m88k_short_data } } */
+
+#define TARGET_OPTIONS \
+{ \
+ { "cpu=", &sparc_select[1].string }, \
+ { "tune=", &sparc_select[2].string }, \
+ { "cmodel=", &sparc_cmodel_string }, \
+ { "align-loops=", &sparc_align_loops_string }, \
+ { "align-jumps=", &sparc_align_jumps_string }, \
+ { "align-functions=", &sparc_align_funcs_string }, \
+ SUBTARGET_OPTIONS \
+}
+
+/* This is meant to be redefined in target specific files. */
+#define SUBTARGET_OPTIONS
+
+/* sparc_select[0] is reserved for the default cpu. */
+struct sparc_cpu_select
+{
+ char *string;
+ char *name;
+ int set_tune_p;
+ int set_arch_p;
+};
+
+extern struct sparc_cpu_select sparc_select[];
+
+/* Variables to record values the user passes. */
+extern char *sparc_align_loops_string;
+extern char *sparc_align_jumps_string;
+extern char *sparc_align_funcs_string;
+/* Parsed values as a power of two. */
+extern int sparc_align_loops;
+extern int sparc_align_jumps;
+extern int sparc_align_funcs;
+
+#define DEFAULT_SPARC_ALIGN_FUNCS \
+(sparc_cpu == PROCESSOR_ULTRASPARC ? 5 : 2)
+
+/* target machine storage layout */
+
+/* Define for cross-compilation to a sparc target with no TFmode from a host
+ with a different float format (e.g. VAX). */
+#define REAL_ARITHMETIC
+
+/* Define this if most significant bit is lowest numbered
+ in instructions that operate on numbered bit-fields. */
+#define BITS_BIG_ENDIAN 1
+
+/* Define this if most significant byte of a word is the lowest numbered. */
+#define BYTES_BIG_ENDIAN 1
+
+/* Define this if most significant word of a multiword number is the lowest
+ numbered. */
+#define WORDS_BIG_ENDIAN 1
+
+/* Define this to set the endianness to use in libgcc2.c, which can
+ not depend on target_flags. */
+#if defined (__LITTLE_ENDIAN__)
+#define LIBGCC2_WORDS_BIG_ENDIAN 0
+#else
+#define LIBGCC2_WORDS_BIG_ENDIAN 1
+#endif
+
+/* number of bits in an addressable storage unit */
+#define BITS_PER_UNIT 8
+
+/* Width in bits of a "word", which is the contents of a machine register.
+ Note that this is not necessarily the width of data type `int';
+ if using 16-bit ints on a 68000, this would still be 32.
+ But on a machine with 16-bit registers, this would be 16. */
+#define BITS_PER_WORD (TARGET_ARCH64 ? 64 : 32)
+#define MAX_BITS_PER_WORD 64
+
+/* Width of a word, in units (bytes). */
+#define UNITS_PER_WORD (TARGET_ARCH64 ? 8 : 4)
+#define MIN_UNITS_PER_WORD 4
+
+/* Now define the sizes of the C data types. */
+
+#define SHORT_TYPE_SIZE 16
+#define INT_TYPE_SIZE 32
+#define LONG_TYPE_SIZE (TARGET_ARCH64 ? 64 : 32)
+#define LONG_LONG_TYPE_SIZE 64
+#define FLOAT_TYPE_SIZE 32
+#define DOUBLE_TYPE_SIZE 64
+
+#if defined (SPARC_BI_ARCH)
+#define MAX_LONG_TYPE_SIZE 64
+#endif
+
+#if 0
+/* ??? This does not work in SunOS 4.x, so it is not enabled here.
+ Instead, it is enabled in sol2.h, because it does work under Solaris. */
+/* Define for support of TFmode long double and REAL_ARITHMETIC.
+ Sparc ABI says that long double is 4 words. */
+#define LONG_DOUBLE_TYPE_SIZE 128
+#endif
+
+/* Width in bits of a pointer.
+ See also the macro `Pmode' defined below. */
+#define POINTER_SIZE (TARGET_PTR64 ? 64 : 32)
+
+/* A macro to update MODE and UNSIGNEDP when an object whose type
+ is TYPE and which has the specified mode and signedness is to be
+ stored in a register. This macro is only called when TYPE is a
+ scalar type. */
+#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
+if (TARGET_ARCH64 \
+ && GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \
+{ \
+ (MODE) = DImode; \
+}
+
+/* Define this macro if the promotion described by PROMOTE_MODE
+ should also be done for outgoing function arguments. */
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_MODE is a no-op
+ for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime test
+ for this value. */
+#define PROMOTE_FUNCTION_ARGS
+
+/* Define this macro if the promotion described by PROMOTE_MODE
+ should also be done for the return value of functions.
+ If this macro is defined, FUNCTION_VALUE must perform the same
+ promotions done by PROMOTE_MODE. */
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_MODE is a no-op
+ for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime test
+ for this value. */
+#define PROMOTE_FUNCTION_RETURN
+
+/* Allocation boundary (in *bits*) for storing arguments in argument list. */
+#define PARM_BOUNDARY (TARGET_ARCH64 ? 64 : 32)
+
+/* Boundary (in *bits*) on which stack pointer should be aligned. */
+#define STACK_BOUNDARY (TARGET_ARCH64 ? 128 : 64)
+
+/* ALIGN FRAMES on double word boundaries */
+
+#define SPARC_STACK_ALIGN(LOC) \
+ (TARGET_ARCH64 ? (((LOC)+15) & ~15) : (((LOC)+7) & ~7))
+
+/* Allocation boundary (in *bits*) for the code of a function. */
+#define FUNCTION_BOUNDARY (1 << (sparc_align_funcs + 3))
+
+/* Alignment of field after `int : 0' in a structure. */
+#define EMPTY_FIELD_BOUNDARY (TARGET_ARCH64 ? 64 : 32)
+
+/* Every structure's size must be a multiple of this. */
+#define STRUCTURE_SIZE_BOUNDARY 8
+
+/* A bitfield declared as `int' forces `int' alignment for the struct. */
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/* No data type wants to be aligned rounder than this. */
+#define BIGGEST_ALIGNMENT (TARGET_ARCH64 ? 128 : 64)
+
+/* The best alignment to use in cases where we have a choice. */
+#define FASTEST_ALIGNMENT 64
+
+/* Make strings word-aligned so strcpy from constants will be faster. */
+#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
+ ((TREE_CODE (EXP) == STRING_CST \
+ && (ALIGN) < FASTEST_ALIGNMENT) \
+ ? FASTEST_ALIGNMENT : (ALIGN))
+
+/* Make arrays of chars word-aligned for the same reasons. */
+#define DATA_ALIGNMENT(TYPE, ALIGN) \
+ (TREE_CODE (TYPE) == ARRAY_TYPE \
+ && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
+ && (ALIGN) < FASTEST_ALIGNMENT ? FASTEST_ALIGNMENT : (ALIGN))
+
+/* Set this nonzero if move instructions will actually fail to work
+ when given unaligned data. */
+#define STRICT_ALIGNMENT 1
+
+/* Things that must be doubleword aligned cannot go in the text section,
+ because the linker fails to align the text section enough!
+ Put them in the data section. This macro is only used in this file. */
+#define MAX_TEXT_ALIGN 32
+
+/* This forces all variables and constants to the data section when PIC.
+ This is because the SunOS 4 shared library scheme thinks everything in
+ text is a function, and patches the address to point to a loader stub. */
+/* This is defined to zero for every system which doesn't use the a.out object
+ file format. */
+#ifndef SUNOS4_SHARED_LIBRARIES
+#define SUNOS4_SHARED_LIBRARIES 0
+#endif
+
+/* This is defined differently for v9 in a cover file. */
+#define SELECT_SECTION(T,RELOC) \
+{ \
+ if (TREE_CODE (T) == VAR_DECL) \
+ { \
+ if (TREE_READONLY (T) && ! TREE_SIDE_EFFECTS (T) \
+ && DECL_INITIAL (T) \
+ && (DECL_INITIAL (T) == error_mark_node \
+ || TREE_CONSTANT (DECL_INITIAL (T))) \
+ && DECL_ALIGN (T) <= MAX_TEXT_ALIGN \
+ && ! (flag_pic && ((RELOC) || SUNOS4_SHARED_LIBRARIES))) \
+ text_section (); \
+ else \
+ data_section (); \
+ } \
+ else if (TREE_CODE (T) == CONSTRUCTOR) \
+ { \
+ if (flag_pic && ((RELOC) || SUNOS4_SHARED_LIBRARIES)) \
+ data_section (); \
+ } \
+ else if (TREE_CODE_CLASS (TREE_CODE (T)) == 'c') \
+ { \
+ if ((TREE_CODE (T) == STRING_CST && flag_writable_strings) \
+ || TYPE_ALIGN (TREE_TYPE (T)) > MAX_TEXT_ALIGN \
+ || (flag_pic && ((RELOC) || SUNOS4_SHARED_LIBRARIES))) \
+ data_section (); \
+ else \
+ text_section (); \
+ } \
+}
+
+/* Use text section for a constant
+ unless we need more alignment than that offers. */
+/* This is defined differently for v9 in a cover file. */
+#define SELECT_RTX_SECTION(MODE, X) \
+{ \
+ if (GET_MODE_BITSIZE (MODE) <= MAX_TEXT_ALIGN \
+ && ! (flag_pic && (symbolic_operand (X) || SUNOS4_SHARED_LIBRARIES))) \
+ text_section (); \
+ else \
+ data_section (); \
+}
+
+/* Standard register usage. */
+
+/* Number of actual hardware registers.
+ The hardware registers are assigned numbers for the compiler
+ from 0 to just below FIRST_PSEUDO_REGISTER.
+ All registers that the compiler knows about must be given numbers,
+ even those that are not normally considered general registers.
+
+ SPARC has 32 integer registers and 32 floating point registers.
+ 64 bit SPARC has 32 additional fp regs, but the odd numbered ones are not
+ accessible. We still account for them to simplify register computations
+ (eg: in CLASS_MAX_NREGS). There are also 4 fp condition code registers, so
+ 32+32+32+4 == 100.
+ Register 100 is used as the integer condition code register. */
+
+#define FIRST_PSEUDO_REGISTER 101
+
+#define SPARC_FIRST_FP_REG 32
+/* Additional V9 fp regs. */
+#define SPARC_FIRST_V9_FP_REG 64
+#define SPARC_LAST_V9_FP_REG 95
+/* V9 %fcc[0123]. V8 uses (figuratively) %fcc0. */
+#define SPARC_FIRST_V9_FCC_REG 96
+#define SPARC_LAST_V9_FCC_REG 99
+/* V8 fcc reg. */
+#define SPARC_FCC_REG 96
+/* Integer CC reg. We don't distinguish %icc from %xcc. */
+#define SPARC_ICC_REG 100
+
+/* Nonzero if REGNO is an fp reg. */
+#define SPARC_FP_REG_P(REGNO) \
+((REGNO) >= SPARC_FIRST_FP_REG && (REGNO) <= SPARC_LAST_V9_FP_REG)
+
+/* Argument passing regs. */
+#define SPARC_OUTGOING_INT_ARG_FIRST 8
+#define SPARC_INCOMING_INT_ARG_FIRST (TARGET_FLAT ? 8 : 24)
+#define SPARC_FP_ARG_FIRST 32
+
+/* 1 for registers that have pervasive standard uses
+ and are not available for the register allocator.
+
+ On non-v9 systems:
+ g1 is free to use as temporary.
+ g2-g4 are reserved for applications. Gcc normally uses them as
+ temporaries, but this can be disabled via the -mno-app-regs option.
+ g5 through g7 are reserved for the operating system.
+
+ On v9 systems:
+ g1,g5 are free to use as temporaries, and are free to use between calls
+ if the call is to an external function via the PLT.
+ g4 is free to use as a temporary in the non-embedded case.
+ g4 is reserved in the embedded case.
+ g2-g3 are reserved for applications. Gcc normally uses them as
+ temporaries, but this can be disabled via the -mno-app-regs option.
+ g6-g7 are reserved for the operating system (or application in
+ embedded case).
+ ??? Register 1 is used as a temporary by the 64 bit sethi pattern, so must
+ currently be a fixed register until this pattern is rewritten.
+ Register 1 is also used when restoring call-preserved registers in large
+ stack frames.
+
+ Registers fixed in arch32 and not arch64 (or vice-versa) are marked in
+ CONDITIONAL_REGISTER_USAGE in order to properly handle -ffixed-.
+*/
+
+#define FIXED_REGISTERS \
+ {1, 0, 0, 0, 0, 0, 1, 1, \
+ 0, 0, 0, 0, 0, 0, 1, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 1, 1, \
+ \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ \
+ 0, 0, 0, 0, 0}
+
+/* 1 for registers not available across function calls.
+ These must include the FIXED_REGISTERS and also any
+ registers that can be used without being saved.
+ The latter must include the registers where values are returned
+ and the register where structure-value addresses are passed.
+ Aside from that, you can include as many other registers as you like. */
+
+#define CALL_USED_REGISTERS \
+ {1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 0, 0, 0, 0, 0, 0, 1, 1, \
+ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ \
+ 1, 1, 1, 1, 1}
+
+/* If !TARGET_FPU, then make the fp registers and fp cc regs fixed so that
+ they won't be allocated. */
+
+#define CONDITIONAL_REGISTER_USAGE \
+do \
+ { \
+ if (TARGET_ARCH32) \
+ { \
+ fixed_regs[5] = 1; \
+ } \
+ else \
+ { \
+ fixed_regs[1] = 1; \
+ } \
+ if (! TARGET_V9) \
+ { \
+ int regno; \
+ for (regno = SPARC_FIRST_V9_FP_REG; \
+ regno <= SPARC_LAST_V9_FP_REG; \
+ regno++) \
+ fixed_regs[regno] = 1; \
+ /* %fcc0 is used by v8 and v9. */ \
+ for (regno = SPARC_FIRST_V9_FCC_REG + 1; \
+ regno <= SPARC_LAST_V9_FCC_REG; \
+ regno++) \
+ fixed_regs[regno] = 1; \
+ } \
+ if (! TARGET_FPU) \
+ { \
+ int regno; \
+ for (regno = 32; regno < SPARC_LAST_V9_FCC_REG; regno++) \
+ fixed_regs[regno] = 1; \
+ } \
+ /* Don't unfix g2-g4 if they were fixed with -ffixed-. */ \
+ fixed_regs[2] |= ! TARGET_APP_REGS; \
+ fixed_regs[3] |= ! TARGET_APP_REGS; \
+ fixed_regs[4] |= ! TARGET_APP_REGS || TARGET_CM_EMBMEDANY; \
+ if (TARGET_FLAT) \
+ { \
+ /* Let the compiler believe the frame pointer is still \
+ %fp, but output it as %i7. */ \
+ fixed_regs[31] = 1; \
+ reg_names[FRAME_POINTER_REGNUM] = "%i7"; \
+ /* ??? This is a hack to disable leaf functions. */ \
+ global_regs[7] = 1; \
+ } \
+ if (profile_block_flag) \
+ { \
+ /* %g1 and %g2 must be fixed, because BLOCK_PROFILER \
+ uses them. */ \
+ fixed_regs[1] = 1; \
+ fixed_regs[2] = 1; \
+ } \
+ if (flag_pic != 0) \
+ { \
+ fixed_regs[23] = 1; \
+ call_used_regs[23] = 1; \
+ } \
+ } \
+while (0)
+
+/* Return number of consecutive hard regs needed starting at reg REGNO
+ to hold something of mode MODE.
+ This is ordinarily the length in words of a value of mode MODE
+ but can be less for certain modes in special long registers.
+
+ On SPARC, ordinary registers hold 32 bits worth;
+ this means both integer and floating point registers.
+ On v9, integer regs hold 64 bits worth; floating point regs hold
+ 32 bits worth (this includes the new fp regs as even the odd ones are
+ included in the hard register count). */
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ (TARGET_ARCH64 \
+ ? ((REGNO) < 32 \
+ ? (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD \
+ : (GET_MODE_SIZE (MODE) + 3) / 4) \
+ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+/* A subreg in 64 bit mode will have the wrong offset for a floating point
+ register. The least significant part is at offset 1, compared to 0 for
+ integer registers. */
+#define ALTER_HARD_SUBREG(TMODE, WORD, FMODE, REGNO) \
+ (TARGET_ARCH64 && (REGNO) >= 32 && (REGNO) < 96 && (TMODE) == SImode ? 1 : ((REGNO) + (WORD)))
+
+/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
+ See sparc.c for how we initialize this. */
+extern int *hard_regno_mode_classes;
+extern int sparc_mode_class[];
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ ((hard_regno_mode_classes[REGNO] & sparc_mode_class[MODE]) != 0)
+
+/* Value is 1 if it is a good idea to tie two pseudo registers
+ when one has mode MODE1 and one has mode MODE2.
+ If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
+ for any hard reg, then this must be 0 for correct output.
+
+ For V9: SFmode can't be combined with other float modes, because they can't
+ be allocated to the %d registers. Also, DFmode won't fit in odd %f
+ registers, but SFmode will. */
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ ((MODE1) == (MODE2) \
+ || (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2) \
+ && (! TARGET_V9 \
+ || (GET_MODE_CLASS (MODE1) != MODE_FLOAT \
+ || (MODE1 != SFmode && MODE2 != SFmode)))))
+
+/* Specify the registers used for certain standard purposes.
+ The values of these macros are register numbers. */
+
+/* SPARC pc isn't overloaded on a register that the compiler knows about. */
+/* #define PC_REGNUM */
+
+/* Register to use for pushing function arguments. */
+#define STACK_POINTER_REGNUM 14
+
+/* Actual top-of-stack address is 92/176 greater than the contents of the
+ stack pointer register for !v9/v9. That is:
+ - !v9: 64 bytes for the in and local registers, 4 bytes for structure return
+ address, and 6*4 bytes for the 6 register parameters.
+ - v9: 128 bytes for the in and local registers + 6*8 bytes for the integer
+ parameter regs. */
+#define STACK_POINTER_OFFSET FIRST_PARM_OFFSET(0)
+
+/* The stack bias (amount by which the hardware register is offset by). */
+#define SPARC_STACK_BIAS ((TARGET_ARCH64 && TARGET_STACK_BIAS) ? 2047 : 0)
+
+/* Is stack biased? */
+#define STACK_BIAS SPARC_STACK_BIAS
+
+/* Base register for access to local variables of the function. */
+#define FRAME_POINTER_REGNUM 30
+
+#if 0
+/* Register that is used for the return address for the flat model. */
+#define RETURN_ADDR_REGNUM 15
+#endif
+
+/* Value should be nonzero if functions must have frame pointers.
+ Zero means the frame pointer need not be set up (and parms
+ may be accessed via the stack pointer) in functions that seem suitable.
+ This is computed in `reload', in reload1.c.
+ Used in flow.c, global.c, and reload1.c.
+
+ Being a non-leaf function does not mean a frame pointer is needed in the
+ flat window model. However, the debugger won't be able to backtrace through
+ us with out it. */
+#define FRAME_POINTER_REQUIRED \
+ (TARGET_FLAT ? (current_function_calls_alloca || current_function_varargs \
+ || !leaf_function_p ()) \
+ : ! (leaf_function_p () && only_leaf_regs_used ()))
+
+/* C statement to store the difference between the frame pointer
+ and the stack pointer values immediately after the function prologue.
+
+ Note, we always pretend that this is a leaf function because if
+ it's not, there's no point in trying to eliminate the
+ frame pointer. If it is a leaf function, we guessed right! */
+#define INITIAL_FRAME_POINTER_OFFSET(VAR) \
+ ((VAR) = (TARGET_FLAT ? sparc_flat_compute_frame_size (get_frame_size ()) \
+ : compute_frame_size (get_frame_size (), 1)))
+
+/* Base register for access to arguments of the function. */
+#define ARG_POINTER_REGNUM FRAME_POINTER_REGNUM
+
+/* Register in which static-chain is passed to a function. This must
+ not be a register used by the prologue. */
+#define STATIC_CHAIN_REGNUM (TARGET_ARCH64 ? 5 : 2)
+
+/* Register which holds offset table for position-independent
+ data references. */
+
+#define PIC_OFFSET_TABLE_REGNUM 23
+
+#define INITIALIZE_PIC initialize_pic ()
+#define FINALIZE_PIC finalize_pic ()
+
+/* Pick a default value we can notice from override_options:
+ !v9: Default is on.
+ v9: Default is off. */
+
+#define DEFAULT_PCC_STRUCT_RETURN -1
+
+/* Sparc ABI says that quad-precision floats and all structures are returned
+ in memory.
+ For v9: unions <= 32 bytes in size are returned in int regs,
+ structures up to 32 bytes are returned in int and fp regs. */
+
+#define RETURN_IN_MEMORY(TYPE) \
+(TARGET_ARCH32 \
+ ? (TYPE_MODE (TYPE) == BLKmode \
+ || TYPE_MODE (TYPE) == TFmode \
+ || TYPE_MODE (TYPE) == TCmode) \
+ : (TYPE_MODE (TYPE) == BLKmode \
+ && int_size_in_bytes (TYPE) > 32))
+
+/* Functions which return large structures get the address
+ to place the wanted value at offset 64 from the frame.
+ Must reserve 64 bytes for the in and local registers.
+ v9: Functions which return large structures get the address to place the
+ wanted value from an invisible first argument. */
+/* Used only in other #defines in this file. */
+#define STRUCT_VALUE_OFFSET 64
+
+#define STRUCT_VALUE \
+ (TARGET_ARCH64 \
+ ? 0 \
+ : gen_rtx_MEM (Pmode, \
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx, \
+ GEN_INT (STRUCT_VALUE_OFFSET))))
+#define STRUCT_VALUE_INCOMING \
+ (TARGET_ARCH64 \
+ ? 0 \
+ : gen_rtx_MEM (Pmode, \
+ gen_rtx_PLUS (Pmode, frame_pointer_rtx, \
+ GEN_INT (STRUCT_VALUE_OFFSET))))
+
+/* Define the classes of registers for register constraints in the
+ machine description. Also define ranges of constants.
+
+ One of the classes must always be named ALL_REGS and include all hard regs.
+ If there is more than one class, another class must be named NO_REGS
+ and contain no registers.
+
+ The name GENERAL_REGS must be the name of a class (or an alias for
+ another name such as ALL_REGS). This is the class of registers
+ that is allowed by "g" or "r" in a register constraint.
+ Also, registers outside this class are allocated only when
+ instructions express preferences for them.
+
+ The classes must be numbered in nondecreasing order; that is,
+ a larger-numbered class must never be contained completely
+ in a smaller-numbered class.
+
+ For any two classes, it is very desirable that there be another
+ class that represents their union. */
+
+/* The SPARC has various kinds of registers: general, floating point,
+ and condition codes [well, it has others as well, but none that we
+ care directly about].
+
+ For v9 we must distinguish between the upper and lower floating point
+ registers because the upper ones can't hold SFmode values.
+ HARD_REGNO_MODE_OK won't help here because reload assumes that register(s)
+ satisfying a group need for a class will also satisfy a single need for
+ that class. EXTRA_FP_REGS is a bit of a misnomer as it covers all 64 fp
+ regs.
+
+ It is important that one class contains all the general and all the standard
+ fp regs. Otherwise find_reg() won't properly allocate int regs for moves,
+ because reg_class_record() will bias the selection in favor of fp regs,
+ because reg_class_subunion[GENERAL_REGS][FP_REGS] will yield FP_REGS,
+ because FP_REGS > GENERAL_REGS.
+
+ It is also important that one class contain all the general and all the
+ fp regs. Otherwise when spilling a DFmode reg, it may be from EXTRA_FP_REGS
+ but find_reloads() may use class GENERAL_OR_FP_REGS. This will cause
+ allocate_reload_reg() to bypass it causing an abort because the compiler
+ thinks it doesn't have a spill reg when in fact it does.
+
+ v9 also has 4 floating point condition code registers. Since we don't
+ have a class that is the union of FPCC_REGS with either of the others,
+ it is important that it appear first. Otherwise the compiler will die
+ trying to compile _fixunsdfsi because fix_truncdfsi2 won't match its
+ constraints.
+
+ It is important that SPARC_ICC_REG have class NO_REGS. Otherwise combine
+ may try to use it to hold an SImode value. See register_operand.
+ ??? Should %fcc[0123] be handled similarly?
+*/
+
+enum reg_class { NO_REGS, FPCC_REGS, I64_REGS, GENERAL_REGS, FP_REGS,
+ EXTRA_FP_REGS, GENERAL_OR_FP_REGS, GENERAL_OR_EXTRA_FP_REGS,
+ ALL_REGS, LIM_REG_CLASSES };
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+/* Give names of register classes as strings for dump file. */
+
+#define REG_CLASS_NAMES \
+ { "NO_REGS", "FPCC_REGS", "I64_REGS", "GENERAL_REGS", "FP_REGS", \
+ "EXTRA_FP_REGS", "GENERAL_OR_FP_REGS", "GENERAL_OR_EXTRA_FP_REGS", \
+ "ALL_REGS" }
+
+/* Define which registers fit in which classes.
+ This is an initializer for a vector of HARD_REG_SET
+ of length N_REG_CLASSES. */
+
+#define REG_CLASS_CONTENTS \
+ {{0, 0, 0, 0}, {0, 0, 0, 0xf}, {0xffff, 0, 0, 0}, \
+ {-1, 0, 0, 0}, {0, -1, 0, 0}, {0, -1, -1, 0}, \
+ {-1, -1, 0, 0}, {-1, -1, -1, 0}, {-1, -1, -1, 0x1f}}
+
+/* The same information, inverted:
+ Return the class number of the smallest class containing
+ reg number REGNO. This could be a conditional expression
+ or could index an array. */
+
+extern enum reg_class sparc_regno_reg_class[];
+
+#define REGNO_REG_CLASS(REGNO) sparc_regno_reg_class[(REGNO)]
+
+/* This is the order in which to allocate registers normally.
+
+ We put %f0/%f1 last among the float registers, so as to make it more
+ likely that a pseudo-register which dies in the float return register
+ will get allocated to the float return register, thus saving a move
+ instruction at the end of the function. */
+
+#define REG_ALLOC_ORDER \
+{ 8, 9, 10, 11, 12, 13, 2, 3, \
+ 15, 16, 17, 18, 19, 20, 21, 22, \
+ 23, 24, 25, 26, 27, 28, 29, 31, \
+ 34, 35, 36, 37, 38, 39, /* %f2-%f7 */ \
+ 40, 41, 42, 43, 44, 45, 46, 47, /* %f8-%f15 */ \
+ 48, 49, 50, 51, 52, 53, 54, 55, /* %f16-%f23 */ \
+ 56, 57, 58, 59, 60, 61, 62, 63, /* %f24-%f31 */ \
+ 64, 65, 66, 67, 68, 69, 70, 71, /* %f32-%f39 */ \
+ 72, 73, 74, 75, 76, 77, 78, 79, /* %f40-%f47 */ \
+ 80, 81, 82, 83, 84, 85, 86, 87, /* %f48-%f55 */ \
+ 88, 89, 90, 91, 92, 93, 94, 95, /* %f56-%f63 */ \
+ 32, 33, /* %f0,%f1 */ \
+ 96, 97, 98, 99, 100, /* %fcc0-3, %icc */ \
+ 1, 4, 5, 6, 7, 0, 14, 30}
+
+/* This is the order in which to allocate registers for
+ leaf functions. If all registers can fit in the "i" registers,
+ then we have the possibility of having a leaf function. */
+
+#define REG_LEAF_ALLOC_ORDER \
+{ 2, 3, 24, 25, 26, 27, 28, 29, \
+ 15, 8, 9, 10, 11, 12, 13, \
+ 16, 17, 18, 19, 20, 21, 22, 23, \
+ 34, 35, 36, 37, 38, 39, \
+ 40, 41, 42, 43, 44, 45, 46, 47, \
+ 48, 49, 50, 51, 52, 53, 54, 55, \
+ 56, 57, 58, 59, 60, 61, 62, 63, \
+ 64, 65, 66, 67, 68, 69, 70, 71, \
+ 72, 73, 74, 75, 76, 77, 78, 79, \
+ 80, 81, 82, 83, 84, 85, 86, 87, \
+ 88, 89, 90, 91, 92, 93, 94, 95, \
+ 32, 33, \
+ 96, 97, 98, 99, 100, \
+ 1, 4, 5, 6, 7, 0, 14, 30, 31}
+
+#define ORDER_REGS_FOR_LOCAL_ALLOC order_regs_for_local_alloc ()
+
+/* ??? %g7 is not a leaf register to effectively #undef LEAF_REGISTERS when
+ -mflat is used. Function only_leaf_regs_used will return 0 if a global
+ register is used and is not permitted in a leaf function. We make %g7
+ a global reg if -mflat and voila. Since %g7 is a system register and is
+ fixed it won't be used by gcc anyway. */
+
+#define LEAF_REGISTERS \
+{ 1, 1, 1, 1, 1, 1, 1, 0, \
+ 0, 0, 0, 0, 0, 0, 1, 0, \
+ 0, 0, 0, 0, 0, 0, 0, 0, \
+ 1, 1, 1, 1, 1, 1, 0, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 1, 1}
+
+extern char leaf_reg_remap[];
+#define LEAF_REG_REMAP(REGNO) (leaf_reg_remap[REGNO])
+
+/* The class value for index registers, and the one for base regs. */
+#define INDEX_REG_CLASS GENERAL_REGS
+#define BASE_REG_CLASS GENERAL_REGS
+
+/* Local macro to handle the two v9 classes of FP regs. */
+#define FP_REG_CLASS_P(CLASS) ((CLASS) == FP_REGS || (CLASS) == EXTRA_FP_REGS)
+
+/* Get reg_class from a letter such as appears in the machine description.
+ In the not-v9 case, coerce v9's 'e' class to 'f', so we can use 'e' in the
+ .md file for v8 and v9.
+ 'd' and 'b' are used for single and double precision VIS operations,
+ if TARGET_VIS.
+ 'h' is used for V8+ 64 bit global and out registers. */
+
+#define REG_CLASS_FROM_LETTER(C) \
+(TARGET_V9 \
+ ? ((C) == 'f' ? FP_REGS \
+ : (C) == 'e' ? EXTRA_FP_REGS \
+ : (C) == 'c' ? FPCC_REGS \
+ : ((C) == 'd' && TARGET_VIS) ? FP_REGS\
+ : ((C) == 'b' && TARGET_VIS) ? EXTRA_FP_REGS\
+ : ((C) == 'h' && TARGET_V8PLUS) ? I64_REGS\
+ : NO_REGS) \
+ : ((C) == 'f' ? FP_REGS \
+ : (C) == 'e' ? FP_REGS \
+ : (C) == 'c' ? FPCC_REGS \
+ : NO_REGS))
+
+/* The letters I, J, K, L and M in a register constraint string
+ can be used to stand for particular ranges of immediate operands.
+ This macro defines what the ranges are.
+ C is the letter, and VALUE is a constant value.
+ Return 1 if VALUE is in the range specified by C.
+
+ `I' is used for the range of constants an insn can actually contain.
+ `J' is used for the range which is just zero (since that is R0).
+ `K' is used for constants which can be loaded with a single sethi insn.
+ `L' is used for the range of constants supported by the movcc insns.
+ `M' is used for the range of constants supported by the movrcc insns. */
+
+#define SPARC_SIMM10_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x200 < 0x400)
+#define SPARC_SIMM11_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x400 < 0x800)
+#define SPARC_SIMM13_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x1000 < 0x2000)
+/* 10 and 11 bit immediates are only used for a few specific insns.
+ SMALL_INT is used throughout the port so we continue to use it. */
+#define SMALL_INT(X) (SPARC_SIMM13_P (INTVAL (X)))
+/* 13 bit immediate, considering only the low 32 bits */
+#define SMALL_INT32(X) (SPARC_SIMM13_P ((int)INTVAL (X) & 0xffffffff))
+#define SPARC_SETHI_P(X) \
+(((unsigned HOST_WIDE_INT) (X) & ~(unsigned HOST_WIDE_INT) 0xfffffc00) == 0)
+
+#define CONST_OK_FOR_LETTER_P(VALUE, C) \
+ ((C) == 'I' ? SPARC_SIMM13_P (VALUE) \
+ : (C) == 'J' ? (VALUE) == 0 \
+ : (C) == 'K' ? SPARC_SETHI_P (VALUE) \
+ : (C) == 'L' ? SPARC_SIMM11_P (VALUE) \
+ : (C) == 'M' ? SPARC_SIMM10_P (VALUE) \
+ : 0)
+
+/* Similar, but for floating constants, and defining letters G and H.
+ Here VALUE is the CONST_DOUBLE rtx itself. */
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
+ ((C) == 'G' ? fp_zero_operand (VALUE) \
+ : (C) == 'H' ? arith_double_operand (VALUE, DImode) \
+ : 0)
+
+/* Given an rtx X being reloaded into a reg required to be
+ in class CLASS, return the class of reg to actually use.
+ In general this is just CLASS; but on some machines
+ in some cases it is preferable to use a more restrictive class. */
+/* We can't load constants into FP registers. We can't load any FP constant
+ if an 'E' constraint fails to match it. */
+#define PREFERRED_RELOAD_CLASS(X,CLASS) \
+ (CONSTANT_P (X) \
+ && (FP_REG_CLASS_P (CLASS) \
+ || (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
+ && (HOST_FLOAT_FORMAT != IEEE_FLOAT_FORMAT \
+ || HOST_BITS_PER_INT != BITS_PER_WORD))) \
+ ? NO_REGS : (CLASS))
+
+/* Return the register class of a scratch register needed to load IN into
+ a register of class CLASS in MODE.
+
+ On the SPARC, when PIC, we need a temporary when loading some addresses
+ into a register.
+
+ Also, we need a temporary when loading/storing a HImode/QImode value
+ between memory and the FPU registers. This can happen when combine puts
+ a paradoxical subreg in a float/fix conversion insn. */
+
+#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, IN) \
+ ((FP_REG_CLASS_P (CLASS) && ((MODE) == HImode || (MODE) == QImode) \
+ && (GET_CODE (IN) == MEM \
+ || ((GET_CODE (IN) == REG || GET_CODE (IN) == SUBREG) \
+ && true_regnum (IN) == -1))) ? GENERAL_REGS : NO_REGS)
+
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, IN) \
+ ((FP_REG_CLASS_P (CLASS) && ((MODE) == HImode || (MODE) == QImode) \
+ && (GET_CODE (IN) == MEM \
+ || ((GET_CODE (IN) == REG || GET_CODE (IN) == SUBREG) \
+ && true_regnum (IN) == -1))) ? GENERAL_REGS : NO_REGS)
+
+/* On SPARC it is not possible to directly move data between
+ GENERAL_REGS and FP_REGS. */
+#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \
+ (FP_REG_CLASS_P (CLASS1) != FP_REG_CLASS_P (CLASS2))
+
+/* Return the stack location to use for secondary memory needed reloads.
+ We want to use the reserved location just below the frame pointer.
+ However, we must ensure that there is a frame, so use assign_stack_local
+ if the frame size is zero. */
+#define SECONDARY_MEMORY_NEEDED_RTX(MODE) \
+ (get_frame_size () == 0 \
+ ? assign_stack_local (MODE, GET_MODE_SIZE (MODE), 0) \
+ : gen_rtx_MEM (MODE, gen_rtx_PLUS (Pmode, frame_pointer_rtx, \
+ GEN_INT (STARTING_FRAME_OFFSET))))
+
+/* Get_secondary_mem widens its argument to BITS_PER_WORD which loses on v9
+ because the movsi and movsf patterns don't handle r/f moves.
+ For v8 we copy the default definition. */
+#define SECONDARY_MEMORY_NEEDED_MODE(MODE) \
+ (TARGET_ARCH64 \
+ ? (GET_MODE_BITSIZE (MODE) < 32 \
+ ? mode_for_size (32, GET_MODE_CLASS (MODE), 0) \
+ : MODE) \
+ : (GET_MODE_BITSIZE (MODE) < BITS_PER_WORD \
+ ? mode_for_size (BITS_PER_WORD, GET_MODE_CLASS (MODE), 0) \
+ : MODE))
+
+/* Return the maximum number of consecutive registers
+ needed to represent mode MODE in a register of class CLASS. */
+/* On SPARC, this is the size of MODE in words. */
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ (FP_REG_CLASS_P (CLASS) ? (GET_MODE_SIZE (MODE) + 3) / 4 \
+ : (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* Stack layout; function entry, exit and calling. */
+
+/* Define the number of register that can hold parameters.
+ This macro is only used in other macro definitions below and in sparc.c.
+ MODE is the mode of the argument.
+ !v9: All args are passed in %o0-%o5.
+ v9: %o0-%o5 and %f0-%f31 are cumulatively used to pass values.
+ See the description in sparc.c. */
+#define NPARM_REGS(MODE) \
+(TARGET_ARCH64 \
+ ? (GET_MODE_CLASS (MODE) == MODE_FLOAT ? 32 : 6) \
+ : 6)
+
+/* Define this if pushing a word on the stack
+ makes the stack pointer a smaller address. */
+#define STACK_GROWS_DOWNWARD
+
+/* Define this if the nominal address of the stack frame
+ is at the high-address end of the local variables;
+ that is, each additional local variable allocated
+ goes at a more negative offset in the frame. */
+#define FRAME_GROWS_DOWNWARD
+
+/* Offset within stack frame to start allocating local variables at.
+ If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
+ first local allocated. Otherwise, it is the offset to the BEGINNING
+ of the first local allocated. */
+/* This allows space for one TFmode floating point value. */
+#define STARTING_FRAME_OFFSET \
+ (TARGET_ARCH64 ? (SPARC_STACK_BIAS - 16) \
+ : (-SPARC_STACK_ALIGN (LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT)))
+
+/* If we generate an insn to push BYTES bytes,
+ this says how many the stack pointer really advances by.
+ On SPARC, don't define this because there are no push insns. */
+/* #define PUSH_ROUNDING(BYTES) */
+
+/* Offset of first parameter from the argument pointer register value.
+ !v9: This is 64 for the ins and locals, plus 4 for the struct-return reg
+ even if this function isn't going to use it.
+ v9: This is 128 for the ins and locals. */
+#define FIRST_PARM_OFFSET(FNDECL) \
+ (TARGET_ARCH64 ? (SPARC_STACK_BIAS + 16 * UNITS_PER_WORD) \
+ : (STRUCT_VALUE_OFFSET + UNITS_PER_WORD))
+
+/* When a parameter is passed in a register, stack space is still
+ allocated for it.
+ !v9: All 6 possible integer registers have backing store allocated.
+ v9: Only space for the arguments passed is allocated. */
+/* ??? Ideally, we'd use zero here (as the minimum), but zero has special
+ meaning to the backend. Further, we need to be able to detect if a
+ varargs/unprototyped function is called, as they may want to spill more
+ registers than we've provided space. Ugly, ugly. So for now we retain
+ all 6 slots even for v9. */
+#define REG_PARM_STACK_SPACE(DECL) (6 * UNITS_PER_WORD)
+
+/* Keep the stack pointer constant throughout the function.
+ This is both an optimization and a necessity: longjmp
+ doesn't behave itself when the stack pointer moves within
+ the function! */
+#define ACCUMULATE_OUTGOING_ARGS
+
+/* Value is the number of bytes of arguments automatically
+ popped when returning from a subroutine call.
+ FUNDECL is the declaration node of the function (as a tree),
+ FUNTYPE is the data type of the function (as a tree),
+ or for a library call it is an identifier node for the subroutine name.
+ SIZE is the number of bytes of arguments passed on the stack. */
+
+#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0
+
+/* Some subroutine macros specific to this machine.
+ When !TARGET_FPU, put float return values in the general registers,
+ since we don't have any fp registers. */
+#define BASE_RETURN_VALUE_REG(MODE) \
+ (TARGET_ARCH64 \
+ ? (TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 : 8) \
+ : (((MODE) == SFmode || (MODE) == DFmode) && TARGET_FPU ? 32 : 8))
+
+#define BASE_OUTGOING_VALUE_REG(MODE) \
+ (TARGET_ARCH64 \
+ ? (TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 \
+ : TARGET_FLAT ? 8 : 24) \
+ : (((MODE) == SFmode || (MODE) == DFmode) && TARGET_FPU ? 32 \
+ : (TARGET_FLAT ? 8 : 24)))
+
+#define BASE_PASSING_ARG_REG(MODE) \
+ (TARGET_ARCH64 \
+ ? (TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 : 8) \
+ : 8)
+
+/* ??? FIXME -- seems wrong for v9 structure passing... */
+#define BASE_INCOMING_ARG_REG(MODE) \
+ (TARGET_ARCH64 \
+ ? (TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 \
+ : TARGET_FLAT ? 8 : 24) \
+ : (TARGET_FLAT ? 8 : 24))
+
+/* Define this macro if the target machine has "register windows". This
+ C expression returns the register number as seen by the called function
+ corresponding to register number OUT as seen by the calling function.
+ Return OUT if register number OUT is not an outbound register. */
+
+#define INCOMING_REGNO(OUT) \
+ ((TARGET_FLAT || (OUT) < 8 || (OUT) > 15) ? (OUT) : (OUT) + 16)
+
+/* Define this macro if the target machine has "register windows". This
+ C expression returns the register number as seen by the calling function
+ corresponding to register number IN as seen by the called function.
+ Return IN if register number IN is not an inbound register. */
+
+#define OUTGOING_REGNO(IN) \
+ ((TARGET_FLAT || (IN) < 24 || (IN) > 31) ? (IN) : (IN) - 16)
+
+/* Define how to find the value returned by a function.
+ VALTYPE is the data type of the value (as a tree).
+ If the precise function being called is known, FUNC is its FUNCTION_DECL;
+ otherwise, FUNC is 0. */
+
+/* On SPARC the value is found in the first "output" register. */
+
+extern struct rtx_def *function_value ();
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+ function_value ((VALTYPE), TYPE_MODE (VALTYPE), 1)
+
+/* But the called function leaves it in the first "input" register. */
+
+#define FUNCTION_OUTGOING_VALUE(VALTYPE, FUNC) \
+ function_value ((VALTYPE), TYPE_MODE (VALTYPE), 0)
+
+/* Define how to find the value returned by a library function
+ assuming the value has mode MODE. */
+
+#define LIBCALL_VALUE(MODE) \
+ function_value (NULL_TREE, (MODE), 1)
+
+/* 1 if N is a possible register number for a function value
+ as seen by the caller.
+ On SPARC, the first "output" reg is used for integer values,
+ and the first floating point register is used for floating point values. */
+
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == 8 || (N) == 32)
+
+/* Define the size of space to allocate for the return value of an
+ untyped_call. */
+
+#define APPLY_RESULT_SIZE 16
+
+/* 1 if N is a possible register number for function argument passing.
+ On SPARC, these are the "output" registers. v9 also uses %f0-%f31. */
+
+#define FUNCTION_ARG_REGNO_P(N) \
+(TARGET_ARCH64 \
+ ? (((N) >= 8 && (N) <= 13) || ((N) >= 32 && (N) <= 63)) \
+ : ((N) >= 8 && (N) <= 13))
+
+/* Define a data type for recording info about an argument list
+ during the scan of that argument list. This data type should
+ hold all necessary information about the function itself
+ and about the args processed so far, enough to enable macros
+ such as FUNCTION_ARG to determine where the next arg should go.
+
+ On SPARC (!v9), this is a single integer, which is a number of words
+ of arguments scanned so far (including the invisible argument,
+ if any, which holds the structure-value-address).
+ Thus 7 or more means all following args should go on the stack.
+
+ For v9, we also need to know whether a prototype is present. */
+
+struct sparc_args {
+ int words; /* number of words passed so far */
+ int prototype_p; /* non-zero if a prototype is present */
+ int libcall_p; /* non-zero if a library call */
+};
+#define CUMULATIVE_ARGS struct sparc_args
+
+/* Initialize a variable CUM of type CUMULATIVE_ARGS
+ for a call to a function whose data type is FNTYPE.
+ For a library call, FNTYPE is 0. */
+
+extern void init_cumulative_args ();
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \
+init_cumulative_args (& (CUM), (FNTYPE), (LIBNAME), (INDIRECT));
+
+/* Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ TYPE is null for libcalls where that information may not be available. */
+
+extern void function_arg_advance ();
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+function_arg_advance (& (CUM), (MODE), (TYPE), (NAMED))
+
+/* Determine where to put an argument to a function.
+ Value is zero to push the argument on the stack,
+ or a hard register in which to store the argument.
+
+ MODE is the argument's machine mode.
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis). */
+
+extern struct rtx_def *function_arg ();
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+function_arg (& (CUM), (MODE), (TYPE), (NAMED), 0)
+
+/* Define where a function finds its arguments.
+ This is different from FUNCTION_ARG because of register windows. */
+
+#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
+function_arg (& (CUM), (MODE), (TYPE), (NAMED), 1)
+
+/* For an arg passed partly in registers and partly in memory,
+ this is the number of registers used.
+ For args passed entirely in registers or entirely in memory, zero. */
+
+extern int function_arg_partial_nregs ();
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
+function_arg_partial_nregs (& (CUM), (MODE), (TYPE), (NAMED))
+
+/* A C expression that indicates when an argument must be passed by reference.
+ If nonzero for an argument, a copy of that argument is made in memory and a
+ pointer to the argument is passed instead of the argument itself.
+ The pointer is passed in whatever way is appropriate for passing a pointer
+ to that type. */
+
+extern int function_arg_pass_by_reference ();
+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
+function_arg_pass_by_reference (& (CUM), (MODE), (TYPE), (NAMED))
+
+/* If defined, a C expression which determines whether, and in which direction,
+ to pad out an argument with extra space. The value should be of type
+ `enum direction': either `upward' to pad above the argument,
+ `downward' to pad below, or `none' to inhibit padding. */
+
+#define FUNCTION_ARG_PADDING(MODE, TYPE) \
+function_arg_padding ((MODE), (TYPE))
+
+/* If defined, a C expression that gives the alignment boundary, in bits,
+ of an argument with the specified mode and type. If it is not defined,
+ PARM_BOUNDARY is used for all arguments.
+ For sparc64, objects requiring 16 byte alignment are passed that way. */
+
+#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \
+((TARGET_ARCH64 \
+ && (GET_MODE_ALIGNMENT (MODE) == 128 \
+ || ((TYPE) && TYPE_ALIGN (TYPE) == 128))) \
+ ? 128 : PARM_BOUNDARY)
+
+/* Define the information needed to generate branch and scc insns. This is
+ stored from the compare operation. Note that we can't use "rtx" here
+ since it hasn't been defined! */
+
+extern struct rtx_def *sparc_compare_op0, *sparc_compare_op1;
+
+/* Define the function that build the compare insn for scc and bcc. */
+
+extern struct rtx_def *gen_compare_reg ();
+
+/* This function handles all v9 scc insns */
+
+extern int gen_v9_scc ();
+
+/* Generate the special assembly code needed to tell the assembler whatever
+ it might need to know about the return value of a function.
+
+ For Sparc assemblers, we need to output a .proc pseudo-op which conveys
+ information to the assembler relating to peephole optimization (done in
+ the assembler). */
+
+#define ASM_DECLARE_RESULT(FILE, RESULT) \
+ fprintf ((FILE), "\t.proc\t0%lo\n", sparc_type_code (TREE_TYPE (RESULT)))
+
+/* Output the label for a function definition. */
+
+#define ASM_DECLARE_FUNCTION_NAME(FILE, NAME, DECL) \
+do { \
+ ASM_DECLARE_RESULT (FILE, DECL_RESULT (DECL)); \
+ ASM_OUTPUT_LABEL (FILE, NAME); \
+} while (0)
+
+/* This macro generates the assembly code for function entry.
+ FILE is a stdio stream to output the code to.
+ SIZE is an int: how many units of temporary storage to allocate.
+ Refer to the array `regs_ever_live' to determine which registers
+ to save; `regs_ever_live[I]' is nonzero if register number I
+ is ever used in the function. This macro is responsible for
+ knowing which registers should not be saved even if used. */
+
+/* On SPARC, move-double insns between fpu and cpu need an 8-byte block
+ of memory. If any fpu reg is used in the function, we allocate
+ such a block here, at the bottom of the frame, just in case it's needed.
+
+ If this function is a leaf procedure, then we may choose not
+ to do a "save" insn. The decision about whether or not
+ to do this is made in regclass.c. */
+
+extern int leaf_function;
+#define FUNCTION_PROLOGUE(FILE, SIZE) \
+ (TARGET_FLAT ? sparc_flat_output_function_prologue (FILE, (int)SIZE) \
+ : output_function_prologue (FILE, (int)SIZE, leaf_function))
+
+/* Output assembler code to FILE to increment profiler label # LABELNO
+ for profiling a function entry.
+
+ 32 bit sparc uses %g2 as the STATIC_CHAIN_REGNUM which gets clobbered
+ during profiling so we need to save/restore it around the call to mcount.
+ We're guaranteed that a save has just been done, and we use the space
+ allocated for intreg/fpreg value passing. */
+
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ do { \
+ char buf[20]; \
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LP", (LABELNO)); \
+ if (! TARGET_ARCH64) \
+ fputs ("\tst %g2,[%fp-4]\n", FILE); \
+ fputs ("\tsethi %hi(", FILE); \
+ assemble_name (FILE, buf); \
+ fputs ("),%o0\n", FILE); \
+ fputs ("\tcall mcount\n\tadd %o0,%lo(", FILE); \
+ assemble_name (FILE, buf); \
+ fputs ("),%o0\n", FILE); \
+ if (! TARGET_ARCH64) \
+ fputs ("\tld [%fp-4],%g2\n", FILE); \
+ } while (0)
+
+/* There are three profiling modes for basic blocks available.
+ The modes are selected at compile time by using the options
+ -a or -ax of the gnu compiler.
+ The variable `profile_block_flag' will be set according to the
+ selected option.
+
+ profile_block_flag == 0, no option used:
+
+ No profiling done.
+
+ profile_block_flag == 1, -a option used.
+
+ Count frequency of execution of every basic block.
+
+ profile_block_flag == 2, -ax option used.
+
+ Generate code to allow several different profiling modes at run time.
+ Available modes are:
+ Produce a trace of all basic blocks.
+ Count frequency of jump instructions executed.
+ In every mode it is possible to start profiling upon entering
+ certain functions and to disable profiling of some other functions.
+
+ The result of basic-block profiling will be written to a file `bb.out'.
+ If the -ax option is used parameters for the profiling will be read
+ from file `bb.in'.
+
+*/
+
+/* The following macro shall output assembler code to FILE
+ to initialize basic-block profiling.
+
+ If profile_block_flag == 2
+
+ Output code to call the subroutine `__bb_init_trace_func'
+ and pass two parameters to it. The first parameter is
+ the address of a block allocated in the object module.
+ The second parameter is the number of the first basic block
+ of the function.
+
+ The name of the block is a local symbol made with this statement:
+
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result.
+
+ The number of the first basic block of the function is
+ passed to the macro in BLOCK_OR_LABEL.
+
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ parameter1 <- LPBX0
+ parameter2 <- BLOCK_OR_LABEL
+ call __bb_init_trace_func
+
+ else if profile_block_flag != 0
+
+ Output code to call the subroutine `__bb_init_func'
+ and pass one single parameter to it, which is the same
+ as the first parameter to `__bb_init_trace_func'.
+
+ The first word of this parameter is a flag which will be nonzero if
+ the object module has already been initialized. So test this word
+ first, and do not call `__bb_init_func' if the flag is nonzero.
+ Note: When profile_block_flag == 2 the test need not be done
+ but `__bb_init_trace_func' *must* be called.
+
+ BLOCK_OR_LABEL may be used to generate a label number as a
+ branch destination in case `__bb_init_func' will not be called.
+
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ cmp (LPBX0),0
+ jne local_label
+ parameter1 <- LPBX0
+ call __bb_init_func
+local_label:
+
+*/
+
+#define FUNCTION_BLOCK_PROFILER(FILE, BLOCK_OR_LABEL) \
+do \
+ { \
+ int bol = (BLOCK_OR_LABEL); \
+ switch (profile_block_flag) \
+ { \
+ case 2: \
+ fprintf (FILE, "\tsethi %%hi(LPBX0),%%o0\n\tor %%o0,%%lo(LPBX0),%%o0\n\tsethi %%hi(%d),%%o1\n\tcall ___bb_init_trace_func\n\tor %%o1,%%lo(%d),%%o1\n",\
+ bol, bol); \
+ break; \
+ default: \
+ fprintf (FILE, "\tsethi %%hi(LPBX0),%%o0\n\tld [%%lo(LPBX0)+%%o0],%%o1\n\ttst %%o1\n\tbne LPY%d\n\tadd %%o0,%%lo(LPBX0),%%o0\n\tcall ___bb_init_func\n\tnop\nLPY%d:\n",\
+ bol, bol); \
+ break; \
+ } \
+ } \
+while (0)
+
+/* The following macro shall output assembler code to FILE
+ to increment a counter associated with basic block number BLOCKNO.
+
+ If profile_block_flag == 2
+
+ Output code to initialize the global structure `__bb' and
+ call the function `__bb_trace_func' which will increment the
+ counter.
+
+ `__bb' consists of two words. In the first word the number
+ of the basic block has to be stored. In the second word
+ the address of a block allocated in the object module
+ has to be stored.
+
+ The basic block number is given by BLOCKNO.
+
+ The address of the block is given by the label created with
+
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 0);
+
+ by FUNCTION_BLOCK_PROFILER.
+
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result.
+
+ If described in a virtual assembler language the code to be
+ output looks like:
+
+ move BLOCKNO -> (__bb)
+ move LPBX0 -> (__bb+4)
+ call __bb_trace_func
+
+ Note that function `__bb_trace_func' must not change the
+ machine state, especially the flag register. To grant
+ this, you must output code to save and restore registers
+ either in this macro or in the macros MACHINE_STATE_SAVE
+ and MACHINE_STATE_RESTORE. The last two macros will be
+ used in the function `__bb_trace_func', so you must make
+ sure that the function prologue does not change any
+ register prior to saving it with MACHINE_STATE_SAVE.
+
+ else if profile_block_flag != 0
+
+ Output code to increment the counter directly.
+ Basic blocks are numbered separately from zero within each
+ compiled object module. The count associated with block number
+ BLOCKNO is at index BLOCKNO in an array of words; the name of
+ this array is a local symbol made with this statement:
+
+ ASM_GENERATE_INTERNAL_LABEL (BUFFER, "LPBX", 2);
+
+ Of course, since you are writing the definition of
+ `ASM_GENERATE_INTERNAL_LABEL' as well as that of this macro, you
+ can take a short cut in the definition of this macro and use the
+ name that you know will result.
+
+ If described in a virtual assembler language, the code to be
+ output looks like:
+
+ inc (LPBX2+4*BLOCKNO)
+
+*/
+
+#define BLOCK_PROFILER(FILE, BLOCKNO) \
+do \
+ { \
+ int blockn = (BLOCKNO); \
+ switch (profile_block_flag) \
+ { \
+ case 2: \
+ fprintf (FILE, "\tsethi %%hi(___bb),%%g1\n\tsethi %%hi(%d),%%g2\n\tor %%g2,%%lo(%d),%%g2\n\tst %%g2,[%%lo(___bb)+%%g1]\n\tsethi %%hi(LPBX0),%%g2\n\tor %%g2,%%lo(LPBX0),%%g2\n\tadd 4,%%g1,%%g1\n\tst %%g2,[%%lo(___bb)+%%g1]\n\tmov %%o7,%%g2\n\tcall ___bb_trace_func\n\tnop\n\tmov %%g2,%%o7\n",\
+ blockn, blockn); \
+ break; \
+ default: \
+ fprintf (FILE, "\tsethi %%hi(LPBX2+%d),%%g1\n\tld [%%lo(LPBX2+%d)+%%g1],%%g2\n\
+\tadd %%g2,1,%%g2\n\tst %%g2,[%%lo(LPBX2+%d)+%%g1]\n", \
+ 4 * blockn, 4 * blockn, 4 * blockn); \
+ break; \
+ } \
+ } \
+while(0)
+
+/* The following macro shall output assembler code to FILE
+ to indicate a return from function during basic-block profiling.
+
+ If profiling_block_flag == 2:
+
+ Output assembler code to call function `__bb_trace_ret'.
+
+ Note that function `__bb_trace_ret' must not change the
+ machine state, especially the flag register. To grant
+ this, you must output code to save and restore registers
+ either in this macro or in the macros MACHINE_STATE_SAVE_RET
+ and MACHINE_STATE_RESTORE_RET. The last two macros will be
+ used in the function `__bb_trace_ret', so you must make
+ sure that the function prologue does not change any
+ register prior to saving it with MACHINE_STATE_SAVE_RET.
+
+ else if profiling_block_flag != 0:
+
+ The macro will not be used, so it need not distinguish
+ these cases.
+*/
+
+#define FUNCTION_BLOCK_PROFILER_EXIT(FILE) \
+ fprintf (FILE, "\tcall ___bb_trace_ret\n\tnop\n" );
+
+/* The function `__bb_trace_func' is called in every basic block
+ and is not allowed to change the machine state. Saving (restoring)
+ the state can either be done in the BLOCK_PROFILER macro,
+ before calling function (rsp. after returning from function)
+ `__bb_trace_func', or it can be done inside the function by
+ defining the macros:
+
+ MACHINE_STATE_SAVE(ID)
+ MACHINE_STATE_RESTORE(ID)
+
+ In the latter case care must be taken, that the prologue code
+ of function `__bb_trace_func' does not already change the
+ state prior to saving it with MACHINE_STATE_SAVE.
+
+ The parameter `ID' is a string identifying a unique macro use.
+
+ On sparc it is sufficient to save the psw register to memory.
+ Unfortunately the psw register can be read in supervisor mode only,
+ so we read only the condition codes by using branch instructions
+ and hope that this is enough. */
+
+#define MACHINE_STATE_SAVE(ID) \
+ int ms_flags, ms_saveret; \
+ asm volatile( \
+ "mov %%g0,%0\n\
+ be,a LFLGNZ"ID"\n\
+ or %0,4,%0\n\
+LFLGNZ"ID":\n\
+ bcs,a LFLGNC"ID"\n\
+ or %0,1,%0\n\
+LFLGNC"ID":\n\
+ bvs,a LFLGNV"ID"\n\
+ or %0,2,%0\n\
+LFLGNV"ID":\n\
+ bneg,a LFLGNN"ID"\n\
+ or %0,8,%0\n\
+LFLGNN"ID":\n\
+ mov %%g2,%1" \
+ : "=r"(ms_flags), "=r"(ms_saveret));
+
+/* On sparc MACHINE_STATE_RESTORE restores the psw register from memory.
+ The psw register can be written in supervisor mode only,
+ which is true even for simple condition codes.
+ We use some combination of instructions to produce the
+ proper condition codes, but some flag combinations can not
+ be generated in this way. If this happens an unimplemented
+ instruction will be executed to abort the program. */
+
+#define MACHINE_STATE_RESTORE(ID) \
+{ extern char flgtab[] __asm__("LFLGTAB"ID); \
+ int scratch; \
+ asm volatile ( \
+ "jmpl %2+%1,%%g0\n\
+ ! Do part of VC in the delay slot here, as it needs 3 insns.\n\
+ addcc 2,%3,%%g0\n\
+LFLGTAB" ID ":\n\
+ ! 0\n\
+ ba LFLGRET"ID"\n\
+ orcc 1,%%g0,%%g0\n\
+ ! C\n\
+ ba LFLGRET"ID"\n\
+ addcc 2,%3,%%g0\n\
+ ! V\n\
+ unimp\n\
+ nop\n\
+ ! VC\n\
+ ba LFLGRET"ID"\n\
+ addxcc %4,%4,%0\n\
+ ! Z\n\
+ ba LFLGRET"ID"\n\
+ subcc %%g0,%%g0,%%g0\n\
+ ! ZC\n\
+ ba LFLGRET"ID"\n\
+ addcc 1,%3,%0\n\
+ ! ZVC\n\
+ ba LFLGRET"ID"\n\
+ addcc %4,%4,%0\n\
+ ! N\n\
+ ba LFLGRET"ID"\n\
+ orcc %%g0,-1,%%g0\n\
+ ! NC\n\
+ ba LFLGRET"ID"\n\
+ addcc %%g0,%3,%%g0\n\
+ ! NV\n\
+ unimp\n\
+ nop\n\
+ ! NVC\n\
+ unimp\n\
+ nop\n\
+ ! NZ\n\
+ unimp\n\
+ nop\n\
+ ! NZC\n\
+ unimp\n\
+ nop\n\
+ ! NZV\n\
+ unimp\n\
+ nop\n\
+ ! NZVC\n\
+ unimp\n\
+ nop\n\
+LFLGRET"ID":\n\
+ mov %5,%%g2" \
+ : "=r"(scratch) \
+ : "r"(ms_flags*8), "r"(flgtab), "r"(-1), \
+ "r"(0x80000000), "r"(ms_saveret) \
+ : "cc", "%g2"); }
+
+/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function,
+ the stack pointer does not matter. The value is tested only in
+ functions that have frame pointers.
+ No definition is equivalent to always zero. */
+
+extern int current_function_calls_alloca;
+extern int current_function_outgoing_args_size;
+
+#define EXIT_IGNORE_STACK \
+ (get_frame_size () != 0 \
+ || current_function_calls_alloca || current_function_outgoing_args_size)
+
+/* This macro generates the assembly code for function exit,
+ on machines that need it. If FUNCTION_EPILOGUE is not defined
+ then individual return instructions are generated for each
+ return statement. Args are same as for FUNCTION_PROLOGUE.
+
+ The function epilogue should not depend on the current stack pointer!
+ It should use the frame pointer only. This is mandatory because
+ of alloca; we also take advantage of it to omit stack adjustments
+ before returning. */
+
+/* This declaration is needed due to traditional/ANSI
+ incompatibilities which cannot be #ifdefed away
+ because they occur inside of macros. Sigh. */
+extern union tree_node *current_function_decl;
+
+#define FUNCTION_EPILOGUE(FILE, SIZE) \
+ (TARGET_FLAT ? sparc_flat_output_function_epilogue (FILE, (int)SIZE) \
+ : output_function_epilogue (FILE, (int)SIZE, leaf_function))
+
+#define DELAY_SLOTS_FOR_EPILOGUE \
+ (TARGET_FLAT ? sparc_flat_epilogue_delay_slots () : 1)
+#define ELIGIBLE_FOR_EPILOGUE_DELAY(trial, slots_filled) \
+ (TARGET_FLAT ? sparc_flat_eligible_for_epilogue_delay (trial, slots_filled) \
+ : eligible_for_epilogue_delay (trial, slots_filled))
+
+/* Define registers used by the epilogue and return instruction. */
+#define EPILOGUE_USES(REGNO) \
+ (!TARGET_FLAT && REGNO == 31)
+
+/* Length in units of the trampoline for entering a nested function. */
+
+#define TRAMPOLINE_SIZE (TARGET_ARCH64 ? 32 : 16)
+
+#define TRAMPOLINE_ALIGNMENT 128 /* 16 bytes */
+
+/* Emit RTL insns to initialize the variable parts of a trampoline.
+ FNADDR is an RTX for the address of the function's pure code.
+ CXT is an RTX for the static chain value for the function. */
+
+void sparc_initialize_trampoline ();
+void sparc64_initialize_trampoline ();
+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
+ if (TARGET_ARCH64) \
+ sparc64_initialize_trampoline (TRAMP, FNADDR, CXT); \
+ else \
+ sparc_initialize_trampoline (TRAMP, FNADDR, CXT)
+
+/* Generate necessary RTL for __builtin_saveregs().
+ ARGLIST is the argument list; see expr.c. */
+
+extern struct rtx_def *sparc_builtin_saveregs ();
+#define EXPAND_BUILTIN_SAVEREGS(ARGLIST) sparc_builtin_saveregs (ARGLIST)
+
+/* Define this macro if the location where a function argument is passed
+ depends on whether or not it is a named argument.
+
+ This macro controls how the NAMED argument to FUNCTION_ARG
+ is set for varargs and stdarg functions. With this macro defined,
+ the NAMED argument is always true for named arguments, and false for
+ unnamed arguments. If this is not defined, but SETUP_INCOMING_VARARGS
+ is defined, then all arguments are treated as named. Otherwise, all named
+ arguments except the last are treated as named.
+ For the v9 we want NAMED to mean what it says it means. */
+
+#define STRICT_ARGUMENT_NAMING TARGET_V9
+
+/* Generate RTL to flush the register windows so as to make arbitrary frames
+ available. */
+#define SETUP_FRAME_ADDRESSES() \
+ emit_insn (gen_flush_register_windows ())
+
+/* Given an rtx for the address of a frame,
+ return an rtx for the address of the word in the frame
+ that holds the dynamic chain--the previous frame's address.
+ ??? -mflat support? */
+#define DYNAMIC_CHAIN_ADDRESS(frame) \
+ gen_rtx_PLUS (Pmode, frame, GEN_INT (14 * UNITS_PER_WORD))
+
+/* The return address isn't on the stack, it is in a register, so we can't
+ access it from the current frame pointer. We can access it from the
+ previous frame pointer though by reading a value from the register window
+ save area. */
+#define RETURN_ADDR_IN_PREVIOUS_FRAME
+
+/* This is the offset of the return address to the true next instruction to be
+ executed for the current function. */
+#define RETURN_ADDR_OFFSET \
+ (8 + 4 * (! TARGET_ARCH64 && current_function_returns_struct))
+
+/* The current return address is in %i7. The return address of anything
+ farther back is in the register window save area at [%fp+60]. */
+/* ??? This ignores the fact that the actual return address is +8 for normal
+ returns, and +12 for structure returns. */
+#define RETURN_ADDR_RTX(count, frame) \
+ ((count == -1) \
+ ? gen_rtx_REG (Pmode, 31) \
+ : gen_rtx_MEM (Pmode, \
+ memory_address (Pmode, plus_constant (frame, 15 * UNITS_PER_WORD))))
+
+/* Before the prologue, the return address is %o7 + 8. OK, sometimes it's
+ +12, but always using +8 is close enough for frame unwind purposes.
+ Actually, just using %o7 is close enough for unwinding, but %o7+8
+ is something you can return to. */
+#define INCOMING_RETURN_ADDR_RTX \
+ gen_rtx_PLUS (word_mode, gen_rtx_REG (word_mode, 15), GEN_INT (8))
+
+/* The offset from the incoming value of %sp to the top of the stack frame
+ for the current function. On sparc64, we have to account for the stack
+ bias if present. */
+#define INCOMING_FRAME_SP_OFFSET SPARC_STACK_BIAS
+
+#define DOESNT_NEED_UNWINDER (! TARGET_FLAT)
+
+/* Addressing modes, and classification of registers for them. */
+
+/* #define HAVE_POST_INCREMENT */
+/* #define HAVE_POST_DECREMENT */
+
+/* #define HAVE_PRE_DECREMENT */
+/* #define HAVE_PRE_INCREMENT */
+
+/* Macros to check register numbers against specific register classes. */
+
+/* These assume that REGNO is a hard or pseudo reg number.
+ They give nonzero only if REGNO is a hard reg of the suitable class
+ or a pseudo reg currently allocated to a suitable hard reg.
+ Since they use reg_renumber, they are safe only once reg_renumber
+ has been allocated, which happens in local-alloc.c. */
+
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < (unsigned)32)
+#define REGNO_OK_FOR_BASE_P(REGNO) \
+((REGNO) < 32 || (unsigned) reg_renumber[REGNO] < (unsigned)32)
+#define REGNO_OK_FOR_FP_P(REGNO) \
+ (((unsigned) (REGNO) - 32 < (TARGET_V9 ? (unsigned)64 : (unsigned)32)) \
+ || ((unsigned) reg_renumber[REGNO] - 32 < (TARGET_V9 ? (unsigned)64 : (unsigned)32)))
+#define REGNO_OK_FOR_CCFP_P(REGNO) \
+ (TARGET_V9 \
+ && (((unsigned) (REGNO) - 96 < (unsigned)4) \
+ || ((unsigned) reg_renumber[REGNO] - 96 < (unsigned)4)))
+
+/* Now macros that check whether X is a register and also,
+ strictly, whether it is in a specified class.
+
+ These macros are specific to the SPARC, and may be used only
+ in code for printing assembler insns and in conditions for
+ define_optimization. */
+
+/* 1 if X is an fp register. */
+
+#define FP_REG_P(X) (REG_P (X) && REGNO_OK_FOR_FP_P (REGNO (X)))
+
+/* Is X, a REG, an in or global register? i.e. is regno 0..7 or 24..31 */
+#define IN_OR_GLOBAL_P(X) (REGNO (X) < 8 || (REGNO (X) >= 24 && REGNO (X) <= 31))
+
+/* Maximum number of registers that can appear in a valid memory address. */
+
+#define MAX_REGS_PER_ADDRESS 2
+
+/* Recognize any constant value that is a valid address.
+ When PIC, we do not accept an address that would require a scratch reg
+ to load into a register. */
+
+#define CONSTANT_ADDRESS_P(X) \
+ (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
+ || GET_CODE (X) == CONST_INT || GET_CODE (X) == HIGH \
+ || (GET_CODE (X) == CONST \
+ && ! (flag_pic && pic_address_needs_scratch (X))))
+
+/* Define this, so that when PIC, reload won't try to reload invalid
+ addresses which require two reload registers. */
+
+#define LEGITIMATE_PIC_OPERAND_P(X) (! pic_address_needs_scratch (X))
+
+/* Nonzero if the constant value X is a legitimate general operand.
+ Anything can be made to work except floating point constants. */
+
+#define LEGITIMATE_CONSTANT_P(X) \
+ (GET_CODE (X) != CONST_DOUBLE || GET_MODE (X) == VOIDmode)
+
+/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
+ and check its validity for a certain class.
+ We have two alternate definitions for each of them.
+ The usual definition accepts all pseudo regs; the other rejects
+ them unless they have been allocated suitable hard regs.
+ The symbol REG_OK_STRICT causes the latter definition to be used.
+
+ Most source files want to accept pseudo regs in the hope that
+ they will get allocated to the class that the insn wants them to be in.
+ Source files for reload pass need to be strict.
+ After reload, it makes no difference, since pseudo regs have
+ been eliminated by then. */
+
+/* Optional extra constraints for this machine. Borrowed from romp.h.
+
+ For the SPARC, `Q' means that this is a memory operand but not a
+ symbolic memory operand. Note that an unassigned pseudo register
+ is such a memory operand. Needed because reload will generate
+ these things in insns and then not re-recognize the insns, causing
+ constrain_operands to fail.
+
+ `S' handles constraints for calls. ??? So where is it? */
+
+#ifndef REG_OK_STRICT
+
+/* Nonzero if X is a hard reg that can be used as an index
+ or if it is a pseudo reg. */
+#define REG_OK_FOR_INDEX_P(X) \
+ (((unsigned) REGNO (X)) - 32 >= (FIRST_PSEUDO_REGISTER - 32))
+/* Nonzero if X is a hard reg that can be used as a base reg
+ or if it is a pseudo reg. */
+#define REG_OK_FOR_BASE_P(X) \
+ (((unsigned) REGNO (X)) - 32 >= (FIRST_PSEUDO_REGISTER - 32))
+
+/* 'T', 'U' are for aligned memory loads which aren't needed for v9. */
+
+#define EXTRA_CONSTRAINT(OP, C) \
+ ((C) == 'Q' \
+ ? ((GET_CODE (OP) == MEM \
+ && memory_address_p (GET_MODE (OP), XEXP (OP, 0)) \
+ && ! symbolic_memory_operand (OP, VOIDmode)) \
+ || (reload_in_progress && GET_CODE (OP) == REG \
+ && REGNO (OP) >= FIRST_PSEUDO_REGISTER)) \
+ : (! TARGET_ARCH64 && (C) == 'T') \
+ ? (mem_aligned_8 (OP)) \
+ : (! TARGET_ARCH64 && (C) == 'U') \
+ ? (register_ok_for_ldd (OP)) \
+ : 0)
+
+#else
+
+/* Nonzero if X is a hard reg that can be used as an index. */
+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
+/* Nonzero if X is a hard reg that can be used as a base reg. */
+#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
+
+#define EXTRA_CONSTRAINT(OP, C) \
+ ((C) == 'Q' \
+ ? (GET_CODE (OP) == REG \
+ ? (REGNO (OP) >= FIRST_PSEUDO_REGISTER \
+ && reg_renumber[REGNO (OP)] < 0) \
+ : GET_CODE (OP) == MEM) \
+ : (! TARGET_ARCH64 && (C) == 'T') \
+ ? mem_aligned_8 (OP) && strict_memory_address_p (Pmode, XEXP (OP, 0)) \
+ : (! TARGET_ARCH64 && (C) == 'U') \
+ ? (GET_CODE (OP) == REG \
+ && (REGNO (OP) < FIRST_PSEUDO_REGISTER \
+ || reg_renumber[REGNO (OP)] >= 0) \
+ && register_ok_for_ldd (OP)) \
+ : 0)
+#endif
+
+/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
+ that is a valid memory address for an instruction.
+ The MODE argument is the machine mode for the MEM expression
+ that wants to use this address.
+
+ On SPARC, the actual legitimate addresses must be REG+REG or REG+SMALLINT
+ ordinarily. This changes a bit when generating PIC.
+
+ If you change this, execute "rm explow.o recog.o reload.o". */
+
+#define RTX_OK_FOR_BASE_P(X) \
+ ((GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \
+ || (GET_CODE (X) == SUBREG \
+ && GET_CODE (SUBREG_REG (X)) == REG \
+ && REG_OK_FOR_BASE_P (SUBREG_REG (X))))
+
+#define RTX_OK_FOR_INDEX_P(X) \
+ ((GET_CODE (X) == REG && REG_OK_FOR_INDEX_P (X)) \
+ || (GET_CODE (X) == SUBREG \
+ && GET_CODE (SUBREG_REG (X)) == REG \
+ && REG_OK_FOR_INDEX_P (SUBREG_REG (X))))
+
+#define RTX_OK_FOR_OFFSET_P(X) \
+ (GET_CODE (X) == CONST_INT && INTVAL (X) >= -0x1000 && INTVAL (X) < 0x1000)
+
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+{ if (RTX_OK_FOR_BASE_P (X)) \
+ goto ADDR; \
+ else if (GET_CODE (X) == PLUS) \
+ { \
+ register rtx op0 = XEXP (X, 0); \
+ register rtx op1 = XEXP (X, 1); \
+ if (flag_pic && op0 == pic_offset_table_rtx) \
+ { \
+ if (RTX_OK_FOR_BASE_P (op1)) \
+ goto ADDR; \
+ else if (flag_pic == 1 \
+ && GET_CODE (op1) != REG \
+ && GET_CODE (op1) != LO_SUM \
+ && GET_CODE (op1) != MEM \
+ && (GET_CODE (op1) != CONST_INT \
+ || SMALL_INT (op1))) \
+ goto ADDR; \
+ } \
+ else if (RTX_OK_FOR_BASE_P (op0)) \
+ { \
+ if (RTX_OK_FOR_INDEX_P (op1) \
+ || RTX_OK_FOR_OFFSET_P (op1)) \
+ goto ADDR; \
+ } \
+ else if (RTX_OK_FOR_BASE_P (op1)) \
+ { \
+ if (RTX_OK_FOR_INDEX_P (op0) \
+ || RTX_OK_FOR_OFFSET_P (op0)) \
+ goto ADDR; \
+ } \
+ } \
+ else if (GET_CODE (X) == LO_SUM) \
+ { \
+ register rtx op0 = XEXP (X, 0); \
+ register rtx op1 = XEXP (X, 1); \
+ if (RTX_OK_FOR_BASE_P (op0) \
+ && CONSTANT_P (op1) \
+ /* We can't allow TFmode, because an offset \
+ greater than or equal to the alignment (8) \
+ may cause the LO_SUM to overflow. */ \
+ && MODE != TFmode) \
+ goto ADDR; \
+ } \
+ else if (GET_CODE (X) == CONST_INT && SMALL_INT (X)) \
+ goto ADDR; \
+}
+
+/* Try machine-dependent ways of modifying an illegitimate address
+ to be legitimate. If we find one, return the new, valid address.
+ This macro is used in only one place: `memory_address' in explow.c.
+
+ OLDX is the address as it was before break_out_memory_refs was called.
+ In some cases it is useful to look at this to decide what needs to be done.
+
+ MODE and WIN are passed so that this macro can use
+ GO_IF_LEGITIMATE_ADDRESS.
+
+ It is always safe for this macro to do nothing. It exists to recognize
+ opportunities to optimize the output. */
+
+/* On SPARC, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */
+extern struct rtx_def *legitimize_pic_address ();
+#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
+{ rtx sparc_x = (X); \
+ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == MULT) \
+ (X) = gen_rtx_PLUS (Pmode, XEXP (X, 1), \
+ force_operand (XEXP (X, 0), NULL_RTX)); \
+ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == MULT) \
+ (X) = gen_rtx_PLUS (Pmode, XEXP (X, 0), \
+ force_operand (XEXP (X, 1), NULL_RTX)); \
+ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 0)) == PLUS) \
+ (X) = gen_rtx_PLUS (Pmode, force_operand (XEXP (X, 0), NULL_RTX),\
+ XEXP (X, 1)); \
+ if (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == PLUS) \
+ (X) = gen_rtx_PLUS (Pmode, XEXP (X, 0), \
+ force_operand (XEXP (X, 1), NULL_RTX)); \
+ if (sparc_x != (X) && memory_address_p (MODE, X)) \
+ goto WIN; \
+ if (flag_pic) (X) = legitimize_pic_address (X, MODE, 0); \
+ else if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 1))) \
+ (X) = gen_rtx_PLUS (Pmode, XEXP (X, 0), \
+ copy_to_mode_reg (Pmode, XEXP (X, 1))); \
+ else if (GET_CODE (X) == PLUS && CONSTANT_ADDRESS_P (XEXP (X, 0))) \
+ (X) = gen_rtx_PLUS (Pmode, XEXP (X, 1), \
+ copy_to_mode_reg (Pmode, XEXP (X, 0))); \
+ else if (GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == CONST \
+ || GET_CODE (X) == LABEL_REF) \
+ (X) = gen_rtx_LO_SUM (Pmode, \
+ copy_to_mode_reg (Pmode, gen_rtx_HIGH (Pmode, X)), X); \
+ if (memory_address_p (MODE, X)) \
+ goto WIN; }
+
+/* Go to LABEL if ADDR (a legitimate address expression)
+ has an effect that depends on the machine mode it is used for.
+ On the SPARC this is never true. */
+
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL)
+
+/* If we are referencing a function make the SYMBOL_REF special.
+ In the Embedded Medium/Anywhere code model, %g4 points to the data segment
+ so we must not add it to function addresses. */
+
+#define ENCODE_SECTION_INFO(DECL) \
+ do { \
+ if (TARGET_CM_EMBMEDANY && TREE_CODE (DECL) == FUNCTION_DECL) \
+ SYMBOL_REF_FLAG (XEXP (DECL_RTL (DECL), 0)) = 1; \
+ } while (0)
+
+/* Specify the machine mode that this machine uses
+ for the index in the tablejump instruction. */
+#define CASE_VECTOR_MODE Pmode
+
+/* Define as C expression which evaluates to nonzero if the tablejump
+ instruction expects the table to contain offsets from the address of the
+ table.
+ Do not define this if the table should contain absolute addresses. */
+/* #define CASE_VECTOR_PC_RELATIVE 1 */
+
+/* Specify the tree operation to be used to convert reals to integers. */
+#define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR
+
+/* This is the kind of divide that is easiest to do in the general case. */
+#define EASY_DIV_EXPR TRUNC_DIV_EXPR
+
+/* Define this as 1 if `char' should by default be signed; else as 0. */
+#define DEFAULT_SIGNED_CHAR 1
+
+/* Max number of bytes we can move from memory to memory
+ in one reasonably fast instruction. */
+#define MOVE_MAX 8
+
+#if 0 /* Sun 4 has matherr, so this is no good. */
+/* This is the value of the error code EDOM for this machine,
+ used by the sqrt instruction. */
+#define TARGET_EDOM 33
+
+/* This is how to refer to the variable errno. */
+#define GEN_ERRNO_RTX \
+ gen_rtx_MEM (SImode, gen_rtx_SYMBOL_REF (Pmode, "errno"))
+#endif /* 0 */
+
+/* Define if operations between registers always perform the operation
+ on the full register even if a narrower mode is specified. */
+#define WORD_REGISTER_OPERATIONS
+
+/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD
+ will either zero-extend or sign-extend. The value of this macro should
+ be the code that says which one of the two operations is implicitly
+ done, NIL if none. */
+#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND
+
+/* Nonzero if access to memory by bytes is slow and undesirable.
+ For RISC chips, it means that access to memory by bytes is no
+ better than access by words when possible, so grab a whole word
+ and maybe make use of that. */
+#define SLOW_BYTE_ACCESS 1
+
+/* We assume that the store-condition-codes instructions store 0 for false
+ and some other value for true. This is the value stored for true. */
+
+#define STORE_FLAG_VALUE 1
+
+/* When a prototype says `char' or `short', really pass an `int'. */
+#define PROMOTE_PROTOTYPES
+
+/* Define this to be nonzero if shift instructions ignore all but the low-order
+ few bits. */
+#define SHIFT_COUNT_TRUNCATED 1
+
+/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits
+ is done just by pretending it is already truncated. */
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+/* Specify the machine mode that pointers have.
+ After generation of rtl, the compiler makes no further distinction
+ between pointers and any other objects of this machine mode. */
+#define Pmode (TARGET_PTR64 ? DImode : SImode)
+
+/* Generate calls to memcpy, memcmp and memset. */
+#define TARGET_MEM_FUNCTIONS
+
+/* Add any extra modes needed to represent the condition code.
+
+ On the Sparc, we have a "no-overflow" mode which is used when an add or
+ subtract insn is used to set the condition code. Different branches are
+ used in this case for some operations.
+
+ We also have two modes to indicate that the relevant condition code is
+ in the floating-point condition code register. One for comparisons which
+ will generate an exception if the result is unordered (CCFPEmode) and
+ one for comparisons which will never trap (CCFPmode).
+
+ CCXmode and CCX_NOOVmode are only used by v9. */
+
+#define EXTRA_CC_MODES CCXmode, CC_NOOVmode, CCX_NOOVmode, CCFPmode, CCFPEmode
+
+/* Define the names for the modes specified above. */
+
+#define EXTRA_CC_NAMES "CCX", "CC_NOOV", "CCX_NOOV", "CCFP", "CCFPE"
+
+/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
+ return the mode to be used for the comparison. For floating-point,
+ CCFP[E]mode is used. CC_NOOVmode should be used when the first operand is a
+ PLUS, MINUS, NEG, or ASHIFT. CCmode should be used when no special
+ processing is needed. */
+#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 || GET_CODE (X) == ASHIFT) \
+ ? (TARGET_ARCH64 && GET_MODE (X) == DImode ? CCX_NOOVmode : CC_NOOVmode) \
+ : ((TARGET_ARCH64 || TARGET_V8PLUS) && GET_MODE (X) == DImode ? CCXmode : CCmode)))
+
+/* Return non-zero if SELECT_CC_MODE will never return MODE for a
+ floating point inequality comparison. */
+
+#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode)
+
+/* A function address in a call instruction
+ is a byte address (for indexing purposes)
+ so give the MEM rtx a byte's mode. */
+#define FUNCTION_MODE SImode
+
+/* Define this if addresses of constant functions
+ shouldn't be put through pseudo regs where they can be cse'd.
+ Desirable on machines where ordinary constants are expensive
+ but a CALL with constant address is cheap. */
+#define NO_FUNCTION_CSE
+
+/* alloca should avoid clobbering the old register save area. */
+#define SETJMP_VIA_SAVE_AREA
+
+/* Define subroutines to call to handle multiply and divide.
+ Use the subroutines that Sun's library provides.
+ The `*' prevents an underscore from being prepended by the compiler. */
+
+#define DIVSI3_LIBCALL "*.div"
+#define UDIVSI3_LIBCALL "*.udiv"
+#define MODSI3_LIBCALL "*.rem"
+#define UMODSI3_LIBCALL "*.urem"
+/* .umul is a little faster than .mul. */
+#define MULSI3_LIBCALL "*.umul"
+
+/* Define library calls for quad FP operations. These are all part of the
+ SPARC ABI. */
+#define ADDTF3_LIBCALL "_Q_add"
+#define SUBTF3_LIBCALL "_Q_sub"
+#define NEGTF2_LIBCALL "_Q_neg"
+#define MULTF3_LIBCALL "_Q_mul"
+#define DIVTF3_LIBCALL "_Q_div"
+#define FLOATSITF2_LIBCALL "_Q_itoq"
+#define FIX_TRUNCTFSI2_LIBCALL "_Q_qtoi"
+#define FIXUNS_TRUNCTFSI2_LIBCALL "_Q_qtou"
+#define EXTENDSFTF2_LIBCALL "_Q_stoq"
+#define TRUNCTFSF2_LIBCALL "_Q_qtos"
+#define EXTENDDFTF2_LIBCALL "_Q_dtoq"
+#define TRUNCTFDF2_LIBCALL "_Q_qtod"
+#define EQTF2_LIBCALL "_Q_feq"
+#define NETF2_LIBCALL "_Q_fne"
+#define GTTF2_LIBCALL "_Q_fgt"
+#define GETF2_LIBCALL "_Q_fge"
+#define LTTF2_LIBCALL "_Q_flt"
+#define LETF2_LIBCALL "_Q_fle"
+
+/* We can define the TFmode sqrt optab only if TARGET_FPU. This is because
+ with soft-float, the SFmode and DFmode sqrt instructions will be absent,
+ and the compiler will notice and try to use the TFmode sqrt instruction
+ for calls to the builtin function sqrt, but this fails. */
+#define INIT_TARGET_OPTABS \
+ do { \
+ add_optab->handlers[(int) TFmode].libfunc \
+ = gen_rtx_SYMBOL_REF (Pmode, ADDTF3_LIBCALL); \
+ sub_optab->handlers[(int) TFmode].libfunc \
+ = gen_rtx_SYMBOL_REF (Pmode, SUBTF3_LIBCALL); \
+ neg_optab->handlers[(int) TFmode].libfunc \
+ = gen_rtx_SYMBOL_REF (Pmode, NEGTF2_LIBCALL); \
+ smul_optab->handlers[(int) TFmode].libfunc \
+ = gen_rtx_SYMBOL_REF (Pmode, MULTF3_LIBCALL); \
+ flodiv_optab->handlers[(int) TFmode].libfunc \
+ = gen_rtx_SYMBOL_REF (Pmode, DIVTF3_LIBCALL); \
+ eqtf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, EQTF2_LIBCALL); \
+ netf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, NETF2_LIBCALL); \
+ gttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, GTTF2_LIBCALL); \
+ getf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, GETF2_LIBCALL); \
+ lttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, LTTF2_LIBCALL); \
+ letf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, LETF2_LIBCALL); \
+ trunctfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, TRUNCTFSF2_LIBCALL); \
+ trunctfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, TRUNCTFDF2_LIBCALL); \
+ extendsftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, EXTENDSFTF2_LIBCALL); \
+ extenddftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, EXTENDDFTF2_LIBCALL); \
+ floatsitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, FLOATSITF2_LIBCALL); \
+ fixtfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, FIX_TRUNCTFSI2_LIBCALL); \
+ fixunstfsi_libfunc \
+ = gen_rtx_SYMBOL_REF (Pmode, FIXUNS_TRUNCTFSI2_LIBCALL); \
+ if (TARGET_FPU) \
+ sqrt_optab->handlers[(int) TFmode].libfunc \
+ = gen_rtx_SYMBOL_REF (Pmode, "_Q_sqrt"); \
+ INIT_SUBTARGET_OPTABS; \
+ } while (0)
+
+/* This is meant to be redefined in the host dependent files */
+#define INIT_SUBTARGET_OPTABS
+
+/* Compute the cost of computing a constant rtl expression RTX
+ whose rtx-code is CODE. The body of this macro is a portion
+ of a switch statement. If the code is computed here,
+ return it with a return statement. Otherwise, break from the switch. */
+
+#define CONST_COSTS(RTX,CODE,OUTER_CODE) \
+ case CONST_INT: \
+ if (INTVAL (RTX) < 0x1000 && INTVAL (RTX) >= -0x1000) \
+ return 0; \
+ case HIGH: \
+ return 2; \
+ case CONST: \
+ case LABEL_REF: \
+ case SYMBOL_REF: \
+ return 4; \
+ case CONST_DOUBLE: \
+ if (GET_MODE (RTX) == DImode) \
+ if ((XINT (RTX, 3) == 0 \
+ && (unsigned) XINT (RTX, 2) < 0x1000) \
+ || (XINT (RTX, 3) == -1 \
+ && XINT (RTX, 2) < 0 \
+ && XINT (RTX, 2) >= -0x1000)) \
+ return 0; \
+ return 8;
+
+/* Compute the cost of an address. For the sparc, all valid addresses are
+ the same cost. */
+
+#define ADDRESS_COST(RTX) 1
+
+/* Compute extra cost of moving data between one register class
+ and another. */
+#define GENERAL_OR_I64(C) ((C) == GENERAL_REGS || (C) == I64_REGS)
+#define REGISTER_MOVE_COST(CLASS1, CLASS2) \
+ (((FP_REG_CLASS_P (CLASS1) && GENERAL_OR_I64 (CLASS2)) \
+ || (GENERAL_OR_I64 (CLASS1) && FP_REG_CLASS_P (CLASS2)) \
+ || (CLASS1) == FPCC_REGS || (CLASS2) == FPCC_REGS) \
+ ? (sparc_cpu == PROCESSOR_ULTRASPARC ? 12 : 6) : 2)
+
+/* Provide the costs of a rtl expression. This is in the body of a
+ switch on CODE. The purpose for the cost of MULT is to encourage
+ `synth_mult' to find a synthetic multiply when reasonable.
+
+ If we need more than 12 insns to do a multiply, then go out-of-line,
+ since the call overhead will be < 10% of the cost of the multiply. */
+
+#define RTX_COSTS(X,CODE,OUTER_CODE) \
+ case MULT: \
+ return TARGET_HARD_MUL ? COSTS_N_INSNS (5) : COSTS_N_INSNS (25); \
+ case DIV: \
+ case UDIV: \
+ case MOD: \
+ case UMOD: \
+ return COSTS_N_INSNS (25); \
+ /* Make FLOAT and FIX more expensive than CONST_DOUBLE,\
+ so that cse will favor the latter. */ \
+ case FLOAT: \
+ case FIX: \
+ return 19;
+
+#define ISSUE_RATE sparc_issue_rate()
+
+/* Adjust the cost of dependencies. */
+#define ADJUST_COST(INSN,LINK,DEP,COST) \
+ if (sparc_cpu == PROCESSOR_SUPERSPARC) \
+ (COST) = supersparc_adjust_cost (INSN, LINK, DEP, COST); \
+ else if (sparc_cpu == PROCESSOR_ULTRASPARC) \
+ (COST) = ultrasparc_adjust_cost (INSN, LINK, DEP, COST); \
+ else
+
+/* Conditional branches with empty delay slots have a length of two. */
+#define ADJUST_INSN_LENGTH(INSN, LENGTH) \
+ if (GET_CODE (INSN) == CALL_INSN \
+ || (GET_CODE (INSN) == JUMP_INSN && ! simplejump_p (insn))) \
+ LENGTH += 1; else
+
+/* Control the assembler format that we output. */
+
+/* Output at beginning of assembler file. */
+
+#define ASM_FILE_START(file)
+
+/* A C string constant describing how to begin a comment in the target
+ assembler language. The compiler assumes that the comment will end at
+ the end of the line. */
+
+#define ASM_COMMENT_START "!"
+
+/* Output to assembler file text saying following lines
+ may contain character constants, extra white space, comments, etc. */
+
+#define ASM_APP_ON ""
+
+/* Output to assembler file text saying following lines
+ no longer contain unusual constructs. */
+
+#define ASM_APP_OFF ""
+
+/* ??? Try to make the style consistent here (_OP?). */
+
+#define ASM_LONGLONG ".xword"
+#define ASM_LONG ".word"
+#define ASM_SHORT ".half"
+#define ASM_BYTE_OP ".byte"
+#define ASM_FLOAT ".single"
+#define ASM_DOUBLE ".double"
+#define ASM_LONGDOUBLE ".xxx" /* ??? Not known (or used yet). */
+
+/* Output before read-only data. */
+
+#define TEXT_SECTION_ASM_OP ".text"
+
+/* Output before writable data. */
+
+#define DATA_SECTION_ASM_OP ".data"
+
+/* How to refer to registers in assembler output.
+ This sequence is indexed by compiler's hard-register-number (see above). */
+
+#define REGISTER_NAMES \
+{"%g0", "%g1", "%g2", "%g3", "%g4", "%g5", "%g6", "%g7", \
+ "%o0", "%o1", "%o2", "%o3", "%o4", "%o5", "%sp", "%o7", \
+ "%l0", "%l1", "%l2", "%l3", "%l4", "%l5", "%l6", "%l7", \
+ "%i0", "%i1", "%i2", "%i3", "%i4", "%i5", "%fp", "%i7", \
+ "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", \
+ "%f8", "%f9", "%f10", "%f11", "%f12", "%f13", "%f14", "%f15", \
+ "%f16", "%f17", "%f18", "%f19", "%f20", "%f21", "%f22", "%f23", \
+ "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31", \
+ "%f32", "%f33", "%f34", "%f35", "%f36", "%f37", "%f38", "%f39", \
+ "%f40", "%f41", "%f42", "%f43", "%f44", "%f45", "%f46", "%f47", \
+ "%f48", "%f49", "%f50", "%f51", "%f52", "%f53", "%f54", "%f55", \
+ "%f56", "%f57", "%f58", "%f59", "%f60", "%f61", "%f62", "%f63", \
+ "%fcc0", "%fcc1", "%fcc2", "%fcc3", "%icc"}
+
+/* Define additional names for use in asm clobbers and asm declarations. */
+
+#define ADDITIONAL_REGISTER_NAMES \
+{{"ccr", SPARC_ICC_REG}, {"cc", SPARC_ICC_REG}}
+
+/* How to renumber registers for dbx and gdb. In the flat model, the frame
+ pointer is really %i7. */
+
+#define DBX_REGISTER_NUMBER(REGNO) \
+ (TARGET_FLAT && REGNO == FRAME_POINTER_REGNUM ? 31 : REGNO)
+
+/* On Sun 4, this limit is 2048. We use 1000 to be safe, since the length
+ can run past this up to a continuation point. Once we used 1500, but
+ a single entry in C++ can run more than 500 bytes, due to the length of
+ mangled symbol names. dbxout.c should really be fixed to do
+ continuations when they are actually needed instead of trying to
+ guess... */
+#define DBX_CONTIN_LENGTH 1000
+
+/* This is how to output a note to DBX telling it the line number
+ to which the following sequence of instructions corresponds.
+
+ This is needed for SunOS 4.0, and should not hurt for 3.2
+ versions either. */
+#define ASM_OUTPUT_SOURCE_LINE(file, line) \
+ { static int sym_lineno = 1; \
+ fprintf (file, ".stabn 68,0,%d,LM%d\nLM%d:\n", \
+ line, sym_lineno, sym_lineno); \
+ sym_lineno += 1; }
+
+/* This is how to output the definition of a user-level label named NAME,
+ such as the label on a static function or variable NAME. */
+
+#define ASM_OUTPUT_LABEL(FILE,NAME) \
+ do { assemble_name (FILE, NAME); fputs (":\n", FILE); } while (0)
+
+/* This is how to output a command to make the user-level label named NAME
+ defined for reference from other files. */
+
+#define ASM_GLOBALIZE_LABEL(FILE,NAME) \
+ do { fputs ("\t.global ", FILE); assemble_name (FILE, NAME); fputs ("\n", FILE);} while (0)
+
+/* The prefix to add to user-visible assembler symbols. */
+
+#define USER_LABEL_PREFIX "_"
+
+/* This is how to output a definition of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
+ fprintf (FILE, "%s%d:\n", PREFIX, NUM)
+
+/* This is how to store into the string LABEL
+ the symbol_ref name of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class.
+ This is suitable for output with `assemble_name'. */
+
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf ((LABEL), "*%s%ld", (PREFIX), (long)(NUM))
+
+/* This is how to output an assembler line defining a `float' constant.
+ We always have to use a .long pseudo-op to do this because the native
+ SVR4 ELF assembler is buggy and it generates incorrect values when we
+ try to use the .float pseudo-op instead. */
+
+#define ASM_OUTPUT_FLOAT(FILE,VALUE) \
+ { \
+ long t; \
+ char str[30]; \
+ REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
+ REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \
+ fprintf (FILE, "\t%s\t0x%lx %s ~%s\n", ASM_LONG, t, \
+ ASM_COMMENT_START, str); \
+ } \
+
+/* This is how to output an assembler line defining a `double' constant.
+ We always have to use a .long pseudo-op to do this because the native
+ SVR4 ELF assembler is buggy and it generates incorrect values when we
+ try to use the .float pseudo-op instead. */
+
+#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
+ { \
+ long t[2]; \
+ char str[30]; \
+ REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \
+ REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \
+ fprintf (FILE, "\t%s\t0x%lx %s ~%s\n", ASM_LONG, t[0], \
+ ASM_COMMENT_START, str); \
+ fprintf (FILE, "\t%s\t0x%lx\n", ASM_LONG, t[1]); \
+ }
+
+/* This is how to output an assembler line defining a `long double'
+ constant. */
+
+#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \
+ { \
+ long t[4]; \
+ char str[30]; \
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE ((VALUE), t); \
+ REAL_VALUE_TO_DECIMAL ((VALUE), "%.20e", str); \
+ fprintf (FILE, "\t%s\t0x%lx %s ~%s\n", ASM_LONG, t[0], \
+ ASM_COMMENT_START, str); \
+ fprintf (FILE, "\t%s\t0x%lx\n", ASM_LONG, t[1]); \
+ fprintf (FILE, "\t%s\t0x%lx\n", ASM_LONG, t[2]); \
+ fprintf (FILE, "\t%s\t0x%lx\n", ASM_LONG, t[3]); \
+ }
+
+/* This is how to output an assembler line defining an `int' constant. */
+
+#define ASM_OUTPUT_INT(FILE,VALUE) \
+( fprintf (FILE, "\t%s\t", ASM_LONG), \
+ output_addr_const (FILE, (VALUE)), \
+ fprintf (FILE, "\n"))
+
+/* This is how to output an assembler line defining a DImode constant. */
+#define ASM_OUTPUT_DOUBLE_INT(FILE,VALUE) \
+ output_double_int (FILE, VALUE)
+
+/* Likewise for `char' and `short' constants. */
+
+#define ASM_OUTPUT_SHORT(FILE,VALUE) \
+( fprintf (FILE, "\t%s\t", ASM_SHORT), \
+ output_addr_const (FILE, (VALUE)), \
+ fprintf (FILE, "\n"))
+
+#define ASM_OUTPUT_CHAR(FILE,VALUE) \
+( fprintf (FILE, "\t%s\t", ASM_BYTE_OP), \
+ output_addr_const (FILE, (VALUE)), \
+ fprintf (FILE, "\n"))
+
+/* This is how to output an assembler line for a numeric constant byte. */
+
+#define ASM_OUTPUT_BYTE(FILE,VALUE) \
+ fprintf (FILE, "\t%s\t0x%x\n", ASM_BYTE_OP, (VALUE))
+
+/* This is how to output an element of a case-vector that is absolute. */
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+do { \
+ char label[30]; \
+ ASM_GENERATE_INTERNAL_LABEL (label, "L", VALUE); \
+ if (Pmode == SImode) \
+ fprintf (FILE, "\t.word\t"); \
+ else \
+ fprintf (FILE, "\t.xword\t"); \
+ assemble_name (FILE, label); \
+ fputc ('\n', FILE); \
+} while (0)
+
+/* This is how to output an element of a case-vector that is relative.
+ (SPARC uses such vectors only when generating PIC.) */
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+do { \
+ char label[30]; \
+ ASM_GENERATE_INTERNAL_LABEL (label, "L", VALUE); \
+ if (Pmode == SImode) \
+ fprintf (FILE, "\t.word\t"); \
+ else \
+ fprintf (FILE, "\t.xword\t"); \
+ assemble_name (FILE, label); \
+ ASM_GENERATE_INTERNAL_LABEL (label, "L", (REL)); \
+ fputc ('-', FILE); \
+ assemble_name (FILE, label); \
+ fputc ('\n', FILE); \
+} while (0)
+
+/* This is how to output an assembler line
+ that says to advance the location counter
+ to a multiple of 2**LOG bytes. */
+
+#define ASM_OUTPUT_ALIGN(FILE,LOG) \
+ if ((LOG) != 0) \
+ fprintf (FILE, "\t.align %d\n", (1<<(LOG)))
+
+#define LABEL_ALIGN_AFTER_BARRIER(LABEL) (sparc_align_jumps)
+
+#define LOOP_ALIGN(LABEL) (sparc_align_loops)
+
+#define ASM_OUTPUT_SKIP(FILE,SIZE) \
+ fprintf (FILE, "\t.skip %u\n", (SIZE))
+
+/* This says how to output an assembler line
+ to define a global common symbol. */
+
+#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \
+( fputs ("\t.common ", (FILE)), \
+ assemble_name ((FILE), (NAME)), \
+ fprintf ((FILE), ",%u,\"bss\"\n", (SIZE)))
+
+/* This says how to output an assembler line to define a local common
+ symbol. */
+
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGNED) \
+( fputs ("\t.reserve ", (FILE)), \
+ assemble_name ((FILE), (NAME)), \
+ fprintf ((FILE), ",%u,\"bss\",%u\n", \
+ (SIZE), ((ALIGNED) / BITS_PER_UNIT)))
+
+/* A C statement (sans semicolon) to output to the stdio stream
+ FILE the assembler definition of uninitialized global DECL named
+ NAME whose size is SIZE bytes and alignment is ALIGN bytes.
+ Try to use asm_output_aligned_bss to implement this macro. */
+
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+ do { \
+ fputs (".globl ", (FILE)); \
+ assemble_name ((FILE), (NAME)); \
+ fputs ("\n", (FILE)); \
+ ASM_OUTPUT_ALIGNED_LOCAL (FILE, NAME, SIZE, ALIGN); \
+ } while (0)
+
+/* Store in OUTPUT a string (made with alloca) containing
+ an assembler-name for a local static variable named NAME.
+ LABELNO is an integer which is different for each call. */
+
+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
+( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
+ sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
+
+#define IDENT_ASM_OP ".ident"
+
+/* Output #ident as a .ident. */
+
+#define ASM_OUTPUT_IDENT(FILE, NAME) \
+ fprintf (FILE, "\t%s\t\"%s\"\n", IDENT_ASM_OP, NAME);
+
+/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
+ Used for C++ multiple inheritance. */
+#define ASM_OUTPUT_MI_THUNK(FILE, THUNK_FNDECL, DELTA, FUNCTION) \
+do { \
+ int big_delta = (DELTA) >= 4096 || (DELTA) < -4096; \
+ if (big_delta) \
+ fprintf (FILE, "\tset %d,%%g1\n\tadd %%o0,%%g1,%%o0\n", (DELTA)); \
+ /* Don't use the jmp solution unless we know the target is local to \
+ the application or shared object. \
+ XXX: Wimp out and don't actually check anything except if this is \
+ an embedded target where we assume there are no shared libs. */ \
+ if (!TARGET_CM_EMBMEDANY || flag_pic) \
+ { \
+ if (! big_delta) \
+ fprintf (FILE, "\tadd %%o0,%d,%%o0\n", DELTA); \
+ fprintf (FILE, "\tmov %%o7,%%g1\n"); \
+ fprintf (FILE, "\tcall "); \
+ assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
+ fprintf (FILE, ",0\n"); \
+ } \
+ else if (TARGET_CM_EMBMEDANY) \
+ { \
+ fprintf (FILE, "\tsetx "); \
+ assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
+ fprintf (FILE, ",%%g5,%%g1\n\tjmp %%g1\n"); \
+ } \
+ else \
+ { \
+ fprintf (FILE, "\tsethi %%hi("); \
+ assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
+ fprintf (FILE, "),%%g1\n\tjmp %%g1+%%lo("); \
+ assemble_name (FILE, XSTR (XEXP (DECL_RTL (FUNCTION), 0), 0)); \
+ fprintf (FILE, ")\n"); \
+ } \
+ if (!TARGET_CM_EMBMEDANY || flag_pic) \
+ fprintf (FILE, "\tmov %%g1,%%o7\n"); \
+ else if (big_delta) \
+ fprintf (FILE, "\tnop\n"); \
+ else \
+ fprintf (FILE, "\tadd %%o0,%d,%%o0\n", DELTA); \
+} while (0)
+
+/* Define the parentheses used to group arithmetic operations
+ in assembler code. */
+
+#define ASM_OPEN_PAREN "("
+#define ASM_CLOSE_PAREN ")"
+
+/* Define results of standard character escape sequences. */
+#define TARGET_BELL 007
+#define TARGET_BS 010
+#define TARGET_TAB 011
+#define TARGET_NEWLINE 012
+#define TARGET_VT 013
+#define TARGET_FF 014
+#define TARGET_CR 015
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
+ ((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' || (CHAR) == '(' || (CHAR) == '_')
+
+/* Print operand X (an rtx) in assembler syntax to file FILE.
+ CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
+ For `%' followed by punctuation, CODE is the punctuation and X is null. */
+
+#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
+
+/* Print a memory address as an operand to reference that memory location. */
+
+#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \
+{ register rtx base, index = 0; \
+ int offset = 0; \
+ register rtx addr = ADDR; \
+ if (GET_CODE (addr) == REG) \
+ fputs (reg_names[REGNO (addr)], FILE); \
+ else if (GET_CODE (addr) == PLUS) \
+ { \
+ if (GET_CODE (XEXP (addr, 0)) == CONST_INT) \
+ offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);\
+ else if (GET_CODE (XEXP (addr, 1)) == CONST_INT) \
+ offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);\
+ else \
+ base = XEXP (addr, 0), index = XEXP (addr, 1); \
+ fputs (reg_names[REGNO (base)], FILE); \
+ if (index == 0) \
+ fprintf (FILE, "%+d", offset); \
+ else if (GET_CODE (index) == REG) \
+ fprintf (FILE, "+%s", reg_names[REGNO (index)]); \
+ else if (GET_CODE (index) == SYMBOL_REF \
+ || GET_CODE (index) == LABEL_REF \
+ || GET_CODE (index) == CONST) \
+ fputc ('+', FILE), output_addr_const (FILE, index); \
+ else abort (); \
+ } \
+ else if (GET_CODE (addr) == MINUS \
+ && GET_CODE (XEXP (addr, 1)) == LABEL_REF) \
+ { \
+ output_addr_const (FILE, XEXP (addr, 0)); \
+ fputs ("-(", FILE); \
+ output_addr_const (FILE, XEXP (addr, 1)); \
+ fputs ("-.)", FILE); \
+ } \
+ else if (GET_CODE (addr) == LO_SUM) \
+ { \
+ output_operand (XEXP (addr, 0), 0); \
+ fputs ("+%lo(", FILE); \
+ output_address (XEXP (addr, 1)); \
+ fputc (')', FILE); \
+ } \
+ else if (flag_pic && GET_CODE (addr) == CONST \
+ && GET_CODE (XEXP (addr, 0)) == MINUS \
+ && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST \
+ && GET_CODE (XEXP (XEXP (XEXP (addr, 0), 1), 0)) == MINUS \
+ && XEXP (XEXP (XEXP (XEXP (addr, 0), 1), 0), 1) == pc_rtx) \
+ { \
+ addr = XEXP (addr, 0); \
+ output_addr_const (FILE, XEXP (addr, 0)); \
+ /* Group the args of the second CONST in parenthesis. */ \
+ fputs ("-(", FILE); \
+ /* Skip past the second CONST--it does nothing for us. */\
+ output_addr_const (FILE, XEXP (XEXP (addr, 1), 0)); \
+ /* Close the parenthesis. */ \
+ fputc (')', FILE); \
+ } \
+ else \
+ { \
+ output_addr_const (FILE, addr); \
+ } \
+}
+
+/* Define the codes that are matched by predicates in sparc.c. */
+
+#define PREDICATE_CODES \
+{"reg_or_0_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
+{"fp_zero_operand", {CONST_DOUBLE}}, \
+{"intreg_operand", {SUBREG, REG}}, \
+{"fcc_reg_operand", {REG}}, \
+{"icc_or_fcc_reg_operand", {REG}}, \
+{"restore_operand", {REG}}, \
+{"call_operand", {MEM}}, \
+{"call_operand_address", {SYMBOL_REF, LABEL_REF, CONST, CONST_DOUBLE, ADDRESSOF, \
+ SUBREG, REG, PLUS, LO_SUM, CONST_INT}}, \
+{"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST, CONST_DOUBLE}}, \
+{"symbolic_memory_operand", {SUBREG, MEM}}, \
+{"label_ref_operand", {LABEL_REF}}, \
+{"sp64_medium_pic_operand", {CONST}}, \
+{"data_segment_operand", {SYMBOL_REF, PLUS, CONST}}, \
+{"text_segment_operand", {LABEL_REF, SYMBOL_REF, PLUS, CONST}}, \
+{"reg_or_nonsymb_mem_operand", {SUBREG, REG, MEM}}, \
+{"sparc_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, MEM}}, \
+{"move_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, CONST_DOUBLE, MEM}}, \
+{"splittable_symbolic_memory_operand", {MEM}}, \
+{"splittable_immediate_memory_operand", {MEM}}, \
+{"eq_or_neq", {EQ, NE}}, \
+{"normal_comp_operator", {GE, GT, LE, LT, GTU, LEU}}, \
+{"noov_compare_op", {NE, EQ, GE, GT, LE, LT, GEU, GTU, LEU, LTU}}, \
+{"v9_regcmp_op", {EQ, NE, GE, LT, LE, GT}}, \
+{"v8plus_regcmp_op", {EQ, NE}}, \
+{"extend_op", {SIGN_EXTEND, ZERO_EXTEND}}, \
+{"cc_arithop", {AND, IOR, XOR}}, \
+{"cc_arithopn", {AND, IOR}}, \
+{"arith_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT}}, \
+{"arith11_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT}}, \
+{"arith10_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT}}, \
+{"arith_double_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, CONST_DOUBLE}}, \
+{"arith11_double_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, CONST_DOUBLE}}, \
+{"arith10_double_operand", {SUBREG, REG, CONSTANT_P_RTX, CONST_INT, CONST_DOUBLE}}, \
+{"small_int", {CONST_INT, CONSTANT_P_RTX}}, \
+{"uns_small_int", {CONST_INT, CONSTANT_P_RTX}}, \
+{"uns_arith_operand", {SUBREG, REG, CONST_INT, CONSTANT_P_RTX}}, \
+{"clobbered_register", {REG}},
+
+
+/* The number of Pmode words for the setjmp buffer. */
+#define JMP_BUF_SIZE 12
+
+#define DONT_ACCESS_GBLS_AFTER_EPILOGUE (flag_pic)
+
+/* Declare functions defined in sparc.c and used in templates. */
+
+extern char *doublemove_string ();
+extern char *output_block_move ();
+extern char *output_cbranch ();
+extern char *output_fp_move_double ();
+extern char *output_fp_move_quad ();
+extern char *output_move_double ();
+extern char *output_move_quad ();
+extern char *output_return ();
+extern char *output_scc_insn ();
+extern char *output_v9branch ();
+extern char *singlemove_string ();
+
+extern void emit_v9_brxx_insn ();
+extern void finalize_pic ();
+extern void order_regs_for_local_alloc ();
+extern void output_double_int ();
+extern void output_function_epilogue ();
+extern void output_function_prologue ();
+extern void print_operand ();
+extern void sparc_flat_output_function_epilogue ();
+extern void sparc_flat_output_function_prologue ();
+
+extern int addrs_ok_for_ldd_peep ();
+extern int arith10_double_operand ();
+extern int arith10_operand ();
+extern int arith11_double_operand ();
+extern int arith11_operand ();
+extern int arith_double_operand ();
+extern int arith_operand ();
+extern int call_operand_address ();
+extern int cc_arithop ();
+extern int cc_arithopn ();
+extern int check_pic ();
+extern int compute_frame_size ();
+extern int data_segment_operand ();
+extern int eligible_for_epilogue_delay ();
+extern int eligible_for_return_delay ();
+extern int emit_move_sequence ();
+extern int extend_op ();
+extern int fcc_reg_operand ();
+extern int fp_zero_operand ();
+extern int icc_or_fcc_reg_operand ();
+extern int label_ref_operand ();
+extern int mem_aligned_8 ();
+extern int move_operand ();
+extern int noov_compare_op ();
+extern int pic_address_needs_scratch ();
+extern int reg_or_0_operand ();
+extern int reg_or_nonsymb_mem_operand ();
+extern int reg_unused_after ();
+extern int register_ok_for_ldd ();
+extern int registers_ok_for_ldd_peep ();
+extern int restore_operand ();
+extern int short_branch ();
+extern int small_int ();
+extern int sp64_medium_pic_operand ();
+extern int sparc_flat_eligible_for_epilogue_delay ();
+extern int sparc_flat_epilogue_delay_slots ();
+extern int sparc_issue_rate ();
+extern int sparc_operand ();
+extern int splittable_immediate_memory_operand ();
+extern int splittable_symbolic_memory_operand ();
+extern int supersparc_adjust_cost ();
+extern int symbolic_memory_operand ();
+extern int symbolic_operand ();
+extern int text_segment_operand ();
+extern int ultrasparc_adjust_cost ();
+extern int uns_small_int ();
+extern int v8plus_regcmp_op ();
+extern int v8plus_regcmp_p ();
+extern int v9_regcmp_op ();
+extern int v9_regcmp_p ();
+
+extern unsigned long sparc_flat_compute_frame_size ();
+extern unsigned long sparc_type_code ();
+
+extern char *sparc_v8plus_shift ();
+
+#ifdef __STDC__
+/* Function used for V8+ code generation. Returns 1 if the high
+ 32 bits of REG are 0 before INSN. */
+extern int sparc_check_64 (struct rtx_def *, struct rtx_def *);
+extern int sparc_return_peephole_ok (struct rtx_def *, struct rtx_def *);
+extern int compute_frame_size (int, int);
+#endif
+
+/* Defined in flags.h, but insn-emit.c does not include flags.h. */
+
+extern int flag_pic;
diff --git a/contrib/gcc/config/sparc/sparc.md b/contrib/gcc/config/sparc/sparc.md
new file mode 100644
index 0000000..ccfde05
--- /dev/null
+++ b/contrib/gcc/config/sparc/sparc.md
@@ -0,0 +1,6684 @@
+;;- Machine description for SPARC chip for GNU C compiler
+;; Copyright (C) 1987, 88, 89, 92-96, 1997 Free Software Foundation, Inc.
+;; Contributed by Michael Tiemann (tiemann@cygnus.com)
+;; 64 bit SPARC V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
+;; at Cygnus Support.
+
+;; This file is part of GNU CC.
+
+;; GNU CC 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, or (at your option)
+;; any later version.
+
+;; GNU CC 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 GNU CC; see the file COPYING. If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+;; The upper 32 fp regs on the v9 can't hold SFmode values. To deal with this
+;; a second register class, EXTRA_FP_REGS, exists for the v9 chip. The name
+;; is a bit of a misnomer as it covers all 64 fp regs. The corresponding
+;; constraint letter is 'e'. To avoid any confusion, 'e' is used instead of
+;; 'f' for all DF/TFmode values, including those that are specific to the v8.
+;;
+;; -mlive-g0 is *not* supported for TARGET_ARCH64, so we don't bother to
+;; test TARGET_LIVE_G0 if we have TARGET_ARCH64.
+
+;; Attribute for cpu type.
+;; These must match the values for enum processor_type in sparc.h.
+(define_attr "cpu" "v7,cypress,v8,supersparc,sparclite,f930,f934,sparclet,tsc701,v9,ultrasparc"
+ (const (symbol_ref "sparc_cpu_attr")))
+
+;; Attribute for the instruction set.
+;; At present we only need to distinguish v9/!v9, but for clarity we
+;; test TARGET_V8 too.
+(define_attr "isa" "v6,v8,v9,sparclet"
+ (const
+ (cond [(symbol_ref "TARGET_V9") (const_string "v9")
+ (symbol_ref "TARGET_V8") (const_string "v8")
+ (symbol_ref "TARGET_SPARCLET") (const_string "sparclet")]
+ (const_string "v6"))))
+
+;; Architecture size.
+(define_attr "arch" "arch32bit,arch64bit"
+ (const
+ (cond [(symbol_ref "TARGET_ARCH64") (const_string "arch64bit")]
+ (const_string "arch32bit"))))
+
+;; Whether -mlive-g0 is in effect.
+(define_attr "live_g0" "no,yes"
+ (const
+ (cond [(symbol_ref "TARGET_LIVE_G0") (const_string "yes")]
+ (const_string "no"))))
+
+;; Insn type. Used to default other attribute values.
+
+;; type "unary" insns have one input operand (1) and one output operand (0)
+;; type "binary" insns have two input operands (1,2) and one output (0)
+;; type "compare" insns have one or two input operands (0,1) and no output
+;; type "call_no_delay_slot" is a call followed by an unimp instruction.
+
+(define_attr "type"
+ "move,unary,binary,compare,load,sload,store,ialu,shift,uncond_branch,branch,call,call_no_delay_slot,return,address,imul,fpload,fpstore,fp,fpmove,fpcmove,fpcmp,fpmul,fpdivs,fpdivd,fpsqrt,cmove,multi,misc"
+ (const_string "binary"))
+
+;; Set true if insn uses call-clobbered intermediate register.
+(define_attr "use_clobbered" "false,true"
+ (if_then_else (and (eq_attr "type" "address")
+ (match_operand 0 "clobbered_register" ""))
+ (const_string "true")
+ (const_string "false")))
+
+;; Length (in # of insns).
+(define_attr "length" ""
+ (cond [(eq_attr "type" "load,sload,fpload")
+ (if_then_else (match_operand 1 "symbolic_memory_operand" "")
+ (const_int 2) (const_int 1))
+
+ (eq_attr "type" "store,fpstore")
+ (if_then_else (match_operand 0 "symbolic_memory_operand" "")
+ (const_int 2) (const_int 1))
+
+ (eq_attr "type" "address") (const_int 2)
+
+ (eq_attr "type" "binary")
+ (if_then_else (ior (match_operand 2 "arith_operand" "")
+ (match_operand 2 "arith_double_operand" ""))
+ (const_int 1) (const_int 3))
+
+ (eq_attr "type" "multi") (const_int 2)
+
+ (eq_attr "type" "move,unary")
+ (if_then_else (ior (match_operand 1 "arith_operand" "")
+ (match_operand 1 "arith_double_operand" ""))
+ (const_int 1) (const_int 2))]
+
+ (const_int 1)))
+
+(define_asm_attributes
+ [(set_attr "length" "1")
+ (set_attr "type" "multi")])
+
+;; Attributes for instruction and branch scheduling
+
+(define_attr "in_call_delay" "false,true"
+ (cond [(eq_attr "type" "uncond_branch,branch,call,call_no_delay_slot,return,multi")
+ (const_string "false")
+ (eq_attr "type" "load,fpload,store,fpstore")
+ (if_then_else (eq_attr "length" "1")
+ (const_string "true")
+ (const_string "false"))
+ (eq_attr "type" "address")
+ (if_then_else (eq_attr "use_clobbered" "false")
+ (const_string "true")
+ (const_string "false"))]
+ (if_then_else (eq_attr "length" "1")
+ (const_string "true")
+ (const_string "false"))))
+
+(define_delay (eq_attr "type" "call")
+ [(eq_attr "in_call_delay" "true") (nil) (nil)])
+
+(define_attr "leaf_function" "false,true"
+ (const (symbol_ref "leaf_function")))
+
+
+(define_attr "in_return_delay" "false,true"
+ (if_then_else (and (and (and (eq_attr "type" "move,load,sload,store,binary,ialu")
+ (eq_attr "length" "1"))
+ (eq_attr "leaf_function" "false"))
+ (match_insn "eligible_for_return_delay"))
+ (const_string "true")
+ (const_string "false")))
+
+(define_delay (and (eq_attr "type" "return")
+ (eq_attr "isa" "v9"))
+ [(eq_attr "in_return_delay" "true") (nil) (nil)])
+
+;; ??? Should implement the notion of predelay slots for floating point
+;; branches. This would allow us to remove the nop always inserted before
+;; a floating point branch.
+
+;; ??? It is OK for fill_simple_delay_slots to put load/store instructions
+;; in a delay slot, but it is not OK for fill_eager_delay_slots to do so.
+;; This is because doing so will add several pipeline stalls to the path
+;; that the load/store did not come from. Unfortunately, there is no way
+;; to prevent fill_eager_delay_slots from using load/store without completely
+;; disabling them. For the SPEC benchmark set, this is a serious lose,
+;; because it prevents us from moving back the final store of inner loops.
+
+(define_attr "in_branch_delay" "false,true"
+ (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,call_no_delay_slot,multi")
+ (eq_attr "length" "1"))
+ (const_string "true")
+ (const_string "false")))
+
+(define_attr "in_uncond_branch_delay" "false,true"
+ (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,call_no_delay_slot,multi")
+ (eq_attr "length" "1"))
+ (const_string "true")
+ (const_string "false")))
+
+(define_attr "in_annul_branch_delay" "false,true"
+ (if_then_else (and (eq_attr "type" "!uncond_branch,branch,call,call_no_delay_slot,multi")
+ (eq_attr "length" "1"))
+ (const_string "true")
+ (const_string "false")))
+
+(define_delay (eq_attr "type" "branch")
+ [(eq_attr "in_branch_delay" "true")
+ (nil) (eq_attr "in_annul_branch_delay" "true")])
+
+(define_delay (eq_attr "type" "uncond_branch")
+ [(eq_attr "in_uncond_branch_delay" "true")
+ (nil) (nil)])
+
+;; Function units of the SPARC
+
+;; (define_function_unit {name} {num-units} {n-users} {test}
+;; {ready-delay} {issue-delay} [{conflict-list}])
+
+;; The integer ALU.
+;; (Noted only for documentation; units that take one cycle do not need to
+;; be specified.)
+
+;; On the sparclite, integer multiply takes 1, 3, or 5 cycles depending on
+;; the inputs.
+
+;; (define_function_unit "alu" 1 0
+;; (eq_attr "type" "unary,binary,move,address") 1 0)
+
+;; ---- cypress CY7C602 scheduling:
+;; Memory with load-delay of 1 (i.e., 2 cycle load).
+
+(define_function_unit "memory" 1 0
+ (and (eq_attr "cpu" "cypress")
+ (eq_attr "type" "load,sload,fpload"))
+ 2 2)
+
+;; SPARC has two floating-point units: the FP ALU,
+;; and the FP MUL/DIV/SQRT unit.
+;; Instruction timings on the CY7C602 are as follows
+;; FABSs 4
+;; FADDs/d 5/5
+;; FCMPs/d 4/4
+;; FDIVs/d 23/37
+;; FMOVs 4
+;; FMULs/d 5/7
+;; FNEGs 4
+;; FSQRTs/d 34/63
+;; FSUBs/d 5/5
+;; FdTOi/s 5/5
+;; FsTOi/d 5/5
+;; FiTOs/d 9/5
+
+;; The CY7C602 can only support 2 fp isnsn simultaneously.
+;; More insns cause the chip to stall.
+
+(define_function_unit "fp_alu" 1 0
+ (and (eq_attr "cpu" "cypress")
+ (eq_attr "type" "fp,fpmove"))
+ 5 5)
+
+(define_function_unit "fp_mds" 1 0
+ (and (eq_attr "cpu" "cypress")
+ (eq_attr "type" "fpmul"))
+ 7 7)
+
+(define_function_unit "fp_mds" 1 0
+ (and (eq_attr "cpu" "cypress")
+ (eq_attr "type" "fpdivs,fpdivd"))
+ 37 37)
+
+(define_function_unit "fp_mds" 1 0
+ (and (eq_attr "cpu" "cypress")
+ (eq_attr "type" "fpsqrt"))
+ 63 63)
+
+;; ----- The TMS390Z55 scheduling
+;; The Supersparc can issue 1 - 3 insns per cycle: up to two integer,
+;; one ld/st, one fp.
+;; Memory delivers its result in one cycle to IU, zero cycles to FP
+
+(define_function_unit "memory" 1 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "load,sload"))
+ 1 1)
+
+(define_function_unit "memory" 1 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "fpload"))
+ 0 1)
+
+(define_function_unit "memory" 1 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "store,fpstore"))
+ 1 1)
+
+(define_function_unit "shift" 1 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "shift"))
+ 1 1)
+
+;; There are only two write ports to the integer register file
+;; A store also uses a write port
+
+(define_function_unit "iwport" 2 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "load,sload,store,shift,ialu"))
+ 1 1)
+
+;; Timings; throughput/latency
+;; FADD 1/3 add/sub, format conv, compar, abs, neg
+;; FMUL 1/3
+;; FDIVs 4/6
+;; FDIVd 7/9
+;; FSQRTs 6/8
+;; FSQRTd 10/12
+;; IMUL 4/4
+
+(define_function_unit "fp_alu" 1 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "fp,fpmove,fpcmp"))
+ 3 1)
+
+(define_function_unit "fp_mds" 1 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "fpmul"))
+ 3 1)
+
+(define_function_unit "fp_mds" 1 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "fpdivs"))
+ 6 4)
+
+(define_function_unit "fp_mds" 1 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "fpdivd"))
+ 9 7)
+
+(define_function_unit "fp_mds" 1 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "fpsqrt"))
+ 12 10)
+
+(define_function_unit "fp_mds" 1 0
+ (and (eq_attr "cpu" "supersparc")
+ (eq_attr "type" "imul"))
+ 4 4)
+
+;; ----- sparclet tsc701 scheduling
+;; The tsc701 issues 1 insn per cycle.
+;; Results may be written back out of order.
+
+;; Loads take 2 extra cycles to complete and 4 can be buffered at a time.
+
+(define_function_unit "tsc701_load" 4 1
+ (and (eq_attr "cpu" "tsc701")
+ (eq_attr "type" "load,sload"))
+ 3 1)
+
+;; Stores take 2(?) extra cycles to complete.
+;; It is desirable to not have any memory operation in the following 2 cycles.
+;; (??? or 2 memory ops in the case of std).
+
+(define_function_unit "tsc701_store" 1 0
+ (and (eq_attr "cpu" "tsc701")
+ (eq_attr "type" "store"))
+ 3 3
+ [(eq_attr "type" "load,sload,store")])
+
+;; The multiply unit has a latency of 5.
+(define_function_unit "tsc701_mul" 1 0
+ (and (eq_attr "cpu" "tsc701")
+ (eq_attr "type" "imul"))
+ 5 5)
+
+;; ----- The UltraSPARC-1 scheduling
+;; UltraSPARC has two integer units. Shift instructions can only execute
+;; on IE0. Condition code setting instructions, call, and jmpl (including
+;; the ret and retl pseudo-instructions) can only execute on IE1.
+;; Branch on register uses IE1, but branch on condition code does not.
+;; Conditional moves take 2 cycles. No other instruction can issue in the
+;; same cycle as a conditional move.
+;; Multiply and divide take many cycles during which no other instructions
+;; can issue.
+;; Memory delivers its result in two cycles (except for signed loads,
+;; which take one cycle more). One memory instruction can be issued per
+;; cycle.
+
+(define_function_unit "memory" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "load,fpload"))
+ 2 1)
+
+(define_function_unit "memory" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "sload"))
+ 3 1)
+
+(define_function_unit "memory" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "store,fpstore"))
+ 1 1)
+
+(define_function_unit "ieu" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "ialu,binary,shift,compare,cmove,call"))
+ 1 1)
+
+(define_function_unit "ieu_shift" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "shift"))
+ 1 1)
+
+(define_function_unit "ieu_shift" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "cmove"))
+ 2 1)
+
+;; Timings; throughput/latency
+;; FMOV 1/1 fmov, fabs, fneg
+;; FMOVcc 1/2
+;; FADD 1/4 add/sub, format conv, compar
+;; FMUL 1/4
+;; FDIVs 12/12
+;; FDIVd 22/22
+;; FSQRTs 12/12
+;; FSQRTd 22/22
+;; FCMP takes 1 cycle to branch, 2 cycles to conditional move.
+
+(define_function_unit "fadd" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpmove"))
+ 1 1)
+
+(define_function_unit "fadd" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpcmove"))
+ 2 1)
+
+(define_function_unit "fadd" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fp"))
+ 4 1)
+
+(define_function_unit "fadd" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpcmp"))
+ 2 1)
+
+(define_function_unit "fmul" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpmul"))
+ 4 1)
+
+(define_function_unit "fadd" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpcmove"))
+ 2 1)
+
+(define_function_unit "fadd" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpdivs"))
+ 12 12)
+
+(define_function_unit "fadd" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpdivd"))
+ 22 22)
+
+(define_function_unit "fadd" 1 0
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpsqrt"))
+ 12 12)
+
+;; Compare instructions.
+;; This controls RTL generation and register allocation.
+
+;; We generate RTL for comparisons and branches by having the cmpxx
+;; patterns store away the operands. Then, the scc and bcc patterns
+;; emit RTL for both the compare and the branch.
+;;
+;; We do this because we want to generate different code for an sne and
+;; seq insn. In those cases, if the second operand of the compare is not
+;; const0_rtx, we want to compute the xor of the two operands and test
+;; it against zero.
+;;
+;; We start with the DEFINE_EXPANDs, then the DEFINE_INSNs to match
+;; the patterns. Finally, we have the DEFINE_SPLITs for some of the scc
+;; insns that actually require more than one machine instruction.
+
+;; Put cmpsi first among compare insns so it matches two CONST_INT operands.
+
+(define_expand "cmpsi"
+ [(set (reg:CC 100)
+ (compare:CC (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "arith_operand" "")))]
+ ""
+ "
+{
+ sparc_compare_op0 = operands[0];
+ sparc_compare_op1 = operands[1];
+ DONE;
+}")
+
+(define_expand "cmpdi"
+ [(set (reg:CCX 100)
+ (compare:CCX (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "arith_double_operand" "")))]
+ "TARGET_ARCH64 || TARGET_V8PLUS"
+ "
+{
+ sparc_compare_op0 = operands[0];
+ sparc_compare_op1 = operands[1];
+ DONE;
+}")
+
+(define_expand "cmpsf"
+ ;; The 96 here isn't ever used by anyone.
+ [(set (reg:CCFP 96)
+ (compare:CCFP (match_operand:SF 0 "register_operand" "")
+ (match_operand:SF 1 "register_operand" "")))]
+ "TARGET_FPU"
+ "
+{
+ sparc_compare_op0 = operands[0];
+ sparc_compare_op1 = operands[1];
+ DONE;
+}")
+
+(define_expand "cmpdf"
+ ;; The 96 here isn't ever used by anyone.
+ [(set (reg:CCFP 96)
+ (compare:CCFP (match_operand:DF 0 "register_operand" "")
+ (match_operand:DF 1 "register_operand" "")))]
+ "TARGET_FPU"
+ "
+{
+ sparc_compare_op0 = operands[0];
+ sparc_compare_op1 = operands[1];
+ DONE;
+}")
+
+(define_expand "cmptf"
+ ;; The 96 here isn't ever used by anyone.
+ [(set (reg:CCFP 96)
+ (compare:CCFP (match_operand:TF 0 "register_operand" "")
+ (match_operand:TF 1 "register_operand" "")))]
+ "TARGET_FPU"
+ "
+{
+ sparc_compare_op0 = operands[0];
+ sparc_compare_op1 = operands[1];
+ DONE;
+}")
+
+;; Now the compare DEFINE_INSNs.
+
+(define_insn "*cmpsi_insn"
+ [(set (reg:CC 100)
+ (compare:CC (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "arith_operand" "rI")))]
+ ""
+ "cmp %0,%1"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmpdi_sp64"
+ [(set (reg:CCX 100)
+ (compare:CCX (match_operand:DI 0 "register_operand" "r")
+ (match_operand:DI 1 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64"
+ "cmp %0,%1"
+ [(set_attr "type" "compare")])
+
+(define_insn "cmpdi_v8plus"
+ [(set (reg:CCX 100)
+ (compare:CCX (match_operand:DI 0 "register_operand" "r,r,r")
+ (match_operand:DI 1 "arith_double_operand" "J,I,r")))
+ (clobber (match_scratch:SI 2 "=&h,&h,&h"))
+ (clobber (match_scratch:SI 3 "=X,X,&h"))]
+ "TARGET_V8PLUS"
+ "*
+{
+ /* The srl can be omitted if the value in the %L0 or %L1 is already
+ zero extended. */
+
+ output_asm_insn (\"sllx %H0,32,%2\", operands);
+
+ if (sparc_check_64 (operands[0], insn) <= 0)
+ output_asm_insn (\"srl %L0,0,%L0\", operands);
+
+ switch (which_alternative)
+ {
+ case 0:
+ return \"orcc %L0,%2,%%g0\";
+ case 1:
+ return \"or %L0,%2,%2\;cmp %2,%1\";
+ case 2:
+ if (sparc_check_64 (operands[1], insn) <= 0)
+ output_asm_insn (\"srl %L1,0,%L1\", operands);
+ return \"sllx %H1,32,%3\;or %L0,%2,%2\;or %L1,%3,%3\;cmp %2,%3\";
+ default:
+ abort();
+ }
+}"
+ [(set_attr "length" "3,4,7")])
+
+(define_insn "*cmpsf_fpe"
+ [(set (match_operand:CCFPE 0 "fcc_reg_operand" "=c")
+ (compare:CCFPE (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")))]
+ "TARGET_FPU"
+ "*
+{
+ if (TARGET_V9)
+ return \"fcmpes %0,%1,%2\";
+ return \"fcmpes %1,%2\";
+}"
+ [(set_attr "type" "fpcmp")])
+
+(define_insn "*cmpdf_fpe"
+ [(set (match_operand:CCFPE 0 "fcc_reg_operand" "=c")
+ (compare:CCFPE (match_operand:DF 1 "register_operand" "e")
+ (match_operand:DF 2 "register_operand" "e")))]
+ "TARGET_FPU"
+ "*
+{
+ if (TARGET_V9)
+ return \"fcmped %0,%1,%2\";
+ return \"fcmped %1,%2\";
+}"
+ [(set_attr "type" "fpcmp")])
+
+(define_insn "*cmptf_fpe"
+ [(set (match_operand:CCFPE 0 "fcc_reg_operand" "=c")
+ (compare:CCFPE (match_operand:TF 1 "register_operand" "e")
+ (match_operand:TF 2 "register_operand" "e")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "*
+{
+ if (TARGET_V9)
+ return \"fcmpeq %0,%1,%2\";
+ return \"fcmpeq %1,%2\";
+}"
+ [(set_attr "type" "fpcmp")])
+
+(define_insn "*cmpsf_fp"
+ [(set (match_operand:CCFP 0 "fcc_reg_operand" "=c")
+ (compare:CCFP (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")))]
+ "TARGET_FPU"
+ "*
+{
+ if (TARGET_V9)
+ return \"fcmps %0,%1,%2\";
+ return \"fcmps %1,%2\";
+}"
+ [(set_attr "type" "fpcmp")])
+
+(define_insn "*cmpdf_fp"
+ [(set (match_operand:CCFP 0 "fcc_reg_operand" "=c")
+ (compare:CCFP (match_operand:DF 1 "register_operand" "e")
+ (match_operand:DF 2 "register_operand" "e")))]
+ "TARGET_FPU"
+ "*
+{
+ if (TARGET_V9)
+ return \"fcmpd %0,%1,%2\";
+ return \"fcmpd %1,%2\";
+}"
+ [(set_attr "type" "fpcmp")])
+
+(define_insn "*cmptf_fp"
+ [(set (match_operand:CCFP 0 "fcc_reg_operand" "=c")
+ (compare:CCFP (match_operand:TF 1 "register_operand" "e")
+ (match_operand:TF 2 "register_operand" "e")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "*
+{
+ if (TARGET_V9)
+ return \"fcmpq %0,%1,%2\";
+ return \"fcmpq %1,%2\";
+}"
+ [(set_attr "type" "fpcmp")])
+
+;; Next come the scc insns. For seq, sne, sgeu, and sltu, we can do this
+;; without jumps using the addx/subx instructions. For seq/sne on v9 we use
+;; the same code as v8 (the addx/subx method has more applications). The
+;; exception to this is "reg != 0" which can be done in one instruction on v9
+;; (so we do it). For the rest, on v9 we use conditional moves; on v8, we do
+;; branches.
+
+;; Seq_special[_xxx] and sne_special[_xxx] clobber the CC reg, because they
+;; generate addcc/subcc instructions.
+
+(define_expand "seqsi_special"
+ [(set (match_dup 3)
+ (xor:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (parallel [(set (match_operand:SI 0 "register_operand" "")
+ (eq:SI (match_dup 3) (const_int 0)))
+ (clobber (reg:CC 100))])]
+ "! TARGET_LIVE_G0"
+ "{ operands[3] = gen_reg_rtx (SImode); }")
+
+(define_expand "seqdi_special"
+ [(set (match_dup 3)
+ (xor:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (match_operand:DI 0 "register_operand" "")
+ (eq:DI (match_dup 3) (const_int 0)))]
+ "TARGET_ARCH64"
+ "{ operands[3] = gen_reg_rtx (DImode); }")
+
+(define_expand "snesi_special"
+ [(set (match_dup 3)
+ (xor:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (parallel [(set (match_operand:SI 0 "register_operand" "")
+ (ne:SI (match_dup 3) (const_int 0)))
+ (clobber (reg:CC 100))])]
+ "! TARGET_LIVE_G0"
+ "{ operands[3] = gen_reg_rtx (SImode); }")
+
+(define_expand "snedi_special"
+ [(set (match_dup 3)
+ (xor:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (match_operand:DI 0 "register_operand" "")
+ (ne:DI (match_dup 3) (const_int 0)))]
+ "TARGET_ARCH64"
+ "{ operands[3] = gen_reg_rtx (DImode); }")
+
+(define_expand "seqdi_special_trunc"
+ [(set (match_dup 3)
+ (xor:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (match_operand:SI 0 "register_operand" "")
+ (eq:DI (match_dup 3) (const_int 0)))]
+ "TARGET_ARCH64"
+ "{ operands[3] = gen_reg_rtx (DImode); }")
+
+(define_expand "snedi_special_trunc"
+ [(set (match_dup 3)
+ (xor:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))
+ (set (match_operand:SI 0 "register_operand" "")
+ (ne:DI (match_dup 3) (const_int 0)))]
+ "TARGET_ARCH64"
+ "{ operands[3] = gen_reg_rtx (DImode); }")
+
+(define_expand "seqsi_special_extend"
+ [(set (match_dup 3)
+ (xor:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (parallel [(set (match_operand:DI 0 "register_operand" "")
+ (eq:SI (match_dup 3) (const_int 0)))
+ (clobber (reg:CC 100))])]
+ "TARGET_ARCH64"
+ "{ operands[3] = gen_reg_rtx (SImode); }")
+
+(define_expand "snesi_special_extend"
+ [(set (match_dup 3)
+ (xor:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (parallel [(set (match_operand:DI 0 "register_operand" "")
+ (ne:SI (match_dup 3) (const_int 0)))
+ (clobber (reg:CC 100))])]
+ "TARGET_ARCH64"
+ "{ operands[3] = gen_reg_rtx (SImode); }")
+
+;; ??? v9: Operand 0 needs a mode, so SImode was chosen.
+;; However, the code handles both SImode and DImode.
+(define_expand "seq"
+ [(set (match_operand:SI 0 "intreg_operand" "")
+ (eq:SI (match_dup 1) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "
+{
+ if (GET_MODE (sparc_compare_op0) == SImode)
+ {
+ rtx pat;
+
+ if (GET_MODE (operands[0]) == SImode)
+ pat = gen_seqsi_special (operands[0], sparc_compare_op0,
+ sparc_compare_op1);
+ else if (! TARGET_ARCH64)
+ FAIL;
+ else
+ pat = gen_seqsi_special_extend (operands[0], sparc_compare_op0,
+ sparc_compare_op1);
+ emit_insn (pat);
+ DONE;
+ }
+ else if (GET_MODE (sparc_compare_op0) == DImode)
+ {
+ rtx pat;
+
+ if (! TARGET_ARCH64)
+ FAIL;
+ else if (GET_MODE (operands[0]) == SImode)
+ pat = gen_seqdi_special_trunc (operands[0], sparc_compare_op0,
+ sparc_compare_op1);
+ else
+ pat = gen_seqdi_special (operands[0], sparc_compare_op0,
+ sparc_compare_op1);
+ emit_insn (pat);
+ DONE;
+ }
+ else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, EQ);
+ emit_insn (gen_sne (operands[0]));
+ DONE;
+ }
+ else if (TARGET_V9)
+ {
+ if (gen_v9_scc (EQ, operands))
+ DONE;
+ /* fall through */
+ }
+ operands[1] = gen_compare_reg (EQ, sparc_compare_op0, sparc_compare_op1);
+}")
+
+;; ??? v9: Operand 0 needs a mode, so SImode was chosen.
+;; However, the code handles both SImode and DImode.
+(define_expand "sne"
+ [(set (match_operand:SI 0 "intreg_operand" "")
+ (ne:SI (match_dup 1) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "
+{
+ if (GET_MODE (sparc_compare_op0) == SImode)
+ {
+ rtx pat;
+
+ if (GET_MODE (operands[0]) == SImode)
+ pat = gen_snesi_special (operands[0], sparc_compare_op0,
+ sparc_compare_op1);
+ else if (! TARGET_ARCH64)
+ FAIL;
+ else
+ pat = gen_snesi_special_extend (operands[0], sparc_compare_op0,
+ sparc_compare_op1);
+ emit_insn (pat);
+ DONE;
+ }
+ else if (GET_MODE (sparc_compare_op0) == DImode)
+ {
+ rtx pat;
+
+ if (! TARGET_ARCH64)
+ FAIL;
+ else if (GET_MODE (operands[0]) == SImode)
+ pat = gen_snedi_special_trunc (operands[0], sparc_compare_op0,
+ sparc_compare_op1);
+ else
+ pat = gen_snedi_special (operands[0], sparc_compare_op0,
+ sparc_compare_op1);
+ emit_insn (pat);
+ DONE;
+ }
+ else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, NE);
+ emit_insn (gen_sne (operands[0]));
+ DONE;
+ }
+ else if (TARGET_V9)
+ {
+ if (gen_v9_scc (NE, operands))
+ DONE;
+ /* fall through */
+ }
+ operands[1] = gen_compare_reg (NE, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "sgt"
+ [(set (match_operand:SI 0 "intreg_operand" "")
+ (gt:SI (match_dup 1) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "
+{
+ if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GT);
+ emit_insn (gen_sne (operands[0]));
+ DONE;
+ }
+ else if (TARGET_V9)
+ {
+ if (gen_v9_scc (GT, operands))
+ DONE;
+ /* fall through */
+ }
+ operands[1] = gen_compare_reg (GT, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "slt"
+ [(set (match_operand:SI 0 "intreg_operand" "")
+ (lt:SI (match_dup 1) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "
+{
+ if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LT);
+ emit_insn (gen_sne (operands[0]));
+ DONE;
+ }
+ else if (TARGET_V9)
+ {
+ if (gen_v9_scc (LT, operands))
+ DONE;
+ /* fall through */
+ }
+ operands[1] = gen_compare_reg (LT, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "sge"
+ [(set (match_operand:SI 0 "intreg_operand" "")
+ (ge:SI (match_dup 1) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "
+{
+ if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GE);
+ emit_insn (gen_sne (operands[0]));
+ DONE;
+ }
+ else if (TARGET_V9)
+ {
+ if (gen_v9_scc (GE, operands))
+ DONE;
+ /* fall through */
+ }
+ operands[1] = gen_compare_reg (GE, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "sle"
+ [(set (match_operand:SI 0 "intreg_operand" "")
+ (le:SI (match_dup 1) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "
+{
+ if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LE);
+ emit_insn (gen_sne (operands[0]));
+ DONE;
+ }
+ else if (TARGET_V9)
+ {
+ if (gen_v9_scc (LE, operands))
+ DONE;
+ /* fall through */
+ }
+ operands[1] = gen_compare_reg (LE, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "sgtu"
+ [(set (match_operand:SI 0 "intreg_operand" "")
+ (gtu:SI (match_dup 1) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "
+{
+ if (! TARGET_V9)
+ {
+ rtx tem;
+
+ /* We can do ltu easily, so if both operands are registers, swap them and
+ do a LTU. */
+ if ((GET_CODE (sparc_compare_op0) == REG
+ || GET_CODE (sparc_compare_op0) == SUBREG)
+ && (GET_CODE (sparc_compare_op1) == REG
+ || GET_CODE (sparc_compare_op1) == SUBREG))
+ {
+ tem = sparc_compare_op0;
+ sparc_compare_op0 = sparc_compare_op1;
+ sparc_compare_op1 = tem;
+ emit_insn (gen_sltu (operands[0]));
+ DONE;
+ }
+ }
+ else
+ {
+ if (gen_v9_scc (GTU, operands))
+ DONE;
+ }
+ operands[1] = gen_compare_reg (GTU, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "sltu"
+ [(set (match_operand:SI 0 "intreg_operand" "")
+ (ltu:SI (match_dup 1) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "
+{
+ if (TARGET_V9)
+ {
+ if (gen_v9_scc (LTU, operands))
+ DONE;
+ }
+ operands[1] = gen_compare_reg (LTU, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "sgeu"
+ [(set (match_operand:SI 0 "intreg_operand" "")
+ (geu:SI (match_dup 1) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "
+{
+ if (TARGET_V9)
+ {
+ if (gen_v9_scc (GEU, operands))
+ DONE;
+ }
+ operands[1] = gen_compare_reg (GEU, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "sleu"
+ [(set (match_operand:SI 0 "intreg_operand" "")
+ (leu:SI (match_dup 1) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "
+{
+ if (! TARGET_V9)
+ {
+ rtx tem;
+
+ /* We can do geu easily, so if both operands are registers, swap them and
+ do a GEU. */
+ if ((GET_CODE (sparc_compare_op0) == REG
+ || GET_CODE (sparc_compare_op0) == SUBREG)
+ && (GET_CODE (sparc_compare_op1) == REG
+ || GET_CODE (sparc_compare_op1) == SUBREG))
+ {
+ tem = sparc_compare_op0;
+ sparc_compare_op0 = sparc_compare_op1;
+ sparc_compare_op1 = tem;
+ emit_insn (gen_sgeu (operands[0]));
+ DONE;
+ }
+ }
+ else
+ {
+ if (gen_v9_scc (LEU, operands))
+ DONE;
+ }
+ operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1);
+}")
+
+;; Now the DEFINE_INSNs for the scc cases.
+
+;; The SEQ and SNE patterns are special because they can be done
+;; without any branching and do not involve a COMPARE.
+
+(define_insn "*snesi_zero"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ne:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 0)))
+ (clobber (reg:CC 100))]
+ "! TARGET_LIVE_G0"
+ "subcc %%g0,%1,%%g0\;addx %%g0,0,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "2")])
+
+(define_insn "*neg_snesi_zero"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (ne:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 0))))
+ (clobber (reg:CC 100))]
+ "! TARGET_LIVE_G0"
+ "subcc %%g0,%1,%%g0\;subx %%g0,0,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "2")])
+
+(define_insn "*snesi_zero_extend"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ne:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 0)))
+ (clobber (reg:CC 100))]
+ "TARGET_ARCH64"
+ "subcc %%g0,%1,%%g0\;addx %%g0,0,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "2")])
+
+(define_insn "*snedi_zero"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (ne:DI (match_operand:DI 1 "register_operand" "r")
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "mov 0,%0\;movrnz %1,1,%0"
+ [(set_attr "type" "cmove")
+ (set_attr "length" "2")])
+
+(define_insn "*neg_snedi_zero"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (neg:DI (ne:DI (match_operand:DI 1 "register_operand" "r")
+ (const_int 0))))]
+ "TARGET_ARCH64"
+ "mov 0,%0\;movrnz %1,-1,%0"
+ [(set_attr "type" "cmove")
+ (set_attr "length" "2")])
+
+(define_insn "*snedi_zero_trunc"
+ [(set (match_operand:SI 0 "register_operand" "=&r")
+ (ne:DI (match_operand:DI 1 "register_operand" "r")
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "mov 0,%0\;movrnz %1,1,%0"
+ [(set_attr "type" "cmove")
+ (set_attr "length" "2")])
+
+(define_insn "*seqsi_zero"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (eq:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 0)))
+ (clobber (reg:CC 100))]
+ "! TARGET_LIVE_G0"
+ "subcc %%g0,%1,%%g0\;subx %%g0,-1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "2")])
+
+(define_insn "*neg_seqsi_zero"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (eq:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 0))))
+ (clobber (reg:CC 100))]
+ "! TARGET_LIVE_G0"
+ "subcc %%g0,%1,%%g0\;addx %%g0,-1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "2")])
+
+(define_insn "*seqsi_zero_extend"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (eq:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 0)))
+ (clobber (reg:CC 100))]
+ "TARGET_ARCH64"
+ "subcc %%g0,%1,%%g0\;subx %%g0,-1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "2")])
+
+(define_insn "*seqdi_zero"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (eq:DI (match_operand:DI 1 "register_operand" "r")
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "mov 0,%0\;movrz %1,1,%0"
+ [(set_attr "type" "cmove")
+ (set_attr "length" "2")])
+
+(define_insn "*neg_seqdi_zero"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (neg:DI (eq:DI (match_operand:DI 1 "register_operand" "r")
+ (const_int 0))))]
+ "TARGET_ARCH64"
+ "mov 0,%0\;movrz %1,-1,%0"
+ [(set_attr "type" "cmove")
+ (set_attr "length" "2")])
+
+(define_insn "*seqdi_zero_trunc"
+ [(set (match_operand:SI 0 "register_operand" "=&r")
+ (eq:DI (match_operand:DI 1 "register_operand" "r")
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "mov 0,%0\;movrz %1,1,%0"
+ [(set_attr "type" "cmove")
+ (set_attr "length" "2")])
+
+;; We can also do (x + (i == 0)) and related, so put them in.
+;; ??? The addx/subx insns use the 32 bit carry flag so there are no DImode
+;; versions for v9.
+
+(define_insn "*x_plus_i_ne_0"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (ne:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 0))
+ (match_operand:SI 2 "register_operand" "r")))
+ (clobber (reg:CC 100))]
+ "! TARGET_LIVE_G0"
+ "subcc %%g0,%1,%%g0\;addx %2,0,%0"
+ [(set_attr "length" "2")])
+
+(define_insn "*x_minus_i_ne_0"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 2 "register_operand" "r")
+ (ne:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 0))))
+ (clobber (reg:CC 100))]
+ "! TARGET_LIVE_G0"
+ "subcc %%g0,%1,%%g0\;subx %2,0,%0"
+ [(set_attr "length" "2")])
+
+(define_insn "*x_plus_i_eq_0"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (eq:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 0))
+ (match_operand:SI 2 "register_operand" "r")))
+ (clobber (reg:CC 100))]
+ "! TARGET_LIVE_G0"
+ "subcc %%g0,%1,%%g0\;subx %2,-1,%0"
+ [(set_attr "length" "2")])
+
+(define_insn "*x_minus_i_eq_0"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 2 "register_operand" "r")
+ (eq:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 0))))
+ (clobber (reg:CC 100))]
+ "! TARGET_LIVE_G0"
+ "subcc %%g0,%1,%%g0\;addx %2,-1,%0"
+ [(set_attr "length" "2")])
+
+;; We can also do GEU and LTU directly, but these operate after a compare.
+;; ??? The addx/subx insns use the 32 bit carry flag so there are no DImode
+;; versions for v9.
+
+(define_insn "*sltu_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ltu:SI (reg:CC 100) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "addx %%g0,0,%0"
+ [(set_attr "type" "misc")])
+
+(define_insn "*neg_sltu_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (ltu:SI (reg:CC 100) (const_int 0))))]
+ "! TARGET_LIVE_G0"
+ "subx %%g0,0,%0"
+ [(set_attr "type" "misc")])
+
+;; ??? Combine should canonicalize these next two to the same pattern.
+(define_insn "*neg_sltu_minus_x"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (neg:SI (ltu:SI (reg:CC 100) (const_int 0)))
+ (match_operand:SI 1 "arith_operand" "rI")))]
+ "! TARGET_LIVE_G0"
+ "subx %%g0,%1,%0"
+ [(set_attr "type" "unary")])
+
+(define_insn "*neg_sltu_plus_x"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (plus:SI (ltu:SI (reg:CC 100) (const_int 0))
+ (match_operand:SI 1 "arith_operand" "rI"))))]
+ "! TARGET_LIVE_G0"
+ "subx %%g0,%1,%0"
+ [(set_attr "type" "unary")])
+
+(define_insn "*sgeu_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (geu:SI (reg:CC 100) (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "subx %%g0,-1,%0"
+ [(set_attr "type" "misc")])
+
+(define_insn "*neg_sgeu_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (geu:SI (reg:CC 100) (const_int 0))))]
+ "! TARGET_LIVE_G0"
+ "addx %%g0,-1,%0"
+ [(set_attr "type" "misc")])
+
+;; We can also do (x + ((unsigned) i >= 0)) and related, so put them in.
+;; ??? The addx/subx insns use the 32 bit carry flag so there are no DImode
+;; versions for v9.
+
+(define_insn "*sltu_plus_x"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (ltu:SI (reg:CC 100) (const_int 0))
+ (match_operand:SI 1 "arith_operand" "rI")))]
+ "! TARGET_LIVE_G0"
+ "addx %%g0,%1,%0"
+ [(set_attr "type" "unary")])
+
+(define_insn "*sltu_plus_x_plus_y"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (ltu:SI (reg:CC 100) (const_int 0))
+ (plus:SI (match_operand:SI 1 "arith_operand" "%r")
+ (match_operand:SI 2 "arith_operand" "rI"))))]
+ ""
+ "addx %1,%2,%0")
+
+(define_insn "*x_minus_sltu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (ltu:SI (reg:CC 100) (const_int 0))))]
+ ""
+ "subx %1,0,%0"
+ [(set_attr "type" "unary")])
+
+;; ??? Combine should canonicalize these next two to the same pattern.
+(define_insn "*x_minus_y_minus_sltu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (ltu:SI (reg:CC 100) (const_int 0))))]
+ ""
+ "subx %1,%2,%0")
+
+(define_insn "*x_minus_sltu_plus_y"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (plus:SI (ltu:SI (reg:CC 100) (const_int 0))
+ (match_operand:SI 2 "arith_operand" "rI"))))]
+ ""
+ "subx %1,%2,%0")
+
+(define_insn "*sgeu_plus_x"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (geu:SI (reg:CC 100) (const_int 0))
+ (match_operand:SI 1 "register_operand" "r")))]
+ ""
+ "subx %1,-1,%0"
+ [(set_attr "type" "unary")])
+
+(define_insn "*x_minus_sgeu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (geu:SI (reg:CC 100) (const_int 0))))]
+ ""
+ "addx %1,-1,%0"
+ [(set_attr "type" "unary")])
+
+;; Now we have the generic scc insns.
+;; !v9: These will be done using a jump.
+;; v9: Use conditional moves which are defined elsewhere.
+;; We have to exclude the cases above, since we will not want combine to
+;; turn something that does not require a jump into something that does.
+
+(define_insn "*scc_si"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 2 "noov_compare_op"
+ [(match_operand 1 "icc_or_fcc_reg_operand" "")
+ (const_int 0)]))]
+ ""
+ "* return output_scc_insn (operands, insn); "
+ [(set_attr "type" "multi")
+ (set_attr "length" "3")])
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operator:SI 2 "noov_compare_op"
+ [(match_operand 1 "icc_or_fcc_reg_operand" "")
+ (const_int 0)]))]
+ ;; 32 bit LTU/GEU are better implemented using addx/subx
+ "TARGET_V9 && REGNO (operands[1]) == SPARC_ICC_REG
+ && (GET_MODE (operands[1]) == CCXmode
+ || (GET_CODE (operands[2]) != LTU && GET_CODE (operands[2]) != GEU))"
+ [(set (match_dup 0) (const_int 0))
+ (set (match_dup 0)
+ (if_then_else:SI (match_op_dup:SI 2 [(match_dup 1) (const_int 0)])
+ (const_int 1)
+ (match_dup 0)))]
+ "")
+
+(define_insn "*scc_di"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (match_operator:DI 2 "noov_compare_op"
+ [(match_operand 1 "icc_or_fcc_reg_operand" "")
+ (const_int 0)]))]
+ "TARGET_ARCH64"
+ "* return output_scc_insn (operands, insn); "
+ [(set_attr "type" "multi")
+ (set_attr "length" "3")])
+
+;; These control RTL generation for conditional jump insns
+
+;; The quad-word fp compare library routines all return nonzero to indicate
+;; true, which is different from the equivalent libgcc routines, so we must
+;; handle them specially here.
+
+(define_expand "beq"
+ [(set (pc)
+ (if_then_else (eq (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ if (TARGET_ARCH64 && sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode)
+ {
+ emit_v9_brxx_insn (EQ, sparc_compare_op0, operands[0]);
+ DONE;
+ }
+ else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, EQ);
+ emit_jump_insn (gen_bne (operands[0]));
+ DONE;
+ }
+ operands[1] = gen_compare_reg (EQ, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "bne"
+ [(set (pc)
+ (if_then_else (ne (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ if (TARGET_ARCH64 && sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode)
+ {
+ emit_v9_brxx_insn (NE, sparc_compare_op0, operands[0]);
+ DONE;
+ }
+ else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, NE);
+ emit_jump_insn (gen_bne (operands[0]));
+ DONE;
+ }
+ operands[1] = gen_compare_reg (NE, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "bgt"
+ [(set (pc)
+ (if_then_else (gt (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ if (TARGET_ARCH64 && sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode)
+ {
+ emit_v9_brxx_insn (GT, sparc_compare_op0, operands[0]);
+ DONE;
+ }
+ else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GT);
+ emit_jump_insn (gen_bne (operands[0]));
+ DONE;
+ }
+ operands[1] = gen_compare_reg (GT, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "bgtu"
+ [(set (pc)
+ (if_then_else (gtu (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ operands[1] = gen_compare_reg (GTU, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "blt"
+ [(set (pc)
+ (if_then_else (lt (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ if (TARGET_ARCH64 && sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode)
+ {
+ emit_v9_brxx_insn (LT, sparc_compare_op0, operands[0]);
+ DONE;
+ }
+ else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LT);
+ emit_jump_insn (gen_bne (operands[0]));
+ DONE;
+ }
+ operands[1] = gen_compare_reg (LT, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "bltu"
+ [(set (pc)
+ (if_then_else (ltu (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ operands[1] = gen_compare_reg (LTU, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "bge"
+ [(set (pc)
+ (if_then_else (ge (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ if (TARGET_ARCH64 && sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode)
+ {
+ emit_v9_brxx_insn (GE, sparc_compare_op0, operands[0]);
+ DONE;
+ }
+ else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, GE);
+ emit_jump_insn (gen_bne (operands[0]));
+ DONE;
+ }
+ operands[1] = gen_compare_reg (GE, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "bgeu"
+ [(set (pc)
+ (if_then_else (geu (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ operands[1] = gen_compare_reg (GEU, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "ble"
+ [(set (pc)
+ (if_then_else (le (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{
+ if (TARGET_ARCH64 && sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode)
+ {
+ emit_v9_brxx_insn (LE, sparc_compare_op0, operands[0]);
+ DONE;
+ }
+ else if (GET_MODE (sparc_compare_op0) == TFmode && ! TARGET_HARD_QUAD)
+ {
+ emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, LE);
+ emit_jump_insn (gen_bne (operands[0]));
+ DONE;
+ }
+ operands[1] = gen_compare_reg (LE, sparc_compare_op0, sparc_compare_op1);
+}")
+
+(define_expand "bleu"
+ [(set (pc)
+ (if_then_else (leu (match_dup 1) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "
+{ operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1);
+}")
+
+;; Now match both normal and inverted jump.
+
+(define_insn "*normal_branch"
+ [(set (pc)
+ (if_then_else (match_operator 0 "noov_compare_op"
+ [(reg 100) (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ return output_cbranch (operands[0], 1, 0,
+ final_sequence && INSN_ANNULLED_BRANCH_P (insn),
+ ! final_sequence, insn);
+}"
+ [(set_attr "type" "branch")])
+
+(define_insn "*inverted_branch"
+ [(set (pc)
+ (if_then_else (match_operator 0 "noov_compare_op"
+ [(reg 100) (const_int 0)])
+ (pc)
+ (label_ref (match_operand 1 "" ""))))]
+ ""
+ "*
+{
+ return output_cbranch (operands[0], 1, 1,
+ final_sequence && INSN_ANNULLED_BRANCH_P (insn),
+ ! final_sequence, insn);
+}"
+ [(set_attr "type" "branch")])
+
+(define_insn "*normal_fp_branch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator"
+ [(match_operand:CCFP 0 "fcc_reg_operand" "c")
+ (const_int 0)])
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ return output_cbranch (operands[1], 2, 0,
+ final_sequence && INSN_ANNULLED_BRANCH_P (insn),
+ ! final_sequence, insn);
+}"
+ [(set_attr "type" "branch")])
+
+(define_insn "*inverted_fp_branch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator"
+ [(match_operand:CCFP 0 "fcc_reg_operand" "c")
+ (const_int 0)])
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ ""
+ "*
+{
+ return output_cbranch (operands[1], 2, 1,
+ final_sequence && INSN_ANNULLED_BRANCH_P (insn),
+ ! final_sequence, insn);
+}"
+ [(set_attr "type" "branch")])
+
+(define_insn "*normal_fpe_branch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator"
+ [(match_operand:CCFPE 0 "fcc_reg_operand" "c")
+ (const_int 0)])
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ ""
+ "*
+{
+ return output_cbranch (operands[1], 2, 0,
+ final_sequence && INSN_ANNULLED_BRANCH_P (insn),
+ ! final_sequence, insn);
+}"
+ [(set_attr "type" "branch")])
+
+(define_insn "*inverted_fpe_branch"
+ [(set (pc)
+ (if_then_else (match_operator 1 "comparison_operator"
+ [(match_operand:CCFPE 0 "fcc_reg_operand" "c")
+ (const_int 0)])
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ ""
+ "*
+{
+ return output_cbranch (operands[1], 2, 1,
+ final_sequence && INSN_ANNULLED_BRANCH_P (insn),
+ ! final_sequence, insn);
+}"
+ [(set_attr "type" "branch")])
+
+;; Sparc V9-specific jump insns. None of these are guaranteed to be
+;; in the architecture.
+
+;; There are no 32 bit brreg insns.
+
+(define_insn "*normal_int_branch_sp64"
+ [(set (pc)
+ (if_then_else (match_operator 0 "v9_regcmp_op"
+ [(match_operand:DI 1 "register_operand" "r")
+ (const_int 0)])
+ (label_ref (match_operand 2 "" ""))
+ (pc)))]
+ "TARGET_ARCH64"
+ "*
+{
+ return output_v9branch (operands[0], 1, 2, 0,
+ final_sequence && INSN_ANNULLED_BRANCH_P (insn),
+ ! final_sequence);
+}"
+ [(set_attr "type" "branch")])
+
+(define_insn "*inverted_int_branch_sp64"
+ [(set (pc)
+ (if_then_else (match_operator 0 "v9_regcmp_op"
+ [(match_operand:DI 1 "register_operand" "r")
+ (const_int 0)])
+ (pc)
+ (label_ref (match_operand 2 "" ""))))]
+ "TARGET_ARCH64"
+ "*
+{
+ return output_v9branch (operands[0], 1, 2, 1,
+ final_sequence && INSN_ANNULLED_BRANCH_P (insn),
+ ! final_sequence);
+}"
+ [(set_attr "type" "branch")])
+
+;; Esoteric move insns (lo_sum, high, pic).
+
+(define_insn "*lo_sum_si"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "immediate_operand" "in")))]
+ ""
+ ;; V9 needs "add" because of the code models. We still use "or" for v8
+ ;; so we can compare the old compiler with the new.
+ "* return TARGET_ARCH64 ? \"add %1,%%lo(%a2),%0\" : \"or %1,%%lo(%a2),%0\";"
+ ;; Need to set length for this arith insn because operand2
+ ;; is not an "arith_operand".
+ [(set_attr "length" "1")])
+
+;; For PIC, symbol_refs are put inside unspec so that the optimizer will not
+;; confuse them with real addresses.
+(define_insn "pic_lo_sum_si"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
+ (unspec:SI [(match_operand:SI 2 "immediate_operand" "in")] 0)))]
+ "flag_pic"
+ ;; V9 needs "add" because of the code models. We still use "or" for v8
+ ;; so we can compare the old compiler with the new.
+ "* return TARGET_ARCH64 ? \"add %1,%%lo(%a2),%0\" : \"or %1,%%lo(%a2),%0\";"
+ ;; Need to set length for this arith insn because operand2
+ ;; is not an "arith_operand".
+ [(set_attr "length" "1")])
+
+;; The PIC version of sethi must appear before the non-pic case so that
+;; the unspec will not be matched as part of the operand.
+;; For PIC, symbol_refs are put inside unspec so that the optimizer will not
+;; confuse them with real addresses.
+(define_insn "pic_sethi_si"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (high:SI (unspec:SI [(match_operand 1 "" "")] 0)))]
+ "flag_pic && check_pic (1)"
+ "sethi %%hi(%a1),%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "1")])
+
+(define_insn "pic_lo_sum_di"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lo_sum:SI (match_operand:DI 1 "register_operand" "r")
+ (unspec:SI [(match_operand:DI 2 "immediate_operand" "in")] 0)))]
+ "TARGET_ARCH64 && flag_pic"
+ "add %1,%%lo(%a2),%0"
+ [(set_attr "length" "1")])
+
+(define_insn "pic_sethi_di"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:SI (unspec:SI [(match_operand 1 "" "")] 0)))]
+ "TARGET_ARCH64 && flag_pic && check_pic (1)"
+ "sethi %%hi(%a1),%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "1")])
+
+(define_insn "get_pc"
+ [(clobber (reg:SI 15))
+ (set (match_operand 0 "register_operand" "=r")
+ (unspec [(match_operand 1 "" "") (match_operand 2 "" "")] 2))]
+ "flag_pic && REGNO (operands[0]) == 23"
+ "sethi %%hi(%a1-4),%0\;call %a2\;add %0,%%lo(%a1+4),%0"
+ [(set_attr "length" "3")])
+
+(define_insn "get_pc_via_rdpc"
+ [(set (match_operand 0 "register_operand" "=r") (pc))]
+ "TARGET_V9"
+ "rd %%pc,%0"
+ [(set_attr "type" "move")])
+
+(define_insn "*sethi_hi"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (high:HI (match_operand 1 "" "")))]
+ "check_pic (1)"
+ "sethi %%hi(%a1),%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "1")])
+
+;; This must appear after the PIC sethi so that the PIC unspec will not
+;; be matched as part of the operand.
+(define_insn "*sethi_si"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (high:SI (match_operand 1 "" "")))]
+ "check_pic (1)"
+ "sethi %%hi(%a1),%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "1")])
+
+(define_insn "*lo_sum_di_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lo_sum:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:DI 2 "immediate_operand" "in")))]
+ "! TARGET_ARCH64"
+ "*
+{
+ /* Don't output a 64 bit constant, since we can't trust the assembler to
+ handle it correctly. */
+ if (GET_CODE (operands[2]) == CONST_DOUBLE)
+ operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[2]));
+ else if (GET_CODE (operands[2]) == CONST_INT
+ && HOST_BITS_PER_WIDE_INT > 32
+ && INTVAL (operands[2]) > 0xffffffff)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffffffff);
+
+ return \"or %L1,%%lo(%a2),%L0\";
+}"
+ ;; Need to set length for this arith insn because operand2
+ ;; is not an "arith_operand".
+ [(set_attr "length" "1")])
+
+;; ??? Optimizer does not handle "or %o1,%lo(0),%o1". How about add?
+
+(define_insn "*lo_sum_di_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lo_sum:DI (match_operand:DI 1 "register_operand" "0")
+ (match_operand:DI 2 "immediate_operand" "in")))]
+ "TARGET_ARCH64"
+ "*
+{
+ /* Don't output a 64 bit constant, since we can't trust the assembler to
+ handle it correctly. */
+ if (GET_CODE (operands[2]) == CONST_DOUBLE)
+ operands[2] = GEN_INT (CONST_DOUBLE_LOW (operands[2]));
+ else if (GET_CODE (operands[2]) == CONST_INT
+ && HOST_BITS_PER_WIDE_INT > 32
+ && INTVAL (operands[2]) > 0xffffffff)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0xffffffff);
+
+ /* Note that we use add here. This is important because Medium/Anywhere
+ code model support depends on it. */
+ return \"add %1,%%lo(%a2),%0\";
+}"
+ ;; Need to set length for this arith insn because operand2
+ ;; is not an "arith_operand".
+ [(set_attr "length" "1")])
+
+(define_insn "*sethi_di_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:DI (match_operand 1 "" "")))]
+ "! TARGET_ARCH64 && check_pic (1)"
+ "*
+{
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+
+ if (GET_CODE (op1) == CONST_INT)
+ {
+ operands[0] = operand_subword (op0, 1, 0, DImode);
+ output_asm_insn (\"sethi %%hi(%a1),%0\", operands);
+
+ operands[0] = operand_subword (op0, 0, 0, DImode);
+ if (INTVAL (op1) < 0)
+ return \"mov -1,%0\";
+ else
+ return \"mov 0,%0\";
+ }
+ else if (GET_CODE (op1) == CONST_DOUBLE)
+ {
+ operands[0] = operand_subword (op0, 1, 0, DImode);
+ operands[1] = GEN_INT (CONST_DOUBLE_LOW (op1));
+ output_asm_insn (\"sethi %%hi(%a1),%0\", operands);
+
+ operands[0] = operand_subword (op0, 0, 0, DImode);
+ operands[1] = GEN_INT (CONST_DOUBLE_HIGH (op1));
+ return singlemove_string (operands);
+ }
+ else
+ abort ();
+ return \"\";
+}"
+ [(set_attr "type" "move")
+ (set_attr "length" "2")])
+
+;;; ??? This pattern originally clobbered a scratch register. However, this
+;;; is invalid, the movdi pattern may not use a temp register because it
+;;; may be called from reload to reload a DImode value. In that case, we
+;;; end up with a scratch register that never gets allocated. To avoid this,
+;;; we use global register 1 which is never otherwise used by gcc as a temp.
+;;; The correct solution here might be to force DImode constants to memory,
+;;; e.g. by using a toc like the romp and rs6000 ports do for addresses, reg
+;;; 1 will then no longer need to be considered a fixed reg.
+
+(define_expand "sethi_di_sp64"
+ [(parallel
+ [(set (match_operand:DI 0 "register_operand" "")
+ (high:DI (match_operand 1 "general_operand" "")))
+ (clobber (reg:DI 1))])]
+ "TARGET_ARCH64"
+ "")
+
+(define_insn "*sethi_di_sp64_const"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:DI (match_operand 1 "const_double_operand" "")))
+ (clobber (reg:DI 1))]
+ "TARGET_ARCH64 && check_pic (1)"
+ "*
+{
+#if HOST_BITS_PER_WIDE_INT == 32
+ rtx high, low;
+
+ split_double (operands[1], &high, &low);
+
+ if (high == const0_rtx)
+ {
+ operands[1] = low;
+ output_asm_insn (\"sethi %%hi(%a1),%0\", operands);
+ }
+ else
+ {
+ operands[1] = high;
+ output_asm_insn (singlemove_string (operands), operands);
+
+ operands[1] = low;
+ output_asm_insn (\"sllx %0,32,%0\", operands);
+ if (low != const0_rtx)
+ output_asm_insn (\"sethi %%hi(%a1),%%g1; or %0,%%g1,%0\", operands);
+ }
+#else
+ rtx op = operands[1];
+
+ if (! SPARC_SETHI_P (INTVAL(op)))
+ {
+ operands[1] = GEN_INT (INTVAL (op) >> 32);
+ output_asm_insn (singlemove_string (operands), operands);
+
+ output_asm_insn (\"sllx %0,32,%0\", operands);
+ if (INTVAL (op) & 0xffffffff)
+ {
+ operands[1] = GEN_INT (INTVAL (op) & 0xffffffff);
+ output_asm_insn (\"sethi %%hi(%a1),%%g1; or %0,%%g1,%0\", operands);
+ }
+ }
+ else
+ {
+ output_asm_insn (\"sethi %%hi(%a1),%0\", operands);
+ }
+#endif
+
+ return \"\";
+}"
+ [(set_attr "type" "move")
+ (set_attr "length" "5")])
+
+;; Most of the required support for the various code models is here.
+;; We can do this because sparcs need the high insn to load the address. We
+;; just need to get high to do the right thing for each code model. Then each
+;; uses the same "%X+%lo(...)" in the load/store insn, though in the case of
+;; the medium/middle code model "%lo" is written "%l44".
+
+;; When TARGET_CM_MEDLOW, assume that the upper 32 bits of symbol addresses are
+;; always 0.
+;; When TARGET_CM_MEDMID, the executable must be in the low 16 TB of memory.
+;; This corresponds to the low 44 bits, and the %[hml]44 relocs are used.
+;; ??? Not implemented yet.
+;; When TARGET_CM_EMBMEDANY, the text and data segments have a maximum size of
+;; 31 bits and may be located anywhere. EMBMEDANY_BASE_REG contains the start
+;; address of the data segment, currently %g4.
+;; When TARGET_CM_MEDANY, the text and data segments have a maximum size of 31
+;; bits and may be located anywhere. The maximum offset from any instruction
+;; to the label _GLOBAL_OFFSET_TABLE_ is 31 bits.
+
+(define_insn "*sethi_di_medlow"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:DI (match_operand 1 "" "")))
+ ;; The clobber is here because emit_move_sequence assumes the worst case.
+ (clobber (reg:DI 1))]
+ "TARGET_CM_MEDLOW && check_pic (1)"
+ "sethi %%hi(%a1),%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "1")])
+
+(define_insn "*sethi_di_medium_pic"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:DI (match_operand 1 "sp64_medium_pic_operand" "")))]
+ "(TARGET_CM_MEDLOW || TARGET_CM_EMBMEDANY) && check_pic (1)"
+ "sethi %%hi(%a1),%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "1")])
+
+;; WARNING: %0 gets %hi(%1)+%g4.
+;; You cannot OR in %lo(%1), it must be added in.
+
+(define_insn "*sethi_di_embmedany_data"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:DI (match_operand 1 "data_segment_operand" "")))
+ ;; The clobber is here because emit_move_sequence assumes the worst case.
+ (clobber (reg:DI 1))]
+ "TARGET_CM_EMBMEDANY && check_pic (1)"
+ "sethi %%hi(%a1),%0; add %0,%_,%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "2")])
+
+(define_insn "*sethi_di_embmedany_text"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (high:DI (match_operand 1 "text_segment_operand" "")))
+ ;; The clobber is here because emit_move_sequence assumes the worst case.
+ (clobber (reg:DI 1))]
+ "TARGET_CM_EMBMEDANY && check_pic (1)"
+ "sethi %%uhi(%a1),%%g1; or %%g1,%%ulo(%a1),%%g1; sllx %%g1,32,%%g1; sethi %%hi(%a1),%0; or %0,%%g1,%0"
+ [(set_attr "type" "move")
+ (set_attr "length" "5")])
+
+;; Move instructions
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "general_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (emit_move_sequence (operands, QImode))
+ DONE;
+}")
+
+(define_insn "*movqi_insn"
+ [(set (match_operand:QI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,Q")
+ (match_operand:QI 1 "move_operand" "rI,K,Q,rJ"))]
+ "! TARGET_LIVE_G0
+ && (register_operand (operands[0], QImode)
+ || register_operand (operands[1], QImode)
+ || operands[1] == const0_rtx)"
+ "@
+ mov %1,%0
+ sethi %%hi(%a1),%0
+ ldub %1,%0
+ stb %r1,%0"
+ [(set_attr "type" "move,move,load,store")
+ (set_attr "length" "1")])
+
+(define_insn "*movqi_insn_liveg0"
+ [(set (match_operand:QI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,r,r,Q")
+ (match_operand:QI 1 "move_operand" "r,J,I,K,Q,r"))]
+ "TARGET_LIVE_G0
+ && (register_operand (operands[0], QImode)
+ || register_operand (operands[1], QImode))"
+ "@
+ mov %1,%0
+ and %0,0,%0
+ and %0,0,%0\;or %0,%1,%0
+ sethi %%hi(%a1),%0
+ ldub %1,%0
+ stb %1,%0"
+ [(set_attr "type" "move,move,move,move,load,store")
+ (set_attr "length" "1,1,2,1,1,1")])
+
+(define_insn "*lo_sum_qi"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (subreg:QI (lo_sum:SI (match_operand:QI 1 "register_operand" "r")
+ (match_operand 2 "immediate_operand" "in")) 0))]
+ ""
+ "or %1,%%lo(%a2),%0"
+ [(set_attr "length" "1")])
+
+(define_insn "*store_qi"
+ [(set (mem:QI (match_operand:SI 0 "symbolic_operand" ""))
+ (match_operand:QI 1 "reg_or_0_operand" "rJ"))
+ (clobber (match_scratch:SI 2 "=&r"))]
+ "(reload_completed || reload_in_progress)
+ && ! TARGET_PTR64"
+ "sethi %%hi(%a0),%2\;stb %r1,[%2+%%lo(%a0)]"
+ [(set_attr "type" "store")
+ (set_attr "length" "2")])
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "general_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (emit_move_sequence (operands, HImode))
+ DONE;
+}")
+
+(define_insn "*movhi_insn"
+ [(set (match_operand:HI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,Q")
+ (match_operand:HI 1 "move_operand" "rI,K,Q,rJ"))]
+ "! TARGET_LIVE_G0
+ && (register_operand (operands[0], HImode)
+ || register_operand (operands[1], HImode)
+ || operands[1] == const0_rtx)"
+ "@
+ mov %1,%0
+ sethi %%hi(%a1),%0
+ lduh %1,%0
+ sth %r1,%0"
+ [(set_attr "type" "move,move,load,store")
+ (set_attr "length" "1")])
+
+(define_insn "*movhi_insn_liveg0"
+ [(set (match_operand:HI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,r,r,Q")
+ (match_operand:HI 1 "move_operand" "r,J,I,K,Q,r"))]
+ "TARGET_LIVE_G0
+ && (register_operand (operands[0], HImode)
+ || register_operand (operands[1], HImode))"
+ "@
+ mov %1,%0
+ and %0,0,%0
+ and %0,0,%0\;or %0,%1,%0
+ sethi %%hi(%a1),%0
+ lduh %1,%0
+ sth %1,%0"
+ [(set_attr "type" "move,move,move,move,load,store")
+ (set_attr "length" "1,1,2,1,1,1")])
+
+(define_insn "*lo_sum_hi"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (lo_sum:HI (match_operand:HI 1 "register_operand" "r")
+ (match_operand 2 "immediate_operand" "in")))]
+ ""
+ "or %1,%%lo(%a2),%0"
+ [(set_attr "length" "1")])
+
+(define_insn "*store_hi"
+ [(set (mem:HI (match_operand:SI 0 "symbolic_operand" ""))
+ (match_operand:HI 1 "reg_or_0_operand" "rJ"))
+ (clobber (match_scratch:SI 2 "=&r"))]
+ "(reload_completed || reload_in_progress)
+ && ! TARGET_PTR64"
+ "sethi %%hi(%a0),%2\;sth %r1,[%2+%%lo(%a0)]"
+ [(set_attr "type" "store")
+ (set_attr "length" "2")])
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (emit_move_sequence (operands, SImode))
+ DONE;
+}")
+
+;; We must support both 'r' and 'f' registers here, because combine may
+;; convert SFmode hard registers to SImode hard registers when simplifying
+;; subreg sets.
+
+;; We cannot combine the similar 'r' and 'f' constraints, because it causes
+;; problems with register allocation. Reload might try to put an integer
+;; in an fp register, or an fp number is an integer register.
+
+(define_insn "*movsi_insn"
+ [(set (match_operand:SI 0 "reg_or_nonsymb_mem_operand" "=r,f,r,r,f,Q,Q,d")
+ (match_operand:SI 1 "move_operand" "rI,!f,K,Q,!Q,rJ,!f,J"))]
+ "! TARGET_LIVE_G0
+ && (register_operand (operands[0], SImode)
+ || register_operand (operands[1], SImode)
+ || operands[1] == const0_rtx)
+ && (GET_CODE (operands[0]) != REG || ! CONSTANT_P (operands[1])
+ || REGNO (operands[0]) < 32
+ || REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)"
+ "@
+ mov %1,%0
+ fmovs %1,%0
+ sethi %%hi(%a1),%0
+ ld %1,%0
+ ld %1,%0
+ st %r1,%0
+ st %1,%0
+ fzeros %0"
+ [(set_attr "type" "move,fpmove,move,load,fpload,store,fpstore,fpmove")
+ (set_attr "length" "1")])
+
+(define_insn "*movsi_insn_liveg0"
+ [(set (match_operand:SI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,f,r,r,f,Q,Q")
+ (match_operand:SI 1 "move_operand" "r,J,I,!f,K,Q,!Q,r,!f"))]
+ "TARGET_LIVE_G0
+ && (register_operand (operands[0], SImode)
+ || register_operand (operands[1], SImode))"
+ "@
+ mov %1,%0
+ and %0,0,%0
+ and %0,0,%0\;or %0,%1,%0
+ fmovs %1,%0
+ sethi %%hi(%a1),%0
+ ld %1,%0
+ ld %1,%0
+ st %1,%0
+ st %1,%0"
+ [(set_attr "type" "move,move,move,fpmove,move,load,fpload,store,fpstore")
+ (set_attr "length" "1,1,2,1,1,1,1,1,1")])
+
+(define_insn "*store_si"
+ [(set (mem:SI (match_operand:SI 0 "symbolic_operand" ""))
+ (match_operand:SI 1 "reg_or_0_operand" "rJ"))
+ (clobber (match_scratch:SI 2 "=&r"))]
+ "(reload_completed || reload_in_progress)
+ && ! TARGET_PTR64"
+ "sethi %%hi(%a0),%2\;st %r1,[%2+%%lo(%a0)]"
+ [(set_attr "type" "store")
+ (set_attr "length" "2")])
+
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (emit_move_sequence (operands, DImode))
+ DONE;
+}")
+
+;; 32 bit V9 movdi is like regular 32 bit except: a 64 bit zero can be stored
+;; to aligned memory with a single instruction, the ldd/std instructions
+;; are not used, and constants can not be moved to floating point registers.
+
+(define_insn "*movdi_sp32_v9"
+ [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "=r,T,Q,r,r,?e,?e,?Q,?b")
+ (match_operand:DI 1 "general_operand" "r,J,r,Q,i,e,Q,e,J"))]
+ "TARGET_V9 && ! TARGET_ARCH64
+ && (register_operand (operands[0], DImode)
+ || register_operand (operands[1], DImode)
+ || operands[1] == const0_rtx)
+ && (GET_CODE (operands[0]) != REG || ! CONSTANT_P (operands[1])
+ || REGNO (operands[0]) < 32
+ || REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)"
+ "*
+{
+ if (which_alternative == 1)
+ return \"stx %%g0,%0\";
+ if (which_alternative == 8)
+ return \"fzero %0\";
+ if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
+ return output_fp_move_double (operands);
+ return output_move_double (operands);
+}"
+ [(set_attr "type" "move,store,store,load,multi,fp,fpload,fpstore,fpmove")
+ (set_attr "length" "2,1,3,3,3,2,3,3,1")])
+
+;; SPARC V9 deprecates std. Split it here.
+(define_split
+ [(set (match_operand:DI 0 "memory_operand" "=m")
+ (match_operand:DI 1 "register_operand" "r"))]
+ "TARGET_V9 && ! TARGET_ARCH64 && reload_completed
+ && REGNO (operands[1]) < 32 && ! MEM_VOLATILE_P (operands[0])
+ && offsettable_memref_p (operands[0])"
+ [(set (match_dup 2) (match_dup 3))
+ (set (match_dup 4) (match_dup 5))]
+ "operands[3] = gen_highpart (SImode, operands[1]);
+ operands[5] = gen_lowpart (SImode, operands[1]);
+ operands[4] = adj_offsettable_operand (operands[0], 4);
+ PUT_MODE (operands[4], SImode);
+ operands[2] = copy_rtx (operands[0]);
+ PUT_MODE (operands[2], SImode);")
+
+;; Split register to register moves.
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (match_operand:DI 1 "arith_double_operand" "rIN"))]
+ "! TARGET_ARCH64
+ && REGNO (operands[0]) < 32
+ && GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 32
+ && ! reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+ "operands[2] = gen_highpart (SImode, operands[0]);
+ operands[3] = gen_lowpart (SImode, operands[0]);
+ operands[4] = gen_highpart (SImode, operands[1]);
+ operands[5] = gen_lowpart (SImode, operands[1]);")
+
+(define_insn "*movdi_sp32"
+ [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "=r,T,U,Q,r,r,?f,?f,?Q")
+ (match_operand:DI 1 "general_operand" "r,U,T,r,Q,i,f,Q,f"))]
+ "! TARGET_V9
+ && (register_operand (operands[0], DImode)
+ || register_operand (operands[1], DImode)
+ || operands[1] == const0_rtx)"
+ "*
+{
+ if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
+ return output_fp_move_double (operands);
+ return output_move_double (operands);
+}"
+ [(set_attr "type" "move,store,load,store,load,multi,fp,fpload,fpstore")
+ (set_attr "length" "2,1,1,3,3,3,2,3,3")])
+
+;;; ??? The trick used below can be extended to load any negative 32 bit
+;;; constant in two instructions. Currently the compiler will use HIGH/LO_SUM
+;;; for anything not matching the HIK constraints, which results in 5
+;;; instructions. Positive 32 bit constants can be loaded in the obvious way
+;;; with sethi/ori. To extend the trick, in the xor instruction, use
+;;; xor %o0, ((op1 & 0x3ff) | -0x400), %o0
+;;; This needs the original value of operands[1], not the inverted value.
+
+(define_insn "*movdi_sp64_insn"
+ [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "=r,r,r,Q,?e,?e,?Q")
+ (match_operand:DI 1 "move_operand" "rI,K,Q,rJ,e,Q,e"))]
+ "TARGET_ARCH64
+ && (register_operand (operands[0], DImode)
+ || register_operand (operands[1], DImode)
+ || operands[1] == const0_rtx)"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return \"mov %1,%0\";
+ case 1:
+ /* Sethi does not sign extend, so we must use a little trickery
+ to use it for negative numbers. Invert the constant before
+ loading it in, then use a xor immediate to invert the loaded bits
+ (along with the upper 32 bits) to the desired constant. This
+ works because the sethi and immediate fields overlap. */
+
+ if ((INTVAL (operands[1]) & 0x80000000) == 0)
+ return \"sethi %%hi(%a1),%0\";
+ else
+ {
+ operands[1] = GEN_INT (~INTVAL (operands[1]));
+ output_asm_insn (\"sethi %%hi(%a1),%0\", operands);
+ /* The low 10 bits are already zero, but invert the rest.
+ Assemblers don't accept 0x1c00, so use -0x400 instead. */
+ return \"xor %0,-0x400,%0\";
+ }
+ case 2:
+ return \"ldx %1,%0\";
+ case 3:
+ return \"stx %r1,%0\";
+ case 4:
+ return \"fmovd %1,%0\";
+ case 5:
+ return \"ldd %1,%0\";
+ case 6:
+ return \"std %1,%0\";
+ default:
+ abort ();
+ }
+}"
+ [(set_attr "type" "move,move,load,store,fp,fpload,fpstore")
+ (set_attr "length" "1,2,1,1,1,1,1")])
+
+;; ??? There's no symbolic (set (mem:DI ...) ...).
+;; Experimentation with v9 suggested one isn't needed.
+
+;; Floating point move insns
+
+;; This pattern forces (set (reg:SF ...) (const_double ...))
+;; to be reloaded by putting the constant into memory.
+;; It must come before the more general movsf pattern.
+(define_insn "*movsf_const_insn"
+ [(set (match_operand:SF 0 "general_operand" "=f,d,m,?r")
+ (match_operand:SF 1 "" "m,G,G,?F"))]
+ "TARGET_FPU
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && (GET_CODE (operands[0]) == REG
+ || fp_zero_operand (operands[1]))"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return \"ld %1,%0\";
+ case 1:
+ return \"fzeros %0\";
+ case 2:
+ return \"st %%g0,%0\";
+ case 3:
+ return singlemove_string (operands);
+ default:
+ abort ();
+ }
+}"
+ [(set_attr "type" "fpload,fpmove,store,load")
+ (set_attr "length" "1,1,1,2")])
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "general_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (emit_move_sequence (operands, SFmode))
+ DONE;
+}")
+
+(define_insn "*movsf_insn"
+ [(set (match_operand:SF 0 "reg_or_nonsymb_mem_operand" "=f,f,Q,r,r,Q")
+ (match_operand:SF 1 "reg_or_nonsymb_mem_operand" "f,Q,f,r,Q,r"))]
+ "TARGET_FPU
+ && (register_operand (operands[0], SFmode)
+ || register_operand (operands[1], SFmode))"
+ "@
+ fmovs %1,%0
+ ld %1,%0
+ st %1,%0
+ mov %1,%0
+ ld %1,%0
+ st %1,%0"
+ [(set_attr "type" "fpmove,fpload,fpstore,move,load,store")])
+
+;; Exactly the same as above, except that all `f' cases are deleted.
+;; This is necessary to prevent reload from ever trying to use a `f' reg
+;; when -mno-fpu.
+
+(define_insn "*movsf_no_f_insn"
+ [(set (match_operand:SF 0 "reg_or_nonsymb_mem_operand" "=r,r,Q")
+ (match_operand:SF 1 "reg_or_nonsymb_mem_operand" "r,Q,r"))]
+ "! TARGET_FPU
+ && (register_operand (operands[0], SFmode)
+ || register_operand (operands[1], SFmode))"
+ "@
+ mov %1,%0
+ ld %1,%0
+ st %1,%0"
+ [(set_attr "type" "move,load,store")])
+
+(define_insn "*store_sf"
+ [(set (mem:SF (match_operand:SI 0 "symbolic_operand" "i"))
+ (match_operand:SF 1 "reg_or_0_operand" "rfG"))
+ (clobber (match_scratch:SI 2 "=&r"))]
+ "(reload_completed || reload_in_progress)
+ && ! TARGET_PTR64"
+ "sethi %%hi(%a0),%2\;st %r1,[%2+%%lo(%a0)]"
+ [(set_attr "type" "store")
+ (set_attr "length" "2")])
+
+;; This pattern forces (set (reg:DF ...) (const_double ...))
+;; to be reloaded by putting the constant into memory.
+;; It must come before the more general movdf pattern.
+
+(define_insn "*movdf_const_insn"
+ [(set (match_operand:DF 0 "general_operand" "=?r,e,o,d")
+ (match_operand:DF 1 "" "?F,m,G,G"))]
+ "TARGET_FPU
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && (GET_CODE (operands[0]) == REG
+ || fp_zero_operand (operands[1]))"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return output_move_double (operands);
+ case 1:
+ return output_fp_move_double (operands);
+ case 2:
+ if (TARGET_ARCH64 || (TARGET_V9 && mem_aligned_8 (operands[0])))
+ {
+ return \"stx %%g0,%0\";
+ }
+ else
+ {
+ operands[1] = adj_offsettable_operand (operands[0], 4);
+ return \"st %%g0,%0\;st %%g0,%1\";
+ }
+ case 3:
+ return \"fzero %0\";
+ default:
+ abort ();
+ }
+}"
+ [(set_attr "type" "load,fpload,store,fpmove")
+ (set_attr "length" "3,3,3,1")])
+
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "general_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (emit_move_sequence (operands, DFmode))
+ DONE;
+}")
+
+(define_insn "*movdf_insn"
+ [(set (match_operand:DF 0 "reg_or_nonsymb_mem_operand" "=e,Q,e,T,U,r,Q,r")
+ (match_operand:DF 1 "reg_or_nonsymb_mem_operand" "e,e,Q,U,T,r,r,Q"))]
+ "TARGET_FPU
+ && (register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
+ "*
+{
+ if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
+ return output_fp_move_double (operands);
+ return output_move_double (operands);
+}"
+ [(set_attr "type" "fp,fpstore,fpload,fpstore,fpload,move,store,load")
+ (set_attr "length" "2,3,3,1,1,2,2,2")])
+
+;; Exactly the same as above, except that all `e' cases are deleted.
+;; This is necessary to prevent reload from ever trying to use a `e' reg
+;; when -mno-fpu.
+
+(define_insn "*movdf_no_e_insn"
+ [(set (match_operand:DF 0 "reg_or_nonsymb_mem_operand" "=T,U,r,Q,&r")
+ (match_operand:DF 1 "reg_or_nonsymb_mem_operand" "U,T,r,r,Q"))]
+ "! TARGET_FPU
+ && (register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
+ "* return output_move_double (operands);"
+ [(set_attr "type" "store,load,move,store,load")
+ (set_attr "length" "1,1,2,3,3")])
+
+;; Must handle overlapping registers here, since parameters can be unaligned
+;; in registers.
+
+(define_split
+ [(set (match_operand:DF 0 "register_operand" "")
+ (match_operand:DF 1 "register_operand" ""))]
+ "! TARGET_ARCH64 && reload_completed
+ && REGNO (operands[0]) < SPARC_FIRST_V9_FP_REG
+ && REGNO (operands[1]) < SPARC_FIRST_V9_FP_REG"
+ [(set (match_dup 2) (match_dup 3))
+ (set (match_dup 4) (match_dup 5))]
+ "
+{
+ rtx first_set = operand_subword (operands[0], 0, 0, DFmode);
+ rtx second_use = operand_subword (operands[1], 1, 0, DFmode);
+
+ if (REGNO (first_set) == REGNO (second_use))
+ {
+ operands[2] = operand_subword (operands[0], 1, 0, DFmode);
+ operands[3] = second_use;
+ operands[4] = first_set;
+ operands[5] = operand_subword (operands[1], 0, 0, DFmode);
+ }
+ else
+ {
+ operands[2] = first_set;
+ operands[3] = operand_subword (operands[1], 0, 0, DFmode);
+ operands[4] = operand_subword (operands[0], 1, 0, DFmode);
+ operands[5] = second_use;
+ }
+}")
+
+(define_insn "*store_df"
+ [(set (mem:DF (match_operand:SI 0 "symbolic_operand" "i,i"))
+ (match_operand:DF 1 "reg_or_0_operand" "re,G"))
+ (clobber (match_scratch:SI 2 "=&r,&r"))]
+ "(reload_completed || reload_in_progress)
+ && ! TARGET_PTR64"
+ "*
+{
+ output_asm_insn (\"sethi %%hi(%a0),%2\", operands);
+ if (which_alternative == 0)
+ return \"std %1,[%2+%%lo(%a0)]\";
+ else
+ return \"st %%g0,[%2+%%lo(%a0)]\;st %%g0,[%2+%%lo(%a0+4)]\";
+}"
+ [(set_attr "type" "store")
+ (set_attr "length" "3")])
+
+;; This pattern forces (set (reg:TF ...) (const_double ...))
+;; to be reloaded by putting the constant into memory.
+;; It must come before the more general movtf pattern.
+(define_insn "*movtf_const_insn"
+ [(set (match_operand:TF 0 "general_operand" "=?r,e,o")
+ (match_operand:TF 1 "" "?F,m,G"))]
+ "TARGET_FPU
+ && GET_CODE (operands[1]) == CONST_DOUBLE
+ && (GET_CODE (operands[0]) == REG
+ || fp_zero_operand (operands[1]))"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return output_move_quad (operands);
+ case 1:
+ return output_fp_move_quad (operands);
+ case 2:
+ if (TARGET_ARCH64 || (TARGET_V9 && mem_aligned_8 (operands[0])))
+ {
+ operands[1] = adj_offsettable_operand (operands[0], 8);
+ return \"stx %%g0,%0\;stx %%g0,%1\";
+ }
+ else
+ {
+ /* ??? Do we run off the end of the array here? */
+ operands[1] = adj_offsettable_operand (operands[0], 4);
+ operands[2] = adj_offsettable_operand (operands[0], 8);
+ operands[3] = adj_offsettable_operand (operands[0], 12);
+ return \"st %%g0,%0\;st %%g0,%1\;st %%g0,%2\;st %%g0,%3\";
+ }
+ default:
+ abort ();
+ }
+}"
+ [(set_attr "type" "load,fpload,store")
+ (set_attr "length" "5,5,5")])
+
+(define_expand "movtf"
+ [(set (match_operand:TF 0 "general_operand" "")
+ (match_operand:TF 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (emit_move_sequence (operands, TFmode))
+ DONE;
+}")
+
+(define_insn "*movtf_insn"
+ [(set (match_operand:TF 0 "reg_or_nonsymb_mem_operand" "=e,Q,e,r,Q,r")
+ (match_operand:TF 1 "reg_or_nonsymb_mem_operand" "e,e,Q,r,r,Q"))]
+ "TARGET_FPU
+ && (register_operand (operands[0], TFmode)
+ || register_operand (operands[1], TFmode))"
+ "*
+{
+ if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
+ return output_fp_move_quad (operands);
+ return output_move_quad (operands);
+}"
+ [(set_attr "type" "fp,fpstore,fpload,move,store,load")
+ (set_attr "length" "5,4,4,5,4,4")])
+
+;; Exactly the same as above, except that all `e' cases are deleted.
+;; This is necessary to prevent reload from ever trying to use a `e' reg
+;; when -mno-fpu.
+
+(define_insn "*movtf_no_e_insn"
+ [(set (match_operand:TF 0 "reg_or_nonsymb_mem_operand" "=r,Q,&r")
+ (match_operand:TF 1 "reg_or_nonsymb_mem_operand" "r,r,Q"))]
+ "! TARGET_FPU
+ && (register_operand (operands[0], TFmode)
+ || register_operand (operands[1], TFmode))"
+ "*
+{
+ if (FP_REG_P (operands[0]) || FP_REG_P (operands[1]))
+ return output_fp_move_quad (operands);
+ return output_move_quad (operands);
+}"
+ [(set_attr "type" "move,store,load")
+ (set_attr "length" "4,5,5")])
+
+;; This is disabled because it does not work. Long doubles have only 8
+;; byte alignment. Adding an offset of 8 or 12 to an 8 byte aligned %lo may
+;; cause it to overflow. See also GO_IF_LEGITIMATE_ADDRESS.
+(define_insn "*store_tf"
+ [(set (mem:TF (match_operand:SI 0 "symbolic_operand" "i,i"))
+ (match_operand:TF 1 "reg_or_0_operand" "re,G"))
+ (clobber (match_scratch:SI 2 "=&r,&r"))]
+ "0 && (reload_completed || reload_in_progress)
+ && ! TARGET_PTR64"
+ "*
+{
+ output_asm_insn (\"sethi %%hi(%a0),%2\", operands);
+ if (which_alternative == 0)
+ return \"std %1,[%2+%%lo(%a0)]\;std %S1,[%2+%%lo(%a0+8)]\";
+ else
+ return \"st %%g0,[%2+%%lo(%a0)]\;st %%g0,[%2+%%lo(%a0+4)]\; st %%g0,[%2+%%lo(%a0+8)]\;st %%g0,[%2+%%lo(%a0+12)]\";
+}"
+ [(set_attr "type" "store")
+ (set_attr "length" "5")])
+
+;; Sparc V9 conditional move instructions.
+
+;; We can handle larger constants here for some flavors, but for now we keep
+;; it simple and only allow those constants supported by all flavours.
+;; Note that emit_conditional_move canonicalizes operands 2,3 so that operand
+;; 3 contains the constant if one is present, but we handle either for
+;; generality (sparc.c puts a constant in operand 2).
+
+(define_expand "movqicc"
+ [(set (match_operand:QI 0 "register_operand" "")
+ (if_then_else:QI (match_operand 1 "comparison_operator" "")
+ (match_operand:QI 2 "arith10_operand" "")
+ (match_operand:QI 3 "arith10_operand" "")))]
+ "TARGET_V9"
+ "
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+
+ if (GET_MODE (sparc_compare_op0) == DImode
+ && ! TARGET_ARCH64)
+ FAIL;
+
+ if (sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode
+ && v9_regcmp_p (code))
+ {
+ operands[1] = gen_rtx_fmt_ee (code, DImode,
+ sparc_compare_op0, sparc_compare_op1);
+ }
+ else
+ {
+ rtx cc_reg = gen_compare_reg (code,
+ sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
+ }
+}")
+
+(define_expand "movhicc"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (if_then_else:HI (match_operand 1 "comparison_operator" "")
+ (match_operand:HI 2 "arith10_operand" "")
+ (match_operand:HI 3 "arith10_operand" "")))]
+ "TARGET_V9"
+ "
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+
+ if (GET_MODE (sparc_compare_op0) == DImode
+ && ! TARGET_ARCH64)
+ FAIL;
+
+ if (sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode
+ && v9_regcmp_p (code))
+ {
+ operands[1] = gen_rtx_fmt_ee (code, DImode,
+ sparc_compare_op0, sparc_compare_op1);
+ }
+ else
+ {
+ rtx cc_reg = gen_compare_reg (code,
+ sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
+ }
+}")
+
+(define_expand "movsicc"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (if_then_else:SI (match_operand 1 "comparison_operator" "")
+ (match_operand:SI 2 "arith10_operand" "")
+ (match_operand:SI 3 "arith10_operand" "")))]
+ "TARGET_V9"
+ "
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+ enum machine_mode op0_mode = GET_MODE (sparc_compare_op0);
+
+ if (sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && ((TARGET_ARCH64 && op0_mode == DImode && v9_regcmp_p (code))
+ || (op0_mode == SImode && v8plus_regcmp_p (code))))
+ {
+ operands[1] = gen_rtx_fmt_ee (code, op0_mode,
+ sparc_compare_op0, sparc_compare_op1);
+ }
+ else
+ {
+ rtx cc_reg = gen_compare_reg (code,
+ sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg),
+ cc_reg, const0_rtx);
+ }
+}")
+
+(define_expand "movdicc"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (if_then_else:DI (match_operand 1 "comparison_operator" "")
+ (match_operand:DI 2 "arith10_double_operand" "")
+ (match_operand:DI 3 "arith10_double_operand" "")))]
+ "TARGET_ARCH64"
+ "
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+
+ if (sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode
+ && v9_regcmp_p (code))
+ {
+ operands[1] = gen_rtx_fmt_ee (code, DImode,
+ sparc_compare_op0, sparc_compare_op1);
+ }
+ else
+ {
+ rtx cc_reg = gen_compare_reg (code,
+ sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg),
+ cc_reg, const0_rtx);
+ }
+}")
+
+(define_expand "movsfcc"
+ [(set (match_operand:SF 0 "register_operand" "")
+ (if_then_else:SF (match_operand 1 "comparison_operator" "")
+ (match_operand:SF 2 "register_operand" "")
+ (match_operand:SF 3 "register_operand" "")))]
+ "TARGET_V9 && TARGET_FPU"
+ "
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+
+ if (GET_MODE (sparc_compare_op0) == DImode
+ && ! TARGET_ARCH64)
+ FAIL;
+
+ if (sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode
+ && v9_regcmp_p (code))
+ {
+ operands[1] = gen_rtx_fmt_ee (code, DImode,
+ sparc_compare_op0, sparc_compare_op1);
+ }
+ else
+ {
+ rtx cc_reg = gen_compare_reg (code,
+ sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
+ }
+}")
+
+(define_expand "movdfcc"
+ [(set (match_operand:DF 0 "register_operand" "")
+ (if_then_else:DF (match_operand 1 "comparison_operator" "")
+ (match_operand:DF 2 "register_operand" "")
+ (match_operand:DF 3 "register_operand" "")))]
+ "TARGET_V9 && TARGET_FPU"
+ "
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+
+ if (GET_MODE (sparc_compare_op0) == DImode
+ && ! TARGET_ARCH64)
+ FAIL;
+
+ if (sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode
+ && v9_regcmp_p (code))
+ {
+ operands[1] = gen_rtx_fmt_ee (code, DImode,
+ sparc_compare_op0, sparc_compare_op1);
+ }
+ else
+ {
+ rtx cc_reg = gen_compare_reg (code,
+ sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
+ }
+}")
+
+(define_expand "movtfcc"
+ [(set (match_operand:TF 0 "register_operand" "")
+ (if_then_else:TF (match_operand 1 "comparison_operator" "")
+ (match_operand:TF 2 "register_operand" "")
+ (match_operand:TF 3 "register_operand" "")))]
+ "TARGET_V9 && TARGET_FPU"
+ "
+{
+ enum rtx_code code = GET_CODE (operands[1]);
+
+ if (GET_MODE (sparc_compare_op0) == DImode
+ && ! TARGET_ARCH64)
+ FAIL;
+
+ if (sparc_compare_op1 == const0_rtx
+ && GET_CODE (sparc_compare_op0) == REG
+ && GET_MODE (sparc_compare_op0) == DImode
+ && v9_regcmp_p (code))
+ {
+ operands[1] = gen_rtx_fmt_ee (code, DImode,
+ sparc_compare_op0, sparc_compare_op1);
+ }
+ else
+ {
+ rtx cc_reg = gen_compare_reg (code,
+ sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
+ }
+}")
+
+;; Conditional move define_insns.
+
+(define_insn "*movqi_cc_sp64"
+ [(set (match_operand:QI 0 "register_operand" "=r,r")
+ (if_then_else:QI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ (const_int 0)])
+ (match_operand:QI 3 "arith11_operand" "rL,0")
+ (match_operand:QI 4 "arith11_operand" "0,rL")))]
+ "TARGET_V9"
+ "@
+ mov%C1 %x2,%3,%0
+ mov%c1 %x2,%4,%0"
+ [(set_attr "type" "cmove")])
+
+(define_insn "*movhi_cc_sp64"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (if_then_else:HI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ (const_int 0)])
+ (match_operand:HI 3 "arith11_operand" "rL,0")
+ (match_operand:HI 4 "arith11_operand" "0,rL")))]
+ "TARGET_V9"
+ "@
+ mov%C1 %x2,%3,%0
+ mov%c1 %x2,%4,%0"
+ [(set_attr "type" "cmove")])
+
+(define_insn "*movsi_cc_sp64"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ (const_int 0)])
+ (match_operand:SI 3 "arith11_operand" "rL,0")
+ (match_operand:SI 4 "arith11_operand" "0,rL")))]
+ "TARGET_V9"
+ "@
+ mov%C1 %x2,%3,%0
+ mov%c1 %x2,%4,%0"
+ [(set_attr "type" "cmove")])
+
+;; ??? The constraints of operands 3,4 need work.
+(define_insn "*movdi_cc_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (if_then_else:DI (match_operator 1 "comparison_operator"
+ [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ (const_int 0)])
+ (match_operand:DI 3 "arith11_double_operand" "rLH,0")
+ (match_operand:DI 4 "arith11_double_operand" "0,rLH")))]
+ "TARGET_ARCH64"
+ "@
+ mov%C1 %x2,%3,%0
+ mov%c1 %x2,%4,%0"
+ [(set_attr "type" "cmove")])
+
+(define_insn "*movsf_cc_sp64"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (if_then_else:SF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ (const_int 0)])
+ (match_operand:SF 3 "register_operand" "f,0")
+ (match_operand:SF 4 "register_operand" "0,f")))]
+ "TARGET_V9 && TARGET_FPU"
+ "@
+ fmovs%C1 %x2,%3,%0
+ fmovs%c1 %x2,%4,%0"
+ [(set_attr "type" "fpcmove")])
+
+(define_insn "*movdf_cc_sp64"
+ [(set (match_operand:DF 0 "register_operand" "=e,e")
+ (if_then_else:DF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ (const_int 0)])
+ (match_operand:DF 3 "register_operand" "e,0")
+ (match_operand:DF 4 "register_operand" "0,e")))]
+ "TARGET_V9 && TARGET_FPU"
+ "@
+ fmovd%C1 %x2,%3,%0
+ fmovd%c1 %x2,%4,%0"
+ [(set_attr "type" "fpcmove")])
+
+(define_insn "*movtf_cc_sp64"
+ [(set (match_operand:TF 0 "register_operand" "=e,e")
+ (if_then_else:TF (match_operator 1 "comparison_operator"
+ [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ (const_int 0)])
+ (match_operand:TF 3 "register_operand" "e,0")
+ (match_operand:TF 4 "register_operand" "0,e")))]
+ "TARGET_V9 && TARGET_FPU && TARGET_HARD_QUAD"
+ "@
+ fmovq%C1 %x2,%3,%0
+ fmovq%c1 %x2,%4,%0"
+ [(set_attr "type" "fpcmove")])
+
+(define_insn "*movqi_cc_reg_sp64"
+ [(set (match_operand:QI 0 "register_operand" "=r,r")
+ (if_then_else:QI (match_operator 1 "v9_regcmp_op"
+ [(match_operand:DI 2 "register_operand" "r,r")
+ (const_int 0)])
+ (match_operand:QI 3 "arith10_operand" "rM,0")
+ (match_operand:QI 4 "arith10_operand" "0,rM")))]
+ "TARGET_ARCH64"
+ "@
+ movr%D1 %2,%r3,%0
+ movr%d1 %2,%r4,%0"
+ [(set_attr "type" "cmove")])
+
+(define_insn "*movhi_cc_reg_sp64"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (if_then_else:HI (match_operator 1 "v9_regcmp_op"
+ [(match_operand:DI 2 "register_operand" "r,r")
+ (const_int 0)])
+ (match_operand:HI 3 "arith10_operand" "rM,0")
+ (match_operand:HI 4 "arith10_operand" "0,rM")))]
+ "TARGET_ARCH64"
+ "@
+ movr%D1 %2,%r3,%0
+ movr%d1 %2,%r4,%0"
+ [(set_attr "type" "cmove")])
+
+(define_insn "*movsi_cc_reg_sp64"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI (match_operator 1 "v9_regcmp_op"
+ [(match_operand:DI 2 "register_operand" "r,r")
+ (const_int 0)])
+ (match_operand:SI 3 "arith10_operand" "rM,0")
+ (match_operand:SI 4 "arith10_operand" "0,rM")))]
+ "TARGET_ARCH64"
+ "@
+ movr%D1 %2,%r3,%0
+ movr%d1 %2,%r4,%0"
+ [(set_attr "type" "cmove")])
+
+;; On UltraSPARC this is slightly worse than cmp/mov %icc if the register
+;; needs to be zero extended but better on average.
+(define_insn "*movsi_cc_reg_v8plus"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI (match_operator 1 "v8plus_regcmp_op"
+ [(match_operand:SI 2 "register_operand" "r,r")
+ (const_int 0)])
+ (match_operand:SI 3 "arith10_operand" "rM,0")
+ (match_operand:SI 4 "arith10_operand" "0,rM")))]
+ "TARGET_V9"
+ "*
+{
+ if (! sparc_check_64 (operands[2], insn))
+ output_asm_insn (\"srl %2,0,%2\", operands);
+ if (which_alternative == 0)
+ return \"movr%D1 %2,%r3,%0\";
+ return \"movr%d1 %2,%r4,%0\";
+}"
+ [(set_attr "type" "cmove")
+ (set_attr "length" "2")])
+
+;; To work well this needs to know the current insn, but that is not an
+;; argument to gen_split_*.
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (if_then_else:SI (match_operator 1 "v8plus_regcmp_op"
+ [(match_operand:SI 2 "register_operand" "r,r")
+ (const_int 0)])
+ (match_operand:SI 3 "arith10_operand" "rM,0")
+ (match_operand:SI 4 "arith10_operand" "0,rM")))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (unspec:SI [(match_dup 1) (match_dup 3) (match_dup 4)] 9))]
+ "if (! sparc_check_64 (operands[2], NULL_RTX))
+ emit_insn (gen_v8plus_clear_high (operands[2], operands[2]));")
+
+;; A conditional move with the condition argument known to be zero extended
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (unspec:SI [(match_operator 1 "v8plus_regcmp_op"
+ [(match_operand:SI 2 "register_operand" "r,r")
+ (const_int 0)])
+ (match_operand:SI 3 "arith10_operand" "rM,0")
+ (match_operand:SI 4 "arith10_operand" "0,rM")] 9))]
+ "TARGET_V9"
+ "@
+ movr%D1 %2,%r3,%0
+ movr%d1 %2,%r4,%0"
+ [(set_attr "type" "cmove")])
+
+;; ??? The constraints of operands 3,4 need work.
+(define_insn "*movdi_cc_reg_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (if_then_else:DI (match_operator 1 "v9_regcmp_op"
+ [(match_operand:DI 2 "register_operand" "r,r")
+ (const_int 0)])
+ (match_operand:DI 3 "arith10_double_operand" "rMH,0")
+ (match_operand:DI 4 "arith10_double_operand" "0,rMH")))]
+ "TARGET_ARCH64"
+ "@
+ movr%D1 %2,%r3,%0
+ movr%d1 %2,%r4,%0"
+ [(set_attr "type" "cmove")])
+
+(define_insn "*movsf_cc_reg_sp64"
+ [(set (match_operand:SF 0 "register_operand" "=f,f")
+ (if_then_else:SF (match_operator 1 "v9_regcmp_op"
+ [(match_operand:DI 2 "register_operand" "r,r")
+ (const_int 0)])
+ (match_operand:SF 3 "register_operand" "f,0")
+ (match_operand:SF 4 "register_operand" "0,f")))]
+ "TARGET_ARCH64 && TARGET_FPU"
+ "@
+ fmovrs%D1 %2,%3,%0
+ fmovrs%d1 %2,%4,%0"
+ [(set_attr "type" "fpcmove")])
+
+(define_insn "*movdf_cc_reg_sp64"
+ [(set (match_operand:DF 0 "register_operand" "=e,e")
+ (if_then_else:DF (match_operator 1 "v9_regcmp_op"
+ [(match_operand:DI 2 "register_operand" "r,r")
+ (const_int 0)])
+ (match_operand:DF 3 "register_operand" "e,0")
+ (match_operand:DF 4 "register_operand" "0,e")))]
+ "TARGET_ARCH64 && TARGET_FPU"
+ "@
+ fmovrd%D1 %2,%3,%0
+ fmovrd%d1 %2,%4,%0"
+ [(set_attr "type" "fpcmove")])
+
+(define_insn "*movtf_cc_reg_sp64"
+ [(set (match_operand:TF 0 "register_operand" "=e,e")
+ (if_then_else:TF (match_operator 1 "v9_regcmp_op"
+ [(match_operand:DI 2 "register_operand" "r,r")
+ (const_int 0)])
+ (match_operand:TF 3 "register_operand" "e,0")
+ (match_operand:TF 4 "register_operand" "0,e")))]
+ "TARGET_ARCH64 && TARGET_FPU"
+ "@
+ fmovrq%D1 %2,%3,%0
+ fmovrq%d1 %2,%4,%0"
+ [(set_attr "type" "fpcmove")])
+
+;;- zero extension instructions
+
+;; These patterns originally accepted general_operands, however, slightly
+;; better code is generated by only accepting register_operands, and then
+;; letting combine generate the ldu[hb] insns.
+
+(define_expand "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:HI 1 "register_operand" "")))]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx (SImode);
+ rtx shift_16 = GEN_INT (16);
+ int op1_subword = 0;
+
+ if (GET_CODE (operand1) == SUBREG)
+ {
+ op1_subword = SUBREG_WORD (operand1);
+ operand1 = XEXP (operand1, 0);
+ }
+
+ emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1,
+ op1_subword),
+ shift_16));
+ emit_insn (gen_lshrsi3 (operand0, temp, shift_16));
+ DONE;
+}")
+
+(define_insn "*zero_extendhisi2_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+ ""
+ "lduh %1,%0"
+ [(set_attr "type" "load")])
+
+(define_expand "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (zero_extend:HI (match_operand:QI 1 "register_operand" "")))]
+ ""
+ "")
+
+(define_insn "*zero_extendqihi2_insn"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (zero_extend:HI (match_operand:QI 1 "sparc_operand" "r,Q")))]
+ "GET_CODE (operands[1]) != CONST_INT"
+ "@
+ and %1,0xff,%0
+ ldub %1,%0"
+ [(set_attr "type" "unary,load")
+ (set_attr "length" "1")])
+
+(define_expand "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (zero_extend:SI (match_operand:QI 1 "register_operand" "")))]
+ ""
+ "")
+
+(define_insn "*zero_extendqisi2_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI (match_operand:QI 1 "sparc_operand" "r,Q")))]
+ "GET_CODE (operands[1]) != CONST_INT"
+ "@
+ and %1,0xff,%0
+ ldub %1,%0"
+ [(set_attr "type" "unary,load")
+ (set_attr "length" "1")])
+
+(define_expand "zero_extendqidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI (match_operand:QI 1 "register_operand" "")))]
+ "TARGET_ARCH64"
+ "")
+
+(define_insn "*zero_extendqidi2_insn"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (zero_extend:DI (match_operand:QI 1 "sparc_operand" "r,Q")))]
+ "TARGET_ARCH64 && GET_CODE (operands[1]) != CONST_INT"
+ "@
+ and %1,0xff,%0
+ ldub %1,%0"
+ [(set_attr "type" "unary,load")
+ (set_attr "length" "1")])
+
+(define_expand "zero_extendhidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI (match_operand:HI 1 "register_operand" "")))]
+ "TARGET_ARCH64"
+ "
+{
+ rtx temp = gen_reg_rtx (DImode);
+ rtx shift_48 = GEN_INT (48);
+ int op1_subword = 0;
+
+ if (GET_CODE (operand1) == SUBREG)
+ {
+ op1_subword = SUBREG_WORD (operand1);
+ operand1 = XEXP (operand1, 0);
+ }
+
+ emit_insn (gen_ashldi3 (temp, gen_rtx_SUBREG (DImode, operand1,
+ op1_subword),
+ shift_48));
+ emit_insn (gen_lshrdi3 (operand0, temp, shift_48));
+ DONE;
+}")
+
+(define_insn "*zero_extendhidi2_insn"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (match_operand:HI 1 "memory_operand" "m")))]
+ "TARGET_ARCH64"
+ "lduh %1,%0"
+ [(set_attr "type" "load")])
+
+
+;; ??? Write truncdisi pattern using sra?
+
+(define_expand "zero_extendsidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (zero_extend:DI (match_operand:SI 1 "register_operand" "")))]
+ "TARGET_ARCH64"
+ "")
+
+(define_insn "*zero_extendsidi2_insn"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (zero_extend:DI (match_operand:SI 1 "sparc_operand" "r,Q")))]
+ "TARGET_ARCH64 && GET_CODE (operands[1]) != CONST_INT"
+ "@
+ srl %1,0,%0
+ lduw %1,%0"
+ [(set_attr "type" "unary,load")
+ (set_attr "length" "1")])
+
+;; Zero extend a 32 bit value in a 64 bit register.
+(define_insn "v8plus_clear_high"
+ [(set (match_operand:SI 0 "reg_or_nonsymb_mem_operand" "=r,Q")
+ (unspec:SI [(match_operand:SI 1 "register_operand" "r,r")] 10))]
+ "TARGET_V9"
+ "*
+if (which_alternative == 1)
+ return \"st %1,%0\";
+if (sparc_check_64 (operands[1], insn) > 0)
+ return final_sequence ? \"nop\" : \"\";
+return \"srl %1,0,%0\";
+"
+ [(set_attr "type" "shift,store")])
+
+;; Simplify comparisons of extended values.
+
+(define_insn "*cmp_zero_extendqisi2"
+ [(set (reg:CC 100)
+ (compare:CC (zero_extend:SI (match_operand:QI 0 "register_operand" "r"))
+ (const_int 0)))]
+ ""
+ "andcc %0,0xff,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_zero_extendqisi2_set"
+ [(set (reg:CC 100)
+ (compare:CC (zero_extend:SI (match_operand:QI 1 "register_operand" "r"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_dup 1)))]
+ ""
+ "andcc %1,0xff,%0"
+ [(set_attr "type" "unary")])
+
+;; Similarly, handle SI->QI mode truncation followed by a compare.
+
+(define_insn "*cmp_siqi_trunc"
+ [(set (reg:CC 100)
+ (compare:CC (subreg:QI (match_operand:SI 0 "register_operand" "r") 0)
+ (const_int 0)))]
+ ""
+ "andcc %0,0xff,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_siqi_trunc_set"
+ [(set (reg:CC 100)
+ (compare:CC (subreg:QI (match_operand:SI 1 "register_operand" "r") 0)
+ (const_int 0)))
+ (set (match_operand:QI 0 "register_operand" "=r")
+ (match_dup 1))]
+ ""
+ "andcc %1,0xff,%0"
+ [(set_attr "type" "unary")])
+
+;;- sign extension instructions
+
+;; These patterns originally accepted general_operands, however, slightly
+;; better code is generated by only accepting register_operands, and then
+;; letting combine generate the lds[hb] insns.
+
+(define_expand "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "")))]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx (SImode);
+ rtx shift_16 = GEN_INT (16);
+ int op1_subword = 0;
+
+ if (GET_CODE (operand1) == SUBREG)
+ {
+ op1_subword = SUBREG_WORD (operand1);
+ operand1 = XEXP (operand1, 0);
+ }
+
+ emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1,
+ op1_subword),
+ shift_16));
+ emit_insn (gen_ashrsi3 (operand0, temp, shift_16));
+ DONE;
+}")
+
+(define_insn "*sign_extendhisi2_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+ ""
+ "ldsh %1,%0"
+ [(set_attr "type" "sload")])
+
+(define_expand "extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "")))]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx (SImode);
+ rtx shift_24 = GEN_INT (24);
+ int op1_subword = 0;
+ int op0_subword = 0;
+
+ if (GET_CODE (operand1) == SUBREG)
+ {
+ op1_subword = SUBREG_WORD (operand1);
+ operand1 = XEXP (operand1, 0);
+ }
+ if (GET_CODE (operand0) == SUBREG)
+ {
+ op0_subword = SUBREG_WORD (operand0);
+ operand0 = XEXP (operand0, 0);
+ }
+ emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1,
+ op1_subword),
+ shift_24));
+ if (GET_MODE (operand0) != SImode)
+ operand0 = gen_rtx_SUBREG (SImode, operand0, op0_subword);
+ emit_insn (gen_ashrsi3 (operand0, temp, shift_24));
+ DONE;
+}")
+
+(define_insn "*sign_extendqihi2_insn"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
+ ""
+ "ldsb %1,%0"
+ [(set_attr "type" "sload")])
+
+(define_expand "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "")))]
+ ""
+ "
+{
+ rtx temp = gen_reg_rtx (SImode);
+ rtx shift_24 = GEN_INT (24);
+ int op1_subword = 0;
+
+ if (GET_CODE (operand1) == SUBREG)
+ {
+ op1_subword = SUBREG_WORD (operand1);
+ operand1 = XEXP (operand1, 0);
+ }
+
+ emit_insn (gen_ashlsi3 (temp, gen_rtx_SUBREG (SImode, operand1,
+ op1_subword),
+ shift_24));
+ emit_insn (gen_ashrsi3 (operand0, temp, shift_24));
+ DONE;
+}")
+
+(define_insn "*sign_extendqisi2_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+ ""
+ "ldsb %1,%0"
+ [(set_attr "type" "sload")])
+
+(define_expand "extendqidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (sign_extend:DI (match_operand:QI 1 "register_operand" "")))]
+ "TARGET_ARCH64"
+ "
+{
+ rtx temp = gen_reg_rtx (DImode);
+ rtx shift_56 = GEN_INT (56);
+ int op1_subword = 0;
+
+ if (GET_CODE (operand1) == SUBREG)
+ {
+ op1_subword = SUBREG_WORD (operand1);
+ operand1 = XEXP (operand1, 0);
+ }
+
+ emit_insn (gen_ashldi3 (temp, gen_rtx_SUBREG (DImode, operand1,
+ op1_subword),
+ shift_56));
+ emit_insn (gen_ashrdi3 (operand0, temp, shift_56));
+ DONE;
+}")
+
+(define_insn "*sign_extendqidi2_insn"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (match_operand:QI 1 "memory_operand" "m")))]
+ "TARGET_ARCH64"
+ "ldsb %1,%0"
+ [(set_attr "type" "sload")])
+
+(define_expand "extendhidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (sign_extend:DI (match_operand:HI 1 "register_operand" "")))]
+ "TARGET_ARCH64"
+ "
+{
+ rtx temp = gen_reg_rtx (DImode);
+ rtx shift_48 = GEN_INT (48);
+ int op1_subword = 0;
+
+ if (GET_CODE (operand1) == SUBREG)
+ {
+ op1_subword = SUBREG_WORD (operand1);
+ operand1 = XEXP (operand1, 0);
+ }
+
+ emit_insn (gen_ashldi3 (temp, gen_rtx_SUBREG (DImode, operand1,
+ op1_subword),
+ shift_48));
+ emit_insn (gen_ashrdi3 (operand0, temp, shift_48));
+ DONE;
+}")
+
+(define_insn "*sign_extendhidi2_insn"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (sign_extend:DI (match_operand:HI 1 "memory_operand" "m")))]
+ "TARGET_ARCH64"
+ "ldsh %1,%0"
+ [(set_attr "type" "load")])
+
+(define_expand "extendsidi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (sign_extend:DI (match_operand:SI 1 "register_operand" "")))]
+ "TARGET_ARCH64"
+ "")
+
+(define_insn "*sign_extendsidi2_insn"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (sign_extend:DI (match_operand:SI 1 "sparc_operand" "r,Q")))]
+ "TARGET_ARCH64"
+ "@
+ sra %1,0,%0
+ ldsw %1,%0"
+ [(set_attr "type" "unary,sload")
+ (set_attr "length" "1")])
+
+;; Special pattern for optimizing bit-field compares. This is needed
+;; because combine uses this as a canonical form.
+
+(define_insn "*cmp_zero_extract"
+ [(set (reg:CC 100)
+ (compare:CC
+ (zero_extract:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "small_int" "n")
+ (match_operand:SI 2 "small_int" "n"))
+ (const_int 0)))]
+ "INTVAL (operands[2]) > 19"
+ "*
+{
+ int len = INTVAL (operands[1]);
+ int pos = 32 - INTVAL (operands[2]) - len;
+ unsigned mask = ((1 << len) - 1) << pos;
+
+ operands[1] = GEN_INT (mask);
+ return \"andcc %0,%1,%%g0\";
+}")
+
+(define_insn "*cmp_zero_extract_sp64"
+ [(set (reg:CCX 100)
+ (compare:CCX
+ (zero_extract:DI (match_operand:DI 0 "register_operand" "r")
+ (match_operand:SI 1 "small_int" "n")
+ (match_operand:SI 2 "small_int" "n"))
+ (const_int 0)))]
+ "TARGET_ARCH64 && INTVAL (operands[2]) > 51"
+ "*
+{
+ int len = INTVAL (operands[1]);
+ int pos = 64 - INTVAL (operands[2]) - len;
+ unsigned HOST_WIDE_INT mask = (((unsigned HOST_WIDE_INT) 1 << len) - 1) << pos;
+
+ operands[1] = GEN_INT (mask);
+ return \"andcc %0,%1,%%g0\";
+}")
+
+;; Conversions between float, double and long double.
+
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "register_operand" "=e")
+ (float_extend:DF
+ (match_operand:SF 1 "register_operand" "f")))]
+ "TARGET_FPU"
+ "fstod %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "extendsftf2"
+ [(set (match_operand:TF 0 "register_operand" "=e")
+ (float_extend:TF
+ (match_operand:SF 1 "register_operand" "f")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "fstoq %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "extenddftf2"
+ [(set (match_operand:TF 0 "register_operand" "=e")
+ (float_extend:TF
+ (match_operand:DF 1 "register_operand" "e")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "fdtoq %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "truncdfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float_truncate:SF
+ (match_operand:DF 1 "register_operand" "e")))]
+ "TARGET_FPU"
+ "fdtos %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "trunctfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float_truncate:SF
+ (match_operand:TF 1 "register_operand" "e")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "fqtos %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "trunctfdf2"
+ [(set (match_operand:DF 0 "register_operand" "=e")
+ (float_truncate:DF
+ (match_operand:TF 1 "register_operand" "e")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "fqtod %1,%0"
+ [(set_attr "type" "fp")])
+
+;; Conversion between fixed point and floating point.
+
+(define_insn "floatsisf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float:SF (match_operand:SI 1 "register_operand" "f")))]
+ "TARGET_FPU"
+ "fitos %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "floatsidf2"
+ [(set (match_operand:DF 0 "register_operand" "=e")
+ (float:DF (match_operand:SI 1 "register_operand" "f")))]
+ "TARGET_FPU"
+ "fitod %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "floatsitf2"
+ [(set (match_operand:TF 0 "register_operand" "=e")
+ (float:TF (match_operand:SI 1 "register_operand" "f")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "fitoq %1,%0"
+ [(set_attr "type" "fp")])
+
+;; Now the same for 64 bit sources.
+
+(define_insn "floatdisf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (float:SF (match_operand:DI 1 "register_operand" "e")))]
+ "TARGET_V9 && TARGET_FPU"
+ "fxtos %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "floatdidf2"
+ [(set (match_operand:DF 0 "register_operand" "=e")
+ (float:DF (match_operand:DI 1 "register_operand" "e")))]
+ "TARGET_V9 && TARGET_FPU"
+ "fxtod %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "floatditf2"
+ [(set (match_operand:TF 0 "register_operand" "=e")
+ (float:TF (match_operand:DI 1 "register_operand" "e")))]
+ "TARGET_V9 && TARGET_FPU && TARGET_HARD_QUAD"
+ "fxtoq %1,%0"
+ [(set_attr "type" "fp")])
+
+;; Convert a float to an actual integer.
+;; Truncation is performed as part of the conversion.
+
+(define_insn "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))]
+ "TARGET_FPU"
+ "fstoi %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "fix_truncdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "e"))))]
+ "TARGET_FPU"
+ "fdtoi %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "fix_trunctfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=f")
+ (fix:SI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "fqtoi %1,%0"
+ [(set_attr "type" "fp")])
+
+;; Now the same, for V9 targets
+
+(define_insn "fix_truncsfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=e")
+ (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))]
+ "TARGET_V9 && TARGET_FPU"
+ "fstox %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "fix_truncdfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=e")
+ (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "e"))))]
+ "TARGET_V9 && TARGET_FPU"
+ "fdtox %1,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "fix_trunctfdi2"
+ [(set (match_operand:DI 0 "register_operand" "=e")
+ (fix:DI (fix:TF (match_operand:TF 1 "register_operand" "e"))))]
+ "TARGET_V9 && TARGET_FPU && TARGET_HARD_QUAD"
+ "fqtox %1,%0"
+ [(set_attr "type" "fp")])
+
+;;- arithmetic instructions
+
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "arith_double_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ ""
+ "
+{
+ if (! TARGET_ARCH64)
+ {
+ emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
+ gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_PLUS (DImode, operands[1],
+ operands[2])),
+ gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_REG (CCmode, SPARC_ICC_REG)))));
+ DONE;
+ }
+}")
+
+(define_insn "*adddi3_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "arith_double_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))
+ (clobber (reg:CC 100))]
+ "! TARGET_ARCH64"
+ "*
+{
+ rtx op2 = operands[2];
+
+ if (GET_CODE (op2) == CONST_INT
+ || GET_CODE (op2) == CONST_DOUBLE)
+ {
+ rtx xoperands[4];
+ xoperands[0] = operands[0];
+ xoperands[1] = operands[1];
+ if (WORDS_BIG_ENDIAN)
+ split_double (op2, &xoperands[2], &xoperands[3]);
+ else
+ split_double (op2, &xoperands[3], &xoperands[2]);
+ if (xoperands[3] == const0_rtx && xoperands[0] == xoperands[1])
+ output_asm_insn (\"add %H1,%2,%H0\", xoperands);
+ else
+ output_asm_insn (\"addcc %L1,%3,%L0\;addx %H1,%2,%H0\", xoperands);
+ return \"\";
+ }
+ return \"addcc %L1,%L2,%L0\;addx %H1,%H2,%H0\";
+}"
+ [(set_attr "length" "2")])
+
+
+;; Split DImode arithmetic
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "arith_double_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))
+ (clobber (reg:CC 100))]
+ "! TARGET_ARCH64 && reload_completed"
+ [(parallel [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (plus:SI (match_dup 4)
+ (match_dup 5))
+ (const_int 0)))
+ (set (match_dup 3)
+ (plus:SI (match_dup 4) (match_dup 5)))])
+ (set (match_dup 6)
+ (plus:SI (plus:SI (match_dup 7)
+ (match_dup 8))
+ (ltu:SI (reg:CC_NOOV 100) (const_int 0))))]
+ "
+{
+ operands[3] = gen_lowpart (SImode, operands[0]);
+ operands[4] = gen_lowpart (SImode, operands[1]);
+ operands[5] = gen_lowpart (SImode, operands[2]);
+ operands[6] = gen_highpart (SImode, operands[0]);
+ operands[7] = gen_highpart (SImode, operands[1]);
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ if (INTVAL (operands[2]) < 0)
+ operands[8] = constm1_rtx;
+ else
+ operands[8] = const0_rtx;
+ }
+ else
+ operands[8] = gen_highpart (SImode, operands[2]);
+}")
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_operand:DI 1 "arith_double_operand" "r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))
+ (clobber (reg:CC 100))]
+ "! TARGET_ARCH64 && reload_completed"
+ [(parallel [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (minus:SI (match_dup 4)
+ (match_dup 5))
+ (const_int 0)))
+ (set (match_dup 3)
+ (minus:SI (match_dup 4) (match_dup 5)))])
+ (set (match_dup 6)
+ (minus:SI (minus:SI (match_dup 7)
+ (match_dup 8))
+ (ltu:SI (reg:CC_NOOV 100) (const_int 0))))]
+ "
+{
+ operands[3] = gen_lowpart (SImode, operands[0]);
+ operands[4] = gen_lowpart (SImode, operands[1]);
+ operands[5] = gen_lowpart (SImode, operands[2]);
+ operands[6] = gen_highpart (SImode, operands[0]);
+ operands[7] = gen_highpart (SImode, operands[1]);
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ if (INTVAL (operands[2]) < 0)
+ operands[8] = constm1_rtx;
+ else
+ operands[8] = const0_rtx;
+ }
+ else
+ operands[8] = gen_highpart (SImode, operands[2]);
+}")
+
+;; LTU here means "carry set"
+(define_insn "*addx"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (plus:SI (match_operand:SI 1 "arith_operand" "%r")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (ltu:SI (reg:CC_NOOV 100) (const_int 0))))]
+ ""
+ "addx %1,%2,%0"
+ [(set_attr "type" "unary")])
+
+(define_insn "*subx"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (ltu:SI (reg:CC_NOOV 100) (const_int 0))))]
+ ""
+ "subx %1,%2,%0"
+ [(set_attr "type" "unary")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:DI 2 "register_operand" "r")))
+ (clobber (reg:CC 100))]
+ "! TARGET_ARCH64"
+ "addcc %L2,%1,%L0\;addx %H2,0,%H0"
+ [(set_attr "type" "multi")])
+
+(define_insn "*adddi3_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_operand:DI 1 "arith_double_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64"
+ "add %1,%2,%0")
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (plus:SI (match_operand:SI 1 "arith_operand" "%r,d")
+ (match_operand:SI 2 "arith_operand" "rI,d")))]
+ ""
+ "@
+ add %1,%2,%0
+ fpadd32s %1,%2,%0"
+ [(set_attr "type" "ialu,fp")])
+
+(define_insn "*cmp_cc_plus"
+ [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (plus:SI (match_operand:SI 0 "arith_operand" "%r")
+ (match_operand:SI 1 "arith_operand" "rI"))
+ (const_int 0)))]
+ ""
+ "addcc %0,%1,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccx_plus"
+ [(set (reg:CCX_NOOV 100)
+ (compare:CCX_NOOV (plus:DI (match_operand:DI 0 "arith_double_operand" "%r")
+ (match_operand:DI 1 "arith_double_operand" "rHI"))
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "addcc %0,%1,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_cc_plus_set"
+ [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (plus:SI (match_operand:SI 1 "arith_operand" "%r")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "addcc %1,%2,%0")
+
+(define_insn "*cmp_ccx_plus_set"
+ [(set (reg:CCX_NOOV 100)
+ (compare:CCX_NOOV (plus:DI (match_operand:DI 1 "arith_double_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_ARCH64"
+ "addcc %1,%2,%0")
+
+(define_expand "subdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ ""
+ "
+{
+ if (! TARGET_ARCH64)
+ {
+ emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
+ gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_MINUS (DImode, operands[1],
+ operands[2])),
+ gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_REG (CCmode, SPARC_ICC_REG)))));
+ DONE;
+ }
+}")
+
+(define_insn "*subdi3_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))
+ (clobber (reg:CC 100))]
+ "! TARGET_ARCH64"
+ "*
+{
+ rtx op2 = operands[2];
+
+ if (GET_CODE (op2) == CONST_INT
+ || GET_CODE (op2) == CONST_DOUBLE)
+ {
+ rtx xoperands[4];
+ xoperands[0] = operands[0];
+ xoperands[1] = operands[1];
+ if (WORDS_BIG_ENDIAN)
+ split_double (op2, &xoperands[2], &xoperands[3]);
+ else
+ split_double (op2, &xoperands[3], &xoperands[2]);
+ if (xoperands[3] == const0_rtx && xoperands[0] == xoperands[1])
+ output_asm_insn (\"sub %H1,%2,%H0\", xoperands);
+ else
+ output_asm_insn (\"subcc %L1,%3,%L0\;subx %H1,%2,%H0\", xoperands);
+ return \"\";
+ }
+ return \"subcc %L1,%L2,%L0\;subx %H1,%H2,%H0\";
+}"
+ [(set_attr "length" "2")])
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))
+ (clobber (reg:CC 100))]
+ "! TARGET_ARCH64"
+ "subcc %L1,%2,%L0\;addx %H1,0,%H0"
+ [(set_attr "type" "multi")])
+
+(define_insn "*subdi3_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64"
+ "sub %1,%2,%0")
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (minus:SI (match_operand:SI 1 "register_operand" "r,d")
+ (match_operand:SI 2 "arith_operand" "rI,d")))]
+ ""
+ "@
+ sub %1,%2,%0
+ fpsub32s %1,%2,%0"
+ [(set_attr "type" "ialu,fp")])
+
+(define_insn "*cmp_minus_cc"
+ [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (minus:SI (match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "arith_operand" "rI"))
+ (const_int 0)))]
+ ""
+ "subcc %0,%1,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_minus_ccx"
+ [(set (reg:CCX_NOOV 100)
+ (compare:CCX_NOOV (minus:DI (match_operand:DI 0 "register_operand" "r")
+ (match_operand:DI 1 "arith_double_operand" "rHI"))
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "subcc %0,%1,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_minus_cc_set"
+ [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (minus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_dup 1) (match_dup 2)))]
+ ""
+ "subcc %1,%2,%0")
+
+(define_insn "*cmp_minus_ccx_set"
+ [(set (reg:CCX_NOOV 100)
+ (compare:CCX_NOOV (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "arith_double_operand" "rHI"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (minus:DI (match_dup 1) (match_dup 2)))]
+ "TARGET_ARCH64"
+ "subcc %1,%2,%0")
+
+;; Integer Multiply/Divide.
+
+;; The 32 bit multiply/divide instructions are deprecated on v9 and shouldn't
+;; we used. We still use them in 32 bit v9 compilers.
+;; The 64 bit v9 compiler will (/should) widen the args and use muldi3.
+
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (match_operand:SI 1 "arith_operand" "%r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ "TARGET_HARD_MUL"
+ "smul %1,%2,%0"
+ [(set_attr "type" "imul")])
+
+(define_expand "muldi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (match_operand:DI 1 "arith_double_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64 || TARGET_V8PLUS"
+ "
+{
+ if (TARGET_V8PLUS)
+ {
+ emit_insn (gen_muldi3_v8plus (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+
+(define_insn "*muldi3_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (match_operand:DI 1 "arith_double_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64"
+ "mulx %1,%2,%0")
+
+;; V8plus wide multiply.
+(define_insn "muldi3_v8plus"
+ [(set (match_operand:DI 0 "register_operand" "=r,h")
+ (mult:DI (match_operand:DI 1 "arith_double_operand" "%r,0")
+ (match_operand:DI 2 "arith_double_operand" "rHI,rHI")))
+ (clobber (match_scratch:SI 3 "=&h,X"))
+ (clobber (match_scratch:SI 4 "=&h,X"))]
+ "TARGET_V8PLUS"
+ "*
+{
+ if (sparc_check_64 (operands[1], insn) <= 0)
+ output_asm_insn (\"srl %L1,0,%L1\", operands);
+ if (which_alternative == 1)
+ output_asm_insn (\"sllx %H1,32,%H1\", operands);
+ if (sparc_check_64 (operands[2], insn) <= 0)
+ output_asm_insn (\"srl %L2,0,%L2\", operands);
+ if (which_alternative == 1)
+ return \"or %L1,%H1,%H1\;sllx %H2,32,%L1\;or %L2,%L1,%L1\;mulx %H1,%L1,%L0\;srlx %L0,32,%H0\";
+ else
+ return \"sllx %H1,32,%3\;sllx %H2,32,%4\;or %L1,%3,%3\;or %L2,%4,%4\;mulx %3,%4,%3\;srlx %3,32,%H0\;mov %3,%L0\";
+}"
+ [(set_attr "length" "9,8")])
+
+;; It is not known whether this will match.
+
+(define_insn "*cmp_mul_set"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (match_operand:SI 1 "arith_operand" "%r")
+ (match_operand:SI 2 "arith_operand" "rI")))
+ (set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (mult:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "TARGET_V8 || TARGET_SPARCLITE || TARGET_DEPRECATED_V8_INSNS"
+ "smulcc %1,%2,%0"
+ [(set_attr "type" "imul")])
+
+(define_expand "mulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" ""))
+ (sign_extend:DI (match_operand:SI 2 "arith_operand" ""))))]
+ "TARGET_HARD_MUL"
+ "
+{
+ if (CONSTANT_P (operands[2]))
+ {
+ if (TARGET_V8PLUS)
+ {
+ emit_insn (gen_const_mulsidi3_v8plus (operands[0], operands[1],
+ operands[2]));
+ DONE;
+ }
+ emit_insn (gen_const_mulsidi3 (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ if (TARGET_V8PLUS)
+ {
+ emit_insn (gen_mulsidi3_v8plus (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+
+;; V9 puts the 64 bit product in a 64 bit register. Only out or global
+;; registers can hold 64 bit values in the V8plus environment.
+(define_insn "mulsidi3_v8plus"
+ [(set (match_operand:DI 0 "register_operand" "=h,r")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r,r"))))
+ (clobber (match_scratch:SI 3 "=X,&h"))]
+ "TARGET_V8PLUS"
+ "@
+ smul %1,%2,%L0\;srlx %L0,32,%H0
+ smul %1,%2,%3\;srlx %3,32,%H0\;mov %3,%L0"
+ [(set_attr "length" "2,3")])
+
+(define_insn "const_mulsidi3_v8plus"
+ [(set (match_operand:DI 0 "register_operand" "=h,r")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
+ (match_operand:SI 2 "small_int" "I,I")))
+ (clobber (match_scratch:SI 3 "=X,&h"))]
+ "TARGET_V8PLUS"
+ "@
+ smul %1,%2,%L0\;srlx %L0,32,%H0
+ smul %1,%2,%3\;srlx %3,32,%H0\;mov %3,%L0"
+ [(set_attr "length" "2,3")])
+
+(define_insn "*mulsidi3_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+ "TARGET_HARD_MUL32"
+ "*
+{
+ return TARGET_SPARCLET ? \"smuld %1,%2,%L0\" : \"smul %1,%2,%L0\;rd %%y,%H0\";
+}"
+ [(set (attr "length")
+ (if_then_else (eq_attr "isa" "sparclet")
+ (const_int 1) (const_int 2)))])
+
+;; Extra pattern, because sign_extend of a constant isn't valid.
+
+(define_insn "const_mulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "small_int" "I")))]
+ "TARGET_HARD_MUL"
+ "*
+{
+ return TARGET_SPARCLET ? \"smuld %1,%2,%L0\" : \"smul %1,%2,%L0\;rd %%y,%H0\";
+}"
+ [(set (attr "length")
+ (if_then_else (eq_attr "isa" "sparclet")
+ (const_int 1) (const_int 2)))])
+
+(define_expand "smulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" ""))
+ (sign_extend:DI (match_operand:SI 2 "arith_operand" "")))
+ (const_int 32))))]
+ "TARGET_HARD_MUL"
+ "
+{
+ if (CONSTANT_P (operands[2]))
+ {
+ if (TARGET_V8PLUS)
+ {
+ emit_insn (gen_const_smulsi3_highpart_v8plus (operands[0],
+ operands[1],
+ operands[2],
+ GEN_INT (32)));
+ DONE;
+ }
+ emit_insn (gen_const_smulsi3_highpart (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ if (TARGET_V8PLUS)
+ {
+ emit_insn (gen_smulsi3_highpart_v8plus (operands[0], operands[1],
+ operands[2], GEN_INT (32)));
+ DONE;
+ }
+}")
+
+(define_insn "smulsi3_highpart_v8plus"
+ [(set (match_operand:SI 0 "register_operand" "=h,r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r,r")))
+ (match_operand:SI 3 "const_int_operand" "i,i"))))
+ (clobber (match_scratch:SI 4 "=X,&h"))]
+ "TARGET_V8PLUS"
+ "@
+ smul %1,%2,%0\;srlx %0,%3,%0
+ smul %1,%2,%4\;srlx %4,%3,%0"
+ [(set_attr "length" "2")])
+
+;; The combiner changes TRUNCATE in the previous pattern to SUBREG.
+(define_insn ""
+ [(set (match_operand:SI 0 "register_operand" "=h,r")
+ (subreg:SI
+ (lshiftrt:DI
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r,r")))
+ (match_operand:SI 3 "const_int_operand" "i,i"))
+ 1))
+ (clobber (match_scratch:SI 4 "=X,&h"))]
+ "TARGET_V8PLUS"
+ "@
+ smul %1,%2,%0\;srlx %0,%3,%0
+ smul %1,%2,%4\;srlx %4,%3,%0"
+ [(set_attr "length" "2")])
+
+(define_insn "const_smulsi3_highpart_v8plus"
+ [(set (match_operand:SI 0 "register_operand" "=h,r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
+ (match_operand 2 "small_int" "i,i"))
+ (match_operand:SI 3 "const_int_operand" "i,i"))))
+ (clobber (match_scratch:SI 4 "=X,&h"))]
+ "TARGET_V8PLUS"
+ "@
+ smul %1,%2,%0\;srlx %0,%3,%0
+ smul %1,%2,%4\;srlx %4,%3,%0"
+ [(set_attr "length" "2")])
+
+(define_insn "*smulsi3_highpart_sp32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))
+ (const_int 32))))]
+ "TARGET_HARD_MUL32"
+ "smul %1,%2,%%g0\;rd %%y,%0"
+ [(set_attr "length" "2")])
+
+(define_insn "const_smulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "register_operand" "r"))
+ (const_int 32))))]
+ "TARGET_HARD_MUL32"
+ "smul %1,%2,%%g0\;rd %%y,%0"
+ [(set_attr "length" "2")])
+
+(define_expand "umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" ""))
+ (zero_extend:DI (match_operand:SI 2 "uns_arith_operand" ""))))]
+ "TARGET_HARD_MUL"
+ "
+{
+ if (CONSTANT_P (operands[2]))
+ {
+ if (TARGET_V8PLUS)
+ {
+ emit_insn (gen_const_umulsidi3_v8plus (operands[0], operands[1],
+ operands[2]));
+ DONE;
+ }
+ emit_insn (gen_const_umulsidi3 (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ if (TARGET_V8PLUS)
+ {
+ emit_insn (gen_umulsidi3_v8plus (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+
+(define_insn "umulsidi3_v8plus"
+ [(set (match_operand:DI 0 "register_operand" "=h,r")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r,r"))))
+ (clobber (match_scratch:SI 3 "=X,&h"))]
+ "TARGET_V8PLUS"
+ "@
+ umul %1,%2,%L0\;srlx %L0,32,%H0
+ umul %1,%2,%3\;srlx %3,32,%H0\;mov %3,%L0"
+ [(set_attr "length" "2,3")])
+
+(define_insn "*umulsidi3_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+ "TARGET_HARD_MUL32"
+ "*
+{
+ return TARGET_SPARCLET ? \"umuld %1,%2,%L0\" : \"umul %1,%2,%L0\;rd %%y,%H0\";
+}"
+ [(set (attr "length")
+ (if_then_else (eq_attr "isa" "sparclet")
+ (const_int 1) (const_int 2)))])
+
+;; Extra pattern, because sign_extend of a constant isn't valid.
+
+(define_insn "const_umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "uns_small_int" "")))]
+ "TARGET_HARD_MUL32"
+ "*
+{
+ return TARGET_SPARCLET ? \"umuld %1,%2,%L0\" : \"umul %1,%2,%L0\;rd %%y,%H0\";
+}"
+ [(set (attr "length")
+ (if_then_else (eq_attr "isa" "sparclet")
+ (const_int 1) (const_int 2)))])
+
+(define_insn "const_umulsidi3_v8plus"
+ [(set (match_operand:DI 0 "register_operand" "=h,r")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
+ (match_operand:SI 2 "uns_small_int" "")))
+ (clobber (match_scratch:SI 3 "=X,h"))]
+ "TARGET_V8PLUS"
+ "@
+ umul %1,%2,%L0\;srlx %L0,32,%H0
+ umul %1,%2,%3\;srlx %3,32,%H0\;mov %3,%L0"
+ [(set_attr "length" "2,3")])
+
+(define_expand "umulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" ""))
+ (zero_extend:DI (match_operand:SI 2 "uns_arith_operand" "")))
+ (const_int 32))))]
+ "TARGET_HARD_MUL"
+ "
+{
+ if (CONSTANT_P (operands[2]))
+ {
+ if (TARGET_V8PLUS)
+ {
+ emit_insn (gen_const_umulsi3_highpart_v8plus (operands[0],
+ operands[1],
+ operands[2],
+ GEN_INT (32)));
+ DONE;
+ }
+ emit_insn (gen_const_umulsi3_highpart (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ if (TARGET_V8PLUS)
+ {
+ emit_insn (gen_umulsi3_highpart_v8plus (operands[0], operands[1],
+ operands[2], GEN_INT (32)));
+ DONE;
+ }
+}")
+
+(define_insn "umulsi3_highpart_v8plus"
+ [(set (match_operand:SI 0 "register_operand" "=h,r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r,r")))
+ (match_operand:SI 3 "const_int_operand" "i,i"))))
+ (clobber (match_scratch:SI 4 "=X,h"))]
+ "TARGET_V8PLUS"
+ "@
+ umul %1,%2,%0\;srlx %0,%3,%0
+ umul %1,%2,%4\;srlx %4,%3,%0"
+ [(set_attr "length" "2")])
+
+(define_insn "const_umulsi3_highpart_v8plus"
+ [(set (match_operand:SI 0 "register_operand" "=h,r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
+ (match_operand:SI 2 "uns_small_int" ""))
+ (match_operand:SI 3 "const_int_operand" "i,i"))))
+ (clobber (match_scratch:SI 4 "=X,h"))]
+ "TARGET_V8PLUS"
+ "@
+ umul %1,%2,%0\;srlx %0,%3,%0
+ umul %1,%2,%4\;srlx %4,%3,%0"
+ [(set_attr "length" "2")])
+
+(define_insn "*umulsi3_highpart_sp32"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))
+ (const_int 32))))]
+ "TARGET_HARD_MUL32"
+ "umul %1,%2,%%g0\;rd %%y,%0"
+ [(set_attr "length" "2")])
+
+(define_insn "const_umulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand:SI 2 "uns_small_int" ""))
+ (const_int 32))))]
+ "TARGET_HARD_MUL32"
+ "umul %1,%2,%%g0\;rd %%y,%0"
+ [(set_attr "length" "2")])
+
+;; The v8 architecture specifies that there must be 3 instructions between
+;; a y register write and a use of it for correct results.
+
+(define_insn "divsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (div:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "move_operand" "rI,m")))
+ (clobber (match_scratch:SI 3 "=&r,&r"))]
+ "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
+ "*
+{
+ if (which_alternative == 0)
+ if (TARGET_V9)
+ return \"sra %1,31,%3\;wr %%g0,%3,%%y\;sdiv %1,%2,%0\";
+ else
+ return \"sra %1,31,%3\;wr %%g0,%3,%%y\;nop\;nop\;nop\;sdiv %1,%2,%0\";
+ else
+ if (TARGET_V9)
+ return \"sra %1,31,%3\;wr %%g0,%3,%%y\;ld %2,%3\;sdiv %1,%3,%0\";
+ else
+ return \"sra %1,31,%3\;wr %%g0,%3,%%y\;ld %2,%3\;nop\;nop\;sdiv %1,%3,%0\";
+}"
+ [(set (attr "length")
+ (if_then_else (eq_attr "isa" "v9")
+ (const_int 4) (const_int 7)))])
+
+(define_insn "divdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (div:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64"
+ "sdivx %1,%2,%0")
+
+;; It is not known whether this will match.
+
+(define_insn "*cmp_sdiv_cc_set"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (div:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))
+ (set (reg:CC 100)
+ (compare:CC (div:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))
+ (clobber (match_scratch:SI 3 "=&r"))]
+ "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
+ "*
+{
+ if (TARGET_V9)
+ return \"sra %1,31,%3\;wr %%g0,%3,%%y\;sdivcc %1,%2,%0\";
+ else
+ return \"sra %1,31,%3\;wr %%g0,%3,%%y\;nop\;nop\;nop\;sdivcc %1,%2,%0\";
+}"
+ [(set (attr "length")
+ (if_then_else (eq_attr "isa" "v9")
+ (const_int 3) (const_int 6)))])
+
+(define_insn "udivsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,&r,&r")
+ (udiv:SI (match_operand:SI 1 "reg_or_nonsymb_mem_operand" "r,r,m")
+ (match_operand:SI 2 "move_operand" "rI,m,r")))]
+ "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
+ "*
+{
+ output_asm_insn (\"wr %%g0,%%g0,%%y\", operands);
+ switch (which_alternative)
+ {
+ default:
+ if (TARGET_V9)
+ return \"udiv %1,%2,%0\";
+ return \"nop\;nop\;nop\;udiv %1,%2,%0\";
+ case 1:
+ return \"ld %2,%0\;nop\;nop\;udiv %1,%0,%0\";
+ case 2:
+ return \"ld %1,%0\;nop\;nop\;udiv %0,%2,%0\";
+ }
+}"
+ [(set (attr "length")
+ (if_then_else (and (eq_attr "isa" "v9")
+ (eq_attr "alternative" "0"))
+ (const_int 2) (const_int 5)))])
+
+(define_insn "udivdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (udiv:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64"
+ "udivx %1,%2,%0")
+
+;; It is not known whether this will match.
+
+(define_insn "*cmp_udiv_cc_set"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (udiv:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))
+ (set (reg:CC 100)
+ (compare:CC (udiv:SI (match_dup 1) (match_dup 2))
+ (const_int 0)))]
+ "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
+ "*
+{
+ if (TARGET_V9)
+ return \"wr %%g0,%%g0,%%y\;udivcc %1,%2,%0\";
+ else
+ return \"wr %%g0,%%g0,%%y\;nop\;nop\;nop\;udivcc %1,%2,%0\";
+}"
+ [(set (attr "length")
+ (if_then_else (eq_attr "isa" "v9")
+ (const_int 2) (const_int 5)))])
+
+; sparclet multiply/accumulate insns
+
+(define_insn "*smacsi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (mult:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (match_operand:SI 3 "register_operand" "0")))]
+ "TARGET_SPARCLET"
+ "smac %1,%2,%0"
+ [(set_attr "type" "imul")])
+
+(define_insn "*smacdi"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (mult:DI (sign_extend:DI
+ (match_operand:SI 1 "register_operand" "%r"))
+ (sign_extend:DI
+ (match_operand:SI 2 "register_operand" "r")))
+ (match_operand:DI 3 "register_operand" "0")))]
+ "TARGET_SPARCLET"
+ "smacd %1,%2,%L0"
+ [(set_attr "type" "imul")])
+
+(define_insn "*umacdi"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plus:DI (mult:DI (zero_extend:DI
+ (match_operand:SI 1 "register_operand" "%r"))
+ (zero_extend:DI
+ (match_operand:SI 2 "register_operand" "r")))
+ (match_operand:DI 3 "register_operand" "0")))]
+ "TARGET_SPARCLET"
+ "umacd %1,%2,%L0"
+ [(set_attr "type" "imul")])
+
+;;- Boolean instructions
+;; We define DImode `and' so with DImode `not' we can get
+;; DImode `andn'. Other combinations are possible.
+
+(define_expand "anddi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (and:DI (match_operand:DI 1 "arith_double_operand" "")
+ (match_operand:DI 2 "arith_double_operand" "")))]
+ ""
+ "")
+
+(define_insn "*anddi3_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r,b")
+ (and:DI (match_operand:DI 1 "arith_double_operand" "%r,b")
+ (match_operand:DI 2 "arith_double_operand" "rHI,b")))]
+ "! TARGET_ARCH64"
+ "*
+{
+ rtx op2 = operands[2];
+
+ if (which_alternative == 1)
+ return \"fand %1,%2,%0\";
+
+ if (GET_CODE (op2) == CONST_INT
+ || GET_CODE (op2) == CONST_DOUBLE)
+ {
+ rtx xoperands[4];
+ xoperands[0] = operands[0];
+ xoperands[1] = operands[1];
+ if (WORDS_BIG_ENDIAN)
+ split_double (op2, &xoperands[2], &xoperands[3]);
+ else
+ split_double (op2, &xoperands[3], &xoperands[2]);
+ output_asm_insn (\"and %L1,%3,%L0\;and %H1,%2,%H0\", xoperands);
+ return \"\";
+ }
+ return \"and %1,%2,%0\;and %R1,%R2,%R0\";
+}"
+ [(set_attr "length" "2,1")])
+
+(define_insn "*anddi3_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI (match_operand:DI 1 "arith_double_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64"
+ "and %1,%2,%0")
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (and:SI (match_operand:SI 1 "arith_operand" "%r,d")
+ (match_operand:SI 2 "arith_operand" "rI,d")))]
+ ""
+ "@
+ and %1,%2,%0
+ fands %1,%2,%0"
+ [(set_attr "type" "ialu,fp")])
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (and:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "" "")))
+ (clobber (match_operand:SI 3 "register_operand" ""))]
+ "GET_CODE (operands[2]) == CONST_INT
+ && !SMALL_INT32 (operands[2])
+ && (INTVAL (operands[2]) & 0x3ff) == 0x3ff"
+ [(set (match_dup 3) (match_dup 4))
+ (set (match_dup 0) (and:SI (not:SI (match_dup 3)) (match_dup 1)))]
+ "
+{
+ operands[4] = GEN_INT (~INTVAL (operands[2]) & 0xffffffff);
+}")
+
+;; Split DImode logical operations requiring two instructions.
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operator:DI 1 "cc_arithop" ; AND, IOR, XOR
+ [(match_operand:DI 2 "register_operand" "")
+ (match_operand:DI 3 "arith_double_operand" "")]))]
+ "! TARGET_ARCH64 && reload_completed
+ && GET_CODE (operands[0]) == REG && REGNO (operands[0]) < 32"
+ [(set (match_dup 4) (match_op_dup:SI 1 [(match_dup 6) (match_dup 8)]))
+ (set (match_dup 5) (match_op_dup:SI 1 [(match_dup 7) (match_dup 9)]))]
+ "
+{
+ operands[4] = gen_highpart (SImode, operands[0]);
+ operands[5] = gen_lowpart (SImode, operands[0]);
+ operands[6] = gen_highpart (SImode, operands[2]);
+ operands[7] = gen_lowpart (SImode, operands[2]);
+ if (GET_CODE (operands[3]) == CONST_INT)
+ {
+ if (INTVAL (operands[3]) < 0)
+ operands[8] = constm1_rtx;
+ else
+ operands[8] = const0_rtx;
+ }
+ else
+ operands[8] = gen_highpart (SImode, operands[3]);
+ operands[9] = gen_lowpart (SImode, operands[3]);
+}")
+
+(define_insn "*and_not_di_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r,b")
+ (and:DI (not:DI (match_operand:DI 1 "register_operand" "r,b"))
+ (match_operand:DI 2 "register_operand" "r,b")))]
+ "! TARGET_ARCH64"
+ "@
+ andn %2,%1,%0\;andn %R2,%R1,%R0
+ fandnot1 %1,%2,%0"
+ [(set_attr "length" "2,1")])
+
+(define_insn "*and_not_di_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (and:DI (not:DI (match_operand:DI 1 "register_operand" "r"))
+ (match_operand:DI 2 "register_operand" "r")))]
+ "TARGET_ARCH64"
+ "andn %2,%1,%0")
+
+(define_insn "*and_not_si"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (and:SI (not:SI (match_operand:SI 1 "register_operand" "r,d"))
+ (match_operand:SI 2 "register_operand" "r,d")))]
+ ""
+ "@
+ andn %2,%1,%0
+ fandnot1s %1,%2,%0"
+ [(set_attr "type" "ialu,fp")])
+
+(define_expand "iordi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ior:DI (match_operand:DI 1 "arith_double_operand" "")
+ (match_operand:DI 2 "arith_double_operand" "")))]
+ ""
+ "")
+
+(define_insn "*iordi3_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r,b")
+ (ior:DI (match_operand:DI 1 "arith_double_operand" "%r,b")
+ (match_operand:DI 2 "arith_double_operand" "rHI,b")))]
+ "! TARGET_ARCH64"
+ "*
+{
+ rtx op2 = operands[2];
+
+ if (which_alternative == 1)
+ return \"for %1,%2,%0\";
+
+ if (GET_CODE (op2) == CONST_INT
+ || GET_CODE (op2) == CONST_DOUBLE)
+ {
+ rtx xoperands[4];
+ xoperands[0] = operands[0];
+ xoperands[1] = operands[1];
+ if (WORDS_BIG_ENDIAN)
+ split_double (op2, &xoperands[2], &xoperands[3]);
+ else
+ split_double (op2, &xoperands[3], &xoperands[2]);
+ output_asm_insn (\"or %L1,%3,%L0\;or %H1,%2,%H0\", xoperands);
+ return \"\";
+ }
+ return \"or %1,%2,%0\;or %R1,%R2,%R0\";
+}"
+ [(set_attr "length" "2,1")])
+
+(define_insn "*iordi3_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ior:DI (match_operand:DI 1 "arith_double_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64"
+ "or %1,%2,%0")
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (ior:SI (match_operand:SI 1 "arith_operand" "%r,d")
+ (match_operand:SI 2 "arith_operand" "rI,d")))]
+ ""
+ "@
+ or %1,%2,%0
+ fors %1,%2,%0"
+ [(set_attr "type" "ialu,fp")])
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ior:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "" "")))
+ (clobber (match_operand:SI 3 "register_operand" ""))]
+ "GET_CODE (operands[2]) == CONST_INT
+ && !SMALL_INT32 (operands[2])
+ && (INTVAL (operands[2]) & 0x3ff) == 0x3ff"
+ [(set (match_dup 3) (match_dup 4))
+ (set (match_dup 0) (ior:SI (not:SI (match_dup 3)) (match_dup 1)))]
+ "
+{
+ operands[4] = GEN_INT (~INTVAL (operands[2]) & 0xffffffff);
+}")
+
+(define_insn "*or_not_di_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r,b")
+ (ior:DI (not:DI (match_operand:DI 1 "register_operand" "r,b"))
+ (match_operand:DI 2 "register_operand" "r,b")))]
+ "! TARGET_ARCH64"
+ "@
+ orn %2,%1,%0\;orn %R2,%R1,%R0
+ fornot1 %1,%2,%0"
+ [(set_attr "length" "2,1")])
+
+(define_insn "*or_not_di_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ior:DI (not:DI (match_operand:DI 1 "register_operand" "r"))
+ (match_operand:DI 2 "register_operand" "r")))]
+ "TARGET_ARCH64"
+ "orn %2,%1,%0")
+
+(define_insn "*or_not_si"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (ior:SI (not:SI (match_operand:SI 1 "register_operand" "r,d"))
+ (match_operand:SI 2 "register_operand" "r,d")))]
+ ""
+ "@
+ orn %2,%1,%0
+ fornot1s %1,%2,%0"
+ [(set_attr "type" "ialu,fp")])
+
+(define_expand "xordi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (xor:DI (match_operand:DI 1 "arith_double_operand" "")
+ (match_operand:DI 2 "arith_double_operand" "")))]
+ ""
+ "")
+
+(define_insn "*xordi3_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r,b")
+ (xor:DI (match_operand:DI 1 "arith_double_operand" "%r,b")
+ (match_operand:DI 2 "arith_double_operand" "rHI,b")))]
+ "! TARGET_ARCH64"
+ "*
+{
+ rtx op2 = operands[2];
+
+ if (which_alternative == 1)
+ return \"fxor %1,%2,%0\";
+
+ if (GET_CODE (op2) == CONST_INT
+ || GET_CODE (op2) == CONST_DOUBLE)
+ {
+ rtx xoperands[4];
+ xoperands[0] = operands[0];
+ xoperands[1] = operands[1];
+ if (WORDS_BIG_ENDIAN)
+ split_double (op2, &xoperands[2], &xoperands[3]);
+ else
+ split_double (op2, &xoperands[3], &xoperands[2]);
+ output_asm_insn (\"xor %L1,%3,%L0\;xor %H1,%2,%H0\", xoperands);
+ return \"\";
+ }
+ return \"xor %1,%2,%0\;xor %R1,%R2,%R0\";
+}"
+ [(set_attr "length" "2,1")
+ (set_attr "type" "ialu,fp")])
+
+(define_insn "*xordi3_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (xor:DI (match_operand:DI 1 "arith_double_operand" "%rJ")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64"
+ "xor %r1,%2,%0")
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (xor:SI (match_operand:SI 1 "arith_operand" "%rJ,d")
+ (match_operand:SI 2 "arith_operand" "rI,d")))]
+ ""
+ "@
+ xor %r1,%2,%0
+ fxors %1,%2,%0"
+ [(set_attr "type" "ialu,fp")])
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (xor:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "" "")))
+ (clobber (match_operand:SI 3 "register_operand" ""))]
+ "GET_CODE (operands[2]) == CONST_INT
+ && !SMALL_INT32 (operands[2])
+ && (INTVAL (operands[2]) & 0x3ff) == 0x3ff"
+ [(set (match_dup 3) (match_dup 4))
+ (set (match_dup 0) (not:SI (xor:SI (match_dup 3) (match_dup 1))))]
+ "
+{
+ operands[4] = GEN_INT (~INTVAL (operands[2]) & 0xffffffff);
+}")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (not:SI (xor:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "" ""))))
+ (clobber (match_operand:SI 3 "register_operand" ""))]
+ "GET_CODE (operands[2]) == CONST_INT
+ && !SMALL_INT32 (operands[2])
+ && (INTVAL (operands[2]) & 0x3ff) == 0x3ff"
+ [(set (match_dup 3) (match_dup 4))
+ (set (match_dup 0) (xor:SI (match_dup 3) (match_dup 1)))]
+ "
+{
+ operands[4] = GEN_INT (~INTVAL (operands[2]) & 0xffffffff);
+}")
+
+;; xnor patterns. Note that (a ^ ~b) == (~a ^ b) == ~(a ^ b).
+;; Combine now canonicalizes to the rightmost expression.
+(define_insn "*xor_not_di_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r,b")
+ (not:DI (xor:DI (match_operand:DI 1 "register_operand" "r,b")
+ (match_operand:DI 2 "register_operand" "r,b"))))]
+ "! TARGET_ARCH64"
+ "@
+ xnor %1,%2,%0\;xnor %R1,%R2,%R0
+ fxnor %1,%2,%0"
+ [(set_attr "length" "2,1")
+ (set_attr "type" "ialu,fp")])
+
+(define_insn "*xor_not_di_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (not:DI (xor:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+ (match_operand:DI 2 "arith_double_operand" "rHI"))))]
+ "TARGET_ARCH64"
+ "xnor %r1,%2,%0"
+ [(set_attr "type" "ialu")])
+
+(define_insn "*xor_not_si"
+ [(set (match_operand:SI 0 "register_operand" "=r,d")
+ (not:SI (xor:SI (match_operand:SI 1 "reg_or_0_operand" "rJ,d")
+ (match_operand:SI 2 "arith_operand" "rI,d"))))]
+ ""
+ "@
+ xnor %r1,%2,%0
+ fxnors %1,%2,%0"
+ [(set_attr "type" "ialu,fp")])
+
+;; These correspond to the above in the case where we also (or only)
+;; want to set the condition code.
+
+(define_insn "*cmp_cc_arith_op"
+ [(set (reg:CC 100)
+ (compare:CC
+ (match_operator:SI 2 "cc_arithop"
+ [(match_operand:SI 0 "arith_operand" "%r")
+ (match_operand:SI 1 "arith_operand" "rI")])
+ (const_int 0)))]
+ ""
+ "%A2cc %0,%1,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccx_arith_op"
+ [(set (reg:CCX 100)
+ (compare:CCX
+ (match_operator:DI 2 "cc_arithop"
+ [(match_operand:DI 0 "arith_double_operand" "%r")
+ (match_operand:DI 1 "arith_double_operand" "rHI")])
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "%A2cc %0,%1,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_cc_arith_op_set"
+ [(set (reg:CC 100)
+ (compare:CC
+ (match_operator:SI 3 "cc_arithop"
+ [(match_operand:SI 1 "arith_operand" "%r")
+ (match_operand:SI 2 "arith_operand" "rI")])
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (match_dup 3))]
+ ""
+ "%A3cc %1,%2,%0")
+
+(define_insn "*cmp_ccx_arith_op_set"
+ [(set (reg:CCX 100)
+ (compare:CCX
+ (match_operator:DI 3 "cc_arithop"
+ [(match_operand:DI 1 "arith_double_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")])
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (match_dup 3))]
+ "TARGET_ARCH64"
+ "%A3cc %1,%2,%0")
+
+(define_insn "*cmp_cc_xor_not"
+ [(set (reg:CC 100)
+ (compare:CC
+ (not:SI (xor:SI (match_operand:SI 0 "reg_or_0_operand" "%rJ")
+ (match_operand:SI 1 "arith_operand" "rI")))
+ (const_int 0)))]
+ ""
+ "xnorcc %r0,%1,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccx_xor_not"
+ [(set (reg:CCX 100)
+ (compare:CCX
+ (not:DI (xor:DI (match_operand:DI 0 "reg_or_0_operand" "%rJ")
+ (match_operand:DI 1 "arith_double_operand" "rHI")))
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "xnorcc %r0,%1,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_cc_xor_not_set"
+ [(set (reg:CC 100)
+ (compare:CC
+ (not:SI (xor:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:SI 2 "arith_operand" "rI")))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (not:SI (xor:SI (match_dup 1) (match_dup 2))))]
+ ""
+ "xnorcc %r1,%2,%0")
+
+(define_insn "*cmp_ccx_xor_not_set"
+ [(set (reg:CCX 100)
+ (compare:CCX
+ (not:DI (xor:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (not:DI (xor:DI (match_dup 1) (match_dup 2))))]
+ "TARGET_ARCH64"
+ "xnorcc %r1,%2,%0")
+
+(define_insn "*cmp_cc_arith_op_not"
+ [(set (reg:CC 100)
+ (compare:CC
+ (match_operator:SI 2 "cc_arithopn"
+ [(not:SI (match_operand:SI 0 "arith_operand" "rI"))
+ (match_operand:SI 1 "reg_or_0_operand" "rJ")])
+ (const_int 0)))]
+ ""
+ "%B2cc %r1,%0,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccx_arith_op_not"
+ [(set (reg:CCX 100)
+ (compare:CCX
+ (match_operator:DI 2 "cc_arithopn"
+ [(not:DI (match_operand:DI 0 "arith_double_operand" "rHI"))
+ (match_operand:DI 1 "reg_or_0_operand" "rJ")])
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "%B2cc %r1,%0,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_cc_arith_op_not_set"
+ [(set (reg:CC 100)
+ (compare:CC
+ (match_operator:SI 3 "cc_arithopn"
+ [(not:SI (match_operand:SI 1 "arith_operand" "rI"))
+ (match_operand:SI 2 "reg_or_0_operand" "rJ")])
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (match_dup 3))]
+ ""
+ "%B3cc %r2,%1,%0")
+
+(define_insn "*cmp_ccx_arith_op_not_set"
+ [(set (reg:CCX 100)
+ (compare:CCX
+ (match_operator:DI 3 "cc_arithopn"
+ [(not:DI (match_operand:DI 1 "arith_double_operand" "rHI"))
+ (match_operand:DI 2 "reg_or_0_operand" "rJ")])
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (match_dup 3))]
+ "TARGET_ARCH64"
+ "%B3cc %r2,%1,%0")
+
+;; We cannot use the "neg" pseudo insn because the Sun assembler
+;; does not know how to make it work for constants.
+
+(define_expand "negdi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_operand:DI 1 "register_operand" "r")))]
+ ""
+ "
+{
+ if (! TARGET_ARCH64)
+ {
+ emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
+ gen_rtx_SET (VOIDmode, operand0,
+ gen_rtx_NEG (DImode, operand1)),
+ gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_REG (CCmode, SPARC_ICC_REG)))));
+ DONE;
+ }
+}")
+
+(define_insn "*negdi2_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_operand:DI 1 "register_operand" "r")))
+ (clobber (reg:CC 100))]
+ "! TARGET_ARCH64"
+ "*
+{
+ if (TARGET_LIVE_G0)
+ output_asm_insn (\"and %%g0,0,%%g0\", operands);
+ return \"subcc %%g0,%L1,%L0\;subx %%g0,%H1,%H0\";
+}"
+ [(set_attr "type" "unary")
+ ;; ??? This is wrong for TARGET_LIVE_G0 but it's not critical.
+ (set_attr "length" "2")])
+
+(define_insn "*negdi2_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_operand:DI 1 "register_operand" "r")))]
+ "TARGET_ARCH64"
+ "sub %%g0,%1,%0"
+ [(set_attr "type" "unary")
+ (set_attr "length" "1")])
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (match_operand:SI 1 "arith_operand" "rI")))]
+ ""
+ "*
+{
+ if (TARGET_LIVE_G0)
+ return \"and %%g0,0,%%g0\;sub %%g0,%1,%0\";
+ return \"sub %%g0,%1,%0\";
+}"
+ [(set_attr "type" "unary")
+ (set (attr "length")
+ (if_then_else (eq_attr "live_g0" "yes") (const_int 2) (const_int 1)))])
+
+(define_insn "*cmp_cc_neg"
+ [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (neg:SI (match_operand:SI 0 "arith_operand" "rI"))
+ (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "subcc %%g0,%0,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccx_neg"
+ [(set (reg:CCX_NOOV 100)
+ (compare:CCX_NOOV (neg:DI (match_operand:DI 0 "arith_double_operand" "rHI"))
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "subcc %%g0,%0,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_cc_set_neg"
+ [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (neg:SI (match_operand:SI 1 "arith_operand" "rI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (match_dup 1)))]
+ "! TARGET_LIVE_G0"
+ "subcc %%g0,%1,%0"
+ [(set_attr "type" "unary")])
+
+(define_insn "*cmp_ccx_set_neg"
+ [(set (reg:CCX_NOOV 100)
+ (compare:CCX_NOOV (neg:DI (match_operand:DI 1 "arith_double_operand" "rHI"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (neg:DI (match_dup 1)))]
+ "TARGET_ARCH64"
+ "subcc %%g0,%1,%0"
+ [(set_attr "type" "unary")])
+
+;; We cannot use the "not" pseudo insn because the Sun assembler
+;; does not know how to make it work for constants.
+(define_expand "one_cmpldi2"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (not:DI (match_operand:DI 1 "register_operand" "")))]
+ ""
+ "")
+
+(define_insn "*one_cmpldi2_sp32"
+ [(set (match_operand:DI 0 "register_operand" "=r,b")
+ (not:DI (match_operand:DI 1 "register_operand" "r,b")))]
+ "! TARGET_ARCH64"
+ "@
+ xnor %1,0,%0\;xnor %R1,0,%R0
+ fnot1 %1,%0"
+ [(set_attr "type" "unary,fp")
+ (set_attr "length" "2,1")])
+
+(define_insn "*one_cmpldi2_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (not:DI (match_operand:DI 1 "arith_double_operand" "rHI")))]
+ "TARGET_ARCH64"
+ "xnor %1,0,%0"
+ [(set_attr "type" "unary")])
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,d")
+ (not:SI (match_operand:SI 1 "arith_operand" "r,I,d")))]
+ ""
+ "*
+{
+ if (which_alternative == 0)
+ return \"xnor %1,0,%0\";
+ if (which_alternative == 2)
+ return \"fnot1s %1,%0\";
+ if (TARGET_LIVE_G0)
+ output_asm_insn (\"and %%g0,0,%%g0\", operands);
+ return \"xnor %%g0,%1,%0\";
+}"
+ [(set_attr "type" "unary,unary,fp")
+ (set_attr_alternative "length"
+ [(const_int 1)
+ (if_then_else (eq_attr "live_g0" "yes") (const_int 2) (const_int 1))
+ (const_int 1)])])
+
+(define_insn "*cmp_cc_not"
+ [(set (reg:CC 100)
+ (compare:CC (not:SI (match_operand:SI 0 "arith_operand" "rI"))
+ (const_int 0)))]
+ "! TARGET_LIVE_G0"
+ "xnorcc %%g0,%0,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_ccx_not"
+ [(set (reg:CCX 100)
+ (compare:CCX (not:DI (match_operand:DI 0 "arith_double_operand" "rHI"))
+ (const_int 0)))]
+ "TARGET_ARCH64"
+ "xnorcc %%g0,%0,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_cc_set_not"
+ [(set (reg:CC 100)
+ (compare:CC (not:SI (match_operand:SI 1 "arith_operand" "rI"))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (not:SI (match_dup 1)))]
+ "! TARGET_LIVE_G0"
+ "xnorcc %%g0,%1,%0"
+ [(set_attr "type" "unary")])
+
+(define_insn "*cmp_ccx_set_not"
+ [(set (reg:CCX 100)
+ (compare:CCX (not:DI (match_operand:DI 1 "arith_double_operand" "rHI"))
+ (const_int 0)))
+ (set (match_operand:DI 0 "register_operand" "=r")
+ (not:DI (match_dup 1)))]
+ "TARGET_ARCH64"
+ "xnorcc %%g0,%1,%0"
+ [(set_attr "type" "unary")])
+
+;; Floating point arithmetic instructions.
+
+(define_insn "addtf3"
+ [(set (match_operand:TF 0 "register_operand" "=e")
+ (plus:TF (match_operand:TF 1 "register_operand" "e")
+ (match_operand:TF 2 "register_operand" "e")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "faddq %1,%2,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "adddf3"
+ [(set (match_operand:DF 0 "register_operand" "=e")
+ (plus:DF (match_operand:DF 1 "register_operand" "e")
+ (match_operand:DF 2 "register_operand" "e")))]
+ "TARGET_FPU"
+ "faddd %1,%2,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (plus:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")))]
+ "TARGET_FPU"
+ "fadds %1,%2,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "subtf3"
+ [(set (match_operand:TF 0 "register_operand" "=e")
+ (minus:TF (match_operand:TF 1 "register_operand" "e")
+ (match_operand:TF 2 "register_operand" "e")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "fsubq %1,%2,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "subdf3"
+ [(set (match_operand:DF 0 "register_operand" "=e")
+ (minus:DF (match_operand:DF 1 "register_operand" "e")
+ (match_operand:DF 2 "register_operand" "e")))]
+ "TARGET_FPU"
+ "fsubd %1,%2,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (minus:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")))]
+ "TARGET_FPU"
+ "fsubs %1,%2,%0"
+ [(set_attr "type" "fp")])
+
+(define_insn "multf3"
+ [(set (match_operand:TF 0 "register_operand" "=e")
+ (mult:TF (match_operand:TF 1 "register_operand" "e")
+ (match_operand:TF 2 "register_operand" "e")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "fmulq %1,%2,%0"
+ [(set_attr "type" "fpmul")])
+
+(define_insn "muldf3"
+ [(set (match_operand:DF 0 "register_operand" "=e")
+ (mult:DF (match_operand:DF 1 "register_operand" "e")
+ (match_operand:DF 2 "register_operand" "e")))]
+ "TARGET_FPU"
+ "fmuld %1,%2,%0"
+ [(set_attr "type" "fpmul")])
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (mult:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")))]
+ "TARGET_FPU"
+ "fmuls %1,%2,%0"
+ [(set_attr "type" "fpmul")])
+
+(define_insn "*muldf3_extend"
+ [(set (match_operand:DF 0 "register_operand" "=e")
+ (mult:DF (float_extend:DF (match_operand:SF 1 "register_operand" "f"))
+ (float_extend:DF (match_operand:SF 2 "register_operand" "f"))))]
+ "(TARGET_V8 || TARGET_V9) && TARGET_FPU"
+ "fsmuld %1,%2,%0"
+ [(set_attr "type" "fpmul")])
+
+(define_insn "*multf3_extend"
+ [(set (match_operand:TF 0 "register_operand" "=e")
+ (mult:TF (float_extend:TF (match_operand:DF 1 "register_operand" "e"))
+ (float_extend:TF (match_operand:DF 2 "register_operand" "e"))))]
+ "(TARGET_V8 || TARGET_V9) && TARGET_FPU && TARGET_HARD_QUAD"
+ "fdmulq %1,%2,%0"
+ [(set_attr "type" "fpmul")])
+
+;; don't have timing for quad-prec. divide.
+(define_insn "divtf3"
+ [(set (match_operand:TF 0 "register_operand" "=e")
+ (div:TF (match_operand:TF 1 "register_operand" "e")
+ (match_operand:TF 2 "register_operand" "e")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "fdivq %1,%2,%0"
+ [(set_attr "type" "fpdivd")])
+
+(define_insn "divdf3"
+ [(set (match_operand:DF 0 "register_operand" "=e")
+ (div:DF (match_operand:DF 1 "register_operand" "e")
+ (match_operand:DF 2 "register_operand" "e")))]
+ "TARGET_FPU"
+ "fdivd %1,%2,%0"
+ [(set_attr "type" "fpdivd")])
+
+(define_insn "divsf3"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (div:SF (match_operand:SF 1 "register_operand" "f")
+ (match_operand:SF 2 "register_operand" "f")))]
+ "TARGET_FPU"
+ "fdivs %1,%2,%0"
+ [(set_attr "type" "fpdivs")])
+
+(define_insn "negtf2"
+ [(set (match_operand:TF 0 "register_operand" "=e,e")
+ (neg:TF (match_operand:TF 1 "register_operand" "0,e")))]
+ ; We don't use quad float insns here so we don't need TARGET_HARD_QUAD.
+ "TARGET_FPU"
+ "*
+{
+ /* v9: can't use fnegs, won't work with upper regs. */
+ if (which_alternative == 0)
+ return TARGET_V9 ? \"fnegd %0,%0\" : \"fnegs %0,%0\";
+ else
+ return TARGET_V9 ? \"fnegd %1,%0\;fmovd %S1,%S0\"
+ : \"fnegs %1,%0\;fmovs %R1,%R0\;fmovs %S1,%S0\;fmovs %T1,%T0\";
+}"
+ [(set_attr "type" "fpmove")
+ (set_attr_alternative "length"
+ [(const_int 1)
+ (if_then_else (eq_attr "isa" "v9") (const_int 2) (const_int 4))])])
+
+(define_insn "negdf2"
+ [(set (match_operand:DF 0 "register_operand" "=e,e")
+ (neg:DF (match_operand:DF 1 "register_operand" "0,e")))]
+ "TARGET_FPU"
+ "*
+{
+ if (TARGET_V9)
+ return \"fnegd %1,%0\";
+ else if (which_alternative == 0)
+ return \"fnegs %0,%0\";
+ else
+ return \"fnegs %1,%0\;fmovs %R1,%R0\";
+}"
+ [(set_attr "type" "fpmove")
+ (set_attr_alternative "length"
+ [(const_int 1)
+ (if_then_else (eq_attr "isa" "v9") (const_int 1) (const_int 2))])])
+
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (neg:SF (match_operand:SF 1 "register_operand" "f")))]
+ "TARGET_FPU"
+ "fnegs %1,%0"
+ [(set_attr "type" "fpmove")])
+
+(define_insn "abstf2"
+ [(set (match_operand:TF 0 "register_operand" "=e,e")
+ (abs:TF (match_operand:TF 1 "register_operand" "0,e")))]
+ ; We don't use quad float insns here so we don't need TARGET_HARD_QUAD.
+ "TARGET_FPU"
+ "*
+{
+ /* v9: can't use fabss, won't work with upper regs. */
+ if (which_alternative == 0)
+ return TARGET_V9 ? \"fabsd %0,%0\" : \"fabss %0,%0\";
+ else
+ return TARGET_V9 ? \"fabsd %1,%0\;fmovd %S1,%S0\"
+ : \"fabss %1,%0\;fmovs %R1,%R0\;fmovs %S1,%S0\;fmovs %T1,%T0\";
+}"
+ [(set_attr "type" "fpmove")
+ (set_attr_alternative "length"
+ [(const_int 1)
+ (if_then_else (eq_attr "isa" "v9") (const_int 2) (const_int 4))])])
+
+(define_insn "absdf2"
+ [(set (match_operand:DF 0 "register_operand" "=e,e")
+ (abs:DF (match_operand:DF 1 "register_operand" "0,e")))]
+ "TARGET_FPU"
+ "*
+{
+ if (TARGET_V9)
+ return \"fabsd %1,%0\";
+ else if (which_alternative == 0)
+ return \"fabss %0,%0\";
+ else
+ return \"fabss %1,%0\;fmovs %R1,%R0\";
+}"
+ [(set_attr "type" "fpmove")
+ (set_attr_alternative "length"
+ [(const_int 1)
+ (if_then_else (eq_attr "isa" "v9") (const_int 1) (const_int 2))])])
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (abs:SF (match_operand:SF 1 "register_operand" "f")))]
+ "TARGET_FPU"
+ "fabss %1,%0"
+ [(set_attr "type" "fpmove")])
+
+(define_insn "sqrttf2"
+ [(set (match_operand:TF 0 "register_operand" "=e")
+ (sqrt:TF (match_operand:TF 1 "register_operand" "e")))]
+ "TARGET_FPU && TARGET_HARD_QUAD"
+ "fsqrtq %1,%0"
+ [(set_attr "type" "fpsqrt")])
+
+(define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "register_operand" "=e")
+ (sqrt:DF (match_operand:DF 1 "register_operand" "e")))]
+ "TARGET_FPU"
+ "fsqrtd %1,%0"
+ [(set_attr "type" "fpsqrt")])
+
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=f")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "f")))]
+ "TARGET_FPU"
+ "fsqrts %1,%0"
+ [(set_attr "type" "fpsqrt")])
+
+;;- arithmetic shift instructions
+
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 31)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
+
+ return \"sll %1,%2,%0\";
+}"
+ [(set_attr "type" "shift")])
+
+(define_expand "ashldi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ "TARGET_ARCH64 || TARGET_V8PLUS"
+ "
+{
+ if (! TARGET_ARCH64)
+ {
+ if (GET_CODE (operands[2]) == CONST_INT)
+ FAIL;
+ emit_insn (gen_ashldi3_v8plus (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashift:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ "TARGET_ARCH64"
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 31)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
+
+ return \"sllx %1,%2,%0\";
+}")
+
+(define_insn "ashldi3_v8plus"
+ [(set (match_operand:DI 0 "register_operand" "=&h,&h,r")
+ (ashift:DI (match_operand:DI 1 "arith_operand" "rI,0,rI")
+ (match_operand:SI 2 "arith_operand" "rI,rI,rI")))
+ (clobber (match_scratch:SI 3 "=X,X,&h"))]
+ "TARGET_V8PLUS"
+ "*return sparc_v8plus_shift (operands, insn, \"sllx\");"
+ [(set_attr "length" "5,5,6")])
+
+;; Optimize (1LL<<x)-1
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=h")
+ (plus:DI (ashift:DI (const_int 1)
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (const_int -1)))]
+ "TARGET_V8PLUS"
+ "*
+{
+ if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == REGNO (operands[0]))
+ return \"mov 1,%L0\;sllx %L0,%2,%L0\;sub %L0,1,%L0\;srlx %L0,32,%H0\";
+ return \"mov 1,%H0\;sllx %H0,%2,%L0\;sub %L0,1,%L0\;srlx %L0,32,%H0\";
+}"
+ [(set_attr "length" "4")])
+
+(define_insn "*cmp_cc_ashift_1"
+ [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (ashift:SI (match_operand:SI 0 "register_operand" "r")
+ (const_int 1))
+ (const_int 0)))]
+ ""
+ "addcc %0,%0,%%g0"
+ [(set_attr "type" "compare")])
+
+(define_insn "*cmp_cc_set_ashift_1"
+ [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (ashift:SI (match_operand:SI 1 "register_operand" "r")
+ (const_int 1))
+ (const_int 0)))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (ashift:SI (match_dup 1) (const_int 1)))]
+ ""
+ "addcc %1,%1,%0")
+
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 31)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
+
+ return \"sra %1,%2,%0\";
+}"
+ [(set_attr "type" "shift")])
+
+(define_expand "ashrdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ "TARGET_ARCH64 || TARGET_V8PLUS"
+ "
+if (! TARGET_ARCH64)
+ {
+ if (GET_CODE (operands[2]) == CONST_INT)
+ FAIL; /* prefer generic code in this case */
+ emit_insn (gen_ashrdi3_v8plus (operands[0], operands[1], operands[2]));
+ DONE;
+ }")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (ashiftrt:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ "TARGET_ARCH64"
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 63)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
+
+ return \"srax %1,%2,%0\";
+}")
+
+(define_insn "ashrdi3_v8plus"
+ [(set (match_operand:DI 0 "register_operand" "=&h,&h,r")
+ (ashiftrt:DI (match_operand:DI 1 "arith_operand" "rI,0,rI")
+ (match_operand:SI 2 "arith_operand" "rI,rI,rI")))
+ (clobber (match_scratch:SI 3 "=X,X,&h"))]
+ "TARGET_V8PLUS"
+ "*return sparc_v8plus_shift (operands, insn, \"srax\");"
+ [(set_attr "length" "5,5,6")])
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 31)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
+
+ return \"srl %1,%2,%0\";
+}"
+ [(set_attr "type" "shift")])
+
+(define_expand "lshrdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lshiftrt:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ "TARGET_ARCH64 || TARGET_V8PLUS"
+ "
+if (! TARGET_ARCH64)
+ {
+ if (GET_CODE (operands[2]) == CONST_INT)
+ FAIL;
+ emit_insn (gen_lshrdi3_v8plus (operands[0], operands[1], operands[2]));
+ DONE;
+ }")
+
+(define_insn ""
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (lshiftrt:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ "TARGET_ARCH64"
+ "*
+{
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 63)
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
+
+ return \"srlx %1,%2,%0\";
+}")
+
+(define_insn "lshrdi3_v8plus"
+ [(set (match_operand:DI 0 "register_operand" "=&h,&h,r")
+ (lshiftrt:DI (match_operand:DI 1 "arith_operand" "rI,0,rI")
+ (match_operand:SI 2 "arith_operand" "rI,rI,rI")))
+ (clobber (match_scratch:SI 3 "=X,X,&h"))]
+ "TARGET_V8PLUS"
+ "*return sparc_v8plus_shift (operands, insn, \"srlx\");"
+ [(set_attr "length" "5,5,6")])
+
+;; Unconditional and other jump instructions
+;; On the Sparc, by setting the annul bit on an unconditional branch, the
+;; following insn is never executed. This saves us a nop. Dbx does not
+;; handle such branches though, so we only use them when optimizing.
+(define_insn "jump"
+ [(set (pc) (label_ref (match_operand 0 "" "")))]
+ ""
+ "*
+{
+ /* Some implementations (e.g. TurboSparc) are reported to have problems
+ with
+ foo: b,a foo
+ i.e. an empty loop with the annul bit set. The workaround is to use
+ foo: b foo; nop
+ instead. */
+
+ if (flag_delayed_branch
+ && (insn_addresses[INSN_UID (operands[0])]
+ == insn_addresses[INSN_UID (insn)]))
+ return \"b %l0%#\";
+ else
+ return \"b%* %l0%(\";
+}"
+ [(set_attr "type" "uncond_branch")])
+
+(define_expand "tablejump"
+ [(parallel [(set (pc) (match_operand 0 "register_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))])]
+ ""
+ "
+{
+ if (GET_MODE (operands[0]) != Pmode)
+ abort ();
+
+ /* In pic mode, our address differences are against the base of the
+ table. Add that base value back in; CSE ought to be able to combine
+ the two address loads. */
+ if (flag_pic)
+ {
+ rtx tmp, tmp2;
+ tmp = gen_rtx_LABEL_REF (Pmode, operands[1]);
+ tmp2 = operands[0];
+ tmp = gen_rtx_PLUS (Pmode, tmp2, tmp);
+ operands[0] = memory_address (Pmode, tmp);
+ }
+}")
+
+(define_insn "*tablejump_sp32"
+ [(set (pc) (match_operand:SI 0 "address_operand" "p"))
+ (use (label_ref (match_operand 1 "" "")))]
+ "! TARGET_PTR64"
+ "jmp %a0%#"
+ [(set_attr "type" "uncond_branch")])
+
+(define_insn "*tablejump_sp64"
+ [(set (pc) (match_operand:DI 0 "address_operand" "p"))
+ (use (label_ref (match_operand 1 "" "")))]
+ "TARGET_PTR64"
+ "jmp %a0%#"
+ [(set_attr "type" "uncond_branch")])
+
+;; This pattern recognizes the "instruction" that appears in
+;; a function call that wants a structure value,
+;; to inform the called function if compiled with Sun CC.
+;(define_insn "*unimp_insn"
+; [(match_operand:SI 0 "immediate_operand" "")]
+; "GET_CODE (operands[0]) == CONST_INT && INTVAL (operands[0]) > 0"
+; "unimp %0"
+; [(set_attr "type" "marker")])
+
+;;- jump to subroutine
+(define_expand "call"
+ ;; Note that this expression is not used for generating RTL.
+ ;; All the RTL is generated explicitly below.
+ [(call (match_operand 0 "call_operand" "")
+ (match_operand 3 "" "i"))]
+ ;; operands[2] is next_arg_register
+ ;; operands[3] is struct_value_size_rtx.
+ ""
+ "
+{
+ rtx fn_rtx, nregs_rtx;
+
+ if (GET_MODE (operands[0]) != FUNCTION_MODE)
+ abort ();
+
+ if (GET_CODE (XEXP (operands[0], 0)) == LABEL_REF)
+ {
+ /* This is really a PIC sequence. We want to represent
+ it as a funny jump so its delay slots can be filled.
+
+ ??? But if this really *is* a CALL, will not it clobber the
+ call-clobbered registers? We lose this if it is a JUMP_INSN.
+ Why cannot we have delay slots filled if it were a CALL? */
+
+ if (! TARGET_ARCH64 && INTVAL (operands[3]) != 0)
+ emit_jump_insn
+ (gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (3,
+ gen_rtx_SET (VOIDmode, pc_rtx,
+ XEXP (operands[0], 0)),
+ GEN_INT (INTVAL (operands[3]) & 0xfff),
+ gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_REG (Pmode, 15)))));
+ else
+ emit_jump_insn
+ (gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2,
+ gen_rtx_SET (VOIDmode, pc_rtx,
+ XEXP (operands[0], 0)),
+ gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_REG (Pmode, 15)))));
+ goto finish_call;
+ }
+
+ fn_rtx = operands[0];
+
+ /* Count the number of parameter registers being used by this call.
+ if that argument is NULL, it means we are using them all, which
+ means 6 on the sparc. */
+#if 0
+ if (operands[2])
+ nregs_rtx = GEN_INT (REGNO (operands[2]) - 8);
+ else
+ nregs_rtx = GEN_INT (6);
+#else
+ nregs_rtx = const0_rtx;
+#endif
+
+ if (! TARGET_ARCH64 && INTVAL (operands[3]) != 0)
+ emit_call_insn
+ (gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (3, gen_rtx_CALL (VOIDmode, fn_rtx, nregs_rtx),
+ GEN_INT (INTVAL (operands[3]) & 0xfff),
+ gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_REG (Pmode, 15)))));
+ else
+ emit_call_insn
+ (gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (2, gen_rtx_CALL (VOIDmode, fn_rtx, nregs_rtx),
+ gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_REG (Pmode, 15)))));
+
+ finish_call:
+#if 0
+ /* If this call wants a structure value,
+ emit an unimp insn to let the called function know about this. */
+ if (! TARGET_ARCH64 && INTVAL (operands[3]) > 0)
+ {
+ rtx insn = emit_insn (operands[3]);
+ SCHED_GROUP_P (insn) = 1;
+ }
+#endif
+
+ DONE;
+}")
+
+;; We can't use the same pattern for these two insns, because then registers
+;; in the address may not be properly reloaded.
+
+(define_insn "*call_address_sp32"
+ [(call (mem:SI (match_operand:SI 0 "address_operand" "p"))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI 15))]
+ ;;- Do not use operand 1 for most machines.
+ "! TARGET_PTR64"
+ "call %a0,%1%#"
+ [(set_attr "type" "call")])
+
+(define_insn "*call_symbolic_sp32"
+ [(call (mem:SI (match_operand:SI 0 "symbolic_operand" "s"))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI 15))]
+ ;;- Do not use operand 1 for most machines.
+ "! TARGET_PTR64"
+ "call %a0,%1%#"
+ [(set_attr "type" "call")])
+
+(define_insn "*call_address_sp64"
+ [(call (mem:SI (match_operand:DI 0 "address_operand" "p"))
+ (match_operand 1 "" ""))
+ (clobber (reg:DI 15))]
+ ;;- Do not use operand 1 for most machines.
+ "TARGET_PTR64"
+ "call %a0,%1%#"
+ [(set_attr "type" "call")])
+
+(define_insn "*call_symbolic_sp64"
+ [(call (mem:SI (match_operand:DI 0 "symbolic_operand" "s"))
+ (match_operand 1 "" ""))
+ (clobber (reg:DI 15))]
+ ;;- Do not use operand 1 for most machines.
+ "TARGET_PTR64"
+ "call %a0,%1%#"
+ [(set_attr "type" "call")])
+
+;; This is a call that wants a structure value.
+;; There is no such critter for v9 (??? we may need one anyway).
+(define_insn "*call_address_struct_value_sp32"
+ [(call (mem:SI (match_operand:SI 0 "address_operand" "p"))
+ (match_operand 1 "" ""))
+ (match_operand 2 "immediate_operand" "")
+ (clobber (reg:SI 15))]
+ ;;- Do not use operand 1 for most machines.
+ "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0"
+ "call %a0,%1\;nop\;unimp %2"
+ [(set_attr "type" "call_no_delay_slot")])
+
+;; This is a call that wants a structure value.
+;; There is no such critter for v9 (??? we may need one anyway).
+(define_insn "*call_symbolic_struct_value_sp32"
+ [(call (mem:SI (match_operand:SI 0 "symbolic_operand" "s"))
+ (match_operand 1 "" ""))
+ (match_operand 2 "immediate_operand" "")
+ (clobber (reg:SI 15))]
+ ;;- Do not use operand 1 for most machines.
+ "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0"
+ "call %a0,%1\;nop\;unimp %2"
+ [(set_attr "type" "call_no_delay_slot")])
+
+;; This is a call that may want a structure value. This is used for
+;; untyped_calls.
+(define_insn "*call_address_untyped_struct_value_sp32"
+ [(call (mem:SI (match_operand:SI 0 "address_operand" "p"))
+ (match_operand 1 "" ""))
+ (match_operand 2 "immediate_operand" "")
+ (clobber (reg:SI 15))]
+ ;;- Do not use operand 1 for most machines.
+ "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0"
+ "call %a0,%1\;nop\;nop"
+ [(set_attr "type" "call_no_delay_slot")])
+
+;; This is a call that wants a structure value.
+(define_insn "*call_symbolic_untyped_struct_value_sp32"
+ [(call (mem:SI (match_operand:SI 0 "symbolic_operand" "s"))
+ (match_operand 1 "" ""))
+ (match_operand 2 "immediate_operand" "")
+ (clobber (reg:SI 15))]
+ ;;- Do not use operand 1 for most machines.
+ "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0"
+ "call %a0,%1\;nop\;nop"
+ [(set_attr "type" "call_no_delay_slot")])
+
+(define_expand "call_value"
+ ;; Note that this expression is not used for generating RTL.
+ ;; All the RTL is generated explicitly below.
+ [(set (match_operand 0 "register_operand" "=rf")
+ (call (match_operand:SI 1 "" "")
+ (match_operand 4 "" "")))]
+ ;; operand 2 is stack_size_rtx
+ ;; operand 3 is next_arg_register
+ ""
+ "
+{
+ rtx fn_rtx, nregs_rtx;
+ rtvec vec;
+
+ if (GET_MODE (operands[1]) != FUNCTION_MODE)
+ abort ();
+
+ fn_rtx = operands[1];
+
+#if 0
+ if (operands[3])
+ nregs_rtx = GEN_INT (REGNO (operands[3]) - 8);
+ else
+ nregs_rtx = GEN_INT (6);
+#else
+ nregs_rtx = const0_rtx;
+#endif
+
+ vec = gen_rtvec (2,
+ gen_rtx_SET (VOIDmode, operands[0],
+ gen_rtx_CALL (VOIDmode, fn_rtx, nregs_rtx)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 15)));
+
+ emit_call_insn (gen_rtx_PARALLEL (VOIDmode, vec));
+
+ DONE;
+}")
+
+(define_insn "*call_value_address_sp32"
+ [(set (match_operand 0 "" "=rf")
+ (call (mem:SI (match_operand:SI 1 "address_operand" "p"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI 15))]
+ ;;- Do not use operand 2 for most machines.
+ "! TARGET_PTR64"
+ "call %a1,%2%#"
+ [(set_attr "type" "call")])
+
+(define_insn "*call_value_symbolic_sp32"
+ [(set (match_operand 0 "" "=rf")
+ (call (mem:SI (match_operand:SI 1 "symbolic_operand" "s"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI 15))]
+ ;;- Do not use operand 2 for most machines.
+ "! TARGET_PTR64"
+ "call %a1,%2%#"
+ [(set_attr "type" "call")])
+
+(define_insn "*call_value_address_sp64"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:DI 1 "address_operand" "p"))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 15))]
+ ;;- Do not use operand 2 for most machines.
+ "TARGET_PTR64"
+ "call %a1,%2%#"
+ [(set_attr "type" "call")])
+
+(define_insn "*call_value_symbolic_sp64"
+ [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:DI 1 "symbolic_operand" "s"))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 15))]
+ ;;- Do not use operand 2 for most machines.
+ "TARGET_PTR64"
+ "call %a1,%2%#"
+ [(set_attr "type" "call")])
+
+(define_expand "untyped_call"
+ [(parallel [(call (match_operand 0 "" "")
+ (const_int 0))
+ (match_operand 1 "" "")
+ (match_operand 2 "" "")])]
+ ""
+ "
+{
+ int i;
+
+ /* Pass constm1 to indicate that it may expect a structure value, but
+ we don't know what size it is. */
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL, constm1_rtx));
+
+ for (i = 0; i < XVECLEN (operands[2], 0); i++)
+ {
+ rtx set = XVECEXP (operands[2], 0, i);
+ emit_move_insn (SET_DEST (set), SET_SRC (set));
+ }
+
+ /* The optimizer does not know that the call sets the function value
+ registers we stored in the result block. We avoid problems by
+ claiming that all hard registers are used and clobbered at this
+ point. */
+ emit_insn (gen_blockage ());
+
+ DONE;
+}")
+
+;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
+;; all of memory. This blocks insns from being moved across this point.
+
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] 0)]
+ ""
+ "")
+
+;; Prepare to return any type including a structure value.
+
+(define_expand "untyped_return"
+ [(match_operand:BLK 0 "memory_operand" "")
+ (match_operand 1 "" "")]
+ ""
+ "
+{
+ rtx valreg1 = gen_rtx_REG (DImode, 24);
+ rtx valreg2 = gen_rtx_REG (TARGET_ARCH64 ? TFmode : DFmode, 32);
+ rtx result = operands[0];
+
+ if (! TARGET_ARCH64)
+ {
+ rtx rtnreg = gen_rtx_REG (SImode, (leaf_function ? 15 : 31));
+ rtx value = gen_reg_rtx (SImode);
+
+ /* Fetch the instruction where we will return to and see if it's an unimp
+ instruction (the most significant 10 bits will be zero). If so,
+ update the return address to skip the unimp instruction. */
+ emit_move_insn (value,
+ gen_rtx_MEM (SImode, plus_constant (rtnreg, 8)));
+ emit_insn (gen_lshrsi3 (value, value, GEN_INT (22)));
+ emit_insn (gen_update_return (rtnreg, value));
+ }
+
+ /* Reload the function value registers. */
+ emit_move_insn (valreg1, change_address (result, DImode, XEXP (result, 0)));
+ emit_move_insn (valreg2,
+ change_address (result, TARGET_ARCH64 ? TFmode : DFmode,
+ plus_constant (XEXP (result, 0), 8)));
+
+ /* Put USE insns before the return. */
+ emit_insn (gen_rtx_USE (VOIDmode, valreg1));
+ emit_insn (gen_rtx_USE (VOIDmode, valreg2));
+
+ /* Construct the return. */
+ expand_null_return ();
+
+ DONE;
+}")
+
+;; This is a bit of a hack. We're incrementing a fixed register (%i7),
+;; and parts of the compiler don't want to believe that the add is needed.
+
+(define_insn "update_return"
+ [(unspec:SI [(match_operand:SI 0 "register_operand" "r")
+ (match_operand:SI 1 "register_operand" "r")] 1)]
+ "! TARGET_ARCH64"
+ "cmp %1,0\;be,a .+8\;add %0,4,%0"
+ [(set_attr "type" "multi")])
+
+(define_insn "return"
+ [(return)
+ (use (reg:SI 31))]
+ "! TARGET_EPILOGUE"
+ "* return output_return (operands);"
+ [(set_attr "type" "return")])
+
+(define_peephole
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operand:SI 1 "arith_operand" "rI"))
+ (parallel [(return)
+ (use (reg:SI 31))])]
+ "sparc_return_peephole_ok (operands[0], operands[1])"
+ "return %%i7+8\;mov %Y1,%Y0")
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop")
+
+(define_expand "indirect_jump"
+ [(set (pc) (match_operand 0 "address_operand" "p"))]
+ ""
+ "")
+
+(define_insn "*branch_sp32"
+ [(set (pc) (match_operand:SI 0 "address_operand" "p"))]
+ "! TARGET_PTR64"
+ "jmp %a0%#"
+ [(set_attr "type" "uncond_branch")])
+
+(define_insn "*branch_sp64"
+ [(set (pc) (match_operand:DI 0 "address_operand" "p"))]
+ "TARGET_PTR64"
+ "jmp %a0%#"
+ [(set_attr "type" "uncond_branch")])
+
+;; ??? Doesn't work with -mflat.
+(define_expand "nonlocal_goto"
+ [(match_operand:SI 0 "general_operand" "")
+ (match_operand:SI 1 "general_operand" "")
+ (match_operand:SI 2 "general_operand" "")
+ (match_operand:SI 3 "" "")]
+ ""
+ "
+{
+ rtx chain = operands[0];
+ rtx fp = operands[1];
+ rtx stack = operands[2];
+ rtx lab = operands[3];
+ rtx labreg;
+
+ /* Trap instruction to flush all the register windows. */
+ emit_insn (gen_flush_register_windows ());
+
+ /* Load the fp value for the containing fn into %fp. This is needed
+ because STACK refers to %fp. Note that virtual register instantiation
+ fails if the virtual %fp isn't set from a register. */
+ if (GET_CODE (fp) != REG)
+ fp = force_reg (Pmode, fp);
+ emit_move_insn (virtual_stack_vars_rtx, fp);
+
+ /* Find the containing function's current nonlocal goto handler,
+ which will do any cleanups and then jump to the label. */
+ labreg = gen_rtx_REG (Pmode, 8);
+ emit_move_insn (labreg, lab);
+
+ /* Restore %fp from stack pointer value for containing function.
+ The restore insn that follows will move this to %sp,
+ and reload the appropriate value into %fp. */
+ emit_move_insn (frame_pointer_rtx, stack);
+
+ /* USE of frame_pointer_rtx added for consistency; not clear if
+ really needed. */
+ /*emit_insn (gen_rtx_USE (VOIDmode, frame_pointer_rtx));*/
+ emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
+ /* Return, restoring reg window and jumping to goto handler. */
+ if (TARGET_V9 && GET_CODE (chain) == CONST_INT
+ && ! (INTVAL (chain) & ~(HOST_WIDE_INT)0xffffffff))
+ {
+ emit_insn (gen_goto_handler_and_restore_v9 (labreg, static_chain_rtx,
+ chain));
+ emit_barrier ();
+ DONE;
+ }
+ /* Put in the static chain register the nonlocal label address. */
+ emit_move_insn (static_chain_rtx, chain);
+ emit_insn (gen_rtx_USE (VOIDmode, static_chain_rtx));
+ emit_insn (gen_goto_handler_and_restore (labreg));
+ emit_barrier ();
+ DONE;
+}")
+
+;; Special trap insn to flush register windows.
+(define_insn "flush_register_windows"
+ [(unspec_volatile [(const_int 0)] 1)]
+ ""
+ "* return TARGET_V9 ? \"flushw\" : \"ta 3\";"
+ [(set_attr "type" "misc")])
+
+(define_insn "goto_handler_and_restore"
+ [(unspec_volatile [(match_operand:SI 0 "register_operand" "=r")] 2)]
+ ""
+ "jmp %0+0\;restore"
+ [(set_attr "type" "misc")
+ (set_attr "length" "2")])
+
+(define_insn "goto_handler_and_restore_v9"
+ [(unspec_volatile [(match_operand:SI 0 "register_operand" "=r,r")
+ (match_operand:SI 1 "register_operand" "=r,r")
+ (match_operand:SI 2 "const_int_operand" "I,n")] 3)]
+ "TARGET_V9 && ! TARGET_ARCH64"
+ "@
+ return %0+0\;mov %2,%Y1
+ sethi %%hi(%2),%1\;return %0+0\;or %Y1,%%lo(%2),%Y1"
+ [(set_attr "type" "misc")
+ (set_attr "length" "2,3")])
+
+(define_insn "*goto_handler_and_restore_v9_sp64"
+ [(unspec_volatile [(match_operand:DI 0 "register_operand" "=r,r")
+ (match_operand:DI 1 "register_operand" "=r,r")
+ (match_operand:SI 2 "const_int_operand" "I,n")] 3)]
+ "TARGET_V9 && TARGET_ARCH64"
+ "@
+ return %0+0\;mov %2,%Y1
+ sethi %%hi(%2),%1\;return %0+0\;or %Y1,%%lo(%2),%Y1"
+ [(set_attr "type" "misc")
+ (set_attr "length" "2,3")])
+
+;; Pattern for use after a setjmp to store FP and the return register
+;; into the stack area.
+
+(define_expand "setjmp"
+ [(const_int 0)]
+ ""
+ "
+{
+ if (TARGET_ARCH64)
+ emit_insn (gen_setjmp_64 ());
+ else
+ emit_insn (gen_setjmp_32 ());
+ DONE;
+}")
+
+(define_expand "setjmp_32"
+ [(set (mem:SI (plus:SI (reg:SI 14) (const_int 56))) (match_dup 0))
+ (set (mem:SI (plus:SI (reg:SI 14) (const_int 60))) (reg:SI 31))]
+ ""
+ "
+{ operands[0] = frame_pointer_rtx; }")
+
+(define_expand "setjmp_64"
+ [(set (mem:DI (plus:DI (reg:DI 14) (const_int 112))) (match_dup 0))
+ (set (mem:DI (plus:DI (reg:DI 14) (const_int 120))) (reg:DI 31))]
+ ""
+ "
+{ operands[0] = frame_pointer_rtx; }")
+
+;; Special pattern for the FLUSH instruction.
+
+(define_insn "flush"
+ [(unspec_volatile [(match_operand 0 "memory_operand" "m")] 3)]
+ ""
+ "* return TARGET_V9 ? \"flush %f0\" : \"iflush %f0\";"
+ [(set_attr "type" "misc")])
+
+;; find first set.
+
+;; The scan instruction searches from the most significant bit while ffs
+;; searches from the least significant bit. The bit index and treatment of
+;; zero also differ. It takes at least 7 instructions to get the proper
+;; result. Here is an obvious 8 instruction sequence.
+
+(define_insn "ffssi2"
+ [(set (match_operand:SI 0 "register_operand" "=&r")
+ (ffs:SI (match_operand:SI 1 "register_operand" "r")))
+ (clobber (match_scratch:SI 2 "=&r"))]
+ "TARGET_SPARCLITE || TARGET_SPARCLET"
+ "*
+{
+ if (TARGET_LIVE_G0)
+ output_asm_insn (\"and %%g0,0,%%g0\", operands);
+ return \"sub %%g0,%1,%0\;and %0,%1,%0\;scan %0,0,%0\;mov 32,%2\;sub %2,%0,%0\;sra %0,31,%2\;and %2,31,%2\;add %2,%0,%0\";
+}"
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+;; ??? This should be a define expand, so that the extra instruction have
+;; a chance of being optimized away.
+
+;; Disabled because none of the UltraSparcs implement popc. The HAL R1
+;; does, but no one uses that and we don't have a switch for it.
+;
+;(define_insn "ffsdi2"
+; [(set (match_operand:DI 0 "register_operand" "=&r")
+; (ffs:DI (match_operand:DI 1 "register_operand" "r")))
+; (clobber (match_scratch:DI 2 "=&r"))]
+; "TARGET_ARCH64"
+; "neg %1,%2\;xnor %1,%2,%2\;popc %2,%0\;movzr %1,0,%0"
+; [(set_attr "type" "multi")
+; (set_attr "length" "4")])
+
+;; Split up troublesome insns for better scheduling. */
+
+;; The following patterns are straightforward. They can be applied
+;; either before or after register allocation.
+
+(define_split
+ [(set (match_operand 0 "splittable_symbolic_memory_operand" "")
+ (match_operand 1 "reg_or_0_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" ""))]
+ "! flag_pic"
+ [(set (match_dup 2) (high:SI (match_dup 3)))
+ (set (match_dup 4) (match_dup 1))]
+ "
+{
+ operands[3] = XEXP (operands[0], 0);
+ operands[4] = gen_rtx_MEM (GET_MODE (operands[0]),
+ gen_rtx_LO_SUM (SImode, operands[2], operands[3]));
+ MEM_IN_STRUCT_P (operands[4]) = MEM_IN_STRUCT_P (operands[0]);
+ MEM_VOLATILE_P (operands[4]) = MEM_VOLATILE_P (operands[0]);
+ RTX_UNCHANGING_P (operands[4]) = RTX_UNCHANGING_P (operands[0]);
+}")
+
+(define_split
+ [(set (match_operand 0 "splittable_immediate_memory_operand" "")
+ (match_operand 1 "general_operand" ""))
+ (clobber (match_operand:SI 2 "register_operand" ""))]
+ "flag_pic"
+ [(set (match_dup 3) (match_dup 1))]
+ "
+{
+ rtx addr = legitimize_pic_address (XEXP (operands[0], 0),
+ GET_MODE (operands[0]),
+ operands[2]);
+ operands[3] = gen_rtx_MEM (GET_MODE (operands[0]), addr);
+ MEM_IN_STRUCT_P (operands[3]) = MEM_IN_STRUCT_P (operands[0]);
+ MEM_VOLATILE_P (operands[3]) = MEM_VOLATILE_P (operands[0]);
+ RTX_UNCHANGING_P (operands[3]) = RTX_UNCHANGING_P (operands[0]);
+}")
+
+(define_split
+ [(set (match_operand 0 "register_operand" "")
+ (match_operand 1 "splittable_immediate_memory_operand" ""))]
+ "flag_pic"
+ [(set (match_dup 0) (match_dup 2))]
+ "
+{
+ rtx addr = legitimize_pic_address (XEXP (operands[1], 0),
+ GET_MODE (operands[1]),
+ operands[0]);
+ operands[2] = gen_rtx_MEM (GET_MODE (operands[1]), addr);
+ MEM_IN_STRUCT_P (operands[2]) = MEM_IN_STRUCT_P (operands[1]);
+ MEM_VOLATILE_P (operands[2]) = MEM_VOLATILE_P (operands[1]);
+ RTX_UNCHANGING_P (operands[2]) = RTX_UNCHANGING_P (operands[1]);
+}")
+
+;; Sign- and Zero-extend operations can have symbolic memory operands.
+
+(define_split
+ [(set (match_operand 0 "register_operand" "")
+ (match_operator 1 "extend_op" [(match_operand 2 "splittable_immediate_memory_operand" "")]))]
+ "flag_pic"
+ [(set (match_dup 0) (match_op_dup 1 [(match_dup 3)]))]
+ "
+{
+ rtx addr = legitimize_pic_address (XEXP (operands[2], 0),
+ GET_MODE (operands[2]),
+ operands[0]);
+ operands[3] = gen_rtx_MEM (GET_MODE (operands[2]), addr);
+ MEM_IN_STRUCT_P (operands[3]) = MEM_IN_STRUCT_P (operands[2]);
+ MEM_VOLATILE_P (operands[3]) = MEM_VOLATILE_P (operands[2]);
+ RTX_UNCHANGING_P (operands[3]) = RTX_UNCHANGING_P (operands[2]);
+}")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "immediate_operand" ""))]
+ "! flag_pic && (GET_CODE (operands[1]) == SYMBOL_REF
+ || GET_CODE (operands[1]) == CONST
+ || GET_CODE (operands[1]) == LABEL_REF)"
+ [(set (match_dup 0) (high:SI (match_dup 1)))
+ (set (match_dup 0)
+ (lo_sum:SI (match_dup 0) (match_dup 1)))]
+ "")
+
+;; LABEL_REFs are not modified by `legitimize_pic_address'
+;; so do not recurse infinitely in the PIC case.
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "immediate_operand" ""))]
+ "flag_pic && (GET_CODE (operands[1]) == SYMBOL_REF
+ || GET_CODE (operands[1]) == CONST)"
+ [(set (match_dup 0) (match_dup 1))]
+ "
+{
+ operands[1] = legitimize_pic_address (operands[1], Pmode, operands[0]);
+}")
+
+;; These split sne/seq insns. The forms of the resulting insns are
+;; somewhat bogus, but they avoid extra patterns and show data dependency.
+;; Nothing will look at these in detail after splitting has occurred.
+
+;; ??? v9 DImode versions are missing because addc and subc use %icc.
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (ne:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 0)))
+ (clobber (reg:CC 100))]
+ ""
+ [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0) (ltu:SI (reg:CC 100) (const_int 0)))]
+ "")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (neg:SI (ne:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 0))))
+ (clobber (reg:CC 100))]
+ ""
+ [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0) (neg:SI (ltu:SI (reg:CC 100) (const_int 0))))]
+ "")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (eq:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 0)))
+ (clobber (reg:CC 100))]
+ ""
+ [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0) (geu:SI (reg:CC 100) (const_int 0)))]
+ "")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (neg:SI (eq:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 0))))
+ (clobber (reg:CC 100))]
+ ""
+ [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0) (neg:SI (geu:SI (reg:CC 100) (const_int 0))))]
+ "")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (ne:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 0))
+ (match_operand:SI 2 "register_operand" "")))
+ (clobber (reg:CC 100))]
+ ""
+ [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0) (plus:SI (ltu:SI (reg:CC 100) (const_int 0))
+ (match_dup 2)))]
+ "")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (minus:SI (match_operand:SI 2 "register_operand" "")
+ (ne:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 0))))
+ (clobber (reg:CC 100))]
+ ""
+ [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0) (minus:SI (match_dup 2)
+ (ltu:SI (reg:CC 100) (const_int 0))))]
+ "")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (eq:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 0))
+ (match_operand:SI 2 "register_operand" "")))
+ (clobber (reg:CC 100))]
+ ""
+ [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0) (plus:SI (geu:SI (reg:CC 100) (const_int 0))
+ (match_dup 2)))]
+ "")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (minus:SI (match_operand:SI 2 "register_operand" "")
+ (eq:SI (match_operand:SI 1 "register_operand" "")
+ (const_int 0))))
+ (clobber (reg:CC 100))]
+ ""
+ [(set (reg:CC_NOOV 100) (compare:CC_NOOV (neg:SI (match_dup 1))
+ (const_int 0)))
+ (set (match_dup 0) (minus:SI (match_dup 2)
+ (geu:SI (reg:CC 100) (const_int 0))))]
+ "")
+
+;; Peepholes go at the end.
+
+;; Optimize consecutive loads or stores into ldd and std when possible.
+;; The conditions in which we do this are very restricted and are
+;; explained in the code for {registers,memory}_ok_for_ldd functions.
+
+(define_peephole
+ [(set (match_operand:SI 0 "memory_operand" "")
+ (const_int 0))
+ (set (match_operand:SI 1 "memory_operand" "")
+ (const_int 0))]
+ "TARGET_V9
+ && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[1])
+ && addrs_ok_for_ldd_peep (XEXP (operands[0], 0), XEXP (operands[1], 0))"
+ "stx %%g0,%0")
+
+(define_peephole
+ [(set (match_operand:SI 0 "memory_operand" "")
+ (const_int 0))
+ (set (match_operand:SI 1 "memory_operand" "")
+ (const_int 0))]
+ "TARGET_V9
+ && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[1])
+ && addrs_ok_for_ldd_peep (XEXP (operands[1], 0), XEXP (operands[0], 0))"
+ "stx %%g0,%1")
+
+(define_peephole
+ [(set (match_operand:SI 0 "register_operand" "=rf")
+ (match_operand:SI 1 "memory_operand" ""))
+ (set (match_operand:SI 2 "register_operand" "=rf")
+ (match_operand:SI 3 "memory_operand" ""))]
+ "registers_ok_for_ldd_peep (operands[0], operands[2])
+ && ! MEM_VOLATILE_P (operands[1]) && ! MEM_VOLATILE_P (operands[3])
+ && addrs_ok_for_ldd_peep (XEXP (operands[1], 0), XEXP (operands[3], 0))"
+ "ldd %1,%0")
+
+(define_peephole
+ [(set (match_operand:SI 0 "memory_operand" "")
+ (match_operand:SI 1 "register_operand" "rf"))
+ (set (match_operand:SI 2 "memory_operand" "")
+ (match_operand:SI 3 "register_operand" "rf"))]
+ "registers_ok_for_ldd_peep (operands[1], operands[3])
+ && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[2])
+ && addrs_ok_for_ldd_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))"
+ "std %1,%0")
+
+(define_peephole
+ [(set (match_operand:SF 0 "register_operand" "=fr")
+ (match_operand:SF 1 "memory_operand" ""))
+ (set (match_operand:SF 2 "register_operand" "=fr")
+ (match_operand:SF 3 "memory_operand" ""))]
+ "registers_ok_for_ldd_peep (operands[0], operands[2])
+ && ! MEM_VOLATILE_P (operands[1]) && ! MEM_VOLATILE_P (operands[3])
+ && addrs_ok_for_ldd_peep (XEXP (operands[1], 0), XEXP (operands[3], 0))"
+ "ldd %1,%0")
+
+(define_peephole
+ [(set (match_operand:SF 0 "memory_operand" "")
+ (match_operand:SF 1 "register_operand" "fr"))
+ (set (match_operand:SF 2 "memory_operand" "")
+ (match_operand:SF 3 "register_operand" "fr"))]
+ "registers_ok_for_ldd_peep (operands[1], operands[3])
+ && ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[2])
+ && addrs_ok_for_ldd_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))"
+ "std %1,%0")
+
+(define_peephole
+ [(set (match_operand:SI 0 "register_operand" "=rf")
+ (match_operand:SI 1 "memory_operand" ""))
+ (set (match_operand:SI 2 "register_operand" "=rf")
+ (match_operand:SI 3 "memory_operand" ""))]
+ "registers_ok_for_ldd_peep (operands[2], operands[0])
+ && ! MEM_VOLATILE_P (operands[3]) && ! MEM_VOLATILE_P (operands[1])
+ && addrs_ok_for_ldd_peep (XEXP (operands[3], 0), XEXP (operands[1], 0))"
+ "ldd %3,%2")
+
+(define_peephole
+ [(set (match_operand:SI 0 "memory_operand" "")
+ (match_operand:SI 1 "register_operand" "rf"))
+ (set (match_operand:SI 2 "memory_operand" "")
+ (match_operand:SI 3 "register_operand" "rf"))]
+ "registers_ok_for_ldd_peep (operands[3], operands[1])
+ && ! MEM_VOLATILE_P (operands[2]) && ! MEM_VOLATILE_P (operands[0])
+ && addrs_ok_for_ldd_peep (XEXP (operands[2], 0), XEXP (operands[0], 0))"
+ "std %3,%2")
+
+(define_peephole
+ [(set (match_operand:SF 0 "register_operand" "=fr")
+ (match_operand:SF 1 "memory_operand" ""))
+ (set (match_operand:SF 2 "register_operand" "=fr")
+ (match_operand:SF 3 "memory_operand" ""))]
+ "registers_ok_for_ldd_peep (operands[2], operands[0])
+ && ! MEM_VOLATILE_P (operands[3]) && ! MEM_VOLATILE_P (operands[1])
+ && addrs_ok_for_ldd_peep (XEXP (operands[3], 0), XEXP (operands[1], 0))"
+ "ldd %3,%2")
+
+(define_peephole
+ [(set (match_operand:SF 0 "memory_operand" "")
+ (match_operand:SF 1 "register_operand" "fr"))
+ (set (match_operand:SF 2 "memory_operand" "")
+ (match_operand:SF 3 "register_operand" "fr"))]
+ "registers_ok_for_ldd_peep (operands[3], operands[1])
+ && ! MEM_VOLATILE_P (operands[2]) && ! MEM_VOLATILE_P (operands[0])
+ && addrs_ok_for_ldd_peep (XEXP (operands[2], 0), XEXP (operands[0], 0))"
+ "std %3,%2")
+
+;; Optimize the case of following a reg-reg move with a test
+;; of reg just moved. Don't allow floating point regs for operand 0 or 1.
+;; This can result from a float to fix conversion.
+
+(define_peephole
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (match_operand:SI 1 "register_operand" "r"))
+ (set (reg:CC 100)
+ (compare:CC (match_operand:SI 2 "register_operand" "r")
+ (const_int 0)))]
+ "(rtx_equal_p (operands[2], operands[0])
+ || rtx_equal_p (operands[2], operands[1]))
+ && ! FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])"
+ "orcc %1,0,%0")
+
+(define_peephole
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (match_operand:DI 1 "register_operand" "r"))
+ (set (reg:CCX 100)
+ (compare:CCX (match_operand:DI 2 "register_operand" "r")
+ (const_int 0)))]
+ "TARGET_ARCH64
+ && (rtx_equal_p (operands[2], operands[0])
+ || rtx_equal_p (operands[2], operands[1]))
+ && ! FP_REG_P (operands[0]) && ! FP_REG_P (operands[1])"
+ "orcc %1,0,%0")
+
+;; Floating-point move peepholes
+;; ??? v9: Do we want similar ones?
+
+(define_peephole
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_dup 0)
+ (match_operand:SI 1 "immediate_operand" "i")))
+ (set (match_operand:DF 2 "register_operand" "=er")
+ (mem:DF (match_dup 0)))]
+ "RTX_UNCHANGING_P (operands[1]) && reg_unused_after (operands[0], insn)"
+ "*
+{
+ /* Go by way of output_move_double in case the register in operand 2
+ is not properly aligned for ldd. */
+ operands[1] = gen_rtx_MEM (DFmode,
+ gen_rtx_LO_SUM (SImode, operands[0], operands[1]));
+ operands[0] = operands[2];
+ return output_move_double (operands);
+}")
+
+(define_peephole
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lo_sum:SI (match_dup 0)
+ (match_operand:SI 1 "immediate_operand" "i")))
+ (set (match_operand:SF 2 "register_operand" "=fr")
+ (mem:SF (match_dup 0)))]
+ "RTX_UNCHANGING_P (operands[1]) && reg_unused_after (operands[0], insn)"
+ "ld [%0+%%lo(%a1)],%2")
+
+;; Return peepholes. First the "normal" ones.
+;; These are necessary to catch insns ending up in the epilogue delay list.
+
+(define_insn "*return_qi"
+ [(set (match_operand:QI 0 "restore_operand" "")
+ (match_operand:QI 1 "arith_operand" "rI"))
+ (return)]
+ "! TARGET_EPILOGUE && ! TARGET_LIVE_G0"
+ "*
+{
+ if (! TARGET_ARCH64 && current_function_returns_struct)
+ return \"jmp %%i7+12\;restore %%g0,%1,%Y0\";
+ else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT
+ || IN_OR_GLOBAL_P (operands[1])))
+ return \"return %%i7+8\;mov %Y1,%Y0\";
+ else
+ return \"ret\;restore %%g0,%1,%Y0\";
+}"
+ [(set_attr "type" "multi")])
+
+(define_insn "*return_hi"
+ [(set (match_operand:HI 0 "restore_operand" "")
+ (match_operand:HI 1 "arith_operand" "rI"))
+ (return)]
+ "! TARGET_EPILOGUE && ! TARGET_LIVE_G0"
+ "*
+{
+ if (! TARGET_ARCH64 && current_function_returns_struct)
+ return \"jmp %%i7+12\;restore %%g0,%1,%Y0\";
+ else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT
+ || IN_OR_GLOBAL_P (operands[1])))
+ return \"return %%i7+8\;mov %Y1,%Y0\";
+ else
+ return \"ret\;restore %%g0,%1,%Y0\";
+}"
+ [(set_attr "type" "multi")])
+
+(define_insn "*return_si"
+ [(set (match_operand:SI 0 "restore_operand" "")
+ (match_operand:SI 1 "arith_operand" "rI"))
+ (return)]
+ "! TARGET_EPILOGUE && ! TARGET_LIVE_G0"
+ "*
+{
+ if (! TARGET_ARCH64 && current_function_returns_struct)
+ return \"jmp %%i7+12\;restore %%g0,%1,%Y0\";
+ else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT
+ || IN_OR_GLOBAL_P (operands[1])))
+ return \"return %%i7+8\;mov %Y1,%Y0\";
+ else
+ return \"ret\;restore %%g0,%1,%Y0\";
+}"
+ [(set_attr "type" "multi")])
+
+;; The following pattern is only generated by delayed-branch scheduling,
+;; when the insn winds up in the epilogue. This can only happen when
+;; ! TARGET_FPU because otherwise fp return values are in %f0.
+(define_insn "*return_sf_no_fpu"
+ [(set (match_operand:SF 0 "restore_operand" "r")
+ (match_operand:SF 1 "register_operand" "r"))
+ (return)]
+ "! TARGET_FPU && ! TARGET_EPILOGUE && ! TARGET_LIVE_G0"
+ "*
+{
+ if (! TARGET_ARCH64 && current_function_returns_struct)
+ return \"jmp %%i7+12\;restore %%g0,%1,%Y0\";
+ else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1]))
+ return \"return %%i7+8\;mov %Y1,%Y0\";
+ else
+ return \"ret\;restore %%g0,%1,%Y0\";
+}"
+ [(set_attr "type" "multi")])
+
+(define_insn "*return_addsi"
+ [(set (match_operand:SI 0 "restore_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "arith_operand" "rI")))
+ (return)]
+ "! TARGET_EPILOGUE && ! TARGET_LIVE_G0"
+ "*
+{
+ if (! TARGET_ARCH64 && current_function_returns_struct)
+ return \"jmp %%i7+12\;restore %r1,%2,%Y0\";
+ /* If operands are global or in registers, can use return */
+ else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1])
+ && (GET_CODE (operands[2]) == CONST_INT
+ || IN_OR_GLOBAL_P (operands[2])))
+ return \"return %%i7+8\;add %Y1,%Y2,%Y0\";
+ else
+ return \"ret\;restore %r1,%2,%Y0\";
+}"
+ [(set_attr "type" "multi")])
+
+(define_insn "*return_di"
+ [(set (match_operand:DI 0 "restore_operand" "")
+ (match_operand:DI 1 "arith_double_operand" "rHI"))
+ (return)]
+ "TARGET_ARCH64 && ! TARGET_EPILOGUE"
+ "ret\;restore %%g0,%1,%Y0"
+ [(set_attr "type" "multi")])
+
+(define_insn "*return_adddi"
+ [(set (match_operand:DI 0 "restore_operand" "")
+ (plus:DI (match_operand:DI 1 "arith_operand" "%r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))
+ (return)]
+ "TARGET_ARCH64 && ! TARGET_EPILOGUE"
+ "ret\;restore %r1,%2,%Y0"
+ [(set_attr "type" "multi")])
+
+;; The following pattern is only generated by delayed-branch scheduling,
+;; when the insn winds up in the epilogue.
+(define_insn "*return_sf"
+ [(set (reg:SF 32)
+ (match_operand:SF 0 "register_operand" "f"))
+ (return)]
+ "! TARGET_EPILOGUE"
+ "ret\;fmovs %0,%%f0"
+ [(set_attr "type" "multi")])
+
+;; Now peepholes to do a call followed by a jump.
+
+(define_peephole
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:SI 1 "call_operand_address" "ps"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI 15))])
+ (set (pc) (label_ref (match_operand 3 "" "")))]
+ "short_branch (INSN_UID (insn), INSN_UID (operands[3])) && in_same_eh_region (insn, operands[3]) && in_same_eh_region (insn, ins1)"
+ "call %a1,%2\;add %%o7,(%l3-.-4),%%o7")
+
+(define_peephole
+ [(parallel [(call (mem:SI (match_operand:SI 0 "call_operand_address" "ps"))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI 15))])
+ (set (pc) (label_ref (match_operand 2 "" "")))]
+ "short_branch (INSN_UID (insn), INSN_UID (operands[2])) && in_same_eh_region (insn, operands[2]) && in_same_eh_region (insn, ins1)"
+ "call %a0,%1\;add %%o7,(%l2-.-4),%%o7")
+
+(define_peephole
+ [(parallel [(set (match_operand 0 "" "")
+ (call (mem:SI (match_operand:DI 1 "call_operand_address" "ps"))
+ (match_operand 2 "" "")))
+ (clobber (reg:DI 15))])
+ (set (pc) (label_ref (match_operand 3 "" "")))]
+ "TARGET_ARCH64 && short_branch (INSN_UID (insn), INSN_UID (operands[3])) && in_same_eh_region (insn, operands[3]) && in_same_eh_region (insn, ins1)"
+ "call %a1,%2\;add %%o7,(%l3-.-4),%%o7")
+
+(define_peephole
+ [(parallel [(call (mem:SI (match_operand:DI 0 "call_operand_address" "ps"))
+ (match_operand 1 "" ""))
+ (clobber (reg:DI 15))])
+ (set (pc) (label_ref (match_operand 2 "" "")))]
+ "TARGET_ARCH64 && short_branch (INSN_UID (insn), INSN_UID (operands[2])) && in_same_eh_region (insn, operands[2]) && in_same_eh_region (insn, ins1)"
+ "call %a0,%1\;add %%o7,(%l2-.-4),%%o7")
+
+;; After a nonlocal goto, we need to restore the PIC register, but only
+;; if we need it. So do nothing much here, but we'll check for this in
+;; finalize_pic.
+
+(define_insn "nonlocal_goto_receiver"
+ [(unspec_volatile [(const_int 0)] 4)]
+ "flag_pic"
+ "")
+
+(define_insn "trap"
+ [(trap_if (const_int 1) (const_int 5))]
+ ""
+ "ta 5"
+ [(set_attr "type" "misc")])
+
+(define_expand "conditional_trap"
+ [(trap_if (match_operator 0 "noov_compare_op"
+ [(match_dup 2) (match_dup 3)])
+ (match_operand:SI 1 "arith_operand" ""))]
+ ""
+ "operands[2] = gen_compare_reg (GET_CODE (operands[0]),
+ sparc_compare_op0, sparc_compare_op1);
+ operands[3] = const0_rtx;")
+
+(define_insn ""
+ [(trap_if (match_operator 0 "noov_compare_op" [(reg:CC 100) (const_int 0)])
+ (match_operand:SI 1 "arith_operand" "rM"))]
+ ""
+ "t%C0 %1"
+ [(set_attr "type" "misc")])
+
+(define_insn ""
+ [(trap_if (match_operator 0 "noov_compare_op" [(reg:CCX 100) (const_int 0)])
+ (match_operand:SI 1 "arith_operand" "rM"))]
+ "TARGET_V9"
+ "t%C0 %%xcc,%1"
+ [(set_attr "type" "misc")])
+
diff --git a/contrib/gcc/config/sparc/splet.h b/contrib/gcc/config/sparc/splet.h
new file mode 100644
index 0000000..23c6414
--- /dev/null
+++ b/contrib/gcc/config/sparc/splet.h
@@ -0,0 +1,53 @@
+/* Definitions of target machine for GNU compiler, for SPARClet.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Doug Evans (dje@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "sparc/aout.h"
+
+/* -mbroken-saverestore is not included here because the long term
+ default is -mno-broken-saverestore. */
+#undef TARGET_DEFAULT
+#define TARGET_DEFAULT (MASK_APP_REGS + MASK_EPILOGUE)
+
+/* -mlive-g0 is only supported on the sparclet. */
+#undef SUBTARGET_SWITCHES
+#define SUBTARGET_SWITCHES \
+{"big-endian", -MASK_LITTLE_ENDIAN}, \
+{"little-endian", MASK_LITTLE_ENDIAN}, \
+{"live-g0", MASK_LIVE_G0}, \
+{"no-live-g0", -MASK_LIVE_G0}, \
+{"broken-saverestore", MASK_BROKEN_SAVERESTORE}, \
+{"no-broken-saverestore", -MASK_BROKEN_SAVERESTORE},
+
+#undef ASM_SPEC
+#define ASM_SPEC "%{mlittle-endian:-EL} %(asm_cpu)"
+
+/* Require the user to supply crt0.o. */
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC ""
+
+#undef LINK_SPEC
+#define LINK_SPEC "%{mlittle-endian:-EL}"
+
+/* sparclet chips are bi-endian. */
+#undef BYTES_BIG_ENDIAN
+#define BYTES_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN)
+#undef WORDS_BIG_ENDIAN
+#define WORDS_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN)
diff --git a/contrib/gcc/config/sparc/sun4gas.h b/contrib/gcc/config/sparc/sun4gas.h
new file mode 100644
index 0000000..3cea956
--- /dev/null
+++ b/contrib/gcc/config/sparc/sun4gas.h
@@ -0,0 +1,27 @@
+/* Definitions of target machine for GNU compiler, for SunOS 4.x with gas
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* gas supports unaligned data. */
+#define UNALIGNED_DOUBLE_INT_ASM_OP ".uaxword"
+#define UNALIGNED_INT_ASM_OP ".uaword"
+#define UNALIGNED_SHORT_ASM_OP ".uahalf"
+
+/* defaults.h will define DWARF2_UNWIND_INFO for us. */
+#undef DWARF2_UNWIND_INFO
diff --git a/contrib/gcc/config/sparc/sun4o3.h b/contrib/gcc/config/sparc/sun4o3.h
new file mode 100644
index 0000000..10c7391
--- /dev/null
+++ b/contrib/gcc/config/sparc/sun4o3.h
@@ -0,0 +1,29 @@
+#include "sparc/sparc.h"
+
+#undef FUNCTION_PROFILER
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ fprintf (FILE, "\tsethi %%hi(LP%d),%%o0\n\tcall .mcount\n\tor %%lo(LP%d),%%o0,%%o0\n", \
+ (LABELNO), (LABELNO))
+
+/* LINK_SPEC is needed only for SunOS 4. */
+
+#undef LINK_SPEC
+
+/* Override MACHINE_STATE_{SAVE,RESTORE} because we have special
+ traps available which can get and set the condition codes
+ reliably. */
+#undef MACHINE_STATE_SAVE
+#define MACHINE_STATE_SAVE(ID) \
+ unsigned long int ms_flags, ms_saveret; \
+ asm volatile("ta 0x20\n\t" \
+ "mov %%g1, %0\n\t" \
+ "mov %%g2, %1\n\t" \
+ : "=r" (ms_flags), "=r" (ms_saveret));
+
+#undef MACHINE_STATE_RESTORE
+#define MACHINE_STATE_RESTORE(ID) \
+ asm volatile("mov %0, %%g1\n\t" \
+ "mov %1, %%g2\n\t" \
+ "ta 0x21\n\t" \
+ : /* no outputs */ \
+ : "r" (ms_flags), "r" (ms_saveret));
diff --git a/contrib/gcc/config/sparc/sunos4.h b/contrib/gcc/config/sparc/sunos4.h
new file mode 100644
index 0000000..14c7a43
--- /dev/null
+++ b/contrib/gcc/config/sparc/sunos4.h
@@ -0,0 +1,49 @@
+/* Definitions of target machine for GNU compiler, for SunOS 4.x
+ Copyright (C) 1994 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#define SUNOS4_SHARED_LIBRARIES 1
+
+/* Use N_BINCL stabs. */
+
+#define DBX_USE_BINCL
+
+#include "sparc/sparc.h"
+
+/* The Sun as doesn't like unaligned data. */
+#define DWARF2_UNWIND_INFO 0
+
+/* Override MACHINE_STATE_{SAVE,RESTORE} because we have special
+ traps available which can get and set the condition codes
+ reliably. */
+#undef MACHINE_STATE_SAVE
+#define MACHINE_STATE_SAVE(ID) \
+ unsigned long int ms_flags, ms_saveret; \
+ asm volatile("ta 0x20\n\t" \
+ "mov %%g1, %0\n\t" \
+ "mov %%g2, %1\n\t" \
+ : "=r" (ms_flags), "=r" (ms_saveret));
+
+#undef MACHINE_STATE_RESTORE
+#define MACHINE_STATE_RESTORE(ID) \
+ asm volatile("mov %0, %%g1\n\t" \
+ "mov %1, %%g2\n\t" \
+ "ta 0x21\n\t" \
+ : /* no outputs */ \
+ : "r" (ms_flags), "r" (ms_saveret));
diff --git a/contrib/gcc/config/sparc/sysv4.h b/contrib/gcc/config/sparc/sysv4.h
new file mode 100644
index 0000000..7e90bdd
--- /dev/null
+++ b/contrib/gcc/config/sparc/sysv4.h
@@ -0,0 +1,231 @@
+/* Target definitions for GNU compiler for Sparc running System V.4
+ Copyright (C) 1991, 92, 95, 96, 97, 1998 Free Software Foundation, Inc.
+ Contributed by Ron Guilmette (rfg@monkeys.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "sparc/sparc.h"
+
+/* Undefine some symbols which are defined in "sparc.h" but which are
+ appropriate only for SunOS 4.x, and not for svr4. */
+
+#undef WORD_SWITCH_TAKES_ARG
+#undef ASM_OUTPUT_SOURCE_LINE
+#undef SELECT_SECTION
+#undef ASM_DECLARE_FUNCTION_NAME
+#undef TEXT_SECTION_ASM_OP
+#undef DATA_SECTION_ASM_OP
+
+#include "svr4.h"
+
+/* ??? Put back the SIZE_TYPE/PTRDIFF_TYPE definitions set by sparc.h.
+ Why, exactly, is svr4.h messing with this? Seems like the chip
+ would know best. */
+
+#undef SIZE_TYPE
+#define SIZE_TYPE (TARGET_ARCH64 ? "long unsigned int" : "unsigned int")
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE (TARGET_ARCH64 ? "long int" : "int")
+
+/* Undefined some symbols which are defined in "svr4.h" but which are
+ appropriate only for typical svr4 systems, but not for the specific
+ case of svr4 running on a Sparc. */
+
+#undef INIT_SECTION_ASM_OP
+#undef FINI_SECTION_ASM_OP
+#undef CONST_SECTION_ASM_OP
+#undef TYPE_OPERAND_FMT
+#undef PUSHSECTION_FORMAT
+#undef STRING_ASM_OP
+#undef COMMON_ASM_OP
+#undef SKIP_ASM_OP
+#undef SET_ASM_OP /* Has no equivalent. See ASM_OUTPUT_DEF below. */
+
+/* Provide a set of pre-definitions and pre-assertions appropriate for
+ the Sparc running svr4. __svr4__ is our extension. */
+
+#define CPP_PREDEFINES \
+"-Dsparc -Dunix -D__svr4__ -Asystem(unix) -Asystem(svr4)"
+
+/* The native assembler can't compute differences between symbols in different
+ sections when generating pic code, so we must put jump tables in the
+ text section. */
+#define JUMP_TABLES_IN_TEXT_SECTION 1
+
+/* Pass -K to the assembler when PIC. */
+#undef ASM_SPEC
+#define ASM_SPEC \
+ "%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} \
+ %{fpic:-K PIC} %{fPIC:-K PIC} %(asm_cpu)"
+
+/* Must use data section for relocatable constants when pic. */
+#undef SELECT_RTX_SECTION
+#define SELECT_RTX_SECTION(MODE,RTX) \
+{ \
+ if (flag_pic && symbolic_operand (RTX)) \
+ data_section (); \
+ else \
+ const_section (); \
+}
+
+/* Define the names of various pseudo-op used by the Sparc/svr4 assembler.
+ Note that many of these are different from the typical pseudo-ops used
+ by most svr4 assemblers. That is probably due to a (misguided?) attempt
+ to keep the Sparc/svr4 assembler somewhat compatible with the Sparc/SunOS
+ assembler. */
+
+#define STRING_ASM_OP ".asciz"
+#define COMMON_ASM_OP ".common"
+#define SKIP_ASM_OP ".skip"
+#define UNALIGNED_DOUBLE_INT_ASM_OP ".uaxword"
+#define UNALIGNED_INT_ASM_OP ".uaword"
+#define UNALIGNED_SHORT_ASM_OP ".uahalf"
+#define PUSHSECTION_ASM_OP ".pushsection"
+#define POPSECTION_ASM_OP ".popsection"
+
+/* This is defined in sparc.h but is not used by svr4.h. */
+#undef ASM_LONG
+#define ASM_LONG ".long"
+
+/* This is the format used to print the second operand of a .type pseudo-op
+ for the Sparc/svr4 assembler. */
+
+#define TYPE_OPERAND_FMT "#%s"
+
+/* This is the format used to print a .pushsection pseudo-op (and its operand)
+ for the Sparc/svr4 assembler. */
+
+#define PUSHSECTION_FORMAT "\t%s\t\"%s\"\n"
+
+#undef ASM_OUTPUT_CASE_LABEL
+#define ASM_OUTPUT_CASE_LABEL(FILE, PREFIX, NUM, JUMPTABLE) \
+do { ASM_OUTPUT_ALIGN ((FILE), Pmode == SImode ? 2 : 3); \
+ ASM_OUTPUT_INTERNAL_LABEL ((FILE), PREFIX, NUM); \
+ } while (0)
+
+/* This is how to equate one symbol to another symbol. The syntax used is
+ `SYM1=SYM2'. Note that this is different from the way equates are done
+ with most svr4 assemblers, where the syntax is `.set SYM1,SYM2'. */
+
+#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \
+ do { fprintf ((FILE), "\t"); \
+ assemble_name (FILE, LABEL1); \
+ fprintf (FILE, " = "); \
+ assemble_name (FILE, LABEL2); \
+ fprintf (FILE, "\n"); \
+ } while (0)
+
+/* Define how the Sparc registers should be numbered for Dwarf output.
+ The numbering provided here should be compatible with the native
+ svr4 SDB debugger in the Sparc/svr4 reference port. The numbering
+ is as follows:
+
+ Assembly name gcc internal regno Dwarf regno
+ ----------------------------------------------------------
+ g0-g7 0-7 0-7
+ o0-o7 8-15 8-15
+ l0-l7 16-23 16-23
+ i0-i7 24-31 24-31
+ f0-f31 32-63 40-71
+*/
+
+#define DBX_REGISTER_NUMBER(REGNO) ((REGNO) < 32 ? (REGNO) : (REGNO) + 8)
+
+/* A set of symbol definitions for assembly pseudo-ops which will
+ get us switched to various sections of interest. These are used
+ in all places where we simply want to switch to a section, and
+ *not* to push the previous section name onto the assembler's
+ section names stack (as we do often in dwarfout.c). */
+
+#define TEXT_SECTION_ASM_OP ".section\t\".text\""
+#define DATA_SECTION_ASM_OP ".section\t\".data\""
+#define BSS_SECTION_ASM_OP ".section\t\".bss\""
+#define CONST_SECTION_ASM_OP ".section\t\".rodata\""
+#define INIT_SECTION_ASM_OP ".section\t\".init\""
+#define FINI_SECTION_ASM_OP ".section\t\".fini\""
+
+/* Define the pseudo-ops used to switch to the .ctors and .dtors sections.
+
+ Note that we want to give these sections the SHF_WRITE attribute
+ because these sections will actually contain data (i.e. tables of
+ addresses of functions in the current root executable or shared library
+ file) and, in the case of a shared library, the relocatable addresses
+ will have to be properly resolved/relocated (and then written into) by
+ the dynamic linker when it actually attaches the given shared library
+ to the executing process. (Note that on SVR4, you may wish to use the
+ `-z text' option to the ELF linker, when building a shared library, as
+ an additional check that you are doing everything right. But if you do
+ use the `-z text' option when building a shared library, you will get
+ errors unless the .ctors and .dtors sections are marked as writable
+ via the SHF_WRITE attribute.) */
+
+#undef CTORS_SECTION_ASM_OP
+#define CTORS_SECTION_ASM_OP ".section\t\".ctors\",#alloc,#write"
+#undef DTORS_SECTION_ASM_OP
+#define DTORS_SECTION_ASM_OP ".section\t\".dtors\",#alloc,#write"
+#undef EH_FRAME_SECTION_ASM_OP
+#define EH_FRAME_SECTION_ASM_OP ".section\t\".eh_frame\",#alloc,#write"
+
+/* A C statement to output something to the assembler file to switch to section
+ NAME for object DECL which is either a FUNCTION_DECL, a VAR_DECL or
+ NULL_TREE. Some target formats do not support arbitrary sections. Do not
+ define this macro in such cases. */
+
+#undef ASM_OUTPUT_SECTION_NAME /* Override svr4.h's definition. */
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
+do { \
+ if ((DECL) && TREE_CODE (DECL) == FUNCTION_DECL) \
+ fprintf (FILE, ".section\t\"%s%s\",#alloc,#execinstr\n", \
+ flag_function_sections ? ".text%" : "", (NAME)); \
+ else if ((DECL) && DECL_READONLY_SECTION (DECL, RELOC)) \
+ fprintf (FILE, ".section\t\"%s\",#alloc\n", (NAME)); \
+ else \
+ fprintf (FILE, ".section\t\"%s\",#alloc,#write\n", (NAME)); \
+} while (0)
+
+/* Output assembler code to FILE to initialize this source file's
+ basic block profiling info, if that has not already been done. */
+
+#undef FUNCTION_BLOCK_PROFILER
+#define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \
+ do { \
+ fprintf (FILE, "\tsethi %%hi(.LLPBX0),%%o0\n\tld [%%lo(.LLPBX0)+%%o0],%%o1\n\ttst %%o1\n\tbne LPY%d\n\tadd %%o0,%%lo(.LLPBX0),%%o0\n\tcall __bb_init_func\n\tnop\nLPY%d:\n", \
+ (LABELNO), (LABELNO)); \
+ } while (0)
+
+/* Output assembler code to FILE to increment the entry-count for
+ the BLOCKNO'th basic block in this source file. */
+
+#undef BLOCK_PROFILER
+#define BLOCK_PROFILER(FILE, BLOCKNO) \
+{ \
+ int blockn = (BLOCKNO); \
+ fprintf (FILE, "\tsethi %%hi(.LLPBX2+%d),%%g1\n\tld [%%lo(.LLPBX2+%d)+%%g1],%%g2\n\
+\tadd %%g2,1,%%g2\n\tst %%g2,[%%lo(.LLPBX2+%d)+%%g1]\n", \
+ 4 * blockn, 4 * blockn, 4 * blockn); \
+}
+
+/* A C statement (sans semicolon) to output to the stdio stream
+ FILE the assembler definition of uninitialized global DECL named
+ NAME whose size is SIZE bytes and alignment is ALIGN bytes.
+ Try to use asm_output_aligned_bss to implement this macro. */
+
+#undef ASM_OUTPUT_ALIGNED_BSS
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+ asm_output_aligned_bss (FILE, DECL, NAME, SIZE, ALIGN)
diff --git a/contrib/gcc/config/sparc/t-elf b/contrib/gcc/config/sparc/t-elf
new file mode 100644
index 0000000..da9df38
--- /dev/null
+++ b/contrib/gcc/config/sparc/t-elf
@@ -0,0 +1,39 @@
+# we need to supply our own assembly versions of libgcc1.c files,
+# since the user may not have native 'cc' available
+
+CROSS_LIBGCC1 = libgcc1-asm.a
+LIB1ASMSRC = sparc/lb1spc.asm
+LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3
+
+# crt0 is built elsewhere
+LIBGCC1_TEST =
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so...
+
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+# MULTILIB_OPTIONS should have msparclite too, but we'd have to make
+# gas build...
+#MULTILIB_OPTIONS = msoft-float mcpu=v8
+MULTILIB_OPTIONS = msoft-float
+#MULTILIB_DIRNAMES = soft v8
+MULTILIB_DIRNAMES = soft
+#MULTILIB_MATCHES = msoft-float=mno-fpu mcpu?v8=mv8
+MULTILIB_MATCHES = msoft-float=mno-fpu
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
+# Assemble startup files.
+crti.o: $(srcdir)/config/sparc/sol2-ci.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) -c -o crti.o -x assembler $(srcdir)/config/sparc/sol2-ci.asm
+crtn.o: $(srcdir)/config/sparc/sol2-cn.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) -c -o crtn.o -x assembler $(srcdir)/config/sparc/sol2-cn.asm
diff --git a/contrib/gcc/config/sparc/t-sol2 b/contrib/gcc/config/sparc/t-sol2
new file mode 100644
index 0000000..d41254a
--- /dev/null
+++ b/contrib/gcc/config/sparc/t-sol2
@@ -0,0 +1,30 @@
+# we need to supply our own assembly versions of libgcc1.c files,
+# since the user may not have native 'cc' available
+
+LIBGCC1 =
+CROSS_LIBGCC1 =
+LIBGCC1_TEST =
+
+# gmon build rule:
+gmon.o: $(srcdir)/config/sparc/gmon-sol2.c $(GCC_PASSES) $(CONFIG_H) stmp-int-hdrs
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/config/sparc/gmon-sol2.c -o gmon.o
+
+# Assemble startup files.
+crt1.o: $(srcdir)/config/sparc/sol2-c1.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) -c -o crt1.o -x assembler $(srcdir)/config/sparc/sol2-c1.asm
+crti.o: $(srcdir)/config/sparc/sol2-ci.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) -c -o crti.o -x assembler $(srcdir)/config/sparc/sol2-ci.asm
+crtn.o: $(srcdir)/config/sparc/sol2-cn.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) -c -o crtn.o -x assembler $(srcdir)/config/sparc/sol2-cn.asm
+gcrt1.o: $(srcdir)/config/sparc/sol2-g1.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) -c -o gcrt1.o -x assembler $(srcdir)/config/sparc/sol2-g1.asm
+
+# We need to use -fPIC when we are using gcc to compile the routines in
+# crtstuff.c. This is only really needed when we are going to use gcc/g++
+# to produce a shared library, but since we don't know ahead of time when
+# we will be doing that, we just always use -fPIC when compiling the
+# routines in crtstuff.c.
+
+CRTSTUFF_T_CFLAGS = -fPIC
+TARGET_LIBGCC2_CFLAGS = -fPIC
diff --git a/contrib/gcc/config/sparc/t-sp64 b/contrib/gcc/config/sparc/t-sp64
new file mode 100644
index 0000000..99acd5d
--- /dev/null
+++ b/contrib/gcc/config/sparc/t-sp64
@@ -0,0 +1,2 @@
+LIBGCC1 =
+CROSS_LIBGCC1 =
diff --git a/contrib/gcc/config/sparc/t-sparcbare b/contrib/gcc/config/sparc/t-sparcbare
new file mode 100644
index 0000000..8bd978b
--- /dev/null
+++ b/contrib/gcc/config/sparc/t-sparcbare
@@ -0,0 +1,26 @@
+# configuration file for a bare sparc cpu
+
+CROSS_LIBGCC1 = libgcc1-asm.a
+LIB1ASMSRC = sparc/lb1spc.asm
+LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so...
+
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+# MULTILIB_OPTIONS should have msparclite too, but we'd have to make
+# gas build...
+MULTILIB_OPTIONS = msoft-float mcpu=v8
+MULTILIB_DIRNAMES = soft v8
+MULTILIB_MATCHES = msoft-float=mno-fpu mcpu?v8=mv8
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
diff --git a/contrib/gcc/config/sparc/t-sparclite b/contrib/gcc/config/sparc/t-sparclite
new file mode 100644
index 0000000..7cdfbb0
--- /dev/null
+++ b/contrib/gcc/config/sparc/t-sparclite
@@ -0,0 +1,24 @@
+CROSS_LIBGCC1 = libgcc1-asm.a
+LIB1ASMSRC = sparc/lb1spl.asm
+LIB1ASMFUNCS = _divsi3 _udivsi3 _modsi3 _umodsi3
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so...
+
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define US_SOFTWARE_GOFAST' > dp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ echo '#define US_SOFTWARE_GOFAST' >> fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+MULTILIB_OPTIONS = mfpu mflat
+MULTILIB_DIRNAMES =
+MULTILIB_MATCHES = mfpu=mhard-float mfpu=mcpu?f934
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
diff --git a/contrib/gcc/config/sparc/t-splet b/contrib/gcc/config/sparc/t-splet
new file mode 100644
index 0000000..3409f5d
--- /dev/null
+++ b/contrib/gcc/config/sparc/t-splet
@@ -0,0 +1,23 @@
+# configuration file for a bare sparclet cpu, aout format files
+
+CROSS_LIBGCC1 = libgcc1-asm.a
+LIB1ASMSRC = sparc/lb1spc.asm
+LIB1ASMFUNCS = _mulsi3 _divsi3 _modsi3
+
+# These are really part of libgcc1, but this will cause them to be
+# built correctly, so...
+
+LIB2FUNCS_EXTRA = fp-bit.c dp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+MULTILIB_OPTIONS = mlittle-endian mlive-g0 mbroken-saverestore
+MULTILIB_DIRNAMES = little live-g0 brknsave
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
diff --git a/contrib/gcc/config/sparc/t-sunos40 b/contrib/gcc/config/sparc/t-sunos40
new file mode 100644
index 0000000..3e10575
--- /dev/null
+++ b/contrib/gcc/config/sparc/t-sunos40
@@ -0,0 +1,7 @@
+# SunOS 4.0.*
+# /bin/as doesn't recognize the v8 instructions, so we can't do a v8
+# multilib build.
+
+LIBGCC1 =
+CROSS_LIBGCC1 =
+LIBGCC1_TEST =
diff --git a/contrib/gcc/config/sparc/t-sunos41 b/contrib/gcc/config/sparc/t-sunos41
new file mode 100644
index 0000000..5783d6a
--- /dev/null
+++ b/contrib/gcc/config/sparc/t-sunos41
@@ -0,0 +1,16 @@
+# SunOS 4.1.*
+
+LIBGCC1 =
+CROSS_LIBGCC1 =
+LIBGCC1_TEST =
+
+MULTILIB_OPTIONS = fpic/fPIC mcpu=v8
+MULTILIB_DIRNAMES = pic ucpic v8
+MULTILIB_MATCHES = mcpu?v8=mv8
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
+# The native linker doesn't handle linking -fpic code with -fPIC code. Ugh.
+# We cope by building both variants of libgcc.
+#TARGET_LIBGCC2_CFLAGS = -fPIC
diff --git a/contrib/gcc/config/sparc/t-vxsparc b/contrib/gcc/config/sparc/t-vxsparc
new file mode 100644
index 0000000..0c7a14a
--- /dev/null
+++ b/contrib/gcc/config/sparc/t-vxsparc
@@ -0,0 +1,17 @@
+LIBGCC1 =
+CROSS_LIBGCC1 =
+
+# We don't want to build .umul, etc., because VxWorks provides them,
+# which means that libgcc1-test will fail.
+LIBGCC1_TEST =
+
+# We don't want to put exit in libgcc.a for VxWorks, because VxWorks
+# does not have _exit.
+TARGET_LIBGCC2_CFLAGS = -Dexit=unused_exit
+
+MULTILIB_OPTIONS=msoft-float mv8
+MULTILIB_DIRNAMES=soft v8
+MULTILIB_MATCHES=msoft-float=mno-fpu
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
diff --git a/contrib/gcc/config/sparc/vxsim.h b/contrib/gcc/config/sparc/vxsim.h
new file mode 100644
index 0000000..6c80375
--- /dev/null
+++ b/contrib/gcc/config/sparc/vxsim.h
@@ -0,0 +1,131 @@
+/* Definitions of target machine for GNU compiler, for SPARC VxSim
+ Copyright 1996 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Supposedly the same as vanilla sparc svr4, except for the stuff below: */
+#include "sparc/sysv4.h"
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES \
+ "-DCPU=SIMSPARCSOLARIS -D__vxworks -D__vxworks__ -Dsparc -D__svr4__ -D__SVR4 \
+ -Asystem(embedded) -Asystem(svr4) -Acpu(sparc) -Amachine(sparc)\
+ -D__GCC_NEW_VARARGS__"
+
+#undef CPP_SPEC
+#define CPP_SPEC ""
+
+#undef CC1_SPEC
+#define CC1_SPEC "-fno-builtin %{sun4:} %{target:}"
+
+/* The sun bundled assembler doesn't accept -Yd, (and neither does gas).
+ It's safe to pass -s always, even if -g is not used. */
+#undef ASM_SPEC
+#define ASM_SPEC \
+ "%{V} %{v:%{!V:-V}} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Wa,*:%*} -s \
+ %{fpic:-K PIC} %{fPIC:-K PIC}"
+
+/* However it appears that Solaris 2.0 uses the same reg numbering as
+ the old BSD-style system did. */
+
+#undef DBX_REGISTER_NUMBER
+/* Same as sparc.h */
+#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
+
+/* We use stabs-in-elf for debugging, because that is what the native
+ toolchain uses. */
+#undef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+
+/* The Solaris 2 assembler uses .skip, not .zero, so put this back. */
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(FILE,SIZE) \
+ fprintf (FILE, "\t.skip %u\n", (SIZE))
+
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+do { \
+ fputs ("\t.local\t", (FILE)); \
+ assemble_name ((FILE), (NAME)); \
+ putc ('\n', (FILE)); \
+ ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN); \
+} while (0)
+
+#undef COMMON_ASM_OP
+#define COMMON_ASM_OP "\t.common"
+
+/* This is how to output a definition of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#undef ASM_OUTPUT_INTERNAL_LABEL
+#define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \
+ fprintf (FILE, ".L%s%d:\n", PREFIX, NUM)
+
+/* This is how to output a reference to an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class. */
+
+#undef ASM_OUTPUT_INTERNAL_LABELREF
+#define ASM_OUTPUT_INTERNAL_LABELREF(FILE,PREFIX,NUM) \
+ fprintf (FILE, ".L%s%d", PREFIX, NUM)
+
+/* This is how to store into the string LABEL
+ the symbol_ref name of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class.
+ This is suitable for output with `assemble_name'. */
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf (LABEL, "*.L%s%d", PREFIX, NUM)
+
+
+
+#undef LIB_SPEC
+#define LIB_SPEC ""
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC ""
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC ""
+
+#undef LINK_SPEC
+#define LINK_SPEC "-r"
+
+/* This defines which switch letters take arguments.
+ It is as in svr4.h but with -R added. */
+
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ ( (CHAR) == 'D' \
+ || (CHAR) == 'U' \
+ || (CHAR) == 'o' \
+ || (CHAR) == 'e' \
+ || (CHAR) == 'u' \
+ || (CHAR) == 'I' \
+ || (CHAR) == 'm' \
+ || (CHAR) == 'L' \
+ || (CHAR) == 'R' \
+ || (CHAR) == 'A' \
+ || (CHAR) == 'h' \
+ || (CHAR) == 'z')
+
+/* ??? This does not work in SunOS 4.x, so it is not enabled in sparc.h.
+ Instead, it is enabled here, because it does work under Solaris. */
+/* Define for support of TFmode long double and REAL_ARITHMETIC.
+ Sparc ABI says that long double is 4 words. */
+#define LONG_DOUBLE_TYPE_SIZE 64
diff --git a/contrib/gcc/config/sparc/vxsparc.h b/contrib/gcc/config/sparc/vxsparc.h
new file mode 100644
index 0000000..18ce6ed
--- /dev/null
+++ b/contrib/gcc/config/sparc/vxsparc.h
@@ -0,0 +1,61 @@
+/* Definitions of target machine for GNU compiler. Vxworks SPARC version.
+ Copyright (C) 1994, 1996 Free Software Foundation, Inc.
+ Contributed by David Henkel-Wallace (gumby@cygnus.com)
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "sparc/aout.h"
+
+/* Specify what to link with. */
+/* VxWorks does all the library stuff itself. */
+
+#undef LIB_SPEC
+#define LIB_SPEC ""
+
+/* Provide required defaults for linker -e. */
+#undef LINK_SPEC
+#define LINK_SPEC "%{!nostdlib:%{!r*:%{!e*:-e start}}}"
+
+/* VxWorks provides the functionality of crt0.o and friends itself. */
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC ""
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-Dsparc -Acpu(sparc) -Amachine(sparc)"
+
+/* Note that we define CPU here even if the user has specified -ansi.
+ This violates user namespace, but the VxWorks headers, and potentially
+ user code, all explicitly rely upon the definition of CPU in order to get
+ the proper processor information. */
+#undef CPP_SPEC
+#define CPP_SPEC "%(cpp_cpu) -DCPU=SPARC"
+
+#undef PTRDIFF_TYPE
+#undef SIZE_TYPE
+#undef WCHAR_TYPE
+#undef WCHAR_TYPE_SIZE
+
+#define PTRDIFF_TYPE "long int"
+#define SIZE_TYPE "unsigned int"
+#define WCHAR_TYPE "char"
+#define WCHAR_TYPE_SIZE 8
+
+/* US Software GOFAST library support. */
+#include "gofast.h"
+#undef INIT_SUBTARGET_OPTABS
+#define INIT_SUBTARGET_OPTABS INIT_GOFAST_OPTABS
diff --git a/contrib/gcc/config/sparc/x-sysv4 b/contrib/gcc/config/sparc/x-sysv4
new file mode 100644
index 0000000..2a661e3
--- /dev/null
+++ b/contrib/gcc/config/sparc/x-sysv4
@@ -0,0 +1,2 @@
+X_CFLAGS=-DSVR4
+ALLOCA=alloca.o
diff --git a/contrib/gcc/config/sparc/xm-linux.h b/contrib/gcc/config/sparc/xm-linux.h
new file mode 100644
index 0000000..691c7d1
--- /dev/null
+++ b/contrib/gcc/config/sparc/xm-linux.h
@@ -0,0 +1,26 @@
+/* Configuration for GCC for SPARC running Linux-based GNU systems.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Eddie C. Dost (ecd@skynet.be)
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef inhibit_libc
+#include <alloca.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
diff --git a/contrib/gcc/config/sparc/xm-lynx.h b/contrib/gcc/config/sparc/xm-lynx.h
new file mode 100644
index 0000000..90fef85
--- /dev/null
+++ b/contrib/gcc/config/sparc/xm-lynx.h
@@ -0,0 +1,39 @@
+/* Configuration for GNU C-compiler for sparc platforms running LynxOS.
+ Copyright (C) 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <xm-lynx.h>
+
+/* This describes the machine the compiler is hosted on. */
+#define HOST_BITS_PER_CHAR 8
+#define HOST_BITS_PER_SHORT 16
+#define HOST_BITS_PER_INT 32
+#define HOST_BITS_PER_LONG 32
+#define HOST_BITS_PER_LONGLONG 64
+
+#define HOST_WORDS_BIG_ENDIAN 1
+
+/* Include <sys/wait.h> to define the exit status access macros. */
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* target machine dependencies.
+ tm.h is a symbolic link to the actual target specific file. */
+
+#include "tm.h"
diff --git a/contrib/gcc/config/sparc/xm-openbsd.h b/contrib/gcc/config/sparc/xm-openbsd.h
new file mode 100644
index 0000000..2df7fb3
--- /dev/null
+++ b/contrib/gcc/config/sparc/xm-openbsd.h
@@ -0,0 +1,23 @@
+/* Configuration file for an host running sparc OpenBSD.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <xm-openbsd.h>
+#include <sparc/xm-sparc.h>
+
diff --git a/contrib/gcc/config/sparc/xm-pbd.h b/contrib/gcc/config/sparc/xm-pbd.h
new file mode 100644
index 0000000..1c3f475
--- /dev/null
+++ b/contrib/gcc/config/sparc/xm-pbd.h
@@ -0,0 +1,10 @@
+/* Host environment for the tti "Unicom" PBB 68020 boards */
+
+#include "sparc/xm-sparc.h"
+
+#define USG
+
+#ifndef __GNUC__
+#define USE_C_ALLOCA
+#endif
+
diff --git a/contrib/gcc/config/sparc/xm-sol2.h b/contrib/gcc/config/sparc/xm-sol2.h
new file mode 100644
index 0000000..5613b08
--- /dev/null
+++ b/contrib/gcc/config/sparc/xm-sol2.h
@@ -0,0 +1,4 @@
+/* If not compiled with GNU C, include the system's <alloca.h> header. */
+#ifndef __GNUC__
+#include <alloca.h>
+#endif
diff --git a/contrib/gcc/config/sparc/xm-sp64.h b/contrib/gcc/config/sparc/xm-sp64.h
new file mode 100644
index 0000000..5954aff
--- /dev/null
+++ b/contrib/gcc/config/sparc/xm-sp64.h
@@ -0,0 +1,25 @@
+/* Configuration for GCC for Sparc v9 running 64-bit native.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include <sparc/xm-sparc.h>
+
+/* This describes the machine the compiler is hosted on. */
+#undef HOST_BITS_PER_LONG
+#define HOST_BITS_PER_LONG 64
diff --git a/contrib/gcc/config/sparc/xm-sparc.h b/contrib/gcc/config/sparc/xm-sparc.h
new file mode 100644
index 0000000..e553a0d
--- /dev/null
+++ b/contrib/gcc/config/sparc/xm-sparc.h
@@ -0,0 +1,49 @@
+/* Configuration for GNU C-compiler for Sun Sparc.
+ Copyright (C) 1988, 1993, 1995, 1997 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann (tiemann@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* #defines that need visibility everywhere. */
+#define FALSE 0
+#define TRUE 1
+
+/* This describes the machine the compiler is hosted on. */
+#define HOST_BITS_PER_CHAR 8
+#define HOST_BITS_PER_SHORT 16
+#define HOST_BITS_PER_INT 32
+#define HOST_BITS_PER_LONG 32
+#define HOST_BITS_PER_LONGLONG 64
+
+/* Doubles are stored in memory with the high order word first. This
+ matters when cross-compiling. */
+#define HOST_WORDS_BIG_ENDIAN 1
+
+/* target machine dependencies.
+ tm.h is a symbolic link to the actual target specific file. */
+#include "tm.h"
+
+/* Arguments to use with `exit'. */
+#define SUCCESS_EXIT_CODE 0
+#define FATAL_EXIT_CODE 33
+
+/* If compiled with Sun CC, the use of alloca requires this #include. */
+#ifndef __GNUC__
+#include "alloca.h"
+#endif
diff --git a/contrib/gcc/config/sparc/xm-sysv4.h b/contrib/gcc/config/sparc/xm-sysv4.h
new file mode 100644
index 0000000..6e663d1
--- /dev/null
+++ b/contrib/gcc/config/sparc/xm-sysv4.h
@@ -0,0 +1,48 @@
+/* Configuration for GNU C-compiler for Sun Sparc running System V.4.
+ Copyright (C) 1992, 1993, 1998 Free Software Foundation, Inc.
+ Contributed by Ron Guilmette (rfg@netcom.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* #defines that need visibility everywhere. */
+#define FALSE 0
+#define TRUE 1
+
+/* This describes the machine the compiler is hosted on. */
+#define HOST_BITS_PER_CHAR 8
+#define HOST_BITS_PER_SHORT 16
+#define HOST_BITS_PER_INT 32
+#define HOST_BITS_PER_LONG 32
+#define HOST_BITS_PER_LONGLONG 64
+
+/* Doubles are stored in memory with the high order word first. This
+ matters when cross-compiling. */
+#define HOST_WORDS_BIG_ENDIAN 1
+
+/* target machine dependencies.
+ tm.h is a symbolic link to the actual target specific file. */
+#include "tm.h"
+
+/* Arguments to use with `exit'. */
+#define SUCCESS_EXIT_CODE 0
+#define FATAL_EXIT_CODE 33
+
+#ifndef __GNUC__
+#define ONLY_INT_FIELDS
+#endif
diff --git a/contrib/gcc/config/svr3.h b/contrib/gcc/config/svr3.h
index fc6e262..3475561 100644
--- a/contrib/gcc/config/svr3.h
+++ b/contrib/gcc/config/svr3.h
@@ -1,8 +1,7 @@
-/* svr3.h -- operating system specific defines to be used when
- targeting GCC for some generic System V Release 3 system.
- Copyright (C) 1991 Free Software Foundation, Inc.
-
- Written by Ron Guilmette (rfg@netcom.com).
+/* Operating system specific defines to be used when targeting GCC for
+ generic System V Release 3 system.
+ Copyright (C) 1991, 1996 Free Software Foundation, Inc.
+ Contributed by Ron Guilmette (rfg@monkeys.com).
This file is part of GNU CC.
@@ -103,7 +102,11 @@ Boston, MA 02111-1307, USA.
#define STARTFILE_SPEC \
"%{pg:gcrt1.o%s}%{!pg:%{p:mcrt1.o%s}%{!p:crt1.o%s}}"
+#ifdef CROSS_COMPILE
+#define LIB_SPEC "-lc crtn.o%s"
+#else
#define LIB_SPEC "%{p:-L/usr/lib/libp}%{pg:-L/usr/lib/libp} -lc crtn.o%s"
+#endif
/* Special flags for the linker. I don't know what they do. */
@@ -156,14 +159,13 @@ Boston, MA 02111-1307, USA.
#undef ASM_BYTE_OP
#define ASM_BYTE_OP "\t.byte"
-/* This is how to output a reference to a user-level label named NAME.
- `assemble_name' uses this.
+/* The prefix to add to user-visible assembler symbols.
For System V Release 3 the convention is to prepend a leading
underscore onto user-level symbol names. */
-#undef ASM_OUTPUT_LABELREF
-#define ASM_OUTPUT_LABELREF(FILE,NAME) fprintf (FILE, "_%s", NAME)
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX "_"
/* This is how to output an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
@@ -247,29 +249,17 @@ do { \
#endif /* STACK_GROWS_DOWNWARD */
-/* Add extra sections .init and .fini, in addition to .bss from att386.h. */
+/* Add extra sections .rodata, .init and .fini. */
#undef EXTRA_SECTIONS
-#define EXTRA_SECTIONS in_const, in_bss, in_init, in_fini
+#define EXTRA_SECTIONS in_const, in_init, in_fini
#undef EXTRA_SECTION_FUNCTIONS
#define EXTRA_SECTION_FUNCTIONS \
CONST_SECTION_FUNCTION \
- BSS_SECTION_FUNCTION \
INIT_SECTION_FUNCTION \
FINI_SECTION_FUNCTION
-#define BSS_SECTION_FUNCTION \
-void \
-bss_section () \
-{ \
- if (in_section != in_bss) \
- { \
- fprintf (asm_out_file, "\t%s\n", BSS_SECTION_ASM_OP); \
- in_section = in_bss; \
- } \
-}
-
#define INIT_SECTION_FUNCTION \
void \
init_section () \
diff --git a/contrib/gcc/config/svr4.h b/contrib/gcc/config/svr4.h
index 41c6ffa..4737697 100644
--- a/contrib/gcc/config/svr4.h
+++ b/contrib/gcc/config/svr4.h
@@ -1,7 +1,7 @@
/* Operating system specific defines to be used when targeting GCC for some
generic System V Release 4 system.
- Copyright (C) 1991, 1994, 1995 Free Software Foundation, Inc.
- Contributed by Ron Guilmette (rfg@segfault.us.com).
+ Copyright (C) 1991, 94-97, 1998 Free Software Foundation, Inc.
+ Contributed by Ron Guilmette (rfg@monkeys.com).
This file is part of GNU CC.
@@ -53,16 +53,9 @@ Boston, MA 02111-1307, USA.
thing as a -T option for svr4. */
#define SWITCH_TAKES_ARG(CHAR) \
- ( (CHAR) == 'D' \
- || (CHAR) == 'U' \
- || (CHAR) == 'o' \
- || (CHAR) == 'e' \
- || (CHAR) == 'u' \
- || (CHAR) == 'I' \
- || (CHAR) == 'm' \
- || (CHAR) == 'L' \
- || (CHAR) == 'A' \
+ (DEFAULT_SWITCH_TAKES_ARG (CHAR) \
|| (CHAR) == 'h' \
+ || (CHAR) == 'x' \
|| (CHAR) == 'z')
/* This defines which multi-letter switches take arguments. On svr4,
@@ -82,7 +75,7 @@ Boston, MA 02111-1307, USA.
/* Provide an ASM_SPEC appropriate for svr4. Here we try to support as
many of the specialized svr4 assembler options as seems reasonable,
given that there are certain options which we can't (or shouldn't)
- support directly due to the fact that they conflict with other options
+ support directly due to the fact that they conflict with other options
for other svr4 tools (e.g. ld) or with other options for GCC itself.
For example, we don't support the -o (output file) or -R (remove
input file) options because GCC already handles these things. We
@@ -97,7 +90,7 @@ Boston, MA 02111-1307, USA.
#undef ASM_SPEC
#define ASM_SPEC \
- "%{V} %{v:%{!V:-V}} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*}"
+ "%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*}"
/* svr4 assemblers need the `-' (indicating input from stdin) to come after
the -o option (and its argument) for some reason. If we try to put it
@@ -108,19 +101,23 @@ Boston, MA 02111-1307, USA.
messages. */
#undef ASM_FINAL_SPEC
-#define ASM_FINAL_SPEC "%{pipe:-}"
+#define ASM_FINAL_SPEC "%|"
/* Under svr4, the normal location of the `ld' and `as' programs is the
/usr/ccs/bin directory. */
+#ifndef CROSS_COMPILE
#undef MD_EXEC_PREFIX
#define MD_EXEC_PREFIX "/usr/ccs/bin/"
+#endif
/* Under svr4, the normal location of the various *crt*.o files is the
/usr/ccs/lib directory. */
+#ifndef CROSS_COMPILE
#undef MD_STARTFILE_PREFIX
#define MD_STARTFILE_PREFIX "/usr/ccs/lib/"
+#endif
/* Provide a LIB_SPEC appropriate for svr4. Here we tack on the default
standard C library (unless we are building a shared library). */
@@ -128,12 +125,6 @@ Boston, MA 02111-1307, USA.
#undef LIB_SPEC
#define LIB_SPEC "%{!shared:%{!symbolic:-lc}}"
-/* Provide a LIBGCC_SPEC appropriate for svr4. We also want to exclude
- libgcc when -symbolic. */
-
-#undef LIBGCC_SPEC
-#define LIBGCC_SPEC "%{!shared:%{!symbolic:-lgcc}}"
-
/* Provide an ENDFILE_SPEC appropriate for svr4. Here we tack on our own
magical crtend.o file (see crtstuff.c) which provides part of the
support for getting C++ file-scope static object constructed before
@@ -141,7 +132,7 @@ Boston, MA 02111-1307, USA.
which is either `gcrtn.o' or `crtn.o'. */
#undef ENDFILE_SPEC
-#define ENDFILE_SPEC "crtend.o%s %{pg:gcrtn.o}%{!pg:crtn.o%s}"
+#define ENDFILE_SPEC "crtend.o%s %{pg:gcrtn.o%s}%{!pg:crtn.o%s}"
/* Provide a LINK_SPEC appropriate for svr4. Here we provide support
for the special GCC options -static, -shared, and -symbolic which
@@ -150,7 +141,7 @@ Boston, MA 02111-1307, USA.
support here for as many of the other svr4 linker options as seems
reasonable, given that some of them conflict with options for other
svr4 tools (e.g. the assembler). In particular, we do support the
- -h*, -z*, -V, -b, -t, -Qy, -Qn, and -YP* options here, and the -e*,
+ -z*, -V, -b, -t, -Qy, -Qn, and -YP* options here, and the -e*,
-l*, -o*, -r, -s, -u*, and -L* options are directly supported
by gcc.c itself. We don't directly support the -m (generate load
map) option because that conflicts with the -m (run m4) option of
@@ -167,16 +158,27 @@ Boston, MA 02111-1307, USA.
not being done. */
#undef LINK_SPEC
-#define LINK_SPEC "%{h*} %{V} %{v:%{!V:-V}} \
+#ifdef CROSS_COMPILE
+#define LINK_SPEC "%{h*} %{v:-V} \
+ %{b} %{Wl,*:%*} \
+ %{static:-dn -Bstatic} \
+ %{shared:-G -dy -z text} \
+ %{symbolic:-Bsymbolic -G -dy -z text} \
+ %{G:-G} \
+ %{YP,*} \
+ %{Qy:} %{!Qn:-Qy}"
+#else
+#define LINK_SPEC "%{h*} %{v:-V} \
%{b} %{Wl,*:%*} \
%{static:-dn -Bstatic} \
- %{shared:-G -dy -z text %{!h*:%{o*:-h %*}}} \
- %{symbolic:-Bsymbolic -G -dy -z text %{!h*:%{o*:-h %*}}} \
+ %{shared:-G -dy -z text} \
+ %{symbolic:-Bsymbolic -G -dy -z text} \
%{G:-G} \
%{YP,*} \
%{!YP,*:%{p:-Y P,/usr/ccs/lib/libp:/usr/lib/libp:/usr/ccs/lib:/usr/lib} \
%{!p:-Y P,/usr/ccs/lib:/usr/lib}} \
%{Qy:} %{!Qn:-Qy}"
+#endif
/* Gcc automatically adds in one of the files /usr/ccs/lib/values-Xc.o,
/usr/ccs/lib/values-Xa.o, or /usr/ccs/lib/values-Xt.o for each final
@@ -243,6 +245,10 @@ do { \
#define DWARF_DEBUGGING_INFO
+/* All ELF targets can support DWARF-2. */
+
+#define DWARF2_DEBUGGING_INFO
+
/* The numbers used to denote specific machine registers in the System V
Release 4 DWARF debugging information are quite likely to be totally
different from the numbers used in BSD stabs debugging information
@@ -259,6 +265,10 @@ do { \
#define DBX_DEBUGGING_INFO
+/* When generating stabs debugging, use N_BINCL entries. */
+
+#define DBX_USE_BINCL
+
/* Use DWARF debugging info by default. */
#ifndef PREFERRED_DEBUGGING_TYPE
@@ -320,8 +330,13 @@ while (0)
embedded stabs. */
#define DBX_OUTPUT_MAIN_SOURCE_FILE_END(FILE, FILENAME) \
- fprintf (FILE, \
- "\t.text\n\t.stabs \"\",%d,0,0,.Letext\n.Letext:\n", N_SO)
+do \
+ { \
+ text_section (); \
+ fprintf (FILE, \
+ "\t.stabs \"\",%d,0,0,.Letext\n.Letext:\n", N_SO); \
+ } \
+while (0)
/* Define the actual types of some ANSI-mandated types. (These
definitions should work for most SVR4 systems). */
@@ -368,14 +383,13 @@ while (0)
#define ASM_OUTPUT_SKIP(FILE,SIZE) \
fprintf (FILE, "\t%s\t%u\n", SKIP_ASM_OP, (SIZE))
-/* This is how to output a reference to a user-level label named NAME.
- `assemble_name' uses this.
+/* The prefix to add to user-visible assembler symbols.
For System V Release 4 the convention is *not* to prepend a leading
underscore onto user-level symbol names. */
-#undef ASM_OUTPUT_LABELREF
-#define ASM_OUTPUT_LABELREF(FILE,NAME) fprintf (FILE, "%s", NAME)
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX ""
/* This is how to output an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
@@ -400,7 +414,7 @@ do { \
#undef ASM_GENERATE_INTERNAL_LABEL
#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \
do { \
- sprintf (LABEL, "*.%s%d", PREFIX, NUM); \
+ sprintf (LABEL, "*.%s%d", PREFIX, (unsigned) (NUM)); \
} while (0)
/* Output the label which precedes a jumptable. Note that for all svr4
@@ -463,6 +477,13 @@ do { \
ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN); \
} while (0)
+/* Biggest alignment supported by the object file format of this
+ machine. Use this macro to limit the alignment which can be
+ specified using the `__attribute__ ((aligned (N)))' construct. If
+ not defined, the default value is `BIGGEST_ALIGNMENT'. */
+
+#define MAX_OFILE_ALIGNMENT (32768*8)
+
/* This is the pseudo-op used to generate a 32-bit word of data with a
specific value in some section. This is the same for all known svr4
assemblers. */
@@ -573,15 +594,81 @@ dtors_section () \
}
/* Switch into a generic section.
- This is currently only used to support section attributes.
-
+
We make the section read-only and executable for a function decl,
- read-only for a const data decl, and writable for a non-const data decl. */
-#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME) \
- fprintf (FILE, ".section\t%s,\"%s\",@progbits\n", NAME, \
- (DECL) && TREE_CODE (DECL) == FUNCTION_DECL ? "ax" : \
- (DECL) && TREE_READONLY (DECL) ? "a" : "aw")
+ read-only for a const data decl, and writable for a non-const data decl.
+
+ If the section has already been defined, we must not
+ emit the attributes here. The SVR4 assembler does not
+ recognize section redefinitions.
+ If DECL is NULL, no attributes are emitted. */
+
+#define ASM_OUTPUT_SECTION_NAME(FILE, DECL, NAME, RELOC) \
+do { \
+ static struct section_info \
+ { \
+ struct section_info *next; \
+ char *name; \
+ enum sect_enum {SECT_RW, SECT_RO, SECT_EXEC} type; \
+ } *sections; \
+ struct section_info *s; \
+ char *mode; \
+ enum sect_enum type; \
+ \
+ for (s = sections; s; s = s->next) \
+ if (!strcmp (NAME, s->name)) \
+ break; \
+ \
+ if (DECL && TREE_CODE (DECL) == FUNCTION_DECL) \
+ type = SECT_EXEC, mode = "ax"; \
+ else if (DECL && DECL_READONLY_SECTION (DECL, RELOC)) \
+ type = SECT_RO, mode = "a"; \
+ else \
+ type = SECT_RW, mode = "aw"; \
+ \
+ if (s == 0) \
+ { \
+ s = (struct section_info *) xmalloc (sizeof (struct section_info)); \
+ s->name = xmalloc ((strlen (NAME) + 1) * sizeof (*NAME)); \
+ strcpy (s->name, NAME); \
+ s->type = type; \
+ s->next = sections; \
+ sections = s; \
+ fprintf (FILE, ".section\t%s,\"%s\",@progbits\n", NAME, mode); \
+ } \
+ else \
+ { \
+ if (DECL && s->type != type) \
+ error_with_decl (DECL, "%s causes a section type conflict"); \
+ \
+ fprintf (FILE, ".section\t%s\n", NAME); \
+ } \
+} while (0)
+#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1)
+#define UNIQUE_SECTION_P(DECL) (DECL_ONE_ONLY (DECL))
+#define UNIQUE_SECTION(DECL,RELOC) \
+do { \
+ int len; \
+ char *name, *string, *prefix; \
+ \
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \
+ \
+ if (! DECL_ONE_ONLY (DECL)) \
+ prefix = "."; \
+ else if (TREE_CODE (DECL) == FUNCTION_DECL) \
+ prefix = ".gnu.linkonce.t."; \
+ else if (DECL_READONLY_SECTION (DECL, RELOC)) \
+ prefix = ".gnu.linkonce.r."; \
+ else \
+ prefix = ".gnu.linkonce.d."; \
+ \
+ len = strlen (name) + strlen (prefix); \
+ string = alloca (len + 1); \
+ sprintf (string, "%s%s", prefix, name); \
+ \
+ DECL_SECTION_NAME (DECL) = build_string (len, string); \
+} while (0)
/* A C statement (sans semicolon) to output an element in the table of
global constructors. */
@@ -610,7 +697,9 @@ dtors_section () \
#define SELECT_SECTION(DECL,RELOC) \
{ \
- if (TREE_CODE (DECL) == STRING_CST) \
+ if (flag_pic && RELOC) \
+ data_section (); \
+ else if (TREE_CODE (DECL) == STRING_CST) \
{ \
if (! flag_writable_strings) \
const_section (); \
@@ -619,11 +708,7 @@ dtors_section () \
} \
else if (TREE_CODE (DECL) == VAR_DECL) \
{ \
- if ((flag_pic && RELOC) \
- || !TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \
- || !DECL_INITIAL (DECL) \
- || (DECL_INITIAL (DECL) != error_mark_node \
- && !TREE_CONSTANT (DECL_INITIAL (DECL)))) \
+ if (! DECL_READONLY_SECTION (DECL, RELOC)) \
data_section (); \
else \
const_section (); \
@@ -707,7 +792,10 @@ dtors_section () \
size_directive_output = 1; \
fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
assemble_name (FILE, NAME); \
- fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
+ putc (',', FILE); \
+ fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \
+ int_size_in_bytes (TREE_TYPE (DECL))); \
+ fputc ('\n', FILE); \
} \
ASM_OUTPUT_LABEL(FILE, NAME); \
} while (0)
@@ -729,7 +817,10 @@ do { \
size_directive_output = 1; \
fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \
assemble_name (FILE, name); \
- fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
+ putc (',', FILE); \
+ fprintf (FILE, HOST_WIDE_INT_PRINT_DEC, \
+ int_size_in_bytes (TREE_TYPE (DECL))); \
+ fputc ('\n', FILE); \
} \
} while (0)
@@ -807,7 +898,7 @@ do { \
register unsigned char *_limited_str = (unsigned char *) (STR); \
register unsigned ch; \
fprintf ((FILE), "\t%s\t\"", STRING_ASM_OP); \
- for (; ch = *_limited_str; _limited_str++) \
+ for (; (ch = *_limited_str); _limited_str++) \
{ \
register int escape; \
switch (escape = ESCAPES[ch]) \
diff --git a/contrib/gcc/config/t-freebsd b/contrib/gcc/config/t-freebsd
new file mode 100644
index 0000000..5164669
--- /dev/null
+++ b/contrib/gcc/config/t-freebsd
@@ -0,0 +1,5 @@
+# Don't run fixproto
+STMP_FIXPROTO =
+# Use only native include files
+USER_H = $(EXTRA_HEADERS) $(LANG_EXTRA_HEADERS)
+
diff --git a/contrib/gcc/config/t-gnu b/contrib/gcc/config/t-gnu
new file mode 100644
index 0000000..58969f2
--- /dev/null
+++ b/contrib/gcc/config/t-gnu
@@ -0,0 +1,13 @@
+LIBGCC1=libgcc1.null
+CROSS_LIBGCC1=libgcc1.null
+
+# The pushl in CTOR initialization interferes with frame pointer elimination.
+
+# We need to use -fPIC when we are using gcc to compile the routines in
+# crtstuff.c. This is only really needed when we are going to use gcc/g++
+# to produce a shared library, but since we don't know ahead of time when
+# we will be doing that, we just always use -fPIC when compiling the
+# routines in crtstuff.c.
+
+CRTSTUFF_T_CFLAGS = -fPIC -fno-omit-frame-pointer
+TARGET_LIBGCC2_CFLAGS = -fPIC
diff --git a/contrib/gcc/config/t-libc-ok b/contrib/gcc/config/t-libc-ok
index 712a4ca..43e4f5e 100644
--- a/contrib/gcc/config/t-libc-ok
+++ b/contrib/gcc/config/t-libc-ok
@@ -1,2 +1,3 @@
LIBGCC1=libgcc1.null
CROSS_LIBGCC1=libgcc1.null
+CRTSTUFF_T_FLAGS_S=-fPIC
diff --git a/contrib/gcc/config/t-linux-aout b/contrib/gcc/config/t-linux-aout
new file mode 100644
index 0000000..8826cdd
--- /dev/null
+++ b/contrib/gcc/config/t-linux-aout
@@ -0,0 +1,11 @@
+# Don't run fixproto
+STMP_FIXPROTO =
+
+# Don't install "assert.h" in gcc. We use the one in glibc.
+INSTALL_ASSERT_H =
+
+# Do not build libgcc1. Let gcc generate those functions. The GNU/Linux
+# C library can handle them.
+LIBGCC1 =
+CROSS_LIBGCC1 =
+LIBGCC1_TEST =
diff --git a/contrib/gcc/config/t-netbsd b/contrib/gcc/config/t-netbsd
new file mode 100644
index 0000000..85d6057
--- /dev/null
+++ b/contrib/gcc/config/t-netbsd
@@ -0,0 +1,9 @@
+LIBGCC1=libgcc1.null
+CROSS_LIBGCC1=libgcc1.null
+LIBGCC1_TEST=
+
+# Don't run fixproto
+STMP_FIXPROTO =
+
+# Don't install "assert.h" in gcc. We use the one in glibc.
+INSTALL_ASSERT_H =
diff --git a/contrib/gcc/config/t-openbsd b/contrib/gcc/config/t-openbsd
new file mode 100644
index 0000000..6bd8123
--- /dev/null
+++ b/contrib/gcc/config/t-openbsd
@@ -0,0 +1,9 @@
+# Don't run fixproto
+STMP_FIXPROTO =
+
+# We don't need GCC's own include files but we do need lang specific ones.
+USER_H = ${LANG_EXTRA_HEADERS}
+INSTALL_ASSERT_H =
+
+# We don't want collisions with our mkstemps
+T_CFLAGS=-Dmkstemps=my_mkstemps
diff --git a/contrib/gcc/config/t-openbsd-thread b/contrib/gcc/config/t-openbsd-thread
new file mode 100644
index 0000000..4b25f25
--- /dev/null
+++ b/contrib/gcc/config/t-openbsd-thread
@@ -0,0 +1,5 @@
+# This is currently needed to compile libgcc2 for threads support
+TARGET_LIBGCC2_CFLAGS=-pthread
+#T_CFLAGS=-pthread
+#T_CPPFLAGS=-pthread
+
diff --git a/contrib/gcc/config/t-rtems b/contrib/gcc/config/t-rtems
new file mode 100644
index 0000000..aa0ca66
--- /dev/null
+++ b/contrib/gcc/config/t-rtems
@@ -0,0 +1,6 @@
+# RTEMS uses newlib which does not require prototype fixing
+STMP_FIXPROTO =
+
+# Don't install "assert.h" in gcc. RTEMS uses the one in newlib.
+INSTALL_ASSERT_H =
+
diff --git a/contrib/gcc/config/t-svr4 b/contrib/gcc/config/t-svr4
index d4abf48..e6be0c3 100644
--- a/contrib/gcc/config/t-svr4
+++ b/contrib/gcc/config/t-svr4
@@ -2,6 +2,7 @@
# crtstuff.c. This is only really needed when we are going to use gcc/g++
# to produce a shared library, but since we don't know ahead of time when
# we will be doing that, we just always use -fPIC when compiling the
-# routines in crtstuff.c.
+# routines in crtstuff.c. Likewise for libgcc2.c.
CRTSTUFF_T_CFLAGS = -fPIC
+TARGET_LIBGCC2_CFLAGS = -fPIC
diff --git a/contrib/gcc/config/x-linux b/contrib/gcc/config/x-linux
index ea2a5f2..a7c0917 100644
--- a/contrib/gcc/config/x-linux
+++ b/contrib/gcc/config/x-linux
@@ -1,14 +1,5 @@
-# It is defined in config/xm-linux.h.
-# X_CFLAGS = -DPOSIX
-
-# The following is needed when compiling stages 2 and 3 because gcc's
-# limits.h must be picked up before /usr/include/limits.h. This is because
-# each does an #include_next of the other if the other hasn't been included.
-# /usr/include/limits.h loses if it gets found first because /usr/include is
-# at the end of the search order. When a new version of gcc is released,
-# gcc's limits.h hasn't been installed yet and hence isn't found.
-
-BOOT_CFLAGS = -O $(CFLAGS) -Iinclude
-
# Don't run fixproto
STMP_FIXPROTO =
+
+# Don't install "assert.h" in gcc. We use the one in glibc.
+INSTALL_ASSERT_H =
diff --git a/contrib/gcc/config/x-linux-aout b/contrib/gcc/config/x-linux-aout
new file mode 100644
index 0000000..36ae68a
--- /dev/null
+++ b/contrib/gcc/config/x-linux-aout
@@ -0,0 +1,14 @@
+# It is defined in config/xm-linux.h.
+# X_CFLAGS = -DPOSIX
+
+# The following is needed when compiling stages 2 and 3 because gcc's
+# limits.h must be picked up before /usr/include/limits.h. This is because
+# each does an #include_next of the other if the other hasn't been included.
+# /usr/include/limits.h loses if it gets found first because /usr/include is
+# at the end of the search order. When a new version of gcc is released,
+# gcc's limits.h hasn't been installed yet and hence isn't found.
+
+# BOOT_CFLAGS = -O $(CFLAGS) -Iinclude
+
+# Don't run fixproto
+# STMP_FIXPROTO =
diff --git a/contrib/gcc/config/xm-alloca.h b/contrib/gcc/config/xm-alloca.h
new file mode 100644
index 0000000..3dbdc37
--- /dev/null
+++ b/contrib/gcc/config/xm-alloca.h
@@ -0,0 +1,4 @@
+/* If not compiled with GNU C, use the portable alloca. */
+#ifndef __GNUC__
+#define USE_C_ALLOCA
+#endif
diff --git a/contrib/gcc/config/xm-freebsd.h b/contrib/gcc/config/xm-freebsd.h
index f73c9aa..b71ff56 100644
--- a/contrib/gcc/config/xm-freebsd.h
+++ b/contrib/gcc/config/xm-freebsd.h
@@ -22,12 +22,3 @@ Boston, MA 02111-1307, USA. */
running FreeBSD. This file should not be specified as $xm_file itself;
instead $xm_file should be CPU/xm-freebsd.h, which should include both
CPU/xm-CPU.h and this file xm-freebsd.h. */
-
-/* FreeBSD has strerror. */
-#define HAVE_STRERROR
-
-/* We have _sys_siglist, but the declaration in <signal.h> conflicts with
- the declarations in collect2.c and mips-tfile.c, so disable the declarations
- in those files. */
-
-#define DONT_DECLARE_SYS_SIGLIST
diff --git a/contrib/gcc/config/xm-gnu.h b/contrib/gcc/config/xm-gnu.h
index 57e74f2..64e8e2f 100644
--- a/contrib/gcc/config/xm-gnu.h
+++ b/contrib/gcc/config/xm-gnu.h
@@ -1,5 +1,5 @@
/* Configuration for GNU C-compiler for hosts running GNU.
- Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1994, 1995, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -23,9 +23,10 @@ Boston, MA 02111-1307, USA. */
instead $xm_file should be CPU/xm-gnu.h, which should include both
CPU/xm-CPU.h and this file xm-gnu.h. */
-#define HAVE_STRERROR /* GNU has strerror. */
#define POSIX /* GNU complies to POSIX.1. */
+#ifndef inhibit_libc
/* Get a definition of O_RDONLY; some of the GCC files don't include this
properly and will define it themselves to be zero. */
#include <fcntl.h>
+#endif
diff --git a/contrib/gcc/config/xm-linux.h b/contrib/gcc/config/xm-linux.h
index 5ffb0f2..2cffdb7 100644
--- a/contrib/gcc/config/xm-linux.h
+++ b/contrib/gcc/config/xm-linux.h
@@ -1,5 +1,5 @@
-/* Configuration for GCC for Intel i386 running Linux.
- Copyright (C) 1995 Free Software Foundation, Inc.
+/* Configuration for GCC for Intel i386 running Linux-based GNU systems.
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by H.J. Lu (hjl@nynexst.com)
This file is part of GNU CC.
@@ -19,22 +19,15 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#define HAVE_VPRINTF
-
-#define HAVE_STRERROR
+#undef HAVE_ATEXIT
+#define HAVE_ATEXIT
+#undef POSIX
#define POSIX
-#define DONT_DECLARE_SYS_SIGLIST
-
/* We do have one, but I'd like to use the one come with gcc since
we have been doing that for a long time with USG defined. H.J. */
-#define NO_STAB_H
+#undef HAVE_STAB_H
#undef BSTRING
#define BSTRING
-#undef bcmp
-#undef bcopy
-#undef bzero
-#undef index
-#undef rindex
diff --git a/contrib/gcc/config/xm-netbsd.h b/contrib/gcc/config/xm-netbsd.h
index 00000ce..099a923 100644
--- a/contrib/gcc/config/xm-netbsd.h
+++ b/contrib/gcc/config/xm-netbsd.h
@@ -23,5 +23,4 @@ Boston, MA 02111-1307, USA. */
instead $xm_file should be CPU/xm-netbsd.h, which should include both
CPU/xm-CPU.h and this file xm-netbsd.h. */
-#define HAVE_STRERROR
#define HAVE_VPRINTF
diff --git a/contrib/gcc/config/xm-openbsd.h b/contrib/gcc/config/xm-openbsd.h
new file mode 100644
index 0000000..74a8421
--- /dev/null
+++ b/contrib/gcc/config/xm-openbsd.h
@@ -0,0 +1,35 @@
+/* Configuration fragment for hosts running a version of OpenBSD.
+ Copyright (C) 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+/* This file gets included by all architectures. It holds stuff
+ that ought to be defined when hosting a compiler on an OpenBSD
+ machine, independently of the architecture. It's included by
+ ${cpu_type}/xm-openbsd.h, not included directly. */
+
+/* OpenBSD is trying to be POSIX-compliant, to the point of fixing
+ problems that may occur with gcc's interpretation. */
+#undef POSIX
+#define POSIX
+
+/* Ensure we get gnu C's defaults. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#endif
+
+
diff --git a/contrib/gcc/config/xm-siglist.h b/contrib/gcc/config/xm-siglist.h
new file mode 100644
index 0000000..d6133d6
--- /dev/null
+++ b/contrib/gcc/config/xm-siglist.h
@@ -0,0 +1,6 @@
+/* Some systems provide no sys_siglist, but do offer the same data under
+ another name. */
+
+#define sys_siglist _sys_siglist
+#undef SYS_SIGLIST_DECLARED
+#define SYS_SIGLIST_DECLARED
diff --git a/contrib/gcc/config/xm-std32.h b/contrib/gcc/config/xm-std32.h
new file mode 100644
index 0000000..c52782e
--- /dev/null
+++ b/contrib/gcc/config/xm-std32.h
@@ -0,0 +1,34 @@
+/* Configuration for GNU C-compiler for standard 32-bit host machine.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* #defines that need visibility everywhere. */
+#define FALSE 0
+#define TRUE 1
+
+/* This describes the machine the compiler is hosted on. */
+#define HOST_BITS_PER_CHAR 8
+#define HOST_BITS_PER_SHORT 16
+#define HOST_BITS_PER_INT 32
+#define HOST_BITS_PER_LONG 32
+#define HOST_BITS_PER_LONGLONG 64
+
+/* Arguments to use with `exit'. */
+#define SUCCESS_EXIT_CODE 0
+#define FATAL_EXIT_CODE 33
diff --git a/contrib/gcc/config/xm-svr3.h b/contrib/gcc/config/xm-svr3.h
index ac1000f..6f25250 100644
--- a/contrib/gcc/config/xm-svr3.h
+++ b/contrib/gcc/config/xm-svr3.h
@@ -1,5 +1,5 @@
/* Configuration for GNU C-compiler for hosts running System V Release 3
- Copyright (C) 1991, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1993, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -18,15 +18,7 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#define bcopy(src,dst,len) memcpy ((dst),(src),(len))
-#define bzero(dst,len) memset ((dst),0,(len))
-#define bcmp(left,right,len) memcmp ((left),(right),(len))
-
-#define rindex strrchr
-#define index strchr
-
#define USG
-#define HAVE_VPRINTF
#ifndef SVR3
#define SVR3
diff --git a/contrib/gcc/config/xm-svr4.h b/contrib/gcc/config/xm-svr4.h
index 3008432..8534aaa 100644
--- a/contrib/gcc/config/xm-svr4.h
+++ b/contrib/gcc/config/xm-svr4.h
@@ -1,5 +1,5 @@
/* Configuration for GNU C-compiler for hosts running System V Release 4
- Copyright (C) 1988 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -18,18 +18,12 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#define bcopy(src,dst,len) memcpy ((dst),(src),(len))
-#define bzero(dst,len) memset ((dst),0,(len))
-#define bcmp(left,right,len) memcmp ((left),(right),(len))
-
-#define rindex strrchr
-#define index strchr
-
#define USG
-#define HAVE_VPRINTF
#define POSIX
/* SVR4 provides no sys_siglist,
but does offer the same data under another name. */
#define sys_siglist _sys_siglist
+#undef SYS_SIGLIST_DECLARED
+#define SYS_SIGLIST_DECLARED
diff --git a/contrib/gcc/configure b/contrib/gcc/configure
index 9c2b12e..d341217 100755
--- a/contrib/gcc/configure
+++ b/contrib/gcc/configure
@@ -1,488 +1,2234 @@
-#!/bin/sh
-# Configuration script for GNU CC
-# Copyright (C) 1988, 90, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+#! /bin/sh
-#This file is part of GNU CC.
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.13
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
-#GNU CC 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, or (at your option)
-#any later version.
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --with-gnu-ld arrange to work with GNU ld."
+ac_help="$ac_help
+ --with-gnu-as arrange to work with GNU as."
+ac_help="$ac_help
+ --with-stabs arrange to use stabs instead of host debug format."
+ac_help="$ac_help
+ --with-elf arrange to use ELF instead of host debug format."
+ac_help="$ac_help
+ --with-local-prefix=DIR specifies directory to put local include."
+ac_help="$ac_help
+ --with-gxx-include-dir=DIR
+ specifies directory to put g++ header files."
+ac_help="$ac_help
+ --enable-checking enable expensive run-time checks."
+ac_help="$ac_help
+ --enable-c-cpplib Use cpplib for C."
+ac_help="$ac_help
+ --enable-haifa Use the experimental scheduler.
+ --disable-haifa Don't use the experimental scheduler for the
+ targets which normally enable it."
+ac_help="$ac_help
+ --with-fast-fixincludes Use a faster fixinclude program. Experimental"
+ac_help="$ac_help
+ --enable-threads enable thread usage for target GCC.
+ --enable-threads=LIB use LIB thread package for target GCC."
-#GNU CC 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.
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
-#You should have received a copy of the GNU General Public License
-#along with GNU CC; see the file COPYING. If not, write to
-#the Free Software Foundation, 59 Temple Place - Suite 330,
-#Boston, MA 02111-1307, USA.
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
-#
-# Shell script to create proper links to machine-dependent files in
-# preparation for compiling gcc.
-#
-# Options: --srcdir=DIR specifies directory where sources are.
-# --host=HOST specifies host configuration.
-# --target=TARGET specifies target configuration.
-# --build=TARGET specifies configuration of machine you are
-# using to compile GCC.
-# --prefix=DIR specifies directory to install in.
-# --local-prefix=DIR specifies directory to put local ./include in.
-# --gxx-include-dir=DIR specifies directory to put g++ header files in.
-# --exec-prefix=DIR specifies directory to install executables in.
-# --with-gnu-ld arrange to work with GNU ld.
-# --with-gnu-as arrange to work with GAS.
-# --with-stabs arrange to use stabs instead of host debug format.
-# --with-elf arrange to use elf instead of host debug format.
-# --enable-FOO, --enable-FOO=BAR include feature FOO (parameter BAR)
-# --disable-FOO do not include feature FOO
-# --nfp assume system has no FPU.
-# --program-prefix=PREFIX specifies prefix for executable names.
-# --program-suffix=SUFFIX specifies suffix for executable names.
-# --program-transform-name=SED-EXPR specifies `sed' expression to
-# apply to executable names.
-#
-# If configure succeeds, it leaves its status in config.status.
-# If configure fails after disturbing the status quo,
-# config.status is removed.
-#
+ac_prev=
+for ac_option
+do
-progname=$0
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
-# Default --srcdir to the directory where the script is found,
-# if a directory was specified.
-# The second sed call is to convert `.//configure' to `./configure'.
-srcdir=`echo $0 | sed 's|//|/|' | sed 's|/[^/]*$||'`
-if [ x$srcdir = x$0 ]
-then
-srcdir=
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.13"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
fi
-host=
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=tree.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+ac_exeext=
+ac_objext=o
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
-# Default prefix to /usr/local.
-prefix=/usr/local
-# On systems where GCC is the native compiler, $prefix should be
-# /usr. But the user can change it with configure --prefix=/foo/bar
-native_prefix=/usr
-
-# local_prefix specifies where to find the directory /usr/local/include
-# We don't use $(prefix) for this
-# because we always want GCC to search /usr/local/include
-# even if GCC is installed somewhere other than /usr/local.
-# Think THREE TIMES before specifying any other value for this!
-# DO NOT make this use $prefix!
-local_prefix=/usr/local
-# Default is to let the Makefile set exec_prefix from $(prefix)
-exec_prefix='$(prefix)'
-#
-# The default g++ include directory is $(libdir)/g++-include.
-gxx_include_dir='$(libdir)/g++-include'
-# Default --program-transform-name to nothing.
-program_transform_name=
-program_transform_set=
remove=rm
hard_link=ln
symbolic_link='ln -s'
copy=cp
-# Record all the arguments, to write them in config.status.
-arguments=$*
+# Check for additional parameters
-#for Test
-#remove="echo rm"
-#hard_link="echo ln"
-#symbolic_link="echo ln -s"
+# With GNU ld
+# Check whether --with-gnu-ld or --without-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then
+ withval="$with_gnu_ld"
+ gnu_ld_flag="$with_gnu_ld"
+else
+ gnu_ld_flag=no
+fi
-target=
-host=
-build=
-name1=
-name2=
-for arg in $*;
-do
- case $next_arg in
- --srcdir)
- srcdir=$arg
- next_arg=
- ;;
- --host)
- host=$arg
- next_arg=
- ;;
- --target)
- target=$arg
- next_arg=
- ;;
- --build)
- build=$arg
- next_arg=
- ;;
- --prefix)
- prefix=$arg
- native_prefix=$prefix
- next_arg=
- ;;
- --local-prefix)
- local_prefix=$arg
- next_arg=
- ;;
- --gxx-include-dir)
- gxx_include_dir=$arg
- next_arg=
- ;;
- --exec-prefix)
- exec_prefix=$arg
- next_arg=
- ;;
- --program-transform-name)
- # Double any backslashes or dollar signs in the argument.
- if [ -n "${arg}" ] ; then
- program_transform_name="${program_transform_name} -e `echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`"
+# With GNU as
+# Check whether --with-gnu-as or --without-gnu-as was given.
+if test "${with_gnu_as+set}" = set; then
+ withval="$with_gnu_as"
+ gas_flag="$with_gnu_as"
+else
+ gas_flag=no
+fi
+
+
+# With stabs
+# Check whether --with-stabs or --without-stabs was given.
+if test "${with_stabs+set}" = set; then
+ withval="$with_stabs"
+ stabs="$with_stabs"
+else
+ stabs=no
+fi
+
+
+# With ELF
+# Check whether --with-elf or --without-elf was given.
+if test "${with_elf+set}" = set; then
+ withval="$with_elf"
+ elf="$with_elf"
+else
+ elf=no
+fi
+
+
+# Specify the local prefix
+local_prefix=
+# Check whether --with-local-prefix or --without-local-prefix was given.
+if test "${with_local_prefix+set}" = set; then
+ withval="$with_local_prefix"
+ case "${withval}" in
+yes) { echo "configure: error: bad value ${withval} given for local include directory prefix" 1>&2; exit 1; } ;;
+no) ;;
+*) local_prefix=$with_local_prefix ;;
+esac
+fi
+
+
+# Default local prefix if it is empty
+if [ x$local_prefix = x ]; then
+ local_prefix=/usr/local
+fi
+
+gxx_include_dir=
+# Specify the g++ header file directory
+# Check whether --with-gxx-include-dir or --without-gxx-include-dir was given.
+if test "${with_gxx_include_dir+set}" = set; then
+ withval="$with_gxx_include_dir"
+ case "${withval}" in
+yes) { echo "configure: error: bad value ${withval} given for g++ include directory" 1>&2; exit 1; } ;;
+no) ;;
+*) gxx_include_dir=$with_gxx_include_dir ;;
+esac
+fi
+
+
+if test x${gxx_include_dir} = x; then
+ if test x${enable_version_specific_runtime_libs} = xyes; then
+ gxx_include_dir='${libsubdir}/include/g++'
+ else
+ gxx_include_dir='${prefix}/include/g++'
+ fi
+fi
+
+# Enable expensive internal checks
+# Check whether --enable-checking or --disable-checking was given.
+if test "${enable_checking+set}" = set; then
+ enableval="$enable_checking"
+ case "${enableval}" in
+yes) cat >> confdefs.h <<\EOF
+#define ENABLE_CHECKING 1
+EOF
+ ;;
+no) ;;
+*) { echo "configure: error: bad value ${enableval} given for checking option" 1>&2; exit 1; } ;;
+esac
+fi
+
+
+# Enable use of cpplib for C.
+cpp_main=cccp
+# Check whether --enable-c-cpplib or --disable-c-cpplib was given.
+if test "${enable_c_cpplib+set}" = set; then
+ enableval="$enable_c_cpplib"
+ if [ x$enable_c_cpplib != xno ]; then
+ extra_c_objs="${extra_c_objs} cpplib.o cppexp.o cpphash.o cpperror.o"
+ extra_c_objs="${extra_c_objs} prefix.o"
+ extra_cxx_objs="${extra_cxx_objs} ../cpplib.o ../cppexp.o ../cpphash.o ../cpperror.o ../prefix.o"
+ extra_c_flags=-DUSE_CPPLIB=1
+ cpp_main=cppmain
+fi
+fi
+
+
+# Enable Haifa scheduler.
+# Check whether --enable-haifa or --disable-haifa was given.
+if test "${enable_haifa+set}" = set; then
+ enableval="$enable_haifa"
+ :
+fi
+
+# Fast fixincludes
+#
+# This is a work in progress...
+# Check whether --with-fast-fixincludes or --without-fast-fixincludes was given.
+if test "${with_fast_fixincludes+set}" = set; then
+ withval="$with_fast_fixincludes"
+ fast_fixinc="$with_fast_fixincludes"
+else
+ fast_fixinc=no
+fi
+
+
+# Enable threads
+# Pass with no value to take the default
+# Pass with a value to specify a thread package
+# Check whether --enable-threads or --disable-threads was given.
+if test "${enable_threads+set}" = set; then
+ enableval="$enable_threads"
+ if [ x$enable_threads = xno ]; then
+ enable_threads=''
+fi
+else
+ enable_threads=''
+fi
+
+
+enable_threads_flag=$enable_threads
+# Check if a valid thread package
+case x${enable_threads_flag} in
+ x | xno)
+ # No threads
+ target_thread_file='single'
+ ;;
+ xyes)
+ # default
+ target_thread_file=''
+ ;;
+ xdecosf1 | xirix | xmach | xos2 | xposix | xpthreads | xsingle | \
+ xsolaris | xwin32 | xdce | xvxworks)
+ target_thread_file=$enable_threads_flag
+ ;;
+ *)
+ echo "$enable_threads is an unknown thread package" 1>&2
+ exit 1
+ ;;
+esac
+
+# Determine the host, build, and target systems
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Do some error checking and defaulting for the host and target type.
+# The inputs are:
+# configure --host=HOST --target=TARGET --build=BUILD NONOPT
+#
+# The rules are:
+# 1. You are not allowed to specify --host, --target, and nonopt at the
+# same time.
+# 2. Host defaults to nonopt.
+# 3. If nonopt is not specified, then host defaults to the current host,
+# as determined by config.guess.
+# 4. Target and build default to nonopt.
+# 5. If nonopt is not specified, then target and build default to host.
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+case $host---$target---$nonopt in
+NONE---*---* | *---NONE---* | *---*---NONE) ;;
+*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;;
+esac
+
+
+# Make sure we can run config.sub.
+if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:771: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+ else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+ fi ;;
+ *) host_alias=$nonopt ;;
+ esac ;;
+esac
+
+host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking target system type""... $ac_c" 1>&6
+echo "configure:792: checking target system type" >&5
+
+target_alias=$target
+case "$target_alias" in
+NONE)
+ case $nonopt in
+ NONE) target_alias=$host_alias ;;
+ *) target_alias=$nonopt ;;
+ esac ;;
+esac
+
+target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
+target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$target" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:810: checking build system type" >&5
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+ case $nonopt in
+ NONE) build_alias=$host_alias ;;
+ *) build_alias=$nonopt ;;
+ esac ;;
+esac
+
+build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+test "$host_alias" != "$target_alias" &&
+ test "$program_prefix$program_suffix$program_transform_name" = \
+ NONENONEs,x,x, &&
+ program_prefix=${target_alias}-
+
+
+# Find the native compiler
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:837: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
fi
- program_transform_set=yes
- next_arg=
- ;;
- --program-prefix)
- if [ -n "${arg}" ]; then
- program_transform_name="${program_transform_name} -e s,^,`echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`,"
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:867: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_prog_rejected=no
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
fi
- program_transform_set=yes
- next_arg=
- ;;
- --program-suffix)
- if [ -n "${arg}" ]; then
- program_transform_name="${program_transform_name} -e s,\$\$,`echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`,"
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ if test -z "$CC"; then
+ case "`uname -s`" in
+ *win32* | *WIN32*)
+ # Extract the first word of "cl", so it can be a program name with args.
+set dummy cl; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:918: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="cl"
+ break
fi
- program_transform_set=yes
- next_arg=
- ;;
- --x-*)
- next_arg=
- ;;
- *)
- case $arg in
- -*)
- if [ x$name1 != x ]
- then
- echo "Positional arguments must be last." 1>&2
- exit 1
- fi
- ;;
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+ ;;
esac
+ fi
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
- case $arg in
- -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
- next_arg=--srcdir
- ;;
- -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
- srcdir=`echo $arg | sed 's/-*s[a-z]*=//'`
- ;;
- -host | --host | --hos | --ho)
- next_arg=--host
- ;;
- -host=* | --host=* | --hos=* | --ho=*)
- host=`echo $arg | sed 's/-*h[a-z]*=//'`
- ;;
- -target | --target | --targe | --targ | --tar | --ta | --t)
- next_arg=--target
- ;;
- -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
- target=`echo $arg | sed 's/-*t[a-z]*=//'`
- ;;
- -build | --build | --buil | --bui | --bu | --b)
- next_arg=--build
- ;;
- -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*)
- build=`echo $arg | sed 's/-*b[a-z]*=//'`
- ;;
- -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
- next_arg=--prefix
- ;;
- -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
- prefix=`echo $arg | sed 's/-*p[a-z]*=//'`
- native_prefix=$prefix
- ;;
- -local-prefix | --local-prefix | --local-prefi | --local-pref | --local-pre \
- | --local-pr | --local-p | --local- | --local | --loc | --lo | --l)
- next_arg=--local-prefix
- ;;
- -local-prefix=* | --local-prefix=* | --local-prefi=* | --local-pref=* \
- | --local-pre=* | --local-pr=* | --local-p=* | --local-=* | --local=* \
- | --loc=* | --lo=* | --l=*)
- local_prefix=`echo $arg | sed 's/-*l[-a-z]*=//'`
- ;;
- -gxx-include-dir | --gxx-include-dir | --gxx-include \
- | --gxx-incl | --gxx-inc | --gxx-in | --gxx-i | --gxx- \
- | --gxx | --gxx | --gx | --g)
- next_arg=--gxx-include-dir
- ;;
- -gxx-include-dir=* | --gxx-include-dir=* | --gxx-include=* \
- | --gxx-incl=* | --gxx-inc=* | --gxx-in=* | --gxx-i=* \
- | --gxx-=* | --gxx=* | --gxx=* | --gxx=* | --g=*)
- gxx_include_dir=`echo $arg | sed 's/-*g[-a-z]*=//'`
- ;;
- -exec-prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre \
- | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e)
- next_arg=--exec-prefix
- ;;
- -exec-prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* \
- | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* \
- | --exe=* | --ex=* | --e=*)
- exec_prefix=`echo $arg | sed 's/-*e[-a-z]*=//'`
- ;;
- -program-transform-name | --program-transform-name \
- | --program-transform-nam | --program-transform-na \
- | --program-transform-n | --program-transform- | --program-transform \
- | --program-transfor | --program-transfo | --program-transf \
- | --program-trans | --program-tran | --program-tra \
- | --program-tr | --program-t)
- next_arg=--program-transform-name
- ;;
- -program-transform-name=* | --program-transform-name=* \
- | --program-transform-nam=* | --program-transform-na=* \
- | --program-transform-n=* | --program-transform-=* \
- | --program-transform=* | --program-transfor=* | --program-transfo=* \
- | --program-transf=* | --program-trans=* | --program-tran=* \
- | --program-tra=* | --program-tr=* | --program-t=*)
- arg=`echo ${arg} | sed -e 's/^[-a-z_]*=//'`
- # Double any \ or $ in the argument.
- if [ -n "${arg}" ] ; then
- program_transform_name="${program_transform_name} -e `echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`"
- fi
- program_transform_set=yes
- ;;
- -program-prefix | --program-prefix | --program-prefi \
- | --program-pref | --program-pre | --program-pr \
- | --program-p)
- next_arg=--program-prefix
- ;;
- -program-prefix=* | --program-prefix=* | --program-prefi=* \
- | --program-pref=* | --program-pre=* | --program-pr=* \
- | --program-p=*)
- arg=`echo ${arg} | sed -e 's/^[-a-z_]*=//'`
- if [ -n "${arg}" ]; then
- program_transform_name="${program_transform_name} -e s,^,`echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`,"
- fi
- program_transform_set=yes
- ;;
- -program-suffix | --program-suffix | --program-suffi \
- | --program-suff | --program-suf | --program-su \
- | --program-s)
- next_arg=--program-suffix
- ;;
- -program-suffix=* | --program-suffix=* | --program-suffi=* \
- | --program-suff=* | --program-suf=* | --program-su=* \
- | --program-s=*)
- arg=`echo ${arg} | sed -e 's/^[-a-z_]*=//'`
- if [ -n "${arg}" ]; then
- program_transform_name="${program_transform_name} -e s,\$\$,`echo ${arg} | sed -e 's/\\\\/\\\\\\\\/g' -e 's/\\\$/$$/g'`,"
- fi
- program_transform_set=yes
- ;;
- -with-gnu-ld | --with-gnu-ld | --with-gnu-l)
- gnu_ld=yes
- ;;
- -gas | --gas | --ga | --g | -with-gnu-as | --with-gnu-as | -with-gnu-a)
- gas=yes
- ;;
- -nfp | --nfp | --nf | --n)
- nfp=yes
- ;;
- -with-stabs | -with-stab | -with-sta | -with-st | -with-s \
- | --with-stabs | --with-stab | --with-sta | --with-st | --with-s \
- | -stabs | -stab | -sta | -st \
- | --stabs | --stab | --sta | --st)
- stabs=yes
- ;;
- -with-elf | -with-el | -with-se \
- | --with-elf | --with-el | --with-e \
- | -elf | -el | -e \
- |--elf | --el | --e)
- elf=yes
- ;;
- -with-* | --with-*) ;; #ignored
- -without-* | --without-*) ;; #ignored
- -disable-* | --disable-*)
- enableopt=`echo ${arg} | sed 's:^-*disable-:enable_:;s:-:_:g'`
- eval $enableopt=no
- ;;
- -enable-* | --enable-*)
- case "$arg" in
- *=*) optarg=`echo $arg | sed 's:^[^=]*=::;s:-:_:g'` ;;
- *) optarg=yes ;;
- esac
- enableopt=`echo ${arg} | sed 's:^-*::;s:=.*$::;s:-:_:g'`
- eval $enableopt="$optarg"
- ;;
- -x | --x) ;; # ignored
- -x-*=* | --x-*=*) ;; # ignored
- -x-* | --x-*)
- next_arg=--x-ignored # ignored
- ;;
- --he*) ;; # ignored for now (--help)
- --vers*) ;; # ignored for now (--version)
- -v | -verb* | --verb*) ;; # ignored for now (--verbose)
- --program-*) ;; #ignored (--program-prefix, --program-suffix)
- --c*) ;; #ignored (--cache-file)
- --q*) ;; #ignored (--quiet)
- --si*) ;; #ignored (--silent)
- -*)
- echo "Invalid option \`$arg'" 1>&2
- exit 1
- ;;
- *)
-# Allow configure HOST TARGET. If just one name is given, it is used
-# as both unless a host was previously given, in which case it is
-# just the target.
- if [ x$name1 != x ]
- then
- if [ x$name2 != x ]
- then
- echo "More than two configuration names." 1>&2
- exit 1
- fi
- name2=$arg
- elif [ x$host != x ]
- then
- name1=$host
- name2=$arg
- host=
- else
- name1=$arg
- fi
- ;;
- esac
- esac
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:950: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext << EOF
+
+#line 961 "configure"
+#include "confdefs.h"
+
+main(){return(0);}
+EOF
+if { (eval echo configure:966: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:992: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:997: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1006: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+
+ac_test_CFLAGS="${CFLAGS+set}"
+ac_save_CFLAGS="$CFLAGS"
+CFLAGS=
+echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:1025: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:1057: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+# Find some useful tools
+for ac_prog in mawk gawk nawk awk
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1090: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AWK="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+AWK="$ac_cv_prog_AWK"
+if test -n "$AWK"; then
+ echo "$ac_t""$AWK" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$AWK" && break
done
-if [ x$name1 != x ]
+# Extract the first word of "flex", so it can be a program name with args.
+set dummy flex; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1122: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$LEX"; then
+ ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_LEX="flex"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_LEX" && ac_cv_prog_LEX="lex"
+fi
+fi
+LEX="$ac_cv_prog_LEX"
+if test -n "$LEX"; then
+ echo "$ac_t""$LEX" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$LEXLIB"
then
- if [ x$name2 = x ]
- then
- name2=$name1
- fi
+ case "$LEX" in
+ flex*) ac_lib=fl ;;
+ *) ac_lib=l ;;
+ esac
+ echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6
+echo "configure:1156: checking for yywrap in -l$ac_lib" >&5
+ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-l$ac_lib $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1164 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char yywrap();
- if [ x$host != x ]
- then
- echo "Duplicate specification of host." 1>&2
- exit 1
- fi
+int main() {
+yywrap()
+; return 0; }
+EOF
+if { (eval echo configure:1175: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
- if [ x$target != x ]
- then
- echo "Duplicate specification of target." 1>&2
- exit 1
- fi
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ LEXLIB="-l$ac_lib"
+else
+ echo "$ac_t""no" 1>&6
+fi
- host=$name1
- build=$name1
- target=$name2
fi
-# Find the source files, if location was not specified.
-if [ x$srcdir = x ]
+echo $ac_n "checking whether ln works""... $ac_c" 1>&6
+echo "configure:1198: checking whether ln works" >&5
+if eval "test \"`echo '$''{'gcc_cv_prog_LN'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ rm -f conftestdata_t
+echo >conftestdata_f
+if ln conftestdata_f conftestdata_t 2>/dev/null
then
- srcdirdefaulted=1
- srcdir=.
- if [ ! -r tree.c ]
- then
- srcdir=..
- fi
+ gcc_cv_prog_LN="ln"
+else
+ if ln -s conftestdata_f conftestdata_t 2>/dev/null
+ then
+ gcc_cv_prog_LN="ln -s"
+ else
+ gcc_cv_prog_LN=cp
+ fi
fi
+rm -f conftestdata_f conftestdata_t
-if [ ! -r ${srcdir}/tree.c ]
-then
- if [ x$srcdirdefaulted = x ]
- then
- echo "$progname: Can't find compiler sources in \`${srcdir}'" 1>&2
- else
- echo "$progname: Can't find compiler sources in \`.' or \`..'" 1>&2
- fi
- exit 1
+fi
+LN="$gcc_cv_prog_LN"
+if test "$gcc_cv_prog_LN" = "ln"; then
+ echo "$ac_t""yes" 1>&6
+else
+ if test "$gcc_cv_prog_LN" = "ln -s"; then
+ echo "$ac_t""no, using ln -s" 1>&6
+ else
+ echo "$ac_t""no, and neither does ln -s, so using cp" 1>&6
+ fi
fi
-if [ -r ${srcdir}/config.status ] && [ x$srcdir != x. ]
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:1230: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'gcc_cv_prog_LN_S'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ rm -f conftestdata_t
+echo >conftestdata_f
+if ln -s conftestdata_f conftestdata_t 2>/dev/null
then
- echo "$progname: \`configure' has been run in \`${srcdir}'" 1>&2
- exit 1
+ gcc_cv_prog_LN_S="ln -s"
+else
+ if ln conftestdata_f conftestdata_t 2>/dev/null
+ then
+ gcc_cv_prog_LN_S=ln
+ else
+ gcc_cv_prog_LN_S=cp
+ fi
fi
+rm -f conftestdata_f conftestdata_t
-# Complain if an arg is missing
-if [ x$build = x ]
-then
- # If host was specified, always use it for build also to avoid
- # confusion. If someone wants a cross compiler where build != host,
- # then they must specify build explicitly. Since this case is
- # extremely rare, it does not matter that it is slightly inconvenient.
- if [ x$host != x ]
- then
- build=$host
-
- # This way of testing the result of a command substitution is
- # defined by Posix.2 (section 3.9.1) as well as traditional shells.
- elif build=`${srcdir}/config.guess`
- then
- echo "This appears to be a ${build} system." 1>&2
+fi
+LN_S="$gcc_cv_prog_LN_S"
+if test "$gcc_cv_prog_LN_S" = "ln -s"; then
+ echo "$ac_t""yes" 1>&6
+else
+ if test "$gcc_cv_prog_LN_S" = "ln"; then
+ echo "$ac_t""no, using ln" 1>&6
+ else
+ echo "$ac_t""no, and neither does ln, so using cp" 1>&6
+ fi
+fi
- elif [ x$target != x ]
- then
- echo 'Config.guess failed to determine the host type. Defaulting to target.'
- build=$target
- else
- echo 'Config.guess failed to determine the host type. You need to specify one.' 1>&2
- echo "\
-Usage: `basename $progname` [--host=HOST] [--build=BUILD]
- [--prefix=DIR] [--gxx-include-dir=DIR] [--local-pref=DIR] [--exec-pref=DIR]
- [--with-gnu-as] [--with-gnu-ld] [--with-stabs] [--with-elf] [--nfp] TARGET" 1>&2
- echo "Where HOST, TARGET and BUILD are three-part configuration names " 1>&2
- if [ -r config.status ]
- then
- tail +2 config.status 1>&2
- fi
- exit 1
+echo $ac_n "checking for volatile""... $ac_c" 1>&6
+echo "configure:1262: checking for volatile" >&5
+if eval "test \"`echo '$''{'gcc_cv_c_volatile'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1267 "configure"
+#include "confdefs.h"
+
+int main() {
+volatile int foo;
+; return 0; }
+EOF
+if { (eval echo configure:1274: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ gcc_cv_c_volatile=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ gcc_cv_c_volatile=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$gcc_cv_c_volatile" 1>&6
+if test $gcc_cv_c_volatile = yes ; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_VOLATILE 1
+EOF
+
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1297: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:1329: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$YACC"; then
+ ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+ ac_dummy="$PATH"
+ for ac_dir in $ac_dummy; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_YACC="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+ echo "$ac_t""$YACC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1370: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1421: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 1436 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1442: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 1453 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1459: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 1470 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1476: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1501: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1506 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1514: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1531 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1549 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
fi
-# If $host was not specified, use $build.
-if [ x$host = x ]
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1570 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1581: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
- host=$build
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
+echo "configure:1605: checking whether time.h and sys/time.h may both be included" >&5
+if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1610 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+int main() {
+struct tm *tp;
+; return 0; }
+EOF
+if { (eval echo configure:1619: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_header_time=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_time=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_header_time" 1>&6
+if test $ac_cv_header_time = yes; then
+ cat >> confdefs.h <<\EOF
+#define TIME_WITH_SYS_TIME 1
+EOF
+
+fi
+
+for ac_hdr in limits.h stddef.h string.h strings.h stdlib.h time.h fcntl.h unistd.h stab.h sys/file.h sys/time.h sys/resource.h sys/param.h sys/times.h wait.h sys/wait.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1643: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1648 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1653: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+# Check for thread headers.
+ac_safe=`echo "thread.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for thread.h""... $ac_c" 1>&6
+echo "configure:1683: checking for thread.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1688 "configure"
+#include "confdefs.h"
+#include <thread.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1693: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ have_thread_h=yes
+else
+ echo "$ac_t""no" 1>&6
+have_thread_h=
+fi
+
+ac_safe=`echo "pthread.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for pthread.h""... $ac_c" 1>&6
+echo "configure:1717: checking for pthread.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1722 "configure"
+#include "confdefs.h"
+#include <pthread.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1727: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ have_pthread_h=yes
+else
+ echo "$ac_t""no" 1>&6
+have_pthread_h=
+fi
+
+
+# See if the system preprocessor understands the ANSI C preprocessor
+# stringification operator.
+echo $ac_n "checking whether cpp understands the stringify operator""... $ac_c" 1>&6
+echo "configure:1753: checking whether cpp understands the stringify operator" >&5
+if eval "test \"`echo '$''{'gcc_cv_c_have_stringify'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1758 "configure"
+#include "confdefs.h"
-# If $target was not specified, use $host.
-if [ x$target = x ]
+int main() {
+#define S(x) #x
+char *test = S(foo);
+; return 0; }
+EOF
+if { (eval echo configure:1766: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ gcc_cv_c_have_stringify=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ gcc_cv_c_have_stringify=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$gcc_cv_c_have_stringify" 1>&6
+if test $gcc_cv_c_have_stringify = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_CPP_STRINGIFY 1
+EOF
+
+fi
+
+# Use <inttypes.h> only if it exists,
+# doesn't clash with <sys/types.h>, and declares intmax_t.
+echo $ac_n "checking for inttypes.h""... $ac_c" 1>&6
+echo "configure:1789: checking for inttypes.h" >&5
+if eval "test \"`echo '$''{'gcc_cv_header_inttypes_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1794 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <inttypes.h>
+int main() {
+intmax_t i = -1;
+; return 0; }
+EOF
+if { (eval echo configure:1802: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ gcc_cv_header_inttypes_h=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ gcc_cv_header_inttypes_h=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$gcc_cv_header_inttypes_h" 1>&6
+if test $gcc_cv_header_inttypes_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_INTTYPES_H 1
+EOF
+
+fi
+
+for ac_func in strtoul bsearch strerror putenv popen bcopy bzero bcmp \
+ index rindex strchr strrchr kill getrlimit setrlimit atoll atoq \
+ sysconf isascii gettimeofday
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1827: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1832 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1855: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for vprintf""... $ac_c" 1>&6
+echo "configure:1881: checking for vprintf" >&5
+if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1886 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char vprintf(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char vprintf();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_vprintf) || defined (__stub___vprintf)
+choke me
+#else
+vprintf();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1909: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func_vprintf=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_vprintf=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_VPRINTF 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test "$ac_cv_func_vprintf" != yes; then
+echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
+echo "configure:1933: checking for _doprnt" >&5
+if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1938 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char _doprnt(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char _doprnt();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub__doprnt) || defined (__stub____doprnt)
+choke me
+#else
+_doprnt();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1961: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+ rm -rf conftest*
+ eval "ac_cv_func__doprnt=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func__doprnt=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ cat >> confdefs.h <<\EOF
+#define HAVE_DOPRNT 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+fi
+
+vfprintf=
+doprint=
+if test $ac_cv_func_vprintf != yes ; then
+ vfprintf=vfprintf.o
+ if test $ac_cv_func__doprnt != yes ; then
+ doprint=doprint.o
+ fi
+fi
+
+
+
+echo $ac_n "checking whether the printf functions support %p""... $ac_c" 1>&6
+echo "configure:1997: checking whether the printf functions support %p" >&5
+if eval "test \"`echo '$''{'gcc_cv_func_printf_ptr'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$cross_compiling" = yes; then
+ gcc_cv_func_printf_ptr=no
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2005 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+
+main()
+{
+ char buf[64];
+ char *p = buf, *q = NULL;
+ sprintf(buf, "%p", p);
+ sscanf(buf, "%p", &q);
+ exit (p != q);
+}
+EOF
+if { (eval echo configure:2018: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
- target=$host
+ gcc_cv_func_printf_ptr=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ gcc_cv_func_printf_ptr=no
+fi
+rm -fr conftest*
+fi
+
+rm -f core core.* *.core
+fi
+
+echo "$ac_t""$gcc_cv_func_printf_ptr" 1>&6
+if test $gcc_cv_func_printf_ptr = yes ; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_PRINTF_PTR 1
+EOF
+
+fi
+
+
+for ac_func in malloc realloc calloc free bcopy bzero bcmp \
+ index rindex getenv atol sbrk abort atof strerror getcwd getwd
+do
+echo $ac_n "checking whether $ac_func must be declared""... $ac_c" 1>&6
+echo "configure:2046: checking whether $ac_func must be declared" >&5
+if eval "test \"`echo '$''{'gcc_cv_decl_needed_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2051 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef HAVE_RINDEX
+#define rindex strrchr
+#endif
+#ifndef HAVE_INDEX
+#define index strchr
+#endif
+
+int main() {
+char *(*pfn) = (char *(*)) $ac_func
+; return 0; }
+EOF
+if { (eval echo configure:2079: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ eval "gcc_cv_decl_needed_$ac_func=no"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "gcc_cv_decl_needed_$ac_func=yes"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$gcc_cv_decl_needed_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ gcc_tr_decl=NEED_DECLARATION_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $gcc_tr_decl 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+done
+
+
+for ac_func in getrlimit setrlimit
+do
+echo $ac_n "checking whether $ac_func must be declared""... $ac_c" 1>&6
+echo "configure:2108: checking whether $ac_func must be declared" >&5
+if eval "test \"`echo '$''{'gcc_cv_decl_needed_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2113 "configure"
+#include "confdefs.h"
+
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifndef HAVE_RINDEX
+#define rindex strrchr
+#endif
+#ifndef HAVE_INDEX
+#define index strchr
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+int main() {
+char *(*pfn) = (char *(*)) $ac_func
+; return 0; }
+EOF
+if { (eval echo configure:2145: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ eval "gcc_cv_decl_needed_$ac_func=no"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "gcc_cv_decl_needed_$ac_func=yes"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$gcc_cv_decl_needed_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ gcc_tr_decl=NEED_DECLARATION_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $gcc_tr_decl 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
fi
+done
+
+
+echo $ac_n "checking for sys_siglist declaration in signal.h or unistd.h""... $ac_c" 1>&6
+echo "configure:2172: checking for sys_siglist declaration in signal.h or unistd.h" >&5
+if eval "test \"`echo '$''{'ac_cv_decl_sys_siglist'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 2177 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <signal.h>
+/* NetBSD declares sys_siglist in unistd.h. */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+int main() {
+char *msg = *(sys_siglist + 1);
+; return 0; }
+EOF
+if { (eval echo configure:2189: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ rm -rf conftest*
+ ac_cv_decl_sys_siglist=yes
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_decl_sys_siglist=no
+fi
+rm -f conftest*
+fi
+
+echo "$ac_t""$ac_cv_decl_sys_siglist" 1>&6
+if test $ac_cv_decl_sys_siglist = yes; then
+ cat >> confdefs.h <<\EOF
+#define SYS_SIGLIST_DECLARED 1
+EOF
+
+fi
+
+
+# File extensions
+manext='.1'
+objext='.o'
+
+
+
build_xm_file=
+build_xm_defines=
+build_install_headers_dir=install-headers-tar
+build_exeext=
host_xm_file=
+host_xm_defines=
host_xmake_file=
-host_broken_install=
-host_install_headers_dir=install-headers-tar
host_truncate_target=
-
-# Validate the specs, and canonicalize them.
-canon_build=`/bin/sh $srcdir/config.sub $build` || exit 1
-canon_host=`/bin/sh $srcdir/config.sub $host` || exit 1
-canon_target=`/bin/sh $srcdir/config.sub $target` || exit 1
+host_exeext=
+cpp_install_dir=
# Decode the host machine, then the target machine.
# For the host machine, we save the xm_file variable as host_xm_file;
# then we decode the target machine and forget everything else
# that came from the host machine.
-for machine in $canon_build $canon_host $canon_target; do
+for machine in $build $host $target; do
- cpu_type=
- xm_file=
- tm_file=
out_file=
xmake_file=
tmake_file=
@@ -491,15 +2237,18 @@ for machine in $canon_build $canon_host $canon_target; do
extra_parts=
extra_programs=
extra_objs=
+ extra_host_objs=
extra_gcc_objs=
+ xm_defines=
+ float_format=
# Set this to force installation and use of collect2.
use_collect2=
# Set this to override the default target model.
target_cpu_default=
- # Set this to force use of install.sh.
- broken_install=
# Set this to control which fixincludes program to use.
- fixincludes=fixincludes
+ if [ x$fast_fixinc != xyes ] ; then
+ fixincludes=fixincludes
+ else fixincludes=fixinc.sh ; fi
# Set this to control how the header file directory is installed.
install_headers_dir=install-headers-tar
# Set this to a non-empty list of args to pass to cpp if the target
@@ -509,6 +2258,74 @@ for machine in $canon_build $canon_host $canon_target; do
truncate_target=
# Set this if gdb needs a dir command with `dirname $out_file`
gdb_needs_out_file_path=
+ # Set this if the build machine requires executables to have a
+ # file name suffix.
+ exeext=
+ # Set this to control which thread package will be used.
+ thread_file=
+ # Reinitialize these from the flag values every loop pass, since some
+ # configure entries modify them.
+ gas="$gas_flag"
+ gnu_ld="$gnu_ld_flag"
+ enable_threads=$enable_threads_flag
+
+ # Set default cpu_type, tm_file and xm_file so it can be updated in
+ # each machine entry.
+ cpu_type=`echo $machine | sed 's/-.*$//'`
+ case $machine in
+ alpha*-*-*)
+ cpu_type=alpha
+ ;;
+ arm*-*-*)
+ cpu_type=arm
+ ;;
+ c*-convex-*)
+ cpu_type=convex
+ ;;
+ i[34567]86-*-*)
+ cpu_type=i386
+ ;;
+ hppa*-*-*)
+ cpu_type=pa
+ ;;
+ m68000-*-*)
+ cpu_type=m68k
+ ;;
+ mips*-*-*)
+ cpu_type=mips
+ ;;
+ powerpc*-*-*)
+ cpu_type=rs6000
+ ;;
+ pyramid-*-*)
+ cpu_type=pyr
+ ;;
+ sparc*-*-*)
+ cpu_type=sparc
+ ;;
+ esac
+
+ tm_file=${cpu_type}/${cpu_type}.h
+ xm_file=${cpu_type}/xm-${cpu_type}.h
+
+ # Common parts for linux-gnu and openbsd systems
+ case $machine in
+ *-*-linux-gnu*)
+ xm_defines="HAVE_ATEXIT POSIX BSTRING"
+ ;;
+ *-*-openbsd*)
+ tm_file=${cpu_type}/openbsd.h
+ # On OpenBSD systems, the headers are okay
+ fixincludes=Makefile.in
+ tmake_file="t-libc-ok t-openbsd"
+ # avoid surprises, always provide an xm-openbsd file
+ xm_file=${cpu_type}/xm-openbsd.h
+ if test x$enable_threads = xyes; then
+ thread_file='posix'
+ tmake_file="${tmake_file} t-openbsd-thread"
+ fi
+ ;;
+ esac
case $machine in
# Support site-specific machine types.
@@ -529,74 +2346,138 @@ for machine in $canon_build $canon_host $canon_target; do
1750a-*-*)
;;
a29k-*-bsd* | a29k-*-sym1*)
- tm_file=a29k/unix.h
- xm_file=a29k/xm-unix.h
+ tm_file="${tm_file} a29k/unix.h"
+ xm_defines=USG
xmake_file=a29k/x-unix
- tmake_file=a29k/t-a29k
use_collect2=yes
;;
a29k-*-udi | a29k-*-coff)
+ tm_file="${tm_file} dbxcoff.h a29k/udi.h"
tmake_file=a29k/t-a29kbare
- tm_file=a29k/a29k-udi.h
;;
- a29k-*-vxworks*)
+ a29k-wrs-vxworks*)
+ tm_file="${tm_file} dbxcoff.h a29k/udi.h a29k/vx29k.h"
tmake_file=a29k/t-vx29k
- tm_file=a29k/vx29k.h
extra_parts="crtbegin.o crtend.o"
+ thread_file='vxworks'
;;
a29k-*-*) # Default a29k environment.
use_collect2=yes
;;
- alpha-dec-osf[23456789]*)
- tm_file=alpha/osf2.h
- if [ x$stabs = xyes ]
- then
- tm_file=alpha/gdb-osf2.h
- fi
- if [ x$gas != xyes ]
- then
- extra_passes="mips-tfile mips-tdump"
- fi
- broken_install=yes
- use_collect2=yes
+ alpha*-*-linux-gnuecoff*)
+ tm_file="${tm_file} alpha/linux-ecoff.h alpha/linux.h"
+ target_cpu_default="MASK_GAS"
+ gas=no
+ xmake_file=none
+ gas=yes gnu_ld=yes
+ ;;
+ alpha*-*-linux-gnulibc1*)
+ tm_file="${tm_file} alpha/elf.h alpha/linux.h alpha/linux-elf.h"
+ target_cpu_default="MASK_GAS"
+ tmake_file="t-linux t-linux-gnulibc1 alpha/t-linux alpha/t-crtbe"
+ extra_parts="crtbegin.o crtend.o"
+ fixincludes=fixinc.wrap
+ xmake_file=none
+ gas=yes gnu_ld=yes
+ if [ x$enable_threads = xyes ]; then
+ thread_file='posix'
+ fi
+ ;;
+ alpha*-*-linux-gnu*)
+ tm_file="${tm_file} alpha/elf.h alpha/linux.h alpha/linux-elf.h"
+ target_cpu_default="MASK_GAS"
+ tmake_file="t-linux alpha/t-linux alpha/t-crtbe"
+ extra_parts="crtbegin.o crtend.o"
+ xmake_file=none
+ fixincludes=Makefile.in
+ gas=yes gnu_ld=yes
+ if [ x$enable_threads = xyes ]; then
+ thread_file='posix'
+ fi
+ ;;
+ alpha*-*-netbsd*)
+ tm_file="${tm_file} alpha/elf.h alpha/netbsd.h alpha/netbsdl-elf.h"
+ xm_file="xm-netbsd.h ${xm_file}"
+ target_cpu_default="MASK_GAS"
+ tmake_file="alpha/t-crtbe"
+ extra_parts="crtbegin.o crtend.o"
+ xmake_file=none
+ fixincludes=fixinc.wrap
+ gas=yes gnu_ld=yes
+ ;;
+
+ alpha*-*-openbsd*)
+ # default x-alpha is only appropriate for dec-osf.
+ target_cpu_default="MASK_GAS"
+ xmake_file=none
;;
- alpha-dec-osf1.2)
- tm_file=alpha/osf12.h
+
+ alpha*-dec-osf*)
if [ x$stabs = xyes ]
then
- tm_file=alpha/gdb-osf12.h
+ tm_file="${tm_file} dbx.h"
fi
if [ x$gas != xyes ]
then
extra_passes="mips-tfile mips-tdump"
fi
- broken_install=yes
use_collect2=yes
+ case $machine in
+ *-*-osf1*)
+ tm_file="${tm_file} alpha/osf.h alpha/osf12.h alpha/osf2or3.h"
+ ;;
+ *-*-osf[23]*)
+ tm_file="${tm_file} alpha/osf.h alpha/osf2or3.h"
+ ;;
+ *-*-osf4*)
+ tm_file="${tm_file} alpha/osf.h"
+ # Some versions of OSF4 (specifically X4.0-9 296.7) have
+ # a broken tar, so we use cpio instead.
+ install_headers_dir=install-headers-cpio
+ ;;
+ esac
+ case $machine in
+ *-*-osf4.0[b-z] | *-*-osf4.[1-9]*)
+ target_cpu_default=MASK_SUPPORT_ARCH
+ ;;
+ esac
;;
- alpha-*-osf*)
- if [ x$stabs = xyes ]
- then
- tm_file=alpha/gdb.h
- fi
- if [ x$gas != xyes ]
+ alpha*-*-vxworks*)
+ tm_file="${tm_file} dbx.h alpha/vxworks.h"
+ if x$gas != xyes
then
extra_passes="mips-tfile mips-tdump"
fi
- broken_install=yes
use_collect2=yes
;;
- alpha-*-winnt3*)
- tm_file=alpha/win-nt.h
- xm_file=alpha/xm-winnt.h
+ alpha*-*-winnt*)
+ tm_file="${tm_file} alpha/win-nt.h"
+ xm_file="${xm_file} config/winnt/xm-winnt.h alpha/xm-winnt.h"
tmake_file=t-libc-ok
xmake_file=winnt/x-winnt
- extra_objs=oldnames.o
+ extra_host_objs=oldnames.o
extra_gcc_objs="spawnv.o oldnames.o"
fixincludes=fixinc.winnt
if [ x$gnu_ld != xyes ]
then
extra_programs=ld.exe
fi
+ if [ x$enable_threads = xyes ]; then
+ thread_file='win32'
+ fi
+ ;;
+ alpha*-dec-vms*)
+ tm_file=alpha/vms.h
+ xm_file="${xm_file} alpha/xm-vms.h"
+ tmake_file=alpha/t-vms
+ fixincludes=Makefile.in
+ ;;
+ arc-*-elf*)
+ extra_parts="crtinit.o crtfini.o"
+ ;;
+ arm-*-coff* | armel-*-coff*)
+ tm_file=arm/coff.h
+ tmake_file=arm/t-bare
;;
arm-*-riscix1.[01]*) # Acorn RISC machine (early versions)
tm_file=arm/riscix1-1.h
@@ -614,51 +2495,65 @@ for machine in $canon_build $canon_host $canon_target; do
use_collect2=yes
;;
arm-semi-aout | armel-semi-aout)
- cpu_type=arm
tm_file=arm/semi.h
tmake_file=arm/t-semi
fixincludes=Makefile.in # There is nothing to fix
;;
- arm-*-*) # generic version
+ arm-semi-aof | armel-semi-aof)
+ tm_file=arm/semiaof.h
+ tmake_file=arm/t-semiaof
+ fixincludes=Makefile.in # There is nothing to fix
+ ;;
+ arm*-*-netbsd*)
+ tm_file=arm/netbsd.h
+ xm_file="xm-netbsd.h ${xm_file}"
+ tmake_file="t-netbsd arm/t-netbsd"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ ;;
+ arm-*-linux-gnuaout*) # ARM GNU/Linux
+ cpu_type=arm
+ xmake_file=x-linux
+ tm_file=arm/linux-gas.h
+ tmake_file=arm/t-linux
+ fixincludes=Makefile.in
+ gnu_ld=yes
+ ;;
+ arm-*-aout)
+ tm_file=arm/aout.h
+ tmake_file=arm/t-bare
;;
c1-convex-*) # Convex C1
- cpu_type=convex
- tm_file=convex/convex1.h
+ target_cpu_default=1
use_collect2=yes
fixincludes=Makefile.in
;;
c2-convex-*) # Convex C2
- cpu_type=convex
- tm_file=convex/convex2.h
+ target_cpu_default=2
use_collect2=yes
fixincludes=Makefile.in
;;
c32-convex-*)
- cpu_type=convex
- tm_file=convex/convex32.h # Convex C32xx
+ target_cpu_default=4
use_collect2=yes
fixincludes=Makefile.in
;;
c34-convex-*)
- cpu_type=convex
- tm_file=convex/convex34.h # Convex C34xx
+ target_cpu_default=8
use_collect2=yes
fixincludes=Makefile.in
;;
c38-convex-*)
- cpu_type=convex
- tm_file=convex/convex38.h # Convex C38xx
+ target_cpu_default=16
use_collect2=yes
fixincludes=Makefile.in
;;
clipper-intergraph-clix*)
- broken_install=yes
- cpu_type=clipper
+ tm_file="${tm_file} svr3.h clipper/clix.h"
xm_file=clipper/xm-clix.h
- tm_file=clipper/clix.h
+ xmake_file=clipper/x-clix
extra_headers=va-clipper.h
extra_parts="crtbegin.o crtend.o"
- xmake_file=clipper/x-clix
install_headers_dir=install-headers-cpio
;;
dsp16xx-*)
@@ -670,182 +2565,196 @@ for machine in $canon_build $canon_host $canon_target; do
# fx80-alliant-*) # Alliant FX/80
# ;;
h8300-*-*)
- cpu_type=h8300
+ float_format=i32
+ ;;
+ hppa*-*-openbsd*)
+ target_cpu_default="MASK_SNAKE"
+ tmake_file=pa/t-openbsd
+ ;;
+ hppa1.1-*-pro*)
+ tm_file="pa/pa-pro.h ${tm_file} pa/pa-pro-end.h libgloss.h"
+ xm_file=pa/xm-papro.h
+ tmake_file=pa/t-pro
;;
hppa1.1-*-osf*)
- cpu_type=pa
- tm_file=pa/pa1-osf.h
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-osf.h"
use_collect2=yes
fixincludes=Makefile.in
;;
+ hppa1.1-*-rtems*)
+ tm_file="pa/pa-pro.h ${tm_file} pa/pa-pro-end.h libgloss.h pa/rtems.h"
+ xm_file=pa/xm-papro.h
+ tmake_file=pa/t-pro
+ ;;
hppa1.0-*-osf*)
- cpu_type=pa
- tm_file=pa/pa-osf.h
+ tm_file="${tm_file} pa/pa-osf.h"
use_collect2=yes
fixincludes=Makefile.in
;;
hppa1.1-*-bsd*)
- cpu_type=pa
- tm_file=pa/pa1.h
+ target_cpu_default=1
use_collect2=yes
fixincludes=Makefile.in
;;
hppa1.0-*-bsd*)
- cpu_type=pa
use_collect2=yes
fixincludes=Makefile.in
;;
hppa1.0-*-hpux7*)
- cpu_type=pa
+ tm_file="pa/pa-oldas.h ${tm_file} pa/pa-hpux7.h"
xm_file=pa/xm-pahpux.h
xmake_file=pa/x-pa-hpux
- tmake_file=pa/t-pa
if [ x$gas = xyes ]
then
- tm_file=pa/pa-gux7.h
- else
- tm_file=pa/pa-hpux7.h
+ tm_file="${tm_file} pa/gas.h"
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
;;
hppa1.0-*-hpux8.0[0-2]*)
- cpu_type=pa
+ tm_file="${tm_file} pa/pa-hpux.h"
xm_file=pa/xm-pahpux.h
xmake_file=pa/x-pa-hpux
- tmake_file=pa/t-pa
if [ x$gas = xyes ]
then
- tm_file=pa/pa-ghpux.h
+ tm_file="${tm_file} pa/pa-gas.h"
else
- tm_file=pa/pa-oldas.h
+ tm_file="pa/pa-oldas.h ${tm_file}"
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
;;
hppa1.1-*-hpux8.0[0-2]*)
- cpu_type=pa
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-hpux.h"
xm_file=pa/xm-pahpux.h
xmake_file=pa/x-pa-hpux
- tmake_file=pa/t-pa
if [ x$gas = xyes ]
then
- tm_file=pa/pa1-ghpux.h
+ tm_file="${tm_file} pa/pa-gas.h"
else
- tm_file=pa/pa1-oldas.h
+ tm_file="pa/pa-oldas.h ${tm_file}"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.1-*-hpux8*)
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-hpux.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [ x$gas = xyes ]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.0-*-hpux8*)
+ tm_file="${tm_file} pa/pa-hpux.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [ x$gas = xyes ]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
;;
- hppa1.1-*-hpux9* | \
hppa1.1-*-hpux10*)
- cpu_type=pa
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hpux10.h"
xm_file=pa/xm-pahpux.h
xmake_file=pa/x-pa-hpux
tmake_file=pa/t-pa
if [ x$gas = xyes ]
then
- tm_file=pa/pa1-ghpux9.h
- else
- tm_file=pa/pa1-hpux9.h
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ if [ x$enable_threads = x ]; then
+ enable_threads=$have_pthread_h
+ fi
+ if [ x$enable_threads = xyes ]; then
+ thread_file='dce'
+ tmake_file="${tmake_file} pa/t-dce-thr"
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
;;
- hppa1.0-*-hpux9* | \
hppa1.0-*-hpux10*)
- cpu_type=pa
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hpux10.h"
xm_file=pa/xm-pahpux.h
xmake_file=pa/x-pa-hpux
tmake_file=pa/t-pa
if [ x$gas = xyes ]
then
- tm_file=pa/pa-ghpux9.h
- else
- tm_file=pa/pa-hpux9.h
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ if [ x$enable_threads = x ]; then
+ enable_threads=$have_pthread_h
+ fi
+ if [ x$enable_threads = xyes ]; then
+ thread_file='dce'
+ tmake_file="${tmake_file} pa/t-dce-thr"
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
;;
hppa1.1-*-hpux*)
- cpu_type=pa
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hpux9.h"
xm_file=pa/xm-pahpux.h
xmake_file=pa/x-pa-hpux
- tmake_file=pa/t-pa
if [ x$gas = xyes ]
then
- tm_file=pa/pa1-ghpux.h
- else
- tm_file=pa/pa1-hpux.h
+ tm_file="${tm_file} pa/pa-gas.h"
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
;;
hppa1.0-*-hpux*)
- cpu_type=pa
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hpux9.h"
xm_file=pa/xm-pahpux.h
xmake_file=pa/x-pa-hpux
- tmake_file=pa/t-pa
if [ x$gas = xyes ]
then
- tm_file=pa/pa-ghpux.h
- else
- tm_file=pa/pa-hpux.h
+ tm_file="${tm_file} pa/pa-gas.h"
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
;;
hppa1.1-*-hiux*)
- cpu_type=pa
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hiux.h"
xm_file=pa/xm-pahpux.h
xmake_file=pa/x-pa-hpux
- tmake_file=pa/t-pa
if [ x$gas = xyes ]
then
- tm_file=pa/pa1-ghiux.h
- else
- tm_file=pa/pa1-hiux.h
+ tm_file="${tm_file} pa/pa-gas.h"
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
;;
hppa1.0-*-hiux*)
- cpu_type=pa
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hiux.h"
xm_file=pa/xm-pahpux.h
xmake_file=pa/x-pa-hpux
- tmake_file=pa/t-pa
if [ x$gas = xyes ]
then
- tm_file=pa/pa-ghiux.h
- else
- tm_file=pa/pa-hiux.h
+ tm_file="${tm_file} pa/pa-gas.h"
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
;;
hppa*-*-lites*)
- cpu_type=pa
- tm_file=pa/pa1.h
+ target_cpu_default=1
use_collect2=yes
fixincludes=Makefile.in
;;
i370-*-mvs*)
- cpu_type=i370
- tm_file=i370/mvs.h
- xm_file=i370/xm-mvs.h
- out_file=i370/mvs370.c
;;
- i[3456]86-ibm-aix*) # IBM PS/2 running AIX
- cpu_type=i386
+ i[34567]86-ibm-aix*) # IBM PS/2 running AIX
if [ x$gas = xyes ]
then
tm_file=i386/aix386.h
@@ -855,28 +2764,34 @@ for machine in $canon_build $canon_host $canon_target; do
tm_file=i386/aix386ng.h
use_collect2=yes
fi
- xm_file=i386/xm-aix.h
+ xm_file="xm-alloca.h i386/xm-aix.h ${xm_file}"
+ xm_defines=USG
xmake_file=i386/x-aix
- broken_install=yes
;;
- i486-ncr-sysv4*) # NCR 3000 - i486 running system V.4
- cpu_type=i386
- xm_file=i386/xm-sysv4.h
+ i[34567]86-ncr-sysv4*) # NCR 3000 - ix86 running system V.4
+ xm_file="xm-siglist.h xm-alloca.h ${xm_file}"
+ xm_defines="USG POSIX SMALL_ARG_MAX"
xmake_file=i386/x-ncr3000
- tm_file=i386/sysv4.h
+ if [ x$stabs = xyes -a x$gas = xyes ]
+ then
+ tm_file=i386/sysv4gdb.h
+ else
+ tm_file=i386/sysv4.h
+ fi
extra_parts="crtbegin.o crtend.o"
tmake_file=i386/t-crtpic
;;
- i[3456]86-next-*)
- cpu_type=i386
+ i[34567]86-next-*)
tm_file=i386/next.h
- out_file=i386/next.c
xm_file=i386/xm-next.h
tmake_file=i386/t-next
xmake_file=i386/x-next
+ extra_objs=nextstep.o
+ if [ x$enable_threads = xyes ]; then
+ thread_file='mach'
+ fi
;;
- i[3456]86-sequent-bsd*) # 80386 from Sequent
- cpu_type=i386
+ i[34567]86-sequent-bsd*) # 80386 from Sequent
use_collect2=yes
if [ x$gas = xyes ]
then
@@ -885,150 +2800,183 @@ for machine in $canon_build $canon_host $canon_target; do
tm_file=i386/sequent.h
fi
;;
- i[3456]86-sequent-ptx1*)
- cpu_type=i386
- xm_file=i386/xm-sysv3.h
+ i[34567]86-sequent-ptx1*)
+ xm_defines="USG SVR3"
xmake_file=i386/x-sysv3
tm_file=i386/seq-sysv3.h
tmake_file=i386/t-crtstuff
fixincludes=fixinc.ptx
extra_parts="crtbegin.o crtend.o"
install_headers_dir=install-headers-cpio
- broken_install=yes
;;
- i[3456]86-sequent-ptx2* | i[3456]86-sequent-sysv*)
- cpu_type=i386
- xm_file=i386/xm-sysv3.h
+ i[34567]86-sequent-ptx2* | i[34567]86-sequent-sysv3*)
+ xm_defines="USG SVR3"
xmake_file=i386/x-sysv3
tm_file=i386/seq2-sysv3.h
tmake_file=i386/t-crtstuff
extra_parts="crtbegin.o crtend.o"
fixincludes=fixinc.ptx
install_headers_dir=install-headers-cpio
- broken_install=yes
+ ;;
+ i[34567]86-sequent-ptx4* | i[34567]86-sequent-sysv4*)
+ xm_file="xm-siglist.h xm-alloca.h ${xm_file}"
+ xm_defines="USG POSIX SMALL_ARG_MAX"
+ xmake_file=x-svr4
+ tm_file=i386/ptx4-i.h
+ tmake_file=t-svr4
+ extra_parts="crtbegin.o crtend.o"
+ fixincludes=fixinc.ptx
+ install_headers_dir=install-headers-cpio
;;
i386-sun-sunos*) # Sun i386 roadrunner
- xm_file=i386/xm-sun.h
+ xm_defines=USG
tm_file=i386/sun.h
use_collect2=yes
;;
- i[3456]86-*-aout*)
- cpu_type=i386
+ i[34567]86-wrs-vxworks*)
+ tm_file=i386/vxi386.h
+ tmake_file=i386/t-i386bare
+ ;;
+ i[34567]86-*-aout*)
tm_file=i386/i386-aout.h
tmake_file=i386/t-i386bare
;;
- i[3456]86-*-bsdi* | i[3456]86-*-bsd386*)
- cpu_type=i386
+ i[34567]86-*-bsdi* | i[34567]86-*-bsd386*)
tm_file=i386/bsd386.h
- xm_file=i386/xm-bsd386.h
# tmake_file=t-libc-ok
;;
- i[3456]86-*-bsd*)
- cpu_type=i386
+ i[34567]86-*-bsd*)
tm_file=i386/386bsd.h
- xm_file=i386/xm-bsd386.h
# tmake_file=t-libc-ok
# Next line turned off because both 386BSD and BSD/386 use GNU ld.
# use_collect2=yes
;;
- i[3456]86-*-freebsd*)
- cpu_type=i386
+ i[34567]86-*-freebsdelf*)
+ tm_file="i386/i386.h i386/att.h linux.h i386/freebsd-elf.h i386/perform.h"
+ # On FreeBSD, the headers are already ok, except for math.h.
+ fixincludes=fixinc.wrap
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ tmake_file=i386/t-freebsd
+ gas=yes
+ gnu_ld=yes
+ stabs=yes
+ ;;
+ i[34567]86-*-freebsd*)
tm_file=i386/freebsd.h
- xm_file=i386/xm-freebsd.h
- # On FreeBSD, the headers are already ok.
- fixincludes=Makefile.in
- xmake_file=i386/x-freebsd
+ # On FreeBSD, the headers are already ok, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=i386/t-freebsd
;;
- i[3456]86-*-netbsd*)
- cpu_type=i386
+ i[34567]86-*-netbsd*)
tm_file=i386/netbsd.h
- xm_file=i386/xm-netbsd.h
- # On NetBSD, the headers are already okay.
- fixincludes=Makefile.in
- tmake_file=t-libc-ok
- xmake_file=x-netbsd
- ;;
- i[3456]86-*-coff*)
- cpu_type=i386
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ ;;
+ i[34567]86-*-openbsd*)
+ # Remove when the math emulator is fixed
+ target_cpu_default="MASK_NO_FANCY_MATH_387"
+ # we need collect2 until our bug is fixed...
+ use_collect2=yes
+ ;;
+ i[34567]86-*-coff*)
tm_file=i386/i386-coff.h
tmake_file=i386/t-i386bare
;;
- i[3456]86-*-isc*) # 80386 running ISC system
- cpu_type=i386
- xm_file=i386/xm-isc.h
+ i[34567]86-*-isc*) # 80386 running ISC system
+ xm_file="${xm_file} i386/xm-isc.h"
+ xm_defines="USG SVR3"
case $machine in
- i[3456]86-*-isc[34]*)
+ i[34567]86-*-isc[34]*)
xmake_file=i386/x-isc3
;;
*)
xmake_file=i386/x-isc
;;
esac
- echo $xmake_file
if [ x$gas = xyes -a x$stabs = xyes ]
then
tm_file=i386/iscdbx.h
tmake_file=i386/t-svr3dbx
- extra_parts="crtbegin.o crtend.o svr3.ifile svr3z.ifile"
+ extra_parts="svr3.ifile svr3z.ifile"
else
tm_file=i386/isccoff.h
tmake_file=i386/t-crtstuff
extra_parts="crtbegin.o crtend.o"
fi
install_headers_dir=install-headers-cpio
- broken_install=yes
;;
- i[3456]86-*-linux*oldld*) # Intel 80386's running GNU/Linux
- cpu_type=i386 # with a.out format using pre BFD linkers
- xm_file=i386/xm-linux.h
- xmake_file=x-linux
+ i[34567]86-*-linux-gnuoldld*) # Intel 80386's running GNU/Linux
+ # with a.out format using
+ # pre BFD linkers
+ xmake_file=x-linux-aout
+ tmake_file="t-linux-aout i386/t-crtstuff"
tm_file=i386/linux-oldld.h
- fixincludes=Makefile.in # The headers are ok already.
- broken_install=yes
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
gnu_ld=yes
+ float_format=i386
;;
- i[3456]86-*-linux*aout*) # Intel 80386's running GNU/Linux
- cpu_type=i386 # with a.out format
- xm_file=i386/xm-linux.h
- xmake_file=x-linux
+ i[34567]86-*-linux-gnuaout*) # Intel 80386's running GNU/Linux
+ # with a.out format
+ xmake_file=x-linux-aout
+ tmake_file="t-linux-aout i386/t-crtstuff"
tm_file=i386/linux-aout.h
- fixincludes=Makefile.in # The headers are ok already.
- broken_install=yes
- gnu_ld=yes
- ;;
- i[3456]86-*-linux*gnulibc1) # Intel 80386's running GNU/Linux
- cpu_type=i386 # with ELF format, using GNU libc v1.
- xm_file=i386/xm-linux.h
- xmake_file=x-linux
- tmake_file=t-linux-gnulibc1
- tm_file=i386/linux.h
- fixincludes=Makefile.in # The headers are ok already.
- broken_install=yes
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
gnu_ld=yes
+ float_format=i386
+ ;;
+ i[34567]86-*-linux-gnulibc1) # Intel 80386's running GNU/Linux
+ # with ELF format using the
+ # GNU/Linux C library 5
+ xmake_file=x-linux
+ tm_file=i386/linux.h
+ tmake_file="t-linux t-linux-gnulibc1 i386/t-crtstuff"
extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
- ;;
- i[3456]86-*-linux*) # Intel 80386's running GNU/Linux
- cpu_type=i386 # with ELF format
- xm_file=i386/xm-linux.h
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ float_format=i386
+ if [ x$enable_threads = xyes ]; then
+ thread_file='single'
+ fi
+ ;;
+ i[34567]86-*-linux-gnu*) # Intel 80386's running GNU/Linux
+ # with ELF format using glibc 2
+ # aka GNU/Linux C library 6
xmake_file=x-linux
- tmake_file=t-linux
tm_file=i386/linux.h
- fixincludes=Makefile.in # The headers are ok already.
- broken_install=yes
- gnu_ld=yes
- # GNU libc version 2 does not supply these;
- # we want them from GCC.
+ tmake_file="t-linux i386/t-crtstuff"
extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ float_format=i386
+ if [ x$enable_threads = xyes ]; then
+ thread_file='posix'
+ fi
+ ;;
+ i[34567]86-*-gnu*)
+ float_format=i386
+ ;;
+ i[34567]86-go32-msdos | i[34567]86-*-go32*)
+ xm_file=i386/xm-go32.h
+ tm_file=i386/go32.h
+ tmake_file=i386/t-go32
+ ;;
+ i[34567]86-pc-msdosdjgpp*)
+ xm_file=i386/xm-go32.h
+ tm_file=i386/go32.h
+ tmake_file=i386/t-go32
+ gnu_ld=yes
+ gas=yes
;;
- i[3456]86-*-gnu*)
- cpu_type=i386 # GNU supports this CPU; rest done below.
+ i[34567]86-moss-msdos* | i[34567]86-*-moss*)
+ tm_file=i386/moss.h
+ tmake_file=t-libc-ok
+ fixincludes=Makefile.in
+ gnu_ld=yes
+ gas=yes
;;
- i[3456]86-go32-msdos | i[3456]86-*-go32)
- cpu_type=i386
- tm_file=i386/go32.h
- ;;
- i[3456]86-*-lynxos*)
- cpu_type=i386
+ i[34567]86-*-lynxos*)
if [ x$gas = xyes ]
then
tm_file=i386/lynx.h
@@ -1039,14 +2987,12 @@ for machine in $canon_build $canon_host $canon_target; do
tmake_file=i386/t-i386bare
xmake_file=x-lynx
;;
- i[3456]86-*-mach*)
- cpu_type=i386
+ i[34567]86-*-mach*)
tm_file=i386/mach.h
# tmake_file=t-libc-ok
use_collect2=yes
;;
- i[3456]86-*-osfrose*) # 386 using OSF/rose
- cpu_type=i386
+ i[34567]86-*-osfrose*) # 386 using OSF/rose
if [ x$elf = xyes ]
then
tm_file=i386/osfelf.h
@@ -1055,16 +3001,48 @@ for machine in $canon_build $canon_host $canon_target; do
tm_file=i386/osfrose.h
use_collect2=yes
fi
- xm_file=i386/xm-osf.h
+ xm_file="i386/xm-osf.h ${xm_file}"
xmake_file=i386/x-osfrose
+ tmake_file=i386/t-osf
extra_objs=halfpic.o
;;
- i[3456]86-*-sco3.2v4*) # 80386 running SCO 3.2v4 system
+ i[34567]86-go32-rtems*)
cpu_type=i386
- xm_file=i386/xm-sco.h
+ xm_file=i386/xm-go32.h
+ tm_file=i386/go32-rtems.h
+ tmake_file="i386/t-go32 t-rtems"
+ ;;
+ i[34567]86-*-rtemself*)
+ cpu_type=i386
+ tm_file=i386/rtemself.h
+ tmake_file="i386/t-i386bare t-rtems"
+ ;;
+ i[34567]86-*-rtems*)
+ cpu_type=i386
+ tm_file=i386/rtems.h
+ tmake_file="i386/t-i386bare t-rtems"
+ ;;
+ i[34567]86-*-sco3.2v5*) # 80386 running SCO Open Server 5
+ xm_file="xm-siglist.h xm-alloca.h ${xm_file} i386/xm-sco5.h"
+ xm_defines="USG SVR3"
+ xmake_file=i386/x-sco5
+ fixincludes=fixinc.sco
+ install_headers_dir=install-headers-cpio
+ tm_file=i386/sco5.h
+ if [ x$gas = xyes ]
+ then
+ tm_file="i386/sco5gas.h ${tm_file}"
+ tmake_file=i386/t-sco5gas
+ else
+ tmake_file=i386/t-sco5
+ fi
+ extra_parts="crti.o crtbegin.o crtend.o crtbeginS.o crtendS.o"
+ ;;
+ i[34567]86-*-sco3.2v4*) # 80386 running SCO 3.2v4 system
+ xm_file="${xm_file} i386/xm-sco.h"
+ xm_defines="USG SVR3 BROKEN_LDEXP SMALL_ARG_MAX NO_SYS_SIGLIST"
xmake_file=i386/x-sco4
fixincludes=fixinc.sco
- broken_install=yes
install_headers_dir=install-headers-cpio
if [ x$stabs = xyes ]
then
@@ -1076,12 +3054,11 @@ for machine in $canon_build $canon_host $canon_target; do
tmake_file=i386/t-crtstuff
extra_parts="crtbegin.o crtend.o"
fi
+ truncate_target=yes
;;
- i[3456]86-*-sco*) # 80386 running SCO system
- cpu_type=i386
+ i[34567]86-*-sco*) # 80386 running SCO system
xm_file=i386/xm-sco.h
xmake_file=i386/x-sco
- broken_install=yes
install_headers_dir=install-headers-cpio
if [ x$stabs = xyes ]
then
@@ -1095,32 +3072,70 @@ for machine in $canon_build $canon_host $canon_target; do
fi
truncate_target=yes
;;
- i[3456]86-*-solaris2* | i[3456]86-*-sunos5*)
- cpu_type=i386
- xm_file=i386/xm-sysv4.h
- tm_file=i386/sol2.h
+ i[34567]86-*-solaris2*)
+ xm_file="xm-siglist.h xm-alloca.h ${xm_file}"
+ xm_defines="USG POSIX SMALL_ARG_MAX"
+ if [ x$stabs = xyes ]
+ then
+ tm_file=i386/sol2dbg.h
+ else
+ tm_file=i386/sol2.h
+ fi
tmake_file=i386/t-sol2
- extra_parts="crt1.o crti.o crtn.o crtbegin.o crtend.o"
+ extra_parts="crt1.o crti.o crtn.o gcrt1.o gmon.o crtbegin.o crtend.o"
xmake_file=x-svr4
- fixincludes=fixinc.svr4
- broken_install=yes
+ case $machine in
+ *-*-solaris2.[0-4])
+ fixincludes=fixinc.svr4;;
+ *)
+ fixincludes=fixinc.wrap;;
+ esac
+ if [ x$enable_threads = xyes ]; then
+ thread_file='solaris'
+ fi
;;
- i[3456]86-*-sysv4*) # Intel 80386's running system V.4
- cpu_type=i386
- xm_file=i386/xm-sysv4.h
+ i[34567]86-*-sysv5*) # Intel x86 on System V Release 5
+ xm_file="xm-alloca.h xm-siglist.h ${xm_file}"
+ xm_defines="USG POSIX"
+ tm_file=i386/sysv4.h
+ if [ x$stabs = xyes ]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ tmake_file=i386/t-crtpic
+ xmake_file=x-svr4
+ extra_parts="crtbegin.o crtend.o"
+ fixincludes=fixinc.svr4
+ ;;
+ i[34567]86-*-sysv4*) # Intel 80386's running system V.4
+ xm_file="xm-siglist.h xm-alloca.h ${xm_file}"
+ xm_defines="USG POSIX SMALL_ARG_MAX"
+ tm_file=i386/sysv4.h
if [ x$stabs = xyes ]
then
- tm_file=i386/sysv4gdb.h
- else
- tm_file=i386/sysv4.h
+ tm_file="${tm_file} dbx.h"
fi
tmake_file=i386/t-crtpic
xmake_file=x-svr4
extra_parts="crtbegin.o crtend.o"
;;
- i[3456]86-*-sysv*) # Intel 80386's running system V
+ i[34567]86-*-osf1*) # Intel 80386's running OSF/1 1.3+
cpu_type=i386
- xm_file=i386/xm-sysv3.h
+ xm_file="${xm_file} xm-svr4.h i386/xm-sysv4.h i386/xm-osf1elf.h"
+ xm_defines="USE_C_ALLOCA SMALL_ARG_MAX"
+ fixincludes=Makefile.in #Don't do it on OSF/1
+ if [ x$stabs = xyes ]
+ then
+ tm_file=i386/osf1elfgdb.h
+ else
+ tm_file=i386/osf1elf.h
+ fi
+ tmake_file=i386/t-osf1elf
+ xmake_file=i386/x-osf1elf
+ extra_parts="crti.o crtn.o crtbegin.o crtend.o"
+ ;;
+ i[34567]86-*-sysv*) # Intel 80386's running system V
+ xm_defines="USG SVR3"
xmake_file=i386/x-sysv3
if [ x$gas = xyes ]
then
@@ -1141,106 +3156,156 @@ for machine in $canon_build $canon_host $canon_target; do
fi
;;
i386-*-vsta) # Intel 80386's running VSTa kernel
- xm_file=i386/xm-vsta.h
+ xm_file="${xm_file} i386/xm-vsta.h"
tm_file=i386/vsta.h
tmake_file=i386/t-vsta
xmake_file=i386/x-vsta
;;
- i[3456]86-*-winnt3*)
- cpu_type=i386
+ i[34567]86-*-pe | i[34567]86-*-cygwin32)
+ xm_file="${xm_file} i386/xm-cygwin32.h"
+ tmake_file=i386/t-cygwin32
+ tm_file=i386/cygwin32.h
+ xmake_file=i386/x-cygwin32
+ extra_objs=winnt.o
+ fixincludes=Makefile.in
+ if [ x$enable_threads = xyes ]; then
+ thread_file='win32'
+ fi
+ exeext=.exe
+ ;;
+ i[34567]86-*-mingw32*)
+ tm_file=i386/mingw32.h
+ xm_file="${xm_file} i386/xm-mingw32.h"
+ tmake_file="i386/t-cygwin32 i386/t-mingw32"
+ extra_objs=winnt.o
+ xmake_file=i386/x-cygwin32
+ fixincludes=Makefile.in
+ if [ x$enable_threads = xyes ]; then
+ thread_file='win32'
+ fi
+ exeext=.exe
+ case $machine in
+ *mingw32msv*)
+ ;;
+ *mingw32crt* | *mingw32*)
+ tm_file="${tm_file} i386/crtdll.h"
+ ;;
+ esac
+ ;;
+ i[34567]86-*-winnt3*)
tm_file=i386/win-nt.h
out_file=i386/i386.c
- xm_file=i386/xm-winnt.h
+ xm_file="xm-winnt.h ${xm_file}"
xmake_file=winnt/x-winnt
tmake_file=i386/t-winnt
- extra_objs="winnt.o oldnames.o"
+ extra_host_objs="winnt.o oldnames.o"
extra_gcc_objs="spawnv.o oldnames.o"
fixincludes=fixinc.winnt
if [ x$gnu_ld != xyes ]
then
extra_programs=ld.exe
fi
+ if [ x$enable_threads = xyes ]; then
+ thread_file='win32'
+ fi
;;
+ i[34567]86-dg-dgux*)
+ xm_file="xm-alloca.h xm-siglist.h ${xm_file}"
+ xm_defines="USG POSIX"
+ out_file=i386/dgux.c
+ tm_file=i386/dgux.h
+ tmake_file=i386/t-dgux
+ xmake_file=i386/x-dgux
+ fixincludes=fixinc.dgux
+ install_headers_dir=install-headers-cpio
+ ;;
i860-alliant-*) # Alliant FX/2800
- xm_file=i860/xm-fx2800.h
+ tm_file="${tm_file} svr4.h i860/sysv4.h i860/fx2800.h"
+ xm_file="${xm_file}"
xmake_file=i860/x-fx2800
- tm_file=i860/fx2800.h
tmake_file=i860/t-fx2800
extra_parts="crtbegin.o crtend.o"
;;
i860-*-bsd*)
+ tm_file="${tm_file} i860/bsd.h"
if [ x$gas = xyes ]
then
- tm_file=i860/bsd-gas.h
- else
- tm_file=i860/bsd.h
+ tm_file="${tm_file} i860/bsd-gas.h"
fi
use_collect2=yes
;;
i860-*-mach*)
- xm_file=i860/xm-i860.h
- tm_file=i860/mach.h
+ tm_file="${tm_file} i860/mach.h"
tmake_file=t-libc-ok
;;
i860-*-osf*) # Intel Paragon XP/S, OSF/1AD
- xm_file=i860/xm-paragon.h
- tm_file=i860/paragon.h
+ tm_file="${tm_file} svr3.h i860/paragon.h"
+ xm_defines="USG SVR3"
tmake_file=t-osf
- broken_install=yes
;;
i860-*-sysv3*)
- xm_file=i860/xm-sysv3.h
+ tm_file="${tm_file} svr3.h i860/sysv3.h"
+ xm_defines="USG SVR3"
xmake_file=i860/x-sysv3
- tm_file=i860/sysv3.h
extra_parts="crtbegin.o crtend.o"
;;
i860-*-sysv4*)
- xm_file=i860/xm-sysv4.h
+ tm_file="${tm_file} svr4.h i860/sysv4.h"
+ xm_defines="USG SVR3"
xmake_file=i860/x-sysv4
- tm_file=i860/sysv4.h
tmake_file=t-svr4
extra_parts="crtbegin.o crtend.o"
;;
i960-wrs-vxworks5 | i960-wrs-vxworks5.0*)
+ tm_file="${tm_file} i960/vx960.h"
tmake_file=i960/t-vxworks960
- tm_file=i960/vx960.h
use_collect2=yes
+ thread_file='vxworks'
;;
- i960-wrs-vxworks5*)
+ i960-wrs-vxworks5* | i960-wrs-vxworks)
+ tm_file="${tm_file} dbxcoff.h i960/i960-coff.h i960/vx960-coff.h"
tmake_file=i960/t-vxworks960
- tm_file=i960/vx960-coff.h
use_collect2=yes
+ thread_file='vxworks'
;;
i960-wrs-vxworks*)
+ tm_file="${tm_file} i960/vx960.h"
tmake_file=i960/t-vxworks960
- tm_file=i960/vx960.h
use_collect2=yes
+ thread_file='vxworks'
;;
i960-*-coff*)
+ tm_file="${tm_file} dbxcoff.h i960/i960-coff.h libgloss.h"
tmake_file=i960/t-960bare
- tm_file=i960/i960-coff.h
+ use_collect2=yes
+ ;;
+ i960-*-rtems)
+ tmake_file="i960/t-960bare t-rtems"
+ tm_file="${tm_file} dbxcoff.h i960/rtems.h"
use_collect2=yes
;;
i960-*-*) # Default i960 environment.
use_collect2=yes
;;
+ m32r-*-elf*)
+ extra_parts="crtinit.o crtfini.o"
+ ;;
m68000-convergent-sysv*)
- cpu_type=m68k
- xm_file=m68k/xm-3b1.h
tm_file=m68k/ctix.h
+ xm_file="m68k/xm-3b1.h ${xm_file}"
+ xm_defines=USG
use_collect2=yes
extra_headers=math-68881.h
;;
m68000-hp-bsd*) # HP 9000/200 running BSD
- cpu_type=m68k
tm_file=m68k/hp2bsd.h
xmake_file=m68k/x-hp2bsd
use_collect2=yes
extra_headers=math-68881.h
;;
m68000-hp-hpux*) # HP 9000 series 300
- cpu_type=m68k
- xm_file=m68k/xm-hp320.h
+ xm_file="xm_alloca.h ${xm_file}"
+ xm_defines="USG NO_SYS_SIGLIST"
if [ x$gas = xyes ]
then
xmake_file=m68k/x-hp320g
@@ -1249,26 +3314,23 @@ for machine in $canon_build $canon_host $canon_target; do
xmake_file=m68k/x-hp320
tm_file=m68k/hp310.h
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
extra_headers=math-68881.h
;;
m68000-sun-sunos3*)
- cpu_type=m68k
tm_file=m68k/sun2.h
use_collect2=yes
extra_headers=math-68881.h
;;
m68000-sun-sunos4*)
- cpu_type=m68k
tm_file=m68k/sun2o4.h
use_collect2=yes
extra_headers=math-68881.h
;;
m68000-att-sysv*)
- cpu_type=m68k
- xm_file=m68k/xm-3b1.h
+ xm_file="m68k/xm-3b1.h ${xm_file}"
+ xm_defines=USG
if [ x$gas = xyes ]
then
tm_file=m68k/3b1g.h
@@ -1278,17 +3340,40 @@ for machine in $canon_build $canon_host $canon_target; do
use_collect2=yes
extra_headers=math-68881.h
;;
+ m68k-apple-aux*) # Apple Macintosh running A/UX
+ xm_defines="USG AUX"
+ tmake_file=m68k/t-aux
+ install_headers_dir=install-headers-cpio
+ extra_headers=math-68881.h
+ extra_parts="crt1.o mcrt1.o maccrt1.o crt2.o crtn.o"
+ tm_file=
+ if [ "$gnu_ld" = yes ]
+ then
+ tm_file="${tm_file} m68k/auxgld.h"
+ else
+ tm_file="${tm_file} m68k/auxld.h"
+ fi
+ if [ "$gas" = yes ]
+ then
+ tm_file="${tm_file} m68k/auxgas.h"
+ else
+ tm_file="${tm_file} m68k/auxas.h"
+ fi
+ tm_file="${tm_file} m68k/a-ux.h"
+ float_format=m68k
+ ;;
m68k-apollo-*)
- xmake_file=m68k/x-apollo68
tm_file=m68k/apollo68.h
+ xmake_file=m68k/x-apollo68
use_collect2=yes
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-altos-sysv*) # Altos 3068
if [ x$gas = xyes ]
then
- xm_file=m68k/xm-altos3068.h
tm_file=m68k/altos3068.h
+ xm_defines=USG
else
echo "The Altos is supported only with the GNU assembler" 1>&2
exit 1
@@ -1307,95 +3392,122 @@ for machine in $canon_build $canon_host $canon_target; do
else
tm_file=m68k/dpx2.h
fi
- xm_file=m68k/xm-m68kv.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines=USG
xmake_file=m68k/x-dpx2
use_collect2=yes
extra_headers=math-68881.h
;;
m68k-atari-sysv4*) # Atari variant of V.4.
tm_file=m68k/atari.h
- xm_file=m68k/xm-atari.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines="USG FULL_PROTOTYPES"
tmake_file=t-svr4
extra_parts="crtbegin.o crtend.o"
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-motorola-sysv*)
- xm_file=m68k/xm-mot3300.h
- xmake_file=m68k/x-mot3300
+ tm_file=m68k/mot3300.h
+ xm_file="xm-alloca.h m68k/xm-mot3300.h ${xm_file}"
+ xm_defines=NO_SYS_SIGLIST
if [ x$gas = xyes ]
then
- tm_file=m68k/mot3300g.h
+ xmake_file=m68k/x-mot3300-gas
+ if [ x$gnu_ld = xyes ]
+ then
+ tmake_file=m68k/t-mot3300-gald
+ else
+ tmake_file=m68k/t-mot3300-gas
+ use_collect2=yes
+ fi
else
- tm_file=m68k/mot3300.h
- gdb_needs_out_file_path=yes
+ xmake_file=m68k/x-mot3300
+ if [ x$gnu_ld = xyes ]
+ then
+ tmake_file=m68k/t-mot3300-gld
+ else
+ tmake_file=m68k/t-mot3300
+ use_collect2=yes
+ fi
fi
- use_collect2=yes
+ gdb_needs_out_file_path=yes
+ extra_parts="crt0.o mcrt0.o"
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-ncr-sysv*) # NCR Tower 32 SVR3
tm_file=m68k/tower-as.h
- xm_file=m68k/xm-tower.h
+ xm_defines="USG SVR3"
xmake_file=m68k/x-tower
extra_parts="crtbegin.o crtend.o"
extra_headers=math-68881.h
;;
m68k-plexus-sysv*)
tm_file=m68k/plexus.h
- xm_file=m68k/xm-plexus.h
+ xm_file="xm-alloca.h m68k/xm-plexus.h ${xm_file}"
+ xm_defines=USG
use_collect2=yes
extra_headers=math-68881.h
;;
m68k-tti-*)
tm_file=m68k/pbb.h
- xm_file=m68k/xm-m68kv.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines=USG
extra_headers=math-68881.h
;;
m68k-crds-unos*)
- xm_file=m68k/xm-crds.h
+ xm_file="xm-alloca.h m68k/xm-crds.h ${xm_file}"
+ xm_defines="USG unos"
xmake_file=m68k/x-crds
tm_file=m68k/crds.h
- broken_install=yes
use_collect2=yes
extra_headers=math-68881.h
;;
m68k-cbm-sysv4*) # Commodore variant of V.4.
tm_file=m68k/amix.h
- xm_file=m68k/xm-amix.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines="USG FULL_PROTOTYPES"
xmake_file=m68k/x-amix
tmake_file=t-svr4
extra_parts="crtbegin.o crtend.o"
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-ccur-rtu)
tm_file=m68k/ccur-GAS.h
xmake_file=m68k/x-ccur
extra_headers=math-68881.h
use_collect2=yes
- broken_install=yes
+ float_format=m68k
;;
m68k-hp-bsd4.4*) # HP 9000/3xx running 4.4bsd
tm_file=m68k/hp3bsd44.h
xmake_file=m68k/x-hp3bsd44
use_collect2=yes
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-hp-bsd*) # HP 9000/3xx running Berkeley Unix
tm_file=m68k/hp3bsd.h
use_collect2=yes
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-isi-bsd*)
- if [ x$nfp = xyes ]
+ if [ x$with_fp = xno ]
then
tm_file=m68k/isi-nfp.h
else
tm_file=m68k/isi.h
+ float_format=m68k
fi
use_collect2=yes
extra_headers=math-68881.h
;;
m68k-hp-hpux7*) # HP 9000 series 300 running HPUX version 7.
- xm_file=m68k/xm-hp320.h
+ xm_file="xm_alloca.h ${xm_file}"
+ xm_defines="USG NO_SYS_SIGLIST"
if [ x$gas = xyes ]
then
xmake_file=m68k/x-hp320g
@@ -1404,13 +3516,14 @@ for machine in $canon_build $canon_host $canon_target; do
xmake_file=m68k/x-hp320
tm_file=m68k/hpux7.h
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-hp-hpux*) # HP 9000 series 300
- xm_file=m68k/xm-hp320.h
+ xm_file="xm_alloca.h ${xm_file}"
+ xm_defines="USG NO_SYS_SIGLIST"
if [ x$gas = xyes ]
then
xmake_file=m68k/x-hp320g
@@ -1419,15 +3532,16 @@ for machine in $canon_build $canon_host $canon_target; do
xmake_file=m68k/x-hp320
tm_file=m68k/hp320.h
fi
- broken_install=yes
install_headers_dir=install-headers-cpio
use_collect2=yes
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-sun-mach*)
tm_file=m68k/sun3mach.h
use_collect2=yes
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-sony-newsos3*)
if [ x$gas = xyes ]
@@ -1438,6 +3552,7 @@ for machine in $canon_build $canon_host $canon_target; do
fi
use_collect2=yes
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-sony-bsd* | m68k-sony-newsos*)
if [ x$gas = xyes ]
@@ -1448,40 +3563,48 @@ for machine in $canon_build $canon_host $canon_target; do
fi
use_collect2=yes
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-next-nextstep2*)
tm_file=m68k/next21.h
- out_file=m68k/next.c
- xm_file=m68k/xm-next.h
+ xm_file="m68k/xm-next.h ${xm_file}"
tmake_file=m68k/t-next
xmake_file=m68k/x-next
+ extra_objs=nextstep.o
extra_headers=math-68881.h
use_collect2=yes
+ float_format=m68k
;;
m68k-next-nextstep3*)
tm_file=m68k/next.h
- out_file=m68k/next.c
- xm_file=m68k/xm-next.h
+ xm_file="m68k/xm-next.h ${xm_file}"
tmake_file=m68k/t-next
xmake_file=m68k/x-next
+ extra_objs=nextstep.o
extra_headers=math-68881.h
+ float_format=m68k
+ if [ x$enable_threads = xyes ]; then
+ thread_file='mach'
+ fi
;;
m68k-sun-sunos3*)
- if [ x$nfp = xyes ]
+ if [ x$with_fp = xno ]
then
tm_file=m68k/sun3n3.h
else
tm_file=m68k/sun3o3.h
+ float_format=m68k
fi
use_collect2=yes
extra_headers=math-68881.h
;;
m68k-sun-sunos*) # For SunOS 4 (the default).
- if [ x$nfp = xyes ]
+ if [ x$with_fp = xno ]
then
tm_file=m68k/sun3n.h
else
tm_file=m68k/sun3.h
+ float_format=m68k
fi
use_collect2=yes
extra_headers=math-68881.h
@@ -1490,16 +3613,20 @@ for machine in $canon_build $canon_host $canon_target; do
tm_file=m68k/vxm68k.h
tmake_file=m68k/t-vxworks68
extra_headers=math-68881.h
+ thread_file='vxworks'
+ float_format=m68k
;;
m68k-*-aout*)
tmake_file=m68k/t-m68kbare
- tm_file=m68k/m68k-aout.h
+ tm_file="m68k/m68k-aout.h libgloss.h"
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-*-coff*)
tmake_file=m68k/t-m68kbare
- tm_file=m68k/m68k-coff.h
+ tm_file="m68k/m68k-coff.h dbx.h libgloss.h"
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-*-lynxos*)
if [ x$gas = xyes ]
@@ -1512,85 +3639,111 @@ for machine in $canon_build $canon_host $canon_target; do
xmake_file=x-lynx
tmake_file=m68k/t-lynx
extra_headers=math-68881.h
+ float_format=m68k
;;
- m68k-*-netbsd*)
- cpu_type=m68k
+ m68k*-*-netbsd*)
tm_file=m68k/netbsd.h
- xm_file=m68k/xm-netbsd.h
- # On NetBSD, the headers are already okay.
- fixincludes=Makefile.in
- tmake_file=t-libc-ok
- xmake_file=x-netbsd
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ float_format=m68k
+ ;;
+ m68k*-*-openbsd*)
+ float_format=m68k
+ # we need collect2 until our bug is fixed...
+ use_collect2=yes
;;
m68k-*-sysv3*) # Motorola m68k's running system V.3
- xm_file=m68k/xm-m68kv.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines=USG
xmake_file=m68k/x-m68kv
extra_parts="crtbegin.o crtend.o"
extra_headers=math-68881.h
+ float_format=m68k
;;
m68k-*-sysv4*) # Motorola m68k's running system V.4
tm_file=m68k/m68kv4.h
- xm_file=m68k/xm-m68kv.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines=USG
tmake_file=t-svr4
extra_parts="crtbegin.o crtend.o"
extra_headers=math-68881.h
+ float_format=m68k
;;
- m68k-*-linux*aout*) # Motorola m68k's running GNU/Linux
- xm_file=m68k/xm-linux.h # with a.out format
+ m68k-*-linux-gnuaout*) # Motorola m68k's running GNU/Linux
+ # with a.out format
xmake_file=x-linux
tm_file=m68k/linux-aout.h
- tmake_file=m68k/t-linux
+ tmake_file="t-linux-aout m68k/t-linux-aout"
fixincludes=Makefile.in # The headers are ok already.
extra_headers=math-68881.h
+ float_format=m68k
gnu_ld=yes
;;
- m68k-*-linux*libc1) # Motorola m68k's running GNU/Linux
- xm_file=m68k/xm-linux.h # with ELF format, using GNU libc v1.
+ m68k-*-linux-gnulibc1) # Motorola m68k's running GNU/Linux
+ # with ELF format using the
+ # GNU/Linux C library 5
xmake_file=x-linux
tm_file=m68k/linux.h
- tmake_file=m68k/t-linux-gnulibc1
+ tmake_file="t-linux t-linux-gnulibc1 m68k/t-linux"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
fixincludes=Makefile.in # The headers are ok already.
extra_headers=math-68881.h
+ float_format=m68k
gnu_ld=yes
- extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
;;
- m68k-*-linux*) # Motorola m68k's running GNU/Linux
- xm_file=m68k/xm-linux.h # with ELF format
+ m68k-*-linux-gnu*) # Motorola m68k's running GNU/Linux
+ # with ELF format using glibc 2
+ # aka the GNU/Linux C library 6.
xmake_file=x-linux
tm_file=m68k/linux.h
- tmake_file=m68k/t-linux
+ tmake_file="t-linux m68k/t-linux"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
fixincludes=Makefile.in # The headers are ok already.
extra_headers=math-68881.h
+ float_format=m68k
gnu_ld=yes
- # GNU libc version 2 does not supply these;
- # we want them from GCC.
- extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ if [ x$enable_threads = xyes ]; then
+ thread_file='posix'
+ fi
+ ;;
+ m68k-*-psos*)
+ tmake_file=m68k/t-m68kbare
+ tm_file=m68k/m68k-psos.h
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-*-rtems*)
+ tmake_file="m68k/t-m68kbare t-rtems"
+ tm_file=m68k/rtems.h
+ extra_headers=math-68881.h
+ float_format=m68k
;;
+
m88k-dg-dgux*)
case $machine in
m88k-dg-dguxbcs*)
tm_file=m88k/dguxbcs.h
- xmake_file=m88k/x-dguxbcs
+ tmake_file=m88k/t-dguxbcs
;;
*)
tm_file=m88k/dgux.h
- xmake_file=m88k/x-dgux
+ tmake_file=m88k/t-dgux
;;
esac
extra_parts="crtbegin.o bcscrtbegin.o crtend.o m88kdgux.ld"
- broken_install=yes
+ xmake_file=m88k/x-dgux
if [ x$gas = xyes ]
then
tmake_file=m88k/t-dgux-gas
- else
- tmake_file=m88k/t-dgux
fi
fixincludes=fixinc.dgux
;;
m88k-dolphin-sysv3*)
tm_file=m88k/dolph.h
extra_parts="crtbegin.o crtend.o"
- xm_file=m88k/xm-sysv3.h
+ xm_file="m88k/xm-sysv3.h ${xm_file}"
xmake_file=m88k/x-dolph
if [ x$gas = xyes ]
then
@@ -1600,7 +3753,7 @@ for machine in $canon_build $canon_host $canon_target; do
m88k-tektronix-sysv3)
tm_file=m88k/tekXD88.h
extra_parts="crtbegin.o crtend.o"
- xm_file=m88k/xm-sysv3.h
+ xm_file="m88k/xm-sysv3.h ${xm_file}"
xmake_file=m88k/x-tekXD88
if [ x$gas = xyes ]
then
@@ -1608,11 +3761,9 @@ for machine in $canon_build $canon_host $canon_target; do
fi
;;
m88k-*-aout*)
- cpu_type=m88k
tm_file=m88k/m88k-aout.h
;;
m88k-*-coff*)
- cpu_type=m88k
tm_file=m88k/m88k-coff.h
tmake_file=m88k/t-bug
;;
@@ -1626,10 +3777,13 @@ for machine in $canon_build $canon_host $canon_target; do
tmake_file=m88k/t-luna
fi
;;
+ m88k-*-openbsd*)
+ tmake_file="${tmake_file} m88k/t-luna-gas"
+ ;;
m88k-*-sysv3*)
tm_file=m88k/sysv3.h
extra_parts="crtbegin.o crtend.o"
- xm_file=m88k/xm-sysv3.h
+ xm_file="m88k/xm-sysv3.h ${xm_file}"
xmake_file=m88k/x-sysv3
if [ x$gas = xyes ]
then
@@ -1645,52 +3799,83 @@ for machine in $canon_build $canon_host $canon_target; do
mips-sgi-irix6*) # SGI System V.4., IRIX 6
tm_file=mips/iris6.h
xm_file=mips/xm-iris6.h
- broken_install=yes
- fixincludes=Makefile.in
+ fixincludes=fixinc.irix
xmake_file=mips/x-iris6
tmake_file=mips/t-iris6
- # See comment in mips/iris[56].h files.
- use_collect2=yes
+ if [ x$enable_threads = xyes ]; then
+: not ported yet thread_file='irix'
+ fi
;;
+ mips-wrs-vxworks)
+ tm_file="mips/elf.h libgloss.h"
+ tmake_file=mips/t-ecoff
+ gas=yes
+ gnu_ld=yes
+ extra_parts="crtbegin.o crtend.o"
+# thread_file='vxworks'
+ ;;
mips-sgi-irix5cross64) # Irix5 host, Irix 6 target, cross64
- tm_file=mips/cross64.h
- xm_file=mips/xm-iris5.h
- broken_install=yes
+ tm_file="mips/iris6.h mips/cross64.h"
+ xm_defines=USG
+ xm_file="mips/xm-iris5.h"
fixincludes=Makefile.in
xmake_file=mips/x-iris
tmake_file=mips/t-cross64
# See comment in mips/iris[56].h files.
use_collect2=yes
+ if [ x$enable_threads = xyes ]; then
+: not ported yet thread_file='irix'
+ fi
;;
- mips-sgi-irix5*) # SGI System V.4., IRIX 5
+ mips-sni-sysv4)
if [ x$gas = xyes ]
then
if [ x$stabs = xyes ]
then
tm_file=mips/iris5gdb.h
else
- tm_file=mips/iris5gas.h
+ tm_file="mips/sni-svr4.h mips/sni-gas.h"
+ fi
+ else
+ tm_file=mips/sni-svr4.h
+ fi
+ xm_defines=USG
+ xmake_file=mips/x-sni-svr4
+ tmake_file=mips/t-mips-gas
+ if [ x$gnu_ld != xyes ]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-sgi-irix5*) # SGI System V.4., IRIX 5
+ if [ x$gas = xyes ]
+ then
+ tm_file="mips/iris5.h mips/iris5gas.h"
+ if [ x$stabs = xyes ]
+ then
+ tm_file="${tm_file} dbx.h"
fi
else
tm_file=mips/iris5.h
fi
- xm_file=mips/xm-iris5.h
- broken_install=yes
- fixincludes=Makefile.in
+ xm_defines=USG
+ xm_file="mips/xm-iris5.h"
+ fixincludes=fixinc.irix
xmake_file=mips/x-iris
# mips-tfile doesn't work yet
tmake_file=mips/t-mips-gas
# See comment in mips/iris5.h file.
use_collect2=yes
+ if [ x$enable_threads = xyes ]; then
+: not ported yet thread_file='irix'
+ fi
;;
mips-sgi-irix4loser*) # Mostly like a MIPS.
+ tm_file="mips/iris4loser.h mips/iris3.h ${tm_file} mips/iris4.h"
if [ x$stabs = xyes ]; then
- tm_file=mips/iris4gl.h
- else
- tm_file=mips/iris4loser.h
+ tm_file="${tm_file} dbx.h"
fi
- xm_file=mips/xm-iris4.h
- broken_install=yes
+ xm_defines=USG
xmake_file=mips/x-iris
if [ x$gas = xyes ]
then
@@ -1702,15 +3887,16 @@ for machine in $canon_build $canon_host $canon_target; do
then
use_collect2=yes
fi
+ if [ x$enable_threads = xyes ]; then
+: not ported yet thread_file='irix'
+ fi
;;
mips-sgi-irix4*) # Mostly like a MIPS.
+ tm_file="mips/iris3.h ${tm_file} mips/iris4.h"
if [ x$stabs = xyes ]; then
- tm_file=mips/iris4-gdb.h
- else
- tm_file=mips/iris4.h
+ tm_file="${tm_file} dbx.h"
fi
- xm_file=mips/xm-iris4.h
- broken_install=yes
+ xm_defines=USG
xmake_file=mips/x-iris
if [ x$gas = xyes ]
then
@@ -1722,15 +3908,16 @@ for machine in $canon_build $canon_host $canon_target; do
then
use_collect2=yes
fi
+ if [ x$enable_threads = xyes ]; then
+: not ported yet thread_file='irix'
+ fi
;;
mips-sgi-*) # Mostly like a MIPS.
+ tm_file="mips/iris3.h ${tm_file}"
if [ x$stabs = xyes ]; then
- tm_file=mips/iris3-gdb.h
- else
- tm_file=mips/iris3.h
+ tm_file="${tm_file} dbx.h"
fi
- xm_file=mips/xm-iris3.h
- broken_install=yes
+ xm_defines=USG
xmake_file=mips/x-iris3
if [ x$gas = xyes ]
then
@@ -1744,17 +3931,16 @@ for machine in $canon_build $canon_host $canon_target; do
fi
;;
mips-dec-osfrose*) # Decstation running OSF/1 reference port with OSF/rose.
- tm_file=mips/osfrose.h
+ tm_file="mips/osfrose.h ${tm_file}"
xmake_file=mips/x-osfrose
tmake_file=mips/t-osfrose
extra_objs=halfpic.o
use_collect2=yes
;;
mips-dec-osf*) # Decstation running OSF/1 as shipped by DIGITAL
+ tm_file=mips/dec-osf1.h
if [ x$stabs = xyes ]; then
- tm_file=mips/dec-gosf1.h
- else
- tm_file=mips/dec-osf1.h
+ tm_file="${tm_file} dbx.h"
fi
xmake_file=mips/x-dec-osf1
if [ x$gas = xyes ]
@@ -1771,8 +3957,6 @@ for machine in $canon_build $canon_host $canon_target; do
;;
mips-dec-bsd*) # Decstation running 4.4 BSD
tm_file=mips/dec-bsd.h
- xmake_file=
- tmake_file=
fixincludes=
if [ x$gas = xyes ]
then
@@ -1786,19 +3970,27 @@ for machine in $canon_build $canon_host $canon_target; do
use_collect2=yes
fi
;;
- mips-dec-netbsd*) # Decstation running NetBSD
+ mipsel-*-netbsd* | mips-dec-netbsd*) # Decstation running NetBSD
tm_file=mips/netbsd.h
- xm_file=mips/xm-netbsd.h
- xmake_file=x-netbsd
- tmake_file=t-libc-ok
- fixincludes=Makefile.in
- prefix=$native_prefix
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ ;;
+ mips*el-*-openbsd*) # mips little endian
+ target_cpu_default="MASK_GAS|MASK_ABICALLS"
+ tm_file=mips/openbsd.h
+ xmake_file=none
+ ;;
+ mips*-*-openbsd*) # mips big endian
+ target_cpu_default="MASK_GAS|MASK_ABICALLS"
+ tm_file=mips/openbsd-be.h
+ xmake_file=none
;;
mips-sony-bsd* | mips-sony-newsos*) # Sony NEWS 3600 or risc/news.
+ tm_file="mips/news4.h ${tm_file}"
if [ x$stabs = xyes ]; then
- tm_file=mips/news4-gdb.h
- else
- tm_file=mips/news4.h
+ tm_file="${tm_file} dbx.h"
fi
if [ x$gas = xyes ]
then
@@ -1815,12 +4007,12 @@ for machine in $canon_build $canon_host $canon_target; do
mips-sony-sysv*) # Sony NEWS 3800 with NEWSOS5.0.
# That is based on svr4.
# t-svr4 is not right because this system doesn't use ELF.
+ tm_file="mips/news5.h ${tm_file}"
if [ x$stabs = xyes ]; then
- tm_file=mips/news5-gdb.h
- else
- tm_file=mips/news5.h
+ tm_file="${tm_file} dbx.h"
fi
- xm_file=mips/xm-news.h
+ xm_file="xm-siglist.h ${xm_file}"
+ xm_defines=USG
if [ x$gas = xyes ]
then
tmake_file=mips/t-mips-gas
@@ -1833,12 +4025,12 @@ for machine in $canon_build $canon_host $canon_target; do
fi
;;
mips-tandem-sysv4*) # Tandem S2 running NonStop UX
+ tm_file="mips/svr4-5.h mips/svr4-t.h"
if [ x$stabs = xyes ]; then
- tm_file=mips/svr4-t-gdb.h
- else
- tm_file=mips/svr4-t.h
+ tm_file="${tm_file} dbx.h"
fi
- xm_file=mips/xm-sysv4.h
+ xm_file="xm-siglist.h ${xm_file}"
+ xm_defines=USG
xmake_file=mips/x-sysv
if [ x$gas = xyes ]
then
@@ -1852,13 +4044,11 @@ for machine in $canon_build $canon_host $canon_target; do
then
use_collect2=yes
fi
- broken_install=yes
;;
mips-*-ultrix* | mips-dec-mach3) # Decstation.
+ tm_file="mips/ultrix.h ${tm_file}"
if [ x$stabs = xyes ]; then
- tm_file=mips/ultrix-gdb.h
- else
- tm_file=mips/ultrix.h
+ tm_file="${tm_file} dbx.h"
fi
xmake_file=mips/x-ultrix
if [ x$gas = xyes ]
@@ -1874,10 +4064,9 @@ for machine in $canon_build $canon_host $canon_target; do
fi
;;
mips-*-riscos[56789]bsd*)
- if [ x$stabs = xyes ]; then # MIPS BSD 4.3, RISC-OS 5.0
- tm_file=mips/bsd-5-gdb.h
- else
- tm_file=mips/bsd-5.h
+ tm_file=mips/bsd-5.h # MIPS BSD 4.3, RISC-OS 5.0
+ if [ x$stabs = xyes ]; then
+ tm_file="${tm_file} dbx.h"
fi
if [ x$gas = xyes ]
then
@@ -1890,13 +4079,11 @@ for machine in $canon_build $canon_host $canon_target; do
then
use_collect2=yes
fi
- broken_install=yes
;;
mips-*-bsd* | mips-*-riscosbsd* | mips-*-riscos[1234]bsd*)
- if [ x$stabs = xyes ]; then # MIPS BSD 4.3, RISC-OS 4.0
- tm_file=mips/bsd-4-gdb.h
- else
- tm_file=mips/bsd-4.h
+ tm_file="mips/bsd-4.h ${tm_file}" # MIPS BSD 4.3, RISC-OS 4.0
+ if [ x$stabs = xyes ]; then
+ tm_file="${tm_file} dbx.h"
fi
if [ x$gas = xyes ]
then
@@ -1909,15 +4096,13 @@ for machine in $canon_build $canon_host $canon_target; do
then
use_collect2=yes
fi
- broken_install=yes
;;
mips-*-riscos[56789]sysv4*)
- if [ x$stabs = xyes ]; then # MIPS System V.4., RISC-OS 5.0
- tm_file=mips/svr4-5-gdb.h
- else
- tm_file=mips/svr4-5.h
+ tm_file=mips/svr4-5.h # MIPS System V.4., RISC-OS 5.0
+ if [ x$stabs = xyes ]; then
+ tm_file="${tm_file} dbx.h"
fi
- xm_file=mips/xm-sysv4.h
+ xm_file="xm-siglist.h ${xm_file}"
xmake_file=mips/x-sysv
if [ x$gas = xyes ]
then
@@ -1930,15 +4115,13 @@ for machine in $canon_build $canon_host $canon_target; do
then
use_collect2=yes
fi
- broken_install=yes
;;
mips-*-sysv4* | mips-*-riscos[1234]sysv4* | mips-*-riscossysv4*)
- if [ x$stabs = xyes ]; then # MIPS System V.4. RISC-OS 4.0
- tm_file=mips/svr4-4-gdb.h
- else
- tm_file=mips/svr4-4.h
+ tm_file="mips/svr4-4.h ${tm_file}"
+ if [ x$stabs = xyes ]; then
+ tm_file="${tm_file} dbx.h"
fi
- xm_file=mips/xm-sysv.h
+ xm_defines=USG
xmake_file=mips/x-sysv
if [ x$gas = xyes ]
then
@@ -1951,15 +4134,13 @@ for machine in $canon_build $canon_host $canon_target; do
then
use_collect2=yes
fi
- broken_install=yes
;;
mips-*-riscos[56789]sysv*)
- if [ x$stabs = xyes ]; then # MIPS System V.3, RISC-OS 5.0
- tm_file=mips/svr3-5-gdb.h
- else
- tm_file=mips/svr3-5.h
+ tm_file=mips/svr3-5.h # MIPS System V.3, RISC-OS 5.0
+ if [ x$stabs = xyes ]; then
+ tm_file="${tm_file} dbx.h"
fi
- xm_file=mips/xm-sysv.h
+ xm_defines=USG
xmake_file=mips/x-sysv
if [ x$gas = xyes ]
then
@@ -1972,15 +4153,13 @@ for machine in $canon_build $canon_host $canon_target; do
then
use_collect2=yes
fi
- broken_install=yes
;;
mips-*-sysv* | mips-*-riscos*sysv*)
- if [ x$stabs = xyes ]; then # MIPS System V.3, RISC-OS 4.0
- tm_file=mips/svr3-4-gdb.h
- else
- tm_file=mips/svr3-4.h
+ tm_file="mips/svr3-4.h ${tm_file}"
+ if [ x$stabs = xyes ]; then
+ tm_file="${tm_file} dbx.h"
fi
- xm_file=mips/xm-sysv.h
+ xm_defines=USG
xmake_file=mips/x-sysv
if [ x$gas = xyes ]
then
@@ -1993,13 +4172,11 @@ for machine in $canon_build $canon_host $canon_target; do
then
use_collect2=yes
fi
- broken_install=yes
;;
- mips-*-riscos[56789]*) # Default MIPS RISC-OS 5.0.
+ mips-*-riscos[56789]*) # Default MIPS RISC-OS 5.0.
+ tm_file=mips/mips-5.h
if [ x$stabs = xyes ]; then
- tm_file=mips/mips-5-gdb.h
- else
- tm_file=mips/mips-5.h
+ tm_file="${tm_file} dbx.h"
fi
if [ x$gas = xyes ]
then
@@ -2011,64 +4188,62 @@ for machine in $canon_build $canon_host $canon_target; do
then
use_collect2=yes
fi
- broken_install=yes
;;
mips-*-gnu*)
- cpu_type=mips # GNU supports this CPU; rest done below.
;;
mipsel-*-ecoff*)
- cpu_type=mips
+ tm_file=mips/ecoffl.h
if [ x$stabs = xyes ]; then
- tm_file=mips/ecoffl-gdb.h
- else
- tm_file=mips/ecoffl.h
+ tm_file="${tm_file} dbx.h"
fi
tmake_file=mips/t-ecoff
;;
mips-*-ecoff*)
+ tm_file="gofast.h mips/ecoff.h"
if [ x$stabs = xyes ]; then
- tm_file=mips/ecoff-gdb.h
- else
- tm_file=mips/ecoff.h
+ tm_file="${tm_file} dbx.h"
fi
tmake_file=mips/t-ecoff
- broken_install=yes
;;
mipsel-*-elf*)
- cpu_type=mips
- tm_file=mips/elfl.h
+ tm_file="mips/elfl.h libgloss.h"
tmake_file=mips/t-ecoff
;;
mips-*-elf*)
- cpu_type=mips
- tm_file=mips/elf.h
+ tm_file="mips/elf.h libgloss.h"
tmake_file=mips/t-ecoff
;;
mips64el-*-elf*)
- cpu_type=mips
- tm_file=mips/elfl64.h
+ tm_file="mips/elfl64.h libgloss.h"
tmake_file=mips/t-ecoff
;;
mips64orionel-*-elf*)
- cpu_type=mips
- tm_file=mips/elflorion.h
+ tm_file="mips/elforion.h mips/elfl64.h libgloss.h"
tmake_file=mips/t-ecoff
;;
mips64-*-elf*)
- cpu_type=mips
- tm_file=mips/elf64.h
+ tm_file="mips/elf64.h libgloss.h"
tmake_file=mips/t-ecoff
;;
mips64orion-*-elf*)
- cpu_type=mips
- tm_file=mips/elforion.h
+ tm_file="mips/elforion.h mips/elf64.h libgloss.h"
tmake_file=mips/t-ecoff
;;
+ mips64orion-*-rtems*)
+ tm_file="mips/elforion.h mips/elf64.h mips/rtems64.h"
+ tmake_file="mips/t-ecoff t-rtems"
+ ;;
+ mipstx39el-*-elf*)
+ tm_file="mips/r3900.h mips/elfl.h mips/abi64.h libgloss.h"
+ tmake_file=mips/t-r3900
+ ;;
+ mipstx39-*-elf*)
+ tm_file="mips/r3900.h mips/elf.h mips/abi64.h libgloss.h"
+ tmake_file=mips/t-r3900
+ ;;
mips-*-*) # Default MIPS RISC-OS 4.0.
if [ x$stabs = xyes ]; then
- tm_file=mips/mips-4-gdb.h
- else
- tm_file=mips/mips.h
+ tm_file="${tm_file} dbx.h"
fi
if [ x$gas = xyes ]
then
@@ -2081,6 +4256,24 @@ for machine in $canon_build $canon_host $canon_target; do
use_collect2=yes
fi
;;
+ mn10200-*-*)
+ cpu_type=mn10200
+ tm_file="mn10200/mn10200.h"
+ if [ x$stabs = xyes ]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ use_collect2=no
+ ;;
+ mn10300-*-*)
+ cpu_type=mn10300
+ tm_file="mn10300/mn10300.h"
+ if [ x$stabs = xyes ]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ use_collect2=no
+ ;;
ns32k-encore-bsd*)
tm_file=ns32k/encore.h
use_collect2=yes
@@ -2091,20 +4284,17 @@ for machine in $canon_build $canon_host $canon_target; do
;;
ns32k-tek6100-bsd*)
tm_file=ns32k/tek6100.h
- broken_install=yes
use_collect2=yes
;;
ns32k-tek6200-bsd*)
tm_file=ns32k/tek6200.h
- broken_install=yes
use_collect2=yes
;;
# This has not been updated to GCC 2.
# ns32k-ns-genix*)
-# xm_file=ns32k/xm-genix.h
+# xm_defines=USG
# xmake_file=ns32k/x-genix
# tm_file=ns32k/genix.h
-# broken_install=yes
# use_collect2=yes
# ;;
ns32k-merlin-*)
@@ -2117,16 +4307,24 @@ for machine in $canon_build $canon_host $canon_target; do
;;
ns32k-pc532-minix*)
tm_file=ns32k/pc532-min.h
- xm_file=ns32k/xm-pc532-min.h
+ xm_file="ns32k/xm-pc532-min.h ${xm-file}"
+ xm_defines=USG
use_collect2=yes
;;
- ns32k-pc532-netbsd*)
+ ns32k-*-netbsd*)
tm_file=ns32k/netbsd.h
- xm_file=ns32k/xm-netbsd.h
- tmake_file=t-libc-ok
- # On NetBSD, the headers are already okay.
- fixincludes=Makefile.in
- xmake_file=x-netbsd
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ ;;
+ pdp11-*-bsd)
+ tm_file="${tm_file} pdp11/2bsd.h"
+ ;;
+ pdp11-*-*)
+ ;;
+ ns32k-*-openbsd*)
+ # Nothing special
;;
pyramid-*-*)
cpu_type=pyr
@@ -2140,149 +4338,333 @@ for machine in $canon_build $canon_host $canon_target; do
xmake_file=romp/x-mach
use_collect2=yes
;;
- powerpc-ibm-aix[456789].*)
- cpu_type=rs6000
- tm_file=rs6000/aix41ppc.h
- tmake_file=rs6000/t-newas
- use_collect2=yes
+ romp-*-openbsd*)
+ # Nothing special
;;
- powerpc-ibm-aix*)
- cpu_type=rs6000
- tm_file=rs6000/powerpc.h
- tmake_file=rs6000/t-rs6000
- use_collect2=yes
+ powerpc-*-openbsd*)
+ tmake_file="${tmake_file} rs6000/t-rs6000 rs6000/t-openbsd"
+ xmake_file=none
;;
- powerpc-*-sysv4* | powerpc-*-elf*)
+ powerpc-*-beos*)
cpu_type=rs6000
- xm_file=rs6000/xm-sysv4.h
+ tm_file=rs6000/beos.h
+ xm_file=rs6000/xm-beos.h
+ tmake_file=rs6000/t-beos
+ xmake_file=rs6000/x-beos
+ ;;
+ powerpc-*-sysv* | powerpc-*-elf*)
tm_file=rs6000/sysv4.h
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+ xm_defines="USG POSIX"
+ extra_headers=ppc-asm.h
if [ x$gas = xyes ]
then
- tmake_file=rs6000/t-ppcgas
+ tmake_file="rs6000/t-ppcos rs6000/t-ppccomm"
else
- tmake_file=rs6000/t-ppc
+ tmake_file="rs6000/t-ppc rs6000/t-ppccomm"
fi
xmake_file=rs6000/x-sysv4
;;
powerpc-*-eabiaix*)
- cpu_type=rs6000
tm_file=rs6000/eabiaix.h
- tmake_file=rs6000/t-eabiaix
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
;;
powerpc-*-eabisim*)
- cpu_type=rs6000
tm_file=rs6000/eabisim.h
- tmake_file=rs6000/t-eabisim
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
;;
powerpc-*-eabi*)
- cpu_type=rs6000
tm_file=rs6000/eabi.h
if [ x$gas = xyes ]
then
- tmake_file=rs6000/t-eabigas
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
else
- tmake_file=rs6000/t-eabi
+ tmake_file="rs6000/t-ppc rs6000/t-ppccomm"
fi
fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
;;
- powerpcle-*-sysv4* | powerpcle-*-elf*)
- cpu_type=rs6000
+ powerpc-*-rtems*)
+ tm_file=rs6000/rtems.h
+ if [ x$gas = xyes ]
+ then
+ tmake_file="rs6000/t-ppcgas t-rtems rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc t-rtems rs6000/t-ppccomm"
+ fi
+ fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
+ ;;
+ powerpc-*-linux-gnulibc1)
+ tm_file=rs6000/linux.h
xm_file=rs6000/xm-sysv4.h
+ out_file=rs6000/rs6000.c
+ if [ x$gas = xyes ]
+ then
+ tmake_file="rs6000/t-ppcos t-linux t-linux-gnulibc1 rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc t-linux t-linux-gnulibc1 rs6000/t-ppccomm"
+ fi
+ xmake_file=x-linux
+ fixincludes=Makefile.in
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ extra_headers=ppc-asm.h
+ if [ x$enable_threads = xyes ]; then
+ thread_file='posix'
+ fi
+ ;;
+ powerpc-*-linux-gnu*)
+ tm_file=rs6000/linux.h
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+ xm_defines="USG ${xm_defines}"
+ out_file=rs6000/rs6000.c
+ if [ x$gas = xyes ]
+ then
+ tmake_file="rs6000/t-ppcos t-linux rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc t-linux rs6000/t-ppccomm"
+ fi
+ xmake_file=x-linux
+ fixincludes=Makefile.in
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ extra_headers=ppc-asm.h
+ if [ x$enable_threads = xyes ]; then
+ thread_file='posix'
+ fi
+ ;;
+ powerpc-wrs-vxworks*)
+ cpu_type=rs6000
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+ xm_defines="USG POSIX"
+ tm_file=rs6000/vxppc.h
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
+ extra_headers=ppc-asm.h
+ thread_file='vxworks'
+ ;;
+ powerpcle-*-sysv* | powerpcle-*-elf*)
tm_file=rs6000/sysv4le.h
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+ xm_defines="USG POSIX"
if [ x$gas = xyes ]
then
- tmake_file=rs6000/t-ppclegas
+ tmake_file="rs6000/t-ppcos rs6000/t-ppccomm"
else
- tmake_file=rs6000/t-ppc
+ tmake_file="rs6000/t-ppc rs6000/t-ppccomm"
fi
xmake_file=rs6000/x-sysv4
+ extra_headers=ppc-asm.h
;;
powerpcle-*-eabisim*)
- cpu_type=rs6000
tm_file=rs6000/eabilesim.h
- tmake_file=rs6000/t-eabisim
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
;;
powerpcle-*-eabi*)
- cpu_type=rs6000
tm_file=rs6000/eabile.h
if [ x$gas = xyes ]
then
- tmake_file=rs6000/t-eabilegas
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
else
- tmake_file=rs6000/t-eabi
+ tmake_file="rs6000/t-ppc rs6000/t-ppccomm"
+ fi
+ fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
+ ;;
+ powerpcle-*-winnt* )
+ tm_file=rs6000/win-nt.h
+ tmake_file=rs6000/t-winnt
+# extra_objs=pe.o
+ fixincludes=Makefile.in
+ if [ x$enable_threads = xyes ]; then
+ thread_file='win32'
fi
+ extra_headers=ppc-asm.h
+ ;;
+ powerpcle-*-pe | powerpcle-*-cygwin32)
+ tm_file=rs6000/cygwin32.h
+ xm_file="rs6000/xm-cygwin32.h ${xm_file}"
+ tmake_file=rs6000/t-winnt
+ xmake_file=rs6000/x-cygwin32
+# extra_objs=pe.o
fixincludes=Makefile.in
+ if [ x$enable_threads = xyes ]; then
+ thread_file='win32'
+ fi
+ exeext=.exe
+ extra_headers=ppc-asm.h
+ ;;
+ powerpcle-*-solaris2*)
+ tm_file=rs6000/sol2.h
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+ xm_defines="USG POSIX"
+ if [ x$gas = xyes ]
+ then
+ tmake_file="rs6000/t-ppcos rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc rs6000/t-ppccomm"
+ fi
+ xmake_file=rs6000/x-sysv4
+ case $machine in
+ *-*-solaris2.[0-4])
+ fixincludes=fixinc.svr4;;
+ *)
+ fixincludes=fixinc.wrap;;
+ esac
+ extra_headers=ppc-asm.h
;;
rs6000-ibm-aix3.[01]*)
tm_file=rs6000/aix31.h
- tmake_file=rs6000/t-rs6000
xmake_file=rs6000/x-aix31
use_collect2=yes
;;
- rs6000-ibm-aix3.2.[456789]*)
+ rs6000-ibm-aix3.2.[456789]* | powerpc-ibm-aix3.2.[456789]*)
tm_file=rs6000/aix3newas.h
- tmake_file=rs6000/t-newas
+ if [ x$host != x$target ]
+ then
+ tmake_file=rs6000/t-xnewas
+ else
+ tmake_file=rs6000/t-newas
+ fi
use_collect2=yes
;;
- rs6000-ibm-aix[456789].*)
+ rs6000-ibm-aix4.[12]* | powerpc-ibm-aix4.[12]*)
tm_file=rs6000/aix41.h
- tmake_file=rs6000/t-newas
- xmake_file=rs6000/x-aix31
+ if [ x$host != x$target ]
+ then
+ tmake_file=rs6000/t-xnewas
+ else
+ tmake_file=rs6000/t-newas
+ fi
+ xmake_file=rs6000/x-aix41
+ use_collect2=yes
+ ;;
+ rs6000-ibm-aix4.[3456789].* | powerpc-ibm-aix4.[3456789].*)
+ tm_file=rs6000/aix43.h
+ if [ x$host != x$target ]
+ then
+ tmake_file=rs6000/t-xaix43
+ else
+ tmake_file=rs6000/t-aix43
+ fi
+ xmake_file=rs6000/x-aix43
+ use_collect2=yes
+ ;;
+ rs6000-ibm-aix[56789].* | powerpc-ibm-aix[56789].*)
+ tm_file=rs6000/aix43.h
+ if [ x$host != x$target ]
+ then
+ tmake_file=rs6000/t-xaix43
+ else
+ tmake_file=rs6000/t-aix43
+ fi
+ xmake_file=rs6000/x-aix43
use_collect2=yes
;;
rs6000-ibm-aix*)
use_collect2=yes
- tmake_file=rs6000/t-rs6000
;;
rs6000-bull-bosx)
- tmake_file=rs6000/t-rs6000
use_collect2=yes
;;
rs6000-*-mach*)
- xm_file=rs6000/xm-mach.h
tm_file=rs6000/mach.h
- tmake_file=rs6000/t-rs6000
+ xm_file="${xm_file} rs6000/xm-mach.h"
xmake_file=rs6000/x-mach
use_collect2=yes
;;
rs6000-*-lynxos*)
- xmake_file=rs6000/x-lynx
- xm_file=rs6000/xm-lynx.h
tm_file=rs6000/lynx.h
+ xm_file=rs6000/xm-lynx.h
tmake_file=rs6000/t-rs6000
+ xmake_file=rs6000/x-lynx
use_collect2=yes
;;
+ sh-*-elf*)
+ tm_file=sh/elf.h
+ float_format=sh
+ ;;
+ sh-*-rtemself*)
+ tmake_file="sh/t-sh t-rtems"
+ tm_file=sh/rtemself.h
+ float_format=sh
+ ;;
+ sh-*-rtems*)
+ tmake_file="sh/t-sh t-rtems"
+ tm_file=sh/rtems.h
+ float_format=sh
+ ;;
sh-*-*)
- cpu_type=sh
+ float_format=sh
;;
sparc-tti-*)
tm_file=sparc/pbd.h
- xm_file=sparc/xm-pbd.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines=USG
;;
sparc-wrs-vxworks* | sparclite-wrs-vxworks*)
- cpu_type=sparc
tm_file=sparc/vxsparc.h
tmake_file=sparc/t-vxsparc
use_collect2=yes
+ thread_file='vxworks'
;;
sparc-*-aout*)
tmake_file=sparc/t-sparcbare
- tm_file=sparc/sparc-aout.h
+ tm_file="sparc/aout.h libgloss.h"
;;
sparc-*-netbsd*)
tm_file=sparc/netbsd.h
- xm_file=sparc/xm-netbsd.h
- # On NetBSD, the headers are already okay.
- fixincludes=Makefile.in
- tmake_file=t-libc-ok
- xmake_file=x-netbsd
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ ;;
+ sparc-*-openbsd*)
+ # we need collect2 until our bug is fixed...
+ use_collect2=yes
;;
sparc-*-bsd*)
tm_file=sparc/bsd.h
;;
+ sparc-*-elf*)
+ tm_file=sparc/elf.h
+ tmake_file=sparc/t-elf
+ extra_parts="crti.o crtn.o crtbegin.o crtend.o"
+ #float_format=i128
+ float_format=i64
+ ;;
+ sparc-*-linux-gnuaout*) # Sparc's running GNU/Linux, a.out
+ xm_file="${xm_file} sparc/xm-linux.h"
+ tm_file=sparc/linux-aout.h
+ xmake_file=x-linux
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ ;;
+ sparc-*-linux-gnulibc1*) # Sparc's running GNU/Linux, libc5
+ xm_file="${xm_file} sparc/xm-linux.h"
+ xmake_file=x-linux
+ tm_file=sparc/linux.h
+ tmake_file="t-linux t-linux-gnulibc1"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ ;;
+ sparc-*-linux-gnu*) # Sparc's running GNU/Linux, libc6
+ xm_file="${xm_file} sparc/xm-linux.h"
+ xmake_file=x-linux
+ tm_file=sparc/linux.h
+ tmake_file="t-linux"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ if [ x$enable_threads = xyes ]; then
+ thread_file='posix'
+ fi
+ ;;
sparc-*-lynxos*)
if [ x$gas = xyes ]
then
@@ -2294,14 +4676,42 @@ for machine in $canon_build $canon_host $canon_target; do
tmake_file=sparc/t-sunos41
xmake_file=x-lynx
;;
- sparc-*-solaris2* | sparc-*-sunos5*)
- xm_file=sparc/xm-sol2.h
- tm_file=sparc/sol2.h
+ sparc-*-rtems*)
+ tmake_file="sparc/t-sparcbare t-rtems"
+ tm_file=sparc/rtems.h
+ ;;
+ sparc-*-solaris2*)
+ if [ x$gnu_ld = xyes ]
+ then
+ tm_file=sparc/sol2.h
+ else
+ tm_file=sparc/sol2-sld.h
+ fi
+ xm_file="xm-siglist.h sparc/xm-sysv4.h sparc/xm-sol2.h"
+ xm_defines="USG POSIX"
tmake_file=sparc/t-sol2
xmake_file=sparc/x-sysv4
- extra_parts="crt1.o crti.o crtn.o gmon.o crtbegin.o crtend.o"
- fixincludes=fixinc.svr4
- broken_install=yes
+ extra_parts="crt1.o crti.o crtn.o gcrt1.o gmon.o crtbegin.o crtend.o"
+ case $machine in
+ *-*-solaris2.[0-4])
+ fixincludes=fixinc.svr4;;
+ *)
+ fixincludes=fixinc.wrap;;
+ esac
+ float_format=i128
+ if [ x${enable_threads} = x ]; then
+ enable_threads=$have_pthread_h
+ if [ x${enable_threads} = x ]; then
+ enable_threads=$have_thread_h
+ fi
+ fi
+ if [ x${enable_threads} = xyes ]; then
+ if [ x${have_pthread_h} = xyes ]; then
+ thread_file='posix'
+ else
+ thread_file='solaris'
+ fi
+ fi
;;
sparc-*-sunos4.0*)
tm_file=sparc/sunos4.h
@@ -2312,86 +4722,123 @@ for machine in $canon_build $canon_host $canon_target; do
tm_file=sparc/sunos4.h
tmake_file=sparc/t-sunos41
use_collect2=yes
+ if [ x$gas = xyes ]; then
+ tm_file="${tm_file} sparc/sun4gas.h"
+ fi
;;
sparc-*-sunos3*)
tm_file=sparc/sun4o3.h
use_collect2=yes
;;
sparc-*-sysv4*)
- xm_file=sparc/xm-sysv4.h
tm_file=sparc/sysv4.h
+ xm_file="xm-siglist.h sparc/xm-sysv4.h"
+ xm_defines="USG POSIX"
tmake_file=t-svr4
xmake_file=sparc/x-sysv4
extra_parts="crtbegin.o crtend.o"
;;
+ sparc-*-vxsim*)
+ xm_file="xm-siglist.h sparc/xm-sysv4.h sparc/xm-sol2.h"
+ xm_defines="USG POSIX"
+ tm_file=sparc/vxsim.h
+ tmake_file=sparc/t-vxsparc
+ xmake_file=sparc/x-sysv4
+ ;;
+ sparclet-*-aout*)
+ tm_file="sparc/splet.h libgloss.h"
+ tmake_file=sparc/t-splet
+ ;;
sparclite-*-coff*)
- cpu_type=sparc
- tm_file=sparc/litecoff.h
+ tm_file="sparc/litecoff.h libgloss.h"
tmake_file=sparc/t-sparclite
;;
- sparclite-*-*)
- cpu_type=sparc
- tm_file=sparc/lite.h
+ sparclite-*-aout*)
+ tm_file="sparc/lite.h aoutos.h libgloss.h"
tmake_file=sparc/t-sparclite
- use_collect2=yes
;;
sparc64-*-aout*)
- cpu_type=sparc
tmake_file=sparc/t-sp64
tm_file=sparc/sp64-aout.h
;;
sparc64-*-elf*)
- cpu_type=sparc
tmake_file=sparc/t-sp64
tm_file=sparc/sp64-elf.h
extra_parts="crtbegin.o crtend.o"
;;
+ sparc64-*-linux*) # 64-bit Sparc's running GNU/Linux
+ tmake_file=sparc/t-sp64
+ xm_file="sparc/xm-sp64.h sparc/xm-linux.h"
+ tm_file=sparc/linux64.h
+ xmake_file=x-linux
+ fixincludes=Makefile.in # The headers are ok already.
+ gnu_ld=yes
+ ;;
# This hasn't been upgraded to GCC 2.
# tahoe-harris-*) # Harris tahoe, using COFF.
# tm_file=tahoe/harris.h
# ;;
# tahoe-*-bsd*) # tahoe running BSD
# ;;
+ thumb-*-coff* | thumbel-*-coff*)
+ tm_file=arm/tcoff.h
+ out_file=arm/thumb.c
+ xm_file=arm/xm-thumb.h
+ md_file=arm/thumb.md
+ tmake_file=arm/t-thumb
+ fixincludes=Makefile.in # There is nothing to fix
+ ;;
# This hasn't been upgraded to GCC 2.
# tron-*-*)
# cpu_type=gmicro
# use_collect2=yes
# ;;
+ v850-*-*)
+ cpu_type=v850
+ tm_file="v850/v850.h"
+ xm_file="v850/xm-v850.h"
+ tmake_file=v850/t-v850
+ if [ x$stabs = xyes ]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ use_collect2=no
+ ;;
vax-*-bsd*) # vaxen running BSD
use_collect2=yes
+ float_format=vax
;;
vax-*-sysv*) # vaxen running system V
- xm_file=vax/xm-vaxv.h
- tm_file=vax/vaxv.h
+ tm_file="${tm_file} vax/vaxv.h"
+ xm_defines=USG
+ float_format=vax
;;
vax-*-netbsd*)
- tm_file=vax/netbsd.h
- xm_file=vax/xm-netbsd.h
- tmake_file=t-libc-ok
- # On NetBSD, the headers are already okay.
- fixincludes=Makefile.in
- xmake_file=x-netbsd
+ tm_file="${tm_file} netbsd.h vax/netbsd.h"
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ float_format=vax
+ ;;
+ vax-*-openbsd*)
+ tmake_file="${tm_file} vax/t-openbsd"
;;
vax-*-ultrix*) # vaxen running ultrix
- tm_file=vax/ultrix.h
+ tm_file="${tm_file} vax/ultrix.h"
use_collect2=yes
+ float_format=vax
;;
vax-*-vms*) # vaxen running VMS
xm_file=vax/xm-vms.h
tm_file=vax/vms.h
+ float_format=vax
;;
- pdp11-*-bsd)
- xm_file=pdp11/xm-pdp11.h
- tm_file=pdp11/2bsd.h
- tmake_file=pdp11/t-pdp11
- ;;
- pdp11-*-*)
- xm_file=pdp11/xm-pdp11.h
- tm_file=pdp11/pdp11.h
- tmake_file=pdp11/t-pdp11
+ vax-*-*) # vax default entry
+ float_format=vax
;;
we32k-att-sysv*)
- cpu_type=we32k
+ xm_file="${xm_file} xm-svr3"
use_collect2=yes
;;
*)
@@ -2402,14 +4849,14 @@ for machine in $canon_build $canon_host $canon_target; do
case $machine in
*-*-linux-gnu*)
- ;; # Existing Linux/GNU systems do not use the GNU setup.
+ ;; # Existing GNU/Linux systems do not use the GNU setup.
*-*-gnu*)
# On the GNU system, the setup is just about the same on
# each different CPU. The specific machines that GNU
# supports are matched above and just set $cpu_type.
- xm_file=${cpu_type}/xm-gnu.h
+ xm_file="xm-gnu.h ${xm_file}"
tm_file=${cpu_type}/gnu.h
- extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o"
# GNU always uses ELF.
elf=yes
# GNU tools are the only tools.
@@ -2417,129 +4864,374 @@ for machine in $canon_build $canon_host $canon_target; do
gas=yes
# On GNU, the headers are already okay.
fixincludes=Makefile.in
- # Don't build libgcc1.c, because there is no non-GNU
- # compiler to build it with. The GNU system C library will
- # include assembly versions of any needed functions.
- tmake_file=t-libc-ok
+ xmake_file=x-linux # These details are the same as Linux.
+ tmake_file=t-gnu # These are not.
;;
*-*-sysv4*)
fixincludes=fixinc.svr4
xmake_try_sysv=x-sysv
- broken_install=yes
install_headers_dir=install-headers-cpio
;;
*-*-sysv*)
- broken_install=yes
install_headers_dir=install-headers-cpio
;;
esac
- # Distinguish i386 from i486/i586.
- # ??? For the moment we treat i586 as an i486.
+ # Distinguish i[34567]86
# Also, do not run mips-tfile on MIPS if using gas.
+ # Process --with-cpu= for PowerPC/rs6000
+ target_cpu_default2=
case $machine in
- i[45]86-*-*)
- target_cpu_default=2
+ i486-*-*)
+ target_cpu_default2=1
;;
- mips*-*-*)
+ i586-*-*)
+ target_cpu_default2=2
+ ;;
+ i686-*-* | i786-*-*)
+ target_cpu_default2=3
+ ;;
+ alpha*-*-*)
+ case $machine in
+ alphaev6*)
+ target_cpu_default2="MASK_CPU_EV6|MASK_BWX|MASK_CIX|MASK_MAX"
+ ;;
+ alphapca56*)
+ target_cpu_default2="MASK_CPU_EV5|MASK_BWX|MASK_MAX"
+ ;;
+ alphaev56*)
+ target_cpu_default2="MASK_CPU_EV5|MASK_BWX"
+ ;;
+ alphaev5*)
+ target_cpu_default2="MASK_CPU_EV5"
+ ;;
+ esac
+
if [ x$gas = xyes ]
then
- target_cpu_default=16
+ if [ "$target_cpu_default2" = "" ]
+ then
+ target_cpu_default2="MASK_GAS"
+ else
+ target_cpu_default2="${target_cpu_default2}|MASK_GAS"
+ fi
fi
;;
- alpha-*-*)
+ arm*-*-*)
+ case "x$with_cpu" in
+ x)
+ # The most generic
+ target_cpu_default2="TARGET_CPU_generic"
+ ;;
+
+ # Distinguish cores, and major variants
+ # arm7m doesn't exist, but D & I don't affect code
+ xarm23678 | xarm250 | xarm67010 \
+ | xarm7m | xarm7dm | xarm7dmi | xarm7tdmi \
+ | xarm7100 | xarm7500 | xarm7500fe | xarm810 \
+ | xstrongarm | xstrongarm110)
+ target_cpu_default2="TARGET_CPU_$with_cpu"
+ ;;
+
+ xyes | xno)
+ echo "--with-cpu must be passed a value" 1>&2
+ exit 1
+ ;;
+
+ *)
+ if [ x$pass2done = xyes ]
+ then
+ echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2
+ exit 1
+ fi
+ ;;
+ esac
+ ;;
+
+ mips*-*-ecoff* | mips*-*-elf*)
if [ x$gas = xyes ]
then
- target_cpu_default=4
+ if [ x$gnu_ld = xyes ]
+ then
+ target_cpu_default2=20
+ else
+ target_cpu_default2=16
+ fi
fi
;;
- esac
+ mips*-*-*)
+ if [ x$gas = xyes ]
+ then
+ target_cpu_default2=16
+ fi
+ ;;
+ powerpc*-*-* | rs6000-*-*)
+ case "x$with_cpu" in
+ x)
+ ;;
- # No need for collect2 if we have the GNU linker.
- case x$gnu_ld in
- xyes)
- use_collect2=
+ xcommon | xpower | xpower2 | xpowerpc | xrios \
+ | xrios1 | xrios2 | xrsc | xrsc1 \
+ | x601 | x602 | x603 | x603e | x604 | x604e | x620 \
+ | x403 | x505 | x801 | x821 | x823 | x860)
+ target_cpu_default2="\"$with_cpu\""
+ ;;
+
+ xyes | xno)
+ echo "--with-cpu must be passed a value" 1>&2
+ exit 1
+ ;;
+
+ *)
+ if [ x$pass2done = xyes ]
+ then
+ echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2
+ exit 1
+ fi
+ ;;
+ esac
+ ;;
+ sparc*-*-*)
+ case ".$with_cpu" in
+ .)
+ target_cpu_default2=TARGET_CPU_"`echo $machine | sed 's/-.*$//'`"
+ ;;
+ .supersparc | .ultrasparc | .v7 | .v8 | .v9)
+ target_cpu_default2="TARGET_CPU_$with_cpu"
+ ;;
+ *)
+ if [ x$pass2done = xyes ]
+ then
+ echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2
+ exit 1
+ fi
+ ;;
+ esac
;;
esac
-# Default certain vars that apply to both host and target in turn.
- if [ x$cpu_type = x ]
- then cpu_type=`echo $machine | sed 's/-.*$//'`
+ if [ "$target_cpu_default2" != "" ]
+ then
+ if [ "$target_cpu_default" != "" ]
+ then
+ target_cpu_default="(${target_cpu_default}|${target_cpu_default2})"
+ else
+ target_cpu_default=$target_cpu_default2
+ fi
fi
+ # No need for collect2 if we have the GNU linker.
+ # Actually, there is now; GNU ld doesn't handle the EH info or
+ # collecting for shared libraries.
+ #case x$gnu_ld in
+ #xyes)
+ # use_collect2=
+ # ;;
+ #esac
+
# Save data on machine being used to compile GCC in build_xm_file.
# Save data on host machine in vars host_xm_file and host_xmake_file.
if [ x$pass1done = x ]
then
- if [ x$xm_file = x ]
+ if [ x"$xm_file" = x ]
then build_xm_file=$cpu_type/xm-$cpu_type.h
else build_xm_file=$xm_file
fi
+ build_xm_defines=$xm_defines
+ build_install_headers_dir=$install_headers_dir
+ build_exeext=$exeext
pass1done=yes
else
if [ x$pass2done = x ]
then
- if [ x$xm_file = x ]
+ if [ x"$xm_file" = x ]
then host_xm_file=$cpu_type/xm-$cpu_type.h
else host_xm_file=$xm_file
fi
- if [ x$xmake_file = x ]
+ host_xm_defines=$xm_defines
+ if [ x"$xmake_file" = x ]
then xmake_file=$cpu_type/x-$cpu_type
fi
- host_xmake_file=$xmake_file
- host_broken_install=$broken_install
- host_install_headers_dir=$install_headers_dir
+ host_xmake_file="$xmake_file"
host_truncate_target=$truncate_target
+ host_extra_gcc_objs=$extra_gcc_objs
+ host_extra_objs=$extra_host_objs
+ host_exeext=$exeext
pass2done=yes
fi
fi
done
+extra_objs="${host_extra_objs} ${extra_objs}"
+
# Default the target-machine variables that were not explicitly set.
-if [ x$tm_file = x ]
+if [ x"$tm_file" = x ]
then tm_file=$cpu_type/$cpu_type.h; fi
if [ x$extra_headers = x ]
then extra_headers=; fi
-if [ x$xm_file = x ]
+if [ x"$xm_file" = x ]
then xm_file=$cpu_type/xm-$cpu_type.h; fi
-md_file=$cpu_type/$cpu_type.md
+if [ x$md_file = x ]
+then md_file=$cpu_type/$cpu_type.md; fi
if [ x$out_file = x ]
then out_file=$cpu_type/$cpu_type.c; fi
-if [ x$tmake_file = x ]
+if [ x"$tmake_file" = x ]
then tmake_file=$cpu_type/t-$cpu_type
fi
+if [ x$float_format = x ]
+then float_format=i64
+fi
+
+if [ x$enable_haifa = x ]
+then
+ case $target in
+ alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc*-* | m32r*-*)
+ enable_haifa=yes;;
+ esac
+fi
+
+# Handle cpp installation.
+if [ x$enable_cpp != x ]
+then
+ tmake_file="$tmake_file t-install-cpp"
+ case x$enable_cpp in
+ xyes | xno) ;;
+ x/*) cpp_install_dir=$enable_cpp ;;
+ x.*) echo "alternate cpp script installation directory must be an absolute path" 1>&2
+ exit 1
+ ;;
+ esac
+fi
+
# Say what files are being used for the output code and MD file.
echo "Using \`$srcdir/config/$out_file' to output insns."
echo "Using \`$srcdir/config/$md_file' as machine description file."
-echo "Using \`$srcdir/config/$tm_file' as target machine macro file."
-echo "Using \`$srcdir/config/$host_xm_file' as host machine macro file."
-if [ $host_xm_file != $build_xm_file ]; then
- echo "Using \`$srcdir/config/$build_xm_file' as build machine macro file."
+
+count=a
+for f in $tm_file; do
+ count=${count}x
+done
+if [ $count = ax ]; then
+ echo "Using \`$srcdir/config/$tm_file' as target machine macro file."
+else
+ echo "Using the following target machine macro files:"
+ for f in $tm_file; do
+ echo " $srcdir/config/$f"
+ done
+fi
+
+count=a
+for f in $host_xm_file; do
+ count=${count}x
+done
+if [ $count = ax ]; then
+ echo "Using \`$srcdir/config/$host_xm_file' as host machine macro file."
+else
+ echo "Using the following host machine macro files:"
+ for f in $host_xm_file; do
+ echo " $srcdir/config/$f"
+ done
+fi
+
+if [ "$host_xm_file" != "$build_xm_file" ]; then
+ count=a
+ for f in $build_xm_file; do
+ count=${count}x
+ done
+ if [ $count = ax ]; then
+ echo "Using \`$srcdir/config/$build_xm_file' as build machine macro file."
+ else
+ echo "Using the following build machine macro files:"
+ for f in $build_xm_file; do
+ echo " $srcdir/config/$f"
+ done
+ fi
+fi
+
+if [ x$thread_file = x ]; then
+ if [ x$target_thread_file != x ]; then
+ thread_file=$target_thread_file
+ else
+ thread_file='single'
+ fi
+fi
+
+# Set up the header files.
+# $links is the list of header files to create.
+# $vars is the list of shell variables with file names to include.
+# auto-host.h is the file containing items generated by autoconf and is
+# the first file included by config.h.
+null_defines=
+host_xm_file="auto-host.h ${host_xm_file}"
+
+# If host=build, it is correct to have hconfig include auto-host.h
+# as well. If host!=build, we are in error and need to do more
+# work to find out the build config parameters.
+if [ x$host = x$build ]
+then
+ build_xm_file="auto-host.h ${build_xm_file}"
+else
+ # We create a subdir, then run autoconf in the subdir.
+ # To prevent recursion we set host and build for the new
+ # invocation of configure to the build for this invocation
+ # of configure.
+ tempdir=build.$$
+ rm -rf $tempdir
+ mkdir $tempdir
+ cd $tempdir
+ case ${srcdir} in
+ /*) realsrcdir=${srcdir};;
+ *) realsrcdir=../${srcdir};;
+ esac
+ CC=${CC_FOR_BUILD} ${realsrcdir}/configure \
+ --target=$target --host=$build --build=$build
+
+ # We just finished tests for the build machine, so rename
+ # the file auto-build.h in the gcc directory.
+ mv auto-host.h ../auto-build.h
+ cd ..
+ rm -rf $tempdir
+ build_xm_file="auto-build.h ${build_xm_file}"
fi
-# Set up the list of links to be made.
-# $links is the list of link names, and $files is the list of names to link to.
-files="$host_xm_file $tm_file $xm_file $build_xm_file"
+vars="host_xm_file tm_file xm_file build_xm_file"
links="config.h tm.h tconfig.h hconfig.h"
+defines="host_xm_defines null_defines xm_defines build_xm_defines"
rm -f config.bak
if [ -f config.status ]; then mv -f config.status config.bak; fi
# Make the links.
-while [ -n "$files" ]
+while [ -n "$vars" ]
do
- # set file to car of files, files to cdr of files
- set $files; file=$1; shift; files=$*
+ set $vars; var=$1; shift; vars=$*
set $links; link=$1; shift; links=$*
+ set $defines; define=$1; shift; defines=$*
rm -f $link
- echo "#include \"$file\"" >$link
+
+ # Define TARGET_CPU_DEFAULT if the system wants one.
+ # This substitutes for lots of *.h files.
+ if [ "$target_cpu_default" != "" -a $link = tm.h ]
+ then
+ echo "#define TARGET_CPU_DEFAULT ($target_cpu_default)" >>$link
+ fi
+
+ for file in `eval echo '$'$var`; do
+ echo "#include \"$file\"" >>$link
+ done
+
+ for def in `eval echo '$'$define`; do
+ echo "#ifndef $def" >>$link
+ echo "#define $def" >>$link
+ echo "#endif" >>$link
+ done
done
# Truncate the target if necessary
@@ -2547,31 +5239,265 @@ if [ x$host_truncate_target != x ]; then
target=`echo $target | sed -e 's/\(..............\).*/\1/'`
fi
-# Get the version number from the toplevel
-version=`sed -e 's/.*\"\([^ \"]*\)[ \"].*/\1/' < ${srcdir}/version.c`
+# Get the version trigger filename from the toplevel
+if [ "${with_gcc_version_trigger+set}" = set ]; then
+ gcc_version_trigger=$with_gcc_version_trigger
+else
+ gcc_version_trigger=${srcdir}/version.c
+fi
+gcc_version=`sed -e 's/.*\"\([^ \"]*\)[ \"].*/\1/' < ${gcc_version_trigger}`
+
+# Get an absolute path to the GCC top-level source directory
+holddir=`pwd`
+cd $srcdir
+topdir=`pwd`
+cd $holddir
+
+# Conditionalize the makefile for this host machine.
+# Make-host contains the concatenation of all host makefile fragments
+# [there can be more than one]. This file is built by configure.frag.
+host_overrides=Make-host
+dep_host_xmake_file=
+for f in .. ${host_xmake_file}
+do
+ if [ -f ${srcdir}/config/$f ]
+ then
+ dep_host_xmake_file="${dep_host_xmake_file} ${srcdir}/config/$f"
+ fi
+done
+
+# Conditionalize the makefile for this target machine.
+# Make-target contains the concatenation of all host makefile fragments
+# [there can be more than one]. This file is built by configure.frag.
+target_overrides=Make-target
+dep_tmake_file=
+for f in .. ${tmake_file}
+do
+ if [ -f ${srcdir}/config/$f ]
+ then
+ dep_tmake_file="${dep_tmake_file} ${srcdir}/config/$f"
+ fi
+done
+
+# If the host doesn't support symlinks, modify CC in
+# FLAGS_TO_PASS so CC="stage1/xgcc -Bstage1/" works.
+# Otherwise, we can use "CC=$(CC)".
+rm -f symtest.tem
+if $symbolic_link $srcdir/gcc.c symtest.tem 2>/dev/null
+then
+ cc_set_by_configure="\$(CC)"
+ stage_prefix_set_by_configure="\$(STAGE_PREFIX)"
+else
+ rm -f symtest.tem
+ if cp -p $srcdir/gcc.c symtest.tem 2>/dev/null
+ then
+ symbolic_link="cp -p"
+ else
+ symbolic_link="cp"
+ fi
+ cc_set_by_configure="\`case '\$(CC)' in stage*) echo '\$(CC)' | sed -e 's|stage|../stage|g';; *) echo '\$(CC)';; esac\`"
+ stage_prefix_set_by_configure="\`case '\$(STAGE_PREFIX)' in stage*) echo '\$(STAGE_PREFIX)' | sed -e 's|stage|../stage|g';; *) echo '\$(STAGE_PREFIX)';; esac\`"
+fi
+rm -f symtest.tem
+
+out_object_file=`basename $out_file .c`.o
+
+tm_file_list=
+for f in $tm_file; do
+ tm_file_list="${tm_file_list} \$(srcdir)/config/$f"
+done
-# For the current directory and all of the language subdirectories,
-# do the rest of the script ...
+host_xm_file_list=
+for f in $host_xm_file; do
+ if test $f != "auto-host.h"; then
+ host_xm_file_list="${host_xm_file_list} \$(srcdir)/config/$f"
+ else
+ host_xm_file_list="${host_xm_file_list} auto-host.h"
+ fi
+done
+build_xm_file_list=
+for f in $build_xm_file; do
+ if test $f != "auto-build.h"; then
+ if test $f != "auto-host.h"; then
+ build_xm_file_list="${build_xm_file_list} \$(srcdir)/config/$f"
+ else
+ build_xm_file_list="${build_xm_file_list} auto-host.h"
+ fi
+ else
+ build_xm_file_list="${build_xm_file_list} auto-build.h"
+ fi
+done
+
+# Define macro CROSS_COMPILE in compilation
+# if this is a cross-compiler.
+# Also use all.cross instead of all.internal
+# and add cross-make to Makefile.
+cross_overrides="/dev/null"
+if [ x$host != x$target ]
+then
+ cross_defines="CROSS=-DCROSS_COMPILE"
+ cross_overrides="${topdir}/cross-make"
+fi
+
+# When building gcc with a cross-compiler, we need to fix a few things.
+# This must come after cross-make as we want all.build to override
+# all.cross.
+build_overrides="/dev/null"
+if [ x$build != x$host ]
+then
+ build_overrides="${topdir}/build-make"
+fi
+
+# Expand extra_headers to include complete path.
+# This substitutes for lots of t-* files.
+extra_headers_list=
+if [ "x$extra_headers" = x ]
+then true
+else
+ # Prepend ${srcdir}/ginclude/ to every entry in extra_headers.
+ for file in $extra_headers;
+ do
+ extra_headers_list="${extra_headers_list} \$(srcdir)/ginclude/${file}"
+ done
+fi
+
+# Add a definition of USE_COLLECT2 if system wants one.
+# Also tell toplev.c what to do.
+# This substitutes for lots of t-* files.
+if [ x$use_collect2 = x ]
+then
+ will_use_collect2=
+ maybe_use_collect2=
+else
+ will_use_collect2="collect2"
+ maybe_use_collect2="-DUSE_COLLECT2"
+fi
+
+# NEED TO CONVERT
+# Set MD_DEPS if the real md file is in md.pre-cpp.
+# Set MD_CPP to the cpp to pass the md file through. Md files use ';'
+# for line oriented comments, so we must always use a GNU cpp. If
+# building gcc with a cross compiler, use the cross compiler just
+# built. Otherwise, we can use the cpp just built.
+md_file_sub=
+if [ "x$md_cppflags" = x ]
+then
+ md_file_sub=$srcdir/config/$md_file
+else
+ md_file=md
+fi
+
+# If we have gas in the build tree, make a link to it.
+if [ -f ../gas/Makefile ]; then
+ rm -f as; $symbolic_link ../gas/as-new$host_exeext as$host_exeext 2>/dev/null
+fi
+
+# If we have nm in the build tree, make a link to it.
+if [ -f ../binutils/Makefile ]; then
+ rm -f nm; $symbolic_link ../binutils/nm-new$host_exeext nm$host_exeext 2>/dev/null
+fi
+
+# If we have ld in the build tree, make a link to it.
+if [ -f ../ld/Makefile ]; then
+# if [[ x$use_collect2 = x ]]; then
+# rm -f ld; $symbolic_link ../ld/ld-new$host_exeext ld$host_exeext 2>/dev/null
+# else
+ rm -f collect-ld; $symbolic_link ../ld/ld-new$host_exeext collect-ld$host_exeext 2>/dev/null
+# fi
+fi
+
+# Figure out what assembler alignment features are present.
+echo $ac_n "checking assembler alignment features""... $ac_c" 1>&6
+echo "configure:5413: checking assembler alignment features" >&5
+gcc_cv_as=
+gcc_cv_as_alignment_features=
+gcc_cv_as_gas_srcdir=`echo $srcdir | sed -e 's,gcc$,gas,'`
+if [ -x as$host_exeext ]; then
+ # Build using assembler in the current directory.
+ gcc_cv_as=./as$host_exeext
+elif [ -f $gcc_cv_as_gas_srcdir/configure.in ]; then
+ # Single tree build which includes gas.
+ for f in $gcc_cv_as_gas_srcdir/configure $gcc_cv_as_gas_srcdir/configure.in $gcc_cv_as_gas_srcdir/Makefile.in
+ do
+ gcc_cv_gas_version=`grep '^VERSION=[0-9]*\.[0-9]*' $f`
+ if [ x$gcc_cv_gas_version != x ]; then
+ break
+ fi
+ done
+ gcc_cv_gas_major_version=`expr "$gcc_cv_gas_version" : "VERSION=\([0-9]*\)"`
+ gcc_cv_gas_minor_version=`expr "$gcc_cv_gas_version" : "VERSION=[0-9]*\.\([0-9]*\)"`
+ if [ x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x ]; then
+ # Gas version 2.6 and later support for .balign and .p2align.
+ # bytes to skip when using .p2align.
+ if [ "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 6 -o "$gcc_cv_gas_major_version" -gt 2 ]; then
+ gcc_cv_as_alignment_features=".balign and .p2align"
+ cat >> confdefs.h <<\EOF
+#define HAVE_GAS_BALIGN_AND_P2ALIGN 1
+EOF
+
+ fi
+ # Gas version 2.8 and later support specifying the maximum
+ # bytes to skip when using .p2align.
+ if [ "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 8 -o "$gcc_cv_gas_major_version" -gt 2 ]; then
+ gcc_cv_as_alignment_features=".p2align including maximum skip"
+ cat >> confdefs.h <<\EOF
+#define HAVE_GAS_MAX_SKIP_P2ALIGN 1
+EOF
+
+ fi
+ fi
+elif [ x$host = x$target ]; then
+ # Native build.
+ gcc_cv_as=as$host_exeext
+fi
+if [ x$gcc_cv_as != x ]; then
+ # Check if we have .balign and .p2align
+ echo ".balign 4" > conftest.s
+ echo ".p2align 2" >> conftest.s
+ if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1; then
+ gcc_cv_as_alignment_features=".balign and .p2align"
+ cat >> confdefs.h <<\EOF
+#define HAVE_GAS_BALIGN_AND_P2ALIGN 1
+EOF
+
+ fi
+ rm -f conftest.s conftest.o
+ # Check if specifying the maximum bytes to skip when
+ # using .p2align is supported.
+ echo ".p2align 4,,7" > conftest.s
+ if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1; then
+ gcc_cv_as_alignment_features=".p2align including maximum skip"
+ cat >> confdefs.h <<\EOF
+#define HAVE_GAS_MAX_SKIP_P2ALIGN 1
+EOF
+
+ fi
+ rm -f conftest.s conftest.o
+fi
+echo "$ac_t""$gcc_cv_as_alignment_features" 1>&6
+
+# Figure out what language subdirectories are present.
subdirs=
for lang in ${srcdir}/*/config-lang.in ..
do
case $lang in
..) ;;
# The odd quoting in the next line works around
- # an apparent bug in bash 1.12 on GNU/Linux.
+ # an apparent bug in bash 1.12 on linux.
${srcdir}/[*]/config-lang.in) ;;
*) subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([^/]*\)/config-lang.in$,\1,'`" ;;
esac
done
-# Are we using gcc as the native compiler?
-case $canon_host in
-*linux*) # All GNU/Linux systems use gcc as the native compiler.
- prefix=$native_prefix
- gxx_include_dir=$prefix/include/g++
- ;;
-esac
+# Make gthr-default.h if we have a thread file.
+gthread_flags=
+if [ $thread_file != single ]; then
+ rm -f gthr-default.h
+ echo "#include \"gthr-${thread_file}.h\"" > gthr-default.h
+ gthread_flags=-DHAVE_GTHR_DEFAULT
+fi
+
# Make empty files to contain the specs and options for each language.
# Then add #include lines to for a compiler that has specs and/or options.
@@ -2592,502 +5518,226 @@ do
fi
done
-# Define SET_MAKE if this old version of `make' doesn't define $(MAKE).
-rm -f Makefile.xx
-(echo 'all:'; echo ' @echo maketemp=$(MAKE)') >Makefile.xx
-case `${MAKE-make} -f Makefile.xx 2>/dev/null | grep maketemp=` in
-'maketemp=')
- SET_MAKE="MAKE = ${MAKE-make}"
- ;;
-*)
- SET_MAKE=
- ;;
-esac
-rm -f Makefile.xx
+# These (without "all_") are set in each config-lang.in.
+# `language' must be a single word so is spelled singularly.
+all_languages=
+all_boot_languages=
+all_compilers=
+all_stagestuff=
+all_diff_excludes=
+all_outputs=Makefile
+# List of language makefile fragments.
+all_lang_makefiles=
+all_headers=
+all_lib2funcs=
-savesrcdir=$srcdir
-for subdir in . $subdirs
-do
- oldsrcdir=$savesrcdir
+# Add the language fragments.
+# Languages are added via two mechanisms. Some information must be
+# recorded in makefile variables, these are defined in config-lang.in.
+# We accumulate them and plug them into the main Makefile.
+# The other mechanism is a set of hooks for each of the main targets
+# like `clean', `install', etc.
- # Re-adjust the path
- case $oldsrcdir in
- /*)
- srcdir=$oldsrcdir/$subdir
- ;;
- *)
- case $subdir in
- .)
- ;;
- *)
- oldsrcdir=../${oldsrcdir}
- srcdir=$oldsrcdir/$subdir
- ;;
- esac
- ;;
- esac
- mainsrcdir=$oldsrcdir
- STARTDIR=`pwd`
- test -d $subdir || mkdir $subdir
- cd $subdir
-
- # Create Makefile.tem from Makefile.in.
- # Make it set VPATH if necessary so that the sources are found.
- # Also change its value of srcdir.
- # Also create a .gdbinit file which runs the one in srcdir
- # and tells GDB to look there for source files.
- case $srcdir in
- . | ./$subdir | .././$subdir)
- rm -f Makefile.tem
- cp Makefile.in Makefile.tem
- chmod +w Makefile.tem
- ;;
- *)
- rm -f Makefile.tem
- echo "VPATH = ${srcdir}" \
- | cat - ${srcdir}/Makefile.in \
- | sed "s@^srcdir = \.@srcdir = ${srcdir}@" > Makefile.tem
- rm -f .gdbinit
- echo "dir ." > .gdbinit
- echo "dir ${srcdir}" >> .gdbinit
- if [ x$gdb_needs_out_file_path = xyes ]
+language_fragments="Make-lang"
+language_hooks="Make-hooks"
+oldstyle_subdirs=
+
+for s in .. $subdirs
+do
+ if [ $s != ".." ]
+ then
+ language=
+ boot_language=
+ compilers=
+ stagestuff=
+ diff_excludes=
+ headers=
+ outputs=
+ lib2funcs=
+ . ${srcdir}/$s/config-lang.in
+ if [ "x$language" = x ]
then
- echo "dir ${srcdir}/config/"`dirname ${out_file}` >> .gdbinit
+ echo "${srcdir}/$s/config-lang.in doesn't set \$language." 1>&2
+ exit 1
fi
- if [ "x$subdirs" != x ]; then
- for s in $subdirs
- do
- echo "dir ${srcdir}/$s" >> .gdbinit
- done
+ all_lang_makefiles="$all_lang_makefiles ${srcdir}/$s/Make-lang.in ${srcdir}/$s/Makefile.in"
+ all_languages="$all_languages $language"
+ if [ "x$boot_language" = xyes ]
+ then
+ all_boot_languages="$all_boot_languages $language"
fi
- echo "source ${srcdir}/.gdbinit" >> .gdbinit
- ;;
- esac
-
- # Conditionalize the makefile for this host machine.
- if [ -f ${mainsrcdir}/config/${host_xmake_file} ]
- then
- rm -f Makefile.xx
- sed -e "/####host/ r ${mainsrcdir}/config/${host_xmake_file}" Makefile.tem > Makefile.xx
- echo "Merged ${host_xmake_file}."
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- dep_host_xmake_file=${host_xmake_file}
- else
- # Say in the makefile that there is no host_xmake_file,
- # by using a name which (when interpreted relative to $srcdir/config)
- # will duplicate another dependency: $srcdir/Makefile.in.
- dep_host_xmake_file=../Makefile.in
+ all_compilers="$all_compilers $compilers"
+ all_stagestuff="$all_stagestuff $stagestuff"
+ all_diff_excludes="$all_diff_excludes $diff_excludes"
+ all_headers="$all_headers $headers"
+ all_outputs="$all_outputs $outputs"
+ if [ x$outputs = x ]
+ then
+ oldstyle_subdirs="$oldstyle_subdirs $s"
+ fi
+ all_lib2funcs="$all_lib2funcs $lib2funcs"
fi
+done
- # Add a definition for MAKE if system wants one.
- case "$SET_MAKE" in
- ?*)
- rm -f Makefile.xx
- (echo "$SET_MAKE"; cat Makefile.tem) >Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- esac
+# Since we can't use `::' targets, we link each language in
+# with a set of hooks, reached indirectly via lang.${target}.
- # Add a definition for INSTALL if system wants one.
- # This substitutes for lots of x-* files.
- if [ x$host_broken_install = x ]
- then true
- else
- rm -f Makefile.xx
- abssrcdir=`cd ${srcdir}; pwd`
- sed "s|^INSTALL = .*|INSTALL = ${abssrcdir}/install.sh -c|" Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- fi
+rm -f Make-hooks
+touch Make-hooks
+target_list="all.build all.cross start.encap rest.encap \
+ info dvi \
+ install-normal install-common install-info install-man \
+ uninstall distdir \
+ mostlyclean clean distclean extraclean maintainer-clean \
+ stage1 stage2 stage3 stage4"
+for t in $target_list
+do
+ x=
+ for l in .. $all_languages
+ do
+ if [ $l != ".." ]; then
+ x="$x $l.$t"
+ fi
+ done
+ echo "lang.$t: $x" >> Make-hooks
+done
- # Some of the following don't make sense in the language makefiles,
- # but rather than introduce another level of nesting, we leave them
- # as is.
+# If we're not building in srcdir, create .gdbinit.
- # Set EXTRA_HEADERS according to extra_headers.
- # This substitutes for lots of t-* files.
- if [ "x$extra_headers" = x ]
- then true
- else
- # Prepend ${srcdir}/ginclude/ to every entry in extra_headers.
- list=
- for file in $extra_headers;
+if [ ! -f Makefile.in ]; then
+ echo "dir ." > .gdbinit
+ echo "dir ${srcdir}" >> .gdbinit
+ if [ x$gdb_needs_out_file_path = xyes ]
+ then
+ echo "dir ${srcdir}/config/"`dirname ${out_file}` >> .gdbinit
+ fi
+ if [ "x$subdirs" != x ]; then
+ for s in $subdirs
do
- list="${list} ${srcdir}/ginclude/${file}"
+ echo "dir ${srcdir}/$s" >> .gdbinit
done
- rm -f Makefile.xx
- sed "s|^EXTRA_HEADERS =|EXTRA_HEADERS = ${list}|" Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- fi
-
- # Set EXTRA_PASSES according to extra_passes.
- # This substitutes for lots of t-* files.
- if [ "x$extra_passes" = x ]
- then true
- else
- rm -f Makefile.xx
- sed "s/^EXTRA_PASSES =/EXTRA_PASSES = $extra_passes/" Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- fi
-
- # Set EXTRA_PARTS according to extra_parts.
- # This substitutes for lots of t-* files.
- if [ "x$extra_parts" = x ]
- then true
- else
- rm -f Makefile.xx
- sed "s/^EXTRA_PARTS =/EXTRA_PARTS = $extra_parts/" Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
fi
+ echo "source ${srcdir}/.gdbinit" >> .gdbinit
+fi
- # Set EXTRA_PROGRAMS according to extra_programs.
- if [ "x$extra_programs" = x ]
- then true
- else
- rm -f Makefile.xx
- sed "s/^EXTRA_PROGRAMS =/EXTRA_PROGRAMS = $extra_programs/" Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- fi
+# Define variables host_canonical and build_canonical
+# because some Cygnus local changes in the Makefile depend on them.
+build_canonical=${build}
+host_canonical=${host}
+target_subdir=
+if [ "${host}" != "${target}" ] ; then
+ target_subdir=${target}/
+fi
- # Set EXTRA_OBJS according to extra_objs.
- # This substitutes for lots of t-* files.
- if [ "x$extra_objs" = x ]
- then true
- else
- rm -f Makefile.xx
- sed "s|^EXTRA_OBJS =|EXTRA_OBJS = $extra_objs|" Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- fi
- # Set EXTRA_GCC_OBJS according to extra_gcc_objs.
- # This substitutes for lots of t-* files.
- if [ "x$extra_gcc_objs" = x ]
- then true
- else
- rm -f Makefile.xx
- sed "s|^EXTRA_GCC_OBJS =|EXTRA_GCC_OBJS = $extra_gcc_objs|" Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- fi
- # Add a definition of USE_COLLECT2 if system wants one.
- # Also tell toplev.c what to do.
- # This substitutes for lots of t-* files.
- if [ x$use_collect2 = x ]
- then true
- else
- rm -f Makefile.xx
- (echo "USE_COLLECT2 = ld"; echo "MAYBE_USE_COLLECT2 = -DUSE_COLLECT2")\
- | cat - Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- fi
-
- # Add -DTARGET_CPU_DEFAULT for toplev.c if system wants one.
- # This substitutes for lots of *.h files.
- if [ x$target_cpu_default = x ]
- then true
- else
- rm -f Makefile.xx
- # This used cat, but rfg@netcom.com said that ran into NFS bugs.
- sed -e "/^# Makefile for GNU C compiler./c\\
-MAYBE_TARGET_DEFAULT = -DTARGET_CPU_DEFAULT=$target_cpu_default\\
-\# Makefile for GNU C compiler." Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- fi
- # Set MD_DEPS if the real md file is in md.pre-cpp.
- # Set MD_CPP to the cpp to pass the md file through. Md files use ';'
- # for line oriented comments, so we must always use a GNU cpp. If
- # building gcc with a cross compiler, use the cross compiler just
- # built. Otherwise, we can use the cpp just built.
- if [ "x$md_cppflags" = x ]
- then
- md_file=$srcdir/config/$md_file
- else
- rm -f Makefile.xx
- (if [ x$host = x$build ] ; then
- echo "MD_DEPS = $(md_file) cpp" ; echo "MD_CPP = ./cpp"
- else
- echo "MD_DEPS = md.pre-cpp" ; echo "MD_CPP = \$(HOST_CC) -x c -E"
- fi
- md_file=md
- echo "MD_CPPFLAGS = $md_cppflags") | \
- cat - Makefile.tem | sed -e "s|^MD_FILE[ ]*=.*|MD_FILE = md|" > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- fi
-
- # If we have gas in the build tree, make a link to it.
- if [ -f ../gas/Makefile ]; then
- rm -f as; $symbolic_link ../gas/as.new as 2>/dev/null
- fi
-
- # If we have ld in the build tree, make a link to it.
- if [ -f ../ld/Makefile ]; then
- if [ x$use_collect2 = x ]; then
- rm -f ld; $symbolic_link ../ld/ld.new ld 2>/dev/null
- else
- rm -f collect-ld; $symbolic_link ../ld/ld.new collect-ld 2>/dev/null
- fi
- fi
-
- # If using -program-transform-name, override the installation names.
- if [ "x${program_transform_set}" = "xyes" ] ; then
- sed -e "s/^program_transform_name[ ]*=.*$/program_transform_name = $program_transform_name/" \
- -e "s/^program_transform_cross_name[ ]*=.*$/program_transform_cross_name = $program_transform_name/" \
- Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- fi
-
- # Conditionalize the makefile for this target machine.
- if [ -f ${mainsrcdir}/config/${tmake_file} ]
- then
- rm -f Makefile.xx
- sed -e "/####target/ r ${mainsrcdir}/config/${tmake_file}" Makefile.tem > Makefile.xx
- echo "Merged ${tmake_file}."
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- dep_tmake_file=${tmake_file}
- else
- # Say in the makefile that there is no tmake_file,
- # by using a name which (when interpreted relative to $srcdir/config)
- # will duplicate another dependency: $srcdir/Makefile.in.
- dep_tmake_file=../Makefile.in
- fi
-
- # If this is the top level Makefile, add the language fragments.
- # Languages are added via two mechanisms. Some information must be
- # recorded in makefile variables, these are defined in config-lang.in.
- # We accumulate them and plug them into the main Makefile.
- # The other mechanism is a set of hooks for each of the main targets
- # like `clean', `install', etc.
- if [ $subdir = . ]
- then
- # These (without "all_") are set in each config-lang.in.
- # `language' must be a single word so is spelled singularly.
- all_languages=
- all_compilers=
- all_stagestuff=
- all_diff_excludes=
- # List of language makefile fragments.
- all_lang_makefiles=
-
- rm -f Makefile.xx Makefile.ll
- touch Makefile.ll
- for s in .. $subdirs
- do
- if [ $s != ".." ]
- then
- language=
- compilers=
- stagestuff=
- diff_excludes=
- . ${mainsrcdir}/$s/config-lang.in
- if [ "x$language" = x ]
- then
- echo "${mainsrcdir}/$s/config-lang.in doesn't set \$language." 1>&2
- exit 1
- fi
- all_lang_makefiles="$all_lang_makefiles ${mainsrcdir}/$s/Make-lang.in ${mainsrcdir}/$s/Makefile.in"
- all_languages="$all_languages $language"
- all_compilers="$all_compilers $compilers"
- all_stagestuff="$all_stagestuff $stagestuff"
- all_diff_excludes="$all_diff_excludes $diff_excludes"
+# If this is using newlib, then define inhibit_libc in
+# LIBGCC2_CFLAGS. This will cause __eprintf to be left out of
+# libgcc.a, but that's OK because newib should have its own version of
+# assert.h.
+inhibit_libc=
+if [ x$with_newlib = xyes ]; then
+ inhibit_libc=-Dinhibit_libc
+fi
- cat ${mainsrcdir}/$s/Make-lang.in >> Makefile.ll
- fi
- done
- sed -e "/####language fragments/ r Makefile.ll" Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- sed -e "s|^SUBDIRS[ ]*=.*$|SUBDIRS = $subdirs|" \
- -e "s|^LANGUAGES[ ]*=[ ]*\(.*\)$|LANGUAGES = \1 $all_languages|" \
- -e "s|^COMPILERS[ ]*=[ ]*\(.*\)$|COMPILERS = \1 $all_compilers|" \
- -e "s|^LANG_MAKEFILES[ ]*=.*$|LANG_MAKEFILES = $all_lang_makefiles|" \
- -e "s|^LANG_STAGESTUFF[ ]*=.*$|LANG_STAGESTUFF = $all_stagestuff|" \
- -e "s|^LANG_DIFF_EXCLUDES[ ]*=.*$|LANG_DIFF_EXCLUDES = $all_diff_excludes|" \
- Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
-
- # Since we can't use `::' targets, we link each language in
- # with a set of hooks, reached indirectly via lang.${target}.
-
- target_list="all.build all.cross start.encap rest.encap \
- info dvi \
- install-normal install-common install-info install-man \
- uninstall distdir \
- mostlyclean clean distclean extraclean maintainer-clean \
- stage1 stage2 stage3 stage4"
- rm -f Makefile.ll
- for t in $target_list
- do
- x=
- for l in .. $all_languages
- do
- if [ $l != ".." ]; then
- x="$x $l.$t"
- fi
- done
- echo "lang.$t: $x" >> Makefile.ll
- done
- sed -e "/####language hooks/ r Makefile.ll" Makefile.tem > Makefile.xx
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- rm -f Makefile.ll
- # If the host doesn't support symlinks, modify CC in
- # FLAGS_TO_PASS so CC="stage1/xgcc -Bstage1/" works.
- # Otherwise, we can use "CC=$(CC)".
- rm -f symtest.tem
- if $symbolic_link symtest1.tem symtest.tem 2>/dev/null
- then
- sed -e 's,CC=set-by-configure,CC=$(CC),' \
- Makefile.tem > Makefile.xx
- else
- sed -e "s,CC=set-by-configure,CC=\`case '$(CC)' in stage*) echo '$(CC)' | sed -e 's|stage|../stage|g';; *) echo '$(CC)';; esac\`," \
- Makefile.tem > Makefile.xx
- fi
- rm -f Makefile.tem
- mv Makefile.xx Makefile.tem
- rm -f symtest.tem
+# Override SCHED_OBJ and SCHED_CFLAGS to enable the Haifa scheduler.
+sched_prefix=
+sched_cflags=
+if [ x$enable_haifa = xyes ]; then
+ echo "Using the Haifa scheduler."
+ sched_prefix=haifa-
+ sched_cflags=-DHAIFA
+fi
- if [ "x$all_languages" != x ]
- then
- # Missing space after `Merged' is intentional.
- echo "Merged$all_languages fragment(s)."
- fi
- # Otherwise, this is a language subdirectory. If the host supports
- # symlinks, point stage[123] at ../stage[123] so bootstrapping and the
- # installation procedure can still use CC="stage1/xgcc -Bstage1/".
- # If the host doesn't support symlinks, FLAGS_TO_PASS has been
- # modified to solve the problem there.
- else
- for t in stage1 stage2 stage3 stage4 include
- do
- rm -f $t
- $symbolic_link ../$t $t 2>/dev/null
- done
+if [ x$enable_haifa != x ]; then
+ # Explicitly remove files that need to be recompiled for the Haifa scheduler.
+ for x in genattrtab.o toplev.o loop.o unroll.o *sched.o; do
+ if [ -f $x ]; then
+ echo "Removing $x"
+ rm -f $x
fi
+ done
+fi
+
+# Nothing to do for FLOAT_H, float_format already handled.
+objdir=`pwd`
+
+
+# Process the language and host/target makefile fragments.
+${CONFIG_SHELL-/bin/sh} $srcdir/configure.frag $srcdir "$subdirs" "$dep_host_xmake_file" "$dep_tmake_file"
+
+# Substitute configuration variables
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- out_object_file=`basename $out_file .c`.o
-
- # Remove all formfeeds, since some Makes get confused by them.
- # Also arrange to give the variables `target', `host_xmake_file',
- # `tmake_file', `prefix', `local_prefix', `exec_prefix', `FIXINCLUDES'
- # `out_file', `out_object', `md_file', `lang_specs_files',
- # `lang_options_files', and `INSTALL_HEADERS_DIR' values in the
- # Makefile from the values they have in this script.
- rm -f Makefile.xx
- rm -f aux-output.c aux-output.o md
- # Create an empty Makefile.sed first, to work around a Nextstep 3.3 bug.
- echo 's| ||' > Makefile.sed
- rm Makefile.sed
- echo 's| ||' > Makefile.sed
- echo "s|^target=.*$|target=${target}|" >> Makefile.sed
- echo "s|^xmake_file=.*$|xmake_file=${dep_host_xmake_file}|" >> Makefile.sed
- echo "s|^tmake_file=.*$|tmake_file=${dep_tmake_file}|" >> Makefile.sed
- echo "s|^version=.*$|version=${version}|" >> Makefile.sed
- echo "s|^version=.*$|version=${version}|" >> Makefile.sed
- echo "s|^out_file=.*$|out_file=${srcdir}/config/${out_file}|" >> Makefile.sed
- echo "s|^out_object_file=.*$|out_object_file=${out_object_file}|" >> Makefile.sed
- echo "s|^md_file=.*$|md_file=${md_file}|" >> Makefile.sed
- echo "s|^tm_file=.*$|tm_file=${srcdir}/config/${tm_file}|" >> Makefile.sed
- echo "s|^host_xm_file=.*$|host_xm_file=${srcdir}/config/${host_xm_file}|" >> Makefile.sed
- echo "s|^build_xm_file=.*$|build_xm_file=${srcdir}/config/${build_xm_file}|" >> Makefile.sed
- echo "s|^lang_specs_files=.*$|lang_specs_files=${lang_specs_files}|" >> Makefile.sed
- echo "s|^lang_options_files=.*$|lang_options_files=${lang_options_files}|" >> Makefile.sed
- echo "s|^prefix[ ]*=.*|prefix = $prefix|" >> Makefile.sed
- echo "s|^gxx_include_dir[ ]*=.*|gxx_include_dir = $gxx_include_dir|" >> Makefile.sed
- echo "s|^local_prefix[ ]*=.*|local_prefix = $local_prefix|" >> Makefile.sed
- echo "s|^exec_prefix[ ]*=.*|exec_prefix = $exec_prefix|" >> Makefile.sed
- echo "s|^FIXINCLUDES[ ]*=.*|FIXINCLUDES = $fixincludes|" >> Makefile.sed
- echo "s|^INSTALL_HEADERS_DIR[ ]*=.*$|INSTALL_HEADERS_DIR = ${host_install_headers_dir}|" >> Makefile.sed
- sed -f Makefile.sed Makefile.tem > Makefile.xx
- rm -f Makefile.tem Makefile.sed
- mv Makefile.xx Makefile.tem
-
- # Install Makefile for real, after making final changes.
- # Define macro CROSS_COMPILE in compilation if this is a cross-compiler.
- # Also use all.cross instead of all.internal, and add cross-make to Makefile.
- if [ x$canon_host = x$canon_target ]
- then
- rm -f Makefile
- if [ x$canon_host = x$canon_build ]
- then
- mv Makefile.tem Makefile
- else
- # When building gcc with a cross-compiler, we need to fix a
- # few things.
- echo "build= $build" > Makefile
- sed -e "s|objc-runtime$||" \
- -e "/####build/ r ${mainsrcdir}/build-make" Makefile.tem >> Makefile
- rm -f Makefile.tem Makefile.xx
- fi
- else
- rm -f Makefile
- echo "CROSS=-DCROSS_COMPILE" > Makefile
- sed -e "/####cross/ r ${mainsrcdir}/cross-make" Makefile.tem >> Makefile
- rm -f Makefile.tem Makefile.xx
- fi
- echo "Created \`$subdir/Makefile'."
- # If a subdirectory has a configure script, run it.
- if [ x$subdir != x. ]
- then
- if [ -f $srcdir/configure ]
- then
- ${CONFIG_SHELL-sh} $srcdir/configure $arguments --srcdir=$srcdir
- fi
- fi
- cd $STARTDIR
-done # end of current-dir SUBDIRS loop
-
-srcdir=$savesrcdir
-
-# Describe the chosen configuration in config.status.
-# Make that file a shellscript which will reestablish the same configuration.
-echo "#!/bin/sh
-# GCC was configured as follows:
-${srcdir}/configure" $arguments > config.new
-echo echo host=$canon_host target=$canon_target build=$canon_build >> config.new
-chmod a+x config.new
-if [ -f config.bak ] && cmp config.bak config.new >/dev/null 2>/dev/null;
-then
- mv -f config.bak config.status
- rm -f config.new
-else
- mv -f config.new config.status
- rm -f config.bak
-fi
-str2=
-str3=
-str4=.
-if [ x$canon_host = x$canon_target ]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Echo that links are built
+if [ x$host = x$target ]
then
str1="native "
else
str1="cross-"
- str2=" from $canon_host"
+ str2=" from $host"
fi
-if [ x$canon_host != x$canon_build ]
+if [ x$host != x$build ]
then
- str3=" on a $canon_build system"
+ str3=" on a $build system"
fi
if [ "x$str2" != x ] || [ "x$str3" != x ]
@@ -3095,11 +5745,523 @@ then
str4=
fi
-echo "Links are now set up to build a ${str1}compiler for ${canon_target}$str4" 1>&2
+echo "Links are now set up to build a ${str1}compiler for ${target}$str4" 1>&2
if [ "x$str2" != x ] || [ "x$str3" != x ]
then
echo " ${str2}${str3}." 1>&2
fi
+# Truncate the target if necessary
+if [ x$host_truncate_target != x ]; then
+ target=`echo $target | sed -e 's/\(..............\).*/\1/'`
+fi
+
+# Configure the subdirectories
+# AC_CONFIG_SUBDIRS($subdirs)
+
+# Create the Makefile
+# and configure language subdirectories
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.13"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+
+trap 'rm -fr `echo "$all_outputs auto-host.h:config.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@SHELL@%$SHELL%g
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@FFLAGS@%$FFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@target@%$target%g
+s%@target_alias@%$target_alias%g
+s%@target_cpu@%$target_cpu%g
+s%@target_vendor@%$target_vendor%g
+s%@target_os@%$target_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@CC@%$CC%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@AWK@%$AWK%g
+s%@LEX@%$LEX%g
+s%@LEXLIB@%$LEXLIB%g
+s%@LN@%$LN%g
+s%@LN_S@%$LN_S%g
+s%@RANLIB@%$RANLIB%g
+s%@YACC@%$YACC%g
+s%@INSTALL@%$INSTALL%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@CPP@%$CPP%g
+s%@vfprintf@%$vfprintf%g
+s%@doprint@%$doprint%g
+s%@manext@%$manext%g
+s%@objext@%$objext%g
+s%@gthread_flags@%$gthread_flags%g
+s%@build_canonical@%$build_canonical%g
+s%@host_canonical@%$host_canonical%g
+s%@target_subdir@%$target_subdir%g
+s%@inhibit_libc@%$inhibit_libc%g
+s%@sched_prefix@%$sched_prefix%g
+s%@sched_cflags@%$sched_cflags%g
+s%@objdir@%$objdir%g
+s%@subdirs@%$subdirs%g
+s%@all_languages@%$all_languages%g
+s%@all_boot_languages@%$all_boot_languages%g
+s%@all_compilers@%$all_compilers%g
+s%@all_lang_makefiles@%$all_lang_makefiles%g
+s%@all_stagestuff@%$all_stagestuff%g
+s%@all_diff_excludes@%$all_diff_excludes%g
+s%@all_lib2funcs@%$all_lib2funcs%g
+s%@all_headers@%$all_headers%g
+s%@cpp_main@%$cpp_main%g
+s%@extra_passes@%$extra_passes%g
+s%@extra_programs@%$extra_programs%g
+s%@extra_parts@%$extra_parts%g
+s%@extra_c_objs@%$extra_c_objs%g
+s%@extra_cxx_objs@%$extra_cxx_objs%g
+s%@extra_c_flags@%$extra_c_flags%g
+s%@extra_objs@%$extra_objs%g
+s%@host_extra_gcc_objs@%$host_extra_gcc_objs%g
+s%@extra_headers_list@%$extra_headers_list%g
+s%@dep_host_xmake_file@%$dep_host_xmake_file%g
+s%@dep_tmake_file@%$dep_tmake_file%g
+s%@out_file@%$out_file%g
+s%@out_object_file@%$out_object_file%g
+s%@md_file@%$md_file%g
+s%@tm_file_list@%$tm_file_list%g
+s%@build_xm_file_list@%$build_xm_file_list%g
+s%@host_xm_file_list@%$host_xm_file_list%g
+s%@lang_specs_files@%$lang_specs_files%g
+s%@lang_options_files@%$lang_options_files%g
+s%@thread_file@%$thread_file%g
+s%@gcc_version@%$gcc_version%g
+s%@gcc_version_trigger@%$gcc_version_trigger%g
+s%@local_prefix@%$local_prefix%g
+s%@gxx_include_dir@%$gxx_include_dir%g
+s%@fixincludes@%$fixincludes%g
+s%@build_install_headers_dir@%$build_install_headers_dir%g
+s%@build_exeext@%$build_exeext%g
+s%@host_exeext@%$host_exeext%g
+s%@float_format@%$float_format%g
+s%@will_use_collect2@%$will_use_collect2%g
+s%@maybe_use_collect2@%$maybe_use_collect2%g
+s%@cc_set_by_configure@%$cc_set_by_configure%g
+s%@stage_prefix_set_by_configure@%$stage_prefix_set_by_configure%g
+s%@install@%$install%g
+s%@symbolic_link@%$symbolic_link%g
+s%@cpp_install_dir@%$cpp_install_dir%g
+/@target_overrides@/r $target_overrides
+s%@target_overrides@%%g
+/@host_overrides@/r $host_overrides
+s%@host_overrides@%%g
+s%@cross_defines@%$cross_defines%g
+/@cross_overrides@/r $cross_overrides
+s%@cross_overrides@%%g
+/@build_overrides@/r $build_overrides
+s%@build_overrides@%%g
+/@language_fragments@/r $language_fragments
+s%@language_fragments@%%g
+/@language_hooks@/r $language_hooks
+s%@language_hooks@%%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"$all_outputs"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="auto-host.h:config.in"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+host='${host}'
+build='${build}'
+target='${target}'
+target_alias='${target_alias}'
+srcdir='${srcdir}'
+subdirs='${subdirs}'
+oldstyle_subdirs='${oldstyle_subdirs}'
+symbolic_link='${symbolic_link}'
+program_transform_set='${program_transform_set}'
+program_transform_name='${program_transform_name}'
+dep_host_xmake_file='${dep_host_xmake_file}'
+host_xmake_file='${host_xmake_file}'
+dep_tmake_file='${dep_tmake_file}'
+tmake_file='${tmake_file}'
+thread_file='${thread_file}'
+gcc_version='${gcc_version}'
+gcc_version_trigger='${gcc_version_trigger}'
+local_prefix='${local_prefix}'
+build_install_headers_dir='${build_install_headers_dir}'
+build_exeext='${build_exeext}'
+host_exeext='${host_exeext}'
+out_file='${out_file}'
+gdb_needs_out_file_path='${gdb_needs_out_file_path}'
+SET_MAKE='${SET_MAKE}'
+target_list='${target_list}'
+target_overrides='${target_overrides}'
+host_overrides='${host_overrides}'
+cross_defines='${cross_defines}'
+cross_overrides='${cross_overrides}'
+build_overrides='${build_overrides}'
+cpp_install_dir='${cpp_install_dir}'
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+. $srcdir/configure.lang
+case x$CONFIG_HEADERS in
+xauto-host.h:config.in)
+echo > cstamp-h ;;
+esac
+# If the host supports symlinks, point stage[1234] at ../stage[1234] so
+# bootstrapping and the installation procedure can still use
+# CC="stage1/xgcc -Bstage1/". If the host doesn't support symlinks,
+# FLAGS_TO_PASS has been modified to solve the problem there.
+# This is virtually a duplicate of what happens in configure.lang; we do
+# an extra check to make sure this only happens if ln -s can be used.
+if [ "$symbolic_link" = "ln -s" ]; then
+ for d in .. ${subdirs} ; do
+ if [ $d != .. ]; then
+ STARTDIR=`pwd`
+ cd $d
+ for t in stage1 stage2 stage3 stage4 include
+ do
+ rm -f $t
+ $symbolic_link ../$t $t 2>/dev/null
+ done
+ cd $STARTDIR
+ fi
+ done
+else true ; fi
+
exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
diff --git a/contrib/gcc/configure.frag b/contrib/gcc/configure.frag
new file mode 100644
index 0000000..4bdac94
--- /dev/null
+++ b/contrib/gcc/configure.frag
@@ -0,0 +1,77 @@
+# configure.frag for GNU CC
+# Process the host/target/language Makefile fragments.
+
+# Copyright (C) 1997 Free Software Foundation, Inc.
+
+#This file is part of GNU CC.
+
+#GNU CC 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, or (at your option)
+#any later version.
+
+#GNU CC 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 GNU CC; see the file COPYING. If not, write to
+#the Free Software Foundation, 59 Temple Place - Suite 330,
+#Boston, MA 02111-1307, USA.
+
+# First parameter is the source directory, second is list of subdirectories,
+# third is list of host makefile fragments, fourth is list of target makefile
+# fragments.
+
+srcdir=$1
+subdirs=$2
+xmake_files=$3
+tmake_files=$4
+
+# Copy all the host makefile fragments into Make-host.
+
+rm -f Make-host
+touch Make-host
+for f in .. $xmake_files
+do
+ if [ -f $f ]
+ then
+ cat $f >> Make-host
+ fi
+done
+
+# Copy all the target makefile fragments into Make-target.
+
+rm -f Make-target
+touch Make-target
+for f in .. $tmake_files
+do
+ if [ -f $f ]
+ then
+ cat $f >> Make-target
+ fi
+done
+
+# Ensure the language build subdirectories exist.
+
+for subdir in . $subdirs
+do
+ if [ $subdir != . ]
+ then
+ test -d $subdir || mkdir $subdir
+ fi
+done
+
+# Now copy each language's Make-lang.in file to Make-lang.
+
+rm -f Make-lang
+touch Make-lang
+
+for subdir in . $subdirs
+do
+ if [ $subdir != . ]
+ then
+ cat $srcdir/$subdir/Make-lang.in >> Make-lang
+ fi
+done
diff --git a/contrib/gcc/configure.in b/contrib/gcc/configure.in
new file mode 100644
index 0000000..a943830
--- /dev/null
+++ b/contrib/gcc/configure.in
@@ -0,0 +1,3833 @@
+# configure.in for GNU CC
+# Process this file with autoconf to generate a configuration script.
+
+# Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+#This file is part of GNU CC.
+
+#GNU CC 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, or (at your option)
+#any later version.
+
+#GNU CC 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 GNU CC; see the file COPYING. If not, write to
+#the Free Software Foundation, 59 Temple Place - Suite 330,
+#Boston, MA 02111-1307, USA.
+
+# Initialization and defaults
+AC_INIT(tree.c)
+AC_CONFIG_HEADER(auto-host.h:config.in)
+
+remove=rm
+hard_link=ln
+symbolic_link='ln -s'
+copy=cp
+
+# Check for additional parameters
+
+# With GNU ld
+AC_ARG_WITH(gnu-ld,
+[ --with-gnu-ld arrange to work with GNU ld.],
+gnu_ld_flag="$with_gnu_ld",
+gnu_ld_flag=no)
+
+# With GNU as
+AC_ARG_WITH(gnu-as,
+[ --with-gnu-as arrange to work with GNU as.],
+gas_flag="$with_gnu_as",
+gas_flag=no)
+
+# With stabs
+AC_ARG_WITH(stabs,
+[ --with-stabs arrange to use stabs instead of host debug format.],
+stabs="$with_stabs",
+stabs=no)
+
+# With ELF
+AC_ARG_WITH(elf,
+[ --with-elf arrange to use ELF instead of host debug format.],
+elf="$with_elf",
+elf=no)
+
+# Specify the local prefix
+local_prefix=
+AC_ARG_WITH(local-prefix,
+[ --with-local-prefix=DIR specifies directory to put local include.],
+[case "${withval}" in
+yes) AC_MSG_ERROR(bad value ${withval} given for local include directory prefix) ;;
+no) ;;
+*) local_prefix=$with_local_prefix ;;
+esac])
+
+# Default local prefix if it is empty
+if [[ x$local_prefix = x ]]; then
+ local_prefix=/usr/local
+fi
+
+gxx_include_dir=
+# Specify the g++ header file directory
+AC_ARG_WITH(gxx-include-dir,
+[ --with-gxx-include-dir=DIR
+ specifies directory to put g++ header files.],
+[case "${withval}" in
+yes) AC_MSG_ERROR(bad value ${withval} given for g++ include directory) ;;
+no) ;;
+*) gxx_include_dir=$with_gxx_include_dir ;;
+esac])
+
+if test x${gxx_include_dir} = x; then
+ if test x${enable_version_specific_runtime_libs} = xyes; then
+ gxx_include_dir='${libsubdir}/include/g++'
+ else
+ gxx_include_dir='${prefix}/include/g++'
+ fi
+fi
+
+# Enable expensive internal checks
+AC_ARG_ENABLE(checking,
+[ --enable-checking enable expensive run-time checks.],
+[case "${enableval}" in
+yes) AC_DEFINE(ENABLE_CHECKING) ;;
+no) ;;
+*) AC_MSG_ERROR(bad value ${enableval} given for checking option) ;;
+esac])
+
+# Enable use of cpplib for C.
+cpp_main=cccp
+AC_ARG_ENABLE(c-cpplib,
+[ --enable-c-cpplib Use cpplib for C.],
+if [[[ x$enable_c_cpplib != xno ]]]; then
+ extra_c_objs="${extra_c_objs} cpplib.o cppexp.o cpphash.o cpperror.o"
+ extra_c_objs="${extra_c_objs} prefix.o"
+ extra_cxx_objs="${extra_cxx_objs} ../cpplib.o ../cppexp.o ../cpphash.o ../cpperror.o ../prefix.o"
+ extra_c_flags=-DUSE_CPPLIB=1
+ cpp_main=cppmain
+fi)
+
+# Enable Haifa scheduler.
+AC_ARG_ENABLE(haifa,
+[ --enable-haifa Use the experimental scheduler.
+ --disable-haifa Don't use the experimental scheduler for the
+ targets which normally enable it.])
+# Fast fixincludes
+#
+# This is a work in progress...
+AC_ARG_WITH(fast-fixincludes,
+[ --with-fast-fixincludes Use a faster fixinclude program. Experimental],
+fast_fixinc="$with_fast_fixincludes",
+fast_fixinc=no)
+
+# Enable threads
+# Pass with no value to take the default
+# Pass with a value to specify a thread package
+AC_ARG_ENABLE(threads,
+[ --enable-threads enable thread usage for target GCC.
+ --enable-threads=LIB use LIB thread package for target GCC.],
+if [[[ x$enable_threads = xno ]]]; then
+ enable_threads=''
+fi,
+enable_threads='')
+
+enable_threads_flag=$enable_threads
+# Check if a valid thread package
+case x${enable_threads_flag} in
+ x | xno)
+ # No threads
+ target_thread_file='single'
+ ;;
+ xyes)
+ # default
+ target_thread_file=''
+ ;;
+ xdecosf1 | xirix | xmach | xos2 | xposix | xpthreads | xsingle | \
+ xsolaris | xwin32 | xdce | xvxworks)
+ target_thread_file=$enable_threads_flag
+ ;;
+ *)
+ echo "$enable_threads is an unknown thread package" 1>&2
+ exit 1
+ ;;
+esac
+
+# Determine the host, build, and target systems
+AC_CANONICAL_SYSTEM
+
+# Find the native compiler
+AC_PROG_CC
+AC_PROG_MAKE_SET
+
+# Find some useful tools
+AC_PROG_AWK
+AC_PROG_LEX
+GCC_PROG_LN
+GCC_PROG_LN_S
+GCC_C_VOLATILE
+AC_PROG_RANLIB
+AC_PROG_YACC
+EGCS_PROG_INSTALL
+
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_CHECK_HEADERS(limits.h stddef.h string.h strings.h stdlib.h time.h fcntl.h unistd.h stab.h sys/file.h sys/time.h sys/resource.h sys/param.h sys/times.h wait.h sys/wait.h)
+
+# Check for thread headers.
+AC_CHECK_HEADER(thread.h, [have_thread_h=yes], [have_thread_h=])
+AC_CHECK_HEADER(pthread.h, [have_pthread_h=yes], [have_pthread_h=])
+
+# See if the system preprocessor understands the ANSI C preprocessor
+# stringification operator.
+AC_MSG_CHECKING(whether cpp understands the stringify operator)
+AC_CACHE_VAL(gcc_cv_c_have_stringify,
+[AC_TRY_COMPILE(,
+[#define S(x) #x
+char *test = S(foo);],
+gcc_cv_c_have_stringify=yes, gcc_cv_c_have_stringify=no)])
+AC_MSG_RESULT($gcc_cv_c_have_stringify)
+if test $gcc_cv_c_have_stringify = yes; then
+ AC_DEFINE(HAVE_CPP_STRINGIFY)
+fi
+
+# Use <inttypes.h> only if it exists,
+# doesn't clash with <sys/types.h>, and declares intmax_t.
+AC_MSG_CHECKING(for inttypes.h)
+AC_CACHE_VAL(gcc_cv_header_inttypes_h,
+[AC_TRY_COMPILE(
+ [#include <sys/types.h>
+#include <inttypes.h>],
+ [intmax_t i = -1;],
+ [gcc_cv_header_inttypes_h=yes],
+ gcc_cv_header_inttypes_h=no)])
+AC_MSG_RESULT($gcc_cv_header_inttypes_h)
+if test $gcc_cv_header_inttypes_h = yes; then
+ AC_DEFINE(HAVE_INTTYPES_H)
+fi
+
+AC_CHECK_FUNCS(strtoul bsearch strerror putenv popen bcopy bzero bcmp \
+ index rindex strchr strrchr kill getrlimit setrlimit atoll atoq \
+ sysconf isascii gettimeofday)
+
+GCC_FUNC_VFPRINTF_DOPRNT
+GCC_FUNC_PRINTF_PTR
+
+GCC_NEED_DECLARATIONS(malloc realloc calloc free bcopy bzero bcmp \
+ index rindex getenv atol sbrk abort atof strerror getcwd getwd)
+
+GCC_NEED_DECLARATIONS(getrlimit setrlimit, [
+#include <sys/types.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+])
+
+AC_DECL_SYS_SIGLIST
+
+# File extensions
+manext='.1'
+objext='.o'
+AC_SUBST(manext)
+AC_SUBST(objext)
+
+build_xm_file=
+build_xm_defines=
+build_install_headers_dir=install-headers-tar
+build_exeext=
+host_xm_file=
+host_xm_defines=
+host_xmake_file=
+host_truncate_target=
+host_exeext=
+cpp_install_dir=
+
+# Decode the host machine, then the target machine.
+# For the host machine, we save the xm_file variable as host_xm_file;
+# then we decode the target machine and forget everything else
+# that came from the host machine.
+for machine in $build $host $target; do
+
+ out_file=
+ xmake_file=
+ tmake_file=
+ extra_headers=
+ extra_passes=
+ extra_parts=
+ extra_programs=
+ extra_objs=
+ extra_host_objs=
+ extra_gcc_objs=
+ xm_defines=
+ float_format=
+ # Set this to force installation and use of collect2.
+ use_collect2=
+ # Set this to override the default target model.
+ target_cpu_default=
+ # Set this to control which fixincludes program to use.
+ if [[ x$fast_fixinc != xyes ]] ; then
+ fixincludes=fixincludes
+ else fixincludes=fixinc.sh ; fi
+ # Set this to control how the header file directory is installed.
+ install_headers_dir=install-headers-tar
+ # Set this to a non-empty list of args to pass to cpp if the target
+ # wants its .md file passed through cpp.
+ md_cppflags=
+ # Set this if directory names should be truncated to 14 characters.
+ truncate_target=
+ # Set this if gdb needs a dir command with `dirname $out_file`
+ gdb_needs_out_file_path=
+ # Set this if the build machine requires executables to have a
+ # file name suffix.
+ exeext=
+ # Set this to control which thread package will be used.
+ thread_file=
+ # Reinitialize these from the flag values every loop pass, since some
+ # configure entries modify them.
+ gas="$gas_flag"
+ gnu_ld="$gnu_ld_flag"
+ enable_threads=$enable_threads_flag
+
+ # Set default cpu_type, tm_file and xm_file so it can be updated in
+ # each machine entry.
+ cpu_type=`echo $machine | sed 's/-.*$//'`
+ case $machine in
+ alpha*-*-*)
+ cpu_type=alpha
+ ;;
+ arm*-*-*)
+ cpu_type=arm
+ ;;
+ c*-convex-*)
+ cpu_type=convex
+ ;;
+ i[[34567]]86-*-*)
+ cpu_type=i386
+ ;;
+ hppa*-*-*)
+ cpu_type=pa
+ ;;
+ m68000-*-*)
+ cpu_type=m68k
+ ;;
+ mips*-*-*)
+ cpu_type=mips
+ ;;
+ powerpc*-*-*)
+ cpu_type=rs6000
+ ;;
+ pyramid-*-*)
+ cpu_type=pyr
+ ;;
+ sparc*-*-*)
+ cpu_type=sparc
+ ;;
+ esac
+
+ tm_file=${cpu_type}/${cpu_type}.h
+ xm_file=${cpu_type}/xm-${cpu_type}.h
+
+ # Common parts for linux-gnu and openbsd systems
+ case $machine in
+ *-*-linux-gnu*)
+ xm_defines="HAVE_ATEXIT POSIX BSTRING"
+ ;;
+ *-*-openbsd*)
+ tm_file=${cpu_type}/openbsd.h
+ # On OpenBSD systems, the headers are okay
+ fixincludes=Makefile.in
+ tmake_file="t-libc-ok t-openbsd"
+ # avoid surprises, always provide an xm-openbsd file
+ xm_file=${cpu_type}/xm-openbsd.h
+ if test x$enable_threads = xyes; then
+ thread_file='posix'
+ tmake_file="${tmake_file} t-openbsd-thread"
+ fi
+ ;;
+ esac
+
+ case $machine in
+ # Support site-specific machine types.
+ *local*)
+ cpu_type=`echo $machine | sed -e 's/-.*//'`
+ rest=`echo $machine | sed -e "s/$cpu_type-//"`
+ xm_file=${cpu_type}/xm-$rest.h
+ tm_file=${cpu_type}/$rest.h
+ if [[ -f $srcdir/config/${cpu_type}/x-$rest ]] ; \
+ then xmake_file=${cpu_type}/x-$rest; \
+ else true; \
+ fi
+ if [[ -f $srcdir/config/${cpu_type}/t-$rest ]] ; \
+ then tmake_file=${cpu_type}/t-$rest; \
+ else true; \
+ fi
+ ;;
+ 1750a-*-*)
+ ;;
+ a29k-*-bsd* | a29k-*-sym1*)
+ tm_file="${tm_file} a29k/unix.h"
+ xm_defines=USG
+ xmake_file=a29k/x-unix
+ use_collect2=yes
+ ;;
+ a29k-*-udi | a29k-*-coff)
+ tm_file="${tm_file} dbxcoff.h a29k/udi.h"
+ tmake_file=a29k/t-a29kbare
+ ;;
+ a29k-wrs-vxworks*)
+ tm_file="${tm_file} dbxcoff.h a29k/udi.h a29k/vx29k.h"
+ tmake_file=a29k/t-vx29k
+ extra_parts="crtbegin.o crtend.o"
+ thread_file='vxworks'
+ ;;
+ a29k-*-*) # Default a29k environment.
+ use_collect2=yes
+ ;;
+ alpha*-*-linux-gnuecoff*)
+ tm_file="${tm_file} alpha/linux-ecoff.h alpha/linux.h"
+ target_cpu_default="MASK_GAS"
+ gas=no
+ xmake_file=none
+ gas=yes gnu_ld=yes
+ ;;
+ alpha*-*-linux-gnulibc1*)
+ tm_file="${tm_file} alpha/elf.h alpha/linux.h alpha/linux-elf.h"
+ target_cpu_default="MASK_GAS"
+ tmake_file="t-linux t-linux-gnulibc1 alpha/t-linux alpha/t-crtbe"
+ extra_parts="crtbegin.o crtend.o"
+ fixincludes=fixinc.wrap
+ xmake_file=none
+ gas=yes gnu_ld=yes
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='posix'
+ fi
+ ;;
+ alpha*-*-linux-gnu*)
+ tm_file="${tm_file} alpha/elf.h alpha/linux.h alpha/linux-elf.h"
+ target_cpu_default="MASK_GAS"
+ tmake_file="t-linux alpha/t-linux alpha/t-crtbe"
+ extra_parts="crtbegin.o crtend.o"
+ xmake_file=none
+ fixincludes=Makefile.in
+ gas=yes gnu_ld=yes
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='posix'
+ fi
+ ;;
+ alpha*-*-netbsd*)
+ tm_file="${tm_file} alpha/elf.h alpha/netbsd.h alpha/netbsdl-elf.h"
+ xm_file="xm-netbsd.h ${xm_file}"
+ target_cpu_default="MASK_GAS"
+ tmake_file="alpha/t-crtbe"
+ extra_parts="crtbegin.o crtend.o"
+ xmake_file=none
+ fixincludes=fixinc.wrap
+ gas=yes gnu_ld=yes
+ ;;
+
+ alpha*-*-openbsd*)
+ # default x-alpha is only appropriate for dec-osf.
+ target_cpu_default="MASK_GAS"
+ xmake_file=none
+ ;;
+
+ alpha*-dec-osf*)
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ if [[ x$gas != xyes ]]
+ then
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ use_collect2=yes
+ case $machine in
+ *-*-osf1*)
+ tm_file="${tm_file} alpha/osf.h alpha/osf12.h alpha/osf2or3.h"
+ ;;
+ *-*-osf[[23]]*)
+ tm_file="${tm_file} alpha/osf.h alpha/osf2or3.h"
+ ;;
+ *-*-osf4*)
+ tm_file="${tm_file} alpha/osf.h"
+ # Some versions of OSF4 (specifically X4.0-9 296.7) have
+ # a broken tar, so we use cpio instead.
+ install_headers_dir=install-headers-cpio
+ ;;
+ esac
+ case $machine in
+ *-*-osf4.0[[b-z]] | *-*-osf4.[[1-9]]*)
+ target_cpu_default=MASK_SUPPORT_ARCH
+ ;;
+ esac
+ ;;
+ alpha*-*-vxworks*)
+ tm_file="${tm_file} dbx.h alpha/vxworks.h"
+ if [ x$gas != xyes ]
+ then
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ use_collect2=yes
+ ;;
+ alpha*-*-winnt*)
+ tm_file="${tm_file} alpha/win-nt.h"
+ xm_file="${xm_file} config/winnt/xm-winnt.h alpha/xm-winnt.h"
+ tmake_file=t-libc-ok
+ xmake_file=winnt/x-winnt
+ extra_host_objs=oldnames.o
+ extra_gcc_objs="spawnv.o oldnames.o"
+ fixincludes=fixinc.winnt
+ if [[ x$gnu_ld != xyes ]]
+ then
+ extra_programs=ld.exe
+ fi
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='win32'
+ fi
+ ;;
+ alpha*-dec-vms*)
+ tm_file=alpha/vms.h
+ xm_file="${xm_file} alpha/xm-vms.h"
+ tmake_file=alpha/t-vms
+ fixincludes=Makefile.in
+ ;;
+ arc-*-elf*)
+ extra_parts="crtinit.o crtfini.o"
+ ;;
+ arm-*-coff* | armel-*-coff*)
+ tm_file=arm/coff.h
+ tmake_file=arm/t-bare
+ ;;
+ arm-*-riscix1.[[01]]*) # Acorn RISC machine (early versions)
+ tm_file=arm/riscix1-1.h
+ use_collect2=yes
+ ;;
+ arm-*-riscix*) # Acorn RISC machine
+ if [[ x$gas = xyes ]]
+ then
+ tm_file=arm/rix-gas.h
+ else
+ tm_file=arm/riscix.h
+ fi
+ xmake_file=arm/x-riscix
+ tmake_file=arm/t-riscix
+ use_collect2=yes
+ ;;
+ arm-semi-aout | armel-semi-aout)
+ tm_file=arm/semi.h
+ tmake_file=arm/t-semi
+ fixincludes=Makefile.in # There is nothing to fix
+ ;;
+ arm-semi-aof | armel-semi-aof)
+ tm_file=arm/semiaof.h
+ tmake_file=arm/t-semiaof
+ fixincludes=Makefile.in # There is nothing to fix
+ ;;
+ arm*-*-netbsd*)
+ tm_file=arm/netbsd.h
+ xm_file="xm-netbsd.h ${xm_file}"
+ tmake_file="t-netbsd arm/t-netbsd"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ ;;
+ arm-*-linux-gnuaout*) # ARM GNU/Linux
+ cpu_type=arm
+ xmake_file=x-linux
+ tm_file=arm/linux-gas.h
+ tmake_file=arm/t-linux
+ fixincludes=Makefile.in
+ gnu_ld=yes
+ ;;
+ arm-*-aout)
+ tm_file=arm/aout.h
+ tmake_file=arm/t-bare
+ ;;
+ c1-convex-*) # Convex C1
+ target_cpu_default=1
+ use_collect2=yes
+ fixincludes=Makefile.in
+ ;;
+ c2-convex-*) # Convex C2
+ target_cpu_default=2
+ use_collect2=yes
+ fixincludes=Makefile.in
+ ;;
+ c32-convex-*)
+ target_cpu_default=4
+ use_collect2=yes
+ fixincludes=Makefile.in
+ ;;
+ c34-convex-*)
+ target_cpu_default=8
+ use_collect2=yes
+ fixincludes=Makefile.in
+ ;;
+ c38-convex-*)
+ target_cpu_default=16
+ use_collect2=yes
+ fixincludes=Makefile.in
+ ;;
+ clipper-intergraph-clix*)
+ tm_file="${tm_file} svr3.h clipper/clix.h"
+ xm_file=clipper/xm-clix.h
+ xmake_file=clipper/x-clix
+ extra_headers=va-clipper.h
+ extra_parts="crtbegin.o crtend.o"
+ install_headers_dir=install-headers-cpio
+ ;;
+ dsp16xx-*)
+ ;;
+ elxsi-elxsi-*)
+ use_collect2=yes
+ ;;
+# This hasn't been upgraded to GCC 2.
+# fx80-alliant-*) # Alliant FX/80
+# ;;
+ h8300-*-*)
+ float_format=i32
+ ;;
+ hppa*-*-openbsd*)
+ target_cpu_default="MASK_SNAKE"
+ tmake_file=pa/t-openbsd
+ ;;
+ hppa1.1-*-pro*)
+ tm_file="pa/pa-pro.h ${tm_file} pa/pa-pro-end.h libgloss.h"
+ xm_file=pa/xm-papro.h
+ tmake_file=pa/t-pro
+ ;;
+ hppa1.1-*-osf*)
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-osf.h"
+ use_collect2=yes
+ fixincludes=Makefile.in
+ ;;
+ hppa1.1-*-rtems*)
+ tm_file="pa/pa-pro.h ${tm_file} pa/pa-pro-end.h libgloss.h pa/rtems.h"
+ xm_file=pa/xm-papro.h
+ tmake_file=pa/t-pro
+ ;;
+ hppa1.0-*-osf*)
+ tm_file="${tm_file} pa/pa-osf.h"
+ use_collect2=yes
+ fixincludes=Makefile.in
+ ;;
+ hppa1.1-*-bsd*)
+ target_cpu_default=1
+ use_collect2=yes
+ fixincludes=Makefile.in
+ ;;
+ hppa1.0-*-bsd*)
+ use_collect2=yes
+ fixincludes=Makefile.in
+ ;;
+ hppa1.0-*-hpux7*)
+ tm_file="pa/pa-oldas.h ${tm_file} pa/pa-hpux7.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/gas.h"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.0-*-hpux8.0[[0-2]]*)
+ tm_file="${tm_file} pa/pa-hpux.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ else
+ tm_file="pa/pa-oldas.h ${tm_file}"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.1-*-hpux8.0[[0-2]]*)
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-hpux.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ else
+ tm_file="pa/pa-oldas.h ${tm_file}"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.1-*-hpux8*)
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-hpux.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.0-*-hpux8*)
+ tm_file="${tm_file} pa/pa-hpux.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.1-*-hpux10*)
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hpux10.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ tmake_file=pa/t-pa
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ if [[ x$enable_threads = x ]]; then
+ enable_threads=$have_pthread_h
+ fi
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='dce'
+ tmake_file="${tmake_file} pa/t-dce-thr"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.0-*-hpux10*)
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hpux10.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ tmake_file=pa/t-pa
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ if [[ x$enable_threads = x ]]; then
+ enable_threads=$have_pthread_h
+ fi
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='dce'
+ tmake_file="${tmake_file} pa/t-dce-thr"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.1-*-hpux*)
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hpux9.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.0-*-hpux*)
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hpux9.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.1-*-hiux*)
+ target_cpu_default=1
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hiux.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa1.0-*-hiux*)
+ tm_file="${tm_file} pa/pa-hpux.h pa/pa-hiux.h"
+ xm_file=pa/xm-pahpux.h
+ xmake_file=pa/x-pa-hpux
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} pa/pa-gas.h"
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ ;;
+ hppa*-*-lites*)
+ target_cpu_default=1
+ use_collect2=yes
+ fixincludes=Makefile.in
+ ;;
+ i370-*-mvs*)
+ ;;
+ i[[34567]]86-ibm-aix*) # IBM PS/2 running AIX
+ if [[ x$gas = xyes ]]
+ then
+ tm_file=i386/aix386.h
+ extra_parts="crtbegin.o crtend.o"
+ tmake_file=i386/t-crtstuff
+ else
+ tm_file=i386/aix386ng.h
+ use_collect2=yes
+ fi
+ xm_file="xm-alloca.h i386/xm-aix.h ${xm_file}"
+ xm_defines=USG
+ xmake_file=i386/x-aix
+ ;;
+ i[[34567]]86-ncr-sysv4*) # NCR 3000 - ix86 running system V.4
+ xm_file="xm-siglist.h xm-alloca.h ${xm_file}"
+ xm_defines="USG POSIX SMALL_ARG_MAX"
+ xmake_file=i386/x-ncr3000
+ if [[ x$stabs = xyes -a x$gas = xyes ]]
+ then
+ tm_file=i386/sysv4gdb.h
+ else
+ tm_file=i386/sysv4.h
+ fi
+ extra_parts="crtbegin.o crtend.o"
+ tmake_file=i386/t-crtpic
+ ;;
+ i[[34567]]86-next-*)
+ tm_file=i386/next.h
+ xm_file=i386/xm-next.h
+ tmake_file=i386/t-next
+ xmake_file=i386/x-next
+ extra_objs=nextstep.o
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='mach'
+ fi
+ ;;
+ i[[34567]]86-sequent-bsd*) # 80386 from Sequent
+ use_collect2=yes
+ if [[ x$gas = xyes ]]
+ then
+ tm_file=i386/seq-gas.h
+ else
+ tm_file=i386/sequent.h
+ fi
+ ;;
+ i[[34567]]86-sequent-ptx1*)
+ xm_defines="USG SVR3"
+ xmake_file=i386/x-sysv3
+ tm_file=i386/seq-sysv3.h
+ tmake_file=i386/t-crtstuff
+ fixincludes=fixinc.ptx
+ extra_parts="crtbegin.o crtend.o"
+ install_headers_dir=install-headers-cpio
+ ;;
+ i[[34567]]86-sequent-ptx2* | i[[34567]]86-sequent-sysv3*)
+ xm_defines="USG SVR3"
+ xmake_file=i386/x-sysv3
+ tm_file=i386/seq2-sysv3.h
+ tmake_file=i386/t-crtstuff
+ extra_parts="crtbegin.o crtend.o"
+ fixincludes=fixinc.ptx
+ install_headers_dir=install-headers-cpio
+ ;;
+ i[[34567]]86-sequent-ptx4* | i[[34567]]86-sequent-sysv4*)
+ xm_file="xm-siglist.h xm-alloca.h ${xm_file}"
+ xm_defines="USG POSIX SMALL_ARG_MAX"
+ xmake_file=x-svr4
+ tm_file=i386/ptx4-i.h
+ tmake_file=t-svr4
+ extra_parts="crtbegin.o crtend.o"
+ fixincludes=fixinc.ptx
+ install_headers_dir=install-headers-cpio
+ ;;
+ i386-sun-sunos*) # Sun i386 roadrunner
+ xm_defines=USG
+ tm_file=i386/sun.h
+ use_collect2=yes
+ ;;
+ i[[34567]]86-wrs-vxworks*)
+ tm_file=i386/vxi386.h
+ tmake_file=i386/t-i386bare
+ ;;
+ i[[34567]]86-*-aout*)
+ tm_file=i386/i386-aout.h
+ tmake_file=i386/t-i386bare
+ ;;
+ i[[34567]]86-*-bsdi* | i[[34567]]86-*-bsd386*)
+ tm_file=i386/bsd386.h
+# tmake_file=t-libc-ok
+ ;;
+ i[[34567]]86-*-bsd*)
+ tm_file=i386/386bsd.h
+# tmake_file=t-libc-ok
+# Next line turned off because both 386BSD and BSD/386 use GNU ld.
+# use_collect2=yes
+ ;;
+ i[[34567]]86-*-freebsdelf*)
+ tm_file="i386/i386.h i386/att.h linux.h i386/freebsd-elf.h i386/perform.h"
+ # On FreeBSD, the headers are already ok, except for math.h.
+ fixincludes=fixinc.wrap
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ tmake_file=i386/t-freebsd
+ gas=yes
+ gnu_ld=yes
+ stabs=yes
+ ;;
+ i[[34567]]86-*-freebsd*)
+ tm_file=i386/freebsd.h
+ # On FreeBSD, the headers are already ok, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=i386/t-freebsd
+ ;;
+ i[[34567]]86-*-netbsd*)
+ tm_file=i386/netbsd.h
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ ;;
+ i[[34567]]86-*-openbsd*)
+ # Remove when the math emulator is fixed
+ target_cpu_default="MASK_NO_FANCY_MATH_387"
+ # we need collect2 until our bug is fixed...
+ use_collect2=yes
+ ;;
+ i[[34567]]86-*-coff*)
+ tm_file=i386/i386-coff.h
+ tmake_file=i386/t-i386bare
+ ;;
+ i[[34567]]86-*-isc*) # 80386 running ISC system
+ xm_file="${xm_file} i386/xm-isc.h"
+ xm_defines="USG SVR3"
+ case $machine in
+ i[[34567]]86-*-isc[[34]]*)
+ xmake_file=i386/x-isc3
+ ;;
+ *)
+ xmake_file=i386/x-isc
+ ;;
+ esac
+ if [[ x$gas = xyes -a x$stabs = xyes ]]
+ then
+ tm_file=i386/iscdbx.h
+ tmake_file=i386/t-svr3dbx
+ extra_parts="svr3.ifile svr3z.ifile"
+ else
+ tm_file=i386/isccoff.h
+ tmake_file=i386/t-crtstuff
+ extra_parts="crtbegin.o crtend.o"
+ fi
+ install_headers_dir=install-headers-cpio
+ ;;
+ i[[34567]]86-*-linux-gnuoldld*) # Intel 80386's running GNU/Linux
+ # with a.out format using
+ # pre BFD linkers
+ xmake_file=x-linux-aout
+ tmake_file="t-linux-aout i386/t-crtstuff"
+ tm_file=i386/linux-oldld.h
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ float_format=i386
+ ;;
+ i[[34567]]86-*-linux-gnuaout*) # Intel 80386's running GNU/Linux
+ # with a.out format
+ xmake_file=x-linux-aout
+ tmake_file="t-linux-aout i386/t-crtstuff"
+ tm_file=i386/linux-aout.h
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ float_format=i386
+ ;;
+ i[[34567]]86-*-linux-gnulibc1) # Intel 80386's running GNU/Linux
+ # with ELF format using the
+ # GNU/Linux C library 5
+ xmake_file=x-linux
+ tm_file=i386/linux.h
+ tmake_file="t-linux t-linux-gnulibc1 i386/t-crtstuff"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ float_format=i386
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='single'
+ fi
+ ;;
+ i[[34567]]86-*-linux-gnu*) # Intel 80386's running GNU/Linux
+ # with ELF format using glibc 2
+ # aka GNU/Linux C library 6
+ xmake_file=x-linux
+ tm_file=i386/linux.h
+ tmake_file="t-linux i386/t-crtstuff"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ float_format=i386
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='posix'
+ fi
+ ;;
+ i[[34567]]86-*-gnu*)
+ float_format=i386
+ ;;
+ i[[34567]]86-go32-msdos | i[[34567]]86-*-go32*)
+ xm_file=i386/xm-go32.h
+ tm_file=i386/go32.h
+ tmake_file=i386/t-go32
+ ;;
+ i[[34567]]86-pc-msdosdjgpp*)
+ xm_file=i386/xm-go32.h
+ tm_file=i386/go32.h
+ tmake_file=i386/t-go32
+ gnu_ld=yes
+ gas=yes
+ ;;
+ i[[34567]]86-moss-msdos* | i[[34567]]86-*-moss*)
+ tm_file=i386/moss.h
+ tmake_file=t-libc-ok
+ fixincludes=Makefile.in
+ gnu_ld=yes
+ gas=yes
+ ;;
+ i[[34567]]86-*-lynxos*)
+ if [[ x$gas = xyes ]]
+ then
+ tm_file=i386/lynx.h
+ else
+ tm_file=i386/lynx-ng.h
+ fi
+ xm_file=i386/xm-lynx.h
+ tmake_file=i386/t-i386bare
+ xmake_file=x-lynx
+ ;;
+ i[[34567]]86-*-mach*)
+ tm_file=i386/mach.h
+# tmake_file=t-libc-ok
+ use_collect2=yes
+ ;;
+ i[[34567]]86-*-osfrose*) # 386 using OSF/rose
+ if [[ x$elf = xyes ]]
+ then
+ tm_file=i386/osfelf.h
+ use_collect2=
+ else
+ tm_file=i386/osfrose.h
+ use_collect2=yes
+ fi
+ xm_file="i386/xm-osf.h ${xm_file}"
+ xmake_file=i386/x-osfrose
+ tmake_file=i386/t-osf
+ extra_objs=halfpic.o
+ ;;
+ i[[34567]]86-go32-rtems*)
+ cpu_type=i386
+ xm_file=i386/xm-go32.h
+ tm_file=i386/go32-rtems.h
+ tmake_file="i386/t-go32 t-rtems"
+ ;;
+ i[[34567]]86-*-rtemself*)
+ cpu_type=i386
+ tm_file=i386/rtemself.h
+ tmake_file="i386/t-i386bare t-rtems"
+ ;;
+ i[[34567]]86-*-rtems*)
+ cpu_type=i386
+ tm_file=i386/rtems.h
+ tmake_file="i386/t-i386bare t-rtems"
+ ;;
+ i[[34567]]86-*-sco3.2v5*) # 80386 running SCO Open Server 5
+ xm_file="xm-siglist.h xm-alloca.h ${xm_file} i386/xm-sco5.h"
+ xm_defines="USG SVR3"
+ xmake_file=i386/x-sco5
+ fixincludes=fixinc.sco
+ install_headers_dir=install-headers-cpio
+ tm_file=i386/sco5.h
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="i386/sco5gas.h ${tm_file}"
+ tmake_file=i386/t-sco5gas
+ else
+ tmake_file=i386/t-sco5
+ fi
+ extra_parts="crti.o crtbegin.o crtend.o crtbeginS.o crtendS.o"
+ ;;
+ i[[34567]]86-*-sco3.2v4*) # 80386 running SCO 3.2v4 system
+ xm_file="${xm_file} i386/xm-sco.h"
+ xm_defines="USG SVR3 BROKEN_LDEXP SMALL_ARG_MAX NO_SYS_SIGLIST"
+ xmake_file=i386/x-sco4
+ fixincludes=fixinc.sco
+ install_headers_dir=install-headers-cpio
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file=i386/sco4dbx.h
+ tmake_file=i386/t-svr3dbx
+ extra_parts="svr3.ifile svr3z.rfile"
+ else
+ tm_file=i386/sco4.h
+ tmake_file=i386/t-crtstuff
+ extra_parts="crtbegin.o crtend.o"
+ fi
+ truncate_target=yes
+ ;;
+ i[[34567]]86-*-sco*) # 80386 running SCO system
+ xm_file=i386/xm-sco.h
+ xmake_file=i386/x-sco
+ install_headers_dir=install-headers-cpio
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file=i386/scodbx.h
+ tmake_file=i386/t-svr3dbx
+ extra_parts="svr3.ifile svr3z.rfile"
+ else
+ tm_file=i386/sco.h
+ extra_parts="crtbegin.o crtend.o"
+ tmake_file=i386/t-crtstuff
+ fi
+ truncate_target=yes
+ ;;
+ i[[34567]]86-*-solaris2*)
+ xm_file="xm-siglist.h xm-alloca.h ${xm_file}"
+ xm_defines="USG POSIX SMALL_ARG_MAX"
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file=i386/sol2dbg.h
+ else
+ tm_file=i386/sol2.h
+ fi
+ tmake_file=i386/t-sol2
+ extra_parts="crt1.o crti.o crtn.o gcrt1.o gmon.o crtbegin.o crtend.o"
+ xmake_file=x-svr4
+ case $machine in
+ *-*-solaris2.[[0-4]])
+ fixincludes=fixinc.svr4;;
+ *)
+ fixincludes=fixinc.wrap;;
+ esac
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='solaris'
+ fi
+ ;;
+ i[[34567]]86-*-sysv5*) # Intel x86 on System V Release 5
+ xm_file="xm-alloca.h xm-siglist.h ${xm_file}"
+ xm_defines="USG POSIX"
+ tm_file=i386/sysv4.h
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ tmake_file=i386/t-crtpic
+ xmake_file=x-svr4
+ extra_parts="crtbegin.o crtend.o"
+ fixincludes=fixinc.svr4
+ ;;
+ i[[34567]]86-*-sysv4*) # Intel 80386's running system V.4
+ xm_file="xm-siglist.h xm-alloca.h ${xm_file}"
+ xm_defines="USG POSIX SMALL_ARG_MAX"
+ tm_file=i386/sysv4.h
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ tmake_file=i386/t-crtpic
+ xmake_file=x-svr4
+ extra_parts="crtbegin.o crtend.o"
+ ;;
+ i[[34567]]86-*-osf1*) # Intel 80386's running OSF/1 1.3+
+ cpu_type=i386
+ xm_file="${xm_file} xm-svr4.h i386/xm-sysv4.h i386/xm-osf1elf.h"
+ xm_defines="USE_C_ALLOCA SMALL_ARG_MAX"
+ fixincludes=Makefile.in #Don't do it on OSF/1
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file=i386/osf1elfgdb.h
+ else
+ tm_file=i386/osf1elf.h
+ fi
+ tmake_file=i386/t-osf1elf
+ xmake_file=i386/x-osf1elf
+ extra_parts="crti.o crtn.o crtbegin.o crtend.o"
+ ;;
+ i[[34567]]86-*-sysv*) # Intel 80386's running system V
+ xm_defines="USG SVR3"
+ xmake_file=i386/x-sysv3
+ if [[ x$gas = xyes ]]
+ then
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file=i386/svr3dbx.h
+ tmake_file=i386/t-svr3dbx
+ extra_parts="svr3.ifile svr3z.rfile"
+ else
+ tm_file=i386/svr3gas.h
+ extra_parts="crtbegin.o crtend.o"
+ tmake_file=i386/t-crtstuff
+ fi
+ else
+ tm_file=i386/sysv3.h
+ extra_parts="crtbegin.o crtend.o"
+ tmake_file=i386/t-crtstuff
+ fi
+ ;;
+ i386-*-vsta) # Intel 80386's running VSTa kernel
+ xm_file="${xm_file} i386/xm-vsta.h"
+ tm_file=i386/vsta.h
+ tmake_file=i386/t-vsta
+ xmake_file=i386/x-vsta
+ ;;
+ i[[34567]]86-*-pe | i[[34567]]86-*-cygwin32)
+ xm_file="${xm_file} i386/xm-cygwin32.h"
+ tmake_file=i386/t-cygwin32
+ tm_file=i386/cygwin32.h
+ xmake_file=i386/x-cygwin32
+ extra_objs=winnt.o
+ fixincludes=Makefile.in
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='win32'
+ fi
+ exeext=.exe
+ ;;
+ i[[34567]]86-*-mingw32*)
+ tm_file=i386/mingw32.h
+ xm_file="${xm_file} i386/xm-mingw32.h"
+ tmake_file="i386/t-cygwin32 i386/t-mingw32"
+ extra_objs=winnt.o
+ xmake_file=i386/x-cygwin32
+ fixincludes=Makefile.in
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='win32'
+ fi
+ exeext=.exe
+ case $machine in
+ *mingw32msv*)
+ ;;
+ *mingw32crt* | *mingw32*)
+ tm_file="${tm_file} i386/crtdll.h"
+ ;;
+ esac
+ ;;
+ i[[34567]]86-*-winnt3*)
+ tm_file=i386/win-nt.h
+ out_file=i386/i386.c
+ xm_file="xm-winnt.h ${xm_file}"
+ xmake_file=winnt/x-winnt
+ tmake_file=i386/t-winnt
+ extra_host_objs="winnt.o oldnames.o"
+ extra_gcc_objs="spawnv.o oldnames.o"
+ fixincludes=fixinc.winnt
+ if [[ x$gnu_ld != xyes ]]
+ then
+ extra_programs=ld.exe
+ fi
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='win32'
+ fi
+ ;;
+ i[[34567]]86-dg-dgux*)
+ xm_file="xm-alloca.h xm-siglist.h ${xm_file}"
+ xm_defines="USG POSIX"
+ out_file=i386/dgux.c
+ tm_file=i386/dgux.h
+ tmake_file=i386/t-dgux
+ xmake_file=i386/x-dgux
+ fixincludes=fixinc.dgux
+ install_headers_dir=install-headers-cpio
+ ;;
+ i860-alliant-*) # Alliant FX/2800
+ tm_file="${tm_file} svr4.h i860/sysv4.h i860/fx2800.h"
+ xm_file="${xm_file}"
+ xmake_file=i860/x-fx2800
+ tmake_file=i860/t-fx2800
+ extra_parts="crtbegin.o crtend.o"
+ ;;
+ i860-*-bsd*)
+ tm_file="${tm_file} i860/bsd.h"
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="${tm_file} i860/bsd-gas.h"
+ fi
+ use_collect2=yes
+ ;;
+ i860-*-mach*)
+ tm_file="${tm_file} i860/mach.h"
+ tmake_file=t-libc-ok
+ ;;
+ i860-*-osf*) # Intel Paragon XP/S, OSF/1AD
+ tm_file="${tm_file} svr3.h i860/paragon.h"
+ xm_defines="USG SVR3"
+ tmake_file=t-osf
+ ;;
+ i860-*-sysv3*)
+ tm_file="${tm_file} svr3.h i860/sysv3.h"
+ xm_defines="USG SVR3"
+ xmake_file=i860/x-sysv3
+ extra_parts="crtbegin.o crtend.o"
+ ;;
+ i860-*-sysv4*)
+ tm_file="${tm_file} svr4.h i860/sysv4.h"
+ xm_defines="USG SVR3"
+ xmake_file=i860/x-sysv4
+ tmake_file=t-svr4
+ extra_parts="crtbegin.o crtend.o"
+ ;;
+ i960-wrs-vxworks5 | i960-wrs-vxworks5.0*)
+ tm_file="${tm_file} i960/vx960.h"
+ tmake_file=i960/t-vxworks960
+ use_collect2=yes
+ thread_file='vxworks'
+ ;;
+ i960-wrs-vxworks5* | i960-wrs-vxworks)
+ tm_file="${tm_file} dbxcoff.h i960/i960-coff.h i960/vx960-coff.h"
+ tmake_file=i960/t-vxworks960
+ use_collect2=yes
+ thread_file='vxworks'
+ ;;
+ i960-wrs-vxworks*)
+ tm_file="${tm_file} i960/vx960.h"
+ tmake_file=i960/t-vxworks960
+ use_collect2=yes
+ thread_file='vxworks'
+ ;;
+ i960-*-coff*)
+ tm_file="${tm_file} dbxcoff.h i960/i960-coff.h libgloss.h"
+ tmake_file=i960/t-960bare
+ use_collect2=yes
+ ;;
+ i960-*-rtems)
+ tmake_file="i960/t-960bare t-rtems"
+ tm_file="${tm_file} dbxcoff.h i960/rtems.h"
+ use_collect2=yes
+ ;;
+ i960-*-*) # Default i960 environment.
+ use_collect2=yes
+ ;;
+ m32r-*-elf*)
+ extra_parts="crtinit.o crtfini.o"
+ ;;
+ m68000-convergent-sysv*)
+ tm_file=m68k/ctix.h
+ xm_file="m68k/xm-3b1.h ${xm_file}"
+ xm_defines=USG
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68000-hp-bsd*) # HP 9000/200 running BSD
+ tm_file=m68k/hp2bsd.h
+ xmake_file=m68k/x-hp2bsd
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68000-hp-hpux*) # HP 9000 series 300
+ xm_file="xm_alloca.h ${xm_file}"
+ xm_defines="USG NO_SYS_SIGLIST"
+ if [[ x$gas = xyes ]]
+ then
+ xmake_file=m68k/x-hp320g
+ tm_file=m68k/hp310g.h
+ else
+ xmake_file=m68k/x-hp320
+ tm_file=m68k/hp310.h
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68000-sun-sunos3*)
+ tm_file=m68k/sun2.h
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68000-sun-sunos4*)
+ tm_file=m68k/sun2o4.h
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68000-att-sysv*)
+ xm_file="m68k/xm-3b1.h ${xm_file}"
+ xm_defines=USG
+ if [[ x$gas = xyes ]]
+ then
+ tm_file=m68k/3b1g.h
+ else
+ tm_file=m68k/3b1.h
+ fi
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68k-apple-aux*) # Apple Macintosh running A/UX
+ xm_defines="USG AUX"
+ tmake_file=m68k/t-aux
+ install_headers_dir=install-headers-cpio
+ extra_headers=math-68881.h
+ extra_parts="crt1.o mcrt1.o maccrt1.o crt2.o crtn.o"
+ tm_file=
+ if [[ "$gnu_ld" = yes ]]
+ then
+ tm_file="${tm_file} m68k/auxgld.h"
+ else
+ tm_file="${tm_file} m68k/auxld.h"
+ fi
+ if [[ "$gas" = yes ]]
+ then
+ tm_file="${tm_file} m68k/auxgas.h"
+ else
+ tm_file="${tm_file} m68k/auxas.h"
+ fi
+ tm_file="${tm_file} m68k/a-ux.h"
+ float_format=m68k
+ ;;
+ m68k-apollo-*)
+ tm_file=m68k/apollo68.h
+ xmake_file=m68k/x-apollo68
+ use_collect2=yes
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-altos-sysv*) # Altos 3068
+ if [[ x$gas = xyes ]]
+ then
+ tm_file=m68k/altos3068.h
+ xm_defines=USG
+ else
+ echo "The Altos is supported only with the GNU assembler" 1>&2
+ exit 1
+ fi
+ extra_headers=math-68881.h
+ ;;
+ m68k-bull-sysv*) # Bull DPX/2
+ if [[ x$gas = xyes ]]
+ then
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file=m68k/dpx2cdbx.h
+ else
+ tm_file=m68k/dpx2g.h
+ fi
+ else
+ tm_file=m68k/dpx2.h
+ fi
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines=USG
+ xmake_file=m68k/x-dpx2
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68k-atari-sysv4*) # Atari variant of V.4.
+ tm_file=m68k/atari.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines="USG FULL_PROTOTYPES"
+ tmake_file=t-svr4
+ extra_parts="crtbegin.o crtend.o"
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-motorola-sysv*)
+ tm_file=m68k/mot3300.h
+ xm_file="xm-alloca.h m68k/xm-mot3300.h ${xm_file}"
+ xm_defines=NO_SYS_SIGLIST
+ if [[ x$gas = xyes ]]
+ then
+ xmake_file=m68k/x-mot3300-gas
+ if [[ x$gnu_ld = xyes ]]
+ then
+ tmake_file=m68k/t-mot3300-gald
+ else
+ tmake_file=m68k/t-mot3300-gas
+ use_collect2=yes
+ fi
+ else
+ xmake_file=m68k/x-mot3300
+ if [[ x$gnu_ld = xyes ]]
+ then
+ tmake_file=m68k/t-mot3300-gld
+ else
+ tmake_file=m68k/t-mot3300
+ use_collect2=yes
+ fi
+ fi
+ gdb_needs_out_file_path=yes
+ extra_parts="crt0.o mcrt0.o"
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-ncr-sysv*) # NCR Tower 32 SVR3
+ tm_file=m68k/tower-as.h
+ xm_defines="USG SVR3"
+ xmake_file=m68k/x-tower
+ extra_parts="crtbegin.o crtend.o"
+ extra_headers=math-68881.h
+ ;;
+ m68k-plexus-sysv*)
+ tm_file=m68k/plexus.h
+ xm_file="xm-alloca.h m68k/xm-plexus.h ${xm_file}"
+ xm_defines=USG
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68k-tti-*)
+ tm_file=m68k/pbb.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines=USG
+ extra_headers=math-68881.h
+ ;;
+ m68k-crds-unos*)
+ xm_file="xm-alloca.h m68k/xm-crds.h ${xm_file}"
+ xm_defines="USG unos"
+ xmake_file=m68k/x-crds
+ tm_file=m68k/crds.h
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68k-cbm-sysv4*) # Commodore variant of V.4.
+ tm_file=m68k/amix.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines="USG FULL_PROTOTYPES"
+ xmake_file=m68k/x-amix
+ tmake_file=t-svr4
+ extra_parts="crtbegin.o crtend.o"
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-ccur-rtu)
+ tm_file=m68k/ccur-GAS.h
+ xmake_file=m68k/x-ccur
+ extra_headers=math-68881.h
+ use_collect2=yes
+ float_format=m68k
+ ;;
+ m68k-hp-bsd4.4*) # HP 9000/3xx running 4.4bsd
+ tm_file=m68k/hp3bsd44.h
+ xmake_file=m68k/x-hp3bsd44
+ use_collect2=yes
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-hp-bsd*) # HP 9000/3xx running Berkeley Unix
+ tm_file=m68k/hp3bsd.h
+ use_collect2=yes
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-isi-bsd*)
+ if [[ x$with_fp = xno ]]
+ then
+ tm_file=m68k/isi-nfp.h
+ else
+ tm_file=m68k/isi.h
+ float_format=m68k
+ fi
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68k-hp-hpux7*) # HP 9000 series 300 running HPUX version 7.
+ xm_file="xm_alloca.h ${xm_file}"
+ xm_defines="USG NO_SYS_SIGLIST"
+ if [[ x$gas = xyes ]]
+ then
+ xmake_file=m68k/x-hp320g
+ tm_file=m68k/hp320g.h
+ else
+ xmake_file=m68k/x-hp320
+ tm_file=m68k/hpux7.h
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-hp-hpux*) # HP 9000 series 300
+ xm_file="xm_alloca.h ${xm_file}"
+ xm_defines="USG NO_SYS_SIGLIST"
+ if [[ x$gas = xyes ]]
+ then
+ xmake_file=m68k/x-hp320g
+ tm_file=m68k/hp320g.h
+ else
+ xmake_file=m68k/x-hp320
+ tm_file=m68k/hp320.h
+ fi
+ install_headers_dir=install-headers-cpio
+ use_collect2=yes
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-sun-mach*)
+ tm_file=m68k/sun3mach.h
+ use_collect2=yes
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-sony-newsos3*)
+ if [[ x$gas = xyes ]]
+ then
+ tm_file=m68k/news3gas.h
+ else
+ tm_file=m68k/news3.h
+ fi
+ use_collect2=yes
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-sony-bsd* | m68k-sony-newsos*)
+ if [[ x$gas = xyes ]]
+ then
+ tm_file=m68k/newsgas.h
+ else
+ tm_file=m68k/news.h
+ fi
+ use_collect2=yes
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-next-nextstep2*)
+ tm_file=m68k/next21.h
+ xm_file="m68k/xm-next.h ${xm_file}"
+ tmake_file=m68k/t-next
+ xmake_file=m68k/x-next
+ extra_objs=nextstep.o
+ extra_headers=math-68881.h
+ use_collect2=yes
+ float_format=m68k
+ ;;
+ m68k-next-nextstep3*)
+ tm_file=m68k/next.h
+ xm_file="m68k/xm-next.h ${xm_file}"
+ tmake_file=m68k/t-next
+ xmake_file=m68k/x-next
+ extra_objs=nextstep.o
+ extra_headers=math-68881.h
+ float_format=m68k
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='mach'
+ fi
+ ;;
+ m68k-sun-sunos3*)
+ if [[ x$with_fp = xno ]]
+ then
+ tm_file=m68k/sun3n3.h
+ else
+ tm_file=m68k/sun3o3.h
+ float_format=m68k
+ fi
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68k-sun-sunos*) # For SunOS 4 (the default).
+ if [[ x$with_fp = xno ]]
+ then
+ tm_file=m68k/sun3n.h
+ else
+ tm_file=m68k/sun3.h
+ float_format=m68k
+ fi
+ use_collect2=yes
+ extra_headers=math-68881.h
+ ;;
+ m68k-wrs-vxworks*)
+ tm_file=m68k/vxm68k.h
+ tmake_file=m68k/t-vxworks68
+ extra_headers=math-68881.h
+ thread_file='vxworks'
+ float_format=m68k
+ ;;
+ m68k-*-aout*)
+ tmake_file=m68k/t-m68kbare
+ tm_file="m68k/m68k-aout.h libgloss.h"
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-*-coff*)
+ tmake_file=m68k/t-m68kbare
+ tm_file="m68k/m68k-coff.h dbx.h libgloss.h"
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-*-lynxos*)
+ if [[ x$gas = xyes ]]
+ then
+ tm_file=m68k/lynx.h
+ else
+ tm_file=m68k/lynx-ng.h
+ fi
+ xm_file=m68k/xm-lynx.h
+ xmake_file=x-lynx
+ tmake_file=m68k/t-lynx
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k*-*-netbsd*)
+ tm_file=m68k/netbsd.h
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ float_format=m68k
+ ;;
+ m68k*-*-openbsd*)
+ float_format=m68k
+ # we need collect2 until our bug is fixed...
+ use_collect2=yes
+ ;;
+ m68k-*-sysv3*) # Motorola m68k's running system V.3
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines=USG
+ xmake_file=m68k/x-m68kv
+ extra_parts="crtbegin.o crtend.o"
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-*-sysv4*) # Motorola m68k's running system V.4
+ tm_file=m68k/m68kv4.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines=USG
+ tmake_file=t-svr4
+ extra_parts="crtbegin.o crtend.o"
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-*-linux-gnuaout*) # Motorola m68k's running GNU/Linux
+ # with a.out format
+ xmake_file=x-linux
+ tm_file=m68k/linux-aout.h
+ tmake_file="t-linux-aout m68k/t-linux-aout"
+ fixincludes=Makefile.in # The headers are ok already.
+ extra_headers=math-68881.h
+ float_format=m68k
+ gnu_ld=yes
+ ;;
+ m68k-*-linux-gnulibc1) # Motorola m68k's running GNU/Linux
+ # with ELF format using the
+ # GNU/Linux C library 5
+ xmake_file=x-linux
+ tm_file=m68k/linux.h
+ tmake_file="t-linux t-linux-gnulibc1 m68k/t-linux"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ fixincludes=Makefile.in # The headers are ok already.
+ extra_headers=math-68881.h
+ float_format=m68k
+ gnu_ld=yes
+ ;;
+ m68k-*-linux-gnu*) # Motorola m68k's running GNU/Linux
+ # with ELF format using glibc 2
+ # aka the GNU/Linux C library 6.
+ xmake_file=x-linux
+ tm_file=m68k/linux.h
+ tmake_file="t-linux m68k/t-linux"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ fixincludes=Makefile.in # The headers are ok already.
+ extra_headers=math-68881.h
+ float_format=m68k
+ gnu_ld=yes
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='posix'
+ fi
+ ;;
+ m68k-*-psos*)
+ tmake_file=m68k/t-m68kbare
+ tm_file=m68k/m68k-psos.h
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+ m68k-*-rtems*)
+ tmake_file="m68k/t-m68kbare t-rtems"
+ tm_file=m68k/rtems.h
+ extra_headers=math-68881.h
+ float_format=m68k
+ ;;
+
+ m88k-dg-dgux*)
+ case $machine in
+ m88k-dg-dguxbcs*)
+ tm_file=m88k/dguxbcs.h
+ tmake_file=m88k/t-dguxbcs
+ ;;
+ *)
+ tm_file=m88k/dgux.h
+ tmake_file=m88k/t-dgux
+ ;;
+ esac
+ extra_parts="crtbegin.o bcscrtbegin.o crtend.o m88kdgux.ld"
+ xmake_file=m88k/x-dgux
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=m88k/t-dgux-gas
+ fi
+ fixincludes=fixinc.dgux
+ ;;
+ m88k-dolphin-sysv3*)
+ tm_file=m88k/dolph.h
+ extra_parts="crtbegin.o crtend.o"
+ xm_file="m88k/xm-sysv3.h ${xm_file}"
+ xmake_file=m88k/x-dolph
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=m88k/t-m88k-gas
+ fi
+ ;;
+ m88k-tektronix-sysv3)
+ tm_file=m88k/tekXD88.h
+ extra_parts="crtbegin.o crtend.o"
+ xm_file="m88k/xm-sysv3.h ${xm_file}"
+ xmake_file=m88k/x-tekXD88
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=m88k/t-m88k-gas
+ fi
+ ;;
+ m88k-*-aout*)
+ tm_file=m88k/m88k-aout.h
+ ;;
+ m88k-*-coff*)
+ tm_file=m88k/m88k-coff.h
+ tmake_file=m88k/t-bug
+ ;;
+ m88k-*-luna*)
+ tm_file=m88k/luna.h
+ extra_parts="crtbegin.o crtend.o"
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=m88k/t-luna-gas
+ else
+ tmake_file=m88k/t-luna
+ fi
+ ;;
+ m88k-*-openbsd*)
+ tmake_file="${tmake_file} m88k/t-luna-gas"
+ ;;
+ m88k-*-sysv3*)
+ tm_file=m88k/sysv3.h
+ extra_parts="crtbegin.o crtend.o"
+ xm_file="m88k/xm-sysv3.h ${xm_file}"
+ xmake_file=m88k/x-sysv3
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=m88k/t-m88k-gas
+ fi
+ ;;
+ m88k-*-sysv4*)
+ tm_file=m88k/sysv4.h
+ extra_parts="crtbegin.o crtend.o"
+ xmake_file=m88k/x-sysv4
+ tmake_file=m88k/t-sysv4
+ ;;
+ mips-sgi-irix6*) # SGI System V.4., IRIX 6
+ tm_file=mips/iris6.h
+ xm_file=mips/xm-iris6.h
+ fixincludes=fixinc.irix
+ xmake_file=mips/x-iris6
+ tmake_file=mips/t-iris6
+ if [[ x$enable_threads = xyes ]]; then
+: not ported yet thread_file='irix'
+ fi
+ ;;
+ mips-wrs-vxworks)
+ tm_file="mips/elf.h libgloss.h"
+ tmake_file=mips/t-ecoff
+ gas=yes
+ gnu_ld=yes
+ extra_parts="crtbegin.o crtend.o"
+# thread_file='vxworks'
+ ;;
+ mips-sgi-irix5cross64) # Irix5 host, Irix 6 target, cross64
+ tm_file="mips/iris6.h mips/cross64.h"
+ xm_defines=USG
+ xm_file="mips/xm-iris5.h"
+ fixincludes=Makefile.in
+ xmake_file=mips/x-iris
+ tmake_file=mips/t-cross64
+ # See comment in mips/iris[56].h files.
+ use_collect2=yes
+ if [[ x$enable_threads = xyes ]]; then
+: not ported yet thread_file='irix'
+ fi
+ ;;
+ mips-sni-sysv4)
+ if [[ x$gas = xyes ]]
+ then
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file=mips/iris5gdb.h
+ else
+ tm_file="mips/sni-svr4.h mips/sni-gas.h"
+ fi
+ else
+ tm_file=mips/sni-svr4.h
+ fi
+ xm_defines=USG
+ xmake_file=mips/x-sni-svr4
+ tmake_file=mips/t-mips-gas
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-sgi-irix5*) # SGI System V.4., IRIX 5
+ if [[ x$gas = xyes ]]
+ then
+ tm_file="mips/iris5.h mips/iris5gas.h"
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ else
+ tm_file=mips/iris5.h
+ fi
+ xm_defines=USG
+ xm_file="mips/xm-iris5.h"
+ fixincludes=fixinc.irix
+ xmake_file=mips/x-iris
+ # mips-tfile doesn't work yet
+ tmake_file=mips/t-mips-gas
+ # See comment in mips/iris5.h file.
+ use_collect2=yes
+ if [[ x$enable_threads = xyes ]]; then
+: not ported yet thread_file='irix'
+ fi
+ ;;
+ mips-sgi-irix4loser*) # Mostly like a MIPS.
+ tm_file="mips/iris4loser.h mips/iris3.h ${tm_file} mips/iris4.h"
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xm_defines=USG
+ xmake_file=mips/x-iris
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ else
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ if [[ x$enable_threads = xyes ]]; then
+: not ported yet thread_file='irix'
+ fi
+ ;;
+ mips-sgi-irix4*) # Mostly like a MIPS.
+ tm_file="mips/iris3.h ${tm_file} mips/iris4.h"
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xm_defines=USG
+ xmake_file=mips/x-iris
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ else
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ if [[ x$enable_threads = xyes ]]; then
+: not ported yet thread_file='irix'
+ fi
+ ;;
+ mips-sgi-*) # Mostly like a MIPS.
+ tm_file="mips/iris3.h ${tm_file}"
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xm_defines=USG
+ xmake_file=mips/x-iris3
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ else
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-dec-osfrose*) # Decstation running OSF/1 reference port with OSF/rose.
+ tm_file="mips/osfrose.h ${tm_file}"
+ xmake_file=mips/x-osfrose
+ tmake_file=mips/t-osfrose
+ extra_objs=halfpic.o
+ use_collect2=yes
+ ;;
+ mips-dec-osf*) # Decstation running OSF/1 as shipped by DIGITAL
+ tm_file=mips/dec-osf1.h
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xmake_file=mips/x-dec-osf1
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ else
+ tmake_file=mips/t-ultrix
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-dec-bsd*) # Decstation running 4.4 BSD
+ tm_file=mips/dec-bsd.h
+ fixincludes=
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ else
+ tmake_file=mips/t-ultrix
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mipsel-*-netbsd* | mips-dec-netbsd*) # Decstation running NetBSD
+ tm_file=mips/netbsd.h
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ ;;
+ mips*el-*-openbsd*) # mips little endian
+ target_cpu_default="MASK_GAS|MASK_ABICALLS"
+ tm_file=mips/openbsd.h
+ xmake_file=none
+ ;;
+ mips*-*-openbsd*) # mips big endian
+ target_cpu_default="MASK_GAS|MASK_ABICALLS"
+ tm_file=mips/openbsd-be.h
+ xmake_file=none
+ ;;
+ mips-sony-bsd* | mips-sony-newsos*) # Sony NEWS 3600 or risc/news.
+ tm_file="mips/news4.h ${tm_file}"
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ else
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ xmake_file=mips/x-sony
+ ;;
+ mips-sony-sysv*) # Sony NEWS 3800 with NEWSOS5.0.
+ # That is based on svr4.
+ # t-svr4 is not right because this system doesn't use ELF.
+ tm_file="mips/news5.h ${tm_file}"
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xm_file="xm-siglist.h ${xm_file}"
+ xm_defines=USG
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ else
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-tandem-sysv4*) # Tandem S2 running NonStop UX
+ tm_file="mips/svr4-5.h mips/svr4-t.h"
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xm_file="xm-siglist.h ${xm_file}"
+ xm_defines=USG
+ xmake_file=mips/x-sysv
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ extra_parts="crtbegin.o crtend.o"
+ else
+ tmake_file=mips/t-mips
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-*-ultrix* | mips-dec-mach3) # Decstation.
+ tm_file="mips/ultrix.h ${tm_file}"
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xmake_file=mips/x-ultrix
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ else
+ tmake_file=mips/t-ultrix
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-*-riscos[[56789]]bsd*)
+ tm_file=mips/bsd-5.h # MIPS BSD 4.3, RISC-OS 5.0
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-bsd-gas
+ else
+ tmake_file=mips/t-bsd
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-*-bsd* | mips-*-riscosbsd* | mips-*-riscos[[1234]]bsd*)
+ tm_file="mips/bsd-4.h ${tm_file}" # MIPS BSD 4.3, RISC-OS 4.0
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-bsd-gas
+ else
+ tmake_file=mips/t-bsd
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-*-riscos[[56789]]sysv4*)
+ tm_file=mips/svr4-5.h # MIPS System V.4., RISC-OS 5.0
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xm_file="xm-siglist.h ${xm_file}"
+ xmake_file=mips/x-sysv
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-svr4-gas
+ else
+ tmake_file=mips/t-svr4
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-*-sysv4* | mips-*-riscos[[1234]]sysv4* | mips-*-riscossysv4*)
+ tm_file="mips/svr4-4.h ${tm_file}"
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xm_defines=USG
+ xmake_file=mips/x-sysv
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-svr4-gas
+ else
+ tmake_file=mips/t-svr4
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-*-riscos[[56789]]sysv*)
+ tm_file=mips/svr3-5.h # MIPS System V.3, RISC-OS 5.0
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xm_defines=USG
+ xmake_file=mips/x-sysv
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-svr3-gas
+ else
+ tmake_file=mips/t-svr3
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-*-sysv* | mips-*-riscos*sysv*)
+ tm_file="mips/svr3-4.h ${tm_file}"
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ xm_defines=USG
+ xmake_file=mips/x-sysv
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-svr3-gas
+ else
+ tmake_file=mips/t-svr3
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-*-riscos[[56789]]*) # Default MIPS RISC-OS 5.0.
+ tm_file=mips/mips-5.h
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ else
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mips-*-gnu*)
+ ;;
+ mipsel-*-ecoff*)
+ tm_file=mips/ecoffl.h
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ tmake_file=mips/t-ecoff
+ ;;
+ mips-*-ecoff*)
+ tm_file="gofast.h mips/ecoff.h"
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ tmake_file=mips/t-ecoff
+ ;;
+ mipsel-*-elf*)
+ tm_file="mips/elfl.h libgloss.h"
+ tmake_file=mips/t-ecoff
+ ;;
+ mips-*-elf*)
+ tm_file="mips/elf.h libgloss.h"
+ tmake_file=mips/t-ecoff
+ ;;
+ mips64el-*-elf*)
+ tm_file="mips/elfl64.h libgloss.h"
+ tmake_file=mips/t-ecoff
+ ;;
+ mips64orionel-*-elf*)
+ tm_file="mips/elforion.h mips/elfl64.h libgloss.h"
+ tmake_file=mips/t-ecoff
+ ;;
+ mips64-*-elf*)
+ tm_file="mips/elf64.h libgloss.h"
+ tmake_file=mips/t-ecoff
+ ;;
+ mips64orion-*-elf*)
+ tm_file="mips/elforion.h mips/elf64.h libgloss.h"
+ tmake_file=mips/t-ecoff
+ ;;
+ mips64orion-*-rtems*)
+ tm_file="mips/elforion.h mips/elf64.h mips/rtems64.h"
+ tmake_file="mips/t-ecoff t-rtems"
+ ;;
+ mipstx39el-*-elf*)
+ tm_file="mips/r3900.h mips/elfl.h mips/abi64.h libgloss.h"
+ tmake_file=mips/t-r3900
+ ;;
+ mipstx39-*-elf*)
+ tm_file="mips/r3900.h mips/elf.h mips/abi64.h libgloss.h"
+ tmake_file=mips/t-r3900
+ ;;
+ mips-*-*) # Default MIPS RISC-OS 4.0.
+ if [[ x$stabs = xyes ]]; then
+ tm_file="${tm_file} dbx.h"
+ fi
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file=mips/t-mips-gas
+ else
+ extra_passes="mips-tfile mips-tdump"
+ fi
+ if [[ x$gnu_ld != xyes ]]
+ then
+ use_collect2=yes
+ fi
+ ;;
+ mn10200-*-*)
+ cpu_type=mn10200
+ tm_file="mn10200/mn10200.h"
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ use_collect2=no
+ ;;
+ mn10300-*-*)
+ cpu_type=mn10300
+ tm_file="mn10300/mn10300.h"
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ use_collect2=no
+ ;;
+ ns32k-encore-bsd*)
+ tm_file=ns32k/encore.h
+ use_collect2=yes
+ ;;
+ ns32k-sequent-bsd*)
+ tm_file=ns32k/sequent.h
+ use_collect2=yes
+ ;;
+ ns32k-tek6100-bsd*)
+ tm_file=ns32k/tek6100.h
+ use_collect2=yes
+ ;;
+ ns32k-tek6200-bsd*)
+ tm_file=ns32k/tek6200.h
+ use_collect2=yes
+ ;;
+# This has not been updated to GCC 2.
+# ns32k-ns-genix*)
+# xm_defines=USG
+# xmake_file=ns32k/x-genix
+# tm_file=ns32k/genix.h
+# use_collect2=yes
+# ;;
+ ns32k-merlin-*)
+ tm_file=ns32k/merlin.h
+ use_collect2=yes
+ ;;
+ ns32k-pc532-mach*)
+ tm_file=ns32k/pc532-mach.h
+ use_collect2=yes
+ ;;
+ ns32k-pc532-minix*)
+ tm_file=ns32k/pc532-min.h
+ xm_file="ns32k/xm-pc532-min.h ${xm-file}"
+ xm_defines=USG
+ use_collect2=yes
+ ;;
+ ns32k-*-netbsd*)
+ tm_file=ns32k/netbsd.h
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ ;;
+ pdp11-*-bsd)
+ tm_file="${tm_file} pdp11/2bsd.h"
+ ;;
+ pdp11-*-*)
+ ;;
+ ns32k-*-openbsd*)
+ # Nothing special
+ ;;
+ pyramid-*-*)
+ cpu_type=pyr
+ xmake_file=pyr/x-pyr
+ use_collect2=yes
+ ;;
+ romp-*-aos*)
+ use_collect2=yes
+ ;;
+ romp-*-mach*)
+ xmake_file=romp/x-mach
+ use_collect2=yes
+ ;;
+ romp-*-openbsd*)
+ # Nothing special
+ ;;
+ powerpc-*-openbsd*)
+ tmake_file="${tmake_file} rs6000/t-rs6000 rs6000/t-openbsd"
+ xmake_file=none
+ ;;
+ powerpc-*-beos*)
+ cpu_type=rs6000
+ tm_file=rs6000/beos.h
+ xm_file=rs6000/xm-beos.h
+ tmake_file=rs6000/t-beos
+ xmake_file=rs6000/x-beos
+ ;;
+ powerpc-*-sysv* | powerpc-*-elf*)
+ tm_file=rs6000/sysv4.h
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+ xm_defines="USG POSIX"
+ extra_headers=ppc-asm.h
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file="rs6000/t-ppcos rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc rs6000/t-ppccomm"
+ fi
+ xmake_file=rs6000/x-sysv4
+ ;;
+ powerpc-*-eabiaix*)
+ tm_file=rs6000/eabiaix.h
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
+ fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
+ ;;
+ powerpc-*-eabisim*)
+ tm_file=rs6000/eabisim.h
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
+ fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
+ ;;
+ powerpc-*-eabi*)
+ tm_file=rs6000/eabi.h
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc rs6000/t-ppccomm"
+ fi
+ fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
+ ;;
+ powerpc-*-rtems*)
+ tm_file=rs6000/rtems.h
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file="rs6000/t-ppcgas t-rtems rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc t-rtems rs6000/t-ppccomm"
+ fi
+ fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
+ ;;
+ powerpc-*-linux-gnulibc1)
+ tm_file=rs6000/linux.h
+ xm_file=rs6000/xm-sysv4.h
+ out_file=rs6000/rs6000.c
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file="rs6000/t-ppcos t-linux t-linux-gnulibc1 rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc t-linux t-linux-gnulibc1 rs6000/t-ppccomm"
+ fi
+ xmake_file=x-linux
+ fixincludes=Makefile.in
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ extra_headers=ppc-asm.h
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='posix'
+ fi
+ ;;
+ powerpc-*-linux-gnu*)
+ tm_file=rs6000/linux.h
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+ xm_defines="USG ${xm_defines}"
+ out_file=rs6000/rs6000.c
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file="rs6000/t-ppcos t-linux rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc t-linux rs6000/t-ppccomm"
+ fi
+ xmake_file=x-linux
+ fixincludes=Makefile.in
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ extra_headers=ppc-asm.h
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='posix'
+ fi
+ ;;
+ powerpc-wrs-vxworks*)
+ cpu_type=rs6000
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+ xm_defines="USG POSIX"
+ tm_file=rs6000/vxppc.h
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
+ extra_headers=ppc-asm.h
+ thread_file='vxworks'
+ ;;
+ powerpcle-*-sysv* | powerpcle-*-elf*)
+ tm_file=rs6000/sysv4le.h
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+ xm_defines="USG POSIX"
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file="rs6000/t-ppcos rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc rs6000/t-ppccomm"
+ fi
+ xmake_file=rs6000/x-sysv4
+ extra_headers=ppc-asm.h
+ ;;
+ powerpcle-*-eabisim*)
+ tm_file=rs6000/eabilesim.h
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
+ fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
+ ;;
+ powerpcle-*-eabi*)
+ tm_file=rs6000/eabile.h
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file="rs6000/t-ppcgas rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc rs6000/t-ppccomm"
+ fi
+ fixincludes=Makefile.in
+ extra_headers=ppc-asm.h
+ ;;
+ powerpcle-*-winnt* )
+ tm_file=rs6000/win-nt.h
+ tmake_file=rs6000/t-winnt
+# extra_objs=pe.o
+ fixincludes=Makefile.in
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='win32'
+ fi
+ extra_headers=ppc-asm.h
+ ;;
+ powerpcle-*-pe | powerpcle-*-cygwin32)
+ tm_file=rs6000/cygwin32.h
+ xm_file="rs6000/xm-cygwin32.h ${xm_file}"
+ tmake_file=rs6000/t-winnt
+ xmake_file=rs6000/x-cygwin32
+# extra_objs=pe.o
+ fixincludes=Makefile.in
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='win32'
+ fi
+ exeext=.exe
+ extra_headers=ppc-asm.h
+ ;;
+ powerpcle-*-solaris2*)
+ tm_file=rs6000/sol2.h
+ xm_file="xm-siglist.h rs6000/xm-sysv4.h"
+ xm_defines="USG POSIX"
+ if [[ x$gas = xyes ]]
+ then
+ tmake_file="rs6000/t-ppcos rs6000/t-ppccomm"
+ else
+ tmake_file="rs6000/t-ppc rs6000/t-ppccomm"
+ fi
+ xmake_file=rs6000/x-sysv4
+ case $machine in
+ *-*-solaris2.[[0-4]])
+ fixincludes=fixinc.svr4;;
+ *)
+ fixincludes=fixinc.wrap;;
+ esac
+ extra_headers=ppc-asm.h
+ ;;
+ rs6000-ibm-aix3.[[01]]*)
+ tm_file=rs6000/aix31.h
+ xmake_file=rs6000/x-aix31
+ use_collect2=yes
+ ;;
+ rs6000-ibm-aix3.2.[[456789]]* | powerpc-ibm-aix3.2.[[456789]]*)
+ tm_file=rs6000/aix3newas.h
+ if [[ x$host != x$target ]]
+ then
+ tmake_file=rs6000/t-xnewas
+ else
+ tmake_file=rs6000/t-newas
+ fi
+ use_collect2=yes
+ ;;
+ rs6000-ibm-aix4.[[12]]* | powerpc-ibm-aix4.[[12]]*)
+ tm_file=rs6000/aix41.h
+ if [[ x$host != x$target ]]
+ then
+ tmake_file=rs6000/t-xnewas
+ else
+ tmake_file=rs6000/t-newas
+ fi
+ xmake_file=rs6000/x-aix41
+ use_collect2=yes
+ ;;
+ rs6000-ibm-aix4.[[3456789]].* | powerpc-ibm-aix4.[[3456789]].*)
+ tm_file=rs6000/aix43.h
+ if [[ x$host != x$target ]]
+ then
+ tmake_file=rs6000/t-xaix43
+ else
+ tmake_file=rs6000/t-aix43
+ fi
+ xmake_file=rs6000/x-aix43
+ use_collect2=yes
+ ;;
+ rs6000-ibm-aix[[56789]].* | powerpc-ibm-aix[[56789]].*)
+ tm_file=rs6000/aix43.h
+ if [[ x$host != x$target ]]
+ then
+ tmake_file=rs6000/t-xaix43
+ else
+ tmake_file=rs6000/t-aix43
+ fi
+ xmake_file=rs6000/x-aix43
+ use_collect2=yes
+ ;;
+ rs6000-ibm-aix*)
+ use_collect2=yes
+ ;;
+ rs6000-bull-bosx)
+ use_collect2=yes
+ ;;
+ rs6000-*-mach*)
+ tm_file=rs6000/mach.h
+ xm_file="${xm_file} rs6000/xm-mach.h"
+ xmake_file=rs6000/x-mach
+ use_collect2=yes
+ ;;
+ rs6000-*-lynxos*)
+ tm_file=rs6000/lynx.h
+ xm_file=rs6000/xm-lynx.h
+ tmake_file=rs6000/t-rs6000
+ xmake_file=rs6000/x-lynx
+ use_collect2=yes
+ ;;
+ sh-*-elf*)
+ tm_file=sh/elf.h
+ float_format=sh
+ ;;
+ sh-*-rtemself*)
+ tmake_file="sh/t-sh t-rtems"
+ tm_file=sh/rtemself.h
+ float_format=sh
+ ;;
+ sh-*-rtems*)
+ tmake_file="sh/t-sh t-rtems"
+ tm_file=sh/rtems.h
+ float_format=sh
+ ;;
+ sh-*-*)
+ float_format=sh
+ ;;
+ sparc-tti-*)
+ tm_file=sparc/pbd.h
+ xm_file="xm-alloca.h ${xm_file}"
+ xm_defines=USG
+ ;;
+ sparc-wrs-vxworks* | sparclite-wrs-vxworks*)
+ tm_file=sparc/vxsparc.h
+ tmake_file=sparc/t-vxsparc
+ use_collect2=yes
+ thread_file='vxworks'
+ ;;
+ sparc-*-aout*)
+ tmake_file=sparc/t-sparcbare
+ tm_file="sparc/aout.h libgloss.h"
+ ;;
+ sparc-*-netbsd*)
+ tm_file=sparc/netbsd.h
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ ;;
+ sparc-*-openbsd*)
+ # we need collect2 until our bug is fixed...
+ use_collect2=yes
+ ;;
+ sparc-*-bsd*)
+ tm_file=sparc/bsd.h
+ ;;
+ sparc-*-elf*)
+ tm_file=sparc/elf.h
+ tmake_file=sparc/t-elf
+ extra_parts="crti.o crtn.o crtbegin.o crtend.o"
+ #float_format=i128
+ float_format=i64
+ ;;
+ sparc-*-linux-gnuaout*) # Sparc's running GNU/Linux, a.out
+ xm_file="${xm_file} sparc/xm-linux.h"
+ tm_file=sparc/linux-aout.h
+ xmake_file=x-linux
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ ;;
+ sparc-*-linux-gnulibc1*) # Sparc's running GNU/Linux, libc5
+ xm_file="${xm_file} sparc/xm-linux.h"
+ xmake_file=x-linux
+ tm_file=sparc/linux.h
+ tmake_file="t-linux t-linux-gnulibc1"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ ;;
+ sparc-*-linux-gnu*) # Sparc's running GNU/Linux, libc6
+ xm_file="${xm_file} sparc/xm-linux.h"
+ xmake_file=x-linux
+ tm_file=sparc/linux.h
+ tmake_file="t-linux"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o"
+ fixincludes=Makefile.in #On Linux, the headers are ok already.
+ gnu_ld=yes
+ if [[ x$enable_threads = xyes ]]; then
+ thread_file='posix'
+ fi
+ ;;
+ sparc-*-lynxos*)
+ if [[ x$gas = xyes ]]
+ then
+ tm_file=sparc/lynx.h
+ else
+ tm_file=sparc/lynx-ng.h
+ fi
+ xm_file=sparc/xm-lynx.h
+ tmake_file=sparc/t-sunos41
+ xmake_file=x-lynx
+ ;;
+ sparc-*-rtems*)
+ tmake_file="sparc/t-sparcbare t-rtems"
+ tm_file=sparc/rtems.h
+ ;;
+ sparc-*-solaris2*)
+ if [[ x$gnu_ld = xyes ]]
+ then
+ tm_file=sparc/sol2.h
+ else
+ tm_file=sparc/sol2-sld.h
+ fi
+ xm_file="xm-siglist.h sparc/xm-sysv4.h sparc/xm-sol2.h"
+ xm_defines="USG POSIX"
+ tmake_file=sparc/t-sol2
+ xmake_file=sparc/x-sysv4
+ extra_parts="crt1.o crti.o crtn.o gcrt1.o gmon.o crtbegin.o crtend.o"
+ case $machine in
+ *-*-solaris2.[[0-4]])
+ fixincludes=fixinc.svr4;;
+ *)
+ fixincludes=fixinc.wrap;;
+ esac
+ float_format=i128
+ if [[ x${enable_threads} = x ]]; then
+ enable_threads=$have_pthread_h
+ if [[ x${enable_threads} = x ]]; then
+ enable_threads=$have_thread_h
+ fi
+ fi
+ if [[ x${enable_threads} = xyes ]]; then
+ if [[ x${have_pthread_h} = xyes ]]; then
+ thread_file='posix'
+ else
+ thread_file='solaris'
+ fi
+ fi
+ ;;
+ sparc-*-sunos4.0*)
+ tm_file=sparc/sunos4.h
+ tmake_file=sparc/t-sunos40
+ use_collect2=yes
+ ;;
+ sparc-*-sunos4*)
+ tm_file=sparc/sunos4.h
+ tmake_file=sparc/t-sunos41
+ use_collect2=yes
+ if [[ x$gas = xyes ]]; then
+ tm_file="${tm_file} sparc/sun4gas.h"
+ fi
+ ;;
+ sparc-*-sunos3*)
+ tm_file=sparc/sun4o3.h
+ use_collect2=yes
+ ;;
+ sparc-*-sysv4*)
+ tm_file=sparc/sysv4.h
+ xm_file="xm-siglist.h sparc/xm-sysv4.h"
+ xm_defines="USG POSIX"
+ tmake_file=t-svr4
+ xmake_file=sparc/x-sysv4
+ extra_parts="crtbegin.o crtend.o"
+ ;;
+ sparc-*-vxsim*)
+ xm_file="xm-siglist.h sparc/xm-sysv4.h sparc/xm-sol2.h"
+ xm_defines="USG POSIX"
+ tm_file=sparc/vxsim.h
+ tmake_file=sparc/t-vxsparc
+ xmake_file=sparc/x-sysv4
+ ;;
+ sparclet-*-aout*)
+ tm_file="sparc/splet.h libgloss.h"
+ tmake_file=sparc/t-splet
+ ;;
+ sparclite-*-coff*)
+ tm_file="sparc/litecoff.h libgloss.h"
+ tmake_file=sparc/t-sparclite
+ ;;
+ sparclite-*-aout*)
+ tm_file="sparc/lite.h aoutos.h libgloss.h"
+ tmake_file=sparc/t-sparclite
+ ;;
+ sparc64-*-aout*)
+ tmake_file=sparc/t-sp64
+ tm_file=sparc/sp64-aout.h
+ ;;
+ sparc64-*-elf*)
+ tmake_file=sparc/t-sp64
+ tm_file=sparc/sp64-elf.h
+ extra_parts="crtbegin.o crtend.o"
+ ;;
+ sparc64-*-linux*) # 64-bit Sparc's running GNU/Linux
+ tmake_file=sparc/t-sp64
+ xm_file="sparc/xm-sp64.h sparc/xm-linux.h"
+ tm_file=sparc/linux64.h
+ xmake_file=x-linux
+ fixincludes=Makefile.in # The headers are ok already.
+ gnu_ld=yes
+ ;;
+# This hasn't been upgraded to GCC 2.
+# tahoe-harris-*) # Harris tahoe, using COFF.
+# tm_file=tahoe/harris.h
+# ;;
+# tahoe-*-bsd*) # tahoe running BSD
+# ;;
+ thumb-*-coff* | thumbel-*-coff*)
+ tm_file=arm/tcoff.h
+ out_file=arm/thumb.c
+ xm_file=arm/xm-thumb.h
+ md_file=arm/thumb.md
+ tmake_file=arm/t-thumb
+ fixincludes=Makefile.in # There is nothing to fix
+ ;;
+# This hasn't been upgraded to GCC 2.
+# tron-*-*)
+# cpu_type=gmicro
+# use_collect2=yes
+# ;;
+ v850-*-*)
+ cpu_type=v850
+ tm_file="v850/v850.h"
+ xm_file="v850/xm-v850.h"
+ tmake_file=v850/t-v850
+ if [[ x$stabs = xyes ]]
+ then
+ tm_file="${tm_file} dbx.h"
+ fi
+ use_collect2=no
+ ;;
+ vax-*-bsd*) # vaxen running BSD
+ use_collect2=yes
+ float_format=vax
+ ;;
+ vax-*-sysv*) # vaxen running system V
+ tm_file="${tm_file} vax/vaxv.h"
+ xm_defines=USG
+ float_format=vax
+ ;;
+ vax-*-netbsd*)
+ tm_file="${tm_file} netbsd.h vax/netbsd.h"
+ xm_file="xm-netbsd.h ${xm_file}"
+ # On NetBSD, the headers are already okay, except for math.h.
+ fixincludes=fixinc.wrap
+ tmake_file=t-netbsd
+ float_format=vax
+ ;;
+ vax-*-openbsd*)
+ tmake_file="${tm_file} vax/t-openbsd"
+ ;;
+ vax-*-ultrix*) # vaxen running ultrix
+ tm_file="${tm_file} vax/ultrix.h"
+ use_collect2=yes
+ float_format=vax
+ ;;
+ vax-*-vms*) # vaxen running VMS
+ xm_file=vax/xm-vms.h
+ tm_file=vax/vms.h
+ float_format=vax
+ ;;
+ vax-*-*) # vax default entry
+ float_format=vax
+ ;;
+ we32k-att-sysv*)
+ xm_file="${xm_file} xm-svr3"
+ use_collect2=yes
+ ;;
+ *)
+ echo "Configuration $machine not supported" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case $machine in
+ *-*-linux-gnu*)
+ ;; # Existing GNU/Linux systems do not use the GNU setup.
+ *-*-gnu*)
+ # On the GNU system, the setup is just about the same on
+ # each different CPU. The specific machines that GNU
+ # supports are matched above and just set $cpu_type.
+ xm_file="xm-gnu.h ${xm_file}"
+ tm_file=${cpu_type}/gnu.h
+ extra_parts="crtbegin.o crtend.o crtbeginS.o crtendS.o"
+ # GNU always uses ELF.
+ elf=yes
+ # GNU tools are the only tools.
+ gnu_ld=yes
+ gas=yes
+ # On GNU, the headers are already okay.
+ fixincludes=Makefile.in
+ xmake_file=x-linux # These details are the same as Linux.
+ tmake_file=t-gnu # These are not.
+ ;;
+ *-*-sysv4*)
+ fixincludes=fixinc.svr4
+ xmake_try_sysv=x-sysv
+ install_headers_dir=install-headers-cpio
+ ;;
+ *-*-sysv*)
+ install_headers_dir=install-headers-cpio
+ ;;
+ esac
+
+ # Distinguish i[34567]86
+ # Also, do not run mips-tfile on MIPS if using gas.
+ # Process --with-cpu= for PowerPC/rs6000
+ target_cpu_default2=
+ case $machine in
+ i486-*-*)
+ target_cpu_default2=1
+ ;;
+ i586-*-*)
+ target_cpu_default2=2
+ ;;
+ i686-*-* | i786-*-*)
+ target_cpu_default2=3
+ ;;
+ alpha*-*-*)
+ case $machine in
+ alphaev6*)
+ target_cpu_default2="MASK_CPU_EV6|MASK_BWX|MASK_CIX|MASK_MAX"
+ ;;
+ alphapca56*)
+ target_cpu_default2="MASK_CPU_EV5|MASK_BWX|MASK_MAX"
+ ;;
+ alphaev56*)
+ target_cpu_default2="MASK_CPU_EV5|MASK_BWX"
+ ;;
+ alphaev5*)
+ target_cpu_default2="MASK_CPU_EV5"
+ ;;
+ esac
+
+ if [[ x$gas = xyes ]]
+ then
+ if [[ "$target_cpu_default2" = "" ]]
+ then
+ target_cpu_default2="MASK_GAS"
+ else
+ target_cpu_default2="${target_cpu_default2}|MASK_GAS"
+ fi
+ fi
+ ;;
+ arm*-*-*)
+ case "x$with_cpu" in
+ x)
+ # The most generic
+ target_cpu_default2="TARGET_CPU_generic"
+ ;;
+
+ # Distinguish cores, and major variants
+ # arm7m doesn't exist, but D & I don't affect code
+ xarm[23678] | xarm250 | xarm[67][01]0 \
+ | xarm7m | xarm7dm | xarm7dmi | xarm7tdmi \
+ | xarm7100 | xarm7500 | xarm7500fe | xarm810 \
+ | xstrongarm | xstrongarm110)
+ target_cpu_default2="TARGET_CPU_$with_cpu"
+ ;;
+
+ xyes | xno)
+ echo "--with-cpu must be passed a value" 1>&2
+ exit 1
+ ;;
+
+ *)
+ if [[ x$pass2done = xyes ]]
+ then
+ echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2
+ exit 1
+ fi
+ ;;
+ esac
+ ;;
+
+ mips*-*-ecoff* | mips*-*-elf*)
+ if [[ x$gas = xyes ]]
+ then
+ if [[ x$gnu_ld = xyes ]]
+ then
+ target_cpu_default2=20
+ else
+ target_cpu_default2=16
+ fi
+ fi
+ ;;
+ mips*-*-*)
+ if [[ x$gas = xyes ]]
+ then
+ target_cpu_default2=16
+ fi
+ ;;
+ powerpc*-*-* | rs6000-*-*)
+ case "x$with_cpu" in
+ x)
+ ;;
+
+ xcommon | xpower | xpower2 | xpowerpc | xrios \
+ | xrios1 | xrios2 | xrsc | xrsc1 \
+ | x601 | x602 | x603 | x603e | x604 | x604e | x620 \
+ | x403 | x505 | x801 | x821 | x823 | x860)
+ target_cpu_default2="\"$with_cpu\""
+ ;;
+
+ xyes | xno)
+ echo "--with-cpu must be passed a value" 1>&2
+ exit 1
+ ;;
+
+ *)
+ if [[ x$pass2done = xyes ]]
+ then
+ echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2
+ exit 1
+ fi
+ ;;
+ esac
+ ;;
+ sparc*-*-*)
+ case ".$with_cpu" in
+ .)
+ target_cpu_default2=TARGET_CPU_"`echo $machine | sed 's/-.*$//'`"
+ ;;
+ .supersparc | .ultrasparc | .v7 | .v8 | .v9)
+ target_cpu_default2="TARGET_CPU_$with_cpu"
+ ;;
+ *)
+ if [[ x$pass2done = xyes ]]
+ then
+ echo "Unknown cpu used with --with-cpu=$with_cpu" 1>&2
+ exit 1
+ fi
+ ;;
+ esac
+ ;;
+ esac
+
+ if [[ "$target_cpu_default2" != "" ]]
+ then
+ if [[ "$target_cpu_default" != "" ]]
+ then
+ target_cpu_default="(${target_cpu_default}|${target_cpu_default2})"
+ else
+ target_cpu_default=$target_cpu_default2
+ fi
+ fi
+
+ # No need for collect2 if we have the GNU linker.
+ # Actually, there is now; GNU ld doesn't handle the EH info or
+ # collecting for shared libraries.
+ #case x$gnu_ld in
+ #xyes)
+ # use_collect2=
+ # ;;
+ #esac
+
+# Save data on machine being used to compile GCC in build_xm_file.
+# Save data on host machine in vars host_xm_file and host_xmake_file.
+ if [[ x$pass1done = x ]]
+ then
+ if [[ x"$xm_file" = x ]]
+ then build_xm_file=$cpu_type/xm-$cpu_type.h
+ else build_xm_file=$xm_file
+ fi
+ build_xm_defines=$xm_defines
+ build_install_headers_dir=$install_headers_dir
+ build_exeext=$exeext
+ pass1done=yes
+ else
+ if [[ x$pass2done = x ]]
+ then
+ if [[ x"$xm_file" = x ]]
+ then host_xm_file=$cpu_type/xm-$cpu_type.h
+ else host_xm_file=$xm_file
+ fi
+ host_xm_defines=$xm_defines
+ if [[ x"$xmake_file" = x ]]
+ then xmake_file=$cpu_type/x-$cpu_type
+ fi
+ host_xmake_file="$xmake_file"
+ host_truncate_target=$truncate_target
+ host_extra_gcc_objs=$extra_gcc_objs
+ host_extra_objs=$extra_host_objs
+ host_exeext=$exeext
+ pass2done=yes
+ fi
+ fi
+done
+
+extra_objs="${host_extra_objs} ${extra_objs}"
+
+# Default the target-machine variables that were not explicitly set.
+if [[ x"$tm_file" = x ]]
+then tm_file=$cpu_type/$cpu_type.h; fi
+
+if [[ x$extra_headers = x ]]
+then extra_headers=; fi
+
+if [[ x"$xm_file" = x ]]
+then xm_file=$cpu_type/xm-$cpu_type.h; fi
+
+if [[ x$md_file = x ]]
+then md_file=$cpu_type/$cpu_type.md; fi
+
+if [[ x$out_file = x ]]
+then out_file=$cpu_type/$cpu_type.c; fi
+
+if [[ x"$tmake_file" = x ]]
+then tmake_file=$cpu_type/t-$cpu_type
+fi
+
+if [[ x$float_format = x ]]
+then float_format=i64
+fi
+
+if [[ x$enable_haifa = x ]]
+then
+ case $target in
+ alpha*-* | hppa1.?-* | powerpc*-* | rs6000-* | *sparc*-* | m32r*-*)
+ enable_haifa=yes;;
+ esac
+fi
+
+# Handle cpp installation.
+if [[ x$enable_cpp != x ]]
+then
+ tmake_file="$tmake_file t-install-cpp"
+ case x$enable_cpp in
+ xyes | xno) ;;
+ x/*) cpp_install_dir=$enable_cpp ;;
+ x.*) echo "alternate cpp script installation directory must be an absolute path" 1>&2
+ exit 1
+ ;;
+ esac
+fi
+
+# Say what files are being used for the output code and MD file.
+echo "Using \`$srcdir/config/$out_file' to output insns."
+echo "Using \`$srcdir/config/$md_file' as machine description file."
+
+count=a
+for f in $tm_file; do
+ count=${count}x
+done
+if [[ $count = ax ]]; then
+ echo "Using \`$srcdir/config/$tm_file' as target machine macro file."
+else
+ echo "Using the following target machine macro files:"
+ for f in $tm_file; do
+ echo " $srcdir/config/$f"
+ done
+fi
+
+count=a
+for f in $host_xm_file; do
+ count=${count}x
+done
+if [[ $count = ax ]]; then
+ echo "Using \`$srcdir/config/$host_xm_file' as host machine macro file."
+else
+ echo "Using the following host machine macro files:"
+ for f in $host_xm_file; do
+ echo " $srcdir/config/$f"
+ done
+fi
+
+if [[ "$host_xm_file" != "$build_xm_file" ]]; then
+ count=a
+ for f in $build_xm_file; do
+ count=${count}x
+ done
+ if [[ $count = ax ]]; then
+ echo "Using \`$srcdir/config/$build_xm_file' as build machine macro file."
+ else
+ echo "Using the following build machine macro files:"
+ for f in $build_xm_file; do
+ echo " $srcdir/config/$f"
+ done
+ fi
+fi
+
+if [[ x$thread_file = x ]]; then
+ if [[ x$target_thread_file != x ]]; then
+ thread_file=$target_thread_file
+ else
+ thread_file='single'
+ fi
+fi
+
+# Set up the header files.
+# $links is the list of header files to create.
+# $vars is the list of shell variables with file names to include.
+# auto-host.h is the file containing items generated by autoconf and is
+# the first file included by config.h.
+null_defines=
+host_xm_file="auto-host.h ${host_xm_file}"
+
+# If host=build, it is correct to have hconfig include auto-host.h
+# as well. If host!=build, we are in error and need to do more
+# work to find out the build config parameters.
+if [[ x$host = x$build ]]
+then
+ build_xm_file="auto-host.h ${build_xm_file}"
+else
+ # We create a subdir, then run autoconf in the subdir.
+ # To prevent recursion we set host and build for the new
+ # invocation of configure to the build for this invocation
+ # of configure.
+ tempdir=build.$$
+ rm -rf $tempdir
+ mkdir $tempdir
+ cd $tempdir
+ case ${srcdir} in
+ /*) realsrcdir=${srcdir};;
+ *) realsrcdir=../${srcdir};;
+ esac
+ CC=${CC_FOR_BUILD} ${realsrcdir}/configure \
+ --target=$target --host=$build --build=$build
+
+ # We just finished tests for the build machine, so rename
+ # the file auto-build.h in the gcc directory.
+ mv auto-host.h ../auto-build.h
+ cd ..
+ rm -rf $tempdir
+ build_xm_file="auto-build.h ${build_xm_file}"
+fi
+
+vars="host_xm_file tm_file xm_file build_xm_file"
+links="config.h tm.h tconfig.h hconfig.h"
+defines="host_xm_defines null_defines xm_defines build_xm_defines"
+
+rm -f config.bak
+if [[ -f config.status ]]; then mv -f config.status config.bak; fi
+
+# Make the links.
+while [[ -n "$vars" ]]
+do
+ set $vars; var=$1; shift; vars=$*
+ set $links; link=$1; shift; links=$*
+ set $defines; define=$1; shift; defines=$*
+
+ rm -f $link
+
+ # Define TARGET_CPU_DEFAULT if the system wants one.
+ # This substitutes for lots of *.h files.
+ if [[ "$target_cpu_default" != "" -a $link = tm.h ]]
+ then
+ echo "#define TARGET_CPU_DEFAULT ($target_cpu_default)" >>$link
+ fi
+
+ for file in `eval echo '$'$var`; do
+ echo "#include \"$file\"" >>$link
+ done
+
+ for def in `eval echo '$'$define`; do
+ echo "#ifndef $def" >>$link
+ echo "#define $def" >>$link
+ echo "#endif" >>$link
+ done
+done
+
+# Truncate the target if necessary
+if [[ x$host_truncate_target != x ]]; then
+ target=`echo $target | sed -e 's/\(..............\).*/\1/'`
+fi
+
+# Get the version trigger filename from the toplevel
+if [[ "${with_gcc_version_trigger+set}" = set ]]; then
+ gcc_version_trigger=$with_gcc_version_trigger
+else
+ gcc_version_trigger=${srcdir}/version.c
+fi
+gcc_version=`sed -e 's/.*\"\([[^ \"]]*\)[[ \"]].*/\1/' < ${gcc_version_trigger}`
+
+# Get an absolute path to the GCC top-level source directory
+holddir=`pwd`
+cd $srcdir
+topdir=`pwd`
+cd $holddir
+
+# Conditionalize the makefile for this host machine.
+# Make-host contains the concatenation of all host makefile fragments
+# [there can be more than one]. This file is built by configure.frag.
+host_overrides=Make-host
+dep_host_xmake_file=
+for f in .. ${host_xmake_file}
+do
+ if [[ -f ${srcdir}/config/$f ]]
+ then
+ dep_host_xmake_file="${dep_host_xmake_file} ${srcdir}/config/$f"
+ fi
+done
+
+# Conditionalize the makefile for this target machine.
+# Make-target contains the concatenation of all host makefile fragments
+# [there can be more than one]. This file is built by configure.frag.
+target_overrides=Make-target
+dep_tmake_file=
+for f in .. ${tmake_file}
+do
+ if [[ -f ${srcdir}/config/$f ]]
+ then
+ dep_tmake_file="${dep_tmake_file} ${srcdir}/config/$f"
+ fi
+done
+
+# If the host doesn't support symlinks, modify CC in
+# FLAGS_TO_PASS so CC="stage1/xgcc -Bstage1/" works.
+# Otherwise, we can use "CC=$(CC)".
+rm -f symtest.tem
+if $symbolic_link $srcdir/gcc.c symtest.tem 2>/dev/null
+then
+ cc_set_by_configure="\$(CC)"
+ stage_prefix_set_by_configure="\$(STAGE_PREFIX)"
+else
+ rm -f symtest.tem
+ if cp -p $srcdir/gcc.c symtest.tem 2>/dev/null
+ then
+ symbolic_link="cp -p"
+ else
+ symbolic_link="cp"
+ fi
+ cc_set_by_configure="\`case '\$(CC)' in stage*) echo '\$(CC)' | sed -e 's|stage|../stage|g';; *) echo '\$(CC)';; esac\`"
+ stage_prefix_set_by_configure="\`case '\$(STAGE_PREFIX)' in stage*) echo '\$(STAGE_PREFIX)' | sed -e 's|stage|../stage|g';; *) echo '\$(STAGE_PREFIX)';; esac\`"
+fi
+rm -f symtest.tem
+
+out_object_file=`basename $out_file .c`.o
+
+tm_file_list=
+for f in $tm_file; do
+ tm_file_list="${tm_file_list} \$(srcdir)/config/$f"
+done
+
+host_xm_file_list=
+for f in $host_xm_file; do
+ if test $f != "auto-host.h"; then
+ host_xm_file_list="${host_xm_file_list} \$(srcdir)/config/$f"
+ else
+ host_xm_file_list="${host_xm_file_list} auto-host.h"
+ fi
+done
+
+build_xm_file_list=
+for f in $build_xm_file; do
+ if test $f != "auto-build.h"; then
+ if test $f != "auto-host.h"; then
+ build_xm_file_list="${build_xm_file_list} \$(srcdir)/config/$f"
+ else
+ build_xm_file_list="${build_xm_file_list} auto-host.h"
+ fi
+ else
+ build_xm_file_list="${build_xm_file_list} auto-build.h"
+ fi
+done
+
+# Define macro CROSS_COMPILE in compilation
+# if this is a cross-compiler.
+# Also use all.cross instead of all.internal
+# and add cross-make to Makefile.
+cross_overrides="/dev/null"
+if [[ x$host != x$target ]]
+then
+ cross_defines="CROSS=-DCROSS_COMPILE"
+ cross_overrides="${topdir}/cross-make"
+fi
+
+# When building gcc with a cross-compiler, we need to fix a few things.
+# This must come after cross-make as we want all.build to override
+# all.cross.
+build_overrides="/dev/null"
+if [[ x$build != x$host ]]
+then
+ build_overrides="${topdir}/build-make"
+fi
+
+# Expand extra_headers to include complete path.
+# This substitutes for lots of t-* files.
+extra_headers_list=
+if [[ "x$extra_headers" = x ]]
+then true
+else
+ # Prepend ${srcdir}/ginclude/ to every entry in extra_headers.
+ for file in $extra_headers;
+ do
+ extra_headers_list="${extra_headers_list} \$(srcdir)/ginclude/${file}"
+ done
+fi
+
+# Add a definition of USE_COLLECT2 if system wants one.
+# Also tell toplev.c what to do.
+# This substitutes for lots of t-* files.
+if [[ x$use_collect2 = x ]]
+then
+ will_use_collect2=
+ maybe_use_collect2=
+else
+ will_use_collect2="collect2"
+ maybe_use_collect2="-DUSE_COLLECT2"
+fi
+
+# NEED TO CONVERT
+# Set MD_DEPS if the real md file is in md.pre-cpp.
+# Set MD_CPP to the cpp to pass the md file through. Md files use ';'
+# for line oriented comments, so we must always use a GNU cpp. If
+# building gcc with a cross compiler, use the cross compiler just
+# built. Otherwise, we can use the cpp just built.
+md_file_sub=
+if [[ "x$md_cppflags" = x ]]
+then
+ md_file_sub=$srcdir/config/$md_file
+else
+ md_file=md
+fi
+
+# If we have gas in the build tree, make a link to it.
+if [[ -f ../gas/Makefile ]]; then
+ rm -f as; $symbolic_link ../gas/as-new$host_exeext as$host_exeext 2>/dev/null
+fi
+
+# If we have nm in the build tree, make a link to it.
+if [[ -f ../binutils/Makefile ]]; then
+ rm -f nm; $symbolic_link ../binutils/nm-new$host_exeext nm$host_exeext 2>/dev/null
+fi
+
+# If we have ld in the build tree, make a link to it.
+if [[ -f ../ld/Makefile ]]; then
+# if [[ x$use_collect2 = x ]]; then
+# rm -f ld; $symbolic_link ../ld/ld-new$host_exeext ld$host_exeext 2>/dev/null
+# else
+ rm -f collect-ld; $symbolic_link ../ld/ld-new$host_exeext collect-ld$host_exeext 2>/dev/null
+# fi
+fi
+
+# Figure out what assembler alignment features are present.
+AC_MSG_CHECKING(assembler alignment features)
+gcc_cv_as=
+gcc_cv_as_alignment_features=
+gcc_cv_as_gas_srcdir=`echo $srcdir | sed -e 's,gcc$,gas,'`
+if [[ -x as$host_exeext ]]; then
+ # Build using assembler in the current directory.
+ gcc_cv_as=./as$host_exeext
+elif [[ -f $gcc_cv_as_gas_srcdir/configure.in ]]; then
+ # Single tree build which includes gas.
+ for f in $gcc_cv_as_gas_srcdir/configure $gcc_cv_as_gas_srcdir/configure.in $gcc_cv_as_gas_srcdir/Makefile.in
+ do
+ gcc_cv_gas_version=`grep '^VERSION=[[0-9]]*\.[[0-9]]*' $f`
+ if [[ x$gcc_cv_gas_version != x ]]; then
+ break
+ fi
+ done
+ gcc_cv_gas_major_version=`expr "$gcc_cv_gas_version" : "VERSION=\([[0-9]]*\)"`
+ gcc_cv_gas_minor_version=`expr "$gcc_cv_gas_version" : "VERSION=[[0-9]]*\.\([[0-9]]*\)"`
+ if [[ x$gcc_cv_gas_major_version != x -a x$gcc_cv_gas_minor_version != x ]]; then
+ # Gas version 2.6 and later support for .balign and .p2align.
+ # bytes to skip when using .p2align.
+ if [[ "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 6 -o "$gcc_cv_gas_major_version" -gt 2 ]]; then
+ gcc_cv_as_alignment_features=".balign and .p2align"
+ AC_DEFINE(HAVE_GAS_BALIGN_AND_P2ALIGN)
+ fi
+ # Gas version 2.8 and later support specifying the maximum
+ # bytes to skip when using .p2align.
+ if [[ "$gcc_cv_gas_major_version" -eq 2 -a "$gcc_cv_gas_minor_version" -ge 8 -o "$gcc_cv_gas_major_version" -gt 2 ]]; then
+ gcc_cv_as_alignment_features=".p2align including maximum skip"
+ AC_DEFINE(HAVE_GAS_MAX_SKIP_P2ALIGN)
+ fi
+ fi
+elif [[ x$host = x$target ]]; then
+ # Native build.
+ gcc_cv_as=as$host_exeext
+fi
+if [[ x$gcc_cv_as != x ]]; then
+ # Check if we have .balign and .p2align
+ echo ".balign 4" > conftest.s
+ echo ".p2align 2" >> conftest.s
+ if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1; then
+ gcc_cv_as_alignment_features=".balign and .p2align"
+ AC_DEFINE(HAVE_GAS_BALIGN_AND_P2ALIGN)
+ fi
+ rm -f conftest.s conftest.o
+ # Check if specifying the maximum bytes to skip when
+ # using .p2align is supported.
+ echo ".p2align 4,,7" > conftest.s
+ if $gcc_cv_as -o conftest.o conftest.s > /dev/null 2>&1; then
+ gcc_cv_as_alignment_features=".p2align including maximum skip"
+ AC_DEFINE(HAVE_GAS_MAX_SKIP_P2ALIGN)
+ fi
+ rm -f conftest.s conftest.o
+fi
+AC_MSG_RESULT($gcc_cv_as_alignment_features)
+
+# Figure out what language subdirectories are present.
+subdirs=
+for lang in ${srcdir}/*/config-lang.in ..
+do
+ case $lang in
+ ..) ;;
+ # The odd quoting in the next line works around
+ # an apparent bug in bash 1.12 on linux.
+ ${srcdir}/[[*]]/config-lang.in) ;;
+ *) subdirs="$subdirs `echo $lang | sed -e 's,^.*/\([[^/]]*\)/config-lang.in$,\1,'`" ;;
+ esac
+done
+
+# Make gthr-default.h if we have a thread file.
+gthread_flags=
+if [[ $thread_file != single ]]; then
+ rm -f gthr-default.h
+ echo "#include \"gthr-${thread_file}.h\"" > gthr-default.h
+ gthread_flags=-DHAVE_GTHR_DEFAULT
+fi
+AC_SUBST(gthread_flags)
+
+# Make empty files to contain the specs and options for each language.
+# Then add #include lines to for a compiler that has specs and/or options.
+
+lang_specs_files=
+lang_options_files=
+rm -f specs.h options.h
+touch specs.h options.h
+for subdir in . $subdirs
+do
+ if [[ -f $srcdir/$subdir/lang-specs.h ]]; then
+ echo "#include \"$subdir/lang-specs.h\"" >>specs.h
+ lang_specs_files="$lang_specs_files $srcdir/$subdir/lang-specs.h"
+ fi
+ if [[ -f $srcdir/$subdir/lang-options.h ]]; then
+ echo "#include \"$subdir/lang-options.h\"" >>options.h
+ lang_options_files="$lang_options_files $srcdir/$subdir/lang-options.h"
+ fi
+done
+
+# These (without "all_") are set in each config-lang.in.
+# `language' must be a single word so is spelled singularly.
+all_languages=
+all_boot_languages=
+all_compilers=
+all_stagestuff=
+all_diff_excludes=
+all_outputs=Makefile
+# List of language makefile fragments.
+all_lang_makefiles=
+all_headers=
+all_lib2funcs=
+
+# Add the language fragments.
+# Languages are added via two mechanisms. Some information must be
+# recorded in makefile variables, these are defined in config-lang.in.
+# We accumulate them and plug them into the main Makefile.
+# The other mechanism is a set of hooks for each of the main targets
+# like `clean', `install', etc.
+
+language_fragments="Make-lang"
+language_hooks="Make-hooks"
+oldstyle_subdirs=
+
+for s in .. $subdirs
+do
+ if [[ $s != ".." ]]
+ then
+ language=
+ boot_language=
+ compilers=
+ stagestuff=
+ diff_excludes=
+ headers=
+ outputs=
+ lib2funcs=
+ . ${srcdir}/$s/config-lang.in
+ if [[ "x$language" = x ]]
+ then
+ echo "${srcdir}/$s/config-lang.in doesn't set \$language." 1>&2
+ exit 1
+ fi
+ all_lang_makefiles="$all_lang_makefiles ${srcdir}/$s/Make-lang.in ${srcdir}/$s/Makefile.in"
+ all_languages="$all_languages $language"
+ if [[ "x$boot_language" = xyes ]]
+ then
+ all_boot_languages="$all_boot_languages $language"
+ fi
+ all_compilers="$all_compilers $compilers"
+ all_stagestuff="$all_stagestuff $stagestuff"
+ all_diff_excludes="$all_diff_excludes $diff_excludes"
+ all_headers="$all_headers $headers"
+ all_outputs="$all_outputs $outputs"
+ if [[ x$outputs = x ]]
+ then
+ oldstyle_subdirs="$oldstyle_subdirs $s"
+ fi
+ all_lib2funcs="$all_lib2funcs $lib2funcs"
+ fi
+done
+
+# Since we can't use `::' targets, we link each language in
+# with a set of hooks, reached indirectly via lang.${target}.
+
+rm -f Make-hooks
+touch Make-hooks
+target_list="all.build all.cross start.encap rest.encap \
+ info dvi \
+ install-normal install-common install-info install-man \
+ uninstall distdir \
+ mostlyclean clean distclean extraclean maintainer-clean \
+ stage1 stage2 stage3 stage4"
+for t in $target_list
+do
+ x=
+ for l in .. $all_languages
+ do
+ if [[ $l != ".." ]]; then
+ x="$x $l.$t"
+ fi
+ done
+ echo "lang.$t: $x" >> Make-hooks
+done
+
+# If we're not building in srcdir, create .gdbinit.
+
+if [[ ! -f Makefile.in ]]; then
+ echo "dir ." > .gdbinit
+ echo "dir ${srcdir}" >> .gdbinit
+ if [[ x$gdb_needs_out_file_path = xyes ]]
+ then
+ echo "dir ${srcdir}/config/"`dirname ${out_file}` >> .gdbinit
+ fi
+ if [[ "x$subdirs" != x ]]; then
+ for s in $subdirs
+ do
+ echo "dir ${srcdir}/$s" >> .gdbinit
+ done
+ fi
+ echo "source ${srcdir}/.gdbinit" >> .gdbinit
+fi
+
+# Define variables host_canonical and build_canonical
+# because some Cygnus local changes in the Makefile depend on them.
+build_canonical=${build}
+host_canonical=${host}
+target_subdir=
+if [[ "${host}" != "${target}" ]] ; then
+ target_subdir=${target}/
+fi
+AC_SUBST(build_canonical)
+AC_SUBST(host_canonical)
+AC_SUBST(target_subdir)
+
+# If this is using newlib, then define inhibit_libc in
+# LIBGCC2_CFLAGS. This will cause __eprintf to be left out of
+# libgcc.a, but that's OK because newib should have its own version of
+# assert.h.
+inhibit_libc=
+if [[ x$with_newlib = xyes ]]; then
+ inhibit_libc=-Dinhibit_libc
+fi
+AC_SUBST(inhibit_libc)
+
+# Override SCHED_OBJ and SCHED_CFLAGS to enable the Haifa scheduler.
+sched_prefix=
+sched_cflags=
+if [[ x$enable_haifa = xyes ]]; then
+ echo "Using the Haifa scheduler."
+ sched_prefix=haifa-
+ sched_cflags=-DHAIFA
+fi
+AC_SUBST(sched_prefix)
+AC_SUBST(sched_cflags)
+if [[ x$enable_haifa != x ]]; then
+ # Explicitly remove files that need to be recompiled for the Haifa scheduler.
+ for x in genattrtab.o toplev.o loop.o unroll.o *sched.o; do
+ if [[ -f $x ]]; then
+ echo "Removing $x"
+ rm -f $x
+ fi
+ done
+fi
+
+# Nothing to do for FLOAT_H, float_format already handled.
+objdir=`pwd`
+AC_SUBST(objdir)
+
+# Process the language and host/target makefile fragments.
+${CONFIG_SHELL-/bin/sh} $srcdir/configure.frag $srcdir "$subdirs" "$dep_host_xmake_file" "$dep_tmake_file"
+
+# Substitute configuration variables
+AC_SUBST(subdirs)
+AC_SUBST(all_languages)
+AC_SUBST(all_boot_languages)
+AC_SUBST(all_compilers)
+AC_SUBST(all_lang_makefiles)
+AC_SUBST(all_stagestuff)
+AC_SUBST(all_diff_excludes)
+AC_SUBST(all_lib2funcs)
+AC_SUBST(all_headers)
+AC_SUBST(cpp_main)
+AC_SUBST(extra_passes)
+AC_SUBST(extra_programs)
+AC_SUBST(extra_parts)
+AC_SUBST(extra_c_objs)
+AC_SUBST(extra_cxx_objs)
+AC_SUBST(extra_c_flags)
+AC_SUBST(extra_objs)
+AC_SUBST(host_extra_gcc_objs)
+AC_SUBST(extra_headers_list)
+AC_SUBST(dep_host_xmake_file)
+AC_SUBST(dep_tmake_file)
+AC_SUBST(out_file)
+AC_SUBST(out_object_file)
+AC_SUBST(md_file)
+AC_SUBST(tm_file_list)
+AC_SUBST(build_xm_file_list)
+AC_SUBST(host_xm_file_list)
+AC_SUBST(lang_specs_files)
+AC_SUBST(lang_options_files)
+AC_SUBST(thread_file)
+AC_SUBST(gcc_version)
+AC_SUBST(gcc_version_trigger)
+AC_SUBST(local_prefix)
+AC_SUBST(gxx_include_dir)
+AC_SUBST(fixincludes)
+AC_SUBST(build_install_headers_dir)
+AC_SUBST(build_exeext)
+AC_SUBST(host_exeext)
+AC_SUBST(float_format)
+AC_SUBST(will_use_collect2)
+AC_SUBST(maybe_use_collect2)
+AC_SUBST(cc_set_by_configure)
+AC_SUBST(stage_prefix_set_by_configure)
+AC_SUBST(install)
+AC_SUBST(symbolic_link)
+AC_SUBST(cpp_install_dir)
+
+
+AC_SUBST_FILE(target_overrides)
+AC_SUBST_FILE(host_overrides)
+AC_SUBST(cross_defines)
+AC_SUBST_FILE(cross_overrides)
+AC_SUBST_FILE(build_overrides)
+AC_SUBST_FILE(language_fragments)
+AC_SUBST_FILE(language_hooks)
+
+# Echo that links are built
+if [[ x$host = x$target ]]
+then
+ str1="native "
+else
+ str1="cross-"
+ str2=" from $host"
+fi
+
+if [[ x$host != x$build ]]
+then
+ str3=" on a $build system"
+fi
+
+if [[ "x$str2" != x ]] || [[ "x$str3" != x ]]
+then
+ str4=
+fi
+
+echo "Links are now set up to build a ${str1}compiler for ${target}$str4" 1>&2
+
+if [[ "x$str2" != x ]] || [[ "x$str3" != x ]]
+then
+ echo " ${str2}${str3}." 1>&2
+fi
+
+# Truncate the target if necessary
+if [[ x$host_truncate_target != x ]]; then
+ target=`echo $target | sed -e 's/\(..............\).*/\1/'`
+fi
+
+# Configure the subdirectories
+# AC_CONFIG_SUBDIRS($subdirs)
+
+# Create the Makefile
+# and configure language subdirectories
+AC_OUTPUT($all_outputs,
+[
+. $srcdir/configure.lang
+case x$CONFIG_HEADERS in
+xauto-host.h:config.in)
+echo > cstamp-h ;;
+esac
+# If the host supports symlinks, point stage[1234] at ../stage[1234] so
+# bootstrapping and the installation procedure can still use
+# CC="stage1/xgcc -Bstage1/". If the host doesn't support symlinks,
+# FLAGS_TO_PASS has been modified to solve the problem there.
+# This is virtually a duplicate of what happens in configure.lang; we do
+# an extra check to make sure this only happens if ln -s can be used.
+if [[ "$symbolic_link" = "ln -s" ]]; then
+ for d in .. ${subdirs} ; do
+ if [[ $d != .. ]]; then
+ STARTDIR=`pwd`
+ cd $d
+ for t in stage1 stage2 stage3 stage4 include
+ do
+ rm -f $t
+ $symbolic_link ../$t $t 2>/dev/null
+ done
+ cd $STARTDIR
+ fi
+ done
+else true ; fi
+],
+[
+host='${host}'
+build='${build}'
+target='${target}'
+target_alias='${target_alias}'
+srcdir='${srcdir}'
+subdirs='${subdirs}'
+oldstyle_subdirs='${oldstyle_subdirs}'
+symbolic_link='${symbolic_link}'
+program_transform_set='${program_transform_set}'
+program_transform_name='${program_transform_name}'
+dep_host_xmake_file='${dep_host_xmake_file}'
+host_xmake_file='${host_xmake_file}'
+dep_tmake_file='${dep_tmake_file}'
+tmake_file='${tmake_file}'
+thread_file='${thread_file}'
+gcc_version='${gcc_version}'
+gcc_version_trigger='${gcc_version_trigger}'
+local_prefix='${local_prefix}'
+build_install_headers_dir='${build_install_headers_dir}'
+build_exeext='${build_exeext}'
+host_exeext='${host_exeext}'
+out_file='${out_file}'
+gdb_needs_out_file_path='${gdb_needs_out_file_path}'
+SET_MAKE='${SET_MAKE}'
+target_list='${target_list}'
+target_overrides='${target_overrides}'
+host_overrides='${host_overrides}'
+cross_defines='${cross_defines}'
+cross_overrides='${cross_overrides}'
+build_overrides='${build_overrides}'
+cpp_install_dir='${cpp_install_dir}'
+])
diff --git a/contrib/gcc/configure.lang b/contrib/gcc/configure.lang
new file mode 100644
index 0000000..d96b6d8
--- /dev/null
+++ b/contrib/gcc/configure.lang
@@ -0,0 +1,233 @@
+# configure.lang for GNU CC
+# This script is run by configure for configuration of language
+# subdirectories which conform to the old GCC configure mechanism
+# for such subdirectories.
+
+# Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+#This file is part of GNU CC.
+
+#GNU CC 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, or (at your option)
+#any later version.
+
+#GNU CC 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 GNU CC; see the file COPYING. If not, write to
+#the Free Software Foundation, 59 Temple Place - Suite 330,
+#Boston, MA 02111-1307, USA.
+
+savesrcdir=$srcdir
+
+for subdir in . $oldstyle_subdirs
+do
+ # We only want to do this in language subdirs, but we have to handle
+ # the case of $oldstyle_subdirs = "".
+ if [ $subdir = . ]
+ then
+ continue
+ fi
+
+ oldsrcdir=$savesrcdir
+
+ # Re-adjust the path
+ case $oldsrcdir in
+ /*)
+ srcdir=$oldsrcdir/$subdir
+ ;;
+ *)
+ oldsrcdir=../${oldsrcdir}
+ srcdir=$oldsrcdir/$subdir
+ ;;
+ esac
+ mainsrcdir=$oldsrcdir
+ STARTDIR=`pwd`
+ test -d $subdir || mkdir $subdir
+ cd $subdir
+
+ # Create Makefile.tem from Makefile.in.
+ # Make it set VPATH if necessary so that the sources are found.
+ # Also change its value of srcdir.
+ # Also create a .gdbinit file which runs the one in srcdir
+ # and tells GDB to look there for source files.
+ case $srcdir in
+ . | ./$subdir | .././$subdir)
+ rm -f Makefile.tem
+ cp Makefile.in Makefile.tem
+ chmod +w Makefile.tem
+ ;;
+ *)
+ rm -f Makefile.tem
+ echo "VPATH = ${srcdir}" \
+ | cat - ${srcdir}/Makefile.in \
+ | sed "s@^srcdir = \.@srcdir = ${srcdir}@" > Makefile.tem
+ rm -f .gdbinit
+ echo "dir ." > .gdbinit
+ echo "dir ${srcdir}" >> .gdbinit
+ echo "dir ${mainsrcdir}" >> .gdbinit
+ if [ x$gdb_needs_out_file_path = xyes ]
+ then
+ echo "dir ${mainsrcdir}/config/"`dirname ${out_file}` >> .gdbinit
+ fi
+ echo "source ${mainsrcdir}/.gdbinit" >> .gdbinit
+ ;;
+ esac
+
+ # Conditionalize the makefile for this host machine.
+ rm -f Makefile.xx Makefile.ll
+ merged_frags=
+ for f in .. ${host_xmake_file}
+ do
+ if [ -f ${mainsrcdir}/config/$f ]
+ then
+ cat ${mainsrcdir}/config/$f >> Makefile.ll
+ if [ x"${merged_frags}" != x ]
+ then
+ merged_frags="${merged_frags} and "
+ fi
+ merged_frags="${merged_frags}${f}"
+ fi
+ done
+ if [ x"${merged_frags}" != x ]
+ then
+ sed -e "/####host/ r Makefile.ll" Makefile.tem > Makefile.xx
+ echo "Merged ${merged_frags}."
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+ rm -f Makefile.ll
+ fi
+
+ # Add a definition for MAKE if system wants one.
+ case "$SET_MAKE" in
+ ?*)
+ rm -f Makefile.xx
+ (echo "$SET_MAKE"; cat Makefile.tem) >Makefile.xx
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+ esac
+
+ # Add a definition for INSTALL if system wants one.
+ # This substitutes for lots of x-* files.
+ if [ x$build_broken_install = x ]
+ then true
+ else
+ rm -f Makefile.xx
+ abssrcdir=`cd ${srcdir}; pwd`
+ sed "s|^INSTALL = .*|${INSTALL}|" Makefile.tem > Makefile.xx
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+ fi
+
+ # If using -program-transform-name, override the installation names.
+ if [ "x${program_transform_set}" = "xyes" ] ; then
+ sed -e "s/^program_transform_name[ ]*=.*$/program_transform_name =
+$program_transform_name/" \
+ -e "s/^program_transform_cross_name[
+]*=.*$/program_transform_cross_name = $program_transform_name/" \
+ Makefile.tem > Makefile.xx
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+ fi
+
+ # Conditionalize the makefile for this target machine.
+ rm -f Makefile.xx Makefile.ll
+ merged_frags=
+ for f in .. ${tmake_file}
+ do
+ if [ -f ${mainsrcdir}/config/$f ]
+ then
+ cat ${mainsrcdir}/config/$f >> Makefile.ll
+ if [ x"${merged_frags}" != x ]
+ then
+ merged_frags="${merged_frags} and "
+ fi
+ merged_frags="${merged_frags}$f"
+ fi
+ done
+ if [ x"${merged_frags}" != x ]
+ then
+ sed -e "/####target/ r Makefile.ll" Makefile.tem > Makefile.xx
+ echo "Merged ${merged_frags}."
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+ rm -f Makefile.ll
+ fi
+
+ # If the host supports
+ # symlinks, point stage[123] at ../stage[123] so bootstrapping and the
+ # installation procedure can still use CC="stage1/xgcc -Bstage1/".
+ # If the host doesn't support symlinks, FLAGS_TO_PASS has been
+ # modified to solve the problem there.
+ for t in stage1 stage2 stage3 stage4 include
+ do
+ rm -f $t
+ $symbolic_link ../$t $t 2>/dev/null
+ done
+
+ # Remove all formfeeds, since some Makes get confused by them.
+ # Also arrange to give the variables `target', `target_alias',
+ # `host_xmake_file', `tmake_file', `prefix', `local_prefix',
+ # `exec_prefix', `INSTALL_HEADERS_DIR', `exeext'
+ # values in the Makefile from the values they have in this script.
+ rm -f Makefile.xx
+ # Create an empty Makefile.sed first, to work around a Nextstep 3.3 bug.
+ echo 's| ||' > Makefile.sed
+ rm Makefile.sed
+ echo 's| ||' > Makefile.sed
+ echo "s|^target=.*$|target=${target}|" >> Makefile.sed
+ echo "s|^target_alias=.*$|target_alias=${target_alias}|" >> Makefile.sed
+ echo "s|^xmake_file=.*$|xmake_file=${dep_host_xmake_file}|" >> Makefile.sed
+ echo "s|^tmake_file=.*$|tmake_file=${dep_tmake_file}|" >> Makefile.sed
+ echo "s|^version=.*$|version=${version}|" >> Makefile.sed
+ echo "s|^GCC_THREAD_FILE=.*$|GCC_THREAD_FILE=${thread_file}|" >> Makefile.sed
+ echo "s|^prefix[ ]*=.*|prefix = $prefix|" >> Makefile.sed
+ echo "s|^local_prefix[ ]*=.*|local_prefix = $local_prefix|" >> Makefile.sed
+ echo "s|^exec_prefix[ ]*=.*|exec_prefix = $exec_prefix|" >> Makefile.sed
+ echo "s|^INSTALL_HEADERS_DIR[ ]*=.*$|INSTALL_HEADERS_DIR = ${build_install_headers_dir}|" >> Makefile.sed
+ echo "s|^exeext[ ]*=.*$|exeext = ${build_exeext}|" >> Makefile.sed
+ sed -f Makefile.sed Makefile.tem > Makefile.xx
+ rm -f Makefile.tem Makefile.sed
+ mv Makefile.xx Makefile.tem
+
+ # Install Makefile for real, after making final changes.
+ # Define macro CROSS_COMPILE in compilation
+ # if this is a cross-compiler.
+ # Also use all.cross instead of all.internal
+ # and add cross-make to Makefile.
+ if [ x$host != x$target ]
+ then
+ rm -f Makefile.xx
+ echo "CROSS=-DCROSS_COMPILE" > Makefile.xx
+ sed -e "/####cross/ r ${mainsrcdir}/cross-make" Makefile.tem >> Makefile.xx
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+ fi
+
+ # When building gcc with a cross-compiler, we need to fix a few things.
+ # This must come after cross-make as we want all.build to override
+ # all.cross.
+ if [ x$build != x$host ]
+ then
+ rm -f Makefile.xx
+ echo "build= $build" > Makefile.xx
+ echo "host= $host" >> Makefile.xx
+ sed -e "s|objc-runtime$||" \
+ -e "/####build/ r ${mainsrcdir}/build-make" Makefile.tem >> Makefile.xx
+ rm -f Makefile.tem
+ mv Makefile.xx Makefile.tem
+ fi
+
+ rm -f Makefile
+ mv Makefile.tem Makefile
+ echo "Created \`$subdir/Makefile'."
+
+ cd $STARTDIR
+done # end of current-dir SUBDIRS loop
+
+# Restore this, remember we're invoked with `.'.
+srcdir=$savesrcdir
diff --git a/contrib/gcc/convert.c b/contrib/gcc/convert.c
index 17e7552..e03d39b 100644
--- a/contrib/gcc/convert.c
+++ b/contrib/gcc/convert.c
@@ -1,5 +1,5 @@
/* Utility routines for data type conversion for GNU C.
- Copyright (C) 1987, 88, 91, 92, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91-95, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU C.
@@ -20,25 +20,23 @@ Boston, MA 02111-1307, USA. */
/* These routines are somewhat language-independent utility function
- intended to be called by the language-specific convert () functions. */
+ intended to be called by the language-specific convert () functions. */
#include "config.h"
#include "tree.h"
#include "flags.h"
#include "convert.h"
+#include "toplev.h"
/* Convert EXPR to some pointer or reference type TYPE.
EXPR must be pointer, reference, integer, enumeral, or literal zero;
- in other cases error is called. */
+ in other cases error is called. */
tree
convert_to_pointer (type, expr)
tree type, expr;
{
- register tree intype = TREE_TYPE (expr);
- register enum tree_code form = TREE_CODE (intype);
-
if (integer_zerop (expr))
{
expr = build_int_2 (0, 0);
@@ -46,64 +44,64 @@ convert_to_pointer (type, expr)
return expr;
}
- if (form == POINTER_TYPE || form == REFERENCE_TYPE)
- return build1 (NOP_EXPR, type, expr);
-
-
- if (form == INTEGER_TYPE || form == ENUMERAL_TYPE)
+ switch (TREE_CODE (TREE_TYPE (expr)))
{
- if (type_precision (intype) == POINTER_SIZE)
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ return build1 (NOP_EXPR, type, expr);
+
+ case INTEGER_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ if (TYPE_PRECISION (TREE_TYPE (expr)) == POINTER_SIZE)
return build1 (CONVERT_EXPR, type, expr);
- expr = convert (type_for_size (POINTER_SIZE, 0), expr);
- /* Modes may be different but sizes should be the same. */
- if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr)))
- != GET_MODE_SIZE (TYPE_MODE (type)))
- /* There is supposed to be some integral type
- that is the same width as a pointer. */
- abort ();
- return convert_to_pointer (type, expr);
- }
- error ("cannot convert to a pointer type");
+ return
+ convert_to_pointer (type,
+ convert (type_for_size (POINTER_SIZE, 0), expr));
- expr = build_int_2 (0, 0);
- TREE_TYPE (expr) = type;
- return expr;
+ default:
+ error ("cannot convert to a pointer type");
+ return convert_to_pointer (type, integer_zero_node);
+ }
}
/* Convert EXPR to some floating-point type TYPE.
EXPR must be float, integer, or enumeral;
- in other cases error is called. */
+ in other cases error is called. */
tree
convert_to_real (type, expr)
tree type, expr;
{
- register enum tree_code form = TREE_CODE (TREE_TYPE (expr));
-
- if (form == REAL_TYPE)
- return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
- type, expr);
-
- if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
- return build1 (FLOAT_EXPR, type, expr);
-
- if (form == COMPLEX_TYPE)
- return convert (type, fold (build1 (REALPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)), expr)));
-
- if (form == POINTER_TYPE || form == REFERENCE_TYPE)
- error ("pointer value used where a floating point value was expected");
- else
- error ("aggregate value used where a float was expected");
-
- {
- register tree tem = make_node (REAL_CST);
- TREE_TYPE (tem) = type;
- TREE_REAL_CST (tem) = REAL_VALUE_ATOF ("0.0", TYPE_MODE (type));
- return tem;
- }
+ switch (TREE_CODE (TREE_TYPE (expr)))
+ {
+ case REAL_TYPE:
+ return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR,
+ type, expr);
+
+ case INTEGER_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ return build1 (FLOAT_EXPR, type, expr);
+
+ case COMPLEX_TYPE:
+ return convert (type,
+ fold (build1 (REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)), expr)));
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ error ("pointer value used where a floating point value was expected");
+ return convert_to_real (type, integer_zero_node);
+
+ default:
+ error ("aggregate value used where a float was expected");
+ return convert_to_real (type, integer_zero_node);
+ }
}
/* Convert EXPR to some integer (or enum) type TYPE.
@@ -118,34 +116,30 @@ tree
convert_to_integer (type, expr)
tree type, expr;
{
- register tree intype = TREE_TYPE (expr);
- register enum tree_code form = TREE_CODE (intype);
+ enum tree_code ex_form = TREE_CODE (expr);
+ tree intype = TREE_TYPE (expr);
+ int inprec = TYPE_PRECISION (intype);
+ int outprec = TYPE_PRECISION (type);
- if (form == POINTER_TYPE || form == REFERENCE_TYPE)
+ switch (TREE_CODE (intype))
{
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
if (integer_zerop (expr))
expr = integer_zero_node;
else
expr = fold (build1 (CONVERT_EXPR,
type_for_size (POINTER_SIZE, 0), expr));
- intype = TREE_TYPE (expr);
- form = TREE_CODE (intype);
- if (intype == type)
- return expr;
- }
- if (form == INTEGER_TYPE || form == ENUMERAL_TYPE
- || form == BOOLEAN_TYPE || form == CHAR_TYPE)
- {
- register unsigned outprec = TYPE_PRECISION (type);
- register unsigned inprec = TYPE_PRECISION (intype);
- register enum tree_code ex_form = TREE_CODE (expr);
+ return convert_to_integer (type, expr);
- /* If we are widening the type, put in an explicit conversion.
- Similarly if we are not changing the width. However, if this is
- a logical operation that just returns 0 or 1, we can change the
- type of the expression. For logical operations, we must
- also change the types of the operands to maintain type
+ case INTEGER_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ /* If this is a logical operation, which just returns 0 or 1, we can
+ change the type of the expression. For some logical operations,
+ we must also change the types of the operands to maintain type
correctness. */
if (TREE_CODE_CLASS (ex_form) == '<')
@@ -153,6 +147,7 @@ convert_to_integer (type, expr)
TREE_TYPE (expr) = type;
return expr;
}
+
else if (ex_form == TRUTH_AND_EXPR || ex_form == TRUTH_ANDIF_EXPR
|| ex_form == TRUTH_OR_EXPR || ex_form == TRUTH_ORIF_EXPR
|| ex_form == TRUTH_XOR_EXPR)
@@ -162,12 +157,18 @@ convert_to_integer (type, expr)
TREE_TYPE (expr) = type;
return expr;
}
+
else if (ex_form == TRUTH_NOT_EXPR)
{
TREE_OPERAND (expr, 0) = convert (type, TREE_OPERAND (expr, 0));
TREE_TYPE (expr) = type;
return expr;
}
+
+ /* If we are widening the type, put in an explicit conversion.
+ Similarly if we are not changing the width. After this, we know
+ we are truncating EXPR. */
+
else if (outprec >= inprec)
return build1 (NOP_EXPR, type, expr);
@@ -352,71 +353,30 @@ convert_to_integer (type, expr)
return convert (type, get_unwidened (TREE_OPERAND (expr, 0), type));
case COND_EXPR:
- /* Can treat the two alternative values like the operands
- of an arithmetic expression. */
- {
- tree arg1 = get_unwidened (TREE_OPERAND (expr, 1), type);
- tree arg2 = get_unwidened (TREE_OPERAND (expr, 2), type);
-
- if (outprec >= BITS_PER_WORD
- || TRULY_NOOP_TRUNCATION (outprec, inprec)
- || inprec > TYPE_PRECISION (TREE_TYPE (arg1))
- || inprec > TYPE_PRECISION (TREE_TYPE (arg2)))
- {
- /* Do the arithmetic in type TYPEX,
- then convert result to TYPE. */
- register tree typex = type;
-
- /* Can't do arithmetic in enumeral types
- so use an integer type that will hold the values. */
- if (TREE_CODE (typex) == ENUMERAL_TYPE)
- typex = type_for_size (TYPE_PRECISION (typex),
- TREE_UNSIGNED (typex));
-
- /* But now perhaps TYPEX is as wide as INPREC.
- In that case, do nothing special here.
- (Otherwise would recurse infinitely in convert. */
- if (TYPE_PRECISION (typex) != inprec)
- {
- /* Don't do unsigned arithmetic where signed was wanted,
- or vice versa. */
- typex = (TREE_UNSIGNED (TREE_TYPE (expr))
- ? unsigned_type (typex) : signed_type (typex));
- return convert (type,
- fold (build (COND_EXPR, typex,
- TREE_OPERAND (expr, 0),
- convert (typex, arg1),
- convert (typex, arg2))));
- }
- else
- /* It is sometimes worthwhile
- to push the narrowing down through the conditional. */
- return fold (build (COND_EXPR, type,
- TREE_OPERAND (expr, 0),
- convert (type, TREE_OPERAND (expr, 1)),
- convert (type, TREE_OPERAND (expr, 2))));
- }
- }
+ /* It is sometimes worthwhile to push the narrowing down through
+ the conditional and never loses. */
+ return fold (build (COND_EXPR, type, TREE_OPERAND (expr, 0),
+ convert (type, TREE_OPERAND (expr, 1)),
+ convert (type, TREE_OPERAND (expr, 2))));
+ default:
+ break;
}
return build1 (NOP_EXPR, type, expr);
- }
- if (form == REAL_TYPE)
- return build1 (FIX_TRUNC_EXPR, type, expr);
+ case REAL_TYPE:
+ return build1 (FIX_TRUNC_EXPR, type, expr);
- if (form == COMPLEX_TYPE)
- return convert (type, fold (build1 (REALPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)), expr)));
+ case COMPLEX_TYPE:
+ return convert (type,
+ fold (build1 (REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)), expr)));
- error ("aggregate value used where an integer was expected");
-
- {
- register tree tem = build_int_2 (0, 0);
- TREE_TYPE (tem) = type;
- return tem;
- }
+ default:
+ error ("aggregate value used where an integer was expected");
+ return convert (type, integer_zero_node);
+ }
}
/* Convert EXPR to the complex type TYPE in the usual ways. */
@@ -425,48 +385,52 @@ tree
convert_to_complex (type, expr)
tree type, expr;
{
- register enum tree_code form = TREE_CODE (TREE_TYPE (expr));
tree subtype = TREE_TYPE (type);
- if (form == REAL_TYPE || form == INTEGER_TYPE || form == ENUMERAL_TYPE)
+ switch (TREE_CODE (TREE_TYPE (expr)))
{
- expr = convert (subtype, expr);
- return build (COMPLEX_EXPR, type, expr,
+ case REAL_TYPE:
+ case INTEGER_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ return build (COMPLEX_EXPR, type, convert (subtype, expr),
convert (subtype, integer_zero_node));
- }
- if (form == COMPLEX_TYPE)
- {
- tree elt_type = TREE_TYPE (TREE_TYPE (expr));
- if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype))
- return expr;
- else if (TREE_CODE (expr) == COMPLEX_EXPR)
- return fold (build (COMPLEX_EXPR,
- type,
- convert (subtype, TREE_OPERAND (expr, 0)),
- convert (subtype, TREE_OPERAND (expr, 1))));
- else
- {
- expr = save_expr (expr);
+ case COMPLEX_TYPE:
+ {
+ tree elt_type = TREE_TYPE (TREE_TYPE (expr));
+
+ if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype))
+ return expr;
+ else if (TREE_CODE (expr) == COMPLEX_EXPR)
return fold (build (COMPLEX_EXPR,
type,
- convert (subtype,
- fold (build1 (REALPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)),
- expr))),
- convert (subtype,
- fold (build1 (IMAGPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)),
- expr)))));
- }
- }
+ convert (subtype, TREE_OPERAND (expr, 0)),
+ convert (subtype, TREE_OPERAND (expr, 1))));
+ else
+ {
+ expr = save_expr (expr);
+ return
+ fold (build (COMPLEX_EXPR,
+ type, convert (subtype,
+ fold (build1 (REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr))),
+ convert (subtype,
+ fold (build1 (IMAGPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr)))));
+ }
+ }
- if (form == POINTER_TYPE || form == REFERENCE_TYPE)
- error ("pointer value used where a complex was expected");
- else
- error ("aggregate value used where a complex was expected");
-
- return build (COMPLEX_EXPR, type,
- convert (subtype, integer_zero_node),
- convert (subtype, integer_zero_node));
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ error ("pointer value used where a complex was expected");
+ return convert_to_complex (type, integer_zero_node);
+
+ default:
+ error ("aggregate value used where a complex was expected");
+ return convert_to_complex (type, integer_zero_node);
+ }
}
diff --git a/contrib/gcc/cp/ChangeLog b/contrib/gcc/cp/ChangeLog
index 420e25d..5102e32 100644
--- a/contrib/gcc/cp/ChangeLog
+++ b/contrib/gcc/cp/ChangeLog
@@ -1,9473 +1,11057 @@
-Thu Aug 22 23:47:38 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+Sun Mar 14 02:38:07 PST 1999 Jeff Law (law@cygnus.com)
- * Version 2.7.2.3 released.
+ * egcs-1.1.2 Released.
-Mon Apr 29 00:27:53 1996 Jason Merrill <jason@yorick.cygnus.com>
-
- * lex.c (real_yylex): Fix handling of __PRETTY_FUNCTION__ like C
- frontend.
-
-Thu Oct 26 16:45:58 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-
- * errfn.c: Include stdio.h.
- (cp_sprintf): Take out decl of sprintf, and cast sprintf to errorfn*.
-
-Mon Nov 20 14:06:28 1995 Mike Stump <mrs@cygnus.com>
-
- * Version 2.7.2 released.
-
-Mon Nov 20 14:05:00 1995 Mike Stump <mrs@cygnus.com>
-
- * g++.c (pfatal_with_name): Add missing third argument to concat.
-
-Thu Oct 26 13:59:54 1995 Mike Stump <mrs@cygnus.com>
-
- * init.c (expand_aggr_init): Handle cv qualifiers on the object's
- type.
-
-Sun Nov 12 18:09:35 1995 Mike Stump <mrs@cygnus.com>
-
- * Version 2.7.1 released.
-
-Thu Nov 2 17:02:47 1995 Jason Merrill <jason@yorick.cygnus.com>
-
- * call.c (convert_harshness): Handle references to arrays.
-
-Fri Oct 27 14:20:21 1995 Jason Merrill <jason@yorick.cygnus.com>
-
- * typeck.c (comp_target_types): Check multi-level pointer
- conversions in both directions.
-
-Tue Oct 17 21:39:05 1995 Jason Merrill <jason@yorick.cygnus.com>
-
- * parse.y (explicit_instantiation): Fix 'extern template' with no
- return type.
-
-Mon Oct 16 14:35:20 1995 Jason Merrill <jason@yorick.cygnus.com>
+Sun Feb 21 20:38:00 1999 H.J. Lu (hjl@gnu.org)
- * parse.y (explicit_instantiation): Support automatic instantiation
- of constructors.
- (named_class_head_*): Support out-of-class definition of nested
- types.
-
-Wed Oct 11 12:20:56 1995 Mike Stump <mrs@cygnus.com>
-
- * search.c (envelope_add_decl): New routine. Fix so that
- methods are hidden in the same way that other members are.
- (dfs_pushdecls): Cleanup and move functionality out of line,
- into envelope_add_decl.
-
-Tue Oct 10 15:46:01 1995 Mike Stump <mrs@cygnus.com>
-
- * typeck.c (mark_addressable): Only call assemble_external if we
- have started the output file.
-
-Tue Oct 10 11:27:18 1995 Jason Merrill <jason@yorick.cygnus.com>
-
- * decl.c (start_function): Fix earlier cv-quals change.
-
-Mon Oct 9 23:53:05 1995 Mike Stump <mrs@cygnus.com>
-
- * parse.y (complex_direct_notype_declarator): Only push the class if
- we are not already in the class.
-
-Mon Oct 9 11:22:03 1995 Doug Evans <dje@canuck.cygnus.com>
-
- * decl.c (duplicate_decls): Call merge_machine_decl_attributes.
- Update olddecl's attributes too.
- (grokdeclarator): #if 0 out call to build_decl_attribute_variant.
- * typeck.c (common_type): Call merge_machine_type_attributes.
-
-Fri Oct 6 14:44:27 1995 Mike Stump <mrs@cygnus.com>
-
- * typeck.c (mark_addressable): Add missing call to
- assemble_external.
+ * decl2.c (start_objects): Make file scope constructors and
+ destructors local to the file if ASM_OUTPUT_CONSTRUCTOR and
+ ASM_OUTPUT_DESTRUCTOR are defined.
-Wed Oct 4 22:05:23 1995 Jeff Law (law@hurl.cygnus.com
+Sat Feb 20 15:08:42 1999 Jeffrey A Law (law@cygnus.com)
- * cp/decl.c (deplicate_decls): Merge in deferred output
- status for variables.
- * cp/tree.c (tree_copy_lang_decl_for_deferred_output): New
- function to copy the g++ specific parts of a DECL node.
- (tree_copy_lang_type_for_deferred_output): Similarly for
- TYPE nodes.
+ 1999-01-25 Martin von Löwis <loewis@informatik.hu-berlin.de>
+ * tree.c (equal_functions): New function.
+ (ovl_member): Call it.
-Wed Oct 4 15:06:39 1995 Mike Stump <mrs@cygnus.com>
+Sat Feb 6 17:00:48 1999 Jeffrey A Law (law@cygnus.com)
- * decl.c (store_parm_decls): Make sure the unwinder start comes
- before the exception specification start.
- * except.c (expand_exception_blocks): Make sure the unwinder end
- comes after the terminate protected catch clause region and after
- the end of the exception specification region.
+ * typeck2.c: Update email addresses.
-Wed Oct 4 12:47:02 1995 Jason Merrill <jason@yorick.cygnus.com>
+1998-11-16 Jason Merrill <jason@yorick.cygnus.com>
- * lex.c (real_yylex): Fix identifier case for linemode.
- (handle_sysv_pragma): Don't abort when we see a pragma we don't
- recognize.
-
-Tue Oct 3 14:09:46 1995 Mike Stump <mrs@cygnus.com>
-
- * decl.c (store_parm_decls): Add a call to start_eh_unwinder.
- * except.c (init_exception_processing): __throw doesn't take any
- arguments.
- (expand_builtin_throw): Ditto. Always use Pmode, instead of SImode
- for all pointers. Use expand_builtin_return_addr to unwind the
- first level off the stack.
- (do_unwind): Always use Pmode, instead of SImode for all pointers.
- (expand_exception_blocks): Add a call to end_eh_unwinder.
- (start_eh_unwinder, end_eh_unwinder): New routines to build machine
- independent stack unwinders for function/method calls.
-
-Mon Oct 2 17:20:42 1995 Mike Stump <mrs@cygnus.com>
+ * typeck2.c (my_friendly_abort): Don't fatal twice in a row.
- * tree.c (unsave_expr_now): Make sure we process the argument list
- of any called functions. Fixes incorrect code generation for
- cleanups.
+1998-11-15 Jason Merrill <jason@yorick.cygnus.com>
-Mon Oct 2 13:04:16 1995 Mike Stump <mrs@cygnus.com>
+ * typeck2.c (my_friendly_abort): Add URL in the other case, too.
- * typeck.c (get_member_function_from_ptrfunc): Save function if it
- needs it. Cures core dump on things like (this->*(f()))().
+1998-11-13 Jason Merrill <jason@yorick.cygnus.com>
-Sat Sep 23 22:51:25 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * decl.c (start_function): Conform to gcc cv-quals convention (no
- expression has a cv-qualified type) in RESULT_DECLs.
- * method.c (make_thunk): Ditto.
-
-Fri Sep 22 10:21:13 1995 Mike Stump <mrs@cygnus.com>
-
- * decl.c (pushtag): Add in the namespace name for the tag.
-
-Thu Sep 21 13:11:13 1995 Mike Stump <mrs@cygnus.com>
-
- * parse.y (maybe_base_class_list, base_class_list, base_class,
- base_class_access_list): Make sure we see the typenames for base
- classes.
- * lex.c (see_typename): Instead of failing to see a typename when
- there is no next token, perfer a typename, and get the next token.
+ * rtti.c (synthesize_tinfo_fn): Call import_export_decl here.
+ (get_tinfo_fn): Not here.
-Wed Sep 20 12:35:27 1995 Michael Meissner <meissner@cygnus.com>
+1998-11-08 Mark Mitchell <mark@markmitchell.com>
- * decl.c (init_decl_processing): Add __builtin_expect.
+ * decl.c (grokdeclarator): Tighten checks for invalid
+ destructors. Improve error-messages and error-recovery.
+ * decl2.c (check_classfn): Don't assume that mangled destructor
+ names contain type information.
-Tue Sep 19 16:48:11 1995 Mike Stump <mrs@cygnus.com>
+1998-11-02 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (cp_convert_to_pointer): Don't allow leftover conversions to
- or from pointer to member functions, they must all be handled before
- this point.
+ * decl2.c (import_export_decl): Call import_export_class.
-Fri Sep 15 17:14:47 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
+1998-10-28 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (resolve_offset_ref): Fix wording of non-static member
- being referenced as a static.
+ * class.c (finish_struct_1): Don't complain about non-copy
+ assignment ops in union members.
-Fri Sep 15 12:39:11 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * class.c (build_vtable): Don't pass at_eof to import_export_vtable.
+ (prepare_fresh_vtable): Likewise.
+ (finish_struct_1): Don't call import_export_class.
+ * decl2.c (finish_vtable_vardecl): Do import/export stuff.
+ (finish_prevtable_vardecl): Lose.
+ (finish_file): Don't call it.
+ * pt.c (instantiate_class_template): Likewise.
- * typeck.c (build_indirect_ref): Only bash pointer if we actually
- call build_expr_type_conversion.
+1998-10-23 Martin von Löwis <loewis@informatik.hu-berlin.de>
-Thu Sep 14 18:24:56 1995 Jason Merrill <jason@deneb.cygnus.com>
-
- * cvt.c (build_expr_type_conversion): Handle conversion from
+ * parse.y (condition): Convert VAR_DECL from reference to indirect
reference.
- * typeck.c (build_indirect_ref): Avoid infinite recursion.
-
-Thu Sep 14 17:23:28 1995 Mike Stump <mrs@cygnus.com>
-
- * decl.c (expand_start_early_try_stmts): New routine to start a try
- block at the start of the function, for function-try-blocks.
- * cp-tree.h (expand_start_early_try_stmts): Declare it.
- * parse.y (function_try_block): Use it, instead of doing it here, as
- we don't want to include rtl.h here, as that conflicts with RETURN
- in the parser.
-
-Wed Sep 13 18:32:24 1995 Mike Stump <mrs@cygnus.com>
-
- * lex.c (reinit_parse_for_block): Support saving inline
- function-try-blocks, uses peekyylex.
- * parse.y (eat_saved_input): New rule, permit the parser to see that
- END_OF_SAVED_INPUT is ok, as it can see this when parsing the
- handlers of a function-try-block.
- (fndef): Use it.
- (component_decl): Make sure TRY and RETURN can come after fn.def2.
- * spew.c (peekyylex): New routine to peek at what will come next.
-
-Wed Sep 13 16:52:06 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * typeck.c (comptypes): Tighten up comparisons of template type
- parms.
-
- * decl.c (duplicate_decls): Turn off whining about virtual functions
- redeclared inline for now.
-
-Wed Sep 13 11:13:40 1995 Mike Stump <mrs@cygnus.com>
-
- * decl.c (store_in_parms): New routine to put things before we
- put base inits.
- * cp-tree.h (store_in_parms): Declare it.
- * decl.c (store_parm_decls): Use it to makr sure the starting of the
- eh spec comes before base inits.
- (finish_function): Use sequences instead of the obsolete
- reorder_insns.
- * parse.y (fndef): Enhance readability and maintainability. Update
- to include function_try_block syntax.
- (function_try_block): Add.
-
-Tue Sep 12 17:43:07 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-
- * call.c (convert_harshness): Use comptypes, not ==, to check if
- TYPE and PARMTYPE are equivalent on a function type.
-
-Tue Sep 12 17:31:33 1995 Douglas Rupp (drupp@cs.washington.edu)
- * Make-lang.in (cc1plus) : Removed unnecessary $(exeext).
+1998-10-18 Jason Merrill <jason@yorick.cygnus.com>
-Mon Sep 11 23:24:07 1995 Mike Stump <mrs@cygnus.com>
+ * method.c (hack_identifier): Just return a member function.
- * except.c (expand_throw): Never allocate storage for thrown pointer
- to objects.
+1998-10-18 Martin von Löwis <loewis@informatik.hu-berlin.de>
-Mon Sep 11 19:36:45 1995 Mike Stump <mrs@cygnus.com>
+ * decl2.c (validate_nonmember_using_decl): Fix using-directives of
+ std if std is ignored.
- * except.c (expand_start_catch_block): Pointers to objects come
- back from catch matching already dereferenced, don't dereference
- again.
+1998-10-14 Jason Merrill <jason@yorick.cygnus.com>
-Mon Sep 11 15:46:28 1995 Mike Stump <mrs@cygnus.com>
+ * spew.c (yylex): Clear looking_for_typename if we got
+ 'enum { ... };'.
- * except.c (expand_throw): Only decay the throw expression, don't do
- any default conversions. This is so that one can throw and catch
- characters, and not have them match integers.
+1998-10-13 Jason Merrill <jason@yorick.cygnus.com>
-Mon Sep 11 13:46:45 1995 Mike Stump <mrs@cygnus.com>
+ * tinfo2.cc (fast_compare): Remove.
+ (before): Just use strcmp.
+ * tinfo.cc (operator==): Just use strcmp.
- * error.c (dump_aggr_type): Deal with anonymous unions that don't
- have a TYPE_NAME.
+1998-10-12 Jason Merrill <jason@yorick.cygnus.com>
-Fri Sep 8 20:40:27 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
+ * tinfo.cc (operator==): Always compare names.
- * lex.c (handle_sysv_pragma): Deal with getting a comma from yylex.
+1998-10-12 Jason Merrill <jason@yorick.cygnus.com>
-Fri Sep 8 15:51:41 1995 Mike Stump <mrs@cygnus.com>
+ * inc/typeinfo: Add #pragma interface.
+ (operator!=): Just call operator==.
+ * tinfo.cc: Add #pragma implementation.
+ (operator==): Move from inc/typeinfo and tinfo2.cc.
- * except.c (expand_end_eh_spec): Handle empty EH specifications.
+ * typeck2.c (my_friendly_abort): Add URL.
-Fri Sep 8 15:27:22 1995 Mike Stump <mrs@cygnus.com>
+1998-10-05 Martin von Löwis <loewis@informatik.hu-berlin.de>
- * cp-tree.h (expand_start_eh_spec): Declare new routine.
- (expand_end_eh_spec): Ditto.
- * decl.c (store_parm_decls): Call expand_start_eh_spec to process
- exception specifications.
- * except.c (expand_leftover_cleanups): Remove unused parameter.
- (expand_end_catch_block): Ditto.
- (expand_exception_blocks): Ditto.
- (expand_start_eh_spec): New routine to mark the start of an
- exception specification region.
- (expand_end_eh_spec): New routine to mark the end of an exception
- specification region.
- (expand_exception_blocks): Call expand_end_eh_spec to process
- exception specifications.
+ * method.c (build_decl_overload_real): Clear
+ numeric_output_need_bar after __.
-Fri Sep 8 14:40:48 1995 Per Bothner <bothner@kalessin.cygnus.com>
+1998-10-04 Jason Merrill <jason@yorick.cygnus.com>
- * lex.c (do_identifier): Use global binding in preference of
- dead for local variable.
+ * decl.c (cp_finish_decl): Make statics in extern inlines and
+ templates common, if possible and the target doesn't support weak
+ symbols.
-Wed Sep 6 19:32:59 1995 Mike Stump <mrs@cygnus.com>
+1998-10-03 Jason Merrill <jason@yorick.cygnus.com>
- * cp-tree.h (build_exception_variant): Remove used first argument.
- * decl.c (duplicate_decls): Ditto.
- (grokfndecl): Ditto.
- (revert_static_member_fn): Ditto.
- * decl2.c (grok_method_quals): Ditto.
- * tree.c (build_exception_variant): Ditto.
- * typeck.c (common_type): Ditto.
- * decl2.c (grokclassfn): After changing the type, call
- build_exception_variant, if necessary.
+ * decl2.c (merge_functions): Remove duplicates.
-Tue Sep 5 15:56:27 1995 Mike Stump <mrs@cygnus.com>
+ * typeck.c (build_conditional_expr): Only fold if ifexp is an
+ INTEGER_CST.
- * except.c (expand_throw): Run cleanups for the throw expression.
+Fri Oct 2 02:07:26 1998 Mumit Khan <khan@xraylith.wisc.edu>
-Wed Aug 30 15:24:38 1995 Stephen L. Favor (sfavor@tigger.intecom.com)
+ * parse.y (nomods_initdcl0): Set up the parser stack correctly.
- * except.c (expand_builtin_throw): Moved gen_label_rtx calls beyond
- the store_parm_decls call which does initialization in the emit_*
- code concerning label numbering.
-
-Thu Aug 31 09:01:07 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c (expand_internal_throw): Let the frontend be responsible
- for managing all frontend EH parameters, the backend routine only
- needs to deal with backend values. type and value are no longer
- passed to __throw.
- (init_exception_processing): Ditto.
- (expand_start_all_catch): Ditto.
- (expand_end_all_catch): Ditto.
- (expand_leftover_cleanups): Ditto.
- (expand_end_catch_block): Ditto.
- (expand_builtin_throw): Ditto.
- (expand_throw): Ditto.
-
-Tue Aug 29 15:04:36 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * cp-tree.h (DECL_REAL_CONTEXT): Give the real declaration context
- for a decl.
- * decl.c (cp_finish_decl): Use it.
-
-Tue Aug 29 10:30:27 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c (expand_internal_throw): Oops, almost forgot type and
- value are now trees.
-
-Mon Aug 28 17:57:45 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-
- Fix the attribute handling to make sure they get noted before we
- create the function's RTL, in case they can affect that.
- * decl.c (grokfndecl): New arg ATTRLIST. Run
- cplus_decl_attributes before creating the decl's rtl.
- (grokdeclarator): New arg ATTRLIST, passed down into grokfndecl.
- (shadow_tag, groktypename, start_decl, start_method): Pass a
- NULL_TREE to grokdeclarator's new last arg.
- * decl2.c (grokfield): New arg ATTRLIST, passed into grokdeclarator.
- (grokbitfield, grokoptypename): Pass a NULL_TREE to
- grokdeclarator's new last arg.
- * except.c (expand_start_catch_block): Likewise.
- * pt.c (process_template_parm, end_template_decl,
- do_function_instantiation): Likewise.
- * cp-tree.h (grokfield): Add arg.
- (grokdeclarator): Move the prototype from here...
- * decl.h: ...to here.
- * lex.c (cons_up_default_function): Pass NULL_TREE to grokfield
- ATTRLIST argument.
- * parse.y: Create a list for the grokfield arg where appropriate,
- and pass it down instead of calling cplus_decl_attributes.
-
-Mon Aug 28 15:07:24 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c: Always allow turning on exception handling. Allow cross
- compilations to use EH.
-
-Thu Aug 24 17:39:24 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c (saved_pc, saved_throw_type, saved_throw_value): Use
- trees, instead of rtxs, and don't depend on using special machine
- dependent registers.
- (expand_internal_throw): Ditto.
- (init_exception_processing): Ditto.
- (expand_start_all_catch): Ditto.
- (expand_end_all_catch): Ditto.
- (expand_start_catch_block): Ditto.
- (expand_leftover_cleanups): Ditto.
- (expand_end_catch_block): Ditto.
- (expand_builtin_throw): Ditto.
- (expand_throw): Ditto.
-
-Wed Aug 23 17:25:51 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * cvt.c (build_expr_type_conversion): Handle conversions to
- reference types.
-
-Wed Aug 23 15:33:59 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c (do_unwind): Work around backend bug with -fpic.
-
-Tue Aug 22 17:20:07 1995 Per Bothner <bothner@kalessin.cygnus.com>
-
- * decl2.c (flag_new_for_scope): Add a new mode that follows ANSI
- for-scoping, but supports (and warns about) old programs.
- Make the new mode (with value 1) the default.
- (lang_f_options): The on-value for flag_new_for_scope is now 2.
- * cp-tree.h (DECL_DEAD_FOR_LOCAL, DECL_ERROR_REPORTED): New macros
- (DECL_SHADOWED_FOR_VAR): Likewise.
- * decl.c (struct binding_level): New fields dead_vars_from_for
- and is_for_scope.
- (note_level_for_for): New function.
- (poplevel): Special processing if is_for_scope.
- (pushdecl): Warn if for-scope variable shadows local.
- * lex.c (do_identifier): Handle old (non-ANSI) for scoping,
- and warn if conflicts.
- * parse.y (FOR): Call note_level_for_for.
-
-Mon Aug 21 10:28:31 1995 Jason Merrill <jason@deneb.cygnus.com>
-
- * decl2.c (import_export_inline): Class interface hackery does not
- apply to synthesized methods.
+1998-08-25 Jason Merrill <jason@yorick.cygnus.com>
-Sun Aug 20 16:29:00 1995 Mike Stump <mrs@cygnus.com>
-
- * search.c (virtual_context): Find the right context more often.
- Solves a `recoverable compiler error, fixups for virtual function'
- problem.
-
-Sun Aug 20 13:53:24 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c (expand_start_all_catch): Ensure that we always transfer
- control to the right EH handler, by rethrowing the end label on the
- region, instead of hoping we are nested and falling through.
- (expand_leftover_cleanups): Ditto.
- (end_protect): Since we now rethrow the end label, put a
- nop after it, so that outer regions are recognized.
- * init.c (build_vec_delete_1): New routine to handle most of vector
- deleting, all code moved here from build_vec_delete.
- (build_array_eh_cleanup): Use build_vec_delete_1 to do all the real
- work.
- (expand_vec_init): If the array needs partial destructing, setup an
- EH region to handle it.
- (build_vec_delete): Move lots of code to build_vec_delete_1, use
- build_vec_delete_1 to do the grunt work.
-
-Sat Aug 19 14:25:33 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-
- Handle decl attributes properly for function definitions without
- previous attribute-loaded declarations.
- * decl.c (start_function): New arg ATTRS. Add a call to
- cplus_decl_attributes with it before we create the RTL.
- * cp-tree.h (start_function): Update prototype.
- * parse.y (fn.def1): Pass ATTRS into start_function instead of
- trying to call cplus_decl_attributes too late. Pass a NULL_TREE
- for other use.
- * decl2.c (finish_file): Pass NULL_TREE as fourth arg to
- start_function.
- * method.c (synthesize_method): Likewise.
- * except.c (expand_builtin_throw): Likewise for start on __throw.
-
-Sat Aug 19 13:36:08 1995 Mike Stump <mrs@cygnus.com>
-
- * class.c (set_rtti_entry): Turn on -fvtable-thunk -frtti support.
- This changes -fvtable-thunks vtable layout, so a recompile will be
- necessary, if you use -fvtable-thunks.
- (get_vtable_entry): Use n, instead of i to be consistent with the
- rest of the compiler.
- (get_vtable_entry_n): Ditto.
- (add_virtual_function): Add a slot for the tdesc, if -fvtable-thunks
- are being used.
- (finish_struct_1): Ditto.
- (skip_rtti_stuff): New routine to collapse similar code from many
- different parts of the compiler. I think I got them all.
- (modify_one_vtable): Use it.
- (fixup_vtable_deltas1): Ditto.
- (override_one_vtable): Ditto.
- * decl2.c (mark_vtable_entries): Ditto.
- * tree.c (debug_binfo): Ditto.
- * search.c (expand_upcast_fixups): Ditto.
- (get_abstract_virtuals_1): Ditto. Use virtuals, instead of tmp to
- consistent with the rest of the compiler.
- (get_abstract_virtuals): Ditto.
- * cp-tree.h (skip_rtti_stuff): New routine, declare it.
- * gc.c (build_headof): Support -fvtable-thunk and -frtti together.
- (build_typeid): Ditto.
- (build_classof): Remove old style way of doing rtti. Remove support
- for `classof' and `headof'.
- * gxx.gperf: Ditto.
- * hash.h: Ditto.
- * parse.y: Ditto.
-
-Fri Aug 18 17:31:58 1995 Jason Merrill <jason@deneb.cygnus.com>
-
- * decl.c (start_function): Clear ctor_label and dtor_label.
-
- * class.c (finish_struct_1): Fix handling of access decls.
-
-Tue Aug 15 19:21:54 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * class.c (finish_struct): Only do minimal processing here, so it
- can be used for class template definitions, as well.
- (finish_struct_1): New function with the rest of the code.
-
-Tue Aug 15 09:46:16 1995 Mike Stump <mrs@cygnus.com>
-
- * class.c (prepare_fresh_vtable): On second though, always build the
- offset (see Aug 10 change), unless -fvtable-thunks is given. It
- does this by calling the new routine set_rtti_entry.
- (finish_struct): Ditto.
- (set_rtti_entry): New routine to update the rtti information at the
- start of the vtable.
-
-Mon Aug 14 12:21:22 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-
- * error.c (dump_decl, case IDENTIFIER_NODE): Only work on a dtor
- if it's declared in the C++ language spec.
- (dump_function_decl): Likewise.
- (dump_function_name): Likewise.
- (ident_fndecl): Make sure we got something back from lookup_name.
- * decl.c (start_function): Likewise.
-
-Fri Aug 11 16:52:15 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * call.c (build_method_call): Don't call build_new when calling a
- constructor without an instance.
-
-Thu Aug 10 20:00:17 1995 Mike Stump <mrs@cygnus.com>
-
- * class.c (prepare_fresh_vtable): Always build the offset to the
- complete object, as it doesn't cost much. This allows dynamic_cast
- to void * to work when -frtti isn't given.
- (finish_struct): Ditto.
-
-Thu Aug 10 16:31:28 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c (build_eh_type): Split out some functionality to new
- routine named build_eh_type_type.
- (build_eh_type_type): New routine.
- (expand_start_catch_block): Use build_eh_type_type, as we never want
- the dynamic type of the catch parameter, just the static type.
- Fixes core dumps when -frtti is used and one catchs pointers to
- classes.
-
-Thu Aug 10 14:55:29 1995 Mike Stump <mrs@cygnus.com>
+ * decl.c (duplicate_decls): Don't complain about different
+ exceptions from an internal decl even if pedantic.
- * except.c (expand_builtin_throw): Since we now use normal calling
- conventions for __throw, we have to remove the first layer off the
- stack, so that the next context we search for handlers is the outer
- context instead of the context that had the call to __throw, if we
- don't immediately find the desired context.
-
-Tue Aug 8 17:44:23 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * tree.c (cp_expand_decl_cleanup): Returns int, not tree.
- * cp-tree.h: Update.
+1998-08-24 Gavin Romig-Koch <gavin@cygnus.com>
- * parse.y (template_type_parm): Add support for `typename'.
-
-Tue Aug 8 12:06:31 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c (expand_internal_throw): New internal routine to throw a
- value.
- (expand_end_all_catch, expand_leftover_cleanups): All throwers
- changed to use `expand_internal_throw' instead of jumping to throw
- label.
- (expand_end_catch_block, expand_throw): Ditto.
- (throw_label): Removed.
- (expand_builtin_throw): Changed so that EH parameters are passed by
- normal function call conventions. Completes Aug 4th work.
+ * typeck.c (c_expand_return): Handle the case that valtype
+ is wider than the functions return type.
-Fri Aug 4 17:17:08 1995 Mike Stump <mrs@cygnus.com>
+1998-08-24 Martin von Löwis <loewis@informatik.hu-berlin.de>
- * cp-tree.h (expand_builtin_throw): Declare it.
- * decl2.c (finish_file): Call expand_builtin_throw.
- * except.c (make_first_label): Remove.
- (init_exception_processing): Don't use a LABEL_REF for throw_label,
- instead use a SYMBOL_REF, this is so that we don't use LABEL_REFs in
- other functions that don't really appear in those functions. This
- solves a problem where cc1plus consumed exponential amounts of
- memory when -Wall was used.
- (expand_end_all_catch, expand_leftover_cleanups,
- expand_end_catch_block, expand_throw): Change all uses of
- throw_label to match new style.
- (do_unwind): Rename parameter to inner_throw_label, as it is now
- different from throw_label. Also, assume that our caller will wrap
- the passed label with a LABEL_REF, if needed.
- (expand_builtin_throw): Make external, change so that the generated
- throw is now a real function.
- (expand_exception_blocks): Never generate throw code inside another
- function.
-
-Fri Aug 4 12:20:02 1995 Mike Stump <mrs@cygnus.com>
-
- * decl.c (grokdeclarator): Move checking of mutable const objects
- and mutable static objects down, as we might decide during parsing
- to unset staticp or constp (for example, when const is part of the
- object being pointed to).
-
-Thu Aug 3 17:13:43 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c (output_exception_table_entry): Enhance portability to
- weird machines.
- (emit_exception_table): Ditto.
-
-Thu Aug 3 16:41:38 1995 Mike Stump <mrs@cygnus.com>
-
- * typeck.c (build_ptrmemfunc): Handle casting of pointer to
- non-virtual member functions.
-
-Wed Aug 2 11:58:25 1995 Mike Stump <mrs@cygnus.com>
-
- * gc.c (build_typeid): Strip cv qualifiers so that const T&, T&, T
- and const T all match.
-
-Wed Aug 2 11:25:33 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c (build_eh_type): Strip cv qualifiers so that const T&,
- T&, T and const T all match.
-
-Tue Aug 1 14:20:16 1995 Mike Stump <mrs@cygnus.com>
-
- * except.c: Fix up comments, cleanup code and eliminate exceptNode,
- exceptStack, exceptstack, push_except_stmts, pop_except_stmts,
- new_except_stack, push_last_insn, pop_last_insn, insn_save_node and
- InsnSave. Also, numerous speed improvements, and correctness
- improvements. Double faulting in all situations should now be
- handled correctly.
- (expand_start_all_catch): Instead of having many terminate protected
- regions, just have one.
- (expand_start_catch_block): No longer have to protect
- false_label_rtx, as it isn't used for EH region marking.
- (expand_end_catch_block): Expand out EH cleanups here by using
- expand_leftover_cleanups.
- (expand_end_all_catch): Use sequences instead of playing with insn
- links directly.
- (expand_exception_blocks): Ditto. Also protect all catch clauses
- with one terminate region.
+ * search.c (my_tree_cons): Reimplement.
-Mon Jul 31 13:24:30 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-08-17 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (report_type_mismatch): Don't talk about an object
- parameter for non-methods.
+ * decl.c (finish_enum): Also set TYPE_SIZE_UNIT.
+ * class.c (finish_struct_bits): Likewise.
-Sun Jul 30 13:13:02 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-08-17 Mark Mitchell <mark@markmitchell.com>
- * class.c (finish_struct): Catch private and protected members of
- anonymous unions here.
- * decl2.c (finish_anon_union): And here.
- * parse.y: Instead of here.
+ * pt.c (check_explicit_specialization): Don't abort on bogus
+ explicit instantiations.
- * errfn.c (ARGSLIST): Support passing four args.
- * error.c (cv_as_string): New function.
- (cp_printers): Add it.
- * call.c (build_method_call): Report 'const' at end of pseudo-decl.
+1998-08-14 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (report_type_mismatch): Deal with a bad_arg of 0.
+ * rtti.c (get_tinfo_fn): Don't mess with the context for now.
- * init.c (expand_aggr_init): Handle volatile objects, too.
+1998-08-13 Mumit Khan <khan@xraylith.wisc.edu>
-Sat Jul 29 13:42:03 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (import_export_class): Don't use dllexport
+ attribute as a heuristic.
- * decl.c (struct binding_level): Keep list of incomplete decls.
- (print_binding_level): Use list_length to count them.
- (pushdecl): Build up the list.
- (hack_incomplete_structures): Walk it and prune completed decls.
+1998-07-29 Jason Merrill <jason@yorick.cygnus.com>
-Fri Jul 28 15:26:44 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (push_overloaded_decl): Use current_namespace instead of
+ DECL_CONTEXT (decl) to determine where we go.
- * typeck.c (comp_target_types): Don't check const and volatile for
- function types.
- (comp_ptr_ttypes_real): Ditto.
+ * decl.c (lookup_name_real): Fix typo.
-Thu Jul 27 15:40:48 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-07-28 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (comp_target_types): Fix.
+ * class.c (finish_struct_1): Convert integer_zero_node to
+ ssizetype before passing it to set_rtti_entry.
+ * typeck2.c (initializer_constant_valid_p): Allow conversion of 0
+ of any size to a pointer.
-Thu Jul 27 15:10:48 1995 Mike Stump <mrs@cygnus.com>
+1998-07-27 Jason Merrill <jason@yorick.cygnus.com>
- * cp-tree.h (unsave_expr_now, build_unsave_expr,
- cp_expand_decl_cleanup): Declare new routines.
- * decl.c (cp_finish_decl, store_parm_decls,
- hack_incomplete_structures): Change all cals from
- expand_decl_cleanup to cp_expand_decl_cleanup.
- * gc.c (protect_value_from_gc): Ditto.
- * expr.c (cplus_expand_expr): Handle UNSAVE_EXPRs.
- * tree.c (unsave_expr): New routine to build an UNSAVE_EXPR.
- (unsave_expr_now): Backend routine used by tree expander.
- (cp_expand_decl_cleanup): Wrap second argument in an UNSAVE_EXPR to
- work around a limitation in the backend. The backend uses the
- cleanups multiple times, on disjoint control flows, so we cannot
- pass unsaved SAVE_EXPRs to the backend.
- * tree.def (UNSAVE_EXPR): New tree code.
- * typeck.c (c_expand_return): Move goto/return code up inside
- conditional, as we don't always want to do this, we only want to do
- this when we don't otherwise finish with this control flow.
+ * typeck2.c (build_functional_cast): Handle default-initialization.
-Thu Jul 27 10:38:43 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
+ * call.c (build_over_call): Pass 1 to popclass.
- * parse.y (typespec): Only complain about typeof if we're not
- getting it from a system header.
+ * parse.y (direct_notype_declarator): Add precedence declaration
+ to notype_unqualified_id case.
+ * Makefile.in (EXPECT): Adjust.
-Thu Jul 27 10:26:23 1995 Doug Evans <dje@canuck.cygnus.com>
+ * tree.c (ovl_member): Fix for single function in OVL.
- Clean up prefix attribute handling.
- * parse.y (reserved_declspecs): Link prefix attributes with declspecs.
- (declmods): Likewise.
- (all rules that reference typed_declspecs and declmods): Call
- split_specs_attrs or strip_attrs to separate declspecs and attrs.
- (lang_extdef): Delete resetting of prefix_attributes.
- (template_def, notype_declarator rule): Use NULL_TREE for
- prefix_attributes.
- (condition): Use NULL_TREE for prefix_attributes.
- (setattrs): Deleted.
- (nomods_initdcl0): Set prefix_attributes to NULL_TREE.
- (component_decl): Delete resetting of prefix_attributes.
- (component_decl_1, notype_components rule): Use NULL_TREE for
- prefix_attributes.
- (simple_stmt): Delete resetting of prefix_attributes.
+1998-07-24 Jason Merrill <jason@yorick.cygnus.com>
-Mon Jul 24 13:37:53 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (lookup_name_real): OK, do return the from_obj value
+ unless got_object depends on template parms.
- * call.c (convert_harshness): Deal with reference conversions before
- others. Actually do array->pointer decay. Call comp_target_types
- with pointer types rather than their targets.
+ * parse.y (nested_name_specifier_1): Pull out the TYPE_MAIN_VARIANT.
- * typeck.c (comp_target_types): Avoid assigning D const * to B *.
+ * pt.c (coerce_template_parms): Also complain about local enums.
-Mon Jul 24 08:54:46 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
+ * cp-tree.h: Add prototype for set_identifier_local_value.
+ * decl.c (set_identifier_local_value_with_scope): Make static,
+ prototype.
+ * search.c (covariant_return_p): Likewise.
+ * except.c (build_terminate_handler, alloc_eh_object): Likewise.
- * pt.c (to_be_restored): Move decl to global scope.
+ * call.c (build_method_call): Only pull out the type of a destructor
+ if it's a template type parm.
+ * decl.c (lookup_name_real): Never return the from_obj value.
-Sat Jul 22 12:22:11 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-07-23 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (start_decl): Put back clearing of DECL_IN_AGGR_P.
+ * except.c (process_start_catch_block_old): Call start_decl_1 for
+ catch parm.
+ * decl.c (start_decl_1): Avoid duplicate error.
-Fri Jul 21 17:09:02 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * init.c (expand_default_init): Only perform the initialization if
+ it will do something.
- * decl.c (grokdeclarator): Downgrade error about 'extern int A::i'
- to pedwarn.
+1998-07-23 H.J. Lu (hjl@gnu.org)
- * pt.c (instantiate_template): Also avoid instantiation if the
- function has already been declared to be a specialization.
+ * parse.y (base_class): Check for invalid base class.
- * decl2.c (check_classfn): Ignore cname argument, and return the
- matching function.
+1998-07-23 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (start_decl): Handle declarations of member functions
- outside of the class (i.e. specialization declarations).
+ * decl2.c (import_export_template): Fold in...
+ (import_export_class): ...to here. Handle dllimport/export.
-Thu Jul 20 10:34:48 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * class.c (build_vtable): Pass at_eof to import_export_vtable.
+ (prepare_fresh_vtable): Likewise.
+ * decl2.c (import_export_class): Split out...
+ (finish_prevtable_vardecl): From here.
+ * class.c (finish_struct_1): Call import_export_class if at_eof.
- * class.c (finish_struct): Don't mess with the type of bitfields.
+ * decl.c (start_function): #if 0 mysterious code I wrote and have
+ forgotten why.
+ * rtti.c (get_tinfo_fn): If this is for a class type, set
+ DECL_CONTEXT.
- * various.c: s/TYPE_POINTER_TO/build_pointer_type/.
+1998-07-22 Jason Merrill <jason@yorick.cygnus.com>
-Thu Jul 20 01:43:10 1995 Mike Stump <mrs@cygnus.com>
+ * inc/exception: Change terminate and unexpected to ().
- * init.c (expand_aggr_init): Assume LOOKUP_ONLYCONVERTING if init
- is not a parameter list (TREE_LIST).
- (expand_default_init): If LOOKUP_ONLYCONVERTING is set, then set
- LOOKUP_NO_CONVERSION so that we don't allow two-level conversions,
- but don't set it otherwise.
+ * parse.y (named_class_head_sans_basetype_defn): A
+ named_class_head_sans_basetype followed by '{' or ':' is a defn.
-Wed Jul 19 20:32:01 1995 Mike Stump <mrs@cygnus.com>
+1998-07-21 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (expand_default_init): Don't allow two-level conversions
- during construction.
+ * tree.c (canonical_type_variant): New fn to handle arrays.
+ * cp-tree.h (CANONICAL_TYPE_VARIANT): Remove.
+ * pt.c (unify, default case): Also fold arg. Fix array bounds case.
+ * method.c (process_overload_item): Use build_overload_value for
+ arrays.
-Wed Jul 19 18:06:37 1995 Mike Stump <mrs@cygnus.com>
+1998-07-19 Jason Merrill <jason@yorick.cygnus.com>
- * gc.c (build_headof): The type of dyncasting to a pointer to cv
- void, should be pointer to cv void.
+ * lex.c (do_identifier): Look for class value even if we don't
+ have a global value. Do implicit declaration if parsing is 2.
+ * semantics.c (finish_call_expr): Pass 2 if we're doing Koenig
+ lookup.
-Wed Jul 19 17:25:43 1995 Mike Stump <mrs@cygnus.com>
+1998-07-19 Mark Mitchell <mark@markmitchell.com>
- * gc.c (build_dynamic_cast): Allow casting in const.
+ * decl.c (pushtag): Revert previous change.
+ * pt.c (lookup_template_class): Don't put out debugging
+ information for types that use template parameters.
-Wed Jul 19 16:34:27 1995 Mike Stump <mrs@cygnus.com>
-
- * typeck.c (build_const_cast): If we are passed error_mark_node,
- return it.
-
-Wed Jul 19 15:24:48 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-
- * class.c (push_nested_class): Make sure TYPE is non-nil.
-
- * cvt.c (type_promotes_to): Watch for error_mark_node on the
- incoming TYPE.
-
-Wed Jul 19 13:23:12 1995 Gerald Baumgartner <gb@alexander.cs.purdue.edu>
-
- * cp-tree.h (SIGTABLE_VT_OFF_NAME): Renamed from SIGTABLE_OFFSET_NAME.
- (SIGTABLE_VB_OFF_NAME): New macro.
- (vt_off_identifier): Renamed from offset_identifier.
- (vb_off_identifier): Added extern declaration.
-
- * decl.c (vt_off_identifier): Renamed from offset identifier.
- (vb_off_identifier): New variable to hold the identifier for the
- sigtable field vb_off.
- (init_decl_processing): Initialize vb_off_identifier.
- Renamed vt_off_identifier from offset_identifier.
- * sig.c (build_signature_method_call): Renamed offset_identifier and
- local variable offset to vt_off_identifer and vt_off, respecitively.
- * sig.c (build_signature_table_constructor): Renamed offset to vt_off.
-
- * decl.c (init_decl_processing): Add vb_off field to
- sigtable_entry_type. Reorder fields so that pfn gets properly
- aligned at a 64 bit boundary on the Alpha.
- * sig.c (build_signature_table_constructor): Build the constructor
- according to the new layout. Set the vb_off field to -1 for now.
-
- * decl.c (init_decl_processing): Align sigtable_entry_type on word
- boundaries instead of double word boundaries to save space.
-
-Tue Jul 18 16:58:37 1995 Mike Stump <mrs@cygnus.com>
-
- * cvt.c (cp_convert): Always call build_cplus_new for a ctor.
-
-Tue Jul 18 14:24:53 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-
- * parse.y (opt.component_decl_list): Only forbid private/protected
- in anonymous unions. We need to make this know when the type is
- defined for an object, to not give the error.
-
-Mon Jul 17 14:22:44 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-
- * parse.y (opt.component_decl_list): Don't allow access control
- as private or protected for union members.
-
-Sun Jul 16 14:01:00 1995 Jim Wilson <wilson@chestnut.cygnus.com>
-
- * lex.c (check_newline): For 'p' case, move goto skipline line to
- before end brace for 'pragma'.
-
-Fri Jul 7 13:55:58 1995 Mike Stump <mrs@cygnus.com>
-
- * g++.1: Tiny updates.
-
-Fri Jul 7 13:05:20 1995 Mike Stump <mrs@cygnus.com>
-
- * decl.c (cp_finish_decl): Only destruct local static variables if
- they are constructed, and only construct the first time control
- passes completely through its declaration (if not initialized with a
- constant-expression).
- (expand_static_init): Ditto.
-
-Wed Jul 5 14:05:04 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
+ * decl.c (pushtag): Don't put out debugging information for
+ compiler-generated typedefs.
+
+ * error.c (dump_type_real): Don't crash when presented with
+ intQI_type_node or the like.
- * typeck.c (comptypes, case OFFSET_REF): If either offset basetype
- is a TEMPLATE_TYPE_PARM, give a match.
+ * semantics.c (finish_translation_unit): Fix spelling error in
+ comment.
-Mon Jul 3 15:17:20 1995 Steve Chamberlain <sac@slash.cygnus.com>
+1998-07-17 Jason Merrill <jason@yorick.cygnus.com>
- * g++.c (sys/file.h): Remove change of Jun 28.
+ * decl.c (lookup_name_real): Pull out single function here.
+ (select_decl): Not here.
+ (unqualified_namespace_lookup): Use CP_DECL_CONTEXT.
-Fri Jun 30 15:42:57 1995 Mike Stump <mrs@cygnus.com>
+ * decl.c (qualify_lookup): Tweak again.
- * method.c (build_overload_value): Handle encoding of null pointer
- constants (or any pointer with a constant numeric value) for
+ * pt.c (lookup_template_class): Don't mess with the context of the
+ instantiation.
+ * decl2.c (current_decl_namespace): Remove special handling for
templates.
-Fri Jun 30 13:45:51 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
+ * pt.c (tsubst, case FUNCTION_DECL): Fix getting complete args for
+ a member template specialization.
- * call.c (convert_harshness): Add QUAL_CODE when we're faced with
- const vs non-const for void conversions.
+ * tree.c (ovl_member): Use decls_match to compare functions.
+ * decl.c (decls_match): Check the context of a function.
-Fri Jun 30 10:19:52 1995 Mike Stump <mrs@cygnus.com>
+ * parse.y (primary): Use notype_unqualified_id instead of IDENTIFIER
+ in Koenig lookup support rules.
+ * semantics.c (finish_call_expr): Handle the new cases.
- * except.c (expand_start_all_catch): Fix problem with finding an
- outer nested try block when there is no code to separate it from an
- inner try block.
+ * typeck.c (build_x_function_call): Handle overloaded methods.
-Fri Jun 30 02:22:26 1995 Mike Stump <mrs@cygnus.com>
+ * decl.c (grokvardecl): Don't call build_static_name for extern "C".
- * search.c (dfs_pushdecls): Consume 2 or 3 orders of magnitude less
- memory please when virtual bases are used.
+1998-07-16 Mark Mitchell <mark@markmitchell.com>
-Thu Jun 29 19:03:47 1995 Mike Stump <mrs@cygnus.com>
+ * semantics.c (finish_object_call_expr): Revert previous change.
+ * call.c (build_new_method_call): Likewise. Instead, convert
+ TYPE_DECLs to IDENTIFIERs here, in the presence of templates.
- * class.c (build_vbase_path): Avoid testing things that cannot be
- null to see if they are null.
- * cvt.c (convert_pointer_to_vbase): Remove code that doesn't work.
- * decl.c (finish_function): Pass a type into the new
- convert_pointer_to_vbase instead of a binfo.
- * search.c (convert_pointer_to_vbase): Rewritten to use get_vbase
- and convert_pointer_to_real.
- (expand_indirect_vtbls_init): Use convert_pointer_to_vbase instead
- of the more cryptic call to get_vbase.
+1998-07-16 Jason Merrill <jason@yorick.cygnus.com>
-Thu Jun 29 09:35:05 1995 Mike Stump <mrs@cygnus.com>
+ * decl.c (qualify_lookup): Handle templates.
- * decl.c (BOOL_TYPE_SIZE): Fix broken SLOW_BYTE_ACCESS check.
+ * decl2.c (do_using_directive): Don't pass ancestor.
+ * decl.c (push_using_directive): Calculate ancestor.
-Thu Jun 29 03:43:55 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (do_nonmember_using_decl): Allow for type shadowing.
+ * decl.c (pushdecl): Move type shadowing handling from here...
+ (duplicate_decls): ...to here.
+ * decl.c (set_identifier_local_value_with_scope): New fn.
+ (pushdecl): Use it.
+ (set_identifier_local_value, lookup_type_current_level): New fns.
+ * decl2.c (do_local_using_decl): Handle types and binding level
+ stuff properly.
- * pt.c (instantiate_template): Don't strip 'this' twice.
+ * init.c (build_offset_ref): Don't call mark_used on an OVERLOAD.
+ * decl.c (select_decl): Extract a lone function from an OVERLOAD.
+ (lookup_namespace_name): Likewise.
+ * typeck.c (build_unary_op): Not here anymore.
- * pt.c (coerce_template_parms): Allow null pointer constants.
+ * decl2.c (do_class_using_decl): Make sure we get an identifier.
+ * class.c (handle_using_decl): Ignore TYPE_DECLs.
- * decl.c (revert_static_member_fn): But only if DECL_ARGUMENTS is
- set.
+ * decl.c (qualify_lookup): New fn.
+ (lookup_name_real): Use it.
-Wed Jun 28 23:34:58 1995 Steve Chamberlain <sac@slash.cygnus.com>
+1998-07-16 Martin v. Loewis <loewis@informatik.hu-berlin.de>
- * g++.c (pfatal_with_name): Use my_strerror to get error
- string.
- (sys/file.h): Include if HAVE_FILE_H defined.
+ * decl2.c (add_using_namespace): When directly using a namespace
+ that was indirect before, promote it.
-Wed Jun 28 18:39:03 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cp-tree.h (LOOKUP_PREFER_TYPES, LOOKUP_PREFER_NAMESPACES,
+ LOOKUP_PREFER_BOTH, LOOKUP_NAMESPACES_ONLY, LOOKUP_TYPES_ONLY,
+ LOOKUP_QUALIFIERS_ONLY, LOOKUP_TEMPLATES_EXPECTED): New macros.
+ * decl.c (select_decl): Replace two flag parameters by one.
+ (unqualified_namespace_lookup): Likewise, pass flag.
+ (lookup_flags): New function.
+ (lookup_name_real): Compute flags, pass them.
+ (lookup_namespace_name): Call with zero-flag.
+ * decl2.c (ambiguous_decl): Add flag parameter, complain only
+ according to flags.
+ (lookup_using_namespace, qualified_lookup_using_namespace):
+ Add flag parameter, pass them through.
+ * lex.c (do_scoped_id): Call with zero-flag.
- * decl.c (revert_static_member_fn): Also remove 'this' from
- DECL_ARGUMENTS.
- * decl2.c (check_classfn): Don't revert this function until we get a
- match.
+1998-07-16 Jason Merrill <jason@yorick.cygnus.com>
-Wed Jun 28 14:07:27 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
+ * typeck.c (convert_for_assignment): Use comptypes.
- * parse.y (component_decl): Clear PREFIX_ATTRIBUTES here.
+1998-07-16 Mark Mitchell <mark@markmitchell.com>
-Wed Jun 28 11:05:13 1995 Mike Stump <mrs@cygnus.com>
+ * semantics.c (finish_object_call_expr): Move test for the
+ function called being a TYPE_DECL to ...
+ * call.c (build_new_method_call): Here.
- * decl2.c (finish_file): Handle global vector news.
- * init.c (build_new): Encode vector news so that later we will know
- how many elements there are.
+1998-07-15 Jason Merrill <jason@yorick.cygnus.com>
-Mon Jun 26 13:38:06 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (arg_assoc_class): Also look at template arguments, if any.
+ (arg_assoc): Handle error_mark_node and multiple levels of TREE_LIST.
- * expr.c (cplus_expand_expr): Don't mess with temp slots.
+ * lex.c (looking_for_typename): Don't initialize.
- * decl2.c (warn_if_unknown_interface): Don't crash if tinst_for_decl
- returns null.
+ * decl2.c (ambiguous_decl): Clarify error message.
- * decl2.c (check_classfn): Use revert_static_member_fn.
- * decl.c (revert_static_member_fn): Diagnose static member functions
- declared const or volatile.
+ * decl.c (push_using_directive): Iterate over namespaces used
+ indirectly.
- * decl2.c (grokfield): Check for missing default args here, too.
- (check_default_args): Function to do the checking.
- * decl.c (pushdecl): Use it.
+1998-07-15 Martin v. Löwis <loewis@informatik.hu-berlin.de>
- * decl.c (pushdecl): Don't warn about shadowing a member of `this'
- if there is no `this'.
+ * decl2.c (add_using_namespace): Iterate over namespaces used
+ indirectly.
-Sun Jun 25 11:34:25 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (lookup_name_real): Accept namespace aliases as locals.
+ (cat_namespace_levels): Ignore aliases.
+ (duplicate_decls): Ignore duplicate aliases.
+ * decl2.c (do_namespace_alias): Process block level namespace
+ aliases. Store alias with pushdecl. Remove odr errors.
+ * parse.y (namespace_alias): New non-terminal.
+ (extdef): Use it.
- * call.c (build_method_call): Downgrade 'called before definition'
- to a warning, as it ought to go away after Monterey.
+1998-07-15 Jason Merrill <jason@yorick.cygnus.com>
-Sat Jun 24 14:18:42 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (arg_assoc_type): Handle METHOD_TYPE like FUNCTION_TYPE.
+ Handle TEMPLATE_TYPE_PARM.
+ (arg_assoc): Rewrite.
- * pt.c (coerce_template_parms): Don't do extra checking on pointer
- to member arguments.
+ * pt.c (complete_template_args): Don't look at the context unless
+ we have to.
- * class.c (finish_struct): const and reference members don't prevent
- a class from being an aggregate.
+ * method.c (build_decl_overload_real): Fix namespace handling.
- * class.c (finish_struct): Signatures are always aggregates.
+ * typeck.c (build_unary_op): Extract a lone function from an
+ OVERLOAD.
-Fri Jun 23 17:20:29 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (build_scoped_method_call): Handle getting a namespace
+ for basetype in a destructor call.
+ (check_dtor_name): Handle enums.
- * decl2.c (check_classfn): Improve error message.
+ * parse.y (using_directive): New nonterminal.
+ (extdef, simple_stmt): Use it.
- * pt.c (tsubst): Handle PROMOTE_PROTOTYPES.
+1998-07-14 Martin von Löwis <loewis@informatik.hu-berlin.de>
-Thu Jun 22 01:50:42 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (add_function): Move error message ...
+ (arg_assoc_namespace): ... from here.
- * typeck.c (comptypes): Don't ignore method quals.
+1998-07-14 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): Non-abstract virtuals are always USED.
+ * parse.y (namespace_qualifier): Fix multiple level handling.
+ * decl2.c (namespace_ancestor): Use CP_DECL_CONTEXT.
+ (arg_assoc): Don't skip the first argument of a function.
- * decl.c (build_ptrmemfunc_type): The underlying union type isn't
- IS_AGGR_TYPE, either.
- * class.c (finish_struct): Use CLASSTYPE_NON_AGGREGATE instead.
- * cp-tree.h: Ditto.
+ * call.c (joust): Don't warn about "confusing" conversions to the
+ same type.
- * cp-tree.h (lang_type): Add aggregate.
- (CLASSTYPE_AGGREGATE): New macro.
- (TYPE_NON_AGGREGATE_CLASS): Ditto.
- * class.c (finish_struct): Determine whether a class is an
- aggregate.
- * decl.c (cp_finish_decl): Check TYPE_NON_AGGREGATE_CLASS instead of
- TYPE_NEEDS_CONSTRUCTING.
- * typeck2.c (digest_init): Check TYPE_NON_AGGREGATE_CLASS for
- subobjects, too.
+1998-07-14 Martin von Löwis <loewis@informatik.hu-berlin.de>
- * pt.c (tsubst, PARM_TYPE): Propagate DECL_ARTIFICIAL.
-
- * decl.c (start_function): For pre-parsed functions, layout all of
- the parm decls again.
- (grokvardecl): TREE_PUBLIC depends on DECL_THIS_EXTERN, not
- DECL_EXTERNAL.
-
- * pt.c (coerce_template_parms): Improve checking for invalid
- template parms.
-
-Wed Jun 21 12:01:16 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-
- * decl.c (grokdeclarator): Forbid declaration of a static member
- with the same name as its enclosing class.
-
-Mon Jun 19 10:28:14 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * decl.c (finish_function): Clear current_class_decl.
+ * class.c (push_nested_class): Complain about namespaces.
+ * decl.c (start_decl): Enter the object's namespace.
+ (cp_finish_decl): Leave it.
+ (grokdeclarator): Likewise.
+ * decl2.c (check_decl_namespace): New function.
+ (finish_file): Call it.
+ * parse.y (complex_direct_notype_declarator): Set complexity
+ of namespace-qualified ids to -1, enter the namespace.
- * typeck.c (build_conditional_expr): Use convert (boolean_type_node
- instead of truthvalue_conversion.
+ * method.c (build_template_decl_overload): Expect _DECL as first
+ parameter. Put context temporarily into current_namespace.
+ * pt.c (check_explicit_specialization): Change caller.
+ (tsubst): Likewise.
- * class.c (finish_struct): A data member with the same name as the
- class doesn't suppress constructors.
+ * init.c (build_offset_ref): Call mark_used and
+ convert_from_reference for namespace members.
-Fri Jun 16 18:11:39 1995 Gerald Baumgartner (gb@alexander.cs.purdue.edu)
+Mon Jul 13 23:25:28 1998 Martin von Lvwis <loewis@informatik.hu-berlin.de>
- * decl.c (start_function): If current_class_decl is a signature
- pointer, don't dereference it but set C_C_D to current_class_decl.
+ * search.c (my_tree_cons): The bitfield is at index 2.
-Fri Jun 16 17:06:28 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Mon Jul 13 17:21:01 1998 Nick Clifton <nickc@cygnus.com>
- * decl.c (duplicate_decls): Complain about virtual functions
- redeclared to be inline.
+ * lang-options.h: Format changed to work with new --help support
+ in gcc/toplev.c
+
+1998-07-12 Martin von Löwis <loewis@informatik.hu-berlin.de>
+
+ * decl2.c (build_expr_from_tree): Change calls of do_identifier.
+ Do Koenig lookup in CALL_EXPR.
+ (arg_assoc): Handle error_mark.
+ * lex.c (is_global): New function.
+ (do_identifier): Expect arguments for Koenig lookup.
+ * parse.y (primary): Add rules for calls of unqualified function calls.
+ (do_id): Change call of do_identifier.
+ * pt.c (finish_stmt_expr): Likewise.
+ * semantics.c (finish_id_expr): Likewise.
+ (finish_call_expr): Add integer parameter to indicate
+ argument-dependent lookup.
+
+ * decl.c (struct binding_level): New field using_directives.
+ (push_using_decl): Not sorry anymore.
+ (push_using_directive): New function.
+ (lookup_tag): Use CP_DECL_CONTEXT to iterate.
+ (unqualified_namespace_lookup): New function, code from ...
+ (lookup_name_real): ... here.
+ * decl2.c (lookup_using_namespace): Pass using list instead of
+ initial scope.
+ (validate_nonmember_using_decl): New function.
+ (do_nonmember_using_decl): New function.
+ (do_toplevel_using_decl): Use them.
+ (do_local_using_decl): New function.
+ (do_using_directive): Support block-level directives.
+ * parse.y (simple_stmt): Support using declarations and
+ directives.
+ (namespace_qualifier, namespace_using_decl): New non-terminals.
+
+ * xref.c (classname): New function.
+ (GNU_xref_hier): Change class and base parameters to tree.
+ * decl.c (xref_baseypes): Change caller.
+ * friend.c (make_friend_class): Likewise.
+
+1998-07-12 Kriang Lerdsuwanakij <lerdsuwa@scf-fs.usc.edu>
+
+ * typeck.c (comptypes, case TEMPLATE_TEMPLATE_PARM): Add parameter
+ comparison.
+
+ * pt.c (for_each_template_parm, case TEMPLATE_DECL): If it is a
+ template template parameter, record its use.
+ (for_each_template_parm, case TEMPLATE_TEMPLATE_PARM): Traverse
+ its template arguments if exists.
+
+ * pt.c (coerce_template_template_parms): New function equivalent
+ to coerce_template_parms when IS_TMPL_PARM is true.
+ (coerce_template_parms): Use it. Remove the IS_TMPL_PARM parameter,
+ all callers changed.
+
+ (coerce_template_parms): Access ARGLIST properly when creating a
+ new vector. Only accept implicit TYPE_DECL as valid argument for
+ a template template parameter when it is a base class of
+ current_class_type. Don't display error message when COMPLAIN is
+ false.
+
+1998-07-12 Klaus Kaempf (kkaempf@progis.de)
+
+ * repo.c (get_base_filename): Use file_name_nondirectory.
+ (open_repo_file): Ditto.
+ * cp-tree.h (file_name_nondirectory): Add prototype.
+
+1998-07-12 Jason Merrill <jason@yorick.cygnus.com>
+
+ * friend.c (do_friend): Pull the identifier out of declarator.
+ Use cp_error and friends.
+ * decl2.c (qualified_lookup_using_namespace): Fix call to
+ purpose_member.
+ * decl.c (lookup_name_real): Don't call complete_type on a namespace.
+ (grokvardecl): Use DECL_CLASS_SCOPE_P.
+ * cvt.c (convert_pointer_to_real): Check for error_mark_node sooner.
+ * class.c (warn_hidden): Fix for OVERLOAD.
+ From grahams@rcp.co.uk:
+ * cp-tree.h (DEFARG_NODE_CHECK): New macro.
+ (DEFARG_LENGTH, DEFARG_POINTER): Use it.
+
+Sun Jul 12 01:20:57 1998 Jeffrey A Law (law@cygnus.com)
+
+ * g++.1 (-traditional): Remove duplicated documentation.
+
+1998-07-11 Mark Mitchell <mark@markmitchell.com>
+
+ * method.c (flush_repeats): Add nrepeats parameter.
+ (issue_nrepeats): Likewise.
+ (is_back_referenceable_type): New function. Don't back-reference
+ TEMPLATE_TYPE_PARMs as well as simple types like integers.
+ (build_mangled_name_for_type): Likewise.
+ (build_mangled_name_for_type_with_Gcode): Likewise.
+ (lasttype): Remove.
+ (nrepeats): Likewise.
+ (Nrepeats): Likewise.
+ (start_squangling): Don't clear the variables removed above.
+ (end_squangling): Likewise.
+ (flush_repeats): Tidy. Use nrepeats parameter rather than
+ Nrepeats global.
+ (issue_nrepeats): Likewise, but with nrepeats global. Use
+ is_backreferenceable_type.
+ (build_overload_nested_name): Tidy. Add comment. Use
+ build_mangled_name_for_type.
+ (build_underscore_int): Comment.
+ (build_overload_scope_ref): Use build_mangled_name_for_type.
+ (build_overload_int): Likewise.
+ (build_template_template_parm_names): Tidy.
+ (build_template_parm_names): Use build_mangled_name_for_type.
+ (build_overload_identifier): Add comments.
+ (build_mangled_name_for_type_with_Gcode): Split out from
+ build_mangled_name.
+ (build_mangled_name_for_type): Use it.
+ (build_mangled_name): Rework to use build_mangled_name_for_type
+ and to not use global nrepeats/Nrepeats. Tidy.
+ (process_modifiers): Tidy.
+ (check_btype): Use is_backreferenceable_type. Add comment.
+ Rename `node' to `type'.
+ (process_overload_item): Set numeric_output_need_bar here.
+ Use build_mangled_name_for_type. Tidy.
+ (build_decl_overload_real): Tidy. Don't use Nrepeats. Use
+ build_mangled_name_for_type.
+
+ * pt.c (push_template_decl_real): Don't look at DECL_TEMPLATE_INFO
+ for TYPE_DECLs.
+
+1998-07-08 Vladimir N. Makarov <vmakarov@cygnus.com>
+
+ * cp-tree.h (warn_long_long): Define.
+ * decl.c (grokdeclarator): Add flag `warn_long_long' as guard for
+ warning "ANSI C++ does not support `long long'".
+ * decl2.c (warn_long_long): Define.
+ (lang_decode_option): Parse -Wlong-long, -Wno-long-long options.
+
+1998-07-07 Jason Merrill <jason@yorick.cygnus.com>
+
+ * decl.c (xref_tag): Handle attributes between 'class' and name.
+ * parse.y (aggr): Likewise.
+ * semantics.c (finish_class_definition): Likewise.
+ * Makefile.in (EXPECTED): Adjust.
+
+ * cp-tree.h: Declare flag_optional_diags and warn_multichar.
+ * decl2.c: Define them.
+ (lang_decode_option): Handle them.
+ * lang-options.h: Add -foptional-diags.
+ * class.c (finish_struct): Don't complain about multiple meanings of
+ name if -fno-optional-diags.
+ * decl.c (pushdecl_class_level): Likewise.
+ * lex.c (real_yylex): Check warn_multichar.
+
+1998-07-06 Jason Merrill <jason@yorick.cygnus.com>
+
+ * decl.c (lookup_tag): Use CP_DECL_CONTEXT.
+
+ * tree.c (make_binfo): Fix length.
+
+1998-06-30 Benjamin Kosnik <bkoz@bliss.nabi.net>
+
+ * decl2.c (lang_decode_option): Remove warn_template_debugging.
+ * lang-options.h: Ditto.
-Fri Jun 16 13:20:38 1995 Mike Stump <mrs@cygnus.com>
+Mon Jun 29 20:17:40 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * except.c (build_eh_type_type_ref): Remove unused variable `susp'.
+ (process_start_catch_block): Likewise for variables
+ `false_label_rtx', `call_rtx' and `return_value_rtx'.
+
+1998-06-29 Brendan Kehoe <brendan@cygnus.com>
+
+ * tree.c (build_srcloc): Make sure we allocate this node on the
+ permanent obstack.
+
+Sat Jun 27 23:34:18 1998 Fred Fish <fnf@ninemoons.com>
+
+ * g++spec.c (NEED_MATH_LIBRARY): Define to 1 if not already defined.
+ (lang_specific_driver): Initialize need_math with NEED_MATH_LIBRARY.
+ (lang_specific_driver): Only add -lm automatically if need_math is
+ nonzero.
- * decl.c (get_unique_name): New routine to name unnamed namespaces.
- (push_namespace): Use get_unique_name for naming unnamed namespaces.
+Sat Jun 27 12:22:56 1998 Jeffrey A Law (law@cygnus.com)
-Fri Jun 16 15:07:29 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * Make-lang.in (g++): Depend on mkstemp.o. Link in mkstemp.o
- * Make-lang.in (DEMANGLER_PROG): Add LIBS.
+Sat Jun 27 07:36:09 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
-Thu Jun 15 15:00:41 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * Makefile.in (EXPR_H): New dependency variable.
+ (decl2.o): Depend on $(EXPR_H).
+ (typeck.o): Likewise.
+ (init.o): Likewise.
+ (expr.o): Likewise.
+
+1998-06-25 Benjamin Kosnik <bkoz@lisa.cygnus.com>
- * decl.c (define_function): Don't set DECL_INTERFACE_KNOWN.
+ * decl.c (start_enum): Put local enums on permanent_obstack.
- * parse.y: Call cplus_decl_attributes with prefix_attributes where
- appropriate.
+1998-06-25 Mark Mitchell <mark@markmitchell.com>
-Wed Jun 14 19:24:49 1995 Mike Stump <mrs@cygnus.com>
+ * cp-tree.h (c_get_alias_set): Declare.
+ * decl.c (init_decl_processing): Set lang_get_alias_set.
- * search.c (get_vbase): New routine to switch hierarchies from the
- CLASSTYPE_VBASECLASSES to the normal one.
- (expand_indirect_vtbls_init): Use get_vbase to figure out how we
- want to convert to a vbase pointer.
+1998-06-25 Andrew MacLeod <amacleod@cygnus.com>
-Mon Jun 12 17:50:30 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cp-tree.h (mark_all_runtime_matches): Add function prototype.
+ * except.c (mark_all_runtime_matches): Set TREE_SYMBOL_REFERENCED
+ flag for all function decls which are in the exception table.
+ * exception.cc (__cplus_type_matcher): Check for CATCH_ALL_TYPE match.
+ * decl2.c (finish_file): Call mark_all_runtime_matches to make sure
+ code is emitted for any referenced rtti function.
- * pt.c (instantiate_class_template): Add the new instantiation to
- template_classes.
- (do_pending_expansions): Call instantiate_member_templates on all of
- the classes in template_classes.
+1998-06-25 Dave Brolley <brolley@cygnus.com>
-Mon Jun 12 12:36:59 1995 Mike Stump <mrs@cygnus.com>
+ * lang-specs.h: Use new | syntax to eliminate
+ string concatenation.
- * decl.c (complete_array_type): Fill in the TYPE_DOMAIN of our
- TYPE_MAIN_VARIANT if it is not filled in.
- * init.c (build_delete): If the TYPE_DOMAIN is not set, give an
- error instead of core dumping.
+1998-06-25 Jason Merrill <jason@yorick.cygnus.com>
-Mon Jun 12 10:41:40 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cp-tree.h (CP_DECL_CONTEXT): New macro.
+ * decl2.c (is_namespace_ancestor, lookup_using_namespace): Use it.
+ * method.c (build_overload_nested_name): Likewise.
+ * sig.c (build_signature_pointer_or_reference_type): Don't set
+ DECL_CONTEXT.
- * call.c (can_convert): Also check for distance > 0.
- (can_convert_arg): Ditto.
- (user_harshness): Ditto.
+1998-06-24 Martin v. Löwis <loewis@informatik.hu-berlin.de>
-Fri Jun 9 19:17:21 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ Set DECL_CONTEXT for globals to NULL_TREE instead of global_namespace.
+ * cp-tree.h (FROB_CONTEXT): New macro.
+ (DECL_MAIN_P): ::main should have a DECL_CONTEXT of NULL_TREE.
+ * decl.c (namespace_binding): Replace NULL_TREE with
+ global_namespace.
+ (set_namespace_binding, pop_namespace, lookup_name_real): Likewise.
+ * decl2.c (is_namespace_ancestor, lookup_using_namespace):
+ Likewise.
+ * decl.c (pushtag): Use FROB_CONTEXT.
+ (pushdecl, make_typename_type, define_function, grokdeclarator):
+ Likewise.
+ * decl2.c (set_decl_namespace, do_namespace_alias): Likewise.
+ * pt.c (push_template_decl_real, lookup_template_class, tsubst):
+ Likewise.
+ * decl2.c (decl_namespace): Return global_namespace if no context.
+ * method.c (build_overload_nested_name): Expect null as context.
+ * pt.c (mangle_class_name_for_template): Do nothing for null
+ contexts.
+ (lookup_template_class): Allow for null id_context.
- * g++.c (MATH_LIBRARY): Provide default.
- (main): Always link with the math library if we link with libstdc++.
+1998-06-25 Richard Henderson <rth@cygnus.com>
- * decl.c (start_function): Complain about redefinition of a function
- even when the pending_inline version is compiled after the other
- version.
+ * method.c (emit_thunk): Set current_function_is_thunk for the
+ ASM_OUTPUT_MI_THUNK case as well.
-Thu Jun 8 15:44:38 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-06-23 Andrew MacLeod <amacleod@cygnus.com>
- * gc.c (build_dynamic_cast): Build up a reference to a parameter of
- aggregate type.
+ * exception.cc (__cplus_type_matcher): Get a match_info pointer
+ instead of an exception table entry as a parameter.
-Wed Jun 7 20:00:31 1995 Mike Stump <mrs@cygnus.com>
+1998-06-23 Andrew MacLeod <amacleod@cygnus.com>
- * *.[chy]: Change all callers of finish_decl to cp_finish_decl.
- * decl.c (finish_decl): New routine to handle call backs from the
- mid end (declare_hidden_char_array).
+ * parse.y (function_try_block): Don't call start_catch_handler.
+ * except.c (call_eh_info): Remove coerced field from declaration.
+ (build_eh_type_type_ref): New function to create an address of a
+ rtti function for the new style exception tables.
+ (expand_start_catch_block): Split function, this contains the
+ common part.
+ (process_start_catch_block_old): New function to perform the rest
+ of expand_start_catch_block under old style exceptions.
+ (process_start_catch_block_old): New function to perform the rest
+ of expand_start_catch_block under new style exceptions.
+ (expand_end_catch_block): Only pop the false label off the stack under
+ the old style of exceptions.
+ * semantics.c (finish_try_block): Don't call start_catch_handler.
+ * exception.cc (struct cp_eh_info): Add original_value field.
+ (__cplus_type_matcher): Perform type matching on the original exception
+ value, and if we have a match, set the current value.
+ (__cp_push_exception): Set the original expcetion value.
-Wed Jun 7 19:02:50 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-06-23 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (start_function): Handle setting C_C_D here.
- (set_C_C_D): Removed.
- (struct saved_scope): Remove class_decl.
- (push_to_top_level): Don't save current_class_decl.
- (pop_from_top_level): Don't restore current_class_decl or C_C_D.
- (struct cp_function): Add C_C_D.
- (push_cp_function_context): Save C_C_D.
- (pop_cp_function_context): Restore C_C_D.
+ * call.c (joust): Fix confusing conversion warning.
-Wed Jun 7 15:31:57 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * call.c (build_op_delete_call): Add placement parm. Check
+ LOOKUP_SPECULATIVELY.
+ * cp-tree.h, decl2.c, init.c: Adjust.
+ * decl.c (finish_function): Use it.
- * init.c (build_vec_delete): Resolve an offset ref before we try to
- use it.
+ * pt.c (tsubst): Diagnose creating void fields or variables.
-Wed Jun 7 14:19:32 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Mon Jun 22 08:50:26 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * typeck.c (build_modify_expr): If the class lacks a constructor or
- assignment operator, return error_mark_node.
- (common_type): Use build_cplus_array_type.
+ * call.c (build_scoped_method_call): Remove unused variable `tmp'.
-Tue Jun 6 09:41:27 1995 Mike Stump <mrs@cygnus.com>
+ * cp-tree.h (check_dtor_name): Add prototype.
- * class.c (dont_allow_type_definitions): New variable set when types
- cannot be defined.
- (finish_struct): Use it.
- * cp-tree.h (dont_allow_type_definitions): Define it.
- * parse.y (primary, handler_seq): Set it.
+ * init.c (expand_member_init): Remove unused variables
+ `ptr_type_node', `parm' and `rval'.
-Mon Jun 5 18:49:38 1995 Mike Stump <mrs@cygnus.com>
+ * ptree.c (print_lang_type): Use HOST_WIDE_INT_PRINT_DEC specifier
+ in call to fprintf.
+ (lang_print_xnode): Likewise.
- * method.c (build_opfncall): Use DECL_CHAIN, not TREE_CHAIN for
- results from lookup_fnfields. Always give warning/error on bad
- code.
+ * typeck2.c (enum_name_string): Cast argument to sprintf to long
+ and use %ld specifier.
-Mon Jun 5 11:39:37 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
-
- * init.c (member_init_ok_or_else): Don't allow initialization of
- an ancestor's member from within a constructor.
-
-Mon Jun 5 11:20:34 1995 Gerald Baumgartner (gb@alexander.cs.purdue.edu)
-
- * sig.c (build_signature_table_constructor): Use DECL_CONTEXT
- instead of DECL_CLASS_CONTEXT for calculating the vfield offset so
- abstract virtual functions are handled correctly.
-
- * sig.c (build_signature_table_constructor): Store the correct
- delta in signature table entries. It does not yet work for
- classes with virtual base classes as implementations of signatures.
- (build_signature_method_call): Add the delta to the object_ptr
- before generating the function call.
-
- * call.c (build_method_call): Make instance_ptr the signature
- pointer itself instead of dereferencing the optr.
- * sig.c (build_signature_method_call): Dereference the optr for the
- direct and virtual calls.
-
- * sig.c (build_signature_table_constructor): Make the tag for
- default implementations -1 instead of 2.
- (build_signature_method_call): Change the generated conditional
- expression correspondingly.
-
- * sig.c (build_signature_pointer_constructor): Deleted the sorry
- message that said we can't handle multiple inheritance for
- implementations of signatures
- (build_signature_method_call): Use the offset from the sigtable
- entry instead of the vptr field from the signature pointer for
- building a virtual function call.
-
- * class.c (build_vfn_ref): Deleted signature specific code, we don't
- call this function anymore from build_signature_method_call.
-
- * cp-tree.h (SIGNATURE_VPTR_NAME): Deleted. We use the right vptr
- field in the object now instead of in the signature pointer/ref.
- (build_vptr_ref): Deleted extern declaration.
- * sig.c (build_vptr_ref): Deleted.
- (build_signature_pointer_or_reference_type): Deleted construction of
- the vptr field.
- (build_signature_pointer_constructor): Deleted initialization of/
- assignment to the vptr field.
-
- * sig.c (build_signature_table_constructor): Convert the signature
- table entry fields to their correct types.
-
- * sig.c (build_signature_table_constructor): Don't call digest_init
- for the fields of a sigtable entry, it's wasted time.
-
- * sig.c (build_signature_table_constructor): Correctly set the
- offset and index fields of a sigtable entry. Build the constructor
- the way digest_init does, digest_init can't handle initializing an
- anonymous union inside a struct.
- (build_signature_method_call): Use the index field instead of the
- delta field to get the vtable index.
-
- * decl.c (init_decl_processing): Fix number of fields for building
- sigtable_entry_type.
-
- * cp-tree.h (tag_identifier, offset_identifier): Added extern decls.
- (SIGTABLE_CODE_NAME): Renamed to SIGTABLE_TAG_NAME.
- (SIGTABLE_PFN_NAME): Deleted, we'll use VTABLE_PFN_NAME instead.
- * decl.c (tag_identifier, offset_identifier): New variables to
- hold the identifiers for the sigtable fields tag and offset.
- (init_decl_processing): Initialize these variables.
- (init_decl_processing): Use these variables to build the
- sigtable_entry_type structure. Rename the code and offset fields
- to tag and delta, respectively; add offset and index fields. Changed
- types of fields from short_integer_type_node to delta_type_node.
- * sig.c (build_signature_table_constructor): Rename code and offset
- to tag and delta, respectively.
- (build_signature_method_call): Ditto. Use above variables.
-
-Fri Jun 2 11:05:58 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * decl.c (set_C_C_D): New function. suspend_momentary before
- building C_C_D.
- (pop_from_top_level): Call it.
- (start_function): Ditto.
- (pop_cp_function_context): Ditto.
+ * xref.c (GNU_xref_end_scope): Use HOST_WIDE_INT_PRINT_DEC
+ specifier in call to fprintf.
+ (GNU_xref_member): Cast argument to sprintf to int.
- * class.c, cp-tree.h, decl.c, decl2.c, parse.y: Lose all references
- to current_vtable_decl, CLASSTYPE_INST_VAR and CLASSTYPE_VTBL_PTR.
+Fri Jun 19 23:22:42 1998 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
- * decl.c (push_cp_function_context): Save current_class_decl.
- (pop_cp_function_context): Restore current_class_decl and set C_C_D.
- (pop_from_top_level): Don't use CLASSTYPE_INST_VAR to set C_C_D.
- (start_function): Ditto.
+ * typeck2.c (pop_init_level): Warn about implicit zero initialization
+ of struct members.
- * class.c (popclass): Don't mess with current_class_decl,
- current_vtable_decl, or C_C_D.
+Thu Jun 18 09:32:32 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
-Mon May 29 12:45:10 1995 Paul Eggert <eggert@twinsun.com>
+ * cp-tree.h: Prototype function `check_java_method'.
- * Make-lang.in (c++.mostlyclean): Remove $(DEMANGLER_PROG).
+1998-06-17 Jason Merrill <jason@yorick.cygnus.com>
-Thu Jun 1 17:03:51 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * class.c (finish_struct): Make conflicting use of id a pedwarn.
+ * decl.c (pushdecl_class_level): Likewise.
- * decl.c (lookup_name_real): Don't try to look anything up in an
- erroneous object.
+1998-06-17 Mark Mitchell <mark@markmitchell.com>
-Fri Jun 2 10:30:14 1995 Mike Stump <mrs@cygnus.com>
+ * pt.c (convert_nontype_argument): Issue an error when presented
+ with an integer (real) constant that cannot be simplified to an
+ INT_CST (REAL_CST).
- * method.c (build_overload_int): New routine. Break out
- functionality from build_overload_value so we can reuse it.
- (build_overload_value): Handle pointer to member functions as value
- parameters for templates.
- (build_overload_identifier): Since template parameters are shared
- among all instantiations, we have to substitute in the real types
- in TREE_TYPE (parm).
- pt.c (coerce_template_parms): Ditto.
- (push_template_decls): Ditto.
- (grok_template_type): Deleted as template parameters are shared
- among all instantiations.
+ * cp-tree.h (c_get_alias_set): Remove declaration added in
+ 1998-06-13 change that should never have been checked in.
-Wed May 31 19:10:32 1995 Mike Stump <mrs@cygnus.com>
+1998-06-17 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokdeclarator): Always give errors on constant overflow
- for array indices.
+ * typeck.c (build_binary_op_nodefault): Change % in format strings
+ to %%.
-Wed May 31 11:39:43 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (grokvardecl): Don't build_static_name for decls that
+ aren't at namespace scope.
- * typeck.c (commonparms): Don't abort if simple_cst_equal returns < 0.
- (build_c_cast): Don't tack on a NON_LVALUE_EXPR when casting to
- reference type.
- (build_indirect_ref): Fix check for *&.
+ * init.c (perform_member_init): Catch default-initialization of
+ references.
-Wed May 24 15:55:18 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+1998-06-17 Mark Mitchell <mark@markmitchell.com>
- * decl.c (duplicate_decls): Check simple_cst_equal result against 0.
- * decl2.c (finish_anon_union): Likewise.
- * method.c (largest_union_member): Likewise.
+ * errfn.c (cp_thing): Handle the `%%' formatting sequence.
-Wed May 24 14:41:11 1995 H.J. Lu (hjl@nynexst.com)
+1998-06-17 Jason Merrill <jason@yorick.cygnus.com>
- * Make-lang.in (cxxmain.o): Replace single quotes with backslashes.
+ * method.c (hack_identifier): Complain about getting a namespace
+ or class template.
+ * typeck.c (decay_conversion): Remove check for namespaces.
+ * typeck2.c (incomplete_type_error): Likewise.
+ * parse.y (template_arg): Add PTYPENAME expansion.
-Mon May 22 17:38:48 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+1998-06-16 Andrew MacLeod <amacleod@cygnus.com>
- * Make-lang.in (g++, g++-cross, cc1plus, DEMANGLER_PROG):
- Use $@ instead of output name so works even if have .exe.
- (cxxmain.o): Use cp if ln -s fails.
- (c++.install-man): Use $(exeext) in executable names.
- (c++.mostlyclean, stage[1-4]): Use $(objext) in object file names.
- * Makefile.in (../cc1plus): Use $(exeext) in name of executable.
+ * decl.c (grokvardecl): Don't build external assembler names for
+ TYPENAMEs in other namespaces as there is no declarator.
+ * error.c (cp_file_of, cp_line_of): Don't extract file or line number
+ info from DECL_CONTEXT if it is NULL.
-Wed May 24 01:39:03 1995 Jason Merrill <jason@deneb.cygnus.com>
+1998-06-16 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_method_call): parms can be null, duh.
+ * call.c (check_dtor_name): Split out.
+ (build_scoped_method_call): Use it.
+ (build_method_call): Use it.
+ * init.c (build_offset_ref): Use it.
-Tue May 23 01:32:09 1995 Jason Merrill <jason@deneb.cygnus.com>
+ * typeck.c (build_static_cast): Fix handling of pointers to members.
- * call.c (build_method_call): If convert_arguments failed, just bail.
+ * decl.c (finish_function): Just return nothing from a constructor.
+ * typeck.c (c_expand_return): Complain about returning a void
+ expression from a destructor.
-Fri May 19 10:31:11 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-06-13 Mark Mitchell <mark@markmitchell.com>
- * cvt.c (convert_force): Pass LOOKUP_NORMAL to cp_convert.
+ * class.c (alter_access): Accept a BINFO explaining how to get
+ from the entity whose accessed is being altered to the type doing
+ the altering.
+ (handle_using_decl): New function containing code split out from ...
+ (finish_struct_1): Here.
- * tree.c (copy_to_permanent): Oops.
+ * cp-tree.h (complete_type_or_else): Declare.
+ * init.c (build_new_1, build_delete): Use it.
+ * typeck.c (require_complete_type): Use complete_type, rather than
+ expanding it inline.
+ (complete_type_or_else): New function.
+ (build_component_ref): Use it.
+ (pointer_int_sum): Make sure the type pointed to is complete.
+ (pointer_diff): Likewise.
-Fri May 19 10:01:07 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * pt.c (for_each_template_parm): Traverse the TYPE_CONTEXT for
+ types.
- * cp-tree.h (break_out_target_exprs): Add decl.
+ * search.c (get_matching_virtual): Note that member templates
+ cannot override virtual functions.
-Thu May 18 13:02:30 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-06-12 Brendan Kehoe <brendan@cygnus.com>
- * decl.c (start_function): Move *all* interface handling stuff after
- the pushdecl.
+ * pt.c (check_explicit_specialization): If DECLARATOR turned into
+ an error_mark_node from lookup_template_function, return the same.
+ (determine_specialization): Also make sure TEMPLATE_ID isn't an
+ error_mark_node, before we try to read its operands.
+ * decl.c (grokdeclarator): If we got an error_mark_node from
+ check_explicit_specialization, just return it right back.
- * tree.c (mapcar): Renamed from make_deep_copy and generalized.
- (perm_manip): Return t if permanent, otherwise 0.
- (copy_to_permanent): Use them.
- (bot_manip): Helper for break_out_target_exprs.
- (break_out_target_exprs): New function. Uses mapcar.
+1998-06-12 Mark Mitchell <mark@markmitchell.com>
- * typeck.c (convert_arguments): Use it.
+ * class.c (instantiate_type): Don't treat template-ids that don't
+ specify any template arguments as equivalent to ordinary
+ identifiers. Use OFFSET_REF instead of SCOPE_REF to refer to
+ pointer-to-members for member templates. Tidy slightly.
+ * cp-tree.def (TEMPLATE_ID_EXPR): Revise documentation.
+ * init.c (build_offset_ref): Handle template-ids like ordinary
+ identifiers, for the most part, but store a TEMPLATE_ID_EXPR in the
+ offset part of the OFFSET_REF.
+ * typeck.c (build_unary_op): Change check for unknown types to
+ look for OFFSET_REFs, not SCOPE_REFs.
- * method.c (hack_identifier): Use convert_from_reference to
- dereference a reference.
+1998-06-11 Mark Mitchell <mark@markmitchell.com>
-Wed May 17 17:54:54 1995 Mike Stump <mrs@cygnus.com>
+ * pt.c (is_member_template_class): New function.
+ (push_template_decl_real): Use it.
- * call.c (convert_harshness): Move reference bashing before pointer
- to member bashing.
+1998-06-11 Benjamin Kosnik <bkoz@elmo.cygnus.com>
-Wed May 17 16:57:53 1995 Mike Stump <mrs@cygnus.com>
+ * friend.c (do_friend): Add support for nested classes using
+ member functions of the enclosing class as friends.
- * cvt.c (convert_to_reference): Only complain, if complaints are
- wanted.
- * typeck.c (build_function_call_real): Ditto. If LOOKUP_SPECULATIVELY
- is set and something won't work, return NULL_TREE.
- * cvt.c (cp_convert): Ditto. Pass flags down to build_method_call.
- (convert): Pass LOOKUP_NORMAL to cp_convert.
- * typeck.c (convert_for_assignment): Ditto.
- (convert_force): Pass LOOKUP_COMPLAIN to cp_convert.
- (convert_arguments): Get out early if we get an error_mark_node.
- (convert_for_initialization): Use cp_convert instead of convert so
- that we can pass flags down.
- * cp-tree.h (LOOKUP_SPECULATIVELY): Added documentation.
+1998-06-10 Mark Mitchell <mark@markmitchell.com>
-Wed May 17 01:43:58 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (convert_default_arg): Make global, not static.
+ (convert_arg_for_ellipsis): Split out from ...
+ (build_over_call): Here.
+ * cp-tree.h (convert_default_arg); Declare.
+ (convert_arg_to_ellipsis): Likewise.
+ (do_member_init): Remove.
+ * init.c (do_member_init): Remove; this code is dead.
+ (expand_member_init): Remove much of this code; it is dead.
+ * typeck.c (convert_arguments): Use convert_default_arg and
+ convert_arg_for_ellipsis, rather than duplicating here.
+
+ * call.c (convert_like): Don't fail silently if
+ build_user_type_conversion fails. Always return error_mark_node
+ for failure.
- * typeck2.c (store_init_value): Don't take the MAIN_VARIANT of the
- decl type.
+1998-06-10 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): Don't complain about a class with no
- user-defined constructors but with a member that has no default
- constructor, as this is OK for aggregates.
+ * search.c (covariant_return_p): Complain about ambiguous base.
- * expr.c (cplus_expand_expr, NEW_EXPR): If this is an explicit
- constructor call, mark slot addressable.
+ * typeck.c (build_component_ref): Diagnose ref to nested type.
-Tue May 16 18:37:51 1995 Douglas Rupp (drupp@cs.washington.edu)
+1998-06-10 Brendan Kehoe <brendan@cygnus.com>
- * g++.c: Changed WINNT to _WIN32.
+ * decl.c (grokparms): Check that INIT isn't an error_mark_node
+ before giving error about invalid type for default arg.
-Tue May 16 12:40:16 1995 Jason Merrill <jason@lisa.cygnus.com>
+1998-06-10 Jason Merrill <jason@yorick.cygnus.com>
- * lex.c (handle_sysv_pragma): Don't use token_buffer.
+ * call.c (build_method_call): Fix thinko.
-Tue May 16 12:05:26 1995 Mike Stump <mrs@cygnus.com>
+1998-06-10 Dave Brolley <brolley@cygnus.com>
- * call.c (resolve_scope_to_name): Add initial semantic support for
- namespaces.
- * class.c (finish_struct): Ditto.
- * cp-tree.h (NAMESPACE_LEVEL): Ditto.
- * cvt.c (build_up_reference, convert_to_reference): Ditto.
- * decl.c (binding_level::namespace_p, suspend_binding_level): Ditto.
- (resume_binding_level, toplevel_bindings_p): Ditto
- (namespace_bindings_p, declare_namespace_level): Ditto.
- (resume_level, push_namespace, pop_namespace): Ditto.
- (pop_everything, pushtag, duplicate_decls, pushdecl): Ditto.
- (implicitly_declare, lookup_namespace_name, lookup_name_real): Ditto.
- (start_decl, make_temporary_for_reference), Ditto.
- (obscure_complex_init, finish_decl, expand_static_init): Ditto.
- (grokvardecl, grokdeclarator, parmlist_is_exprlist): Ditto.
- (store_parm_decls, hack_incomplete_structures): Ditto.
- * decl2.c (get_temp_name, finish_anon_union, current_namespace): Ditto.
- (push_namespace, pop_namespace, do_namespace_alias): Ditto.
- (do_toplevel_using_decl, do_class_using_decl): Ditto.
- * error.c (dump_decl): Ditto.
- * init.c (build_member_call, build_offset_ref): Ditto.
- * lex.c (identifier_type): Ditto.
- * parse.y (lang_extdef, using_decl, extdef, component_decl_1): Ditto.
- (nested_name_specifier_1): Ditto.
- * spew.c (yylex): Ditto.
- * tree.def (NAMESPACE_DECL): Ditto.
+ * decl2.c (lang_decode_option): New argc/argv interface.
+ * cp-tree.h (lang_decode_option): New argc/argv interface.
+ * lang-specs.h (default_compilers): Only call cpp if -E, -M or -MM is
+ specified for cpplib-enabled compilers.
+ * lex.c (lang_init): Don't check_newline for cpplib.
+ (init_parse): Don't initialize cpplib here.
-Tue May 16 11:55:35 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-06-10 Brendan Kehoe <brendan@cygnus.com>
- * decl.c (push_overloaded_decl): Return the new decl even if it
- can't be pushed.
+ * typeck.c (build_component_ref): Make sure FIELD has a lang_specific
+ piece before checking DECL_MUTABLE_P.
-Tue May 16 11:00:37 1995 Jason Merrill <jason@lisa.cygnus.com>
+1998-06-10 John Carr <jfc@mit.edu>
- * typeck.c (decay_conversion): Split out from default_conversion.
- (default_conversion): Call it.
- (build_binary_op): Ditto.
- (build_binary_op_nodefault): Use decay_conversion for truth ops.
+ * tree.c (debug_binfo): Make printf format match arguments.
-Mon May 15 12:47:56 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * error.c (OB_PUTI): Make printf format match arguments.
- * decl.c (warn_extern_redeclared_static): This is a pedwarn.
- (duplicate_decls): Always use the old decl's linkage info. Don't
- play with linkage of consts.
- (pushdecl): Don't play with linkage of consts.
- (redeclaration_error_message): Don't complain about an old public
- decl and a new non-public decl here.
- (grokvardecl): Handle linkage of consts here.
- (grokdeclarator): An 'extern inline' is public. Pass constp to
- grokvardecl.
- (start_function): Wait until after the pushdecl to do some linkage
- stuff.
+1998-06-10 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (import_export_vtable): Make duplicates weak rather than
- static if supported.
- (import_export_inline): Ditto.
- * pt.c (do_pending_expansions): Ditto.
+ * init.c (perform_member_init): Handle default-initialization.
- * class.c (build_vbase_path): flag_assume_nonnull_objects only
- affects reference conversion.
+ * except.c (build_throw): Handle throwing NULL.
- * init.c (emit_base_init): Build up an RTL_EXPR and add it to
- rtl_expr_chain.
- * decl.c, decl2.c: s/base_init_insns/base_init_expr/.
+ * typeck.c (build_x_function_call): Use resolve_offset_ref.
-Tue May 16 07:06:28 1995 Paul Eggert <eggert@twinsun.com>
+ * search.c (compute_access): Only strip an anonymous union
+ for a FIELD_DECL.
- * method.c (numeric_output_need_bar): Renamed from misspelling.
+ * call.c (add_builtin_candidates): Tweak.
- * typeck.c (build_ptrmemfunc): Fix misspellings in messages.
+ * cvt.c (build_expr_type_conversion): Restore code for conversion
+ from class types.
+ * decl2.c (delete_sanity): Use it. Clean up.
-Sun May 14 10:26:22 1995 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
+ * typeck.c (comp_ptr_ttypes_real): Fix cv-qual comparisons.
- * lang-options.h, lang-specs.h: New files.
+1998-06-10 Branko Cibej <branko.cibej@hermes.si>
-Thu May 11 00:31:48 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * typeck.c (c_expand_return): Don't warn about void expressions on
+ return statements in functions returning void.
- * typeck.c (default_conversion): Don't check for BLKmode before
- pulling out the decl_constant_value.
+1998-06-09 Mark Mitchell <mark@markmitchell.com>
- * decl.c (start_function): Clear named_labels and shadowed_labels.
+ * pt.c (fn_type_unification): Revise documentation. Tidy.
+ (type_unification): Likewise.
- * typeck.c (build_function_call_real): Also synthesize methods here.
+1998-06-09 Andrew MacLeod <amacleod@cygnus.com>
-Wed May 10 00:55:59 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * semantics.c (finish_try_block): Rename expand_start_catch, and delete
+ expand_end_catch.
+ * parse.y (function_try_block): Rename expand_start_catch, and delete
+ expand_end_catch.
+ * except.c (expand_end_eh_spec): Rename expand_start_catch, and delete
+ expand_end_catch.
- * decl2.c (finish_file): Synthesize exported methods before the
- reconsider loop.
+1998-06-09 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y: Move declaration of flag_new_for_scope to file scope.
+ * search.c (lookup_member): New fn.
+ * class.c (finish_struct_1): Use it.
+ * decl.c (lookup_name_real): Use it.
-Tue May 9 19:10:33 1995 Mike Stump <mrs@cygnus.com>
+Mon Jun 8 20:45:52 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * decl2.c: Add flag_new_for_scope for new -ffor-scope flag.
- * parse.y (FOR): Conditionalize the pushing and poping of scope for
- the for-init-statement upon the new flag_new_for_scope.
- * parse.y (try_block): Simplify and use compstmt.
+ * Makefile.in (decl2.o): Depend on dwarf2out.h and dwarfout.h.
-Mon May 8 12:41:52 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cp-tree.h: Add prototype for `maybe_print_template_context' and
+ `maybe_make_one_only'.
- * decl.c (define_function): Mark function decl artificial.
+ * decl.c (auto_function): Remove unused variable `decl'.
-Sun May 7 00:51:28 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c: Include dwarf2out.h and dwarfout.h.
- * parse.y (simple_stmt, FOR): Put back push/pop for condition scope.
+ * lex.c: Remove redundant declarations of `set_float_handler' and
+ `asm_out_file'.
- * decl2.c (grokclassfn): DECLs don't have cv-qualified types.
- * tree.c (build_cplus_method_type): Ditto.
+1998-06-08 Andrew MacLeod <amacleod@cygnus.com>
- * cp-tree.h (SET_DECL_ARTIFICIAL): Just set DECL_ARTIFICIAL to 1.
+ * except.c (init_exception_processing): Remove NEW_EH_MODEL compile
+ time flag. Call __cp_eh_info instead of __cp_exception_info.
+ * exception.cc (struct cp_eh_info): Remove NEW_EH_MODEL flag.
+ (__cp_exception_info): Return offset into cp_eh_info structure to
+ match what use to be the start of this structure.
+ (__cp_eh_info): New function to return a pointer to cp_eh_info struct.
+ (__cplus_type_matcher, __cp_push_exception): Remove NEW_EH_MODEL
+ compile time flag.
+ (__uncatch_exception, __check_eh_spec, std::uncaught_exception): Call
+ __cp_eh_info instead of __cp_exception_info.
- * typeck.c (build_function_call_real): If convert_arguments failed,
- just bail.
- (convert_arguments): If one of the arguments is error_mark_node,
- just bail.
+1998-06-08 Jason Merrill <jason@yorick.cygnus.com>
-Sat May 6 02:39:41 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (cp_finish_decl): Disable inlining of extern inlines
+ with static variables.
- * decl.c (duplicate_decls): Don't check DECL_NOT_REALLY_EXTERN for
- decls that don't include it.
+1998-06-08 Mark Mitchell <mark@markmitchell.com>
-Fri May 5 14:23:30 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * init.c (build_offset_ref): Correct previous change to use build,
+ not build_min.
- * decl.c (duplicate_decls): Decls that have DECL_INTERFACE_KNOWN or
- DECL_NOT_REALLY_EXTERN set aren't extern decls.
+1998-06-07 Mark Mitchell <mark@markmitchell.com>
- * typeck.c (build_indirect_ref): Don't call default_conversion for a
- parameter of reference_type.
- * cvt.c (convert_from_reference): Just use build_indirect_ref.
+ * class.c (instantiate_type): Handle pointer-to-members where the
+ member is a template.
+ * init.c (build_offset_ref): Likewise.
+ * typeck.c (build_unary_op): Likewise.
- * pt.c (do_type_instantiation): Only instantiate member functions
- that actually come from templates.
+1998-06-07 Richard Henderson <rth@cygnus.com>
-Fri May 5 09:46:05 1995 Mike Stump <mrs@cygnus.com>
+ * lex.c (lang_init_options): New function.
+ (lang_init): Remove flag_exceptions == 2 hack.
+
+1998-06-05 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y: Generalized cleanup of poplevels, and compound statements
- and compound statements in try blocks. Rewritten `for' rule so that
- the scope of variables declared in the for clause is shortened to
- span just to the end of the statement, instead of the whole
- containing block.
+ * search.c (envelope_add_decl): Tweak for implicit typename.
-Fri May 5 00:37:14 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (joust): Also warn about confusing conversion op/constructor
+ overload resolution.
- * call.c (convert_harshness): Handle pointers to members better.
+ * spew.c (yylex): Also return the TYPE_DECL if got_object.
+ Don't clear got_object after '~'.
+ * call.c (build_scoped_method_call): Tweak destructor handling.
+ (build_method_call): Likewise.
+ * pt.c (tsubst_copy, case METHOD_CALL_EXPR): Don't mess with
+ TYPE_MAIN_VARIANT for destructors.
+ * semantics.c (finish_object_call_expr): Complain about calling a
+ TYPE_DECL.
-Thu May 4 16:00:26 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-06-05 Per Bothner <bothner@cygnus.com>
- * decl2.c (delete_sanity): Do access control here.
- * init.c (build_delete): Instead of here.
+ * g++spec.c (lang_specific_pre_link, lang_specific_extra_ofiles):
+ Define - update needed by gcc.c change.
- * Make-lang.in: Build c++filt.
+1998-06-05 Jason Merrill <jason@yorick.cygnus.com>
-Wed May 3 02:59:53 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * error.c (cp_printers): Use 'o' instead of '_' for the null entry.
- * decl2.c (cplus_decl_attributes): If we just modified a TYPE_DECL,
- update our IDENTIFIER_TYPE_VALUE.
+1998-06-05 Martin v. Loewis <loewis@informatik.hu-berlin.de>
-Fri Apr 28 07:58:41 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cp-tree.h (DECL_NAMESPACE_ALIAS, ORIGINAL_NAMESPACE): Declare.
+ * decl.c (lookup_name_real): Add namespaces_only parameter.
+ If set, return only NAMESPACE_DECLs.
+ (select_decl): Likewise.
+ (identifier_type_value): Give additional parameter.
+ (lookup_name_nonclass): Likewise.
+ (lookup_name): Likewise.
+ (find_binding): Skip namespace aliases.
+ (binding_for_name): Likewise.
+ (push_namespace): Check for namespace aliases.
+ (lookup_name_namespace_only): New function.
+ (begin_only_namespace_names, end_only_namespace_names): New functions.
+ * decl2.c (set_decl_namespace): Skip namespace aliases.
+ (do_using_directive): Likewise.
+ (do_namespace_alias): Produce namespace aliases, fix alias
+ redeclaration.
+ * error.c (dump_decl): Support SCOPE_REF.
+ * parse.y (extdef): Wrap lookup with namespace_only for namespace
+ aliases and using declarations.
- * lex.c (cons_up_default_function): Fix linkage of #pragma
- implemented functions.
+1998-06-04 Jason Merrill <jason@yorick.cygnus.com>
-Thu Apr 27 16:56:24 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * tree.c (really_overloaded_fn): Only see through one TREE_LIST.
- * method.c (build_overload_name): Simplify and fix repeated type
- folding.
+ * error.c (dump_expr): Clean up NEW_EXPR case.
- * decl.c (grokdeclarator): Prohibit pointers to void or reference
- members.
+1998-06-04 Martin von Löwis <loewis@informatik.hu-berlin.de>
-Thu Apr 27 09:49:07 1995 Mike Stump <mrs@cygnus.com>
+ Suggested by Brendan Kehoe
+ * decl2.c (do_toplevel_using_decl): When decl is a TYPE_DECL,
+ treat it as using ::decl.
- * typeck2.c (process_init_constructor): Make sure initializers are
- fully digested.
+ * decl2.c (arg_assoc_type): Process unknown_type_node and OFFSET_TYPE.
-Thu Apr 27 01:11:55 1995 Jason Merrill <jason@python.cygnus.com>
+ * tree.c (mapcar): Support NEW_EXPR.
- * lex.c (cons_up_default_function): Always defer synthesis.
+ * error.c (dump_expr): Support NEW_EXPR.
-Thu Apr 27 00:20:37 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-06-03 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (mark_inline_for_output): Don't play with pending_inline
- stuff.
+ * method.c (make_thunk): Use overload machinery to make name.
+ * search.c (covariant_return_p): New fn.
+ (get_matching_virtual): Use it.
-Wed Apr 26 17:48:24 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * init.c (build_new_1): Fix check for void.
- * call.c (user_harshness): New function; like build_type_conversion,
- but doesn't actually build anything.
- (compute_conversion_costs): Use it instead of build_type_conversion.
+1998-06-01 Per Bothner <bothner@cygnus.com>
-Wed Apr 26 17:11:25 1995 Jason Merrill <jason@deneb.cygnus.com>
+ * cp-tree.h (TYPE_FOR_JAVA): New macro.
+ * decl.c, cp-tree.h (java_byte_type_node, java_short_type_node,
+ java_int_type_node, java_long_type_node, java_float_type_node,
+ java_double_type_node, java_char_type_node, java_boolean_type_node):
+ New "primitive" types, with predefined names __java_byte etc.
+ (record_builtin_java_type): New function.
+ (init_decl_processing): Make Java types with record_builtin_java_type.
+ (pushtag, grokdeclarator): Set TYPE_FOR_JAVA if in extern "JAVA".
+ (xref_baseypes): If base class was TYPE_FOR_JAVA, so is this class.
+ (grokfndecl): Call check_java_method for Java classes.
+ * method.c (is_java_type): Removed. Replaced with TYPE_FOR_JAVA.
+ (process_overload_item): Match types against specific
+ java_XX_type_node types, rather than using is_java_type.
+ * class.c (finish_struct_1): Don't add default copy constructor
+ or operator= if TYPE_FOR_JAVA.
+ (pop_lang_conext): Restore strict_prototyp proper if Java.
+ * decl2.c (acceptable_java_type, check_java_method): New functions.
+ * pt.c (instantiate_class_template): Copy TYPE_FOR_JAVA from pattern.
+ (tsubst): Move common statement after if statement.
+ * typeck.c (comptypes): If strict, TYPE_FOR_JAVA must match.
- * typeck.c (build_function_call_real): Improve error message for
- calling a non-function.
+1998-06-01 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (hack_identifier): Lose check for calling a data member.
+ * pt.c (for_each_template_parm): Use first_rtl_op.
-Wed Apr 26 16:59:13 1995 Mike Stump <mrs@cygnus.com>
+ * tree.c (build_cplus_array_type_1): Also check index_type for
+ template parms.
- * typeck2.c (build_functional_cast): Remove very old cruft.
- Seems like good code is generated without it.
+1998-05-31 Jason Merrill <jason@yorick.cygnus.com>
-Wed Apr 26 00:47:16 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (tsubst): Always copy BINFO_BASETYPES.
- * method.c (do_build_assign_ref): Fix handling of anonymous unions.
- (do_build_copy_constructor): Ditto.
+1998-05-29 scott snyder <snyder@d0sgif.fnal.gov>
- * parse.y (simple_stmt, SWITCH): Call {push,pop}_switch.
+ * tree.c (layout_basetypes): If we change TYPE_SIZE, change
+ TYPE_SIZE_UNIT too.
- * decl.c (push_switch): New function.
- (pop_switch): Ditto.
- (define_case_label): Check for jumping over initialization.
+1998-05-29 Mark Mitchell <mark@markmitchell.com>
- * call.c (build_method_call): Check for an inline function being
- called before its definition has been seen.
- * typeck.c (build_function_call_real): Ditto.
+ * decl.c (grokdeclarator): Don't complain about in-class
+ initialization of static consts if we don't really know the type
+ of the variable.
- * decl.c (duplicate_decls): Check for a function being redeclared
- inline after its address has been taken.
+1998-05-29 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_conditional_expr): Handle related class lvalues.
+ * cp-tree.h (DECL_DESTRUCTOR_P): New macro.
+ * method.c (build_destructor_name): New fn.
+ * decl2.c (maybe_retrofit_in_chrg): Split out...
+ (grokclassfn): From here. Reorganize.
+ * decl.c (grok_ctor_properties): Make sure ctors for types with
+ vbases have the in_chrg parm.
+ * pt.c (instantiate_class_template): Update
+ TYPE_USES_VIRTUAL_BASECLASSES from tsubsted bases. Don't call
+ grok_*_properties.
+ (tsubst): Call grok_ctor_properties and maybe_retrofit_in_chrg.
-Tue Apr 25 13:20:45 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-05-28 Mark Mitchell <mark@markmitchell.com>
- * pt.c (do_pending_expansions): Don't expand unused templates.
+ * pt.c (instantiate_decl): Make test for whether or not static
+ variables should be instantiated early match its comment.
- * parse.y (component_decl): Accept a lone semicolon.
+1998-05-28 Jason Merrill <jason@yorick.cygnus.com>
-Tue Apr 25 00:25:56 1995 Jason Merrill <jason@rtl.cygnus.com>
+ * decl.c (start_decl): Always pedwarn about vacuously redeclaring
+ a member.
+ (start_function): Call check_default_args.
+ * decl2.c (grokfield): Don't call check_default_args.
+ (check_default_args): Use cp_error_at.
+ * lex.c (do_pending_defargs): Call check_default_args.
- * call.c (build_method_call): Don't allow an RTL_EXPR to serve as the
- object parameter anymore.
+1998-05-27 Brendan Kehoe <brendan@cygnus.com>
- * expr.c (cplus_expand_expr): Don't create RTL_EXPRs with no insns.
+ * call.c (build_method_call): Make sure get_type_value returns
+ something before we try to use its TYPE_MAIN_VARIANT.
+ (build_scoped_method_call): Likewise.
-Mon Apr 24 12:35:48 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-05-27 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (simple_stmt, decl case): Clear prefix_attributes.
- (lang_extdef): Ditto.
+ * typeck2.c (digest_init): Complain about getting a TREE_LIST to
+ initialize an array.
- * parse.y (maybe_parmlist): New rule for use in declarators where
- this could either be a list of expressions or parameters. Calls
- suspend_momentary before deciding which.
- (direct_after_type_declarator): Use it.
- (complex_direct_notype_declarator): Use it.
+ * search.c (expand_upcast_fixups): Don't set DECL_CONTEXT and
+ DECL_VIRTUAL_P.
- * pt.c (tsubst): Propagate attributes const and noreturn.
+ * friend.c (do_friend): Clarify template warning.
- * typeck.c (build_modify_expr): If warn_synth, call build_opfncall
- before doing the default thing.
+1998-05-27 Mark Mitchell <mark@markmitchell.com>
-Thu Apr 27 21:49:36 1995 Doug Evans <dje@cygnus.com>
+ * decl.c (shadow_label): Don't treat decls as identifiers.
+ (maybe_push_to_top_level): Clear shadowed_labels.
- * typeck.c (common_type): Call lookup_attribute instead of
- value_member.
+ * pt.c (instantiate_decl): Reset lineno and filename after calling
+ regenerate_decl_from_template.
-Tue Apr 25 18:07:43 1995 Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
+ * decl.c (grokdeclarator): Don't try to use TYPE_OBSTACK on an
+ error_mark_node.
- * Make-lang.in: Change "realclean" to "maintainer-clean".
+1998-05-27 Kevin Buhr <buhr@stat.wisc.edu>
-Sun Apr 23 12:32:38 1995 Mike Stump <mrs@cygnus.com>
+ * parse.y (base_class): Use is_aggr_type, not IS_AGGR_TYPE.
- * decl2.c (finish_file): Fix broken linked list handling.
+1998-05-26 Kriang Lerdsuwanakij <lerdsuwa@scf.usc.edu>
-Fri Apr 21 18:08:43 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (process_template_parm): Accept TYPENAME_TYPE nodes.
+ (convert_nontype_argument): Handle cases when nontype template
+ parameters become classes after substitution.
- * class.c (finish_base_struct): Don't set TYPE_HAS_COMPLEX_*_REF
- as often.
- (finish_struct): Ditto.
+1998-05-26 Mark Mitchell <mark@markmitchell.com>
- * various: Use TYPE_HAS_TRIVIAL_* instead of TYPE_HAS_COMPLEX_*.
+ * friend.c (is_friend): Use comptypes, rather than == to compare
+ types. Modify for new representation of template friends.
+ (make_friend_class): Likewise.
+ * pt.c (tsubst_friend_class): Undo 1998-05-21 change. Tweak.
+ (instantiate_class_template): Deal with template friends.
- * cp-tree.h (TYPE_HAS_TRIVIAL_INIT_REF): New macro.
- (TYPE_HAS_TRIVIAL_ASSIGN_REF): New macro.
+ * decl.c (store_parm_decls): Remove redundant call to
+ expand_main_function.
-Fri Apr 21 15:52:22 1995 Jason Merrill <jason@python.cygnus.com>
+1998-05-26 Benjamin Kosnik <bkoz@loony.cygnus.com>
- * typeck.c (c_expand_return): Only expand a returned TARGET_EXPR if
- it is of the same type as the return value.
+ * decl.c (start_decl): Check for DECL_LANG_SPECIFIC before
+ DECL_USE_TEMPLATE.
-Fri Apr 21 03:01:46 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-05-26 Per Bothner <bothner@cygnus.com>
- * decl2.c (finish_file): Reconsider if synthesizing a method wrote
- out its assembly.
+ * language_as_string: Handle lang_java.
- * typeck.c (convert_for_initialization): Don't call a trivial copy
- constructor.
+1998-05-26 Jason Merrill <jason@yorick.cygnus.com>
- * typeck2.c (store_init_value): Only abort if the type has a
- non-trivial copy constructor.
+ * decl.c (pushdecl): Don't copy the type_decl.
- * typeck.c (c_expand_return): If we're returning in a register and
- the return value is a TARGET_EXPR, expand it. Only do
- expand_aggr_init if we're returning in memory.
- (expand_target_expr): Function to expand a TARGET_EXPR.
- (build_modify_expr): Use it.
+1998-05-26 Martin v. Löwis <loewis@informatik.hu-berlin.de>
- * tree.c (build_cplus_new): Layout the slot.
+ * class.c (pushclass): Always store TYPE_MAIN_VARIANT in
+ current_class_type.
+ * decl.c (grokdeclarator): Put typedefs on the type's obstack.
- * expr.c (cplus_expand_expr): Use expand_call to expand the call
- under a NEW_EXPR, so the target is not discarded.
+ * parse.y (complex_direct_notype_declarator): Use $1 to access
+ scope of notype_qualified_id.
-Thu Apr 20 14:59:31 1995 Mike Stump <mrs@cygnus.com>
+1998-05-26 Dave Brolley <brolley@cygnus.com>
- * gc.c (build_dynamic_cast): Tighten error checking.
+ * lex.c (parse_options,yy_cur,yy_lim): Add for cpplib.
+ (init_parse): Initialize cpplib interface.
-Thu Apr 20 11:23:54 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * Makefile.in (CXX_OBJS): Make sure dependencies never end with an
+ empty continuation.
- * expr.c (cplus_expand_expr): Only abort if the returned target is
- different from what we expected if the type has a non-trivial copy
- constructor.
+1998-05-26 Mark Mitchell <mark@markmitchell.com>
- * decl2.c (cplus_decl_attributes): Attributes applied to a template
- really apply to the template's result.
+ * decl.c (pushtag): Avoid crashing on erroneous input.
- * tree.c (lvalue_p): Check IS_AGGR_TYPE instead of TREE_ADDRESSABLE
- to decide whether to consider a CALL_EXPR an lvalue.
+1998-05-25 Martin v. Löwis <loewis@informatik.hu-berlin.de>
- * class.c (finish_struct_bits): Only set TREE_ADDRESSABLE if the
- type has a non-trivial copy constructor.
+ * decl.c (push_namespace): Only produce one unique name for
+ anonymous namespaces.
+ (get_unique_name): Remove.
- * decl.c (start_function): If interface_known, unset
- DECL_NOT_REALLY_EXTERN on the function.
+1998-05-25 Mark Mitchell <mark@markmitchell.com>
-Wed Apr 19 16:53:13 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (tourney): Don't do any extra comparisons.
- * pt.c (do_function_instantiation): Handle explicit instantiation of
- member functions.
- (do_type_instantiation): Handle 'inline template class foo<int>',
- meaning just spit out the vtable.
+ * decl2.c (build_anon_union_vars): Don't crash on empty sub-unions.
- * lex.c (cons_up_default_function): Set DECL_NOT_REALLY_EXTERN on
- the consed functions.
+ * cp-tree.h (processing_template_parmlist): Declare.
+ * decl.c (pushtag): Don't call push_template_decl when we
+ shouldn't.
+ * pt.c (processing_template_parmlist): New variable.
+ (TMPL_ARGS_HAVE_MULTIPLE_LEVELS): New macro.
+ (complete_template_args): Use it.
+ (add_to_template_args): Likewise.
+ (innermost_args): Likewise.
+ (tsubst): Likewise.
+ (begin_template_parm_list): Use processing_template_parmlist.
+ (end_template_parm_list): Likewise.
- * decl2.c (import_export_inline): Set DECL_INTERFACE_KNOWN.
+ * cp-tree.h (ANON_UNION_TYPE_P): New macro.
+ * decl.c (grokdeclarator): Use it.
+ * decl2.c (grok_x_components): Likewise.
+ * init.c (initializing_context): Likewise.
+ * method.c (do_build_copy_constructor): Likewise.
+ (do_build_assign_ref): Likewise.
+ * search.c (compute_access): Likewise.
+ * typeck.c (build_component_ref): Likewise.
-Wed Apr 19 16:28:17 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * decl.c (grokdeclarator): Don't give a cv-qualified version of an
+ unnamed type a typedef name "for linkage purposes".
- * call.c, class.c, decl2.c, gc.c, init.c, parse.y, pt.c, search.c,
- typeck.c: Include output.h.
+ * pt.c (lookup_template_class): Don't look at
+ IDENTIFIER_CLASS_VALUE when there's no current_class_type.
-Wed Apr 19 14:57:21 1995 Gerald Baumgartner (gb@alexander.cs.purdue.edu)
+ * method.c (build_overload_int): Handle error cases gracefully.
- * call.c (build_method_call): Allow a signature member functions to
- be called from a default implementation.
+ * pt.c (instantiate_decl): Handle static member variables
+ correctly.
-Wed Apr 19 10:21:17 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (tsubst): Use the tsubst'd type when producing new
+ TEMPLATE_PARM_INDEX nodes.
- * repo.c (finish_repo): Remember what directory we are in.
+1998-05-24 Mark Mitchell <mark@markmitchell.com>
- * search.c (expand_upcast_fixups): Don't mess with abort_fndecl.
+ * tree.c (cp_tree_equal): Handle pointers to member functions.
- * repo.c: Use obstacks instead of fixed-size buffers. Don't spit
- out the second copy of the symbol name. Don't remember COLLECT_GCC.
+ * call.c (maybe_handle_implicit_object): Handle QUAL_CONVs. Make
+ sure the type of the REF_BIND is a reference type.
+ (maybe_handle_ref_bind, compare_ics): Rename reference_type to
+ target_type for clarity.
-Wed Apr 19 02:32:40 1995 Mike Stump <mrs@cygnus.com>
+ * parse.y (xcond): Move call to condition_conversion ...
+ * semantics.c (finish_for_cond): Here.
+ * parse.c: Regenerated.
+
+1998-05-24 Jason Merrill <jason@yorick.cygnus.com>
- * search.c (virtual_context): New function to get the virtual
- context of a function.
- (expand_upcast_fixups): New function to generate runtime vtables.
- (fixup_virtual_upcast_offsets): Ditto.
- (expand_indirect_vtbls_init): Use fixup_virtual_upcast_offsets to
- ensure that the this offsets for upcasts from virtual bases into
- other virtual bases or non-virtual bases are correct at construction
- time and destruction time.
- * class.c (fixup_vtable_deltas): Modify to fixup all offsets in all
- vtables in all virtual bases, instead of just one vtable in each
- virtual base.
- (fixup_vtable_deltas1): Ditto.
+ * decl.c (push_namespace): Namespaces have type void.
+ * typeck2.c (incomplete_type_error): Complain about namespace
+ used as expression.
+ * typeck.c (decay_conversion): Likewise.
-Tue Apr 18 03:57:35 1995 Michael Meissner (meissner@cygnus.com)
+1998-05-24 Martin von Löwis <loewis@informatik.hu-berlin.de>
- * Makefile.in (lex.o): Add dependency on c-pragma.h.
+ * error.c (dump_expr): Support namespaces.
- * lex.c (handle_sysv_pragma): Use NULL_PTR and NULL_TREE as
- appropriate, instead of 0.
+1998-05-23 Jason Merrill <jason@yorick.cygnus.com>
-Mon Apr 17 12:28:42 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cp-tree.def: Add SRCLOC.
+ * cp-tree.h: Add struct tree_srcloc and accessor macros.
+ * tree.c (build_srcloc, build_srcloc_here): New fns.
+ * pt.c (add_pending_template): Use build_srcloc_here.
+ (push_tinst_level): Update last_template_error_tick before erroring.
+ (instantiate_decl): Restore lineno and input_filename before
+ calling add_pending_template.
+ * decl2.c (finish_file): Set up lineno and input_filename for
+ pending templates.
- * decl.c (pushdecl): Use decls_match, not duplicate_decls, for
- comparing local and global decls.
+1998-05-22 Jason Merrill <jason@yorick.cygnus.com>
-Fri Apr 14 01:46:52 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (lang_print_error_function): New fn.
+ (init_decl_processing): Set print_error_function to use it.
+ * errfn.c (cp_thing): Don't call maybe_print_template_context here.
- * typeck.c (convert_arguments): Only prohibit passing to ... of
- types with non-trivial copy constructors.
+ * call.c (maybe_handle_ref_bind): Propagate ICS_USER_FLAG and
+ ICS_BAD_FLAG.
- * repo.c (repo_template_used): Don't try to mess with no id.
+ * cvt.c (ocp_convert): Don't set LOOKUP_NO_CONVERSION for
+ copy-initialization.
-Fri Apr 14 23:32:50 1995 Per Bothner <bothner@rtl.cygnus.com>
+ * class.c (build_vtable_entry): Use int_fits_type_p.
+ (build_vtable): Pass a signed offset to build_vtable_entry.
+ (prepare_fresh_vtable, modify_one_vtable, fixup_vtable_deltas1,
+ set_rtti_entry): Likewise.
- * decl.c (duplicate_decls): Use cp_warning_at for redundant-decls.
+1998-05-22 Per Bothner <bothner@cygnus.com>
-Thu Apr 13 15:37:42 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * cp-tree.h: Add comments documenting which LANG_FLAGS are used.
+ (C_TYPE_VARIABLE_SIZE, C_DECL_VARIABLE_SIZE): Removed, not used.
- * cp-tree.h (current_tinst_level): Delete declaration, since it's
- static inside pt.c.
+1998-05-22 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_modify_expr): Catch incompatible array assignment.
+ * pt.c (print_template_context): Use fprintf instead of cp_error.
- * parse.y (attribute_list, attrib): Rewrite actions to feed the
- right stuff to decl_attributes.
+ * pt.c (determine_specialization): Just return an error_mark_node.
+ Also print the decl we want in error messages. If we complain,
+ return error_mark_node.
+ (tsubst_friend_function): Set lineno and input_filename so
+ error messages will be useful.
+ (instantiate_template): Just return an error_mark_node.
+ (check_explicit_specialization): Don't mess with a returned
+ error_mark_node.
-Thu Apr 13 11:24:10 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (print_template_context): Add new argument.
+ (maybe_print_template_context): New fn.
+ (push_tinst_level): Increment tinst_level_tick.
+ (pop_tinst_level): Likewise.
+ * errfn.c (cp_thing): Call maybe_print_template_context. Use
+ xrealloc instead of xmalloc.
- * search.c (dfs_debug_mark): Check for magic virtual like
- import_export_vtable.
+ * typeck.c (build_unary_op, CONVERT_EXPR): Propagate TREE_CONSTANT.
- * typeck.c (build_binary_op_nodefault): Don't call cp_pedwarn with
- four args.
+1998-05-21 Jason Merrill <jason@yorick.cygnus.com>
-Wed Apr 12 12:02:57 1995 Jason Merrill <jason@deneb.cygnus.com>
+ * pt.c (tsubst_friend_class): Don't call redeclare_class_template
+ if the template we looked up is the same as the one we already
+ have.
- * decl2.c (finish_file): Move prevtable pass before needs_messing_up
- decision.
+Thu May 21 11:54:44 1998 Dave Brolley <brolley@cygnus.com>
-Tue Apr 11 11:20:27 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * lex.c: (handle_sysv_pragma): FILE* parameter not used.
+ (cpp_reader,parse_in): Add for cpplib.
+ (check_newline): Call handle_sysv_pragma with new interface.
+ (check_newline): Call GET_DIRECTIVE_LINE, not get_directive_line.
- * decl.c (finish_decl): If we're writing out a static data member of
- a class, we want the debug info for that class.
+ * input.c: (yy_cur,yy_lim,yy_get_token,GETC): Add for cpplib.
+ (sub_getch): Call GETC for cpplib.
- * gc.c (build_t_desc): Check linkage of a class properly.
+ * cp-tree.h: (get_directive_line): Different prototype for cpplib.
+ (GET_DIRECTIVE_LINE): Macro wrapper for get_directive_line.
- * class.c (finish_struct): Set the 'headof' offset for the main
- vtable properly.
- (prepare_fresh_vtable): Fix typeinfo pointer here.
- (modify_one_vtable): Instead of here.
+ * Makefile.in (CXX_OBJS): add @extra_cxx_objs@ for cpplib.
-Mon Apr 10 12:15:59 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-05-21 Jason Merrill <jason@yorick.cygnus.com>
- * repo.c (repo_get_id): New function to return the interesting
- identifier for a repo entity.
- (repo_template_used): Use it.
- (repo_template_instantiated): Mark the id as chosen.
- (init_repo): Record whether or not the id was chosen.
- (finish_repo): Note if an id was newly chosen.
+ * decl2.c (maybe_make_one_only): New fn.
+ (import_export_vtable): Use it.
+ (import_export_decl): Likewise.
+ * pt.c (mark_decl_instantiated): Likewise.
- * pt.c (do_function_instantiation): Call repo_template_instantiated.
- (do_type_instantiation): Ditto. Don't diagnose multiple
- instantiation.
+1998-05-21 Mark Mitchell <mmitchell@usa.net>
- * decl2.c (finish_file): Use DECL_NOT_REALLY_EXTERN when deciding
- whether or not to synthesize a method.
+ * decl2.c (find_representative_member): Rename to ...
+ (build_anon_union_vars): New function.
+ (finish_anon_union): Fix stupidity of previous change.
- Undo these changes:
- * class.c (finish_vtbls): build more vtables if flag_rtti is on.
- * class.c (modify_all_direct_vtables): ditto.
- * init.c (expand_direct_vtbls_init): expand more vtables if
- flag_rtti is on.
+1998-05-20 Jason Merrill <jason@yorick.cygnus.com>
-Sat Apr 8 17:45:41 1995 Mike Stump <mrs@cygnus.com>
+ * decl.c (grokfndecl): Handle definition of specialization in
+ friend declaration.
- * gc.c (build_headof): Use ptrdiff_type_node instead of
- integer_type_node on pointer arithmetic.
+ * error.c (dump_decl): Fix LOOKUP_EXPR handling.
-Sat Apr 8 11:57:04 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-05-20 Mark Mitchell <mmitchell@usa.net>
- * typeck.c (build_modify_expr): Undo previous change.
+ * class.c (delete_duplicate_fields_1): Use DECL_DECLARES_TYPE_P
+ to look for type declarations.
+ (finish_struct): Deal with templates on the CLASSTYPE_TAGS list.
+ * cp-tree.h (DECL_DECLARES_TYPE_P): New macro.
+ (finish_member_class_template): Declare.
+ * decl.c (pushtag): Put member class templates on the
+ CLASSTYPE_TAGS list, just as for ordinary member classes.
+ (pushdecl_class_level): Use DECL_DECLARES_TYPE_P.
+ (lookup_tag): Look for IDENTIFIER_CLASS_VALUEs, just as with
+ IDENTIFIER_NAMESPACE_VALUEs.
+ * parse.y (component_decl): Move code to ...
+ * semantics.c (finish_member_class_template): New function.
+ Don't put member class templates on the list of components for a
+ class.
+ * parse.c: Regenerated.
+ * pt.c (classtype_mangled_name): Don't try DECL_CONTEXT on types.
+ In fact, don't use DECL_CONTEXT at all here.
-Thu Apr 6 01:23:50 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-05-20 Martin von Loewis <loewis@informatik.hu-berlin.de>
- * Makefile.in (compiler): Remove ../cc1plus before rebuilding it.
+ * decl.c (record_unknown_type): New function.
+ (init_decl_processing): Call it for the unknown and global type
+ nodes.
- * repo.c (get_base_filename): Put the .rpo file in the directory
- with the object file, not the source.
+1998-05-20 Mark Mitchell <mmitchell@usa.net>
- * typeck.c (build_conditional_expr): Handle pmf's better.
+ * decl2.c (find_representative_member): New function.
+ (finish_anon_union): Use it.
- * repo.c (finish_repo): Also use ASM_OUTPUT_LABELREF to print out
- the name of the symbol.
+ * cp-tree.h (MAIN_NAME_P): New macro.
+ (DECL_MAIN_P): Likwise.
+ * decl.c (pushdecl): Avoid crashing on redefinitions of `main'.
+ (grokfndecl): Use the new macros.
+ (grokdeclarator): Likewise.
+ (start_function): Likewise.
+ (store_parm_decls): Likewise.
+ (finsh_function): Likewise.
+ * friend.c (do_friend): Likewise.
+ * typeck.c (build_function_call_real): Likewise.
+ (build_unary_op): Likewise.
-Wed Apr 5 15:24:12 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed May 20 02:16:01 1998 Jason Merrill <jason@yorick.cygnus.com>
- * repo.c (open_repo_file): Make repo filename DOS-compliant.
- (*): Also write a new repo file if some previously-used
- templates are no longer used. Only remember the identifier.
+ * decl2.c (start_objects, finish_objects, do_dtors,
+ do_ctors): Split out from...
+ (finish_file): ...here.
- * lex.c (cons_up_default_function): If this function belongs to a
- template class, call repo_template_used for it.
+Tue May 19 20:36:23 1998 Jason Merrill <jason@yorick.cygnus.com>
- * repo.c (repo_template_used): Using a class means using its vtable,
- if any.
- (finish_repo): Ditto.
+ * tree.c (is_overloaded_fn): Don't abort on placeholders from
+ push_class_decls.
- * typeck.c (build_modify_expr): Only wrap TARGET_EXPRs in RTL_EXPRs
- if the type has a complex copy constructor.
+Tue May 19 15:16:22 1998 Brendan Kehoe <brendan@cygnus.com>
- * decl2.c (lang_decode_option): -frepo implies
- -fno-implicit-templates.
+ * class.c (is_empty_class): Return 0 if TYPE is an error_mark_node.
- * decl.c (start_function): Clear current_{base,member}_init_list.
+ * error.c (dump_expr): Handle an ARROW_EXPR.
- * lex.c (init_lex): Also unset *_eq if ! flag_operator_names.
+Tue May 19 15:13:39 1998 Mark Mitchell <mmitchell@usa.net>
-Tue Apr 4 16:11:08 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (saveable_obstack): Declare.
+ (pushdecl): Copy TYPE_DECLs to the same obstack as the type they
+ declare, if necessary.
- * decl.c (struct cp_function): Add {base,member}_init_list.
- (push_cp_function_context): Save current_{base,member}_init_list.
- (pop_cp_function_context): Restore them.
+Tue May 19 14:50:27 1998 Mark Mitchell <mmitchell@usa.net>
-Mon Apr 3 16:55:08 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (compare_qual): Remove.
+ (is_subseq): Tweak.
+ (is_properly_derived_from): New function.
+ (maybe_handle_ref_bind): Likewise.
+ (maybe_handle_implicit_object): Likewise.
+ (compare_ics): Modify substantially to bring into conformance with
+ the standard.
+ * cp-tree.h (TYPE_PTRMEMFUNC_OBJECT_TYPE): New macro.
+ (comp_cv_qualification): Declare.
+ (comp_cv_qual_signature): Likewise.
+ * typeck.c (comp_cv_qualification): Likewise.
+ (comp_cv_qual_signature): Likewise.
- * repo.c (get_base_filename): Take filename parm, fix logic bug.
+Tue May 19 10:05:02 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * typeck.c (build_compound_expr): Do not warn about a compound expr
- in which the first expression has no side effects.
- (build_x_compound_expr): Warn here instead.
- (build_conditional_expr): Don't warn about a conditional expression
- between an enum and the type it promotes to.
+ * Makefile.in (parse.o): Depend on toplev.h.
- * init.c (build_new): Handle initialization of arrays of builtins
- properly.
+ * class.c (typecode_p): Remove prototype and definition.
-Mon Apr 3 15:08:04 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * cp-tree.h (currently_open_class, is_empty_class, member_p):
+ Add prototype.
- * repo.c: Include config.h to get definitions of bcopy and rindex
- on systems that don't have them (e.g., SVR4).
+ * decl.c (push_overloaded_decl_top_level): Remove prototype and
+ definition.
-Mon Apr 3 14:41:55 1995 Mike Stump <mrs@cygnus.com>
+ * errfn.c (cp_error): Cast function pointer `error' to (errorfn *)
+ in call to `cp_thing'.
+ (cp_warning): Likewise for function pointer `warning'.
- * decl2.c (finish_table): Pass NULL_TREE instead of init to
- finish_decl so that it won't try and do error checking on the
- initializer.
+ * except.c (do_function_call): Remove prototype and definition.
+ (call_eh_info): Wrap variable `t1' in macro NEW_EH_MODEL.
-Mon Apr 3 10:45:50 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * method.c (is_java_type): Add prototype and make it static.
- * repo.c (get_base_filename): Analyze COLLECT_GCC_OPTIONS to
- determine whether this compile used -c -o.
- (open_repo_file): Use get_base_filename. Remove the extension.
- (finish_repo): Spit out the values of main_input_filename,
- COLLECT_GCC and COLLECT_GCC_OPTIONS.
+ * parse.y: Include toplev.h.
- * parse.y (structsp): Add TYPENAME_KEYWORD complex_type_name.
+ * pt.c (type_unification): Remove unused variable `arg'.
+ (instantiate_decl): likewise for `save_ti'.
-Sun Apr 2 23:43:51 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * tree.c (propagate_binfo_offsets): Likewise for `base_binfos'.
+
+Tue May 19 02:43:25 1998 Jason Merrill <jason@yorick.cygnus.com>
- * search.c (compute_access): Don't try to do access control on
- nested types.
+ * init.c (build_member_call): Handle template_ids.
+ * parse.y (primary): Add global_scope template_id.
-Fri Mar 31 10:14:23 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Mon May 18 23:22:52 1998 Jason Merrill <jason@yorick.cygnus.com>
- * repo.c: New file to handle things repo.
+ * decl2.c (get_sentry): Use end_temporary_allocation.
+ Don't declare permanent_obstack.
- * pt.c (instantiate_template): Call repo_template_used if the
- definition is accessible.
- (mark_function_instantiated): Split out from
- do_function_instantiation.
- (mark_class_instantiated): Split out from do_type_instantiation.
+Mon May 18 12:28:44 1998 Mark Mitchell <mmitchell@usa.net>
- * parse.y (template_instantiate_once): Call repo_template_used.
+ * parse.y (.finish_new_placement): New non-terminal.
+ (unary_expr, new_type_id): Use it.
+ * parse.c: Regenerated.
+
+Mon May 18 12:20:27 1998 Brendan Kehoe <brendan@cygnus.com>
- * lex.c (lang_init): Call init_repo.
+ * pt.c (redeclare_class_template): Say where the original definition
+ of the template-parameter's default argument appeared.
- * decl2.c: Handle flag_use_repository.
- (finish_file): Call finish_repo.
+Mon May 18 03:00:57 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (start_method): Call repo_template_used if this is a
- template method.
+ * call.c (build_over_call): Tweak empty class handling.
- * Makefile.in (CXX_OBJS): Add repo.o.
- (repo.o): Add dependencies.
+ * decl.c (make_typename_type): Use currently_open_class.
- * Make-lang.in (CXX_SRCS): Add repo.c.
+ * class.c (instantiate_type): Don't abort on TREE_NONLOCAL_FLAG.
- * decl.c (start_function): If DECL_INTERFACE_KNOWN and
- DECL_NOT_REALLY_EXTERN are both set, unset DECL_EXTERNAL.
+Mon May 18 01:43:01 1998 Martin v. Loewis <loewis@informatik.hu-berlin.de>
- * typeck.c (build_binary_op_nodefault): Identify the invalid operand
- types used.
+ * decl.c (lookup_name_real): Don't look at IDENTIFIER_LOCAL_VALUE
+ for a type unless it is one.
- * decl.c (duplicate_decls): Propagate DECL_NOT_REALLY_EXTERN.
+ * class.c (finish_struct_1): Use OVL_CURRENT in error message.
-Thu Mar 30 17:54:42 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Mon May 18 01:24:08 1998 Jeffrey A Law (law@cygnus.com)
- * typeck.c (build_binary_op_nodefault): Tidy up use of build_type
- and result_type. When checking for comparison between signed
- and unsigned, use result_type rather than the (possibly shortened)
- type of op0. Also, don't warn about equality comparison of a
- signed operand to an unsigned constant that fits in the signed
- type.
+ * Makefile.in (program_transform_name, objdir): Define.
- * method.c (do_build_copy_constructor): Reverse
- current_base_init_list after we've built it up.
+ * Makefile.in (BISON): Use bison from the build tree if it exists.
+ (FLEX): Similarly.
-Thu Mar 30 14:35:18 1995 Mike Stump <mrs@cygnus.com>
+Sun May 17 14:52:08 1998 Martin v. Loewis <loewis@informatik.hu-berlin.de>
- * except.c (build_throw): Never warn about the value of throw not
- being used.
+ * typeck.c (type_unknown_p): Return true for TREE_LIST also.
-Thu Mar 30 13:16:54 1995 Mike Stump <mrs@cygnus.com>
+ * call.c (build_method_call): Use TYPE_MAIN_VARIANT on typedefs.
- * except.c (expand_start_catch_block): Check for bad catch parameter
- declarations.
+Sun May 17 14:51:41 1998 Jason Merrill <jason@yorick.cygnus.com>
-Thu Mar 30 13:06:11 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (build_scoped_method_call): Likewise.
- * decl.c (finish_function): Only set DECL_NOT_REALLY_EXTERN if
- DECL_EXTERNAL is not already set.
+Sun May 17 13:53:48 1998 Mark Mitchell <mmitchell@usa.net>
-Thu Mar 30 11:26:24 1995 Mike Stump <mrs@cygnus.com>
+ * init.c (build_new_1): Call suspend_momentary around the creation
+ of values that must be saved for exception handling.
+ * parse.y (.build_new_placement): New non-terminal.
+ (unary_expr, new_placement): Use it.
+ * parse.c: Regenerated.
+
+Sun May 17 12:32:08 1998 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (emit_thunk): Let poplevel know that the last level is
- for a function so it can create a BLOCK_NODE and set DECL_INITIAL.
+ * decl.c (duplicate_decls): Use CANONICAL_TYPE_VARIANT to compare
+ old and new types.
-Thu Mar 30 11:15:06 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (tsubst): Make sure that BINFO_TYPE of new binfos is the
+ canonical type.
- * decl2.c (import_export_inline): Don't set DECL_NOT_REALLY_EXTERN
- here.
+ * call.c (build_over_call): Don't use IS_SIGNATURE on a namespace.
- * decl.c (grokdeclarator): OK, don't abort if we see a decl with
- METHOD_TYPE.
- (finish_function): Set DECL_EXTERNAL and DECL_NOT_REALLY_EXTERN on
- all deferred inlines.
+Fri May 15 20:28:00 1998 Jason Merrill <jason@yorick.cygnus.com>
-Wed Mar 29 19:35:02 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (start_decl): Revert problem change.
- * cp-tree.h (DECL_THIS_INLINE): New macro.
- (DECL_NOT_REALLY_EXTERN): New macro.
- (DECL_THIS_STATIC): New macro.
+ * Makefile.in (CONFLICTS): Fix.
- * decl.c: Lose all references to current_extern_inline. Break
- inline semantics into DECL_INLINE for actual inlining and
- DECL_THIS_INLINE for the linkage wierdness. Use DECL_THIS_STATIC.
- * decl2.c: Use DECL_NOT_REALLY_EXTERN to indicate that we want to
- emit an inline here. Associated changes.
- * lex.c: Ditto.
- * pt.c: Ditto.
- * typeck.c: Ditto.
+Fri May 15 15:34:02 1998 Benjamin Kosnik <bkoz@rhino.cygnus.com>
- * call.c (build_method_call): Don't bother trying to handle inlines
- specially.
- * cvt.c (convert_to_aggr): Ditto.
+ * decl.c (duplicate_decls): Clean up, add DECL_DATA_AREA bits.
- * pt.c (do_function_instantiation): Handle instantiation of
- public inlines, too.
+Fri May 15 00:46:05 1998 Jason Merrill <jason@yorick.cygnus.com>
-Wed Mar 29 16:04:25 1995 Mike Stump <mrs@cygnus.com>
+ * class.c (finish_struct_1): Use BINFO_SIZE.
- * except.c (init_exception_processing): Change the interface for
- __throw_type_match and add decl for new rtti matching routine
- __throw_type_match_rtti.
- (build_eh_type): New routine to build a run time descriptor for the
- expression given.
- (expand_start_catch_block): Update to use new calling convention for
- the matcher.
- (expand_throw): Update to use build_eh_type.
+ * decl.c (start_decl): Use 'tem'.
-Mon Mar 27 07:14:33 1995 Warner Losh <imp@village.org>
+Thu May 14 16:30:47 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
- * g++.c: Removed __NetBSD__ from conditional.
- Declare strerror if HAVE_STRERROR is defined; otherwise
- declare sys_errlist and sys_nerr.
- (my_strerror): New function.
+ * exception.cc: Include eh-common.h.
+ (struct cp_eh_info): add eh_info struct with NEW_EH_MODEL.
+ (__cplus_type_matcher): First stab at new C++ runtime type matcher.
+ (__cp_push_exception): Initialize eh_info struct as well.
+ * except.c: Remove local structs and include eh-common.h.
+ (init_exception_processing): Set language and version codes.
+ (call_eh_info): add presence of eh_info to runtime description of
+ struct cp_eh_info.
+ (expand_end_eh_spec): call start_catch_block() and end_catch_block().
+ * semantics.c (finish_try_block): call start_catch_block() and
+ end_catch_block().
+ * parse.y (function_try_block): call start_catch_block() and
+ end_catch_block().
-Tue Mar 28 14:16:35 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Thu May 14 12:27:34 1998 Brendan Kehoe <brendan@cygnus.com>
- * search.c (get_binfo): Don't try to be so clever.
+ * typeck.c (original_type): New function.
+ (common_type): Use it to get the DECL_ORIGINAL_TYPE for T1 and T2,
+ to see if they're actually the same.
+ * cp-tree.h (original_type): Declare.
- * tree.c (copy_to_permanent): Also suspend_momentary().
+Wed May 13 12:54:30 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * cvt.c (cp_convert_to_pointer): Hand off to convert_fn_pointer even
- if the types are the same.
+ * Makefile.in (lex.o): Depend on output.h.
+
+ * call.c (add_function_candidate): Remove unused variable `cand'.
+ (add_conv_candidate): Likewise.
+ (build_builtin_candidate): Likewise.
+
+ * cp-tree.h: Add prototype for `types_overlap_p'.
+
+ * decl.c (signal_catch): Mark parameter `sig' with ATTRIBUTE_UNUSED.
+
+ * decl2.c (merge_functions): Remove unused variables `tmp' and
+ `tempn'.
+
+ * error.c (expr_as_string): Mark parameter `v' with ATTRIBUTE_UNUSED.
+ (code_as_string): Likewise.
+ (language_as_string): Likewise.
+ (parm_as_string): Likewise.
+ (op_as_string): Likewise.
+ (assop_as_string): Likewise.
+ (cv_as_string): Likewise.
+
+ * lex.c: Include output.h.
+
+ * pt.c (type_unification): Cast first argument of `bzero' to a char*.
+
+ * search.c (dfs_no_overlap_yet): Mark parameter `t' with
+ ATTRIBUTE_UNUSED.
+
+ * tinfo.cc (__class_type_info::dcast): Change the type of variable
+ `i' from int to size_t.
+
+ * typeck.c (language_lvalue_valid): Mark parameter `exp' with
+ ATTRIBUTE_UNUSED.
+
+Tue May 12 21:37:49 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * error.c (dump_simple_decl): Use DECL_CLASS_SCOPE_P and/or
+ DECL_NAMESPACE_SCOPE_P.
+ (lang_decl_name): Likewise.
+ * pt.c (tsubst_friend_function, tsubst): Likewise.
+ * decl.c (pushdecl, redeclaration_error_message, start_decl,
+ cp_finish_decl, start_function): Likewise.
+ * class.c (finish_struct_1): Likewise.
+ * call.c (build_over_call): Likewise.
+ (compare_ics): Use DERIVED_FROM_P.
+
+Tue May 12 07:24:18 1998 Mark Mitchell <mmitchell@usa.net>
+
+ * cp-tree.h (CANONICAL_TYPE_VARIANT): New macro.
+ * method.c (build_mangled_name): Use it.
+ (build_decl_overload_real): Likewise.
+
+ * error.c (dump_simple_decl): New function, broken out from ...
+ (dump_decl): Use it.
+
+Mon May 11 11:38:07 1998 Mark Mitchell <mmitchell@usa.net>
+
+ * ptree.c (lang_print_xnode): Add missing `break'.
+
+ * pt.c (tsubst): Remove duplicate check for IDENTIFIER_NODE.
+
+ * call.c (add_template_candidate): Adjust for changes to
+ fn_type_unification.
+ (add_template_candidate_real): Likewise.
+ (add_template_conv_candidate): Likewise.
+ (build_user_type_conversion_1): Likewise.
+ (build_new_function_call): Likewise.
+ (build_object_call): Likewise.
+ (build_new_op): Likewise.
+ (build_new_method_call): Likewise.
+ * class.c (instantiate_type): Likewise.
+ * cp-tree.h (unification_kind_t): New type.
+ (fn_type_unification): Adjust prototype.
+ (type_unificaiton): Likewise.
+ * pt.c (UNIFY_ALLOW_NONE): New macro.
+ (UNIFY_ALLOW_MORE_CV_QUAL): Likewise.
+ (UNIFY_ALLOW_LESS_CV_QUAL): Likewise.
+ (UNIFY_ALLOW_DERIVED): Likewise.
+ (unify): Change prototype.
+ (maybe_adjust_types_for_deduction): New function.
+ (check_cv_quals_for_unify): Likewise.
+ (determine_specialization): Adjust.
+ (fn_type_unification): Likewise.
+ (type_unification): Likewise.
+ (type_unification_real): Likewise. Use
+ maybe_adjust_types_for_deduction. Fix mishandling of
+ back-unification of template functions passed as arguments. Pass
+ appropriate combination of UNIFY_ALLOW_* to unify.
+ (unify): Remove unused NTPARMS parameter. Use
+ check_cv_quals_for_unify. Remove bogus code that allowed
+ too-generous unification in order to adhere more closely to standard.
+ (get_bindings_real): Adjust.
+ (get_class_bindings): Likewise.
+
+ * method.c (build_overload_identifier): Only use the innermost
+ template arguments when mangling.
+ * pt.c (tsubst_template_argument_vector): New function.
+ (complete_template_args): Deal with the situation where the
+ extra_args contain more than one level of arguments.
+ (lookup_template_class): Deal with member template classes, which
+ may have more than one level of arguments.
+ (tsubst): Don't tsbust into the TREE_TYPE of an IDENTIFIER_NODE.
+ Improve handling of member template classes. Use
+ DECL_PRIMARY_TEMPLATE instead of inline expansion. Use
+ tsubst_template_argument_vector where appropriate.
+ (regenerate_decl_from_template): Break out from ...
+ (instantiate_decl): Here.
+
+ * lex.c (yyprint): Remove TYPENAME_ELLIPSIS.
+ * parse.h: Regenerated.
+ * parse.c: Really regenerated.
+
+ * cp-tree.h (finish_unary_op_expr): New function.
+ (finish_id_expr): Likewise.
+ (begin_new_placement): Likewise.
+ (finish_new_placement): Likewise.
+ (finish_declarator): Likewise.
+ (finish_translation_unit): Likewise.
+ (finish_parmlist): Likewise.
+ (begin_class_definition): Likewise.
+ (finish_class_definition): Likewise.
+ (finish_default_args): Likewise.
+ (finish_inline_definitions): Likewise.
+ * parse.y (GCC_ASM_KEYWORD): Remove.
+ (TYPENAME_ELLIPSIS): Likewise.
+ * parse.c: Regenerated.
+ Use new functions in semantics.c in the actions for many rules.
+ * gxx.gperf (GCC_ASM_KEYWORD): Just use ASM_KEYWORD.
+ * hash.h: Regenerated.
+ * semantics.c (finish_expr_stmt): Allow NULL expr.
+ (finish_unary_op_expr): New function, containing
+ code previously in parse.y.
+ (finish_id_expr): Likewise.
+ (begin_new_placement): Likewise.
+ (finish_new_placement): Likewise.
+ (finish_declarator): Likewise.
+ (finish_translation_unit): Likewise.
+ (finish_parmlist): Likewise.
+ (begin_class_definition): Likewise.
+ (finish_class_definition): Likewise.
+ (finish_default_args): Likewise.
+ (finish_inline_definitions): Likewise.
+
+Sun May 10 23:43:13 1998 Mark Mitchell <mmitchell@usa.net>
+
+ * typeck.c (build_c_cast): Don't decay arrays and functions to
+ pointer type when converting to a class type.
+
+Sun May 10 22:53:56 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * cp-tree.h (DECL_NAMESPACE_SCOPE_P): New macro.
+ (DECL_CLASS_SCOPE_P): Likewise.
+
+Sun May 10 22:48:22 1998 H.J. Lu (hjl@gnu.org)
+
+ * class.c (finish_struct_1): Use OVL_CURRENT on TREE_VEC_ELT.
+ * decl2.c (constructor_name_full): Likewise.
+
+Sun May 10 22:48:12 1998 Mike Stump <mrs@wrs.com>
+
+ * tree.c (mapcar): Add OVERLOAD support.
+
+ * init.c (resolve_offset_ref): We must use basetype_path before we
+ destroy it with a call to convert_pointer_to.
+
+Sat May 9 14:44:37 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * class.c (currently_open_class): New fn.
+ * decl.c (lookup_name_real): Use it.
+ * search.c (lookup_field): Likewise.
+
+Fri May 8 23:32:42 1998 Martin von Loewis <loewis@informatik.hu-berlin.de>
+
+ * cp-tree.def (OVERLOAD): New node.
+ * cp-tree.h (BINDING_TYPE, SET_IDENTIFIER_GLOBAL_VALUE,
+ SET_IDENTIFIER_NAMESPACE_VALUE): Define.
+ (NAMESPACE_BINDING): Remove.
+ (IDENTIFIER_GLOBAL_VALUE, IDENTIFIER_NAMESPACE_VALUE): Use
+ namespace_binding.
+ (OVL_FUNCTION, OVL_CHAIN, OVL_CURRENT, OVL_NEXT, OVL_USED):
+ Define.
+ (tree_overload): New struct.
+ (IDENTIFIER_TYPE_VALUE): Use identifier_type_value.
+ (REAL_IDENTIFIER_TYPE_VALUE): Define.
+ (IDENTIFIER_HAS_TYPE_VALUE): Use IDENTIFIER_TYPE_VALUE.
+ (lang_decl_flags): Remove in_namespace.
+ (lang_decl): Remove chain.
+ (DECL_CHAIN, DECL_NAMESPACE): Remove.
+ (flag_honor_std): Declare extern.
+ (identifier_type_value, pushdecl_namespace_level, push_using_decl,
+ namespace_binding, set_namespace_binding,
+ lookup_function_nonclass, cat_namespace_levels,
+ set_decl_namespace, lookup_arg_dependent, binding_init, ovl_cons,
+ scratch_ovl_cons, ovl_member, build_overload): Declare.
+ (decl_list_length, get_namespace_id, current_namespace_id,
+ overloaded_globals_p): Remove.
+ (lookup_using_namespace, qualified_lookup_using_namespace): Change
+ return type.
+ (push_scratch_obstack): New macro.
+ * call.c (add_function_candidate): Special-case type of OVERLOAD node.
+ (build_user_conversions_1): Iterate using OVL_NEXT for ctors,
+ convs, fns.
+ (build_new_function_call): Iterate using OVL_CHAIN.
+ Print DECL_NAME in when reporting ambiguities.
+ (build_object_call): Iterate using OVL_NEXT for fns, convs.
+ (build_new_op): Call lookup_function_nonclass.
+ Iterate using OVL_NEXT.
+ (build_op_delete_call): Change detection of members.
+ Do not wrap TREE_LIST around fields and single global functions.
+ (build_over_call): Don't push a class level if the context is a
+ namespace.
+ (build_new_method_call): Iterate using OVL_NEXT.
+ * class.c (add_method): Chain overloaded members using
+ build_overload. Remove copying of method.
+ (grow_method): When iterating through the obstack, expect OVERLOAD
+ nodes. Chain overload members.
+ (finish_struct_methods): Chain overload members. Unpack OVERLOAD
+ nodes in call to get_baselinks.
+ (duplicate_tag_error): Expect OVERLOAD nodes when unchaining.
+ (finish_struct_1): Iterate over ctor using OVL_NEXT. Handle
+ fdecls that are OVERLOAD nodes.
+ (validate_lhs): New function.
+ (instantiate_type): Do not copy OVERLOAD nodes. Remove dead
+ code. Use DECL_NAME in error messages. Split code between global
+ and member function processing.
+ * decl.c (global_type_node): New static variable.
+ (in_std): New global.
+ (struct binding_level): New field usings.
+ (resume_binding_level): Assert that we are not in a class.
+ (toplevel_bindings_p): Just check for namespace_p or
+ pseudo_global.
+ (resume_level): Remove.
+ (find_binding): New function.
+ (binding_for_name): Call it.
+ (namespace_binding, set_namespace_binding): New functions.
+ (push_namespace): Associate binding level with new namespace,
+ resume_binding_level for existing namespace. Remove old code.
+ Fake std by counting.
+ (store_bindings): Use REAL_IDENTIFIER_TYPE_VALUE.
+ (maybe_push_to_top_level): Save current namespace.
+ (pop_from_top_level): Restore saved namespace.
+ (pop_namespace): Call suspend_binding_level. Remove old code.
+ (cat_namespace_levels): New function.
+ (set_identifier_type_value_with_scope): For namespace bindings,
+ set BINDING_TYPE, and use global_type_node.
+ Use REAL_IDENTIFIER_TYPE_VALUE otherwise.
+ (identifier_type_value): New function.
+ (pushtag): If no context, use current_namespace.
+ (duplicate_decls): Don't process DECL_CHAIN.
+ (pushdecl): Set DECL_CONTEXT to current_namespace, if it is not
+ already set. Never reset it to NULL_TREE. Lookup global variables
+ in their namespace. Push overloaded templates if they are on
+ namespace level.
+ (pushdecl_namespace_level): New function.
+ (pushdecl_top_level): Implement using pushdecl_namespace_level.
+ (pushdecl_using_decl): New function.
+ (overloaded_globals_p): Remove.
+ (push_overloaded_decl): Create OVERLOAD nodes, and iterate through
+ them. Use namespace_binding and set_namespace_value.
+ (redeclaration_error_message): Complain if the declarations come
+ from different namespaces.
+ (lookup_tag): On namespace level, look in the BINDING_TYPE.
+ (lookup_namespace_name): Pass tree_bindings from stack. Remove
+ old code.
+ (select_decl): New function.
+ (lookup_name_real): Call it for qualified and unqualified lookup.
+ Pass tree_bindings from the stack.
+ If prefer_type is 1, also accept namespaces.
+ (lookup_function_nonclass): New function.
+ (init_decl_processing): Set the binding level of the global
+ namespace to global_binding_level.
+ Build a proper type list for __builtin_apply.
+ Initialize std_node to "fake std" if flag_honor_std is set.
+ Initialize global_type_node.
+ Allocated bad_alloc in namespace std if flag_honor_std.
+ (define_function): Set the DECL_CONTEXT to the current_namespace.
+ (start_decl): A namespace is not considered as a context here. If
+ the DECL_CONTEXT is a namespace, push the decl.
+ (cp_finish_decl): Check for namespaces used as initializers.
+ (grokfndecl): Add namespace parameter. Remove processing of
+ DECL_CHAIN.
+ (grokvardecl): Add namespace parameter.
+ (grokdeclarator): Process SCOPEs that are namespaces. For
+ mangling, temporarily set the DECL_CONTEXT on anonymous structs.
+ (start_function): Check for contexts that are namespaces.
+ Set context for declarations that have not been pushed.
+ (store_parm_decls): Check for ::main only.
+ (finish_function): Likewise.
+ (start_method): Check for contexts that are namespaces.
+ (start_method): Remove DECL_CHAIN processing.
+ * decl2.c (flag_honor_std): Declare.
+ (lang_decode_option): Set it if -fhonor-std or -fnew-abi is given.
+ (decl_namespace_list): New static global.
+ (grok_x_components): Ignore namespaces as type contexts.
+ (check_classfn): Expect OVERLOAD nodes.
+ (grokfield): Remove DECL_CHAIN processing.
+ (finish_file): Call cat_namespace_levels.
+ (merge_functions): New function.
+ (ambiguous_decl): Rewrite.
+ (lookup_using_namespace): Produce tree_bindings.
+ (qualified_lookup_using_namespace): Likewise.
+ (set_decl_namespace, decl_namespace, current_decl_namespace,
+ push_decl_namespace, pop_decl_namespace): New functions.
+ (arg_lookup): New struct.
+ (add_function, arg_assoc_namespace, arg_assoc_class,
+ arg_assoc_type, arg_assoc_args, arg_assoc, lookup_arg_dependent):
+ New functions.
+ (get_namespace_id, current_namespace_id): Remove.
+ (do_toplevel_using_decl): Rewrite.
+ (do_class_using_decl): Complain about namespace qualifiers.
+ (do_using_directive): Sorry if not on namespace level. Complain
+ about unknown namespaces.
+ * error.c (dump_aggr_type): Check for namespace contexts.
+ * except.c (init_exception_processing): Push terminate into std.
+ * friend.c (is_friend): A namespace is not a context, here.
+ * init.c (expand_member_init): Remove DECL_CHAIN processing.
+ (build_offset_ref): Process OVERLOAD nodes.
+ * lang-specs.h (__HONOR_STD): Define if -fnew-abi or -fhonor-std.
+ * lex.c (identifier_type): Loop using OVL_CHAIN.
+ (see_typename): Set looking_for_typename to 2.
+ (real_yylex): Likewise.
+ (do_identifier): Expect OVERLOAD nodes instead of TREE_LISTs.
+ (do_scoped_id): Expect OVERLOAD nodes.
+ Change calling convention for qualified_lookup_using_namespace.
+ (build_lang_decl): Don't set in_namespace anymore.
+ * method.c (typevec_size): New global.
+ (build_overload_nested_name): Return if global_namespace.
+ Otherwise, always expect a declaration context.
+ (build_qualified_name): Likewise.
+ Make sure we don't write beyond typevec_size.
+ (build_decl_overload_real): Likewise.
+ Allocate one extra slot for the namespace.
+ (hack_identifier): Mark code dead.
+ Process OVERLOAD and NAMESPACE_DECL nodes.
+ * parse.y (program): Pop namespaces until in global namespace.
+ (extdef): In a using-declaration, don't discard the identifier if
+ there is no declaration.
+ (left_curly): Ignore type contexts which are namespaces.
+ (typename_sub2): Use IDENTIFIER_TYPE_VALUE to retrieve the type
+ used as scope.
+ * pt.c (template_class_depth): Expect types to be namespaces.
+ (determine_specialization): Simplify by expecting OVERLOAD nodes.
+ (push_template_decl): Push into namespace level.
+ Reset ctx if it is a namespace.
+ Set DECL_CONTEXT to current_namespace if not set already.
+ Ignore real contexts that are namespaces.
+ (mangle_class_name_for_template): Skip global_namespace.
+ Mangle other namepaces as declarations.
+ (lookup_template_function): Set type of OVERLOAD nodes to unknown.
+ (lookup_template_class): Push into namespace of context.
+ If the context is a namespace, set it to global_namespace.
+ Use id_context for mangling.
+ (for_each_template_parm): Handle OVERLOAD and NAMESPACE_DECL nodes.
+ (tsubst_friend_function): Ignore namespace contexts.
+ Push into namespace level.
+ (tsubst): Handle NAMESPACE_DECL nodes.
+ Remove DECL_CHAIN processing.
+ (type_unification_real): Recognize OVERLOAD instead of TREE_LIST nodes.
+ * ptree.c (print_lang_identifier): Print bindings.
+ (lang_print_xnode): Print OVERLOAD nodes.
+ * rtti.c (init_rtti_processing): Push type_info into std.
+ * search.c (lookup_fnfields_here): Expect OVERLOAD nodes.
+ (lookup_fnfields_1, get_virtuals_named_this, get_matching_virtual,
+ dfs_debug_mark, dfs_pushdecls, dfs_compress_decls, add_conversions,
+ lookup_fnfields_here): Likewise.
+ Process all nodes, instead of going through TREE_CHAIN.
+ * sig.c (build_signature_pointer_or_reference_type): Set context
+ to global_namespace.
+ (build_signature_table_constructor): Expect OVERLOAD nodes.
+ * spew.c (yylex): Save old setting of looking_for_typename.
+ * tree.c (decl_list_length): Remove.
+ (binding_init): New function.
+ (count_functions): Rewrite.
+ (is_overloaded_fn): Expect OVERLOAD nodes.
+ (really_overloaded_fn, get_first_fn, lvalue_type): Likewise.
+ (ovl_cons, scratch_ovl_cons, build_overload, build_overload_after,
+ ovl_member): New functions.
+ * typeck.c (require_complete_type): Expect OVERLOAD nodes.
+ (type_unknown_p): Likewise.
+ (require_instantiated_type): Likewise.
+ (build_component_ref): Declare code dead.
+ (build_x_function_call): Create and expect OVERLOAD nodes.
+ (build_function_call_real): Check for ::main only.
+ (build_unary_op): Likewise. Expect OVERLOAD nodes.
+ (convert_for_assignment): Check for TREE_LIST before accessing
+ TREE_VALUE.
+ * decl.c (duplicate_decls): Check for namespace bindings instead
+ of global bindings.
+ (pushdecl, push_overloaded_decl, lookup_tag, lookup_name_real,
+ lookup_name_current_level, start_decl, xref_tag,
+ finish_enum): Likewise.
+ * init.c (build_offset_ref): Likewise.
+ * search.c (lookup_field): Likewise.
+ (lookup_fnfields): Likewise.
+ (dfs_debug_mark): Likewise.
+ * decl.c (poplevel): Use SET_IDENTIFIER_TYPE_VALUE.
+ (poplevel_class, pop_from_top_level): Likewise.
+ * decl2.c (finish_method): Likewise.
+ * class.c (build_vtable): Use SET_IDENTIFIER_GLOBAL_VALUE.
+ * decl.c (record_builtin_type): Likewise.
+ (init_decl_processing, grokfndecl): Likewise.
+ * lex.c (get_time_identifier, do_identifier, do_scoped_id): Likewise.
+ (make_lang_type): Likewise.
+ * parse.y (make_thunk): Likewise.
+ * pt.c (tsubst): Likewise.
+ * tree.c (debug_binfo): Likewise.
+ * exception.cc, new.cc, new1.cc, new2.cc, tinfo.cc, tinfo.h,
+ tinfo2.cc, inc/new.h: Add std qualifications.
+ * inc/new: Wrap with namespace std if __HONOR_STD.
+ * inc/typeinfo: Likewise.
+
+Fri May 8 00:43:50 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * call.c (build_user_type_conversion_1): Handle second_conv
+ properly for templates.
+
+Thu May 7 17:09:25 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
+
+ * method.c (build_decl_overload_real): Set TREE_USED flag to
+ zero for build_type_variants nodes as well.
+
+Wed May 6 19:27:09 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * pt.c (tsubst): Don't tsubst the type of an IDENTIFIER_NODE.
+
+Wed May 6 16:49:48 1998 Jim Wilson <wilson@cygnus.com>
+
+ * Makefile.in (call.o, class.o, decl.o, decl2.o, errfn.o, error.o,
+ except.o, expr.o, friend.o, init.o, lex.o, method.o, pt.o, repo.o,
+ rtti.o, search.o, semantics.o, sig.o, tree.o, typeck.o, typeck2.o,
+ xref.o): Add toplev.h dependencies.
+
+Wed May 6 16:44:58 1998 Jeffrey A Law (law@cygnus.com)
+
+ * errfn.c (cp_error, cp_warning): Remove declarations for
+ error and warning respectively.
+
+Wed May 6 14:28:18 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * error.c: Convert to using ctype macros defined in system.h.
+ * method.c: Likewise.
+ * xref.c: Likewise.
+ * lex.c: Likewise. Also remove redundant system header stuff.
+
+Wed May 6 06:36:41 1998 Robert Lipe <robertl@dgii.com>
+
+ * call.c, class.c, decl.c, decl2.c, errfn.c, error.c, except.c,
+ expr.c, friend.c, init.c, lex.c, method.c, pt.c, repo.c, rtti.c,
+ search.c, semantics.c, sig.c, tree.c, typeck.c, typeck2.c,
+ xref.c: Add include of toplev.h.
+
+Wed May 6 02:33:39 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * tree.c (perm_manip): Also regenerate the RTL of an extern.
+ (copy_to_permanent): Use end_temporary_allocation.
+
+Tue May 5 23:54:04 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * init.c (expand_vec_init): The initialization of each array
+ element is a full-expression.
+
+Tue May 5 18:24:13 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
+
+ * method.c (build_mangled_name): Add a call to build_type_variant
+ to get the right type.
+
+Tue May 5 01:25:03 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * Makefile.in: Add .SUFFIXES.
+
+ * cp-tree.def: Remove NAMESPACE_DECL.
+
+Sun May 3 01:32:14 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * call.c (build_over_call): Do evaluate arg even if it has empty
+ class type.
+ * decl.c (start_function): Don't push a member function.
+
+Thu Apr 30 18:59:23 1998 Jim Wilson <wilson@cygnus.com>
+
+ * Makefile.in (g++FAQ.info): Put -o option before input file.
+
+Thu Apr 30 13:05:33 EDT 1998 Andrew MacLeod <amacleod@cygnus.com>
+
+ * gxxint.texi: Add info for squangling codes K and B.
- * decl.c (start_function): Handle extern inlines more like C++ says
- we should.
+Tue Apr 28 13:22:01 1998 Mark Mitchell <mmitchell@usa.net>
- * init.c (build_member_call): Hand constructor calls off to
- build_functional_cast.
+ * semantics.c (begin_stmt_expr): Avoid duplicating the effect of
+ the expression in templates.
+ (finish_stmt_expr): Likewise.
- * typeck2.c (build_functional_cast): Use DECL_NESTED_TYPENAME to get
- the name of the type.
+1998-04-28 Brendan Kehoe <brendan@cygnus.com>
-Tue Mar 28 13:13:56 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * decl2.c (ambiguous_decl): Fix NAME parm to be a tree, not int.
- * decl.c (grokdeclarator): Check for the decl returned by
- grokfndecl to be null before using build_decl_attribute_variant.
+Mon Apr 27 13:58:10 1998 Mark Mitchell <mmitchell@usa.net>
-Mon Mar 27 18:04:41 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * decl.c (maybe_push_to_top_level): Always clear
+ current_template_parms and processing_template_decl.
+ (pushtag): Remove check of current_class_type and some comments,
+ since maybe_push_to_top_level no longer creates confusion.
- * init.c (build_new): Use build_pointer_type instead of
- TYPE_POINTER_TO.
+Sun Apr 26 12:10:18 1998 Mark Mitchell <mmitchell@usa.net>
-Fri Mar 24 12:11:24 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cp-tree.h (CLASSTYPE_IS_TEMPLATE): New macro.
+ (DECL_CLASS_TEMPLATE_P): Likewise.
+ (DECL_PRIMARY_TEMPLATE): Likewise.
+ (PRIMARY_TEMPLATE_P): Use it.
+ (push_template_decl_real): New function.
+ (redeclare_class_template): Take new template parameters as
+ input.
+ (is_specialization_of): New function.
+ (comp_template_args): Declare.
+ * decl.c (pushtag): Handle friend template classes.
+ (xref_tag): Likewise. Use new calling convention for
+ redeclare_class_template.
+ * decl2.c (grok_x_components): Handle friend templates.
+ * friend.c (is_friend): Use is_specialization_of where
+ appropriate. Deal with friend class templates.
+ (make_friend_class): Let a class template be friends with itself.
+ * pt.c (comp_template_args): Remove declaration.
+ (tsubst_friend_class): New function.
+ (push_template_decl_real): New function.
+ (push_template_decl): Use it.
+ (redeclare_class_template): Adjust for new calling convention.
+ (comp_template_args): Give it external linkage.
+ (instantiate_class_type): Use tsubst_friend_class to deal
+ with friend templates.
+ * typeck.c (comptypes): Use comp_template_args, rather than
+ expanding it inline.
+ * parse.y (component_decl): Handle a nested template type
+ like other component type declarations.
- * typeck.c (build_conditional_expr): Handle pmfs.
- (convert_for_assignment): Fix pmf support.
+ * pt.c (check_explicit_specialization): Handle overloaded
+ constructors correctly.
- * cvt.c (convert_fn_ptr): Support !flag_vtable_thunks.
- (cp_convert_to_pointer): Handle pmfs.
- (cp_convert): Pass pmfs to cp_convert_to_pointer.
+ * pt.c (mabybe_get_template_decl_from_type_decl): New function.
+ (lookup_template_class): Use it.
- * typeck.c (common_type): Handle inheritance for pmfs.
+Thu Apr 23 21:19:06 1998 Jason Merrill <jason@yorick.cygnus.com>
- * typeck2.c (build_m_component_ref): Do access control.
+ * cp-tree.def: Add WRAPPER. USER_CONV now only has two ops.
+ * cp-tree.h: Add WRAPPER support.
+ * call.c (add_candidate): Split out from add_*_candidate fns.
+ (build_over_call): Take the candidate instead of function and args.
+ Enforce access control here. Emit overload warnings here.
+ (add_warning): New fn.
+ (joust): Add WARN parm. If not set, call add_warning instead of
+ printing a warning. Reenable some warnings.
+ (tourney): Pass it.
+ (convert_like): Adjust.
+ (build_new_op): Adjust.
+ (build_new_function_call): Adjust.
+ (build_user_type_conversion_1): Adjust.
+ (USER_CONV_FN): Adjust.
+ * tree.c (build_expr_wrapper, build_expr_ptr_wrapper,
+ build_int_wrapper): New fns.
- * typeck.c (comp_target_types): Check for conversion to void *
- before checking trickier conversions.
+Thu Apr 23 18:27:53 1998 Mark P. Mitchell <mmitchell@usa.net>
- * decl.c (duplicate_decls): Propagate DECL_ABSTRACT_VIRTUAL_P.
+ * pt.c (unify): Fix typo in previous change.
- * pt.c (push_tinst_level): Complain if template instantiation depth
- is greater than max_tinst_depth.
+Thu Apr 23 09:32:58 1998 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (common_type): Assume that we can call common_type to
- unify the target type of a pointer.
+ * error.c (dump_type_real): Declare canonical_name.
-Thu Mar 23 00:48:44 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * typeck.c (comp_target_types): Fix PMFs.
- * decl2.c (finish_file): Don't synthesize methods at
- finish_vtable_prevardecl time. Do synthesize methods that are not
- used, but are public and not external.
+Wed Apr 22 13:24:48 1998 Mark Mitchell <mmitchell@usa.net>
- * cvt.c (build_type_conversion): Only give an error if for_sure.
+ * class.c (finish_struct): Set TREE_PRIVATE and TREE_PROTECTED for
+ the DECL_RESULTs of a member TEMPLATE_DECL, not just the
+ TEMPLATE_DECL.
- * typeck.c (comp_target_types): Only support pointer conversions if
- nptrs > 0.
+ * pt.c (tsubst): Decrease the template-level of
+ TEMPLATE_TEMPLATE_PARMS. Likewise for the DECL_INITIAL of a
+ TEMPLATE_PARM_INDEX.
+ (template_decl_level): New function.
+ (unify): Make sure to record unifications for template
+ parameters, even when the parameters exactly match the arguments.
+ Combine duplicated code for TEMPLATE_TEMPLATE_PARMs and
+ TEMPLATE_TYPE_PARMS. Don't try to unify template parameters that
+ aren't from the level we're currently working on.
-Wed Mar 22 19:30:15 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+Tue Apr 21 22:00:04 1998 Mark Mitchell <mmitchell@usa.net>
- * init.c (build_new): Catch use of an initializer list where it
- shouldn't be.
+ * errfn.c (cp_thing): Use xrealloc, not xmalloc, to copy memory.
-Wed Mar 22 16:21:07 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (check_member_template): Set DECL_IGNORED for member
+ class templates, too.
- * init.c (build_new): Wrap alloc_expr in an RTL_EXPR if nelts is
- non-constant.
+ * decl2.c (grokfield): Remangle the name of a member TYPE_DECL.
- * decl2.c: temp_name_counter is now public.
+Tue Apr 21 18:59:11 1998 Benjamin Kosnik <bkoz@rhino.cygnus.com>
- * decl.c (struct cp_function): Add temp_name_counter field.
- (push_cp_function_context): Save it.
- (pop_cp_function_context): Restore it.
+ * decl.c (duplicate_decls): Only check DECL_FRIEND_P if function.
- * typeck.c (common_type): Handle unifying function types, and unify
- unmatched things to void* with a compiler_error, rather than
- silently like before.
+Tue Apr 21 14:22:00 1998 Jeffrey A Law (law@cygnus.com)
-Wed Mar 22 15:10:34 1995 Mike Stump <mrs@cygnus.com>
+ * cp-tree.h (intTI_type_node, unsigned_intTI_type_node): Declare.
+ * decl.c (intTI_type_node, unsigned_intTI_type_node): Define.
+ (init_decl_processing): Handle TI types.
+ * typeck.c (unsigned_type, signed_type): Handle TI types.
- * decl2.c (finish_prevtable_vardecl, finish_vtable_vardecl): Revert
- Brendan's last change and fix latent problem that causes TD entries
- to not come out when the things that need them has yet to be
- expanded.
+Sat Apr 18 15:25:21 1998 Jim Wilson <wilson@cygnus.com>
-Wed Mar 22 15:12:00 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * g++spec.c (lang_specific_driver): New argument in_added_libraries.
+ New local added_libraries. Increment count when add library to
+ arglist.
- * typeck.c (build_binary_op_nodefault, comparison ops): Update type0
- and type1, since we might have changed op0 or op1.
+Fri Apr 17 21:25:00 1998 Mark Mitchell <mmitchell@usa.net>
-Wed Mar 22 13:33:45 1995 Jason Merrill <jason@python.cygnus.com>
+ * cp-tree.h (type_as_string_real): New function.
+ * pt.c (mangle_class_name_for_template): Use it.
+ * error.c (dump_aggr_type): Change prototype.
+ (dump_type_prefix): Likewise.
+ (dump_type_suffix): Likewise.
+ (dump_type_real): Convert from dump_type. If desired, the
+ "canonica" name of a typedef, i.e., the name of the underlying
+ type, can be printed.
+ (dump_type): Call dump_type_real.
- * typeck.c (common_type): Don't mess up templates.
+Fri Apr 17 14:30:45 1998 Jason Merrill <jason@yorick.cygnus.com>
-Wed Mar 22 04:56:00 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (lang_decode_option): -fnew-abi implies -fvtable-thunks.
- * typeck.c (common_type): Handle ptms properly. Also handle
- T* -> void*.
- (build_binary_op_nodefault): New variable build_type controls what
- type is given to the expression when it is created. Set this to
- boolean_type_node for comparison ops instead of using result_type.
- (comp_target_types): Allow T * -> void *.
+ * typeck.c (comp_target_types): Tweak pedantic case.
+ (comp_target_parms): Tweak pedantic case. Clean up somewhat.
+ Return -1 or 1 instead of 1 or 2.
+ (compparms): Remove STRICT handling.
+ (convert_for_assignment): Fix handling of pmfs.
- * cvt.c (cp_convert_to_pointer): Do access control when converting
- ptms, too.
+Fri Apr 17 14:04:16 1998 Mark Mitchell <mmitchell@usa.net>
-Tue Mar 21 17:25:06 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * typeck.c (comp_target_types): Handle references like pointers.
+ (comp_target_parms): Note that return code from comp_target_types
+ can be negative to indicate failure.
- * parse.y (extern_lang_string): Catch use of linkage specs that
- aren't all naming the same language.
+Fri Apr 17 09:10:52 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- * class.c (finish_struct): Delete accidental duplicate code.
+ * Make-lang.in (c++.all.build): Don't depend on $(DEMANGLER_PROG),
+ which requires a working target compiler to build.
-Tue Mar 21 14:00:57 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Fri Apr 17 08:57:35 1998 Jeffrey A Law (law@cygnus.com)
- * typeck.c (build_binary_op_nodefault): Disable pedwarns about
- comparing functions and incomplete types.
+ * tree.c (avoid_overlap): Add prototype.
- * decl.c (finish_function): Only unset current_function_decl if
- !nested.
- (duplicate_decls): Last change went too far; we only want to stop
- checking for value/reference ambiguity.
+ * spew.c (num_tokens): Add prototype.
+ (nth_noken, add_token, consume_token, debug_yychar): Likewise.
-Tue Mar 21 01:26:39 1995 Mike Stump <mrs@cygnus.com>
+ * search.c (dfs_check_overlap): Add prototype.
+ (dfs_no_overlap_yet): Likewise.
- * gc.c (build_generic_desc): Zap the DECL_SIZE so that we can lay it
- out fresh, as the new type may be larger.
+ * pt.c (original_template): Add prototype.
+ (inline_needs_template_parms): Likewise.
+ (push_inline_template_parms_recursive): Likewise.
+ (retrieve_specialization, register_specialization): Likewise.
+ (print_candidates, reduce_template_parm_level): Likewise.
+ (build_template_decl, mark_template_parm): Likewise.
+ (tsubst_friend_function, get_bindings_real): Likewise.
-Mon Mar 20 19:01:10 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * method.c (start_squangling): Add prototype.
+ (end_squangling, check_ktype, issue_ktype): Likewise.
+ (build_overloaded_scope_ref, check_btype): Likewise.
+ (build_mangled_template_parm_index): Likewise.
- * expr.c (extract_init): Try to expand the RTL for the
- initialization and figure out what it will look like so we can avoid
- run-time initialization. Disabled for now.
- (extract_scalar_init): Helper for scalar initialization.
- (extract_aggr_init): Helper for aggregate initialization.
+ * lex.c (init_cpp_parse): Add prototype.
+ (handle_cp_pragma, handle_sysv_pragma): Likewise.
+ (reduce_cmp, token_cmp): Likewise.
- * decl.c (duplicate_decls): Don't complain about ambiguous
- declarations.
- (obscure_complex_init): Now returns a tree. Call extract_init if
- we're optimizing and this is a toplevel decl.
- (finish_decl): Update accordingly.
+ * except.c (call_eh_info): Add prototype.
+ (push_eh_info, get_eh_info, get_eh_value, get_eh_type): Likewise.
+ (get_eh_caught, get_eh_handlers, do_pop_exception): Likewise.
- * lex.c (check_newline): If we're just changing files (not pushing
- or popping), update input_file_stack->name.
+ * decl2.c (is_namespace_ancestor): Add prototype.
+ (namespace_ancestor, add_using_namespace): Likewise.
+ (ambiguous_decl): Likewise.
-Mon Mar 20 17:55:04 1995 Mike Stump <mrs@cygnus.com>
+ * decl.c (indent): Add prototype.
- * pt.c (type_unification): Only TEMPLATE_DECLs are handled right now
- in the transitive unification code.
+ * call.c (add_template_candidate_real): Add prototype.
-Mon Mar 20 16:07:50 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+Fri Apr 17 01:57:12 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (shadow_tag): Don't allow inline, virtual, or explicit on
- non-functions.
- (grokdeclarator): Don't allow friends to be defined in local classes.
+ * decl2.c (build_expr_from_tree): Just return a PMF.
-Sat Mar 18 04:03:33 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Fri Apr 17 00:45:12 1998 Mark Mitchell <mmitchell@usa.net>
- * decl2.c (finish_prevtable_vardecl): Use DECL_DECLARED_STATIC
- rather than DECL_SAVED_INSNS to decide whether or not this method
- was declared inline.
+ * typeck2.c (process_init_constructor): Don't strip cv-qualifiers
+ when doing initializations.
- * method.c (synthesize_method): Turn off DECL_INLINE if
- function_cannot_inline_p thinks we're too large.
+ * pt.c (unify): Use comptypes to compare type args.
- * typeck.c (build_indirect_ref): Use build_expr_type_conversion.
+Fri Apr 17 00:24:22 1998 Jason Merrill <jason@yorick.cygnus.com>
-Fri Mar 17 17:47:36 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (duplicate_decls): Fix check for when it's safe to free
+ the new decl.
- * class.c (instantiate_type): Handle pmfs.
+ * pt.c (mangle_class_name_for_template): Don't pass a typedef type
+ to type_as_string.
- * typeck.c (convert_for_assignment): Check types when assigning one
- pmf to another.
+Thu Apr 16 17:47:30 1998 Jeffrey A Law (law@cygnus.com)
- * decl.c (define_label): Fix logic for printing out the name of the
- label in an error message.
+ * pt.c (build_template_parm_index): Add prototype.
- * error.c (dump_expr): Support ARRAY_REF.
+ * search.c (my_tree_cons): Don't clear words outside the
+ newly allocated node.
-Fri Mar 17 17:43:02 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+Wed Apr 15 15:34:44 1998 Dave Brolley <brolley@cygnus.com>
- * decl2.c (finish_vtable_vardecl): Call build_t_desc here.
- (finish_prevtable_vardecl): Instead of here.
+ * lex.c (init_parse): Now returns char* containing the filename.
-Fri Mar 17 14:40:45 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed Apr 15 13:20:06 1998 John Carr <jfc@mit.edu>
+ Jeff Law <law@cygnus.com>
- * decl.c (expand_static_init): Also use expand_aggr_init if the
- initializer is a TREE_LIST.
- (grokdeclarator): Only pedwarn about extra qualification if -pedantic.
+ * errfn.c: Rework to avoid problems when HOST_WIDE_INT is longer
+ than a pointer.
- * pt.c (unify): Fix unification of return type.
+Sun Apr 12 22:31:19 1998 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
- * expr.c (fixup_result_decl): Use store_expr, rather than
- emit_move_insn, to move the return value into the place where
- callers will expect it.
+ * cvt.c (cp_convert_to_pointer): Use TYPE_PRECISION.
-Thu Mar 16 22:05:25 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Fri Apr 10 12:16:49 1998 Benjamin Kosnik <bkoz@loony.cygnus.com>
- * init.c (build_offset_ref): Call assmble_external on functions.
- * typeck.c (build_component_ref): Ditto.
+ * decl.c (duplicate_decls): Don't warn for redundant decls if
+ friend: let add_friend take care of it.
-Thu Mar 16 20:28:16 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+Thu Apr 9 02:40:48 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (struct saved_scope): Add members base_init_list and
- member_init_list.
- (push_to_top_level): Save current_base_init_list and
- current_member_init_list to them.
- (pop_from_top_level): Put it back.
+ * sig.c (build_signature_pointer_constructor): Don't set
+ TREE_HAS_CONSTRUCTOR for a signature pointer.
+ * cvt.c (ocp_convert): Don't force a temporary for internal structs.
+ * init.c (resolve_offset_ref): Warn about implicit & on pmfs
+ here, too.
+ * typeck.c (build_unary_op): Only allow taking the address of a
+ real constructor.
+ * typeck2.c (digest_init): Simplify.
+ (store_init_value): Don't pedwarn about using { } for pmfs.
-Thu Mar 16 19:21:14 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Thu Apr 9 22:16:57 1998 Per Bothner <bothner@cygnus.com>
- * pt.c (instantiate_template): Call assemble_external.
+ * cp-tree.h (start_decl): Update prototype.
+ * decl.c (start_decl): Like the C version, new parameters
+ for the attributes. Call cplus_decl_attributes here,
+ (pushdecl): Like C version, do build_type_copy if TYPE_DECL,
+ (grokdeclarator): Pass NULL for new start_decl arguments.
+ * pt.c (tsubst_expr): Likewise.
+ * parse.y: Merge cplus_decl_attribute calls into start_decl calls.
+ * typeck.c (common_type): Check TYPE_MAIN_VARIANT.
+ * lex.c (build_lang_decl): Add lang_name_java.
+ * class.c (push_lang_context): Add lang_name_java.
+ * method.c (build_mangled_name): Check for is_java_type.
-Thu Mar 16 18:07:54 1995 Brendan Kehoe (brendan@phydeaux.cygnus.com)
+Thu Apr 9 22:16:57 1998 Benjamin Kosnik <bkoz@loony.cygnus.com>
- * class.c: Include rtl.h, to get NULL_RTX.
- (finish_struct): Also zero out DECL_SAVED_INSNS, to avoid problems
- on hosts with different sizes for each part of the union.
- * tree.c: Also include rtl.h.
- (layout_basetypes): Same change for DECL_SAVED_INSNS.
+ * decl.c (grokdeclarator): Check TYPE_MAIN_VARIANT.
+ * call.c (build_scoped_method_call): Check for TREE_CODE for
+ VOID_TYPE instead of type == void_type_node.
+ (build_method_call): Ditto.
+ * decl.c (lookup_name_real): Ditto.
+ (grokdeclarator): Ditto.
+ (start_decl): Ditto.
+ (grokparms): Ditto.
+ (start_function): Ditto.
+ (finish_function): Ditto.
+ (start_method): Ditto.
-Thu Mar 16 13:57:36 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Thu Apr 9 00:18:44 1998 Dave Brolley (brolley@cygnus.com)
- * pt.c (unify): Fix array domain unification for 64-bit targets.
+ * lex.c (finput): New variable.
+ (init_cpp_parse): Renamed from init_parse.
+ (init_parse): Handle !USE_CPPLIB. Call init_cpp_parse when finished.
+ (finish_parse): New function.
+ * cp-tree.h (init_lex, init_parse): Remove declarations.
- * decl2.c (finish_file): Push bizarre type decl before walking the
- vtables the first time.
- (walk_vtables): OK, don't set prev to vars if the vardecl_fn messed
- with TREE_CHAIN (prev).
+Mon Apr 6 02:25:05 1998 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (emit_base_init): Use convert_pointer_to_real instead of
- convert_pointer_to when converting to a direct base.
+ * call.c (build_call): Still evaluate the actual argument.
+ * class.c (is_empty_class): Update for -fnew-abi.
-Wed Mar 15 20:26:29 1995 Mike Stump <mrs@cygnus.com>
+ * decl2.c: -fnew-abi implies -fsquangle.
- * pt.c (type_unification): Handle transitive unification better.
+ * method.c (do_build_assign_ref): Don't do anything to copy
+ an empty class.
+ (do_build_copy_constructor): Likewise.
+ * call.c (build_over_call): Likewise.
-Wed Mar 15 13:56:16 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Sat Apr 4 18:43:58 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (walk_vtables): Always set prev to vars.
- (mark_vtable_entries): Call assemble_external on the vtable entries.
+ * tree.c (avoid_overlap): Return a value.
- * class.c (finish_struct): Set the vtable's size to NULL_TREE before
- calling layout_decl, so that it gets updated properly.
+Sat Apr 4 12:52:35 1998 Jeffrey A Law (law@cygnus.com)
- Finally re-enable dynamic synthesis. This time it works.
- * method.c (synthesize_method): Pass decl_function_context (fndecl)
- to {push,pop}_cp_function_context.
- * decl.c (push_cp_function_context): Now takes a tree argument.
- (pop_cp_function_context): Ditto.
- * call.c (build_method_call): Enable synthesis.
- * lex.c (cons_up_default_function): Ditto.
+ * method.c (check_btype): Add missing argument to xrealloc.
+ (check_ktype): Likewise.
-Tue Mar 14 19:14:19 1995 Doug Evans <dje@chestnut.cygnus.com>
+Fri Apr 3 02:22:59 1998 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (setattrs): Chain onto prefix_attributes rather than
- setting it.
+ Implement empty base optimization.
+ * class.c (finish_struct_1): Add vbase fields earlier. Set
+ CLASSTYPE_SIZE of an empty base to 0. Types with bases can be empty.
+ * search.c (dfs_check_overlap, dfs_no_overlap_yet): New fns.
+ (types_overlap_p): New fn.
+ * tree.c (avoid_overlap): New fn.
+ (build_base_fields): Use it to avoid overlapping empty bases.
+ * cp-tree.h, decl2.c, lang-options.h: Add -fnew-abi.
-Wed Mar 15 13:00:00 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * decl.c (cplus_expand_expr_stmt): Strip unused INDIRECT_REFs.
- * decl.c (pushdecl): Check if the type of the VAR_DECL is an
- error_mark_node before trying to read TYPE_LANG_SPECIFIC.
+ Re-implement allocation of base class subobjects.
+ * tree.c (unshare_base_binfos): New fn.
+ (layout_basetypes): Use it. Now handles offsets of both virtual and
+ non-virtual bases, after layout_type.
+ (layout_vbasetypes): Remove.
+ (build_base_fields): Generate FIELD_DECLs for each non-virtual base.
+ (build_vbase_pointer_fields): Split out from old layout_basetypes.
+ * class.c (finish_base_struct): Lose offset handling code.
+ Move nonvdtor warning here. Don't mess with t_binfo anymore.
+ (finish_struct_1): Don't mess with t_binfo anymore. Use fns above.
+ * cp-tree.h: Adjust.
-Mon Mar 13 21:00:28 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+Thu Apr 2 14:25:13 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokdeclarator, case ARRAY_REF): Wrap the exp with fold,
- and convert the size and integer_one_node to the index type.
+ * cp-tree.h: Lose CLASSTYPE_VBASE_SIZE, some unused stuff.
+ * decl.c, decl2.c, pt.c, ptree.c, lex.c: Likewise.
+ * class.c (duplicate_tag_error): Likewise.
+ (finish_struct_1): Set CLASSTYPE_SIZE, CLASSTYPE_MODE, CLASSTYPE_ALIGN.
+ * tree.c (layout_vbasetypes): Update from layout_record, remove
+ var_size support, use CLASSTYPE_SIZE instead of CLASSTYPE_VBASE_SIZE.
+ (layout_basetypes): Likewise.
-Mon Mar 13 08:01:02 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed Apr 1 18:22:25 1998 Jeffrey A Law (law@cygnus.com)
- * typeck.c (get_member_function_from_ptrfunc): Save the instance
- argument, and tack it onto the front of the COND_EXPR to make the
- semantics come out right. Grab the instance argument from
- '*instance_ptrptr', rather than having it passed in separately.
+ * class.c, Make sure system.h is included just after config.h.
+ Delete lingering stdio and errno references too.
+ * decl.c, errfn.c, parse.y, ptree.c search.c, xref.c: Likewise.
- * various: Change various consed-up comparison operations to have
- boolean type. Remove the instance argument in calls to
- get_member_function_from_ptrfunc.
-
- * error.c (dump_expr): Dump true and false as "true" and "false".
+Wed Apr 1 15:38:36 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (finish_file): Also set DECL_STATIC_FUNCTION_P on the
- global init function.
+ * friend.c (is_friend): Fix access control for local classes.
- * decl.c (finish_function): Only set DECL_EXTERNAL here if the
- inline function is public.
+ * class.c (is_empty_class): New fn.
+ * call.c (build_call): Don't pass empty class objects to a function.
-Sat Mar 11 00:58:03 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed Apr 1 14:58:35 1998 Mark Mitchell <mmitchell@usa.net>
- * init.c (is_friend): Be more careful about checking
- DECL_CLASS_CONTEXT on non-member functions.
+ * call.c (build_over_call): Do name resolution for default
+ arguments of function templates in the scope of the templates.
- * decl2.c (finish_vtable_vardecl): Don't bother calling
- assemble_external here.
- (prune_vtable_vardecl): New function that just splices out the
- vtable decl from the top-level decls.
- (import_export_inline): Unset DECL_EXTERNAL at first.
- (finish_file): Don't bother calling assemble_external here. Do
- splice out all of the vtables.
+Tue Mar 31 13:43:57 1998 Jeffrey A Law (law@cygnus.com)
-Fri Mar 10 14:42:29 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c: Include system.h. Remove includes, declarations and
+ defines provided by system.h.
+ * class.c, cvt.c, decl.c, decl2.c, errfn.c error.c: Likewise.
+ * except.c, expr.c friend.c, g++spec.c, init.c, input.c: Likewise.
+ * lex.c, parse.y, pt.c, ptree.c repo.c rtti.c, search.c: Likewise.
+ * semantics.c, sig.c, spew.c, tree.c, typeck.c: Likewise.
+ * typeck2.c, xref.c: Likewise.
+ * Makefile.in: Dependencies updated as appropriate.
+ * Make-lang.in: Likewise.
- * decl.c (finish_function): If we're not emitting the function yet,
- call assemble_external for it.
+Mon Mar 30 12:15:00 1998 Mark Mitchell <mmitchell@usa.net>
- * decl2.c (finish_prevtable_vardecl): Don't call mark_vtable_entries
- here.
- (finish_vtable_vardecl): Don't do the linkage deduction thing here.
- Also don't splice out the current vtable if it is unused.
- (finish_file): Move the second walk_vtables and the synthesis check
- inside the 'reconsider' loop. Move thunk emission after the
- 'reconsider' loop.
-
-Thu Mar 9 16:28:16 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
-
- * pt.c (tsubst): Don't bother calling cp_build_type_variant, since it
- was passing bogus values for readonly and volatile from the original
- template decl, not the resultant type of the tsubst call.
-
- * class.c (duplicate_tag_error): Use cp_error_at to point out the
- previous definition of the tag.
-
-Thu Mar 9 10:46:17 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * decl.c (start_function): Clear base_init_insns and protect_list.
- (struct cp_function): Add base_init_insns field.
- (push_cp_function_context): Also save base_init_insns.
- (pop_cp_function_context): Also restore base_init_insns.
-
-Wed Mar 8 13:31:44 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * init.c (member_init_ok_or_else): Check for initializing a static
- member here.
- (emit_base_init): Instead of here.
-
-Tue Mar 7 16:03:26 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * call.c (build_method_call): Disable synthesis as needed.
- * lex.c (cons_up_default_function): Ditto.
-
-Tue Mar 7 10:14:29 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
-
- * parse.y: New rules to allow attributes in a prefix position.
- (prefix_attributes): New variable. Pass it into cplus_decl_attributes.
- (setattr): New rule.
- (reserved_declspecs, declmods): Catch attributes here.
- * decl2.c (cplus_decl_attributes): Add PREFIX_ATTRIBUTES argument.
- * decl.c (duplicate_decls): Pass DECL_MACHINE_ATTRIBUTES to
- descendent typedef.
- (grokdeclarator): Added code to support machine attributes.
- * Makefile.in (stamp-parse): Expect 5 shift/reduce failures.
-
-Mon Mar 6 15:07:02 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (fn_type_unification): Allow incomplete unification without
+ an immediate error message.
- * call.c (build_method_call): Don't synthesize methods outside of a
- function.
+Mon Mar 30 08:55:42 1998 Jason Merrill <jason@yorick.cygnus.com>
- Make base initialization more re-entrant so that synthesis on the
- fly will work (and, eventually, template instantation on the fly).
- * init.c (sort_member_init): Don't bother with members that can't be
- initialized. Reorganize a bit. Don't initialize base members here.
- (sort_base_init): New function, like sort_member_init, but for base
- classes. Steals some code from emit_base_init.
- (emit_base_init): Simplify. Call sort_{member,base}_init before
- doing any initialization, so we don't have to save
- current_{member,base}_init_list in push_cp_function_context.
- (expand_aggr_vbase_init_1): Adjust for sort_base_init.
- (expand_aggr_vbase_init): Simplify.
- * decl.c (struct cp_function): Add protect_list field.
- (push_cp_function_context): Also save protect_list.
- (pop_cp_function_context): Also restore protect_list.
- * call.c (build_method_call): Enable synthesis at point of call.
- * lex.c (cons_up_default_function): Ditto.
+ * tree.c (member_p): New fn.
+ * decl2.c (finish_file): Only set DECL_STATIC_FUNCTION_P for
+ initializing class members.
- * parse.y: Turn -ansi checks back into -pedantic checks.
+ * cp-tree.def (TEMPLATE_PARM_INDEX): Class 'x'.
+ * ptree.c (lang_print_xnode): Handle TEMPLATE_PARM_INDEX.
- * init.c (build_new): Fix -fcheck-new for array new.
+ * call.c (build_method_call): Handle non-scoped destructors, too.
+ * pt.c (tsubst_copy): Likewise.
-Sat Mar 4 15:55:42 1995 Fergus Henderson <fjh@cs.mu.oz.au>
+ * pt.c (print_template_context): Split out...
+ (push_tinst_level): ...from here.
- * typeck.c (build_compound_expr): warn if left-hand operand of
- comma expression has no side-effects.
+ * friend.c (is_friend): Don't pass a type to decl_function_context.
-Fri Mar 3 15:16:45 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * typeck.c (convert_for_initialization): Always hand off
+ conversions to class type.
- * parse.y (primary): Change 'object qualified_id *' rules to 'object
- overqualified_id *'.
+Sun Mar 29 20:01:59 1998 Jason Merrill <jason@yorick.cygnus.com>
-Fri Mar 3 12:48:17 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * friend.c (is_friend): Local classes have the same access as the
+ enclosing function.
- * parse.y (unary_expr): Catch doing sizeof an overloaded function.
- Make the error look the same as the one we issue in c_sizeof.
+Sun Mar 29 00:47:32 1998 Jeffrey A Law (law@cygnus.com)
- * typeck.c (build_binary_op_nodefault): Give an error for trying
- to compare a pointer-to-member to `void *'.
+ * typeck.c (expand_target_expr): Delete dead function.
-Fri Mar 3 11:28:50 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * typeck.c (build_unary_op): Handle bool increment with smoke and
- mirrors here, rather than in expand_increment where it belongs,
- because Kenner doesn't agree with me.
-
-Fri Mar 3 00:08:10 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
-
- * decl.c (grokparms): Catch a PARM_DECL being used for a default
- argument as well.
-
-Thu Mar 2 20:05:54 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
-
- * init.c (build_new): Don't allow new on a function type.
-
- * parse.y (primary): Avoid a crash when seeing if the arg is of
- the same type as that given for the typespec in an explicit dtor call.
-
-Thu Mar 2 00:49:38 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * decl.c (finish_function): Change test for calling
- mark_inline_for_output.
-
-Wed Mar 1 11:23:46 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * typeck.c (build_modify_expr): Complain if
- build_default_binary_type_conversion fails.
-
- * init.c (expand_default_init): Handle arguments of unknown type
- properly.
+ * search.c: Put various prototypes inside #ifdef MI_MATRIX.
- * cvt.c (build_expr_type_conversion): Only complain about ambiguity
- if 'complain'.
- * various: Pass 'complain'.
+ * repo.c (save_string): Delete dead function.
- * typeck.c (comptypes): Be more picky about comparing UPTs.
+ * method.c (thunk_printable_name): Delete dead function.
-Wed Mar 1 11:03:41 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * lex.c (yynextch): Delete dead function.
- * decl.c (grokdeclarator): If declarator is null, say that the
- type used has an incomplete type.
+ * expr.c (tree_extract_aggr_init): #if 0 out.
-Wed Mar 1 10:06:20 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * except.c (do_unwind): Delete dead function.
+ (easy_expand_asm): Likewise.
- * pt.c (instantiate_template): Copy the template arguments to the
- permanent_obstack. Also use simple_cst_equal to compare them when
- looking for a previous instantiation.
+ * cvt.c (build_conversion_type_1): Delete dead function.
- * tree.c (make_deep_copy): Support copying INTEGER_TYPEs (assuming
- they are array domain types).
+ * cp-tree.h (push_expression_obstack): Declare.
-Tue Feb 28 23:24:55 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (source_type): #if 0 out.
- * cp-tree.h: Define WANT_* constants for passing to
- build_expr_type_conversion.
- * cvt.c (build_expr_type_conversion): New function to build
- conversion to one of a group of suitable types.
- (build_default_binary_type_conversion): Use it.
- * decl2.c (grok_array_decl): Ditto.
- * typeck.c (build_unary_op): Ditto.
- (build_array_ref): Tidy up a bit.
- (build_binary_op): Ditto.
+ * class.c (alter_access): Remove unused label. Add braces
+ around empty else clause.
-Tue Feb 28 19:57:31 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * lex.c (yyprint): Fix argument to printf.
- * decl.c (grokdeclarator): Don't allow decl of an argument as `void'.
+Sat Mar 28 17:43:52 1998 Mark Mitchell <mmitchell@usa.net>
-Tue Feb 28 17:23:36 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (tsubst): Clear TREE_USED for new FUNCTION_DECLs.
- * parse.y (typed_declspecs1): Add 'typespec reserved_typespecquals
- reserved_declspecs' rule.
+ * pt.c (instantiate_class_template): Make sure template
+ arguments are permanent.
+ * init.c (resolve_offset_ref): Don't go looking around in
+ template types.
- * parse.y (expr_or_declarator): Remove notype_qualified_id rule.
- (direct_notype_declarator): Ditto.
- (complex_direct_notype_declarator): Add notype_qualified_id rule.
+ * semantics.c: Add routines to handle expressions, and some
+ declaration processing.
+ * parse.y: Use them.
+ (current_class_depth): Move declaration to cp-tree.h.
+ * parse.c: Regenerated.
+ * cp-tree.h: Use them.
+ (current_class_depth): Declare.
+ * pt.c (tsubst_copy): Use begin_stmt_expr and finish_stmt_expr.
- * lex.c (real_yylex): Handle :> digraph properly.
+Fri Mar 27 20:23:18 1998 Mark Mitchell <mmitchell@usa.net>
-Tue Feb 28 12:26:29 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
-
- * decl.c (grokdeclarator): Check if it's a friend, not if it's
- non-virtual, that's being initialized. Move the check up to
- before FRIENDP would get cleared. Catch an unnamed var/field
- being declared void. Say just `field' instead of `structure field'
- in the error message. Only go for the operator name if DECLARATOR
- is non-null.
-
-Tue Feb 28 00:08:01 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * decl.c (start_function): Complain about abstract return type.
- (grokdeclarator): Complain about declaring constructors and
- destructors to be const or volatile. Complain about declaring
- destructors to be static.
-
- * pt.c (uses_template_parms): Handle pmfs.
-
- * decl.c (grokdeclarator): Don't call variable_size for array bounds
- that only depend on template constant parameters.
-
-Mon Feb 27 15:38:16 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
-
- * error.c (dump_decl): Only look to see if it's a vtable if we
- actually have a name to check out.
+ * error.c (dump_decl): Be a bit more explicit with template
+ type arguments, when verbose.
+
+Fri Mar 27 18:16:40 1998 Jason Merrill <jason@yorick.cygnus.com>
-Mon Feb 27 13:37:53 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * inc/exception: Reorder closing braces.
- * cvt.c (convert_to_aggr): Lose misleading shortcut.
+Fri Mar 27 13:22:18 1998 Mark Mitchell <mmitchell@usa.net>
-Sun Feb 26 17:27:32 1995 Doug Evans <dje@canuck.cygnus.com>
+ * pt.c (redeclare_class_template): New function.
+ * cp_tree.h (redeclare_class_template): Declare it.
+ * decl.c (xref_tag): Use it.
- * decl.c (set_nested_typename): Always set DECL_IGNORED_P,
- not just for dwarf.
+Thu Mar 26 11:16:30 1998 Jason Merrill <jason@yorick.cygnus.com>
-Sun Feb 26 00:10:18 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * call.c (build_over_call): Check IS_AGGR_TYPE, not
+ TYPE_LANG_SPECIFIC.
+ * typeck.c (convert_arguments): Likewise.
- * decl.c (grokdeclarator): Don't allow a static member to be
- declared `register'.
+ * decl.c (grokdeclarator): Remove const and volatile from type after
+ setting constp and volatilep.
- * init.c (make_friend_class): Move up to a pedwarn for the warning
- about a class declaring friends with itself.
+ * class.c (finish_struct_1): Don't warn about bool bitfield larger
+ than one bit.
- * decl.c (grokdeclarator): You can't do `volatile friend class foo'
- or `inline friend class foo'. Only try to make a friend out of
- TYPE if we didn't already reset it to integer_type_node.
+Thu Mar 26 10:25:52 1998 Mark Mitchell <mmitchell@usa.net>
-Sat Feb 25 22:32:03 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * pt.c (convert_nontype_argument): STRIP_NOPS where appropriate.
- * decl.c (grokdeclarator): Don't allow initialization of a
- non-virtual function.
+Thu Mar 26 10:24:05 1998 Mark Mitchell <mmitchell@usa.net>
- * decl.c (start_function): Do a pedwarn if we're changing `main'
- to have an int return type.
+ * call.c (build_object_call): Complain about ambiguous operator(),
+ rather that crashing.
+ (build_new_op): Likewise.
+ (build_op_delete_call): Likewise.
-Sat Feb 25 00:02:05 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Thu Mar 26 10:23:24 1998 Mark Mitchell <mmitchell@usa.net>
- * typeck.c (build_modify_expr): Handle simple assignment from
- TARGET_EXPRs by building up an RTL_EXPR to force expansion. Whew.
+ * cvt.c (perform_qualification_conversions): Use comp_target_types
+ instead of comp_ptr_ttypes.
-Fri Feb 24 18:27:14 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+Wed Mar 25 16:10:50 1998 Mark Mitchell <mmitchell@usa.net>
- * decl.c (grokdeclarator): Also don't allow virtual outside of a
- class decl for a scope method definition performed at global binding.
+ * cp-tree.h (enforce_access): Declare.
+ * call.c (enforce_access): Make it extern, not static.
+ * class.c (alter_access): Use enforce_access; modify code for ISO
+ compliance, rather than ARM rules.
- * init.c (build_offset_ref): Don't allow creation of an OFFSET_REF
- of a bitfield.
+Wed Mar 25 12:10:45 1998 Kriang Lerdsuwanakij <lerdsuwa@scf.usc.edu>
- * decl.c (grokdeclarator): Don't allow a const to be declared mutable.
+ * cp-tree.h: Fix typo.
- * typeck.c (build_binary_op): Return an error_mark_node if either
- one of the args turned into an error_mark_node when we tried to
- use default_conversion.
+Wed Mar 25 02:01:02 1998 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_unary_op): Forbid using postfix -- on a bool.
+ * expr.c (cplus_expand_expr): Only do PCC_STATIC_STRUCT_RETURN thing
+ if (aggregate_value_p (type)).
- * decl.c (grokdeclarator): Allow `signed' and `unsigned' to be
- used on `__wchar_t'.
+ * decl2.c (constructor_name_full): Handle TYPENAME_TYPE.
-Fri Feb 24 13:59:53 1995 Mike Stump <mrs@cygnus.com>
+Tue Mar 24 16:12:01 1998 Mark Mitchell <mmitchell@usa.net>
- * except.c (end_protect_partials): Do it the right way.
+ * tree.c (mapcar): When dealing with a DECL, use it's constant
+ value, if any.
+ * pt.c (lookup_template_class): Don't mangle the names of template
+ classes whose arguments are unknown.
-Wed Feb 22 15:42:56 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (tsubst_expr): Handle GOTO_STMT correctly.
- * typeck.c (build_binary_op_nodefault): Upgrade warning about
- comparing distinct pointer types to pedwarn.
+Tue Mar 24 12:21:55 1998 Benjamin Kosnik <bkoz@lisa.cygnus.com>
- * typeck2.c (digest_init): Cope with extra braces.
+ * decl.c (init_decl_processing): Set TYPE_PRECISON for bools to 1.
- * typeck.c (build_binary_op_nodefault): Use tree_int_cst_sgn instead
- of INT_CST_LT (..., interger_zero_node).
+Tue Mar 24 12:21:48 1998 Jim Wilson <wilson@cygnus.com>
-Wed Feb 22 14:45:52 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * decl.c (init_decl_processing): Initialize TYPE_MAX_VALUE for
+ boolean_type_node to 1.
- * except.c [!TRY_NEW_EH] (end_protect_partials): Define dummy
- function for systems that don't have EH.
+Tue Mar 24 10:23:47 1998 Mark Mitchell <mmitchell@usa.net>
-Tue Feb 21 19:18:31 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * error.c (dump_expr): Remove unused variable `l'.
- * call.c (can_convert_arg): Like can_convert, but takes an arg as
- well.
+ * pt.c (for_each_template_parm): New function, created by
+ converting uses_template_parms.
+ (tree_fn_t): New typedef.
+ (uses_template_parms): Use it.
+ (mark_template_parm): New function.
+ (push_template_decl): Check that the argument list of a partial
+ specialization uses all the template parameters.
- * pt.c (type_unification): Allow implicit conversions for parameters
- that do not depend on template parameters.
+ * Make-lang.in (c++filt): Don't delete cxxmain.c after we're done
+ with it; we might want it for debugging.
+ * cp-tree.h (type_unification): Change interface.
+ * class.c (finish_struct_1): Skip nested template types, just like
+ ordinary nested types.
+ (instantiate_type): Use new interface to type_unification.
+ * lex.c (init_lex): Add __sz as opname for sizeof.
+ * method.c (build_overload_scope_ref): New function.
+ (build_overload_int): Handle complex expressions. Set
+ numeric_output_need_bar if necessary.
+ (build_overload_value): Handle non-PARM_DECL nodes; this
+ routine is now used by build_overload_int. Remove some
+ assignments to numeric_output_need_bar. Use
+ build_overload_scope_ref.
+ (build_qualified_name): Note that some template mangled names end
+ with digits, and set numeric_output_need_bar appropriately. Use
+ build_underscore_int.
+ * pt.c (unify): Change interface.
+ (type_unification_real): Likewise.
+ (determine_specialization): Use new interfaces.
+ (tsubst): Deal gracefully with situations in which the argument
+ vector is not fully filled.
+ (fn_type_unification): Use new interfaces.
+ (type_unification): Likewise. Remove NOP_EXPR hack.
+ (type_unification_real): Likewise.
+ (unify): Likewise. Deal with unification of complex expresions.
-Tue Feb 21 18:43:48 1995 Douglas Rupp (drupp@cs.washington.edu)
+Mon Mar 23 12:24:37 1998 Jason Merrill <jason@yorick.cygnus.com>
- * Make-lang.in, config-lang.in: ($exeext): New macro.
- * Make-lang.in: Try a "cp" if "ln" fails.
- * cp-tree.h (decl_attributes): Added argument.
- * decl2.c (cplus_decl_attribute): Add arg to decl_attributes.
- * cp/g++.c: Added #ifdefs for sys/file.h and process.h for NT.
- Modified spawnvp to have to correct number of arguments for OS/2, NT.
+ * pt.c (complete_template_args): Initialize skip properly.
-Tue Feb 21 18:36:55 1995 Mike Stump <mrs@cygnus.com>
+ * decl.c (make_typename_type): Revert.
+ (make_implicit_typename): Remove.
+ (lookup_name_real): Don't call it. Call lookup_field if we see a
+ TYPE_DECL from a template base.
+ * search.c (lookup_field): Do implicit typename stuff.
- * decl.c (finish_function): Add calls to end_protect_partials to end
- the exception region that protects constructors so that partially
- constructed objects can be partially destructed when the constructor
- throws an exception.
- * init.c (perform_member_init, sort_member_init, emit_base_init):
- Added support for partially constructed objects.
- * init.c (build_partial_cleanup_for): New routine to do partial
- cleanups of a base class.
- * decl2.c (finish_file): Move the emitting of the exception table
- down, after we emit all code that might have exception regions in
- them.
- * except.c (end_protect_partials, might_have_exceptions_p): New
- routines.
- (emit_exception_table): Always output table if called.
- * cp-tree.h (protect_list, end_protect_partials,
- might_have_exceptions_p, emit_exception_table): Added.
+Sun Mar 22 00:50:42 1998 Nick Clifton <nickc@cygnus.com>
+ Geoff Noer <noer@cygnus.com>
-Tue Feb 21 16:05:59 1995 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * Makefile.in: Various fixes for building cygwin32 native toolchains.
+ * Make-lang.in: Likewise.
- * gc.c (build_typeid): Pass a NULL_TREE, not the bogus, unused
- address of a local variable.
- * class.c (build_vfn_ref): Only try to build the PLUS_EXPR if we
- were given a non-null PTR_TO_INSTPTR.
+Fri Mar 20 18:07:39 1998 Kriang Lerdsuwanakij <lerdsuwa@scf.usc.edu>
-Tue Feb 21 01:53:18 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (tsubst, TEMPLATE_TEMPLATE_PARM): Simplify.
- * decl.c (duplicate_decls): Always lay out the merged decl.
+Fri Mar 20 10:42:07 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (finish_vtable_vardecl): Don't do vtable hack on templates.
- (finish_prevtable_vardecl): Ditto.
+ * decl.c (make_implicit_typename): Rewrite removed code.
+ (make_typename_type): Call it if the type we look up comes from
+ a base that uses template parms.
- * method.c (synthesize_method): Set interface_{unknown,only}
- according to the settings for our class, not the file where it comes
- from.
+ * pt.c (complete_template_args): Rewrite.
+ (tsubst, FUNCTION_DECL): Use it.
-Sat Feb 18 12:26:48 1995 Mike Stump <mrs@cygnus.com>
+Fri Mar 20 08:12:43 1998 H.J. Lu (hjl@gnu.org)
- * except.c: Handle systems that define __i386__ but not __i386.
+ * semantics.c (finish_asm_stmt): Fix combine strings. Call
+ c_expand_asm_operands () if output_operands, input_operands or
+ clobbers is not NULL_TREE.
-Fri Feb 17 15:31:31 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Fri Mar 20 00:10:19 1998 Kriang Lerdsuwanakij <lerdsuwa@scf.usc.edu>
- * decl2.c (reparse_decl_as_expr): Support being called without a
- type argument.
+ * pt.c (complete_template_args): New function.
+ (get_bindings): Deal with specializations of function templates
+ with return type containing parameters from outer class
+ templates.
+ (tsubst, TEMPLATE_TEMPLATE_PARM): When reducing parameter level,
+ substitute arguments and compose a new type.
- * parse.y (primary): Add '(' expr_or_declarator ')'. Adds 4 r/r
- conflicts. Sigh.
+Thu Mar 19 19:01:48 1998 Mark Mitchell <mmitchell@usa.net>
-Fri Feb 17 12:02:06 1995 Mike Stump <mrs@cygnus.com>
+ * pt.c (tsubst): Clear DECL_PENDING_INLINE_INFO for new
+ FUNCTION_DECLs.
- * parse.y (template_def, fndef, fn.def1, return_init, condition,
- initdcl0, initdcl, notype_initdcl0, nomods_initdcl0,
- component_decl_1, after_type_component_declarator0,
- notype_component_declarator0, after_type_component_declarator,
- notype_component_declarator, after_type_component_declarator,
- full_parm, maybe_raises, exception_specification_opt): Fix up,
- include exception_specification_opt maybeasm maybe_attribute and
- maybe_init if missing. Rename maybe_raises to
- exception_specification_opt to match draft wording. Use maybe_init
- to simplify rules.
+Thu Mar 19 11:51:58 1998 Jason Merrill <jason@yorick.cygnus.com>
-Fri Feb 17 01:54:46 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (make_implicit_typename): Lose useless code.
- * init.c (build_new): Set TREE_NO_UNUSED_WARNING on COMPOUND_EXPRs
- built for news of scalar types.
+ * call.c (standard_conversion): Handle A* -> const A* properly.
-Thu Feb 16 17:48:28 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (get_bindings_real): Rename from get_bindings. Add
+ check_rettype parm.
+ (get_bindings): Pass 1.
+ (get_bindings_overload): Pass 0.
- * typeck.c (build_binary_op_nodefault): Update code for warning
- about signed/unsigned comparisons from C frontend. Realize that the
- code in the C frontend is, if anything, even more bogus. Fix it.
- (build_binary_op): Undo default_conversion if it wasn't useful.
+Wed Mar 19 09:08:12 1998 Mark Mitchell <mmitchell@usa.net>
- * typeck.c (build_unary_op, ADDR_EXPR): Lose bogus special case for
- PRE*CREMENT_EXPR.
+ * pt.c (check_explicit_specialization): When reverting a static
+ member function, also remove the `this' parameter from
+ last_function_parms.
- * decl2.c (import_export_vtable): Don't try the vtable hack
- if the class doesn't have any real non-inline virtual functions.
- (finish_vtable_vardecl): Don't bother trying to find a non-inline
- virtual function in a non-polymorphic class.
- (finish_prevtable_vardecl): Ditto.
+Thu Mar 19 02:27:48 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (import_export_vtable): Use and set DECL_INTERFACE_KNOWN.
+ * pt.c (tsubst_copy, CONST_DECL): Don't bother tsubsting
+ a function context.
- * cp-tree.h (DECL_INTERFACE_KNOWN): Use DECL_LANG_FLAG_5.
+ * decl.c (store_bindings): Use free_binding_vecs.
+ (pop_from_top_level): Likewise.
- * init.c (expand_virtual_init): Always call assemble_external.
+Wed Mar 18 12:41:43 1998 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (build_vfn_ref): Always call assemble_external.
- (build_vtable): Always call import_export_vtable.
- (prepare_fresh_vtable): Ditto.
- (add_virtual_function): Don't bother setting TREE_ADDRESSABLE.
+ * decl.c (make_implicit_typename): Only change the type of a
+ TYPENAME_TYPE.
-Thu Feb 16 03:28:49 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed Mar 18 10:09:51 1998 Mark Mitchell <mmitchell@usa.net>
- * class.c (finish_struct): Use TYPE_{MIN,MAX}_VALUE to determine
- whether an enumerated type fits in a bitfield.
+ * semantics.c: New file, containing routines to perform the
+ semantic phase of parsing.
+ * parse.y: Use it.
+ * pt.c (tsubst_expr): Likewise.
+ * cp-tree.h: Declare the various functions in semantics.c.
+ Provide macros to access _STMT tree nodes.
+ * cp-tree.def: Add ASM_STMT tree node.
+ * Makefile.in, Make-lang.in: Add dependencies on and for
+ semantics.c.
+
+Wed Mar 18 00:24:10 1998 Jason Merrill <jason@yorick.cygnus.com>
-Wed Feb 15 15:38:12 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (push_template_decl): Only check primary templates.
- * class.c (grow_method): Update method_vec after growing the class
- obstack.
+ * pt.c (check_explicit_specialization): Complain about default args
+ in explicit specialization.
-Wed Feb 15 13:42:59 1995 Mike Stump <mrs@cygnus.com>
+ * parse.y (nomods_initdcl0): Also call cp_finish_decl for a
+ constructor_declarator.
- * parse.y (handler_seq): Push a level for the catch parameters.
+Tue Mar 17 14:44:54 1998 Mark Mitchell <mmitchell@usa.net>
-Wed Feb 15 12:42:57 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * typeck2.c (build_x_arrow): Don't crash when an aggregate type
+ has no overloaded operator ->.
- * init.c (emit_base_init): Update BINFO_INHERITANCE_CHAIN on my
- bases, in case they've been clobbered.
+ * call.c (build_field_call): Don't crash when presented with a
+ field that is actually a nested type.
-Wed Feb 15 12:07:29 1995 Mike Stump <mrs@cygnus.com>
+ * decl.c (pushtag): Deal with friend class injection in local
+ classes.
- * class.c (finish_base_struct): Set up BINFO_INHERITANCE_CHAIN here,
- so that one day it will always be valid.
- * tree.c (propagate_binfo_offsets, layout_vbasetypes): Ditto.
+ * call.c (build_object_call): Don't crash if OBJ is a
+ pointer-to-member-function.
- * cp-tree.h (copy_binfo): Removed, unused.
- * tree.c (copy_binfo): Ditto.
+Tue Mar 17 11:40:26 1998 Jason Merrill <jason@yorick.cygnus.com>
-Wed Feb 15 00:05:30 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (push_template_decl): Complain about template with C linkage,
+ anonymous template class.
- * init.c (build_new): Save the allocation before calling
- expand_vec_init on it.
+Mon Mar 16 12:10:39 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (finish_enum): The TYPE_PRECISION of the enum type mush
- match the TYPE_PRECISION of the underlying type for constant folding
- to work.
+ * class.c (pushclass): Only use the mi_matrix stuff #ifdef MI_MATRIX.
+ * search.c: Likewise.
-Tue Feb 14 15:31:25 1995 Mike Stump <mrs@cygnus.com>
+ * lex.c (do_pending_defargs): Only call
+ maybe_{begin,end}_member_template_processing for FUNCTION_DECLs.
- * except.c (push_eh_entry, expand_start_all_catch,
- expand_leftover_cleanups, expand_end_catch_block): Keep track of
- the context in which the exception region occurs.
- (build_exception_table): If the region was not output, don't output
- the entry in the eh table for it.
+ * parse.y (initdcl0_innards): Move maybeasm back into initdcl0 et al.
-Tue Feb 14 02:15:43 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Mon Mar 16 10:47:22 1998 Mark Mitchell <mmitchell@usa.net>
- * init.c (expand_default_init): Only use a previous constructor call
- if it's a call to our constructor. Does the word "Duh" mean
- anything to you?
+ * parse.y: Deal with CONSTRUCTORS in new_initializers.
- * decl.c (grokparms): Fine, just don't call
- convert_for_initialization at all. OK? Happy now?
+Mon Mar 16 10:54:21 1998 Mark Mitchell <mmitchell@usa.net>
-Mon Feb 13 02:23:44 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (tsubst_copy): Deal with BIND_EXPR in a way that more
+ closely mimics the behavior in parse.y.
+ (tsubst_expr): Return the resuting BLOCK when making a tsubst'ing
+ into a compound statement.
+
+Sun Mar 15 02:07:26 1998 Jason Merrill <jason@yorick.cygnus.com>
- * cp-tree.h (CLASSTYPE_FIRST_CONVERSION): Make sure that the class
- method vector has a second element before returning it.
+ * cp-tree.h (TEMPLATE_PARMS_FOR_INLINE): New macro.
+ * pt.c (inline_needs_template_parms): New fn.
+ (original_template): New fn.
+ (push_inline_template_parms_recursive): New fn.
+ (maybe_begin_member_template_processing): Use them.
+ (maybe_end_member_template_processing): Likewise.
+ (is_member_or_friend_template): Rename to is_member_template.
+ Member functions of local classes are never member templates.
- * decl.c (grokparms): Don't strip REFERENCE_TYPE before calling
- convert_for_initialization.
+Sun Mar 15 01:14:22 1998 Kriang Lerdsuwanakij <lerdsuwa@scf.usc.edu>
-Sun Feb 12 03:57:06 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * lex.c (do_identifier): Handle TEMPLATE_DECL that was
+ added in the class scope to catch redefinition error.
- * typeck.c (build_modify_expr): Compare function name to
- constructor_name (current_class_type) instead of current_class_name.
+ * pt.c (reduce_template_parm_level): Also copy
+ the DECL_TEMPLATE_PARMS field.
- * decl.c (grokparms): Don't do anything with the return value of
- convert_for_initialization.
+Sun Mar 15 10:54:08 1998 Mark Mitchell <mmitchell@usa.net>
- * error.c (dump_decl): Also dump_readonly_or_volatile on the decl.
+ * pt.c (tsubst): Clear TYPE_REFERENCE_TO when creating a
+ reduced-level template type parameter.
- * decl.c (duplicate_decls): Tweak error message.
+Sun Mar 15 12:26:02 1998 Manfred Hollstein <manfred@s-direktnet.de>
- * typeck.c (build_const_cast): Implement checking.
- (build_reinterpret_cast): Implement some checking.
+ * cp-tree.h (struct lang_decl_flags): Add needs_final_overrider.
+ (DECL_NEEDS_FINAL_OVERRIDER_P): New macro.
+ * class.c (override_one_vtable): Set DECL_NEEDS_FINAL_OVERRIDER_P.
+ * decl.c (duplicate_decls): Propagate it.
+ * typeck2.c (abstract_virtuals_error): Use two loops to emit
+ abstract virtual functions and virtual functions which need a
+ final overrider separately.
+
+Thu Mar 12 09:39:40 1998 Manfred Hollstein <manfred@s-direktnet.de>
- * cp-tree.h (CONV_FORCE_TEMP): Require a new temporary when
- converting to the same aggregate type.
- (CONV_STATIC_CAST): Include it.
- (CONV_C_CAST): Ditto.
- * cvt.c (convert_force): Use CONV_C_CAST instead of CONV_OLD_CONVERT.
- (cp_convert): Only force a new temporary if CONV_FORCE_TEMP.
+ * lang-specs.h: Properly put brackets around array elements in
+ initializer.
-Fri Feb 10 16:18:52 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * typeck.c (build_binary_op_nodefault): Correctly place parens around
+ && and || in expression.
- * typeck.c (build_c_cast): Use non_lvalue to tack something on
- where necessary.
+Thu Mar 12 09:26:04 1998 Manfred Hollstein <manfred@s-direktnet.de>
- * decl.c (auto_function): Now a function.
- * except.c (init_exception_processing): terminate, unexpected,
- set_terminate, and set_unexpected have C++ linkage.
+ * call.c (default_parm_conversions): Remove prototype definition.
+ (build_method_call): Remove unused variable result.
- * typeck.c (build_unary_op, TRUTH_NOT_EXPR): Use convert instead of
- truthvalue_conversion for converting to bool, as it handles
- user-defined conversions properly.
- (condition_conversion): Ditto.
+ * cvt.c (ocp_convert): Remove unused variable conversion.
- * except.c (expand_throw): Don't call convert_to_reference.
- Pass the correct parameters to build_new.
+ * decl2.c (ambiguous_decl): Add explicit parameter definition for name.
- * method.c (do_build_assign_ref): Don't use access control when
- converting to a base reference here.
- (do_build_copy_constructor): Or here.
+ * except.c (do_unwind): #if 0 definition of unused variables fcall
+ and next_pc.
- * init.c (build_new): Unset TREE_READONLY on the dereferenced
- pointer before assigning to it.
+ * expr.c (extract_scalar_init): #if 0 prototype and function
+ definition.
- * decl.c (maybe_build_cleanup): Don't bother stripping const here.
+ * init.c (expand_aggr_init_1): Remove unused variable init_type.
+ (build_new_1): Remove unused variable t.
- * decl2.c (delete_sanity): You can now delete pointer to const.
+ * pt.c (instantiate_class_template): Remove unused variable newtag;
+ cast called function return value to void.
+ (do_decl_instantiation): Remove unused variables name and fn.
-Fri Feb 10 13:28:38 1995 Jason Merrill <jason@python.cygnus.com>
+ * tree.c (get_type_decl): Add default return to shut up compiler from
+ complaining control reaches end of non-void function.
- * decl.c (finish_function): Don't rely on actual parameters being
- evaluated left-to-right.
- * except.c (expand_end_catch_block): Ditto.
+ * typeck.c (build_x_conditional_expr): Remove unused variable rval.
-Fri Feb 10 00:52:04 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Thu Mar 12 09:12:15 1998 Manfred Hollstein <manfred@s-direktnet.de>
- * tree.c (real_lvalue_p): Like lvalue_p, but class temps aren't
- considered lvalues.
- * cvt.c (convert_to_reference): Use real_lvalue_p instead of
- lvalue_p.
+ * call.c (default_parm_conversions): Remove prototype definition.
+ (build_method_call): Remove unused variable result.
+ (build_over_call): Add default case in enumeration switch.
- * cvt.c (build_type_conversion_1): Don't call convert on aggregate
- types.
- (convert_to_reference): Fix erroneous text substitution.
+Thu Mar 12 08:39:13 1998 Manfred Hollstein <manfred@s-direktnet.de>
- * typeck2.c (initializer_constant_valid_p): Update from C frontend.
- Add new argument to all callers.
+ * decl2.c (lang_decode_option): Change j's type to size_t.
- * typeck.c (convert_arguments): Check for error_mark_node before
- trying to do anything with the actual parameter.
+ * tree.c (layout_vbasetypes): record_align and desired_align are of
+ type unsigned int; const_size and nonvirtual_const_size likewise.
- * typeck.c (condition_conversion): Build up a CLEANUP_POINT_EXPR and
- fold it.
- (bool_truthvalue_conversion): Remove. Fix all callers to call
- truthvalue_conversion instead.
- (various): Fold CLEANUP_POINT_EXPRs.
+Wed Mar 11 07:25:20 1998 Mark Mitchell <mmitchell@usa.net>
- * parse.y (conditions): Call condition_conversion rather than
- building up a CLEANUP_POINT_EXPR.
+ * parse.y (new_initializer): Make sure all initializers are
+ lists.
- * pt.c (end_template_decl): Don't warn_if_unknown_interface here
- under -falt-external-templates.
+Tue Mar 10 07:32:36 1998 Mark Mitchell <mmitchell@usa.net>
-Thu Feb 9 05:24:10 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (import_export_decl): Mark tinfo functions for
+ cv-qualified versions of class types as DECL_NOT_REALLY_EXTERN.
- * init.c (build_new): Complain about new of const type without
- initializer. Other cleanup.
+Fri Mar 6 23:27:35 1998 Jeffrey A Law (law@cygnus.com)
- * call.c (compute_conversion_costs): Don't call
- build_type_conversion with a reference type; convert to the target
- type and check its lvaluetude.
- * cvt.c (convert_to_reference): Ditto.
+ * method.c: Fix typo.
- * cvt.c (build_type_conversion_1): There will never be any need to
- dereference references here now.
+Fri Mar 6 10:06:59 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
-Thu Feb 9 00:37:47 1995 Mike Stump <mrs@cygnus.com>
+ * method.c: Include "system.h" to get stdlib.h, stdio.h,
+ ctype.h, string.h, etc.
+ (issue_nrepeats): Add default case in enumeration switch.
+ (check_btype): Likewise.
+ (process_overload_item): Likewise.
+
+ * Makefile.in (method.o): Depend on system.h.
- * except.c (expand_builtin_throw): Make sure we only `use' the
- value of return_val_rtx.
+Wed Mar 4 22:26:53 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-Wed Feb 8 15:45:55 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * lex.c (do_scoped_id): Fix parenthesizing.
- * parse.y (structsp): Don't complain about declaring a type being
- defined to be a friend.
+Wed Mar 4 12:11:53 1998 Michael Tiemann <tiemann@axon.cygnus.com>
- * decl2.c (warn_if_unknown_interface): Note the template in question
- and the point of instantiation, for -falt-external-templates.
- * lex.c (reinit_parse_for_method): Pass the decl to
- warn_if_unknown_interface.
- * pt.c (instantiate_template): Ditto.
- (end_template_decl): Ditto.
+ * rtti.c (get_tinfo_fn_dynamic): If this function is called an
+ FLAG_RTTI is unset, initialize type info machinery and continue
+ with FLAG_RTTI enabled.
+ (get_typeid): Ditto.
- * decl.c (set_nested_typename): Set IDENTIFIER_TYPE_VALUE on the
- nested name again, to make local classes work a bit better.
+Wed Mar 4 11:47:55 1998 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_function_call_real): Dereference reference after
- checking for incomplete type.
+ * typeck.c (unary_complex_lvalue): &D::i has type B::* if i comes
+ from B.
- * init.c (build_new): Accept new of const and volatile types.
+Wed Mar 4 11:28:08 1998 Mark Mitchell <mmitchell@usa.net>
-Wed Feb 8 14:04:16 1995 Jason Merrill <jason@deneb.cygnus.com>
+ * pt.c (finish_member_template_decl): Deal more gracefully with
+ invalid declarations.
- * decl.c (grokdeclarator): Fix error message.
+Tue Mar 3 01:38:17 1998 Jason Merrill <jason@yorick.cygnus.com>
-Wed Feb 8 03:16:15 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cvt.c, decl.c, decl2.c, init.c, rtti.c, typeck.c, typeck2.c,
+ cp-tree.h: Clean up more old overloading code, old RTTI code, and
+ some formatting quirks.
- * typeck.c (convert_for_initialization): Do bash arrays when
- converting to a reference to non-array.
+ * call.c, class.c, cp-tree.h, cvt.c, decl.c, init.c, lex.c,
+ method.c, pt.c, ptree.c, typeck.c: Remove support for
+ -fno-ansi-overloading and overloading METHOD_CALL_EXPR.
+ * class.h: Remove.
+ * Makefile.in: Adjust.
-Tue Feb 7 15:50:33 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (unify): Don't allow reduced cv-quals when strict.
- * cvt.c (cp_convert): Don't call convert_to_reference, or
- automatically dereference references. Do pass reference conversions
- to cp_convert_to_pointer.
- (cp_convert_to_pointer): Support references.
+ * call.c, class.c, pt.c, cp-tree.h: Remove nsubsts parm from
+ *type_unification* and unify.
- * call.c (build_method_call): Don't build up a reference to the
- parameter here; let build_overload_call handle that.
+Mon Mar 2 12:11:06 1998 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_c_cast): Call convert_to_reference directly if
- converting to a reference type.
- * method.c (do_build_copy_constructor): Ditto.
- * method.c (do_build_copy_constructor): Ditto.
- (do_build_assign_ref): Ditto.
+ * parse.y (explicit_template_type): Remove TEMPLATE keyword.
+ (nested_name_specifier): And add it before this use.
+ (typename_sub0): And this use. Also add use without the keyword.
+ (typename_sub1): Likewise.
+ * pt.c (instantiate_class_template): Don't actually instantiate
+ anything if our type uses template parms.
- * call.c (build_method_call): Dereference a returned reference.
- * typeck.c (build_function_call_real): Ditto.
+Mon Mar 2 11:04:59 1998 Jim Wilson <wilson@cygnus.com>
- * decl.c (xref_basetypes): Check for unions with basetypes here.
- (xref_tag): Instead of here.
+ * decl.c (start_function): Don't call temporary_allocation for a
+ nested function.
- * pt.c (process_template_parm): Template type parm decls are
- artificial.
+Sun Mar 1 21:06:37 1998 Jason Merrill <jason@yorick.cygnus.com>
-Mon Feb 6 04:32:09 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (instantiate_class_template): Don't mess with friends if
+ our type uses template parms.
- * parse.y (typed_declspecs): Add missing semicolon.
- (do_xref_defn): Resurrect.
- (named_class_head_sans_basetype): Move template specialization
- definition cases to named_class_head_sans_basetype_defn.
+Sat Feb 28 12:06:44 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (grokfield): Call pushdecl_class_level after setting the
- TYPE_NAME, not before.
+ * parse.y (nested_name_specifier): Use explicit_template_type.
+ (typename_sub): Allow a template_type, an explicit_template_type,
+ or an implicit template type at the end.
+ * lex.c (yyprint): Handle a PTYPENAME being a TEMPLATE_DECL.
+ * decl.c (make_typename_type): Handle template-id where the name
+ is a TEMPLATE_DECL.
+ * call.c (build_scoped_method_call): Handle member template
+ destructor call.
+ * pt.c (tsubst_copy, METHOD_CALL_EXPR): Don't assume a member
+ destructor is represented by the type.
-Sun Feb 5 02:50:45 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cp-tree.h (TYPENAME_TYPE_FULLNAME): New macro.
+ * parse.y (nested_name_specifier): Add 'template' case.
+ (explicit_template_type): New rule.
+ (typename_sub): Use it.
+ * decl.c (make_typename_type): Handle getting a template-id for NAME.
+ * pt.c (tsubst): Likewise.
- * call.c (convert_harshness): Don't call sorry here. Don't allow
- conversions between function pointer types if pedantic.
+Fri Feb 27 11:17:50 1998 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (overload_template_name): Pass globalize=1 to xref_tag.
+ * pt.c (add_to_template_args): Fix thinko.
+ (instantiate_class_template): Call it later.
- * lex.c (cons_up_default_function): Use the full name for the return
- type of op=.
+ * pt.c (get_class_bindings): Add outer_args parm.
+ (most_specialized_class): Likewise.
+ (instantiate_class_template): Pass it.
+ (more_specialized_class): Likewise.
+ (lookup_template_class): Get context from template if none
+ was specified.
+ (finish_member_template_decl): Don't do anything with a
+ partial specialization.
+ * decl2.c (check_member_template): Use IS_AGGR_TYPE instead of
+ AGGREGATE_TYPE_P.
+ * class.c (finish_struct): Member class templates have already been
+ checked for name clashes.
+ * decl.c (pushdecl_with_scope): Handle pushing at class level.
+
+Fri Feb 27 02:25:16 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * pt.c (tsubst, TEMPLATE_DECL): Support member class templates.
+ (tsubst, *_PARM): Support multiple levels of template classes.
+ (instantiate_class_template): Look up the pattern from the
+ original template.
+ (lookup_template_class): Handle getting a template for d1.
+ (push_template_decl): Correct setting of 'primary'.
+ (reduce_template_parm_level): Add 'levels' parm.
+ (finish_member_template_decl): Support member class templates.
+ (template_class_depth): Handle multiple levels.
+ * parse.y (component_decl_1, fn.def2): Remove member template case.
+ (component_decl): Add member template cases.
+ * decl2.c (check_member_template): We now handle member template
+ classes.
+ * decl.c (pushtag): Handle member templates.
+ * method.c (do_inline_function_hair): Don't touch
+ IDENTIFIER_GLOBAL_VALUE.
+ * init.c (build_offset_ref): If name isn't an identifier, just
+ return it.
+ * spew.c (yylex): Handle PTYPENAME like TYPENAME.
+
+ * typeck.c (get_delta_difference): Do adjust for conversions to
+ and from virtual base.
+
+Wed Feb 25 09:51:29 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * typeck.c (get_delta_difference): Give hard error for conversion
+ from virtual base.
+
+ * cp-tree.h: Tweak formatting.
+
+Wed Feb 25 00:35:33 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * decl.c (push_namespace): Handle redeclaration error.
+
+ * cp-tree.h (IDENTIFIER_NAMESPACE_VALUE): New macro.
+ (IDENTIFIER_NAMESPACE_BINDINGS): New macro.
+ (NAMESPACE_BINDING): New macro.
+ (IDENTIFIER_GLOBAL_VALUE): Use NAMESPACE_BINDING.
+ * *.c: Use them.
+
+ * pt.c (push_template_decl): Use innermost_args.
+
+ * decl.c (get_unique_name): Tweak from earlier in the name.
+
+Tue Feb 24 22:15:04 1998 Martin von Loewis <loewis@informatik.hu-berlin.de>
+
+ * cp-tree.def: Add CPLUS_BINDING node.
+ * cp-tree.h (tree_binding): new struct
+ (BINDING_SCOPE, BINDING_VALUE): new macros
+ (current_namespace, global_namespace): declare extern
+ (struct lang_decl_flags): new field in_namespace
+ (DECL_NAMESPACE_USING, DECL_NAMESPACE_USERS): new macros
+ (DECL_NAMESPACE, SET_DECL_NAMESPACE): new macros
+ (TREE_INDIRECT_USING): new macro
+ * decl2.c (current_namespace, global_namespace): Declare. The
+ value is a NAMESPACE_DECL now, not a TREE_LIST.
+ (is_namespace_ancestor, namespace_ancestor):new static functions.
+ (add_using_namespace, ambiguous_decl): likewise.
+ (lookup_using_namespace): new support function for lookup_name.
+ (qualified_lookup_using_namespace): new support function for
+ do_scoped_id and lookup_namespace_name
+ (get_namespace_id): mark as obsolete.
+ (current_namespace_id): Likewise.
+ (do_namespace_alias): Implement.
+ (do_using_directive): Implement as call to add_using_namespace.
+ * decl.c (binding_for_name): new function.
+ (push_namespace, pop_namespace): implement.
+ (push_decl): don't install a FUNCTION_DECL in the global branch.
+ (lookup_namespace_name): implement using qualified lookup.
+ (lookup_name_real): For global scoping, lookup in
+ global_namespace. For namespace scoping, lookup in given
+ namespace. For unscoped lookup, iterate over namespace,
+ considering using directives.
+ (init_decl_processing): initialize global_namespace.
+ (grokvardecl): Build assembler name as static name for globals.
+ (grokdeclarator): Remove old namespace mangling.
+ (xref_tag): When installing a global binding for the
+ tag, make sure we have an identifier.
+ * method.c (build_overload_nested_name): mangle namespaces.
+ (build_qualified_name): Likewise.
+ (build_decl_overload_real): Likewise.
+ * lex.c (build_lang_decl): set namespace for new declaration to
+ current_namespace.
+ (do_scoped_id): find global names in global or current
+ namespace, or using qualified namespace lookup, depending on
+ context.
+ * init.c (build_member_call): When scope is namespace, use
+ build_x_function_call instead.
+ (build_offset_ref): When scope is namespace, collapse processing
+ to lookup_namespace_name instead.
+ * error.c (dump_decl): Support NAMESPACE_DECL.
+ * decl.c (pushdecl): Bind globals to current namespace.
+ (push_overloaded_decl): Likewise.
+ (lookup_tag): Likewise.
+ (lookup_name_current_level): Likewise.
+ (xref_tag): Likewise.
+ (start_function): Likewise.
+ * lex.c (do_identifier): Likewise.
+ (identifier_typedecl_value): Likewise.
+ (real_yylex): Likewise.
+ * method.c (do_inline_function_hair): Likewise.
+ * parse.y (unscoped): Likewise.
+ * pt.c (check_explicit_specialization): Likewise.
+ (lookup_template_class): Likewise.
+ * rtti.c (call_void_fn): Likewise.
+ * sig.c (build_sigtable): Likewise.
+ * ptree.c (lang_print_xnode): New function.
+
+Tue Feb 24 01:40:24 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * pt.c (instantiate_class_template): Don't instantiate if pedantic
+ and the args use template parms.
+
+ * pt.c (push_tinst_level): If the instantiaton uses template parms,
+ fail silently.
+ * decl.c (xref_basetypes): Do call complete_type for basetypes
+ that involve template parameters.
+
+Tue Feb 24 00:36:43 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * typeck2.c (process_init_constructor): Fix labeled init check.
+
+Mon Feb 23 05:08:55 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * pt.c, call.c, decl.c, method.c, cp-tree.h: Remove unused NARGS
+ argument to tsubst and friends.
+
+ * pt.c (tsubst, FUNCTION_DECL): Tidy.
+
+ * typeck.c (build_x_function_call): Handle static member function
+ templates like non-templates. Handle friend templates like normal
+ function templates.
+ * pt.c (tsubst, *_PARM): Don't use orig_level.
+ (get_bindings): Don't call add_to_template_args.
+ (instantiate_template): Likewise.
+ (tsubst, FUNCTION_DECL): Call add_to_template_args as appropriate.
+ * ptree.c (print_lang_type): Print index/level for template parms.
- * decl.c (set_nested_typename): Don't worry about anonymous types,
- as they already have a unique name.
- (pushdecl): Remove redundant set_nested_typename
- (xref_tag): Split out base handling into xref_basetypes.
+Mon Feb 23 02:52:29 1998 Mark Mitchell <mmitchell@usa.net>
- * cp-tree.h (TYPE_INCOMPLETE): New macro; TEMPLATE_TYPE_PARMs are
- not considered incomplete even though their definition is unknown.
+ * Make-lang.in (cc1plus): Note that cc1plus depends on
+ cp/cp-tree.h and cp/cp-tree.def.
+
+ * cp-tree.def (TEMPLATE_CONST_PARM): Remove.
+ (TEMPLATE_PARM_INDEX): New tree code, used to indicate a
+ position in a template parameter list.
+ * cp-tree.h (template_parm_index): New structure, used as the tree
+ structure for a TEMPLATE_PARM_INDEX.
+ (TEMPLATE_PARM_IDX): New macro.
+ (TEMPLATE_PARM_LEVEL): Likewise.
+ (TEMPLATE_PARM_DESCENDANTS): Likewise.
+ (TEMPLATE_PARM_ORIG_LEVEL): Likewise.
+ (TEMPLATE_PARM_DECL): Likewise.
+ (TEMPLATE_TYPE_PARM_INDEX): Likewise.
+ (TEMPLATE_TYPE_ORIG_LEVEL): Likewise.
+ (TEMPLATE_TYPE_DECL): Likewise.
+ (TEMPLATE_CONST_IDX): Remove.
+ (TEMPLATE_CONST_LEVEL): Likewise.
+ (TEMPLATE_CONST_SET_INFO): Likewise.
+ (TEMPLATE_TYPE_SET_INFO): Likewise.
+ (TEMPLATE_TYPE_IDX): Redefine in terms of TEMPLATE_PARM_INDEX
+ node.
+ (TEMPLATE_TYPE_LEVEL): Likewise.
+ * decl.c (decls_match): Call comp_template_parms, rather than
+ expanding it inline.
+ (duplicate_decls): If two template declarations are being merged,
+ then their TEMPLATE_INFOs should be merged as well.
+ (grokfndecl): Save template-id information when declaring a friend
+ with explicit template arguments. Pass arguments to
+ check_explicit_specialization via correct convention; at some
+ point check_explicit_specialization changed, but these call-sites
+ did not.
+ (grokdeclarator): Tidy up slightly.
+ * decl2.c (check_classfn): Tidy up slightly. Don't assume that
+ two template functions with the same DECL_ASSEMBLER_NAME the same,
+ since the names are not yet mangled.
+ * error.c (dump_decl): Use TEMPLATE_PARM_INDEX instead of
+ TEMPLATE_CONST_PARM.
+ (dump_expr): Likewise. Use the TEMPLATE_PARM_DECL to get at the
+ decl for a non-type parameter, rather than printing `<tparm ...>'.
+ * friend.c (is_friend): Handle TEMPLATE_DECL friends.
+ (do_friend): Deal with template friends.
+ * lex.c (do_pending_inlines): Call
+ maybe_begin_member_template_processing, rather than
+ conditionally calling begin_member_template_processing.
+ (process_next_inline): Likewise. Call
+ maybe_end_member_template_processing, rather than
+ conditionally calling end_member_template_processing.
+ (do_pending_defargs): Likewise.
+ (do_identifier): Use TEMPLATE_PARM_INDEX instead of
+ TEMPLATE_CONST_PARM.
+ * method.c (build_mangled_template_parm_index): New function.
+ (build_overload_value): Use it.
+ (build_overload_name): Likewise.
+ * pt.c (finish_member_template_decl): Allow friend declarations.
+ (template_class_depth): New function.
+ (is_member_template): Rename, and modify, to become...
+ (is_member_or_friend_template): New function.
+ (end_member_template_processing): Rename, and modify, to become...
+ (maybe_end_member_template_processing).
+ (build_template_parm_index): New function.
+ (reduce_template_parm_level): New function.
+ (process_template_parm): Modify to use build_template_parm_index.
+ (push_template_decl): Deal with friend templates.
+ (uses_template_parms): Use TEMPLATE_PARM_INDEX instead of
+ TEMPLATE_CONST_PARM.
+ (tsubst_friend_function): New function.
+ (instantiate_class_template): Generate the DECL_FRIENDLIST
+ for a new instantiation by using tsubst_friend_function rather
+ than just tsubst.
+ (tsubst): Don't tsubst into a type which is a TEMPLATE_DECL.
+ Use TEMPLATE_PARM_INDEX instead of TEMPLATE_CONST_PARM, and the
+ appropriate new macros. Use reduce_template_parm_level to
+ generate lower-level template parameters. Handle tsubst'ing into
+ TEMPLATE_DECLS that declare TEMPLATE_TEMPLATE_PARMS. Don't forget
+ to tsubst the DECL_CONTEXT and DECL_CLASS_CONTEXT of newly created
+ templates. Similarly for the template parameters for a new
+ template.
+ (tsubst_copy): Tidy up slightly. Use TEMPLATE_PARM_INDEX instead
+ of TEMPLATE_CONST_PARM. Handle TYPE_DECLs by tsubsting into them.
+ (unify): Use TEMPLATE_PARM_INDEX instead of TEMPLATE_CONST_PARM.
+ (get_bindings): Call add_to_template_args if necessary.
+ (instantiate_decl): Handle instantiations of friend templates.
+ * search.c (lookup_field_1): Don't treat the TYPE_FIELDS of a
+ TEMPLATE_TYPE_PARM as a list of fields; it's not!
+ * spew.c (yylex): Do a little manual constant propogation to
+ clarify the code.
+
+Sun Feb 22 19:53:29 1998 Jeffrey A Law (law@cygnus.com)
- * decl.c (xref_defn_tag): Lose.
- (xref_tag): xref_next_defn = ! globalize.
- (pushdecl): Don't set DECL_NESTED_TYPENAME on artificial decls. The
- ones that should have it set will have it set by pushtag.
- (pushdecl_class_level): Ditto.
- (pushtag): Tidy up a bit.
- (set_nested_typename): Push a decl for the nested typename from
- here, rather than from xref_defn_tag.
+ * error.c: Include sys/types.h.
- * parse.y (do_xref): Lose.
- (named_class_head): If we see 'class foo:' we know it's a
- definition, so don't worry about base lists for non-definitions.
+Thu Feb 19 14:49:09 1998 Jeffrey A Law (law@cygnus.com)
- * pt.c (push_template_decls): Template parm decls are artificial.
+ * method.c (build_mangled_name): Start CPP directives in column zero.
- * decl.c (duplicate_decls): Restore check for qualifier
- disagreement for non-functions.
- (decls_match): Remove check for qualifier disagreement.
+Thu Feb 19 10:36:48 1998 Jason Merrill <jason@yorick.cygnus.com>
-Fri Feb 3 14:58:58 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * typeck2.c (process_init_constructor): Sorry about non-trivial
+ labeled initializers.
+ * parse.y (initlist): Reenable labeled initializers.
- * decl.c (grok_reference_init): Convert initializer from
- reference.
- * typeck.c (convert_for_initialization): Ditto.
+Thu Feb 19 10:15:55 1998 Kriang Lerdsuwanakij <lerdsuwa@scf.usc.edu>
- * decl.c (duplicate_decls): Propagate DECL_NESTED_TYPENAME.
+ * pt.c (coerce_template_parms) Add a new parameter, is_tmpl_parm,
+ all callers changed. Rely on the new parameter instead of arg
+ being a TREE_LIST when determine whether we are working inside
+ template template parameter. Clean up is_type test.
+
+Thu Feb 19 10:04:12 1998 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (cp_convert): Don't convert to the same class type by just
- tacking on a NOP_EXPR.
- (convert_to_reference): Use comp_target_types instead of comptypes
- so that we don't allow conversions two levels down.
+ * cvt.c (cp_convert_to_pointer): Preserve TREE_CONSTANT.
+ * typeck2.c (initializer_constant_valid_p): Allow conversions
+ between pointers and refrerences.
-Thu Feb 2 15:07:58 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+1998-02-19 Brendan Kehoe <brendan@cygnus.com>
- * class.c (build_vbase_path): Bash types to make the backend happy.
- * cvt.c (build_up_reference): Bash the types bashed by
- build_vbase_path to be reference types instead of pointer types.
- (convert_to_reference): Ditto.
+ * typeck.c (build_unary_op): Only warn about incr/decr a pointer
+ if pedantic || warn_pointer_arith.
- * typeck.c (build_c_cast): Don't strip NOPs if we're converting to a
- reference type.
+Thu Feb 19 09:37:21 1998 Kriang Lerdsuwanakij <lerdsuwa@scf.usc.edu>
- * parse.y (structsp): Put back error for 'struct B: public A;'.
+ * pt.c (unify): Handle TEMPLATE_DECL.
-Wed Feb 1 23:02:06 1995 Mike Stump <mrs@cygnus.com>
+1998-02-18 Brendan Kehoe <brendan@cygnus.com>
- * except.c: Add support for mips systems that don't define __mips
- but do define mips, like Ultrix.
+ * cp-tree.h (strip_attrs): Remove decl.
-Wed Feb 1 22:39:07 1995 Mike Stump <mrs@cygnus.com>
+1998-02-18 Doug Evans <devans@cygnus.com>
- * except.c: Add support for exception handling on the Alpha.
+ * decl.c (duplicate_decls): Call merge_machine_decl_attributes.
+ Update olddecl's attributes too.
+ (strip_attrs): Remove function.
+ * typeck.c (common_type): Call merge_machine_type_attributes.
-Wed Feb 1 10:12:14 1995 Mike Stump <mrs@cygnus.com>
+Tue Feb 17 14:07:52 1998 Mark Mitchell <mmitchell@usa.net>
- * decl2.c (finish_file): Fix bug in Jan 31st change.
+ * parse.y (initdcl0_innards): New grammar symbol.
+ (nomods_initdecls, nomods_initdcl0): Change type from itype to
+ none, since the resulting value is never used.
+ (parse_decl): New function.
+ (datadef): Remove redundant actions.
+ (initdcl0, notype_initdcl0, nomods_initdcl0): Use initdcl0_innards.
+ * parse.c: Regenerated.
+
+Tue Feb 17 11:54:16 1998 Jason Merrill <jason@yorick.cygnus.com>
-Tue Jan 31 16:59:15 1995 Gerald Baumgartner (gb@lorenzo.cs.purdue.edu)
+ * parse.y (simple_stmt): Use getdecls() to check for decl.
- * sig.c (build_signature_pointer_or_reference_type): Don't set
- IS_AGGR_TYPE for signature pointers/reference so expand_default_init
- doesn't expect to find a copy constructor.
- * call.c (build_method_call): Treat signature pointers/reference
- as if IS_AGGR_TYPE were set.
-
-Tue Jan 31 13:28:56 1995 Mike Stump <mrs@cygnus.com>
-
- * gc.c (get_typeid): Pawn off error messages to build_t_desc.
- (build_t_desc): Inform the user here if they try and build
- with -frtti and don't include <typeinfo.h>.
-
- * decl2.c (finish_prevtable_vardecl): Support rescanning.
- (finish_file): Move finish_prevtable_vardecl up to before the global
- initializers are done as tdecls are initialized in the global
- initializer. Also Pick up any new tdecls or vtables needed by
- synthesized methods.
-
- * class.c (finish_struct): Simplify. We have to do rtti scanning at
- end, so we might as well do all of it there.
-
-Tue Jan 31 05:35:02 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * call.c (build_method_call): Fix -fthis-is-variable for 32-bit
- targets, too.
-
-Tue Jan 31 00:11:04 1995 Mike Stump <mrs@cygnus.com>
-
- * decl2.c (finish_prevtable_vardecl): New routine, mostly split from
- finish_vtable_vardecl. It has the first half functionality from
- that routine.
- * decl2.c (finish_vtable_vardecl): Update to not include stuff not
- in finish_prevtable_vardecl.
- * decl2.c (finish_file): Call finish_prevtable_vardecl.
- * gc.c (build_generic_desc): Allow it to be called when not at the
- global binding layer, but behave as if we were.
- (build_t_desc): Rearrange a bit so that it really works and is
- easier to follow.
- * class.c (finish_struct): Don't decide on tdecls here, as we have
- to wait until the end of the file in general to decide whether or
- not they come out.
-
-Mon Jan 30 01:00:40 1995 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * init.c (build_delete): Check access to operator delete before
- calling the destructor.
- * method.c (build_opfncall, DELETE_EXPR): build_method is allowed to
- return error_mark_node.
- * call.c (build_method_call): Use the one-argument op delete even if
- it's an error.
+Sat Feb 14 11:50:51 1998 Manfred Hollstein <manfred@s-direktnet.de>
- * init.c (build_new): Fix -fthis-is-variable support.
- * call.c (build_method_call): Ditto.
+ * Make-lang.in (DEMANGLER_INSTALL_NAME, DEMANGLER_CROSS_NAME): New
+ macros.
+ (c++.install-common): Install c++filt properly as native or as cross
+ variant.
+ (c++.uninstall): Add c++filt.
- * call.c (convert_harshness): Make conversion from a pointer to bool
- worse than conversion to another pointer.
+Fri Feb 13 14:55:37 1998 Jason Merrill <jason@yorick.cygnus.com>
-Sat Jan 28 16:46:10 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (standard_conversion): Fix multi-level ptr conversions.
- * init.c (build_new): Check new return value if -fcheck-new.
+Fri Feb 13 14:06:22 1998 Mike Stump <mrs@wrs.com>
- * lex.c (check_newline): Clear end_of_file when we're done, too.
+ * init.c (build_new): Propagate error_mark_node up.
-Sat Jan 28 10:38:39 1995 Mike Stump <mrs@cygnus.com>
+Fri Feb 13 13:24:32 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (finish_vtable_vardecl): Make rtti TD tables follow
- vtables whereever they go.
+ * parse.y (simple_stmt): If the condition isn't a declaration,
+ start the controlled block after the test.
- * gc.c (build_t_desc): Remove old way of setting it up, as it wasn't
- right.
+Fri Feb 13 02:26:10 1998 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
-Sat Jan 28 09:10:44 1995 Mike Stump <mrs@cygnus.com>
+ * call.c (build_over_call): Convert builtin abs, labs and fabs to
+ tree-codes.
+ * decl.c (init_decl_processing): Reenable abs, labs and fabs as
+ builtins.
- * decl2.c (finish_vtable_vardecl): Now set the
- interface/implementation of vtables on the first virtual function,
- if one exists, otherwise we use the old method. This is a major win
- in terms of cutting down the size of objects and executables in
- terms of text space and data space. Now most of the savings that
- #pragma interface/implementation gives is automatic in a fair number
- of cases.
+Fri Feb 13 01:36:42 1998 Jason Merrill <jason@yorick.cygnus.com>
-Sat Jan 28 04:57:33 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (standard_conversion): A BASE_CONV replaces an RVALUE_CONV.
- * decl.c (grokdeclarator): Discard the template parameters in a
- template constructor declaration so that the function is always
- named constructor_name (ctype).
+Fri Feb 13 00:21:59 1998 Jason Merrill <jason@yorick.cygnus.com>
- * lex.c (check_newline): Use ungetc to put back the character before
- calling HANDLE_PRAGMA.
+ * cp-tree.h: Add access_protected_virtual_node.
+ * class.c (init_class_processing): Initialize it.
+ * decl.c (xref_basetypes): Use it.
+ * parse.y (base_class_access_list): Likewise.
-Fri Jan 27 17:23:47 1995 Mike Stump <mrs@cygnus.com>
+ * Make-lang.in (DEMANGLER_PROG): Add $(exeext).
+ (c++.install-common): Install c++filt.
- * decl2.c (check_classfn): If the cname is T<int> and fn_name is T,
- make sure we still match them.
+Thu Feb 12 12:46:51 1998 Benjamin Kosnik <bkoz@rhino.cygnus.com>
-Fri Jan 27 16:32:10 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (shadow_tag): Give error for typedef-ing built-in types.
- * parse.y: Add END_OF_LINE token.
+Wed Feb 11 23:28:05 1998 Mark Mitchell <mmitchell@usa.net>
- * lex.c (check_newline): Set linemode when we see a # directive, and
- unset it when we're done. Turn all 'return's into 'goto skipline'.
- Fix all uses of '\n', since we won't see it anymore. Put back the
- character we read before checking for a sysv or target pragma.
- (real_yylex): If we see an EOF in linemode, return END_OF_LINE.
- (handle_sysv_pragma): Don't look at the input stream; quit when we
- see an END_OF_LINE token.
+ * call.c (reference_binding): Use comptypes when comparing
+ TYPE_MAIN_VARIANTS to handle non-canonical array/index types.
- * input.c (getch): Return EOF if we're in line mode and at the end
- of a line.
- (put_back): Don't put back an EOF.
+Wed Feb 11 16:42:04 1998 Mark Mitchell <mmitchell@usa.net>
-Thu Jan 26 19:26:34 1995 Mike Stump <mrs@cygnus.com>
+ * tree.c (is_overloaded_fn): Use really_overloaded_fn.
+ (really_overloaded_fn): Move check here from is_overloaded_fn.
+ (get_first_fn): Use really_overloaded_fn and is_overloaded_fn.
- * except.c (expand_throw): Do the newing of the exception object
- before we load the type descriptor or the address so that we don't
- wipe any of the values out.
+Wed Feb 11 15:54:18 1998 Mark Mitchell <mmitchell@usa.net>
-Thu Jan 26 19:20:00 1995 Mike Stump <mrs@cygnus.com>
+ * typeck.c (build_ptrmemfunc): Type-check pointer-to-member
+ conversions.
- * except.c (init_exception_processing): Don't use r12 on the rs6000.
+Mon Feb 9 22:23:31 1998 Mark Mitchell <mmitchell@usa.net>
+
+ * cp-tree.h (push_template_decl): Return the decl passed in, or an
+ equivalent duplicate.
+ * decl.c (pushtag): Use the return value from push_template_decl.
+ (duplicate_decls): When duplicating a template declaration, merge
+ the DECL_TEMPLATE_RESULTs as well.
+ (make_implicit_typename): Don't try to dive into typename types to
+ find a context for making a new implicit typename.
+ (start_decl): Use the return value from push_template_decl.
+ (grokdeclarator): Complain about declarations list `const operator
+ int'. Since we don't correctly handle in-class initializations of
+ non-static data members, complain about this (now illegal)
+ practice. Issue an error for initializations of non-const statics
+ since that is illegal as well, and since we don't handle that case
+ correctly either.
+ (start_function): Use the return value from push_template_decl.
+ (start_method): Likewise.
+ * decl2.c (grokfield): Likewise. Since the change to
+ grokdeclarator ensures that all initialized fields are in fact
+ static, remove a redundant test for TREE_PUBLIC.
+ * parse.y (initlist): Disable labeled initializers since they do
+ not work as per the documentation, and since they do not use the
+ same syntax as the C front end.
+ * pt.c (push_template_decl): Return the decl passed in, or an
+ equivalent duplicate.
+ (lookup_template_class): When searching in a nested context,
+ use the right arguments.
+ (uses_template_parms): Handle the DECL_INITIAL for a CONST_DECL.
+ * typeck.c (build_component_ref): Assign the correct type to the
+ result of build_vfn_ref.
+
+Tue Feb 10 23:56:46 1998 Jason Merrill <jason@yorick.cygnus.com>
-Tue Jan 24 16:36:31 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (convert_nontype_argument): Fix typo.
+ (check_explicit_specialization): Allow old-style specialization
+ of class template members.
- * decl.c (grokparms): Don't try to build up a reference at this point.
+Tue Feb 10 20:36:52 1998 Jason Merrill <jason@yorick.cygnus.com>
+ Manfred Hollstein <manfred@s-direktnet.de>
- * typeck2.c (build_functional_cast): Don't assume that a NOP_EXPR
- will suffice to convert from integer_zero_node.
+ * decl.c (grokdeclarator): Use DECL_USE_TEMPLATE instead
+ when deciding to override DECL_ASSEMBLER_NAME.
-Wed Jan 25 15:02:09 1995 David S. Miller (davem@nadzieja.rutgers.edu)
+Tue Feb 10 15:30:55 EST 1998 Andrew MacLeod <amacleod@torpedo.to.cygnus.com>
- * class.c (instantiate_type): Change error message text.
- * typeck2.c (store_init_value): Likewise.
+ * decl2.c (lang_f_options): Add -fsquangle to option processing list.
+ * cp-tree.h (flag_do_squangling): Add declaration.
+ * lang-options.h: Add -fsquangle and -fno-squangle.
+ * method.c: Add macros and static variables for squangling.
+ (build_overload_name): Rename to build_mangled_name, add logic for B
+ compression, and split into process_modifiers and
+ process_overload_item.
+ (process_modifiers): New function, to handle constant, reference,
+ and pointer types.
+ (process_overload_item): New function, handles issue of type codes.
+ (build_overload_name): New function, start squangling and call
+ build_mangled_name.
+ (ALLOCATE_TYPEVEC, DEALLOCATE_TYPEVEC): Remove macro and expand inline.
+ (start_squangling): New function to initialize squangling structs.
+ (end_squangling): New function to destroy squangling structs.
+ (nrepeats): Rename variable to Nrepeats.
+ (issue_nrepeats): New function for issuing 'n' type repeats.
+ (check_ktype): New function to check for type K name compression.
+ (build_overload_nested_name): Add a check for K name compression.
+ (build_qualified_name): Add a check for K name compression and don't
+ use DECL_ASSEMBLER_NAME when squangling is on.
+ (check_btype): New function, checks for B type compression.
+ (build_static_name, build_decl_overload_real): Initiate squangling.
+ (build_typename_overload, build_overload_with_type): Initiate
+ squangling
-Mon Jan 23 21:57:14 1995 Mike Stump <mrs@cygnus.com>
+Sun Feb 8 23:47:38 1998 scott snyder <sss@d0linux01.fnal.gov>
- * pt.c (tsubst): When we copy a node, don't forget to copy
- TREE_CHAIN, we use it later.
+ * method.c (make_thunk): Avoid name buffer overflow.
-Mon Jan 23 03:33:47 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Sat Feb 7 16:48:54 1998 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (convert_for_assignment): Initialize variable before use.
+ * pt.c (instantiate_decl): Call cp_finish_decl for vars even if we
+ don't define them yet.
-Fri Jan 20 01:17:59 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * parse.y (nomods_initdcl0): Add constructor_declarator case.
- * g++.c (main): Link with both libstdc++ and libg++ if called as
- something ending with "g++", otherwise only libstdc++. Move -lm to
- the end of the line.
+Fri Feb 6 21:32:25 1998 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
-Thu Jan 19 15:43:11 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * config-lang.in (diff_excludes): Use basename only.
- * call.c (build_method_call): Don't mess with 'this' before calling
- compute_conversion_costs.
+Thu Feb 5 19:10:40 1998 Jason Merrill <jason@yorick.cygnus.com>
-Wed Jan 18 15:40:55 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * tinfo2.cc: Add tinfo for signed char.
- * search.c (get_matching_virtual): Give line number for previous
- declaration.
+Thu Feb 5 14:38:23 1998 Mike Stump <mrs@wrs.com>
- * call.c (convert_harshness): Handle conversions to references
- better.
+ * search.c (compute_access): Handle protected constructors in derived
+ classes as accessible.
- * cvt.c (build_up_reference): OK, handle {MIN,MAX}_EXPR *properly*.
+Wed Feb 4 01:26:49 1998 Jason Merrill <jason@yorick.cygnus.com>
-Wed Jan 18 15:21:38 1995 Mike Stump <mrs@cygnus.com>
+ * expr.c (cplus_expand_expr, PCC_STATIC_STRUCT_RETURN code):
+ Call convert_from_reference sooner.
- * class.c (instantiate_type): Use DECL_CHAIN to walk lists instead,
- as the TREE_CHAIN for methods will take us to the next differently
- named function, DECL_CHAIN won't.
+Tue Feb 3 23:50:52 1998 Mark Mitchell <mmitchell@usa.net>
-Wed Jan 18 14:26:59 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * cvt.c (ocp_convert): Obtain the constant values from constant
+ decls even if the destination type is the same as the type of the
+ decl.
- * tree.c (lvalue_p): Handle {MIN,MAX}_EXPR.
+ * decl2.c (finish_file): Make sure that static inlines with
+ definitions are not marked DECL_EXTERNAL before returning.
- * decl2.c (lang_decode_option): -Wall implies -Wparentheses.
- warn_parentheses defaults to 0.
+Tue Feb 3 22:43:42 1998 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokparms): Put back call to require_instantiated_type.
+ * decl.c: Lose arg_looking_for_template.
+ (lookup_name_real): Likewise.
+ * parse.y: Lose processing_template_arg, template_arg1
+ (primary): Likewise.
+ * spew.c (yylex): Set lastiddecl for PTYPENAMEs, too.
-Tue Jan 17 19:56:15 1995 Mike Stump <mrs@cygnus.com>
+Tue Feb 3 22:04:01 1998 Kriang Lerdsuwanakij <lerdsuwa@scf.usc.edu>
- * except.c (exception_section): Use the data section on the rs6000.
- Change calling convention for named_section.
+ * error.c (dump_decl): Fix type of default arguments for template
+ template parameters and nontype template parameters.
+ * parse.y (template_parm): Handle invalid default template
+ template arguments here.
-Wed Jan 17 18:20:57 1994 Fergus Henderson <fjh@munta.cs.mu.oz.au>
+ * parse.y (template_parm): Use template_arg instead of PTYPENAME
+ for default template template argument.
+ * pt.c (coerce_template_parms): Merge default template argument
+ codes. Can treat RECORD_TYPE as template name if it is implicitly
+ created. Fix argument index in error message.
+ * typeck.c (comptypes): Merge template argument comparison codes in
+ TEMPLATE_TEMPLATE_PARM and RECORD_TYPE.
- * cp-tree.h : Make if (x=0) warn with wall
- * parse.y : Make if (x=0) warn with wall
+Tue Jan 6 01:42:44 1998 Mumit Khan <khan@xraylith.wisc.edu>
-Tue Jan 17 14:12:00 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * lex.c (file_name_nondirectory): Also check for '/'.
- * decl.c (BOOL_TYPE_SIZE): BITS_PER_WORD if SLOW_BYTE_ACCESS,
- BITS_PER_UNIT otherwise.
+Mon Feb 2 11:24:22 1998 Mark Mitchell <mmitchell@usa.net>
- * search.c (get_matching_virtual): Don't check the binfo if the
- types are the same.
+ * parse.y (primary): Deal with statement-expressions in
+ templates.
+ * pt.c (tsubst_copy): Handle BIND_EXPR.
+ * tree.c (mapcar): Likewise.
- * cvt.c (cp_convert): Just call truthvalue_conversion to convert to
- bool.
+ * call.c (add_template_candidate_real): Pass extra parameter to
+ fn_type_unification.
+ * cp-tree.h (fn_type_unification): Add parameter.
+ * pt.c (fn_type_unification): Add additional parameter to deal with
+ static member functions.
+ (get_bindings): Deal with static member functions.
+
+ * cp-tree.h (DECL_NONSTATIC_MEMBER_FUNCTION_P): New macro.
+ (revert_static_member_fn): Declare.
+ * decl.c (revert_static_member_fn): Remove declaration. Change
+ linkage from internal to external.
+ (cp_finish_decl): Deal with virtual functions in classes local to
+ template functions.
+ * decl2.c (finish_file): Don't forget to emit increment/decrement
+ expressions in initializers for file-scope variables.
+ * parse.y (typename_sub2): If the typename doesn't names a
+ template, rather than a type, issue an error message.
+ * pt.c (check_explicit_specialization): Handle specializations of
+ static member functions.
+ (coerce_template_parms): Handle offset references to lists of
+ member functions.
+ * search.c (note_debug_info_needed): Don't crash when handed a
+ type which is being defined.
+ * typeck.c (complete_type): Don't crash when handed NULL_TREE;
+ that can happen with some illegal code.
+
+Mon Feb 2 00:57:38 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * call.c (user_harshness): Initialize `code' to 0.
+ (build_method_call): Initialize `candidates', `cp' and `len' to 0.
+ (null_ptr_cst_p): Add parentheses around && within ||.
+ (standard_conversion): Likewise.
+ (z_candidate): Likewise.
+ (build_user_type_conversion_1): Initialize `args' to NULL_TREE.
+ (build_object_call): Likewise for `mem_args'.
+ (build_new_op): Likewise for `mem_arglist'. Add `return' from
+ default case in enumeration switch.
+
+ * class.c (build_vtable_entry): Add explicit braces to avoid
+ ambiguous `else'.
+ (build_class_init_list): Likewise.
+ (finish_struct_1): Initialize `width' to 0.
+ (instantiate_type): Initialize `name' to NULL_TREE. Add
+ explicit braces to avoid ambiguous `else'.
+
+ * cvt.c (convert_to_aggr): Add explicit braces to avoid ambiguous
+ `else'.
+
+ * decl.c (grok_reference_init): Eliminate unused parameter, all
+ callers changed.
+ (record_builtin_type): Initialize `tdecl' to NULL_TREE.
+ (init_decl_processing): Initialize `vb_off_identifier' to NULL_TREE.
+ (cp_finish_decl): Initialize `ttype' to NULL_TREE.
+ (grokdeclarator): Add parentheses around && within ||. Add
+ explicit braces to avoid ambiguous `else'.
+ (grokparms): Initialize `type' to NULL_TREE.
+ (xref_tag): Remove unused label `just_return'.
+ (finish_enum): Initialize `minnode' and `maxnode' to NULL_TREE.
+ (finish_function): Initialize `cond' and `thenclause' to NULL_TREE.
+ (hack_incomplete_structures): Add parentheses around assignment
+ used as truth value.
+
+ * decl2.c (coerce_delete_type): Hide definition of `e3'.
+
+ * error.c: Include <stdlib.h>.
+ (dump_expr): Change the type of `i' to size_t. Remove unused
+ label `error'.
+
+ * except.c (init_exception_processing): Remove unused variable `d'.
+ (expand_throw): Likewise for `label'.
+
+ * friend.c (add_friends): Add explicit braces to avoid ambiguous
+ `else'.
+
+ * init.c (sort_member_init): Initialize `last_field' to NULL_TREE.
+ (sort_base_init): Likewise for `binfo'.
+ (expand_member_init): Likewise for `rval'.
+ (build_member_call): Add parentheses around assignment used as
+ truth value.
+ (build_offset_ref): Add explicit braces to avoid ambiguous `else'.
+ (build_new): Initialize `nelts' to NULL_TREE. Initialize
+ `old_immediate_size_expand' to 0.
+ (build_new_1): Initialize `nelts' and `alloc_node' to NULL_TREE.
+ (build_vec_delete_1): Remove unused variable `block'.
+ (expand_vec_init): Initialize `itype' to NULL_TREE.
+
+ * lex.c: Include <strings.h> if we don't have <string.h>. Protect
+ declaration of `index' and `rindex' with autoconf macros.
+ (reinit_parse_for_expr): Remove unused variables
+ `look_for_semicolon' and `look_for_lbrac'.
+ (cons_up_default_function): Initialize `args' to NULL_TREE.
+ (readescape): Initialize `firstdig' to 0.
+ (real_yylex): Add parentheses around assignment used as truth value.
+
+ * method.c: Include <strings.h> if we don't have <string.h>.
+ Protect declaration of `index' with autoconf macro.
+
+ * parse.y (primary): Add explicit braces to avoid ambiguous `else'.
+ Initialize `type' to NULL_TREE.
+ (structsp): Remove unused variable `id'.
+
+ * pt.c (coerce_template_parms): Add explicit braces to avoid
+ ambiguous `else'.
+ (lookup_template_class): Initialize `template' to NULL_TREE.
+ (instantiate_class_template): Remove unused variable `name' and `e'.
+ (tsubst): Likewise for `i'. Initialize `last' to NULL_TREE.
+ (do_poplevel): Initialize `saved_warn_unused' to 0.
+ (type_unification): Remove unused varable `parm'.
+ (unify): Likewise for `j'.
+
+ * repo.c (init_repo): Add parentheses around assignment used as
+ truth value.
+ (finish_repo): Remove unused varable `p'.
+
+ * search.c (get_binfo): Initiize `type' to NULL_TREE.
+ (get_base_distance): Likewise.
+ (lookup_field): Initialize `rval_binfo_h', `type', `basetype_path'
+ and `new_v' to NULL_TREE.
+ (lookup_fnfields): Likewise for `rval_binfo_h'.
+ (breadth_first_search): Add parentheses around assignment used as
+ truth value.
+ (get_template_base): Initialize `type' to NULL_TREE.
+
+ * sig.c (append_signature_fields): Initialize `last_mfptr' to
+ NULL_TREE.
+ (build_signature_table_constructor): Likewise for
+ `last_rhs_field', `pfn' and `vt_off'.
+ (build_sigtable): Likewise for `init'.
+
+ * tree.c (break_out_calls): Initialize `t2' to NULL_TREE.
+ (propagate_binfo_offsets): Likewise for `delta'.
+ (hash_tree_cons): Initialize hashcode to 0.
+ (can_free): Likewise for `size'.
+ (cp_tree_equal): Add explicit braces to avoid ambiguous `else'.
+
+ * typeck.c (convert_sequence): Hide prototype.
+ (common_type): Add explicit braces to avoid ambiguous `else'.
+ (comp_target_types): Likewise.
+ (build_x_function_call): Initialize `ctypeptr' to NULL_TREE.
+ (build_function_call_real): Add explicit braces to avoid ambiguous
+ `else'.
+ (convert_arguments): Initialize `called_thing' to 0.
+ (convert_for_initialization): Initialize `savew' and `savee' to 0.
+
+ * typeck2.c (incomplete_type_error): Initialize `errmsg' to 0.
+ (digest_init): Initialize `old_tail_contents' to NULL_TREE.
+ (build_x_arrow): Likewise for `last_rval'.
+
+ * xref.c (GNU_xref_decl): Initialize `cls' to 0.
+
+Sun Feb 1 12:45:34 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
+
+ * decl.c (init_decl_processing): Use set_sizetype.
+ * decl2.c (sizetype): Don't declare.
+ * typeck.c (c_sizeof): Convert result of *_DIV_EXPR to sizetype.
+ (c_sizeof_nowarn, build_binary_op_nodefault): Likewise.
+ (build_component_addr, unary_complex_lvalue): Likewise.
+ * rtti.c (expand_class_desc): Likewise.
+ * class.c (get_vfield_offset): Likewise.
+
+Thu Jan 29 10:39:30 1998 Mark Mitchell <mmitchell@usa.net>
+
+ * pt.c (convert_nontype_argument): Move check for is_overloaded_fn
+ early to avoid bogus error. Handle overloaded function
+ names provided as template arguments correctly.
+ (coerce_template_parms): Don't mishandle overloaded functions when
+ dealing with template template parameters.
+ (lookup_template_class): Issue an error message, rather than
+ crashing, when the TYPE_DECL provided is not a template type.
+
+Wed Jan 28 23:14:44 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * class.c (instantiate_type): Don't just return a known type if
+ it's wrong.
+
+Wed Jan 28 11:04:07 1998 Mark Mitchell <mmitchell@usa.net>
+
+ * class.c (instantiate_type): Remove handling of FUNCTION_DECL
+ since that code could never be reached.
+
+ * error.c (dump_decl): Avoid aborting in the midst of printing an
+ error message about an illegal template declaration.
-Mon Jan 16 13:28:48 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * parse.y (structsp): Print an error message, rather than crashing,
+ when a class-head does not name a class.
- * various: Use boolean_type_node, boolean_true_node,
- boolean_false_node.
+ * pt.c (convert_nontype_argument): Allow REAL_TYPE and COMPLEX_TYPE
+ template arguments as a g++ extension.
+
+ * cp-tree.def (ALIGNOF_EXPR): New tree code.
+ * decl2.c (grok_alignof): If processing_template_decl, just store
+ the expression.
+ * typeck.c (c_alignof): Likewise.
+ * decl2.c (build_expr_from_tree): Handle ALIGNOF_EXPR.
+ * error.c (dump_expr): Likewise.
+ * pt.c (tsubst_copy): Likewise.
+ * tree.c (cp_tree_equal): Likewise.
+ * pt.c (uses_template_parms): Correctly determine whether or not a
+ SIZEOF_EXPR/ALIGNOF_EXPR uses template parameters so that constant
+ folding can be done.
+
+ * cp-tree.h (grok_enum_decls): Remove type parameter.
+ * decl.c (grok_enum_decls): Likewise.
+ * decl2.c (grok_x_components): Call grok_enum_decls
+ unconditionally, since it will do nothing if there is no
+ current_local_enum. Use the new calling sequence.
+ * pt.c (tsubst_enum): Use the new calling sequence for
+ grok_enum_decls.
+
+ * decl.c (start_function): Make member functions of local classes
+ in extern inline functions have comdat linkage here...
+ (grokdeclarator): Rather than here.
+
+Wed Jan 28 10:55:47 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * pt.c (convert_nontype_argument): Use decl_constant_value.
+
+Tue Jan 27 16:42:21 1998 Mark Mitchell <mmitchell@usa.net>
+
+ * call.c (add_template_candidate_real): New function.
+ (add_template_candidate): Use it.
+ (add_template_conv_candidate): Likewise.
+ (joust): Pass extra argument to more_specialized.
+ * class.c (instantiate_type): Handle a single FUNCTION_DECL.
+ (is_local_class): Remove.
+ (finish_struct): Check TI_PENDING_SPECIALIZATION_FLAG.
+ * cp-tree.h (is_local_class): Remove.
+ (perform_array_to_pointer_conversion): Likewise.
+ (finish_member_template_decl): Add.
+ (check_explicit_specialization): Return a tree, not an int.
+ (more_specialized): Take additional argument.
+ (get_bindings): Likewise.
+ (TI_PENDING_SPECIALIZATION_FLAG): New macro.
+ * cvt.c (perform_qualification_conversions): Use comp_ptr_ttypes.
+ (perform_array_to_pointer_conversion): Remove.
+ * decl.c (saved_scope): Add processing_specialization,
+ processing_explicit_instantiation fields.
+ (maybe_push_to_top_level): Save them.
+ (pop_from_top_level): Restore them.
+ (grokfndecl): Use new return value from
+ check_explicit_specialization.
+ (start_decl): Don't check flag_guiding_decls before pushing
+ decls.
+ (cp_finish_decl): Remove previous (bogus) change.
+ (grok_declarator): Use decl_function_context rather than
+ is_local_class.
+ * decl2.c (finish_file): Pass extra argument to get_bindings.
+ (build_expr_from_tree): Let build_x_component_ref check
+ validity of arguments rather than doing it here.
+ * lex.c (cons_up_default_function): Remove code fooling with
+ processing_specialization, processing_explicit_instantiation
+ flags, as that is now done in {maybe_push_top,pop_from}_top_level.
+ * method.c (build_overload_identifier): Mangle local classes in
+ template functions correctly.
+ * parse.y (finish_member_template_decl): Move to pt.c.
+ * pt.c (finish_member_template_decl): Moved here from parse.y.
+ (print_candidates): New function.
+ (determine_specialization): Change interface. Properly look for
+ most specialized versions of template candidates.
+ (check_explicit_specialization): Fully process explicit
+ instantiations.
+ (push_template_decl): Avoid looking at CLASSTYPE fields in
+ FUNCTION_DECLS.
+ (determine_overloaded_function): Remove.
+ (convert_nontype_argument): Change name from
+ convert_nontype_parameter. Use determine_overloaded_function
+ instead of instantiate_type.
+ (mangle_class_name_for_template): Handle type contexts as well as
+ function contexts.
+ (classtype_mangled_name): Likewise.
+ (lookup_template_class): Likewise.
+ (tsubst): Likewise.
+ (more_specialized): Take explict template arguments as a
+ parameter.
+ (most_specialized): Likewise.
+ (get_bindings): Likewise. Check that return types match before
+ proclaiming a function a match.
+ (do_decl_instantiation): Remove code searching for function to
+ instantiate; that is now done in check_explicit_specialization.
+ (add_maybe_template): Pass extra argument to get_bindings.
+ * tree.c (really_overloaded_fn): Use is_overloaded_fn to simplify
+ implementation.
+ * typeck.c (build_component_ref): Check for invalid arguments.
+
+Tue Jan 27 01:44:02 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * expr.c (cplus_expand_expr, AGGR_INIT_EXPR): Don't check that
+ return_target and call_target are equivalent.
+
+ * pt.c (type_unification_real): Just accept function parms that
+ don't use any template parms.
+
+Sun Jan 25 03:30:00 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * decl.c (cp_finish_decl): When bailing on a comdat variable, also
+ unset DECL_NOT_REALLY_EXTERN.
+
+ * parse.y (typename_sub*): Fix std::.
+
+Sat Jan 24 12:13:54 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * error.c (dump_decl): Fix type default template args.
+ (dump_type): Hand TEMPLATE_DECL off to dump_decl.
+
+Fri Jan 23 18:34:37 1998 Mumit Khan <khan@xraylith.wisc.edu>
+
+ * lex.c (DIR_SEPARATOR): Define to be '/' if not already defined.
+ (file_name_nondirectory): Use.
+
+Wed Jan 21 10:29:57 1998 Kriang Lerdsuwanakij <lerdsuwa@scf.usc.edu>
+
+ * pt.c (coerce_template_parms): Don't access elements of ARGLIST
+ that are not really present. Substitute default arguments in
+ template template arguments. Correctly convert TEMPLATE_DECL to
+ TEMPLATE_TEMPLATE_PARM.
+ (comp_template_args): TEMPLATE_DECL and TEMPLATE_TEMPLATE_PARM
+ are no longer treated specially here.
+ * parse.y (template_template_parm): Fix copy error.
+ * decl.c (grokdeclarator): Warn about missing `typename' for nested
+ type created from template template parameters.
+ * parse.y (bad_parm): Likewise
+
+ * class.c (finish_struct): Handle TEMPLATE_TEMPLATE_PARM.
+ (push_nested_class): Likewise.
+ * cp-tree.def (TEMPLATE_TEMPLATE_PARM): New tree code.
+ * cp-tree.h (DECL_TEMPLATE_TEMPLATE_PARM_P): New macro.
+ (copy_template_template_parm): Declare.
+ * decl.c (arg_looking_for_template): New variable.
+ (lookup_name_real): Handle TEMPLATE_TEMPLATE_PARM.
+ Try to return TEMPLATE_DECL or TEMPLATE_TEMPLATE_PARM
+ node if arg_looking_for_template is nonzero.
+ (pushdecl): Handle TEMPLATE_TEMPLATE_PARM.
+ (grok_op_properties, xref_tag, xref_basetypes): Likewise.
+ (grokdeclarator): Handle TEMPLATE_DECL.
+ * decl2.c (constructor_name_full): Handle TEMPLATE_TEMPLATE_PARM.
+ * error.c (dump_type): Add TEMPLATE_DECL and TEMPLATE_TEMPLATE_PARM.
+ (dump_type_prefix, dump_type_suffix) Handle TEMPLATE_TEMPLATE_PARM.
+ (dump_decl): Handle unnamed template type parameters.
+ Handle template template parameters.
+ (dump_function_name): Handle template template parameters.
+ * init.c (is_aggr_typedef, is_aggr_type, get_aggr_from_typedef):
+ Handle TEMPLATE_TEMPLATE_PARM.
+ * method.c (build_template_template_parm_names): New function.
+ (build_template_parm_names): Handle TEMPLATE_DECL.
+ (build_overload_nested_name, build_overload_name):
+ Handle TEMPLATE_TEMPLATE_PARM.
+ * parse.y (maybe_identifier): New nonterminal.
+ (template_type_parm): Use it.
+ (template_template_parm, template_arg1): New nonterminal.
+ (template_parm): Add template_template_parm rules.
+ (template_arg): Set processing_template_arg.
+ (template_arg1): Rules moved from template_arg.
+ (primary, nonnested_type): Set arg_looking_for_template if we are
+ processing template arguments.
+ * pt.c (begin_member_template_processing): Handle TEMPLATE_DECL.
+ (process_template_parm): Handle template template parameters.
+ (coerce_template_parms, comp_template_args): Likewise.
+ (mangle_class_name_for_template, lookup_template_class): Likewise.
+ (uses_template_parms): Handle TEMPLATE_DECL and
+ TEMPLATE_TEMPLATE_PARM.
+ (current_template_args): Handle TEMPLATE_DECL.
+ (tsubst, tsubst_copy, unify): Handle TEMPLATE_TEMPLATE_PARM.
+ * search.c (dfs_walk, dfs_record_inheritance):
+ Handle TEMPLATE_TEMPLATE_PARM.
+ * tree.c (copy_template_template_parm): New function.
+ (mapcar): Handle TEMPLATE_TEMPLATE_PARM.
+ * typeck.c (comptypes): Handle TEMPLATE_TEMPLATE_PARM.
+
+Mon Jan 19 22:40:03 1998 Mark Mitchell <mmitchell@usa.net>
+
+ * decl.c (start_decl): Don't allow duplicate definitions of static
+ data members.
+
+ * call.c (build_user_type_conversion_1): Handle user-defined
+ template conversion operators correctly.
+
+ * decl2.c (build_expr_from_tree): Issue an error message if the
+ object in a COMPONENT_REF is a TEMPLATE_DECL.
+
+ * typeck.c (incomplete_type_error): Handle TEMPLATE_TYPE_PARMs.
+
+ * class.c (is_local_class): New function.
+ * cp-tree.h (is_local_class): Declare it.
+ (last_tree): Likewise.
+ (begin_tree): Likewise.
+ (end_tree): Likewise.
+ (lookup_template_class): Change prototype.
+ * decl.c (cp_finish_decl): Check for NULL where necesary.
+ Consider FUNCTION_DECLS to declare objects with top-level binding,
+ when calling make_decl_rtl.
+ (grokdeclarator): Give members of local classes internal linkage.
+ (start_function): Remove declaration of last_tree.
+ (finish_function): Set flag_keep_inline_functions around call to
+ rest_of_compilation if we are processing a member function in a
+ local class.
+ (start_method): Call push_template_decl for member functions of
+ local classes in template functions.
+ * decl2.c (import_export_decl): Don't give external linkage to
+ instantiations of templates with internal linkage.
+ * parse.y (last_tree): Remove declaration.
+ (template_type): Pass extra parameter to lookup_template_class.
+ (self_template_type): Likewise.
+ (structsp): Move call to reset_specialization into left_curly.
+ (left_curly): Call reset_specialization, and begin_tree.
+ * pt.c (saved_trees): New variable.
+ (mangle_class_name_for_template): Change prototype. Use
+ additional function context to name local classes in templates
+ correctly.
+ (classtype_mangled_name): Pass the context.
+ (push_template_decl): Handle local classes and templates, and
+ member functions for such classes.
+ (convert_nontype_parameter): Fix handling of pointer-to-member
+ constants.
+ (lookup_template_class): Handle local classes in templates.
+ (tsubst): Likewise. Don't assume that template instantiations
+ have external linkage; pay attention to the template declaration.
+ (mark_decl_instantiated): Likewise.
+ (begin_tree): New function.
+ (end_tree): Likewise.
+
+ * decl.c (xref_basetypes): Don't call complete_type for basetypes
+ that involve template parameters; that can lead to infinite
+ recursion unnecessarily.
- * search.c (get_matching_virtual): Allow covariant returns that
- don't require pointer adjustment.
+ * pt.c (register_specialization): Do not register specializations
+ that aren't ready to be registered yet.
+ (check_explicit_specialization): Handle explicit specialization of
+ constructors and destructors.
+ (build_template_decl): New function.
+ (push_template_delc): Handle out-of-class specializations of
+ member templates.
+
+ * pt.c (check_explicit_specialization): Set up the template
+ information before registering the specialization.
+ (coerce_template_parms): Fix thinko.
+ (tsubst): Handle specializations of member templates correctly.
+
+ * class.c (finish_struct_methods): Remove calls to
+ check_explicit_specialization from here.
+ (finish_struct): And insert them here.
+ * cp-tree.h (perform_qualification_conversions): New function.
+ (perform_array_to_pointer_conversion): Likewise.
+ (begin_explicit_instantiation): Likewise.
+ (end_explicit_instantiation): Likewise.
+ (determine_specialization): Renamed from
+ determine_explicit_specialization.
+ (comp_template_parms): New function.
+ (processing_explicit_instantiation): New variable.
+ * cvt.c (perform_qualification_conversions): New function.
+ (perform_array_to_pointer_conversion): Likewise.
+ * decl.c (duplicate_decls): Don't consider template functions
+ alike unless they have the same parameters. Refine handling of
+ instantiation/specialization mismatches.
+ (start_decl): Don't call pushdecl for template specializations,
+ since they don't affect overloading.
+ (start_function): Likewise
+ (grokfndecl): Call check_explicit_specialization a little later.
+ Don't call duplicate_decls for memberm template specializations.
+ (grokdeclarator): Don't update template_count for classes that are
+ themselves specializations. Remove use of `2' as parameter to
+ grokfndecl since that value isn't used.
+ * lex.c (cons_up_default_function): Save and restore
+ processing_explicit_instantiation around calls to grokfield.
+ * parse.y (finish_member_template_decl): New function.
+ (component_decl_1): Use it.
+ (fn.def2): Likewise.
+ (template_arg_list_opt): New nonterminal.
+ (template_type): Use it.
+ (self_template_type): Likewise.
+ (template_id): Likewise.
+ (object_template_id): Likewise.
+ (notype_template_declarator): Likwise.
+ (begin_explicit_instantiation): Likewise.
+ (end_explicit_instantiation): Likewise.
+ (explicit_instantiation): Use them.
+ * pt.c (coerce_template_parms): Add parameters.
+ (processing_explicit_instantiation): New variable.
+ (convert_nontype_parameter): New function.
+ (determine_overloaded_function): Likewise.
+ (begin_explicit_instantiation): Likewise.
+ (end_explicit_instantiation): Likewise.
+ (retrieve_specialization): Likewise.
+ (register_specialization): Likewise.
+ (processing_explicit_specialization): Removed.
+ (determine_specialization): Handle specializations of member
+ functions of template class instantiations.
+ (check_explicit_specialization): Refine to conform to standard.
+ (comp_template_parms): New function.
+ (coerce_template_parms): Call convert_nontype_parameter.
+ (tsubst): Refine handling of member templates. Use
+ register_specialization.
+ (instantiate_template): Use retrieve_specialization.
+ (do_decl_instantiation): Likewise.
+ (instantiate_decl): Likewise.
+ (type_unification): Improve handling of explict template
+ arguments.
+ * tree.c (mapcar): Return error_mark_node, rather than aborting,
+ on VAR_DECLS, FUNCTION_DECLS, and CONST_DECLS.
+ * typeck.c (build_unary_op): Call determine_specialization, rather
+ than determine_explicit_specialization.
+
+Mon Jan 19 13:18:51 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * cvt.c (build_up_reference): A TARGET_EXPR has side effects.
+
+Fri Jan 16 11:40:50 1998 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
+
+ * error.c (dump_decl): For enum tags, output the tag, not its value.
+
+1998-01-13 Brendan Kehoe <brendan@cygnus.com>
+
+ * decl.c (init_decl_processing): Only call init_rtti_processing
+ FLAG_RTTI is set.
+
+Mon Jan 12 01:35:18 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * init.c (build_new_1): Split out from build_new.
+ (build_new): Just return a NEW_EXPR.
+ * expr.c (cplus_expand_expr): Handle NEW_EXPR.
+
+ * decl2.c (get_temp_regvar): Tweak.
+
+ * cp-tree.h (TREE_CALLS_NEW): Comment out.
+ * class.c (resolves_to_fixed_type_p): Remove use.
+ * method.c (build_opfncall): Likewise.
+ * call.c (build_new_op): Likewise.
+
+Wed Jan 7 23:47:13 1998 Jason Merrill <jason@yorick.cygnus.com>
+
+ * exception.cc (__eh_alloc, __eh_free): New fns.
+ (__cp_push_exception, __cp_pop_exception): Use them.
+ (__uncatch_exception): Call terminate here if no exception.
+ * except.c (build_terminate_handler): New fn.
+ (expand_start_catch_block): Use it.
+ (expand_exception_blocks): Likewise.
+ (alloc_eh_object): New fn.
+ (expand_throw): Use it. Protect exception init with terminate.
+ * typeck.c (build_modify_expr): Remove code that ignores trivial
+ methods.
- * typeck.c (build_conditional_expr): Don't call default_conversion
- on ifexp.
+Mon Dec 22 11:36:27 1997 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * call.c (add_builtin_candidate): Add default case in enumeration
+ switch.
+ (build_new_op): Likewise.
+ (convert_like): Likewise.
+ * cvt.c (build_expr_type_conversion): Likewise.
+ * tree.c (real_lvalue_p): Likewise.
+ (lvalue_p): Likewise.
+ (cp_tree_equal): Likewise.
+ * typeck.c (comptypes): Likewise.
+ (build_component_ref): Likewise.
+ (build_function_call_real): Likewise.
+ (build_binary_op_nodefault): Likewise.
+ (build_unary_op): Likewise.
+ (build_modify_expr): Likewise.
+ * typeck2.c (initializer_constant_valid_p): Likewise.
- * cvt.c (build_up_reference): Handle MIN_EXPR and MAX_EXPR.
+Sun Dec 21 15:59:00 1997 Nick Clifton <nickc@cygnus.com>
- * decl.c (grokdeclarator): Upgrade warning about &const to pedwarn.
+ * decl2.c (lang_decode_option): Add support for -Wunknown-pragmas.
-Sun Jan 15 22:17:32 1995 dcb@lovat.fmrco.COM (David Binderman)
+Thu Dec 18 14:51:50 1997 Mark Mitchell <mmitchell@usa.net>
- * pt.c (do_function_instantiation): Free targs once we're done.
+ * pt.c (coerce_template_parms): Make sure to digest_init if
+ possible.
-Sun Jan 15 22:17:32 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (duplicate_decls): Make the newdecl virtual if the
+ olddecl was, just as is done with other attributes of olddecl.
- * decl.c (BOOL_TYPE_SIZE): Defaults to BITS_PER_WORD.
- (init_decl_processing): Use BOOL_TYPE_SIZE instead of CHAR_TYPE_SIZE
- for bool.
+Thu Dec 18 14:43:19 1997 Jason Merrill <jason@yorick.cygnus.com>
-Sat Jan 14 05:33:55 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * typeck.c (unary_complex_lvalue): Ignore op0 when taking the
+ address of an OFFSET_REF.
- * decl2.c (finish_file): We need to mess up if there are any
- variables in the list, not just if there is one with a constructor.
+ * cp-tree.def: Add AGGR_INIT_EXPR.
+ * error.c, tree.c, typeck.c: Replace uses of NEW_EXPR with
+ AGGR_INIT_EXPR where appropriate.
+ * expr.c (cplus_expand_expr): Likewise. Simplify.
-Fri Jan 13 14:42:55 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (finish_file): Remove call to register_exception_table.
- * decl.c (duplicate_decls): Propagate DECL_STATIC_{CON,DE}STRUCTOR.
- (finish_function): Handle DECL_STATIC_{CON,DE}STRUCTOR.
- (finish_function): Trust rest_of_compilation.
+Wed Dec 17 17:08:52 1997 Benjamin Kosnik <bkoz@rhino.cygnus.com>
- * decl2.c (finish_file): Also call functions designated as static
- constructors/destructors.
+ * pt.c (instantiate_class_template): Don't do injection when
+ processing_template_decl is true, as pollutes current_binding_level
+ for base classes.
- * decl.c (grokdeclarator): Allow access decls of operator functions.
- (grokparms): Only do convert_for_initialization if the initializer
- has a type.
- (duplicate_decls): Put back push_obstacks_nochange call.
+Wed Dec 17 21:17:39 1997 Peter Schmid <schmid@ltoi.iap.physik.tu-darmstadt.de>
- * lex.c (real_yylex): Downgrade complaint about the escape sequence
- being too large from pedwarn to warning.
+ * pt.c (maybe_fold_nontype_arg): Add prototype.
- * decl.c (grokdeclarator): Don't complain about long long in system
- headers.
+Tue Dec 16 10:31:20 1997 Jason Merrill <jason@yorick.cygnus.com>
- * lex.c (real_yylex): Handle digraphs.
+ * tree.c (mapcar): Handle TRY_CATCH_EXPR et al.
+ * error.c (dump_expr): Likewise.
-Thu Jan 12 12:17:24 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Mon Dec 15 12:22:04 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (init_decl_processing): -f{no-,}strict-prototype only
- affects C linkage declarations now.
+ * typeck.c (build_function_call_real): Remove "inline called before
+ definition" pedwarn.
- * typeck.c (comp_target_types): Grok simple contravariant conversions.
- (common_type): t1 and t2 are interchangeable.
+ * pt.c (coerce_template_parms): Use maybe_fold_nontype_arg.
- * various: Test return value of comp_target_types differently in
- different places; it now returns -1 for a contravariant conversion
- (which is fine in symmetric cases).
+Sun Dec 14 22:34:20 1997 Jason Merrill <jason@yorick.cygnus.com>
- (common_type): Prefer long double to double even when
- they have the same precision.
+ * cvt.c (cp_convert_to_pointer): Fix base conversion of pm's.
- * decl.c (grokparms): Call convert_for_initialization to check
- default arguments.
+ * pt.c (type_unification_real): Change __null to type void* with
+ a warning.
- * init.c (build_new): void_type_node has a size (of 0).
+Sun Dec 14 20:38:35 1997 Mark Mitchell <mmitchell@usa.net>
- * decl.c (decls_match): Also check for agreement of TREE_READONLY
- and TREE_THIS_VOLATILE.
- (push_class_level_binding): Properly handle shadowing of
- nested tags by fields.
+ * call.c (implicit_conversion): Don't call
+ build_user_type_conversion_1 with a NULL expr, since it will
+ crash.
- * search.c (dfs_pushdecls): Ditto.
+ * pt.c (unify): Don't try to unify array bounds if either array is
+ unbounded.
- * decl2.c (finish_file): Don't second-guess self-initialization.
+Fri Dec 12 16:09:14 1997 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (convert_to_reference): Work with expr directly, rather than
- a copy.
+ * errfn.c (cp_pedwarn, cp_pedwarn_at, cp_error_at, cp_warning_at):
+ Replace extern decls with casts.
- * decl.c (push_overloaded_decl): Only shadow artificial TYPE_DECLs.
+ * decl.c (expand_start_early_try_stmts): Don't mess with a sequence.
+ Update last_parm_cleanup_insn.
+ (store_after_parms): Remove.
+ * cp-tree.h: Adjust.
- * init.c (add_friend): Downgrade duplicate friend message from
- pedwarn to warning.
+Thu Dec 11 22:18:37 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (duplicate_decls): Push obstacks before calling common_type.
+ * decl2.c (comdat_linkage): Also set DECL_COMDAT.
+ (finish_file): Check DECL_COMDAT instead of weak|one_only.
+ (import_export_vtable): Use make_decl_one_only instead of
+ comdat_linkage for win32 tweak.
+ (import_export_decl): Likewise.
+ * pt.c (mark_decl_instantiated): Likewise.
-Thu Jan 12 17:15:21 1995 Michael Ben-Gershon <mybg@cs.huji.ac.il>
+ * decl2.c (finish_file): Lose handling of templates in pending_statics.
- * except.c (push_eh_entry): set LABEL_PRESERVE_P flag for
- exception table labels.
- (expand_start_all_catch): Ditto.
- (expand_leftover_cleanups): Ditto.
- (expand_end_catch_block): Ditto.
- * except.c (make_first_label): new function.
- (expand_start_all_catch): add a call to make_first_label() before
- using a label as a jump destination.
- (expand_end_all_catch): Ditto.
- (expand_leftover_cleanups): Ditto.
- (expand_end_catch_block): Ditto.
- (expand_builtin_throw): Ditto.
- (expand_throw): Ditto.
- * except.c: Add ARM processor support for exception handling.
+Thu Dec 11 21:12:09 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Jan 12 12:17:24 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (finish_file): Lose call to expand_builtin_throw.
+ * except.c (expand_builtin_throw): Remove.
+ * cp-tree.h: Remove ptr_ptr_type_node.
+ * decl.c: Likewise.
- (complete_array_type): Copy code from C frontend.
+Thu Dec 11 20:43:33 1997 Teemu Torma <tot@trema.com>
+
+ * decl.c (ptr_ptr_type_node): Define.
+ (init_decl_processing): Initialize it.
+ * cp-tree.h: Declare it.
+ * exception.cc (__cp_exception_info): Use __get_eh_info.
+ (__cp_push_exception): Ditto.
+ (__cp_pop_exception): Ditto.
- * lex.c (real_yylex): Don't multiply the length of a wide string
- literal by WCHAR_BYTES.
+ From Scott Snyder <snyder@d0sgif.fnal.gov>:
+ * except.c (expand_builtin_throw): Use get_saved_pc_ref instead of
+ saved_pc.
+ (init_exception_processing): Removed saved_pc initialization.
- * decl.c (pushdecl): Check for redeclaration of wchar_t here.
- (duplicate_decls): Instead of here.
- (define_label): Complain about a label named wchar_t.
- (grokdeclarator): Complain about declarations of
- operator-function-ids as non-functions.
+Wed Dec 10 11:04:45 1997 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (unary_complex_lvalue): Also wrap prefix -- and ++ in
- COMPOUND_EXPRs.
- (build_unary_op): Wrap unary plus in a NON_LVALUE_EXPR.
+ * pt.c (instantiate_decl): Defer all templates but inline functions.
- * lex.c (real_yylex): Don't skip whitespace when reading the next
- character after ->.
+Mon Dec 8 23:17:13 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Jan 11 16:32:49 1995 Mike Stump <mrs@cygnus.com>
+ * init.c (expand_vec_init): Don't fold a list of parameters.
- * except.c: Allow cc1plus to be built with native compiler on rs6000.
- (expand_start_all_catch): Add assemble_external calls for various
- routines we call.
- (expand_leftover_cleanups): Ditto.
- (expand_start_catch_block): Ditto.
- (do_unwind): Ditto.
- (expand_builtin_throw): Ditto.
+ * decl.c (copy_args_p): Handle copy elision for types with virtual
+ bases.
+ * call.c (build_over_call): Likewise.
-Wed Jan 11 01:05:42 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Sun Dec 7 22:38:12 1997 Mark Mitchell <mmitchell@usa.net>
- * decl.c (pushtag): Only look for a previous decl in the current
- binding level. Use explicit global scope in DECL_NESTED_TYPENAME.
+ * pt.c (lookup_template_function): Copy the template arguments,
+ not just the list containing them, to the permanent obstack.
- * gxx.gperf: Add __signature__ and __sigof__ keywords.
+Sun Dec 7 15:53:06 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (lang_decode_option): -ansi does not set flag_no_asm. It
- does set flag_no_gnu_keywords and flag_operator_names.
+ * except.c (expand_start_catch_block): suspend_momentary for the
+ terminate handler.
- * lex.c (init_lex): 'overload' is not a keyword unless -traditional.
- Unset extension keywords if -fno-gnu-keywords.
- Allow operator names ('bitand') if -foperator-names.
- Never unset 'asm'; -fno-asm only affects 'typeof'.
+ * error.c (dump_decl): Handle LOOKUP_EXPR.
- * decl.c (lookup_name_real): The got_object special lookup only
- applies to types.
+Sun Dec 7 15:45:07 1997 Mark Mitchell <mmitchell@usa.net>
-Tue Jan 10 18:07:51 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * rtti.c (build_dynamic_cast): Copy the cast-to type to the
+ permanent obstack if we are processing a template decl.
+ * typeck.c (build_static_cast): Likewise.
+ (build_const_cast): Likewise.
+ (build_reinterpret_cast): Likewise.
- * spew.c (yylex): Also use DECL_NESTED_TYPENAME if got_object is set.
+ * pt.c (coerce_template_parms): Coerce some expressions, even
+ when processing_template_decl.
- * parse.y (primary): Unset got_object after all rules that use the
- 'object' nonterminal.
- (object): Set got_object.
+Sun Dec 7 01:46:33 1997 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
- * lex.h: Declare got_object.
+ * typeck.c (build_binary_op_nodefault, pointer_diff): Symmetric
+ handling of pointer difference expressions.
- * decl.c (lookup_name_real): Also lookup names in the context of an
- object specified.
+ * typeck.c (comp_target_types): Comparison of function/method types
+ is independent of nptrs.
-Tue Jan 10 14:30:30 1995 Mike Stump <mrs@cygnus.com>
+Sun Dec 7 01:40:27 1997 Mark Mitchell <mmitchell@usa.net>
- * typeck.c (get_member_function_from_ptrfunc): Use ptrdiff_type_node
- for things that have to be added to pointers, not size_type. Cures
- problems with pointer to members on Alphas.
- (build_binary_op_nodefault): Ditto.
- (get_delta_difference_: Ditto.
- (build_ptrmemfunc): Ditto.
+ * pt.c (tsubst): Avoid creating pointer to reference and
+ reference to reference types.
-Tue Jan 10 01:49:25 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Sat Dec 6 01:29:37 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (pushtag): Stick the new decl in TYPE_NAME before pushing
- it.
+ * parse.y (do_id): New nonterminal.
+ (template_id): Use it.
- * typeck.c (build_component_ref): Don't build up a COMPONENT_REF
- when dealing with overloaded member functions; just act like
- build_offset_ref.
- (commonparms): Remove misleading comment.
+Fri Dec 5 01:17:34 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (duplicate_decls): Complain about repeated default
- arguments here.
- (redeclaration_error_message): Instead of here.
- (pushdecl): Complain about missing default arguments here.
- (grokparms): Instead of here.
- (lookup_name_current_level): Also match on DECL_ASSEMBLER_NAME.
- (grok_reference_init): Do not complain about missing initializer if
- declared 'extern'.
+ * parse.y (template_id): do_identifier for PFUNCNAMEs, too.
+ * spew.c (yylex): Don't do_identifier here.
+ * decl2.c (build_expr_from_tree): Revert last change.
- * search.c (lookup_field): Don't return a TYPE_DECL if there is a
- function alternative and want_type is not set.
+ * decl2.c (build_expr_from_tree): Expand the name for a method call.
+ * parse.y (object_template_id): Don't try to take the DECL_NAME.
-Mon Jan 9 18:16:23 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed Dec 3 20:02:39 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (pushtag): Don't set TYPE_NAME to an identifier. Do push
- the decl when the type has no TYPE_NAME.
- (lookup_nested_type): Don't assume that type has TYPE_NAME set.
- (lookup_name_real): Call lookup_field with want_type =
- prefer_type.
+ * init.c (build_new): Use a TARGET_EXPR instead of SAVE_EXPR for
+ alloc_expr.
+ * call.c (build_op_delete_call): Adjust.
- * search.c (lookup_field): Handle want_type properly in the presence
- of fields with the same name.
+ * except.c (expand_end_catch_block): Lose rethrow region.
+ (expand_start_catch_block): Likewise.
+ (expand_end_catch_block): Don't expand_leftover_cleanups.
- * decl.c (set_nested_typename): Set nested name for file-scope types
- to include leading ::.
- (pushdecl): Set the nested typename if the decl doesn't have one,
- rather than if the type's canonical decl doesn't have one.
+Wed Dec 3 13:24:04 1997 Benjamin Kosnik <bkoz@rhino.cygnus.com>
-Mon Jan 9 16:48:16 1995 Steve Chamberlain (sac@jonny.cygnus.com)
+ * pt.c (tsubst): Remove tree_cons call (places redundant info into
+ DECL_TEMPLATE_INSTANTIATION).
- * typeck.c (pointer_int_sum): Use offset size when calculating
- index expression.
+Wed Dec 3 11:44:52 1997 Jason Merrill <jason@yorick.cygnus.com>
-Mon Jan 9 03:44:33 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * tree.c (is_overloaded_fn): Handle getting a fn template.
+ (really_overloaded_fn): Likewise.
+ * error.c (dump_decl): Handle TEMPLATE_ID_EXPRs better.
+ * pt.c (check_explicit_specialization): Tweak.
+ (determine_explicit_specialization): Tweak.
- * typeck.c (convert_for_assignment): Complain about contravariance
- violation here.
- (comp_target_types): Instead of here.
- (build_unary_op): resolve_offset_ref before checking for a valid
- type.
+ * tree.c, cp-tree.h (get_target_expr): New fn.
- * spew.c (yylex): Decrement looking_for_typename after we see a
- _DEFN.
+Wed Dec 3 08:47:27 1997 Paul Eggert <eggert@twinsun.com>
- * decl.c (pushdecl): Don't install an artificial TYPE_DECL in
- IDENTIFIER_LOCAL_VALUE if we already have a decl with that name.
+ * pt.c (check_explicit_specialization): Fix misspelling in
+ diagnostic: `preceeded'.
+ * typeck.c (get_delta_difference): Fix misspelling in diagnostic:
+ `conversiona'.
- * typeck.c (convert_for_assignment): Converting pointers to bool
- does not need a cast.
+1997-12-02 Mark Mitchell <mmitchell@usa.net>
-Sun Jan 8 18:16:45 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * pt.c (determine_explicit_specialization): Avoid an internal
+ error for bad specializations.
- * class.c (instantiate_type): Initialize nsubsts parm.
+ * method.c (build_overload_value): Handle SCOPE_REF.
- * pt.c (do_function_instantiation): Ditto.
+Tue Dec 2 19:18:50 1997 Mike Stump <mrs@wrs.com>
-Sat Jan 7 14:37:05 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * class.c (prepare_fresh_vtable): Enable even more complex MI
+ vtable names.
- * pt.c (tsubst): Use TREE_STATIC instead of DECL_INLINE &&
- DECL_SAVED_INSNS to determine whether or not we've seen a definition
- of this function.
- (instantiate_template): Ditto.
+Tue Dec 2 01:37:19 1997 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (convert_harshness): Allow const reference binding when
- called from the overloading code, but not when called from
- can_convert (since it isn't a conversion).
- (convert_harshness): Put back some disabled code.
+ * exception.cc (__check_eh_spec): Optimize a bit.
-Fri Jan 6 14:10:57 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * exception.cc (__cp_pop_exception): Lose handler arg.
+ * except.c (do_pop_exception): Likewise.
+ (push_eh_cleanup): Let the cleanup mechanism supply the handler.
+ (expand_end_catch_block): Likewise.
- * call.c (convert_harshness): There is no implicit conversion from
- void* to other pointer types (unless the parameter is (void*)0).
- (convert_harshness): Non-lvalues do not convert to reference types.
+Fri Nov 28 01:58:14 1997 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct_methods): Still set
- TYPE_HAS_{INT,REAL}_CONVERSION.
+ * pt.c (check_explicit_specialization): Complain about using a
+ template-id for a non-specialization.
- * call.c (can_convert): Don't use aggregate initialization.
+Fri Nov 28 12:35:19 1997 Scott Christley <scottc@net-community.com>
- * cp-tree.h: Declare lookup_conversions.
+ * repo.c: Prototype rindex only if needed.
+ * xref.c: Likewise.
-Thu Jan 5 21:08:00 1995 Mike Stump <mrs@cygnus.com>
+Fri Nov 28 01:56:35 1997 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
- * parse.y (simple_stmt): Fix duplicate case value error messages to
- be more readable.
+ * error.c (dump_decl): Handle TEMPLATE_ID_EXPR.
-Wed Jan 4 16:44:19 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+Thu Nov 27 00:59:46 1997 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (build_type_conversion): Total rewrite to use
- convert_harshness instead of reproducing conversion logic here. Now
- much shorter.
+ * typeck.c (build_const_cast): Handle references here instead of
+ handing off to convert_to_reference.
- * call.c (convert_harshness): Support conversions to bool.
- (can_convert): Checks whether a conversion is less harsh
- than USER_CODE, for build_type_conversion.
+ * except.c: Lose Unexpected, SetTerminate, SetUnexpected,
+ TerminateFunctionCall.
+ (init_exception_processing): Likewise. Terminate et al are now
+ the fns, not ADDR_EXPRs.
+ (various): Lose redundant assemble_external calls.
+ (do_unwind): s/BuiltinReturnAddress/builtin_return_address_fndecl/.
- * search.c (add_conversions): Function for passing to dfs_walk which
- adds all the type conversion operators in the current type to a list.
- (lookup_conversions): Calls dfs_walk with add_conversions and return
- the list.
- (dfs_walk): Don't require a qfn.
+ * cp-tree.h (struct lang_decl_flags): Add comdat.
+ (DECL_COMDAT): New macro.
+ * decl.c (duplicate_decls): Propagate it.
+ (cp_finish_decl): Handle it.
+ * decl2.c (import_export_decl): Just set DECL_COMDAT on VAR_DECLs.
- * cp-tree.h: Lose CLASSTYPE_CONVERSIONS hackery.
- (CLASSTYPE_FIRST_CONVERSION): Points to elt 1 of CLASSTYPE_METHOD_VEC.
+ * class.c: Remove static pending_hard_virtuals.
+ (add_virtual_function): Take pointers to pending_virtuals
+ and pending_hard_virtuals.
+ (finish_struct_1): Pass them. Declare pending_hard_virtuals.
- * class.c (finish_struct_bits): Lose CLASSTYPE_CONVERSIONS hackery.
- (grow_method): A separate function for building onto the growing
- method vector.
- (finish_struct_methods): Use it. Put all type conversion operators
- right after the constructors. Perhaps we should sort the methods
- alphabetically?
+Wed Nov 26 20:28:49 1997 Jason Merrill <jason@yorick.cygnus.com>
-Mon Jan 2 14:42:58 1995 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (import_export_vtable): If we support one_only but not
+ weak symbols, mark instantiated template vtables one_only.
+ (import_export_decl): Likewise for tinfo functions.
+ (finish_vtable_vardecl): Also write out vtables from explicitly
+ instantiated template classes.
+ * pt.c (mark_class_instantiated): Revert last change.
- * call.c (build_method_call): Lose another misleading shortcut.
+ * except.c (expand_throw): Call mark_used on the destructor.
-Fri Dec 30 17:57:30 1994 Mike Stump <mrs@cygnus.com>
+Wed Nov 26 15:13:48 1997 Jeffrey A Law (law@cygnus.com)
- * gc.c (build_bltn_desc): Handle bool as a built-in type.
+ * lex.c (lang_init): Enable flag_exceptions by default if no
+ command line switch was specified.
-Fri Dec 30 14:20:21 1994 Mike Stump <mrs@cygnus.com>
+1997-11-26 Mark Mitchell <mmitchell@usa.net>
- * tree.c (layout_vbasetypes): Ensure that we don't loose alignment
- on the complete type because of small virtual bases.
+ * pt.c (unify): Handle `void' template parameters in
+ specializations.
-Fri Dec 30 12:22:29 1994 Mike Stump <mrs@cygnus.com>
+Wed Nov 26 01:11:24 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (n_incomplete): Bump n_incomplete up to int to match C
- front end.
- (pushdecl): Also count decls pushed that are of a type being defined
- as incomplete things.
- * class.c (finish_struct): Move hack_incomplete_structures up to
- just after we set it as not being defined, so that the decls we
- build for RTTI don't count as incomplete.
+ * rtti.c (build_dynamic_cast): Handle template case here.
+ (build_dynamic_cast_1): Not here.
-Thu Dec 29 18:20:57 1994 Mike Stump <mrs@cygnus.com>
+ * typeck2.c (digest_init): Make copies where appropriate.
- * pt.c (tsubst): Fix problem with defining constructors in templated
- classes with virtual bases.
+ * decl2.c (delete_sanity): resolve_offset_ref.
-Wed Dec 28 08:31:00 1994 Mike Stump <mrs@cygnus.com>
+ * except.c: Call terminate without caching so many bits.
- * parse.y (TYPEID): Strip top-level cv-qualifiers on typeid
- expressions.
- * gc.c (build_typeid): Ditto.
+ * except.c (expand_start_catch_block): Fix catching a reference
+ to pointer.
-Thu Dec 22 17:26:33 1994 Mike Stump <mrs@cygnus.com>
+Tue Nov 25 11:28:21 1997 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (build_up_reference): Fix breakage introduced on Nov 29,
- don't assert on complex AGGR inits.
+ * init.c (build_new): Copy size to the saveable obstack.
-Thu Dec 22 14:32:31 1994 Mike Stump <mrs@cygnus.com>
+ * init.c (build_new): Stick a CLEANUP_POINT_EXPR inside the
+ TRY_CATCH_EXPR for now.
- * method.c (build_overload_value): Handle pointer to members as
- template arguments.
+Mon Nov 24 12:15:55 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Dec 22 13:09:07 1994 Mike Stump <mrs@cygnus.com>
+ * typeck.c (mark_addressable): Don't assume a FUNCTION_DECL
+ has DECL_LANG_SPECIFIC.
- * typeck.c (unary_complex_lvalue): Don't call sorry if we know how
- to do take the address of a data member for a pointer to data
- member.
+ * exception.cc (struct cp_eh_info): Add handlers field.
+ (__cp_push_exception): Initialize it.
+ (__cp_pop_exception): Decrement it. Don't pop unless it's 0.
+ (__throw_bad_exception): Remove.
+ * except.c (call_eh_info): Add handlers field.
+ (get_eh_handlers): New fn.
+ (push_eh_cleanup): Increment handlers.
-Thu Dec 22 10:04:19 1994 Mike Stump <mrs@cygnus.com>
+Fri Nov 21 12:22:07 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokdeclarator): Use the typedef name for linkage if the
- type doesn't otherwise have a name.
+ * except.c (expand_start_eh_spec): Use the try/catch code.
+ (expand_end_eh_spec): Likewise. Call __check_eh_spec instead of
+ doing everything inline.
+ (init_exception_processing): throw_type_match now takes
+ const void pointers.
+ * exception.cc (__check_eh_spec): New fn.
+ * inc/exception: Neither terminate nor unexpected return.
+ * decl.c: Make const_ptr_type_node public.
+ * tinfo2.cc (__throw_type_match_rtti): Take the typeinfos constly.
- * decl2.c (grokfield): Ditto.
+ * except.c (expand_start_catch_block): We only need the rethrow
+ region for non-sjlj exceptions.
+ (expand_end_catch_block): Likewise. Use outer_context_label_stack.
- * class.c (finish_struct): Since we reuse the TYPE_DECL for the
- DECL_NAME of enums, structs and classes, we have to avoid trying to
- put it in the TYPE_FIELDS again.
+Thu Nov 20 14:40:17 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Dec 21 11:07:05 1994 Mike Stump <mrs@cygnus.com>
+ * Make-lang.in (CXX_LIB2FUNCS): Add new op new and op delete objs.
+ (various.o): Likewise.
+ * inc/new: Add placement deletes. Add throw specs for default new.
+ * new.cc (set_new_handler): Move here from libgcc2.
+ * new1.cc (new (nothrow)): Catch a bad_alloc thrown from the handler.
+ (new): Move from libgcc2. Throw bad_alloc.
+ * new2.cc: Move the rest of the op news and op deletes from libgcc2.
+ * decl.c (init_decl_processing): Update exception specs on new and
+ delete.
- * decl2.c (check_classfn): Ignore this parameter on static functions
- when checking to see if we match.
+ * method.c (build_decl_overload_real): Don't mess with global
+ placement delete.
-Tue Dec 20 17:47:02 1994 Mike Stump <mrs@cygnus.com>
+ * init.c (build_new): Check for null throw spec, not nothrow_t.
- * typeck.c (unary_complex_lvalue): Handle address of non-left most
- pointers to members by calling get_delta_difference.
+ * decl.c (duplicate_decls): Don't complain about different exceptions
+ from an internal declaration.
-Mon Dec 19 22:40:53 1994 Mike Stump <mrs@cygnus.com>
+ * call.c (build_op_delete_call): Fix check for member fns again.
- * decl2.c (check_classfn): Don't use decls_match yet, as it modifies
- static functions to early.
+ * decl2.c (import_export_decl): Interface hackery affects
+ virtual synthesized methods.
-Thu Dec 19 22:37:48 1994 Mike Stump <mrs@cygnus.com>
+Wed Nov 19 18:24:14 1997 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (make_thunk): Handle encoding of positive thunk offsets.
+ * decl.c (start_decl): Don't just complain about a mismatched
+ scope, fix it.
-Sat Dec 17 13:29:50 1994 Doug Evans <dje@canuck.cygnus.com>
+ * decl.c (make_implicit_typename): Handle case where t is not
+ actually from context.
+ * tree.c (get_type_decl): Lose identifier case.
+ * spew.c (yylex): Lose useless call to identifer_typedecl_value.
+ * parse.y (nonnested_type): Just use lookup_name.
+ (complex_type_name): Just use IDENTIFIER_GLOBAL_VALUE.
- * Make-lang.in (.PHONY): Tell GNU make C++ and c++ are phony targets.
+Wed Nov 19 11:45:07 1997 Michael Tiemann <tiemann@axon.cygnus.com>
-Thu Dec 15 16:32:12 1994 Mike Stump <mrs@cygnus.com>
+ * error.c (dump_function_name): Test DECL_LANG_SPECIFIC in case
+ T was built in C language context (for example, by
+ output_func_start_profiler).
- * decl2.c (check_classfn): Use decls_match to check if this has
- already been declared, as the DECL_ASSEMBLER_NAME may have been
- changed via asm("new_name").
- * decl.c (decls_match): Make public.
+Wed Nov 19 10:39:27 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Dec 15 15:17:55 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (make_implicit_typename): New fn.
+ (lookup_name_real): Use it. Use current_class_type as the context.
- * *.[chy] (expand_aggr_init) Add fourth argument to handle
- distinction between = init and (init) style of initializations.
- * *.[chy] (finish_decl): Add fifth argument to to handle
- distinction between = init and (init) style of initializations.
+Mon Nov 17 23:42:03 1997 Bruno Haible <haible@ilog.fr>
-Tue Dec 13 19:16:05 1994 Mike Stump <mrs@cygnus.com>
+ * pt.c (do_poplevel): Don't prohibit jumps into this contour.
- Fix some random `explicit' bugs.
+Mon Nov 17 02:01:28 1997 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (convert_to_reference): Add third parameter to
- convert_force.
- (convert_force): Ditto.
- * call.c (build_method_call): Ditto.
- * decl2.c (setup_vtbl_ptr): Ditto.
- * init.c (expand_virtual_init): Ditto.
- (build_member_call): Ditto.
- (build_delete): Ditto.
- (build_vbase_delete): Ditto.
- * typeck.c (build_component_addr): Ditto.
- (build_c_cast): Ditto.
- (build_modify_expr): Ditto.
- * cp-tree.h (CONV_NONCONVERTING): Ditto. Add so that we can
- distinguish the context in which the conversion appears. Add thrid
- argument to build_c_cast.
- * cvt.c (cp_convert): Pass whether or not we want to consider
- non-converting constructors down to build_method_call.
- * decl2.c (reparse_absdcl_as_casts): Add third argument to
- build_c_cast.
- * gc.c (build_m_desc): Ditto.
- * init.c (build_new): Ditto.
- * parse.y (expr_no_commas): Ditto.
- (primary): Ditto.
- * typeck.c (build_x_function_call): Ditto.
- (build_static_cast): Ditto.
- (build_reinterpret_cast): Ditto.
- (build_const_cast): Ditto.
- (build_c_cast): Ditto.
- (build_ptrmemfunc): Ditto.
- * typeck2.c (build_functional_cast): Ditto.
- * init.c (expand_aggr_init): Added LOOKUP_ONLYCONVERTING to
- expand_aggr_init_1 as inits are converted to the destination type.
+ * friend.c (do_friend): Warn about non-template friends in templates.
-Tue Dec 13 16:18:57 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (build_op_delete_call): Fix handling of inherited delete.
- * Make-lang.in (cc1plus): Depends on c-pragma.o.
+ * search.c (dfs_record_inheritance): Ignore template type parms.
- * Makefile.in (OBJ{DEP,}S): Add ../c-pragma.o.
+Sat Nov 15 00:30:51 1997 Jason Merrill <jason@yorick.cygnus.com>
- * lex.c (check_newline): If the #pragma is not recognized by g++,
- try machine-specific ones too.
- (handle_sysv_pragma): Copied from c-lex.c.
+ * call.c (build_new_op): Fix copy error.
+ (build_op_new_call): New fn.
+ (build_op_delete_call): New fn.
+ * cp-tree.h: Declare them.
+ * init.c (build_new): Use them. Support placement delete.
+ (build_x_delete): Use build_op_delete_call.
+ (build_delete): Likewise.
+ * decl2.c (delete_sanity): Likewise.
+ (coerce_delete_type): Don't complain about placement delete.
-Mon Dec 12 23:53:06 1994 Mike Stump <mrs@cygnus.com>
+Thu Nov 13 01:52:36 1997 Jason Merrill <jason@yorick.cygnus.com>
- * except.c (expand_throw): Fix Dec 6th change, build_new likes a
- reference better.
+ * call.c (build_new_function_call): Remove unused 'obj' parm.
+ * cp-tree.h, typeck.c: Adjust.
-Mon Dec 12 18:01:00 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+ * init.c (build_new): Make the cleanup last longer.
+ (expand_vec_init): Call do_pending_stack_adjust.
- * typeck.c (build_binary_op): Lose checks on TYPE_PTRMEMFUNC_P with
- IS_AGGR_TYPE, since now they will not both be set on the same type.
+Wed Nov 12 11:04:33 1997 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (do_pending_expansions): Don't clear TREE_PUBLIC on
- instantiations controlled by -fexternal-templates.
+ * pt.c (do_type_instantiation): Fix typo.
+ (mark_class_instantiated): If we support one_only but not weak
+ symbols, don't mark this as known.
- * decl.c (duplicate_decls): Don't complain about different values of
- __attribute__ ((const)) and ((noreturn)).
+ * init.c (build_new): Handle vec delete in EH cleanup.
-Fri Dec 9 18:17:37 1994 Doug Evans <dje@cygnus.com>
+Wed Nov 12 08:11:55 1997 Benjamin Kosnik <bkoz@rhino.cygnus.com>
- * Makefile.in (BISONFLAGS): Delete --yacc.
- (PARSE_H): Depend on $(PARSE_C), for parallel makes.
- (PARSE_C): Undo last patch.
+ * call.c (build_method_call): Call complete_type before checking
+ for destructor.
-Fri Dec 2 10:44:36 1994 Mike Stump (mrs@wombat.gnu.ai.mit.edu)
+Sun Nov 9 01:29:55 1997 Jim Wilson (wilson@cygnus.com)
- * Makefile.in (BISONFLAGS): Add --yacc so that output winds up in
- y.tab.c.
+ * decl.c (add_block_current_level): Delete.
+ * init.c (build_vec_delete_1): Delete build_block and
+ add_block_current_level calls.
-Thu Dec 8 17:39:46 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed Nov 12 00:48:16 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (finish_decl): Don't call obscure_complex_init for decls
- of indeterminate size.
+ * init.c (build_new): Handle freeing allocated memory when the
+ constructor throws.
-Wed Dec 7 16:49:22 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (build_new_method_call): Fix flags arg.
- * decl.c (obscure_complex_init): Function to tweak the decl to
- prevent expand_decl from tring to initialize it.
- (finish_decl): Use it rather than writing the same code in three
- different places.
+ * pt.c (do_type_instantiation): Don't try to instantiate
+ member templates.
+ (mark_decl_instantiated): If we support one_only but not
+ weak symbols, mark this one_only.
+ * decl2.c (import_export_vtable): Don't defer handling of vtables
+ if MULTIPLE_SYMBOL_SPACES.
- * parse.y (bad_parm): Stop trying to support parms without types.
+Tue Nov 11 12:02:12 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Dec 7 12:06:56 1994 Mike Stump <mrs@cygnus.com>
+ * except.c (expand_end_catch_block): Lose call to __sjpopnthrow.
- * decl2.c (grokfield): Make asm specs on static member functions
- work.
+Tue Nov 11 02:53:44 1997 Jason Merrill <jason@lasher.cygnus.com>
-Tue Dec 6 15:43:20 1994 Mike Stump <mrs@cygnus.com>
+ * except.c (do_pop_exception): Return a value.
- * except.c (expand_throw): Make a copy of the thrown object.
+Mon Nov 10 20:25:31 1997 Jason Merrill <jason@yorick.cygnus.com>
-Tue Dec 6 14:16:34 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+ * call.c (build_new_method_call): Handle getting a
+ TEMPLATE_ID_EXPR around a TEMPLATE_DECL. Don't look for a field
+ if we got template parms.
+ * typeck.c (build_x_function_call): Remember the TEMPLATE_ID_EXPR,
+ not just the args.
+ * decl2.c (build_expr_from_tree): Tweak last change.
+ * pt.c (tsubst_copy): Use get_first_fn instead of TREE_VALUE.
+ (maybe_fold_nontype_arg): Split out from tsubst_copy.
+ * tree.c (get_first_fn): Just return a TEMPLATE_ID_EXPR.
- * parse.y: : has lower precedence than =.
+Mon Nov 10 20:08:38 1997 Kriang Lerdsuwanakij <lerdsuwa@scf-fs.usc.edu>
-Tue Dec 6 12:46:17 1994 Mike Stump <mrs@cygnus.com>
+ * pt.c (tsubst_copy): Handle explicit template arguments in
+ function calls.
+ * typeck.c (build_x_function_call): Likewise.
+ * decl2.c (build_expr_from_tree): Lookup function name if it
+ hasn't been done.
- * decl.c (pushdecl): Use DECL_NAME of VAR_DECLs to avoid namespace
- manglings.
- (grokvardecl): Add namespace into variable name.
+ * pt.c (tsubst): Instantiate template functions properly when
+ template parameter does not appear in function arguments and return
+ type.
+ (comp_template_args): Handle member templates required by tsubst.
-Tue Dec 6 11:26:55 1994 Mike Stump <mrs@cygnus.com>
+Mon Nov 10 20:08:38 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (current_namespace_id): New routine to transform a simple
- name into a name in a namespace.
- * decl.c (grokdeclarator): Use it.
- * decl2.c (get_namespace_id): Find the name of the current
- namespace.
- (push_namespace, pop_namespace): Complete out missing
- functionality.
-
-Mon Dec 5 17:11:51 1994 Jason Merrill <jason@phydeaux.cygnus.com>
-
- * class.c (finish_struct): Don't use LONG_LONG_TYPE_SIZE, as it may
- not be defined. Fix warning message for enums and restore warning
- for non-enums.
-
- * decl2.c (push_namespace): Dummy function.
- (pop_namespace): Ditto.
- (do_namespace_alias): Ditto.
- (do_using_decl): Ditto.
- (do_using_directive): Ditto.
-
- * parse.y: New token NSNAME for namespace names.
- (extdef): Add namespace, using definitions.
- (using_decl): New rule for using declarations.
- (any_id): New rule for identifiers with any degree of scoping.
- (identifier): Add NSNAME.
- (notype_identifier): Ditto.
- (component_decl): Add using_decl.
- (nested_name_specifier): Add NSNAME SCOPE.
-
- * typeck.c (convert_for_assignment): Handle conversions between
- enums and bool.
-
- * decl.c (duplicate_decls): Only propagate DECL_MAIN_VARIANT on
- FUNCTION_DECLs.
+ * decl.c (grokdeclarator): Tweak conditions for pedwarn in
+ previous change.
-Mon Dec 5 13:03:16 1994 Mike Stump <mrs@cygnus.com>
+Mon Nov 10 20:08:29 1997 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
- * class.c (finish_struct): Give an error if one tries to declare a
- bit-field's size greater than a long long, as the backend will dump.
- It is not an error to declare an enum bit-field greater than its
- precision. Warn if an enum bit-field is too small to hold all
- its values.
+ * pt.c (coerce_template_parms): Tweak error message.
-Mon Dec 5 11:41:50 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (grokdeclarator): If -Wreturn-type, warn everytime a
+ return type defaults to `int', even if there are storage-class
+ specifiers.
- * typeck.c (convert_for_assignment): Use cp_convert instead of
- convert so that we don't get static casts.
+Mon Nov 10 03:04:20 1997 Jason Merrill <jason@yorick.cygnus.com>
-Sun Dec 4 11:59:01 1994 Mike Stump <mrs@cygnus.com>
+ Complete nested exception support.
+ * except.c (do_pop_exception): Split out...
+ (push_eh_cleanup): From here. Handle the EH region by hand.
+ (expand_start_catch_block): Add a new level for the catch parm.
+ Move the rethrow region outside the two cleanup regions.
+ Protect the initializer for the catch parm with terminate.
+ (expand_end_catch_block): Likewise. End the region for the eh_cleanup.
+ * exception.cc (__cp_pop_exception): Now takes two parms. Handle
+ popping off the middle of the stack.
+ * tree.c (lvalue_p, real_lvalue_p): Handle TRY_CATCH_EXPR,
+ WITH_CLEANUP_EXPR, and UNSAVE_EXPR.
+ (build_cplus_new): Only wrap CALL_EXPRs.
+ * init.c (expand_default_init): Handle a TRY_CATCH_EXPR around
+ the constructor call.
- * cvt.c (cp_convert): Don't complain about int->enum conversion if
- we are doing static casts.
+Sun Nov 9 18:00:26 1997 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
-Fri Dec 2 18:32:41 1994 Mike Stump <mrs@cygnus.com>
+ * Make-lang.in (c++.distdir): Make inc subdirectory.
- * error.c (dump_expr): Do something more intelligent with SAVE_EXPRs
- when dumping expressions in error messages.
+Fri Nov 7 11:57:28 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri Dec 2 17:04:27 1994 Mike Stump <mrs@cygnus.com>
+ * decl2.c (finish_file): Put back some code.
- * gc.c (build_dynamic_cast): Change interface to libg++, ensure that
- the return type is the right type, and make references work.
+Thu Nov 6 11:28:14 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri Dec 2 16:36:43 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl2.c (finish_file): Remove redundant code.
+ * method.c (emit_thunk): Don't let the backend defer generic thunks.
- * decl.c (poplevel): Don't be confused by function-scope
- declarations of non-nested functions.
- (duplicate_decls): Propagate DECL_MAIN_VARIANT.
- (pushdecl): Use duplicate_decls to copy info from old decl into new
- function-scope one rather than doing it here.
+Wed Nov 5 23:52:50 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (mark_inline_for_output): Deal with the DECL_MAIN_VARIANT
- of this decl, in case this is a function-scope declaration.
+ * except.c (call_eh_info): Split out...
+ (push_eh_info): From here.
+ (expand_builtin_throw): Use it.
+ (expand_start_catch_block): Move region start back.
- * decl.c (finish_enum): Make sure that the type has the right
- precision when we call fixup_*_type.
+Tue Nov 4 13:45:10 1997 Doug Evans <devans@canuck.cygnus.com>
-Tue Nov 29 19:12:07 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+ * lex.c (MULTIBYTE_CHARS): #undef if cross compiling.
+ (real_yylex): Record wide strings using target endianness, not host.
- * cvt.c (build_up_reference): Strip superfluous NOP_EXPRs; we do
- want to build up references to rvalues if possible.
- (cp_convert): Stick on a NOP_EXPR when converting to the same type.
+1997-11-03 Brendan Kehoe <brendan@lisa.cygnus.com>
-Tue Nov 29 11:28:59 1994 Mike Stump <mrs@cygnus.com>
+ * repo.c (rindex): Add decl unconditionally.
+ (get_base_filename, open_repo_file): Don't cast rindex.
+ * xref.c (rindex): Add decl unconditionally.
+ (index): Remove unused decl.
+ (open_xref_file): Don't cast rindex.
- * parse.y (maybe_raises): Handle throw ().
- * parse.y (ansi_raise_identifier): grok type-ids in exception
- specifications.
- * tree.c (build_exception_variant): Use list compare to check if
- two exception specifications match.
- * decl.c (duplicate_decls, bad_specifiers): Enhance wording on error
- messages.
- * call.c (build_method_call): Remove TREE_RAISES.
- * cvt.c (convert_to_aggr): Ditto.
- * typeck.c (build_function_call_real, convert_arguments): Ditto.
- * init.c (expand_aggr_init_1): Ditto.
+Sun Nov 2 15:04:12 1997 Jason Merrill <jason@yorick.cygnus.com>
-Tue Nov 29 09:50:39 1994 Mike Stump <mrs@cygnus.com>
+ * class.c (build_vbase_path): Propagate the result type properly.
- * except.c: Add support for m68k and mips exception handling
- support.
+1997-11-01 Brendan Kehoe <brendan@lisa.cygnus.com>
-Tue Nov 29 08:48:33 1994 Mike Stump <mrs@cygnus.com>
+ * except.c (expand_builtin_throw) [!DWARF2_UNWIND_INFO]: Replace
+ remaining use of saved_throw_type with a call to get_eh_type.
- * except.c (expand_end_all_catch): Throw into outer context, if we
- fall off end of catch handlers.
+1997-10-31 Brendan Kehoe <brendan@lisa.cygnus.com>
-Mon Nov 28 16:44:41 1994 Mike Stump <mrs@cygnus.com>
+ * lex.c (FILE_NAME_NONDIRECTORY): Delete macro.
+ (file_name_nondirectory): New function, doing the same as the macro.
+ (set_typedecl_interface_info): Use it instead of the macro.
+ (check_newline): Likewise.
+ (handle_cp_pragma): Likewise.
- * Makefile.in: Make is easier to decide where parse.[ch] will be
- built.
+ * repo.c (get_base_filename): Cast result of rindex to char*.
+ (open_repo_file): Likewise.
+ * xref.c (open_xref_file): Likewise.
+ * error.c (dump_char): Make its arg int, not char.
-Thu Nov 17 20:11:24 1994 Doug Evans <dje@cygnus.com>
+ * except.c (push_eh_info): Pass the number of fields - 1 down, not
+ the exact number of fields.
- * cp/Make-lang.in (CXX_INSTALL_NAME) Use program_transform_name.
- (GXX_INSTALL_NAME) Likewise.
- (CXX_CROSS_NAME) Use program_transform_cross_name.
- (GXX_CROSS_NAME) Likewise.
- (c++.install-man): Use program_transform_name on g++.1.
- (c++.uninstall): Likewise.
+Fri Oct 31 01:47:57 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Nov 3 18:48:19 1994 Paul Eggert <eggert@twinsun.com>
+ Support for nested exceptions.
+ * tinfo2.cc (__is_pointer): New fn.
+ * exception.cc (struct cp_eh_info): Define.
+ (__cp_exception_info, __uncatch_exception): New fns.
+ (__cp_push_exception, __cp_pop_exception): New fns.
+ * except.c: Lose saved_throw_{type,value,cleanup,in_catch}.
+ Lose empty_fndecl.
+ (init_exception_processing): Likewise. __eh_pc is now external.
+ (push_eh_info): New fn.
+ (get_eh_{info,value,type,caught}): New fns.
+ (push_eh_cleanup): Just call __cp_pop_exception.
+ (expand_start_catch_block): Use push_eh_info. Start the eh region
+ sooner.
+ (expand_end_eh_spec): Use push_eh_info.
+ (expand_throw): Call __cp_push_exception to set up the exception info.
+ Just pass the destructor or 0 as the cleanup. Call __uncatch_exception
+ when we rethrow.
+ (expand_builtin_throw): Don't refer to empty_fndecl.
- * Makefile.in (spew.o, lex.o, pt.o):
- Depend on $(srcdir)/parse.h, not parse.h.
+Thu Oct 23 02:01:30 1997 Jason Merrill <jason@yorick.cygnus.com>
-Mon Nov 28 13:53:03 1994 Mike Stump <mrs@cygnus.com>
+ * pt.c (instantiate_decl): SET_DECL_IMPLICIT_INSTANTIATION on new decl.
- * parse.y (THROW): Fix precedence of throw expressions.
+1997-10-22 Brendan Kehoe <brendan@cygnus.com>
-Mon Nov 28 13:15:16 1994 Mike Stump <mrs@cygnus.com>
+ * method.c (build_template_parm_names, build_decl_overload_real):
+ Add static to definitions.
+ * pt.c (add_to_template_args, note_template_header,
+ processing_explicit_specialization, type_unification_real): Likewise.
+ ({determine,check}_explicit_specialization): Use a single string for
+ error messages.
- * typeck.c (build_unary_op): Allow promotions from bool to int on
- unary ~.
+Mon Oct 20 12:06:34 1997 Jason Merrill <jason@yorick.cygnus.com>
-Sun Nov 27 00:16:21 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+ * except.c (expand_exception_blocks): Call do_pending_stack_adust.
+ (expand_end_catch_block): Likewise.
+ (expand_end_eh_spec): Likewise.
- * method.c (build_overload_name): Use DECL_ASSEMBLER_NAME for
- classes when appropriate.
- (build_overload_nested_name): When dealing with a function context,
- use ASM_FORMAT_PRIVATE_NAME to tweak the name of the function to
- avoid conflicts between local classes of the same name.
+Mon Oct 20 11:44:20 1997 Mark Mitchell <mmitchell@usa.net>
-Wed Nov 23 17:59:42 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (duplicate_decls): Handle template specializations
+ correctly.
+ * error.c (dump_function_name): Fix printing of specializations of
+ member functions that are not member templates.
+ * cp-tree.h (processing_specialization): Make global.
+ * pt.c (processing_specialization): Likewise.
+ * lex.c (cons_up_default_function): Save and restore
+ processing_specialization to avoid confusion.
+
+Mon Oct 20 10:52:22 1997 Jason Merrill <jason@yorick.cygnus.com>
- * gxx.gperf, parse.y, lex.h, hash.h, lex.c (init_lex), delc.c
- (duplicate_decls, grokdeclarator), cp-tree.h: Add support for
- `explicit'.
- * cvt.c (convert_to_reference, cp_convert, build_type_conversion_1,
- build_type_conversion): Use LOOKUP_ONLYCONVERTING in
- build_method_calls so that non-converting constructors are not used.
- * call.c (build_method_call): If we shouldn't use a non-converting
- constructor, then don't.
+ * decl.c (init_decl_processing): Give null_node unknown* type.
+ * typeck.c (comp_target_types): Handle UNKNOWN_TYPE.
+ (common_type): Likewise.
+ * error.c (args_as_string): Recognize null_node.
-Wed Nov 23 14:46:56 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+Sun Oct 19 09:13:01 1997 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
- * call.c (build_method_call): Don't try to synthesize methods yet.
+ * typeck.c (rationalize_conditional_expr): Handle {MIN,MAX}_EXPR.
+ (unary_complex_lvalue): Call it for {MIN,MAX}_EXPR.
-Tue Nov 22 12:45:21 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (init_decl_processing): Call using_eh_for_cleanups.
- * pt.c (push_template_decls): Create CONST_DECLs for template
- constant parameters, not VAR_DECLs.
+ * Make-lang.in (g++): Include prefix.o.
-Sat Nov 19 15:28:31 1994 Jim Wilson (wilson@chestnut.cygnus.com)
+Thu Oct 16 15:31:09 1997 Judy Goldberg <judygold@sanwafp.com>
- * typeck.c (build_binary_op_nodefault): Can shorten shift only if
- shift count is less than size in bits of arg0.
+ * pt.c (determine_explicit_specialization): Initialize "dummy"
+ to keep Purify quiet.
-Thu Nov 17 15:30:50 1994 Mike Stump <mrs@cygnus.com>
+Thu Oct 16 00:14:48 1997 Jason Merrill <jason@yorick.cygnus.com>
- * gxx.gperf, hash.h, lex.c (init_lex, real_yylex), parse.y: Add new
- ANSI keywords and, and_eq, bitand, bitor, explicit, namespace, not,
- not_eq, or, or_eq, typename, using, xor, xor_eq to g++. Still need
- to add support for explicit, namespace, typename, and using, support
- for the rest is already in.
+ * method.c (build_overload_value): Handle TEMPLATE_CONST_PARMs here.
+ (build_overload_int): Not here.
-Thu Nov 17 10:56:50 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+Wed Oct 15 00:35:28 1997 Mike Stump <mrs@wrs.com>
- * typeck2.c (build_m_component_ref): Check the basetype of the
- member pointer against the main variant of the object type.
+ * class.c (build_type_pathname): Remove.
+ (prepare_fresh_vtable): Fix problem with complex MI vtable names.
-Mon Nov 14 14:21:52 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+1997-10-14 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cvt.c (convert_to_reference): Make sure that the original expr
- gets its type back when converting a reference.
+ * parse.y (unary_expr): Give a pedwarn if someone tries to use the
+ &&label GNU extension.
- * method.c (build_overload_name): Clear numeric_outputed_need_bar here.
- (build_decl_overload): Instead of here.
+Tue Oct 14 12:01:00 1997 Mark Mitchell <mmitchell@usa.net>
-Tue Nov 8 17:11:24 1994 Jason Merrill <jason@phydeaux.cygnus.com>
+ * decl.c (pushtag): Unset DECL_ASSEMBLER_NAME before setting it,
+ so as to avoid incorrect manglings.
+ * method.c (build_decl_overload_real): Don't mangle return types
+ for constructors.
+
+Tue Oct 14 11:46:14 1997 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (cp_convert): Don't build a TARGET_EXPR if we're not in a
- function.
+ * cp-tree.h (scratchalloc, build_scratch_list, make_scratch_vec,
+ scratch_tree_cons): Define as macros for now.
+ * call.c, class.c, cvt.c, decl.c, decl2.c, except.c, expr.c, init.c,
+ lex.c, method.c, parse.y, pt.c, rtti.c, search.c, tree.c, typeck.c,
+ typeck2.c: Use them and the expression_obstack variants.
- * typeck.c (convert_for_initialization): Handle initialization from
- a TARGET_EXPR.
+Mon Oct 13 17:41:26 1997 Benjamin Kosnik <bkoz@rhino.cygnus.com>
-Sun Nov 6 01:34:24 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * decl.c (store_return_init): Allow classes with explicit ctors to
+ be used with the named return values extension.
- * pt.c (lookup_nested_type_by_name): Fix list-walking logic.
- (tsubst): When replacing a TEMPLATE_TYPE_PARM, propagate
- TYPE_READONLY and TYPE_VOLATILE from the argument.
- (unify): When unifying with a TEMPLATE_TYPE_PARM, remove cv-quals
- present in parm from arg.
- (type_unification): Strip REFERENCE_TYPE from the argument type.
- (unify): Don't strip REFERENCE_TYPE from the argument type.
+Fri Oct 10 12:21:11 1997 Jason Merrill <jason@yorick.cygnus.com>
-Sat Nov 5 22:42:15 1994 Greg McGary (gkm@magilla.cichlid.com)
+ * pt.c (instantiate_decl): Fix previous change.
- * pt.c (do_type_instantiation): Check to see if there's a
- IDENTIFIER_TEMPLATE on a class before calling
- instantiate_member_templates().
+Thu Oct 9 12:08:21 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri Nov 4 19:04:18 1994 Mike Stump <mrs@cygnus.com>
+ * pt.c (tsubst): Fix thinko.
+ (instantiate_decl): Really use the original template.
- * gc.c (get_bad_cast_node): New routine to support compile time
- throws of bad_cast.
- * gc.c (build_dynamic_cast): Support throwing of bad_cast at compile
- time.
+ * call.c (build_new_method_call): Use simple constructor_name for
+ error messages.
-Fri Nov 4 11:12:00 1994 Mike Stump <mrs@cygnus.com>
+Wed Oct 8 22:44:42 1997 Jeffrey A Law (law@cygnus.com)
- * except.c: Add hppa support.
+ * method.c (build_underscore_int): Don't use ANSI specific
+ features.
-Fri Nov 4 10:50:50 1994 Mike Stump <mrs@cygnus.com>
+Wed Oct 8 00:18:22 1997 Jason Merrill <jason@yorick.cygnus.com>
- * except.c: Add rs6000 support.
+ * decl2.c (finish_prevtable_vardecl): Check DECL_REALLY_EXTERN
+ for our key method; it might have been inlined by -O3.
-Thu Nov 3 14:24:23 1994 Mike Stump <mrs@cygnus.com>
+Tue Oct 7 23:00:12 1997 Mark Mitchell <mmitchell@usa.net>
- * except.c (do_unwind): Add i[34]86 support.
+ * decl.c (make_typename_type): Do not try to call lookup_field for
+ non-aggregate types.
-Thu Nov 3 00:10:46 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+Tue Oct 7 22:52:10 1997 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (do_pending_expansions): Unset TREE_PUBLIC on implicit
- instantiations.
+ * typeck.c (build_reinterpret_cast): Tweak.
-Wed Nov 2 15:08:24 1994 Kung Hsu (kung@mexican.cygnus.com)
+Tue Oct 7 22:45:31 1997 Alexandre Oliva <oliva@dcc.unicamp.br>
- * decl.c (finish_function): emit types used in method parameters
- into symbol table.
+ * typeck.c (build_reinterpret_cast): converting a void pointer
+ to function pointer with a reinterpret_cast produces a warning
+ if -pedantic is issued
-Wed Nov 2 15:05:47 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+Tue Oct 7 22:43:43 1997 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
- * pt.c (process_template_parm): Allow pointer to member function
- template parameter types.
- (uses_template_parms): Handle pointer to member function
- CONSTRUCTORs.
+ * typeck.c (c_expand_return): Don't warn about returning a
+ reference-type variable as a reference.
- * g++.c (main): Cast first argument of bzero to (char *).
- Pass -lstdc++ instead of -lg++ unless we are invoked as 'g++'.
+Tue Oct 7 21:11:22 1997 Jason Merrill <jason@yorick.cygnus.com>
-Mon Oct 31 14:50:48 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * method.c (build_static_name): Fix typo.
- * gc.c (build_dynamic_cast): rewrite to make it work.
- * class.c (finish_vtbls): build more vtables if flag_rtti is on.
- * class.c (modify_all_direct_vtables): ditto.
- * init.c (expand_direct_vtbls_init): expand more vtables if
- flag_rtti is on.
- * decl.c (init_type_desc): add default return.
+1997-10-07 Brendan Kehoe <brendan@lisa.cygnus.com>
-Tue Oct 25 17:13:09 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * decl.c (duplicate_decls): Make sure DECL_LANG_SPECIFIC is set on
+ OLDDECL before we try to do DECL_USE_TEMPLATE.
- * tree.c (debug_binfo): get rid of the initial size entry of
- vtable.
- * cp-tree.h: change flag_dossier to flag rtti, define type
- descriptor type nodes.
- * decl.c (init_type_desc): new function to initialize type
- descriptor type nodes.
- * decl.c (record_builtin_type): change flag_dossier to flag_rtti.
- * lex.c (init_lex): ditto.
- * decl.c : change variable flag_dossier to flag_rtti.
- * decl.c (duplicate_decls): get rid initial size entry of vtable.
- * decl.c (hack_incomplete_structures): take out assert 164.
- * search.c (get_abstract_virtuals_1): ditto.
- * search.c (dfs_init_vbase_pointers): change CLASSTYPE_DOSSIER to
- CLASSTYPE_RTTI.
- * parse.y: ditto.
- * class.c (prepare_fresh_vtable): for virtual bases, get right
- offset.
- * class.c (add_virtual_function): change flag_dossier to
- flag_rtti.
- * class.c (modify_one_vtable): modify the right rtti entry.
- * class.c (override_one_vtable): get rid of size entry.
- * class.c (finish_struct): change flag_dossier to flag_rtti, and
- build extra vtables, build type descriptors for polymorphic
- classes.
- * gc.c (build_headof): make headof() works correctly with new
- rtti.
- * gc.c (build_typeid): make this function work with new rtti.
- * gc.c (get_typeid): make this function work with new rtti.
- * gc.c (build_bltn_desc): new function for new rtti.
- * gc.c (build_user_desc): ditto.
- * gc.c (build_class_desc): ditto.
- * gc.c (build_ptr_desc): ditto.
- * gc.c (build_attr_desc): ditto.
- * gc.c (build_func_desc): ditto.
- * gc.c (build_ptmf_desc): ditto.
- * gc.c (build_ptmd_desc): ditto.
- * gc.c (build_t_desc): ditto.
- * gc.c : comment out old build_t_desc, build_i_desc, build_m_desc.
+Tue Oct 7 00:48:36 1997 Jason Merrill <jason@yorick.cygnus.com>
-Tue Oct 25 13:37:41 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * decl.c (duplicate_decls): Don't warn about template instances.
- * call.c (convert_harshness): Check for TREE_UNSIGNED differences
- after checking for integral conversions.
+ * typeck.c (mark_addressable): Lose ancient code that unsets
+ DECL_EXTERNAL.
-Sun Oct 23 13:19:55 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * pt.c (do_decl_instantiation): Lose support for instantiating
+ non-templates.
- * decl2.c: Declare flag_access_control.
- (struct lang_f_options): Add access-control.
- * expr.c (cplus_expand_expr, NEW_EXPR): Unset flag_access_control
- for the call to expand_aggr_init to copy the object out of the
- pcc_struct_return slot.
- * search.c (compute_access): if (!flag_access_control) return
- access_public.
+ * call.c (build_new_function_call): Fix handling of null explicit
+ template args.
+ (build_new_method_call): Likewise.
-Fri Oct 21 00:32:54 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+Mon Oct 6 23:44:34 1997 Mark Mitchell <mmitchell@usa.net>
- * lex.c (cons_up_default_function): Don't try to defer method
- synthesis now.
+ * method.c (build_underscore_int): Fix typo.
- * decl.c (init_decl_processing): Use __pure_virtual for abort_fndecl
- instead of abort, since the OSF/1 dynamic linker doesn't like to see
- relocation entries for abort.
+1997-10-06 Brendan Kehoe <brendan@lisa.cygnus.com>
- * tree.c (array_type_nelts_total): Use sizetype, not
- integer_type_node.
- (array_type_nelts_top): Ditto.
+ * tree.c (print_lang_statistics): #if 0 call to
+ print_inline_obstack_statistics until its definition is checked in.
-Thu Oct 20 15:48:27 1994 Mike Stump <mrs@cygnus.com>
+Mon Oct 6 09:27:29 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokdeclarator): Added handling for catch parameters
- (CATCHPARM).
- * except.c (expand_start_catch_block): Use the new CATCHPARM context
- instead of NORMAL.
- * except.c (expand_throw): Don't let convert_to_reference complain
- about what we are doing.
+ * decl2.c (finish_file): Move dump_tree_statistics to end.
-Thu Oct 20 12:55:24 1994 Jim Wilson (wilson@cygnus.com)
+ * pt.c (instantiate_decl): Look for the original template.
+ (tsubst): Set DECL_IMPLICIT_INSTANTIATION on partial instantiations
+ of member templates.
- * method.c (emit_thunk): Call instantiate_virtual_regs.
+Wed Oct 1 08:41:38 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Oct 19 14:15:33 1994 Mike Stump <mrs@cygnus.com>
+ * Makefile.in (g++FAQ.*): New rules.
+ (CONFLICTS): Update.
+ * g++FAQ.texi: Moved from libg++.
- * except.c (expand_exception_blocks): Make sure throw code doesn't
- get put in function that won't be output.
+ * parse.y (PFUNCNAME): Only specify the type once.
-Mon Oct 17 18:03:15 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+1997-10-01 Brendan Kehoe <brendan@lasher.cygnus.com>
- * decl.c (init_decl_processing): Make alloca a builtin.
+ * lex.c (real_yylex): Clean up the code to fully behave the way
+ the c-lex.c parser does for complex and real numbers.
-Thu Oct 27 21:10:25 1994 Craig Burley (craig@burley)
+Tue Sep 30 08:51:36 1997 Jason Merrill <jason@yorick.cygnus.com>
- * g++.c (main): Only decrement "added" and set "library" to
- NULL when "library" != NULL (just like 940829 fix).
+ * method.c (build_decl_overload_real): Reformat.
-Mon Oct 17 15:56:11 1994 Mike Stump <mrs@cygnus.com>
+Tue Sep 30 00:18:26 1997 Jason Merrill <jason@yorick.cygnus.com>
- * except.c (expand_start_catch_block): Make sure the false label
- gets onto the permanent obstack, as it is used for the exception
- table.
+ * method.c (synthesize_method): If at_eof, determine our linkage.
-Fri Oct 14 18:54:48 1994 Mike Stump <mrs@cygnus.com>
+1997-09-29 Paul Eggert <eggert@twinsun.com>
- * class.c (modify_one_vtable): Since the DECL_CONTEXT of fndecl can
- be set just below, use current_fndecl instead.
+ * lex.c (real_yylex): Treat `$' just like `_', except issue a
+ diagnostic if !dollars_in_ident or if pedantic.
-Fri Oct 14 15:12:22 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * lang-specs.h (@c++): -ansi no longer implies -$.
- * init.c (expand_aggr_vbase_init_1): Don't call expand_aggr_init_1
- with LOOKUP_SPECULATIVELY.
- (expand_default_init): Abort if build_method_call returns NULL_TREE.
+ * decl2.c (lang_decode_option):
+ -traditional and -ansi now do not mess with
+ dollars_in_ident.
- * typeck.c (build_modify_expr): Don't just build a MODIFY_EXPR if
- the rhs is a TARGET_EXPR.
+Mon Sep 29 19:57:51 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
- * parse.y (left_curly): Anonymous types are not affected by #pragma
- interface/implementation.
+ * Makefile.in (parse.o, decl.o): Also depend on
+ $(srcdir)/../except.h $(srcdir)/../output.h.
+ (decl2.o): Also depend on $(srcdir)/../expr.h ../insn-codes.h
+ $(srcdir)/../except.h $(srcdir)/../output.h.
+ (typeck.o, init.o): Also depend on $(srcdir)/../expr.h
+ ../insn-codes.h.
- * method.c (synthesize_method): Don't call setup_vtbl_ptr for the
- default constructor if it isn't needed.
+ * call.c, cp-tree.h, decl.c, tree.c: Finish prototyping.
- * lex.c (cons_up_default_function): Do synthesize methods for
- anonymous types if necessary.
+ * expr.c (cplus_expand_expr): Make it static.
-Thu Oct 13 17:44:55 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * decl2.c, init.c, typeck.c: Include "expr.h".
+ (expand_expr): Use proper values when calling the function.
- * method.c (build_decl_overload): Set numeric_outputed_need_bar to 0.
+Mon Sep 29 11:05:54 1997 Alexandre Oliva <oliva@dcc.unicamp.br>
-Wed Oct 12 13:27:57 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * lang-options.h: new -Wold-style-cast flag.
+ * cp-tree.h (warn_old_style_cast): new variable.
+ * decl2.c (warn_old_style_cast): ditto.
+ (lang_decode_option): support -Wold-style-cast.
+ (reparse_absdcl_as_casts): produce old-style-cast warning.
- * typeck.c (build_modify_expr): Understand how to copy an aggregate.
+Mon Sep 29 09:20:53 1997 Benjamin Kosnik <bkoz@rhino.cygnus.com>
- * init.c (expand_default_init): Ditto. Also remove some of the
- crufty code that assumes methods will not be synthesized properly.
+ * decl.c (cp_finish_decl): Allow expand_aggr_init to set
+ TREE_USED, reset value based on already_used.
- * lex.c (cons_up_default_function): If the containing type has no
- name, these functions should never need to be called, so just
- declare them.
+ * init.c (expand_member_init): Revert change.
+
+Mon Sep 29 08:57:53 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * cp-tree.h, decl.c, decl2.c, pt.c:
+ Lose DECL_C_STATIC and DECL_PUBLIC. Don't pretend statics are public.
+
+ * decl2.c (lang_decode_option): Add missing ;.
+
+Sat Sep 27 16:22:48 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * friend.c (do_friend): Disable injection for all template-derived
+ decls.
+ * decl2.c (lang_decode_option): Handle -fguiding-decls.
+ * parse.y (notype_template_declarator): New nonterminal.
+ (direct_notype_declarator): Use it.
+ (complex_direct_notype_declarator): Likewise.
+ (object_template_id): Accept any kind of identifier after TEMPLATE.
+ (notype_qualified_id): Don't add template declarators here.
+
+Sat Sep 27 16:21:58 1997 Mark Mitchell <mmitchell@usa.net>
+
+ * call.c (add_template_candidate): Add explicit_targs parameter.
+ (build_scoped_method_call): Use it.
+ (build_overload_call_real): Likewise.
+ (build_user_type_conversion_1): Likewise.
+ (build_new_function_call): Likewise.
+ (build_object_call): Likewise.
+ (build_new_op): Likewise.
+ (build_new_method_call): Likewise.
+ (build_new_function_call): Handle TEMPLATE_ID_EXPR.
+ (build_new_method_call): Likewise.
+
+ * class.c (finish_struct_methods): Add specialization pass to
+ determine which methods were specializing which other methods.
+ (instantiate_type): Handle TEMPLATE_ID_EXPR.
+
+ * cp-tree.def (TEMPLATE_ID_EXPR): New tree code.
+
+ * cp-tree.h (name_mangling_version): New variable.
+ (flag_guiding_decls): Likewise.
+ (build_template_decl_overload): New function.
+ (begin_specialization): Likewise.
+ (reset_specialization): Likewise.
+ (end_specialization): Likewise.
+ (determine_explicit_specialization): Likewise.
+ (check_explicit_specialization): Likewise.
+ (lookup_template_function): Likewise.
+ (fn_type_unification): Add explicit_targs parameter.
+ (type_unification): Likewise.
+
+ * decl.c (duplicate_decls): Add smarts for explicit
+ specializations.
+ (grokdeclarator): Handle TEMPLATE_ID_EXPR, and function
+ specializations.
+ (grokfndecl): Call check_explicit_specialization.
+
+ * decl2.c (lang_decode_option): Handle -fname-mangling-version.
+ (build_expr_from_tree): Handle TEMPLATE_ID_EXPR.
+ (check_classfn): Handle specializations.
+
+ * error.c (dump_function_name): Print specialization arguments.
+
+ * friend.c (do_friend): Don't call pushdecl for template
+ instantiations.
+
+ * init.c (build_member_call): Handle TEMPLATE_ID_EXPR.
+
+ * lang-options.h: Add -fname-mangling-version, -fguiding-decls,
+ and -fno-guiding-decls.
+
+ * lex.c (identifier_type): Return PFUNCNAME for template function
+ names.
+
+ * method.c (build_decl_overload_real): New function.
+ (build_template_parm_names): New function.
+ (build_overload_identifier): Use it.
+ (build_underscore_int): New function.
+ (build_overload_int): Use it. Add levels for template
+ parameters.
+ (build_overload_name): Likewise. Also, handle TYPENAME_TYPEs.
+ (build_overload_nested_names): Handle template type parameters.
+ (build_template_decl_overload): New function.
+
+ * parse.y (YYSTYPE): New ntype member.
+ (nested_name_specifier): Use it.
+ (nested_name_specifier_1): Likewise.
+ (PFUNCNAME): New token.
+ (template_id, object_template_id): New non-terminals.
+ (template_parm_list): Note specializations.
+ (template_def): Likewise.
+ (structsp): Likewise.
+ (fn.def2): Handle member template specializations.
+ (component_decl_1): Likewise.
+ (direct_notype_declarator): Handle template-ids.
+ (component_decl_1): Likewise.
+ (direct_notype_declarator): Handle template-ids.
+ (primary): Handle TEMPLATE_ID_EXPR, and template-ids.
+
+ * pt.c (processing_specializations): New variable.
+ (template_header_count): Likewise.
+ (type_unification_real): New function.
+ (processing_explicit_specialization): Likewise.
+ (note_template_header): Likewise.
+ (is_member_template): Handle specializations.
+ (end_template_decl): Call reset_specialization.
+ (push_template_decl): Handle member template specializations.
+ (tsubst): Likewise.
+ (tsubst_copy): Handle TEMPLATE_ID_EXPR.
+ (instantiate_template): Handle specializations.
+ (instantiate_decl): Likewise.
+ (fn_type_unification): Handle explicit_targs.
+ (type_unification): Likewise. Allow incomplete unification
+ without an error message, if allow_incomplete.
+ (get_bindings): Use new calling sequence for fn_type_unification.
+
+ * spew.c (yylex): Handle PFUNCNAME.
+
+ * tree.c (is_overloaded_fn): Handle TEMPLATE_ID_EXPR.
+ (really_overloaded_fn): Likewise.
+ (get_first_fn): Handle function templates.
+
+ * typeck.c (build_x_function_call): Use really_overloaded_fn.
+ Handle TEMPLATE_ID_EXPR.
+ (build_x_unary_op): Likewise.
+ (build_unary_op): Likewise.
+ (mark_addressable): Templates whose address is taken are marked
+ as used.
+
+1997-09-25 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * decl.c (init_decl_processing): Declare __builtin_constant_p as
+ accepting any kind of type, not only int.
+
+Fri Sep 26 00:22:56 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * search.c (get_matching_virtual): Notice virtual bases when sorrying
+ about covariant returns.
+
+ * parse.y (member_init): Also imply typename here. Remove ancient
+ extension for initializing base members.
+
+Thu Sep 25 11:11:13 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ Handle multi-level typenames and implicit typename in base list.
+ * parse.y (typename_sub{,[0-2]}): New rules.
+ (structsp, rule TYPENAME_KEYWORD): Use typename_sub.
+ (nonnested_type): New rule.
+ (complete_type_name): Use it.
+ (base_class.1): Use typename_sub and nonnested_type.
+ (nested_name_specifier): Don't elide std:: here.
+ * decl.c (make_typename_type): Handle getting a type for NAME.
+ (lookup_name_real): Turn std:: into :: here.
+
+ Rvalue conversions were removed in London.
+ * call.c (is_subseq): Don't consider lvalue transformations.
+ (build_conv): LVALUE_CONV and RVALUE_CONV get IDENTITY_RANK.
+ (joust): Reenable ?: kludge.
+
+1997-09-22 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * decl.c (start_function): Up warning of no return type to be a
+ pedwarn.
+
+Mon Sep 22 14:15:34 1997 Benjamin Kosnik <bkoz@rhino.cygnus.com>
+
+ * init.c (expand_member_init): Don't set TREE_USED.
+ * decl.c (cp_finish_decl): Mark decls used if type has TREE_USED
+ set,don't clear TREE_USED wholesale.
+
+Sat Sep 20 15:31:00 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * call.c (build_over_call): Do require_complete_type before
+ build_cplus_new.
- * lex.c (real_yylex): Use HOST_BITS_PER_WIDE_INT to determine the
- bitmask for lexing character constants.
+Thu Sep 18 16:47:52 1997 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_method_call): Disable code that tries to do tricky
- stuff with a default parameter that is a constructor call, but
- actually does other tricky stuff that breaks things.
+ * search.c (lookup_field): Call complete_type in all cases.
-Wed Oct 12 16:14:01 1994 Benoit Belley <belley@cae.ca>
+ * decl.c (finish_function): Just warn about flowing off the end.
- * decl.c (finish_enum): Disable code which forces enums to be signed,
- since this conflicts with their use as bitfields. type_promotes_to
- handles promotion of enums of underlying unsigned types to signed
- integer types.
+Wed Sep 17 10:31:25 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Oct 12 13:24:03 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * decl.c (grokparms): Don't bash a permanent list node if we're
+ in a function.
- * cvt.c (type_promotes_to): Also promote enums to long if
- appropriate.
+1997-09-17 Brendan Kehoe <brendan@lisa.cygnus.com>
- * typeck.c (default_conversion): Don't expect type_promotes_to to
- return a main variant.
+ * Makefile.in (CONFLICTS): Fix s/r conflict count to 18.
-Wed Oct 12 12:19:45 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+Tue Sep 16 14:06:56 1997 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_scoped_method_call): Don't lose side effects in the
- object expression when calling a non-existent destructor.
+ * call.c (build_new_op): Give better error for syntactically
+ correct, but semantically invalid, use of undeclared template.
-Fri Sep 2 19:05:21 1994 Rohan Lenard (rjl@iassf.easams.com.au)
+ * call.c (compare_qual): Handle pmfs.
- * call.c (build_scoped_method_call): Remove erroneous error message
- when destructor call is written as a scoped call.
+ * decl.c (store_parm_decls): last_parm_cleanup_insn is the insn
+ after the exception spec.
-Tue Oct 11 23:48:31 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+Mon Sep 15 11:52:13 1997 Jason Merrill <jason@yorick.cygnus.com>
- * various: Cast pointer arguments to bzero and bcopy to char *.
+ * call.c (null_ptr_cst_p): Integer type, not integral type.
-Tue Oct 11 19:34:32 1994 Mike Stump <mrs@cygnus.com>
+ * call.c (joust): Disable warnings until they can be moved to the
+ right place.
- * class.c (get_derived_offset): Added a type parameter to limit how
- far up the CLASSTYPE_VFIELD_PARENT chain we search.
- * class.c (modify_one_vtable, fixup_vtable_deltas): When forming the
- offset to put into the vtable for the this parameter, make sure we
- don't offset from a parent of the DECL_CONTEXT of the function.
+Fri Sep 12 16:11:13 1997 Per Bothner <bothner@cygnus.com>
-Tue Oct 11 16:10:52 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * Makefile.in, config-lang.in: Convert to autoconf.
- * pt.c (do_function_instantiation): Set DECL_EXTERNAL and
- TREE_STATIC when setting DECL_INTERFACE_KNOWN.
- (do_type_instantiation): Ditto.
+Thu Sep 11 17:14:55 1997 Jason Merrill <jason@yorick.cygnus.com>
- * lex.c (cons_up_default_function): Set DECL_INTERFACE_KNOWN,
- DECL_EXTERNAL and TREE_STATIC as appropriate.
+ * decl.c (lookup_name_real): Add implicit 'typename' to types from
+ base classes.
- * decl2.c (finish_file): Also synthesize methods that don't have
- DECL_EXTERNAL set. Set interface_unknown before doing so.
+ * pt.c (most_specialized_class): Fix typo.
+ (tsubst): Move constant folding to TREE_VEC case.
- * decl.c (start_function): If DECL_INTERFACE_KNOWN is set on the
- function decl, don't muck with TREE_PUBLIC and DECL_EXTERNAL.
+Thu Sep 11 10:08:45 1997 Mark Mitchell <mmitchell@usa.net>
-Mon Oct 10 00:56:53 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * pt.c (do_poplevel): Don't warn about unused local variables
+ while processing_template_decl since we don't always know whether
+ or not they will need constructing/destructing.
- * lex.c (cons_up_default_function): Mark methods in a template class
- as template instances. Store the values of interface_unknown and
- interface_only for do_pending_inlines.
- (do_pending_inlines): Use them.
+ * pt.c (uses_template_parms): Check the values of an enumeration
+ type to make sure they don't depend on template parms.
- * decl2.c (finish_file): If we haven't seen a definition of a
- function declared static, make the decl non-PUBLIC so compile_file
- can give an error.
+ * decl.c (make_typename_type): Don't lookup the field if the
+ context uses template parms, even if we're not
+ processing_template_decl at the moment.
-Sun Oct 9 02:42:29 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * pt.c (coerce_template_parms): Avoid looking at the
+ TYPE_LANG_DECL portion of a typename type, since there won't be
+ one.
+ (tsubst): Do constant folding as necessary to make sure that
+ arguments passed to lookup_template_class really are constants.
- * method.c (do_build_copy_constructor): Handle anonymous unions.
- (do_build_assign_ref): Ditto.
- (largest_union_member): Move from lex.c.
+Wed Sep 10 11:21:55 1997 Jason Merrill <jason@yorick.cygnus.com>
-Sat Oct 8 14:59:43 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * except.c (expand_builtin_throw): #ifndef DWARF2_UNWIND_INFO.
+ * decl2.c (finish_file): Only register exception tables if we
+ need to.
- Re-implement g++'s vague linkage independent of TREE_PUBLIC.
- * pt.c (instantiate_member_templates): Lose redundant
- -fexternal-templates handling.
- (tsubst): Set TREE_PUBLIC and DECL_EXTERNAL on new decls. Don't set
- TREE_STATIC or DECL_INTERFACE_KNOWN.
- (do_pending_expansions): Predicate on DECL_INTERFACE_KNOWN instead
- of DECL_EXTERNAL for explicit instantiations.
- (do_function_instantiation): Do the new thing.
- (do_type_instantiation): Ditto.
- (instantiate_template): Deal with member templates defined in a .cc
- file with -fexternal-templates.
- * except.c (expand_exception_blocks): Use DECL_LINKAGE_KNOWN to
- decide whether to stick builtin_throw here.
- * decl2.c (import_export_inline): Predicate on DECL_INTERFACE_KNOWN
- rather than TREE_PUBLIC. Generally fix rules.
- (finish_file): Use DECL_INITIAL to determine whether or not a method
- has been synthesized, rather than TREE_ASM_WRITTEN.
- * decl.c (warn_extern_redeclared_static): Use DECL_PUBLIC instead of
- TREE_PUBLIC.
- (pushdecl): Ditto.
- (duplicate_decls): Ditto. Deal with DECL_DECLARED_STATIC and
- DECL_INTERFACE_KNOWN.
- (redeclaration_error_message): Fix checking for conflicting linkage.
- (define_function): Set DECL_INTERFACE_KNOWN.
- (grokfndecl): Function decls are PUBLIC until we are sure about
- their linkage. Set DECL_DECLARED_STATIC as needed.
- (start_function): Deal with linkage. Move pushdecl after linkage
- magic.
- (finish_function): Don't set TREE_ASM_WRITTEN on discarded inlines.
- * cp-tree.h (lang_decl_flags): Add interface_known and
- declared_static.
- (DECL_INTERFACE_KNOWN): New macro.
- (DECL_DECLARED_STATIC): New macro.
- (DECL_PUBLIC): New macro.
+ * decl.c (init_decl_processing): Add __builtin_[fs]p.
- Clean up bogus use of TREE_PUBLIC.
- * class.c (alter_access): Fix mistaken use of TREE_PUBLIC (it
- doesn't correspond to TREE_PROTECTED and TREE_PRIVATE).
- * init.c (do_friend): Don't arbitrarily set TREE_PUBLIC.
+Tue Sep 9 19:49:38 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Oct 5 13:44:41 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * pt.c (unify): Just return 0 for a TYPENAME_TYPE.
- * call.c (build_overload_call_real): Don't immediately do
- array->pointer conversion.
+Tue Sep 9 17:57:25 1997 Mark Mitchell <mmitchell@usa.net>
- * pt.c (type_unification): If not passing to a reference, strip
- cv-quals. Also handle array->pointer conversion.
+ * error.c (dump_decl): Avoid crashing when presented with a
+ uninitialized constant, as can occur with a template parameter.
+ (dump_expr): Make sure that there are enough levels of
+ current_template_parms before we start diving through them.
-Tue Oct 4 17:45:37 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+1997-09-09 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c (grokdeclarator): Don't warn about applying const to a
- const typedef or template type parameter.
+ * typeck.c (build_indirect_ref): Heed FLAG_VOLATILE similar to
+ c-typeck.c.
- * decl2.c (finish_file): Also synthesize methods after walking the
- vtables. Ugly ugly ugly.
+Tue Sep 9 09:36:39 1997 Benjamin Kosnik <bkoz@rhino.cygnus.com>
-Mon Oct 3 15:02:41 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * except.c (expand_throw): Call build_delete for all
+ exception types, not just objects with destructors.
- * various: Remove lingering remnants of old exception handling code.
+Mon Sep 8 02:33:20 1997 Jody Goldberg <jodyg@idt.net>
- * decl2.c (finish_file): Synthesize methods before walking the
- vtables, so that the vtables get emitted as needed.
+ * decl.c (current_local_enum): Remove static.
+ * pt.c (tsubst_enum): Save and restore value of current_local_enum
+ in case template is expanded in enum decl.
+ (instantiate_class_template) : Use new tsubst_enum signature.
+ (tsubst_expr): Likewise.
- * decl.c (shadow_tag): Remove obsolete code for pushing tags and
- dealing with exceptions.
+Mon Sep 8 01:21:43 1997 Mark Mitchell <mmitchell@usa.net>
-Mon Oct 3 13:05:27 1994 Ian Lance Taylor <ian@sanguine.cygnus.com>
+ * pt.c (begin_member_template_processing): Take a function as
+ argument, not a set of template arguments. Use the template
+ parameters, rather than the arguments. Handle non-type parameters
+ correctly. Push a binding level for the parameters so that multiple
+ member templates using the same parameter names can be declared.
+ (end_member_template_processing): Pop the binding level.
+ (push_template_decl): Mark member templates as static when
+ appropriate.
- * Make-lang.in (g++-cross): Depend upon version.o and $(LIBDEPS).
+ * lex.c (do_pending_inlines): Pass the function, not its template
+ arguments, to begin_member_template_processing.
+ (process_next_inline): Likewise.
+ (do_pending_defargs): Likewise.
-Mon Oct 3 02:59:28 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * error.c (dump_expr): Obtain the correct declaration for a
+ TEMPLATE_CONST_PARM.
- * decl2.c (finish_file): Fix inline handling.
+ * call.c (add_template_conv_candidate): New function.
+ (build_object_call): Handle member templates, as done in the other
+ build_ functions.
+
+Sat Sep 6 10:20:27 1997 Mark Mitchell <mmitchell@usa.net>
-Sun Oct 2 00:21:56 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * decl.c (replace_defag): Undo previous change.
+ * lex.c (do_pending_defargs): Deal with member templates.
+
+ * pt.c (is_member_template): Avoid crashing when passed a
+ non-function argument.
- * decl.c (grokdeclarator): Handle redundant scope even better.
- ({push,pop}_cp_function_context): Take toplev parameter.
+Fri Sep 5 17:27:38 1997 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (synthesize_method): Pass toplev parameter to
- {push,pop}_cp_function_context depending on decl_function_context
- (fndecl).
+ * class.c (grow_method): Remove check for redeclaration.
- * typeck.c (build_x_unary_op): Unary & on OFFSET_REFs is always the
- built-in version.
+Fri Sep 5 01:37:17 1997 Mark Mitchell <mmitchell@usa.net>
- * method.c (synthesize_method): Don't be confused by __in_chrg
- parameter.
+ * cp-tree.h (INNERMOST_TEMPLATE_PARMS): New macro.
+ (DECL_INNERMOST_TEMPLATE_PARMS): Likewise.
+ (PRIMARY_TEMPLATE_P): Use it.
+ * call.c (build_overload_call_real): Use it.
+ * class.c (instantiate_type): Likewise.
+ * decl.c (decls_match): Likewise.
+ * method.c (build_overload_identifier): Likewise.
+ * pt.c (push_template_decl): Likewise.
+ (classtype_mangled_name): Likewise.
+ (lookup_template_class): Likewise.
+
+ * cp-tree.h (DECL_NTPARMS): Change name from DECL_NT_PARMS to
+ DECL_NTPARMS to conform to usage elsewhere.
+ * call.c (add_template_candidate): Likewise.
+ * class.c (instantiate_type): Likewise.
+ * pt.c (instantiate_template): Likewise.
+ (get_bindings): Likewise.
+
+ * class.c (grow_method): Use DECL_FUNCTION_TEMPLATE_P instead of
+ is_member_template.
+
+ * pt.c (unify): Undo changes to allow multiple levels of template
+ parameters.
+ (type_unification): Likewise.
+ (fn_type_unification): Likewise.
+ (get_class_bindings): Likewise.
+ * cp-tree.h (Likewise).
+
+ * decl.c (replace_defarg): Check that the type of the default
+ parameter does not invlove a template type before complaining
+ about the initialization.
+
+ * error.c (dump_expr): Deal with template constant parameters in
+ member templates correctly.
+
+ * pt.c (is_member_template): Deal with class specializations
+ correctly.
+ (tsubst): Handle "partial instantiation" of member templates
+ correctly.
+
+Wed Sep 3 12:30:24 1997 Mark Mitchell <mmitchell@usa.net>
+
+ * pt.c (type_unification): Change calling squence to allow for
+ multiple levels of template parameters.
+ (tsubst_expr): Likewise.
+ (tsubst): Likewise.
+ (tsubst_copy): Likewise.
+ (instantiate_template): Likewise.
+ (unify): Likewise.
+ * call.c (build_overload_call_real): Use it.
+ (add_builtin_candidate): Use it.
+ (build_new_method_call): Use it.
+ * class.c (instantiate_type): Use it.
+ * decl.c (grokdeclarator): Use it.
+ * decl2.c (finish_file): Use it.
+ * method.c (build_overload_identifier): Use it.
+
+ * call.c (add_template_candidate): Add additional parameter for
+ the function return type. Call fn_type_unification istead of
+ type_unification.
+ (build_user_type_conversion_1): Handle member templates.
+ (build_new_function_call): Likewise.
+ (build_new_op): Likewise.
+ (build_new_method_call): Likewise.
+
+ * class.c (grow_method): Don't give an error message indicating
+ that two member templates with the same name are ambiguous.
+ (finish_struct): Treat member template functions just like member
+ functions.
+
+ * cp-tree.h (check_member_template): Add declaration.
+ (begin_member_template_processing): Likewise.
+ (end_member_template_processing): Likewise.
+ (fn_type_unification): Likewise.
+ (is_member_template): Likewise.
+ (tsubst): Change prototype.
+ (tsubst_expr): Likewise.
+ (tsubst_copy): Likewise.
+ (instantiate_template): Likewise.
+ (get_bindings): Likewise.
+
+ * decl.c (decls_match): Handle multiple levels of template
+ parameters.
+ (pushdecl): Handle template type params just like other type
+ declarations.
+ (push_class_level_binding): Return immediately if the
+ class_binding_level is NULL.
+ (grokfndecl): If check_classfn() returns a member_template, use
+ the result of the template, not the template itself.
+
+ * decl2.c (check_member_template): New function. Check to see
+ that the entity declared to be a member template can be one.
+ (check_classfn): Allow redeclaration of member template functions
+ with different types; the new functions can be specializations or
+ explicit instantiations.
+
+ * error.c (dump_decl): Handle multiple levels of template
+ parameters.
+ (dump_function_decl): Update to handle function templates.
- * class.c (popclass): Set C_C_D like start_function does.
+ * lex.c (do_pending_inlines): Set up template parameter context
+ for member templates.
+ (process_next_inline): Likewise.
- * decl.c (grokdeclarator): Handle redundant scope better.
+ * method. (build_overload_identifier): Adjust for multiple levels
+ of template parameters.
+
+ * parse.y (fn.def2): Add member templates.
+ (component_decl_1): Likewise.
+
+ * pt.c (begin_member_template_processing): New function.
+ (end_member_template_processing): Likewise.
+ (is_member_template): Likewise.
+ (fn_type_unification): Likewise.
+ (current_template_parms): Return a vector of all the template
+ parms, not just the innermost level of parms.
+ (push_template_decl): Deal with the possibility of member
+ templates.
+ (lookup_template_class): Likewise.
+ (uses_template_parms): Likewise.
+ (tsubst): Modify processing to TEMPLATE_TYPE_PARM and
+ TEMPLATE_CONST_PARM to deal with multiple levels of template
+ arguments. Add processing of TEMPLATE_DECL to produce new
+ TEMPLATE_DECLs from old ones.
+ (do_decl_instantiation): Handle member templates.
+
+ * search.c (lookup_fnfields_1): Handle member template conversion
+ operators.
+
+ * tree.c (cp_tree_equal): Check the levels, as well as the
+ indices, of TEMPLATE_CONST_PARMs.
+
+ * typeck.c (comptypes): Check the levels, as well as the indices,
+ fo TEMPLATE_TYPE_PARMs.
+ (build_x_function_call): Treat member templates like member
+ functions.
+
+Wed Sep 3 11:09:25 1997 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (expr_or_declarator): Add '(' expr_or_declarator ')' rule.
- (direct_notype_declarator): Ditto.
- (complex_direct_notype_declarator): Remove it here.
+ * typeck.c (c_expand_return): Always convert_for_initialization
+ before checking for returning a pointer to local.
-Sat Oct 1 21:42:18 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- * init.c (resolve_offset_ref): Fix types used in resolving .*
- expressions.
-
-Sat Oct 1 15:18:49 1994 Jason Merrill (jason@phydeaux.cygnus.com)
+ * pt.c (type_unification): If strict and the function parm doesn't
+ use template parms, just compare types.
- Beginnings of work to synthesize methods only when needed.
- * call.c (build_method_call): Synthesize methods as necessary
- (currently never necessary).
- * class.c (popclass): Don't try to set C_C_D here, as it'll end up
- on the wrong obstack.
- * decl.c (push_cp_function_context): Mostly copied from
- push_c_function_context.
- (pop_cp_function_context): Similarly.
- (finish_function): Reverse order of poplevel and pop_nested_class so
- that current_class_decl is restored properly.
- (start_function): Ditto.
- (finish_function): Add parameter 'nested'. Don't call
- permanent_allocation if (nested).
- * various: Pass extra parameter to finish_function.
- * decl2.c (finish_file): Reorganize end-of-file inline handling,
- synthesizing methods as necessary.
- * lex.c (cons_up_default_function): Call mark_inline_for_output.
- Only synthesize methods immediately if #pragma implementation
- (currently disabled).
- (do_pending_inlines): Call synthesize_method.
- * method.c (synthesize_method): New function; all method synthesis
- goes through here. Calls do_build_assign_ref and
- do_build_copy_constructor.
- (build_default_constructor): Remove.
- (build_dtor): Ditto.
- (build_assign_ref): Rename to do_build_assign_ref and remove stuff
- done by synthesize_method.
- (build_copy_constructor): Similarly.
+Wed Sep 3 10:35:49 1997 Klaus Espenlaub <kespenla@student.informatik.uni-ulm.de>
-Thu Sep 29 16:58:52 1994 Mike Stump <mrs@cygnus.com>
+ * method.c (build_overloaded_value): Replace direct call
+ to the floating point emulator with REAL_VALUE_TO_DECIMAL macro.
- * typeck.c (c_expand_return): Use magic so the backend can fixup the
- assignment into the return register, so cleanups won't clobber it.
+Wed Sep 3 00:02:53 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Sep 29 13:08:50 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (convert_arguments): Don't arbitrarily choose the first
+ of a set of overloaded functions.
- * method.c (hack_identifier): Don't call assemble_external for
- template decls.
+Tue Sep 2 12:09:13 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (finish_decl): Also end temporary allocation if the decl in
- question has a type of error_mark_node.
+ * lex.c (real_yylex): Don't elide __FUNCTION__.
-Wed Sep 28 21:45:00 1994 Mike Stump <mrs@cygnus.com>
+ * method.c (build_overload_value): Add in_template parm.
+ (build_overload_int): Likewise.
+ (build_overload_identifier): Pass it.
- * typeck.c (build_modify_expr): When optimizing ?: on lhs, make sure
- that if the ?: was a reference type, that the subparts will be also.
+ * decl.c (duplicate_decls): Don't bash a previous template
+ definition with a redeclaration.
-Wed Sep 28 16:14:04 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * pt.c (unify): float doesn't match double.
- * except.c (register_exception_table): Use Pmode, not PTRmode.
+ * pt.c (do_type_instantiation): Handle getting a _TYPE or a
+ TYPE_DECL. Handle getting non-template types.
+ * parse.y (explicit_instantiation): Use typespec instead of
+ aggr template_type.
-Fri Sep 23 13:54:27 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue Sep 2 10:27:08 1997 Richard Henderson <rth@cygnus.com>
- * lex.c (do_pending_inlines): Do method synthesis after the
- pending_inlines have been reversed.
+ * typeck.c (build_ptrmemfunc1): Clean up ptr->int cast warnings.
-Thu Sep 22 12:53:03 1994 Per Bothner (bothner@kalessin.cygnus.com)
+Mon Sep 1 13:19:04 1997 Eugene Mamchits <eugin@ips.ras.ru>
- * decl2.c (finish_file): Fix Brendan's fix: Only call
- register_exception_table if there is a non-empty exception table.
+ * call.c (add_builtin_candidate): Add missing TREE_TYPE.
+ (compare_ics): Likewise.
-Thu Sep 22 12:03:46 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+Mon Sep 1 13:19:04 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (finish_file): Only do register_exception_table if
- -fhandle-exceptions is being used.
+ * call.c (joust): Warn about choosing one conversion op over
+ another because of 'this' argument when the other return type is
+ better.
+ (source_type): New fn.
-Wed Sep 21 19:01:51 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * call.c (build_new_op): Strip leading REF_BIND from first operand
+ to builtin operator.
- * except.c (output_exception_table_entry): Simplify
- by using assemble_integer.
- (build_exception_table): Change to return a count.
- Cleanup to use standard macros, instead of hard-wired
- sparc asm format. Don't make __EXCEPTION_TABLE__ global.
- (register_exception_table): New function. Generate call to builtin.
- * decl2.c (finish_file): Call register_exception_table.
- * cp-tree.h (build_exception_table): Fix prototype.
+ * decl2.c (mark_vtable_entries): Mark abort_fndecl as used when we
+ use its RTL.
-Wed Sep 21 13:20:42 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+Thu Aug 28 09:45:23 1997 Jason Merrill <jason@yorick.cygnus.com>
- * tree.c (break_out_calls): Don't try to duplicate the DECL_INITIAL.
+ * call.c (null_ptr_cst_p): Remove support for (void*)0.
- * decl2.c (delete_sanity): Give an error at trying to delete a
- function.
+Wed Aug 27 02:03:34 1997 Jeffrey A Law (law@cygnus.com)
-Wed Sep 21 11:47:10 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (expand_target_expr): Make definition match declaration.
- * lex.c (cons_up_default_function): Mark synthesized destructors
- inline.
+ * class.c (get_basefndecls): Make definition match declaration.
- * decl.c (duplicate_decls): Ignore redeclarations of wchar_t as
- something other than __wchar_t, complaining if -pedantic and not in
- a system header.
+Mon Aug 25 14:30:02 1997 Jason Merrill <jason@yorick.cygnus.com>
-Tue Sep 20 09:43:28 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * input.c (sub_getch): Eventually give up and release the input file.
- * decl.c (xref_tag): Set up BINFO_INHERITANCE_CHAIN on base binfos
- here.
+ * decl.c (cp_finish_decl): If #p i/i, put inline statics in the
+ right place.
- * typeck.c (build_modify_expr): Require complete type after checking
- for error_mark_node.
+ * call.c (joust): Tweak message.
- * call.c (build_method_call): Print parmtypes when complaining of
- ambiguous call.
+Sat Aug 23 18:02:59 1997 Mark Mitchell <mmitchell@usa.net>
- * typeck.c (build_modify_expr): Handle assignment to array from
- non-array.
+ * error.c (type_as_string): Put const/volatile on template type
+ parameters where appropriate.
- * decl.c (lookup_name_real): Deal with got_scope == error_mark_node.
+Sat Aug 23 17:47:22 1997 Jeffrey A Law (law@cygnus.com)
- * call.c (build_method_call): Don't bother with the exact match.
+ * call.c (strictly_better): Make arguments unsigned ints.
-Mon Sep 19 00:51:39 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu Aug 21 18:48:44 1997 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (expand_aggr_init): If we munge the type of the variable,
- also munge the type of the initializer.
+ * lex.c (real_yylex): Refer to __complex instead of complex.
- * decl.c (grokdeclarator): Use <= when comparing to RID_LAST_MODIFIER.
- (init_decl_processing): Push artificial declaration of wchar_t so
- people don't have to declare it before they can use it.
+Thu Aug 21 22:25:46 1997 J"orn Rennecke <amylaar@cygnus.co.uk>
- * error.c (cp_line_of): return lineno in lieu of 0.
+ * lex.c (real_yylex): Don't use getc directly.
- * typeck.c (convert_for_assignment): Handle conversion of pmfs to
- int and bool.
- (build_component_ref): Fold the COMPONENT_REF in case it can be
- reduced.
+Wed Aug 20 17:25:08 1997 Jason Merrill <jason@yorick.cygnus.com>
- * typeck2.c (store_init_value): Don't pedwarn about non-constant
- bracketed initializers for automatic variables.
+ * call.c (is_subseq): Don't try to be clever.
-Sun Sep 18 10:12:12 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Aug 20 03:13:36 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
- * error.c (dump_decl): Don't say `typedef enum foo foo'.
+ * parse.y, pt.c: Include "except.h".
+ * call.c, class.c, class.h, cp-tree.h, cvt.c, decl.c, decl2.c,
+ error.c, except.c, expr.c, friend.c, g++spec.c, init.c, input.c,
+ lex.c, lex.h, method.c, parse.y, pt.c, repo.c, rtti.c, search.c,
+ sig.c, spew.c, tree.c, typeck.c, typeck2.c, xref.c: Finish
+ prototyping.
- * decl.c (start_decl): Don't set TREE_PUBLIC on template decls just
- because they're affected by #pragma i/i. We'll deal with that when
- they get instantiated.
+Wed Aug 20 01:34:40 1997 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_unary_op): Clean up cruft in ADDR_EXPR case.
+ * decl2.c (mark_vtable_entries): Instead of replacing pure
+ virtuals with a reference to __pure_virtual, copy the decl and
+ change the RTL.
- * class.c (instantiate_type): Set TREE_CONSTANT on instantiated
- ADDR_EXPRs if appropriate.
+Tue Aug 19 02:26:07 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (build_ptrmemfunc_type): Unset IS_AGGR_TYPE on pmf types.
+ * pt.c (lookup_nested_type_by_name): Handle typedef wierdness.
- * typeck.c (build_ptrmemfunc): Handle &overloaded_method as an
- initializer properly.
- * typeck2.c (digest_init): Ditto.
+ * typeck2.c (my_friendly_abort): Report bugs to egcs-bugs@cygnus.com.
- * tree.c (cp_build_type_variant): Like c_build_type_variant, except
- it uses build_cplus_array_type.
- * *.c: Use cp_build_type_variant instead of c_build_type_variant.
+ * pt.c (instantiate_class_template): Call repo_template_used
+ before finish_prevtable_vardecl.
- * pt.c (do_type_instantiation): Don't try to instantiate nested
- enums.
+ * call.c (is_subseq): New fn.
+ (compare_ics): Use it.
-Tue Sep 13 10:56:58 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * repo.c (finish_repo): Don't crash on no args.
- * cvt.c (build_up_reference): Handle preincrement and predecrement
- properly.
+ * parse.y (named_complex_class_head_sans_basetype): Handle
+ explicit global scope.
+ * decl2.c (handle_class_head): New fn.
-Tue Sep 13 09:51:59 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * pt.c (unify): Add CONST_DECL case.
- * decl.c (finish_decl): Only lay out the rtl for DECL if it is, in
- fact, static.
+Thu Aug 14 10:05:13 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
-Mon Sep 12 14:40:30 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * rtti.c (permanent_obstack): Fix decl to not be a pointer.
- * decl.c (finish_decl): Lay out the rtl for DECL before doing
- grok_reference_init, in case it's static.
+ * cp-tree.h (report_type_mismatch): Add prototype.
+ * call.c (build_overload_call_real): Remove erroneous fourth
+ argument to report_type_mismatch.
+ (build_user_type_conversion_1): Remove erroneous second arg to
+ tourney.
+ (build_new_function_call): Likewise.
+ (build_object_call): Likewise.
+ (build_new_op): Likewise.
+ (build_new_method_call): Likewise.
-Mon Sep 12 12:45:38 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Aug 13 19:19:25 1997 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): Don't synthesize constructors if the
- class has a field with the same name as the class. Don't die on
- classes with no constructors or destructors. Don't die if the head
- and tail of the class are in different files.
+ * error.c (dump_decl): Don't bother processing a function with no
+ DECL_LANG_SPECIFIC.
- * decl.c (grokdeclarator): Don't treat a function pointer field
- with the same name as the class as a constructor.
+ * method.c (emit_thunk): Call init_function_start in the macro case.
-Fri Sep 9 13:17:00 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Aug 13 10:46:19 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
- * typeck.c (build_c_cast): Pull constant values out of their
- variables here.
+ * decl2.c (DEFAULT_VTABLE_THUNKS): Define to be 0 if not
+ defined and used to set flag_vtable_thunks.
- * decl.c (duplicate_decls): Only propagate DECL_CHAIN in
- FUNCTION_DECLs and TEMPLATE_DECLs.
+Tue Aug 12 20:13:57 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Sep 8 10:07:48 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * parse.y: Don't clear the inlines from their obstack until they've
+ all been processed.
- * decl.c (duplicate_decls): Propagate DECL_CHAIN in all DECLs that
- have it.
+ * decl.c (duplicate_decls): Don't complain about exception
+ specification mismatch if flag_exceptions is off.
- * pt.c (unify): REALs and INTEGERs only unify with their own genus.
- (instantiate_member_templates): Don't muck with DECL_EXTERNAL and
- TREE_PUBLIC unless -fexternal-templates.
+Mon Aug 11 15:01:56 1997 Marc Lehmann <pcg@goof.com>
-Wed Sep 7 13:17:10 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * Make-lang.in (c++.distclean): Remove g++.c on make distclean.
- * pt.c (do_type_instantiation): Call instantiate_member_templates.
- Deal with specializations.
- (tsubst): Don't stick the mangled name in DECL_NAME for function
- instantiations. Don't push them, either.
+Sun Aug 10 12:06:09 1997 Paul Eggert <eggert@twinsun.com>
- * decl2.c (grokfield): Move code for generating the
- DECL_ASSEMBLER_NAME for static members from here.
- * method.c (build_static_name): To here.
- * decl.c (grokvardecl): Call build_static_name.
- (duplicate_decls): Keep old DECL_ASSEMBLER_NAME.
+ * cp-tree.h: Replace STDIO_PROTO with PROTO in include files.
+ * cvt.c, error.c, except.c, expr.c, friend.c, init.c, rtti.c:
+ Include <stdio.h> before include files that formerly used STDIO_PROTO.
-Mon Sep 5 12:49:18 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c, g++spec.c, lex.c, method.c, repo.c:
+ Include "config.h" first, as per autoconf manual.
- * call.c (build_method_call): if -Wsynth, warn when selecting
- synthesized op= over user-supplied one cfront would select.
- * decl2.c (lang_decode_option): Handle -Wsynth.
+Fri Aug 8 11:47:48 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri Sep 2 15:11:59 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (duplicate_decls): Tweak wording.
+ * lex.c (do_pending_defargs): Don't die if we see a default arg
+ that isn't a DEFAULT_ARG.
+ * error.c (dump_expr): Handle DEFAULT_ARG.
- * decl.c (finish_enum): Overhaul to fix several bugs.
- (start_enum): Disable useless code.
+ * decl2.c (lang_decode_option): Handle -fhandle-exceptions.
+ * lang-options.h: Add -fhandle-exceptions.
-Thu Sep 1 16:04:54 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * class.c (build_vtable): vtables are artificial.
+ (prepare_fresh_vtable): Likewise.
- * typeck.c (c_expand_return): Warn about returning a reference to a
- temporary.
- (convert_arguments): Increment argument counter when using default
- arguments, too.
+Wed Aug 6 11:02:36 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Aug 31 14:29:22 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * cvt.c (ocp_convert): After converting to the target type, set
+ LOOKUP_NO_CONVERSION.
- * decl.c (finish_decl): If the type of decl is error_mark_node,
- don't bother trying to do anything.
+ * call.c (joust): Warn about potentially confusing promotion rules
+ with -Wsign-promo.
+ * cp-tree.h, lang-options.h, decl2.c: Support -Wsign-promo.
- * typeck.c (convert_for_initialization): If the rhs contains a
- constructor call, pretend the lhs type needs to be constructed.
+Tue Aug 5 15:15:07 1997 Michael Meissner <meissner@cygnus.com>
- * init.c (expand_default_init): If we stick the object inside the
- initializer, mark the initializer used.
+ * exception.cc: Declare __terminate_func with noreturn attribute.
-Tue Aug 30 13:50:18 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Aug 1 03:18:15 1997 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (build_assign_ref): return *this;
- (build_assign_ref): Fix base assignment order.
- (build_copy_constructor): Fix member init order.
+ * parse.y: Break out eat_saved_input, handle errors.
+ (function_try_block): Use compstmt instead of compstmt_or_error.
-Mon Aug 29 13:54:39 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+Thu Jul 31 17:14:04 1997 Jason Merrill <jason@yorick.cygnus.com>
- * g++.c (main): Remember to clear out SAW_SPECLANG after we see
- its argument.
+ * tree.c (build_cplus_new): Don't set TREE_ADDRESSABLE.
-Sat Aug 27 09:36:03 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Jul 4 01:45:16 1997 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- * method.c (build_copy_constructor): Also copy virtual bases.
+ * Make-lang.in (cplib2.txt, cplib2.ready): Instead of checking for
+ existence of cc1plus check whether $(LANGUAGES) contains C++.
-Fri Aug 26 17:05:15 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Jul 30 13:04:21 1997 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
- * lex.c (do_pending_inlines): Clear out pending_inlines before doing
- any synthesis. Also first set deja_vu on all pending_inlines.
+ * method.c (do_build_copy_constructor): When copying an anonymous
+ union member loop around to handle nested anonymous unions. Use
+ the offset of the member relative to the outer structure, not the
+ union.
- * method.c (build_assign_ref): Use build_member_call to invoke base
- operator=, rather than build_modify_expr. And use
- build_reference_type instead of TYPE_REFERENCE_TO.
- (build_copy_constructor): Use TYPE_NESTED_NAME to identify the
- basetype.
+Tue Jul 29 21:17:29 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (grokfield): Don't complain about undefined local class
- methods.
+ * call.c (resolve_args): New fn.
+ (build_new_function_call): Use it.
+ (build_object_call): Likewise.
+ (build_new_method_call): Likewise.
- * class.c (finish_struct): Don't try to synthesize methods here.
- * lex.c (do_pending_inlines): Instead, synthesize them here.
- (init_lex): Initialize synth_obstack.
- (cons_up_default_function): Stick synthesis request on
- pending_inlines.
+Mon Jul 28 16:02:36 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri Aug 26 12:24:14 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * call.c (build_over_call): tsubst all default parms from templates.
- * call.c (build_method_call) [PCC_STATIC_STRUCT_RETURN]: Also
- accept an RTL_EXPR in what we're about to use for the instance,
- since anything which would end up with pcc_struct_return set
- inside cplus_expand_expr.
+Wed Jul 23 13:36:25 1997 Jason Merrill <jason@yorick.cygnus.com>
- * cp-tree.h (cons_up_default_function): Note change of prototype.
+ * decl.c (struct cp_function): Add static_labelno.
+ (push_cp_function_context): Save it.
+ (pop_cp_function_context): Restore it.
-Thu Aug 25 23:05:30 1994 Gerald Baumgartner (gb@cs.purdue.edu)
+Tue Jul 22 14:43:29 1997 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): Undid change from Aug 21 testing
- CLASSTYPE_INTERFACE and CLASSTYPE_VTABLE_NEEDS_WRITING.
- * parse.y (left_curly): Ditto, undid change from Aug 21.
- * decl.c (xref_tag): Undid change from Aug 21, set
- CLASSTYPE_INTERFACE correctly, and added comments.
+ * typeck.c (build_component_ref_1): Convert from reference.
-Thu Aug 25 00:36:31 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue Jul 22 11:06:23 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- Rework approach to synthesized methods; don't go through the parser
- anymore.
- * class.c (finish_struct): Use new synthesis approach.
- * lex.c (cons_up_default_function): Now just creates declaration,
- not code.
- (largest_union_member): #if 0 out.
- (default_assign_ref_body): Ditto.
- (default_copy_constructor_body): Ditto.
- * method.c (build_default_constructor): New function to synthesize X().
- (build_copy_constructor): Synthesize X(X&).
- (build_assign_ref): Synthesize X::operator=(X&).
- (build_dtor): Synthesize ~X().
+ * parse.y (current_declspecs, prefix_attributes): Initialize to
+ NULL_TREE.
- * error.c (cp_line_of): If we're dealing with an artificial
- TYPE_DECL, look at the type instead.
+ * parse.y (initdcl0): Make sure CURRENT_DECLSPECS is non-nil
+ before we try to force it to be a TREE_LIST.
+ (decl): Make sure $1.t is non-nil.
-Wed Aug 24 11:11:50 1994 Jason Merrill (jason@deneb.cygnus.com)
+Sun Jul 20 11:53:07 1997 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (sort_member_init): Check warn_reorder.
- * decl2.c (lang_decode_option): Handle -W{no-,}reorder.
+ * pt.c (uses_template_parms): Handle template first-parse codes.
- * cp-tree.h (CLASSTYPE_SOURCE_LINE): New macro.
- * error.c (cp_line_of): Use CLASSTYPE_SOURCE_LINE for aggregates.
- * class.c (finish_struct): Set CLASSTYPE_SOURCE_LINE.
+ * decl.c (cp_finish_decl): Only warn about user-defined statics.
-Tue Aug 23 09:28:35 1994 Mike Stump <mrs@cygnus.com>
+Fri Jul 18 17:56:08 1997 Jason Merrill <jason@yorick.cygnus.com>
- * error.c (dump_decl): Improve wording, so that error messages
- dont't read template<, class foo>...
+ * pt.c (unify): Handle BOOLEAN_TYPE.
-Mon Aug 22 15:30:51 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * cp-tree.h: Lose PARM_DEFAULT_FROM_TEMPLATE.
+ * pt.c (tsubst): Don't set it.
+ * call.c (build_over_call): Use uses_template_parms.
- * parse.y (label_colon): Also match a TYPENAME as a label name,
- since they may have declared a class by that name but have also
- tried to have a local label under the same name.
+Thu Jul 17 18:06:30 1997 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (coerce_template_parms): Call cp_error, not cp_error_at,
- for the message so they know at what point it was instantiated.
+ * method.c (build_overload_nested_name): Use static_labelno
+ instead of var_labelno.
+ (build_qualified_name): New fn.
+ (build_overload_name): Split out from here.
+ (build_static_name): Use build_qualified_name.
+ * decl.c (cp_finish_decl): Statics in extern inline functions
+ have comdat linkage.
+ (start_function): Initialize static_labelno.
-Sun Aug 21 23:07:35 1994 Gerald Baumgartner (gb@cs.purdue.edu)
+Thu Jul 17 11:20:17 1997 Benjamin Kosnik <bkoz@rhino.cygnus.com>
- * class.c (finish_struct): Move setting of CLASSTYPE_INTERFACE and
- CLASSTYPE_VTABLE_NEEDS_WRITING for signatures up to left_curly time.
- * decl.c (xref_tag): Move setting of CLASSTYPE_INTERFACE and
- CLASSTYPE_VTABLE_NEEDS_WRITING for signatures down to left_curly time.
- * parse.y (left_curly): New final resting place for setting
- CLASSTYPE_INTERFACE and CLASSTYPE_VTABLE_NEEDS_WRITING for signatures.
+ * class.c (finish_struct_methods): add check of warn_ctor_dtor_privacy
+ before "all member functions in class [] are private"
- * class.c (finish_struct): Don't test for function/field name
- conflicts in signatures, since all the fields are compiler-constructed.
+Wed Jul 16 23:47:08 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri Aug 19 14:04:47 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * lex.c (do_scoped_id): convert_from_reference.
+ * init.c (build_offset_ref): Likewise.
- * method.c (build_overload_nested_name): in qualified name
- mangling, the template with value instantiation will have numeric
- at end and may mixed with the name length of next nested level.
- Add a '_' in between.
- * method.c (build_overload_name): ditto.
- * method.c (build_overload_identifier): ditto.
+Wed Jul 16 12:34:29 1997 Benjamin Kosnik <bkoz@lisa.cygnus.com>
-Thu Aug 18 16:24:43 1994 Mike Stump <mrs@cygnus.com>
+ * error.c (dump_expr): Check TREE_OPERAND before dump_expr_list.
- * error.c (dump_decl): Handle NULL args.
+Mon Jul 14 03:23:46 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Sep 29 16:15:36 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
+ * typeck.c (get_member_function_from_ptrfunc): Promote index
+ before saving it.
- * g++.c: Rework last change so it's done like collect.c (and
- gcc.c).
+Sun Jul 13 00:11:52 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Sep 14 10:17:27 1994 Michael I Bushnell <mib@churchy.gnu.ai.mit.edu>
+ * tree.c (layout_basetypes): Move non-virtual destructor warning.
+ * decl.c (xref_basetypes): Remove non-virtual destructor warning.
- * g++.c: Include <sys/errno.h> in case `errno' is a macro
- as permitted by ANSI C.
+Sat Jul 12 12:47:12 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Aug 18 12:48:09 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (grokdeclarator): Call add_defarg_fn for the function
+ type, too.
+ * lex.c (add_defarg_fn): Adjust.
+ (do_pending_defargs): Adjust. Don't skip the first parm.
- * class.c (finish_struct): Move setting of CLASSTYPE_INTERFACE and
- CLASSTYPE_VTABLE_NEEDS_WRITING up to left_curly time.
- * decl.c (xref_tag): Move setting of CLASSTYPE_INTERFACE and
- CLASSTYPE_VTABLE_NEEDS_WRITING down to left_curly time.
- * parse.y (left_curly): New final resting place for setting
- CLASSTYPE_INTERFACE and CLASSTYPE_VTABLE_NEEDS_WRITING.
+Fri Jul 11 01:39:50 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Aug 11 11:32:42 1994 H.J. Lu (hjl@nynexst.com)
+ * decl.c (build_enumerator): Global enumerators are also readonly.
- * g++.c (main): Only decrement "added" and set "library" to
- NULL when "library" != NULL.
+ * rtti.c (build_dynamic_cast_1): Renamed from build_dynamic_cast.
+ (build_dynamic_cast): Call it and convert_from_reference.
-Sat Aug 13 00:14:52 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * lex.c (add_defarg_fn): New fn.
+ (snarf_defarg): Don't add to defarg_types.
+ (do_pending_defargs): Lose defarg_types. All fns we process now
+ have defargs.
+ * decl.c (grokfndecl): Call add_defarg_fn.
- * decl.c (grokdeclarator): Don't set TREE_PUBLIC on a function decl
- just because its class has a known interface.
- (decls_match): Deal with new format of template parms.
+ * Makefile.in (CONFLICTS): Expect 18 s/r conflicts.
+ * cp-tree.def: Add DEFAULT_ARG.
+ * spew.c (yylex): Call snarf_defarg as appropriate.
+ * parse.y: New tokens DEFARG and DEFARG_MARKER.
+ (defarg_again, pending_defargs, defarg, defarg1): New rules.
+ (structsp): Use pending_defargs.
+ (parms, full_parm): Use defarg.
+ * lex.c (init_lex): Initialize inline_text_firstobj.
+ (do_pending_inlines): Never pass the obstack to feed_input.
+ (process_next_inline): Call end_input instead of restore_pending_input.
+ (clear_inline_text_obstack, reinit_parse_for_expr, do_pending_defargs,
+ finish_defarg, feed_defarg, snarf_defarg, maybe_snarf_defarg): New fns.
+ * input.c (end_input): New fn.
+ (sub_getch): At the end of some fed input, just keep returning EOF
+ until someone calls end_input.
+ Remove 'obstack' field from struct input_source.
+ * decl.c (grokparms): Handle DEFAULT_ARG.
+ (replace_defarg): New fn.
+ * cp-tree.h (DEFARG_LENGTH, DEFARG_POINTER): New macros.
- * lex.c (cons_up_default_function): Don't play with TREE_PUBLIC and
- DECL_EXTERNAL here.
+Wed Jul 9 13:44:12 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri Aug 12 01:55:15 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (implicit_conversion): If nothing else works, try binding
+ an rvalue to a reference.
- * decl.c (pushtag): SET_DECL_ARTIFICIAL on gratuitous typedefs.
- (xref_defn_tag): Ditto.
- (pushdecl): Only allow artificial typedefs to be shadowed.
+Wed Jul 9 13:04:38 1997 Geoffrey Noer <noer@cygnus.com>
- * init.c (emit_base_init): Pass the right binfos to
- expand_aggr_init_1.
+ * decl.c (init_decl_processing): fix Jun 30 patch -- move
+ ifndef for Cygwin32 to include SIGSEGV.
- * class.c (delete_duplicate_fields_1): Make it work right.
- (finish_struct): Catch function/field name conflict.
+Thu Jul 3 01:44:05 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (check_classfn): Pass the function to cp_error, not just
- the name.
+ * class.c (finish_struct_1): Only complain about pointers without
+ copy stuff if there are any constructors.
- * init.c (sort_member_init): Warn when order of member initializers
- does not match order of member declarations.
- (emit_base_init): Call expand_aggr_init_1 with LOOKUP_PROTECT.
+ * rtti.c (build_dynamic_cast): Call complete_type on the types.
- * error.c (dump_expr): Handle lists of functions.
+ * decl.c (grokfndecl): If the function we chose doesn't actually
+ match, die.
- * decl.c (start_function): #pragma interface only affects functions
- that would otherwise be static.
- (finish_decl): Don't warn about an unused variable if it has both
- constructor and destructor, since the 'resource allocation is
- initialization' idiom is relatively common.
+ * decl2.c (grokclassfn): Don't specify 'const int' for the
+ artificial destructor parm.
- * typeck.c (comp_target_types): Don't handle TEMPLATE_TYPE_PARMs.
- (comp_target_parms): Ditto.
- (compparms): Never consider default parms.
- (common_base_type): Don't choose a virtual baseclass if there is a
- more derived class in common.
- (build_conditional_expr): If pedantic, pedwarn about conversion to
- common base in conditional expr.
+ * pt.c (type_unification): If we are called recursively, nothing
+ decays.
- * class.c (instantiate_type): Handle template instantiation better.
+Mon Jun 30 17:53:21 1997 Geoffrey Noer <noer@cygnus.com>
- * typeck.c (convert_arguments): Don't try to get tricky and convert
- to int directly when PROMOTE_PROTOTYPES is set, as it breaks
- user-defined conversions.
+ * decl.c (init_decl_processing): Stop trying to catch signals
+ other than SIGABRT since the Cygwin32 library doesn't support
+ them correctly yet. This fixes a situation in which g++ causes
+ a hang on SIGSEGVs and other such signals in our Win32-hosted
+ tools.
- * lex.c (check_for_missing_semicolon): Also give error at end of
- file.
+Mon Jun 30 14:50:01 1997 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_method_call): Don't promote arrays to pointers here.
+ * tree.c (mapcar, case CALL_EXPR): Handle all the parse node data.
- * typeck.c (convert_arguments): Don't require the actual parameter
- to be of a complete type if the formal parameter is a reference.
+Fri Jun 27 15:18:49 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Aug 11 15:21:40 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck2.c (store_init_value): Always return the value if our
+ type needs constructing.
- * decl.c (grokdeclarator): Soften 'static' on member function error
- to pedwarn.
+ * method.c (hack_identifier): Convert class statics from
+ reference, too.
- * init.c (build_new): Don't automatically save rval.
- (build_offset_ref): Do field lookup with proper basetype_path.
+Thu Jun 26 11:44:46 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Aug 11 12:46:54 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * Make-lang.in (cplib2.ready): Add $(LANGUAGES) dependency.
- * errfn.c (cp_silent): Declare to mark when we should avoid
- emitting warnings and errors.
- (cp_error): Check it.
- (cp_warning): Likewise.
- (cp_pedwarn): Likewise.
- (cp_compiler_error): Likewise.
- (cp_error_at): Likewise.
- (cp_warning_at): Likewise.
- (cp_pedwarn_at): Likewise.
- * call.c (compute_conversion_costs): Set CP_SILENT when we start
- out, and make sure we turn it off before we leave.
+Thu Jun 19 16:49:28 1997 Mike Stump <mrs@cygnus.com>
-Thu Aug 11 00:02:54 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (c_expand_return): Make sure we clean up temporaries at
+ the end of return x;
- * decl2.c (grok_array_decl): Try computing *(A+B) if neither
- argument is obviously an array.
+Thu Jun 19 12:28:43 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
-Wed Aug 10 15:32:04 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * lex.c (check_for_missing_semicolon): Also check for CV_QUALIFIER.
- * typeck.c (c_expand_start_case): Do cleanups here.
+Tue Jun 17 18:35:57 1997 Mike Stump <mrs@cygnus.com>
- * parse.y (xcond): Do bool conversion here, too.
- (simple_stmt, SWITCH case): Don't do cleanups here.
+ * except.c (expand_builtin_throw): Add support
+ -fno-sjlj-exceptions -fPIC exception handling on the SPARC.
- * decl.c (duplicate_decls): Don't treat builtins that have been
- explicitly declared specially.
+Mon Jun 16 01:24:37 1997 Jason Merrill <jason@yorick.cygnus.com>
-Tue Aug 9 01:16:09 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * repo.c (extract_string): Null-terminate.
- * tree.c (make_deep_copy): Support copying pointer, reference,
- function, array, offset and method types.
+ * cp-tree.h (TI_SPEC_INFO): New macro.
+ (CLASSTYPE_TI_SPEC_INFO): New macro.
+ * pt.c (push_template_decl): Correctly determine # of template parms
+ for partial specs.
- * decl.c (init_decl_processing): Mark exit and abort as
- BUILT_IN_NONANSI so that duplicate_decls is kinder about
- redeclaration.
- (duplicate_decls): Don't give two errors for redeclaring a C
- function with the same parms but a different return type.
+ * call.c (compare_ics): Really fix 'this' conversions.
- * parse.y (paren_cond_or_null): Do cleanup and bool conversion here.
- (condition): Instead of here.
- (simple_stmt, SWITCH case): Also do cleanup here.
+ * pt.c (do_decl_instantiation): Don't crash on explicit inst of
+ non-template fn.
- * decl2.c (finish_anon_union): Only break out FIELD_DECLs.
+ * pt.c (push_template_decl): Complain about mismatch in # of
+ template parms between a class template and a member template.
- * call.c (build_method_call): Don't throw away the side effects of
- the object in a call to a non-existent constructor.
- * parse.y (primary): Ditto.
+Sun Jun 15 02:38:20 1997 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (build_decl_overload): Oop.
+ * method.c (synthesize_method): You can't call
+ function_cannot_inline_p after finish_function.
+ * decl.c (finish_function): Turn on flag_inline_functions and turn
+ off DECL_INLINE before handing a synthesized method to the
+ backend.
- * decl2.c (lang_decode_option): Deal with flag_no_nonansi_builtin,
- warn about uselessness of specifying -fansi-overloading.
+Thu Jun 12 17:35:28 1997 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (build_decl_overload): Treat any non-member new with one
- parameter as __builtin_new.
+ * method.c (synthesize_method): Remove July 30 change to never set
+ DECL_INLINE if at_eof.
- * decl.c (init_decl_processing): Setup built-in meanings of exit,
- _exit and abort.
+Thu Jun 12 15:25:08 1997 Mike Stump <mrs@cygnus.com>
-Mon Aug 8 15:03:30 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * xref.c (GNU_xref_member): Ensure that the node has a
+ decl_lang_specific part before checking DECL_FRIEND_P.
- * error.c (dump_readonly_or_volatile): Put a space between const and
- volatile if both apply.
+Thu Jun 12 12:36:05 1997 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (perform_member_init): Clean up after this initialization.
- (emit_base_init): Clean up after each base init, not after all have
- been done.
- (expand_aggr_vbase_init_1): Clean up after this init.
+ * pt.c (instantiate_class_template): Diagnose non-class types used
+ as bases.
-Sun Aug 7 14:55:05 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Jun 11 17:33:40 1997 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_method_call): Deal with destroying references.
+ * typeck.c (build_conditional_expr): Use convert_for_initialization
+ instead of convert_and_check.
- * parse.y (condition): Do bool_truthvalue_conversion here.
- (paren_expr_or_null): And here.
- (simple_if): Not here.
- (simple_stmt): Or here.
+Wed Jun 11 12:31:33 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
-Sat Aug 6 22:29:45 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * parse.y (typespec): Don't pedwarn for typeof.
- * parse.y (paren_expr_or_null): Wrap the expression in a
- CLEANUP_POINT_EXPR.
- (condition): Ditto.
+Tue Jun 10 00:22:09 1997 Jason Merrill <jason@yorick.cygnus.com>
-Sat Aug 6 19:46:37 1994 Rohan Lenard (rjl@easams.com.au)
+ * repo.c (finish_repo): Only check changes if we would write a
+ repo file.
- * call.c (build_scoped_method_call): Fix error message when
- destructor call refers to a nonexistent type.
+ * call.c (compare_ics): Fix handling of 'this' conversions.
-Sat Apr 16 22:43:30 1993 Gerald Baumgartner (gb@cs.purdue.edu)
+ * pt.c (do_decl_instantiation): Support static data too. Rename
+ from do_function_instantiation.
+ * cp-tree.h: Adjust.
+ * parse.y: Adjust.
- * lex.h (rid): Deleted RID_RAISES, it's never used.
- Moved RID_PUBLIC, RID_PRIVATE, RID_PROTECTED, RID_EXCEPTION,
- RID_TEMPLATE and RID_SIGNATURE to the end of the enumeration,
- they don't need to be touched in `grokdeclarator.'
- (RID_LAST_MODIFIER): Defined macro to be RID_MUTABLE.
+ * repo.c (extract_string): New fn.
+ (get_base_filename): Use it.
+ (init_repo): Compare old args with current args.
- * decl.c (grokdeclarator): Use RID_LAST_MODIFIER instead of
- RID_MAX as loop limit for finding declaration specifiers.
+Mon Jun 9 14:25:30 1997 Mike Stump <mrs@cygnus.com>
-Sat Apr 3 21:59:07 1993 Gerald Baumgartner (gb@cs.purdue.edu)
+ * Makefile.in, Make-lang.in: Protect C-ls with a comment
+ character, idea from Paul Eggert <eggert@twinsun.com>.
- * lex.c (debug_yytranslate): Moved to parse.y since it needs to
- access `yytname,' which is static in parse.c.
+Mon Jun 9 01:52:03 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri Apr 2 23:36:57 1993 Gerald Baumgarnter (gb@cs.purdue.edu)
+ * typeck.c (c_expand_return): Be more persistent in looking for
+ returned temps.
- * cp-tree.h (GNU_xref_ref): Fixed typo in extern declaration, it
- was `GNU_xref_def' instead of `GNU_xref_ref.'
+ * cvt.c (build_up_reference): Use NOP_EXPR for switching from
+ pointer to reference.
-Fri Aug 5 14:20:16 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * class.c (build_vbase_path): Don't do anything if PATH has no steps.
- * pt.c (do_function_instantiation): Don't set TREE_PUBLIC and
- DECL_EXTERNAL on 'extern' instantiations; wait until EOF to do that.
- (do_type_instantiation): Ditto.
+Sun Jun 8 03:07:05 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (import_export_inline): Decides at EOF what an inline's
- linkage should be.
- (finish_file): Call it.
+ * init.c (build_member_call, build_offset_ref):
+ Use do_scoped_id instead of do_identifier.
- * decl.c (start_function): Don't rely on the settings of TREE_PUBLIC
- and DECL_EXTERNAL from do_*_instantiation. Only set
- DECL_DEFER_OUTPUT on inlines whose linkage might actually change.
- (finish_function): Use DECL_DEFER_OUTPUT to decide which inlines to
- mark for later consideration, rather than DECL_FUNCTION_MEMBER_P.
+ * cvt.c (convert): Remove bogosity.
-Fri Aug 5 01:12:20 1994 Mike Stump <mrs@cygnus.com>
+Sat Jun 7 20:50:17 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * class.c (get_class_offset_1, get_class_offset): New routine to
- find the offset of the class where a virtual function is defined,
- from the complete type.
- * class.c (modify_one_vtable, fixup_vtable_deltas): Use
- get_class_offset instead of virtual_offset as get_class_offset will
- always provide the right answer.
- * tree.c (virtual_offset): Remove. It only ever worked some of the
- time.
+ * cvt.c (build_up_reference): Do checks of ARGTYPE and
+ TARGET_TYPE before trying to use get_binfo.
-Tue Aug 2 12:44:21 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Jun 6 17:36:39 1997 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_method_call): Put back unary_complex_lvalue call
- that I thought was redundant.
+ * cvt.c (build_up_reference): Call get_binfo to get access control.
- * typeck.c (c_expand_return): Fix a case I missed before.
+ * decl2.c (import_export_decl): If we don't support weaks, leave
+ statics undefined.
-Sun Jul 31 17:54:02 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Jun 6 15:55:49 1997 Mike Stump <mrs@cygnus.com>
- * pt.c (unify): Strip cv-quals from template type arguments (when
- 'const T*' is matched to 'const char*', that does not mean that T is
- 'const char').
+ * except.c (expand_builtin_throw): Add support for machines that
+ cannot access globals after throw's epilogue when
+ -fno-sjlj-exceptions is used.
-Fri Jul 29 01:03:06 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu Jun 5 16:28:43 1997 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (do_type_instantiation): Instantiate nested TAGS, not
- typedefs. Third time's the charm?
+ * parse.y: 'std::' becomes '::'.
+ * lex.c (real_yylex): Remove 'namespace' warning.
+ * init.c (build_member_call): Ignore 'std::'.
+ (build_offset_ref): Likewise.
+ * decl2.c (do_using_directive): Ignore 'using namespace std;'.
+ (do_toplevel_using_decl): Ignore 'using std::whatever'.
+ * decl.c (push_namespace): Just sorry.
+ (pop_namespace): Nop.
+ (init_decl_processing): Declare std namespace.
- * parse.y (template_parm): Support default template parms.
- * pt.c (process_template_parm): Ditto.
- (end_template_parm_list): Ditto.
- (coerce_template_parms): Ditto.
- (mangle_class_name_for_template): Ditto.
- (push_template_decls): Ditto.
- (unify): Ditto.
- * method.c (build_overload_identifier): Ditto.
- * error.c (dump_decl): Ditto.
+Tue Jun 3 18:08:23 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Jul 27 17:47:00 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * search.c (push_class_decls): A name which ambiguously refers to
+ several instantiations of the same template just refers to the
+ template.
- * pt.c (do_type_instantiation): Only instantiate nested *classes*.
+Tue Jun 3 12:30:40 1997 Benjamin Kosnik <bkoz@cirdan.cygnus.com>
-Tue Jul 26 13:22:40 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (build_enumerator): fix problem with unsigned long
+ enumerated values being smashed to ints, causing overflow
+ when computing next enumerated value. (for enum values around
+ MAX_VAL).
- * search.c (note_debug_info_needed): Also emit debugging information
- for the types of fields.
+Mon Jun 2 17:40:56 1997 Jason Merrill <jason@yorick.cygnus.com>
-Mon Jul 25 00:34:44 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (build_component_ref): Only call mark_used on a decl.
- * pt.c (lookup_template_class): Pass 'template' to
- coerce_template_parms instead of 'in_decl', since it's a more
- meaningful context.
+Thu May 29 15:54:17 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * typeck.c (c_expand_return): Make sure any cleanups for the return
- expression get run.
- (build_c_cast): Use CONVERT_EXPR for conversion to void.
+ * typeck.c (build_c_cast): Make the check for a ptr to function
+ more specific before possible default_conversion call.
- * pt.c (do_type_instantiation): Also instantiate nested types.
+Thu May 29 13:02:06 1997 Mike Stump <mrs@cygnus.com>
- * typeck.c (convert_for_assignment): Don't die when comparing
- pointers with different levels of indirection.
+ * except.c (expand_exception_blocks): Simplify and fix and make
+ sure we don't end a region in a sequence, as expand_end_bindings
+ doesn't like it.
- * decl.c (grokdeclarator): The sub-call to grokdeclarator for
- class-local typedefs sets DECL_ARGUMENTS, so we need to clear it
- out.
+Wed May 28 17:08:03 1997 Mike Stump <mrs@cygnus.com>
- * decl2.c (finish_anon_union): Don't die if the union has no
- members.
+ * except.c (init_exception_processing): Mark terminate as not
+ returning so that the optimizer can optimize better.
- * decl.c (grokdeclarator): Undo changes to declspecs when we're done
- so that 'typedef int foo, bar;' will work.
+Tue May 27 19:49:19 1997 Mike Stump <mrs@cygnus.com>
- * decl2.c (finish_file): Don't call expand_aggr_init for
- non-aggregates.
+ * cvt.c (convert): Don't do any extra work, if we can avoid it
+ easily.
-Mon Jul 25 00:03:10 1994 Teemu Torma (tot@trema.fi)
+Tue May 27 18:21:47 1997 Mike Stump <mrs@cygnus.com>
- * decl.c (finish_function): We can't inline constructors and
- destructors under some conditions with -fpic, but don't unset
- DECL_INLINE.
+ * *.[chy]: Change cp_convert to ocp_convert, change convert to
+ cp_convert. convert is now reserved for the backend, and doesn't
+ have the semantics a frontend person should ever want.
-Mon Jul 25 00:03:10 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri May 23 10:58:31 1997 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_object_ref): Make sure 'datum' is a valid object.
+ * lang-specs.h: Define __EXCEPTIONS if exceptions are enabled.
+ Lose -traditional support.
-Sun Jul 24 14:19:31 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu May 22 15:41:28 1997 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): Don't set DECL_FIELD_BITPOS on
- non-fields.
- (finish_struct_methods): Use copy_assignment_arg_p.
+ * rtti.c (get_tinfo_var): Use TYPE_PRECISION (sizetype).
- * cvt.c (cp_convert): If expr is an OFFSET_REF, resolve it instead
- of giving an error.
+ * parse.y (self_reference): Do it for templates, too.
+ * class.c (pushclass): Don't overload_template_name; the alias
+ generated by build_self_reference serves the same purpose.
- * typeck.c (build_binary_op_nodefault): Don't set result_type if we
- don't know how to compare the operands.
+ * tree.c (list_hash): Make static, take more args.
+ (list_hash_lookup): Likewise.
+ (list_hash_add): Make static.
+ (list_hash_canon): Lose.
+ (hash_tree_cons): Only build a new node if one isn't already in the
+ hashtable.
+ (hash_tree_chain): Use hash_tree_cons.
+ * cp-tree.h: Adjust.
+ * decl.c (grokfndecl): Just check IDENTIFIER_GLOBAL_VALUE instead
+ of calling lookup_name.
- * decl.c (grokdeclarator): Avoid seg fault when someone uses '__op'
- as a declarator-id in their program. Like the Linux headers do.
- Arrgh.
+Wed May 21 18:24:19 1997 Jason Merrill <jason@yorick.cygnus.com>
- * tree.c (lvalue_p): Treat calls to functions returning objects by
- value as lvalues again.
+ * pt.c (instantiate_class_template): TYPE_VALUES for an enum
+ doesn't refer to the CONST_DECLs.
- * typeck.c (build_component_addr): Use convert_force to convert the
- pointer in case the component type is also a private base class.
+Tue May 20 21:09:32 1997 Bob Manson <manson@charmed.cygnus.com>
- * search.c (get_matching_virtual): Fix bogus warning of overloaded
- virtual.
+ * rtti.c (get_tinfo_var): Either INT_TYPE_SIZE or 32, whichever
+ is bigger.
+ (expand_class_desc): Convert the last argument to a sizetype.
- * pt.c (overload_template_name): Set DECL_ARTIFICIAL on the created
- TYPE_DECL to fix bogus shadowing warnings.
+Tue May 20 13:55:57 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
-Fri Jul 22 01:15:32 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * gxx.gperf (__complex, __complex__, __imag, __imag__, __real,
+ __real__): Add reswords.
+ * hash.h: Regenerate.
+ * lex.h (rid): Add RID_COMPLEX.
+ (RID_LAST_MODIFIER): Set to RID_COMPLEX.
+ * lex.c (init_lex): Add building of RID_COMPLEX.
+ (real_yylex): General cleanup in line with what c-lex.c also has,
+ sans the cruft for traditional; add handling of SPEC_IMAG, complex
+ types, and imaginary numeric constants.
+ * parse.y (REALPART, IMAGPART): Add tokens.
+ (unary_expr): Add REALPART and IMAGPART rules.
+ * cp-tree.h (complex_{integer,float,double,long}_type_node): Declare.
+ * decl.c (complex_{integer,float,double,long}_type_node): Define
+ types.
+ (init_decl_processing): Set up the types.
+ (grokdeclarator): Add handling of RID_COMPLEX. Set and use
+ DEFAULTED_INT instead of EXPLICIT_INT when we default to int type.
+ * call.c (build_new_op): Add REALPART_EXPR and IMAGPART_EXPR cases.
+ * cvt.c (cp_convert): Handle COMPLEX_TYPE.
+ * error.c (dump_type_prefix, dump_type, dump_type_suffix): Add
+ COMPLEX_TYPE case.
+ * method.c (build_overload_name): Add handling of the different
+ COMPLEX_TYPEs, prefixing them with `J'.
+ * pt.c (process_template_parm): Don't let them use a COMPLEX_TYPE
+ as a template parm.
+ (uses_template_parms, tsubst, unify): Add COMPLEX_TYPE case.
+ * tree.c (lvalue_p): Add REALPART_EXPR and IMAGPART_EXPR cases.
+ (mapcar): Handle COMPLEX_CST.
+ * typeck.c (build_binary_op_nodefault): Handle COMPLEX_TYPE.
+ (common_type): Add code for complex types.
+ (build_unary_op): Add REALPART_EXPR and IMAGPART_EXPR cases.
+ (convert_for_assignment): Likewise.
+ (mark_addressable): Add REALPART_EXPR and IMAGPART_EXPR cases.
+
+Mon May 19 12:26:27 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * pt.c (tsubst): Don't pass the MINUS_EXPR for an array domain to
+ tsubst_expr, as it might try to do overload resolution.
+
+Sat May 17 10:48:31 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * pt.c (instantiate_class_template): Oops.
+
+Fri May 16 14:23:57 1997 Jason Merrill <jason@yorick.cygnus.com>
+
+ * cp-tree.def: Add TAG_DEFN.
+ * pt.c (tsubst_enum): New fn.
+ (instantiate_class_template): Use it.
+ (tsubst_expr): Support TAG_DEFN.
+ (tsubst): Support local enums.
+ (tsubst_copy): Likewise.
+ * decl.c (finish_enum): Likewise.
+ (start_enum): If this is a local enum, switch to permanent_obstack.
+
+Wed May 14 19:08:28 1997 Mike Stump <mrs@cygnus.com>
+
+ * decl.c (store_parm_decls): Set last_parm_cleanup_insn here.
+ (finish_function): Put the base init code for constructors just
+ after the parm cleanup insns.
+ (struct cp_function): Add last_parm_cleanup_insn.
+ (push_cp_function_context): Likewise.
+ (pop_cp_function_context): Likewise.
+
+Tue May 13 15:51:20 1997 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (expand_aggr_init_1): const and volatile mismatches do not
- prevent a TARGET_EXPR from initializing an object directly.
+ * pt.c (tsubst_copy): Handle BIT_NOT_EXPR.
-Tue Jul 19 17:55:37 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed May 7 11:17:59 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cvt.c (build_up_reference): Allow building up references to
- `this', don't warn about making references to artificial variables
- (like `this').
+ * method.c (emit_thunk) [ASM_OUTPUT_MI_THUNK]: Build up the RTL
+ for THUNK_FNDECL before we switch to temporary allocation.
- * tree.c (lvalue_p): `this' is not an lvalue.
+Mon May 5 14:46:53 1997 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_method_call): Accept using a typedef name (or
- template type parameter) for explicit destructor calls.
+ * call.c (build_new_op): Handle null arg2 for ?:.
-Wed Jul 13 03:57:54 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu May 1 18:26:37 1997 Mike Stump <mrs@cygnus.com>
- * method.c (hack_identifier): Put back old code so lists of
- non-functions will be handled properly.
+ * except.c (expand_exception_blocks): Ensure that we flow through
+ the end of the exception region for the exception specification.
+ Move exception region for the exception specification in, so that
+ it doesn't protect the parm cleanup. Remove some obsolete code.
+ * decl.c (store_parm_decls): Likewise.
+ (finish_function): Likewise.
- * cp-tree.h (TYPE_NEEDS_CONSTRUCTING): #if 0 out; this macro is now
- defined in the language-independent tree.h.
+Tue Apr 29 15:38:54 1997 Jason Merrill <jason@yorick.cygnus.com>
- * tree.c (count_functions): Avoid bogus warning when compiling this
- function.
+ * init.c (build_new): Fix nothrow handling.
-Mon Jul 11 18:37:20 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue Apr 29 14:29:50 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c (grok_reference_init): Always save the initializer of a
- reference.
+ * init.c (emit_base_init): Don't warn about the initialization
+ list for an artificial member.
-Fri Jul 8 17:41:46 1994 Mike Stump <mrs@cygnus.com>
+Fri Apr 25 17:47:59 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c (cplus_expand_expr_stmt): Wrap statement expressions inside
- CLEANUP_POINT_EXPRs so that the stack slots can be reused.
- (disabled for now)
+ * expr.c (do_case): Handle !START case for the error msg.
-Fri Jul 8 12:59:38 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Apr 25 11:55:23 1997 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (hack_identifier): Fix for new overloading.
+ * decl2.c, lang-options.h: New option -Weffc++.
+ * class.c, decl.c, init.c, typeck.c: Move Effective C++ warnings
+ to -Weffc++.
- * typeck.c (build_binary_op_nodefault): Don't mess with division by
- zero.
+ * decl2.c (finish_prevtable_vardecl): Change NO_LINKAGE_HEURISTICS
+ to MULTIPLE_SYMBOL_SPACES.
-Fri Jul 8 13:20:28 1994 Gerald Baumgartner (gb@cs.purdue.edu)
+Wed Apr 23 18:06:50 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (finish_file): Only call walk_sigtables, if
- flag_handle_signatures is turned on, don't waste time otherwise.
+ * method.c (emit_thunk, generic case): Set current_function_is_thunk.
-Fri Jul 8 02:27:41 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * method.c (emit_thunk, macro case): Set up DECL_RESULT.
- * decl.c (push_overloaded_decl): Don't create overloads of one when
- shadowing a class type.
- * typeck.c (build_x_function_call): Complain about overloads of one.
+ * typeck.c (c_expand_return): Don't complain about returning void
+ to void in an artificial function.
+ * method.c (make_thunk): Change settings of READONLY/VOLATILE,
+ don't set DECL_RESULT, set DECL_ARTIFICIAL.
+ (emit_thunk, generic code): Also set up DECL_LANG_SPECIFIC.
- * decl.c (grokdeclarator): Don't try to treat a char* as a tree.
- (grokdeclarator): Fix setting of TREE_STATIC.
- (start_decl): Clear DECL_IN_AGGR_P after calling duplicate_decls.
+Wed Apr 23 14:43:06 1997 Mike Stump <mrs@cygnus.com>
-Thu Jul 7 22:20:46 1994 Gerald Baumgartner (gb@andros.cygnus.com)
+ * init.c (init_decl_processing): Add supoprt for setjmp/longjmp based
+ exception handling.
+ * except.c (init_exception_processing): Likewise.
+ (expand_end_catch_block): Likewise.
+ (expand_exception_blocks): Likewise.
+ (expand_throw): Likewise.
+ * exception.cc (__default_terminate): Likewise.
- * cp-tree.h (walk_sigtables): Created extern declaration.
- * decl2.c (walk_sigtables): Created function, patterned after
- walk_vtables, even though we only need it to write out sigtables.
- (finish_sigtable_vardecl): Created function.
- (finish_vtable_vardecl): Changed 0 to NULL_PTR.
- (finish_file): Call walk_sigtables.
+ * init.c (perform_member_init): Use new method of expr level
+ cleanups, instead of cleanups_this_call and friends.
+ (emit_base_init): Likewise.
+ (expand_aggr_vbase_init_1): Likewise.
+ (expand_vec_init): Likewise.
+ * decl.c (cp_finish_decl): Likewise.
+ (expand_static_init): Likewise.
+ (store_parm_decls): Likewise.
+ (cplus_expand_expr_stmt): Likewise.
+ * decl2.c (finish_file): Likewise.
+
+ * Make-lang.in (exception.o): Ok to compile with -O now.
- * sig.c (build_signature_table_constructor): Mark class member
- function pointed to from signature table entry as addressable.
+ * decl.c (maybe_build_cleanup_1): We no longer have to unsave, as
+ we know it will be done later by the backend.
-Thu Jul 7 13:39:37 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (lang_f_options): Remove support for short temps.
+ * lang-options.h: Likewise.
+
+Wed Apr 23 04:12:06 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (start_decl): Check new decl of static member variable
- against the declaration in the class here.
- (grokvardecl): Instead of here.
+ * tree.c (varargs_function_p): New fn.
+ * method.c (emit_thunk): Replace broken generic code with code to
+ generate a heavyweight thunk function.
- * class.c (prepare_fresh_vtable): Call import_export_vtable if not
- -fvtable-thunks.
- (build_vtable): Ditto.
+Tue Apr 22 02:45:18 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (import_export_vtable): Move logic for deciding the
- interface of a template class from here.
- (import_export_template): To here.
- (finish_vtable_vardecl): Call import_export_template before
- import_export_vtable.
+ * pt.c (process_template_parm): pedwarn about floating-point parms.
-Wed Jul 6 20:25:48 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (grokdeclarator): inline no longer implies static.
- * except.c (init_exception_processing): Setup interim_eh_hook to
- call lang_interim_eh.
- * except.c (do_unwind): Propagate throw object value across
- stack unwinding.
- * except.c (saved_throw_value): Used to hold the value of the object
- being thrown. It is always a reference to the real value.
- * except.c (expand_start_catch_block): Add handling for the
- value of the exception object.
- * except.c (expand_start_catch_block): Add handler for the handler,
- so that throws inside the handler go to the outer block.
- * except.c (expand_end_catch_block): Ditto.
- * parse.y (handler_args): Use parm instead, as the other doesn't yet
- handle references correctly.
+ * spew.c (yylex): Always return the TYPE_DECL if we got a scope.
-Wed Jul 6 17:55:32 1994 Per Bothner (bothner@kalessin.cygnus.com)
+Mon Apr 21 15:42:27 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (mark_vtable_entries): If -ftable-thunks, set the
- vtable entry properly to abort.
+ * class.c (check_for_override): The signature of an overriding
+ function is not changed.
-Tue Jul 5 14:07:54 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (build_over_call): Move setting of conv into the loop.
+ Note: this change, along with the related changes of the 18th thru
+ the 20th of April, fix an infinite loop problem in conversions.
- * typeck.c (build_binary_op_nodefault): Downgrade division by zero
- errors to warnings.
+Sun Apr 20 16:24:29 1997 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_overload_call_real): Handle fnname being a list of
- functions.
- * typeck.c (build_x_function_call): Pass list of functions to
- build_overload_call, not just the name.
- * tree.c (count_functions): Complain when called for invalid
- argument.
+ * call.c (build_user_type_conversion_1): Really ignore rvalue
+ conversions when looking for a REFERENCE_TYPE.
- * decl.c (grokdeclarator): Fix settings of TREE_STATIC, TREE_PUBLIC
- and DECL_EXTERNAL on static members and initialized const members.
- * decl2.c (grokfield): Reflect this change.
+ * cvt.c (build_up_reference): Eviscerate, use build_unary_op.
+ * cp-tree.h (TREE_REFERENCE_EXPR): #if 0.
+ * typeck.c (decay_conversion): Don't set TREE_REFERENCE_EXPR.
+ (build_unary_op): Likewise.
+ * call.c (build_over_call): See through a CONVERT_EXPR around the
+ ADDR_EXPR for on a temporary.
+ * typeck.c (c_expand_return): See through a CONVERT_EXPR around
+ the ADDR_EXPR for a local variable.
-Fri Jul 1 09:35:51 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Apr 18 12:11:33 1997 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (init): ANSI C++ does not forbid { }.
+ * call.c (build_user_type_conversion_1): If we're trying to
+ convert to a REFERENCE_TYPE, only consider lvalue conversions.
+ (build_new_function_call): Print candidates.
+ (implicit_conversion): Try a temp binding if the lvalue conv is BAD.
+ (reference_binding): Binding a temporary of a reference-related type
+ is BAD.
-Thu Jun 30 00:35:22 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu Apr 17 14:37:22 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl2.c (lang_decode_option): Set warn_nonvdtor along with -Wall.
- warn_nonvdtor defaults to off.
+ * inc/typeinfo (type_info::before): Add cv-qualifier-seq.
+ * tinfo2.cc (type_info::before): Likewise.
- * class.c (instantiate_type): Use comptypes rather than relying on
- types to satisfy ==.
+Mon Apr 14 12:38:17 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (start_function): Set DECL_DEFER_OUTPUT on all inlines that
- might be static.
+ * call.c (implicit_conversion): Oops.
- * tree.c (build_cplus_new): Never build WITH_CLEANUP_EXPRs.
+Fri Apr 11 02:18:30 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grok_reference_init): Deal with ADDR_EXPRs of TARGET_EXPRs.
+ * call.c (implicit_conversion): Try to find a reference conversion
+ before binding a const reference to a temporary.
- * cvt.c (cp_convert): Pass 0 to with_cleanup_p arg of
- build_cplus_new.
+Wed Apr 2 12:51:36 1997 Mike Stump <mrs@cygnus.com>
-Wed Jun 29 22:31:09 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * exception.cc (__default_unexpected): Call terminate by default,
+ so that if the user overrides terminate, the correct function will
+ be called.
+
+Wed Mar 19 14:14:45 1997 Mike Stump <mrs@cygnus.com>
- * decl2.c (finish_file): Maybe consider static inlines multiple
- times, in case they reference each other.
+ * parse.y (left_curly): Avoid trying to use any fields of
+ error_mark_node, as there aren't any.
-Tue Jun 28 11:58:38 1994 Gerald Baumgartner (gb@cs.purdue.edu)
+Thu Mar 13 16:33:22 1997 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): Don't `cons_up_default_function's
- for signatures.
- (finish_struct): Handle an empty method_vec correctly.
+ * lex.c (do_identifier): Avoid breaking on overloaded methods
+ as default arguments.
- * decl.c (grokdeclarator): Don't warn about a signature being
- empty in a signature pointer declaration if we only saw a
- forward declaration of the signature. Changed `warning's into
- `cp_warning's.
+Wed Mar 12 13:55:10 1997 Hans-Peter Nilsson <Hans-Peter.Nilsson@axis.se>
- * sig.c (build_sigtable): Don't die if a null signature table
- constructor is returned.
- (build_signature_pointer_constructor): If the signature table
- constructor is null, the _sptr field is set to a null pointer
- and cast to the appropriate type. Make copies of all null
- pointers so that the type null_pointer_node doesn't get changed.
- (build_signature_table_constructor): Added comments.
+ * call.c (add_template_candidate): Initialize the variable "dummy".
- * sig.c (build_signature_pointer_constructor): Complain if we
- try to assign to/initialize a signature pointer/reference of
- an undefined signature.
+Mon Mar 10 15:13:14 1997 Brendan Kehoe <brendan@canuck.cygnus.com>
-Mon Jun 27 14:05:16 1994 Gerald Baumgartner (gb@cs.purdue.edu)
+ * decl.c (start_decl): Make sure TYPE isn't an error_mark_node
+ before we try to use TYPE_SIZE and TREE_CONSTANT on it.
- * typeck2.c (store_init_value): Don't be pedantic about
- non-constant initializers of signature tables/pointers/references.
+Fri Mar 7 13:19:36 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
-Fri Jun 24 16:49:41 1994 Gerald Baumgartner (gb@cs.purdue.edu)
+ * cp-tree.h (comp_ptr_ttypes, more_specialized): Add decl.
+ (debug_binfo): Delete decl, not needed.
- * decl.c (grokdeclarator): If we are grokking an opaque typedef
- in a signature, don't complain about it begin static.
+ * tree.c (fnaddr_from_vtable_entry, function_arg_chain,
+ promotes_to_aggr_type): Delete fns.
+ * cp-tree.h (FNADDR_FROM_VTABLE_ENTRY,
+ SET_FNADDR_FROM_VTABLE_ENTRY, FUNCTION_ARG_CHAIN,
+ PROMOTES_TO_AGGR_TYPE): Delete alternates to #if 1.
-Wed Jun 29 16:44:45 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (pending_invalid_xref{,_file,_line}): Delete unused vars.
- Fixes a problem of the this pointer being wrong in virtual calls to
- methods that are not overridden in more derived classes.
+ * friend.c (is_friend_type): Delete fn.
+ * cp-tree.h (is_friend_type): Delete decl.
- * class.c (fixup_vtable_delta): New routine. It will fixup the
- delta entries in vtables, wheever they need updating.
- * class.c (finish_struct): Call the new routine for all virtual
- bases, as they can have different offsets, than those used in base
- classes that we derive our vtable from.
+ * decl.c (original_result_rtx, double_ftype_double,
+ double_ftype_double_double, int_ftype_int, long_ftype_long,
+ float_ftype_float, ldouble_ftype_ldouble, last_dtor_insn): Make static.
+ * typeck.c (original_result_rtx, warn_synth): Delete extern decls.
-Tue Jun 28 23:49:28 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (push_overloaded_decl{,_top_level}): Make static, adding
+ fwd decls.
+ * cp-tree.h (push_overloaded_decl{,_top_level}): Delete decls.
- * typeck.c (build_binary_op): Use the types before default
- conversions in the error message.
+ * decl.c (pushdecl_nonclass_level): #if 0, unused.
+ * cp-tree.h (pushdecl_nonclass_level): #if 0 decl.
- * *.c: Use c_build_type_variant instead of build_type_variant where
- the type might be an array.
+ * lex.c (reinit_lang_specific): #if 0, unused.
+ * cp-tree.h (reinit_lang_specific): #if 0 decl.
- * call.c (build_method_call): Call build_type_variant and
- build_reference_type in the right order.
- * decl.c (record_builtin_type): Ditto.
+ * decl.c (revert_static_member_fn): Make static, adding fwd decl.
+ * cp-tree.h (revert_static_member_fn): Delete decl.
-Wed Jun 29 16:58:53 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * class.c (root_lang_context_p): Delete fn.
+ * cp-tree.h (root_lang_context_p): Delete decl.
- * call.c (build_method_call): Call build_type_variant and
- build_reference_type in the right order.
- * decl.c (record_builtin_type): Ditto.
+ * decl.c (set_current_level_tags_transparency): #if 0, unused.
+ * cp-tree.h (set_current_level_tags_transparency): #if 0 decl.
-Tue Jun 28 23:49:28 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * lex.c (set_vardecl_interface_info): Make static.
+ * cp-tree.h (set_vardecl_interface_info): Delete decl.
- * typeck.c (build_binary_op): Use the types before default
- conversions in the error message.
+ * call.c (find_scoped_type): Make static.
+ * cp-tree.h (find_scoped_type): Delete decl.
- * *.c: Use c_build_type_variant instead of build_type_variant where
- the type might be an array.
+ * search.c (convert_pointer_to_vbase): Make static.
+ * cp-tree.h (convert_pointer_to_vbase): Delete decl.
-Sat Jun 25 11:50:54 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (const_ptr_type_node): Likewise.
+ * cp-tree.h (const_ptr_type_node): Delete decl.
- * cvt.c (convert_to_reference): Try UDC's before doing the
- reinterpret_cast thang, though.
+ * typeck.c (common_base_type): Make static.
+ * cp-tree.h (common_base_types): Delete erroneous decl.
-Fri Jun 24 01:24:01 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (classtype_mangled_name): Make static.
+ * cp-tree.h (classtype_mangled_name): Delete decl.
- * typeck.c (c_expand_return): Don't USE the return value location
- after we've expanded the jump.
+ * lex.c (check_newline): Make static.
+ * cp-tree.h (check_newline): Delete decl.
- * decl2.c (finish_file): Make sure DECL_SAVED_INSNS is not 0 before
- trying to write out an inline.
+ * typeck.c (build_x_array_ref): Delete fn, same idea as
+ grok_array_decl.
+ * cp-tree.h (build_x_array_ref): Delete decl.
- * cvt.c (build_up_reference): Also do address adjustment when the
- target type uses MI.
- (convert_to_reference): Try UDCs only after built-in conversions.
- (build_type_conversion_1): Don't play games with the argument to the
- method.
- (build_type_conversion): #if 0 out code for binding to reference.
+ * lex.c (copy_decl_lang_specific): Delete fn, same idea as
+ copy_lang_decl.
+ * cp-tree.h (copy_decl_lang_specific): #if 0 decl.
-Thu Jun 23 00:22:28 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * class.c (build_vtable_entry): Make static.
+ * cp-tree.h (build_vtable_entry): Delete decl.
- * decl2.c (finish_file): Use TREE_SYMBOL_REFERENCED to decide
- whether to emit inlines.
+ * class.c (build_vbase_pointer): Make static.
+ * cp-tree.h (build_vbase_pointer): Delete decl.
- * decl.c (grokdeclarator): Set explicit_int for decls that just
- specify, say, 'long'.
+ * sig.c (build_sptr_ref): Add forward decl and make static.
+ * cp-tree.h (build_sptr_ref): Delete decl.
- * init.c (do_friend): Do overload C functions (or call pushdecl,
- anyaway).
+ * call.c (build_new_method_call): Add forward decl and make static.
+ * cp-tree.h (build_new_method_call): Delete decl.
-Wed Jun 22 13:40:49 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (build_object_call): Make static.
+ * class.c (check_for_override, complete_type_p, mark_overriders):
+ Likewise.
+ * decl.c (cp_function_chain): Likewise.
+ * lex.c (set_typedecl_interface_info, reinit_parse_for_block):
+ Likewise.
+ * pt.c (comp_template_args, get_class_bindings, push_tinst_level):
+ Likewise.
+ * tree.c (build_cplus_array_type_1): Likewise.
+ * typeck.c (comp_ptr_ttypes_{const,real,reinterpret}): Likewise.
+ (comp_target_parms): Likewise.
- * cvt.c (build_up_reference): Don't call readonly_error.
- (convert_to_reference): Propagate const and volatile from expr to
- its type.
+ * init.c (build_builtin_call): Make static.
+ * cp-tree.h (build_builtin_call): Delete decl.
- * tree.c (lvalue_p): Random CALL_EXPRs are not lvalues.
+ * typeck.c (binary_op_error): Delete decl.
+ * cp-tree.h (binary_op_error): Likewise.
- * cvt.c (build_up_reference): Break out WITH_CLEANUP_EXPR when
- creating a temporary.
- (convert_to_reference): Lose excessive and incorrect trickiness.
- (cp_convert): Call build_cplus_new with with_cleanup_p set.
+Thu Mar 6 16:13:52 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * typeck2.c (build_functional_cast): Ditto.
+ * call.c (build_method_call): Compare against error_mark_node
+ directly, rather than the ERROR_MARK tree code.
+ * cvt.c (cp_convert): Likewise.
+ * decl.c (print_binding_level): Likewise.
+ (duplicate_decls): Likewise.
+ (grokdeclarator): Likewise.
+ (grokdeclarator): Likewise.
+ * init.c (expand_aggr_init_1): Likewise.
+ (decl_constant_value): Likewise.
+ * method.c (build_opfncall): Likewise.
+ (hack_identifier): Likewise.
+ * typeck.c (build_modify_expr): Likewise.
-Tue Jun 21 17:38:38 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (build_c_cast): Don't decl TYPE as register tree.
- * decl.c (grokdeclarator): signed, unsigned, long and short all
- imply 'int'.
+Sun Mar 2 02:54:36 1997 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
- * decl.c (grokdeclarator): Allow "this is a type" syntax.
- (grok_reference_init): Simplify and fix.
+ * pt.c (unify): Strip NOP_EXPR wrappers before unifying integer values.
-Sun Jun 19 17:08:48 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (coerce_template_parms): Add new error message.
- * decl.c (grokdeclarator): pedwarn about a typedef that specifies no
- type.
+ * method.c (build_overload_value): Implement name mangling for
+ floating-point template arguments.
-Sat Jun 18 04:16:50 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * method.c (build_overload_int, icat, dicat): Fix mangling of template
+ arguments whose absolute value doesn't fit in a signed word.
- * decl.c (start_function): Move TREE_PUBLIC and DECL_EXTERNAL
- tinkering to after call to pushdecl.
+Mon Mar 3 12:14:54 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
-Fri Jun 17 14:48:28 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * friend.c: New file; put all of the friend stuff in here.
+ * init.c: Instead of here.
+ * Makefile.in (CXX_OBJS): Add friend.o.
+ (friend.o): Add dependencies.
+ * Make-lang.in (CXX_SRCS): Add $(srcdir)/cp/friend.c.
- * call.c (build_method_call): Handle destructors for non-aggregate
- types properly.
+Sun Mar 2 11:04:43 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Jun 16 16:48:05 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (build_scoped_method_call): Complain if the scope isn't a
+ base.
- * call.c (build_method_call): Make sure that the name given for the
- destructor matches the constructor_name of the instance.
+Wed Feb 26 11:31:06 1997 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (do_function_instantiation): A non-extern instantiation
- overrides a later extern one.
- (do_type_instantiation): Ditto.
+ * parse.y (left_curly): Don't crash on erroneous type.
-Wed Jun 15 19:34:54 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * init.c (build_delete): Fix type of ref.
- * init.c (expand_aggr_init): Use TYPE_MAIN_VARIANT to get the
- unqualified array type.
+Tue Feb 25 12:41:48 1997 Jason Merrill <jason@yorick.cygnus.com>
- * cp-tree.h (EMPTY_CONSTRUCTOR_P): Tests whether NODE is a
- CONSTRUCTOR with no elements.
+ * search.c (get_vbase_1): Renamed from get_vbase.
+ (get_vbase): Wrapper, now non-static.
+ (convert_pointer_to_vbase): Now static.
- * decl.c (various): Lose empty_init_node.
- (finish_decl): Use EMPTY_CONSTRUCTOR_P, do the empty CONSTRUCTOR
- thing depending on the value of DECL_COMMON instead of
- flag_conserve_space, do the empty CONSTRUCTOR thing for types that
- don't have constructors, don't treat a real empty CONSTRUCTOR
- specially.
+ * call.c (build_scoped_method_call): Accept a binfo for BASETYPE.
+ * init.c (build_delete): Pass one.
+ (build_partial_cleanup_for): Use build_scoped_method_call.
+ * decl.c (finish_function): Pass a binfo.
- * typeck2.c (process_init_constructor): Don't treat empty_init_node
- specially.
+Mon Feb 24 15:00:12 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Jun 15 19:05:25 1994 Mike Stump <mrs@cygnus.com>
+ * call.c (build_over_call): Only synthesize non-trivial copy ctors.
- * class.c (override_one_vtable): Don't forget to merge in an old
- overrider when we wanted to reuse a vtable, but couldn't.
+ * typeck.c (build_c_cast): Lose other reference to flag.
-Wed Jun 15 15:03:16 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (build_field_call): Don't look for [cd]tor_identifier.
+ * decl2.c (delete_sanity): Remove meaningless use of
+ LOOKUP_HAS_IN_CHARGE.
+ * decl.c (finish_function): Use build_scoped_method_call instead
+ of build_delete for running vbase dtors.
+ * init.c (build_delete): Call overload resolution code instead of
+ duplicating it badly.
- * decl.c (start_decl): Put statics in common again.
+Thu Feb 20 15:12:15 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokdeclarator): Return NULL_TREE for an error rather than
- setting the type to error_mark_node.
+ * call.c (build_over_call): Call mark_used before trying to elide
+ the call.
- * typeck.c (build_modify_expr): Build up a COMPOUND_EXPR for enum
- bitfield assignments.
+ * decl.c (implicitly_declare): Don't set DECL_ARTIFICIAL.
-Tue Jun 14 12:23:38 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Feb 19 11:18:53 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c (grok_op_properties): Const objects can be passed by value.
+ * typeck.c (build_modify_expr): Always pedwarn for a cast to
+ non-reference used as an lvalue.
-Mon Jun 13 03:10:59 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Feb 19 10:35:37 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (import_export_vtable): Force implicit instantiations to
- be interface_only when -fno-implicit-templates.
+ * cvt.c (cp_convert_to_pointer): Convert from 0 to a pmf properly.
- * decl.c (duplicate_decls): Redeclaring a class template name is an
- error.
+Tue Feb 18 15:40:57 1997 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (end_template_decl): Call GNU_xref_decl for class templates.
- * xref.c (GNU_xref_decl): Support templates.
+ * parse.y (handler): Fix template typo.
-Sat Jun 11 17:09:05 1994 Jason Merrill (jason@deneb.cygnus.com)
+Sun Feb 16 02:12:28 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grok_op_properties): Split out checking for whether this
- function should suppress the default assignment operator.
- * decl2.c (grok_function_init): Ditto.
- (copy_assignment_arg_p): New function do do just that.
- Now considers virtual assignment operators that take a base as an
- argument to count as copy assignment operators.
+ * error.c (lang_decl_name): New fn.
+ * tree.c (lang_printable_name): Use it.
- * search.c (dfs_debug_mark): Lose checks for DWARF_DEBUG and
- TREE_ASM_WRITTEN, as they are redundant.
+Fri Feb 14 16:57:05 1997 Mike Stump <mrs@cygnus.com>
- * pt.c (end_template_decl): Don't try to set DECL_CLASS_CONTEXT on a
- decl that has no LANG_SPECIFIC part.
- (do_type_instantiation): Force the debugging information for this
- type to be emitted.
+ * g++spec.c: Include config.h so that we can catch bzero #defines
+ from the config file.
- * decl.c (start_decl): Clear up uses of various types of templates
- (say sorry for static data members, rather than "invalid template").
- (expand_static_init): Fix initialization of static data members of
- template classes.
+Tue Feb 11 13:50:48 1997 Mike Stump <mrs@cygnus.com>
-Fri Jun 10 00:41:19 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * new1.cc: Include a declaration for malloc, to avoid warning, and
+ avoid lossing on systems that require one (ones that define malloc
+ in xm.h).
- * decl.c (grokdeclarator): Set DECL_CONTEXT on static data members.
+Mon Feb 10 22:51:13 1997 Bruno Haible <bruno@linuix.mathematik.uni-karlsruhe.de>
- * g++.c (main): Use -xc++-cpp-output for .i files.
+ * decl2.c (max_tinst_depth): New variable.
+ (lang_decode_option): Parse "-ftemplate-depth-NN" command line
+ option.
+ * pt.c (max_tinst_depth): Variable moved.
+ * lang-options.h: Declare "-ftemplate-depth-NN" command line option
+ as legal.
- * pt.c (tsubst): Give meaningful error about declaring template for
- a copy constructor which was not declared in the class template.
- (do_type_instantiation): Explicit instantiation before the class
- template is an error.
- (instantiate_template): Don't die if tsubst returns error_mark_node.
+Fri Feb 7 15:43:34 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu Jun 9 19:04:59 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (xref_basetypes): Allow a base class that depends on
+ template parms to be incomplete.
- Don't synthesize the copy assignment operator if the one in a base
- class is pure virtual.
- * cp-tree.h (TYPE_HAS_ABSTRACT_ASSIGN_REF): New macro to indicate
- whether the type has a pure virtual copy assignment operator.
- * class.c (finish_base_struct): Don't generate the copy assignment
- operator if a base class has a pure virtual one.
- * decl.c (grok_op_properties): Add disabled code to set
- TYPE_HAS_ABSTRACT_ASSIGN_REF with comment pointing to where it is
- actually set.
- * decl2.c (grok_function_init): Set TYPE_HAS_ABSTRACT_ASSIGN_REF.
+ * decl2.c (build_expr_from_tree): Support typeid(type).
+ * rtti.c (get_typeid): Support templates.
+ (expand_si_desc, expand_class_desc): Fix string length.
+ (expand_ptr_desc, expand_attr_desc, expand_generic_desc): Likewise.
- * decl2.c (import_export_vtable): Always treat template
- instantiations as if write_virtuals >= 2, and treat implicit
- instantiations as external if -fno-implicit-templates.
- (finish_file): Output all pending inlines if
- flag_keep_inline_functions.
+Tue Feb 4 11:28:24 1997 Jason Merrill <jason@yorick.cygnus.com>
-Wed Jun 8 20:48:02 1994 Mike Stump <mrs@cygnus.com>
+ * pt.c (unify, case TEMPLATE_CONST_PARM): Use cp_tree_equal.
- * tree.c (layout_vbasetypes): Align virtual base classes inside
- complete objects, so that we don't core dump on machines such as
- SPARCs when we access members that require larger than normal
- alignments, such as a double. Also, we bump up the total alignment
- on the complete type, as necessary.
+ * pt.c (tsubst): Put it back for -fno-ansi-overloading.
-Wed Jun 8 16:18:14 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Feb 3 18:41:12 1997 Jason Merrill <jason@yorick.cygnus.com>
- * gxxint.texi (Free Store): New section with code for examining
- cookie.
- (Limitations of g++): Remove operator delete entry, since it is no
- longer accurate. Fix access control entry.
+ * pt.c (tsubst, case FUNCTION_DECL): Lose obsolete code that
+ smashes together template and non-template decls of the same
+ signature.
- * typeck.c (build_unary_op): Pedwarn about taking the address of or
- incrementing a cast to non-reference type.
- (build_modify_expr): Use convert instead of convert_force again.
+Thu Jan 30 19:18:00 1997 Jason Merrill <jason@yorick.cygnus.com>
- * search.c (get_base_distance): Use IS_AGGR_TYPE_CODE to check for
- class type, not == RECORD_TYPE.
+ * pt.c (tsubst): Don't recurse for the type of a TYPENAME_TYPE.
- * decl.c (grokdeclarator): Cope with grokfndecl returning NULL_TREE.
+Wed Jan 29 11:40:35 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * typeck2.c (report_case_error): #if 0 out.
- * lex.c (real_yylex): Lose RANGE.
- * parse.y: Ditto.
+ * decl.c (duplicate_decls): Next route, pedwarn about different
+ exceptions if -pedantic *or* olddecl !DECL_IN_SYSTEM_HEADER.
-Tue Jun 7 18:17:35 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue Jan 28 20:43:29 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * parse.y (simple_stmt, case ranges): Use ELLIPSIS instead of RANGE.
+ * cp-tree.h (HAS_DEFAULT_IMPLEMENTATION): Delete macro.
+ (struct lang_type): Delete has_default_implementation member.
+ Increase dummy to 21.
+ * decl.c (start_method): Delete usage.
-Mon Jun 6 19:39:57 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * cp-tree.h (build_call, null_ptr_cst_p, in_function_p,
+ store_after_parms, start_decl_1, auto_function): Add decls.
+ (get_arglist_len_in_bytes, declare_implicit_exception,
+ have_exceptions_p, make_type_decl, typedecl_for_tag,
+ store_in_parms, pop_implicit_try_blocks, push_exception_cleanup,
+ build_component_type_expr, cplus_exception_name,
+ {make,clear}_anon_parm_name, dont_see_typename): Removed decls.
+ * call.c (build_this): Make static.
+ (is_complete): Likewise.
+ (implicit_conversion): Likewise.
+ (reference_binding): Likewise.
+ (standard_conversion): Likewise.
+ (strip_top_quals): Likewise.
+ (non_reference): Likewise.
+ (build_conv): Likewise.
+ (user_harshness): Likewise.
+ (rank_for_ideal): Likewise.
+ * decl.c (start_decl_1): Delete forward decl.
+ (push_decl_level): Make static.
+ (resume_binding_level): Make static.
+ (namespace_bindings_p): Make static.
+ (declare_namespace_level): Make static.
+ (lookup_name_real): Make static.
+ (duplicate_decls): Make static. Take register off NEWDECL and
+ OLDDECL parm decls.
+ * decl2.c (get_sentry): Make static.
+ (temp_name_p): Delete fn.
+ * except.c (auto_function): Delete decl.
+ * lex.c (handle_{cp,sysv}_pragma): Make static.
+ (handle_sysv_pragma) [HANDLE_SYSV_PRAGMA]: Add forward decl.
+ * method.c (do_build_{copy_constructor,assign_ref}): Make static.
+ * pt.c (tsubst_expr_values): Make static.
+ * rtti.c (combine_strings): Delete decl.
- * typeck.c (build_c_cast): Don't shortcut conversions to the same
- type. Don't replace consts with their values here, since that's now
- done in cp_convert.
+Tue Jan 28 16:40:40 1997 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (cp_convert): When converting to bool, take
- integer_zero_node to false_node and all other INTEGER_CSTs to
- true_node.
- (build_type_conversion): Don't complain about multiple conversions
- to float if we're not really converting.
+ * pt.c (push_template_decl): Handle getting a typedef.
-Fri Jun 3 02:10:56 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (build_new_function_call): Complain about void arg.
- Implement 'extern template class A<int>;' syntax for suppressing
- specific implicit instantiations.
- * cp-tree.h: Update prototypes for do_*_instantiation.
- * pt.c (do_pending_expansions): Don't compile 'extern' explicit
- instantiations.
- (do_function_instantiation): Set DECL_EXTERNAL on 'extern' explicit
- instantiations.
- (do_type_instantiation): Ditto.
- * parse.y (explicit_instantiation): Support 'extern template class
- A<int>;' syntax.
- * decl.c (start_function): Don't modify the settings of TREE_PUBLIC
- and DECL_EXTERNAL on explicit instantiations.
+Tue Jan 28 15:25:09 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cvt.c (cp_convert): Replace constants with their values before
- converting.
- (cp_convert): Consistently use 'e' instead of 'expr'.
+ * decl.c (duplicate_decls): Give pedwarn of different exceptions
+ if -pedantic, instead of olddecl !DECL_IN_SYSTEM_HEADER.
-Thu Jun 2 03:53:30 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Jan 27 19:21:29 1997 Mike Stump <mrs@cygnus.com>
- * typeck2.c (build_x_arrow): Resolve OFFSET_REFs first.
+ * except.c (expand_throw): Don't expand the cleanup tree here,
+ since we are not going to write the rtl out. Fixes problem with
+ -g -O on SPARC.
-Wed Jun 1 18:57:35 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Jan 27 16:24:35 1997 Sean McNeil <sean@mcneil.com>
- * typeck2.c (digest_init): Handle initializing a pmf with an
- overloaded method.
- * typeck.c (build_ptrmemfunc): Handle overloaded methods.
+ * Make-lang.in: Add $(exeext) as necessary.
- * decl.c (pushtag): Use build_decl to make TYPE_DECLs.
- (xref_defn_tag): Ditto.
- * pt.c (process_template_parm): Ditto.
- (lookup_template_class): Ditto.
- (push_template_decls): Ditto.
- (instantiate_class_template): Ditto.
- (create_nested_upt): Ditto.
- * class.c (finish_struct): Don't try to set DECL_CLASS_CONTEXT on
- TYPE_DECLs.
+Mon Jan 27 13:20:39 1997 Mike Stump <mrs@cygnus.com>
- * typeck.c (convert_arguments): Make sure type is not NULL before
- checking its TREE_CODE.
+ * parse.y (handler_seq): Must have at least one catch clause.
-Wed Jun 1 17:40:39 1994 Mike Stump <mrs@cygnus.com>
+Sat Jan 25 12:00:05 1997 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (get_derived_offset): New routine.
- * class.c (finish_base_struct): Make sure we set BINFO_VTABLE and
- BINFO_VIRTUALS when we choose a new base class to inherit from.
- * class.c (modify_one_vtable): Use get_derived_offset to get the
- offset to the most base class subobject that we derived this binfo
- from.
- * class.c (finish_struct): Move code to calculate the
- DECL_FIELD_BITPOS of the vfield up, as we need might need it for
- new calls to get_derived_offset in modify_one_vtable.
-
-Wed Jun 1 16:50:59 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (add_builtin_candidate): Restore ?: hack.
- * init.c (build_member_call): Use build_pointer_type instead of
- TYPE_POINTER_TO.
-
-Wed Jun 1 11:11:15 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * decl.c (grok_op_properties): More warnings.
- * decl.c (grokdeclarator): Make sure we have a DNAME set before we
- try to use it in an error.
+Sat Jan 25 08:50:03 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
-Wed Jun 1 09:48:49 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (duplicate_decls): On second thought, do it as a pedwarn
+ still but only if !DECL_IN_SYSTEM_HEADER (olddecl).
- * typeck.c (convert_arguments, convert_for_initialization): Don't
- strip NOP_EXPRs, when we are converting to a reference.
+ * decl.c (duplicate_decls): Scale back to a warning, and only do
+ 'em if -pedantic.
-Wed Jun 1 01:11:38 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Jan 24 17:52:54 1997 Mike Stump <mrs@cygnus.com>
- * typeck.c (build_modify_expr): Don't dereference references when
- initializing them.
+ * decl.c (duplicate_decls): pedwarn mismatched exception
+ specifications.
- * decl2.c (grokfield): Don't check for grokdeclarator returning
- error_mark_node any more.
+Thu Jan 23 18:18:54 1997 Mike Stump <mrs@cygnus.com>
- * decl.c (grokfndecl): Return NULL_TREE instead of error_mark_node.
- (start_method): Return void_type_node instead of error_mark_node.
+ * call.c (build_new_method_call): Don't display the invisible
+ argument for controlling virtual bases.
- * typeck.c (build_modify_expr): Resolve offset refs earlier.
+Thu Jan 23 16:48:10 1997 Mike Stump <mrs@cygnus.com>
-Tue May 31 16:06:58 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * new: Add nothrow new and delete, bad_alloc and throw specifications
+ for delete.
+ * decl.c (init_decl_processing): Add throw specification for delete.
+ * new.cc (nothrow): Define.
+ * lex.c (real_yylex): Removing warning that throw and friends are
+ keywords.
+ * new1.cc (operator new (size_t sz, const nothrow_t&)): Define.
+ * new2.cc (operator new[] (size_t sz, const nothrow_t&): Define.
+ * Make-lang.in: Add new{1,2}.{cc,o}.
- * call.c (build_method_call): Resolve OFFSET_REFs in the object.
+Thu Jan 23 16:39:06 1997 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_modify_expr): Dereference references before trying
- to assign to them.
-
- * call.c (build_method_call): Don't confuse type conversion
- operators with constructors.
- * typeck2.c (build_functional_cast): Just call build_c_cast if there
- was only one parameter.
- * method.c (build_typename_overload): Don't set
- IDENTIFIER_GLOBAL_VALUE on these identifiers.
- * decl.c (grok_op_properties): Warn about defining a type conversion
- operator that converts to a base class (or reference to it).
- * cvt.c (cp_convert): Don't try to use a type conversion operator
- when converting to a base class.
- (build_type_conversion_1): Don't call constructor_name_full on an
- identifier.
- * cp-tree.h (DERIVED_FROM_P): Should be self-explanatory.
-
- * decl.c (start_decl): Don't complain that error_mark_node is an
- incomplete type.
- (finish_decl): Check for type == error_mark_node.
+ * lex.c (cons_up_default_function): Fix return type of synth op=.
-Mon May 30 23:38:55 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * init.c (emit_base_init): Add warnings for uninitialized members
+ and bases.
- * decl.c (start_function): Set DECL_DEFER_OUTPUT on implicit
- instantiations and inline members.
+ * decl.c (xref_basetypes): Add warning for non-polymorphic type
+ with destructor used as base type.
- * spew.c (yylex): Set looking_for_template if the next token is a '<'.
+ * decl.c (grok_op_properties): Add warning for op= returning void.
+ * typeck.c (c_expand_return): Add warning for op= returning anything
+ other than *this.
- * lex.h: Declare looking_for_template.
+ * class.c (finish_struct_1): Add warning for class with pointers
+ but not copy ctor or copy op=.
- * decl.c (lookup_name_real): Use looking_for_template to arbitrate
- between type and template interpretations of an identifier.
+ * cp-tree.h (TI_PENDING_TEMPLATE_FLAG): New macro.
+ * pt.c (add_pending_template): Use it instead of LANG_FLAG_0.
+ (instantiate_template): If -fexternal-templates, add this
+ instantiation to pending_templates.
-Sat May 28 04:07:40 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (copy_assignment_arg_p): Disable old hack to support
+ Booch components.
- * pt.c (instantiate_template): Zero out p if we found a
- specialization.
+Tue Jan 21 18:32:04 1997 Mike Stump <mrs@cygnus.com>
- * decl.c (grokdeclarator): Elucidate warning.
- (grokdeclarator): If pedantic AND -ansi, complain about long long.
+ * cvt.c (cp_convert): Pedwarn enum to pointer conversions.
- Make explicit instantiation work reasonably. It is now appropriate
- to deprecate the use of -fexternal-templates.
- * pt.c (instantiate_template): Set DECL_TEMPLATE_SPECIALIZATION or
- DECL_IMPLICIT_INSTANTIATION on fndecl as appropriate.
- (end_template_instantiation): Reflect changes in USE_TEMPLATE
- semantics.
- (do_pending_expansions): if (!flag_implicit_templates) DECIDE(0);
- (do_function_instantiation): Don't set EXPLICIT_INST if
- flag_external_templates is set. Do set TREE_PUBLIC and DECL_EXTERN
- appropriately otherwise.
- (do_type_instantiation): Set interface info for class. Set
- TREE_PUBLIC and DECL_EXTERN for methods. Do none of this if
- flag_external_templates is set.
- * parse.y: Reflect changes in USE_TEMPLATE semantics.
- * decl2.c: New flag flag_implicit_templates determines whether or
- not implicit instantiations get emitted. This flag currently
- defaults to true, and must be true for -fexternal-templates to work.
- (finish_file): Consider flag_implement_inlines when
- setting DECL_EXTERNAL. Consider flag_implicit_templates when
- deciding whether or not to emit a static copy.
- * decl.c (start_function): Set TREE_PUBLIC and DECL_EXTERNAL
- properly for template instantiations.
- (start_method): Set DECL_IMPLICIT_INSTANTIATION on methods of a
- template class.
- * cp-tree.h (CLASSTYPE_USE_TEMPLATE): Change semantics.
- (DECL_USE_TEMPLATE): Parallel macro for FUNCTION and VAR_DECLs.
- (various others): Accessor macros for the above.
+Mon Jan 20 17:59:51 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri May 27 13:57:40 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (standard_conversion): Handle getting references. Tack
+ on RVALUE_CONV here. Do it for non-class types, too.
+ (reference_binding): Pass references to standard_conversion.
+ (implicit_conversion): Likewise.
+ (add_builtin_candidate): Disable one ?: kludge.
+ (convert_like): Handle RVALUE_CONVs for non-class types.
+ (joust): Disable the other ?: kludge.
- * typeck.c (build_binary_op_nodefault): Division by constant zero is
- an error.
+Mon Jan 20 14:53:13 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
-Fri May 27 13:50:15 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (init_decl_processing): Add code to build up common
+ function types beforehand, to avoid creation then removal of
+ things already in the hash table.
- * class.c (override_one_vtable): Don't modify things we don't own.
+Mon Jan 20 14:43:49 1997 Jason Merrill <jason@yorick.cygnus.com>
-Fri May 27 01:42:58 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (finish_function): Also zero out DECL_INCOMING_RTL for
+ the arguments.
- * decl.c (finish_decl): Don't postpone processing the initializer of
- a decl with DECL_EXTERNAL set, and do call rest_of_compilation for a
- PUBLIC const at toplevel.
- (grokdeclarator): pedwarn about initializing non-const or
- non-integral statics in the class body.
-
- * decl.c (pushtag): Don't try to set DECL_CLASS_CONTEXT on a
- TYPE_DECL.
+ * error.c (dump_expr, TEMPLATE_CONST_PARM): Don't require
+ current_template_parms.
- * call.c (convert_harshness): Dereference reference on rhs before
- proceeding, properly grok passing const things to non-const
- references.
+Fri Jan 17 10:25:42 1997 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_unary_op): Soften error about taking the address
- of main() to a pedwarn.
+ * search.c (lookup_field): Don't return a function, check want_type.
- * lex.c (default_copy_constructor_body): Unambiguously specify base
- classes (i.e. A((const class ::A&)_ctor_arg) ).
- (default_assign_ref_body): Ditto.
+Thu Jan 16 18:14:35 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
-Thu May 26 13:13:55 1994 Gerald Baumgartner (gb@mexican.cygnus.com)
+ * init.c (build_new): Make sure PLACEMENT has a type.
- * decl2.c (grokfield): Don't complain about local signature
- method declaration without definition.
+Thu Jan 16 17:40:28 1997 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (convert_harshness): If `type' is a signature pointer
- and `parmtype' is a pointer to a signature, just return 0. We
- don't really convert in this case; it's a result of making the
- `this' parameter of a signature method a signature pointer.
+ * init.c (build_new): Support new (nothrow).
- * call.c (build_method_call): Distinguish calling the default copy
- constructor of a signature pointer/reference from a signature
- member function call.
+Wed Jan 15 12:38:14 1997 Jason Merrill <jason@yorick.cygnus.com>
-Thu May 26 12:56:25 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (instantiate_decl): Also do push_to_top_level before setting
+ up DECL_INITIAL.
- * decl2.c (grokfield): Don't set TREE_PUBLIC on member function
- declarations.
+ * cp-tree.h (PARM_DEFAULT_FROM_TEMPLATE): New macro.
+ * pt.c (tsubst): Defer instantiation of default args.
+ * call.c (build_over_call): Until here.
- * decl.c (duplicate_decls): A previous function declaration as
- static overrides a subsequent non-static definition.
- (grokdeclarator): Don't set TREE_PUBLIC on inline method
- declarations.
+Wed Jan 15 10:08:10 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
-Wed May 25 14:36:38 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * search.c (lookup_field): Make sure we have an
+ IDENTIFIER_CLASS_VALUE before we try to return it.
- * decl.c (grokdeclarator): Handle initialization of static const
- members.
- (finish_decl): Ditto.
+Thu Jan 9 07:19:01 1997 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl2.c (grokfield): Allow initialization of static const members
- even when pedantic.
+ * call.c (build_method_call): Delete unused var PARM.
+ (build_overload_call_real): Likewise.
+ (build_object_call): Delete unused var P.
+ (build_new_op): Likewise.
+ * decl.c (builtin_type_tdescs_{arr, len, max}): #if 0 out static
+ var definitions, which are never used.
+ (shadow_tag): Delete unused var FN.
+ * expr.c (cplus_expand_expr): Delete unused var ORIGINAL_TARGET.
+ * init.c (build_new): Delete unused var ALLOC_TEMP.
+ * method.c (hack_identifier): Delete unused var CONTEXT.
+ (do_build_copy_constructor): Delete unused var NAME.
+ (synthesize_method): Delete unused var BASE.
+ * pt.c (lookup_template_class): Delete unused var CODE_TYPE_NODE.
+ * rtti.c (build_headof): Delete unused var VPTR.
+ (get_typeid): Delete unused var T.
+ * typeck.c (build_conditional_expr): Delete unused vars ORIG_OP1
+ and ORIG_OP2.
+ (build_ptrmemfunc): Delete unused vars U and NINDEX.
+ * typeck2.c (build_functional_cast): Delete unused var BINFO.
- * decl2.c (grokfield): Deal with grokdeclarator returning
- error_mark_node.
+Wed Jan 8 13:09:54 1997 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grok_ctor_properties): Return 0 for A(A) constructor.
- (grokfndecl): Check the return value of grok_ctor_properties.
- (start_method): Ditto.
+ * search.c (lookup_field): Use IDENTIFIER_CLASS_VALUE to look up
+ things in a type being defined.
+ * decl.c (finish_enum): Reverse the values so that they are in
+ the correct order.
- * parse.y (absdcl): Expand type_quals inline.
+ * pt.c (instantiate_class_template): Don't initialize
+ BINFO_BASETYPES until the vector is filled out.
+ (unify): Don't abort on conflicting bindings, just fail.
+ (instantiate_decl): Do push_tinst_level before any tsubsting.
-Tue May 24 19:10:32 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * method.c (build_overload_value): Handle getting a
+ TEMPLATE_CONST_PARM for a pointer.
- * decl.c (pushtag): Use IS_AGGR_TYPE rather than checking for a
- RECORD_TYPE.
+Tue Jan 7 14:00:58 1997 Jason Merrill <jason@yorick.cygnus.com>
-Tue May 24 18:09:16 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * init.c (expand_member_init): Don't give 'not a base' error for
+ templates.
- * cp-tree.h (VTABLE_NAME_FORMAT): If flag_vtable_thunks,
- always use "__vt_%s".
- * decl2.c (finish_vtable_vardecl): Don't consider abstract virtuals
- when looking for a "sentinal" method (to decide on emitting vtables).
- * decl2.c (finish_file): Scan all decls for thunks that need
- to be emitted.
- * decl2.c (finish_vtable_vardecl): Don't bother calling emit_thunk.
- * method.c (make_thunk): Use a more meaningful label. If there
- exists a matching top-level THUNK_DECL re-use it; otherwise
- create a new THUNK_DECL (and declare it).
- * method.c (emit_thunk): Make thunk external/public depending
- on the underlying method.
+ * pt.c (instantiate_decl): Call import_export_decl later.
-Tue May 24 00:22:04 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (instantiate_class_template): Return a value.
- * pt.c (tsubst): Use lookup_name_nonclass to find guiding decls, not
- lookup_name.
+ * parse.y (extension): New rule for __extension__.
+ (extdef, unary_expr, decl, component_decl): Use it.
- * call.c (build_overload_call_real): Don't immediately pick a
- function which matches perfectly.
+Tue Jan 7 09:20:28 1997 Mike Stump <mrs@cygnus.com>
- * decl.c (grokdeclarator): Use c_build_type_variant for arrays.
- (grokdeclarator): Warn about, and throw away, cv-quals attached to a
- reference (like 'int &const j').
+ * class.c (base_binfo): Remove unused base_has_virtual member.
+ (finish_base_struct): Likewise.
+ (finish_struct_1): Likewise.
- * typeck.c (convert_arguments): Don't mess with i for methods.
- * call.c (build_method_call): Pass the function decl to
- convert_arguments.
+Tue Dec 31 20:25:50 1996 Mike Stump <mrs@cygnus.com>
- * typeck.c (comp_ptr_ttypes_real): New function. Implements the
- checking for which multi-level pointer conversions are allowed.
- (comp_target_types): Call it.
- (convert_for_assignment): Check const parity on the ultimate target
- type, too. And make those warnings pedwarns.
+ * search.c (expand_upcast_fixups): Fix bogus code generation
+ problem where the generated code uses the wrong index into the
+ runtime built vtable on the stack. Old code could clobber random
+ stack values.
-Mon May 23 14:11:24 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue Dec 31 15:16:56 1996 Mike Stump <mrs@cygnus.com>
- * error.c (dump_char): Use TARGET_* for character constants.
+ * init.c (perform_member_init): Make sure the partial EH cleanups
+ live on the function_obstack.
-Mon May 23 13:03:03 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+Fri Dec 27 10:31:40 1996 Paul Eggert <eggert@twinsun.com>
- * tree.c (debug_no_list_hash): Make static.
+ * Make-lang.in (g++spec.o): Don't use $< with an explicit target;
+ this isn't portable to some versions of `make' (e.g. Solaris 2.5.1).
- * decl.c (decls_match): Say the types don't match if newdecl ends up
- with a null type, after we've checked if olddecl does.
- (pushdecl): Check if the decls themselves match before looking for
- an extern redeclared as static, to avoid inappropriate and incorrect
- warnings.
+Tue Dec 24 10:24:03 1996 Jeffrey A Law (law@cygnus.com)
-Fri May 20 14:04:34 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (grokvardecl): Avoid ANSI style initialization.
- * decl.c (grokdeclarator): Make warning about duplicate short, etc.
- a pedwarn.
+Sun Dec 22 04:22:06 1996 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_c_cast): Casting to function or method type is an
- error.
+ * pt.c (tsubst): Tweak arg types for a FUNCTION_TYPE.
- * class.c (finish_struct): Make warning for anonymous class with no
- instances a pedwarn.
+Fri Dec 20 17:09:25 1996 Jason Merrill <jason@yorick.cygnus.com>
- * Makefile.in (stamp-parse): Expect a s/r conflict.
+ * pt.c (instantiate_class_template): Call grok_{ctor,op}_properties.
- * typeck.c (build_modify_expr): pedwarn about using a non-lvalue
- cast as an lvalue.
+Fri Dec 20 12:17:12 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Thu May 19 12:08:48 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * g++spec.c (lang_specific_driver): Put missing hyphen in front of
+ arguments we compare against. Start the count of I at 1, not 0,
+ since argv[0] is still the command.
- * cvt.c (type_promotes_to): Make sure bool promotes to int rather
- than unsigned on platforms where sizeof(char)==sizeof(int).
+Thu Dec 19 11:53:57 1996 Stan Shebs <shebs@andros.cygnus.com>
-Wed May 18 14:27:06 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * lang-specs.h: Accept .cp as an C++ extension.
- * typeck.c (build_c_cast): Tack on a NOP_EXPR when casting to
- another variant.
- (build_modify_expr): Don't strip NOP_EXPRs, and don't get tricky
- and treat them as lvalues.
+Mon Dec 16 22:43:31 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c (shadow_tag): Do complain about forward declarations of
- enums and empty declarations.
- * parse.y: Don't complain about forward declarations of enums and
- empty declarations.
+ * cp-tree.h (ptr_reasonably_similar): Add decl.
- * typeck.c (convert_for_assignment): Complain about changing
- the signedness of a pointer's target type.
+Thu Dec 12 15:00:35 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * parse.y (stmt): Move duplicated code for checking case values from
- here.
- * decl2.c (check_cp_case_value): To here. And add a call to
- constant_expression_warning.
+ * decl.c (grokvardecl): Change SPECBITS parm to be the SPECBITS_IN
+ pointer. New local SPECBITS with the parm's value.
+ (grokdeclarator): Pass &specbits down.
- * typeck.c (convert_for_assignment): Don't complain about assigning
- a negative value to bool.
+ * parse.y (expr_no_commas): Make sure $$ is not an error_mark_node
+ before we try to do C_SET_EXP_ORIGINAL_CODE on it.
- * decl.c (init_decl_processing): Make bool unsigned.
+ * search.c (envelope_add_decl): Check that the CLASSTYPE_CID of
+ CONTEXT is not 0 before we try to use TYPE_DERIVES_FROM.
- * class.c (finish_struct): Allow bool bitfields.
+ * decl.c (cplus_expand_expr_stmt): Only expand the expr if EXP is
+ not an error_mark_node.
-Wed May 18 12:35:27 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
+Sat Dec 7 17:20:22 1996 Jason Merrill <jason@yorick.cygnus.com>
- * Make-lang.in (c++.install-man): Get g++.1 from $(srcdir)/cp.
+ * cp-tree.h (TYPE_MAIN_DECL): Use TYPE_STUB_DECL.
+ * *.c: Use TYPE_MAIN_DECL instead of TYPE_NAME where appropriate.
+
+Fri Dec 6 14:40:09 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed May 18 03:28:35 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (grokdeclarator): When giving an anonymous struct a name,
+ replace TYPE_NAME instead of TYPE_IDENTIFIER (so TYPE_STUB_DECL is
+ not affected).
- * cvt.c (build_type_conversion): Lose special handling of
- truthvalues.
+ * typeck2.c (build_m_component_ref): If component is a pointer
+ to data member, resolve the OFFSET_REF now.
- * search.c (dfs_pushdecls): Improve shadowing warning.
+ * call.c (convert_like): Don't go into infinite recursion.
-Tue May 17 13:34:46 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (coerce_template_parms): Use tsubst_expr for non-type args.
- * init.c (build_delete): Throw away const and volatile on `this'.
+ * class.c (finish_struct_1): Set DECL_ARTIFICIAL on the vptr.
+ * tree.c (layout_basetypes): And on the vbase ptr.
- * decl.c (finish_enum): Put the constants in TYPE_VALUES again,
- rather than the enumerators.
- (pushtag): s/cdecl/c_decl/g
+Thu Dec 5 02:11:28 1996 Jason Merrill <jason@yorick.cygnus.com>
-Mon May 16 23:04:01 1994 Stephen R. van den Berg (berg@pool.informatik.rwth-aachen.de)
+ * decl.c (BOOL_TYPE_SIZE): Define in terms of POINTER_SIZE or
+ CHAR_TYPE_SIZE so bool is always the same size as another type.
- * cp/typeck.c (common_type): Attribute merging.
- (comp_types): Utilise COMP_TYPE_ATTRIBUTES macro.
+ * decl.c (pushtag): Set DECL_IGNORED_P for DWARF, too.
- * cp/parse.y: Revamp attribute parsing.
+Tue Dec 3 23:18:37 1996 Jason Merrill <jason@yorick.cygnus.com>
-Mon May 16 01:40:34 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (grok_x_components): Remove synthesized methods from
+ TYPE_METHODS of an anonymous union, complain about member
+ functions.
+ * decl.c (shadow_tag): Wipe out memory of synthesized methods in
+ anonymous unions.
+ (finish_function): Just clear the DECL_RTL of our arguments.
- * decl.c (shadow_tag): Also check for inappropriate use of auto and
- register.
+Fri Nov 29 21:54:17 1996 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (build_overload_name): Clarify that the illegal case is a
- pointer or reference to array of unknown bound.
+ * decl2.c (finish_file): Emit DWARF debugging info for static data
+ members.
- * error.c (dump_type_prefix): Print references to arrays properly.
+ * pt.c (tsubst): If t is a stub decl, return the stub decl for type.
- * typeck.c (various): Be more helpful in pointer
- comparison diagnostics.
+Wed Nov 27 14:47:15 1996 Bob Manson <manson@charmed.cygnus.com>
- * tree.c (lvalue_p): MODIFY_EXPRs are lvalues again. Isn't this
- fun?
+ * typeck.c (build_component_ref): Don't die if COMPONENT isn't a
+ IDENTIFIER_NODE.
- * parse.y: Also catch an error after valid stmts.
+Wed Nov 27 16:05:19 1996 Michael Meissner <meissner@tiktok.cygnus.com>
- * search.c (dfs_init_vbase_pointers): Don't abort because `this' is
- const.
+ * Make-lang.in (g++-cross$(exeext)): Fix typo.
- * typeck.c (convert_for_initialization): If call to
- convert_to_reference generated a diagnostic, print out the parm
- number and function decl if any.
+Wed Nov 27 08:14:00 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * errfn.c (cp_thing): Check atarg1 to determine whether or not we're
- specifying a line, not atarg.
+ Make the g++ driver now be a standalone program, rather than one
+ that tries to run the gcc driver after munging up the options.
+ * Make-lang.in (g++.c, g++spec.o): New rules.
+ (g++.o): New rule, based on gcc.o with -DLANG_SPECIFIC_DRIVER
+ added.
+ (g++$(exeext)): New rule, based on xgcc rule.
+ (g++-cross$(exeext)): Now just copies g++$(exeext) over.
+ * g++spec.c: New file.
+ * g++.c: Removed file.
- * tree.c (build_cplus_method_type): Always make `this' const.
+Tue Nov 26 19:01:09 1996 Mike Stump <mrs@cygnus.com>
- * decl2.c (grokclassfn): If -fthis-is-variable and this function is
- a constructor or destructor, make `this' non-const.
+ * cvt.c (build_up_reference): Arrange for any temporary values
+ that have been keep in registers until now to be put into memory.
- * typeck.c (build_modify_expr): Don't warn specially about
- assignment to `this' here anymore, since it will be caught by the
- usual machinery.
+Mon Nov 25 15:16:41 1996 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
- * various: Disallow specific GNU extensions (variable-size arrays,
- etc.) when flag_ansi is set, not necessarily when pedantic is set,
- so that people can compile with -pedantic-errors for tighter const
- checking and such without losing desirable extensions.
+ * Make-lang.in (c++.stage[1234]): Depend upon stage[1-4]-start, so
+ that make -j3 bootstrap works better.
- * typeck2.c (build_functional_cast): Call build_method_call with
- LOOKUP_PROTECT.
- (process_init_constructor): Only process FIELD_DECLs.
+Sun Nov 24 02:09:39 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (finish_decl): Also force static consts with no explicit
- initializer that need constructing into the data segment.
+ * decl.c (pushtag): Do pushdecl for anon tags.
- * init.c (build_delete): Undo last patch, as it interferes with
- automatic cleanups.
+Thu Nov 21 16:30:24 1996 Jason Merrill <jason@yorick.cygnus.com>
-Sat May 14 01:59:31 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (c_expand_return): Fix logic.
+ (unary_complex_lvalue): Avoid unused warning on address of INIT_EXPR.
- * call.c, class.h, cp-tree.h, cvt.c, decl2.c: Lose old overloading
- code.
+Wed Nov 20 18:47:31 1996 Bob Manson <manson@charmed.cygnus.com>
- * init.c (build_delete): pedwarn about using plain delete to delete
- an array.
+ * g++.c (main): Make sure arglist has a final NULL entry. Add
+ PEXECUTE_LAST to the flags passed to pexecute, as otherwise
+ stdin/stdout of the invoked program are redirected to
+ nowheresville.
-Fri May 13 16:45:07 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue Nov 19 16:12:44 1996 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (comp_target_types): Be more helpful in contravariance
- warnings, and make them pedwarns.
+ * decl.c (implicitly_declare): Set DECL_ARTIFICIAL.
- * decl.c (grokdeclarator): Use decl_context to decide whether or not
- this is an access declaration.
+Tue Nov 19 15:48:19 1996 Mike Stump <mrs@cygnus.com>
- * class.c (finish_struct_bits): Set TYPE_HAS_INT_CONVERSION if it
- has a conversion to enum or bool, too.
+ * init.c (resolve_offset_ref): Handle obj.vfn better.
+ * typeck.c (build_component_ref): Set TREE_TYPE on result from
+ build_vfn_ref.
-Fri May 13 16:31:27 1994 Mike Stump <mrs@cygnus.com>
+Tue Nov 19 13:14:33 1996 Mike Stump <mrs@cygnus.com>
- * method.c (emit_thunk): Make declaration for
- current_call_is_indirect local (needed for hppa).
+ * typeck.c (convert_for_assignment): Also handle anachronistic
+ implicit conversions from (::*)() to cv void*.
+ * cvt.c (cp_convert_to_pointer): Likewise.
-Fri May 13 16:16:37 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Nov 18 17:05:26 1996 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (uses_template_parms): Grok BOOLEAN_TYPE.
- (tsubst): Ditto.
+ * lex.c (handle_cp_pragma): Fix bogus warning.
-Fri May 13 16:23:32 1994 Mike Stump <mrs@cygnus.com>
+Mon Nov 18 16:10:43 1996 Mike Stump <mrs@cygnus.com>
- * pt.c (tsubst): If there is already a function for this expansion,
- use it.
- * pt.c (instantiate_template): Ditto.
-
-Fri May 13 10:30:42 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
-
- * parse.y (implicitly_scoped_stmt, simple_stmt case): Use
- kept_level_p for MARK_ENDS argument to expand_end_bindings, to avoid
- generating debug info for unemitted symbols on some systems.
-
- * cp-tree.h (build_static_cast, build_reinterpret_cast,
- build_const_cast): Add declarations.
-
-Fri May 13 09:50:31 1994 Mike Stump <mrs@cygnus.com>
-
- * search.c (expand_indirect_vtbls_init): Fix breakage from Apr 27
- fix. We now try get_binfo, and if that doesn't find what we want,
- we go back to the old method, which still sometimes fails.
-
-Fri May 13 01:43:18 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- * parse.y (initdcl): Call cplus_decl_attributes on the right
- variable.
- * decl2.c (cplus_decl_attributes): Don't call decl_attributes for
- void_type_node.
-
- * typeck.c (build_binary_op_nodefault): Change result_type for
- comparison ops to bool.
- (build_binary_op): Convert args of && and || to bool.
- * cvt.c (build_default_binary_type_conversion): Convert args of &&
- and || to bool.
- (build_default_unary_type_conversion): Convert arg of ! to bool.
- (type_promotes_to): bool promotes to int.
-
-Fri May 13 01:43:18 1994 Mike Stump <mrs@cygnus.com>
-
- Implement the new builtin `bool' type.
- * typeck.c (build_binary_op_nodefault): Convert args of && and || to
- bool.
- (build_unary_op): Convert arg of ! to bool.
- * parse.y: Know true and false. Use bool_truthvalue_conversion.
- * method.c (build_overload_value): Know bool.
- (build_overload_name): Ditto.
- * lex.c (init_lex): Set up RID_BOOL.
- * gxx.gperf: Add bool, true, false.
- * error.c (*): Know bool.
- * decl.c (init_decl_processing): Set up bool, true, false.
- * cvt.c (cp_convert): Handle conversion to bool.
- (build_type_conversion): Ditto.
- * *.c: Accept bool where integers and enums are accepted (use
- INTEGRAL_CODE_P macro).
-
-Thu May 12 19:13:54 1994 Richard Earnshaw (rwe11@cl.cam.ac.uk)
-
- * g++.c: Use #ifdef for __MSDOS__, not #if.
-
-Thu May 12 18:05:18 1994 Mike Stump <mrs@cygnus.com>
-
- * decl2.c (lang_f_options): Handle -fshort-temps. -fshort-temps
- gives old behavior , and destroys temporaries earlier. Default
- behavior now conforms to the ANSI working paper.
-
-Thu May 12 14:45:35 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- * typeck.c (build_modify_expr): Understand MODIFY_EXPR as an lvalue.
- Use convert_force to convert the result of a recursive call when we
- are dealing with a NOP_EXPR. Don't automatically wrap MODIFY_EXPRs
- in COMPOUND_EXPRs any more.
- (various): Lose pedantic_lvalue_warning.
- (unary_complex_lvalue): Understand MODIFY_EXPR.
-
- * cvt.c (convert_to_reference): Allow DECL to be error_mark_node if
- we don't know what we're initializing.
-
-Wed May 11 01:59:36 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- * cvt.c (convert_to_reference): Modify to use convtype parameter.
- Only create temporaries when initializing a reference, not when
- casting.
- (cp_convert): New main function.
- (convert): Call cp_convert.
- * cvt.c, decl.c, typeck.c: Fix calls to convert_to_reference.
- * cp-tree.h (CONV_*): New constants used by conversion code for
- selecting conversions to perform.
-
- * tree.c (lvalue_p): MODIFY_EXPRs are no longer lvalues.
-
- * typeck.c (build_{static,reinterpret,const_cast): Stubs that just
- call build_c_cast.
- * parse.y: Add {static,reinterpret,const}_cast.
- * gxx.gperf: Ditto.
-
- * typeck.c (common_type): Allow methods with basetypes of different
- UPTs.
- (comptypes): Deal with UPTs.
- (build_modify_expr): Wrap all MODIFY_EXPRs in a COMPOUND_EXPR.
-
- * pt.c (end_template_decl): Check for multiple definitions of member
- templates.
+ * cvt.c (cp_convert_to_pointer): Avoid thinking a POINTER_TYPE
+ (METHOD_TYPE) is a TYPE_PTRMEMFUNC_P.
- * call.c (build_method_call): Complain about calling an abstract
- virtual from a constructor.
+Thu Nov 14 23:18:17 1996 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (pointer_int_sum): Check for the integer operand being 0
- after checking the validity of the pointer operand.
+ * class.c (finish_struct_1): Support DWARF2_DEBUG.
+ * search.c (dfs_debug_mark): Likewise.
+ * decl2.c (finish_vtable_vardecl): Likewise.
+ * decl.c (pushtag, finish_enum): Likewise.
+ * lex.c (check_newline): Use debug_* instead of calling *out
+ functions directly.
- * typeck2.c (digest_init): Pedwarn about string initializer being
- too long.
+Thu Nov 14 15:21:46 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Tue May 10 12:10:28 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * Make-lang.in (cplib2.ready): Add else clause to avoid problems
+ on some picky hosts.
- * decl.c (push_overloaded_decl): Only throw away a builtin if the
- decl in question is the artificial one.
+Wed Nov 13 12:32:07 1996 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (simple_stmt, switch): Use implicitly_scoped_stmt because
- expand_{start,end}_case cannot happen in the middle of a block.
+ * class.c (finish_struct_1): A class has a non-trivial copy
+ constructor if it has virtual functions.
- * cvt.c (build_type_conversion_1): Use convert again.
+ * cvt.c (cp_convert): Always call a constructor.
-Tue May 10 11:52:04 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * call.c (reference_binding): Still tack on a REF_BIND
+ for bad conversions.
+ (build_user_type_conversion_1): Propagate ICS_BAD_FLAG.
- * typeck2.c (digest_init): Make sure we check for signed and
- unsigned chars as well when warning about string initializers.
+ * typeck.c (convert_arguments): Pass LOOKUP_ONLYCONVERTING.
+ (c_expand_return): Likewise.
+ * typeck2.c (digest_init): Likewise for { }.
+ * init.c (expand_aggr_init_1): Keep the CONSTRUCTOR handling.
+ * cvt.c (cp_convert): Handle failure better.
- * init.c (emit_base_init): Check if there's a DECL_NAME on the
- member before trying to do an initialization for it.
+Wed Nov 13 11:51:20 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Tue May 10 11:34:37 1994 Mike Stump <mrs@cygnus.com>
+ * g++.c (main): Also set PEXECUTE_SEARCH, to make the invocation
+ of GCC be path-relative.
- * except.c: Don't do anything useful when cross compiling.
+Wed Nov 13 11:27:16 1996 Michael Meissner <meissner@tiktok.cygnus.com>
-Tue May 10 03:04:13 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * Make-lang.in (g++-cross): G++-cross doesn't need version.o, but
+ it does need choose-temp.o and pexecute.o.
- * decl.c (duplicate_decls): Fix up handling of builtins yet again.
- (push_overloaded_decl): Ditto.
+Wed Nov 13 07:53:38 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cvt.c (convert): Don't look for void type conversion.
+ * g++.c (error) [!HAVE_VPRINTF]: Put error back for the only time
+ that we still use it.
+ (P_tmpdir, R_OK, W_OK, X_OK) [__MSDOS__]: Delete unnecessary macros.
-Mon May 9 18:05:41 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Nov 13 02:00:26 1996 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (do_friend): Only do a pushdecl for friends, not
- pushdecl_top_level.
+ * init.c (expand_default_init): Avoid calling constructors to
+ initialize reference temps.
-Mon May 9 13:36:34 1994 Jim Wilson (wilson@sphagnum.cygnus.com)
+ * cvt.c (convert_to_reference): Fix.
- * decl.c (lookup_name_current_level): Put empty statement after
- the label OUT to make the code valid C.
+Tue Nov 12 19:10:07 1996 Jason Merrill <jason@yorick.cygnus.com>
-Mon May 9 12:20:57 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * cvt.c (cp_convert): Simplify for flag_ansi_overloading.
+ (convert_to_reference): Likewise.
+ * typeck.c (convert_for_initialization): Likewise.
+ * init.c (expand_default_init): Likewise.
+ (expand_aggr_init_1): Likewise.
+ * cp-tree.h (CONV_NONCONVERTING): Lose.
+ * typeck.c (build_c_cast): Lose allow_nonconverting parm.
+ * *.c: Adjust.
+ * call.c (build_user_type_conversion_1): Assume LOOKUP_ONLYCONVERTING.
- * typeck.c (build_binary_op_nodefault): Only complain about
- comparing void * and a function pointer if void * is smaller.
+Tue Nov 12 16:29:04 1996 Brendan Kehoe <brendan@canuck.cygnus.com>
-Sun May 8 01:29:13 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (tsubst_expr): Reverse args to expand_start_catch_block.
- * decl.c (lookup_name_current_level): Move through temporary binding
- levels.
+Tue Nov 12 15:26:17 1996 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (already_scoped_stmt): Revive.
- (simple_stmt): Use it again.
+ * init.c (expand_aggr_init_1): Don't crash on non-constructor
+ TARGET_EXPR.
- * decl.c (poplevel): Always call poplevel recursively if we're
- dealing with a temporary binding level.
+Tue Nov 12 14:00:50 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Sat May 7 10:52:28 1994 Mike Stump <mrs@cygnus.com>
+ * g++.c: Include gansidecl.h.
+ (VPROTO, PVPROTO, VA_START): Delete.
+ (choose_temp_base_try, choose_temp_base, perror_exec,
+ run_dos) [__MSDOS__]: Delete fns.
+ (pfatal_with_name): Delete fn.
+ (temp_filename): Declare like in gcc.c.
+ (pexecute, pwait, choose_temp_base): Declare from gcc.c.
+ (error_count, signal_count): Define.
+ (error): Delete both definitions.
+ (PEXECUTE_{FIRST,LAST,SEARCH,VERBOSE}): Define from gcc.c.
+ (pfatal_pexecute): Add fn from gcc.c.
+ (main): Rename local VERBOSE var to VERBOSE_FLAG. Rewrite the
+ code to use the pexecute stuff also used by gcc.c.
+ (MIN_FATAL_STATUS): Define.
+ * Make-lang.in (g++): Add dependency on and linking with
+ choose-temp.o and pexecute.o.
- * decl.c (finish_decl): Make sure we run cleanups for initial values
- of decls. Cures memory leak.
- * decl.c (expand_static_init): Ditto for static variables.
- * decl2.c (finish_file): Ditto for globals.
+ * cp-tree.h: Include gansidecl.h.
+ (STDIO_PROTO): Delete #undef/#define.
+ * cvt.c (NULL): Delete #undef/#define.
+ * expr.c (NULL): Likewise.
+ * init.c (NULL): Likewise.
+ * rtti.c (NULL): Likewise.
+ * xref.c (NULL): Likewise.
-Sat May 7 03:57:44 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * cp-tree.h (build_user_type_conversion): Add prototype.
+ * call.c (build_user_type_conversion): Delete prototype. Correct
+ decl of FLAGS arg to be an int.
+ * cvt.c (build_user_type_conversion): Likewise.
- * typeck.c (commonparms): Don't complain about redefining default
- args.
+Tue Nov 12 12:16:20 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (duplicate_decls): Don't complain twice about conflicting
- function decls.
- (decls_match): Don't look at default args.
- (redeclaration_error_message): Complain about redefining default
- args.
+ * cp-tree.def: Add TRY_BLOCK and HANDLER.
+ * except.c (expand_start_catch_block): Support templates.
+ * parse.y (try_block, handler_seq): Likewise.
+ * pt.c (tsubst_expr): Support TRY_BLOCK and HANDLER.
- * call.c (build_overload_call_real): Also deal with guiding
- declarations coming BEFORE the template decl.
+Mon Nov 11 13:57:31 1996 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (unify): Allow different parms to have different
- cv-qualifiers.
- (unify): Allow trivial conversions on non-template parms.
+ * pt.c (current_template_args): New fn.
+ (push_template_decl): Use it.
+ * decl.c (grokdeclarator): Use it.
-Fri May 6 03:53:23 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (build_expr_from_tree): Dereference ref vars.
- * pt.c (tsubst): Support OFFSET_TYPEs.
- (unify): Ditto.
+ * decl.c (grokdeclarator): Generalize handling of TYPENAME_TYPEs in
+ the decl-specifier-seq.
- * decl2.c (finish_decl_parsing): Call push_nested_class with a type.
+ * decl.c (grok_op_properties): Don't force the type of a conversion
+ op to be complete. Don't warn about converting to the same type
+ for template instantiations.
- * init.c (build_offset_ref): Fix error message.
- * search.c (lookup_field): Ditto.
+ * decl2.c (finish_file): Don't call instantiate_decl on synthesized
+ methods.
- * call.c (build_scoped_method_call): Pass binfo to
- build_method_call.
- * typeck.c (build_object_ref): Ditto.
+Mon Nov 11 13:20:34 1996 Bob Manson <manson@charmed.cygnus.com>
- * typeck2.c (binfo_or_else): Don't return a _TYPE.
+ * typeck.c (get_delta_difference): Remove previous bogusness.
+ Don't give errors if force is set.
- * class.c (finish_struct): Don't complain about re-use of inherited
- names or shadowing of type decls.
- * decl.c (pushdecl_class_level): Ditto.
+Fri Nov 8 17:38:44 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (finish_enum): Set the type of all the enums.
+ * decl2.c (finish_file): Don't emit debug info.
+ * decl.c (pushdecl): Lose obsolete code.
+ (grokdeclarator): Still do the long long thing after complaining.
+ * search.c (note_debug_info_needed): Don't do anything if we're in a
+ template.
+ * method.c (synthesize_method): For non-local classes,
+ push_to_top_level first.
- * class.c (finish_struct): Don't get confused by access decls.
+Fri Nov 8 11:52:28 1996 Bob Manson <manson@charmed.cygnus.com>
- * cp-tree.h (TYPE_MAIN_DECL): New macro to get the _DECL for a
- _TYPE. You can stop using TYPE_NAME for that now.
+ * typeck.c (get_delta_difference): Add no_error parameter.
+ (build_ptrmemfunc): Call get_delta_difference with no_error set;
+ we don't want error messages when converting unrelated
+ pointer-to-member functions.
- * parse.y: Lose doing_explicit (check $0 instead).
- * gxx.gperf: 'template' now has a RID.
- * lex.h (rid): Ditto.
- * lex.c (init_lex): Set up the RID for 'template'.
+Thu Nov 7 11:16:24 1996 Mike Stump <mrs@cygnus.com>
- * parse.y (type_specifier_seq): typed_typespecs or
- nonempty_type_quals. Use it.
- (handler_args): Fix bogus syntax.
- (raise_identifier{,s}, optional_identifier): Lose.
- * except.c (expand_start_catch_block): Use grokdeclarator to parse
- the catch variable.
- (init_exception_processing): The second argument to
- __throw_type_match is ptr_type_node.
+ * error.c (dump_expr): Improve the wording on error messages that
+ involve pointer to member functions.
- Fri May 6 07:18:54 1994 Chip Salzenberg (chip@fin)
+Tue Nov 5 17:12:05 1996 Mike Stump <mrs@cygnus.com>
- [ change propagated from c-decl.c of snapshot 940429 ]
- * cp/decl.c (finish_decl): Setting asmspec_tree should not
- zero out the old RTL.
+ * cvt.c (cp_convert_to_pointer): Move code for conversions from
+ (::*)() to void* or (*)() up a bit, so that we can convert from
+ METHOD_TYPEs as well.
-Fri May 6 01:25:38 1994 Mike Stump <mrs@cygnus.com>
+Tue Nov 5 14:54:17 1996 Jason Merrill <jason@yorick.cygnus.com>
- Add alpha exception handling support to the compiler.
- Quick and dirty backend in except.c.
+ * rtti.c (get_tinfo_fn): Make sure 'type' is permanent.
+ There are no 'member' types.
+ (get_tinfo_fn_dynamic): Diagnose typeid of overloaded fn.
+ (build_x_typeid): Handle errors.
- * cp/*: Remove most remnants of old exception handling support.
- * decl.c (finish_function): Call expand_exception_blocks to put
- the exception hanlding blocks at the end of the function.
- * dec.c (hack_incomplete_structures): Make sure expand_decl_cleanup
- comes after expand_decl_init.
- * except.c: Reimplementation.
- * expr.c (cplus_expand_expr): Handle THROW_EXPRs.
- * lex.c (init_lex): Always have catch, try and throw be reserved
- words, so that we may always parse exception handling.
- * parse.y: Cleanup to support new interface into exception handling.
- * tree.def (THROW_EXPR): Add.
+Mon Nov 4 17:43:12 1996 Mike Stump <mrs@cygnus.com>
-Thu May 5 17:35:37 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (convert_for_assignment): Handle anachronistic implicit
+ conversions from (::*)() to void* or (*)().
+ * cvt.c (cp_convert_to_pointer): Likewise.
+ (cp_convert_to_pointer_force): Remove cp_convert_to_pointer
+ conversions from here.
+ * decl2.c (lang_decode_option): Add -W{no-,}pmf-conversions.
+ * lang-options.h: Likewise.
+ * decl2.c (warn_pmf2ptr): Define.
+ * cp-tree.h: Declare it.
+ * typeck2.c (digest_init): Allow pmfs down into
+ convert_for_initialization.
- * parse.y (simple_stmt, for loops): Use implicitly_scoped_stmt.
- (various): Lose .kindof_pushlevel and partially_scoped_stmt.
+Sun Nov 3 09:43:00 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu May 5 16:17:27 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * typeck.c (c_expand_return): Fix for returning overloaded fn.
- * parse.y (already_scoped_stmt): move expand_end_binding() to
- fix the unmatched LBB/LBE in stabs.
+Fri Nov 1 08:53:17 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu May 5 14:36:17 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * cp-tree.h (DIRECT_BIND): Change from INDIRECT_BIND.
+ * decl.c (grok_reference_init): Pass DIRECT_BIND.
+ * cvt.c (build_up_reference): Don't mark 'this' addressable. Use
+ DIRECT_BIND.
+ * call.c (convert_like): Don't pass INDIRECT_BIND.
+ * typeck.c (convert_arguments): Likewise.
+ * typeck.c (mark_addressable): Allow &this if flag_this_is_variable.
- * decl.c (set_nested_typename): Set TREE_MANGLED on the new
- identifiers.
- (pushdecl): Check TREE_MANGLED.
- (xref_tag): Ditto.
- * cp-tree.h (TREE_MANGLED): This identifier is a
- DECL_NESTED_TYPENAME (named to allow for future use to denote
- mangled function names as well).
+Thu Oct 31 17:08:49 1996 Jason Merrill <jason@yorick.cygnus.com>
- Implement inconsistency checking specified in [class.scope0].
- * decl.c (lookup_name_real): Don't set ICV here after all.
- (finish_enum): Also set the type of the enumerators themselves.
- (build_enumerator): Put the CONST_DECL in the list instead of its
- initial value.
- (pushdecl_class_level): Check inconsistent use of a name in the
- class body.
- * class.c (finish_struct): Check inconsistent use of a name in the
- class body. Don't set DECL_CONTEXT on types here anymore.
- * parse.y (qualified_type_name): Note that the identifier has now
- been used (as a type) in the class body.
- * lex.c (do_identifier): Note that the identifier has now been used
- (as a constant) in the class body.
- * error.c (dump_decl): Print type and enum decls better.
+ * typeck.c (mark_addressable): Support TARGET_EXPR, unify with
+ similar code in build_up_ref.
+ * cvt.c (build_up_reference): Drastically simplify.
-Thu May 5 09:35:35 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+Mon Oct 28 12:45:05 1996 Jeffrey A Law (law@cygnus.com)
- * typeck.c (build_modify_expr): Warn about assignment to `this'.
+ * typeck.c (signed_or_unsigned_type): If the given type already
+ as the correct signedness, then just return it.
-Wed May 4 15:55:49 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c ({un,}signed_type): If can't do anything, call
+ signed_or_unsigned_type.
- * init.c (build_delete): Use the global operator delete when
- requested.
+Thu Oct 24 14:21:59 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl.c (lookup_name_real): If we find the type we're looking in a
- base class while defining a class, set IDENTIFIER_CLASS_VALUE for
- the type.
+ * decl2.c (copy_assignment_arg_p): Don't buy the farm if
+ current_class_type is NULL.
- * class.c (finish_struct): Remove a couple of dependencies on
- language linkage.
+Wed Oct 23 00:43:10 1996 Jason Merrill <jason@gerbil.cygnus.com>
- * decl.c (pushtag): Classes do nest in extern "C" blocks.
- (pushdecl): Only set DECL_NESTED_TYPENAME on the canonical one for
- the type.
- (pushtag): Remove another dependency on the language linkage.
+ * class.c (finish_struct_1): Avoid empty structs by adding a field
+ so layout_type gets the mode right.
- * lex.c (cons_up_default_function): Don't set DECL_CLASS_CONTEXT to
- a const-qualified type.
+ * typeck.c (c_expand_return): Drastically simplify.
- * decl.c (push_overloaded_decl): Throw away built-in decls here.
- (duplicate_decls): Instead of here.
+Mon Oct 21 22:34:02 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed May 4 15:27:40 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * typeck.c (decay_conversion): Handle overloaded methods.
- * typeck.c (get_member_function_from_ptrfunc): Do The Right
- Thing (I hope) if we're using thunks.
+Fri Oct 18 16:03:48 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed May 4 13:52:38 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (build_over_call): A TARGET_EXPR has side-effects.
- * parse.y (specialization): aggr template_type_name ';'.
- (named_class_head_sans_basetype): Use it.
- (explicit_instantiation): Ditto.
- (tmpl.2): Revert.
+Thu Oct 17 11:31:59 1996 Mike Stump <mrs@cygnus.com>
- * cvt.c (build_type_conversion_1): Use convert_for_initialization,
- rather than convert, to do conversions after the UDC.
+ * cvt.c (convert_to_pointer_force): Add code to support pointer to
+ member function to pointer to function conversions.
+ * init.c (resolve_offset_ref): Add code to allow faked up objects,
+ ignoring them if they are not used, and giving an error, if they
+ are needed.
+ * typeck.c (get_member_function_from_ptrfunc): Fold e1 to improve
+ code, and so that we can give an error, if we needed an object,
+ and one was not provided.
+ (build_c_cast): Don't call default_conversion when we want to
+ convert to pointer to function from a METHOD_TYPE.
- * cp-tree.h (SHARED_MEMBER_P): This member is shared between all
- instances of the class.
+Mon Oct 14 00:28:51 1996 Jason Merrill <jason@yorick.cygnus.com>
- * search.c (lookup_field): If the entity found by two routes is the
- same, it's not ambiguous.
+ * Make-lang.in (cplib2.ready): Fix logic.
-Wed May 4 12:10:00 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * decl.c (shadow_tag): Only complain about non-artificial function
+ members.
- * decl.c (lookup_name_real): Check for a NULL TREE_VALUE,
- to prevent the compiler from crashing ...
+ * class.c (finish_struct_1): Add synthesized methods to TYPE_METHODS.
-Wed May 4 11:19:45 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Oct 11 16:12:40 1996 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_method_call): If we don't have an object, check
- basetype_path to figure out where to look up the function.
+ * expr.c (cplus_expand_expr): Pre-tweak call_target like
+ expand_inline_function would.
- * typeck.c (convert_for_initialization): Pass TYPE_BINFO (type) to
- build_method_call in case exp is NULL_TREE.
+ * pt.c (mark_decl_instantiated): If extern_p, call
+ mark_inline_for_output.
-Tue May 3 16:02:53 1994 Per Bothner (bothner@kalessin.cygnus.com)
+Thu Oct 10 15:58:08 1996 Mike Stump <mrs@cygnus.com>
- Give a vtable entries a unique named type, for the sake of gdb.
- * class.c (build_vtable_entry): The addres of a thunk now has
- type vtable_entry_type, not ptr_type_node.
- * method.c (make_thunk): Fix type of THUNK_DECL.
- * class.c (add_virtual_function, override_one_vtable): Use
- vfunc_ptr_type_node, instead of ptr_type_node.
- * cp-tree.h (vfunc_ptr_type_node): New macro.
- * decl.c (init_decl_processing): Make vtable_entry_type
- be a unique type of pointer to a unique function type.
+ * typeck.c (unary_complex_lvalue): Add code to handle intermediate
+ pmd conversions.
-Tue May 3 09:20:44 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (get_delta_difference): Fix wording, as we can be used
+ for pointer to data members.
- * parse.y (do_explicit): Sets doing_explicit to 1.
- (explicit_instantiation): Use do_explicit rather than TEMPLATE
- directly, add "do_explicit error" rule.
- (datadef): Set doing_explicit to 0 after an explicit instantiation.
- (tmpl.2): Don't instantiate if we see a ';' unless we're doing an
- explicit instantiation.
- (named_class_head_sans_basetype): Remove aggr template_type_name
- ';' again.
+Tue Oct 8 12:43:51 1996 Bob Manson <manson@charmed.cygnus.com>
-Mon May 2 23:17:21 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (tsubst): If the function decl isn't a member of this
+ template, return a copy of the decl (including copying the
+ lang-specific part) so we don't hose ourselves later.
- * search.c (lookup_nested_tag): Lose.
+Thu Oct 3 16:24:28 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (grokfield): Set DECL_CONTEXT on TYPE_DECLs.
- (lookup_name_nonclass): Lose.
+ * class.c (finish_struct): Remove DWARF-specific tag handling.
+ * decl.c (pushtag): Likewise.
+ (finish_function): Always clear DECL_ARGUMENTS on function decls with
+ no saved RTX.
+ * decl2.c (finish_file): Emit DWARF debugging info for static data
+ members.
- * decl.c (poplevel_class): Add force parameter.
- (lookup_name_real): Fix handling of explicit scoping which specifies
- a class currently being defined. Add 'nonclass' argument.
- (lookup_name, lookup_name_nonclass): Shells for lookup_name_real.
+Wed Oct 2 21:58:01 1996 Bob Manson <manson@charmed.cygnus.com>
- * class.c (finish_struct): Don't unset IDENTIFIER_CLASS_VALUEs here.
- (popclass): Force clearing of IDENTIFIER_CLASS_VALUEs if we're being
- called from finish_struct.
+ * decl.c (duplicate_decls): Make sure the old DECL_LANG_SPECIFIC
+ isn't the same as the new one before we whack it.
-Mon May 2 19:06:21 1994 Per Bothner (bothner@kalessin.cygnus.com)
+Mon Sep 30 13:38:24 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (init_decl_processing), cp-tree.h: Removed memptr_type.
- (It seeems redundant, given build_ptrmemfunc_type.)
- * typeck.c (get_member_function_from_ptrfunc), gc.c (build_headof,
- build_classof): Use vtable_entry_type instead of memptr_type.
- * method.c (emit_thunk): Call poplevel with functionbody==0
- to prevent DECL_INITIAL being set to a BLOCK.
+ * class.c, cp-tree.h, cvt.c, decl.c, decl2.c, gxx.gperf, hash.h,
+ lex.c, method.c, parse.y, typeck.c, typeck2.c: Remove
+ warn_traditional and warn_strict_prototypes; remove ancient
+ 'overload' code; remove references to flag_traditional.
-Mon May 2 15:02:11 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Sep 30 12:58:40 1996 Mike Stump <mrs@cygnus.com>
- * parse.y (named_class_head_sans_basetype): Add "aggr
- template_type_name ';'" rule for forward declaration of
- specializations.
+ * input.c (sub_getch): Handle 8-bit characters in string literals.
-Mon May 2 15:02:11 1994 Jason Merrill (jason@deneb.cygnus.com)
+Sun Sep 29 03:12:01 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (instantiate_type): Deal with pmf's.
+ * tree.c (mapcar): Handle CONSTRUCTORs.
+ (copy_to_permanent): Handle expression_obstack properly.
- * Make-lang.in (cc1plus): Don't depend on OBJS or BC_OBJS, since
- stamp-objlist does.
+ * Make-lang.in (cplib2.txt): Also depend on the headers.
- * Makefile.in (../cc1plus): Depend on OBJDEPS.
- (OBJDEPS): Dependency version of OBJS.
+ * rtti.c (get_tinfo_var): Don't assume that POINTER_SIZE ==
+ INT_TYPE_SIZE.
+ (expand_class_desc): Use USItype for offset field.
+ * tinfo.h (struct __class_type_info): Likewise.
-Mon May 2 12:51:31 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * method.c (build_overload_int): TYPE_PRECISION should be applied
+ to types.
- * search.c (dfs_debug_mark): unmark TYPE_DECL_SUPPRESS_DEBUG, not
- DECL_IGNORED_P.
+Sat Sep 28 14:44:50 1996 Jason Merrill <jason@yorick.cygnus.com>
-Fri Apr 29 12:29:56 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (build_new_op): A COND_EXPR involving void must be a
+ builtin.
- * class.c (finish_struct): Clear out memory of local tags. And
- typedefs.
+Fri Sep 27 16:40:30 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (grokclassfn): Don't set DECL_CONTEXT to a cv-qualified
- type.
- * search.c (get_matching_virtual): Be more helpful in error message.
+ * typeck.c (build_x_component_ref): New fn.
+ (build_object_ref): Use it.
+ * parse.y (primary): Use it.
+ * decl2.c (build_expr_from_tree): Use it.
+ * cp-tree.h: Declare it.
- * *: Use DECL_ARTIFICIAL (renamed from DECL_SYNTHESIZED).
+ * decl.c (start_decl): variable-sized arrays cannot be initialized.
+ * error.c (dump_type_suffix): Handle variable arrays.
- * lex.c (default_assign_ref_body): Expect TYPE_NESTED_NAME to work.
- (default_copy_constructor_body): Ditto.
+Fri Sep 27 13:14:05 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * class.c (finish_struct): Don't gratuitously create multiple decls
- for nested classes.
+ * Make-lang.in (exception.o): Put back compiling it with -fPIC.
-Thu Apr 28 23:39:38 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Sep 27 03:00:09 1996 Jason Merrill <jason@yorick.cygnus.com>
- Avoid clobbering the arg types of other functions when reverting
- static member functions.
- * decl.c (revert_static_member_fn): Rearrange arguments, don't
- require values for 'fn' and 'argtypes', add warning to comment
- above.
- (decls_match): Rearrange arguments in call to rsmf.
- (grok_op_properties): Don't pass values for fn and argtypes.
- * pt.c (instantiate_template): Don't pass values for fn and argtypes.
+ * decl.c (lookup_name_real): Don't try to look up anything in a
+ TYPENAME_TYPE.
-Thu Apr 28 16:29:11 1994 Doug Evans (dje@canuck.cygnus.com)
+ * tinfo2.cc (__throw_type_match_rtti): Oops.
- * Make-lang.in (cc1plus): Depend on stamp-objlist.
- * Makefile.in (BC_OBJS): Delete.
- (OBJS): Cat ../stamp-objlist to get language independent files.
- Include ../c-common.o.
- (../cc1plus): Delete reference to BC_OBJS.
+Thu Sep 26 22:11:05 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Thu Apr 28 02:12:08 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * Make-lang.in (exception.o): Use -fno-PIC for now.
- * search.c (compute_access): No really, deal with static members
- properly. Would I lie to you?
+Thu Sep 26 10:59:00 1996 Jason Merrill <jason@yorick.cygnus.com>
- Implement lexical hiding of function declarations.
- * pt.c (tsubst): Use lookup_name to look for function decls to guide
- instantiation.
- * method.c (build_opfncall): Use lookup_name_nonclass to look for
- non-member functions.
- * init.c (do_friend): Use lookup_name_nonclass to look for
- functions.
- * error.c (ident_fndecl): Use lookup_name to look for functions.
- * decl2.c (lookup_name_nonclass): New function, skips over
- CLASS_VALUE.
- * decl.c (struct binding_level): Lose overloads_shadowed field.
- (poplevel): Don't deal with overloads_shadowed.
- (push_overloaded_decl): Do lexical hiding for functions.
- * class.c (instantiate_type): Don't check non-members if we have
- members with the same name.
- * call.c (build_method_call): Use lookup_name_nonclass instead of
- IDENTIFIER_GLOBAL_VALUE to check for non-member functions.
- (build_overload_call_real): Ditto.
-
- * decl.c (duplicate_decls): Check for ambiguous overloads here.
- (push_overloaded_decl): Instead of here.
+ * rtti.c (build_dynamic_cast): Pass tinfo fns rather than
+ calling them.
+ (get_tinfo_fn_dynamic): Extracted from build_typeid.
+ * tinfo2.cc (__dynamic_cast): Adjust.
- * decl.c (pushdecl): Back out Chip's last change.
+ * rtti.c (build_typeid): Use resolves_to_fixed_type_p.
+ (build_x_typeid): Likewise.
- * decl.c (grok_op_properties): operators cannot be static members.
+ * parse.y: Call build_x_typeid instead of build_typeid.
+ * cp-tree.def: Add TYPEID_EXPR.
+ * pt.c (tsubst_copy): Handle typeid.
+ * decl2.c (build_expr_from_tree): Likewise.
+ * rtti.c (build_x_typeid): Throw bad_typeid from here.
+ (build_typeid): Not here.
+ * cp-tree.h: Declare build_x_typeid.
- * cp-tree.h (DECL_SYNTHESIZED): DECL_SOURCE_LINE == 0
- (SET_DECL_SYNTHESIZED): DECL_SOURCE_LINE = 0
- * lex.c (cons_up_default_function): Use SET_DECL_SYNTHESIZED.
+Wed Sep 25 17:26:16 1996 Jason Merrill <jason@yorick.cygnus.com>
- * method.c (do_inline_function_hair): Don't put friends of local
- classes into global scope, either.
+ * call.c (convert_like): Pull out constant values.
- * typeck2.c (build_functional_cast): Don't look for a function call
- interpretation.
+ * tree.c (mapcar): Use build_cplus_array_type, not build_array_type.
-Thu Apr 28 15:19:46 1994 Mike Stump <mrs@cygnus.com>
+Wed Sep 25 17:28:53 1996 Michael Meissner <meissner@tiktok.cygnus.com>
- * cp-tree.h: disable use of backend EH.
+ * decl.c (init_decl_processing): Create short int types before
+ creating size_t in case a machine description needs to use
+ unsigned short for size_t.
-Wed Apr 27 21:01:24 1994 Doug Evans (dje@canuck.cygnus.com)
+Tue Sep 24 18:18:44 1996 Jason Merrill <jason@yorick.cygnus.com>
- * Make-lang.in (c++.distdir): mkdir tmp/cp first.
- * Makefile.in (INCLUDES): Move definition to same place as
- parent makefile.
- (ALLOCA): Define.
- (OLDAR_FLAGS): Delete.
- (OLDCC): Define.
- (DIR): Delete.
- (CLIB): Define.
- (####site): Delete.
- (SUBDIR_USE_ALLOCA): Don't use ALLOCA if compiling with gcc.
+ * Make-lang.in (exception.o): Turn off pic.
-Wed Apr 27 19:10:04 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * tinfo2.cc (__throw_type_match_rtti): Fix cv-variants of the same
+ type, multi-level ptr conversions.
- * decl.c (xref_tag): not to use strstr(), it's not available on
- all platforms.
+ * rtti.c (call_void_fn): Renamed and genericized from throw_bad_cast.
+ (throw_bad_cast): Use it.
+ (throw_bad_typeid): New fn.
+ (build_typeid): Throw bad_typeid as needed.
+ Use build_call.
+ (synthesize_tinfo_fn): Handle functions and arrays before checking
+ for cv-quals.
-Wed Apr 27 18:10:12 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * Remove .h from standard C++ headers, add new.h, move into inc
+ subdirectory.
- * class.c (finish_struct): Resolve yet another class/pmf confusion.
+ * exception*: Remove pointer from object, constructors. Add
+ default exception::what that uses type_info::name. Add
+ __throw_bad_typeid.
- * call.c (build_overload_call_real): Don't take the single-function
- shortcut if we're dealing with an overloaded operator.
+ * init.c (build_new): Don't add a cookie to new (void *) T[2].
-Wed Apr 27 17:35:37 1994 Mike Stump <mrs@cygnus.com>
+Mon Sep 23 15:21:53 1996 Jason Merrill <jason@yorick.cygnus.com>
- * search.c (get_base_distance): Search the virtual base class
- binfos, incase someone wants to convert to a real virtual base
- class.
- * search.c (expand_indirect_vtbls_init): Use convert_pointer_to_real
- instead of convert_pointer_to, as it now will work.
+ * Make-lang.in: Building C++ code depends on cc1plus.
-Wed Apr 27 15:36:49 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Sep 23 12:38:40 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cvt.c (convert_to_reference): Don't complain about casting away
- const and volatile.
+ * decl.c (struct saved_scope): Declare PROCESSING_TEMPLATE_DECL as
+ a HOST_WIDE_INT, not a tree.
- * typeck.c (build_unary_op): References are too lvalues.
+Mon Sep 23 12:36:02 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed Apr 27 13:58:05 1994 Mike Stump <mrs@cygnus.com>
+ * exception.cc: Don't include <stdlib.h>.
- * class.c (override_one_vtable): We have to prepare_fresh_vtable
- before we modify it, not after, also, we cannot reuse an old vtable,
- once we commit to a new vtable. Implement ambiguous overrides in
- virtual bases as abstract. Hack until we make the class
- ill-formed.
+ * Make-lang.in (c++.clean): Remove cplib2.*.
-Wed Apr 27 01:17:08 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Sep 23 09:42:19 1996 Doug Evans <dje@canuck.cygnus.com>
- * parse.y (unary_expr): Expand new_placement[opt] and
- new_initializer[opt] inline.
+ * parse.y (component_decl_1, component_costructor_declarator case):
+ Pass attributes/prefix_attributes in tree list.
- * search.c (lookup_fnfields): Don't throw away the inheritance
- information here, either.
- (compute_access): Handle static members properly.
+Mon Sep 23 01:18:50 1996 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (build_member_call): Always set basetype_path, and pass it
- to lookup_fnfields.
+ * tinfo{,2}.cc: #include <stddef.h> instead of <stdlib.h>.
- * search.c (lookup_field): Deal properly with the case where
- xbasetype is a chain of binfos; don't throw away the inheritance
- information.
- (compute_access): protected_ok always starts out at 0.
+Sun Sep 22 05:31:22 1996 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (resolve_offset_ref): Don't cast `this' to the base type
- until we've got our basetype_path.
+ * lex.c (do_identifier): Don't do deferred lookup in a template
+ header.
- * cp-tree.h (IS_OVERLOAD_TYPE): aggregate or enum.
+ * typeck2.c (store_init_value): Oops.
- * cvt.c (build_up_reference): Use build_pointer_type rather than
- TYPE_POINTER_TO.
+ * new.{h,cc}, exception.{h,cc}, typeinfo.h, tinfo{2.cc,.cc,.h}:
+ New files for C++ lang-support library.
+ * Make-lang.in (CXX_EXTRA_HEADERS): Define.
+ (CXX_LIB2FUNCS): Define.
+ And rules for building the C++ lang-support code.
+ * config-lang.in (headers): Define.
+ (lib2funcs): Define.
- * call.c (convert_harshness_ansi): Call type_promotes_to for reals
- as well.
+Sat Sep 21 19:17:28 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (type_promotes_to): Retain const and volatile, add
- float->double promotion.
-
- * decl.c (grokdeclarator): Don't bash references to arrays into
- references to pointers in function parms. Use type_promotes_to.
+ * decl2.c (build_expr_from_tree): If CONSTRUCTOR has a type, call
+ digest_init.
+ * pt.c (tsubst_copy): Compute type for CONSTRUCTOR.
+ * typeck2.c (store_init_value): Check for initializing pmf with { }
+ here.
+ (process_init_constructor): Not here.
-Tue Apr 26 23:44:36 1994 Mike Stump <mrs@cygnus.com>
+Thu Sep 19 16:41:07 1996 Jason Merrill <jason@yorick.cygnus.com>
- Finish off Apr 19th work.
+ * pt.c (begin_template_parm_list): Increment
+ processing_template_decl here.
+ (end_template_parm_list): Not here.
+ (process_template_parm): No need to add 1 to it now.
+ * *.c: Use processing_template_decl instead of current_template_parms
+ to check for being in a template.
- * class.c (finish_struct_bits): Rename has_abstract_virtuals to
- might_have_abstract_virtuals.
- * class.c (strictly_overrides, override_one_vtable,
- merge_overrides): New routines to handle virtual base overrides.
- * class.c (finish_struct): Call merge_overrides to handle overrides
- in virtual bases.
+ * pt.c (uses_template_parms): Handle SCOPE_REF. Fix CONSTRUCTOR.
+ (tsubst_copy): Handle CONSTRUCTOR.
+ (instantiate_decl): Set up context properly for variables.
+ * decl2.c (build_expr_from_tree): Handle CONSTRUCTOR.
+ * class.c (finish_struct): Reverse CLASSTYPE_TAGS.
-Tue Apr 26 12:45:53 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Sep 18 13:30:20 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * typeck.c (build_function_call): Call build_function_call_real with
- LOOKUP_NORMAL.
+ * lex.c (enum tree_node_kind) [GATHER_STATISTICS]: Put the enum back.
- * *: Don't deal with TYPE_EXPRs.
+Wed Sep 18 04:24:07 1996 Jason Merrill <jason@yorick.cygnus.com>
- * tree.c (lvalue_p): If the type of the expression is a reference,
- it's an lvalue.
+ * method.c (make_thunk): Call comdat_linkage before setting the
+ TREE_CODE.
- * cvt.c (convert_to_reference): Complain about passing const
- lvalues to non-const references.
- (convert_from_reference): Don't arbitrarily throw away const and
- volatile on the target type.
+ * decl2.c (comdat_linkage): Use make_decl_one_only.
+ (import_export_decl): Likewise.
+ * decl.c (init_decl_processing): Check supports_one_only instead of
+ SUPPORTS_WEAK.
- * parse.y: Simplify and fix rules for `new'.
+Sat Sep 14 08:34:41 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grok_op_properties): operator void is illegal.
+ * decl2.c (grokfield): Tighten checking for access decls.
-Mon Apr 25 02:36:28 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (make_typename_type): Resolve references to
+ current_class_type. Set CLASSTYPE_GOT_SEMICOLON.
+ (lookup_name_real): Types that depend on a template parameter get
+ an implicit 'typename' unless they're in the current scope.
+ (start_decl_1): We don't care about incomplete types that depend
+ on a template parm.
+ (grokdeclarator): Resolve 'typename's in the type specifier that
+ refer to members of the current scope.
- * parse.y (components): Anonymous bitfields can still have declspecs.
+ * call.c (build_over_call): Remove 'inline called before
+ definition' diagnostic.
+ (build_method_call): Likewise.
+ * decl.c (duplicate_decls): Downgrade 'used before declared
+ inline' to a warning, only with -Winline.
- * decl.c (pushdecl): Postpone handling of function templates like we
- do C functions.
+Fri Sep 13 17:31:40 1996 Stan Shebs <shebs@andros.cygnus.com>
- * search.c (expand_indirect_vtbls_init): Fix infinite loop when
- convert_pointer_to fails.
+ * mpw-make.sed: Fix include paths, add @DASH_C_FLAG@ to compile.
- * call.c (compute_conversion_costs_ansi): A user-defined conversion
- by itself is better than that UDC followed by standard conversions.
- Don't treat integers and reals specially.
+Wed Sep 11 22:38:13 1996 Gerald Baumgartner <gb@cs.purdue.edu>
- * cp-tree.h: Declare flag_ansi.
+ * call.c (build_method_call): When calling a signature
+ default implementation, as in other cases, let instance_ptr simply
+ be instance.
- * typeck.c (c_expand_return): pedwarn on return in void function
- even if the expression is of type void.
- (build_c_cast): Don't do as much checking for casts to void.
- (build_modify_expr): pedwarn about array assignment if this code
- wasn't generated by the compiler.
+Wed Sep 11 22:14:44 1996 Mike Stump <mrs@cygnus.com>
- * tree.c (lvalue_p): A comma expression is an lvalue if its second
- operand is.
+ * parse.y (simple_stmt): Cleanup and use do_poplevel ().
- * typeck.c (default_conversion): Move code for promoting enums and
- ints from here.
- * cvt.c (type_promotes_to): To here.
- * call.c (convert_harshness_ansi): Use type_promotes_to. Also fix
- promotion semantics for reals.
+Wed Sep 11 22:10:48 1996 Mike Stump <mrs@cygnus.com>
-Sun Apr 24 16:52:51 1994 Doug Evans (dje@canuck.cygnus.com)
+ * except.c (expand_start_catch_block): Add a pushlevel so that -g
+ works on hppa and SPARC.
- * Make-lang.in (c++.install-common): Check for g++-cross.
- * Makefile.in: Remove Cygnus cruft.
- (config.status): Delete.
- (RTL_H): Define.
- (TREE_H): Use complete pathname, some native makes have minimal
- VPATH support.
- (*.o): Use complete pathname to headers in parent dir.
- (doc, info, dvi): Delete.
+Wed Sep 11 10:18:06 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Sun Apr 24 16:52:51 1994 Doug Evans (dje@canuck.cygnus.com)
+ * typeck.c (build_indirect_ref): Catch PTR being an error_mark_node.
- * Make-lang.in (c++.install-common): Check for g++-cross.
- * Makefile.in: Remove Cygnus cruft.
- (config.status): Delete.
- (RTL_H): Define.
- (TREE_H): Use complete pathname, some native makes have minimal
- VPATH support.
- (*.o): Use complete pathname to headers in parent dir.
- (doc, info, dvi): Delete.
+Mon Sep 9 19:51:14 1996 Gerald Baumgartner <gb@cs.purdue.edu>
-Sun Apr 24 00:47:49 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (build_over_call): Check first whether DECL_CONTEXT exists
+ before testing whether it's a signature.
- * decl.c (pushdecl): Avoid redundant warning on redeclaring function
- with different return type.
- (decls_match): Compare return types strictly.
+Sun Sep 8 16:06:57 1996 Gerald Baumgartner <gb@cs.purdue.edu>
-Fri Apr 22 12:55:42 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (build_new_method_call): Don't complain about signature
+ pointers and references not being an aggr type.
+ (build_this): If a signature pointer or reference was passed in,
+ just return it.
+ (build_new_method_call): If instance is a signature pointer, set
+ basetype to the signature type of instance.
+ * sig.c (build_signature_method_call): Deleted basetype and
+ instance parameters, they can be found as the DECL_CONTEXT of
+ function and as the first argument passed in.
+ * cp-tree.h: Changed declaration of build_signature_method_call.
+ * call.c (build_method_call): Deleted first two arguments in call
+ of build_signature_method_call.
+ (build_over_call): Added call to build_signature_method_call.
- * cvt.c (build_type_conversion): Do try to convert through other
- pointers. This will fail if the class defines multiple pointer
- conversions.
+Thu Sep 5 16:51:28 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * typeck.c (build_c_cast): Don't tack a non_lvalue_expr onto a
+ target_expr.
+
+Thu Sep 5 10:05:38 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * cvt.c (convert_to_reference): Use %#T, not %#D, for error.
+
+Wed Sep 4 17:16:09 1996 Bob Manson <manson@charmed.cygnus.com>
+
+ * except.c (expand_start_try_stmts): Move to except.c in the backend.
+ (expand_end_try_stmts): Remove.
+
+ * init.c (perform_member_init): Use add_partial_entry () instead
+ of directly manipulating lists.
+ (emit_base_init): Ditto.
+
+Wed Sep 4 12:14:36 1996 Mike Stump <mrs@cygnus.com>
- * error.c (dump_type_prefix): Print out pointers to arrays properly.
- (dump_type_suffix): Ditto. (was 'int *[]', now 'int (*)[]')
+ * except.c (expand_exception_blocks): Always make sure USE and
+ CLOBBER insns that came at the end still do, the backend relies
+ upon this.
- * typeck.c (build_unary_op): Disallow ++/-- on pointers to
- incomplete type.
+Wed Sep 4 07:44:48 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * call.c (build_over_call): We can only use a TARGET_EXPR of the
+ right type.
+
+Tue Sep 3 19:26:05 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * cvt.c (convert_to_reference): Revert last change, don't complain
+ about temp without target decl.
+
+Tue Sep 3 10:22:56 1996 Mike Stump <mrs@cygnus.com>
+
+ * decl.c (grokdeclarator): Don't core dump when void() is given.
+
+Tue Sep 3 02:38:56 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * decl.c (copy_args_p): Don't crash.
+
+Fri Aug 30 14:26:57 1996 Mike Stump <mrs@cygnus.com>
+
+ * pt.c (tsubst): And support template args inside the exception
+ specification.
+
+ * pt.c (tsubst): Add support for exception specifications in
+ template functions.
+
+Fri Aug 30 10:01:55 1996 Mike Stump <mrs@cygnus.com>
+
+ * cp-tree.def (DECL_STMT): Eliminate the throw spec field, only 3
+ fields now.
+ * cp-tree.h (start_decl): Eliminate the throw spec parameter.
+ (start_function): Likewise.
+ (start_method): Likewise.
+ (grokfield): Likewise.
+ (make_call_declarator): Add throw spec parameter.
+ (set_quals_and_spec): Add routine.
+ * lex.c (set_quals_and_spec): Likewise.
+ * decl.h (grokdeclarator): Eliminate the throw spec parameter.
+ * decl.c (shadow_tag): Eliminate the throw spec parameter to
+ grokdeclarator.
+ (groktypename): Likewise.
+ (start_decl): Eliminate the throw spec parameter. Eliminate the
+ throw spec parameter to grokdeclarator. Eliminate the throw spec
+ field in DECL_STMT.
+ (cp_finish_decl): Eliminate the throw spec field in DECL_STMT.
+ (grokfndecl): Remove useless set of raises.
+ (grokdeclarator): Eliminate the throw spec parameter. Eliminate
+ the throw spec parameter to start_decl. Pull the throw spec out
+ of the call declarator.
+ (grokparms): Eliminate the throw spec parameter to grokdeclarator.
+ (start_function): Eliminate the throw spec parameter. Eliminate
+ the throw spec parameter to grokdeclarator.
+ (start_method): Likewise.
+ * decl2.c (grokfield): Likewise.
+ (grokbitfield): Eliminate the throw spec parameter to grokdeclarator.
+ (grokoptypename): Likewise.
+ (finish_file): Eliminate the throw spec parameter to
+ start_function. Add throw spec to make_call_declarator.
+ * except.c (init_exception_processing): Add throw spec to
+ make_call_declarator. Eliminate the throw spec parameter to
+ start_decl.
+ (expand_start_catch_block): Eliminate the throw spec parameter to
+ grokdeclarator.
+ (expand_builtin_throw): Add throw spec to make_call_declarator.
+ Eliminate the throw spec parameter to start_function.
+ (start_anon_func): Likewise.
+ * lex.c (make_call_declarator): Add throw spec parameter.
+ (set_quals_and_spec): New routine.
+ (cons_up_default_function): Add throw spec to make_call_declarator.
+ Eliminate the throw spec parameter to grokfield.
+ * method.c (synthesize_method): Eliminate the throw spec parameter
+ to start_function.
+ * pt.c (process_template_parm): Eliminate the throw spec parameter
+ to grokdeclarator.
+ (tsubst): Add throw spec to make_call_declarator.
+ (tsubst_expr): Eliminate the throw spec parameter to start_decl.
+ (do_function_instantiation): Eliminate the throw spec parameter to
+ grokdeclarator. Eliminate the throw spec parameter to
+ start_function.
+ * rtti.c (synthesize_tinfo_fn): Eliminate the throw spec parameter
+ to start_function.
+ * parse.y (datadef): Remove non-winning optimization.
+ (decl): Likewise.
+ (fndef): Remove ambiguous error productions uncovered by grammer
+ fixing.
+ (constructor_declarator): Add exception_specification_opt here.
+ (component_constructor_declarator): Likewise.
+ (direct_after_type_declarator): Likewise.
+ (complex_direct_notype_declarator): Likewise.
+ (direct_abstract_declarator): Likewise.
+ (fn.def1): Remove exception_specification_opt.
+ (fn.def2): Likewise.
+ (condition): Likewise.
+ (initdcl0): Likewise.
+ (initdcl): Likewise.
+ (notype_initdcl0): Likewise.
+ (nomods_initdcl0): Likewise.
+ (component_decl_1): Likewise.
+ (component_declarator): Likewise.
+ (after_type_component_declarator0): Likewise.
+ (after_type_component_declarator): Likewise.
+ (notype_component_declarator): Likewise.
+
+Wed Aug 28 01:40:30 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * call.c (build_over_call): Also use an INIT_EXPR when
+ initializing anything from an rvalue.
+
+ * call.c (build_over_call): Call stabilize_reference when building
+ an INIT_EXPR instead of calling the copy ctor.
+
+ * call.c (joust): Extend the previous change to all comparisons.
+
+ * decl2.c, method.c, lex.c: Use MAKE_DECL_ONE_ONLY and
+ NO_LINKAGE_HEURISTICS.
+
+ * decl2.c (finish_file): Emit any statics that weren't already.
+
+ * typeck.c (build_static_cast): Implement.
+ * tree.c (build_cplus_new): Handle getting a TARGET_EXPR.
+ * decl.c (grokparms): Use can_convert_arg instead of
+ implicit_conversion directly.
+ (copy_args_p): New fn.
+ * cvt.c (convert_to_reference): Don't complain about temp with
+ static_cast.
+ (build_up_reference): Handle TARGET_EXPRs.
+ * call.c (build_over_call): Elide unnecessary temps.
+ (can_convert*): Use new overloading code.
+
+Tue Aug 27 13:12:21 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * call.c: Move TYPE_PTR*_MACROS ...
+ * cp-tree.h: To here.
+ * typeck.c (build_reinterpret_cast): Implement.
+
+ * call.c (add_builtin_candidate): Use TYPE_PTROB_P instead of
+ ptr_complete_ob.
+ (joust): If we're comparing a function to a builtin and the worst
+ conversion for the builtin is worse than the worst conversion for the
+ function, take the function.
+
+ * typeck.c (build_const_cast): Implement.
+ (comp_ptr_ttypes_const): Like comp_ptr_ttypes, for const_cast.
+ (comp_ptr_ttypes_reinterpret): Like cpt, for reinterpret_cast.
+
+Tue Aug 27 13:14:58 1996 Bob Manson <manson@charmed.cygnus.com>
+
+ * rtti.c (build_dynamic_cast): Don't try to dereference exprtype
+ too early. Make sure we explode if exprtype turns out to be a
+ NULL_TREE when it shouldn't be.
+
+Tue Aug 27 10:56:21 1996 Mike Stump <mrs@cygnus.com>
+
+ * cp-tree.h: New routine make_call_declarator.
+ * lex.c (make_call_declarator): Define it.
+ * except.c (init_exception_processing): Use it.
+ (expand_builtin_throw): Likewise.
+ (start_anon_func): Likewise.
+ * decl2.c (finish_file): Likewise.
+ * lex.c (cons_up_default_function): Likewise.
+ * parse.y: Likewise.
+ * pt.c (tsubst): Likewise.
+
+Mon Aug 26 17:40:03 1996 Mike Stump <mrs@cygnus.com>
- * decl.c (duplicate_decls): Check mismatched TREE_CODES after
- checking for shadowing a builtin. If we're redeclaring a builtin
- function, bash the old decl to avoid an ambiguous overload.
+ * decl2.c (groktypefield): Remove unused code.
- * cvt.c (convert_to_reference): Don't force arrays to decay here.
+Mon Aug 26 17:00:33 1996 Mike Stump <mrs@cygnus.com>
- * tree.c (lvalue_p): A MODIFY_EXPR is an lvalue.
+ * gxx.gperf: Change TYPE_QUAL into CV_QUALIFIER.
+ * parse.y: Likewise. Change maybe_type_qual into maybe_cv_qualifier.
+ Change type_quals into cv_qualifiers. Change nonempty_type_quals into
+ nonempty_cv_qualifiers.
+ * hash.h: Rebuild.
+
+ * lex.c (make_pointer_declarator): Change type_quals into
+ cv_qualifiers.
+ (make_reference_declarator): Likewise.
+
+Thu Aug 22 01:09:22 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (duplicate_decls): Don't assume that the decls will have
- types.
+ * decl.c (start_function): Only check interface_* for templates
+ with flag_alt_external_templates.
- Mon Apr 18 11:35:32 1994 Chip Salzenberg (chip@fin.uucp)
+ * call.c (build_new_op): Check for comparison of different enum types.
+ (build_over_call): Fix arg # output.
- [ cp/* changes propagated from c-* changes in 940318 snapshot ]
- * c-decl.c (pushdecl): Warn if type mismatch with another external decl
- in a global scope.
+ * typeck.c (build_component_ref): Handle pre-found TYPE_DECL.
- Fri Apr 22 06:38:56 1994 Chip Salzenberg (chip@fin.uucp)
+Wed Aug 21 00:13:15 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp/typeck2.c (signature_error): Use cp_error for "%T".
+ * call.c (build_new_op): Check for erroneous args.
- Mon Apr 18 11:59:59 1994 Chip Salzenberg (chip@fin.uucp)
+ * call.c (build_new_method_call): Add missing args to cp_error.
- [ cp/* changes propagated from c-* changes in 940415 snapshot ]
- * cp/decl.c (duplicate_decls, pushdecl, builtin_function):
- Use DECL_FUNCTION_CODE instead of DECL_SET_FUNCTION_CODE.
+ * tree.c (error_type): Dont print reference-to-array.
- Mon Apr 18 11:55:18 1994 Chip Salzenberg (chip@fin.uucp)
+ * typeck.c (convert_for_assignment): Don't say contravariance for
+ removing const.
- [ cp/* changes propagated from c-* changes in 940409 snapshot ]
- * cp/decl.c (duplicate_decls): Put new type in same obstack as
- old ones, or permanent if old ones in different obstacks.
+Tue Aug 20 13:23:00 1996 Jason Merrill <jason@yorick.cygnus.com>
- Mon Apr 18 11:48:49 1994 Chip Salzenberg (chip@fin.uucp)
+ * call.c (build_over_call): Diagnose bad convs for `this'.
- [ cp/* changes propagated from c-* changes in 940401 snapshot ]
- * cp/parse.y (attrib): Handle string args as expressions,
- merging the two rules. `mode' attribute now takes a string arg.
- Delete the rule for an identifier as arg.
+ * lex.c (cons_up_default_function): Set DECL_ARTIFICIAL
+ on _ctor_arg.
- Mon Apr 18 11:24:00 1994 Chip Salzenberg (chip@fin.uucp)
+ * call.c (convert_like): Handle bad convs.
+ (build_over_call): Handle bad convs better.
- [ cp/* changes propagated from c-* changes in 940312 snapshot ]
- * cp/typeck.c (pointer_int_sum): Multiplication should be done signed.
- (pointer_diff): Likewise the division.
+ * decl2.c: -fansi-overloading is now the default.
- Sun Mar 6 19:43:39 1994 Chip Salzenberg (chip@fin.uucp)
+ * call.c (build_new_method_call): Check for erroneous args.
- [ cp/* changes propagated from c-* changes in 940304 snapshot ]
- * cp/decl.c (finish_decl): Issue warning for large objects,
- if requested.
+ * pt.c (instantiate_class_template): Propagate
+ TYPE_USES_MULTIPLE_INHERITANCE.
- Sat Feb 19 22:20:32 1994 Chip Salzenberg (chip@fin.uucp)
+Tue Aug 20 13:09:57 1996 Mike Stump <mrs@cygnus.com>
- [ cp/* changes propagated from c-* changes in 940218 snapshot ]
- * cp/parse.y (attrib): Handle attribute ((section ("string"))).
- * cp/decl.c (duplicate_decls): Merge section name into new decl.
+ * call.c (enforce_access): Add static to routine.
- Tue Feb 8 09:49:17 1994 Chip Salzenberg (chip@fin.uucp)
+Sun Aug 18 14:35:54 1996 Jason Merrill <jason@yorick.cygnus.com>
- [ cp/* changes propagated from c-* changes in 940206 snapshot ]
- * cp/typeck.c (signed_or_unsigned_type): Check for any
- INTEGRAL_TYPE_P not just INTEGER_TYPE.
+ * call.c (build_user_type_conversion_1): Fix bad handling.
+ (compare_ics): Likewise.
- Mon Dec 6 13:35:31 1993 Norbert Kiesel (norbert@i3.INformatik.rwth-aachen.DE)
+Sat Aug 17 21:54:11 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp/decl.c (finish_enum): Start from 0 when determining precision
- for short enums.
+ * call.c (standard_conversion): Oops.
- Fri Dec 3 17:07:58 1993 Ralph Campbell (ralphc@pyramid.COM)
+Sat Aug 17 16:28:11 1996 Geoffrey Noer <noer@cygnus.com>
- * cp/parse.y (unary_expr): Look at $1 for tree_code rather than
- casting $$.
+ * g++.c: Update test for win32 (&& ! cygwin32).
- Wed Nov 17 19:22:09 1993 Chip Salzenberg (chip@fin.uucp)
+Sat Aug 17 03:45:31 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp/typeck.c (build_binary_op_nodefault): Propagate code
- from C front-end to optimize unsigned short division.
- (build_conditional_expr): Fix bug in "1 ? 42 : (void *) 8".
+ * typeck.c (comp_ptr_ttypes_real): Handle OFFSET_TYPEs properly.
+ (ptr_reasonably_similar): New fn.
+ * call.c (BAD_RANK): New rank.
+ (ICS_BAD_FLAG): New macro.
+ (standard_conversion): Handle almost-right pointer conversions.
+ (reference_binding): Handle bad rvalue bindings.
+ (add_*_candidate): Stuff.
+ (build_over_call): Pass bad conversions to convert_for_initialization.
+ (compare_ics): Handle bad convs.
+ (joust): Likewise.
- Wed Nov 17 19:17:18 1993 Chip Salzenberg (chip@fin.uucp)
+Fri Aug 16 15:02:19 1996 Bob Manson <manson@charmed.cygnus.com>
- * cp/call.c (convert_harshness_ansi): Given an (e.g.) char
- constant, prefer 'const char &' to 'int'.
+ * init.c (expand_vec_init): Use ptrdiff_type_node instead of
+ integer_type_node when computing pointer offsets.
- Wed Feb 3 13:11:48 1993 Chip Salzenberg (chip@fin.uucp)
+Fri Aug 16 01:28:32 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp/class.c (finish_struct_methods): Handle multiple
- constructors in fn_fields list.
+ * tree.c (lvalue_type): New fn.
+ (error_type): New fn.
+ * call.c (op_error): Use error_type.
+ (add_conv_candidate): Use lvalue_type.
+ (add_builtin_candidates): Likewise.
+ * error.c (args_as_string): Use error_type.
-Fri Apr 22 12:48:10 1994 Kung Hsu (kung@mexican.cygnus.com)
+Thu Aug 15 17:27:13 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): use TYPE_DECL_SUPPRESS_DEBUG to flag
- types not to be dumped in stabs, like types in #pragma interface.
- * decl.c (init_decl_processing): use TYPE_DECL_SUPPRESS_DEBUG to
- mark unknown type.
+ * pt.c (instantiate_decl): Evaluate DECL_INITIAL of a VAR_DECL here.
+ (tsubst): Not here.
-Fri Apr 22 03:27:26 1994 Doug Evans (dje@cygnus.com)
+ * decl.c (init_decl_processing): With -ansi, __null's type is the
+ signed integral type with the same number of bits as a pointer.
+ Introduce a new variable null_node for it.
+ * cp-tree.h: Adjust.
+ * call.c (null_ptr_cst_p): Adjust.
- * Language directory reorganization.
- See parent makefile.
+Thu Aug 15 17:09:54 1996 Mike Stump <mrs@cygnus.com>
-Thu Apr 21 18:27:57 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * except.c (do_unwind): Mark %i7 as used on the SPARC so we can
+ optimize.
- * cp-tree.h (THUNK_DELTA): It is normally negative, so
- use signed .i variant of frame_size rather than unsigned .u.
- * cp-tree.h (VTABLE_NAME_FORMAT): If flag_vtable_thunks,
- use "VT" rather than "vt" due to binary incompatibility.
- * class.c (get_vtable_name): Use strlen of VTABLE_NAME_FORMAT,
- rather than sizeof, since it is now an expression.
- * class.c (modify_one_vtable): Modify to skip initial element
- containing a count of the vtable.
+Thu Aug 15 01:36:49 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Apr 21 00:09:02 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (import_export_decl): Ignore #pragma interface for tinfo
+ fns of classes without virtual functions.
- * lex.c (check_newline): Force interface_unknown on main input file.
+ * call.c (add_function_candidate): Handle `this' specially.
+ (compare_ics): Likewise.
- * pt.c (do_pending_expansions): Always emit functions that have been
- explicitly instantiated.
- (do_function_instantiation): Set DECL_EXPLICITLY_INSTANTIATED.
- (do_type_instantiation): Set CLASSTYPE_VTABLE_NEEDS_WRITING and
- DECL_EXPLICITLY_INSTANTIATED on all my methods.
- * parse.y (explicit_instantiation): Call do_type_instantiation for
- types.
- * decl2.c (finish_vtable_vardecl): Call import_export_vtable.
- * decl.c (start_function): Don't set DECL_EXTERNAL on a function
- that has been explicitly instantiated.
- * cp-tree.h (DECL_EXPLICITLY_INSTANTIATED): Alias for
- DECL_LANG_FLAG_4.
- * class.c: Move import_export_vtable to decl2.c, and comment out all
- uses.
-
-Wed Apr 20 16:51:06 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- * lex.c (process_next_inline): Don't muck with DECL_INLINE.
- (do_pending_inlines): Ditto.
-
-Tue Apr 19 22:25:41 1994 Mike Stump <mrs@cygnus.com>
-
- Reimplement vtable building, and most vtable pointer setting.
- Allows for earier maintenance, easier understandability, and most
- importantly, correct semantics.
-
- * class.c (build_vtable): Removed unneeded
- SET_BINFO_VTABLE_PATH_MARKED.
- * class.c (prepare_fresh_vtable): Ditto. Added argument.
- * class.c (modify_vtable_entry): General cleanup.
- * class.c (related_vslot, is_normal, modify_other_vtable_entries,
- modify_vtable_entries): Removed.
- * class.c (add_virtual_function): General cleanup.
- * class.c (finish_base_struct): Setup BINFO_VTABLE and
- BINFO_VIRTUALS as early as we can, so that modify_all_vtables can
- work.
- * class.c (finish_vtbls): New routine, mostly from
- unmark_finished_struct.
- * class.c (overrides): New routine.
- * class.c (modify_one_vtable): New routine, mostly from
- modify_other_vtable_entries and modify_vtable_entries.
- * class.c (modify_all_direct_vtables, modify_all_indirect_vtables,
- modify_all_vtables): New routines.
- * class.c (finish_struct): Added arguemnt to prepare_fresh_vtable
- call. General cleanup on how pending_hard_virtuals are handled.
- General cleanup on modifying vtables. Use finish_vtbls, instead of
- unmark_finished_struct.
- * cp-tree.h (init_vtbl_ptrs, expand_direct_vtbls_init,
- get_first_matching_virtual, get_matching_virtual,
- expand_vbase_vtables_init, expand_indirect_vtbls_init): Update.
- * cvt.c (convert_pointer_to_real): cleanup error message.
- * decl.c (grokfndecl): General cleanup.
- * decl.c (finish_function): Change init_vtbl_ptrs call to
- expand_direct_vtbls_init. Change expand_vbase_vtables_init call to
- expand_indirect_vtbls_init.
- * init.c (expand_virtual_init): Remove unneeded argument.
- * init.c (init_vtbl_ptrs): Rename to expand_direct_vtbls_init, added
- two arguments to make more general. Made more general. Now can be
- used for vtable pointer initialization from virtual bases.
- * init.c (emit_base_init): Change expand_vbase_vtables_init call to
- expand_indirect_vtbls_init. Change init_vtbl_ptrs call to
- expand_direct_vtbls_init.
- * init.c (expand_virtual_init): General cleanup.
- * init.c (expand_default_init): Change expand_vbase_vtables_init
- call to expand_indirect_vtbls_init.
- * init.c (expand_recursive_init_1): Change expand_vbase_vtables_init
- call to expand_indirect_vtbls_init.
- * init.c (expand_recursive_init): Change expand_vbase_vtables_init
- call to expand_indirect_vtbls_init.
- * search.c (get_first_matching_virtual): Rename to
- get_matching_virtual. General cleanup and remove setting of
- DECL_CONTEXT. That is now done in a cleaner way in
- modify_vtable_entry and add_virtual_function.
- * search.c (expand_vbase_vtables_init): Rename to
- expand_indirect_vtbls_init. General cleanup. Use
- expand_direct_vtbls_init to do hard work. Ensures that _all_ vtable
- pointers from virtual bases are set up.
- * search.c (bfs_unmark_finished_struct, unmark_finished_struct):
- Removed.
-
- * *.[chy]: Remove support for VTABLE_USES_MASK.
-
-Tue Apr 19 12:51:59 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- * cvt.c (convert_to_reference): Use NOP_EXPRs to switch between
- reference and pointer types instead of bashing the types directly.
-
- * call.c (build_overload_call_real): Use the TREE_CODE to determine
- whether the function is overloaded or not, rather than
- TREE_OVERLOADED.
- * *: Remove all uses of TREE_OVERLOADED.
-
- * decl.c (grokdeclarator): Only complain about initializing const
- fields when -ansi or -pedantic.
-
-Tue Apr 19 12:42:42 1994 Doug Evans (dje@canuck.cygnus.com)
-
- * cp-tree.h (THUNK_DELTA): frame_size is now a union.
-
-Mon Apr 18 00:17:13 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- Do overloading on a block-by-block basis, not function-by-function.
- * decl.c: Lose overloads_to_forget.
- (struct binding_level): Add overloads_shadowed field.
- (poplevel): Restore overloads_shadowed.
- (push_overloaded_decl): Use overloads_shadowed instead of
- overloads_to_forget.
- (finish_function): Don't look at overloads_to_forget.
-
- Copy enum_overflow logic from c-decl.c.
- * decl.c (start_enum): Initialize enum_overflow.
- (build_enumerator): Use enum_overflow. Also use current_scope().
-
- * search.c (current_scope): Move Brendan's comment from
- build_enumerator here.
-
- * typeck.c (convert_for_assignment): Change warnings to pedwarns for
- discarding const/volatile.
-
-Sat Apr 16 01:18:21 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- * typeck.c (comp_target_parms): Accept TEMPLATE_TYPE_PARMs on the rhs.
- (comp_target_types): Ditto.
-
- * decl.c (lookup_name): Don't unset got_scope here.
-
- * spew.c (yylex): Only replace yylval with the TYPE_NESTED_NAME if
- got_scope != NULL_TREE.
-
-Fri Apr 15 16:36:33 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- Horrible kludge to prevent templates from being instantiated by
- their base classes.
- * parse.y (template_instantiate_once): Unset TYPE_BEING_DEFINED
- before we get to left_curly.
- * pt.c (instantiate_class_template): Set TYPE_BEING_DEFINED.
-
- * error.c (dump_decl): If it's a typedef, print out the name of the
- decl, not just the underlying type.
-
- * decl.c (pushdecl): If the old duplicate decl was a TYPE_DECL,
- update the IDENTIFIER_TYPE_VALUE of its name.
-
- * decl2.c (finish_file): When processing the initializer for a
- static member, pretend that the dummy function is a member of the
- same class.
-
-Fri Apr 15 15:56:35 1994 Kung Hsu (kung@mexican.cygnus.com)
-
- * class.c (build_vtable_entry): revert Apr 4 change.
- * decl2.c (mark_vtable_entries): replace pure virtual function
- decl with abort's.
+Tue Aug 13 12:16:10 1996 Jason Merrill <jason@yorick.cygnus.com>
-Fri Apr 15 13:49:33 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (build_conditional_expr): Fix handling of __null.
- * typeck.c (build_conditional_expr): Pedwarn on pointer/integer
- mismatch, and don't pedwarn on 0/function pointer mismatch.
+ * decl2.c (comdat_linkage): New fn.
+ (import_export_vtable): Use it.
+ (import_export_decl): Use it.
+ * method.c (make_thunk): Use it.
- * typeck2.c (digest_init): Lose code for special handling of unions.
- (process_init_constructor): Since they're handled just fine here.
- Pedwarn on excess elements.
+Mon Aug 12 00:09:18 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (grokfield): Complain about local class method declaration
- without definition.
+ * pt.c (end_template_decl): If we don't actually have parms, return.
+ * parse.y (template_header): Accept 'template <>'.
-Fri Apr 15 13:19:40 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * errfn.c: Allow 5 args.
- * method.c (emit_thunk): Add extern declaration for
- current_call_is_indirect (needed for hppa).
+Sun Aug 11 15:20:58 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Apr 14 16:12:31 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * tree.c (make_temp_vec): New fn.
+ * pt.c (push_template_decl): Handle partial specs.
+ (instantiate_class_template): Likewise.
+ (more_specialized): Use get_bindings.
+ (more_specialized_class): New fn.
+ (get_class_bindings): New fn.
+ (most_specialized_class): New fn.
+ (do_function_instantiation): List candidates for ambiguous case.
+ * decl.c (duplicate_decls): Lose reference to DECL_TEMPLATE_MEMBERS.
+ (shadow_tag): Call push_template_decl for partial specializations.
+ * parse.y: Likewise.
+ * cp-tree.h (DECL_TEMPLATE_SPECIALIZATIONS): Replaces
+ DECL_TEMPLATE_MEMBERS.
+ * call.c (print_z_candidates): Reduce duplication.
- Improve local class support; allow classes in different blocks to
- have the same name.
- * decl.c (pushtag): Support local classes better.
- (pushdecl_nonclass_level): New function for pushing mangled decls of
- nested types into the appropriate scope.
- (xref_defn_tag): Use pushdecl_nonclass_level instead of
- pushdecl_top_level.
- (grokfndecl): Don't mess with IDENTIFIER_GLOBAL_VALUE for local
- class methods.
- * method.c (do_inline_function_hair): Ditto.
+Fri Aug 9 14:36:08 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): It is legal for a class with no
- constructors to have nonstatic const and reference members.
+ * decl2.c (lang_decode_option): Allow -fansi-overloading.
-Thu Apr 14 07:15:11 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+Thu Aug 8 17:04:18 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (push_overloaded_decl): Avoid giving errors about
- built-ins, since duplicate_decls will have given warnings/errors
- for them.
+ * pt.c (get_bindings): New fn.
+ (most_specialized): Likewise.
+ (do_function_instantiation): Use them.
+ (add_maybe_template): New fn.
+ * cp-tree.h (DECL_MAYBE_TEMPLATE): New macro.
+ * call.c (build_new_op): Handle guiding decls.
+ (build_new_function_call): Likewise.
+ * decl2.c (finish_file): Likewise.
-Thu Apr 14 03:45:12 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (mark_used): Do synthesis here.
+ * call.c (build_method_call): Not here.
+ (build_over_call): Or here.
+ * typeck.c (build_function_call_real): Or here.
+ * tree.c (bot_manip): Call mark_used on functions used in default
+ args.
- * cvt.c (convert_to_reference): Warn about casting pointer type to
- reference type when this is probably not what they wanted.
+Thu Aug 8 17:48:16 1996 Michael Meissner <meissner@tiktok.cygnus.com>
-Wed Apr 13 13:12:35 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * decl2.c (import_export_vtable): Delete code that disabled vtable
+ heuristic on systems with ASM_OUTPUT_EXTERNAL.
- * decl.c (finish_decl): Don't mindlessly set TREE_USED for
- static consts any more (toplev.c has now been modified to
- not emit warnings if they are unused).
+Wed Aug 7 12:44:11 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed Apr 13 00:22:35 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (build_x_function_call): Handle static call context
+ better.
- * decl.c (grok_op_properties): If op new/delete get here with
- METHOD_TYPEs, do a revert_static_member_fn.
+ * decl.c (finish_function): Set the DECL_CONTEXT of the result to
+ the function, not its outer block.
- * cp-tree.h (IDENTIFIER_CLASS_TYPE_VALUE): Lose.
- * init.c (is_aggr_typedef): Don't look at
- IDENTIFIER_CLASS_TYPE_VALUE.
- (get_aggr_from_typedef): Ditto.
- (get_type_value): Ditto.
- * call.c (build_scoped_method_call): Don't rely on overloaded
- template names having IDENTIFIER_CLASS_VALUE set.
+ * call.c (build_field_call): Pass fields on to build_opfncall
+ regardless of TYPE_OVERLOADS_CALL_EXPR.
+ (build_method_call): Pass on to build_new_method_call sooner.
- * parse.y (component_decl_1, fn.def2): Revert rules for
- constructors.
- (component_decl_1, fn.def2): Use $1 instead of $$, since $$ is being
- clobbered.
+ * typeck.c (build_ptrmemfunc): Just return what instantiate_type
+ gives us.
+ * class.c (instantiate_type): Don't put a POINTER_TYPE to
+ METHOD_TYPE on an expression. Also make a copy of rhs instead of
+ modifying it.
- * decl.c (start_function): Only warn about `void main()' if pedantic
- || warn_return_type.
+Tue Aug 6 12:58:46 1996 Jason Merrill <jason@yorick.cygnus.com>
-Tue Apr 12 02:14:17 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (compare_ics): Handle qual_conv after lvalue_conv.
+ (add_builtin_candidate): Don't take enums for ++.
+ (build_new_method_call): Handle non-aggregates and field calls.
+ Move new overloading code from...
+ * cvt.c: Here.
- Clean up overloading of the template name.
- * class.c (pushclass): overload the template name whenever pushing
- into the scope of a template class, not just if it is
- uninstantiated.
- (popclass): Correspondingly.
- * search.c (push_class_decls): Don't overload_template_name.
- * pt.c (overload_template_name): Don't set IDENTIFIER_LOCAL_VALUE or
- DECL_CONTEXT on things.
- * parse.y (left_curly): Don't overload_template_name.
- * class.c (finish_struct): Don't undo_template_name_overload.
+ * decl.c (grokparms): Don't check default args in templates.
- * method.c (build_opfncall): Only pass one argument to global op
- delete.
+Mon Aug 5 17:17:06 1996 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_method_call): Use TYPE_VEC_DELETE_TAKES_SIZE to
- decide how many arguments to use for vec delete.
+ * cvt.c (build_new_op): Fix args to build_unary_op.
+ (add_builtin_candidates): Don't call type_promotes_to on float.
- * decl.c (grok_op_properties): Be consistent in modifying
- current_class_type.
- (grokdeclarator): Only complain about function decls with no return
- type if we're being pedantic.
-
-Mon Apr 11 00:10:53 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- Add support for operator new [] and operator delete [].
-
- * tree.def: Add VEC_NEW_EXPR and VEC_DELETE_EXPR.
- * ptree.c (print_lang_type): Indicate vec new/delete.
- * parse.y: Support vec new/delete.
- * method.c (build_decl_overload): Deal with vec new/delete.
- (build_opfncall): Ditto.
- * lex.c (init_lex): Set up values of ansi_opname and opname_tab for
- vec new/delete. vec new uses "__vn", and vec delete uses "__vd".
- * init.c (init_init_processing): Set up BIVN and BIVD.
- (do_friend): Don't clean up after mistaken setting of TREE_GETS_NEW,
- since it doesn't happen any more.
- (build_new): Support vec new. Always call something.
- (build_x_delete): Support vec delete.
- (build_vec_delete): Lose dtor_dummy argument, add use_global_delete,
- and pass it to build_x_delete.
- * decl2.c (delete_sanity): Don't change behavior by whether or not
- the type has a destructor. Pass use_global_delete to
- build_vec_delete.
- (coerce_delete_type): Make sure that the type returned has a first
- argument of ptr_type_node.
- * decl.c (init_decl_processing): Also declare the global vec
- new/delete.
- (grokdeclarator): Also force vec new/delete to be static.
- (grok_op_properties): Note presence of vec new/delete, and play with
- their args. If vec delete takes the optional size_t argument, set
- TYPE_VEC_DELETE_TAKES_SIZE.
- * cp-tree.h (TYPE_GETS_{REG,VEC}_DELETE): New macros to simplify
- checking for one delete or the other.
- (lang_type): gets_new and gets_delete are now two bits long. The
- low bit is for the non-array version. Lose gets_placed_new.
- (TYPE_VEC_DELETE_TAKES_SIZE): New macro indicating that the vec
- delete defined by this class wants to know how much space it is
- deleting.
- (TYPE_VEC_NEW_USES_COOKIE): New macro to indicate when vec new must
- add a header containing the number of elements in the vector; i.e.
- when the elements need to be destroyed or vec delete wants to know
- the size.
- * class.c (finish_struct_methods): Also check for overloading vec
- delete.
- * call.c (build_method_call): Also delete second argument for vec
- delete.
+ * decl.c (grokparms): Check the type of the default arg.
- * decl.c (grokdeclarator): Correct complaints again.
- (grokdeclarator): Fix segfault on null declarator.
- (decls_match): Also accept redeclaration with no arguments if both
- declarations were in C context. Bash TREE_TYPE (newdecl) here.
- (duplicate_decls): Instead of here.
+ * cvt.c (build_new_op): Pass non-overloaded cases on rather than
+ returning NULL_TREE.
- * parse.y (nested_name_specifier_1): Lose rules for dealing with
- syntax errors nicely, since they break parsing of 'const i;'.
+ * typeck.c (build_x_binary_op): Avoid doing extra work.
+ (build_x_unary_op): Likewise.
+ (build_x_conditional_expr): Likewise.
+ * cvt.c (build_over_call): Return.
+ (add_builtin_candidate): Fix MEMBER_REF.
+ (build_new_op): Likewise.
- * decl.c (lookup_name): if (got_scope == current_class_type)
- val = IDENTIFIER_CLASS_VALUE (name).
+Mon Aug 5 17:07:47 1996 Mike Stump <mrs@cygnus.com>
- * search.c (lookup_nested_tag): Look in enclosing classes, too.
+ * method.c (build_overload_name): Put bug fix into code but leave
+ disabled for now so we can be bug compatible with older releases
+ that do repeats incorrectly. In the future, we can enable it.
- * spew.c (yylex): Only look one character ahead when checking for a
- SCOPE.
+Mon Aug 5 13:46:28 1996 Jason Merrill <jason@yorick.cygnus.com>
- * lex.c (check_newline): Read first nonwhite char before
- incrementing lineno.
+ * cvt.c (convert_like): Don't call build_cplus_new twice.
- * decl.c (grokdeclarator): Don't claim that typedefs are variables
- in warning.
+ * call.c, cp-tree.h, cvt.c, decl2.c, init.c, method.c, pt.c, typeck.c:
+ Control new overloading code with -fansi-overloading.
- * parse.y: Divide up uses of unqualified_id into
- notype_unqualified_id and unqualified_id, so that TYPENAME can be
- used as an identifier after an object.
+Sun Aug 4 15:29:11 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (push_nested_class): Don't push into non-class scope.
+ * cvt.c (build_over_call): Call build_cplus_new.
+ * call.c (build_method_call): Likewise.
+ * typeck.c (build_function_call_real): Likewise.
+ (build_conditional_expr): If both operands are TARGET_EXPRs, wrap
+ the COND_EXPR in a TARGET_EXPR so they use the same slot.
- * decl.c (grokdeclarator): If an identifier could be a type
- conversion operator, but has no associated type, it's not a type
- conversion operator.
+ * cvt.c (build_up_reference): Propagate INDIRECT_BIND to
+ recursive calls.
+ * typeck.c (complete_type): Propagate
+ TYPE_NEEDS_{CONSTRUCTING,DESTRUCTOR}.
- * pt.c (unify): Check for equality of constants better.
+Sat Aug 3 14:05:07 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokdeclarator): Don't complain about access decls.
+ * cvt.c (joust): More ?: kludging. Sigh.
+ (build_over_call): Don't try to synthesize global fns.
-Sun Apr 10 02:39:55 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * search.c (lookup_conversions): Use binfo marking.
- * decl.c (grokdeclarator): pedwarn about data definitions without
- types here.
+Sat Aug 3 12:33:42 1996 Bob Manson <manson@charmed.cygnus.com>
- * parse.y (datadef): Don't pedwarn about decls without types here,
- since that is valid for functions.
- (fn.def2, component_decl): Support constructors with declmods again.
- (nomods_initdecls): For decls without any mods, so that we don't try
- to get declspecs from some arbitrary $0.
+ * search.c (build_mi_matrix): Use the correct value of cid
+ when determining the new mi_size.
- * search.c (lookup_field): Use cp_error.
+Sat Aug 3 01:27:41 1996 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (nested_name_specifier_1): Don't check aggr/non-aggr type
- here; it breaks destructors for non-aggr types.
+ * cvt.c (add_builtin_candidates): Do consider type conversion ops
+ for the first parms of += et al.
+ (strip_top_quals): New fn.
+ (reference_binding): Use it instead of TYPE_MAIN_VARIANT.
+ (implicit_conversion): Likewise.
+ (add_builtin_candidates): Be careful about arrays.
+ (build_new_method_call): Handle vtable optimization.
- * decl.c (lookup_name): Only look for TYPE_DECLs in base classes of
- a type being defined, like the comment says.
- If got_scope is not an aggregate, just return NULL_TREE.
+Fri Aug 2 01:26:59 1996 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (create_nested_upt): Kung's code for creating types nested
- within uninstantiated templates now lives here (it used to live in
- hack_more_ids). It needs to be expanded.
+ * cp-tree.h (LOOKUP_NO_TEMP_BIND): New flag.
+ * cvt.c (reference_binding): Use it.
+ (implicit_conversion): Use it.
+ (add_builtin_candidate, COND_EXPR): Use it.
- * parse.y: Stop calling see_typename so much.
+ * cvt.c (build_new_function_call): Check for error args.
- * decl.c (lookup_name): Deal with TTPs and UPTs.
+ * typeck.c (comptypes): Just check DERIVED_FROM_P, not UNIQUELY.
- * lex.c (real_yylex): Don't set looking_for_typename just because we
- saw a 'new'.
- (dont_see_typename): #if 0 out.
+ * gxx.gperf: Add __null.
+ * hash.h: Regenerate.
+ * lex.h: Add RID_NULL.
+ * lex.c (init_lex): Create null_pointer_node here, stick it in
+ RID_NULL.
+ * decl.c (init_decl_processing): Still set its type here.
+ * cvt.c (cp_convert_to_pointer): Don't produce null_pointer_node.
+ (convert_to_pointer_force): Likewise.
+ (null_ptr_cst_p): Check for null_pointer_node; only accept (void*)0
+ if (! pedantic).
+ * call.c (convert_harshness): Use null_ptr_cst_p.
+ * typeck.c (convert_for_assignment): Likewise. Don't produce
+ null_pointer_node.
- * spew.c (yylex): Increment looking_for_typename if the next
- character is SCOPE, rather than setting it to 1; this way, the value
- from seeing an aggr specifier will not be lost. This kinda relies
- on looking_for_typename never being < 0, which is now true.
+ * error.c (args_as_string): Handle lists of actual args, too.
+ * cvt.c (null_ptr_cst): Support (void*)0 for now.
+ (build_user_type_conversion_1): Improve diagnostics.
+ (build_new_function_call): Likewise.
+ (build_object_call): Likewise.
+ (build_new_method_call): Likewise. Move call before def diagnostic...
+ (build_over_call): Here.
- * parse.y (nested_name_specifier_1): Accept TEMPLATE_TYPE_PARMs,
- too.
- (named_class_head_sans_basetype): Accept template types, too. Oops.
+ * cvt.c (build_new_method_call): Don't complain about no match if
+ LOOKUP_SPECULATIVELY.
+ (build_over_call): Fix 'this' for virtual fn.
+ (build_new_method_call): Add diagnostic.
-Fri Apr 8 16:39:35 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu Aug 1 16:45:09 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (reparse_decl_as_expr1): Handle SCOPE_REFs.
+ * cvt.c (add_function_candidate): Expect 'this' and 'in_chrg' for
+ constructors to be passed in.
+ (build_over_call): Likewise.
+ (build_user_type_conversion_1): Pass them in.
+ (convert_like): Likewise.
+ (build_object_call): Handle overloaded conversions.
+ (build_over_call): Pass the right args to build_vfn_ref.
+ (standard_conversion): Fix pmf convs.
+ (joust): Handle comparing statics and non-statics.
+ (build_new_method_call): New fn.
+ * call.c (build_method_call): Call it if NEW_OVER.
- * parse.y: Lose START_DECLARATOR.
+Thu Aug 1 16:06:14 1996 Mike Stump <mrs@cygnus.com>
- * search.c (lookup_nested_tag): New function to scan CLASSTYPE_TAGS
- for a class.
+ * lex.c (do_identifier): Don't use %O on IDENTIFIER_OPNAME_Ps, use
+ %D instead.
- * parse.y: Simplify fn.def2 and component_decl. Support 'enum
- A::foo' syntax. Catch invalid scopes better.
+Thu Aug 1 15:24:02 1996 Mike Stump <mrs@cygnus.com>
- * parse.y, lex.c: lose TYPENAME_COLON.
+ * except.c (expand_throw): Use maybe_build_cleanup_and_delete
+ instead of just maybe_build_cleanup so that we deallocate the
+ thrown object.
- * decl2.c (groktypefield): #if 0 out.
+Thu Aug 1 15:18:00 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c (lookup_name): If the type denoted by got_scope is
- currently being defined, look in CLASSTYPE_TAGS rather than FIELDS.
+ * decl2.c (finish_prevtable_vardecl): Make non-static for pt.c's use.
+ * cp-tree.h (finish_prevtable_vardecl): Add decl.
- * class.c (push_nested_class): Don't try to push into
- error_mark_node.
+Thu Aug 1 11:53:51 1996 Bob Manson <manson@charmed.cygnus.com>
-Fri Apr 8 07:26:36 1994 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * pt.c (instantiate_class_template): Call complete_type. Also, if
+ we're at the end of the file and we just instantiated a template
+ class with a vtable, call finish_prevtable_vardecl.
- * Makefile.in (stamp-parse): Update count of conflicts to 33.
+ * error.c (dump_decl): Don't explode (or explode more gracefully
+ as appropriate) if the object being dumped has a null type.
+ (dump_expr): Likewise.
-Thu Apr 7 17:47:53 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * search.c (build_mi_matrix): Ensure that mi_size is large enough,
+ by counting the number of nodes that we'll need before allocating
+ the array.
+ (lookup_fnfields): Fix comment.
+ (breadth_first_search): Fix comment.
- A saner implementation of nested types that treats template types
- no differently from non-template types. There are still some
- shortcomings of our system; most notably, it is difficult to look
- for a nested type that is hidden by another name, because of the way
- we keep track of hidden types. But this shouldn't be a problem for
- just about anyone. Perhaps lookup_field should be fixed up a bit.
+Wed Jul 31 09:57:05 1996 Jason Merrill <jason@yorick.cygnus.com>
- * spew.c: Moved handling of nested types/scoping from the lexer
- into the parser. Removed variable template_type_seen_before_scope.
- Removed functions frob_identifier, hack_more_ids, and various cruft
- that was #if 0'd out in the past, reducing the size of the file from
- 1146 lines to 450 lines. We can't quite do away with spew.c yet,
- though; we still need it for do_aggr () and checking for SCOPE after
- the current identifier. And setting lastiddecl.
+ * pt.c (instantiate_class_template): Propagate TYPE_PACKED and
+ TYPE_ALIGN.
+ * class.c (finish_struct): Call cplus_decl_attributes here.
+ (finish_struct_1): Not here.
+ * cp-tree.h: Adjust.
- * parse.y: Moved handling of nested types/scoping from the lexer
- into the parser, using a new global variable `got_scope'. Reduced
- the number of states by 53. Implemented all uses of explicit global
- scope. Removed terminals SCOPED_TYPENAME and SCOPED_NAME. Removed
- nonterminals tmpl.1, scoped_base_class, id_scope, typename_scope,
- scoped_typename. Added nonterminals nested_type,
- qualified_type_name, complete_type_name, qualified_id, ptr_to_mem,
- nested_name_specifier, global_scope, overqualified_id, type_name.
- Changed many others. Added 9 new reduce/reduce conflicts, which are
- nested type parallels of 9 that were already in the grammar for
- non-nested types. Eight of the now 33 conflicts should be removed
- in the process of resolving the late binding between variable and
- function decls.
+ * pt.c (type_unification): New parameter STRICT.
+ (unify): If STRICT, don't allow cv addition or base deduction.
+ * call.c, class.c, cvt.c, cp-tree.h: Adjust.
- * gxxint.texi (Parser): Update.
+Tue Jul 30 13:06:13 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-tree.h (IS_AGGR_TYPE_CODE): Add UNINSTANTIATED_P_TYPE.
+ * search.c (get_template_base{_recursive}): New fns.
+ * pt.c (more_specialized): New fn.
+ (do_function_instantiation): Use it.
+ (unify): Handle base deduction.
+ * cvt.c (joust): Use more_specialized.
+ Don't arbitrarily choose between non-builtin candidates.
+ (build_over_call): Call require_complete_type.
- * lex.h: Add decl for got_scope.
+ * decl.c (start_function): Statics are static even in a #pragma
+ interface file.
- * lex.c (see_typename): Claim to be the lexer when calling
- lookup_name.
+ * decl2.c (import_export_vtable): Disable vtable heuristic on
+ systems with ASM_OUTPUT_EXTERNAL.
- * decl.c (lookup_name): When called from the lexer, look at
- got_scope and looking_at_typename; otherwise don't.
+ * cvt.c (compare_ics): Fix comparison of PMEM_CONV and BASE_CONV.
+ (standard_conversion): No std conv to enum type.
-Thu Apr 7 22:05:47 1994 Mike Stump <mrs@cygnus.com>
+ * cvt.c (standard_conversion): Fix order of args to DERIVED_FROM_P
+ for ptm's.
- 31th Cygnus<->FSF merge.
+ * cvt.c (reference_binding): Bind directly to a base subobject of
+ a class rvalue.
-Thu Apr 7 17:47:53 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * cvt.c (build_new_op): Enforce access control.
- * decl2.c (mark_vtable_entries): Call this to mark all the
- entries in the vtable addressable.
- (finish_decl_parsing): Handle SCOPE_REFs.
+Tue Jul 30 09:22:53 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl.c (decls_match): Always call compparms with strict == 1.
- Handle the special case of C function redecl here.
- (duplicate_decls): Only keep the old type if the new decl takes no
- arguments.
+ * typeck2.c (process_init_constructor): When scanning the
+ union for a named field, skip things that aren't FIELD_DECLs.
- * typeck.c (compparms): Also allow t1 to be ... if strict == 0.
+ * method.c (synthesize_method): Don't scan fndecl's rtl if
+ we're at the end of the file; just assume the function can't
+ be inlined.
-Thu Apr 7 16:17:50 1994 Mike Stump <mrs@cygnus.com>
+Mon Jul 29 15:48:30 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (build_vtable_entry): Fix breakage introduced Apr 5
- 17:48:41.
+ * cvt.c (build_builtin_candidate): Stick a dummy conversion in if
+ it failed.
-Wed Apr 6 16:05:10 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * cvt.c (build_user_type_conversion_1): Handle overloaded
+ conversion ops.
- * init.c (build_virtual_init), search.c (build_vbase_vtables_init),
- ch-tree.h: Every place these functions were called, the result was
- immediately passed to expand_expr_stmt. Reduce redundancy by
- calling expand_expr_init *inside* these functions. These
- makes for a simpler interface, and we don't have to build
- compound expressions. Hence, rename these function to:
- expand_virtual_init and expand_vbase_vtables_init respectively.
- * init.c, decl.c: Change callers of these functions.
- * init.c, cp-tree.h (expand_virtual_init): Make static.
+ * cvt.c (add_builtin_candidates): Don't consider type conversion
+ operators for the first parameter of operator=.
- * decl2.c (finish_file): Check TREE_PUBLIC||TREE_ADDRESSABLE
- rather than DECL_SAVED_INSNS before emitting inlines.
+Mon Jul 29 15:33:55 1996 Bob Manson <manson@charmed.cygnus.com>
-Wed Apr 6 13:06:39 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (complete_type): Only call layout_type if we're not
+ expanding a template.
- * spew.c (init_spew): #if 0 out stuff used by arbitrate_lookup.
+Mon Jul 29 14:40:38 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (duplicate_decls): If this is a new declaration of an
- extern "C" function, keep the type (for the argtypes).
- (redeclaration_error_message): Don't check DECL_LANGUAGE here.
- (decls_match): Call compparms with a value of strict dependent on
- the value of strict_prototypes for DECL_LANGUAGE (oldecl).
+ * cvt.c (compare_ics): Oops.
- * typeck.c (compparms): ... is only equivalent to non-promoting
- parms if we're not being strict.
+ * cvt.c (op_error): Oops.
- * parse.y (empty_parms): Don't check flag_ansi || pedantic here.
+ * cp-tree.def: Add RVALUE_CONV, rename EXACT_CONV to IDENTITY_CONV.
+ * cvt.c: Add IDENTITY_RANK before others. Use real_lvalue_p.
+ (build_conv): Use them.
+ (implicit_conversion): Use them.
+ (convert_like): Handle them.
+ (build_new_op): Handle builtin COND_EXPR again.
+ (add_builtin_candidates): Strip cv-quals. Fix oops. Include enums
+ in lists of types for COND_EXPR.
+ (add_builtin_candidate): Add enum candidates for COND_EXPR.
- * decl.c (init_decl_processing): if (flag_ansi || pedantic)
- strict_prototypes_lang_c = strict_prototypes_lang_cplusplus;
+Mon Jul 29 12:05:40 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl2.c (grok_function_init): Don't set DECL_INITIAL on pure
- virtuals.
+ * typeck.c (build_modify_expr): Always attempt to build a call to
+ the assignment operator, even if we're using a default one.
+ (convert_for_initialization): Call complete_type.
-Tue Apr 5 17:48:41 1994 Per Bothner (bothner@kalessin.cygnus.com)
+Mon Jul 29 11:25:08 1996 Jason Merrill <jason@yorick.cygnus.com>
- Support for implementing vtables with thunks.
- * tree.def (THUNK_DECL): New TREE_CODE.
- * cp-tree.h (FNADDR_FROM_VTABLE_ENTRY), tree.c
- (fnaddr_from_vtable_entry): Handle flag_vtable_thunks case.
- * cp-tree.h (memptr_type): New variable.
- * class.c (build_vtable_entry): Build thunk if necessary.
- * class.c (build_vfn_ref): If using thunks, don't need
- to add delta field from vtable (there is none!).
- * decl.c: Add memptr_type as well as vtable_entry_type.
- If using thunks, the latter is just ptr_type_node.
- * gc.c, typeck.c: Use memptr_typeChange, not vtable_entry_type.
- * decl2.c (finish_vtable_vardecl): Handle thunks.
- * expr.c (cplus_expand_expr): Support THUNK_DECL.
+ * cvt.c (reference_binding): A REF_BIND gets the reference type.
+ (implicit_conversion): Likewise.
+ (convert_like): Likewise.
+ (compare_ics): Likewise.
+ (compare_qual): Likewise.
+ (print_z_candidates): Handle no candidates.
+ (build_new_op): Don't handle builtin COND_EXPR for now.
- * decl.c (grokdeclarator): Set DECL_THIS_EXTERN if "extern".
- * decl.c (start_function): Set current_extern_inline based on
- DECL_THIS_EXTERN, not TREE_PUBLIC.
- * decl.c (finish_function): Call mark_inline_for_output if needed,
+Sat Jul 27 11:27:47 1996 Stan Shebs <shebs@andros.cygnus.com>
- Improve intelligence about when to emit inlines.
- * cp-tree.h (lang_decl_flags): New field saved_inline.
- * cp-tree.h (DECL_SAVED_INLINE): New macro.
- * class.c (add_virtual_function): Don't set TREE_ADDRESSABLE.
- * decl.h, decl.c (pending_addressable_inlines): Removed.
- * decl2.c (pending_addressable_inlines): Renamed to saved_inlines.
- * decl2.c (mark_inline_for_output): Do nothing if
- DECL_SAVED_INLINE; otherwise set it (and add to saved_inlines list).
- * decl2.c (finish_vtable_vardecl): SET_CLASSTYPE_INTERFACE_KNOWN
- and set CLASSTYPE_INTERFACE_ONLY if there is a non-inline virtual.
- * decl2.c (finish_file): Writing out inlines later, so we can
- also handle the ones needed for vtbales.
- * decl2.c (write_vtable_entries, finish_vtable_typedecl): Removed.
+ * cvt.c (build_builtin_candidate): Init local var in an ANSI way.
- * cp-tree.h, class.c, decl2.c, search.c: Remove -fvtable-hack
- and flag_vtable_hack. Use -fvtable-thunks and flag_vtable_thunks
- instead. (The rationale is that these optimizations both break binary
- compatibility, but should become the default in a future release.)
+Fri Jul 26 01:07:22 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed Apr 6 10:53:56 1994 Mike Stump <mrs@cygnus.com>
+ * cvt.c (joust): If the candidates are the same, arbitrarily pick one.
- * class.c (modify_vtable_entries): Never reset the DECL_CONTEXT
- of a fndecl, as we might not be from that vfield.
+ * cvt.c (build_builtin_candidate): Oops.
+ (build_new_op): Oops.
-Tue Apr 5 17:43:35 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * method.c (build_opfncall): Pass COND_EXPR on.
+ * cvt.c (build_builtin_candidate): Reorganize, support COND_EXPR.
+ (add_builtin_candidate{,s}): Likewise.
+ (add_builtin_candidates): Likewise.
+ (print_z_candidates, op_error, build_new_op): Likewise.
+ (type_decays_to): New fn.
+ * lex.c (init_lex): Just say ?: for COND_EXPR.
- * class.c (add_virtual_function): fix bug for pure virtual, so
- that DECL_VINDEX of the dummy decl copied won't be error.
- (see also Apr 4 change)
+Thu Jul 25 09:33:33 1996 Jason Merrill <jason@yorick.cygnus.com>
-Tue Apr 5 17:23:45 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * typeck.c (complete_type): Call layout_type rather than building
+ a new array type.
- * typeck.c (c_expand_return): Before checking that we're not
- returning the address of a local, make sure it's a VAR_DECL.
- (And don't worry about it being a TREE_LIST.)
+ * cvt.c (add_builtin_candidate): Pointer arithmetic candidates
+ only use ptrdiff_t.
-Tue Apr 5 13:26:42 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Jul 24 12:45:08 1996 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (YYDEBUG): Always define.
- * lex.c (YYDEBUG): Ditto.
+ * cvt.c: Always compile the new overloading code (but don't use it).
+ (implicit_conversion): Add a BASE_CONV when converting to
+ the same class type.
+ (convert_like): Handle BASE_CONV.
-Mon Apr 4 11:28:17 1994 Kung Hsu (kung@mexican.cygnus.com)
+Tue Jul 23 12:46:30 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): backup out the change below, put the
- new change for the same purpose. The change below breaks code.
+ * cvt.c (build_new_op): Support {MAX,MIN}_EXPR.
+ (add_builtin_candidate): Likewise.
- * class.c (finish_struct): if pure virtual, copy node and make
- RTL point to abort, then put in virtual table.
- * decl2.c (grok_function_iit): reinstate Mar 31 change.
-
-Sat Apr 2 03:12:58 1994 Jason Merrill (jason@deneb.cygnus.com)
-
- * init.c (build_new): pedwarn about newing const and volatile
- types.
-
- * tree.c (get_identifier_list): Only do the special handling
- thing if we're dealing with the main variant of the record type.
-
- * cvt.c (convert_to_reference): When converting between
- compatible reference types, use the pointer conversion machinery.
- Don't just blindly overwrite the old type.
-
-Fri Apr 1 17:14:42 1994 Jason Merrill (jason@deneb.cygnus.com)
+ NEW_OVER changes:
+ * typeck.c (build_x_function_call): Try an operator function
+ whenever we call an object of class type.
+ * method.c (build_opfncall): Pass CALL_EXPRs through.
+ * cvt.c (implicit_conversion): Do const-ref case first.
+ (add_conv_candidate, build_object_call, op_error): New fns.
+ (ptr_complete_ob, TYPE_PTROB_P): void is not an object type.
+ ({add,build}_builtin_candidate{,s}, print_z_candidates): Display
+ builtin candidates.
+ (build_new_op): Handle CALL_EXPR. Don't try to decay void.
+ Fall back on preincrement handling. Use op_error.
+ Handle warn_synth.
+ (convert_like): Pass INDIRECT_BIND. Don't try to do anything with
+ an error_mark_node.
+ (build_over_call): Handle PROMOTE_PROTOTYPES and ellipsis promotions
+ properly.
- * call.c (build_method_call): When looking at global functions,
- be sure to use instance_ptr for the first argument, not some version
- of it that has been cast to a base class. Also do this before
- comparing candidates.
+Mon Jul 22 16:21:55 1996 Bob Manson <manson@charmed.cygnus.com>
-Thu Mar 31 19:50:35 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (tsubst_expr): Handle CONTINUE_STMT.
- * call.c (build_method_call): Constructors can be called for
- const objects.
+Mon Jul 22 15:38:58 1996 Mike Stump <mrs@cygnus.com>
-Thu Mar 31 16:20:16 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * typeck.c (build_component_ref_1): Use build_component_ref
+ instead of open coding it here.
- * decl2.c (grok_func_init): do not abort as rtl for pur virtual
- fucntions. They can be defined somewhere else.
+Mon Jul 22 12:18:54 1996 Jason Merrill <jason@yorick.cygnus.com>
-Sat Jan 23 23:23:26 1994 Stephen R. van den Berg (berg@pool.informatik.rwth-aachen.de)
+ * g++.c (main): Don't link with -lg++.
- * decl.c (init_decl_processing): Declare __builtin_return_address
- and __builtin_frame_address for C++ as well.
+ NEW_OVER changes:
+ * cvt.c (convert_to_reference): Don't use convert_from_refeence on
+ result of build_type_conversion.
+ (cp_convert): Only call build_method_call for ctors if
+ build_type_conversion failed.
+ (ptr_complete_ob): New function.
+ (TYPE_PTR{,OB,MEM}_P): New macros.
+ ({add,build}_builtin_candidate{,s}): New functions.
+ (print_z_candidates): Handle builtins.
+ (build_user_type_conversion_1): Don't use conversion fns for
+ converting to a base type.
+ (build_user_type_conversion_1): Set ICS_USER_FLAG on AMBIG_CONVs.
+ (build_user_type_conversion): Use convert_from_reference.
+ (build_new_op): New function.
+ (build_over_call): Fix handling of methods.
+ (compare_ics): Handle AMBIG_CONV properly.
+ * typeck2.c: Increment abort count.
+ * method.c (build_opfncall): Forward most requests to build_new_op.
+ * cp-tree.h (IS_OVERLOAD_TYPE): Tweak.
-Thu Mar 31 12:35:49 1994 Mike Stump <mrs@cygnus.com>
+Fri Jul 19 17:59:29 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * typeck2.c (store_init_value): Integral constant variables are
- always constant, even when doing -fpic.
+ * error.c (dump_expr, case CONSTRUCTOR, case CAST_EXPR): Take out
+ invalid second argument to dump_expr_list.
-Sat Jan 23 23:23:26 1994 Stephen R. van den Berg (berg@pool.informatik.rwth-aachen.de)
+Fri Jul 19 14:04:05 1996 Mike Stump <mrs@cygnus.com>
- * decl.c (redeclaration_error_message): Pass the types to
- comptypes.
+ * decl.c (lookup_name_real): Make sure we do obj->X::i correctly.
-Wed Mar 30 21:29:25 1994 Mike Stump <mrs@cygnus.com>
+Thu Jul 18 14:48:23 1996 Bob Manson <manson@charmed.cygnus.com>
- Cures incorrect errors about pure virtuals in a class, when they
- have been overridden in a derived class.
+ * decl2.c (import_export_vtable): ASM_OUTPUT_EXTERNAL, not
+ ASSEMBLE_EXTERNAL.
- * search.c (get_abstract_virtuals): Reimplement.
- * search.c (get_abstract_virtuals_1): New routine.
+Mon Jul 15 17:48:43 1996 Mike Stump <mrs@cygnus.com>
-Wed Mar 30 14:10:04 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck2.c (process_init_constructor): New pedwarn for using { }
+ to initialize a pointer to member function.
+ * typeck.c (build_ptrmemfunc1): Avoid use of digest_init so that
+ we can avoid the new error.
- * pt.c (push_template_decls): Make the pushed level pseudo
- global.
+Mon Jul 15 15:42:03 1996 Mike Stump <mrs@cygnus.com>
- * parse.y (extdefs): Don't pop everything if the current binding
- level is pseudo_global.
+ * typeck.c (build_ptrmemfunc1): New function to hide details of
+ pointer to member functions better.
- * decl.c (pop_everything): Stop on reaching a pseudo-global
- binding level.
+Mon Jul 15 14:23:02 1996 Mike Stump <mrs@cygnus.com>
- * cp-tree.h (DECL_FUNCTION_MEMBER_P): Change to more reliable test.
+ * init.c (resolve_offset_ref): Resolve OFFSET_REFs that are
+ methods into the actual method, as we know the implied object is
+ not used.
- * decl.c (duplicate_decls): Only copy DECL_SOURCE_{FILE_LINE} if
- the old decl actually had an initializer.
+Mon Jul 15 13:08:29 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * {various}: Clean up gcc -W complaints.
+ * parse.y (maybecomma_warn): Only emit the pedwarn if we're not
+ inside a system header.
- * cp-tree.h (DECL_FUNCTION_MEMBER_P): Currently defined to be
- (DECL_CONTEXT (NODE) != NULL_TREE).
+Fri Jul 12 16:30:05 1996 Bob Manson <manson@charmed.cygnus.com>
- * parse.y (lang_extdef): Call pop_everything if necessary.
+ * call.c (build_method_call): Call complete_type on the
+ instance type.
- * decl.c (pop_everything): New function for popping binding
- levels left over after a syntax error.
- (pushdecl): Use DECL_FUNCTION_MEMBER_P to decide whether or not
- a function is a member.
+Thu Jul 11 17:16:40 1996 Mike Stump <mrs@cygnus.com>
-Wed Mar 30 14:20:50 1994 Mike Stump <mrs@cygnus.com>
+ * typeck.c (build_component_ref): Always build up an OFFSET_REF
+ for obj_ptr->func so that we can know which object to use in a
+ method call.
- Cures calling a more base base class function, when a more derived
- base class member should be called in some MI situations.
+Wed Jul 10 19:36:37 1996 Mike Stump <mrs@cygnus.com>
- * search.c (make_binfo): Use more the more specialized base
- binfos from the binfo given as the second argument to make_binfo,
- instead of the unspecialized ones from the TYPE_BINFO.
- * class.c (finish_base_struct): Ditto, update callers.
- * search.c (dfs_get_vbase_types): Ditto.
- * tree.c (propagate_binfo_offsets, layout_vbasetypes): Ditto.
- * decl.c (xref_tag): Use NULL_TREE instead of 0.
- * lex.c (make_lang_type): Ditto.
+ * typeck.c (build_ptrmemfunc): Remove sorry, now we can cast
+ around things. Also improve maintainability.
-Wed Mar 30 14:10:04 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Jul 10 18:20:11 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl.c (pushdecl): If pushing a C-linkage function, only do a
- push_overloaded_decl.
- (duplicate_decls): Standard overloading does not shadow built-ins.
+ * decl.c (grokdeclarator): Check for overflow when evaluating an
+ array dimension.
-Tue Mar 29 00:54:18 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Jul 10 17:26:19 1996 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (end_template_decl): Don't call push_overloaded_decl.
+ * cvt.c (cp_convert): Don't check for ambiguity with constructor
+ if NEW_OVER.
- * init.c (do_friend): Don't call push_overloaded_decl.
+ * typeck.c (build_x_function_call): Pass function overload
+ questions to new overloading code if NEW_OVER.
+ * init.c (expand_aggr_init_1): Only check for type conversion ops
+ if we're doing copy-initialization (i.e. LOOKUP_ONLYCONVERTING).
+ Don't check for ambiguity with constructor if NEW_OVER.
+ * cvt.c (convert_to_reference): Dereference the result of a type
+ conversion operator.
+ (build_conv): Propagate ICS_USER_FLAG.
+ (implicit_conversion): Call instantiate_type.
+ Pass LOOKUP_ONLYCONVERTING instead of LOOKUP_NORMAL.
+ (add_function_candidate): Fix cv-quals on argtype.
+ (print_z_candidates): New function.
+ (build_new_function_call): Call it.
+ (build_user_type_conversion_1): If LOOKUP_ONLYCONVERTING, don't
+ consider non-converting constructors.
+ Call print_z_candidates.
+ Return an AMBIG_CONV for an ambiguous conversion.
+ (build_user_type_conversion): Handle AMBIG_CONV.
+ (convert_like): Fix test for building TARGET_EXPR.
+ Call instantiate_type.
+ Handle AMBIG_CONV and LVALUE_CONV.
+ (build_over_call): Handle 0 args and ellipsis.
+ * cp-tree.def: Add AMBIG_CONV.
+
+Tue Jul 9 17:48:48 1996 Mike Stump <mrs@cygnus.com>
+
+ * decl.c (lookup_name_real): If we find mem in obj when parsing
+ `obj->mem', make sure we return the right value.
+
+Tue Jul 9 16:11:28 1996 Bob Manson <manson@charmed.cygnus.com>
+
+ * search.c (get_base_distance): Call complete_type.
- * decl.c (pushdecl): Call push_overloaded_decl for functions and
- function templates.
- (duplicate_decls): functions and function templates are not
- duplicates, but don't complain about calling this function to
- compare them.
- (push_overloaded_decl): Don't deal with linkage. Call
- duplicate_decls.
- (redeclaration_error_message): Deal with linkage.
+Tue Jul 9 12:46:34 1996 Mike Stump <mrs@cygnus.com>
+
+ * decl.c (store_bindings): Make static.
- * decl.c (start_function): If push_overloaded_decl returns an
- older version of the function, deal with it.
+Mon Jul 8 16:42:31 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (start_function): Be sure only to push_overloaded_decl
- for non-members.
+ * init.c (expand_aggr_init_1): Don't check type conversions if
+ NEW_OVER.
- * decl.c (grokfndecl): Put back clearing of DECL_CHAIN for
- methods.
- (start_function): Lose broken and redundant code for checking old
- decl.
+ * cvt.c (z_candidate): Put back template field.
+ (add_function_candidate): Set it.
+ (add_template_candidate): Likewise.
+ (joust): Use it.
+ (compare_qual): Handle references and pointers to members.
+ (compare_ics): Handle reference bindings.
- * init.c (add_friend): Give line numbers of both friend decls
- when warning about re-friending.
+ * decl.c (duplicate_decls): Propagate DECL_ONE_ONLY.
- * pt.c (tsubst): Use comptypes rather than == to compare the
- types of the method as declared and as defined, since default
- parameters may be different.
+Mon Jul 8 16:18:56 1996 Bob Manson <manson@charmed.cygnus.com>
- * call.c (build_method_call): Use brendan's candidate printing
- routine.
+ * call.c (compute_conversion_costs): Call complete_type.
- * decl.c (start_method): Methods defined in the class body are
- inline whether or not it's a template class.
+ * tree.c (vec_binfo_member): Use comptypes instead of comparing
+ pointers, so we can handle template parameters.
-Mon Mar 28 16:39:26 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Jul 5 16:51:53 1996 Bob Manson <manson@charmed.cygnus.com>
- * parse.y (initdcl0): Add "extern" to current_declspecs if
- have_extern_spec && ! used_extern_spcec.
+ * cvt.c (cp_convert_to_pointer): We have to call complete_type
+ here; let's make it explicit instead of a side effect of an
+ error check.
- * tree.c (really_overloaded_fn): A fn with more than one
- overload.
+Wed Jul 3 16:29:51 1996 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (end_template_decl): Use really_overloaded_fn.
+ * cvt.c (z_candidate): Remove template field.
+ (reference_binding): Handle binding to temporary.
+ (implicit_conversion): Likewise.
+ (add_function_candidate): Handle artificial constructor parms.
+ Handle functions with too few parms.
+ (add_template_candidate): New function.
+ (build_user_type_conversion_1): Handle constructors.
+ (convert_like): Likewise.
+ (build_over_call): Likewise.
+ (build_new_function_call): Support templates.
+ (compare_ics): Fix reference, inheritance handling.
- * decl.c (duplicate_decls): When smashing a decl into a previous
- definition, keep the old file and line.
- Don't deal with overloaded functions.
- Lose old code for checking arg types of functions.
- Check for overloaded C functions.
- (pushdecl): Deal with overloaded functions.
- (start_decl): Expect pushdecl to return an appropriate function decl.
- (start_function): Ditto.
- (push_overloaded_decl): Don't check for overloaded C functions.
+Mon Jul 1 22:58:18 1996 Bob Manson <manson@charmed.cygnus.com>
- * *.c: Stop using DECL_OVERLOADED, it being archaic.
- TREE_OVERLOADED should probably go, too.
+ * decl.c: Add signed_size_zero_node.
+ (init_decl_processing): Build it.
+ * class.c (prepare_fresh_vtable): Use it instead of size_zero_node
+ when we're trying to make a negative delta.
-Mon Mar 28 14:00:45 1994 Ron Guilmette (rfg@netcom.com)
+Mon Jul 1 17:56:19 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * typeck.c (comp_target_types): Call comp_target_parms with
- strict == 1.
+ Stop doing this damn index==strchr variable name confusion.
+ * class.c (add_virtual_function): Change local var INDEX to be
+ named IDX.
+ (add_method): Likewise.
+ * lex.c (print_parse_statistics): Likewise.
+ * search.c (make_memoized_table_entry): Likewise.
+ (lookup_fnfields_here): Likewise.
+ (lookup_field): Likewise.
+ (lookup_fnfields): Likewise.
+ (get_baselinks): Likewise.
+ * sig.c (build_signature_table_constructor): Likewise.
+ (build_signature_method_call): Likewise.
+ * typeck.c (build_x_array_ref): Change INDEX parm to be named IDX.
+ (get_member_function_from_ptrfunc): Likewise.
+ (build_ptrmemfunc): Change local var INDEX to be IDX.
+ (c_expand_start_case): Likewise.
-Sun Mar 27 00:07:45 1994 Jason Merrill (jason@deneb.cygnus.com)
+Sat Jun 29 14:05:46 1996 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (empty_parms): Don't parse () as (...) in extern "C"
- sections if we're compiling with -ansi or -pedantic.
+ * cvt.c (cp_convert_to_pointer): Move user-defined type conversion
+ handling to before extraction of TYPE_PTRMEMFUNC_FN_TYPE.
+ (convert_to_reference): Use build_type_conversion to convert to
+ the reference type directly.
+ (standard_conversion): Fix void* case, non-conversions.
+ (reference_binding): Fix expr == 0 case, non-conversions.
+ (convert_like): Support REF_BIND.
+ (compare_qual): Split out from compare_ics.
+ (compare_ics): Use it, handle icses with only a qual_conv.
- * decl.c (decls_match): Don't treat (int) and (int&) as matching.
+ * init.c (expand_vec_init): Don't crash if decl is NULL.
- * decl2.c (grokfield): Don't pedwarn twice about initializing
- field.
+Fri Jun 28 11:52:51 1996 Stan Shebs <shebs@andros.cygnus.com>
- * decl.c (push_overloaded_decl): Warn about shadowing
- constructor.
- (redeclaration_error_message): Don't allow 'int a; int a;'
+ * mpw-config.in: New file, configury for Mac MPW.
+ * mpw-make.sed: New file, makefile editing for MPW.
- * cvt.c (build_up_reference): Only check for valid upcast if
- LOOKUP_PROTECT is set, not just any flag.
+Thu Jun 27 15:18:30 1996 Jason Merrill <jason@yorick.cygnus.com>
-Fri Mar 25 01:22:31 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (instantiate_class_template): Call repo_template_used.
- * lex.c (check_newline): When we see a #pragma implementation,
- also set it for the main input file.
+ * search.c (lookup_conversions): Only lookup conversions in
+ complete types.
- * init.c (build_new): Convert array size argument to size_t.
+Thu Jun 27 12:59:53 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * parse.y (primary): If we're doing a parenthesized type-id, call
- groktypename before passing it to build_new.
+ * cp-tree.def: Renamed from tree.def, to avoid confusion with
+ gcc's tree.def.
+ * cp-tree.h, lex.c: Include cp-tree.def.
+ * Makefile.in (CXX_TREE_H): Reference cp-tree.def.
- * call.c (build_method_call): Deal properly with const and
- volatile for instances of reference type.
+Wed Jun 26 18:29:47 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl.c (store_return_init): Change 'if (pedantic) error' to 'if
- (pedantic) pedwarn'.
+ * init.c (build_vec_delete_1): Call complete_type.
- * decl.c (grokdeclarator): Don't complain about putting `static'
- and `inline' on template function decls.
+Mon Jun 24 17:17:32 1996 Mike Stump <mrs@cygnus.com>
-Thu Mar 24 23:18:19 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * except.c (start_anon_func): Make sure anonymous functions are
+ never external.
- * call.c (build_method_call): Preserve const & volatile on
- `this'.
+Fri Jun 21 15:10:58 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Mar 24 16:21:52 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (finish_function): If function_depth > 1, set nested.
- * init.c (build_new, build_vec_delete): Use global new and delete
- for arrays.
- * decl2.c (delete_sanity): Ditto.
+ * decl2.c (grokbitfield): Revert Bob's change.
+ * class.c (finish_struct_1): Fix handling of named bitfield widths.
-Thu Mar 24 02:10:46 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu Jun 20 23:35:38 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (convert_to_reference): If i is an lvalue,
- (int &)i -> *(int*)&i, as per 5.2.8p9 of the latest WP.
- (convert_force): Call convert_to_reference with LOOKUP_COMPLAIN.
+ * pt.c (add_pending_template): Handle types.
+ (lookup_template_class): With -fexternal-templates, just add the class
+ to pending_templates instead of instantiating it now.
+ * decl2.c (finish_file): Handle types in pending_templates.
-Wed Mar 23 17:45:37 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu Jun 20 14:08:40 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl.c (duplicate_decls): Also propagate DECL_TEMPLATE_MEMBERS
- and DECL_TEMPLATE_INSTANTIATIONS.
+ * decl2.c (grokbitfield): Handle constant decls appropriately.
+ Give an appropriate error message now instead of spewing core
+ later.
- * init.c (build_new): Handle array typedefs properly.
+Thu Jun 20 13:01:51 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed Mar 23 18:23:33 1994 Mike Stump <mrs@cygnus.com>
+ * decl2.c: Don't turn on thunks by default for now.
- 30th Cygnus<->FSF merge.
+Wed Jun 19 11:37:04 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed Mar 23 00:46:24 1994 Mike Stump <mrs@cygnus.com>
+ * typeck.c (complete_type): Handle error_mark_node.
+ (common_type, OFFSET_TYPE): Handle template_type_parms.
- * class.c (modify_vtable_entries): Avoid running off the end of the
- virtuals list when processing a virtual destructor.
- * class.c (get_vtable_entry): Ditto.
+Tue Jun 18 10:02:15 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed Mar 23 00:23:59 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (instantiate_decl): If at_eof, call import_export_decl
+ regardless of DECL_INLINE.
- * decl.c (duplicate_decls): If two template decls don't match,
- just return 0.
+ * typeck.c (mark_addressable): Set TREE_ADDRESSABLE on CONSTRUCTORs.
-Tue Mar 22 23:49:41 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * class.c (finish_struct_bits): Copy TYPE_SIZE.
- * typeck.c (convert_for_assignment): Don't pedwarn about
- converting function pointer to void *.
+ * rtti.c (build_dynamic_cast): Support templates.
+ * tree.def: Support DYNAMIC_CAST_EXPR.
+ * pt.c (tsubst_copy): Likewise.
+ * decl2.c (build_expr_from_tree): Likewise.
-Tue Mar 22 22:23:19 1994 Mike Stump <mrs@cygnus.com>
+Mon Jun 17 15:23:36 1996 Jason Merrill <jason@yorick.cygnus.com>
- Major revamp of pointer to member functions. Cures major
- nonfunctionality when used in casts, and MI situations.
+ * typeck.c (build_static_cast): Support templates.
+ (build_const_cast): Likewise.
+ * tree.def: Support CONST/STATIC_CAST_EXPR.
+ * pt.c (tsubst_copy): Likewise.
+ * decl2.c (build_expr_from_tree): Likewise.
- * cvt.c (convert_force): Update call site of build_ptrmemfunc.
- * typeck.c (convert_for_assignment): Ditto.
- * typeck2.c (digest_init): Ditto.
- * typeck2.c (process_init_constructor): Simplify by moving code into
- digest_init.
- * typeck2.c (digest_init): Do default_conversions on init value, if
- we are processing pointer to member functions.
- * class.c (get_vfield_offset): Now non-static. Convert bit offset
- into byte offset.
- * cp-tree.h (get_vfield_offset): Ditto.
- * typeck.c (get_member_function_from_ptrfunc): Convert down to right
- instance, before fetching vtable pointer.
- * typeck.c (get_delta_difference): New routine.
- * typeck.c (build_ptrmemfunc): Revamp to handle casting better, also
- get vtable pointer out of right subobject.
+Sun Jun 16 12:33:57 1996 Jason Merrill <jason@yorick.cygnus.com>
-Tue Mar 22 17:56:48 1994 Mike Stump <mrs@cygnus.com>
+ * decl2.c (finish_vtable_vardecl): Don't trust
+ TREE_SYMBOL_REFERENCED for vtables of local classes.
- * search.c (get_binfo): Return NULL instead of aborting, when
- passed a UNION_TYPE.
+Fri Jun 14 18:13:36 1996 Jason Merrill <jason@yorick.cygnus.com>
-Tue Mar 22 12:44:54 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (tsubst_copy): Handle operator T.
- These patches implement handling of redefinition/redeclaration of
- templates.
+Wed Jun 12 17:52:40 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * typeck.c (comptypes): Simplify. All TEMPLATE_TYPE_PARMs are
- considered compatible.
+ * init.c (build_delete): Move creation of PARMS inside test of
+ TYPE_HAS_DESTRUCTOR, since it's never used outside of that block.
- * parse.y (template_def): Pass defn argument to end_template_decl.
+Tue Jun 11 15:09:18 1996 Bob Manson <manson@charmed.cygnus.com>
- * pt.c (end_template_decl): Add defn argument. Check for
- redefinition. Simplify.
+ * typeck.c (build_conditional_expr): Don't assume that
+ the arguments to ?: are always pointers or records.
- * error.c (OB_UNPUT): New macro, to remove mistakes.
- (aggr_variety): Subroutine of dump_aggr_type.
+Tue Jun 11 13:56:23 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (decls_match): Support templates.
- (duplicate_decls): No longer static. Don't try to lay out template
- decls.
- (pushdecl): Simplify.
+ * decl2.c (import_export_decl): Still emit static/weak/comdat
+ copies of inline template functions with -fno-implicit-templates.
- * cp-tree.h (DECL_TEMPLATE_MEMBERS): Use DECL_SIZE instead of
- DECL_INITIAL.
+Tue Jun 11 11:42:13 1996 Bob Manson <manson@charmed.cygnus.com>
-Mon Mar 21 11:46:55 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * init.c (build_delete): Determine the complete basetype
+ path to the destructor we're calling.
- * error.c (dump_decl): Support class template decls.
- (dump_type): Don't adorn template type parms.
+Fri Jun 7 15:30:10 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl.c (duplicate_decls): Save DECL_TEMPLATE_INFO from old decl
- if it was a definition.
- (redeclaration_error_message): Do the cp_error thang, and reject
- redefinition of templates.
+ * decl.c (build_enumerator): Always copy the INTEGER_CST used to
+ initialize the enum, because we really and truly don't know where
+ it came from.
+ (start_enum): Don't copy integer_zero_node because
+ build_enumerator will do it.
-Mon Mar 21 19:36:06 1994 Per Bothner (bothner@kalessin.cygnus.com)
+Fri Jun 7 11:11:09 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokdeclarator): Set TREE_PUBLIC for METHOD_TYPE
- in FIELD context, when appropriate. Also,
- CLASSTYPE_INTERFACE_ONLY is irrelevant to setting TREE_PUBLIC.
- Also, simplify check for bogus return specifiers.
+ * decl.c (finish_function): Do access control on base destructors.
-Mon Mar 21 11:46:55 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (tsubst, case FUNCTION_DECL): Set up
+ IDENTIFIER_GLOBAL_VALUE for member functions so pushdecl doesn't
+ hose us.
- * parse.y (after_type_declarator1): Expand type_quals.
- (notype_declarator1): Ditto.
- (absdcl1): Ditto.
+Fri Jun 7 10:37:33 1996 Mike Stump <mrs@cygnus.com>
-Sat Mar 19 01:05:17 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * cvt.c (build_up_reference): If we have already extended the
+ lifetime of the temporary, don't try it again.
+ * typeck.c (c_expand_return): Don't try and convert the return
+ value twice when we want a reference, once is enough.
+
+Tue Jun 4 15:41:45 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokdeclarator): Treat class-local typedefs like static
- members; i.e. 'typedef int f();' means that f is a function type,
- not a method type.
+ * pt.c (tsubst_expr, case DECL_STMT): Don't pass
+ LOOKUP_ONLYCONVERTING at all for now.
- * parse.y (decl): Change direct_* back to *.
- (type_id): Change direct_abstract_declarator to absdcl.
- (direct_declarator, direct_initdecls, direct_initdcl0): Remove again.
+ * search.c (add_conversions): Put the conversion function in
+ TREE_VALUE, the basetype in TREE_PURPOSE.
+ * cvt.c (build_type_conversion): Adjust.
+ * cvt.c (build_expr_type_conversion): Adjust.
+ * call.c (user_harshness): Adjust.
-Fri Mar 18 12:47:59 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Jun 3 15:30:52 1996 Jason Merrill <jason@yorick.cygnus.com>
- These two patches fix crashes on instantiating a template inside a
- function with C linkage or containing labels.
+ * method.c (emit_thunk): Pretend this is a FUNCTION_DECL for the
+ backend's benefit.
- * class.c (current_lang_stacksize): No longer static.
+Mon Jun 10 18:58:19 1996 Mike Stump <mrs@cygnus.com>
- * decl.c (struct saved_scope): Add lang_base, lang_stack,
- lang_name, lang_stacksize, and named_labels.
- (push_to_top_level): Save them.
- (pop_from_top_level): Restore them.
+ * except.c (expand_start_catch_block): Add a dummy region, if we
+ get an error, so that we can avoid core dumping later.
- * gxxint.texi (Parser): Update.
+Fri May 31 14:56:13 1996 Mike Stump <mrs@cygnus.com>
- These two patches finish moving the task of expr/declarator
- ambiguity resolution from the lexer to the parser, and add one more
- r/r conflict. START_DECLARATOR can now be nuked.
+ * cp-tree.h (OFFSET_REF): Remove.
+ * tree.def (CP_OFFSET_REF): Rename to OFFSET_REF.
+ * expr.c (cplus_expand_expr): Cleanup callers of expand_expr.
+ * init.c (expand_aggr_init_1): Likewise.
+ (build_new): Likewise.
+ * typeck.c (expand_target_expr): Likewise.
- * parse.y (decl): Add "direct_" in typespec X rules.
- (direct_declarator): New nonterminal for
- direct_after_type_declarator and direct_notype_declarator.
- (direct_initdecls): Like initdecls, but uses direct_initdcl0.
- (direct_initdcl0): Like initdcl0, but uses direct_declarator.
- (named_parm): Add typespec direct_declarator rule.
+Fri May 31 14:22:08 1996 Jason Merrill <jason@yorick.cygnus.com>
- * spew.c (yylex): #if 0 out START_DECLARATOR insertion.
+ * typeck.c (build_modify_expr): Don't use TREE_VALUE on a
+ TARGET_EXPR.
- These two patches disable some excessive cleverness on the part of
- g++; a non-class declaration always hides a class declaration in the
- same scope, and g++ was trying to unhide it depending on the
- enclosing expression.
+Wed May 29 17:04:33 1996 Mike Stump <mrs@cygnus.com>
- * spew.c (arbitrate_lookup): #if 0 out.
+ * cvt.c (build_up_reference): Redo how and when temporaries are
+ created.
+ * decl.c (grok_reference_init): Don't try and be smart about
+ running cleanups.
- * decl.c (lookup_name): Never call arbitrate_lookup.
+Wed May 29 16:02:08 1996 Mike Stump <mrs@cygnus.com>
- * parse.y (complex_notype_declarator1): Add '*'
- complex_notype_declarator1 and '&' complex_notype_declarator1 rules.
+ * cvt.c (build_up_reference): Add NULL_TREE to all calls to build
+ (TARGET_EXPR...), now that it has 4 arguments.
+ * tree.c (build_cplus_new): Likewise.
- * parse.y (complex_direct_notype_declarator): Restore id_scope
- see_typename TYPENAME rule, remove all other rules beginning with
- those tokens.
- (notype_unqualified_id): Add '~' see_typename IDENTIFIER rule.
+Thu May 23 16:40:30 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Mar 17 17:30:01 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * error.c (dump_expr, case CAST_EXPR): Handle T() properly.
- These changes fix the compiler's handling of the functional cast/
- object declaration ambiguities in section 6.8 of the ARM. They also
- add 11 reduce/reduce conflicts. Sigh.
+ * pt.c (instantiate_decl): Don't call push/pop_cp_function_context.
+ * decl.c (struct saved_scope): Remove named_labels,
+ {base,member}_init_list.
+ (maybe_push_to_top_level): Don't set them. Call
+ push_cp_function_context if appropriate.
+ (pop_from_top_level): Likewise.
- * parse.y: Add precedence decls for OPERATOR and '~'.
- (notype_unqualified_id): New nonterminal, encompasses all of the
- ANSI unqualified-id nonterminal except TYPENAMEs.
- (expr_or_declarator): New nonterminal to delay parsing of code like
- `int (*a)'.
- (primary): Use notype_unqualified_id.
- (decl): Add typespec initdecls ';' and typespec declarator ';'
- rules.
- (initdcl0): Deal with the above.
- (complex_notype_declarator1): A notype_declarator that is not also
- an expr_or_declarator.
- (complex_direct_notype_declarator): A direct_notype_declarator that
- doesn't conflict with expr_or_declarator. Use
- notype_unqualified_id. Remove id_scope see_typename TYPENAME rule.
- (functional_cast): New nonterminal, for the three functional cast
- rules. So that they can be moved after
- complex_direct_notype_declarator.
- (see_typename): Don't accept type_quals any more.
+ * method.c (do_build_assign_ref): Remove obsolete check of
+ TYPE_HAS_ASSIGN_REF (basetype).
- * decl2.c (reparse_decl_as_expr): New function to deal with parse
- nodes for code like `int (*a)++;'.
- (reparse_decl_as_expr1): Recursive subroutine of the above.
- (finish_decl_parsing): New function to deal with parse nodes for
- code like `int (*a);'. See the difference?
+ * decl.c (grokfndecl): Diagnose user definition of
+ implicitly-declared methods.
-Thu Mar 17 12:16:10 1994 Mike Stump <mrs@cygnus.com>
+Thu May 23 12:13:08 1996 Bob Manson <manson@charmed.cygnus.com>
- These changes break binary compatibility in code with classes
- that use virtual bases.
+ * method.c (do_build_copy_constructor): Add code to give
+ meaningful error messages instead of crashing.
+ (do_build_assign_ref): Don't synthesize assignment operators for
+ classes containing reference or const members.
- * search.c (dfs_get_vbase_types): Simplify and correct to make
- sure virtual bases are initialized in dfs ordering.
- * search.c (get_vbase_types): Simplify and make readable.
+ * class.c (struct base_info): Remove cant_synth_copy_ctor
+ and cant_synth_asn_ref.
+ (finish_base_struct): Remove the code that tries to conditionalize
+ synthesis of copy constructors & assignment operators based on
+ access permissions. Instead, let it fail when it tries to
+ synthesize the copy constructor. This will give meaningful error
+ messages instead of silently generating code to perform a bitcopy.
-Thu Mar 17 12:01:10 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed May 22 11:45:19 1996 Bob Manson <manson@charmed.cygnus.com>
- * parse.y: s/ typename / type_id /g
+ * lex.c (real_yylex): Remove old-n-crufty #if 0 code for
+ determining types for constant values.
-Wed Mar 16 17:42:52 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * decl.c (struct named_label_list): Use instead of stuffing
+ random items into a TREE_LIST node.
+ (named_label_uses): Use the new struct.
+ (poplevel): Likewise.
+ (lookup_label): Likewise.
+ (define_label): Add an error message to tell the user the line
+ where the goto is located in addition to the destination of the
+ goto.
+ (init_decl_processing): Use NULL instead of NULL_TREE to initialize
+ named_label_uses.
+ (finish_function): Likewise.
+
+ (start_decl): Complain about defining a static data member
+ in a different type from which it was declared.
- * parse.y (typespec): add SCOPE TYPENAME for global scoped
- type. e.g. ::B x.
+Wed May 22 09:33:23 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (complete_array_type): fix a bug that in -pendantic
- mode even there's no initializer, it will continue to build
- default index.
+ * cvt.c (build_expr_type_conversion): Adjust.
-Wed Mar 16 17:43:07 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue May 21 11:21:56 1996 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (direct_notype_declarator): Add PTYPENAME rule, remove
- all of the scoped PTYPENAME rules.
+ * call.c (build_method_call): Always convert 'this' to the
+ appropriate type.
-Wed Mar 16 16:39:02 1994 Mike Stump <mrs@cygnus.com>
+ * search.c (add_conversions): Put the conversion function in
+ TREE_VALUE, the type in TREE_PURPOSE.
+ * cvt.c (build_type_conversion): Adjust.
+ * call.c (user_harshness): Adjust.
- * init.c (build_offset_ref): The value of A::typedef_name is
- always the TYPE_DECL, and never an error.
+ * method.c (emit_thunk): Call temporary_allocation and
+ permanent_allocation around the ASM_OUTPUT_MI_THUNK case, too.
-Tue Mar 15 20:02:35 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * tree.c (build_cplus_array_type): Handle tweaking of
+ TYPE_MAIN_VARIANT here.
+ * typeck.c (common_type): Not here.
- * search.c (get_base_distance_recursive): Two binfos can only
- represent the same object if they are both via_virtual.
+ * typeck.c (complete_type): Only try to complete an array type if
+ it has a domain.
- * class.c (finish_base_struct): Check vbases for ambiguity, too.
+Mon May 20 14:55:59 1996 Jason Merrill <jason@yorick.cygnus.com>
- * search.c (get_vbase_types): Accept binfo argument, too.
+ * decl.c (grokvardecl): Call complete_type.
+ (grokdeclarator): Call complete_type for PARM_DECLs.
-Tue Mar 15 19:22:05 1994 Kung Hsu (kung@mexican.cygnus.com)
+Fri May 17 16:41:17 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (complete_array_type): complete TYPE_DOMAIN of the
- initializer also, because back-end requires it.
+ * pt.c (instantiate_class_template): Re-set
+ CLASSTYPE_GOT_SEMICOLON after calling finish_struct_1.
-Tue Mar 15 15:33:31 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri May 17 14:56:55 1996 Mike Stump <mrs@cygnus.com>
- * error.c (dump_expr): Support member functions (which show up as
- OFFSET_REFs).
+ * cp-tree.h (cp_expand_decl_cleanup): Remove, the backend is now
+ smart enough to do it right.
+ * tree.c (cp_expand_decl_cleanup): Likewise.
+ * decl.c (cp_finish_decl): Use expand_decl_cleanup instead of
+ cp_expand_decl_cleanup.
+ (store_parm_decls): Likewise.
+ (hack_incomplete_structures): Likewise.
+ * except.c (push_eh_cleanup): Likewise.
-Mon Mar 14 16:24:36 1994 Mike Stump <mrs@cygnus.com>
+Fri May 17 13:13:51 1996 Mike Stump <mrs@cygnus.com>
- * init.c (build_new): Set the return type of multidimensional
- news correctly.
+ * expr.c (expand_expr, cond UNSAVE_EXPR): Move from the C++
+ frontend to the backend where it belongs.
+ * tree.c (unsave_expr): Likewise.
+ (unsave_expr_now): Likewise.
+ * tree.def (UNSAVE_EXPR): Likewise.
+ * cp-tree.h (unsave_expr): Likewise.
+ (unsave_expr_now): Likewise.
-Fri Mar 11 15:35:39 1994 Kung Hsu (kung@mexican.cygnus.com)
+Fri May 17 11:02:41 1996 Mike Stump <mrs@cygnus.com>
- * call.c (build_method_call): if basetype not equal to type
- of the instance, use the type of the instance in building
- destructor.
+ * init.c (emit_base_init): Make sure the partial EH cleanups live
+ on the function_obstack.
-Thu Mar 10 17:07:10 1994 Kung Hsu (kung@mexican.cygnus.com)
+Thu May 16 15:29:33 1996 Bob Manson <manson@charmed.cygnus.com>
- * parse.y (direct_notype_declarator): add push_nested_type for
- 'template_type SCOPED_NAME' rule.
+ * expr.c (do_case): Don't try to dereference null TREE_TYPEs
+ when checking for pointer types.
-Tue Mar 8 00:19:58 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu May 16 13:38:58 1996 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (parm): Add typed_declspec1 {absdcl, epsilon} rules.
+ * pt.c (instantiate_class_template): Remove obsolete check for
+ access declarations.
-Sat Mar 5 04:47:48 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu May 16 13:34:15 1996 Mike Stump <mrs@cygnus.com>
- * parse.y (regcast_or_absdcl): New nonterminal to implement late
- reduction of constructs like `int ((int)(int)(int))'.
- (cast_expr): Use it.
- (sub_cast_expr): Everything that can come after a cast.
- (typed_declspecs1): typed_declspecs that are not typed_typespecs.
- (direct_after_type_declarator): Lose PAREN_STAR_PAREN rule.
- (direct_abstract_declarator): Replace '(' parmlist ')' rule with
- '(' complex_parmlist ')' and regcast_or_absdcl.
- (parmlist): Split
- (complex_parmlist): Parmlists that are not also typenames.
- (parms_comma): Enabler.
- (named_parm): A parm that is not also a typename. Use declarator
- rather than dont_see_typename abs_or_notype_decl. Expand
- typed_declspecs inline.
- (abs_or_notype_decl): Lose.
- (dont_see_typename): Comment out.
- (bad_parm): Break out abs_or_notype_decl into two rules.
+ * call.c (build_overload_call): Simplify calls to
+ build_overload_call by removing last parameter.
+ (build_method_call): Likewise.
+ * cp-tree.h: Likewise.
+ * method.c (build_opfncall): Likewise.
+ * typeck.c (build_x_function_call): Likewise.
-Fri Mar 4 18:22:39 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu May 16 13:15:43 1996 Mike Stump <mrs@cygnus.com>
- * decl2.c (reparse_decl_as_casts): New function to change parse
- nodes for `(int)(int)(int)' from "function taking int and returning
- function taking int and returning function taking int" to "... cast
- to int, cast to int, cast to int".
+ * call.c (default_parm_conversions): Factor out common code.
+ (build_method_call): Use it.
+ (build_overload_call_real): Use it.
- * decl2.c (reparse_decl_as_expr): Recursive function to change
- parse nodes for `A()()' from "function returning function returning
- A" to "A().operator()".
+Wed May 15 14:46:14 1996 Mike Stump <mrs@cygnus.com>
- * parse.y (primary): Replace `typespec LEFT_RIGHT' rule with
- `typespec fcast_or_absdcl' rule.
- (fcast_or_absdcl): New nonterminal to implement late reduction of
- constructs like `A()()()()'.
- (typename): Replace `typespec absdcl1' rule with
- `typespec direct_abstract_declarator' rule.
- (direct_abstract_declarator): Replace `LEFT_RIGHT type_quals' rule
- with `fcast_or_absdcl type_quals' rule.
+ * call.c (build_method_call): Allow implicit & on METHOD_TYPEs,
+ but pedwarn as the code is bogus.
+ * typeck.c (decay_conversion): Likewise.
+ (build_function_call_real): Use build_addr_func instead of
+ default_conversion. Don't allow pointer-to-method functions down
+ here.
+ (build_unary_op): Use real pointer-to-member functions instead of
+ fake ones.
+ (build_ptrmemfunc): Use build_addr_func instead of build_unary_op.
+ (convert_for_assignment): Removed some obsolete code.
+ * decl2.c (reparse_absdcl_as_expr): Pass current_class_ref to
+ build_x_function_call instead of current_class_ptr. Only call
+ digest_init once on an initializer, we do this just checking
+ TREE_TYPE.
+ (build_expr_from_tree): Pass current_class_ref to
+ build_x_function_call instead of current_class_ptr.
+ * init.c (build_member_call): Likewise.
+ * pase.y: Likewise.
+ * error.c (dump_expr): Handle OFFSET_REFs better.
+ * pt.c (unify): Handle pointer-to-member functions better.
+ * decl.c (finish_function): Clear out current_class_ref just like
+ we do for current_class_ptr.
-Fri Mar 4 16:18:03 1994 Mike Stump <mrs@cygnus.com>
-
- * tree.c (lvalue_p): Improve OFFSET_REF handling, so that it
- matches Section 5.5.
+ * typeck.c (get_delta_difference): Handle virtual bases better.
-Fri Mar 4 14:01:59 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue May 14 16:37:37 1996 Jason Merrill <jason@yorick.cygnus.com>
- * error.c (dump_type_prefix): Don't print basetype twice for
- pmfs.
+ * sig.c (build_signature_table_constructor): Use the delta for
+ the original basetype for this virtual function with thunks.
+ (build_signature_method_call): We still need to adjust 'this'
+ with thunks.
-Fri Mar 4 13:24:33 1994 Mike Stump <mrs@cygnus.com>
+Tue May 14 16:27:25 1996 Mike Stump <mrs@cygnus.com>
- * typeck.c (convert_arguments): Handle setHandler(A::handlerFn)
- so that it is like setHandler(&A::handlerFn). Cures an `invalid
- lvalue in unary `&''.
+ * call.c (build_addr_func): New routine. Used to get the `real'
+ address of a function or a method. Needed to avoid getting a
+ pointer-to-member function.
+ (build_call): New routine to build CALL_EXPRs.
+ (build_method_call): Use it.
+ * cvt.c (convert_to_aggr): Likewise.
+ * typeck.c (build_function_call_real): Likewise.
+ * sig.c (build_signature_table_constructor): Use build_addr_func.
+ * cp-tree.h (build_call, build_addr_func): Declare them.
-Fri Mar 4 11:15:59 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue May 14 12:47:47 1996 Mike Stump <mrs@cygnus.com>
- * gxxint.texi (Copying Objects): New section discussing default
- op= problems with virtual inheritance.
+ * cp-tree.h (LOOKUP_AGGR): Remove, unused.
+ * parse.y: Remove uses of LOOKUP_AGGR.
- * decl2.c (grokoptypename): Just does grokdeclarator and
- build_typename_overload, since the parser can't call grokdeclarator
- directly.
+Tue May 14 12:07:51 1996 Mike Stump <mrs@cygnus.com>
- * method.c (build_typename_overload): Set IDENTIFIER_GLOBAL_VALUE
- and TREE_TYPE on generated identifiers.
+ * *.[chy]: Rename current_class_decl to current_class_ptr, and
+ C_C_D to current_class_ref.
- * decl.c (grokdeclarator): Don't deal with TYPE_EXPRs anymore.
+Mon May 13 16:55:23 1996 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (parm): Convert `const char *' to `__opPCc' here.
+ * call.c (convert_harshness): Tighten up pointer conversions.
- * error.c (dump_decl): Say sorry rather than my_friendly_aborting
- if we can't figure out what to do.
- (dump_type*): Ditto.
+Sat May 11 04:33:50 1996 Doug Evans <dje@canuck.cygnus.com>
- * typeck2.c (build_m_component_ref): 'component' is an expr, not
- a decl. Also move the IS_AGGR_TYPE check after the stripping of
- REFERENCE_TYPE.
+ * decl2.c (finish_vtable_vardecl): Surround DECL_ONE_ONLY with ifdef.
+ (finish_file): Likewise.
-Fri Mar 4 04:46:05 1994 Mike Stump <mrs@cygnus.com>
+Fri May 10 11:09:57 1996 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_method_call): Handle b->setHandler(A::handlerFn)
- so that it is like b->setHandler(&A::handlerFn). Cures an `invalid
- lvalue in unary `&''.
+ * cvt.c (convert_fn_ptr): We don't use thunks for pmfs.
-Thu Mar 3 12:38:15 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * method.c (emit_thunk): Set flag_omit_frame_pointer in default
+ code.
- * parse.y: Add precedence specification for START_DECLARATOR.
- (type_quals): Move before primary.
- (typename): Move before typed_declspecs, add 'typespec absdcl1' rule.
+Thu May 9 18:18:30 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (grokoptypename): Lose.
+ * decl2.c: Turn on thunks by default where supported.
- * decl.c (grokdeclarator): Parse TYPE_EXPRs in the initial scan,
- rather than waiting until later.
+Tue May 7 20:39:57 1996 Mike Stump <mrs@cygnus.com>
-Wed Mar 2 14:12:23 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * cp-tree.h (build_overload_call_maybe): Removed.
+ * call.c (build_overload_call_real): Invert meaning of last arg to
+ be require_complete.
+ (build_overload_call): Likewise.
+ * typeck.c (build_x_function_call): Use build_overload_call_real
+ instead of build_overload_call_maybe.
- * parse.y (unary_expr): Use 'typename' in 'new' rules, rather
- than expanding it inline.
- (typename): Expand empty option of (former) absdcl inline.
- (abs_or_notype_decl): Ditto.
- (absdcl): Lose empty rule.
- (conversion_declarator): New nonterminal for 'typename' of 'operator
- typename'.
- (operator_name): Use it instead of absdcl.
+Mon May 6 01:23:32 1996 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y: Add precedence declarations for SCOPED_TYPENAME,
- TYPEOF, and SIGOF.
- (typed_declspecs): Accept typed_typespecs, rather than typespec
- directly. Add rules with reserved_typespecquals.
- (reserved_declspecs): Don't accept typespecqual_reserved at the
- beginning of the list. The typed_declspecs rule will deal with this
- omission.
- (declmods): Accept nonempty_type_quals, rather than TYPE_QUAL
- directly.
+ * decl2.c (finish_file): Don't try to emit functions that haven't
+ been compiled.
- * parse.y (direct_notype_declarator,
- direct_after_type_declarator, direct_abstract_declarator): Split up
- the declarator1 nonterminals to match the draft standard and avoid
- ambiguities.
- (new_type_id, new_declarator, direct_new_declarator,
- new_member_declarator): New nonterminals to implement the subset of
- 'typename' allowed in new expressions.
- (unary_expr): Use new_type_id instead of typename.
- (after_type_declarator1, absdcl1): Fix semantics of member pointers.
- (abs_member_declarator, after_type_member_declarator): Lose.
+Fri May 3 09:30:13 1996 Jason Merrill <jason@yorick.cygnus.com>
- * parse.y (absdcl1): Don't require parens around
- abs_member_declarator.
- (abs_member_declarator): Lose see_typename from rules.
- (after_type_member_declarator): Ditto.
+ * decl2.c (finish_vtable_vardecl): Oops.
- * tree.c (get_identifier_list): New function, containing code
- previously duplicated in get_decl_list and list_hash_lookup_or_cons.
- (get_decl_list): Use it.
- (list_hash_lookup_or_cons): Ditto.
+ * decl.c (maybe_push_to_top_level): Do save previous_class_*.
+ Also store the bindings from previous_class_values.
+ (pop_from_top_level): Restore them.
- * parse.y (typed_declspecs, declmods): It's not necessary to hash
- the declspecs on class_obstack, so don't. This way typed_typespecs
- can reduce to typed_declspecs.
+Thu May 2 21:56:49 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed Mar 2 14:29:18 1994 Jason Merrill (jason@cygnus.com)
+ * decl2.c (finish_vtable_vardecl): Only write out vtable if its
+ symbol has been referenced.
+ (finish_file): Re-join synthesis/vtable loop with inline emission
+ loop, disable inlining when an inline is output.
- * cvt.c (build_up_reference): If we aren't checking visibility,
- also allow base->derived conversions.
+Thu May 2 17:20:02 1996 Mike Stump <mrs@cygnus.com>
-Mon Feb 28 15:14:29 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * except.c (init_exception_processing): Setup saved_in_catch.
+ (push_eh_cleanup): Reset __eh_in_catch.
+ (expand_start_catch_block): Set __eh_in_catch.
- * typeck.c (build_c_cast): Remove bogus hack when converting
- to a reference type.
+Thu May 2 16:21:17 1996 Mike Stump <mrs@cygnus.com>
- * cp-tree.h (lang_decl::vbase_init_list, DECL_VBASE_INIT_LIST):
- Removed, not used.
- (lang_stype::methods, lang_decl::next_method): New fields.
- (CLASSTYPE_METHODS, DECL_NEXT_METHOD): New macros.
- * decl.c (duplicate_decls): Preserve DECL_NEXT_METHOD.
+ * except.c (push_eh_cleanup): Add tracking for whether or not we
+ have an active exception object.
+ (expand_builtin_throw): Use it to make sure a rethrow without an
+ exception object is caught.
- * cp-tree.h, decl2.c (flag_vtable_hack): New flag.
- * decl2.c (finish_vtable_vardecl): If flag_vtable_hack,
- and !CLASSTYPE_INTERFACE_KNOWN, try to use the presence of
- a non-inline virtual function to control emitting of vtables.
- * class.c (finish_struct): Build CLASSTYPE_METHODS list.
- * search.c (build_vbase_vtables_init): Don't assemble_external
- (yet) if flag_vtable_hack.
- * class.c (build_vfn_ref): Ditto.
+Thu May 2 11:26:41 1996 Jason Merrill <jason@yorick.cygnus.com>
-Mon Feb 28 14:54:13 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (maybe_push_to_top_level): Clear out class-level bindings
+ cache.
- * parse.y (component_decl): Don't include "typed_declspecs
- declarator ';'" speedup, since it breaks enums.
+Wed May 1 11:26:52 1996 Jason Merrill <jason@yorick.cygnus.com>
-Fri Feb 25 15:43:44 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * decl2.c (finish_file): Also use sentries for vars with
+ DECL_ONE_ONLY or DECL_WEAK set (should any such happen to be
+ created).
- * class.c (finish_struct): Minor optimization for building
- fn_fields list.
+ * lex.c (handle_cp_pragma): Disable #pragma
+ interface/implementation if SUPPORTS_ONE_ONLY > 1.
-Fri Feb 25 15:23:42 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue Apr 30 11:25:46 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (start_function): Fix detection of function overloading.
+ * method.c (emit_thunk): Wrap default case in
+ temporary/permanent_allocation.
-Thu Feb 24 22:26:19 1994 Mike Stump <mrs@cygnus.com>
+ * method.c (make_thunk): Use DECL_ONE_ONLY.
+ (emit_thunk): Call assemble_end_function.
- * lex.c (check_newline): #pragma interface can take a string
- argument, just like #pragma implementation. #pragma implementation
- checks for garbage on the line, line #pragma interface does. Main
- input files do not auto implement like named files, #pragma
- implementation must be used explicitly.
+Mon Apr 29 15:38:29 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Feb 24 17:09:01 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (import_export_vtable): Use DECL_ONE_ONLY.
+ (import_export_decl): Likewise.
+ (finish_prevtable_vardecl): Disable vtable hack if
+ SUPPORTS_ONE_ONLY > 1.
- * parse.y (components): Handle list of one again.
- (notype_components): Ditto.
- (after_type_declarator1): Take maybe_raises out again.
+Mon Apr 29 14:32:47 1996 Mike Stump <mrs@cygnus.com>
- * gxxint.texi (Parser): Document additional r/r conflict.
+ * typeck.c (build_modify_expr): PREINCREMENT_EXPR and
+ PREDECREMENT_EXPRs take two arguments, not one.
-Wed Feb 23 14:42:55 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Apr 29 00:27:53 1996 Jason Merrill <jason@yorick.cygnus.com>
- * gxxint.texi (Parser): Add node.
+ * class.c (build_vtable_entry): Don't build thunks for abstract
+ virtuals.
- * Makefile.in (stamp-parse): Update expected conflict count.
+ * lex.c (real_yylex): Fix handling of __PRETTY_FUNCTION__ like C
+ frontend.
- * parse.y (various): Replace "declmods declarator" with "declmods
- notype_declarator". The comment saying that "declmods declarator ';'"
- corresponds to "int i;" was wrong; it corresponds to "const i;".
- (component_decl): Add "typed_declspecs declarator ';'" rule; this
- *does* correspond to "int i;". Change "declmods components" to
- "declmods notype_components".
- (components): Don't deal with a list of one anymore.
- (notype_components): New nonterminal, corresponds to notype_declarator.
- ({after_,no}type_component_decl{,0}): More new nonterminals.
- ({after_,no}type_declarator): Fold in START_DECLARATOR token.
- Eliminates four reduce/reduce conflicts.
+Sat Apr 27 16:45:35 1996 Jason Merrill <jason@yorick.cygnus.com>
- (expr): Depend on nontrivial_exprlist instead of nonnull_exprlist.
- (nontrivial_exprlist): New nonterminal: A list of at least two
- expr_no_commas's.
- (nonnull_exprlist): Depend on nontrival_exprlist.
- Eliminates four reduce/reduce conflicts.
+ * class.c (set_rtti_entry): Use size_zero_node.
+ (build_vtable): Likewise.
- (named_class_head): Move intermediate code block into separate
- nonterminal so that we can stick %prec EMPTY on it.
+Sat Apr 27 14:48:57 1996 Jason Merrill <jason@phydeaux.cygnus.com>
- Add more %prec EMPTY's to eliminate remaining shift/reduce
- conflicts.
+ * class.c (finish_struct_1): Pass size_zero_node to set_rtti_entry.
+ (prepare_fresh_vtable): Likewise.
- (after_type_declarator): Add maybe_raises to fndecl rules.
- (after_type_declarator_no_typename): Remove.
- For correctness.
+Fri Apr 26 13:14:14 1996 Jason Merrill <jason@yorick.cygnus.com>
- Document remaining reduce/reduce conflicts.
+ * method.c (emit_thunk): Call mark_used on the target function.
-Tue Feb 22 12:10:32 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * call.c (build_method_call): Don't warn about pending templates.
- * search.c (get_base_distance): Only bash BINFO_INHERITANCE_CHAIN
- (TYPE_BINFO (type)) if we care about the path.
+Thu Apr 25 14:55:44 1996 Jason Merrill <jason@yorick.cygnus.com>
- * tree.c (lvalue_p): A COND_EXPR is an lvalue if both of the
- options are.
+ * decl2.c (finish_file): Fix list walking logic.
-Mon Feb 21 19:59:40 1994 Mike Stump <mrs@cygnus.com>
+ * typeck2.c (check_for_new_type): Only warn if -pedantic.
- * Makefile.in (mostlyclean): lex.c is a source file, don't
- remove.
+Wed Apr 24 15:41:15 1996 Bob Manson <manson@charmed.cygnus.com>
-Sat Feb 19 01:27:14 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * class.c (finish_struct_1): Remove old code for
+ dont_allow_type_definitions.
+ * cp-tree.h: Likewise.
+ * spew.c: Make sure cp-tree.h is included before parse.h, so the
+ definition of flagged_type_tree is found before it is used.
+ * lex.c: Likewise.
+ * parse.y: Added the ftype member to the type union, and changed a
+ number of rules to use it instead of ttype. Added calls to
+ check_for_new_type() as appropriate.
+ * typeck2.c (check_for_new_type): New function for checking
+ if a newly defined type appears in the specified tree.
+ * cp-tree.h: Add new type flagged_type_tree. Add a prototype
+ for check_for_new_type().
- * parse.y: Eliminate 20 shift/reduce conflicts.
+Wed Apr 24 00:36:21 1996 Jason Merrill <jason@yorick.cygnus.com>
-Fri Feb 18 11:49:42 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (finish_file): Only use a sentry if the decl is public.
- * pt.c (type_unification): Add subr argument; if set, it means
- that we are calling ourselves recursively, so a partial match is OK.
- (unify): Support pointers to methods and functions.
- (tsubst): Support method pointers.
- * decl.c (build_ptrmemfunc_type): No longer static, so that
- tsubst can get at it.
+ * pt.c (tsubst_expr, DECL_STMT): If we don't have an initializer,
+ don't pass LOOKUP_ONLYCONVERTING.
- * init.c (is_aggr_typedef): Pretend template type parms are
- aggregates.
- * decl2.c (build_push_scope): If cname refers to a template type
- parm, just grin and nod.
+Tue Apr 23 17:18:47 1996 Bob Manson <manson@charmed.cygnus.com>
- * call.c (build_overload_call_real): Pass subr argument to
- type_unification.
- * pt.c (do_function_instantiation): Ditto.
- * class.c (instantiate_type): Ditto.
+ * typeck.c (common_type): Fix the ARRAY_TYPE case so it
+ properly keeps track of const and volatile type modifiers.
- * search.c (get_base_distance): If BINFO is a binfo, use it and
- don't mess with its BINFO_INHERITANCE_CHAIN.
+Tue Apr 23 10:52:56 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (convert_to_reference): Fix temporary generation.
- If ambiguous, return error_mark_node.
+ * tree.c (cp_tree_equal): C++ version of simple_cst_equal.
+ * pt.c (comp_template_args): Use it.
- * init.c (build_new): Put back some necessary code.
+ * rtti.c (get_tinfo_fn, build_dynamic_cast, expand_*_desc): Call
+ assemble_external for artificial function decls.
-Thu Feb 17 15:39:47 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (cp_finish_decl): Oops.
- * init.c (build_new): Deal with array types properly.
+Mon Apr 22 17:28:27 1996 Jason Merrill <jason@yorick.cygnus.com>
- * search.c (get_binfo): Become a shell for get_base_distance.
- (get_binfo_recursive): Lose.
- (get_base_distance_recursive): Find the path to the via_virtual base
- that provides the most access.
- (get_base_distance): Ditto.
+ * decl2.c (import_export_decl): Put static data member templates
+ into common storage, or make them weak, depending on whether they
+ are dynamically or statically initialized.
+ (get_sentry): New function.
+ (finish_file): Do import_export_decl for static data members before
+ building the init/fini functions. Don't init/fini a variable that's
+ EXTERNAL. Use a sentry for variables in common. Fix mismatching
+ push/pop_temp_slots.
+ * decl.c (cp_finish_decl): If DECL_NOT_REALLY_EXTERN, do the
+ expand_static_init thang.
+ * method.c (get_id_2): New function.
- * parse.y (explicit_instantiation): Syntax is 'template class
- A<int>', not 'template A<int>'.
+Mon Apr 22 15:32:45 1996 Bob Manson <manson@charmed.cygnus.com>
- * typeck.c (convert_for_initialization): Remove bogus warning.
+ * parse.y (empty_parms): Make sure we use C++-style prototypes
+ when we're declaring member functions.
- * parse.y (datadef): Revert patch of Oct 27.
+Sun Apr 21 10:08:22 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Feb 17 15:12:29 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * Makefile.in (CONFLICTS): 16 s/r conflicts.
+ * parse.y (self_template_type): New nonterminal.
- * class.c (build_vfn_ref): Cast delta field to ptrdiff_type_node,
- rather than integer_type_node. Does wonders for the Alpha.
+Thu Apr 18 08:56:54 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Feb 17 13:36:21 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (make_typename_type): Handle getting a TYPE_DECL for a
+ name.
+ * parse.y (base_class.1): Allow 'typename foo::bar'.
- * decl.c (build_ptrmemfunc_type): Make sure that the pmf type
- goes onto the same obstack as its target type.
+ * lex.c (check_newline): Remove #pragma code that plays with the
+ input stream, since we now deal with tokens. Clear nextchar when
+ we're done.
+ (handle_cp_pragma): Use real_yylex.
+ (handle_sysv_pragma): Don't do skipline here. Only call real_yylex
+ in one place.
-Wed Feb 16 00:34:46 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * lex.c (check_for_missing_semicolon): Handle SELFNAME.
- * cvt.c (convert_to_reference): If converting via constructor
- on local level, go back to build_cplus_new approach.
+ * lex.c (handle_cp_pragma): Fix "#pragma implementation".
- * tree.c (build_cplus_new): If with_cleanup_p, set cleanup slot
- to error_mark_node to prevent expand_expr from building a cleanup
- for this variable.
+Wed Apr 17 16:51:33 1996 Jason Merrill <jason@yorick.cygnus.com>
- * lex.c (default_assign_ref_body): Return *this from the memcpy
- version, too.
+ * parse.y: New token SELFNAME for potential constructor.
+ * spew.c (yylex): Handle it.
+ * lex.c (identifier_type): Produce it.
- * decl.c (grok_reference_init): Just return if called with
- error_mark_node, don't worry about initializing non-const reference
- with temporary.
+ * parse.y (complete_type_name): In :: case, don't push class binding.
+ (complex_type_name): Likewise.
- * cvt.c (convert_to_reference): Do the right thing for
- non-aggregate reference conversions, pedwarn when generating a
- non-const reference to a temporary.
+Wed Apr 17 15:02:40 1996 Mike Stump <mrs@cygnus.com>
- * class.c (finish_struct): TYPE_HAS_COMPLEX_{INIT,ASSIGN}_REF and
- TYPE_NEEDS_CONSTRUCTING all depend on TYPE_USES_VIRTUAL_BASECLASSES
- again.
+ * typeck.c (build_reinterpret_cast): Handle pointer to member
+ functions.
-Tue Feb 15 19:47:19 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Apr 17 12:28:26 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c (grok_reference_init): Pawn off a lot of the work on
- convert_to_reference. Generally do the right thing.
+ * lex.c (handle_cp_pragma): New function, with decl, doing the cc1plus
+ pragmas.
+ (check_newline): Put the vtable/unit/implementation/interface pragma
+ code into handle_cp_pragma, replacing it with a call.
+ (handle_sysv_pragma): Give int return type, and take FINPUT and TOKEN
+ args. Get the next token after handling the pragma token.
- * cvt.c (convert_to_reference): Conform to the initial comment;
- i.e. don't create temps if decl != error_mark_node. Handle
- cleanups better for temps that do get created. Don't pretend
- that we can use an 'A' to initialize a 'const double &' just by
- tacking on a NOP_EXPR. Support LOOKUP_SPECULATIVELY.
+Wed Apr 17 10:28:34 1996 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_method_call): Set TREE_HAS_CONSTRUCTOR on
- constructor calls.
+ * cvt.c (cp_convert_to_pointer): Avoid doing base analysis on pmfs.
+ (convert_to_pointer_force): Likewise.
-Mon Feb 14 14:50:17 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * init.c (build_new): Fix array new without -fcheck-new.
- * decl.c (grok_reference_init): Make a temporary for initializing
- const reference from constant expression.
+Tue Apr 16 13:44:58 1996 Jason Merrill <jason@yorick.cygnus.com>
-Mon Feb 14 11:31:31 1994 Per Bothner (bothner@kalessin.cygnus.com)
+ * cp-tree.h, call.c, class.c, decl.c, parse.y, pt.c, rtti.c,
+ tree.c: Lose TYPE_NESTED_NAME.
- * cp-tree.h, decl.c (set_identifier_local_value): Deleted function.
- * decl.c (pushdecl): Define decl in correct binding_level
- (which isn't always the inner_binding_level).
+ * parse.y (nested_name_specifier_1): Don't treat non-identifiers
+ as identifiers.
- * cvt.c (build_up_reference): Don't ever call expand_aggr_init.
- It's ugly, and I don't think it's the right thing to do.
+ * tree.def: Add VEC_INIT_EXPR.
+ * expr.c (cplus_expand_expr): Handle it.
+ * init.c (build_new): Use it instead of the RTL_EXPR nastiness and
+ the extra file-scope symbol nastiness.
- * cp-tree.h, class.c, decl.c, decl2.c, sp/search.c:
- Remove NEW_CLASS_SCOPING, assuming it is always 1.
- * decl.c (pop_decl_level): Removed; manually inlined.
+Mon Apr 15 16:21:29 1996 Jason Merrill <jason@yorick.cygnus.com>
-Sun Feb 13 19:04:56 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * method.c (make_thunk): Thunks are static.
+ (emit_thunk): Use ASM_OUTPUT_MI_THUNK if it's defined.
- * class.h (candidate): Add basetypes field.
+ * decl2.c (mark_vtable_entries): Emit thunks as needed.
+ (finish_file): Don't emit them here.
- * call.c (build_method_call): Do access checking after choosing a
- function, not before.
+Sun Apr 14 11:34:39 1996 Jason Merrill <jason@yorick.cygnus.com>
- * Makefile.in (cvt.o, call.o, method.o): Depend on class.h.
- (mostlyclean): Remove ../cc1plus.
+ * rtti.c (build_dynamic_cast): Handle null pointers.
+ (ifnonnull): New function.
-Fri Feb 11 11:52:26 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Apr 12 09:08:27 1996 Bob Manson <manson@charmed.cygnus.com>
- * class.c (finish_struct): Don't allow adjusting access to a field
- of a base class if a local field has the same name.
+ * call.c (build_method_call): Remember the original basetype we
+ were called with. Give an error message instead of trying
+ (incorrectly) to call a non-static member function through a
+ non-inherited class.
- * error.c (dump_type_prefix): Output basetype for METHOD_TYPEs.
+ * search.c (expand_upcast_fixups): Mark the new fixup as
+ DECL_ARTIFICIAL.
-hu Jan 13 17:55:51 EST 1994 Gnanasekaran Swaminathan (gs4t@virginia.edu)
+Thu Apr 11 03:57:09 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-tree.h (DESTRUCTOR_NAME_P): do not confuse AUTO_TEMP names
- with destructor names when either NO_DOLLAR_IN_LABEL or
- NO_DOT_IN_LABEL are not defined.
+ * init.c (build_new): Use a TARGET_EXPR for alloc_expr.
- Now `template <class T, T f(T&), const T*> class A {...}' works.
+ * class.c (set_rtti_entry): Fix for thunks.
- * pt.c (grok_template_type): substitute template parm types
- with actual types in complex type as well.
- (coerce_template_parms): update the grok_template_type ()
- function call.
+ * decl2.c (import_export_decl): Still emit typeinfo fns for
+ cv-variants of builtin types.
- * pt.c (tsubst): Traverse method list using DECL_CHAIN.
+ * rtti.c (expand_class_desc): Set up base_info_type_node here.
+ (init_rtti_processing): Instead of here.
- * decl.c (grok_op_properties): Allow operator++/-- to have
- default arguments.
+Wed Apr 10 14:17:13 1996 Jason Merrill <jason@yorick.cygnus.com>
- * typeck2.c (store_init_value): Don't abort when called to
- initialize a type that needs constructing with a CONSTRUCTOR.
+ * rtti.c (init_rtti_processing): Do init regardless of -frtti.
+ (build_typeid): Only complain about taking dynamic typeid without
+ -frtti.
- * init.c (expand_aggr_init_1, CONSTRUCTOR case): If
- store_init_value fails, build and expand an INIT_EXPR. If
- store_init_value succeeds, call expand_decl_init.
+ * decl2.c: flag_rtti defaults to 1.
-Fri Feb 11 02:49:23 1994 Mike Stump <mrs@cygnus.com>
+ * rtti.c (get_tinfo_var): The general class case is now smaller.
+ (init_rtti_processing): Pack the latter three fields of base_info
+ into 32 bits.
- * class.c (build_vbase_path): Use complete_type_p instead of
- resolves_to_fixed_type_p to determine if the virtual bases are in
- their right place for the type of expr. Cures problem of thinking a
- virtual base class is one place, when it is in fact someplace else.
+Wed Apr 10 13:50:14 1996 Mike Stump <mrs@cygnus.com>
-Fri Feb 11 00:26:46 1994 Mike Stump <mrs@cygnus.com>
+ * init.c (expand_member_init): Don't dump if name is NULL_TREE.
- * init.c (resolve_offset_ref): Make sure we first convert to
- intermediate type, if given, when dealing with members off `this'.
- Solves an incorrrect `type `foo' is not a base type for type
- `multiple'' when it is infact, a base type.
+Wed Apr 10 12:56:02 1996 Mike Stump <mrs@cygnus.com>
-Thu Feb 10 21:49:35 1994 Mike Stump <mrs@cygnus.com>
+ * search.c (make_memoized_table_entry): Undefer the pop, if necessary.
+ (push_memoized_context): Split out code to undefer pop_type_level to
+ (clear_memoized_cache): here.
+ (pop_memoized_context): We can only handle one layer of deferral of
+ pop_type_level so clear the cache, if there was a previous level.
- * class.c (modify_other_vtable_entries): Use get_binfo, instead
- of binfo_value. Solves problem with compiler giving a `base class
- `B' ambiguous in binfo_value (compiler error)' on complex MI
- herarchies, when a virtual function is first defied in a virtual
- base class.
+Tue Apr 9 23:06:09 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Feb 10 17:19:32 1994 Mike Stump <mrs@cygnus.com>
+ * rtti.c (init_rtti_processing): Build up base_info_type_node.
+ (expand_class_desc): Use one pointer to an array of base_info
+ structs, passed using a CONSTRUCTOR.
- * class.c (build_vbase_path): Don't complain about ambiguous
- intermediate conversion when converting down to a virtual base
- class, even if they might seem to be ambiguous.
+Tue Apr 9 14:20:57 1996 Mike Stump <mrs@cygnus.com>
-Thu Feb 10 12:18:26 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * class.c (build_vbase_path): Remove block extern for
+ flag_assume_nonnull_objects here.
+ (build_vfn_ref): Split out functionality into build_vtbl_ref.
+ (build_vtbl_ref): New routine.
+ (build_vtable): Set up rtti info here.
+ (add_virtual_function): Note in CLASSTYPE_RTTI the best
+ place where we can get the rtti pointers from to avoid having to
+ search around for a place.
+ (finish_base_struct): Likewise.
+ (finish_struct_1): Likewise. Never create totally new vtables
+ with totally new vtable pointers for rtti. Disable code to layout
+ vtable pointers better until we want to break binary
+ compatibility.
+ * rtti.c (build_headof_sub): New routine to convert down to a
+ sub-object that has an rtti pointer in the vtable.
+ (build_headof): Use it. Also, use build_vtbl_ref now to be more
+ maintainable.
+ (build_dynamic_cast): Make sure we have saved it, if we need to.
+ * search.c (dfs_init_vbase_pointers): Disable code that deals with
+ a more efficient vtable layout, enable later.
+ * call.c (flag_assume_nonnull_objects): Moved declaration to
+ * cp-tree.h: here. Declare build_vtbl_ref.
+ * pt.c (instantiate_class_template): Use NULL_TREE instead of 0 in
+ function calls that want a tree.
- * typeck2.c (build_functional_cast): #if 0 out constructor
- inheritance code, improve error messages.
+Tue Apr 9 12:10:26 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_base_struct): Complain about base with only
- non-default constructors in derived class with no constructors.
+ * rtti.c (build_dynamic_cast): Handle downcasting to X* given
+ other X subobjects in the most derived type. Ack.
- * decl.c (grokdeclarator): Fix detection of virtual new/delete.
+ * rtti.c (build_dynamic_cast): No need to strip cv-quals here,
+ get_typeid will do it for us.
+ (get_typeid_1): Break out call-building for expand_*_desc to use.
+ (get_typeid): Call it.
+ (expand_*_desc): Likewise.
+ * decl.c (init_decl_processing): Don't set TYPE_BUILT_IN on char *
+ and void *.
+ (init_decl_processing): Lose builtin_type_tdescs lossage.
+ * decl2.c (finish_vtable_vardecl): Remove obsolete code.
-Wed Feb 9 22:02:32 1994 Mike Stump <mrs@cygnus.com>
+Mon Apr 8 17:23:23 1996 Bob Manson <manson@charmed.cygnus.com>
- * search.c (build_mi_virtuals, add_mi_virtuals,
- report_ambiguous_mi_virtuals): Removed unneeded code.
- * class.c (finish_struct_bits): Ditto.
+ * pt.c (tsubst): When calling set_nested_typename, use
+ TYPE_NESTED_NAME (current_class_type) instead of
+ current_class_name.
-Wed Feb 9 11:27:17 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (pushdecl): Likewise.
+ (pushdecl_class_level): Likewise.
+ (grokdeclarator): Use NULL_TREE instead of 0 in the call to
+ set_nested_typename.
+
+Sun Apr 7 10:44:31 1996 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (end_template_instantiation): Push decl before
- pop_from_top_level.
+ * rtti.c (synthesize_tinfo_fn): Handle arrays.
+
+ * cp-tree.h (DECL_REALLY_EXTERN): New macro.
+
+Sat Apr 6 13:56:27 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * rtti.c (throw_bad_cast): Use entry point __throw_bad_cast.
+ (init_rtti_processing): Lose bad_cast_type.
+ (build_dynamic_cast): Use throw_bad_cast.
+
+ * rtti.c (synthesize_tinfo_fn): Handle enums and pmfs.
+
+ * decl2.c (finish_file): Don't synthesize artificial functions
+ that are external and not inline.
+
+ * rtti.c (get_tinfo_fn): If at_eof, call import_export_decl.
+
+ * decl2.c (finish_file): Handle having new inlines added to
+ saved_inlines by synthesis.
+
+ * rtti.c (get_bad_cast_node): Don't require <typeinfo>.
+
+Fri Apr 5 17:02:09 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ RTTI rewrite to initialize nodes as needed, not require that
+ users #include <typeinfo>, complete functionality and reduce wasted
+ space.
+ * rtti.c (init_rtti_processing): New fn.
+ (build_typeid): The vtable entry is now a function.
+ (get_tinfo_var): New fn.
+ (get_tinfo_fn): Likewise.
+ (get_typeid): Use it.
+ (build_dynamic_cast): Declare and use entry point __dynamic_cast.
+ (build_*_desc): Rename to expand_*_desc and rewrite to use entry
+ points __rtti_*.
+ (add_uninstantiated_desc, get_def_to_follow, build_t_desc): Lose.
+ (synthesize_tinfo_fn): New fn.
+ * method.c (build_t_desc_overload): Lose.
+ (build_overload_with_type): More generic.
+ * decl.c (init_decl_processing): Call init_rtti_processing.
+ * class.c (set_rtti_entry): Use get_tinfo_fn.
+ * decl2.c (mark_vtable_entries): Mark the rtti function.
+ (finish_prevtable_vardecl): Don't build_t_desc.
+ (import_export_decl): Handle tinfo functions.
+ (finish_file): Likewise.
+ * typeck.c (inline_conversion): New fn.
+ (build_function_call_real): Use it.
+ * cp-tree.h: Add decls.
+
+ * method.c (hack_identifier): Also convert component_refs from
+ references.
- * typeck2.c (build_m_component_ref): Make sure datum is of
- aggregate type.
+ * lex.c (cons_up_default_function): Use the type, not the name, in
+ declspecs.
- * init.c (get_type_value): New function, returns
- IDENTIFIER_TYPE_VALUE or IDENTIFIER_CLASS_TYPE_VALUE or NULL_TREE.
+ * decl2.c (import_export_vtable): Fix weak vtables.
- * call.c (build_method_call): Don't die on call to destructor for
- non-type.
+Fri Apr 5 13:30:17 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl.c (grokdeclarator): Complain about virtual op new and op
- delete, make static virtuals unvirtual instead of unstatic.
+ * search.c (get_base_distance_recursive): Fix access checks for
+ protected bases.
- * typeck.c (build_c_cast): Also call default_conversion on
- methods.
+Fri Apr 5 11:02:06 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c (grokdeclarator): Don't complain about anonymous
- bitfields.
+ * call.c (unary_complex_lvalue): Delete unneeded decl, it's in
+ cp-tree.h.
+ (convert_harshness): Add prototypes wrapped by PROTO.
+ * decl2.c (grok_function_init): Likewise.
+ (do_toplevel_using_decl): Change to void return type.
+ * class.c (build_vtable_entry): Remove decl of make_thunk.
+ (merge_overrides): Fix order of arg definitions.
+ (finish_vtbls): Likewise.
+ (fixup_vtable_deltas): Likewise.
+ (modify_all_direct_vtables): Likewise.
+ (modify_all_indirect_vtables): Likewise.
+ * search.c (get_base_distance_recursive): Likewise.
+ (get_abstract_virtuals_1): Likewise.
+ (fixup_virtual_upcast_offsets): Likewise.
+ (lookup_fnfields_1): Add prototypes wrapped by PROTO.
+ * init.c (perform_member_init): Fix order of arg definitions.
+ (expand_aggr_init_1): Add prototypes wrapped by PROTO.
+ * cp-tree.h (make_thunk): Add decl.
+ (overload_template_name, push_template_decl): Add decls.
+ (do_toplevel_using_decl): Change to void return type.
+ (vec_binfo_member): Add decl.
- * parse.y (simple_stmt, for loops): Move the continue point after
- the cleanups.
+Thu Apr 4 13:33:10 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * class.c (finish_struct): Fix setting of
- TYPE_HAS_COMPLEX_INIT_REF.
+ * typeck.c (mark_addressable, convert_for_assignment,
+ convert_for_initialization, pointer_int_sum, pointer_diff,
+ unary_complex_lvalue): Add prototypes wrapped by PROTO.
+ (convert_sequence): #if 0 fn decl, since definition also is.
-Tue Feb 8 13:21:40 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu Apr 4 11:00:53 1996 Mike Stump <mrs@cygnus.com>
- * init.c (build_new): Deal with `new double (1)'.
+ * rtti.c (build_dynamic_cast): Make sure we strip qualifiers on
+ cast to pointer types for type searching.
- * class.c (finish_struct): TYPE_HAS_COMPLEX_*_REF are supersets of
- TYPE_HAS_REAL_*_REF, but TYPE_HAS_COMPLEX_INIT_REF is independent of
- TYPE_NEEDS_CONSTRUCTING.
+Wed Apr 3 17:10:57 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c (duplicate_decls): Propagate access decls.
+ * typeck.c (get_delta_difference): Use cp_error, not error, in the
+ case where BINFO == 0.
- * typeck2.c (process_init_constructor): Accept empty_init_node
- for initializing unions.
+Wed Apr 3 12:01:02 1996 Mike Stump <mrs@cygnus.com>
- * class.c, lex.c, cp-tree.h: Use
- TYPE_HAS_COMPLEX_ASSIGN_REF where TYPE_HAS_REAL_ASSIGN_REF was used
- before, use TYPE_HAS_COMPLEX_INIT_REF for TYPE_NEEDS_CONSTRUCTING in
- some places.
+ * call.c (build_method_call): Fix wording of error messages so
+ constructors come out right.
- * decl.c (finish_decl): Don't complain about uninitialized const
- if it was initialized before.
+Tue Apr 2 16:06:59 1996 Bob Manson <manson@charmed.cygnus.com>
-Mon Feb 7 18:12:34 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (push_overloaded_decl): Don't warn about hidden
+ constructors when both the type and the function are declared
+ in a system header file.
- * lex.c (default_assign_ref_body): Don't deal with vbases for
- now.
+Mon Apr 1 09:03:13 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl.c (finish_decl): Fix reversed logic for objects and other
- things that need to be constructed but have no initializer.
+ * class.c (finish_struct_1): Propagate the TYPE_PACKED
+ flag for the type to the type's fields.
- * class.c (finish_struct): Don't set TYPE_HAS_* flags that are
- set by grok_op_properties or finish_decl.
+Sat Mar 30 12:14:33 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c: Don't warn about extern redeclared inline unless
- -Wextern-inline is given.
- * decl2.c (lang_decode_option): Ditto.
- * cp-tree.h: Ditto.
+ * parse.y (complex_parmlist, ELLIPSES): Take out ARM-based warning.
-Mon Feb 7 17:29:24 1994 Per Bothner (bothner@kalessin.cygnus.com)
+Fri Mar 29 15:51:36 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl.c (pushdecl_with_scope): Fix thinko. Add forward
- declaration.
+ * class.c (base_info, finish_base_struct): Replace
+ needs_virtual_dtor with base_has_virtual.
- * decl.c (pushdecl_with_scope): New function.
- * decl.c (pushdecl_top_level): Use new function.
- * decl.c (pushtag): Initialize newdecl.
- * decl.c (pushtag): Push new type decl into correct scope.
+ (finish_struct_1): Remove the old code that tried to make default
+ destructors virtual. Use base_has_virtual when checking if we need
+ to add a vtable entry for the rtti code.
-Mon Feb 7 14:42:03 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Mar 29 14:02:36 1996 Jason Merrill <jason@yorick.cygnus.com>
- * call.c, cvt.c, init.c, search.c, cp-tree.h:
- Eradicate LOOKUP_PROTECTED_OK.
+ * pt.c (push_template_decl): Complain about template decl with
+ inappropriate declaration.
-Mon Feb 7 13:57:19 1994 Per Bothner (bothner@kalessin.cygnus.com)
+Fri Mar 29 12:15:35 1996 Bob Manson <manson@charmed.cygnus.com>
- * decl.c (pushtag, xref_tag), cp-tree.h: Add extra parameter
- 'globalize' to signify implicit declarations.
- * decl.c (globalize_nested_type, maybe_globalize_type): Removed.
- * decl.c (set_identifier_type_value_with_scope): New function.
- * decl.c (set_identifier_local_value): Simplify.
- * spew.c (yylex, do_addr): Modify to return a _DEFN if a
- forward declaration (followed by ';' and not preceded by 'friend').
- * class.c, decl.c, except.c, init.c, parse.y,
- pt.c, search.c: Add new argument to calls to xref_tag and
- pushtag.
+ * typeck.c (build_x_unary_op): Remove bogus check for taking
+ the address of a member function.
-Mon Feb 7 00:22:59 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Mar 29 11:56:02 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-tree.h (ACCESSIBLY_UNIQUELY_DERIVED_P): New macro, means what
- ACCESSIBLY_DERIVED_FROM_P meant before.
- (ACCESSIBLY_DERIVED_FROM_P): Now disregards ambiguity.
+ * parse.y (constructor_declarator): Only push the class if
+ we are not already in the class.
- * cvt.c (build_up_reference): Call get_binfo with PROTECT == 1.
+Fri Mar 29 09:41:02 1996 Jeffrey A. Law <law@cygnus.com>
- * search.c (get_base_distance_recursive): Members and friends of
- a class X can implicitly convert an X* to a pointer to a private or
- protected immediate base class of X.
- (get_binfo_recursive): Ditto.
- (get_base_distance): Ignore ambiguity if PROTECT < 0.
- (get_binfo): Lose multiple values of PROTECT.
- (compute_access): Protected is OK if the start of the
- search is an accessible base class of current_class_type.
+ * method.c (emit_thunk): Remove current_call_is_indirect nonsense.
+ Add additional argument to INIT_CUMULATIVE_ARGS.
- * method.c (build_opfncall): Do check access on operator new here.
+Thu Mar 28 16:41:39 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (finish_function): Don't check access on operator new
- here.
+ * decl.c (shadow_tag): Fix error about anon union with methods.
-Sun Feb 6 14:06:58 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * parse.y (self_reference): Only generate a self-reference if this
+ is a non-template class.
+ (opt.component_decl_list): Only use it if it was generated.
- * decl.c (xref_tag): The base of a derived struct is NOT always
- public. Duh.
+ * parse.y (component_decl_1): Use constructor_declarator.
+ (fn.def2): Likewise.
+ (notype_component_declarator0): Likewise.
- * pt.c (do_explicit_instantiation): New function, called from
- parser to do explicit function instantiation.
- (type_unification): Allow the args list to be terminated with
- void_list_node.
- (do_pending_expansions): Look at i->interface for non-member
- templates.
+Thu Mar 28 15:11:35 1996 Bob Manson <manson@charmed.cygnus.com>
- * parse.y (datadef): Move explicit_instantiation here.
- (structsp): From here.
- (datadef): Complain about `int;'.
+ * typeck.c (build_x_unary_op): Add checks for taking the address
+ of a TARGET_EXPR or of a member function, and give appropriate
+ warnings.
-Sun Feb 6 12:33:18 1994 Per Bothner (bothner@kalessin.cygnus.com)
+Thu Mar 28 14:49:26 1996 Jason Merrill <jason@yorick.cygnus.com>
- * pt.c (end_template_instantiation), cp-tree.h: Remove unused
- second parameter, and simplify first from a TREE_LIST where
- we only care about its TREE_VALUE to just the value (an IDENTIFIER).
- * pt.c (instantiate_member_templates): Simplify argument list
- from a TREE_LIST to just an IDENTIFIER.
- * lex.c (yyprint): PRE_PARSED_CLASS_DECL is now just an IDENTIFIER.
- * parse.y (template_instantiate_once): Simplify accordingly.
- * decl.c (inner_binding_level): New. Use various places to
- simplify.
+ * pt.c (process_template_parm): Allow template type parms to be
+ used as types for template const parms.
-Sun Feb 6 02:49:37 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Mar 27 15:51:19 1996 Mike Stump <mrs@cygnus.com>
- * typeck2.c (build_functional_cast): int() -> int(0).
+ * init.c (expand_vec_init): Ensure the eh cleanups are on the
+ function_obstack.
-Sat Feb 5 00:53:21 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Mar 27 10:14:30 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): Don't do a bitwise copy for op= if the
- class has a virtual function table.
+ * decl.c (lookup_name_real): Be even more picky about the
+ ambiguous lookup warning.
+ (grokdeclarator): Tweak SCOPE_REF constructor declarators here.
+ * parse.y (constructor_declarator): Rather than here.
- * typeck.c (convert_for_initialization): Restore warnings about
- not using defined op=. Should really be my_friendly_aborts, I
- s'pose.
+ * parse.y (constructor_declarator): New nonterminal.
+ (fn.def1): Use it.
+ (explicit_instantiation): Likewise.
-Fri Feb 4 14:21:00 1994 Jason Merrill (jason@deneb.cygnus.com)
+Tue Mar 26 13:41:33 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): Tidy up conditions for doing bitwise
- copies of objects.
+ Add implicit declaration of class name at class scope.
+ * decl.c (lookup_name_real): Restrict pedwarn about ambiguous lookup.
+ * parse.y (self_reference): New nonterminal.
+ (opt.component_decl_list): Use it.
+ (fn.def1): Add nested_name_specifier type_name cases.
+ * class.c (build_self_reference): New function.
+ (finish_struct): Handle access_default later, move self-reference
+ decl to the end.
+ * pt.c (lookup_template_class): Handle getting a TYPE_DECL.
+ * cp-tree.h: Adjust.
- * decl.c (build_default_constructor): #if 0 out.
+ * pt.c (do_function_instantiation): Separate handling of member
+ functions and non-member functions properly.
- * *: Eradicate TYPE_GETS_{ASSIGNMENT,ASSIGN_REF,CONST_ASSIGN_REF,
- CONST_INIT_REF}, TYPE_HAS_REAL_CONSTRUCTOR.
+Mon Mar 25 14:23:22 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokdeclarator): Don't return void_type_node for
- friends being defined here.
+ * pt.c (process_template_parm): Improve error for 'volatile class K'.
- * init.c (perform_member_init): Only do the init if it's useful.
+ * class.c (finish_struct_1): Check the right slot for destructors.
- * lex.c (default_copy_constructor_body): If we don't need to do
- memberwise init, just call __builtin_memcpy.
- (default_assign_ref_body): Ditto.
+ * decl.c (start_enum): Complain about enum templates.
- * decl.c (grokdeclarator): If friendp && virtualp, friendp = 0.
+Mon Mar 25 13:25:31 1996 Mike Stump <mrs@cygnus.com>
-Fri Feb 4 13:02:56 1994 Mike Stump <mrs@cygnus.com>
+ * init.c (resolve_offset_ref): Offset pointers to member data by one.
+ * typeck.c (unary_complex_lvalue): Likewise.
- * lex.c (reinit_parse_for_method, cons_up_default_function):
- Don't give warn_if_unknown_interface warning when it came from a
- system header file.
- * pt.c (end_template_decl, instantiate_template): Ditto.
- * decl.c (start_decl): Ditto.
+Mon Mar 25 13:30:42 1996 Bob Manson <manson@charmed.cygnus.com>
-Fri Feb 4 00:41:21 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (c_expand_return): Check for a returned local
+ array name, similar to the check for an ADDR_EXPR.
- * decl.c (grokdeclarator): Don't try to set TYPE_WAS_ANONYMOUS on
- enums.
+Mon Mar 25 13:07:19 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (constructor_name_full): Use IS_AGGR_TYPE_CODE instead of
- IS_AGGR_TYPE, since we don't know it's a type.
+ * decl.c (cp_finish_decl): Don't build cleanups for static
+ variables here.
-Thu Feb 3 11:36:46 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Mar 22 17:57:55 1996 Mike Stump <mrs@cygnus.com>
- * decl.c (grokdeclarator): Don't complain about anonymous unions.
+ * typeck.c (build_modify_expr): Fix error messages to be more
+ accurate.
+ * cp-tree.h (assop_as_string): Parallel to op_as_string, but for
+ assignment operators.
+ * error.c (assop_as_string): Likewise. Add support for `%Q' for
+ assignment operators.
- * cp-tree.h (TYPE_WAS_ANONYMOUS): This struct was originally
- anonymous, but had a name given to it by a typedef.
+Fri Mar 22 13:48:29 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (grokdeclarator): When renaming an anonymous struct, set
- TYPE_WAS_ANONYMOUS.
+ * decl.c (grokdeclarator): Call bad_specifiers for typedefs. Also
+ give an error if initialized. Pedwarn about nested type with the
+ same name as its enclosing class.
- * decl2.c (constructor_name_full): Use TYPE_WAS_ANONYMOUS.
+ * pt.c (tsubst, case TYPE_DECL): Set DECL_CONTEXT.
- * cp-tree.h (DECL_UNDEFINED_FRIENDS): #if 0 out.
+ * typeck.c (require_complete_type): Be sure to instantiate the
+ MAIN_VARIANT of the type.
- * init.c (xref_friend): Don't set up DECL_UNDEFINED_FRIENDS.
- (embrace_waiting_friends): Don't use DECL_UNDEFINED_FRIENDS.
-
- * decl.c (grokdeclarator): Set TYPE_NESTED_NAME properly on nested
- anonymous structs that get typedef'd.
+ * decl2.c (finish_file): Instantiate pending templates before
+ processing static constructors and destructors.
- * decl.c (grokdeclarator): Always return void_type_node for
- friends.
+ * pt.c (instantiate_decl): Don't instantiate functions at toplevel
+ unless at_eof.
- * error.c (dump_function_decl): Don't use DECL_CLASS_CONTEXT for
- friends.
- (dump_function_decl): Don't print out default args for
- a function used in an expression.
+Fri Mar 22 09:30:17 1996 Bob Manson <manson@beauty.cygnus.com>
- * decl.c (grokdeclarator): Give error on abstract declarator used
- in an invalid context (i.e. `void (*)();').
+ * decl2.c (delete_sanity): If error_mark_node is passed
+ in as an expression, quit while we're ahead.
- * error.c (cp_line_of): Support _TYPE nodes.
- (cp_file_of): Ditto.
+ * decl.c (grokdeclarator): Give an error message if `friend'
+ is combined with any storage class specifiers.
- * cvt.c (build_up_reference): Don't abort if passed a SAVE_EXPR;
- it can happen for the RHS of an assignment stmt where the LHS is
- a COND_EXPR.
+Wed Mar 20 14:51:55 1996 Jason Merrill <jason@yorick.cygnus.com>
- * init.c (expand_aggr_init_1): Deal with bracketed initializer
- lists properly.
+ * parse.y (named_complex_class_head_sans_basetype): Don't crash on
+ definition of nonexistent nested type.
- * class.c (finish_struct): Deal with enumerators and typedefs
- again.
+ * error.c (dump_decl, case TYPE_DECL): Fix decision for whether or
+ not to say 'typedef'.
-Wed Feb 2 11:30:22 1994 Jason Merrill (jason@deneb.cygnus.com)
+Wed Mar 20 00:11:47 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * class.c (finish_struct): Tidy up loop over fields.
+ * cp-tree.h (struct lang_type): Make search_slot a tree, not a char*.
+ * search.c (dfs_walk, dfs_init_vbase_pointers,
+ expand_upcast_fixups): Remove cast of CLASSTYPE_SEARCH_SLOT.
+ (dfs_find_vbases): Remove cast for CLASSTYPE_SEARCH_SLOT init.
- * errfn.c (cp_thing): Don't advance twice after a format.
+Tue Mar 19 17:56:03 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (finish_struct): Complain about needing a constructor
- if a member has only non-default constructors, and don't try to
- generate a default constructor.
+ * except.c (build_throw): Support minimal parse.
+ * pt.c (tsubst_copy): Support THROW_EXPR.
+ * decl2.c (build_expr_from_tree): Likewise.
- * decl.c (finish_decl): Also do the constructor thing if
- TYPE_NEEDS_CONSTRUCTING is set (for arrays).
+ * pt.c (mangle_class_name_for_template): Always allocate
+ scratch_firstobj.
- * search.c (unuse_fields): New function: mark all fields in this
- type unused.
- (dfs_unuse_fields): Helper function.
+Tue Mar 19 16:34:31 1996 Bob Manson <manson@beauty.cygnus.com>
- * class.c (pushclass): If the new class is the same as the old
- class, still unuse the fields.
- (unuse_fields): Move to search.c.
+ * cvt.c (cp_convert_to_pointer): Give an appropriate error
+ when trying to cast from an incomplete type.
- * decl.c (grok_op_properties): Add friendp argument.
- (grokfndecl): Pass it.
- (start_method): Ditto.
+Tue Mar 19 16:00:33 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl2.c (delete_sanity): Add use_global_delete parameter to catch
- ::delete calls.
+ * pt.c (instantiate_class_template): Don't bother setting up
+ CLASSTYPE_TAGS explicitly, as the nested types will add
+ themselves.
- * parse.y (unary_expr): Pass new parameter to delete_sanity.
+Tue Mar 19 15:48:43 1996 Bob Manson <manson@beauty.cygnus.com>
- * lex.c (default_copy_constructor_body): Don't choke if the union
- has no fields.
- (default_assign_ref_body): Ditto.
+ * decl.c (shadow_tag): Remove old error check for usage of
+ an enum without a previous declaration.
+ (xref_tag): Add error message about usage of enums without a
+ previous declaration.
- * call.c (compute_conversion_costs_ansi): Do the right thing for
- ellipsis matches.
+Tue Mar 19 09:21:35 1996 Jason Merrill <jason@yorick.cygnus.com>
- * decl.c (push_to_top_level): Optimize.
+ * lex.c (do_identifier): Only do name consistency check if we're
+ parsing.
- * decl.c (start_function): Look for the lexical scope of a friend
- in DECL_CLASS_CONTEXT.
+ * pt.c (push_template_decl): Don't crash if we get a member defn
+ that doesn't match.
- * init.c (do_friend): Set DECL_CLASS_CONTEXT on global friends.
+ * decl.c (xref_tag_from_type): New function to do an xref without
+ always having to figure out code_type_node.
+ * cp-tree.h: Declare it.
+ * pt.c (instantiate_class_template): Use it for friend classes.
+ (lookup_template_class): Use it.
-Tue Feb 1 15:59:24 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck2.c (build_functional_cast): Pull out a single parm before
+ passing it to build_c_cast.
- * cp-tree.h (TREE_GETS_PLACED_NEW): New macro.
+Tue Mar 19 09:07:15 1996 Bob Manson <manson@beauty.cygnus.com>
- * init.c (init_init_processing): Don't assign BIN/BID to the
- IDENTIFIER_GLOBAL_VALUEs of their respective operators.
- (build_new): Check TREE_GETS_PLACED_NEW.
+ * expr.c (do_case): Give an error message if a pointer is
+ given as a case value.
- * decl.c (grok_op_properties): Don't set TREE_GETS_NEW for a decl of
- op new with placement, set TREE_GETS_PLACED_NEW.
+Mon Mar 18 21:57:54 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-tree.h (ANON_UNION_P): New macro. Applies to decls.
+ * typeck.c (build_c_cast): Don't pull single TEMPLATE_DECL out of
+ an overload list.
- * class.c (finish_struct): Don't treat anonymous unions like
- other aggregate members. Do synthesize methods for unions without
- a name, since they may or may not be "anonymous unions".
+ * lex.c (cons_up_default_function): Really, now, interface hackery
+ does not apply to synthesized methods.
- * decl2.c (grok_x_components): Wipe out memory of synthesized methods
- in anonymous unions.
+Mon Mar 18 18:20:57 1996 Mike Stump <mrs@cygnus.com>
- * lex.c (default_copy_constructor_body): Support unions.
- (default_assign_ref_body): Ditto.
+ * call.c (build_method_call): Ctors and dtors now have special names
+ with respect to lookups.
+ * class.c (add_method): Likewise.
+ (grow_method): Likewise.
+ (finish_struct_methods): Likewise.
+ (warn_hidden): Likewise.
+ (finish_struct_1): Likewise.
+ * cvt.c (convert_to_reference): Likewise.
+ (convert_to_aggr): Likewise.
+ (cp_convert): Likewise.
+ * decl2.c (check_classfn): Likewise.
+ * init.c (expand_member_init): Likewise.
+ (expand_default_init): Likewise.
+ (expand_aggr_init_1): Likewise.
+ (build_offset_ref): Likewise.
+ (build_new): Likewise.
+ (build_delete): Likewise.
+ * lex.c (do_inline_function_hair): Likewise.
+ * search.c (lookup_field_1): Likewise.
+ (lookup_fnfields_here): Likewise.
+ (lookup_field): Likewise.
+ (lookup_fnfields): Likewise.
+ (get_virtual_destructor): Likewise.
+ (dfs_debug_mark): Likewise.
+ (dfs_pushdecls): Likewise.
+ (dfs_compress_decls): Likewise.
+ * tree.c (layout_basetypes): Likewise.
+ * typeck.c (build_component_ref): Likewise.
+ (build_x_function_call): Likewise.
+ (build_modify_expr): Likewise.
+ (convert_for_initialization): Likewise.
+ (build_functional_cast): Likewise.
+ * cp-tree.h (CLASSTYPE_FIRST_CONVERSION): Likewise.
+ (CTOR_NAME): New.
+ (DTOR_NAME): New.
+ * decl.c (ctor_identifier): New.
+ (dtor_identifier): New.
+ (init_decl_processing): Set them.
+
+Mon Mar 18 18:00:51 1996 Mike Stump <mrs@cygnus.com>
+
+ * typeck.c (build_component_ref): Don't get confused by fields whose
+ context has no type name, like pointer to member functions.
+
+Mon Mar 18 13:19:03 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * decl.c (grokdeclarator): Handle typedef without declarator.
+
+ * pt.c (tsubst): Handle SCOPE_REF in declarator.
+
+ * parse.y (bad_parm): Catch another case of missing `typename'.
+
+ * lex.c (yyprint): Handle TYPE_DECLs.
+
+ * decl.c (start_function): Don't try to be clever.
+
+ * lex.c: Lose compiler_error_with_decl.
+ * typeck2.c: Lose error_with_aggr_type.
+ (incomplete_type_error): Use cp_* instead of old functions.
+ (readonly_error): Likewise.
+ * typeck.c (convert_arguments): Likewise.
+ * search.c (lookup_nested_field): Likewise.
+ * method.c (make_thunk): Likewise.
+ * decl.c (grokparms): Likewise.
+ * cp-tree.h: Update.
-Mon Jan 31 12:07:30 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * tree.c (min_tree_cons): Call copy_to_permanent for the purpose
+ and value.
- * cp-tree.h: Fix documentation of LOOKUP_GLOBAL, add prototypes.
+Mon Mar 18 11:25:52 1996 Bob Manson <manson@beauty.cygnus.com>
- * error.c (args_as_string): New function (%A), like type_as_string
- except NULL_TREE -> "..."
+ * method.c (build_opfncall): When deleting a pointer to an
+ array, build a new pointer to the tree past any ARRAY_TYPE
+ nodes.
- * call.c (build_overload_call_real): Fix for new overloading.
+Mon Mar 18 10:11:46 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * decl.c (grok_op_properties): Set all of the TYPE_OVERLOADS_* flags
- here.
+ * decl.c (lookup_name_real): Initialize local var TYPE to NULL_TREE.
- * parse.y (operator_name): Instead of here.
+Fri Mar 15 11:03:57 1996 Jason Merrill <jason@yorick.cygnus.com>
- * typeck2.c (build_functional_cast): Treat a TREE_LIST as a list
- of functions.
+ * pt.c (instantiate_decl): Only call import_export_decl if at_eof
+ and ! DECL_INLINE.
- * call.c (build_overload_call_real): Support LOOKUP_SPECULATIVELY.
+ * decl.c (finish_function): Don't set nested based on
+ hack_decl_function_context.
+ * parse.y (function_try_block): Check for nested function.
+ (pending_inlines): Likewise.
- * method.c (build_opfncall): Don't need to massage return value
- any more, call build_overload_call with all flags.
+ * decl2.c (build_expr_from_tree): If a unary op already has a
+ type, just return it.
- * typeck.c (build_x_binary_op): Put back speculative call to
- build_opfncall.
- (build_x_unary_op): Ditto.
- (build_x_conditional_expr): Ditto.
+ * decl2.c (finish_prevtable_vardecl): Use ADJUST_VTABLE_LINKAGE.
-Mon Jan 31 10:00:30 1994 Mike Stump <mrs@cygnus.com>
+ * decl2.c (walk_vtables): vardecl_fn returns int; return 1 if it does.
+ (finish_file): Check the return value of walk_vtables.
+ (finish_prevtable_vardecl): Return int.
+ (finish_vtable_vardecl): Likewise.
+ (prune_vtable_vardecl): Likewise.
+ * lex.c (set_vardecl_interface_info): Likewise.
+ * cp-tree.h: Adjust return types.
- * cvt.c (build_type_conversion_1): Change call to pedwarn into
- warning, and conditionalize upon warn_cast_qual.
+ * class.c (delete_duplicate_fields_1): Don't complain about
+ duplicate nested types if they're the same type.
+ (finish_struct): Remove check for duplicate.
+ * decl2.c (grokfield): Don't check for typedef of anonymous type.
-Fri Jan 28 11:48:15 1994 Jason Merrill (jason@deneb.cygnus.com)
+Thu Mar 14 10:00:19 1996 Jason Merrill <jason@yorick.cygnus.com>
- * search.c (lookup_field): If xbasetype is a binfo, copy it to
- avoid clobbering its inheritance info.
+ * cp-tree.h: Lose SIGNATURE_GROKKING_TYPEDEF.
- * call.c (build_method_call): Don't overwrite basetype_path with
- TYPE_BINFO (inst_ptr_basetype) if they have the same type.
+ * decl.c (grokdeclarator): Lose special handling of class-level
+ typedef. Lose SIGNATURE_GROKKING_TYPEDEF. Set
+ SIGNATURE_HAS_OPAQUE_TYPEDECLS later.
- * search.c (compute_access): Fix handling of protected inheritance
- and friendship with the enclosing class.
+ * cvt.c (convert_pointer_to_real): Retain cv-quals in conversion.
- * typeck2.c (store_init_value): Allow passing of TREE_CHAIN for
- initialization of arbitrary variable.
+ * pt.c (tsubst_copy): Strip cv-quals from destructor name types.
- * typeck2.c (build_functional_cast): Only try calling a method if
- one exists.
+ * search.c (compute_access): Fix handling of anonymous union
+ members.
+ * class.c (finish_struct_anon): Propagate TREE_{PRIVATE,PROTECTED}
+ from anonymous unions to their members.
- * decl.c (grokdeclarator): Move handling of constructor syntax
- initialization into first loop for generality.
- (parmlist_is_random): Lose.
+ * typeck.c (build_x_function_call): For static member functions,
+ hand off to build_member_call.
- * lex.c (cons_up_default_function): Set TREE_PARMLIST on arguments
- to default function.
+Wed Mar 13 14:03:34 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Jan 27 19:26:51 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (build_component_ref): Handle OFFSET_REFs.
- * decl.c (grokparms): Abort if we get called with something we don't
- expect.
+ * init.c (expand_vec_init): Fix init == 0 case.
-Thu Jan 27 17:37:25 1994 Mike Stump <mrs@cygnus.com>
+Tue Mar 12 14:36:02 1996 Jason Merrill <jason@yorick.cygnus.com>
- * call.c (build_overload_call_real): Change argument complain to
- flags to match style of rest of code. Pass it down to
- build_function_call_real as necessary.
- * call.c (build_overload_call, build_overload_call_maybe): Change
- argument complain to flags to match style of rest of code.
- * cp-tree.h (build_function_call_real): Added fourth flags
- argument.
- * cvt.c (convert_to_reference): Only give warning messages, if
- LOOKUP_COMPLAIN is set.
- * typeck.c (build_x_function_call): Change simple complain
- argument to build_overload_call_maybe and build_overload_call, to
- LOOKUP_COMPLAIN to match style of rest of code.
- * typeck2.c (build_functional_cast): Ditto.
- * typeck.c (build_function_call_real): Add flags, so that we can
- not complain, if we don't want to complain. Complain about
- arguments, if we are complaining, otherwise don't.
- * typeck.c (build_function_call, build_function_call_maybe):
- Stick in flags argument.
- * typeck.c (build_x_binary_op, build_x_unary_op,
- build_x_conditional_expr, build_x_compound_expr): Follow style of
- build_x_indirect_ref, as it is more correct and more common.
+ * init.c (build_new): Pedwarn about init and array new.
+ (expand_vec_init): Handle lists, use convert_for_initialization.
-Thu Jan 27 14:36:20 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (convert_for_initialization): Pass LOOKUP_NO_CONVERSION
+ when converting to an aggregate type.
+ * cvt.c (cp_convert): Pass it through.
- * call.c (build_method_call): Don't check for being called with
- a pointer.
+ * typeck.c (build_conditional_expr): Handle user-defined
+ conversions to slightly different types.
- * decl2.c (finish_file): Don't play with DECL_CLASS_CONTEXT for the
- static initializer function.
+ * decl.c (grokdeclarator): Force an array type in a parm to be
+ permanent.
- * init.c (build_member_call): Use convert_force here, too.
+ * decl2.c (do_using_directive): Sorry.
+ (do_namespace_alias): Likewise.
+ * lex.c (real_yylex): Warn about using the `namespace' keyword.
- * search.c (compute_access): Only treat static members specially
- if they are referenced directly.
+Sun Mar 10 22:26:09 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed Jan 26 18:28:14 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * parse.y (datadef): Move call to note_list_got_semicolon up.
- * gxxint.texi (Access Control): New node.
+Fri Mar 8 11:47:26 1996 Mike Stump <mrs@cygnus.com>
- * search.c (current_scope): New function; returns whichever of
- current_class_type and current_function_decl is the most nested.
- (compute_access): Total overhaul to make it clearer and more
- correct. Don't use the cache for now; in the only situation where
- it was used before, it gained nothing. This frees up three of the
- DECL_LANG_FLAGs for possible other use!
+ * tree.c (unsave_expr): Don't unsave, UNSAVE_EXPRs.
- * cp-tree.h: #if 0 out DECL_PUBLIC & friends.
+Fri Mar 8 11:29:06 1996 Mike Stump <mrs@cygnus.com>
- * typeck.c (build_component_ref_1): Don't check DECL_PUBLIC.
+ * decl.c (cp_finish_decl): The exception regions have to be
+ nested, not overlapping. We start the exception region for a
+ decl, after it has been fully built, and all temporaries for it
+ have been cleaned up.
- * call.c (build_method_call): Use convert_force to cast `this' --
- rely on the access checking for the method itself.
+Thu Mar 7 17:46:06 1996 Mike Stump <mrs@cygnus.com>
- * init.c (is_friend): Do the nesting thing, handle types. I am
- my own friend.
- (is_friend_type): Become a shell for is_friend.
- (add_friend): Never stick in ctype.
- Why are the friendship functions in init.c, anyway?
+ * tree.c (vec_binfo_member): Don't core dump if we have no bases.
-Wed Jan 26 17:50:00 1994 Mike Stump <mrs@cygnus.com>
+Thu Mar 7 14:11:49 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cvt.c (build_type_conversion_1): Don't conditionalize call to
- pedwarn upon pedantic.
+ * tree.def: Add RETURN_INIT.
+ * pt.c (instantiate_decl): Handle RETURN_INIT.
+ * decl.c (store_return_init): Handle minimal_parse_mode.
-Wed Jan 26 17:20:46 1994 Mike Stump <mrs@cygnus.com>
+ * tree.c (cp_build_type_variant): Just return an error_mark_node.
+ * decl.c (make_typename_type): Don't try to get the file and line
+ of an identifier.
+ * typeck.c (comptypes): Handle TYPENAME_TYPE.
- * cvt.c (convert_to_reference): Add 8.4.3 checking so that one
- gets a warning if one tries to initialize a non-const & from a
- non-lvalue.
- * cvt.c (convert_to_reference): Use %P format for argument
- numbers in warnings.
+Wed Mar 6 18:47:50 1996 Per Bothner <bothner@kalessin.cygnus.com>
-Wed Jan 26 14:35:06 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (poplevel): Make sure we clear out and restore old local
+ non-VAR_DECL values by default when they go out of scope.
- * init.c (build_delete): Follow style in call.c to construct the
- virtual call to the desctructor, as that code is right. Fixes a
- problem of the compiler saying a pointer conversion is ambiguous.
+Wed Mar 6 09:57:36 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed Jan 26 11:28:14 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * method.c (build_overload_value): Use DECL_ASSEMBLER_NAME in
+ referring to addresses of variables and functions.
- * cp-tree.h (VTABLE_NAME_P): Change other occurrence of
- VTABLE_NAME_FORMAT to VTABLE_NAME.
+ * error.c (dump_expr): Support SIZEOF_EXPR.
- * *: s/visibility/access/g
+ * init.c (do_friend): Use the return value of check_classfn.
-Tue Jan 25 18:39:12 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (convert_arguments): Call complete_type.
- * typeck.c (build_modify_expr): Don't smash references if INIT_EXPR.
+ * method.c (hack_identifier): After giving an error, set value to
+ error_mark_node.
-Tue Jan 25 13:54:29 1994 Mike Stump <mrs@cygnus.com>
+Tue Mar 5 16:00:15 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * tree.c (hack_decl_function_context): Kludge around DECL_CONTEXT
+ lossage for local classes.
+ * cp-tree.h: Declare it.
+ * decl.c (lookup_name_real): Evil, painful hack for local classes.
+ (grokfndecl): Set DECL_CLASS_CONTEXT and DECL_NO_STATIC_CHAIN here.
+ Use hack_decl_function_context.
+ (grokdeclarator): Don't set DECL_NO_STATIC_CHAIN here.
+ (start_function): Use hack_decl_function_context.
+ (finish_function): Likewise.
+ * method.c (synthesize_method): Likewise.
+ * lex.c (process_next_inline): Likewise.
+ (do_pending_inlines): Likewise.
+ * decl2.c (finish_file): Unset DECL_STATIC_FUNCTION_P when we're
+ done with it.
- * init.c (build_delete): Back out Jan 17th & 18th pacthes, as
- they break libg++.
+Mon Mar 4 22:38:39 1996 Gerald Baumgartner <gb@alexander.cs.purdue.edu>
-Tue Jan 25 13:11:45 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * sig.c (build_signature_pointer_or_reference_type): Align
+ signature pointers/references on 8-byte boundaries so they can be
+ grabbed 2 words at a time on a Sparc.
- * decl.c (duplicate_decls): Fix pointer arithmetic.
+Tue Mar 5 10:21:01 1996 Jason Merrill <jason@yorick.cygnus.com>
-Mon Jan 24 15:50:06 1994 Chip Salzenberg (chip@fin.uucp)
+ * method.c (hack_identifier): Requiring a static chain is now a
+ hard error.
+ * decl.c (grokdeclarator): Set DECL_NO_STATIC_CHAIN on nested
+ functions.
- [ cp-* changes propagated from c-* changes in 940114 snapshot ]
- * cp-parse.y (maybe_attribute): Allow multiple __attribute__
- clauses on a declaration.
+Mon Mar 4 20:03:33 1996 Jason Merrill <jason@yorick.cygnus.com>
-Mon Jan 24 17:06:23 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * init.c (build_offset_ref): Call complete_type.
- * class.c (finish_struct): Do synthesize methods for anon
- structs, just not unions.
+ * decl.c (pop_from_top_level): Always pop previous_class_type.
-Mon Jan 24 13:50:13 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * parse.y: Handle multiple decls in a for-init-statement.
+ * pt.c (tsubst_expr): Likewise.
- * decl.c (xref_tag): handle anonymous nested type.
- * decl.c (globalize_nested_type): add no globalize bit check.
- * spew.c (hack_more_ids) : templated nested decl not push top
- level.
+ * pt.c (tsubst): Use tsubst_expr for the second operand of an
+ ARRAY_REF.
- * parse.y : get rid of 'goto do_components'. It is much better
- for debugging.
+ * decl.c (maybe_push_to_top_level): Don't save previous_class_type.
+ (poplevel_class): Set it here.
+ (pop_from_top_level): Pop it here if we're returning to class scope.
+ * class.c (pushclass): Don't set it here.
- * decl.c (is_anon_name): get rid of the function and use the
- macro ANON_AGGRNAME_P.
- * pt.c : ditto.
+ * decl.c (maybe_push_to_top_level): Save current_template_parms,
+ and clear it if !pseudo.
+ (pop_from_top_level): Restore it.
-Fri Jan 21 14:06:02 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (finish_file): Push the dummy each time we walk the list
+ of vtables.
- * class.c (finish_struct): Don't synthesize any methods for
- anonymous structs/unions.
+ * error.c (dump_expr): Support LOOKUP_EXPR and actually do
+ something for CAST_EXPR.
+
+Mon Feb 19 14:49:18 1996 Rusty Russell <rusty@adelaide.maptek.com.au>
- * typeck.c (build_modify_expr): Don't treat pmf's as class objects.
+ * cvt.c (cp_convert): Warn about implicit conversion of the
+ address of a function to bool, as it is always true.
-Thu Jan 20 18:56:46 1994 Jason Merrill (jason@deneb.cygnus.com)
+Fri Feb 23 23:06:01 1996 Rusty Russell <rusty@adelaide.maptek.com.au>
- * method.c (build_opfncall): Call build_indirect_ref on
- synthesized instance for operator delete.
+ * typeck.c (c_expand_return): Fix warning for local externs returned.
- * pt.c (type_unification): Don't abort if called with a list of
- types in ARGS.
+Mon Mar 4 15:03:11 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (instantiate_type): Deal with function templates.
+ * tree.c (mapcar): Propagate const and volatile properly.
-Thu Jan 20 16:55:35 1994 Jim Wilson (wilson@sphagnum.cygnus.com)
+ * typeck.c (complete_type): Be sure to instantiate the
+ MAIN_VARIANT of the type.
- * Makefile.in (CC): Default to cc not gcc.
+ * method.c (synthesize_method): Class interface hackery does not
+ apply to synthesized methods.
-Thu Jan 20 13:47:54 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Mar 4 14:05:23 1996 Jason Merrill <jason@yorick.cygnus.com>
- * typeck.c (build_modify_expr): Call constructor if appropriate.
+ * pt.c (comp_template_args): Use comptypes rather than just
+ checking for TEMPLATE_TYPE_PARM equivalence.
- * decl.c (push_to_top_level): Clear out class-level bindings cache.
+ * typeck.c (build_x_function_call): Call complete_type before
+ checking TYPE_OVERLOADS_CALL_EXPR.
-Wed Jan 19 13:51:22 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Mar 4 18:48:30 1996 Manfred Hollstein <manfred@lts.sel.alcatel.de>
- * call.c (resolve_scope_to_name): Work recursively (previously only
- looked down one level).
+ * g++.c (main): Check also for new define ALT_LIBM.
- * lex.c (do_pending_inlines): If we're still dealing with the last
- batch of inlines, don't start working on a new one.
+Fri Mar 1 13:09:33 1996 Jason Merrill <jason@yorick.cygnus.com>
- * Makefile.in (stamp-parse): Update conflict count.
- (TAGS): Fix.
+ * pt.c (instantiate_class_template): If we don't have a pattern
+ yet, that's OK.
+ (coerce_template_parms): If we see a local class, bail.
- * parse.y (explicit_instantiation): New rule; implements
- 'template A<int>' syntax (though not 'template foo(int)' yet).
- (structsp): Add explicit_instantiation.
+ * decl.c (grok_reference_init): Make sure there's a type before
+ checking its code.
-Tue Jan 18 13:53:05 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (do_function_instantiation): Avoid crashing on invalid decls.
+ (push_template_decl): Likewise.
- * class.c (finish_struct, etc.): Simplify decision to synthesize
- a destructor.
+ * parse.y (named_class_head): Set
+ CLASSTYPE_TEMPLATE_SPECIALIZATION here if we have basetypes.
- * call.c, class.c, cp-tree.h, decl.c, init.c,
- ptree.c, search.c, typeck.c, typeck2.c: Nuke
- TYPE_NEEDS_CONSTRUCTOR (change all calls to TYPE_NEEDS_CONSTRUCTING).
- * init.c (expand_aggr_init_1): Don't try non-constructor methods
- of initializing objects.
- (build_new): Don't try other methods if the constructor lookup fails.
+ * decl.c (xref_tag): Diagnose redeclaration of template
+ type-parameter name.
- * class.c (finish_base_struct): Set cant_have_default_ctor and
- cant_synth_copy_ctor properly.
- (finish_struct): Ditto.
+ * error.c (dump_type): Handle anonymous template type parms.
-Mon Jan 17 13:58:18 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * pt.c (instantiate_template): Use TYPE_MAIN_DECL instead of
+ TYPE_STUB_DECL.
+ (coerce_template_parms): Likewise.
- * typeck.c (build_modify_expr_1): #if 0 out again.
- (build_modify_expr): #if 0 out memberwise init code again.
+Thu Feb 29 16:26:01 1996 Mike Stump <mrs@cygnus.com>
- * lex.c (default_copy_constructor_body): Be const-correct.
- (default_assign_ref_body): Ditto.
+ * class.c (instantiate_type, case {ARRAY,INDIRECT}_REF,
+ case ADDR_EXPR): Don't modify rhs if a subinstantiation fails.
- * init.c (perform_member_init): Use TYPE_HAS_CONSTRUCTOR to decide
- whether or not to use it, rather than TYPE_NEEDS_CONSTRUCTING.
- (expand_aggr_init): Disable silent conversion from initializer list
- to list of args for a constructor.
+Thu Feb 29 08:20:25 1996 Jason Merrill <jason@yorick.cygnus.com>
- * class.c (base_info): Lose needs_default_ctor.
- (finish_base_struct): Ditto.
- (finish_struct): Ditto.
+ * pt.c (instantiate_template): Take the MAIN_VARIANT of the type
+ before trying to get its STUB_DECL.
+ (coerce_template_parms): Likewise.
- * decl.c (init_decl_processing): Don't turn off flag_default_inline
- just because flag_no_inline is on.
- (finish_decl): Use TYPE_HAS_CONSTRUCTOR to decide to use
- constructor.
+ * parse.y (template_type_parm): If they didn't use 'class',
+ pretend they did after giving an error.
- * class.c (finish_struct): Synthesize default ctor whenever
- allowed.
+ * pt.c (coerce_template_parms): Diagnose use of local class.
- * Makefile.in (TAGS): Don't try to run etags on cp-parse.y.
+ * decl.c (grok_reference_init): Use instantiate_type.
-Sat Jan 15 18:34:33 1994 Mike Stump <mrs@cygnus.com>
+ * error.c (dump_expr): Handle TEMPLATE_DECLs.
- * Makefile.in, configure: Handle the C++ front-end in a
- subdirectory.
- * cp-*: Move C++ front-end to cp/*.
+ * parse.y (named_class_head): Diagnose mismatching types and tags.
-Fri Jan 14 14:09:37 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (pushdecl): Type decls and class templates clash with
+ artificial type decls, not hide them.
- * cp-typeck.c (build_function_call_real): Modify to match other
- instances of taking the address of the function.
+ * decl.c (redeclaration_error_message): Diagnose redefinition of
+ templates properly.
+ (duplicate_decls): Diagnose disallowed overloads for template
+ functions, too.
- * cp-class.c (finish_struct): Set TYPE_HAS_REAL_CONSTRUCTOR to 1 if
- there are non-synthesized constructors.
- Only set TYPE_NEEDS_CONSTRUCTOR if TYPE_HAS_REAL_CONSTRUCTOR.
- Always generate copy constructor if possible.
+ * decl.c (start_decl): Call complete_type before checking for a
+ destructor.
- * cp-tree.h (lang_type): Add has_real_constructor bitfield.
- (TYPE_HAS_REAL_CONSTRUCTOR): Define.
+ * pt.c (tsubst): Use tsubst_expr on the elts of a VEC.
- * cp-lex.c (default_copy_constructor_body): Use init syntax
- for all bases.
+ * decl.c (xref_tag): A TEMPLATE_TYPE_PARM is a match.
- * cp-type2.c (store_init_value): Only give error for initializer list
- if TYPE_HAS_REAL_CONSTRUCTOR.
+Wed Feb 28 09:28:44 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Jan 13 15:38:29 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (grok_op_properties): Don't check for operator++(int) in
+ a template.
- * cp-tree.h (DECL_SYNTHESIZED): Add defn.
- (lang_decl): Add synthesized bitfield to decl_flags.
+ * tree.c (perm_manip): Return a copy of variable and function
+ decls with external linkage.
- * cp-lex.c (cons_up_default_function): Use DECL_SYNTHESIZED to mark
- artificial methods, rather than a line # of 0.
+ * tree.def: Change some of the min tree codes to type "1".
+ * pt.c (uses_template_parms): Handle 'e's, return 1 for LOOKUP_EXPRs.
+ * method.c (build_overload_int): Emit something arbitrary for
+ anything but an INTEGER_CST if we're in a template.
-Fri Jan 14 18:25:29 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * decl.c (cp_finish_decl): Call complete_type before deciding
+ whether or not to lay out the decl.
- * cp-decl (xref_tag): fix a bug in conflict type.
- * cp-parse.y : add SCOPED_NAME for uninstantiated template nested
- type reference.
- * cp-spew.c (yylex) : generated SCOPED_NAME token.
- * cp-lex.c (yyprint): handle SCOPED_NAME.
+ * lex.c (do_identifier): Check for DECL_INITIAL before using it.
-Fri Jan 14 17:00:29 1994 Mike Stump <mrs@cygnus.com>
+Tue Feb 27 16:35:32 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-decl.c (pushdecl): Revert patch from Jan 11 19:33:03, as it is
- not right.
+ * typeck2.c (build_x_arrow): Call complete_type.
-Thu Jan 13 14:00:35 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * pt.c (add_pending_template): Broken out.
+ (lookup_template_class): If -fexternal-templates, call it for all
+ the methods of implemented types.
+ (instantiate_class_template): Instead of instantiating them here.
+ (instantiate_decl): Handle -fexternal-templates earlier.
- * cp-decl2.c (grok_x_components): fix a bug that enum type does not
- have type_flags.
+Tue Feb 27 15:51:32 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Thu Jan 13 11:39:34 1994 Mike Stump <mrs@cygnus.com>
+ * search.c, lex.c, decl.c, class.c, cp-tree.h: Don't wrap the
+ memoized lookup stuff inside GATHER_STATISTICS.
- Ensure that all vtable pointers are initialized with all the right
- values.
+Tue Feb 27 10:38:08 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-class.c (is_normal): Changed to reflect new meaning of
- CLASSTYPE_VFIELD_PARENT.
- * cp-class.c (maybe_fixup_vptrs): Use of
- CLASSTYPE_NEEDS_VIRTUAL_REINIT here is misguided. Use
- BINFO_MODIFIED instead.
- * cp-class.c (finish_struct): Changed to reflect new meaning of
- CLASSTYPE_VFIELD_PARENT.
- * cp-decl.c (get_binfo_from_vfield): Removed, unneeded now.
- * cp-decl.c (finish_function): Use init_vtbl_ptrs, instead of open
- coding it here.
- * cp-init.c (init_vfields): Changed name to init_vtbl_ptrs, and
- re-implement.
- * cp-init.c (emit_base_init): Use new name init_vtbl_ptrs.
- * cp-tree.h (vfield_parent): Changed to integer.
- * cp-tree.h (CLASSTYPE_VFIELD_PARENT): Changed docs to reflect new
- meaning.
- * cp-tree.h (init_vtbl_ptrs): Added init_vtbl_ptrs.
+ * decl.c (start_decl): Complain about array of incomplete type
+ here.
+ (grokdeclarator): Not here.
-Wed Jan 12 18:24:16 1994 Kung Hsu (kung@mexican.cygnus.com)
+ * parse.y (template_parm): Expand full_parm inline so we can set
+ the rule's precedence.
- * cp-decl.c (xref_tag): re-implement globalize nested type.
- * cp-decl2.c (grok_x_components): ditto.
- * cp-parse.y: ditto.
- * cp-tree.h (lang_type): add no_globalize bit in type_flags.
+ * pt.c (tsubst_expr): If we're in a template, just do tsubst_copy.
+ (tsubst): tsubst_expr the DECL_INITIAL of FIELD_DECLs.
+ * decl2.c (grokbitfield): Don't check for integer constant here.
+ * class.c (finish_struct_1): Check here.
-Wed Jan 12 14:08:09 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (define_label): Make the min decl go on permanent_obstack.
- * cp-decl.c (grokdeclarator): Don't set TREE_PUBLIC on friend
- decls with a definition attached.
+ * pt.c (unify): Don't handle CONST_DECLs.
+ (uses_template_parms): Don't check DECL_INITIAL on a CONST_DECL.
+ (tsubst_copy): Likewise.
- * cp-typeck.c (build_modify_expr): Undo previous change in the case
- of INIT_EXPRs.
+ * lex.c (do_identifier): Do pull the DECL_INITIAL out of a
+ CONST_DECL for a template parm.
-Tue Jan 11 19:33:03 1994 Jason Merrill (jason@deneb.cygnus.com)
+Mon Feb 26 12:48:18 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-typeck.c (build_modify_expr): Replace code for generating
- assignment semantics for classes with an error.
- (build_modify_expr_1): #if 0 out.
+ * decl.c (grokdeclarator): Complain about array of incomplete type
+ here.
+ (start_decl_1): Not here.
- * cp-decl.c (pushdecl): Patch bogus design of pushdecl
- behavior for overloaded functions (it doesn't push anything).
+ * pt.c (tsubst): Handle pointer-to-function declarators.
- * cp-class.c (finish_struct): When generating default op=,
- set TYPE_HAS_ASSIGNMENT.
+ * method.c (hack_identifier): If pedantic, diagnose local class
+ methods that require a static chain.
-Mon Jan 10 18:48:06 1994 Mike Stump <mrs@cygnus.com>
+ * decl.c (grok_op_properties): No longer static.
+ * cp-tree.h: Declare it.
+ * pt.c (tsubst): Call it for operators.
+ Use tsubst_copy for TREE_VECs.
- * cp-cvt.c (convert): Make {double, clashing enum} -> enum
- invalid.
- * cp-typeck.c (convert_for_assignment): Simplify.
- * cp-decl2.c (warn_enum_clash): Removed.
- * invoke.texi (-Wenum-clash): Removed.
- * toplev.c (-Wenum-clash): Removed.
+ * parse.y (template_arg): The expr has precedence like '>'.
-Mon Jan 10 17:48:37 1994 Kung Hsu (kung@mexican.cygnus.com)
+Fri Feb 23 14:51:52 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-decl.c (finish_decl): fix incorrect popclass call.
+ * pt.c (coerce_template_parms): Don't coerce an expression using
+ template parms.
+ (uses_template_parms): Also check DECL_INITIAL in CONST_DECLs.
+ (tsubst): Don't use build_index_2_type if the max_value uses template
+ parms.
+ * method.c (build_overload_int): Emit something arbitrary for an
+ expression using template parms.
+
+ * parse.y (template_close_bracket): New non-terminal to catch use
+ of '>>' instead of '> >' in template class names.
+ (template_type): Use it.
+ * Makefile.in (CONFLICTS): Causes one more r/r conflict.
+
+ * tree.def: Add CAST_EXPR.
+ * typeck2.c (build_functional_cast): Use CAST_EXPR instead of
+ CONVERT_EXPR for minimal_parse_mode.
+ * typeck.c (build_c_cast): Likewise.
+ * pt.c (tsubst_copy): Likewise.
+ * decl2.c (build_expr_from_tree): Likewise.
+ * error.c (dump_expr): Likewise.
+
+Fri Feb 23 10:36:46 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * except.c (SetTerminate, SetUnexpected): Put back global vars.
+ (init_exception_processing): Put back decl/init of
+ set_unexpected_fndecl and set_terminate_fndecl, needed to get the
+ fns from libstdc++.
+
+ * decl.c (struct binding_level): Delete ACCEPT_ANY bitfield.
+ (declare_uninstantiated_type_level, uninstantiated_type_level_p):
+ Delete unused fns.
+ * cp-tree.h (declare_uninstantiated_type_level,
+ uninstantiated_type_level_p): Delete prototypes.
+
+Thu Feb 22 19:36:15 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * pt.c (tsubst_expr): Add default return.
+
+Thu Feb 22 16:47:24 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * error.c (fndecl_as_string): Delete unused arg CNAME.
+ * sig.c (build_signature_table_constructor,
+ build_signature_method_call): Fix calls.
+
+ * class.c (the_null_vtable_entry): Delete var definition.
+ (init_class_processing): Delete tree the_null_vtable_entry init.
+ * decl.c (no_print_{functions, builtins}): Declare as static.
+ (__tp_desc_type_node): #if 0 var definition.
+ (init_type_desc): #if 0 init of __tp_desc_type_node.
+ (vb_off_identifier): Move var decl into init_decl_processing.
+ (current_function_assigns_this): Declare as static.
+ (int_ftype_ptr_ptr_int, void_ftype_ptr_int_int): Delete var decls.
+ (init_decl_processing): Delete init of void_ftype_ptr_ptr_int.
+ Move decls of string_ftype_ptr_ptr and int_ftype_string_string here.
+ * decl2.c (delete_sanity): Delete definition/mod of local var ELT_SIZE.
+ * init.c (BI_header_type, BI_header_size): Declare as static.
+ * pt.c (template_classes): Delete unused var.
+ (add_pending_template): Delete decl for non-existent fn.
+ (lookup_template_class): Delete vars CODE and TAG_CODE.
+ (instantiate_template): Delete unused var TARGS.
+ * cp-tree.h (vb_off_identifier, current_function_assigns_this):
+ Delete decls.
+ (__tp_desc_type_node): #if 0 var decl.
+ (fndecl_as_string): Fix prototype.
+
+Thu Feb 22 15:56:19 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * tree.def: Add GOTO_STMT.
+ * pt.c (tsubst_expr): Support goto and labels.
+ * decl.c (define_label): Support minimal parsing.
+ * parse.y (simple_stmt): Likewise.
+
+Thu Feb 22 15:30:12 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * xref.c (GNU_xref_member): Only define/set var I if
+ XREF_SHORT_MEMBER_NAMES is defined, to match when it's actually
+ used.
+ (GNU_xref_end_scope): Delete unused fifth arg TRNS.
+ (GNU_xref_end): Fix call.
+ * decl.c (poplevel, poplevel_class, finish_method): Fix calls.
+ * cp-tree.h (GNU_xref_end_scope): Fix prototype.
+
+ * tree.c (build_exception_variant): Delete unused vars I, A, T,
+ T2, and CNAME.
+ (layout_vbasetypes): Delete unused var NONVIRTUAL_VAR_SIZE.
+ (mapcar): Delete unused var CODE.
+ (build_cplus_new): Delete unused arg WITH_CLEANUP_P.
+ (break_out_cleanups): Fix call.
+ (bot_manip): Likewise.
+ * call.c (build_method_call): Likewise.
+ * cvt.c (build_up_reference, convert_to_reference, cp_convert):
+ Likewise.
+ * typeck.c (unary_complex_lvalue, build_modify_expr,
+ convert_for_initialization): Likewise.
+ * typeck2.c (build_functional_cast): Likewise.
+ * cp-tree.h (build_cplus_new): Fix prototype.
+
+ * repo.c (open_repo_file): Delete unused var Q.
+ (repo_compile_flags, repo_template_declared,
+ repo_template_defined, repo_class_defined, repo_inline_used,
+ repo_vtable_used, repo_tinfo_used): #if 0 unused fns.
+ (repo_get_id, repo_vtable_used): Declare as static.
+ * cp-tree.h (mark_{decl,class}_instantiated, finish_repo): Add
+ prototypes.
+
+Thu Feb 22 14:53:35 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * parse.y (pending_inlines): Add function_try_block case.
+
+ * pt.c (unify): Fix for template const parms.
+
+Thu Feb 22 13:24:15 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * lex.c (extract_interface_info): Delete forward decl.
+ (default_copy_constructor_body, default_assign_ref_body): Delete
+ decls for non-existent functions.
+ (synth_firstobj, inline_text_firstobjs): Delete unused vars.
+ (init_lex): Delete setting them.
+ (cons_up_default_function): Delete unused vars FUNC_BUF,
+ FUNC_LEN, and COMPLEX. Delete code setting COMPLEX. Delete old
+ #if 0'd synth code.
+ (toplevel, expression_obstack): Delete unused extern decls.
+ (tree_node_kind): Delete unused enum.
+ (tree_node_counts, tree_node_sizes): Wrap with #ifdef
+ GATHER_STATISTICS.
+ (tree_node_kind_names): Delete unused extern decl.
+ (synth_obstack): Delete unused var.
+ (init_lex): Don't set it.
+ (init_parse): Add decl before use.
+ (reduce_count): Only define #ifdef GATHER_STATISTICS && REDUCE_LENGTH.
+ (current_unit_{name, language}): Delete unused vars.
+ (check_newline): Don't bother setting them, just accept the #pragma.
+ * cp-tree.h (init_repo, peek_yylex): Add prototypes.
+ (current_unit_{name, language}): Delete decls.
+
+ * search.c: Wrap all of the memoized functions, macros, and
+ variables inside #ifdef GATHER_STATISTICS.
+ (lookup_field, lookup_fnfields): Likewise.
+ (init_search_processing): Likewise.
+ (reinit_search_statistics): Wrap whole function.
+ * lex.c (reinit_lang_specific): Wrap call to reinit_search_statistics.
+
+ * decl.c (finish_function): Only call pop_memoized_context if
+ GATHER_STATISTICS is defined.
+ (start_function): Likewise for push_memoized_context.
+ * class.c (pushclass, popclass): Likewise.
+
+ * cp-tree.h (CLASSTYPE_MTABLE_ENTRY): Move definition from here...
+ * search.c (CLASSTYPE_MTABLE_ENTRY): ... to here.
+
+ * cvt.c (cp_convert): Delete unused local var FORM.
+ * cp-tree.h (can_convert, can_convert_arg, real_lvalue_p): Add
+ prototypes.
+
+Thu Feb 22 13:19:44 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * pt.c (do_poplevel): Oops; really return what we get from
+ poplevel this time.
+
+Thu Feb 22 11:41:44 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * cp-tree.h (is_aggr_type): Add prototype.
+
+ * cp-tree.h ({push,pop}_cp_function_context): Add decls.
+ * method.c ({push,pop}_cp_function_context): Delete decls.
+ * except.c (start_eh_unwinder, end_eh_unwinder): Declare as void.
+ (SetUnexpected, SetTerminate): Delete unused vars.
+ (init_exception_processing): Don't set SetUnexpected or
+ SetTerminate. Don't set SET_UNEXPECTED_FNDECL or SET_TERMINATE_FNDECL.
+ (output_exception_table_entry): Delete unused array LABEL.
+ (expand_internal_throw): Delete unused var PARAMS.
+ (expand_start_catch_block): Delete unused var CLEANUP.
+ (emit_exception_table): Delete unused var EH_NODE_DECL.
+ (expand_builtin_throw): Delete unused vars UNWIND_AND_THROW and
+ GOTO_UNWIND_AND_THROW. Don't set them.
+ (end_eh_unwinder): Add top decl.
+ (pop_rtl_from_perm): Delete unused decl of PERMANENT_OBSTACK.
+ (exception_section, push_rtl_perm, do_function_call,
+ lang_interim_eh, push_eh_cleanup, eh_outer_context,
+ expand_end_eh_spec, end_eh_unwinder): Declare as static.
+ (saved_pc, saved_throw_type, saved_throw_value, saved_cleanup,
+ throw_used): Likewise.
+ * cp-tree.h (expand_end_eh_spec): Delete prototype.
+
+ * search.c (dfs_mark, dfs_mark_vtable_path,
+ dfs_unmark_vtable_path, dfs_mark_new_vtable,
+ dfs_unmark_new_vtable, dfs_clear_search_slot,
+ dfs_search_slot_nonempty_p, bfs_markedp, bfs_unmarkedp,
+ bfs_marked_vtable_pathp, bfs_unmarked_vtable_pathp,
+ bfs_marked_new_vtablep, bfs_unmarked_new_vtablep): #if 0 unused
+ functions.
+ (n_fields_searched, n_calls_lookup_field, n_calls_lookup_field_1,
+ n_calls_lookup_fnfields, n_calls_lookup_fnfields_1,
+ n_calls_get_base_type, n_outer_fields_searched, n_contexts_saved):
+ Only define #ifdef GATHER_STATISTICS.
+ (reinit_search_statistics): Only init some vars if GATHER_STATISTICS
+ is defined.
+ (vbase_decl): Delete var definition.
+ (init_search): Delete old decl.
+ (init_vbase_pointers): Delete building of VBASE_DECL, since it's
+ never actually used.
+ (expand_indirect_vtbls_init): Delete init of VBASE_DECL.
+ (get_base_distance_recursive): Delete unused fourth arg
+ BASETYPE_PATH. Fix call .
+ (get_base_distance): Fix call.
+ (push_class_decls): Delete unused var ID.
+ (make_memoized_table_entry): Declare as static.
+ (breadth_first_search): Declare as static.
+ (tree_has_any_destructor_p): Declare as static.
+ (pop_class_decls): Delete unused arg pop_class_decls.
+ * class.c (popclass): Fix call to pop_class_decls.
+ * cp-tree.h (make_memoized_table_entry, breadth_first_search,
+ tree_has_any_destructor_p): Delete prototypes.
+
+ * rtti.c (build_ptmf_desc): Delete unused arg TYPE.
+ (build_t_desc): Fix call. Delete unused vars ELEMS and TT.
+ (build_dynamic_cast): Delete unused local vars TMP1 and RETVAL.
+ (build_user_desc): Delete unused var T.
+ (build_class_desc): Delete unused vars T and OFF.
+ (build_t_desc): Delete unused var NAME_STRING.
+ (build_headof): Make static.
+ (get_bad_cast_node): Likewise.
+ (get_def_to_follow): Likewise.
+ * cp-tree.h (init_type_desc): Add prototype.
+ (build_headof): Remove prototype.
+
+Thu Feb 22 00:54:22 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * pt.c (tsubst): Only look for matching decls at file scope for
+ non-member functions.
- * cp-decl.c (is_anon_name): new function, check whether the name
- is anonymous name generated by compiler.
- * cp-decl.c (grokdeclarator): allow nested SCOPE_REF
- * cp-spew.c (hack_more_ids): handle nested type in template.
- * cp-parse.y : handle nested type reference in uninstantiated
- template.
- * cp-call.c (build_method_call): handle uninstantiated template
- case.
- * cp-pt.c (search_nested_type_in_tmpl): new function, search nested
- type in template.
- * cp-pt.c (lookup_nested_type_by_name): new function, lookup nested
- type by name.
- * cp-pt.c (tsubst): handle nested type search by name.
+ * call.c (build_scoped_method_call): Handle scoped destructor
+ calls in templates.
-Mon Jan 10 14:32:18 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (*_top_level): Also save previous_class_values.
- * cp-init.c (build_member_call): Propagate qualifiers to new type.
+ * pt.c (tsubst_expr): Support do {} while loops.
+ * parse.y (simple_stmt): Likewise.
+ * tree.def: Likewise.
- * cp-call.c (build_method_call): Count functions the new way.
+ * method.c (build_overload_identifier): For a class nested in a
+ template class, don't mangle in the template parms from our
+ context.
-Fri Jan 7 19:03:26 1994 Jason Merrill (jason@deneb.cygnus.com)
+ * lex.c, cp-tree.h: Remove support for template instantiations in
+ the pending_inlines code.
+ * pt.c: Remove dead functions and unused arguments.
+ (uses_template_parms): TYPENAME_TYPEs always use template parms.
+ * parse.y: Stop passing anything to end_template_decl.
+ * tree.c (print_lang_statistics): Only print tinst info #ifdef
+ GATHER_STATISTICS.
+
+Wed Feb 21 16:57:33 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * init.c (expand_recursive_init{,_1}): Delete decls.
+ (sort_member_init): Delete unused var INIT.
+ (emit_base_init): Delete unused var X.
+ (build_offset_ref): Delete unused var CNAME.
+ (sort_member_init): Delete unused var FIELDS_TO_UNMARK.
+ (emit_base_init): Delete unused local var BASE. Delete extern
+ decl of IN_CHARGE_IDENTIFIER.
+ (build_delete): Delete unused local var VIRTUAL_SIZE.
+
+ * init.c (build_vec_delete): Delete unused third arg ELT_SIZE.
+ (build_delete): Fix call.
+ * decl2.c (delete_sanity): Likewise.
+ * cp-tree.h (build_vec_delete): Update prototype.
+
+ * typeck.c (common_base_type): Delete unused var TMP.
+ (build_binary_op): Delete local var ARGS_SAVE.
+ (build_array_ref): Delete unused var ITYPE.
+ (c_expand_return): Delete unused var USE_TEMP.
+
+ * typeck.c (compexcepttypes): Delete unused arg STRICT.
+ (comptypes): Fix calls.
+ * decl.c (duplicate_decls): Likewise.
+ * cp-tree.h (compexcepttypes): Delete extra arg.
+
+ * decl2.c (check_classfn): Delete unused second arg CNAME.
+ * decl.c (start_decl, grokfndecl): Fix calls.
+ * init.c (do_friend): Likewise.
+ * cp-tree.h (check_classfn): Update prototype.
+
+ * cp-tree.h (signature_error, import_export_vtable,
+ append_signature_fields, id_in_current_class, mark_used,
+ copy_assignment_arg_p): Add decls.
+ * decl2.c (mark_used): Delete decl.
+
+ * class.c (n_*): Wrap with #ifdef GATHER_STATISTICS.
+
+ * class.c (get_vtable_entry): Diable unused function.
+ (doing_hard_virtuals): Delete unused static global var.
+ (finish_struct_1): Don't init DOING_HARD_VIRTUALS.
+ (prepare_fresh_vtable): Delete unused vars PATH and RESULT.
+ (overrides): Delete unused vars RETTYPE and BASE_RETTYPE.
+ (modify_one_vtable): Delete unused var OLD_RTTI.
+ (finish_struct_anon): Delete unused vars OFFSET and X.
+ (finish_struct_bits): Delete unused var METHOD_VEC.
+ (get_basefndecls): Delete unused var PURPOSE. Delete unused
+ for-scope local variable METHODS.
+
+ * call.c (user_harshness): Delete unused/unneeded arg PARM.
+ (ideal_candidate): Delete unused args BASETYPE and PARMS.
+ (build_method_call): Delete unused args passed into ideal_candidate.
+ (build_overload_call_real): Likewise. Delete unused var OVERLOAD_NAME.
+ * cp-tree.h (synthesize_method): Add decl.
+
+ * decl.c (note_level_for_for): Give void return type.
+ (pushdecl_nonclass_level): Likewise.
+ (finish_function): Delete unused vars VFIELDS and ALLOCATED_THIS.
+ (poplevel): Delete unused var IMPLICIT_TRY_BLOCK.
+ (suspend_binding_level): Delete unused var LEVEL.
+ (duplicate_decls): Delete unused var CTYPE.
+ (duplicate_decls): Delete unused var PREVIOUS_C_DECL.
+ (init_decl_processing): Delete unused vars FLOAT_ENDLINK and
+ PTR_ENDLINK.
+ (grokdeclarator): Delete unused var C.
+ (grokdeclarator): Delete unused var SIZE_VARIES.
+ (grokparms): Delete unused var SAW_VOID.
+ (start_function): Delete unused var OLDDECL.
+ (cplus_expand_expr_stmt): Delete unused var
+ REMOVE_IMPLICIT_IMMEDIATELY.
+
+ * cp-tree.h (pushdecl_nonclass_level): Fix prototype.
+
+ * Makefile.in (CONFLICTS): Update to 12 shift/reduce.
+
+Wed Feb 21 00:06:17 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * tree.c (build_min): Set TREE_COMPLEXITY to lineno.
+ (build_min_nt): Likewise.
+ * pt.c (do_pushlevel): Emit line note.
+ (do_poplevel): Return what we get from poplevel.
+ (tsubst_expr): Set lineno from TREE_COMPLEXITY in stmt nodes.
+ * parse.y: Use do_pushlevel and do_poplevel.
+ * cp-tree.h: Declare do_poplevel.
+
+ * cp-tree.h: Declare at_eof.
+ * decl.c (cp_finish_decl): Pass it to rest_of_decl_compilation.
+ * decl2.c (import_export_decl): Renamed from import_export_inline.
+ (finish_file): Call it to do interface handling for statics.
+ * pt.c (tsubst_copy): Call mark_used on variables and functions
+ used here.
- * cp-decl.c (pushtag): Set DECL_ASSEMBLER_NAME for nested classes,
- too.
+ * decl2.c (finish_file): Don't emit statics we can't generate.
+ * pt.c (instantiate_decl): Don't set interface on instantiations
+ we can't generate.
-Tue Jan 4 16:45:51 1994 Kung Hsu (kung@cirdan.cygnus.com)
+ * cp-tree.h (struct tinst_level): Change 'classname' to 'decl'.
+ * tree.c (print_lang_statistics): Print max template depth.
+ * pt.c (push_tinst_level): Dump entire instantiation context.
+ (instantiate_class_template): Use it and pop_tinst_level.
+ (instantiate_decl): Likewise.
- * cp-parse.y: change to handle whether to globalize nested class.
- * cp-decl.c(xref_tag, maybe_globalize_type): Ditto.
+ * call.c class.c cp-tree.h decl.c decl2.c error.c lex.c method.c
+ pt.c ptree.c tree.def: Remove all traces of UNINSTANTIATED_P_TYPE.
-Mon Jan 3 22:22:32 1994 Gerald Baumgartner (gb@cygnus.com)
+Tue Feb 20 18:21:51 1996 Jason Merrill <jason@yorick.cygnus.com>
- * Makefile.in cp-call.c cp-class.c cp-cvt.c cp-decl.c cp-decl2.c
- cp-error.c cp-init.c cp-lex.c cp-lex.h cp-method.c cp-parse.y
- cp-spew.c cp-tree.c cp-tree.h cp-type2.c cp-typeck.c cp-xref.c
- gplus.gperf toplev.c: Incorporated C++ signature extension.
- * cp-sig.c: New file, contains most of signature processing.
- * cp-hash.h: Regenerated from gplus.gperf.
+ * call.c class.c cp-tree.h cvt.c decl.c decl2.c error.c expr.c
+ init.c lex.c method.c parse.y pt.c repo.c search.c spew.c tree.c
+ tree.def typeck.c typeck2.c xref.c: Massive, systemic changes for
+ the new template implementation.
- * gcc.1 g++.1: Added explanation for the `-fhandle-signatures'
- and `-fno-handle-signatures' command line flags.
+Tue Feb 20 17:14:29 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * gcc.texi: Changed the last-modification date.
- * invoke.texi: Added `-fhandle-signatures' in the list of
- C++ language options. Added explanation for this option.
+ * decl2.c (check_cp_case_value): Use STRIP_TYPE_NOPS.
-Tue Dec 28 21:10:03 1993 Mike Stump <mrs@cygnus.com>
+Thu Feb 15 18:44:42 1996 Mike Stump <mrs@cygnus.com>
- * cp-init.c (expand_vec_init): Remove comptypes test, as it is too
- harsh here.
+ * decl.c (cp_finish_decl): Delay emitting the debug information for
+ a typedef that has been installed as the canonical typedef, if the
+ type has not yet been defined.
-Tue Dec 28 13:42:22 1993 Mike Stump <mrs@cygnus.com>
+Thu Feb 15 09:39:08 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-pt.c (do_pending_expansions): Decide to expand a template
- member function, based upon it's class type, not the class type of
- the first place it was declared.
+ * decl2.c (grokfield): Still call pop_nested_class for access decls.
-Tue Dec 28 05:42:31 1993 Mike Stump <mrs@cygnus.com>
+Wed Feb 14 17:30:04 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-class.c (is_normal): New routine, use to determine when the
- given binfo is the normal one. (The one that should have the simple
- vtable name.)
- * cp-class.c (modify_other_vtable_entries): Use DECL_ASSEMBLER_NAME
- to check if two fndecls are `the same'. Sometimes this routine can
- modify the main vtable, and normal should be 1, in that case, so use
- is_normal() to determine if this is the main vtable for the class.
- Don't recurse down virtual bases, as they are shared, and we take
- care of them elsewhere.
- * cp-class.c (modify_vtable_entries): If we have already updated the
- vtable with the new virtual, don't do it again.
- * cp-class.c (finish_struct): Set CLASSTYPE_VFIELD_PARENT as
- appropriate. Do virtual function overriding in virtual bases, after
- normal overriding, so that the base function list in DECL_VINDEX is
- not overridden, before we have a chance to run through the list.
- Use DECL_ASSEMBLER_NAME to check if two fndecls are `the same'.
- Make sure we pass the right address into modify_vtable_entries.
- * cp-tree.h (CLASSTYPE_VFIELD_PARENT): New field to indicate which
- binfo is the one that has the vtable that we based our vtable on.
+ * decl.c (lookup_label): Call label_rtx.
-Fri Dec 24 09:40:52 1993 Michael Tiemann (tiemann@blues.cygnus.com)
+ * decl.c (make_binding_level): New function.
+ (pushlevel, pushlevel_class): Call it instead of explicit
+ duplicate calls to xmalloc.
- * cp-typeck.c (c_expand_start_case): Use default_conversion to
- convert expression from reference type if necessary.
+ * decl.c (init_decl_processing): Delete useless build_pointer_type
+ call.
-Wed Dec 22 17:58:43 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (float_ftype_float, ldouble_ftype_ldouble): Add definitions.
+ (sizet_ftype_string): Delete variable.
+ (init_decl_processing): Add built-in functions fabsf, fabsl,
+ sqrtf, sqrtl, sinf, sin, sinl, cosf, cos, cosl. New local
+ variable strlen_ftype, used for strlen.
- * cp-typeck.c (build_unary_op): Make sure that it's a TREE_LIST before
- trying to read its TREE_VALUE.
+Wed Feb 14 16:21:25 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-class.c (finish_struct_methods): Clear DECL_IN_AGGR_P here.
- (finish_struct): Instead of here.
+ * decl.c (push_to_top_level): Start from current_binding_level
+ again for now; the stl hacks depend on g++ being broken in this
+ way, and it'll be fixed in the template rewrite.
-Tue Dec 21 14:34:25 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * tree.def: Add USING_DECL.
+ * decl2.c (do_class_using_decl): Implement.
+ (grokfield): Pass access decls off to do_class_using_decl instead of
+ grokdeclarator.
+ * error.c (dump_decl): Handle USING_DECLs.
+ * decl.c (grokdeclarator): Remove code for handling access decls.
+ * class.c (finish_struct_1): Adjust accordingly, treat using-decls
+ as access decls for now.
+ (finish_struct): Don't check USING_DECLs for other uses of the name.
- * cp-tree.c (list_hash_lookup_or_cons): Make sure the type doesn't
- have TYPE_PTRMEMFUNC_P set before we try to build its
- CLASSTYPE_ID_AS_LIST.
- (get_decl_list): Likewise, when trying to read it.
+ * search.c (get_matching_virtual): Use cp_error_at.
- * cp-tree.h (VTABLE_NAME): No def with NO_{DOLLAR,DOT} defined.
- (VTABLE_NAME_P): Use it instead of VTABLE_NAME_FORMAT.
+Wed Feb 14 10:36:58 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Mon Dec 20 13:35:03 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * typeck.c (comptypes): Default COMP_TYPE_ATTRIBUTES to 1, to
+ match c-typeck.c.
+ (self_promoting_args_p): Move the check that TYPE is non-nil
+ before trying to look at its main variant.
+ (unsigned_type, signed_type): Add checking of DI/SI/HI/QI nodes.
- * cp-typeck.c (rationalize_conditional_expr): New function.
- (unary_complex_lvalue): Use it.
- (build_modify_expr): Use it, since trying to do an ADDR_EXPR of it
- with build_unary_op won't cut it. Don't wrap the COND_EXPR with a
- SAVE_EXPR either.
+ * cp-tree.h (DECL_WAITING_FRIENDS, SET_DECL_WAITING_FRIENDS):
+ Delete macros.
+ * init.c (xref_friend, embrace_waiting_friends): Delete functions.
+ (do_friend): Delete call to xref_friend.
+ * class.c (finish_struct_1): Delete call to embrace_waiting_friends.
- * cp-decl2.c (explicit_warn_return_type): Deleted variable.
- (lang_decode_option): Set warn_return_type, not explicit_*, for
- -Wreturn-type and -Wall. This is what rest_of_compilation uses to
- decide if it should go into jump_optimize or not.
- * cp-tree.h (explicit_warn_return_type): Deleted.
- * cp-decl.c (grokdeclarator): Use warn_return_type, not explicit_*.
- (finish_function): Also complain about no return in a non-void fn if
- we're being pedantic (don't rely on use of -Wreturn-type).
+ * typeck.c (convert_sequence): #if 0 unused function.
-Fri Dec 17 15:45:46 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * cp-tree.h (DECL_IN_MEMORY_P): New macro w/ the check that used to
+ be in decl_in_memory_p.
+ (decl_in_memory_p): Delete decl.
+ * expr.c (decl_in_memory_p): Delete fn.
+ * typeck.c (mark_addressable): Use DECL_IN_MEMORY_P.
- * cp-decl.c (grokdeclarator): Forbid declaration of a function as
- static if it's being done inside another function.
+ * decl.c (cp_finish_decl): Use DECL_IN_MEMORY_P.
- * cp-search.c (compute_visibility): Check for friendship both ways.
+Tue Feb 13 12:51:21 1996 Jason Merrill <jason@yorick.cygnus.com>
-Fri Dec 17 14:28:25 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * class.c (finish_struct_1): Check for a pure-specifier on a
+ non-virtual function here.
- * cp-cvt.c (build_default_binary_type_conversion): Make error
- messages more helpful.
+ * decl2.c (grok_function_init): Don't check whether the function
+ is virtual here.
+ (grokfield): Don't call check_for_override here.
- * cp-error.c (op_as_string): New function, returns "operator =="
- given EQ_EXPR or suchlike.
+ * decl.c (push_to_top_level): Start from inner_binding_level,
+ check class_shadowed in class levels.
-Fri Dec 17 13:28:11 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+Mon Feb 12 17:46:59 1996 Mike Stump <mrs@cygnus.com>
- * cp-call.c (print_n_candidates): New function.
- (build_overload_call_real): Use it when we complain about a call
- being ambiguous.
+ * decl.c (resume_level): Ignore things that don't have names, instead
+ of core dumping.
-Fri Dec 17 12:41:17 1993 Jason Merrill (jason@deneb.cygnus.com)
+Mon Feb 12 15:47:44 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-call.c (build_method_call): Fix checking for static call
- context.
+ * decl2.c (grokfield): Set DECL_VINDEX properly for FUNCTION_DECLs.
- * cp-method.c (build_opfncall): Call build_indirect_ref on argument
- to operator new.
+Sat Feb 10 17:59:45 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-init.c (build_new): Don't mess with rval when building
- indirect ref.
+ * class.c (finish_struct_1): Set DECL_VINDEX properly on a
+ synthesized dtor.
-Thu Dec 16 16:48:05 1993 Kung Hsu (kung@cirdan.cygnus.com)
+ * parse.y (complete_type_name): Bind global_scope earlier.
+ (complex_type_name): Likewise.
+ (qualified_type_name): Remove.
- * cp-lex.c (default_assign_ref_body): add check when TYPE_NESTED_
- NAME(type) may not be exist. It's not a problem for old compiler.
+Thu Feb 8 15:15:14 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Dec 16 14:46:06 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * decl.c (grokfndecl): Move code that looks for virtuals in base
+ classes...
+ * class.c (check_for_override): ... to a new function.
+ (finish_struct_1): Call it.
- * cp-tree.h (CLASSTYPE_ALTERS_VISIBILITIES_P): Delete macro, it's
- never used for anything.
- (struct lang_type, member type_flags): Delete field
- `alters_visibility', and up `dummy' by 1.
- * cp-class.c (finish_base_struct): Delete code that copies the
- setting of CLASSTYPE_ALTERS_VISIBILITIES_P.
- (finish_struct): Delete code that sets it.
+ * cp-tree.h: Declare warn_sign_compare.
-Thu Dec 16 14:44:39 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * typeck.c (build_binary_op_nodefault): Check warn_sign_compare
+ rather than extra_warnings to decide whether to warn about
+ comparison of signed and unsigned.
- * cp-decl.c, cp-init.c, cp-typeck.c: Fix arguments to
- build_method_call that I messed up before.
+ * decl2.c (lang_decode_option): Handle warn_sign_compare. -Wall
+ implies -Wsign-compare. -Wall doesn't imply -W.
- * cp-search.c (get_base_distance): If protect > 1, allow immediate
- private base.
+Wed Feb 7 15:27:57 1996 Mike Stump <mrs@cygnus.com>
- * cp-class.c (finish_base_struct): Set cant_synth_* correctly.
- (finish_struct): Ditto. Well, nigh-correctly; it won't deal
- properly with the case where a class contains an object of an
- ambiguous base class which has a protected op=. Should be fixed
- when the access control code gets overhauled.
- (finish_struct_methods): Set TYPE_HAS_NONPUBLIC_* correctly.
+ * typeck.c (build_component_ref): Fix to handle anon unions in base
+ classes as well.
-Thu Dec 16 12:17:06 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+Wed Feb 7 14:29:12 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-lex.c (real_yylex): Turn the code back on that deals with
- __FUNCTION__ and __PRETTY_FUNCTION__. Don't use lookup_name, to
- avoid the ambiguity problems that led to it being turned off in the
- first place.
+ * class.c (resolves_to_fixed_type_p): Delete code dealing with
+ a WITH_CLEANUP_EXPR, since we don't generate them any more.
+ * cvt.c (build_up_reference): Likewise.
+ * decl.c (grok_reference_init): Likewise.
+ (cp_finish_decl): Likewise.
+ * error.c (dump_expr): Likewise.
+ * tree.c (real_lvalue_p): Likewise.
+ (lvalue_p): Likewise.
+ (build_cplus_new): Likewise.
+ (unsave_expr_now): Likewise.
+ * typeck.c (unary_complex_lvalue, build_modify_expr,
+ c_expand_return): Likewise.
- * cp-method.c (hack_identifier): Also check for a TYPE_PTRMEMFUNC_P
- to see if something is a method.
+Tue Feb 6 13:39:22 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Wed Dec 15 18:35:58 1993 Mike Stump <mrs@cygnus.com>
+ Make the C++ front-end pay attention to attributes for structures.
+ * class.c (finish_struct): New argument ATTRIBUTES, passed down into
+ finish_struct_1.
+ (finish_struct_1): New argument ATTRIBUTES; call cplus_decl_attributes.
+ Take out old round_up_size use and setting the DECL_ALIGN possibly
+ using it. Take out setting of TYPE_ALIGN to round_up_size, which
+ can override what the attribute set.
+ * cp-tree.h (finish_struct): Update prototype.
+ * parse.y (template_instantiate_once): Pass a NULL_TREE for the
+ attributes to finish_struct.
+ (structsp): For a CLASS decl, add maybe_attribute to rule and pass that
+ value down into finish_struct.
+ * Makefile.in (CONFLICTS): Switch to 7 shift/reduce conflicts.
- * cp-typeck.c (build_modify_expr): Avoid error messages on small
- enum bit fields.
- * cp-typeck.c (convert_for_assignment): Add missing argument to
- cp_warning and cp_pedwarn calls.
+Tue Feb 6 13:12:15 1996 Per Bothner <bothner@kalessin.cygnus.com>
-Wed Dec 15 18:25:32 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (poplevel): Re-word dead for local handling.
+ (pushdecl): Remove useless DECL_DEAD_FOR_LOCAL test.
+ (cp_finish_decl): If is_for_scope, check for duplicates so
+ we can disable is_for_scope. Otherwise, preserve_temp_slots.
- * cp-parse.y (member_init): ANSI C++ doesn't forbid old-style base
- initializers; it's just anachronistic.
+ * lex.c (do_identifier): Use global binding in preference of
+ dead for local variable.
- * cp-decl.c (finish_decl): Don't require external-linkage arrays
- to have a complete type at declaration time when pedantic.
+Mon Feb 5 17:46:46 1996 Mike Stump <mrs@cygnus.com>
-Tue Dec 14 11:37:23 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * init.c (initializing_context): Handle anon union changes, the
+ context where fields of anon unions can be initialized now has to be
+ found by walking up the TYPE_CONTEXT chain.
- * cp-decl.c (pushdecl): Don't set DECL_CONTEXT if it's already set.
+Fri Feb 2 14:54:04 1996 Doug Evans <dje@charmed.cygnus.com>
- * cp-call.c (build_method_call): Don't dereference pointer given
- as instance.
+ * decl.c (start_decl): #ifdef out code to set DECL_COMMON
+ if ASM_OUTPUT{,_ALIGNED}_BSS is defined.
+ (obscure_complex_init): If bss is supported, always set
+ DECL_INITIAL to error_mark_node.
- * cp-decl.c (finish_function): Don't pass pointer to
- build_method_call.
- (finish_function): Ditto.
+Thu Feb 1 16:19:56 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-typeck.c (build_x_function_call): Ditto.
+ * init.c (is_friend): Make sure there's a context before we see if
+ it's an aggr type.
- * cp-method.c (build_component_type_expr): Ditto.
+Thu Feb 1 15:44:53 1996 Mike Stump <mrs@cygnus.com>
- * cp-init.c (build_member_call): Ditto.
- (build_new): Ditto.
+ * init.c (is_friend): Classes are not friendly with nested classes.
-Mon Dec 13 18:04:33 1993 Kung Hsu (kung@cirdan.cygnus.com)
+Thu Feb 1 15:27:37 1996 Doug Evans <dje@charmed.cygnus.com>
- * cp-decl.c (xref_tag): fix regression created by changes made
- in Dec. 7 1993.
- * cp-decl.c (xref_defn_tag): fix parallel nested class problem.
+ * lex.c (check_newline): Pass last character read to HANDLE_PRAGMA,
+ and record its result.
-Fri Dec 10 12:40:25 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+Thu Feb 1 09:27:01 1996 Mike Stump <mrs@cygnus.com>
- * cp-call.c (compute_conversion_costs_ansi) [DEBUG_MATCHING]: Print
- out the final evaluation of the function, so we can see if ELLIPSIS,
- USER, and EVIL were set at the end.
+ * class.c (finish_struct_anon): Switch around code to not move anon
+ union elements around, nor mess up their contexts, nor offsets,
+ instead we now build up the right number of COMPONENT_REFs for all
+ the anon unions that may be present at build_component_ref time.
+ * typeck.c (lookup_anon_field): New routine to handle field lookup
+ on fields without names. We find them, based upon their unique type
+ instead.
+ * typeck.c (build_component_ref): Allow FIELD_DECL components.
+ Handle finding components in anonymous unions, and ensure that a
+ COMPONENT_REF is built for each level as necessary.
- * cp-call.c (convert_harshness_ansi): When the parm isn't an lvalue,
- only go for setting TRIVIAL_CODE if we are dealing with types that
- are compatible.
+Tue Jan 30 18:18:23 1996 Mike Stump <mrs@cygnus.com>
-Thu Dec 9 18:27:22 1993 Mike Stump <mrs@cygnus.com>
+ * cvt.c (build_up_reference): Make the INDIRECT_BIND case come after
+ code that ensures that copy ctors are used if appropriate.
- * cp-decl.c (flag_huge_objects): New flag to allow large objects.
- * toplev.c (lang_options): Ditto.
- * cp-decl2.c (flag_huge_objects, lang_f_options): Ditto.
- * cp-decl.c (delta_type_node): New type for delta entries.
- * cp-tree.h (delta_type_node): Ditto.
- * cp-decl.c (init_decl_processing): Setup delta_type_node.
- * cp-decl.c (init_decl_processing, build_ptrmemfunc_type): Use
- delta_type_node instead of short_integer_type_node.
- * cp-class.c (build_vtable_entry): Ditto.
+Tue Jan 30 17:35:14 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Thu Dec 9 16:19:05 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * init.c (build_vec_delete): Only give an error if base isn't an
+ error_mark_node.
- * cp-tree.h (OPERATOR_TYPENAME_P): Define outside of
- NO_{DOLLAR,DOT} macro checks, so it always gets defined.
- (VTABLE_NAME_P): Define for NO_DOT && NO_DOLLAR_IN_LABEL.
+Mon Jan 29 17:09:06 1996 Mike Stump <mrs@cygnus.com>
+
+ * spew.c (do_aggr): `new struct S;' isn't a forward declaration.
+ (yylex): If we see `new', keep slurping.
+
+Thu Jan 25 18:31:36 1996 Mike Stump <mrs@cygnus.com>
+
+ * class.c (finish_struct_1): Move code for handling anon unions...
+ (finish_struct_anon): to here. Fixup so that we do the offset
+ calculations right, and so that the fields are physically moved to
+ the containers's chain.
+
+Thu Jan 25 18:27:37 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * decl.c (grokdeclarator): Avoid trying to get an operand off an
+ identifier node.
+
+Wed Jan 24 11:25:30 1996 Jim Wilson <wilson@chestnut.cygnus.com>
+
+ * typeck.c (pointer_int_sum): Use TYPE_PRECISION (sizetype) not
+ POINTER_SIZE to agree with expr.c.
+
+Thu Jan 25 13:01:23 1996 Mike Stump <mrs@cygnus.com>
+
+ * search.c (lookup_field): Don't report ambiguities if protect is 0,
+ instead return NULL_TREE.
+
+Wed Jan 24 13:01:26 1996 Mike Stump <mrs@cygnus.com>
+
+ * class.c (finish_struct_1): Call warn_hidden if we want warnings
+ about overloaded virtual functions.
+ (warn_hidden): New routine to warn of virtual functions that are
+ hidden by other virtual functions, that are not overridden.
+ (get_basefndecls): New routine, used by warn_hidden.
+ (mark_overriders): New routine, used by warn_hidden.
+ * search.c (get_matching_virtual): Remove old warning that just
+ isn't very useful.
+
+Tue Jan 23 12:26:10 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * decl.c (output_builtin_tdesc_entries): #if 0 the function definition.
+
+ * typeck.c (null_ptr_cst_p): Delete unused fn.
+ (build_function_call_maybe): Delete unused fn.
+
+ * expr.c (extract_init): #if 0 the code after unconditional return 0
+ for now.
+
+ Delete old cadillac code.
+ * edsel.c: Remove file.
+ * Make-lang.in (CXX_SRCS): Take edsel.c off the list.
+ * Makefile.in (CXX_OBJS): Delete edsel.o.
+ (edsel.o): Delete rule.
+ * cp-tree.h (flag_cadillac): Delete var decl.
+ * lang-options.h: Delete "-fcadillac" and "-fno-cadillac".
+ * decl2.c (flag_cadillac): Delete var definition.
+ (lang_decode_option): Delete handling of -fcadillac and -fno-cadillac.
+ (grokfield): Delete code depending on flag_cadillac.
+ (finish_anon_union): Likewise.
+ * class.c (finish_struct_1): Likewise.
+ (pushclass): Likewise.
+ (popclass): Likewise.
+ (push_lang_context): Likewise.
+ (pop_lang_context): Likewise.
+ * decl.c (init_decl_processing): Likewise.
+ (start_decl): Likewise.
+ (cp_finish_decl): Likewise.
+ (xref_tag): Likewise.
+ (finish_enum): Likewise.
+ (start_function): Likewise.
+ (finish_function): Likewise.
+ (finish_stmt): Likewise.
+ * lex.c (lang_init): Likewise.
+ (check_newline): Likewise.
-Wed Dec 8 17:38:06 1993 Mike Stump <mrs@cygnus.com>
+ * lex.c (do_pending_inlines): Delete synthesized method kludge.
- * cp-decl.c (finish_decl): Make sure things that can go into
- "common", do go into common, if -fcommon is given.
+ Delete defunct, ancient garbage collection implementation.
+ * rtti.c: New file with the RTTI stuff from gc.c.
+ * gc.c: Removed file (moved the remaining stuff into rtti.c).
+ * Makefile.in (CXX_OBJS): Replace gc.o with rtti.o.
+ (rtti.o): New rule, replacing gc.o.
+ * Make-lang.in (CXX_SRCS): Replace gc.c with rtti.c.
+ * cp-tree.h: Delete gc-related fn decls.
+ (DECL_GC_OFFSET): Delete macro.
+ (flag_gc): Delete extern decl.
+ * decl.c (current_function_obstack_index): Delete var decl.
+ (current_function_obstack_usage): Delete var decl.
+ (start_function): Delete clearing of current_function_obstack_index
+ and current_function_obstack_usage.
+ (init_decl_processing): Delete code relying on -fgc.
+ Delete call to init_gc_processing.
+ (cp_finish_decl): Delete calls to build_static_gc_entry and
+ type_needs_gc_entry. Delete gc code setting DECL_GC_OFFSET.
+ (store_parm_decls): Delete -fgc calls to cp_expand_decl_cleanup
+ and to expand_expr of a __gc_main call.
+ (maybe_gc_cleanup): Delete var decl.
+ (finish_function): Delete call to expand_gc_prologue_and_epilogue.
+ * decl2.c (flag_gc): Delete var decl.
+ (lang_f_options): Delete offering of -fgc.
+ (lang_decode_option): Delete -fgc and -fno-gc handling.
+ (get_temp_regvar): Delete gc code.
+ * init.c (build_new): Delete gc code.
+ * lex.c (init_lex): Delete checking of flag_gc.
+
+ * typeck.c (convert_arguments): Delete gc code.
+ (build_component_addr): Delete -fgc warning.
+ (build_modify_expr): Delete gc code.
+
+ * decl2.c (build_push_scope): Delete fn.
+ * cp-tree.h (build_push_scope): Delete decl.
+
+ * search.c (clear_search_slots): Delete fn.
+ * cp-tree.h (clear_search_slots): Delete decl.
+
+ * search.c (tree_needs_constructor_p): Delete fn.
+ * cp-tree.h (tree_needs_constructor_p): Delete decl.
+
+ * tree.c (id_cmp): Delete fn.
+
+ * tree.c (set_fnaddr_from_vtable_entry): Delete fn.
+ * cp-tree.h (set_fnaddr_from_vtable_entry): Delete decl.
+
+ * tree.c (decl_value_member): Delete fn.
+ * cp-tree.h (decl_value_member): Delete decl.
+
+ * tree.c (list_hash_lookup_or_cons): Delete fn.
+ * cp-tree.h (list_hash_lookup_or_cons): Delete decl.
+
+ * method.c (cplus_exception_name): Delete fn.
+ (EXCEPTION_NAME_{PREFIX, LENGTH}): Delete macros.
+
+ * spew.c (shift_tokens): Delete fn.
+
+Mon Jan 22 17:49:33 1996 Jason Merrill <jason@yorick.cygnus.com>
+
+ * except.c (init_exception_processing): Pass 1 to needs_pop in calls
+ to cp_finish_decl.
+ * parse.y: Likewise.
+
+Mon Jan 22 17:34:29 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * tree.c (build_cplus_staticfn_type): Delete function definition;
+ never used.
+ * cp-tree.h (build_cplus_staticfn_type): Delete decl.
+
+ * tree.c (virtual_member): Delete function definition; never used.
+ * cp-tree.h (virtual_member): Delete decl.
+
+Fri Jan 19 18:03:14 1996 Mike Stump <mrs@cygnus.com>
+
+ * typeck.c (build_component_ref): Handle getting vbase pointers
+ out of complex multiple inheritance better.
+
+Fri Jan 19 16:27:40 1996 Mike Stump <mrs@cygnus.com>
+
+ * typeck.c (build_object_ref): Make sure we use the real type, not
+ any reference type.
+
+Fri Jan 19 16:01:47 1996 Mike Stump <mrs@cygnus.com>
+
+ * tree.c (build_exception_variant): Don't create new types if we
+ don't have to, also build new types on the right obstack.
+
+Fri Jan 19 14:09:44 1996 Jason Merrill <jason@yorick.cygnus.com>
-Wed Dec 8 13:01:54 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * decl.c (store_bindings): Split out from push_to_top_level.
+ (push_to_top_level): Call it for b->type_shadowed on class binding
+ levels.
- * cp-call.c (print_harshness) [DEBUG_MATCHING]: New function.
- (compute_conversion_costs_ansi) [DEBUG_MATCHING]: Print out
- argument matching diagnostics to make instantly clear what the
- compiler is doing.
+Fri Jan 19 13:53:14 1996 Mike Stump <mrs@cygnus.com>
- * cp-call.c (convert_harshness_ansi): If the parm isn't an lvalue,
- then check to see if the penalty was increased due to
- signed/unsigned mismatch, and use a TRIVIAL_CODE if it wasn't.
+ * search.c (expand_upcast_fixups): Fix so that offsets stored in
+ vbase_offsets are always right. Fixes a problem where virtual base
+ upcasting and downcasting could be wrong during conversions on this
+ during virtual function dispatch at ctor/dtor time when dynamic
+ vtable fixups for deltas are needed. This only sounds easier than
+ it is. :-)
+ (fixup_virtual_upcast_offsets): Change to reflect new calling
+ convention for expand_upcast_fixups.
-Tue Dec 7 18:29:14 1993 Kung Hsu (kung@cirdan.cygnus.com)
+Fri Jan 19 12:23:08 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-decl.c (xref_tag, pushtag): Fix nested class search/resolution
- problem.
+ * decl2.c (grokbitfield): Strip the NOPs from WIDTH before we
+ check that it's usable as the bitfield width.
-Tue Dec 7 16:09:34 1993 Jason Merrill (jason@deneb.cygnus.com)
+Wed Jan 17 21:22:40 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-class.c (finish_struct): Before synthesizing methods, if no
- methods have yet been declared then set nonprivate_method. Don't
- set non_private method after synthesizing a method.
+ * decl2.c (grokfield): Call cplus_decl_attributes with the attrlist.
+ Pass a null tree to grokdeclarator for its ATTRLIST arg, since it's
+ only ever used for functions in it.
- * cp-lex.c (extract_interface_info): If flag_alt_external_templates
- is set, tie emitted code to the location of template instantiation,
- rather than definition.
+Wed Jan 17 12:10:38 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-tree.h: Declare flag_alt_external_templates.
+ * parse.y (qualified_type_name): Use the TYPE_DECL, not the type.
+ (nested_type): Likewise.
+ (nested_name_specifier): Use lastiddecl.
- * cp-decl2.c (lang_decode_option): Support -falt-external-templates.
+ * decl.c (grokdeclarator): Adjust accordingly.
+ * init.c (expand_member_init): Likewise.
+ * parse.y (base_class): Likewise.
+ * typeck2.c (build_functional_cast): Likewise.
- * toplev.c (lang_options): Ditto.
+ * typeck2.c (build_functional_cast): Fill in name after we've
+ checked for non-aggr type.
- Mon Oct 4 12:50:02 1993 Chip Salzenberg (chip@fin.uucp)
+Wed Jan 17 10:18:01 1996 Mike Stump <mrs@cygnus.com>
- [changes propagated from 930810 snapshot]
- * cp-decl.c (init_decl_processing): Make long long available for use
- as SIZE_TYPE and PTRDIFF_TYPE.
- (finish_decl): Allow file-scope static incomplete array.
- (grokdeclarator): Don't pass on const and volatile fron function
- value type to function type.
- Warn here for volatile fn returning non-void type.
- * cp-parse.y (attrib): Accept attributes `volatile' with alias
- `noreturn', and `const'.
- * cp-typeck.c (default_conversion): Don't lose const and volatile.
- (build_binary_op_nodefault): Generate pedantic warning for comparison
- of complete pointer type with incomplete pointer type.
- (build_c_cast): Be careful that null pointer constant be INTEGER_CST.
+ * decl2.c (warn_pointer_arith): Default to on.
-Tue Dec 7 10:46:48 1993 Jason Merrill (jason@deneb.cygnus.com)
+Tue Jan 16 12:45:38 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-init.c (expand_vec_init): When creating a temporary for copying
- arrays, use the type of the source, not the target.
+ * lex.c (is_rid): New function.
+ * decl.c (grokdeclarator): Diagnose reserved words used as
+ declarator-ids.
- * cp-cvt.c (convert): Pass an argument for errtype to
- convert_to_reference.
+Tue Jan 16 11:39:40 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-error.c (dump_expr, COMPONENT_REF & CALL_EXPR): Deal with
- methods, -> and `this'.
+ * tree.c (get_decl_list): Don't lose cv-quals.
-Mon Dec 6 17:12:33 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * decl.c (grokdeclarator): Fix SCOPE_REF handling and diagnose
+ typespecs used as declarator-ids.
- * cp-error.c (parm_as_string): New function; returns `this' or arg
- number. Corresponds to %P.
- (dump_expr): Deal with method calls.
+Tue Jan 16 11:09:42 1996 Mike Stump <mrs@cygnus.com>
- * cp-cvt.c (convert_to_reference): Stop using warn_for_assignment.
- * cp-typeck.c (convert_for_assignment): Ditto.
- (warn_for_assignment): Lose.
+ * decl.c (poplevel): When poping a level, don't give a warning for
+ any subblocks that already exist.
-Mon Dec 6 11:33:35 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+Tue Jan 16 00:25:33 1996 Jason Merrill <jason@yorick.cygnus.com>
- * cp-call.c (ideal_candidate_ansi): Delete code that was never
- doing anything useful. Instead, sort once, and DO NOT wipe
- out any codes with EVIL_CODE, since that's what we use as a
- marker for the end of the list of candidates.
+ * typeck.c (build_object_ref): Finish what I started.
- * cp-cvt.c (convert_to_aggr): Make sure to always set H_LEN.
+ * parse.y (qualified_type_name): Don't check TYPE_BUILT_IN.
-Mon Dec 6 12:49:17 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * decl2.c (constructor_name_full): Handle TEMPLATE_TYPE_PARMs.
- * cp-init.c (get_aggr_from_typedef): New function, like
- is_aggr_typedef but returns the _TYPE.
+ * decl.c (grokdeclarator): Also accept TEMPLATE_TYPE_PARM as a
+ scope.
- * cp-call.c, cp-init.c, cp-method.c: Eradicate err_name.
+Mon Jan 15 16:19:32 1996 Jason Merrill <jason@yorick.cygnus.com>
-Sun Dec 5 18:12:48 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * decl.c (xref_tag): Handle passing a type in directly.
- * cp-lex.c (readescape): Pedwarn when a hex escape is out of range.
+ * parse.y (qualified_type_name): Pull out the type.
+ (nested_type): Likewise.
+ Take types directly instead of as identifiers.
+ * call.c (build_scoped_method_call): Take types directly instead of
+ as identifiers.
+ * decl.c (xref_basetypes): Likewise.
+ * init.c (expand_member_init): Likewise.
+ (build_member_call): Likewise.
+ (build_offset_ref): Likewise.
+ * typeck2.c (build_scoped_ref): Likewise, remove bogus code.
+ * method.c (do_build_assign_ref): Likewise.
+ * decl.c (grokdeclarator): Handle a type appearing as the
+ declarator-id for constructors.
+ * method.c (do_build_copy_constructor): current_base_init_list now
+ uses the types directly, not their names.
+ * init.c (sort_base_init): Likewise.
+ (expand_member_init): Likewise.
+ * init.c (is_aggr_type): New function, like is_aggr_typedef.
-Thu Nov 25 23:50:19 1993 Chip Salzenberg (chip@fin.uucp)
+Mon Jan 15 08:45:01 1996 Jeffrey A Law <law@cygnus.com>
- Delay language context change until beginning of next decl.
+ * tree.c (layout_basetypes): Call build_lang_field_decl instead
+ of build_lang_decl if first arg is a FIELD_DECL.
- * cp-lex.h (c_header_level): Removed.
- (pending_lang_change): Declared.
- * cp-lex.c (c_header_level): Renamed from in_c_header, made static.
- (pending_lang_change): Defined.
- (check_newline): Rework code that recognizes line number and
- filename changes. Instead of pushing and popping lang context,
- increment and decrement pending_lang_change.
- (do_pending_lang_change): Push and pop lang context according
- to value of pending_lang_change.
- * cp-parse.y (extdefs): Use lang_extdef instead of extdef.
- (extdef): Same as extdef, but call do_pending_lang_change() first.
+Thu Jan 11 14:55:07 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Mon Nov 15 15:39:15 1993 Chip Salzenberg (chip@fin.uucp)
+ * decl.c (cp_finish_decl): Only clear TREE_USED if DECL_NAME is
+ non-empty.
+ * except.c (expand_start_catch_block): Set TREE_USED to avoid
+ warnings about the catch handler.
- * cp-typeck.c (build_binary_op_nodefault): Warn for ordered
- compare of ptr with 0 only if pedantic in both cases.
+Mon Jan 8 17:35:12 1996 Jason Merrill <jason@yorick.cygnus.com>
-Thu Nov 25 13:31:37 1993 Chip Salzenberg (chip@fin.uucp)
+ * typeck.c (build_modify_expr): Use a COMPOUND_EXPR instead of
+ expand_target_expr.
- Reinstate the below patch, which got lost in the Cygnus merge:
- Tue Nov 23 13:59:24 1993 Hallvard B Furuseth (hbf@durin.uio.no)
- * cp-parse.y (maybe_type_qual): Don't fail to set $$.
+Thu Jan 4 12:30:32 1996 Brendan Kehoe <brendan@lisa.cygnus.com>
-Wed Nov 17 19:03:30 1993 Chip Salzenberg (chip@fin.uucp)
+ Fix access control to use trees rather than integers.
+ * class.c (access_{default, public, protected, private,
+ default_virtual, public_virtual, private_virtual}_node): Add
+ definitions.
+ (init_class_processing): Do creation of those nodes.
+ * cp-tree.h (access_type): Delete enum decl.
+ (access_{default, public, protected, private, default_virtual,
+ public_virtual, private_virtual}_node): Add decls.
+ (compute_access): Change return type.
+ * search.c (compute_access): Have tree return type, instead of enum.
+ (lookup_field): Declare THIS_V and NEW_V to be tree nodes.
+ * lex.c (real_yylex): Use yylval.ttype for giving the value of the
+ access_* node for each of RID_{PUBLIC, PRIVATE, PROTECTED}.
+ * parse.y (VISSPEC): Make ttype rather than itype.
+ (base_class_access_list): Likewise.
+ * *.[cy]: Change all refs of `access_public' to `access_public_node',
+ etc.
+ * call.c (build_method_call): Make ACCESS be a tree.
+ * class.c (alter_access, finish_struct_1, filter_struct): Likewise.
+ * cvt.c (convert_to_aggr): Likewise.
+ * init.c (build_offset_ref, resolve_offset_ref, build_delete):
+ Likewise.
+ * method.c (hack_identifier): Likewise.
+ * typeck.c (build_component_ref_1, build_component_ref): ): Likewise.
- * cp-parse.y (attrib): Allow "ident(ident)" like the C front end.
+Thu Jan 4 11:02:20 1996 Mike Stump <mrs@cygnus.com>
-Fri Oct 22 20:43:37 1993 Paul Eggert (eggert@twinsun.com)
+ * typeck.c (pointer_int_sum, pointer_diff): Make code agree with C
+ frontend, and make it more consistent with respect to
+ warn_pointer_arith.
- * cp-lex.c (real_yylex): Diagnose floating point constants
- that are too large.
+Tue Jan 2 00:13:38 1996 Rusty Russell <rusty@adelaide.maptek.com.au>
-Wed Nov 17 19:10:37 1993 Chip Salzenberg (chip@fin.uucp)
+ * decl.c (pushdecl): Check for duplicate parameter names.
- * cp-type2.c (build_functional_cast): ARM page 16: When a class
- and an object, function or enumerator are declared in the same
- scope with the same name, the class name is hidden.
+Wed Jan 3 09:25:48 1996 Mike Stump <mrs@cygnus.com>
-Wed Nov 17 19:07:18 1993 Chip Salzenberg (chip@fin.uucp)
+ * decl.c (expand_static_init): Call assemble_external for atexit.
- * cp-call.c (convert_harshness_ansi): Distinguish float, double,
- and long double from each other when overloading.
- (compute_conversion_costs_{ansi,old}, build_method_call,
- build_overlay_call_real, convert_to_aggr): Always set and
- always use H_LEN member of candidate structure.
+Wed Jan 3 07:55:19 1996 Mike Stump <mrs@cygnus.com>
-Mon Oct 11 23:10:53 1993 Chip Salzenberg (chip@fin.uucp)
+ * except.c (do_unwind): Remove some generated dead code.
+ (eh_outer_context): New routine, factor out some common code from
+ expand_builtin_throw and end_eh_unwinder. Add code to do return
+ address masking for the PA.
+ (expand_builtin_throw): Use eh_outer_context instead of open coding
+ it here.
+ (end_eh_unwinder): Likewise.
+
+Tue Jan 2 17:00:56 1996 Mike Stump <mrs@cygnus.com>
+
+ * except.c (expand_throw): Call assemble_external for __empty, if we
+ use it.
- * cp-decl.c (duplicate_decls): Note redeclarations of library
- functions, and generate distinct warnings for them.
+Thu Dec 28 11:13:15 1995 Mike Stump <mrs@cygnus.com>
-Mon Oct 4 12:26:49 1993 Chip Salzenberg (chip@fin.uucp)
+ * except.c (expand_builtin_throw): Use RETURN_ADDR_OFFSET instead of
+ NORMAL_RETURN_ADDR_OFFSET.
+ (end_eh_unwinder): Likewise.
- Support format warnings in G++.
+Wed Dec 27 22:18:16 1995 Mike Stump <mrs@cygnus.com>
- * cp-tree.h: Protect against multiple inclusion.
- Declare all public functions in c-common.c (copy from c-tree.h).
- (STDIO_PROTO): Define.
- (warn_format): Declare.
- (record_format_info): Remove declaration.
- * cp-decl.c (init_decl_processing): Call init_function_format_info.
- * cp-decl2.c (lang_decode_option): Make "-Wall" include warn_format.
- * cp-typeck.c (build_function_call_real): Call check_function_format.
- (record_format_info): Remove -- obsolete stub.
+ * gc.c (build_dynamic_cast): Make sure we don't cast away const
+ when dealing with references, and make sure we handle dynamic
+ casting to a cv qualified reference.
-Sat Jul 24 12:04:29 1993 Chip Salzenberg (chip@fin.uucp)
+Thu Dec 21 23:50:35 1995 Mike Stump <mrs@cygnus.com>
- * cp-decl.c (duplicate_decls): Don't warn for non-extern var decl
- following an extern one (for -Wredundant-decls).
- * cp-parse.y (primary): In statement expression case, if compstmt
- returns something other than a BLOCK, return it unchanged.
+ * except.c (struct eh_context): New structure top hold eh context
+ information.
+ (push_eh_context): New routine.
+ (pop_eh_context): Likewise.
+ * decl.c (push_cp_function_context): Use them.
+ (pop_cp_function_context): Likewise.
-Thu Dec 2 20:44:58 1993 Chip Salzenberg (chip@fin.uucp)
+Wed Dec 20 12:42:51 1995 Jason Merrill <jason@yorick.cygnus.com>
- * cp-decl.c (warn_extern_redeclared_static): New function made
- from code extracted from pushdecl.
- (duplicate_decls, pushdecl): Call new function.
- (lookup_name_current_level): Allow for IDENTIFIER_GLOBAL_VALUE
- to be a TREE_LIST when function is declared in 'extern "C" {}'.
+ * decl2.c (finish_file): Also prune uninteresting functions in the
+ inline emission loop.
-Fri Dec 3 16:01:10 1993 Jason Merrill (jason@deneb.cygnus.com)
+Wed Dec 20 02:32:07 1995 Jeffrey A Law <law@cygnus.com>
- * cp-class.c (duplicate_tag_error): Use cp_error.
- (finish_base_struct): Check for ambiguity with direct base, and don't
- generate op= or copy ctor if it exists.
+ * sig.c (build_signature_table_constructor): Mark functions
+ in the signature as referenced.
-Fri Dec 3 15:32:34 1993 Kung Hsu (kung@cirdan.cygnus.com)
+Tue Dec 19 22:36:56 1995 Jason Merrill <jason@yorick.cygnus.com>
- * cp-init.c (expand_member_init): when initializer name is null,
- don't try to build it now because emit_base_init will handle it.
+ * decl2.c (finish_file): Do all the vtable/synthesis stuff before
+ the inline emission stuff.
-Fri Dec 3 12:28:59 1993 Jason Merrill (jason@deneb.cygnus.com)
+Mon Dec 18 15:51:33 1995 Jason Merrill <jason@yorick.cygnus.com>
- * cp-lex.c (init_lex): Initialize input_filename to "<internal>" for
- code such as ExceptionHandler::operator=.
+ * cp-tree.h, decl2.c (flag_weak): New flag to control the use of
+ weak symbols.
+ * lang-options.h: Add -f{no-,}weak.
+ * decl.c (init_decl_processing): If the target does not support weak
+ symbols, don't use them.
+ * decl2.c, pt.c: s/SUPPORTS_WEAK/flag_weak/.
-Fri Dec 3 10:32:08 1993 Jason Merrill (jason@deneb.cygnus.com)
+Sun Dec 17 21:13:23 1995 Rusty Russell <rusty@adelaide.maptek.com.au>
- * cp-decl.c (grokdeclarator): Don't try to print out dname when
- complaining about arrays of references if decl_context==TYPENAME,
- since it will be null.
+ * init.c (expand_member_init): warning for base init after members.
- * cp-decl2.c: Default to flag_ansi_overloading.
+Fri Dec 15 15:32:18 1995 Jason Merrill <jason@yorick.cygnus.com>
-Thu Dec 2 18:05:56 1993 Kung Hsu (kung@cirdan.cygnus.com)
+ * cvt.c (build_expr_type_conversion): Don't convert to a reference
+ type.
- * cp-call.c (build_method_call): use binfo from instance if it's
- different from binfo (basetype_path) passed from above.
+Thu Dec 14 16:05:58 1995 Mike Stump <mrs@cygnus.com>
+
+ * method.c (report_type_mismatch): Improve wording for volatile
+ mismatches.
+
+Thu Dec 14 14:16:26 1995 Mike Stump <mrs@cygnus.com>
+
+ * init.c (expand_aggr_init_1): Use expand_aggr_init_1 instead of
+ expand_assignment, as the later doesn't handle things that have
+ copy constructors well. The compiler would do bitwise copying,
+ instead of ctor calling in some cases.
+
+Wed Dec 13 17:05:54 PST 1995 Paul Eggert <eggert@twinsun.com>
+
+ * g++.c (my_strerror): Return "cannot access" if errno is 0.
+ (pfatal_with_name, perror_exec): Don't assume that
+ the returned value from my_strerror contains no '%'s.
+ (concat): Remove.
+ (sys_nerror): Declare only if HAVE_STRERROR is not defined.
+
+Wed Dec 13 16:22:38 1995 Jason Merrill <jason@yorick.cygnus.com>
+
+ Lose CLASSTYPE_METHODS/DECL_NEXT_METHOD chain; make
+ TYPE_METHODS/TREE_CHAIN mean what they used to.
+ * decl2.c (constructor_name_full): Refer to CLASSTYPE_METHOD_VEC
+ instead of TYPE_METHODS.
+ * decl.c (duplicate_decls): Lose references to DECL_NEXT_METHOD.
+ * tree.c (tree_copy_lang_decl_for_deferred_output): Likewise.
+ * cp-tree.h (CLASSTYPE_METHODS): Lose.
+ (CLASSTYPE_METHOD_VEC): Point to lang_spec->methods instead of
+ TYPE_METHODS.
+ (struct lang_decl): Lose next_method field.
+ (DECL_NEXT_METHOD): Lose.
+ * class.c (finish_struct_methods): Don't mess with TYPE_METHODS.
+ (finish_struct): Just use TYPE_METHODS; we don't need fn_fields
+ anymore.
+ (finish_struct_methods): Don't mess with the TREE_CHAINs in
+ fn_fields.
-Thu Dec 2 12:48:36 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * search.c (add_conversions): Don't use TREE_CHAIN to traverse method
+ vector.
-Wed Nov 17 19:14:29 1993 Chip Salzenberg (chip@fin.uucp)
+ * call.c (build_method_call): Synthesize here even when not inlining.
+ * typeck.c (build_function_call_real): Likewise.
- cp-error.c (dump_expr): Use unsigned chars to output a
- TREE_REAL_CST in hex.
+Wed Dec 13 15:02:39 1995 Ian Lance Taylor <ian@cygnus.com>
-Thu Dec 2 11:05:48 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * cp/lex.c (check_newline): If DBX_DEBUGGING_INFO and write_symbols
+ == DBX_DEBUG, call dbxout_start_new_source_file and
+ dbxout_resume_previous_source_file when appropriate.
- * cp-class.c (finish_struct): Fix typo in setting
- cant_synth_asn_ref.
+Tue Dec 12 20:38:55 1995 Mike Stump <mrs@cygnus.com>
- * cp-tree.h (TYPE_NESTED_NAME): New macro, does
- DECL_NESTED_TYPENAME (TYPE_NAME (NODE)).
+ * except.c (start_anon_func): Push to the top level.
+ (end_anon_func): Pop from the top level.
- * cp-lex.c (default_copy_constructor_body): Change
- DECL_NAME (TYPE_NAME (btype)) to TYPE_NESTED_NAME (btype).
- (default_assign_ref_body): Ditto.
- (default_copy_constructor_body): Call operator= explicitly for
- base classes that have no constructor.
+Mon Dec 11 18:56:14 1995 Mike Stump <mrs@cygnus.com>
-Thu Dec 2 10:47:15 1993 Michael Tiemann (tiemann@blues.cygnus.com)
+ * cp-tree.h (build_cleanup): New routine to build cleanups.
+ * decl.c (expand_static_init): Use build_cleanup to build a cleanup
+ call at ctor time and use atexit to run it later.
+ * decl2.c (build_cleanup): New routine, taken from finish_file.
+ (finish_file): Use build_cleanup instead, and don't put function
+ local statics in global dtor list.
+
+Wed Dec 6 14:34:29 1995 Mike Stump <mrs@cygnus.com>
+
+ * except.c (expand_throw): Ensure that we have cleanups, if we try
+ and expand cleanups.
+
+Wed Dec 6 11:48:21 1995 Mike Stump <mrs@cygnus.com>
+
+ * except.c (expand_throw): Add logic to manage dynamic cleanups for
+ the EH object.
+ (expand_end_catch_block): Use the magic of expand_goto, instead of
+ emit_jump so that we get the cleanup for any catch clause parameter
+ and the cleanup for the exception object. Update to reflect label
+ changes.
+ (push_eh_cleanup): New routine to register a cleanup for an
+ exception object.
+ (empty_fndecl): Used to default cleanup actions to
+ nothing.
+ (init_exception_processing): Setup empty_fndecl. Setup
+ saved_cleanup.
+ (expand_start_catch_block): Update to reflect label changes. Call
+ push_eh_object to register the cleanup for the EH object.
+ (start_anon_func): New routine to start building lambda expressions
+ from trees.
+ (end_anon_func): New routine to end them.
+ (struct labelNode): Change so that we can use tree labels, or rtx
+ labels.
+ (saved_cleanup): Object to check for dynamic cleanups for the
+ exception handling object.
+ (push_label_entry): Change so that we can use tree labels, or rtx
+ labels.
+ (pop_label_entry): Likewise.
+ (top_label_entry): Likewise.
+ (expand_start_all_catch): Use tree label instead of rtx label, so
+ that we can get the magic of expand_goto.
+ (expand_end_all_catch): Update to reflect label changes.
+
+ * class.c (build_vfn_ref): Remove building_cleanup logic, as we now
+ use UNSAVE_EXPRs.
+ typeck.c (get_member_function_from_ptrfunc): Remove remnants of
+ building_cleanup logic, as we now use UNSAVE_EXPRs.
+ * cp-tree.h (unsave_expr): Declare it.
+ * decl.c (building_cleanup): Remove.
+ (maybe_build_cleanup): Remove building_cleanup logic, and use
+ UNSAVE_EXPR instead.
+
+Sun Dec 3 01:34:58 1995 Mike Stump <mrs@cygnus.com>
+
+ * gc.c (build_t_desc): Update error message to say <typeinfo>.
+
+Thu Nov 30 12:30:05 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
+
+ * decl.c (pushdecl): Only warn about shadowing a local variable if
+ warn_shadow is true.
+
+Sun Nov 26 16:06:55 1995 Rusty Russell <rusty@adelaide.maptek.com.au>
+
+ * typeck.c (build_binary_op_nodefault): Added warning about
+ comparisons between different enum types with -Wall, unless
+ -fenum-int-equiv set.
+
+Wed Nov 22 15:44:02 1995 Mike Stump <mrs@cygnus.com>
+
+ * class.c (finish_struct_1): Skip down to the inner type in
+ multidimensional arrays. Ensures ctors will be made for types that
+ need constructing.
+
+Wed Nov 22 14:19:22 1995 Mike Stump <mrs@cygnus.com>
+
+ * decl.c (last_dtor_insn): New to track the last compiler generated
+ insn in a dtor.
+ (store_parm_decls): Set it.
+ (finish_function): Use it to see if the dtor is empty. Avoid doing
+ vtable setup all the time, if we can.
+ (struct cp_function): Add last_dtor_insn.
+ (push_cp_function_context): Save it.
+ (pop_cp_function_context): Restore it.
- * cp-call.c (build_method_call): If the instance variable is
- converted to error_mark_node when we're trying to convert it to the
- base type of a method we're looking up, return error_mark_node.
+Wed Nov 22 11:52:19 1995 Paul Russell <Rusty.Russell@adelaide.maptek.com.au>
-Thu Dec 2 10:41:16 1993 Torbjorn Granlund (tege@cygnus.com)
+ * typeck.c (build_unary_op): Set TREE_NO_UNUSED_WARNING to avoid
+ warnings.
- * cp-typeck.c (build_binary_op_nodefault): In *_DIV_EXPR *_MOD_EXPR
- cases, tests for unsigned operands by peeking inside a NOP_EXPR.
+Tue Nov 21 17:15:23 1995 Mike Stump <mrs@cygnus.com>
-Wed Dec 1 13:33:34 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+ * typeck.c (expand_target_expr): Make sure targets get put into the
+ current temp_slot_level, so that the free_temp_slots call will reuse
+ them.
- * cp-call.c (compute_conversion_costs_ansi): Use the size of struct
- harshness_code, not the size of short, for clearing out the
- ansi_harshness.
+Tue Nov 21 13:32:03 1995 Mike Stump <mrs@cygnus.com>
- * cp-call.c (print_candidates): New function.
- (build_method_call): When we had some candidates, but didn't get a
- usable match, don't report that we got an error with the first
- candidate. Instead, say there were no matches, and list the
- candidates with print_candidates. In the second pass, make sure we
- clear out ever_seen, so we can accurately count the number of
- functions that qualified.
+ * class.c (finish_struct_1): Delay delta fixups for virtual bases
+ until after we have done the hard virtuals, to avoid a bogus `every
+ virtual function must have a unique final overrider' for virtual
+ functions that are only overridden by hard virtuals.
-Wed Dec 1 09:53:59 1993 Torbjorn Granlund (tege@cygnus.com)
+Thu Nov 9 13:35:30 1995 Jason Merrill <jason@yorick.cygnus.com>
- * cp-typeck.c (build_binary_op_nodefault): Shorten for *_MOD_EXPR
- only if op1 is known to be != -1.
- (build_binary_op_nodefault): Handle *_DIV_EXPR likewise.
+ * pt.c (do_function_instantiation): Don't try to find a file-scope
+ template for a member function.
-Tue Nov 30 14:07:26 1993 Brendan Kehoe (brendan@lisa.cygnus.com)
+Tue Nov 14 06:20:35 1995 Mike Stump <mrs@cygnus.com>
- * cp-method.c (hack_identifier): If the field itself is private, and
- not from a private base class, say so.
+ * g++.c (main): Add handling of -nodefaultlibs.
-Mon Nov 29 03:00:56 1993 Jason Merrill (jason@deneb.cygnus.com)
+Mon Nov 13 15:45:34 1995 Mike Stump <mrs@cygnus.com>
- * cp-decl.c (grokdeclarator): Always warn on initialization of
- const member.
+ * cp-tree.h (INDIRECT_BIND): Add a way for the frontend to
+ distinguish between direct bindings of reference variables, and
+ indirect bindings of reference variables.
+ * cvt.c (build_up_reference): Use it.
+ * typeck.c (convert_arguments): Use it to indicate this is an
+ indirect binding.
+ * decl.c (cp_finish_decl): Ensure that we reuse stack slots as fast
+ as they are unused.
+ (expand_static_init): Likewise.
+ (cplus_expand_expr_stmt): Likewise.
+ * decl2.c (finish_file): Likewise.
+ * init.c (perform_member_init): Likewise.
+ (emit_base_init): Likewise.
+ (expand_aggr_vbase_init_1): Likewise.
-Wed Nov 24 00:49:35 1993 Jason Merrill (jason@deneb.cygnus.com)
+Fri Nov 10 09:18:09 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-class.c (finish_struct): Set TYPE_GETS_CONST_* properly.
- (finish_base_struct): Set cant_synth_asn_ref properly.
+ * decl.c (push_namespace): Rewrite to use build_lang_decl, so we
+ get a DECL_LANG_SPECIFIC node.
+ * cp-tree.h (lang_decl_flags): Add new member `level'.
+ (NAMESPACE_LEVEL): Don't use decl.arguments, instead use the
+ decl_flags level member.
- * cp-lex.c (cons_up_default_function): Add section for operator=.
- (default_assign_ref_body): New function, mostly cribbed from
- default_copy_constructor_body.
+Mon Nov 6 18:36:13 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-class.c (base_info): Add members cant_synth_copy_ctor,
- cant_synth_asn_ref, no_const_asn_ref.
- (finish_base_struct): Update no_const_asn_ref, note that you should
- update cant_synth_*, propagate TYPE_GETS_ASSIGN_REF.
- (finish_struct): Add decls for cant_synth_*, no_const_asn_ref, and
- initialize them properly. Set no_const_asn_ref properly. Set
- cant_synth_* in some of the situations where they should be set.
- Propagate TYPE_GETS_ASSIGN_REF. Use cant_synth_copy_ctor. Add call
- to cons_up_default_function for operator=.
+ * call.c (build_method_call): Make sure instance has a
+ TYPE_LANG_SPECIFIC node before we dive into it.
-Tue Nov 23 20:24:58 1993 Mike Stump <mrs@cygnus.com>
+Sat Nov 4 20:01:52 1995 Jason Molenda <crash@phydeaux.cygnus.com>
- * cp-cvt.c (convert_force): Add code to perform casting of pointer
- to member function types.
- * cp-typeck.c (build_ptrmemfunc): Add FORCE parameter to indicate
- when the conversion should be done, regardless.
- * cp-tree.h (build_ptrmemfunc): Ditto.
- * cp-type2.c (digest_init): Ditto.
- * cp-typeck.c (convert_for_assignment): Ditto.
+ * method.c (make_thunk): use TREE_SET_CODE to set thunk's tree code.
-Tue Nov 23 18:06:58 1993 Jason Merrill (jason@deneb.cygnus.com)
+Thu Nov 2 17:56:57 1995 Mike Stump <mrs@cygnus.com>
- * cp-error.c (dump_expr): Do the right thing for variables of
- reference type.
+ * decl.c (duplicate_decls): When smashing decls, smash staticness in
+ the usual way.
- * cp-decl.c (grok_op_properties): Set TYPE_HAS_ASSIGN_REF
- and its kin properly.
- (xref_tag): Propagate TYPE_GETS_ASSIGN_REF.
+Thu Nov 2 16:44:02 1995 Mike Stump <mrs@cygnus.com>
-Tue Nov 23 12:26:13 1993 Mike Stump <mrs@cygnus.com>
+ * decl.c (poplevel): Handle the merging of subblocks of cleanups
+ when finishing blocks that have already been created (usually due to
+ the fixup goto code). Fixes bad debugging information.
- * cp-method.c (build_opfncall): Don't count pointer to member
- functions as aggregates here, as we don't want to look up methods in
- them. The compiler would core dump if we did, as they don't have
- normal names.
- * cp-typeck.c (build_indirect_ref): Improve wording on error
- message.
+Wed Nov 1 12:33:53 1995 Jason Merrill <jason@yorick.cygnus.com>
-Mon Nov 22 14:22:23 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * method.c (hack_identifier): Don't abort when we get a TREE_LIST
+ that's not a list of overloaded functions.
- * cp-decl.c (grok_op_properties): Allow operator?: with pedwarn
- (since it's supported in other compiler bits).
+Wed Nov 1 11:38:58 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-method.c (report_type_mismatch): Use cp_error; ignore err_name
- argument.
+ * decl2.c (mark_vtable_entries): Check DECL_LANG_SPECIFIC on fn
+ before trying to use DECL_ABSTRACT_VIRTUAL_P.
- * cp-error.c (dump_function_decl): Don't print return type for
- constructors and destructors.
+Tue Oct 31 11:56:55 1995 Jason Merrill <jason@yorick.cygnus.com>
- * cp-cvt.c (cp_convert_to_pointer): Import code from
- convert_to_pointer so we can return error_mark_node in the case of an
- error, and to allow more meaningful error messages.
- (build_type_conversion): Don't go through void* when trying
- to convert to a pointer type.
+ * decl2.c (mark_used): New function for hooking into setting of
+ TREE_USED on decls.
+ * call.c (build_method_call): Use it.
+ * class.c (instantiate_type): Likewise.
+ * init.c (build_offset_ref): Likewise. Don't call assemble_external
+ for all like-named functions.
+ * method.c (hack_identifier): Likewise.
+ (emit_thunk): Don't call assemble_external.
+ (make_thunk): Create thunk as a FUNCTION_DECL so that it
+ gets the right mode and ENCODE_SECTION_INFO works.
+
+ * parse.y: Use mark_used. Pass operator names to do_identifier.
+ * lex.c (do_identifier): Handle operator names.
- * cp-decl.c (grokfndecl): Move call to grok_op_properties back
- after grokclassfn so that it's dealing with the right decl.
- (grok_op_properties): Don't assert !methodp for op new and op delete.
+ * decl2.c (grokclassfn): Tweak __in_chrg attributes.
- * cp-init.c (build_delete): Don't use TYPE_BUILT_IN (there are now
- no uses of it in the compiler).
+Thu Oct 26 16:45:58 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-call.c (build_scoped_method_call): Fix for destructors of simple
- types.
- (build_method_call): Ditto.
+ * errfn.c: Include stdio.h.
+ (cp_sprintf): Take out decl of sprintf, and cast sprintf to errorfn*.
-Fri Nov 19 12:59:38 1993 Jason Merrill (jason@deneb.cygnus.com)
+Wed Oct 25 18:58:41 1995 Mike Stump <mrs@cygnus.com>
- * cp-tree.c (count_functions): Abstraction function.
+ * typeck2.c (digest_init): Always convert initializers to the
+ right type.
- * cp-call.c (build_overload_call_real): Deal with new overloading
- properly, remove dead code.
+Wed Oct 25 13:25:24 1995 Mike Stump <mrs@cygnus.com>
- * gcc.c (default_compilers): Generate and use .ii files in the
- intermediate stage of compiling C++ source.
+ * init.c (member_init_ok_or_else): Don't allow member initializers
+ for indirect members, as it is invalid.
-Fri Nov 19 11:26:09 1993 Jim Wilson (wilson@sphagnum.cygnus.com)
+Wed Oct 25 11:35:28 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
- * cp-expr.c (cplus_expand_expr): Make call_target a valid memory
- address before using it, so it can be later safely compared.
+ * decl.c (grokdeclarator): Don't allow `friend signed ()'.
-Fri Nov 12 15:30:27 1993 Jason Merrill (jason@deneb.cygnus.com)
+Fri Oct 20 10:30:59 1995 Mike Stump <mrs@cygnus.com>
- * cp-pt.c (tsubst): Deal with new overloading.
+ * parse.y (for.init.statement): Catch compound statements inside for
+ initializations, if we're being pedantic.
- * cp-typeck.c (fntype_p): is the arg function type?
- (comp_target_parms): pedwarn on conversion from (anything) to (...).
- (build_x_function_call): Deal with new overloading.
+Fri Oct 20 10:03:42 1995 Mike Stump <mrs@cygnus.com>
- * cp-tree.c (decl_list_length): Deal with new overloading.
- (decl_value_member): Like value_member, but for DECL_CHAINs.
+ * decl.c (lookup_tag): Return NULL_TREE if we don't find what we are
+ looking for.
- * cp-decl.c (duplicate_decls): Deal with new overloading.
- (start_decl): Ditto.
+Thu Oct 19 14:26:10 1995 Mike Stump <mrs@cygnus.com>
- * cp-class.c (instantiate_type): Deal with new overloading.
+ * error.c (dump_expr): Don't core dump when a boolean expression is
+ used as a default argument.
- * cp-call.c (convert_harshness_ansi): Deal with new overloading.
- (convert_harshness_old): Deal with new overloading.
- (build_overload_call_real): Ditto.
+Thu Oct 19 10:36:30 1995 Jason Merrill <jason@yorick.cygnus.com>
-Mon Nov 8 13:50:49 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * class.c (finish_struct_bits): Check aggregate_value_p instead of
+ RETURN_IN_MEMORY.
- * cp-tree.c (get_unique_fn): New function; returns FUNCTION_DECL
- if unambiguous, NULL_TREE otherwise.
- (get_first_fn): Returns the first appropriate FUNCTION_DECL.
- (is_overloaded_fn): Returns whether or not the passed tree is
- a function or list of functions.
+Wed Oct 18 18:12:32 1995 Jason Merrill <jason@yorick.cygnus.com>
- * cp-init.c (init_init_processing): use `get_first_fn' to find
- the FUNCTION_DEFN for new and delete.
+ * class.c (finish_struct_bits): Also set TREE_ADDRESSABLE on a
+ BLKmode type that would otherwise be returned in registers.
- * cp-decl.c (push_overloaded_decl): Use new overloading strategy, cut
- code size in half (I spit on special cases).
+Mon Oct 16 12:32:19 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-Tue Sep 7 20:03:33 1993 Jason Merrill (jason@deneb.cygnus.com)
+ * g++.c (WITHLIBC): New macro.
+ (main): Declare saw_libc. Use WITHLIBC if `-lc' was used; set
+ saw_libc and pass it at the end if it was set.
- * cp-decl.c: Allow references and template type parameters as well
+Wed Oct 11 16:30:34 1995 Brendan Kehoe <brendan@lisa.cygnus.com>
-Local Variables:
-eval: (auto-fill-mode)
-left-margin: 8
-fill-column: 76
-End:
+ * parse.y (fn.def1): Call split_specs_attrs in
+ declmods notype_declarator case.
diff --git a/contrib/gcc/cp/Make-lang.in b/contrib/gcc/cp/Make-lang.in
index c9d0a39..be02cf1 100644
--- a/contrib/gcc/cp/Make-lang.in
+++ b/contrib/gcc/cp/Make-lang.in
@@ -1,5 +1,5 @@
# Top level makefile fragment for GNU C++.
-# Copyright (C) 1994, 1995 Free Software Foundation, Inc.
+# Copyright (C) 1994, 1995, 1997 Free Software Foundation, Inc.
#This file is part of GNU CC.
@@ -35,7 +35,7 @@
# - making any compiler driver (eg: g++)
# - the compiler proper (eg: cc1plus)
# - define the names for selecting the language in LANGUAGES.
-
+#
# Extra flags to pass to recursive makes.
CXX_FLAGS_TO_PASS = \
"CXX_FOR_BUILD=$(CXX_FOR_BUILD)" \
@@ -45,39 +45,69 @@ CXX_FLAGS_TO_PASS = \
# Actual names to use when installing a native compiler.
CXX_INSTALL_NAME = `t='$(program_transform_name)'; echo c++ | sed $$t`
GXX_INSTALL_NAME = `t='$(program_transform_name)'; echo g++ | sed $$t`
+DEMANGLER_INSTALL_NAME = `t='$(program_transform_name)'; echo c++filt | sed $$t`
# Actual names to use when installing a cross-compiler.
CXX_CROSS_NAME = `t='$(program_transform_cross_name)'; echo c++ | sed $$t`
GXX_CROSS_NAME = `t='$(program_transform_cross_name)'; echo g++ | sed $$t`
+DEMANGLER_CROSS_NAME = `t='$(program_transform_cross_name)'; echo c++filt | sed $$t`
# The name to use for the demangler program.
-DEMANGLER_PROG = c++filt
-
+DEMANGLER_PROG = c++filt$(exeext)
+
+# Extra headers to install.
+CXX_EXTRA_HEADERS = $(srcdir)/cp/inc/typeinfo $(srcdir)/cp/inc/exception \
+ $(srcdir)/cp/inc/new $(srcdir)/cp/inc/new.h
+
+# Extra code to include in libgcc2.
+CXX_LIB2FUNCS = tinfo.o tinfo2.o new.o opnew.o opnewnt.o opvnew.o opvnewnt.o \
+ opdel.o opdelnt.o opvdel.o opvdelnt.o exception.o
+CXX_LIB2SRCS = $(srcdir)/cp/new.cc $(srcdir)/cp/new1.cc $(srcdir)/cp/new2.cc \
+ $(srcdir)/cp/exception.cc $(srcdir)/cp/tinfo.cc \
+ $(srcdir)/cp/tinfo2.cc $(srcdir)/cp/tinfo.h
+#
# Define the names for selecting c++ in LANGUAGES.
# Note that it would be nice to move the dependency on g++
# into the C++ rule, but that needs a little bit of work
# to do the right thing within all.cross.
-C++ c++: cc1plus
+C++ c++: cc1plus$(exeext)
# Tell GNU make to ignore these if they exist.
.PHONY: C++ c++
+g++.c: $(srcdir)/gcc.c
+ -rm -f $@
+ $(LN_S) $(srcdir)/gcc.c $@
+
+g++spec.o: $(srcdir)/cp/g++spec.c
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/cp/g++spec.c
+
+# N.B.: This is a copy of the gcc.o rule, with -DLANG_SPECIFIC_DRIVER added.
+# It'd be nice if we could find an easier way to do this---rather than have
+# to track changes to the toplevel gcc Makefile as well.
+# We depend on g++.c last, to make it obvious where it came from.
+g++.o: $(CONFIG_H) multilib.h config.status $(lang_specs_files) g++.c \
+ system.h
+ $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+ $(DRIVER_DEFINES) \
+ -DLANG_SPECIFIC_DRIVER \
+ -c g++.c
+
# Create the compiler driver for g++.
-g++: $(srcdir)/cp/g++.c $(CONFIG_H) $(LIBDEPS)
- $(CC) $(ALL_CFLAGS) $(INCLUDES) $(LDFLAGS) -o $@ $(srcdir)/cp/g++.c $(LIBS)
+g++$(exeext): g++.o g++spec.o version.o choose-temp.o pexecute.o prefix.o mkstemp.o $(LIBDEPS) $(EXTRA_GCC_OBJS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ g++.o g++spec.o prefix.o \
+ version.o choose-temp.o pexecute.o mkstemp.o $(EXTRA_GCC_OBJS) $(LIBS)
# Create a version of the g++ driver which calls the cross-compiler.
-g++-cross: $(srcdir)/cp/g++.c version.o $(LIBDEPS)
- $(CC) $(ALL_CFLAGS) $(INCLUDES) $(LDFLAGS) -o $@ \
- -DGCC_NAME=\"$(GCC_CROSS_NAME)\" $(srcdir)/cp/g++.c version.o $(LIBS)
+g++-cross$(exeext): g++$(exeext)
+ -rm -f g++-cross$(exeext)
+ cp g++$(exeext) g++-cross$(exeext)
cxxmain.o: cplus-dem.c demangle.h
rm -f cxxmain.c
- ln -s $(srcdir)/cplus-dem.c cxxmain.c > /dev/null 2>&1 \
- || cp $(srcdir)/cplus-dem.c cxxmain.c
+ $(LN_S) $(srcdir)/cplus-dem.c cxxmain.c
$(CC) -c -DMAIN $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
-DVERSION=\"$(version)\" cxxmain.c
- rm -f cxxmain.c
$(DEMANGLER_PROG): cxxmain.o underscore.o getopt.o getopt1.o $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) $(LIBS) -o $@ \
@@ -86,26 +116,95 @@ $(DEMANGLER_PROG): cxxmain.o underscore.o getopt.o getopt1.o $(LIBDEPS)
CXX_SRCS = $(srcdir)/cp/call.c $(srcdir)/cp/decl2.c \
$(srcdir)/cp/except.c $(srcdir)/cp/input.c $(srcdir)/cp/pt.c \
$(srcdir)/cp/spew.c $(srcdir)/cp/xref.c $(srcdir)/cp/class.c \
- $(srcdir)/cp/edsel.c $(srcdir)/cp/expr.c $(srcdir)/cp/lex.c \
+ $(srcdir)/cp/expr.c $(srcdir)/cp/lex.c \
$(srcdir)/cp/ptree.c $(srcdir)/cp/tree.c $(srcdir)/cp/cvt.c \
- $(srcdir)/cp/errfn.c $(srcdir)/cp/gc.c $(srcdir)/cp/method.c \
+ $(srcdir)/cp/errfn.c $(srcdir)/cp/rtti.c $(srcdir)/cp/method.c \
$(srcdir)/cp/search.c $(srcdir)/cp/typeck.c $(srcdir)/cp/decl.c \
- $(srcdir)/cp/error.c $(srcdir)/cp/init.c $(srcdir)/cp/parse.y \
- $(srcdir)/cp/sig.c $(srcdir)/cp/typeck2.c $(srcdir)/cp/repo.c
+ $(srcdir)/cp/error.c $(srcdir)/cp/friend.c $(srcdir)/cp/init.c \
+ $(srcdir)/cp/parse.y $(srcdir)/cp/sig.c $(srcdir)/cp/typeck2.c \
+ $(srcdir)/cp/repo.c $(srcdir)/cp/semantics.c
-cc1plus: $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o c-pragma.o
- cd cp; $(MAKE) $(FLAGS_TO_PASS) $(CXX_FLAGS_TO_PASS) ../cc1plus
-
+cc1plus$(exeext): $(P) $(CXX_SRCS) $(LIBDEPS) stamp-objlist c-common.o c-pragma.o \
+ $(srcdir)/cp/cp-tree.h $(srcdir)/cp/cp-tree.def
+ cd cp; $(MAKE) $(FLAGS_TO_PASS) $(CXX_FLAGS_TO_PASS) ../cc1plus$(exeext)
+#
# Build hooks:
-c++.all.build: g++ $(DEMANGLER_PROG)
-c++.all.cross: g++-cross $(DEMANGLER_PROG)
-c++.start.encap: g++
+c++.all.build: g++$(exeext)
+c++.all.cross: g++-cross$(exeext) $(DEMANGLER_PROG)
+c++.start.encap: g++$(exeext)
c++.rest.encap: $(DEMANGLER_PROG)
c++.info:
c++.dvi:
-
+
+# C++ language-support library pieces for libgcc.
+tinfo.o: cc1plus$(exeext) $(srcdir)/cp/tinfo.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/tinfo.cc
+tinfo2.o: cc1plus$(exeext) $(srcdir)/cp/tinfo2.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/tinfo2.cc
+exception.o: cc1plus$(exeext) $(srcdir)/cp/exception.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c -fexceptions $(srcdir)/cp/exception.cc
+new.o: cc1plus$(exeext) $(srcdir)/cp/new.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/new.cc
+opnew.o: cc1plus$(exeext) $(srcdir)/cp/new1.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/new1.cc -DL_op_new -o opnew.o
+opnewnt.o: cc1plus$(exeext) $(srcdir)/cp/new1.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/new1.cc -DL_op_newnt -o opnewnt.o
+opvnew.o: cc1plus$(exeext) $(srcdir)/cp/new2.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/new2.cc -DL_op_vnew -o opvnew.o
+opvnewnt.o: cc1plus$(exeext) $(srcdir)/cp/new2.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/new2.cc -DL_op_vnewnt -o opvnewnt.o
+opdel.o: cc1plus$(exeext) $(srcdir)/cp/new2.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/new2.cc -DL_op_delete -o opdel.o
+opdelnt.o: cc1plus$(exeext) $(srcdir)/cp/new2.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/new2.cc -DL_op_delnt -o opdelnt.o
+opvdel.o: cc1plus$(exeext) $(srcdir)/cp/new2.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/new2.cc -DL_op_vdel -o opvdel.o
+opvdelnt.o: cc1plus$(exeext) $(srcdir)/cp/new2.cc
+ $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/cp/new2.cc -DL_op_vdelnt -o opvdelnt.o
+
+# We want to update cplib2.txt if any of the source files change...
+cplib2.txt: $(CXX_LIB2SRCS) $(CXX_EXTRA_HEADERS) cplib2.ready
+ case " $(LANGUAGES) " in \
+ *" "[cC]"++ "*) \
+ echo $(CXX_LIB2FUNCS) > cplib2.new;; \
+ *) \
+ echo "" > cplib2.new;; \
+ esac
+ mv -f cplib2.new cplib2.txt
+
+# Or if it would be different.
+cplib2.ready: $(GCC_PASSES) $(LANGUAGES) $(LIBGCC2_DEPS) stmp-int-hdrs
+ @if [ -r cplib2.txt ]; then \
+ case " $(LANGUAGES) " in \
+ *" "[cC]"++ "*) \
+ echo $(CXX_LIB2FUNCS) > cplib2.new;; \
+ *) \
+ echo "" > cplib2.new;; \
+ esac; \
+ if cmp -s cplib2.new cplib2.txt; then true; else \
+ touch cplib2.ready; \
+ fi; \
+ rm -f cplib2.new; \
+ else true ; \
+ fi
+ @if [ -f cplib2.ready ]; then true; else \
+ touch cplib2.ready; \
+ fi
+#
# Install hooks:
# cc1plus is installed elsewhere as part of $(COMPILERS).
@@ -121,17 +220,24 @@ c++.install-common:
$(INSTALL_PROGRAM) g++-cross$(exeext) $(bindir)/$(GXX_CROSS_NAME)$(exeext); \
chmod a+x $(bindir)/$(GXX_CROSS_NAME)$(exeext); \
rm -f $(bindir)/$(CXX_CROSS_NAME)$(exeext); \
- ln $(bindir)/$(GXX_CROSS_NAME)$(exeext) $(bindir)/$(CXX_CROSS_NAME)$(exeext) \
- > /dev/null 2>&1 \
- || cp $(bindir)/$(GXX_CROSS_NAME)$(exeext) $(bindir)/$(CXX_CROSS_NAME)$(exeext) ; \
+ $(LN) $(bindir)/$(GXX_CROSS_NAME)$(exeext) $(bindir)/$(CXX_CROSS_NAME)$(exeext); \
else \
rm -f $(bindir)/$(GXX_INSTALL_NAME)$(exeext); \
$(INSTALL_PROGRAM) g++$(exeext) $(bindir)/$(GXX_INSTALL_NAME)$(exeext); \
chmod a+x $(bindir)/$(GXX_INSTALL_NAME)$(exeext); \
rm -f $(bindir)/$(CXX_INSTALL_NAME)$(exeext); \
- ln $(bindir)/$(GXX_INSTALL_NAME)$(exeext) $(bindir)/$(CXX_INSTALL_NAME)$(exeext) \
- > /dev/null 2>&1 \
- || cp $(bindir)/$(GXX_INSTALL_NAME)$(exeext) $(bindir)/$(CXX_INSTALL_NAME)$(exeext) ; \
+ $(LN) $(bindir)/$(GXX_INSTALL_NAME)$(exeext) $(bindir)/$(CXX_INSTALL_NAME)$(exeext); \
+ fi ; \
+ if [ x$(DEMANGLER_PROG) != x ] && [ -x "$(DEMANGLER_PROG)" ]; then \
+ if [ -f g++-cross$(exeext) ] ; then \
+ rm -f $(bindir)/$(DEMANGLER_CROSS_NAME)$(exeext); \
+ $(INSTALL_PROGRAM) $(DEMANGLER_PROG) $(bindir)/$(DEMANGLER_CROSS_NAME)$(exeext); \
+ chmod a+x $(bindir)/$(DEMANGLER_CROSS_NAME)$(exeext); \
+ else \
+ rm -f $(bindir)/$(DEMANGLER_INSTALL_NAME)$(exeext); \
+ $(INSTALL_PROGRAM) $(DEMANGLER_PROG) $(bindir)/$(DEMANGLER_INSTALL_NAME)$(exeext); \
+ chmod a+x $(bindir)/$(DEMANGLER_INSTALL_NAME)$(exeext); \
+ fi ; \
fi ; \
fi
@@ -155,9 +261,11 @@ c++.uninstall:
-rm -rf $(bindir)/$(CXX_CROSS_NAME)$(exeext)
-rm -rf $(bindir)/$(GXX_INSTALL_NAME)$(exeext)
-rm -rf $(bindir)/$(GXX_CROSS_NAME)$(exeext)
+ -rm -rf $(bindir)/$(DEMANGLER_INSTALL_NAME)$(exeext)
+ -rm -rf $(bindir)/$(DEMANGLER_CROSS_NAME)$(exeext)
-rm -rf $(mandir)/$(GXX_INSTALL_NAME)$(manext)
-rm -rf $(mandir)/$(GXX_CROSS_NAME)$(manext)
-
+#
# Clean hooks:
# A lot of the ancillary files are deleted by the main makefile.
# We just have to delete files specific to us.
@@ -165,33 +273,41 @@ c++.uninstall:
c++.mostlyclean:
-rm -f cp/*$(objext) $(DEMANGLER_PROG)
c++.clean:
+ -rm -f cplib2.txt cplib2.ready
c++.distclean:
-rm -f cp/config.status cp/Makefile
-rm -f cp/parse.output
+ -rm -f g++.c
c++.extraclean:
c++.maintainer-clean:
-rm -f cp/parse.c cp/parse.h
-
+#
# Stage hooks:
# The main makefile has already created stage?/cp.
-c++.stage1:
+c++.stage1: stage1-start
-mv cp/*$(objext) stage1/cp
-c++.stage2:
+c++.stage2: stage2-start
-mv cp/*$(objext) stage2/cp
-c++.stage3:
+c++.stage3: stage3-start
-mv cp/*$(objext) stage3/cp
-c++.stage4:
+c++.stage4: stage4-start
-mv cp/*$(objext) stage4/cp
-
+#
# Maintenance hooks:
# This target creates the files that can be rebuilt, but go in the
# distribution anyway. It then copies the files to the distdir directory.
c++.distdir:
mkdir tmp/cp
+ mkdir tmp/cp/inc
cd cp ; $(MAKE) $(FLAGS_TO_PASS) $(CXX_FLAGS_TO_PASS) parse.c hash.h
cd cp; \
for file in *[0-9a-zA-Z+]; do \
- ln $$file ../tmp/cp >/dev/null 2>&1 || cp $$file ../tmp/cp; \
+ $(LN) $$file ../tmp/cp; \
+ done
+ cd cp/inc; \
+ for file in *[0-9a-zA-Z+]; do \
+ ln $$file ../../tmp/cp/inc >/dev/null 2>&1 \
+ || cp $$file ../../tmp/cp/inc; \
done
diff --git a/contrib/gcc/cp/Makefile.in b/contrib/gcc/cp/Makefile.in
index 11466b2..8d7098d 100644
--- a/contrib/gcc/cp/Makefile.in
+++ b/contrib/gcc/cp/Makefile.in
@@ -1,5 +1,5 @@
# Makefile for GNU C++ compiler.
-# Copyright (C) 1987, 88, 90-4, 1995 Free Software Foundation, Inc.
+# Copyright (C) 1987, 88, 90-5, 1998 Free Software Foundation, Inc.
#This file is part of GNU CC.
@@ -54,10 +54,10 @@ T_CFLAGS =
X_CPPFLAGS =
T_CPPFLAGS =
-CC = cc
-BISON = bison
+CC = @CC@
+BBISON = `if [ -f ../../bison/bison ] ; then echo ../../bison/bison -L $(srcdir)/../../bison/ ; else echo bison ; fi`
BISONFLAGS =
-LEX = flex
+LEX = `if [ -f ../../flex/flex ] ; then echo ../../flex/flex ; else echo flex ; fi`
LEXFLAGS =
AR = ar
AR_FLAGS = rc
@@ -83,14 +83,21 @@ GCC_CFLAGS=$(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS)
# These are used because `configure' appends `cross-make'
# to the makefile when making a cross-compiler.
-target= ... `configure' substitutes actual target name here.
-xmake_file= ... `configure' substitutes actual x- file name here.
-tmake_file= ... `configure' substitutes actual t- file name here.
+# We don't use cross-make. Instead we use the tools
+# from the build tree, if they are available.
+# program_transform_name and objdir are set by configure.in.
+program_transform_name =
+objdir = .
+
+target=@target@
+xmake_file=@dep_host_xmake_file@
+tmake_file=@dep_tmake_file@
#version=`sed -e 's/.*\"\([^ \"]*\)[ \"].*/\1/' < $(srcdir)/version.c`
#mainversion=`sed -e 's/.*\"\([0-9]*\.[0-9]*\).*/\1/' < $(srcdir)/version.c`
# Directory where sources are, from where we are.
-srcdir = .
+srcdir = @srcdir@
+VPATH = @srcdir@
# Additional system libraries to link with.
CLIB=
@@ -113,16 +120,21 @@ all: all.indirect
# sed inserts variable overrides after the following line.
####target overrides
+@target_overrides@
####host overrides
+@host_overrides@
####cross overrides
+@cross_defines@
+@cross_overrides@
####build overrides
-
+@build_overrides@
+#
# Now figure out from those variables how to compile and link.
-all.indirect: Makefile ../cc1plus
+all.indirect: Makefile ../cc1plus$(exeext)
# IN_GCC tells obstack.h that we are using gcc's <stddef.h> file.
-INTERNAL_CFLAGS = $(CROSS) -DIN_GCC
+INTERNAL_CFLAGS = $(CROSS) -DIN_GCC @extra_c_flags@
# This is the variable actually used when we compile.
ALL_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS)
@@ -150,33 +162,37 @@ INCLUDES = -I. -I.. -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../config
.c.o:
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
+# The only suffixes we want for implicit rules are .c and .o.
+.SUFFIXES:
+.SUFFIXES: .c .o
+
# This tells GNU make version 3 not to export all the variables
# defined in this file into the environment.
.NOEXPORT:
-
+#
# Lists of files for various purposes.
# Language-specific object files for g++
CXX_OBJS = call.o decl.o errfn.o expr.o pt.o sig.o typeck2.o \
- class.o decl2.o error.o gc.o lex.o parse.o ptree.o spew.o typeck.o cvt.o \
- edsel.o except.o init.o method.o search.o tree.o xref.o repo.o
+ class.o decl2.o error.o lex.o parse.o ptree.o rtti.o spew.o typeck.o cvt.o \
+ except.o friend.o init.o method.o search.o semantics.o tree.o xref.o \
+ repo.o @extra_cxx_objs@
# Language-independent object files.
OBJS = `cat ../stamp-objlist` ../c-common.o ../c-pragma.o
OBJDEPS = ../stamp-objlist ../c-common.o ../c-pragma.o
-compiler: ../cc1plus
-../cc1plus: $(P) $(CXX_OBJS) $(OBJDEPS) $(LIBDEPS)
- rm -f ../cc1plus$(exeext)
+compiler: ../cc1plus$(exeext)
+../cc1plus$(exeext): $(P) $(CXX_OBJS) $(OBJDEPS) $(LIBDEPS)
$(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \
$(CXX_OBJS) $(OBJS) $(LIBS)
Makefile: $(srcdir)/Makefile.in $(srcdir)/../configure
cd ..; $(SHELL) config.status
-native: config.status ../cc1plus
-
+native: config.status ../cc1plus$(exeext)
+#
# Compiling object files from source files.
# Note that dependencies on obstack.h are not written
@@ -188,15 +204,18 @@ RTL_H = $(srcdir)/../rtl.h $(srcdir)/../rtl.def \
$(srcdir)/../machmode.h $(srcdir)/../machmode.def
TREE_H = $(srcdir)/../tree.h $(srcdir)/../real.h $(srcdir)/../tree.def \
$(srcdir)/../machmode.h $(srcdir)/../machmode.def
-CXX_TREE_H = $(TREE_H) cp-tree.h tree.def
+CXX_TREE_H = $(TREE_H) cp-tree.h cp-tree.def
PARSE_H = $(srcdir)/parse.h
PARSE_C = $(srcdir)/parse.c
+EXPR_H = $(srcdir)/../expr.h ../insn-codes.h
-parse.o : $(PARSE_C) $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h lex.h
+parse.o : $(PARSE_C) $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h lex.h \
+ $(srcdir)/../except.h $(srcdir)/../output.h $(srcdir)/../system.h \
+ $(srcdir)/../toplev.h
$(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(BIG_SWITCHFLAG) \
`echo $(PARSE_C) | sed 's,^\./,,'`
-CONFLICTS = expect 5 shift/reduce conflicts and 38 reduce/reduce conflicts.
+CONFLICTS = expect 26 shift/reduce conflicts and 42 reduce/reduce conflicts.
$(PARSE_H) : $(PARSE_C)
$(PARSE_C) : $(srcdir)/parse.y
@echo $(CONFLICTS)
@@ -221,35 +240,61 @@ $(srcdir)/hash.h:
$(srcdir)/gxx.gperf >$(srcdir)/hash.h
spew.o : spew.c $(CONFIG_H) $(CXX_TREE_H) \
- $(PARSE_H) $(srcdir)/../flags.h lex.h
+ $(PARSE_H) $(srcdir)/../flags.h lex.h $(srcdir)/../system.h
lex.o : lex.c $(CONFIG_H) $(CXX_TREE_H) \
- $(PARSE_H) input.c $(srcdir)/../flags.h hash.h lex.h $(srcdir)/../c-pragma.h
+ $(PARSE_H) input.c $(srcdir)/../flags.h hash.h lex.h \
+ $(srcdir)/../c-pragma.h $(srcdir)/../system.h $(srcdir)/../toplev.h \
+ $(srcdir)/../output.h
decl.o : decl.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
- lex.h decl.h $(srcdir)/../stack.h
+ lex.h decl.h $(srcdir)/../stack.h $(srcdir)/../output.h \
+ $(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h
decl2.o : decl2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
- lex.h decl.h
-typeck2.o : typeck2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h
-typeck.o : typeck.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H)
-class.o : class.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h
-call.o : call.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h class.h
-init.o : init.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H)
-method.o : method.c $(CONFIG_H) $(CXX_TREE_H) class.h
-cvt.o : cvt.c $(CONFIG_H) $(CXX_TREE_H) class.h
-search.o : search.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../stack.h $(srcdir)/../flags.h
-tree.o : tree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h
-ptree.o : ptree.c $(CONFIG_H) $(CXX_TREE_H)
-gc.o : gc.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h
-except.o : except.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H)
+ lex.h decl.h $(EXPR_H) $(srcdir)/../except.h \
+ $(srcdir)/../output.h $(srcdir)/../except.h $(srcdir)/../system.h \
+ $(srcdir)/../toplev.h $(srcdir)/../dwarf2out.h $(srcdir)/../dwarfout.h
+typeck2.o : typeck2.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
+ $(srcdir)/../system.h $(srcdir)/../toplev.h
+typeck.o : typeck.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
+ $(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h
+class.o : class.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
+ $(srcdir)/../system.h $(srcdir)/../toplev.h
+call.o : call.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
+ $(srcdir)/../system.h $(srcdir)/../toplev.h
+friend.o : friend.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
+ $(srcdir)/../system.h $(srcdir)/../toplev.h
+init.o : init.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
+ $(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h
+method.o : method.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
+ $(srcdir)/../toplev.h
+cvt.o : cvt.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h
+search.o : search.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../stack.h \
+ $(srcdir)/../flags.h $(srcdir)/../system.h $(srcdir)/../toplev.h
+tree.o : tree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
+ $(srcdir)/../system.h $(srcdir)/../toplev.h
+ptree.o : ptree.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h
+rtti.o : rtti.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
+ $(srcdir)/../system.h $(srcdir)/../toplev.h
+except.o : except.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h $(RTL_H) \
+ $(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h
expr.o : expr.c $(CONFIG_H) $(CXX_TREE_H) $(RTL_H) $(srcdir)/../flags.h \
- $(srcdir)/../expr.h ../insn-codes.h
-edsel.o : edsel.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../stack.h $(srcdir)/../flags.h
-xref.o : xref.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../input.h
-pt.o : pt.c $(CONFIG_H) $(CXX_TREE_H) decl.h $(PARSE_H)
-error.o : error.c $(CONFIG_H) $(CXX_TREE_H)
-errfn.o : errfn.c $(CONFIG_H) $(CXX_TREE_H)
-sig.o : sig.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h
-repo.o : repo.c $(CONFIG_H) $(CXX_TREE_H)
-
+ $(EXPR_H) $(srcdir)/../system.h $(srcdir)/../toplev.h
+xref.o : xref.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../input.h \
+ $(srcdir)/../system.h $(srcdir)/../toplev.h
+pt.o : pt.c $(CONFIG_H) $(CXX_TREE_H) decl.h $(PARSE_H) lex.h \
+ $(srcdir)/../system.h $(srcdir)/../toplev.h
+error.o : error.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
+ $(srcdir)/../toplev.h
+errfn.o : errfn.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
+ $(srcdir)/../toplev.h
+sig.o : sig.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../flags.h \
+ $(srcdir)/../system.h $(srcdir)/../toplev.h
+repo.o : repo.c $(CONFIG_H) $(CXX_TREE_H) $(srcdir)/../system.h \
+ $(srcdir)/../toplev.h
+semantics.o: semantics.c $(CONFIG_H) $(CXX_TREE_H) lex.h \
+ $(srcdir)/../except.h $(srcdir)/../system.h $(srcdir)/../toplev.h
+
+
+#
# These exist for maintenance purposes.
# Update the tags table.
@@ -263,3 +308,32 @@ TAGS: force
.PHONY: TAGS
force:
+
+g++FAQ.info: $(srcdir)/g++FAQ.texi
+ $(MAKEINFO) --no-split -o ./g++FAQ.info $(srcdir)/g++FAQ.texi
+
+# Preprocess the texi file so that the final document will have
+# hyperlinks.
+# It would be nice if texi2html could do something like this itself.
+
+# Assumption 1: the FAQ puts all http: and ftp: links in a @file{...}.
+# Assumption 2: newsgroups are like @file{comp.foo}
+# Assumption 3: email addresses match the regexp shown.
+
+g++FAQ.html: $(srcdir)/g++FAQ.texi
+ mkdir work
+ sed -e 's?@file{\([fth]*p://[^}]*\)}?@strong{<A HREF="\1">\1</A>}?' \
+ -e 's?@file{\(comp\.[-a-z+.]*\)}?<A HREF="news:\1">\1</A>?' \
+ -e 's?@file{\(gnu\.[-a-z+.]*\)}?<A HREF="news:\1">\1</A>?' \
+ -e 's?\([.+a-zA-Z0-9-]*@@[.a-zA-Z0-9-]*[a-zA-Z0-9]\)?<A HREF="mailto:\1">\1</A>?' \
+ $(srcdir)/g++FAQ.texi > work/g++FAQ.texi
+ cd work; texi2html g++FAQ.texi
+ mv work/*.html .
+ rm -r work
+
+# Make plain-text form.
+
+g++FAQ.txt: $(srcdir)/g++FAQ.texi
+ $(MAKEINFO) --no-split --no-headers -o - $(srcdir)/g++FAQ.texi |\
+ sed '/^Concept Index/,$$d' > g++FAQ.txt
+
diff --git a/contrib/gcc/cp/NEWS b/contrib/gcc/cp/NEWS
new file mode 100644
index 0000000..9cb7d5b
--- /dev/null
+++ b/contrib/gcc/cp/NEWS
@@ -0,0 +1,226 @@
+*** Changes in EGCS 1.1:
+
+* Namespaces are fully supported. The library has not yet been converted
+ to use namespace std, however, and the old std-faking code is still on by
+ default. To turn it off, you can use -fhonor-std.
+
+* Massive template improvements:
+ + member template classes are supported.
+ + template friends are supported.
+ + template template parameters are supported.
+ + local classes in templates are supported.
+ + lots of bugs fixed.
+
+* operator new now throws bad_alloc where appropriate.
+
+* Exception handling is now thread safe, and supports nested exceptions and
+ placement delete. Exception handling overhead on x86 is much lower with
+ GNU as 2.9.
+
+* protected virtual inheritance is now supported.
+
+* Loops are optimized better; we now move the test to the end in most
+ cases, like the C frontend does.
+
+* For class D derived from B which has a member 'int i', &D::i is now of
+ type 'int B::*' instead of 'int D::*'.
+
+* An _experimental_ new ABI for g++ can be turned on with -fnew-abi. The
+ current features of this are more efficient allocation of base classes
+ (including the empty base optimization), and more compact mangling of C++
+ symbol names (which can be turned on separately with -fsquangle). This
+ ABI is subject to change without notice, so don't use it for anything
+ that you don't want to rebuild with every release of the compiler.
+
+ As with all ABI-changing flags, this flag is for experts only, as all
+ code (including the library code in libgcc and libstdc++) must be
+ compiled with the same ABI.
+
+*** Changes in EGCS 1.0:
+
+* A public review copy of the December 1996 Draft of the ISO/ANSI C++
+ standard is now available. See
+
+ http://www.cygnus.com/misc/wp/
+
+ for more information.
+
+* g++ now uses a new implementation of templates. The basic idea is that
+ now templates are minimally parsed when seen and then expanded later.
+ This allows conformant early name binding and instantiation controls,
+ since instantiations no longer have to go through the parser.
+
+ What you get:
+
+ + Inlining of template functions works without any extra effort or
+ modifications.
+ + Instantiations of class templates and methods defined in the class
+ body are deferred until they are actually needed (unless
+ -fexternal-templates is specified).
+ + Nested types in class templates work.
+ + Static data member templates work.
+ + Member function templates are now supported.
+ + Partial specialization of class templates is now supported.
+ + Explicit specification of template parameters to function templates
+ is now supported.
+
+ Things you may need to fix in your code:
+
+ + Syntax errors in templates that are never instantiated will now be
+ diagnosed.
+ + Types and class templates used in templates must be declared
+ first, or the compiler will assume they are not types, and fail.
+ + Similarly, nested types of template type parameters must be tagged
+ with the 'typename' keyword, except in base lists. In many cases,
+ but not all, the compiler will tell you where you need to add
+ 'typename'. For more information, see
+
+ http://www.cygnus.com/misc/wp/dec96pub/template.html#temp.res
+
+ + Guiding declarations are no longer supported. Function declarations,
+ including friend declarations, do not refer to template instantiations.
+ You can restore the old behavior with -fguiding-decls until you fix
+ your code.
+
+ Other features:
+
+ + Default function arguments in templates will not be evaluated (or
+ checked for semantic validity) unless they are needed. Default
+ arguments in class bodies will not be parsed until the class
+ definition is complete.
+ + The -ftemplate-depth-NN flag can be used to increase the maximum
+ recursive template instantiation depth, which defaults to 17. If you
+ need to use this flag, the compiler will tell you.
+ + Explicit instantiation of template constructors and destructors is
+ now supported. For instance:
+
+ template A<int>::A(const A&);
+
+ Still not supported:
+
+ + Member class templates.
+ + Template friends.
+
+* Exception handling support has been significantly improved and is on by
+ default. The compiler supports two mechanisms for walking back up the
+ call stack; one relies on static information about how registers are
+ saved, and causes no runtime overhead for code that does not throw
+ exceptions. The other mechanism uses setjmp and longjmp equivalents, and
+ can result in quite a bit of runtime overhead. You can determine which
+ mechanism is the default for your target by compiling a testcase that
+ uses exceptions and doing an 'nm' on the object file; if it uses __throw,
+ it's using the first mechanism. If it uses __sjthrow, it's using the
+ second.
+
+ You can turn EH support off with -fno-exceptions.
+
+* RTTI support has been rewritten to work properly and is now on by default.
+ This means code that uses virtual functions will have a modest space
+ overhead. You can use the -fno-rtti flag to disable RTTI support.
+
+* On ELF systems, duplicate copies of symbols with 'initialized common'
+ linkage (such as template instantiations, vtables, and extern inlines)
+ will now be discarded by the GNU linker, so you don't need to use -frepo.
+ This support requires GNU ld from binutils 2.8 or later.
+
+* The overload resolution code has been rewritten to conform to the latest
+ C++ Working Paper. Built-in operators are now considered as candidates
+ in operator overload resolution. Function template overloading chooses
+ the more specialized template, and handles base classes in type deduction
+ and guiding declarations properly. In this release the old code can
+ still be selected with -fno-ansi-overloading, although this is not
+ supported and will be removed in a future release.
+
+* Standard usage syntax for the std namespace is supported; std is treated
+ as an alias for global scope. General namespaces are still not supported.
+
+* New flags:
+
+ + New warning -Wno-pmf-conversion (don't warn about
+ converting from a bound member function pointer to function
+ pointer).
+
+ + A flag -Weffc++ has been added for violations of some of the style
+ guidelines in Scott Meyers' _Effective C++_ books.
+
+ + -Woverloaded-virtual now warns if a virtual function in a base
+ class is hidden in a derived class, rather than warning about
+ virtual functions being overloaded (even if all of the inherited
+ signatures are overridden) as it did before.
+
+ + -Wall no longer implies -W. The new warning flag, -Wsign-compare,
+ included in -Wall, warns about dangerous comparisons of signed and
+ unsigned values. Only the flag is new; it was previously part of
+ -W.
+
+ + The new flag, -fno-weak, disables the use of weak symbols.
+
+* Synthesized methods are now emitted in any translation units that need
+ an out-of-line copy. They are no longer affected by #pragma interface
+ or #pragma implementation.
+
+* __FUNCTION__ and __PRETTY_FUNCTION__ are now treated as variables by the
+ parser; previously they were treated as string constants. So code like
+ `printf (__FUNCTION__ ": foo")' must be rewritten to
+ `printf ("%s: foo", __FUNCTION__)'. This is necessary for templates.
+
+* local static variables in extern inline functions will be shared between
+ translation units.
+
+* -fvtable-thunks is supported for all targets, and is the default for
+ Linux with glibc 2.x (also called libc 6.x).
+
+* bool is now always the same size as another built-in type. Previously,
+ a 64-bit RISC target using a 32-bit ABI would have 32-bit pointers and a
+ 64-bit bool. This should only affect Irix 6, which was not supported in
+ 2.7.2.
+
+* new (nothrow) is now supported.
+
+* Synthesized destructors are no longer made virtual just because the class
+ already has virtual functions, only if they override a virtual destructor
+ in a base class. The compiler will warn if this affects your code.
+
+* The g++ driver now only links against libstdc++, not libg++; it is
+ functionally identical to the c++ driver.
+
+* (void *)0 is no longer considered a null pointer constant; NULL in
+ <stddef.h> is now defined as __null, a magic constant of type (void *)
+ normally, or (size_t) with -ansi.
+
+* The name of a class is now implicitly declared in its own scope; A::A
+ refers to A.
+
+* Local classes are now supported.
+
+* __attribute__ can now be attached to types as well as declarations.
+
+* The compiler no longer emits a warning if an ellipsis is used as a
+ function's argument list.
+
+* Definition of nested types outside of their containing class is now
+ supported. For instance:
+
+ struct A {
+ struct B;
+ B* bp;
+ };
+
+ struct A::B {
+ int member;
+ };
+
+* On the HPPA, some classes that do not define a copy constructor
+ will be passed and returned in memory again so that functions
+ returning those types can be inlined.
+
+*** The g++ team thanks everyone that contributed to this release,
+ but especially:
+
+* Joe Buck <jbuck@synopsys.com>, the maintainer of the g++ FAQ.
+* Brendan Kehoe <brendan@cygnus.com>, who coordinates testing of g++.
+* Jason Merrill <jason@cygnus.com>, the g++ maintainer.
+* Mark Mitchell <mmitchell@usa.net>, who implemented member function
+ templates and explicit qualification of function templates.
+* Mike Stump <mrs@wrs.com>, the previous g++ maintainer, who did most of
+ the exception handling work.
diff --git a/contrib/gcc/cp/call.c b/contrib/gcc/cp/call.c
index 3f293ac..e65898e 100644
--- a/contrib/gcc/cp/call.c
+++ b/contrib/gcc/cp/call.c
@@ -1,7 +1,7 @@
/* Functions related to invoking methods and overloaded functions.
- Copyright (C) 1987, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 92-97, 1998 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com) and
- hacked by Brendan Kehoe (brendan@cygnus.com).
+ modified by Brendan Kehoe (brendan@cygnus.com).
This file is part of GNU CC.
@@ -21,1188 +21,75 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* High-level class interface. */
+/* High-level class interface. */
#include "config.h"
+#include "system.h"
#include "tree.h"
-#include <stdio.h>
#include "cp-tree.h"
-#include "class.h"
#include "output.h"
#include "flags.h"
+#include "rtl.h"
+#include "toplev.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void sorry ();
-
extern int inhibit_warnings;
-extern int flag_assume_nonnull_objects;
extern tree ctor_label, dtor_label;
-/* From typeck.c: */
-extern tree unary_complex_lvalue ();
-
-/* Compute the ease with which a conversion can be performed
- between an expected and the given type. */
-static struct harshness_code convert_harshness ();
-
-#define EVIL_RETURN(ARG) ((ARG).code = EVIL_CODE, (ARG))
-#define STD_RETURN(ARG) ((ARG).code = STD_CODE, (ARG))
-#define QUAL_RETURN(ARG) ((ARG).code = QUAL_CODE, (ARG))
-#define TRIVIAL_RETURN(ARG) ((ARG).code = TRIVIAL_CODE, (ARG))
-#define ZERO_RETURN(ARG) ((ARG).code = 0, (ARG))
-
-/* Ordering function for overload resolution. Compare two candidates
- by gross quality. */
-int
-rank_for_overload (x, y)
- struct candidate *x, *y;
-{
- if (y->h.code & (EVIL_CODE|ELLIPSIS_CODE|USER_CODE))
- return y->h.code - x->h.code;
- if (x->h.code & (EVIL_CODE|ELLIPSIS_CODE|USER_CODE))
- return -1;
-
- /* This is set by compute_conversion_costs, for calling a non-const
- member function from a const member function. */
- if ((y->harshness[0].code & CONST_CODE) ^ (x->harshness[0].code & CONST_CODE))
- return y->harshness[0].code - x->harshness[0].code;
-
- if (y->h.code & STD_CODE)
- {
- if (x->h.code & STD_CODE)
- return y->h.distance - x->h.distance;
- return 1;
- }
- if (x->h.code & STD_CODE)
- return -1;
-
- return y->h.code - x->h.code;
-}
-
-/* Compare two candidates, argument by argument. */
-int
-rank_for_ideal (x, y)
- struct candidate *x, *y;
-{
- int i;
-
- if (x->h_len != y->h_len)
- abort ();
-
- for (i = 0; i < x->h_len; i++)
- {
- if (y->harshness[i].code - x->harshness[i].code)
- return y->harshness[i].code - x->harshness[i].code;
- if ((y->harshness[i].code & STD_CODE)
- && (y->harshness[i].distance - x->harshness[i].distance))
- return y->harshness[i].distance - x->harshness[i].distance;
-
- /* They're both the same code. Now see if we're dealing with an
- integral promotion that needs a finer grain of accuracy. */
- if (y->harshness[0].code & PROMO_CODE
- && (y->harshness[i].int_penalty ^ x->harshness[i].int_penalty))
- return y->harshness[i].int_penalty - x->harshness[i].int_penalty;
- }
- return 0;
-}
-
-/* TYPE is the type we wish to convert to. PARM is the parameter
- we have to work with. We use a somewhat arbitrary cost function
- to measure this conversion. */
-static struct harshness_code
-convert_harshness (type, parmtype, parm)
- register tree type, parmtype;
- tree parm;
-{
- struct harshness_code h;
- register enum tree_code codel;
- register enum tree_code coder;
- int lvalue;
-
- h.code = 0;
- h.distance = 0;
- h.int_penalty = 0;
-
-#ifdef GATHER_STATISTICS
- n_convert_harshness++;
-#endif
-
- if (TREE_CODE (parmtype) == REFERENCE_TYPE)
- {
- if (parm)
- parm = convert_from_reference (parm);
- parmtype = TREE_TYPE (parmtype);
- lvalue = 1;
- }
- else if (parm)
- lvalue = lvalue_p (parm);
- else
- lvalue = 0;
-
- if (TYPE_PTRMEMFUNC_P (type))
- type = TYPE_PTRMEMFUNC_FN_TYPE (type);
- if (TYPE_PTRMEMFUNC_P (parmtype))
- parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype);
-
- codel = TREE_CODE (type);
- coder = TREE_CODE (parmtype);
-
- if (TYPE_MAIN_VARIANT (parmtype) == TYPE_MAIN_VARIANT (type))
- return ZERO_RETURN (h);
-
- if (coder == ERROR_MARK)
- return EVIL_RETURN (h);
-
- if (codel == REFERENCE_TYPE)
- {
- tree ttl, ttr;
- int constp = parm ? TREE_READONLY (parm) : TYPE_READONLY (parmtype);
- int volatilep = (parm ? TREE_THIS_VOLATILE (parm)
- : TYPE_VOLATILE (parmtype));
- register tree intype = TYPE_MAIN_VARIANT (parmtype);
- register enum tree_code form = TREE_CODE (intype);
- int penalty = 0;
-
- ttl = TREE_TYPE (type);
-
- /* Only allow const reference binding if we were given a parm to deal
- with, since it isn't really a conversion. This is a hack to
- prevent build_type_conversion from finding this conversion, but
- still allow overloading to find it. */
- if (! lvalue && ! (parm && TYPE_READONLY (ttl)))
- return EVIL_RETURN (h);
-
- if (TYPE_READONLY (ttl) < constp
- || TYPE_VOLATILE (ttl) < volatilep)
- return EVIL_RETURN (h);
-
- /* When passing a non-const argument into a const reference, dig it a
- little, so a non-const reference is preferred over this one. */
- penalty = ((TYPE_READONLY (ttl) > constp)
- + (TYPE_VOLATILE (ttl) > volatilep));
-
- ttl = TYPE_MAIN_VARIANT (ttl);
-
- if (form == OFFSET_TYPE)
- {
- intype = TREE_TYPE (intype);
- form = TREE_CODE (intype);
- }
-
- ttr = intype;
-
- if (TREE_CODE (ttl) == ARRAY_TYPE && TREE_CODE (ttr) == ARRAY_TYPE)
- {
- if (comptypes (ttl, ttr, 1))
- return ZERO_RETURN (h);
- return EVIL_RETURN (h);
- }
-
- h = convert_harshness (ttl, ttr, NULL_TREE);
- if (penalty && h.code == 0)
- {
- h.code = QUAL_CODE;
- h.int_penalty = penalty;
- }
- return h;
- }
-
- if (codel == POINTER_TYPE && fntype_p (parmtype))
- {
- tree p1, p2;
- struct harshness_code h1, h2;
-
- /* Get to the METHOD_TYPE or FUNCTION_TYPE that this might be. */
- type = TREE_TYPE (type);
-
- if (coder == POINTER_TYPE)
- {
- parmtype = TREE_TYPE (parmtype);
- coder = TREE_CODE (parmtype);
- }
-
- if (coder != TREE_CODE (type))
- return EVIL_RETURN (h);
-
- if (type != parmtype && coder == METHOD_TYPE)
- {
- tree ttl = TYPE_METHOD_BASETYPE (type);
- tree ttr = TYPE_METHOD_BASETYPE (parmtype);
-
- int b_or_d = get_base_distance (ttr, ttl, 0, 0);
- if (b_or_d < 0)
- {
- b_or_d = get_base_distance (ttl, ttr, 0, 0);
- if (b_or_d < 0)
- return EVIL_RETURN (h);
- h.distance = -b_or_d;
- }
- else
- h.distance = b_or_d;
- h.code = STD_CODE;
-
- type = build_function_type
- (TREE_TYPE (type), TREE_CHAIN (TYPE_ARG_TYPES (type)));
- parmtype = build_function_type
- (TREE_TYPE (parmtype), TREE_CHAIN (TYPE_ARG_TYPES (parmtype)));
- }
-
- /* We allow the default conversion between function type
- and pointer-to-function type for free. */
- if (comptypes (type, parmtype, 1))
- return h;
-
- if (pedantic)
- return EVIL_RETURN (h);
-
- /* Compare return types. */
- p1 = TREE_TYPE (type);
- p2 = TREE_TYPE (parmtype);
- h2 = convert_harshness (p1, p2, NULL_TREE);
- if (h2.code & EVIL_CODE)
- return h2;
-
- h1.code = TRIVIAL_CODE;
- h1.distance = 0;
-
- if (h2.distance != 0)
- {
- tree binfo;
-
- /* This only works for pointers. */
- if (TREE_CODE (p1) != POINTER_TYPE
- && TREE_CODE (p1) != REFERENCE_TYPE)
- return EVIL_RETURN (h);
-
- p1 = TREE_TYPE (p1);
- p2 = TREE_TYPE (p2);
- /* Don't die if we happen to be dealing with void*. */
- if (!IS_AGGR_TYPE (p1) || !IS_AGGR_TYPE (p2))
- return EVIL_RETURN (h);
- if (h2.distance < 0)
- binfo = get_binfo (p2, p1, 0);
- else
- binfo = get_binfo (p1, p2, 0);
-
- if (! BINFO_OFFSET_ZEROP (binfo))
- {
-#if 0
- static int explained = 0;
- if (h2.distance < 0)
- message_2_types (sorry, "cannot cast `%s' to `%s' at function call site", p2, p1);
- else
- message_2_types (sorry, "cannot cast `%s' to `%s' at function call site", p1, p2);
-
- if (! explained++)
- sorry ("(because pointer values change during conversion)");
-#endif
- return EVIL_RETURN (h);
- }
- }
-
- h1.code |= h2.code;
- if (h2.distance > h1.distance)
- h1.distance = h2.distance;
-
- p1 = TYPE_ARG_TYPES (type);
- p2 = TYPE_ARG_TYPES (parmtype);
- while (p1 && TREE_VALUE (p1) != void_type_node
- && p2 && TREE_VALUE (p2) != void_type_node)
- {
- h2 = convert_harshness (TREE_VALUE (p1), TREE_VALUE (p2),
- NULL_TREE);
- if (h2.code & EVIL_CODE)
- return h2;
-
- if (h2.distance)
- {
- /* This only works for pointers and references. */
- if (TREE_CODE (TREE_VALUE (p1)) != POINTER_TYPE
- && TREE_CODE (TREE_VALUE (p1)) != REFERENCE_TYPE)
- return EVIL_RETURN (h);
- h2.distance = - h2.distance;
- }
-
- h1.code |= h2.code;
- if (h2.distance > h1.distance)
- h1.distance = h2.distance;
- p1 = TREE_CHAIN (p1);
- p2 = TREE_CHAIN (p2);
- }
- if (p1 == p2)
- return h1;
- if (p2)
- {
- if (p1)
- return EVIL_RETURN (h);
- h1.code |= ELLIPSIS_CODE;
- return h1;
- }
- if (p1)
- {
- if (TREE_PURPOSE (p1) == NULL_TREE)
- h1.code |= EVIL_CODE;
- return h1;
- }
- }
- else if (codel == POINTER_TYPE && coder == OFFSET_TYPE)
- {
- tree ttl, ttr;
-
- /* Get to the OFFSET_TYPE that this might be. */
- type = TREE_TYPE (type);
-
- if (coder != TREE_CODE (type))
- return EVIL_RETURN (h);
-
- ttl = TYPE_OFFSET_BASETYPE (type);
- ttr = TYPE_OFFSET_BASETYPE (parmtype);
-
- if (ttl == ttr)
- h.code = 0;
- else
- {
- int b_or_d = get_base_distance (ttr, ttl, 0, 0);
- if (b_or_d < 0)
- {
- b_or_d = get_base_distance (ttl, ttr, 0, 0);
- if (b_or_d < 0)
- return EVIL_RETURN (h);
- h.distance = -b_or_d;
- }
- else
- h.distance = b_or_d;
- h.code = STD_CODE;
- }
-
- /* Now test the OFFSET_TYPE's target compatibility. */
- type = TREE_TYPE (type);
- parmtype = TREE_TYPE (parmtype);
- }
-
- if (coder == UNKNOWN_TYPE)
- {
- if (codel == FUNCTION_TYPE
- || codel == METHOD_TYPE
- || (codel == POINTER_TYPE
- && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)))
- return TRIVIAL_RETURN (h);
- return EVIL_RETURN (h);
- }
-
- if (coder == VOID_TYPE)
- return EVIL_RETURN (h);
-
- if (codel == BOOLEAN_TYPE)
- {
- if (INTEGRAL_CODE_P (coder) || coder == REAL_TYPE)
- return STD_RETURN (h);
- else if (coder == POINTER_TYPE || coder == OFFSET_TYPE)
- {
- /* Make this worse than any conversion to another pointer.
- FIXME this is how I think the language should work, but it may not
- end up being how the language is standardized (jason 1/30/95). */
- h.distance = 32767;
- return STD_RETURN (h);
- }
- return EVIL_RETURN (h);
- }
-
- if (INTEGRAL_CODE_P (codel))
- {
- /* Control equivalence of ints an enums. */
-
- if (codel == ENUMERAL_TYPE
- && flag_int_enum_equivalence == 0)
- {
- /* Enums can be converted to ints, but not vice-versa. */
- if (coder != ENUMERAL_TYPE
- || TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (parmtype))
- return EVIL_RETURN (h);
- }
-
- /* else enums and ints (almost) freely interconvert. */
-
- if (INTEGRAL_CODE_P (coder))
- {
- if (TYPE_MAIN_VARIANT (type)
- == TYPE_MAIN_VARIANT (type_promotes_to (parmtype)))
- {
- h.code = PROMO_CODE;
-#if 0 /* What purpose does this serve? -jason */
- /* A char, short, wchar_t, etc., should promote to an int if
- it can handle it, otherwise to an unsigned. So we'll make
- an unsigned. */
- if (type != integer_type_node)
- h.int_penalty = 1;
-#endif
- }
- else
- h.code = STD_CODE;
-
- return h;
- }
- else if (coder == REAL_TYPE)
- {
- h.code = STD_CODE;
- h.distance = 0;
- return h;
- }
- }
-
- if (codel == REAL_TYPE)
- {
- if (coder == REAL_TYPE)
- {
- if (TYPE_MAIN_VARIANT (type)
- == TYPE_MAIN_VARIANT (type_promotes_to (parmtype)))
- h.code = PROMO_CODE;
- else
- h.code = STD_CODE;
-
- return h;
- }
- else if (INTEGRAL_CODE_P (coder))
- {
- h.code = STD_CODE;
- h.distance = 0;
- return h;
- }
- }
-
- /* Convert arrays which have not previously been converted. */
-#if 0
- if (codel == ARRAY_TYPE)
- codel = POINTER_TYPE;
-#endif
- if (coder == ARRAY_TYPE)
- {
- coder = POINTER_TYPE;
- if (parm)
- {
- parm = decay_conversion (parm);
- parmtype = TREE_TYPE (parm);
- }
- else
- parmtype = build_pointer_type (TREE_TYPE (parmtype));
- }
-
- /* Conversions among pointers */
- if (codel == POINTER_TYPE && coder == POINTER_TYPE)
- {
- register tree ttl = TYPE_MAIN_VARIANT (TREE_TYPE (type));
- register tree ttr = TYPE_MAIN_VARIANT (TREE_TYPE (parmtype));
- int penalty = 4 * (ttl != ttr);
-
- /* Anything converts to void *. Since this may be `const void *'
- (etc.) use VOID_TYPE instead of void_type_node. Otherwise, the
- targets must be the same, except that we do allow (at some cost)
- conversion between signed and unsigned pointer types. */
-
- if ((TREE_CODE (ttl) == METHOD_TYPE
- || TREE_CODE (ttl) == FUNCTION_TYPE)
- && TREE_CODE (ttl) == TREE_CODE (ttr))
- {
- if (comptypes (ttl, ttr, -1))
- {
- h.code = penalty ? STD_CODE : 0;
- h.distance = 0;
- }
- else
- h.code = EVIL_CODE;
- return h;
- }
-
-#if 1
- if (TREE_CODE (ttl) != VOID_TYPE
- && (TREE_CODE (ttr) != VOID_TYPE || !parm || !integer_zerop (parm)))
- {
- if (TREE_UNSIGNED (ttl) != TREE_UNSIGNED (ttr))
- {
- ttl = unsigned_type (ttl);
- ttr = unsigned_type (ttr);
- penalty = 10;
- }
- if (comp_target_types (type, parmtype, 1) <= 0)
- return EVIL_RETURN (h);
- }
-#else
- if (!(TREE_CODE (ttl) == VOID_TYPE
- || TREE_CODE (ttr) == VOID_TYPE
- || (TREE_UNSIGNED (ttl) ^ TREE_UNSIGNED (ttr)
- && (ttl = unsigned_type (ttl),
- ttr = unsigned_type (ttr),
- penalty = 10, 0))
- || (comp_target_types (ttl, ttr, 0) > 0)))
- return EVIL_RETURN (h);
-#endif
-
- if (penalty == 10 || ttr == ttl)
- {
- tree tmp1 = TREE_TYPE (type), tmp2 = TREE_TYPE (parmtype);
-
- /* If one was unsigned but the other wasn't, then we need to
- do a standard conversion from T to unsigned T. */
- if (penalty == 10)
- h.code = PROMO_CODE; /* was STD_CODE */
- else
- h.code = 0;
-
- /* Note conversion from `T*' to `const T*',
- or `T*' to `volatile T*'. */
- if (ttl == ttr
- && ((TYPE_READONLY (tmp1) != TREE_READONLY (tmp2))
- || (TYPE_VOLATILE (tmp1) != TYPE_VOLATILE (tmp2))))
- h.code |= QUAL_CODE;
-
- h.distance = 0;
- return h;
- }
-
-
- if (TREE_CODE (ttl) == RECORD_TYPE && TREE_CODE (ttr) == RECORD_TYPE)
- {
- int b_or_d = get_base_distance (ttl, ttr, 0, 0);
- if (b_or_d < 0)
- {
- b_or_d = get_base_distance (ttr, ttl, 0, 0);
- if (b_or_d < 0)
- return EVIL_RETURN (h);
- h.distance = -b_or_d;
- }
- else
- h.distance = b_or_d;
- h.code = STD_CODE;
- return h;
- }
-
- /* If converting from a `class*' to a `void*', make it
- less favorable than any inheritance relationship. */
- if (TREE_CODE (ttl) == VOID_TYPE && IS_AGGR_TYPE (ttr))
- {
- h.code = STD_CODE;
- h.distance = CLASSTYPE_MAX_DEPTH (ttr)+1;
- return h;
- }
-
- h.code = penalty ? STD_CODE : PROMO_CODE;
- /* Catch things like `const char *' -> `const void *'
- vs `const char *' -> `void *'. */
- if (ttl != ttr)
- {
- tree tmp1 = TREE_TYPE (type), tmp2 = TREE_TYPE (parmtype);
- if ((TYPE_READONLY (tmp1) != TREE_READONLY (tmp2))
- || (TYPE_VOLATILE (tmp1) != TYPE_VOLATILE (tmp2)))
- h.code |= QUAL_CODE;
- }
- return h;
- }
-
- if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
- {
- /* This is not a bad match, but don't let it beat
- integer-enum combinations. */
- if (parm && integer_zerop (parm))
- {
- h.code = STD_CODE;
- h.distance = 0;
- return h;
- }
- }
-
- /* C++: Since the `this' parameter of a signature member function
- is represented as a signature pointer to handle default implementations
- correctly, we can have the case that `type' is a signature pointer
- while `parmtype' is a pointer to a signature table. We don't really
- do any conversions in this case, so just return 0. */
-
- if (codel == RECORD_TYPE && coder == POINTER_TYPE
- && IS_SIGNATURE_POINTER (type) && IS_SIGNATURE (TREE_TYPE (parmtype)))
- return ZERO_RETURN (h);
-
- if (codel == RECORD_TYPE && coder == RECORD_TYPE)
- {
- int b_or_d = get_base_distance (type, parmtype, 0, 0);
- if (b_or_d < 0)
- {
- b_or_d = get_base_distance (parmtype, type, 0, 0);
- if (b_or_d < 0)
- return EVIL_RETURN (h);
- h.distance = -b_or_d;
- }
- else
- h.distance = b_or_d;
- h.code = STD_CODE;
- return h;
- }
- return EVIL_RETURN (h);
-}
-
-/* A clone of build_type_conversion for checking user-defined conversions in
- overload resolution. */
-
-int
-user_harshness (type, parmtype, parm)
- register tree type, parmtype;
- tree parm;
-{
- tree conv;
- tree winner = NULL_TREE;
- int code;
-
- {
- tree typename = build_typename_overload (type);
- if (lookup_fnfields (TYPE_BINFO (parmtype), typename, 0))
- return 0;
- }
-
- for (conv = lookup_conversions (parmtype); conv; conv = TREE_CHAIN (conv))
- {
- struct harshness_code tmp;
-
- if (winner && TREE_PURPOSE (winner) == TREE_PURPOSE (conv))
- continue;
-
- if (tmp = convert_harshness (type, TREE_VALUE (conv), NULL_TREE),
- tmp.code < USER_CODE && tmp.distance >= 0)
- {
- if (winner)
- return EVIL_CODE;
- else
- {
- winner = conv;
- code = tmp.code;
- }
- }
- }
-
- if (winner)
- return code;
-
- return -1;
-}
-
-int
-can_convert (to, from)
- tree to, from;
-{
- struct harshness_code h;
- h = convert_harshness (to, from, NULL_TREE);
- return h.code < USER_CODE && h.distance >= 0;
-}
-
-int
-can_convert_arg (to, from, arg)
- tree to, from, arg;
-{
- struct harshness_code h;
- h = convert_harshness (to, from, arg);
- return h.code < USER_CODE && h.distance >= 0;
-}
-
-#ifdef DEBUG_MATCHING
-static char *
-print_harshness (h)
- struct harshness_code *h;
-{
- static char buf[1024];
- char tmp[1024];
-
- bzero (buf, 1024 * sizeof (char));
- strcat (buf, "codes=[");
- if (h->code & EVIL_CODE)
- strcat (buf, "EVIL");
- if (h->code & CONST_CODE)
- strcat (buf, " CONST");
- if (h->code & ELLIPSIS_CODE)
- strcat (buf, " ELLIPSIS");
- if (h->code & USER_CODE)
- strcat (buf, " USER");
- if (h->code & STD_CODE)
- strcat (buf, " STD");
- if (h->code & PROMO_CODE)
- strcat (buf, " PROMO");
- if (h->code & QUAL_CODE)
- strcat (buf, " QUAL");
- if (h->code & TRIVIAL_CODE)
- strcat (buf, " TRIVIAL");
- if (buf[0] == '\0')
- strcat (buf, "0");
-
- sprintf (tmp, "] distance=%d int_penalty=%d", h->distance, h->int_penalty);
-
- strcat (buf, tmp);
-
- return buf;
-}
-#endif
-
-/* Algorithm: For each argument, calculate how difficult it is to
- make FUNCTION accept that argument. If we can easily tell that
- FUNCTION won't be acceptable to one of the arguments, then we
- don't need to compute the ease of converting the other arguments,
- since it will never show up in the intersection of all arguments'
- favorite functions.
-
- Conversions between builtin and user-defined types are allowed, but
- no function involving such a conversion is preferred to one which
- does not require such a conversion. Furthermore, such conversions
- must be unique. */
-
-void
-compute_conversion_costs (function, tta_in, cp, arglen)
- tree function;
- tree tta_in;
- struct candidate *cp;
- int arglen;
-{
- tree ttf_in = TYPE_ARG_TYPES (TREE_TYPE (function));
- tree ttf = ttf_in;
- tree tta = tta_in;
-
- /* Start out with no strikes against. */
- int evil_strikes = 0;
- int ellipsis_strikes = 0;
- int user_strikes = 0;
- int b_or_d_strikes = 0;
- int easy_strikes = 0;
-
- int strike_index = 0, win;
- struct harshness_code lose;
- extern int cp_silent;
-
-#ifdef GATHER_STATISTICS
- n_compute_conversion_costs++;
-#endif
-
-#ifndef DEBUG_MATCHING
- /* We don't emit any warnings or errors while trying out each candidate. */
- cp_silent = 1;
-#endif
-
- cp->function = function;
- cp->arg = tta ? TREE_VALUE (tta) : NULL_TREE;
- cp->u.bad_arg = 0; /* optimistic! */
-
- cp->h.code = 0;
- cp->h.distance = 0;
- cp->h.int_penalty = 0;
- bzero ((char *) cp->harshness,
- (cp->h_len + 1) * sizeof (struct harshness_code));
-
- while (ttf && tta)
- {
- struct harshness_code h;
-
- if (ttf == void_list_node)
- break;
-
- if (type_unknown_p (TREE_VALUE (tta)))
- {
- /* Must perform some instantiation here. */
- tree rhs = TREE_VALUE (tta);
- tree lhstype = TREE_VALUE (ttf);
-
- /* Keep quiet about possible contravariance violations. */
- int old_inhibit_warnings = inhibit_warnings;
- inhibit_warnings = 1;
-
- /* @@ This is to undo what `grokdeclarator' does to
- parameter types. It really should go through
- something more general. */
-
- TREE_TYPE (tta) = unknown_type_node;
- rhs = instantiate_type (lhstype, rhs, 0);
- inhibit_warnings = old_inhibit_warnings;
-
- if (TREE_CODE (rhs) == ERROR_MARK)
- h.code = EVIL_CODE;
- else
- h = convert_harshness (lhstype, TREE_TYPE (rhs), rhs);
- }
- else
- {
-#ifdef DEBUG_MATCHING
- static tree old_function = NULL_TREE;
-
- if (!old_function || function != old_function)
- {
- cp_error ("trying %D", function);
- old_function = function;
- }
-
- cp_error (" doing (%T) %E against arg %T",
- TREE_TYPE (TREE_VALUE (tta)), TREE_VALUE (tta),
- TREE_VALUE (ttf));
-#endif
-
- h = convert_harshness (TREE_VALUE (ttf),
- TREE_TYPE (TREE_VALUE (tta)),
- TREE_VALUE (tta));
-
-#ifdef DEBUG_MATCHING
- cp_error (" evaluated %s", print_harshness (&h));
-#endif
- }
-
- cp->harshness[strike_index] = h;
- if ((h.code & EVIL_CODE)
- || ((h.code & STD_CODE) && h.distance < 0))
- {
- cp->u.bad_arg = strike_index;
- evil_strikes = 1;
- }
- else if (h.code & ELLIPSIS_CODE)
- ellipsis_strikes += 1;
-#if 0
- /* This is never set by `convert_harshness'. */
- else if (h.code & USER_CODE)
- {
- user_strikes += 1;
- }
-#endif
- else
- {
- if ((h.code & STD_CODE) && h.distance)
- {
- if (h.distance > b_or_d_strikes)
- b_or_d_strikes = h.distance;
- }
- else
- easy_strikes += (h.code & (STD_CODE|PROMO_CODE|TRIVIAL_CODE));
- cp->h.code |= h.code;
- /* Make sure we communicate this. */
- cp->h.int_penalty += h.int_penalty;
- }
-
- ttf = TREE_CHAIN (ttf);
- tta = TREE_CHAIN (tta);
- strike_index += 1;
- }
-
- if (tta)
- {
- /* ran out of formals, and parmlist is fixed size. */
- if (ttf /* == void_type_node */)
- {
- cp->h.code = EVIL_CODE;
- cp->u.bad_arg = -1;
- cp_silent = 0;
- return;
- }
- else
- {
- struct harshness_code h;
- int l = list_length (tta);
- ellipsis_strikes += l;
- h.code = ELLIPSIS_CODE;
- h.distance = 0;
- h.int_penalty = 0;
- for (; l; --l)
- cp->harshness[strike_index++] = h;
- }
- }
- else if (ttf && ttf != void_list_node)
- {
- /* ran out of actuals, and no defaults. */
- if (TREE_PURPOSE (ttf) == NULL_TREE)
- {
- cp->h.code = EVIL_CODE;
- cp->u.bad_arg = -2;
- cp_silent = 0;
- return;
- }
- /* Store index of first default. */
- cp->harshness[arglen].distance = strike_index+1;
- }
- else
- cp->harshness[arglen].distance = 0;
-
- /* Argument list lengths work out, so don't need to check them again. */
- if (evil_strikes)
- {
- /* We do not check for derived->base conversions here, since in
- no case would they give evil strike counts, unless such conversions
- are somehow ambiguous. */
-
- /* See if any user-defined conversions apply.
- But make sure that we do not loop. */
- static int dont_convert_types = 0;
-
- if (dont_convert_types)
- {
- cp->h.code = EVIL_CODE;
- cp_silent = 0;
- return;
- }
-
- win = 0; /* Only get one chance to win. */
- ttf = TYPE_ARG_TYPES (TREE_TYPE (function));
- tta = tta_in;
- strike_index = 0;
- evil_strikes = 0;
-
- while (ttf && tta)
- {
- if (ttf == void_list_node)
- break;
-
- lose = cp->harshness[strike_index];
- if ((lose.code & EVIL_CODE)
- || ((lose.code & STD_CODE) && lose.distance < 0))
- {
- tree actual_type = TREE_TYPE (TREE_VALUE (tta));
- tree formal_type = TREE_VALUE (ttf);
- int extra_conversions = 0;
-
- dont_convert_types = 1;
-
- if (TREE_CODE (formal_type) == REFERENCE_TYPE)
- formal_type = TREE_TYPE (formal_type);
- if (TREE_CODE (actual_type) == REFERENCE_TYPE)
- actual_type = TREE_TYPE (actual_type);
-
- if (formal_type != error_mark_node
- && actual_type != error_mark_node)
- {
- formal_type = TYPE_MAIN_VARIANT (formal_type);
- actual_type = TYPE_MAIN_VARIANT (actual_type);
-
- if (TYPE_HAS_CONSTRUCTOR (formal_type))
- {
- /* If it has a constructor for this type,
- try to use it. */
- /* @@ There is no way to save this result yet, so
- success is a NULL_TREE for now. */
- if (convert_to_aggr (formal_type, TREE_VALUE (tta), 0, 1)
- != error_mark_node)
- win++;
- }
- if (TYPE_LANG_SPECIFIC (actual_type)
- && TYPE_HAS_CONVERSION (actual_type))
- {
- int extra = user_harshness (formal_type, actual_type);
-
- if (extra == EVIL_CODE)
- win += 2;
- else if (extra >= 0)
- {
- win++;
- extra_conversions = extra;
- }
- }
- }
- dont_convert_types = 0;
-
- if (win == 1)
- {
- user_strikes += 1;
- cp->harshness[strike_index].code
- = USER_CODE | (extra_conversions ? STD_CODE : 0);
- win = 0;
- }
- else
- {
- if (cp->u.bad_arg > strike_index)
- cp->u.bad_arg = strike_index;
-
- evil_strikes = win ? 2 : 1;
- break;
- }
- }
-
- ttf = TREE_CHAIN (ttf);
- tta = TREE_CHAIN (tta);
- strike_index += 1;
- }
- }
-
- /* Const member functions get a small penalty because defaulting
- to const is less useful than defaulting to non-const. */
- /* This is bogus, it does not correspond to anything in the ARM.
- This code will be fixed when this entire section is rewritten
- to conform to the ARM. (mrs) */
- if (TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
- {
- tree this_parm = TREE_VALUE (ttf_in);
-
- if (TREE_CODE (this_parm) == RECORD_TYPE /* Is `this' a sig ptr? */
- ? TYPE_READONLY (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (this_parm))))
- : TYPE_READONLY (TREE_TYPE (this_parm)))
- {
- cp->harshness[0].code |= TRIVIAL_CODE;
- ++easy_strikes;
- }
- else
- {
- /* Calling a non-const member function from a const member function
- is probably invalid, but for now we let it only draw a warning.
- We indicate that such a mismatch has occurred by setting the
- harshness to a maximum value. */
- if (TREE_CODE (TREE_TYPE (TREE_VALUE (tta_in))) == POINTER_TYPE
- && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (TREE_VALUE (tta_in))))))
- cp->harshness[0].code |= CONST_CODE;
- }
- }
-
- if (evil_strikes)
- cp->h.code = EVIL_CODE;
- if (ellipsis_strikes)
- cp->h.code |= ELLIPSIS_CODE;
- if (user_strikes)
- cp->h.code |= USER_CODE;
- cp_silent = 0;
-#ifdef DEBUG_MATCHING
- cp_error ("final eval %s", print_harshness (&cp->h));
-#endif
-}
-
-/* Subroutine of ideal_candidate. See if X or Y is a better match
- than the other. */
-static int
-strictly_better (x, y)
- unsigned short x, y;
-{
- unsigned short xor;
-
- if (x == y)
- return 0;
-
- xor = x ^ y;
- if (xor >= x || xor >= y)
- return 1;
- return 0;
-}
-
-/* When one of several possible overloaded functions and/or methods
- can be called, choose the best candidate for overloading.
-
- BASETYPE is the context from which we start method resolution
- or NULL if we are comparing overloaded functions.
- CANDIDATES is the array of candidates we have to choose from.
- N_CANDIDATES is the length of CANDIDATES.
- PARMS is a TREE_LIST of parameters to the function we'll ultimately
- choose. It is modified in place when resolving methods. It is not
- modified in place when resolving overloaded functions.
- LEN is the length of the parameter list. */
-
-static struct candidate *
-ideal_candidate (basetype, candidates, n_candidates, parms, len)
- tree basetype;
- struct candidate *candidates;
- int n_candidates;
- tree parms;
- int len;
-{
- struct candidate *cp = candidates+n_candidates;
- int i, j = -1, best_code;
-
- /* For each argument, sort the functions from best to worst for the arg.
- For each function that's not best for this arg, set its overall
- harshness to EVIL so that other args won't like it. The candidate
- list for the last argument is the intersection of all the best-liked
- functions. */
-
-#if 0
- for (i = 0; i < len; i++)
- {
- qsort (candidates, n_candidates, sizeof (struct candidate),
- rank_for_overload);
- best_code = cp[-1].h.code;
-
- /* To find out functions that are worse than that represented
- by BEST_CODE, we can't just do a comparison like h.code>best_code.
- The total harshness for the "best" fn may be 8|8 for two args, and
- the harshness for the next-best may be 8|2. If we just compared,
- that would be checking 8>10, which would lead to the next-best
- being disqualified. What we actually want to do is get rid
- of functions that are definitely worse than that represented
- by best_code, i.e. those which have bits set higher than the
- highest in best_code. Sooooo, what we do is clear out everything
- represented by best_code, and see if we still come up with something
- higher. If so (e.g., 8|8 vs 8|16), it'll disqualify it properly. */
- for (j = n_candidates-2; j >= 0; j--)
- if ((candidates[j].h.code & ~best_code) > best_code)
- candidates[j].h.code = EVIL_CODE;
- }
-
- if (cp[-1].h.code & EVIL_CODE)
- return NULL;
-#else
- qsort (candidates, n_candidates, sizeof (struct candidate),
- rank_for_overload);
- best_code = cp[-1].h.code;
-#endif
-
- /* If they're at least as good as each other, do an arg-by-arg check. */
- if (! strictly_better (cp[-1].h.code, cp[-2].h.code))
- {
- int better = 0;
- int worse = 0;
-
- for (j = 0; j < n_candidates; j++)
- if (! strictly_better (candidates[j].h.code, best_code))
- break;
-
- qsort (candidates+j, n_candidates-j, sizeof (struct candidate),
- rank_for_ideal);
- for (i = 0; i < len; i++)
- {
- if (cp[-1].harshness[i].code < cp[-2].harshness[i].code)
- better = 1;
- else if (cp[-1].harshness[i].code > cp[-2].harshness[i].code)
- worse = 1;
- else if (cp[-1].harshness[i].code & STD_CODE)
- {
- /* If it involves a standard conversion, let the
- inheritance lattice be the final arbiter. */
- if (cp[-1].harshness[i].distance > cp[-2].harshness[i].distance)
- worse = 1;
- else if (cp[-1].harshness[i].distance < cp[-2].harshness[i].distance)
- better = 1;
- }
- else if (cp[-1].harshness[i].code & PROMO_CODE)
- {
- /* For integral promotions, take into account a finer
- granularity for determining which types should be favored
- over others in such promotions. */
- if (cp[-1].harshness[i].int_penalty > cp[-2].harshness[i].int_penalty)
- worse = 1;
- else if (cp[-1].harshness[i].int_penalty < cp[-2].harshness[i].int_penalty)
- better = 1;
- }
- }
-
- if (! better || worse)
- return NULL;
- }
- return cp-1;
-}
-
-/* Assume that if the class referred to is not in the
- current class hierarchy, that it may be remote.
- PARENT is assumed to be of aggregate type here. */
-static int
-may_be_remote (parent)
- tree parent;
-{
- if (TYPE_OVERLOADS_METHOD_CALL_EXPR (parent) == 0)
- return 0;
-
- if (current_class_type == NULL_TREE)
- return 0;
-
- if (parent == current_class_type)
- return 0;
-
- if (UNIQUELY_DERIVED_FROM_P (parent, current_class_type))
- return 0;
- return 1;
-}
+static tree build_new_method_call PROTO((tree, tree, tree, tree, int));
+
+static tree build_field_call PROTO((tree, tree, tree, tree));
+static tree find_scoped_type PROTO((tree, tree, tree));
+static struct z_candidate * tourney PROTO((struct z_candidate *));
+static int joust PROTO((struct z_candidate *, struct z_candidate *, int));
+static int compare_ics PROTO((tree, tree));
+static tree build_over_call PROTO((struct z_candidate *, tree, int));
+static tree convert_like PROTO((tree, tree));
+static void op_error PROTO((enum tree_code, enum tree_code, tree, tree,
+ tree, char *));
+static tree build_object_call PROTO((tree, tree));
+static tree resolve_args PROTO((tree));
+static struct z_candidate * build_user_type_conversion_1
+ PROTO ((tree, tree, int));
+static void print_z_candidates PROTO((struct z_candidate *));
+static tree build_this PROTO((tree));
+static struct z_candidate * splice_viable PROTO((struct z_candidate *));
+static int any_viable PROTO((struct z_candidate *));
+static struct z_candidate * add_template_candidate
+ PROTO((struct z_candidate *, tree, tree, tree, tree, int,
+ unification_kind_t));
+static struct z_candidate * add_template_candidate_real
+ PROTO((struct z_candidate *, tree, tree, tree, tree, int,
+ tree, unification_kind_t));
+static struct z_candidate * add_template_conv_candidate
+ PROTO((struct z_candidate *, tree, tree, tree, tree));
+static struct z_candidate * add_builtin_candidates
+ PROTO((struct z_candidate *, enum tree_code, enum tree_code,
+ tree, tree *, int));
+static struct z_candidate * add_builtin_candidate
+ PROTO((struct z_candidate *, enum tree_code, enum tree_code,
+ tree, tree, tree, tree *, tree *, int));
+static int is_complete PROTO((tree));
+static struct z_candidate * build_builtin_candidate
+ PROTO((struct z_candidate *, tree, tree, tree, tree *, tree *,
+ int));
+static struct z_candidate * add_conv_candidate
+ PROTO((struct z_candidate *, tree, tree, tree));
+static struct z_candidate * add_function_candidate
+ PROTO((struct z_candidate *, tree, tree, int));
+static tree implicit_conversion PROTO((tree, tree, tree, int));
+static tree standard_conversion PROTO((tree, tree, tree));
+static tree reference_binding PROTO((tree, tree, tree, int));
+static tree strip_top_quals PROTO((tree));
+static tree non_reference PROTO((tree));
+static tree build_conv PROTO((enum tree_code, tree, tree));
+static int is_subseq PROTO((tree, tree));
+static int is_properly_derived_from PROTO((tree, tree));
+static int maybe_handle_ref_bind PROTO((tree*, tree*));
+static void maybe_handle_implicit_object PROTO((tree*));
tree
build_vfield_ref (datum, type)
@@ -1223,7 +110,7 @@ build_vfield_ref (datum, type)
rval = build (COMPONENT_REF, TREE_TYPE (CLASSTYPE_VFIELD (type)),
datum, CLASSTYPE_VFIELD (type));
else
- rval = build_component_ref (datum, DECL_NAME (CLASSTYPE_VFIELD (type)), 0, 0);
+ rval = build_component_ref (datum, DECL_NAME (CLASSTYPE_VFIELD (type)), NULL_TREE, 0);
flag_assume_nonnull_objects = old_assume_nonnull_objects;
return rval;
@@ -1231,13 +118,17 @@ build_vfield_ref (datum, type)
/* Build a call to a member of an object. I.e., one that overloads
operator ()(), or is a pointer-to-function or pointer-to-method. */
+
static tree
build_field_call (basetype_path, instance_ptr, name, parms)
tree basetype_path, instance_ptr, name, parms;
{
tree field, instance;
- if (instance_ptr == current_class_decl)
+ if (name == ctor_identifier || name == dtor_identifier)
+ return NULL_TREE;
+
+ if (instance_ptr == current_class_ptr)
{
/* Check to see if we really have a reference to an instance variable
with `operator()()' overloaded. */
@@ -1253,12 +144,11 @@ build_field_call (basetype_path, instance_ptr, name, parms)
{
/* If it's a field, try overloading operator (),
or calling if the field is a pointer-to-function. */
- instance = build_component_ref_1 (C_C_D, field, 0);
+ instance = build_component_ref_1 (current_class_ref, field, 0);
if (instance == error_mark_node)
return error_mark_node;
- if (TYPE_LANG_SPECIFIC (TREE_TYPE (instance))
- && TYPE_OVERLOADS_CALL_EXPR (TREE_TYPE (instance)))
+ if (TYPE_LANG_SPECIFIC (TREE_TYPE (instance)))
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, instance, parms, NULL_TREE);
if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
@@ -1266,7 +156,7 @@ build_field_call (basetype_path, instance_ptr, name, parms)
if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == FUNCTION_TYPE)
return build_function_call (instance, parms);
else if (TREE_CODE (TREE_TYPE (TREE_TYPE (instance))) == METHOD_TYPE)
- return build_function_call (instance, tree_cons (NULL_TREE, current_class_decl, parms));
+ return build_function_call (instance, expr_tree_cons (NULL_TREE, current_class_ptr, parms));
}
}
return NULL_TREE;
@@ -1281,7 +171,7 @@ build_field_call (basetype_path, instance_ptr, name, parms)
if (field == error_mark_node)
return error_mark_node;
- if (field)
+ if (field && TREE_CODE (field) == FIELD_DECL)
{
tree basetype;
tree ftype = TREE_TYPE (field);
@@ -1289,7 +179,7 @@ build_field_call (basetype_path, instance_ptr, name, parms)
if (TREE_CODE (ftype) == REFERENCE_TYPE)
ftype = TREE_TYPE (ftype);
- if (TYPE_LANG_SPECIFIC (ftype) && TYPE_OVERLOADS_CALL_EXPR (ftype))
+ if (TYPE_LANG_SPECIFIC (ftype))
{
/* Make the next search for this field very short. */
basetype = DECL_FIELD_CONTEXT (field);
@@ -1326,7 +216,7 @@ build_field_call (basetype_path, instance_ptr, name, parms)
return NULL_TREE;
}
-tree
+static tree
find_scoped_type (type, inner_name, inner_types)
tree type, inner_name, inner_types;
{
@@ -1341,28 +231,19 @@ find_scoped_type (type, inner_name, inner_types)
if (TREE_PURPOSE (tags) == inner_name)
{
if (inner_types == NULL_TREE)
- return DECL_NESTED_TYPENAME (TYPE_NAME (TREE_VALUE (tags)));
+ return TYPE_MAIN_DECL (TREE_VALUE (tags));
return resolve_scope_to_name (TREE_VALUE (tags), inner_types);
}
tags = TREE_CHAIN (tags);
}
-#if 0
- /* XXX This needs to be fixed better. */
- if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
- {
- sorry ("nested class lookup in template type");
- return NULL_TREE;
- }
-#endif
-
/* Look for a TYPE_DECL. */
for (tags = TYPE_FIELDS (type); tags; tags = TREE_CHAIN (tags))
if (TREE_CODE (tags) == TYPE_DECL && DECL_NAME (tags) == inner_name)
{
/* Code by raeburn. */
if (inner_types == NULL_TREE)
- return DECL_NESTED_TYPENAME (tags);
+ return tags;
return resolve_scope_to_name (TREE_TYPE (tags), inner_types);
}
@@ -1374,6 +255,7 @@ find_scoped_type (type, inner_name, inner_types)
is a chain of nested type names (held together by SCOPE_REFs);
OUTER_TYPE is the type we know to enclose INNER_TYPES.
Returns NULL_TREE if there is an error. */
+
tree
resolve_scope_to_name (outer_type, inner_stuff)
tree outer_type, inner_stuff;
@@ -1394,7 +276,7 @@ resolve_scope_to_name (outer_type, inner_stuff)
if (rval != NULL_TREE)
return rval;
- type = DECL_CONTEXT (TYPE_NAME (type));
+ type = DECL_CONTEXT (TYPE_MAIN_DECL (type));
}
}
@@ -1458,11 +340,43 @@ resolve_scope_to_name (outer_type, inner_stuff)
return tmp;
}
+/* Returns nonzero iff the destructor name specified in NAME
+ (a BIT_NOT_EXPR) matches BASETYPE. The operand of NAME can take many
+ forms... */
+
+int
+check_dtor_name (basetype, name)
+ tree basetype, name;
+{
+ name = TREE_OPERAND (name, 0);
+
+ if (TREE_CODE (name) == TYPE_DECL)
+ name = TREE_TYPE (name);
+ else if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
+ /* OK */;
+ else if (TREE_CODE (name) == IDENTIFIER_NODE)
+ {
+ if ((IS_AGGR_TYPE (basetype) && name == constructor_name (basetype))
+ || (TREE_CODE (basetype) == ENUMERAL_TYPE
+ && name == TYPE_IDENTIFIER (basetype)))
+ name = basetype;
+ else
+ name = get_type_value (name);
+ }
+ else
+ my_friendly_abort (980605);
+
+ if (name && TYPE_MAIN_VARIANT (basetype) == TYPE_MAIN_VARIANT (name))
+ return 1;
+ return 0;
+}
+
/* Build a method call of the form `EXP->SCOPES::NAME (PARMS)'.
This is how virtual function calls are avoided. */
+
tree
-build_scoped_method_call (exp, scopes, name, parms)
- tree exp, scopes, name, parms;
+build_scoped_method_call (exp, basetype, name, parms)
+ tree exp, basetype, name, parms;
{
/* Because this syntactic form does not allow
a pointer to a base class to be `stolen',
@@ -1470,35 +384,64 @@ build_scoped_method_call (exp, scopes, name, parms)
that happens here.
@@ But we do have to check access privileges later. */
- tree basename = resolve_scope_to_name (NULL_TREE, scopes);
- tree basetype, binfo, decl;
+ tree binfo, decl;
tree type = TREE_TYPE (exp);
if (type == error_mark_node
- || basename == NULL_TREE)
+ || basetype == error_mark_node)
return error_mark_node;
- basetype = IDENTIFIER_TYPE_VALUE (basename);
+ if (processing_template_decl)
+ {
+ if (TREE_CODE (name) == BIT_NOT_EXPR
+ && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
+ {
+ tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 0);
+ if (type)
+ name = build_min_nt (BIT_NOT_EXPR, type);
+ }
+ name = build_min_nt (SCOPE_REF, basetype, name);
+ return build_min_nt (METHOD_CALL_EXPR, name, exp, parms, NULL_TREE);
+ }
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
- /* Destructors can be "called" for simple types; see 5.2.4 and 12.4 Note
- that explicit ~int is caught in the parser; this deals with typedefs
- and template parms. */
- if (TREE_CODE (name) == BIT_NOT_EXPR && ! is_aggr_typedef (basename, 0))
+ if (TREE_CODE (basetype) == TREE_VEC)
{
- if (type != basetype)
- cp_error ("type of `%E' does not match destructor type `%T' (type was `%T')",
- exp, basetype, type);
- name = TREE_OPERAND (name, 0);
- if (basetype != get_type_value (name))
+ binfo = basetype;
+ basetype = BINFO_TYPE (binfo);
+ }
+ else
+ binfo = NULL_TREE;
+
+ /* Check the destructor call syntax. */
+ if (TREE_CODE (name) == BIT_NOT_EXPR)
+ {
+ /* We can get here if someone writes their destructor call like
+ `obj.NS::~T()'; this isn't really a scoped method call, so hand
+ it off. */
+ if (TREE_CODE (basetype) == NAMESPACE_DECL)
+ return build_method_call (exp, name, parms, NULL_TREE, LOOKUP_NORMAL);
+
+ if (! check_dtor_name (basetype, name))
cp_error ("qualified type `%T' does not match destructor name `~%T'",
- basetype, name);
- return convert (void_type_node, exp);
+ basetype, TREE_OPERAND (name, 0));
+
+ /* Destructors can be "called" for simple types; see 5.2.4 and 12.4 Note
+ that explicit ~int is caught in the parser; this deals with typedefs
+ and template parms. */
+ if (! IS_AGGR_TYPE (basetype))
+ {
+ if (TYPE_MAIN_VARIANT (type) != TYPE_MAIN_VARIANT (basetype))
+ cp_error ("type of `%E' does not match destructor type `%T' (type was `%T')",
+ exp, basetype, type);
+
+ return cp_convert (void_type_node, exp);
+ }
}
- if (! is_aggr_typedef (basename, 1))
+ if (! is_aggr_type (basetype, 1))
return error_mark_node;
if (! IS_AGGR_TYPE (type))
@@ -1508,31 +451,29 @@ build_scoped_method_call (exp, scopes, name, parms)
return error_mark_node;
}
- if ((binfo = binfo_or_else (basetype, type)))
+ if (! binfo)
{
+ binfo = get_binfo (basetype, type, 1);
if (binfo == error_mark_node)
return error_mark_node;
+ if (! binfo)
+ error_not_base_type (basetype, type);
+ }
+
+ if (binfo)
+ {
if (TREE_CODE (exp) == INDIRECT_REF)
- decl = build_indirect_ref (convert_pointer_to (binfo,
- build_unary_op (ADDR_EXPR, exp, 0)), NULL_PTR);
+ decl = build_indirect_ref
+ (convert_pointer_to_real
+ (binfo, build_unary_op (ADDR_EXPR, exp, 0)), NULL_PTR);
else
- decl = build_scoped_ref (exp, scopes);
+ decl = build_scoped_ref (exp, basetype);
/* Call to a destructor. */
if (TREE_CODE (name) == BIT_NOT_EXPR)
{
- /* Explicit call to destructor. */
- name = TREE_OPERAND (name, 0);
- if (! (name == constructor_name (TREE_TYPE (decl))
- || TREE_TYPE (decl) == get_type_value (name)))
- {
- cp_error
- ("qualified type `%T' does not match destructor name `~%T'",
- TREE_TYPE (decl), name);
- return error_mark_node;
- }
if (! TYPE_HAS_DESTRUCTOR (TREE_TYPE (decl)))
- return convert (void_type_node, exp);
+ return cp_convert (void_type_node, exp);
return build_delete (TREE_TYPE (decl), decl, integer_two_node,
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR,
@@ -1546,30 +487,92 @@ build_scoped_method_call (exp, scopes, name, parms)
return error_mark_node;
}
-static void
-print_candidates (candidates)
- tree candidates;
+/* We want the address of a function or method. We avoid creating a
+ pointer-to-member function. */
+
+tree
+build_addr_func (function)
+ tree function;
{
- cp_error_at ("candidates are: %D", TREE_VALUE (candidates));
- candidates = TREE_CHAIN (candidates);
+ tree type = TREE_TYPE (function);
- while (candidates)
+ /* We have to do these by hand to avoid real pointer to member
+ functions. */
+ if (TREE_CODE (type) == METHOD_TYPE)
{
- cp_error_at (" %D", TREE_VALUE (candidates));
- candidates = TREE_CHAIN (candidates);
+ tree addr;
+
+ type = build_pointer_type (type);
+
+ if (mark_addressable (function) == 0)
+ return error_mark_node;
+
+ addr = build1 (ADDR_EXPR, type, function);
+
+ /* Address of a static or external variable or function counts
+ as a constant */
+ if (staticp (function))
+ TREE_CONSTANT (addr) = 1;
+
+ function = addr;
}
+ else
+ function = default_conversion (function);
+
+ return function;
}
-static void
-print_n_candidates (candidates, n)
- struct candidate *candidates;
- int n;
+/* Build a CALL_EXPR, we can handle FUNCTION_TYPEs, METHOD_TYPEs, or
+ POINTER_TYPE to those. Note, pointer to member function types
+ (TYPE_PTRMEMFUNC_P) must be handled by our callers. */
+
+tree
+build_call (function, result_type, parms)
+ tree function, result_type, parms;
{
- int i;
+ int is_constructor = 0;
+ tree tmp;
+ tree decl;
- cp_error_at ("candidates are: %D", candidates[0].function);
- for (i = 1; i < n; i++)
- cp_error_at (" %D", candidates[i].function);
+ function = build_addr_func (function);
+
+ if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
+ {
+ sorry ("unable to call pointer to member function here");
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (function) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
+ decl = TREE_OPERAND (function, 0);
+ else
+ decl = NULL_TREE;
+
+ if (decl && DECL_CONSTRUCTOR_P (decl))
+ is_constructor = 1;
+
+ /* Don't pass empty class objects by value. This is useful
+ for tags in STL, which are used to control overload resolution.
+ We don't need to handle other cases of copying empty classes. */
+ if (! decl || ! DECL_BUILT_IN (decl))
+ for (tmp = parms; tmp; tmp = TREE_CHAIN (tmp))
+ if (is_empty_class (TREE_TYPE (TREE_VALUE (tmp)))
+ && ! TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (tmp))))
+ {
+ tree t = make_node (RTL_EXPR);
+ TREE_TYPE (t) = TREE_TYPE (TREE_VALUE (tmp));
+ RTL_EXPR_RTL (t) = const0_rtx;
+ RTL_EXPR_SEQUENCE (t) = NULL_RTX;
+ TREE_VALUE (tmp) = build (COMPOUND_EXPR, TREE_TYPE (t),
+ TREE_VALUE (tmp), t);
+ }
+
+ function = build_nt (CALL_EXPR, function, parms, NULL_TREE);
+ TREE_HAS_CONSTRUCTOR (function) = is_constructor;
+ TREE_TYPE (function) = result_type;
+ TREE_SIDE_EFFECTS (function) = 1;
+
+ return function;
}
/* Build something of the form ptr->method (args)
@@ -1603,31 +606,13 @@ print_n_candidates (candidates, n)
Note that NAME may refer to an instance variable name. If
`operator()()' is defined for the type of that field, then we return
that result. */
+
tree
build_method_call (instance, name, parms, basetype_path, flags)
tree instance, name, parms, basetype_path;
int flags;
{
- register tree function, fntype, value_type;
- register tree basetype, save_basetype;
- register tree baselink, result, method_name, parmtypes, parm;
- tree last;
- int pass;
- enum access_type access = access_public;
-
- /* Range of cases for vtable optimization. */
- enum vtable_needs { not_needed, maybe_needed, unneeded, needed };
- enum vtable_needs need_vtbl = not_needed;
-
- char *name_kind;
- int ever_seen = 0;
- tree instance_ptr = NULL_TREE;
- int all_virtual = flag_all_virtual;
- int static_call_context = 0;
- tree found_fns = NULL_TREE;
-
- /* Keep track of `const' and `volatile' objects. */
- int constp, volatilep;
+ tree basetype, instance_ptr;
#ifdef GATHER_STATISTICS
n_build_method_call++;
@@ -1639,48 +624,59 @@ build_method_call (instance, name, parms, basetype_path, flags)
|| (instance != NULL_TREE && TREE_TYPE (instance) == error_mark_node))
return error_mark_node;
+ if (processing_template_decl)
+ {
+ /* We need to process template parm names here so that tsubst catches
+ them properly. Other type names can wait. */
+ if (TREE_CODE (name) == BIT_NOT_EXPR
+ && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
+ {
+ tree type = get_aggr_from_typedef (TREE_OPERAND (name, 0), 0);
+ if (type && TREE_CODE (type) == TEMPLATE_TYPE_PARM)
+ name = build_min_nt (BIT_NOT_EXPR, type);
+ }
+
+ return build_min_nt (METHOD_CALL_EXPR, name, instance, parms, NULL_TREE);
+ }
+
/* This is the logic that magically deletes the second argument to
- operator delete, if it is not needed. */
+ operator delete, if it is not needed. */
if (name == ansi_opname[(int) DELETE_EXPR] && list_length (parms)==2)
{
tree save_last = TREE_CHAIN (parms);
- tree result;
+
/* get rid of unneeded argument */
TREE_CHAIN (parms) = NULL_TREE;
- result = build_method_call (instance, name, parms, basetype_path,
- (LOOKUP_SPECULATIVELY|flags)
- &~LOOKUP_COMPLAIN);
- /* If it finds a match, return it. */
- if (result)
- return build_method_call (instance, name, parms, basetype_path, flags);
+ if (build_method_call (instance, name, parms, basetype_path,
+ (LOOKUP_SPECULATIVELY|flags) & ~LOOKUP_COMPLAIN))
+ {
+ /* If it finds a match, return it. */
+ return build_method_call (instance, name, parms, basetype_path, flags);
+ }
/* If it doesn't work, two argument delete must work */
TREE_CHAIN (parms) = save_last;
}
/* We already know whether it's needed or not for vec delete. */
else if (name == ansi_opname[(int) VEC_DELETE_EXPR]
+ && TYPE_LANG_SPECIFIC (TREE_TYPE (instance))
&& ! TYPE_VEC_DELETE_TAKES_SIZE (TREE_TYPE (instance)))
TREE_CHAIN (parms) = NULL_TREE;
if (TREE_CODE (name) == BIT_NOT_EXPR)
{
- flags |= LOOKUP_DESTRUCTOR;
- name = TREE_OPERAND (name, 0);
if (parms)
error ("destructors take no parameters");
basetype = TREE_TYPE (instance);
if (TREE_CODE (basetype) == REFERENCE_TYPE)
basetype = TREE_TYPE (basetype);
- if (! ((IS_AGGR_TYPE (basetype)
- && name == constructor_name (basetype))
- || basetype == get_type_value (name)))
- {
- cp_error ("destructor name `~%D' does not match type `%T' of expression",
- name, basetype);
- return convert (void_type_node, instance);
- }
- if (! TYPE_HAS_DESTRUCTOR (basetype))
- return convert (void_type_node, instance);
+ if (! check_dtor_name (basetype, name))
+ cp_error
+ ("destructor name `~%T' does not match type `%T' of expression",
+ TREE_OPERAND (name, 0), basetype);
+
+ if (! TYPE_HAS_DESTRUCTOR (complete_type (basetype)))
+ return cp_convert (void_type_node, instance);
instance = default_conversion (instance);
instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
return build_delete (build_pointer_type (basetype),
@@ -1688,1306 +684,3833 @@ build_method_call (instance, name, parms, basetype_path, flags)
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
}
- {
- char *xref_name;
-
- /* Initialize name for error reporting. */
- if (IDENTIFIER_OPNAME_P (name) && ! IDENTIFIER_TYPENAME_P (name))
- {
- char *p = operator_name_string (name);
- xref_name = (char *)alloca (strlen (p) + 10);
- sprintf (xref_name, "operator %s", p);
- }
- else if (TREE_CODE (name) == SCOPE_REF)
- xref_name = IDENTIFIER_POINTER (TREE_OPERAND (name, 1));
- else
- xref_name = IDENTIFIER_POINTER (name);
+ return build_new_method_call (instance, name, parms, basetype_path, flags);
+}
- GNU_xref_call (current_function_decl, xref_name);
- }
+/* New overloading code. */
+
+struct z_candidate {
+ tree fn;
+ tree convs;
+ tree second_conv;
+ int viable;
+ tree basetype_path;
+ tree template;
+ tree warnings;
+ struct z_candidate *next;
+};
+
+#define IDENTITY_RANK 0
+#define EXACT_RANK 1
+#define PROMO_RANK 2
+#define STD_RANK 3
+#define PBOOL_RANK 4
+#define USER_RANK 5
+#define ELLIPSIS_RANK 6
+#define BAD_RANK 7
+
+#define ICS_RANK(NODE) \
+ (ICS_BAD_FLAG (NODE) ? BAD_RANK \
+ : ICS_ELLIPSIS_FLAG (NODE) ? ELLIPSIS_RANK \
+ : ICS_USER_FLAG (NODE) ? USER_RANK \
+ : ICS_STD_RANK (NODE))
+
+#define ICS_STD_RANK(NODE) TREE_COMPLEXITY (NODE)
+
+#define ICS_USER_FLAG(NODE) TREE_LANG_FLAG_0 (NODE)
+#define ICS_ELLIPSIS_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
+#define ICS_THIS_FLAG(NODE) TREE_LANG_FLAG_2 (NODE)
+#define ICS_BAD_FLAG(NODE) TREE_LANG_FLAG_3 (NODE)
+
+#define USER_CONV_CAND(NODE) \
+ ((struct z_candidate *)WRAPPER_PTR (TREE_OPERAND (NODE, 1)))
+#define USER_CONV_FN(NODE) (USER_CONV_CAND (NODE)->fn)
- if (instance == NULL_TREE)
+int
+null_ptr_cst_p (t)
+ tree t;
+{
+ if (t == null_node
+ || (integer_zerop (t) && TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE))
+ return 1;
+ return 0;
+}
+
+static tree
+build_conv (code, type, from)
+ enum tree_code code;
+ tree type, from;
+{
+ tree t = build1 (code, type, from);
+ int rank = ICS_STD_RANK (from);
+ switch (code)
+ {
+ case PTR_CONV:
+ case PMEM_CONV:
+ case BASE_CONV:
+ case STD_CONV:
+ if (rank < STD_RANK)
+ rank = STD_RANK;
+ break;
+
+ case QUAL_CONV:
+ if (rank < EXACT_RANK)
+ rank = EXACT_RANK;
+
+ default:
+ break;
+ }
+ ICS_STD_RANK (t) = rank;
+ ICS_USER_FLAG (t) = ICS_USER_FLAG (from);
+ ICS_BAD_FLAG (t) = ICS_BAD_FLAG (from);
+ return t;
+}
+
+static tree
+non_reference (t)
+ tree t;
+{
+ if (TREE_CODE (t) == REFERENCE_TYPE)
+ t = TREE_TYPE (t);
+ return t;
+}
+
+static tree
+strip_top_quals (t)
+ tree t;
+{
+ if (TREE_CODE (t) == ARRAY_TYPE)
+ return t;
+ return TYPE_MAIN_VARIANT (t);
+}
+
+/* Returns the standard conversion path (see [conv]) from type FROM to type
+ TO, if any. For proper handling of null pointer constants, you must
+ also pass the expression EXPR to convert from. */
+
+static tree
+standard_conversion (to, from, expr)
+ tree to, from, expr;
+{
+ enum tree_code fcode, tcode;
+ tree conv;
+ int fromref = 0;
+
+ if (TREE_CODE (to) == REFERENCE_TYPE)
+ to = TREE_TYPE (to);
+ if (TREE_CODE (from) == REFERENCE_TYPE)
+ {
+ fromref = 1;
+ from = TREE_TYPE (from);
+ }
+ to = strip_top_quals (to);
+ from = strip_top_quals (from);
+
+ fcode = TREE_CODE (from);
+ tcode = TREE_CODE (to);
+
+ conv = build1 (IDENTITY_CONV, from, expr);
+
+ if (fcode == FUNCTION_TYPE)
{
- basetype = NULL_TREE;
- /* Check cases where this is really a call to raise
- an exception. */
- if (current_class_type && TREE_CODE (name) == IDENTIFIER_NODE)
+ from = build_pointer_type (from);
+ fcode = TREE_CODE (from);
+ conv = build_conv (LVALUE_CONV, from, conv);
+ }
+ else if (fcode == ARRAY_TYPE)
+ {
+ from = build_pointer_type (TREE_TYPE (from));
+ fcode = TREE_CODE (from);
+ conv = build_conv (LVALUE_CONV, from, conv);
+ }
+ else if (fromref || (expr && real_lvalue_p (expr)))
+ conv = build_conv (RVALUE_CONV, from, conv);
+
+ if (from == to)
+ return conv;
+
+ if ((tcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (to))
+ && expr && null_ptr_cst_p (expr))
+ {
+ conv = build_conv (STD_CONV, to, conv);
+ }
+ else if (tcode == POINTER_TYPE && fcode == POINTER_TYPE)
+ {
+ enum tree_code ufcode = TREE_CODE (TREE_TYPE (from));
+ enum tree_code utcode = TREE_CODE (TREE_TYPE (to));
+
+ if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (from)),
+ TYPE_MAIN_VARIANT (TREE_TYPE (to)), 1))
+ ;
+ else if (utcode == VOID_TYPE && ufcode != OFFSET_TYPE
+ && ufcode != FUNCTION_TYPE)
{
- basetype = purpose_member (name, CLASSTYPE_TAGS (current_class_type));
- if (basetype)
- basetype = TREE_VALUE (basetype);
+ from = build_pointer_type
+ (cp_build_type_variant (void_type_node,
+ TYPE_READONLY (TREE_TYPE (from)),
+ TYPE_VOLATILE (TREE_TYPE (from))));
+ conv = build_conv (PTR_CONV, from, conv);
}
- else if (TREE_CODE (name) == SCOPE_REF
- && TREE_CODE (TREE_OPERAND (name, 0)) == IDENTIFIER_NODE)
+ else if (ufcode == OFFSET_TYPE && utcode == OFFSET_TYPE)
{
- if (! is_aggr_typedef (TREE_OPERAND (name, 0), 1))
- return error_mark_node;
- basetype = purpose_member (TREE_OPERAND (name, 1),
- CLASSTYPE_TAGS (IDENTIFIER_TYPE_VALUE (TREE_OPERAND (name, 0))));
- if (basetype)
- basetype = TREE_VALUE (basetype);
+ tree fbase = TYPE_OFFSET_BASETYPE (TREE_TYPE (from));
+ tree tbase = TYPE_OFFSET_BASETYPE (TREE_TYPE (to));
+
+ if (DERIVED_FROM_P (fbase, tbase)
+ && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (from))),
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (to))),
+ 1)))
+ {
+ from = build_offset_type (tbase, TREE_TYPE (TREE_TYPE (from)));
+ from = build_pointer_type (from);
+ conv = build_conv (PMEM_CONV, from, conv);
+ }
+ }
+ else if (IS_AGGR_TYPE (TREE_TYPE (from))
+ && IS_AGGR_TYPE (TREE_TYPE (to)))
+ {
+ if (DERIVED_FROM_P (TREE_TYPE (to), TREE_TYPE (from)))
+ {
+ from = cp_build_type_variant (TREE_TYPE (to),
+ TYPE_READONLY (TREE_TYPE (from)),
+ TYPE_VOLATILE (TREE_TYPE (from)));
+ from = build_pointer_type (from);
+ conv = build_conv (PTR_CONV, from, conv);
+ }
}
- if (basetype != NULL_TREE)
- ;
- /* call to a constructor... */
- else if (basetype_path)
- basetype = BINFO_TYPE (basetype_path);
- else if (IDENTIFIER_HAS_TYPE_VALUE (name))
+ if (comptypes (from, to, 1))
+ /* OK */;
+ else if (comp_ptr_ttypes (TREE_TYPE (to), TREE_TYPE (from)))
+ conv = build_conv (QUAL_CONV, to, conv);
+ else if (ptr_reasonably_similar (TREE_TYPE (to), TREE_TYPE (from)))
{
- basetype = IDENTIFIER_TYPE_VALUE (name);
- name = constructor_name_full (basetype);
+ conv = build_conv (PTR_CONV, to, conv);
+ ICS_BAD_FLAG (conv) = 1;
}
else
+ return 0;
+
+ from = to;
+ }
+ else if (TYPE_PTRMEMFUNC_P (to) && TYPE_PTRMEMFUNC_P (from))
+ {
+ tree fromfn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (from));
+ tree tofn = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (to));
+ tree fbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fromfn)));
+ tree tbase = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (tofn)));
+
+ if (! DERIVED_FROM_P (fbase, tbase)
+ || ! comptypes (TREE_TYPE (fromfn), TREE_TYPE (tofn), 1)
+ || ! compparms (TREE_CHAIN (TYPE_ARG_TYPES (fromfn)),
+ TREE_CHAIN (TYPE_ARG_TYPES (tofn)), 1)
+ || TYPE_READONLY (fbase) != TYPE_READONLY (tbase)
+ || TYPE_VOLATILE (fbase) != TYPE_VOLATILE (tbase))
+ return 0;
+
+ from = cp_build_type_variant (tbase, TYPE_READONLY (fbase),
+ TYPE_VOLATILE (fbase));
+ from = build_cplus_method_type (from, TREE_TYPE (fromfn),
+ TREE_CHAIN (TYPE_ARG_TYPES (fromfn)));
+ from = build_ptrmemfunc_type (build_pointer_type (from));
+ conv = build_conv (PMEM_CONV, from, conv);
+ }
+ else if (tcode == BOOLEAN_TYPE)
+ {
+ if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE
+ || fcode == POINTER_TYPE || TYPE_PTRMEMFUNC_P (from)))
+ return 0;
+
+ conv = build_conv (STD_CONV, to, conv);
+ if (fcode == POINTER_TYPE
+ || (TYPE_PTRMEMFUNC_P (from) && ICS_STD_RANK (conv) < PBOOL_RANK))
+ ICS_STD_RANK (conv) = PBOOL_RANK;
+ }
+ /* We don't check for ENUMERAL_TYPE here because there are no standard
+ conversions to enum type. */
+ else if (tcode == INTEGER_TYPE || tcode == BOOLEAN_TYPE
+ || tcode == REAL_TYPE)
+ {
+ if (! (INTEGRAL_CODE_P (fcode) || fcode == REAL_TYPE))
+ return 0;
+ conv = build_conv (STD_CONV, to, conv);
+
+ /* Give this a better rank if it's a promotion. */
+ if (to == type_promotes_to (from)
+ && ICS_STD_RANK (TREE_OPERAND (conv, 0)) <= PROMO_RANK)
+ ICS_STD_RANK (conv) = PROMO_RANK;
+ }
+ else if (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
+ && DERIVED_FROM_P (to, from))
+ {
+ if (TREE_CODE (conv) == RVALUE_CONV)
+ conv = TREE_OPERAND (conv, 0);
+ conv = build_conv (BASE_CONV, to, conv);
+ }
+ else
+ return 0;
+
+ return conv;
+}
+
+/* Returns the conversion path from type FROM to reference type TO for
+ purposes of reference binding. For lvalue binding, either pass a
+ reference type to FROM or an lvalue expression to EXPR.
+
+ Currently does not distinguish in the generated trees between binding to
+ an lvalue and a temporary. Should it? */
+
+static tree
+reference_binding (rto, rfrom, expr, flags)
+ tree rto, rfrom, expr;
+ int flags;
+{
+ tree conv;
+ int lvalue = 1;
+ tree to = TREE_TYPE (rto);
+ tree from = rfrom;
+ int related;
+
+ if (TREE_CODE (from) == REFERENCE_TYPE)
+ from = TREE_TYPE (from);
+ else if (! expr || ! real_lvalue_p (expr))
+ lvalue = 0;
+
+ related = (comptypes (TYPE_MAIN_VARIANT (to),
+ TYPE_MAIN_VARIANT (from), 1)
+ || (IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from)
+ && DERIVED_FROM_P (to, from)));
+
+ if (lvalue && related
+ && TYPE_READONLY (to) >= TYPE_READONLY (from)
+ && TYPE_VOLATILE (to) >= TYPE_VOLATILE (from))
+ {
+ conv = build1 (IDENTITY_CONV, from, expr);
+
+ if (comptypes (TYPE_MAIN_VARIANT (to),
+ TYPE_MAIN_VARIANT (from), 1))
+ conv = build_conv (REF_BIND, rto, conv);
+ else
{
- tree typedef_name = lookup_name (name, 1);
- if (typedef_name && TREE_CODE (typedef_name) == TYPE_DECL)
- {
- /* Canonicalize the typedef name. */
- basetype = TREE_TYPE (typedef_name);
- name = TYPE_IDENTIFIER (basetype);
- }
- else
+ conv = build_conv (REF_BIND, rto, conv);
+ ICS_STD_RANK (conv) = STD_RANK;
+ }
+ }
+ else
+ conv = NULL_TREE;
+
+ if (! conv)
+ {
+ conv = standard_conversion (to, rfrom, expr);
+ if (conv)
+ {
+ conv = build_conv (REF_BIND, rto, conv);
+
+ /* Bind directly to a base subobject of a class rvalue. Do it
+ after building the conversion for proper handling of ICS_RANK. */
+ if (TREE_CODE (TREE_OPERAND (conv, 0)) == BASE_CONV)
+ TREE_OPERAND (conv, 0) = TREE_OPERAND (TREE_OPERAND (conv, 0), 0);
+ }
+ if (conv
+ && ((! (TYPE_READONLY (to) && ! TYPE_VOLATILE (to)
+ && (flags & LOOKUP_NO_TEMP_BIND) == 0))
+ /* If T1 is reference-related to T2, cv1 must be the same
+ cv-qualification as, or greater cv-qualification than,
+ cv2; otherwise, the program is ill-formed. */
+ || (related
+ && (TYPE_READONLY (to) < TYPE_READONLY (from)
+ || TYPE_VOLATILE (to) < TYPE_VOLATILE (from)))))
+ ICS_BAD_FLAG (conv) = 1;
+ }
+
+ return conv;
+}
+
+/* Returns the implicit conversion sequence (see [over.ics]) from type FROM
+ to type TO. The optional expression EXPR may affect the conversion.
+ FLAGS are the usual overloading flags. Only LOOKUP_NO_CONVERSION is
+ significant. */
+
+static tree
+implicit_conversion (to, from, expr, flags)
+ tree to, from, expr;
+ int flags;
+{
+ tree conv;
+ struct z_candidate *cand;
+
+ if (expr && type_unknown_p (expr))
+ {
+ expr = instantiate_type (to, expr, 0);
+ if (expr == error_mark_node)
+ return 0;
+ from = TREE_TYPE (expr);
+ }
+
+ if (TREE_CODE (to) == REFERENCE_TYPE)
+ conv = reference_binding (to, from, expr, flags);
+ else
+ conv = standard_conversion (to, from, expr);
+
+ if (conv)
+ ;
+ else if (expr != NULL_TREE
+ && (IS_AGGR_TYPE (non_reference (from))
+ || IS_AGGR_TYPE (non_reference (to)))
+ && (flags & LOOKUP_NO_CONVERSION) == 0)
+ {
+ cand = build_user_type_conversion_1
+ (to, expr, LOOKUP_ONLYCONVERTING);
+ if (cand)
+ conv = cand->second_conv;
+ if ((! conv || ICS_BAD_FLAG (conv))
+ && TREE_CODE (to) == REFERENCE_TYPE
+ && (flags & LOOKUP_NO_TEMP_BIND) == 0)
+ {
+ cand = build_user_type_conversion_1
+ (TYPE_MAIN_VARIANT (TREE_TYPE (to)), expr, LOOKUP_ONLYCONVERTING);
+ if (cand)
{
- cp_error ("no constructor named `%T' in scope",
- name);
- return error_mark_node;
+ if (! TYPE_READONLY (TREE_TYPE (to))
+ || TYPE_VOLATILE (TREE_TYPE (to)))
+ ICS_BAD_FLAG (cand->second_conv) = 1;
+ if (!conv || (ICS_BAD_FLAG (conv)
+ > ICS_BAD_FLAG (cand->second_conv)))
+ conv = build_conv (REF_BIND, to, cand->second_conv);
}
}
+ }
- if (! IS_AGGR_TYPE (basetype))
- {
- non_aggr_error:
- if ((flags & LOOKUP_COMPLAIN) && TREE_CODE (basetype) != ERROR_MARK)
- cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
- name, instance, basetype);
+ return conv;
+}
- return error_mark_node;
+/* Add a new entry to the list of candidates. Used by the add_*_candidate
+ functions. */
+
+static struct z_candidate *
+add_candidate (candidates, fn, convs, viable)
+ struct z_candidate *candidates;
+ tree fn, convs;
+ int viable;
+{
+ struct z_candidate *cand
+ = (struct z_candidate *) scratchalloc (sizeof (struct z_candidate));
+
+ cand->fn = fn;
+ cand->convs = convs;
+ cand->second_conv = NULL_TREE;
+ cand->viable = viable;
+ cand->basetype_path = NULL_TREE;
+ cand->template = NULL_TREE;
+ cand->warnings = NULL_TREE;
+ cand->next = candidates;
+
+ return cand;
+}
+
+/* Create an overload candidate for the function or method FN called with
+ the argument list ARGLIST and add it to CANDIDATES. FLAGS is passed on
+ to implicit_conversion. */
+
+static struct z_candidate *
+add_function_candidate (candidates, fn, arglist, flags)
+ struct z_candidate *candidates;
+ tree fn, arglist;
+ int flags;
+{
+ tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ int i, len;
+ tree convs;
+ tree parmnode = parmlist;
+ tree argnode = arglist;
+ int viable = 1;
+
+ /* The `this' and `in_chrg' arguments to constructors are not considered
+ in overload resolution. */
+ if (DECL_CONSTRUCTOR_P (fn))
+ {
+ parmnode = TREE_CHAIN (parmnode);
+ argnode = TREE_CHAIN (argnode);
+ if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+ {
+ parmnode = TREE_CHAIN (parmnode);
+ argnode = TREE_CHAIN (argnode);
}
}
- else if (instance == C_C_D || instance == current_class_decl)
+
+ len = list_length (argnode);
+ convs = make_scratch_vec (len);
+
+ for (i = 0; i < len; ++i)
{
- /* When doing initialization, we side-effect the TREE_TYPE of
- C_C_D, hence we cannot set up BASETYPE from CURRENT_CLASS_TYPE. */
- basetype = TREE_TYPE (C_C_D);
+ tree arg = TREE_VALUE (argnode);
+ tree argtype = TREE_TYPE (arg);
+ tree t;
- /* Anything manifestly `this' in constructors and destructors
- has a known type, so virtual function tables are not needed. */
- if (TYPE_VIRTUAL_P (basetype)
- && !(flags & LOOKUP_NONVIRTUAL))
- need_vtbl = (dtor_label || ctor_label)
- ? unneeded : maybe_needed;
+ /* An overloaded function does not have an argument type */
+ if (TREE_CODE (arg) == OVERLOAD)
+ argtype = unknown_type_node;
+ argtype = cp_build_type_variant
+ (argtype, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
- /* If `this' is a signature pointer and `name' is not a constructor,
- we are calling a signature member function. In that case, set the
- `basetype' to the signature type and dereference the `optr' field. */
- if (IS_SIGNATURE_POINTER (basetype)
- && TYPE_IDENTIFIER (basetype) != name)
+ if (parmnode == void_list_node)
+ break;
+ else if (parmnode)
+ t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg, flags);
+ else
{
- basetype = SIGNATURE_TYPE (basetype);
- instance_ptr = build_optr_ref (instance);
- instance_ptr = convert (build_pointer_type (basetype), instance_ptr);
- basetype_path = TYPE_BINFO (basetype);
+ t = build1 (IDENTITY_CONV, argtype, arg);
+ ICS_ELLIPSIS_FLAG (t) = 1;
}
+
+ if (i == 0 && t && TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE
+ && ! DECL_CONSTRUCTOR_P (fn))
+ ICS_THIS_FLAG (t) = 1;
+
+ TREE_VEC_ELT (convs, i) = t;
+ if (! t)
+ break;
+
+ if (ICS_BAD_FLAG (t))
+ viable = -1;
+
+ if (parmnode)
+ parmnode = TREE_CHAIN (parmnode);
+ argnode = TREE_CHAIN (argnode);
+ }
+
+ if (i < len)
+ viable = 0;
+
+ /* Make sure there are default args for the rest of the parms. */
+ for (; parmnode && parmnode != void_list_node;
+ parmnode = TREE_CHAIN (parmnode))
+ if (! TREE_PURPOSE (parmnode))
+ {
+ viable = 0;
+ break;
+ }
+
+ return add_candidate (candidates, fn, convs, viable);
+}
+
+/* Create an overload candidate for the conversion function FN which will
+ be invoked for expression OBJ, producing a pointer-to-function which
+ will in turn be called with the argument list ARGLIST, and add it to
+ CANDIDATES. FLAGS is passed on to implicit_conversion. */
+
+static struct z_candidate *
+add_conv_candidate (candidates, fn, obj, arglist)
+ struct z_candidate *candidates;
+ tree fn, obj, arglist;
+{
+ tree totype = TREE_TYPE (TREE_TYPE (fn));
+ tree parmlist = TYPE_ARG_TYPES (TREE_TYPE (totype));
+ int i, len = list_length (arglist) + 1;
+ tree convs = make_scratch_vec (len);
+ tree parmnode = parmlist;
+ tree argnode = arglist;
+ int viable = 1;
+ int flags = LOOKUP_NORMAL;
+
+ for (i = 0; i < len; ++i)
+ {
+ tree arg = i == 0 ? obj : TREE_VALUE (argnode);
+ tree argtype = lvalue_type (arg);
+ tree t;
+
+ if (i == 0)
+ t = implicit_conversion (totype, argtype, arg, flags);
+ else if (parmnode == void_list_node)
+ break;
+ else if (parmnode)
+ t = implicit_conversion (TREE_VALUE (parmnode), argtype, arg, flags);
else
{
- instance = C_C_D;
- instance_ptr = current_class_decl;
- basetype_path = TYPE_BINFO (current_class_type);
+ t = build1 (IDENTITY_CONV, argtype, arg);
+ ICS_ELLIPSIS_FLAG (t) = 1;
}
- result = build_field_call (basetype_path, instance_ptr, name, parms);
- if (result)
- return result;
+ TREE_VEC_ELT (convs, i) = t;
+ if (! t)
+ break;
+
+ if (ICS_BAD_FLAG (t))
+ viable = -1;
+
+ if (i == 0)
+ continue;
+
+ if (parmnode)
+ parmnode = TREE_CHAIN (parmnode);
+ argnode = TREE_CHAIN (argnode);
}
- else if (TREE_CODE (instance) == RESULT_DECL)
+
+ if (i < len)
+ viable = 0;
+
+ for (; parmnode && parmnode != void_list_node;
+ parmnode = TREE_CHAIN (parmnode))
+ if (! TREE_PURPOSE (parmnode))
+ {
+ viable = 0;
+ break;
+ }
+
+ return add_candidate (candidates, fn, convs, viable);
+}
+
+static struct z_candidate *
+build_builtin_candidate (candidates, fnname, type1, type2,
+ args, argtypes, flags)
+ struct z_candidate *candidates;
+ tree fnname, type1, type2, *args, *argtypes;
+ int flags;
+
+{
+ tree t, convs;
+ int viable = 1, i;
+ tree types[2];
+
+ types[0] = type1;
+ types[1] = type2;
+
+ convs = make_scratch_vec (args[2] ? 3 : (args[1] ? 2 : 1));
+
+ for (i = 0; i < 2; ++i)
{
- basetype = TREE_TYPE (instance);
- /* Should we ever have to make a virtual function reference
- from a RESULT_DECL, know that it must be of fixed type
- within the scope of this function. */
- if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
- need_vtbl = maybe_needed;
- instance_ptr = build1 (ADDR_EXPR, build_pointer_type (basetype), instance);
+ if (! args[i])
+ break;
+
+ t = implicit_conversion (types[i], argtypes[i], args[i], flags);
+ if (! t)
+ {
+ viable = 0;
+ /* We need something for printing the candidate. */
+ t = build1 (IDENTITY_CONV, types[i], NULL_TREE);
+ }
+ else if (ICS_BAD_FLAG (t))
+ viable = 0;
+ TREE_VEC_ELT (convs, i) = t;
}
- else
+
+ /* For COND_EXPR we rearranged the arguments; undo that now. */
+ if (args[2])
{
- /* The MAIN_VARIANT of the type that `instance_ptr' winds up being. */
- tree inst_ptr_basetype;
+ TREE_VEC_ELT (convs, 2) = TREE_VEC_ELT (convs, 1);
+ TREE_VEC_ELT (convs, 1) = TREE_VEC_ELT (convs, 0);
+ t = implicit_conversion (boolean_type_node, argtypes[2], args[2], flags);
+ if (t)
+ TREE_VEC_ELT (convs, 0) = t;
+ else
+ viable = 0;
+ }
- static_call_context =
- (TREE_CODE (instance) == INDIRECT_REF
- && TREE_CODE (TREE_OPERAND (instance, 0)) == NOP_EXPR
- && TREE_OPERAND (TREE_OPERAND (instance, 0), 0) == error_mark_node);
+ return add_candidate (candidates, fnname, convs, viable);
+}
- if (TREE_CODE (instance) == OFFSET_REF)
- instance = resolve_offset_ref (instance);
+static int
+is_complete (t)
+ tree t;
+{
+ return TYPE_SIZE (complete_type (t)) != NULL_TREE;
+}
- /* the base type of an instance variable is pointer to class */
- basetype = TREE_TYPE (instance);
+/* Create any builtin operator overload candidates for the operator in
+ question given the converted operand types TYPE1 and TYPE2. The other
+ args are passed through from add_builtin_candidates to
+ build_builtin_candidate. */
+
+static struct z_candidate *
+add_builtin_candidate (candidates, code, code2, fnname, type1, type2,
+ args, argtypes, flags)
+ struct z_candidate *candidates;
+ enum tree_code code, code2;
+ tree fnname, type1, type2, *args, *argtypes;
+ int flags;
+{
+ switch (code)
+ {
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ args[1] = integer_zero_node;
+ type2 = integer_type_node;
+ break;
+ default:
+ break;
+ }
- if (TREE_CODE (basetype) == REFERENCE_TYPE)
+ switch (code)
+ {
+
+/* 4 For every pair T, VQ), where T is an arithmetic or enumeration type,
+ and VQ is either volatile or empty, there exist candidate operator
+ functions of the form
+ VQ T& operator++(VQ T&);
+ T operator++(VQ T&, int);
+ 5 For every pair T, VQ), where T is an enumeration type or an arithmetic
+ type other than bool, and VQ is either volatile or empty, there exist
+ candidate operator functions of the form
+ VQ T& operator--(VQ T&);
+ T operator--(VQ T&, int);
+ 6 For every pair T, VQ), where T is a cv-qualified or cv-unqualified
+ complete object type, and VQ is either volatile or empty, there exist
+ candidate operator functions of the form
+ T*VQ& operator++(T*VQ&);
+ T*VQ& operator--(T*VQ&);
+ T* operator++(T*VQ&, int);
+ T* operator--(T*VQ&, int); */
+
+ case POSTDECREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ if (TREE_CODE (type1) == BOOLEAN_TYPE)
+ return candidates;
+ case POSTINCREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ if ((ARITHMETIC_TYPE_P (type1) && TREE_CODE (type1) != ENUMERAL_TYPE)
+ || TYPE_PTROB_P (type1))
{
- basetype = TREE_TYPE (basetype);
- if (! IS_AGGR_TYPE (basetype))
- goto non_aggr_error;
- /* Call to convert not needed because we are remaining
- within the same type. */
- instance_ptr = build1 (NOP_EXPR, build_pointer_type (basetype),
- instance);
- inst_ptr_basetype = TYPE_MAIN_VARIANT (basetype);
+ type1 = build_reference_type (type1);
+ break;
}
- else
+ return candidates;
+
+/* 7 For every cv-qualified or cv-unqualified complete object type T, there
+ exist candidate operator functions of the form
+
+ T& operator*(T*);
+
+ 8 For every function type T, there exist candidate operator functions of
+ the form
+ T& operator*(T*); */
+
+ case INDIRECT_REF:
+ if (TREE_CODE (type1) == POINTER_TYPE
+ && (TYPE_PTROB_P (type1)
+ || TREE_CODE (TREE_TYPE (type1)) == FUNCTION_TYPE))
+ break;
+ return candidates;
+
+/* 9 For every type T, there exist candidate operator functions of the form
+ T* operator+(T*);
+
+ 10For every promoted arithmetic type T, there exist candidate operator
+ functions of the form
+ T operator+(T);
+ T operator-(T); */
+
+ case CONVERT_EXPR: /* unary + */
+ if (TREE_CODE (type1) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type1)) != OFFSET_TYPE)
+ break;
+ case NEGATE_EXPR:
+ if (ARITHMETIC_TYPE_P (type1))
+ break;
+ return candidates;
+
+/* 11For every promoted integral type T, there exist candidate operator
+ functions of the form
+ T operator~(T); */
+
+ case BIT_NOT_EXPR:
+ if (INTEGRAL_TYPE_P (type1))
+ break;
+ return candidates;
+
+/* 12For every quintuple C1, C2, T, CV1, CV2), where C2 is a class type, C1
+ is the same type as C2 or is a derived class of C2, T is a complete
+ object type or a function type, and CV1 and CV2 are cv-qualifier-seqs,
+ there exist candidate operator functions of the form
+ CV12 T& operator->*(CV1 C1*, CV2 T C2::*);
+ where CV12 is the union of CV1 and CV2. */
+
+ case MEMBER_REF:
+ if (TREE_CODE (type1) == POINTER_TYPE
+ && (TYPE_PTRMEMFUNC_P (type2) || TYPE_PTRMEM_P (type2)))
{
- if (! IS_AGGR_TYPE (basetype)
- && ! (TYPE_LANG_SPECIFIC (basetype)
- && (IS_SIGNATURE_POINTER (basetype)
- || IS_SIGNATURE_REFERENCE (basetype))))
- goto non_aggr_error;
-
- /* If `instance' is a signature pointer/reference and `name' is
- not a constructor, we are calling a signature member function.
- In that case set the `basetype' to the signature type. */
- if ((IS_SIGNATURE_POINTER (basetype)
- || IS_SIGNATURE_REFERENCE (basetype))
- && TYPE_IDENTIFIER (basetype) != name)
- basetype = SIGNATURE_TYPE (basetype);
-
- if ((IS_SIGNATURE (basetype)
- && (instance_ptr = instance))
- || (lvalue_p (instance)
- && (instance_ptr = build_unary_op (ADDR_EXPR, instance, 0)))
- || (instance_ptr = unary_complex_lvalue (ADDR_EXPR, instance)))
- {
- if (instance_ptr == error_mark_node)
- return error_mark_node;
- }
- else if (TREE_CODE (instance) == NOP_EXPR
- || TREE_CODE (instance) == CONSTRUCTOR)
- {
- /* A cast is not an lvalue. Initialize a fresh temp
- with the value we are casting from, and proceed with
- that temporary. We can't cast to a reference type,
- so that simplifies the initialization to something
- we can manage. */
- tree temp = get_temp_name (TREE_TYPE (instance), 0);
- if (IS_AGGR_TYPE (TREE_TYPE (instance)))
- expand_aggr_init (temp, instance, 0, flags);
- else
- {
- store_init_value (temp, instance);
- expand_decl_init (temp);
- }
- instance = temp;
- instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
- }
- else
+ tree c1 = TREE_TYPE (type1);
+ tree c2 = (TYPE_PTRMEMFUNC_P (type2)
+ ? TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type2)))
+ : TYPE_OFFSET_BASETYPE (TREE_TYPE (type2)));
+
+ if (IS_AGGR_TYPE (c1) && DERIVED_FROM_P (c2, c1)
+ && (TYPE_PTRMEMFUNC_P (type2)
+ || is_complete (TREE_TYPE (TREE_TYPE (type2)))))
+ break;
+ }
+ return candidates;
+
+/* 13For every pair of promoted arithmetic types L and R, there exist can-
+ didate operator functions of the form
+ LR operator*(L, R);
+ LR operator/(L, R);
+ LR operator+(L, R);
+ LR operator-(L, R);
+ bool operator<(L, R);
+ bool operator>(L, R);
+ bool operator<=(L, R);
+ bool operator>=(L, R);
+ bool operator==(L, R);
+ bool operator!=(L, R);
+ where LR is the result of the usual arithmetic conversions between
+ types L and R.
+
+ 14For every pair of types T and I, where T is a cv-qualified or cv-
+ unqualified complete object type and I is a promoted integral type,
+ there exist candidate operator functions of the form
+ T* operator+(T*, I);
+ T& operator[](T*, I);
+ T* operator-(T*, I);
+ T* operator+(I, T*);
+ T& operator[](I, T*);
+
+ 15For every T, where T is a pointer to complete object type, there exist
+ candidate operator functions of the form112)
+ ptrdiff_t operator-(T, T);
+
+ 16For every pointer type T, there exist candidate operator functions of
+ the form
+ bool operator<(T, T);
+ bool operator>(T, T);
+ bool operator<=(T, T);
+ bool operator>=(T, T);
+ bool operator==(T, T);
+ bool operator!=(T, T);
+
+ 17For every pointer to member type T, there exist candidate operator
+ functions of the form
+ bool operator==(T, T);
+ bool operator!=(T, T); */
+
+ case MINUS_EXPR:
+ if (TYPE_PTROB_P (type1) && TYPE_PTROB_P (type2))
+ break;
+ if (TYPE_PTROB_P (type1) && INTEGRAL_TYPE_P (type2))
+ {
+ type2 = ptrdiff_type_node;
+ break;
+ }
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ break;
+ return candidates;
+
+ case EQ_EXPR:
+ case NE_EXPR:
+ if ((TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2))
+ || (TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2)))
+ break;
+ if ((TYPE_PTRMEMFUNC_P (type1) || TYPE_PTRMEM_P (type1))
+ && null_ptr_cst_p (args[1]))
+ {
+ type2 = type1;
+ break;
+ }
+ if ((TYPE_PTRMEMFUNC_P (type2) || TYPE_PTRMEM_P (type2))
+ && null_ptr_cst_p (args[0]))
+ {
+ type1 = type2;
+ break;
+ }
+ case LT_EXPR:
+ case GT_EXPR:
+ case LE_EXPR:
+ case GE_EXPR:
+ case MAX_EXPR:
+ case MIN_EXPR:
+ if ((ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ || (TYPE_PTR_P (type1) && TYPE_PTR_P (type2)))
+ break;
+ if (TYPE_PTR_P (type1) && null_ptr_cst_p (args[1]))
+ {
+ type2 = type1;
+ break;
+ }
+ if (null_ptr_cst_p (args[0]) && TYPE_PTR_P (type2))
+ {
+ type1 = type2;
+ break;
+ }
+ return candidates;
+
+ case PLUS_EXPR:
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ break;
+ case ARRAY_REF:
+ if (INTEGRAL_TYPE_P (type1) && TYPE_PTROB_P (type2))
+ {
+ type1 = ptrdiff_type_node;
+ break;
+ }
+ if (TYPE_PTROB_P (type1) && INTEGRAL_TYPE_P (type2))
+ {
+ type2 = ptrdiff_type_node;
+ break;
+ }
+ return candidates;
+
+/* 18For every pair of promoted integral types L and R, there exist candi-
+ date operator functions of the form
+ LR operator%(L, R);
+ LR operator&(L, R);
+ LR operator^(L, R);
+ LR operator|(L, R);
+ L operator<<(L, R);
+ L operator>>(L, R);
+ where LR is the result of the usual arithmetic conversions between
+ types L and R. */
+
+ case TRUNC_MOD_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2))
+ break;
+ return candidates;
+
+/* 19For every triple L, VQ, R), where L is an arithmetic or enumeration
+ type, VQ is either volatile or empty, and R is a promoted arithmetic
+ type, there exist candidate operator functions of the form
+ VQ L& operator=(VQ L&, R);
+ VQ L& operator*=(VQ L&, R);
+ VQ L& operator/=(VQ L&, R);
+ VQ L& operator+=(VQ L&, R);
+ VQ L& operator-=(VQ L&, R);
+
+ 20For every pair T, VQ), where T is any type and VQ is either volatile
+ or empty, there exist candidate operator functions of the form
+ T*VQ& operator=(T*VQ&, T*);
+
+ 21For every pair T, VQ), where T is a pointer to member type and VQ is
+ either volatile or empty, there exist candidate operator functions of
+ the form
+ VQ T& operator=(VQ T&, T);
+
+ 22For every triple T, VQ, I), where T is a cv-qualified or cv-
+ unqualified complete object type, VQ is either volatile or empty, and
+ I is a promoted integral type, there exist candidate operator func-
+ tions of the form
+ T*VQ& operator+=(T*VQ&, I);
+ T*VQ& operator-=(T*VQ&, I);
+
+ 23For every triple L, VQ, R), where L is an integral or enumeration
+ type, VQ is either volatile or empty, and R is a promoted integral
+ type, there exist candidate operator functions of the form
+
+ VQ L& operator%=(VQ L&, R);
+ VQ L& operator<<=(VQ L&, R);
+ VQ L& operator>>=(VQ L&, R);
+ VQ L& operator&=(VQ L&, R);
+ VQ L& operator^=(VQ L&, R);
+ VQ L& operator|=(VQ L&, R); */
+
+ case MODIFY_EXPR:
+ switch (code2)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ if (TYPE_PTROB_P (type1) && INTEGRAL_TYPE_P (type2))
{
- if (TREE_CODE (instance) != CALL_EXPR)
- my_friendly_abort (125);
- if (TYPE_NEEDS_CONSTRUCTING (basetype))
- instance = build_cplus_new (basetype, instance, 0);
- else
- {
- instance = get_temp_name (basetype, 0);
- TREE_ADDRESSABLE (instance) = 1;
- }
- instance_ptr = build_unary_op (ADDR_EXPR, instance, 0);
+ type2 = ptrdiff_type_node;
+ break;
}
- /* @@ Should we call comp_target_types here? */
- if (IS_SIGNATURE (basetype))
- inst_ptr_basetype = basetype;
- else
- inst_ptr_basetype = TREE_TYPE (TREE_TYPE (instance_ptr));
- if (TYPE_MAIN_VARIANT (basetype) == TYPE_MAIN_VARIANT (inst_ptr_basetype))
- basetype = inst_ptr_basetype;
- else
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ break;
+ return candidates;
+
+ case TRUNC_MOD_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2))
+ break;
+ return candidates;
+
+ case NOP_EXPR:
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ break;
+ if ((TYPE_PTRMEMFUNC_P (type1) && TYPE_PTRMEMFUNC_P (type2))
+ || (TYPE_PTR_P (type1) && TYPE_PTR_P (type2))
+ || (TYPE_PTRMEM_P (type1) && TYPE_PTRMEM_P (type2))
+ || ((TYPE_PTRMEMFUNC_P (type1)
+ || TREE_CODE (type1) == POINTER_TYPE)
+ && null_ptr_cst_p (args[1])))
{
- instance_ptr = convert (build_pointer_type (basetype), instance_ptr);
- if (instance_ptr == error_mark_node)
- return error_mark_node;
+ type2 = type1;
+ break;
}
+ return candidates;
+
+ default:
+ my_friendly_abort (367);
}
+ type1 = build_reference_type (type1);
+ break;
+
+ case COND_EXPR:
+ /* Kludge around broken overloading rules whereby
+ bool ? const char& : enum is ambiguous
+ (between int and const char&). */
+ flags |= LOOKUP_NO_TEMP_BIND;
+
+ /* Extension: Support ?: of enumeral type. Hopefully this will not
+ be an extension for long. */
+ if (TREE_CODE (type1) == ENUMERAL_TYPE && type1 == type2)
+ break;
+ else if (TREE_CODE (type1) == ENUMERAL_TYPE
+ || TREE_CODE (type2) == ENUMERAL_TYPE)
+ return candidates;
+ if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2))
+ break;
+ if (TREE_CODE (type1) == TREE_CODE (type2)
+ && (TREE_CODE (type1) == REFERENCE_TYPE
+ || TREE_CODE (type1) == POINTER_TYPE
+ || TYPE_PTRMEMFUNC_P (type1)
+ || IS_AGGR_TYPE (type1)))
+ break;
+ if (TREE_CODE (type1) == REFERENCE_TYPE
+ || TREE_CODE (type2) == REFERENCE_TYPE)
+ return candidates;
+ if (((TYPE_PTRMEMFUNC_P (type1) || TREE_CODE (type1) == POINTER_TYPE)
+ && null_ptr_cst_p (args[1]))
+ || IS_AGGR_TYPE (type1))
+ {
+ type2 = type1;
+ break;
+ }
+ if (((TYPE_PTRMEMFUNC_P (type2) || TREE_CODE (type2) == POINTER_TYPE)
+ && null_ptr_cst_p (args[0]))
+ || IS_AGGR_TYPE (type2))
+ {
+ type1 = type2;
+ break;
+ }
+ return candidates;
- /* After converting `instance_ptr' above, `inst_ptr_basetype' was
- not updated, so we use `basetype' instead. */
- if (basetype_path == NULL_TREE
- && IS_SIGNATURE (basetype))
- basetype_path = TYPE_BINFO (basetype);
- else if (basetype_path == NULL_TREE ||
- BINFO_TYPE (basetype_path) != TYPE_MAIN_VARIANT (inst_ptr_basetype))
- basetype_path = TYPE_BINFO (inst_ptr_basetype);
+ default:
+ my_friendly_abort (367);
+ }
- result = build_field_call (basetype_path, instance_ptr, name, parms);
- if (result)
- return result;
+ /* If we're dealing with two pointer types, we need candidates
+ for both of them. */
+ if (type2 && type1 != type2
+ && TREE_CODE (type1) == TREE_CODE (type2)
+ && (TREE_CODE (type1) == REFERENCE_TYPE
+ || (TREE_CODE (type1) == POINTER_TYPE
+ && TYPE_PTRMEM_P (type1) == TYPE_PTRMEM_P (type2))
+ || TYPE_PTRMEMFUNC_P (type1)
+ || IS_AGGR_TYPE (type1)))
+ {
+ candidates = build_builtin_candidate
+ (candidates, fnname, type1, type1, args, argtypes, flags);
+ return build_builtin_candidate
+ (candidates, fnname, type2, type2, args, argtypes, flags);
+ }
+
+ return build_builtin_candidate
+ (candidates, fnname, type1, type2, args, argtypes, flags);
+}
+
+tree
+type_decays_to (type)
+ tree type;
+{
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ return build_pointer_type (TREE_TYPE (type));
+ if (TREE_CODE (type) == FUNCTION_TYPE)
+ return build_pointer_type (type);
+ return type;
+}
+
+/* There are three conditions of builtin candidates:
+
+ 1) bool-taking candidates. These are the same regardless of the input.
+ 2) pointer-pair taking candidates. These are generated for each type
+ one of the input types converts to.
+ 3) arithmetic candidates. According to the WP, we should generate
+ all of these, but I'm trying not to... */
+
+static struct z_candidate *
+add_builtin_candidates (candidates, code, code2, fnname, args, flags)
+ struct z_candidate *candidates;
+ enum tree_code code, code2;
+ tree fnname, *args;
+ int flags;
+{
+ int ref1, i;
+ tree type, argtypes[3], types[2];
- if (!(flags & LOOKUP_NONVIRTUAL) && TYPE_VIRTUAL_P (basetype))
+ for (i = 0; i < 3; ++i)
+ {
+ if (args[i])
+ argtypes[i] = lvalue_type (args[i]);
+ else
+ argtypes[i] = NULL_TREE;
+ }
+
+ switch (code)
+ {
+/* 4 For every pair T, VQ), where T is an arithmetic or enumeration type,
+ and VQ is either volatile or empty, there exist candidate operator
+ functions of the form
+ VQ T& operator++(VQ T&); */
+
+ case POSTINCREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case MODIFY_EXPR:
+ ref1 = 1;
+ break;
+
+/* 24There also exist candidate operator functions of the form
+ bool operator!(bool);
+ bool operator&&(bool, bool);
+ bool operator||(bool, bool); */
+
+ case TRUTH_NOT_EXPR:
+ return build_builtin_candidate
+ (candidates, fnname, boolean_type_node,
+ NULL_TREE, args, argtypes, flags);
+
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ return build_builtin_candidate
+ (candidates, fnname, boolean_type_node,
+ boolean_type_node, args, argtypes, flags);
+
+ case ADDR_EXPR:
+ case COMPOUND_EXPR:
+ case COMPONENT_REF:
+ return candidates;
+
+ default:
+ ref1 = 0;
+ }
+
+ types[0] = types[1] = NULL_TREE;
+
+ for (i = 0; i < 2; ++i)
+ {
+ if (! args[i])
+ ;
+ else if (IS_AGGR_TYPE (argtypes[i]))
{
- if (TREE_SIDE_EFFECTS (instance_ptr))
+ tree convs = lookup_conversions (argtypes[i]);
+
+ if (i == 0 && code == MODIFY_EXPR && code2 == NOP_EXPR)
+ return candidates;
+
+ convs = lookup_conversions (argtypes[i]);
+
+ if (code == COND_EXPR)
{
- /* This action is needed because the instance is needed
- for providing the base of the virtual function table.
- Without using a SAVE_EXPR, the function we are building
- may be called twice, or side effects on the instance
- variable (such as a post-increment), may happen twice. */
- instance_ptr = save_expr (instance_ptr);
- instance = build_indirect_ref (instance_ptr, NULL_PTR);
+ if (real_lvalue_p (args[i]))
+ types[i] = scratch_tree_cons
+ (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
+
+ types[i] = scratch_tree_cons
+ (NULL_TREE, TYPE_MAIN_VARIANT (argtypes[i]), types[i]);
}
- else if (TREE_CODE (TREE_TYPE (instance)) == POINTER_TYPE)
+
+ else if (! convs)
+ return candidates;
+
+ for (; convs; convs = TREE_CHAIN (convs))
{
- /* This happens when called for operator new (). */
- instance = build_indirect_ref (instance, NULL_PTR);
- }
+ type = TREE_TYPE (TREE_TYPE (TREE_VALUE (convs)));
+
+ if (i == 0 && ref1
+ && (TREE_CODE (type) != REFERENCE_TYPE
+ || TYPE_READONLY (TREE_TYPE (type))))
+ continue;
+
+ if (code == COND_EXPR && TREE_CODE (type) == REFERENCE_TYPE)
+ types[i] = scratch_tree_cons (NULL_TREE, type, types[i]);
+
+ type = non_reference (type);
+ if (i != 0 || ! ref1)
+ {
+ type = TYPE_MAIN_VARIANT (type_decays_to (type));
+ if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
+ types[i] = scratch_tree_cons (NULL_TREE, type, types[i]);
+ if (INTEGRAL_TYPE_P (type))
+ type = type_promotes_to (type);
+ }
- need_vtbl = maybe_needed;
+ if (! value_member (type, types[i]))
+ types[i] = scratch_tree_cons (NULL_TREE, type, types[i]);
+ }
+ }
+ else
+ {
+ if (code == COND_EXPR && real_lvalue_p (args[i]))
+ types[i] = scratch_tree_cons
+ (NULL_TREE, build_reference_type (argtypes[i]), types[i]);
+ type = non_reference (argtypes[i]);
+ if (i != 0 || ! ref1)
+ {
+ type = TYPE_MAIN_VARIANT (type_decays_to (type));
+ if (code == COND_EXPR && TREE_CODE (type) == ENUMERAL_TYPE)
+ types[i] = scratch_tree_cons (NULL_TREE, type, types[i]);
+ if (INTEGRAL_TYPE_P (type))
+ type = type_promotes_to (type);
+ }
+ types[i] = scratch_tree_cons (NULL_TREE, type, types[i]);
}
}
- if (TYPE_SIZE (basetype) == 0)
+ for (; types[0]; types[0] = TREE_CHAIN (types[0]))
{
- /* This is worth complaining about, I think. */
- cp_error ("cannot lookup method in incomplete type `%T'", basetype);
- return error_mark_node;
+ if (types[1])
+ for (type = types[1]; type; type = TREE_CHAIN (type))
+ candidates = add_builtin_candidate
+ (candidates, code, code2, fnname, TREE_VALUE (types[0]),
+ TREE_VALUE (type), args, argtypes, flags);
+ else
+ candidates = add_builtin_candidate
+ (candidates, code, code2, fnname, TREE_VALUE (types[0]),
+ NULL_TREE, args, argtypes, flags);
}
- save_basetype = TYPE_MAIN_VARIANT (basetype);
+ return candidates;
+}
-#if 0
- if (all_virtual == 1
- && (! strncmp (IDENTIFIER_POINTER (name), OPERATOR_METHOD_FORMAT,
- OPERATOR_METHOD_LENGTH)
- || instance_ptr == NULL_TREE
- || (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype) == 0)))
- all_virtual = 0;
-#endif
- last = NULL_TREE;
- for (parmtypes = NULL_TREE, parm = parms; parm; parm = TREE_CHAIN (parm))
+/* If TMPL can be successfully instantiated as indicated by
+ EXPLICIT_TARGS and ARGLIST, adds the instantiation to CANDIDATES.
+
+ TMPL is the template. EXPLICIT_TARGS are any explicit template
+ arguments. ARGLIST is the arguments provided at the call-site.
+ The RETURN_TYPE is the desired type for conversion operators. If
+ OBJ is NULL_TREE, FLAGS are as for add_function_candidate. If an
+ OBJ is supplied, FLAGS are ignored, and OBJ is as for
+ add_conv_candidate. */
+
+static struct z_candidate*
+add_template_candidate_real (candidates, tmpl, explicit_targs,
+ arglist, return_type, flags,
+ obj, strict)
+ struct z_candidate *candidates;
+ tree tmpl, explicit_targs, arglist, return_type;
+ int flags;
+ tree obj;
+ unification_kind_t strict;
+{
+ int ntparms = DECL_NTPARMS (tmpl);
+ tree targs = make_scratch_vec (ntparms);
+ struct z_candidate *cand;
+ int i;
+ tree fn;
+
+ i = fn_type_unification (tmpl, explicit_targs, targs, arglist,
+ return_type, strict, NULL_TREE);
+
+ if (i != 0)
+ return candidates;
+
+ fn = instantiate_template (tmpl, targs);
+ if (fn == error_mark_node)
+ return candidates;
+
+ if (obj != NULL_TREE)
+ /* Aha, this is a conversion function. */
+ cand = add_conv_candidate (candidates, fn, obj, arglist);
+ else
+ cand = add_function_candidate (candidates, fn, arglist, flags);
+ if (DECL_TI_TEMPLATE (fn) != tmpl)
+ /* This situation can occur if a member template of a template
+ class is specialized. Then, instantiate_template might return
+ an instantiation of the specialization, in which case the
+ DECL_TI_TEMPLATE field will point at the original
+ specialization. For example:
+
+ template <class T> struct S { template <class U> void f(U);
+ template <> void f(int) {}; };
+ S<double> sd;
+ sd.f(3);
+
+ Here, TMPL will be template <class U> S<double>::f(U).
+ And, instantiate template will give us the specialization
+ template <> S<double>::f(int). But, the DECL_TI_TEMPLATE field
+ for this will point at template <class T> template <> S<T>::f(int),
+ so that we can find the definition. For the purposes of
+ overload resolution, however, we want the original TMPL. */
+ cand->template = tree_cons (tmpl, targs, NULL_TREE);
+ else
+ cand->template = DECL_TEMPLATE_INFO (fn);
+
+ return cand;
+}
+
+
+static struct z_candidate *
+add_template_candidate (candidates, tmpl, explicit_targs,
+ arglist, return_type, flags, strict)
+ struct z_candidate *candidates;
+ tree tmpl, explicit_targs, arglist, return_type;
+ int flags;
+ unification_kind_t strict;
+{
+ return
+ add_template_candidate_real (candidates, tmpl, explicit_targs,
+ arglist, return_type, flags,
+ NULL_TREE, strict);
+}
+
+
+static struct z_candidate *
+add_template_conv_candidate (candidates, tmpl, obj, arglist, return_type)
+ struct z_candidate *candidates;
+ tree tmpl, obj, arglist, return_type;
+{
+ return
+ add_template_candidate_real (candidates, tmpl, NULL_TREE, arglist,
+ return_type, 0, obj, DEDUCE_CONV);
+}
+
+
+static int
+any_viable (cands)
+ struct z_candidate *cands;
+{
+ for (; cands; cands = cands->next)
+ if (pedantic ? cands->viable == 1 : cands->viable)
+ return 1;
+ return 0;
+}
+
+static struct z_candidate *
+splice_viable (cands)
+ struct z_candidate *cands;
+{
+ struct z_candidate **p = &cands;
+
+ for (; *p; )
{
- tree t = TREE_TYPE (TREE_VALUE (parm));
- if (TREE_CODE (t) == OFFSET_TYPE)
+ if (pedantic ? (*p)->viable == 1 : (*p)->viable)
+ p = &((*p)->next);
+ else
+ *p = (*p)->next;
+ }
+
+ return cands;
+}
+
+static tree
+build_this (obj)
+ tree obj;
+{
+ /* Fix this to work on non-lvalues. */
+ if (IS_SIGNATURE_POINTER (TREE_TYPE (obj))
+ || IS_SIGNATURE_REFERENCE (TREE_TYPE (obj)))
+ return obj;
+ else
+ return build_unary_op (ADDR_EXPR, obj, 0);
+}
+
+static void
+print_z_candidates (candidates)
+ struct z_candidate *candidates;
+{
+ char *str = "candidates are:";
+ for (; candidates; candidates = candidates->next)
+ {
+ if (TREE_CODE (candidates->fn) == IDENTIFIER_NODE)
{
- /* Convert OFFSET_TYPE entities to their normal selves. */
- TREE_VALUE (parm) = resolve_offset_ref (TREE_VALUE (parm));
- t = TREE_TYPE (TREE_VALUE (parm));
+ if (candidates->fn == ansi_opname [COND_EXPR])
+ cp_error ("%s %D(%T, %T, %T) <builtin>", str, candidates->fn,
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)),
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 2)));
+ else if (TREE_VEC_LENGTH (candidates->convs) == 2)
+ cp_error ("%s %D(%T, %T) <builtin>", str, candidates->fn,
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)),
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 1)));
+ else
+ cp_error ("%s %D(%T) <builtin>", str, candidates->fn,
+ TREE_TYPE (TREE_VEC_ELT (candidates->convs, 0)));
}
- if (TREE_CODE (TREE_VALUE (parm)) == OFFSET_REF
- && TREE_CODE (t) == METHOD_TYPE)
+ else
+ cp_error_at ("%s %+D%s", str, candidates->fn,
+ candidates->viable == -1 ? " <near match>" : "");
+ str = " ";
+ }
+}
+
+/* Returns the best overload candidate to perform the requested
+ conversion. This function is used for three the overloading situations
+ described in [over.match.copy], [over.match.conv], and [over.match.ref].
+ If TOTYPE is a REFERENCE_TYPE, we're trying to find an lvalue binding as
+ per [dcl.init.ref], so we ignore temporary bindings. */
+
+static struct z_candidate *
+build_user_type_conversion_1 (totype, expr, flags)
+ tree totype, expr;
+ int flags;
+{
+ struct z_candidate *candidates, *cand;
+ tree fromtype = TREE_TYPE (expr);
+ tree ctors = NULL_TREE, convs = NULL_TREE, *p;
+ tree args = NULL_TREE;
+ tree templates = NULL_TREE;
+
+ if (IS_AGGR_TYPE (totype))
+ ctors = lookup_fnfields (TYPE_BINFO (totype), ctor_identifier, 0);
+ if (IS_AGGR_TYPE (fromtype)
+ && (! IS_AGGR_TYPE (totype) || ! DERIVED_FROM_P (totype, fromtype)))
+ convs = lookup_conversions (fromtype);
+
+ candidates = 0;
+ flags |= LOOKUP_NO_CONVERSION;
+
+ if (ctors)
+ {
+ tree t = build_int_2 (0, 0);
+ TREE_TYPE (t) = build_pointer_type (totype);
+ args = build_scratch_list (NULL_TREE, expr);
+ if (TYPE_USES_VIRTUAL_BASECLASSES (totype))
+ args = scratch_tree_cons (NULL_TREE, integer_one_node, args);
+ args = scratch_tree_cons (NULL_TREE, t, args);
+
+ ctors = TREE_VALUE (ctors);
+ }
+ for (; ctors; ctors = OVL_NEXT (ctors))
+ {
+ tree ctor = OVL_CURRENT (ctors);
+ if (DECL_NONCONVERTING_P (ctor))
+ continue;
+
+ if (TREE_CODE (ctor) == TEMPLATE_DECL)
{
- TREE_VALUE (parm) = build_unary_op (ADDR_EXPR, TREE_VALUE (parm), 0);
- }
+ templates = scratch_tree_cons (NULL_TREE, ctor, templates);
+ candidates =
+ add_template_candidate (candidates, ctor,
+ NULL_TREE, args, NULL_TREE, flags,
+ DEDUCE_CALL);
+ }
+ else
+ candidates = add_function_candidate (candidates, ctor,
+ args, flags);
+
+ if (candidates)
+ {
+ candidates->second_conv = build1 (IDENTITY_CONV, totype, NULL_TREE);
+ candidates->basetype_path = TYPE_BINFO (totype);
+ }
+ }
+
+ if (convs)
+ args = build_scratch_list (NULL_TREE, build_this (expr));
+
+ for (; convs; convs = TREE_CHAIN (convs))
+ {
+ tree fns = TREE_VALUE (convs);
+ int convflags = LOOKUP_NO_CONVERSION;
+ tree ics;
+
+ /* If we are called to convert to a reference type, we are trying to
+ find an lvalue binding, so don't even consider temporaries. If
+ we don't find an lvalue binding, the caller will try again to
+ look for a temporary binding. */
+ if (TREE_CODE (totype) == REFERENCE_TYPE)
+ convflags |= LOOKUP_NO_TEMP_BIND;
+
+ if (TREE_CODE (fns) != TEMPLATE_DECL)
+ ics = implicit_conversion
+ (totype, TREE_TYPE (TREE_TYPE (OVL_CURRENT (fns))), 0, convflags);
+ else
+ /* We can't compute this yet. */
+ ics = error_mark_node;
+
+ if (TREE_CODE (totype) == REFERENCE_TYPE && ics && ICS_BAD_FLAG (ics))
+ /* ignore the near match. */;
+ else if (ics)
+ for (; fns; fns = OVL_NEXT (fns))
+ {
+ tree fn = OVL_CURRENT (fns);
+ struct z_candidate *old_candidates = candidates;
+
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
+ {
+ templates = scratch_tree_cons (NULL_TREE, fn, templates);
+ candidates =
+ add_template_candidate (candidates, fn, NULL_TREE,
+ args, totype, flags,
+ DEDUCE_CONV);
+ }
+ else
+ candidates = add_function_candidate (candidates, fn,
+ args, flags);
+
+ if (candidates != old_candidates)
+ {
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
+ ics = implicit_conversion
+ (totype, TREE_TYPE (TREE_TYPE (candidates->fn)),
+ 0, convflags);
+
+ candidates->second_conv = ics;
+ candidates->basetype_path = TREE_PURPOSE (convs);
+
+ if (ics == NULL_TREE)
+ candidates->viable = 0;
+ else if (candidates->viable == 1 && ICS_BAD_FLAG (ics))
+ candidates->viable = -1;
+ }
+ }
+ }
+
+ if (! any_viable (candidates))
+ {
#if 0
- /* This breaks reference-to-array parameters. */
- if (TREE_CODE (t) == ARRAY_TYPE)
+ if (flags & LOOKUP_COMPLAIN)
{
- /* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
- This eliminates needless calls to `compute_conversion_costs'. */
- TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
- t = TREE_TYPE (TREE_VALUE (parm));
+ if (candidates && ! candidates->next)
+ /* say why this one won't work or try to be loose */;
+ else
+ cp_error ("no viable candidates");
}
#endif
- if (t == error_mark_node)
- return error_mark_node;
- last = build_tree_list (NULL_TREE, t);
- parmtypes = chainon (parmtypes, last);
+
+ return 0;
}
- if (instance && IS_SIGNATURE (basetype))
+ candidates = splice_viable (candidates);
+ cand = tourney (candidates);
+
+ if (cand == 0)
{
- /* @@ Should this be the constp/volatilep flags for the optr field
- of the signature pointer? */
- constp = TYPE_READONLY (basetype);
- volatilep = TYPE_VOLATILE (basetype);
- parms = tree_cons (NULL_TREE, instance_ptr, parms);
+ if (flags & LOOKUP_COMPLAIN)
+ {
+ cp_error ("conversion from `%T' to `%T' is ambiguous",
+ fromtype, totype);
+ print_z_candidates (candidates);
+ }
+
+ cand = candidates; /* any one will do */
+ cand->second_conv = build1 (AMBIG_CONV, totype, expr);
+ ICS_USER_FLAG (cand->second_conv) = 1;
+ ICS_BAD_FLAG (cand->second_conv) = 1;
+
+ return cand;
}
- else if (instance)
+
+ for (p = &(cand->second_conv); TREE_CODE (*p) != IDENTITY_CONV; )
+ p = &(TREE_OPERAND (*p, 0));
+
+ /* Pedantically, normal function declarations are never considered
+ to refer to template instantiations, so we only do this with
+ -fguiding-decls. */
+ if (flag_guiding_decls && templates && ! cand->template
+ && !DECL_INITIAL (cand->fn)
+ && TREE_CODE (TREE_TYPE (cand->fn)) != METHOD_TYPE)
+ add_maybe_template (cand->fn, templates);
+
+ *p = build
+ (USER_CONV,
+ (DECL_CONSTRUCTOR_P (cand->fn)
+ ? totype : non_reference (TREE_TYPE (TREE_TYPE (cand->fn)))),
+ expr, build_expr_ptr_wrapper (cand));
+ ICS_USER_FLAG (cand->second_conv) = 1;
+ if (cand->viable == -1)
+ ICS_BAD_FLAG (cand->second_conv) = 1;
+
+ return cand;
+}
+
+tree
+build_user_type_conversion (totype, expr, flags)
+ tree totype, expr;
+ int flags;
+{
+ struct z_candidate *cand
+ = build_user_type_conversion_1 (totype, expr, flags);
+
+ if (cand)
{
- /* TREE_READONLY (instance) fails for references. */
- constp = TYPE_READONLY (TREE_TYPE (TREE_TYPE (instance_ptr)));
- volatilep = TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (instance_ptr)));
- parms = tree_cons (NULL_TREE, instance_ptr, parms);
+ if (TREE_CODE (cand->second_conv) == AMBIG_CONV)
+ return error_mark_node;
+ return convert_from_reference (convert_like (cand->second_conv, expr));
}
- else
+ return NULL_TREE;
+}
+
+/* Do any initial processing on the arguments to a function call. */
+
+static tree
+resolve_args (args)
+ tree args;
+{
+ tree t;
+ for (t = args; t; t = TREE_CHAIN (t))
{
- /* Raw constructors are always in charge. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
- && ! (flags & LOOKUP_HAS_IN_CHARGE))
+ if (TREE_VALUE (t) == error_mark_node)
+ return error_mark_node;
+ else if (TREE_CODE (TREE_TYPE (TREE_VALUE (t))) == VOID_TYPE)
{
- flags |= LOOKUP_HAS_IN_CHARGE;
- parms = tree_cons (NULL_TREE, integer_one_node, parms);
- parmtypes = tree_cons (NULL_TREE, integer_type_node, parmtypes);
+ error ("invalid use of void expression");
+ return error_mark_node;
}
+ else if (TREE_CODE (TREE_VALUE (t)) == OFFSET_REF)
+ TREE_VALUE (t) = resolve_offset_ref (TREE_VALUE (t));
+ }
+ return args;
+}
+
+tree
+build_new_function_call (fn, args)
+ tree fn, args;
+{
+ struct z_candidate *candidates = 0, *cand;
+ tree explicit_targs = NULL_TREE;
+ int template_only = 0;
- constp = 0;
- volatilep = 0;
- instance_ptr = build_int_2 (0, 0);
- TREE_TYPE (instance_ptr) = build_pointer_type (basetype);
- parms = tree_cons (NULL_TREE, instance_ptr, parms);
+ if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
+ {
+ explicit_targs = TREE_OPERAND (fn, 1);
+ fn = TREE_OPERAND (fn, 0);
+ template_only = 1;
}
- parmtypes = tree_cons (NULL_TREE, TREE_TYPE (instance_ptr), parmtypes);
+ if (really_overloaded_fn (fn))
+ {
+ tree t1;
+ tree templates = NULL_TREE;
- if (last == NULL_TREE)
- last = parmtypes;
+ args = resolve_args (args);
- /* Look up function name in the structure type definition. */
+ if (args == error_mark_node)
+ return error_mark_node;
- if ((IDENTIFIER_HAS_TYPE_VALUE (name)
- && ! IDENTIFIER_OPNAME_P (name)
- && IS_AGGR_TYPE (IDENTIFIER_TYPE_VALUE (name))
- && TREE_CODE (IDENTIFIER_TYPE_VALUE (name)) != UNINSTANTIATED_P_TYPE)
- || name == constructor_name (basetype))
- {
- tree tmp = NULL_TREE;
- if (IDENTIFIER_TYPE_VALUE (name) == basetype
- || name == constructor_name (basetype))
- tmp = TYPE_BINFO (basetype);
- else
- tmp = get_binfo (IDENTIFIER_TYPE_VALUE (name), basetype, 0);
-
- if (tmp != NULL_TREE)
+ for (t1 = fn; t1; t1 = OVL_CHAIN (t1))
{
- name_kind = "constructor";
-
- if (TYPE_USES_VIRTUAL_BASECLASSES (basetype)
- && ! (flags & LOOKUP_HAS_IN_CHARGE))
+ tree t = OVL_FUNCTION (t1);
+ if (TREE_CODE (t) == TEMPLATE_DECL)
{
- /* Constructors called for initialization
- only are never in charge. */
- tree tmplist;
-
- flags |= LOOKUP_HAS_IN_CHARGE;
- tmplist = tree_cons (NULL_TREE, integer_zero_node,
- TREE_CHAIN (parms));
- TREE_CHAIN (parms) = tmplist;
- tmplist = tree_cons (NULL_TREE, integer_type_node, TREE_CHAIN (parmtypes));
- TREE_CHAIN (parmtypes) = tmplist;
+ templates = scratch_tree_cons (NULL_TREE, t, templates);
+ candidates = add_template_candidate
+ (candidates, t, explicit_targs, args, NULL_TREE,
+ LOOKUP_NORMAL, DEDUCE_CALL);
}
- basetype = BINFO_TYPE (tmp);
+ else if (! template_only)
+ candidates = add_function_candidate
+ (candidates, t, args, LOOKUP_NORMAL);
}
- else
- name_kind = "method";
+
+ if (! any_viable (candidates))
+ {
+ if (candidates && ! candidates->next)
+ return build_function_call (candidates->fn, args);
+ cp_error ("no matching function for call to `%D (%A)'",
+ DECL_NAME (OVL_FUNCTION (fn)), args);
+ if (candidates)
+ print_z_candidates (candidates);
+ return error_mark_node;
+ }
+ candidates = splice_viable (candidates);
+ cand = tourney (candidates);
+
+ if (cand == 0)
+ {
+ cp_error ("call of overloaded `%D (%A)' is ambiguous",
+ DECL_NAME (OVL_FUNCTION (fn)), args);
+ print_z_candidates (candidates);
+ return error_mark_node;
+ }
+
+ /* Pedantically, normal function declarations are never considered
+ to refer to template instantiations, so we only do this with
+ -fguiding-decls. */
+ if (flag_guiding_decls && templates && ! cand->template
+ && ! DECL_INITIAL (cand->fn))
+ add_maybe_template (cand->fn, templates);
+
+ return build_over_call (cand, args, LOOKUP_NORMAL);
}
- else
- name_kind = "method";
-
- if (basetype_path == NULL_TREE
- || BINFO_TYPE (basetype_path) != TYPE_MAIN_VARIANT (basetype))
- basetype_path = TYPE_BINFO (basetype);
- result = lookup_fnfields (basetype_path, name,
- (flags & LOOKUP_COMPLAIN));
- if (result == error_mark_node)
- return error_mark_node;
+ /* This is not really overloaded. */
+ fn = OVL_CURRENT (fn);
-#if 0
- /* Now, go look for this method name. We do not find destructors here.
-
- Putting `void_list_node' on the end of the parmtypes
- fakes out `build_decl_overload' into doing the right thing. */
- TREE_CHAIN (last) = void_list_node;
- method_name = build_decl_overload (name, parmtypes,
- 1 + (name == constructor_name (save_basetype)
- || name == constructor_name_full (save_basetype)));
- TREE_CHAIN (last) = NULL_TREE;
-#endif
+ return build_function_call (fn, args);
+}
- for (pass = 0; pass < 2; pass++)
+static tree
+build_object_call (obj, args)
+ tree obj, args;
+{
+ struct z_candidate *candidates = 0, *cand;
+ tree fns, convs, mem_args = NULL_TREE;
+ tree type = TREE_TYPE (obj);
+ tree templates = NULL_TREE;
+
+ if (TYPE_PTRMEMFUNC_P (type))
{
- struct candidate *candidates;
- struct candidate *cp;
- int len;
- unsigned best = 1;
+ /* It's no good looking for an overloaded operator() on a
+ pointer-to-member-function. */
+ cp_error ("pointer-to-member function %E cannot be called", obj);
+ cp_error ("without an object; consider using .* or ->*");
+ return error_mark_node;
+ }
- /* This increments every time we go up the type hierarchy.
- The idea is to prefer a function of the derived class if possible. */
- int b_or_d = 0;
+ fns = lookup_fnfields (TYPE_BINFO (type), ansi_opname [CALL_EXPR], 1);
+ if (fns == error_mark_node)
+ return error_mark_node;
- baselink = result;
+ args = resolve_args (args);
- if (pass > 0)
- {
- candidates
- = (struct candidate *) alloca ((ever_seen+1)
- * sizeof (struct candidate));
- bzero ((char *) candidates, (ever_seen + 1) * sizeof (struct candidate));
- cp = candidates;
- len = list_length (parms);
- ever_seen = 0;
+ if (args == error_mark_node)
+ return error_mark_node;
- /* First see if a global function has a shot at it. */
- if (flags & LOOKUP_GLOBAL)
+ if (fns)
+ {
+ tree base = TREE_PURPOSE (fns);
+ mem_args = scratch_tree_cons (NULL_TREE, build_this (obj), args);
+
+ for (fns = TREE_VALUE (fns); fns; fns = OVL_NEXT (fns))
+ {
+ tree fn = OVL_CURRENT (fns);
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
{
- tree friend_parms;
- tree parm = instance_ptr;
+ templates = scratch_tree_cons (NULL_TREE, fn, templates);
+ candidates
+ = add_template_candidate (candidates, fn, NULL_TREE,
+ mem_args, NULL_TREE,
+ LOOKUP_NORMAL, DEDUCE_CALL);
+ }
+ else
+ candidates = add_function_candidate
+ (candidates, fn, mem_args, LOOKUP_NORMAL);
- if (TREE_CODE (TREE_TYPE (parm)) == REFERENCE_TYPE)
- parm = convert_from_reference (parm);
- else if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)
- parm = build_indirect_ref (parm, "friendifying parms (compiler error)");
- else
- my_friendly_abort (167);
+ if (candidates)
+ candidates->basetype_path = base;
+ }
+ }
- friend_parms = tree_cons (NULL_TREE, parm, TREE_CHAIN (parms));
+ convs = lookup_conversions (type);
- cp->h_len = len;
- cp->harshness = (struct harshness_code *)
- alloca ((len + 1) * sizeof (struct harshness_code));
+ for (; convs; convs = TREE_CHAIN (convs))
+ {
+ tree fns = TREE_VALUE (convs);
+ tree totype = TREE_TYPE (TREE_TYPE (OVL_CURRENT (fns)));
+ tree fn;
+
+ if (TREE_CODE (totype) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
+ for (; fns; fns = OVL_NEXT (fn))
+ {
+ fn = OVL_CURRENT (fn);
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
+ {
+ templates = scratch_tree_cons (NULL_TREE, fn, templates);
+ candidates = add_template_conv_candidate (candidates,
+ fn,
+ obj,
+ args,
+ totype);
+ }
+ else
+ candidates = add_conv_candidate (candidates, fn, obj, args);
- result = build_overload_call (name, friend_parms, 0, cp);
- /* If it turns out to be the one we were actually looking for
- (it was probably a friend function), the return the
- good result. */
- if (TREE_CODE (result) == CALL_EXPR)
- return result;
+ if (candidates)
+ candidates->basetype_path = TREE_PURPOSE (convs);
+ }
+ }
- while ((cp->h.code & EVIL_CODE) == 0)
- {
- /* non-standard uses: set the field to 0 to indicate
- we are using a non-member function. */
- cp->u.field = 0;
- if (cp->harshness[len].distance == 0
- && cp->h.code < best)
- best = cp->h.code;
- cp += 1;
- }
- }
- }
+ if (! any_viable (candidates))
+ {
+ cp_error ("no match for call to `(%T) (%A)'", TREE_TYPE (obj), args);
+ print_z_candidates (candidates);
+ return error_mark_node;
+ }
- while (baselink)
- {
- /* We have a hit (of sorts). If the parameter list is
- "error_mark_node", or some variant thereof, it won't
- match any methods. Since we have verified that the is
- some method vaguely matching this one (in name at least),
- silently return.
-
- Don't stop for friends, however. */
- basetype_path = TREE_PURPOSE (baselink);
+ candidates = splice_viable (candidates);
+ cand = tourney (candidates);
- function = TREE_VALUE (baselink);
- if (TREE_CODE (basetype_path) == TREE_LIST)
- basetype_path = TREE_VALUE (basetype_path);
- basetype = BINFO_TYPE (basetype_path);
+ if (cand == 0)
+ {
+ cp_error ("call of `(%T) (%A)' is ambiguous", TREE_TYPE (obj), args);
+ print_z_candidates (candidates);
+ return error_mark_node;
+ }
-#if 0
- /* Cast the instance variable if necessary. */
- if (basetype != TYPE_MAIN_VARIANT
- (TREE_TYPE (TREE_TYPE (TREE_VALUE (parms)))))
- {
- if (basetype == save_basetype)
- TREE_VALUE (parms) = instance_ptr;
- else
- {
- tree type = build_pointer_type
- (build_type_variant (basetype, constp, volatilep));
- TREE_VALUE (parms) = convert_force (type, instance_ptr, 0);
- }
- }
+ if (DECL_NAME (cand->fn) == ansi_opname [CALL_EXPR])
+ return build_over_call (cand, mem_args, LOOKUP_NORMAL);
- /* FIXME: this is the wrong place to get an error. Hopefully
- the access-control rewrite will make this change more cleanly. */
- if (TREE_VALUE (parms) == error_mark_node)
- return error_mark_node;
-#endif
+ obj = convert_like (TREE_VEC_ELT (cand->convs, 0), obj);
- if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function)))
- function = DECL_CHAIN (function);
+ /* FIXME */
+ return build_function_call (obj, args);
+}
- for (; function; function = DECL_CHAIN (function))
- {
-#ifdef GATHER_STATISTICS
- n_inner_fields_searched++;
-#endif
- ever_seen++;
- if (pass > 0)
- found_fns = tree_cons (NULL_TREE, function, found_fns);
+static void
+op_error (code, code2, arg1, arg2, arg3, problem)
+ enum tree_code code, code2;
+ tree arg1, arg2, arg3;
+ char *problem;
+{
+ char * opname
+ = (code == MODIFY_EXPR ? assignop_tab [code2] : opname_tab [code]);
- /* Not looking for friends here. */
- if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE
- && ! DECL_STATIC_FUNCTION_P (function))
- continue;
+ switch (code)
+ {
+ case COND_EXPR:
+ cp_error ("%s for `%T ? %T : %T'", problem,
+ error_type (arg1), error_type (arg2), error_type (arg3));
+ break;
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ cp_error ("%s for `%T%s'", problem, error_type (arg1), opname);
+ break;
+ case ARRAY_REF:
+ cp_error ("%s for `%T[%T]'", problem,
+ error_type (arg1), error_type (arg2));
+ break;
+ default:
+ if (arg2)
+ cp_error ("%s for `%T %s %T'", problem,
+ error_type (arg1), opname, error_type (arg2));
+ else
+ cp_error ("%s for `%s%T'", problem, opname, error_type (arg1));
+ }
+}
+
+tree
+build_new_op (code, flags, arg1, arg2, arg3)
+ enum tree_code code;
+ int flags;
+ tree arg1, arg2, arg3;
+{
+ struct z_candidate *candidates = 0, *cand;
+ tree fns, mem_arglist = NULL_TREE, arglist, fnname;
+ enum tree_code code2 = NOP_EXPR;
+ tree templates = NULL_TREE;
+ tree conv;
+
+ if (arg1 == error_mark_node
+ || arg2 == error_mark_node
+ || arg3 == error_mark_node)
+ return error_mark_node;
+
+ /* This can happen if a template takes all non-type parameters, e.g.
+ undeclared_template<1, 5, 72>a; */
+ if (code == LT_EXPR && TREE_CODE (arg1) == TEMPLATE_DECL)
+ {
+ cp_error ("`%D' must be declared before use", arg1);
+ return error_mark_node;
+ }
+
+ if (code == MODIFY_EXPR)
+ {
+ code2 = TREE_CODE (arg3);
+ arg3 = NULL_TREE;
+ fnname = ansi_assopname[code2];
+ }
+ else
+ fnname = ansi_opname[code];
+
+ switch (code)
+ {
+ case NEW_EXPR:
+ case VEC_NEW_EXPR:
+ {
+ tree rval;
+
+ arglist = scratch_tree_cons (NULL_TREE, arg2, arg3);
+ if (flags & LOOKUP_GLOBAL)
+ return build_new_function_call
+ (lookup_function_nonclass (fnname, arglist), arglist);
+
+ /* FIXME */
+ rval = build_method_call
+ (build_indirect_ref (build1 (NOP_EXPR, arg1, error_mark_node),
+ "new"),
+ fnname, arglist, NULL_TREE, flags);
+ if (rval == error_mark_node)
+ /* User might declare fancy operator new, but invoke it
+ like standard one. */
+ return rval;
+
+ TREE_TYPE (rval) = arg1;
+ return rval;
+ }
+ case VEC_DELETE_EXPR:
+ case DELETE_EXPR:
+ {
+ tree rval;
+
+ if (flags & LOOKUP_GLOBAL)
+ {
+ arglist = build_scratch_list (NULL_TREE, arg1);
+ return build_new_function_call
+ (lookup_function_nonclass (fnname, arglist), arglist);
+ }
+
+ arglist = scratch_tree_cons (NULL_TREE, arg1, build_scratch_list (NULL_TREE, arg2));
+
+ arg1 = TREE_TYPE (arg1);
+
+ /* This handles the case where we're trying to delete
+ X (*a)[10];
+ a=new X[5][10];
+ delete[] a; */
+
+ if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE)
+ {
+ /* Strip off the pointer and the array. */
+ arg1 = TREE_TYPE (TREE_TYPE (arg1));
+
+ while (TREE_CODE (arg1) == ARRAY_TYPE)
+ arg1 = (TREE_TYPE (arg1));
+
+ arg1 = build_pointer_type (arg1);
+ }
+
+ /* FIXME */
+ rval = build_method_call
+ (build_indirect_ref (build1 (NOP_EXPR, arg1,
+ error_mark_node),
+ NULL_PTR),
+ fnname, arglist, NULL_TREE, flags);
#if 0
- if (pass == 0
- && DECL_ASSEMBLER_NAME (function) == method_name)
- goto found;
+ /* This can happen when operator delete is protected. */
+ my_friendly_assert (rval != error_mark_node, 250);
+ TREE_TYPE (rval) = void_type_node;
#endif
+ return rval;
+ }
- if (pass > 0)
- {
- tree these_parms = parms;
+ case CALL_EXPR:
+ return build_object_call (arg1, arg2);
-#ifdef GATHER_STATISTICS
- n_inner_fields_searched++;
-#endif
- cp->h_len = len;
- cp->harshness = (struct harshness_code *)
- alloca ((len + 1) * sizeof (struct harshness_code));
-
- if (DECL_STATIC_FUNCTION_P (function))
- these_parms = TREE_CHAIN (these_parms);
- compute_conversion_costs (function, these_parms, cp, len);
-
- if ((cp->h.code & EVIL_CODE) == 0)
- {
- cp->u.field = function;
- cp->function = function;
- cp->basetypes = basetype_path;
-
- /* Don't allow non-converting constructors to convert. */
- if (flags & LOOKUP_ONLYCONVERTING
- && DECL_LANG_SPECIFIC (function)
- && DECL_NONCONVERTING_P (function))
- continue;
-
- /* No "two-level" conversions. */
- if (flags & LOOKUP_NO_CONVERSION
- && (cp->h.code & USER_CODE))
- continue;
-
- cp++;
- }
- }
- }
- /* Now we have run through one link's member functions.
- arrange to head-insert this link's links. */
- baselink = next_baselink (baselink);
- b_or_d += 1;
- /* Don't grab functions from base classes. lookup_fnfield will
- do the work to get us down into the right place. */
- baselink = NULL_TREE;
- }
- if (pass == 0)
- {
- tree igv = lookup_name_nonclass (name);
+ default:
+ break;
+ }
- /* No exact match could be found. Now try to find match
- using default conversions. */
- if ((flags & LOOKUP_GLOBAL) && igv)
- {
- if (TREE_CODE (igv) == FUNCTION_DECL)
- ever_seen += 1;
- else if (TREE_CODE (igv) == TREE_LIST)
- ever_seen += count_functions (igv);
- }
+ /* The comma operator can have void args. */
+ if (TREE_CODE (arg1) == OFFSET_REF)
+ arg1 = resolve_offset_ref (arg1);
+ if (arg2 && TREE_CODE (arg2) == OFFSET_REF)
+ arg2 = resolve_offset_ref (arg2);
+ if (arg3 && TREE_CODE (arg3) == OFFSET_REF)
+ arg3 = resolve_offset_ref (arg3);
- if (ever_seen == 0)
- {
- if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
- == LOOKUP_SPECULATIVELY)
- return NULL_TREE;
-
- TREE_CHAIN (last) = void_list_node;
- if (flags & LOOKUP_GLOBAL)
- cp_error ("no global or member function `%D(%A)' defined",
- name, parmtypes);
- else
- cp_error ("no member function `%T::%D(%A)' defined",
- save_basetype, name, TREE_CHAIN (parmtypes));
- return error_mark_node;
- }
- continue;
+ if (code == COND_EXPR)
+ {
+ if (arg2 == NULL_TREE
+ || TREE_CODE (TREE_TYPE (arg2)) == VOID_TYPE
+ || TREE_CODE (TREE_TYPE (arg3)) == VOID_TYPE
+ || (! IS_OVERLOAD_TYPE (TREE_TYPE (arg2))
+ && ! IS_OVERLOAD_TYPE (TREE_TYPE (arg3))))
+ goto builtin;
+ }
+ else if (! IS_OVERLOAD_TYPE (TREE_TYPE (arg1))
+ && (! arg2 || ! IS_OVERLOAD_TYPE (TREE_TYPE (arg2))))
+ goto builtin;
+
+ if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
+ arg2 = integer_zero_node;
+
+ if (arg2 && arg3)
+ arglist = scratch_tree_cons (NULL_TREE, arg1, scratch_tree_cons
+ (NULL_TREE, arg2, build_scratch_list (NULL_TREE, arg3)));
+ else if (arg2)
+ arglist = scratch_tree_cons (NULL_TREE, arg1, build_scratch_list (NULL_TREE, arg2));
+ else
+ arglist = build_scratch_list (NULL_TREE, arg1);
+
+ fns = lookup_function_nonclass (fnname, arglist);
+
+ if (fns && TREE_CODE (fns) == TREE_LIST)
+ fns = TREE_VALUE (fns);
+ for (; fns; fns = OVL_NEXT (fns))
+ {
+ tree fn = OVL_CURRENT (fns);
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
+ {
+ templates = scratch_tree_cons (NULL_TREE, fn, templates);
+ candidates
+ = add_template_candidate (candidates, fn, NULL_TREE,
+ arglist, TREE_TYPE (fnname),
+ flags, DEDUCE_CALL);
}
+ else
+ candidates = add_function_candidate (candidates, fn, arglist, flags);
+ }
+
+ if (IS_AGGR_TYPE (TREE_TYPE (arg1)))
+ {
+ fns = lookup_fnfields (TYPE_BINFO (TREE_TYPE (arg1)), fnname, 1);
+ if (fns == error_mark_node)
+ return fns;
+ }
+ else
+ fns = NULL_TREE;
- if (cp - candidates != 0)
+ if (fns)
+ {
+ tree basetype = TREE_PURPOSE (fns);
+ mem_arglist = scratch_tree_cons (NULL_TREE, build_this (arg1), TREE_CHAIN (arglist));
+ for (fns = TREE_VALUE (fns); fns; fns = OVL_NEXT (fns))
{
- /* Rank from worst to best. Then cp will point to best one.
- Private fields have their bits flipped. For unsigned
- numbers, this should make them look very large.
- If the best alternate has a (signed) negative value,
- then all we ever saw were private members. */
- if (cp - candidates > 1)
- {
- int n_candidates = cp - candidates;
- extern int warn_synth;
- TREE_VALUE (parms) = instance_ptr;
- cp = ideal_candidate (save_basetype, candidates,
- n_candidates, parms, len);
- if (cp == (struct candidate *)0)
- {
- if (flags & LOOKUP_COMPLAIN)
- {
- TREE_CHAIN (last) = void_list_node;
- cp_error ("call of overloaded %s `%D(%A)' is ambiguous",
- name_kind, name, TREE_CHAIN (parmtypes));
- print_n_candidates (candidates, n_candidates);
- }
- return error_mark_node;
- }
- if (cp->h.code & EVIL_CODE)
- return error_mark_node;
- if (warn_synth
- && DECL_NAME (cp->function) == ansi_opname[MODIFY_EXPR]
- && DECL_ARTIFICIAL (cp->function)
- && n_candidates == 2)
- {
- cp_warning ("using synthesized `%#D' for copy assignment",
- cp->function);
- cp_warning_at (" where cfront would use `%#D'",
- candidates->function);
- }
- }
- else if (cp[-1].h.code & EVIL_CODE)
- {
- if (flags & LOOKUP_COMPLAIN)
- cp_error ("ambiguous type conversion requested for %s `%D'",
- name_kind, name);
- return error_mark_node;
- }
+ tree fn = OVL_CURRENT (fns);
+ tree this_arglist;
+
+ if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+ this_arglist = mem_arglist;
else
- cp--;
+ this_arglist = arglist;
- /* The global function was the best, so use it. */
- if (cp->u.field == 0)
+ if (TREE_CODE (fn) == TEMPLATE_DECL)
{
- /* We must convert the instance pointer into a reference type.
- Global overloaded functions can only either take
- aggregate objects (which come for free from references)
- or reference data types anyway. */
- TREE_VALUE (parms) = copy_node (instance_ptr);
- TREE_TYPE (TREE_VALUE (parms)) = build_reference_type (TREE_TYPE (TREE_TYPE (instance_ptr)));
- return build_function_call (cp->function, parms);
+ /* A member template. */
+ templates = scratch_tree_cons (NULL_TREE, fn, templates);
+ candidates
+ = add_template_candidate (candidates, fn, NULL_TREE,
+ this_arglist, TREE_TYPE (fnname),
+ flags, DEDUCE_CALL);
}
+ else
+ candidates = add_function_candidate
+ (candidates, fn, this_arglist, flags);
- function = cp->function;
- basetype_path = cp->basetypes;
- if (! DECL_STATIC_FUNCTION_P (function))
- TREE_VALUE (parms) = cp->arg;
- goto found_and_maybe_warn;
+ if (candidates)
+ candidates->basetype_path = basetype;
}
+ }
- if (flags & (LOOKUP_COMPLAIN|LOOKUP_SPECULATIVELY))
- {
- if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
- == LOOKUP_SPECULATIVELY)
- return NULL_TREE;
+ {
+ tree args[3];
- if (DECL_STATIC_FUNCTION_P (cp->function))
- parms = TREE_CHAIN (parms);
- if (ever_seen)
- {
- if (flags & LOOKUP_SPECULATIVELY)
- return NULL_TREE;
- if (static_call_context
- && TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)
- cp_error ("object missing in call to `%D'", cp->function);
- else if (ever_seen > 1)
- {
- TREE_CHAIN (last) = void_list_node;
- cp_error ("no matching function for call to `%T::%D (%A)%V'",
- TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (instance_ptr))),
- name, TREE_CHAIN (parmtypes),
- TREE_TYPE (TREE_TYPE (instance_ptr)));
- TREE_CHAIN (last) = NULL_TREE;
- print_candidates (found_fns);
- }
- else
- report_type_mismatch (cp, parms, name_kind);
- return error_mark_node;
- }
+ /* Rearrange the arguments for ?: so that add_builtin_candidate only has
+ to know about two args; a builtin candidate will always have a first
+ parameter of type bool. We'll handle that in
+ build_builtin_candidate. */
+ if (code == COND_EXPR)
+ {
+ args[0] = arg2;
+ args[1] = arg3;
+ args[2] = arg1;
+ }
+ else
+ {
+ args[0] = arg1;
+ args[1] = arg2;
+ args[2] = NULL_TREE;
+ }
- if ((flags & (LOOKUP_SPECULATIVELY|LOOKUP_COMPLAIN))
- == LOOKUP_COMPLAIN)
- {
- cp_error ("%T has no method named %D", save_basetype, name);
- return error_mark_node;
- }
- return NULL_TREE;
- }
- continue;
+ candidates = add_builtin_candidates
+ (candidates, code, code2, fnname, args, flags);
+ }
- found_and_maybe_warn:
- if ((cp->harshness[0].code & CONST_CODE)
- /* 12.1p2: Constructors can be called for const objects. */
- && ! DECL_CONSTRUCTOR_P (cp->function))
+ if (! any_viable (candidates))
+ {
+ switch (code)
{
+ case POSTINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ /* Look for an `operator++ (int)'. If they didn't have
+ one, then we fall back to the old way of doing things. */
if (flags & LOOKUP_COMPLAIN)
- {
- cp_error_at ("non-const member function `%D'", cp->function);
- error ("called for const object at this point in file");
- }
- /* Not good enough for a match. */
+ cp_pedwarn ("no `%D (int)' declared for postfix `%s', trying prefix operator instead",
+ fnname, opname_tab [code]);
+ if (code == POSTINCREMENT_EXPR)
+ code = PREINCREMENT_EXPR;
else
- return error_mark_node;
- }
- goto found;
- }
- /* Silently return error_mark_node. */
- return error_mark_node;
-
- found:
- if (flags & LOOKUP_PROTECT)
- access = compute_access (basetype_path, function);
+ code = PREDECREMENT_EXPR;
+ return build_new_op (code, flags, arg1, NULL_TREE, NULL_TREE);
+
+ /* The caller will deal with these. */
+ case ADDR_EXPR:
+ case COMPOUND_EXPR:
+ case COMPONENT_REF:
+ return NULL_TREE;
- if (access == access_private)
- {
+ default:
+ break;
+ }
if (flags & LOOKUP_COMPLAIN)
{
- cp_error_at ("%s `%+#D' is %s", name_kind, function,
- TREE_PRIVATE (function) ? "private"
- : "from private base class");
- error ("within this context");
+ op_error (code, code2, arg1, arg2, arg3, "no match");
+ print_z_candidates (candidates);
}
return error_mark_node;
}
- else if (access == access_protected)
+ candidates = splice_viable (candidates);
+ cand = tourney (candidates);
+
+ if (cand == 0)
{
if (flags & LOOKUP_COMPLAIN)
{
- cp_error_at ("%s `%+#D' %s", name_kind, function,
- TREE_PROTECTED (function) ? "is protected"
- : "has protected accessibility");
- error ("within this context");
+ op_error (code, code2, arg1, arg2, arg3, "ambiguous overload");
+ print_z_candidates (candidates);
}
return error_mark_node;
}
- /* From here on down, BASETYPE is the type that INSTANCE_PTR's
- type (if it exists) is a pointer to. */
+ if (TREE_CODE (cand->fn) == FUNCTION_DECL)
+ {
+ extern int warn_synth;
+ if (warn_synth
+ && fnname == ansi_opname[MODIFY_EXPR]
+ && DECL_ARTIFICIAL (cand->fn)
+ && candidates->next
+ && ! candidates->next->next)
+ {
+ cp_warning ("using synthesized `%#D' for copy assignment",
+ cand->fn);
+ cp_warning_at (" where cfront would use `%#D'",
+ cand == candidates
+ ? candidates->next->fn
+ : candidates->fn);
+ }
- if (DECL_ABSTRACT_VIRTUAL_P (function)
- && instance == C_C_D
- && DECL_CONSTRUCTOR_P (current_function_decl)
- && ! (flags & LOOKUP_NONVIRTUAL)
- && value_member (function, get_abstract_virtuals (basetype)))
- cp_error ("abstract virtual `%#D' called from constructor", function);
+ /* Pedantically, normal function declarations are never considered
+ to refer to template instantiations, so we only do this with
+ -fguiding-decls. */
+ if (flag_guiding_decls && templates && ! cand->template
+ && ! DECL_INITIAL (cand->fn)
+ && TREE_CODE (TREE_TYPE (cand->fn)) != METHOD_TYPE)
+ add_maybe_template (cand->fn, templates);
+
+ return build_over_call
+ (cand,
+ TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
+ ? mem_arglist : arglist,
+ LOOKUP_NORMAL);
+ }
- if (IS_SIGNATURE (basetype) && static_call_context)
+ /* Check for comparison of different enum types. */
+ switch (code)
{
- cp_error ("cannot call signature member function `%T::%D' without signature pointer/reference",
- basetype, name);
- return error_mark_node;
+ case GT_EXPR:
+ case LT_EXPR:
+ case GE_EXPR:
+ case LE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ if (flag_int_enum_equivalence == 0
+ && TREE_CODE (TREE_TYPE (arg1)) == ENUMERAL_TYPE
+ && TREE_CODE (TREE_TYPE (arg2)) == ENUMERAL_TYPE
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (arg1))
+ != TYPE_MAIN_VARIANT (TREE_TYPE (arg2))))
+ {
+ cp_warning ("comparison between `%#T' and `%#T'",
+ TREE_TYPE (arg1), TREE_TYPE (arg2));
}
- else if (IS_SIGNATURE (basetype))
- return build_signature_method_call (basetype, instance, function, parms);
+ break;
+ default:
+ break;
+ }
- function = DECL_MAIN_VARIANT (function);
- /* Declare external function if necessary. */
- assemble_external (function);
+ /* We need to strip any leading REF_BIND so that bitfields don't cause
+ errors. This should not remove any important conversions, because
+ builtins don't apply to class objects directly. */
+ conv = TREE_VEC_ELT (cand->convs, 0);
+ if (TREE_CODE (conv) == REF_BIND)
+ conv = TREE_OPERAND (conv, 0);
+ arg1 = convert_like (conv, arg1);
+ if (arg2)
+ arg2 = convert_like (TREE_VEC_ELT (cand->convs, 1), arg2);
+ if (arg3)
+ arg3 = convert_like (TREE_VEC_ELT (cand->convs, 2), arg3);
+
+builtin:
+ switch (code)
+ {
+ case MODIFY_EXPR:
+ return build_modify_expr (arg1, code2, arg2);
+
+ case INDIRECT_REF:
+ return build_indirect_ref (arg1, "unary *");
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case GT_EXPR:
+ case LT_EXPR:
+ case GE_EXPR:
+ case LE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case MAX_EXPR:
+ case MIN_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case TRUNC_MOD_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ return build_binary_op_nodefault (code, arg1, arg2, code);
+
+ case CONVERT_EXPR:
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ case TRUTH_NOT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ return build_unary_op (code, arg1, candidates != 0);
+
+ case ARRAY_REF:
+ return build_array_ref (arg1, arg2);
+
+ case COND_EXPR:
+ return build_conditional_expr (arg1, arg2, arg3);
+
+ case MEMBER_REF:
+ return build_m_component_ref
+ (build_indirect_ref (arg1, NULL_PTR), arg2);
+
+ /* The caller will deal with these. */
+ case ADDR_EXPR:
+ case COMPONENT_REF:
+ case COMPOUND_EXPR:
+ return NULL_TREE;
-#if 1
- /* Is it a synthesized method that needs to be synthesized? */
- if (DECL_ARTIFICIAL (function) && ! flag_no_inline
- && ! DECL_INITIAL (function)
- /* Kludge: don't synthesize for default args. */
- && current_function_decl)
- synthesize_method (function);
-#endif
+ default:
+ my_friendly_abort (367);
+ return NULL_TREE;
+ }
+}
- if (pedantic && DECL_THIS_INLINE (function) && ! DECL_ARTIFICIAL (function)
- && ! DECL_INITIAL (function) && ! DECL_PENDING_INLINE_INFO (function))
- cp_warning ("inline function `%#D' called before definition", function);
+/* Build up a call to operator new. This has to be handled differently
+ from other operators in the way lookup is handled; first members are
+ considered, then globals. CODE is either NEW_EXPR or VEC_NEW_EXPR.
+ TYPE is the type to be created. ARGS are any new-placement args.
+ FLAGS are the usual overloading flags. */
- fntype = TREE_TYPE (function);
- if (TREE_CODE (fntype) == POINTER_TYPE)
- fntype = TREE_TYPE (fntype);
- basetype = DECL_CLASS_CONTEXT (function);
+tree
+build_op_new_call (code, type, args, flags)
+ enum tree_code code;
+ tree type, args;
+ int flags;
+{
+ tree fnname = ansi_opname[code];
- /* If we are referencing a virtual function from an object
- of effectively static type, then there is no need
- to go through the virtual function table. */
- if (need_vtbl == maybe_needed)
+ if (IS_AGGR_TYPE (type) && ! (flags & LOOKUP_GLOBAL)
+ && (TYPE_GETS_NEW (type) & (1 << (code == VEC_NEW_EXPR))))
{
- int fixed_type = resolves_to_fixed_type_p (instance, 0);
+ tree dummy = build1 (NOP_EXPR, build_pointer_type (type),
+ error_mark_node);
+ dummy = build_indirect_ref (dummy, "new");
+ return build_method_call (dummy, fnname, args, NULL_TREE, flags);
+ }
+ else
+ return build_new_function_call
+ (lookup_function_nonclass (fnname, args), args);
+}
- if (all_virtual == 1
- && DECL_VINDEX (function)
- && may_be_remote (basetype))
- need_vtbl = needed;
- else if (DECL_VINDEX (function))
- need_vtbl = fixed_type ? unneeded : needed;
- else
- need_vtbl = not_needed;
+/* Build a call to operator delete. This has to be handled very specially,
+ because the restrictions on what signatures match are different from all
+ other call instances. For a normal delete, only a delete taking (void *)
+ or (void *, size_t) is accepted. For a placement delete, only an exact
+ match with the placement new is accepted.
+
+ CODE is either DELETE_EXPR or VEC_DELETE_EXPR.
+ ADDR is the pointer to be deleted. For placement delete, it is also
+ used to determine what the corresponding new looked like.
+ SIZE is the size of the memory block to be deleted.
+ FLAGS are the usual overloading flags.
+ PLACEMENT is the corresponding placement new call, or 0. */
+
+tree
+build_op_delete_call (code, addr, size, flags, placement)
+ enum tree_code code;
+ tree addr, size, placement;
+ int flags;
+{
+ tree fn, fns, fnname, fntype, argtypes, args, type;
+
+ if (addr == error_mark_node)
+ return error_mark_node;
+
+ type = TREE_TYPE (TREE_TYPE (addr));
+ fnname = ansi_opname[code];
+
+ if (IS_AGGR_TYPE (type) && ! (flags & LOOKUP_GLOBAL))
+ /* In [class.free]
+
+ If the result of the lookup is ambiguous or inaccessible, or if
+ the lookup selects a placement deallocation function, the
+ program is ill-formed.
+
+ Therefore, we ask lookup_fnfields to complain ambout ambiguity. */
+ {
+ fns = lookup_fnfields (TYPE_BINFO (type), fnname, 1);
+ if (fns == error_mark_node)
+ return error_mark_node;
}
+ else
+ fns = NULL_TREE;
+
+ if (fns == NULL_TREE)
+ fns = lookup_name_nonclass (fnname);
+
+ if (placement)
+ {
+ /* placement is a CALL_EXPR around an ADDR_EXPR around a function. */
+
+ /* Extract the function. */
+ argtypes = TREE_OPERAND (TREE_OPERAND (placement, 0), 0);
+ /* Then the second parm type. */
+ argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (argtypes)));
- if (TREE_CODE (fntype) == METHOD_TYPE && static_call_context
- && !DECL_CONSTRUCTOR_P (function))
+ /* Also the second argument. */
+ args = TREE_CHAIN (TREE_OPERAND (placement, 1));
+ }
+ else
{
- /* Let's be nice to the user for now, and give reasonable
- default behavior. */
- instance_ptr = current_class_decl;
- if (instance_ptr)
+ /* First try it without the size argument. */
+ argtypes = void_list_node;
+ args = NULL_TREE;
+ }
+
+ argtypes = tree_cons (NULL_TREE, ptr_type_node, argtypes);
+ fntype = build_function_type (void_type_node, argtypes);
+
+ /* Strip const and volatile from addr. */
+ if (type != TYPE_MAIN_VARIANT (type))
+ addr = cp_convert (build_pointer_type (TYPE_MAIN_VARIANT (type)), addr);
+
+ /* instantiate_type will always return a plain function; pretend it's
+ overloaded. */
+ if (TREE_CODE (fns) == FUNCTION_DECL)
+ fns = scratch_ovl_cons (fns, NULL_TREE);
+
+ fn = instantiate_type (fntype, fns, 0);
+
+ if (fn != error_mark_node)
+ {
+ if (TREE_CODE (fns) == TREE_LIST)
+ /* Member functions. */
+ enforce_access (TREE_PURPOSE (fns), fn);
+ return build_function_call (fn, expr_tree_cons (NULL_TREE, addr, args));
+ }
+
+ /* If we are doing placement delete we do nothing if we don't find a
+ matching op delete. */
+ if (placement)
+ return NULL_TREE;
+
+ /* Normal delete; now try to find a match including the size argument. */
+ argtypes = tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE, sizetype, void_list_node));
+ fntype = build_function_type (void_type_node, argtypes);
+
+ fn = instantiate_type (fntype, fns, 0);
+
+ if (fn != error_mark_node)
+ {
+ if (TREE_CODE (fns) == TREE_LIST)
+ /* Member functions. */
+ enforce_access (TREE_PURPOSE (fns), fn);
+ return build_function_call
+ (fn, expr_tree_cons (NULL_TREE, addr,
+ build_expr_list (NULL_TREE, size)));
+ }
+
+ /* finish_function passes LOOKUP_SPECULATIVELY if we're in a
+ destructor, in which case the error should be deferred
+ until someone actually tries to delete one of these. */
+ if (flags & LOOKUP_SPECULATIVELY)
+ return NULL_TREE;
+
+ cp_error ("no suitable operator delete for `%T'", type);
+ return error_mark_node;
+}
+
+/* If the current scope isn't allowed to access DECL along
+ BASETYPE_PATH, give an error. */
+
+void
+enforce_access (basetype_path, decl)
+ tree basetype_path, decl;
+{
+ tree access = compute_access (basetype_path, decl);
+
+ if (access == access_private_node)
+ {
+ cp_error_at ("`%+#D' is %s", decl,
+ TREE_PRIVATE (decl) ? "private"
+ : "from private base class");
+ error ("within this context");
+ }
+ else if (access == access_protected_node)
+ {
+ cp_error_at ("`%+#D' %s", decl,
+ TREE_PROTECTED (decl) ? "is protected"
+ : "has protected accessibility");
+ error ("within this context");
+ }
+}
+
+/* Perform the conversions in CONVS on the expression EXPR. */
+
+static tree
+convert_like (convs, expr)
+ tree convs, expr;
+{
+ if (ICS_BAD_FLAG (convs)
+ && TREE_CODE (convs) != USER_CONV
+ && TREE_CODE (convs) != AMBIG_CONV)
+ {
+ tree t = convs;
+ for (; t; t = TREE_OPERAND (t, 0))
{
- if (basetype != current_class_type)
+ if (TREE_CODE (t) == USER_CONV)
{
- tree binfo = get_binfo (basetype, current_class_type, 1);
- if (binfo == NULL_TREE)
- {
- error_not_base_type (function, current_class_type);
- return error_mark_node;
- }
- else if (basetype == error_mark_node)
- return error_mark_node;
+ expr = convert_like (t, expr);
+ break;
}
+ else if (TREE_CODE (t) == AMBIG_CONV)
+ return convert_like (t, expr);
+ else if (TREE_CODE (t) == IDENTITY_CONV)
+ break;
}
- /* Only allow a static member function to call another static member
- function. */
- else if (DECL_LANG_SPECIFIC (function)
- && !DECL_STATIC_FUNCTION_P (function))
- {
- cp_error ("cannot call member function `%D' without object",
- function);
- return error_mark_node;
- }
+ return convert_for_initialization
+ (NULL_TREE, TREE_TYPE (convs), expr, LOOKUP_NORMAL,
+ "conversion", NULL_TREE, 0);
}
- value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
+ switch (TREE_CODE (convs))
+ {
+ case USER_CONV:
+ {
+ struct z_candidate *cand
+ = WRAPPER_PTR (TREE_OPERAND (convs, 1));
+ tree fn = cand->fn;
+ tree args;
+
+ if (DECL_CONSTRUCTOR_P (fn))
+ {
+ tree t = build_int_2 (0, 0);
+ TREE_TYPE (t) = build_pointer_type (DECL_CONTEXT (fn));
+
+ args = build_scratch_list (NULL_TREE, expr);
+ if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+ args = scratch_tree_cons (NULL_TREE, integer_one_node, args);
+ args = scratch_tree_cons (NULL_TREE, t, args);
+ }
+ else
+ args = build_this (expr);
+ expr = build_over_call (cand, args, LOOKUP_NORMAL);
+
+ /* If this is a constructor or a function returning an aggr type,
+ we need to build up a TARGET_EXPR. */
+ if (DECL_CONSTRUCTOR_P (fn))
+ expr = build_cplus_new (TREE_TYPE (convs), expr);
+
+ return expr;
+ }
+ case IDENTITY_CONV:
+ if (type_unknown_p (expr))
+ expr = instantiate_type (TREE_TYPE (convs), expr, 1);
+ if (TREE_READONLY_DECL_P (expr))
+ expr = decl_constant_value (expr);
+ return expr;
+ case AMBIG_CONV:
+ /* Call build_user_type_conversion again for the error. */
+ return build_user_type_conversion
+ (TREE_TYPE (convs), TREE_OPERAND (convs, 0), LOOKUP_NORMAL);
+
+ default:
+ break;
+ };
+
+ expr = convert_like (TREE_OPERAND (convs, 0), expr);
+ if (expr == error_mark_node)
+ return error_mark_node;
- if (TYPE_SIZE (value_type) == 0)
+ switch (TREE_CODE (convs))
{
- if (flags & LOOKUP_COMPLAIN)
- incomplete_type_error (0, value_type);
- return error_mark_node;
+ case RVALUE_CONV:
+ if (! IS_AGGR_TYPE (TREE_TYPE (convs)))
+ return expr;
+ /* else fall through */
+ case BASE_CONV:
+ {
+ tree cvt_expr = build_user_type_conversion
+ (TREE_TYPE (convs), expr, LOOKUP_NORMAL);
+ if (!cvt_expr)
+ {
+ /* This can occur if, for example, the EXPR has incomplete
+ type. We can't check for that before attempting the
+ conversion because the type might be an incomplete
+ array type, which is OK if some constructor for the
+ destination type takes a pointer argument. */
+ if (TYPE_SIZE (TREE_TYPE (expr)) == 0)
+ {
+ if (comptypes (TREE_TYPE (expr), TREE_TYPE (convs), 1))
+ incomplete_type_error (expr, TREE_TYPE (expr));
+ else
+ cp_error ("could not convert `%E' (with incomplete type `%T') to `%T'",
+ expr, TREE_TYPE (expr), TREE_TYPE (convs));
+ }
+ else
+ cp_error ("could not convert `%E' to `%T'",
+ expr, TREE_TYPE (convs));
+ return error_mark_node;
+ }
+ return cvt_expr;
+ }
+
+ case REF_BIND:
+ return convert_to_reference
+ (TREE_TYPE (convs), expr,
+ CONV_IMPLICIT, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
+ error_mark_node);
+ case LVALUE_CONV:
+ return decay_conversion (expr);
+
+ default:
+ break;
+ }
+ return ocp_convert (TREE_TYPE (convs), expr, CONV_IMPLICIT,
+ LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
+}
+
+/* ARG is being passed to a varargs function. Perform any conversions
+ required. Return the converted value. */
+
+tree
+convert_arg_to_ellipsis (arg)
+ tree arg;
+{
+ if (TREE_CODE (TREE_TYPE (arg)) == REAL_TYPE
+ && (TYPE_PRECISION (TREE_TYPE (arg))
+ < TYPE_PRECISION (double_type_node)))
+ /* Convert `float' to `double'. */
+ arg = cp_convert (double_type_node, arg);
+ else if (IS_AGGR_TYPE (TREE_TYPE (arg))
+ && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (arg)))
+ cp_warning ("cannot pass objects of type `%T' through `...'",
+ TREE_TYPE (arg));
+ else
+ /* Convert `short' and `char' to full-size `int'. */
+ arg = default_conversion (arg);
+
+ return arg;
+}
+
+/* ARG is a default argument expression being passed to a parameter of
+ the indicated TYPE. Do any required conversions. Return the
+ converted value. */
+
+tree
+convert_default_arg (type, arg)
+ tree type, arg;
+{
+ arg = break_out_target_exprs (arg);
+
+ if (TREE_CODE (arg) == CONSTRUCTOR)
+ {
+ arg = digest_init (type, arg, 0);
+ arg = convert_for_initialization (0, type, arg, LOOKUP_NORMAL,
+ "default argument", 0, 0);
+ }
+ else
+ {
+ /* This could get clobbered by the following call. */
+ if (TREE_HAS_CONSTRUCTOR (arg))
+ arg = copy_node (arg);
+
+ arg = convert_for_initialization (0, type, arg, LOOKUP_NORMAL,
+ "default argument", 0, 0);
+#ifdef PROMOTE_PROTOTYPES
+ if ((TREE_CODE (type) == INTEGER_TYPE
+ || TREE_CODE (type) == ENUMERAL_TYPE)
+ && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+ arg = default_conversion (arg);
+#endif
}
- if (DECL_STATIC_FUNCTION_P (function))
- parms = convert_arguments (NULL_TREE, TYPE_ARG_TYPES (fntype),
- TREE_CHAIN (parms), function, LOOKUP_NORMAL);
- else if (need_vtbl == unneeded)
+ return arg;
+}
+
+static tree
+build_over_call (cand, args, flags)
+ struct z_candidate *cand;
+ tree args;
+ int flags;
+{
+ tree fn = cand->fn;
+ tree convs = cand->convs;
+ tree converted_args = NULL_TREE;
+ tree parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ tree conv, arg, val;
+ int i = 0;
+ int is_method = 0;
+
+ /* Give any warnings we noticed during overload resolution. */
+ if (cand->warnings)
+ for (val = cand->warnings; val; val = TREE_CHAIN (val))
+ joust (cand, WRAPPER_PTR (TREE_VALUE (val)), 1);
+
+ if (DECL_FUNCTION_MEMBER_P (fn))
+ enforce_access (cand->basetype_path, fn);
+
+ if (args && TREE_CODE (args) != TREE_LIST)
+ args = build_scratch_list (NULL_TREE, args);
+ arg = args;
+
+ /* The implicit parameters to a constructor are not considered by overload
+ resolution, and must be of the proper type. */
+ if (DECL_CONSTRUCTOR_P (fn))
{
- int sub_flags = DECL_CONSTRUCTOR_P (function) ? flags : LOOKUP_NORMAL;
- basetype = TREE_TYPE (instance);
- if (TYPE_METHOD_BASETYPE (TREE_TYPE (function)) != TYPE_MAIN_VARIANT (basetype)
- && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+ converted_args = expr_tree_cons (NULL_TREE, TREE_VALUE (arg), converted_args);
+ arg = TREE_CHAIN (arg);
+ parm = TREE_CHAIN (parm);
+ if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
{
- basetype = DECL_CLASS_CONTEXT (function);
- instance_ptr = convert_pointer_to (basetype, instance_ptr);
- instance = build_indirect_ref (instance_ptr, NULL_PTR);
+ converted_args = expr_tree_cons
+ (NULL_TREE, TREE_VALUE (arg), converted_args);
+ arg = TREE_CHAIN (arg);
+ parm = TREE_CHAIN (parm);
}
- parms = tree_cons (NULL_TREE, instance_ptr,
- convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), function, sub_flags));
+ }
+ /* Bypass access control for 'this' parameter. */
+ else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE)
+ {
+ tree parmtype = TREE_VALUE (parm);
+ tree argtype = TREE_TYPE (TREE_VALUE (arg));
+ if (ICS_BAD_FLAG (TREE_VEC_ELT (convs, i)))
+ {
+ int dv = (TYPE_VOLATILE (TREE_TYPE (parmtype))
+ < TYPE_VOLATILE (TREE_TYPE (argtype)));
+ int dc = (TYPE_READONLY (TREE_TYPE (parmtype))
+ < TYPE_READONLY (TREE_TYPE (argtype)));
+ char *p = (dv && dc ? "const and volatile"
+ : dc ? "const" : dv ? "volatile" : "");
+
+ cp_pedwarn ("passing `%T' as `this' argument of `%#D' discards %s",
+ TREE_TYPE (argtype), fn, p);
+ }
+ converted_args = expr_tree_cons
+ (NULL_TREE, convert_force (TREE_VALUE (parm), TREE_VALUE (arg), CONV_C_CAST),
+ converted_args);
+ parm = TREE_CHAIN (parm);
+ arg = TREE_CHAIN (arg);
+ ++i;
+ is_method = 1;
}
- else
+
+ for (; arg && parm;
+ parm = TREE_CHAIN (parm), arg = TREE_CHAIN (arg), ++i)
{
- if ((flags & LOOKUP_NONVIRTUAL) == 0)
- basetype = DECL_CONTEXT (function);
+ tree type = TREE_VALUE (parm);
- /* First parm could be integer_zerop with casts like
- ((Object*)0)->Object::IsA() */
- if (!integer_zerop (TREE_VALUE (parms)))
+ conv = TREE_VEC_ELT (convs, i);
+ if (ICS_BAD_FLAG (conv))
{
- /* Since we can't have inheritance with a union, doing get_binfo
- on it won't work. We do all the convert_pointer_to_real
- stuff to handle MI correctly...for unions, that's not
- an issue, so we must short-circuit that extra work here. */
- tree tmp = TREE_TYPE (TREE_TYPE (TREE_VALUE (parms)));
- if (tmp != NULL_TREE && TREE_CODE (tmp) == UNION_TYPE)
- instance_ptr = TREE_VALUE (parms);
- else
- {
- tree binfo = get_binfo (basetype,
- TREE_TYPE (TREE_TYPE (TREE_VALUE (parms))),
- 0);
- instance_ptr = convert_pointer_to_real (binfo, TREE_VALUE (parms));
- }
- instance_ptr
- = convert_pointer_to (build_type_variant (basetype,
- constp, volatilep),
- instance_ptr);
+ tree t = conv;
+ val = TREE_VALUE (arg);
- if (TREE_CODE (instance_ptr) == COND_EXPR)
+ for (; t; t = TREE_OPERAND (t, 0))
{
- instance_ptr = save_expr (instance_ptr);
- instance = build_indirect_ref (instance_ptr, NULL_PTR);
+ if (TREE_CODE (t) == USER_CONV
+ || TREE_CODE (t) == AMBIG_CONV)
+ {
+ val = convert_like (t, val);
+ break;
+ }
+ else if (TREE_CODE (t) == IDENTITY_CONV)
+ break;
}
- else if (TREE_CODE (instance_ptr) == NOP_EXPR
- && TREE_CODE (TREE_OPERAND (instance_ptr, 0)) == ADDR_EXPR
- && TREE_OPERAND (TREE_OPERAND (instance_ptr, 0), 0) == instance)
- ;
- /* The call to `convert_pointer_to' may return error_mark_node. */
- else if (TREE_CODE (instance_ptr) == ERROR_MARK)
- return instance_ptr;
- else if (instance == NULL_TREE
- || TREE_CODE (instance) != INDIRECT_REF
- || TREE_OPERAND (instance, 0) != instance_ptr)
- instance = build_indirect_ref (instance_ptr, NULL_PTR);
- }
- parms = tree_cons (NULL_TREE, instance_ptr,
- convert_arguments (NULL_TREE, TREE_CHAIN (TYPE_ARG_TYPES (fntype)), TREE_CHAIN (parms), function, LOOKUP_NORMAL));
+ val = convert_for_initialization
+ (NULL_TREE, type, val, LOOKUP_NORMAL,
+ "argument passing", fn, i - is_method);
+ }
+ else
+ val = convert_like (conv, TREE_VALUE (arg));
+
+#ifdef PROMOTE_PROTOTYPES
+ if ((TREE_CODE (type) == INTEGER_TYPE
+ || TREE_CODE (type) == ENUMERAL_TYPE)
+ && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+ val = default_conversion (val);
+#endif
+ converted_args = expr_tree_cons (NULL_TREE, val, converted_args);
}
-#if 0
- /* Constructors do not overload method calls. */
- else if (TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype)
- && name != TYPE_IDENTIFIER (basetype)
- && (TREE_CODE (function) != FUNCTION_DECL
- || strncmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)),
- OPERATOR_METHOD_FORMAT,
- OPERATOR_METHOD_LENGTH))
- && (may_be_remote (basetype) || instance != C_C_D))
+ /* Default arguments */
+ for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm))
{
- tree fn_as_int;
+ tree arg = TREE_PURPOSE (parm);
- parms = TREE_CHAIN (parms);
+ if (DECL_TEMPLATE_INFO (fn))
+ {
+ /* This came from a template. Instantiate the default arg here,
+ not in tsubst. In the case of something like:
- if (!all_virtual && TREE_CODE (function) == FUNCTION_DECL)
- fn_as_int = build_unary_op (ADDR_EXPR, function, 0);
- else
- fn_as_int = convert (TREE_TYPE (default_conversion (function)), DECL_VINDEX (function));
- if (all_virtual == 1)
- fn_as_int = convert (integer_type_node, fn_as_int);
+ template <class T>
+ struct S {
+ static T t();
+ void f(T = t());
+ };
+
+ we must be careful to do name lookup in the scope of
+ S<T>, rather than in the current class. */
+ if (DECL_CLASS_SCOPE_P (fn))
+ pushclass (DECL_REAL_CONTEXT (fn), 2);
+
+ arg = tsubst_expr (arg, DECL_TI_ARGS (fn), NULL_TREE);
+
+ if (DECL_CLASS_SCOPE_P (fn))
+ popclass (1);
+ }
+ converted_args = expr_tree_cons
+ (NULL_TREE, convert_default_arg (TREE_VALUE (parm), arg),
+ converted_args);
+ }
+
+ /* Ellipsis */
+ for (; arg; arg = TREE_CHAIN (arg))
+ converted_args
+ = expr_tree_cons (NULL_TREE,
+ convert_arg_to_ellipsis (TREE_VALUE (arg)),
+ converted_args);
- result = build_opfncall (METHOD_CALL_EXPR, LOOKUP_NORMAL, instance, fn_as_int, parms);
+ converted_args = nreverse (converted_args);
- if (result == NULL_TREE)
+ /* Avoid actually calling copy constructors and copy assignment operators,
+ if possible. */
+ if (DECL_CONSTRUCTOR_P (fn)
+ && TREE_VEC_LENGTH (convs) == 1
+ && copy_args_p (fn))
+ {
+ tree targ;
+ arg = TREE_CHAIN (converted_args);
+ if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
+ arg = TREE_CHAIN (arg);
+ arg = TREE_VALUE (arg);
+
+ /* Pull out the real argument, disregarding const-correctness. */
+ targ = arg;
+ while (TREE_CODE (targ) == NOP_EXPR
+ || TREE_CODE (targ) == NON_LVALUE_EXPR
+ || TREE_CODE (targ) == CONVERT_EXPR)
+ targ = TREE_OPERAND (targ, 0);
+ if (TREE_CODE (targ) == ADDR_EXPR)
{
- compiler_error ("could not overload `operator->()(...)'");
- return error_mark_node;
+ targ = TREE_OPERAND (targ, 0);
+ if (! comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (arg))),
+ TYPE_MAIN_VARIANT (TREE_TYPE (targ)), 1))
+ targ = NULL_TREE;
}
- else if (result == error_mark_node)
- return error_mark_node;
+ else
+ targ = NULL_TREE;
-#if 0
- /* Do this if we want the result of operator->() to inherit
- the type of the function it is subbing for. */
- TREE_TYPE (result) = value_type;
-#endif
+ if (targ)
+ arg = targ;
+ else
+ arg = build_indirect_ref (arg, 0);
+
+ /* [class.copy]: the copy constructor is implicitly defined even if
+ the implementation elided its use. */
+ if (TYPE_HAS_COMPLEX_INIT_REF (DECL_CONTEXT (fn)))
+ mark_used (fn);
+
+ /* If we're creating a temp and we already have one, don't create a
+ new one. If we're not creating a temp but we get one, use
+ INIT_EXPR to collapse the temp into our target. Otherwise, if the
+ ctor is trivial, do a bitwise copy with a simple TARGET_EXPR for a
+ temp or an INIT_EXPR otherwise. */
+ if (integer_zerop (TREE_VALUE (args)))
+ {
+ if (! real_lvalue_p (arg))
+ return arg;
+ else if (TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
+ {
+ val = build (VAR_DECL, DECL_CONTEXT (fn));
+ layout_decl (val, 0);
+ val = build (TARGET_EXPR, DECL_CONTEXT (fn), val, arg, 0, 0);
+ TREE_SIDE_EFFECTS (val) = 1;
+ return val;
+ }
+ }
+ else if (! real_lvalue_p (arg)
+ || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
+ {
+ tree to = stabilize_reference
+ (build_indirect_ref (TREE_VALUE (args), 0));
+
+ /* Don't copy the padding byte; it might not have been allocated
+ if to is a base subobject. */
+ if (is_empty_class (DECL_CLASS_CONTEXT (fn)))
+ return build_unary_op
+ (ADDR_EXPR, build (COMPOUND_EXPR, TREE_TYPE (to),
+ cp_convert (void_type_node, arg), to),
+ 0);
+
+ val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
+ TREE_SIDE_EFFECTS (val) = 1;
+ return build_unary_op (ADDR_EXPR, val, 0);
+ }
+ }
+ else if (DECL_NAME (fn) == ansi_opname[MODIFY_EXPR]
+ && copy_args_p (fn)
+ && TYPE_HAS_TRIVIAL_ASSIGN_REF (DECL_CLASS_CONTEXT (fn)))
+ {
+ tree to = stabilize_reference
+ (build_indirect_ref (TREE_VALUE (converted_args), 0));
- return result;
+ arg = build_indirect_ref (TREE_VALUE (TREE_CHAIN (converted_args)), 0);
+
+ /* Don't copy the padding byte; it might not have been allocated
+ if to is a base subobject. */
+ if (is_empty_class (DECL_CLASS_CONTEXT (fn)))
+ return build (COMPOUND_EXPR, TREE_TYPE (to),
+ cp_convert (void_type_node, arg), to);
+
+ val = build (MODIFY_EXPR, TREE_TYPE (to), to, arg);
+ TREE_SIDE_EFFECTS (val) = 1;
+ return val;
}
-#endif
- if (parms == error_mark_node
- || (parms && TREE_CHAIN (parms) == error_mark_node))
- return error_mark_node;
+ mark_used (fn);
- if (need_vtbl == needed)
+ if (DECL_CLASS_SCOPE_P (fn) && IS_SIGNATURE (DECL_CONTEXT (fn)))
+ return build_signature_method_call (fn, converted_args);
+ else if (DECL_VINDEX (fn) && (flags & LOOKUP_NONVIRTUAL) == 0)
{
- function = build_vfn_ref (&TREE_VALUE (parms), instance,
- DECL_VINDEX (function));
- TREE_TYPE (function) = build_pointer_type (fntype);
+ tree t, *p = &TREE_VALUE (converted_args);
+ tree binfo = get_binfo
+ (DECL_CONTEXT (fn), TREE_TYPE (TREE_TYPE (*p)), 0);
+ *p = convert_pointer_to_real (binfo, *p);
+ if (TREE_SIDE_EFFECTS (*p))
+ *p = save_expr (*p);
+ t = build_pointer_type (TREE_TYPE (fn));
+ fn = build_vfn_ref (p, build_indirect_ref (*p, 0), DECL_VINDEX (fn));
+ TREE_TYPE (fn) = t;
}
+ else if (DECL_INLINE (fn))
+ fn = inline_conversion (fn);
+ else
+ fn = build_addr_func (fn);
- if (TREE_CODE (function) == FUNCTION_DECL)
- GNU_xref_call (current_function_decl,
- IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)));
+ /* Recognize certain built-in functions so we can make tree-codes
+ other than CALL_EXPR. We do this when it enables fold-const.c
+ to do something useful. */
- {
- int is_constructor;
-
- if (TREE_CODE (function) == FUNCTION_DECL)
- {
- is_constructor = DECL_CONSTRUCTOR_P (function);
- TREE_USED (function) = 1;
- function = default_conversion (function);
- }
- else
+ if (TREE_CODE (fn) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL
+ && DECL_BUILT_IN (TREE_OPERAND (fn, 0)))
+ switch (DECL_FUNCTION_CODE (TREE_OPERAND (fn, 0)))
{
- is_constructor = 0;
- function = default_conversion (function);
+ case BUILT_IN_ABS:
+ case BUILT_IN_LABS:
+ case BUILT_IN_FABS:
+ if (converted_args == 0)
+ return integer_zero_node;
+ return build_unary_op (ABS_EXPR, TREE_VALUE (converted_args), 0);
+ default:
+ break;
}
- result = build_nt (CALL_EXPR, function, parms, NULL_TREE);
-
- TREE_TYPE (result) = value_type;
- TREE_SIDE_EFFECTS (result) = 1;
- TREE_HAS_CONSTRUCTOR (result) = is_constructor;
- result = convert_from_reference (result);
- return result;
- }
+ fn = build_call (fn, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), converted_args);
+ if (TREE_TYPE (fn) == void_type_node)
+ return fn;
+ fn = require_complete_type (fn);
+ if (IS_AGGR_TYPE (TREE_TYPE (fn)))
+ fn = build_cplus_new (TREE_TYPE (fn), fn);
+ return convert_from_reference (fn);
}
-/* Similar to `build_method_call', but for overloaded non-member functions.
- The name of this function comes through NAME. The name depends
- on PARMS.
+static tree
+build_new_method_call (instance, name, args, basetype_path, flags)
+ tree instance, name, args, basetype_path;
+ int flags;
+{
+ struct z_candidate *candidates = 0, *cand;
+ tree explicit_targs = NULL_TREE;
+ tree basetype, mem_args = NULL_TREE, fns, instance_ptr;
+ tree pretty_name;
+ tree user_args = args;
+ tree templates = NULL_TREE;
+ int template_only = 0;
+
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+ {
+ explicit_targs = TREE_OPERAND (name, 1);
+ name = TREE_OPERAND (name, 0);
+ if (TREE_CODE (name) == TEMPLATE_DECL)
+ name = DECL_NAME (name);
+ template_only = 1;
+ }
- Note that this function must handle simple `C' promotions,
- as well as variable numbers of arguments (...), and
- default arguments to boot.
+ /* If there is an extra argument for controlling virtual bases,
+ remove it for error reporting. */
+ if (flags & LOOKUP_HAS_IN_CHARGE)
+ user_args = TREE_CHAIN (args);
- If the overloading is successful, we return a tree node which
- contains the call to the function.
+ args = resolve_args (args);
- If overloading produces candidates which are probable, but not definite,
- we hold these candidates. If FINAL_CP is non-zero, then we are free
- to assume that final_cp points to enough storage for all candidates that
- this function might generate. The `harshness' array is preallocated for
- the first candidate, but not for subsequent ones.
+ if (args == error_mark_node)
+ return error_mark_node;
- Note that the DECL_RTL of FUNCTION must be made to agree with this
- function's new name. */
+ if (instance == NULL_TREE)
+ basetype = BINFO_TYPE (basetype_path);
+ else
+ {
+ if (TREE_CODE (instance) == OFFSET_REF)
+ instance = resolve_offset_ref (instance);
+ if (TREE_CODE (TREE_TYPE (instance)) == REFERENCE_TYPE)
+ instance = convert_from_reference (instance);
+ basetype = TREE_TYPE (instance);
-tree
-build_overload_call_real (fnname, parms, flags, final_cp, buildxxx)
- tree fnname, parms;
- int flags;
- struct candidate *final_cp;
- int buildxxx;
-{
- /* must check for overloading here */
- tree overload_name, functions, function, parm;
- tree parmtypes = NULL_TREE, last = NULL_TREE;
- register tree outer;
- int length;
- int parmlength = list_length (parms);
+ /* XXX this should be handled before we get here. */
+ if (! IS_AGGR_TYPE (basetype)
+ && ! (TYPE_LANG_SPECIFIC (basetype)
+ && (IS_SIGNATURE_POINTER (basetype)
+ || IS_SIGNATURE_REFERENCE (basetype))))
+ {
+ if ((flags & LOOKUP_COMPLAIN) && basetype != error_mark_node)
+ cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
+ name, instance, basetype);
- struct candidate *candidates, *cp;
+ return error_mark_node;
+ }
- if (final_cp)
- {
- final_cp[0].h.code = 0;
- final_cp[0].h.distance = 0;
- final_cp[0].function = 0;
- /* end marker. */
- final_cp[1].h.code = EVIL_CODE;
+ /* If `instance' is a signature pointer/reference and `name' is
+ not a constructor, we are calling a signature member function.
+ In that case set the `basetype' to the signature type. */
+ if ((IS_SIGNATURE_POINTER (basetype)
+ || IS_SIGNATURE_REFERENCE (basetype))
+ && TYPE_IDENTIFIER (basetype) != name)
+ basetype = SIGNATURE_TYPE (basetype);
}
- for (parm = parms; parm; parm = TREE_CHAIN (parm))
+ if (basetype_path == NULL_TREE)
+ basetype_path = TYPE_BINFO (basetype);
+
+ if (instance)
{
- register tree t = TREE_TYPE (TREE_VALUE (parm));
+ instance_ptr = build_this (instance);
- if (t == error_mark_node)
- {
- if (final_cp)
- final_cp->h.code = EVIL_CODE;
- return error_mark_node;
- }
- if (TREE_CODE (t) == OFFSET_TYPE)
-#if 0
- /* This breaks reference-to-array parameters. */
- || TREE_CODE (t) == ARRAY_TYPE
-#endif
+ if (! template_only)
{
- /* Perform the conversion from ARRAY_TYPE to POINTER_TYPE in place.
- Also convert OFFSET_TYPE entities to their normal selves.
- This eliminates needless calls to `compute_conversion_costs'. */
- TREE_VALUE (parm) = default_conversion (TREE_VALUE (parm));
- t = TREE_TYPE (TREE_VALUE (parm));
+ /* XXX this should be handled before we get here. */
+ fns = build_field_call (basetype_path, instance_ptr, name, args);
+ if (fns)
+ return fns;
}
- last = build_tree_list (NULL_TREE, t);
- parmtypes = chainon (parmtypes, last);
}
- if (last)
- TREE_CHAIN (last) = void_list_node;
else
- parmtypes = void_list_node;
+ {
+ instance_ptr = build_int_2 (0, 0);
+ TREE_TYPE (instance_ptr) = build_pointer_type (basetype);
+ }
+
+ pretty_name
+ = (name == ctor_identifier ? constructor_name (basetype) : name);
+
+ fns = lookup_fnfields (basetype_path, name, 1);
- if (is_overloaded_fn (fnname))
+ if (fns == error_mark_node)
+ return error_mark_node;
+ if (fns)
{
- functions = fnname;
- if (TREE_CODE (fnname) == TREE_LIST)
- fnname = TREE_PURPOSE (functions);
- else if (TREE_CODE (fnname) == FUNCTION_DECL)
- fnname = DECL_NAME (functions);
+ tree fn = TREE_VALUE (fns);
+ if (name == ctor_identifier && TYPE_USES_VIRTUAL_BASECLASSES (basetype)
+ && ! (flags & LOOKUP_HAS_IN_CHARGE))
+ {
+ flags |= LOOKUP_HAS_IN_CHARGE;
+ args = scratch_tree_cons (NULL_TREE, integer_one_node, args);
+ }
+ mem_args = scratch_tree_cons (NULL_TREE, instance_ptr, args);
+ for (; fn; fn = OVL_NEXT (fn))
+ {
+ tree t = OVL_CURRENT (fn);
+ tree this_arglist;
+
+ /* We can end up here for copy-init of same or base class. */
+ if (name == ctor_identifier
+ && (flags & LOOKUP_ONLYCONVERTING)
+ && DECL_NONCONVERTING_P (t))
+ continue;
+ if (TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)
+ this_arglist = mem_args;
+ else
+ this_arglist = args;
+
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ {
+ /* A member template. */
+ templates = scratch_tree_cons (NULL_TREE, t, templates);
+ candidates =
+ add_template_candidate (candidates, t, explicit_targs,
+ this_arglist,
+ TREE_TYPE (name), flags, DEDUCE_CALL);
+ }
+ else if (! template_only)
+ candidates = add_function_candidate (candidates, t,
+ this_arglist, flags);
+
+ if (candidates)
+ candidates->basetype_path = TREE_PURPOSE (fns);
+ }
}
- else
- functions = lookup_name_nonclass (fnname);
- if (functions == NULL_TREE)
+ if (! any_viable (candidates))
{
+ /* XXX will LOOKUP_SPECULATIVELY be needed when this is done? */
if (flags & LOOKUP_SPECULATIVELY)
return NULL_TREE;
- if (flags & LOOKUP_COMPLAIN)
- error ("only member functions apply");
- if (final_cp)
- final_cp->h.code = EVIL_CODE;
+ cp_error ("no matching function for call to `%T::%D (%A)%V'", basetype,
+ pretty_name, user_args, TREE_TYPE (TREE_TYPE (instance_ptr)));
+ print_z_candidates (candidates);
return error_mark_node;
}
+ candidates = splice_viable (candidates);
+ cand = tourney (candidates);
- if (TREE_CODE (functions) == FUNCTION_DECL && ! IDENTIFIER_OPNAME_P (fnname))
+ if (cand == 0)
{
- functions = DECL_MAIN_VARIANT (functions);
- if (final_cp)
- {
- /* We are just curious whether this is a viable alternative or
- not. */
- compute_conversion_costs (functions, parms, final_cp, parmlength);
- return functions;
- }
- else
- return build_function_call_real (functions, parms, 1, flags);
+ cp_error ("call of overloaded `%D(%A)' is ambiguous", pretty_name,
+ user_args);
+ print_z_candidates (candidates);
+ return error_mark_node;
}
- if (TREE_CODE (functions) == TREE_LIST
- && TREE_VALUE (functions) == NULL_TREE)
+ if (DECL_ABSTRACT_VIRTUAL_P (cand->fn)
+ && instance == current_class_ref
+ && DECL_CONSTRUCTOR_P (current_function_decl)
+ && ! (flags & LOOKUP_NONVIRTUAL)
+ && value_member (cand->fn, get_abstract_virtuals (basetype)))
+ cp_error ("abstract virtual `%#D' called from constructor", cand->fn);
+ if (TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
+ && TREE_CODE (instance_ptr) == NOP_EXPR
+ && TREE_OPERAND (instance_ptr, 0) == error_mark_node)
+ cp_error ("cannot call member function `%D' without object", cand->fn);
+
+ if (DECL_VINDEX (cand->fn) && ! (flags & LOOKUP_NONVIRTUAL)
+ && ((instance == current_class_ref && (dtor_label || ctor_label))
+ || resolves_to_fixed_type_p (instance, 0)))
+ flags |= LOOKUP_NONVIRTUAL;
+
+ /* Pedantically, normal function declarations are never considered
+ to refer to template instantiations, so we only do this with
+ -fguiding-decls. */
+ if (flag_guiding_decls && templates && ! cand->template
+ && ! DECL_INITIAL (cand->fn))
+ add_maybe_template (cand->fn, templates);
+
+ return build_over_call
+ (cand,
+ TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE ? mem_args : args,
+ flags);
+}
+
+/* Returns non-zero iff standard conversion sequence ICS1 is a proper
+ subsequence of ICS2. */
+
+static int
+is_subseq (ics1, ics2)
+ tree ics1, ics2;
+{
+ /* We can assume that a conversion of the same code
+ between the same types indicates a subsequence since we only get
+ here if the types we are converting from are the same. */
+
+ while (TREE_CODE (ics1) == RVALUE_CONV
+ || TREE_CODE (ics1) == LVALUE_CONV)
+ ics1 = TREE_OPERAND (ics1, 0);
+
+ while (1)
{
- if (flags & LOOKUP_SPECULATIVELY)
- return NULL_TREE;
-
- if (flags & LOOKUP_COMPLAIN)
- cp_error ("function `%D' declared overloaded, but no instances of that function declared",
- TREE_PURPOSE (functions));
- if (final_cp)
- final_cp->h.code = EVIL_CODE;
- return error_mark_node;
+ while (TREE_CODE (ics2) == RVALUE_CONV
+ || TREE_CODE (ics2) == LVALUE_CONV)
+ ics2 = TREE_OPERAND (ics2, 0);
+
+ if (TREE_CODE (ics2) == USER_CONV
+ || TREE_CODE (ics2) == AMBIG_CONV
+ || TREE_CODE (ics2) == IDENTITY_CONV)
+ /* At this point, ICS1 cannot be a proper subsequence of
+ ICS2. We can get a USER_CONV when we are comparing the
+ second standard conversion sequence of two user conversion
+ sequences. */
+ return 0;
+
+ ics2 = TREE_OPERAND (ics2, 0);
+
+ if (TREE_CODE (ics2) == TREE_CODE (ics1)
+ && comptypes (TREE_TYPE (ics2), TREE_TYPE (ics1), 1)
+ && comptypes (TREE_TYPE (TREE_OPERAND (ics2, 0)),
+ TREE_TYPE (TREE_OPERAND (ics1, 0)), 1))
+ return 1;
+ }
+}
+
+/* Returns non-zero iff DERIVED is derived from BASE. The inputs may
+ be any _TYPE nodes. */
+
+static int
+is_properly_derived_from (derived, base)
+ tree derived;
+ tree base;
+{
+ if (!IS_AGGR_TYPE_CODE (TREE_CODE (derived))
+ || !IS_AGGR_TYPE_CODE (TREE_CODE (base)))
+ return 0;
+
+ /* We only allow proper derivation here. The DERIVED_FROM_P macro
+ considers every class derived from itself. */
+ return (!comptypes (TYPE_MAIN_VARIANT (derived),
+ TYPE_MAIN_VARIANT (base), 1)
+ && DERIVED_FROM_P (base, derived));
+}
+
+/* We build the ICS for an implicit object parameter as a pointer
+ conversion sequence. However, such a sequence should be compared
+ as if it were a reference conversion sequence. If ICS is the
+ implicit conversion sequence for an implicit object parameter,
+ modify it accordingly. */
+
+static void
+maybe_handle_implicit_object (ics)
+ tree* ics;
+{
+ if (ICS_THIS_FLAG (*ics))
+ {
+ /* [over.match.funcs]
+
+ For non-static member functions, the type of the
+ implicit object parameter is "reference to cv X"
+ where X is the class of which the function is a
+ member and cv is the cv-qualification on the member
+ function declaration. */
+ tree t = *ics;
+ if (TREE_CODE (t) == QUAL_CONV)
+ t = TREE_OPERAND (t, 0);
+ if (TREE_CODE (t) == PTR_CONV)
+ t = TREE_OPERAND (t, 0);
+ t = build1 (IDENTITY_CONV, TREE_TYPE (TREE_TYPE (t)), NULL_TREE);
+ t = build_conv (REF_BIND,
+ build_reference_type (TREE_TYPE (TREE_TYPE (*ics))),
+ t);
+ ICS_STD_RANK (t) = ICS_STD_RANK (*ics);
+ *ics = t;
}
+}
+
+/* If ICS is a REF_BIND, modify it appropriately, set TARGET_TYPE
+ to the type the reference originally referred to, and return 1.
+ Otherwise, return 0. */
- length = count_functions (functions);
+static int
+maybe_handle_ref_bind (ics, target_type)
+ tree* ics;
+ tree* target_type;
+{
+ if (TREE_CODE (*ics) == REF_BIND)
+ {
+ /* [over.ics.rank]
+
+ When a parameter of reference type binds directly
+ (_dcl.init.ref_) to an argument expression, the implicit
+ conversion sequence is the identity conversion, unless the
+ argument expression has a type that is a derived class of the
+ parameter type, in which case the implicit conversion
+ sequence is a derived-to-base Conversion.
+
+ If the parameter binds directly to the result of applying a
+ conversion function to the argument expression, the implicit
+ conversion sequence is a user-defined conversion sequence
+ (_over.ics.user_), with the second standard conversion
+ sequence either an identity conversion or, if the conversion
+ function returns an entity of a type that is a derived class
+ of the parameter type, a derived-to-base Conversion.
+
+ When a parameter of reference type is not bound directly to
+ an argument expression, the conversion sequence is the one
+ required to convert the argument expression to the underlying
+ type of the reference according to _over.best.ics_.
+ Conceptually, this conversion sequence corresponds to
+ copy-initializing a temporary of the underlying type with the
+ argument expression. Any difference in top-level
+ cv-qualification is subsumed by the initialization itself and
+ does not constitute a conversion. */
+
+ tree old_ics = *ics;
+
+ *target_type = TREE_TYPE (TREE_TYPE (*ics));
+ *ics = TREE_OPERAND (*ics, 0);
+ if (TREE_CODE (*ics) == IDENTITY_CONV
+ && is_properly_derived_from (TREE_TYPE (*ics), *target_type))
+ *ics = build_conv (BASE_CONV, *target_type, *ics);
+ ICS_USER_FLAG (*ics) = ICS_USER_FLAG (old_ics);
+ ICS_BAD_FLAG (*ics) = ICS_BAD_FLAG (old_ics);
+
+ return 1;
+ }
- if (final_cp)
- candidates = final_cp;
+ return 0;
+}
+
+/* Compare two implicit conversion sequences according to the rules set out in
+ [over.ics.rank]. Return values:
+
+ 1: ics1 is better than ics2
+ -1: ics2 is better than ics1
+ 0: ics1 and ics2 are indistinguishable */
+
+static int
+compare_ics (ics1, ics2)
+ tree ics1, ics2;
+{
+ tree from_type1;
+ tree from_type2;
+ tree to_type1;
+ tree to_type2;
+ tree deref_from_type1 = NULL_TREE;
+ tree deref_from_type2;
+ tree deref_to_type1;
+ tree deref_to_type2;
+
+ /* REF_BINDING is non-zero if the result of the conversion sequence
+ is a reference type. In that case TARGET_TYPE is the
+ type referred to by the reference. */
+ int ref_binding1;
+ int ref_binding2;
+ tree target_type1;
+ tree target_type2;
+
+ /* Handle implicit object parameters. */
+ maybe_handle_implicit_object (&ics1);
+ maybe_handle_implicit_object (&ics2);
+
+ /* Handle reference parameters. */
+ ref_binding1 = maybe_handle_ref_bind (&ics1, &target_type1);
+ ref_binding2 = maybe_handle_ref_bind (&ics2, &target_type2);
+
+ /* [over.ics.rank]
+
+ When comparing the basic forms of implicit conversion sequences (as
+ defined in _over.best.ics_)
+
+ --a standard conversion sequence (_over.ics.scs_) is a better
+ conversion sequence than a user-defined conversion sequence
+ or an ellipsis conversion sequence, and
+
+ --a user-defined conversion sequence (_over.ics.user_) is a
+ better conversion sequence than an ellipsis conversion sequence
+ (_over.ics.ellipsis_). */
+ if (ICS_RANK (ics1) > ICS_RANK (ics2))
+ return -1;
+ else if (ICS_RANK (ics1) < ICS_RANK (ics2))
+ return 1;
+
+ if (ICS_RANK (ics1) == BAD_RANK)
+ {
+ /* Both ICS are bad. We try to make a decision based on what
+ would have happenned if they'd been good. */
+ if (ICS_USER_FLAG (ics1) > ICS_USER_FLAG (ics2)
+ || ICS_STD_RANK (ics1) > ICS_STD_RANK (ics2))
+ return -1;
+ else if (ICS_USER_FLAG (ics1) < ICS_USER_FLAG (ics2)
+ || ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2))
+ return 1;
+
+ /* We couldn't make up our minds; try to figure it out below. */
+ }
+
+ if (ICS_ELLIPSIS_FLAG (ics1))
+ /* Both conversions are ellipsis conversions. */
+ return 0;
+
+ /* User-defined conversion sequence U1 is a better conversion sequence
+ than another user-defined conversion sequence U2 if they contain the
+ same user-defined conversion operator or constructor and if the sec-
+ ond standard conversion sequence of U1 is better than the second
+ standard conversion sequence of U2. */
+
+ if (ICS_USER_FLAG (ics1))
+ {
+ tree t1, t2;
+
+ for (t1 = ics1; TREE_CODE (t1) != USER_CONV; t1 = TREE_OPERAND (t1, 0))
+ if (TREE_CODE (t1) == AMBIG_CONV)
+ return 0;
+ for (t2 = ics2; TREE_CODE (t2) != USER_CONV; t2 = TREE_OPERAND (t2, 0))
+ if (TREE_CODE (t2) == AMBIG_CONV)
+ return 0;
+
+ if (USER_CONV_FN (t1) != USER_CONV_FN (t2))
+ return 0;
+
+ /* We can just fall through here, after setting up
+ FROM_TYPE1 and FROM_TYPE2. */
+ from_type1 = TREE_TYPE (t1);
+ from_type2 = TREE_TYPE (t2);
+ }
else
{
- candidates
- = (struct candidate *)alloca ((length+1) * sizeof (struct candidate));
- bzero ((char *) candidates, (length + 1) * sizeof (struct candidate));
+ /* We're dealing with two standard conversion sequences.
+
+ [over.ics.rank]
+
+ Standard conversion sequence S1 is a better conversion
+ sequence than standard conversion sequence S2 if
+
+ --S1 is a proper subsequence of S2 (comparing the conversion
+ sequences in the canonical form defined by _over.ics.scs_,
+ excluding any Lvalue Transformation; the identity
+ conversion sequence is considered to be a subsequence of
+ any non-identity conversion sequence */
+
+ from_type1 = ics1;
+ while (TREE_CODE (from_type1) != IDENTITY_CONV)
+ from_type1 = TREE_OPERAND (from_type1, 0);
+ from_type1 = TREE_TYPE (from_type1);
+
+ from_type2 = ics2;
+ while (TREE_CODE (from_type2) != IDENTITY_CONV)
+ from_type2 = TREE_OPERAND (from_type2, 0);
+ from_type2 = TREE_TYPE (from_type2);
+ }
+
+ if (comptypes (from_type1, from_type2, 1))
+ {
+ if (is_subseq (ics1, ics2))
+ return 1;
+ if (is_subseq (ics2, ics1))
+ return -1;
}
+ /* Otherwise, one sequence cannot be a subsequence of the other; they
+ don't start with the same type. This can happen when comparing the
+ second standard conversion sequence in two user-defined conversion
+ sequences. */
+
+ /* [over.ics.rank]
+
+ Or, if not that,
+
+ --the rank of S1 is better than the rank of S2 (by the rules
+ defined below):
- cp = candidates;
+ Standard conversion sequences are ordered by their ranks: an Exact
+ Match is a better conversion than a Promotion, which is a better
+ conversion than a Conversion.
- my_friendly_assert (is_overloaded_fn (functions), 169);
+ Two conversion sequences with the same rank are indistinguishable
+ unless one of the following rules applies:
- functions = get_first_fn (functions);
+ --A conversion that is not a conversion of a pointer, or pointer
+ to member, to bool is better than another conversion that is such
+ a conversion.
+
+ The ICS_STD_RANK automatically handles the pointer-to-bool rule,
+ so that we do not have to check it explicitly. */
+ if (ICS_STD_RANK (ics1) < ICS_STD_RANK (ics2))
+ return 1;
+ else if (ICS_STD_RANK (ics2) < ICS_STD_RANK (ics1))
+ return -1;
+
+ to_type1 = TREE_TYPE (ics1);
+ to_type2 = TREE_TYPE (ics2);
+
+ if (TYPE_PTR_P (from_type1)
+ && TYPE_PTR_P (from_type2)
+ && TYPE_PTR_P (to_type1)
+ && TYPE_PTR_P (to_type2))
+ {
+ deref_from_type1 = TREE_TYPE (from_type1);
+ deref_from_type2 = TREE_TYPE (from_type2);
+ deref_to_type1 = TREE_TYPE (to_type1);
+ deref_to_type2 = TREE_TYPE (to_type2);
+ }
+ /* The rules for pointers to members A::* are just like the rules
+ for pointers A*, except opposite: if B is derived from A then
+ A::* converts to B::*, not vice versa. For that reason, we
+ switch the from_ and to_ variables here. */
+ else if (TYPE_PTRMEM_P (from_type1)
+ && TYPE_PTRMEM_P (from_type2)
+ && TYPE_PTRMEM_P (to_type1)
+ && TYPE_PTRMEM_P (to_type2))
+ {
+ deref_to_type1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (from_type1));
+ deref_to_type2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (from_type2));
+ deref_from_type1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (to_type1));
+ deref_from_type2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (to_type2));
+ }
+ else if (TYPE_PTRMEMFUNC_P (from_type1)
+ && TYPE_PTRMEMFUNC_P (from_type2)
+ && TYPE_PTRMEMFUNC_P (to_type1)
+ && TYPE_PTRMEMFUNC_P (to_type2))
+ {
+ deref_to_type1 = TYPE_PTRMEMFUNC_OBJECT_TYPE (from_type1);
+ deref_to_type2 = TYPE_PTRMEMFUNC_OBJECT_TYPE (from_type2);
+ deref_from_type1 = TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type1);
+ deref_from_type2 = TYPE_PTRMEMFUNC_OBJECT_TYPE (to_type2);
+ }
- /* OUTER is the list of FUNCTION_DECLS, in a TREE_LIST. */
- for (outer = functions; outer; outer = DECL_CHAIN (outer))
+ if (deref_from_type1 != NULL_TREE
+ && IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type1))
+ && IS_AGGR_TYPE_CODE (TREE_CODE (deref_from_type2)))
{
- int template_cost = 0;
- function = outer;
- if (TREE_CODE (function) != FUNCTION_DECL
- && ! (TREE_CODE (function) == TEMPLATE_DECL
- && ! DECL_TEMPLATE_IS_CLASS (function)
- && TREE_CODE (DECL_TEMPLATE_RESULT (function)) == FUNCTION_DECL))
+ /* This was one of the pointer or pointer-like conversions.
+
+ [over.ics.rank]
+
+ --If class B is derived directly or indirectly from class A,
+ conversion of B* to A* is better than conversion of B* to
+ void*, and conversion of A* to void* is better than
+ conversion of B* to void*. */
+ if (TREE_CODE (deref_to_type1) == VOID_TYPE
+ && TREE_CODE (deref_to_type2) == VOID_TYPE)
+ {
+ if (is_properly_derived_from (deref_from_type1,
+ deref_from_type2))
+ return -1;
+ else if (is_properly_derived_from (deref_from_type2,
+ deref_from_type1))
+ return 1;
+ }
+ else if (TREE_CODE (deref_to_type1) == VOID_TYPE
+ || TREE_CODE (deref_to_type2) == VOID_TYPE)
{
- enum tree_code code = TREE_CODE (function);
- if (code == TEMPLATE_DECL)
- code = TREE_CODE (DECL_TEMPLATE_RESULT (function));
- if (code == CONST_DECL)
- cp_error_at
- ("enumeral value `%D' conflicts with function of same name",
- function);
- else if (code == VAR_DECL)
+ if (comptypes (deref_from_type1, deref_from_type2, 1))
{
- if (TREE_STATIC (function))
- cp_error_at
- ("variable `%D' conflicts with function of same name",
- function);
- else
- cp_error_at
- ("constant field `%D' conflicts with function of same name",
- function);
+ if (TREE_CODE (deref_to_type2) == VOID_TYPE)
+ {
+ if (is_properly_derived_from (deref_from_type1,
+ deref_to_type1))
+ return 1;
+ }
+ /* We know that DEREF_TO_TYPE1 is `void' here. */
+ else if (is_properly_derived_from (deref_from_type1,
+ deref_to_type2))
+ return -1;
}
- else if (code == TYPE_DECL)
- continue;
- else
- my_friendly_abort (2);
- error ("at this point in file");
- continue;
}
- if (TREE_CODE (function) == TEMPLATE_DECL)
+ else if (IS_AGGR_TYPE_CODE (TREE_CODE (deref_to_type1))
+ && IS_AGGR_TYPE_CODE (TREE_CODE (deref_to_type2)))
{
- int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (function));
- tree *targs = (tree *) alloca (sizeof (tree) * ntparms);
- int i;
+ /* [over.ics.rank]
- i = type_unification (DECL_TEMPLATE_PARMS (function), targs,
- TYPE_ARG_TYPES (TREE_TYPE (function)),
- parms, &template_cost, 0);
- if (i == 0)
- function = instantiate_template (function, targs);
+ --If class B is derived directly or indirectly from class A
+ and class C is derived directly or indirectly from B,
+
+ --conversion of C* to B* is better than conversion of C* to
+ A*,
+
+ --conversion of B* to A* is better than conversion of C* to
+ A* */
+ if (comptypes (deref_from_type1, deref_from_type2, 1))
+ {
+ if (is_properly_derived_from (deref_to_type1,
+ deref_to_type2))
+ return 1;
+ else if (is_properly_derived_from (deref_to_type2,
+ deref_to_type1))
+ return -1;
+ }
+ else if (comptypes (deref_to_type1, deref_to_type2, 1))
+ {
+ if (is_properly_derived_from (deref_from_type2,
+ deref_from_type1))
+ return 1;
+ else if (is_properly_derived_from (deref_from_type1,
+ deref_from_type2))
+ return -1;
+ }
}
-
- if (TREE_CODE (function) == TEMPLATE_DECL)
+ }
+ else if (IS_AGGR_TYPE_CODE (TREE_CODE (from_type1))
+ && comptypes (from_type1, from_type2, 1))
+ {
+ /* [over.ics.rank]
+
+ --binding of an expression of type C to a reference of type
+ B& is better than binding an expression of type C to a
+ reference of type A&
+
+ --conversion of C to B is better than conversion of C to A, */
+ if (is_properly_derived_from (from_type1, to_type1)
+ && is_properly_derived_from (from_type1, to_type2))
{
- /* Unconverted template -- failed match. */
- cp->function = function;
- cp->u.bad_arg = -4;
- cp->h.code = EVIL_CODE;
+ if (is_properly_derived_from (to_type1, to_type2))
+ return 1;
+ else if (is_properly_derived_from (to_type2, to_type1))
+ return -1;
}
- else
+ }
+ else if (IS_AGGR_TYPE_CODE (TREE_CODE (to_type1))
+ && comptypes (to_type1, to_type2, 1))
+ {
+ /* [over.ics.rank]
+
+ --binding of an expression of type B to a reference of type
+ A& is better than binding an expression of type C to a
+ reference of type A&,
+
+ --onversion of B to A is better than conversion of C to A */
+ if (is_properly_derived_from (from_type1, to_type1)
+ && is_properly_derived_from (from_type2, to_type1))
{
- struct candidate *cp2;
+ if (is_properly_derived_from (from_type2, from_type1))
+ return 1;
+ else if (is_properly_derived_from (from_type1, from_type2))
+ return -1;
+ }
+ }
- /* Check that this decl is not the same as a function that's in
- the list due to some template instantiation. */
- cp2 = candidates;
- while (cp2 != cp)
- if (cp2->function == function)
- break;
- else
- cp2 += 1;
- if (cp2->function == function)
- continue;
+ /* [over.ics.rank]
- function = DECL_MAIN_VARIANT (function);
+ --S1 and S2 differ only in their qualification conversion and yield
+ similar types T1 and T2 (_conv.qual_), respectively, and the cv-
+ qualification signature of type T1 is a proper subset of the cv-
+ qualification signature of type T2 */
+ if (TREE_CODE (ics1) == QUAL_CONV
+ && TREE_CODE (ics2) == QUAL_CONV
+ && comptypes (from_type1, from_type2, 1))
+ return comp_cv_qual_signature (to_type1, to_type2);
- /* Can't use alloca here, since result might be
- passed to calling function. */
- cp->h_len = parmlength;
- cp->harshness = (struct harshness_code *)
- oballoc ((parmlength + 1) * sizeof (struct harshness_code));
+ /* [over.ics.rank]
+
+ --S1 and S2 are reference bindings (_dcl.init.ref_), and the
+ types to which the references refer are the same type except for
+ top-level cv-qualifiers, and the type to which the reference
+ initialized by S2 refers is more cv-qualified than the type to
+ which the reference initialized by S1 refers */
+
+ if (ref_binding1 && ref_binding2
+ && comptypes (TYPE_MAIN_VARIANT (to_type1),
+ TYPE_MAIN_VARIANT (to_type2), 1))
+ return comp_cv_qualification (target_type2, target_type1);
- compute_conversion_costs (function, parms, cp, parmlength);
+ /* Neither conversion sequence is better than the other. */
+ return 0;
+}
- /* Make sure this is clear as well. */
- cp->h.int_penalty += template_cost;
+/* The source type for this standard conversion sequence. */
- if ((cp[0].h.code & EVIL_CODE) == 0)
- {
- cp[1].h.code = EVIL_CODE;
- cp++;
- }
+static tree
+source_type (t)
+ tree t;
+{
+ for (;; t = TREE_OPERAND (t, 0))
+ {
+ if (TREE_CODE (t) == USER_CONV
+ || TREE_CODE (t) == AMBIG_CONV
+ || TREE_CODE (t) == IDENTITY_CONV)
+ return TREE_TYPE (t);
+ }
+ my_friendly_abort (1823);
+}
+
+/* Note a warning about preferring WINNER to LOSER. We do this by storing
+ a pointer to LOSER and re-running joust to produce the warning if WINNER
+ is actually used. */
+
+static void
+add_warning (winner, loser)
+ struct z_candidate *winner, *loser;
+{
+ winner->warnings = expr_tree_cons (NULL_PTR,
+ build_expr_ptr_wrapper (loser),
+ winner->warnings);
+}
+
+/* Compare two candidates for overloading as described in
+ [over.match.best]. Return values:
+
+ 1: cand1 is better than cand2
+ -1: cand2 is better than cand1
+ 0: cand1 and cand2 are indistinguishable */
+
+static int
+joust (cand1, cand2, warn)
+ struct z_candidate *cand1, *cand2;
+ int warn;
+{
+ int winner = 0;
+ int i, off1 = 0, off2 = 0, len;
+
+ /* Candidates that involve bad conversions are always worse than those
+ that don't. */
+ if (cand1->viable > cand2->viable)
+ return 1;
+ if (cand1->viable < cand2->viable)
+ return -1;
+
+ /* a viable function F1
+ is defined to be a better function than another viable function F2 if
+ for all arguments i, ICSi(F1) is not a worse conversion sequence than
+ ICSi(F2), and then */
+
+ /* for some argument j, ICSj(F1) is a better conversion sequence than
+ ICSj(F2) */
+
+ /* For comparing static and non-static member functions, we ignore the
+ implicit object parameter of the non-static function. The WP says to
+ pretend that the static function has an object parm, but that won't
+ work with operator overloading. */
+ len = TREE_VEC_LENGTH (cand1->convs);
+ if (len != TREE_VEC_LENGTH (cand2->convs))
+ {
+ if (DECL_STATIC_FUNCTION_P (cand1->fn)
+ && ! DECL_STATIC_FUNCTION_P (cand2->fn))
+ off2 = 1;
+ else if (! DECL_STATIC_FUNCTION_P (cand1->fn)
+ && DECL_STATIC_FUNCTION_P (cand2->fn))
+ {
+ off1 = 1;
+ --len;
}
+ else
+ my_friendly_abort (42);
}
- if (cp - candidates)
+ for (i = 0; i < len; ++i)
{
- tree rval = error_mark_node;
+ tree t1 = TREE_VEC_ELT (cand1->convs, i+off1);
+ tree t2 = TREE_VEC_ELT (cand2->convs, i+off2);
+ int comp = compare_ics (t1, t2);
- /* Leave marker. */
- cp[0].h.code = EVIL_CODE;
- if (cp - candidates > 1)
+ if (comp != 0)
{
- struct candidate *best_cp
- = ideal_candidate (NULL_TREE, candidates,
- cp - candidates, parms, parmlength);
- if (best_cp == (struct candidate *)0)
+ if (warn_sign_promo
+ && ICS_RANK (t1) + ICS_RANK (t2) == STD_RANK + PROMO_RANK
+ && TREE_CODE (t1) == STD_CONV
+ && TREE_CODE (t2) == STD_CONV
+ && TREE_CODE (TREE_TYPE (t1)) == INTEGER_TYPE
+ && TREE_CODE (TREE_TYPE (t2)) == INTEGER_TYPE
+ && (TYPE_PRECISION (TREE_TYPE (t1))
+ == TYPE_PRECISION (TREE_TYPE (t2)))
+ && (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (t1, 0)))
+ || (TREE_CODE (TREE_TYPE (TREE_OPERAND (t1, 0)))
+ == ENUMERAL_TYPE)))
{
- if (flags & LOOKUP_COMPLAIN)
+ tree type = TREE_TYPE (TREE_OPERAND (t1, 0));
+ tree type1, type2;
+ struct z_candidate *w, *l;
+ if (comp > 0)
+ type1 = TREE_TYPE (t1), type2 = TREE_TYPE (t2),
+ w = cand1, l = cand2;
+ else
+ type1 = TREE_TYPE (t2), type2 = TREE_TYPE (t1),
+ w = cand2, l = cand1;
+
+ if (warn)
{
- cp_error ("call of overloaded `%D' is ambiguous", fnname);
- print_n_candidates (candidates, cp - candidates);
+ cp_warning ("passing `%T' chooses `%T' over `%T'",
+ type, type1, type2);
+ cp_warning (" in call to `%D'", w->fn);
}
- return error_mark_node;
+ else
+ add_warning (w, l);
+ }
+
+ if (winner && comp != winner)
+ {
+ winner = 0;
+ goto tweak;
+ }
+ winner = comp;
+ }
+ }
+
+ /* warn about confusing overload resolution for user-defined conversions,
+ either between a constructor and a conversion op, or between two
+ conversion ops. */
+ if (winner && cand1->second_conv
+ && ((DECL_CONSTRUCTOR_P (cand1->fn)
+ != DECL_CONSTRUCTOR_P (cand2->fn))
+ /* Don't warn if the two conv ops convert to the same type... */
+ || (! DECL_CONSTRUCTOR_P (cand1->fn)
+ && ! comptypes (TREE_TYPE (cand1->second_conv),
+ TREE_TYPE (cand2->second_conv), 1))))
+ {
+ int comp = compare_ics (cand1->second_conv, cand2->second_conv);
+ if (comp != winner)
+ {
+ struct z_candidate *w, *l;
+ if (winner == 1)
+ w = cand1, l = cand2;
+ else
+ w = cand2, l = cand1;
+ if (warn)
+ {
+ tree source = source_type (TREE_VEC_ELT (w->convs, 0));
+ if (! DECL_CONSTRUCTOR_P (w->fn))
+ source = TREE_TYPE (source);
+ cp_warning ("choosing `%D' over `%D'", w->fn, l->fn);
+ cp_warning (" for conversion from `%T' to `%T'",
+ source, TREE_TYPE (w->second_conv));
+ cp_warning (" because conversion sequence for the argument is better");
}
else
- rval = best_cp->function;
+ add_warning (w, l);
}
+ }
+
+ if (winner)
+ return winner;
+
+ /* or, if not that,
+ F1 is a non-template function and F2 is a template function */
+
+ if (! cand1->template && cand2->template)
+ return 1;
+ else if (cand1->template && ! cand2->template)
+ return -1;
+ else if (cand1->template && cand2->template)
+ winner = more_specialized
+ (TI_TEMPLATE (cand1->template), TI_TEMPLATE (cand2->template),
+ NULL_TREE);
+
+ /* or, if not that,
+ the context is an initialization by user-defined conversion (see
+ _dcl.init_ and _over.match.user_) and the standard conversion
+ sequence from the return type of F1 to the destination type (i.e.,
+ the type of the entity being initialized) is a better conversion
+ sequence than the standard conversion sequence from the return type
+ of F2 to the destination type. */
+
+ if (! winner && cand1->second_conv)
+ winner = compare_ics (cand1->second_conv, cand2->second_conv);
+
+ /* If the built-in candidates are the same, arbitrarily pick one. */
+ if (! winner && cand1->fn == cand2->fn
+ && TREE_CODE (cand1->fn) == IDENTIFIER_NODE)
+ {
+ for (i = 0; i < len; ++i)
+ if (! comptypes (TREE_TYPE (TREE_VEC_ELT (cand1->convs, i)),
+ TREE_TYPE (TREE_VEC_ELT (cand2->convs, i)), 1))
+ break;
+ if (i == TREE_VEC_LENGTH (cand1->convs))
+ return 1;
+
+ /* Kludge around broken overloading rules whereby
+ Integer a, b; test ? a : b; is ambiguous, since there's a builtin
+ that takes references and another that takes values. */
+ if (cand1->fn == ansi_opname[COND_EXPR])
+ {
+ tree c1 = TREE_VEC_ELT (cand1->convs, 1);
+ tree c2 = TREE_VEC_ELT (cand2->convs, 1);
+ tree t1 = strip_top_quals (non_reference (TREE_TYPE (c1)));
+ tree t2 = strip_top_quals (non_reference (TREE_TYPE (c2)));
+
+ if (comptypes (t1, t2, 1))
+ {
+ if (TREE_CODE (c1) == REF_BIND && TREE_CODE (c2) != REF_BIND)
+ return 1;
+ if (TREE_CODE (c1) != REF_BIND && TREE_CODE (c2) == REF_BIND)
+ return -1;
+ }
+ }
+ }
+
+tweak:
+
+ /* Extension: If the worst conversion for one candidate is worse than the
+ worst conversion for the other, take the first. */
+ if (! winner && ! pedantic)
+ {
+ int rank1 = IDENTITY_RANK, rank2 = IDENTITY_RANK;
+
+ for (i = 0; i < len; ++i)
+ {
+ if (ICS_RANK (TREE_VEC_ELT (cand1->convs, i+off1)) > rank1)
+ rank1 = ICS_RANK (TREE_VEC_ELT (cand1->convs, i+off1));
+ if (ICS_RANK (TREE_VEC_ELT (cand2->convs, i+off2)) > rank2)
+ rank2 = ICS_RANK (TREE_VEC_ELT (cand2->convs, i+off2));
+ }
+
+ if (rank1 < rank2)
+ return 1;
+ if (rank1 > rank2)
+ return -1;
+ }
+
+ return winner;
+}
+
+/* Given a list of candidates for overloading, find the best one, if any.
+ This algorithm has a worst case of O(2n) (winner is last), and a best
+ case of O(n/2) (totally ambiguous); much better than a sorting
+ algorithm. */
+
+static struct z_candidate *
+tourney (candidates)
+ struct z_candidate *candidates;
+{
+ struct z_candidate *champ = candidates, *challenger;
+ int fate;
+ int champ_compared_to_predecessor = 0;
+
+ /* Walk through the list once, comparing each current champ to the next
+ candidate, knocking out a candidate or two with each comparison. */
+
+ for (challenger = champ->next; challenger; )
+ {
+ fate = joust (champ, challenger, 0);
+ if (fate == 1)
+ challenger = challenger->next;
else
{
- cp -= 1;
- if (cp->h.code & EVIL_CODE)
+ if (fate == 0)
{
- if (flags & LOOKUP_COMPLAIN)
- error ("type conversion ambiguous");
+ champ = challenger->next;
+ if (champ == 0)
+ return 0;
+ champ_compared_to_predecessor = 0;
}
else
- rval = cp->function;
+ {
+ champ = challenger;
+ champ_compared_to_predecessor = 1;
+ }
+
+ challenger = champ->next;
}
+ }
- if (final_cp)
- return rval;
+ /* Make sure the champ is better than all the candidates it hasn't yet
+ been compared to. */
- return buildxxx ? build_function_call_real (rval, parms, 0, flags)
- : build_function_call_real (rval, parms, 1, flags);
+ for (challenger = candidates;
+ challenger != champ
+ && !(champ_compared_to_predecessor && challenger->next == champ);
+ challenger = challenger->next)
+ {
+ fate = joust (champ, challenger, 0);
+ if (fate != 1)
+ return 0;
}
- if (flags & LOOKUP_SPECULATIVELY)
- return NULL_TREE;
-
- if (flags & LOOKUP_COMPLAIN)
- report_type_mismatch (cp, parms, "function",
- decl_as_string (cp->function, 1));
-
- return error_mark_node;
+ return champ;
}
-tree
-build_overload_call (fnname, parms, flags, final_cp)
- tree fnname, parms;
- int flags;
- struct candidate *final_cp;
+int
+can_convert (to, from)
+ tree to, from;
{
- return build_overload_call_real (fnname, parms, flags, final_cp, 0);
+ tree t = implicit_conversion (to, from, NULL_TREE, LOOKUP_NORMAL);
+ return (t && ! ICS_BAD_FLAG (t));
}
-tree
-build_overload_call_maybe (fnname, parms, flags, final_cp)
- tree fnname, parms;
- int flags;
- struct candidate *final_cp;
+int
+can_convert_arg (to, from, arg)
+ tree to, from, arg;
{
- return build_overload_call_real (fnname, parms, flags, final_cp, 1);
+ tree t = implicit_conversion (to, from, arg, LOOKUP_NORMAL);
+ return (t && ! ICS_BAD_FLAG (t));
}
diff --git a/contrib/gcc/cp/class.c b/contrib/gcc/cp/class.c
index e289304..8a61bf8 100644
--- a/contrib/gcc/cp/class.c
+++ b/contrib/gcc/cp/class.c
@@ -1,5 +1,5 @@
/* Functions related to building classes and their related objects.
- Copyright (C) 1987, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -20,15 +20,16 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* High-level class interface. */
+/* High-level class interface. */
#include "config.h"
+#include "system.h"
#include "tree.h"
-#include <stdio.h>
#include "cp-tree.h"
#include "flags.h"
#include "rtl.h"
#include "output.h"
+#include "toplev.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
@@ -37,7 +38,7 @@ Boston, MA 02111-1307, USA. */
extern struct obstack permanent_obstack;
/* This is how we tell when two virtual member functions are really the
- same. */
+ same. */
#define SAME_FN(FN1DECL, FN2DECL) (DECL_ASSEMBLER_NAME (FN1DECL) == DECL_ASSEMBLER_NAME (FN2DECL))
extern void set_class_shadows PROTO ((tree));
@@ -72,7 +73,9 @@ struct class_level
int unused;
};
-tree current_class_decl, C_C_D; /* PARM_DECL: the class instance variable */
+/* The current_class_ptr is the pointer to the current class.
+ current_class_ref is the actual current class. */
+tree current_class_ptr, current_class_ref;
/* The following two can be derived from the previous one */
tree current_class_name; /* IDENTIFIER_NODE: name of current class */
@@ -80,26 +83,76 @@ tree current_class_type; /* _TYPE: the type of the current class */
tree previous_class_type; /* _TYPE: the previous type that was a class */
tree previous_class_values; /* TREE_LIST: copy of the class_shadowed list
when leaving an outermost class scope. */
+
+struct base_info;
+
static tree get_vfield_name PROTO((tree));
-tree the_null_vtable_entry;
+static void finish_struct_anon PROTO((tree));
+static tree build_vbase_pointer PROTO((tree, tree));
+static int complete_type_p PROTO((tree));
+static tree build_vtable_entry PROTO((tree, tree));
+static tree get_vtable_name PROTO((tree));
+static tree get_derived_offset PROTO((tree, tree));
+static tree get_basefndecls PROTO((tree, tree));
+static void set_rtti_entry PROTO((tree, tree, tree));
+static tree build_vtable PROTO((tree, tree));
+static void prepare_fresh_vtable PROTO((tree, tree));
+static void fixup_vtable_deltas1 PROTO((tree, tree));
+static void fixup_vtable_deltas PROTO((tree, int, tree));
+static void grow_method PROTO((tree, tree *));
+static void finish_vtbls PROTO((tree, int, tree));
+static void modify_vtable_entry PROTO((tree, tree, tree));
+static tree get_vtable_entry_n PROTO((tree, unsigned HOST_WIDE_INT));
+static void add_virtual_function PROTO((tree *, tree *, int *, tree, tree));
+static tree delete_duplicate_fields_1 PROTO((tree, tree));
+static void delete_duplicate_fields PROTO((tree));
+static void finish_struct_bits PROTO((tree, int));
+static int alter_access PROTO((tree, tree, tree, tree));
+static void handle_using_decl PROTO((tree, tree, tree, tree));
+static int overrides PROTO((tree, tree));
+static int strictly_overrides PROTO((tree, tree));
+static void merge_overrides PROTO((tree, tree, int, tree));
+static void override_one_vtable PROTO((tree, tree, tree));
+static void mark_overriders PROTO((tree, tree));
+static void check_for_override PROTO((tree, tree));
+static tree maybe_fixup_vptrs PROTO((tree, tree, tree));
+static tree get_class_offset_1 PROTO((tree, tree, tree, tree, tree));
+static tree get_class_offset PROTO((tree, tree, tree, tree));
+static void modify_one_vtable PROTO((tree, tree, tree, tree));
+static void modify_all_vtables PROTO((tree, tree, tree));
+static void modify_all_direct_vtables PROTO((tree, int, tree, tree,
+ tree));
+static void modify_all_indirect_vtables PROTO((tree, int, int, tree,
+ tree, tree));
+static void build_class_init_list PROTO((tree));
+static int finish_base_struct PROTO((tree, struct base_info *));
/* Way of stacking language names. */
tree *current_lang_base, *current_lang_stack;
int current_lang_stacksize;
/* Names of languages we recognize. */
-tree lang_name_c, lang_name_cplusplus;
+tree lang_name_c, lang_name_cplusplus, lang_name_java;
tree current_lang_name;
-char *dont_allow_type_definitions;
-
/* When layout out an aggregate type, the size of the
basetypes (virtual and non-virtual) is passed to layout_record
via this node. */
static tree base_layout_decl;
+/* Constants used for access control. */
+tree access_default_node; /* 0 */
+tree access_public_node; /* 1 */
+tree access_protected_node; /* 2 */
+tree access_private_node; /* 3 */
+tree access_default_virtual_node; /* 4 */
+tree access_public_virtual_node; /* 5 */
+tree access_protected_virtual_node; /* 6 */
+tree access_private_virtual_node; /* 7 */
+
/* Variables shared between class.c and call.c. */
+#ifdef GATHER_STATISTICS
int n_vtables = 0;
int n_vtable_entries = 0;
int n_vtable_searches = 0;
@@ -108,9 +161,11 @@ int n_convert_harshness = 0;
int n_compute_conversion_costs = 0;
int n_build_method_call = 0;
int n_inner_fields_searched = 0;
+#endif
/* Virtual baseclass things. */
-tree
+
+static tree
build_vbase_pointer (exp, type)
tree exp, type;
{
@@ -118,12 +173,13 @@ build_vbase_pointer (exp, type)
name = (char *) alloca (TYPE_NAME_LENGTH (type) + sizeof (VBASE_NAME) + 1);
sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (type));
- return build_component_ref (exp, get_identifier (name), 0, 0);
+ return build_component_ref (exp, get_identifier (name), NULL_TREE, 0);
}
/* Is the type of the EXPR, the complete type of the object?
- If we are going to be wrong, we must be conservative, and return 0. */
-int
+ If we are going to be wrong, we must be conservative, and return 0. */
+
+static int
complete_type_p (expr)
tree expr;
{
@@ -143,20 +199,20 @@ complete_type_p (expr)
case CALL_EXPR:
if (! TREE_HAS_CONSTRUCTOR (expr))
break;
- /* fall through... */
+ /* fall through... */
case VAR_DECL:
case FIELD_DECL:
if (TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
&& IS_AGGR_TYPE (TREE_TYPE (TREE_TYPE (expr)))
&& TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type)
return 1;
- /* fall through... */
+ /* fall through... */
case TARGET_EXPR:
case PARM_DECL:
if (IS_AGGR_TYPE (TREE_TYPE (expr))
&& TYPE_MAIN_VARIANT (TREE_TYPE (expr)) == type)
return 1;
- /* fall through... */
+ /* fall through... */
case PLUS_EXPR:
default:
break;
@@ -174,6 +230,7 @@ complete_type_p (expr)
TYPE is the type we want this path to have on exit.
ALIAS_THIS is non-zero if EXPR in an expression involving `this'. */
+
tree
build_vbase_path (code, type, expr, path, alias_this)
enum tree_code code;
@@ -183,21 +240,28 @@ build_vbase_path (code, type, expr, path, alias_this)
register int changed = 0;
tree last = NULL_TREE, last_virtual = NULL_TREE;
int nonnull = 0;
- int fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
+ int fixed_type_p;
tree null_expr = 0, nonnull_expr;
tree basetype;
tree offset = integer_zero_node;
+ if (BINFO_INHERITANCE_CHAIN (path) == NULL_TREE)
+ return build1 (NOP_EXPR, type, expr);
+
if (nonnull == 0 && (alias_this && flag_this_is_variable <= 0))
nonnull = 1;
+#if 0
/* We need additional logic to convert back to the unconverted type
(the static type of the complete object), and then convert back
to the type we want. Until that is done, or until we can
recognize when that is, we cannot do the short cut logic. (mrs) */
+ fixed_type_p = resolves_to_fixed_type_p (expr, &nonnull);
+#else
/* Do this, until we can undo any previous conversions. See net35.C
- for a testcase. */
+ for a testcase. */
fixed_type_p = complete_type_p (expr);
+#endif
if (!fixed_type_p && TREE_SIDE_EFFECTS (expr))
expr = save_expr (expr);
@@ -207,6 +271,7 @@ build_vbase_path (code, type, expr, path, alias_this)
{
tree reverse_path = NULL_TREE;
+ push_expression_obstack ();
while (path)
{
tree r = copy_node (path);
@@ -215,6 +280,7 @@ build_vbase_path (code, type, expr, path, alias_this)
path = BINFO_INHERITANCE_CHAIN (path);
}
path = reverse_path;
+ pop_obstacks ();
}
basetype = BINFO_TYPE (path);
@@ -230,11 +296,10 @@ build_vbase_path (code, type, expr, path, alias_this)
if (changed)
{
- extern int flag_assume_nonnull_objects;
tree ind;
/* We already check for ambiguous things in the caller, just
- find a path. */
+ find a path. */
if (last)
{
tree binfo = get_binfo (last, TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (nonnull_expr))), 0);
@@ -278,7 +343,8 @@ build_vbase_path (code, type, expr, path, alias_this)
if (null_expr)
{
TREE_OPERAND (expr, 2) = nonnull_expr;
- TREE_TYPE (TREE_OPERAND (expr, 1)) = TREE_TYPE (nonnull_expr);
+ TREE_TYPE (expr) = TREE_TYPE (TREE_OPERAND (expr, 1))
+ = TREE_TYPE (nonnull_expr);
}
else
expr = nonnull_expr;
@@ -310,8 +376,11 @@ build_vbase_path (code, type, expr, path, alias_this)
if (TREE_INT_CST_LOW (offset))
{
/* Bash types to make the backend happy. */
- offset = convert (type, offset);
+ offset = cp_convert (type, offset);
+#if 0
+ /* This shouldn't be necessary. (mrs) */
expr = build1 (NOP_EXPR, type, expr);
+#endif
/* For multiple inheritance: if `this' can be set by any
function, then it could be 0 on entry to any function.
@@ -349,27 +418,20 @@ build_vbase_path (code, type, expr, path, alias_this)
/* Virtual function things. */
-/* Virtual functions to be dealt with after laying out our base
- classes. We do all overrides after we layout virtual base classes.
- */
-static tree pending_hard_virtuals;
-static int doing_hard_virtuals;
-
/* Build an entry in the virtual function table.
DELTA is the offset for the `this' pointer.
PFN is an ADDR_EXPR containing a pointer to the virtual function.
Note that the index (DELTA2) in the virtual function table
is always 0. */
-tree
+
+static tree
build_vtable_entry (delta, pfn)
tree delta, pfn;
{
-
if (flag_vtable_thunks)
{
HOST_WIDE_INT idelta = TREE_INT_CST_LOW (delta);
- extern tree make_thunk ();
- if (idelta)
+ if (idelta && ! DECL_ABSTRACT_VIRTUAL_P (TREE_OPERAND (pfn, 0)))
{
pfn = build1 (ADDR_EXPR, vtable_entry_type,
make_thunk (pfn, idelta));
@@ -384,25 +446,23 @@ build_vtable_entry (delta, pfn)
else
{
extern int flag_huge_objects;
- tree elems = tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, integer_zero_node,
- build_tree_list (NULL_TREE, pfn)));
+ tree elems = expr_tree_cons (NULL_TREE, delta,
+ expr_tree_cons (NULL_TREE, integer_zero_node,
+ build_expr_list (NULL_TREE, pfn)));
tree entry = build (CONSTRUCTOR, vtable_entry_type, NULL_TREE, elems);
- /* DELTA is constructed by `size_int', which means it may be an
- unsigned quantity on some platforms. Therefore, we cannot use
- `int_fits_type_p', because when DELTA is really negative,
- `force_fit_type' will make it look like a very large number. */
-
- if ((TREE_INT_CST_LOW (TYPE_MAX_VALUE (delta_type_node))
- < TREE_INT_CST_LOW (delta))
- || (TREE_INT_CST_LOW (delta)
- < TREE_INT_CST_LOW (TYPE_MIN_VALUE (delta_type_node))))
- if (flag_huge_objects)
- sorry ("object size exceeds built-in limit for virtual function table implementation");
- else
- sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
+ /* DELTA used to be constructed by `size_int' and/or size_binop,
+ which caused overflow problems when it was negative. That should
+ be fixed now. */
+ if (! int_fits_type_p (delta, delta_type_node))
+ {
+ if (flag_huge_objects)
+ sorry ("object size exceeds built-in limit for virtual function table implementation");
+ else
+ sorry ("object size exceeds normal limit for virtual function table implementation, recompile all source and use -fhuge-objects");
+ }
+
TREE_CONSTANT (entry) = 1;
TREE_STATIC (entry) = 1;
TREE_READONLY (entry) = 1;
@@ -416,22 +476,21 @@ build_vtable_entry (delta, pfn)
}
/* Given an object INSTANCE, return an expression which yields the
- virtual function corresponding to INDEX. There are many special
- cases for INSTANCE which we take care of here, mainly to avoid
- creating extra tree nodes when we don't have to. */
+ virtual function vtable element corresponding to INDEX. There are
+ many special cases for INSTANCE which we take care of here, mainly
+ to avoid creating extra tree nodes when we don't have to. */
+
tree
-build_vfn_ref (ptr_to_instptr, instance, idx)
- tree *ptr_to_instptr, instance;
- tree idx;
+build_vtbl_ref (instance, idx)
+ tree instance, idx;
{
- extern int building_cleanup;
tree vtbl, aref;
tree basetype = TREE_TYPE (instance);
if (TREE_CODE (basetype) == REFERENCE_TYPE)
basetype = TREE_TYPE (basetype);
- if (instance == C_C_D)
+ if (instance == current_class_ref)
vtbl = build_indirect_ref (build_vfield_ref (instance, basetype),
NULL_PTR);
else
@@ -479,34 +538,53 @@ build_vfn_ref (ptr_to_instptr, instance, idx)
assemble_external (vtbl);
aref = build_array_ref (vtbl, idx);
- /* Save the intermediate result in a SAVE_EXPR so we don't have to
- compute each component of the virtual function pointer twice. */
- if (!building_cleanup && TREE_CODE (aref) == INDIRECT_REF)
- TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
+ return aref;
+}
+/* Given an object INSTANCE, return an expression which yields the
+ virtual function corresponding to INDEX. There are many special
+ cases for INSTANCE which we take care of here, mainly to avoid
+ creating extra tree nodes when we don't have to. */
+
+tree
+build_vfn_ref (ptr_to_instptr, instance, idx)
+ tree *ptr_to_instptr, instance;
+ tree idx;
+{
+ tree aref = build_vtbl_ref (instance, idx);
+
+ /* When using thunks, there is no extra delta, and we get the pfn
+ directly. */
if (flag_vtable_thunks)
return aref;
- else
+
+ if (ptr_to_instptr)
{
- if (ptr_to_instptr)
- *ptr_to_instptr
- = build (PLUS_EXPR, TREE_TYPE (*ptr_to_instptr),
- *ptr_to_instptr,
- convert (ptrdiff_type_node,
- build_component_ref (aref, delta_identifier, 0, 0)));
- return build_component_ref (aref, pfn_identifier, 0, 0);
+ /* Save the intermediate result in a SAVE_EXPR so we don't have to
+ compute each component of the virtual function pointer twice. */
+ if (TREE_CODE (aref) == INDIRECT_REF)
+ TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
+
+ *ptr_to_instptr
+ = build (PLUS_EXPR, TREE_TYPE (*ptr_to_instptr),
+ *ptr_to_instptr,
+ cp_convert (ptrdiff_type_node,
+ build_component_ref (aref, delta_identifier, NULL_TREE, 0)));
}
+
+ return build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
}
/* Return the name of the virtual function table (as an IDENTIFIER_NODE)
for the given TYPE. */
+
static tree
get_vtable_name (type)
tree type;
{
tree type_id = build_typename_overload (type);
- char *buf = (char *)alloca (strlen (VTABLE_NAME_FORMAT)
- + IDENTIFIER_LENGTH (type_id) + 2);
+ char *buf = (char *) alloca (strlen (VTABLE_NAME_FORMAT)
+ + IDENTIFIER_LENGTH (type_id) + 2);
char *ptr = IDENTIFIER_POINTER (type_id);
int i;
for (i = 0; ptr[i] == OPERATOR_TYPENAME_FORMAT[i]; i++) ;
@@ -522,10 +600,79 @@ get_vtable_name (type)
return get_identifier (buf);
}
+/* Return the offset to the main vtable for a given base BINFO. */
+
+tree
+get_vfield_offset (binfo)
+ tree binfo;
+{
+ tree tmp
+ = size_binop (FLOOR_DIV_EXPR,
+ DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))),
+ size_int (BITS_PER_UNIT));
+ tmp = convert (sizetype, tmp);
+ return size_binop (PLUS_EXPR, tmp, BINFO_OFFSET (binfo));
+}
+
+/* Get the offset to the start of the original binfo that we derived
+ this binfo from. If we find TYPE first, return the offset only
+ that far. The shortened search is useful because the this pointer
+ on method calling is expected to point to a DECL_CONTEXT (fndecl)
+ object, and not a baseclass of it. */
+
+static tree
+get_derived_offset (binfo, type)
+ tree binfo, type;
+{
+ tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
+ tree offset2;
+ int i;
+ while (BINFO_BASETYPES (binfo)
+ && (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
+ {
+ tree binfos = BINFO_BASETYPES (binfo);
+ if (BINFO_TYPE (binfo) == type)
+ break;
+ binfo = TREE_VEC_ELT (binfos, i);
+ }
+ offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
+ return size_binop (MINUS_EXPR, offset1, offset2);
+}
+
+/* Update the rtti info for this class. */
+
+static void
+set_rtti_entry (virtuals, offset, type)
+ tree virtuals, offset, type;
+{
+ tree vfn;
+
+ if (flag_rtti)
+ vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, get_tinfo_fn (type));
+ else
+ vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, size_zero_node);
+ TREE_CONSTANT (vfn) = 1;
+
+ if (! flag_vtable_thunks)
+ TREE_VALUE (virtuals) = build_vtable_entry (offset, vfn);
+ else
+ {
+ tree voff = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
+ TREE_CONSTANT (voff) = 1;
+
+ TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, voff);
+
+ /* The second slot is for the tdesc pointer when thunks are used. */
+ TREE_VALUE (TREE_CHAIN (virtuals))
+ = build_vtable_entry (integer_zero_node, vfn);
+ }
+}
+
/* Build a virtual function for type TYPE.
If BINFO is non-NULL, build the vtable starting with the initial
approximation that it is the same as the one which is the head of
the association list. */
+
static tree
build_vtable (binfo, type)
tree binfo, type;
@@ -535,8 +682,15 @@ build_vtable (binfo, type)
if (binfo)
{
+ tree offset;
+
virtuals = copy_list (BINFO_VIRTUALS (binfo));
decl = build_decl (VAR_DECL, name, TREE_TYPE (BINFO_VTABLE (binfo)));
+
+ /* Now do rtti stuff. */
+ offset = get_derived_offset (TYPE_BINFO (type), NULL_TREE);
+ offset = ssize_binop (MINUS_EXPR, integer_zero_node, offset);
+ set_rtti_entry (virtuals, offset, type);
}
else
{
@@ -552,12 +706,14 @@ build_vtable (binfo, type)
/* Set TREE_PUBLIC and TREE_EXTERN as appropriate. */
import_export_vtable (decl, type, 0);
- IDENTIFIER_GLOBAL_VALUE (name) = decl = pushdecl_top_level (decl);
+ decl = pushdecl_top_level (decl);
+ SET_IDENTIFIER_GLOBAL_VALUE (name, decl);
/* Initialize the association list for this type, based
on our first approximation. */
TYPE_BINFO_VTABLE (type) = decl;
TYPE_BINFO_VIRTUALS (type) = virtuals;
+ DECL_ARTIFICIAL (decl) = 1;
TREE_STATIC (decl) = 1;
#ifndef WRITABLE_VTABLES
/* Make them READONLY by default. (mrs) */
@@ -578,124 +734,124 @@ build_vtable (binfo, type)
return decl;
}
-/* Given a base type PARENT, and a derived type TYPE, build
- a name which distinguishes exactly the PARENT member of TYPE's type.
-
- FORMAT is a string which controls how sprintf formats the name
- we have generated.
+extern tree signed_size_zero_node;
- For example, given
-
- class A; class B; class C : A, B;
+/* Give TYPE a new virtual function table which is initialized
+ with a skeleton-copy of its original initialization. The only
+ entry that changes is the `delta' entry, so we can really
+ share a lot of structure.
- it is possible to distinguish "A" from "C's A". And given
+ FOR_TYPE is the derived type which caused this table to
+ be needed.
- class L;
- class A : L; class B : L; class C : A, B;
+ BINFO is the type association which provided TYPE for FOR_TYPE.
- it is possible to distinguish "L" from "A's L", and also from
- "C's L from A".
+ The order in which vtables are built (by calling this function) for
+ an object must remain the same, otherwise a binary incompatibility
+ can result. */
- Make sure to use the DECL_ASSEMBLER_NAME of the TYPE_NAME of the
- type, as template have DECL_NAMEs like: X<int>, whereas the
- DECL_ASSEMBLER_NAME is set to be something the assembler can handle.
- */
-static tree
-build_type_pathname (format, parent, type)
- char *format;
- tree parent, type;
+static void
+prepare_fresh_vtable (binfo, for_type)
+ tree binfo, for_type;
{
- extern struct obstack temporary_obstack;
- char *first, *base, *name;
+ tree basetype;
+ tree orig_decl = BINFO_VTABLE (binfo);
+ tree name;
+ tree new_decl;
+ tree offset;
+ tree path = binfo;
+ char *buf, *buf2;
+ char joiner = '_';
int i;
- tree id;
-
- parent = TYPE_MAIN_VARIANT (parent);
- /* Remember where to cut the obstack to. */
- first = obstack_base (&temporary_obstack);
-
- /* Put on TYPE+PARENT. */
- obstack_grow (&temporary_obstack,
- TYPE_ASSEMBLER_NAME_STRING (type),
- TYPE_ASSEMBLER_NAME_LENGTH (type));
#ifdef JOINER
- obstack_1grow (&temporary_obstack, JOINER);
-#else
- obstack_1grow (&temporary_obstack, '_');
+ joiner = JOINER;
#endif
- obstack_grow0 (&temporary_obstack,
- TYPE_ASSEMBLER_NAME_STRING (parent),
- TYPE_ASSEMBLER_NAME_LENGTH (parent));
- i = obstack_object_size (&temporary_obstack);
- base = obstack_base (&temporary_obstack);
- obstack_finish (&temporary_obstack);
-
- /* Put on FORMAT+TYPE+PARENT. */
- obstack_blank (&temporary_obstack, strlen (format) + i + 1);
- name = obstack_base (&temporary_obstack);
- sprintf (name, format, base);
- id = get_identifier (name);
- obstack_free (&temporary_obstack, first);
-
- return id;
-}
-/* Update the rtti info for this class. */
-static void
-set_rtti_entry (virtuals, offset, type)
- tree virtuals, offset, type;
-{
- if (! flag_vtable_thunks)
- TREE_VALUE (virtuals)
- = build_vtable_entry (offset,
- (flag_rtti
- ? build_t_desc (type, 0)
- : integer_zero_node));
- else
+ basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (binfo));
+
+ buf2 = TYPE_ASSEMBLER_NAME_STRING (basetype);
+ i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1;
+
+ /* We know that the vtable that we are going to create doesn't exist
+ yet in the global namespace, and when we finish, it will be
+ pushed into the global namespace. In complex MI hierarchies, we
+ have to loop while the name we are thinking of adding is globally
+ defined, adding more name components to the vtable name as we
+ loop, until the name is unique. This is because in complex MI
+ cases, we might have the same base more than once. This means
+ that the order in which this function is called for vtables must
+ remain the same, otherwise binary compatibility can be
+ compromised. */
+
+ while (1)
{
- tree vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, offset);
- TREE_CONSTANT (vfn) = 1;
+ char *buf1 = (char *) alloca (TYPE_ASSEMBLER_NAME_LENGTH (for_type)
+ + 1 + i);
+ char *new_buf2;
- TREE_VALUE (virtuals)
- = build_vtable_entry (integer_zero_node, vfn);
- /* The second slot is for the tdesc pointer when thunks are used. */
- vfn = flag_rtti
- ? build_t_desc (type, 0)
- : integer_zero_node;
- vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, vfn);
- TREE_CONSTANT (vfn) = 1;
+ sprintf (buf1, "%s%c%s", TYPE_ASSEMBLER_NAME_STRING (for_type), joiner,
+ buf2);
+ buf = (char *) alloca (strlen (VTABLE_NAME_FORMAT) + strlen (buf1) + 1);
+ sprintf (buf, VTABLE_NAME_FORMAT, buf1);
+ name = get_identifier (buf);
- TREE_VALUE (TREE_CHAIN (virtuals))
- = build_vtable_entry (integer_zero_node, vfn);
- }
-}
+ /* If this name doesn't clash, then we can use it, otherwise
+ we add more to the name until it is unique. */
-/* Give TYPE a new virtual function table which is initialized
- with a skeleton-copy of its original initialization. The only
- entry that changes is the `delta' entry, so we can really
- share a lot of structure.
+ if (! IDENTIFIER_GLOBAL_VALUE (name))
+ break;
- FOR_TYPE is the derived type which caused this table to
- be needed.
+ /* Set values for next loop through, if the name isn't unique. */
- BINFO is the type association which provided TYPE for FOR_TYPE. */
-static void
-prepare_fresh_vtable (binfo, for_type)
- tree binfo, for_type;
-{
- tree basetype = BINFO_TYPE (binfo);
- tree orig_decl = BINFO_VTABLE (binfo);
- /* This name is too simplistic. We can have multiple basetypes for
- for_type, and we really want different names. (mrs) */
- tree name = build_type_pathname (VTABLE_NAME_FORMAT, basetype, for_type);
- tree new_decl = build_decl (VAR_DECL, name, TREE_TYPE (orig_decl));
- tree path, offset;
- int result;
+ path = BINFO_INHERITANCE_CHAIN (path);
+
+ /* We better not run out of stuff to make it unique. */
+ my_friendly_assert (path != NULL_TREE, 368);
+
+ basetype = TYPE_MAIN_VARIANT (BINFO_TYPE (path));
+
+ if (for_type == basetype)
+ {
+ /* If we run out of basetypes in the path, we have already
+ found created a vtable with that name before, we now
+ resort to tacking on _%d to distinguish them. */
+ int j = 2;
+ i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1 + i + 1 + 3;
+ buf1 = (char *) alloca (i);
+ do {
+ sprintf (buf1, "%s%c%s%c%d",
+ TYPE_ASSEMBLER_NAME_STRING (basetype), joiner,
+ buf2, joiner, j);
+ buf = (char *) alloca (strlen (VTABLE_NAME_FORMAT)
+ + strlen (buf1) + 1);
+ sprintf (buf, VTABLE_NAME_FORMAT, buf1);
+ name = get_identifier (buf);
+
+ /* If this name doesn't clash, then we can use it,
+ otherwise we add something different to the name until
+ it is unique. */
+ } while (++j <= 999 && IDENTIFIER_GLOBAL_VALUE (name));
+
+ /* Hey, they really like MI don't they? Increase the 3
+ above to 6, and the 999 to 999999. :-) */
+ my_friendly_assert (j <= 999, 369);
+ break;
+ }
+
+ i = TYPE_ASSEMBLER_NAME_LENGTH (basetype) + 1 + i;
+ new_buf2 = (char *) alloca (i);
+ sprintf (new_buf2, "%s%c%s",
+ TYPE_ASSEMBLER_NAME_STRING (basetype), joiner, buf2);
+ buf2 = new_buf2;
+ }
+
+ new_decl = build_decl (VAR_DECL, name, TREE_TYPE (orig_decl));
/* Remember which class this vtable is really for. */
DECL_CONTEXT (new_decl) = for_type;
+ DECL_ARTIFICIAL (new_decl) = 1;
TREE_STATIC (new_decl) = 1;
BINFO_VTABLE (binfo) = pushdecl_top_level (new_decl);
DECL_VIRTUAL_P (new_decl) = 1;
@@ -709,13 +865,23 @@ prepare_fresh_vtable (binfo, for_type)
BINFO_VIRTUALS (binfo) = copy_list (BINFO_VIRTUALS (binfo));
if (TREE_VIA_VIRTUAL (binfo))
- offset = BINFO_OFFSET (binfo_member (BINFO_TYPE (binfo),
- CLASSTYPE_VBASECLASSES (for_type)));
+ {
+ tree binfo1 = binfo_member (BINFO_TYPE (binfo),
+ CLASSTYPE_VBASECLASSES (for_type));
+
+ /* XXX - This should never happen, if it does, the caller should
+ ensure that the binfo is from for_type's binfos, not from any
+ base type's. We can remove all this code after a while. */
+ if (binfo1 != binfo)
+ warning ("internal inconsistency: binfo offset error for rtti");
+
+ offset = BINFO_OFFSET (binfo1);
+ }
else
offset = BINFO_OFFSET (binfo);
set_rtti_entry (BINFO_VIRTUALS (binfo),
- size_binop (MINUS_EXPR, integer_zero_node, offset),
+ ssize_binop (MINUS_EXPR, integer_zero_node, offset),
for_type);
#ifdef GATHER_STATISTICS
@@ -733,10 +899,12 @@ prepare_fresh_vtable (binfo, for_type)
SET_BINFO_NEW_VTABLE_MARKED (binfo);
}
+#if 0
/* Access the virtual function table entry that logically
contains BASE_FNDECL. VIRTUALS is the virtual function table's
initializer. We can run off the end, when dealing with virtual
destructors in MI situations, return NULL_TREE in that case. */
+
static tree
get_vtable_entry (virtuals, base_fndecl)
tree virtuals, base_fndecl;
@@ -757,6 +925,7 @@ get_vtable_entry (virtuals, base_fndecl)
}
return virtuals;
}
+#endif
/* Put new entry ENTRY into virtual function table initializer
VIRTUALS.
@@ -776,7 +945,7 @@ modify_vtable_entry (old_entry_in_list, new_entry, fndecl)
TREE_VALUE (old_entry_in_list) = new_entry;
/* Now assign virtual dispatch information, if unset. */
- /* We can dispatch this, through any overridden base function. */
+ /* We can dispatch this, through any overridden base function. */
if (TREE_CODE (DECL_VINDEX (fndecl)) != INTEGER_CST)
{
DECL_VINDEX (fndecl) = DECL_VINDEX (base_fndecl);
@@ -784,8 +953,9 @@ modify_vtable_entry (old_entry_in_list, new_entry, fndecl)
}
}
-/* Access the virtual function table entry i. VIRTUALS is the virtual
+/* Access the virtual function table entry N. VIRTUALS is the virtual
function table's initializer. */
+
static tree
get_vtable_entry_n (virtuals, n)
tree virtuals;
@@ -806,13 +976,17 @@ get_vtable_entry_n (virtuals, n)
HAS_VIRTUAL keeps track of how many virtuals there are in our main
vtable for the type, and we build upon the PENDING_VIRTUALS list
and return it. */
-static tree
-add_virtual_function (pending_virtuals, has_virtual, fndecl, t)
- tree pending_virtuals;
+
+static void
+add_virtual_function (pv, phv, has_virtual, fndecl, t)
+ tree *pv, *phv;
int *has_virtual;
tree fndecl;
- tree t; /* Structure type. */
+ tree t; /* Structure type. */
{
+ tree pending_virtuals = *pv;
+ tree pending_hard_virtuals = *phv;
+
/* FUNCTION_TYPEs and OFFSET_TYPEs no longer freely
convert to void *. Make such a conversion here. */
tree vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fndecl);
@@ -835,11 +1009,8 @@ add_virtual_function (pending_virtuals, has_virtual, fndecl, t)
{
tree entry;
- if (flag_rtti && *has_virtual == 0)
- {
- /* CLASSTYPE_RTTI is only used as a Boolean (NULL or not). */
- CLASSTYPE_RTTI (t) = integer_one_node;
- }
+ /* We remember that this was the base sub-object for rtti. */
+ CLASSTYPE_RTTI (t) = t;
/* If we are using thunks, use two slots at the front, one
for the offset pointer, one for the tdesc pointer. */
@@ -851,21 +1022,21 @@ add_virtual_function (pending_virtuals, has_virtual, fndecl, t)
/* Build a new INT_CST for this DECL_VINDEX. */
{
static tree index_table[256];
- tree index;
+ tree idx;
/* We skip a slot for the offset/tdesc entry. */
int i = ++(*has_virtual);
if (i >= 256 || index_table[i] == 0)
{
- index = build_int_2 (i, 0);
+ idx = build_int_2 (i, 0);
if (i < 256)
- index_table[i] = index;
+ index_table[i] = idx;
}
else
- index = index_table[i];
+ idx = index_table[i];
- /* Now assign virtual dispatch information. */
- DECL_VINDEX (fndecl) = index;
+ /* Now assign virtual dispatch information. */
+ DECL_VINDEX (fndecl) = idx;
DECL_CONTEXT (fndecl) = t;
}
entry = build_vtable_entry (integer_zero_node, vfn);
@@ -879,7 +1050,8 @@ add_virtual_function (pending_virtuals, has_virtual, fndecl, t)
Deal with this after we have laid out our virtual base classes. */
pending_hard_virtuals = temp_tree_cons (fndecl, vfn, pending_hard_virtuals);
}
- return pending_virtuals;
+ *pv = pending_virtuals;
+ *phv = pending_hard_virtuals;
}
/* Obstack on which to build the vector of class methods. */
@@ -892,39 +1064,30 @@ extern struct obstack *current_obstack;
FIELDS is the entry in the METHOD_VEC vector entry of the class type where
the method should be added. */
+
void
add_method (type, fields, method)
tree type, *fields, method;
{
- /* We must make a copy of METHOD here, since we must be sure that
- we have exclusive title to this method's DECL_CHAIN. */
- tree decl;
-
push_obstacks (&permanent_obstack, &permanent_obstack);
- {
- decl = copy_node (method);
- if (DECL_RTL (decl) == 0
- && (!processing_template_decl
- || !uses_template_parms (decl)))
- {
- make_function_rtl (decl);
- DECL_RTL (method) = DECL_RTL (decl);
- }
- }
if (fields && *fields)
- {
- /* Take care not to hide destructor. */
- DECL_CHAIN (decl) = DECL_CHAIN (*fields);
- DECL_CHAIN (*fields) = decl;
- }
+ *fields = build_overload (method, *fields);
else if (CLASSTYPE_METHOD_VEC (type) == 0)
{
tree method_vec = make_node (TREE_VEC);
- if (TYPE_IDENTIFIER (type) == DECL_NAME (decl))
+ if (TYPE_IDENTIFIER (type) == DECL_NAME (method))
{
- TREE_VEC_ELT (method_vec, 0) = decl;
- TREE_VEC_LENGTH (method_vec) = 1;
+ /* ??? Is it possible for there to have been enough room in the
+ current chunk for the tree_vec structure but not a tree_vec
+ plus a tree*? Will this work in that case? */
+ obstack_free (current_obstack, method_vec);
+ obstack_blank (current_obstack, sizeof (struct tree_vec) + sizeof (tree *));
+ if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method)))
+ TREE_VEC_ELT (method_vec, 1) = method;
+ else
+ TREE_VEC_ELT (method_vec, 0) = method;
+ TREE_VEC_LENGTH (method_vec) = 2;
}
else
{
@@ -932,9 +1095,9 @@ add_method (type, fields, method)
current chunk for the tree_vec structure but not a tree_vec
plus a tree*? Will this work in that case? */
obstack_free (current_obstack, method_vec);
- obstack_blank (current_obstack, sizeof (struct tree_vec) + sizeof (tree *));
- TREE_VEC_ELT (method_vec, 1) = decl;
- TREE_VEC_LENGTH (method_vec) = 2;
+ obstack_blank (current_obstack, sizeof (struct tree_vec) + 2*sizeof (tree *));
+ TREE_VEC_ELT (method_vec, 2) = method;
+ TREE_VEC_LENGTH (method_vec) = 3;
obstack_finish (current_obstack);
}
CLASSTYPE_METHOD_VEC (type) = method_vec;
@@ -946,14 +1109,13 @@ add_method (type, fields, method)
/* Adding a new ctor or dtor. This is easy because our
METHOD_VEC always has a slot for such entries. */
- if (TYPE_IDENTIFIER (type) == DECL_NAME (decl))
+ if (TYPE_IDENTIFIER (type) == DECL_NAME (method))
{
- /* TREE_VEC_ELT (method_vec, 0) = decl; */
- if (decl != TREE_VEC_ELT (method_vec, 0))
- {
- DECL_CHAIN (decl) = TREE_VEC_ELT (method_vec, 0);
- TREE_VEC_ELT (method_vec, 0) = decl;
- }
+ int idx = !!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (method));
+ /* TREE_VEC_ELT (method_vec, idx) = method; */
+ if (method != TREE_VEC_ELT (method_vec, idx))
+ TREE_VEC_ELT (method_vec, idx) =
+ build_overload (method, TREE_VEC_ELT (method_vec, idx));
}
else
{
@@ -992,7 +1154,7 @@ add_method (type, fields, method)
}
obstack_finish (ob);
- TREE_VEC_ELT (method_vec, len) = decl;
+ TREE_VEC_ELT (method_vec, len) = method;
TREE_VEC_LENGTH (method_vec) = len + 1;
CLASSTYPE_METHOD_VEC (type) = method_vec;
@@ -1009,8 +1171,8 @@ add_method (type, fields, method)
}
}
}
- DECL_CONTEXT (decl) = type;
- DECL_CLASS_CONTEXT (decl) = type;
+ DECL_CONTEXT (method) = type;
+ DECL_CLASS_CONTEXT (method) = type;
pop_obstacks ();
}
@@ -1030,6 +1192,7 @@ add_method (type, fields, method)
Note that anonymous fields which are not of UNION_TYPE are
not duplicates, they are just anonymous fields. This happens
when we have unnamed bitfields, for example. */
+
static tree
delete_duplicate_fields_1 (field, fields)
tree field, fields;
@@ -1074,13 +1237,25 @@ delete_duplicate_fields_1 (field, fields)
|| TREE_CODE (x) == CONST_DECL)
cp_error_at ("duplicate field `%D' (as enum and non-enum)",
x);
- else if (TREE_CODE (field) == TYPE_DECL
- && TREE_CODE (x) == TYPE_DECL)
- cp_error_at ("duplicate nested type `%D'", x);
- else if (TREE_CODE (field) == TYPE_DECL
- || TREE_CODE (x) == TYPE_DECL)
- cp_error_at ("duplicate field `%D' (as type and non-type)",
- x);
+ else if (DECL_DECLARES_TYPE_P (field)
+ && DECL_DECLARES_TYPE_P (x))
+ {
+ if (comptypes (TREE_TYPE (field), TREE_TYPE (x), 1))
+ continue;
+ cp_error_at ("duplicate nested type `%D'", x);
+ }
+ else if (DECL_DECLARES_TYPE_P (field)
+ || DECL_DECLARES_TYPE_P (x))
+ {
+ /* Hide tag decls. */
+ if ((TREE_CODE (field) == TYPE_DECL
+ && DECL_ARTIFICIAL (field))
+ || (TREE_CODE (x) == TYPE_DECL
+ && DECL_ARTIFICIAL (x)))
+ continue;
+ cp_error_at ("duplicate field `%D' (as type and non-type)",
+ x);
+ }
else
cp_error_at ("duplicate member `%D'", x);
if (prev == 0)
@@ -1103,85 +1278,135 @@ delete_duplicate_fields (fields)
TREE_CHAIN (x) = delete_duplicate_fields_1 (x, TREE_CHAIN (x));
}
-/* Change the access of FDECL to ACCESS in T.
- Return 1 if change was legit, otherwise return 0. */
+/* Change the access of FDECL to ACCESS in T. The access to FDECL is
+ along the path given by BINFO. Return 1 if change was legit,
+ otherwise return 0. */
+
static int
-alter_access (t, fdecl, access)
+alter_access (t, binfo, fdecl, access)
tree t;
+ tree binfo;
tree fdecl;
- enum access_type access;
+ tree access;
{
tree elem = purpose_member (t, DECL_ACCESS (fdecl));
- if (elem && TREE_VALUE (elem) != (tree)access)
+ if (elem)
{
- if (TREE_CODE (TREE_TYPE (fdecl)) == FUNCTION_DECL)
+ if (TREE_VALUE (elem) != access)
{
- cp_error_at ("conflicting access specifications for method `%D', ignored", TREE_TYPE (fdecl));
+ if (TREE_CODE (TREE_TYPE (fdecl)) == FUNCTION_DECL)
+ cp_error_at ("conflicting access specifications for method `%D', ignored", TREE_TYPE (fdecl));
+ else
+ error ("conflicting access specifications for field `%s', ignored",
+ IDENTIFIER_POINTER (DECL_NAME (fdecl)));
}
else
- error ("conflicting access specifications for field `%s', ignored",
- IDENTIFIER_POINTER (DECL_NAME (fdecl)));
- }
- else if (TREE_PRIVATE (fdecl))
- {
- if (access != access_private)
- cp_error_at ("cannot make private `%D' non-private", fdecl);
- goto alter;
- }
- else if (TREE_PROTECTED (fdecl))
- {
- if (access != access_protected)
- cp_error_at ("cannot make protected `%D' non-protected", fdecl);
- goto alter;
+ {
+ /* They're changing the access to the same thing they changed
+ it to before. That's OK. */
+ ;
+ }
}
- /* ARM 11.3: an access declaration may not be used to restrict access
- to a member that is accessible in the base class. */
- else if (access != access_public)
- cp_error_at ("cannot reduce access of public member `%D'", fdecl);
- else if (elem == NULL_TREE)
+ else
{
- alter:
- DECL_ACCESS (fdecl) = tree_cons (t, (tree)access,
- DECL_ACCESS (fdecl));
+ enforce_access (binfo, fdecl);
+
+ DECL_ACCESS (fdecl) = tree_cons (t, access, DECL_ACCESS (fdecl));
return 1;
}
return 0;
}
-/* Return the offset to the main vtable for a given base BINFO. */
-tree
-get_vfield_offset (binfo)
- tree binfo;
-{
- return size_binop (PLUS_EXPR,
- size_binop (FLOOR_DIV_EXPR,
- DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))),
- size_int (BITS_PER_UNIT)),
- BINFO_OFFSET (binfo));
-}
+/* Process the USING_DECL, which is a member of T. The METHOD_VEC, if
+ non-NULL, is the methods of T. The FIELDS are the fields of T.
+ Returns 1 if the USING_DECL was valid, 0 otherwise. */
-/* Get the offset to the start of the original binfo that we derived
- this binfo from. If we find TYPE first, return the offset only
- that far. The shortened search is useful because the this pointer
- on method calling is expected to point to a DECL_CONTEXT (fndecl)
- object, and not a baseclass of it. */
-static tree
-get_derived_offset (binfo, type)
- tree binfo, type;
+void
+handle_using_decl (using_decl, t, method_vec, fields)
+ tree using_decl;
+ tree t;
+ tree method_vec;
+ tree fields;
{
- tree offset1 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
- tree offset2;
+ tree ctype = DECL_INITIAL (using_decl);
+ tree name = DECL_NAME (using_decl);
+ tree access
+ = TREE_PRIVATE (using_decl) ? access_private_node
+ : TREE_PROTECTED (using_decl) ? access_protected_node
+ : access_public_node;
+ tree fdecl, binfo;
+ tree flist = NULL_TREE;
+ tree tmp;
int i;
- while (BINFO_BASETYPES (binfo)
- && (i=CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo))) != -1)
+ int n_methods;
+
+ binfo = binfo_or_else (ctype, t);
+ if (! binfo)
+ return;
+
+ if (name == constructor_name (ctype)
+ || name == constructor_name_full (ctype))
+ cp_error_at ("using-declaration for constructor", using_decl);
+
+ fdecl = lookup_member (binfo, name, 0, 0);
+
+ if (!fdecl)
{
- tree binfos = BINFO_BASETYPES (binfo);
- if (BINFO_TYPE (binfo) == type)
- break;
- binfo = TREE_VEC_ELT (binfos, i);
+ cp_error_at ("no members matching `%D' in `%#T'", using_decl, ctype);
+ return;
}
- offset2 = get_vfield_offset (TYPE_BINFO (BINFO_TYPE (binfo)));
- return size_binop (MINUS_EXPR, offset1, offset2);
+
+ /* Functions are represented as TREE_LIST, with the purpose
+ being the type and the value the functions. Other members
+ come as themselves. */
+ if (TREE_CODE (fdecl) == TREE_LIST)
+ /* Ignore base type this came from. */
+ fdecl = TREE_VALUE (fdecl);
+
+ if (TREE_CODE (fdecl) == OVERLOAD)
+ {
+ /* We later iterate over all functions. */
+ flist = fdecl;
+ fdecl = OVL_FUNCTION (flist);
+ }
+
+ name = DECL_NAME (fdecl);
+ n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
+ for (i = 2; i < n_methods; i++)
+ if (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, i)))
+ == name)
+ {
+ cp_error ("cannot adjust access to `%#D' in `%#T'", fdecl, t);
+ cp_error_at (" because of local method `%#D' with same name",
+ OVL_CURRENT (TREE_VEC_ELT (method_vec, i)));
+ return;
+ }
+
+ if (! DECL_LANG_SPECIFIC (fdecl))
+ /* We don't currently handle DECL_ACCESS for TYPE_DECLs; just return. */
+ return;
+
+ for (tmp = fields; tmp; tmp = TREE_CHAIN (tmp))
+ if (DECL_NAME (tmp) == name)
+ {
+ cp_error ("cannot adjust access to `%#D' in `%#T'", fdecl, t);
+ cp_error_at (" because of local field `%#D' with same name", tmp);
+ return;
+ }
+
+ /* Make type T see field decl FDECL with access ACCESS.*/
+ if (flist)
+ {
+ while (flist)
+ {
+ if (alter_access (t, binfo, OVL_FUNCTION (flist),
+ access) == 0)
+ return;
+ flist = OVL_CHAIN (flist);
+ }
+ }
+ else
+ alter_access (t, binfo, fdecl, access);
}
/* If FOR_TYPE needs to reinitialize virtual function table pointers
@@ -1202,7 +1427,7 @@ maybe_fixup_vptrs (for_type, binfo, base_init_list)
: VF_BASETYPE_VALUE (vfields);
tree base_binfo = get_binfo (basetype, for_type, 0);
- /* Punt until this is implemented. */
+ /* Punt until this is implemented. */
if (1 /* BINFO_MODIFIED (base_binfo) */)
{
tree base_offset = get_vfield_offset (base_binfo);
@@ -1335,10 +1560,13 @@ build_class_init_list (type)
}
if (base_init_list)
- if (member_init_list)
- CLASSTYPE_BASE_INIT_LIST (type) = build_tree_list (base_init_list, member_init_list);
- else
- CLASSTYPE_BASE_INIT_LIST (type) = base_init_list;
+ {
+ if (member_init_list)
+ CLASSTYPE_BASE_INIT_LIST (type) =
+ build_tree_list (base_init_list, member_init_list);
+ else
+ CLASSTYPE_BASE_INIT_LIST (type) = base_init_list;
+ }
else if (member_init_list)
CLASSTYPE_BASE_INIT_LIST (type) = member_init_list;
}
@@ -1350,12 +1578,10 @@ struct base_info
int n_ancestors;
tree vfield;
tree vfields;
+ tree rtti;
char cant_have_default_ctor;
char cant_have_const_ctor;
- char cant_synth_copy_ctor;
- char cant_synth_asn_ref;
char no_const_asn_ref;
- char needs_virtual_dtor;
};
/* Record information about type T derived from its base classes.
@@ -1372,17 +1598,14 @@ struct base_info
offsets include that offset in theirs.
Returns the index of the first base class to have virtual functions,
- or -1 if no such base class.
-
- Note that at this point TYPE_BINFO (t) != t_binfo. */
+ or -1 if no such base class. */
static int
-finish_base_struct (t, b, t_binfo)
+finish_base_struct (t, b)
tree t;
struct base_info *b;
- tree t_binfo;
{
- tree binfos = BINFO_BASETYPES (t_binfo);
+ tree binfos = TYPE_BINFO_BASETYPES (t);
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
int first_vfn_base_index = -1;
bzero ((char *) b, sizeof (struct base_info));
@@ -1392,6 +1615,13 @@ finish_base_struct (t, b, t_binfo)
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree basetype = BINFO_TYPE (base_binfo);
+ /* Effective C++ rule 14. We only need to check TYPE_VIRTUAL_P
+ here because the case of virtual functions but non-virtual
+ dtor is handled in finish_struct_1. */
+ if (warn_ecpp && ! TYPE_VIRTUAL_P (basetype)
+ && TYPE_HAS_DESTRUCTOR (basetype))
+ cp_warning ("base class `%#T' has a non-virtual destructor", basetype);
+
/* If the type of basetype is incomplete, then
we already complained about that fact
(and we should have fixed it up as well). */
@@ -1409,13 +1639,8 @@ finish_base_struct (t, b, t_binfo)
TREE_VEC_ELT (binfos, j) = TREE_VEC_ELT (binfos, j+1);
}
- if (TYPE_HAS_INIT_REF (basetype)
- && !TYPE_HAS_CONST_INIT_REF (basetype))
+ if (! TYPE_HAS_CONST_INIT_REF (basetype))
b->cant_have_const_ctor = 1;
- if (! TYPE_HAS_INIT_REF (basetype)
- || (TYPE_HAS_NONPUBLIC_CTOR (basetype) == 2
- && ! is_friend_type (t, basetype)))
- b->cant_synth_copy_ctor = 1;
if (TYPE_HAS_CONSTRUCTOR (basetype)
&& ! TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype))
@@ -1432,11 +1657,6 @@ finish_base_struct (t, b, t_binfo)
if (TYPE_HAS_ASSIGN_REF (basetype)
&& !TYPE_HAS_CONST_ASSIGN_REF (basetype))
b->no_const_asn_ref = 1;
- if (! TYPE_HAS_ASSIGN_REF (basetype)
- || TYPE_HAS_ABSTRACT_ASSIGN_REF (basetype)
- || (TYPE_HAS_NONPUBLIC_ASSIGN_REF (basetype) == 2
- && ! is_friend_type (t, basetype)))
- b->cant_synth_asn_ref = 1;
b->n_ancestors += CLASSTYPE_N_SUPERCLASSES (basetype);
TYPE_NEEDS_CONSTRUCTING (t) |= TYPE_NEEDS_CONSTRUCTING (basetype);
@@ -1448,52 +1668,15 @@ finish_base_struct (t, b, t_binfo)
TYPE_OVERLOADS_ARRAY_REF (t) |= TYPE_OVERLOADS_ARRAY_REF (basetype);
TYPE_OVERLOADS_ARROW (t) |= TYPE_OVERLOADS_ARROW (basetype);
- if (! TREE_VIA_VIRTUAL (base_binfo)
-#if 0
- /* This cannot be done, as prepare_fresh_vtable wants to modify
- binfos associated with vfields anywhere in the hierarchy, not
- just immediate base classes. Due to unsharing, the compiler
- might consume 3% more memory on a real program.
- */
- && ! BINFO_OFFSET_ZEROP (base_binfo)
-#endif
- && BINFO_BASETYPES (base_binfo))
- {
- tree base_binfos = BINFO_BASETYPES (base_binfo);
- tree chain = NULL_TREE;
- int j;
-
- /* Now unshare the structure beneath BASE_BINFO. */
- for (j = TREE_VEC_LENGTH (base_binfos)-1;
- j >= 0; j--)
- {
- tree base_base_binfo = TREE_VEC_ELT (base_binfos, j);
- if (! TREE_VIA_VIRTUAL (base_base_binfo))
- TREE_VEC_ELT (base_binfos, j)
- = make_binfo (BINFO_OFFSET (base_base_binfo),
- base_base_binfo,
- BINFO_VTABLE (base_base_binfo),
- BINFO_VIRTUALS (base_base_binfo),
- chain);
- chain = TREE_VEC_ELT (base_binfos, j);
- TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo);
- TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo);
- BINFO_INHERITANCE_CHAIN (chain) = base_binfo;
- }
-
- /* Completely unshare potentially shared data, and
- update what is ours. */
- propagate_binfo_offsets (base_binfo, BINFO_OFFSET (base_binfo));
- }
-
if (! TREE_VIA_VIRTUAL (base_binfo))
CLASSTYPE_N_SUPERCLASSES (t) += 1;
if (TYPE_VIRTUAL_P (basetype))
{
- /* If there's going to be a destructor needed, make
- sure it will be virtual. */
- b->needs_virtual_dtor = 1;
+ /* Ensure that this is set from at least a virtual base
+ class. */
+ if (b->rtti == NULL_TREE)
+ b->rtti = CLASSTYPE_RTTI (basetype);
/* Don't borrow virtuals from virtual baseclasses. */
if (TREE_VIA_VIRTUAL (base_binfo))
@@ -1507,8 +1690,8 @@ finish_base_struct (t, b, t_binfo)
/* Update these two, now that we know what vtable we are
going to extend. This is so that we can add virtual
functions, and override them properly. */
- BINFO_VTABLE (t_binfo) = TYPE_BINFO_VTABLE (basetype);
- BINFO_VIRTUALS (t_binfo) = TYPE_BINFO_VIRTUALS (basetype);
+ TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype);
+ TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
b->has_virtual = CLASSTYPE_VSIZE (basetype);
b->vfield = CLASSTYPE_VFIELD (basetype);
b->vfields = copy_list (CLASSTYPE_VFIELDS (basetype));
@@ -1556,8 +1739,8 @@ finish_base_struct (t, b, t_binfo)
/* Update these two, now that we know what vtable we are
going to extend. This is so that we can add virtual
functions, and override them properly. */
- BINFO_VTABLE (t_binfo) = TYPE_BINFO_VTABLE (basetype);
- BINFO_VIRTUALS (t_binfo) = TYPE_BINFO_VIRTUALS (basetype);
+ TYPE_BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (basetype);
+ TYPE_BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (basetype);
b->has_virtual = CLASSTYPE_VSIZE (basetype);
b->vfield = CLASSTYPE_VFIELD (basetype);
CLASSTYPE_VFIELD (t) = b->vfield;
@@ -1583,33 +1766,31 @@ finish_base_struct (t, b, t_binfo)
}
}
- /* Must come after offsets are fixed for all bases. */
+ /* This comment said "Must come after offsets are fixed for all bases."
+ Well, now this happens before the offsets are fixed, but it seems to
+ work fine. Guess we'll see... */
for (i = 0; i < n_baseclasses; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree basetype = BINFO_TYPE (base_binfo);
- if (get_base_distance (basetype, t_binfo, 0, (tree*)0) == -2)
+ if (get_base_distance (basetype, t, 0, (tree*)0) == -2)
{
cp_warning ("direct base `%T' inaccessible in `%T' due to ambiguity",
basetype, t);
- b->cant_synth_asn_ref = 1;
- b->cant_synth_copy_ctor = 1;
}
}
{
- tree v = get_vbase_types (t_binfo);
+ tree v = get_vbase_types (t);
for (; v; v = TREE_CHAIN (v))
{
tree basetype = BINFO_TYPE (v);
- if (get_base_distance (basetype, t_binfo, 0, (tree*)0) == -2)
+ if (get_base_distance (basetype, t, 0, (tree*)0) == -2)
{
if (extra_warnings)
cp_warning ("virtual base `%T' inaccessible in `%T' due to ambiguity",
basetype, t);
- b->cant_synth_asn_ref = 1;
- b->cant_synth_copy_ctor = 1;
}
}
}
@@ -1630,28 +1811,23 @@ finish_base_struct (t, b, t_binfo)
if (b->vfield == 0)
/* If all virtual functions come only from virtual baseclasses. */
return -1;
- return first_vfn_base_index;
-}
-static int
-typecode_p (type, code)
- tree type;
- enum tree_code code;
-{
- return (TREE_CODE (type) == code
- || (TREE_CODE (type) == REFERENCE_TYPE
- && TREE_CODE (TREE_TYPE (type)) == code));
+ /* Update the rtti base if we have a non-virtual base class version
+ of it. */
+ b->rtti = CLASSTYPE_RTTI (BINFO_TYPE (TREE_VEC_ELT (binfos, first_vfn_base_index)));
+
+ return first_vfn_base_index;
}
/* Set memoizing fields and bits of T (and its variants) for later use.
MAX_HAS_VIRTUAL is the largest size of any T's virtual function tables. */
+
static void
finish_struct_bits (t, max_has_virtual)
tree t;
int max_has_virtual;
{
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
- tree method_vec = CLASSTYPE_METHOD_VEC (t);
/* Fix up variants (if any). */
tree variants = TYPE_NEXT_VARIANT (t);
@@ -1670,6 +1846,9 @@ finish_struct_bits (t, max_has_virtual)
/* Copy whatever these are holding today. */
TYPE_MIN_VALUE (variants) = TYPE_MIN_VALUE (t);
TYPE_MAX_VALUE (variants) = TYPE_MAX_VALUE (t);
+ TYPE_FIELDS (variants) = TYPE_FIELDS (t);
+ TYPE_SIZE (variants) = TYPE_SIZE (t);
+ TYPE_SIZE_UNIT (variants) = TYPE_SIZE_UNIT (t);
variants = TYPE_NEXT_VARIANT (variants);
}
@@ -1688,7 +1867,7 @@ finish_struct_bits (t, max_has_virtual)
if (might_have_abstract_virtuals)
{
/* We use error_mark_node from override_one_vtable to signal
- an artificial abstract. */
+ an artificial abstract. */
if (CLASSTYPE_ABSTRACT_VIRTUALS (t) == error_mark_node)
CLASSTYPE_ABSTRACT_VIRTUALS (t) = NULL_TREE;
CLASSTYPE_ABSTRACT_VIRTUALS (t) = get_abstract_virtuals (t);
@@ -1706,12 +1885,7 @@ finish_struct_bits (t, max_has_virtual)
{
basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
- if (TYPE_HAS_CONVERSION (basetype))
- {
- TYPE_HAS_CONVERSION (t) = 1;
- TYPE_HAS_INT_CONVERSION (t) |= TYPE_HAS_INT_CONVERSION (basetype);
- TYPE_HAS_REAL_CONVERSION (t) |= TYPE_HAS_REAL_CONVERSION (basetype);
- }
+ TYPE_HAS_CONVERSION (t) |= TYPE_HAS_CONVERSION (basetype);
if (CLASSTYPE_MAX_DEPTH (basetype) >= CLASSTYPE_MAX_DEPTH (t))
CLASSTYPE_MAX_DEPTH (t) = CLASSTYPE_MAX_DEPTH (basetype) + 1;
}
@@ -1720,12 +1894,17 @@ finish_struct_bits (t, max_has_virtual)
/* If this type has a copy constructor, force its mode to be BLKmode, and
force its TREE_ADDRESSABLE bit to be nonzero. This will cause it to
be passed by invisible reference and prevent it from being returned in
- a register. */
- if (! TYPE_HAS_TRIVIAL_INIT_REF (t))
+ a register.
+
+ Also do this if the class has BLKmode but can still be returned in
+ registers, since function_cannot_inline_p won't let us inline
+ functions returning such a type. This affects the HP-PA. */
+ if (! TYPE_HAS_TRIVIAL_INIT_REF (t)
+ || (TYPE_MODE (t) == BLKmode && ! aggregate_value_p (t)
+ && CLASSTYPE_NON_AGGREGATE (t)))
{
tree variants;
- if (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL)
- DECL_MODE (TYPE_NAME (t)) = BLKmode;
+ DECL_MODE (TYPE_MAIN_DECL (t)) = BLKmode;
for (variants = t; variants; variants = TYPE_NEXT_VARIANT (variants))
{
TYPE_MODE (variants) = BLKmode;
@@ -1734,57 +1913,29 @@ finish_struct_bits (t, max_has_virtual)
}
}
-/* Add FN to the method_vec growing on the class_obstack. Used by
- finish_struct_methods. */
+/* Add FNDECL to the method_vec growing on the class_obstack. Used by
+ finish_struct_methods. Note, FNDECL cannot be a constructor or
+ destructor, those cases are handled by the caller. */
+
static void
-grow_method (fn, method_vec_ptr)
- tree fn;
+grow_method (fndecl, method_vec_ptr)
+ tree fndecl;
tree *method_vec_ptr;
{
tree method_vec = (tree)obstack_base (&class_obstack);
- tree *testp = &TREE_VEC_ELT (method_vec, 0);
- if (*testp == NULL_TREE)
- testp++;
- while (((HOST_WIDE_INT) testp
- < (HOST_WIDE_INT) obstack_next_free (&class_obstack))
- && DECL_NAME (*testp) != DECL_NAME (fn))
+
+ /* Start off past the constructors and destructor. */
+ tree *testp = &TREE_VEC_ELT (method_vec, 2);
+
+ while (testp < (tree *) obstack_next_free (&class_obstack)
+ && (*testp == NULL_TREE || DECL_NAME (OVL_CURRENT (*testp)) != DECL_NAME (fndecl)))
testp++;
- if ((HOST_WIDE_INT) testp
- < (HOST_WIDE_INT) obstack_next_free (&class_obstack))
- {
- tree x, prev_x;
- for (x = *testp; x; x = DECL_CHAIN (x))
- {
- if (DECL_NAME (fn) == ansi_opname[(int) DELETE_EXPR]
- || DECL_NAME (fn) == ansi_opname[(int) VEC_DELETE_EXPR])
- {
- /* ANSI C++ June 5 1992 WP 12.5.5.1 */
- cp_error_at ("`%D' overloaded", fn);
- cp_error_at ("previous declaration as `%D' here", x);
- }
- if (DECL_ASSEMBLER_NAME (fn)==DECL_ASSEMBLER_NAME (x))
- {
- /* We complain about multiple destructors on sight,
- so we do not repeat the warning here. Friend-friend
- ambiguities are warned about outside this loop. */
- if (!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fn)))
- cp_error_at ("ambiguous method `%#D' in structure", fn);
- break;
- }
- prev_x = x;
- }
- if (x == 0)
- {
- if (*testp)
- DECL_CHAIN (prev_x) = fn;
- else
- *testp = fn;
- }
- }
+ if (testp < (tree *) obstack_next_free (&class_obstack))
+ *testp = build_overload (fndecl, *testp);
else
{
- obstack_ptr_grow (&class_obstack, fn);
+ obstack_ptr_grow (&class_obstack, fndecl);
*method_vec_ptr = (tree)obstack_base (&class_obstack);
}
}
@@ -1812,36 +1963,35 @@ grow_method (fn, method_vec_ptr)
us to reduce search time in places like `build_method_call' to
consider only reasonably likely functions. */
-static tree
+tree
finish_struct_methods (t, fn_fields, nonprivate_method)
tree t;
tree fn_fields;
int nonprivate_method;
{
tree method_vec;
- tree save_fn_fields = tree_cons (NULL_TREE, NULL_TREE, fn_fields);
- tree lastp;
- tree name = constructor_name (t);
+ tree save_fn_fields = fn_fields;
+ tree ctor_name = constructor_name (t);
int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (t);
/* Now prepare to gather fn_fields into vector. */
struct obstack *ambient_obstack = current_obstack;
current_obstack = &class_obstack;
- method_vec = make_node (TREE_VEC);
- /* Room has been saved for constructors and destructors. */
+ method_vec = make_tree_vec (2);
current_obstack = ambient_obstack;
+
/* Now make this a live vector. */
obstack_free (&class_obstack, method_vec);
- obstack_blank (&class_obstack, sizeof (struct tree_vec));
- /* First fill in entry 0 with the constructors, and the next few with
- type conversion operators (if any). */
+ /* Save room for constructors and destructors. */
+ obstack_blank (&class_obstack, sizeof (struct tree_vec) + sizeof (struct tree *));
+
+ /* First fill in entry 0 with the constructors, entry 1 with destructors,
+ and the next few with type conversion operators (if any). */
- for (lastp = save_fn_fields; fn_fields; fn_fields = TREE_CHAIN (lastp))
+ for (; fn_fields; fn_fields = TREE_CHAIN (fn_fields))
{
tree fn_name = DECL_NAME (fn_fields);
- if (fn_name == NULL_TREE)
- fn_name = name;
/* Clear out this flag.
@@ -1852,7 +2002,7 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
/* Note here that a copy ctor is private, so we don't dare generate
a default copy constructor for a class that has a member
of this type without making sure they have access to it. */
- if (fn_name == name)
+ if (fn_name == ctor_name)
{
tree parmtypes = FUNCTION_ARG_CHAIN (fn_fields);
tree parmtype = parmtypes ? TREE_VALUE (parmtypes) : void_type_node;
@@ -1870,43 +2020,30 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
TYPE_HAS_NONPUBLIC_CTOR (t) = 2;
}
}
- /* Constructors are handled easily in search routines. */
- DECL_CHAIN (fn_fields) = TREE_VEC_ELT (method_vec, 0);
- TREE_VEC_ELT (method_vec, 0) = fn_fields;
+ if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fn_fields)))
+ {
+ /* Destructors go in slot 1. */
+ TREE_VEC_ELT (method_vec, 1) =
+ build_overload (fn_fields, TREE_VEC_ELT (method_vec, 1));
+ }
+ else
+ {
+ /* Constructors go in slot 0. */
+ TREE_VEC_ELT (method_vec, 0) =
+ build_overload (fn_fields, TREE_VEC_ELT (method_vec, 0));
+ }
}
else if (IDENTIFIER_TYPENAME_P (fn_name))
- {
- tree return_type = TREE_TYPE (TREE_TYPE (fn_fields));
-
- if (typecode_p (return_type, INTEGER_TYPE)
- || typecode_p (return_type, BOOLEAN_TYPE)
- || typecode_p (return_type, ENUMERAL_TYPE))
- TYPE_HAS_INT_CONVERSION (t) = 1;
- else if (typecode_p (return_type, REAL_TYPE))
- TYPE_HAS_REAL_CONVERSION (t) = 1;
-
- grow_method (fn_fields, &method_vec);
- }
- else
- {
- lastp = fn_fields;
- continue;
- }
-
- TREE_CHAIN (lastp) = TREE_CHAIN (fn_fields);
- TREE_CHAIN (fn_fields) = NULL_TREE;
+ grow_method (fn_fields, &method_vec);
}
- fn_fields = TREE_CHAIN (save_fn_fields);
- while (fn_fields)
+ fn_fields = save_fn_fields;
+ for (; fn_fields; fn_fields = TREE_CHAIN (fn_fields))
{
- tree nextp;
tree fn_name = DECL_NAME (fn_fields);
- if (fn_name == NULL_TREE)
- fn_name = name;
- nextp = TREE_CHAIN (fn_fields);
- TREE_CHAIN (fn_fields) = NULL_TREE;
+ if (fn_name == ctor_name || IDENTIFIER_TYPENAME_P (fn_name))
+ continue;
if (fn_name == ansi_opname[(int) MODIFY_EXPR])
{
@@ -1922,7 +2059,6 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
}
grow_method (fn_fields, &method_vec);
- fn_fields = nextp;
}
TREE_VEC_LENGTH (method_vec) = (tree *)obstack_next_free (&class_obstack)
@@ -1932,7 +2068,7 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
if (nonprivate_method == 0
&& CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
- && DECL_FRIENDLIST (TYPE_NAME (t)) == NULL_TREE)
+ && DECL_FRIENDLIST (TYPE_MAIN_DECL (t)) == NULL_TREE)
{
tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
for (i = 0; i < n_baseclasses; i++)
@@ -1942,60 +2078,44 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
nonprivate_method = 1;
break;
}
- if (nonprivate_method == 0)
+ if (nonprivate_method == 0
+ && warn_ctor_dtor_privacy)
cp_warning ("all member functions in class `%T' are private", t);
}
- /* If there are constructors (and destructors), they are at the
- front. Place destructors at very front. Also warn if all
- constructors and/or destructors are private (in which case this
- class is effectively unusable. */
+ /* Warn if all destructors are private (in which case this class is
+ effectively unusable. */
if (TYPE_HAS_DESTRUCTOR (t))
{
- tree dtor, prev;
-
- for (dtor = TREE_VEC_ELT (method_vec, 0);
- dtor;
- prev = dtor, dtor = DECL_CHAIN (dtor))
- {
- if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (dtor)))
- {
- if (TREE_PRIVATE (dtor)
- && CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
- && DECL_FRIENDLIST (TYPE_NAME (t)) == NULL_TREE
- && warn_ctor_dtor_privacy)
- cp_warning ("`%#T' only defines a private destructor and has no friends",
- t);
- break;
- }
- }
+ tree dtor = TREE_VEC_ELT (method_vec, 1);
/* Wild parse errors can cause this to happen. */
if (dtor == NULL_TREE)
TYPE_HAS_DESTRUCTOR (t) = 0;
- else if (dtor != TREE_VEC_ELT (method_vec, 0))
- {
- DECL_CHAIN (prev) = DECL_CHAIN (dtor);
- DECL_CHAIN (dtor) = TREE_VEC_ELT (method_vec, 0);
- TREE_VEC_ELT (method_vec, 0) = dtor;
- }
+ else if (TREE_PRIVATE (dtor)
+ && CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
+ && DECL_FRIENDLIST (TYPE_MAIN_DECL (t)) == NULL_TREE
+ && warn_ctor_dtor_privacy)
+ cp_warning ("`%#T' only defines a private destructor and has no friends",
+ t);
}
/* Now for each member function (except for constructors and
destructors), compute where member functions of the same
name reside in base classes. */
if (n_baseclasses != 0
- && TREE_VEC_LENGTH (method_vec) > 1)
+ && TREE_VEC_LENGTH (method_vec) > 2)
{
int len = TREE_VEC_LENGTH (method_vec);
tree baselink_vec = make_tree_vec (len);
int any_links = 0;
tree baselink_binfo = build_tree_list (NULL_TREE, TYPE_BINFO (t));
- for (i = 1; i < len; i++)
+ for (i = 2; i < len; i++)
{
TREE_VEC_ELT (baselink_vec, i)
- = get_baselinks (baselink_binfo, t, DECL_NAME (TREE_VEC_ELT (method_vec, i)));
+ = get_baselinks (baselink_binfo, t,
+ DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, i))));
if (TREE_VEC_ELT (baselink_vec, i) != 0)
any_links = 1;
}
@@ -2005,46 +2125,10 @@ finish_struct_methods (t, fn_fields, nonprivate_method)
obstack_free (current_obstack, baselink_vec);
}
- /* Now add the methods to the TYPE_METHODS of T, arranged in a chain. */
- {
- tree x, last_x = NULL_TREE;
- int limit = TREE_VEC_LENGTH (method_vec);
-
- for (i = 1; i < limit; i++)
- {
- for (x = TREE_VEC_ELT (method_vec, i); x; x = DECL_CHAIN (x))
- {
- if (last_x != NULL_TREE)
- TREE_CHAIN (last_x) = x;
- last_x = x;
- }
- }
-
- /* Put ctors and dtors at the front of the list. */
- x = TREE_VEC_ELT (method_vec, 0);
- if (x)
- {
- while (DECL_CHAIN (x))
- {
- /* Let's avoid being circular about this. */
- if (x == DECL_CHAIN (x))
- break;
- TREE_CHAIN (x) = DECL_CHAIN (x);
- x = DECL_CHAIN (x);
- }
- if (TREE_VEC_LENGTH (method_vec) > 1)
- TREE_CHAIN (x) = TREE_VEC_ELT (method_vec, 1);
- else
- TREE_CHAIN (x) = NULL_TREE;
- }
- }
-
- TYPE_METHODS (t) = method_vec;
-
return method_vec;
}
-/* Emit error when a duplicate definition of a type is seen. Patch up. */
+/* Emit error when a duplicate definition of a type is seen. Patch up. */
void
duplicate_tag_error (t)
@@ -2058,23 +2142,22 @@ duplicate_tag_error (t)
/* All of the component_decl's were TREE_CHAINed together in the parser.
finish_struct_methods walks these chains and assembles all methods with
the same base name into DECL_CHAINs. Now we don't need the parser chains
- anymore, so we unravel them.
- */
- /*
- * This used to be in finish_struct, but it turns out that the
- * TREE_CHAIN is used by dbxout_type_methods and perhaps some other things...
- */
- if (CLASSTYPE_METHOD_VEC(t))
- {
- tree tv = CLASSTYPE_METHOD_VEC(t);
- int i, len = TREE_VEC_LENGTH (tv);
+ anymore, so we unravel them. */
+
+ /* This used to be in finish_struct, but it turns out that the
+ TREE_CHAIN is used by dbxout_type_methods and perhaps some other
+ things... */
+ if (CLASSTYPE_METHOD_VEC (t))
+ {
+ tree method_vec = CLASSTYPE_METHOD_VEC (t);
+ int i, len = TREE_VEC_LENGTH (method_vec);
for (i = 0; i < len; i++)
{
- tree unchain = TREE_VEC_ELT (tv, i);
+ tree unchain = TREE_VEC_ELT (method_vec, i);
while (unchain != NULL_TREE)
{
- TREE_CHAIN (unchain) = NULL_TREE;
- unchain = DECL_CHAIN(unchain);
+ TREE_CHAIN (OVL_CURRENT (unchain)) = NULL_TREE;
+ unchain = OVL_NEXT (unchain);
}
}
}
@@ -2095,7 +2178,6 @@ duplicate_tag_error (t)
CLASSTYPE_BINFO_AS_LIST (t) = binfo_as_list;
CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown);
- CLASSTYPE_VBASE_SIZE (t) = integer_zero_node;
TYPE_REDEFINED (t) = 1;
}
TYPE_SIZE (t) = NULL_TREE;
@@ -2106,11 +2188,13 @@ duplicate_tag_error (t)
TYPE_CONTEXT (t) = NULL_TREE;
}
-/* finish up all new vtables. */
+/* finish up all new vtables. */
+
static void
finish_vtbls (binfo, do_self, t)
- tree binfo, t;
+ tree binfo;
int do_self;
+ tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
@@ -2138,8 +2222,8 @@ finish_vtbls (binfo, do_self, t)
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+ int is_not_base_vtable
+ = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (TREE_VIA_VIRTUAL (base_binfo))
{
base_binfo = binfo_member (BINFO_TYPE (base_binfo), CLASSTYPE_VBASECLASSES (t));
@@ -2150,20 +2234,21 @@ finish_vtbls (binfo, do_self, t)
/* True if we should override the given BASE_FNDECL with the given
FNDECL. */
+
static int
overrides (fndecl, base_fndecl)
tree fndecl, base_fndecl;
{
- /* Destructors have special names. */
- if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl)) &&
- DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+ /* Destructors have special names. */
+ if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
+ && DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
return 1;
- if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl)) ||
- DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+ if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (base_fndecl))
+ || DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
return 0;
if (DECL_NAME (fndecl) == DECL_NAME (base_fndecl))
{
- tree rettype, base_rettype, types, base_types;
+ tree types, base_types;
#if 0
retypes = TREE_TYPE (TREE_TYPE (fndecl));
base_retypes = TREE_TYPE (TREE_TYPE (base_fndecl));
@@ -2226,6 +2311,7 @@ get_class_offset_1 (parent, binfo, context, t, fndecl)
/* Get the offset to the CONTEXT subobject that is related to the
given BINFO. */
+
static tree
get_class_offset (context, t, binfo, fndecl)
tree context, t, binfo, fndecl;
@@ -2251,7 +2337,7 @@ get_class_offset (context, t, binfo, fndecl)
}
/* Ok, not found in the less derived binfos, now check the more
- derived binfos. */
+ derived binfos. */
offset = get_class_offset_1 (first_binfo, TYPE_BINFO (t), context, t, fndecl);
if (offset==0 || TREE_CODE (offset) != INTEGER_CST)
my_friendly_abort (999); /* we have to find it. */
@@ -2259,6 +2345,7 @@ get_class_offset (context, t, binfo, fndecl)
}
/* Skip RTTI information at the front of the virtual list. */
+
unsigned HOST_WIDE_INT
skip_rtti_stuff (virtuals)
tree *virtuals;
@@ -2287,7 +2374,6 @@ modify_one_vtable (binfo, t, fndecl, pfn)
tree binfo, t, fndecl, pfn;
{
tree virtuals = BINFO_VIRTUALS (binfo);
- tree old_rtti;
unsigned HOST_WIDE_INT n;
/* update rtti entry */
@@ -2333,7 +2419,7 @@ modify_one_vtable (binfo, t, fndecl, pfn)
base_offset = size_binop (PLUS_EXPR,
get_derived_offset (binfo, DECL_CONTEXT (current_fndecl)),
BINFO_OFFSET (binfo));
- this_offset = size_binop (MINUS_EXPR, offset, base_offset);
+ this_offset = ssize_binop (MINUS_EXPR, offset, base_offset);
/* Make sure we can modify the derived association with immunity. */
if (TREE_USED (binfo))
@@ -2369,11 +2455,13 @@ modify_one_vtable (binfo, t, fndecl, pfn)
}
}
-/* These are the ones that are not through virtual base classes. */
+/* These are the ones that are not through virtual base classes. */
+
static void
modify_all_direct_vtables (binfo, do_self, t, fndecl, pfn)
- tree binfo, t, fndecl, pfn;
+ tree binfo;
int do_self;
+ tree t, fndecl, pfn;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
@@ -2387,14 +2475,15 @@ modify_all_direct_vtables (binfo, do_self, t, fndecl, pfn)
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+ int is_not_base_vtable
+ = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (! TREE_VIA_VIRTUAL (base_binfo))
modify_all_direct_vtables (base_binfo, is_not_base_vtable, t, fndecl, pfn);
}
}
/* Fixup all the delta entries in this one vtable that need updating. */
+
static void
fixup_vtable_deltas1 (binfo, t)
tree binfo, t;
@@ -2427,9 +2516,10 @@ fixup_vtable_deltas1 (binfo, t)
Also, we want just the delta between the most base class
that we derived this vfield from and us. */
base_offset = size_binop (PLUS_EXPR,
- get_derived_offset (binfo, DECL_CONTEXT (fndecl)),
+ get_derived_offset (binfo,
+ DECL_CONTEXT (fndecl)),
BINFO_OFFSET (binfo));
- this_offset = size_binop (MINUS_EXPR, offset, base_offset);
+ this_offset = ssize_binop (MINUS_EXPR, offset, base_offset);
if (! tree_int_cst_equal (this_offset, delta))
{
@@ -2469,10 +2559,12 @@ fixup_vtable_deltas1 (binfo, t)
This happens when we have non-overridden virtual functions from a
virtual base class, that are at a different offset, in the new
hierarchy, because the layout of the virtual bases has changed. */
+
static void
fixup_vtable_deltas (binfo, init_self, t)
- tree binfo, t;
+ tree binfo;
int init_self;
+ tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
@@ -2480,8 +2572,8 @@ fixup_vtable_deltas (binfo, init_self, t)
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+ int is_not_base_vtable
+ = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (! TREE_VIA_VIRTUAL (base_binfo))
fixup_vtable_deltas (base_binfo, is_not_base_vtable, t);
}
@@ -2492,11 +2584,13 @@ fixup_vtable_deltas (binfo, init_self, t)
}
}
-/* These are the ones that are through virtual base classes. */
+/* These are the ones that are through virtual base classes. */
+
static void
modify_all_indirect_vtables (binfo, do_self, via_virtual, t, fndecl, pfn)
- tree binfo, t, fndecl, pfn;
+ tree binfo;
int do_self, via_virtual;
+ tree t, fndecl, pfn;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
@@ -2510,8 +2604,8 @@ modify_all_indirect_vtables (binfo, do_self, via_virtual, t, fndecl, pfn)
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+ int is_not_base_vtable
+ = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (TREE_VIA_VIRTUAL (base_binfo))
{
via_virtual = 1;
@@ -2526,7 +2620,7 @@ modify_all_vtables (t, fndecl, vfn)
tree t, fndecl, vfn;
{
/* Do these first, so that we will make use of any non-virtual class's
- vtable, over a virtual classes vtable. */
+ vtable, over a virtual classes vtable. */
modify_all_direct_vtables (TYPE_BINFO (t), 1, t, fndecl, vfn);
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
modify_all_indirect_vtables (TYPE_BINFO (t), 1, 0, t, fndecl, vfn);
@@ -2534,6 +2628,7 @@ modify_all_vtables (t, fndecl, vfn)
/* Here, we already know that they match in every respect.
All we have to check is where they had their declarations. */
+
static int
strictly_overrides (fndecl1, fndecl2)
tree fndecl1, fndecl2;
@@ -2558,6 +2653,7 @@ strictly_overrides (fndecl1, fndecl2)
then it is ill-formed. (mrs)
We take special care to reuse a vtable, if we can. */
+
static void
override_one_vtable (binfo, old, t)
tree binfo, old, t;
@@ -2567,7 +2663,7 @@ override_one_vtable (binfo, old, t)
enum { REUSE_NEW, REUSE_OLD, UNDECIDED, NEITHER } choose = UNDECIDED;
/* If we have already committed to modifying it, then don't try and
- reuse another vtable. */
+ reuse another vtable. */
if (BINFO_NEW_VTABLE_MARKED (binfo))
choose = NEITHER;
@@ -2582,10 +2678,10 @@ override_one_vtable (binfo, old, t)
old_fndecl = FNADDR_FROM_VTABLE_ENTRY (old_fndecl);
fndecl = TREE_OPERAND (fndecl, 0);
old_fndecl = TREE_OPERAND (old_fndecl, 0);
- /* First check to see if they are the same. */
+ /* First check to see if they are the same. */
if (DECL_ASSEMBLER_NAME (fndecl) == DECL_ASSEMBLER_NAME (old_fndecl))
{
- /* No need to do anything. */
+ /* No need to do anything. */
}
else if (strictly_overrides (fndecl, old_fndecl))
{
@@ -2640,15 +2736,16 @@ override_one_vtable (binfo, old, t)
fndecl = copy_node (fndecl);
copy_lang_decl (fndecl);
DECL_ABSTRACT_VIRTUAL_P (fndecl) = 1;
- /* Make sure we search for it later. */
+ DECL_NEEDS_FINAL_OVERRIDER_P (fndecl) = 1;
+ /* Make sure we search for it later. */
if (! CLASSTYPE_ABSTRACT_VIRTUALS (t))
CLASSTYPE_ABSTRACT_VIRTUALS (t) = error_mark_node;
vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, fndecl);
TREE_CONSTANT (vfn) = 1;
- /* We can use integer_zero_node, as we will will core dump
- if this is used anyway. */
+ /* We can use integer_zero_node, as we will core dump
+ if this is used anyway. */
TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, vfn);
}
}
@@ -2656,7 +2753,7 @@ override_one_vtable (binfo, old, t)
old_virtuals = TREE_CHAIN (old_virtuals);
}
- /* Let's reuse the old vtable. */
+ /* Let's reuse the old vtable. */
if (choose == REUSE_OLD)
{
BINFO_VTABLE (binfo) = BINFO_VTABLE (old);
@@ -2667,10 +2764,12 @@ override_one_vtable (binfo, old, t)
/* Merge in overrides for virtual bases.
BINFO is the hierarchy we want to modify, and OLD has the potential
overrides. */
+
static void
merge_overrides (binfo, old, do_self, t)
- tree binfo, old, t;
+ tree binfo, old;
int do_self;
+ tree t;
{
tree binfos = BINFO_BASETYPES (binfo);
tree old_binfos = BINFO_BASETYPES (old);
@@ -2686,13 +2785,252 @@ merge_overrides (binfo, old, do_self, t)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree old_base_binfo = TREE_VEC_ELT (old_binfos, i);
- int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+ int is_not_base_vtable
+ = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (! TREE_VIA_VIRTUAL (base_binfo))
merge_overrides (base_binfo, old_base_binfo, is_not_base_vtable, t);
}
}
+/* Get the base virtual function declarations in T that are either
+ overridden or hidden by FNDECL as a list. We set TREE_PURPOSE with
+ the overrider/hider. */
+
+static tree
+get_basefndecls (fndecl, t)
+ tree fndecl, t;
+{
+ tree methods = TYPE_METHODS (t);
+ tree base_fndecls = NULL_TREE;
+ tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
+ int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+ while (methods)
+ {
+ if (TREE_CODE (methods) == FUNCTION_DECL
+ && DECL_VINDEX (methods) != NULL_TREE
+ && DECL_NAME (fndecl) == DECL_NAME (methods))
+ base_fndecls = temp_tree_cons (fndecl, methods, base_fndecls);
+
+ methods = TREE_CHAIN (methods);
+ }
+
+ if (base_fndecls)
+ return base_fndecls;
+
+ for (i = 0; i < n_baseclasses; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ tree basetype = BINFO_TYPE (base_binfo);
+
+ base_fndecls = chainon (get_basefndecls (fndecl, basetype),
+ base_fndecls);
+ }
+
+ return base_fndecls;
+}
+
+/* Mark the functions that have been hidden with their overriders.
+ Since we start out with all functions already marked with a hider,
+ no need to mark functions that are just hidden. */
+
+static void
+mark_overriders (fndecl, base_fndecls)
+ tree fndecl, base_fndecls;
+{
+ while (base_fndecls)
+ {
+ if (overrides (TREE_VALUE (base_fndecls), fndecl))
+ TREE_PURPOSE (base_fndecls) = fndecl;
+
+ base_fndecls = TREE_CHAIN (base_fndecls);
+ }
+}
+
+/* If this declaration supersedes the declaration of
+ a method declared virtual in the base class, then
+ mark this field as being virtual as well. */
+
+static void
+check_for_override (decl, ctype)
+ tree decl, ctype;
+{
+ tree binfos = BINFO_BASETYPES (TYPE_BINFO (ctype));
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ int virtualp = DECL_VIRTUAL_P (decl);
+
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ if (TYPE_VIRTUAL_P (BINFO_TYPE (base_binfo))
+ || flag_all_virtual == 1)
+ {
+ tree tmp = get_matching_virtual
+ (base_binfo, decl,
+ DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)));
+ if (tmp)
+ {
+ /* If this function overrides some virtual in some base
+ class, then the function itself is also necessarily
+ virtual, even if the user didn't explicitly say so. */
+ DECL_VIRTUAL_P (decl) = 1;
+
+ /* The TMP we really want is the one from the deepest
+ baseclass on this path, taking care not to
+ duplicate if we have already found it (via another
+ path to its virtual baseclass. */
+ if (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
+ {
+ cp_error_at ("method `%D' may not be declared static",
+ decl);
+ cp_error_at ("(since `%D' declared virtual in base class.)",
+ tmp);
+ break;
+ }
+ virtualp = 1;
+
+#if 0 /* The signature of an overriding function is not changed. */
+ {
+ /* The argument types may have changed... */
+ tree type = TREE_TYPE (decl);
+ tree argtypes = TYPE_ARG_TYPES (type);
+ tree base_variant = TREE_TYPE (TREE_VALUE (argtypes));
+ tree raises = TYPE_RAISES_EXCEPTIONS (type);
+
+ argtypes = commonparms (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (tmp))),
+ TREE_CHAIN (argtypes));
+ /* But the return type has not. */
+ type = build_cplus_method_type (base_variant, TREE_TYPE (type), argtypes);
+ if (raises)
+ type = build_exception_variant (type, raises);
+ TREE_TYPE (decl) = type;
+ }
+#endif
+ DECL_VINDEX (decl)
+ = tree_cons (NULL_TREE, tmp, DECL_VINDEX (decl));
+ break;
+ }
+ }
+ }
+ if (virtualp)
+ {
+ if (DECL_VINDEX (decl) == NULL_TREE)
+ DECL_VINDEX (decl) = error_mark_node;
+ IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
+ }
+}
+
+/* Warn about hidden virtual functions that are not overridden in t.
+ We know that constructors and destructors don't apply. */
+
+void
+warn_hidden (t)
+ tree t;
+{
+ tree method_vec = CLASSTYPE_METHOD_VEC (t);
+ int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
+ int i;
+
+ /* We go through each separately named virtual function. */
+ for (i = 2; i < n_methods; ++i)
+ {
+ tree fns = TREE_VEC_ELT (method_vec, i);
+ tree fndecl;
+
+ tree base_fndecls = NULL_TREE;
+ tree binfos = BINFO_BASETYPES (TYPE_BINFO (t));
+ int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+ fndecl = OVL_CURRENT (fns);
+ if (DECL_VINDEX (fndecl) == NULL_TREE)
+ continue;
+
+ /* First we get a list of all possible functions that might be
+ hidden from each base class. */
+ for (i = 0; i < n_baseclasses; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ tree basetype = BINFO_TYPE (base_binfo);
+
+ base_fndecls = chainon (get_basefndecls (fndecl, basetype),
+ base_fndecls);
+ }
+
+ fns = OVL_NEXT (fns);
+ if (fns)
+ fndecl = OVL_CURRENT (fns);
+ else
+ fndecl = NULL_TREE;
+
+ /* ...then mark up all the base functions with overriders, preferring
+ overriders to hiders. */
+ if (base_fndecls)
+ while (fndecl)
+ {
+ mark_overriders (fndecl, base_fndecls);
+
+ fns = OVL_NEXT (fns);
+ if (fns)
+ fndecl = OVL_CURRENT (fns);
+ else
+ fndecl = NULL_TREE;
+ }
+
+ /* Now give a warning for all base functions without overriders,
+ as they are hidden. */
+ while (base_fndecls)
+ {
+ if (! overrides (TREE_VALUE (base_fndecls),
+ TREE_PURPOSE (base_fndecls)))
+ {
+ /* Here we know it is a hider, and no overrider exists. */
+ cp_warning_at ("`%D' was hidden", TREE_VALUE (base_fndecls));
+ cp_warning_at (" by `%D'", TREE_PURPOSE (base_fndecls));
+ }
+
+ base_fndecls = TREE_CHAIN (base_fndecls);
+ }
+ }
+}
+
+/* Check for things that are invalid. There are probably plenty of other
+ things we should check for also. */
+
+static void
+finish_struct_anon (t)
+ tree t;
+{
+ tree field;
+ for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
+ {
+ if (TREE_STATIC (field))
+ continue;
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ if (DECL_NAME (field) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ {
+ tree* uelt = &TYPE_FIELDS (TREE_TYPE (field));
+ for (; *uelt; uelt = &TREE_CHAIN (*uelt))
+ {
+ if (TREE_CODE (*uelt) != FIELD_DECL)
+ continue;
+
+ if (TREE_PRIVATE (*uelt))
+ cp_pedwarn_at ("private member `%#D' in anonymous union",
+ *uelt);
+ else if (TREE_PROTECTED (*uelt))
+ cp_pedwarn_at ("protected member `%#D' in anonymous union",
+ *uelt);
+
+ TREE_PRIVATE (*uelt) = TREE_PRIVATE (field);
+ TREE_PROTECTED (*uelt) = TREE_PROTECTED (field);
+ }
+ }
+ }
+}
+
extern int interface_only, interface_unknown;
/* Create a RECORD_TYPE or UNION_TYPE node for a C struct or union declaration
@@ -2724,6 +3062,8 @@ extern int interface_only, interface_unknown;
TREE_LIST elements, whose TREE_PURPOSE field tells what access
the list has, and the TREE_VALUE slot gives the actual fields.
+ ATTRIBUTES is the set of decl attributes to be applied, if any.
+
If flag_all_virtual == 1, then we lay all functions into
the virtual function table, as though they were declared
virtual. Constructors do not lay down in the virtual function table.
@@ -2760,25 +3100,21 @@ finish_struct_1 (t, warn_anon)
int warn_anon;
{
int old;
- int round_up_size = 1;
-
tree name = TYPE_IDENTIFIER (t);
enum tree_code code = TREE_CODE (t);
tree fields = TYPE_FIELDS (t);
- tree fn_fields = CLASSTYPE_METHODS (t);
+ tree fn_fields = TYPE_METHODS (t);
tree x, last_x, method_vec;
- int needs_virtual_dtor;
int all_virtual;
int has_virtual;
int max_has_virtual;
tree pending_virtuals = NULL_TREE;
+ tree pending_hard_virtuals = NULL_TREE;
tree abstract_virtuals = NULL_TREE;
tree vfield;
tree vfields;
int cant_have_default_ctor;
int cant_have_const_ctor;
- int cant_synth_copy_ctor;
- int cant_synth_asn_ref;
int no_const_asn_ref;
/* The index of the first base class which has virtual
@@ -2790,9 +3126,10 @@ finish_struct_1 (t, warn_anon)
int const_sans_init = 0;
int ref_sans_init = 0;
int nonprivate_method = 0;
- tree t_binfo = TYPE_BINFO (t);
tree access_decls = NULL_TREE;
int aggregate = 1;
+ int empty = 1;
+ int has_pointers = 0;
if (warn_anon && code != UNION_TYPE && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
pedwarn ("anonymous class type not used to declare any objects");
@@ -2807,12 +3144,6 @@ finish_struct_1 (t, warn_anon)
return t;
}
- if (dont_allow_type_definitions)
- {
- pedwarn ("types cannot be defined %s",
- dont_allow_type_definitions);
- }
-
GNU_xref_decl (current_function_decl, t);
/* If this type was previously laid out as a forward reference,
@@ -2831,13 +3162,6 @@ finish_struct_1 (t, warn_anon)
}
#endif
-#if 0
- if (flag_rtti)
- build_t_desc (t, 0);
-#endif
-
- TYPE_BINFO (t) = NULL_TREE;
-
old = suspend_momentary ();
/* Install struct as DECL_FIELD_CONTEXT of each field decl.
@@ -2847,8 +3171,8 @@ finish_struct_1 (t, warn_anon)
Store 0 there, except for ": 0" fields (so we can find them
and delete them, below). */
- if (t_binfo && BINFO_BASETYPES (t_binfo))
- n_baseclasses = TREE_VEC_LENGTH (BINFO_BASETYPES (t_binfo));
+ if (TYPE_BINFO_BASETYPES (t))
+ n_baseclasses = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (t));
else
n_baseclasses = 0;
@@ -2856,27 +3180,18 @@ finish_struct_1 (t, warn_anon)
{
struct base_info base_info;
- /* If using multiple inheritance, this may cause variants of our
- basetypes to be used (instead of their canonical forms). */
- tree vf = layout_basetypes (t, BINFO_BASETYPES (t_binfo));
- last_x = tree_last (vf);
- fields = chainon (vf, fields);
-
- first_vfn_base_index = finish_base_struct (t, &base_info, t_binfo);
- /* Remember where we got our vfield from */
+ first_vfn_base_index = finish_base_struct (t, &base_info);
+ /* Remember where we got our vfield from. */
CLASSTYPE_VFIELD_PARENT (t) = first_vfn_base_index;
has_virtual = base_info.has_virtual;
max_has_virtual = base_info.max_has_virtual;
CLASSTYPE_N_SUPERCLASSES (t) += base_info.n_ancestors;
vfield = base_info.vfield;
vfields = base_info.vfields;
+ CLASSTYPE_RTTI (t) = base_info.rtti;
cant_have_default_ctor = base_info.cant_have_default_ctor;
cant_have_const_ctor = base_info.cant_have_const_ctor;
- cant_synth_copy_ctor = base_info.cant_synth_copy_ctor;
- cant_synth_asn_ref = base_info.cant_synth_asn_ref;
no_const_asn_ref = base_info.no_const_asn_ref;
- needs_virtual_dtor = base_info.needs_virtual_dtor;
- n_baseclasses = TREE_VEC_LENGTH (BINFO_BASETYPES (t_binfo));
aggregate = 0;
}
else
@@ -2886,13 +3201,10 @@ finish_struct_1 (t, warn_anon)
max_has_virtual = has_virtual;
vfield = NULL_TREE;
vfields = NULL_TREE;
- last_x = NULL_TREE;
+ CLASSTYPE_RTTI (t) = NULL_TREE;
cant_have_default_ctor = 0;
cant_have_const_ctor = 0;
- cant_synth_copy_ctor = 0;
- cant_synth_asn_ref = 0;
no_const_asn_ref = 0;
- needs_virtual_dtor = 0;
}
#if 0
@@ -2908,19 +3220,17 @@ finish_struct_1 (t, warn_anon)
/* The three of these are approximations which may later be
modified. Needed at this point to make add_virtual_function
and modify_vtable_entries work. */
- TREE_CHAIN (t_binfo) = TYPE_BINFO (t);
- TYPE_BINFO (t) = t_binfo;
CLASSTYPE_VFIELDS (t) = vfields;
CLASSTYPE_VFIELD (t) = vfield;
if (IS_SIGNATURE (t))
all_virtual = 0;
- else if (flag_all_virtual == 1 && TYPE_OVERLOADS_METHOD_CALL_EXPR (t))
+ else if (flag_all_virtual == 1)
all_virtual = 1;
else
all_virtual = 0;
- for (x = CLASSTYPE_METHODS (t); x; x = TREE_CHAIN (x))
+ for (x = TYPE_METHODS (t); x; x = TREE_CHAIN (x))
{
GNU_xref_member (current_class_name, x);
@@ -2939,48 +3249,61 @@ finish_struct_1 (t, warn_anon)
DECL_SAVED_INSNS (x) = NULL_RTX;
DECL_FIELD_SIZE (x) = 0;
+ check_for_override (x, t);
+ if (DECL_ABSTRACT_VIRTUAL_P (x) && ! DECL_VINDEX (x))
+ cp_error_at ("initializer specified for non-virtual method `%D'", x);
+
/* The name of the field is the original field name
Save this in auxiliary field for later overloading. */
if (DECL_VINDEX (x)
|| (all_virtual == 1 && ! DECL_CONSTRUCTOR_P (x)))
{
- pending_virtuals = add_virtual_function (pending_virtuals,
- &has_virtual, x, t);
+ add_virtual_function (&pending_virtuals, &pending_hard_virtuals,
+ &has_virtual, x, t);
if (DECL_ABSTRACT_VIRTUAL_P (x))
abstract_virtuals = tree_cons (NULL_TREE, x, abstract_virtuals);
+#if 0
+ /* XXX Why did I comment this out? (jason) */
else
TREE_USED (x) = 1;
+#endif
}
}
- for (x = TYPE_FIELDS (t); x; x = TREE_CHAIN (x))
+ if (n_baseclasses)
+ fields = chainon (build_vbase_pointer_fields (t), fields);
+
+ last_x = NULL_TREE;
+ for (x = fields; x; x = TREE_CHAIN (x))
{
GNU_xref_member (current_class_name, x);
- /* Handle access declarations. */
- if (DECL_NAME (x) && TREE_CODE (DECL_NAME (x)) == SCOPE_REF)
+ if (TREE_CODE (x) == FIELD_DECL)
{
- tree fdecl = TREE_OPERAND (DECL_NAME (x), 1);
- enum access_type access
- = TREE_PRIVATE (x) ? access_private :
- TREE_PROTECTED (x) ? access_protected : access_public;
+ DECL_PACKED (x) |= TYPE_PACKED (t);
+ empty = 0;
+ }
+ if (TREE_CODE (x) == USING_DECL)
+ {
+ /* Save access declarations for later. */
if (last_x)
TREE_CHAIN (last_x) = TREE_CHAIN (x);
else
fields = TREE_CHAIN (x);
-
- access_decls = tree_cons ((tree) access, fdecl, access_decls);
+
+ access_decls = scratch_tree_cons (NULL_TREE, x, access_decls);
continue;
}
last_x = x;
- if (TREE_CODE (x) == TYPE_DECL)
+ if (TREE_CODE (x) == TYPE_DECL
+ || TREE_CODE (x) == TEMPLATE_DECL)
continue;
/* If we've gotten this far, it's a data member, possibly static,
- or an enumerator. */
+ or an enumerator. */
DECL_FIELD_CONTEXT (x) = t;
@@ -3009,7 +3332,7 @@ finish_struct_1 (t, warn_anon)
#if 0
if (DECL_NAME (x) == constructor_name (t))
- cant_have_default_ctor = cant_synth_copy_ctor = 1;
+ cant_have_default_ctor = 1;
#endif
if (TREE_TYPE (x) == error_mark_node)
@@ -3049,8 +3372,8 @@ finish_struct_1 (t, warn_anon)
aggregate, initialization by a brace-enclosed list) is the
only way to initialize nonstatic const and reference
members. */
- cant_synth_asn_ref = 1;
cant_have_default_ctor = 1;
+ TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
if (! TYPE_HAS_CONSTRUCTOR (t) && extra_warnings)
{
@@ -3061,6 +3384,9 @@ finish_struct_1 (t, warn_anon)
}
}
+ if (TREE_CODE (TREE_TYPE (x)) == POINTER_TYPE)
+ has_pointers = 1;
+
/* If any field is const, the structure type is pseudo-const. */
if (TREE_READONLY (x))
{
@@ -3072,8 +3398,8 @@ finish_struct_1 (t, warn_anon)
aggregate, initialization by a brace-enclosed list) is the
only way to initialize nonstatic const and reference
members. */
- cant_synth_asn_ref = 1;
cant_have_default_ctor = 1;
+ TYPE_HAS_COMPLEX_ASSIGN_REF (t) = 1;
if (! TYPE_HAS_CONSTRUCTOR (t) && !IS_SIGNATURE (t)
&& extra_warnings)
@@ -3118,9 +3444,26 @@ finish_struct_1 (t, warn_anon)
/* Detect and ignore out of range field width. */
if (DECL_INITIAL (x))
{
- register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
+ tree w = DECL_INITIAL (x);
+ register int width = 0;
+
+ /* Avoid the non_lvalue wrapper added by fold for PLUS_EXPRs. */
+ STRIP_NOPS (w);
- if (width < 0)
+ /* detect invalid field size. */
+ if (TREE_CODE (w) == CONST_DECL)
+ w = DECL_INITIAL (w);
+ else if (TREE_READONLY_DECL_P (w))
+ w = decl_constant_value (w);
+
+ if (TREE_CODE (w) != INTEGER_CST)
+ {
+ cp_error_at ("bit-field `%D' width not an integer constant",
+ x);
+ DECL_INITIAL (x) = NULL_TREE;
+ }
+ else if (width = TREE_INT_CST_LOW (w),
+ width < 0)
{
DECL_INITIAL (x) = NULL;
cp_error_at ("negative width in bit-field `%D'", x);
@@ -3141,7 +3484,8 @@ finish_struct_1 (t, warn_anon)
cp_error_at (" in declaration of `%D'", x);
}
else if (width > TYPE_PRECISION (TREE_TYPE (x))
- && TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE)
+ && TREE_CODE (TREE_TYPE (x)) != ENUMERAL_TYPE
+ && TREE_CODE (TREE_TYPE (x)) != BOOLEAN_TYPE)
{
cp_warning_at ("width of `%D' exceeds its type", x);
}
@@ -3154,23 +3498,13 @@ finish_struct_1 (t, warn_anon)
cp_warning_at ("`%D' is too small to hold all values of `%#T'",
x, TREE_TYPE (x));
}
- }
- /* Process valid field width. */
- if (DECL_INITIAL (x))
- {
- register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
-
- if (width == 0)
+ if (DECL_INITIAL (x) == NULL_TREE)
+ ;
+ else if (width == 0)
{
#ifdef EMPTY_FIELD_BOUNDARY
- /* field size 0 => mark following field as "aligned" */
- if (TREE_CHAIN (x))
- DECL_ALIGN (TREE_CHAIN (x))
- = MAX (DECL_ALIGN (TREE_CHAIN (x)), EMPTY_FIELD_BOUNDARY);
- /* field of size 0 at the end => round up the size. */
- else
- round_up_size = EMPTY_FIELD_BOUNDARY;
+ DECL_ALIGN (x) = MAX (DECL_ALIGN (x), EMPTY_FIELD_BOUNDARY);
#endif
#ifdef PCC_BITFIELD_TYPE_MATTERS
DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
@@ -3182,11 +3516,6 @@ finish_struct_1 (t, warn_anon)
DECL_INITIAL (x) = NULL_TREE;
DECL_FIELD_SIZE (x) = width;
DECL_BIT_FIELD (x) = 1;
- /* Traditionally a bit field is unsigned
- even if declared signed. */
- if (flag_traditional
- && TREE_CODE (TREE_TYPE (x)) == INTEGER_TYPE)
- TREE_TYPE (x) = unsigned_type_node;
}
}
else
@@ -3197,7 +3526,7 @@ finish_struct_1 (t, warn_anon)
{
tree type = TREE_TYPE (x);
- if (TREE_CODE (type) == ARRAY_TYPE)
+ while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
if (TYPE_LANG_SPECIFIC (type) && ! ANON_UNION_P (x)
@@ -3219,8 +3548,8 @@ finish_struct_1 (t, warn_anon)
fie = "constructor";
else if (TYPE_NEEDS_DESTRUCTOR (type))
fie = "destructor";
- else if (TYPE_HAS_REAL_ASSIGNMENT (type))
- fie = "assignment operator";
+ else if (TYPE_HAS_COMPLEX_ASSIGN_REF (type))
+ fie = "copy assignment operator";
if (fie)
cp_error_at ("member `%#D' with %s not allowed in union", x,
fie);
@@ -3233,18 +3562,10 @@ finish_struct_1 (t, warn_anon)
TYPE_HAS_COMPLEX_INIT_REF (t) |= TYPE_HAS_COMPLEX_INIT_REF (type);
}
- if (! TYPE_HAS_INIT_REF (type)
- || (TYPE_HAS_NONPUBLIC_CTOR (type)
- && ! is_friend (t, type)))
- cant_synth_copy_ctor = 1;
- else if (!TYPE_HAS_CONST_INIT_REF (type))
+ if (!TYPE_HAS_CONST_INIT_REF (type))
cant_have_const_ctor = 1;
- if (! TYPE_HAS_ASSIGN_REF (type)
- || (TYPE_HAS_NONPUBLIC_ASSIGN_REF (type)
- && ! is_friend (t, type)))
- cant_synth_asn_ref = 1;
- else if (!TYPE_HAS_CONST_ASSIGN_REF (type))
+ if (!TYPE_HAS_CONST_ASSIGN_REF (type))
no_const_asn_ref = 1;
if (TYPE_HAS_CONSTRUCTOR (type)
@@ -3294,41 +3615,50 @@ finish_struct_1 (t, warn_anon)
&& !IS_SIGNATURE (t))
{
/* Here we must cons up a destructor on the fly. */
- tree dtor = cons_up_default_function (t, name, needs_virtual_dtor != 0);
+ tree dtor = cons_up_default_function (t, name, 0);
+ check_for_override (dtor, t);
/* If we couldn't make it work, then pretend we didn't need it. */
if (dtor == void_type_node)
TYPE_NEEDS_DESTRUCTOR (t) = 0;
else
{
- /* Link dtor onto end of fn_fields. */
+ /* Link dtor onto end of fn_fields. */
TREE_CHAIN (dtor) = fn_fields;
fn_fields = dtor;
- if (DECL_VINDEX (dtor) == NULL_TREE
- && (needs_virtual_dtor
- || pending_virtuals != NULL_TREE
- || pending_hard_virtuals != NULL_TREE))
- DECL_VINDEX (dtor) = error_mark_node;
if (DECL_VINDEX (dtor))
- pending_virtuals = add_virtual_function (pending_virtuals,
- &has_virtual, dtor, t);
+ add_virtual_function (&pending_virtuals, &pending_hard_virtuals,
+ &has_virtual, dtor, t);
nonprivate_method = 1;
}
}
+ /* Effective C++ rule 11. */
+ if (has_pointers && warn_ecpp && TYPE_HAS_CONSTRUCTOR (t)
+ && ! (TYPE_HAS_INIT_REF (t) && TYPE_HAS_ASSIGN_REF (t)))
+ {
+ cp_warning ("`%#T' has pointer data members", t);
+
+ if (! TYPE_HAS_INIT_REF (t))
+ {
+ cp_warning (" but does not override `%T(const %T&)'", t, t);
+ if (! TYPE_HAS_ASSIGN_REF (t))
+ cp_warning (" or `operator=(const %T&)'", t);
+ }
+ else if (! TYPE_HAS_ASSIGN_REF (t))
+ cp_warning (" but does not override `operator=(const %T&)'", t);
+ }
+
TYPE_NEEDS_DESTRUCTOR (t) |= TYPE_HAS_DESTRUCTOR (t);
- if (flag_rtti && (max_has_virtual > 0 || needs_virtual_dtor) &&
- has_virtual == 0)
- has_virtual = 1;
TYPE_HAS_COMPLEX_INIT_REF (t)
|= (TYPE_HAS_INIT_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t)
- || any_default_members);
+ || has_virtual || any_default_members);
TYPE_NEEDS_CONSTRUCTING (t)
|= (TYPE_HAS_CONSTRUCTOR (t) || TYPE_USES_VIRTUAL_BASECLASSES (t)
- || has_virtual || any_default_members || first_vfn_base_index >= 0);
+ || has_virtual || any_default_members);
if (! IS_SIGNATURE (t))
CLASSTYPE_NON_AGGREGATE (t)
= ! aggregate || has_virtual || TYPE_HAS_CONSTRUCTOR (t);
@@ -3346,8 +3676,7 @@ finish_struct_1 (t, warn_anon)
}
/* Create default copy constructor, if needed. */
- if (! TYPE_HAS_INIT_REF (t) && ! cant_synth_copy_ctor
- && ! IS_SIGNATURE (t))
+ if (! TYPE_HAS_INIT_REF (t) && ! IS_SIGNATURE (t) && ! TYPE_FOR_JAVA (t))
{
/* ARM 12.18: You get either X(X&) or X(const X&), but
not both. --Chip */
@@ -3362,8 +3691,7 @@ finish_struct_1 (t, warn_anon)
TYPE_HAS_COMPLEX_ASSIGN_REF (t)
|= TYPE_HAS_ASSIGN_REF (t) || TYPE_USES_VIRTUAL_BASECLASSES (t);
- if (! TYPE_HAS_ASSIGN_REF (t) && ! cant_synth_asn_ref
- && ! IS_SIGNATURE (t))
+ if (! TYPE_HAS_ASSIGN_REF (t) && ! IS_SIGNATURE (t) && ! TYPE_FOR_JAVA (t))
{
tree default_fn = cons_up_default_function (t, name,
5 + no_const_asn_ref);
@@ -3373,19 +3701,20 @@ finish_struct_1 (t, warn_anon)
if (fn_fields)
{
+ TYPE_METHODS (t) = fn_fields;
method_vec = finish_struct_methods (t, fn_fields, nonprivate_method);
if (TYPE_HAS_CONSTRUCTOR (t)
&& CLASSTYPE_FRIEND_CLASSES (t) == NULL_TREE
- && DECL_FRIENDLIST (TYPE_NAME (t)) == NULL_TREE)
+ && DECL_FRIENDLIST (TYPE_MAIN_DECL (t)) == NULL_TREE)
{
int nonprivate_ctor = 0;
tree ctor;
for (ctor = TREE_VEC_ELT (method_vec, 0);
ctor;
- ctor = DECL_CHAIN (ctor))
- if (! TREE_PRIVATE (ctor))
+ ctor = OVL_NEXT (ctor))
+ if (! TREE_PRIVATE (OVL_CURRENT (ctor)))
{
nonprivate_ctor = 1;
break;
@@ -3406,68 +3735,9 @@ finish_struct_1 (t, warn_anon)
TYPE_HAS_DESTRUCTOR (t) = 0;
}
- {
- int n_methods = method_vec ? TREE_VEC_LENGTH (method_vec) : 0;
-
- for (access_decls = nreverse (access_decls); access_decls;
- access_decls = TREE_CHAIN (access_decls))
- {
- tree fdecl = TREE_VALUE (access_decls);
- tree flist = NULL_TREE;
- tree name;
- enum access_type access = (enum access_type)TREE_PURPOSE(access_decls);
- int i = TREE_VEC_ELT (method_vec, 0) ? 0 : 1;
- tree tmp;
-
- if (TREE_CODE (fdecl) == TREE_LIST)
- {
- flist = fdecl;
- fdecl = TREE_VALUE (flist);
- }
-
- name = DECL_NAME (fdecl);
-
- for (; i < n_methods; i++)
- if (DECL_NAME (TREE_VEC_ELT (method_vec, i)) == name)
- {
- cp_error ("cannot adjust access to `%#D' in `%#T'", fdecl, t);
- cp_error_at (" because of local method `%#D' with same name",
- TREE_VEC_ELT (method_vec, i));
- fdecl = NULL_TREE;
- break;
- }
-
- if (! fdecl)
- continue;
-
- for (tmp = fields; tmp; tmp = TREE_CHAIN (tmp))
- if (DECL_NAME (tmp) == name)
- {
- cp_error ("cannot adjust access to `%#D' in `%#T'", fdecl, t);
- cp_error_at (" because of local field `%#D' with same name", tmp);
- fdecl = NULL_TREE;
- break;
- }
-
- if (!fdecl)
- continue;
-
- /* Make type T see field decl FDECL with access ACCESS.*/
- if (flist)
- {
- fdecl = TREE_VALUE (flist);
- while (fdecl)
- {
- if (alter_access (t, fdecl, access) == 0)
- break;
- fdecl = DECL_CHAIN (fdecl);
- }
- }
- else
- alter_access (t, fdecl, access);
- }
-
- }
+ for (access_decls = nreverse (access_decls); access_decls;
+ access_decls = TREE_CHAIN (access_decls))
+ handle_using_decl (TREE_VALUE (access_decls), t, method_vec, fields);
if (vfield == NULL_TREE && has_virtual)
{
@@ -3477,23 +3747,26 @@ finish_struct_1 (t, warn_anon)
ptr_type_node);
/* If you change any of the below, take a look at all the
other VFIELD_BASEs and VTABLE_BASEs in the code, and change
- them too. */
+ them too. */
DECL_ASSEMBLER_NAME (vfield) = get_identifier (VFIELD_BASE);
CLASSTYPE_VFIELD (t) = vfield;
DECL_VIRTUAL_P (vfield) = 1;
+ DECL_ARTIFICIAL (vfield) = 1;
DECL_FIELD_CONTEXT (vfield) = t;
DECL_CLASS_CONTEXT (vfield) = t;
DECL_FCONTEXT (vfield) = t;
DECL_SAVED_INSNS (vfield) = NULL_RTX;
DECL_FIELD_SIZE (vfield) = 0;
DECL_ALIGN (vfield) = TYPE_ALIGN (ptr_type_node);
- if (CLASSTYPE_RTTI (t))
- {
- /* vfield is always first entry in structure. */
- TREE_CHAIN (vfield) = fields;
- fields = vfield;
- }
- else if (last_x)
+#if 0
+ /* This is more efficient, but breaks binary compatibility, turn
+ it on sometime when we don't care. If we turn it on, we also
+ have to enable the code in dfs_init_vbase_pointers. */
+ /* vfield is always first entry in structure. */
+ TREE_CHAIN (vfield) = fields;
+ fields = vfield;
+#else
+ if (last_x)
{
my_friendly_assert (TREE_CHAIN (last_x) == NULL_TREE, 175);
TREE_CHAIN (last_x) = vfield;
@@ -3501,6 +3774,8 @@ finish_struct_1 (t, warn_anon)
}
else
fields = vfield;
+#endif
+ empty = 0;
vfields = chainon (vfields, CLASSTYPE_AS_LIST (t));
}
@@ -3534,13 +3809,18 @@ finish_struct_1 (t, warn_anon)
for (x = fields; x; x = TREE_CHAIN (x))
{
tree name = DECL_NAME (x);
- int i = /*TREE_VEC_ELT (method_vec, 0) ? 0 : */ 1;
+ int i = 2;
+
+ if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x))
+ continue;
+
for (; i < n_methods; ++i)
- if (DECL_NAME (TREE_VEC_ELT (method_vec, i)) == name)
+ if (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, i)))
+ == name)
{
cp_error_at ("data member `%#D' conflicts with", x);
cp_error_at ("function member `%#D'",
- TREE_VEC_ELT (method_vec, i));
+ OVL_CURRENT (TREE_VEC_ELT (method_vec, i)));
break;
}
}
@@ -3551,114 +3831,65 @@ finish_struct_1 (t, warn_anon)
TYPE_FIELDS (t) = fields;
- /* If there's a :0 field at the end, round the size to the
- EMPTY_FIELD_BOUNDARY. */
- TYPE_ALIGN (t) = round_up_size;
-
- /* Pass layout information about base classes to layout_type, if any. */
if (n_baseclasses)
{
- tree pseudo_basetype = TREE_TYPE (base_layout_decl);
-
- TREE_CHAIN (base_layout_decl) = TYPE_FIELDS (t);
- TYPE_FIELDS (t) = base_layout_decl;
+ last_x = build_base_fields (t);
- TYPE_SIZE (pseudo_basetype) = CLASSTYPE_SIZE (t);
- TYPE_MODE (pseudo_basetype) = TYPE_MODE (t);
- TYPE_ALIGN (pseudo_basetype) = CLASSTYPE_ALIGN (t);
- DECL_ALIGN (base_layout_decl) = TYPE_ALIGN (pseudo_basetype);
- /* Don't re-use old size. */
- DECL_SIZE (base_layout_decl) = NULL_TREE;
+ /* If all our bases are empty, we can be empty too. */
+ for (x = last_x; empty && x; x = TREE_CHAIN (x))
+ if (DECL_SIZE (x) != integer_zero_node)
+ empty = 0;
}
+ if (empty)
+ {
+ /* C++: do not let empty structures exist. */
+ tree decl = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE, char_type_node);
+ TREE_CHAIN (decl) = fields;
+ TYPE_FIELDS (t) = decl;
+ }
+ if (n_baseclasses)
+ TYPE_FIELDS (t) = chainon (last_x, TYPE_FIELDS (t));
layout_type (t);
- {
- tree field;
- for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
- {
- if (TREE_STATIC (field))
- continue;
- if (TREE_CODE (field) != FIELD_DECL)
- continue;
-
- /* If this field is an anonymous union,
- give each union-member the same position as the union has.
-
- ??? This is a real kludge because it makes the structure
- of the types look strange. This feature is only used by
- C++, which should have build_component_ref build two
- COMPONENT_REF operations, one for the union and one for
- the inner field. We set the offset of this field to zero
- so that either the old or the correct method will work.
- Setting DECL_FIELD_CONTEXT is wrong unless the inner fields are
- moved into the type of this field, but nothing seems to break
- by doing this. */
-
- if (DECL_NAME (field) == NULL_TREE
- && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
- {
- tree uelt = TYPE_FIELDS (TREE_TYPE (field));
- for (; uelt; uelt = TREE_CHAIN (uelt))
- {
- if (TREE_CODE (uelt) != FIELD_DECL)
- continue;
-
- if (TREE_PRIVATE (uelt))
- cp_pedwarn_at ("private member `%#D' in anonymous union",
- uelt);
- else if (TREE_PROTECTED (uelt))
- cp_pedwarn_at ("protected member `%#D' in anonymous union",
- uelt);
-
- DECL_FIELD_CONTEXT (uelt) = DECL_FIELD_CONTEXT (field);
- DECL_FIELD_BITPOS (uelt) = DECL_FIELD_BITPOS (field);
- }
-
- DECL_FIELD_BITPOS (field) = integer_zero_node;
- }
- }
- }
-
- if (n_baseclasses)
- TYPE_FIELDS (t) = TREE_CHAIN (TYPE_FIELDS (t));
+ /* Remember the size and alignment of the class before adding
+ the virtual bases. */
+ if (empty && flag_new_abi)
+ CLASSTYPE_SIZE (t) = integer_zero_node;
+ else if (flag_new_abi && TYPE_HAS_COMPLEX_INIT_REF (t)
+ && TYPE_HAS_COMPLEX_ASSIGN_REF (t))
+ CLASSTYPE_SIZE (t) = TYPE_BINFO_SIZE (t);
+ else
+ CLASSTYPE_SIZE (t) = TYPE_SIZE (t);
+ CLASSTYPE_ALIGN (t) = TYPE_ALIGN (t);
- /* C++: do not let empty structures exist. */
- if (integer_zerop (TYPE_SIZE (t)))
- TYPE_SIZE (t) = TYPE_SIZE (char_type_node);
+ finish_struct_anon (t);
/* Set the TYPE_DECL for this type to contain the right
value for DECL_OFFSET, so that we can use it as part
of a COMPONENT_REF for multiple inheritance. */
- if (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL)
- layout_decl (TYPE_NAME (t), 0);
+ layout_decl (TYPE_MAIN_DECL (t), 0);
/* Now fix up any virtual base class types that we left lying
around. We must get these done before we try to lay out the
virtual function table. */
- doing_hard_virtuals = 1;
pending_hard_virtuals = nreverse (pending_hard_virtuals);
+ if (n_baseclasses)
+ /* layout_basetypes will remove the base subobject fields. */
+ max_has_virtual = layout_basetypes (t, max_has_virtual);
+ else if (empty)
+ TYPE_FIELDS (t) = fields;
+
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
{
tree vbases;
- max_has_virtual = layout_vbasetypes (t, max_has_virtual);
vbases = CLASSTYPE_VBASECLASSES (t);
CLASSTYPE_N_VBASECLASSES (t) = list_length (vbases);
- /* The rtti code should do this. (mrs) */
-#if 0
- while (vbases)
- {
- /* Update rtti info with offsets for virtual baseclasses. */
- if (flag_rtti && ! BINFO_NEW_VTABLE_MARKED (vbases))
- prepare_fresh_vtable (vbases, t);
- vbases = TREE_CHAIN (vbases);
- }
-#endif
-
{
/* Now fixup overrides of all functions in vtables from all
direct or indirect virtual base classes. */
@@ -3681,19 +3912,6 @@ finish_struct_1 (t, warn_anon)
}
}
}
-
- /* Now fixup any virtual function entries from virtual bases
- that have different deltas. */
- vbases = CLASSTYPE_VBASECLASSES (t);
- while (vbases)
- {
- /* We might be able to shorten the amount of work we do by
- only doing this for vtables that come from virtual bases
- that have differing offsets, but don't want to miss any
- entries. */
- fixup_vtable_deltas (vbases, 1, t);
- vbases = TREE_CHAIN (vbases);
- }
}
/* Set up the DECL_FIELD_BITPOS of the vfield if we need to, as we
@@ -3736,38 +3954,53 @@ finish_struct_1 (t, warn_anon)
TREE_VALUE (pending_hard_virtuals));
pending_hard_virtuals = TREE_CHAIN (pending_hard_virtuals);
}
- doing_hard_virtuals = 0;
+
+ if (TYPE_USES_VIRTUAL_BASECLASSES (t))
+ {
+ tree vbases;
+ /* Now fixup any virtual function entries from virtual bases
+ that have different deltas. This has to come after we do the
+ pending hard virtuals, as we might have a function that comes
+ from multiple virtual base instances that is only overridden
+ by a hard virtual above. */
+ vbases = CLASSTYPE_VBASECLASSES (t);
+ while (vbases)
+ {
+ /* We might be able to shorten the amount of work we do by
+ only doing this for vtables that come from virtual bases
+ that have differing offsets, but don't want to miss any
+ entries. */
+ fixup_vtable_deltas (vbases, 1, t);
+ vbases = TREE_CHAIN (vbases);
+ }
+ }
/* Under our model of GC, every C++ class gets its own virtual
function table, at least virtually. */
- if (pending_virtuals || (flag_rtti && TYPE_VIRTUAL_P (t)))
+ if (pending_virtuals)
{
pending_virtuals = nreverse (pending_virtuals);
/* We must enter these virtuals into the table. */
if (first_vfn_base_index < 0)
{
- /* The first slot is for the rtti offset. */
- pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals);
-
/* The second slot is for the tdesc pointer when thunks are used. */
if (flag_vtable_thunks)
pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals);
- set_rtti_entry (pending_virtuals, integer_zero_node, t);
+ /* The first slot is for the rtti offset. */
+ pending_virtuals = tree_cons (NULL_TREE, NULL_TREE, pending_virtuals);
+
+ set_rtti_entry (pending_virtuals,
+ convert (ssizetype, integer_zero_node), t);
build_vtable (NULL_TREE, t);
}
else
{
- tree offset;
/* Here we know enough to change the type of our virtual
function table, but we will wait until later this function. */
if (! BINFO_NEW_VTABLE_MARKED (TYPE_BINFO (t)))
build_vtable (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (t), first_vfn_base_index), t);
-
- offset = get_derived_offset (TYPE_BINFO (t), NULL_TREE);
- offset = size_binop (MINUS_EXPR, integer_zero_node, offset);
- set_rtti_entry (TYPE_BINFO_VIRTUALS (t), offset, t);
}
/* If this type has basetypes with constructors, then those
@@ -3877,42 +4110,6 @@ finish_struct_1 (t, warn_anon)
}
}
- /* Now add the tags, if any, to the list of TYPE_DECLs
- defined for this type. */
- if (CLASSTYPE_TAGS (t))
- {
- x = CLASSTYPE_TAGS (t);
- last_x = tree_last (TYPE_FIELDS (t));
- while (x)
- {
- tree tag = TYPE_NAME (TREE_VALUE (x));
-
- /* Check to see if it is already there. This will be the case if
- was do enum { red; } color; */
- if (chain_member (tag, TYPE_FIELDS (t)))
- {
- x = TREE_CHAIN (x);
- continue;
- }
-
-#ifdef DWARF_DEBUGGING_INFO
- if (write_symbols == DWARF_DEBUG)
- {
- /* Notify dwarfout.c that this TYPE_DECL node represent a
- gratuitous typedef. */
- DECL_IGNORED_P (tag) = 1;
- }
-#endif /* DWARF_DEBUGGING_INFO */
-
- TREE_NONLOCAL_FLAG (TREE_VALUE (x)) = 0;
- x = TREE_CHAIN (x);
- last_x = chainon (last_x, tag);
- }
- if (TYPE_FIELDS (t) == NULL_TREE)
- TYPE_FIELDS (t) = last_x;
- CLASSTYPE_LOCAL_TYPEDECLS (t) = 1;
- }
-
if (TYPE_HAS_CONSTRUCTOR (t))
{
tree vfields = CLASSTYPE_VFIELDS (t);
@@ -3932,9 +4129,6 @@ finish_struct_1 (t, warn_anon)
else if (TYPE_NEEDS_CONSTRUCTING (t))
build_class_init_list (t);
- if (! IS_SIGNATURE (t))
- embrace_waiting_friends (t);
-
/* Write out inline function definitions. */
do_inline_function_hair (t, CLASSTYPE_INLINE_FRIENDS (t));
CLASSTYPE_INLINE_FRIENDS (t) = 0;
@@ -3942,7 +4136,7 @@ finish_struct_1 (t, warn_anon)
if (CLASSTYPE_VSIZE (t) != 0)
{
#if 0
- /* This is now done above. */
+ /* This is now done above. */
if (DECL_FIELD_CONTEXT (vfield) != t)
{
tree binfo = get_binfo (DECL_FIELD_CONTEXT (vfield), t, 0);
@@ -3961,13 +4155,13 @@ finish_struct_1 (t, warn_anon)
}
#endif
- /* In addition to this one, all the other vfields should be listed. */
+ /* In addition to this one, all the other vfields should be listed. */
/* Before that can be done, we have to have FIELD_DECLs for them, and
a place to find them. */
TYPE_NONCOPIED_PARTS (t) = build_tree_list (default_conversion (TYPE_BINFO_VTABLE (t)), vfield);
if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (t)
- && DECL_VINDEX (TREE_VEC_ELT (method_vec, 0)) == NULL_TREE)
+ && DECL_VINDEX (TREE_VEC_ELT (method_vec, 1)) == NULL_TREE)
cp_warning ("`%#T' has virtual functions but non-virtual destructor",
t);
}
@@ -3975,22 +4169,17 @@ finish_struct_1 (t, warn_anon)
/* Make the rtl for any new vtables we have created, and unmark
the base types we marked. */
finish_vtbls (TYPE_BINFO (t), 1, t);
- TYPE_BEING_DEFINED (t) = 0;
hack_incomplete_structures (t);
#if 0
if (TYPE_NAME (t) && TYPE_IDENTIFIER (t))
undo_template_name_overload (TYPE_IDENTIFIER (t), 1);
#endif
- if (current_class_type)
- popclass (0);
- else
- error ("trying to finish struct, but kicked out due to previous parse errors.");
resume_momentary (old);
- if (flag_cadillac)
- cadillac_finish_struct (t);
+ if (warn_overloaded_virtual)
+ warn_hidden (t);
#if 0
/* This has to be done after we have sorted out what to do with
@@ -3999,13 +4188,12 @@ finish_struct_1 (t, warn_anon)
{
/* Be smarter about nested classes here. If a type is nested,
only output it if we would output the enclosing type. */
- if (DECL_CONTEXT (TYPE_NAME (t))
- && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (TYPE_NAME (t)))) == 't')
- DECL_IGNORED_P (TYPE_NAME (t)) = TREE_ASM_WRITTEN (TYPE_NAME (t));
+ if (DECL_CLASS_SCOPE_P (TYPE_MAIN_DECL (t)))
+ DECL_IGNORED_P (TYPE_MAIN_DECL (t)) = TREE_ASM_WRITTEN (TYPE_MAIN_DECL (t));
}
#endif
- if (write_symbols != DWARF_DEBUG)
+ if (write_symbols != DWARF_DEBUG && write_symbols != DWARF2_DEBUG)
{
/* If the type has methods, we want to think about cutting down
the amount of symbol table stuff we output. The value stored in
@@ -4013,7 +4201,10 @@ finish_struct_1 (t, warn_anon)
For example, if a member function is seen and we decide to
write out that member function, then we can change the value
of the DECL_IGNORED_P slot, and the type will be output when
- that member function's debug info is written out. */
+ that member function's debug info is written out.
+
+ We can't do this with DWARF, which does not support name
+ references between translation units. */
if (CLASSTYPE_METHOD_VEC (t))
{
extern tree pending_vtables;
@@ -4021,16 +4212,19 @@ finish_struct_1 (t, warn_anon)
/* Don't output full info about any type
which does not have its implementation defined here. */
if (TYPE_VIRTUAL_P (t) && write_virtuals == 2)
- TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t))
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t))
= (value_member (TYPE_IDENTIFIER (t), pending_vtables) == 0);
else if (CLASSTYPE_INTERFACE_ONLY (t))
- TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 1;
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+#if 0
+ /* XXX do something about this. */
else if (CLASSTYPE_INTERFACE_UNKNOWN (t))
/* Only a first approximation! */
- TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 1;
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+#endif
}
else if (CLASSTYPE_INTERFACE_ONLY (t))
- TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 1;
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
}
/* Finish debugging output for this type. */
@@ -4040,16 +4234,19 @@ finish_struct_1 (t, warn_anon)
}
tree
-finish_struct (t, list_of_fieldlists, warn_anon)
- tree t;
- tree list_of_fieldlists;
+finish_struct (t, list_of_fieldlists, attributes, warn_anon)
+ tree t, list_of_fieldlists, attributes;
int warn_anon;
{
- tree fields = NULL_TREE, fn_fields, *tail;
- tree *tail_user_methods = &CLASSTYPE_METHODS (t);
+ tree fields = NULL_TREE;
+ tree *tail = &TYPE_METHODS (t);
+ tree specializations = NULL_TREE;
+ tree *specialization_tail = &specializations;
tree name = TYPE_NAME (t);
tree x, last_x = NULL_TREE;
- enum access_type access;
+ tree access;
+ tree dummy = NULL_TREE;
+ tree next_x = NULL_TREE;
if (TREE_CODE (name) == TYPE_DECL)
{
@@ -4071,34 +4268,53 @@ finish_struct (t, list_of_fieldlists, warn_anon)
if (IS_SIGNATURE (t))
append_signature_fields (list_of_fieldlists);
- tail = &fn_fields;
- if (last_x && list_of_fieldlists)
- TREE_CHAIN (last_x) = TREE_VALUE (list_of_fieldlists);
-
- /* For signatures, we made all methods `public' in the parser and
- reported an error if a access specifier was used. */
- if (CLASSTYPE_DECLARED_CLASS (t) == 0)
+ /* Move our self-reference declaration to the end of the field list so
+ any real field with the same name takes precedence. */
+ if (list_of_fieldlists
+ && TREE_VALUE (list_of_fieldlists)
+ && DECL_ARTIFICIAL (TREE_VALUE (list_of_fieldlists)))
{
- if (list_of_fieldlists
- && TREE_PURPOSE (list_of_fieldlists) == (tree)access_default)
- TREE_PURPOSE (list_of_fieldlists) = (tree)access_public;
+ dummy = TREE_VALUE (list_of_fieldlists);
+ list_of_fieldlists = TREE_CHAIN (list_of_fieldlists);
}
- else if (list_of_fieldlists
- && TREE_PURPOSE (list_of_fieldlists) == (tree)access_default)
- TREE_PURPOSE (list_of_fieldlists) = (tree)access_private;
+
+ if (last_x && list_of_fieldlists)
+ TREE_CHAIN (last_x) = TREE_VALUE (list_of_fieldlists);
while (list_of_fieldlists)
{
- access = (enum access_type)TREE_PURPOSE (list_of_fieldlists);
+ access = TREE_PURPOSE (list_of_fieldlists);
+
+ /* For signatures, we made all methods `public' in the parser and
+ reported an error if a access specifier was used. */
+ if (access == access_default_node)
+ {
+ if (CLASSTYPE_DECLARED_CLASS (t) == 0)
+ access = access_public_node;
+ else
+ access = access_private_node;
+ }
- for (x = TREE_VALUE (list_of_fieldlists); x; x = TREE_CHAIN (x))
+ for (x = TREE_VALUE (list_of_fieldlists); x; x = next_x)
{
- TREE_PRIVATE (x) = access == access_private;
- TREE_PROTECTED (x) = access == access_protected;
+ next_x = TREE_CHAIN (x);
+
+ TREE_PRIVATE (x) = access == access_private_node;
+ TREE_PROTECTED (x) = access == access_protected_node;
+
+ if (TREE_CODE (x) == TEMPLATE_DECL)
+ {
+ TREE_PRIVATE (DECL_RESULT (x)) = TREE_PRIVATE (x);
+ TREE_PROTECTED (DECL_RESULT (x)) = TREE_PROTECTED (x);
+ }
+
+ /* A name N used in a class S shall refer to the same declaration
+ in its context and when re-evaluated in the completed scope of S.
- /* Check for inconsistent use of this name in the class body.
Enums, types and static vars have already been checked. */
- if (TREE_CODE (x) != TYPE_DECL
+ if (TREE_CODE (x) != TYPE_DECL && TREE_CODE (x) != USING_DECL
+ && ! (TREE_CODE (x) == TEMPLATE_DECL
+ && TREE_CODE (DECL_RESULT (x)) == TYPE_DECL)
&& TREE_CODE (x) != CONST_DECL && TREE_CODE (x) != VAR_DECL)
{
tree name = DECL_NAME (x);
@@ -4111,6 +4327,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
icv = NULL_TREE;
if (icv
+ && flag_optional_diags
/* Don't complain about constructors. */
&& name != constructor_name (current_class_type)
/* Or inherited names. */
@@ -4119,35 +4336,42 @@ finish_struct (t, list_of_fieldlists, warn_anon)
&& !(TREE_CODE (icv) == TYPE_DECL
&& DECL_CONTEXT (icv) == t))
{
- cp_error_at ("declaration of identifier `%D' as `%+#D'",
- name, x);
- cp_error_at ("conflicts with other use in class as `%#D'",
- icv);
+ cp_pedwarn_at ("declaration of identifier `%D' as `%+#D'",
+ name, x);
+ cp_pedwarn_at ("conflicts with other use in class as `%#D'",
+ icv);
}
}
- if (TREE_CODE (x) == FUNCTION_DECL)
+ if (TREE_CODE (x) == FUNCTION_DECL
+ || DECL_FUNCTION_TEMPLATE_P (x))
{
+ DECL_CLASS_CONTEXT (x) = t;
+
if (last_x)
- TREE_CHAIN (last_x) = TREE_CHAIN (x);
- /* Link x onto end of fn_fields and CLASSTYPE_METHODS. */
+ TREE_CHAIN (last_x) = next_x;
+
+ if (DECL_TEMPLATE_SPECIALIZATION (x))
+ /* We don't enter the specialization into the class
+ method vector since specializations don't affect
+ overloading. Instead we keep track of the
+ specializations, and process them after the method
+ vector is complete. */
+ {
+ *specialization_tail = x;
+ specialization_tail = &TREE_CHAIN (x);
+ TREE_CHAIN (x) = NULL_TREE;
+ continue;
+ }
+
+ /* Link x onto end of TYPE_METHODS. */
*tail = x;
tail = &TREE_CHAIN (x);
- *tail_user_methods = x;
- tail_user_methods = &DECL_NEXT_METHOD (x);
continue;
}
-#if 0
- /* Handle access declarations. */
- if (DECL_NAME (x) && TREE_CODE (DECL_NAME (x)) == SCOPE_REF)
- {
- tree n = DECL_NAME (x);
- x = build_decl
- (USING_DECL, DECL_NAME (TREE_OPERAND (n, 1)), TREE_TYPE (x));
- DECL_RESULT (x) = n;
- }
-#endif
+ if (TREE_CODE (x) != TYPE_DECL)
+ DECL_FIELD_CONTEXT (x) = t;
if (! fields)
fields = x;
@@ -4166,17 +4390,122 @@ finish_struct (t, list_of_fieldlists, warn_anon)
}
}
+ /* Now add the tags, if any, to the list of TYPE_DECLs
+ defined for this type. */
+ if (CLASSTYPE_TAGS (t) || dummy)
+ {
+ /* The list of tags was built up in pushtag in reverse order; we need
+ to fix that so that enumerators will be processed in forward order
+ in template instantiation. */
+ CLASSTYPE_TAGS (t) = x = nreverse (CLASSTYPE_TAGS (t));
+ while (x)
+ {
+ tree tag_type = TREE_VALUE (x);
+ tree tag = TYPE_MAIN_DECL (TREE_VALUE (x));
+
+ if (IS_AGGR_TYPE_CODE (TREE_CODE (tag_type))
+ && CLASSTYPE_IS_TEMPLATE (tag_type))
+ tag = CLASSTYPE_TI_TEMPLATE (tag_type);
+
+ TREE_NONLOCAL_FLAG (tag_type) = 0;
+ x = TREE_CHAIN (x);
+ last_x = chainon (last_x, tag);
+ }
+ if (dummy)
+ last_x = chainon (last_x, dummy);
+ if (fields == NULL_TREE)
+ fields = last_x;
+ CLASSTYPE_LOCAL_TYPEDECLS (t) = 1;
+ }
+
*tail = NULL_TREE;
- *tail_user_methods = NULL_TREE;
TYPE_FIELDS (t) = fields;
- if (0 && processing_template_defn)
+ cplus_decl_attributes (t, attributes, NULL_TREE);
+
+ if (processing_template_decl)
{
- CLASSTYPE_METHOD_VEC (t) = finish_struct_methods (t, fn_fields, 1);
- return t;
+ tree d = getdecls ();
+ for (; d; d = TREE_CHAIN (d))
+ {
+ /* If this is the decl for the class or one of the template
+ parms, we've seen all the injected decls. */
+ if ((TREE_CODE (d) == TYPE_DECL
+ && (TREE_TYPE (d) == t
+ || TREE_CODE (TREE_TYPE (d)) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (TREE_TYPE (d)) == TEMPLATE_TEMPLATE_PARM))
+ || TREE_CODE (d) == CONST_DECL)
+ break;
+ /* Don't inject cache decls. */
+ else if (IDENTIFIER_TEMPLATE (DECL_NAME (d)))
+ continue;
+ DECL_TEMPLATE_INJECT (CLASSTYPE_TI_TEMPLATE (t))
+ = tree_cons (NULL_TREE, d,
+ DECL_TEMPLATE_INJECT (CLASSTYPE_TI_TEMPLATE (t)));
+ }
+ CLASSTYPE_METHOD_VEC (t)
+ = finish_struct_methods (t, TYPE_METHODS (t), 1);
+ TYPE_SIZE (t) = integer_zero_node;
+ }
+ else
+ t = finish_struct_1 (t, warn_anon);
+
+ TYPE_BEING_DEFINED (t) = 0;
+
+ /* Now, figure out which member templates we're specializing. */
+ for (x = specializations; x != NULL_TREE; x = TREE_CHAIN (x))
+ {
+ tree spec_args;
+ tree fn;
+ int pending_specialization;
+
+ if (uses_template_parms (t))
+ /* If t is a template class, and x is a specialization, then x
+ is itself really a template. Due to the vagaries of the
+ parser, however, we will have a handle to a function
+ declaration, rather than the template declaration, at this
+ point. */
+ {
+ my_friendly_assert (DECL_TEMPLATE_INFO (x) != NULL_TREE, 0);
+ my_friendly_assert (DECL_TI_TEMPLATE (x) != NULL_TREE, 0);
+ fn = DECL_TI_TEMPLATE (x);
+ }
+ else
+ fn = x;
+
+ /* We want the specialization arguments, which will be the
+ innermost ones. */
+ if (DECL_TI_ARGS (fn) && TREE_CODE (DECL_TI_ARGS (fn)) == TREE_VEC)
+ spec_args
+ = TREE_VEC_ELT (DECL_TI_ARGS (fn), 0);
+ else
+ spec_args = DECL_TI_ARGS (fn);
+
+ pending_specialization
+ = TI_PENDING_SPECIALIZATION_FLAG (DECL_TEMPLATE_INFO (fn));
+ check_explicit_specialization
+ (lookup_template_function (DECL_NAME (fn), spec_args),
+ fn, 0, 1 | (8 * pending_specialization));
+ TI_PENDING_SPECIALIZATION_FLAG (DECL_TEMPLATE_INFO (fn)) = 0;
+
+ /* Now, the assembler name will be correct for fn, so we
+ make its RTL. */
+ DECL_RTL (fn) = 0;
+ make_decl_rtl (fn, NULL_PTR, 1);
+
+ if (x != fn)
+ {
+ DECL_RTL (x) = 0;
+ make_decl_rtl (x, NULL_PTR, 1);
+ }
}
+
+ if (current_class_type)
+ popclass (0);
else
- return finish_struct_1 (t, warn_anon);
+ error ("trying to finish struct, but kicked out due to previous parse errors.");
+
+ return t;
}
/* Return non-zero if the effective type of INSTANCE is static.
@@ -4185,6 +4514,7 @@ finish_struct (t, list_of_fieldlists, warn_anon)
*NONNULL is set iff INSTANCE can be known to be nonnull, regardless
of our knowledge of its type. */
+
int
resolves_to_fixed_type_p (instance, nonnull)
tree instance;
@@ -4219,13 +4549,6 @@ resolves_to_fixed_type_p (instance, nonnull)
return resolves_to_fixed_type_p (TREE_OPERAND (instance, 0), nonnull);
case RTL_EXPR:
- /* This is a call to `new', hence it's never zero. */
- if (TREE_CALLS_NEW (instance))
- {
- if (nonnull)
- *nonnull = 1;
- return 1;
- }
return 0;
case PLUS_EXPR:
@@ -4249,10 +4572,6 @@ resolves_to_fixed_type_p (instance, nonnull)
case COMPONENT_REF:
return resolves_to_fixed_type_p (TREE_OPERAND (instance, 1), nonnull);
- case WITH_CLEANUP_EXPR:
- if (TREE_CODE (TREE_OPERAND (instance, 0)) == ADDR_EXPR)
- return resolves_to_fixed_type_p (TREE_OPERAND (instance, 0), nonnull);
- /* fall through... */
case VAR_DECL:
case FIELD_DECL:
if (TREE_CODE (TREE_TYPE (instance)) == ARRAY_TYPE
@@ -4262,7 +4581,7 @@ resolves_to_fixed_type_p (instance, nonnull)
*nonnull = 1;
return 1;
}
- /* fall through... */
+ /* fall through... */
case TARGET_EXPR:
case PARM_DECL:
if (IS_AGGR_TYPE (TREE_TYPE (instance)))
@@ -4273,7 +4592,7 @@ resolves_to_fixed_type_p (instance, nonnull)
}
else if (nonnull)
{
- if (instance == current_class_decl
+ if (instance == current_class_ptr
&& flag_this_is_variable <= 0)
{
/* Some people still use `this = 0' inside destructors. */
@@ -4305,8 +4624,16 @@ init_class_processing ()
current_lang_base = (tree *)xmalloc(current_lang_stacksize * sizeof (tree));
current_lang_stack = current_lang_base;
+ access_default_node = build_int_2 (0, 0);
+ access_public_node = build_int_2 (1, 0);
+ access_protected_node = build_int_2 (2, 0);
+ access_private_node = build_int_2 (3, 0);
+ access_default_virtual_node = build_int_2 (4, 0);
+ access_public_virtual_node = build_int_2 (5, 0);
+ access_protected_virtual_node = build_int_2 (6, 0);
+ access_private_virtual_node = build_int_2 (7, 0);
+
/* Keep these values lying around. */
- the_null_vtable_entry = build_vtable_entry (integer_zero_node, integer_zero_node);
base_layout_decl = build_lang_field_decl (FIELD_DECL, NULL_TREE, error_mark_node);
TREE_TYPE (base_layout_decl) = make_node (RECORD_TYPE);
@@ -4352,6 +4679,7 @@ pushclass (type, modify)
tree type;
int modify;
{
+ type = TYPE_MAIN_VARIANT (type);
push_memoized_context (type, modify);
current_class_depth++;
@@ -4359,9 +4687,9 @@ pushclass (type, modify)
*current_class_stack++ = current_class_type;
if (current_class_stack >= current_class_base + current_class_stacksize)
{
- current_class_base =
- (tree *)xrealloc (current_class_base,
- sizeof (tree) * (current_class_stacksize + 10));
+ current_class_base
+ = (tree *)xrealloc (current_class_base,
+ sizeof (tree) * (current_class_stacksize + 10));
current_class_stack = current_class_base + current_class_stacksize;
current_class_stacksize += 10;
}
@@ -4382,6 +4710,11 @@ pushclass (type, modify)
pushlevel_class ();
+#if 0
+ if (CLASSTYPE_TEMPLATE_INFO (type))
+ overload_template_name (type);
+#endif
+
if (modify)
{
tree tags;
@@ -4394,15 +4727,15 @@ pushclass (type, modify)
else
current_function_decl = NULL_TREE;
- if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
- declare_uninstantiated_type_level ();
- else if (type != previous_class_type || current_class_depth > 1)
+ if (type != previous_class_type || current_class_depth > 1)
{
+#ifdef MI_MATRIX
build_mi_matrix (type);
push_class_decls (type);
free_mi_matrix ();
- if (current_class_depth == 1)
- previous_class_type = type;
+#else
+ push_class_decls (type);
+#endif
}
else
{
@@ -4423,35 +4756,33 @@ pushclass (type, modify)
unuse_fields (type);
}
- if (IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (type)))
- overload_template_name (current_class_name, 0);
-
for (tags = CLASSTYPE_TAGS (type); tags; tags = TREE_CHAIN (tags))
{
- TREE_NONLOCAL_FLAG (TREE_VALUE (tags)) = 1;
+ tree tag_type = TREE_VALUE (tags);
+
+ TREE_NONLOCAL_FLAG (tag_type) = 1;
if (! TREE_PURPOSE (tags))
continue;
- pushtag (TREE_PURPOSE (tags), TREE_VALUE (tags), 0);
+ if (! (IS_AGGR_TYPE_CODE (TREE_CODE (tag_type))
+ && CLASSTYPE_IS_TEMPLATE (tag_type)))
+ pushtag (TREE_PURPOSE (tags), tag_type, 0);
+ else
+ pushdecl_class_level (CLASSTYPE_TI_TEMPLATE (tag_type));
}
current_function_decl = this_fndecl;
}
-
- if (flag_cadillac)
- cadillac_push_class (type);
}
/* Get out of the current class scope. If we were in a class scope
previously, that is the one popped to. The flag MODIFY tells whether
the current scope declarations needs to be modified as a result of
popping to the previous scope. 0 is used for class definitions. */
+
void
popclass (modify)
int modify;
{
- if (flag_cadillac)
- cadillac_pop_class ();
-
if (modify < 0)
{
/* Back this old class out completely. */
@@ -4482,8 +4813,6 @@ popclass (modify)
TREE_NONLOCAL_FLAG (TREE_VALUE (tags)) = 0;
tags = TREE_CHAIN (tags);
}
- if (IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (current_class_type)))
- undo_template_name_overload (current_class_name, 0);
}
/* Force clearing of IDENTIFIER_CLASS_VALUEs after a class definition,
@@ -4494,7 +4823,7 @@ popclass (modify)
this really only frees the obstack used for these decls.
That's why it had to be moved down here. */
if (modify)
- pop_class_decls (current_class_type);
+ pop_class_decls ();
current_class_depth--;
current_class_type = *--current_class_stack;
@@ -4506,6 +4835,21 @@ popclass (modify)
;
}
+/* Returns 1 if current_class_type is either T or a nested type of T. */
+
+int
+currently_open_class (t)
+ tree t;
+{
+ int i;
+ if (t == current_class_type)
+ return 1;
+ for (i = 0; i < current_class_depth; ++i)
+ if (current_class_stack [-i*2 - 1] == t)
+ return 1;
+ return 0;
+}
+
/* When entering a class scope, all enclosing class scopes' names with
static meaning (static variables, static functions, types and enumerators)
have to be visible. This recursive function calls pushclass for all
@@ -4520,10 +4864,14 @@ push_nested_class (type, modify)
{
tree context;
- if (type == NULL_TREE || type == error_mark_node || ! IS_AGGR_TYPE (type))
+ my_friendly_assert (!type || TREE_CODE (type) != NAMESPACE_DECL, 980711);
+
+ if (type == NULL_TREE || type == error_mark_node || ! IS_AGGR_TYPE (type)
+ || TREE_CODE (type) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
return;
- context = DECL_CONTEXT (TYPE_NAME (type));
+ context = DECL_CONTEXT (TYPE_MAIN_DECL (type));
if (context && TREE_CODE (context) == RECORD_TYPE)
push_nested_class (context, 2);
@@ -4536,7 +4884,7 @@ void
pop_nested_class (modify)
int modify;
{
- tree context = DECL_CONTEXT (TYPE_NAME (current_class_type));
+ tree context = DECL_CONTEXT (TYPE_MAIN_DECL (current_class_type));
popclass (modify);
if (context && TREE_CODE (context) == RECORD_TYPE)
@@ -4553,14 +4901,14 @@ push_lang_context (name)
*current_lang_stack++ = current_lang_name;
if (current_lang_stack >= current_lang_base + current_lang_stacksize)
{
- current_lang_base =
- (tree *)xrealloc (current_lang_base,
- sizeof (tree) * (current_lang_stacksize + 10));
+ current_lang_base
+ = (tree *)xrealloc (current_lang_base,
+ sizeof (tree) * (current_lang_stacksize + 10));
current_lang_stack = current_lang_base + current_lang_stacksize;
current_lang_stacksize += 10;
}
- if (name == lang_name_cplusplus)
+ if (name == lang_name_cplusplus || name == lang_name_java)
{
strict_prototype = strict_prototypes_lang_cplusplus;
current_lang_name = name;
@@ -4572,44 +4920,64 @@ push_lang_context (name)
}
else
error ("language string `\"%s\"' not recognized", IDENTIFIER_POINTER (name));
-
- if (flag_cadillac)
- cadillac_push_lang (name);
}
/* Get out of the current language scope. */
+
void
pop_lang_context ()
{
- if (flag_cadillac)
- cadillac_pop_lang ();
-
current_lang_name = *--current_lang_stack;
- if (current_lang_name == lang_name_cplusplus)
+ if (current_lang_name == lang_name_cplusplus
+ || current_lang_name == lang_name_java)
strict_prototype = strict_prototypes_lang_cplusplus;
else if (current_lang_name == lang_name_c)
strict_prototype = strict_prototypes_lang_c;
}
+
+/* Type instantiation routines. */
-int
-root_lang_context_p ()
+static tree
+validate_lhs (lhstype, complain)
+ tree lhstype;
+ int complain;
{
- return current_lang_stack == current_lang_base;
+ if (TYPE_PTRMEMFUNC_P (lhstype))
+ lhstype = TYPE_PTRMEMFUNC_FN_TYPE (lhstype);
+
+ if (TREE_CODE (lhstype) == POINTER_TYPE)
+ {
+ if (TREE_CODE (TREE_TYPE (lhstype)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (lhstype)) == METHOD_TYPE)
+ lhstype = TREE_TYPE (lhstype);
+ else
+ {
+ if (complain)
+ error ("invalid type combination for overload");
+ return error_mark_node;
+ }
+ }
+ return lhstype;
}
-
-/* Type instantiation routines. */
-/* This function will instantiate the type of the expression given
- in RHS to match the type of LHSTYPE. If LHSTYPE is NULL_TREE,
- or other errors exist, the TREE_TYPE of RHS will be ERROR_MARK_NODE.
+/* This function will instantiate the type of the expression given in
+ RHS to match the type of LHSTYPE. If errors exist, then return
+ error_mark_node. If only complain is COMPLAIN is set. If we are
+ not complaining, never modify rhs, as overload resolution wants to
+ try many possible instantiations, in hopes that at least one will
+ work.
This function is used in build_modify_expr, convert_arguments,
build_c_cast, and compute_conversion_costs. */
+
tree
instantiate_type (lhstype, rhs, complain)
tree lhstype, rhs;
int complain;
{
+ tree explicit_targs = NULL_TREE;
+ int template_only = 0;
+
if (TREE_CODE (lhstype) == UNKNOWN_TYPE)
{
if (complain)
@@ -4618,7 +4986,19 @@ instantiate_type (lhstype, rhs, complain)
}
if (TREE_TYPE (rhs) != NULL_TREE && ! (type_unknown_p (rhs)))
- return rhs;
+ {
+ if (comptypes (lhstype, TREE_TYPE (rhs), 1))
+ return rhs;
+ if (complain)
+ cp_error ("argument of type `%T' does not match `%T'",
+ TREE_TYPE (rhs), lhstype);
+ return error_mark_node;
+ }
+
+ /* We don't overwrite rhs if it is an overloaded function.
+ Copying it would destroy the tree link. */
+ if (TREE_CODE (rhs) != OVERLOAD)
+ rhs = copy_node (rhs);
/* This should really only be used when attempting to distinguish
what sort of a pointer to function we have. For now, any
@@ -4637,14 +5017,18 @@ instantiate_type (lhstype, rhs, complain)
case INDIRECT_REF:
case ARRAY_REF:
- TREE_TYPE (rhs) = lhstype;
- lhstype = build_pointer_type (lhstype);
- TREE_OPERAND (rhs, 0)
- = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
- if (TREE_OPERAND (rhs, 0) == error_mark_node)
- return error_mark_node;
+ {
+ tree new_rhs;
- return rhs;
+ new_rhs = instantiate_type (build_pointer_type (lhstype),
+ TREE_OPERAND (rhs, 0), complain);
+ if (new_rhs == error_mark_node)
+ return error_mark_node;
+
+ TREE_TYPE (rhs) = lhstype;
+ TREE_OPERAND (rhs, 0) = new_rhs;
+ return rhs;
+ }
case NOP_EXPR:
rhs = copy_node (TREE_OPERAND (rhs, 0));
@@ -4671,9 +5055,13 @@ instantiate_type (lhstype, rhs, complain)
return error_mark_node;
return build_vfn_ref (&base_ptr, base, DECL_VINDEX (function));
}
+ mark_used (function);
return function;
}
+ /* I could not trigger this code. MvL */
+ my_friendly_abort (980326);
+#if 0
my_friendly_assert (TREE_CODE (field) == FIELD_DECL, 178);
my_friendly_assert (!(TREE_CODE (TREE_TYPE (field)) == FUNCTION_TYPE
|| TREE_CODE (TREE_TYPE (field)) == METHOD_TYPE),
@@ -4687,6 +5075,7 @@ instantiate_type (lhstype, rhs, complain)
if (field)
{
TREE_OPERAND (rhs, 1) = field;
+ mark_used (field);
return rhs;
}
@@ -4713,144 +5102,194 @@ instantiate_type (lhstype, rhs, complain)
error ("no appropriate overload exists for COMPONENT_REF");
return error_mark_node;
}
+#endif
return rhs;
}
- case TREE_LIST:
- {
- tree elem, baselink, name;
- int globals = overloaded_globals_p (rhs);
+ case OFFSET_REF:
+ /* This can happen if we are forming a pointer-to-member for a
+ member template. */
+ rhs = TREE_OPERAND (rhs, 1);
+ my_friendly_assert (TREE_CODE (rhs) == TEMPLATE_ID_EXPR, 0);
+
+ /* Fall through. */
-#if 0 /* obsolete */
- /* If there's only one function we know about, return that. */
- if (globals > 0 && TREE_CHAIN (rhs) == NULL_TREE)
- return TREE_VALUE (rhs);
-#endif
+ case TEMPLATE_ID_EXPR:
+ {
+ explicit_targs = TREE_OPERAND (rhs, 1);
+ template_only = 1;
+ rhs = TREE_OPERAND (rhs, 0);
+ }
+ /* fall through */
+ my_friendly_assert (TREE_CODE (rhs) == OVERLOAD, 980401);
- /* First look for an exact match. Search either overloaded
- functions or member functions. May have to undo what
- `default_conversion' might do to lhstype. */
+ case OVERLOAD:
+ {
+ tree elem, elems;
- if (TYPE_PTRMEMFUNC_P (lhstype))
- lhstype = TYPE_PTRMEMFUNC_FN_TYPE (lhstype);
+ /* Check that the LHSTYPE and the RHS are reasonable. */
+ lhstype = validate_lhs (lhstype, complain);
+ if (lhstype == error_mark_node)
+ return lhstype;
- if (TREE_CODE (lhstype) == POINTER_TYPE)
- if (TREE_CODE (TREE_TYPE (lhstype)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (lhstype)) == METHOD_TYPE)
- lhstype = TREE_TYPE (lhstype);
- else
- {
- if (complain)
- error ("invalid type combination for overload");
- return error_mark_node;
- }
-
- if (TREE_CODE (lhstype) != FUNCTION_TYPE && globals > 0)
+ if (TREE_CODE (lhstype) != FUNCTION_TYPE
+ && TREE_CODE (lhstype) != METHOD_TYPE)
{
if (complain)
- cp_error ("cannot resolve overloaded function `%D' based on non-function type",
- TREE_PURPOSE (rhs));
+ cp_error("cannot resolve overloaded function `%D' "
+ "based on non-function type",
+ DECL_NAME (OVL_FUNCTION (rhs)));
return error_mark_node;
}
-
- if (globals > 0)
+
+ /* Look for an exact match, by searching through the
+ overloaded functions. */
+ if (template_only)
+ /* If we're processing a template-id, only a template
+ function can match, so we don't look through the
+ overloaded functions. */
+ ;
+ else for (elems = rhs; elems; elems = OVL_CHAIN (elems))
{
- elem = get_first_fn (rhs);
- while (elem)
- if (! comptypes (lhstype, TREE_TYPE (elem), 1))
- elem = DECL_CHAIN (elem);
- else
+ elem = OVL_FUNCTION (elems);
+ if (comptypes (lhstype, TREE_TYPE (elem), 1))
+ {
+ mark_used (elem);
return elem;
+ }
+ }
- /* No exact match found, look for a compatible template. */
- {
- tree save_elem = 0;
- for (elem = get_first_fn (rhs); elem; elem = DECL_CHAIN (elem))
- if (TREE_CODE (elem) == TEMPLATE_DECL)
+ /* No overloaded function was an exact match. See if we can
+ instantiate some template to match. */
+ {
+ tree save_elem = 0;
+ elems = rhs;
+ if (TREE_CODE (elems) == TREE_LIST)
+ elems = TREE_VALUE (rhs);
+ for (; elems; elems = OVL_NEXT (elems))
+ if (TREE_CODE (elem = OVL_CURRENT (elems)) == TEMPLATE_DECL)
+ {
+ int n = DECL_NTPARMS (elem);
+ tree t = make_scratch_vec (n);
+ int i;
+ i = type_unification
+ (DECL_INNERMOST_TEMPLATE_PARMS (elem), t,
+ TYPE_ARG_TYPES (TREE_TYPE (elem)),
+ TYPE_ARG_TYPES (lhstype), explicit_targs, DEDUCE_EXACT, 1);
+ if (i == 0)
{
- int n = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (elem));
- tree *t = (tree *) alloca (sizeof (tree) * n);
- int i, d = 0;
- i = type_unification (DECL_TEMPLATE_PARMS (elem), t,
- TYPE_ARG_TYPES (TREE_TYPE (elem)),
- TYPE_ARG_TYPES (lhstype), &d, 0);
- if (i == 0)
+ if (save_elem)
{
- if (save_elem)
- {
- cp_error ("ambiguous template instantiation converting to `%#T'", lhstype);
- return error_mark_node;
- }
- save_elem = instantiate_template (elem, t);
- /* Check the return type. */
- if (! comptypes (TREE_TYPE (lhstype),
- TREE_TYPE (TREE_TYPE (save_elem)), 1))
- save_elem = 0;
+ cp_error ("ambiguous template instantiation converting to `%#T'", lhstype);
+ return error_mark_node;
}
+ save_elem = instantiate_template (elem, t);
+ /* Check the return type. */
+ if (! comptypes (TREE_TYPE (lhstype),
+ TREE_TYPE (TREE_TYPE (save_elem)), 1))
+ save_elem = 0;
}
- if (save_elem)
- return save_elem;
+ }
+ if (save_elem)
+ {
+ mark_used (save_elem);
+ return save_elem;
}
+ }
- /* No match found, look for a compatible function. */
- elem = get_first_fn (rhs);
- while (elem && comp_target_types (lhstype,
- TREE_TYPE (elem), 1) <= 0)
- elem = DECL_CHAIN (elem);
- if (elem)
+ /* There's no exact match, and no templates can be
+ instantiated to match. The last thing we try is to see if
+ some ordinary overloaded function is close enough. If
+ we're only looking for template functions, we don't do
+ this. */
+ if (!template_only)
+ {
+ for (elems = rhs; elems; elems = OVL_NEXT (elems))
+ {
+ elem = OVL_CURRENT (elems);
+ if (comp_target_types (lhstype, TREE_TYPE (elem), 1) > 0)
+ break;
+ }
+ if (elems)
{
tree save_elem = elem;
- elem = DECL_CHAIN (elem);
- while (elem && comp_target_types (lhstype,
- TREE_TYPE (elem), 0) <= 0)
- elem = DECL_CHAIN (elem);
- if (elem)
+ for (elems = OVL_CHAIN (elems); elems;
+ elems = OVL_CHAIN (elems))
+ {
+ elem = OVL_FUNCTION (elems);
+ if (comp_target_types (lhstype, TREE_TYPE (elem), 0) > 0)
+ break;
+ }
+ if (elems)
{
if (complain)
{
- cp_error ("cannot resolve overload to target type `%#T'",
- lhstype);
- cp_error_at (" ambiguity between `%#D'", save_elem);
+ cp_error
+ ("cannot resolve overload to target type `%#T'",
+ lhstype);
+ cp_error_at (" ambiguity between `%#D'", save_elem);
cp_error_at (" and `%#D', at least", elem);
}
return error_mark_node;
}
+ mark_used (save_elem);
return save_elem;
}
- if (complain)
- {
- cp_error ("cannot resolve overload to target type `%#T'",
- lhstype);
- cp_error (" because no suitable overload of function `%D' exists",
- TREE_PURPOSE (rhs));
- }
- return error_mark_node;
}
- if (TREE_NONLOCAL_FLAG (rhs))
+ /* We failed to find a match. */
+ if (complain)
{
- /* Got to get it as a baselink. */
- rhs = lookup_fnfields (TYPE_BINFO (current_class_type),
- TREE_PURPOSE (rhs), 0);
+ cp_error ("cannot resolve overload to target type `%#T'", lhstype);
+ cp_error
+ (" because no suitable overload of function `%D' exists",
+ DECL_NAME (OVL_FUNCTION (rhs)));
}
- else
+ return error_mark_node;
+ }
+
+ case TREE_LIST:
+ {
+ tree elem, baselink, name = NULL_TREE;
+
+ if (TREE_PURPOSE (rhs) == error_mark_node)
{
- my_friendly_assert (TREE_CHAIN (rhs) == NULL_TREE, 181);
- if (TREE_CODE (TREE_VALUE (rhs)) == TREE_LIST)
- rhs = TREE_VALUE (rhs);
- my_friendly_assert (TREE_CODE (TREE_VALUE (rhs)) == FUNCTION_DECL,
- 182);
+ /* Make sure we don't drop the non-local flag, as the old code
+ would rely on it. */
+ int nl = TREE_NONLOCAL_FLAG (rhs);
+ /* We don't need the type of this node. */
+ rhs = TREE_VALUE (rhs);
+ my_friendly_assert (TREE_NONLOCAL_FLAG (rhs) == nl, 980331);
}
+ /* Now we should have a baselink. */
+ my_friendly_assert (TREE_CODE (TREE_PURPOSE (rhs)) == TREE_VEC,
+ 980331);
+ /* First look for an exact match. Search member functions.
+ May have to undo what `default_conversion' might do to
+ lhstype. */
+
+ lhstype = validate_lhs (lhstype, complain);
+ if (lhstype == error_mark_node)
+ return lhstype;
+
+ my_friendly_assert (TREE_CHAIN (rhs) == NULL_TREE, 181);
+ my_friendly_assert (TREE_CODE (TREE_VALUE (rhs)) == FUNCTION_DECL
+ || TREE_CODE (TREE_VALUE (rhs)) == OVERLOAD,
+ 182);
+
for (baselink = rhs; baselink;
baselink = next_baselink (baselink))
{
elem = TREE_VALUE (baselink);
while (elem)
- if (comptypes (lhstype, TREE_TYPE (elem), 1))
- return elem;
+ if (comptypes (lhstype, TREE_TYPE (OVL_CURRENT (elem)), 1))
+ {
+ mark_used (OVL_CURRENT (elem));
+ return OVL_CURRENT (elem);
+ }
else
- elem = DECL_CHAIN (elem);
+ elem = OVL_NEXT (elem);
}
/* No exact match found, look for a compatible method. */
@@ -4858,25 +5297,30 @@ instantiate_type (lhstype, rhs, complain)
baselink = next_baselink (baselink))
{
elem = TREE_VALUE (baselink);
- while (elem && comp_target_types (lhstype,
- TREE_TYPE (elem), 1) <= 0)
- elem = DECL_CHAIN (elem);
+ for (; elem; elem = OVL_NEXT (elem))
+ if (comp_target_types (lhstype,
+ TREE_TYPE (OVL_CURRENT (elem)), 1) > 0)
+ break;
if (elem)
{
- tree save_elem = elem;
- elem = DECL_CHAIN (elem);
- while (elem && comp_target_types (lhstype,
- TREE_TYPE (elem), 0) <= 0)
- elem = DECL_CHAIN (elem);
+ tree save_elem = OVL_CURRENT (elem);
+ for (elem = OVL_NEXT (elem); elem; elem = OVL_NEXT (elem))
+ if (comp_target_types (lhstype,
+ TREE_TYPE (OVL_CURRENT (elem)), 0) > 0)
+ break;
if (elem)
{
if (complain)
error ("ambiguous overload for overloaded method requested");
return error_mark_node;
}
+ mark_used (save_elem);
return save_elem;
}
- name = DECL_NAME (TREE_VALUE (rhs));
+ name = rhs;
+ while (TREE_CODE (name) == TREE_LIST)
+ name = TREE_VALUE (name);
+ name = DECL_NAME (OVL_CURRENT (name));
#if 0
if (TREE_CODE (lhstype) == FUNCTION_TYPE && globals < 0)
{
@@ -5006,15 +5450,20 @@ instantiate_type (lhstype, rhs, complain)
error ("type for resolving address of overloaded function must be pointer type");
return error_mark_node;
}
- TREE_TYPE (rhs) = lhstype;
- lhstype = TREE_TYPE (lhstype);
{
- tree fn = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
+ tree fn = instantiate_type (TREE_TYPE (lhstype), TREE_OPERAND (rhs, 0), complain);
if (fn == error_mark_node)
return error_mark_node;
mark_addressable (fn);
+ TREE_TYPE (rhs) = lhstype;
TREE_OPERAND (rhs, 0) = fn;
TREE_CONSTANT (rhs) = staticp (fn);
+ if (TREE_CODE (lhstype) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (lhstype)) == METHOD_TYPE)
+ {
+ build_ptrmemfunc_type (lhstype);
+ rhs = build_ptrmemfunc (lhstype, rhs, 0);
+ }
}
return rhs;
@@ -5036,6 +5485,7 @@ instantiate_type (lhstype, rhs, complain)
this may have to look back through base types to find the
ultimate field name. (For single inheritance, these could
all be the same name. Who knows for multiple inheritance). */
+
static tree
get_vfield_name (type)
tree type;
@@ -5049,8 +5499,8 @@ get_vfield_name (type)
binfo = BINFO_BASETYPE (binfo, 0);
type = BINFO_TYPE (binfo);
- buf = (char *)alloca (sizeof (VFIELD_NAME_FORMAT)
- + TYPE_NAME_LENGTH (type) + 2);
+ buf = (char *) alloca (sizeof (VFIELD_NAME_FORMAT)
+ + TYPE_NAME_LENGTH (type) + 2);
sprintf (buf, VFIELD_NAME_FORMAT, TYPE_NAME_STRING (type));
return get_identifier (buf);
}
@@ -5077,6 +5527,7 @@ print_class_statistics ()
decls that may be cached in the previous_class_values list. For now, let's
use the permanent obstack, later we may create a dedicated obstack just
for this purpose. The effect is undone by pop_obstacks. */
+
void
maybe_push_cache_obstack ()
{
@@ -5084,3 +5535,49 @@ maybe_push_cache_obstack ()
if (current_class_depth == 1)
current_obstack = &permanent_obstack;
}
+
+/* Build a dummy reference to ourselves so Derived::Base (and A::A) works,
+ according to [class]:
+ The class-name is also inserted
+ into the scope of the class itself. For purposes of access checking,
+ the inserted class name is treated as if it were a public member name. */
+
+tree
+build_self_reference ()
+{
+ tree name = constructor_name (current_class_type);
+ tree value = build_lang_decl (TYPE_DECL, name, current_class_type);
+ DECL_NONLOCAL (value) = 1;
+ DECL_CONTEXT (value) = current_class_type;
+ DECL_CLASS_CONTEXT (value) = current_class_type;
+ CLASSTYPE_LOCAL_TYPEDECLS (current_class_type) = 1;
+ DECL_ARTIFICIAL (value) = 1;
+
+ pushdecl_class_level (value);
+ return value;
+}
+
+/* Returns 1 if TYPE contains only padding bytes. */
+
+int
+is_empty_class (type)
+ tree type;
+{
+ tree t;
+
+ if (type == error_mark_node)
+ return 0;
+
+ if (! IS_AGGR_TYPE (type))
+ return 0;
+
+ if (flag_new_abi)
+ return CLASSTYPE_SIZE (type) == integer_zero_node;
+
+ if (TYPE_BINFO_BASETYPES (type))
+ return 0;
+ t = TYPE_FIELDS (type);
+ while (t && TREE_CODE (t) != FIELD_DECL)
+ t = TREE_CHAIN (t);
+ return (t == NULL_TREE);
+}
diff --git a/contrib/gcc/cp/config-lang.in b/contrib/gcc/cp/config-lang.in
index 7a9a5c5..9b39d51 100644
--- a/contrib/gcc/cp/config-lang.in
+++ b/contrib/gcc/cp/config-lang.in
@@ -32,4 +32,10 @@ compilers="cc1plus\$(exeext)"
stagestuff="g++\$(exeext) g++-cross\$(exeext) cc1plus\$(exeext)"
-diff_excludes="-x cp/parse.c -x cp/parse.h"
+diff_excludes="-x parse.c -x parse.h"
+
+headers='$(CXX_EXTRA_HEADERS)'
+
+lib2funcs=cplib2.txt
+
+outputs=cp/Makefile
diff --git a/contrib/gcc/cp/cp-tree.def b/contrib/gcc/cp/cp-tree.def
new file mode 100644
index 0000000..dbbdb66
--- /dev/null
+++ b/contrib/gcc/cp/cp-tree.def
@@ -0,0 +1,240 @@
+/* This file contains the definitions and documentation for the
+ additional tree codes used in the GNU C++ compiler (see tree.def
+ for the standard codes).
+ Copyright (C) 1987, 1988, 1990, 1993 Free Software Foundation, Inc.
+ Hacked by Michael Tiemann (tiemann@cygnus.com)
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Reference to the contents of an offset
+ (a value whose type is an OFFSET_TYPE).
+ Operand 0 is the object within which the offset is taken.
+ Operand 1 is the offset. The language independent OFFSET_REF
+ just won't work for us. */
+DEFTREECODE (OFFSET_REF, "offset_ref", 'r', 2)
+
+/* For NEW_EXPR, operand 0 is the placement list.
+ Operand 1 is the new-declarator.
+ Operand 2 is the initializer. */
+DEFTREECODE (NEW_EXPR, "nw_expr", 'e', 3)
+DEFTREECODE (VEC_NEW_EXPR, "vec_nw_expr", 'e', 3)
+
+/* For DELETE_EXPR, operand 0 is the store to be destroyed.
+ Operand 1 is the value to pass to the destroying function
+ saying whether the store should be deallocated as well. */
+DEFTREECODE (DELETE_EXPR, "dl_expr", 'e', 2)
+DEFTREECODE (VEC_DELETE_EXPR, "vec_dl_expr", 'e', 2)
+
+/* Value is reference to particular overloaded class method.
+ Operand 0 is the class name (an IDENTIFIER_NODE);
+ operand 1 is the field (also an IDENTIFIER_NODE).
+ The COMPLEXITY field holds the class level (usually 0). */
+DEFTREECODE (SCOPE_REF, "scope_ref", 'r', 2)
+
+/* When composing an object with a member, this is the result.
+ Operand 0 is the object. Operand 1 is the member (usually
+ a dereferenced pointer to member). */
+DEFTREECODE (MEMBER_REF, "member_ref", 'r', 2)
+
+/* Type conversion operator in C++. TREE_TYPE is type that this
+ operator converts to. Operand is expression to be converted. */
+DEFTREECODE (TYPE_EXPR, "type_expr", 'e', 1)
+
+/* For AGGR_INIT_EXPR, operand 0 is function which performs initialization,
+ operand 1 is argument list to initialization function,
+ and operand 2 is the slot which was allocated for this expression. */
+DEFTREECODE (AGGR_INIT_EXPR, "aggr_init_expr", 'e', 3)
+
+/* A throw expression. operand 0 is the expression, if there was one,
+ else it is NULL_TREE. */
+DEFTREECODE (THROW_EXPR, "throw_expr", 'e', 1)
+
+/* Initialization of a vector, used in build_new. Operand 0 is the target
+ of the initialization, operand 1 is the initializer, and operand 2 is
+ the number of elements. */
+DEFTREECODE (VEC_INIT_EXPR, "vec_init_expr", 'e', 3)
+
+/* Template definition. The following fields have the specified uses,
+ although there are other macros in cp-tree.h that should be used for
+ accessing this data.
+ DECL_ARGUMENTS template parm vector
+ DECL_TEMPLATE_INFO template text &c
+ DECL_VINDEX list of instantiations already produced;
+ only done for functions so far
+ For class template:
+ DECL_INITIAL associated templates (methods &c)
+ DECL_RESULT null
+ For non-class templates:
+ TREE_TYPE type of object to be constructed
+ DECL_RESULT decl for object to be created
+ (e.g., FUNCTION_DECL with tmpl parms used)
+ */
+DEFTREECODE (TEMPLATE_DECL, "template_decl", 'd', 0)
+
+/* Index into a template parameter list. The TEMPLATE_PARM_IDX gives
+ the index (from 0) of the parameter, while the TEMPLATE_PARM_LEVEL
+ gives the level (from 1) of the parameter.
+
+ Here's an example:
+
+ template <class T> // Index 0, Level 1.
+ struct S
+ {
+ template <class U, // Index 0, Level 2.
+ class V> // Index 1, Level 2.
+ void f();
+ };
+
+ The DESCENDANTS will be a chain of TEMPLATE_PARM_INDEXs descended
+ from this one. The first descendant will have the same IDX, but
+ its LEVEL will be one less. The TREE_CHAIN field is used to chain
+ together the descendants. The TEMPLATE_PARM_DECL is the
+ declaration of this parameter, either a TYPE_DECL or CONST_DECL.
+ The TEMPLATE_PARM_ORIG_LEVEL is the LEVEL of the most distant
+ parent, i.e., the LEVEL that the parameter originally had when it
+ was declared. For example, if we instantiate S<int>, we will have:
+
+ struct S<int>
+ {
+ template <class U, // Index 0, Level 1, Orig Level 2
+ class V> // Index 1, Level 1, Orig Level 2
+ void f();
+ };
+
+ The LEVEL is the level of the parameter when we are worrying about
+ the types of things; the ORIG_LEVEL is the level when we are
+ worrying about instantiating things. */
+DEFTREECODE (TEMPLATE_PARM_INDEX, "template_parm_index", 'x',
+ /* The addition of (sizeof(char*) - 1) in the next
+ expression is to ensure against the case where
+ sizeof(char*) does not evenly divide
+ sizeof(HOST_WIDE_INT). */
+ 2 + ((3 * sizeof (HOST_WIDE_INT) + sizeof(char*) - 1)
+ / sizeof (char*)))
+
+/* Index into a template parameter list. This parameter must be a type.
+ The TYPE_FIELDS value will be a TEMPLATE_PARM_INDEX. */
+DEFTREECODE (TEMPLATE_TYPE_PARM, "template_type_parm", 't', 0)
+
+/* Index into a template parameter list. This parameter must be a type.
+ If it is used in signature of a template, TEMPLATE_INFO is NULL_TREE.
+ Otherwise it is used to declare a type like TT<int>.
+ The TYPE_FIELDS value will be a TEMPLATE_PARM_INDEX. */
+DEFTREECODE (TEMPLATE_TEMPLATE_PARM, "template_template_parm", 't', 0)
+
+/* A type designated by 'typename T::t'. */
+DEFTREECODE (TYPENAME_TYPE, "typename_type", 't', 0)
+
+/* A thunk is a stub function.
+
+ Thunks are used to implement multiple inheritance:
+ At run-time, such a thunk subtracts THUNK_DELTA (an int, not a tree)
+ from the this pointer, and then jumps to DECL_INITIAL
+ (which is an ADDR_EXPR whose operand is a FUNCTION_DECL).
+
+ Other kinds of thunks may be defined later. */
+DEFTREECODE (THUNK_DECL, "thunk_decl", 'd', 0)
+
+/* A using declaration. DECL_INITIAL contains the specified scope.
+ This is not an alias, but is later expanded into multiple aliases. */
+DEFTREECODE (USING_DECL, "using_decl", 'd', 0)
+
+/* An un-parsed default argument. Looks like an IDENTIFIER_NODE. */
+DEFTREECODE (DEFAULT_ARG, "default_arg", 'c', 2)
+
+/* A template-id, like foo<int>. The first operand is the template.
+ The second is the list of explicitly specified arguments. The
+ template will be a FUNCTION_DECL, TEMPLATE_DECL, or a list of
+ overloaded functions and templates if the template-id refers to
+ a global template. If the template-id refers to a member template,
+ the template may be an IDENTIFIER_NODE. */
+DEFTREECODE (TEMPLATE_ID_EXPR, "template_id_expr", 'e', 2)
+
+/* An association between namespace and entity. Parameters are the
+ scope and the (non-type) value.
+ TREE_TYPE indicates the type bound to the name. */
+DEFTREECODE (CPLUS_BINDING, "binding", 'x', 2)
+
+/* A list-like node for chaining overloading candidates. TREE_TYPE is
+ the original name, and the parameter is the FUNCTION_DECL. */
+DEFTREECODE (OVERLOAD, "overload", 'x', 1)
+
+/* A generic wrapper for something not tree that we want to include in
+ tree structure. */
+DEFTREECODE (WRAPPER, "wrapper", 'x', 1)
+
+/* A node to remember a source position. */
+DEFTREECODE (SRCLOC, "srcloc", 'x', 2)
+
+/* A whole bunch of tree codes for the initial, superficial parsing of
+ templates. */
+DEFTREECODE (LOOKUP_EXPR, "lookup_expr", 'e', 2)
+DEFTREECODE (MODOP_EXPR, "modop_expr", 'e', 3)
+DEFTREECODE (CAST_EXPR, "cast_expr", '1', 1)
+DEFTREECODE (REINTERPRET_CAST_EXPR, "reinterpret_cast_expr", '1', 1)
+DEFTREECODE (CONST_CAST_EXPR, "const_cast_expr", '1', 1)
+DEFTREECODE (STATIC_CAST_EXPR, "static_cast_expr", '1', 1)
+DEFTREECODE (DYNAMIC_CAST_EXPR, "dynamic_cast_expr", '1', 1)
+DEFTREECODE (SIZEOF_EXPR, "sizeof_expr", '1', 1)
+DEFTREECODE (ALIGNOF_EXPR, "alignof_expr", '1', 1)
+DEFTREECODE (ARROW_EXPR, "arrow_expr", 'e', 1)
+DEFTREECODE (DOTSTAR_EXPR, "dotstar_expr", 'e', 2)
+DEFTREECODE (TYPEID_EXPR, "typeid_expr", 'e', 1)
+
+DEFTREECODE (EXPR_STMT, "expr_stmt", 'e', 1)
+DEFTREECODE (COMPOUND_STMT, "compound_stmt", 'e', 1)
+DEFTREECODE (DECL_STMT, "decl_stmt", 'e', 3)
+DEFTREECODE (IF_STMT, "if_stmt", 'e', 3)
+DEFTREECODE (FOR_STMT, "for_stmt", 'e', 4)
+DEFTREECODE (WHILE_STMT, "while_stmt", 'e', 2)
+DEFTREECODE (DO_STMT, "do_stmt", 'e', 2)
+DEFTREECODE (RETURN_STMT, "return_stmt", 'e', 1)
+DEFTREECODE (BREAK_STMT, "break_stmt", 'e', 0)
+DEFTREECODE (CONTINUE_STMT, "continue_stmt", 'e', 0)
+DEFTREECODE (SWITCH_STMT, "switch_stmt", 'e', 2)
+DEFTREECODE (GOTO_STMT, "goto_stmt", 'e', 1)
+DEFTREECODE (ASM_STMT, "asm_stmt", 'e', 5)
+
+DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
+DEFTREECODE (CASE_LABEL, "case_label", 'e', 2)
+DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
+DEFTREECODE (TRY_BLOCK, "try_stmt", 'e', 2)
+DEFTREECODE (HANDLER, "catch_stmt", 'e', 2)
+
+DEFTREECODE (TAG_DEFN, "tag_defn", 'e', 0)
+
+/* And some codes for expressing conversions for overload resolution. */
+
+DEFTREECODE (IDENTITY_CONV, "identity_conv", 'e', 1)
+DEFTREECODE (LVALUE_CONV, "lvalue_conv", 'e', 1)
+DEFTREECODE (QUAL_CONV, "qual_conv", 'e', 1)
+DEFTREECODE (STD_CONV, "std_conv", 'e', 1)
+DEFTREECODE (PTR_CONV, "ptr_conv", 'e', 1)
+DEFTREECODE (PMEM_CONV, "pmem_conv", 'e', 1)
+DEFTREECODE (BASE_CONV, "base_conv", 'e', 1)
+DEFTREECODE (REF_BIND, "ref_bind", 'e', 1)
+DEFTREECODE (USER_CONV, "user_conv", 'e', 2)
+DEFTREECODE (AMBIG_CONV, "ambig_conv", 'e', 1)
+DEFTREECODE (RVALUE_CONV, "rvalue_conv", 'e', 1)
+
+/*
+Local variables:
+mode:c
+End:
+*/
diff --git a/contrib/gcc/cp/cp-tree.h b/contrib/gcc/cp/cp-tree.h
index fe9855d..7572921 100644
--- a/contrib/gcc/cp/cp-tree.h
+++ b/contrib/gcc/cp/cp-tree.h
@@ -1,5 +1,5 @@
/* Definitions for C++ parsing and type checking.
- Copyright (C) 1987, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 93, 94, 95, 1996 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -22,24 +22,66 @@ Boston, MA 02111-1307, USA. */
#ifndef _CP_TREE_H
#define _CP_TREE_H
-/* Borrow everything that is C from c-tree.h,
- but do so by copy, not by inclusion, since c-tree.h defines
- lang_identifier. */
-
-#ifndef STDIO_PROTO
-#ifdef BUFSIZ
-#define STDIO_PROTO(ARGS) PROTO(ARGS)
-#else
-#define STDIO_PROTO(ARGS) ()
-#endif
-#endif
+#include "gansidecl.h"
+
+/* Usage of TREE_LANG_FLAG_?:
+ 0: TREE_NONLOCAL_FLAG (in TREE_LIST or _TYPE).
+ BINFO_MARKED (BINFO nodes).
+ TI_USES_TEMPLATE_PARMS.
+ COMPOUND_STMT_NO_SCOPE (in COMPOUND_STMT).
+ NEW_EXPR_USE_GLOBAL (in NEW_EXPR).
+ DELETE_EXPR_USE_GLOBAL (in DELETE_EXPR).
+ LOOKUP_EXPR_GLOBAL (in LOOKUP_EXPR).
+ TREE_NEGATED_INT (in INTEGER_CST).
+ (TREE_MANGLED) (in IDENTIFIER_NODE) (commented-out).
+ 1: IDENTIFIER_VIRTUAL_P.
+ TI_PENDING_TEMPLATE_FLAG.
+ TI_PENDING_SPECIALIZATION_FLAG.
+ TEMPLATE_PARMS_FOR_INLINE.
+ DELETE_EXPR_USE_VEC (in DELETE_EXPR).
+ (TREE_CALLS_NEW) (in _EXPR or _REF) (commented-out).
+ TYPE_USES_COMPLEX_INHERITANCE (in _TYPE).
+ C_DECLARED_LABEL_FLAG.
+ 2: IDENTIFIER_OPNAME_P.
+ BINFO_FIELDS_MARKED.
+ TYPE_VIRTUAL_P.
+ PARM_DECL_EXPR (in SAVE_EXPR).
+ 3: TYPE_USES_VIRTUAL_BASECLASSES (in a class TYPE).
+ BINFO_VTABLE_PATH_MARKED.
+ (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
+ 4: BINFO_NEW_VTABLE_MARKED.
+ TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
+ or FIELD_DECL).
+ 5: BINFO_VIA_PUBLIC.
+ BINFO_VBASE_INIT_MARKED.
+ 6: Not used.
+
+ Usage of TYPE_LANG_FLAG_?:
+ 0: C_TYPE_FIELDS_READONLY (in RECORD_TYPE or UNION_TYPE).
+ 1: TYPE_HAS_CONSTRUCTOR.
+ 2: TYPE_HAS_DESTRUCTOR.
+ 3: TYPE_FOR_JAVA.
+ 4: TYPE_NEEDS_DESTRUCTOR.
+ 5: IS_AGGR_TYPE.
+ 6: TYPE_BUILT_IN.
+
+ Usage of DECL_LANG_FLAG_?:
+ 0: DECL_ERROR_REPORTED (in VAR_DECL).
+ 1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
+ 2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
+ 3: DECL_IN_AGGR_P.
+ 4: DECL_MAYBE_TEMPLATE.
+ 5: DECL_INTERFACE_KNOWN.
+ 6: DECL_THIS_STATIC (in VAR_DECL or FUNCTION_DECL).
+ 7: DECL_DEAD_FOR_LOCAL (in VAR_DECL).
+*/
/* Language-dependent contents of an identifier. */
struct lang_identifier
{
struct tree_identifier ignore;
- tree global_value, local_value;
+ tree namespace_bindings, local_value;
tree class_value;
tree class_template_info;
struct lang_id2 *x;
@@ -51,14 +93,96 @@ struct lang_id2
tree type_desc, as_list, error_locus;
};
+typedef struct
+{
+ tree t;
+ int new_type_flag;
+} flagged_type_tree;
+
+typedef struct
+{
+ char common[sizeof (struct tree_common)];
+ struct rtx_def *rtl; /* Unused, but required to match up with what
+ the middle-end expects. */
+ HOST_WIDE_INT index;
+ HOST_WIDE_INT level;
+ HOST_WIDE_INT orig_level;
+ tree decl;
+} template_parm_index;
+
+/* For a binding between a name and an entity, defines the scope
+ where the binding is declared. Currently always points to a
+ namespace declaration. */
+#define BINDING_SCOPE(NODE) (((struct tree_binding*)NODE)->scope)
+/* This is the declaration bound to the name. Possible values:
+ variable, overloaded function, namespace, template, enumerator. */
+#define BINDING_VALUE(NODE) (((struct tree_binding*)NODE)->value)
+/* If name is bound to a type, this is the type (struct, union, enum). */
+#define BINDING_TYPE(NODE) TREE_TYPE(NODE)
+#define IDENTIFIER_GLOBAL_VALUE(NODE) \
+ namespace_binding (NODE, global_namespace)
+#define SET_IDENTIFIER_GLOBAL_VALUE(NODE, VAL) \
+ set_namespace_binding (NODE, global_namespace, VAL)
+#define IDENTIFIER_NAMESPACE_VALUE(NODE) \
+ namespace_binding (NODE, current_namespace)
+#define SET_IDENTIFIER_NAMESPACE_VALUE(NODE, VAL) \
+ set_namespace_binding (NODE, current_namespace, VAL)
+
+struct tree_binding
+{
+ char common[sizeof (struct tree_common)];
+ tree scope;
+ tree value;
+};
+
+/* The overloaded FUNCTION_DECL. */
+#define OVL_FUNCTION(NODE) (((struct tree_overload*)NODE)->function)
+#define OVL_CHAIN(NODE) TREE_CHAIN(NODE)
+/* Polymorphic access to FUNCTION and CHAIN. */
+#define OVL_CURRENT(NODE) \
+ ((TREE_CODE(NODE)==OVERLOAD) ? OVL_FUNCTION(NODE) : NODE)
+#define OVL_NEXT(NODE) \
+ ((TREE_CODE(NODE)==OVERLOAD) ? TREE_CHAIN(NODE) : NULL_TREE)
+/* If set, this was imported in a using declaration.
+ This is not to confuse with being used somewhere, which
+ is not important for this node. */
+#define OVL_USED(NODE) TREE_USED(NODE)
+
+struct tree_overload
+{
+ char common[sizeof (struct tree_common)];
+ tree function;
+};
+
+#define WRAPPER_PTR(NODE) (((struct tree_wrapper*)NODE)->u.ptr)
+#define WRAPPER_INT(NODE) (((struct tree_wrapper*)NODE)->u.i)
+
+struct tree_wrapper
+{
+ char common[sizeof (struct tree_common)];
+ union {
+ void *ptr;
+ int i;
+ } u;
+};
+
+#define SRCLOC_FILE(NODE) (((struct tree_srcloc*)NODE)->filename)
+#define SRCLOC_LINE(NODE) (((struct tree_srcloc*)NODE)->linenum)
+struct tree_srcloc
+{
+ char common[sizeof (struct tree_common)];
+ char *filename;
+ int linenum;
+};
+
/* To identify to the debug emitters if it should pay attention to the
flag `-Wtemplate-debugging'. */
#define HAVE_TEMPLATES 1
/* Macros for access to language-specific slots in an identifier. */
-#define IDENTIFIER_GLOBAL_VALUE(NODE) \
- (((struct lang_identifier *)(NODE))->global_value)
+#define IDENTIFIER_NAMESPACE_BINDINGS(NODE) \
+ (((struct lang_identifier *)(NODE))->namespace_bindings)
#define IDENTIFIER_CLASS_VALUE(NODE) \
(((struct lang_identifier *)(NODE))->class_value)
#define IDENTIFIER_LOCAL_VALUE(NODE) \
@@ -66,9 +190,14 @@ struct lang_id2
#define IDENTIFIER_TEMPLATE(NODE) \
(((struct lang_identifier *)(NODE))->class_template_info)
-#define IDENTIFIER_TYPE_VALUE(NODE) (TREE_TYPE (NODE))
+/* TREE_TYPE only indicates on local and class scope the current
+ type. For namespace scope, the presence of a type in any namespace
+ is indicated with global_type_node, and the real type behind must
+ be found through lookup. */
+#define IDENTIFIER_TYPE_VALUE(NODE) (identifier_type_value(NODE))
+#define REAL_IDENTIFIER_TYPE_VALUE(NODE) (TREE_TYPE (NODE))
#define SET_IDENTIFIER_TYPE_VALUE(NODE,TYPE) (TREE_TYPE (NODE) = TYPE)
-#define IDENTIFIER_HAS_TYPE_VALUE(NODE) (TREE_TYPE (NODE) ? 1 : 0)
+#define IDENTIFIER_HAS_TYPE_VALUE(NODE) (IDENTIFIER_TYPE_VALUE (NODE) ? 1 : 0)
#define LANG_ID_FIELD(NAME,NODE) \
(((struct lang_identifier *)(NODE))->x \
@@ -139,15 +268,34 @@ extern tree unsigned_type_node;
extern tree string_type_node, char_array_type_node, int_array_type_node;
extern tree wchar_array_type_node;
extern tree wchar_type_node, signed_wchar_type_node, unsigned_wchar_type_node;
+
+extern tree complex_integer_type_node;
+extern tree complex_float_type_node;
+extern tree complex_double_type_node;
+extern tree complex_long_double_type_node;
+
extern tree intQI_type_node, unsigned_intQI_type_node;
extern tree intHI_type_node, unsigned_intHI_type_node;
extern tree intSI_type_node, unsigned_intSI_type_node;
extern tree intDI_type_node, unsigned_intDI_type_node;
+extern tree intTI_type_node, unsigned_intTI_type_node;
+
+extern tree java_byte_type_node;
+extern tree java_short_type_node;
+extern tree java_int_type_node;
+extern tree java_long_type_node;
+extern tree java_float_type_node;
+extern tree java_double_type_node;
+extern tree java_char_type_node;
+extern tree java_boolean_type_node;
extern int current_function_returns_value;
extern int current_function_returns_null;
extern tree current_function_return_value;
+extern tree current_namespace;
+extern tree global_namespace;
+
extern tree ridpointers[];
extern tree ansi_opname[];
extern tree ansi_assopname[];
@@ -181,6 +329,10 @@ extern int flag_no_ident;
extern int warn_implicit;
+/* Nonzero means warn about usage of long long when `-pedantic'. */
+
+extern int warn_long_long;
+
/* Nonzero means warn when all ctors or dtors are private, and the class
has no friends. */
@@ -202,10 +354,6 @@ extern int warn_write_strings;
extern int warn_pointer_arith;
-/* Nonzero means warn for all old-style non-prototype function decls. */
-
-extern int warn_strict_prototypes;
-
/* Nonzero means warn about suggesting putting in ()'s. */
extern int warn_parentheses;
@@ -219,6 +367,10 @@ extern int warn_redundant_decls;
extern int warn_missing_braces;
+/* Warn about comparison of signed and unsigned values. */
+
+extern int warn_sign_compare;
+
/* Warn about a subscript that has type char. */
extern int warn_char_subscripts;
@@ -228,25 +380,36 @@ extern int warn_char_subscripts;
extern int warn_cast_qual;
-/* Warn about traditional constructs whose meanings changed in ANSI C. */
-
-extern int warn_traditional;
-
-/* Warn about *printf or *scanf format/argument anomalies. */
+/* Warn about *printf or *scanf format/argument anomalies. */
extern int warn_format;
/* Nonzero means warn about non virtual destructors in classes that have
- virtual functions. */
+ virtual functions. */
extern int warn_nonvdtor;
+/* Non-zero means warn when we convert a pointer to member function
+ into a pointer to (void or function). */
+
+extern int warn_pmf2ptr;
+
+/* Nonzero means warn about violation of some Effective C++ style rules. */
+
+extern int warn_ecpp;
+
+/* Nonzero means warn where overload resolution chooses a promotion from
+ unsigned to signed over a conversion to an unsigned of the same size. */
+
+extern int warn_sign_promo;
+
/* Non-zero means warn when a function is declared extern and later inline. */
+
extern int warn_extern_inline;
-/* Nonzero means do some things the same way PCC does. */
+/* Non-zero means warn when an old-style cast is used. */
-extern int flag_traditional;
+extern int warn_old_style_cast;
/* Nonzero means to treat bitfields as unsigned unless they say `signed'. */
@@ -264,9 +427,9 @@ extern int flag_signed_bitfields;
extern int write_virtuals;
-/* True for more efficient but incompatible (not not fully tested)
+/* True for more efficient but incompatible (not fully tested)
vtable implementation (using thunks).
- 0 is old behavior; 1 is new behavior. */
+ 0 is old behavior; 1 is new behavior. */
extern int flag_vtable_thunks;
/* INTERFACE_ONLY nonzero means that we are in an "interface"
@@ -285,11 +448,6 @@ extern int flag_elide_constructors;
extern int flag_ansi;
-/* Nonzero means recognize and handle ansi-style exception handling
- constructs. */
-
-extern int flag_handle_exceptions;
-
/* Nonzero means recognize and handle signature language constructs. */
extern int flag_handle_signatures;
@@ -299,24 +457,32 @@ extern int flag_handle_signatures;
extern int flag_default_inline;
-/* Nonzero means emit cadillac protocol. */
+/* The name-mangling scheme to use. Versions of gcc before 2.8 use
+ version 0. */
+extern int name_mangling_version;
+
+/* Nonzero means that guiding declarations are allowed. */
+extern int flag_guiding_decls;
+
+/* Nonzero if squashed mangling is to be performed.
+ This uses the B and K codes to reference previously seen class types
+ and class qualifiers. */
+extern int flag_do_squangling;
-extern int flag_cadillac;
+/* Nonzero if we want to issue diagnostics that the standard says are not
+ required. */
+extern int flag_optional_diags;
/* C++ language-specific tree codes. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM,
enum cplus_tree_code {
__DUMMY = LAST_AND_UNUSED_TREE_CODE,
-#include "tree.def"
+#include "cp-tree.def"
LAST_CPLUS_TREE_CODE
};
#undef DEFTREECODE
-/* Override OFFSET_REFs from the back-end, as we want our very own. */
-/* Allow complex pointer to members to work correctly. */
-#define OFFSET_REF CP_OFFSET_REF
-
-enum languages { lang_c, lang_cplusplus };
+enum languages { lang_c, lang_cplusplus, lang_java };
/* Macros to make error reporting functions' lives easier. */
#define TYPE_IDENTIFIER(NODE) (DECL_NAME (TYPE_NAME (NODE)))
@@ -327,27 +493,28 @@ enum languages { lang_c, lang_cplusplus };
#define TYPE_ASSEMBLER_NAME_LENGTH(NODE) (IDENTIFIER_LENGTH (DECL_ASSEMBLER_NAME (TYPE_NAME (NODE))))
/* The _DECL for this _TYPE. */
-#define TYPE_MAIN_DECL(NODE) (TYPE_NAME (NODE))
+#define TYPE_MAIN_DECL(NODE) (TYPE_STUB_DECL (TYPE_MAIN_VARIANT (NODE)))
#define IS_AGGR_TYPE(t) (TYPE_LANG_FLAG_5 (t))
-#define IS_AGGR_TYPE_CODE(t) (t == RECORD_TYPE || t == UNION_TYPE || t == UNINSTANTIATED_P_TYPE)
+#define IS_AGGR_TYPE_CODE(t) (t == RECORD_TYPE || t == UNION_TYPE)
#define IS_AGGR_TYPE_2(TYPE1,TYPE2) \
(TREE_CODE (TYPE1) == TREE_CODE (TYPE2) \
&& IS_AGGR_TYPE (TYPE1)&IS_AGGR_TYPE (TYPE2))
-#define IS_OVERLOAD_TYPE_CODE(t) (IS_AGGR_TYPE_CODE (t) || t == ENUMERAL_TYPE)
-#define IS_OVERLOAD_TYPE(t) (IS_OVERLOAD_TYPE_CODE (TREE_CODE (t)))
+#define IS_OVERLOAD_TYPE(t) \
+ (IS_AGGR_TYPE (t) || TREE_CODE (t) == ENUMERAL_TYPE)
/* In a *_TYPE, nonzero means a built-in type. */
#define TYPE_BUILT_IN(NODE) TYPE_LANG_FLAG_6(NODE)
-/* Macros which might want to be replaced by function calls. */
+/* True if this a "Java" type, defined in 'extern "Java"'. */
+#define TYPE_FOR_JAVA(NODE) TYPE_LANG_FLAG_3(NODE)
#define DELTA_FROM_VTABLE_ENTRY(ENTRY) \
(!flag_vtable_thunks ? \
TREE_VALUE (CONSTRUCTOR_ELTS (ENTRY)) \
: TREE_CODE (TREE_OPERAND ((ENTRY), 0)) != THUNK_DECL ? integer_zero_node \
: build_int_2 (THUNK_DELTA (TREE_OPERAND ((ENTRY), 0)), 0))
-#if 1
+
/* Virtual function addresses can be gotten from a virtual function
table entry using this macro. */
#define FNADDR_FROM_VTABLE_ENTRY(ENTRY) \
@@ -363,15 +530,6 @@ enum languages { lang_c, lang_cplusplus };
&& IS_AGGR_TYPE (TREE_TYPE (NODE))) \
|| IS_AGGR_TYPE (NODE))
-#else
-#define FNADDR_FROM_VTABLE_ENTRY(ENTRY) (fnaddr_from_vtable_entry (ENTRY))
-#define SET_FNADDR_FROM_VTABLE_ENTRY(ENTRY,VALUE) \
- (set_fnaddr_from_vtable_entry (ENTRY, VALUE))
-/* #define TYPE_NAME_STRING(NODE) (type_name_string (NODE)) */
-#define FUNCTION_ARG_CHAIN(NODE) (function_arg_chain (NODE))
-#define PROMOTES_TO_AGGR_TYPE(NODE,CODE) (promotes_to_aggr_type (NODE, CODE))
-/* #define IS_AGGR_TYPE_2(TYPE1, TYPE2) (is_aggr_type_2 (TYPE1, TYPE2)) */
-#endif
/* Nonzero iff TYPE is uniquely derived from PARENT. Under MI, PARENT can
be an ambiguous base class of TYPE, and this macro will be false. */
#define UNIQUELY_DERIVED_FROM_P(PARENT, TYPE) (get_base_distance (PARENT, TYPE, 0, (tree *)0) >= 0)
@@ -389,57 +547,48 @@ struct lang_type
struct
{
unsigned has_type_conversion : 1;
- unsigned has_int_conversion : 1;
- unsigned has_float_conversion : 1;
unsigned has_init_ref : 1;
- unsigned gets_init_aggr : 1;
unsigned has_assignment : 1;
unsigned has_default_ctor : 1;
unsigned uses_multiple_inheritance : 1;
-
- unsigned has_nonpublic_ctor : 2;
- unsigned has_nonpublic_assign_ref : 2;
unsigned const_needs_init : 1;
unsigned ref_needs_init : 1;
unsigned has_const_assign_ref : 1;
- unsigned vtable_needs_writing : 1;
+ unsigned has_nonpublic_ctor : 2;
+ unsigned has_nonpublic_assign_ref : 2;
+ unsigned vtable_needs_writing : 1;
unsigned has_assign_ref : 1;
unsigned gets_new : 2;
+
unsigned gets_delete : 2;
unsigned has_call_overloaded : 1;
unsigned has_array_ref_overloaded : 1;
unsigned has_arrow_overloaded : 1;
-
unsigned local_typedecls : 1;
unsigned interface_only : 1;
unsigned interface_unknown : 1;
+
unsigned needs_virtual_reinit : 1;
unsigned vec_delete_takes_size : 1;
unsigned declared_class : 1;
unsigned being_defined : 1;
unsigned redefined : 1;
-
- unsigned no_globalize : 1;
unsigned marked : 1;
unsigned marked2 : 1;
unsigned marked3 : 1;
+
unsigned marked4 : 1;
unsigned marked5 : 1;
unsigned marked6 : 1;
-
- unsigned use_template : 2;
unsigned debug_requested : 1;
- unsigned has_method_call_overloaded : 1;
- unsigned private_attr : 1;
+ unsigned use_template : 2;
unsigned got_semicolon : 1;
unsigned ptrmemfunc_flag : 1;
+
unsigned is_signature : 1;
unsigned is_signature_pointer : 1;
-
unsigned is_signature_reference : 1;
- unsigned has_default_implementation : 1;
- unsigned grokking_typedef : 1;
unsigned has_opaque_typedecls : 1;
unsigned sigtable_has_been_generated : 1;
unsigned was_anonymous : 1;
@@ -455,39 +604,30 @@ struct lang_type
/* The MIPS compiler gets it wrong if this struct also
does not fill out to a multiple of 4 bytes. Add a
member `dummy' with new bits if you go over the edge. */
- unsigned dummy : 19;
-
- unsigned n_vancestors : 16;
+ unsigned dummy : 11;
} type_flags;
+#ifdef MI_MATRIX
int cid;
+#endif
int n_ancestors;
+ int n_vancestors;
int vsize;
int max_depth;
int vfield_parent;
- union tree_node *vbinfo[2];
union tree_node *baselink_vec;
union tree_node *vfields;
union tree_node *vbases;
- union tree_node *vbase_size;
union tree_node *tags;
char *memoized_table_entry;
- char *search_slot;
-
-#ifdef ONLY_INT_FIELDS
- unsigned int mode : 8;
-#else
- enum machine_mode mode : 8;
-#endif
+ union tree_node *search_slot;
- unsigned char size_unit;
unsigned char align;
- unsigned char sep_unit;
+ /* Room for another three unsigned chars. */
- union tree_node *sep;
union tree_node *size;
union tree_node *base_init_list;
@@ -497,7 +637,9 @@ struct lang_type
union tree_node *binfo_as_list;
union tree_node *friend_classes;
+#ifdef MI_MATRIX
char *mi_matrix;
+#endif
union tree_node *rtti;
@@ -507,6 +649,8 @@ struct lang_type
union tree_node *signature_pointer_to;
union tree_node *signature_reference_to;
+ union tree_node *template_info;
+
int linenum;
};
@@ -549,21 +693,10 @@ struct lang_type
/* Nonzero for TREE_LIST or _TYPE node means that this node is class-local. */
#define TREE_NONLOCAL_FLAG(NODE) (TREE_LANG_FLAG_0 (NODE))
-/* Nonzero for a _CLASSTYPE node which we know to be private. */
-#define TYPE_PRIVATE_P(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.private_attr)
-
/* Nonzero means that this _CLASSTYPE node defines ways of converting
itself to other types. */
#define TYPE_HAS_CONVERSION(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_type_conversion)
-/* Nonzero means that this _CLASSTYPE node can convert itself to an
- INTEGER_TYPE. */
-#define TYPE_HAS_INT_CONVERSION(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_int_conversion)
-
-/* Nonzero means that this _CLASSTYPE node can convert itself to an
- REAL_TYPE. */
-#define TYPE_HAS_REAL_CONVERSION(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_float_conversion)
-
/* Nonzero means that this _CLASSTYPE node overloads operator=(X&). */
#define TYPE_HAS_ASSIGN_REF(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_assign_ref)
#define TYPE_HAS_CONST_ASSIGN_REF(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_const_assign_ref)
@@ -572,11 +705,6 @@ struct lang_type
#define TYPE_HAS_INIT_REF(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_init_ref)
#define TYPE_HAS_CONST_INIT_REF(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_const_init_ref)
-/* Nonzero means that this _CLASSTYPE node has an X(X ...) constructor.
- Note that there must be other arguments, or this constructor is flagged
- as being erroneous. */
-#define TYPE_GETS_INIT_AGGR(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.gets_init_aggr)
-
/* Nonzero means that this type is being defined. I.e., the left brace
starting the definition of this type has been seen. */
#define TYPE_BEING_DEFINED(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.being_defined)
@@ -584,10 +712,6 @@ struct lang_type
convenient, don't reprocess any methods that appear in its redefinition. */
#define TYPE_REDEFINED(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.redefined)
-/* Nonzero means that this _CLASSTYPE node overloads the method call
- operator. In this case, all method calls go through `operator->()(...). */
-#define TYPE_OVERLOADS_METHOD_CALL_EXPR(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_method_call_overloaded)
-
/* Nonzero means that this type is a signature. */
# define IS_SIGNATURE(NODE) (TYPE_LANG_SPECIFIC(NODE)?TYPE_LANG_SPECIFIC(NODE)->type_flags.is_signature:0)
# define SET_SIGNATURE(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.is_signature=1)
@@ -599,12 +723,6 @@ struct lang_type
/* Nonzero means that this type is a signature reference type. */
# define IS_SIGNATURE_REFERENCE(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.is_signature_reference)
-/* Nonzero means that this signature type has a default implementation. */
-# define HAS_DEFAULT_IMPLEMENTATION(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_default_implementation)
-
-/* Nonzero means that grokdeclarator works on a signature-local typedef. */
-#define SIGNATURE_GROKKING_TYPEDEF(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.grokking_typedef)
-
/* Nonzero means that this signature contains opaque type declarations. */
#define SIGNATURE_HAS_OPAQUE_TYPEDECLS(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_opaque_typedecls)
@@ -636,10 +754,6 @@ struct lang_type
/* The is the VAR_DECL that contains NODE's rtti. */
#define CLASSTYPE_RTTI(NODE) (TYPE_LANG_SPECIFIC(NODE)->rtti)
-/* List of all explicit methods (chained using DECL_NEXT_METHOD),
- in order they were parsed. */
-#define CLASSTYPE_METHODS(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods)
-
/* Nonzero means that this _CLASSTYPE node overloads operator(). */
#define TYPE_OVERLOADS_CALL_EXPR(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.has_call_overloaded)
@@ -660,14 +774,14 @@ struct lang_type
#define TYPE_USES_VIRTUAL_BASECLASSES(NODE) (TREE_LANG_FLAG_3(NODE))
/* List of lists of member functions defined in this class. */
-#define CLASSTYPE_METHOD_VEC(NODE) TYPE_METHODS(NODE)
+#define CLASSTYPE_METHOD_VEC(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods)
/* The first type conversion operator in the class (the others can be
searched with TREE_CHAIN), or the first non-constructor function if
there are no type conversion operators. */
#define CLASSTYPE_FIRST_CONVERSION(NODE) \
- TREE_VEC_LENGTH (CLASSTYPE_METHOD_VEC (NODE)) > 1 \
- ? TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), 1) \
+ TREE_VEC_LENGTH (CLASSTYPE_METHOD_VEC (NODE)) > 2 \
+ ? TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), 2) \
: NULL_TREE;
/* Pointer from any member function to the head of the list of
@@ -695,13 +809,17 @@ struct lang_type
#define SET_CLASSTYPE_MARKED6(NODE) (CLASSTYPE_MARKED6(NODE) = 1)
#define CLEAR_CLASSTYPE_MARKED6(NODE) (CLASSTYPE_MARKED6(NODE) = 0)
+/* A list of the nested tag-types (class, struct, union, or enum)
+ found within this class. The TREE_PURPOSE of each node is the name
+ of the type; the TREE_VALUE is the type itself. This list includes
+ nested member class templates. */
#define CLASSTYPE_TAGS(NODE) (TYPE_LANG_SPECIFIC(NODE)->tags)
/* If this class has any bases, this is the number of the base class from
which our VFIELD is based, -1 otherwise. If this class has no base
classes, this is not used.
In D : B1, B2, PARENT would be 0, if D's vtable came from B1,
- 1, if D's vtable came from B2. */
+ 1, if D's vtable came from B2. */
#define CLASSTYPE_VFIELD_PARENT(NODE) (TYPE_LANG_SPECIFIC(NODE)->vfield_parent)
/* Remove when done merging. */
@@ -725,7 +843,7 @@ struct lang_type
large a multiple-inheritance matrix we need to build to find
derivation information. */
#define CLASSTYPE_N_SUPERCLASSES(NODE) (TYPE_LANG_SPECIFIC(NODE)->n_ancestors)
-#define CLASSTYPE_N_VBASECLASSES(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.n_vancestors)
+#define CLASSTYPE_N_VBASECLASSES(NODE) (TYPE_LANG_SPECIFIC(NODE)->n_vancestors)
/* Record how deep the inheritance is for this class so `void*' conversions
are less favorable than a conversion to the most base type. */
@@ -740,20 +858,11 @@ struct lang_type
it can mean almost anything. */
#define CLASSTYPE_MTABLE_ENTRY(NODE) (TYPE_LANG_SPECIFIC(NODE)->memoized_table_entry)
-/* This is the total size of the baseclasses defined for this type.
- Needed because it is desirable to layout such information
- before beginning to process the class itself, and we
- don't want to compute it second time when actually laying
- out the type for real. */
+/* These are the size, mode and alignment of the type without its
+ virtual base classes, for when we use this type as a base itself. */
#define CLASSTYPE_SIZE(NODE) (TYPE_LANG_SPECIFIC(NODE)->size)
-#define CLASSTYPE_SIZE_UNIT(NODE) (TYPE_LANG_SPECIFIC(NODE)->size_unit)
-#define CLASSTYPE_MODE(NODE) (TYPE_LANG_SPECIFIC(NODE)->mode)
#define CLASSTYPE_ALIGN(NODE) (TYPE_LANG_SPECIFIC(NODE)->align)
-/* This is the space needed for virtual base classes. NULL if
- there are no virtual basetypes. */
-#define CLASSTYPE_VBASE_SIZE(NODE) (TYPE_LANG_SPECIFIC(NODE)->vbase_size)
-
/* A cons list of structure elements which either have constructors
to be called, or virtual function table pointers which
need initializing. Depending on what is being initialized,
@@ -807,17 +916,19 @@ struct lang_type
/* Same, but cache a list whose value is the binfo of this type. */
#define CLASSTYPE_BINFO_AS_LIST(NODE) (TYPE_LANG_SPECIFIC(NODE)->binfo_as_list)
-/* A list of class types with which this type is a friend. */
+/* A list of class types with which this type is a friend. The
+ TREE_VALUE is normally a TYPE, but will be a TEMPLATE_DECL in the
+ case of a template friend. */
#define CLASSTYPE_FRIEND_CLASSES(NODE) (TYPE_LANG_SPECIFIC(NODE)->friend_classes)
+#ifdef MI_MATRIX
/* Keep an inheritance lattice around so we can quickly tell whether
a type is derived from another or not. */
#define CLASSTYPE_MI_MATRIX(NODE) (TYPE_LANG_SPECIFIC(NODE)->mi_matrix)
+#endif
/* Say whether this node was declared as a "class" or a "struct". */
#define CLASSTYPE_DECLARED_CLASS(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.declared_class)
-/* whether this can be globalized. */
-#define CLASSTYPE_NO_GLOBALIZE(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.no_globalize)
/* Nonzero if this class has const members which have no specified initialization. */
#define CLASSTYPE_READONLY_FIELDS_NEED_INIT(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.const_needs_init)
@@ -838,24 +949,20 @@ struct lang_type
/* Nonzero if a _DECL node requires us to output debug info for this class. */
#define CLASSTYPE_DEBUG_REQUESTED(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.debug_requested)
-
-#define TYPE_INCOMPLETE(NODE) \
- (TYPE_SIZE (NODE) == NULL_TREE && TREE_CODE (NODE) != TEMPLATE_TYPE_PARM)
/* Additional macros for inheritance information. */
-#define CLASSTYPE_VBINFO(NODE,VIA_PUBLIC) \
- (TYPE_LANG_SPECIFIC (NODE)->vbinfo[VIA_PUBLIC])
-
/* When following an binfo-specific chain, this is the cumulative
via-public flag. */
#define BINFO_VIA_PUBLIC(NODE) TREE_LANG_FLAG_5 (NODE)
+#ifdef MI_MATRIX
/* When building a matrix to determine by a single lookup
whether one class is derived from another or not,
this field is the index of the class in the table. */
#define CLASSTYPE_CID(NODE) (TYPE_LANG_SPECIFIC(NODE)->cid)
#define BINFO_CID(NODE) CLASSTYPE_CID(BINFO_TYPE(NODE))
+#endif
/* Nonzero means marked by DFS or BFS search, including searches
by `get_binfo' and `get_base_distance'. */
@@ -923,8 +1030,8 @@ struct lang_type
this type can raise. */
#define TYPE_RAISES_EXCEPTIONS(NODE) TYPE_NONCOPIED_PARTS (NODE)
-/* The binding level associated with the namespace. */
-#define NAMESPACE_LEVEL(NODE) ((NODE)->decl.arguments)
+/* The binding level associated with the namespace. */
+#define NAMESPACE_LEVEL(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.level)
struct lang_decl_flags
{
@@ -951,38 +1058,48 @@ struct lang_decl_flags
unsigned saved_inline : 1;
unsigned use_template : 2;
- unsigned c_static : 1;
unsigned nonconverting : 1;
unsigned declared_inline : 1;
unsigned not_really_extern : 1;
- unsigned dummy : 4;
+ unsigned comdat : 1;
+ unsigned needs_final_overrider : 1;
+ unsigned dummy : 3;
tree access;
tree context;
tree memfunc_pointer_to;
+ tree template_info;
+ struct binding_level *level;
};
struct lang_decl
{
struct lang_decl_flags decl_flags;
- struct template_info *template_info;
tree main_decl_variant;
struct pending_inline *pending_inline_info;
- tree next_method;
- tree chain;
};
/* Non-zero if NODE is a _DECL with TREE_READONLY set. */
#define TREE_READONLY_DECL_P(NODE) \
(TREE_READONLY (NODE) && TREE_CODE_CLASS (TREE_CODE (NODE)) == 'd')
+/* Non-zero iff DECL is memory-based. The DECL_RTL of
+ certain const variables might be a CONST_INT, or a REG
+ in some cases. We cannot use `memory_operand' as a test
+ here because on most RISC machines, a variable's address
+ is not, by itself, a legitimate address. */
+#define DECL_IN_MEMORY_P(NODE) \
+ (DECL_RTL (NODE) != NULL_RTX && GET_CODE (DECL_RTL (NODE)) == MEM)
+
/* For FUNCTION_DECLs: return the language in which this decl
was declared. */
#define DECL_LANGUAGE(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.language)
/* For FUNCTION_DECLs: nonzero means that this function is a constructor. */
#define DECL_CONSTRUCTOR_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_attr)
+#define DECL_DESTRUCTOR_P(NODE) (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME(NODE)))
+
/* For FUNCTION_DECLs: nonzero means that this function is a constructor
for an object with virtual baseclasses. */
#define DECL_CONSTRUCTOR_FOR_VBASE_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_for_vbase_attr)
@@ -997,7 +1114,7 @@ struct lang_decl
/* Nonzero for FUNCTION_DECL means that this constructor is known to
not make any assignment to `this', and therefore can be trusted
- to return it unchanged. Otherwise, we must re-assign `current_class_decl'
+ to return it unchanged. Otherwise, we must re-assign `current_class_ptr'
after performing base initializations. */
#define DECL_PRESERVES_THIS(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.preserves_first_arg)
@@ -1023,10 +1140,15 @@ struct lang_decl
(TREE_CODE (NODE) == VAR_DECL || TREE_CODE (NODE) == TYPE_DECL \
|| TREE_CODE (NODE) == CONST_DECL)
+/* Nonzero for FUNCTION_DECL means that this decl is a non-static
+ member function. */
+#define DECL_NONSTATIC_MEMBER_FUNCTION_P(NODE) \
+ (TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE)
+
/* Nonzero for FUNCTION_DECL means that this decl is a member function
(static or non-static). */
#define DECL_FUNCTION_MEMBER_P(NODE) \
- (TREE_CODE (TREE_TYPE (NODE)) == METHOD_TYPE || DECL_STATIC_FUNCTION_P (NODE))
+ (DECL_NONSTATIC_MEMBER_FUNCTION_P (NODE) || DECL_STATIC_FUNCTION_P (NODE))
/* Nonzero for FUNCTION_DECL means that this member function
has `this' as const X *const. */
@@ -1048,31 +1170,57 @@ struct lang_decl
exists as part of an abstract class's interface. */
#define DECL_ABSTRACT_VIRTUAL_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.abstract_virtual)
+/* Nonzero for FUNCTION_DECL means that this member function
+ must be overridden by derived classes. */
+#define DECL_NEEDS_FINAL_OVERRIDER_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.needs_final_overrider)
+
/* Nonzero if allocated on permanent_obstack. */
#define LANG_DECL_PERMANENT(LANGDECL) ((LANGDECL)->decl_flags.permanent_attr)
/* The _TYPE context in which this _DECL appears. This field holds the
class where a virtual function instance is actually defined, and the
- lexical scope of a friend function defined in a class body. */
+ lexical scope of a friend function defined in a class body. */
#define DECL_CLASS_CONTEXT(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.context)
#define DECL_REAL_CONTEXT(NODE) \
((TREE_CODE (NODE) == FUNCTION_DECL && DECL_FUNCTION_MEMBER_P (NODE)) \
- ? DECL_CLASS_CONTEXT (NODE) : DECL_CONTEXT (NODE))
-
-/* For a FUNCTION_DECL: the chain through which the next method
- in the method chain is found. We now use TREE_CHAIN to
- link into the FIELD_DECL chain. */
-#if 1
-#define DECL_CHAIN(NODE) (DECL_LANG_SPECIFIC(NODE)->chain)
-#else
-#define DECL_CHAIN(NODE) (TREE_CHAIN (NODE))
-#endif
-
-/* Next method in CLASSTYPE_METHODS list. */
-#define DECL_NEXT_METHOD(NODE) (DECL_LANG_SPECIFIC(NODE)->next_method)
+ ? DECL_CLASS_CONTEXT (NODE) : CP_DECL_CONTEXT (NODE))
+
+/* NULL_TREE in DECL_CONTEXT represents the global namespace. */
+#define CP_DECL_CONTEXT(NODE) \
+ (DECL_CONTEXT (NODE) ? DECL_CONTEXT (NODE) : global_namespace)
+#define FROB_CONTEXT(NODE) ((NODE) == global_namespace ? NULL_TREE : (NODE))
+
+/* 1 iff NODE has namespace scope, including the global namespace. */
+#define DECL_NAMESPACE_SCOPE_P(NODE) \
+ (DECL_CONTEXT (NODE) == NULL_TREE \
+ || TREE_CODE (DECL_CONTEXT (NODE)) == NAMESPACE_DECL)
+
+/* 1 iff NODE is a class member. */
+#define DECL_CLASS_SCOPE_P(NODE) \
+ (DECL_CONTEXT (NODE) \
+ && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (NODE))) == 't')
+
+/* For a NAMESPACE_DECL: the list of using namespace directives
+ The PURPOSE is the used namespace, the value is the namespace
+ that is the common ancestor. */
+#define DECL_NAMESPACE_USING(NODE) DECL_VINDEX(NODE)
+
+/* In a NAMESPACE_DECL, the DECL_INITIAL is used to record all users
+ of a namespace, to record the transitive closure of using namespace. */
+#define DECL_NAMESPACE_USERS(NODE) DECL_INITIAL (NODE)
+
+/* In a NAMESPACE_DECL, points to the original namespace if this is
+ a namespace alias. */
+#define DECL_NAMESPACE_ALIAS(NODE) DECL_ABSTRACT_ORIGIN (NODE)
+#define ORIGINAL_NAMESPACE(NODE) \
+ (DECL_NAMESPACE_ALIAS (NODE) ? DECL_NAMESPACE_ALIAS (NODE) : (NODE))
+
+/* In a TREE_LIST concatenating using directives, indicate indirekt
+ directives */
+#define TREE_INDIRECT_USING(NODE) ((NODE)->common.lang_flag_0)
/* In a VAR_DECL for a variable declared in a for statement,
- this is the shadowed variable. */
+ this is the shadowed (local) variable. */
#define DECL_SHADOWED_FOR_VAR(NODE) DECL_RESULT(NODE)
/* Points back to the decl which caused this lang_decl to be allocated. */
@@ -1083,7 +1231,7 @@ struct lang_decl
squirreled away. */
#define DECL_PENDING_INLINE_INFO(NODE) (DECL_LANG_SPECIFIC(NODE)->pending_inline_info)
-/* True if on the saved_inlines (see decl2.c) list. */
+/* True if on the saved_inlines (see decl2.c) list. */
#define DECL_SAVED_INLINE(DECL) \
(DECL_LANG_SPECIFIC(DECL)->decl_flags.saved_inline)
@@ -1096,31 +1244,71 @@ struct lang_decl
which this signature member function pointer was created. */
#define DECL_MEMFUNC_POINTING_TO(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.memfunc_pointer_to)
-/* For a TEMPLATE_DECL: template-specific information. */
-#define DECL_TEMPLATE_INFO(NODE) (DECL_LANG_SPECIFIC(NODE)->template_info)
-
-/* Nonzero in INT_CST means that this int is negative by dint of
+/* For a VAR_DECL or FUNCTION_DECL: template-specific information. */
+#define DECL_TEMPLATE_INFO(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.template_info)
+#define CLASSTYPE_TEMPLATE_INFO(NODE) (TYPE_LANG_SPECIFIC(NODE)->template_info)
+#define TI_TEMPLATE(NODE) (TREE_PURPOSE (NODE))
+#define TI_ARGS(NODE) (TREE_VALUE (NODE))
+#define TI_SPEC_INFO(NODE) (TREE_CHAIN (NODE))
+#define TI_USES_TEMPLATE_PARMS(NODE) TREE_LANG_FLAG_0 (NODE)
+#define TI_PENDING_TEMPLATE_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
+/* TI_PENDING_SPECIALIZATION_FLAG on a template-info node indicates
+ that the template is a specialization of a member template, but
+ that we don't yet know which one. */
+#define TI_PENDING_SPECIALIZATION_FLAG(NODE) TREE_LANG_FLAG_1 (NODE)
+#define DECL_TI_TEMPLATE(NODE) TI_TEMPLATE (DECL_TEMPLATE_INFO (NODE))
+#define DECL_TI_ARGS(NODE) TI_ARGS (DECL_TEMPLATE_INFO (NODE))
+#define CLASSTYPE_TI_TEMPLATE(NODE) TI_TEMPLATE (CLASSTYPE_TEMPLATE_INFO (NODE))
+#define CLASSTYPE_TI_ARGS(NODE) TI_ARGS (CLASSTYPE_TEMPLATE_INFO (NODE))
+#define CLASSTYPE_TI_SPEC_INFO(NODE) TI_SPEC_INFO (CLASSTYPE_TEMPLATE_INFO (NODE))
+#define INNERMOST_TEMPLATE_PARMS(NODE) TREE_VALUE(NODE)
+
+#define TEMPLATE_PARMS_FOR_INLINE(NODE) TREE_LANG_FLAG_1 (NODE)
+
+#define DECL_SAVED_TREE(NODE) DECL_MEMFUNC_POINTER_TO (NODE)
+#define COMPOUND_STMT_NO_SCOPE(NODE) TREE_LANG_FLAG_0 (NODE)
+#define NEW_EXPR_USE_GLOBAL(NODE) TREE_LANG_FLAG_0 (NODE)
+#define DELETE_EXPR_USE_GLOBAL(NODE) TREE_LANG_FLAG_0 (NODE)
+#define DELETE_EXPR_USE_VEC(NODE) TREE_LANG_FLAG_1 (NODE)
+#define LOOKUP_EXPR_GLOBAL(NODE) TREE_LANG_FLAG_0 (NODE)
+
+/* The TYPE_MAIN_DECL for a class template type is a TYPE_DECL, not a
+ TEMPLATE_DECL. This macro determines whether or not a given class
+ type is really a template type, as opposed to an instantiation or
+ specialization of one. */
+#define CLASSTYPE_IS_TEMPLATE(NODE) \
+ (CLASSTYPE_TEMPLATE_INFO (NODE) \
+ && !CLASSTYPE_USE_TEMPLATE (NODE) \
+ && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (NODE)))
+
+#define TYPENAME_TYPE_FULLNAME(NODE) CLASSTYPE_SIZE (NODE)
+
+/* Nonzero in INTEGER_CST means that this int is negative by dint of
using a twos-complement negated operand. */
#define TREE_NEGATED_INT(NODE) (TREE_LANG_FLAG_0 (NODE))
+#if 0 /* UNUSED */
/* Nonzero in any kind of _EXPR or _REF node means that it is a call
to a storage allocation routine. If, later, alternate storage
is found to hold the object, this call can be ignored. */
#define TREE_CALLS_NEW(NODE) (TREE_LANG_FLAG_1 (NODE))
+#endif
/* Nonzero in any kind of _TYPE that uses multiple inheritance
or virtual baseclasses. */
#define TYPE_USES_COMPLEX_INHERITANCE(NODE) (TREE_LANG_FLAG_1 (NODE))
+#if 0 /* UNUSED */
/* Nonzero in IDENTIFIER_NODE means that this name is not the name the user
gave; it's a DECL_NESTED_TYPENAME. Someone may want to set this on
mangled function names, too, but it isn't currently. */
#define TREE_MANGLED(NODE) (TREE_LANG_FLAG_0 (NODE))
+#endif
#if 0 /* UNUSED */
/* Nonzero in IDENTIFIER_NODE means that this name is overloaded, and
should be looked up in a non-standard way. */
-#define DECL_OVERLOADED(NODE) (DECL_LANG_FLAG_4 (NODE))
+#define DECL_OVERLOADED(NODE) (FOO)
#endif
/* Nonzero if this (non-TYPE)_DECL has its virtual attribute set.
@@ -1134,20 +1322,10 @@ struct lang_decl
one that does). */
#define TYPE_VIRTUAL_P(NODE) (TREE_LANG_FLAG_2 (NODE))
-#if 0
-/* Same, but tells if this field is private in current context. */
-#define DECL_PRIVATE(NODE) (FOO)
-
-/* Same, but tells if this field is private in current context. */
-#define DECL_PROTECTED(NODE) (DECL_LANG_FLAG_6 (NODE))
-
-#define DECL_PUBLIC(NODE) (DECL_LANG_FLAG_7 (NODE))
-#endif
-
extern int flag_new_for_scope;
/* This flag is true of a local VAR_DECL if it was declared in a for
- statement, but we are no longer in the scope of the for. */
+ statement, but we are no longer in the scope of the for. */
#define DECL_DEAD_FOR_LOCAL(NODE) DECL_LANG_FLAG_7 (NODE)
/* This flag is set on a VAR_DECL that is a DECL_DEAD_FOR_LOCAL
@@ -1179,11 +1357,6 @@ extern int flag_new_for_scope;
These may be shadowed, and may be referenced from nested functions. */
#define C_DECLARED_LABEL_FLAG(label) TREE_LANG_FLAG_1 (label)
-/* Record whether a type or decl was written with nonconstant size.
- Note that TYPE_SIZE may have simplified to a constant. */
-#define C_TYPE_VARIABLE_SIZE(type) TREE_LANG_FLAG_4 (type)
-#define C_DECL_VARIABLE_SIZE(type) DECL_LANG_FLAG_8 (type)
-
/* Nonzero for _TYPE means that the _TYPE defines
at least one constructor. */
#define TYPE_HAS_CONSTRUCTOR(NODE) (TYPE_LANG_FLAG_1(NODE))
@@ -1207,10 +1380,12 @@ extern int flag_new_for_scope;
#define EMPTY_CONSTRUCTOR_P(NODE) (TREE_CODE (NODE) == CONSTRUCTOR \
&& CONSTRUCTOR_ELTS (NODE) == NULL_TREE)
+#if 0
/* Indicates that a NON_LVALUE_EXPR came from a C++ reference.
Used to generate more helpful error message in case somebody
tries to take its address. */
#define TREE_REFERENCE_EXPR(NODE) (TREE_LANG_FLAG_3(NODE))
+#endif
/* Nonzero for _TYPE means that the _TYPE defines a destructor. */
#define TYPE_HAS_DESTRUCTOR(NODE) (TYPE_LANG_FLAG_2(NODE))
@@ -1219,7 +1394,7 @@ extern int flag_new_for_scope;
/* Nonzero for _TYPE node means that creating an object of this type
will involve a call to a constructor. This can apply to objects
of ARRAY_TYPE if the type of the elements needs a constructor. */
-#define TYPE_NEEDS_CONSTRUCTING(NODE) (TYPE_LANG_FLAG_3(NODE))
+#define TYPE_NEEDS_CONSTRUCTING(NODE) ... defined in ../tree.h ...
#endif
/* Nonzero means that an object of this type can not be initialized using
@@ -1250,21 +1425,41 @@ extern int flag_new_for_scope;
#define TYPE_HAS_TRIVIAL_ASSIGN_REF(NODE) \
(TYPE_HAS_ASSIGN_REF (NODE) && ! TYPE_HAS_COMPLEX_ASSIGN_REF (NODE))
+#define TYPE_PTRMEM_P(NODE) \
+ (TREE_CODE (NODE) == POINTER_TYPE \
+ && TREE_CODE (TREE_TYPE (NODE)) == OFFSET_TYPE)
+#define TYPE_PTR_P(NODE) \
+ (TREE_CODE (NODE) == POINTER_TYPE \
+ && TREE_CODE (TREE_TYPE (NODE)) != OFFSET_TYPE)
+#define TYPE_PTROB_P(NODE) \
+ (TYPE_PTR_P (NODE) && TREE_CODE (TREE_TYPE (NODE)) != FUNCTION_TYPE \
+ && TREE_CODE (TREE_TYPE (NODE)) != VOID_TYPE)
+#define TYPE_PTROBV_P(NODE) \
+ (TYPE_PTR_P (NODE) && TREE_CODE (TREE_TYPE (NODE)) != FUNCTION_TYPE)
+#define TYPE_PTRFN_P(NODE) \
+ (TREE_CODE (NODE) == POINTER_TYPE \
+ && TREE_CODE (TREE_TYPE (NODE)) == FUNCTION_TYPE)
+
/* Nonzero for _TYPE node means that this type is a pointer to member
- function type. */
+ function type. */
#define TYPE_PTRMEMFUNC_P(NODE) (TREE_CODE(NODE) == RECORD_TYPE && TYPE_LANG_SPECIFIC(NODE)->type_flags.ptrmemfunc_flag)
#define TYPE_PTRMEMFUNC_FLAG(NODE) (TYPE_LANG_SPECIFIC(NODE)->type_flags.ptrmemfunc_flag)
/* Get the POINTER_TYPE to the METHOD_TYPE associated with this
pointer to member function. TYPE_PTRMEMFUNC_P _must_ be true,
- before using this macro. */
+ before using this macro. */
#define TYPE_PTRMEMFUNC_FN_TYPE(NODE) (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (NODE)))))))
-/* These are use to manipulate the the canonical RECORD_TYPE from the
- hashed POINTER_TYPE, and can only be used on the POINTER_TYPE. */
+
+/* Returns `A' for a type like `int (A::*)(double)' */
+#define TYPE_PTRMEMFUNC_OBJECT_TYPE(NODE) \
+ TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (NODE)))
+
+/* These are use to manipulate the canonical RECORD_TYPE from the
+ hashed POINTER_TYPE, and can only be used on the POINTER_TYPE. */
#define TYPE_GET_PTRMEMFUNC_TYPE(NODE) ((tree)TYPE_LANG_SPECIFIC(NODE))
#define TYPE_SET_PTRMEMFUNC_TYPE(NODE, VALUE) (TYPE_LANG_SPECIFIC(NODE) = ((struct lang_type *)(void*)(VALUE)))
-/* These are to get the delta2 and pfn fields from a TYPE_PTRMEMFUNC_P. */
-#define DELTA2_FROM_PTRMEMFUNC(NODE) (build_component_ref (build_component_ref ((NODE), pfn_or_delta2_identifier, 0, 0), delta2_identifier, 0, 0))
-#define PFN_FROM_PTRMEMFUNC(NODE) (build_component_ref (build_component_ref ((NODE), pfn_or_delta2_identifier, 0, 0), pfn_identifier, 0, 0))
+/* These are to get the delta2 and pfn fields from a TYPE_PTRMEMFUNC_P. */
+#define DELTA2_FROM_PTRMEMFUNC(NODE) (build_component_ref (build_component_ref ((NODE), pfn_or_delta2_identifier, NULL_TREE, 0), delta2_identifier, NULL_TREE, 0))
+#define PFN_FROM_PTRMEMFUNC(NODE) (build_component_ref (build_component_ref ((NODE), pfn_or_delta2_identifier, NULL_TREE, 0), pfn_identifier, NULL_TREE, 0))
/* Nonzero for VAR_DECL and FUNCTION_DECL node means that `extern' was
specified in its declaration. */
@@ -1283,6 +1478,11 @@ extern int flag_new_for_scope;
#define ANON_UNION_P(NODE) (DECL_NAME (NODE) == 0)
+/* Nonzero if TYPE is an anonymous union type. */
+#define ANON_UNION_TYPE_P(TYPE) \
+ (TREE_CODE (TYPE) == UNION_TYPE \
+ && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TYPE)))
+
#define UNKNOWN_TYPE LANG_TYPE
/* Define fields and accessors for nodes representing declared names. */
@@ -1299,22 +1499,22 @@ extern int flag_new_for_scope;
#define DECL_VPARENT(NODE) ((NODE)->decl.arguments)
#endif
-/* Make a slot so we can implement nested types. This slot holds
- the IDENTIFIER_NODE that uniquely names the nested type. This
- is for TYPE_DECLs only. */
-#define DECL_NESTED_TYPENAME(NODE) ((NODE)->decl.arguments)
-#define TYPE_NESTED_NAME(NODE) (DECL_NESTED_TYPENAME (TYPE_NAME (NODE)))
-
#define TYPE_WAS_ANONYMOUS(NODE) (TYPE_LANG_SPECIFIC (NODE)->type_flags.was_anonymous)
/* C++: all of these are overloaded! These apply only to TYPE_DECLs. */
+
+/* The format of each node in the DECL_FRIENDLIST is as follows:
+
+ The TREE_PURPOSE will be the name of a function, i.e., an
+ IDENTIFIER_NODE. The TREE_VALUE will be itself a TREE_LIST, the
+ list of functions with that name which are friends. The
+ TREE_PURPOSE of each node in this sublist will be error_mark_node,
+ if the function was declared a friend individually, in which case
+ the TREE_VALUE will be the function_decl. If, however, all
+ functions with a given name in a class were declared to be friends,
+ the TREE_PUROSE will be the class type, and the TREE_VALUE will be
+ NULL_TREE. */
#define DECL_FRIENDLIST(NODE) (DECL_INITIAL (NODE))
-#if 0
-#define DECL_UNDEFINED_FRIENDS(NODE) ((NODE)->decl.result)
-#endif
-#define DECL_WAITING_FRIENDS(NODE) ((tree)(NODE)->decl.rtl)
-#define SET_DECL_WAITING_FRIENDS(NODE,VALUE) \
- ((NODE)->decl.rtl=(struct rtx_def*)VALUE)
/* The DECL_ACCESS is used to record under which context
special access rules apply. */
@@ -1325,25 +1525,70 @@ extern int flag_new_for_scope;
#define DECL_REFERENCE_SLOT(NODE) ((tree)(NODE)->decl.arguments)
#define SET_DECL_REFERENCE_SLOT(NODE,VAL) ((NODE)->decl.arguments=VAL)
-/* For local VAR_DECLs, holds index into gc-protected obstack. */
-#define DECL_GC_OFFSET(NODE) ((NODE)->decl.result)
-
/* Accessor macros for C++ template decl nodes. */
-#define DECL_TEMPLATE_IS_CLASS(NODE) (DECL_RESULT(NODE) == NULL_TREE)
+
+/* The DECL_TEMPLATE_PARMS are a list. The TREE_PURPOSE of each node
+ indicates the level of the template parameters, with 1 being the
+ outermost set of template parameters. The TREE_VALUE is a vector,
+ whose elements are the template parameters at each level. Each
+ element in the vector is a TREE_LIST, whose TREE_VALUE is a
+ PARM_DECL (if the parameter is a non-type parameter), or a
+ TYPE_DECL (if the parameter is a type parameter). The TREE_PURPOSE
+ is the default value, if any. The TEMPLATE_PARM_INDEX for the
+ parameter is avilable as the DECL_INITIAL (for a PARM_DECL) or as
+ the TREE_TYPE (for a TYPE_DECL). */
#define DECL_TEMPLATE_PARMS(NODE) DECL_ARGUMENTS(NODE)
+#define DECL_INNERMOST_TEMPLATE_PARMS(NODE) \
+ INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (NODE))
+#define DECL_NTPARMS(NODE) \
+ TREE_VEC_LENGTH (DECL_INNERMOST_TEMPLATE_PARMS (NODE))
/* For class templates. */
-#define DECL_TEMPLATE_MEMBERS(NODE) DECL_SIZE(NODE)
+#define DECL_TEMPLATE_SPECIALIZATIONS(NODE) DECL_SIZE(NODE)
/* For function, method, class-data templates. */
#define DECL_TEMPLATE_RESULT(NODE) DECL_RESULT(NODE)
#define DECL_TEMPLATE_INSTANTIATIONS(NODE) DECL_VINDEX(NODE)
+#define DECL_TEMPLATE_INJECT(NODE) DECL_INITIAL(NODE)
+
+/* Nonzero for TEMPLATE_DECL nodes that represents template template
+ parameters */
+#define DECL_TEMPLATE_TEMPLATE_PARM_P(NODE) \
+ (TREE_CODE (NODE) == TEMPLATE_DECL && TREE_TYPE (NODE) \
+ && TREE_CODE (TREE_TYPE (NODE)) == TEMPLATE_TEMPLATE_PARM)
+
+#define DECL_FUNCTION_TEMPLATE_P(NODE) \
+ (TREE_CODE (NODE) == TEMPLATE_DECL \
+ && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == FUNCTION_DECL)
+
+/* Nonzero for a DECL that represents a template class. */
+#define DECL_CLASS_TEMPLATE_P(NODE) \
+ (TREE_CODE (NODE) == TEMPLATE_DECL \
+ && TREE_CODE (DECL_TEMPLATE_RESULT (NODE)) == TYPE_DECL \
+ && !DECL_TEMPLATE_TEMPLATE_PARM_P (NODE))
+
+/* Nonzero if NODE which declares a type. */
+#define DECL_DECLARES_TYPE_P(NODE) \
+ (TREE_CODE (NODE) == TYPE_DECL || DECL_CLASS_TEMPLATE_P (NODE))
+
+/* A `primary' template is one that has its own template header. A
+ member function of a class template is a template, but not primary.
+ A member template is primary. Friend templates are primary, too. */
+
+/* Returns the primary template corresponding to these parameters. */
+#define DECL_PRIMARY_TEMPLATE(NODE) \
+ (TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (NODE)))
+
+/* Returns non-zero if NODE is a primary template. */
+#define PRIMARY_TEMPLATE_P(NODE) (DECL_PRIMARY_TEMPLATE (NODE) == NODE)
+
+#define CLASSTYPE_TEMPLATE_LEVEL(NODE) \
+ (TREE_INT_CST_HIGH (TREE_PURPOSE (CLASSTYPE_TI_TEMPLATE (NODE))))
/* Indicates whether or not (and how) a template was expanded for this
FUNCTION_DECL or VAR_DECL.
0=normal declaration, e.g. int min (int, int);
1=implicit template instantiation
2=explicit template specialization, e.g. int min<int> (int, int);
- 3=explicit template instantiation, e.g. template int min<int> (int, int);
- */
+ 3=explicit template instantiation, e.g. template int min<int> (int, int); */
#define DECL_USE_TEMPLATE(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.use_template)
#define DECL_TEMPLATE_INSTANTIATION(NODE) (DECL_USE_TEMPLATE (NODE) & 1)
@@ -1371,14 +1616,11 @@ extern int flag_new_for_scope;
#define SET_CLASSTYPE_EXPLICIT_INSTANTIATION(NODE) \
(CLASSTYPE_USE_TEMPLATE(NODE) = 3)
+/* This function may be a guiding decl for a template. */
+#define DECL_MAYBE_TEMPLATE(NODE) DECL_LANG_FLAG_4 (NODE)
/* We know what we're doing with this decl now. */
#define DECL_INTERFACE_KNOWN(NODE) DECL_LANG_FLAG_5 (NODE)
-/* This decl was declared or deduced to have internal linkage. This is
- only meaningful if TREE_PUBLIC is set. */
-#define DECL_C_STATIC(NODE) \
- (DECL_LANG_SPECIFIC (NODE)->decl_flags.c_static)
-
/* This function was declared inline. This flag controls the linkage
semantics of 'inline'; whether or not the function is inlined is
controlled by DECL_INLINE. */
@@ -1391,9 +1633,12 @@ extern int flag_new_for_scope;
#define DECL_NOT_REALLY_EXTERN(NODE) \
(DECL_LANG_SPECIFIC (NODE)->decl_flags.not_really_extern)
-#define DECL_PUBLIC(NODE) \
- (TREE_CODE (NODE) == FUNCTION_DECL \
- ? ! DECL_C_STATIC (NODE) : TREE_PUBLIC (NODE))
+#define DECL_REALLY_EXTERN(NODE) \
+ (DECL_EXTERNAL (NODE) && ! DECL_NOT_REALLY_EXTERN (NODE))
+
+/* Used to tell cp_finish_decl that it should approximate comdat linkage
+ as best it can for this decl. */
+#define DECL_COMDAT(NODE) (DECL_LANG_SPECIFIC (NODE)->decl_flags.comdat)
#define THUNK_DELTA(DECL) ((DECL)->decl.frame_size.i)
@@ -1401,6 +1646,45 @@ extern int flag_new_for_scope;
#define UPT_TEMPLATE(NODE) TREE_PURPOSE(TYPE_VALUES(NODE))
#define UPT_PARMS(NODE) TREE_VALUE(TYPE_VALUES(NODE))
+/* An un-parsed default argument looks like an identifier. */
+#define DEFARG_NODE_CHECK(t) TREE_CHECK(t, DEFAULT_ARG)
+#define DEFARG_LENGTH(NODE) (DEFARG_NODE_CHECK(NODE)->identifier.length)
+#define DEFARG_POINTER(NODE) (DEFARG_NODE_CHECK(NODE)->identifier.pointer)
+
+#define builtin_function(NAME, TYPE, CODE, LIBNAME) \
+ define_function (NAME, TYPE, CODE, (void (*) PROTO((tree)))pushdecl, LIBNAME)
+
+/* These macros provide convenient access to the various _STMT nodes
+ created when parsing template declarations. */
+#define IF_COND(NODE) TREE_OPERAND (NODE, 0)
+#define THEN_CLAUSE(NODE) TREE_OPERAND (NODE, 1)
+#define ELSE_CLAUSE(NODE) TREE_OPERAND (NODE, 2)
+#define WHILE_COND(NODE) TREE_OPERAND (NODE, 0)
+#define WHILE_BODY(NODE) TREE_OPERAND (NODE, 1)
+#define DO_COND(NODE) TREE_OPERAND (NODE, 0)
+#define DO_BODY(NODE) TREE_OPERAND (NODE, 1)
+#define RETURN_EXPR(NODE) TREE_OPERAND (NODE, 0)
+#define EXPR_STMT_EXPR(NODE) TREE_OPERAND (NODE, 0)
+#define FOR_INIT_STMT(NODE) TREE_OPERAND (NODE, 0)
+#define FOR_COND(NODE) TREE_OPERAND (NODE, 1)
+#define FOR_EXPR(NODE) TREE_OPERAND (NODE, 2)
+#define FOR_BODY(NODE) TREE_OPERAND (NODE, 3)
+#define SWITCH_COND(NODE) TREE_OPERAND (NODE, 0)
+#define SWITCH_BODY(NODE) TREE_OPERAND (NODE, 1)
+#define CASE_LOW(NODE) TREE_OPERAND (NODE, 0)
+#define CASE_HIGH(NODE) TREE_OPERAND (NODE, 1)
+#define GOTO_DESTINATION(NODE) TREE_OPERAND (NODE, 0)
+#define TRY_STMTS(NODE) TREE_OPERAND (NODE, 0)
+#define TRY_HANDLERS(NODE) TREE_OPERAND (NODE, 1)
+#define HANDLER_PARMS(NODE) TREE_OPERAND (NODE, 0)
+#define HANDLER_BODY(NODE) TREE_OPERAND (NODE, 1)
+#define COMPOUND_BODY(NODE) TREE_OPERAND (NODE, 0)
+#define ASM_CV_QUAL(NODE) TREE_OPERAND (NODE, 0)
+#define ASM_STRING(NODE) TREE_OPERAND (NODE, 1)
+#define ASM_OUTPUTS(NODE) TREE_OPERAND (NODE, 2)
+#define ASM_INPUTS(NODE) TREE_OPERAND (NODE, 3)
+#define ASM_CLOBBERS(NODE) TREE_OPERAND (NODE, 4)
+
/* An enumeration of the kind of tags that C++ accepts. */
enum tag_types { record_type, class_type, union_type, enum_type,
signature_type };
@@ -1423,6 +1707,9 @@ extern int flag_detailed_statistics;
type signature of any virtual function in the base class. */
extern int warn_overloaded_virtual;
+/* Nonzero means warn about use of multicharacter literals. */
+extern int warn_multichar;
+
/* in c-common.c */
extern void declare_function_name PROTO((void));
extern void decl_attributes PROTO((tree, tree, tree));
@@ -1433,6 +1720,7 @@ extern void check_function_format PROTO((tree, tree, tree));
NOP_EXPR is used as a special case (see truthvalue_conversion). */
extern void binary_op_error PROTO((enum tree_code));
extern tree cp_build_type_variant PROTO((tree, int, int));
+extern tree canonical_type_variant PROTO((tree));
extern void c_expand_expr_stmt PROTO((tree));
/* Validate the expression after `case' and apply default promotions. */
extern tree check_case_value PROTO((tree));
@@ -1443,16 +1731,23 @@ extern tree convert_and_check PROTO((tree, tree));
extern void overflow_warning PROTO((tree));
extern void unsigned_conversion_warning PROTO((tree, tree));
/* Read the rest of the current #-directive line. */
-extern char *get_directive_line STDIO_PROTO((FILE *));
+#if USE_CPPLIB
+extern char *get_directive_line PROTO((void));
+#define GET_DIRECTIVE_LINE() get_directive_line ()
+#else
+extern char *get_directive_line PROTO((FILE *));
+#define GET_DIRECTIVE_LINE() get_directive_line (finput)
+#endif
/* Subroutine of build_binary_op, used for comparison operations.
See if the operands have both been converted from subword integer types
and, if so, perhaps change them both back to their original type. */
extern tree shorten_compare PROTO((tree *, tree *, tree *, enum tree_code *));
/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
- or validate its data type for an `if' or `while' statement or ?..: exp. */
+ or validate its data type for an `if' or `while' statement or ?..: exp. */
extern tree truthvalue_conversion PROTO((tree));
extern tree type_for_mode PROTO((enum machine_mode, int));
extern tree type_for_size PROTO((unsigned, int));
+extern int c_get_alias_set PROTO((tree));
/* in decl{2}.c */
extern tree void_list_node;
@@ -1461,7 +1756,9 @@ extern tree default_function_type;
extern tree vtable_entry_type;
extern tree sigtable_entry_type;
extern tree __t_desc_type_node;
+#if 0
extern tree __tp_desc_type_node;
+#endif
extern tree __access_mode_type_node;
extern tree __bltn_desc_type_node, __user_desc_type_node;
extern tree __class_desc_type_node, __attr_desc_type_node;
@@ -1470,87 +1767,89 @@ extern tree __ptmf_desc_type_node, __ptmd_desc_type_node;
extern tree type_info_type_node;
extern tree class_star_type_node;
extern tree this_identifier;
+extern tree ctor_identifier, dtor_identifier;
extern tree pfn_identifier;
extern tree index_identifier;
extern tree delta_identifier;
extern tree delta2_identifier;
extern tree pfn_or_delta2_identifier;
extern tree tag_identifier;
-extern tree vb_off_identifier;
extern tree vt_off_identifier;
/* A node that is a list (length 1) of error_mark_nodes. */
extern tree error_mark_list;
-extern tree ptr_type_node, const_ptr_type_node;
+extern tree ptr_type_node;
extern tree class_type_node, record_type_node, union_type_node, enum_type_node;
extern tree unknown_type_node;
extern tree opaque_type_node, signature_type_node;
/* Node for "pointer to (virtual) function".
- This may be distinct from ptr_type_node so gdb can distinguish them. */
+ This may be distinct from ptr_type_node so gdb can distinguish them. */
#define vfunc_ptr_type_node \
(flag_vtable_thunks ? vtable_entry_type : ptr_type_node)
/* Array type `(void *)[]' */
extern tree vtbl_type_node;
extern tree delta_type_node;
+extern tree std_node;
extern tree long_long_integer_type_node, long_long_unsigned_type_node;
/* For building calls to `delete'. */
extern tree integer_two_node, integer_three_node;
extern tree boolean_type_node, boolean_true_node, boolean_false_node;
+extern tree null_node;
+
/* in pt.c */
-/* PARM_VEC is a vector of template parameters, either IDENTIFIER_NODEs or
- PARM_DECLs. BINDINGS, if non-null, is a vector of bindings for those
- parameters. */
-struct template_info {
- /* Vector of template parameters, either PARM_DECLs or IDENTIFIER_NODEs. */
- tree parm_vec;
- /* If non-null, a vector of bindings for the template parms. */
- tree bindings;
-
- /* Text of template, and length. */
- char *text;
- int length;
- /* Where it came from. */
- char *filename;
- int lineno;
- /* What kind of aggregate -- struct, class, or null. */
- tree aggr;
-};
-extern int processing_template_decl, processing_template_defn;
+/* These values are used for the `STRICT' parameter to type_unfication and
+ fn_type_unification. Their meanings are described with the
+ documentation for fn_type_unification. */
+
+typedef enum unification_kind_t {
+ DEDUCE_CALL,
+ DEDUCE_CONV,
+ DEDUCE_EXACT
+} unification_kind_t;
+
+extern tree current_template_parms;
+extern HOST_WIDE_INT processing_template_decl;
+extern tree last_tree;
/* The template currently being instantiated, and where the instantiation
was triggered. */
struct tinst_level
{
- tree classname;
+ tree decl;
int line;
char *file;
struct tinst_level *next;
};
+extern int minimal_parse_mode;
+
+extern void maybe_print_template_context PROTO ((void));
+
/* in class.c */
extern tree current_class_name;
extern tree current_class_type;
+extern tree current_class_ptr;
extern tree previous_class_type;
+extern tree current_class_ref;
+extern int current_class_depth;
-extern tree current_lang_name, lang_name_cplusplus, lang_name_c;
+extern tree current_lang_name;
+extern tree lang_name_cplusplus, lang_name_c, lang_name_java;
/* Points to the name of that function. May not be the DECL_NAME
of CURRENT_FUNCTION_DECL due to overloading */
extern tree original_function_name;
-extern tree current_class_name, current_class_type, current_class_decl, C_C_D;
-
/* in init.c */
extern tree global_base_init_list;
extern tree current_base_init_list, current_member_init_list;
-extern int current_function_assigns_this;
extern int current_function_just_assigned_this;
extern int current_function_parms_stored;
@@ -1671,6 +1970,8 @@ extern int current_function_parms_stored;
#define THIS_NAME "this"
#define DESTRUCTOR_NAME_FORMAT "~%s"
#define FILE_FUNCTION_PREFIX_LEN 9
+#define CTOR_NAME "__ct"
+#define DTOR_NAME "__dt"
#define IN_CHARGE_NAME "__in_chrg"
@@ -1726,23 +2027,34 @@ extern int current_function_parms_stored;
#define ANON_PARMNAME_P(ID_NODE) (IDENTIFIER_POINTER (ID_NODE)[0] == '_' \
&& IDENTIFIER_POINTER (ID_NODE)[1] <= '9')
#endif /* !defined(NO_DOLLAR_IN_LABEL) || !defined(NO_DOT_IN_LABEL) */
+
+/* Returns non-zero iff ID_NODE is an IDENTIFIER_NODE whose name is
+ `main'. */
+#define MAIN_NAME_P(ID_NODE) \
+ (strcmp (IDENTIFIER_POINTER (ID_NODE), "main") == 0)
+
+/* Returns non-zero iff NODE is a declaration for the global function
+ `main'. */
+#define DECL_MAIN_P(NODE) \
+ (TREE_CODE (NODE) == FUNCTION_DECL \
+ && DECL_CONTEXT (NODE) == NULL_TREE \
+ && DECL_NAME (NODE) != NULL_TREE \
+ && MAIN_NAME_P (DECL_NAME (NODE)))
+
/* Define the sets of attributes that member functions and baseclasses
can have. These are sensible combinations of {public,private,protected}
cross {virtual,non-virtual}. */
-enum access_type {
- access_default,
- access_public,
- access_protected,
- access_private,
- access_default_virtual,
- access_public_virtual,
- access_private_virtual
-};
-
-/* in lex.c */
-extern tree current_unit_name, current_unit_language;
+/* in class.c. */
+extern tree access_default_node; /* 0 */
+extern tree access_public_node; /* 1 */
+extern tree access_protected_node; /* 2 */
+extern tree access_private_node; /* 3 */
+extern tree access_default_virtual_node; /* 4 */
+extern tree access_public_virtual_node; /* 5 */
+extern tree access_protected_virtual_node; /* 6 */
+extern tree access_private_virtual_node; /* 7 */
/* Things for handling inline functions. */
@@ -1757,7 +2069,6 @@ struct pending_inline
char *buf; /* pointer to character stream */
int len; /* length of stream */
- tree parm_vec, bindings; /* in case this is derived from a template */
unsigned int can_free : 1; /* free this after we're done with it? */
unsigned int deja_vu : 1; /* set iff we don't want to see it again. */
unsigned int interface : 2; /* 0=interface 1=unknown 2=implementation */
@@ -1784,10 +2095,6 @@ extern int flag_this_is_variable;
extern int flag_int_enum_equivalence;
-/* Nonzero means layout structures so that we can do garbage collection. */
-
-extern int flag_gc;
-
/* Nonzero means generate 'rtti' that give run-time type information. */
extern int flag_rtti;
@@ -1809,17 +2116,25 @@ extern int flag_alt_external_templates;
extern int flag_implicit_templates;
-/* Current end of entries in the gc obstack for stack pointer variables. */
+/* Nonzero if we want to emit defined symbols with common-like linkage as
+ weak symbols where possible, in order to conform to C++ semantics.
+ Otherwise, emit them as local symbols. */
-extern int current_function_obstack_index;
+extern int flag_weak;
-/* Flag saying whether we have used the obstack in this function or not. */
+/* Nonzero to enable experimental ABI changes. */
-extern int current_function_obstack_usage;
+extern int flag_new_abi;
-enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
+/* Nonzero to not ignore namespace std. */
-extern tree current_class_decl, C_C_D; /* PARM_DECL: the class instance variable */
+extern int flag_honor_std;
+
+/* Nonzero if we're done parsing and into end-of-file activities. */
+
+extern int at_eof;
+
+enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
/* The following two can be derived from the previous one */
extern tree current_class_name; /* IDENTIFIER_NODE: name of current class */
@@ -1837,32 +2152,56 @@ extern tree current_class_type; /* _TYPE: the type of the current class */
LOOKUP_COMPLAIN mean complain if no suitable member function
matching the arguments is found.
LOOKUP_NORMAL is just a combination of these two.
- LOOKUP_AGGR requires the instance to be of aggregate type.
LOOKUP_NONVIRTUAL means make a direct call to the member function found
LOOKUP_GLOBAL means search through the space of overloaded functions,
as well as the space of member functions.
LOOKUP_HAS_IN_CHARGE means that the "in charge" variable is already
in the parameter list.
LOOKUP_ONLYCONVERTING means that non-conversion constructors are not tried.
+ DIRECT_BIND means that if a temporary is created, it should be created so
+ that it lives as long as the current variable bindings; otherwise it
+ only lives until the end of the complete-expression.
LOOKUP_SPECULATIVELY means return NULL_TREE if we cannot find what we are
after. Note, LOOKUP_COMPLAIN is checked and error messages printed
before LOOKUP_SPECULATIVELY is checked.
LOOKUP_NO_CONVERSION means that user-defined conversions are not
permitted. Built-in conversions are permitted.
- LOOKUP_DESTRUCTOR means explicit call to destructor. */
+ LOOKUP_DESTRUCTOR means explicit call to destructor.
+ LOOKUP_NO_TEMP_BIND means temporaries will not be bound to references.
+
+ These are used in global lookup to support elaborated types and
+ qualifiers.
+
+ LOOKUP_PREFER_TYPES means not to accept objects, and possibly namespaces.
+ LOOKUP_PREFER_NAMESPACES means not to accept objects, and possibly types.
+ LOOKUP_PREFER_BOTH means class-or-namespace-name.
+ LOOKUP_TEMPLATES_EXPECTED means that class templates also count
+ as types. */
#define LOOKUP_PROTECT (1)
#define LOOKUP_COMPLAIN (2)
#define LOOKUP_NORMAL (3)
-#define LOOKUP_AGGR (4)
+/* #define LOOKUP_UNUSED (4) */
#define LOOKUP_NONVIRTUAL (8)
#define LOOKUP_GLOBAL (16)
#define LOOKUP_HAS_IN_CHARGE (32)
#define LOOKUP_SPECULATIVELY (64)
#define LOOKUP_ONLYCONVERTING (128)
-/* 256 is free */
+#define DIRECT_BIND (256)
#define LOOKUP_NO_CONVERSION (512)
#define LOOKUP_DESTRUCTOR (512)
+#define LOOKUP_NO_TEMP_BIND (1024)
+#define LOOKUP_PREFER_TYPES (2048)
+#define LOOKUP_PREFER_NAMESPACES (4096)
+#define LOOKUP_PREFER_BOTH (6144)
+#define LOOKUP_TEMPLATES_EXPECTED (8192)
+
+#define LOOKUP_NAMESPACES_ONLY(f) \
+ (((f) & LOOKUP_PREFER_NAMESPACES) && !((f) & LOOKUP_PREFER_TYPES))
+#define LOOKUP_TYPES_ONLY(f) \
+ (!((f) & LOOKUP_PREFER_NAMESPACES) && ((f) & LOOKUP_PREFER_TYPES))
+#define LOOKUP_QUALIFIERS_ONLY(f) ((f) & LOOKUP_PREFER_BOTH)
+
/* These flags are used by the conversion code.
CONV_IMPLICIT : Perform implicit conversions (standard and user-defined).
@@ -1870,7 +2209,6 @@ extern tree current_class_type; /* _TYPE: the type of the current class */
CONV_CONST : Perform the explicit conversions for const_cast.
CONV_REINTERPRET: Perform the explicit conversions for reinterpret_cast.
CONV_PRIVATE : Perform upcasts to private bases.
- CONV_NONCONVERTING : Allow non-converting constructors to be used.
CONV_FORCE_TEMP : Require a new temporary when converting to the same
aggregate type. */
@@ -1879,7 +2217,7 @@ extern tree current_class_type; /* _TYPE: the type of the current class */
#define CONV_CONST 4
#define CONV_REINTERPRET 8
#define CONV_PRIVATE 16
-#define CONV_NONCONVERTING 32
+/* #define CONV_NONCONVERTING 32 */
#define CONV_FORCE_TEMP 64
#define CONV_STATIC_CAST (CONV_IMPLICIT | CONV_STATIC | CONV_FORCE_TEMP)
#define CONV_OLD_CONVERT (CONV_IMPLICIT | CONV_STATIC | CONV_CONST \
@@ -1898,23 +2236,27 @@ extern tree current_class_type; /* _TYPE: the type of the current class */
#define WANT_ARITH (WANT_INT | WANT_FLOAT)
-/* Anatomy of a DECL_FRIENDLIST (which is a TREE_LIST):
- purpose = friend name (IDENTIFIER_NODE);
- value = TREE_LIST of FUNCTION_DECLS;
- chain, type = EMPTY; */
#define FRIEND_NAME(LIST) (TREE_PURPOSE (LIST))
#define FRIEND_DECLS(LIST) (TREE_VALUE (LIST))
-/* These macros are for accessing the fields of TEMPLATE...PARM nodes. */
-#define TEMPLATE_TYPE_TPARMLIST(NODE) TREE_PURPOSE (TYPE_FIELDS (NODE))
-#define TEMPLATE_TYPE_IDX(NODE) TREE_INT_CST_LOW (TREE_VALUE (TYPE_FIELDS (NODE)))
-#define TEMPLATE_TYPE_SET_INFO(NODE,P,I) \
- (TYPE_FIELDS (NODE) = build_tree_list (P, build_int_2 (I, 0)))
-#define TEMPLATE_CONST_TPARMLIST(NODE) (*(tree*)&TREE_INT_CST_LOW(NODE))
-#define TEMPLATE_CONST_IDX(NODE) (TREE_INT_CST_HIGH(NODE))
-#define TEMPLATE_CONST_SET_INFO(NODE,P,I) \
- (TEMPLATE_CONST_TPARMLIST (NODE) = saved_parmlist, \
- TEMPLATE_CONST_IDX (NODE) = I)
+/* These macros are used to access a TEMPLATE_PARM_INDEX. */
+#define TEMPLATE_PARM_IDX(NODE) (((template_parm_index*) NODE)->index)
+#define TEMPLATE_PARM_LEVEL(NODE) (((template_parm_index*) NODE)->level)
+#define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))
+#define TEMPLATE_PARM_ORIG_LEVEL(NODE) (((template_parm_index*) NODE)->orig_level)
+#define TEMPLATE_PARM_DECL(NODE) (((template_parm_index*) NODE)->decl)
+
+/* These macros are for accessing the fields of TEMPLATE_TYPE_PARM
+ and TEMPLATE_TEMPLATE_PARM nodes. */
+#define TEMPLATE_TYPE_PARM_INDEX(NODE) (TYPE_FIELDS (NODE))
+#define TEMPLATE_TYPE_IDX(NODE) \
+ (TEMPLATE_PARM_IDX (TEMPLATE_TYPE_PARM_INDEX (NODE)))
+#define TEMPLATE_TYPE_LEVEL(NODE) \
+ (TEMPLATE_PARM_LEVEL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
+#define TEMPLATE_TYPE_ORIG_LEVEL(NODE) \
+ (TEMPLATE_PARM_ORIG_LEVEL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
+#define TEMPLATE_TYPE_DECL(NODE) \
+ (TEMPLATE_PARM_DECL (TEMPLATE_TYPE_PARM_INDEX (NODE)))
/* in lex.c */
/* Indexed by TREE_CODE, these tables give C-looking names to
@@ -1922,163 +2264,214 @@ extern tree current_class_type; /* _TYPE: the type of the current class */
opname_tab[(int) MINUS_EXPR] == "-". */
extern char **opname_tab, **assignop_tab;
-/* in c-common.c */
-extern tree convert_and_check PROTO((tree, tree));
-extern void overflow_warning PROTO((tree));
-extern void unsigned_conversion_warning PROTO((tree, tree));
-
/* in call.c */
-extern struct candidate *ansi_c_bullshit;
-
-extern int rank_for_overload PROTO((struct candidate *, struct candidate *));
-extern void compute_conversion_costs PROTO((tree, tree, struct candidate *, int));
+extern int check_dtor_name PROTO((tree, tree));
extern int get_arglist_len_in_bytes PROTO((tree));
+
extern tree build_vfield_ref PROTO((tree, tree));
-extern tree find_scoped_type PROTO((tree, tree, tree));
extern tree resolve_scope_to_name PROTO((tree, tree));
extern tree build_scoped_method_call PROTO((tree, tree, tree, tree));
+extern tree build_addr_func PROTO((tree));
+extern tree build_call PROTO((tree, tree, tree));
extern tree build_method_call PROTO((tree, tree, tree, tree, int));
-extern tree build_overload_call_real PROTO((tree, tree, int, struct candidate *, int));
-extern tree build_overload_call PROTO((tree, tree, int, struct candidate *));
-extern tree build_overload_call_maybe PROTO((tree, tree, int, struct candidate *));
+extern int null_ptr_cst_p PROTO((tree));
+extern tree type_decays_to PROTO((tree));
+extern tree build_user_type_conversion PROTO((tree, tree, int));
+extern tree build_new_function_call PROTO((tree, tree));
+extern tree build_new_op PROTO((enum tree_code, int, tree, tree, tree));
+extern tree build_op_new_call PROTO((enum tree_code, tree, tree, int));
+extern tree build_op_delete_call PROTO((enum tree_code, tree, tree, int, tree));
+extern int can_convert PROTO((tree, tree));
+extern int can_convert_arg PROTO((tree, tree, tree));
+extern void enforce_access PROTO((tree, tree));
+extern tree convert_default_arg PROTO((tree, tree));
+extern tree convert_arg_to_ellipsis PROTO((tree));
/* in class.c */
-extern char *dont_allow_type_definitions;
-extern tree build_vbase_pointer PROTO((tree, tree));
extern tree build_vbase_path PROTO((enum tree_code, tree, tree, tree, int));
-extern tree build_vtable_entry PROTO((tree, tree));
+extern tree build_vtbl_ref PROTO((tree, tree));
extern tree build_vfn_ref PROTO((tree *, tree, tree));
extern void add_method PROTO((tree, tree *, tree));
+extern int currently_open_class PROTO((tree));
extern tree get_vfield_offset PROTO((tree));
extern void duplicate_tag_error PROTO((tree));
-extern tree finish_struct PROTO((tree, tree, int));
+extern tree finish_struct PROTO((tree, tree, tree, int));
+extern tree finish_struct_1 PROTO((tree, int));
+extern tree finish_struct_methods PROTO((tree, tree, int));
extern int resolves_to_fixed_type_p PROTO((tree, int *));
extern void init_class_processing PROTO((void));
+extern int is_empty_class PROTO((tree));
extern void pushclass PROTO((tree, int));
extern void popclass PROTO((int));
extern void push_nested_class PROTO((tree, int));
extern void pop_nested_class PROTO((int));
extern void push_lang_context PROTO((tree));
extern void pop_lang_context PROTO((void));
-extern int root_lang_context_p PROTO((void));
extern tree instantiate_type PROTO((tree, tree, int));
extern void print_class_statistics PROTO((void));
extern void maybe_push_cache_obstack PROTO((void));
extern unsigned HOST_WIDE_INT skip_rtti_stuff PROTO((tree *));
+extern tree build_self_reference PROTO((void));
+extern void warn_hidden PROTO((tree));
/* in cvt.c */
extern tree convert_to_reference PROTO((tree, tree, int, int, tree));
extern tree convert_from_reference PROTO((tree));
-extern tree convert_to_aggr PROTO((tree, tree, char **, int));
-extern tree convert_pointer_to PROTO((tree, tree));
extern tree convert_pointer_to_real PROTO((tree, tree));
-extern tree convert_pointer_to_vbase PROTO((tree, tree));
+extern tree convert_pointer_to PROTO((tree, tree));
+extern tree ocp_convert PROTO((tree, tree, int, int));
+extern tree cp_convert PROTO((tree, tree));
extern tree convert PROTO((tree, tree));
-extern tree cp_convert PROTO((tree, tree, int, int));
extern tree convert_force PROTO((tree, tree, int));
extern tree build_type_conversion PROTO((enum tree_code, tree, tree, int));
extern tree build_expr_type_conversion PROTO((int, tree, int));
-extern int build_default_binary_type_conversion PROTO((enum tree_code, tree *, tree *));
extern tree type_promotes_to PROTO((tree));
+extern tree perform_qualification_conversions PROTO((tree, tree));
/* decl.c */
+/* resume_binding_level */
extern int global_bindings_p PROTO((void));
extern int toplevel_bindings_p PROTO((void));
extern void keep_next_level PROTO((void));
extern int kept_level_p PROTO((void));
extern void declare_parm_level PROTO((void));
-extern void declare_implicit_exception PROTO((void));
-extern int have_exceptions_p PROTO((void));
-extern void declare_uninstantiated_type_level PROTO((void));
-extern int uninstantiated_type_level_p PROTO((void));
extern void declare_pseudo_global_level PROTO((void));
extern int pseudo_global_level_p PROTO((void));
+extern void set_class_shadows PROTO((tree));
extern void pushlevel PROTO((int));
+extern void note_level_for_for PROTO((void));
extern void pushlevel_temporary PROTO((int));
extern tree poplevel PROTO((int, int, int));
+extern void resume_level PROTO((struct binding_level *));
extern void delete_block PROTO((tree));
extern void insert_block PROTO((tree));
extern void add_block_current_level PROTO((tree));
extern void set_block PROTO((tree));
extern void pushlevel_class PROTO((void));
extern tree poplevel_class PROTO((int));
-/* skip print_other_binding_stack and print_binding_level */
extern void print_binding_stack PROTO((void));
+extern void print_binding_level PROTO((struct binding_level *));
+extern void push_namespace PROTO((tree));
+extern void pop_namespace PROTO((void));
+extern void maybe_push_to_top_level PROTO((int));
extern void push_to_top_level PROTO((void));
extern void pop_from_top_level PROTO((void));
+extern tree identifier_type_value PROTO((tree));
extern void set_identifier_type_value PROTO((tree, tree));
+extern void set_identifier_local_value PROTO((tree, tree));
extern void pop_everything PROTO((void));
-extern tree make_type_decl PROTO((tree, tree));
extern void pushtag PROTO((tree, tree, int));
extern tree make_anon_name PROTO((void));
extern void clear_anon_tags PROTO((void));
+extern int decls_match PROTO((tree, tree));
+extern int duplicate_decls PROTO((tree, tree));
extern tree pushdecl PROTO((tree));
extern tree pushdecl_top_level PROTO((tree));
-extern void push_class_level_binding PROTO((tree, tree));
-extern void push_overloaded_decl_top_level PROTO((tree, int));
extern tree pushdecl_class_level PROTO((tree));
-extern tree pushdecl_nonclass_level PROTO((tree));
-extern int overloaded_globals_p PROTO((tree));
-extern tree push_overloaded_decl PROTO((tree, int));
+#if 0
+extern void pushdecl_nonclass_level PROTO((tree));
+#endif
+extern tree pushdecl_namespace_level PROTO((tree));
+extern tree push_using_decl PROTO((tree, tree));
+extern tree push_using_directive PROTO((tree));
+extern void push_class_level_binding PROTO((tree, tree));
+extern tree push_using_decl PROTO((tree, tree));
extern tree implicitly_declare PROTO((tree));
extern tree lookup_label PROTO((tree));
extern tree shadow_label PROTO((tree));
extern tree define_label PROTO((char *, int, tree));
+extern void push_switch PROTO((void));
+extern void pop_switch PROTO((void));
extern void define_case_label PROTO((tree));
extern tree getdecls PROTO((void));
extern tree gettags PROTO((void));
+#if 0
extern void set_current_level_tags_transparency PROTO((int));
-extern tree typedecl_for_tag PROTO((tree));
-extern tree lookup_name PROTO((tree, int));
+#endif
+extern tree binding_for_name PROTO((tree, tree));
+extern tree namespace_binding PROTO((tree, tree));
+extern void set_namespace_binding PROTO((tree, tree, tree));
extern tree lookup_namespace_name PROTO((tree, tree));
+extern tree make_typename_type PROTO((tree, tree));
+extern tree lookup_name_nonclass PROTO((tree));
+extern tree lookup_function_nonclass PROTO((tree, tree));
+extern tree lookup_name PROTO((tree, int));
extern tree lookup_name_current_level PROTO((tree));
+extern tree lookup_type_current_level PROTO((tree));
+extern tree lookup_name_namespace_only PROTO((tree));
+extern void begin_only_namespace_names PROTO((void));
+extern void end_only_namespace_names PROTO((void));
+extern tree namespace_ancestor PROTO((tree, tree));
+extern int lookup_using_namespace PROTO((tree,tree,tree,tree,int));
+extern int qualified_lookup_using_namespace PROTO((tree,tree,tree,int));
+extern tree auto_function PROTO((tree, tree, enum built_in_function));
extern void init_decl_processing PROTO((void));
-/* skipped define_function */
+extern int init_type_desc PROTO((void));
+extern tree define_function
+ PROTO((char *, tree, enum built_in_function,
+ void (*) (tree), char *));
extern void shadow_tag PROTO((tree));
-extern int grok_ctor_properties PROTO((tree, tree));
extern tree groktypename PROTO((tree));
-extern tree start_decl PROTO((tree, tree, int, tree));
+extern tree start_decl PROTO((tree, tree, int, tree, tree));
+extern void start_decl_1 PROTO((tree));
extern void cp_finish_decl PROTO((tree, tree, tree, int, int));
+extern void finish_decl PROTO((tree, tree, tree));
extern void expand_static_init PROTO((tree, tree));
extern int complete_array_type PROTO((tree, tree, int));
extern tree build_ptrmemfunc_type PROTO((tree));
/* the grokdeclarator prototype is in decl.h */
extern int parmlist_is_exprlist PROTO((tree));
+extern int copy_args_p PROTO((tree));
+extern int grok_ctor_properties PROTO((tree, tree));
+extern void grok_op_properties PROTO((tree, int, int));
extern tree xref_tag PROTO((tree, tree, tree, int));
+extern tree xref_tag_from_type PROTO((tree, tree, int));
extern void xref_basetypes PROTO((tree, tree, tree, tree));
extern tree start_enum PROTO((tree));
extern tree finish_enum PROTO((tree, tree));
extern tree build_enumerator PROTO((tree, tree));
-extern tree grok_enum_decls PROTO((tree, tree));
-extern int start_function PROTO((tree, tree, tree, tree, int));
-extern void store_parm_decls PROTO((void));
+extern tree grok_enum_decls PROTO((tree));
+extern int start_function PROTO((tree, tree, tree, int));
extern void expand_start_early_try_stmts PROTO((void));
-extern void store_in_parms PROTO((struct rtx_def *));
+extern void store_parm_decls PROTO((void));
extern void store_return_init PROTO((tree, tree));
extern void finish_function PROTO((int, int, int));
-extern tree start_method PROTO((tree, tree, tree));
+extern tree start_method PROTO((tree, tree));
extern tree finish_method PROTO((tree));
extern void hack_incomplete_structures PROTO((tree));
+extern tree maybe_build_cleanup_and_delete PROTO((tree));
extern tree maybe_build_cleanup PROTO((tree));
extern void cplus_expand_expr_stmt PROTO((tree));
extern void finish_stmt PROTO((void));
-extern void pop_implicit_try_blocks PROTO((tree));
-extern void push_exception_cleanup PROTO((tree));
-extern void revert_static_member_fn PROTO((tree *, tree *, tree *));
+extern int id_in_current_class PROTO((tree));
+extern void push_cp_function_context PROTO((tree));
+extern void pop_cp_function_context PROTO((tree));
+extern int in_function_p PROTO((void));
+extern void replace_defarg PROTO((tree, tree));
+extern void print_other_binding_stack PROTO((struct binding_level *));
+extern void revert_static_member_fn PROTO((tree*, tree*, tree*));
+extern void cat_namespace_levels PROTO((void));
/* in decl2.c */
-extern int lang_decode_option PROTO((char *));
+extern int check_java_method PROTO((tree, tree));
+extern int flag_assume_nonnull_objects;
+extern int lang_decode_option PROTO((int, char **));
extern tree grok_method_quals PROTO((tree, tree, tree));
+extern void warn_if_unknown_interface PROTO((tree));
+extern tree grok_x_components PROTO((tree, tree));
+extern void maybe_retrofit_in_chrg PROTO((tree));
+extern void maybe_make_one_only PROTO((tree));
extern void grokclassfn PROTO((tree, tree, tree, enum overload_flags, tree));
extern tree grok_alignof PROTO((tree));
extern tree grok_array_decl PROTO((tree, tree));
extern tree delete_sanity PROTO((tree, tree, int, int));
-extern tree check_classfn PROTO((tree, tree, tree));
-extern tree grokfield PROTO((tree, tree, tree, tree, tree, tree));
+extern tree check_classfn PROTO((tree, tree));
+extern void check_member_template PROTO((tree));
+extern tree grokfield PROTO((tree, tree, tree, tree, tree));
extern tree grokbitfield PROTO((tree, tree, tree));
extern tree groktypefield PROTO((tree, tree));
extern tree grokoptypename PROTO((tree, tree));
-extern tree build_push_scope PROTO((tree, tree));
+extern int copy_assignment_arg_p PROTO((tree, int));
extern void cplus_decl_attributes PROTO((tree, tree, tree));
extern tree constructor_name_full PROTO((tree));
extern tree constructor_name PROTO((tree));
@@ -2092,232 +2485,278 @@ extern tree finish_table PROTO((tree, tree, tree, int));
extern void finish_builtin_type PROTO((tree, char *, tree *, int, tree));
extern tree coerce_new_type PROTO((tree));
extern tree coerce_delete_type PROTO((tree));
-extern void walk_vtables PROTO((void (*)(), void (*)()));
-extern void walk_sigtables PROTO((void (*)(), void (*)()));
+extern void comdat_linkage PROTO((tree));
+extern void import_export_class PROTO((tree));
+extern void import_export_vtable PROTO((tree, tree, int));
+extern int finish_prevtable_vardecl PROTO((tree, tree));
+extern int walk_vtables PROTO((void (*)(tree, tree),
+ int (*)(tree, tree)));
+extern void walk_sigtables PROTO((void (*)(tree, tree),
+ void (*)(tree, tree)));
+extern void import_export_decl PROTO((tree));
+extern tree build_cleanup PROTO((tree));
extern void finish_file PROTO((void));
-extern void warn_if_unknown_interface PROTO((tree));
-extern tree grok_x_components PROTO((tree, tree));
extern tree reparse_absdcl_as_expr PROTO((tree, tree));
extern tree reparse_absdcl_as_casts PROTO((tree, tree));
+extern tree build_expr_from_tree PROTO((tree));
extern tree reparse_decl_as_expr PROTO((tree, tree));
extern tree finish_decl_parsing PROTO((tree));
-extern tree lookup_name_nonclass PROTO((tree));
extern tree check_cp_case_value PROTO((tree));
-extern tree do_toplevel_using_decl PROTO((tree));
+extern void set_decl_namespace PROTO((tree, tree));
+extern tree current_decl_namespace PROTO((void));
+extern void push_decl_namespace PROTO((tree));
+extern void pop_decl_namespace PROTO((void));
+extern void do_namespace_alias PROTO((tree, tree));
+extern void do_toplevel_using_decl PROTO((tree));
+extern void do_local_using_decl PROTO((tree));
extern tree do_class_using_decl PROTO((tree));
-extern tree current_namespace_id PROTO((tree));
-extern tree get_namespace_id PROTO((void));
+extern void do_using_directive PROTO((tree));
extern void check_default_args PROTO((tree));
+extern void mark_used PROTO((tree));
+extern tree handle_class_head PROTO((tree, tree, tree));
+extern tree lookup_arg_dependent PROTO((tree, tree, tree));
-/* in edsel.c */
+/* in errfn.c */
+extern void cp_error ();
+extern void cp_error_at ();
+extern void cp_warning ();
+extern void cp_warning_at ();
+extern void cp_pedwarn ();
+extern void cp_pedwarn_at ();
+extern void cp_compiler_error ();
+extern void cp_sprintf ();
+
+/* in error.c */
+extern void init_error PROTO((void));
+extern char *fndecl_as_string PROTO((tree, int));
+extern char *type_as_string PROTO((tree, int));
+extern char *type_as_string_real PROTO((tree, int, int));
+extern char *args_as_string PROTO((tree, int));
+extern char *decl_as_string PROTO((tree, int));
+extern char *expr_as_string PROTO((tree, int));
+extern char *code_as_string PROTO((enum tree_code, int));
+extern char *language_as_string PROTO((enum languages, int));
+extern char *parm_as_string PROTO((int, int));
+extern char *op_as_string PROTO((enum tree_code, int));
+extern char *assop_as_string PROTO((enum tree_code, int));
+extern char *cv_as_string PROTO((tree, int));
+extern char *lang_decl_name PROTO((tree, int));
+extern char *cp_file_of PROTO((tree));
+extern int cp_line_of PROTO((tree));
/* in except.c */
-extern tree protect_list;
-extern void start_protect PROTO((void));
-extern void end_protect PROTO((tree));
-extern void end_protect_partials ();
-extern void expand_exception_blocks PROTO((void));
-extern void expand_start_try_stmts PROTO((void));
-extern void expand_end_try_stmts PROTO((void));
-extern void expand_start_all_catch PROTO((void));
-extern void expand_end_all_catch PROTO((void));
-extern void start_catch_block PROTO((tree, tree));
-extern void end_catch_block PROTO((void));
-extern void expand_throw PROTO((tree));
-extern int might_have_exceptions_p PROTO((void));
-extern void emit_exception_table PROTO((void));
-extern tree build_throw PROTO((tree));
extern void init_exception_processing PROTO((void));
+extern void expand_start_catch_block PROTO((tree, tree));
+extern void expand_end_catch_block PROTO((void));
extern void expand_builtin_throw PROTO((void));
extern void expand_start_eh_spec PROTO((void));
-extern void expand_end_eh_spec PROTO((tree));
+extern void expand_exception_blocks PROTO((void));
+extern tree start_anon_func PROTO((void));
+extern void end_anon_func PROTO((void));
+extern void expand_throw PROTO((tree));
+extern tree build_throw PROTO((tree));
+extern void mark_all_runtime_matches PROTO((void));
/* in expr.c */
-/* skip cplus_expand_expr */
extern void init_cplus_expand PROTO((void));
extern void fixup_result_decl PROTO((tree, struct rtx_def *));
-extern int decl_in_memory_p PROTO((tree));
-extern tree unsave_expr_now PROTO((tree));
-
-/* in gc.c */
-extern int type_needs_gc_entry PROTO((tree));
-extern int value_safe_from_gc PROTO((tree, tree));
-extern void build_static_gc_entry PROTO((tree, tree));
-extern tree protect_value_from_gc PROTO((tree, tree));
-extern tree build_headof PROTO((tree));
-extern tree build_classof PROTO((tree));
-extern tree build_t_desc PROTO((tree, int));
-extern tree build_i_desc PROTO((tree));
-extern tree build_m_desc PROTO((tree));
-extern void expand_gc_prologue_and_epilogue PROTO((void));
-extern void lang_expand_end_bindings PROTO((struct rtx_def *, struct rtx_def *));
-extern void init_gc_processing PROTO((void));
-extern tree build_typeid PROTO((tree));
-extern tree get_typeid PROTO((tree));
-extern tree build_dynamic_cast PROTO((tree, tree));
+extern int extract_init PROTO((tree, tree));
+extern void do_case PROTO((tree, tree));
+
+/* friend.c */
+extern int is_friend PROTO((tree, tree));
+extern void make_friend_class PROTO((tree, tree));
+extern tree do_friend PROTO((tree, tree, tree, tree, enum overload_flags, tree, int));
/* in init.c */
+extern void init_init_processing PROTO((void));
+extern void expand_direct_vtbls_init PROTO((tree, tree, int, int, tree));
extern void emit_base_init PROTO((tree, int));
extern void check_base_init PROTO((tree));
-extern void expand_direct_vtbls_init PROTO((tree, tree, int, int, tree));
-extern void do_member_init PROTO((tree, tree, tree));
extern void expand_member_init PROTO((tree, tree, tree));
extern void expand_aggr_init PROTO((tree, tree, int, int));
extern int is_aggr_typedef PROTO((tree, int));
+extern int is_aggr_type PROTO((tree, int));
extern tree get_aggr_from_typedef PROTO((tree, int));
extern tree get_type_value PROTO((tree));
extern tree build_member_call PROTO((tree, tree, tree));
extern tree build_offset_ref PROTO((tree, tree));
-extern tree get_member_function PROTO((tree *, tree, tree));
-extern tree get_member_function_from_ptrfunc PROTO((tree *, tree));
extern tree resolve_offset_ref PROTO((tree));
extern tree decl_constant_value PROTO((tree));
-extern int is_friend_type PROTO((tree, tree));
-extern int is_friend PROTO((tree, tree));
-extern void make_friend_class PROTO((tree, tree));
-extern tree do_friend PROTO((tree, tree, tree, tree, enum overload_flags, tree));
-extern void embrace_waiting_friends PROTO((tree));
-extern tree build_builtin_call PROTO((tree, tree, tree));
extern tree build_new PROTO((tree, tree, tree, int));
+extern tree build_new_1 PROTO((tree));
extern tree expand_vec_init PROTO((tree, tree, tree, tree, int));
extern tree build_x_delete PROTO((tree, tree, int, tree));
extern tree build_delete PROTO((tree, tree, tree, int, int));
extern tree build_vbase_delete PROTO((tree, tree));
-extern tree build_vec_delete PROTO((tree, tree, tree, tree, tree, int));
+extern tree build_vec_delete PROTO((tree, tree, tree, tree, int));
/* in input.c */
/* in lex.c */
+extern char *file_name_nondirectory PROTO((char *));
extern tree make_pointer_declarator PROTO((tree, tree));
extern tree make_reference_declarator PROTO((tree, tree));
+extern tree make_call_declarator PROTO((tree, tree, tree, tree));
+extern void set_quals_and_spec PROTO((tree, tree, tree));
extern char *operator_name_string PROTO((tree));
extern void lang_init PROTO((void));
extern void lang_finish PROTO((void));
extern void init_filename_times PROTO((void));
+#if 0
extern void reinit_lang_specific PROTO((void));
-extern void init_lex PROTO((void));
+#endif
extern void reinit_parse_for_function PROTO((void));
-extern int *init_parse PROTO((void));
extern void print_parse_statistics PROTO((void));
extern void extract_interface_info PROTO((void));
-extern void set_vardecl_interface_info PROTO((tree, tree));
extern void do_pending_inlines PROTO((void));
extern void process_next_inline PROTO((tree));
-/* skip restore_pending_input */
+extern struct pending_input *save_pending_input PROTO((void));
+extern void restore_pending_input PROTO((struct pending_input *));
extern void yyungetc PROTO((int, int));
extern void reinit_parse_for_method PROTO((int, tree));
-#if 0
-extern void reinit_parse_for_block PROTO((int, struct obstack *, int));
-#endif
+extern void reinit_parse_for_block PROTO((int, struct obstack *));
extern tree cons_up_default_function PROTO((tree, tree, int));
extern void check_for_missing_semicolon PROTO((tree));
extern void note_got_semicolon PROTO((tree));
extern void note_list_got_semicolon PROTO((tree));
-extern int check_newline PROTO((void));
-extern void dont_see_typename PROTO((void));
+extern void do_pending_lang_change PROTO((void));
extern int identifier_type PROTO((tree));
extern void see_typename PROTO((void));
-extern tree do_identifier PROTO((tree));
+extern tree do_identifier PROTO((tree, int, tree));
+extern tree do_scoped_id PROTO((tree, int));
extern tree identifier_typedecl_value PROTO((tree));
extern int real_yylex PROTO((void));
+extern int is_rid PROTO((tree));
extern tree build_lang_decl PROTO((enum tree_code, tree, tree));
extern tree build_lang_field_decl PROTO((enum tree_code, tree, tree));
extern void copy_lang_decl PROTO((tree));
extern tree make_lang_type PROTO((enum tree_code));
-extern void copy_decl_lang_specific PROTO((tree));
extern void dump_time_statistics PROTO((void));
/* extern void compiler_error PROTO((char *, HOST_WIDE_INT, HOST_WIDE_INT)); */
-extern void compiler_error_with_decl PROTO((tree, char *));
extern void yyerror PROTO((char *));
-
-/* in errfn.c */
-extern void cp_error ();
-extern void cp_error_at ();
-extern void cp_warning ();
-extern void cp_warning_at ();
-extern void cp_pedwarn ();
-extern void cp_pedwarn_at ();
-extern void cp_compiler_error ();
-extern void cp_sprintf ();
-
-/* in error.c */
-extern void init_error PROTO((void));
-extern char *fndecl_as_string PROTO((tree, tree, int));
-extern char *type_as_string PROTO((tree, int));
-extern char *args_as_string PROTO((tree, int));
-extern char *decl_as_string PROTO((tree, int));
-extern char *expr_as_string PROTO((tree, int));
-extern char *code_as_string PROTO((enum tree_code, int));
-extern char *language_as_string PROTO((enum languages, int));
-extern char *parm_as_string PROTO((int, int));
-extern char *op_as_string PROTO((enum tree_code, int));
-extern char *cv_as_string PROTO((tree, int));
+extern void clear_inline_text_obstack PROTO((void));
+extern void maybe_snarf_defarg PROTO((void));
+extern tree snarf_defarg PROTO((void));
+extern void add_defarg_fn PROTO((tree));
+extern void do_pending_defargs PROTO((void));
+extern int identifier_type PROTO((tree));
+extern void yyhook PROTO((int));
/* in method.c */
extern void init_method PROTO((void));
-extern tree make_anon_parm_name PROTO((void));
-extern void clear_anon_parm_name PROTO((void));
extern void do_inline_function_hair PROTO((tree, tree));
-/* skip report_type_mismatch */
extern char *build_overload_name PROTO((tree, int, int));
extern tree build_static_name PROTO((tree, tree));
-extern tree cplus_exception_name PROTO((tree));
extern tree build_decl_overload PROTO((tree, tree, int));
+extern tree build_template_decl_overload PROTO((tree, tree, tree, tree, tree, int));
extern tree build_typename_overload PROTO((tree));
-extern tree build_t_desc_overload PROTO((tree));
-extern void declare_overloaded PROTO((tree));
-#ifdef NO_AUTO_OVERLOAD
-extern int is_overloaded PROTO((tree));
-#endif
+extern tree build_overload_with_type PROTO((tree, tree));
+extern tree build_destructor_name PROTO((tree));
extern tree build_opfncall PROTO((enum tree_code, int, tree, tree, tree));
-extern tree hack_identifier PROTO((tree, tree, int));
-extern tree build_component_type_expr PROTO((tree, tree, tree, int));
+extern tree hack_identifier PROTO((tree, tree));
+extern tree make_thunk PROTO((tree, int));
+extern void emit_thunk PROTO((tree));
+extern void synthesize_method PROTO((tree));
+extern tree get_id_2 PROTO((char *, tree));
/* in pt.c */
-extern tree tsubst PROTO ((tree, tree*, int, tree));
+extern tree innermost_args PROTO ((tree, int));
+extern tree tsubst PROTO ((tree, tree, tree));
+extern tree tsubst_expr PROTO ((tree, tree, tree));
+extern tree tsubst_copy PROTO ((tree, tree, tree));
+extern tree tsubst_chain PROTO((tree, tree));
+extern void maybe_begin_member_template_processing PROTO((tree));
+extern void maybe_end_member_template_processing PROTO((tree));
+extern tree finish_member_template_decl PROTO((tree, tree));
extern void begin_template_parm_list PROTO((void));
+extern void begin_specialization PROTO((void));
+extern void reset_specialization PROTO((void));
+extern void end_specialization PROTO((void));
+extern void begin_explicit_instantiation PROTO((void));
+extern void end_explicit_instantiation PROTO((void));
+extern tree determine_specialization PROTO((tree, tree, tree *, int, int));
+extern tree check_explicit_specialization PROTO((tree, tree, int, int));
extern tree process_template_parm PROTO((tree, tree));
extern tree end_template_parm_list PROTO((tree));
-extern void end_template_decl PROTO((tree, tree, tree, int));
-extern tree lookup_template_class PROTO((tree, tree, tree));
-extern void push_template_decls PROTO((tree, tree, int));
-extern void pop_template_decls PROTO((tree, tree, int));
+extern void end_template_decl PROTO((void));
+extern tree current_template_args PROTO((void));
+extern tree push_template_decl PROTO((tree));
+extern tree push_template_decl_real PROTO((tree, int));
+extern void redeclare_class_template PROTO((tree, tree));
+extern tree lookup_template_class PROTO((tree, tree, tree, tree));
+extern tree lookup_template_function PROTO((tree, tree));
extern int uses_template_parms PROTO((tree));
-extern void instantiate_member_templates PROTO((tree));
-extern tree instantiate_class_template PROTO((tree, int));
-extern tree instantiate_template PROTO((tree, tree *));
-extern void undo_template_name_overload PROTO((tree, int));
-extern void overload_template_name PROTO((tree, int));
-extern void end_template_instantiation PROTO((tree));
-extern void reinit_parse_for_template PROTO((int, tree, tree));
-extern int type_unification PROTO((tree, tree *, tree, tree, int *, int));
-extern int do_pending_expansions PROTO((void));
-extern void do_pending_templates PROTO((void));
+extern tree instantiate_class_template PROTO((tree));
+extern tree instantiate_template PROTO((tree, tree));
+extern void overload_template_name PROTO((tree));
+extern int fn_type_unification PROTO((tree, tree, tree, tree, tree, unification_kind_t, tree));
+extern int type_unification PROTO((tree, tree, tree, tree, tree, unification_kind_t, int));
struct tinst_level *tinst_for_decl PROTO((void));
-extern void do_function_instantiation PROTO((tree, tree, tree));
+extern void mark_decl_instantiated PROTO((tree, int));
+extern int more_specialized PROTO((tree, tree, tree));
+extern void mark_class_instantiated PROTO((tree, int));
+extern void do_decl_instantiation PROTO((tree, tree, tree));
extern void do_type_instantiation PROTO((tree, tree));
-extern tree create_nested_upt PROTO((tree, tree));
+extern tree instantiate_decl PROTO((tree));
+extern tree lookup_nested_type_by_name PROTO((tree, tree));
+extern tree do_poplevel PROTO((void));
+extern tree get_bindings PROTO((tree, tree, tree));
+/* CONT ... */
+extern void add_tree PROTO((tree));
+extern void begin_tree PROTO((void));
+extern void end_tree PROTO((void));
+extern void add_maybe_template PROTO((tree, tree));
+extern void pop_tinst_level PROTO((void));
+extern tree most_specialized PROTO((tree, tree, tree));
+extern tree most_specialized_class PROTO((tree, tree, tree));
+extern int more_specialized_class PROTO((tree, tree));
+extern void do_pushlevel PROTO((void));
+extern int is_member_template PROTO((tree));
+extern int comp_template_parms PROTO((tree, tree));
+extern int template_class_depth PROTO((tree));
+extern int is_specialization_of PROTO((tree, tree));
+extern int comp_template_args PROTO((tree, tree));
+
+extern int processing_specialization;
+extern int processing_explicit_instantiation;
+extern int processing_template_parmlist;
+
+/* in repo.c */
+extern void repo_template_used PROTO((tree));
+extern void repo_template_instantiated PROTO((tree, int));
+extern void init_repo PROTO((char*));
+extern void finish_repo PROTO((void));
+
+/* in rtti.c */
+extern void init_rtti_processing PROTO((void));
+extern tree get_tinfo_fn_dynamic PROTO((tree));
+extern tree build_typeid PROTO((tree));
+extern tree build_x_typeid PROTO((tree));
+extern tree get_tinfo_fn PROTO((tree));
+extern tree get_typeid PROTO((tree));
+extern tree build_dynamic_cast PROTO((tree, tree));
+extern void synthesize_tinfo_fn PROTO((tree));
/* in search.c */
-extern tree make_memoized_table_entry PROTO((tree, tree, int));
+extern int types_overlap_p PROTO((tree, tree));
extern void push_memoized_context PROTO((tree, int));
extern void pop_memoized_context PROTO((int));
+extern tree get_vbase PROTO((tree, tree));
extern tree get_binfo PROTO((tree, tree, int));
extern int get_base_distance PROTO((tree, tree, int, tree *));
-extern enum access_type compute_access PROTO((tree, tree));
+extern tree compute_access PROTO((tree, tree));
extern tree lookup_field PROTO((tree, tree, int, int));
extern tree lookup_nested_field PROTO((tree, int));
extern tree lookup_fnfields PROTO((tree, tree, int));
+extern tree lookup_member PROTO((tree, tree, int, int));
extern tree lookup_nested_tag PROTO((tree, tree));
-extern HOST_WIDE_INT breadth_first_search PROTO((tree, int (*)(), int (*)()));
-extern int tree_needs_constructor_p PROTO((tree, int));
-extern int tree_has_any_destructor_p PROTO((tree, int));
extern tree get_matching_virtual PROTO((tree, tree, int));
extern tree get_abstract_virtuals PROTO((tree));
extern tree get_baselinks PROTO((tree, tree, tree));
extern tree next_baselink PROTO((tree));
extern tree init_vbase_pointers PROTO((tree, tree));
-extern void expand_indirect_vtbls_init PROTO((tree, tree, tree, int));
+extern void expand_indirect_vtbls_init PROTO((tree, tree, tree));
extern void clear_search_slots PROTO((tree));
extern tree get_vbase_types PROTO((tree));
extern void build_mi_matrix PROTO((tree));
@@ -2327,7 +2766,7 @@ extern void add_mi_virtuals PROTO((int, tree));
extern void report_ambiguous_mi_virtuals PROTO((int, tree));
extern void note_debug_info_needed PROTO((tree));
extern void push_class_decls PROTO((tree));
-extern void pop_class_decls PROTO((tree));
+extern void pop_class_decls PROTO((void));
extern void unuse_fields PROTO((tree));
extern void unmark_finished_struct PROTO((tree));
extern void print_search_statistics PROTO((void));
@@ -2335,100 +2774,196 @@ extern void init_search_processing PROTO((void));
extern void reinit_search_statistics PROTO((void));
extern tree current_scope PROTO((void));
extern tree lookup_conversions PROTO((tree));
+extern tree get_template_base PROTO((tree, tree));
+
+/* in semantics.c */
+extern void finish_expr_stmt PROTO((tree));
+extern tree begin_if_stmt PROTO((void));
+extern void finish_if_stmt_cond PROTO((tree, tree));
+extern tree finish_then_clause PROTO((tree));
+extern void begin_else_clause PROTO((void));
+extern void finish_else_clause PROTO((tree));
+extern void finish_if_stmt PROTO((void));
+extern tree begin_while_stmt PROTO((void));
+extern void finish_while_stmt_cond PROTO((tree, tree));
+extern void finish_while_stmt PROTO((tree));
+extern tree begin_do_stmt PROTO((void));
+extern void finish_do_body PROTO((tree));
+extern void finish_do_stmt PROTO((tree, tree));
+extern void finish_return_stmt PROTO((tree));
+extern tree begin_for_stmt PROTO((void));
+extern void finish_for_init_stmt PROTO((tree));
+extern void finish_for_cond PROTO((tree, tree));
+extern void finish_for_expr PROTO((tree, tree));
+extern void finish_for_stmt PROTO((tree, tree));
+extern void finish_break_stmt PROTO((void));
+extern void finish_continue_stmt PROTO((void));
+extern void begin_switch_stmt PROTO((void));
+extern tree finish_switch_cond PROTO((tree));
+extern void finish_switch_stmt PROTO((tree, tree));
+extern void finish_case_label PROTO((tree, tree));
+extern void finish_goto_stmt PROTO((tree));
+extern tree begin_try_block PROTO((void));
+extern void finish_try_block PROTO((tree));
+extern void finish_handler_sequence PROTO((tree));
+extern tree begin_handler PROTO((void));
+extern void finish_handler_parms PROTO((tree));
+extern void finish_handler PROTO((tree));
+extern tree begin_compound_stmt PROTO((int));
+extern tree finish_compound_stmt PROTO((int, tree));
+extern void finish_asm_stmt PROTO((tree, tree, tree, tree, tree));
+extern tree finish_parenthesized_expr PROTO((tree));
+extern tree begin_stmt_expr PROTO((void));
+extern tree finish_stmt_expr PROTO((tree, tree));
+extern tree finish_call_expr PROTO((tree, tree, int));
+extern tree finish_increment_expr PROTO((tree, enum tree_code));
+extern tree finish_this_expr PROTO((void));
+extern tree finish_object_call_expr PROTO((tree, tree, tree));
+extern tree finish_qualified_object_call_expr PROTO((tree, tree, tree));
+extern tree finish_pseudo_destructor_call_expr PROTO((tree, tree, tree));
+extern tree finish_globally_qualified_member_call_expr PROTO ((tree, tree));
+extern tree finish_label_address_expr PROTO((tree));
+extern tree finish_unary_op_expr PROTO((enum tree_code, tree));
+extern tree finish_id_expr PROTO((tree));
+extern int begin_new_placement PROTO((void));
+extern tree finish_new_placement PROTO((tree, int));
+extern int begin_function_definition PROTO((tree, tree));
+extern tree begin_constructor_declarator PROTO((tree, tree));
+extern tree finish_declarator PROTO((tree, tree, tree, tree, int));
+extern void finish_translation_unit PROTO((void));
+extern tree finish_template_type_parm PROTO((tree, tree));
+extern tree finish_template_template_parm PROTO((tree, tree));
+extern tree finish_parmlist PROTO((tree, int));
+extern tree begin_class_definition PROTO((tree));
+extern tree finish_class_definition PROTO((tree, tree, tree, int));
+extern void finish_default_args PROTO((void));
+extern void begin_inline_definitions PROTO((void));
+extern tree finish_member_class_template PROTO((tree, tree));
/* in sig.c */
extern tree build_signature_pointer_type PROTO((tree, int, int));
extern tree build_signature_reference_type PROTO((tree, int, int));
extern tree build_signature_pointer_constructor PROTO((tree, tree));
-extern tree build_signature_method_call PROTO((tree, tree, tree, tree));
+extern tree build_signature_method_call PROTO((tree, tree));
extern tree build_optr_ref PROTO((tree));
-extern tree build_sptr_ref PROTO((tree));
+extern void append_signature_fields PROTO((tree));
/* in spew.c */
extern void init_spew PROTO((void));
+extern int peekyylex PROTO((void));
extern int yylex PROTO((void));
extern tree arbitrate_lookup PROTO((tree, tree, tree));
/* in tree.c */
+extern int member_p PROTO((tree));
+extern int real_lvalue_p PROTO((tree));
+extern tree build_min PVPROTO((enum tree_code, tree, ...));
+extern tree build_min_nt PVPROTO((enum tree_code, ...));
+extern tree min_tree_cons PROTO((tree, tree, tree));
extern int lvalue_p PROTO((tree));
extern int lvalue_or_else PROTO((tree, char *));
-extern tree build_cplus_new PROTO((tree, tree, int));
+extern tree build_cplus_new PROTO((tree, tree));
+extern tree get_target_expr PROTO((tree));
extern tree break_out_cleanups PROTO((tree));
extern tree break_out_calls PROTO((tree));
extern tree build_cplus_method_type PROTO((tree, tree, tree));
extern tree build_cplus_staticfn_type PROTO((tree, tree, tree));
extern tree build_cplus_array_type PROTO((tree, tree));
-extern void propagate_binfo_offsets PROTO((tree, tree));
-extern int layout_vbasetypes PROTO((tree, int));
-extern tree layout_basetypes PROTO((tree, tree));
-extern int list_hash PROTO((tree));
-extern tree list_hash_lookup PROTO((int, tree));
-extern void list_hash_add PROTO((int, tree));
-extern tree list_hash_canon PROTO((int, tree));
+extern int layout_basetypes PROTO((tree, int));
+extern tree build_vbase_pointer_fields PROTO((tree));
+extern tree build_base_fields PROTO((tree));
extern tree hash_tree_cons PROTO((int, int, int, tree, tree, tree));
extern tree hash_tree_chain PROTO((tree, tree));
extern tree hash_chainon PROTO((tree, tree));
extern tree get_decl_list PROTO((tree));
-extern tree list_hash_lookup_or_cons PROTO((tree));
extern tree make_binfo PROTO((tree, tree, tree, tree, tree));
extern tree binfo_value PROTO((tree, tree));
extern tree reverse_path PROTO((tree));
-extern tree virtual_member PROTO((tree, tree));
-extern void debug_binfo PROTO((tree));
-extern int decl_list_length PROTO((tree));
extern int count_functions PROTO((tree));
-extern tree decl_value_member PROTO((tree, tree));
extern int is_overloaded_fn PROTO((tree));
extern tree get_first_fn PROTO((tree));
+extern tree binding_init PROTO((struct tree_binding*));
+extern tree ovl_cons PROTO((tree, tree));
+extern tree scratch_ovl_cons PROTO((tree, tree));
+extern int ovl_member PROTO((tree, tree));
+extern tree build_overload PROTO((tree, tree));
extern tree fnaddr_from_vtable_entry PROTO((tree));
-extern void set_fnaddr_from_vtable_entry PROTO((tree, tree));
extern tree function_arg_chain PROTO((tree));
extern int promotes_to_aggr_type PROTO((tree, enum tree_code));
extern int is_aggr_type_2 PROTO((tree, tree));
-extern void message_2_types PROTO((void (*)(), char *, tree, tree));
-extern char *lang_printable_name PROTO((tree));
+extern char *lang_printable_name PROTO((tree, int));
extern tree build_exception_variant PROTO((tree, tree));
+extern tree copy_template_template_parm PROTO((tree));
extern tree copy_to_permanent PROTO((tree));
extern void print_lang_statistics PROTO((void));
-/* skip __eprintf */
+extern void __eprintf
+ PROTO((const char *, const char *, unsigned, const char *));
extern tree array_type_nelts_total PROTO((tree));
extern tree array_type_nelts_top PROTO((tree));
extern tree break_out_target_exprs PROTO((tree));
-extern tree build_unsave_expr PROTO((tree));
-extern int cp_expand_decl_cleanup PROTO((tree, tree));
+extern tree get_type_decl PROTO((tree));
+extern tree vec_binfo_member PROTO((tree, tree));
+extern tree hack_decl_function_context PROTO((tree));
+extern tree lvalue_type PROTO((tree));
+extern tree error_type PROTO((tree));
+extern tree make_temp_vec PROTO((int));
+extern tree build_ptr_wrapper PROTO((void *));
+extern tree build_expr_ptr_wrapper PROTO((void *));
+extern tree build_int_wrapper PROTO((int));
+extern tree build_srcloc PROTO((char *, int));
+extern tree build_srcloc_here PROTO((void));
+extern int varargs_function_p PROTO((tree));
+extern int really_overloaded_fn PROTO((tree));
+extern int cp_tree_equal PROTO((tree, tree));
+extern int can_free PROTO((struct obstack *, tree));
+extern tree mapcar PROTO((tree, tree (*) (tree)));
+extern void debug_binfo PROTO((tree));
+extern void push_expression_obstack PROTO((void));
+#define scratchalloc expralloc
+#define scratch_tree_cons expr_tree_cons
+#define build_scratch_list build_expr_list
+#define make_scratch_vec make_temp_vec
+#define push_scratch_obstack push_expression_obstack
/* in typeck.c */
extern tree condition_conversion PROTO((tree));
extern tree target_type PROTO((tree));
extern tree require_complete_type PROTO((tree));
+extern tree complete_type PROTO((tree));
+extern tree complete_type_or_else PROTO((tree));
extern int type_unknown_p PROTO((tree));
extern int fntype_p PROTO((tree));
extern tree require_instantiated_type PROTO((tree, tree, tree));
extern tree commonparms PROTO((tree, tree));
+extern tree original_type PROTO((tree));
extern tree common_type PROTO((tree, tree));
-extern int compexcepttypes PROTO((tree, tree, int));
+extern int compexcepttypes PROTO((tree, tree));
extern int comptypes PROTO((tree, tree, int));
extern int comp_target_types PROTO((tree, tree, int));
-extern tree common_base_types PROTO((tree, tree));
extern int compparms PROTO((tree, tree, int));
extern int comp_target_types PROTO((tree, tree, int));
+extern int comp_cv_qualification PROTO((tree, tree));
+extern int comp_cv_qual_signature PROTO((tree, tree));
extern int self_promoting_args_p PROTO((tree));
extern tree unsigned_type PROTO((tree));
extern tree signed_type PROTO((tree));
extern tree signed_or_unsigned_type PROTO((int, tree));
+extern tree expr_sizeof PROTO((tree));
extern tree c_sizeof PROTO((tree));
extern tree c_sizeof_nowarn PROTO((tree));
extern tree c_alignof PROTO((tree));
+extern tree inline_conversion PROTO((tree));
extern tree decay_conversion PROTO((tree));
extern tree default_conversion PROTO((tree));
extern tree build_object_ref PROTO((tree, tree, tree));
extern tree build_component_ref_1 PROTO((tree, tree, int));
extern tree build_component_ref PROTO((tree, tree, tree, int));
+extern tree build_x_component_ref PROTO((tree, tree, tree, int));
extern tree build_x_indirect_ref PROTO((tree, char *));
extern tree build_indirect_ref PROTO((tree, char *));
-extern tree build_x_array_ref PROTO((tree, tree));
extern tree build_array_ref PROTO((tree, tree));
extern tree build_x_function_call PROTO((tree, tree, tree));
+extern tree get_member_function_from_ptrfunc PROTO((tree *, tree));
extern tree build_function_call_real PROTO((tree, tree, int, int));
extern tree build_function_call PROTO((tree, tree));
extern tree build_function_call_maybe PROTO((tree, tree));
@@ -2448,7 +2983,8 @@ extern tree build_compound_expr PROTO((tree));
extern tree build_static_cast PROTO((tree, tree));
extern tree build_reinterpret_cast PROTO((tree, tree));
extern tree build_const_cast PROTO((tree, tree));
-extern tree build_c_cast PROTO((tree, tree, int));
+extern tree build_c_cast PROTO((tree, tree));
+extern tree build_x_modify_expr PROTO((tree, enum tree_code, tree));
extern tree build_modify_expr PROTO((tree, enum tree_code, tree));
extern int language_lvalue_valid PROTO((tree));
extern void warn_for_assignment PROTO((char *, char *, char *, tree, int, int));
@@ -2456,15 +2992,16 @@ extern tree convert_for_initialization PROTO((tree, tree, tree, int, char *, tr
extern void c_expand_asm_operands PROTO((tree, tree, tree, tree, int, char *, int));
extern void c_expand_return PROTO((tree));
extern tree c_expand_start_case PROTO((tree));
-extern tree build_component_ref PROTO((tree, tree, tree, int));
+extern int comp_ptr_ttypes PROTO((tree, tree));
+extern int ptr_reasonably_similar PROTO((tree, tree));
extern tree build_ptrmemfunc PROTO((tree, tree, int));
/* in typeck2.c */
extern tree error_not_base_type PROTO((tree, tree));
extern tree binfo_or_else PROTO((tree, tree));
-extern void error_with_aggr_type (); /* PROTO((tree, char *, HOST_WIDE_INT)); */
extern void readonly_error PROTO((tree, char *, int));
extern void abstract_virtuals_error PROTO((tree, tree));
+extern void signature_error PROTO((tree, tree));
extern void incomplete_type_error PROTO((tree, tree));
extern void my_friendly_abort PROTO((int));
extern void my_friendly_assert PROTO((int, int));
@@ -2476,19 +3013,21 @@ extern tree build_m_component_ref PROTO((tree, tree));
extern tree build_functional_cast PROTO((tree, tree));
extern char *enum_name_string PROTO((tree, tree));
extern void report_case_error PROTO((int, tree, tree, tree));
+extern void check_for_new_type PROTO((char *,flagged_type_tree));
+extern tree initializer_constant_valid_p PROTO((tree, tree));
/* in xref.c */
extern void GNU_xref_begin PROTO((char *));
extern void GNU_xref_end PROTO((int));
extern void GNU_xref_file PROTO((char *));
extern void GNU_xref_start_scope PROTO((HOST_WIDE_INT));
-extern void GNU_xref_end_scope PROTO((HOST_WIDE_INT, HOST_WIDE_INT, int, int, int));
+extern void GNU_xref_end_scope PROTO((HOST_WIDE_INT, HOST_WIDE_INT, int, int));
extern void GNU_xref_ref PROTO((tree, char *));
extern void GNU_xref_decl PROTO((tree, tree));
extern void GNU_xref_call PROTO((tree, char *));
extern void GNU_xref_function PROTO((tree, tree));
extern void GNU_xref_assign PROTO((tree));
-extern void GNU_xref_hier PROTO((char *, char *, int, int, int));
+extern void GNU_xref_hier PROTO((tree, tree, int, int, int));
extern void GNU_xref_member PROTO((tree, tree));
/* -- end of C++ */
diff --git a/contrib/gcc/cp/cvt.c b/contrib/gcc/cp/cvt.c
index 56508c1..18b7d8b 100644
--- a/contrib/gcc/cp/cvt.c
+++ b/contrib/gcc/cp/cvt.c
@@ -1,5 +1,5 @@
/* Language-level data type conversion for GNU C++.
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-96, 1998 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -26,14 +26,17 @@ Boston, MA 02111-1307, USA. */
but what kind of conversions it does will depend on the language. */
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "flags.h"
#include "cp-tree.h"
-#include "class.h"
#include "convert.h"
-#undef NULL
-#define NULL (char *)0
+extern tree static_aggregates;
+
+static tree cp_convert_to_pointer PROTO((tree, tree));
+static tree convert_to_pointer_force PROTO((tree, tree));
+static tree build_up_reference PROTO((tree, tree, int, int));
/* Change of width--truncation and extension of integers or reals--
is represented with NOP_EXPR. Proper functioning of many things
@@ -57,71 +60,87 @@ Boston, MA 02111-1307, USA. */
/* Subroutines of `convert'. */
-/* Build a thunk. What it is, is an entry point that when called will
- adjust the this pointer (the first argument) by offset, and then
- goto the real address of the function given by REAL_ADDR that we
- would like called. What we return is the address of the thunk. */
-static tree
-build_thunk (offset, real_addr)
- tree offset, real_addr;
-{
- if (TREE_CODE (real_addr) != ADDR_EXPR
- || TREE_CODE (TREE_OPERAND (real_addr, 0)) != FUNCTION_DECL)
- {
- sorry ("MI pointer to member conversion too complex");
- return error_mark_node;
- }
- sorry ("MI pointer to member conversion too complex");
- return error_mark_node;
-}
-
-/* Convert a `pointer to member' (POINTER_TYPE to METHOD_TYPE) into
- another `pointer to method'. This may involved the creation of
- a thunk to handle the this offset calculation. */
-static tree
-convert_fn_ptr (type, expr)
- tree type, expr;
-{
- if (flag_vtable_thunks)
- {
- tree intype = TREE_TYPE (expr);
- tree binfo = get_binfo (TYPE_METHOD_BASETYPE (TREE_TYPE (intype)),
- TYPE_METHOD_BASETYPE (TREE_TYPE (type)), 1);
- if (binfo == error_mark_node)
- {
- error (" in pointer to member conversion");
- return error_mark_node;
- }
- if (binfo == NULL_TREE)
- {
- /* ARM 4.8 restriction. */
- error ("invalid pointer to member conversion");
- return error_mark_node;
- }
-
- if (BINFO_OFFSET_ZEROP (binfo))
- return build1 (NOP_EXPR, type, expr);
- return build1 (NOP_EXPR, type, build_thunk (BINFO_OFFSET (binfo), expr));
- }
- else
- return build_ptrmemfunc (type, expr, 1);
-}
-
/* if converting pointer to pointer
if dealing with classes, check for derived->base or vice versa
else if dealing with method pointers, delegate
else convert blindly
else if converting class, pass off to build_type_conversion
else try C-style pointer conversion */
+
static tree
cp_convert_to_pointer (type, expr)
tree type, expr;
{
register tree intype = TREE_TYPE (expr);
register enum tree_code form;
+ tree rval;
+
+ if (IS_AGGR_TYPE (intype))
+ {
+ intype = complete_type (intype);
+ if (TYPE_SIZE (intype) == NULL_TREE)
+ {
+ cp_error ("can't convert from incomplete type `%T' to `%T'",
+ intype, type);
+ return error_mark_node;
+ }
+
+ rval = build_type_conversion (CONVERT_EXPR, type, expr, 1);
+ if (rval)
+ {
+ if (rval == error_mark_node)
+ cp_error ("conversion of `%E' from `%T' to `%T' is ambiguous",
+ expr, intype, type);
+ return rval;
+ }
+ }
if (TYPE_PTRMEMFUNC_P (type))
type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+
+ /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */
+ if (TREE_CODE (type) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+ || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node))
+ {
+ /* Allow an implicit this pointer for pointer to member
+ functions. */
+ if (TYPE_PTRMEMFUNC_P (intype))
+ {
+ tree decl, basebinfo;
+ tree fntype = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (intype));
+ tree t = TYPE_METHOD_BASETYPE (fntype);
+
+ if (current_class_type == 0
+ || get_base_distance (t, current_class_type, 0, &basebinfo)
+ == -1)
+ {
+ decl = build1 (NOP_EXPR, t, error_mark_node);
+ }
+ else if (current_class_ptr == 0)
+ decl = build1 (NOP_EXPR, t, error_mark_node);
+ else
+ decl = current_class_ref;
+
+ expr = build (OFFSET_REF, fntype, decl, expr);
+ }
+
+ if (TREE_CODE (expr) == OFFSET_REF
+ && TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE)
+ expr = resolve_offset_ref (expr);
+ if (TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE)
+ expr = build_addr_func (expr);
+ if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
+ {
+ if (TREE_CODE (TREE_TYPE (TREE_TYPE (expr))) == METHOD_TYPE)
+ if (pedantic || warn_pmf2ptr)
+ cp_pedwarn ("converting from `%T' to `%T'", TREE_TYPE (expr),
+ type);
+ return build1 (NOP_EXPR, type, expr);
+ }
+ intype = TREE_TYPE (expr);
+ }
+
if (TYPE_PTRMEMFUNC_P (intype))
intype = TYPE_PTRMEMFUNC_FN_TYPE (intype);
@@ -133,6 +152,8 @@ cp_convert_to_pointer (type, expr)
if (TYPE_MAIN_VARIANT (type) != intype
&& TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
+ && IS_AGGR_TYPE (TREE_TYPE (type))
+ && IS_AGGR_TYPE (TREE_TYPE (intype))
&& TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
{
enum tree_code code = PLUS_EXPR;
@@ -156,9 +177,11 @@ cp_convert_to_pointer (type, expr)
tree path;
if (code == PLUS_EXPR)
- get_base_distance (TREE_TYPE (type), TREE_TYPE (intype), 0, &path);
+ get_base_distance (TREE_TYPE (type), TREE_TYPE (intype),
+ 0, &path);
else
- get_base_distance (TREE_TYPE (intype), TREE_TYPE (type), 0, &path);
+ get_base_distance (TREE_TYPE (intype), TREE_TYPE (type),
+ 0, &path);
return build_vbase_path (code, type, expr, path, 0);
}
}
@@ -166,18 +189,26 @@ cp_convert_to_pointer (type, expr)
if (TREE_CODE (TREE_TYPE (intype)) == METHOD_TYPE
&& TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
- return convert_fn_ptr (type, expr);
+ return build_ptrmemfunc (type, expr, 1);
if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE
&& TREE_CODE (TREE_TYPE (intype)) == OFFSET_TYPE)
{
tree b1 = TYPE_OFFSET_BASETYPE (TREE_TYPE (type));
tree b2 = TYPE_OFFSET_BASETYPE (TREE_TYPE (intype));
- tree binfo = get_binfo (b1, b2, 1);
+ tree binfo = get_binfo (b2, b1, 1);
+ enum tree_code code = PLUS_EXPR;
+
if (binfo == NULL_TREE)
- binfo = get_binfo (b2, b1, 1);
+ {
+ binfo = get_binfo (b1, b2, 1);
+ code = MINUS_EXPR;
+ }
+
if (binfo == error_mark_node)
return error_mark_node;
+ if (binfo && ! TREE_VIA_VIRTUAL (binfo))
+ expr = size_binop (code, expr, BINFO_OFFSET (binfo));
}
if (TREE_CODE (TREE_TYPE (intype)) == METHOD_TYPE
@@ -189,7 +220,9 @@ cp_convert_to_pointer (type, expr)
return error_mark_node;
}
- return build1 (NOP_EXPR, type, expr);
+ rval = build1 (NOP_EXPR, type, expr);
+ TREE_CONSTANT (rval) = TREE_CONSTANT (expr);
+ return rval;
}
my_friendly_assert (form != OFFSET_TYPE, 186);
@@ -198,23 +231,10 @@ cp_convert_to_pointer (type, expr)
&& (IS_SIGNATURE_POINTER (intype) || IS_SIGNATURE_REFERENCE (intype)))
return convert_to_pointer (type, build_optr_ref (expr));
- if (IS_AGGR_TYPE (intype))
- {
- tree rval;
- rval = build_type_conversion (CONVERT_EXPR, type, expr, 1);
- if (rval)
- {
- if (rval == error_mark_node)
- cp_error ("conversion of `%E' from `%T' to `%T' is ambiguous",
- expr, intype, type);
- return rval;
- }
- }
-
if (integer_zerop (expr))
{
- if (type == TREE_TYPE (null_pointer_node))
- return null_pointer_node;
+ if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+ return build_ptrmemfunc (type, expr, 0);
expr = build_int_2 (0, 0);
TREE_TYPE (expr) = type;
return expr;
@@ -222,9 +242,9 @@ cp_convert_to_pointer (type, expr)
if (INTEGRAL_CODE_P (form))
{
- if (type_precision (intype) == POINTER_SIZE)
+ if (TYPE_PRECISION (intype) == POINTER_SIZE)
return build1 (CONVERT_EXPR, type, expr);
- expr = convert (type_for_size (POINTER_SIZE, 0), expr);
+ expr = cp_convert (type_for_size (POINTER_SIZE, 0), expr);
/* Modes may be different but sizes should be the same. */
if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr)))
!= GET_MODE_SIZE (TYPE_MODE (type)))
@@ -242,6 +262,7 @@ cp_convert_to_pointer (type, expr)
/* Like convert, except permit conversions to take place which
are not normally allowed due to access restrictions
(such as conversion from sub-type to private super-type). */
+
static tree
convert_to_pointer_force (type, expr)
tree type, expr;
@@ -251,8 +272,6 @@ convert_to_pointer_force (type, expr)
if (integer_zerop (expr))
{
- if (type == TREE_TYPE (null_pointer_node))
- return null_pointer_node;
expr = build_int_2 (0, 0);
TREE_TYPE (expr) = type;
return expr;
@@ -273,6 +292,8 @@ convert_to_pointer_force (type, expr)
if (TYPE_MAIN_VARIANT (type) != intype
&& TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE
+ && IS_AGGR_TYPE (TREE_TYPE (type))
+ && IS_AGGR_TYPE (TREE_TYPE (intype))
&& TREE_CODE (TREE_TYPE (intype)) == RECORD_TYPE)
{
enum tree_code code = PLUS_EXPR;
@@ -282,8 +303,9 @@ convert_to_pointer_force (type, expr)
if (distance == -2)
{
ambig:
- cp_error ("type `%T' is ambiguous baseclass of `%s'", TREE_TYPE (type),
- TYPE_NAME_STRING (TREE_TYPE (intype)));
+ cp_error ("type `%T' is ambiguous baseclass of `%s'",
+ TREE_TYPE (type),
+ TYPE_NAME_STRING (TREE_TYPE (intype)));
return error_mark_node;
}
if (distance == -1)
@@ -300,7 +322,6 @@ convert_to_pointer_force (type, expr)
}
return build_vbase_path (code, type, expr, path, 0);
}
- return build1 (NOP_EXPR, type, expr);
}
return cp_convert_to_pointer (type, expr);
@@ -311,343 +332,61 @@ convert_to_pointer_force (type, expr)
value we have to begin with is in ARG.
FLAGS controls how we manage access checking.
- CHECKCONST controls if we report error messages on const subversion. */
+ DIRECT_BIND in FLAGS controls how any temporaries are generated. */
+
static tree
build_up_reference (type, arg, flags, checkconst)
tree type, arg;
int flags, checkconst;
{
- tree rval, targ;
- int literal_flag = 0;
+ tree rval;
tree argtype = TREE_TYPE (arg);
tree target_type = TREE_TYPE (type);
- tree binfo = NULL_TREE;
my_friendly_assert (TREE_CODE (type) == REFERENCE_TYPE, 187);
+
+ if ((flags & DIRECT_BIND) && ! real_lvalue_p (arg))
+ {
+ tree targ = arg;
+ if (toplevel_bindings_p ())
+ arg = get_temp_name (argtype, 1);
+ else
+ {
+ arg = pushdecl (build_decl (VAR_DECL, NULL_TREE, argtype));
+ DECL_ARTIFICIAL (arg) = 1;
+ }
+ DECL_INITIAL (arg) = targ;
+ cp_finish_decl (arg, targ, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
+ }
+ else if (!(flags & DIRECT_BIND) && ! lvalue_p (arg))
+ {
+ tree slot = build_decl (VAR_DECL, NULL_TREE, argtype);
+ arg = build (TARGET_EXPR, argtype, slot, arg, NULL_TREE, NULL_TREE);
+ TREE_SIDE_EFFECTS (arg) = 1;
+ }
+
+ /* If we had a way to wrap this up, and say, if we ever needed it's
+ address, transform all occurrences of the register, into a memory
+ reference we could win better. */
+ rval = build_unary_op (ADDR_EXPR, arg, 1);
if ((flags & LOOKUP_PROTECT)
&& TYPE_MAIN_VARIANT (argtype) != TYPE_MAIN_VARIANT (target_type)
&& IS_AGGR_TYPE (argtype)
&& IS_AGGR_TYPE (target_type))
{
- binfo = get_binfo (target_type, argtype, 1);
+ /* We go through get_binfo for the access control. */
+ tree binfo = get_binfo (target_type, argtype, 1);
if (binfo == error_mark_node)
return error_mark_node;
if (binfo == NULL_TREE)
return error_not_base_type (target_type, argtype);
- }
-
- /* Pass along const and volatile down into the type. */
- if (TYPE_READONLY (type) || TYPE_VOLATILE (type))
- target_type = cp_build_type_variant (target_type, TYPE_READONLY (type),
- TYPE_VOLATILE (type));
- targ = arg;
- if (TREE_CODE (targ) == SAVE_EXPR)
- targ = TREE_OPERAND (targ, 0);
- while (TREE_CODE (targ) == NOP_EXPR
- && (TYPE_MAIN_VARIANT (argtype)
- == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (targ, 0)))))
- targ = TREE_OPERAND (targ, 0);
-
- switch (TREE_CODE (targ))
- {
- case INDIRECT_REF:
- /* This is a call to a constructor which did not know what it was
- initializing until now: it needs to initialize a temporary. */
- if (TREE_HAS_CONSTRUCTOR (targ))
- {
- tree temp = build_cplus_new (argtype, TREE_OPERAND (targ, 0), 1);
- TREE_HAS_CONSTRUCTOR (targ) = 0;
- return build_up_reference (type, temp, flags, 1);
- }
- /* Let &* cancel out to simplify resulting code.
- Also, throw away intervening NOP_EXPRs. */
- arg = TREE_OPERAND (targ, 0);
- if (TREE_CODE (arg) == NOP_EXPR || TREE_CODE (arg) == NON_LVALUE_EXPR
- || (TREE_CODE (arg) == CONVERT_EXPR && TREE_REFERENCE_EXPR (arg)))
- arg = TREE_OPERAND (arg, 0);
-
- /* in doing a &*, we have to get rid of the const'ness on the pointer
- value. Haven't thought about volatile here. Pointers come to mind
- here. */
- if (TREE_READONLY (arg))
- {
- arg = copy_node (arg);
- TREE_READONLY (arg) = 0;
- }
-
- rval = build1 (CONVERT_EXPR, type, arg);
- TREE_REFERENCE_EXPR (rval) = 1;
-
- /* propagate the const flag on something like:
-
- class Base {
- public:
- int foo;
- };
-
- class Derived : public Base {
- public:
- int bar;
- };
-
- void func(Base&);
-
- void func2(const Derived& d) {
- func(d);
- }
-
- on the d parameter. The below could have been avoided, if the flags
- were down in the tree, not sure why they are not. (mrs) */
- /* The below code may have to be propagated to other parts of this
- switch. */
- if (TREE_READONLY (targ) && !TREE_READONLY (arg)
- && (TREE_CODE (arg) == PARM_DECL || TREE_CODE (arg) == VAR_DECL)
- && TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE
- && (TYPE_READONLY (target_type) && checkconst))
- {
- arg = copy_node (arg);
- TREE_READONLY (arg) = TREE_READONLY (targ);
- }
- literal_flag = TREE_CONSTANT (arg);
-
- goto done;
-
- /* Get this out of a register if we happened to be in one by accident.
- Also, build up references to non-lvalues it we must. */
- /* For &x[y], return (&) x+y */
- case ARRAY_REF:
- if (mark_addressable (TREE_OPERAND (targ, 0)) == 0)
- return error_mark_node;
- rval = build_binary_op (PLUS_EXPR, TREE_OPERAND (targ, 0),
- TREE_OPERAND (targ, 1), 1);
- TREE_TYPE (rval) = type;
- if (TREE_CONSTANT (TREE_OPERAND (targ, 1))
- && staticp (TREE_OPERAND (targ, 0)))
- TREE_CONSTANT (rval) = 1;
- goto done;
-
- case SCOPE_REF:
- /* Could be a reference to a static member. */
- {
- tree field = TREE_OPERAND (targ, 1);
- if (TREE_STATIC (field))
- {
- rval = build1 (ADDR_EXPR, type, field);
- literal_flag = 1;
- goto done;
- }
- }
-
- /* We should have farmed out member pointers above. */
- my_friendly_abort (188);
-
- case COMPONENT_REF:
- rval = build_component_addr (targ, build_pointer_type (argtype),
- "attempt to make a reference to bit-field structure member `%s'");
- TREE_TYPE (rval) = type;
- literal_flag = staticp (TREE_OPERAND (targ, 0));
-
- goto done;
-
- /* Anything not already handled and not a true memory reference
- needs to have a reference built up. Do so silently for
- things like integers and return values from function,
- but complain if we need a reference to something declared
- as `register'. */
-
- case RESULT_DECL:
- if (staticp (targ))
- literal_flag = 1;
- TREE_ADDRESSABLE (targ) = 1;
- put_var_into_stack (targ);
- break;
-
- case PARM_DECL:
-#if 0
- if (targ == current_class_decl)
- {
- error ("address of `this' not available");
-/* #if 0 */
- /* This code makes the following core dump the compiler on a sun4,
- if the code below is used.
-
- class e_decl;
- class a_decl;
- typedef a_decl* a_ref;
-
- class a_s {
- public:
- a_s();
- void* append(a_ref& item);
- };
- class a_decl {
- public:
- a_decl (e_decl *parent);
- a_s generic_s;
- a_s decls;
- e_decl* parent;
- };
-
- class e_decl {
- public:
- e_decl();
- a_s implementations;
- };
-
- void foobar(void *);
-
- a_decl::a_decl(e_decl *parent) {
- parent->implementations.append(this);
- }
- */
-
- TREE_ADDRESSABLE (targ) = 1; /* so compiler doesn't die later */
- put_var_into_stack (targ);
- break;
-/* #else */
- return error_mark_node;
-/* #endif */
- }
-#endif
- /* Fall through. */
- case VAR_DECL:
- case CONST_DECL:
- if (DECL_REGISTER (targ) && !TREE_ADDRESSABLE (targ)
- && !DECL_ARTIFICIAL (targ))
- cp_warning ("address needed to build reference for `%D', which is declared `register'",
- targ);
- else if (staticp (targ))
- literal_flag = 1;
-
- TREE_ADDRESSABLE (targ) = 1;
- put_var_into_stack (targ);
- break;
-
- case COMPOUND_EXPR:
- {
- tree real_reference = build_up_reference (type, TREE_OPERAND (targ, 1),
- LOOKUP_PROTECT, checkconst);
- rval = build (COMPOUND_EXPR, type, TREE_OPERAND (targ, 0), real_reference);
- TREE_CONSTANT (rval) = staticp (TREE_OPERAND (targ, 1));
- return rval;
- }
-
- case PREINCREMENT_EXPR:
- case PREDECREMENT_EXPR:
- case MODIFY_EXPR:
- case INIT_EXPR:
- {
- tree real_reference = build_up_reference (type, TREE_OPERAND (targ, 0),
- LOOKUP_PROTECT, checkconst);
- rval = build (COMPOUND_EXPR, type, arg, real_reference);
- TREE_CONSTANT (rval) = staticp (TREE_OPERAND (targ, 0));
- return rval;
- }
-
- case COND_EXPR:
- return build (COND_EXPR, type,
- TREE_OPERAND (targ, 0),
- build_up_reference (type, TREE_OPERAND (targ, 1),
- LOOKUP_PROTECT, checkconst),
- build_up_reference (type, TREE_OPERAND (targ, 2),
- LOOKUP_PROTECT, checkconst));
-
- /* Undo the folding... */
- case MIN_EXPR:
- case MAX_EXPR:
- return build (COND_EXPR, type,
- build (TREE_CODE (targ) == MIN_EXPR ? LT_EXPR : GT_EXPR,
- boolean_type_node, TREE_OPERAND (targ, 0),
- TREE_OPERAND (targ, 1)),
- build_up_reference (type, TREE_OPERAND (targ, 0),
- LOOKUP_PROTECT, checkconst),
- build_up_reference (type, TREE_OPERAND (targ, 1),
- LOOKUP_PROTECT, checkconst));
-
- case WITH_CLEANUP_EXPR:
- return build (WITH_CLEANUP_EXPR, type,
- build_up_reference (type, TREE_OPERAND (targ, 0),
- LOOKUP_PROTECT, checkconst),
- 0, TREE_OPERAND (targ, 2));
-
- case BIND_EXPR:
- arg = TREE_OPERAND (targ, 1);
- if (arg == NULL_TREE)
- {
- compiler_error ("({ ... }) expression not expanded when needed for reference");
- return error_mark_node;
- }
- rval = build1 (ADDR_EXPR, type, arg);
- TREE_REFERENCE_EXPR (rval) = 1;
- return rval;
-
- default:
- break;
- }
-
- if (TREE_ADDRESSABLE (targ) == 0)
- {
- tree temp;
-
- if (TREE_CODE (targ) == CALL_EXPR && IS_AGGR_TYPE (argtype))
- {
- temp = build_cplus_new (argtype, targ, 1);
- if (TREE_CODE (temp) == WITH_CLEANUP_EXPR)
- rval = build (WITH_CLEANUP_EXPR, type,
- build1 (ADDR_EXPR, type, TREE_OPERAND (temp, 0)),
- 0, TREE_OPERAND (temp, 2));
- else
- rval = build1 (ADDR_EXPR, type, temp);
- goto done;
- }
- else
- {
- temp = get_temp_name (argtype, 0);
- if (toplevel_bindings_p ())
- {
- /* Give this new temp some rtl and initialize it. */
- DECL_INITIAL (temp) = targ;
- TREE_STATIC (temp) = 1;
- cp_finish_decl (temp, targ, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
- /* Do this after declaring it static. */
- rval = build_unary_op (ADDR_EXPR, temp, 0);
- TREE_TYPE (rval) = type;
- literal_flag = TREE_CONSTANT (rval);
- goto done;
- }
- else
- {
- rval = build_unary_op (ADDR_EXPR, temp, 0);
- if (binfo && !BINFO_OFFSET_ZEROP (binfo))
- rval = convert_pointer_to (target_type, rval);
- else
- TREE_TYPE (rval) = type;
-
- temp = build (MODIFY_EXPR, argtype, temp, arg);
- TREE_SIDE_EFFECTS (temp) = 1;
- return build (COMPOUND_EXPR, type, temp, rval);
- }
- }
+ rval = convert_pointer_to_real (binfo, rval);
}
else
- rval = build1 (ADDR_EXPR, type, arg);
-
- done:
- if (TYPE_USES_COMPLEX_INHERITANCE (argtype)
- || TYPE_USES_COMPLEX_INHERITANCE (target_type))
- {
- TREE_TYPE (rval) = build_pointer_type (argtype);
- if (flags & LOOKUP_PROTECT)
- rval = convert_pointer_to (target_type, rval);
- else
- rval
- = convert_to_pointer_force (build_pointer_type (target_type), rval);
- TREE_TYPE (rval) = type;
- if (TREE_CODE (rval) == PLUS_EXPR || TREE_CODE (rval) == MINUS_EXPR)
- TREE_TYPE (TREE_OPERAND (rval, 0))
- = TREE_TYPE (TREE_OPERAND (rval, 1)) = type;
- }
- TREE_CONSTANT (rval) = literal_flag;
+ rval
+ = convert_to_pointer_force (build_pointer_type (target_type), rval);
+ rval = build1 (NOP_EXPR, type, rval);
+ TREE_CONSTANT (rval) = TREE_CONSTANT (TREE_OPERAND (rval, 0));
return rval;
}
@@ -682,7 +421,8 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
{
/* Look for a user-defined conversion to lvalue that we can use. */
- rval_as_conversion = build_type_conversion (CONVERT_EXPR, type, expr, 1);
+ rval_as_conversion
+ = build_type_conversion (CONVERT_EXPR, reftype, expr, 1);
if (rval_as_conversion && rval_as_conversion != error_mark_node
&& real_lvalue_p (rval_as_conversion))
@@ -708,15 +448,14 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
ttr = cp_build_type_variant (TREE_TYPE (expr), r, v);
}
- if (! real_lvalue_p (expr) &&
- (decl == NULL_TREE || ! TYPE_READONLY (ttl)))
+ if (! real_lvalue_p (expr) && ! TYPE_READONLY (ttl))
{
if (decl)
/* Ensure semantics of [dcl.init.ref] */
- cp_pedwarn ("initialization of non-const `%T' from rvalue `%T'",
+ cp_pedwarn ("initialization of non-const reference `%#T' from rvalue `%T'",
reftype, intype);
else
- cp_pedwarn ("conversion to `%T' from rvalue `%T'",
+ cp_pedwarn ("conversion to non-const `%T' from rvalue `%T'",
reftype, intype);
}
else if (! (convtype & CONV_CONST))
@@ -749,89 +488,18 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
rval = build_unary_op (ADDR_EXPR, expr, 0);
if (rval != error_mark_node)
- rval = convert_force (build_pointer_type (TREE_TYPE (reftype)), rval, 0);
+ rval = convert_force (build_pointer_type (TREE_TYPE (reftype)),
+ rval, 0);
if (rval != error_mark_node)
rval = build1 (NOP_EXPR, reftype, rval);
}
- else if (decl)
+ else
{
- tree rval_as_ctor = NULL_TREE;
-
- if (rval_as_conversion)
- {
- if (rval_as_conversion == error_mark_node)
- {
- cp_error ("conversion from `%T' to `%T' is ambiguous",
- intype, reftype);
- return error_mark_node;
- }
- rval_as_conversion = build_up_reference (reftype, rval_as_conversion,
- flags, 1);
- }
-
- /* Definitely need to go through a constructor here. */
- if (TYPE_HAS_CONSTRUCTOR (type)
- && ! CLASSTYPE_ABSTRACT_VIRTUALS (type)
- && (rval = build_method_call
- (NULL_TREE, constructor_name_full (type),
- build_tree_list (NULL_TREE, expr), TYPE_BINFO (type),
- LOOKUP_NO_CONVERSION|LOOKUP_SPECULATIVELY
- | LOOKUP_ONLYCONVERTING)))
- {
- tree init;
-
- if (toplevel_bindings_p ())
- {
- extern tree static_aggregates;
- tree t = get_temp_name (type, toplevel_bindings_p ());
- init = build_method_call (t, constructor_name_full (type),
- build_tree_list (NULL_TREE, expr),
- TYPE_BINFO (type),
- LOOKUP_NORMAL|LOOKUP_NO_CONVERSION
- | LOOKUP_ONLYCONVERTING);
-
- if (init == error_mark_node)
- return error_mark_node;
-
- make_decl_rtl (t, NULL_PTR, 1);
- static_aggregates = perm_tree_cons (expr, t, static_aggregates);
- rval = build_unary_op (ADDR_EXPR, t, 0);
- }
- else
- {
- init = build_method_call (NULL_TREE, constructor_name_full (type),
- build_tree_list (NULL_TREE, expr),
- TYPE_BINFO (type),
- LOOKUP_NORMAL|LOOKUP_NO_CONVERSION
- |LOOKUP_ONLYCONVERTING);
-
- if (init == error_mark_node)
- return error_mark_node;
-
- rval = build_cplus_new (type, init, 1);
- rval = build_up_reference (reftype, rval, flags, 1);
- }
- rval_as_ctor = rval;
- }
-
- if (rval_as_ctor && rval_as_conversion)
- {
- cp_error ("ambiguous conversion from `%T' to `%T'; both user-defined conversion and constructor apply",
- intype, reftype);
- return error_mark_node;
- }
- else if (rval_as_ctor)
- rval = rval_as_ctor;
- else if (rval_as_conversion)
- rval = rval_as_conversion;
- else if (! IS_AGGR_TYPE (type) && ! IS_AGGR_TYPE (intype))
- {
- rval = convert (type, expr);
- if (rval == error_mark_node)
- return error_mark_node;
-
- rval = build_up_reference (reftype, rval, flags, 1);
- }
+ rval = convert_for_initialization (NULL_TREE, type, expr, flags,
+ "converting", 0, 0);
+ if (rval == error_mark_node)
+ return error_mark_node;
+ rval = build_up_reference (reftype, rval, flags, 1);
if (rval && ! TYPE_READONLY (TREE_TYPE (reftype)))
cp_pedwarn ("initializing non-const `%T' with `%T' will use a temporary",
@@ -840,7 +508,7 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
if (rval)
{
- /* If we found a way to convert earlier, then use it. */
+ /* If we found a way to convert earlier, then use it. */
return rval;
}
@@ -856,7 +524,8 @@ convert_to_reference (reftype, expr, convtype, flags, decl)
}
/* We are using a reference VAL for its value. Bash that reference all the
- way down to its lowest form. */
+ way down to its lowest form. */
+
tree
convert_from_reference (val)
tree val;
@@ -870,231 +539,13 @@ convert_from_reference (val)
return val;
}
-/* See if there is a constructor of type TYPE which will convert
- EXPR. The reference manual seems to suggest (8.5.6) that we need
- not worry about finding constructors for base classes, then converting
- to the derived class.
-
- MSGP is a pointer to a message that would be an appropriate error
- string. If MSGP is NULL, then we are not interested in reporting
- errors. */
-tree
-convert_to_aggr (type, expr, msgp, protect)
- tree type, expr;
- char **msgp;
- int protect;
-{
- tree basetype = type;
- tree name = TYPE_IDENTIFIER (basetype);
- tree function, fndecl, fntype, parmtypes, parmlist, result;
- tree method_name;
- enum access_type access;
- int can_be_private, can_be_protected;
-
- if (! TYPE_HAS_CONSTRUCTOR (basetype))
- {
- if (msgp)
- *msgp = "type `%s' does not have a constructor";
- return error_mark_node;
- }
-
- access = access_public;
- can_be_private = 0;
- can_be_protected = IDENTIFIER_CLASS_VALUE (name) || name == current_class_name;
-
- parmlist = build_tree_list (NULL_TREE, expr);
- parmtypes = tree_cons (NULL_TREE, TREE_TYPE (expr), void_list_node);
-
- if (TYPE_USES_VIRTUAL_BASECLASSES (basetype))
- {
- parmtypes = tree_cons (NULL_TREE, integer_type_node, parmtypes);
- parmlist = tree_cons (NULL_TREE, integer_one_node, parmlist);
- }
-
- /* The type of the first argument will be filled in inside the loop. */
- parmlist = tree_cons (NULL_TREE, integer_zero_node, parmlist);
- parmtypes = tree_cons (NULL_TREE, build_pointer_type (basetype), parmtypes);
-
-#if 0
- method_name = build_decl_overload (name, parmtypes, 1);
-
- /* constructors are up front. */
- fndecl = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0);
- if (TYPE_HAS_DESTRUCTOR (basetype))
- fndecl = DECL_CHAIN (fndecl);
-
- while (fndecl)
- {
- if (DECL_ASSEMBLER_NAME (fndecl) == method_name)
- {
- function = fndecl;
- if (protect)
- {
- if (TREE_PRIVATE (fndecl))
- {
- can_be_private =
- (basetype == current_class_type
- || is_friend (basetype, current_function_decl)
- || purpose_member (basetype, DECL_ACCESS (fndecl)));
- if (! can_be_private)
- goto found;
- }
- else if (TREE_PROTECTED (fndecl))
- {
- if (! can_be_protected)
- goto found;
- }
- }
- goto found_and_ok;
- }
- fndecl = DECL_CHAIN (fndecl);
- }
-#endif
-
- /* No exact conversion was found. See if an approximate
- one will do. */
- fndecl = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0);
- if (TYPE_HAS_DESTRUCTOR (basetype))
- fndecl = DECL_CHAIN (fndecl);
-
- {
- int saw_private = 0;
- int saw_protected = 0;
- struct candidate *candidates =
- (struct candidate *) alloca ((decl_list_length (fndecl)+1) * sizeof (struct candidate));
- struct candidate *cp = candidates;
-
- while (fndecl)
- {
- function = fndecl;
- cp->h_len = 2;
- cp->harshness = (struct harshness_code *)
- alloca (3 * sizeof (struct harshness_code));
-
- compute_conversion_costs (fndecl, parmlist, cp, 2);
- if ((cp->h.code & EVIL_CODE) == 0)
- {
- cp->u.field = fndecl;
- if (protect)
- {
- if (TREE_PRIVATE (fndecl))
- access = access_private;
- else if (TREE_PROTECTED (fndecl))
- access = access_protected;
- else
- access = access_public;
- }
- else
- access = access_public;
-
- if (access == access_private
- ? (basetype == current_class_type
- || is_friend (basetype, cp->function)
- || purpose_member (basetype, DECL_ACCESS (fndecl)))
- : access == access_protected
- ? (can_be_protected
- || purpose_member (basetype, DECL_ACCESS (fndecl)))
- : 1)
- {
- if (cp->h.code <= TRIVIAL_CODE)
- goto found_and_ok;
- cp++;
- }
- else
- {
- if (access == access_private)
- saw_private = 1;
- else
- saw_protected = 1;
- }
- }
- fndecl = DECL_CHAIN (fndecl);
- }
- if (cp - candidates)
- {
- /* Rank from worst to best. Then cp will point to best one.
- Private fields have their bits flipped. For unsigned
- numbers, this should make them look very large.
- If the best alternate has a (signed) negative value,
- then all we ever saw were private members. */
- if (cp - candidates > 1)
- qsort (candidates, /* char *base */
- cp - candidates, /* int nel */
- sizeof (struct candidate), /* int width */
- rank_for_overload); /* int (*compar)() */
-
- --cp;
- if (cp->h.code & EVIL_CODE)
- {
- if (msgp)
- *msgp = "ambiguous type conversion possible for `%s'";
- return error_mark_node;
- }
-
- function = cp->function;
- fndecl = cp->u.field;
- goto found_and_ok;
- }
- else if (msgp)
- {
- if (saw_private)
- if (saw_protected)
- *msgp = "only private and protected conversions apply";
- else
- *msgp = "only private conversions apply";
- else if (saw_protected)
- *msgp = "only protected conversions apply";
- else
- *msgp = "no appropriate conversion to type `%s'";
- }
- return error_mark_node;
- }
- /* NOTREACHED */
-
- found:
- if (access == access_private)
- if (! can_be_private)
- {
- if (msgp)
- *msgp = TREE_PRIVATE (fndecl)
- ? "conversion to type `%s' is private"
- : "conversion to type `%s' is from private base class";
- return error_mark_node;
- }
- if (access == access_protected)
- if (! can_be_protected)
- {
- if (msgp)
- *msgp = TREE_PRIVATE (fndecl)
- ? "conversion to type `%s' is protected"
- : "conversion to type `%s' is from protected base class";
- return error_mark_node;
- }
- function = fndecl;
- found_and_ok:
-
- /* It will convert, but we don't do anything about it yet. */
- if (msgp == 0)
- return NULL_TREE;
-
- fntype = TREE_TYPE (function);
- function = default_conversion (function);
-
- result = build_nt (CALL_EXPR, function,
- convert_arguments (NULL_TREE, TYPE_ARG_TYPES (fntype),
- parmlist, NULL_TREE, LOOKUP_NORMAL),
- NULL_TREE);
- TREE_TYPE (result) = TREE_TYPE (fntype);
- TREE_SIDE_EFFECTS (result) = 1;
- return result;
-}
-
/* Call this when we know (for any reason) that expr is not, in fact,
zero. This routine is like convert_pointer_to, but it pays
attention to which specific instance of what type we want to
convert to. This routine should eventually become
convert_to_pointer after all references to convert_to_pointer
are removed. */
+
tree
convert_pointer_to_real (binfo, expr)
tree binfo, expr;
@@ -1103,6 +554,9 @@ convert_pointer_to_real (binfo, expr)
tree ptr_type;
tree type, rval;
+ if (intype == error_mark_node)
+ return error_mark_node;
+
if (TREE_CODE (binfo) == TREE_VEC)
type = BINFO_TYPE (binfo);
else if (IS_AGGR_TYPE (binfo))
@@ -1115,13 +569,12 @@ convert_pointer_to_real (binfo, expr)
binfo = NULL_TREE;
}
- ptr_type = build_pointer_type (type);
+ ptr_type = cp_build_type_variant (type, TYPE_READONLY (TREE_TYPE (intype)),
+ TYPE_VOLATILE (TREE_TYPE (intype)));
+ ptr_type = build_pointer_type (ptr_type);
if (ptr_type == TYPE_MAIN_VARIANT (intype))
return expr;
- if (intype == error_mark_node)
- return error_mark_node;
-
my_friendly_assert (!integer_zerop (expr), 191);
if (TREE_CODE (type) == RECORD_TYPE
@@ -1159,6 +612,7 @@ convert_pointer_to_real (binfo, expr)
is more than one instance of that type in the expr, the conversion is
ambiguous. This routine should eventually go away, and all
callers should use convert_to_pointer_real. */
+
tree
convert_pointer_to (binfo, expr)
tree binfo, expr;
@@ -1174,23 +628,39 @@ convert_pointer_to (binfo, expr)
return convert_pointer_to_real (type, expr);
}
+/* C++ conversions, preference to static cast conversions. */
+
+tree
+cp_convert (type, expr)
+ tree type, expr;
+{
+ return ocp_convert (type, expr, CONV_OLD_CONVERT, LOOKUP_NORMAL);
+}
+
/* Conversion...
FLAGS indicates how we should behave. */
tree
-cp_convert (type, expr, convtype, flags)
+ocp_convert (type, expr, convtype, flags)
tree type, expr;
int convtype, flags;
{
register tree e = expr;
register enum tree_code code = TREE_CODE (type);
- if (TREE_CODE (e) == ERROR_MARK
- || TREE_CODE (TREE_TYPE (e)) == ERROR_MARK)
+ if (e == error_mark_node
+ || TREE_TYPE (e) == error_mark_node)
return error_mark_node;
- if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP))
+ if (TREE_READONLY_DECL_P (e))
+ e = decl_constant_value (e);
+
+ if (IS_AGGR_TYPE (type) && (convtype & CONV_FORCE_TEMP)
+ /* Some internal structures (vtable_entry_type, sigtbl_ptr_type)
+ don't go through finish_struct, so they don't have the synthesized
+ constructors. So don't force a temporary. */
+ && TYPE_HAS_CONSTRUCTOR (type))
/* We need a new temporary; don't take this shortcut. */;
else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
/* Trivial conversion: cv-qualifiers do not matter on rvalues. */
@@ -1203,7 +673,7 @@ cp_convert (type, expr, convtype, flags)
/* This is incorrect. A truncation can't be stripped this way.
Extensions will be stripped by the use of get_unwidened. */
if (TREE_CODE (e) == NOP_EXPR)
- return convert (type, TREE_OPERAND (e, 0));
+ return cp_convert (type, TREE_OPERAND (e, 0));
#endif
/* Just convert to the type of the member. */
@@ -1223,18 +693,15 @@ cp_convert (type, expr, convtype, flags)
if (TREE_CODE (e) == OFFSET_REF)
e = resolve_offset_ref (e);
- if (TREE_READONLY_DECL_P (e))
- e = decl_constant_value (e);
-
if (INTEGRAL_CODE_P (code))
{
tree intype = TREE_TYPE (e);
- enum tree_code form = TREE_CODE (intype);
- /* enum = enum, enum = int, enum = float are all errors. */
+ /* enum = enum, enum = int, enum = float, (enum)pointer are all
+ errors. */
if (flag_int_enum_equivalence == 0
&& TREE_CODE (type) == ENUMERAL_TYPE
- && ARITHMETIC_TYPE_P (intype)
- && ! (convtype & CONV_STATIC))
+ && ((ARITHMETIC_TYPE_P (intype) && ! (convtype & CONV_STATIC))
+ || (TREE_CODE (intype) == POINTER_TYPE)))
{
cp_pedwarn ("conversion from `%#T' to `%#T'", intype, type);
@@ -1254,13 +721,19 @@ cp_convert (type, expr, convtype, flags)
return error_mark_node;
}
if (code == BOOLEAN_TYPE)
- return truthvalue_conversion (e);
+ {
+ /* Common Ada/Pascal programmer's mistake. We always warn
+ about this since it is so bad. */
+ if (TREE_CODE (expr) == FUNCTION_DECL)
+ cp_warning ("the address of `%D', will always be `true'", expr);
+ return truthvalue_conversion (e);
+ }
return fold (convert_to_integer (type, e));
}
if (code == POINTER_TYPE || code == REFERENCE_TYPE
|| TYPE_PTRMEMFUNC_P (type))
return fold (cp_convert_to_pointer (type, e));
- if (code == REAL_TYPE)
+ if (code == REAL_TYPE || code == COMPLEX_TYPE)
{
if (IS_AGGR_TYPE (TREE_TYPE (e)))
{
@@ -1273,7 +746,10 @@ cp_convert (type, expr, convtype, flags)
cp_error ("`%#T' used where a floating point value was expected",
TREE_TYPE (e));
}
- return fold (convert_to_real (type, e));
+ if (code == REAL_TYPE)
+ return fold (convert_to_real (type, e));
+ else if (code == COMPLEX_TYPE)
+ return fold (convert_to_complex (type, e));
}
/* New C++ semantics: since assignment is now based on
@@ -1283,7 +759,6 @@ cp_convert (type, expr, convtype, flags)
{
tree dtype = TREE_TYPE (e);
tree ctor = NULL_TREE;
- tree conversion = NULL_TREE;
dtype = TYPE_MAIN_VARIANT (dtype);
@@ -1317,53 +792,24 @@ cp_convert (type, expr, convtype, flags)
There may be some ambiguity between using a constructor
vs. using a type conversion operator when both apply. */
- if (IS_AGGR_TYPE (dtype) && ! DERIVED_FROM_P (type, dtype)
- && TYPE_HAS_CONVERSION (dtype))
- conversion = build_type_conversion (CONVERT_EXPR, type, e, 1);
-
- if (conversion == error_mark_node)
- {
- if (flags & LOOKUP_COMPLAIN)
- error ("ambiguous pointer conversion");
- return conversion;
- }
-
- if (TYPE_HAS_CONSTRUCTOR (type))
- ctor = build_method_call (NULL_TREE, constructor_name_full (type),
- build_tree_list (NULL_TREE, e),
- TYPE_BINFO (type),
- (flags & LOOKUP_NORMAL) | LOOKUP_SPECULATIVELY
- | (convtype&CONV_NONCONVERTING ? 0 : LOOKUP_ONLYCONVERTING)
- | (conversion ? LOOKUP_NO_CONVERSION : 0));
-
- if (ctor == error_mark_node)
- {
- if (flags & LOOKUP_COMPLAIN)
- cp_error ("in conversion to type `%T'", type);
- if (flags & LOOKUP_SPECULATIVELY)
- return NULL_TREE;
- return error_mark_node;
- }
-
- if (conversion && ctor)
- {
- if (flags & LOOKUP_COMPLAIN)
- error ("both constructor and type conversion operator apply");
- if (flags & LOOKUP_SPECULATIVELY)
- return NULL_TREE;
- return error_mark_node;
- }
- else if (conversion)
- return conversion;
- else if (ctor)
- {
- ctor = build_cplus_new (type, ctor, 0);
- return ctor;
- }
+ ctor = e;
+
+ if ((flags & LOOKUP_ONLYCONVERTING)
+ && ! (IS_AGGR_TYPE (dtype) && DERIVED_FROM_P (type, dtype)))
+ /* For copy-initialization, first we create a temp of the proper type
+ with a user-defined conversion sequence, then we direct-initialize
+ the target with the temp (see [dcl.init]). */
+ ctor = build_user_type_conversion (type, ctor, flags);
+ if (ctor)
+ ctor = build_method_call (NULL_TREE, ctor_identifier,
+ build_expr_list (NULL_TREE, ctor),
+ TYPE_BINFO (type), flags);
+ if (ctor)
+ return build_cplus_new (type, ctor);
}
/* If TYPE or TREE_TYPE (E) is not on the permanent_obstack,
- then the it won't be hashed and hence compare as not equal,
+ then it won't be hashed and hence compare as not equal,
even when it is. */
if (code == ARRAY_TYPE
&& TREE_TYPE (TREE_TYPE (e)) == TREE_TYPE (type)
@@ -1382,18 +828,45 @@ cp_convert (type, expr, convtype, flags)
converted to type TYPE. The TREE_TYPE of the value
is always TYPE. This function implements all reasonable
conversions; callers should filter out those that are
- not permitted by the language being compiled. */
+ not permitted by the language being compiled.
+
+ Most of this routine is from build_reinterpret_cast.
+
+ The backend cannot call cp_convert (what was convert) because
+ conversions to/from basetypes may involve memory references
+ (vbases) and adding or subtracting small values (multiple
+ inheritance), but it calls convert from the constant folding code
+ on subtrees of already build trees after it has ripped them apart.
+
+ Also, if we ever support range variables, we'll probably also have to
+ do a little bit more work. */
tree
convert (type, expr)
tree type, expr;
{
- return cp_convert (type, expr, CONV_OLD_CONVERT, LOOKUP_NORMAL);
+ tree intype;
+
+ if (type == error_mark_node || expr == error_mark_node)
+ return error_mark_node;
+
+ intype = TREE_TYPE (expr);
+
+ if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype))
+ {
+ if (TREE_READONLY_DECL_P (expr))
+ expr = decl_constant_value (expr);
+ return fold (build1 (NOP_EXPR, type, expr));
+ }
+
+ return ocp_convert (type, expr, CONV_OLD_CONVERT,
+ LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
}
-/* Like convert, except permit conversions to take place which
+/* Like cp_convert, except permit conversions to take place which
are not normally allowed due to access restrictions
(such as conversion from sub-type to private super-type). */
+
tree
convert_force (type, expr, convtype)
tree type;
@@ -1420,46 +893,11 @@ convert_force (type, expr, convtype)
|| TYPE_PTRMEMFUNC_P (TREE_TYPE (e)))
&& TYPE_PTRMEMFUNC_P (type))
{
- /* compatible pointer to member functions. */
+ /* compatible pointer to member functions. */
return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), e, 1);
}
- return cp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
-}
-
-/* Subroutine of build_type_conversion. */
-static tree
-build_type_conversion_1 (xtype, basetype, expr, typename, for_sure)
- tree xtype, basetype;
- tree expr;
- tree typename;
- int for_sure;
-{
- tree rval;
- int flags;
-
- if (for_sure == 0)
- flags = LOOKUP_PROTECT|LOOKUP_ONLYCONVERTING;
- else
- flags = LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING;
-
- rval = build_method_call (expr, typename, NULL_TREE, NULL_TREE, flags);
- if (rval == error_mark_node)
- {
- if (for_sure == 0)
- return NULL_TREE;
- return error_mark_node;
- }
-
- if (IS_AGGR_TYPE (TREE_TYPE (rval)))
- return rval;
-
- if (warn_cast_qual
- && TREE_TYPE (xtype)
- && (TREE_READONLY (TREE_TYPE (TREE_TYPE (rval)))
- > TREE_READONLY (TREE_TYPE (xtype))))
- warning ("user-defined conversion casting away `const'");
- return convert (xtype, rval);
+ return ocp_convert (type, e, CONV_C_CAST|convtype, LOOKUP_NORMAL);
}
/* Convert an aggregate EXPR to type XTYPE. If a conversion
@@ -1487,58 +925,8 @@ build_type_conversion (code, xtype, expr, for_sure)
{
/* C++: check to see if we can convert this aggregate type
into the required type. */
- tree basetype;
- tree conv;
- tree winner = NULL_TREE;
-
- if (expr == error_mark_node)
- return error_mark_node;
-
- basetype = TREE_TYPE (expr);
- if (TREE_CODE (basetype) == REFERENCE_TYPE)
- basetype = TREE_TYPE (basetype);
-
- basetype = TYPE_MAIN_VARIANT (basetype);
- if (! TYPE_LANG_SPECIFIC (basetype) || ! TYPE_HAS_CONVERSION (basetype))
- return NULL_TREE;
-
- /* Do we have an exact match? */
- {
- tree typename = build_typename_overload (xtype);
- if (lookup_fnfields (TYPE_BINFO (basetype), typename, 0))
- return build_type_conversion_1 (xtype, basetype, expr, typename,
- for_sure);
- }
-
- /* Nope; try looking for others. */
- for (conv = lookup_conversions (basetype); conv; conv = TREE_CHAIN (conv))
- {
- if (winner && TREE_PURPOSE (winner) == TREE_PURPOSE (conv))
- continue;
-
- if (can_convert (xtype, TREE_VALUE (conv)))
- {
- if (winner)
- {
- if (for_sure)
- {
- cp_error ("ambiguous conversion from `%T' to `%T'", basetype,
- xtype);
- cp_error (" candidate conversions include `%T' and `%T'",
- TREE_VALUE (winner), TREE_VALUE (conv));
- }
- return NULL_TREE;
- }
- else
- winner = conv;
- }
- }
-
- if (winner)
- return build_type_conversion_1 (xtype, basetype, expr,
- TREE_PURPOSE (winner), for_sure);
-
- return NULL_TREE;
+ return build_user_type_conversion
+ (xtype, expr, for_sure ? LOOKUP_NORMAL : 0);
}
/* Convert the given EXPR to one of a group of types suitable for use in an
@@ -1568,7 +956,7 @@ build_expr_type_conversion (desires, expr, complain)
if ((desires & WANT_NULL) && TREE_CODE (expr) == INTEGER_CST
&& integer_zerop (expr))
return expr;
- /* else fall through... */
+ /* else fall through... */
case BOOLEAN_TYPE:
return (desires & WANT_INT) ? expr : NULL_TREE;
@@ -1587,6 +975,9 @@ build_expr_type_conversion (desires, expr, complain)
return NULL_TREE;
}
+ /* The code for conversions from class type is currently only used for
+ delete expressions. Other expressions are handled by build_new_op. */
+
if (! TYPE_HAS_CONVERSION (basetype))
return NULL_TREE;
@@ -1594,11 +985,12 @@ build_expr_type_conversion (desires, expr, complain)
{
int win = 0;
tree candidate;
+ tree cand = TREE_VALUE (conv);
- if (winner && TREE_PURPOSE (winner) == TREE_PURPOSE (conv))
+ if (winner && winner == cand)
continue;
- candidate = TREE_VALUE (conv);
+ candidate = TREE_TYPE (TREE_TYPE (cand));
if (TREE_CODE (candidate) == REFERENCE_TYPE)
candidate = TREE_TYPE (candidate);
@@ -1613,6 +1005,9 @@ build_expr_type_conversion (desires, expr, complain)
win = (desires & WANT_FLOAT); break;
case POINTER_TYPE:
win = (desires & WANT_POINTER); break;
+
+ default:
+ break;
}
if (win)
@@ -1623,153 +1018,29 @@ build_expr_type_conversion (desires, expr, complain)
{
cp_error ("ambiguous default type conversion from `%T'",
basetype);
- cp_error (" candidate conversions include `%T' and `%T'",
- TREE_VALUE (winner), TREE_VALUE (conv));
+ cp_error (" candidate conversions include `%D' and `%D'",
+ winner, cand);
}
return error_mark_node;
}
else
- winner = conv;
+ winner = cand;
}
}
if (winner)
- return build_type_conversion_1 (TREE_VALUE (winner), basetype, expr,
- TREE_PURPOSE (winner), 1);
-
- return NULL_TREE;
-}
-
-/* Must convert two aggregate types to non-aggregate type.
- Attempts to find a non-ambiguous, "best" type conversion.
-
- Return 1 on success, 0 on failure.
-
- @@ What are the real semantics of this supposed to be??? */
-int
-build_default_binary_type_conversion (code, arg1, arg2)
- enum tree_code code;
- tree *arg1, *arg2;
-{
- switch (code)
{
- case MULT_EXPR:
- case TRUNC_DIV_EXPR:
- case CEIL_DIV_EXPR:
- case FLOOR_DIV_EXPR:
- case ROUND_DIV_EXPR:
- case EXACT_DIV_EXPR:
- *arg1 = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, *arg1, 0);
- *arg2 = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, *arg2, 0);
- break;
-
- case TRUNC_MOD_EXPR:
- case FLOOR_MOD_EXPR:
- case LSHIFT_EXPR:
- case RSHIFT_EXPR:
- case BIT_AND_EXPR:
- case BIT_XOR_EXPR:
- case BIT_IOR_EXPR:
- *arg1 = build_expr_type_conversion (WANT_INT | WANT_ENUM, *arg1, 0);
- *arg2 = build_expr_type_conversion (WANT_INT | WANT_ENUM, *arg2, 0);
- break;
-
- case PLUS_EXPR:
- {
- tree a1, a2, p1, p2;
- int wins;
-
- a1 = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, *arg1, 0);
- a2 = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, *arg2, 0);
- p1 = build_expr_type_conversion (WANT_POINTER, *arg1, 0);
- p2 = build_expr_type_conversion (WANT_POINTER, *arg2, 0);
-
- wins = (a1 && a2) + (a1 && p2) + (p1 && a2);
-
- if (wins > 1)
- error ("ambiguous default type conversion for `operator +'");
-
- if (a1 && a2)
- *arg1 = a1, *arg2 = a2;
- else if (a1 && p2)
- *arg1 = a1, *arg2 = p2;
- else
- *arg1 = p1, *arg2 = a2;
- break;
- }
-
- case MINUS_EXPR:
- {
- tree a1, a2, p1, p2;
- int wins;
-
- a1 = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, *arg1, 0);
- a2 = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, *arg2, 0);
- p1 = build_expr_type_conversion (WANT_POINTER, *arg1, 0);
- p2 = build_expr_type_conversion (WANT_POINTER, *arg2, 0);
-
- wins = (a1 && a2) + (p1 && p2) + (p1 && a2);
-
- if (wins > 1)
- error ("ambiguous default type conversion for `operator -'");
-
- if (a1 && a2)
- *arg1 = a1, *arg2 = a2;
- else if (p1 && p2)
- *arg1 = p1, *arg2 = p2;
- else
- *arg1 = p1, *arg2 = a2;
- break;
- }
-
- case GT_EXPR:
- case LT_EXPR:
- case GE_EXPR:
- case LE_EXPR:
- case EQ_EXPR:
- case NE_EXPR:
- {
- tree a1, a2, p1, p2;
- int wins;
-
- a1 = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, *arg1, 0);
- a2 = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, *arg2, 0);
- p1 = build_expr_type_conversion (WANT_POINTER | WANT_NULL, *arg1, 0);
- p2 = build_expr_type_conversion (WANT_POINTER | WANT_NULL, *arg2, 0);
-
- wins = (a1 && a2) + (p1 && p2);
-
- if (wins > 1)
- cp_error ("ambiguous default type conversion for `%O'", code);
-
- if (a1 && a2)
- *arg1 = a1, *arg2 = a2;
- else
- *arg1 = p1, *arg2 = p2;
- break;
- }
-
- case TRUTH_ANDIF_EXPR:
- case TRUTH_ORIF_EXPR:
- *arg1 = convert (boolean_type_node, *arg1);
- *arg2 = convert (boolean_type_node, *arg2);
- break;
-
- default:
- *arg1 = NULL_TREE;
- *arg2 = NULL_TREE;
+ tree type = TREE_TYPE (TREE_TYPE (winner));
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+ return build_user_type_conversion (type, expr, LOOKUP_NORMAL);
}
- if (*arg1 == error_mark_node || *arg2 == error_mark_node)
- cp_error ("ambiguous default type conversion for `%O'", code);
-
- if (*arg1 && *arg2)
- return 1;
-
- return 0;
+ return NULL_TREE;
}
-/* Implements integral promotion (4.1) and float->double promotion. */
+/* Implements integral promotion (4.1) and float->double promotion. */
+
tree
type_promotes_to (type)
tree type;
@@ -1804,11 +1075,9 @@ type_promotes_to (type)
}
else if (C_PROMOTING_INTEGER_TYPE_P (type))
{
- /* Traditionally, unsignedness is preserved in default promotions.
- Otherwise, retain unsignedness if really not getting bigger. */
+ /* Retain unsignedness if really not getting bigger. */
if (TREE_UNSIGNED (type)
- && (flag_traditional
- || TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
+ && TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
type = unsigned_type_node;
else
type = integer_type_node;
@@ -1818,3 +1087,24 @@ type_promotes_to (type)
return cp_build_type_variant (type, constp, volatilep);
}
+
+
+/* The routines below this point are carefully written to conform to
+ the standard. They use the same terminology, and follow the rules
+ closely. Although they are used only in pt.c at the moment, they
+ should presumably be used everywhere in the future. */
+
+/* Attempt to perform qualification conversions on EXPR to convert it
+ to TYPE. Return the resulting expression, or error_mark_node if
+ the conversion was impossible. */
+
+tree
+perform_qualification_conversions (type, expr)
+ tree type;
+ tree expr;
+{
+ if (comp_target_types (type, TREE_TYPE (expr), 0) == 1)
+ return build1 (NOP_EXPR, type, expr);
+ else
+ return error_mark_node;
+}
diff --git a/contrib/gcc/cp/decl.c b/contrib/gcc/cp/decl.c
index 103cb0d..68f62ae 100644
--- a/contrib/gcc/cp/decl.c
+++ b/contrib/gcc/cp/decl.c
@@ -1,6 +1,6 @@
/* Process declarations and variables for C compiler.
- Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
- Hacked by Michael Tiemann (tiemann@cygnus.com)
+ Copyright (C) 1988, 92-97, 1998 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -27,17 +27,20 @@ Boston, MA 02111-1307, USA. */
/* ??? not all decl nodes are given the most useful possible
line numbers. For example, the CONST_DECLs for enum values. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "flags.h"
#include "cp-tree.h"
#include "decl.h"
#include "lex.h"
-#include <sys/types.h>
#include <signal.h>
#include "obstack.h"
+#include "defaults.h"
+#include "output.h"
+#include "except.h"
+#include "toplev.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
@@ -45,19 +48,25 @@ Boston, MA 02111-1307, USA. */
extern tree builtin_return_address_fndecl;
extern struct obstack permanent_obstack;
+extern struct obstack* saveable_obstack;
extern int current_class_depth;
-extern tree cleanups_this_call;
-
extern tree static_ctors, static_dtors;
+extern int static_labelno;
+
+extern tree current_namespace;
+extern tree global_namespace;
+
+extern void (*print_error_function) PROTO((char *));
+
/* Stack of places to restore the search obstack back to. */
/* Obstack used for remembering local class declarations (like
enums and static (const) members. */
#include "stack.h"
-static struct obstack decl_obstack;
+struct obstack decl_obstack;
static struct stack_level *decl_stack;
#ifndef CHAR_TYPE_SIZE
@@ -98,9 +107,9 @@ static struct stack_level *decl_stack;
#ifndef BOOL_TYPE_SIZE
#ifdef SLOW_BYTE_ACCESS
-#define BOOL_TYPE_SIZE ((SLOW_BYTE_ACCESS) ? (BITS_PER_WORD) : (BITS_PER_UNIT))
+#define BOOL_TYPE_SIZE ((SLOW_BYTE_ACCESS) ? (POINTER_SIZE) : (CHAR_TYPE_SIZE))
#else
-#define BOOL_TYPE_SIZE BITS_PER_UNIT
+#define BOOL_TYPE_SIZE CHAR_TYPE_SIZE
#endif
#endif
@@ -125,12 +134,54 @@ static struct stack_level *decl_stack;
static tree grokparms PROTO((tree, int));
static tree lookup_nested_type PROTO((tree, tree));
static char *redeclaration_error_message PROTO((tree, tree));
-static void grok_op_properties PROTO((tree, int, int));
-
-tree define_function
- PROTO((char *, tree, enum built_in_function, void (*)(), char *));
+static tree push_overloaded_decl PROTO((tree, int));
+
+static struct stack_level *push_decl_level PROTO((struct stack_level *,
+ struct obstack *));
+static void push_binding_level PROTO((struct binding_level *, int,
+ int));
+static void pop_binding_level PROTO((void));
+static void suspend_binding_level PROTO((void));
+static void resume_binding_level PROTO((struct binding_level *));
+static struct binding_level *make_binding_level PROTO((void));
+static int namespace_bindings_p PROTO((void));
+static void declare_namespace_level PROTO((void));
+static void signal_catch PROTO((int));
+static void storedecls PROTO((tree));
+static void storetags PROTO((tree));
+static void require_complete_types_for_parms PROTO((tree));
+static void push_overloaded_decl_1 PROTO((tree));
+static int ambi_op_p PROTO((tree));
+static int unary_op_p PROTO((tree));
+static tree store_bindings PROTO((tree, tree));
+static tree lookup_tag_reverse PROTO((tree, tree));
+static tree obscure_complex_init PROTO((tree, tree));
+static tree maybe_build_cleanup_1 PROTO((tree, tree));
+static tree lookup_name_real PROTO((tree, int, int, int));
+static void warn_extern_redeclared_static PROTO((tree, tree));
+static void grok_reference_init PROTO((tree, tree, tree));
+static tree grokfndecl PROTO((tree, tree, tree, tree, int,
+ enum overload_flags, tree,
+ tree, tree, int, int, int, int, int, int, tree));
+static tree grokvardecl PROTO((tree, tree, RID_BIT_TYPE *, int, int, tree));
+static tree lookup_tag PROTO((enum tree_code, tree,
+ struct binding_level *, int));
+static void set_identifier_type_value_with_scope
+ PROTO((tree, tree, struct binding_level *));
+static void set_identifier_local_value_with_scope
+ PROTO((tree, tree, struct binding_level *));
+static void record_builtin_type PROTO((enum rid, char *, tree));
+static void record_unknown_type PROTO((tree, char *));
+static int member_function_or_else PROTO((tree, tree, char *));
+static void bad_specifiers PROTO((tree, char *, int, int, int, int,
+ int));
+static void lang_print_error_function PROTO((char *));
+
+#if defined (DEBUG_CP_BINDING_LEVELS)
+static void indent PROTO((void));
+#endif
-/* a node which has tree code ERROR_MARK, and whose type is itself.
+/* A node which has tree code ERROR_MARK, and whose type is itself.
All erroneous expressions are replaced with this node. All functions
that accept nodes as arguments should avoid generating error messages
if this node is one of the arguments, since it is undesirable to get
@@ -168,24 +219,41 @@ tree float_type_node;
tree double_type_node;
tree long_double_type_node;
+tree complex_integer_type_node;
+tree complex_float_type_node;
+tree complex_double_type_node;
+tree complex_long_double_type_node;
+
tree intQI_type_node;
tree intHI_type_node;
tree intSI_type_node;
tree intDI_type_node;
+tree intTI_type_node;
tree unsigned_intQI_type_node;
tree unsigned_intHI_type_node;
tree unsigned_intSI_type_node;
tree unsigned_intDI_type_node;
+tree unsigned_intTI_type_node;
-/* a VOID_TYPE node, and the same, packaged in a TREE_LIST. */
+tree java_byte_type_node;
+tree java_short_type_node;
+tree java_int_type_node;
+tree java_long_type_node;
+tree java_float_type_node;
+tree java_double_type_node;
+tree java_char_type_node;
+tree java_boolean_type_node;
+
+/* A VOID_TYPE node, and the same, packaged in a TREE_LIST. */
tree void_type_node, void_list_node;
tree void_zero_node;
/* Nodes for types `void *' and `const void *'. */
-tree ptr_type_node, const_ptr_type_node;
+tree ptr_type_node;
+tree const_ptr_type_node;
/* Nodes for types `char *' and `const char *'. */
@@ -209,38 +277,33 @@ tree wchar_array_type_node;
/* The bool data type, and constants */
tree boolean_type_node, boolean_true_node, boolean_false_node;
-/* type `int ()' -- used for implicit declaration of functions. */
+/* Type `int ()' -- used for implicit declaration of functions. */
tree default_function_type;
-/* function types `double (double)' and `double (double, double)', etc. */
-
-tree double_ftype_double, double_ftype_double_double;
-tree int_ftype_int, long_ftype_long;
+/* Function types `double (double)' and `double (double, double)', etc. */
-/* Function type `void (void *, void *, int)' and similar ones. */
-
-tree void_ftype_ptr_ptr_int, int_ftype_ptr_ptr_int, void_ftype_ptr_int_int;
-
-/* Function type `char *(char *, char *)' and similar ones */
-tree string_ftype_ptr_ptr, int_ftype_string_string;
-
-/* Function type `size_t (const char *)' */
-tree sizet_ftype_string;
+static tree double_ftype_double, double_ftype_double_double;
+static tree int_ftype_int, long_ftype_long;
+static tree float_ftype_float;
+static tree ldouble_ftype_ldouble;
/* Function type `int (const void *, const void *, size_t)' */
-tree int_ftype_cptr_cptr_sizet;
+static tree int_ftype_cptr_cptr_sizet;
/* C++ extensions */
tree vtable_entry_type;
tree delta_type_node;
#if 0
-/* Old rtti stuff. */
+/* Old rtti stuff. */
tree __baselist_desc_type_node;
tree __i_desc_type_node, __m_desc_type_node;
tree __t_desc_array_type, __i_desc_array_type, __m_desc_array_type;
#endif
-tree __t_desc_type_node, __tp_desc_type_node;
+tree __t_desc_type_node;
+#if 0
+tree __tp_desc_type_node;
+#endif
tree __access_mode_type_node;
tree __bltn_desc_type_node, __user_desc_type_node, __class_desc_type_node;
tree __ptr_desc_type_node, __attr_desc_type_node, __func_desc_type_node;
@@ -252,21 +315,44 @@ tree __ptr_desc_array_type, __attr_dec_array_type, __func_desc_array_type;
tree __ptmf_desc_array_type, __ptmd_desc_array_type;
#endif
+/* Indicates that there is a type value in some namespace, although
+ that is not necessarily in scope at the moment. */
+
+static tree global_type_node;
+
tree class_star_type_node;
tree class_type_node, record_type_node, union_type_node, enum_type_node;
tree unknown_type_node;
tree opaque_type_node, signature_type_node;
tree sigtable_entry_type;
-tree maybe_gc_cleanup;
/* Array type `vtable_entry_type[]' */
tree vtbl_type_node;
+/* namespace std */
+tree std_node;
+int in_std = 0;
+
+/* Expect only namespace names now. */
+static int only_namespace_names;
+
/* In a destructor, the point at which all derived class destroying
has been done, just before any base class destroying will be done. */
tree dtor_label;
+/* In a destructor, the last insn emitted after the start of the
+ function and the parms. */
+
+static rtx last_dtor_insn;
+
+/* In a constructor, the last insn emitted after the start of the
+ function and the parms, the exception specification and any
+ function-try-block. The constructor initializers are emitted after
+ this insn. */
+
+static rtx last_parm_cleanup_insn;
+
/* In a constructor, the point at which we are ready to return
the pointer to the initialized object. */
@@ -284,7 +370,7 @@ extern rtx cleanup_label, return_label;
but due to being an addressable named return value, would up
on the stack, this variable holds the named return value's
original location. */
-rtx original_result_rtx;
+static rtx original_result_rtx;
/* Sequence of insns which represents base initialization. */
tree base_init_expr;
@@ -293,23 +379,40 @@ tree base_init_expr;
Identifiers for `this' in member functions and the auto-delete
parameter for destructors. */
tree this_identifier, in_charge_identifier;
-/* Used in pointer to member functions, in vtables, and in sigtables. */
+tree ctor_identifier, dtor_identifier;
+/* Used in pointer to member functions, in vtables, and in sigtables. */
tree pfn_identifier, index_identifier, delta_identifier, delta2_identifier;
tree pfn_or_delta2_identifier, tag_identifier;
-tree vb_off_identifier, vt_off_identifier;
+tree vt_off_identifier;
+
+struct named_label_list
+{
+ struct binding_level *binding_level;
+ tree names_in_scope;
+ tree label_decl;
+ char *filename_o_goto;
+ int lineno_o_goto;
+ struct named_label_list *next;
+};
/* A list (chain of TREE_LIST nodes) of named label uses.
The TREE_PURPOSE field is the list of variables defined
- the the label's scope defined at the point of use.
+ in the label's scope defined at the point of use.
The TREE_VALUE field is the LABEL_DECL used.
The TREE_TYPE field holds `current_binding_level' at the
point of the label's use.
+ BWAHAHAAHAHahhahahahaah. No, no, no, said the little chicken.
+
+ Look at the pretty struct named_label_list. See the pretty struct
+ with the pretty named fields that describe what they do. See the
+ pretty lack of gratuitous casts. Notice the code got a lot cleaner.
+
Used only for jumps to as-yet undefined labels, since
jumps to defined labels can have their validity checked
by stmt.c. */
-static tree named_label_uses;
+static struct named_label_list *named_label_uses = NULL;
/* A list of objects which have constructors or destructors
which reside in the global scope. The decl is stored in
@@ -325,17 +428,14 @@ tree static_aggregates;
tree integer_zero_node;
tree null_pointer_node;
-/* A node for the integer constants 1, 2, and 3. */
+/* The value for __null (NULL), either of type `void *' or, with -ansi,
+ an integer type of the same size. */
-tree integer_one_node, integer_two_node, integer_three_node;
+tree null_node;
-/* Nonzero if we have seen an invalid cross reference
- to a struct, union, or enum, but not yet printed the message. */
+/* A node for the integer constants 1, 2, and 3. */
-tree pending_invalid_xref;
-/* File and line to appear in the eventual error message. */
-char *pending_invalid_xref_file;
-int pending_invalid_xref_line;
+tree integer_one_node, integer_two_node, integer_three_node;
/* While defining an enum type, this is 1 plus the last enumerator
constant value. */
@@ -375,13 +475,6 @@ static tree named_labels;
static tree shadowed_labels;
-#if 0 /* Not needed by C++ */
-/* Nonzero when store_parm_decls is called indicates a varargs function.
- Value not meaningful after store_parm_decls. */
-
-static int c_function_varargs;
-#endif
-
/* The FUNCTION_DECL for the function currently being compiled,
or 0 if between functions. */
tree current_function_decl;
@@ -427,7 +520,7 @@ extern int flag_no_nonansi_builtin;
extern int flag_ansi;
/* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes)
- objects. */
+ objects. */
extern int flag_huge_objects;
/* Nonzero if we want to conserve space in the .o files. We do this
@@ -445,7 +538,7 @@ extern tree *current_lang_base, *current_lang_stack;
/* Set to 0 at beginning of a constructor, set to 1
if that function does an allocation before referencing its
instance variable. */
-int current_function_assigns_this;
+static int current_function_assigns_this;
int current_function_just_assigned_this;
/* Set to 0 at beginning of a function. Set non-zero when
@@ -453,14 +546,6 @@ int current_function_just_assigned_this;
if this flag is non-zero! */
int current_function_parms_stored;
-/* Current end of entries in the gc obstack for stack pointer variables. */
-
-int current_function_obstack_index;
-
-/* Flag saying whether we have used the obstack in this function or not. */
-
-int current_function_obstack_usage;
-
/* Flag used when debugging spew.c */
extern int spew_debug;
@@ -470,8 +555,14 @@ extern int spew_debug;
when entering another class scope (i.e. a cache miss). */
extern tree previous_class_values;
+/* A expression of value 0 with the same precision as a sizetype
+ node, but signed. */
+tree signed_size_zero_node;
+
/* Allocate a level of searching. */
+
+static
struct stack_level *
push_decl_level (stack, obstack)
struct stack_level *stack;
@@ -484,24 +575,22 @@ push_decl_level (stack, obstack)
}
/* For each binding contour we allocate a binding_level structure
- * which records the names defined in that contour.
- * Contours include:
- * 0) the global one
- * 1) one for each function definition,
- * where internal declarations of the parameters appear.
- * 2) one for each compound statement,
- * to record its declarations.
- *
- * The current meaning of a name can be found by searching the levels from
- * the current one out to the global one.
- *
- * Off to the side, may be the class_binding_level. This exists
- * only to catch class-local declarations. It is otherwise
- * nonexistent.
- *
- * Also there may be binding levels that catch cleanups that
- * must be run when exceptions occur.
- */
+ which records the names defined in that contour.
+ Contours include:
+ 0) the global one
+ 1) one for each function definition,
+ where internal declarations of the parameters appear.
+ 2) one for each compound statement,
+ to record its declarations.
+
+ The current meaning of a name can be found by searching the levels
+ from the current one out to the global one.
+
+ Off to the side, may be the class_binding_level. This exists only
+ to catch class-local declarations. It is otherwise nonexistent.
+
+ Also there may be binding levels that catch cleanups that must be
+ run when exceptions occur. */
/* Note that the information in the `names' component of the global contour
is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers. */
@@ -509,21 +598,27 @@ push_decl_level (stack, obstack)
struct binding_level
{
/* A chain of _DECL nodes for all variables, constants, functions,
- * and typedef types. These are in the reverse of the order supplied.
- */
+ and typedef types. These are in the reverse of the order
+ supplied. */
tree names;
- /* A list of structure, union and enum definitions,
- * for looking up tag names.
- * It is a chain of TREE_LIST nodes, each of whose TREE_PURPOSE is a name,
- * or NULL_TREE; and whose TREE_VALUE is a RECORD_TYPE, UNION_TYPE,
- * or ENUMERAL_TYPE node.
- *
- * C++: the TREE_VALUE nodes can be simple types for component_bindings.
- *
- */
+ /* A list of structure, union and enum definitions, for looking up
+ tag names.
+ It is a chain of TREE_LIST nodes, each of whose TREE_PURPOSE is a name,
+ or NULL_TREE; and whose TREE_VALUE is a RECORD_TYPE, UNION_TYPE,
+ or ENUMERAL_TYPE node.
+
+ C++: the TREE_VALUE nodes can be simple types for
+ component_bindings. */
tree tags;
+ /* A list of USING_DECL nodes. */
+ tree usings;
+
+ /* A list of used namespaces. PURPOSE is the namespace,
+ VALUE the common ancestor with this binding_level's namespace. */
+ tree using_directives;
+
/* For each level, a list of shadowed outer-level local definitions
to be restored when this level is popped.
Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and
@@ -554,7 +649,7 @@ struct binding_level
/* List of VAR_DECLS saved from a previous for statement.
These would be dead in ANSI-conforming code, but might
- be referenced in traditional code. */
+ be referenced in ARM-era code. */
tree dead_vars_from_for;
/* 1 for the level that holds the parameters of a function.
@@ -574,24 +669,19 @@ struct binding_level
unsigned more_cleanups_ok : 1;
unsigned have_cleanups : 1;
- /* Nonzero if we should accept any name as an identifier in
- this scope. This happens in some template definitions. */
- unsigned accept_any : 1;
-
- /* Nonzero if this level is for completing a template class definition
- inside a binding level that temporarily binds the parameters. This
- means that definitions here should not be popped off when unwinding
- this binding level. (Not actually implemented this way,
- unfortunately.) */
+ /* Nonzero if this level is for storing the decls for template
+ parameters and generic decls; these decls will be discarded and
+ replaced with a TEMPLATE_DECL. */
unsigned pseudo_global : 1;
/* This is set for a namespace binding level. */
unsigned namespace_p : 1;
- /* True if this level is that of a for-statement. */
+ /* True if this level is that of a for-statement where we need to
+ worry about ambiguous (ARM or ANSI) scope rules. */
unsigned is_for_scope : 1;
- /* One bit left for this word. */
+ /* Two bits left for this word. */
#if defined(DEBUG_CP_BINDING_LEVELS)
/* Binding depth at which this level began. */
@@ -687,7 +777,7 @@ pop_binding_level ()
if (global_binding_level)
{
- /* cannot pop a level, if there are none left to pop. */
+ /* Cannot pop a level, if there are none left to pop. */
if (current_binding_level == global_binding_level)
my_friendly_abort (123);
}
@@ -699,14 +789,10 @@ pop_binding_level ()
(is_class_level) ? "class" : "block",
current_binding_level, lineno);
if (is_class_level != (current_binding_level == class_binding_level))
-#if 0 /* XXX Don't abort when we're watching how things are being managed. */
- abort ();
-#else
- {
- indent ();
- fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n");
- }
-#endif
+ {
+ indent ();
+ fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n");
+ }
is_class_level = 0;
#endif /* defined(DEBUG_CP_BINDING_LEVELS) */
{
@@ -735,7 +821,7 @@ suspend_binding_level ()
if (global_binding_level)
{
- /* cannot suspend a level, if there are none left to suspend. */
+ /* Cannot suspend a level, if there are none left to suspend. */
if (current_binding_level == global_binding_level)
my_friendly_abort (123);
}
@@ -747,24 +833,14 @@ suspend_binding_level ()
(is_class_level) ? "class" : "block",
current_binding_level, lineno);
if (is_class_level != (current_binding_level == class_binding_level))
-#if 0 /* XXX Don't abort when we're watching how things are being managed. */
- abort ();
-#else
- {
- indent ();
- fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n");
- }
-#endif
+ {
+ indent ();
+ fprintf (stderr, "XXX is_class_level != (current_binding_level == class_binding_level)\n");
+ }
is_class_level = 0;
#endif /* defined(DEBUG_CP_BINDING_LEVELS) */
{
- register struct binding_level *level = current_binding_level;
current_binding_level = current_binding_level->level_chain;
-#if 0 /* defined(DEBUG_CP_BINDING_LEVELS) */
- if (level->binding_depth != binding_depth)
- abort ();
-#endif /* defined(DEBUG_CP_BINDING_LEVELS) */
-
class_binding_level = current_binding_level;
if (class_binding_level->parm_flag != 2)
class_binding_level = 0;
@@ -773,33 +849,15 @@ suspend_binding_level ()
}
}
-void
+static void
resume_binding_level (b)
struct binding_level *b;
{
- if (class_binding_level)
- {
-#if 1
- /* These are here because we cannot deal with shadows yet. */
- sorry ("cannot resume a namespace inside class");
- return;
-#else
- b->level_chain = class_binding_level;
- class_binding_level = (struct binding_level *)0;
-#endif
- }
- else
- {
-#if 1
- /* These are here because we cannot deal with shadows yet. */
- if (b->level_chain != current_binding_level)
- {
- sorry ("cannot resume a namespace inside a different namespace");
- return;
- }
-#endif
- b->level_chain = current_binding_level;
- }
+ /* Resuming binding levels is meant only for namespaces,
+ and those cannot nest into classes. */
+ my_friendly_assert(!class_binding_level, 386);
+ /* Also, resuming a non-directly nested namespace is a no-no. */
+ my_friendly_assert(b->level_chain == current_binding_level, 386);
current_binding_level = b;
#if defined(DEBUG_CP_BINDING_LEVELS)
b->binding_depth = binding_depth;
@@ -811,6 +869,16 @@ resume_binding_level (b)
#endif /* defined(DEBUG_CP_BINDING_LEVELS) */
}
+/* Create a new `struct binding_level'. */
+
+static
+struct binding_level *
+make_binding_level ()
+{
+ /* NOSTRICT */
+ return (struct binding_level *) xmalloc (sizeof (struct binding_level));
+}
+
/* Nonzero if we are currently in the global binding level. */
int
@@ -821,26 +889,20 @@ global_bindings_p ()
/* Nonzero if we are currently in a toplevel binding level. This
means either the global binding level or a namespace in a toplevel
- binding level. */
+ binding level.
+ Since there are no non-toplevel namespace levels, this really
+ means any namespace or pseudo-global level. */
int
toplevel_bindings_p ()
{
- struct binding_level *b = current_binding_level;
-
- while (1)
- {
- if (b == global_binding_level)
- return 1;
- if (! b->namespace_p)
- return 0;
- b=b->level_chain;
- }
+ return current_binding_level->namespace_p
+ || current_binding_level->pseudo_global;
}
/* Nonzero if this is a namespace scope. */
-int
+static int
namespace_bindings_p ()
{
return current_binding_level->namespace_p;
@@ -873,24 +935,12 @@ declare_parm_level ()
}
void
-declare_uninstantiated_type_level ()
-{
- current_binding_level->accept_any = 1;
-}
-
-int
-uninstantiated_type_level_p ()
-{
- return current_binding_level->accept_any;
-}
-
-void
declare_pseudo_global_level ()
{
current_binding_level->pseudo_global = 1;
}
-void
+static void
declare_namespace_level ()
{
current_binding_level->namespace_p = 1;
@@ -939,15 +989,15 @@ pushlevel (tag_transparent)
}
else
{
- /* Create a new `struct binding_level'. */
- newlevel = (struct binding_level *) xmalloc (sizeof (struct binding_level));
+ newlevel = make_binding_level ();
}
+
push_binding_level (newlevel, tag_transparent, keep_next_level_flag);
GNU_xref_start_scope ((HOST_WIDE_INT) newlevel);
keep_next_level_flag = 0;
}
-int
+void
note_level_for_for ()
{
current_binding_level->is_for_scope = 1;
@@ -1000,7 +1050,6 @@ poplevel (keep, reverse, functionbody)
Put it into forward order, just for cleanliness. */
tree decls;
int tmp = functionbody;
- int implicit_try_block = current_binding_level->parm_flag == 3;
int real_functionbody = current_binding_level->keep == 2
? ((functionbody = 0), tmp) : functionbody;
tree tags = functionbody >= 0 ? current_binding_level->tags : 0;
@@ -1012,41 +1061,11 @@ poplevel (keep, reverse, functionbody)
GNU_xref_end_scope ((HOST_WIDE_INT) current_binding_level,
(HOST_WIDE_INT) current_binding_level->level_chain,
current_binding_level->parm_flag,
- current_binding_level->keep,
- current_binding_level->tag_transparent);
+ current_binding_level->keep);
if (current_binding_level->keep == 1)
keep = 1;
- /* This warning is turned off because it causes warnings for
- declarations like `extern struct foo *x'. */
-#if 0
- /* Warn about incomplete structure types in this level. */
- for (link = tags; link; link = TREE_CHAIN (link))
- if (TYPE_SIZE (TREE_VALUE (link)) == NULL_TREE)
- {
- tree type = TREE_VALUE (link);
- char *errmsg;
- switch (TREE_CODE (type))
- {
- case RECORD_TYPE:
- errmsg = "`struct %s' incomplete in scope ending here";
- break;
- case UNION_TYPE:
- errmsg = "`union %s' incomplete in scope ending here";
- break;
- case ENUMERAL_TYPE:
- errmsg = "`enum %s' incomplete in scope ending here";
- break;
- }
- if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- error (errmsg, IDENTIFIER_POINTER (TYPE_NAME (type)));
- else
- /* If this type has a typedef-name, the TYPE_NAME is a TYPE_DECL. */
- error (errmsg, TYPE_NAME_STRING (type));
- }
-#endif /* 0 */
-
/* Get the decls in the order they were written.
Usually current_binding_level->names is in reverse order.
But parameter decls were previously put in forward order. */
@@ -1092,15 +1111,35 @@ poplevel (keep, reverse, functionbody)
block = make_node (BLOCK);
if (block != NULL_TREE)
{
- BLOCK_VARS (block) = decls;
- BLOCK_TYPE_TAGS (block) = tags;
- BLOCK_SUBBLOCKS (block) = subblocks;
- /* If we created the block earlier on, and we are just diddling it now,
- then it already should have a proper BLOCK_END_NOTE value associated
- with it, so avoid trashing that. Otherwise, for a new block, install
- a new BLOCK_END_NOTE value. */
- if (! block_previously_created)
- remember_end_note (block);
+ if (block_previously_created)
+ {
+ if (decls || tags || subblocks)
+ {
+ if (BLOCK_VARS (block) || BLOCK_TYPE_TAGS (block))
+ {
+ warning ("internal compiler error: debugging info corrupted");
+ }
+ BLOCK_VARS (block) = decls;
+ BLOCK_TYPE_TAGS (block) = tags;
+
+ /* We can have previous subblocks and new subblocks when
+ doing fixup_gotos with complex cleanups. We chain the new
+ subblocks onto the end of any pre-existing subblocks. */
+ BLOCK_SUBBLOCKS (block) = chainon (BLOCK_SUBBLOCKS (block),
+ subblocks);
+ }
+ /* If we created the block earlier on, and we are just
+ diddling it now, then it already should have a proper
+ BLOCK_END_NOTE value associated with it. */
+ }
+ else
+ {
+ BLOCK_VARS (block) = decls;
+ BLOCK_TYPE_TAGS (block) = tags;
+ BLOCK_SUBBLOCKS (block) = subblocks;
+ /* Otherwise, for a new block, install a new BLOCK_END_NOTE value. */
+ remember_end_note (block);
+ }
}
/* In each subblock, record that this is its superior. */
@@ -1111,26 +1150,38 @@ poplevel (keep, reverse, functionbody)
/* Clear out the meanings of the local variables of this level. */
- for (link = current_binding_level->dead_vars_from_for;
- link != NULL_TREE; link = TREE_CHAIN (link))
- {
- if (DECL_DEAD_FOR_LOCAL (link))
- {
- tree id = DECL_NAME (link);
- if (IDENTIFIER_LOCAL_VALUE (id) == link)
- IDENTIFIER_LOCAL_VALUE (id) = DECL_SHADOWED_FOR_VAR (link);
- }
- }
-
if (current_binding_level->is_for_scope && flag_new_for_scope == 1)
{
+ struct binding_level *outer = current_binding_level->level_chain;
for (link = decls; link; link = TREE_CHAIN (link))
{
if (TREE_CODE (link) == VAR_DECL)
DECL_DEAD_FOR_LOCAL (link) = 1;
+ else
+ IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE;
+ }
+
+ /* Save declarations made in a 'for' statement so we can support pre-ANSI
+ 'for' scoping semantics. */
+
+ for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
+ {
+ tree id = TREE_PURPOSE (link);
+ tree decl = IDENTIFIER_LOCAL_VALUE (id);
+
+ if (decl && DECL_DEAD_FOR_LOCAL (decl))
+ {
+ /* In this case keep the dead for-decl visible,
+ but remember what (if anything) it shadowed. */
+ DECL_SHADOWED_FOR_VAR (decl) = TREE_VALUE (link);
+ TREE_CHAIN (decl) = outer->dead_vars_from_for;
+ outer->dead_vars_from_for = decl;
+ }
+ else
+ IDENTIFIER_LOCAL_VALUE (id) = TREE_VALUE (link);
}
}
- else
+ else /* Not special for scope. */
{
for (link = decls; link; link = TREE_CHAIN (link))
{
@@ -1148,50 +1199,42 @@ poplevel (keep, reverse, functionbody)
IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE;
}
}
- }
- /* Restore all name-meanings of the outer levels
- that were shadowed by this level. */
+ /* Restore all name-meanings of the outer levels
+ that were shadowed by this level. */
- if (current_binding_level->is_for_scope && flag_new_for_scope == 1)
- {
- struct binding_level *outer = current_binding_level->level_chain;
- for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
+ for (link = current_binding_level->shadowed;
+ link; link = TREE_CHAIN (link))
+ IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
+
+ /* We first restore the regular decls and *then* the dead_vars_from_for
+ to handle this case:
+
+ int i; // i#1
+ {
+ for (int i; ; ) { ...} // i#2
+ int i; // i#3
+ } // we are here
+
+ In this case, we want remove the binding for i#3, restoring
+ that of i#2. Then we want to remove the binding for i#2,
+ and restore that of i#1. */
+
+ link = current_binding_level->dead_vars_from_for;
+ for (; link != NULL_TREE; link = TREE_CHAIN (link))
{
- tree id = TREE_PURPOSE (link);
- tree decl = IDENTIFIER_LOCAL_VALUE (id);
- if (DECL_DEAD_FOR_LOCAL (decl))
- DECL_SHADOWED_FOR_VAR (decl) = TREE_VALUE (link);
- else
- IDENTIFIER_LOCAL_VALUE (id) = TREE_VALUE (link);
+ tree id = DECL_NAME (link);
+ if (IDENTIFIER_LOCAL_VALUE (id) == link)
+ IDENTIFIER_LOCAL_VALUE (id) = DECL_SHADOWED_FOR_VAR (link);
}
- /* Save declarations made in a 'for' statement so we can support pre-ANSI
- 'for' scoping semantics. */
-
- /* We append the current names of for-variables to those from previous
- declarations, so that when we get around to do an poplevel
- on the OUTER level, we restore the any shadowed readl bindings.
- Note that the new names are put first on the combined list,
- so they get to be restored first. This is important if there are
- two for-loops using the same for-variable in the same block.
- The binding we really want restored is whatever binding was shadowed
- by the *first* for-variable, not the binding shadowed by the
- second for-variable (which would be the first for-variable). */
- outer->dead_vars_from_for
- = chainon (current_binding_level->names, outer->dead_vars_from_for);
+ for (link = current_binding_level->class_shadowed;
+ link; link = TREE_CHAIN (link))
+ IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
+ for (link = current_binding_level->type_shadowed;
+ link; link = TREE_CHAIN (link))
+ SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link));
}
- else
- {
- for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
- IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
- }
- for (link = current_binding_level->class_shadowed;
- link; link = TREE_CHAIN (link))
- IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
- for (link = current_binding_level->type_shadowed;
- link; link = TREE_CHAIN (link))
- IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
/* If the level being exited is the top level of a function,
check over all the labels. */
@@ -1238,12 +1281,12 @@ poplevel (keep, reverse, functionbody)
level_chain = current_binding_level->level_chain;
if (level_chain)
{
- tree labels;
- for (labels = named_label_uses; labels; labels = TREE_CHAIN (labels))
- if (TREE_TYPE (labels) == (tree)current_binding_level)
+ struct named_label_list *labels;
+ for (labels = named_label_uses; labels; labels = labels->next)
+ if (labels->binding_level == current_binding_level)
{
- TREE_TYPE (labels) = (tree)level_chain;
- TREE_PURPOSE (labels) = level_chain->names;
+ labels->binding_level = level_chain;
+ labels->names_in_scope = level_chain->names;
}
}
}
@@ -1277,11 +1320,6 @@ poplevel (keep, reverse, functionbody)
/* Take care of compiler's internal binding structures. */
if (tmp == 2)
{
-#if 0
- /* We did not call push_momentary for this
- binding contour, so there is nothing to pop. */
- pop_momentary ();
-#endif
expand_end_bindings (getdecls (), keep, 1);
/* Each and every BLOCK node created here in `poplevel' is important
(e.g. for proper debugging information) so if we created one
@@ -1299,31 +1337,6 @@ poplevel (keep, reverse, functionbody)
return block;
}
-/* Resume a binding level for a namespace. */
-void
-resume_level (b)
- struct binding_level *b;
-{
- tree decls, link;
-
- resume_binding_level (b);
-
- /* Resume the variable caches. */
- decls = current_binding_level->names;
-
- /* Restore the meanings of the local variables of this level. */
-
- for (link = decls; link; link = TREE_CHAIN (link))
- {
- if (DECL_NAME (link) != NULL_TREE)
- IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = link;
-
- /* If this is a TYPE_DECL, push it into the type value slot. */
- if (TREE_CODE (link) == TYPE_DECL)
- SET_IDENTIFIER_TYPE_VALUE (DECL_NAME (link), TREE_TYPE (link));
- }
-}
-
/* Delete the node BLOCK from the current binding level.
This is used for the block inside a stmt expr ({...})
so that the block can be reinserted where appropriate. */
@@ -1361,15 +1374,6 @@ insert_block (block)
= chainon (current_binding_level->blocks, block);
}
-/* Add BLOCK to the current list of blocks for this binding contour. */
-void
-add_block_current_level (block)
- tree block;
-{
- current_binding_level->blocks
- = chainon (current_binding_level->blocks, block);
-}
-
/* Set the BLOCK node for the innermost scope
(the one we are currently in). */
@@ -1381,6 +1385,7 @@ set_block (block)
}
/* Do a pushlevel for class declarations. */
+
void
pushlevel_class ()
{
@@ -1398,8 +1403,7 @@ pushlevel_class ()
}
else
{
- /* Create a new `struct binding_level'. */
- newlevel = (struct binding_level *) xmalloc (sizeof (struct binding_level));
+ newlevel = make_binding_level ();
}
#if defined(DEBUG_CP_BINDING_LEVELS)
@@ -1423,6 +1427,7 @@ pushlevel_class ()
/* ...and a poplevel for class declarations. FORCE is used to force
clearing out of CLASS_VALUEs after a class definition. */
+
tree
poplevel_class (force)
int force;
@@ -1449,22 +1454,24 @@ poplevel_class (force)
else
/* Remember to save what IDENTIFIER's were bound in this scope so we
can recover from cache misses. */
- previous_class_values = class_binding_level->class_shadowed;
+ {
+ previous_class_type = current_class_type;
+ previous_class_values = class_binding_level->class_shadowed;
+ }
for (shadowed = level->type_shadowed;
shadowed;
shadowed = TREE_CHAIN (shadowed))
- IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed)) = TREE_VALUE (shadowed);
+ SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (shadowed), TREE_VALUE (shadowed));
GNU_xref_end_scope ((HOST_WIDE_INT) class_binding_level,
(HOST_WIDE_INT) class_binding_level->level_chain,
class_binding_level->parm_flag,
- class_binding_level->keep,
- class_binding_level->tag_transparent);
+ class_binding_level->keep);
if (class_binding_level->parm_flag != 2)
class_binding_level = (struct binding_level *)0;
- /* Now, pop out of the the binding level which we created up in the
+ /* Now, pop out of the binding level which we created up in the
`pushlevel_class' routine. */
#if defined(DEBUG_CP_BINDING_LEVELS)
is_class_level = 1;
@@ -1476,8 +1483,8 @@ poplevel_class (force)
}
/* For debugging. */
-int no_print_functions = 0;
-int no_print_builtins = 0;
+static int no_print_functions = 0;
+static int no_print_builtins = 0;
void
print_binding_level (lvl)
@@ -1502,11 +1509,11 @@ print_binding_level (lvl)
/* We can probably fit 3 names to a line? */
for (t = lvl->names; t; t = TREE_CHAIN (t))
{
- if (no_print_functions && (TREE_CODE(t) == FUNCTION_DECL))
+ if (no_print_functions && (TREE_CODE (t) == FUNCTION_DECL))
continue;
if (no_print_builtins
- && (TREE_CODE(t) == TYPE_DECL)
- && (!strcmp(DECL_SOURCE_FILE(t),"<built-in>")))
+ && (TREE_CODE (t) == TYPE_DECL)
+ && (!strcmp (DECL_SOURCE_FILE (t),"<built-in>")))
continue;
/* Function decls tend to have longer names. */
@@ -1521,7 +1528,7 @@ print_binding_level (lvl)
i = len;
}
print_node_brief (stderr, "", t, 0);
- if (TREE_CODE (t) == ERROR_MARK)
+ if (t == error_mark_node)
break;
}
if (i)
@@ -1585,17 +1592,7 @@ print_binding_level (lvl)
fprintf (stderr, " type-shadowed:");
for (t = lvl->type_shadowed; t; t = TREE_CHAIN (t))
{
-#if 0
- fprintf (stderr, "\n\t");
- print_node_brief (stderr, "<", TREE_PURPOSE (t), 0);
- if (TREE_VALUE (t))
- print_node_brief (stderr, " ", TREE_VALUE (t), 0);
- else
- fprintf (stderr, " (none)");
- fprintf (stderr, ">");
-#else
fprintf (stderr, " %s ", IDENTIFIER_POINTER (TREE_PURPOSE (t)));
-#endif
}
fprintf (stderr, "\n");
}
@@ -1643,148 +1640,247 @@ print_binding_stack ()
print_binding_level (global_binding_level);
}
-extern char * first_global_object_name;
+/* Namespace binding access routines: The namespace_bindings field of
+ the identifier is polymorphic, with three possible values:
+ NULL_TREE, a list of CPLUS_BINDINGS, or any other tree_node
+ indicating the BINDING_VALUE of global_namespace. */
+
+/* Check whether the a binding for the name to scope is known.
+ Assumes that the bindings of the name are already a list
+ of bindings. Returns the binding found, or NULL_TREE. */
-/* Get a unique name for each call to this routine for unnamed namespaces.
- Mostly copied from get_file_function_name. */
static tree
-get_unique_name ()
+find_binding (name, scope)
+ tree name;
+ tree scope;
{
- static int temp_name_counter = 0;
- char *buf;
- register char *p;
-
- if (first_global_object_name)
- p = first_global_object_name;
- else if (main_input_filename)
- p = main_input_filename;
- else
- p = input_filename;
+ tree iter, prev = NULL_TREE;
-#define UNNAMED_NAMESPACE_FORMAT "__%s_%d"
+ scope = ORIGINAL_NAMESPACE (scope);
+
+ for (iter = IDENTIFIER_NAMESPACE_BINDINGS (name); iter;
+ iter = TREE_CHAIN (iter))
+ {
+ my_friendly_assert (TREE_CODE (iter) == CPLUS_BINDING, 374);
+ if (BINDING_SCOPE (iter) == scope)
+ {
+ /* Move binding found to the fron of the list, so
+ subsequent lookups will find it faster. */
+ if (prev)
+ {
+ TREE_CHAIN (prev) = TREE_CHAIN (iter);
+ TREE_CHAIN (iter) = IDENTIFIER_NAMESPACE_BINDINGS (name);
+ IDENTIFIER_NAMESPACE_BINDINGS (name) = iter;
+ }
+ return iter;
+ }
+ prev = iter;
+ }
+ return NULL_TREE;
+}
- buf = (char *) alloca (sizeof (UNNAMED_NAMESPACE_FORMAT) + strlen (p));
+/* Always returns a binding for name in scope. If the
+ namespace_bindings is not a list, convert it to one first.
+ If no binding is found, make a new one. */
- sprintf (buf, UNNAMED_NAMESPACE_FORMAT, p, temp_name_counter++);
+tree
+binding_for_name (name, scope)
+ tree name;
+ tree scope;
+{
+ tree b = IDENTIFIER_NAMESPACE_BINDINGS (name);
+ tree result;
- /* Don't need to pull weird characters out of global names. */
- if (p != first_global_object_name)
+ scope = ORIGINAL_NAMESPACE (scope);
+
+ if (b && TREE_CODE (b) != CPLUS_BINDING)
{
- for (p = buf+11; *p; p++)
- if (! ((*p >= '0' && *p <= '9')
-#if 0 /* we always want labels, which are valid C++ identifiers (+ `$') */
-#ifndef ASM_IDENTIFY_GCC /* this is required if `.' is invalid -- k. raeburn */
- || *p == '.'
-#endif
-#endif
-#ifndef NO_DOLLAR_IN_LABEL /* this for `$'; unlikely, but... -- kr */
- || *p == '$'
-#endif
-#ifndef NO_DOT_IN_LABEL /* this for `.'; unlikely, but... */
- || *p == '.'
-#endif
- || (*p >= 'A' && *p <= 'Z')
- || (*p >= 'a' && *p <= 'z')))
- *p = '_';
+ /* Get rid of optimization for global scope. */
+ IDENTIFIER_NAMESPACE_BINDINGS (name) = NULL_TREE;
+ BINDING_VALUE (binding_for_name (name, global_namespace)) = b;
+ b = IDENTIFIER_NAMESPACE_BINDINGS (name);
}
+ if (b && (result = find_binding (name, scope)))
+ return result;
+ /* Not found, make a new permanent one. */
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ result = make_node (CPLUS_BINDING);
+ TREE_CHAIN (result) = b;
+ IDENTIFIER_NAMESPACE_BINDINGS (name) = result;
+ BINDING_SCOPE (result) = scope;
+ BINDING_TYPE (result) = NULL_TREE;
+ BINDING_VALUE (result) = NULL_TREE;
+ pop_obstacks ();
+ return result;
+}
- return get_identifier (buf);
+/* Return the binding value for name in scope, considering that
+ namespace_binding may or may not be a list of CPLUS_BINDINGS. */
+
+tree
+namespace_binding (name, scope)
+ tree name;
+ tree scope;
+{
+ tree b = IDENTIFIER_NAMESPACE_BINDINGS (name);
+ if (b == NULL_TREE)
+ return NULL_TREE;
+ if (scope == NULL_TREE)
+ scope = global_namespace;
+ if (TREE_CODE (b) != CPLUS_BINDING)
+ return (scope == global_namespace) ? b : NULL_TREE;
+ name = find_binding (name,scope);
+ if (name == NULL_TREE)
+ return name;
+ return BINDING_VALUE (name);
}
-/* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we
- select a name that is unique to this compilation unit. */
+/* Set the binding value for name in scope. If modifying the binding
+ of global_namespace is attempted, try to optimize it. */
+
void
-push_namespace (name)
+set_namespace_binding (name, scope, val)
tree name;
+ tree scope;
+ tree val;
{
- extern tree current_namespace;
- tree old_id = get_namespace_id ();
- char *buf;
- tree d = make_node (NAMESPACE_DECL);
+ tree b;
- if (! name)
+ if (scope == NULL_TREE)
+ scope = global_namespace;
+
+ if (scope == global_namespace)
{
- /* Create a truly ugly name! */
- name = get_unique_name ();
+ b = IDENTIFIER_NAMESPACE_BINDINGS (name);
+ if (b == NULL_TREE || TREE_CODE (b) != CPLUS_BINDING)
+ {
+ IDENTIFIER_NAMESPACE_BINDINGS (name) = val;
+ return;
+ }
}
+ b = binding_for_name (name, scope);
+ BINDING_VALUE (b) = val;
+}
- DECL_NAME (d) = name;
- DECL_ASSEMBLER_NAME (d) = name;
- /* pushdecl wants to check the size of it to see if it is incomplete... */
- TREE_TYPE (d) = void_type_node;
- /* Mark them as external, so redeclaration_error_message doesn't think
- they are duplicates. */
- DECL_EXTERNAL (d) = 1;
- d = pushdecl (d);
+/* Push into the scope of the NAME namespace. If NAME is NULL_TREE, then we
+ select a name that is unique to this compilation unit. */
- if (NAMESPACE_LEVEL (d) == 0)
- {
- /* This is new for this compilation unit. */
- pushlevel (0);
- declare_namespace_level ();
- NAMESPACE_LEVEL (d) = (tree)current_binding_level;
+void
+push_namespace (name)
+ tree name;
+{
+ tree d;
+ int need_new = 1;
+ int implicit_use = 0;
+ int global = 0;
+ if (!global_namespace)
+ {
+ /* This must be ::. */
+ my_friendly_assert (name == get_identifier ("::"), 377);
+ global = 1;
+ }
+ else if (!name)
+ {
+ /* The name of anonymous namespace is unique for the translation
+ unit. */
+ static tree anon_name = NULL_TREE;
+ if (!anon_name)
+ anon_name = get_file_function_name ('N');
+ name = anon_name;
+ d = IDENTIFIER_NAMESPACE_VALUE (name);
+ if (d)
+ /* Reopening anonymous namespace. */
+ need_new = 0;
+ implicit_use = 1;
+ }
+ else if (current_namespace == global_namespace
+ && name == DECL_NAME (std_node))
+ {
+ in_std++;
+ return;
}
else
{
- resume_level ((struct binding_level*)NAMESPACE_LEVEL (d));
+ /* Check whether this is an extended namespace definition. */
+ d = IDENTIFIER_NAMESPACE_VALUE (name);
+ if (d != NULL_TREE && TREE_CODE (d) == NAMESPACE_DECL)
+ {
+ need_new = 0;
+ if (DECL_NAMESPACE_ALIAS (d))
+ {
+ cp_error ("namespace alias `%D' not allowed here, assuming `%D'",
+ d, DECL_NAMESPACE_ALIAS (d));
+ d = DECL_NAMESPACE_ALIAS (d);
+ }
+ }
+ }
+
+ if (need_new)
+ {
+ /* Make a new namespace, binding the name to it. */
+ d = build_lang_decl (NAMESPACE_DECL, name, void_type_node);
+ /* The global namespace is not pushed, and the global binding
+ level is set elsewhere. */
+ if (!global)
+ {
+ d = pushdecl (d);
+ pushlevel (0);
+ declare_namespace_level ();
+ NAMESPACE_LEVEL (d) = current_binding_level;
+ }
}
+ else
+ resume_binding_level (NAMESPACE_LEVEL (d));
- /* This code is just is bit old now... */
- current_namespace = tree_cons (NULL_TREE, name, current_namespace);
- buf = (char *) alloca (4 + (old_id ? IDENTIFIER_LENGTH (old_id) : 0)
- + IDENTIFIER_LENGTH (name));
- sprintf (buf, "%s%s", old_id ? IDENTIFIER_POINTER (old_id) : "",
- IDENTIFIER_POINTER (name));
- TREE_PURPOSE (current_namespace) = get_identifier (buf);
+ if (implicit_use)
+ do_using_directive (d);
+ /* Enter the name space. */
+ current_namespace = d;
}
/* Pop from the scope of the current namespace. */
+
void
pop_namespace ()
{
- extern tree current_namespace;
- tree decls, link;
- current_namespace = TREE_CHAIN (current_namespace);
-
- /* Just in case we get out of sync. */
- if (! namespace_bindings_p ())
- poplevel (0, 0, 0);
+ if (current_namespace == global_namespace)
+ {
+ my_friendly_assert (in_std>0, 980421);
+ in_std--;
+ return;
+ }
+ current_namespace = CP_DECL_CONTEXT (current_namespace);
+ /* The binding level is not popped, as it might be re-opened later. */
+ suspend_binding_level ();
+}
- decls = current_binding_level->names;
+/* Concatenate the binding levels of all namespaces. */
- /* Clear out the meanings of the local variables of this level. */
+void
+cat_namespace_levels()
+{
+ tree current;
+ tree last;
+ struct binding_level *b;
- for (link = decls; link; link = TREE_CHAIN (link))
+ last = NAMESPACE_LEVEL (global_namespace) -> names;
+ /* The nested namespaces appear in the names list of their ancestors. */
+ for (current = last; current; current = TREE_CHAIN (current))
{
- if (DECL_NAME (link) != NULL_TREE)
+ if (TREE_CODE (current) != NAMESPACE_DECL
+ || DECL_NAMESPACE_ALIAS (current))
+ continue;
+ if (!DECL_LANG_SPECIFIC (current))
{
- /* If the ident. was used or addressed via a local extern decl,
- don't forget that fact. */
- if (DECL_EXTERNAL (link))
- {
- if (TREE_USED (link))
- TREE_USED (DECL_ASSEMBLER_NAME (link)) = 1;
- if (TREE_ADDRESSABLE (link))
- TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1;
- }
- IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = NULL_TREE;
+ /* Hmm. std. */
+ my_friendly_assert (current == std_node, 393);
+ continue;
}
+ b = NAMESPACE_LEVEL (current);
+ while (TREE_CHAIN (last))
+ last = TREE_CHAIN (last);
+ TREE_CHAIN (last) = NAMESPACE_LEVEL (current) -> names;
}
-
- /* Restore all name-meanings of the outer levels
- that were shadowed by this level. */
-
- for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link))
- IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
- for (link = current_binding_level->class_shadowed;
- link; link = TREE_CHAIN (link))
- IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
- for (link = current_binding_level->type_shadowed;
- link; link = TREE_CHAIN (link))
- IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
-
- /* suspend a level. */
- suspend_binding_level ();
}
/* Subroutines for reverting temporarily to top-level for instantiation
@@ -1795,107 +1891,166 @@ pop_namespace ()
struct saved_scope {
struct binding_level *old_binding_level;
tree old_bindings;
+ tree old_namespace;
struct saved_scope *prev;
tree class_name, class_type, function_decl;
- tree base_init_list, member_init_list;
struct binding_level *class_bindings;
- tree previous_class_type;
tree *lang_base, *lang_stack, lang_name;
int lang_stacksize;
- tree named_labels;
+ int minimal_parse_mode;
+ tree last_function_parms;
+ tree template_parms;
+ HOST_WIDE_INT processing_template_decl;
+ tree previous_class_type, previous_class_values;
+ int processing_specialization;
+ int processing_explicit_instantiation;
};
static struct saved_scope *current_saved_scope;
-extern tree prev_class_type;
+
+/* A chain of the binding vecs created by store_bindings. We create a
+ whole bunch of these during compilation, on permanent_obstack, so we
+ can't just throw them away. */
+static tree free_binding_vecs;
+
+static tree
+store_bindings (names, old_bindings)
+ tree names, old_bindings;
+{
+ tree t;
+ for (t = names; t; t = TREE_CHAIN (t))
+ {
+ tree binding, t1, id;
+
+ if (TREE_CODE (t) == TREE_LIST)
+ id = TREE_PURPOSE (t);
+ else
+ id = DECL_NAME (t);
+
+ if (!id
+ || (!IDENTIFIER_LOCAL_VALUE (id)
+ && !IDENTIFIER_CLASS_VALUE (id)))
+ continue;
+
+ for (t1 = old_bindings; t1; t1 = TREE_CHAIN (t1))
+ if (TREE_VEC_ELT (t1, 0) == id)
+ goto skip_it;
+
+ if (free_binding_vecs)
+ {
+ binding = free_binding_vecs;
+ free_binding_vecs = TREE_CHAIN (free_binding_vecs);
+ }
+ else
+ binding = make_tree_vec (4);
+
+ if (id)
+ {
+ my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 135);
+ TREE_VEC_ELT (binding, 0) = id;
+ TREE_VEC_ELT (binding, 1) = REAL_IDENTIFIER_TYPE_VALUE (id);
+ TREE_VEC_ELT (binding, 2) = IDENTIFIER_LOCAL_VALUE (id);
+ TREE_VEC_ELT (binding, 3) = IDENTIFIER_CLASS_VALUE (id);
+ IDENTIFIER_LOCAL_VALUE (id) = NULL_TREE;
+ IDENTIFIER_CLASS_VALUE (id) = NULL_TREE;
+ }
+ TREE_CHAIN (binding) = old_bindings;
+ old_bindings = binding;
+ skip_it:
+ ;
+ }
+ return old_bindings;
+}
void
-push_to_top_level ()
+maybe_push_to_top_level (pseudo)
+ int pseudo;
{
extern int current_lang_stacksize;
- struct saved_scope *s =
- (struct saved_scope *) xmalloc (sizeof (struct saved_scope));
- struct binding_level *b = current_binding_level;
+ struct saved_scope *s
+ = (struct saved_scope *) xmalloc (sizeof (struct saved_scope));
+ struct binding_level *b = inner_binding_level;
tree old_bindings = NULL_TREE;
+ if (current_function_decl)
+ push_cp_function_context (NULL_TREE);
+
+ if (previous_class_type)
+ old_bindings = store_bindings (previous_class_values, old_bindings);
+
/* Have to include global_binding_level, because class-level decls
aren't listed anywhere useful. */
for (; b; b = b->level_chain)
{
tree t;
- if (b == global_binding_level)
- continue;
-
- for (t = b->names; t; t = TREE_CHAIN (t))
- {
- tree binding, t1, t2 = t;
- tree id = DECL_ASSEMBLER_NAME (t2);
+ /* Template IDs are inserted into the global level. If they were
+ inserted into namespace level, finish_file wouldn't find them
+ when doing pending instantiations. Therefore, don't stop at
+ namespace level, but continue until :: . */
+ if (b == global_binding_level || (pseudo && b->pseudo_global))
+ break;
- if (!id
- || (!IDENTIFIER_LOCAL_VALUE (id)
- && !IDENTIFIER_CLASS_VALUE (id)))
- continue;
+ old_bindings = store_bindings (b->names, old_bindings);
+ /* We also need to check class_shadowed to save class-level type
+ bindings, since pushclass doesn't fill in b->names. */
+ if (b->parm_flag == 2)
+ old_bindings = store_bindings (b->class_shadowed, old_bindings);
- for (t1 = old_bindings; t1; t1 = TREE_CHAIN (t1))
- if (TREE_VEC_ELT (t1, 0) == id)
- goto skip_it;
-
- binding = make_tree_vec (4);
- if (id)
- {
- my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 135);
- TREE_VEC_ELT (binding, 0) = id;
- TREE_VEC_ELT (binding, 1) = IDENTIFIER_TYPE_VALUE (id);
- TREE_VEC_ELT (binding, 2) = IDENTIFIER_LOCAL_VALUE (id);
- TREE_VEC_ELT (binding, 3) = IDENTIFIER_CLASS_VALUE (id);
- IDENTIFIER_LOCAL_VALUE (id) = NULL_TREE;
- IDENTIFIER_CLASS_VALUE (id) = NULL_TREE;
- }
- TREE_CHAIN (binding) = old_bindings;
- old_bindings = binding;
- skip_it:
- ;
- }
/* Unwind type-value slots back to top level. */
for (t = b->type_shadowed; t; t = TREE_CHAIN (t))
SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (t), TREE_VALUE (t));
}
- /* Clear out class-level bindings cache. */
- if (current_binding_level == global_binding_level
- && previous_class_type != NULL_TREE)
- {
- popclass (-1);
- previous_class_type = NULL_TREE;
- }
s->old_binding_level = current_binding_level;
- current_binding_level = global_binding_level;
+ current_binding_level = b;
+ s->old_namespace = current_namespace;
s->class_name = current_class_name;
s->class_type = current_class_type;
s->function_decl = current_function_decl;
- s->base_init_list = current_base_init_list;
- s->member_init_list = current_member_init_list;
s->class_bindings = class_binding_level;
- s->previous_class_type = previous_class_type;
s->lang_stack = current_lang_stack;
s->lang_base = current_lang_base;
s->lang_stacksize = current_lang_stacksize;
s->lang_name = current_lang_name;
- s->named_labels = named_labels;
+ s->minimal_parse_mode = minimal_parse_mode;
+ s->last_function_parms = last_function_parms;
+ s->template_parms = current_template_parms;
+ s->processing_template_decl = processing_template_decl;
+ s->previous_class_type = previous_class_type;
+ s->previous_class_values = previous_class_values;
+ s->processing_specialization = processing_specialization;
+ s->processing_explicit_instantiation = processing_explicit_instantiation;
+
current_class_name = current_class_type = NULL_TREE;
current_function_decl = NULL_TREE;
class_binding_level = (struct binding_level *)0;
- previous_class_type = NULL_TREE;
current_lang_stacksize = 10;
current_lang_stack = current_lang_base
= (tree *) xmalloc (current_lang_stacksize * sizeof (tree));
current_lang_name = lang_name_cplusplus;
strict_prototype = strict_prototypes_lang_cplusplus;
named_labels = NULL_TREE;
+ shadowed_labels = NULL_TREE;
+ minimal_parse_mode = 0;
+ previous_class_type = previous_class_values = NULL_TREE;
+ processing_specialization = 0;
+ processing_explicit_instantiation = 0;
+ current_template_parms = NULL_TREE;
+ processing_template_decl = 0;
+ current_namespace = global_namespace;
s->prev = current_saved_scope;
s->old_bindings = old_bindings;
current_saved_scope = s;
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+}
+
+void
+push_to_top_level ()
+{
+ maybe_push_to_top_level (0);
}
void
@@ -1905,28 +2060,36 @@ pop_from_top_level ()
struct saved_scope *s = current_saved_scope;
tree t;
+ /* Clear out class-level bindings cache. */
if (previous_class_type)
- previous_class_type = NULL_TREE;
+ {
+ popclass (-1);
+ previous_class_type = NULL_TREE;
+ }
+
+ pop_obstacks ();
current_binding_level = s->old_binding_level;
current_saved_scope = s->prev;
- for (t = s->old_bindings; t; t = TREE_CHAIN (t))
+ for (t = s->old_bindings; t; )
{
+ tree save = t;
tree id = TREE_VEC_ELT (t, 0);
if (id)
{
- IDENTIFIER_TYPE_VALUE (id) = TREE_VEC_ELT (t, 1);
+ SET_IDENTIFIER_TYPE_VALUE (id, TREE_VEC_ELT (t, 1));
IDENTIFIER_LOCAL_VALUE (id) = TREE_VEC_ELT (t, 2);
IDENTIFIER_CLASS_VALUE (id) = TREE_VEC_ELT (t, 3);
}
+ t = TREE_CHAIN (t);
+ TREE_CHAIN (save) = free_binding_vecs;
+ free_binding_vecs = save;
}
+ current_namespace = s->old_namespace;
current_class_name = s->class_name;
current_class_type = s->class_type;
- current_base_init_list = s->base_init_list;
- current_member_init_list = s->member_init_list;
current_function_decl = s->function_decl;
class_binding_level = s->class_bindings;
- previous_class_type = s->previous_class_type;
free (current_lang_base);
current_lang_base = s->lang_base;
current_lang_stack = s->lang_stack;
@@ -1936,9 +2099,19 @@ pop_from_top_level ()
strict_prototype = strict_prototypes_lang_cplusplus;
else if (current_lang_name == lang_name_c)
strict_prototype = strict_prototypes_lang_c;
- named_labels = s->named_labels;
+ minimal_parse_mode = s->minimal_parse_mode;
+ last_function_parms = s->last_function_parms;
+ current_template_parms = s->template_parms;
+ processing_template_decl = s->processing_template_decl;
+ previous_class_type = s->previous_class_type;
+ previous_class_values = s->previous_class_values;
+ processing_specialization = s->processing_specialization;
+ processing_explicit_instantiation = s->processing_explicit_instantiation;
free (s);
+
+ if (current_function_decl)
+ pop_cp_function_context (NULL_TREE);
}
/* Push a definition of struct, union or enum tag "name".
@@ -1948,7 +2121,7 @@ pop_from_top_level ()
Note that the definition may really be just a forward reference.
In that case, the TYPE_SIZE will be a NULL_TREE.
- C++ gratuitously puts all these tags in the name space. */
+ C++ gratuitously puts all these tags in the name space. */
/* When setting the IDENTIFIER_TYPE_VALUE field of an identifier ID,
record the shadowed value for this binding contour. TYPE is
@@ -1960,16 +2133,25 @@ set_identifier_type_value_with_scope (id, type, b)
tree type;
struct binding_level *b;
{
- if (b != global_binding_level)
+ if (!b->namespace_p)
{
- tree old_type_value = IDENTIFIER_TYPE_VALUE (id);
+ /* Shadow the marker, not the real thing, so that the marker
+ gets restored later. */
+ tree old_type_value = REAL_IDENTIFIER_TYPE_VALUE (id);
b->type_shadowed
= tree_cons (id, old_type_value, b->type_shadowed);
}
+ else
+ {
+ tree binding = binding_for_name (id, current_namespace);
+ BINDING_TYPE (binding) = type;
+ /* Store marker instead of real type. */
+ type = global_type_node;
+ }
SET_IDENTIFIER_TYPE_VALUE (id, type);
}
-/* As set_identifier_type_value_with_scope, but using inner_binding_level. */
+/* As set_identifier_type_value_with_scope, but using inner_binding_level. */
void
set_identifier_type_value (id, type)
@@ -1979,59 +2161,50 @@ set_identifier_type_value (id, type)
set_identifier_type_value_with_scope (id, type, inner_binding_level);
}
-/* Subroutine "set_nested_typename" builds the nested-typename of
- the type decl in question. (Argument CLASSNAME can actually be
- a function as well, if that's the smallest containing scope.) */
-
static void
-set_nested_typename (decl, classname, name, type)
- tree decl, classname, name, type;
+set_identifier_local_value_with_scope (id, val, b)
+ tree id, val;
+ struct binding_level *b;
{
- char *buf;
- my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 136);
+ tree oldlocal;
+ my_friendly_assert (! b->namespace_p, 980716);
- /* No need to do this for anonymous names, since they're unique. */
- if (ANON_AGGRNAME_P (name))
- {
- DECL_NESTED_TYPENAME (decl) = name;
- return;
- }
+ oldlocal = IDENTIFIER_LOCAL_VALUE (id);
+ b->shadowed = tree_cons (id, oldlocal, b->shadowed);
+ IDENTIFIER_LOCAL_VALUE (id) = val;
+}
- if (classname == NULL_TREE)
- classname = get_identifier ("");
+void
+set_identifier_local_value (id, val)
+ tree id, val;
+{
+ set_identifier_local_value_with_scope (id, val, current_binding_level);
+}
- my_friendly_assert (TREE_CODE (classname) == IDENTIFIER_NODE, 137);
- my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 138);
- buf = (char *) alloca (4 + IDENTIFIER_LENGTH (classname)
- + IDENTIFIER_LENGTH (name));
- sprintf (buf, "%s::%s", IDENTIFIER_POINTER (classname),
- IDENTIFIER_POINTER (name));
- DECL_NESTED_TYPENAME (decl) = get_identifier (buf);
- TREE_MANGLED (DECL_NESTED_TYPENAME (decl)) = 1;
+/* Return the type associated with id. */
- /* Create an extra decl so that the nested name will have a type value
- where appropriate. */
- {
- tree nested, type_decl;
- nested = DECL_NESTED_TYPENAME (decl);
- type_decl = build_decl (TYPE_DECL, nested, type);
- DECL_NESTED_TYPENAME (type_decl) = nested;
- SET_DECL_ARTIFICIAL (type_decl);
- /* Mark the TYPE_DECL node created just above as a gratuitous one so that
- dwarfout.c will know not to generate a TAG_typedef DIE for it, and
- sdbout.c won't try to output a .def for "::foo". */
- DECL_IGNORED_P (type_decl) = 1;
-
- /* Remove this when local classes are fixed. */
- SET_IDENTIFIER_TYPE_VALUE (nested, type);
-
- pushdecl_nonclass_level (type_decl);
- }
+tree
+identifier_type_value (id)
+ tree id;
+{
+ /* There is no type with that name, anywhere. */
+ if (REAL_IDENTIFIER_TYPE_VALUE (id) == NULL_TREE)
+ return NULL_TREE;
+ /* This is not the type marker, but the real thing. */
+ if (REAL_IDENTIFIER_TYPE_VALUE (id) != global_type_node)
+ return REAL_IDENTIFIER_TYPE_VALUE (id);
+ /* Have to search for it. It must be on the global level, now.
+ Ask lookup_name not to return non-types. */
+ id = lookup_name_real (id, 2, 1, 0);
+ if (id)
+ return TREE_TYPE (id);
+ return NULL_TREE;
}
/* Pop off extraneous binding levels left over due to syntax errors.
We don't pop past namespaces, as they might be valid. */
+
void
pop_everything ()
{
@@ -2050,41 +2223,10 @@ pop_everything ()
#endif
}
-#if 0 /* not yet, should get fixed properly later */
-/* Create a TYPE_DECL node with the correct DECL_ASSEMBLER_NAME.
- Other routines shouldn't use build_decl directly; they'll produce
- incorrect results with `-g' unless they duplicate this code.
-
- This is currently needed mainly for dbxout.c, but we can make
- use of it in method.c later as well. */
-tree
-make_type_decl (name, type)
- tree name, type;
-{
- tree decl, id;
- decl = build_decl (TYPE_DECL, name, type);
- if (TYPE_NAME (type) == name)
- /* Class/union/enum definition, or a redundant typedef for same. */
- {
- id = get_identifier (build_overload_name (type, 1, 1));
- DECL_ASSEMBLER_NAME (decl) = id;
- }
- else if (TYPE_NAME (type) != NULL_TREE)
- /* Explicit typedef, or implicit typedef for template expansion. */
- DECL_ASSEMBLER_NAME (decl) = DECL_ASSEMBLER_NAME (TYPE_NAME (type));
- else
- {
- /* XXX: Typedef for unnamed struct; some other situations.
- TYPE_NAME is null; what's right here? */
- }
- return decl;
-}
-#endif
-
/* Push a tag name NAME for struct/class/union/enum type TYPE.
- Normally put into into the inner-most non-tag-transparent scope,
+ Normally put it into the inner-most non-tag-transparent scope,
but if GLOBALIZE is true, put it in the inner-most non-class scope.
- The latter is needed for implicit declarations. */
+ The latter is needed for implicit declarations. */
void
pushtag (name, type, globalize)
@@ -2108,117 +2250,124 @@ pushtag (name, type, globalize)
if (name)
{
context = type ? TYPE_CONTEXT (type) : NULL_TREE;
- if (! context && ! globalize)
- context = current_scope ();
+ if (! context)
+ {
+ tree cs = current_scope ();
+
+ if (! globalize)
+ context = cs;
+ else if (cs != NULL_TREE
+ && TREE_CODE_CLASS (TREE_CODE (cs)) == 't')
+ /* When declaring a friend class of a local class, we want
+ to inject the newly named class into the scope
+ containing the local class, not the namespace scope. */
+ context = hack_decl_function_context (get_type_decl (cs));
+ }
if (context)
c_decl = TREE_CODE (context) == FUNCTION_DECL
? context : TYPE_MAIN_DECL (context);
-#if 0
- /* Record the identifier as the type's name if it has none. */
- if (TYPE_NAME (type) == NULL_TREE)
- TYPE_NAME (type) = name;
-#endif
-
+ if (!context)
+ context = current_namespace;
+
/* Do C++ gratuitous typedefing. */
if (IDENTIFIER_TYPE_VALUE (name) != type)
{
- register tree d;
- int newdecl = 0;
-
- if (b->parm_flag != 2
- || TYPE_SIZE (current_class_type) != NULL_TREE)
- {
- d = lookup_nested_type (type, c_decl);
+ register tree d = NULL_TREE;
+ int newdecl = 0, in_class = 0;
- if (d == NULL_TREE)
- {
- newdecl = 1;
-#if 0 /* not yet, should get fixed properly later */
- d = make_type_decl (name, type);
-#else
- d = build_decl (TYPE_DECL, name, type);
- DECL_ASSEMBLER_NAME (d) = current_namespace_id (DECL_ASSEMBLER_NAME (d));
-#endif
- SET_DECL_ARTIFICIAL (d);
-#ifdef DWARF_DEBUGGING_INFO
- if (write_symbols == DWARF_DEBUG)
- {
- /* Mark the TYPE_DECL node we created just above as an
- gratuitous one. We need to do this so that dwarfout.c
- will understand that it is not supposed to output a
- TAG_typedef DIE for it. */
- DECL_IGNORED_P (d) = 1;
- }
-#endif /* DWARF_DEBUGGING_INFO */
- set_identifier_type_value_with_scope (name, type, b);
- }
- else
- d = TYPE_NAME (d);
-
- TYPE_NAME (type) = d;
-
- /* If it is anonymous, then we are called from pushdecl,
- and we don't want to infinitely recurse. */
- if (! ANON_AGGRNAME_P (name))
- {
- if (b->parm_flag == 2)
- d = pushdecl_class_level (d);
- else
- d = pushdecl_with_scope (d, b);
- }
- }
+ if ((b->pseudo_global && b->level_chain->parm_flag == 2)
+ || b->parm_flag == 2)
+ in_class = 1;
else
+ d = lookup_nested_type (type, c_decl);
+
+ if (d == NULL_TREE)
{
- /* Make nested declarations go into class-level scope. */
newdecl = 1;
d = build_decl (TYPE_DECL, name, type);
+ if (current_lang_name == lang_name_java)
+ TYPE_FOR_JAVA (type) = 1;
SET_DECL_ARTIFICIAL (d);
-#ifdef DWARF_DEBUGGING_INFO
- if (write_symbols == DWARF_DEBUG)
+ if (! in_class)
+ set_identifier_type_value_with_scope (name, type, b);
+ }
+ else
+ d = TYPE_MAIN_DECL (d);
+
+ TYPE_NAME (type) = d;
+ DECL_CONTEXT (d) = FROB_CONTEXT (context);
+
+ if (processing_template_parmlist)
+ /* You can't declare a new template type in a template
+ parameter list. But, you can declare a non-template
+ type:
+
+ template <class A*> struct S;
+
+ is a forward-declaration of `A'. */
+ ;
+ else if (IS_AGGR_TYPE (type)
+ && (/* If !GLOBALIZE then we are looking at a
+ definition. It may not be a primary template.
+ (For example, in:
+
+ template <class T>
+ struct S1 { class S2 {}; }
+
+ we have to push_template_decl for S2.) */
+ (processing_template_decl && !globalize)
+ /* If we are declaring a friend template class, we
+ will have GLOBALIZE set, since something like:
+
+ template <class T>
+ struct S1 {
+ template <class U>
+ friend class S2;
+ };
+
+ declares S2 to be at global scope. */
+ || (processing_template_decl >
+ template_class_depth (current_class_type))))
+ {
+ d = push_template_decl_real (d, globalize);
+ /* If the current binding level is the binding level for
+ the template parameters (see the comment in
+ begin_template_parm_list) and the enclosing level is
+ a class scope, and we're not looking at a friend,
+ push the declaration of the member class into the
+ class scope. In the friend case, push_template_decl
+ will already have put the friend into global scope,
+ if appropriate. */
+ if (!globalize && b->pseudo_global &&
+ b->level_chain->parm_flag == 2)
{
- /* Mark the TYPE_DECL node we created just above as an
- gratuitous one. We need to do this so that dwarfout.c
- will understand that it is not supposed to output a
- TAG_typedef DIE for it. */
- DECL_IGNORED_P (d) = 1;
+ pushdecl_with_scope (CLASSTYPE_TI_TEMPLATE (type),
+ b->level_chain);
+ /* Put this tag on the list of tags for the class,
+ since that won't happen below because B is not
+ the class binding level, but is instead the
+ pseudo-global level. */
+ b->level_chain->tags =
+ saveable_tree_cons (name, type, b->level_chain->tags);
+ TREE_NONLOCAL_FLAG (type) = 1;
+ if (TYPE_SIZE (current_class_type) == NULL_TREE)
+ CLASSTYPE_TAGS (current_class_type) = b->level_chain->tags;
}
-#endif /* DWARF_DEBUGGING_INFO */
+ }
- TYPE_MAIN_DECL (type) = d;
+ if (b->parm_flag == 2)
+ d = pushdecl_class_level (d);
+ else
+ d = pushdecl_with_scope (d, b);
- /* Make sure we're in this type's scope when we push the
- decl for a template, otherwise class_binding_level will
- be NULL and we'll end up dying inside of
- push_class_level_binding. */
- if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
- pushclass (type, 0);
- d = pushdecl_class_level (d);
- if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
- popclass (0);
- }
if (newdecl)
{
- if (write_symbols != DWARF_DEBUG)
- {
- if (ANON_AGGRNAME_P (name))
- DECL_IGNORED_P (d) = 1;
- }
+ if (ANON_AGGRNAME_P (name))
+ DECL_IGNORED_P (d) = 1;
- if (context == NULL_TREE)
- /* Non-nested class. */
- set_nested_typename (d, NULL_TREE, name, type);
- else if (context && TREE_CODE (context) == FUNCTION_DECL)
- /* Function-nested class. */
- set_nested_typename (d, DECL_ASSEMBLER_NAME (c_decl),
- name, type);
- else /* if (context && IS_AGGR_TYPE (context)) */
- /* Class-nested class. */
- set_nested_typename (d, DECL_NESTED_TYPENAME (c_decl),
- name, type);
-
- DECL_CONTEXT (d) = context;
TYPE_CONTEXT (type) = DECL_CONTEXT (d);
+ DECL_ASSEMBLER_NAME (d) = DECL_NAME (d);
DECL_ASSEMBLER_NAME (d)
= get_identifier (build_overload_name (type, 1, 1));
}
@@ -2244,20 +2393,18 @@ pushtag (name, type, globalize)
convenient place to record the "scope start" address for
the tagged type. */
-#if 0 /* not yet, should get fixed properly later */
- tree d = make_type_decl (NULL_TREE, type);
-#else
tree d = build_decl (TYPE_DECL, NULL_TREE, type);
-#endif
TYPE_STUB_DECL (type) = pushdecl_with_scope (d, b);
}
}
/* Counter used to create anonymous type names. */
+
static int anon_cnt = 0;
/* Return an IDENTIFIER which can be used as a name for
anonymous structs and unions. */
+
tree
make_anon_name ()
{
@@ -2269,6 +2416,7 @@ make_anon_name ()
/* Clear the TREE_PURPOSE slot of tags which have anonymous typenames.
This keeps dbxout from getting confused. */
+
void
clear_anon_tags ()
{
@@ -2303,6 +2451,7 @@ clear_anon_tags ()
For C++, we must compare the parameter list so that `int' can match
`int&' in a parameter position, but `int&' is not confused with
`const int&'. */
+
int
decls_match (newdecl, olddecl)
tree newdecl, olddecl;
@@ -2317,6 +2466,11 @@ decls_match (newdecl, olddecl)
tree p1 = TYPE_ARG_TYPES (f1);
tree p2 = TYPE_ARG_TYPES (f2);
+ if (DECL_REAL_CONTEXT (newdecl) != DECL_REAL_CONTEXT (olddecl)
+ && ! (DECL_LANGUAGE (newdecl) == lang_c
+ && DECL_LANGUAGE (olddecl) == lang_c))
+ return 0;
+
/* When we parse a static member function definition,
we put together a FUNCTION_DECL which thinks its type
is METHOD_TYPE. Change that to FUNCTION_TYPE, and
@@ -2364,33 +2518,15 @@ decls_match (newdecl, olddecl)
else if (TREE_CODE (newdecl) == TEMPLATE_DECL
&& TREE_CODE (olddecl) == TEMPLATE_DECL)
{
- tree newargs = DECL_TEMPLATE_PARMS (newdecl);
- tree oldargs = DECL_TEMPLATE_PARMS (olddecl);
- int i, len = TREE_VEC_LENGTH (newargs);
-
- if (TREE_VEC_LENGTH (oldargs) != len)
- return 0;
-
- for (i = 0; i < len; i++)
- {
- tree newarg = TREE_VALUE (TREE_VEC_ELT (newargs, i));
- tree oldarg = TREE_VALUE (TREE_VEC_ELT (oldargs, i));
- if (TREE_CODE (newarg) != TREE_CODE (oldarg))
- return 0;
- else if (TREE_CODE (newarg) == TYPE_DECL)
- /* continue */;
- else if (! comptypes (TREE_TYPE (newarg), TREE_TYPE (oldarg), 1))
- return 0;
- }
-
- if (DECL_TEMPLATE_IS_CLASS (newdecl)
- != DECL_TEMPLATE_IS_CLASS (olddecl))
- types_match = 0;
- else if (DECL_TEMPLATE_IS_CLASS (newdecl))
- types_match = 1;
- else
- types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl),
- DECL_TEMPLATE_RESULT (newdecl));
+ if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
+ DECL_TEMPLATE_PARMS (olddecl)))
+ return 0;
+
+ if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
+ types_match = 1;
+ else
+ types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl),
+ DECL_TEMPLATE_RESULT (newdecl));
}
else
{
@@ -2400,8 +2536,20 @@ decls_match (newdecl, olddecl)
types_match = TREE_TYPE (newdecl) == NULL_TREE;
else if (TREE_TYPE (newdecl) == NULL_TREE)
types_match = 0;
+ /* Qualifiers must match, and they may be present on either, the type
+ or the decl. */
+ else if ((TREE_READONLY (newdecl)
+ || TYPE_READONLY (TREE_TYPE (newdecl)))
+ == (TREE_READONLY (olddecl)
+ || TYPE_READONLY (TREE_TYPE (olddecl)))
+ && (TREE_THIS_VOLATILE (newdecl)
+ || TYPE_VOLATILE (TREE_TYPE (newdecl)))
+ == (TREE_THIS_VOLATILE (olddecl)
+ || TYPE_VOLATILE (TREE_TYPE (olddecl))))
+ types_match = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (newdecl)),
+ TYPE_MAIN_VARIANT (TREE_TYPE (olddecl)), 1);
else
- types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 1);
+ types_match = 0;
}
return types_match;
@@ -2414,9 +2562,6 @@ decls_match (newdecl, olddecl)
Note that this does not apply to the C++ case of declaring
a variable `extern const' and then later `const'.
- Don't complain if -traditional, since traditional compilers
- don't complain.
-
Don't complain about built-in functions, since they are beyond
the user's control. */
@@ -2431,8 +2576,7 @@ warn_extern_redeclared_static (newdecl, olddecl)
static char *implicit_extern_static_warning
= "`%D' was declared implicitly `extern' and later `static'";
- if (flag_traditional
- || TREE_CODE (newdecl) == TYPE_DECL)
+ if (TREE_CODE (newdecl) == TYPE_DECL)
return;
name = DECL_ASSEMBLER_NAME (newdecl);
@@ -2464,46 +2608,36 @@ warn_extern_redeclared_static (newdecl, olddecl)
int
duplicate_decls (newdecl, olddecl)
- register tree newdecl, olddecl;
+ tree newdecl, olddecl;
{
extern struct obstack permanent_obstack;
unsigned olddecl_uid = DECL_UID (olddecl);
int olddecl_friend = 0, types_match = 0;
- int new_defines_function;
- tree previous_c_decl = NULL_TREE;
+ int new_defines_function = 0;
- if (TREE_CODE_CLASS (TREE_CODE (olddecl)) == 'd')
- DECL_MACHINE_ATTRIBUTES (newdecl) = DECL_MACHINE_ATTRIBUTES (olddecl);
+ if (newdecl == olddecl)
+ return 1;
types_match = decls_match (newdecl, olddecl);
- if (TREE_CODE (olddecl) != TREE_LIST)
- olddecl_friend = DECL_LANG_SPECIFIC (olddecl) && DECL_FRIEND_P (olddecl);
-
/* If either the type of the new decl or the type of the old decl is an
error_mark_node, then that implies that we have already issued an
error (earlier) for some bogus type specification, and in that case,
it is rather pointless to harass the user with yet more error message
- about the same declaration, so well just pretent the types match here. */
- if ((TREE_TYPE (newdecl)
- && TREE_CODE (TREE_TYPE (newdecl)) == ERROR_MARK)
- || (TREE_TYPE (olddecl)
- && TREE_CODE (TREE_TYPE (olddecl)) == ERROR_MARK))
+ about the same declaration, so just pretend the types match here. */
+ if (TREE_TYPE (newdecl) == error_mark_node
+ || TREE_TYPE (olddecl) == error_mark_node)
types_match = 1;
-
- if (flag_traditional && TREE_CODE (newdecl) == FUNCTION_DECL
- && IDENTIFIER_IMPLICIT_DECL (DECL_ASSEMBLER_NAME (newdecl)) == olddecl)
- /* If -traditional, avoid error for redeclaring fcn
- after implicit decl. */
- ;
- else if (TREE_CODE (olddecl) == FUNCTION_DECL
- && DECL_ARTIFICIAL (olddecl)
- && (DECL_BUILT_IN (olddecl) || DECL_BUILT_IN_NONANSI (olddecl)))
+
+ /* Check for redeclaration and other discrepancies. */
+ if (TREE_CODE (olddecl) == FUNCTION_DECL
+ && DECL_ARTIFICIAL (olddecl)
+ && (DECL_BUILT_IN (olddecl) || DECL_BUILT_IN_NONANSI (olddecl)))
{
/* If you declare a built-in or predefined function name as static,
the old definition is overridden, but optionally warn this was a
bad choice of name. Ditto for overloads. */
- if (! DECL_PUBLIC (newdecl)
+ if (! TREE_PUBLIC (newdecl)
|| (TREE_CODE (newdecl) == FUNCTION_DECL
&& DECL_LANGUAGE (newdecl) != DECL_LANGUAGE (olddecl)))
{
@@ -2539,14 +2673,30 @@ duplicate_decls (newdecl, olddecl)
}
else if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
{
+ if ((TREE_CODE (olddecl) == TYPE_DECL && DECL_ARTIFICIAL (olddecl)
+ && TREE_CODE (newdecl) != TYPE_DECL
+ && ! (TREE_CODE (newdecl) == TEMPLATE_DECL
+ && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL))
+ || (TREE_CODE (newdecl) == TYPE_DECL && DECL_ARTIFICIAL (newdecl)
+ && TREE_CODE (olddecl) != TYPE_DECL
+ && ! (TREE_CODE (olddecl) == TEMPLATE_DECL
+ && (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl))
+ == TYPE_DECL))))
+ {
+ /* We do nothing special here, because C++ does such nasty
+ things with TYPE_DECLs. Instead, just let the TYPE_DECL
+ get shadowed, and know that if we need to find a TYPE_DECL
+ for a given name, we can look in the IDENTIFIER_TYPE_VALUE
+ slot of the identifier. */
+ return 0;
+ }
+
if ((TREE_CODE (newdecl) == FUNCTION_DECL
- && TREE_CODE (olddecl) == TEMPLATE_DECL
- && ! DECL_TEMPLATE_IS_CLASS (olddecl))
+ && DECL_FUNCTION_TEMPLATE_P (olddecl))
|| (TREE_CODE (olddecl) == FUNCTION_DECL
- && TREE_CODE (newdecl) == TEMPLATE_DECL
- && ! DECL_TEMPLATE_IS_CLASS (newdecl)))
+ && DECL_FUNCTION_TEMPLATE_P (newdecl)))
return 0;
-
+
cp_error ("`%#D' redeclared as different kind of symbol", newdecl);
if (TREE_CODE (olddecl) == TREE_LIST)
olddecl = TREE_VALUE (olddecl);
@@ -2563,14 +2713,24 @@ duplicate_decls (newdecl, olddecl)
{
/* The name of a class template may not be declared to refer to
any other template, class, function, object, namespace, value,
- or type in the same scope. */
- if (DECL_TEMPLATE_IS_CLASS (olddecl)
- || DECL_TEMPLATE_IS_CLASS (newdecl))
+ or type in the same scope. */
+ if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == TYPE_DECL
+ || TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
{
cp_error ("declaration of template `%#D'", newdecl);
cp_error_at ("conflicts with previous declaration `%#D'",
olddecl);
}
+ else if (TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)) == FUNCTION_DECL
+ && TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
+ && compparms (TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl))),
+ TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))), 3)
+ && comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
+ DECL_TEMPLATE_PARMS (olddecl)))
+ {
+ cp_error ("new declaration `%#D'", newdecl);
+ cp_error_at ("ambiguates old declaration `%#D'", olddecl);
+ }
return 0;
}
if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -2600,6 +2760,37 @@ duplicate_decls (newdecl, olddecl)
cp_error_at ("previous declaration as `%#D'", olddecl);
}
}
+ else if (TREE_CODE (newdecl) == FUNCTION_DECL
+ && ((DECL_TEMPLATE_SPECIALIZATION (olddecl)
+ && (!DECL_TEMPLATE_INFO (newdecl)
+ || (DECL_TI_TEMPLATE (newdecl)
+ != DECL_TI_TEMPLATE (olddecl))))
+ || (DECL_TEMPLATE_SPECIALIZATION (newdecl)
+ && (!DECL_TEMPLATE_INFO (olddecl)
+ || (DECL_TI_TEMPLATE (olddecl)
+ != DECL_TI_TEMPLATE (newdecl))))))
+ /* It's OK to have a template specialization and a non-template
+ with the same type, or to have specializations of two
+ different templates with the same type. Note that if one is a
+ specialization, and the other is an instantiation of the same
+ template, that we do not exit at this point. That situation
+ can occur if we instantiate a template class, and then
+ specialize one of its methods. This situation is legal, but
+ the declarations must be merged in the usual way. */
+ return 0;
+ else if (TREE_CODE (newdecl) == FUNCTION_DECL
+ && ((DECL_TEMPLATE_INSTANTIATION (olddecl)
+ && !DECL_USE_TEMPLATE (newdecl))
+ || (DECL_TEMPLATE_INSTANTIATION (newdecl)
+ && !DECL_USE_TEMPLATE (olddecl))))
+ /* One of the declarations is a template instantiation, and the
+ other is not a template at all. That's OK. */
+ return 0;
+ else if (TREE_CODE (newdecl) == NAMESPACE_DECL
+ && DECL_NAMESPACE_ALIAS (newdecl)
+ && DECL_NAMESPACE_ALIAS (newdecl) == DECL_NAMESPACE_ALIAS (olddecl))
+ /* Redeclaration of namespace alias, ignore it. */
+ return 1;
else
{
char *errmsg = redeclaration_error_message (newdecl, olddecl);
@@ -2608,7 +2799,7 @@ duplicate_decls (newdecl, olddecl)
cp_error (errmsg, newdecl);
if (DECL_NAME (olddecl) != NULL_TREE)
cp_error_at ((DECL_INITIAL (olddecl)
- && current_binding_level == global_binding_level)
+ && namespace_bindings_p ())
? "`%#D' previously defined here"
: "`%#D' previously declared here", olddecl);
}
@@ -2638,7 +2829,9 @@ duplicate_decls (newdecl, olddecl)
}
}
- if (TREE_CODE (olddecl) == FUNCTION_DECL)
+ if (DECL_LANG_SPECIFIC (olddecl) && DECL_USE_TEMPLATE (olddecl))
+ ;
+ else if (TREE_CODE (olddecl) == FUNCTION_DECL)
{
tree t1 = TYPE_ARG_TYPES (TREE_TYPE (olddecl));
tree t2 = TYPE_ARG_TYPES (TREE_TYPE (newdecl));
@@ -2666,32 +2859,18 @@ duplicate_decls (newdecl, olddecl)
{
cp_error ("default argument given for parameter %d of `%#D'",
i, newdecl);
- cp_error_at ("conflicts with previous specification in `%#D'",
+ cp_error_at ("after previous specification in `%#D'",
olddecl);
}
}
- if (DECL_THIS_INLINE (newdecl) && ! DECL_THIS_INLINE (olddecl))
+ if (DECL_THIS_INLINE (newdecl) && ! DECL_THIS_INLINE (olddecl)
+ && TREE_ADDRESSABLE (olddecl) && warn_inline)
{
-#if 0 /* I think this will be correct, but it's really annoying. We should
- fix the compiler to find vtables by indirection so it isn't
- necessary. (jason 8/25/95) */
- if (DECL_VINDEX (olddecl) && ! DECL_ABSTRACT_VIRTUAL_P (olddecl))
- {
- cp_pedwarn ("virtual function `%#D' redeclared inline",
- newdecl);
- cp_pedwarn_at ("previous non-inline declaration here",
- olddecl);
- }
- else
-#endif
- if (TREE_ADDRESSABLE (olddecl))
- {
- cp_pedwarn ("`%#D' was used before it was declared inline",
- newdecl);
- cp_pedwarn_at ("previous non-inline declaration here",
- olddecl);
- }
+ cp_warning ("`%#D' was used before it was declared inline",
+ newdecl);
+ cp_warning_at ("previous non-inline declaration here",
+ olddecl);
}
}
/* These bits are logically part of the type for non-functions. */
@@ -2707,7 +2886,7 @@ duplicate_decls (newdecl, olddecl)
warn about it. */
warn_extern_redeclared_static (newdecl, olddecl);
- /* We have committed to returning 1 at this point. */
+ /* We have committed to returning 1 at this point. */
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
/* Now that functions must hold information normally held
@@ -2720,15 +2899,28 @@ duplicate_decls (newdecl, olddecl)
DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
if (DECL_CLASS_CONTEXT (olddecl))
DECL_CLASS_CONTEXT (newdecl) = DECL_CLASS_CONTEXT (olddecl);
- if (DECL_CHAIN (newdecl) == NULL_TREE)
- DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl);
- if (DECL_NEXT_METHOD (newdecl) == NULL_TREE)
- DECL_NEXT_METHOD (newdecl) = DECL_NEXT_METHOD (olddecl);
if (DECL_PENDING_INLINE_INFO (newdecl) == (struct pending_inline *)0)
DECL_PENDING_INLINE_INFO (newdecl) = DECL_PENDING_INLINE_INFO (olddecl);
DECL_STATIC_CONSTRUCTOR (newdecl) |= DECL_STATIC_CONSTRUCTOR (olddecl);
DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
DECL_ABSTRACT_VIRTUAL_P (newdecl) |= DECL_ABSTRACT_VIRTUAL_P (olddecl);
+ DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl);
+ DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl);
+ new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE;
+
+ /* Optionally warn about more than one declaration for the same
+ name, but don't warn about a function declaration followed by a
+ definition. */
+ if (warn_redundant_decls && ! DECL_ARTIFICIAL (olddecl)
+ && !(new_defines_function && DECL_INITIAL (olddecl) == NULL_TREE)
+ /* Don't warn about extern decl followed by definition. */
+ && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl))
+ /* Don't warn about friends, let add_friend take care of it. */
+ && ! DECL_FRIEND_P (newdecl))
+ {
+ cp_warning ("redundant redeclaration of `%D' in same scope", newdecl);
+ cp_warning_at ("previous declaration of `%D'", olddecl);
+ }
}
/* Deal with C++: must preserve virtual function table size. */
@@ -2737,8 +2929,6 @@ duplicate_decls (newdecl, olddecl)
register tree newtype = TREE_TYPE (newdecl);
register tree oldtype = TREE_TYPE (olddecl);
- DECL_NESTED_TYPENAME (newdecl) = DECL_NESTED_TYPENAME (olddecl);
-
if (newtype != error_mark_node && oldtype != error_mark_node
&& TYPE_LANG_SPECIFIC (newtype) && TYPE_LANG_SPECIFIC (oldtype))
{
@@ -2746,39 +2936,30 @@ duplicate_decls (newdecl, olddecl)
CLASSTYPE_FRIEND_CLASSES (newtype)
= CLASSTYPE_FRIEND_CLASSES (oldtype);
}
-#if 0
- /* why assert here? Just because debugging information is
- messed up? (mrs) */
- /* it happens on something like:
- typedef struct Thing {
- Thing();
- int x;
- } Thing;
- */
- my_friendly_assert (DECL_IGNORED_P (olddecl) == DECL_IGNORED_P (newdecl),
- 139);
-#endif
- }
-
- /* Special handling ensues if new decl is a function definition. */
- new_defines_function = (TREE_CODE (newdecl) == FUNCTION_DECL
- && DECL_INITIAL (newdecl) != NULL_TREE);
-
- /* Optionally warn about more than one declaration for the same name,
- but don't warn about a function declaration followed by a definition. */
- if (warn_redundant_decls
- && ! DECL_ARTIFICIAL (olddecl)
- && !(new_defines_function && DECL_INITIAL (olddecl) == NULL_TREE)
- /* Don't warn about extern decl followed by (tentative) definition. */
- && !(DECL_EXTERNAL (olddecl) && ! DECL_EXTERNAL (newdecl)))
- {
- cp_warning ("redundant redeclaration of `%D' in same scope", newdecl);
- cp_warning_at ("previous declaration of `%D'", olddecl);
}
/* Copy all the DECL_... slots specified in the new decl
except for any that we copy here from the old type. */
+ DECL_MACHINE_ATTRIBUTES (newdecl)
+ = merge_machine_decl_attributes (olddecl, newdecl);
+ if (TREE_CODE (newdecl) == TEMPLATE_DECL)
+ {
+ if (DECL_INITIAL (DECL_TEMPLATE_RESULT (olddecl)) == NULL_TREE)
+ {
+ if (! duplicate_decls (DECL_TEMPLATE_RESULT (newdecl),
+ DECL_TEMPLATE_RESULT (olddecl)))
+ cp_error ("invalid redeclaration of %D", newdecl);
+ TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl));
+ DECL_TEMPLATE_PARMS (olddecl) = DECL_TEMPLATE_PARMS (newdecl);
+ DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl);
+ }
+ DECL_TEMPLATE_SPECIALIZATIONS (newdecl)
+ = DECL_TEMPLATE_SPECIALIZATIONS (olddecl);
+
+ return 1;
+ }
+
if (types_match)
{
/* Automatically handles default parameters. */
@@ -2805,32 +2986,35 @@ duplicate_decls (newdecl, olddecl)
&& (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl))
!= TYPE_RAISES_EXCEPTIONS (TREE_TYPE (olddecl))))
{
- tree ctype = NULL_TREE;
- ctype = DECL_CLASS_CONTEXT (newdecl);
TREE_TYPE (newdecl) = build_exception_variant (newtype,
TYPE_RAISES_EXCEPTIONS (TREE_TYPE (newdecl)));
TREE_TYPE (olddecl) = build_exception_variant (newtype,
TYPE_RAISES_EXCEPTIONS (oldtype));
- if (! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl), 0))
+ if ((pedantic || ! DECL_IN_SYSTEM_HEADER (olddecl))
+ && DECL_SOURCE_LINE (olddecl) != 0
+ && flag_exceptions
+ && ! compexcepttypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)))
{
- cp_error ("declaration of `%D' throws different exceptions...",
+ cp_pedwarn ("declaration of `%D' throws different exceptions",
newdecl);
- cp_error_at ("...from previous declaration here", olddecl);
+ cp_pedwarn_at ("previous declaration here", olddecl);
}
}
TREE_TYPE (newdecl) = TREE_TYPE (olddecl) = newtype;
/* Lay the type out, unless already done. */
- if (oldtype != TREE_TYPE (newdecl)
- && TREE_TYPE (newdecl) != error_mark_node)
+ if (newtype != canonical_type_variant (oldtype)
+ && TREE_TYPE (newdecl) != error_mark_node
+ && !(processing_template_decl && uses_template_parms (newdecl)))
layout_type (TREE_TYPE (newdecl));
- if (TREE_CODE (newdecl) == VAR_DECL
- || TREE_CODE (newdecl) == PARM_DECL
- || TREE_CODE (newdecl) == RESULT_DECL
- || TREE_CODE (newdecl) == FIELD_DECL
- || TREE_CODE (newdecl) == TYPE_DECL)
+ if ((TREE_CODE (newdecl) == VAR_DECL
+ || TREE_CODE (newdecl) == PARM_DECL
+ || TREE_CODE (newdecl) == RESULT_DECL
+ || TREE_CODE (newdecl) == FIELD_DECL
+ || TREE_CODE (newdecl) == TYPE_DECL)
+ && !(processing_template_decl && uses_template_parms (newdecl)))
layout_decl (newdecl, 0);
/* Merge the type qualifiers. */
@@ -2881,20 +3065,55 @@ duplicate_decls (newdecl, olddecl)
/* Merge the storage class information. */
DECL_WEAK (newdecl) |= DECL_WEAK (olddecl);
+ DECL_ONE_ONLY (newdecl) |= DECL_ONE_ONLY (olddecl);
TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
TREE_STATIC (olddecl) = TREE_STATIC (newdecl) |= TREE_STATIC (olddecl);
if (! DECL_EXTERNAL (olddecl))
DECL_EXTERNAL (newdecl) = 0;
-
- if (TREE_CODE (newdecl) == FUNCTION_DECL)
+
+ if (DECL_LANG_SPECIFIC (newdecl) && DECL_LANG_SPECIFIC (olddecl))
{
- DECL_C_STATIC (newdecl) = DECL_C_STATIC (olddecl);
DECL_INTERFACE_KNOWN (newdecl) |= DECL_INTERFACE_KNOWN (olddecl);
DECL_NOT_REALLY_EXTERN (newdecl) |= DECL_NOT_REALLY_EXTERN (olddecl);
+ DECL_COMDAT (newdecl) |= DECL_COMDAT (olddecl);
+ /* Don't really know how much of the language-specific
+ values we should copy from old to new. */
+ DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
+ DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
+ DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
+ if (DECL_TEMPLATE_INFO (newdecl) == NULL_TREE)
+ {
+ DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
+ DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl);
+ }
+ olddecl_friend = DECL_FRIEND_P (olddecl);
}
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
+ if (DECL_TEMPLATE_INSTANTIATION (olddecl)
+ && !DECL_TEMPLATE_INSTANTIATION (newdecl))
+ {
+ /* If newdecl is not a specialization, then it is not a
+ template-related function at all. And that means that we
+ shoud have exited above, returning 0. */
+ my_friendly_assert (DECL_TEMPLATE_SPECIALIZATION (newdecl),
+ 0);
+
+ if (TREE_USED (olddecl))
+ /* From [temp.expl.spec]:
+
+ If a template, a member template or the member of a class
+ template is explicitly specialized then that
+ specialization shall be declared before the first use of
+ that specialization that would cause an implicit
+ instantiation to take place, in every translation unit in
+ which such a use occurs. */
+ cp_error ("explicit specialization of %D after first use",
+ olddecl);
+
+ SET_DECL_TEMPLATE_SPECIALIZATION (olddecl);
+ }
DECL_THIS_INLINE (newdecl) |= DECL_THIS_INLINE (olddecl);
/* If either decl says `inline', this fn is inline, unless its
@@ -2907,9 +3126,13 @@ duplicate_decls (newdecl, olddecl)
{
DECL_LANGUAGE (olddecl) = DECL_LANGUAGE (newdecl);
DECL_ASSEMBLER_NAME (olddecl) = DECL_ASSEMBLER_NAME (newdecl);
+ DECL_RTL (olddecl) = DECL_RTL (newdecl);
+ }
+ if (! types_match || new_defines_function)
+ {
+ /* These need to be copied so that the names are available. */
DECL_ARGUMENTS (olddecl) = DECL_ARGUMENTS (newdecl);
DECL_RESULT (olddecl) = DECL_RESULT (newdecl);
- DECL_RTL (olddecl) = DECL_RTL (newdecl);
}
if (new_defines_function)
/* If defining a function declared with other language
@@ -2948,32 +3171,12 @@ duplicate_decls (newdecl, olddecl)
NAMESPACE_LEVEL (newdecl) = NAMESPACE_LEVEL (olddecl);
}
- if (TREE_CODE (newdecl) == TEMPLATE_DECL)
- {
- if (DECL_TEMPLATE_INFO (olddecl)->length)
- DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
- DECL_TEMPLATE_MEMBERS (newdecl) = DECL_TEMPLATE_MEMBERS (olddecl);
- DECL_TEMPLATE_INSTANTIATIONS (newdecl)
- = DECL_TEMPLATE_INSTANTIATIONS (olddecl);
- if (DECL_CHAIN (newdecl) == NULL_TREE)
- DECL_CHAIN (newdecl) = DECL_CHAIN (olddecl);
- }
-
/* Now preserve various other info from the definition. */
TREE_ADDRESSABLE (newdecl) = TREE_ADDRESSABLE (olddecl);
TREE_ASM_WRITTEN (newdecl) = TREE_ASM_WRITTEN (olddecl);
DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
DECL_ASSEMBLER_NAME (newdecl) = DECL_ASSEMBLER_NAME (olddecl);
- /* Don't really know how much of the language-specific
- values we should copy from old to new. */
- if (DECL_LANG_SPECIFIC (olddecl))
- {
- DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
- DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
- DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
- }
-
if (TREE_CODE (newdecl) == FUNCTION_DECL)
{
int function_size;
@@ -2991,9 +3194,44 @@ duplicate_decls (newdecl, olddecl)
#define ROUND(x) ((x + obstack_alignment_mask (&permanent_obstack)) \
& ~ obstack_alignment_mask (&permanent_obstack))
- if ((char *)newdecl + ROUND (function_size)
- + ROUND (sizeof (struct lang_decl))
- == obstack_next_free (&permanent_obstack))
+ if (DECL_TEMPLATE_INSTANTIATION (newdecl))
+ {
+ /* If newdecl is a template instantiation, it is possible that
+ the following sequence of events has occurred:
+
+ o A friend function was declared in a class template. The
+ class template was instantiated.
+
+ o The instantiation of the friend declaration was
+ recorded on the instantiation list, and is newdecl.
+
+ o Later, however, instantiate_class_template called pushdecl
+ on the newdecl to perform name injection. But, pushdecl in
+ turn called duplicate_decls when it discovered that another
+ declaration of a global function with the same name already
+ existed.
+
+ o Here, in duplicate_decls, we decided to clobber newdecl.
+
+ If we're going to do that, we'd better make sure that
+ olddecl, and not newdecl, is on the list of
+ instantiations so that if we try to do the instantiation
+ again we won't get the clobbered declaration. */
+
+ tree tmpl = DECL_TI_TEMPLATE (newdecl);
+ tree decls = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+
+ for (; decls; decls = TREE_CHAIN (decls))
+ if (TREE_VALUE (decls) == newdecl)
+ TREE_VALUE (decls) = olddecl;
+ }
+
+ if (((char *)newdecl + ROUND (function_size) == (char *)nl
+ && ((char *)newdecl + ROUND (function_size)
+ + ROUND (sizeof (struct lang_decl))
+ == obstack_next_free (&permanent_obstack)))
+ || ((char *)newdecl + ROUND (function_size)
+ == obstack_next_free (&permanent_obstack)))
{
DECL_MAIN_VARIANT (newdecl) = olddecl;
DECL_LANG_SPECIFIC (olddecl) = ol;
@@ -3001,19 +3239,23 @@ duplicate_decls (newdecl, olddecl)
obstack_free (&permanent_obstack, newdecl);
}
- else if (LANG_DECL_PERMANENT (ol))
+ else if (LANG_DECL_PERMANENT (ol) && ol != nl)
{
if (DECL_MAIN_VARIANT (olddecl) == olddecl)
{
/* Save these lang_decls that would otherwise be lost. */
extern tree free_lang_decl_chain;
tree free_lang_decl = (tree) ol;
+
+ if (DECL_LANG_SPECIFIC (olddecl) == ol)
+ abort ();
+
TREE_CHAIN (free_lang_decl) = free_lang_decl_chain;
free_lang_decl_chain = free_lang_decl;
}
else
{
- /* Storage leak. */
+ /* Storage leak. */;
}
}
}
@@ -3029,6 +3271,10 @@ duplicate_decls (newdecl, olddecl)
if (olddecl_friend)
DECL_FRIEND_P (olddecl) = 1;
+ /* NEWDECL contains the merged attribute lists.
+ Update OLDDECL to be the same. */
+ DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl);
+
return 1;
}
@@ -3045,54 +3291,41 @@ pushdecl (x)
tree x;
{
register tree t;
-#if 0 /* not yet, should get fixed properly later */
- register tree name;
-#else
register tree name = DECL_ASSEMBLER_NAME (x);
-#endif
register struct binding_level *b = current_binding_level;
-#if 0
- static int nglobals; int len;
-
- len = list_length (global_binding_level->names);
- if (len < nglobals)
- my_friendly_abort (8);
- else if (len > nglobals)
- nglobals = len;
-#endif
-
- if (x != current_function_decl
+ if (current_function_decl && x != current_function_decl
+ /* A local declaration for a function doesn't constitute nesting. */
+ && (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x))
/* Don't change DECL_CONTEXT of virtual methods. */
&& (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
&& ! DECL_CONTEXT (x))
DECL_CONTEXT (x) = current_function_decl;
- /* A local declaration for a function doesn't constitute nesting. */
- if (TREE_CODE (x) == FUNCTION_DECL && DECL_INITIAL (x) == 0)
- DECL_CONTEXT (x) = 0;
-
-#if 0 /* not yet, should get fixed properly later */
- /* For functions and class static data, we currently look up the encoded
- form of the name. For types, we want the real name. The former will
- probably be changed soon, according to MDT. */
- if (TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL)
- name = DECL_ASSEMBLER_NAME (x);
- else
- name = DECL_NAME (x);
-#else
+ if (!DECL_CONTEXT (x))
+ DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace);
+
/* Type are looked up using the DECL_NAME, as that is what the rest of the
- compiler wants to use. */
+ compiler wants to use. */
if (TREE_CODE (x) == TYPE_DECL || TREE_CODE (x) == VAR_DECL
- || TREE_CODE (x) == NAMESPACE_DECL)
+ || TREE_CODE (x) == NAMESPACE_DECL || TREE_CODE (x) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (x) == TEMPLATE_TEMPLATE_PARM)
name = DECL_NAME (x);
-#endif
if (name)
{
+#if 0
+ /* Not needed...see below. */
char *file;
int line;
-
- t = lookup_name_current_level (name);
+#endif
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+ name = TREE_OPERAND (name, 0);
+
+ /* Namespace-scoped variables are not found in the current level. */
+ if (TREE_CODE (x) == VAR_DECL && DECL_NAMESPACE_SCOPE_P (x))
+ t = namespace_binding (name, DECL_CONTEXT (x));
+ else
+ t = lookup_name_current_level (name);
if (t == error_mark_node)
{
/* error_mark_node is 0 for a while during initialization! */
@@ -3102,20 +3335,25 @@ pushdecl (x)
else if (t != NULL_TREE)
{
+#if 0
+ /* This is turned off until I have time to do it right (bpk). */
+ /* With the code below that uses it... */
file = DECL_SOURCE_FILE (t);
line = DECL_SOURCE_LINE (t);
- if (TREE_CODE (x) == VAR_DECL && DECL_DEAD_FOR_LOCAL (x))
- ; /* This is OK. */
- else if (TREE_CODE (t) == PARM_DECL)
+#endif
+ if (TREE_CODE (t) == PARM_DECL)
{
if (DECL_CONTEXT (t) == NULL_TREE)
fatal ("parse errors have confused me too much");
+
+ /* Check for duplicate params. */
+ if (duplicate_decls (x, t))
+ return t;
}
else if (((TREE_CODE (x) == FUNCTION_DECL && DECL_LANGUAGE (x) == lang_c)
- || (TREE_CODE (x) == TEMPLATE_DECL
- && ! DECL_TEMPLATE_IS_CLASS (x)))
- && is_overloaded_fn (t))
- /* don't do anything just yet */;
+ || DECL_FUNCTION_TEMPLATE_P (x))
+ && is_overloaded_fn (t))
+ /* Don't do anything just yet. */;
else if (t == wchar_decl_node)
{
if (pedantic && ! DECL_IN_SYSTEM_HEADER (x))
@@ -3126,17 +3364,7 @@ pushdecl (x)
}
else if (TREE_CODE (t) != TREE_CODE (x))
{
- if ((TREE_CODE (t) == TYPE_DECL && DECL_ARTIFICIAL (t))
- || (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)))
- {
- /* We do nothing special here, because C++ does such nasty
- things with TYPE_DECLs. Instead, just let the TYPE_DECL
- get shadowed, and know that if we need to find a TYPE_DECL
- for a given name, we can look in the IDENTIFIER_TYPE_VALUE
- slot of the identifier. */
- ;
- }
- else if (duplicate_decls (x, t))
+ if (duplicate_decls (x, t))
return t;
}
else if (duplicate_decls (x, t))
@@ -3178,6 +3406,20 @@ pushdecl (x)
return t;
}
+ else if (DECL_MAIN_P (x))
+ {
+ /* A redeclaration of main, but not a duplicate of the
+ previous one.
+
+ [basic.start.main]
+
+ This function shall not be overloaded. */
+ cp_error_at ("invalid redeclaration of `%D'", t);
+ cp_error ("as `%D'", x);
+ /* We don't try to push this declaration since that
+ causes a crash. */
+ return x;
+ }
}
if (TREE_CODE (x) == FUNCTION_DECL && ! DECL_FUNCTION_MEMBER_P (x))
@@ -3186,45 +3428,32 @@ pushdecl (x)
if (t != x || DECL_LANGUAGE (x) == lang_c)
return t;
}
- else if (TREE_CODE (x) == TEMPLATE_DECL && ! DECL_TEMPLATE_IS_CLASS (x))
+ else if (DECL_FUNCTION_TEMPLATE_P (x) && DECL_NAMESPACE_SCOPE_P (x))
return push_overloaded_decl (x, 0);
- /* If declaring a type as a typedef, and the type has no known
- typedef name, install this TYPE_DECL as its typedef name. */
+ /* If declaring a type as a typedef, copy the type (unless we're
+ at line 0), and install this TYPE_DECL as the new type's typedef
+ name. See the extensive comment in ../c-decl.c (pushdecl). */
if (TREE_CODE (x) == TYPE_DECL)
{
tree type = TREE_TYPE (x);
- tree name = (type != error_mark_node) ? TYPE_NAME (type) : x;
+ if (DECL_SOURCE_LINE (x) == 0)
+ {
+ if (TYPE_NAME (type) == 0)
+ TYPE_NAME (type) = x;
+ }
+ else if (type != error_mark_node && TYPE_NAME (type) != x)
+ {
+ push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
- if (name == NULL_TREE || TREE_CODE (name) != TYPE_DECL)
- {
- /* If these are different names, and we're at the global
- binding level, make two equivalent definitions. */
- name = x;
- if (global_bindings_p ())
- TYPE_NAME (type) = x;
- }
- else
- {
- tree tname = DECL_NAME (name);
+ DECL_ORIGINAL_TYPE (x) = type;
+ type = build_type_copy (type);
+ TYPE_STUB_DECL (type) = TYPE_STUB_DECL (DECL_ORIGINAL_TYPE (x));
+ TYPE_NAME (type) = x;
+ TREE_TYPE (x) = type;
- /* This is a disgusting kludge for dealing with UPTs. */
- if (global_bindings_p () && ANON_AGGRNAME_P (tname))
- {
- /* do gratuitous C++ typedefing, and make sure that
- we access this type either through TREE_TYPE field
- or via the tags list. */
- TYPE_NAME (TREE_TYPE (x)) = x;
- pushtag (tname, TREE_TYPE (x), 0);
- }
- }
- my_friendly_assert (TREE_CODE (name) == TYPE_DECL, 140);
-
- /* Don't set nested_typename on template type parms, for instance.
- Any artificial decls that need DECL_NESTED_TYPENAME will have it
- set in pushtag. */
- if (! DECL_NESTED_TYPENAME (x) && ! DECL_ARTIFICIAL (x))
- set_nested_typename (x, current_class_name, DECL_NAME (x), type);
+ pop_obstacks ();
+ }
if (type != error_mark_node
&& TYPE_NAME (type)
@@ -3241,11 +3470,12 @@ pushdecl (x)
if (TREE_PUBLIC (x) && TREE_CODE (x) != FUNCTION_DECL)
{
tree decl;
+ tree bindings = binding_for_name (name, current_namespace);
- if (IDENTIFIER_GLOBAL_VALUE (name) != NULL_TREE
- && (DECL_EXTERNAL (IDENTIFIER_GLOBAL_VALUE (name))
- || TREE_PUBLIC (IDENTIFIER_GLOBAL_VALUE (name))))
- decl = IDENTIFIER_GLOBAL_VALUE (name);
+ if (BINDING_VALUE (bindings) != NULL_TREE
+ && (DECL_EXTERNAL (BINDING_VALUE (bindings))
+ || TREE_PUBLIC (BINDING_VALUE (bindings))))
+ decl = BINDING_VALUE (bindings);
else
decl = NULL_TREE;
@@ -3259,21 +3489,16 @@ pushdecl (x)
}
}
- /* In PCC-compatibility mode, extern decls of vars with no current decl
- take effect at top level no matter where they are. */
- if (flag_traditional && DECL_EXTERNAL (x)
- && lookup_name (name, 0) == NULL_TREE)
- b = global_binding_level;
-
/* This name is new in its binding level.
Install the new declaration and return it. */
- if (b == global_binding_level)
+ if (namespace_bindings_p ())
{
/* Install a global value. */
+ tree bindings = binding_for_name (name, current_namespace);
/* If the first global decl has external linkage,
warn if we later see static one. */
- if (IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE && DECL_PUBLIC (x))
+ if (BINDING_VALUE (bindings) == NULL_TREE && TREE_PUBLIC (x))
TREE_PUBLIC (name) = 1;
/* Don't install an artificial TYPE_DECL if we already have
@@ -3281,7 +3506,12 @@ pushdecl (x)
if (TREE_CODE (x) != TYPE_DECL
|| t == NULL_TREE
|| ! DECL_ARTIFICIAL (x))
- IDENTIFIER_GLOBAL_VALUE (name) = x;
+ {
+ if (TREE_CODE (x) == FUNCTION_DECL)
+ my_friendly_assert ((BINDING_VALUE (bindings) == NULL_TREE)
+ || BINDING_VALUE (bindings) == x, 378);
+ BINDING_VALUE (bindings) = x;
+ }
/* Don't forget if the function was used via an implicit decl. */
if (IDENTIFIER_IMPLICIT_DECL (name)
@@ -3310,17 +3540,14 @@ pushdecl (x)
{
/* Here to install a non-global value. */
tree oldlocal = IDENTIFIER_LOCAL_VALUE (name);
- tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name);
+ tree oldglobal = binding_for_name (name, current_namespace);
/* Don't install an artificial TYPE_DECL if we already have
another _DECL with that name. */
if (TREE_CODE (x) != TYPE_DECL
|| t == NULL_TREE
|| ! DECL_ARTIFICIAL (x))
- {
- b->shadowed = tree_cons (name, oldlocal, b->shadowed);
- IDENTIFIER_LOCAL_VALUE (name) = x;
- }
+ set_identifier_local_value_with_scope (name, x, b);
/* If this is a TYPE_DECL, push it into the type value slot. */
if (TREE_CODE (x) == TYPE_DECL)
@@ -3336,24 +3563,24 @@ pushdecl (x)
have a global definition or declaration for the function. */
if (oldlocal == NULL_TREE
&& DECL_EXTERNAL (x)
- && oldglobal != NULL_TREE
+ && BINDING_VALUE (oldglobal) != NULL_TREE
&& TREE_CODE (x) == FUNCTION_DECL
- && TREE_CODE (oldglobal) == FUNCTION_DECL)
+ && TREE_CODE (BINDING_VALUE (oldglobal)) == FUNCTION_DECL)
{
/* We have one. Their types must agree. */
- if (decls_match (x, oldglobal))
+ if (decls_match (x, BINDING_VALUE (oldglobal)))
/* OK */;
else
{
cp_warning ("extern declaration of `%#D' doesn't match", x);
- cp_warning_at ("global declaration `%#D'", oldglobal);
+ cp_warning_at ("global declaration `%#D'", BINDING_VALUE (oldglobal));
}
}
/* If we have a local external declaration,
and no file-scope declaration has yet been seen,
then if we later have a file-scope decl it must not be static. */
if (oldlocal == NULL_TREE
- && oldglobal == NULL_TREE
+ && BINDING_VALUE (oldglobal) == NULL_TREE
&& DECL_EXTERNAL (x)
&& TREE_PUBLIC (x))
{
@@ -3379,7 +3606,7 @@ pushdecl (x)
if (b->parm_flag == 1)
cp_error ("declaration of `%#D' shadows a parameter", name);
}
- else if (oldlocal != NULL_TREE && b->is_for_scope
+ else if (warn_shadow && oldlocal != NULL_TREE && b->is_for_scope
&& !DECL_DEAD_FOR_LOCAL (oldlocal))
{
warning ("variable `%s' shadows local",
@@ -3398,12 +3625,13 @@ pushdecl (x)
if (oldlocal != NULL_TREE && TREE_CODE (oldlocal) == PARM_DECL)
warnstring = "declaration of `%s' shadows a parameter";
else if (IDENTIFIER_CLASS_VALUE (name) != NULL_TREE
- && current_class_decl
+ && current_class_ptr
&& !TREE_STATIC (name))
warnstring = "declaration of `%s' shadows a member of `this'";
else if (oldlocal != NULL_TREE)
warnstring = "declaration of `%s' shadows previous local";
- else if (oldglobal != NULL_TREE)
+ else if (BINDING_VALUE (oldglobal) != NULL_TREE)
+ /* XXX shadow warnings in outer-more namespaces */
warnstring = "declaration of `%s' shadows global declaration";
if (warnstring)
@@ -3435,29 +3663,47 @@ pushdecl (x)
return x;
}
-/* Same as pushdecl, but define X in binding-level LEVEL. */
+/* Same as pushdecl, but define X in binding-level LEVEL. We rely on the
+ caller to set DECL_CONTEXT properly. */
static tree
pushdecl_with_scope (x, level)
tree x;
struct binding_level *level;
{
- register struct binding_level *b = current_binding_level;
+ register struct binding_level *b;
+ tree function_decl = current_function_decl;
- current_binding_level = level;
- x = pushdecl (x);
- current_binding_level = b;
+ current_function_decl = NULL_TREE;
+ if (level->parm_flag == 2)
+ {
+ b = class_binding_level;
+ class_binding_level = level;
+ pushdecl_class_level (x);
+ class_binding_level = b;
+ }
+ else
+ {
+ b = current_binding_level;
+ current_binding_level = level;
+ x = pushdecl (x);
+ current_binding_level = b;
+ }
+ current_function_decl = function_decl;
return x;
}
-/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL,
+/* Like pushdecl, only it places X in the current namespace,
if appropriate. */
+
tree
-pushdecl_top_level (x)
+pushdecl_namespace_level (x)
tree x;
{
register struct binding_level *b = inner_binding_level;
- register tree t = pushdecl_with_scope (x, global_binding_level);
+ register tree t;
+
+ t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace));
/* Now, the type_shadowed stack may screw us. Munge it so it does
what we want. */
@@ -3487,34 +3733,28 @@ pushdecl_top_level (x)
}
else
{
-#if 0
- /* Disabled this 11/10/92, since there are many cases which
- behave just fine when *ptr doesn't satisfy either of these.
- For example, nested classes declared as friends of their enclosing
- class will not meet this criteria. (bpk) */
- my_friendly_assert (*ptr == NULL_TREE || *ptr == newval, 141);
-#endif
*ptr = newval;
}
}
return t;
}
-/* Like push_overloaded_decl, only it places X in GLOBAL_BINDING_LEVEL,
+/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL,
if appropriate. */
-void
-push_overloaded_decl_top_level (x, forget)
+
+tree
+pushdecl_top_level (x)
tree x;
- int forget;
{
- struct binding_level *b = current_binding_level;
-
- current_binding_level = global_binding_level;
- push_overloaded_decl (x, forget);
- current_binding_level = b;
+ tree cur_namespace = current_namespace;
+ current_namespace = global_namespace;
+ x = pushdecl_namespace_level (x);
+ current_namespace = cur_namespace;
+ return x;
}
/* Make the declaration of X appear in CLASS scope. */
+
tree
pushdecl_class_level (x)
tree x;
@@ -3527,21 +3767,24 @@ pushdecl_class_level (x)
{
if (TYPE_BEING_DEFINED (current_class_type))
{
- /* Check for inconsistent use of this name in the class body.
+ /* A name N used in a class S shall refer to the same declaration
+ in its context and when re-evaluated in the completed scope of S.
+
Types, enums, and static vars are checked here; other
members are checked in finish_struct. */
tree icv = IDENTIFIER_CLASS_VALUE (name);
- if (icv
+ if (icv && icv != x
+ && flag_optional_diags
/* Don't complain about inherited names. */
&& id_in_current_class (name)
/* Or shadowed tags. */
- && !(TREE_CODE (icv) == TYPE_DECL
+ && !(DECL_DECLARES_TYPE_P (icv)
&& DECL_CONTEXT (icv) == current_class_type))
{
- cp_error ("declaration of identifier `%D' as `%#D'", name, x);
- cp_error_at ("conflicts with previous use in class as `%#D'",
- icv);
+ cp_pedwarn ("declaration of identifier `%D' as `%#D'", name, x);
+ cp_pedwarn_at ("conflicts with previous use in class as `%#D'",
+ icv);
}
}
@@ -3549,49 +3792,47 @@ pushdecl_class_level (x)
if (TREE_CODE (x) == TYPE_DECL)
{
set_identifier_type_value (name, TREE_TYPE (x));
-
- /* Don't set nested_typename on template type parms, for instance.
- Any artificial decls that need DECL_NESTED_TYPENAME will have it
- set in pushtag. */
- if (! DECL_NESTED_TYPENAME (x) && ! DECL_ARTIFICIAL (x))
- set_nested_typename (x, current_class_name, name, TREE_TYPE (x));
}
}
return x;
}
+#if 0
/* This function is used to push the mangled decls for nested types into
the appropriate scope. Previously pushdecl_top_level was used, but that
is incorrect for members of local classes. */
-tree
+
+void
pushdecl_nonclass_level (x)
tree x;
{
struct binding_level *b = current_binding_level;
-#if 0
- /* Get out of class scope -- this isn't necessary, because class scope
- doesn't make it into current_binding_level. */
- while (b->parm_flag == 2)
- b = b->level_chain;
-#else
my_friendly_assert (b->parm_flag != 2, 180);
-#endif
+#if 0
/* Get out of template binding levels */
while (b->pseudo_global)
b = b->level_chain;
+#endif
pushdecl_with_scope (x, b);
}
+#endif
/* Make the declaration(s) of X appear in CLASS scope
under the name NAME. */
+
void
push_class_level_binding (name, x)
tree name;
tree x;
{
+ /* The class_binding_level will be NULL if x is a template
+ parameter name in a member template. */
+ if (!class_binding_level)
+ return;
+
if (TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)
&& purpose_member (name, class_binding_level->class_shadowed))
return;
@@ -3605,22 +3846,55 @@ push_class_level_binding (name, x)
obstack_ptr_grow (&decl_obstack, x);
}
-/* Tell caller how to interpret a TREE_LIST which contains
- chains of FUNCTION_DECLS. */
-int
-overloaded_globals_p (list)
- tree list;
+/* Insert another USING_DECL into the current binding level,
+ returning this declaration. If this is a redeclaration,
+ do nothing and return NULL_TREE. */
+
+tree
+push_using_decl (scope, name)
+ tree scope;
+ tree name;
{
- my_friendly_assert (TREE_CODE (list) == TREE_LIST, 142);
+ tree decl;
+
+ my_friendly_assert (TREE_CODE (scope) == NAMESPACE_DECL, 383);
+ my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 384);
+ for (decl = current_binding_level->usings; decl; decl = TREE_CHAIN (decl))
+ if (DECL_INITIAL (decl) == scope && DECL_NAME (decl) == name)
+ break;
+ if (decl)
+ return NULL_TREE;
+ decl = build_lang_decl (USING_DECL, name, void_type_node);
+ DECL_INITIAL (decl) = scope;
+ TREE_CHAIN (decl) = current_binding_level->usings;
+ current_binding_level->usings = decl;
+ return decl;
+}
- /* Don't commit caller to seeing them as globals. */
- if (TREE_NONLOCAL_FLAG (list))
- return -1;
- /* Do commit caller to seeing them as globals. */
- if (TREE_CODE (TREE_PURPOSE (list)) == IDENTIFIER_NODE)
- return 1;
- /* Do commit caller to not seeing them as globals. */
- return 0;
+/* Add namespace to using_directives. Return NULL_TREE if nothing was
+ changed (i.e. there was already a directive), or the fresh
+ TREE_LIST otherwise. */
+
+tree
+push_using_directive (used)
+ tree used;
+{
+ tree ud = current_binding_level->using_directives;
+ tree iter, ancestor;
+
+ /* Check if we already have this. */
+ if (purpose_member (used, ud) != NULL_TREE)
+ return NULL_TREE;
+
+ /* Recursively add all namespaces used. */
+ for (iter = DECL_NAMESPACE_USING (used); iter; iter = TREE_CHAIN (iter))
+ push_using_directive (TREE_PURPOSE (iter));
+
+ ancestor = namespace_ancestor (current_decl_namespace (), used);
+ ud = current_binding_level->using_directives;
+ ud = perm_tree_cons (used, ancestor, ud);
+ current_binding_level->using_directives = ud;
+ return ud;
}
/* DECL is a FUNCTION_DECL which may have other definitions already in
@@ -3635,19 +3909,19 @@ overloaded_globals_p (list)
The value returned may be a previous declaration if we guessed wrong
about what language DECL should belong to (C or C++). Otherwise,
it's always DECL (and never something that's not a _DECL). */
-tree
+
+static tree
push_overloaded_decl (decl, forgettable)
tree decl;
int forgettable;
{
tree orig_name = DECL_NAME (decl);
tree old;
- int doing_global = (global_bindings_p () || ! forgettable
- || flag_traditional || pseudo_global_level_p ());
+ int doing_global = (namespace_bindings_p () || ! forgettable);
if (doing_global)
{
- old = IDENTIFIER_GLOBAL_VALUE (orig_name);
+ old = namespace_binding (orig_name, DECL_CONTEXT (decl));
if (old && TREE_CODE (old) == FUNCTION_DECL
&& DECL_ARTIFICIAL (old)
&& (DECL_BUILT_IN (old) || DECL_BUILT_IN_NONANSI (old)))
@@ -3671,18 +3945,12 @@ push_overloaded_decl (decl, forgettable)
if (old)
{
-#if 0
- /* We cache the value of builtin functions as ADDR_EXPRs
- in the name space. Convert it to some kind of _DECL after
- remembering what to forget. */
- if (TREE_CODE (old) == ADDR_EXPR)
- old = TREE_OPERAND (old, 0);
- else
-#endif
if (TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old))
{
tree t = TREE_TYPE (old);
- if (IS_AGGR_TYPE (t) && warn_shadow)
+ if (IS_AGGR_TYPE (t) && warn_shadow
+ && (! DECL_IN_SYSTEM_HEADER (decl)
+ || ! DECL_IN_SYSTEM_HEADER (old)))
cp_warning ("`%#D' hides constructor for `%#T'", decl, t);
old = NULL_TREE;
}
@@ -3690,9 +3958,10 @@ push_overloaded_decl (decl, forgettable)
{
tree tmp;
- for (tmp = get_first_fn (old); tmp; tmp = DECL_CHAIN (tmp))
- if (decl == tmp || duplicate_decls (decl, tmp))
- return tmp;
+ for (tmp = old; tmp; tmp = OVL_NEXT (tmp))
+ if (decl == OVL_CURRENT (tmp)
+ || duplicate_decls (decl, OVL_CURRENT (tmp)))
+ return OVL_CURRENT (tmp);
}
else
{
@@ -3704,19 +3973,16 @@ push_overloaded_decl (decl, forgettable)
if (old || TREE_CODE (decl) == TEMPLATE_DECL)
{
- if (old && is_overloaded_fn (old))
- DECL_CHAIN (decl) = get_first_fn (old);
- else
- DECL_CHAIN (decl) = NULL_TREE;
- old = tree_cons (orig_name, decl, NULL_TREE);
- TREE_TYPE (old) = unknown_type_node;
+ if (old && TREE_CODE (old) != OVERLOAD)
+ old = ovl_cons (old, NULL_TREE);
+ old = ovl_cons (decl, old);
}
else
/* orig_name is not ambiguous. */
old = decl;
if (doing_global)
- IDENTIFIER_GLOBAL_VALUE (orig_name) = old;
+ set_namespace_binding (orig_name, current_namespace, old);
else
IDENTIFIER_LOCAL_VALUE (orig_name) = old;
@@ -3738,7 +4004,7 @@ implicitly_declare (functionid)
/* Save the decl permanently so we can warn if definition follows.
In ANSI C, warn_implicit is usually false, so the saves little space.
But in C++, it's usually true, hence the extra code. */
- if (temp && (flag_traditional || !warn_implicit || toplevel_bindings_p ()))
+ if (temp && (! warn_implicit || toplevel_bindings_p ()))
end_temporary_allocation ();
/* We used to reuse an old implicit decl here,
@@ -3750,8 +4016,7 @@ implicitly_declare (functionid)
TREE_PUBLIC (decl) = 1;
/* ANSI standard says implicit declarations are in the innermost block.
- So we record the decl in the standard fashion.
- If flag_traditional is set, pushdecl does it top-level. */
+ So we record the decl in the standard fashion. */
pushdecl (decl);
rest_of_decl_compilation (decl, NULL_PTR, 0, 0);
@@ -3797,10 +4062,16 @@ redeclaration_error_message (newdecl, olddecl)
if (DECL_LANG_SPECIFIC (olddecl) && DECL_ABSTRACT_VIRTUAL_P (olddecl))
return 0;
+ /* If both functions come from different namespaces, this is not
+ a redeclaration - this is a conflict with a used function. */
+ if (DECL_NAMESPACE_SCOPE_P (olddecl)
+ && DECL_CONTEXT (olddecl) != DECL_CONTEXT (newdecl))
+ return "`%D' conflicts with used function";
+
/* We'll complain about linkage mismatches in
warn_extern_redeclared_static. */
- /* defining the same name twice is no good. */
+ /* Defining the same name twice is no good. */
if (DECL_INITIAL (olddecl) != NULL_TREE
&& DECL_INITIAL (newdecl) != NULL_TREE)
{
@@ -3813,11 +4084,16 @@ redeclaration_error_message (newdecl, olddecl)
}
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
- if (DECL_INITIAL (olddecl) && DECL_INITIAL (newdecl))
+ if ((TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == FUNCTION_DECL
+ && DECL_INITIAL (DECL_TEMPLATE_RESULT (newdecl))
+ && DECL_INITIAL (DECL_TEMPLATE_RESULT (olddecl)))
+ || (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL
+ && TYPE_SIZE (TREE_TYPE (newdecl))
+ && TYPE_SIZE (TREE_TYPE (olddecl))))
return "redefinition of `%#D'";
return 0;
}
- else if (current_binding_level == global_binding_level)
+ else if (toplevel_bindings_p ())
{
/* Objects declared at top level: */
/* If at least one is a reference, it's ok. */
@@ -3856,13 +4132,20 @@ lookup_label (id)
if ((decl == NULL_TREE
|| DECL_SOURCE_LINE (decl) == 0)
- && (named_label_uses == NULL_TREE
- || TREE_PURPOSE (named_label_uses) != current_binding_level->names
- || TREE_VALUE (named_label_uses) != decl))
- {
- named_label_uses
- = tree_cons (current_binding_level->names, decl, named_label_uses);
- TREE_TYPE (named_label_uses) = (tree)current_binding_level;
+ && (named_label_uses == NULL
+ || named_label_uses->names_in_scope != current_binding_level->names
+ || named_label_uses->label_decl != decl))
+ {
+ struct named_label_list *new_ent;
+ new_ent
+ = (struct named_label_list*)oballoc (sizeof (struct named_label_list));
+ new_ent->label_decl = decl;
+ new_ent->names_in_scope = current_binding_level->names;
+ new_ent->binding_level = current_binding_level;
+ new_ent->lineno_o_goto = lineno;
+ new_ent->filename_o_goto = input_filename;
+ new_ent->next = named_label_uses;
+ named_label_uses = new_ent;
}
/* Use a label already defined or ref'd with this name. */
@@ -3877,6 +4160,9 @@ lookup_label (id)
decl = build_decl (LABEL_DECL, id, void_type_node);
+ /* Make sure every label has an rtx. */
+ label_rtx (decl);
+
/* A label not explicitly declared must be local to where it's ref'd. */
DECL_CONTEXT (decl) = current_function_decl;
@@ -3890,7 +4176,7 @@ lookup_label (id)
SET_IDENTIFIER_LABEL_VALUE (id, decl);
named_labels = tree_cons (NULL_TREE, decl, named_labels);
- TREE_VALUE (named_label_uses) = decl;
+ named_label_uses->label_decl = decl;
return decl;
}
@@ -3913,7 +4199,6 @@ shadow_label (name)
{
shadowed_labels = tree_cons (NULL_TREE, decl, shadowed_labels);
SET_IDENTIFIER_LABEL_VALUE (name, NULL_TREE);
- SET_IDENTIFIER_LABEL_VALUE (decl, NULL_TREE);
}
return lookup_label (name);
@@ -3929,7 +4214,20 @@ define_label (filename, line, name)
int line;
tree name;
{
- tree decl = lookup_label (name);
+ tree decl;
+
+ if (minimal_parse_mode)
+ {
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ decl = build_decl (LABEL_DECL, name, void_type_node);
+ pop_obstacks ();
+ DECL_SOURCE_LINE (decl) = line;
+ DECL_SOURCE_FILE (decl) = filename;
+ add_tree (decl);
+ return decl;
+ }
+
+ decl = lookup_label (name);
/* After labels, make any new cleanups go into their
own new (temporary) binding contour. */
@@ -3953,7 +4251,7 @@ define_label (filename, line, name)
}
else
{
- tree uses, prev;
+ struct named_label_list *uses, *prev;
int identified = 0;
/* Mark label as having been defined. */
@@ -3962,17 +4260,17 @@ define_label (filename, line, name)
DECL_SOURCE_FILE (decl) = filename;
DECL_SOURCE_LINE (decl) = line;
- for (prev = NULL_TREE, uses = named_label_uses;
- uses;
- prev = uses, uses = TREE_CHAIN (uses))
- if (TREE_VALUE (uses) == decl)
+ prev = NULL;
+ uses = named_label_uses;
+ while (uses != NULL)
+ if (uses->label_decl == decl)
{
struct binding_level *b = current_binding_level;
while (b)
{
tree new_decls = b->names;
- tree old_decls = ((tree)b == TREE_TYPE (uses)
- ? TREE_PURPOSE (uses) : NULL_TREE);
+ tree old_decls = (b == uses->binding_level)
+ ? uses->names_in_scope : NULL_TREE;
while (new_decls != old_decls)
{
if (TREE_CODE (new_decls) == VAR_DECL
@@ -3985,23 +4283,35 @@ define_label (filename, line, name)
&& DECL_INITIAL (new_decls) != error_mark_node)
|| TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (new_decls))))
{
- if (! identified)
- cp_error ("jump to label `%D'", decl);
- identified = 1;
+ if (! identified)
+ {
+ cp_error ("jump to label `%D'", decl);
+ error_with_file_and_line (uses->filename_o_goto,
+ uses->lineno_o_goto,
+ " from here");
+ identified = 1;
+ }
cp_error_at (" crosses initialization of `%#D'",
new_decls);
}
new_decls = TREE_CHAIN (new_decls);
}
- if ((tree)b == TREE_TYPE (uses))
+ if (b == uses->binding_level)
break;
b = b->level_chain;
}
- if (prev)
- TREE_CHAIN (prev) = TREE_CHAIN (uses);
+ if (prev != NULL)
+ prev->next = uses->next;
else
- named_label_uses = TREE_CHAIN (uses);
+ named_label_uses = uses->next;
+
+ uses = uses->next;
+ }
+ else
+ {
+ prev = uses;
+ uses = uses->next;
}
current_function_return_value = NULL_TREE;
return decl;
@@ -4034,6 +4344,7 @@ pop_switch ()
/* Same, but for CASE labels. If DECL is NULL_TREE, it's the default. */
/* XXX Note decl is never actually used. (bpk) */
+
void
define_case_label (decl)
tree decl;
@@ -4139,8 +4450,8 @@ storetags (tags)
static tree
lookup_tag (form, name, binding_level, thislevel_only)
enum tree_code form;
- struct binding_level *binding_level;
tree name;
+ struct binding_level *binding_level;
int thislevel_only;
{
register struct binding_level *level;
@@ -4156,6 +4467,27 @@ lookup_tag (form, name, binding_level, thislevel_only)
if (TYPE_IDENTIFIER (TREE_VALUE (tail)) == name)
return TREE_VALUE (tail);
}
+ else if (level->namespace_p)
+ /* Do namespace lookup. */
+ /* XXX: is this a real lookup, considering using-directives etc. ??? */
+ for (tail = current_namespace; 1; tail = CP_DECL_CONTEXT (tail))
+ {
+ tree old = BINDING_TYPE (binding_for_name (name, tail));
+ /* If it has an original type, it is a typedef, and we
+ should not return it. */
+ if (old && DECL_ORIGINAL_TYPE (TYPE_NAME (old)))
+ old = NULL_TREE;
+ if (old && TREE_CODE (old) != form
+ && !(form != ENUMERAL_TYPE && TREE_CODE (old) == TEMPLATE_DECL))
+ {
+ cp_error ("`%#D' redeclared as %C", old, form);
+ return NULL_TREE;
+ }
+ if (old)
+ return old;
+ if (thislevel_only || tail == global_namespace)
+ return NULL_TREE;
+ }
else
for (tail = level->tags; tail; tail = TREE_CHAIN (tail))
{
@@ -4165,21 +4497,30 @@ lookup_tag (form, name, binding_level, thislevel_only)
/* Should tighten this up; it'll probably permit
UNION_TYPE and a struct template, for example. */
if (code != form
- && !(form != ENUMERAL_TYPE
- && (code == TEMPLATE_DECL
- || code == UNINSTANTIATED_P_TYPE)))
-
+ && !(form != ENUMERAL_TYPE && code == TEMPLATE_DECL))
{
/* Definition isn't the kind we were looking for. */
cp_error ("`%#D' redeclared as %C", TREE_VALUE (tail),
form);
+ return NULL_TREE;
}
return TREE_VALUE (tail);
}
}
if (thislevel_only && ! level->tag_transparent)
- return NULL_TREE;
- if (current_class_type && level->level_chain == global_binding_level)
+ {
+ if (level->pseudo_global)
+ {
+ tree t = IDENTIFIER_CLASS_VALUE (name);
+ if (t && DECL_CLASS_TEMPLATE_P (t))
+ return TREE_TYPE (t);
+ t = IDENTIFIER_NAMESPACE_VALUE (name);
+ if (t && DECL_CLASS_TEMPLATE_P (t))
+ return TREE_TYPE (t);
+ }
+ return NULL_TREE;
+ }
+ if (current_class_type && level->level_chain->namespace_p)
{
/* Try looking in this class's tags before heading into
global binding level. */
@@ -4208,6 +4549,7 @@ lookup_tag (form, name, binding_level, thislevel_only)
{
cp_error ("`%#D' redeclared as %C in class scope",
TREE_VALUE (tail), form);
+ return NULL_TREE;
}
return TREE_VALUE (tail);
}
@@ -4218,7 +4560,7 @@ lookup_tag (form, name, binding_level, thislevel_only)
if (TYPE_SIZE (context) == NULL_TREE)
goto no_context;
/* Go to next enclosing type, if any. */
- context = DECL_CONTEXT (TYPE_NAME (context));
+ context = DECL_CONTEXT (TYPE_MAIN_DECL (context));
break;
case 'd':
context = DECL_CONTEXT (context);
@@ -4235,12 +4577,14 @@ lookup_tag (form, name, binding_level, thislevel_only)
return NULL_TREE;
}
+#if 0
void
set_current_level_tags_transparency (tags_transparent)
int tags_transparent;
{
current_binding_level->tag_transparent = tags_transparent;
}
+#endif
/* Given a type, find the tag that was defined for it and return the tag name.
Otherwise return 0. However, the value can never be 0
@@ -4271,36 +4615,10 @@ lookup_tag_reverse (type, name)
}
return NULL_TREE;
}
-
-/* Given type TYPE which was not declared in C++ language context,
- attempt to find a name by which it is referred. */
-tree
-typedecl_for_tag (tag)
- tree tag;
-{
- struct binding_level *b = current_binding_level;
-
- if (TREE_CODE (TYPE_NAME (tag)) == TYPE_DECL)
- return TYPE_NAME (tag);
-
- while (b)
- {
- tree decls = b->names;
- while (decls)
- {
- if (TREE_CODE (decls) == TYPE_DECL && TREE_TYPE (decls) == tag)
- break;
- decls = TREE_CHAIN (decls);
- }
- if (decls)
- return decls;
- b = b->level_chain;
- }
- return NULL_TREE;
-}
/* Lookup TYPE in CONTEXT (a chain of nested types or a FUNCTION_DECL).
Return the type value, or NULL_TREE if not found. */
+
static tree
lookup_nested_type (type, context)
tree type;
@@ -4341,22 +4659,233 @@ lookup_nested_type (type, context)
}
/* Look up NAME in the NAMESPACE. */
+
tree
lookup_namespace_name (namespace, name)
tree namespace, name;
{
- struct binding_level *b = (struct binding_level *)NAMESPACE_LEVEL (namespace);
- tree x;
+ struct tree_binding _b;
+ tree val;
+
+ my_friendly_assert (TREE_CODE (namespace) == NAMESPACE_DECL, 370);
+ my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 373);
+
+ val = binding_init (&_b);
+ if (!qualified_lookup_using_namespace (name, namespace, val, 0))
+ return error_mark_node;
- for (x = NULL_TREE; b && !x; b = b->level_chain)
+ if (BINDING_VALUE (val))
{
- for (x = b->names; x; x = TREE_CHAIN (x))
- if (DECL_NAME (x) == name || DECL_ASSEMBLER_NAME (x) == name)
- break;
- /* Must find directly in the namespace. */
- break;
+ val = BINDING_VALUE (val);
+
+ /* If we have a single function from a using decl, pull it out. */
+ if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val))
+ val = OVL_FUNCTION (val);
+ return val;
}
- return x;
+
+ cp_error ("`%D' undeclared in namespace `%D'", name, namespace);
+ return error_mark_node;
+}
+
+tree
+make_typename_type (context, name)
+ tree context, name;
+{
+ tree t, d;
+ tree fullname;
+
+ if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
+ name = TYPE_IDENTIFIER (name);
+ else if (TREE_CODE (name) == TYPE_DECL)
+ name = DECL_NAME (name);
+
+ fullname = name;
+
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+ {
+ name = TREE_OPERAND (name, 0);
+ if (TREE_CODE (name) == TEMPLATE_DECL)
+ name = TREE_OPERAND (fullname, 0) = DECL_NAME (name);
+ }
+ if (TREE_CODE (name) != IDENTIFIER_NODE)
+ my_friendly_abort (2000);
+
+ if (! uses_template_parms (context)
+ || currently_open_class (context))
+ {
+ if (TREE_CODE (fullname) == TEMPLATE_ID_EXPR)
+ {
+ if (IS_AGGR_TYPE (context))
+ t = lookup_field (context, name, 0, 0);
+ else
+ t = NULL_TREE;
+
+ if (t == NULL_TREE || TREE_CODE (t) != TEMPLATE_DECL
+ || TREE_CODE (DECL_RESULT (t)) != TYPE_DECL)
+ {
+ cp_error ("no class template named `%#T' in `%#T'",
+ name, context);
+ return error_mark_node;
+ }
+
+ return lookup_template_class (t, TREE_OPERAND (fullname, 1),
+ NULL_TREE, context);
+ }
+ else
+ {
+ if (IS_AGGR_TYPE (context))
+ t = lookup_field (context, name, 0, 1);
+ else
+ t = NULL_TREE;
+
+ if (t == NULL_TREE)
+ {
+ cp_error ("no type named `%#T' in `%#T'", name, context);
+ return error_mark_node;
+ }
+
+ return TREE_TYPE (t);
+ }
+ }
+
+ if (processing_template_decl)
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ t = make_lang_type (TYPENAME_TYPE);
+ TYPENAME_TYPE_FULLNAME (t) = fullname;
+ d = build_decl (TYPE_DECL, name, t);
+ if (processing_template_decl)
+ pop_obstacks ();
+
+ TYPE_CONTEXT (t) = FROB_CONTEXT (context);
+ TYPE_NAME (TREE_TYPE (d)) = d;
+ TYPE_STUB_DECL (TREE_TYPE (d)) = d;
+ DECL_CONTEXT (d) = FROB_CONTEXT (context);
+ CLASSTYPE_GOT_SEMICOLON (t) = 1;
+
+ return t;
+}
+
+/* Select the right _DECL from multiple choices. */
+
+static tree
+select_decl (binding, flags)
+ tree binding;
+ int flags;
+{
+ tree val;
+ val = BINDING_VALUE (binding);
+ if (LOOKUP_NAMESPACES_ONLY (flags))
+ {
+ /* We are not interested in types. */
+ if (val && TREE_CODE (val) == NAMESPACE_DECL)
+ return val;
+ return NULL_TREE;
+ }
+
+ /* If we could have a type and
+ we have nothing or we need a type and have none. */
+ if (BINDING_TYPE (binding)
+ && (!val || ((flags & LOOKUP_PREFER_TYPES)
+ && TREE_CODE (val) != TYPE_DECL)))
+ val = TYPE_STUB_DECL (BINDING_TYPE (binding));
+ /* Don't return non-types if we really prefer types. */
+ else if (val && LOOKUP_TYPES_ONLY (flags) && TREE_CODE (val) != TYPE_DECL
+ && (!looking_for_template || TREE_CODE (val) != TEMPLATE_DECL))
+ val = NULL_TREE;
+
+ return val;
+}
+
+/* Unscoped lookup of a global, iterate over namespaces, considering
+ using namespace statements. */
+
+static tree
+unqualified_namespace_lookup (name, flags)
+ tree name;
+ int flags;
+{
+ struct tree_binding _binding;
+ tree b = binding_init (&_binding);
+ tree initial = current_decl_namespace();
+ tree scope = initial;
+ tree siter;
+ struct binding_level *level;
+ tree val = NULL_TREE;
+
+ while (!val)
+ {
+ val = binding_for_name (name, scope);
+
+ /* Initialize binding for this context. */
+ BINDING_VALUE (b) = BINDING_VALUE (val);
+ BINDING_TYPE (b) = BINDING_TYPE (val);
+
+ /* Add all _DECLs seen through local using-directives. */
+ for (level = current_binding_level;
+ !level->namespace_p;
+ level = level->level_chain)
+ if (!lookup_using_namespace (name, b, level->using_directives,
+ scope, flags))
+ /* Give up because of error. */
+ return NULL_TREE;
+
+ /* Add all _DECLs seen through global using-directives. */
+ /* XXX local and global using lists should work equally. */
+ siter = initial;
+ while (1)
+ {
+ if (!lookup_using_namespace (name, b, DECL_NAMESPACE_USING (siter),
+ scope, flags))
+ /* Give up because of error. */
+ return NULL_TREE;
+ if (siter == scope) break;
+ siter = CP_DECL_CONTEXT (siter);
+ }
+
+ val = select_decl (b, flags);
+ if (scope == global_namespace)
+ break;
+ scope = CP_DECL_CONTEXT (scope);
+ }
+ return val;
+}
+
+/* Combine prefer_type and namespaces_only into flags. */
+
+static int
+lookup_flags (prefer_type, namespaces_only)
+ int prefer_type, namespaces_only;
+{
+ if (namespaces_only)
+ return LOOKUP_PREFER_NAMESPACES;
+ if (prefer_type > 1)
+ return LOOKUP_PREFER_TYPES;
+ if (prefer_type > 0)
+ return LOOKUP_PREFER_BOTH;
+ return 0;
+}
+
+/* Given a lookup that returned VAL, use FLAGS to decide if we want to
+ ignore it or not. Subroutine of lookup_name_real. */
+
+static tree
+qualify_lookup (val, flags)
+ tree val;
+ int flags;
+{
+ if (val == NULL_TREE)
+ return val;
+ if ((flags & LOOKUP_PREFER_NAMESPACES) && TREE_CODE (val) == NAMESPACE_DECL)
+ return val;
+ if ((flags & LOOKUP_PREFER_TYPES)
+ && (TREE_CODE (val) == TYPE_DECL
+ || ((flags & LOOKUP_TEMPLATES_EXPECTED)
+ && DECL_CLASS_TEMPLATE_P (val))))
+ return val;
+ if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES))
+ return NULL_TREE;
+ return val;
}
/* Look up NAME in the current binding level and its superiors in the
@@ -4365,27 +4894,48 @@ lookup_namespace_name (namespace, name)
such declaration, or return a TREE_LIST with all the overloaded
definitions if there are many, or return 0 if it is undefined.
- If PREFER_TYPE is > 0, we prefer TYPE_DECLs.
+ If PREFER_TYPE is > 0, we prefer TYPE_DECLs or namespaces.
+ If PREFER_TYPE is > 1, we reject non-type decls (e.g. namespaces).
If PREFER_TYPE is -2, we're being called from yylex(). (UGLY)
- Otherwise we prefer non-TYPE_DECLs. */
+ Otherwise we prefer non-TYPE_DECLs.
-tree
-lookup_name_real (name, prefer_type, nonclass)
+ If NONCLASS is non-zero, we don't look for the NAME in class scope,
+ using IDENTIFIER_CLASS_VALUE. */
+
+static tree
+lookup_name_real (name, prefer_type, nonclass, namespaces_only)
tree name;
- int prefer_type, nonclass;
+ int prefer_type, nonclass, namespaces_only;
{
register tree val;
int yylex = 0;
tree from_obj = NULL_TREE;
+ tree locval, classval;
+ int flags;
+
+ /* Hack: copy flag set by parser, if set. */
+ if (only_namespace_names)
+ namespaces_only = 1;
if (prefer_type == -2)
{
extern int looking_for_typename;
- tree type;
+ tree type = NULL_TREE;
yylex = 1;
prefer_type = looking_for_typename;
+ flags = lookup_flags (prefer_type, namespaces_only);
+ /* During parsing, we need to complain. */
+ flags |= LOOKUP_COMPLAIN;
+ /* If the next thing is '<', class templates are types. */
+ if (looking_for_template)
+ flags |= LOOKUP_TEMPLATES_EXPECTED;
+
+ /* std:: becomes :: for now. */
+ if (got_scope == std_node)
+ got_scope = void_type_node;
+
if (got_scope)
type = got_scope;
else if (got_object != error_mark_node)
@@ -4395,23 +4945,27 @@ lookup_name_real (name, prefer_type, nonclass)
{
if (type == error_mark_node)
return error_mark_node;
- else if (type == void_type_node)
- val = IDENTIFIER_GLOBAL_VALUE (name);
- else if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
- /* TFIXME -- don't do this for UPTs in new model. */
- || TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
- {
- if (prefer_type > 0)
- val = create_nested_upt (type, name);
- else
- val = NULL_TREE;
- }
- else if (TREE_CODE (type) == NAMESPACE_DECL)
+ if (TREE_CODE (type) == TYPENAME_TYPE && TREE_TYPE (type))
+ type = TREE_TYPE (type);
+
+ if (TYPE_P (type))
+ type = complete_type (type);
+
+ if (TREE_CODE (type) == VOID_TYPE)
+ type = global_namespace;
+ if (TREE_CODE (type) == NAMESPACE_DECL)
{
- val = lookup_namespace_name (type, name);
+ struct tree_binding b;
+ val = binding_init (&b);
+ if (!qualified_lookup_using_namespace (name, type, val, flags))
+ return NULL_TREE;
+ val = select_decl (val, flags);
}
- else if (! IS_AGGR_TYPE (type))
- /* Someone else will give an error about this if needed. */
+ else if (! IS_AGGR_TYPE (type)
+ || TREE_CODE (type) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (type) == TYPENAME_TYPE)
+ /* Someone else will give an error about this if needed. */
val = NULL_TREE;
else if (TYPE_BEING_DEFINED (type))
{
@@ -4430,68 +4984,128 @@ lookup_name_real (name, prefer_type, nonclass)
}
}
}
- if (val == NULL_TREE
- && CLASSTYPE_LOCAL_TYPEDECLS (type))
+ if (val == NULL_TREE)
val = lookup_field (type, name, 0, 1);
}
else if (type == current_class_type)
val = IDENTIFIER_CLASS_VALUE (name);
else
- val = lookup_field (type, name, 0, prefer_type);
+ val = lookup_member (type, name, 0, prefer_type);
}
else
val = NULL_TREE;
if (got_scope)
goto done;
-
- /* This special lookup only applies to types. */
- else if (got_object && val && TREE_CODE (val) == TYPE_DECL)
+ else if (got_object && val)
from_obj = val;
}
-
- if (current_binding_level != global_binding_level
- && IDENTIFIER_LOCAL_VALUE (name))
- val = IDENTIFIER_LOCAL_VALUE (name);
+ else
+ flags = lookup_flags (prefer_type, namespaces_only);
+
+ locval = classval = NULL_TREE;
+
+ if (! namespace_bindings_p ())
+ locval = qualify_lookup (IDENTIFIER_LOCAL_VALUE (name), flags);
+
/* In C++ class fields are between local and global scope,
just before the global scope. */
- else if (current_class_type && ! nonclass)
+ if (current_class_type && ! nonclass)
{
- val = IDENTIFIER_CLASS_VALUE (name);
- if (val == NULL_TREE
- && TYPE_BEING_DEFINED (current_class_type)
- && CLASSTYPE_LOCAL_TYPEDECLS (current_class_type))
+ classval = IDENTIFIER_CLASS_VALUE (name);
+ if (classval == NULL_TREE && TYPE_BEING_DEFINED (current_class_type))
/* Try to find values from base classes if we are presently
defining a type. We are presently only interested in
TYPE_DECLs. */
- val = lookup_field (current_class_type, name, 0, 1);
+ classval = lookup_field (current_class_type, name, 0, 1);
+
+ /* Add implicit 'typename' to types from template bases. lookup_field
+ will do this for us. If classval is actually from an enclosing
+ scope, lookup_nested_field will get it for us. */
+ if (processing_template_decl
+ && classval && TREE_CODE (classval) == TYPE_DECL
+ && ! currently_open_class (DECL_CONTEXT (classval))
+ && uses_template_parms (current_class_type)
+ && ! DECL_ARTIFICIAL (classval))
+ classval = lookup_field (current_class_type, name, 0, 1);
/* yylex() calls this with -2, since we should never start digging for
the nested name at the point where we haven't even, for example,
created the COMPONENT_REF or anything like that. */
- if (val == NULL_TREE)
- val = lookup_nested_field (name, ! yylex);
+ if (classval == NULL_TREE)
+ classval = lookup_nested_field (name, ! yylex);
- if (val == NULL_TREE)
- val = IDENTIFIER_GLOBAL_VALUE (name);
+ classval = qualify_lookup (classval, flags);
}
+
+ if (locval && classval)
+ {
+ if (current_scope () == current_function_decl
+ && ! hack_decl_function_context (current_function_decl))
+ /* Not in a nested function. */
+ val = locval;
+ else
+ {
+ /* This is incredibly horrible. The whole concept of
+ IDENTIFIER_LOCAL_VALUE / IDENTIFIER_CLASS_VALUE /
+ IDENTIFIER_GLOBAL_VALUE needs to be scrapped for local
+ classes. */
+ tree lctx = hack_decl_function_context (locval);
+ tree cctx = hack_decl_function_context (classval);
+
+ if (lctx == current_scope ())
+ val = locval;
+ else if (lctx == cctx)
+ val = classval;
+ else
+ /* I don't know which is right; let's just guess for now. */
+ val = locval;
+ }
+ }
+ else if (locval)
+ val = locval;
+ else if (classval)
+ val = classval;
else
- val = IDENTIFIER_GLOBAL_VALUE (name);
+ val = unqualified_namespace_lookup (name, flags);
done:
if (val)
{
+ /* This should only warn about types used in qualified-ids. */
if (from_obj && from_obj != val)
- cp_error ("lookup in the scope of `%#T' does not match lookup in the current scope",
- got_object);
+ {
+ if (looking_for_typename && TREE_CODE (from_obj) == TYPE_DECL
+ && TREE_CODE (val) == TYPE_DECL
+ && TREE_TYPE (from_obj) != TREE_TYPE (val))
+ {
+ cp_pedwarn ("lookup of `%D' in the scope of `%#T' (`%#T')",
+ name, got_object, TREE_TYPE (from_obj));
+ cp_pedwarn (" does not match lookup in the current scope (`%#T')",
+ TREE_TYPE (val));
+ }
+
+ /* We don't change val to from_obj if got_object depends on
+ template parms because that breaks implicit typename for
+ destructor calls. */
+ if (! uses_template_parms (got_object))
+ val = from_obj;
+ }
if ((TREE_CODE (val) == TEMPLATE_DECL && looking_for_template)
|| TREE_CODE (val) == TYPE_DECL || prefer_type <= 0)
;
+ /* Caller wants a class-or-namespace-name. */
+ else if (prefer_type == 1 && TREE_CODE (val) == NAMESPACE_DECL)
+ ;
else if (IDENTIFIER_HAS_TYPE_VALUE (name))
- val = TYPE_NAME (IDENTIFIER_TYPE_VALUE (name));
+ val = TYPE_MAIN_DECL (IDENTIFIER_TYPE_VALUE (name));
else if (TREE_TYPE (val) == error_mark_node)
val = error_mark_node;
+
+ /* If we have a single function from a using decl, pull it out. */
+ if (TREE_CODE (val) == OVERLOAD && ! really_overloaded_fn (val))
+ val = OVL_FUNCTION (val);
}
else if (from_obj)
val = from_obj;
@@ -4503,7 +5117,23 @@ tree
lookup_name_nonclass (name)
tree name;
{
- return lookup_name_real (name, 0, 1);
+ return lookup_name_real (name, 0, 1, 0);
+}
+
+tree
+lookup_function_nonclass (name, args)
+ tree name;
+ tree args;
+{
+ return lookup_arg_dependent (name, lookup_name_nonclass (name), args);
+}
+
+tree
+lookup_name_namespace_only (name)
+ tree name;
+{
+ /* type-or-namespace, nonclass, namespace_only */
+ return lookup_name_real (name, 1, 1, 1);
}
tree
@@ -4511,7 +5141,7 @@ lookup_name (name, prefer_type)
tree name;
int prefer_type;
{
- return lookup_name_real (name, prefer_type, 0);
+ return lookup_name_real (name, prefer_type, 0, 0);
}
/* Similar to `lookup_name' but look only at current binding level. */
@@ -4522,9 +5152,9 @@ lookup_name_current_level (name)
{
register tree t = NULL_TREE;
- if (current_binding_level == global_binding_level)
+ if (current_binding_level->namespace_p)
{
- t = IDENTIFIER_GLOBAL_VALUE (name);
+ t = IDENTIFIER_NAMESPACE_VALUE (name);
/* extern "C" function() */
if (t != NULL_TREE && TREE_CODE (t) == TREE_LIST)
@@ -4535,20 +5165,57 @@ lookup_name_current_level (name)
struct binding_level *b = current_binding_level;
while (1)
{
- for (t = b->names; t; t = TREE_CHAIN (t))
- if (DECL_NAME (t) == name || DECL_ASSEMBLER_NAME (t) == name)
- goto out;
+ if (purpose_member (name, b->shadowed))
+ return IDENTIFIER_LOCAL_VALUE (name);
if (b->keep == 2)
b = b->level_chain;
else
break;
}
- out:
- ;
}
return t;
}
+
+/* Like lookup_name_current_level, but for types. */
+
+tree
+lookup_type_current_level (name)
+ tree name;
+{
+ register tree t = NULL_TREE;
+
+ my_friendly_assert (! current_binding_level->namespace_p, 980716);
+
+ if (REAL_IDENTIFIER_TYPE_VALUE (name) != NULL_TREE
+ && REAL_IDENTIFIER_TYPE_VALUE (name) != global_type_node)
+ {
+ struct binding_level *b = current_binding_level;
+ while (1)
+ {
+ if (purpose_member (name, b->type_shadowed))
+ return REAL_IDENTIFIER_TYPE_VALUE (name);
+ if (b->keep == 2)
+ b = b->level_chain;
+ else
+ break;
+ }
+ }
+
+ return t;
+}
+
+void
+begin_only_namespace_names ()
+{
+ only_namespace_names = 1;
+}
+
+void
+end_only_namespace_names ()
+{
+ only_namespace_names = 0;
+}
/* Arrange for the user to get a source line number, even when the
compiler is going down in flames, so that she at least has a
@@ -4559,7 +5226,7 @@ lookup_name_current_level (name)
static void
signal_catch (sig)
- int sig;
+ int sig ATTRIBUTE_UNUSED;
{
signal (SIGSEGV, SIG_DFL);
#ifdef SIGIOT
@@ -4577,10 +5244,13 @@ signal_catch (sig)
my_friendly_abort (0);
}
+#if 0
+/* Unused -- brendan 970107 */
/* Array for holding types considered "built-in". These types
are output in the module in which `main' is defined. */
static tree *builtin_type_tdescs_arr;
static int builtin_type_tdescs_len, builtin_type_tdescs_max;
+#endif
/* Push the declarations of builtin types into the namespace.
RID_INDEX, if < RID_MAX is the index of the builtin type
@@ -4594,7 +5264,7 @@ record_builtin_type (rid_index, name, type)
tree type;
{
tree rname = NULL_TREE, tname = NULL_TREE;
- tree tdecl;
+ tree tdecl = NULL_TREE;
if ((int) rid_index < (int) RID_MAX)
rname = ridpointers[(int) rid_index];
@@ -4605,84 +5275,77 @@ record_builtin_type (rid_index, name, type)
if (tname)
{
-#if 0 /* not yet, should get fixed properly later */
- tdecl = pushdecl (make_type_decl (tname, type));
-#else
tdecl = pushdecl (build_decl (TYPE_DECL, tname, type));
-#endif
set_identifier_type_value (tname, NULL_TREE);
if ((int) rid_index < (int) RID_MAX)
- IDENTIFIER_GLOBAL_VALUE (tname) = tdecl;
+ /* Built-in types live in the global namespace. */
+ SET_IDENTIFIER_GLOBAL_VALUE (tname, tdecl);
}
if (rname != NULL_TREE)
{
if (tname != NULL_TREE)
{
set_identifier_type_value (rname, NULL_TREE);
- IDENTIFIER_GLOBAL_VALUE (rname) = tdecl;
+ SET_IDENTIFIER_GLOBAL_VALUE (rname, tdecl);
}
else
{
-#if 0 /* not yet, should get fixed properly later */
- tdecl = pushdecl (make_type_decl (rname, type));
-#else
tdecl = pushdecl (build_decl (TYPE_DECL, rname, type));
-#endif
set_identifier_type_value (rname, NULL_TREE);
}
}
+}
- if (flag_rtti)
- {
- if (builtin_type_tdescs_len+5 >= builtin_type_tdescs_max)
- {
- builtin_type_tdescs_max *= 2;
- builtin_type_tdescs_arr
- = (tree *)xrealloc (builtin_type_tdescs_arr,
- builtin_type_tdescs_max * sizeof (tree));
- }
- builtin_type_tdescs_arr[builtin_type_tdescs_len++] = type;
- if (TREE_CODE (type) != POINTER_TYPE)
- {
- builtin_type_tdescs_arr[builtin_type_tdescs_len++]
- = build_pointer_type (type);
- builtin_type_tdescs_arr[builtin_type_tdescs_len++]
- = build_pointer_type (build_type_variant (type, 1, 0));
- }
- if (TREE_CODE (type) != VOID_TYPE)
- {
- builtin_type_tdescs_arr[builtin_type_tdescs_len++]
- = build_reference_type (type);
- builtin_type_tdescs_arr[builtin_type_tdescs_len++]
- = build_reference_type (build_type_variant (type, 1, 0));
- }
+/* Record one of the standard Java types.
+ * Declare it as having the given NAME.
+ * If SIZE > 0, it is the size of one of the integral types;
+ * otherwise it is the negative of the size of one of the other types. */
+
+static tree
+record_builtin_java_type (name, size)
+ char *name;
+ int size;
+{
+ tree type, decl;
+ if (size > 0)
+ type = make_signed_type (size);
+ else if (size > -32)
+ { /* "__java_char" or ""__java_boolean". */
+ type = make_unsigned_type (-size);
+ /*if (size == -1) TREE_SET_CODE (type, BOOLEAN_TYPE);*/
}
+ else
+ { /* "__java_float" or ""__java_double". */
+ type = make_node (REAL_TYPE);
+ TYPE_PRECISION (type) = - size;
+ layout_type (type);
+ }
+ record_builtin_type (RID_MAX, name, type);
+ decl = TYPE_NAME (type);
+ DECL_IGNORED_P (decl) = 1;
+ TYPE_FOR_JAVA (type) = 1;
+ return type;
}
+/* Push a type into the namespace so that the back-ends ignore it. */
+
static void
-output_builtin_tdesc_entries ()
+record_unknown_type (type, name)
+ tree type;
+ char *name;
{
- extern struct obstack permanent_obstack;
-
- /* If there's more than one main in this file, don't crash. */
- if (builtin_type_tdescs_arr == 0)
- return;
-
- push_obstacks (&permanent_obstack, &permanent_obstack);
- while (builtin_type_tdescs_len > 0)
- {
- tree type = builtin_type_tdescs_arr[--builtin_type_tdescs_len];
- tree tdesc = build_t_desc (type, 0);
- TREE_ASM_WRITTEN (tdesc) = 0;
- build_t_desc (type, 2);
- }
- free (builtin_type_tdescs_arr);
- builtin_type_tdescs_arr = 0;
- pop_obstacks ();
-}
+ tree decl = pushdecl (build_decl (TYPE_DECL, get_identifier (name), type));
+ /* Make sure the "unknown type" typedecl gets ignored for debug info. */
+ DECL_IGNORED_P (decl) = 1;
+ TYPE_DECL_SUPPRESS_DEBUG (decl) = 1;
+ TYPE_SIZE (type) = TYPE_SIZE (void_type_node);
+ TYPE_ALIGN (type) = 1;
+ TYPE_MODE (type) = TYPE_MODE (void_type_node);
+}
/* Push overloaded decl, in global scope, with one argument so it
can be used as a callback from define_function. */
+
static void
push_overloaded_decl_1 (x)
tree x;
@@ -4690,18 +5353,16 @@ push_overloaded_decl_1 (x)
push_overloaded_decl (x, 0);
}
-#define builtin_function(NAME, TYPE, CODE, LIBNAME) \
- define_function (NAME, TYPE, CODE, (void (*)())pushdecl, LIBNAME)
-
#ifdef __GNUC__
__inline
#endif
-tree auto_function (name, type, code)
+tree
+auto_function (name, type, code)
tree name, type;
enum built_in_function code;
{
return define_function
- (IDENTIFIER_POINTER (name), type, code, (void (*)())push_overloaded_decl_1,
+ (IDENTIFIER_POINTER (name), type, code, push_overloaded_decl_1,
IDENTIFIER_POINTER (build_decl_overload (name, TYPE_ARG_TYPES (type),
0)));
}
@@ -4714,25 +5375,33 @@ tree auto_function (name, type, code)
void
init_decl_processing ()
{
- tree decl;
- register tree endlink, int_endlink, double_endlink, ptr_endlink;
+ register tree endlink, int_endlink, double_endlink, unsigned_endlink;
tree fields[20];
- /* Either char* or void*. */
- tree traditional_ptr_type_node;
/* Data type of memcpy. */
- tree memcpy_ftype;
-#if 0 /* Not yet. */
- /* Data type of strncpy. */
- tree strncpy_ftype;
-#endif
+ tree memcpy_ftype, strlen_ftype;
int wchar_type_size;
tree temp;
tree array_domain_type;
extern int flag_strict_prototype;
+ tree vb_off_identifier = NULL_TREE;
+ /* Function type `char *(char *, char *)' and similar ones */
+ tree string_ftype_ptr_ptr, int_ftype_string_string;
+ tree sizetype_endlink;
+ tree ptr_ftype, ptr_ftype_unsigned, ptr_ftype_sizetype;
+ tree void_ftype, void_ftype_int, void_ftype_ptr, ptr_ftype_void;
/* Have to make these distinct before we try using them. */
lang_name_cplusplus = get_identifier ("C++");
lang_name_c = get_identifier ("C");
+ lang_name_java = get_identifier ("Java");
+
+ /* Enter the global namespace. */
+ my_friendly_assert (global_namespace == NULL_TREE, 375);
+ my_friendly_assert (current_lang_name == NULL_TREE, 375);
+ current_lang_name = lang_name_cplusplus;
+ push_namespace (get_identifier ("::"));
+ global_namespace = current_namespace;
+ current_lang_name = NULL_TREE;
if (flag_strict_prototype == 2)
{
@@ -4747,19 +5416,20 @@ init_decl_processing ()
current_function_decl = NULL_TREE;
named_labels = NULL_TREE;
- named_label_uses = NULL_TREE;
+ named_label_uses = NULL;
current_binding_level = NULL_BINDING_LEVEL;
free_binding_level = NULL_BINDING_LEVEL;
+#ifndef __CYGWIN32__
/* Because most segmentation signals can be traced back into user
code, catch them and at least give the user a chance of working
- around compiler bugs. */
+ around compiler bugs. */
signal (SIGSEGV, signal_catch);
/* We will also catch aborts in the back-end through signal_catch and
give the user a chance to see where the error might be, and to defeat
aborts in the back-end when there have been errors previously in their
- code. */
+ code. */
#ifdef SIGIOT
signal (SIGIOT, signal_catch);
#endif
@@ -4772,13 +5442,15 @@ init_decl_processing ()
#ifdef SIGBUS
signal (SIGBUS, signal_catch);
#endif
+#else /* ndef __CYGWIN32__ */
+ /* Cygwin32 cannot handle catching signals other than
+ SIGABRT yet. We hope this will cease to be the case soon. */
+#ifdef SIGABRT
+ signal (SIGABRT, signal_catch);
+#endif
+#endif /* ndef __CYGWIN32__ */
gcc_obstack_init (&decl_obstack);
- if (flag_rtti)
- {
- builtin_type_tdescs_max = 100;
- builtin_type_tdescs_arr = (tree *)xmalloc (100 * sizeof (tree));
- }
/* Must lay these out before anything else gets laid out. */
error_mark_node = make_node (ERROR_MARK);
@@ -4790,9 +5462,14 @@ init_decl_processing ()
/* Make the binding_level structure for global names. */
pushlevel (0);
global_binding_level = current_binding_level;
+ /* The global level is the namespace level of ::. */
+ NAMESPACE_LEVEL (global_namespace) = global_binding_level;
+ declare_namespace_level ();
this_identifier = get_identifier (THIS_NAME);
in_charge_identifier = get_identifier (IN_CHARGE_NAME);
+ ctor_identifier = get_identifier (CTOR_NAME);
+ dtor_identifier = get_identifier (DTOR_NAME);
pfn_identifier = get_identifier (VTABLE_PFN_NAME);
index_identifier = get_identifier (VTABLE_INDEX_NAME);
delta_identifier = get_identifier (VTABLE_DELTA_NAME);
@@ -4813,10 +5490,10 @@ init_decl_processing ()
/* Define `char', which is like either `signed char' or `unsigned char'
but not the same as either. */
- char_type_node =
- (flag_signed_char
- ? make_signed_type (CHAR_TYPE_SIZE)
- : make_unsigned_type (CHAR_TYPE_SIZE));
+ char_type_node
+ = (flag_signed_char
+ ? make_signed_type (CHAR_TYPE_SIZE)
+ : make_unsigned_type (CHAR_TYPE_SIZE));
record_builtin_type (RID_CHAR, "char", char_type_node);
long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
@@ -4838,32 +5515,21 @@ init_decl_processing ()
record_builtin_type (RID_MAX, "long long unsigned",
long_long_unsigned_type_node);
- /* `unsigned long' is the standard type for sizeof.
- Traditionally, use a signed type.
- Note that stddef.h uses `unsigned long',
- and this must agree, even of long and int are the same size. */
- sizetype
- = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)));
- if (flag_traditional && TREE_UNSIGNED (sizetype))
- sizetype = signed_type (sizetype);
-
- ptrdiff_type_node
- = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
-
- TREE_TYPE (TYPE_SIZE (integer_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (char_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (unsigned_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (long_unsigned_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (long_integer_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (long_long_integer_type_node)) = sizetype;
- TREE_TYPE (TYPE_SIZE (long_long_unsigned_type_node)) = sizetype;
-
short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
record_builtin_type (RID_SHORT, "short int", short_integer_type_node);
short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
record_builtin_type (RID_MAX, "short unsigned int", short_unsigned_type_node);
record_builtin_type (RID_MAX, "unsigned short", short_unsigned_type_node);
+ /* `unsigned long' is the standard type for sizeof.
+ Note that stddef.h uses `unsigned long',
+ and this must agree, even if long and int are the same size. */
+ set_sizetype
+ (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))));
+
+ ptrdiff_type_node
+ = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
+
/* Define both `signed char' and `unsigned char'. */
signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
record_builtin_type (RID_MAX, "signed char", signed_char_type_node);
@@ -4879,6 +5545,8 @@ init_decl_processing ()
pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node));
intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
+ intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
+ pushdecl (build_decl (TYPE_DECL, NULL_TREE, intTI_type_node));
unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
@@ -4887,6 +5555,8 @@ init_decl_processing ()
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node));
unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node));
+ unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
+ pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intTI_type_node));
float_type_node = make_node (REAL_TYPE);
TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
@@ -4906,6 +5576,39 @@ init_decl_processing ()
record_builtin_type (RID_MAX, "long double", long_double_type_node);
layout_type (long_double_type_node);
+ complex_integer_type_node = make_node (COMPLEX_TYPE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"),
+ complex_integer_type_node));
+ TREE_TYPE (complex_integer_type_node) = integer_type_node;
+ layout_type (complex_integer_type_node);
+
+ complex_float_type_node = make_node (COMPLEX_TYPE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
+ complex_float_type_node));
+ TREE_TYPE (complex_float_type_node) = float_type_node;
+ layout_type (complex_float_type_node);
+
+ complex_double_type_node = make_node (COMPLEX_TYPE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"),
+ complex_double_type_node));
+ TREE_TYPE (complex_double_type_node) = double_type_node;
+ layout_type (complex_double_type_node);
+
+ complex_long_double_type_node = make_node (COMPLEX_TYPE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"),
+ complex_long_double_type_node));
+ TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
+ layout_type (complex_long_double_type_node);
+
+ java_byte_type_node = record_builtin_java_type ("__java_byte", 8);
+ java_short_type_node = record_builtin_java_type ("__java_short", 16);
+ java_int_type_node = record_builtin_java_type ("__java_int", 32);
+ java_long_type_node = record_builtin_java_type ("__java_long", 64);
+ java_float_type_node = record_builtin_java_type ("__java_float", -32);
+ java_double_type_node = record_builtin_java_type ("__java_double", -64);
+ java_char_type_node = record_builtin_java_type ("__java_char", -16);
+ java_boolean_type_node = record_builtin_java_type ("__java_boolean", -1);
+
integer_zero_node = build_int_2 (0, 0);
TREE_TYPE (integer_zero_node) = integer_type_node;
integer_one_node = build_int_2 (1, 0);
@@ -4917,6 +5620,9 @@ init_decl_processing ()
boolean_type_node = make_unsigned_type (BOOL_TYPE_SIZE);
TREE_SET_CODE (boolean_type_node, BOOLEAN_TYPE);
+ TYPE_MAX_VALUE (boolean_type_node) = build_int_2 (1, 0);
+ TREE_TYPE (TYPE_MAX_VALUE (boolean_type_node)) = boolean_type_node;
+ TYPE_PRECISION (boolean_type_node) = 1;
record_builtin_type (RID_BOOL, "bool", boolean_type_node);
boolean_false_node = build_int_2 (0, 0);
TREE_TYPE (boolean_false_node) = boolean_type_node;
@@ -4927,6 +5633,9 @@ init_decl_processing ()
size_zero_node = size_int (0);
size_one_node = size_int (1);
+ signed_size_zero_node = build_int_2 (0, 0);
+ TREE_TYPE (signed_size_zero_node) = make_signed_type (TYPE_PRECISION (sizetype));
+
void_type_node = make_node (VOID_TYPE);
record_builtin_type (RID_VOID, NULL_PTR, void_type_node);
layout_type (void_type_node); /* Uses integer_zero_node. */
@@ -4936,15 +5645,17 @@ init_decl_processing ()
null_pointer_node = build_int_2 (0, 0);
TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
layout_type (TREE_TYPE (null_pointer_node));
-
+
/* Used for expressions that do nothing, but are not errors. */
void_zero_node = build_int_2 (0, 0);
TREE_TYPE (void_zero_node) = void_type_node;
string_type_node = build_pointer_type (char_type_node);
- const_string_type_node =
- build_pointer_type (build_type_variant (char_type_node, 1, 0));
+ const_string_type_node
+ = build_pointer_type (build_type_variant (char_type_node, 1, 0));
+#if 0
record_builtin_type (RID_MAX, NULL_PTR, string_type_node);
+#endif
/* Make a type to be the domain of a few array types
whose domains don't really matter.
@@ -4953,7 +5664,7 @@ init_decl_processing ()
initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */
array_domain_type = build_index_type (build_int_2 (200, 0));
- /* make a type for arrays of characters.
+ /* Make a type for arrays of characters.
With luck nothing will ever really depend on the length of this
array type. */
char_array_type_node
@@ -4968,20 +5679,45 @@ init_decl_processing ()
default_function_type
= build_function_type (integer_type_node, NULL_TREE);
- build_pointer_type (default_function_type);
ptr_type_node = build_pointer_type (void_type_node);
- const_ptr_type_node =
- build_pointer_type (build_type_variant (void_type_node, 1, 0));
+ const_ptr_type_node
+ = build_pointer_type (build_type_variant (void_type_node, 1, 0));
+#if 0
record_builtin_type (RID_MAX, NULL_PTR, ptr_type_node);
+#endif
endlink = void_list_node;
int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
double_endlink = tree_cons (NULL_TREE, double_type_node, endlink);
- ptr_endlink = tree_cons (NULL_TREE, ptr_type_node, endlink);
+ unsigned_endlink = tree_cons (NULL_TREE, unsigned_type_node, endlink);
+
+ ptr_ftype = build_function_type (ptr_type_node, NULL_TREE);
+ ptr_ftype_unsigned = build_function_type (ptr_type_node, unsigned_endlink);
+ sizetype_endlink = tree_cons (NULL_TREE, sizetype, endlink);
+ /* We realloc here because sizetype could be int or unsigned. S'ok. */
+ ptr_ftype_sizetype = build_function_type (ptr_type_node, sizetype_endlink);
+
+ void_ftype = build_function_type (void_type_node, endlink);
+ void_ftype_int = build_function_type (void_type_node, int_endlink);
+ void_ftype_ptr
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node, endlink));
+ void_ftype_ptr
+ = build_exception_variant (void_ftype_ptr,
+ tree_cons (NULL_TREE, NULL_TREE, NULL_TREE));
+
+ float_ftype_float
+ = build_function_type (float_type_node,
+ tree_cons (NULL_TREE, float_type_node, endlink));
double_ftype_double
= build_function_type (double_type_node, double_endlink);
+ ldouble_ftype_ldouble
+ = build_function_type (long_double_type_node,
+ tree_cons (NULL_TREE, long_double_type_node,
+ endlink));
+
double_ftype_double_double
= build_function_type (double_type_node,
tree_cons (NULL_TREE, double_type_node,
@@ -4995,12 +5731,6 @@ init_decl_processing ()
tree_cons (NULL_TREE, long_integer_type_node,
endlink));
- void_ftype_ptr_ptr_int
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- int_endlink)));
-
int_ftype_cptr_cptr_sizet
= build_function_type (integer_type_node,
tree_cons (NULL_TREE, const_ptr_type_node,
@@ -5009,12 +5739,6 @@ init_decl_processing ()
sizetype,
endlink))));
- void_ftype_ptr_int_int
- = build_function_type (void_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- tree_cons (NULL_TREE, integer_type_node,
- int_endlink)));
-
string_ftype_ptr_ptr /* strcpy prototype */
= build_function_type (string_type_node,
tree_cons (NULL_TREE, string_type_node,
@@ -5022,17 +5746,6 @@ init_decl_processing ()
const_string_type_node,
endlink)));
-#if 0
- /* Not yet. */
- strncpy_ftype /* strncpy prototype */
- = build_function_type (string_type_node,
- tree_cons (NULL_TREE, string_type_node,
- tree_cons (NULL_TREE, const_string_type_node,
- tree_cons (NULL_TREE,
- sizetype,
- endlink))));
-#endif
-
int_ftype_string_string /* strcmp prototype */
= build_function_type (integer_type_node,
tree_cons (NULL_TREE, const_string_type_node,
@@ -5040,69 +5753,51 @@ init_decl_processing ()
const_string_type_node,
endlink)));
- sizet_ftype_string /* strlen prototype */
+ strlen_ftype /* strlen prototype */
= build_function_type (sizetype,
tree_cons (NULL_TREE, const_string_type_node,
endlink));
- traditional_ptr_type_node
- = (flag_traditional ? string_type_node : ptr_type_node);
-
memcpy_ftype /* memcpy prototype */
- = build_function_type (traditional_ptr_type_node,
+ = build_function_type (ptr_type_node,
tree_cons (NULL_TREE, ptr_type_node,
tree_cons (NULL_TREE, const_ptr_type_node,
- tree_cons (NULL_TREE,
- sizetype,
- endlink))));
+ sizetype_endlink)));
if (flag_huge_objects)
delta_type_node = long_integer_type_node;
else
delta_type_node = short_integer_type_node;
- builtin_function ("__builtin_constant_p", int_ftype_int,
+ builtin_function ("__builtin_constant_p", default_function_type,
BUILT_IN_CONSTANT_P, NULL_PTR);
- builtin_return_address_fndecl =
- builtin_function ("__builtin_return_address",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE,
- unsigned_type_node,
- endlink)),
- BUILT_IN_RETURN_ADDRESS, NULL_PTR);
+ builtin_return_address_fndecl
+ = builtin_function ("__builtin_return_address", ptr_ftype_unsigned,
+ BUILT_IN_RETURN_ADDRESS, NULL_PTR);
- builtin_function ("__builtin_frame_address",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE,
- unsigned_type_node,
- endlink)),
+ builtin_function ("__builtin_frame_address", ptr_ftype_unsigned,
BUILT_IN_FRAME_ADDRESS, NULL_PTR);
+ ptr_ftype_void = build_function_type (ptr_type_node, endlink);
+ builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
+ builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
- builtin_function ("__builtin_alloca",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE,
- sizetype,
- endlink)),
+ builtin_function ("__builtin_alloca", ptr_ftype_sizetype,
BUILT_IN_ALLOCA, "alloca");
+ builtin_function ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
/* Define alloca, ffs as builtins.
Declare _exit just to mark it as volatile. */
if (! flag_no_builtin && !flag_no_nonansi_builtin)
{
- temp = builtin_function ("alloca",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE,
- sizetype,
- endlink)),
+ temp = builtin_function ("alloca", ptr_ftype_sizetype,
BUILT_IN_ALLOCA, NULL_PTR);
/* Suppress error if redefined as a non-function. */
DECL_BUILT_IN_NONANSI (temp) = 1;
temp = builtin_function ("ffs", int_ftype_int, BUILT_IN_FFS, NULL_PTR);
/* Suppress error if redefined as a non-function. */
DECL_BUILT_IN_NONANSI (temp) = 1;
- temp = builtin_function ("_exit", build_function_type (void_type_node,
- int_endlink),
+ temp = builtin_function ("_exit", void_ftype_int,
NOT_BUILT_IN, NULL_PTR);
TREE_THIS_VOLATILE (temp) = 1;
TREE_SIDE_EFFECTS (temp) = 1;
@@ -5110,65 +5805,48 @@ init_decl_processing ()
DECL_BUILT_IN_NONANSI (temp) = 1;
}
- builtin_function ("__builtin_abs", int_ftype_int,
- BUILT_IN_ABS, NULL_PTR);
- builtin_function ("__builtin_fabs", double_ftype_double,
- BUILT_IN_FABS, NULL_PTR);
+ builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR);
+ builtin_function ("__builtin_fabsf", float_ftype_float, BUILT_IN_FABS,
+ NULL_PTR);
+ builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS,
+ NULL_PTR);
+ builtin_function ("__builtin_fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS,
+ NULL_PTR);
builtin_function ("__builtin_labs", long_ftype_long,
BUILT_IN_LABS, NULL_PTR);
- builtin_function ("__builtin_ffs", int_ftype_int,
- BUILT_IN_FFS, NULL_PTR);
- builtin_function ("__builtin_fsqrt", double_ftype_double,
- BUILT_IN_FSQRT, NULL_PTR);
- builtin_function ("__builtin_sin", double_ftype_double,
- BUILT_IN_SIN, "sin");
- builtin_function ("__builtin_cos", double_ftype_double,
- BUILT_IN_COS, "cos");
- builtin_function ("__builtin_saveregs",
- build_function_type (ptr_type_node, NULL_TREE),
+ builtin_function ("__builtin_saveregs", ptr_ftype,
BUILT_IN_SAVEREGS, NULL_PTR);
-/* EXPAND_BUILTIN_VARARGS is obsolete. */
-#if 0
- builtin_function ("__builtin_varargs",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE,
- integer_type_node,
- endlink)),
- BUILT_IN_VARARGS, NULL_PTR);
-#endif
builtin_function ("__builtin_classify_type", default_function_type,
BUILT_IN_CLASSIFY_TYPE, NULL_PTR);
- builtin_function ("__builtin_next_arg",
- build_function_type (ptr_type_node, NULL_TREE),
+ builtin_function ("__builtin_next_arg", ptr_ftype,
BUILT_IN_NEXT_ARG, NULL_PTR);
- builtin_function ("__builtin_args_info",
+ builtin_function ("__builtin_args_info", int_ftype_int,
+ BUILT_IN_ARGS_INFO, NULL_PTR);
+ builtin_function ("__builtin_setjmp",
build_function_type (integer_type_node,
- tree_cons (NULL_TREE,
- integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
endlink)),
- BUILT_IN_ARGS_INFO, NULL_PTR);
+ BUILT_IN_SETJMP, NULL_PTR);
+ builtin_function ("__builtin_longjmp",
+ build_function_type (integer_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ tree_cons (NULL_TREE,
+ integer_type_node,
+ endlink))),
+ BUILT_IN_LONGJMP, NULL_PTR);
/* Untyped call and return. */
- builtin_function ("__builtin_apply_args",
- build_function_type (ptr_type_node, NULL_TREE),
+ builtin_function ("__builtin_apply_args", ptr_ftype,
BUILT_IN_APPLY_ARGS, NULL_PTR);
temp = tree_cons (NULL_TREE,
build_pointer_type (build_function_type (void_type_node,
NULL_TREE)),
- tree_cons (NULL_TREE,
- ptr_type_node,
- tree_cons (NULL_TREE,
- sizetype,
- endlink)));
+ tree_cons (NULL_TREE, ptr_ftype_sizetype, NULL_TREE));
builtin_function ("__builtin_apply",
build_function_type (ptr_type_node, temp),
BUILT_IN_APPLY, NULL_PTR);
- builtin_function ("__builtin_return",
- build_function_type (void_type_node,
- tree_cons (NULL_TREE,
- ptr_type_node,
- endlink)),
+ builtin_function ("__builtin_return", void_ftype_ptr,
BUILT_IN_RETURN, NULL_PTR);
/* Currently under experimentation. */
@@ -5180,47 +5858,64 @@ init_decl_processing ()
BUILT_IN_STRCMP, "strcmp");
builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
BUILT_IN_STRCPY, "strcpy");
-#if 0
- /* Not yet. */
- builtin_function ("__builtin_strncpy", strncpy_ftype,
- BUILT_IN_STRNCPY, "strncpy");
-#endif
- builtin_function ("__builtin_strlen", sizet_ftype_string,
+ builtin_function ("__builtin_strlen", strlen_ftype,
BUILT_IN_STRLEN, "strlen");
+ builtin_function ("__builtin_sqrtf", float_ftype_float,
+ BUILT_IN_FSQRT, "sqrtf");
+ builtin_function ("__builtin_fsqrt", double_ftype_double,
+ BUILT_IN_FSQRT, NULL_PTR);
+ builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble,
+ BUILT_IN_FSQRT, "sqrtl");
+ builtin_function ("__builtin_sinf", float_ftype_float,
+ BUILT_IN_SIN, "sinf");
+ builtin_function ("__builtin_sin", double_ftype_double,
+ BUILT_IN_SIN, "sin");
+ builtin_function ("__builtin_sinl", ldouble_ftype_ldouble,
+ BUILT_IN_SIN, "sinl");
+ builtin_function ("__builtin_cosf", float_ftype_float,
+ BUILT_IN_COS, "cosf");
+ builtin_function ("__builtin_cos", double_ftype_double,
+ BUILT_IN_COS, "cos");
+ builtin_function ("__builtin_cosl", ldouble_ftype_ldouble,
+ BUILT_IN_COS, "cosl");
if (!flag_no_builtin)
{
-#if 0 /* These do not work well with libg++. */
builtin_function ("abs", int_ftype_int, BUILT_IN_ABS, NULL_PTR);
builtin_function ("fabs", double_ftype_double, BUILT_IN_FABS, NULL_PTR);
builtin_function ("labs", long_ftype_long, BUILT_IN_LABS, NULL_PTR);
-#endif
+ builtin_function ("fabsf", float_ftype_float, BUILT_IN_FABS, NULL_PTR);
+ builtin_function ("fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS,
+ NULL_PTR);
builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR);
builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP,
NULL_PTR);
- builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP, NULL_PTR);
+ builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP,
+ NULL_PTR);
builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
NULL_PTR);
-#if 0
- /* Not yet. */
- builtin_function ("strncpy", strncpy_ftype, BUILT_IN_STRNCPY, NULL_PTR);
-#endif
- builtin_function ("strlen", sizet_ftype_string, BUILT_IN_STRLEN, NULL_PTR);
+ builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN, NULL_PTR);
+ builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT, NULL_PTR);
+ builtin_function ("sqrt", double_ftype_double, BUILT_IN_FSQRT, NULL_PTR);
+ builtin_function ("sqrtl", ldouble_ftype_ldouble, BUILT_IN_FSQRT,
+ NULL_PTR);
+ builtin_function ("sinf", float_ftype_float, BUILT_IN_SIN, NULL_PTR);
builtin_function ("sin", double_ftype_double, BUILT_IN_SIN, NULL_PTR);
+ builtin_function ("sinl", ldouble_ftype_ldouble, BUILT_IN_SIN, NULL_PTR);
+ builtin_function ("cosf", float_ftype_float, BUILT_IN_COS, NULL_PTR);
builtin_function ("cos", double_ftype_double, BUILT_IN_COS, NULL_PTR);
+ builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS, NULL_PTR);
/* Declare these functions volatile
to avoid spurious "control drops through" warnings. */
- temp = builtin_function ("abort",
- build_function_type (void_type_node, endlink),
+ temp = builtin_function ("abort", void_ftype,
NOT_BUILT_IN, NULL_PTR);
TREE_THIS_VOLATILE (temp) = 1;
TREE_SIDE_EFFECTS (temp) = 1;
/* Well, these are actually ANSI, but we can't set DECL_BUILT_IN on
them... */
DECL_BUILT_IN_NONANSI (temp) = 1;
- temp = builtin_function ("exit", build_function_type (void_type_node,
- int_endlink),
+ temp = builtin_function ("exit", void_ftype_int,
NOT_BUILT_IN, NULL_PTR);
TREE_THIS_VOLATILE (temp) = 1;
TREE_SIDE_EFFECTS (temp) = 1;
@@ -5230,42 +5925,39 @@ init_decl_processing ()
#if 0
/* Support for these has not been written in either expand_builtin
or build_function_call. */
- builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, 0);
- builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, 0);
+ builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV, NULL_PTR);
+ builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV, NULL_PTR);
builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR,
- 0);
- builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL, 0);
+ NULL_PTR);
+ builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL,
+ NULL_PTR);
builtin_function ("__builtin_fmod", double_ftype_double_double,
- BUILT_IN_FMOD, 0);
+ BUILT_IN_FMOD, NULL_PTR);
builtin_function ("__builtin_frem", double_ftype_double_double,
- BUILT_IN_FREM, 0);
- builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int, BUILT_IN_MEMSET,
- 0);
+ BUILT_IN_FREM, NULL_PTR);
+ builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int,
+ BUILT_IN_MEMSET, NULL_PTR);
builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
- 0);
+ NULL_PTR);
builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
- 0);
+ NULL_PTR);
#endif
/* C++ extensions */
unknown_type_node = make_node (UNKNOWN_TYPE);
-#if 0 /* not yet, should get fixed properly later */
- pushdecl (make_type_decl (get_identifier ("unknown type"),
- unknown_type_node));
-#else
- decl = pushdecl (build_decl (TYPE_DECL, get_identifier ("unknown type"),
- unknown_type_node));
- /* Make sure the "unknown type" typedecl gets ignored for debug info. */
- DECL_IGNORED_P (decl) = 1;
- TYPE_DECL_SUPPRESS_DEBUG (decl) = 1;
-#endif
- TYPE_SIZE (unknown_type_node) = TYPE_SIZE (void_type_node);
- TYPE_ALIGN (unknown_type_node) = 1;
- TYPE_MODE (unknown_type_node) = TYPE_MODE (void_type_node);
+ record_unknown_type (unknown_type_node, "unknown type");
+
/* Indirecting an UNKNOWN_TYPE node yields an UNKNOWN_TYPE node. */
TREE_TYPE (unknown_type_node) = unknown_type_node;
- /* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same result. */
+
+ if (flag_ansi)
+ TREE_TYPE (null_node) = type_for_size (POINTER_SIZE, 0);
+ else
+ TREE_TYPE (null_node) = build_pointer_type (unknown_type_node);
+
+ /* Looking up TYPE_POINTER_TO and TYPE_REFERENCE_TO yield the same
+ result. */
TYPE_POINTER_TO (unknown_type_node) = unknown_type_node;
TYPE_REFERENCE_TO (unknown_type_node) = unknown_type_node;
@@ -5274,7 +5966,7 @@ init_decl_processing ()
TYPE_MAIN_VARIANT (opaque_type_node) = opaque_type_node;
record_builtin_type (RID_MAX, 0, opaque_type_node);
- /* This is special for C++ so functions can be overloaded. */
+ /* This is special for C++ so functions can be overloaded. */
wchar_type_node
= TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (WCHAR_TYPE)));
wchar_type_size = TYPE_PRECISION (wchar_type_node);
@@ -5295,14 +5987,6 @@ init_decl_processing ()
wchar_array_type_node
= build_array_type (wchar_type_node, array_domain_type);
- /* This is a hack that should go away when we deliver the
- real gc code. */
- if (flag_gc)
- {
- builtin_function ("__gc_main", default_function_type, NOT_BUILT_IN, 0);
- pushdecl (lookup_name (get_identifier ("__gc_main"), 0));
- }
-
if (flag_vtable_thunks)
{
/* Make sure we get a unique function type, so we can give
@@ -5381,254 +6065,79 @@ init_decl_processing ()
record_builtin_type (RID_MAX, SIGTABLE_PTR_TYPE, sigtable_entry_type);
}
-#if 0
- if (flag_rtti)
- {
- /* Must build __t_desc type. Currently, type descriptors look like this:
+ std_node = build_decl (NAMESPACE_DECL,
+ get_identifier (flag_honor_std ? "fake std":"std"),
+ void_type_node);
+ pushdecl (std_node);
- struct __t_desc
- {
- const char *name;
- int size;
- int bits;
- struct __t_desc *points_to;
- int ivars_count, meths_count;
- struct __i_desc *ivars[];
- struct __m_desc *meths[];
- struct __t_desc *parents[];
- struct __t_desc *vbases[];
- int offsets[];
- };
-
- ...as per Linton's paper. */
-
- __t_desc_type_node = make_lang_type (RECORD_TYPE);
- __i_desc_type_node = make_lang_type (RECORD_TYPE);
- __m_desc_type_node = make_lang_type (RECORD_TYPE);
- __t_desc_array_type =
- build_array_type (build_pointer_type (__t_desc_type_node), NULL_TREE);
- __i_desc_array_type =
- build_array_type (build_pointer_type (__i_desc_type_node), NULL_TREE);
- __m_desc_array_type =
- build_array_type (build_pointer_type (__m_desc_type_node), NULL_TREE);
-
- fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("name"),
- string_type_node);
- fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("size"),
- unsigned_type_node);
- fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("bits"),
- unsigned_type_node);
- fields[3] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("points_to"),
- build_pointer_type (__t_desc_type_node));
- fields[4] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("ivars_count"),
- integer_type_node);
- fields[5] = build_lang_field_decl (FIELD_DECL,
- get_identifier ("meths_count"),
- integer_type_node);
- fields[6] = build_lang_field_decl (FIELD_DECL, get_identifier ("ivars"),
- build_pointer_type (__i_desc_array_type));
- fields[7] = build_lang_field_decl (FIELD_DECL, get_identifier ("meths"),
- build_pointer_type (__m_desc_array_type));
- fields[8] = build_lang_field_decl (FIELD_DECL, get_identifier ("parents"),
- build_pointer_type (__t_desc_array_type));
- fields[9] = build_lang_field_decl (FIELD_DECL, get_identifier ("vbases"),
- build_pointer_type (__t_desc_array_type));
- fields[10] = build_lang_field_decl (FIELD_DECL, get_identifier ("offsets"),
- build_pointer_type (integer_type_node));
- finish_builtin_type (__t_desc_type_node, "__t_desc", fields, 10, integer_type_node);
-
- /* ivar descriptors look like this:
-
- struct __i_desc
- {
- const char *name;
- int offset;
- struct __t_desc *type;
- };
- */
-
- fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("name"),
- string_type_node);
- fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("offset"),
- integer_type_node);
- fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
- build_pointer_type (__t_desc_type_node));
- finish_builtin_type (__i_desc_type_node, "__i_desc", fields, 2,
- integer_type_node);
-
- /* method descriptors look like this:
-
- struct __m_desc
- {
- const char *name;
- int vindex;
- struct __t_desc *vcontext;
- struct __t_desc *return_type;
- void (*address)();
- short parm_count;
- short required_parms;
- struct __t_desc *parm_types[];
- };
- */
-
- fields[0] = build_lang_field_decl (FIELD_DECL, get_identifier ("name"),
- string_type_node);
- fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("vindex"),
- integer_type_node);
- fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("vcontext"),
- build_pointer_type (__t_desc_type_node));
- fields[3] = build_lang_field_decl (FIELD_DECL, get_identifier ("return_type"),
- build_pointer_type (__t_desc_type_node));
- fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("address"),
- build_pointer_type (default_function_type));
- fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("parm_count"),
- short_integer_type_node);
- fields[6] = build_lang_field_decl (FIELD_DECL, get_identifier ("required_parms"),
- short_integer_type_node);
- fields[7] = build_lang_field_decl (FIELD_DECL, get_identifier ("parm_types"),
- build_pointer_type (build_array_type (build_pointer_type (__t_desc_type_node), NULL_TREE)));
- finish_builtin_type (__m_desc_type_node, "__m_desc", fields, 7,
- integer_type_node);
- }
-
- if (flag_rtti)
- {
- int i = builtin_type_tdescs_len;
- while (i > 0)
- {
- tree tdesc = build_t_desc (builtin_type_tdescs_arr[--i], 0);
- TREE_ASM_WRITTEN (tdesc) = 1;
- TREE_PUBLIC (TREE_OPERAND (tdesc, 0)) = 1;
- }
- }
-#endif /*flag_rtti*/
+ global_type_node = make_node (LANG_TYPE);
+ record_unknown_type (global_type_node, "global type");
/* Now, C++. */
current_lang_name = lang_name_cplusplus;
- auto_function (ansi_opname[(int) NEW_EXPR],
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, sizetype,
- void_list_node)),
- NOT_BUILT_IN);
- auto_function (ansi_opname[(int) VEC_NEW_EXPR],
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, sizetype,
- void_list_node)),
- NOT_BUILT_IN);
- auto_function (ansi_opname[(int) DELETE_EXPR],
- build_function_type (void_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN);
- auto_function (ansi_opname[(int) VEC_DELETE_EXPR],
- build_function_type (void_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN);
+ {
+ tree bad_alloc_type_node, newtype, deltype;
+ if (flag_honor_std)
+ push_namespace (get_identifier ("std"));
+ bad_alloc_type_node = xref_tag
+ (class_type_node, get_identifier ("bad_alloc"), NULL_TREE, 1);
+ if (flag_honor_std)
+ pop_namespace ();
+ newtype = build_exception_variant
+ (ptr_ftype_sizetype, build_tree_list (NULL_TREE, bad_alloc_type_node));
+ deltype = build_exception_variant
+ (void_ftype_ptr, build_tree_list (NULL_TREE, NULL_TREE));
+ auto_function (ansi_opname[(int) NEW_EXPR], newtype, NOT_BUILT_IN);
+ auto_function (ansi_opname[(int) VEC_NEW_EXPR], newtype, NOT_BUILT_IN);
+ auto_function (ansi_opname[(int) DELETE_EXPR], deltype, NOT_BUILT_IN);
+ auto_function (ansi_opname[(int) VEC_DELETE_EXPR], deltype, NOT_BUILT_IN);
+ }
abort_fndecl
- = define_function ("__pure_virtual",
- build_function_type (void_type_node, void_list_node),
+ = define_function ("__pure_virtual", void_ftype,
NOT_BUILT_IN, 0, 0);
/* Perform other language dependent initializations. */
init_class_processing ();
init_init_processing ();
init_search_processing ();
+ if (flag_rtti)
+ init_rtti_processing ();
- if (flag_handle_exceptions)
+ if (flag_exceptions)
init_exception_processing ();
- if (flag_gc)
- init_gc_processing ();
if (flag_no_inline)
{
flag_inline_functions = 0;
-#if 0
- /* This causes unnecessary emission of inline functions. */
- flag_default_inline = 0;
-#endif
}
- if (flag_cadillac)
- init_cadillac ();
+
+ if (! supports_one_only ())
+ flag_weak = 0;
/* Create the global bindings for __FUNCTION__ and __PRETTY_FUNCTION__. */
declare_function_name ();
/* Prepare to check format strings against argument lists. */
init_function_format_info ();
-}
-
-/* initialize type descriptor type node of various rtti type. */
-
-int
-init_type_desc()
-{
- tree tdecl;
-
- tdecl = lookup_name (get_identifier ("type_info"), 0);
- if (tdecl == NULL_TREE)
- return 0;
- __t_desc_type_node = TREE_TYPE(tdecl);
- __tp_desc_type_node = build_pointer_type (__t_desc_type_node);
-
-#if 0
- tdecl = lookup_name (get_identifier ("__baselist_type_info"), 0);
- if (tdecl == NULL_TREE)
- return 0;
- __baselist_desc_type_node = TREE_TYPE (tdecl);
-#endif
-
- tdecl = lookup_name (get_identifier ("__builtin_type_info"), 0);
- if (tdecl == NULL_TREE)
- return 0;
- __bltn_desc_type_node = TREE_TYPE (tdecl);
-
- tdecl = lookup_name (get_identifier ("__user_type_info"), 0);
- if (tdecl == NULL_TREE)
- return 0;
- __user_desc_type_node = TREE_TYPE (tdecl);
-
- tdecl = lookup_name (get_identifier ("__class_type_info"), 0);
- if (tdecl == NULL_TREE)
- return 0;
- __class_desc_type_node = TREE_TYPE (tdecl);
-
- tdecl = lookup_field (__class_desc_type_node,
- get_identifier ("access_mode"), 0, 0);
- if (tdecl == NULL_TREE)
- return 0;
- __access_mode_type_node = TREE_TYPE (tdecl);
-
- tdecl = lookup_name (get_identifier ("__attr_type_info"), 0);
- if (tdecl == NULL_TREE)
- return 0;
- __attr_desc_type_node = TREE_TYPE (tdecl);
- tdecl = lookup_name (get_identifier ("__pointer_type_info"), 0);
- if (tdecl == NULL_TREE)
- return 0;
- __ptr_desc_type_node = TREE_TYPE (tdecl);
+ /* Show we use EH for cleanups. */
+ using_eh_for_cleanups ();
- tdecl = lookup_name (get_identifier ("__func_type_info"), 0);
- if (tdecl == NULL_TREE)
- return 0;
- __func_desc_type_node = TREE_TYPE (tdecl);
-
- tdecl = lookup_name (get_identifier ("__ptmf_type_info"), 0);
- if (tdecl == NULL_TREE)
- return 0;
- __ptmf_desc_type_node = TREE_TYPE (tdecl);
+ print_error_function = lang_print_error_function;
+ lang_get_alias_set = &c_get_alias_set;
+}
- tdecl = lookup_name (get_identifier ("__ptmd_type_info"), 0);
- if (tdecl == NULL_TREE)
- return 0;
- __ptmd_desc_type_node = TREE_TYPE (tdecl);
+/* Function to print any language-specific context for an error message. */
- return 1;
+static void
+lang_print_error_function (file)
+ char *file;
+{
+ default_print_error_function (file);
+ maybe_print_template_context ();
}
+
/* Make a definition for a builtin function named NAME and whose data type
is TYPE. TYPE should be a function type with argument types.
FUNCTION_CODE tells later passes how to compile calls to this function.
@@ -5642,7 +6151,7 @@ define_function (name, type, function_code, pfn, library_name)
char *name;
tree type;
enum built_in_function function_code;
- void (*pfn)();
+ void (*pfn) PROTO((tree));
char *library_name;
{
tree decl = build_lang_decl (FUNCTION_DECL, get_identifier (name), type);
@@ -5650,6 +6159,9 @@ define_function (name, type, function_code, pfn, library_name)
TREE_PUBLIC (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
+ my_friendly_assert (DECL_CONTEXT (decl) == NULL_TREE, 392);
+ DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
+
/* Since `pushdecl' relies on DECL_ASSEMBLER_NAME instead of DECL_NAME,
we cannot change DECL_ASSEMBLER_NAME until we have installed this
function in the namespace. */
@@ -5693,10 +6205,20 @@ shadow_tag (declspecs)
code = TREE_CODE (value);
if (IS_AGGR_TYPE_CODE (code) || code == ENUMERAL_TYPE)
{
- my_friendly_assert (TYPE_NAME (value) != NULL_TREE, 261);
+ my_friendly_assert (TYPE_MAIN_DECL (value) != NULL_TREE, 261);
- if (code == ENUMERAL_TYPE && TYPE_SIZE (value) == 0)
- cp_error ("forward declaration of `%#T'", value);
+ if (IS_AGGR_TYPE (value) && CLASSTYPE_USE_TEMPLATE (value))
+ {
+ if (CLASSTYPE_IMPLICIT_INSTANTIATION (value)
+ && TYPE_SIZE (value) == NULL_TREE)
+ {
+ SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (value);
+ if (processing_template_decl)
+ push_template_decl (TYPE_MAIN_DECL (value));
+ }
+ else if (CLASSTYPE_TEMPLATE_INSTANTIATION (value))
+ cp_error ("specialization after instantiation of `%T'", value);
+ }
t = value;
ok_code = code;
@@ -5724,16 +6246,38 @@ shadow_tag (declspecs)
|| (TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
&& ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))))
{
+ /* See also grok_x_components. */
+ tree *q;
+
+ /* Wipe out memory of synthesized methods */
+ TYPE_HAS_CONSTRUCTOR (t) = 0;
+ TYPE_HAS_DEFAULT_CONSTRUCTOR (t) = 0;
+ TYPE_HAS_INIT_REF (t) = 0;
+ TYPE_HAS_CONST_INIT_REF (t) = 0;
+ TYPE_HAS_ASSIGN_REF (t) = 0;
+ TYPE_HAS_ASSIGNMENT (t) = 0;
+ TYPE_HAS_CONST_ASSIGN_REF (t) = 0;
+
+ q = &TYPE_METHODS (t);
+ while (*q)
+ {
+ if (DECL_ARTIFICIAL (*q))
+ *q = TREE_CHAIN (*q);
+ else
+ q = &TREE_CHAIN (*q);
+ }
+
/* ANSI C++ June 5 1992 WP 9.5.3. Anonymous unions may not have
function members. */
+ if (TYPE_METHODS (t))
+ error ("an anonymous union cannot have function members");
+
if (TYPE_FIELDS (t))
{
tree decl = grokdeclarator (NULL_TREE, declspecs, NORMAL, 0,
- NULL_TREE, NULL_TREE);
+ NULL_TREE);
finish_anon_union (decl);
}
- else
- error ("anonymous union cannot have a function member");
}
else
{
@@ -5754,7 +6298,7 @@ shadow_tag (declspecs)
}
if (found_tag == 0)
- pedwarn ("abstract declarator used as declaration");
+ cp_error ("abstract declarator used as declaration");
else if (found_tag > 1)
pedwarn ("multiple types in one declaration");
}
@@ -5770,7 +6314,7 @@ groktypename (typename)
return typename;
return grokdeclarator (TREE_VALUE (typename),
TREE_PURPOSE (typename),
- TYPENAME, 0, NULL_TREE, NULL_TREE);
+ TYPENAME, 0, NULL_TREE);
}
/* Decode a declarator in an ordinary declaration or data definition.
@@ -5793,10 +6337,10 @@ groktypename (typename)
int debug_temp_inits = 1;
tree
-start_decl (declarator, declspecs, initialized, raises)
+start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
tree declarator, declspecs;
int initialized;
- tree raises;
+ tree attributes, prefix_attributes;
{
register tree decl;
register tree type, tem;
@@ -5804,9 +6348,12 @@ start_decl (declarator, declspecs, initialized, raises)
extern int have_extern_spec;
extern int used_extern_spec;
+#if 0
+ /* See code below that used this. */
int init_written = initialized;
+#endif
- /* This should only be done once on the top most decl. */
+ /* This should only be done once on the top most decl. */
if (have_extern_spec && !used_extern_spec)
{
declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"),
@@ -5814,16 +6361,16 @@ start_decl (declarator, declspecs, initialized, raises)
used_extern_spec = 1;
}
- decl = grokdeclarator (declarator, declspecs, NORMAL, initialized, raises,
+ decl = grokdeclarator (declarator, declspecs, NORMAL, initialized,
NULL_TREE);
- if (decl == NULL_TREE || decl == void_type_node)
+ if (decl == NULL_TREE || TREE_CODE (decl) == VOID_TYPE)
return NULL_TREE;
type = TREE_TYPE (decl);
/* Don't lose if destructors must be executed at file-level. */
- if (TREE_STATIC (decl)
- && TYPE_NEEDS_DESTRUCTOR (type)
+ if (! processing_template_decl && TREE_STATIC (decl)
+ && TYPE_NEEDS_DESTRUCTOR (complete_type (type))
&& !TREE_PERMANENT (decl))
{
push_obstacks (&permanent_obstack, &permanent_obstack);
@@ -5841,60 +6388,22 @@ start_decl (declarator, declspecs, initialized, raises)
pop_obstacks ();
}
- /* Corresponding pop_obstacks is done in `cp_finish_decl'. */
- push_obstacks_nochange ();
-
context
= (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl))
? DECL_CLASS_CONTEXT (decl)
: DECL_CONTEXT (decl);
- if (processing_template_decl)
+ if (initialized && context && TREE_CODE (context) == NAMESPACE_DECL
+ && context != current_namespace && TREE_CODE (decl) == VAR_DECL)
{
- tree d;
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- /* Declarator is a call_expr; extract arguments from it, since
- grokdeclarator didn't do it. */
- tree args;
- args = copy_to_permanent (last_function_parms);
- if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
- {
- tree t = TREE_TYPE (decl);
-
- t = TYPE_METHOD_BASETYPE (t); /* type method belongs to */
- if (TREE_CODE (t) != UNINSTANTIATED_P_TYPE)
- {
- t = build_pointer_type (t); /* base type of `this' */
-#if 1
- /* I suspect this is wrong. */
- t = build_type_variant (t, flag_this_is_variable <= 0,
- 0); /* type of `this' */
-#else
- t = build_type_variant (t, 0, 0); /* type of `this' */
-#endif
- t = build (PARM_DECL, t, this_identifier);
- TREE_CHAIN (t) = args;
- args = t;
- }
- }
- DECL_ARGUMENTS (decl) = args;
- }
- d = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), TREE_TYPE (decl));
- TREE_PUBLIC (d) = TREE_PUBLIC (decl);
- TREE_STATIC (d) = TREE_STATIC (decl);
- DECL_EXTERNAL (d) = (DECL_EXTERNAL (decl)
- && !(context && !DECL_THIS_EXTERN (decl)));
- DECL_TEMPLATE_RESULT (d) = decl;
- decl = d;
+ /* When parsing the initializer, lookup should use the object's
+ namespace. */
+ push_decl_namespace (context);
}
- /* If this type of object needs a cleanup, and control may
- jump past it, make a new binding level so that it is cleaned
- up only when it is initialized first. */
- if (TYPE_NEEDS_DESTRUCTOR (type)
- && current_binding_level->more_cleanups_ok == 0)
- pushlevel_temporary (1);
+ /* We are only interested in class contexts, later. */
+ if (context && TREE_CODE (context) == NAMESPACE_DECL)
+ context = NULL_TREE;
if (initialized)
/* Is it valid for this decl to have an initializer at all?
@@ -5919,51 +6428,30 @@ start_decl (declarator, declspecs, initialized, raises)
break;
default:
- /* Don't allow initializations for incomplete types except for
- arrays which might be completed by the initialization. */
- if (type == error_mark_node)
- ; /* Don't complain again. */
- else if (TYPE_SIZE (type) != NULL_TREE)
- ; /* A complete type is ok. */
- else if (TREE_CODE (type) != ARRAY_TYPE)
- {
- cp_error ("variable `%#D' has initializer but incomplete type",
- decl);
- initialized = 0;
- }
- else if (TYPE_SIZE (TREE_TYPE (type)) == NULL_TREE)
+ if (! processing_template_decl)
{
- cp_error ("elements of array `%#D' have incomplete type", decl);
- initialized = 0;
+ if (type != error_mark_node)
+ {
+ if (TYPE_SIZE (type) != NULL_TREE
+ && ! TREE_CONSTANT (TYPE_SIZE (type)))
+ {
+ cp_error
+ ("variable-sized object `%D' may not be initialized",
+ decl);
+ initialized = 0;
+ }
+
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE)
+ {
+ cp_error
+ ("elements of array `%#D' have incomplete type", decl);
+ initialized = 0;
+ }
+ }
}
}
- if (!initialized
- && TREE_CODE (decl) != TYPE_DECL
- && TREE_CODE (decl) != TEMPLATE_DECL
- && IS_AGGR_TYPE (type) && ! DECL_EXTERNAL (decl))
- {
- if (TYPE_SIZE (type) == NULL_TREE)
- {
- cp_error ("aggregate `%#D' has incomplete type and cannot be initialized",
- decl);
- /* Change the type so that assemble_variable will give
- DECL an rtl we can live with: (mem (const_int 0)). */
- TREE_TYPE (decl) = error_mark_node;
- type = error_mark_node;
- }
- else
- {
- /* If any base type in the hierarchy of TYPE needs a constructor,
- then we set initialized to 1. This way any nodes which are
- created for the purposes of initializing this aggregate
- will live as long as it does. This is necessary for global
- aggregates which do not have their initializers processed until
- the end of the file. */
- initialized = TYPE_NEEDS_CONSTRUCTING (type);
- }
- }
-
if (initialized)
{
if (! toplevel_bindings_p ()
@@ -5971,7 +6459,7 @@ start_decl (declarator, declspecs, initialized, raises)
cp_warning ("declaration of `%#D' has `extern' and is initialized",
decl);
DECL_EXTERNAL (decl) = 0;
- if ( toplevel_bindings_p ())
+ if (toplevel_bindings_p ())
TREE_STATIC (decl) = 1;
/* Tell `pushdecl' this is an initialized decl
@@ -5980,130 +6468,106 @@ start_decl (declarator, declspecs, initialized, raises)
DECL_INITIAL (decl) = error_mark_node;
}
- if (context && TYPE_SIZE (context) != NULL_TREE)
+ if (context && TYPE_SIZE (complete_type (context)) != NULL_TREE)
{
if (TREE_CODE (decl) == VAR_DECL)
{
tree field = lookup_field (context, DECL_NAME (decl), 0, 0);
if (field == NULL_TREE || TREE_CODE (field) != VAR_DECL)
cp_error ("`%#D' is not a static member of `%#T'", decl, context);
- else if (duplicate_decls (decl, field))
- decl = field;
+ else
+ {
+ if (DECL_CONTEXT (field) != context)
+ {
+ cp_pedwarn ("ANSI C++ does not permit `%T::%D' to be defined as `%T::%D'",
+ DECL_CONTEXT (field), DECL_NAME (decl),
+ context, DECL_NAME (decl));
+ DECL_CONTEXT (decl) = DECL_CONTEXT (field);
+ }
+ /* Static data member are tricky; an in-class initialization
+ still doesn't provide a definition, so the in-class
+ declaration will have DECL_EXTERNAL set, but will have an
+ initialization. Thus, duplicate_decls won't warn
+ about this situation, and so we check here. */
+ if (DECL_INITIAL (decl) && DECL_INITIAL (field))
+ cp_error ("duplicate initialization of %D", decl);
+ if (duplicate_decls (decl, field))
+ decl = field;
+ }
}
else
{
- tree field = check_classfn (context, NULL_TREE, decl);
+ tree field = check_classfn (context, decl);
if (field && duplicate_decls (decl, field))
decl = field;
}
/* cp_finish_decl sets DECL_EXTERNAL if DECL_IN_AGGR_P is set. */
- if (DECL_LANG_SPECIFIC (decl))
- DECL_IN_AGGR_P (decl) = 0;
- if (DECL_USE_TEMPLATE (decl) || CLASSTYPE_USE_TEMPLATE (context))
+ DECL_IN_AGGR_P (decl) = 0;
+ if ((DECL_LANG_SPECIFIC (decl) && DECL_USE_TEMPLATE (decl))
+ || CLASSTYPE_USE_TEMPLATE (context))
SET_DECL_TEMPLATE_SPECIALIZATION (decl);
- /* Stupid stupid stupid stupid (jason 7/21/95) */
- if (pedantic && DECL_EXTERNAL (decl)
- && ! DECL_TEMPLATE_SPECIALIZATION (decl))
+ if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl))
cp_pedwarn ("declaration of `%#D' outside of class is not definition",
decl);
pushclass (context, 2);
}
+ /* Set attributes here so if duplicate decl, will have proper attributes. */
+ cplus_decl_attributes (decl, attributes, prefix_attributes);
+
/* Add this decl to the current binding level, but not if it
comes from another scope, e.g. a static member variable.
TEM may equal DECL or it may be a previous decl of the same name. */
- if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE)
- || (TREE_CODE (decl) == TEMPLATE_DECL && !global_bindings_p ())
- || TREE_CODE (type) == LANG_TYPE)
+ if ((TREE_CODE (decl) != PARM_DECL && DECL_CONTEXT (decl) != NULL_TREE
+ /* Definitions of namespace members outside their namespace are
+ possible. */
+ && TREE_CODE (DECL_CONTEXT (decl)) != NAMESPACE_DECL)
+ || (TREE_CODE (decl) == TEMPLATE_DECL && !namespace_bindings_p ())
+ || TREE_CODE (type) == LANG_TYPE
+ /* The declaration of template specializations does not affect
+ the functions available for overload resolution, so we do not
+ call pushdecl. */
+ || (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_TEMPLATE_SPECIALIZATION (decl)))
tem = decl;
else
tem = pushdecl (decl);
-
- /* Tell the back-end to use or not use .common as appropriate. If we say
- -fconserve-space, we want this to save space, at the expense of wrong
- semantics. If we say -fno-conserve-space, we want this to produce
- errors about redefs; to do this we force variables into the data
- segment. Common storage is okay for non-public uninitialized data;
- the linker can't match it with storage from other files, and we may
- save some disk space. */
- DECL_COMMON (tem) = flag_conserve_space || ! TREE_PUBLIC (tem);
-#if 0
- /* We don't do this yet for GNU C++. */
- /* For a local variable, define the RTL now. */
- if (! toplevel_bindings_p ()
- /* But not if this is a duplicate decl
- and we preserved the rtl from the previous one
- (which may or may not happen). */
- && DECL_RTL (tem) == NULL_RTX)
+ if (processing_template_decl)
{
- if (TYPE_SIZE (TREE_TYPE (tem)) != NULL_TREE)
- expand_decl (tem);
- else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE
- && DECL_INITIAL (tem) != NULL_TREE)
- expand_decl (tem);
+ if (! current_function_decl)
+ tem = push_template_decl (tem);
+ else if (minimal_parse_mode)
+ DECL_VINDEX (tem)
+ = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
+ copy_to_permanent (declspecs),
+ NULL_TREE);
}
+
+
+#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)
+ /* Tell the back-end to use or not use .common as appropriate. If we say
+ -fconserve-space, we want this to save .data space, at the expense of
+ wrong semantics. If we say -fno-conserve-space, we want this to
+ produce errors about redefs; to do this we force variables into the
+ data segment. */
+ DECL_COMMON (tem) = flag_conserve_space || ! TREE_PUBLIC (tem);
#endif
- if (TREE_CODE (decl) == TEMPLATE_DECL)
- {
- tree result = DECL_TEMPLATE_RESULT (decl);
- if (DECL_CONTEXT (result) != NULL_TREE)
- {
- tree type;
- type = DECL_CONTEXT (result);
+ if (! processing_template_decl)
+ start_decl_1 (tem);
- if (TREE_CODE (type) != UNINSTANTIATED_P_TYPE)
- {
- cp_error ("declaration of `%D' in non-template type `%T'",
- decl, type);
- return NULL_TREE;
- }
+ /* Corresponding pop_obstacks is done in `cp_finish_decl'. */
+ push_obstacks_nochange ();
- if (TREE_CODE (result) == FUNCTION_DECL)
- return tem;
- else if (TREE_CODE (result) == VAR_DECL)
- {
#if 0
- tree tmpl = UPT_TEMPLATE (type);
-
- fprintf (stderr, "%s:%d: adding ", __FILE__, __LINE__);
- print_node_brief (stderr, "", DECL_NAME (tem), 0);
- fprintf (stderr, " to class %s\n",
- IDENTIFIER_POINTER (DECL_NAME (tmpl)));
- DECL_TEMPLATE_MEMBERS (tmpl)
- = perm_tree_cons (DECL_NAME (tem), tem,
- DECL_TEMPLATE_MEMBERS (tmpl));
- return tem;
-#else
- sorry ("static data member templates");
- return NULL_TREE;
-#endif
- }
- else
- my_friendly_abort (13);
- }
- else if (TREE_CODE (result) == FUNCTION_DECL)
- /*tem = push_overloaded_decl (tem, 0)*/;
- else if (TREE_CODE (result) == VAR_DECL)
- {
- cp_error ("data template `%#D' must be member of a class template",
- result);
- return NULL_TREE;
- }
- else if (TREE_CODE (result) == TYPE_DECL)
- {
- cp_error ("invalid template `%#D'", result);
- return NULL_TREE;
- }
- else
- my_friendly_abort (14);
- }
-
+ /* We have no way of knowing whether the initializer will need to be
+ evaluated at run-time or not until we've parsed it, so let's just put
+ it in the permanent obstack. (jason) */
if (init_written
&& ! (TREE_CODE (tem) == PARM_DECL
|| (TREE_READONLY (tem)
@@ -6114,7 +6578,8 @@ start_decl (declarator, declspecs, initialized, raises)
use temporary storage. Do this even if we will ignore the value. */
if (toplevel_bindings_p () && debug_temp_inits)
{
- if (TYPE_NEEDS_CONSTRUCTING (type)
+ if (processing_template_decl
+ || TYPE_NEEDS_CONSTRUCTING (type)
|| TREE_CODE (type) == REFERENCE_TYPE)
/* In this case, the initializer must lay down in permanent
storage, since it will be saved until `finish_file' is run. */
@@ -6123,81 +6588,108 @@ start_decl (declarator, declspecs, initialized, raises)
temporary_allocation ();
}
}
-
- if (flag_cadillac)
- cadillac_start_decl (tem);
+#endif
return tem;
}
-#if 0 /* unused */
-static void
-make_temporary_for_reference (decl, ctor_call, init, cleanupp)
- tree decl, ctor_call, init;
- tree *cleanupp;
+void
+start_decl_1 (decl)
+ tree decl;
{
tree type = TREE_TYPE (decl);
- tree target_type = TREE_TYPE (type);
- tree tmp, tmp_addr;
+ int initialized = (DECL_INITIAL (decl) != NULL_TREE);
- if (ctor_call)
- {
- tmp_addr = TREE_VALUE (TREE_OPERAND (ctor_call, 1));
- if (TREE_CODE (tmp_addr) == NOP_EXPR)
- tmp_addr = TREE_OPERAND (tmp_addr, 0);
- my_friendly_assert (TREE_CODE (tmp_addr) == ADDR_EXPR, 146);
- tmp = TREE_OPERAND (tmp_addr, 0);
- }
- else
+ /* If this type of object needs a cleanup, and control may
+ jump past it, make a new binding level so that it is cleaned
+ up only when it is initialized first. */
+ if (TYPE_NEEDS_DESTRUCTOR (type)
+ && current_binding_level->more_cleanups_ok == 0)
+ pushlevel_temporary (1);
+
+ if (initialized)
+ /* Is it valid for this decl to have an initializer at all?
+ If not, set INITIALIZED to zero, which will indirectly
+ tell `cp_finish_decl' to ignore the initializer once it is parsed. */
{
- tmp = get_temp_name (target_type, toplevel_bindings_p ());
- tmp_addr = build_unary_op (ADDR_EXPR, tmp, 0);
+ /* Don't allow initializations for incomplete types except for
+ arrays which might be completed by the initialization. */
+ if (type == error_mark_node)
+ ; /* Don't complain again. */
+ else if (TYPE_SIZE (complete_type (type)) != NULL_TREE)
+ ; /* A complete type is ok. */
+ else if (TREE_CODE (type) != ARRAY_TYPE)
+ {
+ cp_error ("variable `%#D' has initializer but incomplete type",
+ decl);
+ initialized = 0;
+ type = TREE_TYPE (decl) = error_mark_node;
+ }
+ else if (TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE)
+ {
+ if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
+ cp_error ("elements of array `%#D' have incomplete type", decl);
+ /* else we already gave an error in start_decl. */
+ initialized = 0;
+ }
}
- TREE_TYPE (tmp_addr) = build_pointer_type (target_type);
- DECL_INITIAL (decl) = convert (build_pointer_type (target_type), tmp_addr);
- TREE_TYPE (DECL_INITIAL (decl)) = type;
- if (TYPE_NEEDS_CONSTRUCTING (target_type))
+ if (!initialized
+ && TREE_CODE (decl) != TYPE_DECL
+ && TREE_CODE (decl) != TEMPLATE_DECL
+ && IS_AGGR_TYPE (type) && ! DECL_EXTERNAL (decl))
{
- if (toplevel_bindings_p ())
+ if ((! processing_template_decl || ! uses_template_parms (type))
+ && TYPE_SIZE (complete_type (type)) == NULL_TREE)
{
- /* lay this variable out now. Otherwise `output_addressed_constants'
- gets confused by its initializer. */
- make_decl_rtl (tmp, NULL_PTR, 1);
- static_aggregates = perm_tree_cons (init, tmp, static_aggregates);
+ cp_error ("aggregate `%#D' has incomplete type and cannot be initialized",
+ decl);
+ /* Change the type so that assemble_variable will give
+ DECL an rtl we can live with: (mem (const_int 0)). */
+ type = TREE_TYPE (decl) = error_mark_node;
}
else
{
- if (ctor_call != NULL_TREE)
- init = ctor_call;
- else
- init = build_method_call (tmp, constructor_name_full (target_type),
- build_tree_list (NULL_TREE, init),
- NULL_TREE, LOOKUP_NORMAL);
- DECL_INITIAL (decl) = build (COMPOUND_EXPR, type, init,
- DECL_INITIAL (decl));
- *cleanupp = maybe_build_cleanup (tmp);
+ /* If any base type in the hierarchy of TYPE needs a constructor,
+ then we set initialized to 1. This way any nodes which are
+ created for the purposes of initializing this aggregate
+ will live as long as it does. This is necessary for global
+ aggregates which do not have their initializers processed until
+ the end of the file. */
+ initialized = TYPE_NEEDS_CONSTRUCTING (type);
}
}
- else
+
+#if 0
+ /* We don't do this yet for GNU C++. */
+ /* For a local variable, define the RTL now. */
+ if (! toplevel_bindings_p ()
+ /* But not if this is a duplicate decl
+ and we preserved the rtl from the previous one
+ (which may or may not happen). */
+ && DECL_RTL (tem) == NULL_RTX)
{
- DECL_INITIAL (tmp) = init;
- TREE_STATIC (tmp) = toplevel_bindings_p ();
- cp_finish_decl (tmp, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
+ if (TYPE_SIZE (TREE_TYPE (tem)) != NULL_TREE)
+ expand_decl (tem);
+ else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE
+ && DECL_INITIAL (tem) != NULL_TREE)
+ expand_decl (tem);
}
- if (TREE_STATIC (tmp))
- preserve_initializer ();
-}
#endif
+ if (! initialized)
+ DECL_INITIAL (decl) = NULL_TREE;
+}
+
/* Handle initialization of references.
- These three arguments from from `cp_finish_decl', and have the
- same meaning here that they do there. */
-/* quotes on semantics can be found in ARM 8.4.3. */
+ These three arguments are from `cp_finish_decl', and have the
+ same meaning here that they do there.
+
+ Quotes on semantics can be found in ARM 8.4.3. */
+
static void
-grok_reference_init (decl, type, init, cleanupp)
+grok_reference_init (decl, type, init)
tree decl, type, init;
- tree *cleanupp;
{
tree tmp;
@@ -6224,6 +6716,10 @@ grok_reference_init (decl, type, init, cleanupp)
return;
}
+ if (TREE_TYPE (init) && TREE_CODE (TREE_TYPE (init)) == UNKNOWN_TYPE)
+ /* decay_conversion is probably wrong for references to functions. */
+ init = decay_conversion (instantiate_type (TREE_TYPE (type), init, 1));
+
if (TREE_CODE (init) == TREE_LIST)
init = build_compound_expr (init);
@@ -6238,39 +6734,14 @@ grok_reference_init (decl, type, init, cleanupp)
}
tmp = convert_to_reference
- (type, init, CONV_IMPLICIT, LOOKUP_SPECULATIVELY|LOOKUP_NORMAL, decl);
+ (type, init, CONV_IMPLICIT,
+ LOOKUP_SPECULATIVELY|LOOKUP_NORMAL|DIRECT_BIND, decl);
if (tmp == error_mark_node)
goto fail;
else if (tmp != NULL_TREE)
{
- tree subtype = TREE_TYPE (type);
init = tmp;
-
- /* Associate the cleanup with the reference so that we
- don't get burned by "aggressive" cleanup policy. */
- if (TYPE_NEEDS_DESTRUCTOR (subtype))
- {
- if (TREE_CODE (init) == WITH_CLEANUP_EXPR)
- {
- *cleanupp = TREE_OPERAND (init, 2);
- TREE_OPERAND (init, 2) = error_mark_node;
- }
- else
- {
- if (TREE_CODE (tmp) == ADDR_EXPR)
- tmp = TREE_OPERAND (tmp, 0);
- if (TREE_CODE (tmp) == TARGET_EXPR)
- {
- *cleanupp = build_delete
- (build_pointer_type (subtype),
- build_unary_op (ADDR_EXPR, TREE_OPERAND (tmp, 0), 0),
- integer_two_node, LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0);
- TREE_OPERAND (tmp, 2) = error_mark_node;
- }
- }
- }
-
DECL_INITIAL (decl) = save_expr (init);
}
else
@@ -6318,10 +6789,12 @@ obscure_complex_init (decl, init)
return NULL_TREE;
}
+#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)
if (toplevel_bindings_p () && ! DECL_COMMON (decl))
DECL_INITIAL (decl) = build (CONSTRUCTOR, TREE_TYPE (decl), NULL_TREE,
NULL_TREE);
else
+#endif
DECL_INITIAL (decl) = error_mark_node;
return init;
@@ -6357,11 +6830,12 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
int flags;
{
register tree type;
- tree cleanup = NULL_TREE, ttype;
+ tree cleanup = NULL_TREE, ttype = NULL_TREE;
int was_incomplete;
int temporary = allocation_temporary_p ();
char *asmspec = NULL;
int was_readonly = 0;
+ int already_used = 0;
/* If this is 0, then we did not change obstacks. */
if (! decl)
@@ -6375,6 +6849,23 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
if (asmspec_tree)
asmspec = TREE_STRING_POINTER (asmspec_tree);
+ if (init && TREE_CODE (init) == NAMESPACE_DECL)
+ {
+ cp_error ("Cannot initialize `%D' to namespace `%D'",
+ decl, init);
+ init = NULL_TREE;
+ }
+
+ if (TREE_CODE (decl) == VAR_DECL
+ && DECL_CONTEXT (decl)
+ && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL
+ && DECL_CONTEXT (decl) != current_namespace
+ && init)
+ {
+ /* Leave the namespace of the object. */
+ pop_decl_namespace ();
+ }
+
/* If the type of the thing we are declaring either has
a constructor, or has a virtual function table pointer,
AND its initialization was accepted by `start_decl',
@@ -6391,8 +6882,27 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
return;
}
- was_incomplete = (DECL_SIZE (decl) == NULL_TREE);
+ if (processing_template_decl)
+ {
+ if (init && DECL_INITIAL (decl))
+ DECL_INITIAL (decl) = init;
+ if (minimal_parse_mode && ! DECL_ARTIFICIAL (decl))
+ {
+ tree stmt = DECL_VINDEX (decl);
+ /* If the decl is declaring a member of a local class (in a
+ template function), the DECL_VINDEX will either be NULL,
+ or it will be an actual virtual function index, not a
+ DECL_STMT. */
+ if (stmt != NULL_TREE && TREE_CODE (stmt) == DECL_STMT)
+ {
+ DECL_VINDEX (decl) = NULL_TREE;
+ TREE_OPERAND (stmt, 2) = copy_to_permanent (init);
+ add_tree (stmt);
+ }
+ }
+ goto finish_end0;
+ }
/* Take care of TYPE_DECLs up front. */
if (TREE_CODE (decl) == TYPE_DECL)
{
@@ -6411,35 +6921,21 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
CLASSTYPE_GOT_SEMICOLON (type) = 1;
}
GNU_xref_decl (current_function_decl, decl);
+
+ /* If we have installed this as the canonical typedef for this
+ type, and that type has not been defined yet, delay emitting
+ the debug information for it, as we will emit it later. */
+ if (TYPE_MAIN_DECL (TREE_TYPE (decl)) == decl
+ && TYPE_SIZE (TREE_TYPE (decl)) == NULL_TREE)
+ TYPE_DECL_SUPPRESS_DEBUG (decl) = 1;
+
rest_of_decl_compilation (decl, NULL_PTR,
- DECL_CONTEXT (decl) == NULL_TREE, 0);
+ DECL_CONTEXT (decl) == NULL_TREE, at_eof);
goto finish_end;
}
if (TREE_CODE (decl) != FUNCTION_DECL)
{
ttype = target_type (type);
-#if 0 /* WTF? -KR
- Leave this out until we can figure out why it was
- needed/desirable in the first place. Then put a comment
- here explaining why. Or just delete the code if no ill
- effects arise. */
- if (TYPE_NAME (ttype)
- && TREE_CODE (TYPE_NAME (ttype)) == TYPE_DECL
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (ttype)))
- {
- tree old_id = TYPE_IDENTIFIER (ttype);
- char *newname = (char *)alloca (IDENTIFIER_LENGTH (old_id) + 2);
- /* Need to preserve template data for UPT nodes. */
- tree old_template = IDENTIFIER_TEMPLATE (old_id);
- newname[0] = '_';
- bcopy (IDENTIFIER_POINTER (old_id), newname + 1,
- IDENTIFIER_LENGTH (old_id) + 1);
- old_id = get_identifier (newname);
- lookup_tag_reverse (ttype, old_id);
- TYPE_IDENTIFIER (ttype) = old_id;
- IDENTIFIER_TEMPLATE (old_id) = old_template;
- }
-#endif
}
if (! DECL_EXTERNAL (decl) && TREE_READONLY (decl)
@@ -6480,7 +6976,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
make_decl_rtl (decl, NULL_PTR,
toplevel_bindings_p ()
|| pseudo_global_level_p ());
- grok_reference_init (decl, type, init, &cleanup);
+ grok_reference_init (decl, type, init);
init = NULL_TREE;
}
@@ -6620,7 +7116,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
if (TREE_CODE (decl) == VAR_DECL)
{
if (DECL_SIZE (decl) == NULL_TREE
- && TYPE_SIZE (TREE_TYPE (decl)) != NULL_TREE)
+ && TYPE_SIZE (complete_type (TREE_TYPE (decl))) != NULL_TREE)
layout_decl (decl, 0);
if (TREE_STATIC (decl) && DECL_SIZE (decl) == NULL_TREE)
@@ -6645,8 +7141,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
/* Let debugger know it should output info for this type. */
note_debug_info_needed (ttype);
- if (TREE_STATIC (decl) && DECL_CONTEXT (decl)
- && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (decl))) == 't')
+ if (TREE_STATIC (decl) && DECL_CLASS_SCOPE_P (decl))
note_debug_info_needed (DECL_CONTEXT (decl));
if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
@@ -6659,21 +7154,12 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
cp_error ("storage size of `%D' isn't constant", decl);
}
- if (!DECL_EXTERNAL (decl) && TYPE_NEEDS_DESTRUCTOR (type))
+ if (! DECL_EXTERNAL (decl) && TYPE_NEEDS_DESTRUCTOR (type)
+ /* Cleanups for static variables are handled by `finish_file'. */
+ && ! TREE_STATIC (decl))
{
int yes = suspend_momentary ();
-
- /* If INIT comes from a functional cast, use the cleanup
- we built for that. Otherwise, make our own cleanup. */
- if (init && TREE_CODE (init) == WITH_CLEANUP_EXPR
- && comptypes (TREE_TYPE (decl), TREE_TYPE (init), 1))
- {
- cleanup = TREE_OPERAND (init, 2);
- init = TREE_OPERAND (init, 0);
- current_binding_level->have_cleanups = 1;
- }
- else
- cleanup = maybe_build_cleanup (decl);
+ cleanup = maybe_build_cleanup (decl);
resume_momentary (yes);
}
}
@@ -6691,24 +7177,96 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
unless the type is an undefined structure or union.
If not, it will get done when the type is completed. */
+ was_incomplete = (DECL_SIZE (decl) == NULL_TREE);
+
if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL
|| TREE_CODE (decl) == RESULT_DECL)
{
/* ??? FIXME: What about nested classes? */
int toplev = toplevel_bindings_p () || pseudo_global_level_p ();
int was_temp
- = ((flag_traditional
- || (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type)))
+ = (TREE_STATIC (decl) && TYPE_NEEDS_DESTRUCTOR (type)
&& allocation_temporary_p ());
if (was_temp)
end_temporary_allocation ();
+ /* Static data in a function with comdat linkage also has comdat
+ linkage. */
if (TREE_CODE (decl) == VAR_DECL
- && ! toplevel_bindings_p ()
- && ! TREE_STATIC (decl)
- && type_needs_gc_entry (type))
- DECL_GC_OFFSET (decl) = size_int (++current_function_obstack_index);
+ && TREE_STATIC (decl)
+ /* Don't mess with __FUNCTION__. */
+ && ! TREE_ASM_WRITTEN (decl)
+ && current_function_decl
+ && DECL_CONTEXT (decl) == current_function_decl
+ && (DECL_THIS_INLINE (current_function_decl)
+ || DECL_TEMPLATE_INSTANTIATION (current_function_decl))
+ && TREE_PUBLIC (current_function_decl))
+ {
+ /* Rather than try to get this right with inlining, we suppress
+ inlining of such functions. */
+ current_function_cannot_inline
+ = "function with static variable cannot be inline";
+
+ /* If flag_weak, we don't need to mess with this, as we can just
+ make the function weak, and let it refer to its unique local
+ copy. This works because we don't allow the function to be
+ inlined. */
+ if (! flag_weak)
+ {
+ if (DECL_INTERFACE_KNOWN (current_function_decl))
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_EXTERNAL (decl) = DECL_EXTERNAL (current_function_decl);
+ }
+ else if (DECL_INITIAL (decl) == NULL_TREE
+ || DECL_INITIAL (decl) == error_mark_node)
+ {
+ TREE_PUBLIC (decl) = 1;
+ DECL_COMMON (decl) = 1;
+ }
+ /* else we lose. We can only do this if we can use common,
+ which we can't if it has been initialized. */
+
+ if (TREE_PUBLIC (decl))
+ DECL_ASSEMBLER_NAME (decl)
+ = build_static_name (current_function_decl, DECL_NAME (decl));
+ else if (! DECL_ARTIFICIAL (decl))
+ {
+ cp_warning_at ("sorry: semantics of inline function static data `%#D' are wrong (you'll wind up with multiple copies)", decl);
+ cp_warning_at (" you can work around this by removing the initializer"), decl;
+ }
+ }
+ }
+
+ else if (TREE_CODE (decl) == VAR_DECL
+ && DECL_LANG_SPECIFIC (decl)
+ && DECL_COMDAT (decl))
+ {
+ /* Dynamically initialized vars go into common. */
+ if (DECL_INITIAL (decl) == NULL_TREE
+ || DECL_INITIAL (decl) == error_mark_node)
+ DECL_COMMON (decl) = 1;
+ else if (EMPTY_CONSTRUCTOR_P (DECL_INITIAL (decl)))
+ {
+ DECL_COMMON (decl) = 1;
+ DECL_INITIAL (decl) = error_mark_node;
+ }
+ else
+ {
+ /* Statically initialized vars are weak or comdat, if
+ supported. */
+ if (flag_weak)
+ make_decl_one_only (decl);
+ else
+ {
+ /* We can't do anything useful; leave vars for explicit
+ instantiation. */
+ DECL_EXTERNAL (decl) = 1;
+ DECL_NOT_REALLY_EXTERN (decl) = 0;
+ }
+ }
+ }
if (TREE_CODE (decl) == VAR_DECL && DECL_VIRTUAL_P (decl))
make_decl_rtl (decl, NULL_PTR, toplev);
@@ -6751,7 +7309,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
make_decl_rtl (decl, asmspec, toplev);
}
else
- rest_of_decl_compilation (decl, asmspec, toplev, 0);
+ rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
}
else if (TREE_CODE (decl) == VAR_DECL
&& DECL_LANG_SPECIFIC (decl)
@@ -6772,14 +7330,14 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
make_decl_rtl (decl, asmspec, 1);
}
else
- rest_of_decl_compilation (decl, asmspec, toplev, 0);
+ rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
}
else
/* Just a constant field. Should not need any rtl. */
goto finish_end0;
}
else
- rest_of_decl_compilation (decl, asmspec, toplev, 0);
+ rest_of_decl_compilation (decl, asmspec, toplev, at_eof);
if (was_temp)
resume_temporary_allocation ();
@@ -6804,22 +7362,22 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
if (TREE_CODE (decl) == FUNCTION_DECL)
;
- else if (DECL_EXTERNAL (decl))
- ;
+ else if (DECL_EXTERNAL (decl)
+ && ! (DECL_LANG_SPECIFIC (decl)
+ && DECL_NOT_REALLY_EXTERN (decl)))
+ {
+ if (init)
+ DECL_INITIAL (decl) = init;
+ }
else if (TREE_STATIC (decl) && type != error_mark_node)
{
/* Cleanups for static variables are handled by `finish_file'. */
if (TYPE_NEEDS_CONSTRUCTING (type) || init != NULL_TREE
|| TYPE_NEEDS_DESTRUCTOR (type))
expand_static_init (decl, init);
-
- /* Make entry in appropriate vector. */
- if (flag_gc && type_needs_gc_entry (type))
- build_static_gc_entry (decl, type);
}
else if (! toplev)
{
- tree old_cleanups = cleanups_this_call;
/* This is a declared decl which must live until the
end of the binding contour. It may need a cleanup. */
@@ -6846,7 +7404,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
{
/* XXX: Why don't we use decl here? */
/* Ans: Because it was already expanded? */
- if (! cp_expand_decl_cleanup (NULL_TREE, cleanup))
+ if (! expand_decl_cleanup (NULL_TREE, cleanup))
cp_error ("parser lost in parsing declaration of `%D'",
decl);
/* Cleanup used up here. */
@@ -6854,10 +7412,59 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
}
}
+ if (current_binding_level->is_for_scope)
+ {
+ struct binding_level *outer = current_binding_level->level_chain;
+
+ /* Check to see if the same name is already bound at
+ the outer level, either because it was directly declared,
+ or because a dead for-decl got preserved. In either case,
+ the code would not have been valid under the ARM
+ scope rules, so clear is_for_scope for the
+ current_binding_level.
+
+ Otherwise, we need to preserve the temp slot for decl
+ to last into the outer binding level. */
+
+ int handling_dead_for_vars = 0;
+ tree link = outer->names;
+ for (; ; link = TREE_CHAIN (link))
+ {
+ if (link == NULL && handling_dead_for_vars == 0)
+ {
+ link = outer->dead_vars_from_for;
+ handling_dead_for_vars = 1;
+ }
+ if (link == NULL)
+ {
+ if (DECL_IN_MEMORY_P (decl))
+ preserve_temp_slots (DECL_RTL (decl));
+ break;
+ }
+ if (DECL_NAME (link) == DECL_NAME (decl))
+ {
+ if (handling_dead_for_vars)
+ {
+ tree shadowing
+ = purpose_member (DECL_NAME (decl),
+ current_binding_level->shadowed);
+ if (shadowing && TREE_VALUE (shadowing) == link)
+ TREE_VALUE (shadowing)
+ = DECL_SHADOWED_FOR_VAR (link);
+ }
+ current_binding_level->is_for_scope = 0;
+ break;
+ }
+ }
+ }
+
+ expand_start_target_temps ();
+
if (DECL_SIZE (decl) && type != error_mark_node)
{
/* Compute and store the initial value. */
expand_decl_init (decl);
+ already_used = TREE_USED (decl) || TREE_USED (type);
if (init || TYPE_NEEDS_CONSTRUCTING (type))
{
@@ -6870,19 +7477,34 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
was initialized was ever used. Don't do this if it has a
destructor, so we don't complain about the 'resource
allocation is initialization' idiom. */
- if (TYPE_NEEDS_CONSTRUCTING (type) && cleanup == NULL_TREE)
+ /* Now set attribute((unused)) on types so decls of
+ that type will be marked used. (see TREE_USED, above.)
+ This avoids the warning problems this particular code
+ tried to work around. */
+
+ if (TYPE_NEEDS_CONSTRUCTING (type)
+ && ! already_used
+ && cleanup == NULL_TREE
+ && DECL_NAME (decl))
TREE_USED (decl) = 0;
+ if (already_used)
+ TREE_USED (decl) = 1;
+ }
+
+ /* Cleanup any temporaries needed for the initial value. */
+ expand_end_target_temps ();
+
+ if (DECL_SIZE (decl) && type != error_mark_node)
+ {
/* Store the cleanup, if there was one. */
if (cleanup)
{
- if (! cp_expand_decl_cleanup (decl, cleanup))
+ if (! expand_decl_cleanup (decl, cleanup))
cp_error ("parser lost in parsing declaration of `%D'",
decl);
}
}
- /* Cleanup any temporaries needed for the initial value. */
- expand_cleanups_to (old_cleanups);
}
finish_end0:
@@ -6896,18 +7518,12 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
&& (TREE_CODE (decl) == VAR_DECL
/* We also have a pushclass done that we need to undo here
if we're at top level and declare a method. */
- || (TREE_CODE (decl) == FUNCTION_DECL
- /* If size hasn't been set, we're still defining it,
- and therefore inside the class body; don't pop
- the binding level.. */
- && TYPE_SIZE (context) != NULL_TREE
- /* The binding level gets popped elsewhere for a
- friend declaration inside another class. */
- /*
- && TYPE_IDENTIFIER (context) == current_class_name
- */
- && context == current_class_type
- )))
+ || TREE_CODE (decl) == FUNCTION_DECL)
+ /* If size hasn't been set, we're still defining it,
+ and therefore inside the class body; don't pop
+ the binding level.. */
+ && TYPE_SIZE (context) != NULL_TREE
+ && context == current_class_type)
popclass (1);
}
}
@@ -6917,6 +7533,7 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
/* If requested, warn about definitions of large data objects. */
if (warn_larger_than
+ && ! processing_template_decl
&& (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
&& !DECL_EXTERNAL (decl))
{
@@ -6941,12 +7558,10 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
if (was_readonly)
TREE_READONLY (decl) = 1;
-
- if (flag_cadillac)
- cadillac_finish_decl (decl);
}
/* This is here for a midend callback from c-common.c */
+
void
finish_decl (decl, init, asmspec_tree)
tree decl, init;
@@ -6961,7 +7576,6 @@ expand_static_init (decl, init)
tree init;
{
tree oldstatic = value_member (decl, static_aggregates);
- tree old_cleanups;
if (oldstatic)
{
@@ -6973,7 +7587,7 @@ expand_static_init (decl, init)
/* Emit code to perform this initialization but once. */
tree temp;
- /* Remember this information until end of file. */
+ /* Remember this information until end of file. */
push_obstacks (&permanent_obstack, &permanent_obstack);
/* Emit code to perform this initialization but once. */
@@ -6981,7 +7595,8 @@ expand_static_init (decl, init)
rest_of_decl_compilation (temp, NULL_PTR, 0, 0);
expand_start_cond (build_binary_op (EQ_EXPR, temp,
integer_zero_node, 1), 0);
- old_cleanups = cleanups_this_call;
+ expand_start_target_temps ();
+
expand_assignment (temp, integer_one_node, 0, 0);
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
|| (init && TREE_CODE (init) == TREE_LIST))
@@ -6993,7 +7608,43 @@ expand_static_init (decl, init)
expand_assignment (decl, init, 0, 0);
/* Cleanup any temporaries needed for the initial value. */
- expand_cleanups_to (old_cleanups);
+ expand_end_target_temps ();
+
+ if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
+ {
+ tree cleanup, fcall;
+ static tree Atexit = 0;
+ if (Atexit == 0)
+ {
+ tree atexit_fndecl, PFV, pfvlist;
+ /* Remember this information until end of file. */
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ PFV = build_pointer_type (build_function_type
+ (void_type_node, void_list_node));
+
+ pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
+
+ push_lang_context (lang_name_c);
+ atexit_fndecl
+ = builtin_function ("atexit",
+ build_function_type (void_type_node,
+ pfvlist),
+ NOT_BUILT_IN, NULL_PTR);
+ assemble_external (atexit_fndecl);
+ Atexit = default_conversion (atexit_fndecl);
+ pop_lang_context ();
+ pop_obstacks ();
+ }
+
+ cleanup = start_anon_func ();
+ expand_expr_stmt (build_cleanup (decl));
+ end_anon_func ();
+ mark_addressable (cleanup);
+ cleanup = build_unary_op (ADDR_EXPR, cleanup, 0);
+ fcall = build_function_call (Atexit, expr_tree_cons (NULL_TREE, cleanup, NULL_TREE));
+ expand_expr_stmt (fcall);
+ }
+
expand_end_cond ();
if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (decl)))
{
@@ -7001,7 +7652,7 @@ expand_static_init (decl, init)
TREE_STATIC (static_aggregates) = 1;
}
- /* Resume old (possibly temporary) allocation. */
+ /* Resume old (possibly temporary) allocation. */
pop_obstacks ();
}
else
@@ -7100,6 +7751,7 @@ complete_array_type (type, initial_value, do_default)
/* Return zero if something is declared to be a member of type
CTYPE when in the context of CUR_TYPE. STRING is the error
message to print in that case. Otherwise, quietly return 1. */
+
static int
member_function_or_else (ctype, cur_type, string)
tree ctype, cur_type;
@@ -7117,6 +7769,7 @@ member_function_or_else (ctype, cur_type, string)
/* Generate errors possibly applicable for a given set of specifiers.
This is for ARM $7.1.2. */
+
static void
bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises)
tree object;
@@ -7147,18 +7800,23 @@ bad_specifiers (object, type, virtualp, quals, inlinep, friendp, raises)
RAISES is a list of exceptions that this function can raise.
CHECK is 1 if we must find this method in CTYPE, 0 if we should
not look, and -1 if we should not call `grokclassfn' at all. */
+
static tree
-grokfndecl (ctype, type, declarator, virtualp, flags, quals,
- raises, attrlist, check, publicp, inlinep)
+grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
+ raises, attrlist, check, friendp, publicp, inlinep, funcdef_flag,
+ template_count, in_namespace)
tree ctype, type;
tree declarator;
+ tree orig_declarator;
int virtualp;
enum overload_flags flags;
tree quals, raises, attrlist;
- int check, publicp, inlinep;
+ int check, friendp, publicp, inlinep, funcdef_flag, template_count;
+ tree in_namespace;
{
tree cname, decl;
int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
+ tree t;
if (ctype)
cname = TREE_CODE (TYPE_NAME (ctype)) == TYPE_DECL
@@ -7169,26 +7827,28 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
if (raises)
{
type = build_exception_variant (type, raises);
- raises = TYPE_RAISES_EXCEPTIONS (type);
}
+
decl = build_lang_decl (FUNCTION_DECL, declarator, type);
- /* propagate volatile out from type to decl */
+ /* Propagate volatile out from type to decl. */
if (TYPE_VOLATILE (type))
- TREE_THIS_VOLATILE (decl) = 1;
+ TREE_THIS_VOLATILE (decl) = 1;
+
+ /* This decl is not from the current namespace. */
+ if (in_namespace)
+ set_decl_namespace (decl, in_namespace);
/* Should probably propagate const out from type to decl I bet (mrs). */
if (staticp)
{
DECL_STATIC_FUNCTION_P (decl) = 1;
DECL_CONTEXT (decl) = ctype;
- DECL_CLASS_CONTEXT (decl) = ctype;
}
- /* All function decls start out public; we'll fix their linkage later (at
- definition or EOF) if appropriate. */
- TREE_PUBLIC (decl) = 1;
+ if (ctype)
+ DECL_CLASS_CONTEXT (decl) = ctype;
- if (ctype == NULL_TREE && ! strcmp (IDENTIFIER_POINTER (declarator), "main"))
+ if (ctype == NULL_TREE && MAIN_NAME_P (declarator))
{
if (inlinep)
error ("cannot declare `main' to be inline");
@@ -7198,8 +7858,12 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
publicp = 1;
}
+ TREE_PUBLIC (decl) = publicp;
if (! publicp)
- DECL_C_STATIC (decl) = 1;
+ {
+ DECL_INTERFACE_KNOWN (decl) = 1;
+ DECL_NOT_REALLY_EXTERN (decl) = 1;
+ }
if (inlinep)
DECL_THIS_INLINE (decl) = DECL_INLINE (decl) = 1;
@@ -7215,10 +7879,43 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
if (IDENTIFIER_OPNAME_P (DECL_NAME (decl)))
grok_op_properties (decl, virtualp, check < 0);
+ if (ctype && hack_decl_function_context (decl))
+ DECL_NO_STATIC_CHAIN (decl) = 1;
+
+ for (t = TYPE_ARG_TYPES (TREE_TYPE (decl)); t; t = TREE_CHAIN (t))
+ if (TREE_PURPOSE (t)
+ && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG)
+ {
+ add_defarg_fn (decl);
+ break;
+ }
+
+ if (friendp
+ && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)
+ {
+ if (funcdef_flag)
+ cp_error
+ ("defining explicit specialization `%D' in friend declaration",
+ orig_declarator);
+ else
+ {
+ /* A friend declaration of the form friend void f<>(). Record
+ the information in the TEMPLATE_ID_EXPR. */
+ SET_DECL_IMPLICIT_INSTANTIATION (decl);
+ DECL_TEMPLATE_INFO (decl)
+ = perm_tree_cons (TREE_OPERAND (orig_declarator, 0),
+ TREE_OPERAND (orig_declarator, 1),
+ NULL_TREE);
+ }
+ }
+
/* Caller will do the rest of this. */
if (check < 0)
return decl;
+ if (check && funcdef_flag)
+ DECL_INITIAL (decl) = error_mark_node;
+
if (flags == NO_SPECIAL && ctype && constructor_name (cname) == declarator)
{
tree tmp;
@@ -7230,26 +7927,40 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
DECL_CONSTRUCTOR_P (decl) = 1;
grokclassfn (ctype, declarator, decl, flags, quals);
- if (check)
- check_classfn (ctype, declarator, decl);
+
+ decl = check_explicit_specialization (orig_declarator, decl,
+ template_count,
+ 2 * (funcdef_flag != 0) +
+ 4 * (friendp != 0));
+
+ if ((! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl))
+ && check)
+ {
+ tmp = check_classfn (ctype, decl);
+
+ if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
+ tmp = DECL_TEMPLATE_RESULT(tmp);
+
+ if (tmp && DECL_ARTIFICIAL (tmp))
+ cp_error ("definition of implicitly-declared `%D'", tmp);
+ if (tmp && duplicate_decls (decl, tmp))
+ return tmp;
+ }
if (! grok_ctor_properties (ctype, decl))
return NULL_TREE;
if (check == 0 && ! current_function_decl)
{
- /* FIXME: this should only need to look at
- IDENTIFIER_GLOBAL_VALUE. */
- tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
+ /* Assembler names live in the global namespace. */
+ tmp = IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl));
if (tmp == NULL_TREE)
- IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl;
+ SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl), decl);
else if (TREE_CODE (tmp) != TREE_CODE (decl))
cp_error ("inconsistent declarations for `%D'", decl);
else
{
duplicate_decls (decl, tmp);
decl = tmp;
- /* avoid creating circularities. */
- DECL_CHAIN (decl) = NULL_TREE;
}
make_decl_rtl (decl, NULL_PTR, 1);
}
@@ -7264,8 +7975,36 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
if (ctype != NULL_TREE)
grokclassfn (ctype, cname, decl, flags, quals);
- if (ctype != NULL_TREE && check)
- check_classfn (ctype, cname, decl);
+ decl = check_explicit_specialization (orig_declarator, decl,
+ template_count,
+ 2 * (funcdef_flag != 0) +
+ 4 * (friendp != 0));
+ if (ctype != NULL_TREE
+ && (! TYPE_FOR_JAVA (ctype) || check_java_method (ctype, decl))
+ && check)
+ {
+ tmp = check_classfn (ctype, decl);
+
+ if (tmp && TREE_CODE (tmp) == TEMPLATE_DECL)
+ tmp = DECL_TEMPLATE_RESULT (tmp);
+
+ if (tmp && DECL_STATIC_FUNCTION_P (tmp)
+ && TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
+ {
+ /* Remove the `this' parm added by grokclassfn.
+ XXX Isn't this done in start_function, too? */
+ revert_static_member_fn (&decl, NULL, NULL);
+ last_function_parms = TREE_CHAIN (last_function_parms);
+ }
+ if (tmp && DECL_ARTIFICIAL (tmp))
+ cp_error ("definition of implicitly-declared `%D'", tmp);
+ if (tmp)
+ {
+ if (!duplicate_decls (decl, tmp))
+ my_friendly_abort (892);
+ return tmp;
+ }
+ }
if (ctype == NULL_TREE || check)
return decl;
@@ -7275,19 +8014,25 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
methods, though. */
if (! current_function_decl)
{
- /* FIXME: this should only need to look at
- IDENTIFIER_GLOBAL_VALUE. */
- tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
- if (tmp == NULL_TREE)
- IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl)) = decl;
- else if (TREE_CODE (tmp) != TREE_CODE (decl))
- cp_error ("inconsistent declarations for `%D'", decl);
- else
+ if (!DECL_TEMPLATE_SPECIALIZATION (decl))
{
- duplicate_decls (decl, tmp);
- decl = tmp;
- /* avoid creating circularities. */
- DECL_CHAIN (decl) = NULL_TREE;
+ /* We don't do this for specializations since the
+ equivalent checks will be done later. Also, at this
+ point the DECL_ASSEMBLER_NAME is not yet fully
+ accurate. */
+
+ /* FIXME: this should only need to look at
+ IDENTIFIER_GLOBAL_VALUE. */
+ tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
+ if (tmp == NULL_TREE)
+ SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl), decl);
+ else if (TREE_CODE (tmp) != TREE_CODE (decl))
+ cp_error ("inconsistent declarations for `%D'", decl);
+ else
+ {
+ duplicate_decls (decl, tmp);
+ decl = tmp;
+ }
}
if (attrlist)
@@ -7295,95 +8040,30 @@ grokfndecl (ctype, type, declarator, virtualp, flags, quals,
TREE_VALUE (attrlist));
make_decl_rtl (decl, NULL_PTR, 1);
}
-
- /* If this declaration supersedes the declaration of
- a method declared virtual in the base class, then
- mark this field as being virtual as well. */
- {
- tree binfos = BINFO_BASETYPES (TYPE_BINFO (ctype));
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
- for (i = 0; i < n_baselinks; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- if (TYPE_VIRTUAL_P (BINFO_TYPE (base_binfo))
- || flag_all_virtual == 1)
- {
- tmp = get_matching_virtual (base_binfo, decl,
- flags == DTOR_FLAG);
- if (tmp)
- {
- /* If this function overrides some virtual in some base
- class, then the function itself is also necessarily
- virtual, even if the user didn't explicitly say so. */
- DECL_VIRTUAL_P (decl) = 1;
-
- /* The TMP we really want is the one from the deepest
- baseclass on this path, taking care not to
- duplicate if we have already found it (via another
- path to its virtual baseclass. */
- if (staticp)
- {
- cp_error ("method `%D' may not be declared static",
- decl);
- cp_error_at ("(since `%D' declared virtual in base class.)",
- tmp);
- break;
- }
- virtualp = 1;
-
- {
- /* The argument types may have changed... */
- tree argtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
- tree base_variant = TREE_TYPE (TREE_VALUE (argtypes));
-
- argtypes = commonparms (TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (tmp))),
- TREE_CHAIN (argtypes));
- /* But the return type has not. */
- type = build_cplus_method_type (base_variant, TREE_TYPE (type), argtypes);
- if (raises)
- {
- type = build_exception_variant (type, raises);
- raises = TYPE_RAISES_EXCEPTIONS (type);
- }
- TREE_TYPE (decl) = type;
- DECL_VINDEX (decl)
- = tree_cons (NULL_TREE, tmp, DECL_VINDEX (decl));
- }
- break;
- }
- }
- }
- }
if (virtualp)
{
+ DECL_VIRTUAL_P (decl) = 1;
if (DECL_VINDEX (decl) == NULL_TREE)
DECL_VINDEX (decl) = error_mark_node;
IDENTIFIER_VIRTUAL_P (DECL_NAME (decl)) = 1;
- if (ctype && CLASSTYPE_VTABLE_NEEDS_WRITING (ctype)
- /* If this function is derived from a template, don't
- make it public. This shouldn't be here, but there's
- no good way to override the interface pragmas for one
- function or class only. Bletch. */
- && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (ctype)) == NULL_TREE
- && (write_virtuals == 2
- || (write_virtuals == 3
- && CLASSTYPE_INTERFACE_KNOWN (ctype))))
- TREE_PUBLIC (decl) = 1;
}
}
return decl;
}
static tree
-grokvardecl (type, declarator, specbits, initialized, constp)
+grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace)
tree type;
tree declarator;
- RID_BIT_TYPE specbits;
+ RID_BIT_TYPE *specbits_in;
int initialized;
int constp;
+ tree in_namespace;
{
tree decl;
+ RID_BIT_TYPE specbits;
+
+ specbits = *specbits_in;
if (TREE_CODE (type) == OFFSET_TYPE)
{
@@ -7397,9 +8077,17 @@ grokvardecl (type, declarator, specbits, initialized, constp)
DECL_ASSEMBLER_NAME (decl) = build_static_name (basetype, declarator);
}
else
- decl = build_decl (VAR_DECL, declarator, type);
+ {
+ tree context = in_namespace ? in_namespace : current_namespace;
+ decl = build_decl (VAR_DECL, declarator, complete_type (type));
+ if (context != global_namespace && namespace_bindings_p ()
+ && current_lang_name != lang_name_c)
+ DECL_ASSEMBLER_NAME (decl) = build_static_name (context,
+ declarator);
+ }
- DECL_ASSEMBLER_NAME (decl) = current_namespace_id (DECL_ASSEMBLER_NAME (decl));
+ if (in_namespace)
+ set_decl_namespace (decl, in_namespace);
if (RIDBIT_SETP (RID_EXTERN, specbits))
{
@@ -7409,8 +8097,7 @@ grokvardecl (type, declarator, specbits, initialized, constp)
/* In class context, static means one per class,
public access, and static storage. */
- if (DECL_FIELD_CONTEXT (decl) != NULL_TREE
- && IS_AGGR_TYPE (DECL_FIELD_CONTEXT (decl)))
+ if (DECL_CLASS_SCOPE_P (decl))
{
TREE_PUBLIC (decl) = 1;
TREE_STATIC (decl) = 1;
@@ -7433,7 +8120,7 @@ grokvardecl (type, declarator, specbits, initialized, constp)
return decl;
}
-/* Create a canonical pointer to member function type. */
+/* Create a canonical pointer to member function type. */
tree
build_ptrmemfunc_type (type)
@@ -7462,9 +8149,9 @@ build_ptrmemfunc_type (type)
t = make_lang_type (RECORD_TYPE);
- /* Let the front-end know this is a pointer to member function. */
+ /* Let the front-end know this is a pointer to member function... */
TYPE_PTRMEMFUNC_FLAG (t) = 1;
- /* and not really an aggregate. */
+ /* ... and not really an aggregate. */
IS_AGGR_TYPE (t) = 0;
fields[0] = build_lang_field_decl (FIELD_DECL, delta_identifier,
@@ -7482,7 +8169,7 @@ build_ptrmemfunc_type (type)
TYPE_SET_PTRMEMFUNC_TYPE (type, t);
- /* Seems to be wanted. */
+ /* Seems to be wanted. */
CLASSTYPE_GOT_SEMICOLON (t) = 1;
return t;
}
@@ -7546,12 +8233,12 @@ build_ptrmemfunc_type (type)
enum return_types { return_normal, return_ctor, return_dtor, return_conversion };
tree
-grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrlist)
+grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
tree declspecs;
tree declarator;
enum decl_context decl_context;
int initialized;
- tree raises, attrlist;
+ tree attrlist;
{
RID_BIT_TYPE specbits;
int nclasses = 0;
@@ -7563,6 +8250,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
int virtualp, explicitp, friendp, inlinep, staticp;
int explicit_int = 0;
int explicit_char = 0;
+ int defaulted_int = 0;
int opaque_typedef = 0;
tree typedef_decl = NULL_TREE;
char *name;
@@ -7570,8 +8258,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
int funcdef_flag = 0;
enum tree_code innermost_code = ERROR_MARK;
int bitfield = 0;
- int size_varies = 0;
+#if 0
+ /* See the code below that used this. */
tree decl_machine_attr = NULL_TREE;
+#endif
/* Set this to error_mark_node for FIELD_DECLs we could not handle properly.
All FIELD_DECLs we build here have `init' put into their DECL_INITIAL. */
tree init = NULL_TREE;
@@ -7586,6 +8276,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
tree ctor_return_type = NULL_TREE;
enum overload_flags flags = NO_SPECIAL;
tree quals = NULL_TREE;
+ tree raises = NULL_TREE;
+ int template_count = 0;
+ tree in_namespace = NULL_TREE;
RIDBIT_RESET_ALL (specbits);
if (decl_context == FUNCDEF)
@@ -7595,228 +8288,263 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
else if (decl_context == BITFIELD)
bitfield = 1, decl_context = FIELD;
- if (flag_traditional && allocation_temporary_p ())
- end_temporary_allocation ();
-
/* Look inside a declarator for the name being declared
and get it as a string, for an error message. */
{
- tree last = NULL_TREE;
- register tree decl = declarator;
+ tree *next = &declarator;
+ register tree decl;
name = NULL;
- while (decl)
- switch (TREE_CODE (decl))
- {
- case COND_EXPR:
- ctype = NULL_TREE;
- decl = TREE_OPERAND (decl, 0);
- break;
-
- case BIT_NOT_EXPR: /* for C++ destructors! */
+ while (next && *next)
+ {
+ decl = *next;
+ switch (TREE_CODE (decl))
{
- tree name = TREE_OPERAND (decl, 0);
- tree rename = NULL_TREE;
-
- my_friendly_assert (flags == NO_SPECIAL, 152);
- flags = DTOR_FLAG;
- return_type = return_dtor;
- my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153);
- if (ctype == NULL_TREE)
- {
- if (current_class_type == NULL_TREE)
- {
- error ("destructors must be member functions");
- flags = NO_SPECIAL;
- }
- else
- {
- tree t = constructor_name (current_class_name);
- if (t != name)
- rename = t;
- }
- }
- else
- {
- tree t = constructor_name (ctype);
- if (t != name)
- rename = t;
- }
-
- if (rename)
- {
- error ("destructor `%s' must match class name `%s'",
- IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (rename));
- TREE_OPERAND (decl, 0) = rename;
- }
- decl = name;
- }
- break;
-
- case ADDR_EXPR: /* C++ reference declaration */
- /* fall through */
- case ARRAY_REF:
- case INDIRECT_REF:
- ctype = NULL_TREE;
- innermost_code = TREE_CODE (decl);
- last = decl;
- decl = TREE_OPERAND (decl, 0);
- break;
+ case COND_EXPR:
+ ctype = NULL_TREE;
+ next = &TREE_OPERAND (decl, 0);
+ break;
- case CALL_EXPR:
- if (parmlist_is_exprlist (TREE_OPERAND (decl, 1)))
+ case BIT_NOT_EXPR: /* For C++ destructors! */
{
- /* This is actually a variable declaration using constructor
- syntax. We need to call start_decl and cp_finish_decl so we
- can get the variable initialized... */
-
- if (last)
- /* We need to insinuate ourselves into the declarator in place
- of the CALL_EXPR. */
- TREE_OPERAND (last, 0) = TREE_OPERAND (decl, 0);
+ tree name = TREE_OPERAND (decl, 0);
+ tree rename = NULL_TREE;
+
+ my_friendly_assert (flags == NO_SPECIAL, 152);
+ flags = DTOR_FLAG;
+ return_type = return_dtor;
+ if (TREE_CODE (name) == TYPE_DECL)
+ TREE_OPERAND (decl, 0) = name = constructor_name (name);
+ my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 153);
+ if (ctype == NULL_TREE)
+ {
+ if (current_class_type == NULL_TREE)
+ {
+ error ("destructors must be member functions");
+ flags = NO_SPECIAL;
+ }
+ else
+ {
+ tree t = constructor_name (current_class_name);
+ if (t != name)
+ rename = t;
+ }
+ }
else
- declarator = TREE_OPERAND (decl, 0);
-
- init = TREE_OPERAND (decl, 1);
-
- decl = start_decl (declarator, declspecs, 1, NULL_TREE);
- finish_decl (decl, init, NULL_TREE);
- return 0;
- }
- innermost_code = TREE_CODE (decl);
- if (decl_context == FIELD && ctype == NULL_TREE)
- ctype = current_class_type;
- if (ctype
- && TREE_OPERAND (decl, 0) == constructor_name_full (ctype))
- TREE_OPERAND (decl, 0) = constructor_name (ctype);
- decl = TREE_OPERAND (decl, 0);
- if (ctype != NULL_TREE
- && decl != NULL_TREE && flags != DTOR_FLAG
- && decl == constructor_name (ctype))
- {
- return_type = return_ctor;
- ctor_return_type = ctype;
- }
- ctype = NULL_TREE;
- break;
-
- case IDENTIFIER_NODE:
- dname = decl;
- decl = NULL_TREE;
+ {
+ tree t = constructor_name (ctype);
+ if (t != name)
+ rename = t;
+ }
- if (! IDENTIFIER_OPNAME_P (dname)
- /* Linux headers use '__op'. Arrgh. */
- || IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname))
- name = IDENTIFIER_POINTER (dname);
- else
- {
- if (IDENTIFIER_TYPENAME_P (dname))
+ if (rename)
{
- my_friendly_assert (flags == NO_SPECIAL, 154);
- flags = TYPENAME_FLAG;
- ctor_return_type = TREE_TYPE (dname);
- return_type = return_conversion;
+ cp_error ("destructor `%T' must match class name `%T'",
+ name, rename);
+ TREE_OPERAND (decl, 0) = rename;
}
- name = operator_name_string (dname);
+ next = &name;
}
- break;
+ break;
- case RECORD_TYPE:
- case UNION_TYPE:
- case ENUMERAL_TYPE:
- /* Parse error puts this typespec where
- a declarator should go. */
- error ("declarator name missing");
- dname = TYPE_NAME (decl);
- if (dname && TREE_CODE (dname) == TYPE_DECL)
- dname = DECL_NAME (dname);
- name = dname ? IDENTIFIER_POINTER (dname) : "<nameless>";
- declspecs = temp_tree_cons (NULL_TREE, decl, declspecs);
- decl = NULL_TREE;
- break;
+ case ADDR_EXPR: /* C++ reference declaration */
+ /* Fall through. */
+ case ARRAY_REF:
+ case INDIRECT_REF:
+ ctype = NULL_TREE;
+ innermost_code = TREE_CODE (decl);
+ next = &TREE_OPERAND (decl, 0);
+ break;
- /* C++ extension */
- case SCOPE_REF:
- {
- /* Perform error checking, and convert class names to types.
- We may call grokdeclarator multiple times for the same
- tree structure, so only do the conversion once. In this
- case, we have exactly what we want for `ctype'. */
- tree cname = TREE_OPERAND (decl, 0);
- if (cname == NULL_TREE)
- ctype = NULL_TREE;
- /* Can't use IS_AGGR_TYPE because CNAME might not be a type. */
- else if (IS_AGGR_TYPE_CODE (TREE_CODE (cname))
- || TREE_CODE (cname) == UNINSTANTIATED_P_TYPE)
- ctype = cname;
- else if (! is_aggr_typedef (cname, 1))
+ case CALL_EXPR:
+ if (parmlist_is_exprlist (TREE_OPERAND (decl, 1)))
{
- TREE_OPERAND (decl, 0) = NULL_TREE;
- }
- /* Must test TREE_OPERAND (decl, 1), in case user gives
- us `typedef (class::memfunc)(int); memfunc *memfuncptr;' */
- else if (TREE_OPERAND (decl, 1)
- && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF)
- {
- TREE_OPERAND (decl, 0) = IDENTIFIER_TYPE_VALUE (cname);
+ /* This is actually a variable declaration using constructor
+ syntax. We need to call start_decl and cp_finish_decl so we
+ can get the variable initialized... */
+
+ *next = TREE_OPERAND (decl, 0);
+ init = TREE_OPERAND (decl, 1);
+
+ decl = start_decl (declarator, declspecs, 1, NULL_TREE, NULL_TREE);
+ /* Look for __unused__ attribute */
+ if (TREE_USED (TREE_TYPE (decl)))
+ TREE_USED (decl) = 1;
+ finish_decl (decl, init, NULL_TREE);
+ return 0;
}
- else if (ctype == NULL_TREE)
+ innermost_code = TREE_CODE (decl);
+ if (decl_context == FIELD && ctype == NULL_TREE)
+ ctype = current_class_type;
+ if (ctype
+ && TREE_OPERAND (decl, 0)
+ && (TREE_CODE (TREE_OPERAND (decl, 0)) == TYPE_DECL
+ && ((DECL_NAME (TREE_OPERAND (decl, 0))
+ == constructor_name_full (ctype))
+ || (DECL_NAME (TREE_OPERAND (decl, 0))
+ == constructor_name (ctype)))))
+ TREE_OPERAND (decl, 0) = constructor_name (ctype);
+ next = &TREE_OPERAND (decl, 0);
+ decl = *next;
+ if (ctype != NULL_TREE
+ && decl != NULL_TREE && flags != DTOR_FLAG
+ && decl == constructor_name (ctype))
{
- ctype = IDENTIFIER_TYPE_VALUE (cname);
- TREE_OPERAND (decl, 0) = ctype;
+ return_type = return_ctor;
+ ctor_return_type = ctype;
}
- else if (TREE_COMPLEXITY (decl) == current_class_depth)
- TREE_OPERAND (decl, 0) = ctype;
- else
+ ctype = NULL_TREE;
+ break;
+
+ case TEMPLATE_ID_EXPR:
{
- if (! UNIQUELY_DERIVED_FROM_P (IDENTIFIER_TYPE_VALUE (cname),
- ctype))
- {
- cp_error ("type `%T' is not derived from type `%T'",
- IDENTIFIER_TYPE_VALUE (cname), ctype);
- TREE_OPERAND (decl, 0) = NULL_TREE;
- }
+ tree fns = TREE_OPERAND (decl, 0);
+
+ if (TREE_CODE (fns) == LOOKUP_EXPR)
+ fns = TREE_OPERAND (fns, 0);
+
+ if (TREE_CODE (fns) == IDENTIFIER_NODE)
+ dname = fns;
+ else if (is_overloaded_fn (fns))
+ dname = DECL_NAME (get_first_fn (fns));
else
- {
- ctype = IDENTIFIER_TYPE_VALUE (cname);
- TREE_OPERAND (decl, 0) = ctype;
- }
+ my_friendly_abort (0);
}
+ /* Fall through. */
- if (ctype
- && TREE_OPERAND (decl, 1) == constructor_name_full (ctype))
- TREE_OPERAND (decl, 1) = constructor_name (ctype);
- decl = TREE_OPERAND (decl, 1);
- if (ctype)
+ case IDENTIFIER_NODE:
+ if (TREE_CODE (decl) == IDENTIFIER_NODE)
+ dname = decl;
+
+ next = 0;
+
+ if (is_rid (dname))
{
- if (TREE_CODE (decl) == IDENTIFIER_NODE
- && constructor_name (ctype) == decl)
- {
- return_type = return_ctor;
- ctor_return_type = ctype;
- }
- else if (TREE_CODE (decl) == BIT_NOT_EXPR
- && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
- && (constructor_name (ctype) == TREE_OPERAND (decl, 0)
- || constructor_name_full (ctype) == TREE_OPERAND (decl, 0)))
+ cp_error ("declarator-id missing; using reserved word `%D'",
+ dname);
+ name = IDENTIFIER_POINTER (dname);
+ }
+ if (! IDENTIFIER_OPNAME_P (dname)
+ /* GNU/Linux headers use '__op'. Arrgh. */
+ || (IDENTIFIER_TYPENAME_P (dname) && ! TREE_TYPE (dname)))
+ name = IDENTIFIER_POINTER (dname);
+ else
+ {
+ if (IDENTIFIER_TYPENAME_P (dname))
{
- return_type = return_dtor;
- ctor_return_type = ctype;
- flags = DTOR_FLAG;
- decl = TREE_OPERAND (decl, 0) = constructor_name (ctype);
+ my_friendly_assert (flags == NO_SPECIAL, 154);
+ flags = TYPENAME_FLAG;
+ ctor_return_type = TREE_TYPE (dname);
+ return_type = return_conversion;
}
+ name = operator_name_string (dname);
}
- }
- break;
+ break;
- case ERROR_MARK:
- decl = NULL_TREE;
- break;
+ /* C++ extension */
+ case SCOPE_REF:
+ {
+ /* Perform error checking, and decide on a ctype. */
+ tree cname = TREE_OPERAND (decl, 0);
+ if (cname == NULL_TREE)
+ ctype = NULL_TREE;
+ else if (TREE_CODE (cname) == NAMESPACE_DECL)
+ {
+ ctype = NULL_TREE;
+ in_namespace = TREE_OPERAND (decl, 0);
+ TREE_OPERAND (decl, 0) = NULL_TREE;
+ }
+ else if (! is_aggr_type (cname, 1))
+ TREE_OPERAND (decl, 0) = NULL_TREE;
+ /* Must test TREE_OPERAND (decl, 1), in case user gives
+ us `typedef (class::memfunc)(int); memfunc *memfuncptr;' */
+ else if (TREE_OPERAND (decl, 1)
+ && TREE_CODE (TREE_OPERAND (decl, 1)) == INDIRECT_REF)
+ ctype = cname;
+ else if (TREE_CODE (cname) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (cname) == TEMPLATE_TEMPLATE_PARM)
+ {
+ cp_error ("`%T::%D' is not a valid declarator", cname,
+ TREE_OPERAND (decl, 1));
+ cp_error (" perhaps you want `typename %T::%D' to make it a type",
+ cname, TREE_OPERAND (decl, 1));
+ return void_type_node;
+ }
+ else if (ctype == NULL_TREE)
+ ctype = cname;
+ else if (TREE_COMPLEXITY (decl) == current_class_depth)
+ TREE_OPERAND (decl, 0) = ctype;
+ else
+ {
+ if (! UNIQUELY_DERIVED_FROM_P (cname, ctype))
+ {
+ cp_error ("type `%T' is not derived from type `%T'",
+ cname, ctype);
+ TREE_OPERAND (decl, 0) = NULL_TREE;
+ }
+ else
+ ctype = cname;
+ }
- default:
- return 0; /* We used to do a 155 abort here. */
- }
+ if (ctype && TREE_CODE (TREE_OPERAND (decl, 1)) == TYPE_DECL
+ && ((DECL_NAME (TREE_OPERAND (decl, 1))
+ == constructor_name_full (ctype))
+ || (DECL_NAME (TREE_OPERAND (decl, 1))
+ == constructor_name (ctype))))
+ TREE_OPERAND (decl, 1) = constructor_name (ctype);
+ next = &TREE_OPERAND (decl, 1);
+ decl = *next;
+ if (ctype)
+ {
+ if (TREE_CODE (decl) == IDENTIFIER_NODE
+ && constructor_name (ctype) == decl)
+ {
+ return_type = return_ctor;
+ ctor_return_type = ctype;
+ }
+ else if (TREE_CODE (decl) == BIT_NOT_EXPR
+ && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
+ && (constructor_name (ctype) == TREE_OPERAND (decl, 0)
+ || constructor_name_full (ctype) == TREE_OPERAND (decl, 0)))
+ {
+ return_type = return_dtor;
+ ctor_return_type = ctype;
+ flags = DTOR_FLAG;
+ TREE_OPERAND (decl, 0) = constructor_name (ctype);
+ next = &TREE_OPERAND (decl, 0);
+ }
+ }
+ }
+ break;
+
+ case ERROR_MARK:
+ next = 0;
+ break;
+
+ case TYPE_DECL:
+ /* Parse error puts this typespec where
+ a declarator should go. */
+ cp_error ("`%T' specified as declarator-id", DECL_NAME (decl));
+ if (TREE_TYPE (decl) == current_class_type)
+ cp_error (" perhaps you want `%T' for a constructor",
+ current_class_name);
+ dname = DECL_NAME (decl);
+ name = IDENTIFIER_POINTER (dname);
+
+ /* Avoid giving two errors for this. */
+ IDENTIFIER_CLASS_VALUE (dname) = NULL_TREE;
+
+ declspecs = temp_tree_cons (NULL_TREE, integer_type_node,
+ declspecs);
+ *next = dname;
+ next = 0;
+ break;
+
+ default:
+ cp_compiler_error ("`%D' as declarator", decl);
+ return 0; /* We used to do a 155 abort here. */
+ }
+ }
if (name == NULL)
name = "type name";
}
@@ -7849,7 +8577,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
We also want to avoid calling this a PARM if it is in a namespace. */
- if (decl_context == NORMAL && ! namespace_bindings_p ())
+ if (decl_context == NORMAL && ! namespace_bindings_p ()
+ && ! pseudo_global_level_p ())
{
struct binding_level *b = current_binding_level;
current_binding_level = b->level_chain;
@@ -7911,7 +8640,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
goto found;
}
- /* C++ aggregate types. */
+ /* C++ aggregate types. */
if (IDENTIFIER_HAS_TYPE_VALUE (id))
{
if (type)
@@ -7927,9 +8656,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
{
if (i == (int) RID_LONG && RIDBIT_SETP (i, specbits))
{
- if (pedantic && ! in_system_header)
+ if (pedantic && ! in_system_header && warn_long_long)
pedwarn ("ANSI C++ does not support `long long'");
- else if (longlong)
+ if (longlong)
error ("`long long long' is too long for GCC");
else
longlong = 1;
@@ -7941,6 +8670,19 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
}
}
+ /* C++ aggregate types. */
+ else if (TREE_CODE (id) == TYPE_DECL || TREE_CODE (id) == TEMPLATE_DECL)
+ {
+ if (type)
+ cp_error ("multiple declarations `%T' and `%T'", type,
+ TREE_TYPE (id));
+ else
+ {
+ type = TREE_TYPE (id);
+ TREE_VALUE (spec) = type;
+ }
+ goto found;
+ }
if (type)
error ("two or more data types in declaration of `%s'", name);
else if (TREE_CODE (id) == IDENTIFIER_NODE)
@@ -7952,11 +8694,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
else
{
type = TREE_TYPE (t);
+#if 0
+ /* See the code below that used this. */
decl_machine_attr = DECL_MACHINE_ATTRIBUTES (id);
+#endif
typedef_decl = t;
}
}
- else if (TREE_CODE (id) != ERROR_MARK)
+ else if (id != error_mark_node)
/* Can't change CLASS nodes into RECORD nodes here! */
type = id;
@@ -7965,7 +8710,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
typedef_type = type;
- /* No type at all: default to `int', and set EXPLICIT_INT
+ /* No type at all: default to `int', and set DEFAULTED_INT
because it was not a user-defined typedef.
Except when we have a `typedef' inside a signature, in
which case the type defaults to `unknown type' and is
@@ -7979,7 +8724,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
{
/* These imply 'int'. */
type = integer_type_node;
- explicit_int = 1;
+ defaulted_int = 1;
}
if (type == NULL_TREE)
@@ -7993,18 +8738,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
type = ctor_return_type;
else if (current_class_type
&& IS_SIGNATURE (current_class_type)
- && (RIDBIT_SETP (RID_TYPEDEF, specbits)
- || SIGNATURE_GROKKING_TYPEDEF (current_class_type))
+ && RIDBIT_SETP (RID_TYPEDEF, specbits)
&& (decl_context == FIELD || decl_context == NORMAL))
{
explicit_int = 0;
opaque_typedef = 1;
type = copy_node (opaque_type_node);
}
- /* access declaration */
- else if (decl_context == FIELD && declarator
- && TREE_CODE (declarator) == SCOPE_REF)
- type = void_type_node;
else
{
if (funcdef_flag)
@@ -8016,10 +8756,15 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
else if (RIDBIT_SETP (RID_TYPEDEF, specbits))
pedwarn ("ANSI C++ forbids typedef which does not specify a type");
- else if (declspecs == NULL_TREE &&
- (innermost_code != CALL_EXPR || pedantic))
- cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type or storage class",
- dname);
+ else if (innermost_code != CALL_EXPR || pedantic
+ || (warn_return_type && return_type == return_normal))
+ {
+ if (innermost_code == CALL_EXPR)
+ cp_pedwarn ("return-type of `%D' defaults to `int'", dname);
+ else
+ cp_pedwarn ("ANSI C++ forbids declaration `%D' with no type",
+ dname);
+ }
type = integer_type_node;
}
}
@@ -8044,13 +8789,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
type = ctor_return_type;
}
- /* Catch typedefs that only specify a type, like 'typedef int;'. */
- else if (RIDBIT_SETP (RID_TYPEDEF, specbits) && declarator == NULL_TREE)
- {
- /* Template "this is a type" syntax; just ignore for now. */
- if (processing_template_defn)
- return void_type_node;
- }
ctype = NULL_TREE;
@@ -8097,7 +8835,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
else
{
ok = 1;
- if (!explicit_int && !explicit_char && pedantic)
+ if (!explicit_int && !defaulted_int && !explicit_char && pedantic)
{
pedwarn ("long, short, signed or unsigned used invalidly for `%s'",
name);
@@ -8117,13 +8855,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
}
+ if (RIDBIT_SETP (RID_COMPLEX, specbits)
+ && TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE)
+ {
+ error ("complex invalid for `%s'", name);
+ RIDBIT_RESET (RID_COMPLEX, specbits);
+ }
+
/* Decide whether an integer type is signed or not.
Optionally treat bitfields as signed by default. */
if (RIDBIT_SETP (RID_UNSIGNED, specbits)
- /* Traditionally, all bitfields are unsigned. */
- || (bitfield && flag_traditional)
|| (bitfield && ! flag_signed_bitfields
- && (explicit_int || explicit_char
+ && (explicit_int || defaulted_int || explicit_char
/* A typedef for plain `int' without `signed'
can be controlled just like plain `int'. */
|| ! (typedef_decl != NULL_TREE
@@ -8154,21 +8897,46 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
else if (RIDBIT_SETP (RID_SHORT, specbits))
type = short_integer_type_node;
+ if (RIDBIT_SETP (RID_COMPLEX, specbits))
+ {
+ /* If we just have "complex", it is equivalent to
+ "complex double", but if any modifiers at all are specified it is
+ the complex form of TYPE. E.g, "complex short" is
+ "complex short int". */
+
+ if (defaulted_int && ! longlong
+ && ! (RIDBIT_SETP (RID_LONG, specbits)
+ || RIDBIT_SETP (RID_SHORT, specbits)
+ || RIDBIT_SETP (RID_SIGNED, specbits)
+ || RIDBIT_SETP (RID_UNSIGNED, specbits)))
+ type = complex_double_type_node;
+ else if (type == integer_type_node)
+ type = complex_integer_type_node;
+ else if (type == float_type_node)
+ type = complex_float_type_node;
+ else if (type == double_type_node)
+ type = complex_double_type_node;
+ else if (type == long_double_type_node)
+ type = complex_long_double_type_node;
+ else
+ type = build_complex_type (type);
+ }
+
+ if (return_type == return_conversion
+ && (RIDBIT_SETP (RID_CONST, specbits)
+ || RIDBIT_SETP (RID_VOLATILE, specbits)))
+ cp_error ("`operator %T' cannot be cv-qualified",
+ ctor_return_type);
+
/* Set CONSTP if this declaration is `const', whether by
explicit specification or via a typedef.
Likewise for VOLATILEP. */
constp = !! RIDBIT_SETP (RID_CONST, specbits) + TYPE_READONLY (type);
volatilep = !! RIDBIT_SETP (RID_VOLATILE, specbits) + TYPE_VOLATILE (type);
+ type = build_type_variant (type, 0, 0);
staticp = 0;
inlinep = !! RIDBIT_SETP (RID_INLINE, specbits);
-#if 0
- /* This sort of redundancy is blessed in a footnote to the Sep 94 WP. */
- if (constp > 1)
- warning ("duplicate `const'");
- if (volatilep > 1)
- warning ("duplicate `volatile'");
-#endif
virtualp = RIDBIT_SETP (RID_VIRTUAL, specbits);
RIDBIT_RESET (RID_VIRTUAL, specbits);
explicitp = RIDBIT_SETP (RID_EXPLICIT, specbits) != 0;
@@ -8198,20 +8966,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
error ("non-object member `%s' cannot be declared `mutable'", name);
RIDBIT_RESET (RID_MUTABLE, specbits);
}
-#if 0
- if (RIDBIT_SETP (RID_TYPEDEF, specbits))
- {
- error ("non-object member `%s' cannot be declared `mutable'", name);
- RIDBIT_RESET (RID_MUTABLE, specbits);
- }
- /* Because local typedefs are parsed twice, we don't want this
- message here. */
- else if (decl_context != FIELD)
- {
- error ("non-member `%s' cannot be declared `mutable'", name);
- RIDBIT_RESET (RID_MUTABLE, specbits);
- }
-#endif
}
/* Warn if two storage classes are given. Default to `auto'. */
@@ -8248,16 +9002,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
/* Static anonymous unions are dealt with here. */
if (staticp && decl_context == TYPENAME
&& TREE_CODE (declspecs) == TREE_LIST
- && TREE_CODE (TREE_VALUE (declspecs)) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TREE_VALUE (declspecs))))
+ && ANON_UNION_TYPE_P (TREE_VALUE (declspecs)))
decl_context = FIELD;
/* Give error if `const,' `volatile,' `inline,' `friend,' or `virtual'
is used in a signature member function declaration. */
if (decl_context == FIELD
&& IS_SIGNATURE (current_class_type)
- && RIDBIT_NOTSETP(RID_TYPEDEF, specbits)
- && !SIGNATURE_GROKKING_TYPEDEF (current_class_type))
+ && RIDBIT_NOTSETP (RID_TYPEDEF, specbits))
{
if (constp)
{
@@ -8301,82 +9053,10 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
&& (RIDBIT_SETP (RID_REGISTER, specbits)
|| RIDBIT_SETP (RID_AUTO, specbits)))
;
+ else if (RIDBIT_SETP (RID_TYPEDEF, specbits))
+ ;
else if (decl_context == FIELD
- && RIDBIT_SETP (RID_TYPEDEF, specbits))
- {
- /* Processing a typedef declaration nested within a class type
- definition. */
- register tree scanner;
- register tree previous_declspec;
- tree loc_typedecl;
-
- if (initialized)
- error ("typedef declaration includes an initializer");
-
- /* To process a class-local typedef declaration, we descend down
- the chain of declspecs looking for the `typedef' spec. When
- we find it, we replace it with `static', and then recursively
- call `grokdeclarator' with the original declarator and with
- the newly adjusted declspecs. This call should return a
- FIELD_DECL node with the TREE_TYPE (and other parts) set
- appropriately. We can then just change the TREE_CODE on that
- from FIELD_DECL to TYPE_DECL and we're done. */
-
- for (previous_declspec = NULL_TREE, scanner = declspecs;
- scanner;
- previous_declspec = scanner, scanner = TREE_CHAIN (scanner))
- {
- if (TREE_VALUE (scanner) == ridpointers[(int) RID_TYPEDEF])
- break;
- }
-
- if (previous_declspec)
- TREE_CHAIN (previous_declspec) = TREE_CHAIN (scanner);
- else
- declspecs = TREE_CHAIN (scanner);
-
- declspecs = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC],
- declspecs);
-
- /* In the recursive call to grokdeclarator we need to know
- whether we are working on a signature-local typedef. */
- if (IS_SIGNATURE (current_class_type))
- SIGNATURE_GROKKING_TYPEDEF (current_class_type) = 1;
-
- loc_typedecl =
- grokdeclarator (declarator, declspecs, FIELD, 0, NULL_TREE, NULL_TREE);
-
- if (previous_declspec)
- TREE_CHAIN (previous_declspec) = scanner;
-
- if (loc_typedecl != error_mark_node)
- {
- register int i = sizeof (struct lang_decl_flags) / sizeof (int);
- register int *pi;
-
- TREE_SET_CODE (loc_typedecl, TYPE_DECL);
- /* This is the same field as DECL_ARGUMENTS, which is set for
- function typedefs by the above grokdeclarator. */
- DECL_NESTED_TYPENAME (loc_typedecl) = 0;
-
- pi = (int *) permalloc (sizeof (struct lang_decl_flags));
- while (i > 0)
- pi[--i] = 0;
- DECL_LANG_SPECIFIC (loc_typedecl) = (struct lang_decl *) pi;
- }
-
- if (IS_SIGNATURE (current_class_type))
- {
- SIGNATURE_GROKKING_TYPEDEF (current_class_type) = 0;
- if (loc_typedecl != error_mark_node && opaque_typedef)
- SIGNATURE_HAS_OPAQUE_TYPEDECLS (current_class_type) = 1;
- }
-
- return loc_typedecl;
- }
- else if (decl_context == FIELD
- && (! IS_SIGNATURE (current_class_type)
- || SIGNATURE_GROKKING_TYPEDEF (current_class_type))
+ && ! IS_SIGNATURE (current_class_type)
/* C++ allows static class elements */
&& RIDBIT_SETP (RID_STATIC, specbits))
/* C++ also allows inlines and signed and unsigned elements,
@@ -8391,7 +9071,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
if (declarator)
{
- tmp = TREE_OPERAND (declarator, 0);
+ /* Avoid trying to get an operand off an identifier node. */
+ if (TREE_CODE (declarator) == IDENTIFIER_NODE)
+ tmp = declarator;
+ else
+ tmp = TREE_OPERAND (declarator, 0);
op = IDENTIFIER_OPNAME_P (tmp);
}
error ("storage class specified for %s `%s'",
@@ -8436,28 +9120,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
{
if (RIDBIT_SETP (RID_AUTO, specbits))
error ("top-level declaration of `%s' specifies `auto'", name);
-#if 0
- if (RIDBIT_SETP (RID_REGISTER, specbits))
- error ("top-level declaration of `%s' specifies `register'", name);
-#endif
-#if 0
- /* I'm not sure under what circumstances we should turn
- on the extern bit, and under what circumstances we should
- warn if other bits are turned on. */
- if (decl_context == NORMAL
- && RIDBIT_NOSETP (RID_EXTERN, specbits)
- && ! root_lang_context_p ())
- {
- RIDBIT_SET (RID_EXTERN, specbits);
- }
-#endif
}
+ if (nclasses > 0 && friendp)
+ error ("storage class specifiers invalid in friend function declarations");
+
/* Now figure out the structure of the declarator proper.
Descend through it, creating more complex types, until we reach
the declared identifier (or NULL_TREE, in an absolute declarator). */
- while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE)
+ while (declarator && TREE_CODE (declarator) != IDENTIFIER_NODE
+ && TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
{
/* Each level of DECLARATOR is either an ARRAY_REF (for ...[..]),
an INDIRECT_REF (for *...),
@@ -8480,7 +9153,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
array or function or pointer, and DECLARATOR has had its
outermost layer removed. */
- if (TREE_CODE (type) == ERROR_MARK)
+ if (type == error_mark_node)
{
if (TREE_CODE (declarator) == SCOPE_REF)
declarator = TREE_OPERAND (declarator, 1);
@@ -8496,11 +9169,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
ctype = TYPE_METHOD_BASETYPE (type);
if (ctype != NULL_TREE)
{
-#if 0 /* not yet, should get fixed properly later */
- tree dummy = make_type_decl (NULL_TREE, type);
-#else
tree dummy = build_decl (TYPE_DECL, NULL_TREE, type);
-#endif
ctype = grok_method_quals (ctype, dummy, quals);
type = TREE_TYPE (dummy);
quals = NULL_TREE;
@@ -8519,7 +9188,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
/* Check for some types that there cannot be arrays of. */
- if (TYPE_MAIN_VARIANT (type) == void_type_node)
+ if (TREE_CODE (type) == VOID_TYPE)
{
cp_error ("declaration of `%D' as array of voids", dname);
type = error_mark_node;
@@ -8574,15 +9243,21 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
the function; then build_vec_delete will need this
value. */
int yes = suspend_momentary ();
- /* might be a cast */
+ /* Might be a cast. */
if (TREE_CODE (size) == NOP_EXPR
&& TREE_TYPE (size) == TREE_TYPE (TREE_OPERAND (size, 0)))
size = TREE_OPERAND (size, 0);
- /* If this is a template parameter, it'll be constant, but
- we don't know what the value is yet. */
- if (TREE_CODE (size) == TEMPLATE_CONST_PARM)
- goto dont_grok_size;
+ /* If this involves a template parameter, it'll be
+ constant, but we don't know what the value is yet. */
+ if (processing_template_decl)
+ {
+ itype = make_node (INTEGER_TYPE);
+ TYPE_MIN_VALUE (itype) = size_zero_node;
+ TYPE_MAX_VALUE (itype) = build_min
+ (MINUS_EXPR, sizetype, size, integer_one_node);
+ goto dont_grok_size;
+ }
if (TREE_CODE (TREE_TYPE (size)) != INTEGER_TYPE
&& TREE_CODE (TREE_TYPE (size)) != ENUMERAL_TYPE)
@@ -8620,20 +9295,36 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
else
cp_pedwarn ("ANSI C++ forbids variable-size array");
}
- /* Make sure the array size remains visibly nonconstant
- even if it is (eg) a const variable with known value. */
- size_varies = 1;
}
- dont_grok_size:
- itype =
- fold (build_binary_op (MINUS_EXPR,
- convert (index_type, size),
- convert (index_type,
- integer_one_node), 1));
+ itype
+ = fold (build_binary_op (MINUS_EXPR,
+ cp_convert (index_type, size),
+ cp_convert (index_type,
+ integer_one_node), 1));
if (! TREE_CONSTANT (itype))
itype = variable_size (itype);
- itype = build_index_type (itype);
+ else if (TREE_OVERFLOW (itype))
+ {
+ error ("overflow in array dimension");
+ TREE_OVERFLOW (itype) = 0;
+ }
+
+ /* If we're a parm, we need to have a permanent type so
+ mangling checks for re-use will work right. If both the
+ element and index types are permanent, the array type
+ will be, too. */
+ if (decl_context == PARM
+ && allocation_temporary_p () && TREE_PERMANENT (type))
+ {
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ itype = build_index_type (itype);
+ pop_obstacks ();
+ }
+ else
+ itype = build_index_type (itype);
+
+ dont_grok_size:
resume_momentary (yes);
}
@@ -8693,15 +9384,23 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
if (inner_decl && TREE_CODE (inner_decl) == SCOPE_REF)
inner_decl = TREE_OPERAND (inner_decl, 1);
+ if (inner_decl && TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR)
+ inner_decl = dname;
+
/* Pick up type qualifiers which should be applied to `this'. */
quals = TREE_OPERAND (declarator, 2);
+ /* Pick up the exception specifications. */
+ raises = TREE_TYPE (declarator);
+
/* Say it's a definition only for the CALL_EXPR
closest to the identifier. */
- funcdecl_p =
- inner_decl && (TREE_CODE (inner_decl) == IDENTIFIER_NODE
- || TREE_CODE (inner_decl) == BIT_NOT_EXPR);
-
+ funcdecl_p
+ = inner_decl
+ && (TREE_CODE (inner_decl) == IDENTIFIER_NODE
+ || TREE_CODE (inner_decl) == TEMPLATE_ID_EXPR
+ || TREE_CODE (inner_decl) == BIT_NOT_EXPR);
+
if (ctype == NULL_TREE
&& decl_context == FIELD
&& funcdecl_p
@@ -8726,8 +9425,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
error ("destructor cannot be static member function");
if (quals)
{
- error ("destructors cannot be declared `const' or `volatile'");
- return void_type_node;
+ cp_error ("destructors may not be `%s'",
+ IDENTIFIER_POINTER (TREE_VALUE (quals)));
+ quals = NULL_TREE;
}
if (decl_context == FIELD)
{
@@ -8736,7 +9436,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
return void_type_node;
}
}
- else /* it's a constructor. */
+ else /* It's a constructor. */
{
if (explicitp == 1)
explicitp = 2;
@@ -8752,20 +9452,21 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
if (quals)
{
- error ("constructors cannot be declared `const' or `volatile'");
- return void_type_node;
+ cp_error ("constructors may not be `%s'",
+ IDENTIFIER_POINTER (TREE_VALUE (quals)));
+ quals = NULL_TREE;
}
{
RID_BIT_TYPE tmp_bits;
- bcopy ((void*)&specbits, (void*)&tmp_bits, sizeof(RID_BIT_TYPE));
+ bcopy ((void*)&specbits, (void*)&tmp_bits, sizeof (RID_BIT_TYPE));
RIDBIT_RESET (RID_INLINE, tmp_bits);
RIDBIT_RESET (RID_STATIC, tmp_bits);
if (RIDBIT_ANY_SET (tmp_bits))
error ("return value type specifier for constructor ignored");
}
type = build_pointer_type (ctype);
- if (decl_context == FIELD &&
- IS_SIGNATURE (current_class_type))
+ if (decl_context == FIELD
+ && IS_SIGNATURE (current_class_type))
{
error ("constructor not allowed in signature");
return void_type_node;
@@ -8801,16 +9502,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
name);
}
- /* Traditionally, declaring return type float means double. */
-
- if (flag_traditional
- && TYPE_MAIN_VARIANT (type) == float_type_node)
- {
- type = build_type_variant (double_type_node,
- TYPE_READONLY (type),
- TYPE_VOLATILE (type));
- }
-
/* Construct the function type and go to the next
inner layer of declarator. */
@@ -8821,31 +9512,39 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
arg_types = grokparms (inner_parms, funcdecl_p ? funcdef_flag : 0);
- if (declarator)
+ if (declarator && flags == DTOR_FLAG)
{
- /* Get past destructors, etc.
- We know we have one because FLAGS will be non-zero.
-
- Complain about improper parameter lists here. */
+ /* A destructor declared in the body of a class will
+ be represented as a BIT_NOT_EXPR. But, we just
+ want the underlying IDENTIFIER. */
if (TREE_CODE (declarator) == BIT_NOT_EXPR)
+ declarator = TREE_OPERAND (declarator, 0);
+
+ if (strict_prototype == 0 && arg_types == NULL_TREE)
+ arg_types = void_list_node;
+ else if (arg_types == NULL_TREE
+ || arg_types != void_list_node)
{
- declarator = TREE_OPERAND (declarator, 0);
-
- if (strict_prototype == 0 && arg_types == NULL_TREE)
- arg_types = void_list_node;
- else if (arg_types == NULL_TREE
- || arg_types != void_list_node)
- {
- error ("destructors cannot be specified with parameters");
- arg_types = void_list_node;
- }
+ cp_error ("destructors may not have parameters");
+ arg_types = void_list_node;
+ last_function_parms = NULL_TREE;
}
}
- /* ANSI seems to say that `const int foo ();'
+ /* ANSI says that `const int foo ();'
does not make the function foo const. */
- type = build_function_type (type,
- flag_traditional ? 0 : arg_types);
+ type = build_function_type (type, arg_types);
+
+ {
+ tree t;
+ for (t = arg_types; t; t = TREE_CHAIN (t))
+ if (TREE_PURPOSE (t)
+ && TREE_CODE (TREE_PURPOSE (t)) == DEFAULT_ARG)
+ {
+ add_defarg_fn (type);
+ break;
+ }
+ }
}
break;
@@ -8928,7 +9627,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
else
{
- if (TYPE_MAIN_VARIANT (type) == void_type_node)
+ if (TREE_CODE (type) == VOID_TYPE)
error ("invalid type: `void &'");
else
type = build_reference_type (type);
@@ -8990,6 +9689,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
resolve to. The code here just needs to build
up appropriate member types. */
tree sname = TREE_OPERAND (declarator, 1);
+ tree t;
+
/* Destructors can have their visibilities changed as well. */
if (TREE_CODE (sname) == BIT_NOT_EXPR)
sname = TREE_OPERAND (sname, 0);
@@ -8997,10 +9698,29 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
if (TREE_COMPLEXITY (declarator) == 0)
/* This needs to be here, in case we are called
multiple times. */ ;
+ else if (TREE_COMPLEXITY (declarator) == -1)
+ /* Namespace member. */
+ pop_decl_namespace ();
else if (friendp && (TREE_COMPLEXITY (declarator) < 2))
- /* don't fall out into global scope. Hides real bug? --eichin */ ;
+ /* Don't fall out into global scope. Hides real bug? --eichin */ ;
+ else if (! IS_AGGR_TYPE_CODE
+ (TREE_CODE (TREE_OPERAND (declarator, 0))))
+ ;
else if (TREE_COMPLEXITY (declarator) == current_class_depth)
{
+ /* Resolve any TYPENAME_TYPEs from the decl-specifier-seq
+ that refer to ctype. They couldn't be resolved earlier
+ because we hadn't pushed into the class yet.
+ Example: resolve 'B<T>::type' in
+ 'B<typename B<T>::type> B<T>::f () { }'. */
+ if (current_template_parms
+ && uses_template_parms (type)
+ && uses_template_parms (current_class_type))
+ {
+ tree args = current_template_args ();
+ type = tsubst (type, args, NULL_TREE);
+ }
+
/* This pop_nested_class corresponds to the
push_nested_class used to push into class scope for
parsing the argument list of a function decl, in
@@ -9022,6 +9742,19 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
ctype = TREE_OPERAND (declarator, 0);
+ t = ctype;
+ while (t != NULL_TREE)
+ {
+ if (CLASSTYPE_TEMPLATE_INFO (t) &&
+ !CLASSTYPE_TEMPLATE_SPECIALIZATION (t))
+ template_count += 1;
+ t = TYPE_MAIN_DECL (t);
+ if (DECL_LANG_SPECIFIC (t))
+ t = DECL_CLASS_CONTEXT (t);
+ else
+ t = NULL_TREE;
+ }
+
if (sname == NULL_TREE)
goto done_scoping;
@@ -9055,53 +9788,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
return void_type_node;
}
}
- else if (TYPE_SIZE (ctype) != NULL_TREE
- || (RIDBIT_SETP (RID_TYPEDEF, specbits)))
+ else if (RIDBIT_SETP (RID_TYPEDEF, specbits)
+ || TYPE_SIZE (complete_type (ctype)) != NULL_TREE)
{
- tree t;
- /* have to move this code elsewhere in this function.
+ /* Have to move this code elsewhere in this function.
this code is used for i.e., typedef int A::M; M *pm;
It is? How? jason 10/2/94 */
- if (explicit_int == -1 && decl_context == FIELD
- && funcdef_flag == 0)
- {
- /* The code in here should only be used to build
- stuff that will be grokked as access decls. */
- t = lookup_field (ctype, sname, 0, 0);
- if (t)
- {
- t = build_lang_field_decl (FIELD_DECL, build_nt (SCOPE_REF, ctype, t), type);
- DECL_INITIAL (t) = init;
- return t;
- }
- /* No such field, try member functions. */
- t = lookup_fnfields (TYPE_BINFO (ctype), sname, 0);
- if (t)
- {
- if (flags == DTOR_FLAG)
- t = TREE_VALUE (t);
- else if (CLASSTYPE_METHOD_VEC (ctype)
- && TREE_VALUE (t) == TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (ctype), 0))
- {
- /* Don't include destructor with constructors. */
- t = DECL_CHAIN (TREE_VALUE (t));
- if (t == NULL_TREE)
- cp_error ("`%T' does not have any constructors",
- ctype);
- t = build_tree_list (NULL_TREE, t);
- }
- t = build_lang_field_decl (FIELD_DECL, build_nt (SCOPE_REF, ctype, t), type);
- DECL_INITIAL (t) = init;
- return t;
- }
-
- cp_error
- ("field `%D' is not a member of structure `%T'",
- sname, ctype);
- }
-
if (current_class_type)
{
cp_error ("cannot declare member `%T::%s' within `%T'",
@@ -9112,14 +9806,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
else if (uses_template_parms (ctype))
{
- enum tree_code c;
if (TREE_CODE (type) == FUNCTION_TYPE)
- {
- type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
- TREE_TYPE (type),
- TYPE_ARG_TYPES (type));
- c = FUNCTION_DECL;
- }
+ type
+ = build_cplus_method_type (build_type_variant (ctype,
+ constp,
+ volatilep),
+ TREE_TYPE (type),
+ TYPE_ARG_TYPES (type));
}
else
{
@@ -9192,7 +9885,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
}
- if (RIDBIT_SETP (RID_TYPEDEF, specbits))
+ if (RIDBIT_SETP (RID_TYPEDEF, specbits) && decl_context != TYPENAME)
{
tree decl;
@@ -9200,45 +9893,61 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
in typenames, fields or parameters. */
if (constp || volatilep)
type = cp_build_type_variant (type, constp, volatilep);
+ if (current_lang_name == lang_name_java)
+ TYPE_FOR_JAVA (type) = 1;
+
+ if (decl_context == FIELD)
+ {
+ if (declarator == current_class_name)
+ cp_pedwarn ("ANSI C++ forbids nested type `%D' with same name as enclosing class",
+ declarator);
+ decl = build_lang_decl (TYPE_DECL, declarator, type);
+ if (IS_SIGNATURE (current_class_type) && opaque_typedef)
+ SIGNATURE_HAS_OPAQUE_TYPEDECLS (current_class_type) = 1;
+ }
+ else
+ {
+ /* Make sure this typedef lives as long as its type,
+ since it might be used as a template parameter. */
+ if (type != error_mark_node)
+ push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
+ decl = build_decl (TYPE_DECL, declarator, type);
+ if (type != error_mark_node)
+ pop_obstacks ();
+ }
/* If the user declares "struct {...} foo" then `foo' will have
an anonymous name. Fill that name in now. Nothing can
refer to it, so nothing needs know about the name change.
The TYPE_NAME field was filled in by build_struct_xref. */
if (type != error_mark_node
+ && !TYPE_READONLY (type) && !TYPE_VOLATILE (type)
&& TYPE_NAME (type)
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& ANON_AGGRNAME_P (TYPE_IDENTIFIER (type)))
{
- /* replace the anonymous name with the real name everywhere. */
+ /* Replace the anonymous name with the real name everywhere. */
lookup_tag_reverse (type, declarator);
- TYPE_IDENTIFIER (type) = declarator;
+ TYPE_NAME (type) = decl;
if (TYPE_LANG_SPECIFIC (type))
TYPE_WAS_ANONYMOUS (type) = 1;
- {
- tree d = TYPE_NAME (type), c = DECL_CONTEXT (d);
-
- if (!c)
- set_nested_typename (d, 0, declarator, type);
- else if (TREE_CODE (c) == FUNCTION_DECL)
- set_nested_typename (d, DECL_ASSEMBLER_NAME (c),
- declarator, type);
- else
- set_nested_typename (d, TYPE_NESTED_NAME (c), declarator, type);
+ /* XXX Temporarily set the scope.
+ When returning, start_decl expects it as NULL_TREE,
+ and will then then set it using pushdecl. */
+ my_friendly_assert (DECL_CONTEXT (decl) == NULL_TREE, 980404);
+ if (current_class_type)
+ DECL_CONTEXT (decl) = current_class_type;
+ else
+ DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
- DECL_ASSEMBLER_NAME (d) = DECL_NAME (d);
- DECL_ASSEMBLER_NAME (d)
- = get_identifier (build_overload_name (type, 1, 1));
- }
+ DECL_ASSEMBLER_NAME (decl) = DECL_NAME (decl);
+ DECL_ASSEMBLER_NAME (decl)
+ = get_identifier (build_overload_name (type, 1, 1));
+ DECL_CONTEXT (decl) = NULL_TREE;
}
-#if 0 /* not yet, should get fixed properly later */
- decl = make_type_decl (declarator, type);
-#else
- decl = build_decl (TYPE_DECL, declarator, type);
-#endif
if (TREE_CODE (type) == OFFSET_TYPE || TREE_CODE (type) == METHOD_TYPE)
{
cp_error_at ("typedef name may not be class-qualified", decl);
@@ -9266,6 +9975,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
error ("non-object member `%s' cannot be declared mutable", name);
}
+ bad_specifiers (decl, "type", virtualp, quals != NULL_TREE,
+ inlinep, friendp, raises != NULL_TREE);
+
+ if (initialized)
+ error ("typedef declaration includes an initializer");
+
return decl;
}
@@ -9289,10 +10004,12 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
/* Note that the grammar rejects storage classes
in typenames, fields or parameters. */
if (constp || volatilep)
- if (IS_SIGNATURE (type))
- error ("`const' or `volatile' specified with signature type");
- else
- type = cp_build_type_variant (type, constp, volatilep);
+ {
+ if (IS_SIGNATURE (type))
+ error ("`const' or `volatile' specified with signature type");
+ else
+ type = cp_build_type_variant (type, constp, volatilep);
+ }
/* Special case: "friend class foo" looks like a TYPENAME context. */
if (friendp)
@@ -9322,11 +10039,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
else if (quals)
{
-#if 0 /* not yet, should get fixed properly later */
- tree dummy = make_type_decl (declarator, type);
-#else
tree dummy = build_decl (TYPE_DECL, declarator, type);
-#endif
if (ctype == NULL_TREE)
{
my_friendly_assert (TREE_CODE (type) == METHOD_TYPE, 159);
@@ -9352,19 +10065,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
We don't complain about parms either, but that is because
a better error message can be made later. */
- if (TYPE_MAIN_VARIANT (type) == void_type_node && decl_context != PARM)
+ if (TREE_CODE (type) == VOID_TYPE && decl_context != PARM)
{
if (! declarator)
error ("unnamed variable or field declared void");
else if (TREE_CODE (declarator) == IDENTIFIER_NODE)
{
if (IDENTIFIER_OPNAME_P (declarator))
-#if 0 /* How could this happen? */
- error ("operator `%s' declared void",
- operator_name_string (declarator));
-#else
my_friendly_abort (356);
-#endif
else
error ("variable or field `%s' declared void", name);
}
@@ -9390,7 +10098,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
if (TREE_CODE (type) == ARRAY_TYPE)
{
- /* Transfer const-ness of array into that of type pointed to. */
+ /* Transfer const-ness of array into that of type pointed to. */
type = build_pointer_type
(cp_build_type_variant (TREE_TYPE (type), constp, volatilep));
volatilep = constp = 0;
@@ -9399,13 +10107,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
type = build_pointer_type (type);
else if (TREE_CODE (type) == OFFSET_TYPE)
type = build_pointer_type (type);
- else if (type == void_type_node && declarator)
+ else if (TREE_CODE (type) == VOID_TYPE && declarator)
{
error ("declaration of `%s' as void", name);
return NULL_TREE;
}
- decl = build_decl (PARM_DECL, declarator, type);
+ decl = build_decl (PARM_DECL, declarator, complete_type (type));
bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE,
inlinep, friendp, raises != NULL_TREE);
@@ -9438,6 +10146,16 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
else if (TREE_CODE (type) == FUNCTION_TYPE)
{
int publicp = 0;
+ tree function_context;
+
+ /* We catch the others as conflicts with the builtin
+ typedefs. */
+ if (friendp && declarator == ridpointers[(int) RID_SIGNED])
+ {
+ cp_error ("function `%D' cannot be declared friend",
+ declarator);
+ friendp = 0;
+ }
if (friendp == 0)
{
@@ -9478,15 +10196,24 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
/* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */
- publicp = (! friendp
- || RIDBIT_SETP (RID_EXTERN, specbits)
- || ! (funcdef_flag < 0 || inlinep));
- decl = grokfndecl (ctype, type, declarator,
+ function_context = (ctype != NULL_TREE) ?
+ hack_decl_function_context (TYPE_MAIN_DECL (ctype)) : NULL_TREE;
+ publicp = (! friendp || ! staticp)
+ && function_context == NULL_TREE;
+ decl = grokfndecl (ctype, type,
+ TREE_CODE (declarator) != TEMPLATE_ID_EXPR
+ ? declarator : dname,
+ declarator,
virtualp, flags, quals, raises, attrlist,
- friendp ? -1 : 0, publicp, inlinep);
+ friendp ? -1 : 0, friendp, publicp, inlinep,
+ funcdef_flag, template_count, in_namespace);
if (decl == NULL_TREE)
return NULL_TREE;
+#if 0
+ /* This clobbers the attrs stored in `decl' from `attrlist'. */
+ /* The decl and setting of decl_machine_attr is also turned off. */
decl = build_decl_attribute_variant (decl, decl_machine_attr);
+#endif
if (explicitp == 2)
DECL_NONCONVERTING_P (decl) = 1;
@@ -9497,13 +10224,15 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
members of other classes. */
/* All method decls are public, so tell grokfndecl to set
TREE_PUBLIC, also. */
- decl = grokfndecl (ctype, type, declarator,
+ decl = grokfndecl (ctype, type, declarator, declarator,
virtualp, flags, quals, raises, attrlist,
- friendp ? -1 : 0, 1, 0);
+ friendp ? -1 : 0, friendp, 1, 0, funcdef_flag,
+ template_count, in_namespace);
if (decl == NULL_TREE)
return NULL_TREE;
}
- else if (TYPE_SIZE (type) == NULL_TREE && !staticp
+ else if (!staticp && ! processing_template_decl
+ && TYPE_SIZE (complete_type (type)) == NULL_TREE
&& (TREE_CODE (type) != ARRAY_TYPE || initialized == 0))
{
if (declarator)
@@ -9515,7 +10244,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
instantiation made the field's type be incomplete. */
if (current_class_type
&& TYPE_NAME (current_class_type)
- && IDENTIFIER_TEMPLATE (DECL_NAME (TYPE_NAME (current_class_type)))
+ && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (current_class_type))
&& declspecs && TREE_VALUE (declspecs)
&& TREE_TYPE (TREE_VALUE (declspecs)) == type)
cp_error (" in instantiation of template `%T'",
@@ -9545,7 +10274,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
tree t = NULL_TREE;
if (decl && DECL_NAME (decl))
t = do_friend (ctype, declarator, decl,
- last_function_parms, flags, quals);
+ last_function_parms, flags, quals,
+ funcdef_flag);
if (t && funcdef_flag)
return t;
@@ -9559,6 +10289,27 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
{
if (initialized)
{
+ if (!staticp)
+ {
+ /* An attempt is being made to initialize a non-static
+ member. But, from [class.mem]:
+
+ 4 A member-declarator can contain a
+ constant-initializer only if it declares a static
+ member (_class.static_) of integral or enumeration
+ type, see _class.static.data_.
+
+ This used to be relatively common practice, but
+ the rest of the compiler does not correctly
+ handle the initialization unless the member is
+ static so we make it static below. */
+ cp_pedwarn ("ANSI C++ forbids initialization of %s `%D'",
+ constp ? "const member" : "member",
+ declarator);
+ cp_pedwarn ("making `%D' static", declarator);
+ staticp = 1;
+ }
+
/* Motion 10 at San Diego: If a static const integral data
member is initialized with an integral constant
expression, the initializer may appear either in the
@@ -9566,34 +10317,22 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
but not both. If it appears in the class, the member is
a member constant. The file-scope definition is always
required. */
- if (staticp)
- {
- if (pedantic)
- {
- if (! constp)
- cp_pedwarn ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
- declarator);
-
- else if (! INTEGRAL_TYPE_P (type))
- cp_pedwarn ("ANSI C++ forbids member constant `%D' of non-integral type `%T'", declarator, type);
- }
- }
-
- /* Note that initialization of const members is prohibited
- by the draft ANSI standard, though it appears to be in
- common practice. 12.6.2: The argument list is used to
- initialize the named nonstatic member.... This (or an
- initializer list) is the only way to initialize
- nonstatic const and reference members. */
- else if (pedantic || ! constp)
- cp_pedwarn ("ANSI C++ forbids initialization of %s `%D'",
- constp ? "const member" : "member", declarator);
+ if (! constp)
+ /* According to Mike Stump, we generate bad code for
+ this case, so we might as well always make it an
+ error. */
+ cp_error ("ANSI C++ forbids in-class initialization of non-const static member `%D'",
+ declarator);
+
+ if (pedantic && ! INTEGRAL_TYPE_P (type)
+ && !uses_template_parms (type))
+ cp_pedwarn ("ANSI C++ forbids initialization of member constant `%D' of non-integral type `%T'", declarator, type);
}
- if (staticp || (constp && initialized))
+ if (staticp)
{
/* ANSI C++ Apr '95 wp 9.2 */
- if (staticp && declarator == current_class_name)
+ if (declarator == current_class_name)
cp_pedwarn ("ANSI C++ forbids static member `%D' with same name as enclosing class",
declarator);
@@ -9604,7 +10343,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
decl = build_lang_field_decl (VAR_DECL, declarator, type);
TREE_STATIC (decl) = 1;
/* In class context, 'static' means public access. */
- TREE_PUBLIC (decl) = DECL_EXTERNAL (decl) = !!staticp;
+ TREE_PUBLIC (decl) = DECL_EXTERNAL (decl) = 1;
}
else
{
@@ -9622,12 +10361,17 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
else if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
{
- tree original_name = declarator;
+ tree original_name;
int publicp = 0;
if (! declarator)
return NULL_TREE;
+ if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
+ original_name = dname;
+ else
+ original_name = declarator;
+
if (RIDBIT_SETP (RID_AUTO, specbits))
error ("storage class `auto' invalid for function `%s'", name);
else if (RIDBIT_SETP (RID_REGISTER, specbits))
@@ -9637,7 +10381,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
Storage classes other than `extern' are not allowed
and `extern' makes no difference. */
if (! toplevel_bindings_p ()
- && ! processing_template_decl
&& (RIDBIT_SETP (RID_STATIC, specbits)
|| RIDBIT_SETP (RID_INLINE, specbits))
&& pedantic)
@@ -9657,36 +10400,44 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
if (current_lang_name == lang_name_cplusplus
- && ! (IDENTIFIER_LENGTH (original_name) == 4
- && IDENTIFIER_POINTER (original_name)[0] == 'm'
- && strcmp (IDENTIFIER_POINTER (original_name), "main") == 0)
+ && ! processing_template_decl
+ && ! MAIN_NAME_P (original_name)
&& ! (IDENTIFIER_LENGTH (original_name) > 10
&& IDENTIFIER_POINTER (original_name)[0] == '_'
&& IDENTIFIER_POINTER (original_name)[1] == '_'
&& strncmp (IDENTIFIER_POINTER (original_name)+2, "builtin_", 8) == 0))
/* Plain overloading: will not be grok'd by grokclassfn. */
- declarator = build_decl_overload (dname, TYPE_ARG_TYPES (type), 0);
+ if (name_mangling_version < 1
+ || TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
+ declarator = build_decl_overload (dname, TYPE_ARG_TYPES (type), 0);
}
else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2)
type = build_cplus_method_type (build_type_variant (ctype, constp, volatilep),
TREE_TYPE (type), TYPE_ARG_TYPES (type));
- /* Record presence of `static'. In C++, `inline' implies `static'. */
+ /* Record presence of `static'. */
publicp = (ctype != NULL_TREE
|| RIDBIT_SETP (RID_EXTERN, specbits)
- || (!RIDBIT_SETP (RID_STATIC, specbits)
- && !RIDBIT_SETP (RID_INLINE, specbits)));
+ || !RIDBIT_SETP (RID_STATIC, specbits));
- decl = grokfndecl (ctype, type, original_name,
+ decl = grokfndecl (ctype, type, original_name, declarator,
virtualp, flags, quals, raises, attrlist,
- processing_template_decl ? 0 : friendp ? 2 : 1,
- publicp, inlinep);
+ 1, friendp,
+ publicp, inlinep, funcdef_flag,
+ template_count, in_namespace);
if (decl == NULL_TREE)
return NULL_TREE;
- if (ctype == NULL_TREE && DECL_LANGUAGE (decl) != lang_c)
- DECL_ASSEMBLER_NAME (decl) = current_namespace_id (declarator);
+ /* Among other times, could occur from check_explicit_specialization
+ returning an error_mark_node. */
+ if (decl == error_mark_node)
+ return error_mark_node;
+ if (ctype == NULL_TREE && DECL_LANGUAGE (decl) != lang_c
+ && (! DECL_USE_TEMPLATE (decl) ||
+ name_mangling_version < 1))
+ DECL_ASSEMBLER_NAME (decl) = declarator;
+
if (staticp == 1)
{
int illegal_static = 0;
@@ -9730,7 +10481,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
if (TREE_CODE (type) == ARRAY_TYPE)
{
- /* Transfer const-ness of array into that of type pointed to. */
+ /* Transfer const-ness of array into that of type
+ pointed to. */
type = build_pointer_type
(cp_build_type_variant (TREE_TYPE (type), constp, volatilep));
volatilep = constp = 0;
@@ -9742,7 +10494,8 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
}
/* An uninitialized decl with `extern' is a reference. */
- decl = grokvardecl (type, declarator, specbits, initialized, constp);
+ decl = grokvardecl (type, declarator, &specbits,
+ initialized, constp, in_namespace);
bad_specifiers (decl, "variable", virtualp, quals != NULL_TREE,
inlinep, friendp, raises != NULL_TREE);
@@ -9804,6 +10557,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, raises, attrli
An empty exprlist is a parmlist. An exprlist which
contains only identifiers at the global level
is a parmlist. Otherwise, it is an exprlist. */
+
int
parmlist_is_exprlist (exprs)
tree exprs;
@@ -9830,14 +10584,18 @@ parmlist_is_exprlist (exprs)
be complete.
C++: also subroutine of `start_function'. */
+
static void
require_complete_types_for_parms (parms)
tree parms;
{
+ if (processing_template_decl)
+ return;
+
while (parms)
{
tree type = TREE_TYPE (parms);
- if (TYPE_SIZE (type) == NULL_TREE)
+ if (TYPE_SIZE (complete_type (type)) == NULL_TREE)
{
if (DECL_NAME (parms))
error ("parameter `%s' has incomplete type",
@@ -9928,14 +10686,14 @@ grokparms (first_parm, funcdef_flag)
}
else if (first_parm != NULL_TREE
&& TREE_CODE (TREE_VALUE (first_parm)) != TREE_LIST
- && TREE_VALUE (first_parm) != void_type_node)
+ && TREE_CODE (TREE_VALUE (first_parm)) != VOID_TYPE)
my_friendly_abort (145);
else
{
/* Types were specified. This is a list of declarators
each represented as a TREE_LIST node. */
register tree parm, chain;
- int any_init = 0, any_error = 0, saw_void = 0;
+ int any_init = 0, any_error = 0;
if (first_parm != NULL_TREE)
{
@@ -9944,42 +10702,41 @@ grokparms (first_parm, funcdef_flag)
for (parm = first_parm; parm != NULL_TREE; parm = chain)
{
- tree type, list_node = parm;
+ tree type = NULL_TREE, list_node = parm;
register tree decl = TREE_VALUE (parm);
tree init = TREE_PURPOSE (parm);
chain = TREE_CHAIN (parm);
/* @@ weak defense against parse errors. */
- if (decl != void_type_node && TREE_CODE (decl) != TREE_LIST)
+ if (TREE_CODE (decl) != VOID_TYPE
+ && TREE_CODE (decl) != TREE_LIST)
{
/* Give various messages as the need arises. */
if (TREE_CODE (decl) == STRING_CST)
- error ("invalid string constant `%s'",
- TREE_STRING_POINTER (decl));
+ cp_error ("invalid string constant `%E'", decl);
else if (TREE_CODE (decl) == INTEGER_CST)
error ("invalid integer constant in parameter list, did you forget to give parameter name?");
continue;
}
- if (decl != void_type_node)
+ if (TREE_CODE (decl) != VOID_TYPE)
{
- /* @@ May need to fetch out a `raises' here. */
decl = grokdeclarator (TREE_VALUE (decl),
TREE_PURPOSE (decl),
PARM, init != NULL_TREE,
- NULL_TREE, NULL_TREE);
+ NULL_TREE);
if (! decl)
continue;
type = TREE_TYPE (decl);
- if (TYPE_MAIN_VARIANT (type) == void_type_node)
+ if (TREE_CODE (type) == VOID_TYPE)
decl = void_type_node;
else if (TREE_CODE (type) == METHOD_TYPE)
{
if (DECL_NAME (decl))
- /* Cannot use `error_with_decl' here because
+ /* Cannot use the decl here because
we don't have DECL_CONTEXT set up yet. */
- error ("parameter `%s' invalidly declared method type",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ cp_error ("parameter `%D' invalidly declared method type",
+ DECL_NAME (decl));
else
error ("parameter invalidly declared method type");
type = build_pointer_type (type);
@@ -9988,8 +10745,8 @@ grokparms (first_parm, funcdef_flag)
else if (TREE_CODE (type) == OFFSET_TYPE)
{
if (DECL_NAME (decl))
- error ("parameter `%s' invalidly declared offset type",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ cp_error ("parameter `%D' invalidly declared offset type",
+ DECL_NAME (decl));
else
error ("parameter invalidly declared offset type");
type = build_pointer_type (type);
@@ -10000,18 +10757,18 @@ grokparms (first_parm, funcdef_flag)
&& CLASSTYPE_ABSTRACT_VIRTUALS (type))
{
abstract_virtuals_error (decl, type);
- any_error = 1; /* seems like a good idea */
+ any_error = 1; /* Seems like a good idea. */
}
else if (TREE_CODE (type) == RECORD_TYPE
&& TYPE_LANG_SPECIFIC (type)
&& IS_SIGNATURE (type))
{
signature_error (decl, type);
- any_error = 1; /* seems like a good idea */
+ any_error = 1; /* Seems like a good idea. */
}
}
- if (decl == void_type_node)
+ if (TREE_CODE (decl) == VOID_TYPE)
{
if (result == NULL_TREE)
{
@@ -10023,7 +10780,6 @@ grokparms (first_parm, funcdef_flag)
TREE_CHAIN (last_result) = void_list_node;
last_result = void_list_node;
}
- saw_void = 1;
if (chain
&& (chain != void_list_node || TREE_CHAIN (chain)))
error ("`void' in parameter list must be entire list");
@@ -10045,6 +10801,11 @@ grokparms (first_parm, funcdef_flag)
any_init++;
if (TREE_CODE (init) == SAVE_EXPR)
PARM_DECL_EXPR (init) = 1;
+ else if (processing_template_decl)
+ ;
+ /* Unparsed default arg from in-class decl. */
+ else if (TREE_CODE (init) == DEFAULT_ARG)
+ ;
else if (TREE_CODE (init) == VAR_DECL
|| TREE_CODE (init) == PARM_DECL)
{
@@ -10054,7 +10815,7 @@ grokparms (first_parm, funcdef_flag)
argument expressions.'' dpANSI C++ 8.2.6 */
/* If extern int i; within a function is not
considered a local variable, then this code is
- wrong. */
+ wrong. */
cp_error ("local variable `%D' may not be used as a default argument", init);
any_error = 1;
}
@@ -10063,15 +10824,13 @@ grokparms (first_parm, funcdef_flag)
}
else
init = require_instantiated_type (type, init, integer_zero_node);
- }
-#if 0 /* This is too early to check; trailing parms might be merged in by
- duplicate_decls. */
- else if (any_init)
- {
- error ("all trailing parameters must have default arguments");
- any_error = 1;
+ if (! processing_template_decl
+ && init != error_mark_node
+ && TREE_CODE (init) != DEFAULT_ARG
+ && ! can_convert_arg (type, TREE_TYPE (init), init))
+ cp_pedwarn ("invalid type `%T' for default argument to `%#D'",
+ TREE_TYPE (init), decl);
}
-#endif
}
else
init = NULL_TREE;
@@ -10086,7 +10845,7 @@ grokparms (first_parm, funcdef_flag)
TREE_CHAIN (last_decl) = decl;
last_decl = decl;
}
- if (TREE_PERMANENT (list_node))
+ if (! current_function_decl && TREE_PERMANENT (list_node))
{
TREE_PURPOSE (list_node) = init;
TREE_VALUE (list_node) = type;
@@ -10122,7 +10881,40 @@ grokparms (first_parm, funcdef_flag)
return result;
}
+
+/* Called from the parser to update an element of TYPE_ARG_TYPES for some
+ FUNCTION_TYPE with the newly parsed version of its default argument, which
+ was previously digested as text. See snarf_defarg et al in lex.c. */
+
+void
+replace_defarg (arg, init)
+ tree arg, init;
+{
+ if (! processing_template_decl
+ && ! can_convert_arg (TREE_VALUE (arg), TREE_TYPE (init), init))
+ cp_pedwarn ("invalid type `%T' for default argument to `%T'",
+ TREE_TYPE (init), TREE_VALUE (arg));
+ TREE_PURPOSE (arg) = init;
+}
+int
+copy_args_p (d)
+ tree d;
+{
+ tree t = FUNCTION_ARG_CHAIN (d);
+ if (DECL_CONSTRUCTOR_P (d)
+ && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (d)))
+ t = TREE_CHAIN (t);
+ if (t && TREE_CODE (TREE_VALUE (t)) == REFERENCE_TYPE
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (t)))
+ == DECL_CLASS_CONTEXT (d))
+ && (TREE_CHAIN (t) == NULL_TREE
+ || TREE_CHAIN (t) == void_list_node
+ || TREE_PURPOSE (TREE_CHAIN (t))))
+ return 1;
+ return 0;
+}
+
/* These memoizing functions keep track of special properties which
a class may have. `grok_ctor_properties' notices whether a class
has a constructor of the form X(X&), and also complains
@@ -10130,6 +10922,7 @@ grokparms (first_parm, funcdef_flag)
`grok_op_properties' takes notice of the various forms of
operator= which are defined, as well as what sorts of type conversion
may apply. Both functions take a FUNCTION_DECL as an argument. */
+
int
grok_ctor_properties (ctype, decl)
tree ctype, decl;
@@ -10141,41 +10934,33 @@ grok_ctor_properties (ctype, decl)
added to any ctor so we can tell if the class has been initialized
yet. This could screw things up in this function, so we deliberately
ignore the leading int if we're in that situation. */
- if (parmtypes
- && TREE_VALUE (parmtypes) == integer_type_node
- && TYPE_USES_VIRTUAL_BASECLASSES (ctype))
+ if (TYPE_USES_VIRTUAL_BASECLASSES (ctype))
{
+ my_friendly_assert (parmtypes
+ && TREE_VALUE (parmtypes) == integer_type_node,
+ 980529);
parmtypes = TREE_CHAIN (parmtypes);
parmtype = TREE_VALUE (parmtypes);
}
if (TREE_CODE (parmtype) == REFERENCE_TYPE
- && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype)
- {
- if (TREE_CHAIN (parmtypes) == NULL_TREE
+ && TYPE_MAIN_VARIANT (TREE_TYPE (parmtype)) == ctype
+ && (TREE_CHAIN (parmtypes) == NULL_TREE
|| TREE_CHAIN (parmtypes) == void_list_node
- || TREE_PURPOSE (TREE_CHAIN (parmtypes)))
- {
- TYPE_HAS_INIT_REF (ctype) = 1;
- if (TYPE_READONLY (TREE_TYPE (parmtype)))
- TYPE_HAS_CONST_INIT_REF (ctype) = 1;
- }
- else
- TYPE_GETS_INIT_AGGR (ctype) = 1;
+ || TREE_PURPOSE (TREE_CHAIN (parmtypes))))
+ {
+ TYPE_HAS_INIT_REF (ctype) = 1;
+ if (TYPE_READONLY (TREE_TYPE (parmtype)))
+ TYPE_HAS_CONST_INIT_REF (ctype) = 1;
}
- else if (TYPE_MAIN_VARIANT (parmtype) == ctype)
+ else if (TYPE_MAIN_VARIANT (parmtype) == ctype
+ && TREE_CHAIN (parmtypes) != NULL_TREE
+ && TREE_CHAIN (parmtypes) == void_list_node)
{
- if (TREE_CHAIN (parmtypes) != NULL_TREE
- && TREE_CHAIN (parmtypes) == void_list_node)
- {
- cp_error ("invalid constructor; you probably meant `%T (%T&)'",
- ctype, ctype);
- SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype);
-
- return 0;
- }
- else
- TYPE_GETS_INIT_AGGR (ctype) = 1;
+ cp_error ("invalid constructor; you probably meant `%T (const %T&)'",
+ ctype, ctype);
+ SET_IDENTIFIER_ERROR_LOCUS (DECL_NAME (decl), ctype);
+ return 0;
}
else if (TREE_CODE (parmtype) == VOID_TYPE
|| TREE_PURPOSE (parmtypes) != NULL_TREE)
@@ -10185,6 +10970,7 @@ grok_ctor_properties (ctype, decl)
}
/* An operator with this name can be either unary or binary. */
+
static int
ambi_op_p (name)
tree name;
@@ -10198,6 +10984,7 @@ ambi_op_p (name)
}
/* An operator with this name can only be unary. */
+
static int
unary_op_p (name)
tree name;
@@ -10209,7 +10996,8 @@ unary_op_p (name)
}
/* Do a little sanity-checking on how they declared their operator. */
-static void
+
+void
grok_op_properties (decl, virtualp, friendp)
tree decl;
int virtualp, friendp;
@@ -10252,10 +11040,10 @@ grok_op_properties (decl, virtualp, friendp)
/* Take care of function decl if we had syntax errors. */
if (argtypes == NULL_TREE)
- TREE_TYPE (decl) =
- build_function_type (ptr_type_node,
- hash_tree_chain (integer_type_node,
- void_list_node));
+ TREE_TYPE (decl)
+ = build_function_type (ptr_type_node,
+ hash_tree_chain (integer_type_node,
+ void_list_node));
else
TREE_TYPE (decl) = coerce_new_type (TREE_TYPE (decl));
}
@@ -10266,10 +11054,10 @@ grok_op_properties (decl, virtualp, friendp)
revert_static_member_fn (&decl, NULL, NULL);
if (argtypes == NULL_TREE)
- TREE_TYPE (decl) =
- build_function_type (void_type_node,
- hash_tree_chain (ptr_type_node,
- void_list_node));
+ TREE_TYPE (decl)
+ = build_function_type (void_type_node,
+ hash_tree_chain (ptr_type_node,
+ void_list_node));
else
{
TREE_TYPE (decl) = coerce_delete_type (TREE_TYPE (decl));
@@ -10301,7 +11089,7 @@ grok_op_properties (decl, virtualp, friendp)
cp_error ("`%D' must be either a non-static member function or a non-member function", decl);
if (p)
- for (; TREE_VALUE (p) != void_type_node ; p = TREE_CHAIN (p))
+ for (; TREE_CODE (TREE_VALUE (p)) != VOID_TYPE ; p = TREE_CHAIN (p))
{
tree arg = TREE_VALUE (p);
if (TREE_CODE (arg) == REFERENCE_TYPE)
@@ -10310,7 +11098,8 @@ grok_op_properties (decl, virtualp, friendp)
/* This lets bad template code slip through. */
if (IS_AGGR_TYPE (arg)
|| TREE_CODE (arg) == ENUMERAL_TYPE
- || TREE_CODE (arg) == TEMPLATE_TYPE_PARM)
+ || TREE_CODE (arg) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
goto foundaggr;
}
cp_error
@@ -10321,11 +11110,10 @@ grok_op_properties (decl, virtualp, friendp)
}
}
- if (name == ansi_opname[(int) CALL_EXPR]
- || name == ansi_opname[(int) METHOD_CALL_EXPR])
- return; /* no restrictions on args */
+ if (name == ansi_opname[(int) CALL_EXPR])
+ return; /* No restrictions on args. */
- if (IDENTIFIER_TYPENAME_P (name))
+ if (IDENTIFIER_TYPENAME_P (name) && ! DECL_TEMPLATE_INFO (decl))
{
tree t = TREE_TYPE (name);
if (TREE_CODE (t) == VOID_TYPE)
@@ -10339,7 +11127,9 @@ grok_op_properties (decl, virtualp, friendp)
if (t == current_class_type)
what = "the same type";
+ /* Don't force t to be complete here. */
else if (IS_AGGR_TYPE (t)
+ && TYPE_SIZE (t)
&& DERIVED_FROM_P (t, current_class_type))
what = "a base class";
@@ -10367,10 +11157,6 @@ grok_op_properties (decl, virtualp, friendp)
if (TREE_CODE (parmtype) != REFERENCE_TYPE
|| TYPE_READONLY (TREE_TYPE (parmtype)))
TYPE_HAS_CONST_ASSIGN_REF (current_class_type) = 1;
-#if 0 /* Too soon; done in grok_function_init */
- if (DECL_ABSTRACT_VIRTUAL_P (decl))
- TYPE_HAS_ABSTRACT_ASSIGN_REF (current_class_type) = 1;
-#endif
}
}
else if (name == ansi_opname[(int) COND_EXPR])
@@ -10388,6 +11174,7 @@ grok_op_properties (decl, virtualp, friendp)
{
if ((name == ansi_opname[(int) POSTINCREMENT_EXPR]
|| name == ansi_opname[(int) POSTDECREMENT_EXPR])
+ && ! processing_template_decl
&& TREE_VALUE (TREE_CHAIN (argtypes)) != integer_type_node)
{
if (methodp)
@@ -10406,6 +11193,31 @@ grok_op_properties (decl, virtualp, friendp)
else
cp_error ("`%D' must take either one or two arguments", decl);
}
+
+ /* More Effective C++ rule 6. */
+ if (warn_ecpp
+ && (name == ansi_opname[(int) POSTINCREMENT_EXPR]
+ || name == ansi_opname[(int) POSTDECREMENT_EXPR]))
+ {
+ tree arg = TREE_VALUE (argtypes);
+ tree ret = TREE_TYPE (TREE_TYPE (decl));
+ if (methodp || TREE_CODE (arg) == REFERENCE_TYPE)
+ arg = TREE_TYPE (arg);
+ arg = TYPE_MAIN_VARIANT (arg);
+ if (list_length (argtypes) == 2)
+ {
+ if (TREE_CODE (ret) != REFERENCE_TYPE
+ || !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ret)),
+ arg, 1))
+ cp_warning ("prefix `%D' should return `%T'", decl,
+ build_reference_type (arg));
+ }
+ else
+ {
+ if (!comptypes (TYPE_MAIN_VARIANT (ret), arg, 1))
+ cp_warning ("postfix `%D' should return `%T'", decl, arg);
+ }
+ }
}
else if (unary_op_p (name))
{
@@ -10426,7 +11238,25 @@ grok_op_properties (decl, virtualp, friendp)
else
cp_error ("`%D' must take exactly two arguments", decl);
}
- }
+
+ /* More Effective C++ rule 7. */
+ if (warn_ecpp
+ && (name == ansi_opname [TRUTH_ANDIF_EXPR]
+ || name == ansi_opname [TRUTH_ORIF_EXPR]
+ || name == ansi_opname [COMPOUND_EXPR]))
+ cp_warning ("user-defined `%D' always evaluates both arguments",
+ decl);
+ }
+
+ /* Effective C++ rule 23. */
+ if (warn_ecpp
+ && list_length (argtypes) == 3
+ && (name == ansi_opname [PLUS_EXPR]
+ || name == ansi_opname [MINUS_EXPR]
+ || name == ansi_opname [TRUNC_DIV_EXPR]
+ || name == ansi_opname [MULT_EXPR])
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) == REFERENCE_TYPE)
+ cp_warning ("`%D' should return by value", decl);
/* 13.4.0.8 */
if (argtypes)
@@ -10465,9 +11295,20 @@ xref_tag (code_type_node, name, binfo, globalize)
enum tag_types tag_code;
enum tree_code code;
int temp = 0;
- int i;
register tree ref, t;
struct binding_level *b = inner_binding_level;
+ int got_type = 0;
+ tree attributes = NULL_TREE;
+
+ /* If we are called from the parser, code_type_node will sometimes be a
+ TREE_LIST. This indicates that the user wrote
+ "class __attribute__ ((foo)) bar". Extract the attributes so we can
+ use them later. */
+ if (TREE_CODE (code_type_node) == TREE_LIST)
+ {
+ attributes = TREE_PURPOSE (code_type_node);
+ code_type_node = TREE_VALUE (code_type_node);
+ }
tag_code = (enum tag_types) TREE_INT_CST_LOW (code_type_node);
switch (tag_code)
@@ -10489,18 +11330,34 @@ xref_tag (code_type_node, name, binfo, globalize)
/* If a cross reference is requested, look up the type
already defined for this tag and return it. */
- t = IDENTIFIER_TYPE_VALUE (name);
- if (t && TREE_CODE (t) != code)
+ if (TREE_CODE_CLASS (TREE_CODE (name)) == 't')
+ {
+ t = name;
+ name = TYPE_IDENTIFIER (t);
+ got_type = 1;
+ }
+ else
+ t = IDENTIFIER_TYPE_VALUE (name);
+ if (t && TREE_CODE (t) != code && TREE_CODE (t) != TEMPLATE_TYPE_PARM
+ && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM)
t = NULL_TREE;
if (! globalize)
{
- /* If we know we are defining this tag, only look it up in this scope
- * and don't try to find it as a type. */
- if (t && TYPE_CONTEXT(t) && TREE_MANGLED (name))
+ if (pedantic && t && (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM))
+ {
+ cp_pedwarn ("redeclaration of template type-parameter `%T'", name);
+ cp_pedwarn_at (" previously declared here", t);
+ }
+ if (t && TYPE_CONTEXT (t) && got_type)
ref = t;
else
- ref = lookup_tag (code, name, b, 1);
+ {
+ /* If we know we are defining this tag, only look it up in
+ this scope and don't try to find it as a type. */
+ ref = lookup_tag (code, name, b, 1);
+ }
}
else
{
@@ -10513,6 +11370,15 @@ xref_tag (code_type_node, name, binfo, globalize)
{
/* Try finding it as a type declaration. If that wins, use it. */
ref = lookup_name (name, 1);
+
+ if (ref != NULL_TREE
+ && processing_template_decl
+ && DECL_CLASS_TEMPLATE_P (ref)
+ && template_class_depth (current_class_type) == 0)
+ /* Since GLOBALIZE is true, we're declaring a global
+ template, so we want this type. */
+ ref = DECL_RESULT (ref);
+
if (ref && TREE_CODE (ref) == TYPE_DECL
&& TREE_CODE (TREE_TYPE (ref)) == code)
ref = TREE_TYPE (ref);
@@ -10539,6 +11405,8 @@ xref_tag (code_type_node, name, binfo, globalize)
if (code == ENUMERAL_TYPE)
{
+ cp_error ("use of enum `%#D' without previous declaration", name);
+
ref = make_node (ENUMERAL_TYPE);
/* Give the type a default layout like unsigned int
@@ -10556,8 +11424,6 @@ xref_tag (code_type_node, name, binfo, globalize)
done in `start_enum'. */
pushtag (name, ref, globalize);
- if (flag_cadillac)
- cadillac_start_enum (ref);
}
else
{
@@ -10582,50 +11448,27 @@ xref_tag (code_type_node, name, binfo, globalize)
#endif
pushtag (name, ref, globalize);
class_binding_level = old_b;
-
- if (flag_cadillac)
- cadillac_start_struct (ref);
}
}
else
{
/* If it no longer looks like a nested type, make sure it's
- in global scope. */
- if (b == global_binding_level && !class_binding_level
- && IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE)
- IDENTIFIER_GLOBAL_VALUE (name) = TYPE_NAME (ref);
-
-#if 0
- if (binfo)
+ in global scope.
+ If it is not an IDENTIFIER, this is not a declaration */
+ if (b->namespace_p && !class_binding_level
+ && TREE_CODE (name) == IDENTIFIER_NODE)
{
- tree tt1 = binfo;
- tree tt2 = TYPE_BINFO_BASETYPES (ref);
-
- if (TYPE_BINFO_BASETYPES (ref))
- for (i = 0; tt1; i++, tt1 = TREE_CHAIN (tt1))
- if (TREE_VALUE (tt1) != TYPE_IDENTIFIER (BINFO_TYPE (TREE_VEC_ELT (tt2, i))))
- {
- cp_error ("redeclaration of derivation chain of type `%#T'",
- ref);
- break;
- }
-
- if (tt1 == NULL_TREE)
- /* The user told us something we already knew. */
- goto just_return;
-
- /* In C++, since these migrate into the global scope, we must
- build them on the permanent obstack. */
- end_temporary_allocation ();
+ if (IDENTIFIER_NAMESPACE_VALUE (name) == NULL_TREE)
+ SET_IDENTIFIER_NAMESPACE_VALUE (name, TYPE_NAME (ref));
}
-#endif
+
+ if (!globalize && processing_template_decl && IS_AGGR_TYPE (ref))
+ redeclare_class_template (ref, current_template_parms);
}
if (binfo)
xref_basetypes (code_type_node, name, ref, binfo);
- just_return:
-
/* Until the type is defined, tentatively accept whatever
structure tag the user hands us. */
if (TYPE_SIZE (ref) == NULL_TREE
@@ -10641,9 +11484,30 @@ xref_tag (code_type_node, name, binfo, globalize)
pop_obstacks ();
+ TREE_TYPE (ref) = attributes;
+
return ref;
}
+tree
+xref_tag_from_type (old, id, globalize)
+ tree old, id;
+ int globalize;
+{
+ tree code_type_node;
+
+ if (TREE_CODE (old) == RECORD_TYPE)
+ code_type_node = (CLASSTYPE_DECLARED_CLASS (old)
+ ? class_type_node : record_type_node);
+ else
+ code_type_node = union_type_node;
+
+ if (id == NULL_TREE)
+ id = TYPE_IDENTIFIER (old);
+
+ return xref_tag (code_type_node, id, NULL_TREE, globalize);
+}
+
void
xref_basetypes (code_type_node, name, ref, binfo)
tree code_type_node;
@@ -10672,34 +11536,42 @@ xref_basetypes (code_type_node, name, ref, binfo)
{
/* The base of a derived struct is public by default. */
int via_public
- = (TREE_PURPOSE (binfo) == (tree)access_public
- || TREE_PURPOSE (binfo) == (tree)access_public_virtual
+ = (TREE_PURPOSE (binfo) == access_public_node
+ || TREE_PURPOSE (binfo) == access_public_virtual_node
|| (tag_code != class_type
- && (TREE_PURPOSE (binfo) == (tree)access_default
- || TREE_PURPOSE (binfo) == (tree)access_default_virtual)));
- int via_protected = TREE_PURPOSE (binfo) == (tree)access_protected;
+ && (TREE_PURPOSE (binfo) == access_default_node
+ || TREE_PURPOSE (binfo) == access_default_virtual_node)));
+ int via_protected
+ = (TREE_PURPOSE (binfo) == access_protected_node
+ || TREE_PURPOSE (binfo) == access_protected_virtual_node);
int via_virtual
- = (TREE_PURPOSE (binfo) == (tree)access_private_virtual
- || TREE_PURPOSE (binfo) == (tree)access_public_virtual
- || TREE_PURPOSE (binfo) == (tree)access_default_virtual);
- tree basetype = TREE_TYPE (TREE_VALUE (binfo));
+ = (TREE_PURPOSE (binfo) == access_private_virtual_node
+ || TREE_PURPOSE (binfo) == access_protected_virtual_node
+ || TREE_PURPOSE (binfo) == access_public_virtual_node
+ || TREE_PURPOSE (binfo) == access_default_virtual_node);
+ tree basetype = TREE_VALUE (binfo);
tree base_binfo;
- GNU_xref_hier (IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (TREE_VALUE (binfo)),
- via_public, via_virtual, 0);
-
if (basetype && TREE_CODE (basetype) == TYPE_DECL)
basetype = TREE_TYPE (basetype);
- if (!basetype || TREE_CODE (basetype) != RECORD_TYPE)
+ if (!basetype
+ || (TREE_CODE (basetype) != RECORD_TYPE
+ && TREE_CODE (basetype) != TYPENAME_TYPE
+ && TREE_CODE (basetype) != TEMPLATE_TYPE_PARM
+ && TREE_CODE (basetype) != TEMPLATE_TEMPLATE_PARM))
{
cp_error ("base type `%T' fails to be a struct or class type",
TREE_VALUE (binfo));
continue;
}
+
+ GNU_xref_hier (name, basetype, via_public, via_virtual, 0);
+
#if 1
- /* This code replaces similar code in layout_basetypes. */
- else if (TYPE_INCOMPLETE (basetype))
+ /* This code replaces similar code in layout_basetypes.
+ We put the complete_type first for implicit `typename'. */
+ if (TYPE_SIZE (complete_type (basetype)) == NULL_TREE
+ && ! (current_template_parms && uses_template_parms (basetype)))
{
cp_error ("base class `%T' has incomplete type", basetype);
continue;
@@ -10716,6 +11588,10 @@ xref_basetypes (code_type_node, name, ref, binfo)
continue;
}
+ if (TYPE_FOR_JAVA (basetype)
+ && current_lang_stack == current_lang_base)
+ TYPE_FOR_JAVA (ref) = 1;
+
/* Note that the BINFO records which describe individual
inheritances are *not* shared in the lattice! They
cannot be shared because a given baseclass may be
@@ -10735,17 +11611,7 @@ xref_basetypes (code_type_node, name, ref, binfo)
BINFO_INHERITANCE_CHAIN (base_binfo) = TYPE_BINFO (ref);
SET_CLASSTYPE_MARKED (basetype);
-#if 0
- /* XYZZY TEST VIRTUAL BASECLASSES */
- if (CLASSTYPE_N_BASECLASSES (basetype) == NULL_TREE
- && TYPE_HAS_DEFAULT_CONSTRUCTOR (basetype)
- && via_virtual == 0)
- {
- warning ("making type `%s' a virtual baseclass",
- TYPE_NAME_STRING (basetype));
- via_virtual = 1;
- }
-#endif
+
/* We are free to modify these bits because they are meaningless
at top level, and BASETYPE is a top-level type. */
if (via_virtual || TYPE_USES_VIRTUAL_BASECLASSES (basetype))
@@ -10754,7 +11620,6 @@ xref_basetypes (code_type_node, name, ref, binfo)
TYPE_USES_COMPLEX_INHERITANCE (ref) = 1;
}
- TYPE_OVERLOADS_METHOD_CALL_EXPR (ref) |= TYPE_OVERLOADS_METHOD_CALL_EXPR (basetype);
TYPE_GETS_NEW (ref) |= TYPE_GETS_NEW (basetype);
TYPE_GETS_DELETE (ref) |= TYPE_GETS_DELETE (basetype);
CLASSTYPE_LOCAL_TYPEDECLS (ref) |= CLASSTYPE_LOCAL_TYPEDECLS (basetype);
@@ -10783,7 +11648,7 @@ xref_basetypes (code_type_node, name, ref, binfo)
}
-static tree current_local_enum = NULL_TREE;
+tree current_local_enum = NULL_TREE;
/* Begin compiling the definition of an enumeration type.
NAME is its name (or null if anonymous).
@@ -10798,6 +11663,14 @@ start_enum (name)
register tree enumtype = NULL_TREE;
struct binding_level *b = inner_binding_level;
+ /* We are wasting space here and putting these on the permanent_obstack so
+ that typeid(local enum) will work correctly. */
+#if 0
+ if (processing_template_decl && current_function_decl)
+#endif
+
+ end_temporary_allocation ();
+
/* If this is the real definition for a previous forward reference,
fill in the contents in the same object that used to be the
forward reference. */
@@ -10806,36 +11679,23 @@ start_enum (name)
enumtype = lookup_tag (ENUMERAL_TYPE, name, b, 1);
if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
- cp_error ("multiple definition of enum `%T'", enumtype);
+ cp_error ("multiple definition of `%#T'", enumtype);
else
{
enumtype = make_node (ENUMERAL_TYPE);
pushtag (name, enumtype, 0);
}
+ if (b->pseudo_global)
+ cp_error ("template declaration of `%#T'", enumtype);
+
if (current_class_type)
TREE_ADDRESSABLE (b->tags) = 1;
- current_local_enum = NULL_TREE;
-
-#if 0 /* This stuff gets cleared in finish_enum anyway. */
- if (TYPE_VALUES (enumtype) != NULL_TREE)
- /* Completely replace its old definition.
- The old enumerators remain defined, however. */
- TYPE_VALUES (enumtype) = NULL_TREE;
-
- /* Initially, set up this enum as like `int'
- so that we can create the enumerators' declarations and values.
- Later on, the precision of the type may be changed and
- it may be laid out again. */
- TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
- TYPE_SIZE (enumtype) = NULL_TREE;
- fixup_signed_type (enumtype);
-#endif
+ current_local_enum = NULL_TREE;
- /* We copy this value because enumerated type constants
- are really of the type of the enumerator, not integer_type_node. */
- enum_next_value = copy_node (integer_zero_node);
+ /* We don't copy this value because build_enumerator needs to do it. */
+ enum_next_value = integer_zero_node;
enum_overflow = 0;
GNU_xref_decl (current_function_decl, enumtype);
@@ -10851,36 +11711,52 @@ tree
finish_enum (enumtype, values)
register tree enumtype, values;
{
- register tree minnode, maxnode;
+ register tree minnode = NULL_TREE, maxnode = NULL_TREE;
/* Calculate the maximum value of any enumerator in this type. */
if (values)
{
register tree pair;
register tree value = DECL_INITIAL (TREE_VALUE (values));
-
- /* Speed up the main loop by performing some precalculations */
- TREE_TYPE (TREE_VALUE (values)) = enumtype;
- TREE_TYPE (value) = enumtype;
+
+ if (! processing_template_decl)
+ {
+ /* Speed up the main loop by performing some precalculations */
+ TREE_TYPE (TREE_VALUE (values)) = enumtype;
+ TREE_TYPE (value) = enumtype;
+ minnode = maxnode = value;
+ }
TREE_VALUE (values) = value;
- minnode = maxnode = value;
for (pair = TREE_CHAIN (values); pair; pair = TREE_CHAIN (pair))
{
value = DECL_INITIAL (TREE_VALUE (pair));
- TREE_TYPE (TREE_VALUE (pair)) = enumtype;
- TREE_TYPE (value) = enumtype;
+ if (! processing_template_decl)
+ {
+ TREE_TYPE (TREE_VALUE (pair)) = enumtype;
+ TREE_TYPE (value) = enumtype;
+ if (tree_int_cst_lt (maxnode, value))
+ maxnode = value;
+ else if (tree_int_cst_lt (value, minnode))
+ minnode = value;
+ }
TREE_VALUE (pair) = value;
- if (tree_int_cst_lt (maxnode, value))
- maxnode = value;
- else if (tree_int_cst_lt (value, minnode))
- minnode = value;
}
}
else
maxnode = minnode = integer_zero_node;
- TYPE_VALUES (enumtype) = values;
+ TYPE_VALUES (enumtype) = nreverse (values);
+
+ if (processing_template_decl)
+ {
+ if (current_function_decl)
+ {
+ add_tree (build_min (TAG_DEFN, enumtype));
+ resume_temporary_allocation ();
+ }
+ return enumtype;
+ }
{
int unsignedp = tree_int_cst_sgn (minnode) >= 0;
@@ -10898,7 +11774,7 @@ finish_enum (enumtype, values)
else
fixup_signed_type (enumtype);
- if (flag_short_enums || precision > TYPE_PRECISION (integer_type_node))
+ if (flag_short_enums || (precision > TYPE_PRECISION (integer_type_node)))
/* Use the width of the narrowest normal C type which is wide enough. */
TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size
(precision, 1));
@@ -10909,9 +11785,6 @@ finish_enum (enumtype, values)
layout_type (enumtype);
}
- if (flag_cadillac)
- cadillac_finish_enum (enumtype);
-
{
register tree tem;
@@ -10923,6 +11796,7 @@ finish_enum (enumtype, values)
TYPE_MIN_VALUE (tem) = TYPE_MIN_VALUE (enumtype);
TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
+ TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype);
TYPE_MODE (tem) = TYPE_MODE (enumtype);
TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
@@ -10931,12 +11805,7 @@ finish_enum (enumtype, values)
}
/* Finish debugging output for this type. */
-#if 0
- /* @@ Do we ever generate generate ENUMERAL_TYPE nodes for which debugging
- information should *not* be generated? I think not. */
- if (! DECL_IGNORED_P (TYPE_NAME (enumtype)))
-#endif
- rest_of_type_compilation (enumtype, global_bindings_p ());
+ rest_of_type_compilation (enumtype, namespace_bindings_p ());
return enumtype;
}
@@ -10951,61 +11820,51 @@ build_enumerator (name, value)
tree name, value;
{
tree decl, result;
- /* Change this to zero if we find VALUE is not shareable. */
- int shareable = 1;
/* Remove no-op casts from the value. */
if (value)
STRIP_TYPE_NOPS (value);
- /* Validate and default VALUE. */
- if (value != NULL_TREE)
- {
- if (TREE_READONLY_DECL_P (value))
- {
- value = decl_constant_value (value);
- shareable = 0;
- }
-
- if (TREE_CODE (value) == INTEGER_CST)
- {
- value = default_conversion (value);
- constant_expression_warning (value);
- }
- else
- {
- cp_error ("enumerator value for `%D' not integer constant", name);
- value = NULL_TREE;
- }
- }
-
- /* The order of things is reversed here so that we
- can check for possible sharing of enum values,
- to keep that from happening. */
- /* Default based on previous value. */
- if (value == NULL_TREE)
- {
- value = enum_next_value;
- if (enum_overflow)
- cp_error ("overflow in enumeration values at `%D'", name);
- }
-
- /* Remove no-op casts from the value. */
- if (value)
- STRIP_TYPE_NOPS (value);
-
- /* Make up for hacks in lex.c. */
- if (value == integer_zero_node)
- value = build_int_2 (0, 0);
- else if (value == integer_one_node)
- value = build_int_2 (1, 0);
- else if (TREE_CODE (value) == INTEGER_CST
- && (shareable == 0
- || TREE_CODE (TREE_TYPE (value)) == ENUMERAL_TYPE))
- {
- value = copy_node (value);
- TREE_TYPE (value) = integer_type_node;
- }
+ if (! processing_template_decl)
+ {
+ /* Validate and default VALUE. */
+ if (value != NULL_TREE)
+ {
+ if (TREE_READONLY_DECL_P (value))
+ value = decl_constant_value (value);
+
+ if (TREE_CODE (value) == INTEGER_CST)
+ {
+ value = default_conversion (value);
+ constant_expression_warning (value);
+ }
+ else
+ {
+ cp_error ("enumerator value for `%D' not integer constant", name);
+ value = NULL_TREE;
+ }
+ }
+
+ /* Default based on previous value. */
+ if (value == NULL_TREE && ! processing_template_decl)
+ {
+ value = enum_next_value;
+ if (enum_overflow)
+ cp_error ("overflow in enumeration values at `%D'", name);
+ }
+
+ /* Remove no-op casts from the value. */
+ if (value)
+ STRIP_TYPE_NOPS (value);
+
+ /* We have to always copy here; not all INTEGER_CSTs are unshared,
+ and there's no wedding ring. Look at size_int()...*/
+ value = copy_node (value);
+#if 0
+ /* To fix MAX_VAL enum consts. (bkoz) */
+ TREE_TYPE (value) = integer_type_node;
+#endif
+ }
/* C++ associates enums with global, function, or class declarations. */
@@ -11027,26 +11886,27 @@ build_enumerator (name, value)
a function could mean local to a class method. */
decl = build_decl (CONST_DECL, name, integer_type_node);
DECL_INITIAL (decl) = value;
+ TREE_READONLY (decl) = 1;
pushdecl (decl);
GNU_xref_decl (current_function_decl, decl);
}
- /* Set basis for default for next value. */
- enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value,
- integer_one_node, PLUS_EXPR);
- enum_overflow = tree_int_cst_lt (enum_next_value, value);
-
- if (enum_next_value == integer_one_node)
- enum_next_value = copy_node (enum_next_value);
+ if (! processing_template_decl)
+ {
+ /* Set basis for default for next value. */
+ enum_next_value = build_binary_op_nodefault (PLUS_EXPR, value,
+ integer_one_node, PLUS_EXPR);
+ enum_overflow = tree_int_cst_lt (enum_next_value, value);
+ }
result = saveable_tree_cons (name, decl, NULL_TREE);
return result;
}
tree
-grok_enum_decls (type, decl)
- tree type, decl;
+grok_enum_decls (decl)
+ tree decl;
{
tree d = current_local_enum;
@@ -11055,7 +11915,6 @@ grok_enum_decls (type, decl)
while (1)
{
- TREE_TYPE (d) = type;
if (TREE_CHAIN (d) == NULL_TREE)
{
TREE_CHAIN (d) = decl;
@@ -11070,6 +11929,8 @@ grok_enum_decls (type, decl)
return decl;
}
+static int function_depth;
+
/* Create the FUNCTION_DECL for a function definition.
DECLSPECS and DECLARATOR are the parts of the declaration;
they describe the function's name and the type it returns,
@@ -11092,11 +11953,11 @@ grok_enum_decls (type, decl)
@@ something we had previously. */
int
-start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
- tree declspecs, declarator, raises, attrs;
+start_function (declspecs, declarator, attrs, pre_parsed_p)
+ tree declspecs, declarator, attrs;
int pre_parsed_p;
{
- tree decl1, olddecl;
+ tree decl1;
tree ctype = NULL_TREE;
tree fntype;
tree restype;
@@ -11105,10 +11966,10 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
int doing_friend = 0;
/* Sanity check. */
- my_friendly_assert (TREE_VALUE (void_list_node) == void_type_node, 160);
+ my_friendly_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE, 160);
my_friendly_assert (TREE_CHAIN (void_list_node) == NULL_TREE, 161);
- /* Assume, until we see it does. */
+ /* Assume, until we see it does. */
current_function_returns_value = 0;
current_function_returns_null = 0;
warn_about_return_type = 0;
@@ -11118,17 +11979,15 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
current_function_just_assigned_this = 0;
current_function_parms_stored = 0;
original_result_rtx = NULL_RTX;
- current_function_obstack_index = 0;
- current_function_obstack_usage = 0;
base_init_expr = NULL_TREE;
- protect_list = NULL_TREE;
current_base_init_list = NULL_TREE;
current_member_init_list = NULL_TREE;
ctor_label = dtor_label = NULL_TREE;
+ static_labelno = 0;
clear_temp_name ();
- /* This should only be done once on the top most decl. */
+ /* This should only be done once on the top most decl. */
if (have_extern_spec && !used_extern_spec)
{
declspecs = decl_tree_cons (NULL_TREE, get_identifier ("extern"), declspecs);
@@ -11139,31 +11998,25 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
{
decl1 = declarator;
+#if 0
+ /* What was this testing for, exactly? */
if (! DECL_ARGUMENTS (decl1)
&& !DECL_STATIC_FUNCTION_P (decl1)
- && DECL_CONTEXT (decl1)
- && DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl1)))
- && IDENTIFIER_TEMPLATE (DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl1)))))
+ && !DECL_ARTIFICIAL (decl1)
+ && DECL_CLASS_SCOPE_P (decl1)
+ && TYPE_IDENTIFIER (DECL_CONTEXT (decl1))
+ && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (DECL_CONTEXT (decl1))))
{
+ tree binding = binding_for_name (DECL_NAME (decl1),
+ current_namespace);
cp_error ("redeclaration of `%#D'", decl1);
if (IDENTIFIER_CLASS_VALUE (DECL_NAME (decl1)))
cp_error_at ("previous declaration here", IDENTIFIER_CLASS_VALUE (DECL_NAME (decl1)));
- else if (IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl1)))
- cp_error_at ("previous declaration here", IDENTIFIER_GLOBAL_VALUE (DECL_NAME (decl1)));
- }
-
- /* This can happen if a template class is instantiated as part of the
- specialization of a member function which is defined in the class
- template. We should just use the specialization, but for now give an
- error. */
- if (DECL_INITIAL (decl1) != NULL_TREE)
- {
- cp_error_at ("specialization of `%#D' not supported", decl1);
- cp_error ("when defined in the class template body", decl1);
+ else if (BINDING_VALUE (binding))
+ cp_error_at ("previous declaration here", BINDING_VALUE (binding));
}
+#endif
- last_function_parms = DECL_ARGUMENTS (decl1);
- last_function_parm_tags = NULL_TREE;
fntype = TREE_TYPE (decl1);
if (TREE_CODE (fntype) == METHOD_TYPE)
ctype = TYPE_METHOD_BASETYPE (fntype);
@@ -11184,23 +12037,23 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
doing_friend = 1;
}
- raises = TYPE_RAISES_EXCEPTIONS (fntype);
-
/* In a fcn definition, arg types must be complete. */
- require_complete_types_for_parms (last_function_parms);
+ require_complete_types_for_parms (DECL_ARGUMENTS (decl1));
/* In case some arg types were completed since the declaration was
parsed, fix up the decls. */
{
- tree t = last_function_parms;
+ tree t = DECL_ARGUMENTS (decl1);
for (; t; t = TREE_CHAIN (t))
layout_decl (t, 0);
}
+
+ last_function_parms = DECL_ARGUMENTS (decl1);
+ last_function_parm_tags = NULL_TREE;
}
else
{
- decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, raises,
- NULL_TREE);
+ decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, 1, NULL_TREE);
/* If the declarator is not suitable for a function definition,
cause a syntax error. */
if (decl1 == NULL_TREE || TREE_CODE (decl1) != FUNCTION_DECL) return 0;
@@ -11212,7 +12065,7 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
&& ! CLASSTYPE_GOT_SEMICOLON (restype))
{
cp_error ("semicolon missing after declaration of `%#T'", restype);
- shadow_tag (build_tree_list (NULL_TREE, restype));
+ shadow_tag (build_expr_list (NULL_TREE, restype));
CLASSTYPE_GOT_SEMICOLON (restype) = 1;
if (TREE_CODE (fntype) == FUNCTION_TYPE)
fntype = build_function_type (integer_type_node,
@@ -11226,15 +12079,13 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
if (TREE_CODE (fntype) == METHOD_TYPE)
ctype = TYPE_METHOD_BASETYPE (fntype);
- else if (IDENTIFIER_LENGTH (DECL_NAME (decl1)) == 4
- && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (decl1)), "main")
- && DECL_CONTEXT (decl1) == NULL_TREE)
+ else if (DECL_MAIN_P (decl1))
{
/* If this doesn't return integer_type, complain. */
if (TREE_TYPE (TREE_TYPE (decl1)) != integer_type_node)
{
if (pedantic || warn_return_type)
- pedwarn ("return type for `main' changed to integer type");
+ pedwarn ("return type for `main' changed to `int'");
TREE_TYPE (decl1) = fntype = default_function_type;
}
warn_about_return_type = 0;
@@ -11248,53 +12099,57 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
cp_warning_at ("`%D' implicitly declared before its definition", IDENTIFIER_IMPLICIT_DECL (DECL_NAME (decl1)));
current_function_decl = decl1;
+ /* Save the parm names or decls from this function's declarator
+ where store_parm_decls will find them. */
+ current_function_parms = last_function_parms;
+ current_function_parm_tags = last_function_parm_tags;
- if (flag_cadillac)
- cadillac_start_function (decl1);
- else
- announce_function (decl1);
+ announce_function (decl1);
- if (TYPE_SIZE (TREE_TYPE (fntype)) == NULL_TREE)
+ if (! processing_template_decl)
{
- if (IS_AGGR_TYPE (TREE_TYPE (fntype)))
- error_with_aggr_type (TREE_TYPE (fntype),
- "return-type `%s' is an incomplete type");
- else
- error ("return-type is an incomplete type");
-
- /* Make it return void instead, but don't change the
- type of the DECL_RESULT, in case we have a named return value. */
- if (ctype)
- TREE_TYPE (decl1)
- = build_cplus_method_type (build_type_variant (ctype,
- TREE_READONLY (decl1),
- TREE_SIDE_EFFECTS (decl1)),
- void_type_node,
- FUNCTION_ARG_CHAIN (decl1));
- else
- TREE_TYPE (decl1)
- = build_function_type (void_type_node,
- TYPE_ARG_TYPES (TREE_TYPE (decl1)));
- DECL_RESULT (decl1)
- = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (fntype)));
- TREE_READONLY (DECL_RESULT (decl1)) = TYPE_READONLY (TREE_TYPE (fntype));
- TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (TREE_TYPE (fntype));
- }
+ if (TYPE_SIZE (complete_type (TREE_TYPE (fntype))) == NULL_TREE)
+ {
+ cp_error ("return-type `%#T' is an incomplete type",
+ TREE_TYPE (fntype));
+
+ /* Make it return void instead, but don't change the
+ type of the DECL_RESULT, in case we have a named return value. */
+ if (ctype)
+ TREE_TYPE (decl1)
+ = build_cplus_method_type (build_type_variant (ctype,
+ TREE_READONLY (decl1),
+ TREE_SIDE_EFFECTS (decl1)),
+ void_type_node,
+ FUNCTION_ARG_CHAIN (decl1));
+ else
+ TREE_TYPE (decl1)
+ = build_function_type (void_type_node,
+ TYPE_ARG_TYPES (TREE_TYPE (decl1)));
+ DECL_RESULT (decl1)
+ = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (fntype)));
+ TREE_READONLY (DECL_RESULT (decl1)) = TYPE_READONLY (TREE_TYPE (fntype));
+ TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (TREE_TYPE (fntype));
+ }
- if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype))
- && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (fntype)))
- abstract_virtuals_error (decl1, TREE_TYPE (fntype));
+ if (TYPE_LANG_SPECIFIC (TREE_TYPE (fntype))
+ && CLASSTYPE_ABSTRACT_VIRTUALS (TREE_TYPE (fntype)))
+ abstract_virtuals_error (decl1, TREE_TYPE (fntype));
+ }
if (warn_about_return_type)
- warning ("return-type defaults to `int'");
+ pedwarn ("return-type defaults to `int'");
+
+ /* Effective C++ rule 15. See also c_expand_return. */
+ if (warn_ecpp
+ && DECL_NAME (decl1) == ansi_opname[(int) MODIFY_EXPR]
+ && TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE)
+ cp_warning ("`operator=' should return a reference to `*this'");
/* Make the init_value nonzero so pushdecl knows this is not tentative.
error_mark_node is replaced below (in poplevel) with the BLOCK. */
DECL_INITIAL (decl1) = error_mark_node;
- /* Didn't get anything from C. */
- olddecl = NULL_TREE;
-
/* This function exists in static storage.
(This does not mean `static' in the C sense!) */
TREE_STATIC (decl1) = 1;
@@ -11303,26 +12158,51 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
If we already have a decl for this name, and it is a FUNCTION_DECL,
use the old decl. */
- if (pre_parsed_p == 0)
- {
- current_function_decl = decl1 = pushdecl (decl1);
+ if (processing_template_decl)
+ decl1 = push_template_decl (decl1);
+ else if (pre_parsed_p == 0)
+ {
+ /* A specialization is not used to guide overload resolution. */
+ if ((flag_guiding_decls
+ || !DECL_TEMPLATE_SPECIALIZATION (decl1))
+ && ! DECL_FUNCTION_MEMBER_P (decl1))
+ decl1 = pushdecl (decl1);
+ else
+ {
+ /* We need to set the DECL_CONTEXT. */
+ if (!DECL_CONTEXT (decl1) && DECL_TEMPLATE_INFO (decl1))
+ DECL_CONTEXT (decl1) = DECL_CONTEXT (DECL_TI_TEMPLATE (decl1));
+ /* And make sure we have enough default args. */
+ check_default_args (decl1);
+ }
DECL_MAIN_VARIANT (decl1) = decl1;
fntype = TREE_TYPE (decl1);
}
- else
- current_function_decl = decl1;
+
+ current_function_decl = decl1;
if (DECL_INTERFACE_KNOWN (decl1))
{
+ tree ctx = hack_decl_function_context (decl1);
+
if (DECL_NOT_REALLY_EXTERN (decl1))
DECL_EXTERNAL (decl1) = 0;
+
+ if (ctx != NULL_TREE && DECL_THIS_INLINE (ctx)
+ && TREE_PUBLIC (ctx))
+ /* This is a function in a local class in an extern inline
+ function. */
+ comdat_linkage (decl1);
}
/* If this function belongs to an interface, it is public.
If it belongs to someone else's interface, it is also external.
It doesn't matter whether it's inline or not. */
- else if (interface_unknown == 0)
+ else if (interface_unknown == 0
+ && (! DECL_TEMPLATE_INSTANTIATION (decl1)
+ || flag_alt_external_templates))
{
- if (DECL_THIS_INLINE (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1))
+ if (DECL_THIS_INLINE (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1)
+ || processing_template_decl)
DECL_EXTERNAL (decl1)
= (interface_only
|| (DECL_THIS_INLINE (decl1) && ! flag_implement_inlines));
@@ -11337,14 +12217,13 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
So clear DECL_EXTERNAL. */
DECL_EXTERNAL (decl1) = 0;
- if (DECL_THIS_INLINE (decl1) && ! DECL_INTERFACE_KNOWN (decl1))
+ if ((DECL_THIS_INLINE (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1))
+ && ! DECL_INTERFACE_KNOWN (decl1)
+ /* Don't try to defer nested functions for now. */
+ && ! hack_decl_function_context (decl1))
DECL_DEFER_OUTPUT (decl1) = 1;
else
- {
- DECL_INTERFACE_KNOWN (decl1) = 1;
- if (DECL_C_STATIC (decl1))
- TREE_PUBLIC (decl1) = 0;
- }
+ DECL_INTERFACE_KNOWN (decl1) = 1;
}
if (ctype != NULL_TREE && DECL_STATIC_FUNCTION_P (decl1))
@@ -11353,8 +12232,8 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
TREE_TYPE (decl1) = fntype
= build_function_type (TREE_TYPE (fntype),
TREE_CHAIN (TYPE_ARG_TYPES (fntype)));
- last_function_parms = TREE_CHAIN (last_function_parms);
- DECL_ARGUMENTS (decl1) = last_function_parms;
+ current_function_parms = TREE_CHAIN (current_function_parms);
+ DECL_ARGUMENTS (decl1) = current_function_parms;
ctype = NULL_TREE;
}
restype = TREE_TYPE (fntype);
@@ -11364,15 +12243,15 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
push_nested_class (ctype, 1);
/* If we're compiling a friend function, neither of the variables
- current_class_decl nor current_class_type will have values. */
+ current_class_ptr nor current_class_type will have values. */
if (! doing_friend)
{
/* We know that this was set up by `grokclassfn'.
We do not wait until `store_parm_decls', since evil
parse errors may never get us to that point. Here
we keep the consistency between `current_class_type'
- and `current_class_decl'. */
- tree t = last_function_parms;
+ and `current_class_ptr'. */
+ tree t = current_function_parms;
my_friendly_assert (t != NULL_TREE
&& TREE_CODE (t) == PARM_DECL, 162);
@@ -11382,14 +12261,14 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
int i = suspend_momentary ();
/* Fool build_indirect_ref. */
- current_class_decl = NULL_TREE;
- C_C_D = build_indirect_ref (t, NULL_PTR);
- current_class_decl = t;
+ current_class_ptr = NULL_TREE;
+ current_class_ref = build_indirect_ref (t, NULL_PTR);
+ current_class_ptr = t;
resume_momentary (i);
}
else
/* We're having a signature pointer here. */
- C_C_D = current_class_decl = t;
+ current_class_ref = current_class_ptr = t;
}
}
@@ -11399,40 +12278,27 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
push_nested_class (DECL_CONTEXT (decl1), 2);
else
push_memoized_context (0, 1);
- current_class_decl = C_C_D = NULL_TREE;
+ current_class_ptr = current_class_ref = NULL_TREE;
}
pushlevel (0);
current_binding_level->parm_flag = 1;
- /* Save the parm names or decls from this function's declarator
- where store_parm_decls will find them. */
- current_function_parms = last_function_parms;
- current_function_parm_tags = last_function_parm_tags;
-
GNU_xref_function (decl1, current_function_parms);
if (attrs)
cplus_decl_attributes (decl1, NULL_TREE, attrs);
make_function_rtl (decl1);
- /* Allocate further tree nodes temporarily during compilation
- of this function only. Tiemann moved up here from bottom of fn. */
- temporary_allocation ();
-
/* Promote the value to int before returning it. */
if (C_PROMOTING_INTEGER_TYPE_P (restype))
- {
- /* It retains unsignedness if traditional or if it isn't
- really getting wider. */
- if (TREE_UNSIGNED (restype)
- && (flag_traditional
- || TYPE_PRECISION (restype)
- == TYPE_PRECISION (integer_type_node)))
- restype = unsigned_type_node;
- else
- restype = integer_type_node;
- }
+ restype = type_promotes_to (restype);
+
+ /* If this fcn was already referenced via a block-scope `extern' decl
+ (or an implicit decl), propagate certain information about the usage. */
+ if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (decl1)))
+ TREE_ADDRESSABLE (decl1) = 1;
+
if (DECL_RESULT (decl1) == NULL_TREE)
{
DECL_RESULT (decl1)
@@ -11441,6 +12307,22 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
TREE_THIS_VOLATILE (DECL_RESULT (decl1)) = TYPE_VOLATILE (restype);
}
+ /* Allocate further tree nodes temporarily during compilation
+ of this function only. Tiemann moved up here from bottom of fn. */
+ /* If this is a nested function, then we must continue to allocate RTL
+ on the permanent obstack in case we need to inline it later. */
+ if (! hack_decl_function_context (decl1))
+ temporary_allocation ();
+
+ if (processing_template_decl)
+ {
+ ++minimal_parse_mode;
+ last_tree = DECL_SAVED_TREE (decl1)
+ = build_nt (EXPR_STMT, void_zero_node);
+ }
+
+ ++function_depth;
+
if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl1))
&& DECL_LANGUAGE (decl1) == lang_cplusplus)
{
@@ -11454,36 +12336,18 @@ start_function (declspecs, declarator, raises, attrs, pre_parsed_p)
ctor_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
}
- /* If this fcn was already referenced via a block-scope `extern' decl
- (or an implicit decl), propagate certain information about the usage. */
- if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (decl1)))
- TREE_ADDRESSABLE (decl1) = 1;
-
return 1;
}
+/* Called after store_parm_decls for a function-try-block. We need to update
+ last_parm_cleanup_insn so that the base initializers for a constructor
+ are run within this block, not before it. */
+
void
expand_start_early_try_stmts ()
{
- rtx insns;
- start_sequence ();
expand_start_try_stmts ();
- insns = get_insns ();
- end_sequence ();
- store_in_parms (insns);
-}
-
-void
-store_in_parms (insns)
- rtx insns;
-{
- rtx last_parm_insn;
-
- last_parm_insn = get_first_nonparm_insn ();
- if (last_parm_insn == NULL_RTX)
- emit_insns (insns);
- else
- emit_insns_before (insns, previous_insn (last_parm_insn));
+ last_parm_cleanup_insn = get_last_insn ();
}
/* Store the parameter declarations into the current function declaration.
@@ -11498,6 +12362,7 @@ store_parm_decls ()
register tree fndecl = current_function_decl;
register tree parm;
int parms_have_cleanups = 0;
+ tree cleanups = NULL_TREE;
/* This is either a chain of PARM_DECLs (when a prototype is used). */
tree specparms = current_function_parms;
@@ -11534,22 +12399,18 @@ store_parm_decls ()
/* Must clear this because it might contain TYPE_DECLs declared
at class level. */
storedecls (NULL_TREE);
+
for (parm = nreverse (specparms); parm; parm = next)
{
next = TREE_CHAIN (parm);
if (TREE_CODE (parm) == PARM_DECL)
{
- tree cleanup = maybe_build_cleanup (parm);
+ tree cleanup;
if (DECL_NAME (parm) == NULL_TREE)
{
-#if 0
- cp_error_at ("parameter name omitted", parm);
-#else
- /* for C++, this is not an error. */
pushdecl (parm);
-#endif
}
- else if (TYPE_MAIN_VARIANT (TREE_TYPE (parm)) == void_type_node)
+ else if (TREE_CODE (TREE_TYPE (parm)) == VOID_TYPE)
cp_error ("parameter `%D' declared void", parm);
else
{
@@ -11572,13 +12433,14 @@ store_parm_decls ()
pushdecl (parm);
}
- if (cleanup)
+ if (! processing_template_decl
+ && (cleanup = maybe_build_cleanup (parm), cleanup))
{
expand_decl (parm);
- if (! cp_expand_decl_cleanup (parm, cleanup))
- cp_error ("parser lost in parsing declaration of `%D'",
- parm);
parms_have_cleanups = 1;
+
+ /* Keep track of the cleanups. */
+ cleanups = tree_cons (parm, cleanup, cleanups);
}
}
else
@@ -11609,7 +12471,29 @@ store_parm_decls ()
/* Initialize the RTL code for the function. */
DECL_SAVED_INSNS (fndecl) = NULL_RTX;
- expand_function_start (fndecl, parms_have_cleanups);
+ if (! processing_template_decl)
+ expand_function_start (fndecl, parms_have_cleanups);
+
+ current_function_parms_stored = 1;
+
+ /* If this function is `main', emit a call to `__main'
+ to run global initializers, etc. */
+ if (DECL_MAIN_P (fndecl))
+ expand_main_function ();
+
+ /* Now that we have initialized the parms, we can start their
+ cleanups. We cannot do this before, since expand_decl_cleanup
+ should not be called before the parm can be used. */
+ if (cleanups
+ && ! processing_template_decl)
+ {
+ for (cleanups = nreverse (cleanups); cleanups; cleanups = TREE_CHAIN (cleanups))
+ {
+ if (! expand_decl_cleanup (TREE_PURPOSE (cleanups), TREE_VALUE (cleanups)))
+ cp_error ("parser lost in parsing declaration of `%D'",
+ TREE_PURPOSE (cleanups));
+ }
+ }
/* Create a binding contour which can be used to catch
cleanup-generated temporaries. Also, if the return value needs or
@@ -11620,57 +12504,20 @@ store_parm_decls ()
expand_start_bindings (0);
}
- current_function_parms_stored = 1;
-
- if (flag_gc)
- {
- maybe_gc_cleanup = build_tree_list (NULL_TREE, error_mark_node);
- if (! cp_expand_decl_cleanup (NULL_TREE, maybe_gc_cleanup))
- cp_error ("parser lost in parsing declaration of `%D'", fndecl);
- }
-
- /* If this function is `main', emit a call to `__main'
- to run global initializers, etc. */
- if (DECL_NAME (fndecl)
- && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 4
- && strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main") == 0
- && DECL_CONTEXT (fndecl) == NULL_TREE)
- {
- expand_main_function ();
-
- if (flag_gc)
- expand_expr (build_function_call (lookup_name (get_identifier ("__gc_main"), 0), NULL_TREE),
- 0, VOIDmode, 0);
-#if 0
- /* done at a different time */
- if (flag_rtti)
- output_builtin_tdesc_entries ();
-#endif
- }
-
- /* Take care of exception handling things. */
- if (flag_handle_exceptions)
+ if (! processing_template_decl && flag_exceptions)
{
- rtx insns;
- start_sequence ();
-
- /* Mark the start of a stack unwinder if we need one. */
- start_eh_unwinder ();
-
/* Do the starting of the exception specifications, if we have any. */
if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
expand_start_eh_spec ();
-
- insns = get_insns ();
- end_sequence ();
-
- if (insns)
- store_in_parms (insns);
}
+
+ last_parm_cleanup_insn = get_last_insn ();
+ last_dtor_insn = get_last_insn ();
}
/* Bind a name and initialization to the return value of
the current function. */
+
void
store_return_init (return_id, init)
tree return_id, init;
@@ -11691,8 +12538,7 @@ store_return_init (return_id, init)
DECL_ASSEMBLER_NAME (decl) = return_id;
}
else
- error ("return identifier `%s' already in place",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
+ cp_error ("return identifier `%D' already in place", decl);
}
/* Can't let this happen for constructors. */
@@ -11716,7 +12562,12 @@ store_return_init (return_id, init)
/* Let `cp_finish_decl' know that this initializer is ok. */
DECL_INITIAL (decl) = init;
pushdecl (decl);
- cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
+
+ if (minimal_parse_mode)
+ add_tree (build_min_nt (RETURN_INIT, return_id,
+ copy_to_permanent (init)));
+ else
+ cp_finish_decl (decl, init, NULL_TREE, 0, 0);
}
}
@@ -11731,7 +12582,10 @@ store_return_init (return_id, init)
C++: CALL_POPLEVEL is non-zero if an extra call to poplevel
(and expand_end_bindings) must be made to take care of the binding
contour for the base initializers. This is only relevant for
- constructors. */
+ constructors.
+
+ NESTED is nonzero if we were in the middle of compiling another function
+ when we started on this one. */
void
finish_function (lineno, call_poplevel, nested)
@@ -11751,6 +12605,9 @@ finish_function (lineno, call_poplevel, nested)
if (fndecl == NULL_TREE)
return;
+ if (! nested && function_depth > 1)
+ nested = 1;
+
fntype = TREE_TYPE (fndecl);
/* TREE_READONLY (fndecl) = 1;
@@ -11764,382 +12621,391 @@ finish_function (lineno, call_poplevel, nested)
store_parm_decls ();
}
- if (write_symbols != NO_DEBUG /*&& TREE_CODE (fntype) != METHOD_TYPE*/)
+ if (processing_template_decl)
{
- tree ttype = target_type (fntype);
- tree parmdecl;
-
- if (IS_AGGR_TYPE (ttype))
- /* Let debugger know it should output info for this type. */
- note_debug_info_needed (ttype);
-
- for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl))
+ if (DECL_CONSTRUCTOR_P (fndecl) && call_poplevel)
{
- ttype = target_type (TREE_TYPE (parmdecl));
+ decls = getdecls ();
+ expand_end_bindings (decls, decls != NULL_TREE, 0);
+ poplevel (decls != NULL_TREE, 0, 0);
+ }
+ }
+ else
+ {
+ if (write_symbols != NO_DEBUG /*&& TREE_CODE (fntype) != METHOD_TYPE*/)
+ {
+ tree ttype = target_type (fntype);
+ tree parmdecl;
+
if (IS_AGGR_TYPE (ttype))
/* Let debugger know it should output info for this type. */
note_debug_info_needed (ttype);
+
+ for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl))
+ {
+ ttype = target_type (TREE_TYPE (parmdecl));
+ if (IS_AGGR_TYPE (ttype))
+ /* Let debugger know it should output info for this type. */
+ note_debug_info_needed (ttype);
+ }
}
- }
- /* Clean house because we will need to reorder insns here. */
- do_pending_stack_adjust ();
+ /* Clean house because we will need to reorder insns here. */
+ do_pending_stack_adjust ();
- if (dtor_label)
- {
- tree binfo = TYPE_BINFO (current_class_type);
- tree cond = integer_one_node;
- tree exprstmt, vfields;
- tree in_charge_node = lookup_name (in_charge_identifier, 0);
- tree virtual_size;
- int ok_to_optimize_dtor = 0;
-
- if (current_function_assigns_this)
- cond = build (NE_EXPR, boolean_type_node,
- current_class_decl, integer_zero_node);
- else
+ if (dtor_label)
{
- int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
+ tree binfo = TYPE_BINFO (current_class_type);
+ tree cond = integer_one_node;
+ tree exprstmt;
+ tree in_charge_node = lookup_name (in_charge_identifier, 0);
+ tree virtual_size;
+ int ok_to_optimize_dtor = 0;
+ int empty_dtor = get_last_insn () == last_dtor_insn;
- /* If this destructor is empty, then we don't need to check
- whether `this' is NULL in some cases. */
- if ((flag_this_is_variable & 1) == 0)
- ok_to_optimize_dtor = 1;
- else if (get_last_insn () == get_first_nonparm_insn ())
- ok_to_optimize_dtor
- = (n_baseclasses == 0
- || (n_baseclasses == 1
- && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0))));
- }
+ if (current_function_assigns_this)
+ cond = build (NE_EXPR, boolean_type_node,
+ current_class_ptr, integer_zero_node);
+ else
+ {
+ int n_baseclasses = CLASSTYPE_N_BASECLASSES (current_class_type);
+
+ /* If this destructor is empty, then we don't need to check
+ whether `this' is NULL in some cases. */
+ if ((flag_this_is_variable & 1) == 0)
+ ok_to_optimize_dtor = 1;
+ else if (empty_dtor)
+ ok_to_optimize_dtor
+ = (n_baseclasses == 0
+ || (n_baseclasses == 1
+ && TYPE_HAS_DESTRUCTOR (TYPE_BINFO_BASETYPE (current_class_type, 0))));
+ }
- /* These initializations might go inline. Protect
- the binding level of the parms. */
- pushlevel (0);
- expand_start_bindings (0);
+ /* These initializations might go inline. Protect
+ the binding level of the parms. */
+ pushlevel (0);
+ expand_start_bindings (0);
- if (current_function_assigns_this)
- {
- current_function_assigns_this = 0;
- current_function_just_assigned_this = 0;
- }
+ if (current_function_assigns_this)
+ {
+ current_function_assigns_this = 0;
+ current_function_just_assigned_this = 0;
+ }
- /* Generate the code to call destructor on base class.
- If this destructor belongs to a class with virtual
- functions, then set the virtual function table
- pointer to represent the type of our base class. */
+ /* Generate the code to call destructor on base class.
+ If this destructor belongs to a class with virtual
+ functions, then set the virtual function table
+ pointer to represent the type of our base class. */
- /* This side-effect makes call to `build_delete' generate the
- code we have to have at the end of this destructor. */
- TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
+ /* This side-effect makes call to `build_delete' generate the
+ code we have to have at the end of this destructor. */
+ TYPE_HAS_DESTRUCTOR (current_class_type) = 0;
- /* These are two cases where we cannot delegate deletion. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
- || TYPE_GETS_REG_DELETE (current_class_type))
- exprstmt = build_delete (current_class_type, C_C_D, integer_zero_node,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
- else
- exprstmt = build_delete (current_class_type, C_C_D, in_charge_node,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
-
- /* If we did not assign to this, then `this' is non-zero at
- the end of a destructor. As a special optimization, don't
- emit test if this is an empty destructor. If it does nothing,
- it does nothing. If it calls a base destructor, the base
- destructor will perform the test. */
-
- if (exprstmt != error_mark_node
- && (TREE_CODE (exprstmt) != NOP_EXPR
- || TREE_OPERAND (exprstmt, 0) != integer_zero_node
- || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
- {
- expand_label (dtor_label);
- if (cond != integer_one_node)
- expand_start_cond (cond, 0);
- if (exprstmt != void_zero_node)
- /* Don't call `expand_expr_stmt' if we're not going to do
- anything, since -Wall will give a diagnostic. */
- expand_expr_stmt (exprstmt);
-
- /* Run destructor on all virtual baseclasses. */
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- {
- tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
- expand_start_cond (build (BIT_AND_EXPR, integer_type_node,
- in_charge_node, integer_two_node), 0);
- while (vbases)
+ /* These are two cases where we cannot delegate deletion. */
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)
+ || TYPE_GETS_REG_DELETE (current_class_type))
+ exprstmt = build_delete (current_class_type, current_class_ref, integer_zero_node,
+ LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
+ else
+ exprstmt = build_delete (current_class_type, current_class_ref, in_charge_node,
+ LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_NORMAL, 0);
+
+ /* If we did not assign to this, then `this' is non-zero at
+ the end of a destructor. As a special optimization, don't
+ emit test if this is an empty destructor. If it does nothing,
+ it does nothing. If it calls a base destructor, the base
+ destructor will perform the test. */
+
+ if (exprstmt != error_mark_node
+ && (TREE_CODE (exprstmt) != NOP_EXPR
+ || TREE_OPERAND (exprstmt, 0) != integer_zero_node
+ || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)))
+ {
+ expand_label (dtor_label);
+ if (cond != integer_one_node)
+ expand_start_cond (cond, 0);
+ if (exprstmt != void_zero_node)
+ /* Don't call `expand_expr_stmt' if we're not going to do
+ anything, since -Wall will give a diagnostic. */
+ expand_expr_stmt (exprstmt);
+
+ /* Run destructor on all virtual baseclasses. */
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
{
- if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
+ tree vbases = nreverse (copy_list (CLASSTYPE_VBASECLASSES (current_class_type)));
+ expand_start_cond (build (BIT_AND_EXPR, integer_type_node,
+ in_charge_node, integer_two_node), 0);
+ while (vbases)
{
- tree ptr = convert_pointer_to_vbase (BINFO_TYPE (vbases), current_class_decl);
- expand_expr_stmt (build_delete (build_pointer_type (BINFO_TYPE (vbases)),
- ptr, integer_zero_node,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR|LOOKUP_HAS_IN_CHARGE, 0));
+ if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (vbases)))
+ {
+ tree vb = get_vbase
+ (BINFO_TYPE (vbases),
+ TYPE_BINFO (current_class_type));
+ expand_expr_stmt
+ (build_scoped_method_call
+ (current_class_ref, vb, dtor_identifier,
+ build_expr_list (NULL_TREE, integer_zero_node)));
+ }
+ vbases = TREE_CHAIN (vbases);
}
- vbases = TREE_CHAIN (vbases);
+ expand_end_cond ();
}
- expand_end_cond ();
+
+ do_pending_stack_adjust ();
+ if (cond != integer_one_node)
+ expand_end_cond ();
}
- do_pending_stack_adjust ();
- if (cond != integer_one_node)
- expand_end_cond ();
- }
+ TYPE_HAS_DESTRUCTOR (current_class_type) = 1;
- TYPE_HAS_DESTRUCTOR (current_class_type) = 1;
-
- virtual_size = c_sizeof (current_class_type);
-
- /* At the end, call delete if that's what's requested. */
- if (TYPE_GETS_REG_DELETE (current_class_type))
- /* This NOP_EXPR means we are in a static call context. */
- exprstmt =
- build_method_call
- (build_indirect_ref
- (build1 (NOP_EXPR, build_pointer_type (current_class_type),
- error_mark_node),
- NULL_PTR),
- ansi_opname[(int) DELETE_EXPR],
- tree_cons (NULL_TREE, current_class_decl,
- build_tree_list (NULL_TREE, virtual_size)),
- NULL_TREE, LOOKUP_NORMAL);
- else if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- exprstmt = build_x_delete (ptr_type_node, current_class_decl, 0,
- virtual_size);
- else
- exprstmt = NULL_TREE;
+ virtual_size = c_sizeof (current_class_type);
- if (exprstmt)
- {
- cond = build (BIT_AND_EXPR, integer_type_node,
- in_charge_node, integer_one_node);
- expand_start_cond (cond, 0);
- expand_expr_stmt (exprstmt);
- expand_end_cond ();
- }
+ /* At the end, call delete if that's what's requested. */
- /* End of destructor. */
- expand_end_bindings (NULL_TREE, getdecls() != NULL_TREE, 0);
- poplevel (2, 0, 0); /* XXX change to 1 */
+ /* FDIS sez: At the point of definition of a virtual destructor
+ (including an implicit definition), non-placement operator
+ delete shall be looked up in the scope of the destructor's
+ class and if found shall be accessible and unambiguous.
- /* Back to the top of destructor. */
- /* Dont execute destructor code if `this' is NULL. */
+ This is somewhat unclear, but I take it to mean that if the
+ class only defines placement deletes we don't do anything here.
+ So we pass LOOKUP_SPECULATIVELY; delete_sanity will complain
+ for us if they ever try to delete one of these. */
- start_sequence ();
+ if (TYPE_GETS_REG_DELETE (current_class_type)
+ || TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ exprstmt = build_op_delete_call
+ (DELETE_EXPR, current_class_ptr, virtual_size,
+ LOOKUP_NORMAL | LOOKUP_SPECULATIVELY, NULL_TREE);
+ else
+ exprstmt = NULL_TREE;
- /* Make all virtual function table pointers in non-virtual base
- classes point to CURRENT_CLASS_TYPE's virtual function
- tables. */
- expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_decl);
- if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
- expand_indirect_vtbls_init (binfo, C_C_D, current_class_decl, 0);
- if (! ok_to_optimize_dtor)
- {
- cond = build_binary_op (NE_EXPR,
- current_class_decl, integer_zero_node, 1);
- expand_start_cond (cond, 0);
- }
+ if (exprstmt)
+ {
+ cond = build (BIT_AND_EXPR, integer_type_node,
+ in_charge_node, integer_one_node);
+ expand_start_cond (cond, 0);
+ expand_expr_stmt (exprstmt);
+ expand_end_cond ();
+ }
- insns = get_insns ();
- end_sequence ();
+ /* End of destructor. */
+ expand_end_bindings (NULL_TREE, getdecls () != NULL_TREE, 0);
+ poplevel (2, 0, 0); /* XXX change to 1 */
+
+ /* Back to the top of destructor. */
+ /* Don't execute destructor code if `this' is NULL. */
+
+ start_sequence ();
+
+ /* If the dtor is empty, and we know there is not possible way we
+ could use any vtable entries, before they are possibly set by
+ a base class dtor, we don't have to setup the vtables, as we
+ know that any base class dtoring will set up any vtables it
+ needs. We avoid MI, because one base class dtor can do a
+ virtual dispatch to an overridden function that would need to
+ have a non-related vtable set up, we cannot avoid setting up
+ vtables in that case. We could change this to see if there is
+ just one vtable. */
+ if (! empty_dtor || TYPE_USES_COMPLEX_INHERITANCE (current_class_type))
+ {
+ /* Make all virtual function table pointers in non-virtual base
+ classes point to CURRENT_CLASS_TYPE's virtual function
+ tables. */
+ expand_direct_vtbls_init (binfo, binfo, 1, 0, current_class_ptr);
- last_parm_insn = get_first_nonparm_insn ();
- if (last_parm_insn == NULL_RTX)
- last_parm_insn = get_last_insn ();
- else
- last_parm_insn = previous_insn (last_parm_insn);
+ if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+ expand_indirect_vtbls_init (binfo, current_class_ref, current_class_ptr);
+ }
+
+ if (! ok_to_optimize_dtor)
+ {
+ cond = build_binary_op (NE_EXPR,
+ current_class_ptr, integer_zero_node, 1);
+ expand_start_cond (cond, 0);
+ }
- emit_insns_after (insns, last_parm_insn);
+ insns = get_insns ();
+ end_sequence ();
- if (! ok_to_optimize_dtor)
- expand_end_cond ();
- }
- else if (current_function_assigns_this)
- {
- /* Does not need to call emit_base_init, because
- that is done (if needed) just after assignment to this
- is seen. */
+ last_parm_insn = get_first_nonparm_insn ();
+ if (last_parm_insn == NULL_RTX)
+ last_parm_insn = get_last_insn ();
+ else
+ last_parm_insn = previous_insn (last_parm_insn);
- if (DECL_CONSTRUCTOR_P (current_function_decl))
- {
- end_protect_partials ();
- expand_label (ctor_label);
- ctor_label = NULL_TREE;
+ emit_insns_after (insns, last_parm_insn);
- if (call_poplevel)
- {
- decls = getdecls ();
- expand_end_bindings (decls, decls != NULL_TREE, 0);
- poplevel (decls != NULL_TREE, 0, 0);
- }
- c_expand_return (current_class_decl);
+ if (! ok_to_optimize_dtor)
+ expand_end_cond ();
}
- else if (TYPE_MAIN_VARIANT (TREE_TYPE (
- DECL_RESULT (current_function_decl))) != void_type_node
- && return_label != NULL_RTX)
- no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ else if (current_function_assigns_this)
+ {
+ /* Does not need to call emit_base_init, because
+ that is done (if needed) just after assignment to this
+ is seen. */
- current_function_assigns_this = 0;
- current_function_just_assigned_this = 0;
- base_init_expr = NULL_TREE;
- }
- else if (DECL_CONSTRUCTOR_P (fndecl))
- {
- tree allocated_this;
- tree cond, thenclause;
- /* Allow constructor for a type to get a new instance of the object
- using `build_new'. */
- tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
- CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
+ if (DECL_CONSTRUCTOR_P (current_function_decl))
+ {
+ end_protect_partials ();
+ expand_label (ctor_label);
+ ctor_label = NULL_TREE;
- DECL_RETURNS_FIRST_ARG (fndecl) = 1;
+ if (call_poplevel)
+ {
+ decls = getdecls ();
+ expand_end_bindings (decls, decls != NULL_TREE, 0);
+ poplevel (decls != NULL_TREE, 0, 0);
+ }
+ /* c_expand_return knows to return 'this' from a constructor. */
+ c_expand_return (NULL_TREE);
+ }
+ else if (TREE_CODE (TREE_TYPE (DECL_RESULT (current_function_decl))) != VOID_TYPE
+ && return_label != NULL_RTX)
+ no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- if (flag_this_is_variable > 0)
- {
- cond = build_binary_op (EQ_EXPR,
- current_class_decl, integer_zero_node, 1);
- thenclause = build_modify_expr (current_class_decl, NOP_EXPR,
- build_new (NULL_TREE, current_class_type, void_type_node, 0));
+ current_function_assigns_this = 0;
+ current_function_just_assigned_this = 0;
+ base_init_expr = NULL_TREE;
}
+ else if (DECL_CONSTRUCTOR_P (fndecl))
+ {
+ tree cond = NULL_TREE, thenclause = NULL_TREE;
+ /* Allow constructor for a type to get a new instance of the object
+ using `build_new'. */
+ tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type);
+ CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = NULL_TREE;
- CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
+ DECL_RETURNS_FIRST_ARG (fndecl) = 1;
- start_sequence ();
+ if (flag_this_is_variable > 0)
+ {
+ cond = build_binary_op (EQ_EXPR,
+ current_class_ptr, integer_zero_node, 1);
+ thenclause = build_modify_expr (current_class_ptr, NOP_EXPR,
+ build_new (NULL_TREE, current_class_type, void_type_node, 0));
+ }
- if (flag_this_is_variable > 0)
- {
- expand_start_cond (cond, 0);
- expand_expr_stmt (thenclause);
- expand_end_cond ();
- }
+ CLASSTYPE_ABSTRACT_VIRTUALS (current_class_type) = abstract_virtuals;
-#if 0
- if (DECL_NAME (fndecl) == NULL_TREE
- && TREE_CHAIN (DECL_ARGUMENTS (fndecl)) != NULL_TREE)
- build_default_constructor (fndecl);
-#endif
+ start_sequence ();
- /* Emit insns from `emit_base_init' which sets up virtual
- function table pointer(s). */
- if (base_init_expr)
- {
- expand_expr_stmt (base_init_expr);
- base_init_expr = NULL_TREE;
- }
+ if (flag_this_is_variable > 0)
+ {
+ expand_start_cond (cond, 0);
+ expand_expr_stmt (thenclause);
+ expand_end_cond ();
+ }
- insns = get_insns ();
- end_sequence ();
+ /* Emit insns from `emit_base_init' which sets up virtual
+ function table pointer(s). */
+ if (base_init_expr)
+ {
+ expand_expr_stmt (base_init_expr);
+ base_init_expr = NULL_TREE;
+ }
- /* This is where the body of the constructor begins.
- If there were no insns in this function body, then the
- last_parm_insn is also the last insn.
+ insns = get_insns ();
+ end_sequence ();
- If optimization is enabled, last_parm_insn may move, so
- we don't hold on to it (across emit_base_init). */
- last_parm_insn = get_first_nonparm_insn ();
- if (last_parm_insn == NULL_RTX)
- last_parm_insn = get_last_insn ();
- else
- last_parm_insn = previous_insn (last_parm_insn);
+ /* This is where the body of the constructor begins. */
- emit_insns_after (insns, last_parm_insn);
+ emit_insns_after (insns, last_parm_cleanup_insn);
- end_protect_partials ();
+ end_protect_partials ();
- /* This is where the body of the constructor ends. */
- expand_label (ctor_label);
- ctor_label = NULL_TREE;
+ /* This is where the body of the constructor ends. */
+ expand_label (ctor_label);
+ ctor_label = NULL_TREE;
- if (call_poplevel)
- {
- decls = getdecls ();
- expand_end_bindings (decls, decls != NULL_TREE, 0);
- poplevel (decls != NULL_TREE, 1, 0);
- }
+ if (call_poplevel)
+ {
+ decls = getdecls ();
+ expand_end_bindings (decls, decls != NULL_TREE, 0);
+ poplevel (decls != NULL_TREE, 1, 0);
+ }
- c_expand_return (current_class_decl);
+ /* c_expand_return knows to return 'this' from a constructor. */
+ c_expand_return (NULL_TREE);
- current_function_assigns_this = 0;
- current_function_just_assigned_this = 0;
- }
- else if (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 4
- && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main")
- && DECL_CONTEXT (fndecl) == NULL_TREE)
- {
- /* Make it so that `main' always returns 0 by default. */
+ current_function_assigns_this = 0;
+ current_function_just_assigned_this = 0;
+ }
+ else if (DECL_MAIN_P (fndecl))
+ {
+ /* Make it so that `main' always returns 0 by default. */
#ifdef VMS
- c_expand_return (integer_one_node);
+ c_expand_return (integer_one_node);
#else
- c_expand_return (integer_zero_node);
+ c_expand_return (integer_zero_node);
#endif
- }
- else if (return_label != NULL_RTX
- && current_function_return_value == NULL_TREE
- && ! DECL_NAME (DECL_RESULT (current_function_decl)))
- no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
- if (flag_gc)
- expand_gc_prologue_and_epilogue ();
+ }
+ else if (return_label != NULL_RTX
+ && current_function_return_value == NULL_TREE
+ && ! DECL_NAME (DECL_RESULT (current_function_decl)))
+ no_return_label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- /* If this function is supposed to return a value, ensure that
- we do not fall into the cleanups by mistake. The end of our
- function will look like this:
+ if (flag_exceptions)
+ expand_exception_blocks ();
- user code (may have return stmt somewhere)
- goto no_return_label
- cleanup_label:
- cleanups
- goto return_label
- no_return_label:
- NOTE_INSN_FUNCTION_END
- return_label:
- things for return
+ /* If this function is supposed to return a value, ensure that
+ we do not fall into the cleanups by mistake. The end of our
+ function will look like this:
+
+ user code (may have return stmt somewhere)
+ goto no_return_label
+ cleanup_label:
+ cleanups
+ goto return_label
+ no_return_label:
+ NOTE_INSN_FUNCTION_END
+ return_label:
+ things for return
+
+ If the user omits a return stmt in the USER CODE section, we
+ will have a control path which reaches NOTE_INSN_FUNCTION_END.
+ Otherwise, we won't. */
+ if (no_return_label)
+ {
+ DECL_CONTEXT (no_return_label) = fndecl;
+ DECL_INITIAL (no_return_label) = error_mark_node;
+ DECL_SOURCE_FILE (no_return_label) = input_filename;
+ DECL_SOURCE_LINE (no_return_label) = lineno;
+ expand_goto (no_return_label);
+ }
- If the user omits a return stmt in the USER CODE section, we
- will have a control path which reaches NOTE_INSN_FUNCTION_END.
- Otherwise, we won't. */
- if (no_return_label)
- {
- DECL_CONTEXT (no_return_label) = fndecl;
- DECL_INITIAL (no_return_label) = error_mark_node;
- DECL_SOURCE_FILE (no_return_label) = input_filename;
- DECL_SOURCE_LINE (no_return_label) = lineno;
- expand_goto (no_return_label);
- }
+ if (cleanup_label)
+ {
+ /* Remove the binding contour which is used
+ to catch cleanup-generated temporaries. */
+ expand_end_bindings (0, 0, 0);
+ poplevel (0, 0, 0);
- if (cleanup_label)
- {
- /* remove the binding contour which is used
- to catch cleanup-generated temporaries. */
- expand_end_bindings (0, 0, 0);
- poplevel (0, 0, 0);
- }
+ /* Emit label at beginning of cleanup code for parameters. */
+ emit_label (cleanup_label);
+ }
- if (cleanup_label)
- /* Emit label at beginning of cleanup code for parameters. */
- emit_label (cleanup_label);
+ /* Get return value into register if that's where it's supposed to be. */
+ if (original_result_rtx)
+ fixup_result_decl (DECL_RESULT (fndecl), original_result_rtx);
- /* Get return value into register if that's where it's supposed to be. */
- if (original_result_rtx)
- fixup_result_decl (DECL_RESULT (fndecl), original_result_rtx);
+ /* Finish building code that will trigger warnings if users forget
+ to make their functions return values. */
+ if (no_return_label || cleanup_label)
+ emit_jump (return_label);
+ if (no_return_label)
+ {
+ /* We don't need to call `expand_*_return' here because we
+ don't need any cleanups here--this path of code is only
+ for error checking purposes. */
+ expand_label (no_return_label);
+ }
- /* Finish building code that will trigger warnings if users forget
- to make their functions return values. */
- if (no_return_label || cleanup_label)
- emit_jump (return_label);
- if (no_return_label)
- {
- /* We don't need to call `expand_*_return' here because we
- don't need any cleanups here--this path of code is only
- for error checking purposes. */
- expand_label (no_return_label);
+ /* Generate rtl for function exit. */
+ expand_function_end (input_filename, lineno, 1);
}
- /* Generate rtl for function exit. */
- expand_function_end (input_filename, lineno, 1);
-
- if (flag_handle_exceptions)
- expand_exception_blocks ();
-
/* This must come after expand_function_end because cleanups might
have declarations (from inline functions) that need to go into
this function's blocks. */
@@ -12147,7 +13013,7 @@ finish_function (lineno, call_poplevel, nested)
my_friendly_abort (122);
poplevel (1, 0, 1);
- /* reset scope for C++: if we were in the scope of a class,
+ /* Reset scope for C++: if we were in the scope of a class,
then when we finish this function, we are not longer so.
This cannot be done until we know for sure that no more
class members will ever be referenced in this function
@@ -12161,79 +13027,115 @@ finish_function (lineno, call_poplevel, nested)
pop_memoized_context (1);
/* Must mark the RESULT_DECL as being in this function. */
- DECL_CONTEXT (DECL_RESULT (fndecl)) = DECL_INITIAL (fndecl);
-
- /* Obey `register' declarations if `setjmp' is called in this fn. */
- if (flag_traditional && current_function_calls_setjmp)
- setjmp_protect (DECL_INITIAL (fndecl));
+ DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
/* Set the BLOCK_SUPERCONTEXT of the outermost function scope to point
to the FUNCTION_DECL node itself. */
BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
- /* So we can tell if jump_optimize sets it to 1. */
- can_reach_end = 0;
+ if (! processing_template_decl)
+ {
+ int saved_flag_keep_inline_functions =
+ flag_keep_inline_functions;
- /* Run the optimizers and output the assembler code for this function. */
- rest_of_compilation (fndecl);
+ /* So we can tell if jump_optimize sets it to 1. */
+ can_reach_end = 0;
- if (DECL_SAVED_INSNS (fndecl) && ! TREE_ASM_WRITTEN (fndecl))
- {
- /* Set DECL_EXTERNAL so that assemble_external will be called as
- necessary. We'll clear it again in finish_file. */
- if (! DECL_EXTERNAL (fndecl))
- DECL_NOT_REALLY_EXTERN (fndecl) = 1;
- DECL_EXTERNAL (fndecl) = 1;
- mark_inline_for_output (fndecl);
- }
+ if (DECL_CONTEXT (fndecl) != NULL_TREE
+ && hack_decl_function_context (fndecl))
+ /* Trick rest_of_compilation into not deferring output of this
+ function, even if it is inline, since the rtl_obstack for
+ this function is the function_obstack of the enclosing
+ function and will be deallocated when the enclosing
+ function is gone. See save_tree_status. */
+ flag_keep_inline_functions = 1;
+
+ /* Run the optimizers and output the assembler code for this
+ function. */
- if (ctype && TREE_ASM_WRITTEN (fndecl))
- note_debug_info_needed (ctype);
+ if (DECL_ARTIFICIAL (fndecl))
+ {
+ /* Do we really *want* to inline this synthesized method? */
- current_function_returns_null |= can_reach_end;
+ int save_fif = flag_inline_functions;
+ flag_inline_functions = 1;
- /* Since we don't normally go through c_expand_return for constructors,
- this normally gets the wrong value.
- Also, named return values have their return codes emitted after
- NOTE_INSN_FUNCTION_END, confusing jump.c. */
- if (DECL_CONSTRUCTOR_P (fndecl)
- || DECL_NAME (DECL_RESULT (fndecl)) != NULL_TREE)
- current_function_returns_null = 0;
+ /* Turn off DECL_INLINE for the moment so function_cannot_inline_p
+ will check our size. */
+ DECL_INLINE (fndecl) = 0;
- if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
- cp_warning ("`noreturn' function `%D' does return", fndecl);
- else if ((warn_return_type || pedantic)
- && current_function_returns_null
- && TYPE_MAIN_VARIANT (TREE_TYPE (fntype)) != void_type_node)
- {
- /* If this function returns non-void and control can drop through,
- complain. */
- cp_pedwarn ("control reaches end of non-void function `%D'", fndecl);
+ rest_of_compilation (fndecl);
+ flag_inline_functions = save_fif;
+ }
+ else
+ rest_of_compilation (fndecl);
+
+ flag_keep_inline_functions = saved_flag_keep_inline_functions;
+
+ if (DECL_SAVED_INSNS (fndecl) && ! TREE_ASM_WRITTEN (fndecl))
+ {
+ /* Set DECL_EXTERNAL so that assemble_external will be called as
+ necessary. We'll clear it again in finish_file. */
+ if (! DECL_EXTERNAL (fndecl))
+ DECL_NOT_REALLY_EXTERN (fndecl) = 1;
+ DECL_EXTERNAL (fndecl) = 1;
+ mark_inline_for_output (fndecl);
+ }
+
+ if (ctype && TREE_ASM_WRITTEN (fndecl))
+ note_debug_info_needed (ctype);
+
+ current_function_returns_null |= can_reach_end;
+
+ /* Since we don't normally go through c_expand_return for constructors,
+ this normally gets the wrong value.
+ Also, named return values have their return codes emitted after
+ NOTE_INSN_FUNCTION_END, confusing jump.c. */
+ if (DECL_CONSTRUCTOR_P (fndecl)
+ || DECL_NAME (DECL_RESULT (fndecl)) != NULL_TREE)
+ current_function_returns_null = 0;
+
+ if (TREE_THIS_VOLATILE (fndecl) && current_function_returns_null)
+ cp_warning ("`noreturn' function `%D' does return", fndecl);
+ else if ((warn_return_type || pedantic)
+ && current_function_returns_null
+ && TREE_CODE (TREE_TYPE (fntype)) != VOID_TYPE)
+ {
+ /* If this function returns non-void and control can drop through,
+ complain. */
+ cp_warning ("control reaches end of non-void function `%D'", fndecl);
+ }
+ /* With just -W, complain only if function returns both with
+ and without a value. */
+ else if (extra_warnings
+ && current_function_returns_value && current_function_returns_null)
+ warning ("this function may return with or without a value");
}
- /* With just -W, complain only if function returns both with
- and without a value. */
- else if (extra_warnings
- && current_function_returns_value && current_function_returns_null)
- warning ("this function may return with or without a value");
+
+ --function_depth;
/* Free all the tree nodes making up this function. */
/* Switch back to allocating nodes permanently
until we start another function. */
+ if (processing_template_decl)
+ {
+ --minimal_parse_mode;
+ DECL_SAVED_TREE (fndecl) = TREE_CHAIN (DECL_SAVED_TREE (fndecl));
+ }
+
if (! nested)
permanent_allocation (1);
- if (flag_cadillac)
- cadillac_finish_function (fndecl);
-
if (DECL_SAVED_INSNS (fndecl) == NULL_RTX)
{
+ tree t;
+
/* Stop pointing to the local nodes about to be freed. */
/* But DECL_INITIAL must remain nonzero so we know this
was an actual function definition. */
DECL_INITIAL (fndecl) = error_mark_node;
- if (! DECL_CONSTRUCTOR_P (fndecl)
- || !TYPE_USES_VIRTUAL_BASECLASSES (TYPE_METHOD_BASETYPE (fntype)))
- DECL_ARGUMENTS (fndecl) = NULL_TREE;
+ for (t = DECL_ARGUMENTS (fndecl); t; t = TREE_CHAIN (t))
+ DECL_RTL (t) = DECL_INCOMING_RTL (t) = NULL_RTX;
}
if (DECL_STATIC_CONSTRUCTOR (fndecl))
@@ -12249,8 +13151,9 @@ finish_function (lineno, call_poplevel, nested)
current_function_decl = NULL_TREE;
}
- named_label_uses = NULL_TREE;
- current_class_decl = NULL_TREE;
+ named_label_uses = NULL;
+ current_class_ptr = NULL_TREE;
+ current_class_ref = NULL_TREE;
}
/* Create the FUNCTION_DECL for a function definition.
@@ -12275,11 +13178,12 @@ finish_function (lineno, call_poplevel, nested)
DO NOT MAKE ANY CHANGES TO THIS CODE WITHOUT MAKING CORRESPONDING
CHANGES TO CODE IN `grokfield'. */
+
tree
-start_method (declspecs, declarator, raises)
- tree declarator, declspecs, raises;
+start_method (declspecs, declarator)
+ tree declarator, declspecs;
{
- tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0, raises,
+ tree fndecl = grokdeclarator (declarator, declspecs, MEMFUNCDEF, 0,
NULL_TREE);
/* Something too ugly to handle. */
@@ -12287,7 +13191,7 @@ start_method (declspecs, declarator, raises)
return NULL_TREE;
/* Pass friends other than inline friend functions back. */
- if (TYPE_MAIN_VARIANT (fndecl) == void_type_node)
+ if (fndecl == void_type_node)
return fndecl;
if (TREE_CODE (fndecl) != FUNCTION_DECL)
@@ -12295,17 +13199,14 @@ start_method (declspecs, declarator, raises)
return NULL_TREE;
if (IS_SIGNATURE (current_class_type))
- {
- IS_DEFAULT_IMPLEMENTATION (fndecl) = 1;
- /* In case we need this info later. */
- HAS_DEFAULT_IMPLEMENTATION (current_class_type) = 1;
- }
+ IS_DEFAULT_IMPLEMENTATION (fndecl) = 1;
if (DECL_IN_AGGR_P (fndecl))
{
if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (fndecl)) != current_class_type)
{
- if (DECL_CONTEXT (fndecl))
+ if (DECL_CONTEXT (fndecl)
+ && TREE_CODE( DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
cp_error ("`%D' is already defined in class %s", fndecl,
TYPE_NAME_STRING (DECL_CONTEXT (fndecl)));
}
@@ -12317,11 +13218,8 @@ start_method (declspecs, declarator, raises)
if (flag_default_inline)
DECL_INLINE (fndecl) = 1;
- if (processing_template_defn)
- {
- SET_DECL_IMPLICIT_INSTANTIATION (fndecl);
- repo_template_used (fndecl);
- }
+ if (processing_template_decl)
+ fndecl = push_template_decl (fndecl);
/* We read in the parameters on the maybepermanent_obstack,
but we won't be getting back to them until after we
@@ -12331,14 +13229,6 @@ start_method (declspecs, declarator, raises)
if (! DECL_FRIEND_P (fndecl))
{
- if (DECL_CHAIN (fndecl) != NULL_TREE)
- {
- /* Need a fresh node here so that we don't get circularity
- when we link these together. If FNDECL was a friend, then
- `pushdecl' does the right thing, which is nothing wrt its
- current value of DECL_CHAIN. */
- fndecl = copy_node (fndecl);
- }
if (TREE_CHAIN (fndecl))
{
fndecl = copy_node (fndecl);
@@ -12385,7 +13275,7 @@ finish_method (decl)
register tree link;
- if (TYPE_MAIN_VARIANT (decl) == void_type_node)
+ if (decl == void_type_node)
return decl;
old_initial = DECL_INITIAL (fndecl);
@@ -12418,13 +13308,12 @@ finish_method (decl)
IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
for (link = current_binding_level->type_shadowed;
link; link = TREE_CHAIN (link))
- IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link);
+ SET_IDENTIFIER_TYPE_VALUE (TREE_PURPOSE (link), TREE_VALUE (link));
GNU_xref_end_scope ((HOST_WIDE_INT) current_binding_level,
(HOST_WIDE_INT) current_binding_level->level_chain,
current_binding_level->parm_flag,
- current_binding_level->keep,
- current_binding_level->tag_transparent);
+ current_binding_level->keep);
poplevel (0, 0, 0);
@@ -12462,7 +13351,7 @@ hack_incomplete_structures (type)
for (list = &current_binding_level->incomplete; *list; )
{
tree decl = TREE_VALUE (*list);
- if (decl && TREE_TYPE (decl) == type
+ if ((decl && TREE_TYPE (decl) == type)
|| (TREE_TYPE (decl)
&& TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
&& TREE_TYPE (TREE_TYPE (decl)) == type))
@@ -12479,7 +13368,7 @@ hack_incomplete_structures (type)
expand_decl (decl);
cleanup = maybe_build_cleanup (decl);
expand_decl_init (decl);
- if (! cp_expand_decl_cleanup (decl, cleanup))
+ if (! expand_decl_cleanup (decl, cleanup))
cp_error ("parser lost in parsing declaration of `%D'",
decl);
}
@@ -12490,32 +13379,21 @@ hack_incomplete_structures (type)
}
}
-/* Nonzero if presently building a cleanup. Needed because
- SAVE_EXPRs are not the right things to use inside of cleanups.
- They are only ever evaluated once, where the cleanup
- might be evaluated several times. In this case, a later evaluation
- of the cleanup might fill in the SAVE_EXPR_RTL, and it will
- not be valid for an earlier cleanup. */
-
-int building_cleanup;
-
/* If DECL is of a type which needs a cleanup, build that cleanup here.
- We don't build cleanups if just going for syntax checking, since
- fixup_cleanups does not know how to not handle them.
+ See build_delete for information about AUTO_DELETE.
Don't build these on the momentary obstack; they must live
the life of the binding contour. */
-tree
-maybe_build_cleanup (decl)
- tree decl;
+
+static tree
+maybe_build_cleanup_1 (decl, auto_delete)
+ tree decl, auto_delete;
{
tree type = TREE_TYPE (decl);
if (TYPE_NEEDS_DESTRUCTOR (type))
{
int temp = 0, flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
tree rval;
- int old_building_cleanup = building_cleanup;
- building_cleanup = 1;
if (TREE_CODE (decl) != PARM_DECL)
temp = suspend_momentary ();
@@ -12533,22 +13411,40 @@ maybe_build_cleanup (decl)
|| flag_expensive_optimizations)
flags |= LOOKUP_NONVIRTUAL;
- rval = build_delete (TREE_TYPE (rval), rval, integer_two_node, flags, 0);
+ rval = build_delete (TREE_TYPE (rval), rval, auto_delete, flags, 0);
if (TYPE_USES_VIRTUAL_BASECLASSES (type)
&& ! TYPE_HAS_DESTRUCTOR (type))
- rval = build_compound_expr (tree_cons (NULL_TREE, rval,
- build_tree_list (NULL_TREE, build_vbase_delete (type, decl))));
+ rval = build_compound_expr (expr_tree_cons (NULL_TREE, rval,
+ build_expr_list (NULL_TREE, build_vbase_delete (type, decl))));
if (TREE_CODE (decl) != PARM_DECL)
resume_momentary (temp);
- building_cleanup = old_building_cleanup;
-
return rval;
}
return 0;
}
+
+/* If DECL is of a type which needs a cleanup, build that cleanup
+ here. The cleanup does free the storage with a call to delete. */
+
+tree
+maybe_build_cleanup_and_delete (decl)
+ tree decl;
+{
+ return maybe_build_cleanup_1 (decl, integer_three_node);
+}
+
+/* If DECL is of a type which needs a cleanup, build that cleanup
+ here. The cleanup does not free the storage with a call a delete. */
+
+tree
+maybe_build_cleanup (decl)
+ tree decl;
+{
+ return maybe_build_cleanup_1 (decl, integer_two_node);
+}
/* Expand a C++ expression at the statement level.
This is needed to ferret out nodes which have UNKNOWN_TYPE.
@@ -12556,13 +13452,21 @@ maybe_build_cleanup (decl)
expressions are combined with other, type-providing, expressions,
leaving only orphan expressions, such as:
- &class::bar; / / takes its address, but does nothing with it.
+ &class::bar; / / takes its address, but does nothing with it. */
- */
void
cplus_expand_expr_stmt (exp)
tree exp;
{
+ if (processing_template_decl)
+ {
+ add_tree (build_min_nt (EXPR_STMT, exp));
+ return;
+ }
+
+ /* Arrange for all temps to disappear. */
+ expand_start_target_temps ();
+
if (TREE_TYPE (exp) == unknown_type_node)
{
if (TREE_CODE (exp) == ADDR_EXPR || TREE_CODE (exp) == TREE_LIST)
@@ -12572,8 +13476,6 @@ cplus_expand_expr_stmt (exp)
}
else
{
- int remove_implicit_immediately = 0;
-
if (TREE_CODE (exp) == FUNCTION_DECL)
{
cp_warning ("reference, not call, to function `%D'", exp);
@@ -12585,12 +13487,22 @@ cplus_expand_expr_stmt (exp)
libg++ to miscompile, and tString to core dump. */
exp = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (exp), exp);
#endif
- expand_expr_stmt (break_out_cleanups (exp));
+
+ /* Strip unused implicit INDIRECT_REFs of references. */
+ if (TREE_CODE (exp) == INDIRECT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
+ exp = TREE_OPERAND (exp, 0);
+
+ /* If we don't do this, we end up down inside expand_expr
+ trying to do TYPE_MODE on the ERROR_MARK, and really
+ go outside the bounds of the type. */
+ if (exp != error_mark_node)
+ expand_expr_stmt (break_out_cleanups (exp));
}
/* Clean up any pending cleanups. This happens when a function call
returns a cleanup-needing value that nobody uses. */
- expand_cleanups_to (NULL_TREE);
+ expand_end_target_temps ();
}
/* When a stmt has been parsed, this function is called.
@@ -12618,9 +13530,6 @@ finish_stmt ()
check_base_init (current_class_type);
}
current_function_assigns_this = 1;
-
- if (flag_cadillac)
- cadillac_finish_stmt ();
}
/* Change a static member function definition into a FUNCTION_TYPE, instead
@@ -12679,18 +13588,20 @@ struct cp_function
tree shadowed_labels;
tree ctor_label;
tree dtor_label;
- tree protect_list;
+ rtx last_dtor_insn;
+ rtx last_parm_cleanup_insn;
tree base_init_list;
tree member_init_list;
tree base_init_expr;
- tree class_decl;
- tree C_C_D;
+ tree current_class_ptr;
+ tree current_class_ref;
rtx result_rtx;
struct cp_function *next;
struct binding_level *binding_level;
+ int static_labelno;
};
-struct cp_function *cp_function_chain;
+static struct cp_function *cp_function_chain;
extern int temp_name_counter;
@@ -12717,17 +13628,19 @@ push_cp_function_context (context)
p->binding_level = current_binding_level;
p->ctor_label = ctor_label;
p->dtor_label = dtor_label;
+ p->last_dtor_insn = last_dtor_insn;
+ p->last_parm_cleanup_insn = last_parm_cleanup_insn;
p->assigns_this = current_function_assigns_this;
p->just_assigned_this = current_function_just_assigned_this;
p->parms_stored = current_function_parms_stored;
p->result_rtx = original_result_rtx;
p->base_init_expr = base_init_expr;
- p->protect_list = protect_list;
p->temp_name_counter = temp_name_counter;
p->base_init_list = current_base_init_list;
p->member_init_list = current_member_init_list;
- p->class_decl = current_class_decl;
- p->C_C_D = C_C_D;
+ p->current_class_ptr = current_class_ptr;
+ p->current_class_ref = current_class_ref;
+ p->static_labelno = static_labelno;
}
/* Restore the variables used during compilation of a C++ function. */
@@ -12745,17 +13658,6 @@ pop_cp_function_context (context)
SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)),
TREE_VALUE (link));
-#if 0
- if (DECL_SAVED_INSNS (current_function_decl) == 0)
- {
- /* Stop pointing to the local nodes about to be freed. */
- /* But DECL_INITIAL must remain nonzero so we know this
- was an actual function definition. */
- DECL_INITIAL (current_function_decl) = error_mark_node;
- DECL_ARGUMENTS (current_function_decl) = 0;
- }
-#endif
-
pop_function_context_from (context);
cp_function_chain = p->next;
@@ -12768,7 +13670,8 @@ pop_cp_function_context (context)
current_binding_level = p->binding_level;
ctor_label = p->ctor_label;
dtor_label = p->dtor_label;
- protect_list = p->protect_list;
+ last_dtor_insn = p->last_dtor_insn;
+ last_parm_cleanup_insn = p->last_parm_cleanup_insn;
current_function_assigns_this = p->assigns_this;
current_function_just_assigned_this = p->just_assigned_this;
current_function_parms_stored = p->parms_stored;
@@ -12777,102 +13680,15 @@ pop_cp_function_context (context)
temp_name_counter = p->temp_name_counter;
current_base_init_list = p->base_init_list;
current_member_init_list = p->member_init_list;
- current_class_decl = p->class_decl;
- C_C_D = p->C_C_D;
+ current_class_ptr = p->current_class_ptr;
+ current_class_ref = p->current_class_ref;
+ static_labelno = p->static_labelno;
free (p);
}
-/* FSF LOCAL dje prefix attributes */
-/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
- lists. SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
-
- The head of the declspec list is stored in DECLSPECS.
- The head of the attribute list is stored in PREFIX_ATTRIBUTES.
-
- Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
- the list elements. We drop the containing TREE_LIST nodes and link the
- resulting attributes together the way decl_attributes expects them. */
-
-void
-split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
- tree specs_attrs;
- tree *declspecs, *prefix_attributes;
-{
- tree t, s, a, next, specs, attrs;
-
- /* This can happen in c++ (eg: decl: typespec initdecls ';'). */
- if (specs_attrs != NULL_TREE
- && TREE_CODE (specs_attrs) != TREE_LIST)
- {
- *declspecs = specs_attrs;
- *prefix_attributes = NULL_TREE;
- return;
- }
-
- /* Remember to keep the lists in the same order, element-wise. */
-
- specs = s = NULL_TREE;
- attrs = a = NULL_TREE;
- for (t = specs_attrs; t; t = next)
- {
- next = TREE_CHAIN (t);
- /* Declspecs have a non-NULL TREE_VALUE. */
- if (TREE_VALUE (t) != NULL_TREE)
- {
- if (specs == NULL_TREE)
- specs = s = t;
- else
- {
- TREE_CHAIN (s) = t;
- s = t;
- }
- }
- else
- {
- if (attrs == NULL_TREE)
- attrs = a = TREE_PURPOSE (t);
- else
- {
- TREE_CHAIN (a) = TREE_PURPOSE (t);
- a = TREE_PURPOSE (t);
- }
- }
- }
-
- /* Terminate the lists. */
- if (s != NULL_TREE)
- TREE_CHAIN (s) = NULL_TREE;
- if (a != NULL_TREE)
- TREE_CHAIN (a) = NULL_TREE;
-
- /* All done. */
- *declspecs = specs;
- *prefix_attributes = attrs;
-}
-
-/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes.
- This function is used by the parser when a rule will accept attributes
- in a particular position, but we don't want to support that just yet.
-
- A warning is issued for every ignored attribute. */
-
-tree
-strip_attrs (specs_attrs)
- tree specs_attrs;
+int
+in_function_p ()
{
- tree specs, attrs;
-
- split_specs_attrs (specs_attrs, &specs, &attrs);
-
- while (attrs)
- {
- warning ("`%s' attribute ignored",
- IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
- attrs = TREE_CHAIN (attrs);
- }
-
- return specs;
+ return function_depth != 0;
}
-/* END FSF LOCAL */
-
diff --git a/contrib/gcc/cp/decl.h b/contrib/gcc/cp/decl.h
index 0824c13..f55dca5 100644
--- a/contrib/gcc/cp/decl.h
+++ b/contrib/gcc/cp/decl.h
@@ -31,7 +31,7 @@ enum decl_context
};
/* We need this in here to get the decl_context definition. */
-extern tree grokdeclarator PROTO((tree, tree, enum decl_context, int, tree, tree));
+extern tree grokdeclarator PROTO((tree, tree, enum decl_context, int, tree));
/* C++: Keep these around to reduce calls to `get_identifier'.
Identifiers for `this' in member functions and the auto-delete
diff --git a/contrib/gcc/cp/decl2.c b/contrib/gcc/cp/decl2.c
index 9b7f88e..c87c607 100644
--- a/contrib/gcc/cp/decl2.c
+++ b/contrib/gcc/cp/decl2.c
@@ -1,5 +1,5 @@
/* Process declarations and variables for C compiler.
- Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1988, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -28,7 +28,7 @@ Boston, MA 02111-1307, USA. */
line numbers. For example, the CONST_DECLs for enum values. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "flags.h"
@@ -36,11 +36,33 @@ Boston, MA 02111-1307, USA. */
#include "decl.h"
#include "lex.h"
#include "output.h"
+#include "except.h"
+#include "expr.h"
#include "defaults.h"
+#include "toplev.h"
+#include "dwarf2out.h"
+#include "dwarfout.h"
+
+#if USE_CPPLIB
+#include "cpplib.h"
+extern cpp_reader parse_in;
+extern cpp_options parse_options;
+static int cpp_initialized;
+#endif
+
+static tree get_sentry PROTO((tree));
+static void mark_vtable_entries PROTO((tree));
+static void grok_function_init PROTO((tree, tree));
+static int finish_vtable_vardecl PROTO((tree, tree));
+static int prune_vtable_vardecl PROTO((tree, tree));
+static void finish_sigtable_vardecl PROTO((tree, tree));
+static int is_namespace_ancestor PROTO((tree, tree));
+static void add_using_namespace PROTO((tree, tree, int));
+static tree ambiguous_decl PROTO((tree, tree, tree,int));
+static tree build_anon_union_vars PROTO((tree, tree*, int, int));
+static void check_decl_namespace PROTO((void));
-extern tree get_file_function_name ();
-extern tree cleanups_this_call;
-static void grok_function_init ();
+extern int current_class_depth;
/* A list of virtual function tables we must make sure to write out. */
tree pending_vtables;
@@ -51,7 +73,7 @@ tree pending_vtables;
tree pending_statics;
/* A list of functions which were declared inline, but which we
- may need to emit outline anyway. */
+ may need to emit outline anyway. */
static tree saved_inlines;
/* Used to help generate temporary names which are unique within
@@ -67,9 +89,23 @@ static int global_temp_name_counter;
extern int spew_debug;
+/* Nonzero if we're done parsing and into end-of-file activities. */
+
+int at_eof;
+
/* Functions called along with real static constructors and destructors. */
tree static_ctors, static_dtors;
+
+/* The current open namespace, and ::. */
+
+tree current_namespace;
+tree global_namespace;
+
+/* The stack for namespaces of current declarations. */
+
+static tree decl_namespace_list;
+
/* C (and C++) language-specific option variables. */
@@ -99,7 +135,8 @@ int flag_no_builtin;
int flag_no_nonansi_builtin;
-/* Nonzero means do some things the same way PCC does. */
+/* Nonzero means do some things the same way PCC does. Only provided so
+ the compiler will link. */
int flag_traditional;
@@ -122,7 +159,7 @@ int flag_ansi;
int flag_implement_inlines = 1;
/* Nonzero means do emit exported implementations of templates, instead of
- multiple static copies in each file that needs a definition. */
+ multiple static copies in each file that needs a definition. */
int flag_external_templates;
@@ -140,20 +177,32 @@ int flag_implicit_templates = 1;
int warn_implicit = 1;
+/* Nonzero means warn about usage of long long when `-pedantic'. */
+
+int warn_long_long = 1;
+
/* Nonzero means warn when all ctors or dtors are private, and the class
has no friends. */
int warn_ctor_dtor_privacy = 1;
-/* True if we want to implement vtbvales using "thunks".
- The default is off now, but will be on later. */
+/* True if we want to implement vtables using "thunks".
+ The default is off. */
-int flag_vtable_thunks;
+#ifndef DEFAULT_VTABLE_THUNKS
+#define DEFAULT_VTABLE_THUNKS 0
+#endif
+int flag_vtable_thunks = DEFAULT_VTABLE_THUNKS;
/* True if we want to deal with repository information. */
int flag_use_repository;
+/* Nonzero if we want to issue diagnostics that the standard says are not
+ required. */
+
+int flag_optional_diags = 1;
+
/* Nonzero means give string constants the type `const char *'
to get extra warnings from them. These warnings will be too numerous
to be useful, except in thoroughly ANSIfied programs. */
@@ -165,24 +214,10 @@ int warn_write_strings;
int warn_cast_qual;
-/* Nonzero means warn that dbx info for template class methods isn't fully
- supported yet. */
-
-int warn_template_debugging;
-
-/* Warn about traditional constructs whose meanings changed in ANSI C. */
-
-int warn_traditional;
-
/* Nonzero means warn about sizeof(function) or addition/subtraction
of function pointers. */
-int warn_pointer_arith;
-
-/* Nonzero means warn for non-prototype function decls
- or non-prototyped defs without previous prototype. */
-
-int warn_strict_prototypes;
+int warn_pointer_arith = 1;
/* Nonzero means warn for any function def without prototype decl. */
@@ -197,7 +232,11 @@ int warn_redundant_decls;
int warn_missing_braces;
-/* Warn about *printf or *scanf format/argument anomalies. */
+/* Warn about comparison of signed and unsigned values. */
+
+int warn_sign_compare;
+
+/* Warn about *printf or *scanf format/argument anomalies. */
int warn_format;
@@ -219,7 +258,7 @@ int warn_parentheses;
int warn_overloaded_virtual;
/* Non-zero means warn when declaring a class that has a non virtual
- destructor, when it really ought to have a virtual one. */
+ destructor, when it really ought to have a virtual one. */
int warn_nonvdtor;
/* Non-zero means warn when a function is declared extern and later inline. */
@@ -231,8 +270,32 @@ int warn_reorder;
/* Non-zero means warn when synthesis behavior differs from Cfront's. */
int warn_synth;
-/* Nonzero means `$' can be in an identifier.
- See cccp.c for reasons why this breaks some obscure ANSI C programs. */
+/* Non-zero means warn when we convert a pointer to member function
+ into a pointer to (void or function). */
+int warn_pmf2ptr = 1;
+
+/* Nonzero means warn about violation of some Effective C++ style rules. */
+
+int warn_ecpp;
+
+/* Nonzero means warn where overload resolution chooses a promotion from
+ unsigned to signed over a conversion to an unsigned of the same size. */
+
+int warn_sign_promo;
+
+/* Nonzero means warn when an old-style cast is used. */
+
+int warn_old_style_cast;
+
+/* Warn about #pragma directives that are not recognised. */
+
+int warn_unknown_pragmas; /* Tri state variable. */
+
+/* Nonzero means warn about use of multicharacter literals. */
+
+int warn_multichar = 1;
+
+/* Nonzero means `$' can be in an identifier. */
#ifndef DOLLARS_IN_IDENTIFIERS
#define DOLLARS_IN_IDENTIFIERS 1
@@ -284,15 +347,12 @@ int flag_memoize_lookups; int flag_save_memoized_contexts;
int write_virtuals;
-/* Nonzero means we should attempt to elide constructors when possible. */
+/* Nonzero means we should attempt to elide constructors when possible.
+ FIXME: This flag is obsolete, and should be torn out along with the
+ old overloading code. */
int flag_elide_constructors;
-/* Nonzero means recognize and handle exception handling constructs.
- Use ansi syntax and semantics. WORK IN PROGRESS! */
-
-int flag_handle_exceptions;
-
/* Nonzero means recognize and handle signature language constructs. */
int flag_handle_signatures;
@@ -307,17 +367,9 @@ int flag_default_inline = 1;
0 means enums can convert to ints, but not vice-versa. */
int flag_int_enum_equivalence;
-/* Controls whether compiler is operating under LUCID's Cadillac
- system. 1 means yes, 0 means no. */
-int flag_cadillac;
-
-/* Controls whether compiler generates code to build objects
- that can be collected when they become garbage. */
-int flag_gc;
-
/* Controls whether compiler generates 'type descriptor' that give
run-time type information. */
-int flag_rtti;
+int flag_rtti = 1;
/* Nonzero if we wish to output cross-referencing information
for the GNU class browser. */
@@ -336,7 +388,7 @@ extern int flag_gnu_xref;
int flag_assume_nonnull_objects = 1;
/* Nonzero if we want to support huge (> 2^(sizeof(short)*8-1) bytes)
- objects. */
+ objects. */
int flag_huge_objects;
@@ -369,6 +421,39 @@ int flag_check_new;
int flag_new_for_scope = 1;
+/* Nonzero if we want to emit defined symbols with common-like linkage as
+ weak symbols where possible, in order to conform to C++ semantics.
+ Otherwise, emit them as local symbols. */
+
+int flag_weak = 1;
+
+/* Nonzero to enable experimental ABI changes. */
+
+int flag_new_abi;
+
+/* Nonzero to not ignore namespace std. */
+
+int flag_honor_std;
+
+/* Maximum template instantiation depth. Must be at least 17 for ANSI
+ compliance. */
+
+int max_tinst_depth = 17;
+
+/* The name-mangling scheme to use. Must be 1 or greater to support
+ template functions with identical types, but different template
+ arguments. */
+int name_mangling_version = 2;
+
+/* Nonzero means that guiding declarations are allowed. */
+int flag_guiding_decls;
+
+/* Nonzero if squashed mangling is to be performed.
+ This uses the B and K codes to reference previously seen class types
+ and class qualifiers. */
+int flag_do_squangling;
+
+
/* Table of language-dependent -f options.
STRING is the option name. VARIABLE is the address of the variable.
ON_VALUE is the value to store in VARIABLE
@@ -384,6 +469,7 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
{"short-enums", &flag_short_enums, 1},
{"short-double", &flag_short_double, 1},
{"cond-mismatch", &flag_cond_mismatch, 1},
+ {"squangle", &flag_do_squangling, 1},
{"asm", &flag_no_asm, 0},
{"builtin", &flag_no_builtin, 0},
{"ident", &flag_no_ident, 0},
@@ -394,12 +480,12 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
{"all-virtual", &flag_all_virtual, 1},
{"memoize-lookups", &flag_memoize_lookups, 1},
{"elide-constructors", &flag_elide_constructors, 1},
- {"handle-exceptions", &flag_handle_exceptions, 1},
+ {"handle-exceptions", &flag_exceptions, 1},
{"handle-signatures", &flag_handle_signatures, 1},
{"default-inline", &flag_default_inline, 1},
{"dollars-in-identifiers", &dollars_in_ident, 1},
{"enum-int-equiv", &flag_int_enum_equivalence, 1},
- {"gc", &flag_gc, 1},
+ {"honor-std", &flag_honor_std, 1},
{"rtti", &flag_rtti, 1},
{"xref", &flag_gnu_xref, 1},
{"nonnull-objects", &flag_assume_nonnull_objects, 1},
@@ -409,26 +495,44 @@ static struct { char *string; int *variable; int on_value;} lang_f_options[] =
{"huge-objects", &flag_huge_objects, 1},
{"conserve-space", &flag_conserve_space, 1},
{"vtable-thunks", &flag_vtable_thunks, 1},
- {"short-temps", &flag_short_temps, 1},
{"access-control", &flag_access_control, 1},
{"nonansi-builtins", &flag_no_nonansi_builtin, 0},
{"gnu-keywords", &flag_no_gnu_keywords, 0},
{"operator-names", &flag_operator_names, 1},
+ {"optional-diags", &flag_optional_diags, 1},
{"check-new", &flag_check_new, 1},
{"repo", &flag_use_repository, 1},
- {"for-scope", &flag_new_for_scope, 2}
+ {"for-scope", &flag_new_for_scope, 2},
+ {"weak", &flag_weak, 1}
};
/* Decode the string P as a language-specific option.
- Return 1 if it is recognized (and handle it);
- return 0 if not recognized. */
+ Return the number of strings consumed for a valid option.
+ Otherwise return 0. */
int
-lang_decode_option (p)
- char *p;
+lang_decode_option (argc, argv)
+ int argc;
+ char **argv;
+
{
+ int strings_processed;
+ char *p = argv[0];
+#if USE_CPPLIB
+ if (! cpp_initialized)
+ {
+ cpp_reader_init (&parse_in);
+ parse_in.data = &parse_options;
+ cpp_options_init (&parse_options);
+ cpp_initialized = 1;
+ }
+ strings_processed = cpp_handle_option (&parse_in, argc, argv);
+#else
+ strings_processed = 0;
+#endif /* ! USE_CPPLIB */
+
if (!strcmp (p, "-ftraditional") || !strcmp (p, "-traditional"))
- flag_traditional = 1, dollars_in_ident = 1, flag_writable_strings = 1,
+ flag_writable_strings = 1,
flag_this_is_variable = 1, flag_new_for_scope = 0;
/* The +e options are for cfront compatibility. They come in as
`-+eN', to kludge around gcc.c's argument handling. */
@@ -451,68 +555,107 @@ lang_decode_option (p)
/* Some kind of -f option.
P's value is the option sans `-f'.
Search for it in the table of options. */
- int found = 0, j;
+ int found = 0;
+ size_t j;
p += 2;
/* Try special -f options. */
+ if (!strcmp (p, "handle-exceptions")
+ || !strcmp (p, "no-handle-exceptions"))
+ warning ("-fhandle-exceptions has been renamed to -fexceptions (and is now on by default)");
+
if (!strcmp (p, "save-memoized"))
{
flag_memoize_lookups = 1;
flag_save_memoized_contexts = 1;
found = 1;
}
- if (!strcmp (p, "no-save-memoized"))
+ else if (!strcmp (p, "no-save-memoized"))
{
flag_memoize_lookups = 0;
flag_save_memoized_contexts = 0;
found = 1;
}
- else if (! strncmp (p, "cadillac", 8))
+ else if (! strcmp (p, "alt-external-templates"))
{
- flag_cadillac = atoi (p+9);
+ flag_external_templates = 1;
+ flag_alt_external_templates = 1;
found = 1;
}
- else if (! strncmp (p, "no-cadillac", 11))
+ else if (! strcmp (p, "no-alt-external-templates"))
{
- flag_cadillac = 0;
+ flag_alt_external_templates = 0;
found = 1;
}
- else if (! strcmp (p, "gc"))
+ else if (!strcmp (p, "repo"))
{
- flag_gc = 1;
- /* This must come along for the ride. */
- flag_rtti = 1;
+ flag_use_repository = 1;
+ flag_implicit_templates = 0;
found = 1;
}
- else if (! strcmp (p, "no-gc"))
+ else if (!strcmp (p, "guiding-decls"))
{
- flag_gc = 0;
- /* This must come along for the ride. */
- flag_rtti = 0;
+ flag_guiding_decls = 1;
+ name_mangling_version = 0;
found = 1;
}
- else if (! strcmp (p, "alt-external-templates"))
+ else if (!strcmp (p, "no-guiding-decls"))
{
- flag_external_templates = 1;
- flag_alt_external_templates = 1;
+ flag_guiding_decls = 0;
found = 1;
}
- else if (! strcmp (p, "no-alt-external-templates"))
+ else if (!strcmp (p, "ansi-overloading"))
+ found = 1;
+ else if (!strcmp (p, "no-ansi-overloading"))
{
- flag_alt_external_templates = 0;
+ error ("-fno-ansi-overloading is no longer supported");
found = 1;
}
- else if (!strcmp (p, "ansi-overloading"))
+ else if (!strcmp (p, "new-abi"))
{
- warning ("-fansi-overloading is no longer meaningful");
- found = 1;
+ flag_new_abi = 1;
+ flag_do_squangling = 1;
+ flag_honor_std = 1;
+ flag_vtable_thunks = 1;
}
- else if (!strcmp (p, "repo"))
+ else if (!strcmp (p, "no-new-abi"))
{
- flag_use_repository = 1;
- flag_implicit_templates = 0;
- found = 1;
+ flag_new_abi = 0;
+ flag_do_squangling = 0;
+ flag_honor_std = 0;
+ }
+ else if (!strncmp (p, "template-depth-", 15))
+ {
+ char *endp = p + 15;
+ while (*endp)
+ {
+ if (*endp >= '0' && *endp <= '9')
+ endp++;
+ else
+ {
+ error ("Invalid option `%s'", p - 2);
+ goto template_depth_lose;
+ }
+ }
+ max_tinst_depth = atoi (p + 15);
+ template_depth_lose: ;
+ }
+ else if (!strncmp (p, "name-mangling-version-", 22))
+ {
+ char *endp = p + 22;
+ while (*endp)
+ {
+ if (*endp >= '0' && *endp <= '9')
+ endp++;
+ else
+ {
+ error ("Invalid option `%s'", p - 2);
+ goto mangling_version_lose;
+ }
+ }
+ name_mangling_version = atoi (p + 22);
+ mangling_version_lose: ;
}
else for (j = 0;
!found && j < sizeof (lang_f_options) / sizeof (lang_f_options[0]);
@@ -546,6 +689,8 @@ lang_decode_option (p)
if (!strcmp (p, "implicit"))
warn_implicit = setting;
+ else if (!strcmp (p, "long-long"))
+ warn_long_long = setting;
else if (!strcmp (p, "return-type"))
warn_return_type = setting;
else if (!strcmp (p, "ctor-dtor-privacy"))
@@ -554,20 +699,18 @@ lang_decode_option (p)
warn_write_strings = setting;
else if (!strcmp (p, "cast-qual"))
warn_cast_qual = setting;
- else if (!strcmp (p, "traditional"))
- warn_traditional = setting;
else if (!strcmp (p, "char-subscripts"))
warn_char_subscripts = setting;
else if (!strcmp (p, "pointer-arith"))
warn_pointer_arith = setting;
- else if (!strcmp (p, "strict-prototypes"))
- warn_strict_prototypes = setting;
else if (!strcmp (p, "missing-prototypes"))
warn_missing_prototypes = setting;
else if (!strcmp (p, "redundant-decls"))
warn_redundant_decls = setting;
else if (!strcmp (p, "missing-braces"))
warn_missing_braces = setting;
+ else if (!strcmp (p, "sign-compare"))
+ warn_sign_compare = setting;
else if (!strcmp (p, "format"))
warn_format = setting;
else if (!strcmp (p, "conversion"))
@@ -582,6 +725,22 @@ lang_decode_option (p)
warn_reorder = setting;
else if (!strcmp (p, "synth"))
warn_synth = setting;
+ else if (!strcmp (p, "pmf-conversions"))
+ warn_pmf2ptr = setting;
+ else if (!strcmp (p, "effc++"))
+ warn_ecpp = setting;
+ else if (!strcmp (p, "sign-promo"))
+ warn_sign_promo = setting;
+ else if (!strcmp (p, "old-style-cast"))
+ warn_old_style_cast = setting;
+ else if (!strcmp (p, "overloaded-virtual"))
+ warn_overloaded_virtual = setting;
+ else if (!strcmp (p, "multichar"))
+ warn_multichar = setting;
+ else if (!strcmp (p, "unknown-pragmas"))
+ /* Set to greater than 1, so that even unknown pragmas in
+ system headers will be warned about. */
+ warn_unknown_pragmas = setting * 2;
else if (!strcmp (p, "comment"))
; /* cpp handles this one. */
else if (!strcmp (p, "comments"))
@@ -592,7 +751,6 @@ lang_decode_option (p)
; /* cpp handles this one. */
else if (!strcmp (p, "all"))
{
- extra_warnings = setting;
warn_return_type = setting;
warn_unused = setting;
warn_implicit = setting;
@@ -601,23 +759,25 @@ lang_decode_option (p)
warn_format = setting;
warn_parentheses = setting;
warn_missing_braces = setting;
+ warn_sign_compare = setting;
warn_extern_inline = setting;
warn_nonvdtor = setting;
+ warn_multichar = setting;
/* We save the value of warn_uninitialized, since if they put
-Wuninitialized on the command line, we need to generate a
warning about not using it without also specifying -O. */
if (warn_uninitialized != 1)
warn_uninitialized = (setting ? 2 : 0);
- warn_template_debugging = setting;
warn_reorder = setting;
+ warn_sign_promo = setting;
+ /* Only warn about unknown pragmas that are not in system
+ headers. */
+ warn_unknown_pragmas = 1;
}
-
- else if (!strcmp (p, "overloaded-virtual"))
- warn_overloaded_virtual = setting;
- else return 0;
+ else return strings_processed;
}
else if (!strcmp (p, "-ansi"))
- dollars_in_ident = 0, flag_no_nonansi_builtin = 1, flag_ansi = 1,
+ flag_no_nonansi_builtin = 1, flag_ansi = 1,
flag_no_gnu_keywords = 1, flag_operator_names = 1;
#ifdef SPEW_DEBUG
/* Undocumented, only ever used when you're invoking cc1plus by hand, since
@@ -627,7 +787,7 @@ lang_decode_option (p)
spew_debug = 1;
#endif
else
- return 0;
+ return strings_processed;
return 1;
}
@@ -635,6 +795,7 @@ lang_decode_option (p)
/* Incorporate `const' and `volatile' qualifiers for member functions.
FUNCTION is a TYPE_DECL or a FUNCTION_DECL.
QUALS is a list of qualifiers. */
+
tree
grok_method_quals (ctype, function, quals)
tree ctype, function, quals;
@@ -682,28 +843,10 @@ grok_method_quals (ctype, function, quals)
return ctype;
}
-#if 0 /* Not used. */
-/* This routine replaces cryptic DECL_NAMEs with readable DECL_NAMEs.
- It leaves DECL_ASSEMBLER_NAMEs with the correct value. */
-/* This does not yet work with user defined conversion operators
- It should. */
-static void
-substitute_nice_name (decl)
- tree decl;
-{
- if (DECL_NAME (decl) && TREE_CODE (DECL_NAME (decl)) == IDENTIFIER_NODE)
- {
- char *n = decl_as_string (DECL_NAME (decl), 1);
- if (n[strlen (n) - 1] == ' ')
- n[strlen (n) - 1] = 0;
- DECL_NAME (decl) = get_identifier (n);
- }
-}
-#endif
-
/* Warn when -fexternal-templates is used and #pragma
interface/implementation is not used all the times it should be,
inform the user. */
+
void
warn_if_unknown_interface (decl)
tree decl;
@@ -734,6 +877,7 @@ warn_if_unknown_interface (decl)
}
/* A subroutine of the parser, to handle a component list. */
+
tree
grok_x_components (specs, components)
tree specs, components;
@@ -758,8 +902,7 @@ grok_x_components (specs, components)
{
case VAR_DECL:
/* Static anonymous unions come out as VAR_DECLs. */
- if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TREE_TYPE (t))))
+ if (ANON_UNION_TYPE_P (TREE_TYPE (t)))
return t;
/* We return SPECS here, because in the parser it was ending
@@ -772,31 +915,37 @@ grok_x_components (specs, components)
/* This code may be needed for UNION_TYPEs as
well. */
tcode = record_type_node;
- if (CLASSTYPE_DECLARED_CLASS(t))
+ if (CLASSTYPE_DECLARED_CLASS (t))
tcode = class_type_node;
- else if (IS_SIGNATURE(t))
+ else if (IS_SIGNATURE (t))
tcode = signature_type_node;
-
- t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0);
- if (TYPE_CONTEXT(t))
- CLASSTYPE_NO_GLOBALIZE(t) = 1;
+
+ if (CLASSTYPE_IS_TEMPLATE (t))
+ /* In this case, the TYPE_IDENTIFIER will be something
+ like S<T>, rather than S, so to get the correct name we
+ look at the template. */
+ x = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
+ else
+ x = TYPE_IDENTIFIER (t);
+
+ t = xref_tag (tcode, x, NULL_TREE, 0);
return NULL_TREE;
break;
case UNION_TYPE:
case ENUMERAL_TYPE:
- if (TREE_CODE(t) == UNION_TYPE)
+ if (TREE_CODE (t) == UNION_TYPE)
tcode = union_type_node;
else
tcode = enum_type_node;
t = xref_tag (tcode, TYPE_IDENTIFIER (t), NULL_TREE, 0);
- if (TREE_CODE(t) == UNION_TYPE && TYPE_CONTEXT(t))
- CLASSTYPE_NO_GLOBALIZE(t) = 1;
- if (TREE_CODE (t) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t)))
+ if (ANON_UNION_TYPE_P (t))
{
+ /* See also shadow_tag. */
+
struct pending_inline **p;
+ tree *q;
x = build_lang_field_decl (FIELD_DECL, NULL_TREE, t);
/* Wipe out memory of synthesized methods */
@@ -808,13 +957,24 @@ grok_x_components (specs, components)
TYPE_HAS_ASSIGNMENT (t) = 0;
TYPE_HAS_CONST_ASSIGN_REF (t) = 0;
+ q = &TYPE_METHODS (t);
+ while (*q)
+ {
+ if (DECL_ARTIFICIAL (*q))
+ *q = TREE_CHAIN (*q);
+ else
+ q = &TREE_CHAIN (*q);
+ }
+ if (TYPE_METHODS (t))
+ error ("an anonymous union cannot have function members");
+
p = &pending_inlines;
for (; *p; *p = (*p)->next)
if (DECL_CONTEXT ((*p)->fndecl) != t)
break;
}
else if (TREE_CODE (t) == ENUMERAL_TYPE)
- x = grok_enum_decls (t, NULL_TREE);
+ x = grok_enum_decls (NULL_TREE);
else
x = NULL_TREE;
return x;
@@ -827,13 +987,63 @@ grok_x_components (specs, components)
}
}
else
- {
- t = TREE_TYPE (components);
- if (TREE_CODE (t) == ENUMERAL_TYPE && TREE_NONLOCAL_FLAG (t))
- return grok_enum_decls (t, components);
- else
- return components;
- }
+ /* There may or may not be any enum decls to grok, but
+ grok_enum_decls will just return components, if there aren't
+ any. We used to try to figure out whether or not there were
+ any enum decls based on the type of components, but that's too
+ hard; it might be something like `enum { a } *p;'. */
+ return grok_enum_decls (components);
+}
+
+/* Constructors for types with virtual baseclasses need an "in-charge" flag
+ saying whether this constructor is responsible for initialization of
+ virtual baseclasses or not. All destructors also need this "in-charge"
+ flag, which additionally determines whether or not the destructor should
+ free the memory for the object.
+
+ This function adds the "in-charge" flag to member function FN if
+ appropriate. It is called from grokclassfn and tsubst.
+ FN must be either a constructor or destructor. */
+
+void
+maybe_retrofit_in_chrg (fn)
+ tree fn;
+{
+ tree basetype, arg_types, parms, parm, fntype;
+
+ if (DECL_CONSTRUCTOR_P (fn)
+ && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CLASS_CONTEXT (fn))
+ && ! DECL_CONSTRUCTOR_FOR_VBASE_P (fn))
+ /* OK */;
+ else if (! DECL_CONSTRUCTOR_P (fn)
+ && TREE_CHAIN (DECL_ARGUMENTS (fn)) == NULL_TREE)
+ /* OK */;
+ else
+ return;
+
+ if (DECL_CONSTRUCTOR_P (fn))
+ DECL_CONSTRUCTOR_FOR_VBASE_P (fn) = 1;
+
+ /* First add it to DECL_ARGUMENTS... */
+ parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node);
+ /* Mark the artificial `__in_chrg' parameter as "artificial". */
+ SET_DECL_ARTIFICIAL (parm);
+ DECL_ARG_TYPE (parm) = integer_type_node;
+ TREE_READONLY (parm) = 1;
+ parms = DECL_ARGUMENTS (fn);
+ TREE_CHAIN (parm) = TREE_CHAIN (parms);
+ TREE_CHAIN (parms) = parm;
+
+ /* ...and then to TYPE_ARG_TYPES. */
+ arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ basetype = TREE_TYPE (TREE_VALUE (arg_types));
+ arg_types = hash_tree_chain (integer_type_node, TREE_CHAIN (arg_types));
+ fntype = build_cplus_method_type (basetype, TREE_TYPE (TREE_TYPE (fn)),
+ arg_types);
+ if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)))
+ fntype = build_exception_variant (fntype,
+ TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn)));
+ TREE_TYPE (fn) = fntype;
}
/* Classes overload their constituent function names automatically.
@@ -866,8 +1076,6 @@ grokclassfn (ctype, cname, function, flags, quals)
tree arg_types;
tree parm;
tree qualtype;
- tree fntype = TREE_TYPE (function);
- tree raises = TYPE_RAISES_EXCEPTIONS (fntype);
if (fn_name == NULL_TREE)
{
@@ -894,24 +1102,6 @@ grokclassfn (ctype, cname, function, flags, quals)
&& (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function)))
constp = 0;
- if (DECL_CONSTRUCTOR_P (function))
- {
- if (TYPE_USES_VIRTUAL_BASECLASSES (ctype))
- {
- DECL_CONSTRUCTOR_FOR_VBASE_P (function) = 1;
- /* In this case we need "in-charge" flag saying whether
- this constructor is responsible for initialization
- of virtual baseclasses or not. */
- parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node);
- /* Mark the artificial `__in_chrg' parameter as "artificial". */
- SET_DECL_ARTIFICIAL (parm);
- DECL_ARG_TYPE (parm) = integer_type_node;
- DECL_REGISTER (parm) = 1;
- TREE_CHAIN (parm) = last_function_parms;
- last_function_parms = parm;
- }
- }
-
parm = build_decl (PARM_DECL, this_identifier, type);
/* Mark the artificial `this' parameter as "artificial". */
SET_DECL_ARTIFICIAL (parm);
@@ -925,99 +1115,37 @@ grokclassfn (ctype, cname, function, flags, quals)
last_function_parms = parm;
}
- if (flags == DTOR_FLAG)
+ DECL_ARGUMENTS (function) = last_function_parms;
+ /* First approximations. */
+ DECL_CONTEXT (function) = ctype;
+ DECL_CLASS_CONTEXT (function) = ctype;
+
+ if (flags == DTOR_FLAG || DECL_CONSTRUCTOR_P (function))
{
- char *buf, *dbuf;
- tree const_integer_type = build_type_variant (integer_type_node, 1, 0);
- int len = sizeof (DESTRUCTOR_DECL_PREFIX)-1;
-
- arg_types = hash_tree_chain (const_integer_type, void_list_node);
- TREE_SIDE_EFFECTS (arg_types) = 1;
- /* Build the overload name. It will look like `7Example'. */
- if (IDENTIFIER_TYPE_VALUE (cname))
- dbuf = build_overload_name (IDENTIFIER_TYPE_VALUE (cname), 1, 1);
- else if (IDENTIFIER_LOCAL_VALUE (cname))
- dbuf = build_overload_name (TREE_TYPE (IDENTIFIER_LOCAL_VALUE (cname)), 1, 1);
- else
- /* Using ctype fixes the `X::Y::~Y()' crash. The cname has no type when
- it's defined out of the class definition, since poplevel_class wipes
- it out. This used to be internal error 346. */
- dbuf = build_overload_name (ctype, 1, 1);
- buf = (char *) alloca (strlen (dbuf) + sizeof (DESTRUCTOR_DECL_PREFIX));
- bcopy (DESTRUCTOR_DECL_PREFIX, buf, len);
- buf[len] = '\0';
- strcat (buf, dbuf);
- DECL_ASSEMBLER_NAME (function) = get_identifier (buf);
- parm = build_decl (PARM_DECL, in_charge_identifier, const_integer_type);
- /* Mark the artificial `__in_chrg' parameter as "artificial". */
- SET_DECL_ARTIFICIAL (parm);
- TREE_USED (parm) = 1;
-#if 0
- /* We don't need to mark the __in_chrg parameter itself as `const'
- since its type is already `const int'. In fact we MUST NOT mark
- it as `const' cuz that will screw up the debug info (causing it
- to say that the type of __in_chrg is `const const int'). */
- TREE_READONLY (parm) = 1;
-#endif
- DECL_ARG_TYPE (parm) = const_integer_type;
- /* This is the same chain as DECL_ARGUMENTS (...). */
- TREE_CHAIN (last_function_parms) = parm;
+ maybe_retrofit_in_chrg (function);
+ arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
+ }
- fntype = build_cplus_method_type (qualtype, void_type_node,
- arg_types);
- if (raises)
- {
- fntype = build_exception_variant (fntype, raises);
- }
- TREE_TYPE (function) = fntype;
+ if (flags == DTOR_FLAG)
+ {
+ DECL_ASSEMBLER_NAME (function) = build_destructor_name (ctype);
TYPE_HAS_DESTRUCTOR (ctype) = 1;
}
else
{
- tree these_arg_types;
-
- if (DECL_CONSTRUCTOR_FOR_VBASE_P (function))
- {
- arg_types = hash_tree_chain (integer_type_node,
- TREE_CHAIN (arg_types));
- fntype = build_cplus_method_type (qualtype,
- TREE_TYPE (TREE_TYPE (function)),
- arg_types);
- if (raises)
- {
- fntype = build_exception_variant (fntype, raises);
- }
- TREE_TYPE (function) = fntype;
- arg_types = TYPE_ARG_TYPES (TREE_TYPE (function));
- }
-
- these_arg_types = arg_types;
-
if (TREE_CODE (TREE_TYPE (function)) == FUNCTION_TYPE)
/* Only true for static member functions. */
- these_arg_types = hash_tree_chain (build_pointer_type (qualtype),
- arg_types);
+ arg_types = hash_tree_chain (build_pointer_type (qualtype),
+ arg_types);
DECL_ASSEMBLER_NAME (function)
- = build_decl_overload (fn_name, these_arg_types,
+ = build_decl_overload (fn_name, arg_types,
1 + DECL_CONSTRUCTOR_P (function));
-
-#if 0
- /* This code is going into the compiler, but currently, it makes
- libg++/src/Integer.cc not compile. The problem is that the nice name
- winds up going into the symbol table, and conversion operations look
- for the manged name. */
- substitute_nice_name (function);
-#endif
}
-
- DECL_ARGUMENTS (function) = last_function_parms;
- /* First approximations. */
- DECL_CONTEXT (function) = ctype;
- DECL_CLASS_CONTEXT (function) = ctype;
}
/* Work on the expr used by alignof (this is only called by the parser). */
+
tree
grok_alignof (expr)
tree expr;
@@ -1025,6 +1153,9 @@ grok_alignof (expr)
tree best, t;
int bestalign;
+ if (processing_template_decl)
+ return build_min (ALIGNOF_EXPR, sizetype, expr);
+
if (TREE_CODE (expr) == COMPONENT_REF
&& DECL_BIT_FIELD (TREE_OPERAND (expr, 1)))
error ("`__alignof__' applied to a bit-field");
@@ -1061,6 +1192,7 @@ grok_alignof (expr)
/* Create an ARRAY_REF, checking for the user doing things backwards
along the way. */
+
tree
grok_array_decl (array_expr, index_exp)
tree array_expr, index_exp;
@@ -1070,6 +1202,10 @@ grok_array_decl (array_expr, index_exp)
if (type == error_mark_node || index_exp == error_mark_node)
return error_mark_node;
+ if (processing_template_decl)
+ return build_min (ARRAY_REF, type ? TREE_TYPE (type) : NULL_TREE,
+ array_expr, index_exp);
+
if (type == NULL_TREE)
{
/* Something has gone very wrong. Assume we are mistakenly reducing
@@ -1083,8 +1219,7 @@ grok_array_decl (array_expr, index_exp)
type = TREE_TYPE (type);
/* If they have an `operator[]', use that. */
- if (TYPE_LANG_SPECIFIC (type)
- && TYPE_OVERLOADS_ARRAY_REF (type))
+ if (IS_AGGR_TYPE (type) || IS_AGGR_TYPE (TREE_TYPE (index_exp)))
return build_opfncall (ARRAY_REF, LOOKUP_NORMAL,
array_expr, index_exp, NULL_TREE);
@@ -1130,78 +1265,70 @@ grok_array_decl (array_expr, index_exp)
for doing an array delete. If DOING_VEC is 2, they gave us the
array size as an argument to delete.
Implements ARM $5.3.4. This is called from the parser. */
+
tree
delete_sanity (exp, size, doing_vec, use_global_delete)
tree exp, size;
int doing_vec, use_global_delete;
{
- tree t = stabilize_reference (convert_from_reference (exp));
- tree type = TREE_TYPE (t);
- enum tree_code code = TREE_CODE (type);
+ tree t, type;
/* For a regular vector delete (aka, no size argument) we will pass
this down as a NULL_TREE into build_vec_delete. */
tree maxindex = NULL_TREE;
- /* This is used for deleting arrays. */
- tree elt_size;
- switch (doing_vec)
+ if (exp == error_mark_node)
+ return exp;
+
+ if (processing_template_decl)
{
- case 2:
- maxindex = build_binary_op (MINUS_EXPR, size, integer_one_node, 1);
- if (! flag_traditional)
- pedwarn ("anachronistic use of array size in vector delete");
- /* Fall through. */
- case 1:
- elt_size = c_sizeof (type);
- break;
- default:
- if (code != POINTER_TYPE)
- {
- cp_error ("type `%#T' argument given to `delete', expected pointer",
- type);
- return error_mark_node;
- }
+ t = build_min (DELETE_EXPR, void_type_node, exp, size);
+ DELETE_EXPR_USE_GLOBAL (t) = use_global_delete;
+ DELETE_EXPR_USE_VEC (t) = doing_vec;
+ return t;
+ }
+
+ if (TREE_CODE (exp) == OFFSET_REF)
+ exp = resolve_offset_ref (exp);
+ exp = convert_from_reference (exp);
+ t = stabilize_reference (exp);
+ t = build_expr_type_conversion (WANT_POINTER, t, 1);
- /* Deleting a pointer with the value zero is valid and has no effect. */
- if (integer_zerop (t))
- return build1 (NOP_EXPR, void_type_node, t);
+ if (t == NULL_TREE || t == error_mark_node)
+ {
+ cp_error ("type `%#T' argument given to `delete', expected pointer",
+ TREE_TYPE (exp));
+ return error_mark_node;
}
- if (code == POINTER_TYPE)
+ if (doing_vec == 2)
{
-#if 0
- /* As of Valley Forge, you can delete a pointer to constant. */
- /* You can't delete a pointer to constant. */
- if (TREE_READONLY (TREE_TYPE (type)))
- {
- error ("`const *' cannot be deleted");
- return error_mark_node;
- }
-#endif
- /* You also can't delete functions. */
- if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
- {
- error ("cannot delete a function");
- return error_mark_node;
- }
+ maxindex = build_binary_op (MINUS_EXPR, size, integer_one_node, 1);
+ pedwarn ("anachronistic use of array size in vector delete");
}
-#if 0
- /* If the type has no destructor, then we should build a regular
- delete, instead of a vector delete. Otherwise, we would end
- up passing a bogus offset into __builtin_delete, which is
- not expecting it. */
- if (doing_vec
- && TREE_CODE (type) == POINTER_TYPE
- && !TYPE_HAS_DESTRUCTOR (TREE_TYPE (type)))
+ type = TREE_TYPE (t);
+
+ /* As of Valley Forge, you can delete a pointer to const. */
+
+ /* You can't delete functions. */
+ if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
{
- doing_vec = 0;
- use_global_delete = 1;
+ error ("cannot delete a function");
+ return error_mark_node;
}
-#endif
+
+ /* An array can't have been allocated by new, so complain. */
+ if (TREE_CODE (t) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (t, 0)) == VAR_DECL
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == ARRAY_TYPE)
+ cp_warning ("deleting array `%#D'", TREE_OPERAND (t, 0));
+
+ /* Deleting a pointer with the value zero is valid and has no effect. */
+ if (integer_zerop (t))
+ return build1 (NOP_EXPR, void_type_node, t);
if (doing_vec)
- return build_vec_delete (t, maxindex, elt_size, integer_one_node,
+ return build_vec_delete (t, maxindex, integer_one_node,
integer_two_node, use_global_delete);
else
{
@@ -1210,31 +1337,123 @@ delete_sanity (exp, size, doing_vec, use_global_delete)
{
/* Only do access checking here; we'll be calling op delete
from the destructor. */
- tree tmp = build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, t,
- size_zero_node, NULL_TREE);
+ tree tmp = build_op_delete_call (DELETE_EXPR, t, size_zero_node,
+ LOOKUP_NORMAL, NULL_TREE);
if (tmp == error_mark_node)
return error_mark_node;
}
return build_delete (type, t, integer_three_node,
- LOOKUP_NORMAL|LOOKUP_HAS_IN_CHARGE,
- use_global_delete);
+ LOOKUP_NORMAL, use_global_delete);
}
}
+/* Report an error if the indicated template declaration is not the
+ sort of thing that should be a member template. */
+
+void
+check_member_template (tmpl)
+ tree tmpl;
+{
+ tree decl;
+
+ my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
+ decl = DECL_TEMPLATE_RESULT (tmpl);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ || (TREE_CODE (decl) == TYPE_DECL
+ && IS_AGGR_TYPE (TREE_TYPE (decl))))
+ {
+ if (current_function_decl)
+ /* 14.5.2.2 [temp.mem]
+
+ A local class shall not have member templates. */
+ cp_error ("declaration of member template `%#D' in local class",
+ decl);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_VIRTUAL_P (decl))
+ {
+ /* 14.5.2.3 [temp.mem]
+
+ A member function template shall not be virtual. */
+ cp_error
+ ("invalid use of `virtual' in template declaration of `%#D'",
+ decl);
+ DECL_VIRTUAL_P (decl) = 0;
+ }
+
+ /* The debug-information generating code doesn't know what to do
+ with member templates. */
+ DECL_IGNORED_P (tmpl) = 1;
+ }
+ else
+ cp_error ("template declaration of `%#D'", decl);
+}
+
+/* Return true iff TYPE is a valid Java parameter or return type. */
+
+int
+acceptable_java_type (type)
+ tree type;
+{
+ if (TREE_CODE (type) == VOID_TYPE || TYPE_FOR_JAVA (type))
+ return 1;
+ if (TREE_CODE (type) == POINTER_TYPE)
+ {
+ type = TREE_TYPE (type);
+ if (TREE_CODE (type) == RECORD_TYPE)
+ {
+ complete_type (type);
+ return TYPE_FOR_JAVA (type);
+ }
+ }
+ return 0;
+}
+
+/* For a METHOD in a Java class CTYPE, return 1 if
+ the parameter and return types are valid Java types.
+ Otherwise, print appropriate error messages, and return 0. */
+
+int
+check_java_method (ctype, method)
+ tree ctype, method;
+{
+ int jerr = 0;
+ tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (method));
+ tree ret_type = TREE_TYPE (TREE_TYPE (method));
+ if (! acceptable_java_type (ret_type))
+ {
+ cp_error ("Java method '%D' has non-Java return type `%T'",
+ method, ret_type);
+ jerr++;
+ }
+ for (; arg_types != NULL_TREE; arg_types = TREE_CHAIN (arg_types))
+ {
+ tree type = TREE_VALUE (arg_types);
+ if (! acceptable_java_type (type))
+ {
+ cp_error ("Java method '%D' has non-Java parameter type `%T'",
+ method, type);
+ jerr++;
+ }
+ }
+ return jerr ? 0 : 1;
+}
+
/* Sanity check: report error if this function FUNCTION is not
really a member of the class (CTYPE) it is supposed to belong to.
CNAME is the same here as it is for grokclassfn above. */
tree
-check_classfn (ctype, cname, function)
- tree ctype, cname, function;
+check_classfn (ctype, function)
+ tree ctype, function;
{
tree fn_name = DECL_NAME (function);
- tree fndecl;
- tree method_vec = CLASSTYPE_METHOD_VEC (ctype);
+ tree fndecl, fndecls;
+ tree method_vec = CLASSTYPE_METHOD_VEC (complete_type (ctype));
tree *methods = 0;
tree *end = 0;
+ tree templates = NULL_TREE;
if (method_vec != 0)
{
@@ -1242,65 +1461,100 @@ check_classfn (ctype, cname, function)
end = TREE_VEC_END (method_vec);
/* First suss out ctors and dtors. */
- if (*methods && fn_name == DECL_NAME (*methods))
+ if (*methods && fn_name == DECL_NAME (OVL_CURRENT (*methods))
+ && DECL_CONSTRUCTOR_P (function))
+ goto got_it;
+ if (*++methods && fn_name == DECL_NAME (OVL_CURRENT (*methods))
+ && DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function)))
goto got_it;
while (++methods != end)
{
- if (fn_name == DECL_NAME (*methods))
+ fndecl = *methods;
+ if (fn_name == DECL_NAME (OVL_CURRENT (*methods)))
{
got_it:
- fndecl = *methods;
- while (fndecl)
+ for (fndecls = *methods; fndecls != NULL_TREE;
+ fndecls = OVL_NEXT (fndecls))
{
- if (DECL_ASSEMBLER_NAME (function) == DECL_ASSEMBLER_NAME (fndecl))
+ fndecl = OVL_CURRENT (fndecls);
+ /* The DECL_ASSEMBLER_NAME for a TEMPLATE_DECL is
+ not mangled, so the check below does not work
+ correctly in that case. Since mangled destructor names
+ do not include the type of the arguments, we
+ can't use this short-cut for them, either. */
+ if (TREE_CODE (function) != TEMPLATE_DECL
+ && TREE_CODE (fndecl) != TEMPLATE_DECL
+ && !DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function))
+ && (DECL_ASSEMBLER_NAME (function)
+ == DECL_ASSEMBLER_NAME (fndecl)))
return fndecl;
-#if 0
- /* This should work, but causes libg++ to fail
- make check-tFix. */
- /* We have to do more extensive argument checking here, as
- the name may have been changed by asm("new_name"). */
- if (decls_match (function, fndecl))
- return fndecl;
-#else
+
+ /* We cannot simply call decls_match because this
+ doesn't work for static member functions that are
+ pretending to be methods, and because the name
+ may have been changed by asm("new_name"). */
if (DECL_NAME (function) == DECL_NAME (fndecl))
{
tree p1 = TYPE_ARG_TYPES (TREE_TYPE (function));
tree p2 = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
/* Get rid of the this parameter on functions that become
- static. */
+ static. */
if (DECL_STATIC_FUNCTION_P (fndecl)
&& TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
p1 = TREE_CHAIN (p1);
if (comptypes (TREE_TYPE (TREE_TYPE (function)),
TREE_TYPE (TREE_TYPE (fndecl)), 1)
- && compparms (p1, p2, 3))
- {
- if (DECL_STATIC_FUNCTION_P (fndecl)
- && TREE_CODE (TREE_TYPE (function)) == METHOD_TYPE)
- revert_static_member_fn (&function, NULL, NULL);
- return fndecl;
- }
+ && compparms (p1, p2, 3)
+ && (DECL_TEMPLATE_SPECIALIZATION (function)
+ == DECL_TEMPLATE_SPECIALIZATION (fndecl))
+ && (!DECL_TEMPLATE_SPECIALIZATION (function)
+ || (DECL_TI_TEMPLATE (function)
+ == DECL_TI_TEMPLATE (fndecl))))
+ return fndecl;
+
+ if (is_member_template (fndecl))
+ /* This function might be an instantiation
+ or specialization of fndecl. */
+ templates =
+ scratch_tree_cons (NULL_TREE, fndecl, templates);
}
-#endif
- fndecl = DECL_CHAIN (fndecl);
}
break; /* loser */
}
+ else if (TREE_CODE (fndecl) == TEMPLATE_DECL
+ && IDENTIFIER_TYPENAME_P (DECL_NAME (fndecl))
+ && IDENTIFIER_TYPENAME_P (fn_name))
+ /* The method in the class is a member template
+ conversion operator. We are declaring another
+ conversion operator. It is possible that even though
+ the names don't match, there is some specialization
+ occurring. */
+ templates =
+ scratch_tree_cons (NULL_TREE, fndecl, templates);
}
}
+ if (templates)
+ /* This function might be an instantiation or a specialization.
+ We should verify that this is possible. If it is, we must
+ somehow add the new declaration to the method vector for the
+ class. Perhaps we should use add_method? For now, we simply
+ return NULL_TREE, which lets the caller know that this
+ function is new, but we don't print an error message. */
+ return NULL_TREE;
+
if (methods != end)
{
tree fndecl = *methods;
cp_error ("prototype for `%#D' does not match any in class `%T'",
function, ctype);
- cp_error_at ("candidate%s: %+#D", DECL_CHAIN (fndecl) ? "s are" : " is",
- fndecl);
- while (fndecl = DECL_CHAIN (fndecl), fndecl)
- cp_error_at (" %#D", fndecl);
+ cp_error_at ("candidate%s: %+#D", OVL_NEXT (fndecl) ? "s are" : " is",
+ OVL_CURRENT (fndecl));
+ while (fndecl = OVL_NEXT (fndecl), fndecl)
+ cp_error_at (" %#D", OVL_CURRENT(fndecl));
}
else
{
@@ -1309,8 +1563,8 @@ check_classfn (ctype, cname, function)
function, ctype);
}
- /* If we did not find the method in the class, add it to
- avoid spurious errors. */
+ /* If we did not find the method in the class, add it to avoid
+ spurious errors. */
add_method (ctype, methods, function);
return NULL_TREE;
}
@@ -1336,8 +1590,8 @@ check_classfn (ctype, cname, function)
CHANGES TO CODE IN `start_method'. */
tree
-grokfield (declarator, declspecs, raises, init, asmspec_tree, attrlist)
- tree declarator, declspecs, raises, init, asmspec_tree, attrlist;
+grokfield (declarator, declspecs, init, asmspec_tree, attrlist)
+ tree declarator, declspecs, init, asmspec_tree, attrlist;
{
register tree value;
char *asmspec = 0;
@@ -1356,14 +1610,25 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree, attrlist)
flags = 0;
}
+ if (declspecs == NULL_TREE
+ && TREE_CODE (declarator) == SCOPE_REF
+ && TREE_CODE (TREE_OPERAND (declarator, 1)) == IDENTIFIER_NODE)
+ {
+ /* Access declaration */
+ if (! IS_AGGR_TYPE_CODE (TREE_CODE (TREE_OPERAND (declarator, 0))))
+ ;
+ else if (TREE_COMPLEXITY (declarator) == current_class_depth)
+ pop_nested_class (1);
+ return do_class_using_decl (declarator);
+ }
+
if (init
&& TREE_CODE (init) == TREE_LIST
&& TREE_VALUE (init) == error_mark_node
&& TREE_CHAIN (init) == NULL_TREE)
- init = NULL_TREE;
+ init = NULL_TREE;
- value = grokdeclarator (declarator, declspecs, FIELD, init != 0,
- raises, NULL_TREE);
+ value = grokdeclarator (declarator, declspecs, FIELD, init != 0, NULL_TREE);
if (! value)
return value; /* friend or constructor went bad. */
@@ -1374,7 +1639,8 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree, attrlist)
if (DECL_NAME (value) != NULL_TREE
&& IDENTIFIER_POINTER (DECL_NAME (value))[0] == '_'
&& ! strcmp (IDENTIFIER_POINTER (DECL_NAME (value)), "_vptr"))
- cp_error ("member `%D' conflicts with virtual function table field name", value);
+ cp_error ("member `%D' conflicts with virtual function table field name",
+ value);
/* Stash away type declarations. */
if (TREE_CODE (value) == TYPE_DECL)
@@ -1384,15 +1650,11 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree, attrlist)
DECL_CLASS_CONTEXT (value) = current_class_type;
CLASSTYPE_LOCAL_TYPEDECLS (current_class_type) = 1;
- /* If we declare a typedef name for something that has no name,
- the typedef name is used for linkage. See 7.1.3 p4 94/0158. */
- if (TYPE_NAME (TREE_TYPE (value))
- && TREE_CODE (TYPE_NAME (TREE_TYPE (value))) == TYPE_DECL
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (TREE_TYPE (value))))
- {
- TYPE_NAME (TREE_TYPE (value)) = value;
- TYPE_STUB_DECL (TREE_TYPE (value)) = value;
- }
+ /* Now that we've updated the context, we need to remangle the
+ name for this TYPE_DECL. */
+ DECL_ASSEMBLER_NAME (value) = DECL_NAME (value);
+ DECL_ASSEMBLER_NAME (value) =
+ get_identifier (build_overload_name (TREE_TYPE (value), 1, 1));
pushdecl_class_level (value);
return value;
@@ -1412,9 +1674,6 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree, attrlist)
return void_type_node;
}
- if (flag_cadillac)
- cadillac_start_decl (value);
-
if (asmspec_tree)
asmspec = TREE_STRING_POINTER (asmspec_tree);
@@ -1458,6 +1717,8 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree, attrlist)
because `decl_const_value' would mis-interpret it
as only meaning that this VAR_DECL is defined. */
init = build1 (NOP_EXPR, TREE_TYPE (value), init);
+ else if (processing_template_decl)
+ ;
else if (! TREE_CONSTANT (init))
{
/* We can allow references to things that are effectively
@@ -1477,45 +1738,51 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree, attrlist)
/* The corresponding pop_obstacks is in cp_finish_decl. */
push_obstacks_nochange ();
+ if (processing_template_decl && ! current_function_decl
+ && (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == FUNCTION_DECL))
+ value = push_template_decl (value);
+
if (attrlist)
cplus_decl_attributes (value, TREE_PURPOSE (attrlist),
TREE_VALUE (attrlist));
if (TREE_CODE (value) == VAR_DECL)
{
+ my_friendly_assert (TREE_PUBLIC (value), 0);
+
/* We cannot call pushdecl here, because that would
fill in the value of our TREE_CHAIN. Instead, we
modify cp_finish_decl to do the right thing, namely, to
put this decl out straight away. */
- if (TREE_PUBLIC (value))
+ /* current_class_type can be NULL_TREE in case of error. */
+ if (asmspec == 0 && current_class_type)
{
- /* current_class_type can be NULL_TREE in case of error. */
- if (asmspec == 0 && current_class_type)
- {
- TREE_PUBLIC (value) = 1;
- DECL_INITIAL (value) = error_mark_node;
- DECL_ASSEMBLER_NAME (value)
- = build_static_name (current_class_type, DECL_NAME (value));
- }
- pending_statics = perm_tree_cons (NULL_TREE, value, pending_statics);
-
- /* Static consts need not be initialized in the class definition. */
- if (init != NULL_TREE && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (value)))
- {
- static int explanation = 0;
-
- error ("initializer invalid for static member with constructor");
- if (explanation++ == 0)
- error ("(you really want to initialize it separately)");
- init = 0;
- }
- /* Force the compiler to know when an uninitialized static
- const member is being used. */
- if (TYPE_READONLY (value) && init == 0)
- TREE_USED (value) = 1;
+ TREE_PUBLIC (value) = 1;
+ DECL_INITIAL (value) = error_mark_node;
+ DECL_ASSEMBLER_NAME (value)
+ = build_static_name (current_class_type, DECL_NAME (value));
}
+ if (! processing_template_decl)
+ pending_statics = perm_tree_cons (NULL_TREE, value, pending_statics);
+
+ /* Static consts need not be initialized in the class definition. */
+ if (init != NULL_TREE && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (value)))
+ {
+ static int explanation = 0;
+
+ error ("initializer invalid for static member with constructor");
+ if (explanation++ == 0)
+ error ("(you really want to initialize it separately)");
+ init = 0;
+ }
+ /* Force the compiler to know when an uninitialized static
+ const member is being used. */
+ if (TYPE_READONLY (value) && init == 0)
+ TREE_USED (value) = 1;
DECL_INITIAL (value) = init;
DECL_IN_AGGR_P (value) = 1;
+ DECL_CONTEXT (value) = current_class_type;
+ DECL_CLASS_CONTEXT (value) = current_class_type;
cp_finish_decl (value, init, asmspec_tree, 1, flags);
pushdecl_class_level (value);
@@ -1539,15 +1806,6 @@ grokfield (declarator, declspecs, raises, init, asmspec_tree, attrlist)
}
if (TREE_CODE (value) == FUNCTION_DECL)
{
- check_default_args (value);
- if (DECL_CHAIN (value) != NULL_TREE)
- {
- /* Need a fresh node here so that we don't get circularity
- when we link these together. */
- value = copy_node (value);
- /* When does this happen? */
- my_friendly_assert (init == NULL_TREE, 193);
- }
if (asmspec)
{
/* This must override the asm specifier which was placed
@@ -1583,7 +1841,7 @@ grokbitfield (declarator, declspecs, width)
tree declarator, declspecs, width;
{
register tree value = grokdeclarator (declarator, declspecs, BITFIELD,
- 0, NULL_TREE, NULL_TREE);
+ 0, NULL_TREE);
if (! value) return NULL_TREE; /* friends went bad. */
@@ -1621,216 +1879,20 @@ grokbitfield (declarator, declspecs, width)
if (width != error_mark_node)
{
- /* detect invalid field size. */
- if (TREE_CODE (width) == CONST_DECL)
- width = DECL_INITIAL (width);
- else if (TREE_READONLY_DECL_P (width))
- width = decl_constant_value (width);
- if (TREE_CODE (width) != INTEGER_CST)
- {
- cp_error ("structure field `%D' width not an integer constant",
- value);
- DECL_INITIAL (value) = NULL_TREE;
- }
- else
- {
- constant_expression_warning (width);
- DECL_INITIAL (value) = width;
- DECL_BIT_FIELD (value) = 1;
- }
+ constant_expression_warning (width);
+ DECL_INITIAL (value) = width;
+ DECL_BIT_FIELD (value) = 1;
}
DECL_IN_AGGR_P (value) = 1;
return value;
}
-#if 0
-/* Like GROKFIELD, except that the declarator has been
- buried in DECLSPECS. Find the declarator, and
- return something that looks like it came from
- GROKFIELD. */
-tree
-groktypefield (declspecs, parmlist)
- tree declspecs;
- tree parmlist;
-{
- tree spec = declspecs;
- tree prev = NULL_TREE;
-
- tree type_id = NULL_TREE;
- tree quals = NULL_TREE;
- tree lengths = NULL_TREE;
- tree decl = NULL_TREE;
-
- while (spec)
- {
- register tree id = TREE_VALUE (spec);
-
- if (TREE_CODE (spec) != TREE_LIST)
- /* Certain parse errors slip through. For example,
- `int class ();' is not caught by the parser. Try
- weakly to recover here. */
- return NULL_TREE;
-
- if (TREE_CODE (id) == TYPE_DECL
- || (TREE_CODE (id) == IDENTIFIER_NODE && TREE_TYPE (id)))
- {
- /* We have a constructor/destructor or
- conversion operator. Use it. */
- if (prev)
- TREE_CHAIN (prev) = TREE_CHAIN (spec);
- else
- declspecs = TREE_CHAIN (spec);
-
- type_id = id;
- goto found;
- }
- prev = spec;
- spec = TREE_CHAIN (spec);
- }
-
- /* Nope, we have a conversion operator to a scalar type or something
- else, that includes things like constructor declarations for
- templates. */
- spec = declspecs;
- while (spec)
- {
- tree id = TREE_VALUE (spec);
-
- if (TREE_CODE (id) == IDENTIFIER_NODE)
- {
- if (id == ridpointers[(int)RID_INT]
- || id == ridpointers[(int)RID_DOUBLE]
- || id == ridpointers[(int)RID_FLOAT]
- || id == ridpointers[(int)RID_WCHAR])
- {
- if (type_id)
- error ("extra `%s' ignored",
- IDENTIFIER_POINTER (id));
- else
- type_id = id;
- }
- else if (id == ridpointers[(int)RID_LONG]
- || id == ridpointers[(int)RID_SHORT]
- || id == ridpointers[(int)RID_CHAR])
- {
- lengths = tree_cons (NULL_TREE, id, lengths);
- }
- else if (id == ridpointers[(int)RID_VOID])
- {
- if (type_id)
- error ("spurious `void' type ignored");
- else
- error ("conversion to `void' type invalid");
- }
- else if (id == ridpointers[(int)RID_AUTO]
- || id == ridpointers[(int)RID_REGISTER]
- || id == ridpointers[(int)RID_TYPEDEF]
- || id == ridpointers[(int)RID_CONST]
- || id == ridpointers[(int)RID_VOLATILE])
- {
- error ("type specifier `%s' used invalidly",
- IDENTIFIER_POINTER (id));
- }
- else if (id == ridpointers[(int)RID_FRIEND]
- || id == ridpointers[(int)RID_VIRTUAL]
- || id == ridpointers[(int)RID_INLINE]
- || id == ridpointers[(int)RID_UNSIGNED]
- || id == ridpointers[(int)RID_SIGNED]
- || id == ridpointers[(int)RID_STATIC]
- || id == ridpointers[(int)RID_EXTERN])
- {
- quals = tree_cons (NULL_TREE, id, quals);
- }
- else
- {
- /* Happens when we have a global typedef
- and a class-local member function with
- the same name. */
- type_id = id;
- goto found;
- }
- }
- else if (TREE_CODE (id) == RECORD_TYPE)
- {
- type_id = TYPE_NAME (id);
- if (TREE_CODE (type_id) == TYPE_DECL)
- type_id = DECL_NAME (type_id);
- if (type_id == NULL_TREE)
- error ("identifier for aggregate type conversion omitted");
- }
- else if (TREE_CODE_CLASS (TREE_CODE (id)) == 't')
- error ("`operator' missing on conversion operator or tag missing from type");
- else
- my_friendly_abort (194);
- spec = TREE_CHAIN (spec);
- }
-
- if (type_id)
- declspecs = chainon (lengths, quals);
- else if (lengths)
- {
- if (TREE_CHAIN (lengths))
- error ("multiple length specifiers");
- type_id = ridpointers[(int)RID_INT];
- declspecs = chainon (lengths, quals);
- }
- else if (quals)
- {
- error ("no type given, defaulting to `operator int ...'");
- type_id = ridpointers[(int)RID_INT];
- declspecs = quals;
- }
- else
- return NULL_TREE;
-
- found:
- decl = grokdeclarator (build_parse_node (CALL_EXPR, type_id, parmlist, NULL_TREE),
- declspecs, FIELD, 0, NULL_TREE, NULL_TREE);
- if (decl == NULL_TREE)
- return NULL_TREE;
-
- if (TREE_CODE (decl) == FUNCTION_DECL && DECL_CHAIN (decl) != NULL_TREE)
- {
- /* Need a fresh node here so that we don't get circularity
- when we link these together. */
- decl = copy_node (decl);
- }
-
- if (decl == void_type_node
- || (TREE_CODE (decl) == FUNCTION_DECL
- && TREE_CODE (TREE_TYPE (decl)) != METHOD_TYPE))
- /* bunch of friends. */
- return decl;
-
- if (DECL_IN_AGGR_P (decl))
- {
- cp_error ("`%D' already defined in the class ", decl);
- return void_type_node;
- }
-
- cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0, 0);
-
- /* If this declaration is common to another declaration
- complain about such redundancy, and return NULL_TREE
- so that we don't build a circular list. */
- if (DECL_CHAIN (decl))
- {
- cp_error ("function `%D' declared twice in class %T", decl,
- DECL_CONTEXT (decl));
- return NULL_TREE;
- }
- DECL_IN_AGGR_P (decl) = 1;
- return decl;
-}
-#endif
-
tree
grokoptypename (declspecs, declarator)
tree declspecs, declarator;
{
- tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0,
- NULL_TREE, NULL_TREE);
+ tree t = grokdeclarator (declarator, declspecs, TYPENAME, 0, NULL_TREE);
return build_typename_overload (t);
}
@@ -1874,11 +1936,18 @@ copy_assignment_arg_p (parmtype, virtualp)
tree parmtype;
int virtualp;
{
+ if (current_class_type == NULL_TREE)
+ return 0;
+
if (TREE_CODE (parmtype) == REFERENCE_TYPE)
parmtype = TREE_TYPE (parmtype);
if ((TYPE_MAIN_VARIANT (parmtype) == current_class_type)
- || (virtualp && DERIVED_FROM_P (parmtype, current_class_type)))
+#if 0
+ /* Non-standard hack to support old Booch components. */
+ || (! virtualp && DERIVED_FROM_P (parmtype, current_class_type))
+#endif
+ )
return 1;
return 0;
@@ -1895,14 +1964,17 @@ grok_function_init (decl, init)
if (TREE_CODE (type) == FUNCTION_TYPE)
cp_error ("initializer specified for non-member function `%D'", decl);
+#if 0
+ /* We'll check for this in finish_struct_1. */
else if (DECL_VINDEX (decl) == NULL_TREE)
cp_error ("initializer specified for non-virtual method `%D'", decl);
+#endif
else if (integer_zerop (init))
{
#if 0
/* Mark this function as being "defined". */
DECL_INITIAL (decl) = error_mark_node;
- /* pure virtual destructors must be defined. */
+ /* pure virtual destructors must be defined. */
/* pure virtual needs to be defined (as abort) only when put in
vtbl. For wellformed call, it should be itself. pr4737 */
if (!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)))
@@ -1922,88 +1994,10 @@ grok_function_init (decl, init)
TYPE_HAS_ABSTRACT_ASSIGN_REF (current_class_type) = 1;
}
}
- else if (TREE_CODE (init) == OFFSET_REF
- && TREE_OPERAND (init, 0) == NULL_TREE
- && TREE_CODE (TREE_TYPE (init)) == METHOD_TYPE)
- {
- tree basetype = DECL_CLASS_CONTEXT (init);
- tree basefn = TREE_OPERAND (init, 1);
- if (TREE_CODE (basefn) != FUNCTION_DECL)
- cp_error ("non-method initializer invalid for method `%D'", decl);
- else if (! BINFO_OFFSET_ZEROP (TYPE_BINFO (DECL_CLASS_CONTEXT (basefn))))
- sorry ("base member function from other than first base class");
- else
- {
- tree binfo = get_binfo (basetype, TYPE_METHOD_BASETYPE (type), 1);
- if (binfo == error_mark_node)
- ;
- else if (binfo == 0)
- error_not_base_type (TYPE_METHOD_BASETYPE (TREE_TYPE (init)),
- TYPE_METHOD_BASETYPE (type));
- else
- {
- /* Mark this function as being defined,
- and give it new rtl. */
- DECL_INITIAL (decl) = error_mark_node;
- DECL_RTL (decl) = DECL_RTL (basefn);
- }
- }
- }
else
cp_error ("invalid initializer for virtual method `%D'", decl);
}
-/* When we get a declaration of the form
-
- type cname::fname ...
-
- the node for `cname::fname' gets built here in a special way.
- Namely, we push into `cname's scope. When this declaration is
- processed, we pop back out. */
-tree
-build_push_scope (cname, name)
- tree cname;
- tree name;
-{
- extern int current_class_depth;
- tree ctype, rval;
- int is_ttp = 0;
-
- if (cname == error_mark_node)
- return error_mark_node;
-
- ctype = IDENTIFIER_TYPE_VALUE (cname);
-
- if (TREE_CODE (ctype) == TEMPLATE_TYPE_PARM)
- is_ttp = 1;
- else if (ctype == NULL_TREE || ! IS_AGGR_TYPE (ctype))
- {
- cp_error ("`%T' not defined as aggregate type", cname);
- return name;
- }
- else if (IS_SIGNATURE (ctype))
- {
- error ("cannot push into signature scope, scope resolution operator ignored");
- return name;
- }
-
- rval = build_parse_node (SCOPE_REF, cname, name);
-
- /* Don't need to push the scope if we're already in it.
- We also don't need to push the scope for a ptr-to-member/method. */
-
- if (ctype == current_class_type || TREE_CODE (name) != IDENTIFIER_NODE
- || is_ttp)
- return rval;
-
- /* We do need to push the scope in this case, since CTYPE helps
- determine subsequent initializers (i.e., Foo::Bar x = foo_enum_1;). */
-
- push_nested_class (ctype, 3);
- TREE_COMPLEXITY (rval) = current_class_depth;
- return rval;
-}
-
void
cplus_decl_attributes (decl, attributes, prefix_attributes)
tree decl, attributes, prefix_attributes;
@@ -2025,22 +2019,25 @@ cplus_decl_attributes (decl, attributes, prefix_attributes)
specified class. Argument can be RECORD_TYPE, TYPE_DECL, or
IDENTIFIER_NODE. When given a template, this routine doesn't
lose the specialization. */
+
tree
constructor_name_full (thing)
tree thing;
{
- if (TREE_CODE (thing) == UNINSTANTIATED_P_TYPE)
- return DECL_NAME (UPT_TEMPLATE (thing));
- if (IS_AGGR_TYPE_CODE (TREE_CODE (thing)))
+ if (TREE_CODE (thing) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (thing) == TEMPLATE_TEMPLATE_PARM
+ || TREE_CODE (thing) == TYPENAME_TYPE)
+ thing = TYPE_NAME (thing);
+ else if (IS_AGGR_TYPE_CODE (TREE_CODE (thing)))
{
if (TYPE_WAS_ANONYMOUS (thing) && TYPE_HAS_CONSTRUCTOR (thing))
- thing = DECL_NAME (TREE_VEC_ELT (TYPE_METHODS (thing), 0));
+ thing = DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (thing), 0)));
else
thing = TYPE_NAME (thing);
}
if (TREE_CODE (thing) == TYPE_DECL
|| (TREE_CODE (thing) == TEMPLATE_DECL
- && DECL_TEMPLATE_IS_CLASS (thing)))
+ && TREE_CODE (DECL_TEMPLATE_RESULT (thing)) == TYPE_DECL))
thing = DECL_NAME (thing);
my_friendly_assert (TREE_CODE (thing) == IDENTIFIER_NODE, 197);
return thing;
@@ -2051,6 +2048,7 @@ constructor_name_full (thing)
specified class. Argument can be RECORD_TYPE, TYPE_DECL, or
IDENTIFIER_NODE. When given a template, return the plain
unspecialized name. */
+
tree
constructor_name (thing)
tree thing;
@@ -2060,13 +2058,13 @@ constructor_name (thing)
t = IDENTIFIER_TEMPLATE (thing);
if (!t)
return thing;
- t = TREE_PURPOSE (t);
- return DECL_NAME (t);
+ return t;
}
/* Cache the value of this class's main virtual function table pointer
in a register variable. This will save one indirection if a
more than one virtual function call is made this function. */
+
void
setup_vtbl_ptr ()
{
@@ -2074,10 +2072,18 @@ setup_vtbl_ptr ()
if (base_init_expr == 0
&& DECL_CONSTRUCTOR_P (current_function_decl))
- emit_base_init (current_class_type, 0);
+ {
+ if (processing_template_decl)
+ add_tree (build_min_nt
+ (CTOR_INITIALIZER,
+ current_member_init_list, current_base_init_list));
+ else
+ emit_base_init (current_class_type, 0);
+ }
}
/* Record the existence of an addressable inline function. */
+
void
mark_inline_for_output (decl)
tree decl;
@@ -2147,6 +2153,7 @@ get_temp_name (type, staticp)
}
TREE_USED (decl) = 1;
TREE_STATIC (decl) = staticp;
+ DECL_ARTIFICIAL (decl) = 1;
/* If this is a local variable, then lay out its rtl now.
Otherwise, callers of this function are responsible for dealing
@@ -2165,39 +2172,99 @@ get_temp_name (type, staticp)
It is not entered into current_binding_level, because
that breaks things when it comes time to do final cleanups
(which take place "outside" the binding contour of the function). */
+
tree
get_temp_regvar (type, init)
tree type, init;
{
- static char buf[sizeof (AUTO_TEMP_FORMAT) + 20] = { '_' };
tree decl;
- sprintf (buf+1, AUTO_TEMP_FORMAT, temp_name_counter++);
- decl = build_decl (VAR_DECL, get_identifier (buf), type);
+ decl = build_decl (VAR_DECL, NULL_TREE, type);
TREE_USED (decl) = 1;
DECL_REGISTER (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
- if (init)
- store_init_value (decl, init);
-
+ DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
/* We can expand these without fear, since they cannot need
constructors or destructors. */
- expand_decl (decl);
- expand_decl_init (decl);
-
- if (type_needs_gc_entry (type))
- DECL_GC_OFFSET (decl) = size_int (++current_function_obstack_index);
+ expand_expr (build_modify_expr (decl, INIT_EXPR, init),
+ NULL_RTX, VOIDmode, 0);
return decl;
}
-/* Make the macro TEMP_NAME_P available to units which do not
- include c-tree.h. */
-int
-temp_name_p (decl)
- tree decl;
+/* Hunts through the global anonymous union ANON_DECL, building
+ appropriate VAR_DECLs. Stores cleanups on the list of ELEMS, and
+ returns a VAR_DECL whose size is the same as the size of the
+ ANON_DECL, if one is available. */
+
+tree
+build_anon_union_vars (anon_decl, elems, static_p, external_p)
+ tree anon_decl;
+ tree* elems;
+ int static_p;
+ int external_p;
{
- return TEMP_NAME_P (decl);
+ tree type = TREE_TYPE (anon_decl);
+ tree main_decl = NULL_TREE;
+ tree field;
+
+ for (field = TYPE_FIELDS (type);
+ field != NULL_TREE;
+ field = TREE_CHAIN (field))
+ {
+ tree decl;
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
+
+ if (TREE_PRIVATE (field))
+ cp_pedwarn_at ("private member `%#D' in anonymous union", field);
+ else if (TREE_PROTECTED (field))
+ cp_pedwarn_at ("protected member `%#D' in anonymous union", field);
+
+ if (DECL_NAME (field) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ {
+ decl = build_anon_union_vars (field, elems, static_p, external_p);
+ if (!decl)
+ continue;
+ }
+ else
+ {
+ decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field));
+ /* tell `pushdecl' that this is not tentative. */
+ DECL_INITIAL (decl) = error_mark_node;
+ TREE_PUBLIC (decl) = 0;
+ TREE_STATIC (decl) = static_p;
+ DECL_EXTERNAL (decl) = external_p;
+ decl = pushdecl (decl);
+ DECL_INITIAL (decl) = NULL_TREE;
+ }
+
+ /* Only write out one anon union element--choose the one that
+ can hold them all. */
+ if (main_decl == NULL_TREE
+ && simple_cst_equal (DECL_SIZE (decl),
+ DECL_SIZE (anon_decl)) == 1)
+ main_decl = decl;
+ else
+ /* ??? This causes there to be no debug info written out
+ about this decl. */
+ TREE_ASM_WRITTEN (decl) = 1;
+
+ if (DECL_NAME (field) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ /* The remainder of the processing was already done in the
+ recursive call. */
+ continue;
+
+ /* If there's a cleanup to do, it belongs in the
+ TREE_PURPOSE of the following TREE_LIST. */
+ *elems = scratch_tree_cons (NULL_TREE, decl, *elems);
+ TREE_TYPE (*elems) = type;
+ }
+
+ return main_decl;
}
/* Finish off the processing of a UNION_TYPE structure.
@@ -2206,18 +2273,19 @@ temp_name_p (decl)
union is an anonymous union, we arrange for that
as well. PUBLIC_P is nonzero if this union is
not declared static. */
+
void
finish_anon_union (anon_union_decl)
tree anon_union_decl;
{
tree type = TREE_TYPE (anon_union_decl);
- tree field, main_decl = NULL_TREE;
tree elems = NULL_TREE;
+ tree main_decl;
int public_p = TREE_PUBLIC (anon_union_decl);
int static_p = TREE_STATIC (anon_union_decl);
int external_p = DECL_EXTERNAL (anon_union_decl);
- if ((field = TYPE_FIELDS (type)) == NULL_TREE)
+ if (TYPE_FIELDS (type) == NULL_TREE)
return;
if (public_p)
@@ -2226,46 +2294,9 @@ finish_anon_union (anon_union_decl)
return;
}
- for (; field; field = TREE_CHAIN (field))
- {
- tree decl;
- if (TREE_CODE (field) != FIELD_DECL)
- continue;
+ main_decl = build_anon_union_vars (anon_union_decl, &elems,
+ static_p, external_p);
- if (TREE_PRIVATE (field))
- cp_pedwarn_at ("private member `%#D' in anonymous union", field);
- else if (TREE_PROTECTED (field))
- cp_pedwarn_at ("protected member `%#D' in anonymous union", field);
-
- decl = build_decl (VAR_DECL, DECL_NAME (field), TREE_TYPE (field));
- /* tell `pushdecl' that this is not tentative. */
- DECL_INITIAL (decl) = error_mark_node;
- TREE_PUBLIC (decl) = public_p;
- TREE_STATIC (decl) = static_p;
- DECL_EXTERNAL (decl) = external_p;
- decl = pushdecl (decl);
-
- /* Only write out one anon union element--choose the one that
- can hold them all. */
- if (main_decl == NULL_TREE
- && 1 == simple_cst_equal (DECL_SIZE (decl),
- DECL_SIZE (anon_union_decl)))
- {
- main_decl = decl;
- }
- else
- {
- /* ??? This causes there to be no debug info written out
- about this decl. */
- TREE_ASM_WRITTEN (decl) = 1;
- }
-
- DECL_INITIAL (decl) = NULL_TREE;
- /* If there's a cleanup to do, it belongs in the
- TREE_PURPOSE of the following TREE_LIST. */
- elems = tree_cons (NULL_TREE, decl, elems);
- TREE_TYPE (elems) = type;
- }
if (static_p)
{
if (main_decl)
@@ -2283,84 +2314,6 @@ finish_anon_union (anon_union_decl)
/* The following call assumes that there are never any cleanups
for anonymous unions--a reasonable assumption. */
expand_anon_union_decl (anon_union_decl, NULL_TREE, elems);
-
- if (flag_cadillac)
- cadillac_finish_anon_union (anon_union_decl);
-}
-
-/* Finish and output a table which is generated by the compiler.
- NAME is the name to give the table.
- TYPE is the type of the table entry.
- INIT is all the elements in the table.
- PUBLICP is non-zero if this table should be given external access. */
-tree
-finish_table (name, type, init, publicp)
- tree name, type, init;
- int publicp;
-{
- tree itype, atype, decl;
- static tree empty_table;
- int is_empty = 0;
- tree asmspec;
-
- itype = build_index_type (size_int (list_length (init) - 1));
- atype = build_cplus_array_type (type, itype);
- layout_type (atype);
-
- if (TREE_VALUE (init) == integer_zero_node
- && TREE_CHAIN (init) == NULL_TREE)
- {
-#if 0
- if (empty_table == NULL_TREE)
-#endif
- {
- empty_table = get_temp_name (atype, 1);
- init = build (CONSTRUCTOR, atype, NULL_TREE, init);
- TREE_CONSTANT (init) = 1;
- TREE_STATIC (init) = 1;
- DECL_INITIAL (empty_table) = init;
- asmspec = build_string (IDENTIFIER_LENGTH (DECL_NAME (empty_table)),
- IDENTIFIER_POINTER (DECL_NAME (empty_table)));
- cp_finish_decl (empty_table, NULL_TREE, asmspec, 0, 0);
- }
- is_empty = 1;
- }
-
- if (name == NULL_TREE)
- {
- if (is_empty)
- return empty_table;
- decl = get_temp_name (atype, 1);
- }
- else
- {
- decl = build_decl (VAR_DECL, name, atype);
- decl = pushdecl (decl);
- TREE_STATIC (decl) = 1;
- }
-
- if (is_empty == 0)
- {
- TREE_PUBLIC (decl) = publicp;
- init = build (CONSTRUCTOR, atype, NULL_TREE, init);
- TREE_CONSTANT (init) = 1;
- TREE_STATIC (init) = 1;
- DECL_INITIAL (decl) = init;
- asmspec = build_string (IDENTIFIER_LENGTH (DECL_NAME (decl)),
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- }
- else
- {
- /* This will cause DECL to point to EMPTY_TABLE in rtl-land. */
- DECL_EXTERNAL (decl) = 1;
- TREE_STATIC (decl) = 0;
- init = 0;
- asmspec = build_string (IDENTIFIER_LENGTH (DECL_NAME (empty_table)),
- IDENTIFIER_POINTER (DECL_NAME (empty_table)));
- }
-
- cp_finish_decl (decl, NULL_TREE, asmspec, 0, 0);
- return decl;
}
/* Finish processing a builtin type TYPE. It's name is NAME,
@@ -2369,6 +2322,7 @@ finish_table (name, type, init, publicp)
used in FIELDS.
It is given the same alignment as ALIGN_TYPE. */
+
void
finish_builtin_type (type, name, fields, len, align_type)
tree type;
@@ -2395,6 +2349,7 @@ finish_builtin_type (type, name, fields, len, align_type)
#else
TYPE_NAME (type) = build_decl (TYPE_DECL, get_identifier (name), type);
#endif
+ TYPE_STUB_DECL (type) = TYPE_NAME (type);
layout_decl (TYPE_NAME (type), 0);
}
@@ -2402,8 +2357,6 @@ finish_builtin_type (type, name, fields, len, align_type)
`operator new' and `operator delete' correspond to
what compiler will be expecting. */
-extern tree sizetype;
-
tree
coerce_new_type (type)
tree type;
@@ -2433,7 +2386,10 @@ tree
coerce_delete_type (type)
tree type;
{
- int e1 = 0, e2 = 0, e3 = 0;
+ int e1 = 0, e2 = 0;
+#if 0
+ e3 = 0;
+#endif
tree arg_types = TYPE_ARG_TYPES (type);
if (TREE_CODE (type) == METHOD_TYPE)
@@ -2441,12 +2397,15 @@ coerce_delete_type (type)
type = build_function_type (TREE_TYPE (type), TREE_CHAIN (arg_types));
arg_types = TREE_CHAIN (arg_types);
}
+
if (TREE_TYPE (type) != void_type_node)
e1 = 1, error ("`operator delete' must return type `void'");
+
if (arg_types == NULL_TREE
|| TREE_VALUE (arg_types) != ptr_type_node)
e2 = 1, error ("`operator delete' takes type `void *' as first parameter");
+#if 0
if (arg_types
&& TREE_CHAIN (arg_types)
&& TREE_CHAIN (arg_types) != void_list_node)
@@ -2466,8 +2425,10 @@ coerce_delete_type (type)
error ("`...' invalid in specification of `operator delete'");
}
}
+
if (e3)
- arg_types = tree_cons (NULL_TREE, ptr_type_node, build_tree_list (NULL_TREE, sizetype));
+ arg_types = tree_cons (NULL_TREE, ptr_type_node,
+ build_tree_list (NULL_TREE, sizetype));
else if (e3 |= e2)
{
if (arg_types == NULL_TREE)
@@ -2476,37 +2437,96 @@ coerce_delete_type (type)
arg_types = tree_cons (NULL_TREE, ptr_type_node, TREE_CHAIN (arg_types));
}
else e3 |= e1;
+#endif
- if (e3)
+ if (e2)
+ arg_types = tree_cons (NULL_TREE, ptr_type_node,
+ arg_types ? TREE_CHAIN (arg_types): NULL_TREE);
+ if (e2 || e1)
type = build_function_type (void_type_node, arg_types);
return type;
}
+extern tree abort_fndecl;
+
static void
mark_vtable_entries (decl)
tree decl;
{
tree entries = CONSTRUCTOR_ELTS (DECL_INITIAL (decl));
+ if (flag_rtti)
+ {
+ tree fnaddr = (flag_vtable_thunks ? TREE_VALUE (TREE_CHAIN (entries))
+ : FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (entries)));
+ tree fn = TREE_OPERAND (fnaddr, 0);
+ TREE_ADDRESSABLE (fn) = 1;
+ mark_used (fn);
+ }
skip_rtti_stuff (&entries);
for (; entries; entries = TREE_CHAIN (entries))
{
- tree fnaddr = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (entries));
+ tree fnaddr = (flag_vtable_thunks ? TREE_VALUE (entries)
+ : FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (entries)));
tree fn = TREE_OPERAND (fnaddr, 0);
TREE_ADDRESSABLE (fn) = 1;
- if (DECL_ABSTRACT_VIRTUAL_P (fn))
+ if (DECL_LANG_SPECIFIC (fn) && DECL_ABSTRACT_VIRTUAL_P (fn))
{
- extern tree abort_fndecl;
- if (flag_vtable_thunks)
- fnaddr = TREE_VALUE (entries);
- TREE_OPERAND (fnaddr, 0) = fn = abort_fndecl;
+ TREE_OPERAND (fnaddr, 0) = fn = copy_node (fn);
+ DECL_RTL (fn) = DECL_RTL (abort_fndecl);
+ mark_used (abort_fndecl);
+ }
+ if (TREE_CODE (fn) == THUNK_DECL && DECL_EXTERNAL (fn))
+ {
+ DECL_EXTERNAL (fn) = 0;
+ emit_thunk (fn);
}
- assemble_external (fn);
+ mark_used (fn);
}
}
+/* Set DECL up to have the closest approximation of "initialized common"
+ linkage available. */
+
+void
+comdat_linkage (decl)
+ tree decl;
+{
+ if (flag_weak)
+ make_decl_one_only (decl);
+ else
+ TREE_PUBLIC (decl) = 0;
+
+ if (DECL_LANG_SPECIFIC (decl))
+ DECL_COMDAT (decl) = 1;
+}
+
+/* For win32 we also want to put explicit instantiations in
+ linkonce sections, so that they will be merged with implicit
+ instantiations; otherwise we get duplicate symbol errors. */
+
+void
+maybe_make_one_only (decl)
+ tree decl;
+{
+ /* This is not necessary on targets that support weak symbols, because
+ the implicit instantiations will defer to the explicit one. */
+ if (! supports_one_only () || SUPPORTS_WEAK)
+ return;
+
+ /* We can't set DECL_COMDAT on functions, or finish_file will think
+ we can get away with not emitting them if they aren't used.
+ We can't use make_decl_one_only for variables, because their
+ DECL_INITIAL may not have been set properly yet. */
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ make_decl_one_only (decl);
+ else
+ comdat_linkage (decl);
+}
+
/* Set TREE_PUBLIC and/or DECL_EXTERN on the vtable DECL,
based on TYPE and other static flags.
@@ -2534,6 +2554,11 @@ import_export_vtable (decl, type, final)
TREE_PUBLIC (decl) = 1;
DECL_EXTERNAL (decl) = ! CLASSTYPE_VTABLE_NEEDS_WRITING (type);
DECL_INTERFACE_KNOWN (decl) = 1;
+
+ /* For WIN32 we also want to put explicit instantiations in
+ linkonce sections. */
+ if (CLASSTYPE_EXPLICIT_INSTANTIATION (type))
+ maybe_make_one_only (decl);
}
else
{
@@ -2542,11 +2567,12 @@ import_export_vtable (decl, type, final)
int found = CLASSTYPE_TEMPLATE_INSTANTIATION (type);
+#ifndef MULTIPLE_SYMBOL_SPACES
if (! found && ! final)
{
tree method;
- for (method = CLASSTYPE_METHODS (type); method != NULL_TREE;
- method = DECL_NEXT_METHOD (method))
+ for (method = TYPE_METHODS (type); method != NULL_TREE;
+ method = TREE_CHAIN (method))
if (DECL_VINDEX (method) != NULL_TREE
&& ! DECL_THIS_INLINE (method)
&& ! DECL_ABSTRACT_VIRTUAL_P (method))
@@ -2555,17 +2581,11 @@ import_export_vtable (decl, type, final)
break;
}
}
+#endif
if (final || ! found)
{
-#ifdef ASSEMBLE_EXTERNAL
- if (TREE_PUBLIC (decl))
- cp_error ("all virtual functions redeclared inline");
-#endif
- if (SUPPORTS_WEAK)
- DECL_WEAK (decl) = 1;
- else
- TREE_PUBLIC (decl) = 0;
+ comdat_linkage (decl);
DECL_EXTERNAL (decl) = 0;
}
else
@@ -2576,86 +2596,84 @@ import_export_vtable (decl, type, final)
}
}
-static void
-import_export_template (type)
- tree type;
-{
- if (CLASSTYPE_IMPLICIT_INSTANTIATION (type)
- && ! flag_implicit_templates
- && CLASSTYPE_INTERFACE_UNKNOWN (type))
- {
- SET_CLASSTYPE_INTERFACE_KNOWN (type);
- CLASSTYPE_INTERFACE_ONLY (type) = 1;
- CLASSTYPE_VTABLE_NEEDS_WRITING (type) = 0;
- }
-}
-
-static void
-finish_prevtable_vardecl (prev, vars)
- tree prev, vars;
+/* Determine whether or not we want to specifically import or export CTYPE,
+ using various heuristics. */
+
+void
+import_export_class (ctype)
+ tree ctype;
{
- tree ctype = DECL_CONTEXT (vars);
- import_export_template (ctype);
+ /* -1 for imported, 1 for exported. */
+ int import_export = 0;
+
+ if (CLASSTYPE_INTERFACE_KNOWN (ctype))
+ return;
+
+#ifdef VALID_MACHINE_TYPE_ATTRIBUTE
+ /* FIXME this should really use some sort of target-independent macro. */
+ if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype)))
+ import_export = -1;
+#endif
- if (CLASSTYPE_INTERFACE_UNKNOWN (ctype) && TYPE_VIRTUAL_P (ctype)
+ /* If we got -fno-implicit-templates, we import template classes that
+ weren't explicitly instantiated. */
+ if (import_export == 0
+ && CLASSTYPE_IMPLICIT_INSTANTIATION (ctype)
+ && ! flag_implicit_templates)
+ import_export = -1;
+
+#ifndef MULTIPLE_SYMBOL_SPACES
+ /* Base our import/export status on that of the first non-inline,
+ non-abstract virtual function, if any. */
+ if (import_export == 0
+ && TYPE_VIRTUAL_P (ctype)
&& ! CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
{
tree method;
- for (method = CLASSTYPE_METHODS (ctype); method != NULL_TREE;
- method = DECL_NEXT_METHOD (method))
+ for (method = TYPE_METHODS (ctype); method != NULL_TREE;
+ method = TREE_CHAIN (method))
{
if (DECL_VINDEX (method) != NULL_TREE
&& !DECL_THIS_INLINE (method)
&& !DECL_ABSTRACT_VIRTUAL_P (method))
{
- SET_CLASSTYPE_INTERFACE_KNOWN (ctype);
- CLASSTYPE_VTABLE_NEEDS_WRITING (ctype) = ! DECL_EXTERNAL (method);
- CLASSTYPE_INTERFACE_ONLY (ctype) = DECL_EXTERNAL (method);
+ import_export = (DECL_REALLY_EXTERN (method) ? -1 : 1);
break;
}
}
}
+#endif
- import_export_vtable (vars, ctype, 1);
-
- /* We cannot use TREE_USED here, as it may be set by the expanding of a
- ctor that is used to build a global object. The long term plan is to
- make the TD entries statically initialized and move this to
- finish_vtable_vardecl time. */
- if (flag_rtti && write_virtuals >= 0
- && ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || 1 || TREE_USED (vars)))
+ if (import_export)
{
- /* Kick out the type descriptor before we dump out global
- initializers, as they are initialized at run time and
- we have to find them when we scan for things that need initialized
- at the top level. */
- build_t_desc (ctype, 1);
+ SET_CLASSTYPE_INTERFACE_KNOWN (ctype);
+ CLASSTYPE_VTABLE_NEEDS_WRITING (ctype) = (import_export > 0);
+ CLASSTYPE_INTERFACE_ONLY (ctype) = (import_export < 0);
}
}
-static void
+static int
finish_vtable_vardecl (prev, vars)
tree prev, vars;
{
+ tree ctype = DECL_CONTEXT (vars);
+ import_export_class (ctype);
+ import_export_vtable (vars, ctype, 1);
+
if (write_virtuals >= 0
- && ! DECL_EXTERNAL (vars) && (TREE_PUBLIC (vars) || TREE_USED (vars)))
+ && ! DECL_EXTERNAL (vars)
+ && ((TREE_PUBLIC (vars) && ! DECL_WEAK (vars) && ! DECL_ONE_ONLY (vars))
+ || CLASSTYPE_EXPLICIT_INSTANTIATION (DECL_CONTEXT (vars))
+ || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars))
+ || (hack_decl_function_context (vars) && TREE_USED (vars)))
+ && ! TREE_ASM_WRITTEN (vars))
{
-#if 0
- /* The long term plan it to make the TD entries statically initialized,
- have the entries built and emitted here. When that happens, this
- can be enabled, and the other call to build_t_desc removed. */
- /* Kick out the type descriptor before writing out the vtable. */
- if (flag_rtti)
- build_t_desc (DECL_CONTEXT (vars), 1);
-#endif
-
/* Write it out. */
mark_vtable_entries (vars);
if (TREE_TYPE (DECL_INITIAL (vars)) == 0)
store_init_value (vars, DECL_INITIAL (vars));
-#ifdef DWARF_DEBUGGING_INFO
- if (write_symbols == DWARF_DEBUG)
+ if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
{
/* Mark the VAR_DECL node representing the vtable itself as a
"gratuitous" one, thereby forcing dwarfout.c to ignore it.
@@ -2680,32 +2698,35 @@ finish_vtable_vardecl (prev, vars)
DECL_IGNORED_P (vars) = 1;
}
-#endif /* DWARF_DEBUGGING_INFO */
rest_of_decl_compilation (vars, NULL_PTR, 1, 1);
+ return 1;
}
- else if (! TREE_USED (vars))
+ else if (! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (vars)))
/* We don't know what to do with this one yet. */
- return;
+ return 0;
/* We know that PREV must be non-zero here. */
TREE_CHAIN (prev) = TREE_CHAIN (vars);
+ return 0;
}
-static void
+static int
prune_vtable_vardecl (prev, vars)
tree prev, vars;
{
/* We know that PREV must be non-zero here. */
TREE_CHAIN (prev) = TREE_CHAIN (vars);
+ return 1;
}
-void
+int
walk_vtables (typedecl_fn, vardecl_fn)
- register void (*typedecl_fn)();
- register void (*vardecl_fn)();
+ register void (*typedecl_fn) PROTO ((tree, tree));
+ register int (*vardecl_fn) PROTO ((tree, tree));
{
tree prev, vars;
+ int flag = 0;
for (prev = 0, vars = getdecls (); vars; vars = TREE_CHAIN (vars))
{
@@ -2713,7 +2734,8 @@ walk_vtables (typedecl_fn, vardecl_fn)
if (TREE_CODE (vars) == VAR_DECL && DECL_VIRTUAL_P (vars))
{
- if (vardecl_fn) (*vardecl_fn) (prev, vars);
+ if (vardecl_fn)
+ flag |= (*vardecl_fn) (prev, vars);
if (prev && TREE_CHAIN (prev) != vars)
continue;
@@ -2728,6 +2750,8 @@ walk_vtables (typedecl_fn, vardecl_fn)
prev = vars;
}
+
+ return flag;
}
static void
@@ -2746,8 +2770,8 @@ finish_sigtable_vardecl (prev, vars)
void
walk_sigtables (typedecl_fn, vardecl_fn)
- register void (*typedecl_fn)();
- register void (*vardecl_fn)();
+ register void (*typedecl_fn) PROTO((tree, tree));
+ register void (*vardecl_fn) PROTO((tree, tree));
{
tree prev, vars;
@@ -2773,10 +2797,10 @@ walk_sigtables (typedecl_fn, vardecl_fn)
}
/* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an
- inline function at end-of-file. */
+ inline function or template instantiation at end-of-file. */
void
-import_export_inline (decl)
+import_export_decl (decl)
tree decl;
{
if (DECL_INTERFACE_KNOWN (decl))
@@ -2784,12 +2808,18 @@ import_export_inline (decl)
if (DECL_TEMPLATE_INSTANTIATION (decl))
{
- if (DECL_IMPLICIT_INSTANTIATION (decl) && flag_implicit_templates)
+ DECL_NOT_REALLY_EXTERN (decl) = 1;
+ if (DECL_IMPLICIT_INSTANTIATION (decl)
+ && (flag_implicit_templates || DECL_THIS_INLINE (decl)))
{
- if (SUPPORTS_WEAK)
- DECL_WEAK (decl) = 1;
+ if (!TREE_PUBLIC (decl))
+ /* Templates are allowed to have internal linkage. See
+ [basic.link]. */
+ ;
+ else if (TREE_CODE (decl) == FUNCTION_DECL)
+ comdat_linkage (decl);
else
- TREE_PUBLIC (decl) = 0;
+ DECL_COMDAT (decl) = 1;
}
else
DECL_NOT_REALLY_EXTERN (decl) = 0;
@@ -2797,31 +2827,307 @@ import_export_inline (decl)
else if (DECL_FUNCTION_MEMBER_P (decl))
{
tree ctype = DECL_CLASS_CONTEXT (decl);
- if (CLASSTYPE_INTERFACE_KNOWN (ctype) && ! DECL_ARTIFICIAL (decl))
+ import_export_class (ctype);
+ if (CLASSTYPE_INTERFACE_KNOWN (ctype)
+ && (! DECL_ARTIFICIAL (decl) || DECL_VINDEX (decl)))
{
DECL_NOT_REALLY_EXTERN (decl)
= ! (CLASSTYPE_INTERFACE_ONLY (ctype)
|| (DECL_THIS_INLINE (decl) && ! flag_implement_inlines));
}
- else if (SUPPORTS_WEAK)
- DECL_WEAK (decl) = 1;
else
- TREE_PUBLIC (decl) = 0;
+ comdat_linkage (decl);
}
- else if (DECL_C_STATIC (decl))
- TREE_PUBLIC (decl) = 0;
- else if (SUPPORTS_WEAK)
- DECL_WEAK (decl) = 1;
+ /* tinfo function */
+ else if (DECL_ARTIFICIAL (decl) && DECL_MUTABLE_P (decl))
+ {
+ tree ctype = TREE_TYPE (DECL_NAME (decl));
+
+ if (IS_AGGR_TYPE (ctype))
+ import_export_class (ctype);
+
+ if (IS_AGGR_TYPE (ctype) && CLASSTYPE_INTERFACE_KNOWN (ctype)
+ && TYPE_VIRTUAL_P (ctype)
+ /* If the type is a cv-qualified variant of a type, then we
+ must emit the tinfo function in this translation unit
+ since it will not be emitted when the vtable for the type
+ is output (which is when the unqualified version is
+ generated). */
+ && ctype == TYPE_MAIN_VARIANT (ctype))
+ {
+ DECL_NOT_REALLY_EXTERN (decl)
+ = ! (CLASSTYPE_INTERFACE_ONLY (ctype)
+ || (DECL_THIS_INLINE (decl) && ! flag_implement_inlines));
+
+ /* For WIN32 we also want to put explicit instantiations in
+ linkonce sections. */
+ if (CLASSTYPE_EXPLICIT_INSTANTIATION (ctype))
+ maybe_make_one_only (decl);
+ }
+ else if (TYPE_BUILT_IN (ctype) && ctype == TYPE_MAIN_VARIANT (ctype))
+ DECL_NOT_REALLY_EXTERN (decl) = 0;
+ else
+ comdat_linkage (decl);
+ }
else
- TREE_PUBLIC (decl) = 0;
+ comdat_linkage (decl);
DECL_INTERFACE_KNOWN (decl) = 1;
}
+tree
+build_cleanup (decl)
+ tree decl;
+{
+ tree temp;
+ tree type = TREE_TYPE (decl);
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ temp = decl;
+ else
+ {
+ mark_addressable (decl);
+ temp = build1 (ADDR_EXPR, build_pointer_type (type), decl);
+ }
+ temp = build_delete (TREE_TYPE (temp), temp,
+ integer_two_node,
+ LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+ return temp;
+}
+
extern int parse_time, varconst_time;
+extern tree pending_templates;
+extern tree maybe_templates;
+
+static tree
+get_sentry (base)
+ tree base;
+{
+ tree sname = get_id_2 ("__sn", base);
+ /* For struct X foo __attribute__((weak)), there is a counter
+ __snfoo. Since base is already an assembler name, sname should
+ be globally unique */
+ tree sentry = IDENTIFIER_GLOBAL_VALUE (sname);
+ if (! sentry)
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ sentry = build_decl (VAR_DECL, sname, integer_type_node);
+ TREE_PUBLIC (sentry) = 1;
+ DECL_ARTIFICIAL (sentry) = 1;
+ TREE_STATIC (sentry) = 1;
+ TREE_USED (sentry) = 1;
+ DECL_COMMON (sentry) = 1;
+ pushdecl_top_level (sentry);
+ cp_finish_decl (sentry, NULL_TREE, NULL_TREE, 0, 0);
+ pop_obstacks ();
+ }
+ return sentry;
+}
+
+/* Start the process of running a particular set of global constructors
+ or destructors. Subroutine of do_[cd]tors. */
+
+static void
+start_objects (method_type)
+ int method_type;
+{
+ tree fnname;
+
+ /* Make ctor or dtor function. METHOD_TYPE may be 'I' or 'D'. */
+
+ fnname = get_file_function_name (method_type);
+
+ start_function (void_list_node,
+ make_call_declarator (fnname, void_list_node, NULL_TREE,
+ NULL_TREE),
+ NULL_TREE, 0);
+
+#if defined(ASM_OUTPUT_CONSTRUCTOR) && defined(ASM_OUTPUT_DESTRUCTOR)
+ /* It can be a static function as long as collect2 does not have
+ to scan the object file to find its ctor/dtor routine. */
+ TREE_PUBLIC (current_function_decl) = 0;
+#endif
+
+ store_parm_decls ();
+ pushlevel (0);
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (0);
+}
+
+/* Finish the process of running a particular set of global constructors
+ or destructors. Subroutine of do_[cd]tors. */
-#define TIMEVAR(VAR, BODY) \
-do { int otime = get_run_time (); BODY; VAR += get_run_time () - otime; } while (0)
+static void
+finish_objects (method_type)
+ int method_type;
+{
+ char *fnname;
+
+ tree list = (method_type == 'I' ? static_ctors : static_dtors);
+
+ if (! current_function_decl && list)
+ start_objects (method_type);
+
+ for (; list; list = TREE_CHAIN (list))
+ expand_expr_stmt (build_function_call (TREE_VALUE (list), NULL_TREE));
+
+ if (! current_function_decl)
+ return;
+
+ fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+
+ /* Finish up. */
+ expand_end_bindings (getdecls (), 1, 0);
+ poplevel (1, 0, 0);
+ pop_momentary ();
+ finish_function (lineno, 0, 0);
+
+ if (method_type == 'I')
+ assemble_constructor (fnname);
+ else
+ assemble_destructor (fnname);
+}
+
+/* Generate a function to run a set of global destructors. Subroutine of
+ finish_file. */
+
+static void
+do_dtors ()
+{
+ tree vars = static_aggregates;
+
+ for (; vars; vars = TREE_CHAIN (vars))
+ {
+ tree decl = TREE_VALUE (vars);
+ tree type = TREE_TYPE (decl);
+ tree temp;
+
+ if (TYPE_NEEDS_DESTRUCTOR (type) && ! TREE_STATIC (vars)
+ && ! DECL_EXTERNAL (decl))
+ {
+ int protect = (TREE_PUBLIC (decl) && (DECL_COMMON (decl)
+ || DECL_ONE_ONLY (decl)
+ || DECL_WEAK (decl)));
+
+ if (! current_function_decl)
+ start_objects ('D');
+
+ temp = build_cleanup (decl);
+
+ if (protect)
+ {
+ tree sentry = get_sentry (DECL_ASSEMBLER_NAME (decl));
+ sentry = build_unary_op (PREDECREMENT_EXPR, sentry, 0);
+ sentry = build_binary_op (EQ_EXPR, sentry, integer_zero_node, 1);
+ expand_start_cond (sentry, 0);
+ }
+
+ expand_expr_stmt (temp);
+
+ if (protect)
+ expand_end_cond ();
+ }
+ }
+
+ finish_objects ('D');
+}
+
+/* Generate a function to run a set of global constructors. Subroutine of
+ finish_file. */
+
+static void
+do_ctors ()
+{
+ tree vars = static_aggregates;
+
+ /* Reverse the list so it's in the right order for ctors. */
+ vars = nreverse (vars);
+
+ for (; vars; vars = TREE_CHAIN (vars))
+ {
+ tree decl = TREE_VALUE (vars);
+ tree init = TREE_PURPOSE (vars);
+
+ /* If this was a static attribute within some function's scope,
+ then don't initialize it here. Also, don't bother
+ with initializers that contain errors. */
+ if (TREE_STATIC (vars)
+ || DECL_EXTERNAL (decl)
+ || (init && TREE_CODE (init) == TREE_LIST
+ && value_member (error_mark_node, init)))
+ continue;
+
+ if (TREE_CODE (decl) == VAR_DECL)
+ {
+ int protect = (TREE_PUBLIC (decl) && (DECL_COMMON (decl)
+ || DECL_ONE_ONLY (decl)
+ || DECL_WEAK (decl)));
+
+ if (! current_function_decl)
+ start_objects ('I');
+
+ /* Set these global variables so that GDB at least puts
+ us near the declaration which required the initialization. */
+ input_filename = DECL_SOURCE_FILE (decl);
+ lineno = DECL_SOURCE_LINE (decl);
+ emit_note (input_filename, lineno);
+
+ /* 9.5p5: The initializer of a static member of a class has
+ the same access rights as a member function. */
+ if (member_p (decl))
+ {
+ DECL_CLASS_CONTEXT (current_function_decl)
+ = DECL_CONTEXT (decl);
+ DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
+ }
+
+ if (protect)
+ {
+ tree sentry = get_sentry (DECL_ASSEMBLER_NAME (decl));
+ sentry = build_unary_op (PREINCREMENT_EXPR, sentry, 0);
+ sentry = build_binary_op
+ (EQ_EXPR, sentry, integer_one_node, 1);
+ expand_start_cond (sentry, 0);
+ }
+
+ expand_start_target_temps ();
+
+ if (IS_AGGR_TYPE (TREE_TYPE (decl))
+ || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+ expand_aggr_init (decl, init, 0, 0);
+ else if (TREE_CODE (init) == TREE_VEC)
+ {
+ expand_expr (expand_vec_init (decl, TREE_VEC_ELT (init, 0),
+ TREE_VEC_ELT (init, 1),
+ TREE_VEC_ELT (init, 2), 0),
+ const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+ else
+ expand_assignment (decl, init, 0, 0);
+
+ /* The expression might have involved increments and
+ decrements. */
+ emit_queue ();
+
+ /* Cleanup any temporaries needed for the initial value. */
+ expand_end_target_temps ();
+
+ if (protect)
+ expand_end_cond ();
+
+ DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
+ DECL_STATIC_FUNCTION_P (current_function_decl) = 0;
+ }
+ else if (decl == error_mark_node)
+ /* OK */;
+ else
+ my_friendly_abort (22);
+ }
+
+ finish_objects ('I');
+}
/* This routine is called from the last rule in yyparse ().
Its job is to create all the code needed to initialize and
@@ -2838,18 +3144,15 @@ finish_file ()
tree vars;
int needs_cleaning = 0, needs_messing_up = 0;
- if (flag_detailed_statistics)
- dump_tree_statistics ();
+ at_eof = 1;
/* Bad parse errors. Just forget about it. */
if (! global_bindings_p () || current_class_type)
return;
- start_time = get_run_time ();
+ check_decl_namespace ();
- /* Push into C language context, because that's all
- we'll need here. */
- push_lang_context (lang_name_c);
+ start_time = get_run_time ();
/* Otherwise, GDB can get confused, because in only knows
about source for LINENO-1 lines. */
@@ -2858,6 +3161,45 @@ finish_file ()
interface_unknown = 1;
interface_only = 0;
+ for (fnname = pending_templates; fnname; fnname = TREE_CHAIN (fnname))
+ {
+ tree srcloc = TREE_PURPOSE (fnname);
+ tree decl = TREE_VALUE (fnname);
+
+ input_filename = SRCLOC_FILE (srcloc);
+ lineno = SRCLOC_LINE (srcloc);
+
+ if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't')
+ {
+ instantiate_class_template (decl);
+ if (CLASSTYPE_TEMPLATE_INSTANTIATION (decl))
+ for (vars = TYPE_METHODS (decl); vars; vars = TREE_CHAIN (vars))
+ if (! DECL_ARTIFICIAL (vars))
+ instantiate_decl (vars);
+ }
+ else
+ instantiate_decl (decl);
+ }
+
+ for (fnname = maybe_templates; fnname; fnname = TREE_CHAIN (fnname))
+ {
+ tree args, fn, decl = TREE_VALUE (fnname);
+
+ if (DECL_INITIAL (decl))
+ continue;
+
+ fn = TREE_PURPOSE (fnname);
+ args = get_bindings (fn, decl, NULL_TREE);
+ fn = instantiate_template (fn, args);
+ instantiate_decl (fn);
+ }
+
+ cat_namespace_levels();
+
+ /* Push into C language context, because that's all
+ we'll need here. */
+ push_lang_context (lang_name_c);
+
#if 1
/* The reason for pushing garbage onto the global_binding_level is to
ensure that we can slice out _DECLs which pertain to virtual function
@@ -2870,7 +3212,7 @@ finish_file ()
virtual function tables, moving the implementation of this code to
decl.c (where we can manipulate global_binding_level directly),
popping the garbage after pushing it and slicing away the vtable
- stuff, or just leaving it alone. */
+ stuff, or just leaving it alone. */
/* Make last thing in global scope not be a virtual function table. */
#if 0 /* not yet, should get fixed properly later */
@@ -2883,199 +3225,28 @@ finish_file ()
pushdecl (vars);
#endif
- /* Walk to mark the inline functions we need, then output them so
- that we can pick up any other tdecls that those routines need. */
- walk_vtables ((void (*)())0, finish_prevtable_vardecl);
-
+ for (vars = static_aggregates; vars; vars = TREE_CHAIN (vars))
+ if (! TREE_ASM_WRITTEN (TREE_VALUE (vars)))
+ rest_of_decl_compilation (TREE_VALUE (vars), 0, 1, 1);
vars = static_aggregates;
- if (static_ctors || vars || might_have_exceptions_p ())
+ if (static_ctors || vars)
needs_messing_up = 1;
- if (static_dtors)
+ if (static_dtors || vars)
needs_cleaning = 1;
- /* See if we really need the hassle. */
- while (vars && needs_cleaning == 0)
- {
- tree decl = TREE_VALUE (vars);
- tree type = TREE_TYPE (decl);
- if (TYPE_NEEDS_DESTRUCTOR (type))
- {
- needs_cleaning = 1;
- needs_messing_up = 1;
- break;
- }
- else
- needs_messing_up |= TYPE_NEEDS_CONSTRUCTING (type);
- vars = TREE_CHAIN (vars);
- }
-
- if (needs_cleaning == 0)
- goto mess_up;
-
- fnname = get_file_function_name ('D');
- start_function (void_list_node,
- build_parse_node (CALL_EXPR, fnname, void_list_node,
- NULL_TREE),
- NULL_TREE, NULL_TREE, 0);
- fnname = DECL_ASSEMBLER_NAME (current_function_decl);
- store_parm_decls ();
-
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
-
- /* These must be done in backward order to destroy,
- in which they happen to be! */
- for (vars = static_aggregates; vars; vars = TREE_CHAIN (vars))
+ /* The aggregates are listed in reverse declaration order, for cleaning. */
+ if (needs_cleaning)
{
- tree decl = TREE_VALUE (vars);
- tree type = TREE_TYPE (decl);
- tree temp = TREE_PURPOSE (vars);
-
- if (TYPE_NEEDS_DESTRUCTOR (type))
- {
- if (TREE_STATIC (vars))
- expand_start_cond (build_binary_op (NE_EXPR, temp, integer_zero_node, 1), 0);
- if (TREE_CODE (type) == ARRAY_TYPE)
- temp = decl;
- else
- {
- mark_addressable (decl);
- temp = build1 (ADDR_EXPR, build_pointer_type (type), decl);
- }
- temp = build_delete (TREE_TYPE (temp), temp,
- integer_two_node, LOOKUP_NORMAL|LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
- expand_expr_stmt (temp);
-
- if (TREE_STATIC (vars))
- expand_end_cond ();
- }
+ do_dtors ();
}
- for (; static_dtors; static_dtors = TREE_CHAIN (static_dtors))
- expand_expr_stmt (build_function_call (TREE_VALUE (static_dtors),
- NULL_TREE));
-
- expand_end_bindings (getdecls(), 1, 0);
- poplevel (1, 0, 0);
- pop_momentary ();
-
- finish_function (lineno, 0, 0);
-
- assemble_destructor (IDENTIFIER_POINTER (fnname));
-
- /* if it needed cleaning, then it will need messing up: drop through */
-
- mess_up:
- /* Must do this while we think we are at the top level. */
- vars = nreverse (static_aggregates);
+ /* do_ctors will reverse the lists for messing up. */
if (needs_messing_up)
{
- fnname = get_file_function_name ('I');
- start_function (void_list_node,
- build_parse_node (CALL_EXPR, fnname,
- void_list_node, NULL_TREE),
- NULL_TREE, NULL_TREE, 0);
- fnname = DECL_ASSEMBLER_NAME (current_function_decl);
- store_parm_decls ();
-
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
-
- if (might_have_exceptions_p ())
- register_exception_table ();
-
- while (vars)
- {
- tree decl = TREE_VALUE (vars);
- tree init = TREE_PURPOSE (vars);
- tree old_cleanups = cleanups_this_call;
-
- /* If this was a static attribute within some function's scope,
- then don't initialize it here. Also, don't bother
- with initializers that contain errors. */
- if (TREE_STATIC (vars)
- || (init && TREE_CODE (init) == TREE_LIST
- && value_member (error_mark_node, init)))
- {
- vars = TREE_CHAIN (vars);
- continue;
- }
-
- if (TREE_CODE (decl) == VAR_DECL)
- {
- /* Set these global variables so that GDB at least puts
- us near the declaration which required the initialization. */
- input_filename = DECL_SOURCE_FILE (decl);
- lineno = DECL_SOURCE_LINE (decl);
- emit_note (input_filename, lineno);
-
- /* 9.5p5: The initializer of a static member of a class has
- the same access rights as a member function. */
- DECL_CLASS_CONTEXT (current_function_decl) = DECL_CONTEXT (decl);
- DECL_STATIC_FUNCTION_P (current_function_decl) = 1;
-
- if (IS_AGGR_TYPE (TREE_TYPE (decl))
- || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
- expand_aggr_init (decl, init, 0, 0);
- else if (TREE_CODE (init) == TREE_VEC)
- {
- expand_expr (expand_vec_init (decl, TREE_VEC_ELT (init, 0),
- TREE_VEC_ELT (init, 1),
- TREE_VEC_ELT (init, 2), 0),
- const0_rtx, VOIDmode, 0);
- free_temp_slots ();
- }
- else
- expand_assignment (decl, init, 0, 0);
-
- DECL_CLASS_CONTEXT (current_function_decl) = NULL_TREE;
- }
- else if (TREE_CODE (decl) == SAVE_EXPR)
- {
- if (! PARM_DECL_EXPR (decl))
- {
- /* a `new' expression at top level. */
- expand_expr (decl, const0_rtx, VOIDmode, 0);
- free_temp_slots ();
- if (TREE_CODE (init) == TREE_VEC)
- {
- expand_expr (expand_vec_init (decl, TREE_VEC_ELT (init, 0),
- TREE_VEC_ELT (init, 1),
- TREE_VEC_ELT (init, 2), 0),
- const0_rtx, VOIDmode, 0);
- free_temp_slots ();
- }
- else
- expand_aggr_init (build_indirect_ref (decl, NULL_PTR), init, 0, 0);
- }
- }
- else if (decl == error_mark_node)
- ;
- else my_friendly_abort (22);
- vars = TREE_CHAIN (vars);
- /* Cleanup any temporaries needed for the initial value. */
- expand_cleanups_to (old_cleanups);
- }
-
- for (; static_ctors; static_ctors = TREE_CHAIN (static_ctors))
- expand_expr_stmt (build_function_call (TREE_VALUE (static_ctors),
- NULL_TREE));
-
- expand_end_bindings (getdecls(), 1, 0);
- poplevel (1, 0, 0);
- pop_momentary ();
-
- finish_function (lineno, 0, 0);
- assemble_constructor (IDENTIFIER_POINTER (fnname));
+ do_ctors ();
}
- expand_builtin_throw ();
-
permanent_allocation (1);
/* Done with C language context needs. */
@@ -3086,10 +3257,21 @@ finish_file ()
while (pending_statics)
{
tree decl = TREE_VALUE (pending_statics);
- if (TREE_USED (decl) == 1
- || TREE_READONLY (decl) == 0
- || DECL_INITIAL (decl) == 0)
- rest_of_decl_compilation (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), 1, 1);
+
+ /* Output DWARF debug information. */
+#ifdef DWARF_DEBUGGING_INFO
+ if (write_symbols == DWARF_DEBUG)
+ dwarfout_file_scope_decl (decl, 1);
+#endif
+#ifdef DWARF2_DEBUGGING_INFO
+ if (write_symbols == DWARF2_DEBUG)
+ dwarf2out_decl (decl);
+#endif
+
+ DECL_DEFER_OUTPUT (decl) = 0;
+ rest_of_decl_compilation
+ (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), 1, 1);
+
pending_statics = TREE_CHAIN (pending_statics);
}
@@ -3100,18 +3282,17 @@ finish_file ()
start_time = get_run_time ();
if (flag_handle_signatures)
- walk_sigtables ((void (*)())0, finish_sigtable_vardecl);
+ walk_sigtables ((void (*) PROTO ((tree, tree))) 0,
+ finish_sigtable_vardecl);
for (fnname = saved_inlines; fnname; fnname = TREE_CHAIN (fnname))
{
tree decl = TREE_VALUE (fnname);
- import_export_inline (decl);
- if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
- && TREE_PUBLIC (decl) && ! DECL_WEAK (decl)
- && DECL_NOT_REALLY_EXTERN (decl))
- synthesize_method (decl);
+ import_export_decl (decl);
}
+ mark_all_runtime_matches ();
+
/* Now write out inline functions which had their addresses taken and
which were not declared virtual and which were not declared `extern
inline'. */
@@ -3120,87 +3301,92 @@ finish_file ()
while (reconsider)
{
- tree last = saved_inlines = tree_cons (NULL_TREE, NULL_TREE,
- saved_inlines);
- tree last_head = last;
- tree place = TREE_CHAIN (saved_inlines);
+ tree *p = &saved_inlines;
reconsider = 0;
- walk_vtables ((void (*)())0, finish_vtable_vardecl);
+ /* We need to do this each time so that newly completed template
+ types don't wind up at the front of the list. Sigh. */
+ vars = build_decl (TYPE_DECL, make_anon_name (), integer_type_node);
+ DECL_IGNORED_P (vars) = 1;
+ SET_DECL_ARTIFICIAL (vars);
+ pushdecl (vars);
- for (; place; place = TREE_CHAIN (place))
- {
- tree decl = TREE_VALUE (place);
+ reconsider |= walk_vtables ((void (*) PROTO((tree, tree))) 0,
+ finish_vtable_vardecl);
- /* Slice out the empty elements put in just above in the
- previous reconsidering. */
- if (decl == NULL_TREE)
- {
- TREE_CHAIN (last) = TREE_CHAIN (place);
- continue;
- }
+ while (*p)
+ {
+ tree decl = TREE_VALUE (*p);
- if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl))
+ if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
+ && TREE_USED (decl)
+ && (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl)))
{
- if (TREE_USED (decl))
- {
- synthesize_method (decl);
- if (TREE_ASM_WRITTEN (decl))
- reconsider = 1;
- }
+ if (DECL_MUTABLE_P (decl))
+ synthesize_tinfo_fn (decl);
else
- {
- last = place;
- continue;
- }
+ synthesize_method (decl);
+ reconsider = 1;
}
- if (TREE_ASM_WRITTEN (decl) || DECL_SAVED_INSNS (decl) == 0)
- {
- TREE_CHAIN (last) = TREE_CHAIN (place);
- continue;
- }
+ /* Catch new template instantiations. */
+ if (decl != TREE_VALUE (*p))
+ continue;
- if ((TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
- || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
- || flag_keep_inline_functions)
+ if (TREE_ASM_WRITTEN (decl)
+ || (DECL_SAVED_INSNS (decl) == 0 && ! DECL_ARTIFICIAL (decl)))
+ *p = TREE_CHAIN (*p);
+ else if (DECL_INITIAL (decl) == 0)
+ p = &TREE_CHAIN (*p);
+ else if ((TREE_PUBLIC (decl) && ! DECL_COMDAT (decl))
+ || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))
+ || flag_keep_inline_functions)
{
- TREE_CHAIN (last) = TREE_CHAIN (place);
-
if (DECL_NOT_REALLY_EXTERN (decl))
{
DECL_EXTERNAL (decl) = 0;
reconsider = 1;
- temporary_allocation ();
+ /* We can't inline this function after it's been
+ emitted. We want a variant of
+ output_inline_function that doesn't prevent
+ subsequent integration... */
+ DECL_INLINE (decl) = 0;
output_inline_function (decl);
permanent_allocation (1);
}
- continue;
+ *p = TREE_CHAIN (*p);
}
-
- last = place;
+ else
+ p = &TREE_CHAIN (*p);
}
}
+
+ /* It's possible that some of the remaining inlines will still be
+ needed. For example, a static inline whose address is used in
+ the initializer for a file-scope static variable will be
+ needed. Code in compile_file will handle this, but we mustn't
+ pretend that there are no definitions for the inlines, or it
+ won't be able to.
+
+ FIXME: This won't catch member functions. We should really
+ unify this stuff with the compile_file stuff. */
+ for (vars = saved_inlines; vars != NULL_TREE; vars = TREE_CHAIN (vars))
+ {
+ tree decl = TREE_VALUE (vars);
+
+ if (DECL_NOT_REALLY_EXTERN (decl)
+ && !DECL_COMDAT (decl)
+ && DECL_INITIAL (decl) != NULL_TREE)
+ DECL_EXTERNAL (decl) = 0;
+ }
}
/* Now delete from the chain of variables all virtual function tables.
We output them all ourselves, because each will be treated specially. */
- walk_vtables ((void (*)())0, prune_vtable_vardecl);
-
- for (vars = getdecls (); vars; vars = TREE_CHAIN (vars))
- {
- if (TREE_CODE (vars) == THUNK_DECL)
- emit_thunk (vars);
- else if (TREE_CODE (vars) == FUNCTION_DECL
- && ! DECL_INTERFACE_KNOWN (vars)
- && DECL_C_STATIC (vars))
- TREE_PUBLIC (vars) = 0;
- }
-
- if (might_have_exceptions_p ())
- emit_exception_table ();
+ walk_vtables ((void (*) PROTO((tree, tree))) 0,
+ prune_vtable_vardecl);
if (write_virtuals == 2)
{
@@ -3222,7 +3408,10 @@ finish_file ()
varconst_time += this_time - start_time;
if (flag_detailed_statistics)
- dump_time_statistics ();
+ {
+ dump_tree_statistics ();
+ dump_time_statistics ();
+ }
}
/* This is something of the form 'A()()()()()+1' that has turned out to be an
@@ -3233,6 +3422,7 @@ finish_file ()
Maybe this shouldn't be recursive, but how often will it actually be
used? (jason) */
+
tree
reparse_absdcl_as_expr (type, decl)
tree type, decl;
@@ -3244,7 +3434,7 @@ reparse_absdcl_as_expr (type, decl)
/* recurse */
decl = reparse_decl_as_expr (type, TREE_OPERAND (decl, 0));
- decl = build_x_function_call (decl, NULL_TREE, current_class_decl);
+ decl = build_x_function_call (decl, NULL_TREE, current_class_ref);
if (TREE_CODE (decl) == CALL_EXPR && TREE_TYPE (decl) != void_type_node)
decl = require_complete_type (decl);
@@ -3259,13 +3449,15 @@ reparse_absdcl_as_expr (type, decl)
In the above example, DECL is the `(int)(int)(int)', and EXPR is the
`1'. */
+
tree
reparse_absdcl_as_casts (decl, expr)
tree decl, expr;
{
tree type;
- if (TREE_CODE (expr) == CONSTRUCTOR)
+ if (TREE_CODE (expr) == CONSTRUCTOR
+ && TREE_TYPE (expr) == 0)
{
type = groktypename (TREE_VALUE (TREE_OPERAND (decl, 1)));
decl = TREE_OPERAND (decl, 0);
@@ -3289,62 +3481,298 @@ reparse_absdcl_as_casts (decl, expr)
{
type = groktypename (TREE_VALUE (TREE_OPERAND (decl, 1)));
decl = TREE_OPERAND (decl, 0);
- expr = build_c_cast (type, expr, 0);
+ expr = build_c_cast (type, expr);
}
+ if (warn_old_style_cast)
+ warning ("use of old-style cast");
+
return expr;
}
-/* Recursive helper function for reparse_decl_as_expr. It may be a good
- idea to reimplement this using an explicit stack, rather than recursion. */
-static tree
-reparse_decl_as_expr1 (decl)
- tree decl;
+/* Given plain tree nodes for an expression, build up the full semantics. */
+
+tree
+build_expr_from_tree (t)
+ tree t;
{
- switch (TREE_CODE (decl))
+ if (t == NULL_TREE || t == error_mark_node)
+ return t;
+
+ switch (TREE_CODE (t))
{
case IDENTIFIER_NODE:
- return do_identifier (decl);
+ return do_identifier (t, 0, NULL_TREE);
+
+ case LOOKUP_EXPR:
+ if (LOOKUP_EXPR_GLOBAL (t))
+ return do_scoped_id (TREE_OPERAND (t, 0), 0);
+ else
+ return do_identifier (TREE_OPERAND (t, 0), 0, NULL_TREE);
+
+ case TEMPLATE_ID_EXPR:
+ return (lookup_template_function
+ (build_expr_from_tree (TREE_OPERAND (t, 0)),
+ build_expr_from_tree (TREE_OPERAND (t, 1))));
+
case INDIRECT_REF:
return build_x_indirect_ref
- (reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)), "unary *");
- case ADDR_EXPR:
- return build_x_unary_op (ADDR_EXPR,
- reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)));
+ (build_expr_from_tree (TREE_OPERAND (t, 0)), "unary *");
+
+ case CAST_EXPR:
+ return build_functional_cast
+ (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+ case REINTERPRET_CAST_EXPR:
+ return build_reinterpret_cast
+ (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+ case CONST_CAST_EXPR:
+ return build_const_cast
+ (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+ case DYNAMIC_CAST_EXPR:
+ return build_dynamic_cast
+ (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+ case STATIC_CAST_EXPR:
+ return build_static_cast
+ (TREE_TYPE (t), build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case NEGATE_EXPR:
case BIT_NOT_EXPR:
- return build_x_unary_op (BIT_NOT_EXPR,
- reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)));
+ case ABS_EXPR:
+ case TRUTH_NOT_EXPR:
+ case ADDR_EXPR:
+ case CONVERT_EXPR: /* Unary + */
+ if (TREE_TYPE (t))
+ return t;
+ return build_x_unary_op (TREE_CODE (t),
+ build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_ANDTC_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case TRUNC_MOD_EXPR:
+ case FLOOR_MOD_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case RSHIFT_EXPR:
+ case LSHIFT_EXPR:
+ case RROTATE_EXPR:
+ case LROTATE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case MAX_EXPR:
+ case MIN_EXPR:
+ case LE_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case GT_EXPR:
+ case MEMBER_REF:
+ return build_x_binary_op
+ (TREE_CODE (t),
+ build_expr_from_tree (TREE_OPERAND (t, 0)),
+ build_expr_from_tree (TREE_OPERAND (t, 1)));
+
+ case DOTSTAR_EXPR:
+ return build_m_component_ref
+ (build_expr_from_tree (TREE_OPERAND (t, 0)),
+ build_expr_from_tree (TREE_OPERAND (t, 1)));
+
case SCOPE_REF:
- return build_offset_ref (TREE_OPERAND (decl, 0), TREE_OPERAND (decl, 1));
+ return build_offset_ref (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1));
+
case ARRAY_REF:
- return grok_array_decl (reparse_decl_as_expr1 (TREE_OPERAND (decl, 0)),
- TREE_OPERAND (decl, 1));
+ if (TREE_OPERAND (t, 0) == NULL_TREE)
+ /* new-type-id */
+ return build_parse_node (ARRAY_REF, NULL_TREE,
+ build_expr_from_tree (TREE_OPERAND (t, 1)));
+ return grok_array_decl (build_expr_from_tree (TREE_OPERAND (t, 0)),
+ build_expr_from_tree (TREE_OPERAND (t, 1)));
+
+ case SIZEOF_EXPR:
+ case ALIGNOF_EXPR:
+ {
+ tree r = build_expr_from_tree (TREE_OPERAND (t, 0));
+ if (TREE_CODE_CLASS (TREE_CODE (r)) != 't')
+ r = TREE_TYPE (r);
+ return TREE_CODE (t) == SIZEOF_EXPR ? c_sizeof (r) : c_alignof (r);
+ }
+
+ case MODOP_EXPR:
+ return build_x_modify_expr
+ (build_expr_from_tree (TREE_OPERAND (t, 0)),
+ TREE_CODE (TREE_OPERAND (t, 1)),
+ build_expr_from_tree (TREE_OPERAND (t, 2)));
+
+ case ARROW_EXPR:
+ return build_x_arrow
+ (build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+ case NEW_EXPR:
+ return build_new
+ (build_expr_from_tree (TREE_OPERAND (t, 0)),
+ build_expr_from_tree (TREE_OPERAND (t, 1)),
+ build_expr_from_tree (TREE_OPERAND (t, 2)),
+ NEW_EXPR_USE_GLOBAL (t));
+
+ case DELETE_EXPR:
+ return delete_sanity
+ (build_expr_from_tree (TREE_OPERAND (t, 0)),
+ build_expr_from_tree (TREE_OPERAND (t, 1)),
+ DELETE_EXPR_USE_VEC (t), DELETE_EXPR_USE_GLOBAL (t));
+
+ case COMPOUND_EXPR:
+ if (TREE_OPERAND (t, 1) == NULL_TREE)
+ return build_x_compound_expr
+ (build_expr_from_tree (TREE_OPERAND (t, 0)));
+ else
+ my_friendly_abort (42);
+
+ case METHOD_CALL_EXPR:
+ if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF)
+ {
+ tree ref = TREE_OPERAND (t, 0);
+ return build_scoped_method_call
+ (build_expr_from_tree (TREE_OPERAND (t, 1)),
+ build_expr_from_tree (TREE_OPERAND (ref, 0)),
+ TREE_OPERAND (ref, 1),
+ build_expr_from_tree (TREE_OPERAND (t, 2)));
+ }
+ return build_method_call
+ (build_expr_from_tree (TREE_OPERAND (t, 1)),
+ TREE_OPERAND (t, 0),
+ build_expr_from_tree (TREE_OPERAND (t, 2)),
+ NULL_TREE, LOOKUP_NORMAL);
+
+ case CALL_EXPR:
+ if (TREE_CODE (TREE_OPERAND (t, 0)) == SCOPE_REF)
+ {
+ tree ref = TREE_OPERAND (t, 0);
+ return build_member_call
+ (build_expr_from_tree (TREE_OPERAND (ref, 0)),
+ TREE_OPERAND (ref, 1),
+ build_expr_from_tree (TREE_OPERAND (t, 1)));
+ }
+ else
+ {
+ tree name = TREE_OPERAND (t, 0);
+ tree id;
+ tree args = build_expr_from_tree (TREE_OPERAND (t, 1));
+ if (args != NULL_TREE && TREE_CODE (name) == LOOKUP_EXPR
+ && !LOOKUP_EXPR_GLOBAL (name)
+ && TREE_CODE ((id = TREE_OPERAND (name, 0))) == IDENTIFIER_NODE
+ && (!current_class_type
+ || !lookup_member (current_class_type, id, 0, 0)))
+ {
+ /* Do Koenig lookup if there are no class members. */
+ name = do_identifier (id, 0, args);
+ }
+ else if (TREE_CODE (name) == TEMPLATE_ID_EXPR
+ || ! really_overloaded_fn (name))
+ name = build_expr_from_tree (name);
+ return build_x_function_call (name, args, current_class_ref);
+ }
+
+ case COND_EXPR:
+ return build_x_conditional_expr
+ (build_expr_from_tree (TREE_OPERAND (t, 0)),
+ build_expr_from_tree (TREE_OPERAND (t, 1)),
+ build_expr_from_tree (TREE_OPERAND (t, 2)));
+
+ case TREE_LIST:
+ {
+ tree purpose, value, chain;
+
+ if (t == void_list_node)
+ return t;
+
+ purpose = TREE_PURPOSE (t);
+ if (purpose)
+ purpose = build_expr_from_tree (purpose);
+ value = TREE_VALUE (t);
+ if (value)
+ value = build_expr_from_tree (value);
+ chain = TREE_CHAIN (t);
+ if (chain && chain != void_type_node)
+ chain = build_expr_from_tree (chain);
+ return expr_tree_cons (purpose, value, chain);
+ }
+
+ case COMPONENT_REF:
+ return build_x_component_ref
+ (build_expr_from_tree (TREE_OPERAND (t, 0)),
+ TREE_OPERAND (t, 1), NULL_TREE, 1);
+
+ case THROW_EXPR:
+ return build_throw (build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+ case CONSTRUCTOR:
+ {
+ tree r;
+
+ /* digest_init will do the wrong thing if we let it. */
+ if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
+ return t;
+
+ r = build_nt (CONSTRUCTOR, NULL_TREE,
+ build_expr_from_tree (CONSTRUCTOR_ELTS (t)));
+
+ if (TREE_TYPE (t))
+ return digest_init (TREE_TYPE (t), r, 0);
+ return r;
+ }
+
+ case TYPEID_EXPR:
+ if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 0))) == 't')
+ return get_typeid (TREE_OPERAND (t, 0));
+ return build_x_typeid (build_expr_from_tree (TREE_OPERAND (t, 0)));
+
+ case VAR_DECL:
+ return convert_from_reference (t);
+
default:
- my_friendly_abort (5);
- return NULL_TREE;
+ return t;
}
}
/* This is something of the form `int (*a)++' that has turned out to be an
expr. It was only converted into parse nodes, so we need to go through
and build up the semantics. Most of the work is done by
- reparse_decl_as_expr1, above.
+ build_expr_from_tree, above.
In the above example, TYPE is `int' and DECL is `*a'. */
+
tree
reparse_decl_as_expr (type, decl)
tree type, decl;
{
- decl = reparse_decl_as_expr1 (decl);
+ decl = build_expr_from_tree (decl);
if (type)
- return build_functional_cast (type, build_tree_list (NULL_TREE, decl));
+ return build_functional_cast (type, build_expr_list (NULL_TREE, decl));
else
return decl;
}
/* This is something of the form `int (*a)' that has turned out to be a
decl. It was only converted into parse nodes, so we need to do the
- checking that make_{pointer,reference}_declarator do. */
+ checking that make_{pointer,reference}_declarator do. */
tree
finish_decl_parsing (decl)
@@ -3385,20 +3813,13 @@ check_cp_case_value (value)
if (value == NULL_TREE)
return value;
- /* build_c_cast puts on a NOP_EXPR to make a non-lvalue.
- Strip such NOP_EXPRs. */
- if (TREE_CODE (value) == NOP_EXPR
- && TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0)))
- value = TREE_OPERAND (value, 0);
+ /* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
+ STRIP_TYPE_NOPS (value);
if (TREE_READONLY_DECL_P (value))
{
value = decl_constant_value (value);
- /* build_c_cast puts on a NOP_EXPR to make a non-lvalue.
- Strip such NOP_EXPRs. */
- if (TREE_CODE (value) == NOP_EXPR
- && TREE_TYPE (value) == TREE_TYPE (TREE_OPERAND (value, 0)))
- value = TREE_OPERAND (value, 0);
+ STRIP_TYPE_NOPS (value);
}
value = fold (value);
@@ -3418,81 +3839,832 @@ check_cp_case_value (value)
return value;
}
-tree current_namespace;
+/* Return 1 if root encloses child. */
-/* Get the inner part of a namespace id. It doesn't have any prefix, nor
- postfix. Returns 0 if in global namespace. */
-tree
-get_namespace_id ()
+static int
+is_namespace_ancestor (root, child)
+ tree root, child;
{
- tree x = current_namespace;
- if (x)
- x = TREE_PURPOSE (x);
- return x;
+ if (root == child)
+ return 1;
+ if (root == global_namespace)
+ return 1;
+ if (child == global_namespace)
+ return 0;
+ return is_namespace_ancestor (root, CP_DECL_CONTEXT (child));
}
+
+
+/* Return the namespace that is the common ancestor
+ of two given namespaces. */
-/* Build up a DECL_ASSEMBLER_NAME for NAME in the current namespace. */
tree
-current_namespace_id (name)
+namespace_ancestor (ns1, ns2)
+ tree ns1, ns2;
+{
+ if (is_namespace_ancestor (ns1, ns2))
+ return ns1;
+ return namespace_ancestor (CP_DECL_CONTEXT (ns1), ns2);
+}
+
+/* Insert used into the using list of user. Set indirect_flag if this
+ directive is not directly from the source. Also find the common
+ ancestor and let our users know about the new namespace */
+static void
+add_using_namespace (user, used, indirect)
+ tree user;
+ tree used;
+ int indirect;
+{
+ tree t;
+ /* Using oneself is a no-op. */
+ if (user == used)
+ return;
+ my_friendly_assert (TREE_CODE (user) == NAMESPACE_DECL, 380);
+ my_friendly_assert (TREE_CODE (used) == NAMESPACE_DECL, 380);
+ /* Check if we already have this. */
+ t = purpose_member (used, DECL_NAMESPACE_USING (user));
+ if (t != NULL_TREE)
+ {
+ if (!indirect)
+ /* Promote to direct usage. */
+ TREE_INDIRECT_USING (t) = 0;
+ return;
+ }
+
+ /* Add used to the user's using list. */
+ DECL_NAMESPACE_USING (user)
+ = perm_tree_cons (used, namespace_ancestor (user, used),
+ DECL_NAMESPACE_USING (user));
+
+ TREE_INDIRECT_USING (DECL_NAMESPACE_USING (user)) = indirect;
+
+ /* Add user to the used's users list. */
+ DECL_NAMESPACE_USERS (used)
+ = perm_tree_cons (user, 0, DECL_NAMESPACE_USERS (used));
+
+ /* Recursively add all namespaces used. */
+ for (t = DECL_NAMESPACE_USING (used); t; t = TREE_CHAIN (t))
+ /* indirect usage */
+ add_using_namespace (user, TREE_PURPOSE (t), 1);
+
+ /* Tell everyone using us about the new used namespaces. */
+ for (t = DECL_NAMESPACE_USERS (user); t; t = TREE_CHAIN (t))
+ add_using_namespace (TREE_PURPOSE (t), used, 1);
+}
+
+/* Combines two sets of overloaded functions into an OVERLOAD chain, removing
+ duplicates. The first list becomes the tail of the result.
+
+ The algorithm is O(n^2). */
+
+static tree
+merge_functions (s1, s2)
+ tree s1;
+ tree s2;
+{
+ for (; s2; s2 = OVL_NEXT (s2))
+ {
+ tree fn = OVL_CURRENT (s2);
+ if (! ovl_member (fn, s1))
+ s1 = build_overload (fn, s1);
+ }
+ return s1;
+}
+
+/* This should return an error not all definitions define functions.
+ It is not an error if we find two functions with exactly the
+ same signature, only if these are selected in overload resolution.
+ old is the current set of bindings, new the freshly-found binding.
+ XXX Do we want to give *all* candidates in case of ambiguity?
+ XXX In what way should I treat extern declarations?
+ XXX I don't want to repeat the entire duplicate_decls here */
+
+static tree
+ambiguous_decl (name, old, new, flags)
tree name;
+ tree old;
+ tree new;
+ int flags;
{
- tree old_id = get_namespace_id ();
- char *buf;
+ tree val, type;
+ my_friendly_assert (old != NULL_TREE, 393);
+ /* Copy the value. */
+ val = BINDING_VALUE (new);
+ if (val)
+ switch (TREE_CODE (val))
+ {
+ case TEMPLATE_DECL:
+ /* If we expect types or namespaces, and not templates,
+ or this is not a template class. */
+ if (LOOKUP_QUALIFIERS_ONLY (flags)
+ && (!(flags & LOOKUP_TEMPLATES_EXPECTED)
+ || !DECL_CLASS_TEMPLATE_P (val)))
+ val = NULL_TREE;
+ break;
+ case TYPE_DECL:
+ if (LOOKUP_NAMESPACES_ONLY (flags))
+ val = NULL_TREE;
+ break;
+ case NAMESPACE_DECL:
+ if (LOOKUP_TYPES_ONLY (flags))
+ val = NULL_TREE;
+ break;
+ default:
+ if (LOOKUP_QUALIFIERS_ONLY (flags))
+ val = NULL_TREE;
+ }
+
+ if (!BINDING_VALUE (old))
+ BINDING_VALUE (old) = val;
+ else if (val && val != BINDING_VALUE (old))
+ {
+ if (is_overloaded_fn (BINDING_VALUE (old))
+ && is_overloaded_fn (val))
+ {
+ BINDING_VALUE (old) = merge_functions (BINDING_VALUE (old),
+ val);
+ }
+ else
+ {
+ /* Some declarations are functions, some are not. */
+ if (flags & LOOKUP_COMPLAIN)
+ {
+ cp_error ("use of `%D' is ambiguous", name);
+ cp_error_at (" first declared as `%#D' here",
+ BINDING_VALUE (old));
+ cp_error_at (" also declared as `%#D' here", val);
+ }
+ return error_mark_node;
+ }
+ }
+ /* ... and copy the type. */
+ type = BINDING_TYPE (new);
+ if (LOOKUP_NAMESPACES_ONLY (flags))
+ type = NULL_TREE;
+ if (!BINDING_TYPE (old))
+ BINDING_TYPE (old) = type;
+ else if (type && BINDING_TYPE (old) != type)
+ {
+ if (flags & LOOKUP_COMPLAIN)
+ {
+ cp_error ("`%D' denotes an ambiguous type",name);
+ cp_error_at (" first type here", BINDING_TYPE (old));
+ cp_error_at (" other type here", type);
+ }
+ }
+ return old;
+}
- /* Global names retain old encoding. */
- if (! old_id)
- return name;
+/* Add the bindings of name in used namespaces to val.
+ The using list is defined by usings, and the lookup goes to scope.
+ Returns zero on errors. */
- buf = (char *) alloca (8 + IDENTIFIER_LENGTH (old_id)
- + IDENTIFIER_LENGTH (name));
- sprintf (buf, "__ns_%s_%s", IDENTIFIER_POINTER (old_id),
- IDENTIFIER_POINTER (name));
- return get_identifier (buf);
+int
+lookup_using_namespace (name, val, usings, scope, flags)
+ tree name, val, usings, scope;
+ int flags;
+{
+ tree iter;
+ tree val1;
+ /* Iterate over all used namespaces in current, searching for using
+ directives of scope. */
+ for (iter = usings; iter; iter = TREE_CHAIN (iter))
+ if (TREE_VALUE (iter) == scope)
+ {
+ val1 = binding_for_name (name, TREE_PURPOSE (iter));
+ /* Resolve ambiguities. */
+ val = ambiguous_decl (name, val, val1, flags);
+ }
+ return val != error_mark_node;
}
+/* [namespace.qual]
+ Excepts the name to lookup and its qualifying scope.
+ Returns the name/type pair found into the CPLUS_BINDING result,
+ or 0 on error. */
+
+int
+qualified_lookup_using_namespace (name, scope, result, flags)
+ tree name;
+ tree scope;
+ tree result;
+ int flags;
+{
+ /* Maintain a list of namespaces visited... */
+ tree seen = NULL_TREE;
+ /* ... and a list of namespace yet to see. */
+ tree todo = NULL_TREE;
+ tree usings;
+ while (scope && (result != error_mark_node))
+ {
+ seen = temp_tree_cons (scope, NULL_TREE, seen);
+ result = ambiguous_decl (name, result,
+ binding_for_name (name, scope), flags);
+ if (!BINDING_VALUE (result) && !BINDING_TYPE (result))
+ /* Consider using directives. */
+ for (usings = DECL_NAMESPACE_USING (scope); usings;
+ usings = TREE_CHAIN (usings))
+ /* If this was a real directive, and we have not seen it. */
+ if (!TREE_INDIRECT_USING (usings)
+ && !purpose_member (TREE_PURPOSE (usings), seen))
+ todo = temp_tree_cons (TREE_PURPOSE (usings), NULL_TREE, todo);
+ if (todo)
+ {
+ scope = TREE_PURPOSE (todo);
+ todo = TREE_CHAIN (todo);
+ }
+ else
+ scope = NULL_TREE; /* If there never was a todo list. */
+ }
+ return result != error_mark_node;
+}
+
+/* [namespace.memdef]/2 */
+
+/* Set the context of a declaration to scope. Complain if we are not
+ outside scope. */
+
+void
+set_decl_namespace (decl, scope)
+ tree decl;
+ tree scope;
+{
+ tree old;
+ if (scope == std_node)
+ scope = global_namespace;
+ /* Get rid of namespace aliases. */
+ scope = ORIGINAL_NAMESPACE (scope);
+
+ if (!is_namespace_ancestor (current_namespace, scope))
+ cp_error ("declaration of `%D' not in a namespace surrounding `%D'",
+ decl, scope);
+ DECL_CONTEXT (decl) = FROB_CONTEXT (scope);
+ if (scope != current_namespace)
+ {
+ /* See whether this has been declared in the namespace. */
+ old = namespace_binding (DECL_NAME (decl), scope);
+ if (!old)
+ /* No old declaration at all. */
+ goto complain;
+ if (!is_overloaded_fn (decl))
+ /* Don't compare non-function decls with decls_match here,
+ since it can't check for the correct constness at this
+ point. pushdecl will find those errors later. */
+ return;
+ /* Since decl is a function, old should contain a function decl. */
+ if (!is_overloaded_fn (old))
+ goto complain;
+ for (; old; old = OVL_NEXT (old))
+ if (decls_match (decl, OVL_CURRENT (old)))
+ return;
+ }
+ else
+ return;
+ complain:
+ cp_error ("`%D' should have been declared inside `%D'",
+ decl, scope);
+}
+
+/* Compute the namespace where a declaration is defined. */
+
+tree
+decl_namespace (decl)
+ tree decl;
+{
+ while (DECL_CONTEXT (decl))
+ {
+ decl = DECL_CONTEXT (decl);
+ if (TREE_CODE (decl) == NAMESPACE_DECL)
+ return decl;
+ if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't')
+ decl = TYPE_STUB_DECL (decl);
+ my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd', 390);
+ }
+
+ return global_namespace;
+}
+
+/* Return the namespace where the current declaration is declared. */
+
+tree
+current_decl_namespace ()
+{
+ tree result;
+ /* If we have been pushed into a different namespace, use it. */
+ if (decl_namespace_list)
+ return TREE_PURPOSE (decl_namespace_list);
+
+ if (current_class_type)
+ result = decl_namespace (TYPE_STUB_DECL (current_class_type));
+ else if (current_function_decl)
+ result = decl_namespace (current_function_decl);
+ else
+ result = current_namespace;
+ return result;
+}
+
+/* Temporarily set the namespace for the current declaration. */
+
+void
+push_decl_namespace (decl)
+ tree decl;
+{
+ if (TREE_CODE (decl) != NAMESPACE_DECL)
+ decl = decl_namespace (decl);
+ decl_namespace_list = tree_cons (decl, NULL_TREE, decl_namespace_list);
+}
+
+void
+pop_decl_namespace ()
+{
+ decl_namespace_list = TREE_CHAIN (decl_namespace_list);
+}
+
+static void
+check_decl_namespace ()
+{
+ my_friendly_assert (decl_namespace_list == NULL_TREE, 980711);
+}
+
+/* [basic.lookup.koenig] */
+/* A non-zero return value in the functions below indicates an error.
+ All nodes allocated in the procedure are on the scratch obstack. */
+
+struct arg_lookup
+{
+ tree name;
+ tree namespaces;
+ tree classes;
+ tree functions;
+};
+
+static int arg_assoc PROTO((struct arg_lookup*, tree));
+static int arg_assoc_args PROTO((struct arg_lookup*, tree));
+
+/* Add a function to the lookup structure.
+ Returns 1 on error. */
+
+static int
+add_function (k, fn)
+ struct arg_lookup *k;
+ tree fn;
+{
+ if (ovl_member (fn, k->functions))
+ return 0;
+ /* We must find only functions, or exactly one non-function. */
+ if (k->functions && is_overloaded_fn (k->functions)
+ && is_overloaded_fn (fn))
+ k->functions = build_overload (fn, k->functions);
+ else
+ if(k->functions)
+ {
+ tree f1 = OVL_CURRENT (k->functions);
+ tree f2 = fn;
+ if (is_overloaded_fn (f1))
+ {
+ fn = f1; f1 = f2; f2 = fn;
+ }
+ cp_error_at ("`%D' is not a function,", f1);
+ cp_error_at (" conflict with `%D'", f2);
+ cp_error (" in call to `%D'", k->name);
+ return 1;
+ }
+ else
+ k->functions = fn;
+ return 0;
+}
+
+/* Add functions of a namespace to the lookup structure.
+ Returns 1 on error. */
+
+static int
+arg_assoc_namespace (k, scope)
+ struct arg_lookup *k;
+ tree scope;
+{
+ tree value;
+
+ if (purpose_member (scope, k->namespaces))
+ return 0;
+ k->namespaces = tree_cons (scope, NULL_TREE, k->namespaces);
+
+ value = namespace_binding (k->name, scope);
+ if (!value)
+ return 0;
+
+ for (; value; value = OVL_NEXT (value))
+ if (add_function (k, OVL_CURRENT (value)))
+ return 1;
+
+ return 0;
+}
+
+/* Adds everything associated with class to the lookup structure.
+ Returns 1 on error. */
+
+static int
+arg_assoc_class (k, type)
+ struct arg_lookup* k;
+ tree type;
+{
+ tree list, friends, context;
+ int i;
+
+ if (purpose_member (type, k->classes))
+ return 0;
+ k->classes = tree_cons (type, NULL_TREE, k->classes);
+
+ context = decl_namespace (TYPE_MAIN_DECL (type));
+ if (arg_assoc_namespace (k, context))
+ return 1;
+
+ /* Process baseclasses. */
+ for (i = 0; i < CLASSTYPE_N_BASECLASSES (type); i++)
+ if (arg_assoc_class (k, TYPE_BINFO_BASETYPE (type, i)))
+ return 1;
+
+ /* Process friends. */
+ for (list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type)); list;
+ list = TREE_CHAIN (list))
+ if (k->name == TREE_PURPOSE (list))
+ for (friends = TREE_VALUE (list); friends;
+ friends = TREE_CHAIN (friends))
+ /* Only interested in global functions with potentially hidden
+ (i.e. unqualified) declarations. */
+ if (TREE_PURPOSE (list) == error_mark_node && TREE_VALUE (list)
+ && decl_namespace (TREE_VALUE (list)) == context)
+ if (add_function (k, TREE_VALUE (list)))
+ return 1;
+
+ /* Process template arguments. */
+ if (CLASSTYPE_TEMPLATE_INFO (type))
+ {
+ list = innermost_args (CLASSTYPE_TI_ARGS (type), 0);
+ for (i = 0; i < TREE_VEC_LENGTH (list); ++i)
+ arg_assoc (k, TREE_VEC_ELT (list, i));
+ }
+
+ return 0;
+}
+
+/* Adds everything associated with a given type.
+ Returns 1 on error. */
+
+static int
+arg_assoc_type (k, type)
+ struct arg_lookup *k;
+ tree type;
+{
+ switch (TREE_CODE (type))
+ {
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case COMPLEX_TYPE:
+ case CHAR_TYPE:
+ case BOOLEAN_TYPE:
+ return 0;
+ case RECORD_TYPE:
+ if (TYPE_PTRMEMFUNC_P (type))
+ return arg_assoc_type (k, TYPE_PTRMEMFUNC_FN_TYPE (type));
+ return arg_assoc_class (k, type);
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case ARRAY_TYPE:
+ return arg_assoc_type (k, TREE_TYPE (type));
+ case UNION_TYPE:
+ case ENUMERAL_TYPE:
+ return arg_assoc_namespace (k, decl_namespace (TYPE_MAIN_DECL (type)));
+ case OFFSET_TYPE:
+ /* Pointer to member: associate class type and value type. */
+ if (arg_assoc_type (k, TYPE_OFFSET_BASETYPE (type)))
+ return 1;
+ return arg_assoc_type (k, TREE_TYPE (type));
+ case METHOD_TYPE:
+ /* The basetype is referenced in the first arg type, so just
+ fall through. */
+ case FUNCTION_TYPE:
+ /* Associate the parameter types. */
+ if (arg_assoc_args (k, TYPE_ARG_TYPES (type)))
+ return 1;
+ /* Associate the return type. */
+ return arg_assoc_type (k, TREE_TYPE (type));
+ case TEMPLATE_TYPE_PARM:
+ return 0;
+ case LANG_TYPE:
+ if (type == unknown_type_node)
+ return 0;
+ /* else fall through */
+ default:
+ my_friendly_abort (390);
+ }
+ return 0;
+}
+
+/* Adds everything associated with arguments. Returns 1 on error. */
+
+static int
+arg_assoc_args (k, args)
+ struct arg_lookup* k;
+ tree args;
+{
+ for (; args; args = TREE_CHAIN (args))
+ if (arg_assoc (k, TREE_VALUE (args)))
+ return 1;
+ return 0;
+}
+
+/* Adds everything associated with a given tree_node. Returns 1 on error. */
+
+static int
+arg_assoc (k, n)
+ struct arg_lookup* k;
+ tree n;
+{
+ if (n == error_mark_node)
+ return 0;
+
+ if (TREE_CODE_CLASS (TREE_CODE (n)) == 't')
+ return arg_assoc_type (k, n);
+
+ if (! type_unknown_p (n))
+ return arg_assoc_type (k, TREE_TYPE (n));
+
+ if (TREE_CODE (n) == ADDR_EXPR)
+ n = TREE_OPERAND (n, 0);
+ while (TREE_CODE (n) == TREE_LIST)
+ n = TREE_VALUE (n);
+
+ my_friendly_assert (TREE_CODE (n) == OVERLOAD, 980715);
+
+ for (; n; n = TREE_CHAIN (n))
+ if (arg_assoc (k, OVL_FUNCTION (n)))
+ return 1;
+
+ return 0;
+}
+
+/* Performs Koenig lookup depending on arguments, where fns
+ are the functions found in normal lookup. */
+
+tree
+lookup_arg_dependent (name, fns, args)
+ tree name;
+ tree fns;
+ tree args;
+{
+ struct arg_lookup k;
+ k.name = name;
+ k.functions = fns;
+ k.namespaces = NULL_TREE;
+ k.classes = NULL_TREE;
+
+ push_scratch_obstack ();
+ arg_assoc_args (&k, args);
+ pop_obstacks ();
+ return k.functions;
+}
+
+/* Process a namespace-alias declaration. */
+
void
do_namespace_alias (alias, namespace)
tree alias, namespace;
{
+ tree binding;
+ tree old;
+
+ if (TREE_CODE (namespace) != NAMESPACE_DECL)
+ {
+ /* The parser did not find it, so it's not there. */
+ cp_error ("unknown namespace `%D'", namespace);
+ return;
+ }
+
+ namespace = ORIGINAL_NAMESPACE (namespace);
+
+ /* Build the alias. */
+ alias = build_lang_decl (NAMESPACE_DECL, alias, void_type_node);
+ DECL_NAMESPACE_ALIAS (alias) = namespace;
+ pushdecl (alias);
}
-tree
-do_toplevel_using_decl (decl)
+/* Check a non-member using-declaration. Return the name and scope
+ being used, and the USING_DECL, or NULL_TREE on failure. */
+
+static tree
+validate_nonmember_using_decl (decl, scope, name)
tree decl;
+ tree *scope;
+ tree *name;
{
- if (decl == NULL_TREE || decl == error_mark_node)
+ if (TREE_CODE (decl) == SCOPE_REF
+ && TREE_OPERAND (decl, 0) == std_node)
+ {
+ *scope = global_namespace;
+ *name = TREE_OPERAND (decl, 1);
+ }
+ else if (TREE_CODE (decl) == SCOPE_REF)
+ {
+ *scope = TREE_OPERAND (decl, 0);
+ *name = TREE_OPERAND (decl, 1);
+ }
+ else if (TREE_CODE (decl) == IDENTIFIER_NODE
+ || TREE_CODE (decl) == TYPE_DECL)
+ {
+ *scope = global_namespace;
+ *name = decl;
+ }
+ else
+ my_friendly_abort (382);
+ if (TREE_CODE_CLASS (TREE_CODE (*name)) == 'd')
+ *name = DECL_NAME (*name);
+ /* Make a USING_DECL. */
+ return push_using_decl (*scope, *name);
+}
+
+/* Process local and global using-declarations. */
+
+static void
+do_nonmember_using_decl (scope, name, oldval, oldtype, newval, newtype)
+ tree scope, name;
+ tree oldval, oldtype;
+ tree *newval, *newtype;
+{
+ tree decls;
+ struct tree_binding _decls;
+
+ *newval = *newtype = NULL_TREE;
+ decls = binding_init (&_decls);
+ if (!qualified_lookup_using_namespace (name, scope, decls, 0))
+ /* Lookup error */
return;
- if (TREE_CODE (decl) == SCOPE_REF)
- decl = resolve_scope_to_name (NULL_TREE, decl);
+ if (!BINDING_VALUE (decls) && !BINDING_TYPE (decls))
+ {
+ cp_error ("`%D' not declared", name);
+ return;
+ }
+
+ /* Check for using functions. */
+ if (BINDING_VALUE (decls) && is_overloaded_fn (BINDING_VALUE (decls)))
+ {
+ tree tmp, tmp1;
+
+ if (oldval && !is_overloaded_fn (oldval))
+ {
+ duplicate_decls (OVL_CURRENT (BINDING_VALUE (decls)), oldval);
+ oldval = NULL_TREE;
+ }
+
+ *newval = oldval;
+ for (tmp = BINDING_VALUE (decls); tmp; tmp = OVL_NEXT (tmp))
+ {
+ /* Compare each new function with each old one.
+ If the old function was also used, there is no conflict. */
+ for (tmp1 = oldval; tmp1; tmp1 = OVL_NEXT (tmp1))
+ if (OVL_CURRENT (tmp) == OVL_CURRENT (tmp1))
+ break;
+ else if (OVL_USED (tmp1))
+ continue;
+ else if (duplicate_decls (OVL_CURRENT (tmp), OVL_CURRENT (tmp1)))
+ return;
+
+ /* Duplicate use, ignore */
+ if (tmp1)
+ continue;
+
+ *newval = build_overload (OVL_CURRENT (tmp), *newval);
+ if (TREE_CODE (*newval) != OVERLOAD)
+ *newval = ovl_cons (*newval, NULL_TREE);
+ OVL_USED (*newval) = 1;
+ }
+ }
+ else
+ {
+ *newval = BINDING_VALUE (decls);
+ if (oldval)
+ duplicate_decls (*newval, oldval);
+ }
- /* Is this the right way to do an id list? */
- if (TREE_CODE (decl) != TREE_LIST)
+ *newtype = BINDING_TYPE (decls);
+ if (oldtype && *newtype && oldtype != *newtype)
{
- pushdecl (decl);
+ cp_error ("using directive `%D' introduced ambiguous type `%T'",
+ name, oldtype);
+ return;
}
- else
- while (decl)
- {
- pushdecl (TREE_VALUE (decl));
- decl = TREE_CHAIN (decl);
- }
+}
+
+/* Process a using-declaration not appearing in class or local scope. */
+
+void
+do_toplevel_using_decl (decl)
+ tree decl;
+{
+ tree scope, name, binding;
+ tree oldval, oldtype, newval, newtype;
+
+ decl = validate_nonmember_using_decl (decl, &scope, &name);
+ if (decl == NULL_TREE)
+ return;
+
+ binding = binding_for_name (name, current_namespace);
+
+ oldval = BINDING_VALUE (binding);
+ oldtype = BINDING_TYPE (binding);
+
+ do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
+
+ /* Copy declarations found. */
+ if (newval)
+ BINDING_VALUE (binding) = newval;
+ if (newtype)
+ BINDING_TYPE (binding) = newtype;
+ return;
+}
+
+/* Process a using-declaration at function scope. */
+
+void
+do_local_using_decl (decl)
+ tree decl;
+{
+ tree scope, name;
+ tree oldval, oldtype, newval, newtype;
+
+ decl = validate_nonmember_using_decl (decl, &scope, &name);
+ if (decl == NULL_TREE)
+ return;
+
+ oldval = lookup_name_current_level (name);
+ oldtype = lookup_type_current_level (name);
+
+ do_nonmember_using_decl (scope, name, oldval, oldtype, &newval, &newtype);
+
+ if (newval)
+ set_identifier_local_value (name, newval);
+ if (newtype)
+ set_identifier_type_value (name, newtype);
}
tree
do_class_using_decl (decl)
tree decl;
{
- tree type;
+ tree name, value;
- /* Ignore for now, unimplemented. */
- return NULL_TREE;
+ if (TREE_CODE (decl) != SCOPE_REF
+ || TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (decl, 0))) != 't')
+ {
+ cp_error ("using-declaration for non-member at class scope");
+ return NULL_TREE;
+ }
+ name = TREE_OPERAND (decl, 1);
+ if (TREE_CODE (name) == BIT_NOT_EXPR)
+ {
+ cp_error ("using-declaration for destructor");
+ return NULL_TREE;
+ }
+ if (TREE_CODE (name) == TYPE_DECL)
+ name = DECL_NAME (name);
+
+ my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 980716);
+
+ value = build_lang_field_decl (USING_DECL, name, void_type_node);
+ DECL_INITIAL (value) = TREE_OPERAND (decl, 0);
+ return value;
}
+/* Process a using-directive. */
+
void
do_using_directive (namespace)
tree namespace;
{
+ if (namespace == std_node)
+ return;
+ /* using namespace A::B::C; */
+ if (TREE_CODE (namespace) == SCOPE_REF)
+ namespace = TREE_OPERAND (namespace, 1);
+ if (TREE_CODE (namespace) == IDENTIFIER_NODE)
+ {
+ /* Lookup in lexer did not find a namespace. */
+ cp_error ("namespace `%T' undeclared", namespace);
+ return;
+ }
+ if (TREE_CODE (namespace) != NAMESPACE_DECL)
+ {
+ cp_error ("`%T' is not a namespace", namespace);
+ return;
+ }
+ namespace = ORIGINAL_NAMESPACE (namespace);
+ if (!toplevel_bindings_p ())
+ push_using_directive (namespace);
+ else
+ /* direct usage */
+ add_using_namespace (current_namespace, namespace, 0);
}
void
@@ -3507,9 +4679,46 @@ check_default_args (x)
saw_def = 1;
else if (saw_def)
{
- cp_error ("default argument missing for parameter %P of `%#D'",
- i, x);
+ cp_error_at ("default argument missing for parameter %P of `%+#D'",
+ i, x);
break;
}
}
}
+
+void
+mark_used (decl)
+ tree decl;
+{
+ TREE_USED (decl) = 1;
+ if (processing_template_decl)
+ return;
+ assemble_external (decl);
+ /* Is it a synthesized method that needs to be synthesized? */
+ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_CLASS_CONTEXT (decl)
+ && DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
+ /* Kludge: don't synthesize for default args. */
+ && current_function_decl)
+ synthesize_method (decl);
+ if (DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl))
+ instantiate_decl (decl);
+}
+
+/* Helper function for named_class_head_sans_basetype nonterminal. */
+
+tree
+handle_class_head (aggr, scope, id)
+ tree aggr, scope, id;
+{
+ if (TREE_CODE (id) == TYPE_DECL)
+ return id;
+
+ if (scope)
+ cp_error ("`%T' does not have a nested type named `%D'", scope, id);
+ else
+ cp_error ("no file-scope type named `%D'", id);
+
+ id = xref_tag
+ (aggr, make_anon_name (), NULL_TREE, 1);
+ return TYPE_MAIN_DECL (id);
+}
diff --git a/contrib/gcc/cp/errfn.c b/contrib/gcc/cp/errfn.c
index 4da07fa..8d20682 100644
--- a/contrib/gcc/cp/errfn.c
+++ b/contrib/gcc/cp/errfn.c
@@ -20,16 +20,22 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "tree.h"
-#include <stdio.h>
-#include <ctype.h>
+#include "toplev.h"
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
/* cp_printer is the type of a function which converts an argument into
a string for digestion by printf. The cp_printer function should deal
with all memory management; the functions in this file will not free
the char*s returned. See error.c for an example use of this code. */
-typedef char* cp_printer PROTO((HOST_WIDE_INT, int));
+typedef char* cp_printer PROTO((tree, int));
extern cp_printer * cp_printers[256];
/* Whether or not we should try to be quiet for errors and warnings; this is
@@ -44,187 +50,235 @@ extern int cp_line_of PROTO((tree));
#define STRDUP(f) (ap = (char *) alloca (strlen (f) +1), strcpy (ap, (f)), ap)
-#define NARGS 4
-#define arglist a1, a2, a3, a4
-#define arglist_dcl HOST_WIDE_INT a1, a2, a3, a4;
-#define ARGSINIT args[0] = a1; args[1] = a2; args[2] = a3; args[3] = a4;
-#define ARGSLIST args[0], args[1], args[2], args[3]
+/* This function supports only `%s', `%d', `%%', and the C++ print
+ codes. */
+#ifdef __STDC__
+static void
+cp_thing (errorfn *errfn, int atarg1, const char *format, va_list ap)
+#else
static void
-cp_thing (errfn, atarg1, format, arglist)
+cp_thing (errfn, atarg1, format, ap)
errorfn *errfn;
int atarg1;
- char *format;
- arglist_dcl
+ const char *format;
+ va_list ap;
+#endif
{
- char *fmt;
- char *f;
- char *ap;
- int arg;
- HOST_WIDE_INT atarg = atarg1 ? a1 : 0;
- HOST_WIDE_INT args[NARGS];
- ARGSINIT
-
- fmt = STRDUP(format);
-
- for (f = fmt, arg = 0; *f; ++f)
+ static char *buf;
+ static long buflen;
+ int nargs = 0;
+ long len;
+ long offset;
+ const char *f;
+ tree atarg = 0;
+
+ len = strlen (format) + 1;
+ if (len > buflen)
+ {
+ buflen = len;
+ buf = xrealloc (buf, buflen);
+ }
+ offset = 0;
+
+ for (f = format; *f; ++f)
{
cp_printer * function;
int alternate;
int maybe_here;
/* ignore text */
- if (*f != '%') continue;
+ if (*f != '%')
+ {
+ buf[offset++] = *f;
+ continue;
+ }
++f;
alternate = 0;
maybe_here = 0;
- /* ignore most flags */
- while (*f == ' ' || *f == '-' || *f == '+' || *f == '#')
+ /* Check for '+' and '#' (in that order). */
+ if (*f == '+')
{
- if (*f == '+')
- maybe_here = 1;
- else if (*f == '#')
- alternate = 1;
+ maybe_here = 1;
++f;
}
-
- /* ignore field width */
- if (*f == '*')
+ if (*f == '#')
{
+ alternate = 1;
++f;
- ++arg;
}
- else
- while (isdigit (*f))
- ++f;
- /* ignore precision */
- if (*f == '.')
+ /* no field width or precision */
+
+ function = cp_printers[(int)*f];
+
+ if (function || *f == 's')
{
- ++f;
- if (*f == '*')
+ char *p;
+ int plen;
+
+ if (*f == 's')
{
- ++f;
- ++arg;
+ p = va_arg (ap, char *);
+ nargs++;
}
else
- while (isdigit (*f))
- ++f;
- }
+ {
+ tree t = va_arg (ap, tree);
+ nargs++;
- /* ignore "long" */
- if (*f == 'l')
- ++f;
+ /* This indicates that ATARG comes from a different
+ location than normal. */
+ if (maybe_here && atarg1)
+ atarg = t;
- function = cp_printers[(int)*f];
+ /* If atarg1 is set and this is the first argument, then
+ set ATARG appropriately. */
+ if (atarg1 && nargs == 1)
+ atarg = t;
- if (function)
- {
- char *p;
-
- if (arg >= NARGS) abort ();
-
- if (maybe_here && atarg1)
- atarg = args[arg];
+ p = (*function) (t, alternate);
+ }
- /* Must use a temporary to avoid calling *function twice */
- p = (*function) (args[arg], alternate);
- args[arg] = (HOST_WIDE_INT) STRDUP(p);
- *f = 's';
+ plen = strlen (p);
+ len += plen;
+ if (len > buflen)
+ {
+ buflen = len;
+ buf = xrealloc (buf, len);
+ }
+ strcpy (buf + offset, p);
+ offset += plen;
}
+ else if (*f == '%')
+ {
+ /* A `%%' has occurred in the input string. Since the
+ string we produce here will be passed to vprintf we must
+ preserve both `%' characters. */
- ++arg; /* Assume valid format string */
-
+ len += 2;
+ if (len > buflen)
+ {
+ buflen = len;
+ buf = xrealloc (buf, len);
+ }
+ strcpy (buf + offset, "%%");
+ offset += 2;
+ }
+ else
+ {
+ if (*f != 'd')
+ abort ();
+ len += HOST_BITS_PER_INT / 2;
+ if (len > buflen)
+ {
+ buflen = len;
+ buf = xrealloc (buf, len);
+ }
+ sprintf (buf + offset, "%d", va_arg (ap, int));
+ nargs++;
+ offset += strlen (buf + offset);
+ /* With an ANSI C library one could write
+ out += sprintf (...); */
+ }
}
+ buf[offset] = '\0';
+
+ /* If ATARG1 is set, but we haven't extracted any arguments, then
+ extract one tree argument for ATARG. */
+ if (nargs == 0 && atarg1)
+ atarg = va_arg (ap, tree);
if (atarg)
{
- char *file = cp_file_of ((tree) atarg);
- int line = cp_line_of ((tree) atarg);
- (*errfn) (file, line, fmt, ARGSLIST);
+ char *file = cp_file_of (atarg);
+ int line = cp_line_of (atarg);
+ (*errfn) (file, line, buf);
}
else
- (*errfn) (fmt, ARGSLIST);
+ (*errfn) (buf);
}
-void
-cp_error (format, arglist)
- char *format;
- arglist_dcl
+#ifdef __STDC__
+#define DECLARE(name) void name (const char *format, ...)
+#define INIT va_start (ap, format)
+#else
+#define DECLARE(name) void name (format, va_alist) char *format; va_dcl
+#define INIT va_start (ap)
+#endif
+
+DECLARE (cp_error)
{
- extern errorfn error;
+ va_list ap;
+ INIT;
if (! cp_silent)
- cp_thing (error, 0, format, arglist);
+ cp_thing ((errorfn *) error, 0, format, ap);
+ va_end (ap);
}
-void
-cp_warning (format, arglist)
- char *format;
- arglist_dcl
+DECLARE (cp_warning)
{
- extern errorfn warning;
+ va_list ap;
+ INIT;
if (! cp_silent)
- cp_thing (warning, 0, format, arglist);
+ cp_thing ((errorfn *) warning, 0, format, ap);
+ va_end (ap);
}
-void
-cp_pedwarn (format, arglist)
- char *format;
- arglist_dcl
+DECLARE (cp_pedwarn)
{
- extern errorfn pedwarn;
+ va_list ap;
+ INIT;
if (! cp_silent)
- cp_thing (pedwarn, 0, format, arglist);
+ cp_thing ((errorfn *) pedwarn, 0, format, ap);
+ va_end (ap);
}
-void
-cp_compiler_error (format, arglist)
- char *format;
- arglist_dcl
+DECLARE (cp_compiler_error)
{
extern errorfn compiler_error;
+ va_list ap;
+ INIT;
if (! cp_silent)
- cp_thing (compiler_error, 0, format, arglist);
+ cp_thing (compiler_error, 0, format, ap);
+ va_end (ap);
}
-void
-cp_sprintf (format, arglist)
- char *format;
- arglist_dcl
+DECLARE (cp_sprintf)
{
- cp_thing ((errorfn *) sprintf, 0, format, arglist);
+ va_list ap;
+ INIT;
+ cp_thing ((errorfn *) sprintf, 0, format, ap);
+ va_end (ap);
}
-void
-cp_error_at (format, arglist)
- char *format;
- arglist_dcl
+DECLARE (cp_error_at)
{
- extern errorfn error_with_file_and_line;
+ va_list ap;
+ INIT;
if (! cp_silent)
- cp_thing (error_with_file_and_line, 1, format, arglist);
+ cp_thing ((errorfn *) error_with_file_and_line, 1, format, ap);
+ va_end (ap);
}
-void
-cp_warning_at (format, arglist)
- char *format;
- arglist_dcl
+DECLARE (cp_warning_at)
{
- extern errorfn warning_with_file_and_line;
+ va_list ap;
+ INIT;
if (! cp_silent)
- cp_thing (warning_with_file_and_line, 1, format, arglist);
+ cp_thing ((errorfn *) warning_with_file_and_line, 1, format, ap);
+ va_end (ap);
}
-void
-cp_pedwarn_at (format, arglist)
- char *format;
- arglist_dcl
+DECLARE (cp_pedwarn_at)
{
- extern errorfn pedwarn_with_file_and_line;
+ va_list ap;
+ INIT;
if (! cp_silent)
- cp_thing (pedwarn_with_file_and_line, 1, format, arglist);
+ cp_thing ((errorfn *) pedwarn_with_file_and_line, 1, format, ap);
+ va_end (ap);
}
diff --git a/contrib/gcc/cp/error.c b/contrib/gcc/cp/error.c
index 4eb196e..bb21bcb 100644
--- a/contrib/gcc/cp/error.c
+++ b/contrib/gcc/cp/error.c
@@ -1,6 +1,6 @@
/* Call-backs for C++ error reporting.
This code is non-reentrant.
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 94-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,10 +20,11 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "cp-tree.h"
#include "obstack.h"
-#include <ctype.h>
+#include "toplev.h"
typedef char* cp_printer ();
@@ -34,21 +35,22 @@ typedef char* cp_printer ();
#define L language_as_string
#define O op_as_string
#define P parm_as_string
+#define Q assop_as_string
#define T type_as_string
#define V cv_as_string
-#define _ (cp_printer *) 0
+#define o (cp_printer *) 0
cp_printer * cp_printers[256] =
-{
+{
/*0 1 2 3 4 5 6 7 8 9 A B C D E F */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x00 */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x10 */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x20 */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x30 */
- _, A, _, C, D, E, _, _, _, _, _, _, L, _, _, O, /* 0x40 */
- P, _, _, _, T, _, V, _, _, _, _, _, _, _, _, _, /* 0x50 */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x60 */
- _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, /* 0x70 */
+ o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, /* 0x00 */
+ o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, /* 0x10 */
+ o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, /* 0x20 */
+ o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, /* 0x30 */
+ o, A, o, C, D, E, o, o, o, o, o, o, L, o, o, O, /* 0x40 */
+ P, Q, o, o, T, o, V, o, o, o, o, o, o, o, o, o, /* 0x50 */
+ o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, /* 0x60 */
+ o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, /* 0x70 */
};
#undef C
#undef D
@@ -56,9 +58,10 @@ cp_printer * cp_printers[256] =
#undef L
#undef O
#undef P
+#undef Q
#undef T
#undef V
-#undef _
+#undef o
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
@@ -77,16 +80,32 @@ static char *scratch_firstobj;
IDENTIFIER_LENGTH (ID)))
# define OB_PUTCP(S) (obstack_grow (&scratch_obstack, (S), strlen (S)))
# define OB_FINISH() (obstack_1grow (&scratch_obstack, '\0'))
-# define OB_PUTI(CST) do { sprintf (digit_buffer, "%d", (CST)); \
+# define OB_PUTI(CST) do { sprintf (digit_buffer, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)(CST)); \
OB_PUTCP (digit_buffer); } while (0)
# define OB_UNPUT(N) obstack_blank (&scratch_obstack, - (N));
# define NEXT_CODE(t) (TREE_CODE (TREE_TYPE (t)))
-static void dump_type (), dump_decl (), dump_function_decl ();
-static void dump_expr (), dump_unary_op (), dump_binary_op ();
-static void dump_aggr_type (), dump_type_prefix (), dump_type_suffix ();
-static void dump_function_name ();
+enum pad { none, before, after };
+
+static void dump_type PROTO((tree, int));
+static void dump_type_real PROTO((tree, int, int));
+static void dump_simple_decl PROTO((tree, tree, int));
+static void dump_decl PROTO((tree, int));
+static void dump_function_decl PROTO((tree, int));
+static void dump_expr PROTO((tree, int));
+static void dump_unary_op PROTO((char *, tree, int));
+static void dump_binary_op PROTO((char *, tree));
+static void dump_aggr_type PROTO((tree, int, int));
+static void dump_type_prefix PROTO((tree, int, int));
+static void dump_type_suffix PROTO((tree, int, int));
+static void dump_function_name PROTO((tree));
+static void dump_expr_list PROTO((tree));
+static void dump_global_iord PROTO((tree));
+static void dump_readonly_or_volatile PROTO((tree, enum pad));
+static void dump_char PROTO((int));
+static char *aggr_variety PROTO((tree));
+static tree ident_fndecl PROTO((tree));
void
init_error ()
@@ -95,8 +114,6 @@ init_error ()
scratch_firstobj = (char *)obstack_alloc (&scratch_obstack, 0);
}
-enum pad { none, before, after };
-
static void
dump_readonly_or_volatile (t, p)
tree t;
@@ -119,11 +136,13 @@ dump_readonly_or_volatile (t, p)
value. */
static char digit_buffer[128];
-/* Dump into the obstack a human-readable equivalent of TYPE. */
+/* Dump into the obstack a human-readable equivalent of TYPE. */
+
static void
-dump_type (t, v)
+dump_type_real (t, v, canonical_name)
tree t;
int v; /* verbose? */
+ int canonical_name;
{
if (t == NULL_TREE)
return;
@@ -145,19 +164,19 @@ dump_type (t, v)
/* i.e. function taking no arguments */
if (t != void_list_node)
{
- dump_type (TREE_VALUE (t), v);
+ dump_type_real (TREE_VALUE (t), v, canonical_name);
/* Can this happen other than for default arguments? */
if (TREE_PURPOSE (t) && v)
{
OB_PUTS (" = ");
- dump_expr (TREE_PURPOSE (t));
+ dump_expr (TREE_PURPOSE (t), 0);
}
if (TREE_CHAIN (t))
{
if (TREE_CHAIN (t) != void_list_node)
{
OB_PUTC2 (',', ' ');
- dump_type (TREE_CHAIN (t), v);
+ dump_type_real (TREE_CHAIN (t), v, canonical_name);
}
}
else OB_PUTS (" ...");
@@ -169,7 +188,7 @@ dump_type (t, v)
break;
case TREE_VEC:
- dump_type (BINFO_TYPE (t), v);
+ dump_type_real (BINFO_TYPE (t), v, canonical_name);
break;
case RECORD_TYPE:
@@ -179,21 +198,27 @@ dump_type (t, v)
&& (IS_SIGNATURE_POINTER (t) || IS_SIGNATURE_REFERENCE (t)))
{
if (TYPE_READONLY (t) | TYPE_VOLATILE (t))
- dump_readonly_or_volatile (t);
- dump_type (SIGNATURE_TYPE (t), v);
+ dump_readonly_or_volatile (t, after);
+ dump_type_real (SIGNATURE_TYPE (t), v, canonical_name);
if (IS_SIGNATURE_POINTER (t))
OB_PUTC ('*');
else
OB_PUTC ('&');
}
else
- dump_aggr_type (t, v);
+ dump_aggr_type (t, v, canonical_name);
break;
case TYPE_DECL:
+ case TEMPLATE_DECL:
dump_decl (t, v);
break;
+ case COMPLEX_TYPE:
+ OB_PUTS ("complex ");
+ dump_type_real (TREE_TYPE (t), v, canonical_name);
+ break;
+
case INTEGER_TYPE:
if (!TREE_UNSIGNED (TYPE_MAIN_VARIANT (t)) && TREE_UNSIGNED (t))
OB_PUTS ("unsigned ");
@@ -204,17 +229,56 @@ dump_type (t, v)
case REAL_TYPE:
case VOID_TYPE:
case BOOLEAN_TYPE:
- dump_readonly_or_volatile (t, after);
- OB_PUTID (TYPE_IDENTIFIER (t));
+ {
+ tree type;
+ dump_readonly_or_volatile (t, after);
+ type = canonical_name ? TYPE_MAIN_VARIANT (t) : t;
+ if (TYPE_NAME (type) && TYPE_IDENTIFIER (type))
+ OB_PUTID (TYPE_IDENTIFIER (type));
+ else
+ /* Types like intQI_type_node and friends have no names.
+ These don't come up in user error messages, but it's nice
+ to be able to print them from the debugger. */
+ OB_PUTS ("{anonymous}");
+ }
break;
- case TEMPLATE_TYPE_PARM:
- OB_PUTID (TYPE_IDENTIFIER (t));
+ case TEMPLATE_TEMPLATE_PARM:
+ if (!CLASSTYPE_TEMPLATE_INFO (t))
+ {
+ /* For parameters inside template signature. */
+ if (TYPE_IDENTIFIER (t))
+ OB_PUTID (TYPE_IDENTIFIER (t));
+ else
+ OB_PUTS ("{anonymous template template parm}");
+ }
+ else
+ {
+ int i;
+ tree args = CLASSTYPE_TI_ARGS (t);
+ OB_PUTID (TYPE_IDENTIFIER (t));
+ OB_PUTC ('<');
+ for (i = 0; i < TREE_VEC_LENGTH (args); i++)
+ {
+ tree arg = TREE_VEC_ELT (args, i);
+ if (TREE_CODE_CLASS (TREE_CODE (arg)) == 't'
+ || TREE_CODE (arg) == TEMPLATE_DECL)
+ dump_type_real (arg, 0, canonical_name);
+ else
+ dump_expr (arg, 0);
+ if (i < TREE_VEC_LENGTH (args)-1)
+ OB_PUTC2 (',', ' ');
+ }
+ OB_PUTC ('>');
+ }
break;
- case UNINSTANTIATED_P_TYPE:
- OB_PUTID (DECL_NAME (UPT_TEMPLATE (t)));
- OB_PUTS ("<...>");
+ case TEMPLATE_TYPE_PARM:
+ dump_readonly_or_volatile (t, after);
+ if (TYPE_IDENTIFIER (t))
+ OB_PUTID (TYPE_IDENTIFIER (t));
+ else
+ OB_PUTS ("{anonymous template type parm}");
break;
/* This is not always necessary for pointers and such, but doing this
@@ -226,8 +290,15 @@ dump_type (t, v)
offset_type:
case FUNCTION_TYPE:
case METHOD_TYPE:
- dump_type_prefix (t, v);
- dump_type_suffix (t, v);
+ dump_type_prefix (t, v, canonical_name);
+ dump_type_suffix (t, v, canonical_name);
+ break;
+
+ case TYPENAME_TYPE:
+ OB_PUTS ("typename ");
+ dump_type_real (TYPE_CONTEXT (t), 0, canonical_name);
+ OB_PUTS ("::");
+ OB_PUTID (TYPE_IDENTIFIER (t));
break;
default:
@@ -252,12 +323,22 @@ aggr_variety (t)
return "struct";
}
-/* Print out a class declaration, in the form `class foo'. */
static void
-dump_aggr_type (t, v)
+dump_type (t, v)
tree t;
int v; /* verbose? */
{
+ dump_type_real (t, v, 0);
+}
+
+/* Print out a class declaration, in the form `class foo'. */
+
+static void
+dump_aggr_type (t, v, canonical_name)
+ tree t;
+ int v; /* verbose? */
+ int canonical_name;
+{
tree name;
char *variety = aggr_variety (t);
@@ -269,9 +350,9 @@ dump_aggr_type (t, v)
OB_PUTC (' ');
}
- name = TYPE_NAME (t);
+ name = TYPE_NAME (canonical_name ? TYPE_MAIN_VARIANT (t) : t);
- if (name && DECL_CONTEXT (name))
+ if (name && DECL_CONTEXT (name) && DECL_CONTEXT (name) != global_namespace)
{
/* FUNCTION_DECL or RECORD_TYPE */
dump_decl (DECL_CONTEXT (name), 0);
@@ -308,9 +389,10 @@ dump_aggr_type (t, v)
int *[]&. */
static void
-dump_type_prefix (t, v)
+dump_type_prefix (t, v, canonical_name)
tree t;
int v; /* verbosity */
+ int canonical_name;
{
if (TYPE_PTRMEMFUNC_P (t))
{
@@ -324,7 +406,7 @@ dump_type_prefix (t, v)
{
tree sub = TREE_TYPE (t);
- dump_type_prefix (sub, v);
+ dump_type_prefix (sub, v, canonical_name);
/* A tree for a member pointer looks like pointer to offset,
so let the OFFSET_TYPE case handle it. */
if (TREE_CODE (sub) != OFFSET_TYPE)
@@ -358,7 +440,7 @@ dump_type_prefix (t, v)
case REFERENCE_TYPE:
{
tree sub = TREE_TYPE (t);
- dump_type_prefix (sub, v);
+ dump_type_prefix (sub, v, canonical_name);
switch (TREE_CODE (sub))
{
@@ -382,11 +464,11 @@ dump_type_prefix (t, v)
case OFFSET_TYPE:
offset_type:
- dump_type_prefix (TREE_TYPE (t), v);
+ dump_type_prefix (TREE_TYPE (t), v, canonical_name);
if (TREE_CODE (t) == OFFSET_TYPE) /* pmfs deal with this in d_t_p */
{
OB_PUTC (' ');
- dump_type (TYPE_OFFSET_BASETYPE (t), 0);
+ dump_type_real (TYPE_OFFSET_BASETYPE (t), 0, canonical_name);
OB_PUTC2 (':', ':');
}
OB_PUTC ('*');
@@ -396,19 +478,19 @@ dump_type_prefix (t, v)
/* Can only be reached through function pointer -- this would not be
correct if FUNCTION_DECLs used it. */
case FUNCTION_TYPE:
- dump_type_prefix (TREE_TYPE (t), v);
+ dump_type_prefix (TREE_TYPE (t), v, canonical_name);
OB_PUTC2 (' ', '(');
break;
case METHOD_TYPE:
- dump_type_prefix (TREE_TYPE (t), v);
+ dump_type_prefix (TREE_TYPE (t), v, canonical_name);
OB_PUTC2 (' ', '(');
- dump_aggr_type (TYPE_METHOD_BASETYPE (t), 0);
+ dump_aggr_type (TYPE_METHOD_BASETYPE (t), 0, canonical_name);
OB_PUTC2 (':', ':');
break;
case ARRAY_TYPE:
- dump_type_prefix (TREE_TYPE (t), v);
+ dump_type_prefix (TREE_TYPE (t), v, canonical_name);
break;
case ENUMERAL_TYPE:
@@ -419,14 +501,16 @@ dump_type_prefix (t, v)
case REAL_TYPE:
case RECORD_TYPE:
case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
case TREE_LIST:
case TYPE_DECL:
case TREE_VEC:
- case UNINSTANTIATED_P_TYPE:
case UNION_TYPE:
case UNKNOWN_TYPE:
case VOID_TYPE:
- dump_type (t, v);
+ case TYPENAME_TYPE:
+ case COMPLEX_TYPE:
+ dump_type_real (t, v, canonical_name);
break;
default:
@@ -436,9 +520,10 @@ dump_type_prefix (t, v)
}
static void
-dump_type_suffix (t, v)
+dump_type_suffix (t, v, canonical_name)
tree t;
int v; /* verbose? */
+ int canonical_name;
{
if (TYPE_PTRMEMFUNC_P (t))
t = TYPE_PTRMEMFUNC_FN_TYPE (t);
@@ -450,7 +535,7 @@ dump_type_suffix (t, v)
case OFFSET_TYPE:
if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
OB_PUTC (')');
- dump_type_suffix (TREE_TYPE (t), v);
+ dump_type_suffix (TREE_TYPE (t), v, canonical_name);
break;
/* Can only be reached through function pointer */
@@ -471,16 +556,25 @@ dump_type_suffix (t, v)
if (TREE_CODE (t) == METHOD_TYPE)
dump_readonly_or_volatile
(TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))), before);
- dump_type_suffix (TREE_TYPE (t), v);
+ dump_type_suffix (TREE_TYPE (t), v, canonical_name);
break;
}
case ARRAY_TYPE:
OB_PUTC ('[');
if (TYPE_DOMAIN (t))
- OB_PUTI (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (t))) + 1);
+ {
+ if (TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (t))) == INTEGER_CST)
+ OB_PUTI (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (t))) + 1);
+ else if (TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (t))) == MINUS_EXPR)
+ dump_expr (TREE_OPERAND (TYPE_MAX_VALUE (TYPE_DOMAIN (t)), 0), 0);
+ else
+ dump_expr (fold (build_binary_op
+ (PLUS_EXPR, TYPE_MAX_VALUE (TYPE_DOMAIN (t)),
+ integer_one_node, 1)), 0);
+ }
OB_PUTC (']');
- dump_type_suffix (TREE_TYPE (t), v);
+ dump_type_suffix (TREE_TYPE (t), v, canonical_name);
break;
case ENUMERAL_TYPE:
@@ -491,13 +585,15 @@ dump_type_suffix (t, v)
case REAL_TYPE:
case RECORD_TYPE:
case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
case TREE_LIST:
case TYPE_DECL:
case TREE_VEC:
- case UNINSTANTIATED_P_TYPE:
case UNION_TYPE:
case UNKNOWN_TYPE:
case VOID_TYPE:
+ case TYPENAME_TYPE:
+ case COMPLEX_TYPE:
break;
default:
@@ -508,7 +604,8 @@ dump_type_suffix (t, v)
/* Return a function declaration which corresponds to the IDENTIFIER_NODE
argument. */
-tree
+
+static tree
ident_fndecl (t)
tree t;
{
@@ -538,9 +635,9 @@ ident_fndecl (t)
#endif
#define GLOBAL_IORD_P(NODE) \
- !strncmp(IDENTIFIER_POINTER(NODE),GLOBAL_THING,sizeof(GLOBAL_THING)-1)
+ ! strncmp (IDENTIFIER_POINTER(NODE), GLOBAL_THING, sizeof (GLOBAL_THING) - 1)
-void
+static void
dump_global_iord (t)
tree t;
{
@@ -560,6 +657,31 @@ dump_global_iord (t)
}
static void
+dump_simple_decl (t, type, v)
+ tree t;
+ tree type;
+ int v;
+{
+ if (v > 0)
+ {
+ dump_type_prefix (type, v, 0);
+ OB_PUTC (' ');
+ dump_readonly_or_volatile (t, after);
+ }
+ if (DECL_CLASS_SCOPE_P (t))
+ {
+ dump_type (DECL_CONTEXT (t), 0);
+ OB_PUTC2 (':', ':');
+ }
+ if (DECL_NAME (t))
+ dump_decl (DECL_NAME (t), v);
+ else
+ OB_PUTS ("{anon}");
+ if (v > 0)
+ dump_type_suffix (type, v, 0);
+}
+
+static void
dump_decl (t, v)
tree t;
int v; /* verbosity */
@@ -576,18 +698,20 @@ dump_decl (t, v)
case TYPE_DECL:
{
/* Don't say 'typedef class A' */
- tree type = TREE_TYPE (t);
- if (((IS_AGGR_TYPE (type) && ! TYPE_PTRMEMFUNC_P (type))
- || TREE_CODE (type) == ENUMERAL_TYPE)
- && type == TYPE_MAIN_VARIANT (type))
+ if (DECL_ARTIFICIAL (t))
{
- dump_type (type, v);
+ if (v > 0 && TREE_CODE (TREE_TYPE (t)) == TEMPLATE_TYPE_PARM)
+ /* Say `class T' not just `T'. */
+ OB_PUTS ("class ");
+
+ dump_type (TREE_TYPE (t), v);
break;
}
}
if (v > 0)
OB_PUTS ("typedef ");
- goto general;
+ dump_simple_decl (t, DECL_ORIGINAL_TYPE (t)
+ ? DECL_ORIGINAL_TYPE (t) : TREE_TYPE (t), v);
break;
case VAR_DECL:
@@ -600,32 +724,24 @@ dump_decl (t, v)
/* else fall through */
case FIELD_DECL:
case PARM_DECL:
- general:
- if (v > 0)
- {
- dump_type_prefix (TREE_TYPE (t), v);
- OB_PUTC (' ');
- dump_readonly_or_volatile (t, after);
- }
- /* DECL_CLASS_CONTEXT isn't being set in some cases. Hmm... */
- if (DECL_CONTEXT (t)
- && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) == 't')
- {
- dump_type (DECL_CONTEXT (t), 0);
- OB_PUTC2 (':', ':');
- }
- if (DECL_NAME (t))
- dump_decl (DECL_NAME (t), v);
- else
- OB_PUTS ("{anon}");
- if (v > 0)
- dump_type_suffix (TREE_TYPE (t), v);
+ dump_simple_decl (t, TREE_TYPE (t), v);
break;
case NAMESPACE_DECL:
+ if (DECL_CONTEXT (t) != global_namespace)
+ {
+ dump_decl (DECL_CONTEXT (t), v);
+ OB_PUTC2 (':',':');
+ }
OB_PUTID (DECL_NAME (t));
break;
+ case SCOPE_REF:
+ dump_decl (TREE_OPERAND (t, 0), 0);
+ OB_PUTS ("::");
+ dump_decl (TREE_OPERAND (t, 1), 0);
+ break;
+
case ARRAY_REF:
dump_decl (TREE_OPERAND (t, 0), v);
OB_PUTC ('[');
@@ -646,7 +762,7 @@ dump_decl (t, v)
break;
/* These special cases are duplicated here so that other functions
- can feed identifiers to cp_error and get them demangled properly. */
+ can feed identifiers to cp_error and get them demangled properly. */
case IDENTIFIER_NODE:
{ tree f;
if (DESTRUCTOR_NAME_P (t)
@@ -677,45 +793,64 @@ dump_decl (t, v)
case FUNCTION_DECL:
if (GLOBAL_IORD_P (DECL_ASSEMBLER_NAME (t)))
dump_global_iord (DECL_ASSEMBLER_NAME (t));
+ else if (! DECL_LANG_SPECIFIC (t))
+ OB_PUTS ("{internal}");
else
dump_function_decl (t, v);
break;
case TEMPLATE_DECL:
{
- tree args = DECL_TEMPLATE_PARMS (t);
- int i, len = args ? TREE_VEC_LENGTH (args) : 0;
- OB_PUTS ("template <");
- for (i = 0; i < len; i++)
+ tree orig_args = DECL_TEMPLATE_PARMS (t);
+ tree args;
+ int i;
+ for (args = orig_args = nreverse (orig_args);
+ args;
+ args = TREE_CHAIN (args))
{
- tree arg = TREE_VEC_ELT (args, i);
- tree defval = TREE_PURPOSE (arg);
- arg = TREE_VALUE (arg);
- if (TREE_CODE (arg) == TYPE_DECL)
- {
- OB_PUTS ("class ");
- OB_PUTID (DECL_NAME (arg));
- }
- else
- dump_decl (arg, 1);
+ int len = TREE_VEC_LENGTH (TREE_VALUE (args));
- if (defval)
+ OB_PUTS ("template <");
+ for (i = 0; i < len; i++)
{
- OB_PUTS (" = ");
- dump_decl (defval, 1);
- }
+ tree arg = TREE_VEC_ELT (TREE_VALUE (args), i);
+ tree defval = TREE_PURPOSE (arg);
+ arg = TREE_VALUE (arg);
+ if (TREE_CODE (arg) == TYPE_DECL)
+ {
+ if (DECL_NAME (arg))
+ {
+ OB_PUTS ("class ");
+ OB_PUTID (DECL_NAME (arg));
+ }
+ else
+ OB_PUTS ("class");
+ }
+ else
+ dump_decl (arg, 1);
+
+ if (defval)
+ {
+ OB_PUTS (" = ");
+ if (TREE_CODE (arg) == TYPE_DECL
+ || TREE_CODE (arg) == TEMPLATE_DECL)
+ dump_type (defval, 1);
+ else
+ dump_expr (defval, 1);
+ }
- OB_PUTC2 (',', ' ');
+ OB_PUTC2 (',', ' ');
+ }
+ if (len != 0)
+ OB_UNPUT (2);
+ OB_PUTC2 ('>', ' ');
}
- if (len != 0)
- OB_UNPUT (2);
- OB_PUTC2 ('>', ' ');
+ nreverse(orig_args);
- if (DECL_TEMPLATE_IS_CLASS (t))
- {
- OB_PUTS ("class ");
- OB_PUTID (DECL_NAME (t));
- }
+ if (TREE_CODE (DECL_TEMPLATE_RESULT (t)) == TYPE_DECL)
+ dump_type (TREE_TYPE (t), v);
+ else if (TREE_TYPE (t) == NULL_TREE)
+ my_friendly_abort (353);
else switch (NEXT_CODE (t))
{
case METHOD_TYPE:
@@ -724,20 +859,60 @@ dump_decl (t, v)
break;
default:
- my_friendly_abort (353);
+ /* This case can occur with some illegal code. */
+ dump_type (TREE_TYPE (t), v);
+ }
+ }
+ break;
+
+ case TEMPLATE_ID_EXPR:
+ {
+ tree args;
+ tree name = TREE_OPERAND (t, 0);
+ if (is_overloaded_fn (name))
+ name = DECL_NAME (get_first_fn (name));
+ dump_decl (name, v);
+ OB_PUTC ('<');
+ for (args = TREE_OPERAND (t, 1); args; args = TREE_CHAIN (args))
+ {
+ if (TREE_CODE_CLASS (TREE_CODE (TREE_VALUE (args))) == 't'
+ || TREE_CODE (TREE_VALUE (args)) == TEMPLATE_DECL)
+ dump_type (TREE_VALUE (args), 0);
+ else
+ dump_expr (TREE_VALUE (args), 0);
+ if (TREE_CHAIN (args))
+ OB_PUTC2 (',', ' ');
}
+ OB_PUTC ('>');
}
break;
+ case LOOKUP_EXPR:
+ dump_decl (TREE_OPERAND (t, 0), v);
+ break;
+
case LABEL_DECL:
OB_PUTID (DECL_NAME (t));
break;
case CONST_DECL:
- if (NEXT_CODE (t) == ENUMERAL_TYPE)
- goto general;
- else
+ if ((TREE_TYPE (t) != NULL_TREE && NEXT_CODE (t) == ENUMERAL_TYPE)
+ || (DECL_INITIAL (t) &&
+ TREE_CODE (DECL_INITIAL (t)) == TEMPLATE_PARM_INDEX))
+ dump_simple_decl (t, TREE_TYPE (t), v);
+ else if (DECL_NAME (t))
+ dump_decl (DECL_NAME (t), v);
+ else if (DECL_INITIAL (t))
dump_expr (DECL_INITIAL (t), 0);
+ else
+ OB_PUTS ("enumerator");
+ break;
+
+ case USING_DECL:
+ OB_PUTS ("using ");
+ dump_type (DECL_INITIAL (t), 0);
+ OB_PUTS ("::");
+ OB_PUTID (DECL_NAME (t));
break;
default:
@@ -755,11 +930,18 @@ dump_function_decl (t, v)
tree t;
int v;
{
- tree name = DECL_ASSEMBLER_NAME (t);
- tree fntype = TREE_TYPE (t);
- tree parmtypes = TYPE_ARG_TYPES (fntype);
+ tree name;
+ tree fntype;
+ tree parmtypes;
tree cname = NULL_TREE;
+ if (TREE_CODE (t) == TEMPLATE_DECL)
+ t = DECL_TEMPLATE_RESULT (t);
+
+ name = DECL_ASSEMBLER_NAME (t);
+ fntype = TREE_TYPE (t);
+ parmtypes = TYPE_ARG_TYPES (fntype);
+
/* Friends have DECL_CLASS_CONTEXT set, but not DECL_CONTEXT. */
if (DECL_CONTEXT (t))
cname = DECL_CLASS_CONTEXT (t);
@@ -778,7 +960,7 @@ dump_function_decl (t, v)
&& ! DECL_CONSTRUCTOR_P (t)
&& ! DESTRUCTOR_NAME_P (name))
{
- dump_type_prefix (TREE_TYPE (fntype), 1);
+ dump_type_prefix (TREE_TYPE (fntype), 1, 0);
OB_PUTC (' ');
}
}
@@ -809,7 +991,7 @@ dump_function_decl (t, v)
OB_PUTC (')');
if (v && ! IDENTIFIER_TYPENAME_P (name))
- dump_type_suffix (TREE_TYPE (fntype), 1);
+ dump_type_suffix (TREE_TYPE (fntype), 1, 0);
if (TREE_CODE (fntype) == METHOD_TYPE)
{
@@ -825,6 +1007,7 @@ dump_function_decl (t, v)
/* Handle the function name for a FUNCTION_DECL node, grokking operators
and destructors properly. */
+
static void
dump_function_name (t)
tree t;
@@ -858,11 +1041,98 @@ dump_function_name (t)
}
else
dump_decl (name, 0);
+
+ if (DECL_LANG_SPECIFIC (t) && DECL_USE_TEMPLATE (t))
+ {
+ tree args = DECL_TEMPLATE_INFO (t) ? DECL_TI_ARGS (t) : NULL_TREE;
+
+ if (args != NULL_TREE
+ && DECL_CONTEXT (t) != NULL_TREE
+ && uses_template_parms (DECL_CONTEXT (t))
+ /* This next clause checks that there is only one level of
+ template arguments. In that case, they are the
+ arguments for the class context. */
+ && (TREE_CODE (args) == TREE_LIST
+ || (TREE_CODE (args) == TREE_VEC
+ && TREE_VEC_ELT (args, 0) != NULL_TREE
+ && TREE_CODE (TREE_VEC_ELT (args, 0)) != TREE_VEC)))
+ /* We have something like this:
+
+ template <class T> struct S { void f(); };
+
+ and we are printing S<int>::f(). This is a template
+ instantiation, but we don't print anything after the f. */
+ ;
+ else
+ {
+ OB_PUTC ('<');
+
+ /* Be careful only to print things when we have them, so as not
+ to crash producing error messages. */
+ if (args)
+ {
+ if (TREE_CODE (args) == TREE_LIST)
+ {
+ tree arg;
+ int need_comma = 0;
+
+ for (arg = args; arg; arg = TREE_CHAIN (arg))
+ {
+ tree a = TREE_VALUE (arg);
+
+ if (need_comma)
+ OB_PUTS (", ");
+
+ if (a)
+ {
+ if (TREE_CODE_CLASS (TREE_CODE (a)) == 't'
+ || TREE_CODE (a) == TEMPLATE_DECL)
+ dump_type (a, 0);
+ else
+ dump_expr (a, 0);
+ }
+
+ need_comma = 1;
+ }
+ }
+ else if (TREE_CODE (args) == TREE_VEC)
+ {
+ int i;
+ int need_comma = 0;
+
+ if (TREE_VEC_LENGTH (args) > 0
+ && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+ args = TREE_VEC_ELT (args,
+ TREE_VEC_LENGTH (args) - 1);
+
+ for (i = 0; i < TREE_VEC_LENGTH (args); i++)
+ {
+ tree a = TREE_VEC_ELT (args, i);
+
+ if (need_comma)
+ OB_PUTS (", ");
+
+ if (a)
+ {
+ if (TREE_CODE_CLASS (TREE_CODE (a)) == 't'
+ || TREE_CODE (a) == TEMPLATE_DECL)
+ dump_type (a, 0);
+ else
+ dump_expr (a, 0);
+ }
+
+ need_comma = 1;
+ }
+ }
+ }
+ OB_PUTC ('>');
+ }
+ }
}
static void
dump_char (c)
- char c;
+ int c;
{
switch (c)
{
@@ -897,7 +1167,7 @@ dump_char (c)
OB_PUTS ("\\\"");
break;
default:
- if (isprint (c))
+ if (ISPRINT (c))
OB_PUTC (c);
else
{
@@ -908,6 +1178,7 @@ dump_char (c)
}
/* Print out a list of initializers (subr of dump_expr) */
+
static void
dump_expr_list (l)
tree l;
@@ -922,6 +1193,7 @@ dump_expr_list (l)
}
/* Print out an expression */
+
static void
dump_expr (t, nop)
tree t;
@@ -934,6 +1206,8 @@ dump_expr (t, nop)
case FIELD_DECL:
case CONST_DECL:
case FUNCTION_DECL:
+ case TEMPLATE_DECL:
+ case NAMESPACE_DECL:
dump_decl (t, -1);
break;
@@ -950,12 +1224,12 @@ dump_expr (t, nop)
}
else if (type == boolean_type_node)
{
- if (t == boolean_false_node)
+ if (t == boolean_false_node
+ || (TREE_INT_CST_LOW (t) == 0
+ && TREE_INT_CST_HIGH (t) == 0))
OB_PUTS ("false");
else if (t == boolean_true_node)
OB_PUTS ("true");
- else
- my_friendly_abort (366);
}
else if (type == char_type_node)
{
@@ -995,7 +1269,7 @@ dump_expr (t, nop)
#else
{
unsigned char *p = (unsigned char *) &TREE_REAL_CST (t);
- int i;
+ size_t i;
strcpy (digit_buffer, "0x");
for (i = 0; i < sizeof TREE_REAL_CST (t); i++)
sprintf (digit_buffer + 2 + 2*i, "%02x", *p++);
@@ -1044,10 +1318,11 @@ dump_expr (t, nop)
}
break;
- case NEW_EXPR:
+ case AGGR_INIT_EXPR:
OB_PUTID (TYPE_IDENTIFIER (TREE_TYPE (t)));
OB_PUTC ('(');
- dump_expr_list (TREE_CHAIN (TREE_OPERAND (t, 1)));
+ if (TREE_OPERAND (t, 1))
+ dump_expr_list (TREE_CHAIN (TREE_OPERAND (t, 1)));
OB_PUTC (')');
break;
@@ -1059,7 +1334,7 @@ dump_expr (t, nop)
if (TREE_CODE (fn) == ADDR_EXPR)
fn = TREE_OPERAND (fn, 0);
- if (NEXT_CODE (fn) == METHOD_TYPE)
+ if (TREE_TYPE (fn) != NULL_TREE && NEXT_CODE (fn) == METHOD_TYPE)
{
tree ob = TREE_VALUE (args);
if (TREE_CODE (ob) == ADDR_EXPR)
@@ -1076,16 +1351,37 @@ dump_expr (t, nop)
args = TREE_CHAIN (args);
}
dump_expr (fn, 0);
- OB_PUTC('(');
+ OB_PUTC ('(');
dump_expr_list (args);
OB_PUTC (')');
}
break;
- case WITH_CLEANUP_EXPR:
- /* Note that this only works for G++ cleanups. If somebody
- builds a general cleanup, there's no way to represent it. */
- dump_expr (TREE_OPERAND (t, 0), 0);
+ case NEW_EXPR:
+ {
+ tree type = TREE_OPERAND (t, 1);
+ if (NEW_EXPR_USE_GLOBAL (t))
+ OB_PUTS ("::");
+ OB_PUTS ("new ");
+ if (TREE_OPERAND (t, 0))
+ {
+ OB_PUTC ('(');
+ dump_expr_list (TREE_OPERAND (t, 0));
+ OB_PUTS (") ");
+ }
+ if (TREE_CODE (type) == ARRAY_REF)
+ type = build_cplus_array_type
+ (TREE_OPERAND (type, 0),
+ build_index_type (size_binop (MINUS_EXPR, TREE_OPERAND (type, 1),
+ integer_one_node)));
+ dump_type (type, 0);
+ if (TREE_OPERAND (t, 2))
+ {
+ OB_PUTC ('(');
+ dump_expr_list (TREE_OPERAND (t, 2));
+ OB_PUTC (')');
+ }
+ }
break;
case TARGET_EXPR:
@@ -1188,7 +1484,8 @@ dump_expr (t, nop)
}
else
{
- if (NEXT_CODE (TREE_OPERAND (t, 0)) == REFERENCE_TYPE)
+ if (TREE_OPERAND (t,0) != NULL_TREE
+ && NEXT_CODE (TREE_OPERAND (t, 0)) == REFERENCE_TYPE)
dump_expr (TREE_OPERAND (t, 0), nop);
else
dump_unary_op ("*", t, nop);
@@ -1215,7 +1512,7 @@ dump_expr (t, nop)
/* FIXME: This is a KLUDGE workaround for a parsing problem. There
should be another level of INDIRECT_REF so that I don't have to do
this. */
- if (NEXT_CODE (t) == POINTER_TYPE)
+ if (TREE_TYPE (t) != NULL_TREE && NEXT_CODE (t) == POINTER_TYPE)
{
tree next = TREE_TYPE (TREE_TYPE (t));
@@ -1240,8 +1537,46 @@ dump_expr (t, nop)
break;
case CONSTRUCTOR:
+ if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
+ {
+ tree idx = build_component_ref (t, index_identifier, NULL_TREE, 0);
+
+ if (integer_all_onesp (idx))
+ {
+ tree pfn = PFN_FROM_PTRMEMFUNC (t);
+ dump_expr (pfn, 0);
+ break;
+ }
+ if (TREE_CODE (idx) == INTEGER_CST
+ && TREE_INT_CST_HIGH (idx) == 0)
+ {
+ tree virtuals;
+ unsigned HOST_WIDE_INT n;
+
+ t = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t)));
+ t = TYPE_METHOD_BASETYPE (t);
+ virtuals = BINFO_VIRTUALS (TYPE_BINFO (TYPE_MAIN_VARIANT (t)));
+
+ n = TREE_INT_CST_LOW (idx);
+
+ /* Map vtable index back one, to allow for the null pointer to
+ member. */
+ --n;
+
+ while (n > 0 && virtuals)
+ {
+ --n;
+ virtuals = TREE_CHAIN (virtuals);
+ }
+ if (virtuals)
+ {
+ dump_expr (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0);
+ break;
+ }
+ }
+ }
OB_PUTC ('{');
- dump_expr_list (CONSTRUCTOR_ELTS (t), 0);
+ dump_expr_list (CONSTRUCTOR_ELTS (t));
OB_PUTC ('}');
break;
@@ -1255,12 +1590,82 @@ dump_expr (t, nop)
dump_expr (TREE_OPERAND (t, 1), 0);
else
{
- sorry ("operand of OFFSET_REF not understood");
- goto error;
+ dump_expr (TREE_OPERAND (t, 0), 0);
+ OB_PUTS (" .* ");
+ dump_expr (TREE_OPERAND (t, 1), 0);
}
break;
}
+ case TEMPLATE_PARM_INDEX:
+ dump_decl (TEMPLATE_PARM_DECL (t), -1);
+ break;
+
+ case IDENTIFIER_NODE:
+ OB_PUTID (t);
+ break;
+
+ case SCOPE_REF:
+ dump_type (TREE_OPERAND (t, 0), 0);
+ OB_PUTS ("::");
+ dump_expr (TREE_OPERAND (t, 1), 0);
+ break;
+
+ case CAST_EXPR:
+ if (TREE_OPERAND (t, 0) == NULL_TREE
+ || TREE_CHAIN (TREE_OPERAND (t, 0)))
+ {
+ dump_type (TREE_TYPE (t), 0);
+ OB_PUTC ('(');
+ dump_expr_list (TREE_OPERAND (t, 0));
+ OB_PUTC (')');
+ }
+ else
+ {
+ OB_PUTC ('(');
+ dump_type (TREE_TYPE (t), 0);
+ OB_PUTC (')');
+ OB_PUTC ('(');
+ dump_expr_list (TREE_OPERAND (t, 0));
+ OB_PUTC (')');
+ }
+ break;
+
+ case LOOKUP_EXPR:
+ OB_PUTID (TREE_OPERAND (t, 0));
+ break;
+
+ case ARROW_EXPR:
+ dump_expr (TREE_OPERAND (t, 0), nop);
+ OB_PUTS ("->");
+ break;
+
+ case SIZEOF_EXPR:
+ case ALIGNOF_EXPR:
+ if (TREE_CODE (t) == SIZEOF_EXPR)
+ OB_PUTS ("sizeof (");
+ else
+ {
+ my_friendly_assert (TREE_CODE (t) == ALIGNOF_EXPR, 0);
+ OB_PUTS ("__alignof__ (");
+ }
+ if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 0))) == 't')
+ dump_type (TREE_OPERAND (t, 0), 0);
+ else
+ dump_unary_op ("*", t, 0);
+ OB_PUTC (')');
+ break;
+
+ case DEFAULT_ARG:
+ OB_PUTS ("{unparsed}");
+ break;
+
+ case TRY_CATCH_EXPR:
+ case WITH_CLEANUP_EXPR:
+ case CLEANUP_POINT_EXPR:
+ dump_expr (TREE_OPERAND (t, 0), nop);
+ break;
+
case TREE_LIST:
if (TREE_VALUE (t) && TREE_CODE (TREE_VALUE (t)) == FUNCTION_DECL)
{
@@ -1278,7 +1683,6 @@ dump_expr (t, nop)
/* fall through to ERROR_MARK... */
case ERROR_MARK:
- error:
OB_PUTCP ("{error}");
break;
}
@@ -1311,34 +1715,47 @@ dump_unary_op (opstring, t, nop)
}
char *
-fndecl_as_string (cname, fndecl, print_ret_type_p)
- tree cname, fndecl;
+fndecl_as_string (fndecl, print_ret_type_p)
+ tree fndecl;
int print_ret_type_p;
{
return decl_as_string (fndecl, print_ret_type_p);
}
-/* Same, but handtype a _TYPE.
+/* Same, but handle a _TYPE.
Called from convert_to_reference, mangle_class_name_for_template,
- build_unary_op, and GNU_xref_decl. */
+ build_unary_op, and GNU_xref_decl. If CANONICAL_NAME is non-zero,
+ when describing a typedef, we use the name of the type described,
+ rather than the name of the typedef. */
+
char *
-type_as_string (typ, v)
+type_as_string_real (typ, v, canonical_name)
tree typ;
int v;
+ int canonical_name;
{
OB_INIT ();
- dump_type (typ, v);
+ dump_type_real (typ, v, canonical_name);
OB_FINISH ();
return (char *)obstack_base (&scratch_obstack);
}
+
+char *
+type_as_string (typ, v)
+ tree typ;
+ int v;
+{
+ return type_as_string_real (typ, v, 0);
+}
+
char *
expr_as_string (decl, v)
tree decl;
- int v;
+ int v ATTRIBUTE_UNUSED;
{
OB_INIT ();
@@ -1351,6 +1768,7 @@ expr_as_string (decl, v)
/* A cross between type_as_string and fndecl_as_string.
Only called from substitute_nice_name. */
+
char *
decl_as_string (decl, v)
tree decl;
@@ -1365,14 +1783,48 @@ decl_as_string (decl, v)
return (char *)obstack_base (&scratch_obstack);
}
+/* Generate the three forms of printable names for lang_printable_name. */
+
+char *
+lang_decl_name (decl, v)
+ tree decl;
+ int v;
+{
+ if (v >= 2)
+ return decl_as_string (decl, 1);
+
+ OB_INIT ();
+
+ if (v == 1 && DECL_CLASS_SCOPE_P (decl))
+ {
+ tree cname;
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ cname = DECL_CLASS_CONTEXT (decl);
+ else
+ cname = DECL_CONTEXT (decl);
+ dump_type (cname, 0);
+ OB_PUTC2 (':', ':');
+ }
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ dump_function_name (decl);
+ else
+ dump_decl (DECL_NAME (decl), 0);
+
+ OB_FINISH ();
+
+ return (char *)obstack_base (&scratch_obstack);
+}
+
+
char *
cp_file_of (t)
tree t;
{
- if (TREE_CODE (t) == PARM_DECL)
+ if (TREE_CODE (t) == PARM_DECL && DECL_CONTEXT (t))
return DECL_SOURCE_FILE (DECL_CONTEXT (t));
else if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
- return DECL_SOURCE_FILE (TYPE_NAME (t));
+ return DECL_SOURCE_FILE (TYPE_MAIN_DECL (t));
else
return DECL_SOURCE_FILE (t);
}
@@ -1382,18 +1834,13 @@ cp_line_of (t)
tree t;
{
int line = 0;
- if (TREE_CODE (t) == PARM_DECL)
+ if (TREE_CODE (t) == PARM_DECL && DECL_CONTEXT (t))
line = DECL_SOURCE_LINE (DECL_CONTEXT (t));
if (TREE_CODE (t) == TYPE_DECL && DECL_ARTIFICIAL (t))
t = TREE_TYPE (t);
if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
- {
- if (IS_AGGR_TYPE (t))
- line = CLASSTYPE_SOURCE_LINE (t);
- else
- line = DECL_SOURCE_LINE (TYPE_NAME (t));
- }
+ line = DECL_SOURCE_LINE (TYPE_MAIN_DECL (t));
else
line = DECL_SOURCE_LINE (t);
@@ -1406,7 +1853,7 @@ cp_line_of (t)
char *
code_as_string (c, v)
enum tree_code c;
- int v;
+ int v ATTRIBUTE_UNUSED;
{
return tree_code_name [c];
}
@@ -1414,7 +1861,7 @@ code_as_string (c, v)
char *
language_as_string (c, v)
enum languages c;
- int v;
+ int v ATTRIBUTE_UNUSED;
{
switch (c)
{
@@ -1424,6 +1871,9 @@ language_as_string (c, v)
case lang_cplusplus:
return "C++";
+ case lang_java:
+ return "Java";
+
default:
my_friendly_abort (355);
return 0;
@@ -1431,9 +1881,11 @@ language_as_string (c, v)
}
/* Return the proper printed version of a parameter to a C++ function. */
+
char *
parm_as_string (p, v)
- int p, v;
+ int p;
+ int v ATTRIBUTE_UNUSED;
{
if (p < 0)
return "`this'";
@@ -1445,7 +1897,7 @@ parm_as_string (p, v)
char *
op_as_string (p, v)
enum tree_code p;
- int v;
+ int v ATTRIBUTE_UNUSED;
{
static char buf[] = "operator ";
@@ -1457,20 +1909,48 @@ op_as_string (p, v)
}
char *
+assop_as_string (p, v)
+ enum tree_code p;
+ int v ATTRIBUTE_UNUSED;
+{
+ static char buf[] = "operator ";
+
+ if (p == 0)
+ return "{unknown}";
+
+ strcpy (buf + 9, assignop_tab [p]);
+ return buf;
+}
+
+char *
args_as_string (p, v)
tree p;
int v;
{
if (p == NULL_TREE)
- return "...";
+ return "";
+
+ if (TREE_CODE_CLASS (TREE_CODE (TREE_VALUE (p))) == 't')
+ return type_as_string (p, v);
- return type_as_string (p, v);
+ OB_INIT ();
+ for (; p; p = TREE_CHAIN (p))
+ {
+ if (TREE_VALUE (p) == null_node)
+ OB_PUTS ("NULL");
+ else
+ dump_type (error_type (TREE_VALUE (p)), v);
+ if (TREE_CHAIN (p))
+ OB_PUTS (", ");
+ }
+ OB_FINISH ();
+ return (char *)obstack_base (&scratch_obstack);
}
char *
cv_as_string (p, v)
tree p;
- int v;
+ int v ATTRIBUTE_UNUSED;
{
OB_INIT ();
diff --git a/contrib/gcc/cp/except.c b/contrib/gcc/cp/except.c
index 51577f8..d294497 100644
--- a/contrib/gcc/cp/except.c
+++ b/contrib/gcc/cp/except.c
@@ -1,5 +1,5 @@
/* Handle exceptional things in C++.
- Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
Contributed by Michael Tiemann <tiemann@cygnus.com>
Rewritten by Mike Stump <mrs@cygnus.com>, based upon an
initial re-implementation courtesy Tad Hunt.
@@ -22,91 +22,48 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* High-level class interface. */
-
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "cp-tree.h"
#include "flags.h"
#include "obstack.h"
#include "expr.h"
+#include "output.h"
+#include "except.h"
+#include "function.h"
+#include "defaults.h"
+#include "toplev.h"
+#include "eh-common.h"
-tree protect_list;
-
-extern void (*interim_eh_hook) PROTO((tree));
rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
-/* holds the fndecl for __builtin_return_address () */
+/* Holds the fndecl for __builtin_return_address. */
tree builtin_return_address_fndecl;
-tree throw_fndecl;
-
-static int
-doing_eh (do_warn)
- int do_warn;
-{
- if (! flag_handle_exceptions)
- {
- static int warned = 0;
- if (! warned && do_warn)
- {
- error ("exception handling disabled, use -fhandle-exceptions to enable.");
- warned = 1;
- }
- return 0;
- }
- return 1;
-}
-
-
-/*
-NO GNEWS IS GOOD GNEWS WITH GARRY GNUS: This version is much closer
-to supporting exception handling as per ANSI C++ working draft.
-It is a complete rewrite of all the EH stuff that was here before
- Shortcomings:
- 1. Throw specifications of functions still don't work.
- Cool Things:
- 1. Destructors are called properly :-)
- 2. No overhead for the non-exception thrown case.
- 3. Fixing shortcoming 1 is simple.
- -Tad Hunt (tad@mail.csh.rit.edu)
-
-*/
/* A couple of backend routines from m88k.c */
-/* used to cache a call to __builtin_return_address () */
-static tree BuiltinReturnAddress;
-
-
-#include <stdio.h>
-
-/* XXX - Tad: for EH */
-/* output an exception table entry */
-
-static void
-output_exception_table_entry (file, start_label, end_label, eh_label)
- FILE *file;
- rtx start_label, end_label, eh_label;
-{
- char label[100];
-
- assemble_integer (start_label, GET_MODE_SIZE (Pmode), 1);
- assemble_integer (end_label, GET_MODE_SIZE (Pmode), 1);
- assemble_integer (eh_label, GET_MODE_SIZE (Pmode), 1);
- putc ('\n', file); /* blank line */
-}
-
-static void
-easy_expand_asm (str)
- char *str;
-{
- expand_asm (build_string (strlen (str)+1, str));
-}
-
+static void push_eh_cleanup PROTO((void));
+static tree build_eh_type_type PROTO((tree));
+static tree build_eh_type PROTO((tree));
+static void expand_end_eh_spec PROTO((tree));
+static tree call_eh_info PROTO((void));
+static void push_eh_info PROTO((void));
+static tree get_eh_info PROTO((void));
+static tree get_eh_value PROTO((void));
+static tree get_eh_type PROTO((void));
+static tree get_eh_caught PROTO((void));
+static tree get_eh_handlers PROTO((void));
+static tree do_pop_exception PROTO((void));
+static void process_start_catch_block PROTO((tree, tree));
+static void process_start_catch_block_old PROTO((tree, tree));
+static tree build_eh_type_type_ref PROTO((tree));
+static tree build_terminate_handler PROTO((void));
+static tree alloc_eh_object PROTO((tree));
#if 0
-/* This is the startup, and finish stuff per exception table. */
+/* This is the startup, and finish stuff per exception table. */
/* XXX - Tad: exception handling section */
#ifndef EXCEPT_SECTION_ASM_OP
@@ -114,14 +71,6 @@ easy_expand_asm (str)
#endif
#ifdef EXCEPT_SECTION_ASM_OP
-typedef struct {
- void *start_protect;
- void *end_protect;
- void *exception_handler;
- } exception_table;
-#endif /* EXCEPT_SECTION_ASM_OP */
-
-#ifdef EXCEPT_SECTION_ASM_OP
/* on machines which support it, the exception table lives in another section,
but it needs a label so we can reference it... This sets up that
@@ -145,45 +94,9 @@ asm (TEXT_SECTION_ASM_OP);
#endif
-void
-exception_section ()
-{
-#ifdef ASM_OUTPUT_SECTION_NAME
- named_section (NULL_TREE, ".gcc_except_table");
-#else
- if (flag_pic)
- data_section ();
- else
-#if defined(TARGET_POWERPC) /* are we on a __rs6000? */
- data_section ();
-#else
- readonly_data_section ();
-#endif
-#endif
-}
-
-
-
-
-/* from: my-cp-except.c */
-
-/* VI: ":set ts=4" */
-#if 0
-#include <stdio.h> */
-#include "config.h"
-#include "tree.h"
-#include "rtl.h"
-#include "cp-tree.h"
-#endif
#include "decl.h"
-#if 0
-#include "flags.h"
-#endif
#include "insn-flags.h"
#include "obstack.h"
-#if 0
-#include "expr.h"
-#endif
/* ======================================================================
Briefly the algorithm works like this:
@@ -194,15 +107,15 @@ exception_section ()
output to start the protection for that block.
When a destructor or end try block is encountered, pop_eh_entry
- (&eh_stack) is called. Pop_eh_entry () returns the ehEntry it
- created when push_eh_entry () was called. The ehEntry structure
+ (&eh_stack) is called. Pop_eh_entry () returns the eh_entry it
+ created when push_eh_entry () was called. The eh_entry structure
contains three things at this point. The start protect label,
the end protect label, and the exception handler label. The end
protect label should be output before the call to the destructor
(if any). If it was a destructor, then its parse tree is stored
- in the finalization variable in the ehEntry structure. Otherwise
+ in the finalization variable in the eh_entry structure. Otherwise
the finalization variable is set to NULL to reflect the fact that
- is the the end of a try block. Next, this modified ehEntry node
+ it is the end of a try block. Next, this modified eh_entry node
is enqueued in the finalizations queue by calling
enqueue_eh_entry (&queue,entry).
@@ -231,12 +144,12 @@ exception_section ()
any of those finalizations throw an exception, we must call
terminate according to the ARM (section r.15.6.1). What this
means is that we need to dequeue and emit finalizations for each
- entry in the ehQueue until we get to an entry with a NULL
+ entry in the eh_queue until we get to an entry with a NULL
finalization field. For any of the finalization entries, if it
is not a call to terminate (), we must protect it by giving it
another start label, end label, and exception handler label,
setting its finalization tree to be a call to terminate (), and
- enqueue'ing this new ehEntry to be output at an outer level.
+ enqueue'ing this new eh_entry to be output at an outer level.
Finally, after all that is done, we can get around to outputting
the catch block which basically wraps all the "catch (...) {...}"
statements in a big if/then/else construct that matches the
@@ -244,66 +157,21 @@ exception_section ()
===================================================================== */
-extern rtx emit_insn PROTO((rtx));
-extern rtx gen_nop PROTO(());
-
/* local globals for function calls
====================================================================== */
-/* used to cache "terminate ()", "unexpected ()", "set_terminate ()", and
- "set_unexpected ()" after default_conversion. (lib-except.c) */
-static tree Terminate, Unexpected, SetTerminate, SetUnexpected, CatchMatch, Throw;
+/* Used to cache "terminate" and "__throw_type_match*". */
+static tree Terminate, CatchMatch;
-/* used to cache __find_first_exception_table_match ()
- for throw (lib-except.c) */
+/* Used to cache __find_first_exception_table_match for throw. */
static tree FirstExceptionMatch;
-/* used to cache a call to __unwind_function () (lib-except.c) */
+/* Used to cache a call to __unwind_function. */
static tree Unwind;
-/* holds a ready to emit call to "terminate ()". */
-static tree TerminateFunctionCall;
-
/* ====================================================================== */
-
-/* data structures for my various quick and dirty stacks and queues
- Eventually, most of this should go away, because I think it can be
- integrated with stuff already built into the compiler. */
-
-/* =================================================================== */
-
-struct labelNode {
- rtx label;
- struct labelNode *chain;
-};
-
-
-/* this is the most important structure here. Basically this is how I store
- an exception table entry internally. */
-struct ehEntry {
- rtx start_label;
- rtx end_label;
- rtx exception_handler_label;
-
- tree finalization;
- tree context;
-};
-
-struct ehNode {
- struct ehEntry *entry;
- struct ehNode *chain;
-};
-
-struct ehStack {
- struct ehNode *top;
-};
-
-struct ehQueue {
- struct ehNode *head;
- struct ehNode *tail;
-};
/* ========================================================================= */
@@ -313,538 +181,247 @@ struct ehQueue {
========================================================================= */
-/* Holds the pc for doing "throw" */
-tree saved_pc;
-/* Holds the type of the thing being thrown. */
-tree saved_throw_type;
-/* Holds the value being thrown. */
-tree saved_throw_value;
+extern rtx catch_clauses;
+extern tree const_ptr_type_node;
-int throw_used;
-
-static rtx catch_clauses;
-static first_catch_label;
-
-static struct ehStack ehstack;
-static struct ehQueue ehqueue;
-static struct ehQueue eh_table_output_queue;
-static struct labelNode *false_label_stack = NULL;
-static struct labelNode *caught_return_label_stack = NULL;
/* ========================================================================= */
-/* function prototypes */
-static struct ehEntry *pop_eh_entry PROTO((struct ehStack *stack));
-static void enqueue_eh_entry PROTO((struct ehQueue *queue, struct ehEntry *entry));
-static rtx push_eh_entry PROTO((struct ehStack *stack));
-static struct ehEntry *dequeue_eh_entry PROTO((struct ehQueue *queue));
-static void new_eh_queue PROTO((struct ehQueue *queue));
-static void new_eh_stack PROTO((struct ehStack *stack));
-static void push_label_entry PROTO((struct labelNode **labelstack, rtx label));
-static rtx pop_label_entry PROTO((struct labelNode **labelstack));
-static rtx top_label_entry PROTO((struct labelNode **labelstack));
-static struct ehEntry *copy_eh_entry PROTO((struct ehEntry *entry));
-
-
-
-/* All my cheesy stack/queue/misc data structure handling routines
-
- ========================================================================= */
-
-static void
-push_label_entry (labelstack, label)
- struct labelNode **labelstack;
- rtx label;
-{
- struct labelNode *newnode=(struct labelNode*)xmalloc (sizeof (struct labelNode));
-
- newnode->label = label;
- newnode->chain = *labelstack;
- *labelstack = newnode;
-}
-
-static rtx
-pop_label_entry (labelstack)
- struct labelNode **labelstack;
-{
- rtx label;
- struct labelNode *tempnode;
-
- if (! *labelstack) return NULL_RTX;
-
- tempnode = *labelstack;
- label = tempnode->label;
- *labelstack = (*labelstack)->chain;
- free (tempnode);
-
- return label;
-}
-
-static rtx
-top_label_entry (labelstack)
- struct labelNode **labelstack;
-{
- if (! *labelstack) return NULL_RTX;
+/* sets up all the global eh stuff that needs to be initialized at the
+ start of compilation.
- return (*labelstack)->label;
-}
+ This includes:
+ - Setting up all the function call trees. */
-/* Push to permanent obstack for rtl generation.
- One level only! */
-static struct obstack *saved_rtl_obstack;
void
-push_rtl_perm ()
-{
- extern struct obstack permanent_obstack;
- extern struct obstack *rtl_obstack;
-
- saved_rtl_obstack = rtl_obstack;
- rtl_obstack = &permanent_obstack;
-}
-
-/* Pop back to normal rtl handling. */
-static void
-pop_rtl_from_perm ()
+init_exception_processing ()
{
- extern struct obstack permanent_obstack;
- extern struct obstack *rtl_obstack;
+ /* void vtype () */
+ tree vtype = build_function_type (void_type_node, void_list_node);
- rtl_obstack = saved_rtl_obstack;
-}
-
-static rtx
-push_eh_entry (stack)
- struct ehStack *stack;
-{
- struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
- struct ehEntry *entry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
-
- if (stack == NULL) {
- free (node);
- free (entry);
- return NULL_RTX;
- }
-
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry->start_label = gen_label_rtx ();
- entry->end_label = gen_label_rtx ();
- entry->exception_handler_label = gen_label_rtx ();
- pop_rtl_from_perm ();
-
- LABEL_PRESERVE_P (entry->start_label) = 1;
- LABEL_PRESERVE_P (entry->end_label) = 1;
- LABEL_PRESERVE_P (entry->exception_handler_label) = 1;
-
- entry->finalization = NULL_TREE;
- entry->context = current_function_decl;
-
- node->entry = entry;
- node->chain = stack->top;
- stack->top = node;
-
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (entry));
-
- return entry->start_label;
-}
+ if (flag_honor_std)
+ push_namespace (get_identifier ("std"));
+ Terminate = auto_function (get_identifier ("terminate"),
+ vtype, NOT_BUILT_IN);
+ TREE_THIS_VOLATILE (Terminate) = 1;
+ if (flag_honor_std)
+ pop_namespace ();
-static struct ehEntry *
-pop_eh_entry (stack)
- struct ehStack *stack;
-{
- struct ehNode *tempnode;
- struct ehEntry *tempentry;
+ push_lang_context (lang_name_c);
- if (stack && (tempnode = stack->top)) {
- tempentry = tempnode->entry;
- stack->top = stack->top->chain;
- free (tempnode);
+ set_exception_lang_code (EH_LANG_C_plus_plus);
+ set_exception_version_code (1);
+
+ CatchMatch
+ = builtin_function (flag_rtti
+ ? "__throw_type_match_rtti"
+ : "__throw_type_match",
+ build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE, const_ptr_type_node,
+ tree_cons (NULL_TREE, const_ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ void_list_node)))),
+ NOT_BUILT_IN, NULL_PTR);
+ FirstExceptionMatch
+ = builtin_function ("__find_first_exception_table_match",
+ build_function_type (ptr_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ void_list_node)),
+ NOT_BUILT_IN, NULL_PTR);
+ Unwind
+ = builtin_function ("__unwind_function",
+ build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ void_list_node)),
+ NOT_BUILT_IN, NULL_PTR);
- return tempentry;
- }
+ pop_lang_context ();
- return NULL;
+ /* If we use setjmp/longjmp EH, arrange for all cleanup actions to
+ be protected with __terminate. */
+ protect_cleanup_actions_with_terminate = 1;
}
-static struct ehEntry *
-copy_eh_entry (entry)
- struct ehEntry *entry;
-{
- struct ehEntry *newentry;
-
- newentry = (struct ehEntry*)xmalloc (sizeof (struct ehEntry));
- memcpy ((void*)newentry, (void*)entry, sizeof (struct ehEntry));
+/* Retrieve a pointer to the cp_eh_info node for the current exception. */
- return newentry;
-}
-
-static void
-enqueue_eh_entry (queue, entry)
- struct ehQueue *queue;
- struct ehEntry *entry;
+static tree
+call_eh_info ()
{
- struct ehNode *node = (struct ehNode*)xmalloc (sizeof (struct ehNode));
+ tree fn;
- node->entry = entry;
- node->chain = NULL;
-
- if (queue->head == NULL)
- {
- queue->head = node;
- }
+ fn = get_identifier ("__cp_eh_info");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- queue->tail->chain = node;
+ tree t1, t, fields[7];
+
+ /* Declare cp_eh_info * __cp_eh_info (void),
+ as defined in exception.cc. */
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ /* struct cp_eh_info. This must match exception.cc. Note that this
+ type is not pushed anywhere. */
+ t1= make_lang_type (RECORD_TYPE);
+ fields[0] = build_lang_field_decl (FIELD_DECL,
+ get_identifier ("handler_label"), ptr_type_node);
+ fields[1] = build_lang_field_decl (FIELD_DECL,
+ get_identifier ("dynamic_handler_chain"), ptr_type_node);
+ fields[2] = build_lang_field_decl (FIELD_DECL,
+ get_identifier ("info"), ptr_type_node);
+ /* N.B.: The fourth field LEN is expected to be
+ the number of fields - 1, not the total number of fields. */
+ finish_builtin_type (t1, "eh_context", fields, 2, ptr_type_node);
+ t1 = build_pointer_type (t1);
+
+ t1= make_lang_type (RECORD_TYPE);
+ fields[0] = build_lang_field_decl (FIELD_DECL,
+ get_identifier ("match_function"), ptr_type_node);
+ fields[1] = build_lang_field_decl (FIELD_DECL,
+ get_identifier ("language"), short_integer_type_node);
+ fields[2] = build_lang_field_decl (FIELD_DECL,
+ get_identifier ("version"), short_integer_type_node);
+ /* N.B.: The fourth field LEN is expected to be
+ the number of fields - 1, not the total number of fields. */
+ finish_builtin_type (t1, "__eh_info", fields, 2, ptr_type_node);
+ t = make_lang_type (RECORD_TYPE);
+ fields[0] = build_lang_field_decl (FIELD_DECL,
+ get_identifier ("eh_info"), t1);
+ fields[1] = build_lang_field_decl (FIELD_DECL, get_identifier ("value"),
+ ptr_type_node);
+ fields[2] = build_lang_field_decl (FIELD_DECL, get_identifier ("type"),
+ ptr_type_node);
+ fields[3] = build_lang_field_decl
+ (FIELD_DECL, get_identifier ("cleanup"),
+ build_pointer_type (build_function_type
+ (ptr_type_node, tree_cons
+ (NULL_TREE, ptr_type_node, void_list_node))));
+ fields[4] = build_lang_field_decl (FIELD_DECL, get_identifier ("caught"),
+ boolean_type_node);
+ fields[5] = build_lang_field_decl (FIELD_DECL, get_identifier ("next"),
+ build_pointer_type (t));
+ fields[6] = build_lang_field_decl
+ (FIELD_DECL, get_identifier ("handlers"), long_integer_type_node);
+ /* N.B.: The fourth field LEN is expected to be
+ the number of fields - 1, not the total number of fields. */
+ finish_builtin_type (t, "cp_eh_info", fields, 6, ptr_type_node);
+ t = build_pointer_type (t);
+
+ /* And now the function. */
+ fn = build_lang_decl (FUNCTION_DECL, fn,
+ build_function_type (t, void_list_node));
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
}
- queue->tail = node;
+ return build_function_call (fn, NULL_TREE);
}
-static struct ehEntry *
-dequeue_eh_entry (queue)
- struct ehQueue *queue;
-{
- struct ehNode *tempnode;
- struct ehEntry *tempentry;
-
- if (queue->head == NULL)
- return NULL;
-
- tempnode = queue->head;
- queue->head = queue->head->chain;
-
- tempentry = tempnode->entry;
- free (tempnode);
-
- return tempentry;
-}
+/* Retrieve a pointer to the cp_eh_info node for the current exception
+ and save it in the current binding level. */
static void
-new_eh_queue (queue)
- struct ehQueue *queue;
+push_eh_info ()
{
- queue->head = queue->tail = NULL;
+ tree decl, fn = call_eh_info ();
+
+ /* Remember the pointer to the current exception info; it won't change
+ during this catch block. */
+ decl = build_decl (VAR_DECL, get_identifier ("__exception_info"),
+ TREE_TYPE (fn));
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_INITIAL (decl) = fn;
+ decl = pushdecl (decl);
+ cp_finish_decl (decl, fn, NULL_TREE, 0, 0);
}
-static void
-new_eh_stack (stack)
- struct ehStack *stack;
-{
- stack->top = NULL;
-}
+/* Returns a reference to the cp_eh_info node for the current exception. */
-/* cheesyness to save some typing. returns the return value rtx */
-rtx
-do_function_call (func, params, return_type)
- tree func, params, return_type;
+static tree
+get_eh_info ()
{
- tree func_call;
- func_call = build_function_call (func, params);
- expand_call (func_call, NULL_RTX, 0);
- if (return_type != NULL_TREE)
- return hard_function_value (return_type, func_call);
- return NULL_RTX;
+ /* Look for the pointer pushed in push_eh_info. */
+ tree t = lookup_name (get_identifier ("__exception_info"), 0);
+ return build_indirect_ref (t, NULL_PTR);
}
-static void
-expand_internal_throw (pc)
- rtx pc;
-{
- tree params;
+/* Returns a reference to the current exception object. */
- emit_move_insn (DECL_RTL (saved_pc), pc);
-#ifdef JUMP_TO_THROW
- emit_indirect_jump (gen_rtx (SYMBOL_REF, Pmode, "__throw"));
-#else
- do_function_call (Throw, NULL_TREE, NULL_TREE);
-#endif
- throw_used = 1;
-}
-
-/* ========================================================================= */
-
-void
-lang_interim_eh (finalization)
- tree finalization;
+static tree
+get_eh_value ()
{
- if (finalization)
- end_protect (finalization);
- else
- start_protect ();
+ return build_component_ref (get_eh_info (), get_identifier ("value"),
+ NULL_TREE, 0);
}
-extern tree auto_function PROTO((tree, tree, enum built_in_function));
-
-/* sets up all the global eh stuff that needs to be initialized at the
- start of compilation.
+/* Returns a reference to the current exception type. */
- This includes:
- - Setting up all the function call trees
- - Initializing the ehqueue
- - Initializing the eh_table_output_queue
- - Initializing the ehstack
-*/
-
-void
-init_exception_processing ()
+static tree
+get_eh_type ()
{
- extern tree define_function ();
- tree unexpected_fndecl, terminate_fndecl;
- tree set_unexpected_fndecl, set_terminate_fndecl;
- tree catch_match_fndecl;
- tree find_first_exception_match_fndecl;
- tree unwind_fndecl;
- tree declspecs;
- tree d;
-
- /* void (*)() */
- tree PFV = build_pointer_type (build_function_type
- (void_type_node, void_list_node));
-
- /* arg list for the build_function_type call for set_terminate () and
- set_unexpected () */
- tree pfvlist = tree_cons (NULL_TREE, PFV, void_list_node);
-
- /* void (*pfvtype (void (*) ()))() */
- tree pfvtype = build_function_type (PFV, pfvlist);
-
- /* void vtype () */
- tree vtype = build_function_type (void_type_node, void_list_node);
-
- set_terminate_fndecl = auto_function (get_identifier ("set_terminate"),
- pfvtype, NOT_BUILT_IN);
- set_unexpected_fndecl = auto_function (get_identifier ("set_unexpected"),
- pfvtype, NOT_BUILT_IN);
- unexpected_fndecl = auto_function (get_identifier ("unexpected"),
- vtype, NOT_BUILT_IN);
- terminate_fndecl = auto_function (get_identifier ("terminate"),
- vtype, NOT_BUILT_IN);
-
- interim_eh_hook = lang_interim_eh;
-
- push_lang_context (lang_name_c);
-
- catch_match_fndecl =
- define_function (flag_rtti
- ? "__throw_type_match_rtti"
- : "__throw_type_match",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)))),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- find_first_exception_match_fndecl =
- define_function ("__find_first_exception_table_match",
- build_function_type (ptr_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- unwind_fndecl =
- define_function ("__unwind_function",
- build_function_type (void_type_node,
- tree_cons (NULL_TREE, ptr_type_node,
- void_list_node)),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- throw_fndecl =
- define_function ("__throw",
- build_function_type (void_type_node, void_list_node),
- NOT_BUILT_IN,
- pushdecl,
- 0);
- DECL_EXTERNAL (throw_fndecl) = 0;
- TREE_PUBLIC (throw_fndecl) = 0;
-
- Unexpected = default_conversion (unexpected_fndecl);
- Terminate = default_conversion (terminate_fndecl);
- SetTerminate = default_conversion (set_terminate_fndecl);
- SetUnexpected = default_conversion (set_unexpected_fndecl);
- CatchMatch = default_conversion (catch_match_fndecl);
- FirstExceptionMatch = default_conversion (find_first_exception_match_fndecl);
- Unwind = default_conversion (unwind_fndecl);
- Throw = default_conversion (throw_fndecl);
- BuiltinReturnAddress = default_conversion (builtin_return_address_fndecl);
-
- TerminateFunctionCall = build_function_call (Terminate, NULL_TREE);
-
- pop_lang_context ();
-
- new_eh_queue (&ehqueue);
- new_eh_queue (&eh_table_output_queue);
- new_eh_stack (&ehstack);
-
- declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
- d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_pc"));
- d = start_decl (d, declspecs, 0, NULL_TREE);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
- saved_pc = lookup_name (get_identifier ("__eh_pc"), 0);
-
- declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
- d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_type"));
- d = start_decl (d, declspecs, 0, NULL_TREE);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
- saved_throw_type = lookup_name (get_identifier ("__eh_type"), 0);
-
- declspecs = tree_cons (NULL_TREE, get_identifier ("void"), NULL_TREE);
- d = build_parse_node (INDIRECT_REF, get_identifier ("__eh_value"));
- d = start_decl (d, declspecs, 0, NULL_TREE);
- DECL_COMMON (d) = 1;
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
- saved_throw_value = lookup_name (get_identifier ("__eh_value"), 0);
+ return build_component_ref (get_eh_info (), get_identifier ("type"),
+ NULL_TREE, 0);
}
-/* call this to begin a block of unwind protection (ie: when an object is
- constructed) */
-void
-start_protect ()
-{
- if (! doing_eh (0))
- return;
+/* Returns a reference to whether or not the current exception
+ has been caught. */
- emit_label (push_eh_entry (&ehstack));
-}
-
-/* call this to end a block of unwind protection. the finalization tree is
- the finalization which needs to be run in order to cleanly unwind through
- this level of protection. (ie: call this when a scope is exited)*/
-void
-end_protect (finalization)
- tree finalization;
+static tree
+get_eh_caught ()
{
- struct ehEntry *entry;
-
- if (! doing_eh (0))
- return;
-
- entry = pop_eh_entry (&ehstack);
-
- emit_label (entry->end_label);
- /* Put in something that takes up space, as otherwise the end
- address for the EH region could have the exact same address as
- the outer region, causing us to miss the fact that resuming
- exception handling with this PC value would be inside the outer
- region. */
- emit_insn (gen_nop ());
-
- entry->finalization = finalization;
-
- enqueue_eh_entry (&ehqueue, entry);
+ return build_component_ref (get_eh_info (), get_identifier ("caught"),
+ NULL_TREE, 0);
}
-/* call this on start of a try block. */
-void
-expand_start_try_stmts ()
-{
- if (! doing_eh (1))
- return;
-
- start_protect ();
-}
+/* Returns a reference to whether or not the current exception
+ has been caught. */
-void
-expand_end_try_stmts ()
+static tree
+get_eh_handlers ()
{
- end_protect (integer_zero_node);
+ return build_component_ref (get_eh_info (), get_identifier ("handlers"),
+ NULL_TREE, 0);
}
+/* Build a type value for use at runtime for a type that is matched
+ against by the exception handling system. */
-/* call this to start processing of all the catch blocks. */
-void
-expand_start_all_catch ()
+static tree
+build_eh_type_type (type)
+ tree type;
{
- struct ehEntry *entry;
- rtx label;
-
- if (! doing_eh (1))
- return;
-
- emit_line_note (input_filename, lineno);
- label = gen_label_rtx ();
+ char *typestring;
+ tree exp;
- /* The label for the exception handling block we will save. This is
- Lresume, in the documention. */
- emit_label (label);
-
- /* Put in something that takes up space, as otherwise the end
- address for the EH region could have the exact same address as
- the outer region, causing us to miss the fact that resuming
- exception handling with this PC value would be inside the outer
- region. */
- emit_insn (gen_nop ());
+ if (type == error_mark_node)
+ return error_mark_node;
- push_label_entry (&caught_return_label_stack, label);
+ /* peel back references, so they match. */
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
- /* Start a new sequence for all the catch blocks. We will add this
- to the gloabl sequence catch_clauses, when we have completed all
- the handlers in this handler-seq. */
- start_sequence ();
+ /* Peel off cv qualifiers. */
+ type = TYPE_MAIN_VARIANT (type);
- while (1)
+ if (flag_rtti)
{
- entry = dequeue_eh_entry (&ehqueue);
- emit_label (entry->exception_handler_label);
-
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
-
- /* When we get down to the matching entry, stop. */
- if (entry->finalization == integer_zero_node)
- break;
-
- /* The below can be optimized away, and we could just fall into the
- next EH handler, if we are certain they are nested. */
- /* Code to throw out to outer context, if we fall off end of the
- handler. */
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- entry->end_label));
- free (entry);
+ return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
}
-}
-
-/* call this to end processing of all the catch blocks. */
-void
-expand_end_all_catch ()
-{
- rtx new_catch_clause;
-
- if (! doing_eh (1))
- return;
-
- /* Code to throw out to outer context, if we fall off end of catch
- handlers. This is rethrow (Lresume, same id, same obj); in the
- documentation. */
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- top_label_entry (&caught_return_label_stack)));
-
- /* Now we have the complete catch sequence. */
- new_catch_clause = get_insns ();
- end_sequence ();
-
- /* this level of catch blocks is done, so set up the successful catch jump
- label for the next layer of catch blocks. */
- pop_label_entry (&caught_return_label_stack);
- /* Add the new sequence of catchs to the main one for this
- function. */
- push_to_sequence (catch_clauses);
- emit_insns (new_catch_clause);
- catch_clauses = get_insns ();
- end_sequence ();
-
- /* Here we fall through into the continuation code. */
+ typestring = build_overload_name (type, 1, 1);
+ exp = combine_strings (build_string (strlen (typestring)+1, typestring));
+ return build1 (ADDR_EXPR, ptr_type_node, exp);
}
-/* Build a type value for use at runtime for a type that is matched
- against by the exception handling system. */
+/* Build the address of a runtime type for use in the runtime matching
+ field of the new exception model */
+
static tree
-build_eh_type_type (type)
+build_eh_type_type_ref (type)
tree type;
{
char *typestring;
@@ -853,25 +430,37 @@ build_eh_type_type (type)
if (type == error_mark_node)
return error_mark_node;
- /* peel back references, so they match. */
+ /* peel back references, so they match. */
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
- /* Peel off cv qualifiers. */
+ /* Peel off cv qualifiers. */
type = TYPE_MAIN_VARIANT (type);
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
if (flag_rtti)
{
- return build1 (ADDR_EXPR, ptr_type_node, get_typeid (type));
+ exp = get_tinfo_fn (type);
+ TREE_USED (exp) = 1;
+ mark_inline_for_output (exp);
+ exp = build1 (ADDR_EXPR, ptr_type_node, exp);
}
-
- typestring = build_overload_name (type, 1, 1);
- exp = combine_strings (build_string (strlen (typestring)+1, typestring));
- return build1 (ADDR_EXPR, ptr_type_node, exp);
+ else
+ {
+ typestring = build_overload_name (type, 1, 1);
+ exp = combine_strings (build_string (strlen (typestring)+1, typestring));
+ exp = build1 (ADDR_EXPR, ptr_type_node, exp);
+ }
+ pop_obstacks ();
+ return (exp);
}
+
/* Build a type value for use at runtime for a exp that is thrown or
matched against by the exception handling system. */
+
static tree
build_eh_type (exp)
tree exp;
@@ -884,64 +473,200 @@ build_eh_type (exp)
return build_eh_type_type (TREE_TYPE (exp));
}
-/* call this to start a catch block. Typename is the typename, and identifier
+/* This routine is called to mark all the symbols representing runtime
+ type functions in the exception table as haveing been referenced.
+ This will make sure code is emitted for them. Called from finish_file. */
+void
+mark_all_runtime_matches ()
+{
+ int x,num;
+ void **ptr;
+ tree exp;
+
+ num = find_all_handler_type_matches (&ptr);
+ if (num == 0 || ptr == NULL)
+ return;
+
+ for (x=0; x <num; x++)
+ {
+ exp = (tree) ptr[x];
+ if (TREE_CODE (exp) == ADDR_EXPR)
+ {
+ exp = TREE_OPERAND (exp, 0);
+ if (TREE_CODE (exp) == FUNCTION_DECL)
+ TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (exp)) = 1;
+ }
+ }
+
+ free (ptr);
+}
+
+/* Build up a call to __cp_pop_exception, to destroy the exception object
+ for the current catch block. HANDLER is either true or false, telling
+ the library whether or not it is being called from an exception handler;
+ if it is, it avoids destroying the object on rethrow. */
+
+static tree
+do_pop_exception ()
+{
+ tree fn, cleanup;
+ fn = get_identifier ("__cp_pop_exception");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ /* Declare void __cp_pop_exception (void *),
+ as defined in exception.cc. */
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ fn = build_lang_decl
+ (FUNCTION_DECL, fn,
+ build_function_type (void_type_node, tree_cons
+ (NULL_TREE, ptr_type_node, void_list_node)));
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ /* Arrange to do a dynamically scoped cleanup upon exit from this region. */
+ cleanup = lookup_name (get_identifier ("__exception_info"), 0);
+ cleanup = build_function_call (fn, expr_tree_cons
+ (NULL_TREE, cleanup, NULL_TREE));
+ return cleanup;
+}
+
+/* This routine creates the cleanup for the current exception. */
+
+static void
+push_eh_cleanup ()
+{
+ int yes;
+
+ expand_expr (build_unary_op (PREINCREMENT_EXPR, get_eh_handlers (), 1),
+ const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ yes = suspend_momentary ();
+ /* All cleanups must last longer than normal. */
+ expand_decl_cleanup (NULL_TREE, do_pop_exception ());
+ resume_momentary (yes);
+}
+
+/* Build up a call to terminate on the function obstack, for use as an
+ exception handler. */
+
+static tree
+build_terminate_handler ()
+{
+ int yes = suspend_momentary ();
+ tree term = build_function_call (Terminate, NULL_TREE);
+ resume_momentary (yes);
+ return term;
+}
+
+/* Call this to start a catch block. Typename is the typename, and identifier
is the variable to place the object in or NULL if the variable doesn't
matter. If typename is NULL, that means its a "catch (...)" or catch
everything. In that case we don't need to do any type checking.
(ie: it ends up as the "else" clause rather than an "else if" clause) */
+
void
expand_start_catch_block (declspecs, declarator)
tree declspecs, declarator;
{
- rtx false_label_rtx;
- rtx protect_label_rtx;
- tree decl = NULL_TREE;
- tree init;
+ tree decl;
+
+ if (processing_template_decl)
+ {
+ if (declspecs)
+ {
+ decl = grokdeclarator (declarator, declspecs, CATCHPARM,
+ 1, NULL_TREE);
+ pushdecl (decl);
+ decl = build_min_nt (DECL_STMT, copy_to_permanent (declarator),
+ copy_to_permanent (declspecs),
+ NULL_TREE);
+ add_tree (decl);
+ }
+ return;
+ }
if (! doing_eh (1))
return;
- /* Create a binding level for the parm. */
+ if (flag_new_exceptions)
+ process_start_catch_block (declspecs, declarator);
+ else
+ process_start_catch_block_old (declspecs, declarator);
+}
+
+
+/* This function performs the expand_start_catch_block functionality for
+ exceptions implemented in the old style, where catch blocks were all
+ called, and had to check the runtime information themselves. */
+
+static void
+process_start_catch_block_old (declspecs, declarator)
+ tree declspecs, declarator;
+{
+ rtx false_label_rtx;
+ tree decl = NULL_TREE;
+ tree init;
+
+ /* Create a binding level for the eh_info and the exception object
+ cleanup. */
+ pushlevel (0);
expand_start_bindings (0);
false_label_rtx = gen_label_rtx ();
- /* This is saved for the exception table. */
- push_rtl_perm ();
- protect_label_rtx = gen_label_rtx ();
- pop_rtl_from_perm ();
- push_label_entry (&false_label_stack, false_label_rtx);
- push_label_entry (&false_label_stack, protect_label_rtx);
+ push_label_entry (&false_label_stack, false_label_rtx, NULL_TREE);
+
+ emit_line_note (input_filename, lineno);
+
+ push_eh_info ();
if (declspecs)
{
+ decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
+
+ if (decl == NULL_TREE)
+ error ("invalid catch parameter");
+ }
+
+ if (decl)
+ {
tree exp;
rtx call_rtx, return_value_rtx;
tree init_type;
- decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1,
- NULL_TREE, NULL_TREE);
+ /* Make sure we mark the catch param as used, otherwise we'll get
+ a warning about an unused ((anonymous)). */
+ TREE_USED (decl) = 1;
- if (decl == NULL_TREE)
- {
- error ("invalid catch parameter");
- return;
- }
-
- /* Figure out the type that the initializer is. */
+ /* Figure out the type that the initializer is. */
init_type = TREE_TYPE (decl);
if (TREE_CODE (init_type) != REFERENCE_TYPE
&& TREE_CODE (init_type) != POINTER_TYPE)
init_type = build_reference_type (init_type);
- exp = saved_throw_value;
- exp = tree_cons (NULL_TREE,
+ exp = get_eh_value ();
+
+ /* Since pointers are passed by value, initialize a reference to
+ pointer catch parm with the address of the value slot. */
+ if (TREE_CODE (init_type) == REFERENCE_TYPE
+ && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
+ exp = build_unary_op (ADDR_EXPR, exp, 1);
+
+ exp = expr_tree_cons (NULL_TREE,
build_eh_type_type (TREE_TYPE (decl)),
- tree_cons (NULL_TREE,
- saved_throw_type,
- tree_cons (NULL_TREE, exp, NULL_TREE)));
+ expr_tree_cons (NULL_TREE,
+ get_eh_type (),
+ expr_tree_cons (NULL_TREE, exp, NULL_TREE)));
exp = build_function_call (CatchMatch, exp);
call_rtx = expand_call (exp, NULL_RTX, 0);
- assemble_external (TREE_OPERAND (CatchMatch, 0));
return_value_rtx = hard_function_value (ptr_type_node, exp);
@@ -952,543 +677,405 @@ expand_start_catch_block (declspecs, declarator)
/* if it returned FALSE, jump over the catch block, else fall into it */
emit_jump_insn (gen_beq (false_label_rtx));
- init = convert_from_reference (save_expr (make_tree (init_type, call_rtx)));
+ push_eh_cleanup ();
+
+ /* Create a binding level for the parm. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
+ init = convert_from_reference (make_tree (init_type, call_rtx));
+
+ /* If the constructor for the catch parm exits via an exception, we
+ must call terminate. See eh23.C. */
+ if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
+ {
+ /* Generate the copy constructor call directly so we can wrap it.
+ See also expand_default_init. */
+ init = ocp_convert (TREE_TYPE (decl), init,
+ CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
+ init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
+ build_terminate_handler ());
+ }
- /* Do we need the below two lines? */
/* Let `cp_finish_decl' know that this initializer is ok. */
DECL_INITIAL (decl) = init;
decl = pushdecl (decl);
- cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
+
+ start_decl_1 (decl);
+ cp_finish_decl (decl, DECL_INITIAL (decl),
+ NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
}
else
{
- /* Fall into the catch all section. */
+ push_eh_cleanup ();
+
+ /* Create a binding level for the parm. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
+ /* Fall into the catch all section. */
}
- /* This is the starting of something to protect. */
- emit_label (protect_label_rtx);
+ init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
+ expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
emit_line_note (input_filename, lineno);
}
+/* This function performs the expand_start_catch_block functionality for
+ exceptions implemented in the new style. __throw determines whether
+ a handler needs to be called or not, so the handler itself has to do
+ nothing additionaal. */
-/* this is called from expand_exception_blocks and
- expand_end_catch_block to expand the toplevel finalizations for a
- function. We return the first label emitted, if any, otherwise
- return NULL_RTX. */
-static rtx
-expand_leftover_cleanups ()
+static void
+process_start_catch_block (declspecs, declarator)
+ tree declspecs, declarator;
{
- struct ehEntry *entry;
- rtx first_label = NULL_RTX;
+ tree decl = NULL_TREE;
+ tree init;
- while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
+ /* Create a binding level for the eh_info and the exception object
+ cleanup. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
+
+ if (declspecs)
{
- if (! first_label)
- first_label = entry->exception_handler_label;
- emit_label (entry->exception_handler_label);
+ decl = grokdeclarator (declarator, declspecs, CATCHPARM, 1, NULL_TREE);
- expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
+ if (decl == NULL_TREE)
+ error ("invalid catch parameter");
+ }
+
+ if (decl)
+ start_catch_handler (build_eh_type_type_ref (TREE_TYPE (decl)));
+ else
+ start_catch_handler (CATCH_ALL_TYPE);
+
+ emit_line_note (input_filename, lineno);
+
+ push_eh_info ();
+
+ if (decl)
+ {
+ tree exp;
+ tree init_type;
+
+ /* Make sure we mark the catch param as used, otherwise we'll get
+ a warning about an unused ((anonymous)). */
+ TREE_USED (decl) = 1;
+
+ /* Figure out the type that the initializer is. */
+ init_type = TREE_TYPE (decl);
+ if (TREE_CODE (init_type) != REFERENCE_TYPE
+ && TREE_CODE (init_type) != POINTER_TYPE)
+ init_type = build_reference_type (init_type);
+
+ exp = get_eh_value ();
+
+ /* Since pointers are passed by value, initialize a reference to
+ pointer catch parm with the address of the value slot. */
+ if (TREE_CODE (init_type) == REFERENCE_TYPE
+ && TREE_CODE (TREE_TYPE (init_type)) == POINTER_TYPE)
+ exp = build_unary_op (ADDR_EXPR, exp, 1);
- /* The below can be optimized away, and we could just fall into the
- next EH handler, if we are certain they are nested. */
- /* Code to throw out to outer context, if we fall off end of the
- handler. */
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- entry->end_label));
+ exp = ocp_convert (init_type , exp, CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
- /* leftover try block, opps. */
- if (entry->finalization == integer_zero_node)
- abort ();
+ push_eh_cleanup ();
- free (entry);
+ /* Create a binding level for the parm. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
+ init = convert_from_reference (exp);
+
+ /* If the constructor for the catch parm exits via an exception, we
+ must call terminate. See eh23.C. */
+ if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
+ {
+ /* Generate the copy constructor call directly so we can wrap it.
+ See also expand_default_init. */
+ init = ocp_convert (TREE_TYPE (decl), init,
+ CONV_IMPLICIT|CONV_FORCE_TEMP, 0);
+ init = build (TRY_CATCH_EXPR, TREE_TYPE (init), init,
+ build_terminate_handler ());
+ }
+
+ /* Let `cp_finish_decl' know that this initializer is ok. */
+ DECL_INITIAL (decl) = init;
+ decl = pushdecl (decl);
+
+ cp_finish_decl (decl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
+ }
+ else
+ {
+ push_eh_cleanup ();
+
+ /* Create a binding level for the parm. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
+ /* Fall into the catch all section. */
}
- return first_label;
+ init = build_modify_expr (get_eh_caught (), NOP_EXPR, integer_one_node);
+ expand_expr (init, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ emit_line_note (input_filename, lineno);
}
+
+
/* Call this to end a catch block. Its responsible for emitting the
code to handle jumping back to the correct place, and for emitting
the label to jump to if this catch block didn't match. */
-void expand_end_catch_block ()
-{
- rtx start_protect_label_rtx;
- rtx end_protect_label_rtx;
- tree decls;
- struct ehEntry entry;
+void
+expand_end_catch_block ()
+{
if (! doing_eh (1))
return;
- /* fall to outside the try statement when done executing handler and
+ /* Cleanup the EH parameter. */
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ poplevel (kept_level_p (), 1, 0);
+
+ /* Cleanup the EH object. */
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ poplevel (kept_level_p (), 1, 0);
+
+ /* Fall to outside the try statement when done executing handler and
we fall off end of handler. This is jump Lresume in the
documentation. */
- emit_jump (top_label_entry (&caught_return_label_stack));
-
- /* We end the rethrow protection region as soon as we hit a label. */
- end_protect_label_rtx = expand_leftover_cleanups ();
-
- /* Code to throw out to outer context, if we get a throw from within
- our catch handler. */
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry.exception_handler_label = gen_label_rtx ();
- pop_rtl_from_perm ();
- /* This label is Lhandler in the documentation. */
- emit_label (entry.exception_handler_label);
- expand_internal_throw (gen_rtx (LABEL_REF,
- Pmode,
- top_label_entry (&caught_return_label_stack)));
-
- /* No associated finalization. */
- entry.finalization = NULL_TREE;
- entry.context = current_function_decl;
-
- if (end_protect_label_rtx == NULL_RTX)
- end_protect_label_rtx = entry.exception_handler_label;
-
- /* Because we are emitted out of line, we have to protect this. */
- /* label for the start of the protection region. */
- start_protect_label_rtx = pop_label_entry (&false_label_stack);
+ expand_goto (top_label_entry (&caught_return_label_stack));
- /* Cleanup the EH parameter. */
- decls = getdecls ();
- expand_end_bindings (decls, decls != NULL_TREE, 0);
-
- /* label we emit to jump to if this catch block didn't match. */
+ /* label we emit to jump to if this catch block didn't match. */
/* This the closing } in the `if (eq) {' of the documentation. */
- emit_label (pop_label_entry (&false_label_stack));
+ if (! flag_new_exceptions)
+ emit_label (pop_label_entry (&false_label_stack));
+}
+
+/* An exception spec is implemented more or less like:
- /* Because we are reordered out of line, we have to protect this. */
- entry.start_label = start_protect_label_rtx;
- entry.end_label = end_protect_label_rtx;
+ try {
+ function body;
+ } catch (...) {
+ void *p[] = { typeid(raises) };
+ __check_eh_spec (p, count);
+ }
- LABEL_PRESERVE_P (entry.start_label) = 1;
- LABEL_PRESERVE_P (entry.end_label) = 1;
- LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
+ __check_eh_spec in exception.cc handles all the details. */
- /* These set up a call to throw the caught exception into the outer
- context. */
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
+void
+expand_start_eh_spec ()
+{
+ expand_start_try_stmts ();
}
-/* unwind the stack. */
static void
-do_unwind (inner_throw_label)
- rtx inner_throw_label;
+expand_end_eh_spec (raises)
+ tree raises;
{
-#if defined(SPARC_STACK_ALIGN) /* was sparc */
- tree fcall;
- tree params;
- rtx return_val_rtx;
- rtx temp;
-
- /* call to __builtin_return_address () */
- params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
- fcall = build_function_call (BuiltinReturnAddress, params);
- return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
- /* In the return, the new pc is pc+8, as the value coming in is
- really the address of the call insn, not the next insn. */
- temp = gen_reg_rtx (Pmode);
- emit_move_insn (temp, inner_throw_label);
- emit_move_insn (return_val_rtx, plus_constant (temp, -8));
- easy_expand_asm ("ret");
- easy_expand_asm ("restore");
- emit_barrier ();
-#endif
-#if defined(ARM_FRAME_RTX) /* was __arm */
- if (flag_omit_frame_pointer)
- sorry ("this implementation of exception handling requires a frame pointer");
-
- emit_move_insn (stack_pointer_rtx,
- gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -8)));
- emit_move_insn (hard_frame_pointer_rtx,
- gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -12)));
-#endif
-#if defined(TARGET_88000) /* was m88k */
- rtx temp_frame = frame_pointer_rtx;
+ tree tmp, fn, decl, types = NULL_TREE;
+ int count = 0;
- temp_frame = memory_address (Pmode, temp_frame);
- temp_frame = copy_to_reg (gen_rtx (MEM, Pmode, temp_frame));
+ expand_start_all_catch ();
+ expand_start_catch_block (NULL_TREE, NULL_TREE);
- /* hopefully this will successfully pop the frame! */
- emit_move_insn (frame_pointer_rtx, temp_frame);
- emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
- emit_move_insn (arg_pointer_rtx, frame_pointer_rtx);
- emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
- (HOST_WIDE_INT)m88k_debugger_offset (stack_pointer_rtx, 0))));
+ /* Build up an array of type_infos. */
+ for (; raises && TREE_VALUE (raises); raises = TREE_CHAIN (raises))
+ {
+ types = expr_tree_cons
+ (NULL_TREE, build_eh_type_type (TREE_VALUE (raises)), types);
+ ++count;
+ }
-#if 0
- emit_insn (gen_add2_insn (arg_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
- -(HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
+ types = build_nt (CONSTRUCTOR, NULL_TREE, types);
+ TREE_HAS_CONSTRUCTOR (types) = 1;
- emit_move_insn (stack_pointer_rtx, arg_pointer_rtx);
+ /* We can't pass the CONSTRUCTOR directly, so stick it in a variable. */
+ tmp = build_array_type (const_ptr_type_node, NULL_TREE);
+ decl = build_decl (VAR_DECL, NULL_TREE, tmp);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_INITIAL (decl) = types;
+ cp_finish_decl (decl, types, NULL_TREE, 0, 0);
- emit_insn (gen_add2_insn (stack_pointer_rtx, gen_rtx (CONST_INT, VOIDmode,
- (HOST_WIDE_INT)m88k_debugger_offset (arg_pointer_rtx, 0))));
-#endif
-#endif
-#if !defined(TARGET_88000) && !defined(ARM_FRAME_RTX) && !defined(SPARC_STACK_ALIGN)
- tree fcall;
- tree params;
- rtx return_val_rtx;
+ decl = decay_conversion (decl);
- /* call to __builtin_return_address () */
- params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
- fcall = build_function_call (BuiltinReturnAddress, params);
- return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
-#if 0
- /* I would like to do this here, but doesn't seem to work. */
- emit_move_insn (return_val_rtx, inner_throw_label);
- /* So, for now, just pass throw label to stack unwinder. */
-#endif
- params = tree_cons (NULL_TREE, make_tree (ptr_type_node,
- inner_throw_label), NULL_TREE);
+ fn = get_identifier ("__check_eh_spec");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ tmp = tree_cons
+ (NULL_TREE, integer_type_node, tree_cons
+ (NULL_TREE, TREE_TYPE (decl), void_list_node));
+ tmp = build_function_type (void_type_node, tmp);
- do_function_call (Unwind, params, NULL_TREE);
- assemble_external (TREE_OPERAND (Unwind, 0));
- emit_barrier ();
-#endif
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ TREE_THIS_VOLATILE (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ tmp = expr_tree_cons (NULL_TREE, build_int_2 (count, 0), expr_tree_cons
+ (NULL_TREE, decl, NULL_TREE));
+ tmp = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), tmp);
+ expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ expand_end_catch_block ();
+ expand_end_all_catch ();
}
+/* This is called to expand all the toplevel exception handling
+ finalization for a function. It should only be called once per
+ function. */
+
+void
+expand_exception_blocks ()
+{
+ do_pending_stack_adjust ();
+ push_to_sequence (catch_clauses);
+ expand_leftover_cleanups ();
+ do_pending_stack_adjust ();
+ catch_clauses = get_insns ();
+ end_sequence ();
+
+ /* Do this after we expand leftover cleanups, so that the
+ expand_eh_region_end that expand_end_eh_spec does will match the
+ right expand_eh_region_start, and make sure it comes out before
+ the terminate protected region. */
+ if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
+ {
+ expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
+ do_pending_stack_adjust ();
+ push_to_sequence (catch_clauses);
+ expand_leftover_cleanups ();
+ do_pending_stack_adjust ();
+ catch_clauses = get_insns ();
+ end_sequence ();
+ }
-/* is called from expand_exception_blocks () to generate the code in a function
- to "throw" if anything in the function needs to perform a throw.
+ if (catch_clauses)
+ {
+ rtx funcend = gen_label_rtx ();
+ emit_jump (funcend);
- expands "throw" as the following pseudo code:
+ /* We cannot protect n regions this way if we must flow into the
+ EH region through the top of the region, as we have to with
+ the setjmp/longjmp approach. */
+ if (exceptions_via_longjmp == 0)
+ expand_eh_region_start ();
- throw:
- eh = find_first_exception_match (saved_pc);
- if (!eh) goto gotta_rethrow_it;
- goto eh;
+ emit_insns (catch_clauses);
+ catch_clauses = NULL_RTX;
- gotta_rethrow_it:
- saved_pc = __builtin_return_address (0);
- pop_to_previous_level ();
- goto throw;
+ if (exceptions_via_longjmp == 0)
+ expand_eh_region_end (build_terminate_handler ());
- */
-void
-expand_builtin_throw ()
+ expand_leftover_cleanups ();
+
+ emit_label (funcend);
+ }
+}
+
+tree
+start_anon_func ()
{
- tree fcall;
+ static int counter = 0;
+ int old_interface_unknown = interface_unknown;
+ char name[32];
tree params;
- rtx return_val_rtx;
- rtx gotta_rethrow_it;
- rtx gotta_call_terminate;
- rtx unwind_and_throw;
- rtx goto_unwind_and_throw;
- rtx top_of_loop;
- rtx unwind_first;
tree t;
- if (! doing_eh (0))
- return;
+ push_cp_function_context (NULL_TREE);
+ push_to_top_level ();
- if (! throw_used)
- return;
+ /* No need to mangle this. */
+ push_lang_context (lang_name_c);
+
+ interface_unknown = 1;
params = void_list_node;
- t = build_parse_node (CALL_EXPR, get_identifier ("__throw"), params, NULL_TREE);
+ /* tcf stands for throw clean function. */
+ sprintf (name, "__tcf_%d", counter++);
+ t = make_call_declarator (get_identifier (name), params, NULL_TREE,
+ NULL_TREE);
start_function (decl_tree_cons (NULL_TREE, get_identifier ("static"),
void_list_node),
- t, NULL_TREE, NULL_TREE, 0);
+ t, NULL_TREE, 0);
store_parm_decls ();
pushlevel (0);
clear_last_expr ();
push_momentary ();
expand_start_bindings (0);
+ emit_line_note (input_filename, lineno);
- gotta_rethrow_it = gen_label_rtx ();
- gotta_call_terminate = gen_label_rtx ();
- unwind_and_throw = gen_label_rtx ();
- goto_unwind_and_throw = gen_label_rtx ();
- top_of_loop = gen_label_rtx ();
- unwind_first = gen_label_rtx ();
-
- emit_jump (unwind_first);
-
- emit_label (top_of_loop);
-
- /* search for an exception handler for the saved_pc */
- return_val_rtx = do_function_call (FirstExceptionMatch,
- tree_cons (NULL_TREE, saved_pc, NULL_TREE),
- ptr_type_node);
- assemble_external (TREE_OPERAND (FirstExceptionMatch, 0));
-
- /* did we find one? */
- emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
- GET_MODE (return_val_rtx), 0, 0);
-
- /* if not, jump to gotta_rethrow_it */
- emit_jump_insn (gen_beq (gotta_rethrow_it));
-
- /* we found it, so jump to it */
- emit_indirect_jump (return_val_rtx);
-
- /* code to deal with unwinding and looking for it again */
- emit_label (gotta_rethrow_it);
-
- /* call to __builtin_return_address () */
-#if defined(ARM_FRAME_RTX) /* was __arm */
-/* This replaces a 'call' to __builtin_return_address */
- return_val_rtx = gen_reg_rtx (Pmode);
- emit_move_insn (return_val_rtx, gen_rtx (MEM, Pmode, plus_constant (hard_frame_pointer_rtx, -4)));
-#else
- params = tree_cons (NULL_TREE, integer_zero_node, NULL_TREE);
- fcall = build_function_call (BuiltinReturnAddress, params);
- return_val_rtx = expand_expr (fcall, NULL_RTX, Pmode, 0);
-#endif
-
- /* did __builtin_return_address () return a valid address? */
- emit_cmp_insn (return_val_rtx, const0_rtx, EQ, NULL_RTX,
- GET_MODE (return_val_rtx), 0, 0);
-
- emit_jump_insn (gen_beq (gotta_call_terminate));
-
-#if defined(ARM_FRAME_RTX) /* was __arm */
- /* On the ARM, '__builtin_return_address', must have 4
- subtracted from it. */
- emit_insn (gen_add2_insn (return_val_rtx, GEN_INT (-4)));
-
- /* If we are generating code for an ARM2/ARM3 machine or for an ARM6 in 26 bit
- mode, the condition codes must be masked out of the return value, or else
- they will confuse BuiltinReturnAddress. This does not apply to ARM6 and
- later processors when running in 32 bit mode. */
- if (!TARGET_6)
- emit_insn (gen_rtx (SET, Pmode, return_val_rtx, gen_rtx (AND, Pmode, return_val_rtx, GEN_INT (0x03fffffc))));
-#else
-#if !defined(SPARC_STACK_ALIGN) /* was sparc */
- /* On the SPARC, __builtin_return_address is already -8, no need to
- subtract any more from it. */
- return_val_rtx = plus_constant (return_val_rtx, -1);
-#endif
-#endif
+ interface_unknown = old_interface_unknown;
- /* yes it did */
- t = build_modify_expr (saved_pc, NOP_EXPR, make_tree (ptr_type_node, return_val_rtx));
- expand_expr (t, const0_rtx, VOIDmode, 0);
-
- do_unwind (gen_rtx (LABEL_REF, Pmode, top_of_loop));
- emit_jump (top_of_loop);
-
- /* no it didn't --> therefore we need to call terminate */
- emit_label (gotta_call_terminate);
- do_function_call (Terminate, NULL_TREE, NULL_TREE);
- assemble_external (TREE_OPERAND (Terminate, 0));
-
- {
- rtx ret_val, return_val_rtx;
- emit_label (unwind_first);
- ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
- 0, hard_frame_pointer_rtx);
-
- /* Set it up so that we continue inside, at the top of the loop. */
- emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, top_of_loop));
-#ifdef NORMAL_RETURN_ADDR_OFFSET
- return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET);
- if (return_val_rtx != ret_val)
- emit_move_insn (ret_val, return_val_rtx);
-#endif
+ pop_lang_context ();
- /* Fall into epilogue to unwind prologue. */
- }
+ return current_function_decl;
+}
- expand_end_bindings (getdecls(), 1, 0);
+void
+end_anon_func ()
+{
+ expand_end_bindings (getdecls (), 1, 0);
poplevel (1, 0, 0);
pop_momentary ();
finish_function (lineno, 0, 0);
-}
-
-void
-expand_start_eh_spec ()
-{
- start_protect ();
+ pop_from_top_level ();
+ pop_cp_function_context (NULL_TREE);
}
-void
-expand_end_eh_spec (raises)
- tree raises;
-{
- tree expr, second_try;
- rtx check = gen_label_rtx ();
- rtx cont;
- rtx ret = gen_reg_rtx (Pmode);
- rtx flag = gen_reg_rtx (TYPE_MODE (integer_type_node));
- rtx end = gen_label_rtx ();
-
- expr = make_node (RTL_EXPR);
- TREE_TYPE (expr) = void_type_node;
- RTL_EXPR_RTL (expr) = const0_rtx;
- TREE_SIDE_EFFECTS (expr) = 1;
- start_sequence_for_rtl_expr (expr);
- cont = gen_label_rtx ();
- emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
- emit_jump (check);
- emit_label (cont);
- jumpif (make_tree (integer_type_node, flag), end);
- do_function_call (Terminate, NULL_TREE, NULL_TREE);
- assemble_external (TREE_OPERAND (Terminate, 0));
- emit_barrier ();
- RTL_EXPR_SEQUENCE (expr) = get_insns ();
- end_sequence ();
-
- second_try = expr;
-
- expr = make_node (RTL_EXPR);
- TREE_TYPE (expr) = void_type_node;
- RTL_EXPR_RTL (expr) = const0_rtx;
- TREE_SIDE_EFFECTS (expr) = 1;
- start_sequence_for_rtl_expr (expr);
-
- cont = gen_label_rtx ();
- emit_move_insn (ret, gen_rtx (LABEL_REF, Pmode, cont));
- emit_jump (check);
- emit_label (cont);
- jumpif (make_tree (integer_type_node, flag), end);
- start_protect ();
- do_function_call (Unexpected, NULL_TREE, NULL_TREE);
- assemble_external (TREE_OPERAND (Unexpected, 0));
- emit_barrier ();
- end_protect (second_try);
-
- emit_label (check);
- emit_move_insn (flag, const1_rtx);
- cont = gen_label_rtx ();
- while (raises)
- {
- tree exp;
- tree match_type = TREE_VALUE (raises);
-
- if (match_type)
- {
- /* check TREE_VALUE (raises) here */
- exp = saved_throw_value;
- exp = tree_cons (NULL_TREE,
- build_eh_type_type (match_type),
- tree_cons (NULL_TREE,
- saved_throw_type,
- tree_cons (NULL_TREE, exp, NULL_TREE)));
- exp = build_function_call (CatchMatch, exp);
- assemble_external (TREE_OPERAND (CatchMatch, 0));
-
- jumpif (exp, cont);
- }
-
- raises = TREE_CHAIN (raises);
- }
- emit_move_insn (flag, const0_rtx);
- emit_label (cont);
- emit_indirect_jump (ret);
- emit_label (end);
-
- RTL_EXPR_SEQUENCE (expr) = get_insns ();
- end_sequence ();
-
- end_protect (expr);
-}
+/* Return a pointer to a buffer for an exception object of type TYPE. */
-/* This is called to expand all the toplevel exception handling
- finalization for a function. It should only be called once per
- function. */
-void
-expand_exception_blocks ()
+static tree
+alloc_eh_object (type)
+ tree type;
{
- static rtx funcend;
- rtx insns;
-
- start_sequence ();
-
- funcend = gen_label_rtx ();
- emit_jump (funcend);
- /* expand_null_return (); */
-
- start_sequence ();
+ tree fn, exp;
- /* Add all the catch clauses here. */
- emit_insns (catch_clauses);
- catch_clauses = NULL_RTX;
-
- expand_leftover_cleanups ();
-
- insns = get_insns ();
- end_sequence ();
-
- /* Do this after we expand leftover cleanups, so that the end_protect
- that expand_end_eh_spec does will match the right start_protect,
- and make sure it comes out before the terminate protected region. */
- if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)))
- {
- expand_end_eh_spec (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl)));
- push_to_sequence (insns);
-
- /* Now expand any new ones. */
- expand_leftover_cleanups ();
-
- insns = get_insns ();
- end_sequence ();
- }
-
- if (insns)
+ fn = get_identifier ("__eh_alloc");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
{
- struct ehEntry entry;
-
- /* These are saved for the exception table. */
- push_rtl_perm ();
- entry.start_label = gen_label_rtx ();
- entry.end_label = gen_label_rtx ();
- entry.exception_handler_label = gen_label_rtx ();
- entry.finalization = TerminateFunctionCall;
- entry.context = current_function_decl;
- assemble_external (TREE_OPERAND (Terminate, 0));
- pop_rtl_from_perm ();
-
- LABEL_PRESERVE_P (entry.start_label) = 1;
- LABEL_PRESERVE_P (entry.end_label) = 1;
- LABEL_PRESERVE_P (entry.exception_handler_label) = 1;
-
- emit_label (entry.start_label);
- emit_insns (insns);
-
- enqueue_eh_entry (&eh_table_output_queue, copy_eh_entry (&entry));
-
- emit_label (entry.exception_handler_label);
- expand_expr (entry.finalization, const0_rtx, VOIDmode, 0);
- emit_label (entry.end_label);
- emit_barrier ();
+ /* Declare __eh_alloc (size_t), as defined in exception.cc. */
+ tree tmp;
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ tmp = tree_cons (NULL_TREE, sizetype, void_list_node);
+ fn = build_lang_decl (FUNCTION_DECL, fn,
+ build_function_type (ptr_type_node, tmp));
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
}
- {
- /* Mark the end of the stack unwinder. */
- rtx unwind_insns;
- start_sequence ();
- end_eh_unwinder (funcend);
- expand_leftover_cleanups ();
- unwind_insns = get_insns ();
- end_sequence ();
- if (unwind_insns)
- {
- insns = unwind_insns;
- emit_insns (insns);
- }
- }
-
- emit_label (funcend);
-
- /* Only if we had previous insns do we want to emit the jump around
- them. If there weren't any, then insns will remain NULL_RTX. */
- if (insns)
- insns = get_insns ();
- end_sequence ();
-
- emit_insns (insns);
+ exp = build_function_call (fn, expr_tree_cons
+ (NULL_TREE, size_in_bytes (type), NULL_TREE));
+ exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
+ return exp;
}
-
-/* call this to expand a throw statement. This follows the following
+/* Expand a throw statement. This follows the following
algorithm:
1. Allocate space to save the current PC onto the stack.
@@ -1497,30 +1084,40 @@ expand_exception_blocks ()
3. If this is the first call to throw in this function:
generate a label for the throw block
4. jump to the throw block label. */
+
void
expand_throw (exp)
tree exp;
{
- rtx label;
+ tree fn;
+ static tree cleanup_type;
if (! doing_eh (1))
return;
- /* This is the label that represents where in the code we were, when
- we got an exception. This needs to be updated when we rethrow an
- exception, so that the matching routine knows to search out. */
- label = gen_label_rtx ();
- emit_label (label);
-
if (exp)
{
tree throw_type;
- tree e;
+ tree cleanup = NULL_TREE, e;
/* throw expression */
- /* First, decay it. */
+ /* First, decay it. */
exp = decay_conversion (exp);
+ /* cleanup_type is void (*)(void *, int),
+ the internal type of a destructor. */
+ if (cleanup_type == NULL_TREE)
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ cleanup_type = build_pointer_type
+ (build_function_type
+ (void_type_node, tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, integer_type_node, void_list_node))));
+ pop_obstacks ();
+ }
+
if (TREE_CODE (TREE_TYPE (exp)) == POINTER_TYPE)
{
throw_type = build_eh_type (exp);
@@ -1528,163 +1125,167 @@ expand_throw (exp)
}
else
{
- /* Make a copy of the thrown object. WP 15.1.5 */
- exp = build_new (NULL_TREE, TREE_TYPE (exp),
- build_tree_list (NULL_TREE, exp),
- 0);
+ tree object, ptr;
- if (exp == error_mark_node)
- error (" in thrown expression");
+ /* OK, this is kind of wacky. The WP says that we call
+ terminate
- throw_type = build_eh_type (build_indirect_ref (exp, NULL_PTR));
- }
+ when the exception handling mechanism, after completing
+ evaluation of the expression to be thrown but before the
+ exception is caught (_except.throw_), calls a user function
+ that exits via an uncaught exception.
- e = build_modify_expr (saved_throw_type, NOP_EXPR, throw_type);
- expand_expr (e, const0_rtx, VOIDmode, 0);
- e = build_modify_expr (saved_throw_value, NOP_EXPR, exp);
- e = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (e), e);
- expand_expr (e, const0_rtx, VOIDmode, 0);
- }
- else
- {
- /* rethrow current exception */
- /* This part is easy, as we don't have to do anything else. */
- }
+ So we have to protect the actual initialization of the
+ exception object with terminate(), but evaluate the expression
+ first. We also expand the call to __eh_alloc
+ first. Since there could be temps in the expression, we need
+ to handle that, too. */
- expand_internal_throw (gen_rtx (LABEL_REF, Pmode, label));
-}
+ expand_start_target_temps ();
-void
-end_protect_partials () {
- while (protect_list)
- {
- end_protect (TREE_VALUE (protect_list));
- protect_list = TREE_CHAIN (protect_list);
- }
-}
+#if 0
+ /* Unfortunately, this doesn't work. */
+ preexpand_calls (exp);
+#else
+ /* Store the throw expression into a temp. This can be less
+ efficient than storing it into the allocated space directly, but
+ oh well. To do this efficiently we would need to insinuate
+ ourselves into expand_call. */
+ if (TREE_SIDE_EFFECTS (exp))
+ {
+ tree temp = build (VAR_DECL, TREE_TYPE (exp));
+ DECL_ARTIFICIAL (temp) = 1;
+ layout_decl (temp, 0);
+ DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
+ expand_expr (build (INIT_EXPR, TREE_TYPE (exp), temp, exp),
+ NULL_RTX, VOIDmode, 0);
+ expand_decl_cleanup (NULL_TREE, maybe_build_cleanup (temp));
+ exp = temp;
+ }
+#endif
-int
-might_have_exceptions_p ()
-{
- if (eh_table_output_queue.head)
- return 1;
- return 0;
-}
+ /* Allocate the space for the exception. */
+ ptr = save_expr (alloc_eh_object (TREE_TYPE (exp)));
+ expand_expr (ptr, const0_rtx, VOIDmode, 0);
-/* Output the exception table.
- Return the number of handlers. */
-void
-emit_exception_table ()
-{
- int count = 0;
- extern FILE *asm_out_file;
- struct ehEntry *entry;
- tree eh_node_decl;
+ expand_eh_region_start ();
- if (! doing_eh (0))
- return;
+ object = build_indirect_ref (ptr, NULL_PTR);
+ exp = build_modify_expr (object, INIT_EXPR, exp);
- exception_section ();
+ if (exp == error_mark_node)
+ error (" in thrown expression");
- /* Beginning marker for table. */
- assemble_align (GET_MODE_ALIGNMENT (Pmode));
- assemble_label ("__EXCEPTION_TABLE__");
- output_exception_table_entry (asm_out_file,
- const0_rtx, const0_rtx, const0_rtx);
+ expand_expr (exp, const0_rtx, VOIDmode, 0);
+ expand_eh_region_end (build_terminate_handler ());
+ expand_end_target_temps ();
- while (entry = dequeue_eh_entry (&eh_table_output_queue))
- {
- tree context = entry->context;
+ throw_type = build_eh_type (object);
- if (context && ! TREE_ASM_WRITTEN (context))
- continue;
+ if (TYPE_HAS_DESTRUCTOR (TREE_TYPE (object)))
+ {
+ cleanup = lookup_fnfields (TYPE_BINFO (TREE_TYPE (object)),
+ dtor_identifier, 0);
+ cleanup = TREE_VALUE (cleanup);
+ mark_used (cleanup);
+ mark_addressable (cleanup);
+ /* Pretend it's a normal function. */
+ cleanup = build1 (ADDR_EXPR, cleanup_type, cleanup);
+ }
- count++;
- output_exception_table_entry (asm_out_file,
- entry->start_label, entry->end_label,
- entry->exception_handler_label);
- }
+ exp = ptr;
+ }
- /* Ending marker for table. */
- assemble_label ("__EXCEPTION_END__");
- output_exception_table_entry (asm_out_file,
- constm1_rtx, constm1_rtx, constm1_rtx);
-}
+ if (cleanup == NULL_TREE)
+ {
+ cleanup = build_int_2 (0, 0);
+ TREE_TYPE (cleanup) = cleanup_type;
+ }
-void
-register_exception_table ()
-{
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__register_exceptions"), 0,
- VOIDmode, 1,
- gen_rtx (SYMBOL_REF, Pmode, "__EXCEPTION_TABLE__"),
- Pmode);
-}
+ fn = get_identifier ("__cp_push_exception");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ /* Declare __cp_push_exception (void*, void*, void (*)(void*, int)),
+ as defined in exception.cc. */
+ tree tmp;
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, cleanup_type, void_list_node)));
+ fn = build_lang_decl (FUNCTION_DECL, fn,
+ build_function_type (void_type_node, tmp));
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
-/* Build a throw expression. */
-tree
-build_throw (e)
- tree e;
-{
- if (e != error_mark_node)
+ e = expr_tree_cons (NULL_TREE, exp, expr_tree_cons
+ (NULL_TREE, throw_type, expr_tree_cons
+ (NULL_TREE, cleanup, NULL_TREE)));
+ e = build_function_call (fn, e);
+ expand_expr (e, const0_rtx, VOIDmode, 0);
+ }
+ else
{
- e = build1 (THROW_EXPR, void_type_node, e);
- TREE_SIDE_EFFECTS (e) = 1;
- TREE_USED (e) = 1;
+ /* rethrow current exception; note that it's no longer caught. */
+
+ tree fn = get_identifier ("__uncatch_exception");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ /* Declare void __uncatch_exception (void)
+ as defined in exception.cc. */
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ fn = build_lang_decl (FUNCTION_DECL, fn,
+ build_function_type (void_type_node,
+ void_list_node));
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ exp = build_function_call (fn, NULL_TREE);
+ expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
- return e;
-}
-start_eh_unwinder ()
-{
- start_protect ();
+ expand_internal_throw ();
}
-end_eh_unwinder (end)
- rtx end;
+/* Build a throw expression. */
+
+tree
+build_throw (e)
+ tree e;
{
- tree expr;
- rtx return_val_rtx, ret_val, label;
+ if (e == error_mark_node)
+ return e;
- if (! doing_eh (0))
- return;
+ if (processing_template_decl)
+ return build_min (THROW_EXPR, void_type_node, e);
- expr = make_node (RTL_EXPR);
- TREE_TYPE (expr) = void_type_node;
- RTL_EXPR_RTL (expr) = const0_rtx;
- TREE_SIDE_EFFECTS (expr) = 1;
- start_sequence_for_rtl_expr (expr);
-
- ret_val = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
- 0, hard_frame_pointer_rtx);
- return_val_rtx = copy_to_reg (ret_val);
-#ifdef NORMAL_RETURN_ADDR_OFFSET
- return_val_rtx = plus_constant (return_val_rtx, NORMAL_RETURN_ADDR_OFFSET-1);
-#else
- return_val_rtx = plus_constant (return_val_rtx, -1);
-#endif
- emit_move_insn (DECL_RTL (saved_pc), return_val_rtx);
-
-#ifdef JUMP_TO_THROW
- emit_move_insn (ret_val, gen_rtx (SYMBOL_REF, Pmode, "__throw"));
-#else
- label = gen_label_rtx ();
- emit_move_insn (ret_val, gen_rtx (LABEL_REF, Pmode, label));
-#endif
+ if (! flag_ansi && e == null_node)
+ {
+ cp_warning ("throwing NULL");
+ e = integer_zero_node;
+ }
-#ifdef NORMAL_RETURN_ADDR_OFFSET
- return_val_rtx = plus_constant (ret_val, -NORMAL_RETURN_ADDR_OFFSET);
- if (return_val_rtx != ret_val)
- emit_move_insn (ret_val, return_val_rtx);
-#endif
-
- emit_jump (end);
+ e = build1 (THROW_EXPR, void_type_node, e);
+ TREE_SIDE_EFFECTS (e) = 1;
+ TREE_USED (e) = 1;
-#ifndef JUMP_TO_THROW
- emit_label (label);
- do_function_call (Throw, NULL_TREE, NULL_TREE);
-#endif
-
- RTL_EXPR_SEQUENCE (expr) = get_insns ();
- end_sequence ();
- end_protect (expr);
+ return e;
}
diff --git a/contrib/gcc/cp/exception.cc b/contrib/gcc/cp/exception.cc
new file mode 100644
index 0000000..4c10404
--- /dev/null
+++ b/contrib/gcc/cp/exception.cc
@@ -0,0 +1,324 @@
+// Functions for Exception Support for -*- C++ -*-
+// Copyright (C) 1994, 1995, 1996, 1998 Free Software Foundation
+
+// This file is part of GNU CC.
+
+// GNU CC 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, or (at your option)
+// any later version.
+
+// GNU CC 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 GNU CC; see the file COPYING. If not, write to
+// the Free Software Foundation, 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+// As a special exception, if you link this library with other files,
+// some of which are compiled with GCC, to produce an executable,
+// this library does not by itself cause the resulting executable
+// to be covered by the GNU General Public License.
+// This exception does not however invalidate any other reasons why
+// the executable file might be covered by the GNU General Public License.
+
+#pragma implementation "exception"
+
+#include "typeinfo"
+#include "exception"
+#include <stddef.h>
+#include "eh-common.h"
+
+/* Define terminate, unexpected, set_terminate, set_unexpected as
+ well as the default terminate func and default unexpected func. */
+
+extern std::terminate_handler __terminate_func __attribute__((__noreturn__));
+using std::terminate;
+
+void
+std::terminate ()
+{
+ __terminate_func ();
+}
+
+void
+__default_unexpected ()
+{
+ terminate ();
+}
+
+static std::unexpected_handler __unexpected_func __attribute__((__noreturn__))
+ = __default_unexpected;
+
+std::terminate_handler
+std::set_terminate (std::terminate_handler func)
+{
+ std::terminate_handler old = __terminate_func;
+
+ __terminate_func = func;
+ return old;
+}
+
+std::unexpected_handler
+std::set_unexpected (std::unexpected_handler func)
+{
+ std::unexpected_handler old = __unexpected_func;
+
+ __unexpected_func = func;
+ return old;
+}
+
+void
+std::unexpected ()
+{
+ __unexpected_func ();
+}
+
+/* C++-specific state about the current exception.
+ This must match init_exception_processing().
+
+ Note that handlers and caught are not redundant; when rethrown, an
+ exception can have multiple active handlers and still be considered
+ uncaught. */
+
+struct cp_eh_info
+{
+ __eh_info eh_info;
+ void *value;
+ void *type;
+ void (*cleanup)(void *, int);
+ bool caught;
+ cp_eh_info *next;
+ long handlers;
+ void *original_value;
+};
+
+/* Language-specific EH info pointer, defined in libgcc2. */
+
+extern "C" cp_eh_info **__get_eh_info (); // actually void **
+
+/* Is P the type_info node for a pointer of some kind? */
+
+extern bool __is_pointer (void *);
+
+
+/* OLD Compiler hook to return a pointer to the info for the current exception.
+ Used by get_eh_info (). This fudges the actualy returned value to
+ point to the beginning of what USE to be the cp_eh_info structure.
+ THis is so that old code that dereferences this pointer will find
+ things where it expects it to be.*/
+extern "C" void *
+__cp_exception_info (void)
+{
+ return &((*__get_eh_info ())->value);
+}
+
+/* Compiler hook to return a pointer to the info for the current exception.
+ Used by get_eh_info (). */
+
+extern "C" cp_eh_info *
+__cp_eh_info (void)
+{
+ return *__get_eh_info ();
+}
+
+/* Allocate a buffer for a cp_eh_info and an exception object of size SIZE,
+ and return a pointer to the beginning of the object's space. */
+
+extern "C" void * malloc (size_t);
+extern "C" void *
+__eh_alloc (size_t size)
+{
+ void *p = malloc (size);
+ if (p == 0)
+ terminate ();
+ return p;
+}
+
+/* Free the memory for an cp_eh_info and associated exception, given
+ a pointer to the cp_eh_info. */
+
+extern "C" void free (void *);
+extern "C" void
+__eh_free (void *p)
+{
+ free (p);
+}
+
+
+typedef void * (* rtimetype) (void);
+
+extern "C" void *
+__cplus_type_matcher (cp_eh_info *info, rtimetype match_info,
+ exception_descriptor *exception_table)
+{
+ void *ret;
+
+ if (exception_table->lang.language != EH_LANG_C_plus_plus)
+ return NULL;
+
+ if (match_info == CATCH_ALL_TYPE)
+ return info->value;
+
+ /* we don't worry about version info yet, there is only one version! */
+
+ void *match_type = match_info ();
+ ret = __throw_type_match_rtti (match_type, info->type, info->original_value);
+ /* change value of exception */
+ if (ret)
+ info->value = ret;
+ return ret;
+}
+
+
+/* Compiler hook to push a new exception onto the stack.
+ Used by expand_throw(). */
+
+extern "C" void
+__cp_push_exception (void *value, void *type, void (*cleanup)(void *, int))
+{
+ cp_eh_info *p = (cp_eh_info *) __eh_alloc (sizeof (cp_eh_info));
+
+ p->value = value;
+ p->type = type;
+ p->cleanup = cleanup;
+ p->handlers = 0;
+ p->caught = false;
+ p->original_value = value;
+
+ p->eh_info.match_function = __cplus_type_matcher;
+ p->eh_info.language = EH_LANG_C_plus_plus;
+ p->eh_info.version = 1;
+
+ cp_eh_info **q = __get_eh_info ();
+
+ p->next = *q;
+ *q = p;
+}
+
+/* Compiler hook to pop an exception that has been finalized. Used by
+ push_eh_cleanup(). P is the info for the exception caught by the
+ current catch block. */
+
+extern "C" void
+__cp_pop_exception (cp_eh_info *p)
+{
+ cp_eh_info **q = __get_eh_info ();
+
+ --p->handlers;
+
+ /* Don't really pop if there are still active handlers for our exception,
+ or if our exception is being rethrown (i.e. if the active exception is
+ our exception and it is uncaught). */
+ if (p->handlers != 0
+ || (p == *q && !p->caught))
+ return;
+
+ for (; *q; q = &((*q)->next))
+ if (*q == p)
+ break;
+
+ if (! *q)
+ terminate ();
+
+ *q = p->next;
+
+ if (p->cleanup)
+ /* 2 is a magic value for destructors; see build_delete(). */
+ p->cleanup (p->value, 2);
+
+ if (! __is_pointer (p->type))
+ __eh_free (p->value);
+
+ __eh_free (p);
+}
+
+extern "C" void
+__uncatch_exception (void)
+{
+ cp_eh_info *p = __cp_eh_info ();
+ if (p == 0)
+ terminate ();
+ p->caught = false;
+}
+
+/* As per [except.unexpected]:
+ If an exception is thrown, we check it against the spec. If it doesn't
+ match, we call unexpected (). If unexpected () throws, we check that
+ exception against the spec. If it doesn't match, if the spec allows
+ bad_exception we throw that; otherwise we call terminate ().
+
+ The compiler treats an exception spec as a try block with a generic
+ handler that just calls this function with a list of the allowed
+ exception types, so we have an active exception that can be rethrown.
+
+ This function does not return. */
+
+extern "C" void
+__check_eh_spec (int n, const void **spec)
+{
+ cp_eh_info *p = __cp_eh_info ();
+
+ for (int i = 0; i < n; ++i)
+ {
+ if (__throw_type_match_rtti (spec[i], p->type, p->value))
+ throw;
+ }
+
+ try
+ {
+ std::unexpected ();
+ }
+ catch (...)
+ {
+ // __exception_info is an artificial var pushed into each catch block.
+ if (p != __exception_info)
+ {
+ p = __exception_info;
+ for (int i = 0; i < n; ++i)
+ {
+ if (__throw_type_match_rtti (spec[i], p->type, p->value))
+ throw;
+ }
+ }
+
+ const std::type_info &bad_exc = typeid (std::bad_exception);
+ for (int i = 0; i < n; ++i)
+ {
+ if (__throw_type_match_rtti (spec[i], &bad_exc, p->value))
+ throw std::bad_exception ();
+ }
+
+ terminate ();
+ }
+}
+
+extern "C" void
+__throw_bad_cast (void)
+{
+ throw std::bad_cast ();
+}
+
+extern "C" void
+__throw_bad_typeid (void)
+{
+ throw std::bad_typeid ();
+}
+
+/* Has the current exception been caught? */
+
+bool
+std::uncaught_exception ()
+{
+ cp_eh_info *p = __cp_eh_info ();
+ return p && ! p->caught;
+}
+
+const char * std::exception::
+what () const
+{
+ return typeid (*this).name ();
+}
diff --git a/contrib/gcc/cp/expr.c b/contrib/gcc/cp/expr.c
index 99a611e..4c3d8b6 100644
--- a/contrib/gcc/cp/expr.c
+++ b/contrib/gcc/cp/expr.c
@@ -21,18 +21,24 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
#include "expr.h"
#include "cp-tree.h"
+#include "toplev.h"
-#undef NULL
-#define NULL 0
+#if 0
+static tree extract_aggr_init PROTO((tree, tree));
+static tree extract_scalar_init PROTO((tree, tree));
+#endif
+static rtx cplus_expand_expr PROTO((tree, rtx, enum machine_mode,
+ enum expand_modifier));
/* Hook used by expand_expr to expand language-specific tree codes. */
-rtx
+static rtx
cplus_expand_expr (exp, target, tmode, modifier)
tree exp;
rtx target;
@@ -42,11 +48,10 @@ cplus_expand_expr (exp, target, tmode, modifier)
tree type = TREE_TYPE (exp);
register enum machine_mode mode = TYPE_MODE (type);
register enum tree_code code = TREE_CODE (exp);
- rtx original_target = target;
int ignore = target == const0_rtx;
if (ignore)
- target = 0, original_target = 0;
+ target = 0;
/* No sense saving up arithmetic to be done
if it's all in the wrong mode to form part of an address.
@@ -57,7 +62,7 @@ cplus_expand_expr (exp, target, tmode, modifier)
switch (code)
{
- case NEW_EXPR:
+ case AGGR_INIT_EXPR:
{
/* Something needs to be initialized, but we didn't know
where that thing was when building the tree. For example,
@@ -74,8 +79,6 @@ cplus_expand_expr (exp, target, tmode, modifier)
tree func = TREE_OPERAND (exp, 0);
tree args = TREE_OPERAND (exp, 1);
tree type = TREE_TYPE (exp), slot;
- tree fn_type = TREE_TYPE (TREE_TYPE (func));
- tree return_type = TREE_TYPE (fn_type);
tree call_exp;
rtx call_target, return_target;
int pcc_struct_return = 0;
@@ -84,14 +87,8 @@ cplus_expand_expr (exp, target, tmode, modifier)
`target' represents. SLOT holds the slot for TARGET. */
slot = TREE_OPERAND (exp, 2);
- if (target == 0)
- {
- /* Should always be called with a target in BLKmode case. */
- my_friendly_assert (mode != BLKmode, 205);
- my_friendly_assert (DECL_RTL (slot) != 0, 206);
-
- target = gen_reg_rtx (mode);
- }
+ /* Should always be called with a target. */
+ my_friendly_assert (target != NULL_RTX, 205);
/* The target the initializer will initialize (CALL_TARGET)
must now be directed to initialize the target we are
@@ -110,97 +107,58 @@ cplus_expand_expr (exp, target, tmode, modifier)
parameter value. */
mark_addressable (slot);
if (TREE_PERMANENT (args))
- args = tree_cons (0, build1 (ADDR_EXPR, type, slot),
+ args = expr_tree_cons (0, build1 (ADDR_EXPR, type, slot),
TREE_CHAIN (args));
else
TREE_VALUE (args) = build1 (ADDR_EXPR, type, slot);
call_target = 0;
}
- else if (TREE_CODE (return_type) == REFERENCE_TYPE)
- {
- type = return_type;
- call_target = 0;
- }
else
{
-#ifdef PCC_STATIC_STRUCT_RETURN
- pcc_struct_return = 1;
- call_target = 0;
-#else
call_target = target;
+#ifdef PCC_STATIC_STRUCT_RETURN
+ if (aggregate_value_p (type))
+ {
+ pcc_struct_return = 1;
+ call_target = 0;
+ }
#endif
}
- if (call_target)
- {
- /* Make this a valid memory address now. The code below assumes
- that it can compare rtx and make assumptions based on the
- result. The assumptions are true only if the address was
- valid to begin with. */
- call_target = validize_mem (call_target);
- }
- call_exp = build (CALL_EXPR, type, func, args, 0);
+ call_exp = build (CALL_EXPR, type, func, args, NULL_TREE);
TREE_SIDE_EFFECTS (call_exp) = 1;
return_target = expand_call (call_exp, call_target, ignore);
- if (call_target == 0)
- {
- if (pcc_struct_return)
- {
- extern int flag_access_control;
- int old_ac = flag_access_control;
-
- tree init = build_decl (VAR_DECL, 0, type);
- TREE_ADDRESSABLE (init) = 1;
- DECL_RTL (init) = return_target;
-
- flag_access_control = 0;
- expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING);
- flag_access_control = old_ac;
-
- if (TYPE_NEEDS_DESTRUCTOR (type))
- {
- init = build_decl (VAR_DECL, 0,
- build_reference_type (type));
- DECL_RTL (init) = XEXP (return_target, 0);
-
- init = maybe_build_cleanup (convert_from_reference (init));
- if (init != NULL_TREE)
- expand_expr (init, 0, 0, 0);
- }
- call_target = return_target = DECL_RTL (slot);
- }
- else
- call_target = return_target;
- }
-
- if (call_target != return_target)
- {
- my_friendly_assert (TYPE_HAS_TRIVIAL_INIT_REF (type), 317);
- if (GET_MODE (return_target) == BLKmode)
- emit_block_move (call_target, return_target, expr_size (exp),
- TYPE_ALIGN (type) / BITS_PER_UNIT);
- else
- emit_move_insn (call_target, return_target);
- }
- if (TREE_CODE (return_type) == REFERENCE_TYPE)
+ if (call_target)
+ /* Trust that the right thing has been done; it's too hard to
+ verify. */
+ return return_target;
+
+ /* If we're suffering under the ancient PCC_STATIC_STRUCT_RETURN
+ calling convention, we need to copy the return value out of
+ the static return buffer into slot. */
+ if (pcc_struct_return)
{
- tree init;
-
- if (GET_CODE (call_target) == REG
- && REGNO (call_target) < FIRST_PSEUDO_REGISTER)
- my_friendly_abort (39);
+ extern int flag_access_control;
+ int old_ac = flag_access_control;
- type = TREE_TYPE (exp);
+ tree init = build_decl (VAR_DECL, NULL_TREE,
+ build_reference_type (type));
+ DECL_RTL (init) = XEXP (return_target, 0);
+ init = convert_from_reference (init);
- init = build (RTL_EXPR, return_type, 0, call_target);
- /* We got back a reference to the type we want. Now initialize
- target with that. */
+ flag_access_control = 0;
expand_aggr_init (slot, init, 0, LOOKUP_ONLYCONVERTING);
+ flag_access_control = old_ac;
+
+ if (TYPE_NEEDS_DESTRUCTOR (type))
+ {
+ init = maybe_build_cleanup (init);
+ if (init != NULL_TREE)
+ expand_expr (init, const0_rtx, VOIDmode, 0);
+ }
}
- if (DECL_RTL (slot) != target)
- emit_move_insn (DECL_RTL (slot), target);
return DECL_RTL (slot);
}
@@ -226,13 +184,16 @@ cplus_expand_expr (exp, target, tmode, modifier)
expand_throw (TREE_OPERAND (exp, 0));
return NULL;
- case UNSAVE_EXPR:
- {
- rtx temp;
- temp = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
- TREE_OPERAND (exp, 0) = unsave_expr_now (TREE_OPERAND (exp, 0));
- return temp;
- }
+ case VEC_INIT_EXPR:
+ return expand_expr
+ (expand_vec_init
+ (NULL_TREE, TREE_OPERAND (exp, 0),
+ build_binary_op (MINUS_EXPR, TREE_OPERAND (exp, 2),
+ integer_one_node, 1),
+ TREE_OPERAND (exp, 1), 0), target, tmode, modifier);
+
+ case NEW_EXPR:
+ return expand_expr (build_new_1 (exp), target, tmode, modifier);
default:
break;
@@ -278,19 +239,7 @@ fixup_result_decl (decl, result)
}
}
-/* Return nonzero iff DECL is memory-based. The DECL_RTL of
- certain const variables might be a CONST_INT, or a REG
- in some cases. We cannot use `memory_operand' as a test
- here because on most RISC machines, a variable's address
- is not, by itself, a legitimate address. */
-
-int
-decl_in_memory_p (decl)
- tree decl;
-{
- return DECL_RTL (decl) != 0 && GET_CODE (DECL_RTL (decl)) == MEM;
-}
-
+#if 0
/* Expand this initialization inline and see if it's simple enough that
it can be done at compile-time. */
@@ -333,8 +282,8 @@ extract_scalar_init (decl, init)
to = XEXP (r, 0);
- if (! (to == value ||
- (GET_CODE (to) == SUBREG && XEXP (to, 0) == value)))
+ if (! (to == value
+ || (GET_CODE (to) == SUBREG && XEXP (to, 0) == value)))
return 0;
r = XEXP (r, 1);
@@ -351,6 +300,7 @@ extract_scalar_init (decl, init)
return t;
}
+#endif
int
extract_init (decl, init)
@@ -358,6 +308,7 @@ extract_init (decl, init)
{
return 0;
+#if 0
if (IS_AGGR_TYPE (TREE_TYPE (decl))
|| TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
init = extract_aggr_init (decl, init);
@@ -369,4 +320,93 @@ extract_init (decl, init)
DECL_INITIAL (decl) = init;
return 1;
+#endif
+}
+
+void
+do_case (start, end)
+ tree start, end;
+{
+ tree value1 = NULL_TREE, value2 = NULL_TREE, label;
+
+ if (start != NULL_TREE && TREE_TYPE (start) != NULL_TREE
+ && POINTER_TYPE_P (TREE_TYPE (start)))
+ error ("pointers are not permitted as case values");
+
+ if (end && pedantic)
+ pedwarn ("ANSI C++ forbids range expressions in switch statement");
+
+ if (processing_template_decl)
+ {
+ add_tree (build_min_nt (CASE_LABEL, start, end));
+ return;
+ }
+
+ if (start)
+ value1 = check_cp_case_value (start);
+ if (end)
+ value2 = check_cp_case_value (end);
+
+ label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ if (value1 != error_mark_node
+ && value2 != error_mark_node)
+ {
+ tree duplicate;
+ int success;
+
+ if (end)
+ success = pushcase_range (value1, value2, convert_and_check,
+ label, &duplicate);
+ else if (start)
+ success = pushcase (value1, convert_and_check, label, &duplicate);
+ else
+ success = pushcase (NULL_TREE, 0, label, &duplicate);
+
+ if (success == 1)
+ {
+ if (end)
+ error ("case label not within a switch statement");
+ else if (start)
+ cp_error ("case label `%E' not within a switch statement", start);
+ else
+ error ("default label not within a switch statement");
+ }
+ else if (success == 2)
+ {
+ if (end)
+ {
+ error ("duplicate (or overlapping) case value");
+ cp_error_at ("this is the first entry overlapping that value",
+ duplicate);
+ }
+ else if (start)
+ {
+ cp_error ("duplicate case value `%E'", start);
+ cp_error_at ("previously used here", duplicate);
+ }
+ else
+ {
+ error ("multiple default labels in one switch");
+ cp_error_at ("this is the first default label", duplicate);
+ }
+ }
+ else if (success == 3)
+ warning ("case value out of range");
+ else if (success == 4)
+ warning ("empty range specified");
+ else if (success == 5)
+ {
+ if (end)
+ error ("case label within scope of cleanup or variable array");
+ else if (! start)
+ error ("`default' label within scope of cleanup or variable array");
+ else
+ cp_error ("case label `%E' within scope of cleanup or variable array", start);
+ }
+ }
+ if (start)
+ define_case_label (label);
+ else
+ define_case_label (NULL_TREE);
}
diff --git a/contrib/gcc/cp/friend.c b/contrib/gcc/cp/friend.c
new file mode 100644
index 0000000..58747ef
--- /dev/null
+++ b/contrib/gcc/cp/friend.c
@@ -0,0 +1,484 @@
+/* Help friends in C++.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "rtl.h"
+#include "cp-tree.h"
+#include "flags.h"
+#include "output.h"
+#include "toplev.h"
+
+static void add_friend PROTO((tree, tree));
+static void add_friends PROTO((tree, tree, tree));
+
+/* Friend data structures are described in cp-tree.h. */
+
+int
+is_friend (type, supplicant)
+ tree type, supplicant;
+{
+ int declp;
+ register tree list;
+ tree context;
+
+ if (supplicant == NULL_TREE || type == NULL_TREE)
+ return 0;
+
+ declp = (TREE_CODE_CLASS (TREE_CODE (supplicant)) == 'd');
+
+ if (declp)
+ /* It's a function decl. */
+ {
+ tree list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type));
+ tree name = DECL_NAME (supplicant);
+ tree ctype;
+
+ if (DECL_FUNCTION_MEMBER_P (supplicant))
+ ctype = DECL_CLASS_CONTEXT (supplicant);
+ else
+ ctype = NULL_TREE;
+
+ for (; list ; list = TREE_CHAIN (list))
+ {
+ if (name == TREE_PURPOSE (list))
+ {
+ tree friends = TREE_VALUE (list);
+ for (; friends ; friends = TREE_CHAIN (friends))
+ {
+ if (comptypes (ctype, TREE_PURPOSE (friends), 1))
+ return 1;
+
+ if (TREE_VALUE (friends) == NULL_TREE)
+ continue;
+
+ if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL)
+ {
+ if (is_specialization_of (supplicant,
+ TREE_VALUE (friends)))
+ return 1;
+
+ continue;
+ }
+
+ /* FIXME: The use of comptypes here is bogus, since
+ two specializations of a template with non-type
+ parameters may have the same type, but be
+ different. */
+ if (comptypes (TREE_TYPE (supplicant),
+ TREE_TYPE (TREE_VALUE (friends)), 1))
+ return 1;
+ }
+ break;
+ }
+ }
+ }
+ else
+ /* It's a type. */
+ {
+ if (type == supplicant)
+ return 1;
+
+ list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type)));
+ for (; list ; list = TREE_CHAIN (list))
+ {
+ tree t = TREE_VALUE (list);
+
+ if (TREE_CODE (t) == TEMPLATE_DECL ?
+ is_specialization_of (TYPE_MAIN_DECL (supplicant), t) :
+ comptypes (supplicant, t, 1))
+ return 1;
+ }
+ }
+
+ if (declp && DECL_FUNCTION_MEMBER_P (supplicant))
+ context = DECL_CLASS_CONTEXT (supplicant);
+ else if (! declp)
+ /* Local classes have the same access as the enclosing function. */
+ context = hack_decl_function_context (TYPE_MAIN_DECL (supplicant));
+ else
+ context = NULL_TREE;
+
+ /* A namespace is not friend to anybody. */
+ if (context && TREE_CODE (context) == NAMESPACE_DECL)
+ context = NULL_TREE;
+
+ if (context)
+ return is_friend (type, context);
+
+ return 0;
+}
+
+/* Add a new friend to the friends of the aggregate type TYPE.
+ DECL is the FUNCTION_DECL of the friend being added. */
+
+static void
+add_friend (type, decl)
+ tree type, decl;
+{
+ tree typedecl = TYPE_MAIN_DECL (type);
+ tree list = DECL_FRIENDLIST (typedecl);
+ tree name = DECL_NAME (decl);
+
+ while (list)
+ {
+ if (name == TREE_PURPOSE (list))
+ {
+ tree friends = TREE_VALUE (list);
+ for (; friends ; friends = TREE_CHAIN (friends))
+ {
+ if (decl == TREE_VALUE (friends))
+ {
+ cp_warning ("`%D' is already a friend of class `%T'",
+ decl, type);
+ cp_warning_at ("previous friend declaration of `%D'",
+ TREE_VALUE (friends));
+ return;
+ }
+ }
+ TREE_VALUE (list) = tree_cons (error_mark_node, decl,
+ TREE_VALUE (list));
+ return;
+ }
+ list = TREE_CHAIN (list);
+ }
+ DECL_FRIENDLIST (typedecl)
+ = tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
+ DECL_FRIENDLIST (typedecl));
+ if (DECL_NAME (decl) == ansi_opname[(int) MODIFY_EXPR])
+ {
+ tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
+ if (parmtypes && TREE_CHAIN (parmtypes))
+ {
+ tree parmtype = TREE_VALUE (TREE_CHAIN (parmtypes));
+ if (TREE_CODE (parmtype) == REFERENCE_TYPE
+ && TREE_TYPE (parmtypes) == TREE_TYPE (typedecl))
+ TYPE_HAS_ASSIGN_REF (TREE_TYPE (typedecl)) = 1;
+ }
+ }
+}
+
+/* Declare that every member function NAME in FRIEND_TYPE
+ (which may be NULL_TREE) is a friend of type TYPE. */
+
+static void
+add_friends (type, name, friend_type)
+ tree type, name, friend_type;
+{
+ tree typedecl = TYPE_MAIN_DECL (type);
+ tree list = DECL_FRIENDLIST (typedecl);
+
+ while (list)
+ {
+ if (name == TREE_PURPOSE (list))
+ {
+ tree friends = TREE_VALUE (list);
+ while (friends && TREE_PURPOSE (friends) != friend_type)
+ friends = TREE_CHAIN (friends);
+ if (friends)
+ {
+ if (friend_type)
+ warning ("method `%s::%s' is already a friend of class",
+ TYPE_NAME_STRING (friend_type),
+ IDENTIFIER_POINTER (name));
+ else
+ warning ("function `%s' is already a friend of class `%s'",
+ IDENTIFIER_POINTER (name),
+ IDENTIFIER_POINTER (DECL_NAME (typedecl)));
+ }
+ else
+ TREE_VALUE (list) = tree_cons (friend_type, NULL_TREE,
+ TREE_VALUE (list));
+ return;
+ }
+ list = TREE_CHAIN (list);
+ }
+ DECL_FRIENDLIST (typedecl)
+ = tree_cons (name,
+ build_tree_list (friend_type, NULL_TREE),
+ DECL_FRIENDLIST (typedecl));
+ if (! strncmp (IDENTIFIER_POINTER (name),
+ IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]),
+ strlen (IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]))))
+ {
+ TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
+ sorry ("declaring \"friend operator =\" will not find \"operator = (X&)\" if it exists");
+ }
+}
+
+/* Make FRIEND_TYPE a friend class to TYPE. If FRIEND_TYPE has already
+ been defined, we make all of its member functions friends of
+ TYPE. If not, we make it a pending friend, which can later be added
+ when its definition is seen. If a type is defined, then its TYPE_DECL's
+ DECL_UNDEFINED_FRIENDS contains a (possibly empty) list of friend
+ classes that are not defined. If a type has not yet been defined,
+ then the DECL_WAITING_FRIENDS contains a list of types
+ waiting to make it their friend. Note that these two can both
+ be in use at the same time! */
+
+void
+make_friend_class (type, friend_type)
+ tree type, friend_type;
+{
+ tree classes;
+ int is_template_friend;
+
+ if (IS_SIGNATURE (type))
+ {
+ error ("`friend' declaration in signature definition");
+ return;
+ }
+ if (IS_SIGNATURE (friend_type))
+ {
+ error ("signature type `%s' declared `friend'",
+ IDENTIFIER_POINTER (TYPE_IDENTIFIER (friend_type)));
+ return;
+ }
+ if (processing_template_decl > template_class_depth (type))
+ /* If the TYPE is a template then it makes sense for it to be
+ friends with itself; this means that each instantiation is
+ friends with all other instantiations. */
+ is_template_friend = 1;
+ else if (comptypes (type, friend_type, 1))
+ {
+ pedwarn ("class `%s' is implicitly friends with itself",
+ TYPE_NAME_STRING (type));
+ return;
+ }
+ else
+ is_template_friend = 0;
+
+ GNU_xref_hier (type, friend_type, 0, 0, 1);
+
+ if (is_template_friend)
+ friend_type = CLASSTYPE_TI_TEMPLATE (friend_type);
+
+ classes = CLASSTYPE_FRIEND_CLASSES (type);
+ while (classes
+ /* Stop if we find the same type on the list. */
+ && !(TREE_CODE (TREE_VALUE (classes)) == TEMPLATE_DECL ?
+ friend_type == TREE_VALUE (classes) :
+ comptypes (TREE_VALUE (classes), friend_type, 1)))
+ classes = TREE_CHAIN (classes);
+ if (classes)
+ cp_warning ("`%T' is already a friend of `%T'",
+ TREE_VALUE (classes), type);
+ else
+ {
+ CLASSTYPE_FRIEND_CLASSES (type)
+ = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
+ }
+}
+
+/* Main friend processor. This is large, and for modularity purposes,
+ has been removed from grokdeclarator. It returns `void_type_node'
+ to indicate that something happened, though a FIELD_DECL is
+ not returned.
+
+ CTYPE is the class this friend belongs to.
+
+ DECLARATOR is the name of the friend.
+
+ DECL is the FUNCTION_DECL that the friend is.
+
+ In case we are parsing a friend which is part of an inline
+ definition, we will need to store PARM_DECL chain that comes
+ with it into the DECL_ARGUMENTS slot of the FUNCTION_DECL.
+
+ FLAGS is just used for `grokclassfn'.
+
+ QUALS say what special qualifies should apply to the object
+ pointed to by `this'. */
+
+tree
+do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
+ tree ctype, declarator, decl, parmdecls;
+ enum overload_flags flags;
+ tree quals;
+ int funcdef_flag;
+{
+ int is_friend_template = 0;
+
+ /* Every decl that gets here is a friend of something. */
+ DECL_FRIEND_P (decl) = 1;
+
+ if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
+ {
+ declarator = TREE_OPERAND (declarator, 0);
+ if (TREE_CODE (declarator) == LOOKUP_EXPR)
+ declarator = TREE_OPERAND (declarator, 0);
+ if (is_overloaded_fn (declarator))
+ declarator = DECL_NAME (get_first_fn (declarator));
+ }
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ is_friend_template = processing_template_decl >
+ template_class_depth (current_class_type);
+
+ if (ctype)
+ {
+ tree cname = TYPE_NAME (ctype);
+ if (TREE_CODE (cname) == TYPE_DECL)
+ cname = DECL_NAME (cname);
+
+ /* A method friend. */
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ if (flags == NO_SPECIAL && ctype && declarator == cname)
+ DECL_CONSTRUCTOR_P (decl) = 1;
+
+ /* This will set up DECL_ARGUMENTS for us. */
+ grokclassfn (ctype, cname, decl, flags, quals);
+
+ if (is_friend_template)
+ decl = DECL_TI_TEMPLATE (push_template_decl (decl));
+
+ if (TYPE_SIZE (ctype) != 0 && template_class_depth (ctype) == 0)
+ decl = check_classfn (ctype, decl);
+
+ /* TYPE_BEING_DEFINED is a hack for nested classes having
+ member functions of the enclosing class as friends. Will
+ go away as parsing of classes gets rewritten. */
+ if (TREE_TYPE (decl) != error_mark_node)
+ {
+ if (TYPE_BEING_DEFINED (ctype) ||
+ TYPE_SIZE (ctype) || template_class_depth (ctype) > 0)
+ add_friend (current_class_type, decl);
+ else
+ cp_error ("member `%D' declared as friend before type `%T' defined",
+ decl, ctype);
+ }
+ }
+ else
+ {
+ /* Possibly a bunch of method friends. */
+
+ /* Get the class they belong to. */
+ tree ctype = IDENTIFIER_TYPE_VALUE (cname);
+ tree fields = lookup_fnfields (TYPE_BINFO (ctype), declarator, 0);
+
+ if (fields)
+ add_friends (current_class_type, declarator, ctype);
+ else
+ cp_error ("method `%D' is not a member of class `%T'",
+ declarator, ctype);
+ decl = void_type_node;
+ }
+ }
+ else if (TREE_CODE (decl) == FUNCTION_DECL
+ && (MAIN_NAME_P (declarator)
+ || (IDENTIFIER_LENGTH (declarator) > 10
+ && IDENTIFIER_POINTER (declarator)[0] == '_'
+ && IDENTIFIER_POINTER (declarator)[1] == '_'
+ && strncmp (IDENTIFIER_POINTER (declarator)+2,
+ "builtin_", 8) == 0)))
+ {
+ /* raw "main", and builtin functions never gets overloaded,
+ but they can become friends. */
+ add_friend (current_class_type, decl);
+ DECL_FRIEND_P (decl) = 1;
+ decl = void_type_node;
+ }
+ /* A global friend.
+ @@ or possibly a friend from a base class ?!? */
+ else if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ /* Friends must all go through the overload machinery,
+ even though they may not technically be overloaded.
+
+ Note that because classes all wind up being top-level
+ in their scope, their friend wind up in top-level scope as well. */
+ DECL_ASSEMBLER_NAME (decl)
+ = build_decl_overload (declarator, TYPE_ARG_TYPES (TREE_TYPE (decl)),
+ TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
+ DECL_ARGUMENTS (decl) = parmdecls;
+ if (funcdef_flag)
+ DECL_CLASS_CONTEXT (decl) = current_class_type;
+
+ if (! DECL_USE_TEMPLATE (decl))
+ {
+ /* We can call pushdecl here, because the TREE_CHAIN of this
+ FUNCTION_DECL is not needed for other purposes. Don't do this
+ for a template instantiation. */
+ if (!is_friend_template)
+ {
+ /* However, we don't call pushdecl() for a friend
+ function of a template class, since in general,
+ such a declaration depends on template
+ parameters. Instead, we call pushdecl when the
+ class is instantiated. */
+ if (template_class_depth (current_class_type) == 0)
+ decl = pushdecl (decl);
+ }
+ else
+ decl = push_template_decl (decl);
+
+ if (! funcdef_flag && ! flag_guiding_decls && ! is_friend_template
+ && current_template_parms && uses_template_parms (decl))
+ {
+ static int explained;
+ cp_warning ("friend declaration `%#D'", decl);
+ warning (" declares a non-template function");
+ if (! explained)
+ {
+ warning (" (if this is not what you intended, make sure");
+ warning (" the function template has already been declared,");
+ warning (" and add <> after the function name here)");
+ explained = 1;
+ }
+ }
+ }
+
+ make_decl_rtl (decl, NULL_PTR, 1);
+ add_friend (current_class_type,
+ is_friend_template ? DECL_TI_TEMPLATE (decl) : decl);
+ DECL_FRIEND_P (decl) = 1;
+ }
+ else
+ {
+ /* @@ Should be able to ingest later definitions of this function
+ before use. */
+ tree decl = lookup_name_nonclass (declarator);
+ if (decl == NULL_TREE)
+ {
+ cp_warning ("implicitly declaring `%T' as struct", declarator);
+ decl = xref_tag (record_type_node, declarator, NULL_TREE, 1);
+ decl = TYPE_MAIN_DECL (decl);
+ }
+
+ /* Allow abbreviated declarations of overloaded functions,
+ but not if those functions are really class names. */
+ if (TREE_CODE (decl) == TREE_LIST && TREE_TYPE (TREE_PURPOSE (decl)))
+ {
+ cp_warning ("`friend %T' archaic, use `friend class %T' instead",
+ declarator, declarator);
+ decl = TREE_TYPE (TREE_PURPOSE (decl));
+ }
+
+ if (TREE_CODE (decl) == TREE_LIST)
+ add_friends (current_class_type, TREE_PURPOSE (decl), NULL_TREE);
+ else
+ make_friend_class (current_class_type, TREE_TYPE (decl));
+ decl = void_type_node;
+ }
+ return decl;
+}
diff --git a/contrib/gcc/cp/g++.1 b/contrib/gcc/cp/g++.1
index ae016fa..5101d5f 100644
--- a/contrib/gcc/cp/g++.1
+++ b/contrib/gcc/cp/g++.1
@@ -430,38 +430,6 @@ differently depending on whether `\|\c
testing both of these predefined macros you can distinguish four
situations: GNU C, traditional GNU C, other ANSI C compilers, and
other old C compilers.
-.TP
-\ \ \ \(bu
-In the preprocessor, comments convert to nothing at all, rather than
-to a space. This allows traditional token concatenation.
-.TP
-\ \ \ \(bu
-In the preprocessor, macro arguments are recognized within string
-constants in a macro definition (and their values are stringified,
-though without additional quote marks, when they appear in such a
-context). The preprocessor always considers a string constant to end
-at a newline.
-.TP
-\ \ \ \(bu
-The preprocessor does not predefine the macro \c
-.B __STDC__\c
-\& when you use
-`\|\c
-.B \-traditional\c
-\&\|', but still predefines\c
-.B __GNUC__\c
-\& (since the GNU extensions indicated by
-.B __GNUC__\c
-\& are not affected by
-`\|\c
-.B \-traditional\c
-\&\|'). If you need to write header files that work
-differently depending on whether `\|\c
-.B \-traditional\c
-\&\|' is in use, by
-testing both of these predefined macros you can distinguish four
-situations: GNU C, traditional GNU C, other ANSI C compilers, and
-other old C compilers.
.PP
.TP
\ \ \ \(bu
diff --git a/contrib/gcc/cp/g++spec.c b/contrib/gcc/cp/g++spec.c
new file mode 100644
index 0000000..542ca06
--- /dev/null
+++ b/contrib/gcc/cp/g++spec.c
@@ -0,0 +1,269 @@
+/* Specific flags and argument handling of the C++ front-end.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+
+#include "system.h"
+
+#include "gansidecl.h"
+
+/* This bit is set if we saw a `-xfoo' language specification. */
+#define LANGSPEC (1<<1)
+/* This bit is set if they did `-lm' or `-lmath'. */
+#define MATHLIB (1<<2)
+/* This bit is set if they did `-lc'. */
+#define WITHLIBC (1<<3)
+
+#ifndef MATH_LIBRARY
+#define MATH_LIBRARY "-lm"
+#endif
+#ifndef NEED_MATH_LIBRARY
+#define NEED_MATH_LIBRARY 1 /* Default is pass MATH_LIBRARY to linker */
+#endif
+
+extern char *xmalloc PROTO((size_t));
+
+void
+lang_specific_driver (fn, in_argc, in_argv, in_added_libraries)
+ void (*fn)();
+ int *in_argc;
+ char ***in_argv;
+ int *in_added_libraries;
+{
+ int i, j;
+
+ /* If non-zero, the user gave us the `-v' flag. */
+ int saw_verbose_flag = 0;
+
+ /* This will be 0 if we encounter a situation where we should not
+ link in libstdc++. */
+ int library = 1;
+
+ /* The number of arguments being added to what's in argv, other than
+ libraries. We use this to track the number of times we've inserted
+ -xc++/-xnone. */
+ int added = 2;
+
+ /* Used to track options that take arguments, so we don't go wrapping
+ those with -xc++/-xnone. */
+ char *quote = NULL;
+
+ /* The new argument list will be contained in this. */
+ char **arglist;
+
+ /* Non-zero if we saw a `-xfoo' language specification on the
+ command line. Used to avoid adding our own -xc++ if the user
+ already gave a language for the file. */
+ int saw_speclang = 0;
+
+ /* "-lm" or "-lmath" if it appears on the command line. */
+ char *saw_math = 0;
+
+ /* "-lc" if it appears on the command line. */
+ char *saw_libc = 0;
+
+ /* An array used to flag each argument that needs a bit set for
+ LANGSPEC, MATHLIB, or WITHLIBC. */
+ int *args;
+
+ /* By default, we throw on the math library. */
+ int need_math = NEED_MATH_LIBRARY;
+
+ /* The total number of arguments with the new stuff. */
+ int argc;
+
+ /* The argument list. */
+ char **argv;
+
+ /* The number of libraries added in. */
+ int added_libraries;
+
+ /* The total number of arguments with the new stuff. */
+ int num_args = 1;
+
+ argc = *in_argc;
+ argv = *in_argv;
+ added_libraries = *in_added_libraries;
+
+ args = (int *) xmalloc (argc * sizeof (int));
+ bzero ((char *) args, argc * sizeof (int));
+
+ for (i = 1; i < argc; i++)
+ {
+ /* If the previous option took an argument, we swallow it here. */
+ if (quote)
+ {
+ quote = NULL;
+ continue;
+ }
+
+ /* We don't do this anymore, since we don't get them with minus
+ signs on them. */
+ if (argv[i][0] == '\0' || argv[i][1] == '\0')
+ continue;
+
+ if (argv[i][0] == '-')
+ {
+ if (library != 0 && (strcmp (argv[i], "-nostdlib") == 0
+ || strcmp (argv[i], "-nodefaultlibs") == 0))
+ {
+ library = 0;
+ }
+ else if (strcmp (argv[i], "-lm") == 0
+ || strcmp (argv[i], "-lmath") == 0
+#ifdef ALT_LIBM
+ || strcmp (argv[i], ALT_LIBM) == 0
+#endif
+ )
+ {
+ args[i] |= MATHLIB;
+ need_math = 0;
+ }
+ else if (strcmp (argv[i], "-lc") == 0)
+ args[i] |= WITHLIBC;
+ else if (strcmp (argv[i], "-v") == 0)
+ {
+ saw_verbose_flag = 1;
+ if (argc == 2)
+ {
+ /* If they only gave us `-v', don't try to link
+ in libg++. */
+ library = 0;
+ }
+ }
+ else if (strncmp (argv[i], "-x", 2) == 0)
+ saw_speclang = 1;
+ else if (((argv[i][2] == '\0'
+ && (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL)
+ || strcmp (argv[i], "-Tdata") == 0))
+ quote = argv[i];
+ else if (library != 0 && ((argv[i][2] == '\0'
+ && (char *) strchr ("cSEM", argv[i][1]) != NULL)
+ || strcmp (argv[i], "-MM") == 0))
+ {
+ /* Don't specify libraries if we won't link, since that would
+ cause a warning. */
+ library = 0;
+ added -= 2;
+ }
+ else
+ /* Pass other options through. */
+ continue;
+ }
+ else
+ {
+ int len;
+
+ if (saw_speclang)
+ {
+ saw_speclang = 0;
+ continue;
+ }
+
+ /* If the filename ends in .c or .i, put options around it.
+ But not if a specified -x option is currently active. */
+ len = strlen (argv[i]);
+ if (len > 2
+ && (argv[i][len - 1] == 'c' || argv[i][len - 1] == 'i')
+ && argv[i][len - 2] == '.')
+ {
+ args[i] |= LANGSPEC;
+ added += 2;
+ }
+ }
+ }
+
+ if (quote)
+ (*fn) ("argument to `%s' missing\n", quote);
+
+ /* If we know we don't have to do anything, bail now. */
+ if (! added && ! library)
+ {
+ free (args);
+ return;
+ }
+
+ num_args = argc + added + need_math;
+ arglist = (char **) xmalloc (num_args * sizeof (char *));
+
+ /* NOTE: We start at 1 now, not 0. */
+ for (i = 0, j = 0; i < argc; i++, j++)
+ {
+ arglist[j] = argv[i];
+
+ /* Make sure -lstdc++ is before the math library, since libstdc++
+ itself uses those math routines. */
+ if (!saw_math && (args[i] & MATHLIB) && library)
+ {
+ --j;
+ saw_math = argv[i];
+ }
+
+ if (!saw_libc && (args[i] & WITHLIBC) && library)
+ {
+ --j;
+ saw_libc = argv[i];
+ }
+
+ /* Wrap foo.c and foo.i files in a language specification to
+ force the gcc compiler driver to run cc1plus on them. */
+ if (args[i] & LANGSPEC)
+ {
+ int len = strlen (argv[i]);
+ if (argv[i][len - 1] == 'i')
+ arglist[j++] = "-xc++-cpp-output";
+ else
+ arglist[j++] = "-xc++";
+ arglist[j++] = argv[i];
+ arglist[j] = "-xnone";
+ }
+ }
+
+ /* Add `-lstdc++' if we haven't already done so. */
+ if (library)
+ {
+ arglist[j++] = "-lstdc++";
+ added_libraries++;
+ }
+ if (saw_math)
+ arglist[j++] = saw_math;
+ else if (library && need_math)
+ {
+ arglist[j++] = MATH_LIBRARY;
+ added_libraries++;
+ }
+ if (saw_libc)
+ arglist[j++] = saw_libc;
+
+ arglist[j] = NULL;
+
+ *in_argc = j;
+ *in_argv = arglist;
+ *in_added_libraries = added_libraries;
+}
+
+/* Called before linking. Returns 0 on success and -1 on failure. */
+int lang_specific_pre_link () /* Not used for C++. */
+{
+ return 0;
+}
+
+/* Number of extra output files that lang_specific_pre_link may generate. */
+int lang_specific_extra_outfiles = 0; /* Not used for C++. */
diff --git a/contrib/gcc/cp/gxx.gperf b/contrib/gcc/cp/gxx.gperf
index e5465e8..71538567 100644
--- a/contrib/gcc/cp/gxx.gperf
+++ b/contrib/gcc/cp/gxx.gperf
@@ -5,24 +5,31 @@ struct resword { char *name; short token; enum rid rid;};
%%
__alignof, ALIGNOF, NORID
__alignof__, ALIGNOF, NORID
-__asm, GCC_ASM_KEYWORD, NORID
-__asm__, GCC_ASM_KEYWORD, NORID
+__asm, ASM_KEYWORD, NORID
+__asm__, ASM_KEYWORD, NORID
__attribute, ATTRIBUTE, NORID
__attribute__, ATTRIBUTE, NORID
-__const, TYPE_QUAL, RID_CONST
-__const__, TYPE_QUAL, RID_CONST
+__complex, TYPESPEC, RID_COMPLEX
+__complex__, TYPESPEC, RID_COMPLEX
+__const, CV_QUALIFIER, RID_CONST
+__const__, CV_QUALIFIER, RID_CONST
__extension__, EXTENSION, NORID
+__imag, IMAGPART, NORID
+__imag__, IMAGPART, NORID
__inline, SCSPEC, RID_INLINE
__inline__, SCSPEC, RID_INLINE
__label__, LABEL, NORID
+__null, CONSTANT, RID_NULL
+__real, REALPART, NORID
+__real__, REALPART, NORID
__signature__, AGGR, RID_SIGNATURE /* Extension */,
__signed, TYPESPEC, RID_SIGNED
__signed__, TYPESPEC, RID_SIGNED
__sigof__, SIGOF, NORID /* Extension */,
__typeof, TYPEOF, NORID
__typeof__, TYPEOF, NORID
-__volatile, TYPE_QUAL, RID_VOLATILE
-__volatile__, TYPE_QUAL, RID_VOLATILE
+__volatile, CV_QUALIFIER, RID_VOLATILE
+__volatile__, CV_QUALIFIER, RID_VOLATILE
__wchar_t, TYPESPEC, RID_WCHAR /* Unique to ANSI C++ */,
asm, ASM_KEYWORD, NORID,
and, ANDAND, NORID,
@@ -37,7 +44,7 @@ catch, CATCH, NORID,
char, TYPESPEC, RID_CHAR,
class, AGGR, RID_CLASS,
compl, '~', NORID,
-const, TYPE_QUAL, RID_CONST,
+const, CV_QUALIFIER, RID_CONST,
const_cast, CONST_CAST, NORID,
continue, CONTINUE, NORID,
default, DEFAULT, NORID,
@@ -66,7 +73,6 @@ not_eq, EQCOMPARE, NORID,
operator, OPERATOR, NORID,
or, OROR, NORID,
or_eq, ASSIGN, NORID,
-overload, OVERLOAD, NORID,
private, VISSPEC, RID_PRIVATE,
protected, VISSPEC, RID_PROTECTED,
public, VISSPEC, RID_PUBLIC,
@@ -96,7 +102,7 @@ unsigned, TYPESPEC, RID_UNSIGNED,
using, USING, NORID,
virtual, SCSPEC, RID_VIRTUAL,
void, TYPESPEC, RID_VOID,
-volatile, TYPE_QUAL, RID_VOLATILE,
+volatile, CV_QUALIFIER, RID_VOLATILE,
while, WHILE, NORID,
xor, '^', NORID,
xor_eq, ASSIGN, NORID,
diff --git a/contrib/gcc/cp/gxxint.texi b/contrib/gcc/cp/gxxint.texi
index 015a33c..7cb57f2 100644
--- a/contrib/gcc/cp/gxxint.texi
+++ b/contrib/gcc/cp/gxxint.texi
@@ -9,7 +9,7 @@
@chapter Internal Architecture of the Compiler
This is meant to describe the C++ front-end for gcc in detail.
-Questions and comments to mrs@@cygnus.com.
+Questions and comments to Benjamin Kosnik @code{<bkoz@@cygnus.com>}.
@menu
* Limitations of g++::
@@ -26,6 +26,7 @@ Questions and comments to mrs@@cygnus.com.
* Copying Objects::
* Exception Handling::
* Free Store::
+* Mangling:: Function name mangling for C++ and Java
* Concept Index::
@end menu
@@ -53,38 +54,6 @@ Access checking is unimplemented for nested types.
@item
@code{volatile} is not implemented in general.
-@cindex pointers to members
-@item
-Pointers to members are only minimally supported, and there are places
-where the grammar doesn't even properly accept them yet.
-
-@cindex multiple inheritance
-@item
-@code{this} will be wrong in virtual members functions defined in a
-virtual base class, when they are overridden in a derived class, when
-called via a non-left most object.
-
-An example would be:
-
-@example
-extern "C" int printf(const char*, ...);
-struct A @{ virtual void f() @{ @} @};
-struct B : virtual A @{ int b; B() : b(0) @{@} void f() @{ b++; @} @};
-struct C : B @{@};
-struct D : B @{@};
-struct E : C, D @{@};
-int main()
-@{
- E e;
- C& c = e; D& d = e;
- c.f(); d.f();
- printf ("C::b = %d, D::b = %d\n", e.C::b, e.D::b);
- return 0;
-@}
-@end example
-
-This will print out 2, 0, instead of 1,1.
-
@end itemize
@node Routines, Implementation Specifics, Limitations of g++, Top
@@ -269,6 +238,13 @@ The functions @code{convert_to_aggr} and @code{build_method_call} use
a given candidate function (that's how we get the list of candidates for
@code{ideal_candidate}).
+@item The Explicit Keyword
+
+The use of @code{explicit} on a constructor is used by @code{grokdeclarator}
+to set the field @code{DECL_NONCONVERTING_P}. That value is used by
+@code{build_method_call} and @code{build_user_type_conversion_1} to decide
+if a particular constructor should be used as a candidate for conversions.
+
@end itemize
@node Glossary, Macros, Implementation Specifics, Top
@@ -310,9 +286,7 @@ vtables. See also vtable and vfield.
This section describes some of the macros used on trees. The list
should be alphabetical. Eventually all macros should be documented
-here. There are some postscript drawings that can be used to better
-understand from of the more complex data structures, contact Mike Stump
-(@code{mrs@@cygnus.com}) for information about them.
+here.
@table @code
@item BINFO_BASETYPES
@@ -521,18 +495,6 @@ FIELD_DECLs
@end display
-@item DECL_NESTED_TYPENAME
-Holds the fully qualified type name. Example, Base::Derived.
-
-Has values of:
-
- IDENTIFIER_NODEs
-
-What things can this be used on:
-
- TYPE_DECLs
-
-
@item DECL_NAME
Has values of:
@@ -682,6 +644,15 @@ appear in cp-decl.c and cp-decl2.c, so the are a good candidate for
proper fixing, and removal.
+@item TREE_HAS_CONSTRUCTOR
+A flag to indicate when a CALL_EXPR represents a call to a constructor.
+If set, we know that the type of the object, is the complete type of the
+object, and that the value returned is nonnull. When used in this
+fashion, it is an optimization. Can also be used on SAVE_EXPRs to
+indicate when they are of fixed type and nonnull. Can also be used on
+INDIRECT_EXPRs on CALL_EXPRs that represent a call to a constructor.
+
+
@item TREE_PRIVATE
Set for FIELD_DECLs by finish_struct. But not uniformly set.
@@ -859,7 +830,7 @@ get_binfo (VF_BASETYPE_VALUE (vfield), t, 0)
@end example
@noindent
-will return the binfo for the the given vfield.
+will return the binfo for the given vfield.
May or may not be set at @code{modify_vtable_entries} time. Set at
@code{finish_base_struct} time.
@@ -871,7 +842,7 @@ What things can this be used on:
@item VF_DERIVED_VALUE
Identifies the type of the most derived class of the vfield, excluding
-the the class this vfield is for.
+the class this vfield is for.
Set at @code{finish_base_struct} time.
@@ -1217,24 +1188,32 @@ The below points out some things that work in g++'s exception handling.
All completely constructed temps and local variables are cleaned up in
all unwinded scopes. Completely constructed parts of partially
constructed objects are cleaned up. This includes partially built
-arrays. Exception specifications are now handled.
+arrays. Exception specifications are now handled. Thrown objects are
+now cleaned up all the time. We can now tell if we have an active
+exception being thrown or not (__eh_type != 0). We use this to call
+terminate if someone does a throw; without there being an active
+exception object. uncaught_exception () works. Exception handling
+should work right if you optimize. Exception handling should work with
+-fpic or -fPIC.
The below points out some flaws in g++'s exception handling, as it now
stands.
Only exact type matching or reference matching of throw types works when
--fno-rtti is used. Only works on a SPARC (like Suns), i386, arm and
-rs6000 machines. Partial support is in for all other machines, but a
-stack unwinder called __unwind_function has to be written, and added to
-libgcc2 for them. See below for details on __unwind_function. Don't
-expect exception handling to work right if you optimize, in fact the
-compiler will probably core dump. RTL_EXPRs for EH cond variables for
-&& and || exprs should probably be wrapped in UNSAVE_EXPRs, and
-RTL_EXPRs tweaked so that they can be unsaved, and the UNSAVE_EXPR code
-should be in the backend, or alternatively, UNSAVE_EXPR should be ripped
-out and exactly one finalization allowed to be expanded by the backend.
-I talked with kenner about this, and we have to allow multiple
-expansions.
+-fno-rtti is used. Only works on a SPARC (like Suns) (both -mflat and
+-mno-flat models work), SPARClite, Hitachi SH, i386, arm, rs6000,
+PowerPC, Alpha, mips, VAX, m68k and z8k machines. SPARC v9 may not
+work. HPPA is mostly done, but throwing between a shared library and
+user code doesn't yet work. Some targets have support for data-driven
+unwinding. Partial support is in for all other machines, but a stack
+unwinder called __unwind_function has to be written, and added to
+libgcc2 for them. The new EH code doesn't rely upon the
+__unwind_function for C++ code, instead it creates per function
+unwinders right inside the function, unfortunately, on many platforms
+the definition of RETURN_ADDR_RTX in the tm.h file for the machine port
+is wrong. See below for details on __unwind_function. RTL_EXPRs for EH
+cond variables for && and || exprs should probably be wrapped in
+UNSAVE_EXPRs, and RTL_EXPRs tweaked so that they can be unsaved.
We only do pointer conversions on exception matching a la 15.3 p2 case
3: `A handler with type T, const T, T&, or const T& is a match for a
@@ -1266,12 +1245,13 @@ build_exception_variant should sort the incoming list, so that it
implements set compares, not exact list equality. Type smashing should
smash exception specifications using set union.
-Thrown objects are usually allocated on the heap, in the usual way, but
-they are never deleted. They should be deleted by the catch clauses.
-If one runs out of heap space, throwing an object will probably never
-work. This could be relaxed some by passing an __in_chrg parameter to
-track who has control over the exception object. Thrown objects are not
-allocated on the heap when they are pointer to object types.
+Thrown objects are usually allocated on the heap, in the usual way. If
+one runs out of heap space, throwing an object will probably never work.
+This could be relaxed some by passing an __in_chrg parameter to track
+who has control over the exception object. Thrown objects are not
+allocated on the heap when they are pointer to object types. We should
+extend it so that all small (<4*sizeof(void*)) objects are stored
+directly, instead of allocated on the heap.
When the backend returns a value, it can create new exception regions
that need protecting. The new region should rethrow the object in
@@ -1285,13 +1265,13 @@ Ln: throw value;
copy value onto heap
jump throw (Ln, id, address of copy of value on heap)
- try {
+ try @{
+Lstart: the start of the main EH region
|... ...
+Lend: the end of the main EH region
- } catch (T o) {
+ @} catch (T o) @{
...1
- }
+ @}
Lresume:
nop used to make sure there is something before
the next region ends, if there is one
@@ -1312,7 +1292,7 @@ Lover:
[
[
call throw_type_match
- if (eq) {
+ if (eq) @{
] these lines disappear when there is no catch condition
+Lsregion2:
| ...1
@@ -1320,7 +1300,7 @@ Lover:
|Lhandler: handler for the region Lsregion2-Leregion2
| rethrow (Lresume, same id, same obj);
+Leregion2
- }
+ @}
] there are zero or more of these sections, depending upon how many
catch clauses there are
----------------------------- expand_end_all_catch --------------------------
@@ -1336,7 +1316,7 @@ Ldone:
start_all_catch emits labels: Lresume,
-#end example
+@end example
The __unwind_function takes a pointer to the throw handler, and is
expected to pop the stack frame that was built to call it, as well as
@@ -1346,7 +1326,7 @@ machine state as determined by the context in which we are unwinding
into. The way I normally start is to compile:
void *g;
- foo(void* a) { g = a; }
+ foo(void* a) @{ g = a; @}
with -S, and change the thing that alters the PC (return, or ret
usually) to not alter the PC, making sure to leave all other semantics
@@ -1423,6 +1403,33 @@ things: first, a way to figure out where the frame pointer was stored,
and second, a functional @code{__builtin_return_address} implementation
for except.c to be able to use it.
+Or just support DWARF 2 unwind info.
+
+@subsection New Backend Exception Support
+
+This subsection discusses various aspects of the design of the
+data-driven model being implemented for the exception handling backend.
+
+The goal is to generate enough data during the compilation of user code,
+such that we can dynamically unwind through functions at run time with a
+single routine (@code{__throw}) that lives in libgcc.a, built by the
+compiler, and dispatch into associated exception handlers.
+
+This information is generated by the DWARF 2 debugging backend, and
+includes all of the information __throw needs to unwind an arbitrary
+frame. It specifies where all of the saved registers and the return
+address can be found at any point in the function.
+
+Major disadvantages when enabling exceptions are:
+
+@itemize @bullet
+@item
+Code that uses caller saved registers, can't, when flow can be
+transferred into that code from an exception handler. In high performance
+code this should not usually be true, so the effects should be minimal.
+
+@end itemize
+
@subsection Backend Exception Support
The backend must be extended to fully support exceptions. Right now
@@ -1453,7 +1460,7 @@ descriptor that refers to fully contained code that has been eliminated
should also be removed, although not doing this is harmless in terms of
semantics.
-#end itemize
+@end itemize
The above is not meant to be exhaustive, but does include all things I
have thought of so far. I am sure other limitations exist.
@@ -1469,9 +1476,9 @@ required to call them in pairs. When marking the end of a region, an
argument can be passed to indicate the handler for the marked region.
This can be passed in many ways, currently a tree is used. Another
possibility would be insns for the handler, or a label that denotes a
-handler. I have a feeling insns might be the the best way to pass it.
+handler. I have a feeling insns might be the best way to pass it.
Semantics are, if an exception is thrown inside the region, control is
-transfered unconditionally to the handler. If control passes through
+transferred unconditionally to the handler. If control passes through
the handler, then the backend is to rethrow the exception, in the
context of the end of the original region. The handler is protected by
the conventional mechanisms; it is the frontend's responsibility to
@@ -1490,21 +1497,6 @@ between a cleanup-rethrower, and a real handler, if would also have to
have a way to know if a handler `matches' a thrown exception, and this
is frontend specific.
-The UNSAVE_EXPR tree code has to be migrated to the backend. Exprs such
-as TARGET_EXPRs, WITH_CLEANUP_EXPRs, CALL_EXPRs and RTL_EXPRs have to be
-changed to support unsaving. This is meant to be a complete list.
-SAVE_EXPRs can be unsaved already. expand_decl_cleanup should be
-changed to unsave it's argument, if needed. See
-cp/tree.c:cp_expand_decl_cleanup, unsave_expr_now, unsave_expr, and
-cp/expr.c:cplus_expand_expr(case UNSAVE_EXPR:) for the UNSAVE_EXPR code.
-Now, as to why... because kenner already tripped over the exact same
-problem in Ada, we talked about it, he didn't like any of the solution,
-but yet, didn't like no solution either. He was willing to live with
-the drawbacks of this solution. The drawback is unsave_expr_now. It
-should have a callback into the frontend, to allow the unsaveing of
-frontend special codes. The callback goes in, inplace of the call to
-my_friendly_abort.
-
The stack unwinder is one of the hardest parts to do. It is highly
machine dependent. The form that kenner seems to like was a couple of
macros, that would do the machine dependent grunt work. One preexisting
@@ -1513,31 +1505,15 @@ macro he seemed to want was __builtin_return_address, and the other
would do the hard work of fixing up the registers, adjusting the stack
pointer, frame pointer, arg pointer and so on.
-The eh archive (~mrs/eh) might be good reading for understanding the Ada
-perspective, and some of kenners mindset, and a detailed explanation
-(Message-Id: <9308301130.AA10543@vlsi1.ultra.nyu.edu>) of the concepts
-involved.
-
-Here is a guide to existing backend type code. It is all in
-cp/except.c. Check out do_unwind, and expand_builtin_throw for current
-code on how to figure out what handler matches an exception,
-emit_exception_table for code on emitting the PC range table that is
-built during compilation, expand_exception_blocks for code that emits
-all the handlers at the end of a functions, end_protect to mark the end
-of an exception region, start_protect to mark the start of an exception
-region, lang_interim_eh is the master hook used by the backend into the
-EH backend that now exists in the frontend, and expand_internal_throw to
-raise an exception.
-
-@node Free Store, Concept Index, Exception Handling, Top
+@node Free Store, Mangling, Exception Handling, Top
@section Free Store
-operator new [] adds a magic cookie to the beginning of arrays for which
-the number of elements will be needed by operator delete []. These are
-arrays of objects with destructors and arrays of objects that define
-operator delete [] with the optional size_t argument. This cookie can
-be examined from a program as follows:
+@code{operator new []} adds a magic cookie to the beginning of arrays
+for which the number of elements will be needed by @code{operator delete
+[]}. These are arrays of objects with destructors and arrays of objects
+that define @code{operator delete []} with the optional size_t argument.
+This cookie can be examined from a program as follows:
@example
typedef unsigned long size_t;
@@ -1576,8 +1552,373 @@ The linkage code in g++ is horribly twisted in order to meet two design goals:
To meet the first goal, we defer emission of inlines and vtables until
the end of the translation unit, where we can decide whether or not they
are needed, and how to emit them if they are.
+
+@node Mangling, Concept Index, Free Store, Top
+@section Function name mangling for C++ and Java
+
+Both C++ and Jave provide overloaded function and methods,
+which are methods with the same types but different parameter lists.
+Selecting the correct version is done at compile time.
+Though the overloaded functions have the same name in the source code,
+they need to be translated into different assembler-level names,
+since typical assemblers and linkers cannot handle overloading.
+This process of encoding the parameter types with the method name
+into a unique name is called @dfn{name mangling}. The inverse
+process is called @dfn{demangling}.
+
+It is convenient that C++ and Java use compatible mangling schemes,
+since the makes life easier for tools such as gdb, and it eases
+integration between C++ and Java.
+
+Note there is also a standard "Jave Native Interface" (JNI) which
+implements a different calling convention, and uses a different
+mangling scheme. The JNI is a rather abstract ABI so Java can call methods
+written in C or C++;
+we are concerned here about a lower-level interface primarily
+intended for methods written in Java, but that can also be used for C++
+(and less easily C).
+
+Note that on systems that follow BSD tradition, a C identifier @code{var}
+would get "mangled" into the assembler name @samp{_var}. On such
+systems, all other mangled names are also prefixed by a @samp{_}
+which is not shown in the following examples.
+
+@subsection Method name mangling
+
+C++ mangles a method by emitting the function name, followed by @code{__},
+followed by encodings of any method qualifiers (such as @code{const}),
+followed by the mangling of the method's class,
+followed by the mangling of the parameters, in order.
+
+For example @code{Foo::bar(int, long) const} is mangled
+as @samp{bar__C3Fooil}.
+
+For a constructor, the method name is left out.
+That is @code{Foo::Foo(int, long) const} is mangled
+as @samp{__C3Fooil}.
+
+GNU Java does the same.
+
+@subsection Primitive types
+
+The C++ types @code{int}, @code{long}, @code{short}, @code{char},
+and @code{long long} are mangled as @samp{i}, @samp{l},
+@samp{s}, @samp{c}, and @samp{x}, respectively.
+The corresponding unsigned types have @samp{U} prefixed
+to the mangling. The type @code{signed char} is mangled @samp{Sc}.
+
+The C++ and Java floating-point types @code{float} and @code{double}
+are mangled as @samp{f} and @samp{d} respectively.
+
+The C++ @code{bool} type and the Java @code{boolean} type are
+mangled as @samp{b}.
+
+The C++ @code{wchar_t} and the Java @code{char} types are
+mangled as @samp{w}.
+
+The Java integral types @code{byte}, @code{short}, @code{int}
+and @code{long} are mangled as @samp{c}, @samp{s}, @samp{i},
+and @samp{x}, respectively.
+
+C++ code that has included @code{javatypes.h} will mangle
+the typedefs @code{jbyte}, @code{jshort}, @code{jint}
+and @code{jlong} as respectively @samp{c}, @samp{s}, @samp{i},
+and @samp{x}. (This has not been implemented yet.)
+
+@subsection Mangling of simple names
+
+A simple class, package, template, or namespace name is
+encoded as the number of characters in the name, followed by
+the actual characters. Thus the class @code{Foo}
+is encoded as @samp{3Foo}.
+
+If any of the characters in the name are not alphanumeric
+(i.e not one of the standard ASCII letters, digits, or '_'),
+or the initial character is a digit, then the name is
+mangled as a sequence of encoded Unicode letters.
+A Unicode encoding starts with a @samp{U} to indicate
+that Unicode escapes are used, followed by the number of
+bytes used by the Unicode encoding, followed by the bytes
+representing the encoding. ASSCI letters and
+non-initial digits are encoded without change. However, all
+other characters (including underscore and initial digits) are
+translated into a sequence starting with an underscore,
+followed by the big-endian 4-hex-digit lower-case encoding of the character.
+
+If a method name contains Unicode-escaped characters, the
+entire mangled method name is followed by a @samp{U}.
+
+For example, the method @code{X\u0319::M\u002B(int)} is encoded as
+@samp{M_002b__U6X_0319iU}.
+
+
+@subsection Pointer and reference types
+
+A C++ pointer type is mangled as @samp{P} followed by the
+mangling of the type pointed to.
+
+A C++ reference type as mangled as @samp{R} followed by the
+mangling of the type referenced.
+
+A Java object reference type is equivalent
+to a C++ pointer parameter, so we mangle such an parameter type
+as @samp{P} followed by the mangling of the class name.
+
+@subsection Squangled type compression
+
+Squangling (enabled with the @samp{-fsquangle} option), utilizes
+the @samp{B} code to indicate reuse of a previously
+seen type within an indentifier. Types are recognized in a left to
+right manner and given increasing values, which are
+appended to the code in the standard manner. Ie, multiple digit numbers
+are delimited by @samp{_} characters. A type is considered to be any
+non primitive type, regardless of whether its a parameter, template
+parameter, or entire template. Certain codes are considered modifiers
+of a type, and are not included as part of the type. These are the
+@samp{C}, @samp{V}, @samp{P}, @samp{A}, @samp{R}, and @samp{U} codes,
+denoting constant, volatile, pointer, array, reference, and unsigned.
+These codes may precede a @samp{B} type in order to make the required
+modifications to the type.
+
+For example:
+@example
+template <class T> class class1 @{ @};
+
+template <class T> class class2 @{ @};
+
+class class3 @{ @};
+
+int f(class2<class1<class3> > a ,int b, const class1<class3>&c, class3 *d) @{ @}
+
+ B0 -> class2<class1<class3>
+ B1 -> class1<class3>
+ B2 -> class3
+@end example
+Produces the mangled name @samp{f__FGt6class21Zt6class11Z6class3iRCB1PB2}.
+The int parameter is a basic type, and does not receive a B encoding...
+
+@subsection Qualified names
+
+Both C++ and Java allow a class to be lexically nested inside another
+class. C++ also supports namespaces (not yet implemented by G++).
+Java also supports packages.
+
+These are all mangled the same way: First the letter @samp{Q}
+indicates that we are emitting a qualified name.
+That is followed by the number of parts in the qualified name.
+If that number is 9 or less, it is emitted with no delimiters.
+Otherwise, an underscore is written before and after the count.
+Then follows each part of the qualified name, as described above.
+
+For example @code{Foo::\u0319::Bar} is encoded as
+@samp{Q33FooU5_03193Bar}.
+
+Squangling utilizes the the letter @samp{K} to indicate a
+remembered portion of a qualified name. As qualified names are processed
+for an identifier, the names are numbered and remembered in a
+manner similar to the @samp{B} type compression code.
+Names are recognized left to right, and given increasing values, which are
+appended to the code in the standard manner. ie, multiple digit numbers
+are delimited by @samp{_} characters.
+
+For example
+@example
+class Andrew
+@{
+ class WasHere
+ @{
+ class AndHereToo
+ @{
+ @};
+ @};
+@};
+
+f(Andrew&r1, Andrew::WasHere& r2, Andrew::WasHere::AndHereToo& r3) @{ @}
+
+ K0 -> Andrew
+ K1 -> Andrew::WasHere
+ K2 -> Andrew::WasHere::AndHereToo
+@end example
+Function @samp{f()} would be mangled as :
+@samp{f__FR6AndrewRQ2K07WasHereRQ2K110AndHereToo}
+
+There are some occasions when either a @samp{B} or @samp{K} code could
+be chosen, preference is always given to the @samp{B} code. Ie, the example
+in the section on @samp{B} mangling could have used a @samp{K} code
+instead of @samp{B2}.
+
+@subsection Templates
+
+A class template instantiation is encoded as the letter @samp{t},
+followed by the encoding of the template name, followed
+the number of template parameters, followed by encoding of the template
+parameters. If a template parameter is a type, it is written
+as a @samp{Z} followed by the encoding of the type.
+
+A function template specialization (either an instantiation or an
+explicit specialization) is encoded by an @samp{H} followed by the
+encoding of the template parameters, as described above, followed by an
+@samp{_}, the encoding of the argument types to the template function
+(not the specialization), another @samp{_}, and the return type. (Like
+the argument types, the return type is the return type of the function
+template, not the specialization.) Template parameters in the argument
+and return types are encoded by an @samp{X} for type parameters, or a
+@samp{Y} for constant parameters, an index indicating their position
+in the template parameter list declaration, and their template depth.
+
+@subsection Arrays
+
+C++ array types are mangled by emitting @samp{A}, followed by
+the length of the array, followed by an @samp{_}, followed by
+the mangling of the element type. Of course, normally
+array parameter types decay into a pointer types, so you
+don't see this.
+
+Java arrays are objects. A Java type @code{T[]} is mangled
+as if it were the C++ type @code{JArray<T>}.
+For example @code{java.lang.String[]} is encoded as
+@samp{Pt6JArray1ZPQ34java4lang6String}.
+
+@subsection Static fields
+
+Both C++ and Java classes can have static fields.
+These are allocated statically, and are shared among all instances.
+
+The mangling starts with a prefix (@samp{_} in most systems), which is
+followed by the mangling
+of the class name, followed by the "joiner" and finally the field name.
+The joiner (see @code{JOINER} in @code{cp-tree.h}) is a special
+separator character. For historical reasons (and idiosyncracies
+of assembler syntax) it can @samp{$} or @samp{.} (or even
+@samp{_} on a few systems). If the joiner is @samp{_} then the prefix
+is @samp{__static_} instead of just @samp{_}.
+
+For example @code{Foo::Bar::var} (or @code{Foo.Bar.var} in Java syntax)
+would be encoded as @samp{_Q23Foo3Bar$var} or @samp{_Q23Foo3Bar.var}
+(or rarely @samp{__static_Q23Foo3Bar_var}).
+
+If the name of a static variable needs Unicode escapes,
+the Unicode indicator @samp{U} comes before the "joiner".
+This @code{\u1234Foo::var\u3445} becomes @code{_U8_1234FooU.var_3445}.
+
+@subsection Table of demangling code characters
+
+The following special characters are used in mangling:
+
+@table @samp
+@item A
+Indicates a C++ array type.
+
+@item b
+Encodes the C++ @code{bool} type,
+and the Java @code{boolean} type.
+
+@item B
+Used for squangling. Similar in concept to the 'T' non-squangled code.
+
+@item c
+Encodes the C++ @code{char} type, and the Java @code{byte} type.
+
+@item C
+A modifier to indicate a @code{const} type.
+Also used to indicate a @code{const} member function
+(in which cases it precedes the encoding of the method's class).
+
+@item d
+Encodes the C++ and Java @code{double} types.
+
+@item e
+Indicates extra unknown arguments @code{...}.
+
+@item E
+Indicates the opening parenthesis of an expression.
+
+@item f
+Encodes the C++ and Java @code{float} types.
+
+@item F
+Used to indicate a function type.
+
+@item H
+Used to indicate a template function.
+
+@item i
+Encodes the C++ and Java @code{int} types.
+
+@item J
+Indicates a complex type.
+
+@item K
+Used by squangling to compress qualified names.
+
+@item l
+Encodes the C++ @code{long} type.
+
+@item P
+Indicates a pointer type. Followed by the type pointed to.
+
+@item Q
+Used to mangle qualified names, which arise from nested classes.
+Should also be used for namespaces (?).
+In Java used to mangle package-qualified names, and inner classes.
+
+@item r
+Encodes the GNU C++ @code{long double} type.
+
+@item R
+Indicates a reference type. Followed by the referenced type.
+
+@item s
+Encodes the C++ and java @code{short} types.
+
+@item S
+A modifier that indicates that the following integer type is signed.
+Only used with @code{char}.
+
+Also used as a modifier to indicate a static member function.
+
+@item t
+Indicates a template instantiation.
+
+@item T
+A back reference to a previously seen type.
+
+@item U
+A modifier that indicates that the following integer type is unsigned.
+Also used to indicate that the following class or namespace name
+is encoded using Unicode-mangling.
+
+@item v
+Encodes the C++ and Java @code{void} types.
+
+@item V
+A modified for a @code{const} type or method.
+
+@item w
+Encodes the C++ @code{wchar_t} type, and the Java @code{char} types.
+
+@item W
+Indicates the closing parenthesis of an expression.
+
+@item x
+Encodes the GNU C++ @code{long long} type, and the Java @code{long} type.
+
+@item X
+Encodes a template type parameter, when part of a function type.
+
+@item Y
+Encodes a template constant parameter, when part of a function type.
+
+@item Z
+Used for template type parameters.
+
+@end table
+
+The letters @samp{G}, @samp{M}, @samp{O}, and @samp{p}
+also seem to be used for obscure purposes ...
+
+@node Concept Index, , Mangling, Top
-@node Concept Index, , Free Store, Top
@section Concept Index
@printindex cp
diff --git a/contrib/gcc/cp/inc/exception b/contrib/gcc/cp/inc/exception
new file mode 100644
index 0000000..9954146
--- /dev/null
+++ b/contrib/gcc/cp/inc/exception
@@ -0,0 +1,43 @@
+// Exception Handling support header for -*- C++ -*-
+// Copyright (C) 1995, 1996 Free Software Foundation
+
+#ifndef __EXCEPTION__
+#define __EXCEPTION__
+
+#pragma interface "exception"
+
+extern "C++" {
+
+#ifdef __HONOR_STD
+namespace std {
+#endif
+
+class exception {
+public:
+ exception () { }
+ virtual ~exception () { }
+ virtual const char* what () const;
+};
+
+class bad_exception : public exception {
+public:
+ bad_exception () { }
+ virtual ~bad_exception () { }
+};
+
+typedef void (*terminate_handler) ();
+typedef void (*unexpected_handler) ();
+
+terminate_handler set_terminate (terminate_handler);
+void terminate () __attribute__ ((__noreturn__));
+unexpected_handler set_unexpected (unexpected_handler);
+void unexpected () __attribute__ ((__noreturn__));
+bool uncaught_exception ();
+
+#ifdef __HONOR_STD
+} // namespace std
+#endif
+
+} // extern "C++"
+
+#endif
diff --git a/contrib/gcc/cp/inc/new b/contrib/gcc/cp/inc/new
new file mode 100644
index 0000000..0f25a5c
--- /dev/null
+++ b/contrib/gcc/cp/inc/new
@@ -0,0 +1,46 @@
+// The -*- C++ -*- dynamic memory management header.
+// Copyright (C) 1994, 1996 Free Software Foundation
+
+#ifndef __NEW__
+#define __NEW__
+
+#pragma interface "new"
+#include <stddef.h>
+#include <exception>
+
+extern "C++" {
+
+#ifdef __HONOR_STD
+namespace std {
+#endif
+
+ class bad_alloc : public exception {
+ public:
+ virtual const char* what() const throw() { return "bad_alloc"; }
+ };
+
+ struct nothrow_t {};
+ extern const nothrow_t nothrow;
+ typedef void (*new_handler)();
+ new_handler set_new_handler (new_handler);
+
+#ifdef __HONOR_STD
+} // namespace std
+#endif
+
+// replaceable signatures
+void *operator new (size_t) throw (std::bad_alloc);
+void *operator new[] (size_t) throw (std::bad_alloc);
+void operator delete (void *) throw();
+void operator delete[] (void *) throw();
+void *operator new (size_t, const std::nothrow_t&) throw();
+void *operator new[] (size_t, const std::nothrow_t&) throw();
+void operator delete (void *, const std::nothrow_t&) throw();
+void operator delete[] (void *, const std::nothrow_t&) throw();
+
+// default placement versions of operator new
+inline void *operator new(size_t, void *place) throw() { return place; }
+inline void *operator new[](size_t, void *place) throw() { return place; }
+} // extern "C++"
+
+#endif
diff --git a/contrib/gcc/cp/inc/new.h b/contrib/gcc/cp/inc/new.h
new file mode 100644
index 0000000..799db7e
--- /dev/null
+++ b/contrib/gcc/cp/inc/new.h
@@ -0,0 +1,13 @@
+// -*- C++ -*- forwarding header.
+
+#ifndef __NEW_H__
+#define __NEW_H__
+
+#include <new>
+
+#ifdef __HONOR_STD
+using std::new_handler;
+using std::set_new_handler;
+#endif
+
+#endif // __NEW_H__
diff --git a/contrib/gcc/cp/inc/typeinfo b/contrib/gcc/cp/inc/typeinfo
new file mode 100644
index 0000000..e46acb9
--- /dev/null
+++ b/contrib/gcc/cp/inc/typeinfo
@@ -0,0 +1,62 @@
+// RTTI support for -*- C++ -*-
+// Copyright (C) 1994, 1995, 1996 Free Software Foundation
+
+#ifndef __TYPEINFO__
+#define __TYPEINFO__
+
+#pragma interface "typeinfo"
+
+#include <exception>
+
+extern "C++" {
+
+#ifdef __HONOR_STD
+namespace std {
+#endif
+
+class type_info {
+private:
+ // assigning type_info is not supported. made private.
+ type_info& operator= (const type_info&);
+ type_info (const type_info&);
+
+protected:
+ type_info (const char *n): _name (n) { }
+
+ const char *_name;
+
+public:
+ // destructor
+ virtual ~type_info ();
+
+ bool before (const type_info& arg) const;
+ const char* name () const
+ { return _name; }
+ bool operator== (const type_info& arg) const;
+ bool operator!= (const type_info& arg) const;
+};
+
+inline bool type_info::
+operator!= (const type_info& arg) const
+{
+ return !operator== (arg);
+}
+
+class bad_cast : public exception {
+public:
+ bad_cast() { }
+ virtual ~bad_cast() { }
+};
+
+class bad_typeid : public exception {
+ public:
+ bad_typeid () { }
+ virtual ~bad_typeid () { }
+};
+
+#ifdef __HONOR_STD
+} // namespace std
+#endif
+
+} // extern "C++"
+#endif
diff --git a/contrib/gcc/cp/init.c b/contrib/gcc/cp/init.c
index 9752a9b..931d033 100644
--- a/contrib/gcc/cp/init.c
+++ b/contrib/gcc/cp/init.c
@@ -1,5 +1,5 @@
/* Handle initialization things in C++.
- Copyright (C) 1987, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -19,18 +19,20 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-
-/* High-level class interface. */
+/* High-level class interface. */
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "cp-tree.h"
#include "flags.h"
#include "output.h"
+#include "except.h"
+#include "expr.h"
+#include "toplev.h"
-#undef NULL
-#define NULL 0
+extern void compiler_error ();
/* In C++, structures with well-defined constructors are initialized by
those constructors, unasked. CURRENT_BASE_INIT_LIST
@@ -43,35 +45,36 @@ Boston, MA 02111-1307, USA. */
line. Perhaps this was not intended. */
tree current_base_init_list, current_member_init_list;
-void emit_base_init ();
-void check_base_init ();
-static void expand_aggr_vbase_init ();
-void expand_member_init ();
-void expand_aggr_init ();
-
-static void expand_aggr_init_1 ();
-static void expand_recursive_init_1 ();
-static void expand_recursive_init ();
+static void expand_aggr_vbase_init_1 PROTO((tree, tree, tree, tree));
+static void expand_aggr_vbase_init PROTO((tree, tree, tree, tree));
+static void expand_aggr_init_1 PROTO((tree, tree, tree, tree, int,
+ int));
+static void expand_default_init PROTO((tree, tree, tree, tree, int,
+ int));
+static tree build_vec_delete_1 PROTO((tree, tree, tree, tree, tree,
+ int));
+static void perform_member_init PROTO((tree, tree, tree, int));
+static void sort_base_init PROTO((tree, tree *, tree *));
+static tree build_builtin_call PROTO((tree, tree, tree));
+static tree build_array_eh_cleanup PROTO((tree, tree, tree));
+static int member_init_ok_or_else PROTO((tree, tree, char *));
static void expand_virtual_init PROTO((tree, tree));
-tree expand_vec_init ();
-
-static void add_friend (), add_friends ();
+static tree sort_member_init PROTO((tree));
+static tree build_partial_cleanup_for PROTO((tree));
+static tree initializing_context PROTO((tree));
/* Cache _builtin_new and _builtin_delete exprs. */
static tree BIN, BID, BIVN, BIVD;
-/* Cache the identifier nodes for the two magic field of a new cookie. */
+/* Cache the identifier nodes for the magic field of a new cookie. */
static tree nc_nelts_field_id;
-#if 0
-static tree nc_ptr_2comp_field_id;
-#endif
static tree minus_one;
/* Set up local variable for this file. MUST BE CALLED AFTER
INIT_DECL_PROCESSING. */
-tree BI_header_type, BI_header_size;
+static tree BI_header_type, BI_header_size;
void init_init_processing ()
{
@@ -119,6 +122,7 @@ void init_init_processing ()
Relies upon binfo being inside TYPE_BINFO (TREE_TYPE (TREE_TYPE
(addr))). */
+
void
expand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr)
tree real_binfo, binfo, addr;
@@ -132,8 +136,8 @@ expand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr)
{
tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
+ int is_not_base_vtable
+ = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
if (! TREE_VIA_VIRTUAL (real_base_binfo))
expand_direct_vtbls_init (real_base_binfo, base_binfo,
is_not_base_vtable, can_elide, addr);
@@ -153,23 +157,26 @@ expand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr)
/* 348 - 351 */
/* Subroutine of emit_base_init. */
+
static void
-perform_member_init (member, name, init, explicit, protect_list)
- tree member, name, init, *protect_list;
+perform_member_init (member, name, init, explicit)
+ tree member, name, init;
int explicit;
{
tree decl;
tree type = TREE_TYPE (member);
+ expand_start_target_temps ();
+
if (TYPE_NEEDS_CONSTRUCTING (type)
|| (init && TYPE_HAS_CONSTRUCTOR (type)))
{
/* Since `init' is already a TREE_LIST on the current_member_init_list,
only build it into one if we aren't already a list. */
if (init != NULL_TREE && TREE_CODE (init) != TREE_LIST)
- init = build_tree_list (NULL_TREE, init);
+ init = build_expr_list (NULL_TREE, init);
- decl = build_component_ref (C_C_D, name, 0, explicit);
+ decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
if (explicit
&& TREE_CODE (type) == ARRAY_TYPE
@@ -190,9 +197,17 @@ perform_member_init (member, name, init, explicit, protect_list)
{
if (explicit)
{
- cp_error ("incomplete initializer for member `%D' of class `%T' which has no constructor",
- member, current_class_type);
- init = error_mark_node;
+ /* default-initialization. */
+ if (AGGREGATE_TYPE_P (type))
+ init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ cp_error ("default-initialization of `%#D', which has reference type",
+ member);
+ init = error_mark_node;
+ }
+ else
+ init = integer_zero_node;
}
/* member traversal: note it leaves init NULL */
else if (TREE_CODE (TREE_TYPE (member)) == REFERENCE_TYPE)
@@ -215,38 +230,47 @@ perform_member_init (member, name, init, explicit, protect_list)
current_member_init_list. */
if (init || explicit)
{
- decl = build_component_ref (C_C_D, name, 0, explicit);
+ decl = build_component_ref (current_class_ref, name, NULL_TREE,
+ explicit);
expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
}
- expand_cleanups_to (NULL_TREE);
+
+ expand_end_target_temps ();
+ free_temp_slots ();
if (TYPE_NEEDS_DESTRUCTOR (type))
{
- tree expr = build_component_ref (C_C_D, name, 0, explicit);
+ tree expr;
+
+ /* All cleanups must be on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+
+ expr = build_component_ref (current_class_ref, name, NULL_TREE,
+ explicit);
expr = build_delete (type, expr, integer_zero_node,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
if (expr != error_mark_node)
- {
- start_protect ();
- *protect_list = tree_cons (NULL_TREE, expr, *protect_list);
- }
+ add_partial_entry (expr);
+
+ pop_obstacks ();
}
}
extern int warn_reorder;
/* Subroutine of emit_member_init. */
+
static tree
sort_member_init (t)
tree t;
{
- tree x, member, name, field, init;
+ tree x, member, name, field;
tree init_list = NULL_TREE;
- tree fields_to_unmark = NULL_TREE;
int last_pos = 0;
- tree last_field;
+ tree last_field = NULL_TREE;
for (member = TYPE_FIELDS (t); member ; member = TREE_CHAIN (member))
{
@@ -266,6 +290,8 @@ sort_member_init (t)
name = TREE_PURPOSE (x);
#if 0
+ /* This happens in templates, since the IDENTIFIER is replaced
+ with the COMPONENT_REF in tsubst_expr. */
field = (TREE_CODE (name) == COMPONENT_REF
? TREE_OPERAND (name, 1) : IDENTIFIER_CLASS_VALUE (name));
#else
@@ -353,10 +379,10 @@ sort_base_init (t, rbase_ptr, vbase_ptr)
last = tree_cons (NULL_TREE, NULL_TREE, current_base_init_list);
for (x = TREE_CHAIN (last); x; x = TREE_CHAIN (x))
{
- tree basename = TREE_PURPOSE (x);
- tree binfo;
+ tree basetype = TREE_PURPOSE (x);
+ tree binfo = NULL_TREE;
- if (basename == NULL_TREE)
+ if (basetype == NULL_TREE)
{
/* Initializer for single base class. Must not
use multiple inheritance or this is ambiguous. */
@@ -375,9 +401,9 @@ sort_base_init (t, rbase_ptr, vbase_ptr)
}
binfo = TREE_VEC_ELT (binfos, 0);
}
- else if (is_aggr_typedef (basename, 1))
+ else if (is_aggr_type (basetype, 1))
{
- binfo = binfo_or_else (IDENTIFIER_TYPE_VALUE (basename), t);
+ binfo = binfo_or_else (basetype, t);
if (binfo == NULL_TREE)
continue;
@@ -402,8 +428,7 @@ sort_base_init (t, rbase_ptr, vbase_ptr)
if (i < 0)
{
cp_error ("`%T' is not an immediate base class of `%T'",
- IDENTIFIER_TYPE_VALUE (basename),
- current_class_type);
+ basetype, current_class_type);
continue;
}
}
@@ -468,17 +493,14 @@ sort_base_init (t, rbase_ptr, vbase_ptr)
}
/* Perform partial cleanups for a base for exception handling. */
+
static tree
build_partial_cleanup_for (binfo)
tree binfo;
{
- tree expr = convert_pointer_to_real (binfo,
- build_unary_op (ADDR_EXPR, C_C_D, 0));
-
- return build_delete (TREE_TYPE (expr),
- expr,
- integer_zero_node,
- LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
+ return build_scoped_method_call
+ (current_class_ref, binfo, dtor_identifier,
+ build_expr_list (NULL_TREE, integer_zero_node));
}
/* Perform whatever initializations have yet to be done on the base
@@ -506,9 +528,7 @@ emit_base_init (t, immediately)
tree t;
int immediately;
{
- extern tree in_charge_identifier;
-
- tree member, x;
+ tree member;
tree mem_init_list;
tree rbase_init_list, vbase_init_list;
tree t_binfo = TYPE_BINFO (t);
@@ -516,8 +536,6 @@ emit_base_init (t, immediately)
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree expr = NULL_TREE;
- my_friendly_assert (protect_list == NULL_TREE, 999);
-
if (! immediately)
{
int momentary;
@@ -549,7 +567,7 @@ emit_base_init (t, immediately)
tree first_arg = TREE_CHAIN (DECL_ARGUMENTS (current_function_decl));
expand_start_cond (first_arg, 0);
- expand_aggr_vbase_init (t_binfo, C_C_D, current_class_decl,
+ expand_aggr_vbase_init (t_binfo, current_class_ref, current_class_ptr,
vbase_init_list);
expand_end_cond ();
}
@@ -557,7 +575,6 @@ emit_base_init (t, immediately)
/* Now, perform initialization of non-virtual base classes. */
for (i = 0; i < n_baseclasses; i++)
{
- tree base = current_class_decl;
tree base_binfo = TREE_VEC_ELT (binfos, i);
tree init = void_list_node;
@@ -565,7 +582,7 @@ emit_base_init (t, immediately)
continue;
#if 0 /* Once unsharing happens soon enough. */
- my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo);
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (base_binfo) == t_binfo, 999);
#else
BINFO_INHERITANCE_CHAIN (base_binfo) = t_binfo;
#endif
@@ -573,36 +590,49 @@ emit_base_init (t, immediately)
if (TREE_PURPOSE (rbase_init_list))
init = TREE_VALUE (rbase_init_list);
else if (TYPE_NEEDS_CONSTRUCTING (BINFO_TYPE (base_binfo)))
- init = NULL_TREE;
+ {
+ init = NULL_TREE;
+ if (extra_warnings && copy_args_p (current_function_decl))
+ cp_warning ("base class `%#T' should be explicitly initialized in the copy constructor",
+ BINFO_TYPE (base_binfo));
+ }
if (init != void_list_node)
{
- member = convert_pointer_to_real (base_binfo, current_class_decl);
- expand_aggr_init_1 (base_binfo, 0,
+ expand_start_target_temps ();
+
+ member = convert_pointer_to_real (base_binfo, current_class_ptr);
+ expand_aggr_init_1 (base_binfo, NULL_TREE,
build_indirect_ref (member, NULL_PTR), init,
BINFO_OFFSET_ZEROP (base_binfo), LOOKUP_NORMAL);
- expand_cleanups_to (NULL_TREE);
+
+ expand_end_target_temps ();
+ free_temp_slots ();
}
if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
{
- start_protect ();
- protect_list = tree_cons (NULL_TREE,
- build_partial_cleanup_for (base_binfo),
- protect_list);
+ tree expr;
+
+ /* All cleanups must be on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+ expr = build_partial_cleanup_for (base_binfo);
+ pop_obstacks ();
+ add_partial_entry (expr);
}
rbase_init_list = TREE_CHAIN (rbase_init_list);
}
/* Initialize all the virtual function table fields that
- do come from virtual base classes. */
+ do come from virtual base classes. */
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
- expand_indirect_vtbls_init (t_binfo, C_C_D, current_class_decl, 0);
+ expand_indirect_vtbls_init (t_binfo, current_class_ref, current_class_ptr);
/* Initialize all the virtual function table fields that
do not come from virtual base classes. */
- expand_direct_vtbls_init (t_binfo, t_binfo, 1, 1, current_class_decl);
+ expand_direct_vtbls_init (t_binfo, t_binfo, 1, 1, current_class_ptr);
for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member))
{
@@ -622,10 +652,15 @@ emit_base_init (t, immediately)
init = TREE_VALUE (mem_init_list);
from_init_list = 1;
+#if 0
+ if (TREE_CODE (name) == COMPONENT_REF)
+ name = DECL_NAME (TREE_OPERAND (name, 1));
+#else
/* Also see if it's ever a COMPONENT_REF here. If it is, we
need to do `expand_assignment (name, init, 0, 0);' and
a continue. */
my_friendly_assert (TREE_CODE (name) != COMPONENT_REF, 349);
+#endif
}
else
{
@@ -633,9 +668,15 @@ emit_base_init (t, immediately)
init = DECL_INITIAL (member);
from_init_list = 0;
+
+ /* Effective C++ rule 12. */
+ if (warn_ecpp && init == NULL_TREE
+ && !DECL_ARTIFICIAL (member)
+ && TREE_CODE (TREE_TYPE (member)) != ARRAY_TYPE)
+ cp_warning ("`%D' should be initialized in the member initialization list", member);
}
- perform_member_init (member, name, init, from_init_list, &protect_list);
+ perform_member_init (member, name, init, from_init_list);
mem_init_list = TREE_CHAIN (mem_init_list);
}
@@ -673,7 +714,7 @@ emit_base_init (t, immediately)
my_friendly_assert (DECL_FIELD_CONTEXT (field) != t, 351);
#endif
- perform_member_init (field, name, init, 1, &protect_list);
+ perform_member_init (field, name, init, 1);
}
mem_init_list = TREE_CHAIN (mem_init_list);
}
@@ -697,6 +738,7 @@ emit_base_init (t, immediately)
/* Check that all fields are properly initialized after
an assignment to `this'. */
+
void
check_base_init (t)
tree t;
@@ -713,6 +755,7 @@ check_base_init (t)
BINFO is the exact type that DECL is supposed to be. In
multiple inheritance, this might mean "C's A" if C : A, B. */
+
static void
expand_virtual_init (binfo, decl)
tree binfo, decl;
@@ -743,23 +786,30 @@ expand_virtual_init (binfo, decl)
/* Subroutine of `expand_aggr_vbase_init'.
BINFO is the binfo of the type that is being initialized.
INIT_LIST is the list of initializers for the virtual baseclass. */
+
static void
expand_aggr_vbase_init_1 (binfo, exp, addr, init_list)
tree binfo, exp, addr, init_list;
{
tree init = purpose_member (binfo, init_list);
tree ref = build_indirect_ref (addr, NULL_PTR);
+
+ expand_start_target_temps ();
+
if (init)
init = TREE_VALUE (init);
/* Call constructors, but don't set up vtables. */
expand_aggr_init_1 (binfo, exp, ref, init, 0, LOOKUP_COMPLAIN);
- expand_cleanups_to (NULL_TREE);
+
+ expand_end_target_temps ();
+ free_temp_slots ();
}
/* Initialize this object's virtual base class pointers. This must be
done only at the top-level of the object being constructed.
INIT_LIST is list of initialization for constructor to perform. */
+
static void
expand_aggr_vbase_init (binfo, exp, addr, init_list)
tree binfo;
@@ -788,38 +838,25 @@ expand_aggr_vbase_init (binfo, exp, addr, init_list)
}
}
-/* Subroutine to perform parser actions for member initialization.
- S_ID is the scoped identifier.
- NAME is the name of the member.
- INIT is the initializer, or `void_type_node' if none. */
-void
-do_member_init (s_id, name, init)
- tree s_id, name, init;
-{
- tree binfo, base;
+/* Find the context in which this FIELD can be initialized. */
- if (current_class_type == NULL_TREE
- || ! is_aggr_typedef (s_id, 1))
- return;
- binfo = get_binfo (IDENTIFIER_TYPE_VALUE (s_id),
- current_class_type, 1);
- if (binfo == error_mark_node)
- return;
- if (binfo == 0)
- {
- error_not_base_type (IDENTIFIER_TYPE_VALUE (s_id), current_class_type);
- return;
- }
+static tree
+initializing_context (field)
+ tree field;
+{
+ tree t = DECL_CONTEXT (field);
- base = convert_pointer_to (binfo, current_class_decl);
- expand_member_init (build_indirect_ref (base, NULL_PTR), name, init);
+ /* Anonymous union members can be initialized in the first enclosing
+ non-anonymous union context. */
+ while (t && ANON_UNION_TYPE_P (t))
+ t = TYPE_CONTEXT (t);
+ return t;
}
/* Function to give error message if member initialization specification
is erroneous. FIELD is the member we decided to initialize.
TYPE is the type for which the initialization is being performed.
- FIELD must be a member of TYPE, or the base type from which FIELD
- comes must not need a constructor.
+ FIELD must be a member of TYPE.
MEMBER_NAME is the name of the member. */
@@ -831,23 +868,12 @@ member_init_ok_or_else (field, type, member_name)
{
if (field == error_mark_node)
return 0;
- if (field == NULL_TREE)
+ if (field == NULL_TREE || initializing_context (field) != type)
{
cp_error ("class `%T' does not have any field named `%s'", type,
member_name);
return 0;
}
- if (DECL_CONTEXT (field) != type
- && TYPE_NEEDS_CONSTRUCTING (DECL_CONTEXT (field)))
- {
- if (current_function_decl && DECL_CONSTRUCTOR_P (current_function_decl))
- cp_error ("initialization of `%D' inside constructor for `%T'",
- field, type);
- else
- cp_error ("member `%D' comes from base class needing constructor",
- field);
- return 0;
- }
if (TREE_STATIC (field))
{
cp_error ("field `%#D' is static; only point of initialization is its declaration",
@@ -873,22 +899,25 @@ member_init_ok_or_else (field, type, member_name)
If INIT is non-NULL, then it the initialization should
be placed in `current_base_init_list', where it will be processed
by `emit_base_init'. */
+
void
expand_member_init (exp, name, init)
tree exp, name, init;
{
- extern tree ptr_type_node; /* should be in tree.h */
-
tree basetype = NULL_TREE, field;
- tree parm;
- tree rval, type;
- tree actual_name;
+ tree type;
if (exp == NULL_TREE)
return; /* complain about this later */
type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+ if (name && TREE_CODE (name) == TYPE_DECL)
+ {
+ basetype = TREE_TYPE (name);
+ name = DECL_NAME (name);
+ }
+
if (name == NULL_TREE && IS_AGGR_TYPE (type))
switch (CLASSTYPE_N_BASECLASSES (type))
{
@@ -904,169 +933,84 @@ expand_member_init (exp, name, init)
return;
}
- if (init)
- {
- /* The grammar should not allow fields which have names
- that are TYPENAMEs. Therefore, if the field has
- a non-NULL TREE_TYPE, we may assume that this is an
- attempt to initialize a base class member of the current
- type. Otherwise, it is an attempt to initialize a
- member field. */
-
- if (init == void_type_node)
- init = NULL_TREE;
+ my_friendly_assert (init != NULL_TREE, 0);
- if (name == NULL_TREE || IDENTIFIER_HAS_TYPE_VALUE (name))
- {
- tree base_init;
+ /* The grammar should not allow fields which have names that are
+ TYPENAMEs. Therefore, if the field has a non-NULL TREE_TYPE, we
+ may assume that this is an attempt to initialize a base class
+ member of the current type. Otherwise, it is an attempt to
+ initialize a member field. */
- if (name == NULL_TREE)
- {
-/*
- if (basetype)
- name = TYPE_IDENTIFIER (basetype);
- else
- {
- error ("no base class to initialize");
- return;
- }
-*/
- }
- else
- {
- basetype = IDENTIFIER_TYPE_VALUE (name);
- if (basetype != type
- && ! binfo_member (basetype, TYPE_BINFO (type))
- && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type)))
- {
- if (IDENTIFIER_CLASS_VALUE (name))
- goto try_member;
- if (TYPE_USES_VIRTUAL_BASECLASSES (type))
- error ("type `%s' is not an immediate or virtual basetype for `%s'",
- IDENTIFIER_POINTER (name),
- TYPE_NAME_STRING (type));
- else
- error ("type `%s' is not an immediate basetype for `%s'",
- IDENTIFIER_POINTER (name),
- TYPE_NAME_STRING (type));
- return;
- }
- }
+ if (init == void_type_node)
+ init = NULL_TREE;
- if (purpose_member (name, current_base_init_list))
- {
- error ("base class `%s' already initialized",
- IDENTIFIER_POINTER (name));
- return;
- }
+ if (name == NULL_TREE || basetype)
+ {
+ tree base_init;
- base_init = build_tree_list (name, init);
- TREE_TYPE (base_init) = basetype;
- current_base_init_list = chainon (current_base_init_list, base_init);
- }
- else
+ if (name == NULL_TREE)
{
- tree member_init;
-
- try_member:
- field = lookup_field (type, name, 1, 0);
-
- if (! member_init_ok_or_else (field, type, IDENTIFIER_POINTER (name)))
- return;
-
- if (purpose_member (name, current_member_init_list))
+#if 0
+ if (basetype)
+ name = TYPE_IDENTIFIER (basetype);
+ else
{
- error ("field `%s' already initialized", IDENTIFIER_POINTER (name));
+ error ("no base class to initialize");
return;
}
-
- member_init = build_tree_list (name, init);
- TREE_TYPE (member_init) = TREE_TYPE (field);
- current_member_init_list = chainon (current_member_init_list, member_init);
+#endif
}
- return;
- }
- else if (name == NULL_TREE)
- {
- compiler_error ("expand_member_init: name == NULL_TREE");
- return;
- }
-
- basetype = type;
- field = lookup_field (basetype, name, 0, 0);
-
- if (! member_init_ok_or_else (field, basetype, IDENTIFIER_POINTER (name)))
- return;
-
- /* now see if there is a constructor for this type
- which will take these args. */
-
- if (TYPE_HAS_CONSTRUCTOR (TREE_TYPE (field)))
- {
- tree parmtypes, fndecl;
-
- if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL)
- {
- /* just know that we've seen something for this node */
- DECL_INITIAL (exp) = error_mark_node;
- TREE_USED (exp) = 1;
+ else if (basetype != type
+ && ! current_template_parms
+ && ! vec_binfo_member (basetype,
+ TYPE_BINFO_BASETYPES (type))
+ && ! binfo_member (basetype, CLASSTYPE_VBASECLASSES (type)))
+ {
+ if (IDENTIFIER_CLASS_VALUE (name))
+ goto try_member;
+ if (TYPE_USES_VIRTUAL_BASECLASSES (type))
+ cp_error ("type `%T' is not an immediate or virtual basetype for `%T'",
+ basetype, type);
+ else
+ cp_error ("type `%T' is not an immediate basetype for `%T'",
+ basetype, type);
+ return;
}
- type = TYPE_MAIN_VARIANT (TREE_TYPE (field));
- actual_name = TYPE_IDENTIFIER (type);
- parm = build_component_ref (exp, name, 0, 0);
-
- /* Now get to the constructor. */
- fndecl = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0);
- /* Get past destructor, if any. */
- if (TYPE_HAS_DESTRUCTOR (type))
- fndecl = DECL_CHAIN (fndecl);
-
- if (fndecl)
- my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 209);
-
- /* If the field is unique, we can use the parameter
- types to guide possible type instantiation. */
- if (DECL_CHAIN (fndecl) == NULL_TREE)
+
+ if (purpose_member (basetype, current_base_init_list))
{
- /* There was a confusion here between
- FIELD and FNDECL. The following code
- should be correct, but abort is here
- to make sure. */
- my_friendly_abort (48);
- parmtypes = FUNCTION_ARG_CHAIN (fndecl);
+ cp_error ("base class `%T' already initialized", basetype);
+ return;
}
- else
+
+ if (warn_reorder && current_member_init_list)
{
- parmtypes = NULL_TREE;
- fndecl = NULL_TREE;
+ cp_warning ("base initializer for `%T'", basetype);
+ warning (" will be re-ordered to precede member initializations");
}
- init = convert_arguments (parm, parmtypes, NULL_TREE, fndecl, LOOKUP_NORMAL);
- if (init == NULL_TREE || TREE_TYPE (init) != error_mark_node)
- rval = build_method_call (NULL_TREE, actual_name, init, NULL_TREE, LOOKUP_NORMAL);
- else
+ base_init = build_tree_list (basetype, init);
+ current_base_init_list = chainon (current_base_init_list, base_init);
+ }
+ else
+ {
+ tree member_init;
+
+ try_member:
+ field = lookup_field (type, name, 1, 0);
+
+ if (! member_init_ok_or_else (field, type, IDENTIFIER_POINTER (name)))
return;
- if (rval != error_mark_node)
+ if (purpose_member (name, current_member_init_list))
{
- /* Now, fill in the first parm with our guy */
- TREE_VALUE (TREE_OPERAND (rval, 1))
- = build_unary_op (ADDR_EXPR, parm, 0);
- TREE_TYPE (rval) = ptr_type_node;
- TREE_SIDE_EFFECTS (rval) = 1;
+ cp_error ("field `%D' already initialized", field);
+ return;
}
- }
- else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field)))
- {
- parm = build_component_ref (exp, name, 0, 0);
- expand_aggr_init (parm, NULL_TREE, 0, 0);
- rval = error_mark_node;
- }
- /* Now initialize the member. It does not have to
- be of aggregate type to receive initialization. */
- if (rval != error_mark_node)
- expand_expr_stmt (rval);
+ member_init = build_tree_list (name, init);
+ current_member_init_list = chainon (current_member_init_list, member_init);
+ }
}
/* This is like `expand_member_init', only it stores one aggregate
@@ -1083,8 +1027,9 @@ expand_member_init (exp, name, init)
explaining that such initializations are invalid.
ALIAS_THIS is nonzero iff we are initializing something which is
- essentially an alias for C_C_D. In this case, the base constructor
- may move it on us, and we must keep track of such deviations.
+ essentially an alias for current_class_ref. In this case, the base
+ constructor may move it on us, and we must keep track of such
+ deviations.
If INIT resolves to a CALL_EXPR which happens to return
something of the type we are looking for, then we know
@@ -1104,8 +1049,7 @@ expand_member_init (exp, name, init)
initialization.
A constructor or a conversion operator may have to be used to
- perform the initialization, but not both, as it would be ambiguous.
- */
+ perform the initialization, but not both, as it would be ambiguous. */
void
expand_aggr_init (exp, init, alias_this, flags)
@@ -1186,14 +1130,15 @@ expand_aggr_init (exp, init, alias_this, flags)
}
static void
-expand_default_init (binfo, true_exp, exp, type, init, alias_this, flags)
+expand_default_init (binfo, true_exp, exp, init, alias_this, flags)
tree binfo;
tree true_exp, exp;
- tree type;
tree init;
int alias_this;
int flags;
{
+ tree type = TREE_TYPE (exp);
+
/* It fails because there may not be a constructor which takes
its own type as the first (or only parameter), but which does
take other types via a conversion. So, if the thing initializing
@@ -1203,6 +1148,37 @@ expand_default_init (binfo, true_exp, exp, type, init, alias_this, flags)
tree rval;
tree parms;
+ if (init && TREE_CODE (init) != TREE_LIST
+ && (flags & LOOKUP_ONLYCONVERTING))
+ {
+ /* Base subobjects should only get direct-initialization. */
+ if (true_exp != exp)
+ abort ();
+
+ /* We special-case TARGET_EXPRs here to avoid an error about
+ private copy constructors for temporaries bound to reference vars.
+ If the TARGET_EXPR represents a call to a function that has
+ permission to create such objects, a reference can bind directly
+ to the return value. An object variable must be initialized
+ via the copy constructor, even if the call is elided. */
+ if (! (TREE_CODE (exp) == VAR_DECL && DECL_ARTIFICIAL (exp)
+ && TREE_CODE (init) == TARGET_EXPR && TREE_TYPE (init) == type))
+ init = ocp_convert (type, init, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
+
+ if (TREE_CODE (init) == TRY_CATCH_EXPR)
+ /* We need to protect the initialization of a catch parm
+ with a call to terminate(), which shows up as a TRY_CATCH_EXPR
+ around the TARGET_EXPR for the copy constructor. See
+ expand_start_catch_block. */
+ TREE_OPERAND (init, 0) = build (INIT_EXPR, TREE_TYPE (exp), exp,
+ TREE_OPERAND (init, 0));
+ else
+ init = build (INIT_EXPR, TREE_TYPE (exp), exp, init);
+ TREE_SIDE_EFFECTS (init) = 1;
+ expand_expr_stmt (init);
+ return;
+ }
+
if (init == NULL_TREE
|| (TREE_CODE (init) == TREE_LIST && ! TREE_TYPE (init)))
{
@@ -1210,64 +1186,22 @@ expand_default_init (binfo, true_exp, exp, type, init, alias_this, flags)
if (parms)
init = TREE_VALUE (parms);
}
- else if (TREE_CODE (init) == INDIRECT_REF && TREE_HAS_CONSTRUCTOR (init)
- && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (init)))
- {
- rval = convert_for_initialization (exp, type, init, 0, 0, 0, 0);
- TREE_USED (rval) = 1;
- expand_expr_stmt (rval);
- return;
- }
else
- parms = build_tree_list (NULL_TREE, init);
+ parms = build_expr_list (NULL_TREE, init);
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
{
if (true_exp == exp)
- parms = tree_cons (NULL_TREE, integer_one_node, parms);
+ parms = expr_tree_cons (NULL_TREE, integer_one_node, parms);
else
- parms = tree_cons (NULL_TREE, integer_zero_node, parms);
+ parms = expr_tree_cons (NULL_TREE, integer_zero_node, parms);
flags |= LOOKUP_HAS_IN_CHARGE;
}
- if (init && TREE_CHAIN (parms) == NULL_TREE
- && TYPE_HAS_TRIVIAL_INIT_REF (type)
- && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (init)))
- {
- rval = build (INIT_EXPR, type, exp, init);
- TREE_SIDE_EFFECTS (rval) = 1;
- expand_expr_stmt (rval);
- }
- else
- {
- if (flags & LOOKUP_ONLYCONVERTING)
- flags |= LOOKUP_NO_CONVERSION;
- rval = build_method_call (exp, constructor_name_full (type),
- parms, binfo, flags);
-
- /* Private, protected, or otherwise unavailable. */
- if (rval == error_mark_node)
- {
- if (flags & LOOKUP_COMPLAIN)
- cp_error ("in base initialization for %sclass `%T'",
- TREE_VIA_VIRTUAL (binfo) ? "virtual base " : "",
- binfo);
- }
- else if (rval == NULL_TREE)
- my_friendly_abort (361);
- else
- {
- /* p. 222: if the base class assigns to `this', then that
- value is used in the derived class. */
- if ((flag_this_is_variable & 1) && alias_this)
- {
- TREE_TYPE (rval) = TREE_TYPE (current_class_decl);
- expand_assignment (current_class_decl, rval, 0, 0);
- }
- else
- expand_expr_stmt (rval);
- }
- }
+ rval = build_method_call (exp, ctor_identifier,
+ parms, binfo, flags);
+ if (TREE_SIDE_EFFECTS (rval))
+ expand_expr_stmt (rval);
}
/* This function is responsible for initializing EXP with INIT
@@ -1301,7 +1235,6 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
int flags;
{
tree type = TREE_TYPE (exp);
- tree init_type = NULL_TREE;
my_friendly_assert (init != error_mark_node && type != error_mark_node, 211);
@@ -1310,357 +1243,31 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, alias_this, flags)
NULL_TREE, know that it was meant for us--just slide exp on
in and expand the constructor. Constructors now come
as TARGET_EXPRs. */
- if (init)
- {
- tree init_list = NULL_TREE;
-
- if (TREE_CODE (init) == TREE_LIST)
- {
- init_list = init;
- if (TREE_CHAIN (init) == NULL_TREE)
- init = TREE_VALUE (init);
- }
-
- init_type = TREE_TYPE (init);
-
- if (TREE_CODE (init) != TREE_LIST)
- {
- if (TREE_CODE (init_type) == ERROR_MARK)
- return;
-
-#if 0
- /* These lines are found troublesome 5/11/89. */
- if (TREE_CODE (init_type) == REFERENCE_TYPE)
- init_type = TREE_TYPE (init_type);
-#endif
- /* This happens when we use C++'s functional cast notation.
- If the types match, then just use the TARGET_EXPR
- directly. Otherwise, we need to create the initializer
- separately from the object being initialized. */
- if (TREE_CODE (init) == TARGET_EXPR)
- {
- if (TYPE_MAIN_VARIANT (init_type) == TYPE_MAIN_VARIANT (type))
- {
- if (TREE_CODE (exp) == VAR_DECL
- || TREE_CODE (exp) == RESULT_DECL)
- /* Unify the initialization targets. */
- DECL_RTL (TREE_OPERAND (init, 0)) = DECL_RTL (exp);
- else
- DECL_RTL (TREE_OPERAND (init, 0)) = expand_expr (exp, NULL_RTX, 0, 0);
-
- expand_expr_stmt (init);
- return;
- }
- else
- {
- init = TREE_OPERAND (init, 1);
- init = build (CALL_EXPR, init_type,
- TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), 0);
- TREE_SIDE_EFFECTS (init) = 1;
- if (init_list)
- TREE_VALUE (init_list) = init;
- }
- }
-
- if (init_type == type && TREE_CODE (init) == CALL_EXPR
-#if 0
- /* It is valid to directly initialize from a CALL_EXPR
- without going through X(X&), apparently. */
- && ! TYPE_GETS_INIT_REF (type)
-#endif
- )
- {
- /* A CALL_EXPR is a legitimate form of initialization, so
- we should not print this warning message. */
-#if 0
- /* Should have gone away due to 5/11/89 change. */
- if (TREE_CODE (TREE_TYPE (init)) == REFERENCE_TYPE)
- init = convert_from_reference (init);
-#endif
- expand_assignment (exp, init, 0, 0);
- if (exp == DECL_RESULT (current_function_decl))
- {
- /* Failing this assertion means that the return value
- from receives multiple initializations. */
- my_friendly_assert (DECL_INITIAL (exp) == NULL_TREE
- || DECL_INITIAL (exp) == error_mark_node,
- 212);
- DECL_INITIAL (exp) = init;
- }
- return;
- }
- else if (init_type == type
- && TREE_CODE (init) == COND_EXPR)
- {
- /* Push value to be initialized into the cond, where possible.
- Avoid spurious warning messages when initializing the
- result of this function. */
- TREE_OPERAND (init, 1)
- = build_modify_expr (exp, INIT_EXPR, TREE_OPERAND (init, 1));
- if (exp == DECL_RESULT (current_function_decl))
- DECL_INITIAL (exp) = NULL_TREE;
- TREE_OPERAND (init, 2)
- = build_modify_expr (exp, INIT_EXPR, TREE_OPERAND (init, 2));
- if (exp == DECL_RESULT (current_function_decl))
- DECL_INITIAL (exp) = init;
- TREE_SIDE_EFFECTS (init) = 1;
- expand_expr (init, const0_rtx, VOIDmode, 0);
- free_temp_slots ();
- return;
- }
- }
-
- /* We did not know what we were initializing before. Now we do. */
- if (TREE_CODE (init) == TARGET_EXPR)
- {
- tree tmp = TREE_OPERAND (TREE_OPERAND (init, 1), 1);
-
- if (TREE_CODE (TREE_VALUE (tmp)) == NOP_EXPR
- && TREE_OPERAND (TREE_VALUE (tmp), 0) == integer_zero_node)
- {
- /* In order for this to work for RESULT_DECLs, if their
- type has a constructor, then they must be BLKmode
- so that they will be meaningfully addressable. */
- tree arg = build_unary_op (ADDR_EXPR, exp, 0);
- init = TREE_OPERAND (init, 1);
- init = build (CALL_EXPR, build_pointer_type (TREE_TYPE (init)),
- TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), 0);
- TREE_SIDE_EFFECTS (init) = 1;
- TREE_VALUE (TREE_OPERAND (init, 1))
- = convert_pointer_to (TREE_TYPE (TREE_TYPE (TREE_VALUE (tmp))), arg);
-
- if (alias_this)
- {
- expand_assignment (current_function_decl, init, 0, 0);
- return;
- }
- if (exp == DECL_RESULT (current_function_decl))
- {
- if (DECL_INITIAL (DECL_RESULT (current_function_decl)))
- fatal ("return value from function receives multiple initializations");
- DECL_INITIAL (exp) = init;
- }
- expand_expr_stmt (init);
- return;
- }
- }
-
- if (TREE_CODE (exp) == VAR_DECL
- && TREE_CODE (init) == CONSTRUCTOR
- && TREE_HAS_CONSTRUCTOR (init))
- {
- tree t = store_init_value (exp, init);
- if (!t)
- {
- expand_decl_init (exp);
- return;
- }
- t = build (INIT_EXPR, type, exp, init);
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr_stmt (t);
- return;
- }
-
- /* Handle this case: when calling a constructor: xyzzy foo(bar);
- which really means: xyzzy foo = bar; Ugh!
-
- More useful for this case: xyzzy *foo = new xyzzy (bar); */
-
- if (! TYPE_NEEDS_CONSTRUCTING (type) && ! IS_AGGR_TYPE (type))
- {
- if (init_list && TREE_CHAIN (init_list))
- {
- warning ("initializer list being treated as compound expression");
- init = convert (type, build_compound_expr (init_list));
- if (init == error_mark_node)
- return;
- }
-
- expand_assignment (exp, init, 0, 0);
-
- return;
- }
- /* See whether we can go through a type conversion operator.
- This wins over going through a non-existent constructor. If
- there is a constructor, it is ambiguous. */
- if (TREE_CODE (init) != TREE_LIST)
- {
- tree ttype = TREE_CODE (init_type) == REFERENCE_TYPE
- ? TREE_TYPE (init_type) : init_type;
-
- if (ttype != type && IS_AGGR_TYPE (ttype))
- {
- tree rval = build_type_conversion (CONVERT_EXPR, type, init, 0);
-
- if (rval)
- {
- /* See if there is a constructor for``type'' that takes a
- ``ttype''-typed object. */
- tree parms = build_tree_list (NULL_TREE, init);
- tree as_cons = NULL_TREE;
- if (TYPE_HAS_CONSTRUCTOR (type))
- as_cons = build_method_call (exp, constructor_name_full (type),
- parms, binfo,
- LOOKUP_SPECULATIVELY|LOOKUP_NO_CONVERSION);
- if (as_cons != NULL_TREE && as_cons != error_mark_node)
- /* ANSI C++ June 5 1992 WP 12.3.2.6.1 */
- cp_error ("ambiguity between conversion to `%T' and constructor",
- type);
- else
- expand_assignment (exp, rval, 0, 0);
- return;
- }
- }
- }
- }
-
- /* Handle default copy constructors here, does not matter if there is
- a constructor or not. */
- if (type == init_type && IS_AGGR_TYPE (type)
- && init && TREE_CODE (init) != TREE_LIST)
- expand_default_init (binfo, true_exp, exp, type, init, alias_this, flags);
- /* Not sure why this is here... */
- else if (TYPE_HAS_CONSTRUCTOR (type))
- expand_default_init (binfo, true_exp, exp, type, init, alias_this, flags);
- else if (TREE_CODE (type) == ARRAY_TYPE)
- {
- if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (type)))
- expand_vec_init (exp, exp, array_type_nelts (type), init, 0);
- else if (TYPE_VIRTUAL_P (TREE_TYPE (type)))
- sorry ("arrays of objects with virtual functions but no constructors");
- }
- else
- expand_recursive_init (binfo, true_exp, exp, init,
- CLASSTYPE_BASE_INIT_LIST (type), alias_this);
-}
-
-/* A pointer which holds the initializer. First call to
- expand_aggr_init gets this value pointed to, and sets it to init_null. */
-static tree *init_ptr, init_null;
-
-/* Subroutine of expand_recursive_init:
-
- ADDR is the address of the expression being initialized.
- INIT_LIST is the cons-list of initializations to be performed.
- ALIAS_THIS is its same, lovable self. */
-static void
-expand_recursive_init_1 (binfo, true_exp, addr, init_list, alias_this)
- tree binfo, true_exp, addr;
- tree init_list;
- int alias_this;
-{
- while (init_list)
+ if (init && TREE_CODE (exp) == VAR_DECL
+ && TREE_CODE (init) == CONSTRUCTOR
+ && TREE_HAS_CONSTRUCTOR (init))
{
- if (TREE_PURPOSE (init_list))
- {
- if (TREE_CODE (TREE_PURPOSE (init_list)) == FIELD_DECL)
- {
- tree member = TREE_PURPOSE (init_list);
- tree subexp = build_indirect_ref (convert_pointer_to (TREE_VALUE (init_list), addr), NULL_PTR);
- tree member_base = build (COMPONENT_REF, TREE_TYPE (member), subexp, member);
- if (IS_AGGR_TYPE (TREE_TYPE (member)))
- expand_aggr_init (member_base, DECL_INITIAL (member), 0, 0);
- else if (TREE_CODE (TREE_TYPE (member)) == ARRAY_TYPE
- && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (member)))
- {
- member_base = save_expr (default_conversion (member_base));
- expand_vec_init (member, member_base,
- array_type_nelts (TREE_TYPE (member)),
- DECL_INITIAL (member), 0);
- }
- else
- expand_expr_stmt (build_modify_expr (member_base, INIT_EXPR, DECL_INITIAL (member)));
- }
- else if (TREE_CODE (TREE_PURPOSE (init_list)) == TREE_LIST)
- {
- expand_recursive_init_1 (binfo, true_exp, addr, TREE_PURPOSE (init_list), alias_this);
- expand_recursive_init_1 (binfo, true_exp, addr, TREE_VALUE (init_list), alias_this);
- }
- else if (TREE_CODE (TREE_PURPOSE (init_list)) == ERROR_MARK)
- {
- /* Only initialize the virtual function tables if we
- are initializing the ultimate users of those vtables. */
- if (TREE_VALUE (init_list))
- {
- /* We have to ensure that the first argment to
- expand_virtual_init is in binfo's hierarchy. */
- /* Is it the case that this is exactly the right binfo? */
- /* If it is ok, then fixup expand_virtual_init, to make
- it much simpler. */
- expand_virtual_init (get_binfo (TREE_VALUE (init_list), binfo, 0),
- addr);
- if (TREE_VALUE (init_list) == binfo
- && TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
- expand_indirect_vtbls_init (binfo, true_exp, addr, 1);
- }
- }
- else
- my_friendly_abort (49);
- }
- else if (TREE_VALUE (init_list)
- && TREE_CODE (TREE_VALUE (init_list)) == TREE_VEC)
+ tree t = store_init_value (exp, init);
+ if (!t)
{
- tree subexp = build_indirect_ref (convert_pointer_to (TREE_VALUE (init_list), addr), NULL_PTR);
- expand_aggr_init_1 (binfo, true_exp, subexp, *init_ptr,
- alias_this && BINFO_OFFSET_ZEROP (TREE_VALUE (init_list)),
- LOOKUP_COMPLAIN);
-
- /* INIT_PTR is used up. */
- init_ptr = &init_null;
+ expand_decl_init (exp);
+ return;
}
- else
- my_friendly_abort (50);
- init_list = TREE_CHAIN (init_list);
- }
-}
-
-/* Initialize EXP with INIT. Type EXP does not have a constructor,
- but it has a baseclass with a constructor or a virtual function
- table which needs initializing.
-
- INIT_LIST is a cons-list describing what parts of EXP actually
- need to be initialized. INIT is given to the *unique*, first
- constructor within INIT_LIST. If there are multiple first
- constructors, such as with multiple inheritance, INIT must
- be zero or an ambiguity error is reported.
-
- ALIAS_THIS is passed from `expand_aggr_init'. See comments
- there. */
-
-static void
-expand_recursive_init (binfo, true_exp, exp, init, init_list, alias_this)
- tree binfo, true_exp, exp, init;
- tree init_list;
- int alias_this;
-{
- tree *old_init_ptr = init_ptr;
- tree addr = build_unary_op (ADDR_EXPR, exp, 0);
- init_ptr = &init;
-
- if (true_exp == exp && TYPE_USES_VIRTUAL_BASECLASSES (BINFO_TYPE (binfo)))
- {
- expand_aggr_vbase_init (binfo, exp, addr, init_list);
- expand_indirect_vtbls_init (binfo, true_exp, addr, 1);
+ t = build (INIT_EXPR, type, exp, init);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr_stmt (t);
+ return;
}
- expand_recursive_init_1 (binfo, true_exp, addr, init_list, alias_this);
-
- if (*init_ptr)
- {
- tree type = TREE_TYPE (exp);
- if (TREE_CODE (type) == REFERENCE_TYPE)
- type = TREE_TYPE (type);
- if (IS_AGGR_TYPE (type))
- cp_error ("unexpected argument to constructor `%T'", type);
- else
- error ("unexpected argument to constructor");
- }
- init_ptr = old_init_ptr;
+ /* We know that expand_default_init can handle everything we want
+ at this point. */
+ expand_default_init (binfo, true_exp, exp, init, alias_this, flags);
}
/* Report an error if NAME is not the name of a user-defined,
aggregate type. If OR_ELSE is nonzero, give an error message. */
+
int
is_aggr_typedef (name, or_else)
tree name;
@@ -1681,7 +1288,30 @@ is_aggr_typedef (name, or_else)
}
if (! IS_AGGR_TYPE (type)
- && TREE_CODE (type) != TEMPLATE_TYPE_PARM)
+ && TREE_CODE (type) != TEMPLATE_TYPE_PARM
+ && TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM)
+ {
+ if (or_else)
+ cp_error ("`%T' is not an aggregate type", type);
+ return 0;
+ }
+ return 1;
+}
+
+/* Report an error if TYPE is not a user-defined, aggregate type. If
+ OR_ELSE is nonzero, give an error message. */
+
+int
+is_aggr_type (type, or_else)
+ tree type;
+ int or_else;
+{
+ if (type == error_mark_node)
+ return 0;
+
+ if (! IS_AGGR_TYPE (type)
+ && TREE_CODE (type) != TEMPLATE_TYPE_PARM
+ && TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM)
{
if (or_else)
cp_error ("`%T' is not an aggregate type", type);
@@ -1691,6 +1321,7 @@ is_aggr_typedef (name, or_else)
}
/* Like is_aggr_typedef, but returns typedef if successful. */
+
tree
get_aggr_from_typedef (name, or_else)
tree name;
@@ -1711,7 +1342,8 @@ get_aggr_from_typedef (name, or_else)
}
if (! IS_AGGR_TYPE (type)
- && TREE_CODE (type) != TEMPLATE_TYPE_PARM)
+ && TREE_CODE (type) != TEMPLATE_TYPE_PARM
+ && TREE_CODE (type) != TEMPLATE_TEMPLATE_PARM)
{
if (or_else)
cp_error ("type `%T' is of non-aggregate type", type);
@@ -1737,40 +1369,59 @@ get_type_value (name)
/* This code could just as well go in `class.c', but is placed here for
modularity. */
-/* For an expression of the form CNAME :: NAME (PARMLIST), build
+/* For an expression of the form TYPE :: NAME (PARMLIST), build
the appropriate function call. */
+
tree
-build_member_call (cname, name, parmlist)
- tree cname, name, parmlist;
+build_member_call (type, name, parmlist)
+ tree type, name, parmlist;
{
- tree type, t;
- tree method_name = name;
+ tree t;
+ tree method_name;
int dtor = 0;
int dont_use_this = 0;
tree basetype_path, decl;
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR
+ && TREE_CODE (type) == NAMESPACE_DECL)
+ {
+ /* 'name' already refers to the decls from the namespace, since we
+ hit do_identifier for template_ids. */
+ my_friendly_assert (is_overloaded_fn (TREE_OPERAND (name, 0)), 980519);
+ return build_x_function_call (name, parmlist, current_class_ref);
+ }
+
+ if (type == std_node)
+ return build_x_function_call (do_scoped_id (name, 0), parmlist,
+ current_class_ref);
+ if (TREE_CODE (type) == NAMESPACE_DECL)
+ return build_x_function_call (lookup_namespace_name (type, name),
+ parmlist, current_class_ref);
+
+ if (TREE_CODE (name) != TEMPLATE_ID_EXPR)
+ method_name = name;
+ else
+ method_name = TREE_OPERAND (name, 0);
+
if (TREE_CODE (method_name) == BIT_NOT_EXPR)
{
method_name = TREE_OPERAND (method_name, 0);
dtor = 1;
}
- if (TREE_CODE (cname) == SCOPE_REF)
- cname = resolve_scope_to_name (NULL_TREE, cname);
-
/* This shouldn't be here, and build_member_call shouldn't appear in
parse.y! (mrs) */
- if (cname && get_aggr_from_typedef (cname, 0) == 0
- && TREE_CODE (cname) == IDENTIFIER_NODE)
+ if (type && TREE_CODE (type) == IDENTIFIER_NODE
+ && get_aggr_from_typedef (type, 0) == 0)
{
- tree ns = lookup_name (cname, 0);
+ tree ns = lookup_name (type, 0);
if (ns && TREE_CODE (ns) == NAMESPACE_DECL)
{
- return build_x_function_call (build_offset_ref (cname, name), parmlist, current_class_decl);
+ return build_x_function_call (build_offset_ref (type, name), parmlist, current_class_ref);
}
}
- if (cname == NULL_TREE || ! (type = get_aggr_from_typedef (cname, 1)))
+ if (type == NULL_TREE || ! is_aggr_type (type, 1))
return error_mark_node;
/* An operator we did not like. */
@@ -1779,12 +1430,6 @@ build_member_call (cname, name, parmlist)
if (dtor)
{
-#if 0
- /* Everything can explicitly call a destructor; see 12.4 */
- if (! TYPE_HAS_DESTRUCTOR (type))
- cp_error ("type `%#T' does not have a destructor", type);
- else
-#endif
cp_error ("cannot call destructor `%T::~%T' without object", type,
method_name);
return error_mark_node;
@@ -1801,14 +1446,14 @@ build_member_call (cname, name, parmlist)
basetype_path = TYPE_BINFO (type);
decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
}
- else if (current_class_decl == 0)
+ else if (current_class_ptr == 0)
{
dont_use_this = 1;
decl = build1 (NOP_EXPR, build_pointer_type (type), error_mark_node);
}
else
{
- tree olddecl = current_class_decl;
+ tree olddecl = current_class_ptr;
tree oldtype = TREE_TYPE (TREE_TYPE (olddecl));
if (oldtype != type)
{
@@ -1825,8 +1470,11 @@ build_member_call (cname, name, parmlist)
if (method_name == constructor_name (type)
|| method_name == constructor_name_full (type))
return build_functional_cast (type, parmlist);
- if (t = lookup_fnfields (basetype_path, method_name, 0))
- return build_method_call (decl, method_name, parmlist, basetype_path,
+ if ((t = lookup_fnfields (basetype_path, method_name, 0)))
+ return build_method_call (decl,
+ TREE_CODE (name) == TEMPLATE_ID_EXPR
+ ? name : method_name,
+ parmlist, basetype_path,
LOOKUP_NORMAL|LOOKUP_NONVIRTUAL);
if (TREE_CODE (name) == IDENTIFIER_NODE
&& ((t = lookup_field (TYPE_BINFO (type), name, 1, 0))))
@@ -1849,9 +1497,9 @@ build_member_call (cname, name, parmlist)
cp_error ("invalid use of member `%D'", t);
return error_mark_node;
}
- if (TYPE_LANG_SPECIFIC (TREE_TYPE (decl))
- && TYPE_OVERLOADS_CALL_EXPR (TREE_TYPE (decl)))
- return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, decl, parmlist, NULL_TREE);
+ if (TYPE_LANG_SPECIFIC (TREE_TYPE (decl)))
+ return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, decl,
+ parmlist, NULL_TREE);
return build_function_call (decl, parmlist);
}
else
@@ -1863,54 +1511,77 @@ build_member_call (cname, name, parmlist)
/* Build a reference to a member of an aggregate. This is not a
C++ `&', but really something which can have its address taken,
- and then act as a pointer to member, for example CNAME :: FIELD
- can have its address taken by saying & CNAME :: FIELD.
+ and then act as a pointer to member, for example TYPE :: FIELD
+ can have its address taken by saying & TYPE :: FIELD.
@@ Prints out lousy diagnostics for operator <typename>
@@ fields.
@@ This function should be rewritten and placed in search.c. */
+
tree
-build_offset_ref (cname, name)
- tree cname, name;
+build_offset_ref (type, name)
+ tree type, name;
{
- tree decl, type, fnfields, fields, t = error_mark_node;
- tree basetypes = NULL_TREE;
- int dtor = 0;
+ tree decl, fnfields, fields, t = error_mark_node;
+ tree basebinfo = NULL_TREE;
+ tree orig_name = name;
- if (TREE_CODE (cname) == SCOPE_REF)
- cname = resolve_scope_to_name (NULL_TREE, cname);
+ /* class templates can come in as TEMPLATE_DECLs here. */
+ if (TREE_CODE (name) == TEMPLATE_DECL)
+ return name;
+
+ if (type == std_node)
+ return do_scoped_id (name, 0);
+
+ if (processing_template_decl || uses_template_parms (type))
+ return build_min_nt (SCOPE_REF, type, name);
/* Handle namespace names fully here. */
- if (TREE_CODE (cname) == IDENTIFIER_NODE
- && get_aggr_from_typedef (cname, 0) == 0)
+ if (TREE_CODE (type) == NAMESPACE_DECL)
{
- tree ns = lookup_name (cname, 0);
- tree val;
- if (ns && TREE_CODE (ns) == NAMESPACE_DECL)
+ t = lookup_namespace_name (type, name);
+ if (! type_unknown_p (t))
{
- val = lookup_namespace_name (ns, name);
- if (val)
- return val;
- cp_error ("namespace `%D' has no member named `%D'", ns, name);
- return error_mark_node;
+ mark_used (t);
+ t = convert_from_reference (t);
}
+ return t;
}
- if (cname == NULL_TREE || ! is_aggr_typedef (cname, 1))
+ if (type == NULL_TREE || ! is_aggr_type (type, 1))
return error_mark_node;
- type = IDENTIFIER_TYPE_VALUE (cname);
+ if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
+ {
+ /* If the NAME is a TEMPLATE_ID_EXPR, we are looking at
+ something like `a.template f<int>' or the like. For the most
+ part, we treat this just like a.f. We do remember, however,
+ the template-id that was used. */
+ name = TREE_OPERAND (orig_name, 0);
+ my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 0);
+ }
if (TREE_CODE (name) == BIT_NOT_EXPR)
{
- dtor = 1;
- name = TREE_OPERAND (name, 0);
+ if (! check_dtor_name (type, name))
+ cp_error ("qualified type `%T' does not match destructor name `~%T'",
+ type, TREE_OPERAND (name, 0));
+ name = dtor_identifier;
}
+#if 0
+ /* I think this is wrong, but the draft is unclear. --jason 6/15/98 */
+ else if (name == constructor_name_full (type)
+ || name == constructor_name (type))
+ name = ctor_identifier;
+#endif
- if (TYPE_SIZE (type) == 0)
+ if (TYPE_SIZE (complete_type (type)) == 0)
{
- t = IDENTIFIER_CLASS_VALUE (name);
+ if (type == current_class_type)
+ t = IDENTIFIER_CLASS_VALUE (name);
+ else
+ t = NULL_TREE;
if (t == 0)
{
cp_error ("incomplete type `%T' does not have member `%D'", type,
@@ -1920,7 +1591,7 @@ build_offset_ref (cname, name)
if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == VAR_DECL
|| TREE_CODE (t) == CONST_DECL)
{
- TREE_USED (t) = 1;
+ mark_used (t);
return t;
}
if (TREE_CODE (t) == FIELD_DECL)
@@ -1932,125 +1603,104 @@ build_offset_ref (cname, name)
return error_mark_node;
}
-#if 0
- if (TREE_CODE (name) == TYPE_EXPR)
- /* Pass a TYPE_DECL to build_component_type_expr. */
- return build_component_type_expr (TYPE_NAME (TREE_TYPE (cname)),
- name, NULL_TREE, 1);
-#endif
-
if (current_class_type == 0
- || get_base_distance (type, current_class_type, 0, &basetypes) == -1)
+ || get_base_distance (type, current_class_type, 0, &basebinfo) == -1)
{
- basetypes = TYPE_BINFO (type);
- decl = build1 (NOP_EXPR,
- IDENTIFIER_TYPE_VALUE (cname),
- error_mark_node);
+ basebinfo = TYPE_BINFO (type);
+ decl = build1 (NOP_EXPR, type, error_mark_node);
}
- else if (current_class_decl == 0)
- decl = build1 (NOP_EXPR, IDENTIFIER_TYPE_VALUE (cname),
- error_mark_node);
+ else if (current_class_ptr == 0)
+ decl = build1 (NOP_EXPR, type, error_mark_node);
else
- decl = C_C_D;
+ decl = current_class_ref;
- fnfields = lookup_fnfields (basetypes, name, 1);
- fields = lookup_field (basetypes, name, 0, 0);
+ fnfields = lookup_fnfields (basebinfo, name, 1);
+ fields = lookup_field (basebinfo, name, 0, 0);
if (fields == error_mark_node || fnfields == error_mark_node)
return error_mark_node;
/* A lot of this logic is now handled in lookup_field and
- lookup_fnfield. */
+ lookup_fnfield. */
if (fnfields)
{
- basetypes = TREE_PURPOSE (fnfields);
+ extern int flag_save_memoized_contexts;
/* Go from the TREE_BASELINK to the member function info. */
t = TREE_VALUE (fnfields);
- if (fields)
+ if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
{
- if (DECL_FIELD_CONTEXT (fields) == DECL_FIELD_CONTEXT (t))
+ /* The FNFIELDS are going to contain functions that aren't
+ necessarily templates, and templates that don't
+ necessarily match the explicit template parameters. We
+ save all the functions, and the explicit parameters, and
+ then figure out exactly what to instantiate with what
+ arguments in instantiate_type. */
+
+ if (TREE_CODE (t) != OVERLOAD)
+ /* The code in instantiate_type which will process this
+ expects to encounter OVERLOADs, not raw functions. */
+ t = ovl_cons (t, NULL_TREE);
+
+ return build (OFFSET_REF,
+ build_offset_type (type, unknown_type_node),
+ decl,
+ build (TEMPLATE_ID_EXPR,
+ TREE_TYPE (t),
+ t,
+ TREE_OPERAND (orig_name, 1)));
+ }
+
+ if (!really_overloaded_fn (t))
+ {
+ tree access;
+
+ /* Get rid of a potential OVERLOAD around it */
+ t = OVL_CURRENT (t);
+
+ /* unique functions are handled easily. */
+ basebinfo = TREE_PURPOSE (fnfields);
+ access = compute_access (basebinfo, t);
+ if (access == access_protected_node)
{
- error ("ambiguous member reference: member `%s' defined as both field and function",
- IDENTIFIER_POINTER (name));
+ cp_error_at ("member function `%#D' is protected", t);
+ error ("in this context");
return error_mark_node;
}
- if (UNIQUELY_DERIVED_FROM_P (DECL_FIELD_CONTEXT (fields), DECL_FIELD_CONTEXT (t)))
- ;
- else if (UNIQUELY_DERIVED_FROM_P (DECL_FIELD_CONTEXT (t), DECL_FIELD_CONTEXT (fields)))
- t = fields;
- else
+ if (access == access_private_node)
{
- error ("ambiguous member reference: member `%s' derives from distinct classes in multiple inheritance lattice");
+ cp_error_at ("member function `%#D' is private", t);
+ error ("in this context");
return error_mark_node;
}
+ mark_used (t);
+ return build (OFFSET_REF, TREE_TYPE (t), decl, t);
}
- if (t == TREE_VALUE (fnfields))
- {
- extern int flag_save_memoized_contexts;
-
- if (DECL_CHAIN (t) == NULL_TREE || dtor)
- {
- enum access_type access;
+ /* FNFIELDS is most likely allocated on the search_obstack,
+ which will go away after this class scope. If we need
+ to save this value for later (either for memoization
+ or for use as an initializer for a static variable), then
+ do so here.
- /* unique functions are handled easily. */
- unique:
- access = compute_access (basetypes, t);
- if (access == access_protected)
- {
- cp_error_at ("member function `%#D' is protected", t);
- error ("in this context");
- return error_mark_node;
- }
- if (access == access_private)
- {
- cp_error_at ("member function `%#D' is private", t);
- error ("in this context");
- return error_mark_node;
- }
- assemble_external (t);
- return build (OFFSET_REF, TREE_TYPE (t), decl, t);
- }
+ ??? The smart thing to do for the case of saving initializers
+ is to resolve them before we're done with this scope. */
+ if (!TREE_PERMANENT (fnfields)
+ && ((flag_save_memoized_contexts && toplevel_bindings_p ())
+ || ! allocation_temporary_p ()))
+ fnfields = copy_list (fnfields);
- /* overloaded functions may need more work. */
- if (cname == name)
- {
- if (TYPE_HAS_DESTRUCTOR (type)
- && DECL_CHAIN (DECL_CHAIN (t)) == NULL_TREE)
- {
- t = DECL_CHAIN (t);
- goto unique;
- }
- }
- /* FNFIELDS is most likely allocated on the search_obstack,
- which will go away after this class scope. If we need
- to save this value for later (either for memoization
- or for use as an initializer for a static variable), then
- do so here.
-
- ??? The smart thing to do for the case of saving initializers
- is to resolve them before we're done with this scope. */
- if (!TREE_PERMANENT (fnfields)
- && ((flag_save_memoized_contexts && global_bindings_p ())
- || ! allocation_temporary_p ()))
- fnfields = copy_list (fnfields);
-
- for (t = TREE_VALUE (fnfields); t; t = DECL_CHAIN (t))
- assemble_external (t);
-
- t = build_tree_list (error_mark_node, fnfields);
- TREE_TYPE (t) = build_offset_type (type, unknown_type_node);
- return t;
- }
+ t = build_tree_list (error_mark_node, fnfields);
+ TREE_TYPE (t) = build_offset_type (type, unknown_type_node);
+ return t;
}
/* Now that we know we are looking for a field, see if we
have access to that field. Lookup_field will give us the
error message. */
- t = lookup_field (basetypes, name, 1, 0);
+ t = lookup_field (basebinfo, name, 1, 0);
if (t == error_mark_node)
return error_mark_node;
@@ -2070,9 +1720,8 @@ build_offset_ref (cname, name)
values can be returned without further ado. */
if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == CONST_DECL)
{
- assemble_external (t);
- TREE_USED (t) = 1;
- return t;
+ mark_used (t);
+ return convert_from_reference (t);
}
if (TREE_CODE (t) == FIELD_DECL && DECL_BIT_FIELD (t))
@@ -2082,80 +1731,16 @@ build_offset_ref (cname, name)
}
/* static class functions too. */
- if (TREE_CODE (t) == FUNCTION_DECL && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
+ if (TREE_CODE (t) == FUNCTION_DECL
+ && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
my_friendly_abort (53);
- /* In member functions, the form `cname::name' is no longer
- equivalent to `this->cname::name'. */
+ /* In member functions, the form `type::name' is no longer
+ equivalent to `this->type::name', at least not until
+ resolve_offset_ref. */
return build (OFFSET_REF, build_offset_type (type, TREE_TYPE (t)), decl, t);
}
-/* Given an object EXP and a member function reference MEMBER,
- return the address of the actual member function. */
-tree
-get_member_function (exp_addr_ptr, exp, member)
- tree *exp_addr_ptr;
- tree exp, member;
-{
- tree ctype = TREE_TYPE (exp);
- tree function = save_expr (build_unary_op (ADDR_EXPR, member, 0));
-
- if (TYPE_VIRTUAL_P (ctype)
- || (flag_all_virtual == 1 && TYPE_OVERLOADS_METHOD_CALL_EXPR (ctype)))
- {
- tree e0, e1, e3;
- tree exp_addr;
-
- /* Save away the unadulterated `this' pointer. */
- exp_addr = save_expr (*exp_addr_ptr);
-
- /* Cast function to signed integer. */
- e0 = build1 (NOP_EXPR, integer_type_node, function);
-
- /* There is a hack here that takes advantage of
- twos complement arithmetic, and the fact that
- there are more than one UNITS to the WORD.
- If the high bit is set for the `function',
- then we pretend it is a virtual function,
- and the array indexing will knock this bit
- out the top, leaving a valid index. */
- if (UNITS_PER_WORD <= 1)
- my_friendly_abort (54);
-
- e1 = build (GT_EXPR, boolean_type_node, e0, integer_zero_node);
- e1 = build_compound_expr (tree_cons (NULL_TREE, exp_addr,
- build_tree_list (NULL_TREE, e1)));
- e1 = save_expr (e1);
-
- if (TREE_SIDE_EFFECTS (*exp_addr_ptr))
- {
- exp = build_indirect_ref (exp_addr, NULL_PTR);
- *exp_addr_ptr = exp_addr;
- }
-
- /* This is really hairy: if the function pointer is a pointer
- to a non-virtual member function, then we can't go mucking
- with the `this' pointer (any more than we already have to
- this point). If it is a pointer to a virtual member function,
- then we have to adjust the `this' pointer according to
- what the virtual function table tells us. */
-
- e3 = build_vfn_ref (exp_addr_ptr, exp, e0);
- my_friendly_assert (e3 != error_mark_node, 213);
-
- /* Change this pointer type from `void *' to the
- type it is really supposed to be. */
- TREE_TYPE (e3) = TREE_TYPE (function);
-
- /* If non-virtual, use what we had originally. Otherwise,
- use the value we get from the virtual function table. */
- *exp_addr_ptr = build_conditional_expr (e1, exp_addr, *exp_addr_ptr);
-
- function = build_conditional_expr (e1, function, e3);
- }
- return build_indirect_ref (function, NULL_PTR);
-}
-
/* If a OFFSET_REF made it through to here, then it did
not have its address taken. */
@@ -2169,9 +1754,17 @@ resolve_offset_ref (exp)
tree basetype, addr;
if (TREE_CODE (exp) == TREE_LIST)
- return build_unary_op (ADDR_EXPR, exp, 0);
+ {
+ cp_pedwarn ("assuming & on overloaded member function");
+ return build_unary_op (ADDR_EXPR, exp, 0);
+ }
- if (TREE_CODE (exp) != OFFSET_REF)
+ if (TREE_CODE (exp) == OFFSET_REF)
+ {
+ member = TREE_OPERAND (exp, 1);
+ base = TREE_OPERAND (exp, 0);
+ }
+ else
{
my_friendly_assert (TREE_CODE (type) == OFFSET_TYPE, 214);
if (TYPE_OFFSET_BASETYPE (type) != current_class_type)
@@ -2181,17 +1774,13 @@ resolve_offset_ref (exp)
}
member = exp;
type = TREE_TYPE (type);
- base = C_C_D;
- }
- else
- {
- member = TREE_OPERAND (exp, 1);
- base = TREE_OPERAND (exp, 0);
+ base = current_class_ref;
}
if ((TREE_CODE (member) == VAR_DECL
&& ! TYPE_PTRMEMFUNC_P (TREE_TYPE (member)))
- || TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE)
+ || TREE_CODE (TREE_TYPE (member)) == FUNCTION_TYPE
+ || TREE_CODE (TREE_TYPE (member)) == METHOD_TYPE)
{
/* These were static members. */
if (mark_addressable (member) == 0)
@@ -2199,9 +1788,13 @@ resolve_offset_ref (exp)
return member;
}
+ if (TREE_CODE (TREE_TYPE (member)) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (TREE_TYPE (member))) == METHOD_TYPE)
+ return member;
+
/* Syntax error can cause a member which should
have been seen as static to be grok'd as non-static. */
- if (TREE_CODE (member) == FIELD_DECL && C_C_D == NULL_TREE)
+ if (TREE_CODE (member) == FIELD_DECL && current_class_ref == NULL_TREE)
{
if (TREE_ADDRESSABLE (member) == 0)
{
@@ -2215,37 +1808,38 @@ resolve_offset_ref (exp)
/* The first case is really just a reference to a member of `this'. */
if (TREE_CODE (member) == FIELD_DECL
- && (base == C_C_D
+ && (base == current_class_ref
|| (TREE_CODE (base) == NOP_EXPR
&& TREE_OPERAND (base, 0) == error_mark_node)))
{
- tree basetype_path;
- enum access_type access;
+ tree basetype_path, access;
if (TREE_CODE (exp) == OFFSET_REF && TREE_CODE (type) == OFFSET_TYPE)
basetype = TYPE_OFFSET_BASETYPE (type);
else
basetype = DECL_CONTEXT (member);
- base = current_class_decl;
+ base = current_class_ptr;
if (get_base_distance (basetype, TREE_TYPE (TREE_TYPE (base)), 0, &basetype_path) < 0)
{
error_not_base_type (basetype, TREE_TYPE (TREE_TYPE (base)));
return error_mark_node;
}
- addr = convert_pointer_to (basetype, base);
+ /* Kludge: we need to use basetype_path now, because
+ convert_pointer_to will bash it. */
access = compute_access (basetype_path, member);
- if (access == access_public)
+ addr = convert_pointer_to (basetype, base);
+ if (access == access_public_node)
return build (COMPONENT_REF, TREE_TYPE (member),
build_indirect_ref (addr, NULL_PTR), member);
- if (access == access_protected)
+ if (access == access_protected_node)
{
cp_error_at ("member `%D' is protected", member);
error ("in this context");
return error_mark_node;
}
- if (access == access_private)
+ if (access == access_private_node)
{
cp_error_at ("member `%D' is private", member);
error ("in this context");
@@ -2254,24 +1848,39 @@ resolve_offset_ref (exp)
my_friendly_abort (55);
}
- /* If this is a reference to a member function, then return
- the address of the member function (which may involve going
- through the object's vtable), otherwise, return an expression
- for the dereferenced pointer-to-member construct. */
- addr = build_unary_op (ADDR_EXPR, base, 0);
-
- if (TREE_CODE (TREE_TYPE (member)) == METHOD_TYPE)
+ /* Ensure that we have an object. */
+ if (TREE_CODE (base) == NOP_EXPR
+ && TREE_OPERAND (base, 0) == error_mark_node)
+ addr = error_mark_node;
+ else
{
- basetype = DECL_CLASS_CONTEXT (member);
- addr = convert_pointer_to (basetype, addr);
- return build_unary_op (ADDR_EXPR, get_member_function (&addr, build_indirect_ref (addr, NULL_PTR), member), 0);
+ /* If this is a reference to a member function, then return the
+ address of the member function (which may involve going
+ through the object's vtable), otherwise, return an expression
+ for the dereferenced pointer-to-member construct. */
+ addr = build_unary_op (ADDR_EXPR, base, 0);
}
- else if (TREE_CODE (TREE_TYPE (member)) == OFFSET_TYPE)
+
+ if (TREE_CODE (TREE_TYPE (member)) == OFFSET_TYPE)
{
+ if (addr == error_mark_node)
+ {
+ cp_error ("object missing in `%E'", exp);
+ return error_mark_node;
+ }
+
basetype = TYPE_OFFSET_BASETYPE (TREE_TYPE (member));
addr = convert_pointer_to (basetype, addr);
- member = convert (ptrdiff_type_node,
- build_unary_op (ADDR_EXPR, member, 0));
+ member = cp_convert (ptrdiff_type_node,
+ build_unary_op (ADDR_EXPR, member, 0));
+
+ /* Pointer to data members are offset by one, so that a null
+ pointer with a real value of 0 is distinguishable from an
+ offset of the first member of a structure. */
+ member = build_binary_op (MINUS_EXPR, member,
+ cp_convert (ptrdiff_type_node, integer_one_node),
+ 0);
+
return build1 (INDIRECT_REF, type,
build (PLUS_EXPR, build_pointer_type (type),
addr, member));
@@ -2300,7 +1909,7 @@ decl_constant_value (decl)
&& ! pedantic
#endif /* 0 */
&& DECL_INITIAL (decl) != 0
- && TREE_CODE (DECL_INITIAL (decl)) != ERROR_MARK
+ && DECL_INITIAL (decl) != error_mark_node
/* This is invalid if initial value is not constant.
If it has either a function call, a memory reference,
or a variable, then re-evaluating it could give different results. */
@@ -2318,499 +1927,18 @@ decl_constant_value (decl)
return decl;
}
-/* Friend handling routines. */
-/* Friend data structures:
-
- Lists of friend functions come from TYPE_DECL nodes. Since all
- aggregate types are automatically typedef'd, these nodes are guaranteed
- to exist.
-
- The TREE_PURPOSE of a friend list is the name of the friend,
- and its TREE_VALUE is another list.
-
- For each element of that list, either the TREE_VALUE or the TREE_PURPOSE
- will be filled in, but not both. The TREE_VALUE of that list is an
- individual function which is a friend. The TREE_PURPOSE of that list
- indicates a type in which all functions by that name are friends.
-
- Lists of friend classes come from _TYPE nodes. Love that consistency
- thang. */
-
-int
-is_friend_type (type1, type2)
- tree type1, type2;
-{
- return is_friend (type1, type2);
-}
-
-int
-is_friend (type, supplicant)
- tree type, supplicant;
-{
- int declp;
- register tree list;
-
- if (supplicant == NULL_TREE || type == NULL_TREE)
- return 0;
-
- declp = (TREE_CODE_CLASS (TREE_CODE (supplicant)) == 'd');
-
- if (declp)
- /* It's a function decl. */
- {
- tree list = DECL_FRIENDLIST (TYPE_NAME (type));
- tree name = DECL_NAME (supplicant);
- tree ctype;
-
- if (DECL_FUNCTION_MEMBER_P (supplicant))
- ctype = DECL_CLASS_CONTEXT (supplicant);
- else
- ctype = NULL_TREE;
-
- for (; list ; list = TREE_CHAIN (list))
- {
- if (name == TREE_PURPOSE (list))
- {
- tree friends = TREE_VALUE (list);
- name = DECL_ASSEMBLER_NAME (supplicant);
- for (; friends ; friends = TREE_CHAIN (friends))
- {
- if (ctype == TREE_PURPOSE (friends))
- return 1;
- if (name == DECL_ASSEMBLER_NAME (TREE_VALUE (friends)))
- return 1;
- }
- break;
- }
- }
- }
- else
- /* It's a type. */
- {
- if (type == supplicant)
- return 1;
-
- list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_NAME (type)));
- for (; list ; list = TREE_CHAIN (list))
- if (supplicant == TREE_VALUE (list))
- return 1;
- }
-
- {
- tree context;
-
- if (! declp)
- context = DECL_CONTEXT (TYPE_NAME (supplicant));
- else if (DECL_FUNCTION_MEMBER_P (supplicant))
- context = DECL_CLASS_CONTEXT (supplicant);
- else
- context = NULL_TREE;
-
- if (context)
- return is_friend (type, context);
- }
-
- return 0;
-}
-
-/* Add a new friend to the friends of the aggregate type TYPE.
- DECL is the FUNCTION_DECL of the friend being added. */
-static void
-add_friend (type, decl)
- tree type, decl;
-{
- tree typedecl = TYPE_NAME (type);
- tree list = DECL_FRIENDLIST (typedecl);
- tree name = DECL_NAME (decl);
-
- while (list)
- {
- if (name == TREE_PURPOSE (list))
- {
- tree friends = TREE_VALUE (list);
- for (; friends ; friends = TREE_CHAIN (friends))
- {
- if (decl == TREE_VALUE (friends))
- {
- cp_warning ("`%D' is already a friend of class `%T'",
- decl, type);
- cp_warning_at ("previous friend declaration of `%D'",
- TREE_VALUE (friends));
- return;
- }
- }
- TREE_VALUE (list) = tree_cons (error_mark_node, decl,
- TREE_VALUE (list));
- return;
- }
- list = TREE_CHAIN (list);
- }
- DECL_FRIENDLIST (typedecl)
- = tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
- DECL_FRIENDLIST (typedecl));
- if (DECL_NAME (decl) == ansi_opname[(int) MODIFY_EXPR])
- {
- tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
- TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
- if (parmtypes && TREE_CHAIN (parmtypes))
- {
- tree parmtype = TREE_VALUE (TREE_CHAIN (parmtypes));
- if (TREE_CODE (parmtype) == REFERENCE_TYPE
- && TREE_TYPE (parmtypes) == TREE_TYPE (typedecl))
- TYPE_HAS_ASSIGN_REF (TREE_TYPE (typedecl)) = 1;
- }
- }
-}
-
-/* Declare that every member function NAME in FRIEND_TYPE
- (which may be NULL_TREE) is a friend of type TYPE. */
-static void
-add_friends (type, name, friend_type)
- tree type, name, friend_type;
-{
- tree typedecl = TYPE_NAME (type);
- tree list = DECL_FRIENDLIST (typedecl);
-
- while (list)
- {
- if (name == TREE_PURPOSE (list))
- {
- tree friends = TREE_VALUE (list);
- while (friends && TREE_PURPOSE (friends) != friend_type)
- friends = TREE_CHAIN (friends);
- if (friends)
- if (friend_type)
- warning ("method `%s::%s' is already a friend of class",
- TYPE_NAME_STRING (friend_type),
- IDENTIFIER_POINTER (name));
- else
- warning ("function `%s' is already a friend of class `%s'",
- IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (DECL_NAME (typedecl)));
- else
- TREE_VALUE (list) = tree_cons (friend_type, NULL_TREE,
- TREE_VALUE (list));
- return;
- }
- list = TREE_CHAIN (list);
- }
- DECL_FRIENDLIST (typedecl) =
- tree_cons (name,
- build_tree_list (friend_type, NULL_TREE),
- DECL_FRIENDLIST (typedecl));
- if (! strncmp (IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]),
- strlen (IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]))))
- {
- TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
- sorry ("declaring \"friend operator =\" will not find \"operator = (X&)\" if it exists");
- }
-}
-
-/* Set up a cross reference so that type TYPE will make member function
- CTYPE::DECL a friend when CTYPE is finally defined. For more than
- one, set up a cross reference so that functions with the name DECL
- and type CTYPE know that they are friends of TYPE. */
-static void
-xref_friend (type, decl, ctype)
- tree type, decl, ctype;
-{
- tree friend_decl = TYPE_NAME (ctype);
-#if 0
- tree typedecl = TYPE_NAME (type);
- tree t = tree_cons (NULL_TREE, ctype, DECL_UNDEFINED_FRIENDS (typedecl));
-
- DECL_UNDEFINED_FRIENDS (typedecl) = t;
-#else
- tree t = 0;
-#endif
- SET_DECL_WAITING_FRIENDS (friend_decl,
- tree_cons (type, t,
- DECL_WAITING_FRIENDS (friend_decl)));
- TREE_TYPE (DECL_WAITING_FRIENDS (friend_decl)) = decl;
-}
-
-/* Make FRIEND_TYPE a friend class to TYPE. If FRIEND_TYPE has already
- been defined, we make all of its member functions friends of
- TYPE. If not, we make it a pending friend, which can later be added
- when its definition is seen. If a type is defined, then its TYPE_DECL's
- DECL_UNDEFINED_FRIENDS contains a (possibly empty) list of friend
- classes that are not defined. If a type has not yet been defined,
- then the DECL_WAITING_FRIENDS contains a list of types
- waiting to make it their friend. Note that these two can both
- be in use at the same time! */
-void
-make_friend_class (type, friend_type)
- tree type, friend_type;
-{
- tree classes;
-
- if (IS_SIGNATURE (type))
- {
- error ("`friend' declaration in signature definition");
- return;
- }
- if (IS_SIGNATURE (friend_type))
- {
- error ("signature type `%s' declared `friend'",
- IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (friend_type))));
- return;
- }
- if (type == friend_type)
- {
- pedwarn ("class `%s' is implicitly friends with itself",
- TYPE_NAME_STRING (type));
- return;
- }
-
- GNU_xref_hier (TYPE_NAME_STRING (type),
- TYPE_NAME_STRING (friend_type), 0, 0, 1);
-
- classes = CLASSTYPE_FRIEND_CLASSES (type);
- while (classes && TREE_VALUE (classes) != friend_type)
- classes = TREE_CHAIN (classes);
- if (classes)
- warning ("class `%s' is already friends with class `%s'",
- TYPE_NAME_STRING (TREE_VALUE (classes)), TYPE_NAME_STRING (type));
- else
- {
- CLASSTYPE_FRIEND_CLASSES (type)
- = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
- }
-}
-
-/* Main friend processor. This is large, and for modularity purposes,
- has been removed from grokdeclarator. It returns `void_type_node'
- to indicate that something happened, though a FIELD_DECL is
- not returned.
-
- CTYPE is the class this friend belongs to.
-
- DECLARATOR is the name of the friend.
-
- DECL is the FUNCTION_DECL that the friend is.
-
- In case we are parsing a friend which is part of an inline
- definition, we will need to store PARM_DECL chain that comes
- with it into the DECL_ARGUMENTS slot of the FUNCTION_DECL.
-
- FLAGS is just used for `grokclassfn'.
-
- QUALS say what special qualifies should apply to the object
- pointed to by `this'. */
-tree
-do_friend (ctype, declarator, decl, parmdecls, flags, quals)
- tree ctype, declarator, decl, parmdecls;
- enum overload_flags flags;
- tree quals;
-{
- /* Every decl that gets here is a friend of something. */
- DECL_FRIEND_P (decl) = 1;
-
- if (ctype)
- {
- tree cname = TYPE_NAME (ctype);
- if (TREE_CODE (cname) == TYPE_DECL)
- cname = DECL_NAME (cname);
-
- /* A method friend. */
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- if (flags == NO_SPECIAL && ctype && declarator == cname)
- DECL_CONSTRUCTOR_P (decl) = 1;
-
- /* This will set up DECL_ARGUMENTS for us. */
- grokclassfn (ctype, cname, decl, flags, quals);
- if (TYPE_SIZE (ctype) != 0)
- check_classfn (ctype, cname, decl);
-
- if (TREE_TYPE (decl) != error_mark_node)
- {
- if (TYPE_SIZE (ctype))
- {
- /* We don't call pushdecl here yet, or ever on this
- actual FUNCTION_DECL. We must preserve its TREE_CHAIN
- until the end. */
- make_decl_rtl (decl, NULL_PTR, 1);
- add_friend (current_class_type, decl);
- }
- else
- {
- register char *classname
- = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (ctype)));
-
- error ("member declared as friend before type `%s' defined",
- classname);
- }
- }
- }
- else
- {
- /* Possibly a bunch of method friends. */
-
- /* Get the class they belong to. */
- tree ctype = IDENTIFIER_TYPE_VALUE (cname);
-
- /* This class is defined, use its methods now. */
- if (TYPE_SIZE (ctype))
- {
- tree fields = lookup_fnfields (TYPE_BINFO (ctype), declarator, 0);
- if (fields)
- add_friends (current_class_type, declarator, ctype);
- else
- error ("method `%s' is not a member of class `%s'",
- IDENTIFIER_POINTER (declarator),
- IDENTIFIER_POINTER (cname));
- }
- else
- /* Note: DECLARATOR actually has more than one; in this
- case, we're making sure that fns with the name DECLARATOR
- and type CTYPE know they are friends of the current
- class type. */
- xref_friend (current_class_type, declarator, ctype);
- decl = void_type_node;
- }
- }
- else if (TREE_CODE (decl) == FUNCTION_DECL
- && ((IDENTIFIER_LENGTH (declarator) == 4
- && IDENTIFIER_POINTER (declarator)[0] == 'm'
- && ! strcmp (IDENTIFIER_POINTER (declarator), "main"))
- || (IDENTIFIER_LENGTH (declarator) > 10
- && IDENTIFIER_POINTER (declarator)[0] == '_'
- && IDENTIFIER_POINTER (declarator)[1] == '_'
- && strncmp (IDENTIFIER_POINTER (declarator)+2,
- "builtin_", 8) == 0)))
- {
- /* raw "main", and builtin functions never gets overloaded,
- but they can become friends. */
- add_friend (current_class_type, decl);
- DECL_FRIEND_P (decl) = 1;
- decl = void_type_node;
- }
- /* A global friend.
- @@ or possibly a friend from a base class ?!? */
- else if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- /* Friends must all go through the overload machinery,
- even though they may not technically be overloaded.
-
- Note that because classes all wind up being top-level
- in their scope, their friend wind up in top-level scope as well. */
- DECL_ASSEMBLER_NAME (decl)
- = build_decl_overload (declarator, TYPE_ARG_TYPES (TREE_TYPE (decl)),
- TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE);
- DECL_ARGUMENTS (decl) = parmdecls;
- DECL_CLASS_CONTEXT (decl) = current_class_type;
-
- /* We can call pushdecl here, because the TREE_CHAIN of this
- FUNCTION_DECL is not needed for other purposes. */
- decl = pushdecl (decl);
-
- make_decl_rtl (decl, NULL_PTR, 1);
- add_friend (current_class_type, decl);
-
- DECL_FRIEND_P (decl) = 1;
-#if 0
- TREE_OVERLOADED (declarator) = 1;
-#endif
- }
- else
- {
- /* @@ Should be able to ingest later definitions of this function
- before use. */
- tree decl = lookup_name_nonclass (declarator);
- if (decl == NULL_TREE)
- {
- warning ("implicitly declaring `%s' as struct",
- IDENTIFIER_POINTER (declarator));
- decl = xref_tag (record_type_node, declarator, NULL_TREE, 1);
- decl = TYPE_NAME (decl);
- }
-
- /* Allow abbreviated declarations of overloaded functions,
- but not if those functions are really class names. */
- if (TREE_CODE (decl) == TREE_LIST && TREE_TYPE (TREE_PURPOSE (decl)))
- {
- warning ("`friend %s' archaic, use `friend class %s' instead",
- IDENTIFIER_POINTER (declarator),
- IDENTIFIER_POINTER (declarator));
- decl = TREE_TYPE (TREE_PURPOSE (decl));
- }
-
- if (TREE_CODE (decl) == TREE_LIST)
- add_friends (current_class_type, TREE_PURPOSE (decl), NULL_TREE);
- else
- make_friend_class (current_class_type, TREE_TYPE (decl));
- decl = void_type_node;
- }
- return decl;
-}
-
-/* TYPE has now been defined. It may, however, have a number of things
- waiting make make it their friend. We resolve these references
- here. */
-void
-embrace_waiting_friends (type)
- tree type;
-{
- tree decl = TYPE_NAME (type);
- tree waiters;
-
- if (TREE_CODE (decl) != TYPE_DECL)
- return;
-
- for (waiters = DECL_WAITING_FRIENDS (decl); waiters;
- waiters = TREE_CHAIN (waiters))
- {
- tree waiter = TREE_PURPOSE (waiters);
-#if 0
- tree waiter_prev = TREE_VALUE (waiters);
-#endif
- tree decl = TREE_TYPE (waiters);
- tree name = decl ? (TREE_CODE (decl) == IDENTIFIER_NODE
- ? decl : DECL_NAME (decl)) : NULL_TREE;
- if (name)
- {
- /* @@ There may be work to be done since we have not verified
- @@ consistency between original and friend declarations
- @@ of the functions waiting to become friends. */
- tree field = lookup_fnfields (TYPE_BINFO (type), name, 0);
- if (field)
- if (decl == name)
- add_friends (waiter, name, type);
- else
- add_friend (waiter, decl);
- else
- error_with_file_and_line (DECL_SOURCE_FILE (TYPE_NAME (waiter)),
- DECL_SOURCE_LINE (TYPE_NAME (waiter)),
- "no method `%s' defined in class `%s' to be friend",
- IDENTIFIER_POINTER (DECL_NAME (TREE_TYPE (waiters))),
- TYPE_NAME_STRING (type));
- }
- else
- make_friend_class (type, waiter);
-
-#if 0
- if (TREE_CHAIN (waiter_prev))
- TREE_CHAIN (waiter_prev) = TREE_CHAIN (TREE_CHAIN (waiter_prev));
- else
- DECL_UNDEFINED_FRIENDS (TYPE_NAME (waiter)) = NULL_TREE;
-#endif
- }
-}
-
/* Common subroutines of build_new and build_vec_delete. */
/* Common interface for calling "builtin" functions that are not
really builtin. */
-tree
+static tree
build_builtin_call (type, node, arglist)
tree type;
tree node;
tree arglist;
{
- tree rval = build (CALL_EXPR, type, node, arglist, 0);
+ tree rval = build (CALL_EXPR, type, node, arglist, NULL_TREE);
TREE_SIDE_EFFECTS (rval) = 1;
assemble_external (TREE_OPERAND (node, 0));
TREE_USED (TREE_OPERAND (node, 0)) = 1;
@@ -2851,11 +1979,9 @@ build_new (placement, decl, init, use_global_new)
tree decl, init;
int use_global_new;
{
- tree type, true_type, size, rval;
- tree nelts;
- tree alloc_expr, alloc_temp;
+ tree type, rval;
+ tree nelts = NULL_TREE, t;
int has_array = 0;
- enum tree_code code = NEW_EXPR;
tree pending_sizes = NULL_TREE;
@@ -2866,7 +1992,7 @@ build_new (placement, decl, init, use_global_new)
{
tree absdcl = TREE_VALUE (decl);
tree last_absdcl = NULL_TREE;
- int old_immediate_size_expand;
+ int old_immediate_size_expand = 0;
if (current_function_decl
&& DECL_CONSTRUCTOR_P (current_function_decl))
@@ -2903,9 +2029,14 @@ build_new (placement, decl, init, use_global_new)
{
if (this_nelts == NULL_TREE)
error ("new of array type fails to specify size");
+ else if (processing_template_decl)
+ {
+ nelts = this_nelts;
+ absdcl = TREE_OPERAND (absdcl, 0);
+ }
else
{
- this_nelts = save_expr (convert (sizetype, this_nelts));
+ this_nelts = save_expr (cp_convert (sizetype, this_nelts));
absdcl = TREE_OPERAND (absdcl, 0);
if (this_nelts == integer_zero_node)
{
@@ -2925,7 +2056,7 @@ build_new (placement, decl, init, use_global_new)
else
TREE_VALUE (decl) = absdcl;
- type = true_type = groktypename (decl);
+ type = groktypename (decl);
if (! type || type == error_mark_node)
{
immediate_size_expand = old_immediate_size_expand;
@@ -2945,7 +2076,7 @@ build_new (placement, decl, init, use_global_new)
{
/* An aggregate type. */
type = IDENTIFIER_TYPE_VALUE (decl);
- decl = TYPE_NAME (type);
+ decl = TYPE_MAIN_DECL (type);
}
else
{
@@ -2954,18 +2085,29 @@ build_new (placement, decl, init, use_global_new)
my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 215);
type = TREE_TYPE (decl);
}
- true_type = type;
}
else if (TREE_CODE (decl) == TYPE_DECL)
{
type = TREE_TYPE (decl);
- true_type = type;
}
else
{
type = decl;
- true_type = type;
- decl = TYPE_NAME (type);
+ decl = TYPE_MAIN_DECL (type);
+ }
+
+ if (processing_template_decl)
+ {
+ if (has_array)
+ t = min_tree_cons (min_tree_cons (NULL_TREE, type, NULL_TREE),
+ build_min_nt (ARRAY_REF, NULL_TREE, nelts),
+ NULL_TREE);
+ else
+ t = type;
+
+ rval = build_min_nt (NEW_EXPR, placement, t, init);
+ NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
+ return rval;
}
/* ``A reference cannot be created by the new operator. A reference
@@ -2974,7 +2116,7 @@ build_new (placement, decl, init, use_global_new)
if (TREE_CODE (type) == REFERENCE_TYPE)
{
error ("new cannot be applied to a reference type");
- type = true_type = TREE_TYPE (type);
+ type = TREE_TYPE (type);
}
if (TREE_CODE (type) == FUNCTION_TYPE)
@@ -2990,9 +2132,58 @@ build_new (placement, decl, init, use_global_new)
{
nelts = array_type_nelts_top (type);
has_array = 1;
- type = true_type = TREE_TYPE (type);
+ type = TREE_TYPE (type);
}
+ if (has_array)
+ t = build_nt (ARRAY_REF, type, nelts);
+ else
+ t = type;
+
+ rval = build (NEW_EXPR, build_pointer_type (type), placement, t, init);
+ NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
+ TREE_SIDE_EFFECTS (rval) = 1;
+
+ /* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain. */
+ rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval);
+ TREE_NO_UNUSED_WARNING (rval) = 1;
+
+ if (pending_sizes)
+ rval = build_compound_expr (chainon (pending_sizes,
+ build_expr_list (NULL_TREE, rval)));
+
+ return rval;
+}
+
+/* Called from cplus_expand_expr when expanding a NEW_EXPR. The return
+ value is immediately handed to expand_expr. */
+
+tree
+build_new_1 (exp)
+ tree exp;
+{
+ tree placement, init;
+ tree type, true_type, size, rval;
+ tree nelts = NULL_TREE;
+ tree alloc_expr, alloc_node = NULL_TREE;
+ int has_array = 0;
+ enum tree_code code = NEW_EXPR;
+ int use_cookie, nothrow, check_new;
+ int use_global_new;
+
+ placement = TREE_OPERAND (exp, 0);
+ type = TREE_OPERAND (exp, 1);
+ init = TREE_OPERAND (exp, 2);
+ use_global_new = NEW_EXPR_USE_GLOBAL (exp);
+
+ if (TREE_CODE (type) == ARRAY_REF)
+ {
+ has_array = 1;
+ nelts = TREE_OPERAND (type, 1);
+ type = TREE_OPERAND (type, 0);
+ }
+ true_type = type;
+
if (TYPE_READONLY (type) || TYPE_VOLATILE (type))
type = TYPE_MAIN_VARIANT (type);
@@ -3004,24 +2195,22 @@ build_new (placement, decl, init, use_global_new)
nelts = build_binary_op (MULT_EXPR, nelts, this_nelts, 1);
true_type = TREE_TYPE (true_type);
}
+
+ if (!complete_type_or_else (true_type))
+ return error_mark_node;
+
if (has_array)
size = fold (build_binary_op (MULT_EXPR, size_in_bytes (true_type),
nelts, 1));
else
size = size_in_bytes (type);
- if (true_type == void_type_node)
+ if (TREE_CODE (true_type) == VOID_TYPE)
{
error ("invalid type `void' for new");
return error_mark_node;
}
- if (TYPE_SIZE (true_type) == 0)
- {
- incomplete_type_error (0, true_type);
- return error_mark_node;
- }
-
if (TYPE_LANG_SPECIFIC (true_type)
&& CLASSTYPE_ABSTRACT_VIRTUALS (true_type))
{
@@ -3035,9 +2224,22 @@ build_new (placement, decl, init, use_global_new)
return error_mark_node;
}
+#if 1
+ /* Get a little extra space to store a couple of things before the new'ed
+ array, if this isn't the default placement new. */
+
+ use_cookie = (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type)
+ && ! (placement && ! TREE_CHAIN (placement)
+ && TREE_TYPE (TREE_VALUE (placement)) == ptr_type_node));
+#else
/* Get a little extra space to store a couple of things before the new'ed
- array. */
- if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type))
+ array, if this is either non-placement new or new (nothrow). */
+
+ use_cookie = (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type)
+ && (! placement || nothrow));
+#endif
+
+ if (use_cookie)
{
tree extra = BI_header_size;
@@ -3045,21 +2247,17 @@ build_new (placement, decl, init, use_global_new)
}
if (has_array)
- code = VEC_NEW_EXPR;
-
- /* Allocate the object. */
- if (! use_global_new && TYPE_LANG_SPECIFIC (true_type)
- && (TYPE_GETS_NEW (true_type) & (1 << has_array)))
- rval = build_opfncall (code, LOOKUP_NORMAL,
- build_pointer_type (true_type), size, placement);
- else if (placement)
{
- rval = build_opfncall (code, LOOKUP_GLOBAL|LOOKUP_COMPLAIN,
- ptr_type_node, size, placement);
- rval = convert (build_pointer_type (true_type), rval);
+ code = VEC_NEW_EXPR;
+
+ if (init && pedantic)
+ cp_pedwarn ("initialization in array new");
}
- else if (! has_array && flag_this_is_variable > 0
- && TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node)
+
+ /* Allocate the object. */
+
+ if (! has_array && ! placement && flag_this_is_variable > 0
+ && TYPE_NEEDS_CONSTRUCTING (true_type) && init != void_type_node)
{
if (init == NULL_TREE || TREE_CODE (init) == TREE_LIST)
rval = NULL_TREE;
@@ -3071,33 +2269,50 @@ build_new (placement, decl, init, use_global_new)
}
else
{
- rval = build_builtin_call (build_pointer_type (true_type),
- has_array ? BIVN : BIN,
- build_tree_list (NULL_TREE, size));
-#if 0
- /* See comment above as to why this is disabled. */
- if (alignment)
- {
- rval = build (PLUS_EXPR, build_pointer_type (true_type), rval,
- alignment);
- rval = build (BIT_AND_EXPR, build_pointer_type (true_type),
- rval, build1 (BIT_NOT_EXPR, integer_type_node,
- alignment));
- }
-#endif
- TREE_CALLS_NEW (rval) = 1;
+ int susp;
+
+ if (flag_exceptions)
+ /* We will use RVAL when generating an exception handler for
+ this new-expression, so we must save it. */
+ susp = suspend_momentary ();
+
+ rval = build_op_new_call
+ (code, true_type, expr_tree_cons (NULL_TREE, size, placement),
+ LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL));
+ rval = cp_convert (build_pointer_type (true_type), rval);
+
+ if (flag_exceptions)
+ resume_momentary (susp);
+ }
+
+ /* unless an allocation function is declared with an empty excep-
+ tion-specification (_except.spec_), throw(), it indicates failure to
+ allocate storage by throwing a bad_alloc exception (clause _except_,
+ _lib.bad.alloc_); it returns a non-null pointer otherwise If the allo-
+ cation function is declared with an empty exception-specification,
+ throw(), it returns null to indicate failure to allocate storage and a
+ non-null pointer otherwise.
+
+ So check for a null exception spec on the op new we just called. */
+
+ nothrow = 0;
+ if (rval)
+ {
+ /* The CALL_EXPR. */
+ tree t = TREE_OPERAND (rval, 0);
+ /* The function. */
+ t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
+ t = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (t));
+
+ if (t && TREE_VALUE (t) == NULL_TREE)
+ nothrow = 1;
}
+ check_new = flag_check_new || nothrow;
- if (flag_check_new && rval)
+ if ((check_new || flag_exceptions) && rval)
{
- /* For array new, we need to make sure that the call to new is
- not expanded as part of the RTL_EXPR for the initialization,
- so we can't just use save_expr here. */
-
- alloc_temp = get_temp_name (TREE_TYPE (rval), 0);
- alloc_expr = build (MODIFY_EXPR, TREE_TYPE (rval), alloc_temp, rval);
- TREE_SIDE_EFFECTS (alloc_expr) = 1;
- rval = alloc_temp;
+ alloc_expr = get_target_expr (rval);
+ alloc_node = rval = TREE_OPERAND (alloc_expr, 0);
}
else
alloc_expr = NULL_TREE;
@@ -3106,25 +2321,25 @@ build_new (placement, decl, init, use_global_new)
sure we have some extra bytes in that case for the BI_header_size
cookies? And how does that interact with the code below? (mrs) */
/* Finish up some magic for new'ed arrays */
- if (has_array && TYPE_VEC_NEW_USES_COOKIE (true_type) && rval != NULL_TREE)
+ if (use_cookie && rval != NULL_TREE)
{
tree extra = BI_header_size;
tree cookie, exp1;
- rval = convert (ptr_type_node, rval); /* convert to void * first */
- rval = convert (string_type_node, rval); /* lets not add void* and ints */
+ rval = convert (string_type_node, rval); /* for ptr arithmetic */
rval = save_expr (build_binary_op (PLUS_EXPR, rval, extra, 1));
/* Store header info. */
- cookie = build_indirect_ref (build (MINUS_EXPR, build_pointer_type (BI_header_type),
+ cookie = build_indirect_ref (build (MINUS_EXPR,
+ build_pointer_type (BI_header_type),
rval, extra), NULL_PTR);
exp1 = build (MODIFY_EXPR, void_type_node,
- build_component_ref (cookie, nc_nelts_field_id, 0, 0),
+ build_component_ref (cookie, nc_nelts_field_id,
+ NULL_TREE, 0),
nelts);
TREE_SIDE_EFFECTS (exp1) = 1;
- rval = convert (build_pointer_type (true_type), rval);
- TREE_CALLS_NEW (rval) = 1;
- TREE_SIDE_EFFECTS (rval) = 1;
- rval = build_compound_expr (tree_cons (NULL_TREE, exp1,
- build_tree_list (NULL_TREE, rval)));
+ rval = cp_convert (build_pointer_type (true_type), rval);
+ rval = build_compound_expr
+ (expr_tree_cons (NULL_TREE, exp1,
+ build_expr_list (NULL_TREE, rval)));
}
if (rval == error_mark_node)
@@ -3163,7 +2378,6 @@ build_new (placement, decl, init, use_global_new)
rval);
TREE_NO_UNUSED_WARNING (rval) = 1;
TREE_SIDE_EFFECTS (rval) = 1;
- TREE_CALLS_NEW (rval) = 1;
}
else if (! has_array)
{
@@ -3175,7 +2389,7 @@ build_new (placement, decl, init, use_global_new)
if (rval && TYPE_USES_VIRTUAL_BASECLASSES (true_type))
{
- init = tree_cons (NULL_TREE, integer_one_node, init);
+ init = expr_tree_cons (NULL_TREE, integer_one_node, init);
flags |= LOOKUP_HAS_IN_CHARGE;
}
@@ -3184,96 +2398,90 @@ build_new (placement, decl, init, use_global_new)
if (newrval && TREE_CODE (TREE_TYPE (newrval)) == POINTER_TYPE)
newrval = build_indirect_ref (newrval, NULL_PTR);
- newrval = build_method_call (newrval, constructor_name_full (true_type),
- init, NULL_TREE, flags);
+ newrval = build_method_call (newrval, ctor_identifier,
+ init, TYPE_BINFO (true_type), flags);
- if (newrval)
- {
- rval = newrval;
- TREE_HAS_CONSTRUCTOR (rval) = 1;
- }
- else
- rval = error_mark_node;
- }
- else if (current_function_decl == NULL_TREE)
- {
- extern tree static_aggregates;
+ if (newrval == NULL_TREE || newrval == error_mark_node)
+ return error_mark_node;
- /* In case of static initialization, SAVE_EXPR is good enough. */
- rval = save_expr (rval);
- rval = copy_to_permanent (rval);
- init = copy_to_permanent (init);
- init = expand_vec_init (decl, rval,
- build_binary_op (MINUS_EXPR, nelts,
- integer_one_node, 1),
- init, 0);
- init = copy_to_permanent (init);
- static_aggregates = perm_tree_cons (init, rval, static_aggregates);
+ rval = newrval;
+ TREE_HAS_CONSTRUCTOR (rval) = 1;
}
else
+ rval = build (VEC_INIT_EXPR, TREE_TYPE (rval),
+ save_expr (rval), init, nelts);
+
+ /* If any part of the object initialization terminates by throwing
+ an exception and the new-expression does not contain a
+ new-placement, then the deallocation function is called to free
+ the memory in which the object was being constructed. */
+ if (flag_exceptions && alloc_expr)
{
- /* Have to wrap this in RTL_EXPR for two cases:
- in base or member initialization and if we
- are a branch of a ?: operator. Since we
- can't easily know the latter, just do it always. */
- tree xval = make_node (RTL_EXPR);
-
- /* If we want to check the value of the allocation expression,
- and the number of elements in the array is not a constant, we
- *must* expand the SAVE_EXPR for nelts in alloc_expr before we
- expand it in the actual initialization. So we need to build up
- an RTL_EXPR for alloc_expr. Sigh. */
- if (alloc_expr && ! TREE_CONSTANT (nelts))
+ enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
+ tree cleanup, fn = NULL_TREE;
+ int flags = LOOKUP_NORMAL | (use_global_new * LOOKUP_GLOBAL);
+
+ /* All cleanups must last longer than normal. */
+ int yes = suspend_momentary ();
+
+ if (placement)
{
- tree xval = make_node (RTL_EXPR);
- rtx rtxval;
- TREE_TYPE (xval) = TREE_TYPE (alloc_expr);
- do_pending_stack_adjust ();
- start_sequence_for_rtl_expr (xval);
- emit_note (0, -1);
- rtxval = expand_expr (alloc_expr, NULL, VOIDmode, 0);
- do_pending_stack_adjust ();
- TREE_SIDE_EFFECTS (xval) = 1;
- RTL_EXPR_SEQUENCE (xval) = get_insns ();
- end_sequence ();
- RTL_EXPR_RTL (xval) = rtxval;
- TREE_TYPE (xval) = TREE_TYPE (alloc_expr);
- alloc_expr = xval;
- }
+ flags |= LOOKUP_SPECULATIVELY;
- TREE_TYPE (xval) = TREE_TYPE (rval);
- do_pending_stack_adjust ();
- start_sequence_for_rtl_expr (xval);
+ /* We expect alloc_expr to look like a TARGET_EXPR around
+ a NOP_EXPR around the CALL_EXPR we want. */
+ fn = TREE_OPERAND (alloc_expr, 1);
+ fn = TREE_OPERAND (fn, 0);
+ }
- /* As a matter of principle, `start_sequence' should do this. */
- emit_note (0, -1);
+ /* Copy size to the saveable obstack. */
+ size = copy_node (size);
- rval = save_expr (rval);
- rval = expand_vec_init (decl, rval,
- build_binary_op (MINUS_EXPR, nelts,
- integer_one_node, 1),
- init, 0);
+ cleanup = build_op_delete_call (dcode, alloc_node, size, flags, fn);
- do_pending_stack_adjust ();
+ resume_momentary (yes);
- TREE_SIDE_EFFECTS (xval) = 1;
- TREE_CALLS_NEW (xval) = 1;
- RTL_EXPR_SEQUENCE (xval) = get_insns ();
- end_sequence ();
+ /* Ack! First we allocate the memory. Then we set our sentry
+ variable to true, and expand a cleanup that deletes the memory
+ if sentry is true. Then we run the constructor and store the
+ returned pointer in buf. Then we clear sentry and return buf. */
- if (TREE_CODE (rval) == SAVE_EXPR)
- {
- /* Errors may cause this to not get evaluated. */
- if (SAVE_EXPR_RTL (rval) == 0)
- SAVE_EXPR_RTL (rval) = const0_rtx;
- RTL_EXPR_RTL (xval) = SAVE_EXPR_RTL (rval);
- }
- else
+ if (cleanup)
{
- my_friendly_assert (TREE_CODE (rval) == VAR_DECL, 217);
- RTL_EXPR_RTL (xval) = DECL_RTL (rval);
+#if 0
+ /* Disable this until flow is fixed so that it doesn't
+ think the initialization of sentry is a dead write. */
+ tree end, sentry, begin, buf, t = TREE_TYPE (rval);
+
+ begin = get_target_expr (boolean_true_node);
+ sentry = TREE_OPERAND (begin, 0);
+
+ yes = suspend_momentary ();
+ TREE_OPERAND (begin, 2)
+ = build (COND_EXPR, void_type_node, sentry,
+ cleanup, void_zero_node);
+ resume_momentary (yes);
+
+ rval = get_target_expr (rval);
+
+ end = build (MODIFY_EXPR, TREE_TYPE (sentry),
+ sentry, boolean_false_node);
+ TREE_SIDE_EFFECTS (end) = 1;
+
+ buf = TREE_OPERAND (rval, 0);
+
+ rval = build (COMPOUND_EXPR, t, begin,
+ build (COMPOUND_EXPR, t, rval,
+ build (COMPOUND_EXPR, t, end, buf)));
+#else
+ /* FIXME: this is a workaround for a crash due to overlapping
+ exception regions. Cleanups shouldn't really happen here. */
+ rval = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (rval), rval);
+
+ rval = build (TRY_CATCH_EXPR, TREE_TYPE (rval), rval, cleanup);
+ rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
+#endif
}
- rval = xval;
}
}
else if (TYPE_READONLY (true_type))
@@ -3281,45 +2489,27 @@ build_new (placement, decl, init, use_global_new)
done:
- if (alloc_expr)
+ if (alloc_expr && rval == alloc_node)
{
- /* Did we modify the storage? */
- if (rval != alloc_temp)
- {
- tree ifexp = build_binary_op (NE_EXPR, alloc_expr,
- integer_zero_node, 1);
- rval = build_conditional_expr (ifexp, rval, alloc_temp);
- }
- else
- rval = alloc_expr;
+ rval = TREE_OPERAND (alloc_expr, 1);
+ alloc_expr = NULL_TREE;
}
- if (rval && TREE_TYPE (rval) != build_pointer_type (type))
+ if (check_new && alloc_expr)
{
- /* The type of new int [3][3] is not int *, but int [3] * */
- rval = build_c_cast (build_pointer_type (type), rval, 0);
+ /* Did we modify the storage? */
+ tree ifexp = build_binary_op (NE_EXPR, alloc_node,
+ integer_zero_node, 1);
+ rval = build_conditional_expr (ifexp, rval, alloc_node);
}
- if (pending_sizes)
- rval = build_compound_expr (chainon (pending_sizes,
- build_tree_list (NULL_TREE, rval)));
+ if (alloc_expr)
+ rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
- if (flag_gc)
+ if (rval && TREE_TYPE (rval) != build_pointer_type (type))
{
- extern tree gc_visible;
- tree objbits;
- tree update_expr;
-
- rval = save_expr (rval);
- /* We don't need a `headof' operation to do this because
- we know where the object starts. */
- objbits = build1 (INDIRECT_REF, unsigned_type_node,
- build (MINUS_EXPR, ptr_type_node,
- rval, c_sizeof_nowarn (unsigned_type_node)));
- update_expr = build_modify_expr (objbits, BIT_IOR_EXPR, gc_visible);
- rval = build_compound_expr (tree_cons (NULL_TREE, rval,
- tree_cons (NULL_TREE, update_expr,
- build_tree_list (NULL_TREE, rval))));
+ /* The type of new int [3][3] is not int *, but int [3] * */
+ rval = build_c_cast (build_pointer_type (type), rval);
}
return rval;
@@ -3333,7 +2523,7 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
int use_global_delete;
{
tree virtual_size;
- tree ptype = build_pointer_type (type);
+ tree ptype = build_pointer_type (type = complete_type (type));
tree size_exp = size_in_bytes (type);
/* Temporary variables used by the loop. */
@@ -3355,9 +2545,6 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
This is also the containing expression returned by this function. */
tree controller = NULL_TREE;
- /* This is the BLOCK to record the symbol binding for debugging. */
- tree block;
-
if (! IS_AGGR_TYPE (type) || ! TYPE_NEEDS_DESTRUCTOR (type))
{
loop = integer_zero_node;
@@ -3373,22 +2560,20 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
base,
virtual_size)));
DECL_REGISTER (tbase) = 1;
- controller = build (BIND_EXPR, void_type_node, tbase, 0, 0);
+ controller = build (BIND_EXPR, void_type_node, tbase, NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (controller) = 1;
- block = build_block (tbase, 0, 0, 0, 0);
- add_block_current_level (block);
if (auto_delete != integer_zero_node
&& auto_delete != integer_two_node)
{
- tree base_tbd = convert (ptype,
- build_binary_op (MINUS_EXPR,
- convert (ptr_type_node, base),
- BI_header_size,
- 1));
+ tree base_tbd = cp_convert (ptype,
+ build_binary_op (MINUS_EXPR,
+ cp_convert (ptr_type_node, base),
+ BI_header_size,
+ 1));
/* This is the real size */
virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
- body = build_tree_list (NULL_TREE,
+ body = build_expr_list (NULL_TREE,
build_x_delete (ptype, base_tbd,
2 | use_global_delete,
virtual_size));
@@ -3400,24 +2585,24 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
else
body = NULL_TREE;
- body = tree_cons (NULL_TREE,
+ body = expr_tree_cons (NULL_TREE,
build_delete (ptype, tbase, auto_delete,
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 1),
body);
- body = tree_cons (NULL_TREE,
+ body = expr_tree_cons (NULL_TREE,
build_modify_expr (tbase, NOP_EXPR, build (MINUS_EXPR, ptype, tbase, size_exp)),
body);
- body = tree_cons (NULL_TREE,
+ body = expr_tree_cons (NULL_TREE,
build (EXIT_EXPR, void_type_node,
build (EQ_EXPR, boolean_type_node, base, tbase)),
body);
loop = build (LOOP_EXPR, void_type_node, build_compound_expr (body));
- loop = tree_cons (NULL_TREE, tbase_init,
- tree_cons (NULL_TREE, loop, NULL_TREE));
+ loop = expr_tree_cons (NULL_TREE, tbase_init,
+ expr_tree_cons (NULL_TREE, loop, NULL_TREE));
loop = build_compound_expr (loop);
no_destructor:
@@ -3438,12 +2623,12 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
base_tbd = base;
else
{
- base_tbd = convert (ptype,
- build_binary_op (MINUS_EXPR,
- convert (string_type_node, base),
- BI_header_size,
- 1));
- /* True size with header. */
+ base_tbd = cp_convert (ptype,
+ build_binary_op (MINUS_EXPR,
+ cp_convert (string_type_node, base),
+ BI_header_size,
+ 1));
+ /* True size with header. */
virtual_size = size_binop (PLUS_EXPR, virtual_size, BI_header_size);
}
deallocate_expr = build_x_delete (ptype, base_tbd,
@@ -3458,8 +2643,8 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
if (loop && deallocate_expr != integer_zero_node)
{
- body = tree_cons (NULL_TREE, loop,
- tree_cons (NULL_TREE, deallocate_expr, NULL_TREE));
+ body = expr_tree_cons (NULL_TREE, loop,
+ expr_tree_cons (NULL_TREE, deallocate_expr, NULL_TREE));
body = build_compound_expr (body);
}
else
@@ -3477,13 +2662,14 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
return controller;
}
else
- return convert (void_type_node, body);
+ return cp_convert (void_type_node, body);
}
/* Build a tree to cleanup partially built arrays.
BASE is that starting address of the array.
COUNT is the count of objects that have been built, that need destroying.
TYPE is the type of elements in the array. */
+
static tree
build_array_eh_cleanup (base, count, type)
tree base, count, type;
@@ -3520,7 +2706,7 @@ expand_vec_init (decl, base, maxindex, init, from_array)
tree type = TREE_TYPE (TREE_TYPE (base));
tree size;
- maxindex = convert (integer_type_node, maxindex);
+ maxindex = cp_convert (ptrdiff_type_node, maxindex);
if (maxindex == error_mark_node)
return error_mark_node;
@@ -3538,15 +2724,15 @@ expand_vec_init (decl, base, maxindex, init, from_array)
/* Set to zero in case size is <= 0. Optimizer will delete this if
it is not needed. */
rval = get_temp_regvar (build_pointer_type (type),
- convert (build_pointer_type (type), null_pointer_node));
+ cp_convert (build_pointer_type (type), null_pointer_node));
base = default_conversion (base);
- base = convert (build_pointer_type (type), base);
+ base = cp_convert (build_pointer_type (type), base);
expand_assignment (rval, base, 0, 0);
base = get_temp_regvar (build_pointer_type (type), base);
if (init != NULL_TREE
&& TREE_CODE (init) == CONSTRUCTOR
- && TREE_TYPE (init) == TREE_TYPE (decl))
+ && (! decl || TREE_TYPE (init) == TREE_TYPE (decl)))
{
/* Initialization of array from {...}. */
tree elts = CONSTRUCTOR_ELTS (init);
@@ -3574,7 +2760,7 @@ expand_vec_init (decl, base, maxindex, init, from_array)
goto done_init;
}
- iterator = get_temp_regvar (integer_type_node,
+ iterator = get_temp_regvar (ptrdiff_type_node,
build_int_2 (host_i, 0));
init = NULL_TREE;
goto init_by_default;
@@ -3596,9 +2782,10 @@ expand_vec_init (decl, base, maxindex, init, from_array)
{
tree itype;
- iterator = get_temp_regvar (integer_type_node, maxindex);
+ iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
init_by_default:
+ itype = NULL_TREE;
/* If initializing one array from another,
initialize element by element. */
@@ -3629,9 +2816,12 @@ expand_vec_init (decl, base, maxindex, init, from_array)
expand_start_cond (build (GE_EXPR, boolean_type_node,
iterator, integer_zero_node), 0);
if (TYPE_NEEDS_DESTRUCTOR (type))
- start_protect ();
+ expand_eh_region_start ();
expand_start_loop_continue_elsewhere (1);
+ /* The initialization of each array element is a full-expression. */
+ expand_start_target_temps ();
+
if (from_array)
{
tree to = build1 (INDIRECT_REF, type, base);
@@ -3667,9 +2857,13 @@ expand_vec_init (decl, base, maxindex, init, from_array)
if (base2)
expand_assignment (base2,
build (PLUS_EXPR, build_pointer_type (type), base2, size), 0, 0);
+
+ /* Cleanup any temporaries needed for the initial value. */
+ expand_end_target_temps ();
+
expand_loop_continue_here ();
expand_exit_loop_if_false (0, build (NE_EXPR, boolean_type_node,
- build (PREDECREMENT_EXPR, integer_type_node, iterator, integer_one_node), minus_one));
+ build (PREDECREMENT_EXPR, ptrdiff_type_node, iterator, integer_one_node), minus_one));
if (obey_regdecls)
{
@@ -3678,13 +2872,35 @@ expand_vec_init (decl, base, maxindex, init, from_array)
use_variable (DECL_RTL (base2));
}
expand_end_loop ();
- if (TYPE_NEEDS_DESTRUCTOR (type))
- end_protect (build_array_eh_cleanup (rval,
- build_binary_op (MINUS_EXPR,
- maxindex,
- iterator,
- 1),
- type));
+ if (TYPE_NEEDS_DESTRUCTOR (type) && flag_exceptions)
+ {
+ /* We have to ensure that this can live to the cleanup
+ expansion time, since we know it is only ever needed
+ once, generate code now. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+ {
+ tree e1, cleanup = make_node (RTL_EXPR);
+ TREE_TYPE (cleanup) = void_type_node;
+ RTL_EXPR_RTL (cleanup) = const0_rtx;
+ TREE_SIDE_EFFECTS (cleanup) = 1;
+ do_pending_stack_adjust ();
+ start_sequence_for_rtl_expr (cleanup);
+
+ e1 = build_array_eh_cleanup
+ (rval,
+ build_binary_op (MINUS_EXPR, maxindex, iterator, 1),
+ type);
+ expand_expr (e1, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ do_pending_stack_adjust ();
+ RTL_EXPR_SEQUENCE (cleanup) = get_insns ();
+ end_sequence ();
+
+ cleanup = protect_with_terminate (cleanup);
+ expand_eh_region_end (cleanup);
+ }
+ pop_obstacks ();
+ }
expand_end_cond ();
if (obey_regdecls)
use_variable (DECL_RTL (iterator));
@@ -3709,6 +2925,7 @@ expand_vec_init (decl, base, maxindex, init, from_array)
static object, see Free Store 12.5 ANSI C++ WP.
This does not call any destructors. */
+
tree
build_x_delete (type, addr, which_delete, virtual_size)
tree type, addr;
@@ -3717,16 +2934,10 @@ build_x_delete (type, addr, which_delete, virtual_size)
{
int use_global_delete = which_delete & 1;
int use_vec_delete = !!(which_delete & 2);
- tree rval;
enum tree_code code = use_vec_delete ? VEC_DELETE_EXPR : DELETE_EXPR;
+ int flags = LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL);
- if (! use_global_delete && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
- && (TYPE_GETS_DELETE (TREE_TYPE (type)) & (1 << use_vec_delete)))
- rval = build_opfncall (code, LOOKUP_NORMAL, addr, virtual_size, NULL_TREE);
- else
- rval = build_builtin_call (void_type_node, use_vec_delete ? BIVD : BID,
- build_tree_list (NULL_TREE, addr));
- return rval;
+ return build_op_delete_call (code, addr, virtual_size, flags, NULL_TREE);
}
/* Generate a call to a destructor. TYPE is the type to cast ADDR to.
@@ -3740,6 +2951,7 @@ build_x_delete (type, addr, which_delete, virtual_size)
flags. See cp-tree.h for more info.
This function does not delete an object's virtual base classes. */
+
tree
build_delete (type, addr, auto_delete, flags, use_global_delete)
tree type, addr;
@@ -3747,11 +2959,9 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
int flags;
int use_global_delete;
{
- tree function, parms;
tree member;
tree expr;
tree ref;
- int ptr;
if (addr == error_mark_node)
return error_mark_node;
@@ -3766,18 +2976,15 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
if (TREE_CODE (type) == POINTER_TYPE)
{
type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
- if (TYPE_SIZE (type) == 0)
- {
- incomplete_type_error (0, type);
- return error_mark_node;
- }
+ if (!complete_type_or_else (type))
+ return error_mark_node;
if (TREE_CODE (type) == ARRAY_TYPE)
goto handle_array;
if (! IS_AGGR_TYPE (type))
{
/* Call the builtin operator delete. */
return build_builtin_call (void_type_node, BID,
- build_tree_list (NULL_TREE, addr));
+ build_expr_list (NULL_TREE, addr));
}
if (TREE_SIDE_EFFECTS (addr))
addr = save_expr (addr);
@@ -3785,7 +2992,6 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
/* throw away const and volatile on target type of addr */
addr = convert_force (build_pointer_type (type), addr, 0);
ref = build_indirect_ref (addr, NULL_PTR);
- ptr = 1;
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
@@ -3798,7 +3004,6 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
return error_mark_node;
}
return build_vec_delete (addr, array_type_nelts (type),
- c_sizeof_nowarn (TREE_TYPE (type)),
auto_delete, integer_two_node,
use_global_delete);
}
@@ -3816,12 +3021,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
else
addr = convert_force (build_pointer_type (type), addr, 0);
- if (TREE_CODE (addr) == NOP_EXPR
- && TREE_OPERAND (addr, 0) == current_class_decl)
- ref = C_C_D;
- else
- ref = build_indirect_ref (addr, NULL_PTR);
- ptr = 0;
+ ref = build_indirect_ref (addr, NULL_PTR);
}
my_friendly_assert (IS_AGGR_TYPE (type), 220);
@@ -3831,37 +3031,27 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
if (auto_delete == integer_zero_node)
return void_zero_node;
- /* Pass the size of the object down to the operator delete() in
- addition to the ADDR. */
- if (TYPE_GETS_REG_DELETE (type) && !use_global_delete)
- {
- tree virtual_size = c_sizeof_nowarn (type);
- return build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, addr,
- virtual_size, NULL_TREE);
- }
-
- /* Call the builtin operator delete. */
- return build_builtin_call (void_type_node, BID,
- build_tree_list (NULL_TREE, addr));
+ return build_op_delete_call
+ (DELETE_EXPR, addr, c_sizeof_nowarn (type),
+ LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
+ NULL_TREE);
}
- parms = build_tree_list (NULL_TREE, addr);
/* Below, we will reverse the order in which these calls are made.
If we have a destructor, then that destructor will take care
of the base classes; otherwise, we must do that here. */
if (TYPE_HAS_DESTRUCTOR (type))
{
- tree dtor = DECL_MAIN_VARIANT (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0));
- tree basetypes = TYPE_BINFO (type);
tree passed_auto_delete;
tree do_delete = NULL_TREE;
+ tree ifexp;
if (use_global_delete)
{
tree cond = fold (build (BIT_AND_EXPR, integer_type_node,
auto_delete, integer_one_node));
tree call = build_builtin_call
- (void_type_node, BID, build_tree_list (NULL_TREE, addr));
+ (void_type_node, BID, build_expr_list (NULL_TREE, addr));
cond = fold (build (COND_EXPR, void_type_node, cond,
call, void_zero_node));
@@ -3874,106 +3064,29 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
else
passed_auto_delete = auto_delete;
- if (flags & LOOKUP_PROTECT)
- {
- enum access_type access = compute_access (basetypes, dtor);
-
- if (access == access_private)
- {
- if (flags & LOOKUP_COMPLAIN)
- cp_error ("destructor for type `%T' is private in this scope", type);
- return error_mark_node;
- }
- else if (access == access_protected)
- {
- if (flags & LOOKUP_COMPLAIN)
- cp_error ("destructor for type `%T' is protected in this scope", type);
- return error_mark_node;
- }
- }
+ expr = build_method_call
+ (ref, dtor_identifier, build_expr_list (NULL_TREE, passed_auto_delete),
+ NULL_TREE, flags);
- /* Once we are in a destructor, try not going through
- the virtual function table to find the next destructor. */
- if (DECL_VINDEX (dtor)
- && ! (flags & LOOKUP_NONVIRTUAL)
- && TREE_CODE (auto_delete) != PARM_DECL
- && (ptr == 1 || ! resolves_to_fixed_type_p (ref, 0)))
- {
- tree binfo, basetype;
- /* The code below is probably all broken. See call.c for the
- complete right way to do this. this offsets may not be right
- in the below. (mrs) */
- /* This destructor must be called via virtual function table. */
- dtor = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (DECL_CONTEXT (dtor)), 0);
- basetype = DECL_CLASS_CONTEXT (dtor);
- binfo = get_binfo (basetype,
- TREE_TYPE (TREE_TYPE (TREE_VALUE (parms))),
- 0);
- expr = convert_pointer_to_real (binfo, TREE_VALUE (parms));
- if (expr != TREE_VALUE (parms))
- {
- expr = fold (expr);
- ref = build_indirect_ref (expr, NULL_PTR);
- TREE_VALUE (parms) = expr;
- }
- function = build_vfn_ref (&TREE_VALUE (parms), ref, DECL_VINDEX (dtor));
- if (function == error_mark_node)
- return error_mark_node;
- TREE_TYPE (function) = build_pointer_type (TREE_TYPE (dtor));
- TREE_CHAIN (parms) = build_tree_list (NULL_TREE, passed_auto_delete);
- expr = build_function_call (function, parms);
- if (do_delete)
- expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
- if (ptr && (flags & LOOKUP_DESTRUCTOR) == 0)
- {
- /* Handle the case where a virtual destructor is
- being called on an item that is 0.
+ if (do_delete)
+ expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
- @@ Does this really need to be done? */
- tree ifexp = build_binary_op(NE_EXPR, addr, integer_zero_node,1);
-#if 0
- if (TREE_CODE (ref) == VAR_DECL
- || TREE_CODE (ref) == COMPONENT_REF)
- warning ("losing in build_delete");
-#endif
- expr = build (COND_EXPR, void_type_node,
- ifexp, expr, void_zero_node);
- }
- }
+ if (flags & LOOKUP_DESTRUCTOR)
+ /* Explicit destructor call; don't check for null pointer. */
+ ifexp = integer_one_node;
else
- {
- tree ifexp;
-
- if ((flags & LOOKUP_DESTRUCTOR)
- || TREE_CODE (ref) == VAR_DECL
- || TREE_CODE (ref) == PARM_DECL
- || TREE_CODE (ref) == COMPONENT_REF
- || TREE_CODE (ref) == ARRAY_REF)
- /* These can't be 0. */
- ifexp = integer_one_node;
- else
- /* Handle the case where a non-virtual destructor is
- being called on an item that is 0. */
- ifexp = build_binary_op (NE_EXPR, addr, integer_zero_node, 1);
-
- /* Used to mean that this destructor was known to be empty,
- but that's now obsolete. */
- my_friendly_assert (DECL_INITIAL (dtor) != void_type_node, 221);
-
- TREE_CHAIN (parms) = build_tree_list (NULL_TREE, passed_auto_delete);
- expr = build_function_call (dtor, parms);
- if (do_delete)
- expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete);
-
- if (ifexp != integer_one_node)
- expr = build (COND_EXPR, void_type_node,
- ifexp, expr, void_zero_node);
- }
+ /* Handle deleting a null pointer. */
+ ifexp = fold (build_binary_op (NE_EXPR, addr, integer_zero_node, 1));
+
+ if (ifexp != integer_one_node)
+ expr = build (COND_EXPR, void_type_node,
+ ifexp, expr, void_zero_node);
+
return expr;
}
else
{
- /* This can get visibilities wrong. */
+ /* We only get here from finish_function for a destructor. */
tree binfos = BINFO_BASETYPES (TYPE_BINFO (type));
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree base_binfo = n_baseclasses > 0 ? TREE_VEC_ELT (binfos, 0) : NULL_TREE;
@@ -3981,57 +3094,24 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
tree parent_auto_delete = auto_delete;
tree cond;
- /* If this type does not have a destructor, but does have
- operator delete, call the parent parent destructor (if any),
- but let this node do the deleting. Otherwise, it is ok
- to let the parent destructor do the deleting. */
- if (TYPE_GETS_REG_DELETE (type) && !use_global_delete)
- {
- parent_auto_delete = integer_zero_node;
- if (auto_delete == integer_zero_node)
- cond = NULL_TREE;
- else
- {
- tree virtual_size;
-
- /* This is probably wrong. It should be the size of the
- virtual object being deleted. */
- virtual_size = c_sizeof_nowarn (type);
-
- expr = build_opfncall (DELETE_EXPR, LOOKUP_NORMAL, addr,
- virtual_size, NULL_TREE);
- if (expr == error_mark_node)
- return error_mark_node;
- if (auto_delete != integer_one_node)
- cond = build (COND_EXPR, void_type_node,
- build (BIT_AND_EXPR, integer_type_node,
- auto_delete, integer_one_node),
- expr, void_zero_node);
- else
- cond = expr;
- }
- }
+ /* If we have member delete or vbases, we call delete in
+ finish_function. */
+ if (auto_delete == integer_zero_node)
+ cond = NULL_TREE;
else if (base_binfo == NULL_TREE
- || (TREE_VIA_VIRTUAL (base_binfo) == 0
- && ! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo))))
+ || ! TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (base_binfo)))
{
- tree virtual_size;
-
- /* This is probably wrong. It should be the size of the virtual
- object being deleted. */
- virtual_size = c_sizeof_nowarn (type);
-
cond = build (COND_EXPR, void_type_node,
build (BIT_AND_EXPR, integer_type_node, auto_delete, integer_one_node),
build_builtin_call (void_type_node, BID,
- build_tree_list (NULL_TREE, addr)),
+ build_expr_list (NULL_TREE, addr)),
void_zero_node);
}
else
cond = NULL_TREE;
if (cond)
- exprstmt = build_tree_list (NULL_TREE, cond);
+ exprstmt = build_expr_list (NULL_TREE, cond);
if (base_binfo
&& ! TREE_VIA_VIRTUAL (base_binfo)
@@ -4044,9 +3124,10 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
else
this_auto_delete = integer_zero_node;
- expr = build_delete (build_pointer_type (BINFO_TYPE (base_binfo)), addr,
- this_auto_delete, flags, 0);
- exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
+ expr = build_scoped_method_call
+ (ref, base_binfo, dtor_identifier,
+ build_expr_list (NULL_TREE, this_auto_delete));
+ exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
}
/* Take care of the remaining baseclasses. */
@@ -4057,15 +3138,11 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
|| TREE_VIA_VIRTUAL (base_binfo))
continue;
- /* May be zero offset if other baseclasses are virtual. */
- expr = fold (build (PLUS_EXPR, build_pointer_type (BINFO_TYPE (base_binfo)),
- addr, BINFO_OFFSET (base_binfo)));
+ expr = build_scoped_method_call
+ (ref, base_binfo, dtor_identifier,
+ build_expr_list (NULL_TREE, integer_zero_node));
- expr = build_delete (build_pointer_type (BINFO_TYPE (base_binfo)), expr,
- integer_zero_node,
- flags, 0);
-
- exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
+ exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
}
for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
@@ -4074,10 +3151,10 @@ build_delete (type, addr, auto_delete, flags, use_global_delete)
continue;
if (TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (member)))
{
- tree this_member = build_component_ref (ref, DECL_NAME (member), 0, 0);
+ tree this_member = build_component_ref (ref, DECL_NAME (member), NULL_TREE, 0);
tree this_type = TREE_TYPE (member);
expr = build_delete (this_type, this_member, integer_two_node, flags, 0);
- exprstmt = tree_cons (NULL_TREE, expr, exprstmt);
+ exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt);
}
}
@@ -4104,7 +3181,7 @@ build_vbase_delete (type, decl)
{
tree this_addr = convert_force (build_pointer_type (BINFO_TYPE (vbases)),
addr, 0);
- result = tree_cons (NULL_TREE,
+ result = expr_tree_cons (NULL_TREE,
build_delete (TREE_TYPE (this_addr), this_addr,
integer_zero_node,
LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0),
@@ -4130,10 +3207,11 @@ build_vbase_delete (type, decl)
values we'd have to extract. (We could use MAXINDEX with pointers to
confirm the size, and trap if the numbers differ; not clear that it'd
be worth bothering.) */
+
tree
-build_vec_delete (base, maxindex, elt_size, auto_delete_vec, auto_delete,
+build_vec_delete (base, maxindex, auto_delete_vec, auto_delete,
use_global_delete)
- tree base, maxindex, elt_size;
+ tree base, maxindex;
tree auto_delete_vec, auto_delete;
int use_global_delete;
{
@@ -4146,7 +3224,7 @@ build_vec_delete (base, maxindex, elt_size, auto_delete_vec, auto_delete,
base = stabilize_reference (base);
- /* Since we can use base many times, save_expr it. */
+ /* Since we can use base many times, save_expr it. */
if (TREE_SIDE_EFFECTS (base))
base = save_expr (base);
@@ -4156,7 +3234,7 @@ build_vec_delete (base, maxindex, elt_size, auto_delete_vec, auto_delete,
tree cookie_addr = build (MINUS_EXPR, build_pointer_type (BI_header_type),
base, BI_header_size);
tree cookie = build_indirect_ref (cookie_addr, NULL_PTR);
- maxindex = build_component_ref (cookie, nc_nelts_field_id, 0, 0);
+ maxindex = build_component_ref (cookie, nc_nelts_field_id, NULL_TREE, 0);
do
type = TREE_TYPE (type);
while (TREE_CODE (type) == ARRAY_TYPE);
@@ -4171,7 +3249,8 @@ build_vec_delete (base, maxindex, elt_size, auto_delete_vec, auto_delete,
}
else
{
- error ("type to vector delete is neither pointer or array type");
+ if (base != error_mark_node)
+ error ("type to vector delete is neither pointer or array type");
return error_mark_node;
}
diff --git a/contrib/gcc/cp/input.c b/contrib/gcc/cp/input.c
index 77a6468..5a73fea 100644
--- a/contrib/gcc/cp/input.c
+++ b/contrib/gcc/cp/input.c
@@ -29,22 +29,16 @@ Boston, MA 02111-1307, USA. */
lex.c for very minor efficiency gains (primarily in function
inlining). */
-#include <stdio.h>
-#include "obstack.h"
+#include "system.h"
extern FILE *finput;
-struct pending_input *save_pending_input ();
-void restore_pending_input ();
-
struct input_source {
/* saved string */
char *str;
int length;
/* current position, when reading as input */
int offset;
- /* obstack to free this input string from when finished, if any */
- struct obstack *obstack;
/* linked list maintenance */
struct input_source *next;
/* values to restore after reading all of current string */
@@ -65,6 +59,25 @@ extern int lineno;
#define inline
#endif
+#if USE_CPPLIB
+extern unsigned char *yy_cur, *yy_lim;
+extern int yy_get_token ();
+#define GETC() (yy_cur < yy_lim ? *yy_cur++ : yy_get_token ())
+#else
+#define GETC() getc (finput)
+#endif
+
+extern void feed_input PROTO((char *, int));
+extern void put_input PROTO((int));
+extern void put_back PROTO((int));
+extern int getch PROTO((void));
+extern int input_redirected PROTO((void));
+
+static inline struct input_source * allocate_input PROTO((void));
+static inline void free_input PROTO((struct input_source *));
+static inline void end_input PROTO((void));
+static inline int sub_getch PROTO((void));
+
static inline struct input_source *
allocate_input ()
{
@@ -78,7 +91,6 @@ allocate_input ()
}
inp = (struct input_source *) xmalloc (sizeof (struct input_source));
inp->next = 0;
- inp->obstack = 0;
return inp;
}
@@ -86,9 +98,6 @@ static inline void
free_input (inp)
struct input_source *inp;
{
- if (inp->obstack)
- obstack_free (inp->obstack, inp->str);
- inp->obstack = 0;
inp->str = 0;
inp->length = 0;
inp->next = free_inputs;
@@ -102,10 +111,9 @@ static int putback_char = -1;
inline
void
-feed_input (str, len, delete)
+feed_input (str, len)
char *str;
int len;
- struct obstack *delete;
{
struct input_source *inp = allocate_input ();
@@ -115,7 +123,6 @@ feed_input (str, len, delete)
inp->str = str;
inp->length = len;
- inp->obstack = delete;
inp->offset = 0;
inp->next = input;
inp->filename = input_filename;
@@ -129,6 +136,22 @@ feed_input (str, len, delete)
struct pending_input *to_be_restored; /* XXX */
extern int end_of_file;
+static inline void
+end_input ()
+{
+ struct input_source *inp = input;
+
+ end_of_file = 0;
+ input = inp->next;
+ input_filename = inp->filename;
+ lineno = inp->lineno;
+ /* Get interface/implementation back in sync. */
+ extract_interface_info ();
+ putback_char = inp->putback_char;
+ restore_pending_input (inp->input);
+ free_input (inp);
+}
+
static inline int
sub_getch ()
{
@@ -140,32 +163,20 @@ sub_getch ()
}
if (input)
{
- if (input->offset == input->length)
+ if (input->offset >= input->length)
{
- struct input_source *inp = input;
my_friendly_assert (putback_char == -1, 223);
- to_be_restored = inp->input;
- input->offset++;
- return EOF;
- }
- else if (input->offset > input->length)
- {
- struct input_source *inp = input;
-
- end_of_file = 0;
- input = inp->next;
- input_filename = inp->filename;
- lineno = inp->lineno;
- /* Get interface/implementation back in sync. */
- extract_interface_info ();
- putback_char = inp->putback_char;
- free_input (inp);
+ ++(input->offset);
+ if (input->offset - input->length < 64)
+ return EOF;
+
+ /* We must be stuck in an error-handling rule; give up. */
+ end_input ();
return getch ();
}
- if (input)
- return input->str[input->offset++];
+ return (unsigned char)input->str[input->offset++];
}
- return getc (finput);
+ return GETC ();
}
inline
diff --git a/contrib/gcc/cp/lang-options.h b/contrib/gcc/cp/lang-options.h
index d551357..5c50332 100644
--- a/contrib/gcc/cp/lang-options.h
+++ b/contrib/gcc/cp/lang-options.h
@@ -18,90 +18,106 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+DEFINE_LANG_NAME ("C++")
+
/* This is the contribution to the `lang_options' array in gcc.c for
g++. */
- "-+e0", /* gcc.c tacks the `-' on the front. */
- "-+e1",
- "-+e2",
- "-faccess-control",
- "-fno-access-control",
- "-fall-virtual",
- "-fno-all-virtual",
- "-falt-external-templates",
- "-fno-alt-external-templates",
- "-fansi-overloading",
- "-fno-ansi-overloading",
- "-fcadillac",
- "-fno-cadillac",
- "-fcheck-new",
- "-fno-check-new",
- "-fconserve-space",
- "-fno-conserve-space",
- "-fdefault-inline",
- "-fno-default-inline",
- "-frtti",
- "-fno-rtti",
- "-felide-constructors",
- "-fno-elide-constructors",
- "-fenum-int-equiv",
- "-fno-enum-int-equiv",
- "-fexternal-templates",
- "-fno-external-templates",
- "-ffor-scope",
- "-fno-for-scope",
- "-fgc",
- "-fno-gc",
- "-fgnu-keywords",
- "-fno-gnu-keywords",
- "-fhandle-exceptions",
- "-fno-handle-exceptions",
- "-fhandle-signatures",
- "-fno-handle-signatures",
- "-fhuge-objects",
- "-fno-huge-objects",
- "-fimplement-inlines",
- "-fno-implement-inlines",
- "-fimplicit-templates",
- "-fno-implicit-templates",
- "-flabels-ok",
- "-fno-labels-ok",
- "-fmemoize-lookups",
- "-fno-memoize-lookups",
- "-fnonnull-objects",
- "-fno-nonnull-objects",
- "-foperator-names",
- "-fno-operator-names",
- "-frepo",
- "-fno-repo",
- "-fsave-memoized",
- "-fno-save-memoized",
- "-fshort-temps",
- "-fno-short-temps",
- "-fstats",
- "-fno-stats",
- "-fstrict-prototype",
- "-fno-strict-prototype",
- "-fthis-is-variable",
- "-fno-this-is-variable",
- "-fvtable-thunks",
- "-fno-vtable-thunks",
- "-fxref",
- "-fno-xref",
+ { "-+e0", "" }, /* gcc.c tacks the `-' on the front. */
+ { "-+e1", "" },
+ { "-+e2", "" },
+ { "-faccess-control", "" },
+ { "-fno-access-control", "Do not obey access control semantics" },
+ { "-fall-virtual", "Make all member functions virtual" },
+ { "-fno-all-virtual", "" },
+ { "-falt-external-templates", "Change when template instances are emitted" },
+ { "-fno-alt-external-templates", "" },
+ { "-fansi-overloading", "" },
+ { "-fno-ansi-overloading", "" },
+ { "-fcheck-new", "Check the return value of new" },
+ { "-fno-check-new", "" },
+ { "-fconserve-space", "Reduce size of object files" },
+ { "-fno-conserve-space", "" },
+ { "-fdefault-inline", "" },
+ { "-fno-default-inline", "Do not inline mmeber functions be default"},
+ { "-frtti", "" },
+ { "-fno-rtti", "Do not generate run time type descriptor information" },
+ { "-felide-constructors", "" },
+ { "-fno-elide-constructors", "" },
+ { "-fenum-int-equiv", "" },
+ { "-fno-enum-int-equiv", "" },
+ { "-fexternal-templates", "" },
+ { "-fno-external-templates", "" },
+ { "-ffor-scope", "" },
+ { "-fno-for-scope", "Scope of for-init-statement vars extends outside" },
+ { "-fguiding-decls", "Implement guiding declarations" },
+ { "-fno-guiding-decls", "" },
+ { "-fgnu-keywords", "" },
+ { "-fno-gnu-keywords", "Do not recognise GNU defined keywords" },
+ { "-fhandle-exceptions", "Enable exception handling" },
+ { "-fno-handle-exceptions", "" },
+ { "-fhandle-signatures", "Handle signature language constructs" },
+ { "-fno-handle-signatures", "" },
+ { "-fhonor-std", "Do not ignore the namespace standard" },
+ { "-fno-honor-std", "" },
+ { "-fhuge-objects", "Enable support for huge objects" },
+ { "-fno-huge-objects", "" },
+ { "-fimplement-inlines", "" },
+ { "-fno-implement-inlines", "Export functions even if they can be inlined" },
+ { "-fimplicit-templates", "Emit implicit instatiations if needed" },
+ { "-fno-implicit-templates", "" },
+ { "-flabels-ok", "Labels can be used as first class objects" },
+ { "-fno-labels-ok", "" },
+ { "-fmemoize-lookups", "Enable caching of member function resolutions" },
+ { "-fno-memoize-lookups", "" },
+ { "-fname-mangling-version-", "Set the version of name mangling to use" },
+ { "-fnew-abi", "Enable experimental ABI changes" },
+ { "-fno-new-abi", "" },
+ { "-fnonnull-objects", "" },
+ { "-fno-nonnull-objects", "Do not assume that a reference is always valid" },
+ { "-foperator-names", "Recognise and/bitand/bitor/compl/not/or/xor" },
+ { "-fno-operator-names", "" },
+ { "-foptional-diags", "" },
+ { "-fno-optional-diags", "Disable optional diagnostics" },
+ { "-frepo", "Enable automatic template instantiation" },
+ { "-fno-repo", "" },
+ { "-fsave-memoized", "Save cache of member function resolutions" },
+ { "-fno-save-memoized", "" },
+ { "-fsquangle", "Enable squashed name mangling" },
+ { "-fno-squangle", "" },
+ { "-fstats", "Display statistics accumulated during compilation" },
+ { "-fno-stats", "" },
+ { "-fstrict-prototype", "" },
+ { "-fno-strict-prototype", "Do not assume that empty prototype means no args" },
+ { "-ftemplate-depth-", "Specify maximum template instantiation depth"},
+ { "-fthis-is-variable", "Make 'this' not be type '* const'" },
+ { "-fno-this-is-variable", "" },
+ { "-fvtable-thunks", "Implement vtables using thunks" },
+ { "-fno-vtable-thunks", "" },
+ { "-fweak", "Emit common-like symbols as weak symbols" },
+ { "-fno-weak", "" },
+ { "-fxref", "Emit cross referencing information" },
+ { "-fno-xref", "" },
- "-Wreturn-type",
- "-Wno-return-type",
- "-Woverloaded-virtual",
- "-Wno-overloaded-virtual",
- "-Wtemplate-debugging",
- "-Wno-template-debugging",
- "-Wctor-dtor-privacy",
- "-Wno-ctor-dtor-privacy",
- "-Wnon-virtual-dtor",
- "-Wno-non-virtual-dtor",
- "-Wextern-inline",
- "-Wno-extern-inline",
- "-Wreorder",
- "-Wno-reorder",
- "-Wsynth",
- "-Wno-synth",
+ { "-Wreturn-type", "Warn about inconsistent return types" },
+ { "-Wno-return-type", "" },
+ { "-Woverloaded-virtual", "Warn about overloaded virtual function names" },
+ { "-Wno-overloaded-virtual", "" },
+ { "-Wctor-dtor-privacy", "Warn when all ctors/dtors are private" },
+ { "-Wno-ctor-dtor-privacy", "" },
+ { "-Wnon-virtual-dtor", "Warn about non virtual destructors" },
+ { "-Wno-non-virtual-dtor", "" },
+ { "-Wextern-inline", "Warn when a function is declared extern, then inline" },
+ { "-Wno-extern-inline", "" },
+ { "-Wreorder", "Warn when the compiler reorders code" },
+ { "-Wno-reorder", "" },
+ { "-Wsynth", "Warn when synthesis behaviour differs from Cfront" },
+ { "-Wno-synth", "" },
+ { "-Wpmf-conversions", "Warn when type converting pointers to member functions" },
+ { "-Wno-pmf-conversions", "" },
+ { "-Weffc++", "Warn about violations of Effective C++ style rules" },
+ { "-Wno-effc++", "" },
+ { "-Wsign-promo", "Warn when overload promotes from unsigned to signed" },
+ { "-Wno-sign-promo", "" },
+ { "-Wold-style-cast", "Warn if a C style cast is used in a program" },
+ { "-Wno-old-style-cast", "" },
diff --git a/contrib/gcc/cp/lang-specs.h b/contrib/gcc/cp/lang-specs.h
index fbb72c9..b208ca1 100644
--- a/contrib/gcc/cp/lang-specs.h
+++ b/contrib/gcc/cp/lang-specs.h
@@ -21,39 +21,74 @@ Boston, MA 02111-1307, USA. */
/* This is the contribution to the `default_compilers' array in gcc.c for
g++. */
- {".cc", "@c++"},
- {".cxx", "@c++"},
- {".cpp", "@c++"},
- {".c++", "@c++"},
- {".C", "@c++"},
+ {".cc", {"@c++"}},
+ {".cp", {"@c++"}},
+ {".cxx", {"@c++"}},
+ {".cpp", {"@c++"}},
+ {".c++", {"@c++"}},
+ {".C", {"@c++"}},
{"@c++",
- "cpp -lang-c++ %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+#if USE_CPPLIB
+ {
+ "%{E|M|MM:cpp -lang-c++ %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C++ does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
-undef -D__GNUC__=%v1 -D__GNUG__=%v1 -D__cplusplus -D__GNUC_MINOR__=%v2\
- %{ansi:-trigraphs -$ -D__STRICT_ANSI__} %{!undef:%{!ansi:%p} %P}\
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
- %{traditional-cpp:-traditional} %{trigraphs}\
+ %{ansi:-trigraphs -D__STRICT_ANSI__} %{!undef:%{!ansi:%p} %P}\
+ %{!fno-exceptions:-D__EXCEPTIONS}\
+ %{fhonor-std:-D__HONOR_STD} %{fnew-abi:-D__HONOR_STD}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}} %{trigraphs}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
+ %i %{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}}\n}\
+ %{!E:%{!M:%{!MM:cc1plus %i %1 %2\
+ -lang-c++ %{nostdinc*} %{C} %{A*} %{I*} %{P} %I\
+ -undef -D__GNUC__=%v1 -D__GNUG__=%v1 -D__cplusplus\
+ -D__GNUC_MINOR__=%v2\
+ %{ansi:-trigraphs -D__STRICT_ANSI__} %{!undef:%{!ansi:%p} %P}\
+ %{!fno-exceptions:-D__EXCEPTIONS}\
+ %{fhonor-std:-D__HONOR_STD} %{fnew-abi:-D__HONOR_STD}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{trigraphs}\
+ %{!Q:-quiet} -dumpbase %b.cc %{d*} %{m*} %{a}\
+ %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi}\
+ %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
+ %{v:-version} %{pg:-p} %{p}\
+ %{f*} %{+e*} %{aux-info*}\
+ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
+ %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}}|\n\
+ %{!S:as %a %Y\
+ %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
+ %{!pipe:%g.s} %A\n }}}}"}},
+#else /* ! USE_CPPLIB */
+ {"cpp -lang-c++ %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ %{C:%{!E:%eGNU C++ does not support -C without using -E}}\
+ %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
+ -undef -D__GNUC__=%v1 -D__GNUG__=%v1 -D__cplusplus -D__GNUC_MINOR__=%v2\
+ %{ansi:-trigraphs -D__STRICT_ANSI__} %{!undef:%{!ansi:%p} %P}\
+ %{!fno-exceptions:-D__EXCEPTIONS}\
+ %{fhonor-std:-D__HONOR_STD} %{fnew-abi:-D__HONOR_STD}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}} %{trigraphs}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.ii}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
- "%{!M:%{!MM:%{!E:cc1plus %{!pipe:%g.ii} %1 %2\
+ "%{!M:%{!MM:%{!E:cc1plus %{!pipe:%g.ii} %1 %2\
%{!Q:-quiet} -dumpbase %b.cc %{d*} %{m*} %{a}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi}\
- %{traditional} %{v:-version} %{pg:-p} %{p}\
+ %{v:-version} %{pg:-p} %{p}\
%{f*} %{+e*} %{aux-info*}\
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}}|\n\
%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %{!pipe:%g.s} %A\n }}}}"},
- {".ii", "@c++-cpp-output"},
+ %{!pipe:%g.s} %A\n }}}}"}},
+#endif /* ! USE_CPPLIB */
+ {".ii", {"@c++-cpp-output"}},
{"@c++-cpp-output",
- "%{!M:%{!MM:%{!E:cc1plus %i %1 %2 %{!Q:-quiet} %{d*} %{m*} %{a}\
+ {"%{!M:%{!MM:%{!E:cc1plus %i %1 %2 %{!Q:-quiet} %{d*} %{m*} %{a}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi}\
- %{traditional} %{v:-version} %{pg:-p} %{p}\
+ %{v:-version} %{pg:-p} %{p}\
%{f*} %{+e*} %{aux-info*}\
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %{!pipe:%g.s} %A\n }}}}"},
+ %{!pipe:%g.s} %A\n }}}}"}},
diff --git a/contrib/gcc/cp/lex.c b/contrib/gcc/cp/lex.c
index 9e51883..57639ad 100644
--- a/contrib/gcc/cp/lex.c
+++ b/contrib/gcc/cp/lex.c
@@ -1,5 +1,5 @@
/* Separate lexical analyzer for GNU C++.
- Copyright (C) 1987, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -25,64 +25,100 @@ Boston, MA 02111-1307, USA. */
/* Cause the `yydebug' variable to be defined. */
#define YYDEBUG 1
-#include <sys/types.h>
-#include <stdio.h>
-#include <errno.h>
-#include <setjmp.h>
#include "config.h"
+#include "system.h"
+#include <setjmp.h>
#include "input.h"
#include "tree.h"
#include "lex.h"
-#include "parse.h"
#include "cp-tree.h"
+#include "parse.h"
#include "flags.h"
#include "obstack.h"
#include "c-pragma.h"
+#include "toplev.h"
+#include "output.h"
+
+/* MULTIBYTE_CHARS support only works for native compilers.
+ ??? Ideally what we want is to model widechar support after
+ the current floating point support. */
+#ifdef CROSS_COMPILE
+#undef MULTIBYTE_CHARS
+#endif
#ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
#include <locale.h>
#endif
-#ifndef errno
-extern int errno; /* needed for VAX. */
-#endif
-extern jmp_buf toplevel;
-
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern struct obstack *expression_obstack, permanent_obstack;
-extern struct obstack *current_obstack, *saveable_obstack;
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
-extern double atof ();
+extern struct obstack permanent_obstack;
+extern struct obstack *current_obstack, *saveable_obstack;
-extern char *get_directive_line (); /* In c-common.c */
+extern void yyprint PROTO((FILE *, int, YYSTYPE));
+extern void compiler_error PROTO((char *, HOST_WIDE_INT,
+ HOST_WIDE_INT));
+
+static tree get_time_identifier PROTO((char *));
+static int check_newline PROTO((void));
+static int skip_white_space PROTO((int));
+static void finish_defarg PROTO((void));
+static int my_get_run_time PROTO((void));
+static int get_last_nonwhite_on_line PROTO((void));
+static int interface_strcmp PROTO((char *));
+static int readescape PROTO((int *));
+static char *extend_token_buffer PROTO((char *));
+static void consume_string PROTO((struct obstack *, int));
+static void set_typedecl_interface_info PROTO((tree, tree));
+static void feed_defarg PROTO((tree, tree));
+static int set_vardecl_interface_info PROTO((tree, tree));
+static void store_pending_inline PROTO((tree, struct pending_inline *));
+static void reinit_parse_for_expr PROTO((struct obstack *));
+static int *init_cpp_parse PROTO((void));
+static int handle_cp_pragma PROTO((char *));
+#ifdef HANDLE_SYSV_PRAGMA
+static int handle_sysv_pragma PROTO((int));
+#endif
+#ifdef GATHER_STATISTICS
+#ifdef REDUCE_LENGTH
+static int reduce_cmp PROTO((int *, int *));
+static int token_cmp PROTO((int *, int *));
+#endif
+#endif
/* Given a file name X, return the nondirectory portion.
Keep in mind that X can be computed more than once. */
-#ifndef FILE_NAME_NONDIRECTORY
-#define FILE_NAME_NONDIRECTORY(X) \
- (rindex (X, '/') != 0 ? rindex (X, '/') + 1 : X)
-#endif
-
-extern char *index ();
-extern char *rindex ();
-
-void extract_interface_info ();
-void yyerror ();
+char *
+file_name_nondirectory (x)
+ char *x;
+{
+ char *tmp = (char *) rindex (x, '/');
+ if (DIR_SEPARATOR != '/' && ! tmp)
+ tmp = (char *) rindex (x, DIR_SEPARATOR);
+ if (tmp)
+ return (char *) (tmp + 1);
+ else
+ return x;
+}
/* This obstack is needed to hold text. It is not safe to use
TOKEN_BUFFER because `check_newline' calls `yylex'. */
struct obstack inline_text_obstack;
-static char *inline_text_firstobj;
-
-/* This obstack is used to hold information about methods to be
- synthesized. It should go away when synthesized methods are handled
- properly (i.e. only when needed). */
-struct obstack synth_obstack;
-static char *synth_firstobj;
+char *inline_text_firstobj;
+#if USE_CPPLIB
+#include "cpplib.h"
+extern cpp_reader parse_in;
+extern cpp_options parse_options;
+extern unsigned char *yy_cur, *yy_lim;
+#else
+FILE *finput;
+#endif
int end_of_file;
/* Pending language change.
@@ -101,7 +137,7 @@ extern struct obstack token_obstack;
#else
extern void put_back (/* int */);
extern int input_redirected ();
-extern void feed_input (/* char *, int, struct obstack * */);
+extern void feed_input (/* char *, int */);
#endif
/* Holds translations from TREE_CODEs to operator name strings,
@@ -132,52 +168,43 @@ tree ridpointers[(int) RID_MAX];
/* We may keep statistics about how long which files took to compile. */
static int header_time, body_time;
-static tree get_time_identifier ();
static tree filename_times;
static tree this_filename_time;
-/* For implementing #pragma unit. */
-tree current_unit_name;
-tree current_unit_language;
-
/* Array for holding counts of the numbers of tokens seen. */
extern int *token_count;
-
-/* Textual definition used for default functions. */
-static void default_copy_constructor_body ();
-static void default_assign_ref_body ();
/* Return something to represent absolute declarators containing a *.
TARGET is the absolute declarator that the * contains.
- TYPE_QUALS is a list of modifiers such as const or volatile
+ CV_QUALIFIERS is a list of modifiers such as const or volatile
to apply to the pointer type, represented as identifiers.
We return an INDIRECT_REF whose "contents" are TARGET
and whose type is the modifier list. */
tree
-make_pointer_declarator (type_quals, target)
- tree type_quals, target;
+make_pointer_declarator (cv_qualifiers, target)
+ tree cv_qualifiers, target;
{
if (target && TREE_CODE (target) == IDENTIFIER_NODE
&& ANON_AGGRNAME_P (target))
error ("type name expected before `*'");
target = build_parse_node (INDIRECT_REF, target);
- TREE_TYPE (target) = type_quals;
+ TREE_TYPE (target) = cv_qualifiers;
return target;
}
/* Return something to represent absolute declarators containing a &.
TARGET is the absolute declarator that the & contains.
- TYPE_QUALS is a list of modifiers such as const or volatile
+ CV_QUALIFIERS is a list of modifiers such as const or volatile
to apply to the reference type, represented as identifiers.
We return an ADDR_EXPR whose "contents" are TARGET
and whose type is the modifier list. */
tree
-make_reference_declarator (type_quals, target)
- tree type_quals, target;
+make_reference_declarator (cv_qualifiers, target)
+ tree cv_qualifiers, target;
{
if (target)
{
@@ -195,9 +222,26 @@ make_reference_declarator (type_quals, target)
error ("type name expected before `&'");
}
target = build_parse_node (ADDR_EXPR, target);
- TREE_TYPE (target) = type_quals;
+ TREE_TYPE (target) = cv_qualifiers;
+ return target;
+}
+
+tree
+make_call_declarator (target, parms, cv_qualifiers, exception_specification)
+ tree target, parms, cv_qualifiers, exception_specification;
+{
+ target = build_parse_node (CALL_EXPR, target, parms, cv_qualifiers);
+ TREE_TYPE (target) = exception_specification;
return target;
}
+
+void
+set_quals_and_spec (call_declarator, cv_qualifiers, exception_specification)
+ tree call_declarator, cv_qualifiers, exception_specification;
+{
+ TREE_OPERAND (call_declarator, 2) = cv_qualifiers;
+ TREE_TYPE (call_declarator) = exception_specification;
+}
/* Build names and nodes for overloaded operators. */
@@ -252,9 +296,6 @@ int interface_unknown; /* whether or not we know this class
/* lexical analyzer */
-/* File used for outputting assembler code. */
-extern FILE *asm_out_file;
-
#ifndef WCHAR_TYPE_SIZE
#ifdef INT_TYPE_SIZE
#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
@@ -272,13 +313,10 @@ char *token_buffer; /* Pointer to token buffer.
#include "hash.h"
-int check_newline ();
/* Nonzero tells yylex to ignore \ in string constants. */
static int ignore_escape_flag = 0;
-static int skip_white_space ();
-
static tree
get_time_identifier (name)
char *name;
@@ -296,7 +334,7 @@ get_time_identifier (name)
end_temporary_allocation ();
IDENTIFIER_LOCAL_VALUE (time_identifier) = build_int_2 (0, 0);
IDENTIFIER_CLASS_VALUE (time_identifier) = build_int_2 (0, 1);
- IDENTIFIER_GLOBAL_VALUE (time_identifier) = filename_times;
+ SET_IDENTIFIER_GLOBAL_VALUE (time_identifier, filename_times);
filename_times = time_identifier;
pop_obstacks ();
}
@@ -319,13 +357,13 @@ my_get_run_time ()
/* Table indexed by tree code giving a string containing a character
classifying the tree code. Possibilities are
- t, d, s, c, r, <, 1 and 2. See cp/tree.def for details. */
+ t, d, s, c, r, <, 1 and 2. See cp/cp-tree.def for details. */
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
-char *cplus_tree_code_type[] = {
- "x",
-#include "tree.def"
+char cplus_tree_code_type[] = {
+ 'x',
+#include "cp-tree.def"
};
#undef DEFTREECODE
@@ -337,7 +375,7 @@ char *cplus_tree_code_type[] = {
int cplus_tree_code_length[] = {
0,
-#include "tree.def"
+#include "cp-tree.def"
};
#undef DEFTREECODE
@@ -347,22 +385,28 @@ int cplus_tree_code_length[] = {
char *cplus_tree_code_name[] = {
"@@dummy",
-#include "tree.def"
+#include "cp-tree.def"
};
#undef DEFTREECODE
/* toplev.c needs to call these. */
void
+lang_init_options ()
+{
+ /* Default exceptions on. */
+ flag_exceptions = 1;
+}
+
+void
lang_init ()
{
+#if ! USE_CPPLIB
/* the beginning of the file is a new line; check for # */
/* With luck, we discover the real source file's name from that
and put it in input_filename. */
put_back (check_newline ());
-
- if (flag_cadillac)
- cadillac_start ();
+#endif
if (flag_gnu_xref) GNU_xref_begin (input_filename);
init_repo (input_filename);
}
@@ -394,23 +438,66 @@ init_filename_times ()
/* Change by Bryan Boreham, Kewill, Thu Jul 27 09:46:05 1989.
Stuck this hack in to get the files open correctly; this is called
- in place of init_lex if we are an unexec'd binary. */
+ in place of init_parse if we are an unexec'd binary. */
+
+#if 0
void
reinit_lang_specific ()
{
init_filename_times ();
reinit_search_statistics ();
}
+#endif
-void
-init_lex ()
+static int *
+init_cpp_parse ()
+{
+#ifdef GATHER_STATISTICS
+#ifdef REDUCE_LENGTH
+ reduce_count = (int *)malloc (sizeof (int) * (REDUCE_LENGTH + 1));
+ bzero (reduce_count, sizeof (int) * (REDUCE_LENGTH + 1));
+ reduce_count += 1;
+ token_count = (int *)malloc (sizeof (int) * (TOKEN_LENGTH + 1));
+ bzero (token_count, sizeof (int) * (TOKEN_LENGTH + 1));
+ token_count += 1;
+#endif
+#endif
+ return token_count;
+}
+
+char *
+init_parse (filename)
+ char *filename;
{
- extern char *(*decl_printable_name) ();
extern int flag_no_gnu_keywords;
extern int flag_operator_names;
int i;
+#if USE_CPPLIB
+ yy_cur = "\n";
+ yy_lim = yy_cur + 1;
+
+ parse_in.show_column = 1;
+ if (! cpp_start_read (&parse_in, filename))
+ abort ();
+#else
+ /* Open input file. */
+ if (filename == 0 || !strcmp (filename, "-"))
+ {
+ finput = stdin;
+ filename = "stdin";
+ }
+ else
+ finput = fopen (filename, "r");
+ if (finput == 0)
+ pfatal_with_name (filename);
+
+#ifdef IO_BUFFER_SIZE
+ setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE);
+#endif
+#endif /* !USE_CPPLIB */
+
/* Initialize the lookahead machinery. */
init_spew ();
@@ -420,18 +507,9 @@ init_lex ()
init_cplus_expand ();
- tree_code_type
- = (char **) realloc (tree_code_type,
- sizeof (char *) * LAST_CPLUS_TREE_CODE);
- tree_code_length
- = (int *) realloc (tree_code_length,
- sizeof (int) * LAST_CPLUS_TREE_CODE);
- tree_code_name
- = (char **) realloc (tree_code_name,
- sizeof (char *) * LAST_CPLUS_TREE_CODE);
- bcopy ((char *)cplus_tree_code_type,
- (char *)(tree_code_type + (int) LAST_AND_UNUSED_TREE_CODE),
- (LAST_CPLUS_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE) * sizeof (char *));
+ bcopy (cplus_tree_code_type,
+ tree_code_type + (int) LAST_AND_UNUSED_TREE_CODE,
+ (int)LAST_CPLUS_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE);
bcopy ((char *)cplus_tree_code_length,
(char *)(tree_code_length + (int) LAST_AND_UNUSED_TREE_CODE),
(LAST_CPLUS_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE) * sizeof (int));
@@ -568,15 +646,13 @@ init_lex ()
IDENTIFIER_OPNAME_P (ansi_opname[(int) MAX_EXPR]) = 1;
ansi_opname[(int) COND_EXPR] = get_identifier ("__cn");
IDENTIFIER_OPNAME_P (ansi_opname[(int) COND_EXPR]) = 1;
- ansi_opname[(int) METHOD_CALL_EXPR] = get_identifier ("__wr");
- IDENTIFIER_OPNAME_P (ansi_opname[(int) METHOD_CALL_EXPR]) = 1;
+ ansi_opname[(int) SIZEOF_EXPR] = get_identifier ("__sz");
+ IDENTIFIER_OPNAME_P (ansi_opname[(int) SIZEOF_EXPR]) = 1;
init_method ();
init_error ();
gcc_obstack_init (&inline_text_obstack);
inline_text_firstobj = (char *) obstack_alloc (&inline_text_obstack, 0);
- gcc_obstack_init (&synth_obstack);
- synth_firstobj = (char *) obstack_alloc (&synth_obstack, 0);
/* Start it at 0, because check_newline is called at the very beginning
and will increment it to 1. */
@@ -641,8 +717,11 @@ init_lex ()
ridpointers[(int) RID_REGISTER] = get_identifier ("register");
SET_IDENTIFIER_AS_LIST (ridpointers[(int) RID_REGISTER],
build_tree_list (NULL_TREE, ridpointers[(int) RID_REGISTER]));
+ ridpointers[(int) RID_COMPLEX] = get_identifier ("__complex");
+ SET_IDENTIFIER_AS_LIST (ridpointers[(int) RID_COMPLEX],
+ build_tree_list (NULL_TREE, ridpointers[(int) RID_COMPLEX]));
- /* C++ extensions. These are probably not correctly named. */
+ /* C++ extensions. These are probably not correctly named. */
ridpointers[(int) RID_WCHAR] = get_identifier ("__wchar_t");
SET_IDENTIFIER_AS_LIST (ridpointers[(int) RID_WCHAR],
build_tree_list (NULL_TREE, ridpointers[(int) RID_WCHAR]));
@@ -684,7 +763,7 @@ init_lex ()
ridpointers[(int) RID_TEMPLATE] = get_identifier ("template");
SET_IDENTIFIER_AS_LIST (ridpointers[(int) RID_TEMPLATE],
build_tree_list (NULL_TREE, ridpointers[(int) RID_TEMPLATE]));
- /* This is for ANSI C++. */
+ /* This is for ANSI C++. */
ridpointers[(int) RID_MUTABLE] = get_identifier ("mutable");
SET_IDENTIFIER_AS_LIST (ridpointers[(int) RID_MUTABLE],
build_tree_list (NULL_TREE, ridpointers[(int) RID_MUTABLE]));
@@ -694,17 +773,19 @@ init_lex ()
TREE_TYPE (signature_type_node) = signature_type_node;
ridpointers[(int) RID_SIGNATURE] = signature_type_node;
+ null_node = build_int_2 (0, 0);
+ ridpointers[RID_NULL] = null_node;
+
opname_tab[(int) COMPONENT_REF] = "->";
opname_tab[(int) MEMBER_REF] = "->*";
- opname_tab[(int) METHOD_CALL_EXPR] = "->()";
- opname_tab[(int) INDIRECT_REF] = "(unary *)";
+ opname_tab[(int) INDIRECT_REF] = "*";
opname_tab[(int) ARRAY_REF] = "[]";
opname_tab[(int) MODIFY_EXPR] = "=";
opname_tab[(int) NEW_EXPR] = "new";
opname_tab[(int) DELETE_EXPR] = "delete";
opname_tab[(int) VEC_NEW_EXPR] = "new []";
opname_tab[(int) VEC_DELETE_EXPR] = "delete []";
- opname_tab[(int) COND_EXPR] = "... ? ... : ...";
+ opname_tab[(int) COND_EXPR] = "?:";
opname_tab[(int) CALL_EXPR] = "()";
opname_tab[(int) PLUS_EXPR] = "+";
opname_tab[(int) MINUS_EXPR] = "-";
@@ -741,9 +822,9 @@ init_lex ()
opname_tab[(int) EQ_EXPR] = "==";
opname_tab[(int) NE_EXPR] = "!=";
opname_tab[(int) IN_EXPR] = "in";
- opname_tab[(int) RANGE_EXPR] = "..";
- opname_tab[(int) CONVERT_EXPR] = "(unary +)";
- opname_tab[(int) ADDR_EXPR] = "(unary &)";
+ opname_tab[(int) RANGE_EXPR] = "...";
+ opname_tab[(int) CONVERT_EXPR] = "+";
+ opname_tab[(int) ADDR_EXPR] = "&";
opname_tab[(int) PREDECREMENT_EXPR] = "--";
opname_tab[(int) PREINCREMENT_EXPR] = "++";
opname_tab[(int) POSTDECREMENT_EXPR] = "--";
@@ -785,7 +866,7 @@ init_lex ()
#if 0
/* let's parse things, and if they use it, then give them an error. */
- if (!flag_handle_exceptions)
+ if (!flag_exceptions)
{
UNSET_RESERVED_WORD ("throw");
UNSET_RESERVED_WORD ("try");
@@ -793,11 +874,12 @@ init_lex ()
}
#endif
- if (! (flag_gc || flag_rtti) || flag_no_gnu_keywords)
+ if (!flag_rtti || flag_no_gnu_keywords)
{
UNSET_RESERVED_WORD ("classof");
UNSET_RESERVED_WORD ("headof");
}
+
if (! flag_handle_signatures || flag_no_gnu_keywords)
{
/* Easiest way to not recognize signature
@@ -822,11 +904,21 @@ init_lex ()
UNSET_RESERVED_WORD ("xor");
UNSET_RESERVED_WORD ("xor_eq");
}
- if (! flag_traditional)
- UNSET_RESERVED_WORD ("overload");
- token_count = init_parse ();
+ token_count = init_cpp_parse ();
interface_unknown = 1;
+
+ return filename;
+}
+
+void
+finish_parse ()
+{
+#if USE_CPPLIB
+ cpp_finish (&parse_in);
+#else
+ fclose (finput);
+#endif
}
void
@@ -855,10 +947,14 @@ yyprint (file, yychar, yylval)
case IDENTIFIER_DEFN:
case TYPENAME_DEFN:
case PTYPENAME_DEFN:
- case TYPENAME_ELLIPSIS:
case SCSPEC:
case PRE_PARSED_CLASS_DECL:
t = yylval.ttype;
+ if (TREE_CODE (t) == TYPE_DECL || TREE_CODE (t) == TEMPLATE_DECL)
+ {
+ fprintf (file, " `%s'", IDENTIFIER_POINTER (DECL_NAME (t)));
+ break;
+ }
my_friendly_assert (TREE_CODE (t) == IDENTIFIER_NODE, 224);
if (IDENTIFIER_POINTER (t))
fprintf (file, " `%s'", IDENTIFIER_POINTER (t));
@@ -880,27 +976,19 @@ yyprint (file, yychar, yylval)
}
}
+#if defined(GATHER_STATISTICS) && defined(REDUCE_LENGTH)
static int *reduce_count;
+#endif
+
int *token_count;
+#if 0
#define REDUCE_LENGTH (sizeof (yyr2) / sizeof (yyr2[0]))
#define TOKEN_LENGTH (256 + sizeof (yytname) / sizeof (yytname[0]))
-
-int *
-init_parse ()
-{
-#ifdef GATHER_STATISTICS
- reduce_count = (int *)malloc (sizeof (int) * (REDUCE_LENGTH + 1));
- bzero (reduce_count, sizeof (int) * (REDUCE_LENGTH + 1));
- reduce_count += 1;
- token_count = (int *)malloc (sizeof (int) * (TOKEN_LENGTH + 1));
- bzero (token_count, sizeof (int) * (TOKEN_LENGTH + 1));
- token_count += 1;
#endif
- return token_count;
-}
#ifdef GATHER_STATISTICS
+#ifdef REDUCE_LENGTH
void
yyhook (yyn)
int yyn;
@@ -922,11 +1010,13 @@ token_cmp (p, q)
return token_count[*q] - token_count[*p];
}
#endif
+#endif
void
print_parse_statistics ()
{
#ifdef GATHER_STATISTICS
+#ifdef REDUCE_LENGTH
#if YYDEBUG != 0
int i;
int maxlen = REDUCE_LENGTH;
@@ -944,13 +1034,13 @@ print_parse_statistics ()
qsort (sorted, TOKEN_LENGTH, sizeof (int), token_cmp);
for (i = 0; i < TOKEN_LENGTH; i++)
{
- int index = sorted[i];
- if (token_count[index] == 0)
+ int idx = sorted[i];
+ if (token_count[idx] == 0)
break;
- if (token_count[index] < token_count[-1])
+ if (token_count[idx] < token_count[-1])
break;
fprintf (stderr, "token %d, `%s', count = %d\n",
- index, yytname[YYTRANSLATE (index)], token_count[index]);
+ idx, yytname[YYTRANSLATE (idx)], token_count[idx]);
}
fprintf (stderr, "\n");
for (i = 0; i < REDUCE_LENGTH; i++)
@@ -958,22 +1048,24 @@ print_parse_statistics ()
qsort (sorted, REDUCE_LENGTH, sizeof (int), reduce_cmp);
for (i = 0; i < REDUCE_LENGTH; i++)
{
- int index = sorted[i];
- if (reduce_count[index] == 0)
+ int idx = sorted[i];
+ if (reduce_count[idx] == 0)
break;
- if (reduce_count[index] < reduce_count[-1])
+ if (reduce_count[idx] < reduce_count[-1])
break;
fprintf (stderr, "rule %d, line %d, count = %d\n",
- index, yyrline[index], reduce_count[index]);
+ idx, yyrline[idx], reduce_count[idx]);
}
fprintf (stderr, "\n");
#endif
#endif
+#endif
}
/* Sets the value of the 'yydebug' variable to VALUE.
This is a function so we don't have to have YYDEBUG defined
in order to build the compiler. */
+
void
set_yydebug (value)
int value;
@@ -1016,6 +1108,7 @@ static struct impl_files *impl_file_chain;
/* Helper function to load global variables with interface
information. */
+
void
extract_interface_info ()
{
@@ -1032,12 +1125,12 @@ extract_interface_info ()
fileinfo = get_time_identifier (input_filename);
fileinfo = IDENTIFIER_CLASS_VALUE (fileinfo);
interface_only = TREE_INT_CST_LOW (fileinfo);
- if (!processing_template_defn || flag_external_templates)
- interface_unknown = TREE_INT_CST_HIGH (fileinfo);
+ interface_unknown = TREE_INT_CST_HIGH (fileinfo);
}
/* Return nonzero if S is not considered part of an
INTERFACE/IMPLEMENTATION pair. Otherwise, return 0. */
+
static int
interface_strcmp (s)
char *s;
@@ -1076,7 +1169,7 @@ interface_strcmp (s)
return 1;
}
-void
+static void
set_typedecl_interface_info (prev, vars)
tree prev, vars;
{
@@ -1085,10 +1178,10 @@ set_typedecl_interface_info (prev, vars)
tree type = TREE_TYPE (vars);
CLASSTYPE_INTERFACE_ONLY (type) = TREE_INT_CST_LOW (fileinfo)
- = interface_strcmp (FILE_NAME_NONDIRECTORY (DECL_SOURCE_FILE (vars)));
+ = interface_strcmp (file_name_nondirectory (DECL_SOURCE_FILE (vars)));
}
-void
+static int
set_vardecl_interface_info (prev, vars)
tree prev, vars;
{
@@ -1097,22 +1190,26 @@ set_vardecl_interface_info (prev, vars)
if (CLASSTYPE_INTERFACE_KNOWN (type))
{
if (CLASSTYPE_INTERFACE_ONLY (type))
- set_typedecl_interface_info (prev, TYPE_NAME (type));
+ set_typedecl_interface_info (prev, TYPE_MAIN_DECL (type));
else
CLASSTYPE_VTABLE_NEEDS_WRITING (type) = 1;
DECL_EXTERNAL (vars) = CLASSTYPE_INTERFACE_ONLY (type);
TREE_PUBLIC (vars) = 1;
+ return 1;
}
+ return 0;
}
/* Called from the top level: if there are any pending inlines to
do, set up to process them now. This function sets up the first function
to be parsed; after it has been, the rule for fndef in parse.y will
call process_next_inline to start working on the next one. */
+
void
do_pending_inlines ()
{
struct pending_inline *t;
+ tree context;
/* Oops, we're still dealing with the last batch. */
if (yychar == PRE_PARSED_FUNCTION_DECL)
@@ -1121,7 +1218,7 @@ do_pending_inlines ()
/* Reverse the pending inline functions, since
they were cons'd instead of appended. */
{
- struct pending_inline *prev = 0, *tail, *bottom = 0;
+ struct pending_inline *prev = 0, *tail;
t = pending_inlines;
pending_inlines = 0;
@@ -1132,33 +1229,6 @@ do_pending_inlines ()
t->deja_vu = 1;
prev = t;
}
-
- /* This kludge should go away when synthesized methods are handled
- properly, i.e. only when needed. */
- for (t = prev; t; t = t->next)
- {
- if (t->lineno <= 0)
- {
- tree f = t->fndecl;
- DECL_PENDING_INLINE_INFO (f) = 0;
- interface_unknown = t->interface == 1;
- interface_only = t->interface == 0;
- synthesize_method (f);
- if (tail)
- tail->next = t->next;
- else
- prev = t->next;
- if (! bottom)
- bottom = t;
- }
- else
- tail = t;
- }
- if (bottom)
- {
- obstack_free (&synth_obstack, bottom);
- extract_interface_info ();
- }
t = prev;
}
@@ -1166,13 +1236,13 @@ do_pending_inlines ()
return;
/* Now start processing the first inline function. */
- my_friendly_assert ((t->parm_vec == NULL_TREE) == (t->bindings == NULL_TREE),
- 226);
- if (t->parm_vec)
- push_template_decls (t->parm_vec, t->bindings, 0);
+ context = hack_decl_function_context (t->fndecl);
+ if (context)
+ push_cp_function_context (context);
+ maybe_begin_member_template_processing (t->fndecl);
if (t->len > 0)
{
- feed_input (t->buf, t->len, t->can_free ? &inline_text_obstack : 0);
+ feed_input (t->buf, t->len);
lineno = t->lineno;
#if 0
if (input_filename != t->filename)
@@ -1191,68 +1261,51 @@ do_pending_inlines ()
/* Pass back a handle on the rest of the inline functions, so that they
can be processed later. */
yylval.ttype = build_tree_list ((tree) t, t->fndecl);
-#if 0
- if (flag_default_inline && t->fndecl
- /* If we're working from a template, don't change
- the `inline' state. */
- && t->parm_vec == NULL_TREE)
- DECL_INLINE (t->fndecl) = 1;
-#endif
DECL_PENDING_INLINE_INFO (t->fndecl) = 0;
}
-extern struct pending_input *to_be_restored;
static int nextchar = -1;
/* Called from the fndecl rule in the parser when the function just parsed
was declared using a PRE_PARSED_FUNCTION_DECL (i.e. came from
do_pending_inlines). */
+
void
process_next_inline (t)
tree t;
{
+ tree context;
struct pending_inline *i = (struct pending_inline *) TREE_PURPOSE (t);
- my_friendly_assert ((i->parm_vec == NULL_TREE) == (i->bindings == NULL_TREE),
- 227);
- if (i->parm_vec)
- pop_template_decls (i->parm_vec, i->bindings, 0);
+ context = hack_decl_function_context (i->fndecl);
+ maybe_end_member_template_processing (i->fndecl);
+ if (context)
+ pop_cp_function_context (context);
i = i->next;
if (yychar == YYEMPTY)
yychar = yylex ();
if (yychar != END_OF_SAVED_INPUT)
{
error ("parse error at end of saved function text");
+
/* restore_pending_input will abort unless yychar is either
- * END_OF_SAVED_INPUT or YYEMPTY; since we already know we're
- * hosed, feed back YYEMPTY.
- * We also need to discard nextchar, since that may have gotten
- * set as well.
- */
+ END_OF_SAVED_INPUT or YYEMPTY; since we already know we're
+ hosed, feed back YYEMPTY. We also need to discard nextchar,
+ since that may have gotten set as well. */
nextchar = -1;
}
yychar = YYEMPTY;
- if (to_be_restored == 0)
- my_friendly_abort (123);
- restore_pending_input (to_be_restored);
- to_be_restored = 0;
+ end_input ();
if (i && i->fndecl != NULL_TREE)
{
- my_friendly_assert ((i->parm_vec == NULL_TREE) == (i->bindings == NULL_TREE),
- 228);
- if (i->parm_vec)
- push_template_decls (i->parm_vec, i->bindings, 0);
- feed_input (i->buf, i->len, i->can_free ? &inline_text_obstack : 0);
+ context = hack_decl_function_context (i->fndecl);
+ if (context)
+ push_cp_function_context (context);
+ maybe_begin_member_template_processing (i->fndecl);
+ feed_input (i->buf, i->len);
lineno = i->lineno;
input_filename = i->filename;
yychar = PRE_PARSED_FUNCTION_DECL;
yylval.ttype = build_tree_list ((tree) i, i->fndecl);
-#if 0
- if (flag_default_inline
- /* If we're working from a template, don't change
- the `inline' state. */
- && i->parm_vec == NULL_TREE)
- DECL_INLINE (i->fndecl) = 1;
-#endif
DECL_PENDING_INLINE_INFO (i->fndecl) = 0;
}
if (i)
@@ -1367,25 +1420,10 @@ restore_pending_input (p)
free (p);
}
-/* Return next non-whitespace input character, which may come
- from `finput', or from `nextchar'. */
-static int
-yynextch ()
-{
- int c;
-
- if (nextchar >= 0)
- {
- c = nextchar;
- nextchar = -1;
- }
- else c = getch ();
- return skip_white_space (c);
-}
-
/* Unget character CH from the input stream.
If RESCAN is non-zero, then we want to `see' this
character as the next input token. */
+
void
yyungetc (ch, rescan)
int ch;
@@ -1407,106 +1445,30 @@ yyungetc (ch, rescan)
}
}
+void
+clear_inline_text_obstack ()
+{
+ obstack_free (&inline_text_obstack, inline_text_firstobj);
+}
+
/* This function stores away the text for an inline function that should
be processed later. It decides how much later, and may need to move
the info between obstacks; therefore, the caller should not refer to
- the T parameter after calling this function.
-
- This function also stores the list of template-parameter bindings that
- will be needed for expanding the template, if any. */
+ the T parameter after calling this function. */
static void
store_pending_inline (decl, t)
tree decl;
struct pending_inline *t;
{
- extern int processing_template_defn;
- int delay_to_eof = 0;
- struct pending_inline **inlines;
-
t->fndecl = decl;
- /* Default: compile right away, and no extra bindings are needed. */
- t->parm_vec = t->bindings = 0;
- if (processing_template_defn)
- {
- tree type = current_class_type;
- /* Assumption: In this (possibly) nested class sequence, only
- one name will have template parms. */
- while (type && TREE_CODE_CLASS (TREE_CODE (type)) == 't')
- {
- tree decl = TYPE_NAME (type);
- tree tmpl = IDENTIFIER_TEMPLATE (DECL_NAME (decl));
- if (tmpl)
- {
- t->parm_vec = DECL_TEMPLATE_INFO (TREE_PURPOSE (tmpl))->parm_vec;
- t->bindings = TREE_VALUE (tmpl);
- }
- type = DECL_CONTEXT (decl);
- }
- if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE
- || TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)
- {
- if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
- my_friendly_assert (TYPE_MAX_VALUE (TREE_TYPE (decl)) == current_class_type,
- 233);
-
- /* Inline functions can be compiled immediately. Other functions
- will be output separately, so if we're in interface-only mode,
- punt them now, or output them now if we're doing implementations
- and we know no overrides will exist. Otherwise, we delay until
- end-of-file, to see if the definition is really required. */
- if (DECL_THIS_INLINE (decl))
- /* delay_to_eof == 0 */;
- else if (current_class_type && !interface_unknown)
- {
- if (interface_only)
- {
-#if 0
- print_node_brief (stderr, "\ndiscarding text for ", decl, 0);
-#endif
- if (t->can_free)
- obstack_free (&inline_text_obstack, t->buf);
- DECL_PENDING_INLINE_INFO (decl) = 0;
- return;
- }
- }
- /* Don't delay the processing of virtual functions. */
- else if (DECL_VINDEX (decl) == NULL_TREE)
- delay_to_eof = 1;
- }
- else
- my_friendly_abort (58);
- }
-
- if (delay_to_eof)
- {
- extern struct pending_inline *pending_template_expansions;
-
- if (t->can_free)
- {
- char *free_to = t->buf;
- t->buf = (char *) obstack_copy (&permanent_obstack, t->buf,
- t->len + 1);
- t = (struct pending_inline *) obstack_copy (&permanent_obstack,
- (char *)t, sizeof (*t));
- obstack_free (&inline_text_obstack, free_to);
- }
- inlines = &pending_template_expansions;
- t->can_free = 0;
- }
- else
- {
- inlines = &pending_inlines;
- DECL_PENDING_INLINE_INFO (decl) = t;
- }
+ DECL_PENDING_INLINE_INFO (decl) = t;
/* Because we use obstacks, we must process these in precise order. */
- t->next = *inlines;
- *inlines = t;
+ t->next = pending_inlines;
+ pending_inlines = t;
}
-void reinit_parse_for_block ();
-
void
reinit_parse_for_method (yychar, decl)
int yychar;
@@ -1516,7 +1478,7 @@ reinit_parse_for_method (yychar, decl)
int starting_lineno = lineno;
char *starting_filename = input_filename;
- reinit_parse_for_block (yychar, &inline_text_obstack, 0);
+ reinit_parse_for_block (yychar, &inline_text_obstack);
len = obstack_object_size (&inline_text_obstack);
current_base_init_list = NULL_TREE;
@@ -1543,26 +1505,23 @@ reinit_parse_for_method (yychar, decl)
t->token_value = 0;
t->buf = buf;
t->len = len;
- t->can_free = 1;
t->deja_vu = 0;
+#if 0
if (interface_unknown && processing_template_defn && flag_external_templates && ! DECL_IN_SYSTEM_HEADER (decl))
warn_if_unknown_interface (decl);
+#endif
t->interface = (interface_unknown ? 1 : (interface_only ? 0 : 2));
store_pending_inline (decl, t);
}
}
-/* Consume a block -- actually, a method or template definition beginning
- with `:' or `{' -- and save it away on the specified obstack.
+/* Consume a block -- actually, a method beginning
+ with `:' or `{' -- and save it away on the specified obstack. */
- Argument IS_TEMPLATE indicates which set of error messages should be
- output if something goes wrong. This should really be cleaned up somehow,
- without loss of clarity. */
void
-reinit_parse_for_block (pyychar, obstackp, is_template)
+reinit_parse_for_block (pyychar, obstackp)
int pyychar;
struct obstack *obstackp;
- int is_template;
{
register int c = 0;
int blev = 1;
@@ -1582,13 +1541,13 @@ reinit_parse_for_block (pyychar, obstackp, is_template)
look_for_lbrac = 1;
blev = 0;
}
- else if (pyychar == RETURN && !is_template)
+ else if (pyychar == RETURN)
{
obstack_grow (obstackp, "return", 6);
look_for_lbrac = 1;
blev = 0;
}
- else if (pyychar == TRY && !is_template)
+ else if (pyychar == TRY)
{
obstack_grow (obstackp, "try", 3);
look_for_lbrac = 1;
@@ -1596,9 +1555,7 @@ reinit_parse_for_block (pyychar, obstackp, is_template)
}
else
{
- yyerror (is_template
- ? "parse error in template specification"
- : "parse error in method specification");
+ yyerror ("parse error in method specification");
obstack_1grow (obstackp, '{');
}
@@ -1695,9 +1652,7 @@ reinit_parse_for_block (pyychar, obstackp, is_template)
{
if (look_for_lbrac)
{
- error (is_template
- ? "template body missing"
- : "function body for constructor missing");
+ error ("function body for constructor missing");
obstack_1grow (obstackp, '{');
obstack_1grow (obstackp, '}');
len += 2;
@@ -1726,6 +1681,262 @@ reinit_parse_for_block (pyychar, obstackp, is_template)
obstack_1grow (obstackp, '\0');
}
+/* Consume a no-commas expression -- actually, a default argument -- and
+ save it away on the specified obstack. */
+
+static void
+reinit_parse_for_expr (obstackp)
+ struct obstack *obstackp;
+{
+ register int c = 0;
+ int starting_lineno = lineno;
+ char *starting_filename = input_filename;
+ int len;
+ int plev = 0;
+
+ if (nextchar != EOF)
+ {
+ c = nextchar;
+ nextchar = EOF;
+ }
+ else
+ c = getch ();
+
+ while (c != EOF)
+ {
+ int this_lineno = lineno;
+
+ c = skip_white_space (c);
+
+ /* Don't lose our cool if there are lots of comments. */
+ if (lineno == this_lineno + 1)
+ obstack_1grow (obstackp, '\n');
+ else if (lineno == this_lineno)
+ ;
+ else if (lineno - this_lineno < 10)
+ {
+ int i;
+ for (i = lineno - this_lineno; i > 0; --i)
+ obstack_1grow (obstackp, '\n');
+ }
+ else
+ {
+ char buf[16];
+ sprintf (buf, "\n# %d \"", lineno);
+ len = strlen (buf);
+ obstack_grow (obstackp, buf, len);
+
+ len = strlen (input_filename);
+ obstack_grow (obstackp, input_filename, len);
+ obstack_1grow (obstackp, '\"');
+ obstack_1grow (obstackp, '\n');
+ }
+
+ while (c > ' ') /* ASCII dependent... */
+ {
+ if (plev <= 0 && (c == ')' || c == ','))
+ {
+ put_back (c);
+ goto done;
+ }
+ obstack_1grow (obstackp, c);
+ if (c == '(' || c == '[')
+ ++plev;
+ else if (c == ']' || c == ')')
+ --plev;
+ else if (c == '\\')
+ {
+ /* Don't act on the next character...e.g, doing an escaped
+ double-quote. */
+ c = getch ();
+ if (c == EOF)
+ {
+ error_with_file_and_line (starting_filename,
+ starting_lineno,
+ "end of file read inside definition");
+ goto done;
+ }
+ obstack_1grow (obstackp, c);
+ }
+ else if (c == '\"')
+ consume_string (obstackp, c);
+ else if (c == '\'')
+ consume_string (obstackp, c);
+ c = getch ();
+ }
+
+ if (c == EOF)
+ {
+ error_with_file_and_line (starting_filename,
+ starting_lineno,
+ "end of file read inside definition");
+ goto done;
+ }
+ else if (c != '\n')
+ {
+ obstack_1grow (obstackp, c);
+ c = getch ();
+ }
+ }
+ done:
+ obstack_1grow (obstackp, '\0');
+}
+
+int do_snarf_defarg;
+
+/* Decide whether the default argument we are about to see should be
+ gobbled up as text for later parsing. */
+
+void
+maybe_snarf_defarg ()
+{
+ if (current_class_type && TYPE_BEING_DEFINED (current_class_type))
+ do_snarf_defarg = 1;
+}
+
+/* When we see a default argument in a method declaration, we snarf it as
+ text using snarf_defarg. When we get up to namespace scope, we then go
+ through and parse all of them using do_pending_defargs. Since yacc
+ parsers are not reentrant, we retain defargs state in these two
+ variables so that subsequent calls to do_pending_defargs can resume
+ where the previous call left off. */
+
+tree defarg_fns;
+tree defarg_parm;
+
+tree
+snarf_defarg ()
+{
+ int len;
+ char *buf;
+ tree arg;
+
+ reinit_parse_for_expr (&inline_text_obstack);
+ len = obstack_object_size (&inline_text_obstack);
+ buf = obstack_finish (&inline_text_obstack);
+
+ push_obstacks (&inline_text_obstack, &inline_text_obstack);
+ arg = make_node (DEFAULT_ARG);
+ DEFARG_LENGTH (arg) = len - 1;
+ DEFARG_POINTER (arg) = buf;
+ pop_obstacks ();
+
+ return arg;
+}
+
+/* Called from grokfndecl to note a function decl with unparsed default
+ arguments for later processing. Also called from grokdeclarator
+ for function types with unparsed defargs; the call from grokfndecl
+ will always come second, so we can overwrite the entry from the type. */
+
+void
+add_defarg_fn (decl)
+ tree decl;
+{
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ TREE_VALUE (defarg_fns) = decl;
+ else
+ {
+ push_obstacks (&inline_text_obstack, &inline_text_obstack);
+ defarg_fns = tree_cons (current_class_type, decl, defarg_fns);
+ pop_obstacks ();
+ }
+}
+
+/* Helper for do_pending_defargs. Starts the parsing of a default arg. */
+
+static void
+feed_defarg (f, p)
+ tree f, p;
+{
+ tree d = TREE_PURPOSE (p);
+ feed_input (DEFARG_POINTER (d), DEFARG_LENGTH (d));
+ if (TREE_CODE (f) == FUNCTION_DECL)
+ {
+ lineno = DECL_SOURCE_LINE (f);
+ input_filename = DECL_SOURCE_FILE (f);
+ }
+ yychar = DEFARG_MARKER;
+ yylval.ttype = p;
+}
+
+/* Helper for do_pending_defargs. Ends the parsing of a default arg. */
+
+static void
+finish_defarg ()
+{
+ if (yychar == YYEMPTY)
+ yychar = yylex ();
+ if (yychar != END_OF_SAVED_INPUT)
+ {
+ error ("parse error at end of saved function text");
+
+ /* restore_pending_input will abort unless yychar is either
+ END_OF_SAVED_INPUT or YYEMPTY; since we already know we're
+ hosed, feed back YYEMPTY. We also need to discard nextchar,
+ since that may have gotten set as well. */
+ nextchar = -1;
+ }
+ yychar = YYEMPTY;
+ end_input ();
+}
+
+/* Main function for deferred parsing of default arguments. Called from
+ the parser. */
+
+void
+do_pending_defargs ()
+{
+ if (defarg_parm)
+ finish_defarg ();
+
+ for (; defarg_fns; defarg_fns = TREE_CHAIN (defarg_fns))
+ {
+ tree defarg_fn = TREE_VALUE (defarg_fns);
+ if (defarg_parm == NULL_TREE)
+ {
+ push_nested_class (TREE_PURPOSE (defarg_fns), 1);
+ pushlevel (0);
+ if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
+ maybe_begin_member_template_processing (defarg_fn);
+
+ if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
+ {
+#if 0
+ tree p;
+ for (p = DECL_ARGUMENTS (defarg_fn); p; p = TREE_CHAIN (p))
+ pushdecl (copy_node (p));
+#endif
+ defarg_parm = TYPE_ARG_TYPES (TREE_TYPE (defarg_fn));
+ }
+ else
+ defarg_parm = TYPE_ARG_TYPES (defarg_fn);
+ }
+ else
+ defarg_parm = TREE_CHAIN (defarg_parm);
+
+ for (; defarg_parm; defarg_parm = TREE_CHAIN (defarg_parm))
+ if (TREE_PURPOSE (defarg_parm)
+ && TREE_CODE (TREE_PURPOSE (defarg_parm)) == DEFAULT_ARG)
+ {
+ feed_defarg (defarg_fn, defarg_parm);
+
+ /* Return to the parser, which will process this defarg
+ and call us again. */
+ return;
+ }
+
+ if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
+ {
+ maybe_end_member_template_processing (defarg_fn);
+ check_default_args (defarg_fn);
+ }
+
+ poplevel (0, 0, 0);
+ pop_nested_class (1);
+ }
+}
+
/* Build a default function named NAME for type TYPE.
KIND says what to build.
@@ -1743,13 +1954,10 @@ cons_up_default_function (type, full_name, kind)
int kind;
{
extern tree void_list_node;
- char *func_buf = NULL;
- int func_len = 0;
tree declspecs = NULL_TREE;
- tree fn, args;
+ tree fn, args = NULL_TREE;
tree argtype;
int retref = 0;
- int complex = 0;
tree name = constructor_name (full_name);
switch (kind)
@@ -1766,7 +1974,6 @@ cons_up_default_function (type, full_name, kind)
case 2:
/* Default constructor. */
args = void_list_node;
- complex = TYPE_NEEDS_CONSTRUCTING (type);
break;
case 3:
@@ -1780,15 +1987,15 @@ cons_up_default_function (type, full_name, kind)
build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg")),
void_list_node);
- complex = TYPE_HAS_COMPLEX_INIT_REF (type);
break;
case 5:
- type = build_type_variant (type, 1, 0);
- /* Fall through... */
case 6:
retref = 1;
- declspecs = build_decl_list (NULL_TREE, full_name);
+ declspecs = build_decl_list (NULL_TREE, type);
+
+ if (kind == 5)
+ type = build_type_variant (type, 1, 0);
name = ansi_opname [(int) MODIFY_EXPR];
@@ -1797,7 +2004,6 @@ cons_up_default_function (type, full_name, kind)
build_tree_list (hash_tree_chain (argtype, NULL_TREE),
get_identifier ("_ctor_arg")),
void_list_node);
- complex = TYPE_HAS_COMPLEX_ASSIGN_REF (type);
break;
default:
@@ -1810,23 +2016,28 @@ cons_up_default_function (type, full_name, kind)
TREE_PARMLIST (args) = 1;
{
- tree declarator = build_parse_node (CALL_EXPR, name, args, NULL_TREE);
+ tree declarator = make_call_declarator (name, args, NULL_TREE, NULL_TREE);
if (retref)
declarator = build_parse_node (ADDR_EXPR, declarator);
-
- fn = grokfield (declarator, declspecs, NULL_TREE, NULL_TREE,
- NULL_TREE, NULL_TREE);
+
+ fn = grokfield (declarator, declspecs, NULL_TREE, NULL_TREE, NULL_TREE);
}
if (fn == void_type_node)
return fn;
+ if (kind > 2)
+ SET_DECL_ARTIFICIAL (TREE_CHAIN (DECL_ARGUMENTS (fn)));
+
+#if 0
if (processing_template_defn)
{
SET_DECL_IMPLICIT_INSTANTIATION (fn);
repo_template_used (fn);
}
+#endif
+#if 0
if (CLASSTYPE_INTERFACE_KNOWN (type))
{
DECL_INTERFACE_KNOWN (fn) = 1;
@@ -1834,29 +2045,10 @@ cons_up_default_function (type, full_name, kind)
&& flag_implement_inlines);
}
else
+#endif
DECL_NOT_REALLY_EXTERN (fn) = 1;
-#if 0
- /* When on-the-fly synthesis works properly, remove the second and third
- conditions here. */
- if (flag_keep_inline_functions
-#if 0
- || ! flag_no_inline
- || complex
-#endif
- || ! DECL_EXTERNAL (fn))
- {
- struct pending_inline *t;
- t = (struct pending_inline *)
- obstack_alloc (&synth_obstack, sizeof (struct pending_inline));
- t->lineno = -kind;
- t->can_free = 0;
- t->interface = (interface_unknown ? 1 : (interface_only ? 0 : 2));
- store_pending_inline (fn, t);
- }
- else
-#endif
- mark_inline_for_output (fn);
+ mark_inline_for_output (fn);
#ifdef DEBUG_DEFAULT_FUNCTIONS
{ char *fn_type = NULL;
@@ -1888,6 +2080,7 @@ cons_up_default_function (type, full_name, kind)
/* Heuristic to tell whether the user is missing a semicolon
after a struct or enum declaration. Emit an error message
if we know the user has blown it. */
+
void
check_for_missing_semicolon (type)
tree type;
@@ -1898,7 +2091,9 @@ check_for_missing_semicolon (type)
if ((yychar > 255
&& yychar != SCSPEC
&& yychar != IDENTIFIER
- && yychar != TYPENAME)
+ && yychar != TYPENAME
+ && yychar != CV_QUALIFIER
+ && yychar != SELFNAME)
|| end_of_file)
{
if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (type)))
@@ -2020,7 +2215,9 @@ get_last_nonwhite_on_line ()
int linemode;
-int
+static int handle_cp_pragma PROTO((char *));
+
+static int
check_newline ()
{
register int c;
@@ -2064,254 +2261,35 @@ check_newline ()
&& getch () == 'm'
&& getch () == 'a')
{
- /* Read first nonwhite char after the `#pragma'. */
-
- do
- c = getch ();
- while (c == ' ' || c == '\t');
-
- if (c == 'v'
- && getch () == 't'
- && getch () == 'a'
- && getch () == 'b'
- && getch () == 'l'
- && getch () == 'e'
- && ((c = getch ()) == ' ' || c == '\t'))
- {
- extern tree pending_vtables;
-
- /* More follows: it must be a string constant (class name). */
- token = real_yylex ();
- if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST)
- {
- error ("invalid #pragma vtable");
- goto skipline;
- }
- if (write_virtuals != 2)
- {
- warning ("use `+e2' option to enable #pragma vtable");
- goto skipline;
- }
- pending_vtables = perm_tree_cons (NULL_TREE, get_identifier (TREE_STRING_POINTER (yylval.ttype)), pending_vtables);
- if (nextchar < 0)
- nextchar = getch ();
- c = nextchar;
- if (c != EOF)
- warning ("trailing characters ignored");
- }
- else if (c == 'u'
- && getch () == 'n'
- && getch () == 'i'
- && getch () == 't'
- && ((c = getch ()) == ' ' || c == '\t'))
+ token = real_yylex ();
+ if (token == IDENTIFIER
+ && TREE_CODE (yylval.ttype) == IDENTIFIER_NODE)
{
- /* More follows: it must be a string constant (unit name). */
- token = real_yylex ();
- if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST)
- {
- error ("invalid #pragma unit");
- goto skipline;
- }
- current_unit_name = get_identifier (TREE_STRING_POINTER (yylval.ttype));
- current_unit_language = current_lang_name;
- if (nextchar < 0)
- nextchar = getch ();
- c = nextchar;
- if (c != EOF)
- warning ("trailing characters ignored");
+ /* If this is 1, we handled it; if it's -1, it was one we
+ wanted but had something wrong with it. Only if it's
+ 0 was it not handled. */
+ if (handle_cp_pragma (IDENTIFIER_POINTER (yylval.ttype)))
+ goto skipline;
}
- else if (c == 'i')
- {
- tree fileinfo = IDENTIFIER_CLASS_VALUE (get_time_identifier (input_filename));
- c = getch ();
-
- if (c == 'n'
- && getch () == 't'
- && getch () == 'e'
- && getch () == 'r'
- && getch () == 'f'
- && getch () == 'a'
- && getch () == 'c'
- && getch () == 'e'
- && ((c = getch ()) == ' ' || c == '\t' || c == EOF))
- {
- int warned_already = 0;
- char *main_filename = input_filename;
-
- main_filename = FILE_NAME_NONDIRECTORY (main_filename);
- while (c == ' ' || c == '\t')
- c = getch ();
- if (c != EOF)
- {
- put_back (c);
- token = real_yylex ();
- if (token != STRING
- || TREE_CODE (yylval.ttype) != STRING_CST)
- {
- error ("invalid `#pragma interface'");
- goto skipline;
- }
- main_filename = TREE_STRING_POINTER (yylval.ttype);
- c = getch();
- put_back (c);
- }
-
- while (c == ' ' || c == '\t')
- c = getch ();
-
- while (c != EOF)
- {
- if (!warned_already && extra_warnings
- && c != ' ' && c != '\t')
- {
- warning ("garbage after `#pragma interface' ignored");
- warned_already = 1;
- }
- c = getch ();
- }
-
- write_virtuals = 3;
-
- if (impl_file_chain == 0)
- {
- /* If this is zero at this point, then we are
- auto-implementing. */
- if (main_input_filename == 0)
- main_input_filename = input_filename;
-
-#ifdef AUTO_IMPLEMENT
- filename = FILE_NAME_NONDIRECTORY (main_input_filename);
- fi = get_time_identifier (filename);
- fi = IDENTIFIER_CLASS_VALUE (fi);
- TREE_INT_CST_LOW (fi) = 0;
- TREE_INT_CST_HIGH (fi) = 1;
- /* Get default. */
- impl_file_chain = (struct impl_files *)permalloc (sizeof (struct impl_files));
- impl_file_chain->filename = filename;
- impl_file_chain->next = 0;
-#endif
- }
-
- interface_only = interface_strcmp (main_filename);
- interface_unknown = 0;
- TREE_INT_CST_LOW (fileinfo) = interface_only;
- TREE_INT_CST_HIGH (fileinfo) = interface_unknown;
- }
- else if (c == 'm'
- && getch () == 'p'
- && getch () == 'l'
- && getch () == 'e'
- && getch () == 'm'
- && getch () == 'e'
- && getch () == 'n'
- && getch () == 't'
- && getch () == 'a'
- && getch () == 't'
- && getch () == 'i'
- && getch () == 'o'
- && getch () == 'n'
- && ((c = getch ()) == ' ' || c == '\t' || c == EOF))
- {
- int warned_already = 0;
- char *main_filename = main_input_filename ? main_input_filename : input_filename;
-
- main_filename = FILE_NAME_NONDIRECTORY (main_filename);
- while (c == ' ' || c == '\t')
- c = getch ();
- if (c != EOF)
- {
- put_back (c);
- token = real_yylex ();
- if (token != STRING
- || TREE_CODE (yylval.ttype) != STRING_CST)
- {
- error ("invalid `#pragma implementation'");
- goto skipline;
- }
- main_filename = TREE_STRING_POINTER (yylval.ttype);
- c = getch();
- put_back (c);
- }
-
- while (c == ' ' || c == '\t')
- c = getch ();
-
- while (c != EOF)
- {
- if (!warned_already && extra_warnings
- && c != ' ' && c != '\t')
- {
- warning ("garbage after `#pragma implementation' ignored");
- warned_already = 1;
- }
- c = getch ();
- }
+ else if (token == END_OF_LINE)
+ goto skipline;
- if (write_virtuals == 3)
- {
- struct impl_files *ifiles = impl_file_chain;
- while (ifiles)
- {
- if (! strcmp (ifiles->filename, main_filename))
- break;
- ifiles = ifiles->next;
- }
- if (ifiles == 0)
- {
- ifiles = (struct impl_files*) permalloc (sizeof (struct impl_files));
- ifiles->filename = main_filename;
- ifiles->next = impl_file_chain;
- impl_file_chain = ifiles;
- }
- }
- else if ((main_input_filename != 0
- && ! strcmp (main_input_filename, input_filename))
- || ! strcmp (input_filename, main_filename))
- {
- write_virtuals = 3;
- if (impl_file_chain == 0)
- {
- impl_file_chain = (struct impl_files*) permalloc (sizeof (struct impl_files));
- impl_file_chain->filename = main_filename;
- impl_file_chain->next = 0;
- }
- }
- else
- error ("`#pragma implementation' can only appear at top-level");
- interface_only = 0;
-#if 1
- /* We make this non-zero so that we infer decl linkage
- in the impl file only for variables first declared
- in the interface file. */
- interface_unknown = 1;
-#else
- /* We make this zero so that templates in the impl
- file will be emitted properly. */
- interface_unknown = 0;
-#endif
- TREE_INT_CST_LOW (fileinfo) = interface_only;
- TREE_INT_CST_HIGH (fileinfo) = interface_unknown;
- }
- }
#ifdef HANDLE_SYSV_PRAGMA
- else
- {
- put_back (c);
- handle_sysv_pragma ();
- }
+ if (handle_sysv_pragma (token))
+ goto skipline;
#else
#ifdef HANDLE_PRAGMA
- /* FIXME: This will break if we're doing any of the C++ input
- tricks. */
- else
- {
- ungetc (c, finput);
- HANDLE_PRAGMA (finput);
- }
+#if USE_CPPLIB
+ /* TODO: ??? */
+ goto skipline;
+#else
+ if (HANDLE_PRAGMA (finput, yylval.ttype))
+ goto skipline;
+#endif /* !USE_CPPLIB */
#endif
#endif
- goto skipline;
}
+ goto skipline;
}
else if (c == 'd')
{
@@ -2322,11 +2300,7 @@ check_newline ()
&& getch () == 'e'
&& ((c = getch ()) == ' ' || c == '\t'))
{
-#ifdef DWARF_DEBUGGING_INFO
- if ((debug_info_level == DINFO_LEVEL_VERBOSE)
- && (write_symbols == DWARF_DEBUG))
- dwarfout_define (lineno, get_directive_line (finput));
-#endif /* DWARF_DEBUGGING_INFO */
+ debug_define (lineno, GET_DIRECTIVE_LINE ());
goto skipline;
}
}
@@ -2338,11 +2312,7 @@ check_newline ()
&& getch () == 'f'
&& ((c = getch ()) == ' ' || c == '\t'))
{
-#ifdef DWARF_DEBUGGING_INFO
- if ((debug_info_level == DINFO_LEVEL_VERBOSE)
- && (write_symbols == DWARF_DEBUG))
- dwarfout_undef (lineno, get_directive_line (finput));
-#endif /* DWARF_DEBUGGING_INFO */
+ debug_undef (lineno, GET_DIRECTIVE_LINE ());
goto skipline;
}
}
@@ -2362,23 +2332,14 @@ check_newline ()
&& getch () == 't'
&& ((c = getch ()) == ' ' || c == '\t'))
{
-#ifdef ASM_OUTPUT_IDENT
- extern FILE *asm_out_file;
-#endif
/* #ident. The pedantic warning is now in cccp.c. */
/* Here we have just seen `#ident '.
A string constant should follow. */
- while (c == ' ' || c == '\t')
- c = getch ();
-
- /* If no argument, ignore the line. */
- if (c == EOF)
- goto skipline;
-
- put_back (c);
token = real_yylex ();
+ if (token == END_OF_LINE)
+ goto skipline;
if (token != STRING
|| TREE_CODE (yylval.ttype) != STRING_CST)
{
@@ -2483,9 +2444,6 @@ linenum:
body_time = this_time;
}
- if (flag_cadillac)
- cadillac_note_source ();
-
input_filename
= (char *) permalloc (TREE_STRING_LENGTH (yylval.ttype) + 1);
strcpy (input_filename, TREE_STRING_POINTER (yylval.ttype));
@@ -2500,7 +2458,7 @@ linenum:
{
while (ifiles->next)
ifiles = ifiles->next;
- ifiles->filename = FILE_NAME_NONDIRECTORY (input_filename);
+ ifiles->filename = file_name_nondirectory (input_filename);
}
main_input_filename = input_filename;
@@ -2590,13 +2548,7 @@ linenum:
p->name = input_filename;
input_file_stack = p;
input_file_stack_tick++;
-#ifdef DWARF_DEBUGGING_INFO
- if (debug_info_level == DINFO_LEVEL_VERBOSE
- && write_symbols == DWARF_DEBUG)
- dwarfout_start_new_source_file (input_filename);
-#endif /* DWARF_DEBUGGING_INFO */
- if (flag_cadillac)
- cadillac_push_source ();
+ debug_start_source_file (input_filename);
in_system_header = entering_system_header;
if (c_header_level)
++c_header_level;
@@ -2619,29 +2571,19 @@ linenum:
warning ("badly nested C headers from preprocessor");
--pending_lang_change;
}
- if (flag_cadillac)
- cadillac_pop_source ();
in_system_header = entering_system_header;
p = input_file_stack;
input_file_stack = p->next;
free (p);
input_file_stack_tick++;
-#ifdef DWARF_DEBUGGING_INFO
- if (debug_info_level == DINFO_LEVEL_VERBOSE
- && write_symbols == DWARF_DEBUG)
- dwarfout_resume_previous_source_file (input_file_stack->line);
-#endif /* DWARF_DEBUGGING_INFO */
+ debug_end_source_file (input_file_stack->line);
}
else
error ("#-lines for entering and leaving files don't match");
}
else
- {
- in_system_header = entering_system_header;
- if (flag_cadillac)
- cadillac_switch_source (-1);
- }
+ in_system_header = entering_system_header;
}
/* If NEXTCHAR is not end of line, we don't care what it is. */
@@ -2655,6 +2597,7 @@ linenum:
skipline:
linemode = 0;
end_of_file = 0;
+ nextchar = -1;
while ((c = getch ()) != EOF && c != '\n');
return c;
}
@@ -2668,13 +2611,6 @@ do_pending_lang_change ()
pop_lang_context ();
}
-#if 0
-#define isalnum(char) (char >= 'a' ? char <= 'z' : char >= '0' ? char <= '9' || (char >= 'A' && char <= 'Z') : 0)
-#define isdigit(char) (char >= '0' && char <= '9')
-#else
-#include <ctype.h>
-#endif
-
#define ENDFILE -1 /* token that represents end-of-file */
/* Read an escape sequence, returning its equivalent as a character,
@@ -2687,25 +2623,19 @@ readescape (ignore_ptr)
register int c = getch ();
register int code;
register unsigned count;
- unsigned firstdig;
+ unsigned firstdig = 0;
int nonnull;
switch (c)
{
case 'x':
- if (warn_traditional)
- warning ("the meaning of `\\x' varies with -traditional");
-
- if (flag_traditional)
- return c;
-
code = 0;
count = 0;
nonnull = 0;
while (1)
{
c = getch ();
- if (! isxdigit (c))
+ if (! ISXDIGIT (c))
{
put_back (c);
break;
@@ -2773,11 +2703,6 @@ readescape (ignore_ptr)
return TARGET_BS;
case 'a':
- if (warn_traditional)
- warning ("the meaning of `\\a' varies with -traditional");
-
- if (flag_traditional)
- return c;
return TARGET_BELL;
case 'v':
@@ -2812,46 +2737,47 @@ readescape (ignore_ptr)
/* Value is 1 (or 2) if we should try to make the next identifier look like
a typename (when it may be a local variable or a class variable).
Value is 0 if we treat this name in a default fashion. */
-int looking_for_typename = 0;
-
-#if 0
-/* NO LONGER USED: Value is -1 if we must not see a type name. */
-void
-dont_see_typename ()
-{
- looking_for_typename = -1;
- if (yychar == TYPENAME || yychar == PTYPENAME)
- {
- yychar = IDENTIFIER;
- lastiddecl = 0;
- }
-}
-#endif
+int looking_for_typename;
#ifdef __GNUC__
-extern __inline int identifier_type ();
__inline
#endif
int
identifier_type (decl)
tree decl;
{
- if (TREE_CODE (decl) == TEMPLATE_DECL
- && DECL_TEMPLATE_IS_CLASS (decl))
- return PTYPENAME;
+ if (TREE_CODE (decl) == TEMPLATE_DECL)
+ {
+ if (TREE_CODE (DECL_RESULT (decl)) == TYPE_DECL)
+ return PTYPENAME;
+ else if (looking_for_template)
+ return PFUNCNAME;
+ }
+ if (looking_for_template && really_overloaded_fn (decl))
+ {
+ tree t;
+ for (t = decl; t != NULL_TREE; t = OVL_CHAIN (t))
+ if (DECL_FUNCTION_TEMPLATE_P (OVL_FUNCTION (t)))
+ return PFUNCNAME;
+ }
if (TREE_CODE (decl) == NAMESPACE_DECL)
return NSNAME;
if (TREE_CODE (decl) != TYPE_DECL)
return IDENTIFIER;
+ if (((got_scope && TREE_TYPE (decl) == got_scope)
+ || TREE_TYPE (decl) == current_class_type)
+ && DECL_ARTIFICIAL (decl))
+ return SELFNAME;
return TYPENAME;
}
void
see_typename ()
{
- looking_for_typename = 1;
+ /* Only types expected, not even namespaces. */
+ looking_for_typename = 2;
if (yychar < 0)
- if ((yychar = yylex()) < 0) yychar = 0;
+ if ((yychar = yylex ()) < 0) yychar = 0;
looking_for_typename = 0;
if (yychar == IDENTIFIER)
{
@@ -2866,20 +2792,44 @@ see_typename ()
}
}
+/* Return true if d is in a global scope. */
+
+static int
+is_global (d)
+ tree d;
+{
+ while (1)
+ switch (TREE_CODE (d))
+ {
+ case OVERLOAD: d = OVL_FUNCTION (d); continue;
+ case TREE_LIST: d = TREE_VALUE (d); continue;
+ default:
+ my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (d)) == 'd', 980629);
+ d = CP_DECL_CONTEXT (d);
+ return TREE_CODE (d) == NAMESPACE_DECL;
+ }
+}
+
tree
-do_identifier (token)
+do_identifier (token, parsing, args)
register tree token;
+ int parsing;
+ tree args;
{
- register tree id = lastiddecl;
+ register tree id;
+ int lexing = (parsing == 1);
+ int in_call = (parsing == 2);
+
+ if (! lexing || IDENTIFIER_OPNAME_P (token))
+ id = lookup_name (token, 0);
+ else
+ id = lastiddecl;
- if (yychar == YYEMPTY)
- yychar = yylex ();
/* Scope class declarations before global
declarations. */
- if (id == IDENTIFIER_GLOBAL_VALUE (token)
+ if ((!id || is_global (id))
&& current_class_type != 0
- && TYPE_SIZE (current_class_type) == 0
- && TREE_CODE (current_class_type) != UNINSTANTIATED_P_TYPE)
+ && TYPE_SIZE (current_class_type) == 0)
{
/* Could be from one of the base classes. */
tree field = lookup_field (current_class_type, token, 1, 0);
@@ -2890,7 +2840,8 @@ do_identifier (token)
But we still want to return this value. */
id = lookup_field (current_class_type, token, 0, 0);
else if (TREE_CODE (field) == VAR_DECL
- || TREE_CODE (field) == CONST_DECL)
+ || TREE_CODE (field) == CONST_DECL
+ || TREE_CODE (field) == TEMPLATE_DECL)
id = field;
else if (TREE_CODE (field) != FIELD_DECL)
my_friendly_abort (61);
@@ -2903,11 +2854,25 @@ do_identifier (token)
}
}
+ /* Do Koenig lookup if appropriate (inside templates we build lookup
+ expressions instead). */
+ if (args && !current_template_parms && (!id || is_global (id)))
+ {
+ /* If we have arguments and we only found global names,
+ do Koenig lookup. */
+ id = lookup_arg_dependent (token, id, args);
+ }
+
/* Remember that this name has been used in the class definition, as per
[class.scope0] */
- if (id && current_class_type
+ if (id && current_class_type && parsing
&& TYPE_BEING_DEFINED (current_class_type)
- && ! IDENTIFIER_CLASS_VALUE (token))
+ && ! IDENTIFIER_CLASS_VALUE (token)
+ /* Avoid breaking if we get called for a default argument that
+ refers to an overloaded method. Eventually this will not be
+ necessary, since default arguments shouldn't be parsed until
+ after the class is complete. (jason 3/12/97) */
+ && TREE_CODE (id) != OVERLOAD)
pushdecl_class_level (id);
if (!id || id == error_mark_node)
@@ -2920,7 +2885,16 @@ do_identifier (token)
if (id && id != error_mark_node && TREE_TYPE (id) == error_mark_node)
return id;
}
- if (yychar == '(' || yychar == LEFT_RIGHT)
+
+ if (current_template_parms)
+ return build_min_nt (LOOKUP_EXPR, token, NULL_TREE);
+ else if (IDENTIFIER_OPNAME_P (token))
+ {
+ if (token != ansi_opname[ERROR_MARK])
+ cp_error ("`%D' not defined", token);
+ id = error_mark_node;
+ }
+ else if (in_call)
{
id = implicitly_declare (token);
}
@@ -2931,7 +2905,7 @@ do_identifier (token)
}
else
{
- if (IDENTIFIER_GLOBAL_VALUE (token) != error_mark_node
+ if (IDENTIFIER_NAMESPACE_VALUE (token) != error_mark_node
|| IDENTIFIER_ERROR_LOCUS (token) != current_function_decl)
{
static int undeclared_variable_notice;
@@ -2947,7 +2921,7 @@ do_identifier (token)
}
id = error_mark_node;
/* Prevent repeated error messages. */
- IDENTIFIER_GLOBAL_VALUE (token) = error_mark_node;
+ SET_IDENTIFIER_NAMESPACE_VALUE (token, error_mark_node);
SET_IDENTIFIER_ERROR_LOCUS (token, current_function_decl);
}
}
@@ -2955,6 +2929,11 @@ do_identifier (token)
if (TREE_CODE (id) == VAR_DECL && DECL_DEAD_FOR_LOCAL (id))
{
tree shadowed = DECL_SHADOWED_FOR_VAR (id);
+ while (shadowed != NULL_TREE && TREE_CODE (shadowed) == VAR_DECL
+ && DECL_DEAD_FOR_LOCAL (shadowed))
+ shadowed = DECL_SHADOWED_FOR_VAR (shadowed);
+ if (!shadowed)
+ shadowed = IDENTIFIER_NAMESPACE_VALUE (DECL_NAME (id));
if (shadowed)
{
if (!DECL_ERROR_REPORTED (id))
@@ -2992,20 +2971,109 @@ do_identifier (token)
if (IDENTIFIER_CLASS_VALUE (token) == id)
{
/* Check access. */
- enum access_type access
- = compute_access (TYPE_BINFO (current_class_type), id);
- if (access == access_private)
+ tree access = compute_access (TYPE_BINFO (current_class_type), id);
+ if (access == access_private_node)
cp_error ("enum `%D' is private", id);
/* protected is OK, since it's an enum of `this'. */
}
- id = DECL_INITIAL (id);
+ if (! processing_template_decl
+ || (DECL_INITIAL (id)
+ && TREE_CODE (DECL_INITIAL (id)) == TEMPLATE_PARM_INDEX))
+ id = DECL_INITIAL (id);
}
else
- id = hack_identifier (id, token, yychar);
+ id = hack_identifier (id, token);
+
+ if (current_template_parms)
+ {
+ if (is_overloaded_fn (id))
+ {
+ tree t = build_min (LOOKUP_EXPR, unknown_type_node,
+ token, get_first_fn (id));
+ if (id != IDENTIFIER_NAMESPACE_VALUE (token))
+ TREE_OPERAND (t, 1) = error_mark_node;
+ id = t;
+ }
+ else if (! TREE_PERMANENT (id) || TREE_CODE (id) == PARM_DECL
+ || TREE_CODE (id) == USING_DECL)
+ id = build_min (LOOKUP_EXPR, TREE_TYPE (id), token, error_mark_node);
+ /* else just use the decl */
+ }
+
return id;
}
tree
+do_scoped_id (token, parsing)
+ tree token;
+ int parsing;
+{
+ tree id;
+ /* during parsing, this is ::name. Otherwise, it is black magic. */
+ if (parsing)
+ {
+ struct tree_binding _b;
+ id = binding_init (&_b);
+ if (!qualified_lookup_using_namespace (token, global_namespace, id, 0))
+ id = NULL_TREE;
+ else
+ id = BINDING_VALUE (id);
+ }
+ else
+ id = IDENTIFIER_GLOBAL_VALUE (token);
+ if (parsing && yychar == YYEMPTY)
+ yychar = yylex ();
+ if (! id)
+ {
+ if (processing_template_decl)
+ {
+ id = build_min_nt (LOOKUP_EXPR, token, NULL_TREE);
+ LOOKUP_EXPR_GLOBAL (id) = 1;
+ return id;
+ }
+ if (parsing && (yychar == '(' || yychar == LEFT_RIGHT))
+ id = implicitly_declare (token);
+ else
+ {
+ if (IDENTIFIER_NAMESPACE_VALUE (token) != error_mark_node)
+ error ("undeclared variable `%s' (first use here)",
+ IDENTIFIER_POINTER (token));
+ id = error_mark_node;
+ /* Prevent repeated error messages. */
+ SET_IDENTIFIER_NAMESPACE_VALUE (token, error_mark_node);
+ }
+ }
+ else
+ {
+ if (TREE_CODE (id) == ADDR_EXPR)
+ mark_used (TREE_OPERAND (id, 0));
+ else if (TREE_CODE (id) != OVERLOAD)
+ mark_used (id);
+ }
+ if (TREE_CODE (id) == CONST_DECL && ! processing_template_decl)
+ {
+ /* XXX CHS - should we set TREE_USED of the constant? */
+ id = DECL_INITIAL (id);
+ /* This is to prevent an enum whose value is 0
+ from being considered a null pointer constant. */
+ id = build1 (NOP_EXPR, TREE_TYPE (id), id);
+ TREE_CONSTANT (id) = 1;
+ }
+
+ if (processing_template_decl)
+ {
+ if (is_overloaded_fn (id))
+ {
+ id = build_min (LOOKUP_EXPR, unknown_type_node,
+ token, get_first_fn (id));
+ LOOKUP_EXPR_GLOBAL (id) = 1;
+ }
+ /* else just use the decl */
+ }
+ return convert_from_reference (id);
+}
+
+tree
identifier_typedecl_value (node)
tree node;
{
@@ -3021,35 +3089,17 @@ identifier_typedecl_value (node)
}
do (IDENTIFIER_LOCAL_VALUE (node));
do (IDENTIFIER_CLASS_VALUE (node));
- do (IDENTIFIER_GLOBAL_VALUE (node));
+ do (IDENTIFIER_NAMESPACE_VALUE (node));
#undef do
/* Will this one ever happen? */
- if (TYPE_NAME (type))
- return TYPE_NAME (type);
+ if (TYPE_MAIN_DECL (type))
+ return TYPE_MAIN_DECL (type);
/* We used to do an internal error of 62 here, but instead we will
handle the return of a null appropriately in the callers. */
return NULL_TREE;
}
-struct try_type
-{
- tree *node_var;
- char unsigned_flag;
- char long_flag;
- char long_long_flag;
-};
-
-struct try_type type_sequence[] =
-{
- { &integer_type_node, 0, 0, 0},
- { &unsigned_type_node, 1, 0, 0},
- { &long_integer_type_node, 0, 1, 0},
- { &long_unsigned_type_node, 1, 1, 0},
- { &long_long_integer_type_node, 0, 1, 1},
- { &long_long_unsigned_type_node, 1, 1, 1}
-};
-
int
real_yylex ()
{
@@ -3103,21 +3153,17 @@ real_yylex ()
value = END_OF_SAVED_INPUT;
else if (linemode)
value = END_OF_LINE;
- else if (do_pending_expansions ())
- /* this will set yychar for us */
- return yychar;
else
value = ENDFILE;
break;
case '$':
- if (dollars_in_ident)
- {
- dollar_seen = 1;
- goto letter;
- }
- value = '$';
- goto done;
+ if (! dollars_in_ident)
+ error ("`$' in identifier");
+ else if (pedantic)
+ pedwarn ("`$' in identifier");
+ dollar_seen = 1;
+ goto letter;
case 'L':
/* Capital L may start a wide-string or wide-character constant. */
@@ -3166,15 +3212,21 @@ real_yylex ()
/* Make this run fast. We know that we are reading straight
from FINPUT in this case (since identifiers cannot straddle
input sources. */
- while (isalnum (c) || (c == '_') || c == '$')
+ while (ISALNUM (c) || (c == '_') || c == '$')
{
- if (c == '$' && ! dollars_in_ident)
- break;
+ if (c == '$')
+ {
+ if (! dollars_in_ident)
+ error ("`$' in identifier");
+ else if (pedantic)
+ pedwarn ("`$' in identifier");
+ }
+
if (p >= token_buffer + maxtoken)
p = extend_token_buffer (p);
*p++ = c;
- c = getc (finput);
+ c = getch ();
}
if (linemode && c == '\n')
@@ -3190,10 +3242,16 @@ real_yylex ()
*p++ = c;
c = getch ();
- while (isalnum (c) || (c == '_') || c == '$')
+ while (ISALNUM (c) || (c == '_') || c == '$')
{
- if (c == '$' && ! dollars_in_ident)
- break;
+ if (c == '$')
+ {
+ if (! dollars_in_ident)
+ error ("`$' in identifier");
+ else if (pedantic)
+ pedwarn ("`$' in identifier");
+ }
+
if (p >= token_buffer + maxtoken)
p = extend_token_buffer (p);
@@ -3213,7 +3271,7 @@ real_yylex ()
{
register struct resword *ptr;
- if (ptr = is_reserved_word (token_buffer, p - token_buffer))
+ if ((ptr = is_reserved_word (token_buffer, p - token_buffer)))
{
if (ptr->rid)
{
@@ -3226,7 +3284,7 @@ real_yylex ()
&& TREE_CODE (IDENTIFIER_GLOBAL_VALUE (old_ttype)) == TYPE_DECL)
looking_for_typename = 0;
else if (ptr->token == AGGR || ptr->token == ENUM)
- looking_for_typename = 1;
+ looking_for_typename = 2;
/* Check if this is a language-type declaration.
Just glimpse the next non-white character. */
@@ -3253,13 +3311,13 @@ real_yylex ()
switch (ptr->rid)
{
case RID_PUBLIC:
- yylval.itype = access_public;
+ yylval.ttype = access_public_node;
break;
case RID_PRIVATE:
- yylval.itype = access_private;
+ yylval.ttype = access_private_node;
break;
case RID_PROTECTED:
- yylval.itype = access_protected;
+ yylval.ttype = access_protected_node;
break;
default:
my_friendly_abort (63);
@@ -3313,14 +3371,6 @@ real_yylex ()
token_buffer[0] = '^';
token_buffer[1] = 0;
}
- else if (ptr->token == NAMESPACE)
- {
- static int warned;
- if (! warned)
- warning ("namespaces are mostly broken in this version of g++");
-
- warned = 1;
- }
value = (int) ptr->token;
}
@@ -3329,18 +3379,6 @@ real_yylex ()
/* If we did not find a keyword, look for an identifier
(or a typename). */
- if (strcmp ("catch", token_buffer) == 0
- || strcmp ("throw", token_buffer) == 0
- || strcmp ("try", token_buffer) == 0)
- {
- static int did_warn = 0;
- if (! did_warn && ! flag_handle_exceptions)
- {
- pedwarn ("`catch', `throw', and `try' are all C++ reserved words");
- did_warn = 1;
- }
- }
-
if (value == IDENTIFIER || value == TYPESPEC)
GNU_xref_ref (current_function_decl, token_buffer);
@@ -3365,30 +3403,6 @@ real_yylex ()
#endif
yylval.ttype = tmp;
-
- /* A user-invisible read-only initialized variable
- should be replaced by its value. We only handle strings
- since that's the only case used in C (and C++). */
- /* Note we go right after the local value for the identifier
- (e.g., __FUNCTION__ or __PRETTY_FUNCTION__). We used to
- call lookup_name, but that could result in an error about
- ambiguities. */
- tmp = IDENTIFIER_LOCAL_VALUE (yylval.ttype);
- if (tmp != NULL_TREE
- && TREE_CODE (tmp) == VAR_DECL
- && DECL_IGNORED_P (tmp)
- && TREE_READONLY (tmp)
- && DECL_INITIAL (tmp) != NULL_TREE
- && TREE_CODE (DECL_INITIAL (tmp)) == STRING_CST)
- {
- tree stringval = DECL_INITIAL (tmp);
-
- /* Copy the string value so that we won't clobber anything
- if we put something in the TREE_CHAIN of this one. */
- yylval.ttype = build_string (TREE_STRING_LENGTH (stringval),
- TREE_STRING_POINTER (stringval));
- value = STRING;
- }
}
if (value == NEW && ! global_bindings_p ())
{
@@ -3421,7 +3435,7 @@ real_yylex ()
}
error ("parse error at `..'");
}
- if (isdigit (c1))
+ if (ISDIGIT (c1))
{
put_back (c1);
goto resume_numerical_scan;
@@ -3435,7 +3449,7 @@ real_yylex ()
/* Optimize for most frequent case. */
{
register int c1 = getch ();
- if (! isalnum (c1) && c1 != '.')
+ if (! ISALNUM (c1) && c1 != '.')
{
/* Terminate string. */
token_buffer[0] = c;
@@ -3450,7 +3464,7 @@ real_yylex ()
}
put_back (c1);
}
- /* fall through... */
+ /* fall through... */
case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
resume_numerical_scan:
@@ -3473,12 +3487,12 @@ real_yylex ()
enum anon1 { NOT_FLOAT, AFTER_POINT, TOO_MANY_POINTS} floatflag
= NOT_FLOAT;
- p = token_buffer;
- *p++ = c;
-
for (count = 0; count < TOTAL_PARTS; count++)
parts[count] = 0;
+ p = token_buffer;
+ *p++ = c;
+
if (c == '0')
{
*p++ = (c = getch ());
@@ -3500,18 +3514,25 @@ real_yylex ()
/* Read all the digits-and-decimal-points. */
while (c == '.'
- || (isalnum (c) && (c != 'l') && (c != 'L')
+ || (ISALNUM (c) && (c != 'l') && (c != 'L')
&& (c != 'u') && (c != 'U')
+ && c != 'i' && c != 'I' && c != 'j' && c != 'J'
&& (floatflag == NOT_FLOAT || ((c != 'f') && (c != 'F')))))
{
if (c == '.')
{
if (base == 16)
error ("floating constant may not be in radix 16");
- if (floatflag == AFTER_POINT)
+ if (floatflag == TOO_MANY_POINTS)
+ /* We have already emitted an error. Don't need another. */
+ ;
+ else if (floatflag == AFTER_POINT)
{
error ("malformed floating constant");
floatflag = TOO_MANY_POINTS;
+ /* Avoid another error from atof by forcing all characters
+ from here on to be ignored. */
+ p[-1] = '\0';
}
else
floatflag = AFTER_POINT;
@@ -3522,7 +3543,7 @@ real_yylex ()
only when it is followed by a digit.
Otherwise, unread the following non-digit
and use the '.' as a structural token. */
- if (p == token_buffer + 2 && !isdigit (c))
+ if (p == token_buffer + 2 && !ISDIGIT (c))
{
if (c == '.')
{
@@ -3547,7 +3568,7 @@ real_yylex ()
/* It is not a decimal point.
It should be a digit (perhaps a hex digit). */
- if (isdigit (c))
+ if (ISDIGIT (c))
{
c = c - '0';
}
@@ -3611,9 +3632,8 @@ real_yylex ()
if (floatflag != NOT_FLOAT)
{
tree type = double_type_node;
- char f_seen = 0;
- char l_seen = 0;
- int garbage_chars = 0;
+ int exceeds_double = 0;
+ int imag = 0;
REAL_VALUE_TYPE value;
jmp_buf handler;
@@ -3630,9 +3650,9 @@ real_yylex ()
*p++ = c;
c = getch ();
}
- if (! isdigit (c))
+ if (! ISDIGIT (c))
error ("floating constant exponent has no digits");
- while (isdigit (c))
+ while (ISDIGIT (c))
{
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
@@ -3652,76 +3672,117 @@ real_yylex ()
}
else
{
+ int fflag = 0, lflag = 0;
+ /* Copy token_buffer now, while it has just the number
+ and not the suffixes; once we add `f' or `i',
+ REAL_VALUE_ATOF may not work any more. */
+ char *copy = (char *) alloca (p - token_buffer + 1);
+ bcopy (token_buffer, copy, p - token_buffer + 1);
+
set_float_handler (handler);
- /* The second argument, machine_mode, of REAL_VALUE_ATOF
- tells the desired precision of the binary result of
- decimal-to-binary conversion. */
- /* Read the suffixes to choose a data type. */
- switch (c)
+ while (1)
{
- case 'f': case 'F':
- type = float_type_node;
- value = REAL_VALUE_ATOF (token_buffer, TYPE_MODE (type));
- garbage_chars = -1;
- break;
+ int lose = 0;
- case 'l': case 'L':
- type = long_double_type_node;
- value = REAL_VALUE_ATOF (token_buffer, TYPE_MODE (type));
- garbage_chars = -1;
- break;
+ /* Read the suffixes to choose a data type. */
+ switch (c)
+ {
+ case 'f': case 'F':
+ if (fflag)
+ error ("more than one `f' in numeric constant");
+ fflag = 1;
+ break;
+
+ case 'l': case 'L':
+ if (lflag)
+ error ("more than one `l' in numeric constant");
+ lflag = 1;
+ break;
+
+ case 'i': case 'I':
+ if (imag)
+ error ("more than one `i' or `j' in numeric constant");
+ else if (pedantic)
+ pedwarn ("ANSI C++ forbids imaginary numeric constants");
+ imag = 1;
+ break;
+
+ default:
+ lose = 1;
+ }
+
+ if (lose)
+ break;
+
+ if (p >= token_buffer + maxtoken - 3)
+ p = extend_token_buffer (p);
+ *p++ = c;
+ *p = 0;
+ c = getch ();
+ }
+
+ /* The second argument, machine_mode, of REAL_VALUE_ATOF
+ tells the desired precision of the binary result
+ of decimal-to-binary conversion. */
- default:
- value = REAL_VALUE_ATOF (token_buffer, TYPE_MODE (type));
+ if (fflag)
+ {
+ if (lflag)
+ error ("both `f' and `l' in floating constant");
+
+ type = float_type_node;
+ value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+ /* A diagnostic is required here by some ANSI C testsuites.
+ This is not pedwarn, become some people don't want
+ an error for this. */
+ if (REAL_VALUE_ISINF (value) && pedantic)
+ warning ("floating point number exceeds range of `float'");
+ }
+ else if (lflag)
+ {
+ type = long_double_type_node;
+ value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+ if (REAL_VALUE_ISINF (value) && pedantic)
+ warning ("floating point number exceeds range of `long double'");
}
+ else
+ {
+ value = REAL_VALUE_ATOF (copy, TYPE_MODE (type));
+ if (REAL_VALUE_ISINF (value) && pedantic)
+ warning ("floating point number exceeds range of `double'");
+ }
+
set_float_handler (NULL_PTR);
}
- if (pedantic
- && (REAL_VALUE_ISINF (value)
#ifdef ERANGE
- || (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT
- && errno == ERANGE
- /* ERANGE is also reported for underflow, so test the
- value to distinguish overflow from that. */
- && (REAL_VALUES_LESS (dconst1, value)
- || REAL_VALUES_LESS (value, dconstm1)))
-#endif
- ))
- {
- pedwarn ("floating point number exceeds range of `%s'",
- IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
- }
- /* Note: garbage_chars is -1 if first char is *not* garbage. */
- while (isalnum (c))
+ if (errno == ERANGE && pedantic)
{
- if (c == 'f' || c == 'F')
- {
- if (f_seen)
- error ("two `f's in floating constant");
- f_seen = 1;
- }
- if (c == 'l' || c == 'L')
+ /* ERANGE is also reported for underflow,
+ so test the value to distinguish overflow from that. */
+ if (REAL_VALUES_LESS (dconst1, value)
+ || REAL_VALUES_LESS (value, dconstm1))
{
- if (l_seen)
- error ("two `l's in floating constant");
- l_seen = 1;
+ pedwarn ("floating point number exceeds range of `%s'",
+ IDENTIFIER_POINTER (TYPE_IDENTIFIER (type)));
+ exceeds_double = 1;
}
- if (p >= token_buffer + maxtoken - 3)
- p = extend_token_buffer (p);
- *p++ = c;
- c = getch ();
- garbage_chars++;
}
+#endif
- if (garbage_chars > 0)
- error ("garbage at end of number");
+ /* If the result is not a number, assume it must have been
+ due to some error message above, so silently convert
+ it to a zero. */
+ if (REAL_VALUE_ISNAN (value))
+ value = dconst0;
/* Create a node with determined type and value. */
- yylval.ttype = build_real (type, value);
-
- put_back (c);
- *p = 0;
+ if (imag)
+ yylval.ttype = build_complex (NULL_TREE,
+ cp_convert (type, integer_zero_node),
+ build_real (type, value));
+ else
+ yylval.ttype = build_real (type, value);
}
else
{
@@ -3730,6 +3791,7 @@ real_yylex ()
int spec_unsigned = 0;
int spec_long = 0;
int spec_long_long = 0;
+ int spec_imag = 0;
int bytes, warn;
while (1)
@@ -3752,29 +3814,22 @@ real_yylex ()
}
spec_long = 1;
}
- else
+ else if (c == 'i' || c == 'j' || c == 'I' || c == 'J')
{
- if (isalnum (c))
- {
- error ("garbage at end of number");
- while (isalnum (c))
- {
- if (p >= token_buffer + maxtoken - 3)
- p = extend_token_buffer (p);
- *p++ = c;
- c = getch ();
- }
- }
- break;
+ if (spec_imag)
+ error ("more than one `i' or `j' in numeric constant");
+ else if (pedantic)
+ pedwarn ("ANSI C++ forbids imaginary numeric constants");
+ spec_imag = 1;
}
+ else
+ break;
if (p >= token_buffer + maxtoken - 3)
p = extend_token_buffer (p);
*p++ = c;
c = getch ();
}
- put_back (c);
-
/* If the constant is not long long and it won't fit in an
unsigned long, or if the constant is long long and won't fit
in an unsigned long long, then warn that the constant is out
@@ -3813,145 +3868,52 @@ real_yylex ()
yylval.ttype = build_int_2 (low, high);
TREE_TYPE (yylval.ttype) = long_long_unsigned_type_node;
-#if 0
- /* Find the first allowable type that the value fits in. */
- type = 0;
- for (i = 0; i < sizeof (type_sequence) / sizeof (type_sequence[0]);
- i++)
- if (!(spec_long && !type_sequence[i].long_flag)
- && !(spec_long_long && !type_sequence[i].long_long_flag)
- && !(spec_unsigned && !type_sequence[i].unsigned_flag)
- /* A hex or octal constant traditionally is unsigned. */
- && !(base != 10 && flag_traditional
- && !type_sequence[i].unsigned_flag)
- /* A decimal constant can't be unsigned int
- unless explicitly specified. */
- && !(base == 10 && !spec_unsigned
- && *type_sequence[i].node_var == unsigned_type_node))
- if (int_fits_type_p (yylval.ttype, *type_sequence[i].node_var))
- {
- type = *type_sequence[i].node_var;
- break;
- }
- if (flag_traditional && type == long_unsigned_type_node
- && !spec_unsigned)
- type = long_integer_type_node;
-
- if (type == 0)
- {
- type = long_long_integer_type_node;
- warning ("integer constant out of range");
- }
-
- /* Warn about some cases where the type of a given constant
- changes from traditional C to ANSI C. */
- if (warn_traditional)
- {
- tree other_type = 0;
-
- /* This computation is the same as the previous one
- except that flag_traditional is used backwards. */
- for (i = 0; i < sizeof (type_sequence) / sizeof (type_sequence[0]);
- i++)
- if (!(spec_long && !type_sequence[i].long_flag)
- && !(spec_long_long && !type_sequence[i].long_long_flag)
- && !(spec_unsigned && !type_sequence[i].unsigned_flag)
- /* A hex or octal constant traditionally is unsigned. */
- && !(base != 10 && !flag_traditional
- && !type_sequence[i].unsigned_flag)
- /* A decimal constant can't be unsigned int
- unless explicitly specified. */
- && !(base == 10 && !spec_unsigned
- && *type_sequence[i].node_var == unsigned_type_node))
- if (int_fits_type_p (yylval.ttype, *type_sequence[i].node_var))
- {
- other_type = *type_sequence[i].node_var;
- break;
- }
- if (!flag_traditional && type == long_unsigned_type_node
- && !spec_unsigned)
- type = long_integer_type_node;
-
- if (other_type != 0 && other_type != type)
- {
- if (flag_traditional)
- warning ("type of integer constant would be different without -traditional");
- else
- warning ("type of integer constant would be different with -traditional");
- }
- }
-
-#else /* 1 */
+ /* Calculate the ANSI type. */
if (!spec_long && !spec_unsigned
- && !(flag_traditional && base != 10)
&& int_fits_type_p (yylval.ttype, integer_type_node))
- {
-#if 0
- if (warn_traditional && base != 10)
- warning ("small nondecimal constant becomes signed in ANSI C++");
-#endif
- type = integer_type_node;
- }
+ type = integer_type_node;
else if (!spec_long && (base != 10 || spec_unsigned)
&& int_fits_type_p (yylval.ttype, unsigned_type_node))
- {
- /* Nondecimal constants try unsigned even in traditional C. */
- type = unsigned_type_node;
- }
-
+ /* Nondecimal constants try unsigned even in traditional C. */
+ type = unsigned_type_node;
else if (!spec_unsigned && !spec_long_long
&& int_fits_type_p (yylval.ttype, long_integer_type_node))
type = long_integer_type_node;
-
- else if (! spec_long_long
- && int_fits_type_p (yylval.ttype,
- long_unsigned_type_node))
- {
-#if 0
- if (warn_traditional && !spec_unsigned)
- warning ("large integer constant becomes unsigned in ANSI C++");
-#endif
- if (flag_traditional && !spec_unsigned)
- type = long_integer_type_node;
- else
- type = long_unsigned_type_node;
- }
-
+ else if (! spec_long_long)
+ type = long_unsigned_type_node;
else if (! spec_unsigned
/* Verify value does not overflow into sign bit. */
&& TREE_INT_CST_HIGH (yylval.ttype) >= 0
&& int_fits_type_p (yylval.ttype,
long_long_integer_type_node))
type = long_long_integer_type_node;
+ else
+ type = long_long_unsigned_type_node;
- else if (int_fits_type_p (yylval.ttype,
- long_long_unsigned_type_node))
- {
-#if 0
- if (warn_traditional && !spec_unsigned)
- warning ("large nondecimal constant is unsigned in ANSI C++");
-#endif
+ if (!int_fits_type_p (yylval.ttype, type) && !warn)
+ pedwarn ("integer constant out of range");
- if (flag_traditional && !spec_unsigned)
- type = long_long_integer_type_node;
- else
- type = long_long_unsigned_type_node;
- }
+ if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type))
+ warning ("decimal integer constant is so large that it is unsigned");
- else
+ if (spec_imag)
{
- type = long_long_integer_type_node;
- warning ("integer constant out of range");
-
- if (base == 10 && ! spec_unsigned && TREE_UNSIGNED (type))
- warning ("decimal integer constant is so large that it is unsigned");
+ if (TYPE_PRECISION (type)
+ <= TYPE_PRECISION (integer_type_node))
+ yylval.ttype
+ = build_complex (NULL_TREE, integer_zero_node,
+ cp_convert (integer_type_node,
+ yylval.ttype));
+ else
+ error ("complex integer constant is too wide for `__complex int'");
}
-#endif
-
- TREE_TYPE (yylval.ttype) = type;
- *p = 0;
+ else
+ TREE_TYPE (yylval.ttype) = type;
}
+ put_back (c);
+ *p = 0;
+
value = CONSTANT; break;
}
@@ -3994,7 +3956,7 @@ real_yylex ()
&& (unsigned) c >= (1 << width))
warning ("escape sequence out of range for character");
#ifdef MAP_CHARACTER
- if (isprint (c))
+ if (ISPRINT (c))
c = MAP_CHARACTER (c);
#endif
}
@@ -4037,7 +3999,7 @@ real_yylex ()
num_chars = max_chars;
error ("character constant too long");
}
- else if (num_chars != 1 && ! flag_traditional)
+ else if (num_chars != 1 && warn_multichar)
warning ("multi-character character constant");
/* If char type is signed, sign-extend the constant. */
@@ -4125,7 +4087,7 @@ real_yylex ()
skipnewline:
c = getch ();
if (c == EOF) {
- error("Unterminated string");
+ error ("Unterminated string");
break;
}
}
@@ -4151,27 +4113,29 @@ real_yylex ()
bzero (widep + (len * WCHAR_BYTES), WCHAR_BYTES);
#else
{
- union { long l; char c[sizeof (long)]; } u;
- int big_endian;
char *wp, *cp;
- /* Determine whether host is little or big endian. */
- u.l = 1;
- big_endian = u.c[sizeof (long) - 1];
- wp = widep + (big_endian ? WCHAR_BYTES - 1 : 0);
-
+ wp = widep + (BYTES_BIG_ENDIAN ? WCHAR_BYTES - 1 : 0);
bzero (widep, (p - token_buffer) * WCHAR_BYTES);
for (cp = token_buffer + 1; cp < p; cp++)
*wp = *cp, wp += WCHAR_BYTES;
len = p - token_buffer - 1;
}
#endif
+ if (processing_template_decl)
+ push_obstacks (&permanent_obstack, &permanent_obstack);
yylval.ttype = build_string ((len + 1) * WCHAR_BYTES, widep);
+ if (processing_template_decl)
+ pop_obstacks ();
TREE_TYPE (yylval.ttype) = wchar_array_type_node;
}
else
{
+ if (processing_template_decl)
+ push_obstacks (&permanent_obstack, &permanent_obstack);
yylval.ttype = build_string (p - token_buffer, token_buffer + 1);
+ if (processing_template_decl)
+ pop_obstacks ();
TREE_TYPE (yylval.ttype) = char_array_type_node;
}
@@ -4373,21 +4337,49 @@ real_yylex ()
done:
/* yylloc.last_line = lineno; */
#ifdef GATHER_STATISTICS
+#ifdef REDUCE_LENGTH
token_count[value] += 1;
#endif
+#endif
return value;
}
+int
+is_rid (t)
+ tree t;
+{
+ return !!is_reserved_word (IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t));
+}
+
+#ifdef GATHER_STATISTICS
+/* The original for tree_node_kind is in the toplevel tree.c; changes there
+ need to be brought into here, unless this were actually put into a header
+ instead. */
+/* Statistics-gathering stuff. */
typedef enum
{
- d_kind, t_kind, s_kind, r_kind, e_kind, c_kind,
- id_kind, op_id_kind, perm_list_kind, temp_list_kind,
- vec_kind, x_kind, lang_decl, lang_type, all_kinds
+ d_kind,
+ t_kind,
+ b_kind,
+ s_kind,
+ r_kind,
+ e_kind,
+ c_kind,
+ id_kind,
+ op_id_kind,
+ perm_list_kind,
+ temp_list_kind,
+ vec_kind,
+ x_kind,
+ lang_decl,
+ lang_type,
+ all_kinds
} tree_node_kind;
+
extern int tree_node_counts[];
extern int tree_node_sizes[];
-extern char *tree_node_kind_names[];
+#endif
/* Place to save freed lang_decls which were allocated on the
permanent_obstack. @@ Not currently used. */
@@ -4428,24 +4420,11 @@ build_lang_decl (code, name, type)
== TREE_PERMANENT (t), 234);
DECL_MAIN_VARIANT (t) = t;
if (current_lang_name == lang_name_cplusplus)
- {
- DECL_LANGUAGE (t) = lang_cplusplus;
-#if 0
-#ifndef NO_AUTO_OVERLOAD
- if (code == FUNCTION_DECL && name != 0
- && ! (IDENTIFIER_LENGTH (name) == 4
- && IDENTIFIER_POINTER (name)[0] == 'm'
- && strcmp (IDENTIFIER_POINTER (name), "main") == 0)
- && ! (IDENTIFIER_LENGTH (name) > 10
- && IDENTIFIER_POINTER (name)[0] == '_'
- && IDENTIFIER_POINTER (name)[1] == '_'
- && strncmp (IDENTIFIER_POINTER (name)+2, "builtin_", 8) == 0))
- TREE_OVERLOADED (name) = 1;
-#endif
-#endif
- }
+ DECL_LANGUAGE (t) = lang_cplusplus;
else if (current_lang_name == lang_name_c)
DECL_LANGUAGE (t) = lang_c;
+ else if (current_lang_name == lang_name_java)
+ DECL_LANGUAGE (t) = lang_java;
else my_friendly_abort (64);
#if 0 /* not yet, should get fixed properly later */
@@ -4459,7 +4438,7 @@ build_lang_decl (code, name, type)
#endif
#ifdef GATHER_STATISTICS
tree_node_counts[(int)lang_decl] += 1;
- tree_node_sizes[(int)lang_decl] += sizeof(struct lang_decl);
+ tree_node_sizes[(int)lang_decl] += sizeof (struct lang_decl);
#endif
return t;
@@ -4506,6 +4485,9 @@ copy_lang_decl (node)
int size;
int *pi;
+ if (! DECL_LANG_SPECIFIC (node))
+ return;
+
if (TREE_CODE (node) == FIELD_DECL)
size = sizeof (struct lang_decl_flags);
else
@@ -4538,10 +4520,9 @@ make_lang_type (code)
pi[--i] = 0;
TYPE_LANG_SPECIFIC (t) = (struct lang_type *) pi;
- CLASSTYPE_AS_LIST (t) = build_tree_list (NULL_TREE, t);
+ CLASSTYPE_AS_LIST (t) = build_expr_list (NULL_TREE, t);
SET_CLASSTYPE_INTERFACE_UNKNOWN_X (t, interface_unknown);
CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
- CLASSTYPE_VBASE_SIZE (t) = integer_zero_node;
TYPE_BINFO (t) = make_binfo (integer_zero_node, t, NULL_TREE, NULL_TREE,
NULL_TREE);
CLASSTYPE_BINFO_AS_LIST (t) = build_tree_list (NULL_TREE, TYPE_BINFO (t));
@@ -4553,40 +4534,13 @@ make_lang_type (code)
#ifdef GATHER_STATISTICS
tree_node_counts[(int)lang_type] += 1;
- tree_node_sizes[(int)lang_type] += sizeof(struct lang_type);
+ tree_node_sizes[(int)lang_type] += sizeof (struct lang_type);
#endif
return t;
}
void
-copy_decl_lang_specific (decl)
- tree decl;
-{
- extern struct obstack *current_obstack, *saveable_obstack;
- register int *old = (int *)DECL_LANG_SPECIFIC (decl);
- struct obstack *obstack = current_obstack;
- register int i = sizeof (struct lang_decl) / sizeof (int);
- register int *pi;
-
- if (! TREE_PERMANENT (decl))
- obstack = saveable_obstack;
- else
- my_friendly_assert (obstack == &permanent_obstack, 237);
-
- pi = (int *) obstack_alloc (obstack, sizeof (struct lang_decl));
- while (i-- > 0)
- pi[i] = old[i];
-
- DECL_LANG_SPECIFIC (decl) = (struct lang_decl *) pi;
-
-#ifdef GATHER_STATISTICS
- tree_node_counts[(int)lang_decl] += 1;
- tree_node_sizes[(int)lang_decl] += sizeof(struct lang_decl);
-#endif
-}
-
-void
dump_time_statistics ()
{
register tree prev = 0, decl, next;
@@ -4604,7 +4558,7 @@ dump_time_statistics ()
for (decl = filename_times; decl; decl = next)
{
next = IDENTIFIER_GLOBAL_VALUE (decl);
- IDENTIFIER_GLOBAL_VALUE (decl) = prev;
+ SET_IDENTIFIER_GLOBAL_VALUE (decl, prev);
prev = decl;
}
@@ -4622,32 +4576,6 @@ compiler_error (s, v, v2)
sprintf (buf, s, v, v2);
error_with_file_and_line (input_filename, lineno, "%s (compiler error)", buf);
}
-
-void
-compiler_error_with_decl (decl, s)
- tree decl;
- char *s;
-{
- char *name;
- count_error (0);
-
- report_error_function (0);
-
- if (TREE_CODE (decl) == PARM_DECL)
- fprintf (stderr, "%s:%d: ",
- DECL_SOURCE_FILE (DECL_CONTEXT (decl)),
- DECL_SOURCE_LINE (DECL_CONTEXT (decl)));
- else
- fprintf (stderr, "%s:%d: ",
- DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl));
-
- name = lang_printable_name (decl);
- if (name)
- fprintf (stderr, s, name);
- else
- fprintf (stderr, s, "((anonymous))");
- fprintf (stderr, " (compiler error)\n");
-}
void
yyerror (string)
@@ -4679,6 +4607,182 @@ yyerror (string)
error (buf, token_buffer);
}
+static int
+handle_cp_pragma (pname)
+ char *pname;
+{
+ register int token;
+
+ if (! strcmp (pname, "vtable"))
+ {
+ extern tree pending_vtables;
+
+ /* More follows: it must be a string constant (class name). */
+ token = real_yylex ();
+ if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST)
+ {
+ error ("invalid #pragma vtable");
+ return -1;
+ }
+
+ if (write_virtuals != 2)
+ {
+ warning ("use `+e2' option to enable #pragma vtable");
+ return -1;
+ }
+ pending_vtables
+ = perm_tree_cons (NULL_TREE,
+ get_identifier (TREE_STRING_POINTER (yylval.ttype)),
+ pending_vtables);
+ token = real_yylex ();
+ if (token != END_OF_LINE)
+ warning ("trailing characters ignored");
+ return 1;
+ }
+ else if (! strcmp (pname, "unit"))
+ {
+ /* More follows: it must be a string constant (unit name). */
+ token = real_yylex ();
+ if (token != STRING || TREE_CODE (yylval.ttype) != STRING_CST)
+ {
+ error ("invalid #pragma unit");
+ return -1;
+ }
+ token = real_yylex ();
+ if (token != END_OF_LINE)
+ warning ("trailing characters ignored");
+ return 1;
+ }
+ else if (! strcmp (pname, "interface"))
+ {
+ tree fileinfo = IDENTIFIER_CLASS_VALUE (get_time_identifier (input_filename));
+ char *main_filename = input_filename;
+
+ main_filename = file_name_nondirectory (main_filename);
+
+ token = real_yylex ();
+
+ if (token != END_OF_LINE)
+ {
+ if (token != STRING
+ || TREE_CODE (yylval.ttype) != STRING_CST)
+ {
+ error ("invalid `#pragma interface'");
+ return -1;
+ }
+ main_filename = TREE_STRING_POINTER (yylval.ttype);
+ token = real_yylex ();
+ }
+
+ if (token != END_OF_LINE)
+ warning ("garbage after `#pragma interface' ignored");
+
+#ifndef NO_LINKAGE_HEURISTICS
+ write_virtuals = 3;
+
+ if (impl_file_chain == 0)
+ {
+ /* If this is zero at this point, then we are
+ auto-implementing. */
+ if (main_input_filename == 0)
+ main_input_filename = input_filename;
+
+#ifdef AUTO_IMPLEMENT
+ filename = file_name_nondirectory (main_input_filename);
+ fi = get_time_identifier (filename);
+ fi = IDENTIFIER_CLASS_VALUE (fi);
+ TREE_INT_CST_LOW (fi) = 0;
+ TREE_INT_CST_HIGH (fi) = 1;
+ /* Get default. */
+ impl_file_chain = (struct impl_files *)permalloc (sizeof (struct impl_files));
+ impl_file_chain->filename = filename;
+ impl_file_chain->next = 0;
+#endif
+ }
+
+ interface_only = interface_strcmp (main_filename);
+ interface_unknown = 0;
+ TREE_INT_CST_LOW (fileinfo) = interface_only;
+ TREE_INT_CST_HIGH (fileinfo) = interface_unknown;
+#endif /* NO_LINKAGE_HEURISTICS */
+
+ return 1;
+ }
+ else if (! strcmp (pname, "implementation"))
+ {
+ tree fileinfo = IDENTIFIER_CLASS_VALUE (get_time_identifier (input_filename));
+ char *main_filename = main_input_filename ? main_input_filename : input_filename;
+
+ main_filename = file_name_nondirectory (main_filename);
+ token = real_yylex ();
+ if (token != END_OF_LINE)
+ {
+ if (token != STRING
+ || TREE_CODE (yylval.ttype) != STRING_CST)
+ {
+ error ("invalid `#pragma implementation'");
+ return -1;
+ }
+ main_filename = TREE_STRING_POINTER (yylval.ttype);
+ token = real_yylex ();
+ }
+
+ if (token != END_OF_LINE)
+ warning ("garbage after `#pragma implementation' ignored");
+
+#ifndef NO_LINKAGE_HEURISTICS
+ if (write_virtuals == 3)
+ {
+ struct impl_files *ifiles = impl_file_chain;
+ while (ifiles)
+ {
+ if (! strcmp (ifiles->filename, main_filename))
+ break;
+ ifiles = ifiles->next;
+ }
+ if (ifiles == 0)
+ {
+ ifiles = (struct impl_files*) permalloc (sizeof (struct impl_files));
+ ifiles->filename = main_filename;
+ ifiles->next = impl_file_chain;
+ impl_file_chain = ifiles;
+ }
+ }
+ else if ((main_input_filename != 0
+ && ! strcmp (main_input_filename, input_filename))
+ || ! strcmp (input_filename, main_filename))
+ {
+ write_virtuals = 3;
+ if (impl_file_chain == 0)
+ {
+ impl_file_chain = (struct impl_files*) permalloc (sizeof (struct impl_files));
+ impl_file_chain->filename = main_filename;
+ impl_file_chain->next = 0;
+ }
+ }
+ else
+ error ("`#pragma implementation' can only appear at top-level");
+ interface_only = 0;
+#if 1
+ /* We make this non-zero so that we infer decl linkage
+ in the impl file only for variables first declared
+ in the interface file. */
+ interface_unknown = 1;
+#else
+ /* We make this zero so that templates in the impl
+ file will be emitted properly. */
+ interface_unknown = 0;
+#endif
+ TREE_INT_CST_LOW (fileinfo) = interface_only;
+ TREE_INT_CST_HIGH (fileinfo) = interface_unknown;
+#endif /* NO_LINKAGE_HEURISTICS */
+
+ return 1;
+ }
+
+ return 0;
+}
+
#ifdef HANDLE_SYSV_PRAGMA
/* Handle a #pragma directive. INPUT is the current input stream,
@@ -4688,11 +4792,13 @@ yyerror (string)
/* This function has to be in this file, in order to get at
the token types. */
-handle_sysv_pragma ()
+static int
+handle_sysv_pragma (token)
+ register int token;
{
for (;;)
{
- switch (yylex ())
+ switch (token)
{
case IDENTIFIER:
case TYPENAME:
@@ -4717,14 +4823,11 @@ handle_sysv_pragma ()
handle_pragma_token (")", NULL_TREE);
break;
case END_OF_LINE:
- handle_pragma_token (NULL_PTR, NULL_TREE);
- return;
default:
handle_pragma_token (NULL_PTR, NULL_TREE);
- while (yylex () != END_OF_LINE)
- /* continue */;
- return;
+ return 1;
}
+ token = real_yylex ();
}
}
#endif /* HANDLE_SYSV_PRAGMA */
diff --git a/contrib/gcc/cp/lex.h b/contrib/gcc/cp/lex.h
index 1cf5687..8df6b76 100644
--- a/contrib/gcc/cp/lex.h
+++ b/contrib/gcc/cp/lex.h
@@ -62,8 +62,10 @@ enum rid
RID_SIGNED,
RID_AUTO,
RID_MUTABLE,
+ RID_COMPLEX,
- /* This is where grokdeclarator ends its search when setting the specbits. */
+ /* This is where grokdeclarator ends its search when setting the
+ specbits. */
RID_PUBLIC,
RID_PRIVATE,
@@ -71,22 +73,23 @@ enum rid
RID_EXCEPTION,
RID_TEMPLATE,
RID_SIGNATURE,
+ RID_NULL,
/* Before adding enough to get up to 64, the RIDBIT_* macros
- will have to be changed a little. */
+ will have to be changed a little. */
RID_MAX
};
#define NORID RID_UNUSED
#define RID_FIRST_MODIFIER RID_EXTERN
-#define RID_LAST_MODIFIER RID_MUTABLE
+#define RID_LAST_MODIFIER RID_COMPLEX
/* The type that can represent all values of RIDBIT. */
-/* We assume that we can stick in at least 32 bits into this. */
+/* We assume that we can stick in at least 32 bits into this. */
typedef struct { unsigned long idata[2]; }
RID_BIT_TYPE;
-/* Be careful, all these modify N twice. */
+/* Be careful, all these modify N twice. */
#define RIDBIT_SETP(N, V) (((unsigned long)1 << (int) ((N)%32)) \
& (V).idata[(N)/32])
#define RIDBIT_NOTSETP(NN, VV) (! RIDBIT_SETP (NN, VV))
@@ -129,7 +132,4 @@ extern tree got_object;
Positive is push count, negative is pop count. */
extern int pending_lang_change;
-extern tree make_pointer_declarator (), make_reference_declarator ();
-extern void reinit_parse_for_function ();
-extern void reinit_parse_for_method ();
-extern int yylex ();
+extern int yylex PROTO((void));
diff --git a/contrib/gcc/cp/method.c b/contrib/gcc/cp/method.c
index a0e1527..29b31c4 100644
--- a/contrib/gcc/cp/method.c
+++ b/contrib/gcc/cp/method.c
@@ -1,9 +1,9 @@
/* Handle the hair of processing (but not expanding) inline functions.
Also manage function and variable name overloading.
- Copyright (C) 1987, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
- This file is part of GNU CC.
+This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,28 +21,33 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#ifndef __GNUC__
+#define __inline
+#endif
+
#ifndef PARM_CAN_BE_ARRAY_TYPE
#define PARM_CAN_BE_ARRAY_TYPE 1
#endif
/* Handle method declarations. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "cp-tree.h"
-#include "class.h"
#include "obstack.h"
-#include <ctype.h>
#include "rtl.h"
#include "expr.h"
#include "output.h"
#include "hard-reg-set.h"
#include "flags.h"
+#include "toplev.h"
/* TREE_LIST of the current inline functions that need to be
processed. */
struct pending_inline *pending_inlines;
+int static_labelno;
+
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
@@ -50,6 +55,38 @@ struct pending_inline *pending_inlines;
static struct obstack scratch_obstack;
static char *scratch_firstobj;
+static void icat PROTO((HOST_WIDE_INT));
+static void dicat PROTO((HOST_WIDE_INT, HOST_WIDE_INT));
+static void flush_repeats PROTO((int, tree));
+static void build_overload_identifier PROTO((tree));
+static void build_overload_nested_name PROTO((tree));
+static void build_overload_int PROTO((tree, int));
+static void build_overload_identifier PROTO((tree));
+static void build_qualified_name PROTO((tree));
+static void build_overload_value PROTO((tree, tree, int));
+static void issue_nrepeats PROTO((int, tree));
+static char *build_mangled_name PROTO((tree,int,int));
+static void process_modifiers PROTO((tree));
+static void process_overload_item PROTO((tree,int));
+static void do_build_assign_ref PROTO((tree));
+static void do_build_copy_constructor PROTO((tree));
+static tree largest_union_member PROTO((tree));
+static tree build_decl_overload_real PROTO((tree, tree, tree, tree,
+ tree, int));
+static void build_template_template_parm_names PROTO((tree));
+static void build_template_parm_names PROTO((tree, tree));
+static void build_underscore_int PROTO((int));
+static void start_squangling PROTO((void));
+static void end_squangling PROTO((void));
+static int check_ktype PROTO((tree, int));
+static int issue_ktype PROTO((tree));
+static void build_overload_scope_ref PROTO((tree));
+static void build_mangled_template_parm_index PROTO((char *, tree));
+static int is_back_referenceable_type PROTO((tree));
+static int check_btype PROTO((tree));
+static void build_mangled_name_for_type PROTO((tree));
+static void build_mangled_name_for_type_with_Gcode PROTO((tree, int));
+
# define OB_INIT() (scratch_firstobj ? (obstack_free (&scratch_obstack, scratch_firstobj), 0) : 0)
# define OB_PUTC(C) (obstack_1grow (&scratch_obstack, (C)))
# define OB_PUTC2(C1,C2) \
@@ -62,10 +99,6 @@ static char *scratch_firstobj;
# define OB_FINISH() (obstack_1grow (&scratch_obstack, '\0'))
# define OB_LAST() (obstack_next_free (&scratch_obstack)[-1])
-#ifdef NO_AUTO_OVERLOAD
-int is_overloaded ();
-#endif
-
void
init_method ()
{
@@ -91,10 +124,12 @@ do_inline_function_hair (type, friend_list)
if (method && TREE_CODE (method) == TREE_VEC)
{
- if (TREE_VEC_ELT (method, 0))
+ if (TREE_VEC_ELT (method, 1))
+ method = TREE_VEC_ELT (method, 1);
+ else if (TREE_VEC_ELT (method, 0))
method = TREE_VEC_ELT (method, 0);
else
- method = TREE_VEC_ELT (method, 1);
+ method = TREE_VEC_ELT (method, 2);
}
while (method)
@@ -112,11 +147,6 @@ do_inline_function_hair (type, friend_list)
DECL_CONTEXT (args) = method;
args = TREE_CHAIN (args);
}
-
- /* Allow this decl to be seen in global scope. Don't do this for
- local class methods, though. */
- if (! current_function_decl)
- IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (method)) = method;
}
method = TREE_CHAIN (method);
}
@@ -135,157 +165,142 @@ do_inline_function_hair (type, friend_list)
DECL_CONTEXT (args) = fndecl;
args = TREE_CHAIN (args);
}
-
- /* Allow this decl to be seen in global scope */
- if (! current_function_decl)
- IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (fndecl)) = fndecl;
}
friend_list = TREE_CHAIN (friend_list);
}
}
-/* Report an argument type mismatch between the best declared function
- we could find and the current argument list that we have. */
-void
-report_type_mismatch (cp, parmtypes, name_kind)
- struct candidate *cp;
- tree parmtypes;
- char *name_kind;
-{
- int i = cp->u.bad_arg;
- tree ttf, tta;
- char *tmp_firstobj;
-
- switch (i)
- {
- case -4:
- my_friendly_assert (TREE_CODE (cp->function) == TEMPLATE_DECL, 240);
- cp_error ("type unification failed for function template `%#D'",
- cp->function);
- return;
-
- case -2:
- cp_error ("too few arguments for %s `%#D'", name_kind, cp->function);
- return;
- case -1:
- cp_error ("too many arguments for %s `%#D'", name_kind, cp->function);
- return;
- case 0:
- if (TREE_CODE (TREE_TYPE (cp->function)) != METHOD_TYPE)
- break;
- case -3:
- /* Happens when the implicit object parameter is rejected. */
- my_friendly_assert (! TYPE_READONLY (TREE_TYPE (TREE_VALUE (parmtypes))),
- 241);
- cp_error ("call to non-const %s `%#D' with const object",
- name_kind, cp->function);
- return;
- }
-
- ttf = TYPE_ARG_TYPES (TREE_TYPE (cp->function));
- tta = parmtypes;
-
- while (i-- > 0)
- {
- ttf = TREE_CHAIN (ttf);
- tta = TREE_CHAIN (tta);
- }
+/* Here is where overload code starts. */
- OB_INIT ();
- OB_PUTS ("bad argument ");
- sprintf (digit_buffer, "%d", cp->u.bad_arg
- - (TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)
- + 1);
- OB_PUTCP (digit_buffer);
-
- OB_PUTS (" for function `");
- OB_PUTCP (decl_as_string (cp->function, 1));
- OB_PUTS ("' (type was ");
-
- /* Reset `i' so that type printing routines do the right thing. */
- if (tta)
- {
- enum tree_code code = TREE_CODE (TREE_TYPE (TREE_VALUE (tta)));
- if (code == ERROR_MARK)
- OB_PUTS ("(failed type instantiation)");
- else
- {
- i = (code == FUNCTION_TYPE || code == METHOD_TYPE);
- OB_PUTCP (type_as_string (TREE_TYPE (TREE_VALUE (tta)), 1));
- }
- }
- else OB_PUTS ("void");
- OB_PUTC (')');
- OB_FINISH ();
+/* type tables for K and B type compression */
+static tree *btypelist = NULL;
+static tree *ktypelist = NULL;
+static int maxbsize = 0;
+static int maxksize = 0;
- tmp_firstobj = (char *)alloca (obstack_object_size (&scratch_obstack));
- bcopy (obstack_base (&scratch_obstack), tmp_firstobj,
- obstack_object_size (&scratch_obstack));
- error (tmp_firstobj);
-}
-
-/* Here is where overload code starts. */
+/* number of each type seen */
+static int maxbtype = 0;
+static int maxktype = 0;
-/* Array of types seen so far in top-level call to `build_overload_name'.
+/* Array of types seen so far in top-level call to `build_mangled_name'.
Allocated and deallocated by caller. */
-static tree *typevec;
-
-/* Number of types interned by `build_overload_name' so far. */
-static int maxtype;
+static tree *typevec = NULL;
+static int typevec_size;
-/* Number of occurrences of last type seen. */
-static int nrepeats;
+/* Number of types interned by `build_mangled_name' so far. */
+static int maxtype = 0;
/* Nonzero if we should not try folding parameter types. */
static int nofold;
-#define ALLOCATE_TYPEVEC(PARMTYPES) \
- do { maxtype = 0, nrepeats = 0; \
- typevec = (tree *)alloca (list_length (PARMTYPES) * sizeof (tree)); } while (0)
+/* This appears to be set to true if an underscore is required to be
+ comcatenated before another number can be outputed. */
+static int numeric_output_need_bar;
-#define DEALLOCATE_TYPEVEC(PARMTYPES) \
- do { tree t = (PARMTYPES); \
- while (t) { TREE_USED (TREE_VALUE (t)) = 0; t = TREE_CHAIN (t); } \
- } while (0)
+static __inline void
+start_squangling ()
+{
+ if (flag_do_squangling)
+ {
+ nofold = 0;
+ maxbtype = 0;
+ maxktype = 0;
+ maxbsize = 50;
+ maxksize = 50;
+ btypelist = (tree *)xmalloc (sizeof (tree) * maxbsize);
+ ktypelist = (tree *)xmalloc (sizeof (tree) * maxksize);
+ }
+}
+
+static __inline void
+end_squangling ()
+{
+ if (flag_do_squangling)
+ {
+ if (ktypelist)
+ free (ktypelist);
+ if (btypelist)
+ free (btypelist);
+ maxbsize = 0;
+ maxksize = 0;
+ maxbtype = 0;
+ maxktype = 0;
+ ktypelist = NULL;
+ btypelist = NULL;
+ }
+}
/* Code to concatenate an asciified integer to a string. */
-static
-#ifdef __GNUC__
-__inline
-#endif
-void
+
+static __inline void
icat (i)
- int i;
+ HOST_WIDE_INT i;
{
+ unsigned HOST_WIDE_INT ui;
+
/* Handle this case first, to go really quickly. For many common values,
- the result of i/10 below is 1. */
+ the result of ui/10 below is 1. */
if (i == 1)
{
OB_PUTC ('1');
return;
}
- if (i < 0)
+ if (i >= 0)
+ ui = i;
+ else
{
OB_PUTC ('m');
- i = -i;
+ ui = -i;
+ }
+
+ if (ui >= 10)
+ icat (ui / 10);
+
+ OB_PUTC ('0' + (ui % 10));
+}
+
+static void
+dicat (lo, hi)
+ HOST_WIDE_INT lo, hi;
+{
+ unsigned HOST_WIDE_INT ulo, uhi, qlo, qhi;
+
+ if (hi >= 0)
+ {
+ uhi = hi;
+ ulo = lo;
}
- if (i < 10)
- OB_PUTC ('0' + i);
else
{
- icat (i / 10);
- OB_PUTC ('0' + (i % 10));
+ uhi = (lo == 0 ? -hi : -hi-1);
+ ulo = -lo;
}
+ if (uhi == 0
+ && ulo < ((unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT - 1)))
+ {
+ icat (ulo);
+ return;
+ }
+ /* Divide 2^HOST_WIDE_INT*uhi+ulo by 10. */
+ qhi = uhi / 10;
+ uhi = uhi % 10;
+ qlo = uhi * (((unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT - 1)) / 5);
+ qlo += ulo / 10;
+ ulo = ulo % 10;
+ ulo += uhi * (((unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT - 1)) % 5)
+ * 2;
+ qlo += ulo / 10;
+ ulo = ulo % 10;
+ /* Quotient is 2^HOST_WIDE_INT*qhi+qlo, remainder is ulo. */
+ dicat (qlo, qhi);
+ OB_PUTC ('0' + ulo);
}
-static
-#ifdef __GNUC__
-__inline
-#endif
-void
-flush_repeats (type)
+static __inline void
+flush_repeats (nrepeats, type)
+ int nrepeats;
tree type;
{
int tindex = 0;
@@ -302,86 +317,327 @@ flush_repeats (type)
}
else
OB_PUTC ('T');
- nrepeats = 0;
icat (tindex);
if (tindex > 9)
OB_PUTC ('_');
}
-static int numeric_output_need_bar;
-static void build_overload_identifier ();
+/* Returns nonzero iff this is a type to which we will want to make
+ back-references (using the `B' code). */
+
+int
+is_back_referenceable_type (type)
+ tree type;
+{
+ if (btypelist == NULL)
+ /* We're not generating any back-references. */
+ return 0;
+
+ switch (TREE_CODE (type))
+ {
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case VOID_TYPE:
+ case BOOLEAN_TYPE:
+ /* These types have single-character manglings, so there's no
+ point in generating back-references. */
+ return 0;
+
+ case TEMPLATE_TYPE_PARM:
+ /* It would be a bit complex to demangle signatures correctly if
+ we generated back-references to these, and the manglings of
+ type parameters are short. */
+ return 0;
+
+ default:
+ return 1;
+ }
+}
+
+/* Issue the squangling code indicating NREPEATS repetitions of TYPE,
+ which was the last parameter type output. */
+
+static void
+issue_nrepeats (nrepeats, type)
+ int nrepeats;
+ tree type;
+{
+ if (nrepeats == 1 && !is_back_referenceable_type (type))
+ /* For types whose manglings are short, don't bother using the
+ repetition code if there's only one repetition, since the
+ repetition code will be about as long as the ordinary mangling. */
+ build_mangled_name_for_type (type);
+ else
+ {
+ OB_PUTC ('n');
+ icat (nrepeats);
+ if (nrepeats > 9)
+ OB_PUTC ('_');
+ }
+}
+
+/* Check to see if a tree node has been entered into the Kcode typelist */
+/* if not, add it. Return -1 if it isn't found, otherwise return the index */
+static int
+check_ktype (node, add)
+ tree node;
+ int add;
+{
+ int x;
+ tree localnode = node;
+
+ if (ktypelist == NULL)
+ return -1;
+
+ if (TREE_CODE (node) == TYPE_DECL)
+ localnode = TREE_TYPE (node);
+
+ for (x=0; x < maxktype; x++)
+ {
+ if (localnode == ktypelist[x])
+ return x ;
+ }
+ /* Didn't find it, so add it here */
+ if (add)
+ {
+ if (maxksize <= maxktype)
+ {
+ maxksize = maxksize* 3 / 2;
+ ktypelist = (tree *)xrealloc (ktypelist, sizeof (tree) * maxksize);
+ }
+ ktypelist[maxktype++] = localnode;
+ }
+ return -1;
+}
+
+
+static __inline int
+issue_ktype (decl)
+ tree decl;
+{
+ int kindex;
+ kindex = check_ktype (decl, FALSE);
+ if (kindex != -1)
+ {
+ OB_PUTC ('K');
+ icat (kindex);
+ if (kindex > 9)
+ OB_PUTC ('_');
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Build a representation for DECL, which may be an entity not at
+ global scope. If so, a marker indicating that the name is
+ qualified has already been output, but the qualifying context has
+ not. */
static void
build_overload_nested_name (decl)
tree decl;
{
- if (DECL_CONTEXT (decl))
+ tree context;
+
+ if (ktypelist && issue_ktype (decl))
+ return;
+
+ if (decl == global_namespace)
+ return;
+
+ context = CP_DECL_CONTEXT (decl);
+
+ /* try to issue a K type, and if we can't continue the normal path */
+ if (!(ktypelist && issue_ktype (context)))
+ {
+ /* For a template type parameter, we want to output an 'Xn'
+ rather than 'T' or some such. */
+ if (TREE_CODE (context) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (context) == TEMPLATE_TEMPLATE_PARM)
+ build_mangled_name_for_type (context);
+ else
{
- tree context = DECL_CONTEXT (decl);
if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
- context = TYPE_MAIN_DECL (context);
+ context = TYPE_NAME (context);
build_overload_nested_name (context);
}
+ }
if (TREE_CODE (decl) == FUNCTION_DECL)
{
tree name = DECL_ASSEMBLER_NAME (decl);
char *label;
- extern int var_labelno;
- ASM_FORMAT_PRIVATE_NAME (label, IDENTIFIER_POINTER (name), var_labelno);
- var_labelno++;
+ ASM_FORMAT_PRIVATE_NAME (label, IDENTIFIER_POINTER (name), static_labelno);
+ static_labelno++;
if (numeric_output_need_bar)
- {
- OB_PUTC ('_');
- numeric_output_need_bar = 0;
- }
+ OB_PUTC ('_');
icat (strlen (label));
OB_PUTCP (label);
+ numeric_output_need_bar = 1;
}
+ else if (TREE_CODE (decl) == NAMESPACE_DECL)
+ build_overload_identifier (DECL_NAME (decl));
else /* TYPE_DECL */
- {
- tree name = DECL_NAME (decl);
- build_overload_identifier (name);
- }
+ build_overload_identifier (decl);
}
-/* Encoding for an INTEGER_CST value. */
+/* Output the decimal representation of I. If I > 9, the decimal
+ representation is preceeded and followed by an underscore. */
+
static void
-build_overload_int (value)
+build_underscore_int (i)
+ int i;
+{
+ if (i > 9)
+ OB_PUTC ('_');
+ icat (i);
+ if (i > 9)
+ OB_PUTC ('_');
+}
+
+static void
+build_overload_scope_ref (value)
tree value;
{
- my_friendly_assert (TREE_CODE (value) == INTEGER_CST, 243);
- if (TYPE_PRECISION (value) == 2 * HOST_BITS_PER_WIDE_INT)
+ OB_PUTC2 ('Q', '2');
+ numeric_output_need_bar = 0;
+ build_mangled_name_for_type (TREE_OPERAND (value, 0));
+ build_overload_identifier (TREE_OPERAND (value, 1));
+}
+
+/* Encoding for an INTEGER_CST value. */
+
+static void
+build_overload_int (value, in_template)
+ tree value;
+ int in_template;
+{
+ if (in_template && TREE_CODE (value) != INTEGER_CST)
{
- if (tree_int_cst_lt (value, integer_zero_node))
+ if (TREE_CODE (value) == SCOPE_REF)
+ {
+ build_overload_scope_ref (value);
+ return;
+ }
+
+ OB_PUTC ('E');
+ numeric_output_need_bar = 0;
+
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (value))))
+ {
+ int i;
+ int operands = tree_code_length[(int) TREE_CODE (value)];
+ tree id;
+ char* name;
+
+ id = ansi_opname [(int) TREE_CODE (value)];
+ my_friendly_assert (id != NULL_TREE, 0);
+ name = IDENTIFIER_POINTER (id);
+ if (name[0] != '_' || name[1] != '_')
+ /* On some erroneous inputs, we can get here with VALUE a
+ LOOKUP_EXPR. In that case, the NAME will be the
+ identifier for "<invalid operator>". We must survive
+ this routine in order to issue a sensible error
+ message, so we fall through to the case below. */
+ goto bad_value;
+
+ for (i = 0; i < operands; ++i)
+ {
+ tree operand;
+ enum tree_code tc;
+
+ /* We just outputted either the `E' or the name of the
+ operator. */
+ numeric_output_need_bar = 0;
+
+ if (i != 0)
+ /* Skip the leading underscores. */
+ OB_PUTCP (name + 2);
+
+ operand = TREE_OPERAND (value, i);
+ tc = TREE_CODE (operand);
+
+ if (TREE_CODE_CLASS (tc) == 't')
+ /* We can get here with sizeof, e.g.:
+
+ template <class T> void f(A<sizeof(T)>); */
+ build_mangled_name_for_type (operand);
+ else if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (tc)))
+ build_overload_int (operand, in_template);
+ else
+ build_overload_value (TREE_TYPE (operand),
+ operand,
+ in_template);
+ }
+ }
+ else
{
- OB_PUTC ('m');
- value = build_int_2 (~ TREE_INT_CST_LOW (value),
- - TREE_INT_CST_HIGH (value));
+ /* We don't ever want this output, but it's
+ inconvenient not to be able to build the string.
+ This should cause assembler errors we'll notice. */
+
+ static int n;
+ bad_value:
+ sprintf (digit_buffer, " *%d", n++);
+ OB_PUTCP (digit_buffer);
}
+
+ OB_PUTC ('W');
+ numeric_output_need_bar = 0;
+ return;
+ }
+
+ my_friendly_assert (TREE_CODE (value) == INTEGER_CST, 243);
+ if (TYPE_PRECISION (TREE_TYPE (value)) == 2 * HOST_BITS_PER_WIDE_INT)
+ {
if (TREE_INT_CST_HIGH (value)
!= (TREE_INT_CST_LOW (value) >> (HOST_BITS_PER_WIDE_INT - 1)))
{
/* need to print a DImode value in decimal */
- sorry ("conversion of long long as PT parameter");
+ dicat (TREE_INT_CST_LOW (value), TREE_INT_CST_HIGH (value));
+ numeric_output_need_bar = 1;
+ return;
}
/* else fall through to print in smaller mode */
}
/* Wordsize or smaller */
icat (TREE_INT_CST_LOW (value));
+ numeric_output_need_bar = 1;
}
+
+/* Output S followed by a representation of the TEMPLATE_PARM_INDEX
+ supplied in INDEX. */
+
+static void
+build_mangled_template_parm_index (s, index)
+ char* s;
+ tree index;
+{
+ OB_PUTCP (s);
+ build_underscore_int (TEMPLATE_PARM_IDX (index));
+ /* We use the LEVEL, not the ORIG_LEVEL, because the mangling is a
+ representation of the function from the point of view of its
+ type. */
+ build_underscore_int (TEMPLATE_PARM_LEVEL (index));
+}
+
+
static void
-build_overload_value (type, value)
+build_overload_value (type, value, in_template)
tree type, value;
+ int in_template;
{
while (TREE_CODE (value) == NON_LVALUE_EXPR
|| TREE_CODE (value) == NOP_EXPR)
value = TREE_OPERAND (value, 0);
- my_friendly_assert (TREE_CODE (type) == PARM_DECL, 242);
- type = TREE_TYPE (type);
+
+ if (TREE_CODE (type) == PARM_DECL)
+ type = TREE_TYPE (type);
+
+ my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (type)) == 't', 0);
if (numeric_output_need_bar)
{
@@ -389,6 +645,12 @@ build_overload_value (type, value)
numeric_output_need_bar = 0;
}
+ if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
+ {
+ build_mangled_template_parm_index ("Y", value);
+ return;
+ }
+
if (TREE_CODE (type) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE)
{
@@ -411,65 +673,82 @@ build_overload_value (type, value)
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
{
- build_overload_int (value);
- numeric_output_need_bar = 1;
+ build_overload_int (value, in_template);
return;
}
-#ifndef REAL_IS_NOT_DOUBLE
case REAL_TYPE:
{
REAL_VALUE_TYPE val;
char *bufp = digit_buffer;
- extern char *index ();
+
+ pedwarn ("ANSI C++ forbids floating-point template arguments");
my_friendly_assert (TREE_CODE (value) == REAL_CST, 244);
val = TREE_REAL_CST (value);
- if (val < 0)
+ if (REAL_VALUE_ISNAN (val))
{
- val = -val;
- *bufp++ = 'm';
+ sprintf (bufp, "NaN");
}
- sprintf (bufp, "%e", val);
- bufp = (char *) index (bufp, 'e');
- if (!bufp)
- strcat (digit_buffer, "e0");
else
{
- char *p;
- bufp++;
- if (*bufp == '-')
+ if (REAL_VALUE_NEGATIVE (val))
{
+ val = REAL_VALUE_NEGATE (val);
*bufp++ = 'm';
}
- p = bufp;
- if (*p == '+')
- p++;
- while (*p == '0')
- p++;
- if (*p == 0)
+ if (REAL_VALUE_ISINF (val))
{
- *bufp++ = '0';
- *bufp = 0;
+ sprintf (bufp, "Infinity");
}
- else if (p != bufp)
+ else
{
- while (*p)
- *bufp++ = *p++;
- *bufp = 0;
+ REAL_VALUE_TO_DECIMAL (val, "%.20e", bufp);
+ bufp = (char *) index (bufp, 'e');
+ if (!bufp)
+ strcat (digit_buffer, "e0");
+ else
+ {
+ char *p;
+ bufp++;
+ if (*bufp == '-')
+ {
+ *bufp++ = 'm';
+ }
+ p = bufp;
+ if (*p == '+')
+ p++;
+ while (*p == '0')
+ p++;
+ if (*p == 0)
+ {
+ *bufp++ = '0';
+ *bufp = 0;
+ }
+ else if (p != bufp)
+ {
+ while (*p)
+ *bufp++ = *p++;
+ *bufp = 0;
+ }
+ }
+#ifdef NO_DOT_IN_LABEL
+ bufp = (char *) index (bufp, '.');
+ if (bufp)
+ *bufp = '_';
+#endif
}
}
OB_PUTCP (digit_buffer);
numeric_output_need_bar = 1;
return;
}
-#endif
case POINTER_TYPE:
if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE
&& TREE_CODE (value) != ADDR_EXPR)
{
if (TREE_CODE (value) == CONSTRUCTOR)
{
- /* This is dangerous code, crack built up pointer to members. */
+ /* This is dangerous code, crack built up pointer to members. */
tree args = CONSTRUCTOR_ELTS (value);
tree a1 = TREE_VALUE (args);
tree a2 = TREE_VALUE (TREE_CHAIN (args));
@@ -479,9 +758,9 @@ build_overload_value (type, value)
if (TREE_CODE (a1) == INTEGER_CST
&& TREE_CODE (a2) == INTEGER_CST)
{
- build_overload_int (a1);
+ build_overload_int (a1, in_template);
OB_PUTC ('_');
- build_overload_int (a2);
+ build_overload_int (a2, in_template);
OB_PUTC ('_');
if (TREE_CODE (a3) == ADDR_EXPR)
{
@@ -496,8 +775,7 @@ build_overload_value (type, value)
else if (TREE_CODE (a3) == INTEGER_CST)
{
OB_PUTC ('i');
- build_overload_int (a3);
- numeric_output_need_bar = 1;
+ build_overload_int (a3, in_template);
return;
}
}
@@ -507,23 +785,31 @@ build_overload_value (type, value)
}
if (TREE_CODE (value) == INTEGER_CST)
{
- build_overload_int (value);
+ build_overload_int (value, in_template);
+ return;
+ }
+ else if (TREE_CODE (value) == TEMPLATE_PARM_INDEX)
+ {
+ build_mangled_template_parm_index ("", value);
numeric_output_need_bar = 1;
return;
}
+
value = TREE_OPERAND (value, 0);
if (TREE_CODE (value) == VAR_DECL)
{
my_friendly_assert (DECL_NAME (value) != 0, 245);
- build_overload_identifier (DECL_NAME (value));
+ build_overload_identifier (DECL_ASSEMBLER_NAME (value));
return;
}
else if (TREE_CODE (value) == FUNCTION_DECL)
{
my_friendly_assert (DECL_NAME (value) != 0, 246);
- build_overload_identifier (DECL_NAME (value));
+ build_overload_identifier (DECL_ASSEMBLER_NAME (value));
return;
}
+ else if (TREE_CODE (value) == SCOPE_REF)
+ build_overload_scope_ref (value);
else
my_friendly_abort (71);
break; /* not really needed */
@@ -535,46 +821,120 @@ build_overload_value (type, value)
}
}
+
+/* Add encodings for the declaration of template template parameters.
+ PARMLIST must be a TREE_VEC */
+
+static void
+build_template_template_parm_names (parmlist)
+ tree parmlist;
+{
+ int i, nparms;
+
+ my_friendly_assert (TREE_CODE (parmlist) == TREE_VEC, 246.5);
+ nparms = TREE_VEC_LENGTH (parmlist);
+ icat (nparms);
+ for (i = 0; i < nparms; i++)
+ {
+ tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
+ if (TREE_CODE (parm) == TYPE_DECL)
+ {
+ /* This parameter is a type. */
+ OB_PUTC ('Z');
+ }
+ else if (TREE_CODE (parm) == TEMPLATE_DECL)
+ {
+ /* This parameter is a template. */
+ OB_PUTC ('z');
+ build_template_template_parm_names (DECL_INNERMOST_TEMPLATE_PARMS (parm));
+ }
+ else
+ /* It's a PARM_DECL. */
+ build_mangled_name_for_type (TREE_TYPE (parm));
+ }
+}
+
+
+/* Add encodings for the vector of template parameters in PARMLIST,
+ given the vector of arguments to be substituted in ARGLIST. */
+
+static void
+build_template_parm_names (parmlist, arglist)
+ tree parmlist;
+ tree arglist;
+{
+ int i, nparms;
+
+ nparms = TREE_VEC_LENGTH (parmlist);
+ icat (nparms);
+ for (i = 0; i < nparms; i++)
+ {
+ tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
+ tree arg = TREE_VEC_ELT (arglist, i);
+ if (TREE_CODE (parm) == TYPE_DECL)
+ {
+ /* This parameter is a type. */
+ OB_PUTC ('Z');
+ build_mangled_name_for_type (arg);
+ }
+ else if (TREE_CODE (parm) == TEMPLATE_DECL)
+ {
+ /* This parameter is a template. */
+ if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+ /* Output parameter declaration, argument index and level */
+ build_mangled_name_for_type (arg);
+ else
+ {
+ /* A TEMPLATE_DECL node, output the parameter declaration
+ and template name */
+
+ OB_PUTC ('z');
+ build_template_template_parm_names (DECL_INNERMOST_TEMPLATE_PARMS (parm));
+ icat (IDENTIFIER_LENGTH (DECL_NAME (arg)));
+ OB_PUTID (DECL_NAME (arg));
+ }
+ }
+ else
+ {
+ parm = tsubst (parm, arglist, NULL_TREE);
+ /* It's a PARM_DECL. */
+ build_mangled_name_for_type (TREE_TYPE (parm));
+ build_overload_value (parm, arg, uses_template_parms (arglist));
+ }
+ }
+ }
+
+/* Output the representation for NAME, which is either a TYPE_DECL or
+ an IDENTIFIER. */
+
static void
build_overload_identifier (name)
tree name;
{
- if (IDENTIFIER_TEMPLATE (name))
- {
+ if (TREE_CODE (name) == TYPE_DECL
+ && IS_AGGR_TYPE (TREE_TYPE (name))
+ && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name))
+ && (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name)))
+ || (TREE_CODE (DECL_CONTEXT (CLASSTYPE_TI_TEMPLATE
+ (TREE_TYPE (name))))
+ == FUNCTION_DECL)))
+ {
+ /* NAME is the TYPE_DECL for a template specialization. */
tree template, parmlist, arglist, tname;
- int i, nparms;
- template = IDENTIFIER_TEMPLATE (name);
- arglist = TREE_VALUE (template);
+ template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
+ arglist = innermost_args (TREE_VALUE (template), 0);
template = TREE_PURPOSE (template);
tname = DECL_NAME (template);
- parmlist = DECL_ARGUMENTS (template);
- nparms = TREE_VEC_LENGTH (parmlist);
+ parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
OB_PUTC ('t');
icat (IDENTIFIER_LENGTH (tname));
OB_PUTID (tname);
- icat (nparms);
- for (i = 0; i < nparms; i++)
- {
- tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
- tree arg = TREE_VEC_ELT (arglist, i);
- if (TREE_CODE (parm) == TYPE_DECL)
- {
- /* This parameter is a type. */
- OB_PUTC ('Z');
- build_overload_name (arg, 0, 0);
- }
- else
- {
- parm = tsubst (parm, &TREE_VEC_ELT (arglist, 0),
- TREE_VEC_LENGTH (arglist), NULL_TREE);
- /* It's a PARM_DECL. */
- build_overload_name (TREE_TYPE (parm), 0, 0);
- build_overload_value (parm, arg);
- }
- }
+ build_template_parm_names (parmlist, arglist);
}
else
{
+ if (TREE_CODE (name) == TYPE_DECL)
+ name = DECL_NAME (name);
if (numeric_output_need_bar)
{
OB_PUTC ('_');
@@ -585,6 +945,81 @@ build_overload_identifier (name)
}
}
+/* Given DECL, either a class TYPE, TYPE_DECL or FUNCTION_DECL, produce
+ the mangling for it. Used by build_mangled_name and build_static_name. */
+
+static void
+build_qualified_name (decl)
+ tree decl;
+{
+ tree context;
+ int i = 1;
+
+ if (TREE_CODE_CLASS (TREE_CODE (decl)) == 't')
+ decl = TYPE_NAME (decl);
+
+ /* If DECL_ASSEMBLER_NAME has been set properly, use it. */
+ if (TREE_CODE (decl) == TYPE_DECL
+ && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !flag_do_squangling)
+ {
+ tree id = DECL_ASSEMBLER_NAME (decl);
+ OB_PUTID (id);
+ if (ISDIGIT (IDENTIFIER_POINTER (id) [IDENTIFIER_LENGTH (id) - 1]))
+ numeric_output_need_bar = 1;
+ return;
+ }
+
+ context = decl;
+ /* if we can't find a Ktype, do it the hard way */
+ if (check_ktype (context, FALSE) == -1)
+ {
+ /* count type and namespace scopes */
+ while (DECL_CONTEXT (context) && DECL_CONTEXT (context) != global_namespace)
+ {
+ i += 1;
+ context = DECL_CONTEXT (context);
+ if (check_ktype (context, FALSE) != -1) /* found it! */
+ break;
+ if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
+ context = TYPE_NAME (context);
+ }
+ }
+
+ if (i > 1)
+ {
+ OB_PUTC ('Q');
+ build_underscore_int (i);
+ numeric_output_need_bar = 0;
+ }
+ build_overload_nested_name (decl);
+}
+
+/* Output the mangled representation for TYPE. If EXTRA_GCODE is
+ non-zero, mangled names for structure/union types are intentionally
+ mangled differently from the method described in the ARM. */
+
+void
+build_mangled_name_for_type_with_Gcode (type, extra_Gcode)
+ tree type;
+ int extra_Gcode;
+{
+ if (TYPE_PTRMEMFUNC_P (type))
+ type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+ type = canonical_type_variant (type);
+ process_modifiers (type);
+ process_overload_item (type, extra_Gcode);
+}
+
+/* Like build_mangled_name_for_type_with_Gcode, but never outputs the
+ `G'. */
+
+void
+build_mangled_name_for_type (type)
+ tree type;
+{
+ build_mangled_name_for_type_with_Gcode (type, 0);
+}
+
/* Given a list of parameters in PARMTYPES, create an unambiguous
overload string. Should distinguish any type that C (or C++) can
distinguish. I.e., pointers to functions are treated correctly.
@@ -602,375 +1037,495 @@ build_overload_name (parmtypes, begin, end)
tree parmtypes;
int begin, end;
{
- int just_one;
- tree parmtype;
+ char *ret;
+ start_squangling ();
+ ret = build_mangled_name (parmtypes, begin, end);
+ end_squangling ();
+ return ret ;
+}
- if (begin) OB_INIT ();
- numeric_output_need_bar = 0;
+/* Output the mangled representation for PARMTYPES. If PARMTYPES is a
+ TREE_LIST, then it is a list of parameter types. Otherwise,
+ PARMTYPES must be a single type. */
- if ((just_one = (TREE_CODE (parmtypes) != TREE_LIST)))
- {
- parmtype = parmtypes;
- goto only_one;
- }
+static char *
+build_mangled_name (parmtypes, begin, end)
+ tree parmtypes;
+ int begin, end;
+{
+ if (begin)
+ OB_INIT ();
- while (parmtypes)
+ if (TREE_CODE (parmtypes) != TREE_LIST)
+ /* There is only one type. */
+ build_mangled_name_for_type (parmtypes);
+ else
{
- parmtype = TREE_VALUE (parmtypes);
-
- only_one:
+ /* There are several types in a parameter list. */
+ int nrepeats = 0;
+ int old_style_repeats = !flag_do_squangling && !nofold && typevec;
+ tree last_type = NULL_TREE;
- if (! nofold && ! just_one)
+ for (; parmtypes && parmtypes != void_list_node;
+ parmtypes = TREE_CHAIN (parmtypes))
{
- /* Every argument gets counted. */
- typevec[maxtype++] = parmtype;
+ tree parmtype = canonical_type_variant (TREE_VALUE (parmtypes));
- if (TREE_USED (parmtype) && parmtype == typevec[maxtype-2])
+ if (old_style_repeats)
{
- nrepeats++;
- goto next;
+ /* Every argument gets counted. */
+ my_friendly_assert (maxtype < typevec_size, 387);
+ typevec[maxtype++] = parmtype;
}
- if (nrepeats)
- flush_repeats (typevec[maxtype-2]);
+ if (parmtype == last_type)
+ {
+ if (flag_do_squangling
+ || (old_style_repeats && TREE_USED (parmtype)
+ && !TYPE_FOR_JAVA (parmtype)))
+ {
+ /* The next type is the same as this one. Keep
+ track of the repetition, and output the repeat
+ count later. */
+ nrepeats++;
+ continue;
+ }
+ }
+ else if (nrepeats != 0)
+ {
+ /* Indicate how many times the previous parameter was
+ repeated. */
+ if (old_style_repeats)
+ flush_repeats (nrepeats, last_type);
+ else
+ issue_nrepeats (nrepeats, last_type);
+ nrepeats = 0;
+ }
+
+ last_type = parmtype;
- if (TREE_USED (parmtype))
+ if (old_style_repeats)
{
- flush_repeats (parmtype);
- goto next;
+ if (nrepeats)
+ {
+ flush_repeats (nrepeats, last_type);
+ nrepeats = 0;
+ }
+
+ if (TREE_USED (parmtype))
+ {
+#if 0
+ /* We can turn this on at some point when we want
+ improved symbol mangling. */
+ nrepeats++;
+#else
+ /* This is bug compatible with 2.7.x */
+ flush_repeats (nrepeats, parmtype);
+#endif
+ nrepeats = 0;
+ continue;
+ }
+
+ /* Only cache types which take more than one character. */
+ if ((parmtype != TYPE_MAIN_VARIANT (parmtype)
+ || (TREE_CODE (parmtype) != INTEGER_TYPE
+ && TREE_CODE (parmtype) != REAL_TYPE))
+ && ! TYPE_FOR_JAVA (parmtype))
+ TREE_USED (parmtype) = 1;
}
- /* Only cache types which take more than one character. */
- if (parmtype != TYPE_MAIN_VARIANT (parmtype)
- || (TREE_CODE (parmtype) != INTEGER_TYPE
- && TREE_CODE (parmtype) != REAL_TYPE))
- TREE_USED (parmtype) = 1;
+ /* Output the PARMTYPE. */
+ build_mangled_name_for_type_with_Gcode (parmtype, 1);
}
- if (TYPE_PTRMEMFUNC_P (parmtype))
- parmtype = TYPE_PTRMEMFUNC_FN_TYPE (parmtype);
+ /* Output the repeat count for the last parameter, if
+ necessary. */
+ if (nrepeats != 0)
+ {
+ if (old_style_repeats)
+ flush_repeats (nrepeats, last_type);
+ else
+ issue_nrepeats (nrepeats, last_type);
+ nrepeats = 0;
+ }
- if (TREE_READONLY (parmtype))
- OB_PUTC ('C');
- if (TREE_CODE (parmtype) == INTEGER_TYPE
- && TYPE_MAIN_VARIANT (parmtype) == unsigned_type (TYPE_MAIN_VARIANT (parmtype)))
- OB_PUTC ('U');
- if (TYPE_VOLATILE (parmtype))
- OB_PUTC ('V');
+ if (!parmtypes)
+ /* The parameter list ends in an ellipsis. */
+ OB_PUTC ('e');
+ }
- switch (TREE_CODE (parmtype))
- {
- case OFFSET_TYPE:
- OB_PUTC ('O');
- build_overload_name (TYPE_OFFSET_BASETYPE (parmtype), 0, 0);
+ if (end)
+ OB_FINISH ();
+ return (char *)obstack_base (&scratch_obstack);
+}
+
+/* handles emitting modifiers such as Constant, read-only, and volatile */
+void
+process_modifiers (parmtype)
+ tree parmtype;
+{
+ if (TREE_READONLY (parmtype))
+ OB_PUTC ('C');
+ if (TREE_CODE (parmtype) == INTEGER_TYPE
+ && (TYPE_MAIN_VARIANT (parmtype)
+ == unsigned_type (TYPE_MAIN_VARIANT (parmtype)))
+ && ! TYPE_FOR_JAVA (parmtype))
+ OB_PUTC ('U');
+ if (TYPE_VOLATILE (parmtype))
+ OB_PUTC ('V');
+}
+
+/* Check to see if TYPE has been entered into the Bcode typelist. If
+ so, return 1 and emit a backreference to TYPE. Otherwise, add TYPE
+ to the list of back-referenceable types and return 0. */
+
+int
+check_btype (type)
+ tree type;
+{
+ int x;
+
+ if (btypelist == NULL)
+ return 0;
+
+ if (!is_back_referenceable_type (type))
+ return 0;
+
+ /* We assume that our caller has put out any necessary
+ qualifiers. */
+ type = TYPE_MAIN_VARIANT (type);
+
+ for (x = 0; x < maxbtype; x++)
+ if (type == btypelist[x])
+ {
+ OB_PUTC ('B');
+ icat (x);
+ if (x > 9)
OB_PUTC ('_');
- build_overload_name (TREE_TYPE (parmtype), 0, 0);
- break;
+ return 1 ;
+ }
+
+ if (maxbsize <= maxbtype)
+ {
+ /* Enlarge the table. */
+ maxbsize = maxbsize * 3 / 2;
+ btypelist = (tree *)xrealloc (btypelist, sizeof (tree) * maxbsize);
+ }
+
+ /* Register the TYPE. */
+ btypelist[maxbtype++] = type;
- case REFERENCE_TYPE:
- OB_PUTC ('R');
- goto more;
+ return 0;
+}
- case ARRAY_TYPE:
+/* handle emitting the correct code for various node types */
+static void
+process_overload_item (parmtype, extra_Gcode)
+ tree parmtype;
+ int extra_Gcode;
+{
+ numeric_output_need_bar = 0;
+
+ /* These tree types are considered modifiers for B code squangling , */
+ /* and therefore should not get entries in the Btypelist */
+ /* they are, however, repeatable types */
+
+ switch (TREE_CODE (parmtype))
+ {
+ case REFERENCE_TYPE:
+ OB_PUTC ('R');
+ goto more;
+
+ case ARRAY_TYPE:
#if PARM_CAN_BE_ARRAY_TYPE
- {
- tree length;
+ {
+ tree length;
- OB_PUTC ('A');
- if (TYPE_DOMAIN (parmtype) == NULL_TREE)
- error ("pointer or reference to array of unknown bound in parm type");
- else
+ OB_PUTC ('A');
+ if (TYPE_DOMAIN (parmtype) == NULL_TREE)
+ error("pointer/reference to array of unknown bound in parm type");
+ else
+ {
+ tree length = array_type_nelts (parmtype);
+ if (TREE_CODE (length) != INTEGER_CST || flag_do_squangling)
{
- length = array_type_nelts (parmtype);
- if (TREE_CODE (length) == INTEGER_CST)
- icat (TREE_INT_CST_LOW (length) + 1);
+ length = fold (build (PLUS_EXPR, TREE_TYPE (length),
+ length, integer_one_node));
+ STRIP_NOPS (length);
}
- OB_PUTC ('_');
- goto more;
+ build_overload_value (sizetype, length, 1);
}
+ if (numeric_output_need_bar && ! flag_do_squangling)
+ OB_PUTC ('_');
+ goto more;
+ }
#else
- OB_PUTC ('P');
- goto more;
+ OB_PUTC ('P');
+ goto more;
#endif
- case POINTER_TYPE:
- OB_PUTC ('P');
- more:
- build_overload_name (TREE_TYPE (parmtype), 0, 0);
- break;
+ case POINTER_TYPE:
+ OB_PUTC ('P');
+ more:
+ build_mangled_name_for_type (TREE_TYPE (parmtype));
+ return;
+ break;
- case FUNCTION_TYPE:
- case METHOD_TYPE:
- {
- tree firstarg = TYPE_ARG_TYPES (parmtype);
- /* Otherwise have to implement reentrant typevecs,
- unmark and remark types, etc. */
- int old_nofold = nofold;
- nofold = 1;
-
- if (nrepeats)
- flush_repeats (typevec[maxtype-1]);
-
- /* @@ It may be possible to pass a function type in
- which is not preceded by a 'P'. */
- if (TREE_CODE (parmtype) == FUNCTION_TYPE)
- {
- OB_PUTC ('F');
- if (firstarg == NULL_TREE)
- OB_PUTC ('e');
- else if (firstarg == void_list_node)
- OB_PUTC ('v');
- else
- build_overload_name (firstarg, 0, 0);
- }
- else
- {
- int constp = TYPE_READONLY (TREE_TYPE (TREE_VALUE (firstarg)));
- int volatilep = TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (firstarg)));
- OB_PUTC ('M');
- firstarg = TREE_CHAIN (firstarg);
-
- build_overload_name (TYPE_METHOD_BASETYPE (parmtype), 0, 0);
- if (constp)
- OB_PUTC ('C');
- if (volatilep)
- OB_PUTC ('V');
-
- /* For cfront 2.0 compatibility. */
- OB_PUTC ('F');
-
- if (firstarg == NULL_TREE)
- OB_PUTC ('e');
- else if (firstarg == void_list_node)
- OB_PUTC ('v');
- else
- build_overload_name (firstarg, 0, 0);
- }
+ default:
+ break;
+ }
+
+ if (flag_do_squangling && check_btype (parmtype))
+ /* If PARMTYPE is already in the list of back-referenceable types,
+ then check_btype will output the appropriate reference, and
+ there's nothing more to do. */
+ return;
- /* Separate args from return type. */
- OB_PUTC ('_');
- build_overload_name (TREE_TYPE (parmtype), 0, 0);
- nofold = old_nofold;
- break;
+ switch (TREE_CODE (parmtype))
+ {
+ case OFFSET_TYPE:
+ OB_PUTC ('O');
+ build_mangled_name_for_type (TYPE_OFFSET_BASETYPE (parmtype));
+ OB_PUTC ('_');
+ build_mangled_name_for_type (TREE_TYPE (parmtype));
+ break;
+
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ {
+ tree parms = TYPE_ARG_TYPES (parmtype);
+
+ /* Rather than implementing a reentrant TYPEVEC, we turn off
+ repeat codes here, unless we're squangling. Squangling
+ doesn't make use of the TYPEVEC, so there's no reentrancy
+ problem. */
+ int old_nofold = nofold;
+ if (!flag_do_squangling)
+ nofold = 1;
+
+ if (TREE_CODE (parmtype) == METHOD_TYPE)
+ {
+ /* Mark this as a method. */
+ OB_PUTC ('M');
+ /* Output the class of which this method is a member. */
+ build_mangled_name_for_type (TYPE_METHOD_BASETYPE (parmtype));
+ /* Output any qualifiers for the `this' parameter. */
+ process_modifiers (TREE_TYPE (TREE_VALUE (parms)));
}
- case INTEGER_TYPE:
- parmtype = TYPE_MAIN_VARIANT (parmtype);
- if (parmtype == integer_type_node
- || parmtype == unsigned_type_node)
- OB_PUTC ('i');
- else if (parmtype == long_integer_type_node
- || parmtype == long_unsigned_type_node)
- OB_PUTC ('l');
- else if (parmtype == short_integer_type_node
- || parmtype == short_unsigned_type_node)
- OB_PUTC ('s');
- else if (parmtype == signed_char_type_node)
- {
- OB_PUTC ('S');
- OB_PUTC ('c');
- }
- else if (parmtype == char_type_node
- || parmtype == unsigned_char_type_node)
- OB_PUTC ('c');
- else if (parmtype == wchar_type_node)
- OB_PUTC ('w');
- else if (parmtype == long_long_integer_type_node
- || parmtype == long_long_unsigned_type_node)
- OB_PUTC ('x');
+ /* Output the parameter types. */
+ OB_PUTC ('F');
+ if (parms == NULL_TREE)
+ OB_PUTC ('e');
+ else if (parms == void_list_node)
+ OB_PUTC ('v');
+ else
+ build_mangled_name (parms, 0, 0);
+
+ /* Output the return type. */
+ OB_PUTC ('_');
+ build_mangled_name_for_type (TREE_TYPE (parmtype));
+
+ nofold = old_nofold;
+ break;
+ }
+
+ case INTEGER_TYPE:
+ parmtype = TYPE_MAIN_VARIANT (parmtype);
+ if (parmtype == integer_type_node
+ || parmtype == unsigned_type_node
+ || parmtype == java_int_type_node)
+ OB_PUTC ('i');
+ else if (parmtype == long_integer_type_node
+ || parmtype == long_unsigned_type_node)
+ OB_PUTC ('l');
+ else if (parmtype == short_integer_type_node
+ || parmtype == short_unsigned_type_node
+ || parmtype == java_short_type_node)
+ OB_PUTC ('s');
+ else if (parmtype == signed_char_type_node)
+ {
+ OB_PUTC ('S');
+ OB_PUTC ('c');
+ }
+ else if (parmtype == char_type_node
+ || parmtype == unsigned_char_type_node
+ || parmtype == java_byte_type_node)
+ OB_PUTC ('c');
+ else if (parmtype == wchar_type_node
+ || parmtype == java_char_type_node)
+ OB_PUTC ('w');
+ else if (parmtype == long_long_integer_type_node
+ || parmtype == long_long_unsigned_type_node
+ || parmtype == java_long_type_node)
+ OB_PUTC ('x');
#if 0
- /* it would seem there is no way to enter these in source code,
- yet. (mrs) */
- else if (parmtype == long_long_long_integer_type_node
- || parmtype == long_long_long_unsigned_type_node)
- OB_PUTC ('q');
+ /* it would seem there is no way to enter these in source code,
+ yet. (mrs) */
+ else if (parmtype == long_long_long_integer_type_node
+ || parmtype == long_long_long_unsigned_type_node)
+ OB_PUTC ('q');
#endif
- else
- my_friendly_abort (73);
- break;
-
- case BOOLEAN_TYPE:
- OB_PUTC ('b');
- break;
-
- case REAL_TYPE:
- parmtype = TYPE_MAIN_VARIANT (parmtype);
- if (parmtype == long_double_type_node)
- OB_PUTC ('r');
- else if (parmtype == double_type_node)
- OB_PUTC ('d');
- else if (parmtype == float_type_node)
- OB_PUTC ('f');
- else my_friendly_abort (74);
- break;
-
- case VOID_TYPE:
- if (! just_one)
- {
-#if 0
- extern tree void_list_node;
+ else if (parmtype == java_boolean_type_node)
+ OB_PUTC ('b');
+ else
+ my_friendly_abort (73);
+ break;
- /* See if anybody is wasting memory. */
- my_friendly_assert (parmtypes == void_list_node, 247);
-#endif
- /* This is the end of a parameter list. */
- if (end) OB_FINISH ();
- return (char *)obstack_base (&scratch_obstack);
- }
- OB_PUTC ('v');
- break;
-
- case ERROR_MARK: /* not right, but nothing is anyway */
- break;
-
- /* have to do these */
- case UNION_TYPE:
- case RECORD_TYPE:
- if (! just_one)
- /* Make this type signature look incompatible
- with AT&T. */
- OB_PUTC ('G');
- goto common;
- case ENUMERAL_TYPE:
- common:
- {
- tree name = TYPE_NAME (parmtype);
- int i = 1;
+ case BOOLEAN_TYPE:
+ OB_PUTC ('b');
+ break;
- if (TREE_CODE (name) == TYPE_DECL)
- {
- tree context = name;
+ case REAL_TYPE:
+ parmtype = TYPE_MAIN_VARIANT (parmtype);
+ if (parmtype == long_double_type_node)
+ OB_PUTC ('r');
+ else if (parmtype == double_type_node
+ || parmtype == java_double_type_node)
+ OB_PUTC ('d');
+ else if (parmtype == float_type_node
+ || parmtype == java_float_type_node)
+ OB_PUTC ('f');
+ else my_friendly_abort (74);
+ break;
- /* If DECL_ASSEMBLER_NAME has been set properly, use it. */
- if (DECL_ASSEMBLER_NAME (context) != DECL_NAME (context))
- {
- OB_PUTID (DECL_ASSEMBLER_NAME (context));
- break;
- }
- while (DECL_CONTEXT (context))
- {
- i += 1;
- context = DECL_CONTEXT (context);
- if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
- context = TYPE_NAME (context);
- }
- name = DECL_NAME (name);
- }
- my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 248);
- if (i > 1)
- {
- OB_PUTC ('Q');
- if (i > 9)
- OB_PUTC ('_');
- icat (i);
- if (i > 9)
- OB_PUTC ('_');
- numeric_output_need_bar = 0;
- build_overload_nested_name (TYPE_MAIN_DECL (parmtype));
- }
- else
- build_overload_identifier (name);
- break;
- }
+ case COMPLEX_TYPE:
+ OB_PUTC ('J');
+ build_mangled_name_for_type (TREE_TYPE (parmtype));
+ break;
- case UNKNOWN_TYPE:
- /* This will take some work. */
- OB_PUTC ('?');
- break;
-
- case TEMPLATE_TYPE_PARM:
- case TEMPLATE_CONST_PARM:
- case UNINSTANTIATED_P_TYPE:
- /* We don't ever want this output, but it's inconvenient not to
- be able to build the string. This should cause assembler
- errors we'll notice. */
- {
- static int n;
- sprintf (digit_buffer, " *%d", n++);
- OB_PUTCP (digit_buffer);
- }
- break;
+ case VOID_TYPE:
+ OB_PUTC ('v');
+ break;
- default:
- my_friendly_abort (75);
- }
+ case ERROR_MARK: /* not right, but nothing is anyway */
+ break;
- next:
- if (just_one) break;
- parmtypes = TREE_CHAIN (parmtypes);
- }
- if (! just_one)
- {
- if (nrepeats)
- flush_repeats (typevec[maxtype-1]);
+ /* have to do these */
+ case UNION_TYPE:
+ case RECORD_TYPE:
+ {
+ if (extra_Gcode)
+ OB_PUTC ('G'); /* make it look incompatible with AT&T */
+ /* drop through into next case */
+ }
+ case ENUMERAL_TYPE:
+ {
+ tree name = TYPE_NAME (parmtype);
+
+ if (TREE_CODE (name) == IDENTIFIER_NODE)
+ {
+ build_overload_identifier (TYPE_NAME (parmtype));
+ break;
+ }
+ my_friendly_assert (TREE_CODE (name) == TYPE_DECL, 248);
+
+ build_qualified_name (name);
+ break;
+ }
+
+ case UNKNOWN_TYPE:
+ /* This will take some work. */
+ OB_PUTC ('?');
+ break;
- /* To get here, parms must end with `...'. */
- OB_PUTC ('e');
+ case TEMPLATE_TEMPLATE_PARM:
+ /* Find and output the original template parameter
+ declaration. */
+ if (CLASSTYPE_TEMPLATE_INFO (parmtype))
+ {
+ build_mangled_template_parm_index ("tzX",
+ TEMPLATE_TYPE_PARM_INDEX
+ (parmtype));
+ build_template_parm_names
+ (DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (parmtype)),
+ CLASSTYPE_TI_ARGS (parmtype));
+ }
+ else
+ {
+ build_mangled_template_parm_index ("ZzX",
+ TEMPLATE_TYPE_PARM_INDEX
+ (parmtype));
+ build_template_template_parm_names
+ (DECL_INNERMOST_TEMPLATE_PARMS (TYPE_STUB_DECL (parmtype)));
+ }
+ break;
+
+ case TEMPLATE_TYPE_PARM:
+ build_mangled_template_parm_index ("X",
+ TEMPLATE_TYPE_PARM_INDEX
+ (parmtype));
+ break;
+
+ case TYPENAME_TYPE:
+ /* When mangling the type of a function template whose
+ declaration looks like:
+
+ template <class T> void foo(typename T::U)
+
+ we have to mangle these. */
+ build_qualified_name (parmtype);
+ break;
+
+ default:
+ my_friendly_abort (75);
}
- if (end) OB_FINISH ();
- return (char *)obstack_base (&scratch_obstack);
}
-tree
-build_static_name (basetype, name)
- tree basetype, name;
-{
- char *basename = build_overload_name (basetype, 1, 1);
- char *buf = (char *) alloca (IDENTIFIER_LENGTH (name)
- + sizeof (STATIC_NAME_FORMAT)
- + strlen (basename));
- sprintf (buf, STATIC_NAME_FORMAT, basename, IDENTIFIER_POINTER (name));
- return get_identifier (buf);
-}
-
-/* Generate an identifier that encodes the (ANSI) exception TYPE. */
-
-/* This should be part of `ansi_opname', or at least be defined by the std. */
-#define EXCEPTION_NAME_PREFIX "__ex"
-#define EXCEPTION_NAME_LENGTH 4
+/* Produce the mangling for a variable named NAME in CONTEXT, which can
+ be either a class TYPE or a FUNCTION_DECL. */
tree
-cplus_exception_name (type)
- tree type;
+build_static_name (context, name)
+ tree context, name;
{
OB_INIT ();
- OB_PUTS (EXCEPTION_NAME_PREFIX);
- return get_identifier (build_overload_name (type, 0, 1));
+ numeric_output_need_bar = 0;
+ start_squangling ();
+#ifdef JOINER
+ OB_PUTC ('_');
+ build_qualified_name (context);
+ OB_PUTC (JOINER);
+#else
+ OB_PUTS ("__static_");
+ build_qualified_name (context);
+ OB_PUTC ('_');
+#endif
+ OB_PUTID (name);
+ OB_FINISH ();
+ end_squangling ();
+
+ return get_identifier ((char *)obstack_base (&scratch_obstack));
}
-/* Change the name of a function definition so that it may be
- overloaded. NAME is the name of the function to overload,
- PARMS is the parameter list (which determines what name the
- final function obtains).
-
- FOR_METHOD is 1 if this overload is being performed
- for a method, rather than a function type. It is 2 if
- this overload is being performed for a constructor. */
-tree
-build_decl_overload (dname, parms, for_method)
+static tree
+build_decl_overload_real (dname, parms, ret_type, tparms, targs,
+ for_method)
tree dname;
tree parms;
+ tree ret_type;
+ tree tparms;
+ tree targs;
int for_method;
{
char *name = IDENTIFIER_POINTER (dname);
/* member operators new and delete look like methods at this point. */
- if (! for_method && parms != NULL_TREE && TREE_CODE (parms) == TREE_LIST)
+ if (! for_method && parms != NULL_TREE && TREE_CODE (parms) == TREE_LIST
+ && TREE_CHAIN (parms) == void_list_node)
{
if (dname == ansi_opname[(int) DELETE_EXPR])
return get_identifier ("__builtin_delete");
else if (dname == ansi_opname[(int) VEC_DELETE_EXPR])
return get_identifier ("__builtin_vec_delete");
- else if (TREE_CHAIN (parms) == void_list_node)
- {
- if (dname == ansi_opname[(int) NEW_EXPR])
- return get_identifier ("__builtin_new");
- else if (dname == ansi_opname[(int) VEC_NEW_EXPR])
- return get_identifier ("__builtin_vec_new");
- }
+ if (dname == ansi_opname[(int) NEW_EXPR])
+ return get_identifier ("__builtin_new");
+ else if (dname == ansi_opname[(int) VEC_NEW_EXPR])
+ return get_identifier ("__builtin_vec_new");
}
+ start_squangling ();
OB_INIT ();
if (for_method != 2)
OB_PUTCP (name);
@@ -978,50 +1533,107 @@ build_decl_overload (dname, parms, for_method)
and figure out its name without any extra encoding. */
OB_PUTC2 ('_', '_');
- if (for_method)
- {
-#if 0
- /* We can get away without doing this. */
- OB_PUTC ('M');
-#endif
- {
- tree this_type = TREE_VALUE (parms);
+ numeric_output_need_bar = 0;
- if (TREE_CODE (this_type) == RECORD_TYPE) /* a signature pointer */
- parms = temp_tree_cons (NULL_TREE, SIGNATURE_TYPE (this_type),
- TREE_CHAIN (parms));
- else
- parms = temp_tree_cons (NULL_TREE, TREE_TYPE (this_type),
- TREE_CHAIN (parms));
- }
+ if (tparms)
+ {
+ OB_PUTC ('H');
+ build_template_parm_names (tparms, targs);
+ OB_PUTC ('_');
}
- else
+ else if (!for_method && current_namespace == global_namespace)
+ /* XXX this works only if we call this in the same namespace
+ as the declaration. Unfortunately, we don't have the _DECL,
+ only its name */
OB_PUTC ('F');
+ if (!for_method && current_namespace != global_namespace)
+ /* qualify with namespace */
+ build_qualified_name (current_namespace);
+
if (parms == NULL_TREE)
- OB_PUTC2 ('e', '\0');
+ OB_PUTC ('e');
else if (parms == void_list_node)
- OB_PUTC2 ('v', '\0');
+ OB_PUTC ('v');
else
{
- ALLOCATE_TYPEVEC (parms);
+ if (!flag_do_squangling) /* Allocate typevec array. */
+ {
+ maxtype = 0;
+ typevec_size = list_length (parms);
+ if (!for_method && current_namespace != global_namespace)
+ /* the namespace of a global function needs one slot */
+ typevec_size++;
+ typevec = (tree *)alloca (typevec_size * sizeof (tree));
+ }
nofold = 0;
+
if (for_method)
{
- build_overload_name (TREE_VALUE (parms), 0, 0);
+ tree this_type = TREE_VALUE (parms);
+
+ if (TREE_CODE (this_type) == RECORD_TYPE) /* a signature pointer */
+ this_type = SIGNATURE_TYPE (this_type);
+ else
+ this_type = TREE_TYPE (this_type);
- typevec[maxtype++] = TREE_VALUE (parms);
- TREE_USED (TREE_VALUE (parms)) = 1;
+ build_mangled_name_for_type (this_type);
+
+ if (!flag_do_squangling)
+ {
+ my_friendly_assert (maxtype < typevec_size, 387);
+ typevec[maxtype++] = this_type;
+ TREE_USED (this_type) = 1;
+
+ /* By setting up PARMS in this way, the loop below will
+ automatically clear TREE_USED on THIS_TYPE. */
+ parms = temp_tree_cons (NULL_TREE, this_type,
+ TREE_CHAIN (parms));
+ }
if (TREE_CHAIN (parms))
- build_overload_name (TREE_CHAIN (parms), 0, 1);
+ build_mangled_name (TREE_CHAIN (parms), 0, 0);
else
- OB_PUTC2 ('e', '\0');
+ OB_PUTC ('e');
}
else
- build_overload_name (parms, 0, 1);
- DEALLOCATE_TYPEVEC (parms);
+ {
+ /* the namespace qualifier for a global function
+ will count as type */
+ if (current_namespace != global_namespace
+ && !flag_do_squangling)
+ {
+ my_friendly_assert (maxtype < typevec_size, 387);
+ typevec[maxtype++] = current_namespace;
+ }
+ build_mangled_name (parms, 0, 0);
+ }
+
+ if (!flag_do_squangling) /* Deallocate typevec array */
+ {
+ tree t = parms;
+ typevec = NULL;
+ while (t)
+ {
+ tree temp = TREE_VALUE (t);
+ TREE_USED (temp) = 0;
+ /* clear out the type variant in case we used it */
+ temp = canonical_type_variant (temp);
+ TREE_USED (temp) = 0;
+ t = TREE_CHAIN (t);
+ }
+ }
+ }
+
+ if (ret_type != NULL_TREE && for_method != 2)
+ {
+ /* Add the return type. */
+ OB_PUTC ('_');
+ build_mangled_name_for_type (ret_type);
}
+
+ OB_FINISH ();
+ end_squangling ();
{
tree n = get_identifier (obstack_base (&scratch_obstack));
if (IDENTIFIER_OPNAME_P (dname))
@@ -1030,7 +1642,59 @@ build_decl_overload (dname, parms, for_method)
}
}
+/* Change the name of a function definition so that it may be
+ overloaded. NAME is the name of the function to overload,
+ PARMS is the parameter list (which determines what name the
+ final function obtains).
+
+ FOR_METHOD is 1 if this overload is being performed
+ for a method, rather than a function type. It is 2 if
+ this overload is being performed for a constructor. */
+
+tree
+build_decl_overload (dname, parms, for_method)
+ tree dname;
+ tree parms;
+ int for_method;
+{
+ return build_decl_overload_real (dname, parms, NULL_TREE, NULL_TREE,
+ NULL_TREE, for_method);
+}
+
+
+/* Like build_decl_overload, but for template functions. */
+
+tree
+build_template_decl_overload (decl, parms, ret_type, tparms, targs,
+ for_method)
+ tree decl;
+ tree parms;
+ tree ret_type;
+ tree tparms;
+ tree targs;
+ int for_method;
+{
+ tree res, saved_ctx;
+
+ /* If the template is in a namespace, we need to put that into the
+ mangled name. Unfortunately, build_decl_overload_real does not
+ get the decl to mangle, so it relies on the current
+ namespace. Therefore, we set that here temporarily. */
+
+ my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd', 980702);
+ saved_ctx = current_namespace;
+ current_namespace = CP_DECL_CONTEXT (decl);
+
+ res = build_decl_overload_real (DECL_NAME (decl), parms, ret_type,
+ tparms, targs, for_method);
+
+ current_namespace = saved_ctx;
+ return res;
+}
+
+
/* Build an overload name for the type expression TYPE. */
+
tree
build_typename_overload (type)
tree type;
@@ -1040,111 +1704,53 @@ build_typename_overload (type)
OB_INIT ();
OB_PUTID (ansi_opname[(int) TYPE_EXPR]);
nofold = 1;
- build_overload_name (type, 0, 1);
+ start_squangling ();
+ build_mangled_name (type, 0, 1);
id = get_identifier (obstack_base (&scratch_obstack));
IDENTIFIER_OPNAME_P (id) = 1;
#if 0
- IDENTIFIER_GLOBAL_VALUE (id) = TYPE_NAME (type);
+ IDENTIFIER_GLOBAL_VALUE (id) = TYPE_MAIN_DECL (type);
#endif
TREE_TYPE (id) = type;
+ end_squangling ();
return id;
}
-#ifndef NO_DOLLAR_IN_LABEL
-#define T_DESC_FORMAT "TD$"
-#define I_DESC_FORMAT "ID$"
-#define M_DESC_FORMAT "MD$"
-#else
-#if !defined(NO_DOT_IN_LABEL)
-#define T_DESC_FORMAT "TD."
-#define I_DESC_FORMAT "ID."
-#define M_DESC_FORMAT "MD."
-#else
-#define T_DESC_FORMAT "__t_desc_"
-#define I_DESC_FORMAT "__i_desc_"
-#define M_DESC_FORMAT "__m_desc_"
-#endif
-#endif
-
-/* Build an overload name for the type expression TYPE. */
tree
-build_t_desc_overload (type)
- tree type;
+build_overload_with_type (name, type)
+ tree name, type;
{
OB_INIT ();
- OB_PUTS (T_DESC_FORMAT);
+ OB_PUTID (name);
nofold = 1;
-#if 0
- /* Use a different format if the type isn't defined yet. */
- if (TYPE_SIZE (type) == NULL_TREE)
- {
- char *p;
- int changed;
-
- for (p = tname; *p; p++)
- if (isupper (*p))
- {
- changed = 1;
- *p = tolower (*p);
- }
- /* If there's no change, we have an inappropriate T_DESC_FORMAT. */
- my_friendly_assert (changed != 0, 249);
- }
-#endif
-
- build_overload_name (type, 0, 1);
+ start_squangling ();
+ build_mangled_name (type, 0, 1);
+ end_squangling ();
return get_identifier (obstack_base (&scratch_obstack));
}
-/* Top-level interface to explicit overload requests. Allow NAME
- to be overloaded. Error if NAME is already declared for the current
- scope. Warning if function is redundantly overloaded. */
-
-void
-declare_overloaded (name)
- tree name;
+tree
+get_id_2 (name, name2)
+ char *name;
+ tree name2;
{
-#ifdef NO_AUTO_OVERLOAD
- if (is_overloaded (name))
- warning ("function `%s' already declared overloaded",
- IDENTIFIER_POINTER (name));
- else if (IDENTIFIER_GLOBAL_VALUE (name))
- error ("overloading function `%s' that is already defined",
- IDENTIFIER_POINTER (name));
- else
- {
- TREE_OVERLOADED (name) = 1;
- IDENTIFIER_GLOBAL_VALUE (name) = build_tree_list (name, NULL_TREE);
- TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)) = unknown_type_node;
- }
-#else
- if (current_lang_name == lang_name_cplusplus)
- {
- if (0)
- warning ("functions are implicitly overloaded in C++");
- }
- else if (current_lang_name == lang_name_c)
- error ("overloading function `%s' cannot be done in C language context");
- else
- my_friendly_abort (76);
-#endif
+ OB_INIT ();
+ OB_PUTCP (name);
+ OB_PUTID (name2);
+ OB_FINISH ();
+ return get_identifier (obstack_base (&scratch_obstack));
}
-#ifdef NO_AUTO_OVERLOAD
-/* Check to see if NAME is overloaded. For first approximation,
- check to see if its TREE_OVERLOADED is set. This is used on
- IDENTIFIER nodes. */
-int
-is_overloaded (name)
- tree name;
+/* Returns a DECL_ASSEMBLER_NAME for the destructor of type TYPE. */
+
+tree
+build_destructor_name (type)
+ tree type;
{
- /* @@ */
- return (TREE_OVERLOADED (name)
- && (! IDENTIFIER_CLASS_VALUE (name) || current_class_type == 0)
- && ! IDENTIFIER_LOCAL_VALUE (name));
+ return build_overload_with_type (get_identifier (DESTRUCTOR_DECL_PREFIX),
+ type);
}
-#endif
/* Given a tree_code CODE, and some arguments (at least one),
attempt to use an overloaded operator on the arguments.
@@ -1175,296 +1781,7 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
int flags;
tree xarg1, xarg2, arg3;
{
- tree rval = 0;
- tree arg1, arg2;
- tree type1, type2, fnname;
- tree fields1 = 0, parms = 0;
- tree global_fn;
- int try_second;
- int binary_is_unary;
-
- if (xarg1 == error_mark_node)
- return error_mark_node;
-
- if (code == COND_EXPR)
- {
- if (TREE_CODE (xarg2) == ERROR_MARK
- || TREE_CODE (arg3) == ERROR_MARK)
- return error_mark_node;
- }
- if (code == COMPONENT_REF)
- if (TREE_CODE (TREE_TYPE (xarg1)) == POINTER_TYPE)
- return rval;
-
- /* First, see if we can work with the first argument */
- type1 = TREE_TYPE (xarg1);
-
- /* Some tree codes have length > 1, but we really only want to
- overload them if their first argument has a user defined type. */
- switch (code)
- {
- case PREINCREMENT_EXPR:
- case PREDECREMENT_EXPR:
- case POSTINCREMENT_EXPR:
- case POSTDECREMENT_EXPR:
- case COMPONENT_REF:
- binary_is_unary = 1;
- try_second = 0;
- break;
-
- /* ARRAY_REFs and CALL_EXPRs must overload successfully.
- If they do not, return error_mark_node instead of NULL_TREE. */
- case ARRAY_REF:
- if (xarg2 == error_mark_node)
- return error_mark_node;
- case CALL_EXPR:
- rval = error_mark_node;
- binary_is_unary = 0;
- try_second = 0;
- break;
-
- case VEC_NEW_EXPR:
- case NEW_EXPR:
- {
- tree args = tree_cons (NULL_TREE, xarg2, arg3);
- fnname = ansi_opname[(int) code];
- if (flags & LOOKUP_GLOBAL)
- return build_overload_call (fnname, args, flags & LOOKUP_COMPLAIN,
- (struct candidate *)0);
-
- rval = build_method_call
- (build_indirect_ref (build1 (NOP_EXPR, xarg1, error_mark_node),
- "new"),
- fnname, args, NULL_TREE, flags);
- if (rval == error_mark_node)
- /* User might declare fancy operator new, but invoke it
- like standard one. */
- return rval;
-
- TREE_TYPE (rval) = xarg1;
- TREE_CALLS_NEW (rval) = 1;
- return rval;
- }
- break;
-
- case VEC_DELETE_EXPR:
- case DELETE_EXPR:
- {
- fnname = ansi_opname[(int) code];
- if (flags & LOOKUP_GLOBAL)
- return build_overload_call (fnname,
- build_tree_list (NULL_TREE, xarg1),
- flags & LOOKUP_COMPLAIN,
- (struct candidate *)0);
-
- rval = build_method_call
- (build_indirect_ref (build1 (NOP_EXPR, TREE_TYPE (xarg1),
- error_mark_node),
- NULL_PTR),
- fnname, tree_cons (NULL_TREE, xarg1,
- build_tree_list (NULL_TREE, xarg2)),
- NULL_TREE, flags);
-#if 0
- /* This can happen when operator delete is protected. */
- my_friendly_assert (rval != error_mark_node, 250);
- TREE_TYPE (rval) = void_type_node;
-#endif
- return rval;
- }
- break;
-
- default:
- binary_is_unary = 0;
- try_second = tree_code_length [(int) code] == 2;
- if (try_second && xarg2 == error_mark_node)
- return error_mark_node;
- break;
- }
-
- if (try_second && xarg2 == error_mark_node)
- return error_mark_node;
-
- /* What ever it was, we do not know how to deal with it. */
- if (type1 == NULL_TREE)
- return rval;
-
- if (TREE_CODE (type1) == OFFSET_TYPE)
- type1 = TREE_TYPE (type1);
-
- if (TREE_CODE (type1) == REFERENCE_TYPE)
- {
- arg1 = convert_from_reference (xarg1);
- type1 = TREE_TYPE (arg1);
- }
- else
- {
- arg1 = xarg1;
- }
-
- if (!IS_AGGR_TYPE (type1) || TYPE_PTRMEMFUNC_P (type1))
- {
- /* Try to fail. First, fail if unary */
- if (! try_second)
- return rval;
- /* Second, see if second argument is non-aggregate. */
- type2 = TREE_TYPE (xarg2);
- if (TREE_CODE (type2) == OFFSET_TYPE)
- type2 = TREE_TYPE (type2);
- if (TREE_CODE (type2) == REFERENCE_TYPE)
- {
- arg2 = convert_from_reference (xarg2);
- type2 = TREE_TYPE (arg2);
- }
- else
- {
- arg2 = xarg2;
- }
-
- if (!IS_AGGR_TYPE (type2))
- return rval;
- try_second = 0;
- }
-
- if (try_second)
- {
- /* First arg may succeed; see whether second should. */
- type2 = TREE_TYPE (xarg2);
- if (TREE_CODE (type2) == OFFSET_TYPE)
- type2 = TREE_TYPE (type2);
- if (TREE_CODE (type2) == REFERENCE_TYPE)
- {
- arg2 = convert_from_reference (xarg2);
- type2 = TREE_TYPE (arg2);
- }
- else
- {
- arg2 = xarg2;
- }
-
- if (! IS_AGGR_TYPE (type2))
- try_second = 0;
- }
-
- if (type1 == unknown_type_node
- || (try_second && TREE_TYPE (xarg2) == unknown_type_node))
- {
- /* This will not be implemented in the foreseeable future. */
- return rval;
- }
-
- if (code == MODIFY_EXPR)
- fnname = ansi_assopname[(int) TREE_CODE (arg3)];
- else
- fnname = ansi_opname[(int) code];
-
- global_fn = lookup_name_nonclass (fnname);
-
- /* This is the last point where we will accept failure. This
- may be too eager if we wish an overloaded operator not to match,
- but would rather a normal operator be called on a type-converted
- argument. */
-
- if (IS_AGGR_TYPE (type1))
- {
- fields1 = lookup_fnfields (TYPE_BINFO (type1), fnname, 0);
- /* ARM $13.4.7, prefix/postfix ++/--. */
- if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
- {
- xarg2 = integer_zero_node;
- binary_is_unary = 0;
-
- if (fields1)
- {
- tree t, t2;
- int have_postfix = 0;
-
- /* Look for an `operator++ (int)'. If they didn't have
- one, then we fall back to the old way of doing things. */
- for (t = TREE_VALUE (fields1); t ; t = DECL_CHAIN (t))
- {
- t2 = TYPE_ARG_TYPES (TREE_TYPE (t));
- if (TREE_CHAIN (t2) != NULL_TREE
- && TREE_VALUE (TREE_CHAIN (t2)) == integer_type_node)
- {
- have_postfix = 1;
- break;
- }
- }
-
- if (! have_postfix)
- {
- char *op = POSTINCREMENT_EXPR ? "++" : "--";
-
- /* There's probably a LOT of code in the world that
- relies upon this old behavior. */
- if (! flag_traditional)
- pedwarn ("no `operator%s (int)' declared for postfix `%s', using prefix operator instead",
- op, op);
- xarg2 = NULL_TREE;
- binary_is_unary = 1;
- }
- }
- }
- }
-
- if (fields1 == NULL_TREE && global_fn == NULL_TREE)
- return rval;
-
- /* If RVAL winds up being `error_mark_node', we will return
- that... There is no way that normal semantics of these
- operators will succeed. */
-
- /* This argument may be an uncommitted OFFSET_REF. This is
- the case for example when dealing with static class members
- which are referenced from their class name rather than
- from a class instance. */
- if (TREE_CODE (xarg1) == OFFSET_REF
- && TREE_CODE (TREE_OPERAND (xarg1, 1)) == VAR_DECL)
- xarg1 = TREE_OPERAND (xarg1, 1);
- if (try_second && xarg2 && TREE_CODE (xarg2) == OFFSET_REF
- && TREE_CODE (TREE_OPERAND (xarg2, 1)) == VAR_DECL)
- xarg2 = TREE_OPERAND (xarg2, 1);
-
- if (global_fn)
- flags |= LOOKUP_GLOBAL;
-
- if (code == CALL_EXPR)
- {
- /* This can only be a member function. */
- return build_method_call (xarg1, fnname, xarg2,
- NULL_TREE, LOOKUP_NORMAL);
- }
- else if (tree_code_length[(int) code] == 1 || binary_is_unary)
- {
- parms = NULL_TREE;
- rval = build_method_call (xarg1, fnname, NULL_TREE, NULL_TREE, flags);
- }
- else if (code == COND_EXPR)
- {
- parms = tree_cons (0, xarg2, build_tree_list (NULL_TREE, arg3));
- rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);
- }
- else if (code == METHOD_CALL_EXPR)
- {
- /* must be a member function. */
- parms = tree_cons (NULL_TREE, xarg2, arg3);
- return build_method_call (xarg1, fnname, parms, NULL_TREE,
- LOOKUP_NORMAL);
- }
- else if (fields1)
- {
- parms = build_tree_list (NULL_TREE, xarg2);
- rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);
- }
- else
- {
- parms = tree_cons (NULL_TREE, xarg1,
- build_tree_list (NULL_TREE, xarg2));
- rval = build_overload_call (fnname, parms, flags,
- (struct candidate *)0);
- }
-
- return rval;
+ return build_new_op (code, flags, xarg1, xarg2, arg3);
}
/* This function takes an identifier, ID, and attempts to figure out what
@@ -1478,7 +1795,6 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
NAME is $1 from the bison rule. It is an IDENTIFIER_NODE.
VALUE is $$ from the bison rule. It is the value returned by lookup_name ($1)
- yychar is the pending input character (suitably encoded :-).
As a last ditch, try to look up the name as a label and return that
address.
@@ -1488,13 +1804,12 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
compiler faster). */
tree
-hack_identifier (value, name, yychar)
+hack_identifier (value, name)
tree value, name;
- int yychar;
{
tree type;
- if (TREE_CODE (value) == ERROR_MARK)
+ if (value == error_mark_node)
{
if (current_class_name)
{
@@ -1507,6 +1822,9 @@ hack_identifier (value, name, yychar)
fndecl = TREE_VALUE (fields);
my_friendly_assert (TREE_CODE (fndecl) == FUNCTION_DECL, 251);
+ /* I could not trigger this code. MvL */
+ my_friendly_abort (980325);
+#ifdef DEAD
if (DECL_CHAIN (fndecl) == NULL_TREE)
{
warning ("methods cannot be converted to function pointers");
@@ -1518,6 +1836,7 @@ hack_identifier (value, name, yychar)
IDENTIFIER_POINTER (name));
return error_mark_node;
}
+#endif
}
}
if (flag_labels_ok && IDENTIFIER_LABEL_VALUE (name))
@@ -1530,23 +1849,27 @@ hack_identifier (value, name, yychar)
type = TREE_TYPE (value);
if (TREE_CODE (value) == FIELD_DECL)
{
- if (current_class_decl == NULL_TREE)
+ if (current_class_ptr == NULL_TREE)
{
error ("request for member `%s' in static member function",
IDENTIFIER_POINTER (DECL_NAME (value)));
return error_mark_node;
}
- TREE_USED (current_class_decl) = 1;
+ TREE_USED (current_class_ptr) = 1;
/* Mark so that if we are in a constructor, and then find that
this field was initialized by a base initializer,
we can emit an error message. */
TREE_USED (value) = 1;
- return build_component_ref (C_C_D, name, 0, 1);
+ value = build_component_ref (current_class_ref, name, NULL_TREE, 1);
}
-
- if (really_overloaded_fn (value))
+ else if (TREE_CODE (value) == FUNCTION_DECL
+ && DECL_FUNCTION_MEMBER_P (value))
+ /* This is a placeholder; don't mark it used. */
+ return value;
+ else if (really_overloaded_fn (value))
{
+#if 0
tree t = get_first_fn (value);
for (; t; t = DECL_CHAIN (t))
{
@@ -1556,21 +1879,46 @@ hack_identifier (value, name, yychar)
assemble_external (t);
TREE_USED (t) = 1;
}
+#endif
}
+ else if (TREE_CODE (value) == OVERLOAD)
+ /* not really overloaded function */
+ mark_used (OVL_FUNCTION (value));
else if (TREE_CODE (value) == TREE_LIST)
{
+ /* Ambiguous reference to base members, possibly other cases?. */
tree t = value;
while (t && TREE_CODE (t) == TREE_LIST)
{
- assemble_external (TREE_VALUE (t));
- TREE_USED (t) = 1;
+ mark_used (TREE_VALUE (t));
t = TREE_CHAIN (t);
}
}
+ else if (TREE_CODE (value) == NAMESPACE_DECL)
+ {
+ cp_error ("use of namespace `%D' as expression", value);
+ return error_mark_node;
+ }
+ else if (DECL_CLASS_TEMPLATE_P (value))
+ {
+ cp_error ("use of class template `%T' as expression", value);
+ return error_mark_node;
+ }
else
+ mark_used (value);
+
+ if (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL)
{
- assemble_external (value);
- TREE_USED (value) = 1;
+ tree context = decl_function_context (value);
+ if (context != NULL_TREE && context != current_function_decl
+ && ! TREE_STATIC (value))
+ {
+ cp_error ("use of %s from containing function",
+ (TREE_CODE (value) == VAR_DECL
+ ? "`auto' variable" : "parameter"));
+ cp_error_at (" `%#D' declared here", value);
+ value = error_mark_node;
+ }
}
if (TREE_CODE_CLASS (TREE_CODE (value)) == 'd' && DECL_NONLOCAL (value))
@@ -1578,8 +1926,7 @@ hack_identifier (value, name, yychar)
if (DECL_LANG_SPECIFIC (value)
&& DECL_CLASS_CONTEXT (value) != current_class_type)
{
- tree path;
- enum access_type access;
+ tree path, access;
register tree context
= (TREE_CODE (value) == FUNCTION_DECL && DECL_VIRTUAL_P (value))
? DECL_CLASS_CONTEXT (value)
@@ -1589,13 +1936,13 @@ hack_identifier (value, name, yychar)
if (path)
{
access = compute_access (path, value);
- if (access != access_public)
+ if (access != access_public_node)
{
if (TREE_CODE (value) == VAR_DECL)
error ("static member `%s' is %s",
IDENTIFIER_POINTER (name),
- TREE_PRIVATE (value) ? "private" :
- "from a private base class");
+ TREE_PRIVATE (value) ? "private"
+ : "from a private base class");
else
error ("enum `%s' is from private base class",
IDENTIFIER_POINTER (name));
@@ -1603,9 +1950,8 @@ hack_identifier (value, name, yychar)
}
}
}
- return value;
}
- if (TREE_CODE (value) == TREE_LIST && TREE_NONLOCAL_FLAG (value))
+ else if (TREE_CODE (value) == TREE_LIST && TREE_NONLOCAL_FLAG (value))
{
if (type == 0)
{
@@ -1617,437 +1963,167 @@ hack_identifier (value, name, yychar)
return value;
}
- if (TREE_CODE (type) == REFERENCE_TYPE)
- {
- my_friendly_assert (TREE_CODE (value) == VAR_DECL
- || TREE_CODE (value) == PARM_DECL
- || TREE_CODE (value) == RESULT_DECL, 252);
- return convert_from_reference (value);
- }
+ if (TREE_CODE (type) == REFERENCE_TYPE && ! processing_template_decl)
+ value = convert_from_reference (value);
return value;
}
-#if 0
-/* Given an object OF, and a type conversion operator COMPONENT
- build a call to the conversion operator, if a call is requested,
- or return the address (as a pointer to member function) if one is not.
-
- OF can be a TYPE_DECL or any kind of datum that would normally
- be passed to `build_component_ref'. It may also be NULL_TREE,
- in which case `current_class_type' and `current_class_decl'
- provide default values.
-
- BASETYPE_PATH, if non-null, is the path of basetypes
- to go through before we get the the instance of interest.
-
- PROTECT says whether we apply C++ scoping rules or not. */
-tree
-build_component_type_expr (of, component, basetype_path, protect)
- tree of, component, basetype_path;
- int protect;
-{
- tree cname = NULL_TREE;
- tree tmp, last;
- tree name;
- int flags = protect ? LOOKUP_NORMAL : LOOKUP_COMPLAIN;
-
- if (of)
- my_friendly_assert (IS_AGGR_TYPE (TREE_TYPE (of)), 253);
- my_friendly_assert (TREE_CODE (component) == TYPE_EXPR, 254);
-
- tmp = TREE_OPERAND (component, 0);
- last = NULL_TREE;
-
- while (tmp)
- {
- switch (TREE_CODE (tmp))
- {
- case CALL_EXPR:
- if (last)
- TREE_OPERAND (last, 0) = TREE_OPERAND (tmp, 0);
- else
- TREE_OPERAND (component, 0) = TREE_OPERAND (tmp, 0);
-
- last = groktypename (build_tree_list (TREE_TYPE (component),
- TREE_OPERAND (component, 0)));
- name = build_typename_overload (last);
- TREE_TYPE (name) = last;
-
- if (TREE_OPERAND (tmp, 0)
- && TREE_OPERAND (tmp, 0) != void_list_node)
- {
- cp_error ("`operator %T' requires empty parameter list", last);
- TREE_OPERAND (tmp, 0) = NULL_TREE;
- }
-
- if (of && TREE_CODE (of) != TYPE_DECL)
- return build_method_call (of, name, NULL_TREE, NULL_TREE, flags);
- else if (of)
- {
- tree this_this;
-
- if (current_class_decl == NULL_TREE)
- {
- cp_error ("object required for `operator %T' call",
- TREE_TYPE (name));
- return error_mark_node;
- }
-
- this_this = convert_pointer_to (TREE_TYPE (of),
- current_class_decl);
- this_this = build_indirect_ref (this_this, NULL_PTR);
- return build_method_call (this_this, name, NULL_TREE,
- NULL_TREE, flags | LOOKUP_NONVIRTUAL);
- }
- else if (current_class_decl)
- return build_method_call (tmp, name, NULL_TREE, NULL_TREE, flags);
-
- cp_error ("object required for `operator %T' call",
- TREE_TYPE (name));
- return error_mark_node;
-
- case INDIRECT_REF:
- case ADDR_EXPR:
- case ARRAY_REF:
- break;
-
- case SCOPE_REF:
- my_friendly_assert (cname == 0, 255);
- cname = TREE_OPERAND (tmp, 0);
- tmp = TREE_OPERAND (tmp, 1);
- break;
-
- default:
- my_friendly_abort (77);
- }
- last = tmp;
- tmp = TREE_OPERAND (tmp, 0);
- }
-
- last = groktypename (build_tree_list (TREE_TYPE (component), TREE_OPERAND (component, 0)));
- name = build_typename_overload (last);
- TREE_TYPE (name) = last;
- if (of && TREE_CODE (of) == TYPE_DECL)
- {
- if (cname == NULL_TREE)
- {
- cname = DECL_NAME (of);
- of = NULL_TREE;
- }
- else my_friendly_assert (cname == DECL_NAME (of), 256);
- }
-
- if (of)
- {
- tree this_this;
-
- if (current_class_decl == NULL_TREE)
- {
- cp_error ("object required for `operator %T' call",
- TREE_TYPE (name));
- return error_mark_node;
- }
-
- this_this = convert_pointer_to (TREE_TYPE (of), current_class_decl);
- return build_component_ref (this_this, name, 0, protect);
- }
- else if (cname)
- return build_offset_ref (cname, name);
- else if (current_class_name)
- return build_offset_ref (current_class_name, name);
-
- cp_error ("object required for `operator %T' member reference",
- TREE_TYPE (name));
- return error_mark_node;
-}
-#endif
-
-static char *
-thunk_printable_name (decl)
- tree decl;
-{
- return "<thunk function>";
-}
-
tree
make_thunk (function, delta)
tree function;
int delta;
{
- char buffer[250];
- tree thunk_fndecl, thunk_id;
+ tree thunk_id;
tree thunk;
- char *func_name;
- static int thunk_number = 0;
tree func_decl;
+
if (TREE_CODE (function) != ADDR_EXPR)
abort ();
func_decl = TREE_OPERAND (function, 0);
if (TREE_CODE (func_decl) != FUNCTION_DECL)
abort ();
- func_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func_decl));
- if (delta<=0)
- sprintf (buffer, "__thunk_%d_%s", -delta, func_name);
+
+ OB_INIT ();
+ OB_PUTS ("__thunk_");
+ if (delta > 0)
+ {
+ OB_PUTC ('n');
+ icat (delta);
+ }
else
- sprintf (buffer, "__thunk_n%d_%s", delta, func_name);
- thunk_id = get_identifier (buffer);
+ icat (-delta);
+ OB_PUTC ('_');
+ OB_PUTID (DECL_ASSEMBLER_NAME (func_decl));
+ OB_FINISH ();
+ thunk_id = get_identifier (obstack_base (&scratch_obstack));
+
thunk = IDENTIFIER_GLOBAL_VALUE (thunk_id);
if (thunk && TREE_CODE (thunk) != THUNK_DECL)
{
- error_with_decl ("implementation-reserved name `%s' used");
- IDENTIFIER_GLOBAL_VALUE (thunk_id) = thunk = NULL_TREE;
+ cp_error ("implementation-reserved name `%D' used", thunk_id);
+ thunk = NULL_TREE;
+ SET_IDENTIFIER_GLOBAL_VALUE (thunk_id, thunk);
}
if (thunk == NULL_TREE)
{
- thunk = build_decl (THUNK_DECL, thunk_id, TREE_TYPE (func_decl));
- DECL_RESULT (thunk)
- = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (vtable_entry_type)));
- TREE_READONLY (thunk) = TYPE_READONLY (TREE_TYPE (vtable_entry_type));
- TREE_THIS_VOLATILE (thunk) = TYPE_VOLATILE (TREE_TYPE (vtable_entry_type));
- make_function_rtl (thunk);
+ thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl));
+ TREE_READONLY (thunk) = TREE_READONLY (func_decl);
+ TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (func_decl);
+ comdat_linkage (thunk);
+ TREE_SET_CODE (thunk, THUNK_DECL);
DECL_INITIAL (thunk) = function;
THUNK_DELTA (thunk) = delta;
+ DECL_EXTERNAL (thunk) = 1;
+ DECL_ARTIFICIAL (thunk) = 1;
/* So that finish_file can write out any thunks that need to be: */
pushdecl_top_level (thunk);
}
return thunk;
}
+/* Emit the definition of a C++ multiple inheritance vtable thunk. */
+
void
emit_thunk (thunk_fndecl)
- tree thunk_fndecl;
+ tree thunk_fndecl;
{
- rtx insns;
- char *fnname;
- char buffer[250];
- tree argp;
- struct args_size stack_args_size;
tree function = TREE_OPERAND (DECL_INITIAL (thunk_fndecl), 0);
int delta = THUNK_DELTA (thunk_fndecl);
- int tem;
- int failure = 0;
- int current_call_is_indirect = 0; /* needed for HPPA FUNCTION_ARG */
-
- /* Used to remember which regs we need to emit a USE rtx for. */
- rtx need_use[FIRST_PSEUDO_REGISTER];
- int need_use_count = 0;
-
- /* rtx for the 'this' parameter. */
- rtx this_rtx = 0, this_reg_rtx = 0, fixed_this_rtx;
-
- char *(*save_decl_printable_name) () = decl_printable_name;
- /* Data on reg parms scanned so far. */
- CUMULATIVE_ARGS args_so_far;
if (TREE_ASM_WRITTEN (thunk_fndecl))
return;
TREE_ASM_WRITTEN (thunk_fndecl) = 1;
- if (TREE_PUBLIC (function))
- {
- TREE_PUBLIC (thunk_fndecl) = 1;
- if (DECL_EXTERNAL (function))
- {
- DECL_EXTERNAL (thunk_fndecl) = 1;
- assemble_external (thunk_fndecl);
- return;
- }
- }
+ TREE_ADDRESSABLE (function) = 1;
+ mark_used (function);
- decl_printable_name = thunk_printable_name;
if (current_function_decl)
abort ();
- current_function_decl = thunk_fndecl;
- init_function_start (thunk_fndecl, input_filename, lineno);
- pushlevel (0);
- expand_start_bindings (1);
-
- /* Start updating where the next arg would go. */
- INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (function), NULL_RTX);
- stack_args_size.constant = 0;
- stack_args_size.var = 0;
- /* SETUP for possible structure return address FIXME */
-
- /* Now look through all the parameters, make sure that we
- don't clobber any registers used for parameters.
- Also, pick up an rtx for the first "this" parameter. */
- for (argp = TYPE_ARG_TYPES (TREE_TYPE (function));
- argp != NULL_TREE;
- argp = TREE_CHAIN (argp))
- {
- tree passed_type = TREE_VALUE (argp);
- register rtx entry_parm;
- int named = 1; /* FIXME */
- struct args_size stack_offset;
- struct args_size arg_size;
-
- if (passed_type == void_type_node)
- break;
-
- if ((TREE_CODE (TYPE_SIZE (passed_type)) != INTEGER_CST
- && contains_placeholder_p (TYPE_SIZE (passed_type)))
-#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
- || FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far,
- TYPE_MODE (passed_type),
- passed_type, named)
-#endif
- )
- passed_type = build_pointer_type (passed_type);
-
- entry_parm = FUNCTION_ARG (args_so_far,
- TYPE_MODE (passed_type),
- passed_type,
- named);
- if (entry_parm != 0)
- need_use[need_use_count++] = entry_parm;
-
- locate_and_pad_parm (TYPE_MODE (passed_type), passed_type,
-#ifdef STACK_PARMS_IN_REG_PARM_AREA
- 1,
-#else
- entry_parm != 0,
-#endif
- thunk_fndecl,
- &stack_args_size, &stack_offset, &arg_size);
-
-/* REGNO (entry_parm);*/
- if (this_rtx == 0)
- {
- this_reg_rtx = entry_parm;
- if (!entry_parm)
- {
- rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
-
- rtx internal_arg_pointer, stack_parm;
-
- if ((ARG_POINTER_REGNUM == STACK_POINTER_REGNUM
- || ! (fixed_regs[ARG_POINTER_REGNUM]
- || ARG_POINTER_REGNUM == FRAME_POINTER_REGNUM)))
- internal_arg_pointer = copy_to_reg (virtual_incoming_args_rtx);
- else
- internal_arg_pointer = virtual_incoming_args_rtx;
-
- if (offset_rtx == const0_rtx)
- entry_parm = gen_rtx (MEM, TYPE_MODE (passed_type),
- internal_arg_pointer);
- else
- entry_parm = gen_rtx (MEM, TYPE_MODE (passed_type),
- gen_rtx (PLUS, Pmode,
- internal_arg_pointer,
- offset_rtx));
- }
-
- this_rtx = entry_parm;
- }
-
- FUNCTION_ARG_ADVANCE (args_so_far,
- TYPE_MODE (passed_type),
- passed_type,
- named);
- }
-
- fixed_this_rtx = plus_constant (this_rtx, delta);
- if (this_rtx != fixed_this_rtx)
- emit_move_insn (this_rtx, fixed_this_rtx);
-
- if (this_reg_rtx)
- emit_insn (gen_rtx (USE, VOIDmode, this_reg_rtx));
-
- emit_indirect_jump (XEXP (DECL_RTL (function), 0));
-
- while (need_use_count > 0)
- emit_insn (gen_rtx (USE, VOIDmode, need_use[--need_use_count]));
-
- expand_end_bindings (NULL, 1, 0);
- poplevel (0, 0, 1);
-
- /* From now on, allocate rtl in current_obstack, not in saveable_obstack.
- Note that that may have been done above, in save_for_inline_copying.
- The call to resume_temporary_allocation near the end of this function
- goes back to the usual state of affairs. */
-
- rtl_in_current_obstack ();
-
- insns = get_insns ();
-
- /* Copy any shared structure that should not be shared. */
-
- unshare_all_rtl (insns);
-
- /* Instantiate all virtual registers. */
-
- instantiate_virtual_regs (current_function_decl, get_insns ());
-
- /* We are no longer anticipating cse in this function, at least. */
-
- cse_not_expected = 1;
-
- /* Now we choose between stupid (pcc-like) register allocation
- (if we got the -noreg switch and not -opt)
- and smart register allocation. */
-
- if (optimize > 0) /* Stupid allocation probably won't work */
- obey_regdecls = 0; /* if optimizations being done. */
-
- regclass_init ();
-
- regclass (insns, max_reg_num ());
- if (obey_regdecls)
- {
- stupid_life_analysis (insns, max_reg_num (), NULL);
- failure = reload (insns, 0, NULL);
- }
- else
- {
- /* Do control and data flow analysis,
- and write some of the results to dump file. */
-
- flow_analysis (insns, max_reg_num (), NULL);
- local_alloc ();
- failure = global_alloc (NULL);
- }
-
- reload_completed = 1;
-
-#ifdef LEAF_REGISTERS
- leaf_function = 0;
- if (optimize > 0 && only_leaf_regs_used () && leaf_function_p ())
- leaf_function = 1;
-#endif
-
- /* If a machine dependent reorganization is needed, call it. */
-#ifdef MACHINE_DEPENDENT_REORG
- MACHINE_DEPENDENT_REORG (insns);
-#endif
-
- /* Now turn the rtl into assembler code. */
-
- {
- char *fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
- assemble_start_function (thunk_fndecl, fnname);
- final (insns, asm_out_file, optimize, 0);
- assemble_end_function (thunk_fndecl, fnname);
- };
-
- exit_rest_of_compilation:
+ TREE_SET_CODE (thunk_fndecl, FUNCTION_DECL);
- reload_completed = 0;
-
- /* Cancel the effect of rtl_in_current_obstack. */
-
- resume_temporary_allocation ();
+ {
+#ifdef ASM_OUTPUT_MI_THUNK
+ char *fnname;
+ current_function_decl = thunk_fndecl;
+ /* Make sure we build up its RTL before we go onto the
+ temporary obstack. */
+ make_function_rtl (thunk_fndecl);
+ temporary_allocation ();
+ DECL_RESULT (thunk_fndecl)
+ = build_decl (RESULT_DECL, 0, integer_type_node);
+ fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
+ init_function_start (thunk_fndecl, input_filename, lineno);
+ current_function_is_thunk = 1;
+ assemble_start_function (thunk_fndecl, fnname);
+ ASM_OUTPUT_MI_THUNK (asm_out_file, thunk_fndecl, delta, function);
+ assemble_end_function (thunk_fndecl, fnname);
+ permanent_allocation (1);
+ current_function_decl = 0;
+#else /* ASM_OUTPUT_MI_THUNK */
+ /* If we don't have the necessary macro for efficient thunks, generate a
+ thunk function that just makes a call to the real function.
+ Unfortunately, this doesn't work for varargs. */
+
+ tree a, t;
+
+ if (varargs_function_p (function))
+ cp_error ("generic thunk code fails for method `%#D' which uses `...'",
+ function);
+
+ /* Set up clone argument trees for the thunk. */
+ t = NULL_TREE;
+ for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a))
+ {
+ tree x = copy_node (a);
+ TREE_CHAIN (x) = t;
+ DECL_CONTEXT (x) = thunk_fndecl;
+ t = x;
+ }
+ a = nreverse (t);
+ DECL_ARGUMENTS (thunk_fndecl) = a;
+ DECL_RESULT (thunk_fndecl) = NULL_TREE;
+ DECL_LANG_SPECIFIC (thunk_fndecl) = DECL_LANG_SPECIFIC (function);
+ copy_lang_decl (thunk_fndecl);
+ DECL_INTERFACE_KNOWN (thunk_fndecl) = 1;
+ DECL_NOT_REALLY_EXTERN (thunk_fndecl) = 1;
+
+ start_function (NULL_TREE, thunk_fndecl, NULL_TREE, 1);
+ store_parm_decls ();
+ current_function_is_thunk = 1;
+
+ /* Build up the call to the real function. */
+ t = build_int_2 (delta, -1 * (delta < 0));
+ TREE_TYPE (t) = signed_type (sizetype);
+ t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
+ t = expr_tree_cons (NULL_TREE, t, NULL_TREE);
+ for (a = TREE_CHAIN (a); a; a = TREE_CHAIN (a))
+ t = expr_tree_cons (NULL_TREE, a, t);
+ t = nreverse (t);
+ t = build_call (function, TREE_TYPE (TREE_TYPE (function)), t);
+ c_expand_return (t);
+
+ finish_function (lineno, 0, 0);
+
+ /* Don't let the backend defer this function. */
+ if (DECL_DEFER_OUTPUT (thunk_fndecl))
+ {
+ output_inline_function (thunk_fndecl);
+ permanent_allocation (1);
+ }
+#endif /* ASM_OUTPUT_MI_THUNK */
+ }
- decl_printable_name = save_decl_printable_name;
- current_function_decl = 0;
+ TREE_SET_CODE (thunk_fndecl, THUNK_DECL);
}
/* Code for synthesizing methods which have default semantics defined. */
/* For the anonymous union in TYPE, return the member that is at least as
large as the rest of the members, so we can copy it. */
+
static tree
largest_union_member (type)
tree type;
@@ -2064,7 +2140,8 @@ largest_union_member (type)
}
/* Generate code for default X(X&) constructor. */
-void
+
+static void
do_build_copy_constructor (fndecl)
tree fndecl;
{
@@ -2078,9 +2155,13 @@ do_build_copy_constructor (fndecl)
parm = TREE_CHAIN (parm);
parm = convert_from_reference (parm);
- if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type))
+ if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type)
+ && is_empty_class (current_class_type))
+ /* Don't copy the padding byte; it might not have been allocated
+ if *this is a base subobject. */;
+ else if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type))
{
- t = build (INIT_EXPR, void_type_node, C_C_D, parm);
+ t = build (INIT_EXPR, void_type_node, current_class_ref, parm);
TREE_SIDE_EFFECTS (t) = 1;
cplus_expand_expr_stmt (t);
}
@@ -2099,8 +2180,12 @@ do_build_copy_constructor (fndecl)
(build_reference_type (basetype), parm,
CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
p = convert_from_reference (p);
- current_base_init_list = tree_cons (TYPE_NESTED_NAME (basetype),
- p, current_base_init_list);
+
+ if (p == error_mark_node)
+ cp_error ("in default copy constructor");
+ else
+ current_base_init_list = tree_cons (basetype,
+ p, current_base_init_list);
}
for (i = 0; i < n_bases; ++i)
@@ -2113,17 +2198,25 @@ do_build_copy_constructor (fndecl)
p = convert_to_reference
(build_reference_type (basetype), parm,
CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
- p = convert_from_reference (p);
- current_base_init_list = tree_cons (TYPE_NESTED_NAME (basetype),
- p, current_base_init_list);
+
+ if (p == error_mark_node)
+ cp_error ("in default copy constructor");
+ else
+ {
+ p = convert_from_reference (p);
+ current_base_init_list = tree_cons (basetype,
+ p, current_base_init_list);
+ }
}
for (; fields; fields = TREE_CHAIN (fields))
{
- tree name, init, t;
+ tree init, t;
tree field = fields;
if (TREE_CODE (field) != FIELD_DECL)
continue;
+
+ init = parm;
if (DECL_NAME (field))
{
if (VFIELD_NAME_P (DECL_NAME (field)))
@@ -2136,14 +2229,22 @@ do_build_copy_constructor (fndecl)
continue;
}
else if ((t = TREE_TYPE (field)) != NULL_TREE
- && TREE_CODE (t) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && ANON_UNION_TYPE_P (t)
&& TYPE_FIELDS (t) != NULL_TREE)
- field = largest_union_member (t);
+ {
+ do
+ {
+ init = build (COMPONENT_REF, t, init, field);
+ field = largest_union_member (t);
+ }
+ while ((t = TREE_TYPE (field)) != NULL_TREE
+ && ANON_UNION_TYPE_P (t)
+ && TYPE_FIELDS (t) != NULL_TREE);
+ }
else
continue;
- init = build (COMPONENT_REF, TREE_TYPE (field), parm, field);
+ init = build (COMPONENT_REF, TREE_TYPE (field), init, field);
init = build_tree_list (NULL_TREE, init);
current_member_init_list
@@ -2157,7 +2258,7 @@ do_build_copy_constructor (fndecl)
pop_momentary ();
}
-void
+static void
do_build_assign_ref (fndecl)
tree fndecl;
{
@@ -2168,9 +2269,13 @@ do_build_assign_ref (fndecl)
parm = convert_from_reference (parm);
- if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type))
+ if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)
+ && is_empty_class (current_class_type))
+ /* Don't copy the padding byte; it might not have been allocated
+ if *this is a base subobject. */;
+ else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type))
{
- tree t = build (MODIFY_EXPR, void_type_node, C_C_D, parm);
+ tree t = build (MODIFY_EXPR, void_type_node, current_class_ref, parm);
TREE_SIDE_EFFECTS (t) = 1;
cplus_expand_expr_stmt (t);
}
@@ -2184,17 +2289,13 @@ do_build_assign_ref (fndecl)
for (i = 0; i < n_bases; ++i)
{
tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
- if (TYPE_HAS_ASSIGN_REF (basetype))
- {
- tree p = convert_to_reference
- (build_reference_type (basetype), parm,
- CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
- p = convert_from_reference (p);
- p = build_member_call (TYPE_NESTED_NAME (basetype),
- ansi_opname [MODIFY_EXPR],
- build_tree_list (NULL_TREE, p));
- expand_expr_stmt (p);
- }
+ tree p = convert_to_reference
+ (build_reference_type (basetype), parm,
+ CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
+ p = convert_from_reference (p);
+ p = build_member_call (basetype, ansi_opname [MODIFY_EXPR],
+ build_expr_list (NULL_TREE, p));
+ expand_expr_stmt (p);
}
for (; fields; fields = TREE_CHAIN (fields))
{
@@ -2203,6 +2304,27 @@ do_build_assign_ref (fndecl)
if (TREE_CODE (field) != FIELD_DECL)
continue;
+
+ if (TREE_READONLY (field))
+ {
+ if (DECL_NAME (field))
+ cp_error ("non-static const member `%#D', can't use default assignment operator", field);
+ else
+ cp_error ("non-static const member in type `%T', can't use default assignment operator", current_class_type);
+ continue;
+ }
+ else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
+ {
+ if (DECL_NAME (field))
+ cp_error ("non-static reference member `%#D', can't use default assignment operator", field);
+ else
+ cp_error ("non-static reference member in type `%T', can't use default assignment operator", current_class_type);
+ continue;
+ }
+
+ comp = current_class_ref;
+ init = parm;
+
if (DECL_NAME (field))
{
if (VFIELD_NAME_P (DECL_NAME (field)))
@@ -2215,42 +2337,49 @@ do_build_assign_ref (fndecl)
continue;
}
else if ((t = TREE_TYPE (field)) != NULL_TREE
- && TREE_CODE (t) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+ && ANON_UNION_TYPE_P (t)
&& TYPE_FIELDS (t) != NULL_TREE)
- field = largest_union_member (t);
+ {
+ do
+ {
+ comp = build (COMPONENT_REF, t, comp, field);
+ init = build (COMPONENT_REF, t, init, field);
+ field = largest_union_member (t);
+ }
+ while ((t = TREE_TYPE (field)) != NULL_TREE
+ && ANON_UNION_TYPE_P (t)
+ && TYPE_FIELDS (t) != NULL_TREE);
+ }
else
continue;
- comp = build (COMPONENT_REF, TREE_TYPE (field), C_C_D, field);
- init = build (COMPONENT_REF, TREE_TYPE (field), parm, field);
+ comp = build (COMPONENT_REF, TREE_TYPE (field), comp, field);
+ init = build (COMPONENT_REF, TREE_TYPE (field), init, field);
expand_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
}
}
- c_expand_return (C_C_D);
+ c_expand_return (current_class_ref);
pop_momentary ();
}
-void push_cp_function_context ();
-void pop_cp_function_context ();
-
void
synthesize_method (fndecl)
tree fndecl;
{
int nested = (current_function_decl != NULL_TREE);
- tree context = decl_function_context (fndecl);
- char *f = input_filename;
- tree base = DECL_CLASS_CONTEXT (fndecl);
+ tree context = hack_decl_function_context (fndecl);
+
+ if (at_eof)
+ import_export_decl (fndecl);
- if (nested)
+ if (! context)
+ push_to_top_level ();
+ else if (nested)
push_cp_function_context (context);
- input_filename = DECL_SOURCE_FILE (fndecl);
- interface_unknown = CLASSTYPE_INTERFACE_UNKNOWN (base);
- interface_only = CLASSTYPE_INTERFACE_ONLY (base);
- start_function (NULL_TREE, fndecl, NULL_TREE, NULL_TREE, 1);
+ interface_unknown = 1;
+ start_function (NULL_TREE, fndecl, NULL_TREE, 1);
store_parm_decls ();
if (DECL_NAME (fndecl) == ansi_opname[MODIFY_EXPR])
@@ -2270,18 +2399,9 @@ synthesize_method (fndecl)
finish_function (lineno, 0, nested);
- /* Do we really *want* to inline this function? */
- if (DECL_INLINE (fndecl))
- {
- /* Turn off DECL_INLINE for the moment so function_cannot_inline_p
- will check our size. */
- DECL_INLINE (fndecl) = 0;
- if (function_cannot_inline_p (fndecl) == 0)
- DECL_INLINE (fndecl) = 1;
- }
-
- input_filename = f;
extract_interface_info ();
- if (nested)
+ if (! context)
+ pop_from_top_level ();
+ else if (nested)
pop_cp_function_context (context);
}
diff --git a/contrib/gcc/cp/mpw-config.in b/contrib/gcc/cp/mpw-config.in
new file mode 100644
index 0000000..88dd85f
--- /dev/null
+++ b/contrib/gcc/cp/mpw-config.in
@@ -0,0 +1,11 @@
+# Configuration fragment for G++.
+# Most of the real configuration work happens in the main GCC configure.
+
+# We need to join some lines in the Makefile.in before the sed
+# process will work properly. The funky little sed script works by
+# recognizing lines with a trailing '$@ \', adding the next line to
+# its "pattern space", editing out the backslash and line, then
+# putting the result out.
+
+sed -e '/$@ \\/{N;s/$@ \\./$@ /;P;D;}' \Option-d
+ "{srcdir}"Makefile.in >"{o}"hacked_Makefile.in
diff --git a/contrib/gcc/cp/mpw-make.sed b/contrib/gcc/cp/mpw-make.sed
new file mode 100644
index 0000000..120b5a1
--- /dev/null
+++ b/contrib/gcc/cp/mpw-make.sed
@@ -0,0 +1,112 @@
+# Sed commands to finish translating the G++ Unix makefile into MPW syntax.
+
+# Remove control-Ls, they upset MPW make.
+s/ //g
+
+# Remove references to always-empty variables used to mark things.
+/CYGNUS-LOCAL-/s/{CYGNUS-LOCAL-[a-z0-9]*}//g
+
+# Add a bunch of definitions, mostly empty.
+/^# Variables that exist for you to override.$/a\
+\
+xmake_file = \
+tmake_file = \
+build_xm_file = \
+MALLOC = \
+MD_DEPS = \
+REAL_H = \
+HOST_CC_LD = {CC_LD}\
+ALL_CCLDFLAGS = \
+HOST_CCLDFLAGS = \
+CONFIG_H = \
+LIBDEPS = \
+
+# The "target" variable is special to MPW make, avoid it.
+/{target}/s/{target}/{target_canonical}/g
+
+# Suppress the suppression of smart makes.
+/^\.y\.c/d
+
+# Whack out "..." assignments.
+/\.\.\./s/^\([a-z_]*= \.\.\.\)/#\1/
+
+# Previous edits go a little overboard, undo.
+/^objext = /s/"{o}"//
+
+# Always link in low-level MPW functions.
+/^LIBDEPS=/s/$/ ::strerror.c.o ::mpwlib.c.o/
+/{CLIB}/s/{CLIB}/ ::strerror.c.o ::mpwlib.c.o {CLIB}/
+
+# Don't get tricky about finding various .o file, point at dir above.
+/^SUBDIR_OBSTACK/s/`.*`/::obstack.c.o/
+/^SUBDIR_USE_ALLOCA/s/`.*`/::alloca.c.o/
+/^SUBDIR_MALLOC/s/`.*`//
+
+# Point includes at parent directly correctly.
+/^INCLUDES = /s/:\./::/g
+/^INCLUDES = /s/"{srcdir}"\.\./"{topsrcdir}"gcc:/g
+/^INCLUDES = /s,"{srcdir}"/\.\.,"{topsrcdir}"gcc:,g
+/^INCLUDES = /s,"{srcdir}":config,"{topsrcdir}"gcc:config:,g
+
+# Add the special MPW include dirs.
+/^INCLUDES = /s/$/ -i "{topsrcdir}"include:mpw: -i :::extra-include:/
+
+# A nasty hack to reduce confusion.
+/true/s/ ; @true$//
+
+# (should be in common translation?)
+/{CC_LD} /s/$/ {EXTRALIBS}/
+
+# Don't use general compiler flags (which may include definitions
+# and other compiler-only bits) with linking commands.
+/{CC_LD} /s/ALL_CFLAGS/ALL_CCLDFLAGS/
+
+# Whack out build rules that are not useful.
+/^Makefile \\Option-f /,/^$/d
+/^config.status \\Option-f /,/^$/d
+# (Note that MPW make is not case sensitive, and so this name
+# is considered the same as "md_file".)
+/^{MD_FILE} \\Option-f/,/^$/d
+
+# Depending on config.status is not useful for us.
+/config.status/s/ config.status//
+
+# Repeat of stuff from generic edit.
+/{s}/s/"{s}""{s}"/"{s}"/g
+/{s}/s/"{s}""{srcdir}"/"{s}"/g
+/{s}/s/"{srcdir}""{s}"/"{s}"/g
+
+# Fix references to C frontend files in main dir.
+/::c-/s/"{o}"::c-/"{o}":c-/g
+
+# Fix pathnames to generated files in the objdir.
+/parse/s/"{s}"parse\.\([chy]\)/"{o}"parse.\1/g
+/parse/s/^parse\.\([chy]\)/"{o}"parse.\1/
+/y.tab.c/s/"{s}"y\.tab\.c/"{o}"y.tab.c/g
+/y.tab.c/s/^y\.tab\.c/"{o}"y.tab.c/
+/y.tab.h/s/"{s}"y\.tab\.h/"{o}"y.tab.h/g
+/y.tab.h/s/^y\.tab\.h/"{o}"y.tab.h/
+
+# Put in the definition of YYEMPTY directly.
+/grep/s/grep .* >>/Echo '#define YYEMPTY -1' >>/
+
+# If the dates are wrong, then this tries to run gperf, which we don't
+# really want.
+/^"{srcdir}"hash.h/,/hash.h$/d
+
+# Sed the object file list instead of using cat (meow).
+/cat/s/`cat /`sed -e 's,:,::,g' -e 's,{objext},.o,g' /
+
+# Simplify dependencies of generated parser files.
+/^{PARSE_C}/s/^/#/
+/^stamp-parse/s/^stamp-parse/{PARSE_C}/
+
+# Fix the compile line for the generated parser.
+/{CC} -c/,/echo {PARSE_C}/c\
+ {CC} @DASH_C_FLAG@ {ALL_CFLAGS} {ALL_CPPFLAGS} {INCLUDES} {BIG_SWITCHFLAG} "{o}"parse.c -o "{o}"parse.c.o\
+
+# Change all Rez commands to use mac-gcc.r.
+/{REZ}/s/"{s}"[-a-zA-Z{}]*\.r/"{topsrcdir}"gcc:mac-gcc.r/
+
+# Remove pathname junk from the container name.
+/{REZ}/s/'"'::cc1plus'"'/'"'cc1plus'"'/
diff --git a/contrib/gcc/cp/new.cc b/contrib/gcc/cp/new.cc
new file mode 100644
index 0000000..28187a4
--- /dev/null
+++ b/contrib/gcc/cp/new.cc
@@ -0,0 +1,42 @@
+// Implementation file for the -*- C++ -*- dynamic memory management header.
+// Copyright (C) 1996 Free Software Foundation
+
+// This file is part of GNU CC.
+
+// GNU CC 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, or (at your option)
+// any later version.
+
+// GNU CC 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 GNU CC; see the file COPYING. If not, write to
+// the Free Software Foundation, 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+// As a special exception, if you link this library with other files,
+// some of which are compiled with GCC, to produce an executable,
+// this library does not by itself cause the resulting executable
+// to be covered by the GNU General Public License.
+// This exception does not however invalidate any other reasons why
+// the executable file might be covered by the GNU General Public License.
+
+#pragma implementation "new"
+#include "new"
+
+const std::nothrow_t std::nothrow = { };
+
+using std::new_handler;
+new_handler __new_handler;
+
+new_handler
+set_new_handler (new_handler handler)
+{
+ new_handler prev_handler = __new_handler;
+ __new_handler = handler;
+ return prev_handler;
+}
diff --git a/contrib/gcc/cp/new1.cc b/contrib/gcc/cp/new1.cc
new file mode 100644
index 0000000..5bb85c9
--- /dev/null
+++ b/contrib/gcc/cp/new1.cc
@@ -0,0 +1,89 @@
+// Support routines for the -*- C++ -*- dynamic memory management.
+// Copyright (C) 1997 Free Software Foundation
+
+// This file is part of GNU CC.
+
+// GNU CC 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, or (at your option)
+// any later version.
+
+// GNU CC 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 GNU CC; see the file COPYING. If not, write to
+// the Free Software Foundation, 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+// As a special exception, if you link this library with other files,
+// some of which are compiled with GCC, to produce an executable,
+// this library does not by itself cause the resulting executable
+// to be covered by the GNU General Public License.
+// This exception does not however invalidate any other reasons why
+// the executable file might be covered by the GNU General Public License.
+
+#include "new"
+using std::new_handler;
+using std::bad_alloc;
+
+extern "C" void *malloc (size_t);
+extern new_handler __new_handler;
+
+#define WEAK(x) \
+ x __attribute__ ((weak)); \
+ x
+
+#ifdef L_op_newnt
+WEAK (void * operator new (size_t sz, const std::nothrow_t&) throw())
+{
+ void *p;
+
+ /* malloc (0) is unpredictable; avoid it. */
+ if (sz == 0)
+ sz = 1;
+ p = (void *) malloc (sz);
+ while (p == 0)
+ {
+ new_handler handler = __new_handler;
+ if (! handler)
+ return 0;
+ try
+ {
+ handler ();
+ }
+ catch (bad_alloc &)
+ {
+ return 0;
+ }
+
+ p = (void *) malloc (sz);
+ }
+
+ return p;
+}
+#endif
+
+#ifdef L_op_new
+WEAK (void * operator new (size_t sz) throw (std::bad_alloc))
+{
+ void *p;
+
+ /* malloc (0) is unpredictable; avoid it. */
+ if (sz == 0)
+ sz = 1;
+ p = (void *) malloc (sz);
+ while (p == 0)
+ {
+ new_handler handler = __new_handler;
+ if (! handler)
+ throw bad_alloc ();
+ handler ();
+ p = (void *) malloc (sz);
+ }
+
+ return p;
+}
+#endif
diff --git a/contrib/gcc/cp/new2.cc b/contrib/gcc/cp/new2.cc
new file mode 100644
index 0000000..0be1c0d
--- /dev/null
+++ b/contrib/gcc/cp/new2.cc
@@ -0,0 +1,80 @@
+// Boilerplate support routines for -*- C++ -*- dynamic memory management.
+// Copyright (C) 1997 Free Software Foundation
+
+// This file is part of GNU CC.
+
+// GNU CC 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, or (at your option)
+// any later version.
+
+// GNU CC 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 GNU CC; see the file COPYING. If not, write to
+// the Free Software Foundation, 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+// As a special exception, if you link this library with other files,
+// some of which are compiled with GCC, to produce an executable,
+// this library does not by itself cause the resulting executable
+// to be covered by the GNU General Public License.
+// This exception does not however invalidate any other reasons why
+// the executable file might be covered by the GNU General Public License.
+
+#include "new"
+
+extern "C" void free (void *);
+
+#define WEAK(x) \
+ x __attribute__ ((weak)); \
+ x
+
+#ifdef L_op_vnew
+WEAK(void * operator new[] (size_t sz) throw (std::bad_alloc))
+{
+ return ::operator new(sz);
+}
+#endif
+
+#ifdef L_op_vnewnt
+WEAK(void *operator new[] (size_t sz, const std::nothrow_t& nothrow) throw())
+{
+ return ::operator new(sz, nothrow);
+}
+#endif
+
+#ifdef L_op_delete
+WEAK (void operator delete (void *ptr) throw ())
+{
+ if (ptr)
+ free (ptr);
+}
+#endif
+
+#ifdef L_op_vdel
+WEAK (void operator delete[] (void *ptr) throw ())
+{
+ if (ptr)
+ free (ptr);
+}
+#endif
+
+#ifdef L_op_delnt
+WEAK (void operator delete (void *ptr, const std::nothrow_t&) throw ())
+{
+ if (ptr)
+ free (ptr);
+}
+#endif
+
+#ifdef L_op_vdelnt
+WEAK (void operator delete[] (void *ptr, const std::nothrow_t&) throw ())
+{
+ if (ptr)
+ free (ptr);
+}
+#endif
diff --git a/contrib/gcc/cp/parse.y b/contrib/gcc/cp/parse.y
index fd034af..279cec3 100644
--- a/contrib/gcc/cp/parse.y
+++ b/contrib/gcc/cp/parse.y
@@ -1,5 +1,5 @@
/* YACC parser for C++ syntax.
- Copyright (C) 1988, 1989, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1988, 89, 93, 94, 95, 1996 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -32,8 +32,7 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
-#include <stdio.h>
-#include <errno.h>
+#include "system.h"
#include "tree.h"
#include "input.h"
@@ -41,6 +40,8 @@ Boston, MA 02111-1307, USA. */
#include "lex.h"
#include "cp-tree.h"
#include "output.h"
+#include "except.h"
+#include "toplev.h"
/* Since parsers are distinct for each language, put the language string
definition here. (fnf) */
@@ -49,18 +50,7 @@ char *language_string = "GNU C++";
extern tree void_list_node;
extern struct obstack permanent_obstack;
-#ifndef errno
-extern int errno;
-#endif
-
extern int end_of_file;
-extern int current_class_depth;
-
-/* FSF LOCAL dje prefix attributes */
-extern tree strip_attrs PROTO((tree));
-/* END FSF LOCAL */
-
-void yyerror ();
/* Like YYERROR but do call yyerror. */
#define YYERROR1 { yyerror ("syntax error"); YYERROR; }
@@ -72,12 +62,12 @@ void yyerror ();
error message if the user supplies an empty conditional expression. */
static char *cond_stmt_keyword;
+static tree empty_parms PROTO((void));
+
/* Nonzero if we have an `extern "C"' acting as an extern specifier. */
int have_extern_spec;
int used_extern_spec;
-void yyhook ();
-
/* Cons up an empty parameter list. */
#ifdef __GNUC__
__inline
@@ -87,17 +77,19 @@ empty_parms ()
{
tree parms;
- if (strict_prototype)
+ if (strict_prototype
+ || current_class_type != NULL)
parms = void_list_node;
else
parms = NULL_TREE;
return parms;
}
+
%}
%start program
-%union {long itype; tree ttype; char *strtype; enum tree_code code; }
+%union {long itype; tree ttype; char *strtype; enum tree_code code; flagged_type_tree ftype; }
/* All identifiers that are not reserved words
and are not declared typedefs in the current block */
@@ -107,6 +99,10 @@ empty_parms ()
In some contexts, they are treated just like IDENTIFIER,
but they can also serve as typespecs in declarations. */
%token TYPENAME
+%token SELFNAME
+
+/* A template function. */
+%token PFUNCNAME
/* Reserved words that specify storage class.
yylval contains an IDENTIFIER_NODE which indicates which one. */
@@ -118,7 +114,7 @@ empty_parms ()
/* Reserved words that qualify type: "const" or "volatile".
yylval contains an IDENTIFIER_NODE which indicates which one. */
-%token TYPE_QUAL
+%token CV_QUALIFIER
/* Character or numeric constants.
yylval is the node for the constant. */
@@ -132,16 +128,17 @@ empty_parms ()
%token ELLIPSIS
/* the reserved words */
-/* SCO include files test "ASM", so use something else. */
+/* SCO include files test "ASM", so use something else. */
%token SIZEOF ENUM /* STRUCT UNION */ IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
-%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD GCC_ASM_KEYWORD TYPEOF ALIGNOF
+%token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
%token SIGOF
%token ATTRIBUTE EXTENSION LABEL
+%token REALPART IMAGPART
/* the reserved words... C++ extensions */
%token <ttype> AGGR
-%token <itype> VISSPEC
-%token DELETE NEW OVERLOAD THIS OPERATOR CXX_TRUE CXX_FALSE
+%token <ttype> VISSPEC
+%token DELETE NEW THIS OPERATOR CXX_TRUE CXX_FALSE
%token NAMESPACE TYPENAME_KEYWORD USING
%token LEFT_RIGHT TEMPLATE
%token TYPEID DYNAMIC_CAST STATIC_CAST REINTERPRET_CAST CONST_CAST
@@ -159,7 +156,7 @@ empty_parms ()
%nonassoc IF
%nonassoc ELSE
-%left IDENTIFIER TYPENAME PTYPENAME SCSPEC TYPESPEC TYPE_QUAL ENUM AGGR ELLIPSIS TYPEOF SIGOF OPERATOR NSNAME TYPENAME_KEYWORD
+%left IDENTIFIER PFUNCNAME TYPENAME SELFNAME PTYPENAME SCSPEC TYPESPEC CV_QUALIFIER ENUM AGGR ELLIPSIS TYPEOF SIGOF OPERATOR NSNAME TYPENAME_KEYWORD
%left '{' ',' ';'
@@ -190,14 +187,15 @@ empty_parms ()
%type <code> unop
%type <ttype> identifier IDENTIFIER TYPENAME CONSTANT expr nonnull_exprlist
-%type <ttype> paren_expr_or_null nontrivial_exprlist
+%type <ttype> PFUNCNAME maybe_identifier
+%type <ttype> paren_expr_or_null nontrivial_exprlist SELFNAME
%type <ttype> expr_no_commas cast_expr unary_expr primary string STRING
-%type <ttype> typed_declspecs reserved_declspecs boolean.literal
-%type <ttype> typed_typespecs reserved_typespecquals
-%type <ttype> declmods typespec typespecqual_reserved
-%type <ttype> SCSPEC TYPESPEC TYPE_QUAL nonempty_type_quals maybe_type_qual
+%type <ttype> reserved_declspecs boolean.literal
+%type <ttype> reserved_typespecquals
+%type <ttype> declmods
+%type <ttype> SCSPEC TYPESPEC CV_QUALIFIER maybe_cv_qualifier
%type <itype> initdecls notype_initdecls initdcl /* C++ modification */
-%type <ttype> init initlist maybeasm maybe_init
+%type <ttype> init initlist maybeasm maybe_init defarg defarg1
%type <ttype> asm_operands nonnull_asm_operands asm_operand asm_clobbers
%type <ttype> maybe_attribute attributes attribute attribute_list attrib
%type <ttype> any_word
@@ -207,77 +205,84 @@ empty_parms ()
%type <ttype> declarator notype_declarator after_type_declarator
%type <ttype> direct_notype_declarator direct_after_type_declarator
-%type <ttype> structsp opt.component_decl_list component_decl_list
+%type <ttype> opt.component_decl_list component_decl_list
%type <ttype> component_decl component_decl_1 components notype_components
-%type <ttype> component_declarator component_declarator0
+%type <ttype> component_declarator component_declarator0 self_reference
%type <ttype> notype_component_declarator notype_component_declarator0
%type <ttype> after_type_component_declarator after_type_component_declarator0
%type <ttype> enumlist enumerator
-%type <ttype> type_id absdcl type_quals
+%type <ttype> absdcl cv_qualifiers
%type <ttype> direct_abstract_declarator conversion_declarator
-%type <ttype> new_type_id new_declarator direct_new_declarator
-%type <ttype> xexpr parmlist parms parm bad_parm full_parm
+%type <ttype> new_declarator direct_new_declarator
+%type <ttype> xexpr parmlist parms bad_parm
%type <ttype> identifiers_or_typenames
%type <ttype> fcast_or_absdcl regcast_or_absdcl
%type <ttype> expr_or_declarator complex_notype_declarator
%type <ttype> notype_unqualified_id unqualified_id qualified_id
+%type <ttype> template_id do_id object_template_id notype_template_declarator
%type <ttype> overqualified_id notype_qualified_id any_id
%type <ttype> complex_direct_notype_declarator functional_cast
-%type <ttype> named_parm complex_parmlist typed_declspecs1 parms_comma
+%type <ttype> complex_parmlist parms_comma
+%type <ttype> namespace_qualifier namespace_using_decl
+
+%type <ftype> type_id new_type_id typed_typespecs typespec typed_declspecs
+%type <ftype> typed_declspecs1 type_specifier_seq nonempty_cv_qualifiers
+%type <ftype> structsp typespecqual_reserved parm named_parm full_parm
/* C++ extensions */
-%token <ttype> TYPENAME_ELLIPSIS PTYPENAME
+%token <ttype> PTYPENAME
%token <ttype> PRE_PARSED_FUNCTION_DECL EXTERN_LANG_STRING ALL
-%token <ttype> PRE_PARSED_CLASS_DECL
-%type <ttype> fn.def1 /* Not really! */
-%type <ttype> fn.def2 return_id
+%token <ttype> PRE_PARSED_CLASS_DECL DEFARG DEFARG_MARKER
+%type <ttype> component_constructor_declarator
+%type <ttype> fn.def2 return_id fn.defpen constructor_declarator
%type <itype> ctor_initializer_opt
%type <ttype> named_class_head named_class_head_sans_basetype
%type <ttype> named_complex_class_head_sans_basetype
%type <ttype> unnamed_class_head
%type <ttype> class_head base_class_list
-%type <itype> base_class_access_list
+%type <ttype> base_class_access_list
%type <ttype> base_class maybe_base_class_list base_class.1
%type <ttype> exception_specification_opt ansi_raise_identifier ansi_raise_identifiers
%type <ttype> operator_name
%type <ttype> object aggr
-%type <itype> new delete
+%type <itype> new delete .begin_new_placement
/* %type <ttype> primary_no_id */
%type <ttype> nonmomentary_expr maybe_parmlist
-%type <itype> initdcl0 notype_initdcl0 member_init_list
+%type <itype> initdcl0 notype_initdcl0 member_init_list initdcl0_innards
%type <ttype> template_header template_parm_list template_parm
-%type <ttype> template_type_parm
-%type <ttype> template_type template_arg_list template_arg
-%type <ttype> template_instantiation template_type_name tmpl.2
-%type <ttype> template_instantiate_once template_instantiate_some
-%type <itype> fn_tmpl_end
-/* %type <itype> try_for_typename */
+%type <ttype> template_type_parm template_template_parm
+%type <code> template_close_bracket
+%type <ttype> template_type template_arg_list template_arg_list_opt
+%type <ttype> template_arg
%type <ttype> condition xcond paren_cond_or_null
%type <ttype> type_name nested_name_specifier nested_type ptr_to_mem
-%type <ttype> qualified_type_name complete_type_name notype_identifier
+%type <ttype> complete_type_name notype_identifier nonnested_type
%type <ttype> complex_type_name nested_name_specifier_1
-%type <itype> nomods_initdecls nomods_initdcl0
-%type <ttype> new_initializer new_placement specialization type_specifier_seq
-%type <ttype> using_decl .poplevel
-
-/* in order to recognize aggr tags as defining and thus shadowing. */
+%type <ttype> new_initializer new_placement
+%type <ttype> using_decl
+%type <ttype> typename_sub typename_sub0 typename_sub1 typename_sub2
+%type <ttype> explicit_template_type
+/* in order to recognize aggr tags as defining and thus shadowing. */
%token TYPENAME_DEFN IDENTIFIER_DEFN PTYPENAME_DEFN
-%type <ttype> named_class_head_sans_basetype_defn
+%type <ttype> named_class_head_sans_basetype_defn
%type <ttype> identifier_defn IDENTIFIER_DEFN TYPENAME_DEFN PTYPENAME_DEFN
+%type <ttype> self_template_type
+
%token NSNAME
%type <ttype> NSNAME
/* Used in lex.c for parsing pragmas. */
%token END_OF_LINE
-/* lex.c and pt.c depends on this being the last token. Define
+/* lex.c and pt.c depend on this being the last token. Define
any new tokens before this one! */
%token END_OF_SAVED_INPUT
%{
/* List of types and structure classes of the current declaration. */
static tree current_declspecs;
+
/* List of prefix attributes in effect.
Prefix attributes are parsed by the reserved_declspecs and declmods
rules. They create a list that contains *both* declspecs and attrs. */
@@ -291,28 +296,51 @@ static tree current_aggr;
/* Tell yyparse how to print a token's value, if yydebug is set. */
#define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL)
-extern void yyprint ();
+extern void yyprint PROTO((FILE *, int, YYSTYPE));
extern tree combine_strings PROTO((tree));
+
+static int
+parse_decl(declarator, specs_attrs, attributes, initialized, decl)
+ tree declarator;
+ tree specs_attrs;
+ tree attributes;
+ int initialized;
+ tree* decl;
+{
+ int sm;
+
+ split_specs_attrs (specs_attrs, &current_declspecs, &prefix_attributes);
+ if (current_declspecs
+ && TREE_CODE (current_declspecs) != TREE_LIST)
+ current_declspecs = get_decl_list (current_declspecs);
+ if (have_extern_spec && !used_extern_spec)
+ {
+ current_declspecs = decl_tree_cons (NULL_TREE,
+ get_identifier ("extern"),
+ current_declspecs);
+ used_extern_spec = 1;
+ }
+ sm = suspend_momentary ();
+ *decl = start_decl (declarator, current_declspecs, initialized,
+ attributes, prefix_attributes);
+ return sm;
+}
%}
%%
-program: /* empty */
+program:
+ /* empty */
| extdefs
- {
- /* In case there were missing closebraces,
- get us back to the global binding level. */
- while (! global_bindings_p ())
- poplevel (0, 0, 0);
- finish_file ();
- }
+ { finish_translation_unit (); }
;
/* the reason for the strange actions in this rule
is so that notype_initdecls when reached via datadef
- can find a valid list of type and sc specs in $0. */
+ can find a valid list of type and sc specs in $0. */
extdefs:
- { $<ttype>$ = NULL_TREE; } lang_extdef
+ { $<ttype>$ = NULL_TREE; }
+ lang_extdef
{ $<ttype>$ = NULL_TREE; }
| extdefs lang_extdef
{ $<ttype>$ = NULL_TREE; }
@@ -332,32 +360,36 @@ extdefs_opt:
{ have_extern_spec = 0; }
;
+extension:
+ EXTENSION
+ { $<itype>$ = pedantic;
+ pedantic = 0; }
+ ;
+
asm_keyword:
ASM_KEYWORD
- | GCC_ASM_KEYWORD
;
lang_extdef:
- { if (pending_lang_change) do_pending_lang_change(); }
+ { if (pending_lang_change) do_pending_lang_change(); }
extdef
- { if (! toplevel_bindings_p () && ! pseudo_global_level_p())
- pop_everything (); }
+ { if (! toplevel_bindings_p () && ! pseudo_global_level_p())
+ pop_everything (); }
;
extdef:
- fndef
+ fndef eat_saved_input
{ if (pending_inlines) do_pending_inlines (); }
| datadef
{ if (pending_inlines) do_pending_inlines (); }
| template_def
{ if (pending_inlines) do_pending_inlines (); }
- | overloaddef
| asm_keyword '(' string ')' ';'
{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3);
assemble_asm ($3); }
| extern_lang_string '{' extdefs_opt '}'
{ pop_lang_context (); }
- | extern_lang_string .hush_warning fndef .warning_ok
+ | extern_lang_string .hush_warning fndef .warning_ok eat_saved_input
{ if (pending_inlines) do_pending_inlines ();
pop_lang_context (); }
| extern_lang_string .hush_warning datadef .warning_ok
@@ -371,12 +403,24 @@ extdef:
{ push_namespace (NULL_TREE); }
extdefs_opt '}'
{ pop_namespace (); }
- | NAMESPACE identifier '=' any_id ';'
- { do_namespace_alias ($2, $4); }
+ | namespace_alias
| using_decl ';'
{ do_toplevel_using_decl ($1); }
- | USING NAMESPACE any_id ';'
- { do_using_directive ($3); }
+ | using_directive
+ | extension extdef
+ { pedantic = $<itype>1; }
+ ;
+
+namespace_alias:
+ NAMESPACE identifier '='
+ { begin_only_namespace_names (); }
+ any_id ';'
+ {
+ end_only_namespace_names ();
+ if (lastiddecl)
+ $5 = lastiddecl;
+ do_namespace_alias ($2, $5);
+ }
;
using_decl:
@@ -388,6 +432,45 @@ using_decl:
{ $$ = $3; }
;
+namespace_using_decl:
+ USING namespace_qualifier identifier
+ { $$ = build_parse_node (SCOPE_REF, $2, $3); }
+ | USING global_scope identifier
+ { $$ = build_parse_node (SCOPE_REF, global_namespace, $3); }
+ | USING global_scope namespace_qualifier identifier
+ { $$ = build_parse_node (SCOPE_REF, $3, $4); }
+ ;
+
+using_directive:
+ USING NAMESPACE
+ { begin_only_namespace_names (); }
+ any_id ';'
+ {
+ end_only_namespace_names ();
+ /* If no declaration was found, the using-directive is
+ invalid. Since that was not reported, we need the
+ identifier for the error message. */
+ if (TREE_CODE ($4) == IDENTIFIER_NODE && lastiddecl)
+ $4 = lastiddecl;
+ do_using_directive ($4);
+ }
+ ;
+
+namespace_qualifier:
+ NSNAME SCOPE
+ {
+ if (TREE_CODE ($$) == IDENTIFIER_NODE)
+ $$ = lastiddecl;
+ got_scope = $$;
+ }
+ | namespace_qualifier NSNAME SCOPE
+ {
+ $$ = $2;
+ if (TREE_CODE ($$) == IDENTIFIER_NODE)
+ $$ = lastiddecl;
+ got_scope = $$;
+ }
+
any_id:
unqualified_id
| qualified_id
@@ -411,6 +494,9 @@ template_header:
{ begin_template_parm_list (); }
template_parm_list '>'
{ $$ = end_template_parm_list ($4); }
+ | TEMPLATE '<' '>'
+ { begin_specialization();
+ $$ = NULL_TREE; }
;
template_parm_list:
@@ -420,22 +506,22 @@ template_parm_list:
{ $$ = process_template_parm ($1, $3); }
;
+maybe_identifier:
+ identifier
+ { $$ = $1; }
+ | /* empty */
+ { $$ = NULL_TREE; }
+
template_type_parm:
- aggr
- {
- $$ = build_tree_list ($1, NULL_TREE);
- ttpa:
- if (TREE_PURPOSE ($$) == signature_type_node)
- sorry ("signature as template type parameter");
- else if (TREE_PURPOSE ($$) != class_type_node)
- pedwarn ("template type parameters must use the keyword `class'");
- }
- | aggr identifier
- { $$ = build_tree_list ($1, $2); goto ttpa; }
- | TYPENAME_KEYWORD
- { $$ = build_tree_list (class_type_node, NULL_TREE); }
- | TYPENAME_KEYWORD identifier
- { $$ = build_tree_list (class_type_node, $2); }
+ aggr maybe_identifier
+ { $$ = finish_template_type_parm ($1, $2); }
+ | TYPENAME_KEYWORD maybe_identifier
+ { $$ = finish_template_type_parm (class_type_node, $2); }
+ ;
+
+template_template_parm:
+ template_header aggr maybe_identifier
+ { $$ = finish_template_template_parm ($2, $3); }
;
template_parm:
@@ -447,169 +533,65 @@ template_parm:
their match before considering them nameless parameter
declarations. */
template_type_parm
- { $$ = build_tree_list (NULL_TREE, $$); }
- | template_type_parm '=' typespec
- { $$ = build_tree_list ($3, $$); }
- | full_parm
- ;
-
-overloaddef:
- OVERLOAD ov_identifiers ';'
- { warning ("use of `overload' is an anachronism"); }
- ;
-
-ov_identifiers: IDENTIFIER
- { declare_overloaded ($1); }
- | ov_identifiers ',' IDENTIFIER
- { declare_overloaded ($3); }
- ;
-
-template_def:
- /* Class template declarations go here; they aren't normal class
- declarations, because we can't process the bodies yet. */
- template_header named_class_head_sans_basetype '{'
- { yychar = '{'; goto template1; }
- ';'
- | template_header named_class_head_sans_basetype_defn '{'
- { yychar = '{'; goto template1; }
- ';'
- | template_header named_class_head_sans_basetype ':'
- { yychar = ':'; goto template1; }
- ';'
- | template_header named_class_head_sans_basetype_defn ':'
- {
- yychar = ':';
- template1:
- if (current_aggr == signature_type_node)
- sorry ("template type defining a signature");
- /* Maybe pedantic warning for union?
- How about an enum? :-) */
- end_template_decl ($1, $2, current_aggr, 1);
- reinit_parse_for_template (yychar, $1, $2);
- yychar = YYEMPTY;
- }
- ';'
- | template_header named_class_head_sans_basetype ';'
- {
- end_template_decl ($1, $2, current_aggr, 0);
- /* declare $2 as template name with $1 parm list */
- }
- | template_header named_class_head_sans_basetype_defn ';'
- {
- end_template_decl ($1, $2, current_aggr, 0);
- /* declare $2 as template name with $1 parm list */
- }
- | template_header /* notype_initdcl0 ';' */
- notype_declarator exception_specification_opt maybeasm maybe_attribute
- fn_tmpl_end
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | template_type_parm '=' type_id
+ { $$ = build_tree_list (groktypename ($3.t), $1); }
+ | parm
+ { $$ = build_tree_list (NULL_TREE, $1.t); }
+ | parm '=' expr_no_commas %prec ARITHCOMPARE
+ { $$ = build_tree_list ($3, $1.t); }
+ | template_template_parm
+ { $$ = build_tree_list (NULL_TREE, $1); }
+ | template_template_parm '=' template_arg
{
- tree d;
- int momentary;
- int def = ($6 != ';');
- momentary = suspend_momentary ();
- d = start_decl ($<ttype>2, /*current_declspecs*/NULL_TREE, 0,
- $3);
- cplus_decl_attributes (d, $5, /*prefix_attributes*/NULL_TREE);
- cp_finish_decl (d, NULL_TREE, $4, 0, 0);
- end_template_decl ($1, d, 0, def);
- if (def)
- reinit_parse_for_template ((int) $6, $1, d);
- resume_momentary (momentary);
- }
- | template_header typed_declspecs /*initdcl0*/
- declarator exception_specification_opt maybeasm maybe_attribute
- fn_tmpl_end
- {
- tree d, specs, attrs;
- int momentary;
- int def = ($7 != ';');
- split_specs_attrs ($2, &specs, &attrs);
- momentary = suspend_momentary ();
- d = start_decl ($<ttype>3, specs, 0, $<ttype>4);
- cplus_decl_attributes (d, $6, attrs);
- cp_finish_decl (d, NULL_TREE, $5, 0, 0);
- end_template_decl ($1, d, 0, def);
- if (def)
+ if (TREE_CODE ($3) != TEMPLATE_DECL
+ && TREE_CODE ($3) != TEMPLATE_TEMPLATE_PARM
+ && TREE_CODE ($3) != TYPE_DECL)
{
- reinit_parse_for_template ((int) $7, $1, d);
- yychar = YYEMPTY;
+ error ("invalid default template argument");
+ $3 = error_mark_node;
}
- note_list_got_semicolon ($<ttype>2);
- resume_momentary (momentary);
- }
- | template_header declmods notype_declarator fn_tmpl_end
- {
- tree d, specs, attrs;
- int def = ($4 != ';');
- split_specs_attrs ($2, &specs, &attrs);
- d = start_decl ($<ttype>3, specs, 0, NULL_TREE);
- cplus_decl_attributes (d, NULL_TREE, attrs);
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
- end_template_decl ($1, d, 0, def);
- if (def)
- reinit_parse_for_template ((int) $4, $1, d);
+ $$ = build_tree_list ($3, $1);
}
- /* Try to recover from syntax errors in templates. */
- | template_header error '}' { end_template_decl ($1, 0, 0, 0); }
- | template_header error ';' { end_template_decl ($1, 0, 0, 0); }
;
-fn_tmpl_end: '{' { $$ = '{'; }
- | ':' { $$ = ':'; }
- | ';' { $$ = ';'; }
- | '=' { $$ = '='; }
- | RETURN { $$ = RETURN; }
+template_def:
+ template_header
+ extdef
+ {
+ if ($1)
+ end_template_decl ();
+ else
+ end_specialization ();
+ }
+ | template_header
+ error %prec EMPTY
+ {
+ if ($1)
+ end_template_decl ();
+ else
+ end_specialization ();
+ }
;
datadef:
nomods_initdecls ';'
- {}
| declmods notype_initdecls ';'
{}
- /* Normal case to make fast: "const i;". */
- | declmods notype_declarator ';'
- { tree d, specs, attrs;
- split_specs_attrs ($1, &specs, &attrs);
- d = start_decl ($<ttype>2, specs, 0, NULL_TREE);
- cplus_decl_attributes (d, NULL_TREE, attrs);
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
- }
| typed_declspecs initdecls ';'
{
- note_list_got_semicolon ($<ttype>$);
- }
- /* Normal case: make this fast. */
- | typed_declspecs declarator ';'
- { tree d, specs, attrs;
- split_specs_attrs ($1, &specs, &attrs);
- d = start_decl ($<ttype>2, specs, 0, NULL_TREE);
- cplus_decl_attributes (d, NULL_TREE, attrs);
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
- note_list_got_semicolon ($<ttype>$);
+ note_list_got_semicolon ($1.t);
}
| declmods ';'
- { pedwarn ("empty declaration"); }
+ { pedwarn ("empty declaration"); }
| explicit_instantiation ';'
| typed_declspecs ';'
- {
- tree t, attrs;
- split_specs_attrs ($1, &t, &attrs);
- shadow_tag (t);
- if (TREE_CODE (t) == TREE_LIST
- && TREE_PURPOSE (t) == NULL_TREE)
- {
- t = TREE_VALUE (t);
- if (IS_AGGR_TYPE (t)
- && IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (t)))
- {
- if (CLASSTYPE_USE_TEMPLATE (t) == 0)
- SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t);
- else if (CLASSTYPE_TEMPLATE_INSTANTIATION (t))
- error ("override declaration for already-expanded template");
- }
- }
- note_list_got_semicolon ($<ttype>$);
- }
+ {
+ tree t, attrs;
+ split_specs_attrs ($1.t, &t, &attrs);
+ shadow_tag (t);
+ note_list_got_semicolon ($1.t);
+ }
| error ';'
| error '}'
| ';'
@@ -635,79 +617,108 @@ eat_saved_input:
fndef:
fn.def1 maybe_return_init ctor_initializer_opt compstmt_or_error
- {
- finish_function (lineno, (int)$3, 0);
- if ($<ttype>$) process_next_inline ($<ttype>$);
- }
+ { finish_function (lineno, (int)$3, 0); }
| fn.def1 maybe_return_init function_try_block
- {
- if ($<ttype>$) process_next_inline ($<ttype>$);
+ { }
+ | fn.def1 maybe_return_init error
+ { }
+ ;
+
+constructor_declarator:
+ nested_name_specifier SELFNAME '('
+ { $$ = begin_constructor_declarator ($1, $2); }
+ parmlist ')' cv_qualifiers exception_specification_opt
+ { $$ = make_call_declarator ($<ttype>4, $5, $7, $8); }
+ | nested_name_specifier SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt
+ { $$ = begin_constructor_declarator ($1, $2);
+ $$ = make_call_declarator ($$, empty_parms (), $4, $5);
+ }
+ | global_scope nested_name_specifier SELFNAME '('
+ { $$ = begin_constructor_declarator ($2, $3); }
+ parmlist ')' cv_qualifiers exception_specification_opt
+ { $$ = make_call_declarator ($<ttype>5, $6, $8, $9); }
+ | global_scope nested_name_specifier SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt
+ { $$ = begin_constructor_declarator ($2, $3);
+ $$ = make_call_declarator ($$, empty_parms (), $5, $6);
+ }
+ | nested_name_specifier self_template_type '('
+ { $$ = begin_constructor_declarator ($1, $2); }
+ parmlist ')' cv_qualifiers exception_specification_opt
+ { $$ = make_call_declarator ($<ttype>4, $5, $7, $8); }
+ | nested_name_specifier self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt
+ { $$ = begin_constructor_declarator ($1, $2);
+ $$ = make_call_declarator ($$, empty_parms (), $4, $5);
+ }
+ | global_scope nested_name_specifier self_template_type '('
+ { $$ = begin_constructor_declarator ($2, $3); }
+ parmlist ')' cv_qualifiers exception_specification_opt
+ { $$ = make_call_declarator ($<ttype>5, $6, $8, $9); }
+ | global_scope nested_name_specifier self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt
+ { $$ = begin_constructor_declarator ($2, $3);
+ $$ = make_call_declarator ($$, empty_parms (), $5, $6);
}
- eat_saved_input
- | typed_declspecs declarator error
- {}
- | declmods notype_declarator error
- {}
- | notype_declarator error
- {}
;
fn.def1:
- typed_declspecs declarator exception_specification_opt
- { tree specs, attrs;
- split_specs_attrs ($1, &specs, &attrs);
- if (! start_function (specs, $2, $3, attrs, 0))
- YYERROR1;
- reinit_parse_for_function ();
- $$ = NULL_TREE; }
- | declmods notype_declarator exception_specification_opt
- { tree specs = strip_attrs ($1);
- if (! start_function (specs, $2, $3, NULL_TREE, 0))
- YYERROR1;
- reinit_parse_for_function ();
- $$ = NULL_TREE; }
- | notype_declarator exception_specification_opt
- { if (! start_function (NULL_TREE, $$, $2, NULL_TREE, 0))
- YYERROR1;
- reinit_parse_for_function ();
- $$ = NULL_TREE; }
- | PRE_PARSED_FUNCTION_DECL
- { start_function (NULL_TREE, TREE_VALUE ($$),
- NULL_TREE, NULL_TREE, 1);
- reinit_parse_for_function (); }
+ typed_declspecs declarator
+ { if (!begin_function_definition ($1.t, $2))
+ YYERROR1; }
+ | declmods notype_declarator
+ { if (!begin_function_definition ($1, $2))
+ YYERROR1; }
+ | notype_declarator
+ { if (!begin_function_definition (NULL_TREE, $1))
+ YYERROR1; }
+ | declmods constructor_declarator
+ { if (!begin_function_definition ($1, $2))
+ YYERROR1; }
+ | constructor_declarator
+ { if (!begin_function_definition (NULL_TREE, $1))
+ YYERROR1; }
+ ;
+
+component_constructor_declarator:
+ SELFNAME '(' parmlist ')' cv_qualifiers exception_specification_opt
+ { $$ = make_call_declarator ($1, $3, $5, $6); }
+ | SELFNAME LEFT_RIGHT cv_qualifiers exception_specification_opt
+ { $$ = make_call_declarator ($1, empty_parms (), $3, $4); }
+ | self_template_type '(' parmlist ')' cv_qualifiers exception_specification_opt
+ { $$ = make_call_declarator ($1, $3, $5, $6); }
+ | self_template_type LEFT_RIGHT cv_qualifiers exception_specification_opt
+ { $$ = make_call_declarator ($1, empty_parms (), $3, $4); }
;
/* more C++ complexity. See component_decl for a comment on the
reduce/reduce conflict introduced by these rules. */
fn.def2:
- typed_declspecs '(' parmlist ')' type_quals exception_specification_opt
+ declmods component_constructor_declarator
{ tree specs = strip_attrs ($1);
- $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs), $3, $5);
- $$ = start_method (TREE_CHAIN (specs), $$, $6);
+ $$ = start_method (specs, $2);
rest_of_mdef:
if (! $$)
YYERROR1;
if (yychar == YYEMPTY)
yychar = YYLEX;
reinit_parse_for_method (yychar, $$); }
- | typed_declspecs LEFT_RIGHT type_quals exception_specification_opt
- { tree specs = strip_attrs ($1);
- $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs),
- empty_parms (), $3);
- $$ = start_method (TREE_CHAIN (specs), $$, $4);
- goto rest_of_mdef;
- }
- | typed_declspecs declarator exception_specification_opt
+ | component_constructor_declarator
+ { $$ = start_method (NULL_TREE, $1); goto rest_of_mdef; }
+ | typed_declspecs declarator
+ { tree specs = strip_attrs ($1.t);
+ $$ = start_method (specs, $2); goto rest_of_mdef; }
+ | declmods notype_declarator
{ tree specs = strip_attrs ($1);
- $$ = start_method (specs, $2, $3); goto rest_of_mdef; }
- | declmods notype_declarator exception_specification_opt
+ $$ = start_method (specs, $2); goto rest_of_mdef; }
+ | notype_declarator
+ { $$ = start_method (NULL_TREE, $$); goto rest_of_mdef; }
+ | declmods constructor_declarator
{ tree specs = strip_attrs ($1);
- $$ = start_method (specs, $2, $3); goto rest_of_mdef; }
- | notype_declarator exception_specification_opt
- { $$ = start_method (NULL_TREE, $$, $2); goto rest_of_mdef; }
+ $$ = start_method (specs, $2); goto rest_of_mdef; }
+ | constructor_declarator
+ { $$ = start_method (NULL_TREE, $$); goto rest_of_mdef; }
;
-return_id: RETURN IDENTIFIER
+return_id:
+ RETURN IDENTIFIER
{
if (! current_function_parms_stored)
store_parm_decls ();
@@ -715,7 +726,8 @@ return_id: RETURN IDENTIFIER
}
;
-return_init: return_id maybe_init
+return_init:
+ return_id maybe_init
{ store_return_init ($<ttype>$, $2); }
| return_id '(' nonnull_exprlist ')'
{ store_return_init ($<ttype>$, $3); }
@@ -737,7 +749,7 @@ base_init:
;
.set_base_init:
- /* empty */
+ /* empty */
{
if (! current_function_parms_stored)
store_parm_decls ();
@@ -765,40 +777,39 @@ member_init_list:
| member_init_list error
;
-member_init: '(' nonnull_exprlist ')'
+member_init:
+ '(' nonnull_exprlist ')'
{
- if (current_class_name && !flag_traditional)
+ if (current_class_name)
pedwarn ("anachronistic old style base class initializer");
- expand_member_init (C_C_D, NULL_TREE, $2);
+ expand_member_init (current_class_ref, NULL_TREE, $2);
}
| LEFT_RIGHT
{
- if (current_class_name && !flag_traditional)
+ if (current_class_name)
pedwarn ("anachronistic old style base class initializer");
- expand_member_init (C_C_D, NULL_TREE, void_type_node);
+ expand_member_init (current_class_ref, NULL_TREE, void_type_node);
}
| notype_identifier '(' nonnull_exprlist ')'
- { expand_member_init (C_C_D, $<ttype>$, $3); }
+ { expand_member_init (current_class_ref, $1, $3); }
| notype_identifier LEFT_RIGHT
- { expand_member_init (C_C_D, $<ttype>$, void_type_node); }
- | complete_type_name '(' nonnull_exprlist ')'
- { expand_member_init (C_C_D, $<ttype>$, $3); }
- | complete_type_name LEFT_RIGHT
- { expand_member_init (C_C_D, $<ttype>$, void_type_node); }
- /* GNU extension */
- | notype_qualified_id '(' nonnull_exprlist ')'
- {
- do_member_init (OP0 ($1), OP1 ($1), $3);
- }
- | notype_qualified_id LEFT_RIGHT
- {
- do_member_init (OP0 ($1), OP1 ($1), void_type_node);
- }
+ { expand_member_init (current_class_ref, $1, void_type_node); }
+ | nonnested_type '(' nonnull_exprlist ')'
+ { expand_member_init (current_class_ref, $1, $3); }
+ | nonnested_type LEFT_RIGHT
+ { expand_member_init (current_class_ref, $1, void_type_node); }
+ | typename_sub '(' nonnull_exprlist ')'
+ { expand_member_init (current_class_ref, TYPE_MAIN_DECL ($1),
+ $3); }
+ | typename_sub LEFT_RIGHT
+ { expand_member_init (current_class_ref, TYPE_MAIN_DECL ($1),
+ void_type_node); }
;
identifier:
IDENTIFIER
| TYPENAME
+ | SELFNAME
| PTYPENAME
| NSNAME
;
@@ -806,7 +817,7 @@ identifier:
notype_identifier:
IDENTIFIER
| PTYPENAME
- | NSNAME %prec EMPTY
+ | NSNAME %prec EMPTY
;
identifier_defn:
@@ -816,43 +827,90 @@ identifier_defn:
;
explicit_instantiation:
- TEMPLATE specialization template_instantiation
- { do_type_instantiation ($3 ? $3 : $2, NULL_TREE); }
- | TEMPLATE typed_declspecs declarator
- { tree specs = strip_attrs ($2);
- do_function_instantiation (specs, $3, NULL_TREE); }
- | TEMPLATE notype_declarator
- { do_function_instantiation (NULL_TREE, $2, NULL_TREE); }
- | SCSPEC TEMPLATE specialization template_instantiation
- { do_type_instantiation ($4 ? $4 : $3, $1); }
- | SCSPEC TEMPLATE typed_declspecs declarator
- { tree specs = strip_attrs ($3);
- do_function_instantiation (specs, $4, $1); }
- | SCSPEC TEMPLATE notype_declarator
- { do_function_instantiation (NULL_TREE, $3, $1); }
- ;
+ TEMPLATE begin_explicit_instantiation typespec ';'
+ { do_type_instantiation ($3.t, NULL_TREE);
+ yyungetc (';', 1); }
+ end_explicit_instantiation
+ | TEMPLATE begin_explicit_instantiation typed_declspecs declarator
+ { tree specs = strip_attrs ($3.t);
+ do_decl_instantiation (specs, $4, NULL_TREE); }
+ end_explicit_instantiation
+ | TEMPLATE begin_explicit_instantiation notype_declarator
+ { do_decl_instantiation (NULL_TREE, $3, NULL_TREE); }
+ end_explicit_instantiation
+ | TEMPLATE begin_explicit_instantiation constructor_declarator
+ { do_decl_instantiation (NULL_TREE, $3, NULL_TREE); }
+ end_explicit_instantiation
+ | SCSPEC TEMPLATE begin_explicit_instantiation typespec ';'
+ { do_type_instantiation ($4.t, $1);
+ yyungetc (';', 1); }
+ end_explicit_instantiation
+ | SCSPEC TEMPLATE begin_explicit_instantiation typed_declspecs
+ declarator
+ { tree specs = strip_attrs ($4.t);
+ do_decl_instantiation (specs, $5, $1); }
+ end_explicit_instantiation
+ | SCSPEC TEMPLATE begin_explicit_instantiation notype_declarator
+ { do_decl_instantiation (NULL_TREE, $4, $1); }
+ end_explicit_instantiation
+ | SCSPEC TEMPLATE begin_explicit_instantiation constructor_declarator
+ { do_decl_instantiation (NULL_TREE, $4, $1); }
+ end_explicit_instantiation
+ ;
+
+begin_explicit_instantiation:
+ { begin_explicit_instantiation(); }
+
+end_explicit_instantiation:
+ { end_explicit_instantiation(); }
+
+/* The TYPENAME expansions are to deal with use of a template class name as
+ a template within the class itself, where the template decl is hidden by
+ a type decl. Got all that? */
template_type:
- template_type_name tmpl.2 template_instantiation
- { if ($3) $$ = $3; }
+ PTYPENAME '<' template_arg_list_opt template_close_bracket
+ {
+ $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
+ if ($$ != error_mark_node)
+ $$ = TYPE_STUB_DECL ($$);
+ }
+ | TYPENAME '<' template_arg_list_opt template_close_bracket
+ {
+ $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
+ if ($$ != error_mark_node)
+ $$ = TYPE_STUB_DECL ($$);
+ }
+ | self_template_type
;
-template_type_name:
- PTYPENAME '<' template_arg_list '>'
- { $$ = lookup_template_class ($$, $3, NULL_TREE); }
- | PTYPENAME '<' '>'
- { $$ = lookup_template_class ($$, NULL_TREE, NULL_TREE); }
- | TYPENAME '<' template_arg_list '>'
- { $$ = lookup_template_class ($$, $3, NULL_TREE); }
+self_template_type:
+ SELFNAME '<' template_arg_list_opt template_close_bracket
+ {
+ $$ = lookup_template_class ($1, $3, NULL_TREE, NULL_TREE);
+ if ($$ != error_mark_node)
+ $$ = TYPE_STUB_DECL ($$);
+ }
;
-tmpl.2:
- /* empty */ %prec EMPTY
- { $$ = instantiate_class_template ($<ttype>0, 1); }
+template_close_bracket:
+ '>'
+ | RSHIFT
+ {
+ /* Handle `Class<Class<Type>>' without space in the `>>' */
+ pedwarn ("`>>' should be `> >' in template class name");
+ yyungetc ('>', 1);
+ }
;
+template_arg_list_opt:
+ /* empty */
+ { $$ = NULL_TREE; }
+ | template_arg_list
+ ;
+
template_arg_list:
- template_arg
+ template_arg
{ $$ = build_tree_list (NULL_TREE, $$); }
| template_arg_list ',' template_arg
{ $$ = chainon ($$, build_tree_list (NULL_TREE, $3)); }
@@ -860,77 +918,14 @@ template_arg_list:
template_arg:
type_id
- { $$ = groktypename ($$); }
- | expr_no_commas %prec UNARY
- ;
-
-template_instantiate_once:
- PRE_PARSED_CLASS_DECL maybe_base_class_list
- {
- tree t, decl, tmpl;
-
- tmpl = TREE_PURPOSE (IDENTIFIER_TEMPLATE ($1));
- t = xref_tag (DECL_TEMPLATE_INFO (tmpl)->aggr, $1, $2, 0);
- set_current_level_tags_transparency (1);
- my_friendly_assert (TREE_CODE (t) == RECORD_TYPE
- || TREE_CODE (t) == UNION_TYPE, 257);
- $<ttype>$ = t;
-
- /* Now, put a copy of the decl in global scope, to avoid
- recursive expansion. */
- decl = IDENTIFIER_LOCAL_VALUE ($1);
- if (!decl)
- decl = IDENTIFIER_CLASS_VALUE ($1);
- /* Now, put a copy of the decl in global scope, to avoid
- recursive expansion. */
- if (decl)
- {
- /* Need to copy it to clear the chain pointer,
- and need to get it into permanent storage. */
- my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 258);
- push_obstacks (&permanent_obstack, &permanent_obstack);
- decl = copy_node (decl);
- if (DECL_LANG_SPECIFIC (decl))
- copy_lang_decl (decl);
- pop_obstacks ();
- pushdecl_top_level (decl);
- }
- /* Kludge; see instantiate_class_template. */
- TYPE_BEING_DEFINED (t) = 0;
- }
- left_curly opt.component_decl_list '}'
- {
- tree t = finish_struct ($<ttype>3, $5, 0);
-
- pop_obstacks ();
- end_template_instantiation ($1);
-
- repo_template_used (t);
-
- /* Now go after the methods & class data. */
- instantiate_member_templates ($1);
-
- pop_tinst_level();
-
- CLASSTYPE_GOT_SEMICOLON (t) = 1;
- }
+ { $$ = groktypename ($1.t); }
+ | PTYPENAME
+ { $$ = lastiddecl; }
+ | expr_no_commas %prec ARITHCOMPARE
;
-template_instantiation:
- /* empty */
- { $$ = NULL_TREE; }
- | template_instantiate_once
- { $$ = $1; }
- ;
-
-template_instantiate_some:
- /* empty */
- { $$ = NULL_TREE; /* never used from here... */}
- | template_instantiate_once template_instantiate_some
- { $$ = $1; /*???*/ }
- ;
-
-unop: '-'
+unop:
+ '-'
{ $$ = NEGATE_EXPR; }
| '+'
{ $$ = CONVERT_EXPR; }
@@ -942,7 +937,8 @@ unop: '-'
{ $$ = TRUTH_NOT_EXPR; }
;
-expr: nontrivial_exprlist
+expr:
+ nontrivial_exprlist
{ $$ = build_x_compound_expr ($$); }
| expr_no_commas
;
@@ -953,7 +949,7 @@ paren_expr_or_null:
cond_stmt_keyword);
$$ = integer_zero_node; }
| '(' expr ')'
- { $$ = condition_conversion ($2); }
+ { $$ = $2; }
;
paren_cond_or_null:
@@ -962,20 +958,19 @@ paren_cond_or_null:
cond_stmt_keyword);
$$ = integer_zero_node; }
| '(' condition ')'
- { $$ = condition_conversion ($2); }
+ { $$ = $2; }
;
xcond:
- /* empty */
+ /* empty */
{ $$ = NULL_TREE; }
| condition
- { $$ = condition_conversion ($$); }
| error
{ $$ = NULL_TREE; }
;
condition:
- type_specifier_seq declarator exception_specification_opt maybeasm maybe_attribute '='
+ type_specifier_seq declarator maybeasm maybe_attribute '='
{ {
tree d;
for (d = getdecls (); d; d = TREE_CHAIN (d))
@@ -987,17 +982,16 @@ condition:
cp_error ("definition of enum `%T' in condition", s);
}
}
- current_declspecs = $1;
- $<itype>6 = suspend_momentary ();
- $<ttype>$ = start_decl ($<ttype>2, current_declspecs, 1, $3);
- cplus_decl_attributes ($<ttype>$, $5,
- /*prefix_attributes*/ NULL_TREE);
+ current_declspecs = $1.t;
+ $<itype>5 = suspend_momentary ();
+ $<ttype>$ = start_decl ($<ttype>2, current_declspecs, 1,
+ $4, /*prefix_attributes*/ NULL_TREE);
}
- init
+ init
{
- cp_finish_decl ($<ttype>7, $8, $5, 0, LOOKUP_ONLYCONVERTING);
- resume_momentary ($<itype>6);
- $$ = $<ttype>7;
+ cp_finish_decl ($<ttype>6, $7, $4, 1, LOOKUP_ONLYCONVERTING);
+ resume_momentary ($<itype>5);
+ $$ = convert_from_reference ($<ttype>6);
if (TREE_CODE (TREE_TYPE ($$)) == ARRAY_TYPE)
cp_error ("definition of array `%#D' in condition", $$);
}
@@ -1012,45 +1006,39 @@ compstmtend:
;
already_scoped_stmt:
- '{' compstmtend
- { finish_stmt (); }
+ '{'
+ { $<ttype>$ = begin_compound_stmt (1); }
+ compstmtend
+ { finish_compound_stmt (1, $<ttype>2); }
| simple_stmt
;
nontrivial_exprlist:
expr_no_commas ',' expr_no_commas
- { $$ = tree_cons (NULL_TREE, $$,
- build_tree_list (NULL_TREE, $3)); }
+ { $$ = expr_tree_cons (NULL_TREE, $$,
+ build_expr_list (NULL_TREE, $3)); }
| expr_no_commas ',' error
- { $$ = tree_cons (NULL_TREE, $$,
- build_tree_list (NULL_TREE, error_mark_node)); }
+ { $$ = expr_tree_cons (NULL_TREE, $$,
+ build_expr_list (NULL_TREE, error_mark_node)); }
| nontrivial_exprlist ',' expr_no_commas
- { chainon ($$, build_tree_list (NULL_TREE, $3)); }
+ { chainon ($$, build_expr_list (NULL_TREE, $3)); }
| nontrivial_exprlist ',' error
- { chainon ($$, build_tree_list (NULL_TREE, error_mark_node)); }
+ { chainon ($$, build_expr_list (NULL_TREE, error_mark_node)); }
;
nonnull_exprlist:
expr_no_commas
- { $$ = build_tree_list (NULL_TREE, $$); }
+ { $$ = build_expr_list (NULL_TREE, $$); }
| nontrivial_exprlist
;
unary_expr:
- primary %prec UNARY
- {
-#if 0
- if (TREE_CODE ($$) == TYPE_EXPR)
- $$ = build_component_type_expr (C_C_D, $$, NULL_TREE, 1);
-#endif
- }
+ primary %prec UNARY
+ { $$ = $1; }
/* __extension__ turns off -pedantic for following primary. */
- | EXTENSION
- { $<itype>1 = pedantic;
- pedantic = 0; }
- cast_expr %prec UNARY
- { $$ = $3;
+ | extension cast_expr %prec UNARY
+ { $$ = $2;
pedantic = $<itype>1; }
| '*' cast_expr %prec UNARY
{ $$ = build_x_indirect_ref ($2, "unary *"); }
@@ -1059,71 +1047,62 @@ unary_expr:
| '~' cast_expr
{ $$ = build_x_unary_op (BIT_NOT_EXPR, $2); }
| unop cast_expr %prec UNARY
- { $$ = build_x_unary_op ($1, $2);
- if ($1 == NEGATE_EXPR && TREE_CODE ($2) == INTEGER_CST)
- TREE_NEGATED_INT ($$) = 1;
- overflow_warning ($$);
- }
+ { $$ = finish_unary_op_expr ($1, $2); }
/* Refer to the address of a label as a pointer. */
| ANDAND identifier
- { tree label = lookup_label ($2);
- if (label == NULL_TREE)
- $$ = null_pointer_node;
- else
- {
- TREE_USED (label) = 1;
- $$ = build1 (ADDR_EXPR, ptr_type_node, label);
- TREE_CONSTANT ($$) = 1;
- }
- }
+ { if (pedantic)
+ pedwarn ("ANSI C++ forbids `&&'");
+ $$ = finish_label_address_expr ($2); }
| SIZEOF unary_expr %prec UNARY
- { if (TREE_CODE ($2) == COMPONENT_REF
- && DECL_BIT_FIELD (TREE_OPERAND ($2, 1)))
- error ("sizeof applied to a bit-field");
- /* ANSI says arrays and functions are converted inside comma.
- But we can't really convert them in build_compound_expr
- because that would break commas in lvalues.
- So do the conversion here if operand was a comma. */
- if (TREE_CODE ($2) == COMPOUND_EXPR
- && (TREE_CODE (TREE_TYPE ($2)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE ($2)) == FUNCTION_TYPE))
- $2 = default_conversion ($2);
- else if (TREE_CODE ($2) == TREE_LIST)
- {
- tree t = TREE_VALUE ($2);
- if (t != NULL_TREE
- && ((TREE_TYPE (t)
- && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
- || is_overloaded_fn (t)))
- pedwarn ("ANSI C++ forbids taking the sizeof a function type");
- }
- $$ = c_sizeof (TREE_TYPE ($2)); }
+ { $$ = expr_sizeof ($2); }
| SIZEOF '(' type_id ')' %prec HYPERUNARY
- { $$ = c_sizeof (groktypename ($3)); }
+ { $$ = c_sizeof (groktypename ($3.t)); }
| ALIGNOF unary_expr %prec UNARY
{ $$ = grok_alignof ($2); }
| ALIGNOF '(' type_id ')' %prec HYPERUNARY
- { $$ = c_alignof (groktypename ($3)); }
+ { $$ = c_alignof (groktypename ($3.t));
+ check_for_new_type ("alignof", $3); }
/* The %prec EMPTY's here are required by the = init initializer
syntax extension; see below. */
- | new new_type_id %prec EMPTY
- { $$ = build_new (NULL_TREE, $2, NULL_TREE, $1); }
+ | new new_type_id %prec EMPTY
+ { $$ = build_new (NULL_TREE, $2.t, NULL_TREE, $1);
+ check_for_new_type ("new", $2); }
| new new_type_id new_initializer
- { $$ = build_new (NULL_TREE, $2, $3, $1); }
- | new new_placement new_type_id %prec EMPTY
- { $$ = build_new ($2, $3, NULL_TREE, $1); }
+ { $$ = build_new (NULL_TREE, $2.t, $3, $1);
+ check_for_new_type ("new", $2); }
+ | new new_placement new_type_id %prec EMPTY
+ { $$ = build_new ($2, $3.t, NULL_TREE, $1);
+ check_for_new_type ("new", $3); }
| new new_placement new_type_id new_initializer
- { $$ = build_new ($2, $3, $4, $1); }
- | new '(' type_id ')' %prec EMPTY
- { $$ = build_new (NULL_TREE, groktypename($3),
- NULL_TREE, $1); }
- | new '(' type_id ')' new_initializer
- { $$ = build_new (NULL_TREE, groktypename($3), $5, $1); }
- | new new_placement '(' type_id ')' %prec EMPTY
- { $$ = build_new ($2, groktypename($4), NULL_TREE, $1); }
- | new new_placement '(' type_id ')' new_initializer
- { $$ = build_new ($2, groktypename($4), $6, $1); }
+ { $$ = build_new ($2, $3.t, $4, $1);
+ check_for_new_type ("new", $3); }
+ /* The .begin_new_placement in the following rules is
+ necessary to avoid shift/reduce conflicts that lead to
+ mis-parsing some expressions. Of course, these constructs
+ are not really new-placement and it is bogus to call
+ begin_new_placement. But, the parser cannot always tell at this
+ point whether the next thing is an expression or a type-id,
+ so there is nothing we can do. Fortunately,
+ begin_new_placement does nothing harmful. When we rewrite
+ the parser, this lossage should be removed, of course. */
+ | new '(' .begin_new_placement type_id .finish_new_placement
+ %prec EMPTY
+ { $$ = build_new (NULL_TREE, groktypename($4.t),
+ NULL_TREE, $1);
+ check_for_new_type ("new", $4); }
+ | new '(' .begin_new_placement type_id .finish_new_placement
+ new_initializer
+ { $$ = build_new (NULL_TREE, groktypename($4.t), $6, $1);
+ check_for_new_type ("new", $4); }
+ | new new_placement '(' .begin_new_placement type_id
+ .finish_new_placement %prec EMPTY
+ { $$ = build_new ($2, groktypename($5.t), NULL_TREE, $1);
+ check_for_new_type ("new", $5); }
+ | new new_placement '(' .begin_new_placement type_id
+ .finish_new_placement new_initializer
+ { $$ = build_new ($2, groktypename($5.t), $7, $1);
+ check_for_new_type ("new", $5); }
| delete cast_expr %prec UNARY
{ $$ = delete_sanity ($2, NULL_TREE, 0, $1); }
@@ -1131,20 +1110,34 @@ unary_expr:
{ $$ = delete_sanity ($4, NULL_TREE, 1, $1);
if (yychar == YYEMPTY)
yychar = YYLEX; }
- | delete '[' expr ']' cast_expr %prec UNARY
+ | delete '[' expr ']' cast_expr %prec UNARY
{ $$ = delete_sanity ($5, $3, 2, $1);
if (yychar == YYEMPTY)
yychar = YYLEX; }
+ | REALPART cast_expr %prec UNARY
+ { $$ = build_x_unary_op (REALPART_EXPR, $2); }
+ | IMAGPART cast_expr %prec UNARY
+ { $$ = build_x_unary_op (IMAGPART_EXPR, $2); }
;
+ /* Note this rule is not suitable for use in new_placement
+ since it uses NULL_TREE as the argument to
+ finish_new_placement. This rule serves only to avoid
+ reduce/reduce conflicts in unary_expr. See the comments
+ there on the use of begin/finish_new_placement. */
+.finish_new_placement:
+ ')'
+ { finish_new_placement (NULL_TREE, $<itype>-1); }
+
+.begin_new_placement:
+ { $$ = begin_new_placement (); }
+
new_placement:
- '(' nonnull_exprlist ')'
- { $$ = $2; }
- | '{' nonnull_exprlist '}'
- {
- $$ = $2;
- pedwarn ("old style placement syntax, use () instead");
- }
+ '(' .begin_new_placement nonnull_exprlist ')'
+ { $$ = finish_new_placement ($3, $2); }
+ | '{' .begin_new_placement nonnull_exprlist '}'
+ { cp_pedwarn ("old style placement syntax, use () instead");
+ $$ = finish_new_placement ($3, $2); }
;
new_initializer:
@@ -1154,7 +1147,7 @@ new_initializer:
{ $$ = NULL_TREE; }
| '(' typespec ')'
{
- cp_error ("`%T' is not a valid expression", $2);
+ cp_error ("`%T' is not a valid expression", $2.t);
$$ = error_mark_node;
}
/* GNU extension so people can use initializer lists. Note that
@@ -1164,21 +1157,24 @@ new_initializer:
{
if (pedantic)
pedwarn ("ANSI C++ forbids initialization of new expression with `='");
- $$ = $2;
+ if (TREE_CODE ($2) != TREE_LIST
+ && TREE_CODE ($2) != CONSTRUCTOR)
+ $$ = build_expr_list (NULL_TREE, $2);
+ else
+ $$ = $2;
}
;
/* This is necessary to postpone reduction of `int ((int)(int)(int))'. */
regcast_or_absdcl:
- '(' type_id ')' %prec EMPTY
- { $2 = tree_cons (NULL_TREE, $2, void_list_node);
- TREE_PARMLIST ($2) = 1;
- $$ = build_parse_node (CALL_EXPR, NULL_TREE, $2,
- NULL_TREE); }
- | regcast_or_absdcl '(' type_id ')' %prec EMPTY
- { $3 = tree_cons (NULL_TREE, $3, void_list_node);
- TREE_PARMLIST ($3) = 1;
- $$ = build_parse_node (CALL_EXPR, $$, $3, NULL_TREE); }
+ '(' type_id ')' %prec EMPTY
+ { $2.t = finish_parmlist (build_tree_list (NULL_TREE, $2.t), 0);
+ $$ = make_call_declarator (NULL_TREE, $2.t, NULL_TREE, NULL_TREE);
+ check_for_new_type ("cast", $2); }
+ | regcast_or_absdcl '(' type_id ')' %prec EMPTY
+ { $3.t = finish_parmlist (build_tree_list (NULL_TREE, $3.t), 0);
+ $$ = make_call_declarator ($$, $3.t, NULL_TREE, NULL_TREE);
+ check_for_new_type ("cast", $3); }
;
cast_expr:
@@ -1242,15 +1238,11 @@ expr_no_commas:
| expr_no_commas '?' xexpr ':' expr_no_commas
{ $$ = build_x_conditional_expr ($$, $3, $5); }
| expr_no_commas '=' expr_no_commas
- { $$ = build_modify_expr ($$, NOP_EXPR, $3);
- C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); }
+ { $$ = build_x_modify_expr ($$, NOP_EXPR, $3);
+ if ($$ != error_mark_node)
+ C_SET_EXP_ORIGINAL_CODE ($$, MODIFY_EXPR); }
| expr_no_commas ASSIGN expr_no_commas
- { register tree rval;
- if ((rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, $$, $3,
- make_node ($2))))
- $$ = rval;
- else
- $$ = build_modify_expr ($$, $2, $3); }
+ { $$ = build_x_modify_expr ($$, $2, $3); }
| THROW
{ $$ = build_throw (NULL_TREE); }
| THROW expr_no_commas
@@ -1258,13 +1250,13 @@ expr_no_commas:
/* These extensions are not defined. The second arg to build_m_component_ref
is old, build_m_component_ref now does an implicit
build_indirect_ref (x, NULL_PTR) on the second argument.
- | object '&' expr_no_commas %prec UNARY
+ | object '&' expr_no_commas %prec UNARY
{ $$ = build_m_component_ref ($$, build_x_unary_op (ADDR_EXPR, $3)); }
| object unop expr_no_commas %prec UNARY
{ $$ = build_m_component_ref ($$, build_x_unary_op ($2, $3)); }
| object '(' type_id ')' expr_no_commas %prec UNARY
- { tree type = groktypename ($3);
- $$ = build_m_component_ref ($$, build_c_cast (type, $5, 0)); }
+ { tree type = groktypename ($3.t);
+ $$ = build_m_component_ref ($$, build_c_cast (type, $5)); }
| object primary_no_id %prec UNARY
{ $$ = build_m_component_ref ($$, $2); }
*/
@@ -1273,30 +1265,62 @@ expr_no_commas:
notype_unqualified_id:
'~' see_typename identifier
{ $$ = build_parse_node (BIT_NOT_EXPR, $3); }
+ | template_id
| operator_name
| IDENTIFIER
| PTYPENAME
- | NSNAME %prec EMPTY
+ | NSNAME %prec EMPTY
;
+do_id:
+ { $$ = do_identifier ($<ttype>-1, 1, NULL_TREE); }
+
+template_id:
+ PFUNCNAME '<' do_id template_arg_list_opt template_close_bracket
+ { $$ = lookup_template_function ($3, $4); }
+ | operator_name '<' do_id template_arg_list_opt template_close_bracket
+ { $$ = lookup_template_function ($3, $4); }
+ ;
+
+object_template_id:
+ TEMPLATE identifier '<' template_arg_list_opt template_close_bracket
+ { $$ = lookup_template_function ($2, $4); }
+ | TEMPLATE PFUNCNAME '<' template_arg_list_opt template_close_bracket
+ { $$ = lookup_template_function ($2, $4); }
+ | TEMPLATE operator_name '<' template_arg_list_opt
+ template_close_bracket
+ { $$ = lookup_template_function ($2, $4); }
+ ;
+
unqualified_id:
notype_unqualified_id
| TYPENAME
+ | SELFNAME
;
expr_or_declarator:
notype_unqualified_id
- | '*' expr_or_declarator %prec UNARY
+ | '*' expr_or_declarator %prec UNARY
{ $$ = build_parse_node (INDIRECT_REF, $2); }
- | '&' expr_or_declarator %prec UNARY
+ | '&' expr_or_declarator %prec UNARY
{ $$ = build_parse_node (ADDR_EXPR, $2); }
| '(' expr_or_declarator ')'
{ $$ = $2; }
;
+notype_template_declarator:
+ IDENTIFIER '<' template_arg_list_opt template_close_bracket
+ { $$ = lookup_template_function ($1, $3); }
+ | NSNAME '<' template_arg_list template_close_bracket
+ { $$ = lookup_template_function ($1, $3); }
+ ;
+
direct_notype_declarator:
complex_direct_notype_declarator
- | notype_unqualified_id
+ /* This precedence declaration is to prefer this reduce
+ to the Koenig lookup shift in primary, below. I hate yacc. */
+ | notype_unqualified_id %prec '('
+ | notype_template_declarator
| '(' expr_or_declarator ')'
{ $$ = finish_decl_parsing ($2); }
;
@@ -1304,43 +1328,26 @@ direct_notype_declarator:
primary:
notype_unqualified_id
{
- if (TREE_CODE ($$) == BIT_NOT_EXPR)
- $$ = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND ($$, 0));
- else if (IDENTIFIER_OPNAME_P ($$))
- {
- tree op = $$;
- $$ = lookup_name (op, 0);
- if ($$ == NULL_TREE)
- {
- if (op != ansi_opname[ERROR_MARK])
- error ("operator %s not defined",
- operator_name_string (op));
- $$ = error_mark_node;
- }
- }
- else
- $$ = do_identifier ($$);
+ if (TREE_CODE ($1) == BIT_NOT_EXPR)
+ $$ = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND ($1, 0));
+ else
+ $$ = finish_id_expr ($1);
}
| CONSTANT
| boolean.literal
| string
- { $$ = combine_strings ($$); }
+ {
+ if (processing_template_decl)
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ $$ = combine_strings ($$);
+ if (processing_template_decl)
+ pop_obstacks ();
+ }
| '(' expr ')'
- { char class;
- $$ = $2;
- class = TREE_CODE_CLASS (TREE_CODE ($$));
- if (class == 'e' || class == '1'
- || class == '2' || class == '<')
- /* This inhibits warnings in truthvalue_conversion. */
- C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); }
+ { $$ = finish_parenthesized_expr ($2); }
| '(' expr_or_declarator ')'
- { char class;
- $$ = reparse_decl_as_expr (NULL_TREE, $2);
- class = TREE_CODE_CLASS (TREE_CODE ($$));
- if (class == 'e' || class == '1'
- || class == '2' || class == '<')
- /* This inhibits warnings in truthvalue_conversion. */
- C_SET_EXP_ORIGINAL_CODE ($$, ERROR_MARK); }
+ { $2 = reparse_decl_as_expr (NULL_TREE, $2);
+ $$ = finish_parenthesized_expr ($2); }
| '(' error ')'
{ $$ = error_mark_node; }
| '('
@@ -1349,90 +1356,35 @@ primary:
error ("braced-group within expression allowed only inside a function");
YYERROR;
}
- keep_next_level ();
- $<ttype>$ = expand_start_stmt_expr (); }
- compstmt ')'
- { tree rtl_exp;
if (pedantic)
- pedwarn ("ANSI C++ forbids braced-groups within expressions");
- rtl_exp = expand_end_stmt_expr ($<ttype>2);
- /* The statements have side effects, so the group does. */
- TREE_SIDE_EFFECTS (rtl_exp) = 1;
-
- if (TREE_CODE ($3) == BLOCK)
- {
- /* Make a BIND_EXPR for the BLOCK already made. */
- $$ = build (BIND_EXPR, TREE_TYPE (rtl_exp),
- NULL_TREE, rtl_exp, $3);
- /* Remove the block from the tree at this point.
- It gets put back at the proper place
- when the BIND_EXPR is expanded. */
- delete_block ($3);
- }
- else
- $$ = $3;
+ pedwarn ("ANSI C++ forbids braced-groups within expressions");
+ $<ttype>$ = begin_stmt_expr ();
}
+ compstmt ')'
+ { $$ = finish_stmt_expr ($<ttype>2, $3); }
+ /* Koenig lookup support
+ We could store lastiddecl in $1 to avoid another lookup,
+ but that would result in many additional reduce/reduce conflicts. */
+ | notype_unqualified_id '(' nonnull_exprlist ')'
+ { $$ = finish_call_expr ($1, $3, 1); }
+ | notype_unqualified_id LEFT_RIGHT
+ { $$ = finish_call_expr ($1, NULL_TREE, 1); }
| primary '(' nonnull_exprlist ')'
- { /* [eichin:19911016.1902EST] */
- $<ttype>$ = build_x_function_call ($1, $3, current_class_decl);
- /* here we instantiate_class_template as needed... */
- do_pending_templates ();
- } template_instantiate_some {
- if (TREE_CODE ($<ttype>5) == CALL_EXPR
- && TREE_TYPE ($<ttype>5) != void_type_node)
- $$ = require_complete_type ($<ttype>5);
- else
- $$ = $<ttype>5;
- }
+ { $$ = finish_call_expr ($1, $3, 0); }
| primary LEFT_RIGHT
- {
- $$ = build_x_function_call ($$, NULL_TREE, current_class_decl);
- if (TREE_CODE ($$) == CALL_EXPR
- && TREE_TYPE ($$) != void_type_node)
- $$ = require_complete_type ($$);
- }
+ { $$ = finish_call_expr ($1, NULL_TREE, 0); }
| primary '[' expr ']'
{ $$ = grok_array_decl ($$, $3); }
| primary PLUSPLUS
- { /* If we get an OFFSET_REF, turn it into what it really
- means (e.g., a COMPONENT_REF). This way if we've got,
- say, a reference to a static member that's being operated
- on, we don't end up trying to find a member operator for
- the class it's in. */
- if (TREE_CODE ($$) == OFFSET_REF)
- $$ = resolve_offset_ref ($$);
- $$ = build_x_unary_op (POSTINCREMENT_EXPR, $$); }
+ { $$ = finish_increment_expr ($1, POSTINCREMENT_EXPR); }
| primary MINUSMINUS
- { if (TREE_CODE ($$) == OFFSET_REF)
- $$ = resolve_offset_ref ($$);
- $$ = build_x_unary_op (POSTDECREMENT_EXPR, $$); }
+ { $$ = finish_increment_expr ($1, POSTDECREMENT_EXPR); }
/* C++ extensions */
| THIS
- { if (current_class_decl)
- {
-#ifdef WARNING_ABOUT_CCD
- TREE_USED (current_class_decl) = 1;
-#endif
- $$ = current_class_decl;
- }
- else if (current_function_decl
- && DECL_STATIC_FUNCTION_P (current_function_decl))
- {
- error ("`this' is unavailable for static member functions");
- $$ = error_mark_node;
- }
- else
- {
- if (current_function_decl)
- error ("invalid use of `this' in non-member function");
- else
- error ("invalid use of `this' at top level");
- $$ = error_mark_node;
- }
- }
- | TYPE_QUAL '(' nonnull_exprlist ')'
+ { $$ = finish_this_expr (); }
+ | CV_QUALIFIER '(' nonnull_exprlist ')'
{
- tree type;
+ tree type = NULL_TREE;
tree id = $$;
/* This is a C cast in C++'s `functional' notation. */
@@ -1471,180 +1423,80 @@ primary:
}
#endif
else my_friendly_abort (79);
- $$ = build_c_cast (type, build_compound_expr ($3), 1);
+ $$ = build_c_cast (type, build_compound_expr ($3));
}
}
| functional_cast
- | DYNAMIC_CAST '<'
- { dont_allow_type_definitions = "inside dynamic_cast"; }
- type_id '>'
- { dont_allow_type_definitions = 0; }
- '(' expr ')'
- { tree type = groktypename ($4);
- $$ = build_dynamic_cast (type, $8); }
- | STATIC_CAST '<'
- { dont_allow_type_definitions = "inside static_cast"; }
- type_id '>'
- { dont_allow_type_definitions = 0; }
- '(' expr ')'
- { tree type = groktypename ($4);
- $$ = build_static_cast (type, $8); }
- | REINTERPRET_CAST '<'
- { dont_allow_type_definitions = "inside reinterpret_cast"; }
- type_id '>'
- { dont_allow_type_definitions = 0; }
- '(' expr ')'
- { tree type = groktypename ($4);
- $$ = build_reinterpret_cast (type, $8); }
- | CONST_CAST '<'
- { dont_allow_type_definitions = "inside const_cast"; }
- type_id '>'
- { dont_allow_type_definitions = 0; }
- '(' expr ')'
- { tree type = groktypename ($4);
- $$ = build_const_cast (type, $8); }
+ | DYNAMIC_CAST '<' type_id '>' '(' expr ')'
+ { tree type = groktypename ($3.t);
+ check_for_new_type ("dynamic_cast", $3);
+ $$ = build_dynamic_cast (type, $6); }
+ | STATIC_CAST '<' type_id '>' '(' expr ')'
+ { tree type = groktypename ($3.t);
+ check_for_new_type ("static_cast", $3);
+ $$ = build_static_cast (type, $6); }
+ | REINTERPRET_CAST '<' type_id '>' '(' expr ')'
+ { tree type = groktypename ($3.t);
+ check_for_new_type ("reinterpret_cast", $3);
+ $$ = build_reinterpret_cast (type, $6); }
+ | CONST_CAST '<' type_id '>' '(' expr ')'
+ { tree type = groktypename ($3.t);
+ check_for_new_type ("const_cast", $3);
+ $$ = build_const_cast (type, $6); }
| TYPEID '(' expr ')'
- { $$ = build_typeid ($3); }
+ { $$ = build_x_typeid ($3); }
| TYPEID '(' type_id ')'
- { tree type = groktypename ($3);
+ { tree type = groktypename ($3.t);
+ check_for_new_type ("typeid", $3);
$$ = get_typeid (TYPE_MAIN_VARIANT (type)); }
| global_scope IDENTIFIER
- {
- do_scoped_id:
- $$ = IDENTIFIER_GLOBAL_VALUE ($2);
- if (yychar == YYEMPTY)
- yychar = YYLEX;
- if (! $$)
- {
- if (yychar == '(' || yychar == LEFT_RIGHT)
- $$ = implicitly_declare ($2);
- else
- {
- if (IDENTIFIER_GLOBAL_VALUE ($2) != error_mark_node)
- error ("undeclared variable `%s' (first use here)",
- IDENTIFIER_POINTER ($2));
- $$ = error_mark_node;
- /* Prevent repeated error messages. */
- IDENTIFIER_GLOBAL_VALUE ($2) = error_mark_node;
- }
- }
- else
- {
- if (TREE_CODE ($$) == ADDR_EXPR)
- assemble_external (TREE_OPERAND ($$, 0));
- else
- assemble_external ($$);
- TREE_USED ($$) = 1;
- }
- if (TREE_CODE ($$) == CONST_DECL)
- {
- /* XXX CHS - should we set TREE_USED of the constant? */
- $$ = DECL_INITIAL ($$);
- /* This is to prevent an enum whose value is 0
- from being considered a null pointer constant. */
- $$ = build1 (NOP_EXPR, TREE_TYPE ($$), $$);
- TREE_CONSTANT ($$) = 1;
- }
-
- }
+ { $$ = do_scoped_id ($2, 1); }
+ | global_scope template_id
+ { $$ = $2; }
| global_scope operator_name
{
got_scope = NULL_TREE;
if (TREE_CODE ($2) == IDENTIFIER_NODE)
- goto do_scoped_id;
- $$ = $2;
+ $$ = do_scoped_id ($2, 1);
+ else
+ $$ = $2;
}
- | overqualified_id %prec HYPERUNARY
+ | overqualified_id %prec HYPERUNARY
{ $$ = build_offset_ref (OP0 ($$), OP1 ($$)); }
| overqualified_id '(' nonnull_exprlist ')'
- { $$ = build_member_call (OP0 ($$), OP1 ($$), $3); }
+ { $$ = finish_globally_qualified_member_call_expr ($1, $3); }
| overqualified_id LEFT_RIGHT
- { $$ = build_member_call (OP0 ($$), OP1 ($$), NULL_TREE); }
+ { $$ = finish_globally_qualified_member_call_expr ($1, NULL_TREE); }
+ | object object_template_id %prec UNARY
+ {
+ $$ = build_x_component_ref ($$, $2, NULL_TREE, 1);
+ }
+ | object object_template_id '(' nonnull_exprlist ')'
+ { $$ = finish_object_call_expr ($2, $1, $4); }
+ | object object_template_id LEFT_RIGHT
+ { $$ = finish_object_call_expr ($2, $1, NULL_TREE); }
| object unqualified_id %prec UNARY
- { got_object = NULL_TREE;
- $$ = build_component_ref ($$, $2, NULL_TREE, 1); }
- | object overqualified_id %prec UNARY
- { got_object = NULL_TREE;
- $$ = build_object_ref ($$, OP0 ($2), OP1 ($2)); }
+ { $$ = build_x_component_ref ($$, $2, NULL_TREE, 1); }
+ | object overqualified_id %prec UNARY
+ { if (processing_template_decl)
+ $$ = build_min_nt (COMPONENT_REF, $1, copy_to_permanent ($2));
+ else
+ $$ = build_object_ref ($$, OP0 ($2), OP1 ($2)); }
| object unqualified_id '(' nonnull_exprlist ')'
- {
- got_object = NULL_TREE;
-#if 0
- /* This is a future direction of this code, but because
- build_x_function_call cannot always undo what is done
- in build_component_ref entirely yet, we cannot do this. */
- $$ = build_x_function_call (build_component_ref ($$, $2, NULL_TREE, 1), $4, $$);
- if (TREE_CODE ($$) == CALL_EXPR
- && TREE_TYPE ($$) != void_type_node)
- $$ = require_complete_type ($$);
-#else
- $$ = build_method_call ($$, $2, $4, NULL_TREE,
- (LOOKUP_NORMAL|LOOKUP_AGGR));
-#endif
- }
+ { $$ = finish_object_call_expr ($2, $1, $4); }
| object unqualified_id LEFT_RIGHT
- {
- got_object = NULL_TREE;
-#if 0
- /* This is a future direction of this code, but because
- build_x_function_call cannot always undo what is done
- in build_component_ref entirely yet, we cannot do this. */
- $$ = build_x_function_call (build_component_ref ($$, $2, NULL_TREE, 1), NULL_TREE, $$);
- if (TREE_CODE ($$) == CALL_EXPR
- && TREE_TYPE ($$) != void_type_node)
- $$ = require_complete_type ($$);
-#else
- $$ = build_method_call ($$, $2, NULL_TREE, NULL_TREE,
- (LOOKUP_NORMAL|LOOKUP_AGGR));
-#endif
- }
+ { $$ = finish_object_call_expr ($2, $1, NULL_TREE); }
| object overqualified_id '(' nonnull_exprlist ')'
- {
- got_object = NULL_TREE;
- if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (OP0 ($2))))
- {
- warning ("signature name in scope resolution ignored");
- $$ = build_method_call ($$, OP1 ($2), $4, NULL_TREE,
- (LOOKUP_NORMAL|LOOKUP_AGGR));
- }
- else
- $$ = build_scoped_method_call ($$, OP0 ($2), OP1 ($2), $4);
- }
+ { $$ = finish_qualified_object_call_expr ($2, $1, $4); }
| object overqualified_id LEFT_RIGHT
- {
- got_object = NULL_TREE;
- if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (OP0 ($2))))
- {
- warning ("signature name in scope resolution ignored");
- $$ = build_method_call ($$, OP1 ($2), NULL_TREE, NULL_TREE,
- (LOOKUP_NORMAL|LOOKUP_AGGR));
- }
- else
- $$ = build_scoped_method_call ($$, OP0 ($2), OP1 ($2), NULL_TREE);
- }
+ { $$ = finish_qualified_object_call_expr ($2, $1, NULL_TREE); }
/* p->int::~int() is valid -- 12.4 */
| object '~' TYPESPEC LEFT_RIGHT
- {
- got_object = NULL_TREE;
- if (IDENTIFIER_GLOBAL_VALUE ($3)
- && (TREE_CODE (TREE_TYPE ($1))
- != TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE ($3)))))
- cp_error ("`%E' is not of type `%T'", $1, $3);
- $$ = convert (void_type_node, $1);
- }
+ { $$ = finish_pseudo_destructor_call_expr ($1, NULL_TREE, $3); }
| object TYPESPEC SCOPE '~' TYPESPEC LEFT_RIGHT
- {
- got_object = NULL_TREE;
- if ($2 != $5)
- cp_error ("destructor specifier `%T::~%T()' must have matching names", $2, $5);
- if (TREE_CODE (TREE_TYPE ($1))
- != TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE ($2))))
- cp_error ("`%E' is not of type `%T'", $1, $2);
- $$ = convert (void_type_node, $1);
- }
+ { $$ = finish_pseudo_destructor_call_expr ($1, $2, $5); }
| object error
{
- got_object = NULL_TREE;
$$ = error_mark_node;
}
;
@@ -1668,9 +1520,9 @@ primary_no_id:
pedwarn ("ANSI C++ forbids braced-groups within expressions");
$$ = expand_end_stmt_expr ($<ttype>2); }
| primary_no_id '(' nonnull_exprlist ')'
- { $$ = build_x_function_call ($$, $3, current_class_decl); }
+ { $$ = build_x_function_call ($$, $3, current_class_ref); }
| primary_no_id LEFT_RIGHT
- { $$ = build_x_function_call ($$, NULL_TREE, current_class_decl); }
+ { $$ = build_x_function_call ($$, NULL_TREE, current_class_ref); }
| primary_no_id '[' expr ']'
{ goto do_array; }
| primary_no_id PLUSPLUS
@@ -1687,13 +1539,15 @@ primary_no_id:
;
*/
-new: NEW
+new:
+ NEW
{ $$ = 0; }
| global_scope NEW
{ got_scope = NULL_TREE; $$ = 1; }
;
-delete: DELETE
+delete:
+ DELETE
{ $$ = 0; }
| global_scope delete
{ got_scope = NULL_TREE; $$ = 1; }
@@ -1726,7 +1580,8 @@ nodecls:
}
;
-object: primary '.'
+object:
+ primary '.'
{ got_object = TREE_TYPE ($$); }
| primary POINTSAT
{
@@ -1736,79 +1591,65 @@ object: primary '.'
;
decl:
- /* Normal case: make this fast. */
- typespec declarator ';'
- { tree d = get_decl_list ($1);
- int yes = suspend_momentary ();
- d = start_decl ($2, d, 0, NULL_TREE);
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
- resume_momentary (yes);
- if (IS_AGGR_TYPE_CODE (TREE_CODE ($1)))
- note_got_semicolon ($1);
- }
- | typed_declspecs declarator ';'
- { tree d, specs, attrs;
- int yes;
- split_specs_attrs ($1, &specs, &attrs);
- yes = suspend_momentary ();
- d = start_decl ($2, specs, 0, NULL_TREE);
- cplus_decl_attributes (d, NULL_TREE, attrs);
- cp_finish_decl (d, NULL_TREE, NULL_TREE, 0, 0);
- resume_momentary (yes);
- note_list_got_semicolon ($1);
- }
- | typespec initdecls ';'
+ typespec initdecls ';'
{
resume_momentary ($2);
- if (IS_AGGR_TYPE_CODE (TREE_CODE ($1)))
- note_got_semicolon ($1);
+ if ($1.t && IS_AGGR_TYPE_CODE (TREE_CODE ($1.t)))
+ note_got_semicolon ($1.t);
}
| typed_declspecs initdecls ';'
{
resume_momentary ($2);
- note_list_got_semicolon ($1);
+ note_list_got_semicolon ($1.t);
}
| declmods notype_initdecls ';'
{ resume_momentary ($2); }
| typed_declspecs ';'
{
- shadow_tag ($1);
- note_list_got_semicolon ($1);
+ shadow_tag ($1.t);
+ note_list_got_semicolon ($1.t);
}
| declmods ';'
{ warning ("empty declaration"); }
+ | extension decl
+ { pedantic = $<itype>1; }
;
/* Any kind of declarator (thus, all declarators allowed
after an explicit typespec). */
declarator:
- after_type_declarator %prec EMPTY
- | notype_declarator %prec EMPTY
+ after_type_declarator %prec EMPTY
+ | notype_declarator %prec EMPTY
;
/* This is necessary to postpone reduction of `int()()()()'. */
fcast_or_absdcl:
- LEFT_RIGHT %prec EMPTY
- { $$ = build_parse_node (CALL_EXPR, NULL_TREE, empty_parms (),
- NULL_TREE); }
- | fcast_or_absdcl LEFT_RIGHT %prec EMPTY
- { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (),
- NULL_TREE); }
+ LEFT_RIGHT %prec EMPTY
+ { $$ = make_call_declarator (NULL_TREE, empty_parms (),
+ NULL_TREE, NULL_TREE); }
+ | fcast_or_absdcl LEFT_RIGHT %prec EMPTY
+ { $$ = make_call_declarator ($$, empty_parms (), NULL_TREE,
+ NULL_TREE); }
;
/* ANSI type-id (8.1) */
type_id:
typed_typespecs absdcl
- { $$ = build_decl_list ($$, $2); }
- | nonempty_type_quals absdcl
- { $$ = build_decl_list ($$, $2); }
+ { $$.t = build_decl_list ($1.t, $2);
+ $$.new_type_flag = $1.new_type_flag; }
+ | nonempty_cv_qualifiers absdcl
+ { $$.t = build_decl_list ($1.t, $2);
+ $$.new_type_flag = $1.new_type_flag; }
| typespec absdcl
- { $$ = build_decl_list (get_decl_list ($$), $2); }
- | typed_typespecs %prec EMPTY
- { $$ = build_decl_list ($$, NULL_TREE); }
- | nonempty_type_quals %prec EMPTY
- { $$ = build_decl_list ($$, NULL_TREE); }
+ { $$.t = build_decl_list (get_decl_list ($1.t), $2);
+ $$.new_type_flag = $1.new_type_flag; }
+ | typed_typespecs %prec EMPTY
+ { $$.t = build_decl_list ($1.t, NULL_TREE);
+ $$.new_type_flag = $1.new_type_flag; }
+ | nonempty_cv_qualifiers %prec EMPTY
+ { $$.t = build_decl_list ($1.t, NULL_TREE);
+ $$.new_type_flag = $1.new_type_flag; }
;
/* Declspecs which contain at least one type specifier or typedef name.
@@ -1817,24 +1658,30 @@ type_id:
In the result, declspecs have a non-NULL TREE_VALUE, attributes do not. */
typed_declspecs:
- typed_typespecs %prec EMPTY
+ typed_typespecs %prec EMPTY
| typed_declspecs1
;
typed_declspecs1:
declmods typespec
- { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
- | typespec reserved_declspecs %prec HYPERUNARY
- { $$ = decl_tree_cons (NULL_TREE, $$, $2); }
+ { $$.t = decl_tree_cons (NULL_TREE, $2.t, $1);
+ $$.new_type_flag = $2.new_type_flag; }
+ | typespec reserved_declspecs %prec HYPERUNARY
+ { $$.t = decl_tree_cons (NULL_TREE, $1.t, $2);
+ $$.new_type_flag = $1.new_type_flag; }
| typespec reserved_typespecquals reserved_declspecs
- { $$ = decl_tree_cons (NULL_TREE, $$, chainon ($2, $3)); }
+ { $$.t = decl_tree_cons (NULL_TREE, $1.t, chainon ($2, $3));
+ $$.new_type_flag = $1.new_type_flag; }
| declmods typespec reserved_declspecs
- { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1));
+ $$.new_type_flag = $2.new_type_flag; }
| declmods typespec reserved_typespecquals
- { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1));
+ $$.new_type_flag = $2.new_type_flag; }
| declmods typespec reserved_typespecquals reserved_declspecs
- { $$ = decl_tree_cons (NULL_TREE, $2,
- chainon ($3, chainon ($4, $$))); }
+ { $$.t = decl_tree_cons (NULL_TREE, $2.t,
+ chainon ($3, chainon ($4, $1)));
+ $$.new_type_flag = $2.new_type_flag; }
;
reserved_declspecs:
@@ -1844,7 +1691,7 @@ reserved_declspecs:
IDENTIFIER_POINTER ($$));
$$ = build_decl_list (NULL_TREE, $$); }
| reserved_declspecs typespecqual_reserved
- { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ { $$ = decl_tree_cons (NULL_TREE, $2.t, $$); }
| reserved_declspecs SCSPEC
{ if (extra_warnings)
warning ("`%s' is not at beginning of declaration",
@@ -1862,11 +1709,11 @@ reserved_declspecs:
In the result, declspecs have a non-NULL TREE_VALUE, attributes do not. */
declmods:
- nonempty_type_quals %prec EMPTY
- { TREE_STATIC ($$) = 1; }
+ nonempty_cv_qualifiers %prec EMPTY
+ { $$ = $1.t; TREE_STATIC ($$) = 1; }
| SCSPEC
{ $$ = IDENTIFIER_AS_LIST ($$); }
- | declmods TYPE_QUAL
+ | declmods CV_QUALIFIER
{ $$ = decl_tree_cons (NULL_TREE, $2, $$);
TREE_STATIC ($$) = 1; }
| declmods SCSPEC
@@ -1889,71 +1736,81 @@ declmods:
typed_typespecs:
typespec %prec EMPTY
- { $$ = get_decl_list ($$); }
- | nonempty_type_quals typespec
- { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ { $$.t = get_decl_list ($1.t);
+ $$.new_type_flag = $1.new_type_flag; }
+ | nonempty_cv_qualifiers typespec
+ { $$.t = decl_tree_cons (NULL_TREE, $2.t, $1.t);
+ $$.new_type_flag = $2.new_type_flag; }
| typespec reserved_typespecquals
- { $$ = decl_tree_cons (NULL_TREE, $$, $2); }
- | nonempty_type_quals typespec reserved_typespecquals
- { $$ = decl_tree_cons (NULL_TREE, $2, chainon ($3, $$)); }
+ { $$.t = decl_tree_cons (NULL_TREE, $1.t, $2);
+ $$.new_type_flag = $1.new_type_flag; }
+ | nonempty_cv_qualifiers typespec reserved_typespecquals
+ { $$.t = decl_tree_cons (NULL_TREE, $2.t, chainon ($3, $1.t));
+ $$.new_type_flag = $1.new_type_flag; }
;
reserved_typespecquals:
typespecqual_reserved
- { $$ = build_decl_list (NULL_TREE, $$); }
+ { $$ = build_decl_list (NULL_TREE, $1.t); }
| reserved_typespecquals typespecqual_reserved
- { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+ { $$ = decl_tree_cons (NULL_TREE, $2.t, $1); }
;
/* A typespec (but not a type qualifier).
Once we have seen one of these in a declaration,
if a typedef name appears then it is being redeclared. */
-typespec: structsp
+typespec:
+ structsp
| TYPESPEC %prec EMPTY
+ { $$.t = $1; $$.new_type_flag = 0; }
| complete_type_name
+ { $$.t = $1; $$.new_type_flag = 0; }
| TYPEOF '(' expr ')'
- { $$ = TREE_TYPE ($3);
- if (pedantic && !in_system_header)
- pedwarn ("ANSI C++ forbids `typeof'"); }
+ { $$.t = TREE_TYPE ($3);
+ $$.new_type_flag = 0; }
| TYPEOF '(' type_id ')'
- { $$ = groktypename ($3);
- if (pedantic && !in_system_header)
- pedwarn ("ANSI C++ forbids `typeof'"); }
+ { $$.t = groktypename ($3.t);
+ $$.new_type_flag = 0; }
| SIGOF '(' expr ')'
{ tree type = TREE_TYPE ($3);
+ $$.new_type_flag = 0;
if (IS_AGGR_TYPE (type))
{
sorry ("sigof type specifier");
- $$ = type;
+ $$.t = type;
}
else
{
error ("`sigof' applied to non-aggregate expression");
- $$ = error_mark_node;
+ $$.t = error_mark_node;
}
}
| SIGOF '(' type_id ')'
- { tree type = groktypename ($3);
+ { tree type = groktypename ($3.t);
+ $$.new_type_flag = 0;
if (IS_AGGR_TYPE (type))
{
sorry ("sigof type specifier");
- $$ = type;
+ $$.t = type;
}
else
{
error("`sigof' applied to non-aggregate type");
- $$ = error_mark_node;
+ $$.t = error_mark_node;
}
}
;
/* A typespec that is a reserved word, or a type qualifier. */
-typespecqual_reserved: TYPESPEC
- | TYPE_QUAL
+typespecqual_reserved:
+ TYPESPEC
+ { $$.t = $1; $$.new_type_flag = 0; }
+ | CV_QUALIFIER
+ { $$.t = $1; $$.new_type_flag = 0; }
| structsp
;
@@ -1979,104 +1836,67 @@ maybeasm:
{ if (TREE_CHAIN ($3)) $3 = combine_strings ($3); $$ = $3; }
;
-initdcl0:
- declarator exception_specification_opt maybeasm maybe_attribute '='
- { split_specs_attrs ($<ttype>0, &current_declspecs,
- &prefix_attributes);
- if (TREE_CODE (current_declspecs) != TREE_LIST)
- current_declspecs = get_decl_list (current_declspecs);
- if (have_extern_spec && !used_extern_spec)
- {
- current_declspecs = decl_tree_cons
- (NULL_TREE, get_identifier ("extern"),
- current_declspecs);
- used_extern_spec = 1;
- }
- $<itype>5 = suspend_momentary ();
- $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2);
- cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); }
- init
-/* Note how the declaration of the variable is in effect while its init is parsed! */
- { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING);
- $$ = $<itype>5; }
- | declarator exception_specification_opt maybeasm maybe_attribute
- { tree d;
- split_specs_attrs ($<ttype>0, &current_declspecs,
- &prefix_attributes);
- if (TREE_CODE (current_declspecs) != TREE_LIST)
- current_declspecs = get_decl_list (current_declspecs);
- if (have_extern_spec && !used_extern_spec)
- {
- current_declspecs = decl_tree_cons
- (NULL_TREE, get_identifier ("extern"),
- current_declspecs);
- used_extern_spec = 1;
- }
- $$ = suspend_momentary ();
- d = start_decl ($<ttype>1, current_declspecs, 0, $2);
- cplus_decl_attributes (d, $4, prefix_attributes);
- cp_finish_decl (d, NULL_TREE, $3, 0, 0); }
- ;
-
initdcl:
- declarator exception_specification_opt maybeasm maybe_attribute '='
- { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2);
- cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); }
+ declarator maybeasm maybe_attribute '='
+ { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1,
+ $3, prefix_attributes); }
init
/* Note how the declaration of the variable is in effect while its init is parsed! */
- { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING); }
- | declarator exception_specification_opt maybeasm maybe_attribute
- { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 0, $2);
- cplus_decl_attributes ($<ttype>$, $4, prefix_attributes);
- cp_finish_decl ($<ttype>$, NULL_TREE, $3, 0, 0); }
- ;
-
-notype_initdcl0:
- notype_declarator exception_specification_opt maybeasm maybe_attribute '='
- { split_specs_attrs ($<ttype>0, &current_declspecs,
- &prefix_attributes);
- $<itype>5 = suspend_momentary ();
- $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 1, $2);
- cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); }
+ { cp_finish_decl ($<ttype>5, $6, $2, 1, LOOKUP_ONLYCONVERTING); }
+ | declarator maybeasm maybe_attribute
+ { $<ttype>$ = start_decl ($<ttype>1, current_declspecs, 0,
+ $3, prefix_attributes);
+ cp_finish_decl ($<ttype>$, NULL_TREE, $2, 1, 0); }
+ ;
+
+ /* This rule assumes a certain configuration of the parser stack.
+ In particular, $0, the element directly before the beginning of
+ this rule on the stack, must be a maybeasm. $-1 must be a
+ declarator or notype_declarator. And $-2 must be some declmods
+ or declspecs. We can't move the maybeasm into this rule because
+ we need that reduce so we prefer fn.def1 when appropriate. */
+initdcl0_innards:
+ maybe_attribute '='
+ { $<itype>2 = parse_decl ($<ttype>-1, $<ttype>-2,
+ $1, 1, &$<ttype>$); }
+ /* Note how the declaration of the variable is in effect
+ while its init is parsed! */
init
-/* Note how the declaration of the variable is in effect while its init is parsed! */
- { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING);
- $$ = $<itype>5; }
- | notype_declarator exception_specification_opt maybeasm maybe_attribute
+ { cp_finish_decl ($<ttype>3, $4, $<ttype>0, 1,
+ LOOKUP_ONLYCONVERTING);
+ $$ = $<itype>2; }
+ | maybe_attribute
{ tree d;
- split_specs_attrs ($<ttype>0, &current_declspecs,
- &prefix_attributes);
- $$ = suspend_momentary ();
- d = start_decl ($<ttype>1, current_declspecs, 0, $2);
- cplus_decl_attributes (d, $4, prefix_attributes);
- cp_finish_decl (d, NULL_TREE, $3, 0, 0); }
- ;
-
+ $$ = parse_decl ($<ttype>-1, $<ttype>-2, $1, 0, &d);
+ cp_finish_decl (d, NULL_TREE, $<ttype>0, 1, 0); }
+ ;
+
+initdcl0:
+ declarator maybeasm initdcl0_innards
+ { $$ = $3; }
+
+notype_initdcl0:
+ notype_declarator maybeasm initdcl0_innards
+ { $$ = $3; }
+ ;
+
nomods_initdcl0:
- notype_declarator exception_specification_opt maybeasm maybe_attribute '='
- { current_declspecs = NULL_TREE;
- prefix_attributes = NULL_TREE;
- $<itype>5 = suspend_momentary ();
- $<ttype>$ = start_decl ($1, current_declspecs, 1, $2);
- cplus_decl_attributes ($<ttype>$, $4, prefix_attributes); }
- init
-/* Note how the declaration of the variable is in effect while its init is parsed! */
- { cp_finish_decl ($<ttype>6, $7, $3, 0, LOOKUP_ONLYCONVERTING);
- $$ = $<itype>5; }
- | notype_declarator exception_specification_opt maybeasm maybe_attribute
+ notype_declarator maybeasm
+ { /* Set things up as initdcl0_innards expects. */
+ $<ttype>2 = $1;
+ $1 = NULL_TREE; }
+ initdcl0_innards
+ {}
+ | constructor_declarator maybeasm maybe_attribute
{ tree d;
- current_declspecs = NULL_TREE;
- prefix_attributes = NULL_TREE;
- $$ = suspend_momentary ();
- d = start_decl ($1, current_declspecs, 0, $2);
- cplus_decl_attributes (d, $4, prefix_attributes);
- cp_finish_decl (d, NULL_TREE, $3, 0, 0); }
+ parse_decl($1, NULL_TREE, $3, 0, &d);
+ cp_finish_decl (d, NULL_TREE, $2, 1, 0); }
;
/* the * rules are dummies to accept the Apollo extended syntax
- so that the header files compile. */
+ so that the header files compile. */
maybe_attribute:
- /* empty */
+ /* empty */
{ $$ = NULL_TREE; }
| attributes
{ $$ = $1; }
@@ -2102,7 +1922,7 @@ attribute_list:
;
attrib:
- /* empty */
+ /* empty */
{ $$ = NULL_TREE; }
| any_word
{ $$ = build_tree_list ($1, NULL_TREE); }
@@ -2121,25 +1941,28 @@ any_word:
identifier
| SCSPEC
| TYPESPEC
- | TYPE_QUAL
+ | CV_QUALIFIER
;
/* A nonempty list of identifiers, including typenames. */
identifiers_or_typenames:
- identifier
+ identifier
{ $$ = build_tree_list (NULL_TREE, $1); }
| identifiers_or_typenames ',' identifier
{ $$ = chainon ($1, build_tree_list (NULL_TREE, $3)); }
;
maybe_init:
- %prec EMPTY /* empty */
+ /* empty */ %prec EMPTY
{ $$ = NULL_TREE; }
| '=' init
{ $$ = $2; }
+/* If we are processing a template, we don't want to expand this
+ initializer yet. */
+
init:
- expr_no_commas %prec '='
+ expr_no_commas %prec '='
| '{' '}'
{ $$ = build_nt (CONSTRUCTOR, NULL_TREE, NULL_TREE);
TREE_HAS_CONSTRUCTOR ($$) = 1; }
@@ -2159,101 +1982,126 @@ initlist:
init
{ $$ = build_tree_list (NULL_TREE, $$); }
| initlist ',' init
- { $$ = tree_cons (NULL_TREE, $3, $$); }
+ { $$ = expr_tree_cons (NULL_TREE, $3, $$); }
/* These are for labeled elements. */
| '[' expr_no_commas ']' init
- { $$ = build_tree_list ($2, $4); }
- | initlist ',' CASE expr_no_commas ':' init
- { $$ = tree_cons ($4, $6, $$); }
+ { $$ = build_expr_list ($2, $4); }
| identifier ':' init
- { $$ = build_tree_list ($$, $3); }
+ { $$ = build_expr_list ($$, $3); }
| initlist ',' identifier ':' init
- { $$ = tree_cons ($3, $5, $$); }
+ { $$ = expr_tree_cons ($3, $5, $$); }
+ ;
+
+fn.defpen:
+ PRE_PARSED_FUNCTION_DECL
+ { start_function (NULL_TREE, TREE_VALUE ($1),
+ NULL_TREE, 1);
+ reinit_parse_for_function (); }
+
+pending_inline:
+ fn.defpen maybe_return_init ctor_initializer_opt compstmt_or_error
+ {
+ int nested = (hack_decl_function_context
+ (current_function_decl) != NULL_TREE);
+ finish_function (lineno, (int)$3, nested);
+ process_next_inline ($1);
+ }
+ | fn.defpen maybe_return_init function_try_block
+ { process_next_inline ($1); }
+ | fn.defpen maybe_return_init error
+ { process_next_inline ($1); }
+ ;
+
+pending_inlines:
+ /* empty */
+ | pending_inlines pending_inline eat_saved_input
+ ;
+
+/* A regurgitated default argument. The value of DEFARG_MARKER will be
+ the TREE_LIST node for the parameter in question. */
+defarg_again:
+ DEFARG_MARKER expr_no_commas END_OF_SAVED_INPUT
+ { replace_defarg ($1, $2); }
+ | DEFARG_MARKER error END_OF_SAVED_INPUT
+ { replace_defarg ($1, error_mark_node); }
+
+pending_defargs:
+ /* empty */ %prec EMPTY
+ | pending_defargs defarg_again
+ { do_pending_defargs (); }
+ | pending_defargs error
+ { do_pending_defargs (); }
;
structsp:
ENUM identifier '{'
{ $<itype>3 = suspend_momentary ();
- $$ = start_enum ($2); }
+ $<ttype>$ = start_enum ($2); }
enumlist maybecomma_warn '}'
- { $$ = finish_enum ($<ttype>4, $5);
+ { $$.t = finish_enum ($<ttype>4, $5);
+ $$.new_type_flag = 1;
resume_momentary ((int) $<itype>3);
check_for_missing_semicolon ($<ttype>4); }
| ENUM identifier '{' '}'
- { $$ = finish_enum (start_enum ($2), NULL_TREE);
- check_for_missing_semicolon ($$); }
+ { $$.t = finish_enum (start_enum ($2), NULL_TREE);
+ $$.new_type_flag = 1;
+ check_for_missing_semicolon ($$.t); }
| ENUM '{'
{ $<itype>2 = suspend_momentary ();
- $$ = start_enum (make_anon_name ()); }
+ $<ttype>$ = start_enum (make_anon_name ()); }
enumlist maybecomma_warn '}'
- { $$ = finish_enum ($<ttype>3, $4);
+ { $$.t = finish_enum ($<ttype>3, $4);
resume_momentary ((int) $<itype>1);
- check_for_missing_semicolon ($<ttype>3); }
+ check_for_missing_semicolon ($<ttype>3);
+ $$.new_type_flag = 1; }
| ENUM '{' '}'
- { $$ = finish_enum (start_enum (make_anon_name()), NULL_TREE);
- check_for_missing_semicolon ($$); }
+ { $$.t = finish_enum (start_enum (make_anon_name()), NULL_TREE);
+ $$.new_type_flag = 1;
+ check_for_missing_semicolon ($$.t); }
| ENUM identifier
- { $$ = xref_tag (enum_type_node, $2, NULL_TREE, 1); }
+ { $$.t = xref_tag (enum_type_node, $2, NULL_TREE, 1);
+ $$.new_type_flag = 0; }
| ENUM complex_type_name
- { $$ = xref_tag (enum_type_node, $2, NULL_TREE, 1); }
- | TYPENAME_KEYWORD complex_type_name
- { $$ = $2; }
+ { $$.t = xref_tag (enum_type_node, $2, NULL_TREE, 1);
+ $$.new_type_flag = 0; }
+ | TYPENAME_KEYWORD typename_sub
+ { $$.t = $2;
+ $$.new_type_flag = 0; }
/* C++ extensions, merged with C to avoid shift/reduce conflicts */
- | class_head left_curly opt.component_decl_list '}'
- {
+ | class_head left_curly
+ opt.component_decl_list '}' maybe_attribute
+ {
int semi;
- tree id;
-#if 0
- /* Need to rework class nesting in the
- presence of nested classes, etc. */
- shadow_tag (CLASSTYPE_AS_LIST ($$)); */
-#endif
if (yychar == YYEMPTY)
yychar = YYLEX;
semi = yychar == ';';
- /* finish_struct nukes this anyway; if
- finish_exception does too, then it can go. */
- if (semi)
- note_got_semicolon ($$);
- if (TREE_CODE ($$) == ENUMERAL_TYPE)
- /* $$ = $1 from default rule. */;
- else
+ $<ttype>$ = finish_class_definition ($1, $3, $5, semi);
+ }
+ pending_defargs
+ { finish_default_args (); }
+ pending_inlines
+ { $$.t = $<ttype>6;
+ $$.new_type_flag = 1;
+ begin_inline_definitions (); }
+ | class_head %prec EMPTY
+ {
+ $$.new_type_flag = 0;
+ if (TYPE_BINFO ($1) == NULL_TREE)
{
- $$ = finish_struct ($$, $3, semi);
- if (semi) note_got_semicolon ($$);
- }
-
- pop_obstacks ();
-
- id = TYPE_IDENTIFIER ($$);
- if (id && IDENTIFIER_TEMPLATE (id))
+ cp_error ("%T is not a class type", $1);
+ $$.t = error_mark_node;
+ }
+ else
{
- tree decl;
-
- /* I don't know if the copying of this TYPE_DECL is
- * really needed. However, it's such a small per-
- * formance penalty that the extra safety is a bargain.
- * - niklas@appli.se
- */
- push_obstacks (&permanent_obstack, &permanent_obstack);
- decl = copy_node (lookup_name (id, 0));
- if (DECL_LANG_SPECIFIC (decl))
- copy_lang_decl (decl);
- pop_obstacks ();
- undo_template_name_overload (id, 0);
- pushdecl_top_level (decl);
+ $$.t = $1;
+ /* struct B: public A; is not accepted by the WP grammar. */
+ if (TYPE_BINFO_BASETYPES ($$.t) && !TYPE_SIZE ($$.t)
+ && ! TYPE_BEING_DEFINED ($$.t))
+ cp_error ("base clause without member specification for `%#T'",
+ $$.t);
}
- if (! semi)
- check_for_missing_semicolon ($$); }
- | class_head %prec EMPTY
- {
- /* struct B: public A; is not accepted by the WP grammar. */
- if (TYPE_BINFO_BASETYPES ($$) && !TYPE_SIZE ($$)
- && ! TYPE_BEING_DEFINED ($$))
- cp_error ("base clause without member specification for `%#T'",
- $$);
}
;
@@ -2265,64 +2113,70 @@ maybecomma:
maybecomma_warn:
/* empty */
| ','
- { if (pedantic) pedwarn ("comma at end of enumerator list"); }
+ { if (pedantic && !in_system_header)
+ pedwarn ("comma at end of enumerator list"); }
;
-aggr: AGGR
+aggr:
+ AGGR
| aggr SCSPEC
{ error ("storage class specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
| aggr TYPESPEC
{ error ("type specifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
- | aggr TYPE_QUAL
+ | aggr CV_QUALIFIER
{ error ("type qualifier `%s' not allowed after struct or class", IDENTIFIER_POINTER ($2)); }
| aggr AGGR
{ error ("no body nor ';' separates two class, struct or union declarations"); }
- ;
-
-specialization:
- aggr template_type_name ';'
- {
- yyungetc (';', 1); current_aggr = $$; $$ = $2;
- if ($<ttype>0 == ridpointers[(int) RID_TEMPLATE])
- instantiate_class_template ($$, 2);
- }
+ | aggr attributes
+ { $$ = build_decl_list ($2, $1); }
;
named_class_head_sans_basetype:
aggr identifier
{ current_aggr = $$; $$ = $2; }
- | specialization
;
named_class_head_sans_basetype_defn:
- aggr identifier_defn %prec EMPTY
+ aggr identifier_defn %prec EMPTY
{ current_aggr = $$; $$ = $2; }
- | aggr template_type_name '{'
- { yyungetc ('{', 1);
- aggr2:
- current_aggr = $$;
- $$ = $2;
- overload_template_name ($$, 0); }
- | aggr template_type_name ':'
- { yyungetc (':', 1); goto aggr2; }
+ | named_class_head_sans_basetype '{'
+ { yyungetc ('{', 1); }
+ | named_class_head_sans_basetype ':'
+ { yyungetc (':', 1); }
;
named_complex_class_head_sans_basetype:
aggr nested_name_specifier identifier
- { current_aggr = $$; $$ = $3; }
- | aggr template_type %prec EMPTY
+ {
+ current_aggr = $1;
+ $$ = handle_class_head ($1, $2, $3);
+ }
+ | aggr global_scope nested_name_specifier identifier
+ {
+ current_aggr = $1;
+ $$ = handle_class_head ($1, $3, $4);
+ }
+ | aggr global_scope identifier
+ {
+ current_aggr = $1;
+ $$ = handle_class_head ($1, NULL_TREE, $3);
+ }
+ | aggr template_type
{ current_aggr = $$; $$ = $2; }
+ | aggr nested_name_specifier template_type
+ { current_aggr = $$; $$ = $3; }
;
-do_xref_defn: /* empty */ %prec EMPTY
- { $<ttype>$ = xref_tag (current_aggr, $<ttype>0, NULL_TREE, 0); }
+do_xref_defn:
+ /* empty */ %prec EMPTY
+ { $<ttype>$ = xref_tag (current_aggr, $<ttype>0, NULL_TREE, 0); }
;
named_class_head:
- named_class_head_sans_basetype %prec EMPTY
+ named_class_head_sans_basetype %prec EMPTY
{ $$ = xref_tag (current_aggr, $1, NULL_TREE, 1); }
| named_class_head_sans_basetype_defn do_xref_defn
- maybe_base_class_list %prec EMPTY
+ maybe_base_class_list %prec EMPTY
{
$$ = $<ttype>2;
if ($3)
@@ -2331,22 +2185,46 @@ named_class_head:
| named_complex_class_head_sans_basetype maybe_base_class_list
{
$$ = TREE_TYPE ($1);
+ if (TREE_INT_CST_LOW (current_aggr) == union_type
+ && TREE_CODE ($$) != UNION_TYPE)
+ cp_pedwarn ("`union' tag used in declaring `%#T'", $$);
+ else if (TREE_CODE ($$) == UNION_TYPE
+ && TREE_INT_CST_LOW (current_aggr) != union_type)
+ cp_pedwarn ("non-`union' tag used in declaring `%#T'", $$);
if ($2)
- xref_basetypes (current_aggr, $1, TREE_TYPE ($1), $2);
+ {
+ if (IS_AGGR_TYPE ($$) && CLASSTYPE_USE_TEMPLATE ($$))
+ {
+ if (CLASSTYPE_IMPLICIT_INSTANTIATION ($$)
+ && TYPE_SIZE ($$) == NULL_TREE)
+ {
+ SET_CLASSTYPE_TEMPLATE_SPECIALIZATION ($$);
+ if (processing_template_decl)
+ push_template_decl (TYPE_MAIN_DECL ($$));
+ }
+ else if (CLASSTYPE_TEMPLATE_INSTANTIATION ($$))
+ cp_error ("specialization after instantiation of `%T'", $$);
+ }
+ xref_basetypes (current_aggr, $1, $$, $2);
+ }
}
;
-unnamed_class_head: aggr '{'
+unnamed_class_head:
+ aggr '{'
{ $$ = xref_tag ($$, make_anon_name (), NULL_TREE, 0);
yyungetc ('{', 1); }
;
-class_head: unnamed_class_head | named_class_head ;
+class_head:
+ unnamed_class_head
+ | named_class_head
+ ;
maybe_base_class_list:
- %prec EMPTY /* empty */
+ /* empty */ %prec EMPTY
{ $$ = NULL_TREE; }
- | ':' see_typename %prec EMPTY
+ | ':' see_typename %prec EMPTY
{ yyungetc(':', 1); $$ = NULL_TREE; }
| ':' see_typename base_class_list %prec EMPTY
{ $$ = $3; }
@@ -2362,8 +2240,14 @@ base_class:
base_class.1
{
tree type;
- type = IDENTIFIER_TYPE_VALUE ($$);
- if (! is_aggr_typedef ($$, 1))
+ if ($1 == NULL_TREE)
+ {
+ error ("invalid base class");
+ type = error_mark_node;
+ }
+ else
+ type = TREE_TYPE ($1);
+ if (! is_aggr_type (type, 1))
$$ = NULL_TREE;
else if (current_aggr == signature_type_node
&& (! type) && (! IS_SIGNATURE (type)))
@@ -2375,7 +2259,7 @@ base_class:
{
sorry ("signature inheritance, base type `%s' ignored",
IDENTIFIER_POINTER ($$));
- $$ = build_tree_list ((tree)access_public, $$);
+ $$ = build_tree_list (access_public_node, type);
}
else if (type && IS_SIGNATURE (type))
{
@@ -2383,15 +2267,21 @@ base_class:
$$ = NULL_TREE;
}
else
- $$ = build_tree_list ((tree)access_default, $$);
+ $$ = build_tree_list (access_default_node, type);
}
| base_class_access_list see_typename base_class.1
{
tree type;
- type = IDENTIFIER_TYPE_VALUE ($3);
+ if ($3 == NULL_TREE)
+ {
+ error ("invalid base class");
+ type = error_mark_node;
+ }
+ else
+ type = TREE_TYPE ($3);
if (current_aggr == signature_type_node)
error ("access and source specifiers not allowed in signature");
- if (! is_aggr_typedef ($3, 1))
+ if (! is_aggr_type (type, 1))
$$ = NULL_TREE;
else if (current_aggr == signature_type_node
&& (! type) && (! IS_SIGNATURE (type)))
@@ -2403,7 +2293,7 @@ base_class:
{
sorry ("signature inheritance, base type `%s' ignored",
IDENTIFIER_POINTER ($$));
- $$ = build_tree_list ((tree)access_public, $3);
+ $$ = build_tree_list (access_public_node, type);
}
else if (type && IS_SIGNATURE (type))
{
@@ -2411,12 +2301,14 @@ base_class:
$$ = NULL_TREE;
}
else
- $$ = build_tree_list ((tree) $$, $3);
+ $$ = build_tree_list ($$, type);
}
;
base_class.1:
- complete_type_name
+ typename_sub
+ { $$ = TYPE_MAIN_DECL ($1); }
+ | nonnested_type
| SIGOF '(' expr ')'
{
if (current_aggr == signature_type_node)
@@ -2424,8 +2316,7 @@ base_class.1:
if (IS_AGGR_TYPE (TREE_TYPE ($3)))
{
sorry ("`sigof' as base signature specifier");
- /* need to return some dummy signature identifier */
- $$ = $3;
+ $$ = TREE_TYPE ($3);
}
else
{
@@ -2443,11 +2334,10 @@ base_class.1:
{
if (current_aggr == signature_type_node)
{
- if (IS_AGGR_TYPE (groktypename ($3)))
+ if (IS_AGGR_TYPE (groktypename ($3.t)))
{
sorry ("`sigof' as base signature specifier");
- /* need to return some dummy signature identifier */
- $$ = $3;
+ $$ = groktypename ($3.t);
}
else
{
@@ -2466,128 +2356,65 @@ base_class.1:
base_class_access_list:
VISSPEC see_typename
| SCSPEC see_typename
- { if ($<ttype>$ != ridpointers[(int)RID_VIRTUAL])
- sorry ("non-virtual access");
- $$ = access_default_virtual; }
+ { if ($1 != ridpointers[(int)RID_VIRTUAL])
+ cp_error ("`%D' access", $1);
+ $$ = access_default_virtual_node; }
| base_class_access_list VISSPEC see_typename
- { int err = 0;
- if ($2 == access_protected)
- {
- warning ("`protected' access not implemented");
- $2 = access_public;
- err++;
- }
- else if ($2 == access_public)
- {
- if ($1 == access_private)
- {
- mixed:
- error ("base class cannot be public and private");
- }
- else if ($1 == access_default_virtual)
- $$ = access_public_virtual;
- }
- else /* $2 == access_private */
- {
- if ($1 == access_public)
- goto mixed;
- else if ($1 == access_default_virtual)
- $$ = access_private_virtual;
- }
+ {
+ if ($1 != access_default_virtual_node)
+ error ("multiple access specifiers");
+ else if ($2 == access_public_node)
+ $$ = access_public_virtual_node;
+ else if ($2 == access_protected_node)
+ $$ = access_protected_virtual_node;
+ else /* $2 == access_private_node */
+ $$ = access_private_virtual_node;
}
| base_class_access_list SCSPEC see_typename
{ if ($2 != ridpointers[(int)RID_VIRTUAL])
- sorry ("non-virtual access");
- if ($$ == access_public)
- $$ = access_public_virtual;
- else if ($$ == access_private)
- $$ = access_private_virtual; }
+ cp_error ("`%D' access", $2);
+ else if ($$ == access_public_node)
+ $$ = access_public_virtual_node;
+ else if ($$ == access_protected_node)
+ $$ = access_protected_virtual_node;
+ else if ($$ == access_private_node)
+ $$ = access_private_virtual_node;
+ else
+ error ("multiple `virtual' specifiers");
+ }
;
-left_curly: '{'
- { tree t = $<ttype>0;
- push_obstacks_nochange ();
- end_temporary_allocation ();
-
- if (! IS_AGGR_TYPE (t))
- {
- t = $<ttype>0 = make_lang_type (RECORD_TYPE);
- TYPE_NAME (t) = get_identifier ("erroneous type");
- }
- if (TYPE_SIZE (t))
- duplicate_tag_error (t);
- if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t))
- {
- t = make_lang_type (TREE_CODE (t));
- pushtag (TYPE_IDENTIFIER ($<ttype>0), t, 0);
- $<ttype>0 = t;
- }
- pushclass (t, 0);
- TYPE_BEING_DEFINED (t) = 1;
- /* Reset the interface data, at the earliest possible
- moment, as it might have been set via a class foo;
- before. */
- /* Don't change signatures. */
- if (! IS_SIGNATURE (t))
- {
- extern tree pending_vtables;
- int needs_writing;
- tree name = TYPE_IDENTIFIER (t);
-
- if (! ANON_AGGRNAME_P (name))
- {
- CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
- SET_CLASSTYPE_INTERFACE_UNKNOWN_X
- (t, interface_unknown);
- }
+left_curly:
+ '{'
+ { $<ttype>0 = begin_class_definition ($<ttype>0); }
+ ;
- /* Record how to set the access of this class's
- virtual functions. If write_virtuals == 2 or 3, then
- inline virtuals are ``extern inline''. */
- switch (write_virtuals)
- {
- case 0:
- case 1:
- needs_writing = 1;
- break;
- case 2:
- needs_writing = !! value_member (name, pending_vtables);
- break;
- case 3:
- needs_writing = ! CLASSTYPE_INTERFACE_ONLY (t)
- && CLASSTYPE_INTERFACE_KNOWN (t);
- break;
- default:
- needs_writing = 0;
- }
- CLASSTYPE_VTABLE_NEEDS_WRITING (t) = needs_writing;
- }
-#if 0
- t = TYPE_IDENTIFIER ($<ttype>0);
- if (t && IDENTIFIER_TEMPLATE (t))
- overload_template_name (t, 1);
-#endif
+self_reference:
+ /* empty */
+ {
+ $$ = build_self_reference ();
}
;
opt.component_decl_list:
- /* empty */
- { $$ = NULL_TREE; }
- | component_decl_list
+ self_reference
+ { if ($$) $$ = build_tree_list (access_public_node, $$); }
+ | self_reference component_decl_list
{
if (current_aggr == signature_type_node)
- $$ = build_tree_list ((tree) access_public, $$);
+ $$ = build_tree_list (access_public_node, $2);
else
- $$ = build_tree_list ((tree) access_default, $$);
+ $$ = build_tree_list (access_default_node, $2);
+ if ($1) $$ = tree_cons (access_public_node, $1, $$);
}
| opt.component_decl_list VISSPEC ':' component_decl_list
{
- tree visspec = (tree) $2;
+ tree visspec = $2;
if (current_aggr == signature_type_node)
{
error ("access specifier not allowed in signature");
- visspec = (tree) access_public;
+ visspec = access_public_node;
}
$$ = chainon ($$, build_tree_list (visspec, $4));
}
@@ -2637,6 +2464,13 @@ component_decl:
{ $$ = finish_method ($$); }
| ';'
{ $$ = NULL_TREE; }
+ | extension component_decl
+ { $$ = $2;
+ pedantic = $<itype>1; }
+ | template_header component_decl
+ { $$ = finish_member_template_decl ($1, $2); }
+ | template_header typed_declspecs ';'
+ { $$ = finish_member_class_template ($1, $2.t); }
;
component_decl_1:
@@ -2644,12 +2478,15 @@ component_decl_1:
speed; we need to call grok_x_components for enums, so the
speedup would be insignificant. */
typed_declspecs components
- { $$ = grok_x_components ($1, $2); }
+ { $$ = grok_x_components ($1.t, $2); }
| declmods notype_components
{ $$ = grok_x_components ($1, $2); }
- | notype_declarator exception_specification_opt maybeasm maybe_attribute maybe_init
- { $$ = grokfield ($$, NULL_TREE, $2, $5, $3,
- build_tree_list ($4, NULL_TREE)); }
+ | notype_declarator maybeasm maybe_attribute maybe_init
+ { $$ = grokfield ($$, NULL_TREE, $4, $2,
+ build_tree_list ($3, NULL_TREE)); }
+ | constructor_declarator maybeasm maybe_attribute maybe_init
+ { $$ = grokfield ($$, NULL_TREE, $4, $2,
+ build_tree_list ($3, NULL_TREE)); }
| ':' expr_no_commas
{ $$ = grokbitfield (NULL_TREE, NULL_TREE, $2); }
| error
@@ -2663,25 +2500,18 @@ component_decl_1:
should "A::foo" be declared as a function or "A::bar" as a data
member? In other words, is "bar" an after_type_declarator or a
parmlist? */
- | typed_declspecs '(' parmlist ')' type_quals exception_specification_opt maybeasm maybe_attribute maybe_init
- { tree specs, attrs;
- split_specs_attrs ($1, &specs, &attrs);
- $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs),
- $3, $5);
- $$ = grokfield ($$, TREE_CHAIN (specs), $6, $9, $7,
- build_tree_list ($8, attrs)); }
- | typed_declspecs LEFT_RIGHT type_quals exception_specification_opt maybeasm maybe_attribute maybe_init
+ | declmods component_constructor_declarator maybeasm maybe_attribute maybe_init
{ tree specs, attrs;
split_specs_attrs ($1, &specs, &attrs);
- $$ = build_parse_node (CALL_EXPR, TREE_VALUE (specs),
- empty_parms (), $3);
- $$ = grokfield ($$, TREE_CHAIN (specs), $4, $7, $5,
- build_tree_list ($6, attrs)); }
+ $$ = grokfield ($2, specs, $5, $3,
+ build_tree_list ($4, attrs)); }
+ | component_constructor_declarator maybeasm maybe_attribute maybe_init
+ { $$ = grokfield ($$, NULL_TREE, $4, $2,
+ build_tree_list ($3, NULL_TREE)); }
| using_decl
{ $$ = do_class_using_decl ($1); }
- ;
-/* The case of exactly one component is handled directly by component_decl. */
+/* The case of exactly one component is handled directly by component_decl. */
/* ??? Huh? ^^^ */
components:
/* empty: possibly anonymous */
@@ -2724,12 +2554,12 @@ component_declarator:
;
after_type_component_declarator0:
- after_type_declarator exception_specification_opt maybeasm maybe_attribute maybe_init
+ after_type_declarator maybeasm maybe_attribute maybe_init
{ split_specs_attrs ($<ttype>0, &current_declspecs,
&prefix_attributes);
$<ttype>0 = current_declspecs;
- $$ = grokfield ($$, current_declspecs, $2, $5, $3,
- build_tree_list ($4, prefix_attributes)); }
+ $$ = grokfield ($$, current_declspecs, $4, $2,
+ build_tree_list ($3, prefix_attributes)); }
| TYPENAME ':' expr_no_commas maybe_attribute
{ split_specs_attrs ($<ttype>0, &current_declspecs,
&prefix_attributes);
@@ -2739,12 +2569,18 @@ after_type_component_declarator0:
;
notype_component_declarator0:
- notype_declarator exception_specification_opt maybeasm maybe_attribute maybe_init
+ notype_declarator maybeasm maybe_attribute maybe_init
+ { split_specs_attrs ($<ttype>0, &current_declspecs,
+ &prefix_attributes);
+ $<ttype>0 = current_declspecs;
+ $$ = grokfield ($$, current_declspecs, $4, $2,
+ build_tree_list ($3, prefix_attributes)); }
+ | constructor_declarator maybeasm maybe_attribute maybe_init
{ split_specs_attrs ($<ttype>0, &current_declspecs,
&prefix_attributes);
$<ttype>0 = current_declspecs;
- $$ = grokfield ($$, current_declspecs, $2, $5, $3,
- build_tree_list ($4, prefix_attributes)); }
+ $$ = grokfield ($$, current_declspecs, $4, $2,
+ build_tree_list ($3, prefix_attributes)); }
| IDENTIFIER ':' expr_no_commas maybe_attribute
{ split_specs_attrs ($<ttype>0, &current_declspecs,
&prefix_attributes);
@@ -2760,18 +2596,18 @@ notype_component_declarator0:
;
after_type_component_declarator:
- after_type_declarator exception_specification_opt maybeasm maybe_attribute maybe_init
- { $$ = grokfield ($$, current_declspecs, $2, $5, $3,
- build_tree_list ($4, prefix_attributes)); }
+ after_type_declarator maybeasm maybe_attribute maybe_init
+ { $$ = grokfield ($$, current_declspecs, $4, $2,
+ build_tree_list ($3, prefix_attributes)); }
| TYPENAME ':' expr_no_commas maybe_attribute
{ $$ = grokbitfield ($$, current_declspecs, $3);
cplus_decl_attributes ($$, $4, prefix_attributes); }
;
notype_component_declarator:
- notype_declarator exception_specification_opt maybeasm maybe_attribute maybe_init
- { $$ = grokfield ($$, current_declspecs, $2, $5, $3,
- build_tree_list ($4, prefix_attributes)); }
+ notype_declarator maybeasm maybe_attribute maybe_init
+ { $$ = grokfield ($$, current_declspecs, $4, $2,
+ build_tree_list ($3, prefix_attributes)); }
| IDENTIFIER ':' expr_no_commas maybe_attribute
{ $$ = grokbitfield ($$, current_declspecs, $3);
cplus_decl_attributes ($$, $4, prefix_attributes); }
@@ -2800,44 +2636,52 @@ enumerator:
/* ANSI new-type-id (5.3.4) */
new_type_id:
type_specifier_seq new_declarator
- { $$ = build_decl_list ($$, $2); }
- | type_specifier_seq %prec EMPTY
- { $$ = build_decl_list ($$, NULL_TREE); }
+ { $$.t = build_decl_list ($1.t, $2);
+ $$.new_type_flag = $1.new_type_flag; }
+ | type_specifier_seq %prec EMPTY
+ { $$.t = build_decl_list ($1.t, NULL_TREE);
+ $$.new_type_flag = $1.new_type_flag; }
/* GNU extension to allow arrays of arbitrary types with
- non-constant dimension. */
- | '(' type_id ')' '[' expr ']'
+ non-constant dimension. For the use of begin_new_placement
+ here, see the comments in unary_expr above. */
+ | '(' .begin_new_placement type_id .finish_new_placement
+ '[' expr ']'
{
if (pedantic)
pedwarn ("ANSI C++ forbids array dimensions with parenthesized type in new");
- $$ = build_parse_node (ARRAY_REF, TREE_VALUE ($2), $5);
- $$ = build_decl_list (TREE_PURPOSE ($2), $$);
+ $$.t = build_parse_node (ARRAY_REF, TREE_VALUE ($3.t), $6);
+ $$.t = build_decl_list (TREE_PURPOSE ($3.t), $$.t);
+ $$.new_type_flag = $3.new_type_flag;
}
;
-type_quals:
- /* empty */ %prec EMPTY
+cv_qualifiers:
+ /* empty */ %prec EMPTY
{ $$ = NULL_TREE; }
- | type_quals TYPE_QUAL
+ | cv_qualifiers CV_QUALIFIER
{ $$ = decl_tree_cons (NULL_TREE, $2, $$); }
;
-nonempty_type_quals:
- TYPE_QUAL
- { $$ = IDENTIFIER_AS_LIST ($$); }
- | nonempty_type_quals TYPE_QUAL
- { $$ = decl_tree_cons (NULL_TREE, $2, $$); }
+nonempty_cv_qualifiers:
+ CV_QUALIFIER
+ { $$.t = IDENTIFIER_AS_LIST ($1);
+ $$.new_type_flag = 0; }
+ | nonempty_cv_qualifiers CV_QUALIFIER
+ { $$.t = decl_tree_cons (NULL_TREE, $2, $1.t);
+ $$.new_type_flag = $1.new_type_flag; }
;
/* These rules must follow the rules for function declarations
and component declarations. That way, longer rules are preferred. */
suspend_mom:
- { $<itype>$ = suspend_momentary (); }
+ /* empty */
+ { $<itype>$ = suspend_momentary (); }
/* An expression which will not live on the momentary obstack. */
nonmomentary_expr:
- suspend_mom expr
- { resume_momentary ((int) $<itype>1); $$ = $2; }
+ suspend_mom expr
+ { resume_momentary ((int) $<itype>1); $$ = $2; }
;
/* An expression which will not live on the momentary obstack. */
@@ -2855,72 +2699,90 @@ maybe_parmlist:
/* A declarator that is allowed only after an explicit typespec. */
/* may all be followed by prec '.' */
after_type_declarator:
- '*' nonempty_type_quals after_type_declarator %prec UNARY
- { $$ = make_pointer_declarator ($2, $3); }
- | '&' nonempty_type_quals after_type_declarator %prec UNARY
- { $$ = make_reference_declarator ($2, $3); }
+ '*' nonempty_cv_qualifiers after_type_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2.t, $3); }
+ | '&' nonempty_cv_qualifiers after_type_declarator %prec UNARY
+ { $$ = make_reference_declarator ($2.t, $3); }
| '*' after_type_declarator %prec UNARY
{ $$ = make_pointer_declarator (NULL_TREE, $2); }
| '&' after_type_declarator %prec UNARY
{ $$ = make_reference_declarator (NULL_TREE, $2); }
- | ptr_to_mem type_quals after_type_declarator
+ | ptr_to_mem cv_qualifiers after_type_declarator
{ tree arg = make_pointer_declarator ($2, $3);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
| direct_after_type_declarator
;
-qualified_type_name:
- type_name %prec EMPTY
+nonnested_type:
+ type_name %prec EMPTY
{
- /* Remember that this name has been used in the class
- definition, as per [class.scope0] */
- if (current_class_type
- && TYPE_BEING_DEFINED (current_class_type)
- && ! IDENTIFIER_CLASS_VALUE ($$))
+ if (TREE_CODE ($1) == IDENTIFIER_NODE)
{
- tree t = lookup_name ($$, -2);
- if (t)
- pushdecl_class_level (t);
+ $$ = lookup_name ($1, 1);
+ if (current_class_type
+ && TYPE_BEING_DEFINED (current_class_type)
+ && ! IDENTIFIER_CLASS_VALUE ($1))
+ {
+ /* Remember that this name has been used in the class
+ definition, as per [class.scope0] */
+ pushdecl_class_level ($$);
+ }
}
+ else
+ $$ = $1;
}
+ | global_scope type_name
+ {
+ if (TREE_CODE ($2) == IDENTIFIER_NODE)
+ $$ = IDENTIFIER_GLOBAL_VALUE ($2);
+ else
+ $$ = $2;
+ got_scope = NULL_TREE;
+ }
+ ;
+
+complete_type_name:
+ nonnested_type
| nested_type
+ | global_scope nested_type
+ { $$ = $2; }
;
nested_type:
- nested_name_specifier type_name %prec EMPTY
- { $$ = $2; }
+ nested_name_specifier type_name %prec EMPTY
+ { $$ = get_type_decl ($2); }
;
direct_after_type_declarator:
- direct_after_type_declarator maybe_parmlist type_quals %prec '.'
- { $$ = build_parse_node (CALL_EXPR, $$, $2, $3); }
+ direct_after_type_declarator maybe_parmlist cv_qualifiers exception_specification_opt %prec '.'
+ { $$ = make_call_declarator ($$, $2, $3, $4); }
| direct_after_type_declarator '[' nonmomentary_expr ']'
{ $$ = build_parse_node (ARRAY_REF, $$, $3); }
| direct_after_type_declarator '[' ']'
{ $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
| '(' after_type_declarator ')'
{ $$ = $2; }
- | nested_name_specifier type_name %prec EMPTY
- { push_nested_class (TREE_TYPE ($$), 3);
+ | nested_name_specifier type_name %prec EMPTY
+ { push_nested_class ($1, 3);
$$ = build_parse_node (SCOPE_REF, $$, $2);
TREE_COMPLEXITY ($$) = current_class_depth; }
- | type_name %prec EMPTY
+ | type_name %prec EMPTY
;
/* A declarator allowed whether or not there has been
an explicit typespec. These cannot redeclare a typedef-name. */
notype_declarator:
- '*' nonempty_type_quals notype_declarator %prec UNARY
- { $$ = make_pointer_declarator ($2, $3); }
- | '&' nonempty_type_quals notype_declarator %prec UNARY
- { $$ = make_reference_declarator ($2, $3); }
+ '*' nonempty_cv_qualifiers notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2.t, $3); }
+ | '&' nonempty_cv_qualifiers notype_declarator %prec UNARY
+ { $$ = make_reference_declarator ($2.t, $3); }
| '*' notype_declarator %prec UNARY
{ $$ = make_pointer_declarator (NULL_TREE, $2); }
| '&' notype_declarator %prec UNARY
{ $$ = make_reference_declarator (NULL_TREE, $2); }
- | ptr_to_mem type_quals notype_declarator
+ | ptr_to_mem cv_qualifiers notype_declarator
{ tree arg = make_pointer_declarator ($2, $3);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
@@ -2928,15 +2790,15 @@ notype_declarator:
;
complex_notype_declarator:
- '*' nonempty_type_quals notype_declarator %prec UNARY
- { $$ = make_pointer_declarator ($2, $3); }
- | '&' nonempty_type_quals notype_declarator %prec UNARY
- { $$ = make_reference_declarator ($2, $3); }
+ '*' nonempty_cv_qualifiers notype_declarator %prec UNARY
+ { $$ = make_pointer_declarator ($2.t, $3); }
+ | '&' nonempty_cv_qualifiers notype_declarator %prec UNARY
+ { $$ = make_reference_declarator ($2.t, $3); }
| '*' complex_notype_declarator %prec UNARY
{ $$ = make_pointer_declarator (NULL_TREE, $2); }
| '&' complex_notype_declarator %prec UNARY
{ $$ = make_reference_declarator (NULL_TREE, $2); }
- | ptr_to_mem type_quals notype_declarator
+ | ptr_to_mem cv_qualifiers notype_declarator
{ tree arg = make_pointer_declarator ($2, $3);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
@@ -2944,8 +2806,8 @@ complex_notype_declarator:
;
complex_direct_notype_declarator:
- direct_notype_declarator maybe_parmlist type_quals %prec '.'
- { $$ = build_parse_node (CALL_EXPR, $$, $2, $3); }
+ direct_notype_declarator maybe_parmlist cv_qualifiers exception_specification_opt %prec '.'
+ { $$ = make_call_declarator ($$, $2, $3, $4); }
| '(' complex_notype_declarator ')'
{ $$ = $2; }
| direct_notype_declarator '[' nonmomentary_expr ']'
@@ -2953,24 +2815,44 @@ complex_direct_notype_declarator:
| direct_notype_declarator '[' ']'
{ $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
| notype_qualified_id
- { if (TREE_TYPE (OP0 ($$)) != current_class_type)
+ { if (TREE_CODE (OP0 ($1)) == NAMESPACE_DECL)
+ {
+ push_decl_namespace (OP0 ($1));
+ TREE_COMPLEXITY ($1) = -1;
+ }
+ else if (OP0 ($1) != current_class_type)
+ {
+ push_nested_class (OP0 ($1), 3);
+ TREE_COMPLEXITY ($1) = current_class_depth;
+ }
+ }
+ | nested_name_specifier notype_template_declarator
+ { got_scope = NULL_TREE;
+ $$ = build_parse_node (SCOPE_REF, $1, $2);
+ if ($1 != current_class_type)
{
- push_nested_class (TREE_TYPE (OP0 ($$)), 3);
+ push_nested_class ($1, 3);
TREE_COMPLEXITY ($$) = current_class_depth;
}
}
;
qualified_id:
- nested_name_specifier unqualified_id
+ nested_name_specifier unqualified_id
{ got_scope = NULL_TREE;
$$ = build_parse_node (SCOPE_REF, $$, $2); }
+ | nested_name_specifier object_template_id
+ { got_scope = NULL_TREE;
+ $$ = build_parse_node (SCOPE_REF, $1, $2); }
;
notype_qualified_id:
- nested_name_specifier notype_unqualified_id
+ nested_name_specifier notype_unqualified_id
{ got_scope = NULL_TREE;
$$ = build_parse_node (SCOPE_REF, $$, $2); }
+ | nested_name_specifier object_template_id
+ { got_scope = NULL_TREE;
+ $$ = build_parse_node (SCOPE_REF, $1, $2); }
;
overqualified_id:
@@ -2981,33 +2863,58 @@ overqualified_id:
functional_cast:
typespec '(' nonnull_exprlist ')'
- { $$ = build_functional_cast ($$, $3); }
+ { $$ = build_functional_cast ($1.t, $3); }
| typespec '(' expr_or_declarator ')'
- { $$ = reparse_decl_as_expr ($$, $3); }
- | typespec fcast_or_absdcl %prec EMPTY
- { $$ = reparse_absdcl_as_expr ($$, $2); }
+ { $$ = reparse_decl_as_expr ($1.t, $3); }
+ | typespec fcast_or_absdcl %prec EMPTY
+ { $$ = reparse_absdcl_as_expr ($1.t, $2); }
;
type_name:
TYPENAME
- | template_type %prec EMPTY
+ | SELFNAME
+ | template_type %prec EMPTY
;
nested_name_specifier:
nested_name_specifier_1
| nested_name_specifier nested_name_specifier_1
{ $$ = $2; }
+ | nested_name_specifier TEMPLATE explicit_template_type SCOPE
+ { got_scope = $$ = make_typename_type ($1, $3); }
;
/* Why the @#$%^& do type_name and notype_identifier need to be expanded
inline here?!? (jason) */
nested_name_specifier_1:
TYPENAME SCOPE
- { got_scope = TREE_TYPE ($$); }
+ {
+ if (TREE_CODE ($1) == IDENTIFIER_NODE)
+ {
+ $$ = lastiddecl;
+ /* Remember that this name has been used in the class
+ definition, as per [class.scope0] */
+ if (current_class_type
+ && TYPE_BEING_DEFINED (current_class_type)
+ && ! IDENTIFIER_CLASS_VALUE ($1))
+ pushdecl_class_level ($$);
+ }
+ got_scope = $$ = TYPE_MAIN_VARIANT (TREE_TYPE ($$));
+ }
+ | SELFNAME SCOPE
+ {
+ if (TREE_CODE ($1) == IDENTIFIER_NODE)
+ $$ = lastiddecl;
+ got_scope = $$ = TREE_TYPE ($$);
+ }
| NSNAME SCOPE
- { got_scope = $$; }
+ {
+ if (TREE_CODE ($$) == IDENTIFIER_NODE)
+ $$ = lastiddecl;
+ got_scope = $$;
+ }
| template_type SCOPE
- { got_scope = TREE_TYPE ($$); }
+ { got_scope = $$ = complete_type (TREE_TYPE ($1)); }
/* These break 'const i;'
| IDENTIFIER SCOPE
{
@@ -3020,15 +2927,106 @@ nested_name_specifier_1:
{ goto failed_scope; } */
;
-complete_type_name:
- qualified_type_name
- | global_scope qualified_type_name
+typename_sub:
+ typename_sub0
+ | global_scope typename_sub0
{ $$ = $2; }
;
+typename_sub0:
+ typename_sub1 identifier %prec EMPTY
+ {
+ if (TREE_CODE_CLASS (TREE_CODE ($1)) == 't')
+ $$ = make_typename_type ($1, $2);
+ else if (TREE_CODE ($2) == IDENTIFIER_NODE)
+ cp_error ("`%T' is not a class or namespace", $2);
+ else
+ {
+ $$ = $2;
+ if (TREE_CODE ($$) == TYPE_DECL)
+ $$ = TREE_TYPE ($$);
+ }
+ }
+ | typename_sub1 template_type %prec EMPTY
+ { $$ = TREE_TYPE ($2); }
+ | typename_sub1 explicit_template_type %prec EMPTY
+ { $$ = make_typename_type ($1, $2); }
+ | typename_sub1 TEMPLATE explicit_template_type %prec EMPTY
+ { $$ = make_typename_type ($1, $3); }
+ ;
+
+typename_sub1:
+ typename_sub2
+ {
+ if (TREE_CODE ($1) == IDENTIFIER_NODE)
+ cp_error ("`%T' is not a class or namespace", $1);
+ }
+ | typename_sub1 typename_sub2
+ {
+ if (TREE_CODE_CLASS (TREE_CODE ($1)) == 't')
+ $$ = make_typename_type ($1, $2);
+ else if (TREE_CODE ($2) == IDENTIFIER_NODE)
+ cp_error ("`%T' is not a class or namespace", $2);
+ else
+ {
+ $$ = $2;
+ if (TREE_CODE ($$) == TYPE_DECL)
+ $$ = TREE_TYPE ($$);
+ }
+ }
+ | typename_sub1 explicit_template_type SCOPE
+ { got_scope = $$ = make_typename_type ($1, $2); }
+ | typename_sub1 TEMPLATE explicit_template_type SCOPE
+ { got_scope = $$ = make_typename_type ($1, $3); }
+ ;
+
+typename_sub2:
+ TYPENAME SCOPE
+ {
+ if (TREE_CODE ($1) != IDENTIFIER_NODE)
+ $1 = lastiddecl;
+
+ /* Retrieve the type for the identifier, which might involve
+ some computation. */
+ got_scope = $$ = complete_type (IDENTIFIER_TYPE_VALUE ($1));
+
+ if ($$ == error_mark_node)
+ cp_error ("`%T' is not a class or namespace", $1);
+ }
+ | SELFNAME SCOPE
+ {
+ if (TREE_CODE ($1) != IDENTIFIER_NODE)
+ $$ = lastiddecl;
+ got_scope = $$ = complete_type (TREE_TYPE ($$));
+ }
+ | template_type SCOPE
+ { got_scope = $$ = complete_type (TREE_TYPE ($$)); }
+ | PTYPENAME SCOPE
+ | IDENTIFIER SCOPE
+ | NSNAME SCOPE
+ {
+ if (TREE_CODE ($$) == IDENTIFIER_NODE)
+ $$ = lastiddecl;
+ got_scope = $$;
+ }
+ ;
+
+explicit_template_type:
+ identifier '<' template_arg_list_opt template_close_bracket
+ { $$ = build_min_nt (TEMPLATE_ID_EXPR, $1, $3); }
+ ;
+
complex_type_name:
- nested_type
- | global_scope qualified_type_name
+ global_scope type_name
+ {
+ if (TREE_CODE ($2) == IDENTIFIER_NODE)
+ $$ = IDENTIFIER_GLOBAL_VALUE ($2);
+ else
+ $$ = $2;
+ got_scope = NULL_TREE;
+ }
+ | nested_type
+ | global_scope nested_type
{ $$ = $2; }
;
@@ -3040,7 +3038,7 @@ ptr_to_mem:
;
/* All uses of explicit global scope must go through this nonterminal so
- that got_scope will be set before yylex is called to get the next token. */
+ that got_scope will be set before yylex is called to get the next token. */
global_scope:
SCOPE
{ got_scope = void_type_node; }
@@ -3048,23 +3046,23 @@ global_scope:
/* ANSI new-declarator (5.3.4) */
new_declarator:
- '*' type_quals new_declarator
+ '*' cv_qualifiers new_declarator
{ $$ = make_pointer_declarator ($2, $3); }
- | '*' type_quals %prec EMPTY
+ | '*' cv_qualifiers %prec EMPTY
{ $$ = make_pointer_declarator ($2, NULL_TREE); }
- | '&' type_quals new_declarator %prec EMPTY
+ | '&' cv_qualifiers new_declarator %prec EMPTY
{ $$ = make_reference_declarator ($2, $3); }
- | '&' type_quals %prec EMPTY
+ | '&' cv_qualifiers %prec EMPTY
{ $$ = make_reference_declarator ($2, NULL_TREE); }
- | ptr_to_mem type_quals %prec EMPTY
+ | ptr_to_mem cv_qualifiers %prec EMPTY
{ tree arg = make_pointer_declarator ($2, NULL_TREE);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
- | ptr_to_mem type_quals new_declarator
+ | ptr_to_mem cv_qualifiers new_declarator
{ tree arg = make_pointer_declarator ($2, $3);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
- | direct_new_declarator %prec EMPTY
+ | direct_new_declarator %prec EMPTY
;
/* ANSI direct-new-declarator (5.3.4) */
@@ -3077,31 +3075,31 @@ direct_new_declarator:
/* ANSI abstract-declarator (8.1) */
absdcl:
- '*' nonempty_type_quals absdcl
- { $$ = make_pointer_declarator ($2, $3); }
+ '*' nonempty_cv_qualifiers absdcl
+ { $$ = make_pointer_declarator ($2.t, $3); }
| '*' absdcl
{ $$ = make_pointer_declarator (NULL_TREE, $2); }
- | '*' nonempty_type_quals %prec EMPTY
- { $$ = make_pointer_declarator ($2, NULL_TREE); }
- | '*' %prec EMPTY
+ | '*' nonempty_cv_qualifiers %prec EMPTY
+ { $$ = make_pointer_declarator ($2.t, NULL_TREE); }
+ | '*' %prec EMPTY
{ $$ = make_pointer_declarator (NULL_TREE, NULL_TREE); }
- | '&' nonempty_type_quals absdcl
- { $$ = make_reference_declarator ($2, $3); }
+ | '&' nonempty_cv_qualifiers absdcl
+ { $$ = make_reference_declarator ($2.t, $3); }
| '&' absdcl
{ $$ = make_reference_declarator (NULL_TREE, $2); }
- | '&' nonempty_type_quals %prec EMPTY
- { $$ = make_reference_declarator ($2, NULL_TREE); }
- | '&' %prec EMPTY
+ | '&' nonempty_cv_qualifiers %prec EMPTY
+ { $$ = make_reference_declarator ($2.t, NULL_TREE); }
+ | '&' %prec EMPTY
{ $$ = make_reference_declarator (NULL_TREE, NULL_TREE); }
- | ptr_to_mem type_quals %prec EMPTY
+ | ptr_to_mem cv_qualifiers %prec EMPTY
{ tree arg = make_pointer_declarator ($2, NULL_TREE);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
- | ptr_to_mem type_quals absdcl
+ | ptr_to_mem cv_qualifiers absdcl
{ tree arg = make_pointer_declarator ($2, $3);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
- | direct_abstract_declarator %prec EMPTY
+ | direct_abstract_declarator %prec EMPTY
;
/* ANSI direct-abstract-declarator (8.1) */
@@ -3110,20 +3108,20 @@ direct_abstract_declarator:
{ $$ = $2; }
/* `(typedef)1' is `int'. */
| PAREN_STAR_PAREN
- | direct_abstract_declarator '(' parmlist ')' type_quals %prec '.'
- { $$ = build_parse_node (CALL_EXPR, $$, $3, $5); }
- | direct_abstract_declarator LEFT_RIGHT type_quals %prec '.'
- { $$ = build_parse_node (CALL_EXPR, $$, empty_parms (), $3); }
+ | direct_abstract_declarator '(' parmlist ')' cv_qualifiers exception_specification_opt %prec '.'
+ { $$ = make_call_declarator ($$, $3, $5, $6); }
+ | direct_abstract_declarator LEFT_RIGHT cv_qualifiers exception_specification_opt %prec '.'
+ { $$ = make_call_declarator ($$, empty_parms (), $3, $4); }
| direct_abstract_declarator '[' nonmomentary_expr ']' %prec '.'
{ $$ = build_parse_node (ARRAY_REF, $$, $3); }
| direct_abstract_declarator '[' ']' %prec '.'
{ $$ = build_parse_node (ARRAY_REF, $$, NULL_TREE); }
- | '(' complex_parmlist ')' type_quals %prec '.'
- { $$ = build_parse_node (CALL_EXPR, NULL_TREE, $2, $4); }
- | regcast_or_absdcl type_quals %prec '.'
- { TREE_OPERAND ($$, 2) = $2; }
- | fcast_or_absdcl type_quals %prec '.'
- { TREE_OPERAND ($$, 2) = $2; }
+ | '(' complex_parmlist ')' cv_qualifiers exception_specification_opt %prec '.'
+ { $$ = make_call_declarator (NULL_TREE, $2, $4, $5); }
+ | regcast_or_absdcl cv_qualifiers exception_specification_opt %prec '.'
+ { set_quals_and_spec ($$, $2, $3); }
+ | fcast_or_absdcl cv_qualifiers exception_specification_opt %prec '.'
+ { set_quals_and_spec ($$, $2, $3); }
| '[' nonmomentary_expr ']' %prec '.'
{ $$ = build_parse_node (ARRAY_REF, NULL_TREE, $2); }
| '[' ']' %prec '.'
@@ -3141,25 +3139,8 @@ stmts:
| stmts errstmt
;
-errstmt: error ';'
- ;
-
-/* build the LET_STMT node before parsing its contents,
- so that any LET_STMTs within the context can have their display pointers
- set up to point at this one. */
-
-.pushlevel: /* empty */
- { emit_line_note (input_filename, lineno);
- pushlevel (0);
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0); }
- ;
-
-.poplevel: /* empty */
- { expand_end_bindings (getdecls (), kept_level_p (), 1);
- $$ = poplevel (kept_level_p (), 1, 0);
- pop_momentary (); }
+errstmt:
+ error ';'
;
/* Read zero or more forward-declarations for labels
@@ -3196,29 +3177,35 @@ compstmt_or_error:
| error compstmt
;
-compstmt: '{' .pushlevel compstmtend .poplevel
- { $$ = $4; }
+compstmt:
+ '{'
+ { $<ttype>$ = begin_compound_stmt (0); }
+ compstmtend
+ { $$ = finish_compound_stmt (0, $<ttype>2); }
;
simple_if:
IF
- { cond_stmt_keyword = "if"; }
- .pushlevel paren_cond_or_null
- { emit_line_note (input_filename, lineno);
- expand_start_cond ($4, 0); }
- implicitly_scoped_stmt
+ {
+ $<ttype>$ = begin_if_stmt ();
+ cond_stmt_keyword = "if";
+ }
+ paren_cond_or_null
+ { finish_if_stmt_cond ($3, $<ttype>2); }
+ implicitly_scoped_stmt
+ { $<ttype>$ = finish_then_clause ($<ttype>2); }
;
implicitly_scoped_stmt:
compstmt
- { finish_stmt (); }
- | .pushlevel simple_stmt .poplevel
- { $$ = $3; }
+ | { $<ttype>$ = begin_compound_stmt (0); }
+ simple_stmt
+ { $$ = finish_compound_stmt (0, $<ttype>1); }
;
stmt:
compstmt
- { finish_stmt (); }
+ {}
| simple_stmt
;
@@ -3226,234 +3213,93 @@ simple_stmt:
decl
{ finish_stmt (); }
| expr ';'
- {
- tree expr = $1;
- emit_line_note (input_filename, lineno);
- /* Do default conversion if safe and possibly important,
- in case within ({...}). */
- if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
- && lvalue_p (expr))
- || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
- expr = default_conversion (expr);
- cplus_expand_expr_stmt (expr);
- clear_momentary ();
- finish_stmt (); }
+ { finish_expr_stmt ($1); }
| simple_if ELSE
- { expand_start_else (); }
+ { begin_else_clause (); }
implicitly_scoped_stmt
- { expand_end_cond (); }
- .poplevel
- { finish_stmt (); }
- | simple_if %prec IF
- { expand_end_cond ();
- expand_end_bindings (getdecls (), kept_level_p (), 1);
- poplevel (kept_level_p (), 1, 0);
- pop_momentary ();
- finish_stmt (); }
+ {
+ finish_else_clause ($<ttype>1);
+ finish_if_stmt ();
+ }
+ | simple_if %prec IF
+ { finish_if_stmt (); }
| WHILE
- { emit_nop ();
- emit_line_note (input_filename, lineno);
- expand_start_loop (1);
- cond_stmt_keyword = "while"; }
- .pushlevel paren_cond_or_null
- { expand_exit_loop_if_false (0, $4); }
- already_scoped_stmt .poplevel
- { expand_end_loop ();
- finish_stmt (); }
+ {
+ $<ttype>$ = begin_while_stmt ();
+ cond_stmt_keyword = "while";
+ }
+ paren_cond_or_null
+ { finish_while_stmt_cond ($3, $<ttype>2); }
+ already_scoped_stmt
+ { finish_while_stmt ($<ttype>2); }
| DO
- { emit_nop ();
- emit_line_note (input_filename, lineno);
- expand_start_loop_continue_elsewhere (1); }
+ { $<ttype>$ = begin_do_stmt (); }
implicitly_scoped_stmt WHILE
- { expand_loop_continue_here ();
- cond_stmt_keyword = "do"; }
+ {
+ finish_do_body ($<ttype>2);
+ cond_stmt_keyword = "do";
+ }
paren_expr_or_null ';'
- { emit_line_note (input_filename, lineno);
- expand_exit_loop_if_false (0, $6);
- expand_end_loop ();
- clear_momentary ();
- finish_stmt (); }
+ { finish_do_stmt ($6, $<ttype>2); }
| FOR
- { emit_line_note (input_filename, lineno);
- if (flag_new_for_scope > 0)
- {
- /* Conditionalize .pushlevel */
- pushlevel (0);
- note_level_for_for ();
- clear_last_expr ();
- push_momentary ();
- expand_start_bindings (0);
- }
- }
+ { $<ttype>$ = begin_for_stmt (); }
'(' for.init.statement
- { emit_nop ();
- emit_line_note (input_filename, lineno);
- expand_start_loop_continue_elsewhere (1); }
- .pushlevel xcond ';'
- { emit_line_note (input_filename, lineno);
- if ($7) expand_exit_loop_if_false (0, $7); }
+ { finish_for_init_stmt ($<ttype>2); }
+ xcond ';'
+ { finish_for_cond ($6, $<ttype>2); }
xexpr ')'
- /* Don't let the tree nodes for $10 be discarded
- by clear_momentary during the parsing of the next stmt. */
- { push_momentary (); }
- already_scoped_stmt .poplevel
- { emit_line_note (input_filename, lineno);
- expand_loop_continue_here ();
- if ($10) cplus_expand_expr_stmt ($10);
- pop_momentary ();
- expand_end_loop ();
- if (flag_new_for_scope > 0)
- {
- expand_end_bindings (getdecls (), kept_level_p (), 1);
- poplevel (kept_level_p (), 1, 0);
- pop_momentary ();
- }
- finish_stmt (); }
- | SWITCH .pushlevel '(' condition ')'
- { emit_line_note (input_filename, lineno);
- c_expand_start_case ($4);
- push_switch ();
- /* Don't let the tree nodes for $4 be discarded by
- clear_momentary during the parsing of the next stmt. */
- push_momentary (); }
+ { finish_for_expr ($9, $<ttype>2); }
+ already_scoped_stmt
+ { finish_for_stmt ($9, $<ttype>2); }
+ | SWITCH
+ { begin_switch_stmt (); }
+ '(' condition ')'
+ { $<ttype>$ = finish_switch_cond ($4); }
implicitly_scoped_stmt
- { expand_end_case ($4);
- pop_momentary ();
- pop_switch (); }
- .poplevel
- { finish_stmt (); }
+ { finish_switch_stmt ($4, $<ttype>6); }
| CASE expr_no_commas ':'
- { register tree value = check_cp_case_value ($2);
- register tree label
- = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
- if (value != error_mark_node)
- {
- tree duplicate;
- int success = pushcase (value, convert_and_check,
- label, &duplicate);
- if (success == 1)
- cp_error ("case label `%E' not within a switch statement", $2);
- else if (success == 2)
- {
- cp_error ("duplicate case value `%E'", $2);
- cp_error_at ("previously used here", duplicate);
- }
- else if (success == 3)
- warning ("case value out of range");
- else if (success == 5)
- cp_error ("case label `%E' within scope of cleanup or variable array", $2);
- }
- define_case_label (label);
- }
+ { finish_case_label ($2, NULL_TREE); }
stmt
| CASE expr_no_commas ELLIPSIS expr_no_commas ':'
- { register tree value1 = check_cp_case_value ($2);
- register tree value2 = check_cp_case_value ($4);
- register tree label
- = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-
- if (pedantic)
- pedwarn ("ANSI C++ forbids range expressions in switch statement");
- if (value1 != error_mark_node
- && value2 != error_mark_node)
- {
- tree duplicate;
- int success = pushcase_range (value1, value2,
- convert_and_check, label,
- &duplicate);
- if (success == 1)
- error ("case label not within a switch statement");
- else if (success == 2)
- {
- error ("duplicate (or overlapping) case value");
- error_with_decl (duplicate, "this is the first entry overlapping that value");
- }
- else if (success == 3)
- warning ("case value out of range");
- else if (success == 4)
- warning ("empty range specified");
- else if (success == 5)
- error ("case label within scope of cleanup or variable array");
- }
- define_case_label (label);
- }
+ { finish_case_label ($2, $4); }
stmt
| DEFAULT ':'
- {
- tree duplicate;
- register tree label
- = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
- int success = pushcase (NULL_TREE, 0, label, &duplicate);
- if (success == 1)
- error ("default label not within a switch statement");
- else if (success == 2)
- {
- error ("multiple default labels in one switch");
- error_with_decl (duplicate, "this is the first default label");
- }
- define_case_label (NULL_TREE);
- }
+ { finish_case_label (NULL_TREE, NULL_TREE); }
stmt
| BREAK ';'
- { emit_line_note (input_filename, lineno);
- if ( ! expand_exit_something ())
- error ("break statement not within loop or switch"); }
+ { finish_break_stmt (); }
| CONTINUE ';'
- { emit_line_note (input_filename, lineno);
- if (! expand_continue_loop (0))
- error ("continue statement not within a loop"); }
+ { finish_continue_stmt (); }
| RETURN ';'
- { emit_line_note (input_filename, lineno);
- c_expand_return (NULL_TREE); }
+ { finish_return_stmt (NULL_TREE); }
| RETURN expr ';'
- { emit_line_note (input_filename, lineno);
- c_expand_return ($2);
- finish_stmt ();
- }
- | asm_keyword maybe_type_qual '(' string ')' ';'
- { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
- emit_line_note (input_filename, lineno);
- expand_asm ($4);
- finish_stmt ();
+ { finish_return_stmt ($2); }
+ | asm_keyword maybe_cv_qualifier '(' string ')' ';'
+ {
+ finish_asm_stmt ($2, $4, NULL_TREE, NULL_TREE,
+ NULL_TREE);
}
/* This is the case with just output operands. */
- | asm_keyword maybe_type_qual '(' string ':' asm_operands ')' ';'
- { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
- emit_line_note (input_filename, lineno);
- c_expand_asm_operands ($4, $6, NULL_TREE, NULL_TREE,
- $2 == ridpointers[(int)RID_VOLATILE],
- input_filename, lineno);
- finish_stmt ();
+ | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ')' ';'
+ {
+ finish_asm_stmt ($2, $4, $6, NULL_TREE,
+ NULL_TREE);
}
/* This is the case with input operands as well. */
- | asm_keyword maybe_type_qual '(' string ':' asm_operands ':' asm_operands ')' ';'
- { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
- emit_line_note (input_filename, lineno);
- c_expand_asm_operands ($4, $6, $8, NULL_TREE,
- $2 == ridpointers[(int)RID_VOLATILE],
- input_filename, lineno);
- finish_stmt ();
- }
+ | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':' asm_operands ')' ';'
+ { finish_asm_stmt ($2, $4, $6, $8, NULL_TREE); }
/* This is the case with clobbered registers as well. */
- | asm_keyword maybe_type_qual '(' string ':' asm_operands ':'
+ | asm_keyword maybe_cv_qualifier '(' string ':' asm_operands ':'
asm_operands ':' asm_clobbers ')' ';'
- { if (TREE_CHAIN ($4)) $4 = combine_strings ($4);
- emit_line_note (input_filename, lineno);
- c_expand_asm_operands ($4, $6, $8, $10,
- $2 == ridpointers[(int)RID_VOLATILE],
- input_filename, lineno);
- finish_stmt ();
- }
+ { finish_asm_stmt ($2, $4, $6, $8, $10); }
| GOTO '*' expr ';'
- { emit_line_note (input_filename, lineno);
- expand_computed_goto ($3); }
+ {
+ if (pedantic)
+ pedwarn ("ANSI C++ forbids computed gotos");
+ finish_goto_stmt ($3);
+ }
| GOTO identifier ';'
- { tree decl;
- emit_line_note (input_filename, lineno);
- decl = lookup_label ($2);
- TREE_USED (decl) = 1;
- expand_goto (decl); }
+ { finish_goto_stmt ($2); }
| label_colon stmt
{ finish_stmt (); }
| label_colon '}'
@@ -3463,6 +3309,10 @@ simple_stmt:
| ';'
{ finish_stmt (); }
| try_block
+ | using_directive
+ | namespace_using_decl
+ { do_local_using_decl ($1); }
+ | namespace_alias
;
function_try_block:
@@ -3472,40 +3322,45 @@ function_try_block:
store_parm_decls ();
expand_start_early_try_stmts ();
}
- ctor_initializer_opt compstmt_or_error
- { expand_end_try_stmts ();
- expand_start_all_catch (); }
+ ctor_initializer_opt compstmt
+ {
+ expand_start_all_catch ();
+ }
handler_seq
{
+ int nested = (hack_decl_function_context
+ (current_function_decl) != NULL_TREE);
expand_end_all_catch ();
- finish_function (lineno, (int)$3, 0);
+ finish_function (lineno, (int)$3, nested);
}
;
try_block:
TRY
- { expand_start_try_stmts (); }
+ { $<ttype>$ = begin_try_block (); }
compstmt
- { expand_end_try_stmts ();
- expand_start_all_catch (); }
+ { finish_try_block ($<ttype>2); }
handler_seq
- { expand_end_all_catch (); }
+ { finish_handler_sequence ($<ttype>2); }
;
handler_seq:
- /* empty */
- | handler_seq CATCH .pushlevel
- { dont_allow_type_definitions = "inside exception declarations"; }
- handler_args
- { dont_allow_type_definitions = 0; }
+ handler
+ | handler_seq handler
+ ;
+
+handler:
+ CATCH
+ { $<ttype>$ = begin_handler(); }
+ handler_args
+ { finish_handler_parms ($<ttype>2); }
compstmt
- { expand_end_catch_block (); }
- .poplevel
+ { finish_handler ($<ttype>2); }
;
type_specifier_seq:
- typed_typespecs %prec EMPTY
- | nonempty_type_quals %prec EMPTY
+ typed_typespecs %prec EMPTY
+ | nonempty_cv_qualifiers %prec EMPTY
;
handler_args:
@@ -3513,17 +3368,22 @@ handler_args:
{ expand_start_catch_block (NULL_TREE, NULL_TREE); }
/* This doesn't allow reference parameters, the below does.
| '(' type_specifier_seq absdcl ')'
- { expand_start_catch_block ($2, $3); }
+ { check_for_new_type ("inside exception declarations", $2);
+ expand_start_catch_block ($2.t, $3); }
| '(' type_specifier_seq ')'
- { expand_start_catch_block ($2, NULL_TREE); }
+ { check_for_new_type ("inside exception declarations", $2);
+ expand_start_catch_block ($2.t, NULL_TREE); }
| '(' type_specifier_seq notype_declarator ')'
- { expand_start_catch_block ($2, $3); }
+ { check_for_new_type ("inside exception declarations", $2);
+ expand_start_catch_block ($2.t, $3); }
| '(' typed_typespecs after_type_declarator ')'
- { expand_start_catch_block ($2, $3); }
- This allows reference parameters... */
+ { check_for_new_type ("inside exception declarations", $2);
+ expand_start_catch_block ($2.t, $3); }
+ This allows reference parameters... */
| '(' parm ')'
- { expand_start_catch_block (TREE_PURPOSE ($2),
- TREE_VALUE ($2)); }
+ { check_for_new_type ("inside exception declarations", $2);
+ expand_start_catch_block (TREE_PURPOSE ($2.t),
+ TREE_VALUE ($2.t)); }
;
label_colon:
@@ -3531,13 +3391,15 @@ label_colon:
{ tree label;
do_label:
label = define_label (input_filename, lineno, $1);
- if (label)
+ if (label && ! minimal_parse_mode)
expand_label (label);
}
| PTYPENAME ':'
{ goto do_label; }
| TYPENAME ':'
{ goto do_label; }
+ | SELFNAME ':'
+ { goto do_label; }
;
for.init.statement:
@@ -3545,20 +3407,23 @@ for.init.statement:
{ if ($1) cplus_expand_expr_stmt ($1); }
| decl
| '{' compstmtend
+ { if (pedantic)
+ pedwarn ("ANSI C++ forbids compound statements inside for initializations");
+ }
;
/* Either a type-qualifier or nothing. First thing in an `asm' statement. */
-maybe_type_qual:
- /* empty */
+maybe_cv_qualifier:
+ /* empty */
{ emit_line_note (input_filename, lineno);
$$ = NULL_TREE; }
- | TYPE_QUAL
+ | CV_QUALIFIER
{ emit_line_note (input_filename, lineno); }
;
xexpr:
- /* empty */
+ /* empty */
{ $$ = NULL_TREE; }
| expr
| error
@@ -3567,7 +3432,8 @@ xexpr:
/* These are the operands other than the first string and colon
in asm ("addextend %2,%1": "=dm" (x), "0" (y), "g" (*x)) */
-asm_operands: /* empty */
+asm_operands:
+ /* empty */
{ $$ = NULL_TREE; }
| nonnull_asm_operands
;
@@ -3596,69 +3462,39 @@ asm_clobbers:
In C++, declaring a function with no parameters
means that that function takes *no* parameters. */
-parmlist: /* empty */
+parmlist:
+ /* empty */
{
- if (strict_prototype)
- $$ = void_list_node;
- else
- $$ = NULL_TREE;
+ $$ = empty_parms();
}
| complex_parmlist
| type_id
- { $$ = tree_cons (NULL_TREE, $$, void_list_node);
- TREE_PARMLIST ($$) = 1; }
+ { $$ = finish_parmlist (build_tree_list (NULL_TREE, $1.t), 0);
+ check_for_new_type ("inside parameter list", $1); }
;
/* This nonterminal does not include the common sequence '(' type_id ')',
as it is ambiguous and must be disambiguated elsewhere. */
complex_parmlist:
parms
- {
- $$ = chainon ($$, void_list_node);
- TREE_PARMLIST ($$) = 1;
- }
+ { $$ = finish_parmlist ($$, 0); }
| parms_comma ELLIPSIS
- {
- TREE_PARMLIST ($$) = 1;
- }
+ { $$ = finish_parmlist ($1, 1); }
/* C++ allows an ellipsis without a separating ',' */
| parms ELLIPSIS
- {
- TREE_PARMLIST ($$) = 1;
- }
+ { $$ = finish_parmlist ($1, 1); }
| type_id ELLIPSIS
- {
- $$ = build_tree_list (NULL_TREE, $$);
- TREE_PARMLIST ($$) = 1;
- }
+ { $$ = finish_parmlist (build_tree_list (NULL_TREE,
+ $1.t), 1); }
| ELLIPSIS
- {
- /* ARM $8.2.5 has this as a boxed-off comment. */
- if (pedantic)
- warning ("use of `...' without a first argument is non-portable");
- $$ = NULL_TREE;
- }
- | TYPENAME_ELLIPSIS
- {
- TREE_PARMLIST ($$) = 1;
- }
- | parms TYPENAME_ELLIPSIS
- {
- TREE_PARMLIST ($$) = 1;
- }
- | type_id TYPENAME_ELLIPSIS
- {
- $$ = build_tree_list (NULL_TREE, $$);
- TREE_PARMLIST ($$) = 1;
- }
+ { $$ = finish_parmlist (NULL_TREE, 1); }
| parms ':'
{
/* This helps us recover from really nasty
parse errors, for example, a missing right
parenthesis. */
yyerror ("possibly missing ')'");
- $$ = chainon ($$, void_list_node);
- TREE_PARMLIST ($$) = 1;
+ $$ = finish_parmlist ($1, 0);
yyungetc (':', 0);
yychar = ')';
}
@@ -3668,21 +3504,37 @@ complex_parmlist:
parse errors, for example, a missing right
parenthesis. */
yyerror ("possibly missing ')'");
- $$ = tree_cons (NULL_TREE, $$, void_list_node);
- TREE_PARMLIST ($$) = 1;
+ $$ = finish_parmlist (build_tree_list (NULL_TREE,
+ $1.t), 0);
yyungetc (':', 0);
yychar = ')';
}
;
+/* A default argument to a */
+defarg:
+ '='
+ { maybe_snarf_defarg (); }
+ defarg1
+ { $$ = $3; }
+ ;
+
+defarg1:
+ DEFARG
+ | init
+ ;
+
/* A nonempty list of parameter declarations or type names. */
parms:
named_parm
- { $$ = build_tree_list (NULL_TREE, $$); }
- | parm '=' init
- { $$ = build_tree_list ($3, $$); }
+ { check_for_new_type ("in a parameter list", $1);
+ $$ = build_tree_list (NULL_TREE, $1.t); }
+ | parm defarg
+ { check_for_new_type ("in a parameter list", $1);
+ $$ = build_tree_list ($2, $1.t); }
| parms_comma full_parm
- { $$ = chainon ($$, $2); }
+ { check_for_new_type ("in a parameter list", $2);
+ $$ = chainon ($$, $2.t); }
| parms_comma bad_parm
{ $$ = chainon ($$, build_tree_list (NULL_TREE, $2)); }
| parms_comma bad_parm '=' init
@@ -3692,80 +3544,58 @@ parms:
parms_comma:
parms ','
| type_id ','
- { $$ = build_tree_list (NULL_TREE, $$); }
+ { check_for_new_type ("in a parameter list", $1);
+ $$ = build_tree_list (NULL_TREE, $1.t); }
;
/* A single parameter declaration or parameter type name,
- as found in a parmlist. The first four cases make up for 10%
- of the time spent parsing C++. We cannot use them because
- of `int id[]' which won't get parsed properly. */
+ as found in a parmlist. */
named_parm:
-/*
- typed_declspecs dont_see_typename '*' IDENTIFIER
- { tree specs = strip_attrs ($1);
- $$ = build_tree_list (specs, build_parse_node (INDIRECT_REF, $4));
- see_typename (); }
- | typed_declspecs dont_see_typename '&' IDENTIFIER
- { tree specs = strip_attrs ($1);
- $$ = build_tree_list (specs, build_parse_node (ADDR_EXPR, $4));
- see_typename (); }
- | TYPENAME IDENTIFIER
- { $$ = build_tree_list (get_decl_list ($$), $2); }
- | TYPESPEC IDENTIFIER
- { $$ = build_tree_list (get_decl_list ($$), $2); }
- | */
/* Here we expand typed_declspecs inline to avoid mis-parsing of
TYPESPEC IDENTIFIER. */
typed_declspecs1 declarator
- { tree specs = strip_attrs ($1);
- $$ = build_tree_list (specs, $2); }
+ { tree specs = strip_attrs ($1.t);
+ $$.new_type_flag = $1.new_type_flag;
+ $$.t = build_tree_list (specs, $2); }
| typed_typespecs declarator
- { $$ = build_tree_list ($$, $2); }
+ { $$.t = build_tree_list ($1.t, $2);
+ $$.new_type_flag = $1.new_type_flag; }
| typespec declarator
- { $$ = build_tree_list (get_decl_list ($$), $2); }
+ { $$.t = build_tree_list (get_decl_list ($1.t), $2);
+ $$.new_type_flag = $1.new_type_flag; }
| typed_declspecs1 absdcl
- { tree specs = strip_attrs ($1);
- $$ = build_tree_list (specs, $2); }
- | typed_declspecs1 %prec EMPTY
- { tree specs = strip_attrs ($1);
- $$ = build_tree_list (specs, NULL_TREE); }
+ { tree specs = strip_attrs ($1.t);
+ $$.t = build_tree_list (specs, $2);
+ $$.new_type_flag = $1.new_type_flag; }
+ | typed_declspecs1 %prec EMPTY
+ { tree specs = strip_attrs ($1.t);
+ $$.t = build_tree_list (specs, NULL_TREE);
+ $$.new_type_flag = $1.new_type_flag; }
| declmods notype_declarator
{ tree specs = strip_attrs ($1);
- $$ = build_tree_list (specs, $2); }
+ $$.t = build_tree_list (specs, $2);
+ $$.new_type_flag = 0; }
;
full_parm:
- parm maybe_init
- { $$ = build_tree_list ($2, $$); }
+ parm
+ { $$.t = build_tree_list (NULL_TREE, $1.t);
+ $$.new_type_flag = $1.new_type_flag; }
+ | parm defarg
+ { $$.t = build_tree_list ($2, $1.t);
+ $$.new_type_flag = $1.new_type_flag; }
;
parm:
- named_parm
+ named_parm
| type_id
;
-see_typename: %prec EMPTY
- { see_typename (); }
+see_typename:
+ /* empty */ %prec EMPTY
+ { see_typename (); }
;
-/*
-dont_see_typename: %prec EMPTY
- { dont_see_typename (); }
- ;
-
-try_for_typename:
- {
- if ($<ttype>-1 == error_mark_node)
- $$ = 0;
- else
- {
- $$ = 1;
- pushclass ($<ttype>-1, 1);
- }
- }
- ;
-*/
-
bad_parm:
/* empty */ %prec EMPTY
{
@@ -3775,22 +3605,26 @@ bad_parm:
| notype_declarator
{
error ("type specifier omitted for parameter");
+ if (TREE_CODE ($$) == SCOPE_REF
+ && (TREE_CODE (TREE_OPERAND ($$, 0)) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (TREE_OPERAND ($$, 0)) == TEMPLATE_TEMPLATE_PARM))
+ cp_error (" perhaps you want `typename %E' to make it a type", $$);
$$ = build_tree_list (integer_type_node, $$);
}
;
exception_specification_opt:
- %prec EMPTY /* empty */
+ /* empty */ %prec EMPTY
{ $$ = NULL_TREE; }
- | THROW '(' ansi_raise_identifiers ')' %prec EMPTY
+ | THROW '(' ansi_raise_identifiers ')' %prec EMPTY
{ $$ = $3; }
- | THROW LEFT_RIGHT %prec EMPTY
+ | THROW LEFT_RIGHT %prec EMPTY
{ $$ = build_decl_list (NULL_TREE, NULL_TREE); }
;
ansi_raise_identifier:
type_id
- { $$ = build_decl_list (NULL_TREE, groktypename($$)); }
+ { $$ = build_decl_list (NULL_TREE, groktypename($1.t)); }
;
ansi_raise_identifiers:
@@ -3803,19 +3637,20 @@ ansi_raise_identifiers:
;
conversion_declarator:
- /* empty */ %prec EMPTY
+ /* empty */ %prec EMPTY
{ $$ = NULL_TREE; }
- | '*' type_quals conversion_declarator
+ | '*' cv_qualifiers conversion_declarator
{ $$ = make_pointer_declarator ($2, $3); }
- | '&' type_quals conversion_declarator
+ | '&' cv_qualifiers conversion_declarator
{ $$ = make_reference_declarator ($2, $3); }
- | ptr_to_mem type_quals conversion_declarator
+ | ptr_to_mem cv_qualifiers conversion_declarator
{ tree arg = make_pointer_declarator ($2, $3);
$$ = build_parse_node (SCOPE_REF, $1, arg);
}
;
-operator: OPERATOR
+operator:
+ OPERATOR
{ got_scope = NULL_TREE; }
;
@@ -3878,9 +3713,9 @@ operator_name:
{ $$ = ansi_opname[CALL_EXPR]; }
| operator '[' ']'
{ $$ = ansi_opname[ARRAY_REF]; }
- | operator NEW %prec EMPTY
+ | operator NEW %prec EMPTY
{ $$ = ansi_opname[NEW_EXPR]; }
- | operator DELETE %prec EMPTY
+ | operator DELETE %prec EMPTY
{ $$ = ansi_opname[DELETE_EXPR]; }
| operator NEW '[' ']'
{ $$ = ansi_opname[VEC_NEW_EXPR]; }
@@ -3888,7 +3723,7 @@ operator_name:
{ $$ = ansi_opname[VEC_DELETE_EXPR]; }
/* Names here should be looked up in class scope ALSO. */
| operator type_specifier_seq conversion_declarator
- { $$ = grokoptypename ($2, $3); }
+ { $$ = grokoptypename ($2.t, $3); }
| operator error
{ $$ = ansi_opname[ERROR_MARK]; }
;
diff --git a/contrib/gcc/cp/pt.c b/contrib/gcc/cp/pt.c
index 3ce0224..556b761 100644
--- a/contrib/gcc/cp/pt.c
+++ b/contrib/gcc/cp/pt.c
@@ -1,6 +1,7 @@
/* Handle parameterized types (templates) for GNU C++.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
Written by Ken Raeburn (raeburn@cygnus.com) while at Watchmaker Computing.
+ Rewritten by Jason Merrill (jason@cygnus.com).
This file is part of GNU CC.
@@ -20,17 +21,12 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Known bugs or deficiencies include:
- * templates for class static data don't work (methods only)
- * duplicated method templates can crash the compiler
- * interface/impl data is taken from file defining the template
- * all methods must be provided in header files; can't use a source
- file that contains only the method templates and "just win"
- * method templates must be seen before the expansion of the
- class template is done
- */
+
+ all methods must be provided in header files; can't use a source
+ file that contains only the method templates and "just win". */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "obstack.h"
#include "tree.h"
@@ -41,6 +37,12 @@ Boston, MA 02111-1307, USA. */
#include "lex.h"
#include "output.h"
#include "defaults.h"
+#include "except.h"
+#include "toplev.h"
+
+/* The type of functions taking a tree, and some additional data, and
+ returning an int. */
+typedef int (*tree_fn_t) PROTO((tree, void*));
extern struct obstack permanent_obstack;
@@ -48,40 +50,1348 @@ extern int lineno;
extern char *input_filename;
struct pending_inline *pending_template_expansions;
-int processing_template_decl;
-int processing_template_defn;
+tree current_template_parms;
+HOST_WIDE_INT processing_template_decl;
+
+tree pending_templates;
+static tree *template_tail = &pending_templates;
+
+tree maybe_templates;
+static tree *maybe_template_tail = &maybe_templates;
+
+int minimal_parse_mode;
-/* This is a kludge to handle instantiation of template methods that are
- used before their definition. It should not be necessary after the
- template rewrite. */
-static tree template_classes;
+int processing_specialization;
+int processing_explicit_instantiation;
+int processing_template_parmlist;
+static int template_header_count;
+
+static tree saved_trees;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-static int unify ();
-static void add_pending_template ();
+#define UNIFY_ALLOW_NONE 0
+#define UNIFY_ALLOW_MORE_CV_QUAL 1
+#define UNIFY_ALLOW_LESS_CV_QUAL 2
+#define UNIFY_ALLOW_DERIVED 4
+
+static int unify PROTO((tree, tree, tree, tree, int, int*));
+static void add_pending_template PROTO((tree));
+static int push_tinst_level PROTO((tree));
+static tree classtype_mangled_name PROTO((tree));
+static char *mangle_class_name_for_template PROTO((char *, tree, tree, tree));
+static tree tsubst_expr_values PROTO((tree, tree));
+static int list_eq PROTO((tree, tree));
+static tree get_class_bindings PROTO((tree, tree, tree, tree));
+static tree coerce_template_parms PROTO((tree, tree, tree, int, int));
+static tree tsubst_enum PROTO((tree, tree, tree *));
+static tree add_to_template_args PROTO((tree, tree));
+static void maybe_adjust_types_for_deduction PROTO((unification_kind_t, tree*,
+ tree*));
+static int type_unification_real PROTO((tree, tree, tree, tree,
+ int, unification_kind_t, int, int*));
+static tree complete_template_args PROTO((tree, tree, int));
+static void note_template_header PROTO((int));
+static tree maybe_fold_nontype_arg PROTO((tree));
+static tree convert_nontype_argument PROTO((tree, tree));
+static tree get_bindings_overload PROTO((tree, tree, tree));
+static int for_each_template_parm PROTO((tree, tree_fn_t, void*));
+static tree build_template_parm_index PROTO((int, int, int, tree, tree));
+static tree original_template PROTO((tree));
+static int inline_needs_template_parms PROTO((tree));
+static void push_inline_template_parms_recursive PROTO((tree, int));
+static tree retrieve_specialization PROTO((tree, tree));
+static void register_specialization PROTO((tree, tree, tree));
+static void print_candidates PROTO((tree));
+static tree reduce_template_parm_level PROTO((tree, tree, int));
+static tree build_template_decl PROTO((tree, tree));
+static int mark_template_parm PROTO((tree, void *));
+static tree tsubst_friend_function PROTO((tree, tree));
+static tree tsubst_friend_class PROTO((tree, tree));
+static tree get_bindings_real PROTO((tree, tree, tree, int));
+static int template_decl_level PROTO((tree));
+static tree maybe_get_template_decl_from_type_decl PROTO((tree));
+static int check_cv_quals_for_unify PROTO((int, tree, tree));
+static tree tsubst_template_arg_vector PROTO((tree, tree));
+static void regenerate_decl_from_template PROTO((tree, tree));
+static int is_member_template_class PROTO((tree));
+
+/* Nonzero if ARGVEC contains multiple levels of template arguments. */
+#define TMPL_ARGS_HAVE_MULTIPLE_LEVELS(NODE) \
+ (NODE != NULL_TREE \
+ && TREE_CODE (NODE) == TREE_VEC \
+ && TREE_VEC_LENGTH (NODE) > 0 \
+ && TREE_VEC_ELT (NODE, 0) != NULL_TREE \
+ && TREE_CODE (TREE_VEC_ELT (NODE, 0)) == TREE_VEC)
+
+/* Do any processing required when DECL (a member template declaration
+ using TEMPLATE_PARAMETERS as its innermost parameter list) is
+ finished. Returns the TEMPLATE_DECL corresponding to DECL, unless
+ it is a specialization, in which case the DECL itself is returned. */
+
+tree
+finish_member_template_decl (template_parameters, decl)
+ tree template_parameters;
+ tree decl;
+{
+ if (template_parameters)
+ end_template_decl ();
+ else
+ end_specialization ();
+
+ if (decl == NULL_TREE || decl == void_type_node)
+ return NULL_TREE;
+ else if (TREE_CODE (decl) == TREE_LIST)
+ {
+ /* Assume that the class is the only declspec. */
+ decl = TREE_VALUE (decl);
+ if (IS_AGGR_TYPE (decl) && CLASSTYPE_TEMPLATE_INFO (decl)
+ && ! CLASSTYPE_TEMPLATE_SPECIALIZATION (decl))
+ {
+ tree tmpl = CLASSTYPE_TI_TEMPLATE (decl);
+ check_member_template (tmpl);
+ return tmpl;
+ }
+ return NULL_TREE;
+ }
+ else if (DECL_TEMPLATE_INFO (decl))
+ {
+ if (!DECL_TEMPLATE_SPECIALIZATION (decl))
+ {
+ check_member_template (DECL_TI_TEMPLATE (decl));
+ return DECL_TI_TEMPLATE (decl);
+ }
+ else
+ return decl;
+ }
+ else
+ cp_error ("invalid member template declaration `%D'", decl);
+
+
+ return error_mark_node;
+}
+
+/* Returns the template nesting level of the indicated class TYPE.
+
+ For example, in:
+ template <class T>
+ struct A
+ {
+ template <class U>
+ struct B {};
+ };
+
+ A<T>::B<U> has depth two, while A<T> has depth one. Also,
+ both A<T>::B<int> and A<int>::B<U> have depth one. */
+
+int
+template_class_depth (type)
+ tree type;
+{
+ int depth;
+
+ for (depth = 0;
+ type && TREE_CODE (type) != FUNCTION_DECL
+ && TREE_CODE (type) != NAMESPACE_DECL;
+ type = TYPE_CONTEXT (type))
+ if (CLASSTYPE_TEMPLATE_INFO (type)
+ && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
+ && uses_template_parms (CLASSTYPE_TI_ARGS (type)))
+ ++depth;
+
+ return depth;
+}
+
+/* Return the original template for this decl, disregarding any
+ specializations. */
+
+static tree
+original_template (decl)
+ tree decl;
+{
+ while (DECL_TEMPLATE_INFO (decl))
+ decl = DECL_TI_TEMPLATE (decl);
+ return decl;
+}
+
+/* Returns 1 if processing DECL as part of do_pending_inlines
+ needs us to push template parms. */
-void overload_template_name (), pop_template_decls ();
+static int
+inline_needs_template_parms (decl)
+ tree decl;
+{
+ if (! DECL_TEMPLATE_INFO (decl))
+ return 0;
+
+ return (list_length (DECL_TEMPLATE_PARMS (original_template (decl)))
+ > (processing_template_decl + DECL_TEMPLATE_SPECIALIZATION (decl)));
+}
+
+/* Subroutine of maybe_begin_member_template_processing.
+ Push the template parms in PARMS, starting from LEVELS steps into the
+ chain, and ending at the beginning, since template parms are listed
+ innermost first. */
+
+static void
+push_inline_template_parms_recursive (parmlist, levels)
+ tree parmlist;
+ int levels;
+{
+ tree parms = TREE_VALUE (parmlist);
+ int i;
+
+ if (levels > 1)
+ push_inline_template_parms_recursive (TREE_CHAIN (parmlist), levels - 1);
+
+ ++processing_template_decl;
+ current_template_parms
+ = tree_cons (build_int_2 (0, processing_template_decl),
+ parms, current_template_parms);
+ TEMPLATE_PARMS_FOR_INLINE (current_template_parms) = 1;
+
+ pushlevel (0);
+ for (i = 0; i < TREE_VEC_LENGTH (parms); ++i)
+ {
+ tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
+ my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (parm)) == 'd', 0);
+
+ switch (TREE_CODE (parm))
+ {
+ case TYPE_DECL:
+ case TEMPLATE_DECL:
+ pushdecl (parm);
+ break;
+
+ case PARM_DECL:
+ {
+ /* Make a CONST_DECL as is done in process_template_parm. */
+ tree decl = build_decl (CONST_DECL, DECL_NAME (parm),
+ TREE_TYPE (parm));
+ DECL_INITIAL (decl) = DECL_INITIAL (parm);
+ pushdecl (decl);
+ }
+ break;
+
+ default:
+ my_friendly_abort (0);
+ }
+ }
+}
+
+/* Restore the template parameter context for a member template or
+ a friend template defined in a class definition. */
+
+void
+maybe_begin_member_template_processing (decl)
+ tree decl;
+{
+ tree parms;
+ int levels;
+
+ if (! inline_needs_template_parms (decl))
+ return;
+
+ parms = DECL_TEMPLATE_PARMS (original_template (decl));
+
+ levels = list_length (parms) - processing_template_decl;
+
+ if (DECL_TEMPLATE_SPECIALIZATION (decl))
+ {
+ --levels;
+ parms = TREE_CHAIN (parms);
+ }
+
+ push_inline_template_parms_recursive (parms, levels);
+}
+
+/* Undo the effects of begin_member_template_processing. */
+
+void
+maybe_end_member_template_processing (decl)
+ tree decl;
+{
+ if (! processing_template_decl)
+ return;
+
+ while (current_template_parms
+ && TEMPLATE_PARMS_FOR_INLINE (current_template_parms))
+ {
+ --processing_template_decl;
+ current_template_parms = TREE_CHAIN (current_template_parms);
+ poplevel (0, 0, 0);
+ }
+}
+
+/* Returns non-zero iff T is a member template function. We must be
+ careful as in
+
+ template <class T> class C { void f(); }
+
+ Here, f is a template function, and a member, but not a member
+ template. This function does not concern itself with the origin of
+ T, only its present state. So if we have
+
+ template <class T> class C { template <class U> void f(U); }
+
+ then neither C<int>::f<char> nor C<T>::f<double> is considered
+ to be a member template. */
+
+int
+is_member_template (t)
+ tree t;
+{
+ if (TREE_CODE (t) != FUNCTION_DECL
+ && !DECL_FUNCTION_TEMPLATE_P (t))
+ /* Anything that isn't a function or a template function is
+ certainly not a member template. */
+ return 0;
+
+ /* A local class can't have member templates. */
+ if (hack_decl_function_context (t))
+ return 0;
+
+ if ((DECL_FUNCTION_MEMBER_P (t)
+ && !DECL_TEMPLATE_SPECIALIZATION (t))
+ || (TREE_CODE (t) == TEMPLATE_DECL
+ && DECL_FUNCTION_MEMBER_P (DECL_TEMPLATE_RESULT (t))))
+ {
+ tree tmpl;
+
+ if (DECL_FUNCTION_TEMPLATE_P (t))
+ tmpl = t;
+ else if (DECL_TEMPLATE_INFO (t)
+ && DECL_FUNCTION_TEMPLATE_P (DECL_TI_TEMPLATE (t)))
+ tmpl = DECL_TI_TEMPLATE (t);
+ else
+ tmpl = NULL_TREE;
+
+ if (tmpl
+ /* If there are more levels of template parameters than
+ there are template classes surrounding the declaration,
+ then we have a member template. */
+ && (list_length (DECL_TEMPLATE_PARMS (tmpl)) >
+ template_class_depth (DECL_CLASS_CONTEXT (t))))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Returns non-zero iff T is a member template class. See
+ is_member_template for a description of what precisely constitutes
+ a member template. */
+
+int
+is_member_template_class (t)
+ tree t;
+{
+ if (!DECL_CLASS_TEMPLATE_P (t))
+ /* Anything that isn't a class template, is certainly not a member
+ template. */
+ return 0;
+
+ if (!DECL_CLASS_SCOPE_P (t))
+ /* Anything whose context isn't a class type is surely not a
+ member template. */
+ return 0;
+
+ /* If there are more levels of template parameters than there are
+ template classes surrounding the declaration, then we have a
+ member template. */
+ return (list_length (DECL_TEMPLATE_PARMS (t)) >
+ template_class_depth (DECL_CONTEXT (t)));
+}
+
+/* Return a new template argument vector which contains all of ARGS
+ for all outer templates TMPL is contained in, but has as its
+ innermost set of arguments the EXTRA_ARGS. If UNBOUND_ONLY, we
+ are only interested in unbound template arguments, not arguments from
+ enclosing templates that have been instantiated already. */
+
+static tree
+complete_template_args (tmpl, extra_args, unbound_only)
+ tree tmpl, extra_args;
+ int unbound_only;
+{
+ /* depth is the number of levels of enclosing args we're adding. */
+ int depth, i;
+ tree args, new_args, spec_args = NULL_TREE;
+ int extra_arg_depth;
+
+ my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
+ my_friendly_assert (TREE_CODE (extra_args) == TREE_VEC, 0);
+
+ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (extra_args))
+ extra_arg_depth = TREE_VEC_LENGTH (extra_args);
+ else
+ extra_arg_depth = 1;
+
+ if (DECL_TEMPLATE_INFO (tmpl) && !unbound_only)
+ {
+ /* A specialization of a member template of a template class shows up
+ as a TEMPLATE_DECL with DECL_TEMPLATE_SPECIALIZATION set.
+ DECL_TI_ARGS is the specialization args, and DECL_TI_TEMPLATE
+ is the template being specialized. */
+ if (DECL_TEMPLATE_SPECIALIZATION (tmpl))
+ {
+ spec_args = DECL_TI_ARGS (tmpl);
+ tmpl = DECL_TI_TEMPLATE (tmpl);
+ }
+
+ if (DECL_TEMPLATE_INFO (tmpl))
+ {
+ /* A partial instantiation of a member template shows up as a
+ TEMPLATE_DECL with DECL_TEMPLATE_INFO. DECL_TI_ARGS is
+ all the bound template arguments. */
+ args = DECL_TI_ARGS (tmpl);
+ if (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
+ depth = 1;
+ else
+ depth = TREE_VEC_LENGTH (args);
+ }
+ else
+ /* If we are a specialization, we might have no previously bound
+ template args. */
+ depth = 0;
+
+ new_args = make_tree_vec (depth + extra_arg_depth + (!!spec_args));
+
+ if (depth == 1)
+ TREE_VEC_ELT (new_args, 0) = args;
+ else
+ for (i = 0; i < depth; ++i)
+ TREE_VEC_ELT (new_args, i) = TREE_VEC_ELT (args, i);
+ }
+ else
+ {
+ tree type;
+ int skip;
+
+ /* For unbound args, we have to do more work. We are getting bindings
+ for the innermost args from extra_args, so we start from our
+ context and work out until we've seen all the args. We need to
+ do it this way to handle partial specialization. */
+
+ depth = list_length (DECL_TEMPLATE_PARMS (tmpl)) - 1;
+ if (depth == 0)
+ return extra_args;
+
+ new_args = make_tree_vec (depth + extra_arg_depth);
+
+ /* If this isn't a member template, extra_args is for the innermost
+ template class, so skip over it. */
+ skip = (! is_member_template (tmpl));
+
+ if (depth > skip)
+ {
+ type = DECL_REAL_CONTEXT (tmpl);
+ for (i = depth; i; type = TYPE_CONTEXT (type))
+ if (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type)))
+ {
+ if (skip)
+ skip = 0;
+ else
+ {
+ --i;
+ TREE_VEC_ELT (new_args, i) = CLASSTYPE_TI_ARGS (type);
+ }
+ }
+ }
+ }
+
+ if (extra_arg_depth == 1)
+ TREE_VEC_ELT (new_args, depth++) = extra_args;
+ else
+ for (i = 0; i < extra_arg_depth; ++i)
+ TREE_VEC_ELT (new_args, depth++) = TREE_VEC_ELT (extra_args, i);
+
+ if (spec_args)
+ TREE_VEC_ELT (new_args, depth) = spec_args;
+
+ return new_args;
+}
+
+/* Return a new template argument vector which contains all of ARGS,
+ but has as its innermost set of arguments the EXTRA_ARGS. */
+
+static tree
+add_to_template_args (args, extra_args)
+ tree args;
+ tree extra_args;
+{
+ tree new_args;
+
+ if (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
+ {
+ new_args = make_tree_vec (2);
+ TREE_VEC_ELT (new_args, 0) = args;
+ }
+ else
+ {
+ int i;
+
+ new_args = make_tree_vec (TREE_VEC_LENGTH (args) + 1);
+
+ for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
+ TREE_VEC_ELT (new_args, i) = TREE_VEC_ELT (args, i);
+ }
+
+ TREE_VEC_ELT (new_args,
+ TREE_VEC_LENGTH (new_args) - 1) = extra_args;
+
+ return new_args;
+}
+
+/* We've got a template header coming up; push to a new level for storing
+ the parms. */
-/* We've got a template header coming up; set obstacks up to save the
- nodes created permanently. (There might be cases with nested templates
- where we don't have to do this, but they aren't implemented, and it
- probably wouldn't be worth the effort.) */
void
begin_template_parm_list ()
{
+ /* We use a non-tag-transparent scope here, which causes pushtag to
+ put tags in this scope, rather than in the enclosing class or
+ namespace scope. This is the right thing, since we want
+ TEMPLATE_DECLS, and not TYPE_DECLS for template classes. For a
+ global template class, push_template_decl handles putting the
+ TEMPLATE_DECL into top-level scope. For a nested template class,
+ e.g.:
+
+ template <class T> struct S1 {
+ template <class T> struct S2 {};
+ };
+
+ pushtag contains special code to call pushdecl_with_scope on the
+ TEMPLATE_DECL for S2. */
pushlevel (0);
- push_obstacks (&permanent_obstack, &permanent_obstack);
- pushlevel (0);
+ declare_pseudo_global_level ();
+ ++processing_template_decl;
+ ++processing_template_parmlist;
+ note_template_header (0);
+}
+
+/* We've just seen template <>. */
+
+void
+begin_specialization ()
+{
+ note_template_header (1);
+}
+
+/* Called at then end of processing a declaration preceeded by
+ template<>. */
+
+void
+end_specialization ()
+{
+ reset_specialization ();
+}
+
+/* Any template <>'s that we have seen thus far are not referring to a
+ function specialization. */
+
+void
+reset_specialization ()
+{
+ processing_specialization = 0;
+ template_header_count = 0;
+}
+
+/* We've just seen a template header. If SPECIALIZATION is non-zero,
+ it was of the form template <>. */
+
+static void
+note_template_header (specialization)
+ int specialization;
+{
+ processing_specialization = specialization;
+ template_header_count++;
+}
+
+/* We're beginning an explicit instantiation. */
+
+void
+begin_explicit_instantiation ()
+{
+ ++processing_explicit_instantiation;
+}
+
+
+void
+end_explicit_instantiation ()
+{
+ my_friendly_assert(processing_explicit_instantiation > 0, 0);
+ --processing_explicit_instantiation;
+}
+
+/* Retrieve the specialization (in the sense of [temp.spec] - a
+ specialization is either an instantiation or an explicit
+ specialization) of TMPL for the given template ARGS. If there is
+ no such specialization, return NULL_TREE. The ARGS are a vector of
+ arguments, or a vector of vectors of arguments, in the case of
+ templates with more than one level of parameters. */
+
+static tree
+retrieve_specialization (tmpl, args)
+ tree tmpl;
+ tree args;
+{
+ tree s;
+
+ my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
+
+ for (s = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+ s != NULL_TREE;
+ s = TREE_CHAIN (s))
+ if (comp_template_args (TREE_PURPOSE (s), args))
+ return TREE_VALUE (s);
+
+ return NULL_TREE;
+}
+
+/* Returns non-zero iff DECL is a specialization of TMPL. */
+
+int
+is_specialization_of (decl, tmpl)
+ tree decl;
+ tree tmpl;
+{
+ tree t;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ for (t = decl;
+ t != NULL_TREE;
+ t = DECL_TEMPLATE_INFO (t) ? DECL_TI_TEMPLATE (t) : NULL_TREE)
+ if (t == tmpl)
+ return 1;
+ }
+ else
+ {
+ my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 0);
+
+ for (t = TREE_TYPE (decl);
+ t != NULL_TREE;
+ t = CLASSTYPE_USE_TEMPLATE (t)
+ ? TREE_TYPE (CLASSTYPE_TI_TEMPLATE (t)) : NULL_TREE)
+ if (comptypes (TYPE_MAIN_VARIANT (t),
+ TYPE_MAIN_VARIANT (TREE_TYPE (tmpl)), 1))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Register the specialization SPEC as a specialization of TMPL with
+ the indicated ARGS. */
+
+static void
+register_specialization (spec, tmpl, args)
+ tree spec;
+ tree tmpl;
+ tree args;
+{
+ tree s;
+
+ my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
+
+ if (TREE_CODE (spec) != TEMPLATE_DECL
+ && list_length (DECL_TEMPLATE_PARMS (tmpl)) > 1)
+ /* Avoid registering function declarations as
+ specializations of member templates, as would otherwise
+ happen with out-of-class specializations of member
+ templates. */
+ return;
+
+ for (s = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
+ s != NULL_TREE;
+ s = TREE_CHAIN (s))
+ if (comp_template_args (TREE_PURPOSE (s), args))
+ {
+ tree fn = TREE_VALUE (s);
+
+ if (DECL_TEMPLATE_SPECIALIZATION (spec))
+ {
+ if (DECL_TEMPLATE_INSTANTIATION (fn))
+ {
+ if (TREE_USED (fn)
+ || DECL_EXPLICIT_INSTANTIATION (fn))
+ {
+ cp_error ("specialization of %D after instantiation",
+ fn);
+ return;
+ }
+ else
+ {
+ /* This situation should occur only if the first
+ specialization is an implicit instantiation,
+ the second is an explicit specialization, and
+ the implicit instantiation has not yet been
+ used. That situation can occur if we have
+ implicitly instantiated a member function of
+ class type, and then specialized it later. */
+ TREE_VALUE (s) = spec;
+ return;
+ }
+ }
+ else if (DECL_TEMPLATE_SPECIALIZATION (fn))
+ {
+ if (DECL_INITIAL (fn))
+ cp_error ("duplicate specialization of %D", fn);
+
+ TREE_VALUE (s) = spec;
+ return;
+ }
+ }
+ }
+
+ DECL_TEMPLATE_SPECIALIZATIONS (tmpl)
+ = perm_tree_cons (args, spec, DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+}
+
+/* Print the list of candidate FNS in an error message. */
+
+static void
+print_candidates (fns)
+ tree fns;
+{
+ tree fn;
+
+ char* str = "candidates are:";
+
+ for (fn = fns; fn != NULL_TREE; fn = TREE_CHAIN (fn))
+ {
+ cp_error_at ("%s %+#D", str, TREE_VALUE (fn));
+ str = " ";
+ }
+}
+
+/* Returns the template (one of the functions given by TEMPLATE_ID)
+ which can be specialized to match the indicated DECL with the
+ explicit template args given in TEMPLATE_ID. If
+ NEED_MEMBER_TEMPLATE is true the function is a specialization of a
+ member template. The template args (those explicitly specified and
+ those deduced) are output in a newly created vector *TARGS_OUT. If
+ it is impossible to determine the result, an error message is
+ issued, unless COMPLAIN is 0. The DECL may be NULL_TREE if none is
+ available. */
+
+tree
+determine_specialization (template_id, decl, targs_out,
+ need_member_template,
+ complain)
+ tree template_id;
+ tree decl;
+ tree* targs_out;
+ int need_member_template;
+ int complain;
+{
+ tree fns, targs_in;
+ tree templates = NULL_TREE;
+ tree fn;
+ int i;
+
+ *targs_out = NULL_TREE;
+
+ if (template_id == error_mark_node)
+ return error_mark_node;
+
+ fns = TREE_OPERAND (template_id, 0);
+ targs_in = TREE_OPERAND (template_id, 1);
+
+ if (fns == error_mark_node)
+ return error_mark_node;
+
+ /* Check for baselinks. */
+ if (TREE_CODE (fns) == TREE_LIST)
+ fns = TREE_VALUE (fns);
+
+ for (; fns; fns = OVL_NEXT (fns))
+ {
+ tree tmpl;
+
+ fn = OVL_CURRENT (fns);
+ if (!need_member_template
+ && TREE_CODE (fn) == FUNCTION_DECL
+ && DECL_FUNCTION_MEMBER_P (fn)
+ && DECL_USE_TEMPLATE (fn)
+ && DECL_TI_TEMPLATE (fn))
+ /* We can get here when processing something like:
+ template <class T> class X { void f(); }
+ template <> void X<int>::f() {}
+ We're specializing a member function, but not a member
+ template. */
+ tmpl = DECL_TI_TEMPLATE (fn);
+ else if (TREE_CODE (fn) != TEMPLATE_DECL
+ || (need_member_template && !is_member_template (fn)))
+ continue;
+ else
+ tmpl = fn;
+
+ if (list_length (targs_in) > DECL_NTPARMS (tmpl))
+ continue;
+
+ if (decl == NULL_TREE)
+ {
+ tree targs = make_scratch_vec (DECL_NTPARMS (tmpl));
+
+ /* We allow incomplete unification here, because we are going to
+ check all the functions. */
+ i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
+ targs,
+ NULL_TREE,
+ NULL_TREE,
+ targs_in,
+ DEDUCE_EXACT, 1);
+
+ if (i == 0)
+ /* Unification was successful. */
+ templates = scratch_tree_cons (targs, tmpl, templates);
+ }
+ else
+ templates = scratch_tree_cons (NULL_TREE, tmpl, templates);
+ }
+
+ if (decl != NULL_TREE)
+ {
+ tree tmpl = most_specialized (templates, decl, targs_in);
+
+ if (tmpl == error_mark_node)
+ goto ambiguous;
+ else if (tmpl == NULL_TREE)
+ goto no_match;
+
+ *targs_out = get_bindings (tmpl, decl, targs_in);
+ return tmpl;
+ }
+
+ if (templates == NULL_TREE)
+ {
+ no_match:
+ if (complain)
+ {
+ cp_error_at ("template-id `%D' for `%+D' does not match any template declaration",
+ template_id, decl);
+ return error_mark_node;
+ }
+ return NULL_TREE;
+ }
+ else if (TREE_CHAIN (templates) != NULL_TREE)
+ {
+ ambiguous:
+ if (complain)
+ {
+ cp_error_at ("ambiguous template specialization `%D' for `%+D'",
+ template_id, decl);
+ print_candidates (templates);
+ return error_mark_node;
+ }
+ return NULL_TREE;
+ }
+
+ /* We have one, and exactly one, match. */
+ *targs_out = TREE_PURPOSE (templates);
+ return TREE_VALUE (templates);
+}
+
+/* Check to see if the function just declared, as indicated in
+ DECLARATOR, and in DECL, is a specialization of a function
+ template. We may also discover that the declaration is an explicit
+ instantiation at this point.
+
+ Returns DECL, or an equivalent declaration that should be used
+ instead.
+
+ FLAGS is a bitmask consisting of the following flags:
+
+ 1: We are being called by finish_struct. (We are unable to
+ determine what template is specialized by an in-class
+ declaration until the class definition is complete, so
+ finish_struct_methods calls this function again later to finish
+ the job.)
+ 2: The function has a definition.
+ 4: The function is a friend.
+ 8: The function is known to be a specialization of a member
+ template.
+
+ The TEMPLATE_COUNT is the number of references to qualifying
+ template classes that appeared in the name of the function. For
+ example, in
+
+ template <class T> struct S { void f(); };
+ void S<int>::f();
+
+ the TEMPLATE_COUNT would be 1. However, explicitly specialized
+ classes are not counted in the TEMPLATE_COUNT, so that in
+
+ template <class T> struct S {};
+ template <> struct S<int> { void f(); }
+ template <>
+ void S<int>::f();
+
+ the TEMPLATE_COUNT would be 0. (Note that this declaration is
+ illegal; there should be no template <>.)
+
+ If the function is a specialization, it is marked as such via
+ DECL_TEMPLATE_SPECIALIZATION. Furthermore, its DECL_TEMPLATE_INFO
+ is set up correctly, and it is added to the list of specializations
+ for that template. */
+
+tree
+check_explicit_specialization (declarator, decl, template_count, flags)
+ tree declarator;
+ tree decl;
+ int template_count;
+ int flags;
+{
+ int finish_member = flags & 1;
+ int have_def = flags & 2;
+ int is_friend = flags & 4;
+ int specialization = 0;
+ int explicit_instantiation = 0;
+ int member_specialization = flags & 8;
+
+ tree ctype = DECL_CLASS_CONTEXT (decl);
+ tree dname = DECL_NAME (decl);
+
+ if (!finish_member)
+ {
+ if (processing_specialization)
+ {
+ /* The last template header was of the form template <>. */
+
+ if (template_header_count > template_count)
+ {
+ /* There were more template headers than qualifying template
+ classes. */
+ if (template_header_count - template_count > 1)
+ /* There shouldn't be that many template parameter
+ lists. There can be at most one parameter list for
+ every qualifying class, plus one for the function
+ itself. */
+ cp_error ("too many template parameter lists in declaration of `%D'", decl);
+
+ SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+ if (ctype)
+ member_specialization = 1;
+ else
+ specialization = 1;
+ }
+ else if (template_header_count == template_count)
+ {
+ /* The counts are equal. So, this might be a
+ specialization, but it is not a specialization of a
+ member template. It might be something like
+
+ template <class T> struct S {
+ void f(int i);
+ };
+ template <>
+ void S<int>::f(int i) {} */
+ specialization = 1;
+ SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+ }
+ else
+ {
+ /* This cannot be an explicit specialization. There are not
+ enough headers for all of the qualifying classes. For
+ example, we might have:
+
+ template <>
+ void S<int>::T<char>::f();
+
+ But, we're missing another template <>. */
+ cp_error("too few template parameter lists in declaration of `%D'", decl);
+ return decl;
+ }
+ }
+ else if (processing_explicit_instantiation)
+ {
+ if (template_header_count)
+ cp_error ("template parameter list used in explicit instantiation");
+
+ if (have_def)
+ cp_error ("definition provided for explicit instantiation");
+
+ explicit_instantiation = 1;
+ }
+ else if (ctype != NULL_TREE
+ && !TYPE_BEING_DEFINED (ctype)
+ && CLASSTYPE_TEMPLATE_INSTANTIATION (ctype))
+ {
+ /* This case catches outdated code that looks like this:
+
+ template <class T> struct S { void f(); };
+ void S<int>::f() {} // Missing template <>
+
+ We disable this check when the type is being defined to
+ avoid complaining about default compiler-generated
+ constructors, destructors, and assignment operators.
+ Since the type is an instantiation, not a specialization,
+ these are the only functions that can be defined before
+ the class is complete. */
+
+ /* If they said
+ template <class T> void S<int>::f() {}
+ that's bogus. */
+ if (template_header_count)
+ {
+ cp_error ("template parameters specified in specialization");
+ return decl;
+ }
+
+ if (pedantic)
+ cp_pedwarn
+ ("explicit specialization not preceded by `template <>'");
+ specialization = 1;
+ SET_DECL_TEMPLATE_SPECIALIZATION (decl);
+ }
+ else if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
+ {
+ /* This case handles bogus declarations like
+ template <> template <class T>
+ void f<int>(); */
+
+ cp_error ("template-id `%D' in declaration of primary template",
+ declarator);
+ return decl;
+ }
+ }
+
+ if (specialization || member_specialization)
+ {
+ tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ for (; t; t = TREE_CHAIN (t))
+ if (TREE_PURPOSE (t))
+ {
+ cp_pedwarn
+ ("default argument specified in explicit specialization");
+ break;
+ }
+ }
+
+ if (specialization || member_specialization || explicit_instantiation)
+ {
+ tree tmpl = NULL_TREE;
+ tree targs = NULL_TREE;
+
+ /* Make sure that the declarator is a TEMPLATE_ID_EXPR. */
+ if (TREE_CODE (declarator) != TEMPLATE_ID_EXPR)
+ {
+ tree fns;
+
+ my_friendly_assert (TREE_CODE (declarator) == IDENTIFIER_NODE,
+ 0);
+ if (!ctype)
+ fns = IDENTIFIER_NAMESPACE_VALUE (dname);
+ else
+ fns = dname;
+
+ declarator =
+ lookup_template_function (fns, NULL_TREE);
+ }
+
+ if (declarator == error_mark_node)
+ return error_mark_node;
+
+ if (TREE_CODE (TREE_OPERAND (declarator, 0)) == LOOKUP_EXPR)
+ {
+ /* A friend declaration. We can't do much, because we don't
+ know what this resolves to, yet. */
+ my_friendly_assert (is_friend != 0, 0);
+ my_friendly_assert (!explicit_instantiation, 0);
+ SET_DECL_IMPLICIT_INSTANTIATION (decl);
+ return decl;
+ }
+
+ if (ctype != NULL_TREE && TYPE_BEING_DEFINED (ctype))
+ {
+ if (!explicit_instantiation)
+ {
+ /* Since finish_struct_1 has not been called yet, we
+ can't call lookup_fnfields. We note that this
+ template is a specialization, and proceed, letting
+ finish_struct fix this up later. */
+ tree ti = perm_tree_cons (NULL_TREE,
+ TREE_OPERAND (declarator, 1),
+ NULL_TREE);
+ TI_PENDING_SPECIALIZATION_FLAG (ti) = 1;
+ DECL_TEMPLATE_INFO (decl) = ti;
+ }
+ else
+ /* It's not legal to write an explicit instantiation in
+ class scope, e.g.:
+
+ class C { template void f(); }
+
+ This case is caught by the parser. However, on
+ something like:
+
+ template class C { void f(); };
+
+ (which is illegal) we can get here. The error will be
+ issued later. */
+ ;
+
+ return decl;
+ }
+ else if (ctype != NULL_TREE
+ && (TREE_CODE (TREE_OPERAND (declarator, 0)) ==
+ IDENTIFIER_NODE))
+ {
+ /* Find the list of functions in ctype that have the same
+ name as the declared function. */
+ tree name = TREE_OPERAND (declarator, 0);
+ tree fns;
+
+ if (name == constructor_name (ctype)
+ || name == constructor_name_full (ctype))
+ {
+ int is_constructor = DECL_CONSTRUCTOR_P (decl);
+
+ if (is_constructor ? !TYPE_HAS_CONSTRUCTOR (ctype)
+ : !TYPE_HAS_DESTRUCTOR (ctype))
+ {
+ /* From [temp.expl.spec]:
+
+ If such an explicit specialization for the member
+ of a class template names an implicitly-declared
+ special member function (clause _special_), the
+ program is ill-formed.
+
+ Similar language is found in [temp.explicit]. */
+ cp_error ("specialization of implicitly-declared special member function");
+
+ return decl;
+ }
+
+ name = is_constructor ? ctor_identifier : dtor_identifier;
+ }
+
+ fns = lookup_fnfields (TYPE_BINFO (ctype), name, 1);
+
+ if (fns == NULL_TREE)
+ {
+ cp_error ("no member function `%s' declared in `%T'",
+ IDENTIFIER_POINTER (name),
+ ctype);
+ return decl;
+ }
+ else
+ TREE_OPERAND (declarator, 0) = fns;
+ }
+
+ /* Figure out what exactly is being specialized at this point.
+ Note that for an explicit instantiation, even one for a
+ member function, we cannot tell apriori whether the
+ instantiation is for a member template, or just a member
+ function of a template class. In particular, even in if the
+ instantiation is for a member template, the template
+ arguments could be deduced from the declaration. */
+ tmpl = determine_specialization (declarator, decl,
+ &targs,
+ member_specialization,
+ 1);
+
+ if (tmpl && tmpl != error_mark_node)
+ {
+ if (explicit_instantiation)
+ {
+ decl = instantiate_template (tmpl, targs);
+ if (!DECL_TEMPLATE_SPECIALIZATION (decl))
+ /* There doesn't seem to be anything in the draft to
+ prevent a specialization from being explicitly
+ instantiated. We're careful not to destroy the
+ information indicating that this is a
+ specialization here. */
+ SET_DECL_EXPLICIT_INSTANTIATION (decl);
+ return decl;
+ }
+ else if (DECL_STATIC_FUNCTION_P (tmpl)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
+ {
+ revert_static_member_fn (&decl, 0, 0);
+ last_function_parms = TREE_CHAIN (last_function_parms);
+ }
+
+ /* Mangle the function name appropriately. Note that we do
+ not mangle specializations of non-template member
+ functions of template classes, e.g. with
+ template <class T> struct S { void f(); }
+ and given the specialization
+ template <> void S<int>::f() {}
+ we do not mangle S<int>::f() here. That's because it's
+ just an ordinary member function and doesn't need special
+ treatment. */
+ if ((is_member_template (tmpl) || ctype == NULL_TREE)
+ && name_mangling_version >= 1)
+ {
+ tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (tmpl));
+
+ if (ctype
+ && TREE_CODE (TREE_TYPE (tmpl)) == FUNCTION_TYPE)
+ arg_types =
+ hash_tree_chain (build_pointer_type (ctype),
+ arg_types);
+
+ DECL_ASSEMBLER_NAME (decl)
+ = build_template_decl_overload
+ (decl, arg_types, TREE_TYPE (TREE_TYPE (tmpl)),
+ DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
+ targs, ctype != NULL_TREE);
+ }
+
+ if (is_friend && !have_def)
+ {
+ /* This is not really a declaration of a specialization.
+ It's just the name of an instantiation. But, it's not
+ a request for an instantiation, either. */
+ SET_DECL_IMPLICIT_INSTANTIATION (decl);
+ DECL_TEMPLATE_INFO (decl)
+ = perm_tree_cons (tmpl, targs, NULL_TREE);
+ return decl;
+ }
+
+ /* If DECL_TI_TEMPLATE (decl), the decl is an
+ instantiation of a specialization of a member template.
+ (In other words, there was a member template, in a
+ class template. That member template was specialized.
+ We then instantiated the class, so there is now an
+ instance of that specialization.)
+
+ According to the CD2,
+
+ 14.7.3.13 [tmpl.expl.spec]
+
+ A specialization of a member function template or
+ member class template of a non-specialized class
+ template is itself a template.
+
+ So, we just leave the template info alone in this case. */
+ if (!(DECL_TEMPLATE_INFO (decl) && DECL_TI_TEMPLATE (decl)))
+ DECL_TEMPLATE_INFO (decl)
+ = perm_tree_cons (tmpl, targs, NULL_TREE);
+
+ register_specialization (decl, tmpl, targs);
+
+ return decl;
+ }
+ }
+
+ return decl;
+}
+
+/* Returns 1 iff PARMS1 and PARMS2 are identical sets of template
+ parameters. These are represented in the same format used for
+ DECL_TEMPLATE_PARMS. */
+
+int comp_template_parms (parms1, parms2)
+ tree parms1;
+ tree parms2;
+{
+ tree p1;
+ tree p2;
+
+ if (parms1 == parms2)
+ return 1;
+
+ for (p1 = parms1, p2 = parms2;
+ p1 != NULL_TREE && p2 != NULL_TREE;
+ p1 = TREE_CHAIN (p1), p2 = TREE_CHAIN (p2))
+ {
+ tree t1 = TREE_VALUE (p1);
+ tree t2 = TREE_VALUE (p2);
+ int i;
+
+ my_friendly_assert (TREE_CODE (t1) == TREE_VEC, 0);
+ my_friendly_assert (TREE_CODE (t2) == TREE_VEC, 0);
+
+ if (TREE_VEC_LENGTH (t1) != TREE_VEC_LENGTH (t2))
+ return 0;
+
+ for (i = 0; i < TREE_VEC_LENGTH (t2); ++i)
+ {
+ tree parm1 = TREE_VALUE (TREE_VEC_ELT (t1, i));
+ tree parm2 = TREE_VALUE (TREE_VEC_ELT (t2, i));
+
+ if (TREE_CODE (parm1) != TREE_CODE (parm2))
+ return 0;
+
+ if (TREE_CODE (parm1) == TEMPLATE_TYPE_PARM)
+ continue;
+ else if (!comptypes (TREE_TYPE (parm1),
+ TREE_TYPE (parm2), 1))
+ return 0;
+ }
+ }
+
+ if ((p1 != NULL_TREE) != (p2 != NULL_TREE))
+ /* One set of parameters has more parameters lists than the
+ other. */
+ return 0;
+
+ return 1;
+}
+
+/* Return a new TEMPLATE_PARM_INDEX with the indicated INDEX, LEVEL,
+ ORIG_LEVEL, DECL, and TYPE. */
+
+static tree
+build_template_parm_index (index, level, orig_level, decl, type)
+ int index;
+ int level;
+ int orig_level;
+ tree decl;
+ tree type;
+{
+ tree t = make_node (TEMPLATE_PARM_INDEX);
+ TEMPLATE_PARM_IDX (t) = index;
+ TEMPLATE_PARM_LEVEL (t) = level;
+ TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level;
+ TEMPLATE_PARM_DECL (t) = decl;
+ TREE_TYPE (t) = type;
+
+ return t;
+}
+
+/* Return a TEMPLATE_PARM_INDEX, similar to INDEX, but whose
+ TEMPLATE_PARM_LEVEL has been decreased by LEVELS. If such a
+ TEMPLATE_PARM_INDEX already exists, it is returned; otherwise, a
+ new one is created. */
+
+static tree
+reduce_template_parm_level (index, type, levels)
+ tree index;
+ tree type;
+ int levels;
+{
+ if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE
+ || (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_DESCENDANTS (index))
+ != TEMPLATE_PARM_LEVEL (index) - levels))
+ {
+ tree decl
+ = build_decl (TREE_CODE (TEMPLATE_PARM_DECL (index)),
+ DECL_NAME (TEMPLATE_PARM_DECL (index)),
+ type);
+ tree t
+ = build_template_parm_index (TEMPLATE_PARM_IDX (index),
+ TEMPLATE_PARM_LEVEL (index) - levels,
+ TEMPLATE_PARM_ORIG_LEVEL (index),
+ decl, type);
+ TEMPLATE_PARM_DESCENDANTS (index) = t;
+
+ /* Template template parameters need this. */
+ DECL_TEMPLATE_PARMS (decl)
+ = DECL_TEMPLATE_PARMS (TEMPLATE_PARM_DECL (index));
+ }
+
+ return TEMPLATE_PARM_DESCENDANTS (index);
}
/* Process information from new template parameter NEXT and append it to the
- LIST being built. The rules for use of a template parameter type name
- by later parameters are not well-defined for us just yet. However, the
- only way to avoid having to parse expressions of unknown complexity (and
- with tokens of unknown types) is to disallow it completely. So for now,
- that is what is assumed. */
+ LIST being built. */
+
tree
process_template_parm (list, next)
tree list, next;
@@ -89,51 +1399,92 @@ process_template_parm (list, next)
tree parm;
tree decl = 0;
tree defval;
- int is_type;
+ int is_type, idx;
+
parm = next;
my_friendly_assert (TREE_CODE (parm) == TREE_LIST, 259);
defval = TREE_PURPOSE (parm);
parm = TREE_VALUE (parm);
is_type = TREE_PURPOSE (parm) == class_type_node;
+
+ if (list)
+ {
+ tree p = TREE_VALUE (tree_last (list));
+
+ if (TREE_CODE (p) == TYPE_DECL)
+ idx = TEMPLATE_TYPE_IDX (TREE_TYPE (p));
+ else if (TREE_CODE (p) == TEMPLATE_DECL)
+ idx = TEMPLATE_TYPE_IDX (TREE_TYPE (DECL_TEMPLATE_RESULT (p)));
+ else
+ idx = TEMPLATE_PARM_IDX (DECL_INITIAL (p));
+ ++idx;
+ }
+ else
+ idx = 0;
+
if (!is_type)
{
- tree tinfo = 0;
my_friendly_assert (TREE_CODE (TREE_PURPOSE (parm)) == TREE_LIST, 260);
/* is a const-param */
parm = grokdeclarator (TREE_VALUE (parm), TREE_PURPOSE (parm),
- PARM, 0, NULL_TREE, NULL_TREE);
+ PARM, 0, NULL_TREE);
/* A template parameter is not modifiable. */
TREE_READONLY (parm) = 1;
- if (IS_AGGR_TYPE (TREE_TYPE (parm)))
+ if (IS_AGGR_TYPE (TREE_TYPE (parm))
+ && TREE_CODE (TREE_TYPE (parm)) != TEMPLATE_TYPE_PARM
+ && TREE_CODE (TREE_TYPE (parm)) != TYPENAME_TYPE)
{
- sorry ("aggregate template parameter types");
+ cp_error ("`%#T' is not a valid type for a template constant parameter",
+ TREE_TYPE (parm));
+ if (DECL_NAME (parm) == NULL_TREE)
+ error (" a template type parameter must begin with `class' or `typename'");
TREE_TYPE (parm) = void_type_node;
}
- tinfo = make_node (TEMPLATE_CONST_PARM);
- my_friendly_assert (TREE_PERMANENT (tinfo), 260.5);
+ else if (pedantic
+ && (TREE_CODE (TREE_TYPE (parm)) == REAL_TYPE
+ || TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE))
+ cp_pedwarn ("`%T' is not a valid type for a template constant parameter",
+ TREE_TYPE (parm));
if (TREE_PERMANENT (parm) == 0)
{
parm = copy_node (parm);
TREE_PERMANENT (parm) = 1;
}
- TREE_TYPE (tinfo) = TREE_TYPE (parm);
decl = build_decl (CONST_DECL, DECL_NAME (parm), TREE_TYPE (parm));
- DECL_INITIAL (decl) = tinfo;
- DECL_INITIAL (parm) = tinfo;
+ DECL_INITIAL (parm) = DECL_INITIAL (decl)
+ = build_template_parm_index (idx, processing_template_decl,
+ processing_template_decl,
+ decl, TREE_TYPE (parm));
}
else
{
- tree t = make_node (TEMPLATE_TYPE_PARM);
- decl = build_decl (TYPE_DECL, TREE_VALUE (parm), t);
- TYPE_MAIN_DECL (t) = decl;
- parm = decl;
- if (defval)
+ tree t;
+ parm = TREE_VALUE (parm);
+
+ if (parm && TREE_CODE (parm) == TEMPLATE_DECL)
{
- if (IDENTIFIER_HAS_TYPE_VALUE (defval))
- defval = IDENTIFIER_TYPE_VALUE (defval);
- else
- defval = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (defval));
+ t = make_lang_type (TEMPLATE_TEMPLATE_PARM);
+ /* This is for distinguishing between real templates and template
+ template parameters */
+ TREE_TYPE (parm) = t;
+ TREE_TYPE (DECL_TEMPLATE_RESULT (parm)) = t;
+ decl = parm;
}
+ else
+ {
+ t = make_lang_type (TEMPLATE_TYPE_PARM);
+ /* parm is either IDENTIFIER_NODE or NULL_TREE */
+ decl = build_decl (TYPE_DECL, parm, t);
+ }
+
+ CLASSTYPE_GOT_SEMICOLON (t) = 1;
+ TYPE_NAME (t) = decl;
+ TYPE_STUB_DECL (t) = decl;
+ parm = decl;
+ TEMPLATE_TYPE_PARM_INDEX (t)
+ = build_template_parm_index (idx, processing_template_decl,
+ processing_template_decl,
+ decl, TREE_TYPE (parm));
}
SET_DECL_ARTIFICIAL (decl);
pushdecl (decl);
@@ -150,196 +1501,965 @@ tree
end_template_parm_list (parms)
tree parms;
{
- int nparms = 0;
- int saw_default = 0;
- tree saved_parmlist;
+ int nparms;
tree parm;
- for (parm = parms; parm; parm = TREE_CHAIN (parm))
- nparms++;
- saved_parmlist = make_tree_vec (nparms);
+ tree saved_parmlist = make_tree_vec (list_length (parms));
+
+ current_template_parms
+ = tree_cons (build_int_2 (0, processing_template_decl),
+ saved_parmlist, current_template_parms);
for (parm = parms, nparms = 0; parm; parm = TREE_CHAIN (parm), nparms++)
+ TREE_VEC_ELT (saved_parmlist, nparms) = parm;
+
+ --processing_template_parmlist;
+
+ return saved_parmlist;
+}
+
+/* end_template_decl is called after a template declaration is seen. */
+
+void
+end_template_decl ()
+{
+ reset_specialization ();
+
+ if (! processing_template_decl)
+ return;
+
+ /* This matches the pushlevel in begin_template_parm_list. */
+ poplevel (0, 0, 0);
+
+ --processing_template_decl;
+ current_template_parms = TREE_CHAIN (current_template_parms);
+ (void) get_pending_sizes (); /* Why? */
+}
+
+/* Generate a valid set of template args from current_template_parms. */
+
+tree
+current_template_args ()
+{
+ tree header = current_template_parms;
+ int length = list_length (header);
+ tree args = make_tree_vec (length);
+ int l = length;
+
+ while (header)
{
- tree p = TREE_VALUE (parm);
- if (TREE_PURPOSE (parm))
- saw_default = 1;
- else if (saw_default)
+ tree a = copy_node (TREE_VALUE (header));
+ int i = TREE_VEC_LENGTH (a);
+ TREE_TYPE (a) = NULL_TREE;
+ while (i--)
{
- error ("if a default argument is given for one template parameter");
- error ("default arguments must be given for all subsequent");
- error ("parameters as well");
+ tree t = TREE_VEC_ELT (a, i);
+
+ /* t will be a list if we are called from within a
+ begin/end_template_parm_list pair, but a vector directly
+ if within a begin/end_member_template_processing pair. */
+ if (TREE_CODE (t) == TREE_LIST)
+ {
+ t = TREE_VALUE (t);
+
+ if (TREE_CODE (t) == TYPE_DECL
+ || TREE_CODE (t) == TEMPLATE_DECL)
+ t = TREE_TYPE (t);
+ else
+ t = DECL_INITIAL (t);
+ }
+
+ TREE_VEC_ELT (a, i) = t;
}
+ TREE_VEC_ELT (args, --l) = a;
+ header = TREE_CHAIN (header);
+ }
- if (TREE_CODE (p) == TYPE_DECL)
+ return args;
+}
+
+
+/* Return a TEMPLATE_DECL corresponding to DECL, using the indicated
+ template PARMS. Used by push_template_decl below. */
+
+static tree
+build_template_decl (decl, parms)
+ tree decl;
+ tree parms;
+{
+ tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
+ DECL_TEMPLATE_PARMS (tmpl) = parms;
+ DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);
+ if (DECL_LANG_SPECIFIC (decl))
+ {
+ DECL_CLASS_CONTEXT (tmpl) = DECL_CLASS_CONTEXT (decl);
+ DECL_STATIC_FUNCTION_P (tmpl) =
+ DECL_STATIC_FUNCTION_P (decl);
+ }
+
+ return tmpl;
+}
+
+struct template_parm_data
+{
+ int level;
+ int* parms;
+};
+
+/* Subroutine of push_template_decl used to see if each template
+ parameter in a partial specialization is used in the explicit
+ argument list. If T is of the LEVEL given in DATA (which is
+ treated as a template_parm_data*), then DATA->PARMS is marked
+ appropriately. */
+
+static int
+mark_template_parm (t, data)
+ tree t;
+ void* data;
+{
+ int level;
+ int idx;
+ struct template_parm_data* tpd = (struct template_parm_data*) data;
+
+ if (TREE_CODE (t) == TEMPLATE_PARM_INDEX)
+ {
+ level = TEMPLATE_PARM_LEVEL (t);
+ idx = TEMPLATE_PARM_IDX (t);
+ }
+ else
+ {
+ level = TEMPLATE_TYPE_LEVEL (t);
+ idx = TEMPLATE_TYPE_IDX (t);
+ }
+
+ if (level == tpd->level)
+ tpd->parms[idx] = 1;
+
+ /* Return zero so that for_each_template_parm will continue the
+ traversal of the tree; we want to mark *every* template parm. */
+ return 0;
+}
+
+/* Creates a TEMPLATE_DECL for the indicated DECL using the template
+ parameters given by current_template_args, or reuses a
+ previously existing one, if appropriate. Returns the DECL, or an
+ equivalent one, if it is replaced via a call to duplicate_decls.
+
+ If IS_FRIEND is non-zero, DECL is a friend declaration. */
+
+tree
+push_template_decl_real (decl, is_friend)
+ tree decl;
+ int is_friend;
+{
+ tree tmpl;
+ tree args;
+ tree info;
+ tree ctx;
+ int primary;
+
+ is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));
+
+ if (is_friend)
+ /* For a friend, we want the context of the friend function, not
+ the type of which it is a friend. */
+ ctx = DECL_CONTEXT (decl);
+ else if (DECL_REAL_CONTEXT (decl)
+ && TREE_CODE (DECL_REAL_CONTEXT (decl)) != NAMESPACE_DECL)
+ /* In the case of a virtual function, we want the class in which
+ it is defined. */
+ ctx = DECL_REAL_CONTEXT (decl);
+ else
+ /* Otherwise, if we're currently definining some class, the DECL
+ is assumed to be a member of the class. */
+ ctx = current_class_type;
+
+ if (ctx && TREE_CODE (ctx) == NAMESPACE_DECL)
+ ctx = NULL_TREE;
+
+ if (!DECL_CONTEXT (decl))
+ DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
+
+ /* For determining whether this is a primary template or not, we're really
+ interested in the lexical context, not the true context. */
+ if (is_friend)
+ /* For a TYPE_DECL, there is no DECL_CLASS_CONTEXT. */
+ info = TREE_CODE (decl) == FUNCTION_DECL
+ ? DECL_CLASS_CONTEXT (decl) : current_class_type;
+ else
+ info = ctx;
+
+ if (info && TREE_CODE (info) == FUNCTION_DECL)
+ primary = 0;
+ /* Note that template_class_depth returns 0 if given NULL_TREE, so
+ this next line works even when we are at global scope. */
+ else if (processing_template_decl > template_class_depth (info))
+ primary = 1;
+ else
+ primary = 0;
+
+ if (primary)
+ {
+ if (current_lang_name == lang_name_c)
+ cp_error ("template with C linkage");
+ if (TREE_CODE (decl) == TYPE_DECL && ANON_AGGRNAME_P (DECL_NAME (decl)))
+ cp_error ("template class without a name");
+ }
+
+ /* Partial specialization. */
+ if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl)
+ && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)))
+ {
+ tree type = TREE_TYPE (decl);
+ tree maintmpl = CLASSTYPE_TI_TEMPLATE (type);
+ tree mainargs = CLASSTYPE_TI_ARGS (type);
+ tree spec = DECL_TEMPLATE_SPECIALIZATIONS (maintmpl);
+
+ /* We check that each of the template parameters given in the
+ partial specialization is used in the argument list to the
+ specialization. For example:
+
+ template <class T> struct S;
+ template <class T> struct S<T*>;
+
+ The second declaration is OK because `T*' uses the template
+ parameter T, whereas
+
+ template <class T> struct S<int>;
+
+ is no good. Even trickier is:
+
+ template <class T>
+ struct S1
+ {
+ template <class U>
+ struct S2;
+ template <class U>
+ struct S2<T>;
+ };
+
+ The S2<T> declaration is actually illegal; it is a
+ full-specialization. Of course,
+
+ template <class U>
+ struct S2<T (*)(U)>;
+
+ or some such would have been OK. */
+ int i;
+ struct template_parm_data tpd;
+ int ntparms = TREE_VEC_LENGTH (TREE_VALUE (current_template_parms));
+ int did_error_intro = 0;
+
+ tpd.level = TREE_INT_CST_HIGH (TREE_PURPOSE (current_template_parms));
+ tpd.parms = alloca (sizeof (int) * ntparms);
+ for (i = 0; i < ntparms; ++i)
+ tpd.parms[i] = 0;
+ for (i = 0; i < TREE_VEC_LENGTH (mainargs); ++i)
+ for_each_template_parm (TREE_VEC_ELT (mainargs, i),
+ &mark_template_parm,
+ &tpd);
+ for (i = 0; i < ntparms; ++i)
+ if (tpd.parms[i] == 0)
+ {
+ /* One of the template parms was not used in the
+ specialization. */
+ if (!did_error_intro)
+ {
+ cp_error ("template parameters not used in partial specialization:");
+ did_error_intro = 1;
+ }
+
+ cp_error (" `%D'",
+ TREE_VALUE (TREE_VEC_ELT
+ (TREE_VALUE (current_template_parms),
+ i)));
+ }
+
+ for (; spec; spec = TREE_CHAIN (spec))
{
- tree t = TREE_TYPE (p);
- TEMPLATE_TYPE_SET_INFO (t, saved_parmlist, nparms);
+ /* purpose: args to main template
+ value: spec template */
+ if (comp_template_args (TREE_PURPOSE (spec), mainargs))
+ return decl;
}
+
+ DECL_TEMPLATE_SPECIALIZATIONS (maintmpl) = CLASSTYPE_TI_SPEC_INFO (type)
+ = perm_tree_cons (mainargs, TREE_VALUE (current_template_parms),
+ DECL_TEMPLATE_SPECIALIZATIONS (maintmpl));
+ TREE_TYPE (DECL_TEMPLATE_SPECIALIZATIONS (maintmpl)) = type;
+ return decl;
+ }
+
+ args = current_template_args ();
+
+ if (!ctx
+ || TREE_CODE (ctx) == FUNCTION_DECL
+ || TYPE_BEING_DEFINED (ctx)
+ || (is_friend && !DECL_TEMPLATE_INFO (decl)))
+ {
+ if (DECL_LANG_SPECIFIC (decl)
+ && DECL_TEMPLATE_INFO (decl)
+ && DECL_TI_TEMPLATE (decl))
+ tmpl = DECL_TI_TEMPLATE (decl);
else
{
- tree tinfo = DECL_INITIAL (p);
- DECL_INITIAL (p) = NULL_TREE;
- TEMPLATE_CONST_SET_INFO (tinfo, saved_parmlist, nparms);
+ tmpl = build_template_decl (decl, current_template_parms);
+
+ if (DECL_LANG_SPECIFIC (decl)
+ && DECL_TEMPLATE_SPECIALIZATION (decl))
+ {
+ /* A specialization of a member template of a template
+ class. */
+ SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);
+ DECL_TEMPLATE_INFO (tmpl) = DECL_TEMPLATE_INFO (decl);
+ DECL_TEMPLATE_INFO (decl) = NULL_TREE;
+ }
}
- TREE_VEC_ELT (saved_parmlist, nparms) = parm;
}
- set_current_level_tags_transparency (1);
- processing_template_decl++;
- return saved_parmlist;
+ else
+ {
+ tree t;
+ tree a;
+
+ if (CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
+ cp_error ("must specialize `%#T' before defining member `%#D'",
+ ctx, decl);
+ if (TREE_CODE (decl) == TYPE_DECL)
+ {
+ if (IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (decl)))
+ && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl))
+ && CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)))
+ tmpl = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl));
+ else
+ {
+ cp_error ("`%D' does not declare a template type", decl);
+ return decl;
+ }
+ }
+ else if (! DECL_TEMPLATE_INFO (decl))
+ {
+ cp_error ("template definition of non-template `%#D'", decl);
+ return decl;
+ }
+ else
+ tmpl = DECL_TI_TEMPLATE (decl);
+
+ if (is_member_template (tmpl) || is_member_template_class (tmpl))
+ {
+ if (DECL_FUNCTION_TEMPLATE_P (tmpl)
+ && DECL_TEMPLATE_INFO (decl) && DECL_TI_ARGS (decl)
+ && DECL_TEMPLATE_SPECIALIZATION (decl))
+ {
+ tree new_tmpl;
+
+ /* The declaration is a specialization of a member
+ template, declared outside the class. Therefore, the
+ innermost template arguments will be NULL, so we
+ replace them with the arguments determined by the
+ earlier call to check_explicit_specialization. */
+ args = DECL_TI_ARGS (decl);
+
+ new_tmpl
+ = build_template_decl (decl, current_template_parms);
+ DECL_TEMPLATE_RESULT (new_tmpl) = decl;
+ TREE_TYPE (new_tmpl) = TREE_TYPE (decl);
+ DECL_TI_TEMPLATE (decl) = new_tmpl;
+ SET_DECL_TEMPLATE_SPECIALIZATION (new_tmpl);
+ DECL_TEMPLATE_INFO (new_tmpl) =
+ perm_tree_cons (tmpl, args, NULL_TREE);
+
+ register_specialization (new_tmpl, tmpl, args);
+ return decl;
+ }
+
+ a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
+ t = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
+ if (TREE_VEC_LENGTH (t) != TREE_VEC_LENGTH (a))
+ {
+ cp_error ("got %d template parameters for `%#D'",
+ TREE_VEC_LENGTH (a), decl);
+ cp_error (" but %d required", TREE_VEC_LENGTH (t));
+ }
+ if (TREE_VEC_LENGTH (args) > 1)
+ /* Get the template parameters for the enclosing template
+ class. */
+ a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 2);
+ else
+ a = NULL_TREE;
+ }
+ else
+ a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
+
+ t = NULL_TREE;
+
+ if (CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx))
+ {
+ /* When processing an inline member template of a
+ specialized class, there is no CLASSTYPE_TI_SPEC_INFO. */
+ if (CLASSTYPE_TI_SPEC_INFO (ctx))
+ t = TREE_VALUE (CLASSTYPE_TI_SPEC_INFO (ctx));
+ }
+ else if (CLASSTYPE_TEMPLATE_INFO (ctx))
+ t = DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (ctx));
+
+ /* There should be template arguments if and only if there is a
+ template class. */
+ my_friendly_assert((a != NULL_TREE) == (t != NULL_TREE), 0);
+
+ if (t != NULL_TREE
+ && TREE_VEC_LENGTH (t) != TREE_VEC_LENGTH (a))
+ {
+ cp_error ("got %d template parameters for `%#D'",
+ TREE_VEC_LENGTH (a), decl);
+ cp_error (" but `%#T' has %d", ctx, TREE_VEC_LENGTH (t));
+ }
+ }
+ /* Get the innermost set of template arguments. We don't do this
+ for a non-template member function of a nested template class
+ because there we will never get a `partial instantiation' of the
+ function containing the outer arguments, and so we must save all
+ of the arguments here. */
+ if (TREE_CODE (decl) != FUNCTION_DECL
+ || template_class_depth (ctx) <= 1
+ || primary)
+ args = innermost_args (args, 0);
+
+ DECL_TEMPLATE_RESULT (tmpl) = decl;
+ TREE_TYPE (tmpl) = TREE_TYPE (decl);
+
+ if (! ctx && !(is_friend && template_class_depth (info) > 0))
+ /* Note that we do not try to push a global template friend
+ declared in a template class; such a thing may well depend on
+ the template parameters of the class. */
+ tmpl = pushdecl_namespace_level (tmpl);
+
+ if (primary)
+ DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
+
+ info = perm_tree_cons (tmpl, args, NULL_TREE);
+
+ if (TREE_CODE (decl) == TYPE_DECL && DECL_ARTIFICIAL (decl))
+ {
+ CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (tmpl)) = info;
+ if (!ctx || TREE_CODE (ctx) != FUNCTION_DECL)
+ DECL_NAME (decl) = classtype_mangled_name (TREE_TYPE (decl));
+ }
+ else if (! DECL_LANG_SPECIFIC (decl))
+ cp_error ("template declaration of `%#D'", decl);
+ else
+ DECL_TEMPLATE_INFO (decl) = info;
+
+ return DECL_TEMPLATE_RESULT (tmpl);
}
-/* end_template_decl is called after a template declaration is seen.
- D1 is template header; D2 is class_head_sans_basetype or a
- TEMPLATE_DECL with its DECL_RESULT field set. */
-void
-end_template_decl (d1, d2, is_class, defn)
- tree d1, d2, is_class;
- int defn;
+tree
+push_template_decl (decl)
+ tree decl;
{
- tree decl;
- struct template_info *tmpl;
+ return push_template_decl_real (decl, 0);
+}
- tmpl = (struct template_info *) obstack_alloc (&permanent_obstack,
- sizeof (struct template_info));
- tmpl->text = 0;
- tmpl->length = 0;
- tmpl->aggr = is_class;
+/* Called when a class template TYPE is redeclared with the indicated
+ template PARMS, e.g.:
- /* cloned from reinit_parse_for_template */
- tmpl->filename = input_filename;
- tmpl->lineno = lineno;
- tmpl->parm_vec = d1; /* [eichin:19911015.2306EST] */
+ template <class T> struct S;
+ template <class T> struct S {}; */
- if (d2 == NULL_TREE || d2 == error_mark_node)
+void
+redeclare_class_template (type, parms)
+ tree type;
+ tree parms;
+{
+ tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
+ tree tmpl_parms;
+ int i;
+
+ if (!PRIMARY_TEMPLATE_P (tmpl))
+ /* The type is nested in some template class. Nothing to worry
+ about here; there are no new template parameters for the nested
+ type. */
+ return;
+
+ parms = INNERMOST_TEMPLATE_PARMS (parms);
+ tmpl_parms = DECL_INNERMOST_TEMPLATE_PARMS (tmpl);
+
+ if (TREE_VEC_LENGTH (parms) != TREE_VEC_LENGTH (tmpl_parms))
{
- decl = 0;
- goto lose;
+ cp_error_at ("previous declaration `%D'", tmpl);
+ cp_error ("used %d template parameter%s instead of %d",
+ TREE_VEC_LENGTH (tmpl_parms),
+ TREE_VEC_LENGTH (tmpl_parms) == 1 ? "" : "s",
+ TREE_VEC_LENGTH (parms));
+ return;
}
- if (is_class)
+ for (i = 0; i < TREE_VEC_LENGTH (tmpl_parms); ++i)
{
- decl = build_lang_decl (TEMPLATE_DECL, d2, NULL_TREE);
- GNU_xref_decl (current_function_decl, decl);
+ tree tmpl_parm = TREE_VALUE (TREE_VEC_ELT (tmpl_parms, i));
+ tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
+ tree tmpl_default = TREE_PURPOSE (TREE_VEC_ELT (tmpl_parms, i));
+ tree parm_default = TREE_PURPOSE (TREE_VEC_ELT (parms, i));
+
+ if (TREE_CODE (tmpl_parm) != TREE_CODE (parm))
+ {
+ cp_error_at ("template parameter `%#D'", tmpl_parm);
+ cp_error ("redeclared here as `%#D'", parm);
+ return;
+ }
+
+ if (tmpl_default != NULL_TREE && parm_default != NULL_TREE)
+ {
+ /* We have in [temp.param]:
+
+ A template-parameter may not be given default arguments
+ by two different declarations in the same scope. */
+ cp_error ("redefinition of default argument for `%#D'", parm);
+ cp_error_at (" original definition appeared here", tmpl_parm);
+ return;
+ }
+
+ if (parm_default != NULL_TREE)
+ /* Update the previous template parameters (which are the ones
+ that will really count) with the new default value. */
+ TREE_PURPOSE (TREE_VEC_ELT (tmpl_parms, i)) = parm_default;
}
- else
+}
+
+/* Attempt to convert the non-type template parameter EXPR to the
+ indicated TYPE. If the conversion is successful, return the
+ converted value. If the conversion is unsuccesful, return
+ NULL_TREE if we issued an error message, or error_mark_node if we
+ did not. We issue error messages for out-and-out bad template
+ parameters, but not simply because the conversion failed, since we
+ might be just trying to do argument deduction. By the time this
+ function is called, neither TYPE nor EXPR may make use of template
+ parameters. */
+
+static tree
+convert_nontype_argument (type, expr)
+ tree type;
+ tree expr;
+{
+ tree expr_type = TREE_TYPE (expr);
+
+ /* A template-argument for a non-type, non-template
+ template-parameter shall be one of:
+
+ --an integral constant-expression of integral or enumeration
+ type; or
+
+ --the name of a non-type template-parameter; or
+
+ --the name of an object or function with external linkage,
+ including function templates and function template-ids but
+ excluding non-static class members, expressed as id-expression;
+ or
+
+ --the address of an object or function with external linkage,
+ including function templates and function template-ids but
+ excluding non-static class members, expressed as & id-expression
+ where the & is optional if the name refers to a function or
+ array; or
+
+ --a pointer to member expressed as described in _expr.unary.op_. */
+
+ /* An integral constant-expression can include const variables
+ or enumerators. */
+ if (INTEGRAL_TYPE_P (expr_type) && TREE_READONLY_DECL_P (expr))
+ expr = decl_constant_value (expr);
+
+ if (is_overloaded_fn (expr))
+ /* OK for now. We'll check that it has external linkage later.
+ Check this first since if expr_type is the unknown_type_node
+ we would otherwise complain below. */
+ ;
+ else if (INTEGRAL_TYPE_P (expr_type)
+ || TYPE_PTRMEM_P (expr_type)
+ || TYPE_PTRMEMFUNC_P (expr_type)
+ /* The next two are g++ extensions. */
+ || TREE_CODE (expr_type) == REAL_TYPE
+ || TREE_CODE (expr_type) == COMPLEX_TYPE)
{
- if (TREE_CODE (d2) == TEMPLATE_DECL)
- decl = d2;
- else
+ if (! TREE_CONSTANT (expr))
{
- /* Class destructor templates and operator templates are
- slipping past as non-template nodes. Process them here, since
- I haven't figured out where to catch them earlier. I could
- go do that, but it's a choice between getting that done and
- staying only N months behind schedule. Sorry.... */
- enum tree_code code;
- my_friendly_assert (TREE_CODE (d2) == CALL_EXPR, 263);
- code = TREE_CODE (TREE_OPERAND (d2, 0));
- my_friendly_assert (code == BIT_NOT_EXPR
- || code == OP_IDENTIFIER
- || code == SCOPE_REF, 264);
- d2 = grokdeclarator (d2, NULL_TREE, MEMFUNCDEF, 0, NULL_TREE, NULL_TREE);
- decl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (d2),
- TREE_TYPE (d2));
- DECL_TEMPLATE_RESULT (decl) = d2;
- DECL_CONTEXT (decl) = DECL_CONTEXT (d2);
- DECL_CLASS_CONTEXT (decl) = DECL_CLASS_CONTEXT (d2);
- DECL_NAME (decl) = DECL_NAME (d2);
- TREE_TYPE (decl) = TREE_TYPE (d2);
- if (interface_unknown && flag_external_templates
- && ! flag_alt_external_templates
- && ! DECL_IN_SYSTEM_HEADER (decl))
- warn_if_unknown_interface (decl);
- TREE_PUBLIC (decl) = TREE_PUBLIC (d2) = flag_external_templates && !interface_unknown;
- DECL_EXTERNAL (decl) = (DECL_EXTERNAL (d2)
- && !(DECL_CLASS_CONTEXT (d2)
- && !DECL_THIS_EXTERN (d2)));
- }
-
- /* All routines creating TEMPLATE_DECL nodes should now be using
- build_lang_decl, which will have set this up already. */
- my_friendly_assert (DECL_LANG_SPECIFIC (decl) != 0, 265);
-
- /* @@ Somewhere, permanent allocation isn't being used. */
- if (! DECL_TEMPLATE_IS_CLASS (decl)
- && TREE_CODE (DECL_TEMPLATE_RESULT (decl)) == FUNCTION_DECL)
- {
- tree result = DECL_TEMPLATE_RESULT (decl);
- /* Will do nothing if allocation was already permanent. */
- DECL_ARGUMENTS (result) = copy_to_permanent (DECL_ARGUMENTS (result));
- }
-
- /* If this is for a method, there's an extra binding level here. */
- if (DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl)) != NULL_TREE)
- {
- /* @@ Find out where this should be getting set! */
- tree r = DECL_TEMPLATE_RESULT (decl);
- if (DECL_LANG_SPECIFIC (r) && DECL_CLASS_CONTEXT (r) == NULL_TREE)
- DECL_CLASS_CONTEXT (r) = DECL_CONTEXT (r);
+ non_constant:
+ cp_error ("non-constant `%E' cannot be used as template argument",
+ expr);
+ return NULL_TREE;
}
}
- DECL_TEMPLATE_INFO (decl) = tmpl;
- DECL_TEMPLATE_PARMS (decl) = d1;
+ else if (TYPE_PTR_P (expr_type)
+ /* If expr is the address of an overloaded function, we
+ will get the unknown_type_node at this point. */
+ || expr_type == unknown_type_node)
+ {
+ tree referent;
+ tree e = expr;
+ STRIP_NOPS (e);
- /* So that duplicate_decls can do the right thing. */
- if (defn)
- DECL_INITIAL (decl) = error_mark_node;
-
- /* If context of decl is non-null (i.e., method template), add it
- to the appropriate class template, and pop the binding levels. */
- if (! is_class && DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl)) != NULL_TREE)
- {
- tree ctx = DECL_CONTEXT (DECL_TEMPLATE_RESULT (decl));
- tree tmpl, t;
- my_friendly_assert (TREE_CODE (ctx) == UNINSTANTIATED_P_TYPE, 266);
- tmpl = UPT_TEMPLATE (ctx);
- for (t = DECL_TEMPLATE_MEMBERS (tmpl); t; t = TREE_CHAIN (t))
- if (TREE_PURPOSE (t) == DECL_NAME (decl)
- && duplicate_decls (decl, TREE_VALUE (t)))
- goto already_there;
- DECL_TEMPLATE_MEMBERS (tmpl) =
- perm_tree_cons (DECL_NAME (decl), decl, DECL_TEMPLATE_MEMBERS (tmpl));
- already_there:
- poplevel (0, 0, 0);
- poplevel (0, 0, 0);
+ if (TREE_CODE (e) != ADDR_EXPR)
+ {
+ bad_argument:
+ cp_error ("`%E' is not a valid template argument", expr);
+ error ("it must be %s%s with external linkage",
+ TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
+ ? "a pointer to " : "",
+ TREE_CODE (TREE_TYPE (TREE_TYPE (expr))) == FUNCTION_TYPE
+ ? "a function" : "an object");
+ return NULL_TREE;
+ }
+
+ referent = TREE_OPERAND (e, 0);
+ STRIP_NOPS (referent);
+
+ if (TREE_CODE (referent) == STRING_CST)
+ {
+ cp_error ("string literal %E is not a valid template argument",
+ referent);
+ error ("because it is the address of an object with static linkage");
+ return NULL_TREE;
+ }
+
+ if (is_overloaded_fn (referent))
+ /* We'll check that it has external linkage later. */
+ ;
+ else if (TREE_CODE (referent) != VAR_DECL)
+ goto bad_argument;
+ else if (!TREE_PUBLIC (referent))
+ {
+ cp_error ("address of non-extern `%E' cannot be used as template argument", referent);
+ return error_mark_node;
+ }
}
- /* Otherwise, go back to top level first, and push the template decl
- again there. */
- else
+ else if (TREE_CODE (expr) == VAR_DECL)
{
- poplevel (0, 0, 0);
- poplevel (0, 0, 0);
- pushdecl (decl);
+ if (!TREE_PUBLIC (expr))
+ goto bad_argument;
+ }
+ else
+ {
+ cp_error ("object `%E' cannot be used as template argument", expr);
+ return NULL_TREE;
}
- lose:
-#if 0 /* It happens sometimes, with syntactic or semantic errors.
- One specific case:
- template <class A, int X, int Y> class Foo { ... };
- template <class A, int X, int y> Foo<X,Y>::method (Foo& x) { ... }
- Note the missing "A" in the class containing "method". */
- my_friendly_assert (global_bindings_p (), 267);
-#else
- while (! global_bindings_p ())
- poplevel (0, 0, 0);
-#endif
- pop_obstacks ();
- processing_template_decl--;
- (void) get_pending_sizes ();
+ switch (TREE_CODE (type))
+ {
+ case INTEGER_TYPE:
+ case BOOLEAN_TYPE:
+ case ENUMERAL_TYPE:
+ /* For a non-type template-parameter of integral or enumeration
+ type, integral promotions (_conv.prom_) and integral
+ conversions (_conv.integral_) are applied. */
+ if (!INTEGRAL_TYPE_P (expr_type))
+ return error_mark_node;
+
+ /* It's safe to call digest_init in this case; we know we're
+ just converting one integral constant expression to another. */
+ expr = digest_init (type, expr, (tree*) 0);
+
+ if (TREE_CODE (expr) != INTEGER_CST)
+ /* Curiously, some TREE_CONSTNAT integral expressions do not
+ simplify to integer constants. For example, `3 % 0',
+ remains a TRUNC_MOD_EXPR. */
+ goto non_constant;
+
+ return expr;
+
+ case REAL_TYPE:
+ case COMPLEX_TYPE:
+ /* These are g++ extensions. */
+ if (TREE_CODE (expr_type) != TREE_CODE (type))
+ return error_mark_node;
+
+ expr = digest_init (type, expr, (tree*) 0);
+
+ if (TREE_CODE (expr) != REAL_CST)
+ goto non_constant;
+
+ return expr;
+
+ case POINTER_TYPE:
+ {
+ tree type_pointed_to = TREE_TYPE (type);
+
+ if (TYPE_PTRMEM_P (type))
+ /* For a non-type template-parameter of type pointer to data
+ member, qualification conversions (_conv.qual_) are
+ applied. */
+ return perform_qualification_conversions (type, expr);
+ else if (TREE_CODE (type_pointed_to) == FUNCTION_TYPE)
+ {
+ /* For a non-type template-parameter of type pointer to
+ function, only the function-to-pointer conversion
+ (_conv.func_) is applied. If the template-argument
+ represents a set of overloaded functions (or a pointer to
+ such), the matching function is selected from the set
+ (_over.over_). */
+ tree fns;
+ tree fn;
+
+ if (TREE_CODE (expr) == ADDR_EXPR)
+ fns = TREE_OPERAND (expr, 0);
+ else
+ fns = expr;
+
+ fn = instantiate_type (type_pointed_to, fns, 0);
+
+ if (fn == error_mark_node)
+ return error_mark_node;
+
+ if (!TREE_PUBLIC (fn))
+ {
+ if (really_overloaded_fn (fns))
+ return error_mark_node;
+ else
+ goto bad_argument;
+ }
+
+ expr = build_unary_op (ADDR_EXPR, fn, 0);
+
+ my_friendly_assert (comptypes (type, TREE_TYPE (expr), 1),
+ 0);
+ return expr;
+ }
+ else
+ {
+ /* For a non-type template-parameter of type pointer to
+ object, qualification conversions (_conv.qual_) and the
+ array-to-pointer conversion (_conv.array_) are applied.
+ [Note: In particular, neither the null pointer conversion
+ (_conv.ptr_) nor the derived-to-base conversion
+ (_conv.ptr_) are applied. Although 0 is a valid
+ template-argument for a non-type template-parameter of
+ integral type, it is not a valid template-argument for a
+ non-type template-parameter of pointer type.]
+
+ The call to decay_conversion performs the
+ array-to-pointer conversion, if appropriate. */
+ expr = decay_conversion (expr);
+
+ if (expr == error_mark_node)
+ return error_mark_node;
+ else
+ return perform_qualification_conversions (type, expr);
+ }
+ }
+ break;
+
+ case REFERENCE_TYPE:
+ {
+ tree type_referred_to = TREE_TYPE (type);
+
+ if (TREE_CODE (type_referred_to) == FUNCTION_TYPE)
+ {
+ /* For a non-type template-parameter of type reference to
+ function, no conversions apply. If the
+ template-argument represents a set of overloaded
+ functions, the matching function is selected from the
+ set (_over.over_). */
+ tree fns = expr;
+ tree fn;
+
+ fn = instantiate_type (type_referred_to, fns, 0);
+
+ if (!TREE_PUBLIC (fn))
+ {
+ if (really_overloaded_fn (fns))
+ /* Don't issue an error here; we might get a different
+ function if the overloading had worked out
+ differently. */
+ return error_mark_node;
+ else
+ goto bad_argument;
+ }
+
+ if (fn == error_mark_node)
+ return error_mark_node;
+
+ my_friendly_assert (comptypes (type, TREE_TYPE (fn), 1),
+ 0);
+
+ return fn;
+ }
+ else
+ {
+ /* For a non-type template-parameter of type reference to
+ object, no conversions apply. The type referred to by the
+ reference may be more cv-qualified than the (otherwise
+ identical) type of the template-argument. The
+ template-parameter is bound directly to the
+ template-argument, which must be an lvalue. */
+ if (!comptypes (TYPE_MAIN_VARIANT (expr_type),
+ TYPE_MAIN_VARIANT (type), 1)
+ || (TYPE_READONLY (expr_type) >
+ TYPE_READONLY (type_referred_to))
+ || (TYPE_VOLATILE (expr_type) >
+ TYPE_VOLATILE (type_referred_to))
+ || !real_lvalue_p (expr))
+ return error_mark_node;
+ else
+ return expr;
+ }
+ }
+ break;
+
+ case RECORD_TYPE:
+ {
+ tree fns;
+ tree fn;
+
+ if (!TYPE_PTRMEMFUNC_P (type))
+ /* This handles templates like
+ template<class T, T t> void f();
+ when T is substituted with any class. The second template
+ parameter becomes invalid and the template candidate is
+ rejected. */
+ return error_mark_node;
+
+ /* For a non-type template-parameter of type pointer to member
+ function, no conversions apply. If the template-argument
+ represents a set of overloaded member functions, the
+ matching member function is selected from the set
+ (_over.over_). */
+
+ if (!TYPE_PTRMEMFUNC_P (expr_type) &&
+ expr_type != unknown_type_node)
+ return error_mark_node;
+
+ if (TREE_CODE (expr) == CONSTRUCTOR)
+ {
+ /* A ptr-to-member constant. */
+ if (!comptypes (type, expr_type, 1))
+ return error_mark_node;
+ else
+ return expr;
+ }
+
+ if (TREE_CODE (expr) != ADDR_EXPR)
+ return error_mark_node;
+
+ fns = TREE_OPERAND (expr, 0);
+
+ fn = instantiate_type (TREE_TYPE (TREE_TYPE (type)),
+ fns, 0);
+
+ if (fn == error_mark_node)
+ return error_mark_node;
+
+ expr = build_unary_op (ADDR_EXPR, fn, 0);
+
+ my_friendly_assert (comptypes (type, TREE_TYPE (expr), 1),
+ 0);
+ return expr;
+ }
+ break;
+
+ default:
+ /* All non-type parameters must have one of these types. */
+ my_friendly_abort (0);
+ break;
+ }
+
+ return error_mark_node;
}
-tree tsubst PROTO ((tree, tree*, int, tree));
+/* Return 1 if PARM_PARMS and ARG_PARMS matches using rule for
+ template template parameters. Both PARM_PARMS and ARG_PARMS are
+ vectors of TREE_LIST nodes containing TYPE_DECL, TEMPLATE_DECL
+ or PARM_DECL.
+
+ ARG_PARMS may contain more parameters than PARM_PARMS. If this is
+ the case, then extra parameters must have default arguments.
+
+ Consider the example:
+ template <class T, class Allocator = allocator> class vector;
+ template<template <class U> class TT> class C;
+
+ C<vector> is a valid instantiation. PARM_PARMS for the above code
+ contains a TYPE_DECL (for U), ARG_PARMS contains two TYPE_DECLs (for
+ T and Allocator) and OUTER_ARGS contains the argument that is used to
+ substitute the TT parameter. */
+
+static int
+coerce_template_template_parms (parm_parms, arg_parms, in_decl, outer_args)
+ tree parm_parms, arg_parms, in_decl, outer_args;
+{
+ int nparms, nargs, i;
+ tree parm, arg;
+
+ my_friendly_assert (TREE_CODE (parm_parms) == TREE_VEC, 0);
+ my_friendly_assert (TREE_CODE (arg_parms) == TREE_VEC, 0);
+
+ nparms = TREE_VEC_LENGTH (parm_parms);
+ nargs = TREE_VEC_LENGTH (arg_parms);
+
+ /* The rule here is opposite of coerce_template_parms. */
+ if (nargs < nparms
+ || (nargs > nparms
+ && TREE_PURPOSE (TREE_VEC_ELT (arg_parms, nparms)) == NULL_TREE))
+ return 0;
+
+ for (i = 0; i < nparms; ++i)
+ {
+ parm = TREE_VALUE (TREE_VEC_ELT (parm_parms, i));
+ arg = TREE_VALUE (TREE_VEC_ELT (arg_parms, i));
+
+ if (arg == NULL_TREE || arg == error_mark_node
+ || parm == NULL_TREE || parm == error_mark_node)
+ return 0;
+
+ if (TREE_CODE (arg) != TREE_CODE (parm))
+ return 0;
+
+ switch (TREE_CODE (parm))
+ {
+ case TYPE_DECL:
+ break;
+
+ case TEMPLATE_DECL:
+ /* We encounter instantiations of templates like
+ template <template <template <class> class> class TT>
+ class C; */
+ sorry ("nested template template parameter");
+ return 0;
+
+ case PARM_DECL:
+ /* The tsubst call is used to handle cases such as
+ template <class T, template <T> class TT> class D;
+ i.e. the parameter list of TT depends on earlier parameters. */
+ if (!comptypes (tsubst (TREE_TYPE (parm), outer_args, in_decl),
+ TREE_TYPE (arg), 1))
+ return 0;
+ break;
+
+ default:
+ my_friendly_abort (0);
+ }
+ }
+ return 1;
+}
/* Convert all template arguments to their appropriate types, and return
a vector containing the resulting values. If any error occurs, return
- error_mark_node. */
+ error_mark_node, and, if COMPLAIN is non-zero, issue an error message.
+ Some error messages are issued even if COMPLAIN is zero; for
+ instance, if a template argument is composed from a local class.
+
+ If REQUIRE_ALL_ARGUMENTS is non-zero, all arguments must be
+ provided in ARGLIST, or else trailing parameters must have default
+ values. If REQUIRE_ALL_ARGUMENTS is zero, we will attempt argument
+ deduction for any unspecified trailing arguments. */
+
static tree
-coerce_template_parms (parms, arglist, in_decl)
+coerce_template_parms (parms, arglist, in_decl,
+ complain,
+ require_all_arguments)
tree parms, arglist;
tree in_decl;
+ int complain;
+ int require_all_arguments;
{
int nparms, nargs, i, lost = 0;
- tree vec;
+ tree vec = NULL_TREE;
if (arglist == NULL_TREE)
nargs = 0;
@@ -352,25 +2472,34 @@ coerce_template_parms (parms, arglist, in_decl)
if (nargs > nparms
|| (nargs < nparms
+ && require_all_arguments
&& TREE_PURPOSE (TREE_VEC_ELT (parms, nargs)) == NULL_TREE))
{
- error ("incorrect number of parameters (%d, should be %d)",
- nargs, nparms);
- if (in_decl)
- cp_error_at ("in template expansion for decl `%D'", in_decl);
+ if (complain)
+ {
+ error ("incorrect number of parameters (%d, should be %d)",
+ nargs, nparms);
+
+ if (in_decl)
+ cp_error_at ("in template expansion for decl `%D'",
+ in_decl);
+ }
+
return error_mark_node;
}
- if (arglist && TREE_CODE (arglist) == TREE_VEC)
+ if (arglist && TREE_CODE (arglist) == TREE_VEC && nargs == nparms)
vec = copy_node (arglist);
else
{
vec = make_tree_vec (nparms);
+
for (i = 0; i < nparms; i++)
{
tree arg;
+ tree parm = TREE_VEC_ELT (parms, i);
- if (arglist)
+ if (arglist && TREE_CODE (arglist) == TREE_LIST)
{
arg = arglist;
arglist = TREE_CHAIN (arglist);
@@ -380,8 +2509,21 @@ coerce_template_parms (parms, arglist, in_decl)
else
arg = TREE_VALUE (arg);
}
+ else if (i < nargs)
+ {
+ arg = TREE_VEC_ELT (arglist, i);
+ if (arg == error_mark_node)
+ lost++;
+ }
+ else if (TREE_PURPOSE (parm) == NULL_TREE)
+ {
+ my_friendly_assert (!require_all_arguments, 0);
+ break;
+ }
+ else if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL)
+ arg = tsubst (TREE_PURPOSE (parm), vec, in_decl);
else
- arg = TREE_PURPOSE (TREE_VEC_ELT (parms, i));
+ arg = tsubst_expr (TREE_PURPOSE (parm), vec, in_decl);
TREE_VEC_ELT (vec, i) = arg;
}
@@ -391,77 +2533,184 @@ coerce_template_parms (parms, arglist, in_decl)
tree arg = TREE_VEC_ELT (vec, i);
tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i));
tree val = 0;
- int is_type, requires_type;
+ int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
- is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't';
- requires_type = TREE_CODE (parm) == TYPE_DECL;
+ if (arg == NULL_TREE)
+ /* We're out of arguments. */
+ {
+ my_friendly_assert (!require_all_arguments, 0);
+ break;
+ }
+
+ if (arg == error_mark_node)
+ {
+ cp_error ("template argument %d is invalid", i + 1);
+ lost++;
+ continue;
+ }
+
+ if (TREE_CODE (arg) == TREE_LIST
+ && TREE_TYPE (arg) != NULL_TREE
+ && TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE)
+ {
+ /* The template argument was the name of some
+ member function. That's usually
+ illegal, but static members are OK. In any
+ case, grab the underlying fields/functions
+ and issue an error later if required. */
+ arg = TREE_VALUE (arg);
+ TREE_TYPE (arg) = unknown_type_node;
+ }
+
+ requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL;
+ requires_type = TREE_CODE (parm) == TYPE_DECL
+ || requires_tmpl_type;
+
+ /* Check if it is a class template. If REQUIRES_TMPL_TYPE is true,
+ we also accept implicitly created TYPE_DECL as a valid argument.
+ This is necessary to handle the case where we pass a template name
+ to a template template parameter in a scope where we've derived from
+ in instantiation of that template, so the template name refers to that
+ instantiation. We really ought to handle this better. */
+ is_tmpl_type = (TREE_CODE (arg) == TEMPLATE_DECL
+ && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)
+ || (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM
+ && !CLASSTYPE_TEMPLATE_INFO (arg))
+ || (TREE_CODE (arg) == RECORD_TYPE
+ && CLASSTYPE_TEMPLATE_INFO (arg)
+ && TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL
+ && DECL_ARTIFICIAL (TYPE_NAME (arg))
+ && requires_tmpl_type
+ && current_class_type
+ /* FIXME what about nested types? */
+ && get_binfo (arg, current_class_type, 0));
+ if (is_tmpl_type && TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+ arg = TYPE_STUB_DECL (arg);
+ else if (is_tmpl_type && TREE_CODE (arg) == RECORD_TYPE)
+ arg = CLASSTYPE_TI_TEMPLATE (arg);
+
+ is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't' || is_tmpl_type;
+
+ if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF
+ && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM)
+ {
+ cp_pedwarn ("to refer to a type member of a template parameter,");
+ cp_pedwarn (" use `typename %E'", arg);
+
+ arg = make_typename_type (TREE_OPERAND (arg, 0),
+ TREE_OPERAND (arg, 1));
+ is_type = 1;
+ }
if (is_type != requires_type)
{
if (in_decl)
- cp_error ("type/value mismatch in template parameter list for `%D'",
- in_decl);
+ {
+ if (complain)
+ {
+ cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
+ i + 1, in_decl);
+ if (is_type)
+ cp_error (" expected a constant of type `%T', got `%T'",
+ TREE_TYPE (parm),
+ (is_tmpl_type ? DECL_NAME (arg) : arg));
+ else
+ cp_error (" expected a type, got `%E'", arg);
+ }
+ }
lost++;
TREE_VEC_ELT (vec, i) = error_mark_node;
continue;
}
- if (is_type)
- val = groktypename (arg);
- else
+ if (is_tmpl_type ^ requires_tmpl_type)
{
- tree t = tsubst (TREE_TYPE (parm), &TREE_VEC_ELT (vec, 0),
- TREE_VEC_LENGTH (vec), in_decl);
- val = digest_init (t, arg, (tree *) 0);
-
- if (val == error_mark_node)
- ;
-
- /* 14.2: Other template-arguments must be constant-expressions,
- addresses of objects or functions with external linkage, or of
- static class members. */
- else if (!TREE_CONSTANT (val))
+ if (in_decl && complain)
{
- cp_error ("non-const `%E' cannot be used as template argument",
- arg);
- val = error_mark_node;
+ cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
+ i + 1, in_decl);
+ if (is_tmpl_type)
+ cp_error (" expected a type, got `%T'", DECL_NAME (arg));
+ else
+ cp_error (" expected a class template, got `%T'", arg);
}
- else if (POINTER_TYPE_P (TREE_TYPE (val))
- && ! integer_zerop (val)
- && TREE_CODE (TREE_TYPE (TREE_TYPE (val))) != OFFSET_TYPE
- && TREE_CODE (TREE_TYPE (TREE_TYPE (val))) != METHOD_TYPE)
+ lost++;
+ TREE_VEC_ELT (vec, i) = error_mark_node;
+ continue;
+ }
+
+ if (is_type)
+ {
+ if (requires_tmpl_type)
{
- t = val;
- STRIP_NOPS (t);
- if (TREE_CODE (t) == ADDR_EXPR)
+ tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
+ tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
+
+ if (coerce_template_template_parms (parmparm, argparm,
+ in_decl, vec))
{
- tree a = TREE_OPERAND (t, 0);
- STRIP_NOPS (a);
- if (TREE_CODE (a) == STRING_CST)
- {
- cp_error ("string literal %E is not a valid template argument", a);
- error ("because it is the address of an object with static linkage");
- val = error_mark_node;
- }
- else if (TREE_CODE (a) != VAR_DECL
- && TREE_CODE (a) != FUNCTION_DECL)
- goto bad;
- else if (! DECL_PUBLIC (a))
- {
- cp_error ("address of non-extern `%E' cannot be used as template argument", a);
- val = error_mark_node;
- }
+ val = arg;
+
+ /* TEMPLATE_TEMPLATE_PARM node is preferred over
+ TEMPLATE_DECL. */
+ if (val != error_mark_node
+ && DECL_TEMPLATE_TEMPLATE_PARM_P (val))
+ val = TREE_TYPE (val);
}
else
{
- bad:
- cp_error ("`%E' is not a valid template argument", t);
- error ("it must be %s%s with external linkage",
- TREE_CODE (TREE_TYPE (val)) == POINTER_TYPE
- ? "a pointer to " : "",
- TREE_CODE (TREE_TYPE (TREE_TYPE (val))) == FUNCTION_TYPE
- ? "a function" : "an object");
+ if (in_decl && complain)
+ {
+ cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
+ i + 1, in_decl);
+ cp_error (" expected a template of type `%D', got `%D'", parm, arg);
+ }
+
val = error_mark_node;
}
}
+ else
+ {
+ val = groktypename (arg);
+ if (! processing_template_decl)
+ {
+ tree t = target_type (val);
+ if (((IS_AGGR_TYPE (t) && TREE_CODE (t) != TYPENAME_TYPE)
+ || TREE_CODE (t) == ENUMERAL_TYPE)
+ && decl_function_context (TYPE_MAIN_DECL (t)))
+ {
+ cp_error ("type `%T' composed from a local type is not a valid template-argument",
+ val);
+ return error_mark_node;
+ }
+ }
+ }
+ }
+ else
+ {
+ tree t = tsubst (TREE_TYPE (parm), vec, in_decl);
+
+ if (processing_template_decl)
+ arg = maybe_fold_nontype_arg (arg);
+
+ if (!uses_template_parms (arg) && !uses_template_parms (t))
+ /* We used to call digest_init here. However, digest_init
+ will report errors, which we don't want when complain
+ is zero. More importantly, digest_init will try too
+ hard to convert things: for example, `0' should not be
+ converted to pointer type at this point according to
+ the standard. Accepting this is not merely an
+ extension, since deciding whether or not these
+ conversions can occur is part of determining which
+ function template to call, or whether a given epxlicit
+ argument specification is legal. */
+ val = convert_nontype_argument (t, arg);
+ else
+ val = arg;
+
+ if (val == NULL_TREE)
+ val = error_mark_node;
+ else if (val == error_mark_node && complain)
+ cp_error ("could not convert template argument `%E' to `%T'",
+ arg, t);
}
if (val == error_mark_node)
@@ -474,24 +2723,63 @@ coerce_template_parms (parms, arglist, in_decl)
return vec;
}
+/* Renturns 1 iff the OLDARGS and NEWARGS are in fact identical sets
+ of template arguments. Returns 0 otherwise. */
+
+int
+comp_template_args (oldargs, newargs)
+ tree oldargs, newargs;
+{
+ int i;
+
+ if (TREE_VEC_LENGTH (oldargs) != TREE_VEC_LENGTH (newargs))
+ return 0;
+
+ for (i = 0; i < TREE_VEC_LENGTH (oldargs); ++i)
+ {
+ tree nt = TREE_VEC_ELT (newargs, i);
+ tree ot = TREE_VEC_ELT (oldargs, i);
+
+ if (nt == ot)
+ continue;
+ if (TREE_CODE (nt) != TREE_CODE (ot))
+ return 0;
+ if (TREE_CODE (nt) == TREE_VEC)
+ {
+ /* For member templates */
+ if (comp_template_args (nt, ot))
+ continue;
+ }
+ else if (TREE_CODE_CLASS (TREE_CODE (ot)) == 't')
+ {
+ if (comptypes (ot, nt, 1))
+ continue;
+ }
+ else if (cp_tree_equal (ot, nt) > 0)
+ continue;
+ return 0;
+ }
+ return 1;
+}
+
/* Given class template name and parameter list, produce a user-friendly name
for the instantiation. */
+
static char *
-mangle_class_name_for_template (name, parms, arglist)
+mangle_class_name_for_template (name, parms, arglist, ctx)
char *name;
tree parms, arglist;
+ tree ctx;
{
static struct obstack scratch_obstack;
static char *scratch_firstobj;
int i, nparms;
if (!scratch_firstobj)
- {
- gcc_obstack_init (&scratch_obstack);
- scratch_firstobj = obstack_alloc (&scratch_obstack, 1);
- }
+ gcc_obstack_init (&scratch_obstack);
else
obstack_free (&scratch_obstack, scratch_firstobj);
+ scratch_firstobj = obstack_alloc (&scratch_obstack, 1);
#if 0
#define buflen sizeof(buf)
@@ -506,6 +2794,21 @@ mangle_class_name_for_template (name, parms, arglist)
#define cat(s) obstack_grow (&scratch_obstack, (s), strlen (s))
#endif
+ if (ctx && ctx != global_namespace)
+ {
+ char* s;
+
+ if (TREE_CODE (ctx) == FUNCTION_DECL)
+ s = fndecl_as_string (ctx, 0);
+ else if (TREE_CODE_CLASS (TREE_CODE (ctx)) == 't')
+ s = type_as_string_real (ctx, 0, 1);
+ else if (TREE_CODE (ctx) == NAMESPACE_DECL)
+ s = decl_as_string (ctx, 0);
+ else
+ my_friendly_abort (0);
+ cat (s);
+ cat ("::");
+ }
cat (name);
ccat ('<');
nparms = TREE_VEC_LENGTH (parms);
@@ -520,7 +2823,27 @@ mangle_class_name_for_template (name, parms, arglist)
if (TREE_CODE (parm) == TYPE_DECL)
{
- cat (type_as_string (arg, 0));
+ cat (type_as_string_real (arg, 0, 1));
+ continue;
+ }
+ else if (TREE_CODE (parm) == TEMPLATE_DECL)
+ {
+ if (TREE_CODE (arg) == TEMPLATE_DECL)
+ {
+ /* Already substituted with real template. Just output
+ the template name here */
+ tree context = DECL_CONTEXT (arg);
+ if (context)
+ {
+ my_friendly_assert (TREE_CODE (context) == NAMESPACE_DECL, 980422);
+ cat(decl_as_string (DECL_CONTEXT (arg), 0));
+ cat("::");
+ }
+ cat (IDENTIFIER_POINTER (DECL_NAME (arg)));
+ }
+ else
+ /* Output the parameter declaration */
+ cat (type_as_string_real (arg, 0, 1));
continue;
}
else
@@ -560,6 +2883,100 @@ mangle_class_name_for_template (name, parms, arglist)
return NULL;
}
+static tree
+classtype_mangled_name (t)
+ tree t;
+{
+ if (CLASSTYPE_TEMPLATE_INFO (t)
+ && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (t)))
+ {
+ tree name = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
+ /* We do not pass in the context here since that is only needed
+ when mangling the name of instantiations, not the primary
+ template declaration. In reality, it should not be needed
+ then either, but the way lookup_template_class operates
+ requires the context for the moment. In the long run,
+ lookup_template_class should not be looking for existing
+ instantiations by matching mangled names, but rather by
+ matching the templates, and then scanning the instantiation
+ list. */
+ char *mangled_name = mangle_class_name_for_template
+ (IDENTIFIER_POINTER (name),
+ DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (t)),
+ CLASSTYPE_TI_ARGS (t), NULL_TREE);
+ tree id = get_identifier (mangled_name);
+ IDENTIFIER_TEMPLATE (id) = name;
+ return id;
+ }
+ else
+ return TYPE_IDENTIFIER (t);
+}
+
+static void
+add_pending_template (d)
+ tree d;
+{
+ tree ti;
+
+ if (TREE_CODE_CLASS (TREE_CODE (d)) == 't')
+ ti = CLASSTYPE_TEMPLATE_INFO (d);
+ else
+ ti = DECL_TEMPLATE_INFO (d);
+
+ if (TI_PENDING_TEMPLATE_FLAG (ti))
+ return;
+
+ *template_tail = perm_tree_cons
+ (build_srcloc_here (), d, NULL_TREE);
+ template_tail = &TREE_CHAIN (*template_tail);
+ TI_PENDING_TEMPLATE_FLAG (ti) = 1;
+}
+
+
+/* Return a TEMPLATE_ID_EXPR corresponding to the indicated FNS (which
+ may be either a _DECL or an overloaded function or an
+ IDENTIFIER_NODE), and ARGLIST. */
+
+tree
+lookup_template_function (fns, arglist)
+ tree fns, arglist;
+{
+ tree type;
+
+ if (fns == NULL_TREE)
+ {
+ cp_error ("non-template used as template");
+ return error_mark_node;
+ }
+
+ if (arglist != NULL_TREE && !TREE_PERMANENT (arglist))
+ copy_to_permanent (arglist);
+
+ type = TREE_TYPE (fns);
+ if (TREE_CODE (fns) == OVERLOAD || !type)
+ type = unknown_type_node;
+
+ return build_min (TEMPLATE_ID_EXPR, type, fns, arglist);
+}
+
+/* Within the scope of a template class S<T>, the name S gets bound
+ (in build_self_reference) to a TYPE_DECL for the class, not a
+ TEMPLATE_DECL. If DECL is a TYPE_DECL for current_class_type,
+ or one of its enclosing classes, and that type is a template,
+ return the associated TEMPLATE_DECL. Otherwise, the original
+ DECL is returned. */
+
+tree
+maybe_get_template_decl_from_type_decl (decl)
+ tree decl;
+{
+ return (decl != NULL_TREE
+ && TREE_CODE (decl) == TYPE_DECL
+ && DECL_ARTIFICIAL (decl)
+ && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
+ ? CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)) : decl;
+}
+
/* Given an IDENTIFIER_NODE (type TEMPLATE_DECL) and a chain of
parameters, find the desired type.
@@ -568,26 +2985,75 @@ mangle_class_name_for_template (name, parms, arglist)
to keep it from being reclaimed when the decl storage is reclaimed.
IN_DECL, if non-NULL, is the template declaration we are trying to
- instantiate. */
+ instantiate.
+
+ If the template class is really a local class in a template
+ function, then the FUNCTION_CONTEXT is the function in which it is
+ being instantiated. */
+
tree
-lookup_template_class (d1, arglist, in_decl)
+lookup_template_class (d1, arglist, in_decl, context)
tree d1, arglist;
tree in_decl;
+ tree context;
{
- tree template, parmlist;
+ tree template = NULL_TREE, parmlist;
char *mangled_name;
- tree id;
+ tree id, t;
+
+ if (TREE_CODE (d1) == IDENTIFIER_NODE)
+ {
+ if (IDENTIFIER_LOCAL_VALUE (d1)
+ && DECL_TEMPLATE_TEMPLATE_PARM_P (IDENTIFIER_LOCAL_VALUE (d1)))
+ template = IDENTIFIER_LOCAL_VALUE (d1);
+ else
+ {
+ if (context)
+ push_decl_namespace (context);
+ if (current_class_type != NULL_TREE)
+ template =
+ maybe_get_template_decl_from_type_decl
+ (IDENTIFIER_CLASS_VALUE (d1));
+ if (template == NULL_TREE)
+ template = lookup_name_nonclass (d1);
+ if (context)
+ pop_decl_namespace ();
+ }
+ if (template)
+ context = DECL_CONTEXT (template);
+ }
+ else if (TREE_CODE (d1) == TYPE_DECL && IS_AGGR_TYPE (TREE_TYPE (d1)))
+ {
+ if (CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (d1)) == NULL_TREE)
+ return error_mark_node;
+ template = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (d1));
+ d1 = DECL_NAME (template);
+ }
+ else if (TREE_CODE_CLASS (TREE_CODE (d1)) == 't' && IS_AGGR_TYPE (d1))
+ {
+ template = CLASSTYPE_TI_TEMPLATE (d1);
+ d1 = DECL_NAME (template);
+ }
+ else if (TREE_CODE (d1) == TEMPLATE_DECL
+ && TREE_CODE (DECL_RESULT (d1)) == TYPE_DECL)
+ {
+ template = d1;
+ d1 = DECL_NAME (template);
+ context = DECL_CONTEXT (template);
+ }
+ else
+ my_friendly_abort (272);
- my_friendly_assert (TREE_CODE (d1) == IDENTIFIER_NODE, 272);
- template = IDENTIFIER_GLOBAL_VALUE (d1); /* XXX */
- if (! template)
- template = IDENTIFIER_CLASS_VALUE (d1);
/* With something like `template <class T> class X class X { ... };'
we could end up with D1 having nothing but an IDENTIFIER_LOCAL_VALUE.
We don't want to do that, but we have to deal with the situation, so
let's give them some syntax errors to chew on instead of a crash. */
if (! template)
return error_mark_node;
+
+ if (context == NULL_TREE)
+ context = global_namespace;
+
if (TREE_CODE (template) != TEMPLATE_DECL)
{
cp_error ("non-template type `%T' used as a template", d1);
@@ -595,123 +3061,205 @@ lookup_template_class (d1, arglist, in_decl)
cp_error_at ("for template declaration `%D'", in_decl);
return error_mark_node;
}
- parmlist = DECL_TEMPLATE_PARMS (template);
- arglist = coerce_template_parms (parmlist, arglist, template);
- if (arglist == error_mark_node)
- return error_mark_node;
- if (uses_template_parms (arglist))
- {
- tree t = make_lang_type (UNINSTANTIATED_P_TYPE);
- tree d;
- id = make_anon_name ();
- d = build_decl (TYPE_DECL, id, t);
- TYPE_NAME (t) = d;
- TYPE_VALUES (t) = build_tree_list (template, arglist);
- pushdecl_top_level (d);
- }
- else
- {
- mangled_name = mangle_class_name_for_template (IDENTIFIER_POINTER (d1),
- parmlist, arglist);
- id = get_identifier (mangled_name);
- }
- if (!IDENTIFIER_TEMPLATE (id))
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (template))
{
- arglist = copy_to_permanent (arglist);
- IDENTIFIER_TEMPLATE (id) = perm_tree_cons (template, arglist, NULL_TREE);
- }
- return id;
-}
-
-void
-push_template_decls (parmlist, arglist, class_level)
- tree parmlist, arglist;
- int class_level;
-{
- int i, nparms;
+ /* Create a new TEMPLATE_DECL and TEMPLATE_TEMPLATE_PARM node to store
+ template arguments */
- /* Don't want to push values into global context. */
- if (!class_level)
- {
- pushlevel (1);
- declare_pseudo_global_level ();
- }
+ tree parm = copy_template_template_parm (TREE_TYPE (template));
+ tree template2 = TYPE_STUB_DECL (parm);
+ tree arglist2;
- nparms = TREE_VEC_LENGTH (parmlist);
+ CLASSTYPE_GOT_SEMICOLON (parm) = 1;
+ parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
- for (i = 0; i < nparms; i++)
+ arglist2 = coerce_template_parms (parmlist, arglist, template, 1, 1);
+ if (arglist2 == error_mark_node)
+ return error_mark_node;
+
+ arglist2 = copy_to_permanent (arglist2);
+ CLASSTYPE_TEMPLATE_INFO (parm)
+ = perm_tree_cons (template2, arglist2, NULL_TREE);
+ TYPE_SIZE (parm) = 0;
+ return parm;
+ }
+ else if (PRIMARY_TEMPLATE_P (template)
+ || (TREE_CODE (TYPE_CONTEXT (TREE_TYPE (template)))
+ == FUNCTION_DECL))
{
- int requires_type, is_type;
- tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
- tree arg = TREE_VEC_ELT (arglist, i);
- tree decl = 0;
+ tree arglist_for_mangling;
- requires_type = TREE_CODE (parm) == TYPE_DECL;
- is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't';
- if (is_type)
+ parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
+
+ if (/* ARGLIST can be NULL_TREE if there are default arguments. */
+ arglist != NULL_TREE
+ && TREE_CODE (arglist) == TREE_VEC
+ && TREE_VEC_LENGTH (arglist) > 1
+ && list_length (DECL_TEMPLATE_PARMS (template)) > 1)
{
- /* add typename to namespace */
- if (!requires_type)
- {
- error ("template use error: type provided where value needed");
- continue;
- }
- decl = arg;
- my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (decl)) == 't', 273);
- decl = build_decl (TYPE_DECL, DECL_NAME (parm), decl);
+ /* We have multiple levels of arguments to coerce, at once. */
+ tree new_args =
+ make_tree_vec (list_length (DECL_TEMPLATE_PARMS (template)));
+ int i;
+
+ for (i = TREE_VEC_LENGTH (arglist) - 1,
+ t = DECL_TEMPLATE_PARMS (template);
+ i >= 0 && t != NULL_TREE;
+ --i, t = TREE_CHAIN (t))
+ TREE_VEC_ELT (new_args, i) =
+ coerce_template_parms (TREE_VALUE (t),
+ TREE_VEC_ELT (arglist, i),
+ template, 1, 1);
+ arglist = new_args;
}
else
+ arglist = coerce_template_parms (parmlist,
+ innermost_args (arglist, 0),
+ template, 1, 1);
+ if (arglist == error_mark_node)
+ return error_mark_node;
+ if (uses_template_parms (arglist))
{
- /* add const decl to namespace */
- tree val;
- tree parmtype;
- if (requires_type)
+ tree found;
+ if (comp_template_args
+ (CLASSTYPE_TI_ARGS (TREE_TYPE (template)), arglist))
+ found = TREE_TYPE (template);
+ else
{
- error ("template use error: value provided where type needed");
- continue;
+ for (found = DECL_TEMPLATE_INSTANTIATIONS (template);
+ found; found = TREE_CHAIN (found))
+ {
+ if (TI_USES_TEMPLATE_PARMS (found)
+ && comp_template_args (TREE_PURPOSE (found), arglist))
+ break;
+ }
+ if (found)
+ found = TREE_VALUE (found);
}
- parmtype = tsubst (TREE_TYPE (parm), &TREE_VEC_ELT (arglist, 0),
- TREE_VEC_LENGTH (arglist), NULL_TREE);
- val = digest_init (parmtype, arg, (tree *) 0);
- if (val != error_mark_node)
+
+ if (found)
{
- decl = build_decl (CONST_DECL, DECL_NAME (parm),
- parmtype);
- DECL_INITIAL (decl) = val;
- TREE_READONLY (decl) = 1;
+ if (can_free (&permanent_obstack, arglist))
+ obstack_free (&permanent_obstack, arglist);
+ return found;
}
}
- if (decl != 0)
+
+ if (TREE_CODE (arglist) == TREE_VEC)
+ arglist_for_mangling = innermost_args (arglist, 0);
+ else
+ arglist_for_mangling = arglist;
+
+ /* FIXME avoid duplication. */
+ mangled_name = mangle_class_name_for_template (IDENTIFIER_POINTER (d1),
+ parmlist,
+ arglist_for_mangling,
+ context);
+ id = get_identifier (mangled_name);
+ IDENTIFIER_TEMPLATE (id) = d1;
+
+ maybe_push_to_top_level (uses_template_parms (arglist));
+ t = xref_tag_from_type (TREE_TYPE (template), id, 1);
+
+ if (context != NULL_TREE)
{
- SET_DECL_ARTIFICIAL (decl);
- layout_decl (decl, 0);
- if (class_level)
- pushdecl_class_level (decl);
- else
- pushdecl (decl);
+ /* Set up the context for the type_decl correctly. Note
+ that we must clear DECL_ASSEMBLER_NAME to fool
+ build_overload_name into creating a new name. */
+ tree type_decl = TYPE_STUB_DECL (t);
+
+ TYPE_CONTEXT (t) = FROB_CONTEXT (context);
+ DECL_CONTEXT (type_decl) = FROB_CONTEXT (context);
+ DECL_ASSEMBLER_NAME (type_decl) = DECL_NAME (type_decl);
+ DECL_ASSEMBLER_NAME (type_decl) =
+ get_identifier (build_overload_name (t, 1, 1));
+ }
+
+ pop_from_top_level ();
+ }
+ else
+ {
+ tree type_ctx = TYPE_CONTEXT (TREE_TYPE (template));
+ tree args = tsubst (CLASSTYPE_TI_ARGS (type_ctx), arglist, in_decl);
+ tree ctx = lookup_template_class (type_ctx, args,
+ in_decl, NULL_TREE);
+ id = d1;
+ arglist = CLASSTYPE_TI_ARGS (ctx);
+
+ if (TYPE_BEING_DEFINED (ctx) && ctx == current_class_type)
+ {
+ int save_temp = processing_template_decl;
+ processing_template_decl = 0;
+ t = xref_tag_from_type (TREE_TYPE (template), id, 0);
+ processing_template_decl = save_temp;
+ }
+ else
+ {
+ t = lookup_nested_type_by_name (ctx, id);
+ my_friendly_assert (t != NULL_TREE, 42);
}
}
-}
-void
-pop_template_decls (parmlist, arglist, class_level)
- tree parmlist, arglist;
- int class_level;
-{
- if (!class_level)
- poplevel (0, 0, 0);
+ /* Seems to be wanted. */
+ CLASSTYPE_GOT_SEMICOLON (t) = 1;
+
+ if (! CLASSTYPE_TEMPLATE_INFO (t))
+ {
+ arglist = copy_to_permanent (arglist);
+ CLASSTYPE_TEMPLATE_INFO (t)
+ = perm_tree_cons (template, arglist, NULL_TREE);
+ DECL_TEMPLATE_INSTANTIATIONS (template) = perm_tree_cons
+ (arglist, t, DECL_TEMPLATE_INSTANTIATIONS (template));
+ TI_USES_TEMPLATE_PARMS (DECL_TEMPLATE_INSTANTIATIONS (template))
+ = uses_template_parms (arglist);
+
+ SET_CLASSTYPE_IMPLICIT_INSTANTIATION (t);
+
+ /* We need to set this again after CLASSTYPE_TEMPLATE_INFO is set up. */
+ DECL_ASSEMBLER_NAME (TYPE_MAIN_DECL (t)) = id;
+ if (! uses_template_parms (arglist))
+ DECL_ASSEMBLER_NAME (TYPE_MAIN_DECL (t))
+ = get_identifier (build_overload_name (t, 1, 1));
+
+ if (flag_external_templates && ! uses_template_parms (arglist)
+ && CLASSTYPE_INTERFACE_KNOWN (TREE_TYPE (template))
+ && ! CLASSTYPE_INTERFACE_ONLY (TREE_TYPE (template)))
+ add_pending_template (t);
+
+ if (uses_template_parms (arglist))
+ /* If the type makes use of template parameters, the
+ code that generates debugging information will crash. */
+ DECL_IGNORED_P (TYPE_STUB_DECL (t)) = 1;
+ }
+
+ return t;
}
/* Should be defined in parse.h. */
extern int yychar;
+/* For each TEMPLATE_TYPE_PARM, TEMPLATE_TEMPLATE_PARM, or
+ TEMPLATE_PARM_INDEX in T, call FN with the parameter and the DATA.
+ If FN returns non-zero, the iteration is terminated, and
+ for_each_template_parm returns 1. Otherwise, the iteration
+ continues. If FN never returns a non-zero value, the value
+ returned by for_each_template_parm is 0. If FN is NULL, it is
+ considered to be the function which always returns 1. */
+
int
-uses_template_parms (t)
+for_each_template_parm (t, fn, data)
tree t;
+ tree_fn_t fn;
+ void* data;
{
if (!t)
return 0;
+
+ if (TREE_CODE_CLASS (TREE_CODE (t)) == 't'
+ && for_each_template_parm (TYPE_CONTEXT (t), fn, data))
+ return 1;
+
switch (TREE_CODE (t))
{
case INDIRECT_REF:
@@ -719,101 +3267,137 @@ uses_template_parms (t)
/* We assume that the object must be instantiated in order to build
the COMPONENT_REF, so we test only whether the type of the
COMPONENT_REF uses template parms. */
- return uses_template_parms (TREE_TYPE (t));
+ return for_each_template_parm (TREE_TYPE (t), fn, data);
case IDENTIFIER_NODE:
if (!IDENTIFIER_TEMPLATE (t))
return 0;
- return uses_template_parms (TREE_VALUE (IDENTIFIER_TEMPLATE (t)));
+ my_friendly_abort (42);
/* aggregates of tree nodes */
case TREE_VEC:
{
int i = TREE_VEC_LENGTH (t);
while (i--)
- if (uses_template_parms (TREE_VEC_ELT (t, i)))
+ if (for_each_template_parm (TREE_VEC_ELT (t, i), fn, data))
return 1;
return 0;
}
case TREE_LIST:
- if (uses_template_parms (TREE_PURPOSE (t))
- || uses_template_parms (TREE_VALUE (t)))
+ if (for_each_template_parm (TREE_PURPOSE (t), fn, data)
+ || for_each_template_parm (TREE_VALUE (t), fn, data))
+ return 1;
+ return for_each_template_parm (TREE_CHAIN (t), fn, data);
+
+ case OVERLOAD:
+ if (for_each_template_parm (OVL_FUNCTION (t), fn, data))
return 1;
- return uses_template_parms (TREE_CHAIN (t));
+ return for_each_template_parm (OVL_CHAIN (t), fn, data);
/* constructed type nodes */
case POINTER_TYPE:
case REFERENCE_TYPE:
- return uses_template_parms (TREE_TYPE (t));
+ return for_each_template_parm (TREE_TYPE (t), fn, data);
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_FLAG (t))
- return uses_template_parms (TYPE_PTRMEMFUNC_FN_TYPE (t));
+ return for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE (t),
+ fn, data);
case UNION_TYPE:
- if (!TYPE_NAME (t))
- return 0;
- if (!TYPE_IDENTIFIER (t))
+ if (! CLASSTYPE_TEMPLATE_INFO (t))
return 0;
- return uses_template_parms (TYPE_IDENTIFIER (t));
+ return for_each_template_parm (TREE_VALUE
+ (CLASSTYPE_TEMPLATE_INFO (t)),
+ fn, data);
case FUNCTION_TYPE:
- if (uses_template_parms (TYPE_ARG_TYPES (t)))
+ if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data))
return 1;
- return uses_template_parms (TREE_TYPE (t));
+ return for_each_template_parm (TREE_TYPE (t), fn, data);
case ARRAY_TYPE:
- if (uses_template_parms (TYPE_DOMAIN (t)))
+ if (for_each_template_parm (TYPE_DOMAIN (t), fn, data))
return 1;
- return uses_template_parms (TREE_TYPE (t));
+ return for_each_template_parm (TREE_TYPE (t), fn, data);
case OFFSET_TYPE:
- if (uses_template_parms (TYPE_OFFSET_BASETYPE (t)))
+ if (for_each_template_parm (TYPE_OFFSET_BASETYPE (t), fn, data))
return 1;
- return uses_template_parms (TREE_TYPE (t));
+ return for_each_template_parm (TREE_TYPE (t), fn, data);
case METHOD_TYPE:
- if (uses_template_parms (TYPE_METHOD_BASETYPE (t)))
+ if (for_each_template_parm (TYPE_METHOD_BASETYPE (t), fn, data))
return 1;
- if (uses_template_parms (TYPE_ARG_TYPES (t)))
+ if (for_each_template_parm (TYPE_ARG_TYPES (t), fn, data))
return 1;
- return uses_template_parms (TREE_TYPE (t));
+ return for_each_template_parm (TREE_TYPE (t), fn, data);
/* decl nodes */
case TYPE_DECL:
- return uses_template_parms (DECL_NAME (t));
+ return for_each_template_parm (TREE_TYPE (t), fn, data);
+
+ case TEMPLATE_DECL:
+ /* A template template parameter is encountered */
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (t))
+ return for_each_template_parm (TREE_TYPE (t), fn, data);
+ /* Already substituted template template parameter */
+ return 0;
+
+ case CONST_DECL:
+ if (for_each_template_parm (DECL_INITIAL (t), fn, data))
+ return 1;
+ goto check_type_and_context;
+
case FUNCTION_DECL:
- if (uses_template_parms (TREE_TYPE (t)))
+ case VAR_DECL:
+ /* ??? What about FIELD_DECLs? */
+ if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t)
+ && for_each_template_parm (DECL_TI_ARGS (t), fn, data))
return 1;
/* fall through */
- case VAR_DECL:
case PARM_DECL:
- /* ??? What about FIELD_DECLs? */
- /* The type of a decl can't use template parms if the name of the
- variable doesn't, because it's impossible to resolve them. So
- ignore the type field for now. */
- if (DECL_CONTEXT (t) && uses_template_parms (DECL_CONTEXT (t)))
+ check_type_and_context:
+ if (for_each_template_parm (TREE_TYPE (t), fn, data))
+ return 1;
+ if (DECL_CONTEXT (t)
+ && for_each_template_parm (DECL_CONTEXT (t), fn, data))
return 1;
- if (uses_template_parms (TREE_TYPE (t)))
- {
- error ("template parms used where they can't be resolved");
- }
return 0;
case CALL_EXPR:
- return uses_template_parms (TREE_TYPE (t));
+ return for_each_template_parm (TREE_TYPE (t), fn, data);
case ADDR_EXPR:
- return uses_template_parms (TREE_OPERAND (t, 0));
+ return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
/* template parm nodes */
+ case TEMPLATE_TEMPLATE_PARM:
+ /* Record template parameters such as `T' inside `TT<T>'. */
+ if (CLASSTYPE_TEMPLATE_INFO (t)
+ && for_each_template_parm (CLASSTYPE_TI_ARGS (t), fn, data))
+ return 1;
case TEMPLATE_TYPE_PARM:
- case TEMPLATE_CONST_PARM:
- return 1;
+ case TEMPLATE_PARM_INDEX:
+ if (fn)
+ return (*fn)(t, data);
+ else
+ return 1;
/* simple type nodes */
case INTEGER_TYPE:
- if (uses_template_parms (TYPE_MIN_VALUE (t)))
+ if (for_each_template_parm (TYPE_MIN_VALUE (t), fn, data))
return 1;
- return uses_template_parms (TYPE_MAX_VALUE (t));
+ return for_each_template_parm (TYPE_MAX_VALUE (t), fn, data);
case REAL_TYPE:
+ case COMPLEX_TYPE:
case VOID_TYPE:
- case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
+ case NAMESPACE_DECL:
+ return 0;
+
+ case ENUMERAL_TYPE:
+ {
+ tree v;
+
+ for (v = TYPE_VALUES (t); v != NULL_TREE; v = TREE_CHAIN (v))
+ if (for_each_template_parm (TREE_VALUE (v), fn, data))
+ return 1;
+ }
return 0;
/* constants */
@@ -828,25 +3412,45 @@ uses_template_parms (t)
/* NOTREACHED */
return 0;
- case UNINSTANTIATED_P_TYPE:
+ case LOOKUP_EXPR:
+ case TYPENAME_TYPE:
return 1;
+ case SCOPE_REF:
+ return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
+
case CONSTRUCTOR:
if (TREE_TYPE (t) && TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
- return uses_template_parms (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (t)));
- /* else fall through */
+ return for_each_template_parm (TYPE_PTRMEMFUNC_FN_TYPE
+ (TREE_TYPE (t)), fn, data);
+ return for_each_template_parm (TREE_OPERAND (t, 1), fn, data);
+
+ case MODOP_EXPR:
+ case CAST_EXPR:
+ case REINTERPRET_CAST_EXPR:
+ case CONST_CAST_EXPR:
+ case STATIC_CAST_EXPR:
+ case DYNAMIC_CAST_EXPR:
+ case ARROW_EXPR:
+ case DOTSTAR_EXPR:
+ case TYPEID_EXPR:
+ return 1;
+
+ case SIZEOF_EXPR:
+ case ALIGNOF_EXPR:
+ return for_each_template_parm (TREE_OPERAND (t, 0), fn, data);
default:
switch (TREE_CODE_CLASS (TREE_CODE (t)))
{
case '1':
case '2':
- case '3':
+ case 'e':
case '<':
{
int i;
- for (i = tree_code_length[(int) TREE_CODE (t)]; --i >= 0;)
- if (uses_template_parms (TREE_OPERAND (t, i)))
+ for (i = first_rtl_op (TREE_CODE (t)); --i >= 0;)
+ if (for_each_template_parm (TREE_OPERAND (t, i), fn, data))
return 1;
return 0;
}
@@ -861,77 +3465,99 @@ uses_template_parms (t)
}
}
-void
-instantiate_member_templates (classname)
- tree classname;
+int
+uses_template_parms (t)
+ tree t;
{
- tree t;
- tree id = classname;
- tree members = DECL_TEMPLATE_MEMBERS (TREE_PURPOSE (IDENTIFIER_TEMPLATE (id)));
-
- for (t = members; t; t = TREE_CHAIN (t))
- {
- tree parmvec, type, classparms, tdecl, t2;
- int nparms, xxx = 0, i;
-
- my_friendly_assert (TREE_VALUE (t) != NULL_TREE, 275);
- my_friendly_assert (TREE_CODE (TREE_VALUE (t)) == TEMPLATE_DECL, 276);
- /* @@ Should verify that class parm list is a list of
- distinct template parameters, and covers all the template
- parameters. */
- tdecl = TREE_VALUE (t);
- type = DECL_CONTEXT (DECL_TEMPLATE_RESULT (tdecl));
- classparms = UPT_PARMS (type);
- nparms = TREE_VEC_LENGTH (classparms);
- parmvec = make_tree_vec (nparms);
- for (i = 0; i < nparms; i++)
- TREE_VEC_ELT (parmvec, i) = NULL_TREE;
- switch (unify (DECL_TEMPLATE_PARMS (tdecl),
- &TREE_VEC_ELT (parmvec, 0), nparms,
- type, IDENTIFIER_TYPE_VALUE (classname),
- &xxx))
- {
- case 0:
- /* Success -- well, no inconsistency, at least. */
- for (i = 0; i < nparms; i++)
- if (TREE_VEC_ELT (parmvec, i) == NULL_TREE)
- goto failure;
- t2 = instantiate_template (tdecl,
- &TREE_VEC_ELT (parmvec, 0));
- type = IDENTIFIER_TYPE_VALUE (id);
- my_friendly_assert (type != 0, 277);
- break;
- case 1:
- /* Failure. */
- failure:
- cp_error_at ("type unification error instantiating `%D'", tdecl);
- cp_error ("while instantiating members of `%T'", classname);
+ return for_each_template_parm (t, 0, 0);
+}
- continue /* loop of members */;
- default:
- /* Eek, a bug. */
- my_friendly_abort (83);
+static struct tinst_level *current_tinst_level;
+static struct tinst_level *free_tinst_level;
+static int tinst_depth;
+extern int max_tinst_depth;
+#ifdef GATHER_STATISTICS
+int depth_reached;
+#endif
+int tinst_level_tick;
+int last_template_error_tick;
+
+/* Print out all the template instantiations that we are currently
+ working on. If ERR, we are being called from cp_thing, so do
+ the right thing for an error message. */
+
+static void
+print_template_context (err)
+ int err;
+{
+ struct tinst_level *p = current_tinst_level;
+ int line = lineno;
+ char *file = input_filename;
+
+ if (err)
+ {
+ if (current_function_decl == p->decl)
+ /* Avoid redundancy with the the "In function" line. */;
+ else if (current_function_decl == NULL_TREE)
+ fprintf (stderr, "%s: In instantiation of `%s':\n",
+ file, decl_as_string (p->decl, 0));
+ else
+ my_friendly_abort (980521);
+
+ if (p)
+ {
+ line = p->line;
+ file = p->file;
+ p = p->next;
}
}
+
+ next:
+ for (; p; p = p->next)
+ {
+ fprintf (stderr, "%s:%d: instantiated from `%s'\n", file, line,
+ decl_as_string (p->decl, 0));
+ line = p->line;
+ file = p->file;
+ }
+ fprintf (stderr, "%s:%d: instantiated from here\n", file, line);
}
-static struct tinst_level *current_tinst_level = 0;
-static struct tinst_level *free_tinst_level = 0;
-static int tinst_depth = 0;
-int max_tinst_depth = 17;
+/* Called from cp_thing to print the template context for an error. */
-int
-push_tinst_level (name)
- tree name;
+void
+maybe_print_template_context ()
+{
+ if (last_template_error_tick == tinst_level_tick
+ || current_tinst_level == 0)
+ return;
+
+ last_template_error_tick = tinst_level_tick;
+ print_template_context (1);
+}
+
+static int
+push_tinst_level (d)
+ tree d;
{
struct tinst_level *new;
- tree global = IDENTIFIER_GLOBAL_VALUE (name);
if (tinst_depth >= max_tinst_depth)
{
+ /* If the instantiation in question still has unbound template parms,
+ we don't really care if we can't instantiate it, so just return.
+ This happens with base instantiation for implicit `typename'. */
+ if (uses_template_parms (d))
+ return 0;
+
+ last_template_error_tick = tinst_level_tick;
error ("template instantiation depth exceeds maximum of %d",
max_tinst_depth);
- cp_error (" instantiating `%D'", name);
+ error (" (use -ftemplate-depth-NN to increase the maximum)");
+ cp_error (" instantiating `%D'", d);
+
+ print_template_context (0);
+
return 0;
}
@@ -943,20 +3569,19 @@ push_tinst_level (name)
else
new = (struct tinst_level *) xmalloc (sizeof (struct tinst_level));
- new->classname = name;
- if (global)
- {
- new->line = DECL_SOURCE_LINE (global);
- new->file = DECL_SOURCE_FILE (global);
- }
- else
- {
- new->line = lineno;
- new->file = input_filename;
- }
+ new->decl = d;
+ new->line = lineno;
+ new->file = input_filename;
new->next = current_tinst_level;
current_tinst_level = new;
+
++tinst_depth;
+#ifdef GATHER_STATISTICS
+ if (tinst_depth > depth_reached)
+ depth_reached = tinst_depth;
+#endif
+
+ ++tinst_level_tick;
return 1;
}
@@ -969,6 +3594,7 @@ pop_tinst_level ()
old->next = free_tinst_level;
free_tinst_level = old;
--tinst_depth;
+ ++tinst_level_tick;
}
struct tinst_level *
@@ -982,119 +3608,485 @@ tinst_for_decl ()
return p;
}
+/* DECL is a friend FUNCTION_DECL or TEMPLATE_DECL. ARGS is the
+ vector of template arguments, as for tsubst.
+
+ Returns an appropriate tsbust'd friend declaration. */
+
+static tree
+tsubst_friend_function (decl, args)
+ tree decl;
+ tree args;
+{
+ tree new_friend;
+ int line = lineno;
+ char *file = input_filename;
+
+ lineno = DECL_SOURCE_LINE (decl);
+ input_filename = DECL_SOURCE_FILE (decl);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_TEMPLATE_INSTANTIATION (decl)
+ && TREE_CODE (DECL_TI_TEMPLATE (decl)) != TEMPLATE_DECL)
+ /* This was a friend declared with an explicit template
+ argument list, e.g.:
+
+ friend void f<>(T);
+
+ to indicate that f was a template instantiation, not a new
+ function declaration. Now, we have to figure out what
+ instantiation of what template. */
+ {
+ tree template_id;
+ tree new_args;
+ tree tmpl;
+ tree tinfo;
+
+ template_id
+ = lookup_template_function (tsubst_expr (DECL_TI_TEMPLATE (decl),
+ args, NULL_TREE),
+ tsubst (DECL_TI_ARGS (decl),
+ args, NULL_TREE));
+
+ /* Temporarily remove the DECL_TEMPLATE_INFO so as not to
+ confuse tsubst. */
+ tinfo = DECL_TEMPLATE_INFO (decl);
+ DECL_TEMPLATE_INFO (decl) = NULL_TREE;
+ new_friend = tsubst (decl, args, NULL_TREE);
+ DECL_TEMPLATE_INFO (decl) = tinfo;
+
+ tmpl = determine_specialization (template_id,
+ new_friend,
+ &new_args,
+ 0, 1);
+ new_friend = instantiate_template (tmpl, new_args);
+ goto done;
+ }
+ else
+ new_friend = tsubst (decl, args, NULL_TREE);
+
+ /* The new_friend will look like an instantiation, to the
+ compiler, but is not an instantiation from the point of view of
+ the language. For example, we might have had:
+
+ template <class T> struct S {
+ template <class U> friend void f(T, U);
+ };
+
+ Then, in S<int>, template <class U> void f(int, U) is not an
+ instantiation of anything. */
+ DECL_USE_TEMPLATE (new_friend) = 0;
+ if (TREE_CODE (decl) == TEMPLATE_DECL)
+ DECL_USE_TEMPLATE (DECL_TEMPLATE_RESULT (new_friend)) = 0;
+
+ if (DECL_NAMESPACE_SCOPE_P (new_friend))
+ {
+ if (TREE_CODE (new_friend) == TEMPLATE_DECL)
+ /* This declaration is a `primary' template. */
+ TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (new_friend))
+ = new_friend;
+
+ new_friend = pushdecl_namespace_level (new_friend);
+ }
+ else if (TYPE_SIZE (DECL_CONTEXT (new_friend)))
+ {
+ /* Check to see that the declaration is really present, and,
+ possibly obtain an improved declaration. */
+ tree fn = check_classfn (DECL_CONTEXT (new_friend),
+ new_friend);
+
+ if (fn)
+ new_friend = fn;
+ }
+
+ done:
+ lineno = line;
+ input_filename = file;
+ return new_friend;
+}
+
+/* FRIEND_TMPL is a friend TEMPLATE_DECL. ARGS is the vector of
+ template arguments, as for tsubst.
+
+ Returns an appropriate tsbust'd friend type. */
+
+static tree
+tsubst_friend_class (friend_tmpl, args)
+ tree friend_tmpl;
+ tree args;
+{
+ tree friend_type;
+ tree tmpl = lookup_name (DECL_NAME (friend_tmpl), 1);
+
+ tmpl = maybe_get_template_decl_from_type_decl (tmpl);
+
+ if (tmpl != NULL_TREE && DECL_CLASS_TEMPLATE_P (tmpl))
+ {
+ /* The friend template has already been declared. Just
+ check to see that the declarations match. */
+ redeclare_class_template (TREE_TYPE (tmpl),
+ DECL_TEMPLATE_PARMS (friend_tmpl));
+ friend_type = TREE_TYPE (tmpl);
+ }
+ else
+ {
+ /* The friend template has not already been declared. In this
+ case, the instantiation of the template class will cause the
+ injection of this template into the global scope. */
+ tmpl = tsubst (friend_tmpl, args, NULL_TREE);
+
+ /* The new TMPL is not an instantiation of anything, so we
+ forget its origins. We don't reset CLASSTYPE_TI_TEMPLATE for
+ the new type because that is supposed to be the corresponding
+ template decl, i.e., TMPL. */
+ DECL_USE_TEMPLATE (tmpl) = 0;
+ DECL_TEMPLATE_INFO (tmpl) = NULL_TREE;
+ CLASSTYPE_USE_TEMPLATE (TREE_TYPE (tmpl)) = 0;
+
+ /* Inject this template into the global scope. */
+ friend_type = TREE_TYPE (pushdecl_top_level (tmpl));
+ }
+
+ return friend_type;
+}
+
tree
-instantiate_class_template (classname, setup_parse)
- tree classname;
- int setup_parse;
+instantiate_class_template (type)
+ tree type;
{
- struct template_info *template_info;
- tree template, t1;
+ tree template, template_info, args, pattern, t, *field_chain;
+ tree typedecl, outer_args;
- if (classname == error_mark_node)
+ if (type == error_mark_node)
return error_mark_node;
- my_friendly_assert (TREE_CODE (classname) == IDENTIFIER_NODE, 278);
- template = IDENTIFIER_TEMPLATE (classname);
+ template_info = CLASSTYPE_TEMPLATE_INFO (type);
+
+ if (TYPE_BEING_DEFINED (type) || TYPE_SIZE (type))
+ return type;
- if (IDENTIFIER_HAS_TYPE_VALUE (classname))
+ template = TI_TEMPLATE (template_info);
+ my_friendly_assert (TREE_CODE (template) == TEMPLATE_DECL, 279);
+ args = TI_ARGS (template_info);
+
+ if (DECL_TEMPLATE_INFO (template))
{
- tree type = IDENTIFIER_TYPE_VALUE (classname);
- if (TREE_CODE (type) == UNINSTANTIATED_P_TYPE)
- return type;
- if (TYPE_BEING_DEFINED (type)
- || TYPE_SIZE (type)
- || CLASSTYPE_USE_TEMPLATE (type) != 0)
- return type;
+ outer_args = DECL_TI_ARGS (template);
+ while (DECL_TEMPLATE_INFO (template))
+ template = DECL_TI_TEMPLATE (template);
}
+ else
+ outer_args = NULL_TREE;
- /* If IDENTIFIER_LOCAL_VALUE is already set on this template classname
- (it's something like `foo<int>'), that means we're already working on
- the instantiation for it. Normally, a classname comes in with nothing
- but its IDENTIFIER_TEMPLATE slot set. If we were to try to instantiate
- this again, we'd get a redeclaration error. Since we're already working
- on it, we'll pass back this classname's TYPE_DECL (it's the value of
- the classname's IDENTIFIER_LOCAL_VALUE). Only do this if we're setting
- things up for the parser, though---if we're just trying to instantiate
- it (e.g., via tsubst) we can trip up cuz it may not have an
- IDENTIFIER_TYPE_VALUE when it will need one. */
- if (setup_parse && IDENTIFIER_LOCAL_VALUE (classname))
- return IDENTIFIER_LOCAL_VALUE (classname);
+ t = most_specialized_class
+ (DECL_TEMPLATE_SPECIALIZATIONS (template), args, outer_args);
- if (uses_template_parms (classname))
+ if (t == error_mark_node)
{
- if (!TREE_TYPE (classname))
+ char *str = "candidates are:";
+ cp_error ("ambiguous class template instantiation for `%#T'", type);
+ for (t = DECL_TEMPLATE_SPECIALIZATIONS (template); t; t = TREE_CHAIN (t))
{
- tree t = make_lang_type (RECORD_TYPE);
- tree d = build_decl (TYPE_DECL, classname, t);
- DECL_NAME (d) = classname;
- TYPE_NAME (t) = d;
- pushdecl (d);
+ if (get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t),
+ args, outer_args))
+ {
+ cp_error_at ("%s %+#T", str, TREE_TYPE (t));
+ str = " ";
+ }
}
- return NULL_TREE;
+ TYPE_BEING_DEFINED (type) = 1;
+ return error_mark_node;
}
+ else if (t)
+ pattern = TREE_TYPE (t);
+ else
+ pattern = TREE_TYPE (template);
- t1 = TREE_PURPOSE (template);
- my_friendly_assert (TREE_CODE (t1) == TEMPLATE_DECL, 279);
+ if (TYPE_SIZE (pattern) == NULL_TREE)
+ return type;
- /* If a template is declared but not defined, accept it; don't crash.
- Later uses requiring the definition will be flagged as errors by
- other code. Thanks to niklas@appli.se for this bug fix. */
- if (DECL_TEMPLATE_INFO (t1)->text == 0)
- setup_parse = 0;
+ if (t)
+ args = get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t),
+ args, outer_args);
- push_to_top_level ();
- template_info = DECL_TEMPLATE_INFO (t1);
- if (setup_parse && push_tinst_level (classname))
- {
- push_template_decls (DECL_TEMPLATE_PARMS (TREE_PURPOSE (template)),
- TREE_VALUE (template), 0);
- set_current_level_tags_transparency (1);
- feed_input (template_info->text, template_info->length, (struct obstack *)0);
- lineno = template_info->lineno;
- input_filename = template_info->filename;
- /* Get interface/implementation back in sync. */
- extract_interface_info ();
- overload_template_name (classname, 0);
- /* Kludge so that we don't get screwed by our own base classes. */
- TYPE_BEING_DEFINED (TREE_TYPE (classname)) = 1;
- yychar = PRE_PARSED_CLASS_DECL;
- yylval.ttype = classname;
- processing_template_defn++;
- if (!flag_external_templates)
- interface_unknown++;
- template_classes
- = perm_tree_cons (classname, NULL_TREE, template_classes);
+ if (pedantic && uses_template_parms (args))
+ /* If there are still template parameters amongst the args, then
+ we can't instantiate the type; there's no telling whether or not one
+ of the template parameters might eventually be instantiated to some
+ value that results in a specialization being used. */
+ return type;
+
+ /* We must copy the arguments to the permanent obstack since
+ during the tsubst'ing below they may wind up in the
+ DECL_TI_ARGS of some instantiated member template. */
+ args = copy_to_permanent (args);
+
+ TYPE_BEING_DEFINED (type) = 1;
+
+ if (! push_tinst_level (type))
+ return type;
+
+ maybe_push_to_top_level (uses_template_parms (type));
+ pushclass (type, 0);
+
+ if (outer_args)
+ args = add_to_template_args (outer_args, args);
+
+ if (flag_external_templates)
+ {
+ if (flag_alt_external_templates)
+ {
+ CLASSTYPE_INTERFACE_ONLY (type) = interface_only;
+ SET_CLASSTYPE_INTERFACE_UNKNOWN_X (type, interface_unknown);
+ CLASSTYPE_VTABLE_NEEDS_WRITING (type)
+ = (! CLASSTYPE_INTERFACE_ONLY (type)
+ && CLASSTYPE_INTERFACE_KNOWN (type));
+ }
+ else
+ {
+ CLASSTYPE_INTERFACE_ONLY (type) = CLASSTYPE_INTERFACE_ONLY (pattern);
+ SET_CLASSTYPE_INTERFACE_UNKNOWN_X
+ (type, CLASSTYPE_INTERFACE_UNKNOWN (pattern));
+ CLASSTYPE_VTABLE_NEEDS_WRITING (type)
+ = (! CLASSTYPE_INTERFACE_ONLY (type)
+ && CLASSTYPE_INTERFACE_KNOWN (type));
+ }
}
else
{
- tree t, decl, id, tmpl;
-
- id = classname;
- tmpl = TREE_PURPOSE (IDENTIFIER_TEMPLATE (id));
- t = xref_tag (DECL_TEMPLATE_INFO (tmpl)->aggr, id, NULL_TREE, 0);
- my_friendly_assert (TREE_CODE (t) == RECORD_TYPE
- || TREE_CODE (t) == UNION_TYPE, 280);
-
- /* Now, put a copy of the decl in global scope, to avoid
- * recursive expansion. */
- decl = IDENTIFIER_LOCAL_VALUE (id);
- if (!decl)
- decl = IDENTIFIER_CLASS_VALUE (id);
- if (decl)
- {
- my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 281);
- /* We'd better make sure we're on the permanent obstack or else
- * we'll get a "friendly" abort 124 in pushdecl. Perhaps a
- * copy_to_permanent would be sufficient here, but then a
- * sharing problem might occur. I don't know -- niklas@appli.se */
- push_obstacks (&permanent_obstack, &permanent_obstack);
- pushdecl_top_level (copy_node (decl));
- pop_obstacks ();
+ SET_CLASSTYPE_INTERFACE_UNKNOWN (type);
+ CLASSTYPE_VTABLE_NEEDS_WRITING (type) = 1;
+ }
+
+ TYPE_HAS_CONSTRUCTOR (type) = TYPE_HAS_CONSTRUCTOR (pattern);
+ TYPE_HAS_DESTRUCTOR (type) = TYPE_HAS_DESTRUCTOR (pattern);
+ TYPE_HAS_ASSIGNMENT (type) = TYPE_HAS_ASSIGNMENT (pattern);
+ TYPE_OVERLOADS_CALL_EXPR (type) = TYPE_OVERLOADS_CALL_EXPR (pattern);
+ TYPE_OVERLOADS_ARRAY_REF (type) = TYPE_OVERLOADS_ARRAY_REF (pattern);
+ TYPE_OVERLOADS_ARROW (type) = TYPE_OVERLOADS_ARROW (pattern);
+ TYPE_GETS_NEW (type) = TYPE_GETS_NEW (pattern);
+ TYPE_GETS_DELETE (type) = TYPE_GETS_DELETE (pattern);
+ TYPE_VEC_DELETE_TAKES_SIZE (type) = TYPE_VEC_DELETE_TAKES_SIZE (pattern);
+ TYPE_HAS_ASSIGN_REF (type) = TYPE_HAS_ASSIGN_REF (pattern);
+ TYPE_HAS_CONST_ASSIGN_REF (type) = TYPE_HAS_CONST_ASSIGN_REF (pattern);
+ TYPE_HAS_ABSTRACT_ASSIGN_REF (type) = TYPE_HAS_ABSTRACT_ASSIGN_REF (pattern);
+ TYPE_HAS_INIT_REF (type) = TYPE_HAS_INIT_REF (pattern);
+ TYPE_HAS_CONST_INIT_REF (type) = TYPE_HAS_CONST_INIT_REF (pattern);
+ TYPE_HAS_DEFAULT_CONSTRUCTOR (type) = TYPE_HAS_DEFAULT_CONSTRUCTOR (pattern);
+ TYPE_HAS_CONVERSION (type) = TYPE_HAS_CONVERSION (pattern);
+ TYPE_USES_COMPLEX_INHERITANCE (type)
+ = TYPE_USES_COMPLEX_INHERITANCE (pattern);
+ TYPE_USES_MULTIPLE_INHERITANCE (type)
+ = TYPE_USES_MULTIPLE_INHERITANCE (pattern);
+ TYPE_USES_VIRTUAL_BASECLASSES (type)
+ = TYPE_USES_VIRTUAL_BASECLASSES (pattern);
+ TYPE_PACKED (type) = TYPE_PACKED (pattern);
+ TYPE_ALIGN (type) = TYPE_ALIGN (pattern);
+ TYPE_FOR_JAVA (type) = TYPE_FOR_JAVA (pattern); /* For libjava's JArray<T> */
+
+ CLASSTYPE_LOCAL_TYPEDECLS (type) = CLASSTYPE_LOCAL_TYPEDECLS (pattern);
+
+ /* If this is a partial instantiation, don't tsubst anything. We will
+ only use this type for implicit typename, so the actual contents don't
+ matter. All that matters is whether a particular name is a type. */
+ if (uses_template_parms (type))
+ {
+ TYPE_BINFO_BASETYPES (type) = TYPE_BINFO_BASETYPES (pattern);
+ TYPE_FIELDS (type) = TYPE_FIELDS (pattern);
+ TYPE_METHODS (type) = TYPE_METHODS (pattern);
+ CLASSTYPE_TAGS (type) = CLASSTYPE_TAGS (pattern);
+ TYPE_SIZE (type) = integer_zero_node;
+ goto end;
+ }
+
+ {
+ tree binfo = TYPE_BINFO (type);
+ tree pbases = TYPE_BINFO_BASETYPES (pattern);
+
+ if (pbases)
+ {
+ tree bases;
+ int i;
+ int len = TREE_VEC_LENGTH (pbases);
+ bases = make_tree_vec (len);
+ for (i = 0; i < len; ++i)
+ {
+ tree elt, basetype;
+
+ TREE_VEC_ELT (bases, i) = elt
+ = tsubst (TREE_VEC_ELT (pbases, i), args, NULL_TREE);
+ BINFO_INHERITANCE_CHAIN (elt) = binfo;
+
+ basetype = TREE_TYPE (elt);
+
+ if (! IS_AGGR_TYPE (basetype))
+ cp_error
+ ("base type `%T' of `%T' fails to be a struct or class type",
+ basetype, type);
+ else if (TYPE_SIZE (complete_type (basetype)) == NULL_TREE)
+ cp_error ("base class `%T' of `%T' has incomplete type",
+ basetype, type);
+
+ /* These are set up in xref_basetypes for normal classes, so
+ we have to handle them here for template bases. */
+ if (TYPE_USES_VIRTUAL_BASECLASSES (basetype))
+ {
+ TYPE_USES_VIRTUAL_BASECLASSES (type) = 1;
+ TYPE_USES_COMPLEX_INHERITANCE (type) = 1;
+ }
+ TYPE_GETS_NEW (type) |= TYPE_GETS_NEW (basetype);
+ TYPE_GETS_DELETE (type) |= TYPE_GETS_DELETE (basetype);
+ CLASSTYPE_LOCAL_TYPEDECLS (type)
+ |= CLASSTYPE_LOCAL_TYPEDECLS (basetype);
+ }
+ /* Don't initialize this until the vector is filled out, or
+ lookups will crash. */
+ BINFO_BASETYPES (binfo) = bases;
+ }
+ }
+
+ field_chain = &TYPE_FIELDS (type);
+
+ for (t = CLASSTYPE_TAGS (pattern); t; t = TREE_CHAIN (t))
+ {
+ tree tag = TREE_VALUE (t);
+
+ /* These will add themselves to CLASSTYPE_TAGS for the new type. */
+ if (TREE_CODE (tag) == ENUMERAL_TYPE)
+ {
+ (void) tsubst_enum (tag, args, field_chain);
+ while (*field_chain)
+ {
+ DECL_FIELD_CONTEXT (*field_chain) = type;
+ field_chain = &TREE_CHAIN (*field_chain);
+ }
}
- pop_from_top_level ();
+ else
+ tsubst (tag, args, NULL_TREE);
}
- return NULL_TREE;
+ /* Don't replace enum constants here. */
+ for (t = TYPE_FIELDS (pattern); t; t = TREE_CHAIN (t))
+ if (TREE_CODE (t) != CONST_DECL)
+ {
+ tree r = tsubst (t, args, NULL_TREE);
+ if (TREE_CODE (r) == VAR_DECL)
+ {
+ pending_statics = perm_tree_cons (NULL_TREE, r, pending_statics);
+ /* Perhaps we should do more of grokfield here. */
+ start_decl_1 (r);
+ DECL_IN_AGGR_P (r) = 1;
+ DECL_EXTERNAL (r) = 1;
+ cp_finish_decl (r, DECL_INITIAL (r), NULL_TREE, 0, 0);
+ }
+
+ *field_chain = r;
+ field_chain = &TREE_CHAIN (r);
+ }
+
+ TYPE_METHODS (type) = tsubst_chain (TYPE_METHODS (pattern), args);
+
+ /* Construct the DECL_FRIENDLIST for the new class type. */
+ typedecl = TYPE_MAIN_DECL (type);
+ for (t = DECL_FRIENDLIST (TYPE_MAIN_DECL (pattern));
+ t != NULL_TREE;
+ t = TREE_CHAIN (t))
+ {
+ tree friends;
+
+ DECL_FRIENDLIST (typedecl)
+ = tree_cons (TREE_PURPOSE (t), NULL_TREE,
+ DECL_FRIENDLIST (typedecl));
+
+ for (friends = TREE_VALUE (t);
+ friends != NULL_TREE;
+ friends = TREE_CHAIN (friends))
+ {
+ if (TREE_PURPOSE (friends) == error_mark_node)
+ {
+ TREE_VALUE (DECL_FRIENDLIST (typedecl))
+ = tree_cons (error_mark_node,
+ tsubst_friend_function (TREE_VALUE (friends),
+ args),
+ TREE_VALUE (DECL_FRIENDLIST (typedecl)));
+ }
+ else
+ {
+ TREE_VALUE (DECL_FRIENDLIST (typedecl))
+ = tree_cons (tsubst (TREE_PURPOSE (friends), args, NULL_TREE),
+ NULL_TREE,
+ TREE_VALUE (DECL_FRIENDLIST (typedecl)));
+
+ }
+ }
+ }
+
+ for (t = CLASSTYPE_FRIEND_CLASSES (pattern);
+ t != NULL_TREE;
+ t = TREE_CHAIN (t))
+ {
+ tree friend_type = TREE_VALUE (t);
+ tree new_friend_type;
+
+ if (TREE_CODE (friend_type) != TEMPLATE_DECL)
+ /* The call to xref_tag_from_type does injection for friend
+ classes. */
+ new_friend_type =
+ xref_tag_from_type (tsubst (friend_type, args, NULL_TREE),
+ NULL_TREE, 1);
+ else
+ new_friend_type = tsubst_friend_class (friend_type, args);
+
+ if (TREE_CODE (friend_type) == TEMPLATE_DECL)
+ /* Trick make_friend_class into realizing that the friend
+ we're adding is a template, not an ordinary class. It's
+ important that we use make_friend_class since it will
+ perform some error-checking and output cross-reference
+ information. */
+ ++processing_template_decl;
+
+ make_friend_class (type, new_friend_type);
+
+ if (TREE_CODE (friend_type) == TEMPLATE_DECL)
+ --processing_template_decl;
+ }
+
+ /* This does injection for friend functions. */
+ if (!processing_template_decl)
+ {
+ t = tsubst (DECL_TEMPLATE_INJECT (template), args, NULL_TREE);
+
+ for (; t; t = TREE_CHAIN (t))
+ {
+ tree d = TREE_VALUE (t);
+
+ if (TREE_CODE (d) == TYPE_DECL)
+ /* Already injected. */;
+ else
+ pushdecl (d);
+ }
+ }
+
+ for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
+ if (TREE_CODE (t) == FIELD_DECL)
+ {
+ TREE_TYPE (t) = complete_type (TREE_TYPE (t));
+ require_complete_type (t);
+ }
+
+ type = finish_struct_1 (type, 0);
+ CLASSTYPE_GOT_SEMICOLON (type) = 1;
+
+ repo_template_used (type);
+
+ end:
+ TYPE_BEING_DEFINED (type) = 0;
+ popclass (0);
+
+ pop_from_top_level ();
+ pop_tinst_level ();
+
+ return type;
}
static int
@@ -1113,77 +4105,209 @@ list_eq (t1, t2)
return list_eq (TREE_CHAIN (t1), TREE_CHAIN (t2));
}
-static tree
+tree
lookup_nested_type_by_name (ctype, name)
tree ctype, name;
{
tree t;
+ complete_type (ctype);
+
for (t = CLASSTYPE_TAGS (ctype); t; t = TREE_CHAIN (t))
{
- if (name == TREE_PURPOSE (t))
+ if (name == TREE_PURPOSE (t)
+ /* this catches typedef enum { foo } bar; */
+ || name == TYPE_IDENTIFIER (TREE_VALUE (t)))
return TREE_VALUE (t);
}
return NULL_TREE;
}
+/* If arg is a non-type template parameter that does not depend on template
+ arguments, fold it like we weren't in the body of a template. */
+
static tree
-search_nested_type_in_tmpl (tmpl, type)
- tree tmpl, type;
+maybe_fold_nontype_arg (arg)
+ tree arg;
{
- tree t;
+ if (TREE_CODE_CLASS (TREE_CODE (arg)) != 't'
+ && !uses_template_parms (arg))
+ {
+ /* Sometimes, one of the args was an expression involving a
+ template constant parameter, like N - 1. Now that we've
+ tsubst'd, we might have something like 2 - 1. This will
+ confuse lookup_template_class, so we do constant folding
+ here. We have to unset processing_template_decl, to
+ fool build_expr_from_tree() into building an actual
+ tree. */
+
+ int saved_processing_template_decl = processing_template_decl;
+ processing_template_decl = 0;
+ arg = fold (build_expr_from_tree (arg));
+ processing_template_decl = saved_processing_template_decl;
+ }
+ return arg;
+}
+
+/* Return the TREE_VEC with the arguments for the innermost template header,
+ where ARGS is either that or the VEC of VECs for all the arguments.
- if (tmpl == NULL || TYPE_CONTEXT(type) == NULL)
- return tmpl;
- t = search_nested_type_in_tmpl (tmpl, TYPE_CONTEXT(type));
- if (t == NULL) return t;
- t = lookup_nested_type_by_name(t, DECL_NAME(TYPE_NAME(type)));
+ If is_spec, then we are dealing with a specialization of a member
+ template, and want the second-innermost args, the innermost ones that
+ are instantiated. */
+
+tree
+innermost_args (args, is_spec)
+ tree args;
+ int is_spec;
+{
+ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
+ return TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1 - is_spec);
+ return args;
+}
+
+/* Substitute ARGS into the vector of template arguments T. */
+
+tree
+tsubst_template_arg_vector (t, args)
+ tree t;
+ tree args;
+{
+ int len = TREE_VEC_LENGTH (t), need_new = 0, i;
+ tree *elts = (tree *) alloca (len * sizeof (tree));
+
+ bzero ((char *) elts, len * sizeof (tree));
+
+ for (i = 0; i < len; i++)
+ {
+ if (TREE_VEC_ELT (t, i) != NULL_TREE
+ && TREE_CODE (TREE_VEC_ELT (t, i)) == TREE_VEC)
+ elts[i] = tsubst_template_arg_vector (TREE_VEC_ELT (t, i), args);
+ else
+ elts[i] = maybe_fold_nontype_arg
+ (tsubst_expr (TREE_VEC_ELT (t, i), args, NULL_TREE));
+
+ if (elts[i] != TREE_VEC_ELT (t, i))
+ need_new = 1;
+ }
+
+ if (!need_new)
+ return t;
+
+ t = make_tree_vec (len);
+ for (i = 0; i < len; i++)
+ TREE_VEC_ELT (t, i) = elts[i];
+
return t;
}
+/* Take the tree structure T and replace template parameters used therein
+ with the argument vector ARGS. IN_DECL is an associated decl for
+ diagnostics.
+
+ tsubst is used for dealing with types, decls and the like; for
+ expressions, use tsubst_expr or tsubst_copy. */
+
tree
-tsubst (t, args, nargs, in_decl)
- tree t, *args;
- int nargs;
+tsubst (t, args, in_decl)
+ tree t, args;
tree in_decl;
{
tree type;
- if (t == NULL_TREE || t == error_mark_node)
+ if (t == NULL_TREE || t == error_mark_node
+ || t == integer_type_node
+ || t == void_type_node
+ || t == char_type_node
+ || TREE_CODE (t) == NAMESPACE_DECL)
return t;
- type = TREE_TYPE (t);
- if (type
- /* Minor optimization.
- ?? Are these really the most frequent cases? Is the savings
- significant? */
- && type != integer_type_node
- && type != void_type_node
- && type != char_type_node)
- type = tsubst (type, args, nargs, in_decl);
+ if (TREE_CODE (t) == IDENTIFIER_NODE)
+ type = IDENTIFIER_TYPE_VALUE (t);
+ else
+ type = TREE_TYPE (t);
+ if (type == unknown_type_node)
+ my_friendly_abort (42);
+
+ if (type && TREE_CODE (t) != FUNCTION_DECL
+ && TREE_CODE (t) != TYPENAME_TYPE
+ && TREE_CODE (t) != TEMPLATE_DECL
+ && TREE_CODE (t) != IDENTIFIER_NODE)
+ type = tsubst (type, args, in_decl);
switch (TREE_CODE (t))
{
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (t))
- return build_ptrmemfunc_type
- (tsubst (TYPE_PTRMEMFUNC_FN_TYPE (t), args, nargs, in_decl));
-
+ {
+ tree r = build_ptrmemfunc_type
+ (tsubst (TYPE_PTRMEMFUNC_FN_TYPE (t), args, in_decl));
+ return cp_build_type_variant (r, TYPE_READONLY (t),
+ TYPE_VOLATILE (t));
+ }
+
/* else fall through */
+ case UNION_TYPE:
+ if (uses_template_parms (t))
+ {
+ tree argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, in_decl);
+ tree context;
+ tree r;
+ if (TYPE_CONTEXT (t) != NULL_TREE)
+ {
+ context = tsubst (TYPE_CONTEXT (t), args, in_decl);
+
+ if (TREE_CODE (context) != FUNCTION_DECL
+ && TREE_CODE (context) != NAMESPACE_DECL)
+ {
+ /* For a member class template, we need all the
+ template arguments. */
+ if (CLASSTYPE_IS_TEMPLATE (TYPE_CONTEXT (t)))
+ argvec =
+ add_to_template_args (CLASSTYPE_TI_ARGS (context),
+ argvec);
+
+ if (CLASSTYPE_TEMPLATE_INFO (context))
+ argvec =
+ complete_template_args (CLASSTYPE_TI_TEMPLATE (context),
+ argvec, 0);
+ }
+ }
+ else
+ context = NULL_TREE;
+
+ r = lookup_template_class (t, argvec, in_decl, context);
+
+ return cp_build_type_variant (r, TYPE_READONLY (t),
+ TYPE_VOLATILE (t));
+ }
+
+ /* else fall through */
case ERROR_MARK:
case IDENTIFIER_NODE:
case OP_IDENTIFIER:
case VOID_TYPE:
case REAL_TYPE:
- case ENUMERAL_TYPE:
+ case COMPLEX_TYPE:
case BOOLEAN_TYPE:
case INTEGER_CST:
case REAL_CST:
case STRING_CST:
- case UNION_TYPE:
+ case NAMESPACE_DECL:
return t;
+ case ENUMERAL_TYPE:
+ {
+ tree ctx = tsubst (TYPE_CONTEXT (t), args, in_decl);
+ if (ctx == NULL_TREE || TREE_CODE (ctx) == NAMESPACE_DECL)
+ return t;
+ else if (ctx == current_function_decl)
+ return lookup_name (TYPE_IDENTIFIER (t), 1);
+ else
+ return lookup_nested_type_by_name (ctx, TYPE_IDENTIFIER (t));
+ }
+
case INTEGER_TYPE:
if (t == integer_type_node)
return t;
@@ -1191,296 +4315,526 @@ tsubst (t, args, nargs, in_decl)
if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST
&& TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
return t;
- return build_index_2_type
- (tsubst (TYPE_MIN_VALUE (t), args, nargs, in_decl),
- tsubst (TYPE_MAX_VALUE (t), args, nargs, in_decl));
- case TEMPLATE_TYPE_PARM:
{
- tree arg = args[TEMPLATE_TYPE_IDX (t)];
- return cp_build_type_variant
- (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
- TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
- }
+ tree max = TREE_OPERAND (TYPE_MAX_VALUE (t), 0);
+ max = tsubst_expr (max, args, in_decl);
+ if (processing_template_decl)
+ {
+ tree itype = make_node (INTEGER_TYPE);
+ TYPE_MIN_VALUE (itype) = size_zero_node;
+ TYPE_MAX_VALUE (itype) = build_min (MINUS_EXPR, sizetype, max,
+ integer_one_node);
+ return itype;
+ }
- case TEMPLATE_CONST_PARM:
- return args[TEMPLATE_CONST_IDX (t)];
+ max = fold (build_binary_op (MINUS_EXPR, max, integer_one_node, 1));
+ return build_index_2_type (size_zero_node, max);
+ }
- case FUNCTION_DECL:
+ case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
+ case TEMPLATE_PARM_INDEX:
{
- tree r;
- tree fnargs, result;
-
- if (type == TREE_TYPE (t)
- && (DECL_CONTEXT (t) == NULL_TREE
- || TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) != 't'))
- return t;
- fnargs = tsubst (DECL_ARGUMENTS (t), args, nargs, t);
- result = tsubst (DECL_RESULT (t), args, nargs, t);
- if (DECL_CONTEXT (t) != NULL_TREE
- && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) == 't')
+ int idx;
+ int level;
+ int levels;
+ tree r = NULL_TREE;
+
+ if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
{
- /* Look it up in that class, and return the decl node there,
- instead of creating a new one. */
- tree ctx, methods, name, method;
- int n_methods;
- int i, found = 0;
-
- name = DECL_NAME (t);
- ctx = tsubst (DECL_CONTEXT (t), args, nargs, t);
- methods = CLASSTYPE_METHOD_VEC (ctx);
- if (methods == NULL_TREE)
- /* No methods at all -- no way this one can match. */
- goto no_match;
- n_methods = TREE_VEC_LENGTH (methods);
-
- r = NULL_TREE;
-
- if (!strncmp (OPERATOR_TYPENAME_FORMAT,
- IDENTIFIER_POINTER (name),
- sizeof (OPERATOR_TYPENAME_FORMAT) - 1))
- {
- /* Type-conversion operator. Reconstruct the name, in
- case it's the name of one of the template's parameters. */
- name = build_typename_overload (TREE_TYPE (type));
- }
+ idx = TEMPLATE_TYPE_IDX (t);
+ level = TEMPLATE_TYPE_LEVEL (t);
+ }
+ else
+ {
+ idx = TEMPLATE_PARM_IDX (t);
+ level = TEMPLATE_PARM_LEVEL (t);
+ }
- if (DECL_CONTEXT (t) != NULL_TREE
- && TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) == 't'
- && constructor_name (DECL_CONTEXT (t)) == DECL_NAME (t))
- name = constructor_name (ctx);
+ if (TREE_VEC_LENGTH (args) > 0)
+ {
+ tree arg = NULL_TREE;
- if (DECL_CONSTRUCTOR_P (t) && TYPE_USES_VIRTUAL_BASECLASSES (ctx))
+ if (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (args))
{
- /* Since we didn't know that this class had virtual bases until after
- we instantiated it, we have to recreate the arguments to this
- constructor, as otherwise it would miss the __in_chrg parameter. */
- tree newtype, parm;
- tree parms = TREE_CHAIN (TYPE_ARG_TYPES (type));
- parms = hash_tree_chain (integer_type_node, parms);
- newtype = build_cplus_method_type (ctx,
- TREE_TYPE (type),
- parms);
- newtype = build_type_variant (newtype,
- TYPE_READONLY (type),
- TYPE_VOLATILE (type));
- type = newtype;
-
- fnargs = copy_node (DECL_ARGUMENTS (t));
- TREE_CHAIN (fnargs) = TREE_CHAIN (DECL_ARGUMENTS (t));
-
- /* In this case we need "in-charge" flag saying whether
- this constructor is responsible for initialization
- of virtual baseclasses or not. */
- parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node);
- /* Mark the artificial `__in_chrg' parameter as "artificial". */
- SET_DECL_ARTIFICIAL (parm);
- DECL_ARG_TYPE (parm) = integer_type_node;
- DECL_REGISTER (parm) = 1;
- TREE_CHAIN (parm) = TREE_CHAIN (fnargs);
- TREE_CHAIN (fnargs) = parm;
-
- fnargs = tsubst (fnargs, args, nargs, t);
+ levels = TREE_VEC_LENGTH (args);
+ if (level <= levels)
+ arg = TREE_VEC_ELT
+ (TREE_VEC_ELT (args, level - 1), idx);
}
-#if 0
- fprintf (stderr, "\nfor function %s in class %s:\n",
- IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (TYPE_IDENTIFIER (ctx)));
-#endif
- for (i = 0; i < n_methods; i++)
+ else
{
- int pass;
-
- method = TREE_VEC_ELT (methods, i);
- if (method == NULL_TREE || DECL_NAME (method) != name)
- continue;
+ levels = 1;
+ if (level == 1)
+ arg = TREE_VEC_ELT (args, idx);
+ }
- pass = 0;
- maybe_error:
- for (; method; method = DECL_CHAIN (method))
+ if (arg != NULL_TREE)
+ {
+ if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+ return cp_build_type_variant
+ (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
+ TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
+ else if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
{
- my_friendly_assert (TREE_CODE (method) == FUNCTION_DECL,
- 282);
- if (! comptypes (type, TREE_TYPE (method), 1))
+ if (CLASSTYPE_TEMPLATE_INFO (t))
{
- tree mtype = TREE_TYPE (method);
- tree t1, t2;
-
- /* Keep looking for a method that matches
- perfectly. This takes care of the problem
- where destructors (which have implicit int args)
- look like constructors which have an int arg. */
- if (pass == 0)
- continue;
-
- t1 = TYPE_ARG_TYPES (mtype);
- t2 = TYPE_ARG_TYPES (type);
- if (TREE_CODE (mtype) == FUNCTION_TYPE)
- t2 = TREE_CHAIN (t2);
-
- if (list_eq (t1, t2))
- {
- if (TREE_CODE (mtype) == FUNCTION_TYPE)
- {
- tree newtype;
- newtype = build_function_type (TREE_TYPE (type),
- TYPE_ARG_TYPES (type));
- newtype = build_type_variant (newtype,
- TYPE_READONLY (type),
- TYPE_VOLATILE (type));
- type = newtype;
- if (TREE_TYPE (type) != TREE_TYPE (mtype))
- goto maybe_bad_return_type;
- }
- else if (TYPE_METHOD_BASETYPE (mtype)
- == TYPE_METHOD_BASETYPE (type))
- {
- /* Types didn't match, but arg types and
- `this' do match, so the return type is
- all that should be messing it up. */
- maybe_bad_return_type:
- if (TREE_TYPE (type) != TREE_TYPE (mtype))
- error ("inconsistent return types for method `%s' in class `%s'",
- IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (TYPE_IDENTIFIER (ctx)));
- }
- r = method;
- break;
- }
- found = 1;
- continue;
+ /* We are processing a type constructed from
+ a template template parameter */
+ tree argvec = tsubst (CLASSTYPE_TI_ARGS (t),
+ args, in_decl);
+ tree r;
+
+ /* We can get a TEMPLATE_TEMPLATE_PARM here when
+ we are resolving nested-types in the signature of
+ a member function templates.
+ Otherwise ARG is a TEMPLATE_DECL and is the real
+ template to be instantiated. */
+ if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+ arg = TYPE_NAME (arg);
+
+ r = lookup_template_class (DECL_NAME (arg),
+ argvec, in_decl,
+ DECL_CONTEXT (arg));
+ return cp_build_type_variant (r, TYPE_READONLY (t),
+ TYPE_VOLATILE (t));
}
-#if 0
- fprintf (stderr, "\tfound %s\n\n",
- IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (method)));
-#endif
- if (DECL_ARTIFICIAL (method))
- {
- cp_error ("template for method `%D' which has default implementation in class `%T'", name, ctx);
- if (in_decl)
- cp_error_at ("in attempt to instantiate `%D' declared at this point in file", in_decl);
- return error_mark_node;
- }
-
- if (DECL_ARGUMENTS (method)
- && ! TREE_PERMANENT (DECL_ARGUMENTS (method)))
- /* @@ Is this early enough? Might we want to do
- this instead while processing the expansion? */
- DECL_ARGUMENTS (method)
- = tsubst (DECL_ARGUMENTS (t), args, nargs, t);
- r = method;
- break;
- }
- if (r == NULL_TREE && pass == 0)
- {
- pass = 1;
- method = TREE_VEC_ELT (methods, i);
- goto maybe_error;
+ else
+ /* We are processing a template argument list. */
+ return arg;
}
+ else
+ return arg;
}
- if (r == NULL_TREE)
+ }
+
+ if (level == 1)
+ /* This can happen during the attempted tsubst'ing in
+ unify. This means that we don't yet have any information
+ about the template parameter in question. */
+ return t;
+
+ /* If we get here, we must have been looking at a parm for a
+ more deeply nested template. Make a new version of this
+ template parameter, but with a lower level. */
+ switch (TREE_CODE (t))
+ {
+ case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
+ r = copy_node (t);
+ TEMPLATE_TYPE_PARM_INDEX (r)
+ = reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (t),
+ r, levels);
+ TYPE_STUB_DECL (r) = TYPE_NAME (r) = TEMPLATE_TYPE_DECL (r);
+ TYPE_MAIN_VARIANT (r) = r;
+ TYPE_POINTER_TO (r) = NULL_TREE;
+ TYPE_REFERENCE_TO (r) = NULL_TREE;
+
+ if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
+ && CLASSTYPE_TEMPLATE_INFO (t))
{
- no_match:
- cp_error
- (found
- ? "template for method `%D' doesn't match any in class `%T'"
- : "method `%D' not found in class `%T'", name, ctx);
- if (in_decl)
- cp_error_at ("in attempt to instantiate `%D' declared at this point in file", in_decl);
- return error_mark_node;
+ tree argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, in_decl);
+ CLASSTYPE_TEMPLATE_INFO (r)
+ = perm_tree_cons (TYPE_NAME (t), argvec, NULL_TREE);
}
+ break;
+
+ case TEMPLATE_PARM_INDEX:
+ r = reduce_template_parm_level (t, type, levels);
+ break;
+
+ default:
+ my_friendly_abort (0);
+ }
+
+ return r;
+ }
+
+ case TEMPLATE_DECL:
+ {
+ /* We can get here when processing a member template function
+ of a template class. */
+ tree tmpl;
+ tree decl = DECL_TEMPLATE_RESULT (t);
+ tree parms;
+ tree* new_parms;
+ tree spec;
+ int is_template_template_parm = DECL_TEMPLATE_TEMPLATE_PARM_P (t);
+
+ if (!is_template_template_parm)
+ {
+ /* We might already have an instance of this template. */
+ spec = retrieve_specialization (t, args);
+ if (spec != NULL_TREE)
+ return spec;
+ }
+
+ /* Make a new template decl. It will be similar to the
+ original, but will record the current template arguments.
+ We also create a new function declaration, which is just
+ like the old one, but points to this new template, rather
+ than the old one. */
+ tmpl = copy_node (t);
+ copy_lang_decl (tmpl);
+ my_friendly_assert (DECL_LANG_SPECIFIC (tmpl) != 0, 0);
+ TREE_CHAIN (tmpl) = NULL_TREE;
+
+ if (is_template_template_parm)
+ {
+ tree new_decl = tsubst (decl, args, in_decl);
+ DECL_RESULT (tmpl) = new_decl;
+ TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
+ return tmpl;
+ }
+
+ DECL_CONTEXT (tmpl) = tsubst (DECL_CONTEXT (t),
+ args, in_decl);
+ DECL_CLASS_CONTEXT (tmpl) = tsubst (DECL_CLASS_CONTEXT (t),
+ args, in_decl);
+ DECL_TEMPLATE_INFO (tmpl) = build_tree_list (t, args);
+
+ if (TREE_CODE (decl) == TYPE_DECL)
+ {
+ tree new_type = tsubst (TREE_TYPE (t), args, in_decl);
+ TREE_TYPE (tmpl) = new_type;
+ CLASSTYPE_TI_TEMPLATE (new_type) = tmpl;
+ DECL_RESULT (tmpl) = TYPE_MAIN_DECL (new_type);
}
else
{
- r = DECL_NAME (t);
- {
- tree decls;
- int got_it = 0;
-
- decls = lookup_name_nonclass (r);
- if (decls == NULL_TREE)
- /* no match */;
- else if (TREE_CODE (decls) == TREE_LIST)
- for (decls = TREE_VALUE (decls); decls ;
- decls = DECL_CHAIN (decls))
- {
- if (TREE_CODE (decls) == FUNCTION_DECL
- && TREE_TYPE (decls) == type)
- {
- got_it = 1;
- r = decls;
- break;
- }
- }
- else
- {
- tree val = decls;
- decls = NULL_TREE;
- if (TREE_CODE (val) == FUNCTION_DECL
- && TREE_TYPE (val) == type)
- {
- got_it = 1;
- r = val;
- }
- }
+ tree new_decl = tsubst (decl, args, in_decl);
+ DECL_RESULT (tmpl) = new_decl;
+ DECL_TI_TEMPLATE (new_decl) = tmpl;
+ TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
+ }
- if (!got_it)
- {
- tree a = build_decl_overload (r, TYPE_VALUES (type),
- DECL_CONTEXT (t) != NULL_TREE);
- r = build_lang_decl (FUNCTION_DECL, r, type);
- DECL_ASSEMBLER_NAME (r) = a;
- }
- else if (TREE_STATIC (r))
- {
- /* This overrides the template version, use it. */
- return r;
- }
- }
+ DECL_TEMPLATE_INSTANTIATIONS (tmpl) = NULL_TREE;
+ SET_DECL_IMPLICIT_INSTANTIATION (tmpl);
+
+ /* The template parameters for this new template are all the
+ template parameters for the old template, except the
+ outermost level of parameters. */
+ for (new_parms = &DECL_TEMPLATE_PARMS (tmpl),
+ parms = DECL_TEMPLATE_PARMS (t);
+ TREE_CHAIN (parms) != NULL_TREE;
+ new_parms = &(TREE_CHAIN (*new_parms)),
+ parms = TREE_CHAIN (parms))
+ {
+ tree new_vec =
+ make_tree_vec (TREE_VEC_LENGTH (TREE_VALUE (parms)));
+ int i;
+
+ for (i = 0; i < TREE_VEC_LENGTH (new_vec); ++i)
+ {
+ tree default_value =
+ TREE_PURPOSE (TREE_VEC_ELT (TREE_VALUE (parms), i));
+ tree parm_decl =
+ TREE_VALUE (TREE_VEC_ELT (TREE_VALUE (parms), i));
+
+ TREE_VEC_ELT (new_vec, i)
+ = build_tree_list (tsubst (default_value, args, in_decl),
+ tsubst (parm_decl, args, in_decl));
+
+ }
+
+ *new_parms =
+ tree_cons (build_int_2 (0,
+ TREE_INT_CST_HIGH
+ (TREE_PURPOSE (parms)) - 1),
+ new_vec,
+ NULL_TREE);
}
- TREE_PUBLIC (r) = 1;
- DECL_EXTERNAL (r) = 1;
+
+ if (PRIMARY_TEMPLATE_P (t))
+ DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
+
+ /* We don't partially instantiate partial specializations. */
+ if (TREE_CODE (decl) == TYPE_DECL)
+ return tmpl;
+
+ /* What should we do with the specializations of this member
+ template? Are they specializations of this new template,
+ or instantiations of the templates they previously were?
+ this new template? And where should their
+ DECL_TI_TEMPLATES point? */
+ DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = NULL_TREE;
+ for (spec = DECL_TEMPLATE_SPECIALIZATIONS (t);
+ spec != NULL_TREE;
+ spec = TREE_CHAIN (spec))
+ {
+ /* It helps to consider example here. Consider:
+
+ template <class T>
+ struct S {
+ template <class U>
+ void f(U u);
+
+ template <>
+ void f(T* t) {}
+ };
+
+ Now, for example, we are instantiating S<int>::f(U u).
+ We want to make a template:
+
+ template <class U>
+ void S<int>::f(U);
+
+ It will have a specialization, for the case U = int*, of
+ the form:
+
+ template <>
+ void S<int>::f<int*>(int*);
+
+ This specialization will be an instantiation of
+ the specialization given in the declaration of S, with
+ argument list int*. */
+
+ tree fn = TREE_VALUE (spec);
+ tree spec_args;
+ tree new_fn;
+
+ if (!DECL_TEMPLATE_SPECIALIZATION (fn))
+ /* Instantiations are on the same list, but they're of
+ no concern to us. */
+ continue;
+
+ spec_args = tsubst (DECL_TI_ARGS (fn), args,
+ in_decl);
+ new_fn = tsubst (DECL_RESULT (fn), args,
+ in_decl);
+ DECL_TEMPLATE_SPECIALIZATIONS (tmpl) =
+ perm_tree_cons (spec_args, new_fn,
+ DECL_TEMPLATE_SPECIALIZATIONS (tmpl));
+ }
+
+ /* Record this partial instantiation. */
+ register_specialization (tmpl, t, args);
+
+ return tmpl;
+ }
+
+ case FUNCTION_DECL:
+ {
+ tree r = NULL_TREE;
+ tree ctx;
+ tree argvec;
+ tree tmpl = NULL_TREE;
+ int member;
+
+ if (DECL_CLASS_SCOPE_P (t))
+ {
+ if (DECL_NAME (t) == constructor_name (DECL_CONTEXT (t)))
+ member = 2;
+ else
+ member = 1;
+ ctx = tsubst (DECL_CLASS_CONTEXT (t), args, t);
+ }
+ else
+ {
+ member = 0;
+ ctx = NULL_TREE;
+ }
+ type = tsubst (type, args, in_decl);
+
+ /* If we are instantiating a specialization, get the other args. */
+ if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
+ {
+ tree spec;
+
+ tmpl = DECL_TI_TEMPLATE (t);
+
+ /* Start by getting the innermost args. */
+ if (DECL_TEMPLATE_SPECIALIZATION (tmpl))
+ argvec = args;
+ else
+ argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
+
+ if (DECL_TEMPLATE_INFO (tmpl))
+ argvec = complete_template_args (tmpl, argvec, 0);
+
+ /* Do we already have this instantiation? */
+ spec = retrieve_specialization (tmpl, argvec);
+ if (spec)
+ return spec;
+ }
+
+ /* We do NOT check for matching decls pushed separately at this
+ point, as they may not represent instantiations of this
+ template, and in any case are considered separate under the
+ discrete model. Instead, see add_maybe_template. */
+
+ r = copy_node (t);
+ copy_lang_decl (r);
+ DECL_USE_TEMPLATE (r) = 0;
+ TREE_TYPE (r) = type;
+
+ DECL_CONTEXT (r)
+ = tsubst (DECL_CONTEXT (t), args, t);
+ DECL_CLASS_CONTEXT (r) = ctx;
+
+ if (member && !strncmp (OPERATOR_TYPENAME_FORMAT,
+ IDENTIFIER_POINTER (DECL_NAME (r)),
+ sizeof (OPERATOR_TYPENAME_FORMAT) - 1))
+ {
+ /* Type-conversion operator. Reconstruct the name, in
+ case it's the name of one of the template's parameters. */
+ DECL_NAME (r) = build_typename_overload (TREE_TYPE (type));
+ }
+
+ DECL_ARGUMENTS (r) = tsubst (DECL_ARGUMENTS (t), args, t);
+ DECL_MAIN_VARIANT (r) = r;
+ DECL_RESULT (r) = NULL_TREE;
+ DECL_INITIAL (r) = NULL_TREE;
+
TREE_STATIC (r) = 0;
+ TREE_PUBLIC (r) = TREE_PUBLIC (t);
+ DECL_EXTERNAL (r) = 1;
DECL_INTERFACE_KNOWN (r) = 0;
- DECL_INLINE (r) = DECL_INLINE (t);
- DECL_THIS_INLINE (r) = DECL_THIS_INLINE (t);
- TREE_READONLY (r) = TREE_READONLY (t);
- TREE_THIS_VOLATILE (r) = TREE_THIS_VOLATILE (t);
- {
-#if 0 /* Maybe later. -jason */
- struct tinst_level *til = tinst_for_decl();
+ DECL_DEFER_OUTPUT (r) = 0;
+ TREE_CHAIN (r) = NULL_TREE;
+ DECL_PENDING_INLINE_INFO (r) = 0;
+ TREE_USED (r) = 0;
- /* should always be true under new approach */
- if (til)
- {
- DECL_SOURCE_FILE (r) = til->file;
- DECL_SOURCE_LINE (r) = til->line;
- }
- else
-#endif
- {
- DECL_SOURCE_FILE (r) = DECL_SOURCE_FILE (t);
- DECL_SOURCE_LINE (r) = DECL_SOURCE_LINE (t);
- }
- }
- DECL_CLASS_CONTEXT (r) = tsubst (DECL_CLASS_CONTEXT (t), args, nargs, t);
+ if (DECL_CONSTRUCTOR_P (r))
+ {
+ maybe_retrofit_in_chrg (r);
+ grok_ctor_properties (ctx, r);
+ }
+ if (IDENTIFIER_OPNAME_P (DECL_NAME (r)))
+ grok_op_properties (r, DECL_VIRTUAL_P (r), DECL_FRIEND_P (r));
+
+ if (DECL_DESTRUCTOR_P (t))
+ DECL_ASSEMBLER_NAME (r) = build_destructor_name (ctx);
+ else
+ {
+ /* Instantiations of template functions must be mangled
+ specially, in order to conform to 14.5.5.1
+ [temp.over.link]. We use in_decl below rather than
+ DECL_TI_TEMPLATE (r) because the latter is set to
+ NULL_TREE in instantiate_decl. */
+ tree tmpl;
+ tree arg_types;
+
+ if (DECL_TEMPLATE_INFO (r))
+ tmpl = DECL_TI_TEMPLATE (r);
+ else
+ tmpl = in_decl;
+
+ /* tmpl will be NULL if this is a specialization of a
+ member function of a template class. */
+ if (name_mangling_version < 1
+ || tmpl == NULL_TREE
+ || (member && !is_member_template (tmpl)
+ && !DECL_TEMPLATE_INFO (tmpl)))
+ {
+ arg_types = TYPE_ARG_TYPES (type);
+ if (member && TREE_CODE (type) == FUNCTION_TYPE)
+ arg_types = hash_tree_chain
+ (build_pointer_type (DECL_CONTEXT (r)),
+ arg_types);
+
+ DECL_ASSEMBLER_NAME (r)
+ = build_decl_overload (DECL_NAME (r), arg_types,
+ member);
+ }
+ else
+ {
+ tree tparms;
+ tree targs;
+
+ if (!DECL_TEMPLATE_SPECIALIZATION (tmpl))
+ {
+ /* We pass the outermost template parameters to
+ build_template_decl_overload, since the innermost
+ template parameters are still just template
+ parameters; there are no corresponding subsitution
+ arguments. Levels of parms that have been bound
+ before are not represented in DECL_TEMPLATE_PARMS. */
+ tparms = DECL_TEMPLATE_PARMS (tmpl);
+ while (tparms && TREE_CHAIN (tparms) != NULL_TREE)
+ tparms = TREE_CHAIN (tparms);
+
+ targs = innermost_args (args, 0);
+ }
+ else
+ {
+ /* If the template is a specialization, then it is
+ a member template specialization. We have
+ something like:
+
+ template <class T> struct S {
+ template <int i> void f();
+ template <> void f<7>();
+ };
+
+ and now we are forming S<double>::f<7>.
+ Therefore, the template parameters of interest
+ are those that are specialized by the template
+ (i.e., the int), not those we are using to
+ instantiate the template, i.e. the double. */
+ tparms = DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (tmpl));
+ targs = DECL_TI_ARGS (tmpl);
+ }
+
+ my_friendly_assert (tparms != NULL_TREE
+ && TREE_CODE (tparms) == TREE_LIST,
+ 0);
+ tparms = TREE_VALUE (tparms);
+
+ arg_types = TYPE_ARG_TYPES (TREE_TYPE (tmpl));
+ if (member && TREE_CODE (type) == FUNCTION_TYPE)
+ arg_types = hash_tree_chain
+ (build_pointer_type (DECL_CONTEXT (r)),
+ arg_types);
+
+ DECL_ASSEMBLER_NAME (r)
+ = build_template_decl_overload
+ (r, arg_types, TREE_TYPE (TREE_TYPE (tmpl)),
+ tparms, targs, member);
+ }
+ }
+ DECL_RTL (r) = 0;
make_decl_rtl (r, NULL_PTR, 1);
- DECL_ARGUMENTS (r) = fnargs;
- DECL_RESULT (r) = result;
-#if 0
- if (DECL_CONTEXT (t) == NULL_TREE
- || TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (t))) != 't')
- push_overloaded_decl_top_level (r, 0);
-#endif
+
+ if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
+ {
+ DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
+
+ /* If we're not using ANSI overloading, then we might have
+ called duplicate_decls above, and gotten back an
+ preexisting version of this function. We treat such a
+ function as a specialization. Otherwise, we cleared
+ both TREE_STATIC and DECL_TEMPLATE_SPECIALIZATION, so
+ this condition will be false. */
+ if (TREE_STATIC (r) || DECL_TEMPLATE_SPECIALIZATION (r))
+ SET_DECL_TEMPLATE_SPECIALIZATION (r);
+ else
+ SET_DECL_IMPLICIT_INSTANTIATION (r);
+
+ register_specialization (r, tmpl, argvec);
+ }
+
+ /* Like grokfndecl. If we don't do this, pushdecl will mess up our
+ TREE_CHAIN because it doesn't find a previous decl. Sigh. */
+ if (member
+ && IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r)) == NULL_TREE)
+ SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r), r);
+
return r;
}
case PARM_DECL:
{
- tree r;
- r = build_decl (PARM_DECL, DECL_NAME (t), type);
- DECL_INITIAL (r) = TREE_TYPE (r);
- DECL_ARTIFICIAL (r) = DECL_ARTIFICIAL (t);
+ tree r = copy_node (t);
+ TREE_TYPE (r) = type;
+ if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
+ DECL_INITIAL (r) = TREE_TYPE (r);
+ else
+ DECL_INITIAL (r) = tsubst (DECL_INITIAL (r), args, in_decl);
+
+ DECL_CONTEXT (r) = NULL_TREE;
#ifdef PROMOTE_PROTOTYPES
if ((TREE_CODE (type) == INTEGER_TYPE
|| TREE_CODE (type) == ENUMERAL_TYPE)
@@ -1488,10 +4842,98 @@ tsubst (t, args, nargs, in_decl)
DECL_ARG_TYPE (r) = integer_type_node;
#endif
if (TREE_CHAIN (t))
- TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args, nargs, TREE_CHAIN (t));
+ TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args, TREE_CHAIN (t));
+ return r;
+ }
+
+ case FIELD_DECL:
+ {
+ tree r = copy_node (t);
+ TREE_TYPE (r) = type;
+ copy_lang_decl (r);
+#if 0
+ DECL_FIELD_CONTEXT (r) = tsubst (DECL_FIELD_CONTEXT (t), args, in_decl);
+#endif
+ DECL_INITIAL (r) = tsubst_expr (DECL_INITIAL (t), args, in_decl);
+ TREE_CHAIN (r) = NULL_TREE;
+ if (TREE_CODE (type) == VOID_TYPE)
+ cp_error_at ("instantiation of `%D' as type void", r);
+ return r;
+ }
+
+ case USING_DECL:
+ {
+ tree r = copy_node (t);
+ DECL_INITIAL (r)
+ = tsubst_copy (DECL_INITIAL (t), args, in_decl);
+ TREE_CHAIN (r) = NULL_TREE;
+ return r;
+ }
+
+ case VAR_DECL:
+ {
+ tree r;
+ tree ctx = tsubst_copy (DECL_CONTEXT (t), args, in_decl);
+
+ /* Do we already have this instantiation? */
+ if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
+ {
+ tree tmpl = DECL_TI_TEMPLATE (t);
+ tree decls = DECL_TEMPLATE_INSTANTIATIONS (tmpl);
+
+ for (; decls; decls = TREE_CHAIN (decls))
+ if (DECL_CONTEXT (TREE_VALUE (decls)) == ctx)
+ return TREE_VALUE (decls);
+ }
+
+ r = copy_node (t);
+ TREE_TYPE (r) = type;
+ DECL_CONTEXT (r) = ctx;
+ if (TREE_STATIC (r))
+ DECL_ASSEMBLER_NAME (r)
+ = build_static_name (DECL_CONTEXT (r), DECL_NAME (r));
+
+ /* Don't try to expand the initializer until someone tries to use
+ this variable; otherwise we run into circular dependencies. */
+ DECL_INITIAL (r) = NULL_TREE;
+
+ DECL_RTL (r) = 0;
+ DECL_SIZE (r) = 0;
+
+ if (DECL_LANG_SPECIFIC (r))
+ {
+ copy_lang_decl (r);
+ DECL_CLASS_CONTEXT (r) = DECL_CONTEXT (r);
+ }
+
+ if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
+ {
+ tree tmpl = DECL_TI_TEMPLATE (t);
+ tree *declsp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl);
+ tree argvec = tsubst (DECL_TI_ARGS (t), args, in_decl);
+
+ DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
+ *declsp = perm_tree_cons (argvec, r, *declsp);
+ SET_DECL_IMPLICIT_INSTANTIATION (r);
+ }
+ TREE_CHAIN (r) = NULL_TREE;
+ if (TREE_CODE (type) == VOID_TYPE)
+ cp_error_at ("instantiation of `%D' as type void", r);
return r;
}
+ case TYPE_DECL:
+ if (t == TYPE_NAME (TREE_TYPE (t)))
+ return TYPE_NAME (type);
+
+ {
+ tree r = copy_node (t);
+ TREE_TYPE (r) = type;
+ DECL_CONTEXT (r) = current_class_type;
+ TREE_CHAIN (r) = NULL_TREE;
+ return r;
+ }
+
case TREE_LIST:
{
tree purpose, value, chain, result;
@@ -1506,13 +4948,13 @@ tsubst (t, args, nargs, in_decl)
purpose = TREE_PURPOSE (t);
if (purpose)
- purpose = tsubst (purpose, args, nargs, in_decl);
+ purpose = tsubst (purpose, args, in_decl);
value = TREE_VALUE (t);
if (value)
- value = tsubst (value, args, nargs, in_decl);
+ value = tsubst (value, args, in_decl);
chain = TREE_CHAIN (t);
if (chain && chain != void_type_node)
- chain = tsubst (chain, args, nargs, in_decl);
+ chain = tsubst (chain, args, in_decl);
if (purpose == TREE_PURPOSE (t)
&& value == TREE_VALUE (t)
&& chain == TREE_CHAIN (t))
@@ -1523,59 +4965,119 @@ tsubst (t, args, nargs, in_decl)
return result;
}
case TREE_VEC:
- {
- int len = TREE_VEC_LENGTH (t), need_new = 0, i;
- tree *elts = (tree *) alloca (len * sizeof (tree));
- bzero ((char *) elts, len * sizeof (tree));
+ if (type != NULL_TREE)
+ {
+ /* A binfo node. We always need to make a copy, of the node
+ itself and of its BINFO_BASETYPES. */
- for (i = 0; i < len; i++)
- {
- elts[i] = tsubst (TREE_VEC_ELT (t, i), args, nargs, in_decl);
- if (elts[i] != TREE_VEC_ELT (t, i))
- need_new = 1;
- }
+ t = copy_node (t);
- if (!need_new)
+ /* Make sure type isn't a typedef copy. */
+ type = BINFO_TYPE (TYPE_BINFO (type));
+
+ TREE_TYPE (t) = complete_type (type);
+ if (IS_AGGR_TYPE (type))
+ {
+ BINFO_VTABLE (t) = TYPE_BINFO_VTABLE (type);
+ BINFO_VIRTUALS (t) = TYPE_BINFO_VIRTUALS (type);
+ if (TYPE_BINFO_BASETYPES (type) != NULL_TREE)
+ BINFO_BASETYPES (t) = copy_node (TYPE_BINFO_BASETYPES (type));
+ }
return t;
+ }
+
+ /* Otherwise, a vector of template arguments. */
+ return tsubst_template_arg_vector (t, args);
- t = make_tree_vec (len);
- for (i = 0; i < len; i++)
- TREE_VEC_ELT (t, i) = elts[i];
- return t;
- }
case POINTER_TYPE:
case REFERENCE_TYPE:
{
tree r;
enum tree_code code;
+
if (type == TREE_TYPE (t))
return t;
code = TREE_CODE (t);
- if (code == POINTER_TYPE)
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ static int last_line = 0;
+ static char* last_file = 0;
+
+ /* We keep track of the last time we issued this error
+ message to avoid spewing a ton of messages during a
+ single bad template instantiation. */
+ if (last_line != lineno ||
+ last_file != input_filename)
+ {
+ cp_error ("cannot form type %s to reference type %T during template instantiation",
+ (code == POINTER_TYPE) ? "pointer" : "reference",
+ type);
+ last_line = lineno;
+ last_file = input_filename;
+ }
+
+ /* Use the underlying type in an attempt at error
+ recovery; maybe the user meant vector<int> and wrote
+ vector<int&>, or some such. */
+ if (code == REFERENCE_TYPE)
+ r = type;
+ else
+ r = build_pointer_type (TREE_TYPE (type));
+ }
+ else if (code == POINTER_TYPE)
r = build_pointer_type (type);
else
r = build_reference_type (type);
r = cp_build_type_variant (r, TYPE_READONLY (t), TYPE_VOLATILE (t));
+
/* Will this ever be needed for TYPE_..._TO values? */
layout_type (r);
return r;
}
case OFFSET_TYPE:
return build_offset_type
- (tsubst (TYPE_OFFSET_BASETYPE (t), args, nargs, in_decl), type);
+ (tsubst (TYPE_OFFSET_BASETYPE (t), args, in_decl), type);
case FUNCTION_TYPE:
case METHOD_TYPE:
{
tree values = TYPE_ARG_TYPES (t);
tree context = TYPE_CONTEXT (t);
- tree new_value;
+ tree raises = TYPE_RAISES_EXCEPTIONS (t);
+ tree fntype;
/* Don't bother recursing if we know it won't change anything. */
if (values != void_list_node)
- values = tsubst (values, args, nargs, in_decl);
+ {
+ /* This should probably be rewritten to use hash_tree_cons for
+ the memory savings. */
+ tree first = NULL_TREE;
+ tree last = NULL_TREE;
+
+ for (; values && values != void_list_node;
+ values = TREE_CHAIN (values))
+ {
+ tree value = TYPE_MAIN_VARIANT (type_decays_to
+ (tsubst (TREE_VALUE (values), args, in_decl)));
+ /* Don't instantiate default args unless they are used.
+ Handle it in build_over_call instead. */
+ tree purpose = TREE_PURPOSE (values);
+ tree x = build_tree_list (purpose, value);
+
+ if (first)
+ TREE_CHAIN (last) = x;
+ else
+ first = x;
+ last = x;
+ }
+
+ if (values == void_list_node)
+ TREE_CHAIN (last) = void_list_node;
+
+ values = first;
+ }
if (context)
- context = tsubst (context, args, nargs, in_decl);
+ context = tsubst (context, args, in_decl);
/* Could also optimize cases where return value and
values have common elements (e.g., T min(const &T, const T&). */
@@ -1589,38 +5091,43 @@ tsubst (t, args, nargs, in_decl)
if (TREE_CODE (t) == FUNCTION_TYPE
&& context == NULL_TREE)
{
- new_value = build_function_type (type, values);
+ fntype = build_function_type (type, values);
}
else if (context == NULL_TREE)
{
tree base = tsubst (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))),
- args, nargs, in_decl);
- new_value = build_cplus_method_type (base, type,
- TREE_CHAIN (values));
+ args, in_decl);
+ fntype = build_cplus_method_type (base, type,
+ TREE_CHAIN (values));
}
else
{
- new_value = make_node (TREE_CODE (t));
- TREE_TYPE (new_value) = type;
- TYPE_CONTEXT (new_value) = context;
- TYPE_VALUES (new_value) = values;
- TYPE_SIZE (new_value) = TYPE_SIZE (t);
- TYPE_ALIGN (new_value) = TYPE_ALIGN (t);
- TYPE_MODE (new_value) = TYPE_MODE (t);
+ fntype = make_node (TREE_CODE (t));
+ TREE_TYPE (fntype) = type;
+ TYPE_CONTEXT (fntype) = FROB_CONTEXT (context);
+ TYPE_VALUES (fntype) = values;
+ TYPE_SIZE (fntype) = TYPE_SIZE (t);
+ TYPE_ALIGN (fntype) = TYPE_ALIGN (t);
+ TYPE_MODE (fntype) = TYPE_MODE (t);
if (TYPE_METHOD_BASETYPE (t))
- TYPE_METHOD_BASETYPE (new_value) = tsubst (TYPE_METHOD_BASETYPE (t),
- args, nargs, in_decl);
+ TYPE_METHOD_BASETYPE (fntype) = tsubst (TYPE_METHOD_BASETYPE (t),
+ args, in_decl);
/* Need to generate hash value. */
my_friendly_abort (84);
}
- new_value = build_type_variant (new_value,
- TYPE_READONLY (t),
- TYPE_VOLATILE (t));
- return new_value;
+ fntype = build_type_variant (fntype,
+ TYPE_READONLY (t),
+ TYPE_VOLATILE (t));
+ if (raises)
+ {
+ raises = tsubst (raises, args, in_decl);
+ fntype = build_exception_variant (fntype, raises);
+ }
+ return fntype;
}
case ARRAY_TYPE:
{
- tree domain = tsubst (TYPE_DOMAIN (t), args, nargs, in_decl);
+ tree domain = tsubst (TYPE_DOMAIN (t), args, in_decl);
tree r;
if (type == TREE_TYPE (t) && domain == TYPE_DOMAIN (t))
return t;
@@ -1628,421 +5135,932 @@ tsubst (t, args, nargs, in_decl)
return r;
}
- case UNINSTANTIATED_P_TYPE:
- {
- int nparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (UPT_TEMPLATE (t)));
- tree argvec = make_tree_vec (nparms);
- tree parmvec = UPT_PARMS (t);
- int i;
- tree id, rt;
- for (i = 0; i < nparms; i++)
- TREE_VEC_ELT (argvec, i) = tsubst (TREE_VEC_ELT (parmvec, i),
- args, nargs, in_decl);
- id = lookup_template_class (DECL_NAME (UPT_TEMPLATE (t)), argvec, NULL_TREE);
- if (! IDENTIFIER_HAS_TYPE_VALUE (id)) {
- instantiate_class_template(id, 0);
- /* set up pending_classes */
- add_pending_template (id);
-
- TYPE_MAIN_VARIANT (IDENTIFIER_TYPE_VALUE (id)) =
- IDENTIFIER_TYPE_VALUE (id);
- }
- rt = IDENTIFIER_TYPE_VALUE (id);
-
- /* kung: this part handles nested type in template definition */
-
- if ( !ANON_AGGRNAME_P (DECL_NAME(TYPE_NAME(t))))
- {
- rt = search_nested_type_in_tmpl (rt, t);
- }
-
- return build_type_variant (rt, TYPE_READONLY (t), TYPE_VOLATILE (t));
- }
-
- case MINUS_EXPR:
case PLUS_EXPR:
+ case MINUS_EXPR:
return fold (build (TREE_CODE (t), TREE_TYPE (t),
- tsubst (TREE_OPERAND (t, 0), args, nargs, in_decl),
- tsubst (TREE_OPERAND (t, 1), args, nargs, in_decl)));
+ tsubst (TREE_OPERAND (t, 0), args, in_decl),
+ tsubst (TREE_OPERAND (t, 1), args, in_decl)));
case NEGATE_EXPR:
case NOP_EXPR:
return fold (build1 (TREE_CODE (t), TREE_TYPE (t),
- tsubst (TREE_OPERAND (t, 0), args, nargs, in_decl)));
+ tsubst (TREE_OPERAND (t, 0), args, in_decl)));
+
+ case TYPENAME_TYPE:
+ {
+ tree ctx = tsubst (TYPE_CONTEXT (t), args, in_decl);
+ tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args, in_decl);
+ f = make_typename_type (ctx, f);
+ return cp_build_type_variant
+ (f, TYPE_READONLY (f) || TYPE_READONLY (t),
+ TYPE_VOLATILE (f) || TYPE_VOLATILE (t));
+ }
+
+ case INDIRECT_REF:
+ return make_pointer_declarator
+ (type, tsubst (TREE_OPERAND (t, 0), args, in_decl));
+
+ case ADDR_EXPR:
+ return make_reference_declarator
+ (type, tsubst (TREE_OPERAND (t, 0), args, in_decl));
+
+ case ARRAY_REF:
+ return build_parse_node
+ (ARRAY_REF, tsubst (TREE_OPERAND (t, 0), args, in_decl),
+ tsubst_expr (TREE_OPERAND (t, 1), args, in_decl));
+
+ case CALL_EXPR:
+ return make_call_declarator
+ (tsubst (TREE_OPERAND (t, 0), args, in_decl),
+ tsubst (TREE_OPERAND (t, 1), args, in_decl),
+ TREE_OPERAND (t, 2),
+ tsubst (TREE_TYPE (t), args, in_decl));
+
+ case SCOPE_REF:
+ return build_parse_node
+ (TREE_CODE (t), tsubst (TREE_OPERAND (t, 0), args, in_decl),
+ tsubst (TREE_OPERAND (t, 1), args, in_decl));
default:
- sorry ("use of `%s' in function template",
+ sorry ("use of `%s' in template",
tree_code_name [(int) TREE_CODE (t)]);
return error_mark_node;
}
}
+void
+do_pushlevel ()
+{
+ emit_line_note (input_filename, lineno);
+ pushlevel (0);
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (0);
+}
+
tree
-instantiate_template (tmpl, targ_ptr)
- tree tmpl, *targ_ptr;
+do_poplevel ()
{
- tree targs, fndecl;
- int i, len;
- struct pending_inline *p;
- struct template_info *t;
- struct obstack *old_fmp_obstack;
- extern struct obstack *function_maybepermanent_obstack;
+ tree t;
+ int saved_warn_unused = 0;
- push_obstacks (&permanent_obstack, &permanent_obstack);
- old_fmp_obstack = function_maybepermanent_obstack;
- function_maybepermanent_obstack = &permanent_obstack;
+ if (processing_template_decl)
+ {
+ saved_warn_unused = warn_unused;
+ warn_unused = 0;
+ }
+ expand_end_bindings (getdecls (), kept_level_p (), 0);
+ if (processing_template_decl)
+ warn_unused = saved_warn_unused;
+ t = poplevel (kept_level_p (), 1, 0);
+ pop_momentary ();
+ return t;
+}
- my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 283);
- len = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (tmpl));
+/* Like tsubst, but deals with expressions. This function just replaces
+ template parms; to finish processing the resultant expression, use
+ tsubst_expr. */
- i = len;
- while (i--)
- targ_ptr[i] = copy_to_permanent (targ_ptr[i]);
+tree
+tsubst_copy (t, args, in_decl)
+ tree t, args;
+ tree in_decl;
+{
+ enum tree_code code;
- for (fndecl = DECL_TEMPLATE_INSTANTIATIONS (tmpl);
- fndecl; fndecl = TREE_CHAIN (fndecl))
+ if (t == NULL_TREE || t == error_mark_node)
+ return t;
+
+ code = TREE_CODE (t);
+
+ switch (code)
{
- tree *t1 = &TREE_VEC_ELT (TREE_PURPOSE (fndecl), 0);
- for (i = len - 1; i >= 0; i--)
- if (simple_cst_equal (t1[i], targ_ptr[i]) <= 0)
- goto no_match;
+ case PARM_DECL:
+ return do_identifier (DECL_NAME (t), 0, NULL_TREE);
- /* Here, we have a match. */
- fndecl = TREE_VALUE (fndecl);
- goto exit;
+ case CONST_DECL:
+ case FIELD_DECL:
+ if (DECL_CONTEXT (t))
+ {
+ tree ctx;
+ if (TREE_CODE (DECL_CONTEXT (t)) == FUNCTION_DECL)
+ return lookup_name (DECL_NAME (t), 0);
- no_match:
- ;
- }
+ ctx = tsubst (DECL_CONTEXT (t), args, in_decl);
+ if (ctx != DECL_CONTEXT (t))
+ return lookup_field (ctx, DECL_NAME (t), 0, 0);
+ }
+ return t;
- targs = make_tree_vec (len);
- i = len;
- while (i--)
- TREE_VEC_ELT (targs, i) = targ_ptr[i];
+ case VAR_DECL:
+ case FUNCTION_DECL:
+ if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
+ t = tsubst (t, args, in_decl);
+ mark_used (t);
+ return t;
- /* substitute template parameters */
- fndecl = tsubst (DECL_RESULT (tmpl), targ_ptr,
- TREE_VEC_LENGTH (targs), tmpl);
+ case TEMPLATE_DECL:
+ if (is_member_template (t))
+ return tsubst (t, args, in_decl);
+ else
+ return t;
+
+#if 0
+ case IDENTIFIER_NODE:
+ return do_identifier (t, 0);
+#endif
+
+ case CAST_EXPR:
+ case REINTERPRET_CAST_EXPR:
+ case CONST_CAST_EXPR:
+ case STATIC_CAST_EXPR:
+ case DYNAMIC_CAST_EXPR:
+ return build1
+ (code, tsubst (TREE_TYPE (t), args, in_decl),
+ tsubst_copy (TREE_OPERAND (t, 0), args, in_decl));
- if (fndecl == error_mark_node)
- goto exit;
+ case INDIRECT_REF:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case NEGATE_EXPR:
+ case TRUTH_NOT_EXPR:
+ case BIT_NOT_EXPR:
+ case ADDR_EXPR:
+ case CONVERT_EXPR: /* Unary + */
+ case SIZEOF_EXPR:
+ case ALIGNOF_EXPR:
+ case ARROW_EXPR:
+ case THROW_EXPR:
+ case TYPEID_EXPR:
+ return build1
+ (code, NULL_TREE,
+ tsubst_copy (TREE_OPERAND (t, 0), args, in_decl));
- assemble_external (fndecl);
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_ANDTC_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case TRUNC_MOD_EXPR:
+ case FLOOR_MOD_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case RSHIFT_EXPR:
+ case LSHIFT_EXPR:
+ case RROTATE_EXPR:
+ case LROTATE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case MAX_EXPR:
+ case MIN_EXPR:
+ case LE_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case GT_EXPR:
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ case COMPOUND_EXPR:
+ case SCOPE_REF:
+ case DOTSTAR_EXPR:
+ case MEMBER_REF:
+ return build_nt
+ (code, tsubst_copy (TREE_OPERAND (t, 0), args, in_decl),
+ tsubst_copy (TREE_OPERAND (t, 1), args, in_decl));
- /* If it's a static member fn in the template, we need to change it
- into a FUNCTION_TYPE and chop off its this pointer. */
- if (TREE_CODE (TREE_TYPE (DECL_RESULT (tmpl))) == METHOD_TYPE
- && DECL_STATIC_FUNCTION_P (fndecl))
- {
- revert_static_member_fn (&DECL_RESULT (tmpl), NULL, NULL);
- /* Chop off the this pointer that grokclassfn so kindly added
- for us (it didn't know yet if the fn was static or not). */
- DECL_ARGUMENTS (fndecl) = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
- }
-
- t = DECL_TEMPLATE_INFO (tmpl);
-
- /* If we have a preexisting version of this function, don't expand
- the template version, use the other instead. */
- if (TREE_STATIC (fndecl) || DECL_TEMPLATE_SPECIALIZATION (fndecl))
- {
- SET_DECL_TEMPLATE_SPECIALIZATION (fndecl);
- p = (struct pending_inline *)0;
- }
- else if (t->text)
- {
- SET_DECL_IMPLICIT_INSTANTIATION (fndecl);
- repo_template_used (fndecl);
- p = (struct pending_inline *) permalloc (sizeof (struct pending_inline));
- p->parm_vec = t->parm_vec;
- p->bindings = targs;
- p->can_free = 0;
- p->deja_vu = 0;
- p->buf = t->text;
- p->len = t->length;
- p->fndecl = fndecl;
+ case CALL_EXPR:
{
- int l = lineno;
- char * f = input_filename;
+ tree fn = TREE_OPERAND (t, 0);
+ if (is_overloaded_fn (fn))
+ fn = tsubst_copy (get_first_fn (fn), args, in_decl);
+ else
+ /* Sometimes FN is a LOOKUP_EXPR. */
+ fn = tsubst_copy (fn, args, in_decl);
+ return build_nt
+ (code, fn, tsubst_copy (TREE_OPERAND (t, 1), args, in_decl),
+ NULL_TREE);
+ }
- lineno = p->lineno = t->lineno;
- input_filename = p->filename = t->filename;
+ case METHOD_CALL_EXPR:
+ {
+ tree name = TREE_OPERAND (t, 0);
+ if (TREE_CODE (name) == BIT_NOT_EXPR)
+ {
+ name = tsubst_copy (TREE_OPERAND (name, 0), args, in_decl);
+ name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
+ }
+ else if (TREE_CODE (name) == SCOPE_REF
+ && TREE_CODE (TREE_OPERAND (name, 1)) == BIT_NOT_EXPR)
+ {
+ tree base = tsubst_copy (TREE_OPERAND (name, 0), args, in_decl);
+ name = TREE_OPERAND (name, 1);
+ name = tsubst_copy (TREE_OPERAND (name, 0), args, in_decl);
+ name = build1 (BIT_NOT_EXPR, NULL_TREE, name);
+ name = build_nt (SCOPE_REF, base, name);
+ }
+ else
+ name = tsubst_copy (TREE_OPERAND (t, 0), args, in_decl);
+ return build_nt
+ (code, name, tsubst_copy (TREE_OPERAND (t, 1), args, in_decl),
+ tsubst_copy (TREE_OPERAND (t, 2), args, in_decl),
+ NULL_TREE);
+ }
- extract_interface_info ();
+ case BIND_EXPR:
+ case COND_EXPR:
+ case MODOP_EXPR:
+ {
+ tree r = build_nt
+ (code, tsubst_copy (TREE_OPERAND (t, 0), args, in_decl),
+ tsubst_copy (TREE_OPERAND (t, 1), args, in_decl),
+ tsubst_copy (TREE_OPERAND (t, 2), args, in_decl));
- if (interface_unknown && flag_external_templates)
+ if (code == BIND_EXPR && !processing_template_decl)
{
- if (DECL_CLASS_CONTEXT (fndecl)
- && CLASSTYPE_INTERFACE_KNOWN (DECL_CLASS_CONTEXT (fndecl)))
- {
- interface_unknown = 0;
- interface_only
- = CLASSTYPE_INTERFACE_ONLY (DECL_CLASS_CONTEXT (fndecl));
- }
- else if (! DECL_IN_SYSTEM_HEADER (tmpl))
- warn_if_unknown_interface (tmpl);
+ /* This processing should really occur in tsubst_expr,
+ However, tsubst_expr does not recurse into expressions,
+ since it assumes that there aren't any statements
+ inside them. Instead, it simply calls
+ build_expr_from_tree. So, we need to expand the
+ BIND_EXPR here. */
+ tree rtl_expr = begin_stmt_expr ();
+ tree block = tsubst_expr (TREE_OPERAND (r, 1), args, in_decl);
+ r = finish_stmt_expr (rtl_expr, block);
}
- if (interface_unknown || ! flag_external_templates)
- p->interface = 1; /* unknown */
- else
- p->interface = interface_only ? 0 : 2;
+ return r;
+ }
- lineno = l;
- input_filename = f;
+ case NEW_EXPR:
+ {
+ tree r = build_nt
+ (code, tsubst_copy (TREE_OPERAND (t, 0), args, in_decl),
+ tsubst_copy (TREE_OPERAND (t, 1), args, in_decl),
+ tsubst_copy (TREE_OPERAND (t, 2), args, in_decl));
+ NEW_EXPR_USE_GLOBAL (r) = NEW_EXPR_USE_GLOBAL (t);
+ return r;
+ }
- extract_interface_info ();
+ case DELETE_EXPR:
+ {
+ tree r = build_nt
+ (code, tsubst_copy (TREE_OPERAND (t, 0), args, in_decl),
+ tsubst_copy (TREE_OPERAND (t, 1), args, in_decl));
+ DELETE_EXPR_USE_GLOBAL (r) = DELETE_EXPR_USE_GLOBAL (t);
+ DELETE_EXPR_USE_VEC (r) = DELETE_EXPR_USE_VEC (t);
+ return r;
+ }
+
+ case TEMPLATE_ID_EXPR:
+ {
+ /* Substituted template arguments */
+ tree targs = tsubst_copy (TREE_OPERAND (t, 1), args, in_decl);
+ tree chain;
+ for (chain = targs; chain; chain = TREE_CHAIN (chain))
+ TREE_VALUE (chain) = maybe_fold_nontype_arg (TREE_VALUE (chain));
+
+ return lookup_template_function
+ (tsubst_copy (TREE_OPERAND (t, 0), args, in_decl), targs);
}
+
+ case TREE_LIST:
+ {
+ tree purpose, value, chain;
+
+ if (t == void_list_node)
+ return t;
+
+ purpose = TREE_PURPOSE (t);
+ if (purpose)
+ purpose = tsubst_copy (purpose, args, in_decl);
+ value = TREE_VALUE (t);
+ if (value)
+ value = tsubst_copy (value, args, in_decl);
+ chain = TREE_CHAIN (t);
+ if (chain && chain != void_type_node)
+ chain = tsubst_copy (chain, args, in_decl);
+ if (purpose == TREE_PURPOSE (t)
+ && value == TREE_VALUE (t)
+ && chain == TREE_CHAIN (t))
+ return t;
+ return tree_cons (purpose, value, chain);
+ }
+
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case ENUMERAL_TYPE:
+ case INTEGER_TYPE:
+ case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
+ case TEMPLATE_PARM_INDEX:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case OFFSET_TYPE:
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ case ARRAY_TYPE:
+ case TYPENAME_TYPE:
+ case TYPE_DECL:
+ return tsubst (t, args, in_decl);
+
+ case IDENTIFIER_NODE:
+ if (IDENTIFIER_TYPENAME_P (t))
+ return build_typename_overload
+ (tsubst (TREE_TYPE (t), args, in_decl));
+ else
+ return t;
+
+ case CONSTRUCTOR:
+ return build
+ (CONSTRUCTOR, tsubst (TREE_TYPE (t), args, in_decl), NULL_TREE,
+ tsubst_copy (CONSTRUCTOR_ELTS (t), args, in_decl));
+
+ default:
+ return t;
}
- else
- p = (struct pending_inline *)0;
+}
- DECL_TEMPLATE_INSTANTIATIONS (tmpl) =
- tree_cons (targs, fndecl, DECL_TEMPLATE_INSTANTIATIONS (tmpl));
+/* Like tsubst_copy, but also does semantic processing and RTL expansion. */
- if (p == (struct pending_inline *)0)
+tree
+tsubst_expr (t, args, in_decl)
+ tree t, args;
+ tree in_decl;
+{
+ if (t == NULL_TREE || t == error_mark_node)
+ return t;
+
+ if (processing_template_decl)
+ return tsubst_copy (t, args, in_decl);
+
+ switch (TREE_CODE (t))
{
- /* do nothing */
+ case RETURN_STMT:
+ lineno = TREE_COMPLEXITY (t);
+ finish_return_stmt (tsubst_expr (RETURN_EXPR (t),
+ args, in_decl));
+ break;
+
+ case EXPR_STMT:
+ lineno = TREE_COMPLEXITY (t);
+ finish_expr_stmt (tsubst_expr (EXPR_STMT_EXPR (t),
+ args, in_decl));
+ break;
+
+ case DECL_STMT:
+ {
+ int i = suspend_momentary ();
+ tree dcl, init;
+
+ lineno = TREE_COMPLEXITY (t);
+ emit_line_note (input_filename, lineno);
+ dcl = start_decl
+ (tsubst (TREE_OPERAND (t, 0), args, in_decl),
+ tsubst (TREE_OPERAND (t, 1), args, in_decl),
+ TREE_OPERAND (t, 2) != 0, NULL_TREE, NULL_TREE);
+ init = tsubst_expr (TREE_OPERAND (t, 2), args, in_decl);
+ cp_finish_decl
+ (dcl, init, NULL_TREE, 1, /*init ? LOOKUP_ONLYCONVERTING :*/ 0);
+ resume_momentary (i);
+ return dcl;
+ }
+
+ case FOR_STMT:
+ {
+ tree tmp;
+ lineno = TREE_COMPLEXITY (t);
+
+ begin_for_stmt ();
+ for (tmp = FOR_INIT_STMT (t); tmp; tmp = TREE_CHAIN (tmp))
+ tsubst_expr (tmp, args, in_decl);
+ finish_for_init_stmt (NULL_TREE);
+ finish_for_cond (tsubst_expr (FOR_COND (t), args,
+ in_decl),
+ NULL_TREE);
+ tmp = tsubst_expr (FOR_EXPR (t), args, in_decl);
+ finish_for_expr (tmp, NULL_TREE);
+ tsubst_expr (FOR_BODY (t), args, in_decl);
+ finish_for_stmt (tmp, NULL_TREE);
+ }
+ break;
+
+ case WHILE_STMT:
+ {
+ lineno = TREE_COMPLEXITY (t);
+ begin_while_stmt ();
+ finish_while_stmt_cond (tsubst_expr (WHILE_COND (t),
+ args, in_decl),
+ NULL_TREE);
+ tsubst_expr (WHILE_BODY (t), args, in_decl);
+ finish_while_stmt (NULL_TREE);
+ }
+ break;
+
+ case DO_STMT:
+ {
+ lineno = TREE_COMPLEXITY (t);
+ begin_do_stmt ();
+ tsubst_expr (DO_BODY (t), args, in_decl);
+ finish_do_body (NULL_TREE);
+ finish_do_stmt (tsubst_expr (DO_COND (t), args,
+ in_decl),
+ NULL_TREE);
+ }
+ break;
+
+ case IF_STMT:
+ {
+ tree tmp;
+
+ lineno = TREE_COMPLEXITY (t);
+ begin_if_stmt ();
+ finish_if_stmt_cond (tsubst_expr (IF_COND (t),
+ args, in_decl),
+ NULL_TREE);
+
+ if (tmp = THEN_CLAUSE (t), tmp)
+ {
+ tsubst_expr (tmp, args, in_decl);
+ finish_then_clause (NULL_TREE);
+ }
+
+ if (tmp = ELSE_CLAUSE (t), tmp)
+ {
+ begin_else_clause ();
+ tsubst_expr (tmp, args, in_decl);
+ finish_else_clause (NULL_TREE);
+ }
+
+ finish_if_stmt ();
+ }
+ break;
+
+ case COMPOUND_STMT:
+ {
+ tree substmt;
+
+ lineno = TREE_COMPLEXITY (t);
+ begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
+ for (substmt = COMPOUND_BODY (t);
+ substmt != NULL_TREE;
+ substmt = TREE_CHAIN (substmt))
+ tsubst_expr (substmt, args, in_decl);
+ return finish_compound_stmt (COMPOUND_STMT_NO_SCOPE (t),
+ NULL_TREE);
+ }
+ break;
+
+ case BREAK_STMT:
+ lineno = TREE_COMPLEXITY (t);
+ finish_break_stmt ();
+ break;
+
+ case CONTINUE_STMT:
+ lineno = TREE_COMPLEXITY (t);
+ finish_continue_stmt ();
+ break;
+
+ case SWITCH_STMT:
+ {
+ tree val, tmp;
+
+ lineno = TREE_COMPLEXITY (t);
+ begin_switch_stmt ();
+ val = tsubst_expr (SWITCH_COND (t), args, in_decl);
+ finish_switch_cond (val);
+
+ if (tmp = TREE_OPERAND (t, 1), tmp)
+ tsubst_expr (tmp, args, in_decl);
+
+ finish_switch_stmt (val, NULL_TREE);
+ }
+ break;
+
+ case CASE_LABEL:
+ finish_case_label (tsubst_expr (CASE_LOW (t), args, in_decl),
+ tsubst_expr (CASE_HIGH (t), args, in_decl));
+ break;
+
+ case LABEL_DECL:
+ t = define_label (DECL_SOURCE_FILE (t), DECL_SOURCE_LINE (t),
+ DECL_NAME (t));
+ if (t)
+ expand_label (t);
+ break;
+
+ case GOTO_STMT:
+ lineno = TREE_COMPLEXITY (t);
+ t = GOTO_DESTINATION (t);
+ if (TREE_CODE (t) != IDENTIFIER_NODE)
+ /* Computed goto's must be tsubst'd into. On the other hand,
+ non-computed gotos must not be; the identifier in question
+ will have no binding. */
+ t = tsubst_expr (t, args, in_decl);
+ finish_goto_stmt (t);
+ break;
+
+ case ASM_STMT:
+ lineno = TREE_COMPLEXITY (t);
+ finish_asm_stmt (tsubst_expr (ASM_CV_QUAL (t), args, in_decl),
+ tsubst_expr (ASM_STRING (t), args, in_decl),
+ tsubst_expr (ASM_OUTPUTS (t), args, in_decl),
+ tsubst_expr (ASM_INPUTS (t), args, in_decl),
+ tsubst_expr (ASM_CLOBBERS (t), args, in_decl));
+ break;
+
+ case TRY_BLOCK:
+ lineno = TREE_COMPLEXITY (t);
+ begin_try_block ();
+ tsubst_expr (TRY_STMTS (t), args, in_decl);
+ finish_try_block (NULL_TREE);
+ {
+ tree handler = TRY_HANDLERS (t);
+ for (; handler; handler = TREE_CHAIN (handler))
+ tsubst_expr (handler, args, in_decl);
+ }
+ finish_handler_sequence (NULL_TREE);
+ break;
+
+ case HANDLER:
+ lineno = TREE_COMPLEXITY (t);
+ begin_handler ();
+ if (HANDLER_PARMS (t))
+ {
+ tree d = HANDLER_PARMS (t);
+ expand_start_catch_block
+ (tsubst (TREE_OPERAND (d, 1), args, in_decl),
+ tsubst (TREE_OPERAND (d, 0), args, in_decl));
+ }
+ else
+ expand_start_catch_block (NULL_TREE, NULL_TREE);
+ finish_handler_parms (NULL_TREE);
+ tsubst_expr (HANDLER_BODY (t), args, in_decl);
+ finish_handler (NULL_TREE);
+ break;
+
+ case TAG_DEFN:
+ lineno = TREE_COMPLEXITY (t);
+ t = TREE_TYPE (t);
+ if (TREE_CODE (t) == ENUMERAL_TYPE)
+ tsubst_enum (t, args, NULL);
+ break;
+
+ default:
+ return build_expr_from_tree (tsubst_copy (t, args, in_decl));
}
- else if (DECL_INLINE (fndecl))
+ return NULL_TREE;
+}
+
+tree
+instantiate_template (tmpl, targ_ptr)
+ tree tmpl, targ_ptr;
+{
+ tree fndecl;
+ int i, len;
+ struct obstack *old_fmp_obstack;
+ extern struct obstack *function_maybepermanent_obstack;
+
+ if (tmpl == error_mark_node)
+ return error_mark_node;
+
+ my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 283);
+
+ /* Check to see if we already have this specialization. This does work
+ for member template specializations; the list is set up from the
+ tsubst TEMPLATE_DECL case when the containing class is instantiated. */
+ if (DECL_FUNCTION_TEMPLATE_P (tmpl))
{
- DECL_PENDING_INLINE_INFO (fndecl) = p;
- p->next = pending_inlines;
- pending_inlines = p;
+ tree spec = retrieve_specialization (tmpl, targ_ptr);
+
+ if (spec != NULL_TREE)
+ return spec;
}
- else
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ old_fmp_obstack = function_maybepermanent_obstack;
+ function_maybepermanent_obstack = &permanent_obstack;
+
+ len = DECL_NTPARMS (tmpl);
+
+ i = len;
+ while (i--)
{
- p->next = pending_template_expansions;
- pending_template_expansions = p;
+ tree t = TREE_VEC_ELT (targ_ptr, i);
+ if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
+ {
+ tree nt = target_type (t);
+ if (IS_AGGR_TYPE (nt) && decl_function_context (TYPE_MAIN_DECL (nt)))
+ {
+ cp_error ("type `%T' composed from a local class is not a valid template-argument", t);
+ cp_error (" trying to instantiate `%D'", tmpl);
+ fndecl = error_mark_node;
+ goto out;
+ }
+ }
+ TREE_VEC_ELT (targ_ptr, i) = copy_to_permanent (t);
}
- exit:
+ targ_ptr = copy_to_permanent (targ_ptr);
+
+ /* substitute template parameters */
+ fndecl = tsubst (DECL_RESULT (tmpl), targ_ptr, tmpl);
+
+ if (flag_external_templates)
+ add_pending_template (fndecl);
+
+ out:
function_maybepermanent_obstack = old_fmp_obstack;
pop_obstacks ();
return fndecl;
}
-/* classlevel should now never be true. jason 4/12/94 */
+/* Push the name of the class template into the scope of the instantiation. */
+
void
-undo_template_name_overload (id, classlevel)
- tree id;
- int classlevel;
+overload_template_name (type)
+ tree type;
{
- tree template;
+ tree id = DECL_NAME (CLASSTYPE_TI_TEMPLATE (type));
+ tree decl;
- template = IDENTIFIER_TEMPLATE (id);
- if (!template)
+ if (IDENTIFIER_CLASS_VALUE (id)
+ && TREE_TYPE (IDENTIFIER_CLASS_VALUE (id)) == type)
return;
-#if 0 /* not yet, should get fixed properly later */
- poplevel (0, 0, 0);
-#endif
-#if 1 /* XXX */
- /* This was a botch... See `overload_template_name' just below. */
- if (!classlevel)
- poplevel (0, 0, 0);
-#endif
+ decl = build_decl (TYPE_DECL, id, type);
+ SET_DECL_ARTIFICIAL (decl);
+ pushdecl_class_level (decl);
}
-/* classlevel should now never be true. jason 4/12/94 */
-void
-overload_template_name (id, classlevel)
- tree id;
- int classlevel;
+/* Like type_unification but designed specially to handle conversion
+ operators.
+
+ The FN is a TEMPLATE_DECL for a function. The ARGS are the
+ arguments that are being used when calling it.
+
+ If FN is a conversion operator, RETURN_TYPE is the type desired as
+ the result of the conversion operator.
+
+ The EXTRA_FN_ARG, if any, is the type of an additional
+ parameter to be added to the beginning of FN's parameter list.
+
+ The other arguments are as for type_unification. */
+
+int
+fn_type_unification (fn, explicit_targs, targs, args, return_type,
+ strict, extra_fn_arg)
+ tree fn, explicit_targs, targs, args, return_type;
+ unification_kind_t strict;
+ tree extra_fn_arg;
{
- tree template, t, decl;
- struct template_info *tinfo;
+ tree parms;
- my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 284);
- template = IDENTIFIER_TEMPLATE (id);
- if (!template)
- return;
+ my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
- template = TREE_PURPOSE (template);
- tinfo = DECL_TEMPLATE_INFO (template);
- template = DECL_NAME (template);
- my_friendly_assert (template != NULL_TREE, 285);
+ parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
-#if 1 /* XXX */
- /* This was a botch... names of templates do not get their own private
- scopes. Rather, they should go into the binding level already created
- by push_template_decls. Except that there isn't one of those for
- specializations. */
- if (!classlevel)
+ if (IDENTIFIER_TYPENAME_P (DECL_NAME (fn)))
{
- pushlevel (1);
- declare_pseudo_global_level ();
+ /* This is a template conversion operator. Use the return types
+ as well as the argument types. */
+ parms = scratch_tree_cons (NULL_TREE,
+ TREE_TYPE (TREE_TYPE (fn)),
+ parms);
+ args = scratch_tree_cons (NULL_TREE, return_type, args);
}
-#endif
- t = xref_tag (tinfo->aggr, id, NULL_TREE, 1);
- my_friendly_assert (TREE_CODE (t) == RECORD_TYPE
- || TREE_CODE (t) == UNION_TYPE
- || TREE_CODE (t) == UNINSTANTIATED_P_TYPE, 286);
+ if (extra_fn_arg != NULL_TREE)
+ parms = scratch_tree_cons (NULL_TREE, extra_fn_arg, parms);
+
+ /* We allow incomplete unification without an error message here
+ because the standard doesn't seem to explicitly prohibit it. Our
+ callers must be ready to deal with unification failures in any
+ event. */
+ return type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn),
+ targs,
+ parms,
+ args,
+ explicit_targs,
+ strict, 1);
+}
- decl = build_decl (TYPE_DECL, template, t);
- SET_DECL_ARTIFICIAL (decl);
-#if 0 /* fix this later */
- /* We don't want to call here if the work has already been done. */
- t = (classlevel
- ? IDENTIFIER_CLASS_VALUE (template)
- : IDENTIFIER_LOCAL_VALUE (template));
- if (t
- && TREE_CODE (t) == TYPE_DECL
- && TREE_TYPE (t) == t)
- my_friendly_abort (85);
-#endif
+/* Type unification.
- if (classlevel)
- pushdecl_class_level (decl);
- else
- pushdecl (decl);
+ We have a function template signature with one or more references to
+ template parameters, and a parameter list we wish to fit to this
+ template. If possible, produce a list of parameters for the template
+ which will cause it to fit the supplied parameter list.
-#if 0 /* This seems bogus to me; if it isn't, explain why. (jason) */
- /* Fake this for now, just to make dwarfout.c happy. It will have to
- be done in a proper way later on. */
- DECL_CONTEXT (decl) = t;
-#endif
-}
+ Return zero for success, 2 for an incomplete match that doesn't resolve
+ all the types, and 1 for complete failure. An error message will be
+ printed only for an incomplete match.
-extern struct pending_input *to_be_restored;
+ TPARMS[NTPARMS] is an array of template parameter types.
-/* NAME is the IDENTIFIER value of a PRE_PARSED_CLASS_DECL. */
-void
-end_template_instantiation (name)
- tree name;
+ TARGS[NTPARMS] is the array into which the deduced template
+ parameter values are placed. PARMS is the function template's
+ signature (using TEMPLATE_PARM_IDX nodes), and ARGS is the argument
+ list we're trying to match against it.
+
+ The EXPLICIT_TARGS are explicit template arguments provided via a
+ template-id.
+
+ The parameter STRICT is one of:
+
+ DEDUCE_CALL:
+ We are deducing arguments for a function call, as in
+ [temp.deduct.call].
+
+ DEDUCE_CONV:
+ We are deducing arguments for a conversion function, as in
+ [temp.deduct.conv].
+
+ DEDUCE_EXACT:
+ We are deducing arguments when calculating the partial
+ ordering between specializations of function or class
+ templates, as in [temp.func.order] and [temp.class.order],
+ when doing an explicit instantiation as in [temp.explicit],
+ when determining an explicit specialization as in
+ [temp.expl.spec], or when taking the address of a function
+ template, as in [temp.deduct.funcaddr]. */
+
+int
+type_unification (tparms, targs, parms, args, explicit_targs,
+ strict, allow_incomplete)
+ tree tparms, targs, parms, args, explicit_targs;
+ unification_kind_t strict;
+ int allow_incomplete;
{
- tree t, decl;
+ int* explicit_mask;
+ int i;
- processing_template_defn--;
- if (!flag_external_templates)
- interface_unknown--;
+ for (i = 0; i < TREE_VEC_LENGTH (tparms); i++)
+ TREE_VEC_ELT (targs, i) = NULL_TREE;
- /* Restore the old parser input state. */
- if (yychar == YYEMPTY)
- yychar = yylex ();
- if (yychar != END_OF_SAVED_INPUT)
- error ("parse error at end of class template");
- else
+ if (explicit_targs != NULL_TREE)
{
- restore_pending_input (to_be_restored);
- to_be_restored = 0;
- }
-
- /* Our declarations didn't get stored in the global slot, since
- there was a (supposedly tags-transparent) scope in between. */
- t = IDENTIFIER_TYPE_VALUE (name);
- my_friendly_assert (t != NULL_TREE
- && TREE_CODE_CLASS (TREE_CODE (t)) == 't',
- 287);
- SET_CLASSTYPE_IMPLICIT_INSTANTIATION (t);
- /* Make methods of template classes static, unless
- -fexternal-templates is given. */
- if (!flag_external_templates)
- SET_CLASSTYPE_INTERFACE_UNKNOWN (t);
- decl = IDENTIFIER_GLOBAL_VALUE (name);
- my_friendly_assert (TREE_CODE (decl) == TYPE_DECL, 288);
-
- undo_template_name_overload (name, 0);
- t = IDENTIFIER_TEMPLATE (name);
- pop_template_decls (DECL_TEMPLATE_PARMS (TREE_PURPOSE (t)), TREE_VALUE (t),
- 0);
- /* This will fix up the type-value field. */
- pushdecl (decl);
- pop_from_top_level ();
+ tree arg_vec;
+ arg_vec = coerce_template_parms (tparms, explicit_targs, NULL_TREE, 0,
+ 0);
-#ifdef DWARF_DEBUGGING_INFO
- if (write_symbols == DWARF_DEBUG && TREE_CODE (decl) == TYPE_DECL)
- {
- /* We just completed the definition of a new file-scope type,
- so we can go ahead and output debug-info for it now. */
- TYPE_STUB_DECL (TREE_TYPE (decl)) = decl;
- rest_of_type_compilation (TREE_TYPE (decl), 1);
+ if (arg_vec == error_mark_node)
+ return 1;
+
+ explicit_mask = alloca (sizeof (int) * TREE_VEC_LENGTH (targs));
+ bzero ((char *) explicit_mask, sizeof(int) * TREE_VEC_LENGTH (targs));
+
+ for (i = 0;
+ i < TREE_VEC_LENGTH (arg_vec)
+ && TREE_VEC_ELT (arg_vec, i) != NULL_TREE;
+ ++i)
+ {
+ TREE_VEC_ELT (targs, i) = TREE_VEC_ELT (arg_vec, i);
+ /* Let unify know that this argument was explicit. */
+ explicit_mask [i] = 1;
+ }
}
-#endif /* DWARF_DEBUGGING_INFO */
+ else
+ explicit_mask = 0;
- /* Restore interface/implementation settings. */
- extract_interface_info ();
+ return
+ type_unification_real (tparms, targs, parms, args, 0,
+ strict, allow_incomplete, explicit_mask);
}
-
-/* Store away the text of an template. */
+
+/* Adjust types before performing type deduction, as described in
+ [temp.deduct.call] and [temp.deduct.conv]. The rules in these two
+ sections are symmetric. PARM is the type of a function parameter
+ or the return type of the conversion function. ARG is the type of
+ the argument passed to the call, or the type of the value
+ intialized with the result of the conversion function. */
void
-reinit_parse_for_template (yychar, d1, d2)
- int yychar;
- tree d1, d2;
+maybe_adjust_types_for_deduction (strict, parm, arg)
+ unification_kind_t strict;
+ tree* parm;
+ tree* arg;
{
- struct template_info *template_info;
- extern struct obstack inline_text_obstack; /* see comment in lex.c */
-
- if (d2 == NULL_TREE || d2 == error_mark_node)
+ switch (strict)
{
- lose:
- /* @@ Should use temp obstack, and discard results. */
- reinit_parse_for_block (yychar, &inline_text_obstack, 1);
+ case DEDUCE_CALL:
+ break;
+
+ case DEDUCE_CONV:
+ {
+ /* Swap PARM and ARG throughout the remainder of this
+ function; the handling is precisely symmetric since PARM
+ will initialize ARG rather than vice versa. */
+ tree* temp = parm;
+ parm = arg;
+ arg = temp;
+ break;
+ }
+
+ case DEDUCE_EXACT:
+ /* There is nothing to do in this case. */
return;
+
+ default:
+ my_friendly_abort (0);
}
- if (TREE_CODE (d2) == IDENTIFIER_NODE)
- d2 = IDENTIFIER_GLOBAL_VALUE (d2);
- if (!d2)
- goto lose;
- template_info = DECL_TEMPLATE_INFO (d2);
- if (!template_info)
+ if (TREE_CODE (*parm) != REFERENCE_TYPE)
{
- template_info = (struct template_info *) permalloc (sizeof (struct template_info));
- bzero ((char *) template_info, sizeof (struct template_info));
- DECL_TEMPLATE_INFO (d2) = template_info;
+ /* [temp.deduct.call]
+
+ If P is not a reference type:
+
+ --If A is an array type, the pointer type produced by the
+ array-to-pointer standard conversion (_conv.array_) is
+ used in place of A for type deduction; otherwise,
+
+ --If A is a function type, the pointer type produced by
+ the function-to-pointer standard conversion
+ (_conv.func_) is used in place of A for type deduction;
+ otherwise,
+
+ --If A is a cv-qualified type, the top level
+ cv-qualifiers of A's type are ignored for type
+ deduction. */
+ if (TREE_CODE (*arg) == ARRAY_TYPE)
+ *arg = build_pointer_type (TREE_TYPE (*arg));
+ else if (TREE_CODE (*arg) == FUNCTION_TYPE
+ || TREE_CODE (*arg) == METHOD_TYPE)
+ *arg = build_pointer_type (*arg);
+ else
+ *arg = TYPE_MAIN_VARIANT (*arg);
}
- template_info->filename = input_filename;
- template_info->lineno = lineno;
- reinit_parse_for_block (yychar, &inline_text_obstack, 1);
- template_info->text = obstack_base (&inline_text_obstack);
- template_info->length = obstack_object_size (&inline_text_obstack);
- obstack_finish (&inline_text_obstack);
- template_info->parm_vec = d1;
+
+ /* [temp.deduct.call]
+
+ If P is a cv-qualified type, the top level cv-qualifiers
+ of P's type are ignored for type deduction. If P is a
+ reference type, the type referred to by P is used for
+ type deduction. */
+ *parm = TYPE_MAIN_VARIANT (*parm);
+ if (TREE_CODE (*parm) == REFERENCE_TYPE)
+ *parm = TREE_TYPE (*parm);
}
-/* Type unification.
-
- We have a function template signature with one or more references to
- template parameters, and a parameter list we wish to fit to this
- template. If possible, produce a list of parameters for the template
- which will cause it to fit the supplied parameter list.
-
- Return zero for success, 2 for an incomplete match that doesn't resolve
- all the types, and 1 for complete failure. An error message will be
- printed only for an incomplete match.
-
- TPARMS[NTPARMS] is an array of template parameter types;
- TARGS[NTPARMS] is the array of template parameter values. PARMS is
- the function template's signature (using TEMPLATE_PARM_IDX nodes),
- and ARGS is the argument list we're trying to match against it.
+/* Like type_unfication. EXPLICIT_MASK, if non-NULL, is an array of
+ integers, with ones in positions corresponding to arguments in
+ targs that were provided explicitly, and zeros elsewhere.
- If SUBR is 1, we're being called recursively (to unify the arguments of
- a function or method parameter of a function template), so don't zero
- out targs and don't fail on an incomplete match. */
+ If SUBR is 1, we're being called recursively (to unify the
+ arguments of a function or method parameter of a function
+ template). */
-int
-type_unification (tparms, targs, parms, args, nsubsts, subr)
- tree tparms, *targs, parms, args;
- int *nsubsts, subr;
+static int
+type_unification_real (tparms, targs, parms, args, subr,
+ strict, allow_incomplete, explicit_mask)
+ tree tparms, targs, parms, args;
+ int subr;
+ unification_kind_t strict;
+ int allow_incomplete;
+ int* explicit_mask;
{
tree parm, arg;
int i;
int ntparms = TREE_VEC_LENGTH (tparms);
+ int sub_strict;
my_friendly_assert (TREE_CODE (tparms) == TREE_VEC, 289);
- my_friendly_assert (TREE_CODE (parms) == TREE_LIST, 290);
+ my_friendly_assert (parms == NULL_TREE
+ || TREE_CODE (parms) == TREE_LIST, 290);
/* ARGS could be NULL (via a call from parse.y to
build_x_function_call). */
if (args)
my_friendly_assert (TREE_CODE (args) == TREE_LIST, 291);
my_friendly_assert (ntparms > 0, 292);
- if (!subr)
- bzero ((char *) targs, sizeof (tree) * ntparms);
+ switch (strict)
+ {
+ case DEDUCE_CALL:
+ sub_strict = UNIFY_ALLOW_MORE_CV_QUAL | UNIFY_ALLOW_DERIVED;
+ break;
+
+ case DEDUCE_CONV:
+ sub_strict = UNIFY_ALLOW_LESS_CV_QUAL;
+ break;
+
+ case DEDUCE_EXACT:
+ sub_strict = UNIFY_ALLOW_NONE;
+ break;
+
+ default:
+ my_friendly_abort (0);
+ }
while (parms
&& parms != void_list_node
@@ -2059,11 +6077,33 @@ type_unification (tparms, targs, parms, args, nsubsts, subr)
if (arg == unknown_type_node)
return 1;
- if (! uses_template_parms (parm)
- && TREE_CODE_CLASS (TREE_CODE (arg)) != 't')
+ /* Conversions will be performed on a function argument that
+ corresponds with a function parameter that contains only
+ non-deducible template parameters and explicitly specified
+ template parameters. */
+ if (! uses_template_parms (parm))
{
- if (can_convert_arg (parm, TREE_TYPE (arg), arg))
+ tree type;
+
+ if (TREE_CODE_CLASS (TREE_CODE (arg)) != 't')
+ type = TREE_TYPE (arg);
+ else
+ {
+ type = arg;
+ arg = NULL_TREE;
+ }
+
+ if (strict == DEDUCE_EXACT)
+ {
+ if (comptypes (parm, type, 1))
+ continue;
+ }
+ else
+ /* It might work; we shouldn't check now, because we might
+ get into infinite recursion. Overload resolution will
+ handle it. */
continue;
+
return 1;
}
@@ -2076,41 +6116,38 @@ type_unification (tparms, targs, parms, args, nsubsts, subr)
if (TREE_CODE_CLASS (TREE_CODE (arg)) != 't')
{
my_friendly_assert (TREE_TYPE (arg) != NULL_TREE, 293);
- if (TREE_CODE (arg) == TREE_LIST
- && TREE_TYPE (arg) == unknown_type_node
- && TREE_CODE (TREE_VALUE (arg)) == TEMPLATE_DECL)
+ if (TREE_CODE (arg) == OVERLOAD
+ && TREE_CODE (OVL_FUNCTION (arg)) == TEMPLATE_DECL)
{
- int nsubsts, ntparms;
- tree *targs;
+ tree targs;
+ tree arg_type;
/* Have to back unify here */
- arg = TREE_VALUE (arg);
- nsubsts = 0;
- ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (arg));
- targs = (tree *) alloca (sizeof (tree) * ntparms);
- parm = tree_cons (NULL_TREE, parm, NULL_TREE);
- return type_unification (DECL_TEMPLATE_PARMS (arg), targs,
- TYPE_ARG_TYPES (TREE_TYPE (arg)),
- parm, &nsubsts, 0);
+ arg = OVL_FUNCTION (arg);
+ targs = make_scratch_vec (DECL_NTPARMS (arg));
+ arg_type = TREE_TYPE (arg);
+ maybe_adjust_types_for_deduction (strict, &parm, &arg_type);
+ parm = expr_tree_cons (NULL_TREE, parm, NULL_TREE);
+ arg_type = scratch_tree_cons (NULL_TREE, arg_type, NULL_TREE);
+ return
+ type_unification (DECL_INNERMOST_TEMPLATE_PARMS (arg),
+ targs, arg_type, parm, NULL_TREE,
+ DEDUCE_EXACT, allow_incomplete);
}
arg = TREE_TYPE (arg);
}
#endif
- if (TREE_CODE (arg) == REFERENCE_TYPE)
- arg = TREE_TYPE (arg);
-
- if (TREE_CODE (parm) != REFERENCE_TYPE)
+ if (! flag_ansi && arg == TREE_TYPE (null_node))
{
- if (TREE_CODE (arg) == FUNCTION_TYPE
- || TREE_CODE (arg) == METHOD_TYPE)
- arg = build_pointer_type (arg);
- else if (TREE_CODE (arg) == ARRAY_TYPE)
- arg = build_pointer_type (TREE_TYPE (arg));
- else
- arg = TYPE_MAIN_VARIANT (arg);
+ warning ("using type void* for NULL");
+ arg = ptr_type_node;
}
- switch (unify (tparms, targs, ntparms, parm, arg, nsubsts))
+ if (!subr)
+ maybe_adjust_types_for_deduction (strict, &parm, &arg);
+
+ switch (unify (tparms, targs, parm, arg, sub_strict,
+ explicit_mask))
{
case 0:
break;
@@ -2129,21 +6166,78 @@ type_unification (tparms, targs, parms, args, nsubsts, subr)
return 1;
if (!subr)
for (i = 0; i < ntparms; i++)
- if (!targs[i])
+ if (TREE_VEC_ELT (targs, i) == NULL_TREE)
{
- error ("incomplete type unification");
+ if (!allow_incomplete)
+ error ("incomplete type unification");
return 2;
}
return 0;
}
-/* Tail recursion is your friend. */
-static int
-unify (tparms, targs, ntparms, parm, arg, nsubsts)
- tree tparms, *targs, parm, arg;
- int *nsubsts, ntparms;
+/* Returns the level of DECL, which declares a template parameter. */
+
+int
+template_decl_level (decl)
+ tree decl;
+{
+ switch (TREE_CODE (decl))
+ {
+ case TYPE_DECL:
+ case TEMPLATE_DECL:
+ return TEMPLATE_TYPE_LEVEL (TREE_TYPE (decl));
+
+ case PARM_DECL:
+ return TEMPLATE_PARM_LEVEL (DECL_INITIAL (decl));
+
+ default:
+ my_friendly_abort (0);
+ return 0;
+ }
+}
+
+/* Decide whether ARG can be unified with PARM, considering only the
+ cv-qualifiers of each type, given STRICT as documented for unify.
+ Returns non-zero iff the unification is OK on that basis.*/
+
+int
+check_cv_quals_for_unify (strict, arg, parm)
+ int strict;
+ tree arg;
+ tree parm;
+{
+ return !((!(strict & UNIFY_ALLOW_MORE_CV_QUAL)
+ && (TYPE_READONLY (arg) < TYPE_READONLY (parm)
+ || TYPE_VOLATILE (arg) < TYPE_VOLATILE (parm)))
+ || (!(strict & UNIFY_ALLOW_LESS_CV_QUAL)
+ && (TYPE_READONLY (arg) > TYPE_READONLY (parm)
+ || TYPE_VOLATILE (arg) > TYPE_VOLATILE (parm))));
+}
+
+/* Takes parameters as for type_unification. Returns 0 if the
+ type deduction suceeds, 1 otherwise. The parameter STRICT is a
+ bitwise or of the following flags:
+
+ UNIFY_ALLOW_NONE:
+ Require an exact match between PARM and ARG.
+ UNIFY_ALLOW_MORE_CV_QUAL:
+ Allow the deduced ARG to be more cv-qualified than ARG.
+ UNIFY_ALLOW_LESS_CV_QUAL:
+ Allow the deduced ARG to be less cv-qualified than ARG.
+ UNIFY_ALLOW_DERIVED:
+ Allow the deduced ARG to be a template base class of ARG,
+ or a pointer to a template base class of the type pointed to by
+ ARG. */
+
+int
+unify (tparms, targs, parm, arg, strict, explicit_mask)
+ tree tparms, targs, parm, arg;
+ int strict;
+ int* explicit_mask;
{
int idx;
+ tree targ;
+ tree tparm;
/* I don't think this will do the right thing with respect to types.
But the only case I've seen it in so far has been array bounds, where
@@ -2156,133 +6250,264 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
return 1;
if (arg == unknown_type_node)
return 1;
- if (arg == parm)
+ /* If PARM uses template parameters, then we can't bail out here,
+ even in ARG == PARM, since we won't record unifications for the
+ template parameters. We might need them if we're trying to
+ figure out which of two things is more specialized. */
+ if (arg == parm && !uses_template_parms (parm))
return 0;
+ /* Immediately reject some pairs that won't unify because of
+ cv-qualification mismatches. */
+ if (TREE_CODE (arg) == TREE_CODE (parm)
+ && TREE_CODE_CLASS (TREE_CODE (arg)) == 't'
+ /* We check the cv-qualifiers when unifying with template type
+ parameters below. We want to allow ARG `const T' to unify with
+ PARM `T' for example, when computing which of two templates
+ is more specialized, for example. */
+ && TREE_CODE (arg) != TEMPLATE_TYPE_PARM
+ && !check_cv_quals_for_unify (strict, arg, parm))
+ return 1;
+
switch (TREE_CODE (parm))
{
+ case TYPENAME_TYPE:
+ /* In a type which contains a nested-name-specifier, template
+ argument values cannot be deduced for template parameters used
+ within the nested-name-specifier. */
+ return 0;
+
case TEMPLATE_TYPE_PARM:
- (*nsubsts)++;
- if (TEMPLATE_TYPE_TPARMLIST (parm) != tparms)
- {
- error ("mixed template headers?!");
- my_friendly_abort (86);
- return 1;
- }
+ case TEMPLATE_TEMPLATE_PARM:
+ tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
+
+ if (TEMPLATE_TYPE_LEVEL (parm)
+ != template_decl_level (tparm))
+ /* The PARM is not one we're trying to unify. Just check
+ to see if it matches ARG. */
+ return (TREE_CODE (arg) == TREE_CODE (parm)
+ && comptypes (parm, arg, 1)) ? 0 : 1;
idx = TEMPLATE_TYPE_IDX (parm);
-#if 0
- /* Template type parameters cannot contain cv-quals; i.e.
- template <class T> void f (T& a, T& b) will not generate
- void f (const int& a, const int& b). */
- if (TYPE_READONLY (arg) > TYPE_READONLY (parm)
- || TYPE_VOLATILE (arg) > TYPE_VOLATILE (parm))
- return 1;
- arg = TYPE_MAIN_VARIANT (arg);
-#else
- {
- int constp = TYPE_READONLY (arg) > TYPE_READONLY (parm);
- int volatilep = TYPE_VOLATILE (arg) > TYPE_VOLATILE (parm);
- arg = cp_build_type_variant (arg, constp, volatilep);
- }
-#endif
- /* Simple cases: Value already set, does match or doesn't. */
- if (targs[idx] == arg)
- return 0;
- else if (targs[idx])
- return 1;
+ targ = TREE_VEC_ELT (targs, idx);
+ tparm = TREE_VALUE (TREE_VEC_ELT (tparms, idx));
+
/* Check for mixed types and values. */
- if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TYPE_DECL)
+ if ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM
+ && TREE_CODE (tparm) != TYPE_DECL)
+ || (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
+ && TREE_CODE (tparm) != TEMPLATE_DECL))
return 1;
- targs[idx] = arg;
- return 0;
- case TEMPLATE_CONST_PARM:
- (*nsubsts)++;
- idx = TEMPLATE_CONST_IDX (parm);
- if (targs[idx] == arg)
+
+ if (!strict && targ != NULL_TREE
+ && explicit_mask && explicit_mask[idx])
+ /* An explicit template argument. Don't even try to match
+ here; the overload resolution code will manage check to
+ see whether the call is legal. */
return 0;
- else if (targs[idx])
+
+ if (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM)
{
- tree t = targs[idx];
- if (TREE_CODE (t) == TREE_CODE (arg))
- switch (TREE_CODE (arg))
+ if (CLASSTYPE_TEMPLATE_INFO (parm))
+ {
+ /* We arrive here when PARM does not involve template
+ specialization. */
+
+ /* ARG must be constructed from a template class. */
+ if (TREE_CODE (arg) != RECORD_TYPE || !CLASSTYPE_TEMPLATE_INFO (arg))
+ return 1;
+
{
- case INTEGER_CST:
- if (tree_int_cst_equal (t, arg))
- return 0;
- break;
- case REAL_CST:
- if (REAL_VALUES_EQUAL (TREE_REAL_CST (t), TREE_REAL_CST (arg)))
- return 0;
- break;
- /* STRING_CST values are not valid template const parms. */
- default:
- ;
+ tree parmtmpl = CLASSTYPE_TI_TEMPLATE (parm);
+ tree parmvec = CLASSTYPE_TI_ARGS (parm);
+ tree argvec = CLASSTYPE_TI_ARGS (arg);
+ tree argtmplvec
+ = DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (arg));
+ int i;
+
+ /* The parameter and argument roles have to be switched here
+ in order to handle default arguments properly. For example,
+ template<template <class> class TT> void f(TT<int>)
+ should be able to accept vector<int> which comes from
+ template <class T, class Allocator = allocator>
+ class vector. */
+
+ if (coerce_template_parms (argtmplvec, parmvec, parmtmpl, 1, 1)
+ == error_mark_node)
+ return 1;
+
+ /* Deduce arguments T, i from TT<T> or TT<i>. */
+ for (i = 0; i < TREE_VEC_LENGTH (parmvec); ++i)
+ {
+ tree t = TREE_VEC_ELT (parmvec, i);
+ if (TREE_CODE (t) != TEMPLATE_TYPE_PARM
+ && TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM
+ && TREE_CODE (t) != TEMPLATE_PARM_INDEX)
+ continue;
+
+ /* This argument can be deduced. */
+
+ if (unify (tparms, targs, t,
+ TREE_VEC_ELT (argvec, i),
+ UNIFY_ALLOW_NONE, explicit_mask))
+ return 1;
+ }
}
- my_friendly_abort (87);
- return 1;
+ arg = CLASSTYPE_TI_TEMPLATE (arg);
+ }
+ }
+ else
+ {
+ /* If PARM is `const T' and ARG is only `int', we don't have
+ a match unless we are allowing additional qualification.
+ If ARG is `const int' and PARM is just `T' that's OK;
+ that binds `const int' to `T'. */
+ if (!check_cv_quals_for_unify (strict | UNIFY_ALLOW_LESS_CV_QUAL,
+ arg, parm))
+ return 1;
+
+ /* Consider the case where ARG is `const volatile int' and
+ PARM is `const T'. Then, T should be `volatile int'. */
+ arg =
+ cp_build_type_variant (arg,
+ TYPE_READONLY (arg) > TYPE_READONLY (parm),
+ TYPE_VOLATILE (arg) > TYPE_VOLATILE (parm));
}
-/* else if (typeof arg != tparms[idx])
- return 1;*/
- targs[idx] = copy_to_permanent (arg);
+ /* Simple cases: Value already set, does match or doesn't. */
+ if (targ != NULL_TREE
+ && (comptypes (targ, arg, 1)
+ || (explicit_mask && explicit_mask[idx])))
+ return 0;
+ else if (targ)
+ return 1;
+ TREE_VEC_ELT (targs, idx) = arg;
+ return 0;
+
+ case TEMPLATE_PARM_INDEX:
+ tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
+
+ if (TEMPLATE_PARM_LEVEL (parm)
+ != template_decl_level (tparm))
+ /* The PARM is not one we're trying to unify. Just check
+ to see if it matches ARG. */
+ return (TREE_CODE (arg) == TREE_CODE (parm)
+ && cp_tree_equal (parm, arg) > 0) ? 0 : 1;
+
+ idx = TEMPLATE_PARM_IDX (parm);
+ targ = TREE_VEC_ELT (targs, idx);
+
+ if (targ)
+ {
+ int i = (cp_tree_equal (targ, arg) > 0);
+ if (i == 1)
+ return 0;
+ else if (i == 0)
+ return 1;
+ else
+ my_friendly_abort (42);
+ }
+
+ TREE_VEC_ELT (targs, idx) = copy_to_permanent (arg);
return 0;
case POINTER_TYPE:
- if (TREE_CODE (arg) != POINTER_TYPE)
- return 1;
- return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
- nsubsts);
+ {
+ int sub_strict;
+
+ if (TREE_CODE (arg) == RECORD_TYPE && TYPE_PTRMEMFUNC_FLAG (arg))
+ return (unify (tparms, targs, parm,
+ TYPE_PTRMEMFUNC_FN_TYPE (arg), strict,
+ explicit_mask));
+
+ if (TREE_CODE (arg) != POINTER_TYPE)
+ return 1;
+
+ /* [temp.deduct.call]
+
+ A can be another pointer or pointer to member type that can
+ be converted to the deduced A via a qualification
+ conversion (_conv.qual_).
+
+ We pass down STRICT here rather than UNIFY_ALLOW_NONE.
+ This will allow for additional cv-qualification of the
+ pointed-to types if appropriate. In general, this is a bit
+ too generous; we are only supposed to allow qualification
+ conversions and this method will allow an ARG of char** and
+ a deduced ARG of const char**. However, overload
+ resolution will subsequently invalidate the candidate, so
+ this is probably OK. */
+ sub_strict = strict;
+
+ if (TREE_CODE (TREE_TYPE (arg)) != RECORD_TYPE
+ || TYPE_PTRMEMFUNC_FLAG (TREE_TYPE (arg)))
+ /* The derived-to-base conversion only persists through one
+ level of pointers. */
+ sub_strict &= ~UNIFY_ALLOW_DERIVED;
+
+ return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE
+ (arg), sub_strict, explicit_mask);
+ }
case REFERENCE_TYPE:
- if (TREE_CODE (arg) == REFERENCE_TYPE)
- arg = TREE_TYPE (arg);
- return unify (tparms, targs, ntparms, TREE_TYPE (parm), arg, nsubsts);
+ if (TREE_CODE (arg) != REFERENCE_TYPE)
+ return 1;
+ return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
+ UNIFY_ALLOW_NONE, explicit_mask);
case ARRAY_TYPE:
if (TREE_CODE (arg) != ARRAY_TYPE)
return 1;
- if (unify (tparms, targs, ntparms, TYPE_DOMAIN (parm), TYPE_DOMAIN (arg),
- nsubsts) != 0)
+ if ((TYPE_DOMAIN (parm) == NULL_TREE)
+ != (TYPE_DOMAIN (arg) == NULL_TREE))
return 1;
- return unify (tparms, targs, ntparms, TREE_TYPE (parm), TREE_TYPE (arg),
- nsubsts);
+ if (TYPE_DOMAIN (parm) != NULL_TREE
+ && unify (tparms, targs, TYPE_DOMAIN (parm),
+ TYPE_DOMAIN (arg), UNIFY_ALLOW_NONE, explicit_mask) != 0)
+ return 1;
+ return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
+ UNIFY_ALLOW_NONE, explicit_mask);
case REAL_TYPE:
+ case COMPLEX_TYPE:
case INTEGER_TYPE:
+ case BOOLEAN_TYPE:
+ case VOID_TYPE:
if (TREE_CODE (arg) != TREE_CODE (parm))
return 1;
if (TREE_CODE (parm) == INTEGER_TYPE)
{
if (TYPE_MIN_VALUE (parm) && TYPE_MIN_VALUE (arg)
- && unify (tparms, targs, ntparms,
- TYPE_MIN_VALUE (parm), TYPE_MIN_VALUE (arg), nsubsts))
+ && unify (tparms, targs, TYPE_MIN_VALUE (parm),
+ TYPE_MIN_VALUE (arg), UNIFY_ALLOW_NONE, explicit_mask))
return 1;
if (TYPE_MAX_VALUE (parm) && TYPE_MAX_VALUE (arg)
- && unify (tparms, targs, ntparms,
- TYPE_MAX_VALUE (parm), TYPE_MAX_VALUE (arg), nsubsts))
+ && unify (tparms, targs, TYPE_MAX_VALUE (parm),
+ TYPE_MAX_VALUE (arg), UNIFY_ALLOW_NONE, explicit_mask))
return 1;
}
+ else if (TREE_CODE (parm) == REAL_TYPE
+ /* We use the TYPE_MAIN_VARIANT since we have already
+ checked cv-qualification at the top of the
+ function. */
+ && !comptypes (TYPE_MAIN_VARIANT (arg),
+ TYPE_MAIN_VARIANT (parm), 1))
+ return 1;
+
/* As far as unification is concerned, this wins. Later checks
will invalidate it if necessary. */
return 0;
/* Types INTEGER_CST and MINUS_EXPR can come from array bounds. */
+ /* Type INTEGER_CST can come from ordinary constant template args. */
case INTEGER_CST:
+ while (TREE_CODE (arg) == NOP_EXPR)
+ arg = TREE_OPERAND (arg, 0);
+
if (TREE_CODE (arg) != INTEGER_CST)
return 1;
return !tree_int_cst_equal (parm, arg);
- case MINUS_EXPR:
- {
- tree t1, t2;
- t1 = TREE_OPERAND (parm, 0);
- t2 = TREE_OPERAND (parm, 1);
- return unify (tparms, targs, ntparms, t1,
- fold (build (PLUS_EXPR, integer_type_node, arg, t2)),
- nsubsts);
- }
-
case TREE_VEC:
{
int i;
@@ -2291,282 +6516,487 @@ unify (tparms, targs, ntparms, parm, arg, nsubsts)
if (TREE_VEC_LENGTH (parm) != TREE_VEC_LENGTH (arg))
return 1;
for (i = TREE_VEC_LENGTH (parm) - 1; i >= 0; i--)
- if (unify (tparms, targs, ntparms,
+ if (unify (tparms, targs,
TREE_VEC_ELT (parm, i), TREE_VEC_ELT (arg, i),
- nsubsts))
+ UNIFY_ALLOW_NONE, explicit_mask))
return 1;
return 0;
}
- case UNINSTANTIATED_P_TYPE:
- {
- tree a;
- /* Unification of something that is not a class fails. */
- if (! IS_AGGR_TYPE (arg))
- return 1;
- a = IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (arg));
- if (a && UPT_TEMPLATE (parm) == TREE_PURPOSE (a))
- return unify (tparms, targs, ntparms, UPT_PARMS (parm),
- TREE_VALUE (a), nsubsts);
- /* FIXME: Should check base conversions here. */
- return 1;
- }
-
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_FLAG (parm))
- return unify (tparms, targs, ntparms, TYPE_PTRMEMFUNC_FN_TYPE (parm),
- arg, nsubsts);
+ return unify (tparms, targs, TYPE_PTRMEMFUNC_FN_TYPE (parm),
+ arg, strict, explicit_mask);
- /* Allow trivial conversions. */
- if (TYPE_MAIN_VARIANT (parm) != TYPE_MAIN_VARIANT (arg)
- || TYPE_READONLY (parm) < TYPE_READONLY (arg)
- || TYPE_VOLATILE (parm) < TYPE_VOLATILE (arg))
+ if (TREE_CODE (arg) != RECORD_TYPE)
return 1;
- return 0;
+
+ if (CLASSTYPE_TEMPLATE_INFO (parm) && uses_template_parms (parm))
+ {
+ tree t = NULL_TREE;
+ if (strict & UNIFY_ALLOW_DERIVED)
+ /* [temp.deduct.call]
+
+ If P is a class, and P has the form template-id, then A
+ can be a derived class of the deduced A. Likewise, if
+ P is a pointer to a class of the form template-id, A
+ can be a pointer to a derived class pointed to by the
+ deduced A. */
+ t = get_template_base (CLASSTYPE_TI_TEMPLATE (parm), arg);
+ else if
+ (CLASSTYPE_TEMPLATE_INFO (arg)
+ && CLASSTYPE_TI_TEMPLATE (parm) == CLASSTYPE_TI_TEMPLATE (arg))
+ t = arg;
+ if (! t || t == error_mark_node)
+ return 1;
- case METHOD_TYPE:
- if (TREE_CODE (arg) != METHOD_TYPE)
+ return unify (tparms, targs, CLASSTYPE_TI_ARGS (parm),
+ CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE,
+ explicit_mask);
+ }
+ else if (!comptypes (TYPE_MAIN_VARIANT (parm),
+ TYPE_MAIN_VARIANT (arg), 1))
return 1;
- goto check_args;
+ return 0;
+ case METHOD_TYPE:
case FUNCTION_TYPE:
- if (TREE_CODE (arg) != FUNCTION_TYPE)
+ if (TREE_CODE (arg) != TREE_CODE (parm))
return 1;
- check_args:
- if (unify (tparms, targs, ntparms, TREE_TYPE (parm),
- TREE_TYPE (arg), nsubsts))
+
+ if (unify (tparms, targs, TREE_TYPE (parm),
+ TREE_TYPE (arg), UNIFY_ALLOW_NONE, explicit_mask))
return 1;
- return type_unification (tparms, targs, TYPE_ARG_TYPES (parm),
- TYPE_ARG_TYPES (arg), nsubsts, 1);
+ return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
+ TYPE_ARG_TYPES (arg), 1,
+ DEDUCE_EXACT, 0, explicit_mask);
case OFFSET_TYPE:
if (TREE_CODE (arg) != OFFSET_TYPE)
return 1;
- if (unify (tparms, targs, ntparms, TYPE_OFFSET_BASETYPE (parm),
- TYPE_OFFSET_BASETYPE (arg), nsubsts))
+ if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
+ TYPE_OFFSET_BASETYPE (arg), UNIFY_ALLOW_NONE, explicit_mask))
return 1;
- return unify (tparms, targs, ntparms, TREE_TYPE (parm),
- TREE_TYPE (arg), nsubsts);
+ return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
+ UNIFY_ALLOW_NONE, explicit_mask);
+
+ case CONST_DECL:
+ if (arg != decl_constant_value (parm))
+ return 1;
+ return 0;
+
+ case TEMPLATE_DECL:
+ /* Matched cases are handled by the ARG == PARM test above. */
+ return 1;
+
+ case MINUS_EXPR:
+ if (TREE_CODE (TREE_OPERAND (parm, 1)) == INTEGER_CST)
+ {
+ /* We handle this case specially, since it comes up with
+ arrays. In particular, something like:
+
+ template <int N> void f(int (&x)[N]);
+
+ Here, we are trying to unify the range type, which
+ looks like [0 ... (N - 1)]. */
+ tree t, t1, t2;
+ t1 = TREE_OPERAND (parm, 0);
+ t2 = TREE_OPERAND (parm, 1);
+
+ /* Should this be a regular fold? */
+ t = maybe_fold_nontype_arg (build (PLUS_EXPR,
+ integer_type_node,
+ arg, t2));
+
+ return unify (tparms, targs, t1, t, UNIFY_ALLOW_NONE,
+ explicit_mask);
+ }
+ /* else fall through */
default:
- sorry ("use of `%s' in template type unification",
- tree_code_name [(int) TREE_CODE (parm)]);
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (parm))))
+ {
+ /* We're looking at an expression. This can happen with
+ something like:
+
+ template <int I>
+ void foo(S<I>, S<I + 2>);
+
+ If the call looked like:
+
+ foo(S<2>(), S<4>());
+
+ we would have already matched `I' with `2'. Now, we'd
+ like to know if `4' matches `I + 2'. So, we substitute
+ into that expression, and fold constants, in the hope of
+ figuring it out. */
+ tree t =
+ maybe_fold_nontype_arg (tsubst_expr (parm, targs, NULL_TREE));
+ tree a = maybe_fold_nontype_arg (arg);
+
+ if (!IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (t))))
+ /* Good, we mangaged to simplify the exression. */
+ return unify (tparms, targs, t, a, UNIFY_ALLOW_NONE,
+ explicit_mask);
+ else
+ /* Bad, we couldn't simplify this. Assume it doesn't
+ unify. */
+ return 1;
+ }
+ else
+ sorry ("use of `%s' in template type unification",
+ tree_code_name [(int) TREE_CODE (parm)]);
+
return 1;
}
}
-
-#undef DEBUG
+void
+mark_decl_instantiated (result, extern_p)
+ tree result;
+ int extern_p;
+{
+ if (DECL_TEMPLATE_INSTANTIATION (result))
+ SET_DECL_EXPLICIT_INSTANTIATION (result);
+
+ if (TREE_CODE (result) != FUNCTION_DECL)
+ /* The TREE_PUBLIC flag for function declarations will have been
+ set correctly by tsubst. */
+ TREE_PUBLIC (result) = 1;
+
+ if (! extern_p)
+ {
+ DECL_INTERFACE_KNOWN (result) = 1;
+ DECL_NOT_REALLY_EXTERN (result) = 1;
+ /* For WIN32 we also want to put explicit instantiations in
+ linkonce sections. */
+ if (TREE_PUBLIC (result))
+ maybe_make_one_only (result);
+ }
+ else if (TREE_CODE (result) == FUNCTION_DECL)
+ mark_inline_for_output (result);
+}
+
+/* Given two function templates PAT1 and PAT2, and explicit template
+ arguments EXPLICIT_ARGS return:
+
+ 1 if PAT1 is more specialized than PAT2 as described in [temp.func.order].
+ -1 if PAT2 is more specialized than PAT1.
+ 0 if neither is more specialized. */
+
int
-do_pending_expansions ()
+more_specialized (pat1, pat2, explicit_args)
+ tree pat1, pat2, explicit_args;
{
- struct pending_inline *i, *new_list = 0;
-
- {
- tree t;
- for (t = template_classes; t; t = TREE_CHAIN (t))
- instantiate_member_templates (TREE_PURPOSE (t));
- }
-
- if (!pending_template_expansions)
- return 0;
+ tree targs;
+ int winner = 0;
-#ifdef DEBUG
- fprintf (stderr, "\n\n\t\t IN DO_PENDING_EXPANSIONS\n\n");
-#endif
+ targs = get_bindings_overload (pat1, pat2, explicit_args);
+ if (targs)
+ {
+ --winner;
+ }
- i = pending_template_expansions;
- while (i)
+ targs = get_bindings_overload (pat2, pat1, explicit_args);
+ if (targs)
{
- tree context;
+ ++winner;
+ }
- struct pending_inline *next = i->next;
- tree t = i->fndecl;
+ return winner;
+}
- int decision = 0;
-#define DECIDE(N) do {decision=(N); goto decided;} while(0)
+/* Given two class template specialization list nodes PAT1 and PAT2, return:
- my_friendly_assert (TREE_CODE (t) == FUNCTION_DECL
- || TREE_CODE (t) == VAR_DECL, 294);
- if (TREE_ASM_WRITTEN (t))
- DECIDE (0);
+ 1 if PAT1 is more specialized than PAT2 as described in [temp.class.order].
+ -1 if PAT2 is more specialized than PAT1.
+ 0 if neither is more specialized. */
+
+int
+more_specialized_class (pat1, pat2)
+ tree pat1, pat2;
+{
+ tree targs;
+ int winner = 0;
+
+ targs = get_class_bindings
+ (TREE_VALUE (pat1), TREE_PURPOSE (pat1),
+ TREE_PURPOSE (pat2), NULL_TREE);
+ if (targs)
+ --winner;
+
+ targs = get_class_bindings
+ (TREE_VALUE (pat2), TREE_PURPOSE (pat2),
+ TREE_PURPOSE (pat1), NULL_TREE);
+ if (targs)
+ ++winner;
+
+ return winner;
+}
- if (DECL_EXPLICIT_INSTANTIATION (t))
- DECIDE (DECL_NOT_REALLY_EXTERN (t));
- else if (! flag_implicit_templates)
- DECIDE (0);
+/* Return the template arguments that will produce the function signature
+ DECL from the function template FN, with the explicit template
+ arguments EXPLICIT_ARGS. If CHECK_RETTYPE is 1, the return type must
+ also match. */
- if (i->interface == 1)
- /* OK, it was an implicit instantiation. */
- {
- if (SUPPORTS_WEAK)
- DECL_WEAK (t) = 1;
- else
- TREE_PUBLIC (t) = 0;
- }
-
- /* If it's a method, let the class type decide it.
- @@ What if the method template is in a separate file?
- Maybe both file contexts should be taken into account?
- Maybe only do this if i->interface == 1 (unknown)? */
- context = DECL_CONTEXT (t);
- if (context != NULL_TREE
- && TREE_CODE_CLASS (TREE_CODE (context)) == 't')
- {
- /* I'm interested in the context of this version of the function,
- not the original virtual declaration. */
- context = DECL_CLASS_CONTEXT (t);
-
- /* If `unknown', we might want a static copy.
- If `implementation', we want a global one.
- If `interface', ext ref. */
- if (CLASSTYPE_INTERFACE_KNOWN (context))
- DECIDE (!CLASSTYPE_INTERFACE_ONLY (context));
-#if 1 /* This doesn't get us stuff needed only by the file initializer. */
- DECIDE (TREE_USED (t));
-#else /* This compiles too much stuff, but that's probably better in
- most cases than never compiling the stuff we need. */
- DECIDE (1);
-#endif
- }
+static tree
+get_bindings_real (fn, decl, explicit_args, check_rettype)
+ tree fn, decl, explicit_args;
+ int check_rettype;
+{
+ int ntparms = DECL_NTPARMS (fn);
+ tree targs = make_scratch_vec (ntparms);
+ tree decl_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ tree extra_fn_arg = NULL_TREE;
+ int i;
- if (i->interface == 1)
- DECIDE (TREE_USED (t));
- else
- DECIDE (i->interface);
-
- decided:
-#ifdef DEBUG
- print_node_brief (stderr, decision ? "yes: " : "no: ", t, 0);
- fprintf (stderr, "\t%s\n",
- (DECL_ASSEMBLER_NAME (t)
- ? IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t))
- : ""));
-#endif
- if (decision)
- {
- i->next = pending_inlines;
- pending_inlines = i;
- }
+ if (DECL_STATIC_FUNCTION_P (fn)
+ && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl))
+ {
+ /* Sometimes we are trying to figure out what's being
+ specialized by a declaration that looks like a method, and it
+ turns out to be a static member function. */
+ if (CLASSTYPE_TEMPLATE_INFO (DECL_REAL_CONTEXT (fn))
+ && !is_member_template (fn))
+ /* The natural thing to do here seems to be to remove the
+ spurious `this' parameter from the DECL, but that prevents
+ unification from making use of the class type. So,
+ instead, we have fn_type_unification add to the parameters
+ for FN. */
+ extra_fn_arg = build_pointer_type (DECL_REAL_CONTEXT (fn));
else
- {
- i->next = new_list;
- new_list = i;
- }
- i = next;
+ /* In this case, though, adding the extra_fn_arg can confuse
+ things, so we remove from decl_arg_types instead. */
+ decl_arg_types = TREE_CHAIN (decl_arg_types);
}
- pending_template_expansions = new_list;
- if (!pending_inlines)
- return 0;
- do_pending_inlines ();
- return 1;
+
+ i = fn_type_unification (fn, explicit_args, targs,
+ decl_arg_types,
+ TREE_TYPE (TREE_TYPE (decl)),
+ DEDUCE_EXACT,
+ extra_fn_arg);
+
+ if (i != 0)
+ return NULL_TREE;
+
+ if (check_rettype)
+ {
+ /* Check to see that the resulting return type is also OK. */
+ tree t = tsubst (TREE_TYPE (TREE_TYPE (fn)),
+ complete_template_args (fn, targs, 1),
+ NULL_TREE);
+
+ if (!comptypes (t, TREE_TYPE (TREE_TYPE (decl)), 1))
+ return NULL_TREE;
+ }
+
+ return targs;
}
-
-struct pending_template {
- struct pending_template *next;
- tree id;
-};
+/* For most uses, we want to check the return type. */
-static struct pending_template* pending_templates;
+tree
+get_bindings (fn, decl, explicit_args)
+ tree fn, decl, explicit_args;
+{
+ return get_bindings_real (fn, decl, explicit_args, 1);
+}
-void
-do_pending_templates ()
+/* But for more_specialized, we only care about the parameter types. */
+
+static tree
+get_bindings_overload (fn, decl, explicit_args)
+ tree fn, decl, explicit_args;
{
- struct pending_template* t;
-
- for ( t = pending_templates; t; t = t->next)
+ return get_bindings_real (fn, decl, explicit_args, 0);
+}
+
+static tree
+get_class_bindings (tparms, parms, args, outer_args)
+ tree tparms, parms, args, outer_args;
+{
+ int i, ntparms = TREE_VEC_LENGTH (tparms);
+ tree vec = make_temp_vec (ntparms);
+
+ if (outer_args)
{
- instantiate_class_template (t->id, 1);
+ tparms = tsubst (tparms, outer_args, NULL_TREE);
+ parms = tsubst (parms, outer_args, NULL_TREE);
}
- for ( t = pending_templates; t; t = pending_templates)
+ for (i = 0; i < TREE_VEC_LENGTH (parms); ++i)
{
- pending_templates = t->next;
- free(t);
+ switch (unify (tparms, vec,
+ TREE_VEC_ELT (parms, i), TREE_VEC_ELT (args, i),
+ UNIFY_ALLOW_NONE, 0))
+ {
+ case 0:
+ break;
+ case 1:
+ return NULL_TREE;
+ }
}
+
+ for (i = 0; i < ntparms; ++i)
+ if (! TREE_VEC_ELT (vec, i))
+ return NULL_TREE;
+
+ return vec;
}
-static void
-add_pending_template (pt)
- tree pt;
+/* Return the most specialized of the list of templates in FNS that can
+ produce an instantiation matching DECL, given the explicit template
+ arguments EXPLICIT_ARGS. */
+
+tree
+most_specialized (fns, decl, explicit_args)
+ tree fns, decl, explicit_args;
{
- struct pending_template *p;
-
- p = (struct pending_template *) malloc (sizeof (struct pending_template));
- p->next = pending_templates;
- pending_templates = p;
- p->id = pt;
+ tree fn, champ, args, *p;
+ int fate;
+
+ for (p = &fns; *p; )
+ {
+ args = get_bindings (TREE_VALUE (*p), decl, explicit_args);
+ if (args)
+ {
+ p = &TREE_CHAIN (*p);
+ }
+ else
+ *p = TREE_CHAIN (*p);
+ }
+
+ if (! fns)
+ return NULL_TREE;
+
+ fn = fns;
+ champ = TREE_VALUE (fn);
+ fn = TREE_CHAIN (fn);
+ for (; fn; fn = TREE_CHAIN (fn))
+ {
+ fate = more_specialized (champ, TREE_VALUE (fn), explicit_args);
+ if (fate == 1)
+ ;
+ else
+ {
+ if (fate == 0)
+ {
+ fn = TREE_CHAIN (fn);
+ if (! fn)
+ return error_mark_node;
+ }
+ champ = TREE_VALUE (fn);
+ }
+ }
+
+ for (fn = fns; fn && TREE_VALUE (fn) != champ; fn = TREE_CHAIN (fn))
+ {
+ fate = more_specialized (champ, TREE_VALUE (fn), explicit_args);
+ if (fate != 1)
+ return error_mark_node;
+ }
+
+ return champ;
}
-void
-mark_function_instantiated (result, extern_p)
- tree result;
- int extern_p;
+/* Return the most specialized of the class template specializations in
+ SPECS that can produce an instantiation matching ARGS. */
+
+tree
+most_specialized_class (specs, mainargs, outer_args)
+ tree specs, mainargs, outer_args;
{
- if (DECL_TEMPLATE_INSTANTIATION (result))
- SET_DECL_EXPLICIT_INSTANTIATION (result);
- TREE_PUBLIC (result) = 1;
+ tree list = NULL_TREE, t, args, champ;
+ int fate;
- if (! extern_p)
+ for (t = specs; t; t = TREE_CHAIN (t))
{
- DECL_INTERFACE_KNOWN (result) = 1;
- DECL_NOT_REALLY_EXTERN (result) = 1;
+ args = get_class_bindings (TREE_VALUE (t), TREE_PURPOSE (t),
+ mainargs, outer_args);
+ if (args)
+ {
+ list = decl_tree_cons (TREE_PURPOSE (t), TREE_VALUE (t), list);
+ TREE_TYPE (list) = TREE_TYPE (t);
+ }
+ }
+
+ if (! list)
+ return NULL_TREE;
+
+ t = list;
+ champ = t;
+ t = TREE_CHAIN (t);
+ for (; t; t = TREE_CHAIN (t))
+ {
+ fate = more_specialized_class (champ, t);
+ if (fate == 1)
+ ;
+ else
+ {
+ if (fate == 0)
+ {
+ t = TREE_CHAIN (t);
+ if (! t)
+ return error_mark_node;
+ }
+ champ = t;
+ }
}
+
+ for (t = list; t && t != champ; t = TREE_CHAIN (t))
+ {
+ fate = more_specialized_class (champ, t);
+ if (fate != 1)
+ return error_mark_node;
+ }
+
+ return champ;
}
/* called from the parser. */
+
void
-do_function_instantiation (declspecs, declarator, storage)
+do_decl_instantiation (declspecs, declarator, storage)
tree declspecs, declarator, storage;
{
- tree decl = grokdeclarator (declarator, declspecs, NORMAL, 0,
- NULL_TREE, NULL_TREE);
- tree name;
- tree fn;
+ tree decl = grokdeclarator (declarator, declspecs, NORMAL, 0, NULL_TREE);
tree result = NULL_TREE;
int extern_p = 0;
+ if (! DECL_LANG_SPECIFIC (decl))
+ {
+ cp_error ("explicit instantiation of non-template `%#D'", decl);
+ return;
+ }
+
/* If we've already seen this template instance, use it. */
- if (name = DECL_ASSEMBLER_NAME (decl),
- fn = IDENTIFIER_GLOBAL_VALUE (name),
- fn && DECL_TEMPLATE_INSTANTIATION (fn))
- result = fn;
- else if (name = DECL_NAME (decl), fn = IDENTIFIER_GLOBAL_VALUE (name), fn)
- {
- for (fn = get_first_fn (fn); fn; fn = DECL_CHAIN (fn))
- if (decls_match (fn, decl)
- && DECL_DEFER_OUTPUT (fn))
- {
- result = fn;
- break;
- }
- else if (TREE_CODE (fn) == TEMPLATE_DECL)
- {
- int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (fn));
- tree *targs = (tree *) malloc (sizeof (tree) * ntparms);
- int i, dummy = 0;
- i = type_unification (DECL_TEMPLATE_PARMS (fn), targs,
- TYPE_ARG_TYPES (TREE_TYPE (fn)),
- TYPE_ARG_TYPES (TREE_TYPE (decl)),
- &dummy, 0);
- if (i == 0)
- {
- if (result)
- cp_error ("ambiguous template instantiation for `%D' requested", decl);
- else
- result = instantiate_template (fn, targs);
- }
- free (targs);
- }
+ if (TREE_CODE (decl) == VAR_DECL)
+ {
+ result = lookup_field (DECL_CONTEXT (decl), DECL_NAME (decl), 0, 0);
+ if (result && TREE_CODE (result) != VAR_DECL)
+ result = NULL_TREE;
+ }
+ else if (TREE_CODE (decl) != FUNCTION_DECL)
+ {
+ cp_error ("explicit instantiation of `%#D'", decl);
+ return;
}
+ else if (DECL_TEMPLATE_INSTANTIATION (decl))
+ result = decl;
+
if (! result)
{
cp_error ("no matching template for `%D' found", decl);
return;
}
+ if (! DECL_TEMPLATE_INFO (result))
+ {
+ cp_pedwarn ("explicit instantiation of non-template `%#D'", result);
+ return;
+ }
+
if (flag_external_templates)
return;
@@ -2577,8 +7007,11 @@ do_function_instantiation (declspecs, declarator, storage)
else
cp_error ("storage class `%D' applied to template instantiation",
storage);
- mark_function_instantiated (result, extern_p);
+
+ mark_decl_instantiated (result, extern_p);
repo_template_instantiated (result, extern_p);
+ if (! extern_p)
+ instantiate_decl (result);
}
void
@@ -2599,12 +7032,23 @@ mark_class_instantiated (t, extern_p)
}
void
-do_type_instantiation (name, storage)
- tree name, storage;
+do_type_instantiation (t, storage)
+ tree t, storage;
{
- tree t = TREE_TYPE (name);
int extern_p = 0;
int nomem_p = 0;
+ int static_p = 0;
+
+ if (TREE_CODE (t) == TYPE_DECL)
+ t = TREE_TYPE (t);
+
+ if (! IS_AGGR_TYPE (t) || ! CLASSTYPE_TEMPLATE_INFO (t))
+ {
+ cp_error ("explicit instantiation of non-template type `%T'", t);
+ return;
+ }
+
+ complete_type (t);
/* With -fexternal-templates, explicit instantiations are treated the same
as implicit ones. */
@@ -2624,6 +7068,8 @@ do_type_instantiation (name, storage)
nomem_p = 1;
else if (storage == ridpointers[(int) RID_EXTERN])
extern_p = 1;
+ else if (storage == ridpointers[(int) RID_STATIC])
+ static_p = 1;
else
{
cp_error ("storage class `%D' applied to template instantiation",
@@ -2647,30 +7093,26 @@ do_type_instantiation (name, storage)
{
tree tmp;
- /* Classes nested in template classes currently don't have an
- IDENTIFIER_TEMPLATE--their out-of-line members are handled
- by the enclosing template class. Note that there are name
- conflict bugs with this approach. */
- tmp = TYPE_IDENTIFIER (t);
- if (IDENTIFIER_TEMPLATE (tmp))
- instantiate_member_templates (tmp);
-
- /* this should really be done by instantiate_member_templates */
- tmp = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), 0);
- for (; tmp; tmp = TREE_CHAIN (tmp))
- if (DECL_TEMPLATE_INSTANTIATION (tmp))
- {
- mark_function_instantiated (tmp, extern_p);
- repo_template_instantiated (tmp, extern_p);
- }
-#if 0
+ if (! static_p)
+ for (tmp = TYPE_METHODS (t); tmp; tmp = TREE_CHAIN (tmp))
+ if (TREE_CODE (tmp) == FUNCTION_DECL
+ && DECL_TEMPLATE_INSTANTIATION (tmp))
+ {
+ mark_decl_instantiated (tmp, extern_p);
+ repo_template_instantiated (tmp, extern_p);
+ if (! extern_p)
+ instantiate_decl (tmp);
+ }
+
for (tmp = TYPE_FIELDS (t); tmp; tmp = TREE_CHAIN (tmp))
- {
- if (TREE_CODE (tmp) == VAR_DECL)
- /* eventually do something */;
- }
-#endif
+ if (TREE_CODE (tmp) == VAR_DECL && DECL_TEMPLATE_INSTANTIATION (tmp))
+ {
+ mark_decl_instantiated (tmp, extern_p);
+ repo_template_instantiated (tmp, extern_p);
+ if (! extern_p)
+ instantiate_decl (tmp);
+ }
for (tmp = CLASSTYPE_TAGS (t); tmp; tmp = TREE_CHAIN (tmp))
if (IS_AGGR_TYPE (TREE_VALUE (tmp)))
@@ -2678,17 +7120,376 @@ do_type_instantiation (name, storage)
}
}
+/* Given a function DECL, which is a specialization of TEMP, modify
+ DECL to be a re-instantiation of TEMPL with the same template
+ arguments.
+
+ One reason for doing this is a scenario like this:
+
+ template <class T>
+ void f(const T&, int i);
+
+ void g() { f(3, 7); }
+
+ template <class T>
+ void f(const T& t, const int i) { }
+
+ Note that when the template is first instantiated, with
+ instantiate_template, the resulting DECL will have no name for the
+ first parameter, and the wrong type for the second. So, when we go
+ to instantiate the DECL, we regenerate it. */
+
+void
+regenerate_decl_from_template (decl, tmpl)
+ tree decl;
+ tree tmpl;
+{
+ tree args;
+ tree save_ti;
+ tree code_pattern;
+ tree new_decl;
+
+ args = DECL_TI_ARGS (decl);
+ code_pattern = DECL_TEMPLATE_RESULT (tmpl);
+
+ /* Trick tsubst into giving us a new decl. CODE_PATTERN must be the
+ most distant ancestor of DECL, since that's the one that will
+ actually be altered by a redefinition. */
+ save_ti = DECL_TEMPLATE_INFO (code_pattern);
+ DECL_TEMPLATE_INFO (code_pattern) = NULL_TREE;
+ new_decl = tsubst (code_pattern, args, NULL_TREE);
+ SET_DECL_IMPLICIT_INSTANTIATION (new_decl);
+ DECL_TEMPLATE_INFO (code_pattern) = save_ti;
+
+ if (TREE_CODE (decl) == VAR_DECL)
+ {
+ /* Set up DECL_INITIAL, since tsubst doesn't. */
+ pushclass (DECL_CONTEXT (decl), 2);
+ DECL_INITIAL (new_decl) =
+ tsubst_expr (DECL_INITIAL (code_pattern), args,
+ DECL_TI_TEMPLATE (decl));
+ popclass (1);
+ }
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
+ new decl. */
+ DECL_INITIAL (new_decl) = error_mark_node;
+
+ if (DECL_TEMPLATE_SPECIALIZATION (new_decl)
+ && !DECL_TEMPLATE_INFO (new_decl))
+ /* Set up the information about what is being specialized. */
+ DECL_TEMPLATE_INFO (new_decl) = DECL_TEMPLATE_INFO (decl);
+ }
+
+ duplicate_decls (new_decl, decl);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ DECL_INITIAL (new_decl) = NULL_TREE;
+}
+
+/* Produce the definition of D, a _DECL generated from a template. */
+
tree
-create_nested_upt (scope, name)
- tree scope, name;
+instantiate_decl (d)
+ tree d;
{
- tree t = make_lang_type (UNINSTANTIATED_P_TYPE);
- tree d = build_decl (TYPE_DECL, name, t);
+ tree ti = DECL_TEMPLATE_INFO (d);
+ tree tmpl = TI_TEMPLATE (ti);
+ tree args = TI_ARGS (ti);
+ tree td;
+ tree decl_pattern, code_pattern;
+ int nested = in_function_p ();
+ int d_defined;
+ int pattern_defined;
+ int line = lineno;
+ char *file = input_filename;
+
+ for (td = tmpl;
+ DECL_TEMPLATE_INSTANTIATION (td)
+ /* This next clause handles friend templates defined inside
+ class templates. The friend templates are not really
+ instantiations from the point of view of the language, but
+ they are instantiations from the point of view of the
+ compiler. */
+ || (DECL_TEMPLATE_INFO (td) && !DECL_TEMPLATE_SPECIALIZATION (td));
+ )
+ td = DECL_TI_TEMPLATE (td);
+
+ /* In the case of a member template, decl_pattern is the partially
+ instantiated declaration (in the instantiated class), and code_pattern
+ is the original template definition. */
+ decl_pattern = DECL_TEMPLATE_RESULT (tmpl);
+ code_pattern = DECL_TEMPLATE_RESULT (td);
+
+ if (TREE_CODE (d) == FUNCTION_DECL)
+ {
+ d_defined = (DECL_INITIAL (d) != NULL_TREE);
+ pattern_defined = (DECL_INITIAL (code_pattern) != NULL_TREE);
+ }
+ else
+ {
+ d_defined = ! DECL_IN_AGGR_P (d);
+ pattern_defined = ! DECL_IN_AGGR_P (code_pattern);
+ }
+
+ if (d_defined)
+ return d;
+
+ if (TREE_CODE (d) == FUNCTION_DECL)
+ {
+ tree spec = retrieve_specialization (tmpl, args);
+
+ if (spec != NULL_TREE
+ && DECL_TEMPLATE_SPECIALIZATION (spec))
+ return spec;
+ }
+
+ /* This needs to happen before any tsubsting. */
+ if (! push_tinst_level (d))
+ return d;
+
+ push_to_top_level ();
+ lineno = DECL_SOURCE_LINE (d);
+ input_filename = DECL_SOURCE_FILE (d);
+
+ if (pattern_defined)
+ {
+ repo_template_used (d);
+
+ if (flag_external_templates && ! DECL_INTERFACE_KNOWN (d))
+ {
+ if (flag_alt_external_templates)
+ {
+ if (interface_unknown)
+ warn_if_unknown_interface (d);
+ }
+ else if (DECL_INTERFACE_KNOWN (code_pattern))
+ {
+ DECL_INTERFACE_KNOWN (d) = 1;
+ DECL_NOT_REALLY_EXTERN (d) = ! DECL_EXTERNAL (code_pattern);
+ }
+ else
+ warn_if_unknown_interface (code_pattern);
+ }
+
+ if (at_eof)
+ import_export_decl (d);
+ }
+
+ /* Reject all external templates except inline functions. */
+ if (DECL_INTERFACE_KNOWN (d)
+ && ! DECL_NOT_REALLY_EXTERN (d)
+ && ! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d)))
+ goto out;
+
+ if (TREE_CODE (d) == VAR_DECL
+ && TREE_READONLY (d)
+ && DECL_INITIAL (d) == NULL_TREE
+ && DECL_INITIAL (code_pattern) != NULL_TREE)
+ /* We need to set up DECL_INITIAL regardless of pattern_defined if
+ the variable is a static const initialized in the class body. */;
+ else if (! pattern_defined
+ || (! (TREE_CODE (d) == FUNCTION_DECL && DECL_INLINE (d) && nested)
+ && ! at_eof))
+ {
+ /* Defer all templates except inline functions used in another
+ function. */
+ lineno = line;
+ input_filename = file;
+
+ add_pending_template (d);
+ goto out;
+ }
+
+ regenerate_decl_from_template (d, td);
+
+ /* We already set the file and line above. Reset them now in case
+ they changed as a result of calling regenerate_decl_from_template. */
+ lineno = DECL_SOURCE_LINE (d);
+ input_filename = DECL_SOURCE_FILE (d);
+
+ if (TREE_CODE (d) == VAR_DECL)
+ {
+ DECL_IN_AGGR_P (d) = 0;
+ if (DECL_INTERFACE_KNOWN (d))
+ DECL_EXTERNAL (d) = ! DECL_NOT_REALLY_EXTERN (d);
+ else
+ {
+ DECL_EXTERNAL (d) = 1;
+ DECL_NOT_REALLY_EXTERN (d) = 1;
+ }
+ cp_finish_decl (d, DECL_INITIAL (d), NULL_TREE, 0, 0);
+ }
+ else if (TREE_CODE (d) == FUNCTION_DECL)
+ {
+ tree t = DECL_SAVED_TREE (code_pattern);
+
+ start_function (NULL_TREE, d, NULL_TREE, 1);
+ store_parm_decls ();
+
+ if (t && TREE_CODE (t) == RETURN_INIT)
+ {
+ store_return_init
+ (TREE_OPERAND (t, 0),
+ tsubst_expr (TREE_OPERAND (t, 1), args, tmpl));
+ t = TREE_CHAIN (t);
+ }
+
+ if (t && TREE_CODE (t) == CTOR_INITIALIZER)
+ {
+ current_member_init_list
+ = tsubst_expr_values (TREE_OPERAND (t, 0), args);
+ current_base_init_list
+ = tsubst_expr_values (TREE_OPERAND (t, 1), args);
+ t = TREE_CHAIN (t);
+ }
- TYPE_NAME (t) = d;
- TYPE_VALUES (t) = TYPE_VALUES (scope);
- TYPE_CONTEXT (t) = scope;
+ setup_vtbl_ptr ();
+ /* Always keep the BLOCK node associated with the outermost
+ pair of curly braces of a function. These are needed
+ for correct operation of dwarfout.c. */
+ keep_next_level ();
+
+ my_friendly_assert (TREE_CODE (t) == COMPOUND_STMT, 42);
+ tsubst_expr (t, args, tmpl);
+
+ finish_function (lineno, 0, nested);
+ }
+
+out:
+ lineno = line;
+ input_filename = file;
+
+ pop_from_top_level ();
+ pop_tinst_level ();
- pushdecl (d);
return d;
}
+
+tree
+tsubst_chain (t, argvec)
+ tree t, argvec;
+{
+ if (t)
+ {
+ tree first = tsubst (t, argvec, NULL_TREE);
+ tree last = first;
+
+ for (t = TREE_CHAIN (t); t; t = TREE_CHAIN (t))
+ {
+ tree x = tsubst (t, argvec, NULL_TREE);
+ TREE_CHAIN (last) = x;
+ last = x;
+ }
+
+ return first;
+ }
+ return NULL_TREE;
+}
+
+static tree
+tsubst_expr_values (t, argvec)
+ tree t, argvec;
+{
+ tree first = NULL_TREE;
+ tree *p = &first;
+
+ for (; t; t = TREE_CHAIN (t))
+ {
+ tree pur = tsubst_copy (TREE_PURPOSE (t), argvec, NULL_TREE);
+ tree val = tsubst_expr (TREE_VALUE (t), argvec, NULL_TREE);
+ *p = build_tree_list (pur, val);
+ p = &TREE_CHAIN (*p);
+ }
+ return first;
+}
+
+tree last_tree;
+
+void
+add_tree (t)
+ tree t;
+{
+ last_tree = TREE_CHAIN (last_tree) = t;
+}
+
+
+void
+begin_tree ()
+{
+ saved_trees = tree_cons (NULL_TREE, last_tree, saved_trees);
+ last_tree = NULL_TREE;
+}
+
+
+void
+end_tree ()
+{
+ my_friendly_assert (saved_trees != NULL_TREE, 0);
+
+ last_tree = TREE_VALUE (saved_trees);
+ saved_trees = TREE_CHAIN (saved_trees);
+}
+
+/* D is an undefined function declaration in the presence of templates with
+ the same name, listed in FNS. If one of them can produce D as an
+ instantiation, remember this so we can instantiate it at EOF if D has
+ not been defined by that time. */
+
+void
+add_maybe_template (d, fns)
+ tree d, fns;
+{
+ tree t;
+
+ if (DECL_MAYBE_TEMPLATE (d))
+ return;
+
+ t = most_specialized (fns, d, NULL_TREE);
+ if (! t)
+ return;
+ if (t == error_mark_node)
+ {
+ cp_error ("ambiguous template instantiation for `%D'", d);
+ return;
+ }
+
+ *maybe_template_tail = perm_tree_cons (t, d, NULL_TREE);
+ maybe_template_tail = &TREE_CHAIN (*maybe_template_tail);
+ DECL_MAYBE_TEMPLATE (d) = 1;
+}
+
+/* Instantiate an enumerated type. Used by instantiate_class_template and
+ tsubst_expr. */
+
+static tree
+tsubst_enum (tag, args, field_chain)
+ tree tag, args;
+ tree * field_chain;
+{
+ extern tree current_local_enum;
+ tree prev_local_enum = current_local_enum;
+
+ tree newtag = start_enum (TYPE_IDENTIFIER (tag));
+ tree e, values = NULL_TREE;
+
+ for (e = TYPE_VALUES (tag); e; e = TREE_CHAIN (e))
+ {
+ tree elt = build_enumerator (TREE_PURPOSE (e),
+ tsubst_expr (TREE_VALUE (e), args,
+ NULL_TREE));
+ TREE_CHAIN (elt) = values;
+ values = elt;
+ }
+
+ finish_enum (newtag, values);
+
+ if (NULL != field_chain)
+ *field_chain = grok_enum_decls (NULL_TREE);
+
+ current_local_enum = prev_local_enum;
+
+ return newtag;
+}
diff --git a/contrib/gcc/cp/ptree.c b/contrib/gcc/cp/ptree.c
index ad1480a..aa3066c 100644
--- a/contrib/gcc/cp/ptree.c
+++ b/contrib/gcc/cp/ptree.c
@@ -21,8 +21,8 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "tree.h"
-#include <stdio.h>
#include "cp-tree.h"
void
@@ -66,16 +66,16 @@ print_lang_type (file, node, indent)
register tree node;
int indent;
{
- if (TREE_CODE (node) == TEMPLATE_TYPE_PARM)
+ if (TREE_CODE (node) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (node) == TEMPLATE_TEMPLATE_PARM)
{
- print_node (file, "tinfo", TYPE_VALUES (node), indent + 4);
- return;
- }
-
- if (TREE_CODE (node) == UNINSTANTIATED_P_TYPE)
- {
- print_node (file, "template", UPT_TEMPLATE (node), indent + 4);
- print_node (file, "parameters", UPT_PARMS (node), indent + 4);
+ indent_to (file, indent + 3);
+ fputs ("index ", file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, TEMPLATE_TYPE_IDX (node));
+ fputs (" level ", file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, TEMPLATE_TYPE_LEVEL (node));
+ fputs (" orig_level ", file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, TEMPLATE_TYPE_ORIG_LEVEL (node));
return;
}
@@ -98,10 +98,6 @@ print_lang_type (file, node, indent)
fputs (" X()", file);
if (TYPE_HAS_CONVERSION (node))
fputs (" has-type-conversion", file);
- if (TYPE_HAS_INT_CONVERSION (node))
- fputs (" has-int-conversion", file);
- if (TYPE_HAS_REAL_CONVERSION (node))
- fputs (" has-float-conversion", file);
if (TYPE_HAS_INIT_REF (node))
{
if (TYPE_HAS_CONST_INIT_REF (node))
@@ -121,10 +117,6 @@ print_lang_type (file, node, indent)
fputs (" has=", file);
if (TYPE_HAS_ASSIGN_REF (node))
fputs (" this=(X&)", file);
- if (TYPE_OVERLOADS_METHOD_CALL_EXPR (node))
- fputs (" op->()", file);
- if (TYPE_GETS_INIT_AGGR (node))
- fputs (" gets X(X, ...)", file);
if (TYPE_OVERLOADS_CALL_EXPR (node))
fputs (" op()", file);
if (TYPE_OVERLOADS_ARRAY_REF (node))
@@ -158,7 +150,7 @@ print_lang_identifier (file, node, indent)
tree node;
int indent;
{
- print_node (file, "global", IDENTIFIER_GLOBAL_VALUE (node), indent + 4);
+ print_node (file, "bindings", IDENTIFIER_NAMESPACE_BINDINGS (node), indent + 4);
print_node (file, "class", IDENTIFIER_CLASS_VALUE (node), indent + 4);
print_node (file, "local", IDENTIFIER_LOCAL_VALUE (node), indent + 4);
print_node (file, "label", IDENTIFIER_LABEL_VALUE (node), indent + 4);
@@ -166,3 +158,34 @@ print_lang_identifier (file, node, indent)
print_node (file, "implicit", IDENTIFIER_IMPLICIT_DECL (node), indent + 4);
print_node (file, "error locus", IDENTIFIER_ERROR_LOCUS (node), indent + 4);
}
+
+void
+lang_print_xnode (file, node, indent)
+ FILE *file;
+ tree node;
+ int indent;
+{
+ switch (TREE_CODE (node))
+ {
+ case CPLUS_BINDING:
+ print_node (file, "scope", BINDING_SCOPE (node), indent+4);
+ print_node (file, "value", BINDING_VALUE (node), indent+4);
+ print_node (file, "chain", TREE_CHAIN (node), indent+4);
+ break;
+ case OVERLOAD:
+ print_node (file, "function", OVL_FUNCTION (node), indent+4);
+ print_node (file, "chain", TREE_CHAIN (node), indent+4);
+ break;
+ case TEMPLATE_PARM_INDEX:
+ indent_to (file, indent + 3);
+ fputs ("index ", file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, TEMPLATE_PARM_IDX (node));
+ fputs (" level ", file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, TEMPLATE_PARM_LEVEL (node));
+ fputs (" orig_level ", file);
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, TEMPLATE_PARM_ORIG_LEVEL (node));
+ break;
+ default:
+ break;
+ }
+}
diff --git a/contrib/gcc/cp/repo.c b/contrib/gcc/cp/repo.c
index 50fc9f8..742250d 100644
--- a/contrib/gcc/cp/repo.c
+++ b/contrib/gcc/cp/repo.c
@@ -1,5 +1,5 @@
/* Code to maintain a C++ template repository.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1997 Free Software Foundation, Inc.
Contributed by Jason Merrill (jason@cygnus.com)
This file is part of GNU CC.
@@ -25,22 +25,30 @@ Boston, MA 02111-1307, USA. */
The results of the automatic process should be easily reproducible with
explicit code. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "cp-tree.h"
#include "input.h"
#include "obstack.h"
+#include "toplev.h"
-extern char * rindex ();
-extern char * getenv ();
-extern char * getpwd ();
+extern char *getpwd PROTO((void));
+
+static tree repo_get_id PROTO((tree));
+static char *extract_string PROTO((char **));
+static char *get_base_filename PROTO((char *));
+static void open_repo_file PROTO((char *));
+static char *afgets PROTO((FILE *));
+static void reopen_repo_file_for_write PROTO((void));
static tree pending_repo;
static tree original_repo;
static char *repo_name;
static FILE *repo_file;
+static char *old_args, *old_dir, *old_main;
+
extern int flag_use_repository;
extern int errorcount, sorrycount;
extern struct obstack temporary_obstack;
@@ -49,6 +57,7 @@ extern struct obstack permanent_obstack;
#define IDENTIFIER_REPO_USED(NODE) (TREE_LANG_FLAG_3 (NODE))
#define IDENTIFIER_REPO_CHOSEN(NODE) (TREE_LANG_FLAG_4 (NODE))
+#if 0
/* Record the flags used to compile this translation unit. */
void
@@ -82,8 +91,9 @@ void
repo_class_defined (t)
tree t;
{}
+#endif
-tree
+static tree
repo_get_id (t)
tree t;
{
@@ -97,7 +107,7 @@ repo_get_id (t)
}
/* Note that a template has been used. If we can see the definition, offer
- to emit it. */
+ to emit it. */
void
repo_template_used (t)
@@ -120,7 +130,7 @@ repo_template_used (t)
else if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
{
if (IDENTIFIER_REPO_CHOSEN (id))
- mark_function_instantiated (t, 0);
+ mark_decl_instantiated (t, 0);
}
else
my_friendly_abort (1);
@@ -132,9 +142,10 @@ repo_template_used (t)
}
}
+#if 0
/* Note that the vtable for a class has been used, and offer to emit it. */
-void
+static void
repo_vtable_used (t)
tree t;
{
@@ -172,6 +183,7 @@ repo_tinfo_used (ti)
tree ti;
{
}
+#endif
void
repo_template_instantiated (t, extern_p)
@@ -186,12 +198,37 @@ repo_template_instantiated (t, extern_p)
}
}
+/* Parse a reasonable subset of shell quoting syntax. */
+
static char *
-save_string (s, len)
- char *s;
- int len;
+extract_string (pp)
+ char **pp;
{
- return obstack_copy0 (&temporary_obstack, s, len);
+ char *p = *pp;
+ int backquote = 0;
+ int inside = 0;
+
+ for (;;)
+ {
+ char c = *p;
+ if (c == '\0')
+ break;
+ ++p;
+ if (backquote)
+ obstack_1grow (&temporary_obstack, c);
+ else if (! inside && c == ' ')
+ break;
+ else if (! inside && c == '\\')
+ backquote = 1;
+ else if (c == '\'')
+ inside = !inside;
+ else
+ obstack_1grow (&temporary_obstack, c);
+ }
+
+ obstack_1grow (&temporary_obstack, '\0');
+ *pp = p;
+ return obstack_finish (&temporary_obstack);
}
static char *
@@ -199,30 +236,17 @@ get_base_filename (filename)
char *filename;
{
char *p = getenv ("COLLECT_GCC_OPTIONS");
- char *output = 0;
+ char *output = NULL;
int compiling = 0;
- if (p)
- while (*p)
- {
- char *q = p;
- while (*q && *q != ' ') q++;
- if (*p == '-' && p[1] == 'o')
- {
- p += 2;
- if (p == q)
- {
- p++; q++;
- if (*q)
- while (*q && *q != ' ') q++;
- }
+ while (p && *p)
+ {
+ char *q = extract_string (&p);
- output = save_string (p, q - p);
- }
- else if (*p == '-' && p[1] == 'c')
- compiling = 1;
- if (*q) q++;
- p = q;
+ if (strcmp (q, "-o") == 0)
+ output = extract_string (&p);
+ else if (strcmp (q, "-c") == 0)
+ compiling = 1;
}
if (compiling && output)
@@ -235,26 +259,20 @@ get_base_filename (filename)
return NULL;
}
- p = rindex (filename, '/');
- if (p)
- return p+1;
- else
- return filename;
+ return file_name_nondirectory (filename);
}
static void
open_repo_file (filename)
char *filename;
{
- register char *p, *q;
+ register char *p;
char *s = get_base_filename (filename);
if (s == NULL)
return;
- p = rindex (s, '/');
- if (! p)
- p = s;
+ p = file_name_nondirectory (s);
p = rindex (p, '.');
if (! p)
p = s + strlen (s);
@@ -292,13 +310,21 @@ init_repo (filename)
if (repo_file == 0)
return;
- while (buf = afgets (repo_file))
+ while ((buf = afgets (repo_file)))
{
switch (buf[0])
{
case 'A':
+ old_args = obstack_copy0 (&permanent_obstack, buf + 2,
+ strlen (buf + 2));
+ break;
case 'D':
+ old_dir = obstack_copy0 (&permanent_obstack, buf + 2,
+ strlen (buf + 2));
+ break;
case 'M':
+ old_main = obstack_copy0 (&permanent_obstack, buf + 2,
+ strlen (buf + 2));
break;
case 'C':
case 'O':
@@ -344,8 +370,8 @@ void
finish_repo ()
{
tree t;
- char *p;
int repo_changed = 0;
+ char *dir, *args;
if (! flag_use_repository)
return;
@@ -378,6 +404,16 @@ finish_repo ()
}
}
+ dir = getpwd ();
+ args = getenv ("COLLECT_GCC_OPTIONS");
+
+ if (! repo_changed && pending_repo)
+ if (strcmp (old_main, main_input_filename) != 0
+ || strcmp (old_dir, dir) != 0
+ || (args == NULL) != (old_args == NULL)
+ || (args && strcmp (old_args, args) != 0))
+ repo_changed = 1;
+
if (! repo_changed || errorcount || sorrycount)
goto out;
@@ -387,13 +423,9 @@ finish_repo ()
goto out;
fprintf (repo_file, "M %s\n", main_input_filename);
-
- p = getpwd ();
- fprintf (repo_file, "D %s\n", p);
-
- p = getenv ("COLLECT_GCC_OPTIONS");
- if (p != 0)
- fprintf (repo_file, "A %s\n", p);
+ fprintf (repo_file, "D %s\n", dir);
+ if (args)
+ fprintf (repo_file, "A %s\n", args);
for (t = pending_repo; t; t = TREE_CHAIN (t))
{
diff --git a/contrib/gcc/cp/rtti.c b/contrib/gcc/cp/rtti.c
new file mode 100644
index 0000000..b93c1cc
--- /dev/null
+++ b/contrib/gcc/cp/rtti.c
@@ -0,0 +1,1135 @@
+/* RunTime Type Identification
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Mostly written by Jason Merrill (jason@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "flags.h"
+#include "output.h"
+#include "assert.h"
+#include "toplev.h"
+
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+extern struct obstack permanent_obstack;
+
+static tree call_void_fn PROTO((char *));
+static tree build_headof_sub PROTO((tree));
+static tree build_headof PROTO((tree));
+static tree get_tinfo_var PROTO((tree));
+static tree get_typeid_1 PROTO((tree));
+static tree ifnonnull PROTO((tree, tree));
+static tree build_dynamic_cast_1 PROTO((tree, tree));
+static void expand_si_desc PROTO((tree, tree));
+static void expand_class_desc PROTO((tree, tree));
+static void expand_attr_desc PROTO((tree, tree));
+static void expand_ptr_desc PROTO((tree, tree));
+static void expand_generic_desc PROTO((tree, tree, char *));
+static tree throw_bad_cast PROTO((void));
+static tree throw_bad_typeid PROTO((void));
+
+tree type_info_type_node;
+tree tinfo_fn_id;
+tree tinfo_fn_type;
+
+void
+init_rtti_processing ()
+{
+ if (flag_honor_std)
+ push_namespace (get_identifier ("std"));
+ type_info_type_node = xref_tag
+ (class_type_node, get_identifier ("type_info"), NULL_TREE, 1);
+ if (flag_honor_std)
+ pop_namespace ();
+ tinfo_fn_id = get_identifier ("__tf");
+ tinfo_fn_type = build_function_type
+ (build_reference_type (build_type_variant (type_info_type_node, 1, 0)),
+ void_list_node);
+}
+
+/* Given a pointer to an object with at least one virtual table
+ pointer somewhere, return a pointer to a possible sub-object that
+ has a virtual table pointer in it that is the vtable parent for
+ that sub-object. */
+
+static tree
+build_headof_sub (exp)
+ tree exp;
+{
+ tree type = TREE_TYPE (TREE_TYPE (exp));
+ tree basetype = CLASSTYPE_RTTI (type);
+ tree binfo = get_binfo (basetype, type, 0);
+
+ exp = convert_pointer_to_real (binfo, exp);
+ return exp;
+}
+
+/* Given the expression EXP of type `class *', return the head of the
+ object pointed to by EXP with type cv void*, if the class has any
+ virtual functions (TYPE_VIRTUAL_P), else just return the
+ expression. */
+
+static tree
+build_headof (exp)
+ tree exp;
+{
+ tree type = TREE_TYPE (exp);
+ tree aref;
+ tree offset;
+
+ if (TREE_CODE (type) != POINTER_TYPE)
+ {
+ error ("`headof' applied to non-pointer type");
+ return error_mark_node;
+ }
+ type = TREE_TYPE (type);
+
+ if (!TYPE_VIRTUAL_P (type))
+ return exp;
+
+ /* If we don't have rtti stuff, get to a sub-object that does. */
+ if (!CLASSTYPE_VFIELDS (TREE_TYPE (TREE_TYPE (exp))))
+ exp = build_headof_sub (exp);
+
+ /* We use this a couple of times below, protect it. */
+ exp = save_expr (exp);
+
+ aref = build_vtbl_ref (build_indirect_ref (exp, NULL_PTR), integer_zero_node);
+
+ if (flag_vtable_thunks)
+ offset = aref;
+ else
+ offset = build_component_ref (aref, delta_identifier, NULL_TREE, 0);
+
+ type = build_type_variant (ptr_type_node, TREE_READONLY (exp),
+ TREE_THIS_VOLATILE (exp));
+ return build (PLUS_EXPR, type, exp,
+ cp_convert (ptrdiff_type_node, offset));
+}
+
+/* Build a call to a generic entry point taking and returning void. */
+
+static tree
+call_void_fn (name)
+ char *name;
+{
+ tree d = get_identifier (name);
+ tree type;
+
+ if (IDENTIFIER_GLOBAL_VALUE (d))
+ d = IDENTIFIER_GLOBAL_VALUE (d);
+ else
+ {
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ type = build_function_type (void_type_node, void_list_node);
+ d = build_lang_decl (FUNCTION_DECL, d, type);
+ DECL_EXTERNAL (d) = 1;
+ TREE_PUBLIC (d) = 1;
+ DECL_ARTIFICIAL (d) = 1;
+ pushdecl_top_level (d);
+ make_function_rtl (d);
+ assemble_external (d);
+
+ pop_obstacks ();
+ }
+
+ return build_call (d, void_type_node, NULL_TREE);
+}
+
+/* Get a bad_cast node for the program to throw...
+
+ See libstdc++/exception.cc for __throw_bad_cast */
+
+static tree
+throw_bad_cast ()
+{
+ return call_void_fn ("__throw_bad_cast");
+}
+
+static tree
+throw_bad_typeid ()
+{
+ return call_void_fn ("__throw_bad_typeid");
+}
+
+/* Return the type_info function associated with the expression EXP. If
+ EXP is a reference to a polymorphic class, return the dynamic type;
+ otherwise return the static type of the expression. */
+
+tree
+get_tinfo_fn_dynamic (exp)
+ tree exp;
+{
+ tree type;
+
+ if (exp == error_mark_node)
+ return error_mark_node;
+
+ if (type_unknown_p (exp))
+ {
+ error ("typeid of overloaded function");
+ return error_mark_node;
+ }
+
+ type = TREE_TYPE (exp);
+
+ /* peel back references, so they match. */
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+
+ /* Peel off cv qualifiers. */
+ type = TYPE_MAIN_VARIANT (type);
+
+ /* If exp is a reference to polymorphic type, get the real type_info. */
+ if (TYPE_VIRTUAL_P (type) && ! resolves_to_fixed_type_p (exp, 0))
+ {
+ /* build reference to type_info from vtable. */
+ tree t;
+
+ if (! flag_rtti)
+ {
+ warning ("taking dynamic typeid of object without -frtti");
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ init_rtti_processing ();
+ pop_obstacks ();
+ flag_rtti = 1;
+ }
+
+ /* If we don't have rtti stuff, get to a sub-object that does. */
+ if (! CLASSTYPE_VFIELDS (type))
+ {
+ exp = build_unary_op (ADDR_EXPR, exp, 0);
+ exp = build_headof_sub (exp);
+ exp = build_indirect_ref (exp, NULL_PTR);
+ }
+
+ if (flag_vtable_thunks)
+ t = build_vfn_ref ((tree *) 0, exp, integer_one_node);
+ else
+ t = build_vfn_ref ((tree *) 0, exp, integer_zero_node);
+ TREE_TYPE (t) = build_pointer_type (tinfo_fn_type);
+ return t;
+ }
+
+ /* otherwise return the type_info for the static type of the expr. */
+ return get_tinfo_fn (TYPE_MAIN_VARIANT (type));
+}
+
+tree
+build_typeid (exp)
+ tree exp;
+{
+ exp = get_tinfo_fn_dynamic (exp);
+ exp = build_call (exp, TREE_TYPE (tinfo_fn_type), NULL_TREE);
+ return convert_from_reference (exp);
+}
+
+tree
+build_x_typeid (exp)
+ tree exp;
+{
+ tree cond = NULL_TREE;
+ tree type = TREE_TYPE (tinfo_fn_type);
+ int nonnull;
+
+ if (processing_template_decl)
+ return build_min_nt (TYPEID_EXPR, exp);
+
+ if (TREE_CODE (exp) == INDIRECT_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
+ && TYPE_VIRTUAL_P (TREE_TYPE (exp))
+ && ! resolves_to_fixed_type_p (exp, &nonnull)
+ && ! nonnull)
+ {
+ exp = stabilize_reference (exp);
+ cond = cp_convert (boolean_type_node, TREE_OPERAND (exp, 0));
+ }
+
+ exp = get_tinfo_fn_dynamic (exp);
+
+ if (exp == error_mark_node)
+ return error_mark_node;
+
+ exp = build_call (exp, type, NULL_TREE);
+
+ if (cond)
+ {
+ tree bad = throw_bad_typeid ();
+
+ bad = build_compound_expr
+ (expr_tree_cons (NULL_TREE, bad, build_expr_list
+ (NULL_TREE, cp_convert (type, integer_zero_node))));
+ exp = build (COND_EXPR, type, cond, exp, bad);
+ }
+
+ return convert_from_reference (exp);
+}
+
+static tree
+get_tinfo_var (type)
+ tree type;
+{
+ tree tname = build_overload_with_type (get_identifier ("__ti"), type);
+ tree tdecl, arrtype;
+ int size;
+
+ if (IDENTIFIER_GLOBAL_VALUE (tname))
+ return IDENTIFIER_GLOBAL_VALUE (tname);
+
+ /* Figure out how much space we need to allocate for the type_info object.
+ If our struct layout or the type_info classes are changed, this will
+ need to be modified. */
+ if (TYPE_VOLATILE (type) || TYPE_READONLY (type))
+ size = 3 * POINTER_SIZE + INT_TYPE_SIZE;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && ! (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE
+ || TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE))
+ size = 3 * POINTER_SIZE;
+ else if (IS_AGGR_TYPE (type))
+ {
+ if (CLASSTYPE_N_BASECLASSES (type) == 0)
+ size = 2 * POINTER_SIZE;
+ else if (! TYPE_USES_COMPLEX_INHERITANCE (type)
+ && (TREE_VIA_PUBLIC
+ (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0))))
+ size = 3 * POINTER_SIZE;
+ else
+ size = 3 * POINTER_SIZE + TYPE_PRECISION (sizetype);
+ }
+ else
+ size = 2 * POINTER_SIZE;
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ /* The type for a character array of the appropriate size. */
+ arrtype = build_cplus_array_type
+ (unsigned_char_type_node,
+ build_index_type (size_int (size / BITS_PER_UNIT - 1)));
+
+ tdecl = build_decl (VAR_DECL, tname, arrtype);
+ TREE_PUBLIC (tdecl) = 1;
+ DECL_EXTERNAL (tdecl) = 1;
+ DECL_ARTIFICIAL (tdecl) = 1;
+ pushdecl_top_level (tdecl);
+ cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0);
+
+ pop_obstacks ();
+
+ return tdecl;
+}
+
+tree
+get_tinfo_fn (type)
+ tree type;
+{
+ tree name;
+ tree d;
+
+ if (TREE_CODE (type) == OFFSET_TYPE)
+ type = TREE_TYPE (type);
+ if (TREE_CODE (type) == METHOD_TYPE)
+ type = build_function_type (TREE_TYPE (type),
+ TREE_CHAIN (TYPE_ARG_TYPES (type)));
+
+ name = build_overload_with_type (tinfo_fn_id, type);
+
+ if (IDENTIFIER_GLOBAL_VALUE (name))
+ return IDENTIFIER_GLOBAL_VALUE (name);
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ d = build_lang_decl (FUNCTION_DECL, name, tinfo_fn_type);
+ DECL_EXTERNAL (d) = 1;
+ TREE_PUBLIC (d) = 1;
+ DECL_ARTIFICIAL (d) = 1;
+ DECL_NOT_REALLY_EXTERN (d) = 1;
+ DECL_MUTABLE_P (d) = 1;
+ TREE_TYPE (name) = copy_to_permanent (type);
+
+ pushdecl_top_level (d);
+ make_function_rtl (d);
+ assemble_external (d);
+ mark_inline_for_output (d);
+ pop_obstacks ();
+
+ return d;
+}
+
+static tree
+get_typeid_1 (type)
+ tree type;
+{
+ tree t = build_call
+ (get_tinfo_fn (type), TREE_TYPE (tinfo_fn_type), NULL_TREE);
+ return convert_from_reference (t);
+}
+
+/* Return the type_info object for TYPE, creating it if necessary. */
+
+tree
+get_typeid (type)
+ tree type;
+{
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ if (! flag_rtti)
+ {
+ warning ("requesting typeid of object without -frtti");
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ init_rtti_processing ();
+ pop_obstacks ();
+ flag_rtti = 1;
+ }
+
+ if (processing_template_decl)
+ return build_min_nt (TYPEID_EXPR, type);
+
+ /* If the type of the type-id is a reference type, the result of the
+ typeid expression refers to a type_info object representing the
+ referenced type. */
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+
+ /* The top-level cv-qualifiers of the lvalue expression or the type-id
+ that is the operand of typeid are always ignored. */
+ type = TYPE_MAIN_VARIANT (type);
+
+ return get_typeid_1 (type);
+}
+
+/* Check whether TEST is null before returning RESULT. If TEST is used in
+ RESULT, it must have previously had a save_expr applied to it. */
+
+static tree
+ifnonnull (test, result)
+ tree test, result;
+{
+ return build (COND_EXPR, TREE_TYPE (result),
+ build (EQ_EXPR, boolean_type_node, test, integer_zero_node),
+ cp_convert (TREE_TYPE (result), integer_zero_node),
+ result);
+}
+
+/* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working
+ paper. */
+
+static tree
+build_dynamic_cast_1 (type, expr)
+ tree type, expr;
+{
+ enum tree_code tc = TREE_CODE (type);
+ tree exprtype = TREE_TYPE (expr);
+ enum tree_code ec;
+ tree dcast_fn;
+
+ assert (exprtype != NULL_TREE);
+ ec = TREE_CODE (exprtype);
+
+ switch (tc)
+ {
+ case POINTER_TYPE:
+ if (ec == REFERENCE_TYPE)
+ {
+ expr = convert_from_reference (expr);
+ exprtype = TREE_TYPE (expr);
+ ec = TREE_CODE (exprtype);
+ }
+ if (ec != POINTER_TYPE)
+ goto fail;
+ if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE)
+ goto fail;
+ if (TYPE_SIZE (complete_type (TREE_TYPE (exprtype))) == NULL_TREE)
+ goto fail;
+ if (TREE_READONLY (TREE_TYPE (exprtype))
+ && ! TYPE_READONLY (TREE_TYPE (type)))
+ goto fail;
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
+ break;
+ /* else fall through */
+ case REFERENCE_TYPE:
+ if (TREE_CODE (TREE_TYPE (type)) != RECORD_TYPE)
+ goto fail;
+ if (TYPE_SIZE (complete_type (TREE_TYPE (type))) == NULL_TREE)
+ goto fail;
+ break;
+ /* else fall through */
+ default:
+ goto fail;
+ }
+
+ /* Apply trivial conversion T -> T& for dereferenced ptrs. */
+ if (ec == RECORD_TYPE)
+ {
+ exprtype = build_type_variant (exprtype, TREE_READONLY (expr),
+ TREE_THIS_VOLATILE (expr));
+ exprtype = build_reference_type (exprtype);
+ expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT,
+ LOOKUP_NORMAL, NULL_TREE);
+ ec = REFERENCE_TYPE;
+ }
+
+ if (tc == REFERENCE_TYPE)
+ {
+ if (ec != REFERENCE_TYPE)
+ goto fail;
+ if (TREE_CODE (TREE_TYPE (exprtype)) != RECORD_TYPE)
+ goto fail;
+ if (TYPE_SIZE (complete_type (TREE_TYPE (exprtype))) == NULL_TREE)
+ goto fail;
+ if (TREE_READONLY (TREE_TYPE (exprtype))
+ && ! TYPE_READONLY (TREE_TYPE (type)))
+ goto fail;
+ }
+
+ /* If *type is an unambiguous accessible base class of *exprtype,
+ convert statically. */
+ {
+ int distance;
+ tree path;
+
+ distance = get_base_distance (TREE_TYPE (type), TREE_TYPE (exprtype), 1,
+ &path);
+ if (distance >= 0)
+ return build_vbase_path (PLUS_EXPR, type, expr, path, 0);
+ }
+
+ /* Otherwise *exprtype must be a polymorphic class (have a vtbl). */
+ if (TYPE_VIRTUAL_P (TREE_TYPE (exprtype)))
+ {
+ tree expr1;
+ /* if TYPE is `void *', return pointer to complete object. */
+ if (tc == POINTER_TYPE
+ && TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
+ {
+ /* if b is an object, dynamic_cast<void *>(&b) == (void *)&b. */
+ if (TREE_CODE (expr) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE)
+ return build1 (NOP_EXPR, type, expr);
+
+ /* Since expr is used twice below, save it. */
+ expr = save_expr (expr);
+
+ expr1 = build_headof (expr);
+ if (TREE_TYPE (expr1) != type)
+ expr1 = build1 (NOP_EXPR, type, expr1);
+ return ifnonnull (expr, expr1);
+ }
+ else
+ {
+ tree retval;
+ tree result, td1, td2, td3, elems, expr2;
+
+ /* If we got here, we can't convert statically. Therefore,
+ dynamic_cast<D&>(b) (b an object) cannot succeed. */
+ if (ec == REFERENCE_TYPE)
+ {
+ if (TREE_CODE (expr) == VAR_DECL
+ && TREE_CODE (TREE_TYPE (expr)) == RECORD_TYPE)
+ {
+ cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed",
+ expr, type);
+ return throw_bad_cast ();
+ }
+ }
+ /* Ditto for dynamic_cast<D*>(&b). */
+ else if (TREE_CODE (expr) == ADDR_EXPR)
+ {
+ tree op = TREE_OPERAND (expr, 0);
+ if (TREE_CODE (op) == VAR_DECL
+ && TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE)
+ {
+ cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed",
+ expr, type);
+ retval = build_int_2 (0, 0);
+ TREE_TYPE (retval) = type;
+ return retval;
+ }
+ }
+
+ /* Since expr is used twice below, save it. */
+ expr = save_expr (expr);
+
+ expr1 = expr;
+ if (tc == REFERENCE_TYPE)
+ expr1 = build_unary_op (ADDR_EXPR, expr1, 0);
+
+ /* Build run-time conversion. */
+ expr2 = build_headof (expr1);
+
+ if (ec == POINTER_TYPE)
+ td1 = get_tinfo_fn_dynamic (build_indirect_ref (expr, NULL_PTR));
+ else
+ td1 = get_tinfo_fn_dynamic (expr);
+ td1 = decay_conversion (td1);
+
+ td2 = decay_conversion
+ (get_tinfo_fn (TYPE_MAIN_VARIANT (TREE_TYPE (type))));
+ td3 = decay_conversion
+ (get_tinfo_fn (TYPE_MAIN_VARIANT (TREE_TYPE (exprtype))));
+
+ elems = tree_cons
+ (NULL_TREE, td1, tree_cons
+ (NULL_TREE, td2, tree_cons
+ (NULL_TREE, build_int_2 (1, 0), tree_cons
+ (NULL_TREE, expr2, tree_cons
+ (NULL_TREE, td3, tree_cons
+ (NULL_TREE, expr1, NULL_TREE))))));
+
+ dcast_fn = get_identifier ("__dynamic_cast");
+ if (IDENTIFIER_GLOBAL_VALUE (dcast_fn))
+ dcast_fn = IDENTIFIER_GLOBAL_VALUE (dcast_fn);
+ else
+ {
+ tree tmp;
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, TREE_TYPE (td1), tree_cons
+ (NULL_TREE, TREE_TYPE (td1), tree_cons
+ (NULL_TREE, integer_type_node, tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, TREE_TYPE (td1), tree_cons
+ (NULL_TREE, ptr_type_node, void_list_node))))));
+ tmp = build_function_type (ptr_type_node, tmp);
+ dcast_fn = build_lang_decl (FUNCTION_DECL, dcast_fn, tmp);
+ DECL_EXTERNAL (dcast_fn) = 1;
+ TREE_PUBLIC (dcast_fn) = 1;
+ DECL_ARTIFICIAL (dcast_fn) = 1;
+ pushdecl_top_level (dcast_fn);
+ make_function_rtl (dcast_fn);
+ assemble_external (dcast_fn);
+ pop_obstacks ();
+ }
+
+ result = build_call
+ (dcast_fn, TREE_TYPE (TREE_TYPE (dcast_fn)), elems);
+
+ if (tc == REFERENCE_TYPE)
+ {
+ expr1 = throw_bad_cast ();
+ expr1 = build_compound_expr
+ (expr_tree_cons (NULL_TREE, expr1,
+ build_expr_list (NULL_TREE, cp_convert (type, integer_zero_node))));
+ TREE_TYPE (expr1) = type;
+ result = save_expr (result);
+ return build (COND_EXPR, type, result, result, expr1);
+ }
+
+ /* Now back to the type we want from a void*. */
+ result = cp_convert (type, result);
+ return ifnonnull (expr, result);
+ }
+ }
+
+ fail:
+ cp_error ("cannot dynamic_cast `%E' (of type `%#T') to type `%#T'",
+ expr, exprtype, type);
+ return error_mark_node;
+}
+
+tree
+build_dynamic_cast (type, expr)
+ tree type, expr;
+{
+ if (type == error_mark_node || expr == error_mark_node)
+ return error_mark_node;
+
+ if (processing_template_decl)
+ return build_min (DYNAMIC_CAST_EXPR, copy_to_permanent (type), expr);
+
+ return convert_from_reference (build_dynamic_cast_1 (type, expr));
+}
+
+/* Build and initialize various sorts of descriptors. Every descriptor
+ node has a name associated with it (the name created by mangling).
+ For this reason, we use the identifier as our access to the __*_desc
+ nodes, instead of sticking them directly in the types. Otherwise we
+ would burden all built-in types (and pointer types) with slots that
+ we don't necessarily want to use.
+
+ For each descriptor we build, we build a variable that contains
+ the descriptor's information. When we need this info at runtime,
+ all we need is access to these variables.
+
+ Note: these constructors always return the address of the descriptor
+ info, since that is simplest for their mutual interaction. */
+
+extern tree const_string_type_node;
+
+/* Build an initializer for a __si_type_info node. */
+
+static void
+expand_si_desc (tdecl, type)
+ tree tdecl;
+ tree type;
+{
+ tree t, elems, fn;
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name)+1, name));
+
+ type = BINFO_TYPE (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0));
+ expand_expr_stmt (get_typeid_1 (type));
+ t = decay_conversion (get_tinfo_var (type));
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, t, NULL_TREE)));
+
+ fn = get_identifier ("__rtti_si");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (type_info_type_node),
+ void_list_node)));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);
+ expand_expr_stmt (fn);
+}
+
+/* Build an initializer for a __class_type_info node. */
+
+static void
+expand_class_desc (tdecl, type)
+ tree tdecl;
+ tree type;
+{
+ tree name_string;
+ tree fn, tmp;
+ char *name;
+
+ int i = CLASSTYPE_N_BASECLASSES (type);
+ int base_cnt = 0;
+ tree binfos = TYPE_BINFO_BASETYPES (type);
+#if 0
+ /* See code below that used these. */
+ tree vb = CLASSTYPE_VBASECLASSES (type);
+ int n_base = i;
+#endif
+ tree base, elems, access, offset, isvir;
+ tree elt, elts = NULL_TREE;
+ static tree base_info_type_node;
+
+ if (base_info_type_node == NULL_TREE)
+ {
+ tree fields [4];
+
+ /* A reasonably close approximation of __class_type_info::base_info */
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ base_info_type_node = make_lang_type (RECORD_TYPE);
+
+ /* Actually const __user_type_info * */
+ fields [0] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE,
+ build_pointer_type (build_type_variant (type_info_type_node, 1, 0)));
+ fields [1] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE, unsigned_intSI_type_node);
+ DECL_BIT_FIELD (fields[1]) = 1;
+ DECL_FIELD_SIZE (fields[1]) = 29;
+
+ fields [2] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE, boolean_type_node);
+ DECL_BIT_FIELD (fields[2]) = 1;
+ DECL_FIELD_SIZE (fields[2]) = 1;
+
+ /* Actually enum access */
+ fields [3] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE, integer_type_node);
+ DECL_BIT_FIELD (fields[3]) = 1;
+ DECL_FIELD_SIZE (fields[3]) = 2;
+
+ finish_builtin_type (base_info_type_node, "__base_info", fields,
+ 3, ptr_type_node);
+ pop_obstacks ();
+ }
+
+ while (--i >= 0)
+ {
+ tree binfo = TREE_VEC_ELT (binfos, i);
+
+ expand_expr_stmt (get_typeid_1 (BINFO_TYPE (binfo)));
+ base = decay_conversion (get_tinfo_var (BINFO_TYPE (binfo)));
+
+ if (TREE_VIA_VIRTUAL (binfo))
+ {
+ tree t = BINFO_TYPE (binfo);
+ char *name;
+ tree field;
+
+ name = (char *) alloca (TYPE_NAME_LENGTH (t)+sizeof (VBASE_NAME)+1);
+ sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (t));
+ field = lookup_field (type, get_identifier (name), 0, 0);
+ offset = size_binop (FLOOR_DIV_EXPR,
+ DECL_FIELD_BITPOS (field), size_int (BITS_PER_UNIT));
+ offset = convert (sizetype, offset);
+ }
+ else
+ offset = BINFO_OFFSET (binfo);
+
+ if (TREE_VIA_PUBLIC (binfo))
+ access = access_public_node;
+ else if (TREE_VIA_PROTECTED (binfo))
+ access = access_protected_node;
+ else
+ access = access_private_node;
+ if (TREE_VIA_VIRTUAL (binfo))
+ isvir = boolean_true_node;
+ else
+ isvir = boolean_false_node;
+
+ elt = build
+ (CONSTRUCTOR, base_info_type_node, NULL_TREE, tree_cons
+ (NULL_TREE, base, tree_cons
+ (NULL_TREE, offset, tree_cons
+ (NULL_TREE, isvir, tree_cons
+ (NULL_TREE, access, NULL_TREE)))));
+ TREE_HAS_CONSTRUCTOR (elt) = TREE_CONSTANT (elt) = TREE_STATIC (elt) = 1;
+ elts = expr_tree_cons (NULL_TREE, elt, elts);
+ base_cnt++;
+ }
+#if 0
+ i = n_base;
+ while (vb)
+ {
+ tree b;
+ access = access_public_node;
+ while (--i >= 0)
+ {
+ b = TREE_VEC_ELT (binfos, i);
+ if (BINFO_TYPE (vb) == BINFO_TYPE (b) && TREE_VIA_VIRTUAL (b))
+ {
+ if (TREE_VIA_PUBLIC (b))
+ access = access_public_node;
+ else if (TREE_VIA_PROTECTED (b))
+ access = access_protected_node;
+ else
+ access = access_private_node;
+ break;
+ }
+ }
+ base = build_t_desc (BINFO_TYPE (vb), 1);
+ offset = BINFO_OFFSET (vb);
+ isvir = build_int_2 (1, 0);
+
+ base_list = expr_tree_cons (NULL_TREE, base, base_list);
+ isvir_list = expr_tree_cons (NULL_TREE, isvir, isvir_list);
+ acc_list = expr_tree_cons (NULL_TREE, access, acc_list);
+ off_list = expr_tree_cons (NULL_TREE, offset, off_list);
+
+ base_cnt++;
+ vb = TREE_CHAIN (vb);
+ }
+#endif
+
+ name = build_overload_name (type, 1, 1);
+ name_string = combine_strings (build_string (strlen (name)+1, name));
+
+ {
+ tree arrtype = build_array_type (base_info_type_node, NULL_TREE);
+ elts = build (CONSTRUCTOR, arrtype, NULL_TREE, elts);
+ TREE_HAS_CONSTRUCTOR (elts) = TREE_CONSTANT (elts)
+ = TREE_STATIC (elts) = 1;
+ complete_array_type (arrtype, elts, 1);
+ }
+
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, decay_conversion (elts), tree_cons
+ (NULL_TREE, cp_convert (sizetype, build_int_2 (base_cnt, 0)),
+ NULL_TREE))));
+
+ fn = get_identifier ("__rtti_class");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (base_info_type_node), tree_cons
+ (NULL_TREE, sizetype, void_list_node))));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);
+ expand_expr_stmt (fn);
+}
+
+/* Build an initializer for a __pointer_type_info node. */
+
+static void
+expand_ptr_desc (tdecl, type)
+ tree tdecl;
+ tree type;
+{
+ tree t, elems, fn;
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name)+1, name));
+
+ type = TREE_TYPE (type);
+ expand_expr_stmt (get_typeid_1 (type));
+ t = decay_conversion (get_tinfo_var (type));
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, t, NULL_TREE)));
+
+ fn = get_identifier ("__rtti_ptr");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (type_info_type_node),
+ void_list_node)));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);
+ expand_expr_stmt (fn);
+}
+
+/* Build an initializer for a __attr_type_info node. */
+
+static void
+expand_attr_desc (tdecl, type)
+ tree tdecl;
+ tree type;
+{
+ tree elems, t, fn;
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name)+1, name));
+ tree attrval = build_int_2
+ (TYPE_READONLY (type) | TYPE_VOLATILE (type) * 2, 0);
+
+ expand_expr_stmt (get_typeid_1 (TYPE_MAIN_VARIANT (type)));
+ t = decay_conversion (get_tinfo_var (TYPE_MAIN_VARIANT (type)));
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, attrval, expr_tree_cons (NULL_TREE, t, NULL_TREE))));
+
+ fn = get_identifier ("__rtti_attr");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, integer_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (type_info_type_node),
+ void_list_node))));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);
+ expand_expr_stmt (fn);
+}
+
+/* Build an initializer for a type_info node that just has a name. */
+
+static void
+expand_generic_desc (tdecl, type, fnname)
+ tree tdecl;
+ tree type;
+ char *fnname;
+{
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name)+1, name));
+ tree elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), NULL_TREE));
+
+ tree fn = get_identifier (fnname);
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, void_list_node));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ fn = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), elems);
+ expand_expr_stmt (fn);
+}
+
+/* Generate the code for a type_info initialization function.
+ Note that we take advantage of the passage
+
+ 5.2.7 Type identification [expr.typeid]
+
+ Whether or not the destructor is called for the type_info object at the
+ end of the program is unspecified.
+
+ and don't bother to arrange for these objects to be destroyed. It
+ doesn't matter, anyway, since the destructors don't do anything.
+
+ This must only be called from toplevel (i.e. from finish_file)! */
+
+void
+synthesize_tinfo_fn (fndecl)
+ tree fndecl;
+{
+ tree type = TREE_TYPE (DECL_NAME (fndecl));
+ tree tmp, addr, tdecl;
+
+ if (at_eof)
+ {
+ import_export_decl (fndecl);
+ if (DECL_REALLY_EXTERN (fndecl))
+ return;
+ }
+
+ tdecl = get_tinfo_var (type);
+ DECL_EXTERNAL (tdecl) = 0;
+ TREE_STATIC (tdecl) = 1;
+ DECL_COMMON (tdecl) = 1;
+ TREE_USED (tdecl) = 1;
+ DECL_ALIGN (tdecl) = TYPE_ALIGN (ptr_type_node);
+ cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0);
+
+ start_function (NULL_TREE, fndecl, NULL_TREE, 1);
+ store_parm_decls ();
+ clear_last_expr ();
+ push_momentary ();
+
+ /* If the first word of the array (the vtable) is non-zero, we've already
+ initialized the object, so don't do it again. */
+ addr = decay_conversion (tdecl);
+ tmp = cp_convert (build_pointer_type (ptr_type_node), addr);
+ tmp = build_indirect_ref (tmp, 0);
+ tmp = build_binary_op (EQ_EXPR, tmp, integer_zero_node, 1);
+ expand_start_cond (tmp, 0);
+
+ if (TREE_CODE (type) == FUNCTION_TYPE)
+ expand_generic_desc (tdecl, type, "__rtti_func");
+ else if (TREE_CODE (type) == ARRAY_TYPE)
+ expand_generic_desc (tdecl, type, "__rtti_array");
+ else if (TYPE_VOLATILE (type) || TYPE_READONLY (type))
+ expand_attr_desc (tdecl, type);
+ else if (TREE_CODE (type) == POINTER_TYPE)
+ {
+ if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE)
+ expand_generic_desc (tdecl, type, "__rtti_ptmd");
+ else if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+ expand_generic_desc (tdecl, type, "__rtti_ptmf");
+ else
+ expand_ptr_desc (tdecl, type);
+ }
+ else if (TYPE_PTRMEMFUNC_P (type))
+ expand_generic_desc (tdecl, type, "__rtti_ptmf");
+ else if (IS_AGGR_TYPE (type))
+ {
+ if (CLASSTYPE_N_BASECLASSES (type) == 0)
+ expand_generic_desc (tdecl, type, "__rtti_user");
+ else if (! TYPE_USES_COMPLEX_INHERITANCE (type)
+ && (TREE_VIA_PUBLIC
+ (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0))))
+ expand_si_desc (tdecl, type);
+ else
+ expand_class_desc (tdecl, type);
+ }
+ else if (TREE_CODE (type) == ENUMERAL_TYPE)
+ expand_generic_desc (tdecl, type, "__rtti_user");
+ else
+ my_friendly_abort (252);
+
+ expand_end_cond ();
+
+ /* OK, now return the type_info object. */
+ tmp = cp_convert (build_pointer_type (type_info_type_node), addr);
+ tmp = build_indirect_ref (tmp, 0);
+ c_expand_return (tmp);
+ finish_function (lineno, 0, 0);
+}
diff --git a/contrib/gcc/cp/search.c b/contrib/gcc/cp/search.c
index 0ac50a1..d5971e0 100644
--- a/contrib/gcc/cp/search.c
+++ b/contrib/gcc/cp/search.c
@@ -1,6 +1,6 @@
/* Breadth-first and depth-first routines for
searching multiple-inheritance lattice for GNU C++.
- Copyright (C) 1987, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -20,30 +20,32 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* High-level class interface. */
+/* High-level class interface. */
#include "config.h"
+#include "system.h"
#include "tree.h"
-#include <stdio.h>
#include "cp-tree.h"
#include "obstack.h"
#include "flags.h"
#include "rtl.h"
#include "output.h"
+#include "toplev.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-void init_search ();
extern struct obstack *current_obstack;
extern tree abort_fndecl;
#include "stack.h"
/* Obstack used for remembering decision points of breadth-first. */
+
static struct obstack search_obstack;
/* Methods for pushing and popping objects to and from obstacks. */
+
struct stack_level *
push_stack_level (obstack, tp, size)
struct obstack *obstack;
@@ -74,19 +76,83 @@ pop_stack_level (stack)
#define search_level stack_level
static struct search_level *search_stack;
-static tree lookup_field_1 ();
-static int lookup_fnfields_1 ();
-static void dfs_walk ();
-static int markedp ();
-static void dfs_unmark ();
-static void dfs_init_vbase_pointers ();
+static void clear_memoized_cache PROTO((void));
+static tree make_memoized_table_entry PROTO((tree, tree, int));
+static tree get_abstract_virtuals_1 PROTO((tree, int, tree));
+static tree get_vbase_1 PROTO((tree, tree, unsigned int *));
+static tree convert_pointer_to_vbase PROTO((tree, tree));
+static tree lookup_field_1 PROTO((tree, tree));
+static tree convert_pointer_to_single_level PROTO((tree, tree));
+static int lookup_fnfields_1 PROTO((tree, tree));
+static int lookup_fnfields_here PROTO((tree, tree));
+static int is_subobject_of_p PROTO((tree, tree));
+static int hides PROTO((tree, tree));
+static tree virtual_context PROTO((tree, tree, tree));
+static tree get_template_base_recursive
+ PROTO((tree, tree, tree, int));
+static void dfs_walk PROTO((tree, void (*) (tree), int (*) (tree)));
+static void dfs_check_overlap PROTO((tree));
+static int dfs_no_overlap_yet PROTO((tree));
+static void envelope_add_decl PROTO((tree, tree, tree *));
+static int get_base_distance_recursive
+ PROTO((tree, int, int, int, int *, tree *, tree, tree *,
+ int, int *, int, int));
+static void expand_upcast_fixups
+ PROTO((tree, tree, tree, tree, tree, tree, tree *));
+static void fixup_virtual_upcast_offsets
+ PROTO((tree, tree, int, int, tree, tree, tree, tree,
+ tree *));
+static int markedp PROTO((tree));
+static int unmarkedp PROTO((tree));
+#ifdef MI_MATRIX
+static int numberedp PROTO((tree));
+static int unnumberedp PROTO((tree));
+#endif
+static int marked_vtable_pathp PROTO((tree));
+static int unmarked_vtable_pathp PROTO((tree));
+static int marked_new_vtablep PROTO((tree));
+static int unmarked_new_vtablep PROTO((tree));
+static int dfs_debug_unmarkedp PROTO((tree));
+#ifdef MI_MATRIX
+static void dfs_number PROTO((tree));
+static void dfs_unnumber PROTO((tree));
+static void dfs_record_inheritance PROTO((tree));
+#endif
+static void dfs_debug_mark PROTO((tree));
+static void dfs_find_vbases PROTO((tree));
+static void dfs_clear_vbase_slots PROTO((tree));
+static void dfs_unmark PROTO((tree));
+static void dfs_init_vbase_pointers PROTO((tree));
+static void dfs_get_vbase_types PROTO((tree));
+static void dfs_pushdecls PROTO((tree));
+static void dfs_compress_decls PROTO((tree));
+static void dfs_unuse_fields PROTO((tree));
+static void add_conversions PROTO((tree));
+static tree get_virtuals_named_this PROTO((tree));
+static tree get_virtual_destructor PROTO((tree, int));
+static int tree_has_any_destructor_p PROTO((tree, int));
+static int covariant_return_p PROTO((tree, tree));
+static struct search_level *push_search_level
+ PROTO((struct stack_level *, struct obstack *));
+static struct search_level *pop_search_level
+ PROTO((struct stack_level *));
+static struct type_level *push_type_level
+ PROTO((struct stack_level *, struct obstack *));
+static struct type_level *pop_type_level
+ PROTO((struct type_level *));
+static tree my_tree_cons PROTO((tree, tree, tree));
+static tree my_build_string PROTO((char *));
+static struct memoized_entry * my_new_memoized_entry
+ PROTO((struct memoized_entry *));
+static HOST_WIDE_INT breadth_first_search
+ PROTO((tree, int (*) (tree, int), int (*) (tree, int)));
static tree vbase_types;
-static tree vbase_decl, vbase_decl_ptr;
-static tree vbase_decl_ptr_intermediate;
+static tree vbase_decl_ptr_intermediate, vbase_decl_ptr;
static tree vbase_init_result;
/* Allocate a level of searching. */
+
static struct search_level *
push_search_level (stack, obstack)
struct stack_level *stack;
@@ -99,6 +165,7 @@ push_search_level (stack, obstack)
}
/* Discard a level of search allocation. */
+
static struct search_level *
pop_search_level (obstack)
struct stack_level *obstack;
@@ -109,6 +176,7 @@ pop_search_level (obstack)
}
/* Search memoization. */
+
struct type_level
{
struct stack_level base;
@@ -133,7 +201,6 @@ static tree _vptr_name;
/* Make things that look like tree nodes, but allocate them
on type_obstack_entries. */
static int my_tree_node_counter;
-static tree my_tree_cons (), my_build_string ();
extern int flag_memoize_lookups, flag_save_memoized_contexts;
@@ -141,12 +208,14 @@ extern int flag_memoize_lookups, flag_save_memoized_contexts;
static int my_memoized_entry_counter;
static int memoized_fast_finds[2], memoized_adds[2], memoized_fast_rejects[2];
static int memoized_fields_searched[2];
+#ifdef GATHER_STATISTICS
static int n_fields_searched;
static int n_calls_lookup_field, n_calls_lookup_field_1;
static int n_calls_lookup_fnfields, n_calls_lookup_fnfields_1;
static int n_calls_get_base_type;
static int n_outer_fields_searched;
static int n_contexts_saved;
+#endif /* GATHER_STATISTICS */
/* Local variables to help save memoization contexts. */
static tree prev_type_memoized;
@@ -157,6 +226,7 @@ static struct type_level *prev_type_stack;
static tree closed_envelopes = NULL_TREE;
/* Allocate a level of type memoization context. */
+
static struct type_level *
push_type_level (stack, obstack)
struct stack_level *stack;
@@ -186,18 +256,17 @@ pop_type_level (stack)
/* Make something that looks like a TREE_LIST, but
do it on the type_obstack_entries obstack. */
+
static tree
my_tree_cons (purpose, value, chain)
tree purpose, value, chain;
{
- tree p = (tree)obstack_alloc (&type_obstack_entries, sizeof (struct tree_list));
+ tree p;
+ struct obstack *ambient_obstack = current_obstack;
+ current_obstack = &type_obstack_entries;
+ p = tree_cons (purpose, value, chain);
+ current_obstack = ambient_obstack;
++my_tree_node_counter;
- TREE_TYPE (p) = NULL_TREE;
- ((HOST_WIDE_INT *)p)[3] = 0;
- TREE_SET_CODE (p, TREE_LIST);
- TREE_PURPOSE (p) = purpose;
- TREE_VALUE (p) = value;
- TREE_CHAIN (p) = chain;
return p;
}
@@ -217,6 +286,7 @@ my_build_string (str)
/* Memoizing machinery to make searches for multiple inheritance
reasonably efficient. */
+
#define MEMOIZE_HASHSIZE 8
typedef struct memoized_entry
{
@@ -237,26 +307,43 @@ static struct memoized_entry *
my_new_memoized_entry (chain)
struct memoized_entry *chain;
{
- struct memoized_entry *p =
- (struct memoized_entry *)obstack_alloc (&type_obstack_entries,
- sizeof (struct memoized_entry));
+ struct memoized_entry *p
+ = (struct memoized_entry *)obstack_alloc (&type_obstack_entries,
+ sizeof (struct memoized_entry));
bzero ((char *) p, sizeof (struct memoized_entry));
MEMOIZED_CHAIN (p) = chain;
MEMOIZED_UID (p) = ++my_memoized_entry_counter;
return p;
}
+/* Clears the deferred pop from pop_memoized_context, if any. */
+
+static void
+clear_memoized_cache ()
+{
+ if (prev_type_stack)
+ {
+ type_stack = pop_type_level (prev_type_stack);
+ prev_type_memoized = 0;
+ prev_type_stack = 0;
+ }
+}
+
/* Make an entry in the memoized table for type TYPE
that the entry for NAME is FIELD. */
-tree
+static tree
make_memoized_table_entry (type, name, function_p)
tree type, name;
int function_p;
{
- int index = MEMOIZED_HASH_FN (name);
+ int idx = MEMOIZED_HASH_FN (name);
tree entry, *prev_entry;
+ /* Since we allocate from the type_obstack, we must pop any deferred
+ levels. */
+ clear_memoized_cache ();
+
memoized_adds[function_p] += 1;
if (CLASSTYPE_MTABLE_ENTRY (type) == 0)
{
@@ -268,9 +355,9 @@ make_memoized_table_entry (type, name, function_p)
my_friendly_abort (88);
}
if (function_p)
- prev_entry = &MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
+ prev_entry = &MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type), idx);
else
- prev_entry = &MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
+ prev_entry = &MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), idx);
entry = my_tree_cons (name, NULL_TREE, *prev_entry);
*prev_entry = entry;
@@ -309,6 +396,7 @@ make_memoized_table_entry (type, name, function_p)
be NULL_TREE if we are not in a class's scope.
USE_OLD, if nonzero tries to use previous context. */
+
void
push_memoized_context (type, use_old)
tree type;
@@ -323,7 +411,7 @@ push_memoized_context (type, use_old)
{
#ifdef GATHER_STATISTICS
n_contexts_saved++;
-#endif
+#endif /* GATHER_STATISTICS */
type_stack = prev_type_stack;
prev_type_stack = 0;
@@ -334,9 +422,7 @@ push_memoized_context (type, use_old)
return;
}
/* Otherwise, need to pop old stack here. */
- type_stack = pop_type_level (prev_type_stack);
- prev_type_memoized = 0;
- prev_type_stack = 0;
+ clear_memoized_cache ();
}
type_stack = push_type_level ((struct stack_level *)type_stack,
@@ -349,6 +435,7 @@ push_memoized_context (type, use_old)
If we wanted to, we could not use pop_search_level, since
poping that level allows the data we have collected to
be clobbered; a stack of obstacks would be needed. */
+
void
pop_memoized_context (use_old)
int use_old;
@@ -364,6 +451,9 @@ pop_memoized_context (use_old)
while (len--)
tem[len*2+1] = (tree)CLASSTYPE_MTABLE_ENTRY (tem[len*2]);
+ /* If there was a deferred pop, we need to pop it now. */
+ clear_memoized_cache ();
+
prev_type_stack = type_stack;
prev_type_memoized = type_stack->type;
}
@@ -384,9 +474,10 @@ pop_memoized_context (use_old)
/* Get a virtual binfo that is found inside BINFO's hierarchy that is
the same type as the type given in PARENT. To be optimal, we want
the first one that is found by going through the least number of
- virtual bases. DEPTH should be NULL_PTR. */
+ virtual bases. */
+
static tree
-get_vbase (parent, binfo, depth)
+get_vbase_1 (parent, binfo, depth)
tree parent, binfo;
unsigned int *depth;
{
@@ -394,12 +485,6 @@ get_vbase (parent, binfo, depth)
int i, n_baselinks;
tree rval = NULL_TREE;
- if (depth == 0)
- {
- unsigned int d = (unsigned int)-1;
- return get_vbase (parent, binfo, &d);
- }
-
if (BINFO_TYPE (binfo) == parent && TREE_VIA_VIRTUAL (binfo))
{
*depth = 0;
@@ -420,7 +505,7 @@ get_vbase (parent, binfo, depth)
if (*depth == 0)
break;
- nrval = get_vbase (parent, base_binfo, depth);
+ nrval = get_vbase_1 (parent, base_binfo, depth);
if (nrval)
rval = nrval;
}
@@ -428,46 +513,28 @@ get_vbase (parent, binfo, depth)
return rval;
}
+tree
+get_vbase (parent, binfo)
+ tree parent;
+ tree binfo;
+{
+ unsigned int d = (unsigned int)-1;
+ return get_vbase_1 (parent, binfo, &d);
+}
+
/* Convert EXPR to a virtual base class of type TYPE. We know that
EXPR is a non-null POINTER_TYPE to RECORD_TYPE. We also know that
the type of what expr points to has a virtual base of type TYPE. */
-tree
+
+static tree
convert_pointer_to_vbase (type, expr)
tree type;
tree expr;
{
- tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr))), NULL_PTR);
+ tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr))));
return convert_pointer_to_real (vb, expr);
}
-/* This is the newer recursive depth first search routine. */
-#if 0 /* unused */
-/* Return non-zero if PARENT is directly derived from TYPE. By directly
- we mean it's only one step up the inheritance lattice. We check this
- by walking horizontally across the types that TYPE directly inherits
- from, to see if PARENT is among them. This is used by get_binfo and
- by compute_access. */
-static int
-immediately_derived (parent, type)
- tree parent, type;
-{
- if (TYPE_BINFO (type))
- {
- tree binfos = BINFO_BASETYPES (TYPE_BINFO (type));
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
- for (i = 0; i < n_baselinks; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
-
- if (parent == BINFO_TYPE (base_binfo))
- return 1;
- }
- }
- return 0;
-}
-#endif
-
/* Check whether the type given in BINFO is derived from PARENT. If
it isn't, return 0. If it is, but the derivation is MI-ambiguous
AND protect != 0, emit an error message and return error_mark_node.
@@ -484,7 +551,7 @@ get_binfo (parent, binfo, protect)
register tree parent, binfo;
int protect;
{
- tree type;
+ tree type = NULL_TREE;
int dist;
tree rval = NULL_TREE;
@@ -519,17 +586,27 @@ get_binfo (parent, binfo, protect)
}
/* This is the newer depth first get_base_distance routine. */
+
static int
-get_base_distance_recursive (binfo, depth, is_private, basetype_path, rval,
+get_base_distance_recursive (binfo, depth, is_private, rval,
rval_private_ptr, new_binfo_ptr, parent, path_ptr,
- protect, via_virtual_ptr, via_virtual)
- tree binfo, basetype_path, *new_binfo_ptr, parent, *path_ptr;
- int *rval_private_ptr, depth, is_private, rval, protect, *via_virtual_ptr,
- via_virtual;
+ protect, via_virtual_ptr, via_virtual,
+ current_scope_in_chain)
+ tree binfo;
+ int depth, is_private, rval;
+ int *rval_private_ptr;
+ tree *new_binfo_ptr, parent, *path_ptr;
+ int protect, *via_virtual_ptr, via_virtual;
+ int current_scope_in_chain;
{
tree binfos;
int i, n_baselinks;
+ if (protect
+ && !current_scope_in_chain
+ && is_friend (BINFO_TYPE (binfo), current_scope ()))
+ current_scope_in_chain = 1;
+
if (BINFO_TYPE (binfo) == parent || binfo == parent)
{
if (rval == -1)
@@ -577,19 +654,21 @@ get_base_distance_recursive (binfo, depth, is_private, basetype_path, rval,
tree base_binfo = TREE_VEC_ELT (binfos, i);
/* Find any specific instance of a virtual base, when searching with
- a binfo... */
+ a binfo... */
if (BINFO_MARKED (base_binfo) == 0 || TREE_CODE (parent) == TREE_VEC)
{
int via_private
= (protect
&& (is_private
|| (!TREE_VIA_PUBLIC (base_binfo)
+ && !(TREE_VIA_PROTECTED (base_binfo)
+ && current_scope_in_chain)
&& !is_friend (BINFO_TYPE (binfo), current_scope ()))));
int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
int was;
/* When searching for a non-virtual, we cannot mark
- virtually found binfos. */
+ virtually found binfos. */
if (! this_virtual)
SET_BINFO_MARKED (base_binfo);
@@ -597,11 +676,12 @@ get_base_distance_recursive (binfo, depth, is_private, basetype_path, rval,
was = WATCH_VALUES (rval, *via_virtual_ptr);
rval = get_base_distance_recursive (base_binfo, depth, via_private,
- binfo, rval, rval_private_ptr,
+ rval, rval_private_ptr,
new_binfo_ptr, parent, path_ptr,
protect, via_virtual_ptr,
- this_virtual);
- /* watch for updates; only update if path is good. */
+ this_virtual,
+ current_scope_in_chain);
+ /* watch for updates; only update if path is good. */
if (path_ptr && WATCH_VALUES (rval, *via_virtual_ptr) != was)
BINFO_INHERITANCE_CHAIN (base_binfo) = binfo;
if (rval == -2 && *via_virtual_ptr == 0)
@@ -642,19 +722,22 @@ get_base_distance (parent, binfo, protect, path_ptr)
{
int rval;
int rval_private = 0;
- tree type;
+ tree type = NULL_TREE;
tree new_binfo = NULL_TREE;
int via_virtual;
int watch_access = protect;
+ /* Should we be completing types here? */
if (TREE_CODE (parent) != TREE_VEC)
- parent = TYPE_MAIN_VARIANT (parent);
+ parent = complete_type (TYPE_MAIN_VARIANT (parent));
+ else
+ complete_type (TREE_TYPE (parent));
if (TREE_CODE (binfo) == TREE_VEC)
type = BINFO_TYPE (binfo);
else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
{
- type = binfo;
+ type = complete_type (binfo);
binfo = TYPE_BINFO (type);
if (path_ptr)
@@ -675,9 +758,10 @@ get_base_distance (parent, binfo, protect, path_ptr)
if (path_ptr)
watch_access = 1;
- rval = get_base_distance_recursive (binfo, 0, 0, NULL_TREE, -1,
+ rval = get_base_distance_recursive (binfo, 0, 0, -1,
&rval_private, &new_binfo, parent,
- path_ptr, watch_access, &via_virtual, 0);
+ path_ptr, watch_access, &via_virtual, 0,
+ 0);
dfs_walk (binfo, dfs_unmark, markedp);
@@ -688,7 +772,7 @@ get_base_distance (parent, binfo, protect, path_ptr)
if (rval && protect && rval_private)
return -3;
- /* find real virtual base classes. */
+ /* find real virtual base classes. */
if (rval == -1 && TREE_CODE (parent) == TREE_VEC
&& parent == binfo_member (BINFO_TYPE (parent),
CLASSTYPE_VBASECLASSES (type)))
@@ -711,20 +795,32 @@ get_base_distance (parent, binfo, protect, path_ptr)
/* Do a 1-level search for NAME as a member of TYPE. The caller must
figure out whether it can access this field. (Since it is only one
level, this is reasonable.) */
+
static tree
lookup_field_1 (type, name)
tree type, name;
{
- register tree field = TYPE_FIELDS (type);
+ register tree field;
+
+ if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
+ /* The TYPE_FIELDS of a TEMPLATE_TYPE_PARM are not fields at all;
+ instead TYPE_FIELDS is the TEMPLATE_PARM_INDEX. (Miraculously,
+ the code often worked even when we treated the index as a list
+ of fields!) */
+ return NULL_TREE;
+
+ field = TYPE_FIELDS (type);
#ifdef GATHER_STATISTICS
n_calls_lookup_field_1++;
-#endif
+#endif /* GATHER_STATISTICS */
while (field)
{
#ifdef GATHER_STATISTICS
n_fields_searched++;
-#endif
+#endif /* GATHER_STATISTICS */
+ my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (field)) == 'd', 0);
if (DECL_NAME (field) == NULL_TREE
&& TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
{
@@ -754,17 +850,17 @@ lookup_field_1 (type, name)
/* There are a number of cases we need to be aware of here:
current_class_type current_function_decl
- * global NULL NULL
- * fn-local NULL SET
- * class-local SET NULL
- * class->fn SET SET
- * fn->class SET SET
+ global NULL NULL
+ fn-local NULL SET
+ class-local SET NULL
+ class->fn SET SET
+ fn->class SET SET
Those last two make life interesting. If we're in a function which is
itself inside a class, we need decls to go into the fn's decls (our
second case below). But if we're in a class and the class itself is
inside a function, we need decls to go into the decls for the class. To
- achieve this last goal, we must see if, when both current_class_decl and
+ achieve this last goal, we must see if, when both current_class_ptr and
current_function_decl are set, the class was declared inside that
function. If so, we know to put the decls into the class's scope. */
@@ -794,23 +890,23 @@ current_scope ()
This will be static when lookup_fnfield comes into this file.
- access_public means that the field can be accessed by the current lexical
+ access_public_node means that the field can be accessed by the current lexical
scope.
- access_protected means that the field cannot be accessed by the current
+ access_protected_node means that the field cannot be accessed by the current
lexical scope because it is protected.
- access_private means that the field cannot be accessed by the current
- lexical scope because it is private. */
+ access_private_node means that the field cannot be accessed by the current
+ lexical scope because it is private. */
#if 0
-#define PUBLIC_RETURN return (DECL_PUBLIC (field) = 1), access_public
-#define PROTECTED_RETURN return (DECL_PROTECTED (field) = 1), access_protected
-#define PRIVATE_RETURN return (DECL_PRIVATE (field) = 1), access_private
+#define PUBLIC_RETURN return (DECL_PUBLIC (field) = 1), access_public_node
+#define PROTECTED_RETURN return (DECL_PROTECTED (field) = 1), access_protected_node
+#define PRIVATE_RETURN return (DECL_PRIVATE (field) = 1), access_private_node
#else
-#define PUBLIC_RETURN return access_public
-#define PROTECTED_RETURN return access_protected
-#define PRIVATE_RETURN return access_private
+#define PUBLIC_RETURN return access_public_node
+#define PROTECTED_RETURN return access_protected_node
+#define PRIVATE_RETURN return access_private_node
#endif
#if 0
@@ -818,11 +914,11 @@ current_scope ()
static tree previous_scope = NULL_TREE;
#endif
-enum access_type
+tree
compute_access (basetype_path, field)
tree basetype_path, field;
{
- enum access_type access;
+ tree access;
tree types;
tree context;
int protected_ok, via_protected;
@@ -831,16 +927,16 @@ compute_access (basetype_path, field)
/* Replaces static decl above. */
tree previous_scope;
#endif
- int static_mem =
- ((TREE_CODE (field) == FUNCTION_DECL && DECL_STATIC_FUNCTION_P (field))
- || (TREE_CODE (field) != FUNCTION_DECL && TREE_STATIC (field)));
+ int static_mem
+ = ((TREE_CODE (field) == FUNCTION_DECL && DECL_STATIC_FUNCTION_P (field))
+ || (TREE_CODE (field) != FUNCTION_DECL && TREE_STATIC (field)));
if (! flag_access_control)
- return access_public;
+ return access_public_node;
/* The field lives in the current class. */
if (BINFO_TYPE (basetype_path) == current_class_type)
- return access_public;
+ return access_public_node;
#if 0
/* Disabled until pushing function scope clears these out. If ever. */
@@ -848,30 +944,28 @@ compute_access (basetype_path, field)
if (current_scope () == previous_scope)
{
if (DECL_PUBLIC (field))
- return access_public;
+ return access_public_node;
if (DECL_PROTECTED (field))
- return access_protected;
+ return access_protected_node;
if (DECL_PRIVATE (field))
- return access_private;
+ return access_private_node;
}
#endif
/* We don't currently support access control on nested types. */
if (TREE_CODE (field) == TYPE_DECL)
- return access_public;
+ return access_public_node;
previous_scope = current_scope ();
-
- context = DECL_CLASS_CONTEXT (field);
- if (context == NULL_TREE)
- context = DECL_CONTEXT (field);
+
+ context = DECL_REAL_CONTEXT (field);
/* Fields coming from nested anonymous unions have their DECL_CLASS_CONTEXT
slot set to the union type rather than the record type containing
- the anonymous union. In this case, DECL_FIELD_CONTEXT is correct. */
- if (context && TREE_CODE (context) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
- context = DECL_FIELD_CONTEXT (field);
+ the anonymous union. */
+ if (context && ANON_UNION_TYPE_P (context)
+ && TREE_CODE (field) == FIELD_DECL)
+ context = TYPE_CONTEXT (context);
/* Virtual function tables are never private. But we should know that
we are looking for this, and not even try to hide it. */
@@ -898,8 +992,8 @@ compute_access (basetype_path, field)
else if (TREE_PROTECTED (field))
{
if (current_class_type
- && static_mem
- && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
+ && (static_mem || DECL_CONSTRUCTOR_P (field))
+ && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
PUBLIC_RETURN;
else
PROTECTED_RETURN;
@@ -912,7 +1006,7 @@ compute_access (basetype_path, field)
basetype_path = reverse_path (basetype_path);
types = basetype_path;
via_protected = 0;
- access = access_default;
+ access = access_default_node;
protected_ok = static_mem && current_class_type
&& ACCESSIBLY_DERIVED_FROM_P (BINFO_TYPE (types), current_class_type);
@@ -934,7 +1028,7 @@ compute_access (basetype_path, field)
member = purpose_member (type, DECL_ACCESS (field));
if (member)
{
- access = (enum access_type) TREE_VALUE (member);
+ access = TREE_VALUE (member);
break;
}
@@ -948,7 +1042,7 @@ compute_access (basetype_path, field)
via_protected = 1;
else if (! TREE_VIA_PUBLIC (types) && ! private_ok)
{
- access = access_private;
+ access = access_private_node;
break;
}
}
@@ -959,30 +1053,30 @@ compute_access (basetype_path, field)
/* No special visibilities apply. Use normal rules. */
- if (access == access_default)
+ if (access == access_default_node)
{
if (is_friend (context, previous_scope))
- access = access_public;
+ access = access_public_node;
else if (TREE_PRIVATE (field))
- access = access_private;
+ access = access_private_node;
else if (TREE_PROTECTED (field))
- access = access_protected;
+ access = access_protected_node;
else
- access = access_public;
+ access = access_public_node;
}
- if (access == access_public && via_protected)
- access = access_protected;
+ if (access == access_public_node && via_protected)
+ access = access_protected_node;
- if (access == access_protected && protected_ok)
- access = access_public;
+ if (access == access_protected_node && protected_ok)
+ access = access_public_node;
#if 0
- if (access == access_public)
+ if (access == access_public_node)
DECL_PUBLIC (field) = 1;
- else if (access == access_protected)
+ else if (access == access_protected_node)
DECL_PROTECTED (field) = 1;
- else if (access == access_private)
+ else if (access == access_private_node)
DECL_PRIVATE (field) = 1;
else my_friendly_abort (96);
#endif
@@ -993,6 +1087,7 @@ compute_access (basetype_path, field)
found as a base class and sub-object of the object denoted by
BINFO. This routine relies upon binfos not being shared, except
for binfos for virtual bases. */
+
static int
is_subobject_of_p (parent, binfo)
tree parent, binfo;
@@ -1019,7 +1114,8 @@ is_subobject_of_p (parent, binfo)
correspond to ANSI working paper Sept 17, 1992 10p4. The two
binfos given are the binfos corresponding to the particular places
the FIELD_DECLs are found. This routine relies upon binfos not
- being shared, except for virtual bases. */
+ being shared, except for virtual bases. */
+
static int
hides (hider_binfo, hidee_binfo)
tree hider_binfo, hidee_binfo;
@@ -1029,29 +1125,31 @@ hides (hider_binfo, hidee_binfo)
part is always true is the second part is true.
When hider and hidee are the same (two ways to get to the exact
- same member) we consider either one as hiding the other. */
+ same member) we consider either one as hiding the other. */
return is_subobject_of_p (hidee_binfo, hider_binfo);
}
/* Very similar to lookup_fnfields_1 but it ensures that at least one
function was declared inside the class given by TYPE. It really should
only return functions that match the given TYPE. */
+
static int
lookup_fnfields_here (type, name)
tree type, name;
{
- int index = lookup_fnfields_1 (type, name);
+ int idx = lookup_fnfields_1 (type, name);
tree fndecls;
- if (index <= 0)
- return index;
- fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ /* ctors and dtors are always only in the right class. */
+ if (idx <= 1)
+ return idx;
+ fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
while (fndecls)
{
- if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (fndecls))
+ if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (OVL_CURRENT (fndecls)))
== TYPE_MAIN_VARIANT (type))
- return index;
- fndecls = TREE_CHAIN (fndecls);
+ return idx;
+ fndecls = OVL_CHAIN (fndecls);
}
return -1;
}
@@ -1064,17 +1162,18 @@ lookup_fnfields_here (type, name)
It was not clear what should happen if WANT_TYPE is set, and an
ambiguity is found. At least one use (lookup_name) to not see
the error. */
+
tree
lookup_field (xbasetype, name, protect, want_type)
register tree xbasetype, name;
int protect, want_type;
{
int head = 0, tail = 0;
- tree rval, rval_binfo = NULL_TREE, rval_binfo_h;
- tree type, basetype_chain, basetype_path;
- enum access_type this_v = access_default;
+ tree rval, rval_binfo = NULL_TREE, rval_binfo_h = NULL_TREE;
+ tree type = NULL_TREE, basetype_chain, basetype_path = NULL_TREE;
+ tree this_v = access_default_node;
tree entry, binfo, binfo_h;
- enum access_type own_access = access_default;
+ tree own_access = access_default_node;
int vbase_name_p = VBASE_NAME_P (name);
/* rval_binfo is the binfo associated with the found member, note,
@@ -1086,7 +1185,7 @@ lookup_field (xbasetype, name, protect, want_type)
/* rval_binfo_h and binfo_h are binfo values used when we perform the
hiding checks, as virtual base classes may not be shared. The strategy
- is we always go into the the binfo hierarchy owned by TYPE_BINFO of
+ is we always go into the binfo hierarchy owned by TYPE_BINFO of
virtual base classes, as we cross virtual base class lines. This way
we know that binfo of a virtual base class will always == itself when
found along any line. (mrs) */
@@ -1095,12 +1194,25 @@ lookup_field (xbasetype, name, protect, want_type)
/* Set this to nonzero if we don't know how to compute
accurate error messages for access control. */
- int index = MEMOIZED_HASH_FN (name);
+ int idx = MEMOIZED_HASH_FN (name);
+#if 0
+ /* We cannot search for constructor/destructor names like this. */
+ /* This can't go here, but where should it go? */
/* If we are looking for a constructor in a templated type, use the
unspecialized name, as that is how we store it. */
if (IDENTIFIER_TEMPLATE (name))
name = constructor_name (name);
+#endif
+
+ if (xbasetype == current_class_type && TYPE_BEING_DEFINED (xbasetype)
+ && IDENTIFIER_CLASS_VALUE (name))
+ {
+ tree field = IDENTIFIER_CLASS_VALUE (name);
+ if (TREE_CODE (field) != FUNCTION_DECL
+ && ! (want_type && TREE_CODE (field) != TYPE_DECL))
+ return field;
+ }
if (TREE_CODE (xbasetype) == TREE_VEC)
{
@@ -1110,15 +1222,18 @@ lookup_field (xbasetype, name, protect, want_type)
else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
{
type = xbasetype;
- basetype_path = TYPE_BINFO (xbasetype);
+ basetype_path = TYPE_BINFO (type);
BINFO_VIA_PUBLIC (basetype_path) = 1;
BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
}
- else my_friendly_abort (97);
+ else
+ my_friendly_abort (97);
+
+ complete_type (type);
if (CLASSTYPE_MTABLE_ENTRY (type))
{
- tree tem = MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
+ tree tem = MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), idx);
while (tem && TREE_PURPOSE (tem) != name)
{
@@ -1144,8 +1259,8 @@ lookup_field (xbasetype, name, protect, want_type)
#ifdef GATHER_STATISTICS
n_calls_lookup_field++;
-#endif
- if (protect && flag_memoize_lookups && ! global_bindings_p ())
+#endif /* GATHER_STATISTICS */
+ if (protect && flag_memoize_lookups && ! toplevel_bindings_p ())
entry = make_memoized_table_entry (type, name, 0);
else
entry = 0;
@@ -1154,6 +1269,9 @@ lookup_field (xbasetype, name, protect, want_type)
if (rval || lookup_fnfields_here (type, name) >= 0)
{
+ if (entry)
+ TREE_VALUE (entry) = rval;
+
if (rval)
{
if (want_type)
@@ -1179,50 +1297,30 @@ lookup_field (xbasetype, name, protect, want_type)
this_v = compute_access (basetype_path, rval);
if (TREE_CODE (rval) == CONST_DECL)
{
- if (this_v == access_private)
+ if (this_v == access_private_node)
errstr = "enum `%D' is a private value of class `%T'";
- else if (this_v == access_protected)
+ else if (this_v == access_protected_node)
errstr = "enum `%D' is a protected value of class `%T'";
}
else
{
- if (this_v == access_private)
+ if (this_v == access_private_node)
errstr = "member `%D' is a private member of class `%T'";
- else if (this_v == access_protected)
+ else if (this_v == access_protected_node)
errstr = "member `%D' is a protected member of class `%T'";
}
}
- if (entry)
- {
- if (errstr)
- {
- /* This depends on behavior of lookup_field_1! */
- tree error_string = my_build_string (errstr);
- TREE_TYPE (entry) = error_string;
- }
- else
- {
- /* Let entry know there is no problem with this access. */
- TREE_TYPE (entry) = NULL_TREE;
- }
- TREE_VALUE (entry) = rval;
- }
-
- if (errstr && protect)
- {
- cp_error (errstr, name, type);
- return error_mark_node;
- }
- return rval;
+ rval_binfo = basetype_path;
+ goto out;
}
- basetype_chain = build_tree_list (NULL_TREE, basetype_path);
+ basetype_chain = build_expr_list (NULL_TREE, basetype_path);
TREE_VIA_PUBLIC (basetype_chain) = TREE_VIA_PUBLIC (basetype_path);
TREE_VIA_PROTECTED (basetype_chain) = TREE_VIA_PROTECTED (basetype_path);
TREE_VIA_VIRTUAL (basetype_chain) = TREE_VIA_VIRTUAL (basetype_path);
- /* The ambiguity check relies upon breadth first searching. */
+ /* The ambiguity check relies upon breadth first searching. */
search_stack = push_search_level (search_stack, &search_obstack);
binfo = basetype_path;
@@ -1248,11 +1346,11 @@ lookup_field (xbasetype, name, protect, want_type)
TREE_VIA_PROTECTED (btypes) = TREE_VIA_PROTECTED (base_binfo);
TREE_VIA_VIRTUAL (btypes) = TREE_VIA_VIRTUAL (base_binfo);
if (TREE_VIA_VIRTUAL (base_binfo))
- btypes = tree_cons (NULL_TREE,
+ btypes = my_tree_cons (NULL_TREE,
TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
btypes);
else
- btypes = tree_cons (NULL_TREE,
+ btypes = my_tree_cons (NULL_TREE,
TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
btypes);
obstack_ptr_grow (&search_obstack, btypes);
@@ -1293,12 +1391,12 @@ lookup_field (xbasetype, name, protect, want_type)
else if (rval_binfo && hides (rval_binfo_h, binfo_h))
{
/* This is ok, the member found is in rval_binfo, not
- here (binfo). */
+ here (binfo). */
}
else if (rval_binfo==NULL_TREE || hides (binfo_h, rval_binfo_h))
{
/* This is ok, the member found is here (binfo), not in
- rval_binfo. */
+ rval_binfo. */
if (nval)
{
rval = nval;
@@ -1310,7 +1408,7 @@ lookup_field (xbasetype, name, protect, want_type)
}
else
{
- /* Undo finding it before, as something else hides it. */
+ /* Undo finding it before, as something else hides it. */
rval = NULL_TREE;
}
rval_binfo = binfo;
@@ -1318,9 +1416,9 @@ lookup_field (xbasetype, name, protect, want_type)
}
else
{
- /* This is ambiguous. */
+ /* This is ambiguous. */
errstr = "request for member `%D' is ambiguous";
- protect = 2;
+ protect += 2;
break;
}
}
@@ -1370,14 +1468,14 @@ lookup_field (xbasetype, name, protect, want_type)
/* If is possible for one of the derived types on the path to
have defined special access for this field. Look for such
declarations and report an error if a conflict is found. */
- enum access_type new_v;
+ tree new_v = NULL_TREE;
- if (this_v != access_default)
+ if (this_v != access_default_node)
new_v = compute_access (TREE_VALUE (TREE_CHAIN (*tp)), rval);
- if (this_v != access_default && new_v != this_v)
+ if (this_v != access_default_node && new_v != this_v)
{
errstr = "conflicting access to member `%D'";
- this_v = access_default;
+ this_v = access_default_node;
}
own_access = new_v;
CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
@@ -1397,20 +1495,21 @@ lookup_field (xbasetype, name, protect, want_type)
if (errstr == 0)
{
- if (own_access == access_private)
+ if (own_access == access_private_node)
errstr = "member `%D' declared private";
- else if (own_access == access_protected)
+ else if (own_access == access_protected_node)
errstr = "member `%D' declared protected";
- else if (this_v == access_private)
+ else if (this_v == access_private_node)
errstr = TREE_PRIVATE (rval)
? "member `%D' is private"
: "member `%D' is from private base class";
- else if (this_v == access_protected)
+ else if (this_v == access_protected_node)
errstr = TREE_PROTECTED (rval)
? "member `%D' is protected"
: "member `%D' is from protected base class";
}
+ out:
if (entry)
{
if (errstr)
@@ -1426,15 +1525,44 @@ lookup_field (xbasetype, name, protect, want_type)
}
}
+ if (protect == 2)
+ {
+ /* If we are not interested in ambiguities, don't report them,
+ just return NULL_TREE. */
+ rval = NULL_TREE;
+ protect = 0;
+ }
+
if (errstr && protect)
{
cp_error (errstr, name, type);
rval = error_mark_node;
}
+
+ /* Do implicit typename stuff. */
+ if (rval && TREE_CODE (rval) == TYPE_DECL
+ && ! DECL_ARTIFICIAL (rval)
+ && processing_template_decl
+ && ! currently_open_class (BINFO_TYPE (rval_binfo))
+ && uses_template_parms (type))
+ {
+ binfo = rval_binfo;
+ for (; ; binfo = BINFO_INHERITANCE_CHAIN (binfo))
+ if (BINFO_INHERITANCE_CHAIN (binfo) == NULL_TREE
+ || (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo))
+ == current_class_type))
+ break;
+
+ entry = make_typename_type (BINFO_TYPE (binfo), name);
+ TREE_TYPE (entry) = TREE_TYPE (rval);
+ rval = TYPE_MAIN_DECL (entry);
+ }
+
return rval;
}
/* Try to find NAME inside a nested class. */
+
tree
lookup_nested_field (name, complain)
tree name;
@@ -1443,14 +1571,14 @@ lookup_nested_field (name, complain)
register tree t;
tree id = NULL_TREE;
- if (TREE_CHAIN (current_class_type))
+ if (TYPE_MAIN_DECL (current_class_type))
{
/* Climb our way up the nested ladder, seeing if we're trying to
modify a field in an enclosing class. If so, we should only
be able to modify if it's static. */
- for (t = TREE_CHAIN (current_class_type);
+ for (t = TYPE_MAIN_DECL (current_class_type);
t && DECL_CONTEXT (t);
- t = TREE_CHAIN (DECL_CONTEXT (t)))
+ t = TYPE_MAIN_DECL (DECL_CONTEXT (t)))
{
if (TREE_CODE (DECL_CONTEXT (t)) != RECORD_TYPE)
break;
@@ -1477,10 +1605,8 @@ lookup_nested_field (name, complain)
enums in nested classes) when we do need to call
this fn at parse time. So, in those cases, we pass
complain as a 0 and just return a NULL_TREE. */
- error ("assignment to non-static member `%s' of enclosing class `%s'",
- lang_printable_name (id),
- IDENTIFIER_POINTER (TYPE_IDENTIFIER
- (DECL_CONTEXT (t))));
+ cp_error ("assignment to non-static member `%D' of enclosing class `%T'",
+ id, DECL_CONTEXT (t));
/* Mark this for do_identifier(). It would otherwise
claim that the variable was undeclared. */
TREE_TYPE (id) = error_mark_node;
@@ -1501,6 +1627,7 @@ lookup_nested_field (name, complain)
/* TYPE is a class type. Return the index of the fields within
the method vector with name NAME, or -1 is no such field exists. */
+
static int
lookup_fnfields_1 (type, name)
tree type, name;
@@ -1514,18 +1641,41 @@ lookup_fnfields_1 (type, name)
#ifdef GATHER_STATISTICS
n_calls_lookup_fnfields_1++;
-#endif
- if (*methods && name == constructor_name (type))
+#endif /* GATHER_STATISTICS */
+
+ /* Constructors are first... */
+ if (*methods && name == ctor_identifier)
return 0;
+ /* and destructors are second. */
+ if (*++methods && name == dtor_identifier)
+ return 1;
+
while (++methods != end)
{
#ifdef GATHER_STATISTICS
n_outer_fields_searched++;
-#endif
- if (DECL_NAME (*methods) == name)
+#endif /* GATHER_STATISTICS */
+ if (DECL_NAME (OVL_CURRENT (*methods)) == name)
break;
}
+
+ /* If we didn't find it, it might have been a template
+ conversion operator. (Note that we don't look for this case
+ above so that we will always find specializations first.) */
+ if (methods == end
+ && IDENTIFIER_TYPENAME_P (name))
+ {
+ methods = &TREE_VEC_ELT (method_vec, 0) + 1;
+
+ while (++methods != end)
+ {
+ if (TREE_CODE (OVL_CURRENT (*methods)) == TEMPLATE_DECL
+ && IDENTIFIER_TYPENAME_P (DECL_NAME (OVL_CURRENT (*methods))))
+ break;
+ }
+ }
+
if (methods != end)
return methods - &TREE_VEC_ELT (method_vec, 0);
}
@@ -1537,7 +1687,7 @@ lookup_fnfields_1 (type, name)
which gives the following information (in a list):
TREE_TYPE: list of basetypes needed to get to...
- TREE_VALUE: list of all functions in of given type
+ TREE_VALUE: list of all functions in a given type
which have name NAME.
No access information is computed by this function,
@@ -1551,14 +1701,15 @@ lookup_fnfields_1 (type, name)
As a special case, is COMPLAIN is -1, we don't complain, and we
don't return error_mark_node, but rather the complete list of
virtuals. This is used by get_virtuals_named_this. */
+
tree
lookup_fnfields (basetype_path, name, complain)
tree basetype_path, name;
int complain;
{
int head = 0, tail = 0;
- tree type, rval, rval_binfo = NULL_TREE, rvals = NULL_TREE, rval_binfo_h;
- tree entry, binfo, basetype_chain, binfo_h;
+ tree type, rval, rval_binfo = NULL_TREE, rvals = NULL_TREE;
+ tree rval_binfo_h = NULL_TREE, entry, binfo, basetype_chain, binfo_h;
int find_all = 0;
/* rval_binfo is the binfo associated with the found member, note,
@@ -1570,7 +1721,7 @@ lookup_fnfields (basetype_path, name, complain)
/* rval_binfo_h and binfo_h are binfo values used when we perform the
hiding checks, as virtual base classes may not be shared. The strategy
- is we always go into the the binfo hierarchy owned by TYPE_BINFO of
+ is we always go into the binfo hierarchy owned by TYPE_BINFO of
virtual base classes, as we cross virtual base class lines. This way
we know that binfo of a virtual base class will always == itself when
found along any line. (mrs) */
@@ -1582,7 +1733,7 @@ lookup_fnfields (basetype_path, name, complain)
/* Set this to nonzero if we don't know how to compute
accurate error messages for access control. */
- int index = MEMOIZED_HASH_FN (name);
+ int idx = MEMOIZED_HASH_FN (name);
if (complain == -1)
{
@@ -1590,19 +1741,23 @@ lookup_fnfields (basetype_path, name, complain)
protect = complain = 0;
}
+#if 0
+ /* We cannot search for constructor/destructor names like this. */
+ /* This can't go here, but where should it go? */
/* If we are looking for a constructor in a templated type, use the
unspecialized name, as that is how we store it. */
if (IDENTIFIER_TEMPLATE (name))
name = constructor_name (name);
+#endif
binfo = basetype_path;
binfo_h = binfo;
- type = BINFO_TYPE (basetype_path);
+ type = complete_type (BINFO_TYPE (basetype_path));
- /* The memoization code is in need of maintenance. */
+ /* The memoization code is in need of maintenance. */
if (!find_all && CLASSTYPE_MTABLE_ENTRY (type))
{
- tree tem = MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
+ tree tem = MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type), idx);
while (tem && TREE_PURPOSE (tem) != name)
{
@@ -1653,25 +1808,25 @@ lookup_fnfields (basetype_path, name, complain)
#ifdef GATHER_STATISTICS
n_calls_lookup_fnfields++;
-#endif
- if (protect && flag_memoize_lookups && ! global_bindings_p ())
+#endif /* GATHER_STATISTICS */
+ if (protect && flag_memoize_lookups && ! toplevel_bindings_p ())
entry = make_memoized_table_entry (type, name, 1);
else
entry = 0;
- index = lookup_fnfields_here (type, name);
- if (index >= 0 || lookup_field_1 (type, name))
+ idx = lookup_fnfields_here (type, name);
+ if (idx >= 0 || lookup_field_1 (type, name))
{
rval_binfo = basetype_path;
rval_binfo_h = rval_binfo;
}
- if (index >= 0)
+ if (idx >= 0)
{
- rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
rvals = my_tree_cons (basetype_path, rval, rvals);
if (BINFO_BASETYPES (binfo) && CLASSTYPE_BASELINK_VEC (type))
- TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), index);
+ TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
if (entry)
{
@@ -1683,6 +1838,16 @@ lookup_fnfields (basetype_path, name, complain)
}
rval = NULL_TREE;
+ if (name == ctor_identifier || name == dtor_identifier)
+ {
+ /* Don't allow lookups of constructors and destructors to go
+ deeper than the first place we look. */
+ if (entry)
+ TREE_TYPE (entry) = TREE_VALUE (entry) = NULL_TREE;
+
+ return NULL_TREE;
+ }
+
if (basetype_path == TYPE_BINFO (type))
{
basetype_chain = CLASSTYPE_BINFO_AS_LIST (type);
@@ -1692,13 +1857,13 @@ lookup_fnfields (basetype_path, name, complain)
}
else
{
- basetype_chain = build_tree_list (NULL_TREE, basetype_path);
+ basetype_chain = build_expr_list (NULL_TREE, basetype_path);
TREE_VIA_PUBLIC (basetype_chain) = TREE_VIA_PUBLIC (basetype_path);
TREE_VIA_PROTECTED (basetype_chain) = TREE_VIA_PROTECTED (basetype_path);
TREE_VIA_VIRTUAL (basetype_chain) = TREE_VIA_VIRTUAL (basetype_path);
}
- /* The ambiguity check relies upon breadth first searching. */
+ /* The ambiguity check relies upon breadth first searching. */
search_stack = push_search_level (search_stack, &search_obstack);
binfo = basetype_path;
@@ -1708,7 +1873,7 @@ lookup_fnfields (basetype_path, name, complain)
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- int index;
+ int idx;
/* Process and/or queue base types. */
for (i = 0; i < n_baselinks; i++)
@@ -1724,11 +1889,11 @@ lookup_fnfields (basetype_path, name, complain)
TREE_VIA_PROTECTED (btypes) = TREE_VIA_PROTECTED (base_binfo);
TREE_VIA_VIRTUAL (btypes) = TREE_VIA_VIRTUAL (base_binfo);
if (TREE_VIA_VIRTUAL (base_binfo))
- btypes = tree_cons (NULL_TREE,
+ btypes = my_tree_cons (NULL_TREE,
TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
btypes);
else
- btypes = tree_cons (NULL_TREE,
+ btypes = my_tree_cons (NULL_TREE,
TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
btypes);
obstack_ptr_grow (&search_obstack, btypes);
@@ -1758,32 +1923,32 @@ lookup_fnfields (basetype_path, name, complain)
and we do find NAME in TYPE, verify that such a second
sighting is in fact valid. */
- index = lookup_fnfields_here (type, name);
+ idx = lookup_fnfields_here (type, name);
- if (index >= 0 || (lookup_field_1 (type, name)!=NULL_TREE && !find_all))
+ if (idx >= 0 || (lookup_field_1 (type, name)!=NULL_TREE && !find_all))
{
if (rval_binfo && !find_all && hides (rval_binfo_h, binfo_h))
{
/* This is ok, the member found is in rval_binfo, not
- here (binfo). */
+ here (binfo). */
}
else if (rval_binfo==NULL_TREE || find_all || hides (binfo_h, rval_binfo_h))
{
/* This is ok, the member found is here (binfo), not in
- rval_binfo. */
- if (index >= 0)
+ rval_binfo. */
+ if (idx >= 0)
{
- rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
/* Note, rvals can only be previously set if find_all is
true. */
rvals = my_tree_cons (basetype_path, rval, rvals);
if (TYPE_BINFO_BASETYPES (type)
&& CLASSTYPE_BASELINK_VEC (type))
- TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), index);
+ TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
}
else
{
- /* Undo finding it before, as something else hides it. */
+ /* Undo finding it before, as something else hides it. */
rval = NULL_TREE;
rvals = NULL_TREE;
}
@@ -1792,7 +1957,7 @@ lookup_fnfields (basetype_path, name, complain)
}
else
{
- /* This is ambiguous. */
+ /* This is ambiguous. */
errstr = "request for method `%D' is ambiguous";
rvals = error_mark_node;
break;
@@ -1835,22 +2000,51 @@ lookup_fnfields (basetype_path, name, complain)
return rvals;
}
+
+/* Look for a field or function named NAME in an inheritance lattice
+ dominated by XBASETYPE. PROTECT is zero if we can avoid computing
+ access information, otherwise it is 1. WANT_TYPE is 1 when we should
+ only return TYPE_DECLs, if no TYPE_DECL can be found return NULL_TREE. */
+
+tree
+lookup_member (xbasetype, name, protect, want_type)
+ tree xbasetype, name;
+ int protect, want_type;
+{
+ tree ret, basetype_path;
+
+ if (TREE_CODE (xbasetype) == TREE_VEC)
+ basetype_path = xbasetype;
+ else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
+ {
+ basetype_path = TYPE_BINFO (xbasetype);
+ BINFO_VIA_PUBLIC (basetype_path) = 1;
+ BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+ }
+ else
+ my_friendly_abort (97);
+
+ ret = lookup_field (basetype_path, name, protect, want_type);
+ if (! ret && ! want_type)
+ ret = lookup_fnfields (basetype_path, name, protect);
+ return ret;
+}
/* BREADTH-FIRST SEARCH ROUTINES. */
/* Search a multiple inheritance hierarchy by breadth-first search.
- TYPE is an aggregate type, possibly in a multiple-inheritance hierarchy.
+ BINFO is an aggregate type, possibly in a multiple-inheritance hierarchy.
TESTFN is a function, which, if true, means that our condition has been met,
and its return value should be returned.
QFN, if non-NULL, is a predicate dictating whether the type should
even be queued. */
-HOST_WIDE_INT
+static HOST_WIDE_INT
breadth_first_search (binfo, testfn, qfn)
tree binfo;
- int (*testfn)();
- int (*qfn)();
+ int (*testfn) PROTO((tree, int));
+ int (*qfn) PROTO((tree, int));
{
int head = 0, tail = 0;
int rval = 0;
@@ -1888,7 +2082,7 @@ breadth_first_search (binfo, testfn, qfn)
binfo = search_stack->first[head++];
i = (HOST_WIDE_INT) search_stack->first[head++];
- if (rval = (*testfn) (binfo, i))
+ if ((rval = (*testfn) (binfo, i)))
break;
binfo = BINFO_BASETYPE (binfo, i);
}
@@ -1908,18 +2102,7 @@ breadth_first_search (binfo, testfn, qfn)
}
/* Functions to use in breadth first searches. */
-typedef tree (*pft)();
-typedef int (*pfi)();
-
-int tree_needs_constructor_p (binfo, i)
- tree binfo;
- int i;
-{
- tree basetype;
- my_friendly_assert (i != 0, 296);
- basetype = BINFO_TYPE (BINFO_BASETYPE (binfo, i));
- return TYPE_NEEDS_CONSTRUCTING (basetype);
-}
+typedef int (*pfi) PROTO((tree, int));
static tree declarator;
@@ -1941,15 +2124,16 @@ get_virtuals_named_this (binfo)
{
tree fndecl;
- for (fndecl = TREE_VALUE (fields); fndecl; fndecl = DECL_CHAIN (fndecl))
- if (DECL_VINDEX (fndecl))
+ for (fndecl = TREE_VALUE (fields); fndecl; fndecl = OVL_NEXT (fndecl))
+ if (DECL_VINDEX (OVL_CURRENT (fndecl)))
return fields;
fields = next_baselink (fields);
}
return NULL_TREE;
}
-static tree get_virtual_destructor (binfo, i)
+static tree
+get_virtual_destructor (binfo, i)
tree binfo;
int i;
{
@@ -1957,12 +2141,13 @@ static tree get_virtual_destructor (binfo, i)
if (i >= 0)
type = BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo), i));
if (TYPE_HAS_DESTRUCTOR (type)
- && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0)))
- return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0);
+ && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1)))
+ return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1);
return 0;
}
-int tree_has_any_destructor_p (binfo, i)
+static int
+tree_has_any_destructor_p (binfo, i)
tree binfo;
int i;
{
@@ -1972,18 +2157,83 @@ int tree_has_any_destructor_p (binfo, i)
return TYPE_NEEDS_DESTRUCTOR (type);
}
+/* Returns > 0 if a function with type DRETTYPE overriding a function
+ with type BRETTYPE is covariant, as defined in [class.virtual].
+
+ Returns 1 if trivial covariance, 2 if non-trivial (requiring runtime
+ adjustment), or -1 if pedantically invalid covariance. */
+
+static int
+covariant_return_p (brettype, drettype)
+ tree brettype, drettype;
+{
+ tree binfo;
+
+ if (TREE_CODE (brettype) == FUNCTION_DECL
+ || TREE_CODE (brettype) == THUNK_DECL)
+ {
+ brettype = TREE_TYPE (TREE_TYPE (brettype));
+ drettype = TREE_TYPE (TREE_TYPE (drettype));
+ }
+ else if (TREE_CODE (brettype) == METHOD_TYPE)
+ {
+ brettype = TREE_TYPE (brettype);
+ drettype = TREE_TYPE (drettype);
+ }
+
+ if (comptypes (brettype, drettype, 1))
+ return 0;
+
+ if (! (TREE_CODE (brettype) == TREE_CODE (drettype)
+ && (TREE_CODE (brettype) == POINTER_TYPE
+ || TREE_CODE (brettype) == REFERENCE_TYPE)
+ && TYPE_READONLY (brettype) == TYPE_READONLY (drettype)
+ && TYPE_VOLATILE (brettype) == TYPE_VOLATILE (drettype)))
+ return 0;
+
+ if (! can_convert (brettype, drettype))
+ return 0;
+
+ brettype = TREE_TYPE (brettype);
+ drettype = TREE_TYPE (drettype);
+
+ /* If not pedantic, allow any standard pointer conversion. */
+ if (! IS_AGGR_TYPE (drettype) || ! IS_AGGR_TYPE (brettype))
+ return -1;
+
+ binfo = get_binfo (brettype, drettype, 1);
+
+ /* If we get an error_mark_node from get_binfo, it already complained,
+ so let's just succeed. */
+ if (binfo == error_mark_node)
+ return 1;
+
+ if (! BINFO_OFFSET_ZEROP (binfo) || TREE_VIA_VIRTUAL (binfo))
+ return 2;
+ return 1;
+}
+
/* Given a class type TYPE, and a function decl FNDECL, look for a
virtual function in TYPE's hierarchy which FNDECL could match as a
virtual function. It doesn't matter which one we find.
DTORP is nonzero if we are looking for a destructor. Destructors
need special treatment because they do not match by name. */
+
tree
get_matching_virtual (binfo, fndecl, dtorp)
tree binfo, fndecl;
int dtorp;
{
tree tmp = NULL_TREE;
+ int i;
+
+ if (TREE_CODE (fndecl) == TEMPLATE_DECL)
+ /* In [temp.mem] we have:
+
+ A specialization of a member function template does not
+ override a virtual function from a base class. */
+ return NULL_TREE;
/* Breadth first search routines start searching basetypes
of TYPE, so we must perform first ply of search here. */
@@ -2024,8 +2274,10 @@ get_matching_virtual (binfo, fndecl, dtorp)
for (; baselink; baselink = next_baselink (baselink))
{
- for (tmp = TREE_VALUE (baselink); tmp; tmp = DECL_CHAIN (tmp))
+ tree tmps;
+ for (tmps = TREE_VALUE (baselink); tmps; tmps = OVL_NEXT (tmps))
{
+ tmp = OVL_CURRENT (tmps);
if (! DECL_VINDEX (tmp))
continue;
@@ -2045,35 +2297,15 @@ get_matching_virtual (binfo, fndecl, dtorp)
tree brettype = TREE_TYPE (TREE_TYPE (tmp));
if (comptypes (brettype, drettype, 1))
/* OK */;
- else if
- (TREE_CODE (brettype) == TREE_CODE (drettype)
- && (TREE_CODE (brettype) == POINTER_TYPE
- || TREE_CODE (brettype) == REFERENCE_TYPE)
- && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (brettype)),
- TYPE_MAIN_VARIANT (TREE_TYPE (drettype)),
- 0))
- /* covariant return type */
+ else if ((i = covariant_return_p (brettype, drettype)))
{
- tree b = TREE_TYPE (brettype), d = TREE_TYPE (drettype);
- if (TYPE_MAIN_VARIANT (b) != TYPE_MAIN_VARIANT (d))
- {
- tree binfo = get_binfo (b, d, 1);
- if (binfo != error_mark_node
- && ! BINFO_OFFSET_ZEROP (binfo))
- sorry ("adjusting pointers for covariant returns");
- }
- if (TYPE_READONLY (d) > TYPE_READONLY (b))
- {
- cp_error ("return type of `%#D' adds const", fndecl);
- cp_error_at (" overriding definition as `%#D'",
- tmp);
- }
- else if (TYPE_VOLATILE (d) > TYPE_VOLATILE (b))
+ if (i == 2)
+ sorry ("adjusting pointers for covariant returns");
+
+ if (pedantic && i == -1)
{
- cp_error ("return type of `%#D' adds volatile",
- fndecl);
- cp_error_at (" overriding definition as `%#D'",
- tmp);
+ cp_pedwarn_at ("invalid covariant return type for `%#D' (must be pointer or reference to class)", fndecl);
+ cp_pedwarn_at (" overriding `%#D'", tmp);
}
}
else if (IS_AGGR_TYPE_2 (brettype, drettype)
@@ -2081,25 +2313,24 @@ get_matching_virtual (binfo, fndecl, dtorp)
{
error ("invalid covariant return type (must use pointer or reference)");
cp_error_at (" overriding `%#D'", tmp);
- cp_error (" with `%#D'", fndecl);
+ cp_error_at (" with `%#D'", fndecl);
}
else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE)
{
- cp_error ("conflicting return type specified for virtual function `%#D'", fndecl);
+ cp_error_at ("conflicting return type specified for virtual function `%#D'", fndecl);
cp_error_at (" overriding definition as `%#D'", tmp);
SET_IDENTIFIER_ERROR_LOCUS (name, basetype);
}
break;
}
}
- if (tmp)
+ /* If not at the end */
+ if (tmps)
{
best = tmp;
break;
}
}
- if (best == NULL_TREE && warn_overloaded_virtual)
- cp_warning_at ("conflicting specification deriving virtual function `%D'", fndecl);
return best;
}
@@ -2108,10 +2339,12 @@ get_matching_virtual (binfo, fndecl, dtorp)
/* Return the list of virtual functions which are abstract in type
TYPE that come from non virtual base classes. See
expand_direct_vtbls_init for the style of search we do. */
+
static tree
get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
- tree binfo, abstract_virtuals;
+ tree binfo;
int do_self;
+ tree abstract_virtuals;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
@@ -2119,8 +2352,8 @@ get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
for (i = 0; i < n_baselinks; i++)
{
tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+ int is_not_base_vtable
+ = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
if (! TREE_VIA_VIRTUAL (base_binfo))
abstract_virtuals
= get_abstract_virtuals_1 (base_binfo, is_not_base_vtable,
@@ -2148,6 +2381,7 @@ get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
/* Return the list of virtual functions which are abstract in type TYPE.
This information is cached, and so must be built on a
non-temporary obstack. */
+
tree
get_abstract_virtuals (type)
tree type;
@@ -2155,7 +2389,7 @@ get_abstract_virtuals (type)
tree vbases;
tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (type);
- /* First get all from non-virtual bases. */
+ /* First get all from non-virtual bases. */
abstract_virtuals
= get_abstract_virtuals_1 (TYPE_BINFO (type), 1, abstract_virtuals);
@@ -2190,7 +2424,7 @@ get_baselinks (type_as_binfo_list, type, name)
tree type_as_binfo_list;
tree type, name;
{
- int head = 0, tail = 0, index;
+ int head = 0, tail = 0, idx;
tree rval = 0, nval = 0;
tree basetypes = type_as_binfo_list;
tree binfo = TYPE_BINFO (type);
@@ -2226,17 +2460,17 @@ get_baselinks (type_as_binfo_list, type, name)
basetypes = search_stack->first[head++];
binfo = TREE_VALUE (basetypes);
type = BINFO_TYPE (binfo);
- index = lookup_fnfields_1 (type, name);
- if (index >= 0)
+ idx = lookup_fnfields_1 (type, name);
+ if (idx >= 0)
{
- nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
rval = hash_tree_cons (0, 0, 0, basetypes, nval, rval);
if (TYPE_BINFO_BASETYPES (type) == 0)
goto dont_queue;
else if (TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)) == 1)
{
if (CLASSTYPE_BASELINK_VEC (type))
- TREE_TYPE (rval) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), index);
+ TREE_TYPE (rval) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
goto dont_queue;
}
}
@@ -2266,6 +2500,7 @@ next_baselink (baselink)
/* DEPTH-FIRST SEARCH ROUTINES. */
+#ifdef MI_MATRIX
/* Assign unique numbers to _CLASSTYPE members of the lattice
specified by TYPE. The root nodes are marked first; the nodes
are marked depth-fisrt, left-right. */
@@ -2290,11 +2525,13 @@ static int mi_size;
((mi_matrix+mi_size*(CLASSTYPE_CID (C1)-1))[CLASSTYPE_CID (C2)-1])
#define BINFO_DERIVES_FROM_STAR(C) \
(mi_matrix+(BINFO_CID (C)-1))
+#endif
/* This routine converts a pointer to be a pointer of an immediate
base class. The normal convert_pointer_to routine would diagnose
the conversion as ambiguous, under MI code that has the base class
- as an ambiguous base class. */
+ as an ambiguous base class. */
+
static tree
convert_pointer_to_single_level (to_type, expr)
tree to_type, expr;
@@ -2313,12 +2550,13 @@ convert_pointer_to_single_level (to_type, expr)
This routine has to remember the path it walked up, when
dfs_init_vbase_pointers is the work function, as otherwise there
- would be no record. */
+ would be no record. */
+
static void
dfs_walk (binfo, fn, qfn)
tree binfo;
- void (*fn)();
- int (*qfn)();
+ void (*fn) PROTO((tree));
+ int (*qfn) PROTO((tree));
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
@@ -2329,7 +2567,10 @@ dfs_walk (binfo, fn, qfn)
if (qfn == 0 || (*qfn)(base_binfo))
{
- if (fn == dfs_init_vbase_pointers)
+ if (TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TEMPLATE_PARM)
+ /* Pass */;
+ else if (fn == dfs_init_vbase_pointers)
{
/* When traversing an arbitrary MI hierarchy, we need to keep
a record of the path we took to get down to the final base
@@ -2354,7 +2595,7 @@ dfs_walk (binfo, fn, qfn)
/* No need for the conversion here, as we know it is the
right type. */
vbase_decl_ptr_intermediate
- = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo));
+ = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo));
}
else
{
@@ -2366,47 +2607,56 @@ dfs_walk (binfo, fn, qfn)
dfs_walk (base_binfo, fn, qfn);
vbase_decl_ptr_intermediate = saved_vbase_decl_ptr_intermediate;
- } else
- dfs_walk (base_binfo, fn, qfn);
+ }
+ else
+ dfs_walk (base_binfo, fn, qfn);
}
}
fn (binfo);
}
+#ifdef MI_MATRIX
/* Predicate functions which serve for dfs_walk. */
static int numberedp (binfo) tree binfo;
{ return BINFO_CID (binfo); }
static int unnumberedp (binfo) tree binfo;
{ return BINFO_CID (binfo) == 0; }
+#endif
static int markedp (binfo) tree binfo;
{ return BINFO_MARKED (binfo); }
-static int bfs_markedp (binfo, i) tree binfo; int i;
-{ return BINFO_MARKED (BINFO_BASETYPE (binfo, i)); }
static int unmarkedp (binfo) tree binfo;
{ return BINFO_MARKED (binfo) == 0; }
+
+#if 0
+static int bfs_markedp (binfo, i) tree binfo; int i;
+{ return BINFO_MARKED (BINFO_BASETYPE (binfo, i)); }
static int bfs_unmarkedp (binfo, i) tree binfo; int i;
{ return BINFO_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
-static int marked_vtable_pathp (binfo) tree binfo;
-{ return BINFO_VTABLE_PATH_MARKED (binfo); }
static int bfs_marked_vtable_pathp (binfo, i) tree binfo; int i;
{ return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)); }
-static int unmarked_vtable_pathp (binfo) tree binfo;
-{ return BINFO_VTABLE_PATH_MARKED (binfo) == 0; }
static int bfs_unmarked_vtable_pathp (binfo, i) tree binfo; int i;
{ return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
-static int marked_new_vtablep (binfo) tree binfo;
-{ return BINFO_NEW_VTABLE_MARKED (binfo); }
static int bfs_marked_new_vtablep (binfo, i) tree binfo; int i;
{ return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo, i)); }
-static int unmarked_new_vtablep (binfo) tree binfo;
-{ return BINFO_NEW_VTABLE_MARKED (binfo) == 0; }
static int bfs_unmarked_new_vtablep (binfo, i) tree binfo; int i;
{ return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
+#endif
+static int marked_vtable_pathp (binfo) tree binfo;
+{ return BINFO_VTABLE_PATH_MARKED (binfo); }
+static int unmarked_vtable_pathp (binfo) tree binfo;
+{ return BINFO_VTABLE_PATH_MARKED (binfo) == 0; }
+static int marked_new_vtablep (binfo) tree binfo;
+{ return BINFO_NEW_VTABLE_MARKED (binfo); }
+static int unmarked_new_vtablep (binfo) tree binfo;
+{ return BINFO_NEW_VTABLE_MARKED (binfo) == 0; }
+
+#if 0
static int dfs_search_slot_nonempty_p (binfo) tree binfo;
{ return CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) != 0; }
+#endif
static int dfs_debug_unmarkedp (binfo) tree binfo;
{ return CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo)) == 0; }
@@ -2415,6 +2665,7 @@ static int dfs_debug_unmarkedp (binfo) tree binfo;
test anything (vis a vis marking) if they are paired with
a predicate function (above). */
+#ifdef MI_MATRIX
/* Assign each type within the lattice a number which is unique
in the lattice. The first number assigned is 1. */
@@ -2431,15 +2682,19 @@ dfs_unnumber (binfo)
{
BINFO_CID (binfo) = 0;
}
+#endif
+#if 0
static void
dfs_mark (binfo) tree binfo;
{ SET_BINFO_MARKED (binfo); }
+#endif
static void
dfs_unmark (binfo) tree binfo;
{ CLEAR_BINFO_MARKED (binfo); }
+#if 0
static void
dfs_mark_vtable_path (binfo) tree binfo;
{ SET_BINFO_VTABLE_PATH_MARKED (binfo); }
@@ -2459,6 +2714,7 @@ dfs_unmark_new_vtable (binfo) tree binfo;
static void
dfs_clear_search_slot (binfo) tree binfo;
{ CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
+#endif
static void
dfs_debug_mark (binfo)
@@ -2472,9 +2728,12 @@ dfs_debug_mark (binfo)
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
- /* If interface info is known, the value of (?@@?) is correct. */
- if (methods == 0
- || CLASSTYPE_INTERFACE_KNOWN (t)
+ if (methods == 0)
+ return;
+
+ /* If interface info is known, either we've already emitted the debug
+ info or we don't need to. */
+ if (CLASSTYPE_INTERFACE_KNOWN (t)
|| (write_virtuals == 2 && TYPE_VIRTUAL_P (t)))
return;
@@ -2484,10 +2743,13 @@ dfs_debug_mark (binfo)
if (current_function_decl == NULL_TREE
|| DECL_CLASS_CONTEXT (current_function_decl) != t)
{
- if (TREE_VEC_ELT (methods, 0))
+ if (TREE_VEC_ELT (methods, 1))
+ methods = TREE_VEC_ELT (methods, 1);
+ else if (TREE_VEC_ELT (methods, 0))
methods = TREE_VEC_ELT (methods, 0);
else
- methods = TREE_VEC_ELT (methods, 1);
+ methods = TREE_VEC_ELT (methods, 2);
+ methods = OVL_CURRENT (methods);
while (methods)
{
if (DECL_VINDEX (methods)
@@ -2505,13 +2767,14 @@ dfs_debug_mark (binfo)
/* We cannot rely on some alien method to solve our problems,
so we must write out the debug info ourselves. */
TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0;
- rest_of_type_compilation (t, global_bindings_p ());
+ rest_of_type_compilation (t, toplevel_bindings_p ());
}
/* Attach to the type of the virtual base class, the pointer to the
virtual base class, given the global pointer vbase_decl_ptr.
We use the global vbase_types. ICK! */
+
static void
dfs_find_vbases (binfo)
tree binfo;
@@ -2530,8 +2793,8 @@ dfs_find_vbases (binfo)
tree binfo = binfo_member (vbase, vbase_types);
CLASSTYPE_SEARCH_SLOT (vbase)
- = (char *) build (PLUS_EXPR, build_pointer_type (vbase),
- vbase_decl_ptr, BINFO_OFFSET (binfo));
+ = build (PLUS_EXPR, build_pointer_type (vbase),
+ vbase_decl_ptr, BINFO_OFFSET (binfo));
}
}
SET_BINFO_VTABLE_PATH_MARKED (binfo);
@@ -2548,12 +2811,12 @@ dfs_init_vbase_pointers (binfo)
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
- /* If there is a rtti, it is the first field, though perhaps from
- the base class. Otherwise, the first fields are virtual base class
- pointer fields. */
- if (CLASSTYPE_RTTI (type) && VFIELD_NAME_P (DECL_NAME (fields)))
- /* Get past vtable for the object. */
+#if 0
+ /* See finish_struct_1 for when we can enable this. */
+ /* If we have a vtable pointer first, skip it. */
+ if (VFIELD_NAME_P (DECL_NAME (fields)))
fields = TREE_CHAIN (fields);
+#endif
if (fields == NULL_TREE
|| DECL_NAME (fields) == NULL_TREE
@@ -2570,7 +2833,7 @@ dfs_init_vbase_pointers (binfo)
{
tree ref = build (COMPONENT_REF, TREE_TYPE (fields),
build_indirect_ref (this_vbase_ptr, NULL_PTR), fields);
- tree init = (tree)CLASSTYPE_SEARCH_SLOT (TREE_TYPE (TREE_TYPE (fields)));
+ tree init = CLASSTYPE_SEARCH_SLOT (TREE_TYPE (TREE_TYPE (fields)));
vbase_init_result = tree_cons (binfo_member (TREE_TYPE (TREE_TYPE (fields)),
vbase_types),
build_modify_expr (ref, NOP_EXPR, init),
@@ -2582,6 +2845,7 @@ dfs_init_vbase_pointers (binfo)
/* Sometimes this needs to clear both VTABLE_PATH and NEW_VTABLE. Other
times, just NEW_VTABLE, but optimizer should make both with equal
efficiency (though it does not currently). */
+
static void
dfs_clear_vbase_slots (binfo)
tree binfo;
@@ -2603,9 +2867,7 @@ init_vbase_pointers (type, decl_ptr)
tree binfo = TYPE_BINFO (type);
flag_this_is_variable = -2;
vbase_types = CLASSTYPE_VBASECLASSES (type);
- vbase_decl_ptr = decl_ptr;
- vbase_decl = build_indirect_ref (decl_ptr, NULL_PTR);
- vbase_decl_ptr_intermediate = vbase_decl_ptr;
+ vbase_decl_ptr = vbase_decl_ptr_intermediate = decl_ptr;
vbase_init_result = NULL_TREE;
dfs_walk (binfo, dfs_find_vbases, unmarked_vtable_pathp);
dfs_walk (binfo, dfs_init_vbase_pointers, marked_vtable_pathp);
@@ -2626,6 +2888,7 @@ init_vbase_pointers (type, decl_ptr)
We know that if there is more than one place (binfo) the fndecl that the
declared, they all refer to the same binfo. See get_class_offset_1 for
the check that ensures this. */
+
static tree
virtual_context (fndecl, t, vbase)
tree fndecl, t, vbase;
@@ -2663,7 +2926,10 @@ virtual_context (fndecl, t, vbase)
they may upcast into a direct base, or
they may upcast into a different vbase.
- We only need to do fixups in case 2 and 3.
+ We only need to do fixups in case 2 and 3. In case 2, we add in
+ the virtual base offset to effect an upcast, in case 3, we add in
+ the virtual base offset to effect an upcast, then subtract out the
+ offset for the other virtual base, to effect a downcast into it.
This routine mirrors fixup_vtable_deltas in functionality, though
this one is runtime based, and the other is compile time based.
@@ -2671,10 +2937,15 @@ virtual_context (fndecl, t, vbase)
done at runtime.
VBASE_OFFSETS is an association list of virtual bases that contains
- offset information, so the offsets are only calculated once. */
+ offset information for the virtual bases, so the offsets are only
+ calculated once. The offsets are computed by where we think the
+ vbase should be (as noted by the CLASSTYPE_SEARCH_SLOT) minus where
+ the vbase really is. */
+
static void
-expand_upcast_fixups (binfo, addr, orig_addr, vbase, t, vbase_offsets)
- tree binfo, addr, orig_addr, vbase, t, *vbase_offsets;
+expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
+ vbase_offsets)
+ tree binfo, addr, orig_addr, vbase, vbase_addr, t, *vbase_offsets;
{
tree virtuals = BINFO_VIRTUALS (binfo);
tree vc;
@@ -2684,8 +2955,8 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, t, vbase_offsets)
delta = purpose_member (vbase, *vbase_offsets);
if (! delta)
{
- delta = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbase));
- delta = build (MINUS_EXPR, ptrdiff_type_node, delta, addr);
+ delta = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbase));
+ delta = build (MINUS_EXPR, ptrdiff_type_node, delta, vbase_addr);
delta = save_expr (delta);
delta = tree_cons (vbase, delta, *vbase_offsets);
*vbase_offsets = delta;
@@ -2702,8 +2973,8 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, t, vbase_offsets)
&& current_fndecl != abort_fndecl
&& (vc=virtual_context (current_fndecl, t, vbase)) != vbase)
{
- /* This may in fact need a runtime fixup. */
- tree idx = DECL_VINDEX (current_fndecl);
+ /* This may in fact need a runtime fixup. */
+ tree idx = build_int_2 (n, 0);
tree vtbl = BINFO_VTABLE (binfo);
tree nvtbl = lookup_name (DECL_NAME (vtbl), 0);
tree aref, ref, naref;
@@ -2714,51 +2985,69 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, t, vbase_offsets)
|| nvtbl == IDENTIFIER_GLOBAL_VALUE (DECL_NAME (vtbl)))
{
/* Dup it if it isn't in local scope yet. */
- nvtbl = build_decl (VAR_DECL,
- DECL_NAME (vtbl),
- TYPE_MAIN_VARIANT (TREE_TYPE (BINFO_VTABLE (binfo))));
+ nvtbl = build_decl
+ (VAR_DECL, DECL_NAME (vtbl),
+ TYPE_MAIN_VARIANT (TREE_TYPE (BINFO_VTABLE (binfo))));
DECL_ALIGN (nvtbl) = MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (nvtbl));
TREE_READONLY (nvtbl) = 0;
+ DECL_ARTIFICIAL (nvtbl) = 1;
nvtbl = pushdecl (nvtbl);
init = NULL_TREE;
- cp_finish_decl (nvtbl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
- DECL_VIRTUAL_P (nvtbl) = 1;
- DECL_CONTEXT (nvtbl) = t;
+ cp_finish_decl (nvtbl, init, NULL_TREE, 0,
+ LOOKUP_ONLYCONVERTING);
+
+ /* We don't set DECL_VIRTUAL_P and DECL_CONTEXT on nvtbl
+ because they wouldn't be useful; everything that wants to
+ look at the vtable will look at the decl for the normal
+ vtable. Setting DECL_CONTEXT also screws up
+ decl_function_context. */
+
init = build (MODIFY_EXPR, TREE_TYPE (nvtbl),
nvtbl, vtbl);
TREE_SIDE_EFFECTS (init) = 1;
expand_expr_stmt (init);
- /* Update the vtable pointers as necessary. */
- ref = build_vfield_ref (build_indirect_ref (addr, NULL_PTR), DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))));
- expand_expr_stmt (build_modify_expr (ref, NOP_EXPR,
- build_unary_op (ADDR_EXPR, nvtbl, 0)));
+ /* Update the vtable pointers as necessary. */
+ ref = build_vfield_ref
+ (build_indirect_ref (addr, NULL_PTR),
+ DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo))));
+ expand_expr_stmt
+ (build_modify_expr (ref, NOP_EXPR,
+ build_unary_op (ADDR_EXPR, nvtbl, 0)));
}
assemble_external (vtbl);
aref = build_array_ref (vtbl, idx);
naref = build_array_ref (nvtbl, idx);
- old_delta = build_component_ref (aref, delta_identifier, 0, 0);
- new_delta = build_component_ref (naref, delta_identifier, 0, 0);
+ old_delta = build_component_ref (aref, delta_identifier,
+ NULL_TREE, 0);
+ new_delta = build_component_ref (naref, delta_identifier,
+ NULL_TREE, 0);
+
+ /* This is a upcast, so we have to add the offset for the
+ virtual base. */
old_delta = build_binary_op (PLUS_EXPR, old_delta,
TREE_VALUE (delta), 0);
if (vc)
{
- /* If this is set, we need to add in delta adjustments for
- the other virtual base. */
+ /* If this is set, we need to subtract out the delta
+ adjustments for the other virtual base that we
+ downcast into. */
tree vc_delta = purpose_member (vc, *vbase_offsets);
if (! vc_delta)
{
tree vc_addr = convert_pointer_to_real (vc, orig_addr);
- vc_delta = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vc));
+ vc_delta = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vc));
vc_delta = build (MINUS_EXPR, ptrdiff_type_node,
- vc_addr, vc_delta);
+ vc_delta, vc_addr);
vc_delta = save_expr (vc_delta);
*vbase_offsets = tree_cons (vc, vc_delta, *vbase_offsets);
}
else
vc_delta = TREE_VALUE (vc_delta);
- old_delta = build_binary_op (PLUS_EXPR, old_delta, vc_delta, 0);
+ /* This is a downcast, so we have to subtract the offset
+ for the virtual base. */
+ old_delta = build_binary_op (MINUS_EXPR, old_delta, vc_delta, 0);
}
TREE_READONLY (new_delta) = 0;
@@ -2772,10 +3061,12 @@ expand_upcast_fixups (binfo, addr, orig_addr, vbase, t, vbase_offsets)
/* Fixup upcast offsets for all direct vtables. Patterned after
expand_direct_vtbls_init. */
+
static void
fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, orig_addr, type, vbase, vbase_offsets)
- tree real_binfo, binfo, addr, orig_addr, type, vbase, *vbase_offsets;
+ tree real_binfo, binfo;
int init_self, can_elide;
+ tree addr, orig_addr, type, vbase, *vbase_offsets;
{
tree real_binfos = BINFO_BASETYPES (real_binfo);
tree binfos = BINFO_BASETYPES (binfo);
@@ -2785,8 +3076,8 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
{
tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
+ int is_not_base_vtable
+ = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
if (! TREE_VIA_VIRTUAL (real_base_binfo))
fixup_virtual_upcast_offsets (real_base_binfo, base_binfo,
is_not_base_vtable, can_elide, addr,
@@ -2800,8 +3091,9 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
/* Should we use something besides CLASSTYPE_VFIELDS? */
if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (real_binfo)))
{
- addr = convert_pointer_to_real (binfo, addr);
- expand_upcast_fixups (real_binfo, addr, orig_addr, vbase, type, vbase_offsets);
+ tree new_addr = convert_pointer_to_real (binfo, addr);
+ expand_upcast_fixups (real_binfo, new_addr, orig_addr, vbase, addr,
+ type, vbase_offsets);
}
}
@@ -2818,30 +3110,22 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
offsets are valid to store vtables. When zero, we must store new
vtables through virtual baseclass pointers.
- We setup and use the globals: vbase_decl, vbase_decl_ptr, vbase_types
+ We setup and use the globals: vbase_decl_ptr, vbase_types
ICK! */
void
-expand_indirect_vtbls_init (binfo, true_exp, decl_ptr, use_computed_offsets)
+expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
tree binfo;
tree true_exp, decl_ptr;
- int use_computed_offsets;
{
tree type = BINFO_TYPE (binfo);
+
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
{
rtx fixup_insns = NULL_RTX;
- int old_flag = flag_this_is_variable;
tree vbases = CLASSTYPE_VBASECLASSES (type);
vbase_types = vbases;
vbase_decl_ptr = true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0) : decl_ptr;
- vbase_decl = true_exp ? true_exp : build_indirect_ref (decl_ptr, NULL_PTR);
-
- if (use_computed_offsets)
- {
- /* This is an object of type IN_TYPE, */
- flag_this_is_variable = -2;
- }
dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep);
@@ -2849,57 +3133,25 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr, use_computed_offsets)
for (; vbases; vbases = TREE_CHAIN (vbases))
{
tree addr;
- if (use_computed_offsets)
- addr = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbases));
- else
- {
-#if 1
- addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vbase_decl_ptr);
-#else
- /* This should should never work better than the above. (mrs) */
- tree vbinfo = get_binfo (TREE_TYPE (vbases),
- TREE_TYPE (vbase_decl),
- 0);
-
- /* See is we can get lucky. */
- if (TREE_VIA_VIRTUAL (vbinfo))
- addr = convert_pointer_to_real (vbinfo, vbase_decl_ptr);
- else
- {
- /* We go through all these contortions to avoid this
- call, as it will fail when the virtual base type
- is ambiguous from here. We don't yet have a way
- to search for and find just an instance of the
- virtual base class. Searching for the binfo in
- vbases won't work, as we don't have the vbase
- pointer field, for all vbases in the main class,
- only direct vbases. */
- addr = convert_pointer_to_real (TREE_TYPE (vbases),
- vbase_decl_ptr);
- if (addr == error_mark_node)
- continue;
- }
-#endif
- }
- /* Do all vtables from this virtual base. */
+ addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vbase_decl_ptr);
+
+ /* Do all vtables from this virtual base. */
/* This assumes that virtual bases can never serve as parent
- binfos. (in the CLASSTPE_VFIELD_PARENT sense) */
+ binfos. (in the CLASSTYPE_VFIELD_PARENT sense) */
expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)),
1, 0, addr);
- /* If we are using computed offsets we can skip fixups. */
- if (use_computed_offsets)
- continue;
-
- /* Now we adjust the offsets for virtual functions that cross
- virtual boundaries on an implicit upcast on vf call so that
- the layout of the most complete type is used, instead of
- assuming the layout of the virtual bases from our current type. */
+ /* Now we adjust the offsets for virtual functions that
+ cross virtual boundaries on an implicit upcast on vf call
+ so that the layout of the most complete type is used,
+ instead of assuming the layout of the virtual bases from
+ our current type. */
if (flag_vtable_thunks)
{
- /* We don't have dynamic thunks yet! So for now, just fail silently. */
+ /* We don't have dynamic thunks yet!
+ So for now, just fail silently. */
}
else
{
@@ -2930,19 +3182,9 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr, use_computed_offsets)
}
dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);
-
- flag_this_is_variable = old_flag;
}
}
-void
-clear_search_slots (type)
- tree type;
-{
- dfs_walk (TYPE_BINFO (type),
- dfs_clear_search_slot, dfs_search_slot_nonempty_p);
-}
-
/* get virtual base class types.
This adds type to the vbase_types list in reverse dfs order.
Ordering is very important, so don't change it. */
@@ -2963,6 +3205,7 @@ dfs_get_vbase_types (binfo)
}
/* get a list of virtual base classes in dfs order. */
+
tree
get_vbase_types (type)
tree type;
@@ -2989,6 +3232,7 @@ get_vbase_types (type)
return vbase_types;
}
+#ifdef MI_MATRIX
static void
dfs_record_inheritance (binfo)
tree binfo;
@@ -3004,6 +3248,11 @@ dfs_record_inheritance (binfo)
tree baseclass = BINFO_TYPE (base_binfo);
mi_boolean *base_row = BINFO_DERIVES_FROM_STAR (base_binfo);
+ if (TREE_CODE (baseclass) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (baseclass) == TEMPLATE_TEMPLATE_PARM)
+ continue;
+ my_friendly_assert (CLASSTYPE_CID (baseclass) != 0, 2365);
+
/* Don't search if there's nothing there! MI_SIZE can be
zero as a result of parse errors. */
if (TYPE_BINFO_BASETYPES (baseclass) && mi_size > 0)
@@ -3045,11 +3294,14 @@ build_mi_matrix (type)
}
#endif
+ dfs_walk (binfo, dfs_number, unnumberedp);
+
mi_size = CLASSTYPE_N_SUPERCLASSES (type) + CLASSTYPE_N_VBASECLASSES (type);
+ if (mi_size < (cid-1))
+ mi_size = cid-1;
mi_matrix = (char *)xmalloc ((mi_size + 1) * (mi_size + 1));
mi_type = type;
bzero (mi_matrix, (mi_size + 1) * (mi_size + 1));
- dfs_walk (binfo, dfs_number, unnumberedp);
dfs_walk (binfo, dfs_record_inheritance, unmarkedp);
dfs_walk (binfo, dfs_unmark, markedp);
}
@@ -3067,6 +3319,7 @@ free_mi_matrix ()
cid = 0;
#endif
}
+#endif
/* If we want debug info for a type TYPE, make sure all its base types
are also marked as being potentially interesting. This avoids
@@ -3078,6 +3331,22 @@ note_debug_info_needed (type)
tree type;
{
tree field;
+
+ if (current_template_parms)
+ return;
+
+ if (TYPE_BEING_DEFINED (type))
+ /* We can't go looking for the base types and fields just yet. */
+ return;
+
+ /* We can't do the TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
+ does not support name references between translation units. Well, we
+ could, but that would mean putting global labels in the debug output
+ before each exported type and each of its functions and static data
+ members. */
+ if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
+ return;
+
dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp);
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
@@ -3100,7 +3369,13 @@ envelope_add_decl (type, decl, values)
tree name = DECL_NAME (decl);
int dont_add = 0;
- /* virtual base names are always unique. */
+ /* Yet Another Implicit Typename Kludge: Since we don't tsubst
+ the members for partial instantiations, DECL_CONTEXT (decl) is wrong.
+ But pretend it's right for this function. */
+ if (processing_template_decl)
+ type = DECL_REAL_CONTEXT (decl);
+
+ /* virtual base names are always unique. */
if (VBASE_NAME_P (name))
*values = NULL_TREE;
@@ -3121,10 +3396,7 @@ envelope_add_decl (type, decl, values)
warning ("in this context");
}
- context = (TREE_CODE (value) == FUNCTION_DECL
- && DECL_VIRTUAL_P (value))
- ? DECL_CLASS_CONTEXT (value)
- : DECL_CONTEXT (value);
+ context = DECL_REAL_CONTEXT (value);
if (context == type)
{
@@ -3134,7 +3406,17 @@ envelope_add_decl (type, decl, values)
else
dont_add = 1;
}
- else if (context && TYPE_DERIVES_FROM (context, type))
+ else if (type == current_class_type
+#ifdef MI_MATRIX
+ /* If we don't check CLASSTYPE_CID on CONTEXT right now,
+ we'll end up subtracting from the address of MI_MATRIX,
+ putting us off in la la land. */
+ || (CLASSTYPE_CID (type)
+ && TYPE_DERIVES_FROM (context, type))
+#else
+ || DERIVED_FROM_P (context, type)
+#endif
+ )
{
/* Don't add in *values to list */
*values = NULL_TREE;
@@ -3152,7 +3434,17 @@ envelope_add_decl (type, decl, values)
? DECL_CLASS_CONTEXT (value)
: DECL_CONTEXT (value);
- if (context && TYPE_DERIVES_FROM (context, type))
+ if (type == current_class_type
+#ifdef MI_MATRIX
+ /* If we don't check CLASSTYPE_CID on CONTEXT right now,
+ we'll end up subtracting from the address of MI_MATRIX,
+ putting us off in la la land. */
+ || (CLASSTYPE_CID (type)
+ && TYPE_DERIVES_FROM (context, type))
+#else
+ || DERIVED_FROM_P (context, type)
+#endif
+ )
{
/* remove *tmp from list */
*tmp = TREE_CHAIN (*tmp);
@@ -3253,17 +3545,17 @@ dfs_pushdecls (binfo)
}
method_vec = CLASSTYPE_METHOD_VEC (type);
- if (method_vec != 0)
+ if (method_vec)
{
/* Farm out constructors and destructors. */
- methods = &TREE_VEC_ELT (method_vec, 1);
+ methods = &TREE_VEC_ELT (method_vec, 2);
end = TREE_VEC_END (method_vec);
while (methods != end)
{
/* This will cause lookup_name to return a pointer
to the tree_list of possible methods of this name. */
- tree name = DECL_NAME (*methods);
+ tree name = DECL_NAME (OVL_CURRENT (*methods));
tree class_value = IDENTIFIER_CLASS_VALUE (name);
/* If the class value is not an envelope of the kind described in
@@ -3283,7 +3575,11 @@ dfs_pushdecls (binfo)
If we can't do that, keep a TREE_LIST with possibly ambiguous
decls in there. */
maybe_push_cache_obstack ();
- envelope_add_decl (type, *methods, &TREE_PURPOSE (class_value));
+ /* Arbitrarily choose the first function in the list. This is OK
+ because this is only used for initial lookup; anything that
+ actually uses the function will look it up again. */
+ envelope_add_decl (type, OVL_CURRENT (*methods),
+ &TREE_PURPOSE (class_value));
pop_obstacks ();
methods++;
@@ -3293,6 +3589,7 @@ dfs_pushdecls (binfo)
}
/* Consolidate unique (by name) member functions. */
+
static void
dfs_compress_decls (binfo)
tree binfo;
@@ -3303,14 +3600,15 @@ dfs_compress_decls (binfo)
if (method_vec != 0)
{
/* Farm out constructors and destructors. */
- tree *methods = &TREE_VEC_ELT (method_vec, 1);
+ tree *methods = &TREE_VEC_ELT (method_vec, 2);
tree *end = TREE_VEC_END (method_vec);
for (; methods != end; methods++)
{
/* This is known to be an envelope of the kind described before
dfs_pushdecls. */
- tree class_value = IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods));
+ tree class_value =
+ IDENTIFIER_CLASS_VALUE (DECL_NAME (OVL_CURRENT (*methods)));
tree tmp = TREE_PURPOSE (class_value);
/* This was replaced in scope by somebody else. Just leave it
@@ -3320,7 +3618,7 @@ dfs_compress_decls (binfo)
if (TREE_CHAIN (tmp) == NULL_TREE
&& TREE_VALUE (tmp)
- && DECL_CHAIN (TREE_VALUE (tmp)) == NULL_TREE)
+ && OVL_NEXT (TREE_VALUE (tmp)) == NULL_TREE)
{
TREE_PURPOSE (class_value) = TREE_VALUE (tmp);
}
@@ -3335,26 +3633,14 @@ dfs_compress_decls (binfo)
with `error_mark_node' so that if they are encountered
without explicit qualification, we can emit an error
message. */
+
void
push_class_decls (type)
tree type;
{
- tree id;
struct obstack *ambient_obstack = current_obstack;
-
search_stack = push_search_level (search_stack, &search_obstack);
- id = TYPE_IDENTIFIER (type);
-#if 0
- if (IDENTIFIER_TEMPLATE (id) != 0)
- {
- tree tmpl = IDENTIFIER_TEMPLATE (id);
- push_template_decls (DECL_ARGUMENTS (TREE_PURPOSE (tmpl)),
- TREE_VALUE (tmpl), 1);
- overload_template_name (id, 1);
- }
-#endif
-
/* Push class fields into CLASS_VALUE scope, and mark. */
dfs_walk (TYPE_BINFO (type), dfs_pushdecls, unmarkedp);
@@ -3381,7 +3667,31 @@ push_class_decls (type)
{
tree node = TREE_VALUE (new);
- while (TREE_CODE (node) == TREE_LIST)
+ if (TREE_CODE (node) == TYPE_DECL
+ && DECL_ARTIFICIAL (node)
+ && IS_AGGR_TYPE (TREE_TYPE (node))
+ && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (node)))
+ {
+ tree t = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (node));
+ tree n = new;
+
+ for (; n; n = TREE_CHAIN (n))
+ {
+ tree d = TREE_VALUE (n);
+ if (TREE_CODE (d) == TYPE_DECL
+ && DECL_ARTIFICIAL (node)
+ && IS_AGGR_TYPE (TREE_TYPE (d))
+ && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (d))
+ && CLASSTYPE_TI_TEMPLATE (TREE_TYPE (d)) == t)
+ /* OK */;
+ else
+ break;
+ }
+
+ if (n == NULL_TREE)
+ new = t;
+ }
+ else while (TREE_CODE (node) == TREE_LIST)
node = TREE_VALUE (node);
id = DECL_NAME (node);
}
@@ -3402,6 +3712,7 @@ push_class_decls (type)
}
/* Here's a subroutine we need because C lacks lambdas. */
+
static void
dfs_unuse_fields (binfo)
tree binfo;
@@ -3429,8 +3740,7 @@ unuse_fields (type)
}
void
-pop_class_decls (type)
- tree type;
+pop_class_decls ()
{
/* We haven't pushed a search level when dealing with cached classes,
so we'd better not try to pop it. */
@@ -3464,9 +3774,9 @@ print_search_statistics ()
fprintf (stderr, "%d fnfields searched in %d calls to lookup_fnfields\n",
n_outer_fields_searched, n_calls_lookup_fnfields);
fprintf (stderr, "%d calls to get_base_type\n", n_calls_get_base_type);
-#else
+#else /* GATHER_STATISTICS */
fprintf (stderr, "no search statistics\n");
-#endif
+#endif /* GATHER_STATISTICS */
}
void
@@ -3478,7 +3788,7 @@ init_search_processing ()
/* This gives us room to build our chains of basetypes,
whether or not we decide to memoize them. */
- type_stack = push_type_level (0, &type_obstack);
+ type_stack = push_type_level ((struct stack_level *)0, &type_obstack);
_vptr_name = get_identifier ("_vptr");
}
@@ -3494,24 +3804,34 @@ reinit_search_statistics ()
memoized_fast_rejects[1] = 0;
memoized_fields_searched[0] = 0;
memoized_fields_searched[1] = 0;
+#ifdef GATHER_STATISTICS
n_fields_searched = 0;
n_calls_lookup_field = 0, n_calls_lookup_field_1 = 0;
n_calls_lookup_fnfields = 0, n_calls_lookup_fnfields_1 = 0;
n_calls_get_base_type = 0;
n_outer_fields_searched = 0;
n_contexts_saved = 0;
+#endif /* GATHER_STATISTICS */
}
+#define scratch_tree_cons expr_tree_cons
+
static tree conversions;
static void
add_conversions (binfo)
tree binfo;
{
- tree tmp = CLASSTYPE_FIRST_CONVERSION (BINFO_TYPE (binfo));
- for (; tmp && IDENTIFIER_TYPENAME_P (DECL_NAME (tmp));
- tmp = TREE_CHAIN (tmp))
- conversions = tree_cons (DECL_NAME (tmp), TREE_TYPE (TREE_TYPE (tmp)),
- conversions);
+ int i;
+ tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
+
+ for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)
+ {
+ tree tmp = TREE_VEC_ELT (method_vec, i);
+ if (! IDENTIFIER_TYPENAME_P (DECL_NAME (OVL_CURRENT (tmp))))
+ break;
+ conversions = scratch_tree_cons (binfo, tmp, conversions);
+ }
+ SET_BINFO_MARKED (binfo);
}
tree
@@ -3519,6 +3839,135 @@ lookup_conversions (type)
tree type;
{
conversions = NULL_TREE;
- dfs_walk (TYPE_BINFO (type), add_conversions, 0);
+ if (TYPE_SIZE (type))
+ {
+ dfs_walk (TYPE_BINFO (type), add_conversions, unmarkedp);
+ dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp);
+ }
return conversions;
}
+
+/* Subroutine of get_template_base. */
+
+static tree
+get_template_base_recursive (binfo, rval, template, via_virtual)
+ tree binfo, template, rval;
+ int via_virtual;
+{
+ tree binfos;
+ int i, n_baselinks;
+ tree type = BINFO_TYPE (binfo);
+
+ if (CLASSTYPE_TEMPLATE_INFO (type)
+ && CLASSTYPE_TI_TEMPLATE (type) == template)
+ {
+ if (rval == NULL_TREE || rval == type)
+ return type;
+ else
+ return error_mark_node;
+ }
+
+ binfos = BINFO_BASETYPES (binfo);
+ n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+ /* Process base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+ /* Find any specific instance of a virtual base, when searching with
+ a binfo... */
+ if (BINFO_MARKED (base_binfo) == 0)
+ {
+ int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
+
+ /* When searching for a non-virtual, we cannot mark
+ virtually found binfos. */
+ if (! this_virtual)
+ SET_BINFO_MARKED (base_binfo);
+
+ rval = get_template_base_recursive
+ (base_binfo, rval, template, this_virtual);
+ if (rval == error_mark_node)
+ return rval;
+ }
+ }
+
+ return rval;
+}
+
+/* Given a class template TEMPLATE and a class type or binfo node BINFO,
+ find the unique base type in BINFO that is an instance of TEMPLATE.
+ If there are more than one, return error_mark_node. Used by unify. */
+
+tree
+get_template_base (template, binfo)
+ register tree template, binfo;
+{
+ tree type = NULL_TREE, rval;
+
+ if (TREE_CODE (binfo) == TREE_VEC)
+ type = BINFO_TYPE (binfo);
+ else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
+ {
+ type = complete_type (binfo);
+ binfo = TYPE_BINFO (type);
+ }
+ else
+ my_friendly_abort (92);
+
+ if (CLASSTYPE_TEMPLATE_INFO (type)
+ && CLASSTYPE_TI_TEMPLATE (type) == template)
+ return type;
+
+ rval = get_template_base_recursive (binfo, NULL_TREE, template, 0);
+ dfs_walk (binfo, dfs_unmark, markedp);
+
+ return rval;
+}
+
+/* Check whether the empty class indicated by EMPTY_BINFO is also present
+ at offset 0 in COMPARE_TYPE, and set found_overlap if so. */
+
+static tree compare_type;
+static int found_overlap;
+static void
+dfs_check_overlap (empty_binfo)
+ tree empty_binfo;
+{
+ tree binfo;
+ for (binfo = TYPE_BINFO (compare_type); ; binfo = BINFO_BASETYPE (binfo, 0))
+ {
+ if (BINFO_TYPE (binfo) == BINFO_TYPE (empty_binfo))
+ {
+ found_overlap = 1;
+ break;
+ }
+ else if (BINFO_BASETYPES (binfo) == NULL_TREE)
+ break;
+ }
+}
+
+/* Trivial function to stop base traversal when we find something. */
+
+static int
+dfs_no_overlap_yet (t)
+ tree t ATTRIBUTE_UNUSED;
+{
+ return found_overlap == 0;
+}
+
+/* Returns nonzero if EMPTY_TYPE or any of its bases can also be found at
+ offset 0 in NEXT_TYPE. Used in laying out empty base class subobjects. */
+
+int
+types_overlap_p (empty_type, next_type)
+ tree empty_type, next_type;
+{
+ if (! IS_AGGR_TYPE (next_type))
+ return 0;
+ compare_type = next_type;
+ found_overlap = 0;
+ dfs_walk (TYPE_BINFO (empty_type), dfs_check_overlap, dfs_no_overlap_yet);
+ return found_overlap;
+}
diff --git a/contrib/gcc/cp/semantics.c b/contrib/gcc/cp/semantics.c
new file mode 100644
index 0000000..5068512
--- /dev/null
+++ b/contrib/gcc/cp/semantics.c
@@ -0,0 +1,1393 @@
+/* Perform the semantic phase of parsing, i.e., the process of
+ building tree structure, checking semantic consistency, and
+ building RTL. These routines are used both during actual parsing
+ and during the instantiation of template functions.
+
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Written by Mark Mitchell (mmitchell@usa.net) based on code found
+ formerly in parse.y and pt.c.
+
+ This file is part of GNU CC.
+
+ GNU CC 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, or (at your option)
+ any later version.
+
+ GNU CC 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 GNU CC; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "except.h"
+#include "lex.h"
+#include "toplev.h"
+
+/* There routines provide a modular interface to perform many parsing
+ operations. They may therefore be used during actual parsing, or
+ during template instantiation, which may be regarded as a
+ degenerate form of parsing. Since the current g++ parser is
+ lacking in several respects, and will be reimplemented, we are
+ attempting to move most code that is not directly related to
+ parsing into this file; that will make implementing the new parser
+ much easier since it will be able to make use of these routines. */
+
+/* When parsing a template, LAST_TREE contains the last statement
+ parsed. These are chained together through the TREE_CHAIN field,
+ but often need to be re-organized since the parse is performed
+ bottom-up. This macro makes LAST_TREE the indicated SUBSTMT of
+ STMT. */
+
+#define RECHAIN_STMTS(stmt, substmt, last) \
+ do { \
+ substmt = last; \
+ TREE_CHAIN (stmt) = NULL_TREE; \
+ last_tree = stmt; \
+ } while (0)
+
+#define RECHAIN_STMTS_FROM_LAST(stmt, substmt) \
+ RECHAIN_STMTS (stmt, substmt, last_tree)
+
+#define RECHAIN_STMTS_FROM_CHAIN(stmt, substmt) \
+ RECHAIN_STMTS (stmt, substmt, TREE_CHAIN (stmt))
+
+/* Finish an expression-statement, whose EXPRESSION is as indicated. */
+
+void
+finish_expr_stmt (expr)
+ tree expr;
+{
+ if (expr != NULL_TREE)
+ {
+ if (!processing_template_decl)
+ {
+ emit_line_note (input_filename, lineno);
+ /* Do default conversion if safe and possibly important,
+ in case within ({...}). */
+ if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+ && lvalue_p (expr))
+ || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
+ expr = default_conversion (expr);
+ }
+
+ cplus_expand_expr_stmt (expr);
+ clear_momentary ();
+ }
+
+ finish_stmt ();
+}
+
+/* Begin an if-statement. Returns a newly created IF_STMT if
+ appropriate. */
+
+tree
+begin_if_stmt ()
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ r = NULL_TREE;
+
+ do_pushlevel ();
+
+ return r;
+}
+
+/* Process the COND of an if-statement, which may be given by
+ IF_STMT. */
+
+void
+finish_if_stmt_cond (cond, if_stmt)
+ tree cond;
+ tree if_stmt;
+{
+ if (processing_template_decl)
+ {
+ if (last_tree != if_stmt)
+ RECHAIN_STMTS_FROM_LAST (if_stmt, IF_COND (if_stmt));
+ else
+ IF_COND (if_stmt) = cond;
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ expand_start_cond (condition_conversion (cond), 0);
+ }
+}
+
+/* Finish the then-clause of an if-statement, which may be given by
+ IF_STMT. */
+
+tree
+finish_then_clause (if_stmt)
+ tree if_stmt;
+{
+ if (processing_template_decl)
+ {
+ RECHAIN_STMTS_FROM_CHAIN (if_stmt,
+ THEN_CLAUSE (if_stmt));
+ last_tree = if_stmt;
+ return if_stmt;
+ }
+ else
+ return NULL_TREE;
+}
+
+/* Begin the else-clause of an if-statement. */
+
+void
+begin_else_clause ()
+{
+ if (!processing_template_decl)
+ expand_start_else ();
+}
+
+/* Finish the else-clause of an if-statement, which may be given by
+ IF_STMT. */
+
+void
+finish_else_clause (if_stmt)
+ tree if_stmt;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (if_stmt, ELSE_CLAUSE (if_stmt));
+}
+
+/* Finsh an if-statement. */
+
+void
+finish_if_stmt ()
+{
+ if (!processing_template_decl)
+ expand_end_cond ();
+
+ do_poplevel ();
+ finish_stmt ();
+}
+
+/* Begin a while-statement. Returns a newly created WHILE_STMT if
+ appropriate. */
+
+tree
+begin_while_stmt ()
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (WHILE_STMT, NULL_TREE, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ {
+ emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop (1);
+ r = NULL_TREE;
+ }
+
+ do_pushlevel ();
+
+ return r;
+}
+
+/* Process the COND of an if-statement, which may be given by
+ WHILE_STMT. */
+
+void
+finish_while_stmt_cond (cond, while_stmt)
+ tree cond;
+ tree while_stmt;
+{
+ if (processing_template_decl)
+ {
+ if (last_tree != while_stmt)
+ RECHAIN_STMTS_FROM_LAST (while_stmt,
+ WHILE_COND (while_stmt));
+ else
+ TREE_OPERAND (while_stmt, 0) = cond;
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (0, condition_conversion (cond));
+ }
+
+ /* If COND wasn't a declaration, clear out the
+ block we made for it and start a new one here so the
+ optimization in expand_end_loop will work. */
+ if (getdecls () == NULL_TREE)
+ {
+ do_poplevel ();
+ do_pushlevel ();
+ }
+}
+
+/* Finish a while-statement, which may be given by WHILE_STMT. */
+
+void
+finish_while_stmt (while_stmt)
+ tree while_stmt;
+{
+ do_poplevel ();
+
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (while_stmt, WHILE_BODY (while_stmt));
+ else
+ expand_end_loop ();
+ finish_stmt ();
+}
+
+/* Begin a do-statement. Returns a newly created DO_STMT if
+ appropriate. */
+
+tree
+begin_do_stmt ()
+{
+ if (processing_template_decl)
+ {
+ tree r = build_min_nt (DO_STMT, NULL_TREE, NULL_TREE);
+ add_tree (r);
+ return r;
+ }
+ else
+ {
+ emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop_continue_elsewhere (1);
+ return NULL_TREE;
+ }
+}
+
+/* Finish the body of a do-statement, which may be given by DO_STMT. */
+
+void
+finish_do_body (do_stmt)
+ tree do_stmt;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (do_stmt, DO_BODY (do_stmt));
+ else
+ expand_loop_continue_here ();
+}
+
+/* Finish a do-statement, which may be given by DO_STMT, and whose
+ COND is as indicated. */
+
+void
+finish_do_stmt (cond, do_stmt)
+ tree cond;
+ tree do_stmt;
+{
+ if (processing_template_decl)
+ DO_COND (do_stmt) = cond;
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ expand_exit_loop_if_false (0, condition_conversion (cond));
+ expand_end_loop ();
+ }
+
+ clear_momentary ();
+ finish_stmt ();
+}
+
+/* Finish a return-statement. The EXPRESSION returned, if any, is as
+ indicated. */
+
+void
+finish_return_stmt (expr)
+ tree expr;
+{
+ emit_line_note (input_filename, lineno);
+ c_expand_return (expr);
+ finish_stmt ();
+}
+
+/* Begin a for-statement. Returns a new FOR_STMT if appropriate. */
+
+tree
+begin_for_stmt ()
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (FOR_STMT, NULL_TREE, NULL_TREE,
+ NULL_TREE, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ r = NULL_TREE;
+
+ if (flag_new_for_scope > 0)
+ {
+ do_pushlevel ();
+ note_level_for_for ();
+ }
+
+ return r;
+}
+
+/* Finish the for-init-statement of a for-statement, which may be
+ given by FOR_STMT. */
+
+void
+finish_for_init_stmt (for_stmt)
+ tree for_stmt;
+{
+ if (processing_template_decl)
+ {
+ if (last_tree != for_stmt)
+ RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_INIT_STMT (for_stmt));
+ }
+ else
+ {
+ emit_nop ();
+ emit_line_note (input_filename, lineno);
+ expand_start_loop_continue_elsewhere (1);
+ }
+
+ do_pushlevel ();
+}
+
+/* Finish the COND of a for-statement, which may be given by
+ FOR_STMT. */
+
+void
+finish_for_cond (cond, for_stmt)
+ tree cond;
+ tree for_stmt;
+{
+ if (processing_template_decl)
+ {
+ if (last_tree != for_stmt)
+ RECHAIN_STMTS_FROM_LAST (for_stmt, FOR_COND (for_stmt));
+ else
+ FOR_COND (for_stmt) = cond;
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ if (cond)
+ expand_exit_loop_if_false (0, condition_conversion (cond));
+ }
+
+ /* If the cond wasn't a declaration, clear out the
+ block we made for it and start a new one here so the
+ optimization in expand_end_loop will work. */
+ if (getdecls () == NULL_TREE)
+ {
+ do_poplevel ();
+ do_pushlevel ();
+ }
+}
+
+/* Finish the increment-EXPRESSION in a for-statement, which may be
+ given by FOR_STMT. */
+
+void
+finish_for_expr (expr, for_stmt)
+ tree expr;
+ tree for_stmt;
+{
+ if (processing_template_decl)
+ FOR_EXPR (for_stmt) = expr;
+
+ /* Don't let the tree nodes for EXPR be discarded
+ by clear_momentary during the parsing of the next stmt. */
+ push_momentary ();
+}
+
+/* Finish the body of a for-statement, which may be given by
+ FOR_STMT. The increment-EXPR for the loop must be
+ provided. */
+
+void
+finish_for_stmt (expr, for_stmt)
+ tree expr;
+ tree for_stmt;
+{
+ /* Pop the scope for the body of the loop. */
+ do_poplevel ();
+
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (for_stmt, FOR_BODY (for_stmt));
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ expand_loop_continue_here ();
+ if (expr)
+ cplus_expand_expr_stmt (expr);
+ expand_end_loop ();
+ }
+
+ pop_momentary ();
+
+ if (flag_new_for_scope > 0)
+ do_poplevel ();
+
+ finish_stmt ();
+}
+
+/* Finish a break-statement. */
+
+void
+finish_break_stmt ()
+{
+ emit_line_note (input_filename, lineno);
+ if (processing_template_decl)
+ add_tree (build_min_nt (BREAK_STMT));
+ else if ( ! expand_exit_something ())
+ cp_error ("break statement not within loop or switch");
+}
+
+/* Finish a continue-statement. */
+
+void
+finish_continue_stmt ()
+{
+ emit_line_note (input_filename, lineno);
+ if (processing_template_decl)
+ add_tree (build_min_nt (CONTINUE_STMT));
+ else if (! expand_continue_loop (0))
+ cp_error ("continue statement not within a loop");
+}
+
+/* Begin a switch-statement. */
+
+void
+begin_switch_stmt ()
+{
+ do_pushlevel ();
+}
+
+/* Finish the cond of a switch-statement. Returns a new
+ SWITCH_STMT if appropriate. */
+
+tree
+finish_switch_cond (cond)
+ tree cond;
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (SWITCH_STMT, cond, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ c_expand_start_case (cond);
+ r = NULL_TREE;
+ }
+ push_switch ();
+
+ /* Don't let the tree nodes for COND be discarded by
+ clear_momentary during the parsing of the next stmt. */
+ push_momentary ();
+
+ return r;
+}
+
+/* Finish the body of a switch-statement, which may be given by
+ SWITCH_STMT. The COND to switch on is indicated. */
+
+void
+finish_switch_stmt (cond, switch_stmt)
+ tree cond;
+ tree switch_stmt;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (switch_stmt, SWITCH_BODY (switch_stmt));
+ else
+ expand_end_case (cond);
+ pop_momentary ();
+ pop_switch ();
+ do_poplevel ();
+ finish_stmt ();
+}
+
+/* Finish a case-label. */
+
+void
+finish_case_label (low_value, high_value)
+ tree low_value;
+ tree high_value;
+{
+ do_case (low_value, high_value);
+}
+
+
+/* Finish a goto-statement. */
+
+void
+finish_goto_stmt (destination)
+ tree destination;
+{
+ if (processing_template_decl)
+ add_tree (build_min_nt (GOTO_STMT, destination));
+ else
+ {
+ emit_line_note (input_filename, lineno);
+
+ if (TREE_CODE (destination) == IDENTIFIER_NODE)
+ {
+ tree decl = lookup_label (destination);
+ TREE_USED (decl) = 1;
+ expand_goto (decl);
+ }
+ else
+ expand_computed_goto (destination);
+ }
+}
+
+/* Begin a try-block. Returns a newly-created TRY_BLOCK if
+ appropriate. */
+
+tree
+begin_try_block ()
+{
+ if (processing_template_decl)
+ {
+ tree r = build_min_nt (TRY_BLOCK, NULL_TREE,
+ NULL_TREE);
+ add_tree (r);
+ return r;
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ expand_start_try_stmts ();
+ return NULL_TREE;
+ }
+}
+
+/* Finish a try-block, which may be given by TRY_BLOCK. */
+
+void
+finish_try_block (try_block)
+ tree try_block;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_LAST (try_block, TRY_STMTS (try_block));
+ else
+ {
+ expand_start_all_catch ();
+ }
+}
+
+/* Finish a handler-sequence for a try-block, which may be given by
+ TRY_BLOCK. */
+
+void
+finish_handler_sequence (try_block)
+ tree try_block;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
+ else
+ {
+ expand_end_all_catch ();
+ }
+}
+
+/* Begin a handler. Returns a HANDLER if appropriate. */
+
+tree
+begin_handler ()
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (HANDLER, NULL_TREE, NULL_TREE);
+ add_tree (r);
+ }
+ else
+ r = NULL_TREE;
+
+ do_pushlevel ();
+
+ return r;
+}
+
+/* Finish the handler-parameters for a handler, which may be given by
+ HANDLER. */
+
+void
+finish_handler_parms (handler)
+ tree handler;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_PARMS (handler));
+}
+
+/* Finish a handler, which may be given by HANDLER. */
+
+void
+finish_handler (handler)
+ tree handler;
+{
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (handler, HANDLER_BODY (handler));
+ else
+ expand_end_catch_block ();
+
+ do_poplevel ();
+}
+
+/* Begin a compound-statement. If HAS_NO_SCOPE is non-zero, the
+ compound-statement does not define a scope. Returns a new
+ COMPOUND_STMT if appropriate. */
+
+tree
+begin_compound_stmt (has_no_scope)
+ int has_no_scope;
+{
+ tree r;
+
+ if (processing_template_decl)
+ {
+ r = build_min_nt (COMPOUND_STMT, NULL_TREE);
+ add_tree (r);
+ if (has_no_scope)
+ COMPOUND_STMT_NO_SCOPE (r) = 1;
+ }
+ else
+ r = NULL_TREE;
+
+ if (!has_no_scope)
+ do_pushlevel ();
+
+ return r;
+}
+
+
+/* Finish a compound-statement, which may be given by COMPOUND_STMT.
+ If HAS_NO_SCOPE is non-zero, the compound statement does not define
+ a scope. */
+
+tree
+finish_compound_stmt (has_no_scope, compound_stmt)
+ int has_no_scope;
+ tree compound_stmt;
+{
+ tree r;
+
+ if (!has_no_scope)
+ r = do_poplevel ();
+ else
+ r = NULL_TREE;
+
+ if (processing_template_decl)
+ RECHAIN_STMTS_FROM_CHAIN (compound_stmt,
+ COMPOUND_BODY (compound_stmt));
+
+ finish_stmt ();
+
+ return r;
+}
+
+/* Finish an asm-statement, whose components are a CV_QUALIFIER, a
+ STRING, some OUTPUT_OPERANDS, some INPUT_OPERANDS, and some
+ CLOBBERS. */
+
+void
+finish_asm_stmt (cv_qualifier, string, output_operands,
+ input_operands, clobbers)
+ tree cv_qualifier;
+ tree string;
+ tree output_operands;
+ tree input_operands;
+ tree clobbers;
+{
+ if (TREE_CHAIN (string))
+ string = combine_strings (string);
+
+ if (processing_template_decl)
+ {
+ tree r = build_min_nt (ASM_STMT, cv_qualifier, string,
+ output_operands, input_operands,
+ clobbers);
+ add_tree (r);
+ }
+ else
+ {
+ emit_line_note (input_filename, lineno);
+ if (output_operands != NULL_TREE || input_operands != NULL_TREE
+ || clobbers != NULL_TREE)
+ {
+ if (cv_qualifier != NULL_TREE
+ && cv_qualifier != ridpointers[(int) RID_VOLATILE])
+ cp_warning ("%s qualifier ignored on asm",
+ IDENTIFIER_POINTER (cv_qualifier));
+
+ c_expand_asm_operands (string, output_operands,
+ input_operands,
+ clobbers,
+ cv_qualifier
+ == ridpointers[(int) RID_VOLATILE],
+ input_filename, lineno);
+ }
+ else
+ {
+ if (cv_qualifier != NULL_TREE)
+ cp_warning ("%s qualifier ignored on asm",
+ IDENTIFIER_POINTER (cv_qualifier));
+ expand_asm (string);
+ }
+
+ finish_stmt ();
+ }
+}
+
+/* Finish a parenthesized expression EXPR. */
+
+tree
+finish_parenthesized_expr (expr)
+ tree expr;
+{
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr))))
+ /* This inhibits warnings in truthvalue_conversion. */
+ C_SET_EXP_ORIGINAL_CODE (expr, ERROR_MARK);
+
+ return expr;
+}
+
+/* Begin a statement-expression. The value returned must be passed to
+ finish_stmt_expr. */
+
+tree
+begin_stmt_expr ()
+{
+ keep_next_level ();
+ /* If we're processing_template_decl, then the upcoming compound
+ statement will be chained onto the tree structure, starting at
+ last_tree. We return last_tree so that we can later unhook the
+ compound statement. */
+ return processing_template_decl ? last_tree : expand_start_stmt_expr();
+}
+
+/* Finish a statement-expression. RTL_EXPR should be the value
+ returned by the previous begin_stmt_expr; EXPR is the
+ statement-expression. Returns an expression representing the
+ statement-expression. */
+
+tree
+finish_stmt_expr (rtl_expr, expr)
+ tree rtl_expr;
+ tree expr;
+{
+ tree result;
+
+ if (!processing_template_decl)
+ {
+ rtl_expr = expand_end_stmt_expr (rtl_expr);
+ /* The statements have side effects, so the group does. */
+ TREE_SIDE_EFFECTS (rtl_expr) = 1;
+ }
+
+ if (TREE_CODE (expr) == BLOCK)
+ {
+ /* Make a BIND_EXPR for the BLOCK already made. */
+ if (processing_template_decl)
+ result = build (BIND_EXPR, NULL_TREE,
+ NULL_TREE, last_tree, expr);
+ else
+ result = build (BIND_EXPR, TREE_TYPE (rtl_expr),
+ NULL_TREE, rtl_expr, expr);
+
+ /* Remove the block from the tree at this point.
+ It gets put back at the proper place
+ when the BIND_EXPR is expanded. */
+ delete_block (expr);
+ }
+ else
+ result = expr;
+
+ if (processing_template_decl)
+ {
+ /* Remove the compound statement from the tree structure; it is
+ now saved in the BIND_EXPR. */
+ last_tree = rtl_expr;
+ TREE_CHAIN (last_tree) = NULL_TREE;
+ }
+
+ return result;
+}
+
+/* Finish a call to FN with ARGS. Returns a representation of the
+ call. */
+
+tree
+finish_call_expr (fn, args, koenig)
+ tree fn;
+ tree args;
+ int koenig;
+{
+ tree result;
+
+ if (koenig)
+ {
+ if (TREE_CODE (fn) == BIT_NOT_EXPR)
+ fn = build_x_unary_op (BIT_NOT_EXPR, TREE_OPERAND (fn, 0));
+ else if (TREE_CODE (fn) != TEMPLATE_ID_EXPR)
+ fn = do_identifier (fn, 2, args);
+ }
+ result = build_x_function_call (fn, args, current_class_ref);
+
+ if (TREE_CODE (result) == CALL_EXPR
+ && TREE_TYPE (result) != void_type_node)
+ result = require_complete_type (result);
+
+ return result;
+}
+
+/* Finish a call to a postfix increment or decrement or EXPR. (Which
+ is indicated by CODE, which should be POSTINCREMENT_EXPR or
+ POSTDECREMENT_EXPR.) */
+
+tree
+finish_increment_expr (expr, code)
+ tree expr;
+ enum tree_code code;
+{
+ /* If we get an OFFSET_REF, turn it into what it really means (e.g.,
+ a COMPONENT_REF). This way if we've got, say, a reference to a
+ static member that's being operated on, we don't end up trying to
+ find a member operator for the class it's in. */
+
+ if (TREE_CODE (expr) == OFFSET_REF)
+ expr = resolve_offset_ref (expr);
+ return build_x_unary_op (code, expr);
+}
+
+/* Finish a use of `this'. Returns an expression for `this'. */
+
+tree
+finish_this_expr ()
+{
+ tree result;
+
+ if (current_class_ptr)
+ {
+#ifdef WARNING_ABOUT_CCD
+ TREE_USED (current_class_ptr) = 1;
+#endif
+ result = current_class_ptr;
+ }
+ else if (current_function_decl
+ && DECL_STATIC_FUNCTION_P (current_function_decl))
+ {
+ error ("`this' is unavailable for static member functions");
+ result = error_mark_node;
+ }
+ else
+ {
+ if (current_function_decl)
+ error ("invalid use of `this' in non-member function");
+ else
+ error ("invalid use of `this' at top level");
+ result = error_mark_node;
+ }
+
+ return result;
+}
+
+/* Finish a member function call using OBJECT and ARGS as arguments to
+ FN. Returns an expression for the call. */
+
+tree
+finish_object_call_expr (fn, object, args)
+ tree fn;
+ tree object;
+ tree args;
+{
+#if 0
+ /* This is a future direction of this code, but because
+ build_x_function_call cannot always undo what is done in
+ build_component_ref entirely yet, we cannot do this. */
+
+ tree real_fn = build_component_ref (object, fn, NULL_TREE, 1);
+ return finish_call_expr (real_fn, args);
+#else
+ if (TREE_CODE (fn) == TYPE_DECL)
+ {
+ if (processing_template_decl)
+ /* This can happen on code like:
+
+ class X;
+ template <class T> void f(T t) {
+ t.X();
+ }
+
+ We just grab the underlying IDENTIFIER. */
+ fn = DECL_NAME (fn);
+ else
+ {
+ cp_error ("calling type `%T' like a method", fn);
+ return error_mark_node;
+ }
+ }
+
+ return build_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL);
+#endif
+}
+
+/* Finish a qualified member function call using OBJECT and ARGS as
+ arguments to FN. Returns an expressino for the call. */
+
+tree
+finish_qualified_object_call_expr (fn, object, args)
+ tree fn;
+ tree object;
+ tree args;
+{
+ if (IS_SIGNATURE (TREE_OPERAND (fn, 0)))
+ {
+ warning ("signature name in scope resolution ignored");
+ return finish_object_call_expr (TREE_OPERAND (fn, 1), object, args);
+ }
+ else
+ return build_scoped_method_call (object, TREE_OPERAND (fn, 0),
+ TREE_OPERAND (fn, 1), args);
+}
+
+/* Finish a pseudo-destructor call expression of OBJECT, with SCOPE
+ being the scope, if any, of DESTRUCTOR. Returns an expression for
+ the call. */
+
+tree
+finish_pseudo_destructor_call_expr (object, scope, destructor)
+ tree object;
+ tree scope;
+ tree destructor;
+{
+ if (scope && scope != destructor)
+ cp_error ("destructor specifier `%T::~%T()' must have matching names",
+ scope, destructor);
+
+ if ((scope == NULL_TREE || IDENTIFIER_GLOBAL_VALUE (destructor))
+ && (TREE_CODE (TREE_TYPE (object)) !=
+ TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (destructor)))))
+ cp_error ("`%E' is not of type `%T'", object, destructor);
+
+ return cp_convert (void_type_node, object);
+}
+
+/* Finish a call to a globally qualified member function FN using
+ ARGS. Returns an expression for the call. */
+
+tree
+finish_globally_qualified_member_call_expr (fn, args)
+ tree fn;
+ tree args;
+{
+ if (processing_template_decl)
+ return build_min_nt (CALL_EXPR, copy_to_permanent (fn), args,
+ NULL_TREE);
+ else
+ return build_member_call (TREE_OPERAND (fn, 0),
+ TREE_OPERAND (fn, 1),
+ args);
+}
+
+/* Finish an expression taking the address of LABEL. Returns an
+ expression for the address. */
+
+tree
+finish_label_address_expr (label)
+ tree label;
+{
+ tree result;
+
+ label = lookup_label (label);
+ if (label == NULL_TREE)
+ result = null_pointer_node;
+ else
+ {
+ TREE_USED (label) = 1;
+ result = build1 (ADDR_EXPR, ptr_type_node, label);
+ TREE_CONSTANT (result) = 1;
+ }
+
+ return result;
+}
+
+/* Finish an expression of the form CODE EXPR. */
+
+tree
+finish_unary_op_expr (code, expr)
+ enum tree_code code;
+ tree expr;
+{
+ tree result = build_x_unary_op (code, expr);
+ if (code == NEGATE_EXPR && TREE_CODE (expr) == INTEGER_CST)
+ TREE_NEGATED_INT (result) = 1;
+ overflow_warning (result);
+ return result;
+}
+
+/* Finish an id-expression. */
+
+tree
+finish_id_expr (expr)
+ tree expr;
+{
+ if (TREE_CODE (expr) == IDENTIFIER_NODE)
+ expr = do_identifier (expr, 1, NULL_TREE);
+
+ return expr;
+}
+
+/* Begin a new-placement. */
+
+int
+begin_new_placement ()
+{
+ /* The arguments to a placement new might be passed to a
+ deallocation function, in the event that the allocation throws an
+ exception. Since we don't expand exception handlers until the
+ end of a function, we must make sure the arguments stay around
+ that long. */
+ return suspend_momentary ();
+}
+
+/* Finish a new-placement. The ARGS are the placement arguments. The
+ COOKIE is the value returned by the previous call to
+ begin_new_placement. */
+
+tree
+finish_new_placement (args, cookie)
+ tree args;
+ int cookie;
+{
+ resume_momentary (cookie);
+ return args;
+}
+
+/* Begin a function defniition declared with DECL_SPECS and
+ DECLARATOR. Returns non-zero if the function-declaration is
+ legal. */
+
+int
+begin_function_definition (decl_specs, declarator)
+ tree decl_specs;
+ tree declarator;
+{
+ tree specs;
+ tree attrs;
+ split_specs_attrs (decl_specs, &specs, &attrs);
+ if (!start_function (specs, declarator, attrs, 0))
+ return 0;
+
+ reinit_parse_for_function ();
+ return 1;
+}
+
+/* Begin a constructor declarator of the form `SCOPE::NAME'. Returns
+ a SCOPE_REF. */
+
+tree
+begin_constructor_declarator (scope, name)
+ tree scope;
+ tree name;
+{
+ tree result = build_parse_node (SCOPE_REF, scope, name);
+
+ if (scope != current_class_type)
+ {
+ push_nested_class (scope, 3);
+ TREE_COMPLEXITY (result) = current_class_depth;
+ }
+
+ return result;
+}
+
+/* Finish an init-declarator. Returns a DECL. */
+
+tree
+finish_declarator (declarator, declspecs, attributes,
+ prefix_attributes, initialized)
+ tree declarator;
+ tree declspecs;
+ tree attributes;
+ tree prefix_attributes;
+ int initialized;
+{
+ return start_decl (declarator, declspecs, initialized, attributes,
+ prefix_attributes);
+}
+
+/* Finish a translation unit. */
+
+void
+finish_translation_unit ()
+{
+ /* In case there were missing closebraces,
+ get us back to the global binding level. */
+ while (! toplevel_bindings_p ())
+ poplevel (0, 0, 0);
+ while (current_namespace != global_namespace)
+ pop_namespace ();
+ finish_file ();
+}
+
+/* Finish a template type parameter, specified as AGGR IDENTIFIER.
+ Returns the parameter. */
+
+tree
+finish_template_type_parm (aggr, identifier)
+ tree aggr;
+ tree identifier;
+{
+ if (aggr == signature_type_node)
+ sorry ("signature as template type parameter");
+ else if (aggr != class_type_node)
+ {
+ pedwarn ("template type parameters must use the keyword `class' or `typename'");
+ aggr = class_type_node;
+ }
+
+ return build_tree_list (aggr, identifier);
+}
+
+/* Finish a template template parameter, specified as AGGR IDENTIFIER.
+ Returns the parameter. */
+
+tree
+finish_template_template_parm (aggr, identifier)
+ tree aggr;
+ tree identifier;
+{
+ tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE);
+ tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
+ DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
+ DECL_TEMPLATE_RESULT (tmpl) = decl;
+ SET_DECL_ARTIFICIAL (decl);
+ end_template_decl ();
+
+ return finish_template_type_parm (aggr, tmpl);
+}
+
+/* Finish a parameter list, indicated by PARMS. If ELLIPSIS is
+ non-zero, the parameter list was terminated by a `...'. */
+
+tree
+finish_parmlist (parms, ellipsis)
+ tree parms;
+ int ellipsis;
+{
+ if (!ellipsis)
+ chainon (parms, void_list_node);
+ /* We mark the PARMS as a parmlist so that declarator processing can
+ disambiguate certain constructs. */
+ if (parms != NULL_TREE)
+ TREE_PARMLIST (parms) = 1;
+
+ return parms;
+}
+
+/* Begin a class definition, as indicated by T. */
+
+tree
+begin_class_definition (t)
+ tree t;
+{
+ tree new_type = t;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ if (t == error_mark_node
+ || ! IS_AGGR_TYPE (t))
+ {
+ t = new_type = make_lang_type (RECORD_TYPE);
+ pushtag (make_anon_name (), t, 0);
+ }
+ if (TYPE_SIZE (t))
+ duplicate_tag_error (t);
+ if (TYPE_SIZE (t) || TYPE_BEING_DEFINED (t))
+ {
+ t = make_lang_type (TREE_CODE (t));
+ pushtag (TYPE_IDENTIFIER (t), t, 0);
+ new_type = t;
+ }
+ if (processing_template_decl && TYPE_CONTEXT (t)
+ && TREE_CODE (TYPE_CONTEXT (t)) != NAMESPACE_DECL
+ && ! current_class_type)
+ push_template_decl (TYPE_STUB_DECL (t));
+ pushclass (t, 0);
+ TYPE_BEING_DEFINED (t) = 1;
+ if (IS_AGGR_TYPE (t) && CLASSTYPE_USE_TEMPLATE (t))
+ {
+ if (CLASSTYPE_IMPLICIT_INSTANTIATION (t)
+ && TYPE_SIZE (t) == NULL_TREE)
+ {
+ SET_CLASSTYPE_TEMPLATE_SPECIALIZATION (t);
+ if (processing_template_decl)
+ push_template_decl (TYPE_MAIN_DECL (t));
+ }
+ else if (CLASSTYPE_TEMPLATE_INSTANTIATION (t))
+ cp_error ("specialization after instantiation of `%T'", t);
+ }
+ /* Reset the interface data, at the earliest possible
+ moment, as it might have been set via a class foo;
+ before. */
+ /* Don't change signatures. */
+ if (! IS_SIGNATURE (t))
+ {
+ extern tree pending_vtables;
+ int needs_writing;
+ tree name = TYPE_IDENTIFIER (t);
+
+ if (! ANON_AGGRNAME_P (name))
+ {
+ CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
+ SET_CLASSTYPE_INTERFACE_UNKNOWN_X
+ (t, interface_unknown);
+ }
+
+ /* Record how to set the access of this class's
+ virtual functions. If write_virtuals == 2 or 3, then
+ inline virtuals are ``extern inline''. */
+ switch (write_virtuals)
+ {
+ case 0:
+ case 1:
+ needs_writing = 1;
+ break;
+ case 2:
+ needs_writing = !! value_member (name, pending_vtables);
+ break;
+ case 3:
+ needs_writing = ! CLASSTYPE_INTERFACE_ONLY (t)
+ && CLASSTYPE_INTERFACE_KNOWN (t);
+ break;
+ default:
+ needs_writing = 0;
+ }
+ CLASSTYPE_VTABLE_NEEDS_WRITING (t) = needs_writing;
+ }
+#if 0
+ t = TYPE_IDENTIFIER ($<ttype>0);
+ if (t && IDENTIFIER_TEMPLATE (t))
+ overload_template_name (t, 1);
+#endif
+ reset_specialization();
+
+ /* In case this is a local class within a template
+ function, we save the current tree structure so
+ that we can get it back later. */
+ begin_tree ();
+
+ return new_type;
+}
+
+/* Finish a class definition T, with the indicated COMPONENTS, and
+ with the indicate ATTRIBUTES. If SEMI, the definition is
+ immediately followed by a semicolon. Returns the type. */
+
+tree
+finish_class_definition (t, components, attributes, semi)
+ tree t;
+ tree components;
+ tree attributes;
+ int semi;
+{
+#if 0
+ /* Need to rework class nesting in the presence of nested classes,
+ etc. */
+ shadow_tag (CLASSTYPE_AS_LIST (t)); */
+#endif
+
+ /* finish_struct nukes this anyway; if finish_exception does too,
+ then it can go. */
+ if (semi)
+ note_got_semicolon (t);
+
+ /* If we got any attributes in class_head, xref_tag will stick them in
+ TREE_TYPE of the type. Grab them now. */
+ attributes = chainon (TREE_TYPE (t), attributes);
+ TREE_TYPE (t) = NULL_TREE;
+
+ if (TREE_CODE (t) == ENUMERAL_TYPE)
+ ;
+ else
+ {
+ t = finish_struct (t, components, attributes, semi);
+ if (semi)
+ note_got_semicolon (t);
+ }
+
+ pop_obstacks ();
+
+ if (! semi)
+ check_for_missing_semicolon (t);
+ if (current_scope () == current_function_decl)
+ do_pending_defargs ();
+
+ return t;
+}
+
+/* Finish processing the default argument expressions cached during
+ the processing of a class definition. */
+
+void
+finish_default_args ()
+{
+ if (pending_inlines
+ && current_scope () == current_function_decl)
+ do_pending_inlines ();
+}
+
+/* Finish processing the inline function definitions cached during the
+ processing of a class definition. */
+
+void
+begin_inline_definitions ()
+{
+ if (current_class_type == NULL_TREE)
+ clear_inline_text_obstack ();
+
+ /* Undo the begin_tree in begin_class_definition. */
+ end_tree ();
+}
+
+/* Finish processing the declaration of a member class template
+ TYPES whose template parameters are given by PARMS. */
+
+tree
+finish_member_class_template (parms, types)
+ tree parms;
+ tree types;
+{
+ note_list_got_semicolon (types);
+ grok_x_components (types, NULL_TREE);
+ if (TYPE_CONTEXT (TREE_VALUE (types)) != current_class_type)
+ /* The component was in fact a friend declaration. We avoid
+ finish_member_template_decl performing certain checks by
+ unsetting TYPES. */
+ types = NULL_TREE;
+ finish_member_template_decl (parms, types);
+ /* As with other component type declarations, we do
+ not store the new DECL on the list of
+ component_decls. */
+ return NULL_TREE;
+}
diff --git a/contrib/gcc/cp/sig.c b/contrib/gcc/cp/sig.c
index 135dc6d..65350db 100644
--- a/contrib/gcc/cp/sig.c
+++ b/contrib/gcc/cp/sig.c
@@ -1,5 +1,5 @@
/* Functions dealing with signatures and signature pointers/references.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 1996 Free Software Foundation, Inc.
Contributed by Gerald Baumgartner (gb@cs.purdue.edu)
This file is part of GNU CC.
@@ -21,21 +21,34 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "obstack.h"
#include "tree.h"
#include "cp-tree.h"
#include "flags.h"
#include "assert.h"
+#include "toplev.h"
extern struct obstack *current_obstack;
extern struct obstack permanent_obstack;
extern struct obstack *saveable_obstack;
-extern void error ();
-extern void sorry ();
extern void compiler_error ();
-extern void make_decl_rtl PROTO((tree, char *, int));
+
+static tree save_this PROTO((tree));
+static tree build_sptr_ref PROTO((tree));
+static tree build_member_function_pointer PROTO((tree));
+static void undo_casts PROTO((tree));
+static tree build_signature_pointer_or_reference_name
+ PROTO((tree, int, int, int));
+static void build_signature_pointer_or_reference_decl
+ PROTO((tree, tree));
+static tree build_signature_pointer_or_reference_type
+ PROTO((tree, int, int, int));
+static tree get_sigtable_name PROTO((tree, tree));
+static tree build_signature_table_constructor PROTO((tree, tree));
+static int match_method_types PROTO((tree, tree));
+static tree build_sigtable PROTO((tree, tree, tree));
/* Used to help generate globally unique names for signature tables. */
@@ -153,8 +166,7 @@ build_signature_pointer_or_reference_type (to_type, constp, volatilep, refp)
const s * sptr;
};
- Similarly, for `volatile' and `const volatile'.
- */
+ Similarly, for `volatile' and `const volatile'. */
t = make_lang_type (RECORD_TYPE);
{
@@ -185,7 +197,10 @@ build_signature_pointer_or_reference_type (to_type, constp, volatilep, refp)
TREE_CHAIN (optr) = sptr;
TYPE_FIELDS (t) = optr;
- TYPE_ALIGN (t) = TYPE_ALIGN (optr_type);
+ /* Allow signature pointers/references to be grabbed 2 words at a time.
+ For this to work on a Sparc, we need 8-byte alignment. */
+ TYPE_ALIGN (t) = MAX (TYPE_ALIGN (double_type_node),
+ TYPE_ALIGN (optr_type));
/* A signature pointer/reference type isn't a `real' class type. */
IS_AGGR_TYPE (t) = 0;
@@ -336,7 +351,7 @@ append_signature_fields (list_of_fieldlists)
tree l, x;
tree last_x = NULL_TREE;
tree mfptr;
- tree last_mfptr;
+ tree last_mfptr = NULL_TREE;
tree mfptr_list = NULL_TREE;
/* For signatures it should actually be only a list with one element. */
@@ -396,8 +411,8 @@ match_method_types (sig_mtype, class_mtype)
/* Compare the first argument `this.' */
{
/* Get the type of what the `optr' is pointing to. */
- tree sig_this =
- TREE_TYPE (TREE_TYPE (TYPE_FIELDS (TREE_VALUE (sig_arg_types))));
+ tree sig_this
+ = TREE_TYPE (TREE_TYPE (TYPE_FIELDS (TREE_VALUE (sig_arg_types))));
tree class_this = TREE_VALUE (class_arg_types);
if (TREE_CODE (class_this) == RECORD_TYPE) /* Is `this' a sig ptr? */
@@ -420,6 +435,7 @@ match_method_types (sig_mtype, class_mtype)
}
/* Undo casts of opaque type variables to the RHS types. */
+
static void
undo_casts (sig_ty)
tree sig_ty;
@@ -446,7 +462,7 @@ build_signature_table_constructor (sig_ty, rhs)
tree sig_field = TYPE_FIELDS (sig_ty);
tree result = NULL_TREE;
tree first_rhs_field = NULL_TREE;
- tree last_rhs_field;
+ tree last_rhs_field = NULL_TREE;
int sig_ptr_p = IS_SIGNATURE (rhstype);
int offset_p = sig_ptr_p;
@@ -516,25 +532,26 @@ build_signature_table_constructor (sig_ty, rhs)
else
{
/* Find the class method of the correct type. */
-
+ tree rhs_methods;
basetypes = TREE_PURPOSE (baselink);
if (TREE_CODE (basetypes) == TREE_LIST)
basetypes = TREE_VALUE (basetypes);
- rhs_method = TREE_VALUE (baselink);
- for (; rhs_method; rhs_method = TREE_CHAIN (rhs_method))
- if (sig_mname == DECL_NAME (rhs_method)
+ rhs_methods = TREE_VALUE (baselink);
+ for (; rhs_methods; rhs_methods = OVL_NEXT (rhs_methods))
+ if ((rhs_method = OVL_CURRENT (rhs_methods))
+ && sig_mname == DECL_NAME (rhs_method)
&& ! DECL_STATIC_FUNCTION_P (rhs_method)
&& match_method_types (sig_mtype, TREE_TYPE (rhs_method)))
break;
- if (rhs_method == NULL_TREE
+ if (rhs_methods == NULL_TREE
|| (compute_access (basetypes, rhs_method)
- != access_public))
+ != access_public_node))
{
error ("class `%s' does not contain a method conforming to `%s'",
TYPE_NAME_STRING (rhstype),
- fndecl_as_string (NULL, sig_method, 1));
+ fndecl_as_string (sig_method, 1));
undo_casts (sig_ty);
return error_mark_node;
}
@@ -559,7 +576,7 @@ build_signature_table_constructor (sig_ty, rhs)
}
else
{
- tree tag, vb_off, delta, index, pfn, vt_off;
+ tree tag, vb_off, delta, idx, pfn = NULL_TREE, vt_off = NULL_TREE;
tree tag_decl, vb_off_decl, delta_decl, index_decl;
tree pfn_decl, vt_off_decl;
@@ -569,8 +586,9 @@ build_signature_table_constructor (sig_ty, rhs)
tag = build_unary_op (NEGATE_EXPR, integer_one_node, 0);
vb_off = build_unary_op (NEGATE_EXPR, integer_one_node, 0);
delta = integer_zero_node;
- index = integer_zero_node;
- pfn = build_unary_op (ADDR_EXPR, rhs_method, 0);
+ idx = integer_zero_node;
+ pfn = build_addr_func (rhs_method);
+ TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (rhs_method)) = 1;
TREE_TYPE (pfn) = ptr_type_node;
TREE_ADDRESSABLE (rhs_method) = 1;
offset_p = 0; /* we can't offset the rhs sig table */
@@ -580,9 +598,13 @@ build_signature_table_constructor (sig_ty, rhs)
/* virtual member function */
tag = integer_one_node;
vb_off = build_unary_op (NEGATE_EXPR, integer_one_node, 0);
- delta = BINFO_OFFSET (get_binfo (DECL_CLASS_CONTEXT (rhs_method),
- rhstype, 1));
- index = DECL_VINDEX (rhs_method);
+ if (flag_vtable_thunks)
+ delta = BINFO_OFFSET
+ (get_binfo (DECL_CONTEXT (rhs_method), rhstype, 1));
+ else
+ delta = BINFO_OFFSET
+ (get_binfo (DECL_CLASS_CONTEXT (rhs_method), rhstype, 1));
+ idx = DECL_VINDEX (rhs_method);
vt_off = get_vfield_offset (get_binfo (DECL_CONTEXT (rhs_method),
rhstype, 0));
}
@@ -593,8 +615,9 @@ build_signature_table_constructor (sig_ty, rhs)
vb_off = build_unary_op (NEGATE_EXPR, integer_one_node, 0);
delta = BINFO_OFFSET (get_binfo (DECL_CLASS_CONTEXT (rhs_method),
rhstype, 1));
- index = integer_zero_node;
- pfn = build_unary_op (ADDR_EXPR, rhs_method, 0);
+ idx = integer_zero_node;
+ pfn = build_addr_func (rhs_method);
+ TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (rhs_method)) = 1;
TREE_TYPE (pfn) = ptr_type_node;
TREE_ADDRESSABLE (rhs_method) = 1;
}
@@ -609,25 +632,25 @@ build_signature_table_constructor (sig_ty, rhs)
pfn_decl = TREE_CHAIN (index_decl);
vt_off_decl = TREE_CHAIN (pfn_decl);
- tag = convert (TREE_TYPE (tag_decl), tag);
- vb_off = convert (TREE_TYPE (vb_off_decl), vb_off);
- delta = convert (TREE_TYPE (delta_decl), delta);
- index = convert (TREE_TYPE (index_decl), index);
+ tag = cp_convert (TREE_TYPE (tag_decl), tag);
+ vb_off = cp_convert (TREE_TYPE (vb_off_decl), vb_off);
+ delta = cp_convert (TREE_TYPE (delta_decl), delta);
+ idx = cp_convert (TREE_TYPE (index_decl), idx);
if (DECL_VINDEX (rhs_method))
{
- vt_off = convert (TREE_TYPE (vt_off_decl), vt_off);
+ vt_off = cp_convert (TREE_TYPE (vt_off_decl), vt_off);
tbl_entry = build_tree_list (vt_off_decl, vt_off);
}
else
{
- pfn = convert (TREE_TYPE (pfn_decl), pfn);
+ pfn = cp_convert (TREE_TYPE (pfn_decl), pfn);
tbl_entry = build_tree_list (pfn_decl, pfn);
}
tbl_entry = tree_cons (delta_decl, delta,
- tree_cons (index_decl, index, tbl_entry));
+ tree_cons (index_decl, idx, tbl_entry));
tbl_entry = tree_cons (tag_decl, tag,
tree_cons (vb_off_decl, vb_off, tbl_entry));
tbl_entry = build (CONSTRUCTOR, sigtable_entry_type,
@@ -703,7 +726,7 @@ build_sigtable (sig_type, rhs_type, init_from)
}
if (decl == NULL_TREE)
{
- tree init;
+ tree init = NULL_TREE;
/* We allow only one signature table to be generated for signatures
with opaque types. Otherwise we create a loophole in the type
@@ -732,7 +755,7 @@ build_sigtable (sig_type, rhs_type, init_from)
decl = pushdecl_top_level (build_decl (VAR_DECL, name, sig_type));
current_function_decl = context;
}
- IDENTIFIER_GLOBAL_VALUE (name) = decl;
+ SET_IDENTIFIER_GLOBAL_VALUE (name, decl);
store_init_value (decl, init_expr);
if (IS_SIGNATURE (rhs_type))
{
@@ -779,9 +802,9 @@ build_signature_pointer_constructor (lhs, rhs)
if (! ((TREE_CODE (rhstype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (rhstype)) == RECORD_TYPE)
- || (TYPE_LANG_SPECIFIC (rhstype) &&
- (IS_SIGNATURE_POINTER (rhstype)
- || IS_SIGNATURE_REFERENCE (rhstype)))))
+ || (TYPE_LANG_SPECIFIC (rhstype)
+ && (IS_SIGNATURE_POINTER (rhstype)
+ || IS_SIGNATURE_REFERENCE (rhstype)))))
{
error ("invalid assignment to signature pointer or reference");
return error_mark_node;
@@ -803,8 +826,8 @@ build_signature_pointer_constructor (lhs, rhs)
saveable_obstack = &permanent_obstack;
}
- if (TYPE_LANG_SPECIFIC (rhstype) &&
- (IS_SIGNATURE_POINTER (rhstype) || IS_SIGNATURE_REFERENCE (rhstype)))
+ if (TYPE_LANG_SPECIFIC (rhstype)
+ && (IS_SIGNATURE_POINTER (rhstype) || IS_SIGNATURE_REFERENCE (rhstype)))
{
if (SIGNATURE_TYPE (rhstype) == sig_ty)
{
@@ -859,7 +882,6 @@ build_signature_pointer_constructor (lhs, rhs)
result = tree_cons (NULL_TREE, optr_expr,
build_tree_list (NULL_TREE, sptr_expr));
result = build_nt (CONSTRUCTOR, NULL_TREE, result);
- TREE_HAS_CONSTRUCTOR (result) = 1;
result = digest_init (lhstype, result, 0);
}
else
@@ -910,22 +932,24 @@ save_this (instance)
/* Build a signature member function call. Looks up the signature table
entry corresponding to FUNCTION. Depending on the value of the CODE
field, either call the function in PFN directly, or use OFFSET to
- index INSTANCE's virtual function table. */
+ index the object's virtual function table. */
tree
-build_signature_method_call (basetype, instance, function, parms)
- tree basetype, instance, function, parms;
+build_signature_method_call (function, parms)
+ tree function, parms;
{
+ tree instance = TREE_VALUE (parms);
tree saved_instance = save_this (instance); /* Create temp for `this'. */
tree object_ptr = build_optr_ref (saved_instance);
tree new_object_ptr, new_parms;
tree signature_tbl_ptr = build_sptr_ref (saved_instance);
tree sig_field_name = DECL_NAME (DECL_MEMFUNC_POINTER_TO (function));
+ tree basetype = DECL_CONTEXT (function);
tree basetype_path = TYPE_BINFO (basetype);
tree tbl_entry = build_component_ref (build1 (INDIRECT_REF, basetype,
signature_tbl_ptr),
sig_field_name, basetype_path, 1);
- tree tag, delta, pfn, vt_off, index, vfn;
+ tree tag, delta, pfn, vt_off, idx, vfn;
tree deflt_call = NULL_TREE, direct_call, virtual_call, result;
tbl_entry = save_expr (tbl_entry);
@@ -933,7 +957,7 @@ build_signature_method_call (basetype, instance, function, parms)
delta = build_component_ref (tbl_entry, delta_identifier, NULL_TREE, 1);
pfn = build_component_ref (tbl_entry, pfn_identifier, NULL_TREE, 1);
vt_off = build_component_ref (tbl_entry, vt_off_identifier, NULL_TREE, 1);
- index = build_component_ref (tbl_entry, index_identifier, NULL_TREE, 1);
+ idx = build_component_ref (tbl_entry, index_identifier, NULL_TREE, 1);
TREE_TYPE (pfn) = build_pointer_type (TREE_TYPE (function));
if (IS_DEFAULT_IMPLEMENTATION (function))
@@ -943,11 +967,11 @@ build_signature_method_call (basetype, instance, function, parms)
}
new_object_ptr = build (PLUS_EXPR, build_pointer_type (basetype),
- convert (ptrdiff_type_node, object_ptr),
- convert (ptrdiff_type_node, delta));
+ cp_convert (ptrdiff_type_node, object_ptr),
+ cp_convert (ptrdiff_type_node, delta));
parms = tree_cons (NULL_TREE,
- convert (build_pointer_type (basetype), object_ptr),
+ cp_convert (build_pointer_type (basetype), object_ptr),
TREE_CHAIN (parms));
new_parms = tree_cons (NULL_TREE, new_object_ptr, TREE_CHAIN (parms));
@@ -955,10 +979,10 @@ build_signature_method_call (basetype, instance, function, parms)
/* Cast the signature method to have `this' of a normal pointer type. */
tree old_this = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn))));
- TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn)))) =
- build_type_variant (build_pointer_type (basetype),
- TYPE_READONLY (old_this),
- TYPE_VOLATILE (old_this));
+ TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (pfn))))
+ = build_type_variant (build_pointer_type (basetype),
+ TYPE_READONLY (old_this),
+ TYPE_VOLATILE (old_this));
direct_call = build_function_call (pfn, new_parms);
@@ -967,23 +991,20 @@ build_signature_method_call (basetype, instance, function, parms)
vfld = build (PLUS_EXPR,
build_pointer_type (build_pointer_type (vtbl_type_node)),
- convert (ptrdiff_type_node, object_ptr),
- convert (ptrdiff_type_node, vt_off));
+ cp_convert (ptrdiff_type_node, object_ptr),
+ cp_convert (ptrdiff_type_node, vt_off));
vtbl = build_indirect_ref (build_indirect_ref (vfld, NULL_PTR),
NULL_PTR);
- aref = build_array_ref (vtbl, index);
+ aref = build_array_ref (vtbl, idx);
if (flag_vtable_thunks)
vfn = aref;
else
- vfn = build_component_ref (aref, pfn_identifier, 0, 0);
+ vfn = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
TREE_TYPE (vfn) = build_pointer_type (TREE_TYPE (function));
- if (flag_vtable_thunks)
- virtual_call = build_function_call (vfn, parms);
- else
- virtual_call = build_function_call (vfn, new_parms);
+ virtual_call = build_function_call (vfn, new_parms);
}
/* Undo the cast, make `this' a signature pointer again. */
@@ -998,7 +1019,7 @@ build_signature_method_call (basetype, instance, function, parms)
&& (!deflt_call || deflt_call == error_mark_node)))
{
compiler_error ("cannot build call of signature member function `%s'",
- fndecl_as_string (NULL, function, 1));
+ fndecl_as_string (function, 1));
return error_mark_node;
}
@@ -1039,7 +1060,7 @@ build_optr_ref (instance)
/* Create a COMPONENT_REF expression for referencing the SPTR field
of a signature pointer or reference. */
-tree
+static tree
build_sptr_ref (instance)
tree instance;
{
diff --git a/contrib/gcc/cp/spew.c b/contrib/gcc/cp/spew.c
index 4b30b95..f153150 100644
--- a/contrib/gcc/cp/spew.c
+++ b/contrib/gcc/cp/spew.c
@@ -24,20 +24,20 @@ Boston, MA 02111-1307, USA. */
when compiling parse.c and spew.c. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "input.h"
#include "tree.h"
#include "lex.h"
-#include "parse.h"
#include "cp-tree.h"
+#include "parse.h"
#include "flags.h"
#include "obstack.h"
/* This takes a token stream that hasn't decided much about types and
tries to figure out as much as it can, with excessive lookahead and
- backtracking. */
+ backtracking. */
-/* fifo of tokens recognized and available to parser. */
+/* fifo of tokens recognized and available to parser. */
struct token {
/* The values for YYCHAR will fit in a short. */
short yychar;
@@ -45,7 +45,17 @@ struct token {
YYSTYPE yylval;
};
-static int do_aggr ();
+static int do_aggr PROTO((void));
+static int probe_obstack PROTO((struct obstack *, tree, unsigned int));
+static void scan_tokens PROTO((int));
+
+#ifdef SPEW_DEBUG
+static int num_tokens PROTO((void));
+static struct token *nth_token PROTO((int));
+static void add_token PROTO((struct token *));
+static void consume_token PROTO((void));
+static int debug_yychar PROTO((int));
+#endif
/* From lex.c: */
/* the declaration found for the last IDENTIFIER token read in.
@@ -67,50 +77,55 @@ static unsigned int yylex_ctr = 0;
static int debug_yychar ();
#endif
-/* Initialize token_obstack. Called once, from init_lex. */
+/* Initialize token_obstack. Called once, from init_parse. */
+
void
init_spew ()
{
- gcc_obstack_init(&token_obstack);
+ gcc_obstack_init (&token_obstack);
}
#ifdef SPEW_DEBUG
/* Use functions for debugging... */
-/* Return the number of tokens available on the fifo. */
+/* Return the number of tokens available on the fifo. */
+
static int
num_tokens ()
{
- return (obstack_object_size(&token_obstack)/sizeof(struct token))
+ return (obstack_object_size (&token_obstack) / sizeof (struct token))
- first_token;
}
-/* Fetch the token N down the line from the head of the fifo. */
+/* Fetch the token N down the line from the head of the fifo. */
+
static struct token*
nth_token (n)
int n;
{
/* could just have this do slurp_ implicitly, but this way is easier
- * to debug... */
- my_friendly_assert (n < num_tokens(), 298);
- return ((struct token*)obstack_base(&token_obstack))+n+first_token;
+ to debug... */
+ my_friendly_assert (n < num_tokens (), 298);
+ return ((struct token*)obstack_base (&token_obstack)) + n + first_token;
}
-/* Add a token to the token fifo. */
+/* Add a token to the token fifo. */
+
static void
add_token (t)
struct token* t;
{
- obstack_grow(&token_obstack,t,sizeof (struct token));
+ obstack_grow (&token_obstack, t, sizeof (struct token));
}
/* Consume the next token out of the fifo. */
+
static void
-consume_token()
+consume_token ()
{
- if (num_tokens() == 1)
+ if (num_tokens () == 1)
{
- obstack_free(&token_obstack, obstack_base (&token_obstack));
+ obstack_free (&token_obstack, obstack_base (&token_obstack));
first_token = 0;
}
else
@@ -121,15 +136,15 @@ consume_token()
/* ...otherwise use macros. */
#define num_tokens() \
- ((obstack_object_size(&token_obstack)/sizeof(struct token)) - first_token)
+ ((obstack_object_size (&token_obstack) / sizeof (struct token)) - first_token)
#define nth_token(N) \
- (((struct token*)obstack_base(&token_obstack))+(N)+first_token)
+ (((struct token*)obstack_base (&token_obstack))+(N)+first_token)
-#define add_token(T) obstack_grow(&token_obstack, (T), sizeof (struct token))
+#define add_token(T) obstack_grow (&token_obstack, (T), sizeof (struct token))
#define consume_token() \
- (num_tokens() == 1 \
+ (num_tokens () == 1 \
? (obstack_free (&token_obstack, obstack_base (&token_obstack)), \
(first_token = 0)) \
: first_token++)
@@ -158,11 +173,11 @@ scan_tokens (n)
goto pad_tokens;
}
- while (num_tokens() <= n)
+ while (num_tokens () <= n)
{
- obstack_blank(&token_obstack,sizeof (struct token));
+ obstack_blank (&token_obstack, sizeof (struct token));
tmp = ((struct token *)obstack_next_free (&token_obstack))-1;
- tmp->yychar = real_yylex();
+ tmp->yychar = real_yylex ();
tmp->end_of_file = end_of_file;
tmp->yylval = yylval;
end_of_file = 0;
@@ -173,7 +188,7 @@ scan_tokens (n)
pad_tokens:
while (num_tokens () <= n)
{
- obstack_blank(&token_obstack,sizeof (struct token));
+ obstack_blank (&token_obstack, sizeof (struct token));
tmp = ((struct token *)obstack_next_free (&token_obstack))-1;
tmp->yychar = EMPTY;
tmp->end_of_file = 0;
@@ -182,35 +197,7 @@ scan_tokens (n)
}
}
-/* Create room for N tokens at the front of the fifo. This is used
- to insert new tokens into the stream ahead of the current token. */
-
-static void
-shift_tokens (n)
- int n;
-{
- if (first_token >= n)
- first_token -= n;
- else
- {
- int old_token_count = num_tokens ();
- char *tmp;
-
- obstack_blank (&token_obstack, (n-first_token) * sizeof (struct token));
- if (old_token_count)
- {
- tmp = (char *)alloca ((num_tokens () + (n-first_token))
- * sizeof (struct token));
- /* This move does not rely on the system being able to handle
- overlapping moves. */
- bcopy ((char *) nth_token (0), tmp,
- old_token_count * sizeof (struct token));
- bcopy (tmp, (char *) nth_token (n),
- old_token_count * sizeof (struct token));
- }
- first_token = 0;
- }
-}
+/* Like _obstack_allocated_p, but stop after checking NLEVELS chunks. */
static int
probe_obstack (h, obj, nlevels)
@@ -224,7 +211,7 @@ probe_obstack (h, obj, nlevels)
lp = (h)->chunk;
/* We use >= rather than > since the object cannot be exactly at
the beginning of the chunk but might be an empty object exactly
- at the end of an adjacent chunk. */
+ at the end of an adjacent chunk. */
for (; nlevels != 0 && lp != 0 && ((tree)lp >= obj || (tree)lp->limit < obj);
nlevels -= 1)
{
@@ -237,40 +224,52 @@ probe_obstack (h, obj, nlevels)
/* from lex.c: */
/* Value is 1 (or 2) if we should try to make the next identifier look like
a typename (when it may be a local variable or a class variable).
- Value is 0 if we treat this name in a default fashion. */
+ Value is 0 if we treat this name in a default fashion. */
extern int looking_for_typename;
int looking_for_template;
+extern int do_snarf_defarg;
extern struct obstack *current_obstack, *saveable_obstack;
tree got_scope;
tree got_object;
int
-peekyylex()
+peekyylex ()
{
scan_tokens (0);
return nth_token (0)->yychar;
}
int
-yylex()
+yylex ()
{
struct token tmp_token;
tree trrr;
+ int old_looking_for_typename = 0;
retry:
#ifdef SPEW_DEBUG
if (spew_debug)
{
yylex_ctr ++;
- fprintf(stderr, "\t\t## %d ##",yylex_ctr);
+ fprintf (stderr, "\t\t## %d ##", yylex_ctr);
}
#endif
+ if (do_snarf_defarg)
+ {
+ my_friendly_assert (num_tokens () == 0, 2837);
+ tmp_token.yychar = DEFARG;
+ tmp_token.yylval.ttype = snarf_defarg ();
+ tmp_token.end_of_file = 0;
+ do_snarf_defarg = 0;
+ add_token (&tmp_token);
+ }
+
/* if we've got tokens, send them */
- if (num_tokens())
+ else if (num_tokens ())
{
- tmp_token= *nth_token(0);
+ tmp_token= *nth_token (0);
/* TMP_TOKEN.YYLVAL.TTYPE may have been allocated on the wrong obstack.
If we don't find it in CURRENT_OBSTACK's current or immediately
@@ -288,13 +287,13 @@ yylex()
tmp_token.yychar = real_yylex ();
tmp_token.yylval = yylval;
tmp_token.end_of_file = end_of_file;
- add_token(&tmp_token);
+ add_token (&tmp_token);
}
/* many tokens just need to be returned. At first glance, all we
- * have to do is send them back up, but some of them are needed to
- * figure out local context. */
- switch(tmp_token.yychar)
+ have to do is send them back up, but some of them are needed to
+ figure out local context. */
+ switch (tmp_token.yychar)
{
case EMPTY:
/* This is a lexical no-op. */
@@ -308,8 +307,11 @@ yylex()
case IDENTIFIER:
scan_tokens (1);
if (nth_token (1)->yychar == SCOPE)
- /* Don't interfere with the setting from an 'aggr' prefix. */
- looking_for_typename++;
+ {
+ /* Don't interfere with the setting from an 'aggr' prefix. */
+ old_looking_for_typename = looking_for_typename;
+ looking_for_typename = 1;
+ }
else if (nth_token (1)->yychar == '<')
looking_for_template = 1;
@@ -321,81 +323,92 @@ yylex()
switch (tmp_token.yychar)
{
case TYPENAME:
- lastiddecl = identifier_typedecl_value (tmp_token.yylval.ttype);
- if (lastiddecl != trrr)
- {
- lastiddecl = trrr;
- if (got_scope || got_object)
- tmp_token.yylval.ttype = DECL_NESTED_TYPENAME (trrr);
- }
- break;
- case IDENTIFIER:
- lastiddecl = trrr;
- break;
- case PTYPENAME:
- lastiddecl = NULL_TREE;
- break;
+ case SELFNAME:
case NSNAME:
+ case PTYPENAME:
lastiddecl = trrr;
+
+ /* If this got special lookup, remember it. In these cases,
+ we don't have to worry about being a declarator-id. */
if (got_scope || got_object)
tmp_token.yylval.ttype = trrr;
break;
+
+ case PFUNCNAME:
+ case IDENTIFIER:
+ lastiddecl = trrr;
+ break;
+
default:
my_friendly_abort (101);
}
}
else
- lastiddecl = trrr;
+ lastiddecl = NULL_TREE;
got_scope = NULL_TREE;
- /* and fall through to... */
+ /* and fall through to... */
case IDENTIFIER_DEFN:
case TYPENAME:
case TYPENAME_DEFN:
case PTYPENAME:
case PTYPENAME_DEFN:
consume_token ();
- if (looking_for_typename > 0)
- looking_for_typename--;
+ /* If we see a SCOPE next, restore the old value.
+ Otherwise, we got what we want. */
+ looking_for_typename = old_looking_for_typename;
looking_for_template = 0;
break;
case SCSPEC:
- /* do_aggr needs to check if the previous token was RID_FRIEND,
- so just increment first_token instead of calling consume_token. */
- first_token++;
+ case NEW:
+ /* do_aggr needs to check if the previous token was RID_NEW,
+ so just increment first_token instead of calling consume_token. */
+ ++first_token;
break;
+
case TYPESPEC:
consume_token ();
break;
case AGGR:
- *nth_token(0) = tmp_token;
+ *nth_token (0) = tmp_token;
do_aggr ();
- /* fall through to output... */
+ /* fall through to output... */
case ENUM:
/* Set this again, in case we are rescanning. */
- looking_for_typename = 1;
- /* fall through... */
+ looking_for_typename = 2;
+ /* fall through... */
default:
- consume_token();
+ consume_token ();
}
+ /* class member lookup only applies to the first token after the object
+ expression, except for explicit destructor calls. */
+ if (tmp_token.yychar != '~')
+ got_object = NULL_TREE;
+
+ /* Clear looking_for_typename if we got 'enum { ... };'. */
+ if (tmp_token.yychar == '{' || tmp_token.yychar == ':'
+ || tmp_token.yychar == ';')
+ looking_for_typename = 0;
+
yylval = tmp_token.yylval;
yychar = tmp_token.yychar;
end_of_file = tmp_token.end_of_file;
#ifdef SPEW_DEBUG
if (spew_debug)
- debug_yychar(yychar);
+ debug_yychar (yychar);
#endif
+
return yychar;
}
/* token[0] == AGGR (struct/union/enum)
- * Thus, token[1] is either a TYPENAME or a TYPENAME_DEFN.
- * If token[2] == '{' or ':' then it's TYPENAME_DEFN.
- * It's also a definition if it's a forward declaration (as in 'struct Foo;')
- * which we can tell lf token[2] == ';' *and* token[-1] != FRIEND.
- */
+ Thus, token[1] is either a TYPENAME or a TYPENAME_DEFN.
+ If token[2] == '{' or ':' then it's TYPENAME_DEFN.
+ It's also a definition if it's a forward declaration (as in 'struct Foo;')
+ which we can tell if token[2] == ';' *and* token[-1] != FRIEND or NEW. */
+
static int
do_aggr ()
{
@@ -408,10 +421,16 @@ do_aggr ()
yc2 = nth_token (2)->yychar;
if (yc2 == ';')
{
- /* It's a forward declaration iff we were not preceded by 'friend'. */
- if (first_token > 0 && nth_token (-1)->yychar == SCSPEC
- && nth_token (-1)->yylval.ttype == ridpointers[(int) RID_FRIEND])
- return 0;
+ /* It's a forward declaration iff we were not preceded by
+ 'friend' or `new'. */
+ if (first_token > 0)
+ {
+ if (nth_token (-1)->yychar == SCSPEC
+ && nth_token (-1)->yylval.ttype == ridpointers[(int) RID_FRIEND])
+ return 0;
+ if (nth_token (-1)->yychar == NEW)
+ return 0;
+ }
}
else if (yc2 != '{' && yc2 != ':')
return 0;
@@ -434,7 +453,8 @@ do_aggr ()
}
#ifdef SPEW_DEBUG
-/* debug_yychar takes a yychar (token number) value and prints its name. */
+/* debug_yychar takes a yychar (token number) value and prints its name. */
+
static int
debug_yychar (yy)
int yy;
@@ -444,7 +464,7 @@ debug_yychar (yy)
int i;
- if(yy<256) {
+ if (yy<256) {
fprintf (stderr, "<%d: %c >\n", yy, yy);
return 0;
}
diff --git a/contrib/gcc/cp/tinfo.cc b/contrib/gcc/cp/tinfo.cc
new file mode 100644
index 0000000..d8380da
--- /dev/null
+++ b/contrib/gcc/cp/tinfo.cc
@@ -0,0 +1,134 @@
+// Methods for type_info for -*- C++ -*- Run Time Type Identification.
+// Copyright (C) 1994, 1996 Free Software Foundation
+
+// This file is part of GNU CC.
+
+// GNU CC 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, or (at your option)
+// any later version.
+
+// GNU CC 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 GNU CC; see the file COPYING. If not, write to
+// the Free Software Foundation, 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+// As a special exception, if you link this library with other files,
+// some of which are compiled with GCC, to produce an executable,
+// this library does not by itself cause the resulting executable
+// to be covered by the GNU General Public License.
+// This exception does not however invalidate any other reasons why
+// the executable file might be covered by the GNU General Public License.
+
+#pragma implementation "typeinfo"
+
+#include <stddef.h>
+#include "tinfo.h"
+#include "new" // for placement new
+
+// This file contains the minimal working set necessary to link with code
+// that uses virtual functions and -frtti but does not actually use RTTI
+// functionality.
+
+std::type_info::
+~type_info ()
+{ }
+
+// We can't rely on common symbols being shared between shared objects.
+bool type_info::
+operator== (const type_info& arg) const
+{
+ return (&arg == this) || (strcmp (name (), arg.name ()) == 0);
+}
+
+extern "C" void
+__rtti_class (void *addr, const char *name,
+ const __class_type_info::base_info *bl, size_t bn)
+{ new (addr) __class_type_info (name, bl, bn); }
+
+extern "C" void
+__rtti_si (void *addr, const char *n, const std::type_info *ti)
+{
+ new (addr) __si_type_info
+ (n, static_cast <const __user_type_info &> (*ti));
+}
+
+extern "C" void
+__rtti_user (void *addr, const char *name)
+{ new (addr) __user_type_info (name); }
+
+// dynamic_cast helper methods.
+// Returns a pointer to the desired sub-object or 0.
+
+void * __user_type_info::
+dcast (const type_info& to, int, void *addr, const type_info *, void *) const
+{ return (*this == to) ? addr : 0; }
+
+void * __si_type_info::
+dcast (const type_info& to, int require_public, void *addr,
+ const type_info *sub, void *subptr) const
+{
+ if (*this == to)
+ return addr;
+ return base.dcast (to, require_public, addr, sub, subptr);
+}
+
+void* __class_type_info::
+dcast (const type_info& desired, int is_public, void *objptr,
+ const type_info *sub, void *subptr) const
+{
+ if (*this == desired)
+ return objptr;
+
+ void *match_found = 0;
+ for (size_t i = 0; i < n_bases; i++)
+ {
+ if (is_public && base_list[i].access != PUBLIC)
+ continue;
+
+ void *p = (char *)objptr + base_list[i].offset;
+ if (base_list[i].is_virtual)
+ p = *(void **)p;
+ p = base_list[i].base->dcast (desired, is_public, p, sub, subptr);
+ if (p)
+ {
+ if (match_found == 0)
+ match_found = p;
+ else if (match_found != p)
+ {
+ if (sub)
+ {
+ // Perhaps we're downcasting from *sub to desired; see if
+ // subptr is a subobject of exactly one of {match_found,p}.
+
+ const __user_type_info &d =
+ static_cast <const __user_type_info &> (desired);
+
+ void *os = d.dcast (*sub, 1, match_found);
+ void *ns = d.dcast (*sub, 1, p);
+
+ if (os == ns)
+ /* ambiguous -- subptr is a virtual base */;
+ else if (os == subptr)
+ continue;
+ else if (ns == subptr)
+ {
+ match_found = p;
+ continue;
+ }
+ }
+
+ // base found at two different pointers,
+ // conversion is not unique
+ return 0;
+ }
+ }
+ }
+
+ return match_found;
+}
diff --git a/contrib/gcc/cp/tinfo.h b/contrib/gcc/cp/tinfo.h
new file mode 100644
index 0000000..3cfee04
--- /dev/null
+++ b/contrib/gcc/cp/tinfo.h
@@ -0,0 +1,55 @@
+// RTTI support internals for -*- C++ -*-
+// Copyright (C) 1994, 1995, 1996 Free Software Foundation
+
+#include "typeinfo"
+
+// Class declarations shared between the typeinfo implementation files.
+
+// type_info for a class with no base classes (or an enum).
+
+struct __user_type_info : public std::type_info {
+ __user_type_info (const char *n) : type_info (n) {}
+
+ // If our type can be converted to the desired type,
+ // return the pointer, adjusted accordingly; else return 0.
+ virtual void* dcast (const type_info &, int, void *,
+ const type_info * = 0, void * = 0) const;
+};
+
+// type_info for a class with one public, nonvirtual base class.
+
+class __si_type_info : public __user_type_info {
+ const __user_type_info &base;
+
+public:
+ __si_type_info (const char *n, const __user_type_info &b)
+ : __user_type_info (n), base (b) { }
+
+ virtual void *dcast (const type_info &, int, void *,
+ const type_info * = 0, void * = 0) const;
+};
+
+// type_info for a general class.
+
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+
+struct __class_type_info : public __user_type_info {
+ enum access { PUBLIC = 1, PROTECTED = 2, PRIVATE = 3 };
+
+ struct base_info {
+ const __user_type_info *base;
+ USItype offset: 29;
+ bool is_virtual: 1;
+ access access: 2;
+ };
+
+ const base_info *base_list;
+ size_t n_bases;
+
+ __class_type_info (const char *name, const base_info *bl, size_t bn)
+ : __user_type_info (name), base_list (bl), n_bases (bn) {}
+
+ // This is a little complex.
+ virtual void* dcast (const type_info &, int, void *,
+ const type_info * = 0, void * = 0) const;
+};
diff --git a/contrib/gcc/cp/tinfo2.cc b/contrib/gcc/cp/tinfo2.cc
new file mode 100644
index 0000000..3e63354
--- /dev/null
+++ b/contrib/gcc/cp/tinfo2.cc
@@ -0,0 +1,300 @@
+// Methods for type_info for -*- C++ -*- Run Time Type Identification.
+// Copyright (C) 1994, 1996 Free Software Foundation
+
+// This file is part of GNU CC.
+
+// GNU CC 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, or (at your option)
+// any later version.
+
+// GNU CC 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 GNU CC; see the file COPYING. If not, write to
+// the Free Software Foundation, 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+// As a special exception, if you link this library with other files,
+// some of which are compiled with GCC, to produce an executable,
+// this library does not by itself cause the resulting executable
+// to be covered by the GNU General Public License.
+// This exception does not however invalidate any other reasons why
+// the executable file might be covered by the GNU General Public License.
+
+#include <stddef.h>
+#include "tinfo.h"
+#include "new" // for placement new
+
+using std::type_info;
+
+bool
+type_info::before (const type_info &arg) const
+{
+ return strcmp (name (), arg.name ()) < 0;
+}
+
+// type info for pointer type.
+
+struct __pointer_type_info : public type_info {
+ const type_info& type;
+
+ __pointer_type_info (const char *n, const type_info& ti)
+ : type_info (n), type (ti) {}
+};
+
+// type info for attributes
+
+struct __attr_type_info : public type_info {
+ enum cv { NONE = 0, CONST = 1, VOLATILE = 2, CONSTVOL = 1 | 2 };
+
+ const type_info& type;
+ cv attr;
+
+ __attr_type_info (const char *n, cv a, const type_info& t)
+ : type_info (n), type (t), attr (a) {}
+};
+
+// type_info for builtin type
+
+struct __builtin_type_info : public type_info {
+ __builtin_type_info (const char *n): type_info (n) {}
+};
+
+// type info for function.
+
+struct __func_type_info : public type_info {
+ __func_type_info (const char *n) : type_info (n) {}
+};
+
+// type info for pointer to member function.
+
+struct __ptmf_type_info : public type_info {
+ __ptmf_type_info (const char *n) : type_info (n) {}
+};
+
+// type info for pointer to data member.
+
+struct __ptmd_type_info : public type_info {
+ __ptmd_type_info (const char *n): type_info (n) {}
+};
+
+// type info for array.
+
+struct __array_type_info : public type_info {
+ __array_type_info (const char *n): type_info (n) {}
+};
+
+// Entry points for the compiler.
+
+/* Low level match routine used by compiler to match types of catch
+ variables and thrown objects. */
+
+extern "C" void*
+__throw_type_match_rtti (const void *catch_type_r, const void *throw_type_r,
+ void *objptr)
+{
+ const type_info &catch_type = *(const type_info *)catch_type_r;
+ const type_info &throw_type = *(const type_info *)throw_type_r;
+
+ if (catch_type == throw_type)
+ return objptr;
+
+#if 0
+ printf ("We want to match a %s against a %s!\n",
+ throw_type.name (), catch_type.name ());
+#endif
+
+ void *new_objptr = 0;
+
+ if (const __user_type_info *p
+ = dynamic_cast <const __user_type_info *> (&throw_type))
+ {
+ /* The 1 skips conversions to private bases. */
+ new_objptr = p->dcast (catch_type, 1, objptr);
+ }
+ else if (const __pointer_type_info *fr =
+ dynamic_cast <const __pointer_type_info *> (&throw_type))
+ {
+ const __pointer_type_info *to =
+ dynamic_cast <const __pointer_type_info *> (&catch_type);
+
+ if (! to)
+ goto fail;
+
+ const type_info *subfr = &fr->type, *subto = &to->type;
+ __attr_type_info::cv cvfrom, cvto;
+
+ if (const __attr_type_info *at
+ = dynamic_cast <const __attr_type_info *> (subfr))
+ {
+ cvfrom = at->attr;
+ subfr = &at->type;
+ }
+ else
+ cvfrom = __attr_type_info::NONE;
+
+ if (const __attr_type_info *at
+ = dynamic_cast <const __attr_type_info *> (subto))
+ {
+ cvto = at->attr;
+ subto = &at->type;
+ }
+ else
+ cvto = __attr_type_info::NONE;
+
+ if (((cvfrom & __attr_type_info::CONST)
+ > (cvto & __attr_type_info::CONST))
+ || ((cvfrom & __attr_type_info::VOLATILE)
+ > (cvto & __attr_type_info::VOLATILE)))
+ goto fail;
+
+ if (*subto == *subfr)
+ new_objptr = objptr;
+ else if (*subto == typeid (void)
+ && dynamic_cast <const __func_type_info *> (subfr) == 0)
+ new_objptr = objptr;
+ else if (const __user_type_info *p
+ = dynamic_cast <const __user_type_info *> (subfr))
+ {
+ /* The 1 skips conversions to private bases. */
+ new_objptr = p->dcast (*subto, 1, objptr);
+ }
+ else if (const __pointer_type_info *pfr
+ = dynamic_cast <const __pointer_type_info *> (subfr))
+ {
+ // Multi-level pointer conversion.
+
+ const __pointer_type_info *pto
+ = dynamic_cast <const __pointer_type_info *> (subto);
+
+ if (! pto)
+ goto fail;
+
+ bool constp = (cvto & __attr_type_info::CONST);
+ for (subto = &pto->type, subfr = &pfr->type; ;
+ subto = &pto->type, subfr = &pfr->type)
+ {
+ if (const __attr_type_info *at
+ = dynamic_cast <const __attr_type_info *> (subfr))
+ {
+ cvfrom = at->attr;
+ subfr = &at->type;
+ }
+ else
+ cvfrom = __attr_type_info::NONE;
+
+ if (const __attr_type_info *at
+ = dynamic_cast <const __attr_type_info *> (subto))
+ {
+ cvto = at->attr;
+ subto = &at->type;
+ }
+ else
+ cvto = __attr_type_info::NONE;
+
+ if (((cvfrom & __attr_type_info::CONST)
+ > (cvto & __attr_type_info::CONST))
+ || ((cvfrom & __attr_type_info::VOLATILE)
+ > (cvto & __attr_type_info::VOLATILE)))
+ goto fail;
+
+ if (! constp
+ && (((cvfrom & __attr_type_info::CONST)
+ < (cvto & __attr_type_info::CONST))
+ || ((cvfrom & __attr_type_info::VOLATILE)
+ < (cvto & __attr_type_info::VOLATILE))))
+ goto fail;
+
+ if (*subto == *subfr)
+ {
+ new_objptr = objptr;
+ break;
+ }
+
+ pto = dynamic_cast <const __pointer_type_info *> (subto);
+ pfr = dynamic_cast <const __pointer_type_info *> (subfr);
+ if (! pto || ! pfr)
+ goto fail;
+
+ if (! (cvto & __attr_type_info::CONST))
+ constp = false;
+ }
+ }
+ }
+ fail:
+
+#if 0
+ if (new_objptr)
+ printf ("It converts, delta is %d\n", new_objptr-objptr);
+#endif
+ return new_objptr;
+}
+
+/* Called from __cp_pop_exception. Is P the type_info node for a pointer
+ of some kind? */
+
+bool
+__is_pointer (void *p)
+{
+ const type_info *t = reinterpret_cast <const type_info *>(p);
+ const __pointer_type_info *pt =
+ dynamic_cast <const __pointer_type_info *> (t);
+ return pt != 0;
+}
+
+extern "C" void
+__rtti_ptr (void *addr, const char *n, const type_info *ti)
+{ new (addr) __pointer_type_info (n, *ti); }
+
+extern "C" void
+__rtti_attr (void *addr, const char *n, int attrval, const type_info *ti)
+{
+ new (addr) __attr_type_info
+ (n, static_cast <__attr_type_info::cv> (attrval), *ti);
+}
+
+extern "C" void
+__rtti_func (void *addr, const char *name)
+{ new (addr) __func_type_info (name); }
+
+extern "C" void
+__rtti_ptmf (void *addr, const char *name)
+{ new (addr) __ptmf_type_info (name); }
+
+extern "C" void
+__rtti_ptmd (void *addr, const char *name)
+{ new (addr) __ptmd_type_info (name); }
+
+extern "C" void
+__rtti_array (void *addr, const char *name)
+{ new (addr) __array_type_info (name); }
+
+extern "C" void *
+__dynamic_cast (const type_info& (*from)(void), const type_info& (*to)(void),
+ int require_public, void *address,
+ const type_info & (*sub)(void), void *subptr)
+{
+ return static_cast <const __user_type_info &> (from ()).dcast
+ (to (), require_public, address, &(sub ()), subptr);
+}
+
+// type_info nodes and functions for the builtin types. The mangling here
+// must match the mangling in gcc/cp/rtti.c.
+
+#define BUILTIN(mangled) \
+unsigned char __ti##mangled [sizeof (__builtin_type_info)] \
+ __attribute__ ((aligned (__alignof__ (void *)))); \
+extern "C" const type_info &__tf##mangled (void) { \
+ if ((*(void **) __ti##mangled) == 0) \
+ new (__ti##mangled) __builtin_type_info (#mangled); \
+ return *(type_info *)__ti##mangled; \
+}
+
+BUILTIN (v); BUILTIN (x); BUILTIN (l); BUILTIN (i); BUILTIN (s); BUILTIN (b);
+BUILTIN (c); BUILTIN (w); BUILTIN (r); BUILTIN (d); BUILTIN (f);
+BUILTIN (Ui); BUILTIN (Ul); BUILTIN (Ux); BUILTIN (Us); BUILTIN (Uc);
+BUILTIN (Sc);
diff --git a/contrib/gcc/cp/tree.c b/contrib/gcc/cp/tree.c
index 7fb688e..7c7768f 100644
--- a/contrib/gcc/cp/tree.c
+++ b/contrib/gcc/cp/tree.c
@@ -1,5 +1,5 @@
/* Language-dependent node constructors for parse phase of GNU compiler.
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -20,12 +20,34 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "obstack.h"
#include "tree.h"
#include "cp-tree.h"
#include "flags.h"
#include "rtl.h"
+#include "toplev.h"
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+extern void compiler_error ();
+
+static tree get_identifier_list PROTO((tree));
+static tree bot_manip PROTO((tree));
+static tree perm_manip PROTO((tree));
+static tree build_cplus_array_type_1 PROTO((tree, tree));
+static void list_hash_add PROTO((int, tree));
+static int list_hash PROTO((tree, tree, tree));
+static tree list_hash_lookup PROTO((int, int, int, int, tree, tree,
+ tree));
+static void propagate_binfo_offsets PROTO((tree, tree));
+static void unshare_base_binfos PROTO((tree));
+static int avoid_overlap PROTO((tree, tree));
+static int equal_functions PROTO((tree, tree));
#define CEIL(x,y) (((x) + (y) - 1) / (y))
@@ -43,17 +65,20 @@ real_lvalue_p (ref)
if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
return 1;
- if (ref == current_class_decl && flag_this_is_variable <= 0)
+ if (ref == current_class_ptr && flag_this_is_variable <= 0)
return 0;
switch (TREE_CODE (ref))
{
/* preincrements and predecrements are valid lvals, provided
- what they refer to are valid lvals. */
+ what they refer to are valid lvals. */
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
case COMPONENT_REF:
case SAVE_EXPR:
+ case UNSAVE_EXPR:
+ case TRY_CATCH_EXPR:
+ case WITH_CLEANUP_EXPR:
return real_lvalue_p (TREE_OPERAND (ref, 0));
case STRING_CST:
@@ -74,9 +99,6 @@ real_lvalue_p (ref)
return 1;
break;
- case WITH_CLEANUP_EXPR:
- return real_lvalue_p (TREE_OPERAND (ref, 0));
-
/* A currently unresolved scope ref. */
case SCOPE_REF:
my_friendly_abort (103);
@@ -101,11 +123,16 @@ real_lvalue_p (ref)
case MIN_EXPR:
return (real_lvalue_p (TREE_OPERAND (ref, 0))
&& real_lvalue_p (TREE_OPERAND (ref, 1)));
+
+ default:
+ break;
}
return 0;
}
+/* This differs from real_lvalue_p in that class rvalues are considered
+ lvalues. */
int
lvalue_p (ref)
tree ref;
@@ -116,17 +143,22 @@ lvalue_p (ref)
if (TREE_CODE (TREE_TYPE (ref)) == REFERENCE_TYPE)
return 1;
- if (ref == current_class_decl && flag_this_is_variable <= 0)
+ if (ref == current_class_ptr && flag_this_is_variable <= 0)
return 0;
switch (TREE_CODE (ref))
{
/* preincrements and predecrements are valid lvals, provided
- what they refer to are valid lvals. */
+ what they refer to are valid lvals. */
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
case COMPONENT_REF:
case SAVE_EXPR:
+ case UNSAVE_EXPR:
+ case TRY_CATCH_EXPR:
+ case WITH_CLEANUP_EXPR:
return lvalue_p (TREE_OPERAND (ref, 0));
case STRING_CST:
@@ -147,9 +179,6 @@ lvalue_p (ref)
return 1;
break;
- case WITH_CLEANUP_EXPR:
- return lvalue_p (TREE_OPERAND (ref, 0));
-
case TARGET_EXPR:
return 1;
@@ -182,6 +211,9 @@ lvalue_p (ref)
case MIN_EXPR:
return (lvalue_p (TREE_OPERAND (ref, 0))
&& lvalue_p (TREE_OPERAND (ref, 1)));
+
+ default:
+ break;
}
return 0;
@@ -206,44 +238,47 @@ lvalue_or_else (ref, string)
Build an encapsulation of the initialization to perform
and return it so that it can be processed by language-independent
- and language-specific expression expanders.
+ and language-specific expression expanders. */
- If WITH_CLEANUP_P is nonzero, we build a cleanup for this expression.
- Otherwise, cleanups are not built here. For example, when building
- an initialization for a stack slot, since the called function handles
- the cleanup, we would not want to do it here. */
tree
-build_cplus_new (type, init, with_cleanup_p)
+build_cplus_new (type, init)
tree type;
tree init;
- int with_cleanup_p;
{
tree slot;
tree rval;
+ if (TREE_CODE (init) != CALL_EXPR && TREE_CODE (init) != AGGR_INIT_EXPR)
+ return init;
+
slot = build (VAR_DECL, type);
+ DECL_ARTIFICIAL (slot) = 1;
layout_decl (slot, 0);
- rval = build (NEW_EXPR, type,
+ rval = build (AGGR_INIT_EXPR, type,
TREE_OPERAND (init, 0), TREE_OPERAND (init, 1), slot);
TREE_SIDE_EFFECTS (rval) = 1;
- TREE_ADDRESSABLE (rval) = 1;
- rval = build (TARGET_EXPR, type, slot, rval, 0);
+ rval = build (TARGET_EXPR, type, slot, rval, NULL_TREE, NULL_TREE);
+ TREE_SIDE_EFFECTS (rval) = 1;
+
+ return rval;
+}
+
+/* Encapsulate the expression INIT in a TARGET_EXPR. */
+
+tree
+get_target_expr (init)
+ tree init;
+{
+ tree slot;
+ tree rval;
+
+ slot = build (VAR_DECL, TREE_TYPE (init));
+ DECL_ARTIFICIAL (slot) = 1;
+ layout_decl (slot, 0);
+ rval = build (TARGET_EXPR, TREE_TYPE (init), slot, init,
+ NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (rval) = 1;
- TREE_ADDRESSABLE (rval) = 1;
-#if 0
- if (with_cleanup_p && TYPE_NEEDS_DESTRUCTOR (type))
- {
- TREE_OPERAND (rval, 2) = error_mark_node;
- rval = build (WITH_CLEANUP_EXPR, type, rval, 0,
- build_delete (build_pointer_type (type),
- build_unary_op (ADDR_EXPR, slot, 0),
- integer_two_node,
- LOOKUP_NORMAL|LOOKUP_DESTRUCTOR, 0));
- TREE_SIDE_EFFECTS (rval) = 1;
- TREE_ADDRESSABLE (rval) = 1;
- }
-#endif
return rval;
}
@@ -258,7 +293,7 @@ break_out_cleanups (exp)
if (TREE_CODE (tmp) == CALL_EXPR
&& TYPE_NEEDS_DESTRUCTOR (TREE_TYPE (tmp)))
- return build_cplus_new (TREE_TYPE (tmp), tmp, 1);
+ return build_cplus_new (TREE_TYPE (tmp), tmp);
while (TREE_CODE (tmp) == NOP_EXPR
|| TREE_CODE (tmp) == CONVERT_EXPR
@@ -269,7 +304,7 @@ break_out_cleanups (exp)
{
TREE_OPERAND (tmp, 0)
= build_cplus_new (TREE_TYPE (TREE_OPERAND (tmp, 0)),
- TREE_OPERAND (tmp, 0), 1);
+ TREE_OPERAND (tmp, 0));
break;
}
else
@@ -286,7 +321,7 @@ tree
break_out_calls (exp)
tree exp;
{
- register tree t1, t2;
+ register tree t1, t2 = NULL_TREE;
register enum tree_code code;
register int changed = 0;
register int i;
@@ -299,7 +334,7 @@ break_out_calls (exp)
if (code == CALL_EXPR)
return copy_node (exp);
- /* Don't try and defeat a save_expr, as it should only be done once. */
+ /* Don't try and defeat a save_expr, as it should only be done once. */
if (code == SAVE_EXPR)
return exp;
@@ -372,6 +407,7 @@ break_out_calls (exp)
extern struct obstack *current_obstack;
extern struct obstack permanent_obstack, class_obstack;
extern struct obstack *saveable_obstack;
+extern struct obstack *expression_obstack;
/* Here is how primitive or already-canonicalized types' hash
codes are made. MUST BE CONSISTENT WITH tree.c !!! */
@@ -380,6 +416,7 @@ extern struct obstack *saveable_obstack;
/* Construct, lay out and return the type of methods belonging to class
BASETYPE and whose arguments are described by ARGTYPES and whose values
are described by RETTYPE. If each type exists already, reuse it. */
+
tree
build_cplus_method_type (basetype, rettype, argtypes)
tree basetype, rettype, argtypes;
@@ -418,34 +455,8 @@ build_cplus_method_type (basetype, rettype, argtypes)
return t;
}
-tree
-build_cplus_staticfn_type (basetype, rettype, argtypes)
- tree basetype, rettype, argtypes;
-{
- register tree t;
- int hashcode;
-
- /* Make a node of the sort we want. */
- t = make_node (FUNCTION_TYPE);
-
- TYPE_METHOD_BASETYPE (t) = TYPE_MAIN_VARIANT (basetype);
- TREE_TYPE (t) = rettype;
-
- TYPE_ARG_TYPES (t) = argtypes;
-
- /* If we already have such a type, use the old one and free this one.
- Note that it also frees up the above cons cell if found. */
- hashcode = TYPE_HASH (basetype) + TYPE_HASH (rettype) + type_hash_list (argtypes);
- t = type_hash_canon (hashcode, t);
-
- if (TYPE_SIZE (t) == 0)
- layout_type (t);
-
- return t;
-}
-
-tree
-build_cplus_array_type (elt_type, index_type)
+static tree
+build_cplus_array_type_1 (elt_type, index_type)
tree elt_type;
tree index_type;
{
@@ -462,7 +473,15 @@ build_cplus_array_type (elt_type, index_type)
saveable_obstack = &permanent_obstack;
}
- t = build_array_type (elt_type, index_type);
+ if (processing_template_decl
+ || uses_template_parms (index_type))
+ {
+ t = make_node (ARRAY_TYPE);
+ TREE_TYPE (t) = elt_type;
+ TYPE_DOMAIN (t) = index_type;
+ }
+ else
+ t = build_array_type (elt_type, index_type);
/* Push these needs up so that initialization takes place
more easily. */
@@ -472,6 +491,24 @@ build_cplus_array_type (elt_type, index_type)
saveable_obstack = ambient_saveable_obstack;
return t;
}
+
+tree
+build_cplus_array_type (elt_type, index_type)
+ tree elt_type;
+ tree index_type;
+{
+ tree t;
+ int constp = TYPE_READONLY (elt_type);
+ int volatilep = TYPE_VOLATILE (elt_type);
+ elt_type = TYPE_MAIN_VARIANT (elt_type);
+
+ t = build_cplus_array_type_1 (elt_type, index_type);
+
+ if (constp || volatilep)
+ t = cp_build_type_variant (t, constp, volatilep);
+
+ return t;
+}
/* Make a variant type in the proper way for C/C++, propagating qualifiers
down to the element type of an array. */
@@ -481,15 +518,18 @@ cp_build_type_variant (type, constp, volatilep)
tree type;
int constp, volatilep;
{
+ if (type == error_mark_node)
+ return type;
+
if (TREE_CODE (type) == ARRAY_TYPE)
{
tree real_main_variant = TYPE_MAIN_VARIANT (type);
push_obstacks (TYPE_OBSTACK (real_main_variant),
TYPE_OBSTACK (real_main_variant));
- type = build_cplus_array_type (cp_build_type_variant (TREE_TYPE (type),
- constp, volatilep),
- TYPE_DOMAIN (type));
+ type = build_cplus_array_type_1 (cp_build_type_variant
+ (TREE_TYPE (type), constp, volatilep),
+ TYPE_DOMAIN (type));
/* TYPE must be on same obstack as REAL_MAIN_VARIANT. If not,
make a copy. (TYPE might have come from the hash table and
@@ -503,9 +543,33 @@ cp_build_type_variant (type, constp, volatilep)
TYPE_MAIN_VARIANT (type) = real_main_variant;
pop_obstacks ();
+ return type;
}
return build_type_variant (type, constp, volatilep);
}
+
+/* Returns the canonical version of TYPE. In other words, if TYPE is
+ a typedef, returns the underlying type. The cv-qualification of
+ the type returned matches the type input; they will always be
+ compatible types. */
+
+tree
+canonical_type_variant (t)
+ tree t;
+{
+ int constp, volatilep;
+ if (TREE_CODE (t) == ARRAY_TYPE)
+ {
+ constp = TYPE_READONLY (TREE_TYPE (t));
+ volatilep = TYPE_VOLATILE (TREE_TYPE (t));
+ }
+ else
+ {
+ constp = TYPE_READONLY (t);
+ volatilep = TYPE_VOLATILE (t);
+ }
+ return cp_build_type_variant (TYPE_MAIN_VARIANT (t), constp, volatilep);
+}
/* Add OFFSET to all base types of T.
@@ -513,7 +577,8 @@ cp_build_type_variant (type, constp, volatilep)
Note that we don't have to worry about having two paths to the
same base type, since this type owns its association list. */
-void
+
+static void
propagate_binfo_offsets (binfo, offset)
tree binfo;
tree offset;
@@ -530,8 +595,7 @@ propagate_binfo_offsets (binfo, offset)
else
{
int j;
- tree base_binfos = BINFO_BASETYPES (base_binfo);
- tree delta;
+ tree delta = NULL_TREE;
for (j = i+1; j < n_baselinks; j++)
if (! TREE_VIA_VIRTUAL (TREE_VEC_ELT (binfos, j)))
@@ -553,31 +617,8 @@ propagate_binfo_offsets (binfo, offset)
#else
BINFO_OFFSET (base_binfo) = offset;
#endif
- if (base_binfos)
- {
- int k;
- tree chain = NULL_TREE;
-
- /* Now unshare the structure beneath BASE_BINFO. */
- for (k = TREE_VEC_LENGTH (base_binfos)-1;
- k >= 0; k--)
- {
- tree base_base_binfo = TREE_VEC_ELT (base_binfos, k);
- if (! TREE_VIA_VIRTUAL (base_base_binfo))
- TREE_VEC_ELT (base_binfos, k)
- = make_binfo (BINFO_OFFSET (base_base_binfo),
- base_base_binfo,
- BINFO_VTABLE (base_base_binfo),
- BINFO_VIRTUALS (base_base_binfo),
- chain);
- chain = TREE_VEC_ELT (base_binfos, k);
- TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo);
- TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo);
- BINFO_INHERITANCE_CHAIN (chain) = base_binfo;
- }
- /* Now propagate the offset to the base types. */
- propagate_binfo_offsets (base_binfo, offset);
- }
+
+ unshare_base_binfos (base_binfo);
/* Go to our next class that counts for offset propagation. */
i = j;
@@ -587,48 +628,82 @@ propagate_binfo_offsets (binfo, offset)
}
}
-/* Compute the actual offsets that our virtual base classes
- will have *for this type*. This must be performed after
- the fields are laid out, since virtual baseclasses must
- lay down at the end of the record.
+/* Makes new binfos for the indirect bases under BASE_BINFO, and updates
+ BINFO_OFFSET for them and their bases. */
+
+static void
+unshare_base_binfos (base_binfo)
+ tree base_binfo;
+{
+ if (BINFO_BASETYPES (base_binfo))
+ {
+ tree base_binfos = BINFO_BASETYPES (base_binfo);
+ tree chain = NULL_TREE;
+ int j;
+
+ /* Now unshare the structure beneath BASE_BINFO. */
+ for (j = TREE_VEC_LENGTH (base_binfos)-1;
+ j >= 0; j--)
+ {
+ tree base_base_binfo = TREE_VEC_ELT (base_binfos, j);
+ if (! TREE_VIA_VIRTUAL (base_base_binfo))
+ TREE_VEC_ELT (base_binfos, j)
+ = make_binfo (BINFO_OFFSET (base_base_binfo),
+ base_base_binfo,
+ BINFO_VTABLE (base_base_binfo),
+ BINFO_VIRTUALS (base_base_binfo),
+ chain);
+ chain = TREE_VEC_ELT (base_binfos, j);
+ TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo);
+ TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo);
+ BINFO_INHERITANCE_CHAIN (chain) = base_binfo;
+ }
- Returns the maximum number of virtual functions any of the virtual
+ /* Completely unshare potentially shared data, and
+ update what is ours. */
+ propagate_binfo_offsets (base_binfo, BINFO_OFFSET (base_binfo));
+ }
+}
+
+/* Finish the work of layout_record, now taking virtual bases into account.
+ Also compute the actual offsets that our base classes will have.
+ This must be performed after the fields are laid out, since virtual
+ baseclasses must lay down at the end of the record.
+
+ Returns the maximum number of virtual functions any of the
baseclasses provide. */
+
int
-layout_vbasetypes (rec, max)
+layout_basetypes (rec, max)
tree rec;
int max;
{
+ tree binfos = TYPE_BINFO_BASETYPES (rec);
+ int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
/* Get all the virtual base types that this type uses.
The TREE_VALUE slot holds the virtual baseclass type. */
tree vbase_types = get_vbase_types (rec);
+ unsigned int record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
+ unsigned int desired_align;
+
+ /* Record size so far is CONST_SIZE bits, where CONST_SIZE is an integer. */
+ register unsigned int const_size = 0;
+ unsigned int nonvirtual_const_size;
+
#ifdef STRUCTURE_SIZE_BOUNDARY
- unsigned record_align = MAX (STRUCTURE_SIZE_BOUNDARY, TYPE_ALIGN (rec));
-#else
- unsigned record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
+ /* Packed structures don't need to have minimum size. */
+ if (! TYPE_PACKED (rec))
+ record_align = MAX (record_align, STRUCTURE_SIZE_BOUNDARY);
#endif
- int desired_align;
-
- /* Record size so far is CONST_SIZE + VAR_SIZE bits,
- where CONST_SIZE is an integer
- and VAR_SIZE is a tree expression.
- If VAR_SIZE is null, the size is just CONST_SIZE.
- Naturally we try to avoid using VAR_SIZE. */
- register unsigned const_size = 0;
- register tree var_size = 0;
- int nonvirtual_const_size;
- tree nonvirtual_var_size;
CLASSTYPE_VBASECLASSES (rec) = vbase_types;
- if (TREE_CODE (TYPE_SIZE (rec)) == INTEGER_CST)
- const_size = TREE_INT_CST_LOW (TYPE_SIZE (rec));
- else
- var_size = TYPE_SIZE (rec);
+ my_friendly_assert (TREE_CODE (TYPE_SIZE (rec)) == INTEGER_CST, 19970302);
+ const_size = TREE_INT_CST_LOW (TYPE_SIZE (rec));
nonvirtual_const_size = const_size;
- nonvirtual_var_size = var_size;
while (vbase_types)
{
@@ -643,8 +718,7 @@ layout_vbasetypes (rec, max)
else
{
/* Give each virtual base type the alignment it wants. */
- const_size = CEIL (const_size, TYPE_ALIGN (basetype))
- * TYPE_ALIGN (basetype);
+ const_size = CEIL (const_size, desired_align) * desired_align;
offset = size_int (CEIL (const_size, BITS_PER_UNIT));
}
@@ -652,18 +726,10 @@ layout_vbasetypes (rec, max)
max = CLASSTYPE_VSIZE (basetype);
BINFO_OFFSET (vbase_types) = offset;
- if (TREE_CODE (TYPE_SIZE (basetype)) == INTEGER_CST)
- {
- /* Every virtual baseclass takes a least a UNIT, so that we can
- take it's address and get something different for each base. */
- const_size += MAX (BITS_PER_UNIT,
- TREE_INT_CST_LOW (TYPE_SIZE (basetype))
- - TREE_INT_CST_LOW (CLASSTYPE_VBASE_SIZE (basetype)));
- }
- else if (var_size == 0)
- var_size = TYPE_SIZE (basetype);
- else
- var_size = size_binop (PLUS_EXPR, var_size, TYPE_SIZE (basetype));
+ /* Every virtual baseclass takes a least a UNIT, so that we can
+ take it's address and get something different for each base. */
+ const_size += MAX (BITS_PER_UNIT,
+ TREE_INT_CST_LOW (CLASSTYPE_SIZE (basetype)));
vbase_types = TREE_CHAIN (vbase_types);
}
@@ -671,7 +737,7 @@ layout_vbasetypes (rec, max)
if (const_size)
{
/* Because a virtual base might take a single byte above,
- we have to re-adjust the total size to make sure it it
+ we have to re-adjust the total size to make sure it is
a multiple of the alignment. */
/* Give the whole object the alignment it wants. */
const_size = CEIL (const_size, record_align) * record_align;
@@ -682,117 +748,176 @@ layout_vbasetypes (rec, max)
TYPE_ALIGN (rec) = record_align;
if (const_size != nonvirtual_const_size)
{
- CLASSTYPE_VBASE_SIZE (rec)
- = size_int (const_size - nonvirtual_const_size);
TYPE_SIZE (rec) = size_int (const_size);
+ TYPE_SIZE_UNIT (rec) = size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (rec),
+ size_int (BITS_PER_UNIT));
+ }
+
+ /* Now propagate offset information throughout the lattice. */
+ for (i = 0; i < n_baseclasses; i++)
+ {
+ register tree base_binfo = TREE_VEC_ELT (binfos, i);
+ register tree basetype = BINFO_TYPE (base_binfo);
+ tree field = TYPE_FIELDS (rec);
+
+ if (TREE_VIA_VIRTUAL (base_binfo))
+ continue;
+
+ my_friendly_assert (TREE_TYPE (field) == basetype, 23897);
+ BINFO_OFFSET (base_binfo)
+ = size_int (CEIL (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field)),
+ BITS_PER_UNIT));
+ unshare_base_binfos (base_binfo);
+ TYPE_FIELDS (rec) = TREE_CHAIN (field);
}
- /* Now propagate offset information throughout the lattice
- under the vbase type. */
for (vbase_types = CLASSTYPE_VBASECLASSES (rec); vbase_types;
vbase_types = TREE_CHAIN (vbase_types))
{
- tree base_binfos = BINFO_BASETYPES (vbase_types);
-
BINFO_INHERITANCE_CHAIN (vbase_types) = TYPE_BINFO (rec);
+ unshare_base_binfos (vbase_types);
+ }
- if (base_binfos)
- {
- tree chain = NULL_TREE;
- int j;
- /* Now unshare the structure beneath BASE_BINFO. */
+ return max;
+}
- for (j = TREE_VEC_LENGTH (base_binfos)-1;
- j >= 0; j--)
- {
- tree base_base_binfo = TREE_VEC_ELT (base_binfos, j);
- if (! TREE_VIA_VIRTUAL (base_base_binfo))
- TREE_VEC_ELT (base_binfos, j)
- = make_binfo (BINFO_OFFSET (base_base_binfo),
- base_base_binfo,
- BINFO_VTABLE (base_base_binfo),
- BINFO_VIRTUALS (base_base_binfo),
- chain);
- chain = TREE_VEC_ELT (base_binfos, j);
- TREE_VIA_PUBLIC (chain) = TREE_VIA_PUBLIC (base_base_binfo);
- TREE_VIA_PROTECTED (chain) = TREE_VIA_PROTECTED (base_base_binfo);
- BINFO_INHERITANCE_CHAIN (chain) = vbase_types;
- }
+/* If the empty base field in DECL overlaps with a base of the same type in
+ NEWDECL, which is either another base field or the first data field of
+ the class, pad the base just before NEWDECL and return 1. Otherwise,
+ return 0. */
+
+static int
+avoid_overlap (decl, newdecl)
+ tree decl, newdecl;
+{
+ tree field;
+
+ if (newdecl == NULL_TREE
+ || ! types_overlap_p (TREE_TYPE (decl), TREE_TYPE (newdecl)))
+ return 0;
+
+ for (field = decl; TREE_CHAIN (field) && TREE_CHAIN (field) != newdecl;
+ field = TREE_CHAIN (field))
+ ;
+
+ DECL_SIZE (field) = integer_one_node;
+
+ return 1;
+}
- propagate_binfo_offsets (vbase_types, BINFO_OFFSET (vbase_types));
+/* Returns a list of fields to stand in for the base class subobjects
+ of REC. These fields are later removed by layout_basetypes. */
+
+tree
+build_base_fields (rec)
+ tree rec;
+{
+ /* Chain to hold all the new FIELD_DECLs which stand in for base class
+ subobjects. */
+ tree base_decls = NULL_TREE;
+ tree binfos = TYPE_BINFO_BASETYPES (rec);
+ int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ tree decl, nextdecl;
+ int i, saw_empty = 0;
+ unsigned int base_align = 0;
+
+ for (i = 0; i < n_baseclasses; ++i)
+ {
+ register tree base_binfo = TREE_VEC_ELT (binfos, i);
+ register tree basetype = BINFO_TYPE (base_binfo);
+
+ if (TYPE_SIZE (basetype) == 0)
+ /* This error is now reported in xref_tag, thus giving better
+ location information. */
+ continue;
+
+ if (TREE_VIA_VIRTUAL (base_binfo))
+ continue;
+
+ decl = build_lang_field_decl (FIELD_DECL, NULL_TREE, basetype);
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_FIELD_CONTEXT (decl) = DECL_CLASS_CONTEXT (decl) = rec;
+ DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype);
+ DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype);
+ TREE_CHAIN (decl) = base_decls;
+ base_decls = decl;
+
+ if (! flag_new_abi)
+ {
+ /* Brain damage for backwards compatibility. For no good reason,
+ the old layout_basetypes made every base at least as large as
+ the alignment for the bases up to that point, gratuitously
+ wasting space. So we do the same thing here. */
+ base_align = MAX (base_align, DECL_ALIGN (decl));
+ DECL_SIZE (decl)
+ = size_int (MAX (TREE_INT_CST_LOW (DECL_SIZE (decl)),
+ base_align));
}
+ else if (DECL_SIZE (decl) == integer_zero_node)
+ saw_empty = 1;
}
- return max;
-}
+ /* Reverse the list of fields so we allocate the bases in the proper
+ order. */
+ base_decls = nreverse (base_decls);
-/* Lay out the base types of a record type, REC.
- Tentatively set the size and alignment of REC
- according to the base types alone.
+ /* In the presence of empty base classes, we run the risk of allocating
+ two objects of the same class on top of one another. Avoid that. */
+ if (flag_new_abi && saw_empty)
+ for (decl = base_decls; decl; decl = TREE_CHAIN (decl))
+ {
+ if (DECL_SIZE (decl) == integer_zero_node)
+ {
+ /* First step through the following bases until we find
+ an overlap or a non-empty base. */
+ for (nextdecl = TREE_CHAIN (decl); nextdecl;
+ nextdecl = TREE_CHAIN (nextdecl))
+ {
+ if (avoid_overlap (decl, nextdecl)
+ || DECL_SIZE (nextdecl) != integer_zero_node)
+ goto nextbase;
+ }
+
+ /* If we're still looking, also check against the first
+ field. */
+ for (nextdecl = TYPE_FIELDS (rec);
+ nextdecl && TREE_CODE (nextdecl) != FIELD_DECL;
+ nextdecl = TREE_CHAIN (nextdecl))
+ /* keep looking */;
+ avoid_overlap (decl, nextdecl);
+ }
+ nextbase:;
+ }
- Offsets for immediate nonvirtual baseclasses are also computed here.
+ return base_decls;
+}
- TYPE_BINFO (REC) should be NULL_TREE on entry, and this routine
- creates a list of base_binfos in TYPE_BINFO (REC) from BINFOS.
+/* Returns list of virtual base class pointers in a FIELD_DECL chain. */
- Returns list of virtual base classes in a FIELD_DECL chain. */
tree
-layout_basetypes (rec, binfos)
- tree rec, binfos;
+build_vbase_pointer_fields (rec)
+ tree rec;
{
/* Chain to hold all the new FIELD_DECLs which point at virtual
base classes. */
tree vbase_decls = NULL_TREE;
-
-#ifdef STRUCTURE_SIZE_BOUNDARY
- unsigned record_align = MAX (STRUCTURE_SIZE_BOUNDARY, TYPE_ALIGN (rec));
-#else
- unsigned record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
-#endif
-
- /* Record size so far is CONST_SIZE + VAR_SIZE bits, where CONST_SIZE is
- an integer and VAR_SIZE is a tree expression. If VAR_SIZE is null,
- the size is just CONST_SIZE. Naturally we try to avoid using
- VAR_SIZE. And so far, we've been successful. */
-#if 0
- register tree var_size = 0;
-#endif
-
- register unsigned const_size = 0;
- int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ tree binfos = TYPE_BINFO_BASETYPES (rec);
+ int n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ tree decl;
+ int i;
/* Handle basetypes almost like fields, but record their
offsets differently. */
for (i = 0; i < n_baseclasses; i++)
{
- int inc, desired_align, int_vbase_size;
register tree base_binfo = TREE_VEC_ELT (binfos, i);
register tree basetype = BINFO_TYPE (base_binfo);
- tree decl, offset;
if (TYPE_SIZE (basetype) == 0)
- {
-#if 0
- /* This error is now reported in xref_tag, thus giving better
- location information. */
- error_with_aggr_type (base_binfo,
- "base class `%s' has incomplete type");
-
- TREE_VIA_PUBLIC (base_binfo) = 1;
- TREE_VIA_PROTECTED (base_binfo) = 0;
- TREE_VIA_VIRTUAL (base_binfo) = 0;
-
- /* Should handle this better so that
-
- class A;
- class B: private A { virtual void F(); };
-
- does not dump core when compiled. */
- my_friendly_abort (121);
-#endif
- continue;
- }
+ /* This error is now reported in xref_tag, thus giving better
+ location information. */
+ continue;
/* All basetypes are recorded in the association list of the
derived type. */
@@ -816,17 +941,20 @@ layout_basetypes (rec, binfos)
tree other_base_binfo = TREE_VEC_ELT (binfos, j);
if (! TREE_VIA_VIRTUAL (other_base_binfo)
&& binfo_member (basetype,
- CLASSTYPE_VBASECLASSES (BINFO_TYPE (other_base_binfo))))
+ CLASSTYPE_VBASECLASSES (BINFO_TYPE
+ (other_base_binfo))
+ ))
goto got_it;
}
sprintf (name, VBASE_NAME_FORMAT, TYPE_NAME_STRING (basetype));
- decl = build_lang_decl (FIELD_DECL, get_identifier (name),
- build_pointer_type (basetype));
+ decl = build_lang_field_decl (FIELD_DECL, get_identifier (name),
+ build_pointer_type (basetype));
/* If you change any of the below, take a look at all the
other VFIELD_BASEs and VTABLE_BASEs in the code, and change
- them too. */
+ them too. */
DECL_ASSEMBLER_NAME (decl) = get_identifier (VTABLE_BASE);
DECL_VIRTUAL_P (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
DECL_FIELD_CONTEXT (decl) = rec;
DECL_CLASS_CONTEXT (decl) = rec;
DECL_FCONTEXT (decl) = basetype;
@@ -837,78 +965,12 @@ layout_basetypes (rec, binfos)
BINFO_VPTR_FIELD (base_binfo) = decl;
vbase_decls = decl;
- if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (basetype)
- && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0)) == NULL_TREE)
- {
- warning_with_decl (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0),
- "destructor `%s' non-virtual");
- warning ("in inheritance relationship `%s: virtual %s'",
- TYPE_NAME_STRING (rec),
- TYPE_NAME_STRING (basetype));
- }
got_it:
/* The space this decl occupies has already been accounted for. */
- continue;
- }
-
- if (const_size == 0)
- offset = integer_zero_node;
- else
- {
- /* Give each base type the alignment it wants. */
- const_size = CEIL (const_size, TYPE_ALIGN (basetype))
- * TYPE_ALIGN (basetype);
- offset = size_int ((const_size + BITS_PER_UNIT - 1) / BITS_PER_UNIT);
-
-#if 0
- /* bpk: Disabled this check until someone is willing to
- claim it as theirs and explain exactly what circumstances
- warrant the warning. */
- if (warn_nonvdtor && TYPE_HAS_DESTRUCTOR (basetype)
- && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0)) == NULL_TREE)
- {
- warning_with_decl (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0),
- "destructor `%s' non-virtual");
- warning ("in inheritance relationship `%s:%s %s'",
- TYPE_NAME_STRING (rec),
- TREE_VIA_VIRTUAL (base_binfo) ? " virtual" : "",
- TYPE_NAME_STRING (basetype));
- }
-#endif
- }
- BINFO_OFFSET (base_binfo) = offset;
- if (CLASSTYPE_VSIZE (basetype))
- {
- BINFO_VTABLE (base_binfo) = TYPE_BINFO_VTABLE (basetype);
- BINFO_VIRTUALS (base_binfo) = TYPE_BINFO_VIRTUALS (basetype);
- }
- TREE_CHAIN (base_binfo) = TYPE_BINFO (rec);
- TYPE_BINFO (rec) = base_binfo;
-
- /* Add only the amount of storage not present in
- the virtual baseclasses. */
-
- int_vbase_size = TREE_INT_CST_LOW (CLASSTYPE_VBASE_SIZE (basetype));
- if (TREE_INT_CST_LOW (TYPE_SIZE (basetype)) > int_vbase_size)
- {
- inc = MAX (record_align,
- (TREE_INT_CST_LOW (TYPE_SIZE (basetype))
- - int_vbase_size));
-
- /* Record must have at least as much alignment as any field. */
- desired_align = TYPE_ALIGN (basetype);
- record_align = MAX (record_align, desired_align);
-
- const_size += inc;
+ ;
}
}
- if (const_size)
- CLASSTYPE_SIZE (rec) = size_int (const_size);
- else
- CLASSTYPE_SIZE (rec) = integer_zero_node;
- CLASSTYPE_ALIGN (rec) = record_align;
-
return vbase_decls;
}
@@ -932,27 +994,27 @@ struct list_hash
and the hash code is computed differently for each of these. */
#define TYPE_HASH_SIZE 59
-struct list_hash *list_hash_table[TYPE_HASH_SIZE];
+static struct list_hash *list_hash_table[TYPE_HASH_SIZE];
/* Compute a hash code for a list (chain of TREE_LIST nodes
with goodies in the TREE_PURPOSE, TREE_VALUE, and bits of the
TREE_COMMON slots), by adding the hash codes of the individual entries. */
-int
-list_hash (list)
- tree list;
+static int
+list_hash (purpose, value, chain)
+ tree purpose, value, chain;
{
register int hashcode = 0;
- if (TREE_CHAIN (list))
- hashcode += TYPE_HASH (TREE_CHAIN (list));
+ if (chain)
+ hashcode += TYPE_HASH (chain);
- if (TREE_VALUE (list))
- hashcode += TYPE_HASH (TREE_VALUE (list));
+ if (value)
+ hashcode += TYPE_HASH (value);
else
hashcode += 1007;
- if (TREE_PURPOSE (list))
- hashcode += TYPE_HASH (TREE_PURPOSE (list));
+ if (purpose)
+ hashcode += TYPE_HASH (purpose);
else
hashcode += 1009;
return hashcode;
@@ -961,31 +1023,30 @@ list_hash (list)
/* Look in the type hash table for a type isomorphic to TYPE.
If one is found, return it. Otherwise return 0. */
-tree
-list_hash_lookup (hashcode, list)
- int hashcode;
- tree list;
+static tree
+list_hash_lookup (hashcode, via_public, via_protected, via_virtual,
+ purpose, value, chain)
+ int hashcode, via_public, via_virtual, via_protected;
+ tree purpose, value, chain;
{
register struct list_hash *h;
+
for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
if (h->hashcode == hashcode
- && TREE_VIA_VIRTUAL (h->list) == TREE_VIA_VIRTUAL (list)
- && TREE_VIA_PUBLIC (h->list) == TREE_VIA_PUBLIC (list)
- && TREE_VIA_PROTECTED (h->list) == TREE_VIA_PROTECTED (list)
- && TREE_PURPOSE (h->list) == TREE_PURPOSE (list)
- && TREE_VALUE (h->list) == TREE_VALUE (list)
- && TREE_CHAIN (h->list) == TREE_CHAIN (list))
- {
- my_friendly_assert (TREE_TYPE (h->list) == TREE_TYPE (list), 299);
- return h->list;
- }
+ && TREE_VIA_VIRTUAL (h->list) == via_virtual
+ && TREE_VIA_PUBLIC (h->list) == via_public
+ && TREE_VIA_PROTECTED (h->list) == via_protected
+ && TREE_PURPOSE (h->list) == purpose
+ && TREE_VALUE (h->list) == value
+ && TREE_CHAIN (h->list) == chain)
+ return h->list;
return 0;
}
/* Add an entry to the list-hash-table
for a list TYPE whose hash code is HASHCODE. */
-void
+static void
list_hash_add (hashcode, list)
int hashcode;
tree list;
@@ -1011,30 +1072,8 @@ list_hash_add (hashcode, list)
This function frees the list you pass in if it is a duplicate. */
/* Set to 1 to debug without canonicalization. Never set by program. */
-static int debug_no_list_hash = 0;
-
-tree
-list_hash_canon (hashcode, list)
- int hashcode;
- tree list;
-{
- tree t1;
-
- if (debug_no_list_hash)
- return list;
-
- t1 = list_hash_lookup (hashcode, list);
- if (t1 != 0)
- {
- obstack_free (&class_obstack, list);
- return t1;
- }
- /* If this is a new list, record it for later reuse. */
- list_hash_add (hashcode, list);
-
- return list;
-}
+static int debug_no_list_hash = 0;
tree
hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain)
@@ -1043,37 +1082,43 @@ hash_tree_cons (via_public, via_virtual, via_protected, purpose, value, chain)
{
struct obstack *ambient_obstack = current_obstack;
tree t;
- int hashcode;
+ int hashcode = 0;
+
+ if (! debug_no_list_hash)
+ {
+ hashcode = list_hash (purpose, value, chain);
+ t = list_hash_lookup (hashcode, via_public, via_protected, via_virtual,
+ purpose, value, chain);
+ if (t)
+ return t;
+ }
current_obstack = &class_obstack;
+
t = tree_cons (purpose, value, chain);
TREE_VIA_PUBLIC (t) = via_public;
TREE_VIA_PROTECTED (t) = via_protected;
TREE_VIA_VIRTUAL (t) = via_virtual;
- hashcode = list_hash (t);
- t = list_hash_canon (hashcode, t);
+
+ /* If this is a new list, record it for later reuse. */
+ if (! debug_no_list_hash)
+ list_hash_add (hashcode, t);
+
current_obstack = ambient_obstack;
return t;
}
/* Constructor for hashed lists. */
+
tree
hash_tree_chain (value, chain)
tree value, chain;
{
- struct obstack *ambient_obstack = current_obstack;
- tree t;
- int hashcode;
-
- current_obstack = &class_obstack;
- t = tree_cons (NULL_TREE, value, chain);
- hashcode = list_hash (t);
- t = list_hash_canon (hashcode, t);
- current_obstack = ambient_obstack;
- return t;
+ return hash_tree_cons (0, 0, 0, NULL_TREE, value, chain);
}
/* Similar, but used for concatenating two lists. */
+
tree
hash_chainon (list1, list2)
tree list1, list2;
@@ -1111,17 +1156,9 @@ get_identifier_list (value)
list = tree_cons (NULL_TREE, value, NULL_TREE);
else
{
- register tree id;
- /* This will return the correct thing for regular types,
- nested types, and templates. Yay! */
- if (TYPE_NESTED_NAME (type))
- id = TYPE_NESTED_NAME (type);
- else
- id = TYPE_IDENTIFIER (type);
-
- if (CLASSTYPE_ID_AS_LIST (type) == NULL_TREE)
+ if (! CLASSTYPE_ID_AS_LIST (type))
CLASSTYPE_ID_AS_LIST (type)
- = perm_tree_cons (NULL_TREE, id, NULL_TREE);
+ = perm_tree_cons (NULL_TREE, TYPE_IDENTIFIER (type), NULL_TREE);
list = CLASSTYPE_ID_AS_LIST (type);
}
}
@@ -1137,7 +1174,8 @@ get_decl_list (value)
if (TREE_CODE (value) == IDENTIFIER_NODE)
list = get_identifier_list (value);
else if (TREE_CODE (value) == RECORD_TYPE
- && TYPE_LANG_SPECIFIC (value))
+ && TYPE_LANG_SPECIFIC (value)
+ && value == TYPE_MAIN_VARIANT (value))
list = CLASSTYPE_AS_LIST (value);
if (list != NULL_TREE)
@@ -1148,59 +1186,6 @@ get_decl_list (value)
return build_decl_list (NULL_TREE, value);
}
-
-/* Look in the type hash table for a type isomorphic to
- `build_tree_list (NULL_TREE, VALUE)'.
- If one is found, return it. Otherwise return 0. */
-
-tree
-list_hash_lookup_or_cons (value)
- tree value;
-{
- register int hashcode = TYPE_HASH (value);
- register struct list_hash *h;
- struct obstack *ambient_obstack;
- tree list = NULL_TREE;
-
- if (TREE_CODE (value) == IDENTIFIER_NODE)
- list = get_identifier_list (value);
- else if (TREE_CODE (value) == TYPE_DECL
- && TREE_CODE (TREE_TYPE (value)) == RECORD_TYPE
- && TYPE_LANG_SPECIFIC (TREE_TYPE (value)))
- list = CLASSTYPE_ID_AS_LIST (TREE_TYPE (value));
- else if (TREE_CODE (value) == RECORD_TYPE
- && TYPE_LANG_SPECIFIC (value))
- list = CLASSTYPE_AS_LIST (value);
-
- if (list != NULL_TREE)
- {
- my_friendly_assert (TREE_CHAIN (list) == NULL_TREE, 302);
- return list;
- }
-
- if (debug_no_list_hash)
- return hash_tree_chain (value, NULL_TREE);
-
- for (h = list_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
- if (h->hashcode == hashcode
- && TREE_VIA_VIRTUAL (h->list) == 0
- && TREE_VIA_PUBLIC (h->list) == 0
- && TREE_VIA_PROTECTED (h->list) == 0
- && TREE_PURPOSE (h->list) == 0
- && TREE_VALUE (h->list) == value)
- {
- my_friendly_assert (TREE_TYPE (h->list) == 0, 303);
- my_friendly_assert (TREE_CHAIN (h->list) == 0, 304);
- return h->list;
- }
-
- ambient_obstack = current_obstack;
- current_obstack = &class_obstack;
- list = build_tree_list (NULL_TREE, value);
- list_hash_add (hashcode, list);
- current_obstack = ambient_obstack;
- return list;
-}
/* Build an association between TYPE and some parameters:
@@ -1210,7 +1195,7 @@ list_hash_lookup_or_cons (value)
BINFO is the base binfo to use, if we are deriving from one. This
is necessary, as we want specialized parent binfos from base
classes, so that the VTABLE_NAMEs of bases are for the most derived
- type, instead of of the simple type.
+ type, instead of the simple type.
VTABLE is the virtual function table with which to initialize
sub-objects of type TYPE.
@@ -1225,7 +1210,7 @@ make_binfo (offset, binfo, vtable, virtuals, chain)
tree vtable, virtuals;
tree chain;
{
- tree new_binfo = make_tree_vec (6);
+ tree new_binfo = make_tree_vec (7);
tree type;
if (TREE_CODE (binfo) == TREE_VEC)
@@ -1282,38 +1267,6 @@ reverse_path (path)
return prev;
}
-tree
-virtual_member (elem, list)
- tree elem;
- tree list;
-{
- tree t;
- tree rval, nval;
-
- for (t = list; t; t = TREE_CHAIN (t))
- if (elem == BINFO_TYPE (t))
- return t;
- rval = 0;
- for (t = list; t; t = TREE_CHAIN (t))
- {
- tree binfos = BINFO_BASETYPES (t);
- int i;
-
- if (binfos != NULL_TREE)
- for (i = TREE_VEC_LENGTH (binfos)-1; i >= 0; i--)
- {
- nval = binfo_value (elem, BINFO_TYPE (TREE_VEC_ELT (binfos, i)));
- if (nval)
- {
- if (rval && BINFO_OFFSET (nval) != BINFO_OFFSET (rval))
- my_friendly_abort (104);
- rval = nval;
- }
- }
- }
- return rval;
-}
-
void
debug_binfo (elem)
tree elem;
@@ -1321,9 +1274,9 @@ debug_binfo (elem)
unsigned HOST_WIDE_INT n;
tree virtuals;
- fprintf (stderr, "type \"%s\"; offset = %d\n",
+ fprintf (stderr, "type \"%s\"; offset = %ld\n",
TYPE_NAME_STRING (BINFO_TYPE (elem)),
- TREE_INT_CST_LOW (BINFO_OFFSET (elem)));
+ (long) TREE_INT_CST_LOW (BINFO_OFFSET (elem)));
fprintf (stderr, "vtable type:\n");
debug_tree (BINFO_TYPE (elem));
if (BINFO_VTABLE (elem))
@@ -1338,142 +1291,168 @@ debug_binfo (elem)
while (virtuals)
{
tree fndecl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0);
- fprintf (stderr, "%s [%d =? %d]\n",
+ fprintf (stderr, "%s [%ld =? %ld]\n",
IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)),
- n, TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
+ (long) n, (long) TREE_INT_CST_LOW (DECL_VINDEX (fndecl)));
++n;
virtuals = TREE_CHAIN (virtuals);
}
}
-/* Return the length of a chain of nodes chained through DECL_CHAIN.
- We expect a null pointer to mark the end of the chain.
- This is the Lisp primitive `length'. */
+/* Initialize an CPLUS_BINDING node that does not live on an obstack. */
-int
-decl_list_length (t)
- tree t;
+tree
+binding_init (node)
+ struct tree_binding* node;
{
- register tree tail;
- register int len = 0;
-
- my_friendly_assert (TREE_CODE (t) == FUNCTION_DECL
- || TREE_CODE (t) == TEMPLATE_DECL, 300);
- for (tail = t; tail; tail = DECL_CHAIN (tail))
- len++;
-
- return len;
+ static struct tree_binding* source;
+ if (!source)
+ {
+ extern struct obstack permanent_obstack;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ source = (struct tree_binding*)make_node (CPLUS_BINDING);
+ pop_obstacks ();
+ }
+ *node = *source;
+ TREE_PERMANENT ((tree)node) = 0;
+ return (tree)node;
}
int
count_functions (t)
tree t;
{
+ int i;
if (TREE_CODE (t) == FUNCTION_DECL)
return 1;
- else if (TREE_CODE (t) == TREE_LIST)
- return decl_list_length (TREE_VALUE (t));
+ else if (TREE_CODE (t) == OVERLOAD)
+ {
+ for (i=0; t; t = OVL_CHAIN (t))
+ i++;
+ return i;
+ }
my_friendly_abort (359);
return 0;
}
-/* Like value_member, but for DECL_CHAINs. */
-tree
-decl_value_member (elem, list)
- tree elem, list;
-{
- while (list)
- {
- if (elem == list)
- return list;
- list = DECL_CHAIN (list);
- }
- return NULL_TREE;
-}
-
int
is_overloaded_fn (x)
tree x;
{
- if (TREE_CODE (x) == FUNCTION_DECL)
- return 1;
-
- if (TREE_CODE (x) == TREE_LIST
- && (TREE_CODE (TREE_VALUE (x)) == FUNCTION_DECL
- || TREE_CODE (TREE_VALUE (x)) == TEMPLATE_DECL))
- return 1;
-
- return 0;
+ /* XXX A baselink is also considered an overloaded function.
+ As is a placeholder from push_class_decls. */
+ if (TREE_CODE (x) == TREE_LIST)
+ {
+ my_friendly_assert (TREE_CODE (TREE_PURPOSE (x)) == TREE_VEC
+ || TREE_CODE (TREE_PURPOSE (x)) == IDENTIFIER_NODE,
+ 388);
+ x = TREE_VALUE (x);
+ }
+ return (TREE_CODE (x) == FUNCTION_DECL
+ || TREE_CODE (x) == TEMPLATE_ID_EXPR
+ || DECL_FUNCTION_TEMPLATE_P (x)
+ || TREE_CODE (x) == OVERLOAD);
}
int
really_overloaded_fn (x)
tree x;
{
- if (TREE_CODE (x) == TREE_LIST
- && (TREE_CODE (TREE_VALUE (x)) == FUNCTION_DECL
- || TREE_CODE (TREE_VALUE (x)) == TEMPLATE_DECL))
- return 1;
-
- return 0;
+ /* A baselink is also considered an overloaded function.
+ This might also be an ambiguous class member. */
+ if (TREE_CODE (x) == TREE_LIST)
+ x = TREE_VALUE (x);
+ return (TREE_CODE (x) == OVERLOAD
+ && (TREE_CHAIN (x) != NULL_TREE
+ || DECL_FUNCTION_TEMPLATE_P (OVL_FUNCTION (x))));
}
tree
get_first_fn (from)
tree from;
{
- if (TREE_CODE (from) == FUNCTION_DECL)
- return from;
+ my_friendly_assert (is_overloaded_fn (from), 9);
+ /* A baselink is also considered an overloaded function. */
+ if (TREE_CODE (from) == TREE_LIST)
+ from = TREE_VALUE (from);
+ return OVL_CURRENT (from);
+}
- my_friendly_assert (TREE_CODE (from) == TREE_LIST, 9);
+/* Return a new OVL node, concatenating it with the old one. */
+
+tree
+ovl_cons (decl, chain)
+ tree decl;
+ tree chain;
+{
+ tree result = make_node (OVERLOAD);
+ TREE_TYPE (result) = unknown_type_node;
+ OVL_FUNCTION (result) = decl;
+ TREE_CHAIN (result) = chain;
- return TREE_VALUE (from);
+ return result;
}
+/* Same as ovl_cons, but on the scratch_obstack. */
+
tree
-fnaddr_from_vtable_entry (entry)
- tree entry;
+scratch_ovl_cons (value, chain)
+ tree value, chain;
{
- if (flag_vtable_thunks)
- {
- tree func = entry;
- if (TREE_CODE (func) == ADDR_EXPR)
- func = TREE_OPERAND (func, 0);
- if (TREE_CODE (func) == THUNK_DECL)
- return DECL_INITIAL (func);
- else
- return entry;
- }
- else
- return TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (entry))));
+ register tree node;
+ register struct obstack *ambient_obstack = current_obstack;
+ extern struct obstack *expression_obstack;
+ current_obstack = expression_obstack;
+ node = ovl_cons (value, chain);
+ current_obstack = ambient_obstack;
+ return node;
}
-void
-set_fnaddr_from_vtable_entry (entry, value)
- tree entry, value;
+/* Build a new overloaded function. If this is the first one,
+ just return it; otherwise, ovl_cons the _DECLs */
+
+tree
+build_overload (decl, chain)
+ tree decl;
+ tree chain;
{
- if (flag_vtable_thunks)
- abort ();
- else
- TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (entry)))) = value;
+ if (!chain)
+ return decl;
+ if (TREE_CODE (chain) != OVERLOAD)
+ chain = ovl_cons (chain, NULL_TREE);
+ return ovl_cons (decl, chain);
}
-tree
-function_arg_chain (t)
- tree t;
+/* Returns true iff functions are equivalent. Equivalent functions are
+ not identical only if one is a function-local extern function.
+ This assumes that function-locals don't have TREE_PERMANENT. */
+
+static int
+equal_functions (fn1, fn2)
+ tree fn1;
+ tree fn2;
{
- return TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (t)));
+ if (!TREE_PERMANENT (fn1) || !TREE_PERMANENT (fn2))
+ return decls_match (fn1, fn2);
+ return fn1 == fn2;
}
+/* True if fn is in ovl. */
+
int
-promotes_to_aggr_type (t, code)
- tree t;
- enum tree_code code;
+ovl_member (fn, ovl)
+ tree fn;
+ tree ovl;
{
- if (TREE_CODE (t) == code)
- t = TREE_TYPE (t);
- return IS_AGGR_TYPE (t);
+ if (ovl == NULL_TREE)
+ return 0;
+ if (TREE_CODE (ovl) != OVERLOAD)
+ return equal_functions (ovl, fn);
+ for (; ovl; ovl = OVL_CHAIN (ovl))
+ if (equal_functions (OVL_FUNCTION (ovl), fn))
+ return 1;
+ return 0;
}
int
@@ -1484,30 +1463,13 @@ is_aggr_type_2 (t1, t2)
return 0;
return IS_AGGR_TYPE (t1) && IS_AGGR_TYPE (t2);
}
-
-/* Give message using types TYPE1 and TYPE2 as arguments.
- PFN is the function which will print the message;
- S is the format string for PFN to use. */
-void
-message_2_types (pfn, s, type1, type2)
- void (*pfn) ();
- char *s;
- tree type1, type2;
-{
- tree name1 = TYPE_NAME (type1);
- tree name2 = TYPE_NAME (type2);
- if (TREE_CODE (name1) == TYPE_DECL)
- name1 = DECL_NAME (name1);
- if (TREE_CODE (name2) == TYPE_DECL)
- name2 = DECL_NAME (name2);
- (*pfn) (s, IDENTIFIER_POINTER (name1), IDENTIFIER_POINTER (name2));
-}
#define PRINT_RING_SIZE 4
char *
-lang_printable_name (decl)
+lang_printable_name (decl, v)
tree decl;
+ int v;
{
static tree decl_ring[PRINT_RING_SIZE];
static char *print_ring[PRINT_RING_SIZE];
@@ -1515,9 +1477,10 @@ lang_printable_name (decl)
int i;
/* Only cache functions. */
- if (TREE_CODE (decl) != FUNCTION_DECL
+ if (v < 2
+ || TREE_CODE (decl) != FUNCTION_DECL
|| DECL_LANG_SPECIFIC (decl) == 0)
- return decl_as_string (decl, 1);
+ return lang_decl_name (decl, v);
/* See if this print name is lying around. */
for (i = 0; i < PRINT_RING_SIZE; i++)
@@ -1541,50 +1504,30 @@ lang_printable_name (decl)
if (print_ring[ring_counter])
free (print_ring[ring_counter]);
- {
- int print_ret_type_p
- = (!DECL_CONSTRUCTOR_P (decl)
- && !DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (decl)));
-
- char *name = (char *)decl_as_string (decl, print_ret_type_p);
- print_ring[ring_counter] = (char *)malloc (strlen (name) + 1);
- strcpy (print_ring[ring_counter], name);
- decl_ring[ring_counter] = decl;
- }
+ print_ring[ring_counter] = xstrdup (lang_decl_name (decl, v));
+ decl_ring[ring_counter] = decl;
return print_ring[ring_counter];
}
-/* Comparison function for sorting identifiers in RAISES lists.
- Note that because IDENTIFIER_NODEs are unique, we can sort
- them by address, saving an indirection. */
-static int
-id_cmp (p1, p2)
- tree *p1, *p2;
-{
- return (HOST_WIDE_INT)TREE_VALUE (*p1) - (HOST_WIDE_INT)TREE_VALUE (*p2);
-}
-
/* Build the FUNCTION_TYPE or METHOD_TYPE which may throw exceptions
listed in RAISES. */
+
tree
build_exception_variant (type, raises)
tree type;
tree raises;
{
- int i;
tree v = TYPE_MAIN_VARIANT (type);
- tree t, t2, cname;
- tree *a = (tree *)alloca ((list_length (raises)+1) * sizeof (tree));
int constp = TYPE_READONLY (type);
int volatilep = TYPE_VOLATILE (type);
- for (v = TYPE_NEXT_VARIANT (v); v; v = TYPE_NEXT_VARIANT (v))
+ for (; v; v = TYPE_NEXT_VARIANT (v))
{
if (TYPE_READONLY (v) != constp
|| TYPE_VOLATILE (v) != volatilep)
continue;
- /* @@ This should do set equality, not exact match. */
+ /* @@ This should do set equality, not exact match. */
if (simple_cst_list_equal (TYPE_RAISES_EXCEPTIONS (v), raises))
/* List of exceptions raised matches previously found list.
@@ -1594,9 +1537,8 @@ build_exception_variant (type, raises)
}
/* Need to build a new variant. */
- v = copy_node (type);
- TYPE_NEXT_VARIANT (v) = TYPE_NEXT_VARIANT (type);
- TYPE_NEXT_VARIANT (type) = v;
+ v = build_type_copy (type);
+
if (raises && ! TREE_PERMANENT (raises))
{
push_obstacks_nochange ();
@@ -1604,10 +1546,32 @@ build_exception_variant (type, raises)
raises = copy_list (raises);
pop_obstacks ();
}
+
TYPE_RAISES_EXCEPTIONS (v) = raises;
return v;
}
+/* Given a TEMPLATE_TEMPLATE_PARM node T, create a new one together with its
+ lang_specific field and its corresponding TEMPLATE_DECL node */
+
+tree
+copy_template_template_parm (t)
+ tree t;
+{
+ tree template = TYPE_NAME (t);
+ tree t2 = make_lang_type (TEMPLATE_TEMPLATE_PARM);
+ template = copy_node (template);
+ copy_lang_decl (template);
+ TREE_TYPE (template) = t2;
+ TYPE_NAME (t2) = template;
+ TYPE_STUB_DECL (t2) = template;
+
+ /* No need to copy these */
+ TYPE_FIELDS (t2) = TYPE_FIELDS (t);
+ CLASSTYPE_TEMPLATE_INFO (t2) = CLASSTYPE_TEMPLATE_INFO (t);
+ return t2;
+}
+
/* Subroutine of copy_to_permanent
Assuming T is a node build bottom-up, make it all exist on
@@ -1616,9 +1580,8 @@ build_exception_variant (type, raises)
tree
mapcar (t, func)
tree t;
- tree (*func)();
+ tree (*func) PROTO((tree));
{
- enum tree_code code;
tree tmp;
if (t == NULL_TREE)
@@ -1627,7 +1590,7 @@ mapcar (t, func)
if (tmp = func (t), tmp != NULL_TREE)
return tmp;
- switch (code = TREE_CODE (t))
+ switch (TREE_CODE (t))
{
case ERROR_MARK:
return error_mark_node;
@@ -1635,7 +1598,21 @@ mapcar (t, func)
case VAR_DECL:
case FUNCTION_DECL:
case CONST_DECL:
- break;
+ /* Rather than aborting, return error_mark_node. This allows us
+ to report a sensible error message on code like this:
+
+ void g() { int i; f<i>(7); }
+
+ In a case like:
+
+ void g() { const int i = 7; f<i>(7); }
+
+ however, we must actually return the constant initializer. */
+ tmp = decl_constant_value (t);
+ if (tmp != t)
+ return mapcar (tmp, func);
+ else
+ return error_mark_node;
case PARM_DECL:
{
@@ -1658,6 +1635,15 @@ mapcar (t, func)
return t;
}
+ case OVERLOAD:
+ {
+ tree chain = OVL_CHAIN (t);
+ t = copy_node (t);
+ OVL_FUNCTION (t) = mapcar (OVL_FUNCTION (t), func);
+ OVL_CHAIN (t) = mapcar (chain, func);
+ return t;
+ }
+
case TREE_VEC:
{
int len = TREE_VEC_LENGTH (t);
@@ -1675,7 +1661,7 @@ mapcar (t, func)
case COND_EXPR:
case TARGET_EXPR:
- case NEW_EXPR:
+ case AGGR_INIT_EXPR:
t = copy_node (t);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
@@ -1720,10 +1706,28 @@ mapcar (t, func)
case PREINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
case POSTINCREMENT_EXPR:
+ case ARRAY_REF:
+ case SCOPE_REF:
+ case TRY_CATCH_EXPR:
+ case WITH_CLEANUP_EXPR:
+ t = copy_node (t);
+ TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+ TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
+ return t;
+
case CALL_EXPR:
t = copy_node (t);
+ TREE_TYPE (t) = mapcar (TREE_TYPE (t), func);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
+
+ /* tree.def says that operand two is RTL, but
+ build_call_declarator puts trees in there. */
+ if (TREE_OPERAND (t, 2)
+ && TREE_CODE (TREE_OPERAND (t, 2)) == TREE_LIST)
+ TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
+ else
+ TREE_OPERAND (t, 2) = NULL_TREE;
return t;
case CONVERT_EXPR:
@@ -1734,32 +1738,66 @@ mapcar (t, func)
case TRUTH_NOT_EXPR:
case NOP_EXPR:
case COMPONENT_REF:
+ case CLEANUP_POINT_EXPR:
t = copy_node (t);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
return t;
case POINTER_TYPE:
- return build_pointer_type (mapcar (TREE_TYPE (t), func));
+ tmp = build_pointer_type (mapcar (TREE_TYPE (t), func));
+ return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
case REFERENCE_TYPE:
- return build_reference_type (mapcar (TREE_TYPE (t), func));
+ tmp = build_reference_type (mapcar (TREE_TYPE (t), func));
+ return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
case FUNCTION_TYPE:
- return build_function_type (mapcar (TREE_TYPE (t), func),
- mapcar (TYPE_ARG_TYPES (t), func));
+ tmp = build_function_type (mapcar (TREE_TYPE (t), func),
+ mapcar (TYPE_ARG_TYPES (t), func));
+ return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
case ARRAY_TYPE:
- return build_array_type (mapcar (TREE_TYPE (t), func),
- mapcar (TYPE_DOMAIN (t), func));
+ tmp = build_cplus_array_type (mapcar (TREE_TYPE (t), func),
+ mapcar (TYPE_DOMAIN (t), func));
+ return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
case INTEGER_TYPE:
- return build_index_type (mapcar (TYPE_MAX_VALUE (t), func));
-
+ tmp = build_index_type (mapcar (TYPE_MAX_VALUE (t), func));
+ return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
case OFFSET_TYPE:
- return build_offset_type (mapcar (TYPE_OFFSET_BASETYPE (t), func),
- mapcar (TREE_TYPE (t), func));
+ tmp = build_offset_type (mapcar (TYPE_OFFSET_BASETYPE (t), func),
+ mapcar (TREE_TYPE (t), func));
+ return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
case METHOD_TYPE:
- return build_method_type
- (mapcar (TYPE_METHOD_BASETYPE (t), func),
- build_function_type
- (mapcar (TREE_TYPE (t), func),
- mapcar (TREE_CHAIN (TYPE_ARG_TYPES (t)), func)));
+ tmp = build_cplus_method_type
+ (mapcar (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))), func),
+ mapcar (TREE_TYPE (t), func),
+ mapcar (TREE_CHAIN (TYPE_ARG_TYPES (t)), func));
+ return cp_build_type_variant (tmp, TYPE_READONLY (t), TYPE_VOLATILE (t));
+
+ case COMPLEX_CST:
+ t = copy_node (t);
+ TREE_REALPART (t) = mapcar (TREE_REALPART (t), func);
+ TREE_IMAGPART (t) = mapcar (TREE_REALPART (t), func);
+ return t;
+
+ case CONSTRUCTOR:
+ t = copy_node (t);
+ CONSTRUCTOR_ELTS (t) = mapcar (CONSTRUCTOR_ELTS (t), func);
+ return t;
+
+ case TEMPLATE_TEMPLATE_PARM:
+ return copy_template_template_parm (t);
+
+ case BIND_EXPR:
+ t = copy_node (t);
+ TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+ TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
+ TREE_OPERAND (t, 2) = NULL_TREE;
+ return t;
+
+ case NEW_EXPR:
+ t = copy_node (t);
+ TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
+ TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
+ TREE_OPERAND (t, 2) = mapcar (TREE_OPERAND (t, 2), func);
+ return t;
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (t))
@@ -1768,7 +1806,7 @@ mapcar (t, func)
/* else fall through */
/* This list is incomplete, but should suffice for now.
- It is very important that `sorry' does not call
+ It is very important that `sorry' not call
`report_error_function'. That could cause an infinite loop. */
default:
sorry ("initializer contains unrecognized tree code");
@@ -1786,50 +1824,65 @@ perm_manip (t)
{
if (TREE_PERMANENT (t))
return t;
+
+ /* Support `void f () { extern int i; A<&i> a; }' */
+ if ((TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL)
+ && TREE_PUBLIC (t))
+ {
+ t = copy_node (t);
+
+ /* copy_rtx won't make a new SYMBOL_REF, so call make_decl_rtl again. */
+ DECL_RTL (t) = 0;
+ make_decl_rtl (t, NULL_PTR, 1);
+
+ return t;
+ }
return NULL_TREE;
}
/* Assuming T is a node built bottom-up, make it all exist on
permanent obstack, if it is not permanent already. */
+
tree
copy_to_permanent (t)
tree t;
{
- register struct obstack *ambient_obstack = current_obstack;
- register struct obstack *ambient_saveable_obstack = saveable_obstack;
- int resume;
-
if (t == NULL_TREE || TREE_PERMANENT (t))
return t;
- saveable_obstack = &permanent_obstack;
- current_obstack = saveable_obstack;
- resume = suspend_momentary ();
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
t = mapcar (t, perm_manip);
- resume_momentary (resume);
- current_obstack = ambient_obstack;
- saveable_obstack = ambient_saveable_obstack;
+ pop_obstacks ();
return t;
}
+#ifdef GATHER_STATISTICS
+extern int depth_reached;
+#endif
+
void
print_lang_statistics ()
{
- extern struct obstack maybepermanent_obstack;
+ extern struct obstack decl_obstack;
print_obstack_statistics ("class_obstack", &class_obstack);
- print_obstack_statistics ("permanent_obstack", &permanent_obstack);
- print_obstack_statistics ("maybepermanent_obstack", &maybepermanent_obstack);
+ print_obstack_statistics ("decl_obstack", &decl_obstack);
print_search_statistics ();
print_class_statistics ();
+#ifdef GATHER_STATISTICS
+ fprintf (stderr, "maximum template instantiation depth reached: %d\n",
+ depth_reached);
+#endif
}
/* This is used by the `assert' macro. It is provided in libgcc.a,
which `cc' doesn't know how to link. Note that the C++ front-end
no longer actually uses the `assert' macro (instead, it calls
my_friendly_assert). But all of the back-end files still need this. */
+
void
__eprintf (string, expression, line, filename)
#ifdef __STDC__
@@ -1849,8 +1902,9 @@ __eprintf (string, expression, line, filename)
abort ();
}
-/* Return, as an INTEGER_CST node, the number of elements for
- TYPE (which is an ARRAY_TYPE). This counts only elements of the top array. */
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+ (which is an ARRAY_TYPE). This counts only elements of the top
+ array. */
tree
array_type_nelts_top (type)
@@ -1861,9 +1915,9 @@ array_type_nelts_top (type)
integer_one_node));
}
-/* Return, as an INTEGER_CST node, the number of elements for
- TYPE (which is an ARRAY_TYPE). This one is a recursive count of all
- ARRAY_TYPEs that are clumped together. */
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+ (which is an ARRAY_TYPE). This one is a recursive count of all
+ ARRAY_TYPEs that are clumped together. */
tree
array_type_nelts_total (type)
@@ -1888,12 +1942,26 @@ bot_manip (t)
if (TREE_CODE (t) != TREE_LIST && ! TREE_SIDE_EFFECTS (t))
return t;
else if (TREE_CODE (t) == TARGET_EXPR)
- return build_cplus_new (TREE_TYPE (t),
- break_out_target_exprs (TREE_OPERAND (t, 1)), 0);
+ {
+ if (TREE_CODE (TREE_OPERAND (t, 1)) == AGGR_INIT_EXPR)
+ {
+ mark_used (TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 1), 0), 0));
+ return build_cplus_new
+ (TREE_TYPE (t), break_out_target_exprs (TREE_OPERAND (t, 1)));
+ }
+ t = copy_node (t);
+ TREE_OPERAND (t, 0) = build (VAR_DECL, TREE_TYPE (t));
+ layout_decl (TREE_OPERAND (t, 0), 0);
+ return t;
+ }
+ else if (TREE_CODE (t) == CALL_EXPR)
+ mark_used (TREE_OPERAND (TREE_OPERAND (t, 0), 0));
+
return NULL_TREE;
}
/* Actually, we'll just clean out the target exprs for the moment. */
+
tree
break_out_target_exprs (t)
tree t;
@@ -1901,95 +1969,456 @@ break_out_target_exprs (t)
return mapcar (t, bot_manip);
}
+/* Obstack used for allocating nodes in template function and variable
+ definitions. */
+
+/* Similar to `build_nt', except we build
+ on the permanent_obstack, regardless. */
+
tree
-unsave_expr (expr)
- tree expr;
+build_min_nt VPROTO((enum tree_code code, ...))
{
- tree t;
+#ifndef __STDC__
+ enum tree_code code;
+#endif
+ register struct obstack *ambient_obstack = expression_obstack;
+ va_list p;
+ register tree t;
+ register int length;
+ register int i;
+
+ VA_START (p, code);
+
+#ifndef __STDC__
+ code = va_arg (p, enum tree_code);
+#endif
- t = build1 (UNSAVE_EXPR, TREE_TYPE (expr), expr);
- TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (expr);
+ expression_obstack = &permanent_obstack;
+
+ t = make_node (code);
+ length = tree_code_length[(int) code];
+ TREE_COMPLEXITY (t) = lineno;
+
+ for (i = 0; i < length; i++)
+ {
+ tree x = va_arg (p, tree);
+ TREE_OPERAND (t, i) = copy_to_permanent (x);
+ }
+
+ va_end (p);
+ expression_obstack = ambient_obstack;
return t;
}
-/* Modify a tree in place so that all the evaluate only once things
- are cleared out. Return the EXPR given. */
+/* Similar to `build', except we build
+ on the permanent_obstack, regardless. */
+
tree
-unsave_expr_now (expr)
- tree expr;
+build_min VPROTO((enum tree_code code, tree tt, ...))
{
+#ifndef __STDC__
enum tree_code code;
+ tree tt;
+#endif
+ register struct obstack *ambient_obstack = expression_obstack;
+ va_list p;
+ register tree t;
+ register int length;
register int i;
- if (expr == NULL_TREE)
- return expr;
+ VA_START (p, tt);
+
+#ifndef __STDC__
+ code = va_arg (p, enum tree_code);
+ tt = va_arg (p, tree);
+#endif
- code = TREE_CODE (expr);
- switch (code)
+ expression_obstack = &permanent_obstack;
+
+ t = make_node (code);
+ length = tree_code_length[(int) code];
+ TREE_TYPE (t) = tt;
+ TREE_COMPLEXITY (t) = lineno;
+
+ for (i = 0; i < length; i++)
{
+ tree x = va_arg (p, tree);
+ TREE_OPERAND (t, i) = copy_to_permanent (x);
+ }
+
+ va_end (p);
+ expression_obstack = ambient_obstack;
+ return t;
+}
+
+/* Same as `tree_cons' but make a permanent object. */
+
+tree
+min_tree_cons (purpose, value, chain)
+ tree purpose, value, chain;
+{
+ register tree node;
+ register struct obstack *ambient_obstack = current_obstack;
+ current_obstack = &permanent_obstack;
+
+ node = tree_cons (copy_to_permanent (purpose),
+ copy_to_permanent (value), chain);
+ current_obstack = ambient_obstack;
+ return node;
+}
+
+tree
+get_type_decl (t)
+ tree t;
+{
+ if (TREE_CODE (t) == TYPE_DECL)
+ return t;
+ if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
+ return TYPE_STUB_DECL (t);
+
+ my_friendly_abort (42);
+
+ /* Stop compiler from complaining control reaches end of non-void function. */
+ return 0;
+}
+
+int
+can_free (obstack, t)
+ struct obstack *obstack;
+ tree t;
+{
+ int size = 0;
+
+ if (TREE_CODE (t) == TREE_VEC)
+ size = (TREE_VEC_LENGTH (t)-1) * sizeof (tree) + sizeof (struct tree_vec);
+ else
+ my_friendly_abort (42);
+
+#define ROUND(x) ((x + obstack_alignment_mask (obstack)) \
+ & ~ obstack_alignment_mask (obstack))
+ if ((char *)t + ROUND (size) == obstack_next_free (obstack))
+ return 1;
+#undef ROUND
+
+ return 0;
+}
+
+/* Return first vector element whose BINFO_TYPE is ELEM.
+ Return 0 if ELEM is not in VEC. VEC may be NULL_TREE. */
+
+tree
+vec_binfo_member (elem, vec)
+ tree elem, vec;
+{
+ int i;
+
+ if (vec)
+ for (i = 0; i < TREE_VEC_LENGTH (vec); ++i)
+ if (comptypes (elem, BINFO_TYPE (TREE_VEC_ELT (vec, i)), 1))
+ return TREE_VEC_ELT (vec, i);
+
+ return NULL_TREE;
+}
+
+/* Kludge around the fact that DECL_CONTEXT for virtual functions returns
+ the wrong thing for decl_function_context. Hopefully the uses in the
+ backend won't matter, since we don't need a static chain for local class
+ methods. FIXME! */
+
+tree
+hack_decl_function_context (decl)
+ tree decl;
+{
+ if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FUNCTION_MEMBER_P (decl))
+ return decl_function_context (TYPE_MAIN_DECL (DECL_CLASS_CONTEXT (decl)));
+ return decl_function_context (decl);
+}
+
+/* Return truthvalue of whether T1 is the same tree structure as T2.
+ Return 1 if they are the same.
+ Return 0 if they are understandably different.
+ Return -1 if either contains tree structure not understood by
+ this function. */
+
+int
+cp_tree_equal (t1, t2)
+ tree t1, t2;
+{
+ register enum tree_code code1, code2;
+ int cmp;
+
+ if (t1 == t2)
+ return 1;
+ if (t1 == 0 || t2 == 0)
+ return 0;
+
+ code1 = TREE_CODE (t1);
+ code2 = TREE_CODE (t2);
+
+ if (code1 == NOP_EXPR || code1 == CONVERT_EXPR || code1 == NON_LVALUE_EXPR)
+ {
+ if (code2 == NOP_EXPR || code2 == CONVERT_EXPR || code2 == NON_LVALUE_EXPR)
+ return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+ else
+ return cp_tree_equal (TREE_OPERAND (t1, 0), t2);
+ }
+ else if (code2 == NOP_EXPR || code2 == CONVERT_EXPR
+ || code2 == NON_LVALUE_EXPR)
+ return cp_tree_equal (t1, TREE_OPERAND (t2, 0));
+
+ if (code1 != code2)
+ return 0;
+
+ switch (code1)
+ {
+ case INTEGER_CST:
+ return TREE_INT_CST_LOW (t1) == TREE_INT_CST_LOW (t2)
+ && TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
+
+ case REAL_CST:
+ return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
+
+ case STRING_CST:
+ return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
+ && !bcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+ TREE_STRING_LENGTH (t1));
+
+ case CONSTRUCTOR:
+ /* We need to do this when determining whether or not two
+ non-type pointer to member function template arguments
+ are the same. */
+ if (!(comptypes (TREE_TYPE (t1), TREE_TYPE (t2), 1)
+ /* The first operand is RTL. */
+ && TREE_OPERAND (t1, 0) == TREE_OPERAND (t2, 0)))
+ return 0;
+ return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+
+ case TREE_LIST:
+ cmp = cp_tree_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
+ if (cmp <= 0)
+ return cmp;
+ cmp = cp_tree_equal (TREE_VALUE (t1), TREE_VALUE (t2));
+ if (cmp <= 0)
+ return cmp;
+ return cp_tree_equal (TREE_CHAIN (t1), TREE_CHAIN (t2));
+
case SAVE_EXPR:
- SAVE_EXPR_RTL (expr) = NULL_RTX;
- break;
+ return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+
+ case CALL_EXPR:
+ cmp = cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+ if (cmp <= 0)
+ return cmp;
+ return simple_cst_list_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
case TARGET_EXPR:
- sorry ("TARGET_EXPR reused inside UNSAVE_EXPR");
+ /* Special case: if either target is an unallocated VAR_DECL,
+ it means that it's going to be unified with whatever the
+ TARGET_EXPR is really supposed to initialize, so treat it
+ as being equivalent to anything. */
+ if ((TREE_CODE (TREE_OPERAND (t1, 0)) == VAR_DECL
+ && DECL_NAME (TREE_OPERAND (t1, 0)) == NULL_TREE
+ && DECL_RTL (TREE_OPERAND (t1, 0)) == 0)
+ || (TREE_CODE (TREE_OPERAND (t2, 0)) == VAR_DECL
+ && DECL_NAME (TREE_OPERAND (t2, 0)) == NULL_TREE
+ && DECL_RTL (TREE_OPERAND (t2, 0)) == 0))
+ cmp = 1;
+ else
+ cmp = cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+ if (cmp <= 0)
+ return cmp;
+ return cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1));
+
+ case WITH_CLEANUP_EXPR:
+ cmp = cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+ if (cmp <= 0)
+ return cmp;
+ return cp_tree_equal (TREE_OPERAND (t1, 2), TREE_OPERAND (t1, 2));
+
+ case COMPONENT_REF:
+ if (TREE_OPERAND (t1, 1) == TREE_OPERAND (t2, 1))
+ return cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+ return 0;
+
+ case VAR_DECL:
+ case PARM_DECL:
+ case CONST_DECL:
+ case FUNCTION_DECL:
+ return 0;
+
+ case TEMPLATE_PARM_INDEX:
+ return TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2)
+ && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2);
+
+ case SIZEOF_EXPR:
+ case ALIGNOF_EXPR:
+ if (TREE_CODE (TREE_OPERAND (t1, 0)) != TREE_CODE (TREE_OPERAND (t2, 0)))
+ return 0;
+ if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t1, 0))) == 't')
+ return comptypes (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0), 1);
break;
-
- case RTL_EXPR:
- warning ("RTL_EXPR reused inside UNSAVE_EXPR");
- RTL_EXPR_SEQUENCE (expr) = NULL_RTX;
+
+ default:
break;
+ }
- case CALL_EXPR:
- CALL_EXPR_RTL (expr) = NULL_RTX;
- if (TREE_OPERAND (expr, 1)
- && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
+ switch (TREE_CODE_CLASS (code1))
+ {
+ int i;
+ case '1':
+ case '2':
+ case '<':
+ case 'e':
+ case 'r':
+ case 's':
+ cmp = 1;
+ for (i=0; i<tree_code_length[(int) code1]; ++i)
{
- tree exp = TREE_OPERAND (expr, 1);
- while (exp)
- {
- unsave_expr_now (TREE_VALUE (exp));
- exp = TREE_CHAIN (exp);
- }
+ cmp = cp_tree_equal (TREE_OPERAND (t1, i), TREE_OPERAND (t2, i));
+ if (cmp <= 0)
+ return cmp;
}
- break;
-
- case WITH_CLEANUP_EXPR:
- warning ("WITH_CLEANUP_EXPR reused inside UNSAVE_EXPR");
- RTL_EXPR_RTL (expr) = NULL_RTX;
- break;
+ return cmp;
}
- switch (TREE_CODE_CLASS (code))
- {
- case 'c': /* a constant */
- case 't': /* a type node */
- case 'x': /* something random, like an identifier or an ERROR_MARK. */
- case 'd': /* A decl node */
- case 'b': /* A block node */
- return expr;
+ return -1;
+}
- case 'e': /* an expression */
- case 'r': /* a reference */
- case 's': /* an expression with side effects */
- case '<': /* a comparison expression */
- case '2': /* a binary arithmetic expression */
- case '1': /* a unary arithmetic expression */
- for (i = tree_code_length[(int) code] - 1; i >= 0; i--)
- unsave_expr_now (TREE_OPERAND (expr, i));
- return expr;
+/* Similar to make_tree_vec, but build on a temporary obstack. */
- default:
- my_friendly_abort (999);
- }
+tree
+make_temp_vec (len)
+ int len;
+{
+ register tree node;
+ register struct obstack *ambient_obstack = current_obstack;
+ current_obstack = expression_obstack;
+ node = make_tree_vec (len);
+ current_obstack = ambient_obstack;
+ return node;
+}
+
+/* Build a wrapper around some pointer PTR so we can use it as a tree. */
+
+tree
+build_ptr_wrapper (ptr)
+ void *ptr;
+{
+ tree t = make_node (WRAPPER);
+ WRAPPER_PTR (t) = ptr;
+ return t;
+}
+
+/* Same, but on the expression_obstack. */
+
+tree
+build_expr_ptr_wrapper (ptr)
+ void *ptr;
+{
+ tree t;
+ push_expression_obstack ();
+ t = build_ptr_wrapper (ptr);
+ pop_obstacks ();
+ return t;
+}
+
+/* Build a wrapper around some integer I so we can use it as a tree. */
+
+tree
+build_int_wrapper (i)
+ int i;
+{
+ tree t = make_node (WRAPPER);
+ WRAPPER_INT (t) = i;
+ return t;
}
-/* Since cleanup may have SAVE_EXPRs in it, we protect it with an
- UNSAVE_EXPR as the backend cannot yet handle SAVE_EXPRs in cleanups
- by itself. */
+tree
+build_srcloc (file, line)
+ char *file;
+ int line;
+{
+ tree t;
+
+ /* Make sure that we put these on the permanent obstack; up in
+ add_pending_template, we pass this return value into perm_tree_cons,
+ which also puts it on the permanent_obstack. However, this wasn't
+ explicitly doing the same. */
+ register struct obstack *ambient_obstack = current_obstack;
+ current_obstack = &permanent_obstack;
+
+ t = make_node (SRCLOC);
+ SRCLOC_FILE (t) = file;
+ SRCLOC_LINE (t) = line;
+
+ current_obstack = ambient_obstack;
+
+ return t;
+}
+
+tree
+build_srcloc_here ()
+{
+ return build_srcloc (input_filename, lineno);
+}
+
+void
+push_expression_obstack ()
+{
+ push_obstacks_nochange ();
+ current_obstack = expression_obstack;
+}
+
+/* The type of ARG when used as an lvalue. */
+
+tree
+lvalue_type (arg)
+ tree arg;
+{
+ tree type = TREE_TYPE (arg);
+ if (TREE_CODE (arg) == OVERLOAD)
+ type = unknown_type_node;
+ return cp_build_type_variant
+ (type, TREE_READONLY (arg), TREE_THIS_VOLATILE (arg));
+}
+
+/* The type of ARG for printing error messages; denote lvalues with
+ reference types. */
+
+tree
+error_type (arg)
+ tree arg;
+{
+ tree type = TREE_TYPE (arg);
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ ;
+ else if (real_lvalue_p (arg))
+ type = build_reference_type (lvalue_type (arg));
+ else if (IS_AGGR_TYPE (type))
+ type = lvalue_type (arg);
+
+ return type;
+}
+
+/* Does FUNCTION use a variable-length argument list? */
+
+int
+varargs_function_p (function)
+ tree function;
+{
+ tree parm = TYPE_ARG_TYPES (TREE_TYPE (function));
+ for (; parm; parm = TREE_CHAIN (parm))
+ if (TREE_VALUE (parm) == void_type_node)
+ return 0;
+ return 1;
+}
+
+/* Returns 1 if decl is a member of a class. */
+
int
-cp_expand_decl_cleanup (decl, cleanup)
- tree decl, cleanup;
+member_p (decl)
+ tree decl;
{
- return expand_decl_cleanup (decl, unsave_expr (cleanup));
+ tree ctx = DECL_CONTEXT (decl);
+ return (ctx && TREE_CODE_CLASS (TREE_CODE (ctx)) == 't');
}
diff --git a/contrib/gcc/cp/typeck.c b/contrib/gcc/cp/typeck.c
index 9247bf0..4e1d4fd 100644
--- a/contrib/gcc/cp/typeck.c
+++ b/contrib/gcc/cp/typeck.c
@@ -1,5 +1,5 @@
/* Build expressions with type checking for C++ compiler.
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -29,31 +29,38 @@ Boston, MA 02111-1307, USA. */
and to process initializations in declarations (since they work
like a strange sort of assignment). */
-extern void error ();
-extern void warning ();
-
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "cp-tree.h"
#include "flags.h"
#include "output.h"
-
-int mark_addressable ();
-static tree convert_for_assignment ();
-/* static */ tree convert_for_initialization ();
-extern tree shorten_compare ();
-extern void binary_op_error ();
-static tree pointer_int_sum ();
-static tree pointer_diff ();
-static tree convert_sequence ();
-/* static */ tree unary_complex_lvalue ();
+#include "expr.h"
+#include "toplev.h"
+
+extern void compiler_error ();
+
+static tree convert_for_assignment PROTO((tree, tree, char*, tree,
+ int));
+static tree pointer_int_sum PROTO((enum tree_code, tree, tree));
+static tree rationalize_conditional_expr PROTO((enum tree_code, tree));
+static int comp_target_parms PROTO((tree, tree, int));
+static int comp_ptr_ttypes_real PROTO((tree, tree, int));
+static int comp_ptr_ttypes_const PROTO((tree, tree));
+static int comp_ptr_ttypes_reinterpret PROTO((tree, tree));
+static int comp_array_types PROTO((int (*) (tree, tree, int), tree,
+ tree, int));
+static tree build_ptrmemfunc1 PROTO((tree, tree, tree, tree, tree));
+static tree common_base_type PROTO((tree, tree));
+#if 0
+static tree convert_sequence PROTO((tree, tree));
+#endif
+static tree lookup_anon_field PROTO((tree, tree));
+static tree pointer_diff PROTO((tree, tree, tree));
+static tree qualify_type PROTO((tree, tree));
static tree get_delta_difference PROTO((tree, tree, int));
-extern rtx original_result_rtx;
-extern int warn_synth;
-
/* Return the target type of TYPE, which meas return T for:
T*, T&, T[], T (...), and otherwise, just T. */
@@ -79,7 +86,15 @@ tree
require_complete_type (value)
tree value;
{
- tree type = TREE_TYPE (value);
+ tree type;
+
+ if (processing_template_decl)
+ return value;
+
+ if (TREE_CODE (value) == OVERLOAD)
+ type = unknown_type_node;
+ else
+ type = TREE_TYPE (value);
/* First, detect a valid value with a complete type. */
if (TYPE_SIZE (type) != 0
@@ -93,34 +108,92 @@ require_complete_type (value)
not been laid out. Try to avoid an error by interpreting
it as this->X::Y, if reasonable. */
if (TREE_CODE (value) == OFFSET_REF
- && C_C_D != 0
- && TREE_OPERAND (value, 0) == C_C_D)
+ && current_class_ref != 0
+ && TREE_OPERAND (value, 0) == current_class_ref)
{
tree base, member = TREE_OPERAND (value, 1);
tree basetype = TYPE_OFFSET_BASETYPE (type);
my_friendly_assert (TREE_CODE (member) == FIELD_DECL, 305);
- base = convert_pointer_to (basetype, current_class_decl);
+ base = convert_pointer_to (basetype, current_class_ptr);
value = build (COMPONENT_REF, TREE_TYPE (member),
build_indirect_ref (base, NULL_PTR), member);
return require_complete_type (value);
}
- incomplete_type_error (value, type);
- return error_mark_node;
+ if (TYPE_SIZE (complete_type (type)))
+ return value;
+ else
+ {
+ incomplete_type_error (value, type);
+ return error_mark_node;
+ }
+}
+
+/* Try to complete TYPE, if it is incomplete. For example, if TYPE is
+ a template instantiation, do the instantiation. Returns TYPE,
+ whether or not it could be completed, unless something goes
+ horribly wrong, in which case the error_mark_node is returned. */
+
+tree
+complete_type (type)
+ tree type;
+{
+ if (type == NULL_TREE)
+ /* Rather than crash, we return something sure to cause an error
+ at some point. */
+ return error_mark_node;
+
+ if (type == error_mark_node || TYPE_SIZE (type) != NULL_TREE)
+ ;
+ else if (TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type))
+ {
+ tree t = complete_type (TREE_TYPE (type));
+ if (TYPE_SIZE (t) != NULL_TREE && ! processing_template_decl)
+ layout_type (type);
+ TYPE_NEEDS_CONSTRUCTING (type)
+ = TYPE_NEEDS_CONSTRUCTING (TYPE_MAIN_VARIANT (t));
+ TYPE_NEEDS_DESTRUCTOR (type)
+ = TYPE_NEEDS_DESTRUCTOR (TYPE_MAIN_VARIANT (t));
+ }
+ else if (IS_AGGR_TYPE (type) && CLASSTYPE_TEMPLATE_INSTANTIATION (type))
+ instantiate_class_template (TYPE_MAIN_VARIANT (type));
+
+ return type;
+}
+
+/* Like complete_type, but issue an error if the TYPE cannot be
+ completed. Returns NULL_TREE if the type cannot be made
+ complete. */
+
+tree
+complete_type_or_else (type)
+ tree type;
+{
+ type = complete_type (type);
+ if (type != error_mark_node && !TYPE_SIZE (type))
+ {
+ incomplete_type_error (NULL_TREE, type);
+ return NULL_TREE;
+ }
+ else
+ return type;
}
/* Return truthvalue of whether type of EXP is instantiated. */
+
int
type_unknown_p (exp)
tree exp;
{
- return (TREE_CODE (exp) == TREE_LIST
+ return (TREE_CODE (exp) == OVERLOAD
+ || TREE_CODE (exp) == TREE_LIST
|| TREE_TYPE (exp) == unknown_type_node
|| (TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE
&& TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node));
}
/* Return truthvalue of whether T is function (or pfn) type. */
+
int
fntype_p (t)
tree t;
@@ -134,6 +207,7 @@ fntype_p (t)
/* Do `exp = require_instantiated_type (type, exp);' to make sure EXP
does not have an uninstantiated type.
TYPE is type to instantiate with, if uninstantiated. */
+
tree
require_instantiated_type (type, exp, errval)
tree type, exp, errval;
@@ -144,7 +218,8 @@ require_instantiated_type (type, exp, errval)
return errval;
}
- if (TREE_TYPE (exp) == unknown_type_node
+ if (TREE_CODE (exp) == OVERLOAD
+ || TREE_TYPE (exp) == unknown_type_node
|| (TREE_CODE (TREE_TYPE (exp)) == OFFSET_TYPE
&& TREE_TYPE (TREE_TYPE (exp)) == unknown_type_node))
{
@@ -239,6 +314,25 @@ commonparms (p1, p2)
return newargs;
}
+/* Given a type, perhaps copied for a typedef,
+ find the "original" version of it. */
+tree
+original_type (t)
+ tree t;
+{
+ while (TYPE_NAME (t) != NULL_TREE)
+ {
+ tree x = TYPE_NAME (t);
+ if (TREE_CODE (x) != TYPE_DECL)
+ break;
+ x = DECL_ORIGINAL_TYPE (x);
+ if (x == NULL_TREE)
+ break;
+ t = x;
+ }
+ return t;
+}
+
/* Return the common type of two types.
We assume that comptypes has already been done and returned 1;
if that isn't so, this may crash.
@@ -258,8 +352,12 @@ common_type (t1, t2)
tree attributes;
/* Save time if the two types are the same. */
-
- if (t1 == t2) return t1;
+ if (t1 == t2)
+ return t1;
+ t1 = original_type (t1);
+ t2 = original_type (t2);
+ if (t1 == t2)
+ return t1;
/* If one type is nonsense, use the other. */
if (t1 == error_mark_node)
@@ -267,7 +365,8 @@ common_type (t1, t2)
if (t2 == error_mark_node)
return t1;
- /* Merge the attributes */
+ /* Merge the attributes. */
+ attributes = merge_machine_type_attributes (t1, t2);
{ register tree a1, a2;
a1 = TYPE_ATTRIBUTES (t1);
@@ -281,25 +380,27 @@ common_type (t1, t2)
/* One that completely contains the other? Take it. */
else if (a2 && !attribute_list_contained (a1, a2))
- if (attribute_list_contained (a2, a1))
+ {
+ if (attribute_list_contained (a2, a1))
attributes = a2;
- else
- {
- /* Pick the longest list, and hang on the other list. */
- /* ??? For the moment we punt on the issue of attrs with args. */
+ else
+ {
+ /* Pick the longest list, and hang on the other list. */
+ /* ??? For the moment we punt on the issue of attrs with args. */
- if (list_length (a1) < list_length (a2))
- attributes = a2, a2 = a1;
+ if (list_length (a1) < list_length (a2))
+ attributes = a2, a2 = a1;
- for (; a2; a2 = TREE_CHAIN (a2))
- if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
- attributes) == NULL_TREE)
- {
- a1 = copy_node (a2);
- TREE_CHAIN (a1) = attributes;
- attributes = a1;
- }
- }
+ for (; a2; a2 = TREE_CHAIN (a2))
+ if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
+ attributes) == NULL_TREE)
+ {
+ a1 = copy_node (a2);
+ TREE_CHAIN (a1) = attributes;
+ attributes = a1;
+ }
+ }
+ }
}
/* Treat an enum type as the unsigned integer type of the same width. */
@@ -309,9 +410,32 @@ common_type (t1, t2)
if (TREE_CODE (t2) == ENUMERAL_TYPE)
t2 = type_for_size (TYPE_PRECISION (t2), 1);
+ if (TYPE_PTRMEMFUNC_P (t1))
+ t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+ if (TYPE_PTRMEMFUNC_P (t2))
+ t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
code1 = TREE_CODE (t1);
code2 = TREE_CODE (t2);
+ /* If one type is complex, form the common type of the non-complex
+ components, then make that complex. Use T1 or T2 if it is the
+ required type. */
+ if (code1 == COMPLEX_TYPE || code2 == COMPLEX_TYPE)
+ {
+ tree subtype1 = code1 == COMPLEX_TYPE ? TREE_TYPE (t1) : t1;
+ tree subtype2 = code2 == COMPLEX_TYPE ? TREE_TYPE (t2) : t2;
+ tree subtype = common_type (subtype1, subtype2);
+
+ if (code1 == COMPLEX_TYPE && TREE_TYPE (t1) == subtype)
+ return build_type_attribute_variant (t1, attributes);
+ else if (code2 == COMPLEX_TYPE && TREE_TYPE (t2) == subtype)
+ return build_type_attribute_variant (t2, attributes);
+ else
+ return build_type_attribute_variant (build_complex_type (subtype),
+ attributes);
+ }
+
switch (code1)
{
case INTEGER_TYPE:
@@ -382,6 +506,10 @@ common_type (t1, t2)
target = tt1;
else if (tt1 == void_type_node || tt2 == void_type_node)
target = void_type_node;
+ else if (tt1 == unknown_type_node)
+ target = tt2;
+ else if (tt2 == unknown_type_node)
+ target = tt1;
else
target = common_type (tt1, tt2);
@@ -397,15 +525,6 @@ common_type (t1, t2)
return t1;
}
-#if 0
- case POINTER_TYPE:
- t1 = build_pointer_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
- return build_type_attribute_variant (t1, attributes);
-
- case REFERENCE_TYPE:
- t1 = build_reference_type (common_type (TREE_TYPE (t1), TREE_TYPE (t2)));
- return build_type_attribute_variant (t1, attributes);
-#endif
case ARRAY_TYPE:
{
@@ -416,7 +535,8 @@ common_type (t1, t2)
if (elt == TREE_TYPE (t2) && TYPE_DOMAIN (t2))
return build_type_attribute_variant (t2, attributes);
/* Merge the element types, and have a size if either arg has one. */
- t1 = build_cplus_array_type (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
+ t1 = build_cplus_array_type
+ (elt, TYPE_DOMAIN (TYPE_DOMAIN (t1) ? t1 : t2));
return build_type_attribute_variant (t1, attributes);
}
@@ -459,8 +579,8 @@ common_type (t1, t2)
case RECORD_TYPE:
case UNION_TYPE:
- my_friendly_assert (TYPE_MAIN_VARIANT (t1) == t1
- && TYPE_MAIN_VARIANT (t2) == t2, 306);
+ t1 = TYPE_MAIN_VARIANT (t1);
+ t2 = TYPE_MAIN_VARIANT (t2);
if (DERIVED_FROM_P (t1, t2) && binfo_or_else (t1, t2))
return build_type_attribute_variant (t1, attributes);
@@ -480,7 +600,8 @@ common_type (t1, t2)
tree b1 = TYPE_OFFSET_BASETYPE (t1);
tree b2 = TYPE_OFFSET_BASETYPE (t2);
- if (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2))
+ if (comptypes (b1, b2, 1)
+ || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
basetype = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t2)));
else
{
@@ -494,10 +615,13 @@ common_type (t1, t2)
/* If this was a member function type, get back to the
original type of type member function (i.e., without
the class instance variable up front. */
- t1 = build_function_type (TREE_TYPE (t1), TREE_CHAIN (TYPE_ARG_TYPES (t1)));
- t2 = build_function_type (TREE_TYPE (t2), TREE_CHAIN (TYPE_ARG_TYPES (t2)));
+ t1 = build_function_type (TREE_TYPE (t1),
+ TREE_CHAIN (TYPE_ARG_TYPES (t1)));
+ t2 = build_function_type (TREE_TYPE (t2),
+ TREE_CHAIN (TYPE_ARG_TYPES (t2)));
t3 = common_type (t1, t2);
- t3 = build_cplus_method_type (basetype, TREE_TYPE (t3), TYPE_ARG_TYPES (t3));
+ t3 = build_cplus_method_type (basetype, TREE_TYPE (t3),
+ TYPE_ARG_TYPES (t3));
t1 = build_exception_variant (t3, raises);
}
else
@@ -511,7 +635,8 @@ common_type (t1, t2)
tree b1 = TYPE_OFFSET_BASETYPE (t1);
tree b2 = TYPE_OFFSET_BASETYPE (t2);
- if (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2))
+ if (comptypes (b1, b2, 1)
+ || (DERIVED_FROM_P (b1, b2) && binfo_or_else (b1, b2)))
return build_type_attribute_variant (t2, attributes);
else if (binfo_or_else (b2, b1))
return build_type_attribute_variant (t1, attributes);
@@ -524,17 +649,17 @@ common_type (t1, t2)
}
/* Return 1 if TYPE1 and TYPE2 raise the same exceptions. */
+
int
-compexcepttypes (t1, t2, strict)
+compexcepttypes (t1, t2)
tree t1, t2;
- int strict;
{
return TYPE_RAISES_EXCEPTIONS (t1) == TYPE_RAISES_EXCEPTIONS (t2);
}
static int
comp_array_types (cmp, t1, t2, strict)
- register int (*cmp)();
+ register int (*cmp) PROTO((tree, tree, int));
tree t1, t2;
int strict;
{
@@ -580,13 +705,14 @@ comp_array_types (cmp, t1, t2, strict)
0 : <= (compared according to C++)
-1: <= or >= (relaxed)
- Otherwise, pointers involving base classes and derived classes
- can be mixed as valid: i.e. a pointer to a base class may be assigned
- to a pointer to one of its derived classes, as per C++. A pointer to
+ Otherwise, pointers involving base classes and derived classes can
+ be mixed as valid: i.e. a pointer to a derived class may be converted
+ to a pointer to one of its base classes, as per C++. A pointer to
a derived class may be passed as a parameter to a function expecting a
pointer to a base classes. These allowances do not commute. In this
case, TYPE1 is assumed to be the base class, and TYPE2 is assumed to
be the derived class. */
+
int
comptypes (type1, type2, strict)
tree type1, type2;
@@ -620,6 +746,11 @@ comptypes (type1, type2, strict)
return 1;
}
+ if (TYPE_PTRMEMFUNC_P (t1))
+ t1 = TYPE_PTRMEMFUNC_FN_TYPE (t1);
+ if (TYPE_PTRMEMFUNC_P (t2))
+ t2 = TYPE_PTRMEMFUNC_FN_TYPE (t2);
+
/* Different classes of types can't be compatible. */
if (TREE_CODE (t1) != TREE_CODE (t2))
@@ -644,29 +775,51 @@ comptypes (type1, type2, strict)
return 0;
if (TYPE_VOLATILE (t1) != TYPE_VOLATILE (t2))
return 0;
+ if (strict > 0 && TYPE_FOR_JAVA (t1) != TYPE_FOR_JAVA (t2))
+ return 0;
/* Allow for two different type nodes which have essentially the same
definition. Note that we already checked for equality of the type
- type qualifiers (just above). */
+ qualifiers (just above). */
if (TYPE_MAIN_VARIANT (t1) == TYPE_MAIN_VARIANT (t2))
return 1;
-#ifdef COMP_TYPE_ATTRIBUTES
+ /* ??? COMP_TYPE_ATTRIBUTES is currently useless for variables as each
+ attribute is its own main variant (`val' will remain 0). */
+#ifndef COMP_TYPE_ATTRIBUTES
+#define COMP_TYPE_ATTRIBUTES(t1,t2) 1
+#endif
+
+ /* 1 if no need for warning yet, 2 if warning cause has been seen. */
if (! (attrval = COMP_TYPE_ATTRIBUTES (t1, t2)))
return 0;
-#else
- /* 1 if no need for warning yet, 2 if warning cause has been seen. */
- attrval = 1;
-#endif
/* 1 if no need for warning yet, 2 if warning cause has been seen. */
val = 0;
switch (TREE_CODE (t1))
{
+ case TEMPLATE_TEMPLATE_PARM:
+ if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2)
+ || TEMPLATE_TYPE_LEVEL (t1) != TEMPLATE_TYPE_LEVEL (t2))
+ return 0;
+ if (! comp_template_parms (DECL_TEMPLATE_PARMS (TYPE_NAME (t1)),
+ DECL_TEMPLATE_PARMS (TYPE_NAME (t2))))
+ return 0;
+ if (! CLASSTYPE_TEMPLATE_INFO (t1) && ! CLASSTYPE_TEMPLATE_INFO (t2))
+ return 1;
+ /* Don't check inheritance. */
+ strict = 1;
+ /* fall through */
+
case RECORD_TYPE:
case UNION_TYPE:
+ if (CLASSTYPE_TEMPLATE_INFO (t1) && CLASSTYPE_TEMPLATE_INFO (t2)
+ && (CLASSTYPE_TI_TEMPLATE (t1) == CLASSTYPE_TI_TEMPLATE (t2)
+ || TREE_CODE (t1) == TEMPLATE_TEMPLATE_PARM))
+ return comp_template_args (CLASSTYPE_TI_ARGS (t1),
+ CLASSTYPE_TI_ARGS (t2));
if (strict <= 0)
goto look_hard;
return 0;
@@ -678,7 +831,7 @@ comptypes (type1, type2, strict)
break;
case METHOD_TYPE:
- if (! compexcepttypes (t1, t2, strict))
+ if (! compexcepttypes (t1, t2))
return 0;
/* This case is anti-symmetrical!
@@ -706,7 +859,7 @@ comptypes (type1, type2, strict)
{
int rval;
look_hard:
- rval = t1 == t2 || UNIQUELY_DERIVED_FROM_P (t1, t2);
+ rval = t1 == t2 || DERIVED_FROM_P (t1, t2);
if (rval)
{
@@ -715,7 +868,7 @@ comptypes (type1, type2, strict)
}
if (strict < 0)
{
- val = UNIQUELY_DERIVED_FROM_P (t2, t1);
+ val = DERIVED_FROM_P (t2, t1);
break;
}
}
@@ -726,7 +879,7 @@ comptypes (type1, type2, strict)
break;
case FUNCTION_TYPE:
- if (! compexcepttypes (t1, t2, strict))
+ if (! compexcepttypes (t1, t2))
return 0;
val = ((TREE_TYPE (t1) == TREE_TYPE (t2)
@@ -740,41 +893,31 @@ comptypes (type1, type2, strict)
break;
case TEMPLATE_TYPE_PARM:
- return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2);
+ return TEMPLATE_TYPE_IDX (t1) == TEMPLATE_TYPE_IDX (t2)
+ && TEMPLATE_TYPE_LEVEL (t1) == TEMPLATE_TYPE_LEVEL (t2);
- case UNINSTANTIATED_P_TYPE:
- if (UPT_TEMPLATE (t1) != UPT_TEMPLATE (t2))
+ case TYPENAME_TYPE:
+ if (TYPE_IDENTIFIER (t1) != TYPE_IDENTIFIER (t2))
return 0;
- {
- int i = TREE_VEC_LENGTH (UPT_PARMS (t1));
- tree *p1 = &TREE_VEC_ELT (UPT_PARMS (t1), 0);
- tree *p2 = &TREE_VEC_ELT (UPT_PARMS (t2), 0);
-
- while (i--)
- {
- if (TREE_CODE_CLASS (TREE_CODE (p1[i])) == 't')
- {
- if (! comptypes (p1[i], p2[i], 1))
- return 0;
- }
- else
- {
- if (simple_cst_equal (p1[i], p2[i]) <= 0)
- return 0;
- }
- }
- }
- return 1;
+ return comptypes (TYPE_CONTEXT (t1), TYPE_CONTEXT (t2), 1);
+
+ default:
+ break;
}
return attrval == 2 && val == 1 ? 2 : val;
}
-/* Return 1 if TTL and TTR are pointers to types that are equivalent,
- ignoring their qualifiers.
+/* Return 1 or -1 if TTL and TTR are pointers to types that are equivalent,
+ ignoring their qualifiers, 0 if not. Return 1 means that TTR can be
+ converted to TTL. Return -1 means that TTL can be converted to TTR but
+ not vice versa.
NPTRS is the number of pointers we can strip off and keep cool.
This is used to permit (for aggr A, aggr B) A, B* to convert to A*,
- but to not permit B** to convert to A**. */
+ but to not permit B** to convert to A**.
+
+ This should go away. Callers should use can_convert or something
+ similar instead. (jason 17 Apr 1997) */
int
comp_target_types (ttl, ttr, nptrs)
@@ -789,14 +932,20 @@ comp_target_types (ttl, ttr, nptrs)
if (TREE_CODE (ttr) != TREE_CODE (ttl))
return 0;
- if (TREE_CODE (ttr) == POINTER_TYPE)
+ if (TREE_CODE (ttr) == POINTER_TYPE
+ || (TREE_CODE (ttr) == REFERENCE_TYPE))
{
+ int is_ptr = TREE_CODE (ttr) == POINTER_TYPE;
+
ttl = TREE_TYPE (ttl);
ttr = TREE_TYPE (ttr);
- if (nptrs > 0)
+ if (nptrs > 0 && is_ptr)
{
- if (TREE_CODE (ttl) == VOID_TYPE
+ if (TREE_CODE (ttl) == UNKNOWN_TYPE
+ || TREE_CODE (ttr) == UNKNOWN_TYPE)
+ return 1;
+ else if (TREE_CODE (ttl) == VOID_TYPE
&& TREE_CODE (ttr) != FUNCTION_TYPE
&& TREE_CODE (ttr) != METHOD_TYPE
&& TREE_CODE (ttr) != OFFSET_TYPE)
@@ -843,35 +992,71 @@ comp_target_types (ttl, ttr, nptrs)
}
}
- if (TREE_CODE (ttr) == REFERENCE_TYPE)
- return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs);
if (TREE_CODE (ttr) == ARRAY_TYPE)
return comp_array_types (comp_target_types, ttl, ttr, 0);
else if (TREE_CODE (ttr) == FUNCTION_TYPE || TREE_CODE (ttr) == METHOD_TYPE)
- if (comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs))
- switch (comp_target_parms (TYPE_ARG_TYPES (ttl), TYPE_ARG_TYPES (ttr), 1))
+ {
+ tree argsl, argsr;
+ int saw_contra = 0;
+
+ if (pedantic)
{
- case 0:
- return 0;
- case 1:
- return 1;
- case 2:
- return -1;
- default:
- my_friendly_abort (112);
+ if (comptypes (TREE_TYPE (ttl), TREE_TYPE (ttr), 1) == 0)
+ return 0;
}
- else
- return 0;
+ else
+ {
+ switch (comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), -1))
+ {
+ case 0:
+ return 0;
+ case -1:
+ saw_contra = 1;
+ }
+ }
+
+ argsl = TYPE_ARG_TYPES (ttl);
+ argsr = TYPE_ARG_TYPES (ttr);
+
+ /* Compare 'this' here, not in comp_target_parms. */
+ if (TREE_CODE (ttr) == METHOD_TYPE)
+ {
+ tree tl = TYPE_METHOD_BASETYPE (ttl);
+ tree tr = TYPE_METHOD_BASETYPE (ttr);
+ if (comptypes (tr, tl, 0) == 0)
+ {
+ if (comptypes (tl, tr, 0))
+ saw_contra = 1;
+ else
+ return 0;
+ }
+
+ argsl = TREE_CHAIN (argsl);
+ argsr = TREE_CHAIN (argsr);
+ }
+
+ switch (comp_target_parms (argsl, argsr, 1))
+ {
+ case 0:
+ return 0;
+ case -1:
+ saw_contra = 1;
+ }
+
+ return saw_contra ? -1 : 1;
+ }
/* for C++ */
else if (TREE_CODE (ttr) == OFFSET_TYPE)
{
/* Contravariance: we can assign a pointer to base member to a pointer
to derived member. Note difference from simple pointer case, where
we can pass a pointer to derived to a pointer to base. */
- if (comptypes (TYPE_OFFSET_BASETYPE (ttr), TYPE_OFFSET_BASETYPE (ttl), 0))
+ if (comptypes (TYPE_OFFSET_BASETYPE (ttr),
+ TYPE_OFFSET_BASETYPE (ttl), 0))
return comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs);
- else if (comptypes (TYPE_OFFSET_BASETYPE (ttl), TYPE_OFFSET_BASETYPE (ttr), 0)
+ else if (comptypes (TYPE_OFFSET_BASETYPE (ttl),
+ TYPE_OFFSET_BASETYPE (ttr), 0)
&& comp_target_types (TREE_TYPE (ttl), TREE_TYPE (ttr), nptrs))
return -1;
}
@@ -889,14 +1074,55 @@ comp_target_types (ttl, ttr, nptrs)
return 0;
}
+/* Returns 1 if TYPE1 is more cv-qualified than TYPE2, -1 if TYPE2 is
+ more cv-qualified that TYPE1, and 0 otherwise. */
+
+int
+comp_cv_qualification (type1, type2)
+ tree type1;
+ tree type2;
+{
+ if (TYPE_READONLY (type1) == TYPE_READONLY (type2)
+ && TYPE_VOLATILE (type1) == TYPE_VOLATILE (type2))
+ return 0;
+
+ if (TYPE_READONLY (type1) >= TYPE_READONLY (type2)
+ && TYPE_VOLATILE (type1) >= TYPE_VOLATILE (type2))
+ return 1;
+
+ if (TYPE_READONLY (type2) >= TYPE_READONLY (type1)
+ && TYPE_VOLATILE (type2) >= TYPE_VOLATILE (type1))
+ return -1;
+
+ return 0;
+}
+
+/* Returns 1 if the cv-qualification signature of TYPE1 is a proper
+ subset of the cv-qualification signature of TYPE2, and the types
+ are similar. Returns -1 if the other way 'round, and 0 otherwise. */
+
+int
+comp_cv_qual_signature (type1, type2)
+ tree type1;
+ tree type2;
+{
+ if (comp_ptr_ttypes_real (type2, type1, -1))
+ return 1;
+ else if (comp_ptr_ttypes_real (type1, type2, -1))
+ return -1;
+ else
+ return 0;
+}
+
/* If two types share a common base type, return that basetype.
If there is not a unique most-derived base type, this function
returns ERROR_MARK_NODE. */
-tree
+
+static tree
common_base_type (tt1, tt2)
tree tt1, tt2;
{
- tree best = NULL_TREE, tmp;
+ tree best = NULL_TREE;
int i;
/* If one is a baseclass of another, that's good enough. */
@@ -905,15 +1131,6 @@ common_base_type (tt1, tt2)
if (UNIQUELY_DERIVED_FROM_P (tt2, tt1))
return tt2;
-#if 0
- /* If they share a virtual baseclass, that's good enough. */
- for (tmp = CLASSTYPE_VBASECLASSES (tt1); tmp; tmp = TREE_CHAIN (tmp))
- {
- if (binfo_member (BINFO_TYPE (tmp), CLASSTYPE_VBASECLASSES (tt2)))
- return BINFO_TYPE (tmp);
- }
-#endif
-
/* Otherwise, try to find a unique baseclass of TT1
that is shared by TT2, and follow that down. */
for (i = CLASSTYPE_N_BASECLASSES (tt1)-1; i >= 0; i--)
@@ -957,9 +1174,10 @@ common_base_type (tt1, tt2)
If either list is empty, we win.
Otherwise, the two lists must be equivalent, element by element.
- C++: See comment above about TYPE1, TYPE2, STRICT.
- If STRICT == 3, it means checking is strict, but do not compare
- default parameter values. */
+ C++: See comment above about TYPE1, TYPE2.
+
+ STRICT is no longer used. */
+
int
compparms (parms1, parms2, strict)
tree parms1, parms2;
@@ -970,45 +1188,16 @@ compparms (parms1, parms2, strict)
/* An unspecified parmlist matches any specified parmlist
whose argument types don't need default promotions. */
- if (strict <= 0 && t1 == 0)
- return self_promoting_args_p (t2);
- if (strict < 0 && t2 == 0)
- return self_promoting_args_p (t1);
-
while (1)
{
if (t1 == 0 && t2 == 0)
return 1;
/* If one parmlist is shorter than the other,
- they fail to match, unless STRICT is <= 0. */
+ they fail to match. */
if (t1 == 0 || t2 == 0)
- {
- if (strict > 0)
- return 0;
- if (strict < 0)
- return 1;
- if (strict == 0)
- return t1 && TREE_PURPOSE (t1);
- }
- if (! comptypes (TREE_VALUE (t2), TREE_VALUE (t1), strict))
- {
- if (strict > 0)
- return 0;
- if (strict == 0)
- return t2 == void_list_node && TREE_PURPOSE (t1);
- return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
- }
-#if 0
- /* Default parms are not part of the type of a function. */
- if (strict != 3 && TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
- {
- int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
- if (cmp < 0)
- my_friendly_abort (113);
- if (cmp == 0)
- return 0;
- }
-#endif
+ return 0;
+ if (! comptypes (TREE_VALUE (t2), TREE_VALUE (t1), 1))
+ return 0;
t1 = TREE_CHAIN (t1);
t2 = TREE_CHAIN (t2);
@@ -1016,8 +1205,15 @@ compparms (parms1, parms2, strict)
}
/* This really wants return whether or not parameter type lists
- would make their owning functions assignment compatible or not. */
-int
+ would make their owning functions assignment compatible or not.
+
+ The return value is like for comp_target_types.
+
+ This should go away, possibly with the exception of the empty parmlist
+ conversion; there are no conversions between function types in C++.
+ (jason 17 Apr 1997) */
+
+static int
comp_target_parms (parms1, parms2, strict)
tree parms1, parms2;
int strict;
@@ -1025,9 +1221,9 @@ comp_target_parms (parms1, parms2, strict)
register tree t1 = parms1, t2 = parms2;
int warn_contravariance = 0;
- /* An unspecified parmlist matches any specified parmlist
- whose argument types don't need default promotions.
- @@@ see 13.3.3 for a counterexample... */
+ /* In C, an unspecified parmlist matches any specified parmlist
+ whose argument types don't need default promotions. This is not
+ true for C++, but let's do it anyway for unfixed headers. */
if (t1 == 0 && t2 != 0)
{
@@ -1054,11 +1250,15 @@ comp_target_parms (parms1, parms2, strict)
}
p1 = TREE_VALUE (t1);
p2 = TREE_VALUE (t2);
- if (p1 == p2)
+ if (comptypes (p1, p2, 1))
continue;
+ if (pedantic)
+ return 0;
+
if ((TREE_CODE (p1) == POINTER_TYPE && TREE_CODE (p2) == POINTER_TYPE)
- || (TREE_CODE (p1) == REFERENCE_TYPE && TREE_CODE (p2) == REFERENCE_TYPE))
+ || (TREE_CODE (p1) == REFERENCE_TYPE
+ && TREE_CODE (p2) == REFERENCE_TYPE))
{
if (strict <= 0
&& (TYPE_MAIN_VARIANT (TREE_TYPE (p1))
@@ -1076,58 +1276,24 @@ comp_target_parms (parms1, parms2, strict)
}
if (IS_AGGR_TYPE (TREE_TYPE (p1)))
{
- if (comptypes (p2, p1, 0) == 0)
- {
- if (comptypes (p1, p2, 0) != 0)
- warn_contravariance = 1;
- else
- return 0;
- }
- continue;
+ if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (p1)),
+ TYPE_MAIN_VARIANT (TREE_TYPE (p2)), 1) == 0)
+ return 0;
}
}
/* Note backwards order due to contravariance. */
- if (comp_target_types (p2, p1, 1) == 0)
+ if (comp_target_types (p2, p1, 1) <= 0)
{
- if (comp_target_types (p1, p2, 1))
+ if (comp_target_types (p1, p2, 1) > 0)
{
warn_contravariance = 1;
continue;
}
if (strict != 0)
return 0;
-#if 0
- /* What good do these cases do? */
- if (strict == 0)
- return p2 == void_type_node && TREE_PURPOSE (t1);
- return TREE_PURPOSE (t1) || TREE_PURPOSE (t2);
-#endif
- }
- /* Target types are compatible--just make sure that if
- we use parameter lists, that they are ok as well. */
- if (TREE_CODE (p1) == FUNCTION_TYPE || TREE_CODE (p1) == METHOD_TYPE)
- switch (comp_target_parms (TYPE_ARG_TYPES (p1),
- TYPE_ARG_TYPES (p2),
- strict))
- {
- case 0:
- return 0;
- case 1:
- break;
- case 2:
- warn_contravariance = 1;
- }
-
- if (TREE_PURPOSE (t1) && TREE_PURPOSE (t2))
- {
- int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
- if (cmp < 0)
- my_friendly_abort (114);
- if (cmp == 0)
- return 0;
}
}
- return 1 + warn_contravariance;
+ return warn_contravariance ? -1 : 1;
}
/* Return 1 if PARMS specifies a fixed number of parameters
@@ -1145,10 +1311,10 @@ self_promoting_args_p (parms)
if (TREE_CHAIN (t) == 0 && type != void_type_node)
return 0;
- if (TYPE_MAIN_VARIANT (type) == float_type_node)
+ if (type == 0)
return 0;
- if (type == 0)
+ if (TYPE_MAIN_VARIANT (type) == float_type_node)
return 0;
if (C_PROMOTING_INTEGER_TYPE_P (type))
@@ -1176,7 +1342,18 @@ unsigned_type (type)
return long_unsigned_type_node;
if (type1 == long_long_integer_type_node)
return long_long_unsigned_type_node;
- return type;
+ if (type1 == intTI_type_node)
+ return unsigned_intTI_type_node;
+ if (type1 == intDI_type_node)
+ return unsigned_intDI_type_node;
+ if (type1 == intSI_type_node)
+ return unsigned_intSI_type_node;
+ if (type1 == intHI_type_node)
+ return unsigned_intHI_type_node;
+ if (type1 == intQI_type_node)
+ return unsigned_intQI_type_node;
+
+ return signed_or_unsigned_type (1, type);
}
/* Return a signed type the same as TYPE in other respects. */
@@ -1196,7 +1373,18 @@ signed_type (type)
return long_integer_type_node;
if (type1 == long_long_unsigned_type_node)
return long_long_integer_type_node;
- return type;
+ if (type1 == unsigned_intTI_type_node)
+ return intTI_type_node;
+ if (type1 == unsigned_intDI_type_node)
+ return intDI_type_node;
+ if (type1 == unsigned_intSI_type_node)
+ return intSI_type_node;
+ if (type1 == unsigned_intHI_type_node)
+ return intHI_type_node;
+ if (type1 == unsigned_intQI_type_node)
+ return intQI_type_node;
+
+ return signed_or_unsigned_type (0, type);
}
/* Return a type the same as TYPE except unsigned or
@@ -1207,8 +1395,10 @@ signed_or_unsigned_type (unsignedp, type)
int unsignedp;
tree type;
{
- if (! INTEGRAL_TYPE_P (type))
+ if (! INTEGRAL_TYPE_P (type)
+ || TREE_UNSIGNED (type) == unsignedp)
return type;
+
if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
return unsignedp ? unsigned_char_type_node : signed_char_type_node;
if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
@@ -1223,6 +1413,8 @@ signed_or_unsigned_type (unsignedp, type)
return type;
}
+/* Compute the value of the `sizeof' operator. */
+
tree
c_sizeof (type)
tree type;
@@ -1230,6 +1422,9 @@ c_sizeof (type)
enum tree_code code = TREE_CODE (type);
tree t;
+ if (processing_template_decl)
+ return build_min (SIZEOF_EXPR, sizetype, type);
+
if (code == FUNCTION_TYPE)
{
if (pedantic || warn_pointer_arith)
@@ -1274,15 +1469,16 @@ c_sizeof (type)
return size_int (0);
}
- if (TYPE_SIZE (type) == 0)
+ if (TYPE_SIZE (complete_type (type)) == 0)
{
- error ("`sizeof' applied to an incomplete type");
+ cp_error ("`sizeof' applied to incomplete type `%T'", type);
return size_int (0);
}
/* Convert in case a char is more than one unit. */
t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (TYPE_PRECISION (char_type_node)));
+ t = convert (sizetype, t);
/* size_binop does not put the constant in range, so do it now. */
if (TREE_CODE (t) == INTEGER_CST && force_fit_type (t, 0))
TREE_CONSTANT_OVERFLOW (t) = TREE_OVERFLOW (t) = 1;
@@ -1290,6 +1486,36 @@ c_sizeof (type)
}
tree
+expr_sizeof (e)
+ tree e;
+{
+ if (processing_template_decl)
+ return build_min (SIZEOF_EXPR, sizetype, e);
+
+ if (TREE_CODE (e) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (e, 1)))
+ error ("sizeof applied to a bit-field");
+ /* ANSI says arrays and functions are converted inside comma.
+ But we can't really convert them in build_compound_expr
+ because that would break commas in lvalues.
+ So do the conversion here if operand was a comma. */
+ if (TREE_CODE (e) == COMPOUND_EXPR
+ && (TREE_CODE (TREE_TYPE (e)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (e)) == FUNCTION_TYPE))
+ e = default_conversion (e);
+ else if (TREE_CODE (e) == TREE_LIST)
+ {
+ tree t = TREE_VALUE (e);
+ if (t != NULL_TREE
+ && ((TREE_TYPE (t)
+ && TREE_CODE (TREE_TYPE (t)) == FUNCTION_TYPE)
+ || is_overloaded_fn (t)))
+ pedwarn ("ANSI C++ forbids taking the sizeof a function type");
+ }
+ return c_sizeof (TREE_TYPE (e));
+}
+
+tree
c_sizeof_nowarn (type)
tree type;
{
@@ -1305,18 +1531,12 @@ c_sizeof_nowarn (type)
type = TREE_TYPE (type);
if (TYPE_SIZE (type) == 0)
- {
-#if 0
- /* ??? Tiemann, why have any diagnostic here?
- There is none in the corresponding function for C. */
- warning ("sizeof applied to an incomplete type");
-#endif
- return size_int (0);
- }
+ return size_int (0);
/* Convert in case a char is more than one unit. */
t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
size_int (TYPE_PRECISION (char_type_node)));
+ t = convert (sizetype, t);
force_fit_type (t, 0);
return t;
}
@@ -1331,6 +1551,9 @@ c_alignof (type)
enum tree_code code = TREE_CODE (type);
tree t;
+ if (processing_template_decl)
+ return build_min (ALIGNOF_EXPR, sizetype, type);
+
if (code == FUNCTION_TYPE || code == METHOD_TYPE)
return size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
@@ -1368,13 +1591,19 @@ decay_conversion (exp)
register tree type = TREE_TYPE (exp);
register enum tree_code code = TREE_CODE (type);
- if (code == OFFSET_TYPE /* || TREE_CODE (exp) == OFFSET_REF */ )
+ if (code == OFFSET_TYPE)
{
if (TREE_CODE (exp) == OFFSET_REF)
return decay_conversion (resolve_offset_ref (exp));
type = TREE_TYPE (type);
code = TREE_CODE (type);
+
+ if (type == unknown_type_node)
+ {
+ cp_pedwarn ("assuming & on overloaded member function");
+ return build_unary_op (ADDR_EXPR, exp, 0);
+ }
}
if (code == REFERENCE_TYPE)
@@ -1408,12 +1637,7 @@ decay_conversion (exp)
}
if (code == METHOD_TYPE)
{
- if (TREE_CODE (exp) == OFFSET_REF)
- {
- my_friendly_assert (TREE_CODE (TREE_OPERAND (exp, 1)) == FUNCTION_DECL,
- 308);
- return build_unary_op (ADDR_EXPR, TREE_OPERAND (exp, 1), 0);
- }
+ cp_pedwarn ("assuming & on `%E'", exp);
return build_unary_op (ADDR_EXPR, exp, 0);
}
if (code == ARRAY_TYPE)
@@ -1431,11 +1655,12 @@ decay_conversion (exp)
if (TREE_CODE (TREE_TYPE (inner)) == REFERENCE_TYPE)
{
inner = build1 (CONVERT_EXPR,
- build_pointer_type (TREE_TYPE (TREE_TYPE (inner))),
+ build_pointer_type (TREE_TYPE
+ (TREE_TYPE (inner))),
inner);
- TREE_REFERENCE_EXPR (inner) = 1;
+ TREE_CONSTANT (inner) = TREE_CONSTANT (TREE_OPERAND (inner, 0));
}
- return convert (build_pointer_type (TREE_TYPE (type)), inner);
+ return cp_convert (build_pointer_type (TREE_TYPE (type)), inner);
}
if (TREE_CODE (exp) == COMPOUND_EXPR)
@@ -1464,8 +1689,8 @@ decay_conversion (exp)
if (TYPE_READONLY (type) || TYPE_VOLATILE (type)
|| constp || volatilep)
restype = cp_build_type_variant (restype,
- TYPE_READONLY (type) || constp,
- TYPE_VOLATILE (type) || volatilep);
+ TYPE_READONLY (type) || constp,
+ TYPE_VOLATILE (type) || volatilep);
ptrtype = build_pointer_type (restype);
if (TREE_CODE (exp) == VAR_DECL)
@@ -1484,7 +1709,7 @@ decay_conversion (exp)
/* This way is better for a COMPONENT_REF since it can
simplify the offset for a component. */
adr = build_unary_op (ADDR_EXPR, exp, 1);
- return convert (ptrtype, adr);
+ return cp_convert (ptrtype, adr);
}
return exp;
@@ -1506,14 +1731,27 @@ default_conversion (exp)
{
tree t = type_promotes_to (type);
if (t != type)
- return convert (t, exp);
+ return cp_convert (t, exp);
}
- if (flag_traditional
- && TYPE_MAIN_VARIANT (type) == float_type_node)
- return convert (double_type_node, exp);
return exp;
}
+
+/* Take the address of an inline function without setting TREE_ADDRESSABLE
+ or TREE_USED. */
+
+tree
+inline_conversion (exp)
+ tree exp;
+{
+ if (TREE_CODE (exp) == FUNCTION_DECL)
+ {
+ tree type = build_type_variant
+ (TREE_TYPE (exp), TREE_READONLY (exp), TREE_THIS_VOLATILE (exp));
+ exp = build1 (ADDR_EXPR, build_pointer_type (type), exp);
+ }
+ return exp;
+}
tree
build_object_ref (datum, basetype, field)
@@ -1532,107 +1770,107 @@ build_object_ref (datum, basetype, field)
basetype, field, dtype);
return error_mark_node;
}
- else if (IS_SIGNATURE (IDENTIFIER_TYPE_VALUE (basetype)))
+ else if (IS_SIGNATURE (basetype))
{
warning ("signature name in scope resolution ignored");
return build_component_ref (datum, field, NULL_TREE, 1);
}
- else if (is_aggr_typedef (basetype, 1))
+ else if (is_aggr_type (basetype, 1))
{
- tree real_basetype = IDENTIFIER_TYPE_VALUE (basetype);
- tree binfo = binfo_or_else (real_basetype, TREE_TYPE (datum));
+ tree binfo = binfo_or_else (basetype, dtype);
if (binfo)
- return build_component_ref (build_scoped_ref (datum, basetype),
- field, binfo, 1);
+ return build_x_component_ref (build_scoped_ref (datum, basetype),
+ field, binfo, 1);
}
return error_mark_node;
}
-/* Like `build_component_ref, but uses an already found field.
- Must compute access for C_C_D. Otherwise, ok. */
+/* Like `build_component_ref, but uses an already found field, and converts
+ from a reference. Must compute access for current_class_ref.
+ Otherwise, ok. */
+
tree
build_component_ref_1 (datum, field, protect)
tree datum, field;
int protect;
{
- register tree basetype = TREE_TYPE (datum);
- register enum tree_code code = TREE_CODE (basetype);
- register tree ref;
-
- if (code == REFERENCE_TYPE)
- {
- datum = convert_from_reference (datum);
- basetype = TREE_TYPE (datum);
- code = TREE_CODE (basetype);
- }
+ return convert_from_reference
+ (build_component_ref (datum, field, NULL_TREE, protect));
+}
- if (! IS_AGGR_TYPE_CODE (code))
- {
- if (code != ERROR_MARK)
- cp_error ("request for member `%D' in `%E', which is of non-aggregate type `%T'",
- field, datum, basetype);
- return error_mark_node;
- }
+/* Given a COND_EXPR, MIN_EXPR, or MAX_EXPR in T, return it in a form that we
+ can, for example, use as an lvalue. This code used to be in
+ unary_complex_lvalue, but we needed it to deal with `a = (d == c) ? b : c'
+ expressions, where we're dealing with aggregates. But now it's again only
+ called from unary_complex_lvalue. The case (in particular) that led to
+ this was with CODE == ADDR_EXPR, since it's not an lvalue when we'd
+ get it there. */
- if (TYPE_SIZE (basetype) == 0)
+static tree
+rationalize_conditional_expr (code, t)
+ enum tree_code code;
+ tree t;
+{
+ /* For MIN_EXPR or MAX_EXPR, fold-const.c has arranged things so that
+ the first operand is always the one to be used if both operands
+ are equal, so we know what conditional expression this used to be. */
+ if (TREE_CODE (t) == MIN_EXPR || TREE_CODE (t) == MAX_EXPR)
{
- incomplete_type_error (0, basetype);
- return error_mark_node;
+ return
+ build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
+ ? LE_EXPR : GE_EXPR),
+ TREE_OPERAND (t, 0),
+ TREE_OPERAND (t, 1)),
+ build_unary_op (code, TREE_OPERAND (t, 0), 0),
+ build_unary_op (code, TREE_OPERAND (t, 1), 0));
}
- /* Look up component name in the structure type definition. */
+ return
+ build_conditional_expr (TREE_OPERAND (t, 0),
+ build_unary_op (code, TREE_OPERAND (t, 1), 0),
+ build_unary_op (code, TREE_OPERAND (t, 2), 0));
+}
- if (field == error_mark_node)
- my_friendly_abort (115);
+/* Given the TYPE of an anonymous union field inside T, return the
+ FIELD_DECL for the field. If not found return NULL_TREE. Because
+ anonymous unions can nest, we must also search all anonymous unions
+ that are directly reachable. */
- if (TREE_STATIC (field))
- return field;
+static tree
+lookup_anon_field (t, type)
+ tree t, type;
+{
+ tree field;
- if (datum == C_C_D)
+ for (field = TYPE_FIELDS (t); field; field = TREE_CHAIN (field))
{
- enum access_type access
- = compute_access (TYPE_BINFO (current_class_type), field);
+ if (TREE_STATIC (field))
+ continue;
+ if (TREE_CODE (field) != FIELD_DECL)
+ continue;
- if (access == access_private)
+ /* If we find it directly, return the field. */
+ if (DECL_NAME (field) == NULL_TREE
+ && type == TREE_TYPE (field))
{
- cp_error ("field `%D' is private", field);
- return error_mark_node;
+ return field;
}
- else if (access == access_protected)
+
+ /* Otherwise, it could be nested, search harder. */
+ if (DECL_NAME (field) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
{
- cp_error ("field `%D' is protected", field);
- return error_mark_node;
+ tree subfield = lookup_anon_field (TREE_TYPE (field), type);
+ if (subfield)
+ return subfield;
}
}
-
- ref = build (COMPONENT_REF, TREE_TYPE (field), datum, field);
-
- if (TREE_READONLY (datum) || TREE_READONLY (field))
- TREE_READONLY (ref) = 1;
- if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field))
- TREE_THIS_VOLATILE (ref) = 1;
- if (DECL_MUTABLE_P (field))
- TREE_READONLY (ref) = 0;
-
- return ref;
+ return NULL_TREE;
}
-/* Given a COND_EXPR in T, return it in a form that we can, for
- example, use as an lvalue. This code used to be in unary_complex_lvalue,
- but we needed it to deal with `a = (d == c) ? b : c' expressions, where
- we're dealing with aggregates. So, we now call this in unary_complex_lvalue,
- and in build_modify_expr. The case (in particular) that led to this was
- with CODE == ADDR_EXPR, since it's not an lvalue when we'd get it there. */
-static tree
-rationalize_conditional_expr (code, t)
- enum tree_code code;
- tree t;
-{
- return
- build_conditional_expr (TREE_OPERAND (t, 0),
- build_unary_op (code, TREE_OPERAND (t, 1), 0),
- build_unary_op (code, TREE_OPERAND (t, 2), 0));
-}
+/* Build a COMPONENT_REF for a given DATUM, and it's member COMPONENT.
+ COMPONENT can be an IDENTIFIER_NODE that is the name of the member
+ that we are interested in, or it can be a FIELD_DECL. */
tree
build_component_ref (datum, component, basetype_path, protect)
@@ -1640,11 +1878,15 @@ build_component_ref (datum, component, basetype_path, protect)
int protect;
{
register tree basetype = TREE_TYPE (datum);
- register enum tree_code code = TREE_CODE (basetype);
+ register enum tree_code code;
register tree field = NULL;
register tree ref;
- /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference inside it. */
+ if (processing_template_decl)
+ return build_min_nt (COMPONENT_REF, datum, component);
+
+ /* If DATUM is a COMPOUND_EXPR or COND_EXPR, move our reference
+ inside it. */
switch (TREE_CODE (datum))
{
case COMPOUND_EXPR:
@@ -1661,33 +1903,42 @@ build_component_ref (datum, component, basetype_path, protect)
basetype_path, protect),
build_component_ref (TREE_OPERAND (datum, 2), component,
basetype_path, protect));
+
+ case TEMPLATE_DECL:
+ cp_error ("invalid use of %D", datum);
+ datum = error_mark_node;
+ break;
+
+ default:
+ break;
}
+ code = TREE_CODE (basetype);
+
if (code == REFERENCE_TYPE)
{
-#if 0
- /* TREE_REFERENCE_EXPRs are not converted by `convert_from_reference'.
- @@ Maybe that is not right. */
- if (TREE_REFERENCE_EXPR (datum))
- datum = build1 (INDIRECT_REF, TREE_TYPE (basetype), datum);
- else
-#endif
- datum = convert_from_reference (datum);
+ datum = convert_from_reference (datum);
+ basetype = TREE_TYPE (datum);
+ code = TREE_CODE (basetype);
+ }
+ if (TREE_CODE (datum) == OFFSET_REF)
+ {
+ datum = resolve_offset_ref (datum);
basetype = TREE_TYPE (datum);
code = TREE_CODE (basetype);
}
- /* First, see if there is a field or component with name COMPONENT. */
+ /* First, see if there is a field or component with name COMPONENT. */
if (TREE_CODE (component) == TREE_LIST)
{
+ /* I could not trigger this code. MvL */
+ my_friendly_abort (980326);
+#ifdef DEAD
my_friendly_assert (!(TREE_CHAIN (component) == NULL_TREE
&& DECL_CHAIN (TREE_VALUE (component)) == NULL_TREE), 309);
+#endif
return build (COMPONENT_REF, TREE_TYPE (component), datum, component);
}
-#if 0
- if (TREE_CODE (component) == TYPE_EXPR)
- return build_component_type_expr (datum, component, NULL_TREE, protect);
-#endif
if (! IS_AGGR_TYPE_CODE (code))
{
@@ -1697,11 +1948,8 @@ build_component_ref (datum, component, basetype_path, protect)
return error_mark_node;
}
- if (TYPE_SIZE (basetype) == 0)
- {
- incomplete_type_error (0, basetype);
- return error_mark_node;
- }
+ if (!complete_type_or_else (basetype))
+ return error_mark_node;
if (TREE_CODE (component) == BIT_NOT_EXPR)
{
@@ -1716,7 +1964,7 @@ build_component_ref (datum, component, basetype_path, protect)
cp_error ("type `%T' has no destructor", basetype);
return error_mark_node;
}
- return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 0);
+ return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (basetype), 1);
}
/* Look up component name in the structure type definition. */
@@ -1726,12 +1974,22 @@ build_component_ref (datum, component, basetype_path, protect)
hierarchy, the compiler will abort (because vptr lookups are
not supposed to be ambiguous. */
field = CLASSTYPE_VFIELD (basetype);
+ else if (TREE_CODE (component) == FIELD_DECL)
+ field = component;
+ else if (TREE_CODE (component) == TYPE_DECL)
+ {
+ cp_pedwarn ("invalid use of type decl `%#D' as expression", component);
+ return component;
+ }
else
{
+ tree name = component;
+ if (TREE_CODE (component) == VAR_DECL)
+ name = DECL_NAME (component);
if (basetype_path == NULL_TREE)
basetype_path = TYPE_BINFO (basetype);
- field = lookup_field (basetype_path, component,
- protect && ! VFIELD_NAME_P (component), 0);
+ field = lookup_field (basetype_path, name,
+ protect && !VFIELD_NAME_P (name), 0);
if (field == error_mark_node)
return error_mark_node;
@@ -1740,36 +1998,47 @@ build_component_ref (datum, component, basetype_path, protect)
/* Not found as a data field, look for it as a method. If found,
then if this is the only possible one, return it, else
report ambiguity error. */
- tree fndecls = lookup_fnfields (basetype_path, component, 1);
+ tree fndecls = lookup_fnfields (basetype_path, name, 1);
if (fndecls == error_mark_node)
return error_mark_node;
if (fndecls)
{
if (TREE_CHAIN (fndecls) == NULL_TREE
- && DECL_CHAIN (TREE_VALUE (fndecls)) == NULL_TREE)
+ && TREE_CODE (TREE_VALUE (fndecls)) != OVERLOAD)
{
- enum access_type access;
- tree fndecl;
+ tree access, fndecl;
/* Unique, so use this one now. */
basetype = TREE_PURPOSE (fndecls);
fndecl = TREE_VALUE (fndecls);
access = compute_access (TREE_PURPOSE (fndecls), fndecl);
- if (access == access_public)
+ if (access == access_public_node)
{
if (DECL_VINDEX (fndecl)
&& ! resolves_to_fixed_type_p (datum, 0))
{
tree addr = build_unary_op (ADDR_EXPR, datum, 0);
- addr = convert_pointer_to (DECL_CONTEXT (fndecl), addr);
+ tree fntype = TREE_TYPE (fndecl);
+
+ addr = convert_pointer_to (DECL_CONTEXT (fndecl),
+ addr);
datum = build_indirect_ref (addr, NULL_PTR);
my_friendly_assert (datum != error_mark_node, 310);
- fndecl = build_vfn_ref (&addr, datum, DECL_VINDEX (fndecl));
+ fndecl = build_vfn_ref (&addr, datum,
+ DECL_VINDEX (fndecl));
+ /* The type of fndecl is a function type,
+ not a pointer-to-function type, since
+ build_vfn_ref returns not the correct
+ vtable slot, but the indirection of the
+ correct vtable slot. */
+ TREE_TYPE (fndecl) = fntype;
}
- assemble_external (fndecl);
- return fndecl;
+ else
+ mark_used (fndecl);
+ return build (OFFSET_REF, TREE_TYPE (fndecl),
+ datum, fndecl);
}
- if (access == access_protected)
+ if (access == access_protected_node)
cp_error ("member function `%D' is protected", fndecl);
else
cp_error ("member function `%D' is private", fndecl);
@@ -1781,9 +2050,6 @@ build_component_ref (datum, component, basetype_path, protect)
not matter unless we're actually calling the function. */
tree t;
- for (t = TREE_VALUE (fndecls); t; t = DECL_CHAIN (t))
- assemble_external (t);
-
t = build_tree_list (error_mark_node, fndecls);
TREE_TYPE (t) = build_offset_type (basetype,
unknown_type_node);
@@ -1791,12 +2057,7 @@ build_component_ref (datum, component, basetype_path, protect)
}
}
-#if 0
- if (component == ansi_opname[(int) TYPE_EXPR])
- cp_error ("`%#T' has no such type conversion operator", basetype);
- else
-#endif
- cp_error ("`%#T' has no member named `%D'", basetype, component);
+ cp_error ("`%#T' has no member named `%D'", basetype, name);
return error_mark_node;
}
else if (TREE_TYPE (field) == error_mark_node)
@@ -1805,30 +2066,61 @@ build_component_ref (datum, component, basetype_path, protect)
if (TREE_CODE (field) != FIELD_DECL)
{
if (TREE_CODE (field) == TYPE_DECL)
- {
- cp_error ("invalid use of type decl `%#D' as expression", field);
- return error_mark_node;
- }
- if (DECL_RTL (field) != 0)
- assemble_external (field);
- TREE_USED (field) = 1;
+ cp_pedwarn ("invalid use of type decl `%#D' as expression", field);
+ else if (DECL_RTL (field) != 0)
+ mark_used (field);
+ else
+ TREE_USED (field) = 1;
return field;
}
}
- if (DECL_FIELD_CONTEXT (field) != basetype
- && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+ /* See if we have to do any conversions so that we pick up the field from the
+ right context. */
+ if (DECL_FIELD_CONTEXT (field) != basetype)
{
- tree addr = build_unary_op (ADDR_EXPR, datum, 0);
- if (integer_zerop (addr))
+ tree context = DECL_FIELD_CONTEXT (field);
+ tree base = context;
+ while (!comptypes (base, basetype,1) && TYPE_NAME (base)
+ && ANON_UNION_TYPE_P (base))
{
- error ("invalid reference to NULL ptr, use ptr-to-member instead");
- return error_mark_node;
+ base = TYPE_CONTEXT (base);
+ }
+
+ /* Handle base classes here... */
+ if (base != basetype && TYPE_USES_COMPLEX_INHERITANCE (basetype))
+ {
+ tree addr = build_unary_op (ADDR_EXPR, datum, 0);
+ if (integer_zerop (addr))
+ {
+ error ("invalid reference to NULL ptr, use ptr-to-member instead");
+ return error_mark_node;
+ }
+ if (VBASE_NAME_P (DECL_NAME (field)))
+ {
+ /* It doesn't matter which vbase pointer we grab, just
+ find one of them. */
+ tree binfo = get_binfo (base,
+ TREE_TYPE (TREE_TYPE (addr)), 0);
+ addr = convert_pointer_to_real (binfo, addr);
+ }
+ else
+ addr = convert_pointer_to (base, addr);
+ datum = build_indirect_ref (addr, NULL_PTR);
+ my_friendly_assert (datum != error_mark_node, 311);
+ }
+ basetype = base;
+
+ /* Handle things from anon unions here... */
+ if (TYPE_NAME (context) && ANON_UNION_TYPE_P (context))
+ {
+ tree subfield = lookup_anon_field (basetype, context);
+ tree subdatum = build_component_ref (datum, subfield,
+ basetype_path, protect);
+ return build_component_ref (subdatum, field, basetype_path, protect);
}
- addr = convert_pointer_to (DECL_FIELD_CONTEXT (field), addr);
- datum = build_indirect_ref (addr, NULL_PTR);
- my_friendly_assert (datum != error_mark_node, 311);
}
+
ref = fold (build (COMPONENT_REF, TREE_TYPE (field),
break_out_cleanups (datum), field));
@@ -1836,11 +2128,27 @@ build_component_ref (datum, component, basetype_path, protect)
TREE_READONLY (ref) = 1;
if (TREE_THIS_VOLATILE (datum) || TREE_THIS_VOLATILE (field))
TREE_THIS_VOLATILE (ref) = 1;
- if (DECL_MUTABLE_P (field))
+ if (DECL_LANG_SPECIFIC (field) && DECL_MUTABLE_P (field))
TREE_READONLY (ref) = 0;
return ref;
}
+
+/* Variant of build_component_ref for use in expressions, which should
+ never have REFERENCE_TYPE. */
+
+tree
+build_x_component_ref (datum, component, basetype_path, protect)
+ tree datum, component, basetype_path;
+ int protect;
+{
+ tree t = build_component_ref (datum, component, basetype_path, protect);
+
+ if (! processing_template_decl)
+ t = convert_from_reference (t);
+
+ return t;
+}
/* Given an expression PTR for a pointer, return an expression
for the value pointed to.
@@ -1854,7 +2162,13 @@ build_x_indirect_ref (ptr, errorstring)
tree ptr;
char *errorstring;
{
- tree rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE, NULL_TREE);
+ tree rval;
+
+ if (processing_template_decl)
+ return build_min_nt (INDIRECT_REF, ptr);
+
+ rval = build_opfncall (INDIRECT_REF, LOOKUP_NORMAL, ptr, NULL_TREE,
+ NULL_TREE);
if (rval)
return rval;
return build_indirect_ref (ptr, errorstring);
@@ -1865,27 +2179,22 @@ build_indirect_ref (ptr, errorstring)
tree ptr;
char *errorstring;
{
- register tree pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE ?
- ptr : default_conversion (ptr));
- register tree type = TREE_TYPE (pointer);
+ register tree pointer, type;
- if (ptr == current_class_decl)
- return C_C_D;
+ if (ptr == error_mark_node)
+ return error_mark_node;
- if (IS_AGGR_TYPE (type))
- {
- ptr = build_expr_type_conversion (WANT_POINTER, pointer, 1);
+ pointer = (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
+ ? ptr : default_conversion (ptr));
+ type = TREE_TYPE (pointer);
- if (ptr)
- {
- pointer = ptr;
- type = TREE_TYPE (pointer);
- }
- }
+ if (ptr == current_class_ptr)
+ return current_class_ref;
if (TREE_CODE (type) == POINTER_TYPE || TREE_CODE (type) == REFERENCE_TYPE)
{
if (TREE_CODE (pointer) == ADDR_EXPR
+ && !flag_volatile
&& (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (pointer, 0)))
== TYPE_MAIN_VARIANT (TREE_TYPE (type)))
&& (TREE_READONLY (TREE_OPERAND (pointer, 0))
@@ -1899,10 +2208,14 @@ build_indirect_ref (ptr, errorstring)
register tree ref = build1 (INDIRECT_REF,
TYPE_MAIN_VARIANT (t), pointer);
+ /* We *must* set TREE_READONLY when dereferencing a pointer to const,
+ so that we get the proper error message if the result is used
+ to assign to. Also, &* is supposed to be a no-op. */
TREE_READONLY (ref) = TYPE_READONLY (t);
- TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
TREE_SIDE_EFFECTS (ref)
- = TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer);
+ = (TYPE_VOLATILE (t) || TREE_SIDE_EFFECTS (pointer)
+ || flag_volatile);
+ TREE_THIS_VOLATILE (ref) = TYPE_VOLATILE (t);
return ref;
}
}
@@ -1937,21 +2250,9 @@ build_indirect_ref (ptr, errorstring)
will inherit the type of the array, which will be some pointer type. */
tree
-build_x_array_ref (array, index)
- tree array, index;
-{
- tree rval = build_opfncall (ARRAY_REF, LOOKUP_NORMAL, array, index, NULL_TREE);
- if (rval)
- return rval;
- return build_array_ref (array, index);
-}
-
-tree
build_array_ref (array, idx)
tree array, idx;
{
- tree itype;
-
if (idx == 0)
{
error ("subscript missing in array reference");
@@ -1962,8 +2263,6 @@ build_array_ref (array, idx)
|| TREE_TYPE (idx) == error_mark_node)
return error_mark_node;
- itype = TREE_TYPE (idx);
-
if (TREE_CODE (TREE_TYPE (array)) == ARRAY_TYPE
&& TREE_CODE (array) != INDIRECT_REF)
{
@@ -1994,7 +2293,8 @@ build_array_ref (array, idx)
Likewise an array of elements of variable size. */
if (TREE_CODE (idx) != INTEGER_CST
|| (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))) != 0
- && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array)))) != INTEGER_CST))
+ && (TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))))
+ != INTEGER_CST)))
{
if (mark_addressable (array) == 0)
return error_mark_node;
@@ -2072,15 +2372,17 @@ build_array_ref (array, idx)
return error_mark_node;
}
- return build_indirect_ref (build_binary_op_nodefault (PLUS_EXPR, ar, ind, PLUS_EXPR),
+ return build_indirect_ref (build_binary_op_nodefault (PLUS_EXPR, ar,
+ ind, PLUS_EXPR),
"array indexing");
}
}
/* Build a function call to function FUNCTION with parameters PARAMS.
PARAMS is a list--a chain of TREE_LIST nodes--in which the
- TREE_VALUE of each node is a parameter-expression.
- FUNCTION's data type may be a function type or a pointer-to-function.
+ TREE_VALUE of each node is a parameter-expression. The PARAMS do
+ not include any object pointer that may be required. FUNCTION's
+ data type may be a function type or a pointer-to-function.
For C++: If FUNCTION's data type is a TREE_LIST, then the tree list
is the list of possible methods that FUNCTION could conceivably
@@ -2095,35 +2397,82 @@ build_array_ref (array, idx)
In the second case, TREE_PURPOSE (function) is the function's
name directly.
- DECL is the class instance variable, usually CURRENT_CLASS_DECL. */
+ DECL is the class instance variable, usually CURRENT_CLASS_REF.
+
+ When calling a TEMPLATE_DECL, we don't require a complete return
+ type. */
-/*
- * [eichin:19911015.1726EST] actually return a possibly incomplete
- * type
- */
tree
build_x_function_call (function, params, decl)
tree function, params, decl;
{
tree type;
+ tree template_id = NULL_TREE;
int is_method;
if (function == error_mark_node)
return error_mark_node;
+ if (processing_template_decl)
+ return build_min_nt (CALL_EXPR, function, params, NULL_TREE);
+
+ /* Save explicit template arguments if found */
+ if (TREE_CODE (function) == TEMPLATE_ID_EXPR)
+ {
+ template_id = function;
+ function = TREE_OPERAND (function, 0);
+ }
+
type = TREE_TYPE (function);
+
+ if (TREE_CODE (type) == OFFSET_TYPE
+ && TREE_TYPE (type) == unknown_type_node
+ && TREE_CODE (function) == TREE_LIST
+ && TREE_CHAIN (function) == NULL_TREE)
+ {
+ /* Undo (Foo:bar)()... */
+ type = TYPE_OFFSET_BASETYPE (type);
+ function = TREE_VALUE (function);
+ my_friendly_assert (TREE_CODE (function) == TREE_LIST, 999);
+ my_friendly_assert (TREE_CHAIN (function) == NULL_TREE, 999);
+ function = TREE_VALUE (function);
+ if (TREE_CODE (function) == OVERLOAD)
+ function = OVL_FUNCTION (function);
+ my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 999);
+ function = DECL_NAME (function);
+ return build_method_call (decl, function, params,
+ TYPE_BINFO (type), LOOKUP_NORMAL);
+ }
+
is_method = ((TREE_CODE (function) == TREE_LIST
&& current_class_type != NULL_TREE
- && IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function)) == function)
+ && (IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (function))
+ == function))
|| TREE_CODE (function) == IDENTIFIER_NODE
|| TREE_CODE (type) == METHOD_TYPE
|| TYPE_PTRMEMFUNC_P (type));
+ if ((TREE_CODE (function) == FUNCTION_DECL
+ && DECL_STATIC_FUNCTION_P (function))
+ || (TREE_CODE (function) == TEMPLATE_DECL
+ && DECL_STATIC_FUNCTION_P (DECL_RESULT (function))))
+ return build_member_call
+ (DECL_CONTEXT (function), DECL_NAME (function), params);
+
+ /* A friend template. Make it look like a toplevel declaration. */
+ if (! is_method && TREE_CODE (function) == TEMPLATE_DECL)
+ function = scratch_ovl_cons (function, NULL_TREE);
+
/* Handle methods, friends, and overloaded functions, respectively. */
if (is_method)
{
- if (TREE_CODE (function) == FUNCTION_DECL)
+ tree basetype = NULL_TREE;
+
+ if (TREE_CODE (function) == FUNCTION_DECL
+ || DECL_FUNCTION_TEMPLATE_P (function))
{
+ basetype = DECL_CLASS_CONTEXT (function);
+
if (DECL_NAME (function))
function = DECL_NAME (function);
else
@@ -2131,15 +2480,10 @@ build_x_function_call (function, params, decl)
}
else if (TREE_CODE (function) == TREE_LIST)
{
-#if 0
- if (TREE_CODE (TREE_VALUE (function)) == TREE_LIST)
- function = TREE_PURPOSE (TREE_VALUE (function));
- else
- function = TREE_PURPOSE (function);
-#else
- my_friendly_assert (TREE_CODE (TREE_VALUE (function)) == FUNCTION_DECL, 312);
+ my_friendly_assert (TREE_CODE (TREE_VALUE (function))
+ == FUNCTION_DECL, 312);
+ basetype = DECL_CLASS_CONTEXT (TREE_VALUE (function));
function = TREE_PURPOSE (function);
-#endif
}
else if (TREE_CODE (function) != IDENTIFIER_NODE)
{
@@ -2158,7 +2502,8 @@ build_x_function_call (function, params, decl)
if (TREE_CODE (TREE_TYPE (function)) != POINTER_TYPE
&& ! TYPE_PTRMEMFUNC_P (TREE_TYPE (function))
&& TREE_CODE (function) != OFFSET_REF)
- function = build (OFFSET_REF, TREE_TYPE (type), NULL_TREE, function);
+ function = build (OFFSET_REF, TREE_TYPE (type), NULL_TREE,
+ function);
goto do_x_function;
}
@@ -2166,6 +2511,10 @@ build_x_function_call (function, params, decl)
must go through here in case it is a virtual function.
@@ Perhaps this could be optimized. */
+ if (basetype && (! current_class_type
+ || ! DERIVED_FROM_P (basetype, current_class_type)))
+ return build_member_call (basetype, function, params);
+
if (decl == NULL_TREE)
{
if (current_class_type == NULL_TREE)
@@ -2180,6 +2529,9 @@ build_x_function_call (function, params, decl)
decl = build_indirect_ref (decl, NULL_PTR);
}
+ /* Put back explicit template arguments, if any. */
+ if (template_id)
+ function = template_id;
return build_method_call (decl, function, params,
NULL_TREE, LOOKUP_NORMAL);
}
@@ -2188,16 +2540,16 @@ build_x_function_call (function, params, decl)
{
/* Should we undo what was done in build_component_ref? */
if (TREE_CODE (TREE_PURPOSE (TREE_OPERAND (function, 1))) == TREE_VEC)
- /* Get the name that build_component_ref hid. */
+ /* Get the name that build_component_ref hid. */
function = DECL_NAME (TREE_VALUE (TREE_OPERAND (function, 1)));
else
function = TREE_PURPOSE (TREE_OPERAND (function, 1));
return build_method_call (decl, function, params,
NULL_TREE, LOOKUP_NORMAL);
}
- else if (TREE_CODE (function) == TREE_LIST)
+ else if (really_overloaded_fn (function))
{
- if (TREE_VALUE (function) == NULL_TREE)
+ if (OVL_FUNCTION (function) == NULL_TREE)
{
cp_error ("function `%D' declared overloaded, but no definitions appear with which to resolve it?!?",
TREE_PURPOSE (function));
@@ -2205,18 +2557,15 @@ build_x_function_call (function, params, decl)
}
else
{
- tree val = TREE_VALUE (function);
-
- if (TREE_CODE (val) == TEMPLATE_DECL)
- return build_overload_call_maybe
- (function, params, LOOKUP_COMPLAIN, (struct candidate *)0);
- else if (DECL_CHAIN (val) != NULL_TREE)
- return build_overload_call
- (function, params, LOOKUP_COMPLAIN, (struct candidate *)0);
- else
- my_friendly_abort (360);
+ /* Put back explicit template arguments, if any. */
+ if (template_id)
+ function = template_id;
+ return build_new_function_call (function, params);
}
}
+ else
+ /* Remove a potential OVERLOAD around it */
+ function = OVL_CURRENT (function);
do_x_function:
if (TREE_CODE (function) == OFFSET_REF)
@@ -2228,12 +2577,23 @@ build_x_function_call (function, params, decl)
if (TREE_OPERAND (function, 0))
decl = TREE_OPERAND (function, 0);
else
- decl = C_C_D;
+ decl = current_class_ref;
decl_addr = build_unary_op (ADDR_EXPR, decl, 0);
- function = get_member_function_from_ptrfunc (&decl_addr,
- TREE_OPERAND (function, 1));
- params = tree_cons (NULL_TREE, decl_addr, params);
+
+ /* Sigh. OFFSET_REFs are being used for too many things.
+ They're being used both for -> and ->*, and we want to resolve
+ the -> cases here, but leave the ->*. We could use
+ resolve_offset_ref for those, too, but it would call
+ get_member_function_from_ptrfunc and decl_addr wouldn't get
+ updated properly. Nasty. */
+ if (TREE_CODE (TREE_OPERAND (function, 1)) == FIELD_DECL)
+ function = resolve_offset_ref (function);
+ else
+ function = TREE_OPERAND (function, 1);
+
+ function = get_member_function_from_ptrfunc (&decl_addr, function);
+ params = expr_tree_cons (NULL_TREE, decl_addr, params);
return build_function_call (function, params);
}
@@ -2243,14 +2603,14 @@ build_x_function_call (function, params, decl)
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
- if (TYPE_LANG_SPECIFIC (type) && TYPE_OVERLOADS_CALL_EXPR (type))
+ if (IS_AGGR_TYPE (type))
return build_opfncall (CALL_EXPR, LOOKUP_NORMAL, function, params, NULL_TREE);
}
if (is_method)
{
tree fntype = TREE_TYPE (function);
- tree ctypeptr;
+ tree ctypeptr = NULL_TREE;
/* Explicitly named method? */
if (TREE_CODE (function) == FUNCTION_DECL)
@@ -2260,7 +2620,8 @@ build_x_function_call (function, params, decl)
passed in as an argument. */
else if (TYPE_PTRMEMFUNC_P (fntype))
{
- tree rec = TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (fntype)));
+ tree rec = TYPE_METHOD_BASETYPE (TREE_TYPE
+ (TYPE_PTRMEMFUNC_FN_TYPE (fntype)));
ctypeptr = build_pointer_type (rec);
}
/* Unexpected node type? */
@@ -2282,8 +2643,8 @@ build_x_function_call (function, params, decl)
decl = convert_pointer_to (TREE_TYPE (ctypeptr), decl);
}
else
- decl = build_c_cast (ctypeptr, decl, 0);
- params = tree_cons (NULL_TREE, decl, params);
+ decl = build_c_cast (ctypeptr, decl);
+ params = expr_tree_cons (NULL_TREE, decl, params);
}
return build_function_call (function, params);
@@ -2304,7 +2665,7 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (function)))
{
- tree fntype, index, e1, delta, delta2, e2, e3, aref, vtbl;
+ tree fntype, idx, e1, delta, delta2, e2, e3, aref, vtbl;
tree instance;
tree instance_ptr = *instance_ptrptr;
@@ -2316,43 +2677,49 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
function = save_expr (function);
fntype = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (function));
- index = save_expr (build_component_ref (function,
- index_identifier,
- 0, 0));
- e1 = build (GT_EXPR, boolean_type_node, index,
- convert (delta_type_node, integer_zero_node));
- delta = convert (ptrdiff_type_node,
- build_component_ref (function, delta_identifier, 0, 0));
+
+ /* Promoting idx before saving it improves performance on RISC
+ targets. Without promoting, the first compare used
+ load-with-sign-extend, while the second used normal load then
+ shift to sign-extend. An optimizer flaw, perhaps, but it's easier
+ to make this change. */
+ idx = save_expr (default_conversion
+ (build_component_ref (function,
+ index_identifier,
+ NULL_TREE, 0)));
+ e1 = build_binary_op (GT_EXPR, idx, integer_zero_node, 1);
+ delta = cp_convert (ptrdiff_type_node,
+ build_component_ref (function, delta_identifier,
+ NULL_TREE, 0));
delta2 = DELTA2_FROM_PTRMEMFUNC (function);
- /* convert down to the right base, before using the instance. */
+ /* Convert down to the right base, before using the instance. */
instance
= convert_pointer_to_real (TYPE_METHOD_BASETYPE (TREE_TYPE (fntype)),
instance_ptr);
- if (instance == error_mark_node)
+ if (instance == error_mark_node && instance_ptr != error_mark_node)
return instance;
vtbl = convert_pointer_to (ptr_type_node, instance);
vtbl
= build (PLUS_EXPR,
build_pointer_type (build_pointer_type (vtable_entry_type)),
- vtbl, convert (ptrdiff_type_node, delta2));
+ vtbl, cp_convert (ptrdiff_type_node, delta2));
vtbl = build_indirect_ref (vtbl, NULL_PTR);
aref = build_array_ref (vtbl, build_binary_op (MINUS_EXPR,
- index,
+ idx,
integer_one_node, 1));
if (! flag_vtable_thunks)
{
aref = save_expr (aref);
- /* Save the intermediate result in a SAVE_EXPR so we don't have to
- compute each component of the virtual function pointer twice. */
- if (/* !building_cleanup && */ TREE_CODE (aref) == INDIRECT_REF)
- TREE_OPERAND (aref, 0) = save_expr (TREE_OPERAND (aref, 0));
-
- delta = build_binary_op (PLUS_EXPR,
- build_conditional_expr (e1, build_component_ref (aref, delta_identifier, 0, 0), integer_zero_node),
- delta, 1);
+ delta = build_binary_op
+ (PLUS_EXPR,
+ build_conditional_expr (e1, build_component_ref (aref,
+ delta_identifier,
+ NULL_TREE, 0),
+ integer_zero_node),
+ delta, 1);
}
*instance_ptrptr = build (PLUS_EXPR, TREE_TYPE (instance_ptr),
@@ -2360,11 +2727,18 @@ get_member_function_from_ptrfunc (instance_ptrptr, function)
if (flag_vtable_thunks)
e2 = aref;
else
- e2 = build_component_ref (aref, pfn_identifier, 0, 0);
+ e2 = build_component_ref (aref, pfn_identifier, NULL_TREE, 0);
e3 = PFN_FROM_PTRMEMFUNC (function);
TREE_TYPE (e2) = TREE_TYPE (e3);
- function = build_conditional_expr (e1, e2, e3);
+ e1 = build_conditional_expr (e1, e2, e3);
+
+ if (instance_ptr == error_mark_node
+ && TREE_CODE (e1) != ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (e1, 0)) != FUNCTION_DECL)
+ cp_error ("object missing in `%E'", function);
+
+ function = e1;
/* Make sure this doesn't get evaluated first inside one of the
branches of the COND_EXPR. */
@@ -2399,68 +2773,41 @@ build_function_call_real (function, params, require_complete, flags)
GNU_xref_call (current_function_decl,
IDENTIFIER_POINTER (name ? name
- : TYPE_IDENTIFIER (DECL_CLASS_CONTEXT (function))));
- assemble_external (function);
+ : TYPE_IDENTIFIER (DECL_CLASS_CONTEXT
+ (function))));
+ mark_used (function);
fndecl = function;
/* Convert anything with function type to a pointer-to-function. */
- if (pedantic
- && name
- && IDENTIFIER_LENGTH (name) == 4
- && ! strcmp (IDENTIFIER_POINTER (name), "main")
- && DECL_CONTEXT (function) == NULL_TREE)
- {
- pedwarn ("ANSI C++ forbids calling `main' from within program");
- }
-
- if (pedantic && DECL_THIS_INLINE (function) && ! DECL_INITIAL (function)
- && ! DECL_ARTIFICIAL (function)
- && ! DECL_PENDING_INLINE_INFO (function))
- cp_pedwarn ("inline function `%#D' called before definition",
- function);
+ if (pedantic && DECL_MAIN_P (function))
+ pedwarn ("ANSI C++ forbids calling `main' from within program");
/* Differs from default_conversion by not setting TREE_ADDRESSABLE
(because calling an inline function does not mean the function
needs to be separately compiled). */
if (DECL_INLINE (function))
- {
- /* Is it a synthesized method that needs to be synthesized? */
- if (DECL_ARTIFICIAL (function) && ! flag_no_inline
- && ! DECL_INITIAL (function)
- /* Kludge: don't synthesize for default args. */
- && current_function_decl)
- synthesize_method (function);
-
- fntype = build_type_variant (TREE_TYPE (function),
- TREE_READONLY (function),
- TREE_THIS_VOLATILE (function));
- function = build1 (ADDR_EXPR, build_pointer_type (fntype), function);
- }
+ function = inline_conversion (function);
else
- {
- assemble_external (function);
- TREE_USED (function) = 1;
- function = default_conversion (function);
- }
+ function = build_addr_func (function);
}
else
{
fndecl = NULL_TREE;
- /* Convert anything with function type to a pointer-to-function. */
- if (function == error_mark_node)
- return error_mark_node;
- function = default_conversion (function);
+ function = build_addr_func (function);
}
+ if (function == error_mark_node)
+ return error_mark_node;
+
fntype = TREE_TYPE (function);
if (TYPE_PTRMEMFUNC_P (fntype))
{
- tree instance_ptr = build_unary_op (ADDR_EXPR, C_C_D, 0);
- fntype = TYPE_PTRMEMFUNC_FN_TYPE (fntype);
- function = get_member_function_from_ptrfunc (&instance_ptr, function);
+ cp_error ("must use .* or ->* to call pointer-to-member function in `%E (...)'",
+ function);
+ return error_mark_node;
}
is_method = (TREE_CODE (fntype) == POINTER_TYPE
@@ -2468,7 +2815,8 @@ build_function_call_real (function, params, require_complete, flags)
if (!((TREE_CODE (fntype) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (fntype)) == FUNCTION_TYPE)
- || is_method))
+ || is_method
+ || TREE_CODE (function) == TEMPLATE_ID_EXPR))
{
cp_error ("`%E' cannot be used as a function", function);
return error_mark_node;
@@ -2488,10 +2836,12 @@ build_function_call_real (function, params, require_complete, flags)
params, fndecl, 0);
if (coerced_params == error_mark_node)
- if (flags & LOOKUP_SPECULATIVELY)
- return NULL_TREE;
- else
- return error_mark_node;
+ {
+ if (flags & LOOKUP_SPECULATIVELY)
+ return NULL_TREE;
+ else
+ return error_mark_node;
+ }
/* Check for errors in format strings. */
@@ -2513,22 +2863,25 @@ build_function_call_real (function, params, require_complete, flags)
if (coerced_params == 0)
return integer_zero_node;
return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
+
+ default:
+ break;
}
/* C++ */
value_type = TREE_TYPE (fntype) ? TREE_TYPE (fntype) : void_type_node;
{
- register tree result =
- build (CALL_EXPR, value_type,
- function, coerced_params, NULL_TREE);
-
- TREE_SIDE_EFFECTS (result) = 1;
+ register tree result
+ = build_call (function, value_type, coerced_params);
- if (! require_complete)
- return convert_from_reference (result);
- if (value_type == void_type_node)
- return result;
- result = require_complete_type (result);
+ if (require_complete)
+ {
+ if (value_type == void_type_node)
+ return result;
+ result = require_complete_type (result);
+ }
+ if (IS_AGGR_TYPE (value_type))
+ result = build_cplus_new (value_type, result);
return convert_from_reference (result);
}
}
@@ -2539,14 +2892,6 @@ build_function_call (function, params)
{
return build_function_call_real (function, params, 1, LOOKUP_NORMAL);
}
-
-tree
-build_function_call_maybe (function, params)
- tree function, params;
-{
- return build_function_call_real (function, params, 0, 0);
-}
-
/* Convert the actual parameter expressions in the list VALUES
to the types in the list TYPELIST.
@@ -2576,15 +2921,17 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
tree return_loc, typelist, values, fndecl;
int flags;
{
- extern tree gc_protect_fndecl;
register tree typetail, valtail;
register tree result = NULL_TREE;
- char *called_thing;
+ char *called_thing = 0;
int i = 0;
if (! flag_elide_constructors)
return_loc = 0;
+ /* Argument passing is always copy-initialization. */
+ flags |= LOOKUP_ONLYCONVERTING;
+
if (fndecl)
{
if (TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
@@ -2613,9 +2960,8 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
{
if (fndecl)
{
- char *buf = (char *)alloca (40 + strlen (called_thing));
- sprintf (buf, "too many arguments to %s `%%s'", called_thing);
- error_with_decl (fndecl, buf);
+ cp_error_at ("too many arguments to %s `%+D'", called_thing,
+ fndecl);
error ("at this point in file");
}
else
@@ -2638,44 +2984,22 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
/* Strip the `&' from an overloaded FUNCTION_DECL. */
if (TREE_CODE (val) == ADDR_EXPR)
val = TREE_OPERAND (val, 0);
- if (TREE_CODE (val) == TREE_LIST
- && TREE_CHAIN (val) == NULL_TREE
- && TREE_TYPE (TREE_VALUE (val)) != NULL_TREE
- && (TREE_TYPE (val) == unknown_type_node
- || DECL_CHAIN (TREE_VALUE (val)) == NULL_TREE))
- /* Instantiates automatically. */
- val = TREE_VALUE (val);
+ if (really_overloaded_fn (val))
+ cp_error ("insufficient type information to resolve address of overloaded function `%D'",
+ DECL_NAME (get_first_fn (val)));
else
- {
- error ("insufficient type information in parameter list");
- val = integer_zero_node;
- }
+ error ("insufficient type information in parameter list");
+ val = integer_zero_node;
}
else if (TREE_CODE (val) == OFFSET_REF
&& TREE_CODE (TREE_TYPE (val)) == METHOD_TYPE)
{
- /* This is unclean. Should be handled elsewhere. */
+ /* This is unclean. Should be handled elsewhere. */
val = build_unary_op (ADDR_EXPR, val, 0);
}
else if (TREE_CODE (val) == OFFSET_REF)
val = resolve_offset_ref (val);
- {
-#if 0
- /* This code forces the assumption that if we have a ptr-to-func
- type in an arglist, that every routine that wants to check
- its validity has done so, and thus we need not do any
- more conversion. I don't remember why this is necessary. */
- else if (TREE_CODE (ttype) == FUNCTION_TYPE
- && (type == NULL
- || TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (type)) == VOID_TYPE))
- {
- type = build_pointer_type (ttype);
- }
-#endif
- }
-
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
Strip such NOP_EXPRs, since VAL is used in non-lvalue context. */
if (TREE_CODE (val) == NOP_EXPR
@@ -2701,29 +3025,21 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
/* Formal parm type is specified by a function prototype. */
tree parmval;
- if (TYPE_SIZE (type) == 0)
+ if (TYPE_SIZE (complete_type (type)) == 0)
{
error ("parameter type of called function is incomplete");
parmval = val;
}
else
{
-#if 0 && defined (PROMOTE_PROTOTYPES)
- /* This breaks user-defined conversions. */
- /* Rather than truncating and then reextending,
- convert directly to int, if that's the type we will want. */
- if (! flag_traditional
- && (TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE)
- && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
- type = integer_type_node;
-#endif
- parmval = convert_for_initialization (return_loc, type, val, flags,
- "argument passing", fndecl, i);
+ parmval = convert_for_initialization
+ (return_loc, type, val, flags,
+ "argument passing", fndecl, i);
#ifdef PROMOTE_PROTOTYPES
if ((TREE_CODE (type) == INTEGER_TYPE
|| TREE_CODE (type) == ENUMERAL_TYPE)
- && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
+ && (TYPE_PRECISION (type)
+ < TYPE_PRECISION (integer_type_node)))
parmval = default_conversion (parmval);
#endif
}
@@ -2731,41 +3047,18 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
if (parmval == error_mark_node)
return error_mark_node;
- result = tree_cons (NULL_TREE, parmval, result);
+ result = expr_tree_cons (NULL_TREE, parmval, result);
}
else
{
if (TREE_CODE (TREE_TYPE (val)) == REFERENCE_TYPE)
val = convert_from_reference (val);
- if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
- && (TYPE_PRECISION (TREE_TYPE (val))
- < TYPE_PRECISION (double_type_node)))
- /* Convert `float' to `double'. */
- result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
- else if (TYPE_LANG_SPECIFIC (TREE_TYPE (val))
- && ! TYPE_HAS_TRIVIAL_INIT_REF (TREE_TYPE (val)))
- {
- cp_warning ("cannot pass objects of type `%T' through `...'",
- TREE_TYPE (val));
- result = tree_cons (NULL_TREE, val, result);
- }
- else
- /* Convert `short' and `char' to full-size `int'. */
- result = tree_cons (NULL_TREE, default_conversion (val), result);
+ result = expr_tree_cons (NULL_TREE,
+ convert_arg_to_ellipsis (val),
+ result);
}
- if (flag_gc
- /* There are certain functions for which we don't need
- to protect our arguments. GC_PROTECT_FNDECL is one. */
- && fndecl != gc_protect_fndecl
- && type_needs_gc_entry (TREE_TYPE (TREE_VALUE (result)))
- && ! value_safe_from_gc (NULL_TREE, TREE_VALUE (result)))
- /* This will build a temporary variable whose cleanup is
- to clear the obstack entry. */
- TREE_VALUE (result) = protect_value_from_gc (NULL_TREE,
- TREE_VALUE (result));
-
if (typetail)
typetail = TREE_CHAIN (typetail);
}
@@ -2778,42 +3071,13 @@ convert_arguments (return_loc, typelist, values, fndecl, flags)
for (; typetail != void_list_node; ++i)
{
tree type = TREE_VALUE (typetail);
- tree val = break_out_target_exprs (TREE_PURPOSE (typetail));
- tree parmval;
-
- if (val == NULL_TREE)
- parmval = error_mark_node;
- else if (TREE_CODE (val) == CONSTRUCTOR)
- {
- parmval = digest_init (type, val, (tree *)0);
- parmval = convert_for_initialization (return_loc, type, parmval, flags,
- "default constructor", fndecl, i);
- }
- else
- {
- /* This could get clobbered by the following call. */
- if (TREE_HAS_CONSTRUCTOR (val))
- val = copy_node (val);
-
- parmval = convert_for_initialization (return_loc, type, val, flags,
- "default argument", fndecl, i);
-#ifdef PROMOTE_PROTOTYPES
- if ((TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE)
- && (TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)))
- parmval = default_conversion (parmval);
-#endif
- }
+ tree val = TREE_PURPOSE (typetail);
+ tree parmval = convert_default_arg (type, val);
if (parmval == error_mark_node)
return error_mark_node;
- if (flag_gc
- && type_needs_gc_entry (TREE_TYPE (parmval))
- && ! value_safe_from_gc (NULL_TREE, parmval))
- parmval = protect_value_from_gc (NULL_TREE, parmval);
-
- result = tree_cons (0, parmval, result);
+ result = expr_tree_cons (0, parmval, result);
typetail = TREE_CHAIN (typetail);
/* ends with `...'. */
if (typetail == NULL_TREE)
@@ -2846,14 +3110,10 @@ build_x_binary_op (code, arg1, arg2)
enum tree_code code;
tree arg1, arg2;
{
- tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY,
- arg1, arg2, NULL_TREE);
- if (rval)
- return build_opfncall (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
- if (code == MEMBER_REF)
- return build_m_component_ref (build_indirect_ref (arg1, NULL_PTR),
- arg2);
- return build_binary_op (code, arg1, arg2, 1);
+ if (processing_template_decl)
+ return build_min_nt (code, arg1, arg2);
+
+ return build_new_op (code, LOOKUP_NORMAL, arg1, arg2, NULL_TREE);
}
tree
@@ -2869,7 +3129,6 @@ build_binary_op (code, arg1, arg2, convert_p)
if (convert_p)
{
- tree args_save [2];
tree type0, type1;
args[0] = decay_conversion (args[0]);
args[1] = decay_conversion (args[1]);
@@ -2893,15 +3152,7 @@ build_binary_op (code, arg1, arg2, convert_p)
}
if (IS_AGGR_TYPE (type0) || IS_AGGR_TYPE (type1))
- {
- /* Try to convert this to something reasonable. */
- if (! build_default_binary_type_conversion(code, &args[0], &args[1]))
- {
- cp_error ("no match for `%O(%#T, %#T)'", code,
- TREE_TYPE (arg1), TREE_TYPE (arg2));
- return error_mark_node;
- }
- }
+ my_friendly_abort (754867);
}
return build_binary_op_nodefault (code, args[0], args[1], code);
}
@@ -3028,7 +3279,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
We must subtract them as integers, then divide by object size. */
if (code0 == POINTER_TYPE && code1 == POINTER_TYPE
&& comp_target_types (type0, type1, 1))
- return pointer_diff (op0, op1);
+ return pointer_diff (op0, op1, common_type (type0, type1));
/* Handle pointer minus int. Just like pointer plus int. */
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
return pointer_int_sum (MINUS_EXPR, op0, op1);
@@ -3045,8 +3296,10 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
case FLOOR_DIV_EXPR:
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+ || code0 == COMPLEX_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+ || code1 == COMPLEX_TYPE))
{
if (TREE_CODE (op1) == INTEGER_CST && integer_zerop (op1))
cp_warning ("division by zero in `%E / 0'", op0);
@@ -3083,7 +3336,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
in the short type, making the entire operation go away. */
if (TREE_CODE (op0) == INTEGER_CST
&& TREE_CODE (op1) == NOP_EXPR
- && TYPE_PRECISION (type1) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0)))
+ && (TYPE_PRECISION (type1)
+ > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op1, 0))))
&& TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op1, 0))))
{
final_type = result_type;
@@ -3092,7 +3346,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
}
if (TREE_CODE (op1) == INTEGER_CST
&& TREE_CODE (op0) == NOP_EXPR
- && TYPE_PRECISION (type0) > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0)))
+ && (TYPE_PRECISION (type0)
+ > TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (op0, 0))))
&& TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (op0, 0))))
{
final_type = result_type;
@@ -3104,9 +3359,9 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
case TRUNC_MOD_EXPR:
case FLOOR_MOD_EXPR:
if (code1 == INTEGER_TYPE && integer_zerop (op1))
- cp_warning ("division by zero in `%E % 0'", op0);
+ cp_warning ("division by zero in `%E %% 0'", op0);
else if (code1 == REAL_TYPE && real_zerop (op1))
- cp_warning ("division by zero in `%E % 0.'", op0);
+ cp_warning ("division by zero in `%E %% 0.'", op0);
if (code0 == INTEGER_TYPE && code1 == INTEGER_TYPE)
{
@@ -3155,7 +3410,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
/* Convert the shift-count to an integer, regardless of
size of value being shifted. */
if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
- op1 = convert (integer_type_node, op1);
+ op1 = cp_convert (integer_type_node, op1);
/* Avoid converting op1 to result_type later. */
converted = 1;
}
@@ -3177,7 +3432,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
/* Convert the shift-count to an integer, regardless of
size of value being shifted. */
if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
- op1 = convert (integer_type_node, op1);
+ op1 = cp_convert (integer_type_node, op1);
/* Avoid converting op1 to result_type later. */
converted = 1;
}
@@ -3202,15 +3457,17 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
/* Convert the shift-count to an integer, regardless of
size of value being shifted. */
if (TYPE_MAIN_VARIANT (TREE_TYPE (op1)) != integer_type_node)
- op1 = convert (integer_type_node, op1);
+ op1 = cp_convert (integer_type_node, op1);
}
break;
case EQ_EXPR:
case NE_EXPR:
build_type = boolean_type_node;
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE
+ || code0 == COMPLEX_TYPE)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+ || code1 == COMPLEX_TYPE))
short_compare = 1;
else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE)
{
@@ -3259,14 +3516,14 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
else if (TYPE_PTRMEMFUNC_P (type0) && TREE_CODE (op1) == INTEGER_CST
&& integer_zerop (op1))
{
- op0 = build_component_ref (op0, index_identifier, 0, 0);
+ op0 = build_component_ref (op0, index_identifier, NULL_TREE, 0);
op1 = integer_zero_node;
result_type = TREE_TYPE (op0);
}
else if (TYPE_PTRMEMFUNC_P (type1) && TREE_CODE (op0) == INTEGER_CST
&& integer_zerop (op0))
{
- op0 = build_component_ref (op1, index_identifier, 0, 0);
+ op0 = build_component_ref (op1, index_identifier, NULL_TREE, 0);
op1 = integer_zero_node;
result_type = TREE_TYPE (op0);
}
@@ -3280,18 +3537,23 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
&& ((op1.index != -1 && op0.delta2 == op1.delta2)
|| op0.pfn == op1.pfn)) */
- tree index0 = build_component_ref (op0, index_identifier, 0, 0);
- tree index1 = save_expr (build_component_ref (op1, index_identifier, 0, 0));
+ tree index0 = build_component_ref (op0, index_identifier,
+ NULL_TREE, 0);
+ tree index1 = save_expr (build_component_ref (op1, index_identifier,
+ NULL_TREE, 0));
tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
tree pfn1 = PFN_FROM_PTRMEMFUNC (op1);
tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
tree delta21 = DELTA2_FROM_PTRMEMFUNC (op1);
tree e1, e2, e3;
tree integer_neg_one_node
- = build_binary_op (MINUS_EXPR, integer_zero_node, integer_one_node, 1);
+ = build_binary_op (MINUS_EXPR, integer_zero_node,
+ integer_one_node, 1);
e1 = build_binary_op (EQ_EXPR, index0, index1, 1);
e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node, 1);
- e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2, build_binary_op (EQ_EXPR, delta20, delta21, 1), 1);
+ e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
+ build_binary_op (EQ_EXPR, delta20, delta21, 1),
+ 1);
e3 = build_binary_op (EQ_EXPR, pfn0, pfn1, 1);
e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3, 1);
e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2, 1);
@@ -3302,7 +3564,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
else if (TYPE_PTRMEMFUNC_P (type0)
&& TYPE_PTRMEMFUNC_FN_TYPE (type0) == type1)
{
- tree index0 = build_component_ref (op0, index_identifier, 0, 0);
+ tree index0 = build_component_ref (op0, index_identifier,
+ NULL_TREE, 0);
tree index1;
tree pfn0 = PFN_FROM_PTRMEMFUNC (op0);
tree delta20 = DELTA2_FROM_PTRMEMFUNC (op0);
@@ -3313,25 +3576,32 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
if (TREE_CODE (TREE_OPERAND (op1, 0)) == FUNCTION_DECL
&& DECL_VINDEX (TREE_OPERAND (op1, 0)))
{
- /* Map everything down one to make room for the null pointer to member. */
+ /* Map everything down one to make room for
+ the null pointer to member. */
index1 = size_binop (PLUS_EXPR,
DECL_VINDEX (TREE_OPERAND (op1, 0)),
integer_one_node);
op1 = integer_zero_node;
- delta21 = CLASSTYPE_VFIELD (TYPE_METHOD_BASETYPE (TREE_TYPE (type1)));
+ delta21 = CLASSTYPE_VFIELD (TYPE_METHOD_BASETYPE
+ (TREE_TYPE (type1)));
delta21 = DECL_FIELD_BITPOS (delta21);
- delta21 = size_binop (FLOOR_DIV_EXPR, delta21, size_int (BITS_PER_UNIT));
+ delta21 = size_binop (FLOOR_DIV_EXPR, delta21,
+ size_int (BITS_PER_UNIT));
+ delta21 = convert (sizetype, delta21);
}
else
index1 = integer_neg_one_node;
{
- tree nop1 = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type0), op1);
+ tree nop1 = build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type0),
+ op1);
TREE_CONSTANT (nop1) = TREE_CONSTANT (op1);
op1 = nop1;
}
e1 = build_binary_op (EQ_EXPR, index0, index1, 1);
e2 = build_binary_op (NE_EXPR, index1, integer_neg_one_node, 1);
- e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2, build_binary_op (EQ_EXPR, delta20, delta21, 1), 1);
+ e2 = build_binary_op (TRUTH_ANDIF_EXPR, e2,
+ build_binary_op (EQ_EXPR, delta20, delta21, 1),
+ 1);
e3 = build_binary_op (EQ_EXPR, pfn0, op1, 1);
e2 = build_binary_op (TRUTH_ORIF_EXPR, e2, e3, 1);
e2 = build_binary_op (TRUTH_ANDIF_EXPR, e1, e2, 1);
@@ -3392,25 +3662,25 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
else if (code0 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
result_type = type0;
- if (pedantic)
- pedwarn ("ANSI C++ forbids comparison between pointer and integer");
- else if (! flag_traditional)
- warning ("comparison between pointer and integer");
+ pedwarn ("ANSI C++ forbids comparison between pointer and integer");
}
else if (code0 == INTEGER_TYPE && code1 == POINTER_TYPE)
{
result_type = type1;
- if (pedantic)
- pedwarn ("ANSI C++ forbids comparison between pointer and integer");
- else if (! flag_traditional)
- warning ("comparison between pointer and integer");
+ pedwarn ("ANSI C++ forbids comparison between pointer and integer");
}
break;
+
+ default:
+ break;
}
- if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
- && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+ if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
+ &&
+ (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
{
+ int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
+
if (shorten || common || short_compare)
result_type = common_type (type0, type1);
@@ -3425,7 +3695,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
Eg, (short)-1 | (unsigned short)-1 is (int)-1
but calculated in (unsigned short) it would be (unsigned short)-1. */
- if (shorten)
+ if (shorten && none_complex)
{
int unsigned0, unsigned1;
tree arg0 = get_narrower (op0, &unsigned0);
@@ -3466,7 +3736,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
&& (unsigned0 || !uns))
result_type
= signed_or_unsigned_type (unsigned0,
- common_type (TREE_TYPE (arg0), TREE_TYPE (arg1)));
+ common_type (TREE_TYPE (arg0),
+ TREE_TYPE (arg1)));
else if (TREE_CODE (arg0) == INTEGER_CST
&& (unsigned1 || !uns)
&& (TYPE_PRECISION (TREE_TYPE (arg1))
@@ -3511,7 +3782,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
it never happens because available widths are 2**N. */
&& (!TREE_UNSIGNED (final_type)
|| unsigned_arg
- || ((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0))
+ || (((unsigned) 2 * TYPE_PRECISION (TREE_TYPE (arg0)))
<= TYPE_PRECISION (result_type))))
{
/* Do an unsigned shift if the operand was zero-extended. */
@@ -3520,7 +3791,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
TREE_TYPE (arg0));
/* Convert value-to-be-shifted to that type. */
if (TREE_TYPE (op0) != result_type)
- op0 = convert (result_type, op0);
+ op0 = cp_convert (result_type, op0);
converted = 1;
}
}
@@ -3539,13 +3810,13 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
tree val
= shorten_compare (&xop0, &xop1, &xresult_type, &xresultcode);
if (val != 0)
- return convert (boolean_type_node, val);
+ return cp_convert (boolean_type_node, val);
op0 = xop0, op1 = xop1;
converted = 1;
resultcode = xresultcode;
}
- if (short_compare && extra_warnings)
+ if (short_compare && warn_sign_compare)
{
int op0_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op0));
int op1_signed = ! TREE_UNSIGNED (TREE_TYPE (orig_op1));
@@ -3554,6 +3825,17 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
tree primop0 = get_narrower (op0, &unsignedp0);
tree primop1 = get_narrower (op1, &unsignedp1);
+ /* Check for comparison of different enum types. */
+ if (flag_int_enum_equivalence == 0
+ && TREE_CODE (TREE_TYPE (orig_op0)) == ENUMERAL_TYPE
+ && TREE_CODE (TREE_TYPE (orig_op1)) == ENUMERAL_TYPE
+ && TYPE_MAIN_VARIANT (TREE_TYPE (orig_op0))
+ != TYPE_MAIN_VARIANT (TREE_TYPE (orig_op1)))
+ {
+ cp_warning ("comparison between `%#T' and `%#T'",
+ TREE_TYPE (orig_op0), TREE_TYPE (orig_op1));
+ }
+
/* Give warnings for comparisons between signed and unsigned
quantities that may fail. */
/* Do the checking based on the original operand trees, so that
@@ -3580,9 +3862,11 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
not use the most significant bit of result_type. */
else if ((resultcode == EQ_EXPR || resultcode == NE_EXPR)
&& ((op0_signed && TREE_CODE (orig_op1) == INTEGER_CST
- && int_fits_type_p (orig_op1, signed_type (result_type))
+ && int_fits_type_p (orig_op1,
+ signed_type (result_type)))
|| (op1_signed && TREE_CODE (orig_op0) == INTEGER_CST
- && int_fits_type_p (orig_op0, signed_type (result_type))))))
+ && int_fits_type_p (orig_op0,
+ signed_type (result_type)))))
/* OK */;
else
warning ("comparison between signed and unsigned");
@@ -3595,8 +3879,8 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
have all bits set that are set in the ~ operand when it is
extended. */
- if (TREE_CODE (primop0) == BIT_NOT_EXPR
- ^ TREE_CODE (primop1) == BIT_NOT_EXPR)
+ if ((TREE_CODE (primop0) == BIT_NOT_EXPR)
+ ^ (TREE_CODE (primop1) == BIT_NOT_EXPR))
{
if (TREE_CODE (primop0) == BIT_NOT_EXPR)
primop0 = get_narrower (TREE_OPERAND (op0, 0), &unsignedp0);
@@ -3659,9 +3943,9 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
if (! converted)
{
if (TREE_TYPE (op0) != result_type)
- op0 = convert (result_type, op0);
+ op0 = cp_convert (result_type, op0);
if (TREE_TYPE (op1) != result_type)
- op1 = convert (result_type, op1);
+ op1 = cp_convert (result_type, op1);
}
if (build_type == NULL_TREE)
@@ -3675,7 +3959,7 @@ build_binary_op_nodefault (code, orig_op0, orig_op1, error_code)
if (folded == result)
TREE_CONSTANT (folded) = TREE_CONSTANT (op0) & TREE_CONSTANT (op1);
if (final_type != 0)
- return convert (final_type, folded);
+ return cp_convert (final_type, folded);
return folded;
}
}
@@ -3697,6 +3981,9 @@ pointer_int_sum (resultcode, ptrop, intop)
register tree result_type = TREE_TYPE (ptrop);
+ if (!complete_type_or_else (result_type))
+ return error_mark_node;
+
if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
{
if (pedantic || warn_pointer_arith)
@@ -3717,12 +4004,12 @@ pointer_int_sum (resultcode, ptrop, intop)
}
else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
{
- if (pedantic)
+ if (pedantic || warn_pointer_arith)
pedwarn ("ANSI C++ forbids using pointer to a member in arithmetic");
size_exp = integer_one_node;
}
else
- size_exp = size_in_bytes (TREE_TYPE (result_type));
+ size_exp = size_in_bytes (complete_type (TREE_TYPE (result_type)));
/* Needed to make OOPS V2R3 work. */
intop = folded;
@@ -3748,19 +4035,21 @@ pointer_int_sum (resultcode, ptrop, intop)
intop = TREE_OPERAND (intop, 0);
}
- /* Convert the integer argument to a type the same size as a pointer
+ /* Convert the integer argument to a type the same size as sizetype
so the multiply won't overflow spuriously. */
- if (TYPE_PRECISION (TREE_TYPE (intop)) != POINTER_SIZE)
- intop = convert (type_for_size (POINTER_SIZE, 0), intop);
+ if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype))
+ intop = cp_convert (type_for_size (TYPE_PRECISION (sizetype), 0), intop);
/* Replace the integer argument with a suitable product by the object size.
Do this multiplication as signed, then convert to the appropriate
pointer type (actually unsigned integral). */
- intop = convert (result_type,
- build_binary_op (MULT_EXPR, intop,
- convert (TREE_TYPE (intop), size_exp), 1));
+ intop = cp_convert (result_type,
+ build_binary_op (MULT_EXPR, intop,
+ cp_convert (TREE_TYPE (intop),
+ size_exp),
+ 1));
/* Create the sum or difference. */
@@ -3776,14 +4065,18 @@ pointer_int_sum (resultcode, ptrop, intop)
The resulting tree has type int. */
static tree
-pointer_diff (op0, op1)
+pointer_diff (op0, op1, ptrtype)
register tree op0, op1;
+ register tree ptrtype;
{
register tree result, folded;
tree restype = ptrdiff_type_node;
- tree target_type = TREE_TYPE (TREE_TYPE (op0));
+ tree target_type = TREE_TYPE (ptrtype);
- if (pedantic)
+ if (!complete_type_or_else (target_type))
+ return error_mark_node;
+
+ if (pedantic || warn_pointer_arith)
{
if (TREE_CODE (target_type) == VOID_TYPE)
pedwarn ("ANSI C++ forbids using pointer of type `void *' in subtraction");
@@ -3798,8 +4091,8 @@ pointer_diff (op0, op1)
/* First do the subtraction as integers;
then drop through to build the divide operator. */
- op0 = build_binary_op (MINUS_EXPR,
- convert (restype, op0), convert (restype, op1), 1);
+ op0 = build_binary_op (MINUS_EXPR, cp_convert (restype, op0),
+ cp_convert (restype, op1), 1);
/* This generates an error if op1 is a pointer to an incomplete type. */
if (TYPE_SIZE (TREE_TYPE (TREE_TYPE (op1))) == 0)
@@ -3814,7 +4107,7 @@ pointer_diff (op0, op1)
/* Do the division. */
- result = build (EXACT_DIV_EXPR, restype, op0, convert (restype, op1));
+ result = build (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
folded = fold (result);
if (folded == result)
@@ -3845,9 +4138,6 @@ build_component_addr (arg, argtype, msg)
return error_mark_node;
}
- if (flag_gc)
- cp_warning ("address of `%T::%D' taken", basetype, field);
-
if (TREE_CODE (field) == FIELD_DECL
&& TYPE_USES_COMPLEX_INHERITANCE (basetype))
{
@@ -3867,8 +4157,9 @@ build_component_addr (arg, argtype, msg)
tree offset = size_binop (EASY_DIV_EXPR, DECL_FIELD_BITPOS (field),
size_int (BITS_PER_UNIT));
int flag = TREE_CONSTANT (rval);
+ offset = convert (sizetype, offset);
rval = fold (build (PLUS_EXPR, argtype,
- rval, convert (argtype, offset)));
+ rval, cp_convert (argtype, offset)));
TREE_CONSTANT (rval) = flag;
}
return rval;
@@ -3883,21 +4174,33 @@ build_x_unary_op (code, xarg)
enum tree_code code;
tree xarg;
{
+ if (processing_template_decl)
+ return build_min_nt (code, xarg, NULL_TREE);
+
/* & rec, on incomplete RECORD_TYPEs is the simple opr &, not an
- error message. */
+ error message. */
if (code == ADDR_EXPR
+ && TREE_CODE (xarg) != TEMPLATE_ID_EXPR
&& ((IS_AGGR_TYPE_CODE (TREE_CODE (TREE_TYPE (xarg)))
&& TYPE_SIZE (TREE_TYPE (xarg)) == NULL_TREE)
|| (TREE_CODE (xarg) == OFFSET_REF)))
/* don't look for a function */;
else
{
- tree rval = build_opfncall (code, LOOKUP_SPECULATIVELY, xarg,
- NULL_TREE, NULL_TREE);
- if (rval)
- return build_opfncall (code, LOOKUP_NORMAL, xarg,
- NULL_TREE, NULL_TREE);
+ tree rval;
+
+ rval = build_new_op (code, LOOKUP_NORMAL, xarg,
+ NULL_TREE, NULL_TREE);
+ if (rval || code != ADDR_EXPR)
+ return rval;
}
+
+ if (code == ADDR_EXPR)
+ {
+ if (TREE_CODE (xarg) == TARGET_EXPR)
+ warning ("taking address of temporary");
+ }
+
return build_unary_op (code, xarg, 0);
}
@@ -3907,7 +4210,10 @@ tree
condition_conversion (expr)
tree expr;
{
- tree t = convert (boolean_type_node, expr);
+ tree t;
+ if (processing_template_decl)
+ return expr;
+ t = cp_convert (boolean_type_node, expr);
t = fold (build1 (CLEANUP_POINT_EXPR, boolean_type_node, t));
return t;
}
@@ -3920,6 +4226,7 @@ condition_conversion (expr)
NOCONVERT nonzero suppresses the default promotions
(such as from short to int). */
+
tree
build_unary_op (code, xarg, noconvert)
enum tree_code code;
@@ -3949,6 +4256,7 @@ build_unary_op (code, xarg, noconvert)
if (!noconvert)
arg = default_conversion (arg);
arg = build1 (NON_LVALUE_EXPR, TREE_TYPE (arg), arg);
+ TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
}
break;
@@ -3960,7 +4268,14 @@ build_unary_op (code, xarg, noconvert)
break;
case BIT_NOT_EXPR:
- if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM, arg, 1)))
+ if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+ {
+ code = CONJ_EXPR;
+ if (!noconvert)
+ arg = default_conversion (arg);
+ }
+ else if (!(arg = build_expr_type_conversion (WANT_INT | WANT_ENUM,
+ arg, 1)))
errstring = "wrong type argument to bit-complement";
else if (!noconvert)
arg = default_conversion (arg);
@@ -3973,8 +4288,16 @@ build_unary_op (code, xarg, noconvert)
arg = default_conversion (arg);
break;
+ case CONJ_EXPR:
+ /* Conjugating a real value is a no-op, but allow it anyway. */
+ if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_ENUM, arg, 1)))
+ errstring = "wrong type argument to conjugation";
+ else if (!noconvert)
+ arg = default_conversion (arg);
+ break;
+
case TRUTH_NOT_EXPR:
- arg = convert (boolean_type_node, arg);
+ arg = cp_convert (boolean_type_node, arg);
val = invert_truthvalue (arg);
if (arg != error_mark_node)
return val;
@@ -3984,6 +4307,22 @@ build_unary_op (code, xarg, noconvert)
case NOP_EXPR:
break;
+ case REALPART_EXPR:
+ if (TREE_CODE (arg) == COMPLEX_CST)
+ return TREE_REALPART (arg);
+ else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+ return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+ else
+ return arg;
+
+ case IMAGPART_EXPR:
+ if (TREE_CODE (arg) == COMPLEX_CST)
+ return TREE_IMAGPART (arg);
+ else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+ return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
+ else
+ return cp_convert (TREE_TYPE (arg), integer_zero_node);
+
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
case PREDECREMENT_EXPR:
@@ -3995,6 +4334,19 @@ build_unary_op (code, xarg, noconvert)
if (val != 0)
return val;
+ /* Increment or decrement the real part of the value,
+ and don't change the imaginary part. */
+ if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
+ {
+ tree real, imag;
+
+ arg = stabilize_reference (arg);
+ real = build_unary_op (REALPART_EXPR, arg, 1);
+ imag = build_unary_op (IMAGPART_EXPR, arg, 1);
+ return build (COMPLEX_EXPR, TREE_TYPE (arg),
+ build_unary_op (code, real, 1), imag);
+ }
+
/* Report invalid types. */
if (!(arg = build_expr_type_conversion (WANT_ARITH | WANT_POINTER,
@@ -4038,13 +4390,14 @@ build_unary_op (code, xarg, noconvert)
if (TREE_CODE (argtype) == POINTER_TYPE)
{
enum tree_code tmp = TREE_CODE (TREE_TYPE (argtype));
- if (TYPE_SIZE (TREE_TYPE (argtype)) == 0)
+ if (TYPE_SIZE (complete_type (TREE_TYPE (argtype))) == 0)
cp_error ("cannot %s a pointer to incomplete type `%T'",
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
? "increment" : "decrement"), TREE_TYPE (argtype));
- else if (tmp == FUNCTION_TYPE || tmp == METHOD_TYPE
- || tmp == VOID_TYPE || tmp == OFFSET_TYPE)
+ else if ((pedantic || warn_pointer_arith)
+ && (tmp == FUNCTION_TYPE || tmp == METHOD_TYPE
+ || tmp == VOID_TYPE || tmp == OFFSET_TYPE))
cp_pedwarn ("ANSI C++ forbids %sing a pointer of type `%T'",
((code == PREINCREMENT_EXPR
|| code == POSTINCREMENT_EXPR)
@@ -4054,7 +4407,7 @@ build_unary_op (code, xarg, noconvert)
else
inc = integer_one_node;
- inc = convert (argtype, inc);
+ inc = cp_convert (argtype, inc);
/* Handle incrementing a cast-expression. */
@@ -4068,7 +4421,7 @@ build_unary_op (code, xarg, noconvert)
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
{
- tree incremented, modify, value;
+ tree incremented, modify, value, compound;
if (! lvalue_p (arg) && pedantic)
pedwarn ("cast to non-reference type used as lvalue");
arg = stabilize_reference (arg);
@@ -4081,9 +4434,17 @@ build_unary_op (code, xarg, noconvert)
? PLUS_EXPR : MINUS_EXPR),
argtype, value, inc);
TREE_SIDE_EFFECTS (incremented) = 1;
+
modify = build_modify_expr (arg, NOP_EXPR, incremented);
- return build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+ compound = build (COMPOUND_EXPR, TREE_TYPE (arg), modify, value);
+
+ /* Eliminate warning about unused result of + or -. */
+ TREE_NO_UNUSED_WARNING (compound) = 1;
+ return compound;
}
+
+ default:
+ break;
}
/* Complain about anything else that is not a true lvalue. */
@@ -4124,7 +4485,7 @@ build_unary_op (code, xarg, noconvert)
val = build (code, TREE_TYPE (arg), arg, inc);
TREE_SIDE_EFFECTS (val) = 1;
- return convert (result_type, val);
+ return cp_convert (result_type, val);
}
case ADDR_EXPR:
@@ -4134,38 +4495,30 @@ build_unary_op (code, xarg, noconvert)
argtype = TREE_TYPE (arg);
if (TREE_CODE (argtype) == REFERENCE_TYPE)
{
- arg = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
- TREE_REFERENCE_EXPR (arg) = 1;
+ arg = build1
+ (CONVERT_EXPR,
+ build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
+ TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
return arg;
}
- else if (pedantic
- && TREE_CODE (arg) == FUNCTION_DECL
- && DECL_NAME (arg)
- && DECL_CONTEXT (arg) == NULL_TREE
- && IDENTIFIER_LENGTH (DECL_NAME (arg)) == 4
- && IDENTIFIER_POINTER (DECL_NAME (arg))[0] == 'm'
- && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (arg)), "main"))
+ else if (pedantic && DECL_MAIN_P (arg))
/* ARM $3.4 */
pedwarn ("taking address of function `main'");
/* Let &* cancel out to simplify resulting code. */
if (TREE_CODE (arg) == INDIRECT_REF)
{
- /* We don't need to have `current_class_decl' wrapped in a
+ /* We don't need to have `current_class_ptr' wrapped in a
NON_LVALUE_EXPR node. */
- if (arg == C_C_D)
- return current_class_decl;
+ if (arg == current_class_ref)
+ return current_class_ptr;
- /* Keep `default_conversion' from converting if
- ARG is of REFERENCE_TYPE. */
arg = TREE_OPERAND (arg, 0);
if (TREE_CODE (TREE_TYPE (arg)) == REFERENCE_TYPE)
{
- if (TREE_CODE (arg) == VAR_DECL && DECL_INITIAL (arg)
- && !TREE_SIDE_EFFECTS (DECL_INITIAL (arg)))
- arg = DECL_INITIAL (arg);
- arg = build1 (CONVERT_EXPR, build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
- TREE_REFERENCE_EXPR (arg) = 1;
+ arg = build1
+ (CONVERT_EXPR,
+ build_pointer_type (TREE_TYPE (TREE_TYPE (arg))), arg);
TREE_CONSTANT (arg) = TREE_CONSTANT (TREE_OPERAND (arg, 0));
}
else if (lvalue_p (arg))
@@ -4196,20 +4549,46 @@ build_unary_op (code, xarg, noconvert)
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
- if (TREE_CODE (arg) == TREE_LIST)
+ if (TREE_CODE (arg) == OVERLOAD
+ || (TREE_CODE (arg) == OFFSET_REF
+ && TREE_CODE (TREE_OPERAND (arg, 1)) == TEMPLATE_ID_EXPR))
+ return build1 (ADDR_EXPR, unknown_type_node, arg);
+ else if (TREE_CODE (arg) == TREE_LIST)
{
- if (TREE_CODE (TREE_VALUE (arg)) == FUNCTION_DECL
- && DECL_CHAIN (TREE_VALUE (arg)) == NULL_TREE)
+ if (TREE_CODE (TREE_VALUE (arg)) == FUNCTION_DECL)
/* Unique overloaded non-member function. */
return build_unary_op (ADDR_EXPR, TREE_VALUE (arg), 0);
if (TREE_CHAIN (arg) == NULL_TREE
&& TREE_CODE (TREE_VALUE (arg)) == TREE_LIST
- && DECL_CHAIN (TREE_VALUE (TREE_VALUE (arg))) == NULL_TREE)
+ && TREE_CODE (TREE_VALUE (TREE_VALUE (arg))) != OVERLOAD)
/* Unique overloaded member function. */
return build_unary_op (ADDR_EXPR, TREE_VALUE (TREE_VALUE (arg)),
0);
return build1 (ADDR_EXPR, unknown_type_node, arg);
}
+ else if (TREE_CODE (arg) == TEMPLATE_ID_EXPR)
+ {
+ tree targs;
+ tree fn;
+
+ /* We don't require a match here; it's possible that the
+ context (like a cast to a particular type) will resolve
+ the particular choice of template. */
+ fn = determine_specialization (arg,
+ NULL_TREE,
+ &targs,
+ 0,
+ 0);
+
+ if (fn)
+ {
+ fn = instantiate_template (fn, targs);
+ mark_addressable (fn);
+ return build_unary_op (ADDR_EXPR, fn, 0);
+ }
+
+ return build1 (ADDR_EXPR, unknown_type_node, arg);
+ }
/* Handle complex lvalues (when permitted)
by reduction to simpler cases. */
@@ -4228,11 +4607,16 @@ build_unary_op (code, xarg, noconvert)
case FIX_CEIL_EXPR:
if (! lvalue_p (arg) && pedantic)
pedwarn ("taking the address of a cast to non-reference type");
+ break;
+
+ default:
+ break;
}
/* Allow the address of a constructor if all the elements
are constant. */
- if (TREE_CODE (arg) == CONSTRUCTOR && TREE_CONSTANT (arg))
+ if (TREE_CODE (arg) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (arg)
+ && TREE_CONSTANT (arg))
;
/* Anything not already handled and not a true memory reference
is an error. */
@@ -4262,8 +4646,9 @@ build_unary_op (code, xarg, noconvert)
tree addr;
if (TREE_CODE (arg) == COMPONENT_REF)
- addr = build_component_addr (arg, argtype,
- "attempt to take address of bit-field structure member `%s'");
+ addr = build_component_addr
+ (arg, argtype,
+ "attempt to take address of bit-field structure member `%s'");
else
addr = build1 (code, argtype, arg);
@@ -4271,8 +4656,19 @@ build_unary_op (code, xarg, noconvert)
function counts as a constant */
if (staticp (arg))
TREE_CONSTANT (addr) = 1;
+
+ if (TREE_CODE (argtype) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (argtype)) == METHOD_TYPE)
+ {
+ build_ptrmemfunc_type (argtype);
+ addr = build_ptrmemfunc (argtype, addr, 0);
+ }
+
return addr;
}
+
+ default:
+ break;
}
if (!errstring)
@@ -4286,6 +4682,7 @@ build_unary_op (code, xarg, noconvert)
return error_mark_node;
}
+#if 0
/* If CONVERSIONS is a conversion expression or a nested sequence of such,
convert ARG with the same conversions in the same order
and return the result. */
@@ -4304,14 +4701,15 @@ convert_sequence (conversions, arg)
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
case FIX_CEIL_EXPR:
- return convert (TREE_TYPE (conversions),
- convert_sequence (TREE_OPERAND (conversions, 0),
- arg));
+ return cp_convert (TREE_TYPE (conversions),
+ convert_sequence (TREE_OPERAND (conversions, 0),
+ arg));
default:
return arg;
}
}
+#endif
/* Apply unary lvalue-demanding operator CODE to the expression ARG
for certain kinds of expressions which are not really lvalues
@@ -4333,7 +4731,8 @@ unary_complex_lvalue (code, arg)
}
/* Handle (a ? b : c) used as an "lvalue". */
- if (TREE_CODE (arg) == COND_EXPR)
+ if (TREE_CODE (arg) == COND_EXPR
+ || TREE_CODE (arg) == MIN_EXPR || TREE_CODE (arg) == MAX_EXPR)
return rationalize_conditional_expr (code, arg);
if (TREE_CODE (arg) == MODIFY_EXPR
@@ -4351,15 +4750,9 @@ unary_complex_lvalue (code, arg)
|| TREE_CODE (arg) == INIT_EXPR)
{
tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
- return build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
- }
-
- if (TREE_CODE (arg) == WITH_CLEANUP_EXPR)
- {
- tree real_result = build_unary_op (code, TREE_OPERAND (arg, 0), 0);
- real_result = build (WITH_CLEANUP_EXPR, TREE_TYPE (real_result),
- real_result, 0, TREE_OPERAND (arg, 2));
- return real_result;
+ arg = build (COMPOUND_EXPR, TREE_TYPE (real_result), arg, real_result);
+ TREE_NO_UNUSED_WARNING (arg) = 1;
+ return arg;
}
if (TREE_CODE (TREE_TYPE (arg)) == FUNCTION_TYPE
@@ -4370,7 +4763,6 @@ unary_complex_lvalue (code, arg)
is really the representation of a pointer to it.
Here give the representation its true type. */
tree t;
- tree offset;
my_friendly_assert (TREE_CODE (arg) != SCOPE_REF, 313);
@@ -4379,15 +4771,24 @@ unary_complex_lvalue (code, arg)
t = TREE_OPERAND (arg, 1);
- if (TREE_CODE (t) == FUNCTION_DECL) /* Check all this code for right semantics. */
- return build_unary_op (ADDR_EXPR, t, 0);
+ /* Check all this code for right semantics. */
+ if (TREE_CODE (t) == FUNCTION_DECL)
+ {
+ if (DECL_DESTRUCTOR_P (t))
+ cp_error ("taking address of destructor");
+ return build_unary_op (ADDR_EXPR, t, 0);
+ }
if (TREE_CODE (t) == VAR_DECL)
return build_unary_op (ADDR_EXPR, t, 0);
else
{
+ tree type;
+ tree offset;
+
if (TREE_OPERAND (arg, 0)
&& (TREE_CODE (TREE_OPERAND (arg, 0)) != NOP_EXPR
- || TREE_OPERAND (TREE_OPERAND (arg, 0), 0) != error_mark_node))
+ || (TREE_OPERAND (TREE_OPERAND (arg, 0), 0)
+ != error_mark_node)))
if (TREE_CODE (t) != FIELD_DECL)
{
/* Don't know if this should return address to just
@@ -4396,38 +4797,25 @@ unary_complex_lvalue (code, arg)
return error_mark_node;
}
- offset = get_delta_difference (DECL_FIELD_CONTEXT (t),
- TREE_TYPE (TREE_OPERAND (arg, 0)),
- 0);
- offset = size_binop (PLUS_EXPR, offset,
- size_binop (EASY_DIV_EXPR,
- DECL_FIELD_BITPOS (t),
- size_int (BITS_PER_UNIT)));
- return convert (build_pointer_type (TREE_TYPE (arg)), offset);
- }
- }
+ /* Add in the offset to the field. */
+ offset = convert (sizetype,
+ size_binop (EASY_DIV_EXPR,
+ DECL_FIELD_BITPOS (t),
+ size_int (BITS_PER_UNIT)));
- if (TREE_CODE (arg) == OFFSET_REF)
- {
- tree left = TREE_OPERAND (arg, 0), left_addr;
- tree right_addr = build_unary_op (ADDR_EXPR, TREE_OPERAND (arg, 1), 0);
+ /* We offset all pointer to data members by 1 so that we can
+ distinguish between a null pointer to data member and the first
+ data member of a structure. */
+ offset = size_binop (PLUS_EXPR, offset, size_int (1));
- if (left == 0)
- if (current_class_decl)
- left_addr = current_class_decl;
- else
- {
- error ("no `this' for pointer to member");
- return error_mark_node;
- }
- else
- left_addr = build_unary_op (ADDR_EXPR, left, 0);
+ type = build_offset_type (DECL_FIELD_CONTEXT (t), TREE_TYPE (t));
+ type = build_pointer_type (type);
- return build (PLUS_EXPR, build_pointer_type (TREE_TYPE (arg)),
- build1 (NOP_EXPR, integer_type_node, left_addr),
- build1 (NOP_EXPR, integer_type_node, right_addr));
+ return cp_convert (type, offset);
+ }
}
+
/* We permit compiler to make function calls returning
objects of aggregate type look like lvalues. */
{
@@ -4441,24 +4829,13 @@ unary_complex_lvalue (code, arg)
if (TREE_CODE (arg) == SAVE_EXPR)
targ = arg;
else
- targ = build_cplus_new (TREE_TYPE (arg), arg, 1);
+ targ = build_cplus_new (TREE_TYPE (arg), arg);
return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (arg)), targ);
}
if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == INDIRECT_REF)
return build (SAVE_EXPR, build_pointer_type (TREE_TYPE (arg)),
TREE_OPERAND (targ, 0), current_function_decl, NULL);
-
- /* We shouldn't wrap WITH_CLEANUP_EXPRs inside of SAVE_EXPRs, but in case
- we do, here's how to handle it. */
- if (TREE_CODE (arg) == SAVE_EXPR && TREE_CODE (targ) == WITH_CLEANUP_EXPR)
- {
-#if 0
- /* Not really a bug, but something to turn on when testing. */
- compiler_error ("WITH_CLEANUP_EXPR wrapped in SAVE_EXPR");
-#endif
- return unary_complex_lvalue (ADDR_EXPR, targ);
- }
}
/* Don't let anything else be handled specially. */
@@ -4469,7 +4846,7 @@ unary_complex_lvalue (code, arg)
address of it; it should not be allocated in a register.
Value is 1 if successful.
- C++: we do not allow `current_class_decl' to be addressable. */
+ C++: we do not allow `current_class_ptr' to be addressable. */
int
mark_addressable (exp)
@@ -4486,22 +4863,24 @@ mark_addressable (exp)
case ADDR_EXPR:
case COMPONENT_REF:
case ARRAY_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
x = TREE_OPERAND (x, 0);
break;
case PARM_DECL:
- if (x == current_class_decl)
+ if (x == current_class_ptr)
{
- error ("address of `this' not available");
+ if (! flag_this_is_variable)
+ error ("address of `this' not available");
TREE_ADDRESSABLE (x) = 1; /* so compiler doesn't die later */
put_var_into_stack (x);
return 1;
}
case VAR_DECL:
- if (TREE_STATIC (x)
- && TREE_READONLY (x)
+ if (TREE_STATIC (x) && TREE_READONLY (x)
&& DECL_RTL (x) != 0
- && ! decl_in_memory_p (x))
+ && ! DECL_IN_MEMORY_P (x))
{
/* We thought this would make a good constant variable,
but we were wrong. */
@@ -4510,7 +4889,8 @@ mark_addressable (exp)
TREE_ASM_WRITTEN (x) = 0;
DECL_RTL (x) = 0;
- rest_of_decl_compilation (x, 0, IDENTIFIER_LOCAL_VALUE (x) == 0, 0);
+ rest_of_decl_compilation (x, 0, IDENTIFIER_LOCAL_VALUE (x) == 0,
+ 0);
TREE_ADDRESSABLE (x) = 1;
pop_obstacks ();
@@ -4526,31 +4906,36 @@ mark_addressable (exp)
case CONST_DECL:
case RESULT_DECL:
- /* For C++, we don't warn about taking the address of a register
- variable for CONST_DECLs; ARM p97 explicitly says it's okay. */
+ if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
+ && !DECL_ARTIFICIAL (x) && extra_warnings)
+ cp_warning ("address requested for `%D', which is declared `register'",
+ x);
put_var_into_stack (x);
TREE_ADDRESSABLE (x) = 1;
return 1;
case FUNCTION_DECL:
- /* We have to test both conditions here. The first may
- be non-zero in the case of processing a default function.
- The second may be non-zero in the case of a template function. */
- x = DECL_MAIN_VARIANT (x);
- if ((DECL_THIS_INLINE (x) || DECL_PENDING_INLINE_INFO (x))
- && (DECL_CONTEXT (x) == NULL_TREE
- || TREE_CODE_CLASS (TREE_CODE (DECL_CONTEXT (x))) != 't'
- || ! CLASSTYPE_INTERFACE_ONLY (DECL_CONTEXT (x))))
+ if (DECL_LANG_SPECIFIC (x) != 0)
{
- mark_inline_for_output (x);
- if (x == current_function_decl)
- DECL_EXTERNAL (x) = 0;
+ x = DECL_MAIN_VARIANT (x);
+ /* We have to test both conditions here. The first may be
+ non-zero in the case of processing a default function. The
+ second may be non-zero in the case of a template function. */
+ if (DECL_TEMPLATE_INFO (x) && !DECL_TEMPLATE_SPECIALIZATION (x))
+ mark_used (x);
}
TREE_ADDRESSABLE (x) = 1;
TREE_USED (x) = 1;
TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
- if (asm_out_file)
- assemble_external (x);
+ return 1;
+
+ case CONSTRUCTOR:
+ TREE_ADDRESSABLE (x) = 1;
+ return 1;
+
+ case TARGET_EXPR:
+ TREE_ADDRESSABLE (x) = 1;
+ mark_addressable (TREE_OPERAND (x, 0));
return 1;
default:
@@ -4564,15 +4949,10 @@ tree
build_x_conditional_expr (ifexp, op1, op2)
tree ifexp, op1, op2;
{
- tree rval = NULL_TREE;
+ if (processing_template_decl)
+ return build_min_nt (COND_EXPR, ifexp, op1, op2);
- /* See comments in `build_x_binary_op'. */
- if (op1 != 0)
- rval = build_opfncall (COND_EXPR, LOOKUP_SPECULATIVELY, ifexp, op1, op2);
- if (rval)
- return build_opfncall (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
-
- return build_conditional_expr (ifexp, op1, op2);
+ return build_new_op (COND_EXPR, LOOKUP_NORMAL, ifexp, op1, op2);
}
tree
@@ -4584,7 +4964,6 @@ build_conditional_expr (ifexp, op1, op2)
register enum tree_code code1;
register enum tree_code code2;
register tree result_type = NULL_TREE;
- tree orig_op1 = op1, orig_op2 = op2;
/* If second operand is omitted, it is the same as the first one;
make sure it is calculated only once. */
@@ -4595,7 +4974,7 @@ build_conditional_expr (ifexp, op1, op2)
ifexp = op1 = save_expr (ifexp);
}
- ifexp = convert (boolean_type_node, ifexp);
+ ifexp = cp_convert (boolean_type_node, ifexp);
if (TREE_CODE (ifexp) == ERROR_MARK)
return error_mark_node;
@@ -4626,17 +5005,12 @@ build_conditional_expr (ifexp, op1, op2)
code2 = TREE_CODE (type2);
}
-#if 1 /* Produces wrong result if within sizeof. Sorry. */
/* Don't promote the operands separately if they promote
the same way. Return the unpromoted type and let the combined
value get promoted if necessary. */
if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2)
&& code2 != ARRAY_TYPE
-#if 0
- /* For C++, let the enumeral type come through. */
- && code2 != ENUMERAL_TYPE
-#endif
&& code2 != FUNCTION_TYPE
&& code2 != METHOD_TYPE)
{
@@ -4665,9 +5039,17 @@ build_conditional_expr (ifexp, op1, op2)
result = fold (build (COND_EXPR, type1, ifexp, op1, op2));
if (TREE_TYPE (result) != type1)
result = build1 (NOP_EXPR, type1, result);
+ /* Expand both sides into the same slot,
+ hopefully the target of the ?: expression. */
+ if (TREE_CODE (op1) == TARGET_EXPR && TREE_CODE (op2) == TARGET_EXPR)
+ {
+ tree slot = build (VAR_DECL, TREE_TYPE (result));
+ layout_decl (slot, 0);
+ result = build (TARGET_EXPR, TREE_TYPE (result),
+ slot, result, NULL_TREE, NULL_TREE);
+ }
return result;
}
-#endif
/* They don't match; promote them both and then try to reconcile them.
But don't permit mismatching enum types. */
@@ -4675,7 +5057,8 @@ build_conditional_expr (ifexp, op1, op2)
{
if (code2 == ENUMERAL_TYPE)
{
- cp_error ("enumeral mismatch in conditional expression: `%T' vs `%T'", type1, type2);
+ cp_error ("enumeral mismatch in conditional expression: `%T' vs `%T'",
+ type1, type2);
return error_mark_node;
}
else if (extra_warnings && ! IS_AGGR_TYPE_CODE (code2)
@@ -4739,16 +5122,14 @@ build_conditional_expr (ifexp, op1, op2)
pedwarn ("ANSI C++ forbids conditional expr with only one void side");
result_type = void_type_node;
}
+ else if (code1 == POINTER_TYPE && null_ptr_cst_p (op2))
+ result_type = qualify_type (type1, type2);
+ else if (code2 == POINTER_TYPE && null_ptr_cst_p (op1))
+ result_type = qualify_type (type2, type1);
else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE)
{
if (comp_target_types (type1, type2, 1))
result_type = common_type (type1, type2);
- else if (integer_zerop (op1) && TREE_TYPE (type1) == void_type_node
- && TREE_CODE (orig_op1) != NOP_EXPR)
- result_type = qualify_type (type2, type1);
- else if (integer_zerop (op2) && TREE_TYPE (type2) == void_type_node
- && TREE_CODE (orig_op2) != NOP_EXPR)
- result_type = qualify_type (type1, type2);
else if (TYPE_MAIN_VARIANT (TREE_TYPE (type1)) == void_type_node)
{
if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
@@ -4766,7 +5147,8 @@ build_conditional_expr (ifexp, op1, op2)
result_type = type2;
else if (IS_AGGR_TYPE (TREE_TYPE (type1))
&& IS_AGGR_TYPE (TREE_TYPE (type2))
- && (result_type = common_base_type (TREE_TYPE (type1), TREE_TYPE (type2))))
+ && (result_type = common_base_type (TREE_TYPE (type1),
+ TREE_TYPE (type2))))
{
if (result_type == error_mark_node)
{
@@ -4793,30 +5175,12 @@ build_conditional_expr (ifexp, op1, op2)
}
else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE)
{
- if (!integer_zerop (op2))
- pedwarn ("pointer/integer type mismatch in conditional expression");
- else
- {
- op2 = null_pointer_node;
-#if 0 /* Sez who? */
- if (pedantic && TREE_CODE (type1) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids conditional expr between 0 and function pointer");
-#endif
- }
+ pedwarn ("pointer/integer type mismatch in conditional expression");
result_type = type1;
}
else if (code2 == POINTER_TYPE && code1 == INTEGER_TYPE)
{
- if (!integer_zerop (op1))
- pedwarn ("pointer/integer type mismatch in conditional expression");
- else
- {
- op1 = null_pointer_node;
-#if 0 /* Sez who? */
- if (pedantic && TREE_CODE (type2) == FUNCTION_TYPE)
- pedwarn ("ANSI C++ forbids conditional expr between 0 and function pointer");
-#endif
- }
+ pedwarn ("pointer/integer type mismatch in conditional expression");
result_type = type2;
}
@@ -4826,33 +5190,56 @@ build_conditional_expr (ifexp, op1, op2)
an aggregate value, try converting to a scalar type. */
if (code1 == RECORD_TYPE && code2 == RECORD_TYPE)
{
- cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'", type1, type2);
+ cp_error ("aggregate mismatch in conditional expression: `%T' vs `%T'",
+ type1, type2);
return error_mark_node;
}
+ /* Warning: this code assumes that conversion between cv-variants of
+ a type is done using NOP_EXPRs. */
if (code1 == RECORD_TYPE && TYPE_HAS_CONVERSION (type1))
{
- tree tmp = build_type_conversion (CONVERT_EXPR, type2, op1, 0);
+ /* There are other types besides pointers and records. */
+ tree tmp;
+ if (code2 == POINTER_TYPE)
+ tmp = build_pointer_type
+ (build_type_variant (TREE_TYPE (type2), 1, 1));
+ else
+ tmp = type2;
+ tmp = build_type_conversion (CONVERT_EXPR, tmp, op1, 0);
if (tmp == NULL_TREE)
{
- cp_error ("aggregate type `%T' could not convert on lhs of `:'", type1);
+ cp_error ("incompatible types `%T' and `%T' in `?:'",
+ type1, type2);
return error_mark_node;
}
if (tmp == error_mark_node)
error ("ambiguous pointer conversion");
- result_type = type2;
+ else
+ STRIP_NOPS (tmp);
+ result_type = common_type (type2, TREE_TYPE (tmp));
op1 = tmp;
}
else if (code2 == RECORD_TYPE && TYPE_HAS_CONVERSION (type2))
{
- tree tmp = build_type_conversion (CONVERT_EXPR, type1, op2, 0);
+ tree tmp;
+ if (code1 == POINTER_TYPE)
+ tmp = build_pointer_type
+ (build_type_variant (TREE_TYPE (type1), 1, 1));
+ else
+ tmp = type1;
+
+ tmp = build_type_conversion (CONVERT_EXPR, tmp, op2, 0);
if (tmp == NULL_TREE)
{
- cp_error ("aggregate type `%T' could not convert on rhs of `:'", type2);
+ cp_error ("incompatible types `%T' and `%T' in `?:'",
+ type1, type2);
return error_mark_node;
}
if (tmp == error_mark_node)
error ("ambiguous pointer conversion");
- result_type = type1;
+ else
+ STRIP_NOPS (tmp);
+ result_type = common_type (type1, TREE_TYPE (tmp));
op2 = tmp;
}
else if (flag_cond_mismatch)
@@ -4869,48 +5256,13 @@ build_conditional_expr (ifexp, op1, op2)
result_type = build_ptrmemfunc_type (result_type);
if (result_type != TREE_TYPE (op1))
- op1 = convert_and_check (result_type, op1);
+ op1 = convert_for_initialization
+ (NULL_TREE, result_type, op1, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
if (result_type != TREE_TYPE (op2))
- op2 = convert_and_check (result_type, op2);
-
-#if 0
- /* XXX delete me, I've been here for years. */
- if (IS_AGGR_TYPE_CODE (code1))
- {
- result_type = TREE_TYPE (op1);
- if (TREE_CONSTANT (ifexp))
- return (integer_zerop (ifexp) ? op2 : op1);
+ op2 = convert_for_initialization
+ (NULL_TREE, result_type, op2, LOOKUP_NORMAL, "converting", NULL_TREE, 0);
- if (TYPE_MODE (result_type) == BLKmode)
- {
- register tree tempvar
- = build_decl (VAR_DECL, NULL_TREE, result_type);
- register tree xop1 = build_modify_expr (tempvar, NOP_EXPR, op1);
- register tree xop2 = build_modify_expr (tempvar, NOP_EXPR, op2);
- register tree result = fold (build (COND_EXPR, result_type,
- ifexp, xop1, xop2));
-
- layout_decl (tempvar, 0);
- /* No way to handle variable-sized objects here.
- I fear that the entire handling of BLKmode conditional exprs
- needs to be redone. */
- my_friendly_assert (TREE_CONSTANT (DECL_SIZE (tempvar)), 315);
- DECL_RTL (tempvar)
- = assign_stack_local (DECL_MODE (tempvar),
- (TREE_INT_CST_LOW (DECL_SIZE (tempvar))
- + BITS_PER_UNIT - 1)
- / BITS_PER_UNIT,
- 0);
-
- TREE_SIDE_EFFECTS (result)
- = TREE_SIDE_EFFECTS (ifexp) | TREE_SIDE_EFFECTS (op1)
- | TREE_SIDE_EFFECTS (op2);
- return build (COMPOUND_EXPR, result_type, result, tempvar);
- }
- }
-#endif /* 0 */
-
- if (TREE_CONSTANT (ifexp))
+ if (TREE_CODE (ifexp) == INTEGER_CST)
return integer_zerop (ifexp) ? op2 : op1;
return convert_from_reference
@@ -4919,6 +5271,7 @@ build_conditional_expr (ifexp, op1, op2)
/* Handle overloading of the ',' operator when needed. Otherwise,
this function just builds an expression list. */
+
tree
build_x_compound_expr (list)
tree list;
@@ -4926,13 +5279,17 @@ build_x_compound_expr (list)
tree rest = TREE_CHAIN (list);
tree result;
+ if (processing_template_decl)
+ return build_min_nt (COMPOUND_EXPR, list, NULL_TREE);
+
if (rest == NULL_TREE)
return build_compound_expr (list);
result = build_opfncall (COMPOUND_EXPR, LOOKUP_NORMAL,
TREE_VALUE (list), TREE_VALUE (rest), NULL_TREE);
if (result)
- return build_x_compound_expr (tree_cons (NULL_TREE, result, TREE_CHAIN (rest)));
+ return build_x_compound_expr (expr_tree_cons (NULL_TREE, result,
+ TREE_CHAIN (rest)));
if (! TREE_SIDE_EFFECTS (TREE_VALUE (list)))
{
@@ -4949,8 +5306,10 @@ build_x_compound_expr (list)
warn_if_unused_value (TREE_VALUE(list));
#endif
- return build_compound_expr (tree_cons (NULL_TREE, TREE_VALUE (list),
- build_tree_list (NULL_TREE, build_x_compound_expr (rest))));
+ return build_compound_expr
+ (expr_tree_cons (NULL_TREE, TREE_VALUE (list),
+ build_expr_list (NULL_TREE,
+ build_x_compound_expr (rest))));
}
/* Given a list of expressions, return a compound expression
@@ -4990,127 +5349,264 @@ build_compound_expr (list)
break_out_cleanups (TREE_VALUE (list)), rest);
}
-#ifdef __GNUC__
-__inline
-#endif
-int
-null_ptr_cst_p (t)
- tree t;
-{
- return (TREE_CODE (t) == INTEGER_CST && integer_zerop (t));
-}
-
-tree build_static_cast (type, expr)
+tree
+build_static_cast (type, expr)
tree type, expr;
{
- return build_c_cast (type, expr, 0);
+ tree intype, binfo;
+ int ok;
+
+ if (type == error_mark_node || expr == error_mark_node)
+ return error_mark_node;
+
+ if (TREE_CODE (expr) == OFFSET_REF)
+ expr = resolve_offset_ref (expr);
+
+ if (processing_template_decl)
+ {
+ tree t = build_min (STATIC_CAST_EXPR, copy_to_permanent (type),
+ expr);
+ return t;
+ }
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (type) != REFERENCE_TYPE
+ && TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
+
+ if (TREE_CODE (type) == VOID_TYPE)
+ return build1 (CONVERT_EXPR, type, expr);
+
+ if (type_unknown_p (expr))
+ {
+ expr = instantiate_type (type, expr, 1);
+ if (expr == error_mark_node)
+ return error_mark_node;
+ }
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ return (convert_from_reference
+ (convert_to_reference (type, expr, CONV_STATIC|CONV_IMPLICIT,
+ LOOKUP_COMPLAIN, NULL_TREE)));
+
+ if (IS_AGGR_TYPE (type))
+ return build_cplus_new
+ (type, (build_method_call
+ (NULL_TREE, ctor_identifier, build_expr_list (NULL_TREE, expr),
+ TYPE_BINFO (type), LOOKUP_NORMAL)));
+
+ expr = decay_conversion (expr);
+ intype = TREE_TYPE (expr);
+
+ /* FIXME handle casting to array type. */
+
+ ok = 0;
+ if (can_convert_arg (type, intype, expr))
+ ok = 1;
+ else if (TYPE_PTROB_P (type) && TYPE_PTROB_P (intype))
+ {
+ tree binfo;
+ if (IS_AGGR_TYPE (TREE_TYPE (type)) && IS_AGGR_TYPE (TREE_TYPE (intype))
+ && (TYPE_READONLY (TREE_TYPE (type))
+ >= TYPE_READONLY (TREE_TYPE (intype)))
+ && (TYPE_VOLATILE (TREE_TYPE (type))
+ >= TYPE_VOLATILE (TREE_TYPE (intype)))
+ && (binfo = get_binfo (TREE_TYPE (intype), TREE_TYPE (type), 0))
+ && ! TREE_VIA_VIRTUAL (binfo))
+ ok = 1;
+ }
+ else if (TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+ {
+ if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type))),
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (intype))), 1)
+ && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (type)))
+ >= TYPE_READONLY (TREE_TYPE (TREE_TYPE (intype))))
+ && (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (type)))
+ >= TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (intype))))
+ && (binfo = get_binfo (TYPE_OFFSET_BASETYPE (TREE_TYPE (type)),
+ TYPE_OFFSET_BASETYPE (TREE_TYPE (intype)), 0))
+ && ! TREE_VIA_VIRTUAL (binfo))
+ ok = 1;
+ }
+ else if (TREE_CODE (intype) != BOOLEAN_TYPE
+ && TREE_CODE (type) != ARRAY_TYPE
+ && TREE_CODE (type) != FUNCTION_TYPE
+ && can_convert (intype, type))
+ ok = 1;
+
+ if (ok)
+ return build_c_cast (type, expr);
+
+ cp_error ("static_cast from `%T' to `%T'", intype, type);
+ return error_mark_node;
}
-tree build_reinterpret_cast (type, expr)
+tree
+build_reinterpret_cast (type, expr)
tree type, expr;
{
- tree intype = TREE_TYPE (expr);
+ tree intype;
- if (TYPE_PTRMEMFUNC_P (type))
- type = TYPE_PTRMEMFUNC_FN_TYPE (type);
- if (TYPE_PTRMEMFUNC_P (intype))
- intype = TYPE_PTRMEMFUNC_FN_TYPE (intype);
+ if (type == error_mark_node || expr == error_mark_node)
+ return error_mark_node;
+
+ if (TREE_CODE (expr) == OFFSET_REF)
+ expr = resolve_offset_ref (expr);
- if (! POINTER_TYPE_P (type) && ! TREE_CODE (type) == INTEGER_TYPE)
+ if (processing_template_decl)
{
- cp_error ("reinterpret_cast cannot convert to type `%T'", type);
- return error_mark_node;
+ tree t = build_min (REINTERPRET_CAST_EXPR,
+ copy_to_permanent (type), expr);
+ return t;
}
- if (! POINTER_TYPE_P (intype) && ! TREE_CODE (intype) == INTEGER_TYPE)
+
+ if (TREE_CODE (type) != REFERENCE_TYPE)
{
- cp_error ("reinterpret_cast cannot convert from type `%T'", type);
- return error_mark_node;
+ expr = decay_conversion (expr);
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
}
- if (TREE_CODE (type) == INTEGER_TYPE && TREE_CODE (intype) != POINTER_TYPE)
+
+ if (type_unknown_p (expr))
{
- cp_error ("reinterpret_cast cannot convert non-pointer type `%T' to `%T'",
- intype, type);
- return error_mark_node;
+ expr = instantiate_type (type, expr, 1);
+ if (expr == error_mark_node)
+ return error_mark_node;
}
- if (TREE_CODE (intype) == INTEGER_TYPE && TREE_CODE (type) != POINTER_TYPE)
+
+ intype = TREE_TYPE (expr);
+
+ if (TREE_CODE (type) == REFERENCE_TYPE)
{
- cp_error ("reinterpret_cast cannot convert `%T' to non-pointer type `%T'",
- intype, type);
- return error_mark_node;
+ if (! real_lvalue_p (expr))
+ {
+ cp_error ("reinterpret_cast from `%T' rvalue to `%T'", intype, type);
+ return error_mark_node;
+ }
+ expr = build_unary_op (ADDR_EXPR, expr, 0);
+ if (expr != error_mark_node)
+ expr = build_reinterpret_cast
+ (build_pointer_type (TREE_TYPE (type)), expr);
+ if (expr != error_mark_node)
+ expr = build_indirect_ref (expr, 0);
+ return expr;
}
+ else if (comptypes (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type), 1))
+ return build_static_cast (type, expr);
- if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (intype) == POINTER_TYPE)
- expr = convert (ptr_type_node, expr);
+ if (TYPE_PTR_P (type) && (TREE_CODE (intype) == INTEGER_TYPE
+ || TREE_CODE (intype) == ENUMERAL_TYPE))
+ /* OK */;
+ else if (TREE_CODE (type) == INTEGER_TYPE && TYPE_PTR_P (intype))
+ {
+ if (TYPE_PRECISION (type) < TYPE_PRECISION (intype))
+ cp_pedwarn ("reinterpret_cast from `%T' to `%T' loses precision",
+ intype, type);
+ }
+ else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
+ || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
+ {
+ if (TREE_READONLY_DECL_P (expr))
+ expr = decl_constant_value (expr);
+ return fold (build1 (NOP_EXPR, type, expr));
+ }
+ else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
+ || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
+ {
+ if (! comp_ptr_ttypes_reinterpret (TREE_TYPE (type), TREE_TYPE (intype)))
+ cp_pedwarn ("reinterpret_cast from `%T' to `%T' casts away const (or volatile)",
+ intype, type);
- return build_c_cast (type, expr, 0);
+ if (TREE_READONLY_DECL_P (expr))
+ expr = decl_constant_value (expr);
+ return fold (build1 (NOP_EXPR, type, expr));
+ }
+ else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
+ || (TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype)))
+ {
+ pedwarn ("ANSI C++ forbids casting between pointers to functions and objects");
+ if (TREE_READONLY_DECL_P (expr))
+ expr = decl_constant_value (expr);
+ return fold (build1 (NOP_EXPR, type, expr));
+ }
+ else
+ {
+ cp_error ("reinterpret_cast from `%T' to `%T'", intype, type);
+ return error_mark_node;
+ }
+
+ return cp_convert (type, expr);
}
-tree build_const_cast (type, expr)
+tree
+build_const_cast (type, expr)
tree type, expr;
{
- tree intype = TREE_TYPE (expr);
- tree t1, t2;
+ tree intype;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
- if (TYPE_PTRMEMFUNC_P (type))
- type = TYPE_PTRMEMFUNC_FN_TYPE (type);
- if (TYPE_PTRMEMFUNC_P (intype))
- intype = TYPE_PTRMEMFUNC_FN_TYPE (intype);
+ if (TREE_CODE (expr) == OFFSET_REF)
+ expr = resolve_offset_ref (expr);
- if (! POINTER_TYPE_P (type))
- {
- cp_error ("const_cast cannot convert to non-pointer type `%T'", type);
- return error_mark_node;
- }
- if (TREE_CODE (type) == REFERENCE_TYPE && ! real_lvalue_p (expr))
+ if (processing_template_decl)
{
- cp_error ("const_cast cannot convert rvalue to type `%T'", type);
- return error_mark_node;
+ tree t = build_min (CONST_CAST_EXPR, copy_to_permanent (type),
+ expr);
+ return t;
}
- if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (intype) != POINTER_TYPE)
+
+ if (TREE_CODE (type) != REFERENCE_TYPE)
{
- cp_error ("const_cast cannot convert non-pointer type `%T' to type `%T'",
- intype, type);
- return error_mark_node;
+ expr = decay_conversion (expr);
+
+ /* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
+ Strip such NOP_EXPRs if VALUE is being used in non-lvalue context. */
+ if (TREE_CODE (expr) == NOP_EXPR
+ && TREE_TYPE (expr) == TREE_TYPE (TREE_OPERAND (expr, 0)))
+ expr = TREE_OPERAND (expr, 0);
}
- if (TREE_CODE (type) == REFERENCE_TYPE)
+ if (type_unknown_p (expr))
{
- t1 = TREE_TYPE (type);
- t2 = intype;
+ expr = instantiate_type (type, expr, 1);
+ if (expr == error_mark_node)
+ return error_mark_node;
}
- else
- {
- t1 = TREE_TYPE (type);
- t2 = TREE_TYPE (intype);
- for (; TREE_CODE (t1) == POINTER_TYPE && TREE_CODE (t2) == POINTER_TYPE;
- t1 = TREE_TYPE (t1), t2 = TREE_TYPE (t2))
- ;
- }
+ intype = TREE_TYPE (expr);
- if (TREE_CODE (t1) == OFFSET_TYPE && TREE_CODE (t2) == OFFSET_TYPE)
+ if (comptypes (TYPE_MAIN_VARIANT (intype), TYPE_MAIN_VARIANT (type), 1))
+ return build_static_cast (type, expr);
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
{
- if (TYPE_OFFSET_BASETYPE (t1) != TYPE_OFFSET_BASETYPE (t2))
+ if (! real_lvalue_p (expr))
{
- cp_error ("const_cast cannot convert between pointers to members of different types `%T' and `%T'",
- TYPE_OFFSET_BASETYPE (t2), TYPE_OFFSET_BASETYPE (t1));
+ cp_error ("const_cast from `%T' rvalue to `%T'", intype, type);
return error_mark_node;
}
- t1 = TREE_TYPE (t1);
- t2 = TREE_TYPE (t2);
- }
- if (TYPE_MAIN_VARIANT (t1) != TYPE_MAIN_VARIANT (t2))
- {
- cp_error ("const_cast cannot convert unrelated type `%T' to `%T'",
- t2, t1);
- return error_mark_node;
+ if (comp_ptr_ttypes_const (TREE_TYPE (type), intype))
+ {
+ expr = build_unary_op (ADDR_EXPR, expr, 0);
+ expr = build1 (NOP_EXPR, type, expr);
+ return convert_from_reference (expr);
+ }
}
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (intype) == POINTER_TYPE
+ && comp_ptr_ttypes_const (TREE_TYPE (type), TREE_TYPE (intype)))
+ return cp_convert (type, expr);
- return build_c_cast (type, expr, 0);
+ cp_error ("const_cast from `%T' to `%T'", intype, type);
+ return error_mark_node;
}
/* Build an expression representing a cast to type TYPE of expression EXPR.
@@ -5119,10 +5615,8 @@ tree build_const_cast (type, expr)
when doing the cast. */
tree
-build_c_cast (type, expr, allow_nonconverting)
- register tree type;
- tree expr;
- int allow_nonconverting;
+build_c_cast (type, expr)
+ tree type, expr;
{
register tree value = expr;
@@ -5172,11 +5666,12 @@ build_c_cast (type, expr, allow_nonconverting)
return error_mark_node;
}
- /* If there's only one function in the overloaded space,
- just take it. */
- if (TREE_CODE (value) == TREE_LIST
- && TREE_CHAIN (value) == NULL_TREE)
- value = TREE_VALUE (value);
+ if (processing_template_decl)
+ {
+ tree t = build_min (CAST_EXPR, type,
+ min_tree_cons (NULL_TREE, value, NULL_TREE));
+ return t;
+ }
if (TREE_CODE (type) == VOID_TYPE)
value = build1 (CONVERT_EXPR, type, value);
@@ -5191,16 +5686,39 @@ build_c_cast (type, expr, allow_nonconverting)
else
{
tree otype;
- int flag;
/* Convert functions and arrays to pointers and
convert references to their expanded types,
- but don't convert any other types. */
- if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
- || TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
- || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
- value = default_conversion (value);
+ but don't convert any other types. If, however, we are
+ casting to a class type, there's no reason to do this: the
+ cast will only succeed if there is a converting constructor,
+ and the default conversions will be done at that point. In
+ fact, doing the default conversion here is actually harmful
+ in cases like this:
+
+ typedef int A[2];
+ struct S { S(const A&); };
+
+ since we don't want the array-to-pointer conversion done. */
+ if (!IS_AGGR_TYPE (type))
+ {
+ if (TREE_CODE (TREE_TYPE (value)) == FUNCTION_TYPE
+ || (TREE_CODE (TREE_TYPE (value)) == METHOD_TYPE
+ /* Don't do the default conversion if we want a
+ pointer to a function. */
+ && ! (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE))
+ || TREE_CODE (TREE_TYPE (value)) == ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
+ value = default_conversion (value);
+ }
+ else if (TREE_CODE (TREE_TYPE (value)) == REFERENCE_TYPE)
+ /* However, even for class types, we still need to strip away
+ the reference type, since the call to convert_force below
+ does not expect the input expression to be of reference
+ type. */
+ value = convert_from_reference (value);
+
otype = TREE_TYPE (value);
/* Optionally warn about potentially worrisome casts. */
@@ -5229,6 +5747,8 @@ build_c_cast (type, expr, allow_nonconverting)
warning ("cast increases required alignment of target type");
#if 0
+ /* We should see about re-enabling these, they seem useful to
+ me. */
if (TREE_CODE (type) == INTEGER_TYPE
&& TREE_CODE (otype) == POINTER_TYPE
&& TYPE_PRECISION (type) != TYPE_PRECISION (otype))
@@ -5243,11 +5763,9 @@ build_c_cast (type, expr, allow_nonconverting)
warning ("cast to pointer from integer of different size");
#endif
- flag = allow_nonconverting ? CONV_NONCONVERTING : 0;
-
if (TREE_CODE (type) == REFERENCE_TYPE)
value = (convert_from_reference
- (convert_to_reference (type, value, CONV_OLD_CONVERT|flag,
+ (convert_to_reference (type, value, CONV_C_CAST,
LOOKUP_COMPLAIN, NULL_TREE)));
else
{
@@ -5257,7 +5775,7 @@ build_c_cast (type, expr, allow_nonconverting)
value = decl_constant_value (value);
ovalue = value;
- value = convert_force (type, value, flag);
+ value = convert_force (type, value, CONV_C_CAST);
/* Ignore any integer overflow caused by the cast. */
if (TREE_CODE (value) == INTEGER_CST)
@@ -5269,324 +5787,22 @@ build_c_cast (type, expr, allow_nonconverting)
}
/* Always produce some operator for an explicit cast,
- so we can tell (for -pedantic) that the cast is no lvalue.
- Also, pedantically, don't let (void *) (FOO *) 0 be a null
- pointer constant. */
- if (TREE_CODE (type) != REFERENCE_TYPE
- && (value == expr
- || (pedantic
- && TREE_CODE (value) == INTEGER_CST
- && TREE_CODE (expr) == INTEGER_CST
- && TREE_CODE (TREE_TYPE (expr)) != INTEGER_TYPE)))
+ so we can tell (for -pedantic) that the cast is no lvalue. */
+ if (TREE_CODE (type) != REFERENCE_TYPE && value == expr
+ && real_lvalue_p (value))
value = non_lvalue (value);
return value;
}
-#if 0
-/* Build an assignment expression of lvalue LHS from value RHS.
-
- In C++, if the left hand side of the assignment is a REFERENCE_TYPE,
- that reference becomes deferenced down to it base type. */
-
-/* Return a reference to the BASE_INDEX part of EXPR. TYPE is
- the type to which BASE_INDEX applies. */
-static tree
-get_base_ref (type, base_index, expr)
- tree type;
- int base_index;
- tree expr;
-{
- tree binfos = TYPE_BINFO_BASETYPES (type);
- tree base_binfo = TREE_VEC_ELT (binfos, base_index);
- tree ref;
-
- if (TREE_CODE (expr) == ARRAY_REF
- || ! BINFO_OFFSET_ZEROP (base_binfo)
- || TREE_VIA_VIRTUAL (base_binfo)
- || TYPE_MODE (type) != TYPE_MODE (BINFO_TYPE (base_binfo)))
- {
- tree addr = build_unary_op (ADDR_EXPR, expr, 0);
- ref = build_indirect_ref (convert_pointer_to (base_binfo, addr),
- NULL_PTR);
- }
- else
- {
- ref = copy_node (expr);
- TREE_TYPE (ref) = BINFO_TYPE (base_binfo);
- }
- return ref;
-}
-
/* Build an assignment expression of lvalue LHS from value RHS.
MODIFYCODE is the code for a binary operator that we use
to combine the old value of LHS with RHS to get the new value.
Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.
- C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.
-
- `build_modify_expr_1' implements recursive part of memberwise
- assignment operation. */
-static tree
-build_modify_expr_1 (lhs, modifycode, rhs, basetype_path)
- tree lhs, rhs;
- enum tree_code modifycode;
- tree basetype_path;
-{
- register tree result;
- tree newrhs = rhs;
- tree lhstype = TREE_TYPE (lhs);
- tree olhstype = lhstype;
-
- /* Avoid duplicate error messages from operands that had errors. */
- if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
- return error_mark_node;
-
- /* If a binary op has been requested, combine the old LHS value with the RHS
- producing the value we should actually store into the LHS. */
-
- if (modifycode == INIT_EXPR)
- ;
- else if (modifycode == NOP_EXPR)
- {
- /* must deal with overloading of `operator=' here. */
- if (TREE_CODE (lhstype) == REFERENCE_TYPE)
- lhstype = TREE_TYPE (lhstype);
- else
- lhstype = olhstype;
- }
- else
- {
- lhs = stabilize_reference (lhs);
- newrhs = build_binary_op (modifycode, lhs, rhs, 1);
- modifycode = NOP_EXPR;
- }
-
- /* If storing into a structure or union member,
- it has probably been given type `int'.
- Compute the type that would go with
- the actual amount of storage the member occupies. */
-
- if (TREE_CODE (lhs) == COMPONENT_REF
- && (TREE_CODE (lhstype) == INTEGER_TYPE
- || TREE_CODE (lhstype) == REAL_TYPE
- || TREE_CODE (lhstype) == ENUMERAL_TYPE))
- lhstype = TREE_TYPE (get_unwidened (lhs, 0));
-
- /* C++: The semantics of C++ differ from those of C when an
- assignment of an aggregate is desired. Assignment in C++ is
- now defined as memberwise assignment of non-static members
- and base class objects. This rule applies recursively
- until a member of a built-in type is found.
-
- Also, we cannot do a bit-wise copy of aggregates which
- contain virtual function table pointers. Those
- pointer values must be preserved through the copy.
- However, this is handled in expand_expr, and not here.
- This is because much better code can be generated at
- that stage than this one. */
- if (TREE_CODE (lhstype) == RECORD_TYPE
- && TYPE_LANG_SPECIFIC (lhstype)
- && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
- {
- register tree elt;
- int i;
-
- /* Perform operation on object. */
- if (modifycode == INIT_EXPR && TYPE_HAS_INIT_REF (lhstype))
- {
- result = build_method_call (lhs, constructor_name_full (lhstype),
- build_tree_list (NULL_TREE, rhs),
- basetype_path, LOOKUP_NORMAL);
- return build_indirect_ref (result, NULL_PTR);
- }
- else if (modifycode == NOP_EXPR)
- {
- /* `operator=' is not an inheritable operator; see 13.4.3. */
- if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_HAS_ASSIGNMENT (lhstype))
- {
- result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
- if (result == NULL_TREE)
- return error_mark_node;
- return result;
- }
- }
-
- if (TYPE_USES_VIRTUAL_BASECLASSES (lhstype)
- || (modifycode == NOP_EXPR && TYPE_GETS_ASSIGNMENT (lhstype))
- || (modifycode == INIT_EXPR && TYPE_GETS_INIT_REF (lhstype)))
- {
- tree binfos = BINFO_BASETYPES (TYPE_BINFO (lhstype));
- result = NULL_TREE;
-
- if (binfos != NULL_TREE)
- /* Perform operation on each member, depth-first, left-right. */
- for (i = 0; i <= TREE_VEC_LENGTH (binfos)-1; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- tree base_lhs, base_rhs;
- tree new_result;
-
- /* Assignments from virtual baseclasses handled elsewhere. */
- if (TREE_VIA_VIRTUAL (base_binfo))
- continue;
-
- base_lhs = get_base_ref (lhstype, i, lhs);
- base_rhs = get_base_ref (lhstype, i, newrhs);
-
- BINFO_INHERITANCE_CHAIN (base_binfo) = basetype_path;
- new_result
- = build_modify_expr_1 (base_lhs, modifycode, base_rhs,
- base_binfo);
-
- /* We either get back a compound stmt, or a simple one. */
- if (new_result && TREE_CODE (new_result) == TREE_LIST)
- new_result = build_compound_expr (new_result);
- result = tree_cons (NULL_TREE, new_result, result);
- }
-
- for (elt = TYPE_FIELDS (lhstype); elt; elt = TREE_CHAIN (elt))
- {
- tree vbases = NULL_TREE;
- tree elt_lhs, elt_rhs;
-
- if (TREE_CODE (elt) != FIELD_DECL)
- continue;
- if (DECL_NAME (elt)
- && (VFIELD_NAME_P (DECL_NAME (elt))
- || VBASE_NAME_P (DECL_NAME (elt))))
- continue;
-
- if (TREE_READONLY (elt)
- || TREE_CODE (TREE_TYPE (elt)) == REFERENCE_TYPE)
- {
- cp_error ("cannot generate default `%T::operator ='",
- lhstype);
- if (TREE_CODE (TREE_TYPE (elt)) == REFERENCE_TYPE)
- cp_error_at ("because member `%#D' is a reference", elt);
- else
- cp_error_at ("because member `%#D' is const", elt);
-
- return error_mark_node;
- }
-
- if (IS_AGGR_TYPE (TREE_TYPE (elt))
- && TYPE_LANG_SPECIFIC (TREE_TYPE (elt)))
- vbases = CLASSTYPE_VBASECLASSES (TREE_TYPE (elt));
-
- elt_lhs = build (COMPONENT_REF, TREE_TYPE (elt), lhs, elt);
- elt_rhs = build (COMPONENT_REF, TREE_TYPE (elt), newrhs, elt);
- /* It is not always safe to go through `build_modify_expr_1'
- when performing element-wise copying. This is because
- an element may be of ARRAY_TYPE, which will not
- be properly copied as a naked element. */
- if (TREE_CODE (TREE_TYPE (elt)) == RECORD_TYPE
- && TYPE_LANG_SPECIFIC (TREE_TYPE (elt)))
- basetype_path = TYPE_BINFO (TREE_TYPE (elt));
-
- while (vbases)
- {
- tree elt_lhs_addr = build_unary_op (ADDR_EXPR, elt_lhs, 0);
- tree elt_rhs_addr = build_unary_op (ADDR_EXPR, elt_rhs, 0);
-
- elt_lhs_addr = convert_pointer_to (vbases, elt_lhs_addr);
- elt_rhs_addr = convert_pointer_to (vbases, elt_rhs_addr);
- result
- = tree_cons (NULL_TREE,
- build_modify_expr_1
- (build_indirect_ref (elt_lhs_addr, NULL_PTR),
- modifycode,
- build_indirect_ref (elt_rhs_addr, NULL_PTR),
- basetype_path),
- result);
- if (TREE_VALUE (result) == error_mark_node)
- return error_mark_node;
- vbases = TREE_CHAIN (vbases);
- }
- elt_lhs = build_modify_expr_1 (elt_lhs, modifycode, elt_rhs,
- basetype_path);
- result = tree_cons (NULL_TREE, elt_lhs, result);
- }
-
- if (result)
- return build_compound_expr (result);
- /* No fields to move. */
- return integer_zero_node;
- }
- else
- {
- result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
- void_type_node, lhs, rhs);
- TREE_SIDE_EFFECTS (result) = 1;
- return result;
- }
- }
-
- result = build_modify_expr (lhs, modifycode, newrhs);
- /* ARRAY_TYPEs cannot be converted to anything meaningful,
- and leaving it there screws up `build_compound_expr' when
- it tries to defaultly convert everything. */
- if (TREE_CODE (TREE_TYPE (result)) == ARRAY_TYPE)
- TREE_TYPE (result) = void_type_node;
- return result;
-}
-#endif
-
-/* Taken from expr.c:
- Subroutine of expand_expr:
- record the non-copied parts (LIST) of an expr (LHS), and return a list
- which specifies the initial values of these parts. */
-
-static tree
-init_noncopied_parts (lhs, list)
- tree lhs;
- tree list;
-{
- tree tail;
- tree parts = 0;
-
- for (tail = list; tail; tail = TREE_CHAIN (tail))
- if (TREE_CODE (TREE_VALUE (tail)) == TREE_LIST)
- parts = chainon (parts, init_noncopied_parts (lhs, TREE_VALUE (tail)));
- else
- {
- tree part = TREE_VALUE (tail);
- tree part_type = TREE_TYPE (part);
- tree to_be_initialized = build (COMPONENT_REF, part_type, lhs, part);
- parts = tree_cons (TREE_PURPOSE (tail), to_be_initialized, parts);
- }
- return parts;
-}
+ C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed. */
tree
-expand_target_expr (t)
- tree t;
-{
- tree xval = make_node (RTL_EXPR);
- rtx rtxval;
-
- do_pending_stack_adjust ();
- start_sequence_for_rtl_expr (xval);
- emit_note (0, -1);
- rtxval = expand_expr (t, NULL, VOIDmode, 0);
- do_pending_stack_adjust ();
- TREE_SIDE_EFFECTS (xval) = 1;
- RTL_EXPR_SEQUENCE (xval) = get_insns ();
- end_sequence ();
- RTL_EXPR_RTL (xval) = rtxval;
- TREE_TYPE (xval) = TREE_TYPE (t);
- return xval;
-}
-
-/* Build an assignment expression of lvalue LHS from value RHS.
- MODIFYCODE is the code for a binary operator that we use
- to combine the old value of LHS with RHS to get the new value.
- Or else MODIFYCODE is NOP_EXPR meaning do a simple assignment.
-
- C++: If MODIFYCODE is INIT_EXPR, then leave references unbashed.
-*/
-tree
build_modify_expr (lhs, modifycode, rhs)
tree lhs;
enum tree_code modifycode;
@@ -5599,24 +5815,18 @@ build_modify_expr (lhs, modifycode, rhs)
tree olhs = lhs;
/* Avoid duplicate error messages from operands that had errors. */
- if (TREE_CODE (lhs) == ERROR_MARK || TREE_CODE (rhs) == ERROR_MARK)
+ if (lhs == error_mark_node || rhs == error_mark_node)
return error_mark_node;
/* Types that aren't fully specified cannot be used in assignments. */
lhs = require_complete_type (lhs);
- /* Decide early if we are going to protect RHS from GC
- before assigning it to LHS. */
- if (type_needs_gc_entry (TREE_TYPE (rhs))
- && ! value_safe_from_gc (lhs, rhs))
- rhs = protect_value_from_gc (lhs, rhs);
-
newrhs = rhs;
/* Handle assignment to signature pointers/refs. */
- if (TYPE_LANG_SPECIFIC (lhstype) &&
- (IS_SIGNATURE_POINTER (lhstype) || IS_SIGNATURE_REFERENCE (lhstype)))
+ if (TYPE_LANG_SPECIFIC (lhstype)
+ && (IS_SIGNATURE_POINTER (lhstype) || IS_SIGNATURE_REFERENCE (lhstype)))
{
return build_signature_pointer_constructor (lhs, rhs);
}
@@ -5630,7 +5840,8 @@ build_modify_expr (lhs, modifycode, rhs)
case PREINCREMENT_EXPR:
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
lhs = build (TREE_CODE (lhs), TREE_TYPE (lhs),
- stabilize_reference (TREE_OPERAND (lhs, 0)));
+ stabilize_reference (TREE_OPERAND (lhs, 0)),
+ TREE_OPERAND (lhs, 1));
return build (COMPOUND_EXPR, lhstype,
lhs,
build_modify_expr (TREE_OPERAND (lhs, 0),
@@ -5640,14 +5851,14 @@ build_modify_expr (lhs, modifycode, rhs)
case COMPOUND_EXPR:
newrhs = build_modify_expr (TREE_OPERAND (lhs, 1),
modifycode, rhs);
- if (TREE_CODE (newrhs) == ERROR_MARK)
+ if (newrhs == error_mark_node)
return error_mark_node;
return build (COMPOUND_EXPR, lhstype,
TREE_OPERAND (lhs, 0), newrhs);
case MODIFY_EXPR:
newrhs = build_modify_expr (TREE_OPERAND (lhs, 0), modifycode, rhs);
- if (TREE_CODE (newrhs) == ERROR_MARK)
+ if (newrhs == error_mark_node)
return error_mark_node;
return build (COMPOUND_EXPR, lhstype, lhs, newrhs);
@@ -5660,19 +5871,22 @@ build_modify_expr (lhs, modifycode, rhs)
so the code to compute it is only emitted once. */
tree cond
= build_conditional_expr (TREE_OPERAND (lhs, 0),
- build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
+ build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 1)),
modifycode, rhs),
- build_modify_expr (convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
+ build_modify_expr (cp_convert (TREE_TYPE (lhs), TREE_OPERAND (lhs, 2)),
modifycode, rhs));
- if (TREE_CODE (cond) == ERROR_MARK)
+ if (cond == error_mark_node)
return cond;
/* Make sure the code to compute the rhs comes out
before the split. */
return build (COMPOUND_EXPR, TREE_TYPE (lhs),
/* Case to void to suppress warning
from warn_if_unused_value. */
- convert (void_type_node, rhs), cond);
+ cp_convert (void_type_node, rhs), cond);
}
+
+ default:
+ break;
}
if (TREE_CODE (lhs) == OFFSET_REF)
@@ -5709,19 +5923,11 @@ build_modify_expr (lhs, modifycode, rhs)
{
if (! IS_AGGR_TYPE (lhstype))
/* Do the default thing */;
- else if (! TYPE_HAS_CONSTRUCTOR (lhstype))
- {
- cp_error ("`%T' has no constructors", lhstype);
- return error_mark_node;
- }
- else if (TYPE_HAS_TRIVIAL_INIT_REF (lhstype)
- && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
- /* Do the default thing */;
else
{
- result = build_method_call (lhs, constructor_name_full (lhstype),
- build_tree_list (NULL_TREE, rhs),
- NULL_TREE, LOOKUP_NORMAL);
+ result = build_method_call (lhs, ctor_identifier,
+ build_expr_list (NULL_TREE, rhs),
+ TYPE_BINFO (lhstype), LOOKUP_NORMAL);
if (result == NULL_TREE)
return error_mark_node;
return result;
@@ -5729,25 +5935,9 @@ build_modify_expr (lhs, modifycode, rhs)
}
else if (modifycode == NOP_EXPR)
{
-#if 1
/* `operator=' is not an inheritable operator. */
if (! IS_AGGR_TYPE (lhstype))
/* Do the default thing */;
- else if (! TYPE_HAS_ASSIGNMENT (lhstype))
- {
- cp_error ("`%T' does not define operator=", lhstype);
- return error_mark_node;
- }
- else if (TYPE_HAS_TRIVIAL_ASSIGN_REF (lhstype)
- && TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs)))
- {
- if (warn_synth)
- /* If we care about this, do overload resolution. */
- build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
-
- /* Do the default thing */;
- }
else
{
result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
@@ -5756,72 +5946,22 @@ build_modify_expr (lhs, modifycode, rhs)
return error_mark_node;
return result;
}
-#else
- /* Treat `operator=' as an inheritable operator. */
- if (TYPE_LANG_SPECIFIC (lhstype) && TYPE_GETS_ASSIGNMENT (lhstype))
- {
- tree orig_lhstype = lhstype;
- while (! TYPE_HAS_ASSIGNMENT (lhstype))
- {
- int i, n_baseclasses = CLASSTYPE_N_BASECLASSES (lhstype);
- tree basetype = NULL_TREE;
- for (i = 0; i < n_baseclasses; i++)
- if (TYPE_GETS_ASSIGNMENT (TYPE_BINFO_BASETYPE (lhstype, i)))
- {
- if (basetype != NULL_TREE)
- {
- message_2_types (error, "base classes `%s' and `%s' both have operator ='",
- basetype,
- TYPE_BINFO_BASETYPE (lhstype, i));
- return error_mark_node;
- }
- basetype = TYPE_BINFO_BASETYPE (lhstype, i);
- }
- lhstype = basetype;
- }
- if (orig_lhstype != lhstype)
- {
- lhs = build_indirect_ref (convert_pointer_to (lhstype,
- build_unary_op (ADDR_EXPR, lhs, 0)), NULL_PTR);
- if (lhs == error_mark_node)
- {
- cp_error ("conversion to private basetype `%T'", lhstype);
- return error_mark_node;
- }
- }
- result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
- lhs, rhs, make_node (NOP_EXPR));
- if (result == NULL_TREE)
- return error_mark_node;
- return result;
- }
-#endif
lhstype = olhstype;
}
else if (PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE))
{
- /* This case must convert to some sort of lvalue that
- can participate in an op= operation. */
- tree lhs_tmp = lhs;
- tree rhs_tmp = rhs;
- if (build_default_binary_type_conversion (modifycode, &lhs_tmp, &rhs_tmp))
- {
- lhs = stabilize_reference (lhs_tmp);
- /* Forget is was ever anything else. */
- olhstype = lhstype = TREE_TYPE (lhs);
- newrhs = build_binary_op (modifycode, lhs, rhs_tmp, 1);
- }
- else
- {
- cp_error ("no match for `%O(%#T, %#T)'", modifycode,
- TREE_TYPE (lhs), TREE_TYPE (rhs));
- return error_mark_node;
- }
+ my_friendly_abort (978652);
}
else
{
lhs = stabilize_reference (lhs);
newrhs = build_binary_op (modifycode, lhs, rhs, 1);
+ if (newrhs == error_mark_node)
+ {
+ cp_error (" in evaluation of `%Q(%#T, %#T)'", modifycode,
+ TREE_TYPE (lhs), TREE_TYPE (rhs));
+ return error_mark_node;
+ }
}
/* Handle a cast used as an "lvalue".
@@ -5848,16 +5988,22 @@ build_modify_expr (lhs, modifycode, rhs)
{
tree inner_lhs = TREE_OPERAND (lhs, 0);
tree result;
- if (! lvalue_p (lhs) && pedantic)
- pedwarn ("cast to non-reference type used as lvalue");
+
+ /* WP 5.4.1: The result is an lvalue if T is a reference type,
+ otherwise the result is an rvalue. */
+ if (! lvalue_p (lhs))
+ pedwarn ("ANSI C++ forbids cast to non-reference type used as lvalue");
result = build_modify_expr (inner_lhs, NOP_EXPR,
- convert (TREE_TYPE (inner_lhs),
- convert (lhstype, newrhs)));
- if (TREE_CODE (result) == ERROR_MARK)
+ cp_convert (TREE_TYPE (inner_lhs),
+ cp_convert (lhstype, newrhs)));
+ if (result == error_mark_node)
return result;
- return convert (TREE_TYPE (lhs), result);
+ return cp_convert (TREE_TYPE (lhs), result);
}
+
+ default:
+ break;
}
/* Now we have handled acceptable kinds of LHS that are not truly lvalues.
@@ -5907,7 +6053,7 @@ build_modify_expr (lhs, modifycode, rhs)
}
/* check to see if there is an assignment to `this' */
- if (lhs == current_class_decl)
+ if (lhs == current_class_ptr)
{
if (flag_this_is_variable > 0
&& DECL_NAME (current_function_decl) != NULL_TREE
@@ -5959,104 +6105,6 @@ build_modify_expr (lhs, modifycode, rhs)
if (TREE_SIDE_EFFECTS (newrhs))
newrhs = stabilize_reference (newrhs);
-#if 0
- /* This is now done by generating X(X&) and operator=(X&). */
- /* C++: The semantics of C++ differ from those of C when an
- assignment of an aggregate is desired. Assignment in C++ is
- now defined as memberwise assignment of non-static members
- and base class objects. This rule applies recursively
- until a member of a built-in type is found.
-
- Also, we cannot do a bit-wise copy of aggregates which
- contain virtual function table pointers. Those
- pointer values must be preserved through the copy.
- However, this is handled in expand_expr, and not here.
- This is because much better code can be generated at
- that stage than this one. */
- if (TREE_CODE (lhstype) == RECORD_TYPE
- && ! TYPE_PTRMEMFUNC_P (lhstype)
- && (TYPE_MAIN_VARIANT (lhstype) == TYPE_MAIN_VARIANT (TREE_TYPE (newrhs))
- || (TREE_CODE (TREE_TYPE (newrhs)) == RECORD_TYPE
- && UNIQUELY_DERIVED_FROM_P (lhstype, TREE_TYPE (newrhs)))))
- {
- tree vbases = CLASSTYPE_VBASECLASSES (lhstype);
- tree lhs_addr = build_unary_op (ADDR_EXPR, lhs, 0);
- tree rhs_addr;
-
- /* Memberwise assignment would cause NEWRHS to be
- evaluated for every member that gets assigned.
- By wrapping side-effecting exprs in a SAVE_EXPR,
- NEWRHS will only be evaluated once. */
- if (IS_AGGR_TYPE (TREE_TYPE (newrhs))
- && TREE_SIDE_EFFECTS (newrhs)
- /* This are things we don't have to save. */
- && TREE_CODE (newrhs) != COND_EXPR
- && TREE_CODE (newrhs) != TARGET_EXPR
- && TREE_CODE (newrhs) != WITH_CLEANUP_EXPR)
- /* Call `break_out_cleanups' on NEWRHS in case there are cleanups.
- If NEWRHS is a CALL_EXPR that needs a cleanup, failure to do so
- will result in expand_expr expanding the call without knowing
- that it should run the cleanup. */
- newrhs = save_expr (break_out_cleanups (newrhs));
-
- if (TREE_CODE (newrhs) == COND_EXPR)
- rhs_addr = rationalize_conditional_expr (ADDR_EXPR, newrhs);
- else
- rhs_addr = build_unary_op (ADDR_EXPR, newrhs, 0);
-
- result = tree_cons (NULL_TREE,
- convert (build_reference_type (lhstype), lhs),
- NULL_TREE);
-
- if (! comptypes (TREE_TYPE (lhs_addr), TREE_TYPE (rhs_addr), 1))
- rhs_addr = convert_pointer_to (TREE_TYPE (TREE_TYPE (lhs_addr)), rhs_addr);
- {
- tree noncopied_parts = NULL_TREE;
-
- if (TYPE_NONCOPIED_PARTS (lhstype) != 0)
- noncopied_parts = init_noncopied_parts (lhs,
- TYPE_NONCOPIED_PARTS (lhstype));
- while (noncopied_parts != 0)
- {
- result = tree_cons (NULL_TREE,
- build_modify_expr (convert (ptr_type_node, TREE_VALUE (noncopied_parts)),
- NOP_EXPR,
- TREE_PURPOSE (noncopied_parts)),
- result);
- noncopied_parts = TREE_CHAIN (noncopied_parts);
- }
- }
- /* Once we have our hands on an address, we must change NEWRHS
- to work from there. Otherwise we can get multiple evaluations
- of NEWRHS. */
- if (TREE_CODE (newrhs) != SAVE_EXPR)
- newrhs = build_indirect_ref (rhs_addr, NULL_PTR);
-
- while (vbases)
- {
- tree elt_lhs = convert_pointer_to (vbases, lhs_addr);
- tree elt_rhs = convert_pointer_to (vbases, rhs_addr);
- result
- = tree_cons (NULL_TREE,
- build_modify_expr_1 (build_indirect_ref (elt_lhs, NULL_PTR),
- modifycode,
- build_indirect_ref (elt_rhs, NULL_PTR),
- TYPE_BINFO (lhstype)),
- result);
- if (TREE_VALUE (result) == error_mark_node)
- return error_mark_node;
- vbases = TREE_CHAIN (vbases);
- }
- result = tree_cons (NULL_TREE,
- build_modify_expr_1 (lhs,
- modifycode,
- newrhs,
- TYPE_BINFO (lhstype)),
- result);
- return build_compound_expr (result);
- }
-#endif
-
/* Convert new value to destination type. */
if (TREE_CODE (lhstype) == ARRAY_TYPE)
@@ -6115,16 +6163,7 @@ build_modify_expr (lhs, modifycode, rhs)
}
else
{
-#if 0
- if (IS_AGGR_TYPE (lhstype))
- {
- if (result = build_opfncall (MODIFY_EXPR,
- LOOKUP_NORMAL, lhs, newrhs,
- make_node (NOP_EXPR)))
- return result;
- }
-#endif
- /* Avoid warnings on enum bit fields. */
+ /* Avoid warnings on enum bit fields. */
if (TREE_CODE (olhstype) == ENUMERAL_TYPE
&& TREE_CODE (lhstype) == INTEGER_TYPE)
{
@@ -6137,17 +6176,18 @@ build_modify_expr (lhs, modifycode, rhs)
NULL_TREE, 0);
if (TREE_CODE (newrhs) == CALL_EXPR
&& TYPE_NEEDS_CONSTRUCTING (lhstype))
- newrhs = build_cplus_new (lhstype, newrhs, 0);
+ newrhs = build_cplus_new (lhstype, newrhs);
/* Can't initialize directly from a TARGET_EXPR, since that would
cause the lhs to be constructed twice, and possibly result in
accidental self-initialization. So we force the TARGET_EXPR to be
- expanded. expand_expr should really do this by itself. */
+ expanded without a target. */
if (TREE_CODE (newrhs) == TARGET_EXPR)
- newrhs = expand_target_expr (newrhs);
+ newrhs = build (COMPOUND_EXPR, TREE_TYPE (newrhs), newrhs,
+ TREE_OPERAND (newrhs, 0));
}
- if (TREE_CODE (newrhs) == ERROR_MARK)
+ if (newrhs == error_mark_node)
return error_mark_node;
if (TREE_CODE (newrhs) == COND_EXPR)
@@ -6158,7 +6198,7 @@ build_modify_expr (lhs, modifycode, rhs)
if (TREE_SIDE_EFFECTS (lhs))
cond = build_compound_expr (tree_cons
(NULL_TREE, lhs,
- build_tree_list (NULL_TREE, cond)));
+ build_expr_list (NULL_TREE, cond)));
/* Cannot have two identical lhs on this one tree (result) as preexpand
calls will rip them out and fill in RTL for them, but when the
@@ -6178,45 +6218,17 @@ build_modify_expr (lhs, modifycode, rhs)
result
= build (COND_EXPR, result_type, cond,
build_modify_expr (lhs, modifycode,
- convert (result_type,
- TREE_OPERAND (newrhs, 1))),
+ cp_convert (result_type,
+ TREE_OPERAND (newrhs, 1))),
build_modify_expr (lhs1, modifycode,
- convert (result_type,
- TREE_OPERAND (newrhs, 2))));
+ cp_convert (result_type,
+ TREE_OPERAND (newrhs, 2))));
}
}
- else if (modifycode != INIT_EXPR && TREE_CODE (newrhs) == WITH_CLEANUP_EXPR)
- {
- tree cleanup = TREE_OPERAND (newrhs, 2);
- tree slot;
-
- /* Finish up by running cleanups and having the "value" of the lhs. */
- tree exprlist = tree_cons (NULL_TREE, cleanup,
- build_tree_list (NULL_TREE, lhs));
- newrhs = TREE_OPERAND (newrhs, 0);
- if (TREE_CODE (newrhs) == TARGET_EXPR)
- slot = TREE_OPERAND (newrhs, 0);
- else if (TREE_CODE (newrhs) == ADDR_EXPR)
- {
- /* Bad but valid. */
- slot = newrhs;
- warning ("address taken of temporary object");
- }
- else
- my_friendly_abort (118);
-
- /* Copy the value computed in SLOT into LHS. */
- exprlist = tree_cons (NULL_TREE,
- build_modify_expr (lhs, modifycode, slot),
- exprlist);
- /* Evaluate the expression that needs CLEANUP. This will
- compute the value into SLOT. */
- exprlist = tree_cons (NULL_TREE, newrhs, exprlist);
- result = convert (lhstype, build_compound_expr (exprlist));
- }
else
result = build (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
lhstype, lhs, newrhs);
+
TREE_SIDE_EFFECTS (result) = 1;
/* If we got the LHS in a different type for storing in,
@@ -6227,7 +6239,7 @@ build_modify_expr (lhs, modifycode, rhs)
if (olhstype == TREE_TYPE (result))
return result;
/* Avoid warnings converting integral types back into enums
- for enum bit fields. */
+ for enum bit fields. */
if (TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
&& TREE_CODE (olhstype) == ENUMERAL_TYPE)
{
@@ -6239,13 +6251,32 @@ build_modify_expr (lhs, modifycode, rhs)
NULL_TREE, 0);
}
+tree
+build_x_modify_expr (lhs, modifycode, rhs)
+ tree lhs;
+ enum tree_code modifycode;
+ tree rhs;
+{
+ if (processing_template_decl)
+ return build_min_nt (MODOP_EXPR, lhs,
+ build_min_nt (modifycode, NULL_TREE, NULL_TREE), rhs);
+
+ if (modifycode != NOP_EXPR)
+ {
+ tree rval = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL, lhs, rhs,
+ make_node (modifycode));
+ if (rval)
+ return rval;
+ }
+ return build_modify_expr (lhs, modifycode, rhs);
+}
/* Return 0 if EXP is not a valid lvalue in this language
even though `lvalue_or_else' would accept it. */
int
language_lvalue_valid (exp)
- tree exp;
+ tree exp ATTRIBUTE_UNUSED;
{
return 1;
}
@@ -6253,6 +6284,7 @@ language_lvalue_valid (exp)
/* Get difference in deltas for different pointer to member function
types. Return integer_zero_node, if FROM cannot be converted to a
TO type. If FORCE is true, then allow reverse conversions as well. */
+
static tree
get_delta_difference (from, to, force)
tree from, to;
@@ -6280,35 +6312,117 @@ get_delta_difference (from, to, force)
if (!force)
{
error_not_base_type (from, to);
- error (" in pointer to member function conversion");
+ error (" in pointer to member conversion");
return delta;
}
binfo = get_binfo (to, from, 1);
- if (binfo == error_mark_node)
- {
- error (" in pointer to member function conversion");
- return delta;
- }
- if (binfo == 0)
- {
- error ("cannot convert pointer to member of type %T to unrelated pointer to member of type %T", from, to);
- return delta;
- }
+ if (binfo == 0 || binfo == error_mark_node)
+ return delta;
if (TREE_VIA_VIRTUAL (binfo))
{
- warning ("pointer to member conversion to virtual base class will only work if you are very careful");
+ binfo = binfo_member (BINFO_TYPE (binfo),
+ CLASSTYPE_VBASECLASSES (from));
+ cp_warning ("pointer to member cast to virtual base `%T'",
+ BINFO_TYPE (binfo));
+ warning (" will only work if you are very careful");
}
+ delta = BINFO_OFFSET (binfo);
+ delta = cp_convert (ptrdiff_type_node, delta);
+
return build_binary_op (MINUS_EXPR,
integer_zero_node,
- BINFO_OFFSET (binfo), 1);
+ delta, 1);
}
+
if (TREE_VIA_VIRTUAL (binfo))
{
- warning ("pointer to member conversion from virtual base class will only work if you are very careful");
+ if (force)
+ {
+ cp_warning ("pointer to member cast from virtual base `%T'",
+ BINFO_TYPE (binfo));
+ warning (" will only work if you are very careful");
+ }
+ else
+ cp_error ("pointer to member conversion from virtual base `%T'",
+ BINFO_TYPE (binfo));
}
+
return BINFO_OFFSET (binfo);
}
+static tree
+build_ptrmemfunc1 (type, delta, idx, pfn, delta2)
+ tree type, delta, idx, pfn, delta2;
+{
+ tree u;
+
+#if 0
+ /* This is the old way we did it. We want to avoid calling
+ digest_init, so that it can give an error if we use { } when
+ initializing a pointer to member function. */
+
+ if (pfn)
+ {
+ u = build_nt (CONSTRUCTOR, NULL_TREE,
+ expr_tree_cons (pfn_identifier, pfn, NULL_TREE));
+ }
+ else
+ {
+ u = build_nt (CONSTRUCTOR, NULL_TREE,
+ expr_tree_cons (delta2_identifier, delta2, NULL_TREE));
+ }
+
+ u = build_nt (CONSTRUCTOR, NULL_TREE,
+ expr_tree_cons (NULL_TREE, delta,
+ expr_tree_cons (NULL_TREE, idx,
+ expr_tree_cons (NULL_TREE, u, NULL_TREE))));
+
+ return digest_init (type, u, (tree*)0);
+#else
+ tree delta_field, idx_field, pfn_or_delta2_field, pfn_field, delta2_field;
+ tree subtype;
+ int allconstant, allsimple;
+
+ delta_field = TYPE_FIELDS (type);
+ idx_field = TREE_CHAIN (delta_field);
+ pfn_or_delta2_field = TREE_CHAIN (idx_field);
+ subtype = TREE_TYPE (pfn_or_delta2_field);
+ pfn_field = TYPE_FIELDS (subtype);
+ delta2_field = TREE_CHAIN (pfn_field);
+
+ if (pfn)
+ {
+ allconstant = TREE_CONSTANT (pfn);
+ allsimple = !! initializer_constant_valid_p (pfn, TREE_TYPE (pfn));
+ u = expr_tree_cons (pfn_field, pfn, NULL_TREE);
+ }
+ else
+ {
+ delta2 = convert_and_check (delta_type_node, delta2);
+ allconstant = TREE_CONSTANT (delta2);
+ allsimple = !! initializer_constant_valid_p (delta2, TREE_TYPE (delta2));
+ u = expr_tree_cons (delta2_field, delta2, NULL_TREE);
+ }
+
+ delta = convert_and_check (delta_type_node, delta);
+ idx = convert_and_check (delta_type_node, idx);
+
+ allconstant = allconstant && TREE_CONSTANT (delta) && TREE_CONSTANT (idx);
+ allsimple = allsimple
+ && initializer_constant_valid_p (delta, TREE_TYPE (delta))
+ && initializer_constant_valid_p (idx, TREE_TYPE (idx));
+
+ u = build (CONSTRUCTOR, subtype, NULL_TREE, u);
+ u = expr_tree_cons (delta_field, delta,
+ expr_tree_cons (idx_field, idx,
+ expr_tree_cons (pfn_or_delta2_field, u, NULL_TREE)));
+ u = build (CONSTRUCTOR, type, NULL_TREE, u);
+ TREE_CONSTANT (u) = allconstant;
+ TREE_STATIC (u) = allconstant && allsimple;
+ return u;
+#endif
+}
+
/* Build a constructor for a pointer to member function. It can be
used to initialize global variables, local variable, or used
as a value in expressions. TYPE is the POINTER to METHOD_TYPE we
@@ -6325,119 +6439,71 @@ build_ptrmemfunc (type, pfn, force)
tree type, pfn;
int force;
{
- tree index = integer_zero_node;
+ tree idx = integer_zero_node;
tree delta = integer_zero_node;
tree delta2 = integer_zero_node;
tree vfield_offset;
- tree npfn;
- tree u;
+ tree npfn = NULL_TREE;
- /* Handle multiple conversions of pointer to member functions. */
+ /* Handle multiple conversions of pointer to member functions. */
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (pfn)))
{
- tree ndelta, ndelta2, nindex;
+ tree ndelta, ndelta2;
+ tree e1, e2, e3, n;
+ tree pfn_type;
+
/* Is is already the right type? */
-#if 0
- /* Sorry, can't do this, the backend is too stupid. */
- if (TYPE_METHOD_BASETYPE (TREE_TYPE (type))
- == TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))))
- {
- if (type != TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
- {
- npfn = build1 (NOP_EXPR, TYPE_GET_PTRMEMFUNC_TYPE (type), pfn);
- TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
- }
- return pfn;
- }
-#else
if (type == TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))
return pfn;
-#endif
- if (TREE_CODE (pfn) != CONSTRUCTOR)
- {
- tree e1, e2, e3;
- ndelta = convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, 0, 0));
- ndelta2 = convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
- index = build_component_ref (pfn, index_identifier, 0, 0);
- delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
- TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
- force);
- delta = build_binary_op (PLUS_EXPR, delta, ndelta, 1);
- delta2 = build_binary_op (PLUS_EXPR, ndelta2, delta2, 1);
- e1 = fold (build (GT_EXPR, boolean_type_node, index, integer_zero_node));
+ pfn_type = TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn));
+ if (!force
+ && comp_target_types (type, pfn_type, 0) != 1)
+ cp_error ("conversion to `%T' from `%T'", type, pfn_type);
+
+ ndelta = cp_convert (ptrdiff_type_node, build_component_ref (pfn, delta_identifier, NULL_TREE, 0));
+ ndelta2 = cp_convert (ptrdiff_type_node, DELTA2_FROM_PTRMEMFUNC (pfn));
+ idx = build_component_ref (pfn, index_identifier, NULL_TREE, 0);
+
+ n = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (pfn_type)),
+ TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
+ force);
+
+ delta = build_binary_op (PLUS_EXPR, ndelta, n, 1);
+ delta2 = build_binary_op (PLUS_EXPR, ndelta2, n, 1);
+ e1 = fold (build (GT_EXPR, boolean_type_node, idx, integer_zero_node));
- u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
- u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, index,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- e2 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+ e2 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx,
+ NULL_TREE, delta2);
- pfn = PFN_FROM_PTRMEMFUNC (pfn);
- npfn = build1 (NOP_EXPR, type, pfn);
- TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+ pfn = PFN_FROM_PTRMEMFUNC (pfn);
+ npfn = build1 (NOP_EXPR, type, pfn);
+ TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
- u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
- u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, index,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- e3 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
- return build_conditional_expr (e1, e2, e3);
- }
-
- ndelta = TREE_VALUE (CONSTRUCTOR_ELTS (pfn));
- nindex = TREE_VALUE (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn)));
- npfn = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (CONSTRUCTOR_ELTS (pfn))));
- npfn = TREE_VALUE (CONSTRUCTOR_ELTS (npfn));
- if (integer_zerop (nindex))
- pfn = integer_zero_node;
- else if (integer_zerop (fold (size_binop (PLUS_EXPR, nindex, integer_one_node))))
- {
- tree e3;
- delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (pfn)))),
- TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
- force);
- delta = build_binary_op (PLUS_EXPR, delta, ndelta, 1);
- pfn = build1 (NOP_EXPR, type, npfn);
- TREE_CONSTANT (pfn) = TREE_CONSTANT (npfn);
-
- u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, pfn, NULL_TREE));
- u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, nindex,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- e3 = digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
- return e3;
- }
- else
- {
- sorry ("value casting of variable nonnull pointer to member functions not supported");
- return error_mark_node;
- }
+ e3 = build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn,
+ NULL_TREE);
+ return build_conditional_expr (e1, e2, e3);
}
- /* Handle null pointer to member function conversions. */
+ /* Handle null pointer to member function conversions. */
if (integer_zerop (pfn))
{
- pfn = build_c_cast (type, integer_zero_node, 0);
- u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, pfn, NULL_TREE));
- u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, integer_zero_node,
- tree_cons (NULL_TREE, integer_zero_node,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+ pfn = build_c_cast (type, integer_zero_node);
+ return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type),
+ integer_zero_node, integer_zero_node,
+ pfn, NULL_TREE);
}
if (TREE_CODE (pfn) == TREE_LIST
|| (TREE_CODE (pfn) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (pfn, 0)) == TREE_LIST))
- {
- pfn = instantiate_type (type, pfn, 1);
- if (pfn == error_mark_node)
- return error_mark_node;
- if (TREE_CODE (pfn) != ADDR_EXPR)
- pfn = build_unary_op (ADDR_EXPR, pfn, 0);
- }
+ return instantiate_type (type, pfn, 1);
+
+ if (!force
+ && comp_target_types (type, TREE_TYPE (pfn), 0) != 1)
+ cp_error ("conversion to `%T' from `%T'", type, TREE_TYPE (pfn));
- /* Allow pointer to member conversions here. */
+ /* Allow pointer to member conversions here. */
delta = get_delta_difference (TYPE_METHOD_BASETYPE (TREE_TYPE (TREE_TYPE (pfn))),
TYPE_METHOD_BASETYPE (TREE_TYPE (type)),
force);
@@ -6449,7 +6515,7 @@ build_ptrmemfunc (type, pfn, force)
if (TREE_CODE (TREE_OPERAND (pfn, 0)) == FUNCTION_DECL
&& DECL_VINDEX (TREE_OPERAND (pfn, 0)))
{
- /* Find the offset to the vfield pointer in the object. */
+ /* Find the offset to the vfield pointer in the object. */
vfield_offset = get_binfo (DECL_CONTEXT (TREE_OPERAND (pfn, 0)),
DECL_CLASS_CONTEXT (TREE_OPERAND (pfn, 0)),
0);
@@ -6457,25 +6523,26 @@ build_ptrmemfunc (type, pfn, force)
delta2 = size_binop (PLUS_EXPR, vfield_offset, delta2);
/* Map everything down one to make room for the null pointer to member. */
- index = size_binop (PLUS_EXPR,
- DECL_VINDEX (TREE_OPERAND (pfn, 0)),
- integer_one_node);
- u = build_nt (CONSTRUCTOR, 0, tree_cons (delta2_identifier, delta2, NULL_TREE));
+ idx = size_binop (PLUS_EXPR,
+ DECL_VINDEX (TREE_OPERAND (pfn, 0)),
+ integer_one_node);
}
else
{
- index = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
-
- npfn = build1 (NOP_EXPR, type, pfn);
- TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+ idx = size_binop (MINUS_EXPR, integer_zero_node, integer_one_node);
- u = build_nt (CONSTRUCTOR, 0, tree_cons (pfn_identifier, npfn, NULL_TREE));
+ if (type == TREE_TYPE (pfn))
+ {
+ npfn = pfn;
+ }
+ else
+ {
+ npfn = build1 (NOP_EXPR, type, pfn);
+ TREE_CONSTANT (npfn) = TREE_CONSTANT (pfn);
+ }
}
- u = build_nt (CONSTRUCTOR, 0, tree_cons (NULL_TREE, delta,
- tree_cons (NULL_TREE, index,
- tree_cons (NULL_TREE, u, NULL_TREE))));
- return digest_init (TYPE_GET_PTRMEMFUNC_TYPE (type), u, (tree*)0);
+ return build_ptrmemfunc1 (TYPE_GET_PTRMEMFUNC_TYPE (type), delta, idx, npfn, delta2);
}
/* Convert value RHS to type TYPE as preparation for an assignment
@@ -6521,7 +6588,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
if (rhs == error_mark_node)
return error_mark_node;
- if (TREE_VALUE (rhs) == error_mark_node)
+ if (TREE_CODE (rhs) == TREE_LIST && TREE_VALUE (rhs) == error_mark_node)
return error_mark_node;
if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
@@ -6549,7 +6616,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
else if (TREE_READONLY_DECL_P (rhs))
rhs = decl_constant_value (rhs);
- if (type == rhstype)
+ if (comptypes (type, rhstype, 1))
{
overflow_warning (rhs);
return rhs;
@@ -6561,8 +6628,10 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
return error_mark_node;
}
/* Arithmetic types all interconvert. */
- if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE)
- && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE))
+ if ((codel == INTEGER_TYPE || codel == REAL_TYPE || codel == BOOLEAN_TYPE
+ || codel == COMPLEX_TYPE)
+ && (coder == INTEGER_TYPE || coder == REAL_TYPE || coder == BOOLEAN_TYPE
+ || coder == COMPLEX_TYPE))
{
/* But we should warn if assigning REAL_TYPE to INTEGER_TYPE. */
if (coder == REAL_TYPE && codel == INTEGER_TYPE)
@@ -6600,7 +6669,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
|| (coder == ENUMERAL_TYPE
&& (INTEGRAL_CODE_P (codel) || codel == REAL_TYPE)))
{
- return cp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
+ return ocp_convert (type, rhs, CONV_IMPLICIT, LOOKUP_NORMAL);
}
/* Conversions among pointers */
else if (codel == POINTER_TYPE
@@ -6676,13 +6745,13 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
return error_mark_node;
}
- if (ctt < 0)
+ if (ctt < 0 && TYPE_MAIN_VARIANT (ttl) != TYPE_MAIN_VARIANT (ttr))
cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
rhstype, type);
if (TYPE_MAIN_VARIANT (ttl) != void_type_node
&& TYPE_MAIN_VARIANT (ttr) == void_type_node
- && rhs != null_pointer_node)
+ && ! null_ptr_cst_p (rhs))
{
if (coder == RECORD_TYPE)
cp_pedwarn ("implicit conversion of signature pointer to type `%T'",
@@ -6733,31 +6802,6 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
}
}
}
- else if (TREE_CODE (ttr) == OFFSET_TYPE
- && TREE_CODE (ttl) != OFFSET_TYPE)
- {
- /* Normally, pointers to different type codes (other
- than void) are not compatible, but we perform
- some type instantiation if that resolves the
- ambiguity of (X Y::*) and (X *). */
-
- if (current_class_decl)
- {
- if (TREE_CODE (rhs) == INTEGER_CST)
- {
- rhs = build (PLUS_EXPR, build_pointer_type (TREE_TYPE (ttr)),
- current_class_decl, rhs);
- return convert_for_assignment (type, rhs,
- errtype, fndecl, parmnum);
- }
- }
- if (TREE_CODE (ttl) == METHOD_TYPE)
- error ("%s between pointer-to-method and pointer-to-member types",
- errtype);
- else
- error ("%s between pointer and pointer-to-member types", errtype);
- return error_mark_node;
- }
else
{
int add_quals = 0, const_parity = 0, volatile_parity = 0;
@@ -6769,8 +6813,8 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
for (; ; ttl = TREE_TYPE (ttl), ttr = TREE_TYPE (ttr))
{
nptrs -= 1;
- const_parity |= TYPE_READONLY (ttl) < TYPE_READONLY (ttr);
- volatile_parity |= TYPE_VOLATILE (ttl) < TYPE_VOLATILE (ttr);
+ const_parity |= (TYPE_READONLY (ttl) < TYPE_READONLY (ttr));
+ volatile_parity |= (TYPE_VOLATILE (ttl) < TYPE_VOLATILE (ttr));
if (! left_const
&& (TYPE_READONLY (ttl) > TYPE_READONLY (ttr)
@@ -6849,24 +6893,6 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
cp_warning ("\t`%T' != `%T'", type, rhstype);
}
}
- else if (TREE_CODE (TREE_TYPE (rhs)) == METHOD_TYPE)
- {
- /* When does this happen? */
- my_friendly_abort (119);
- /* Conversion of a pointer-to-member type to void *. */
- rhs = build_unary_op (ADDR_EXPR, rhs, 0);
- TREE_TYPE (rhs) = type;
- return rhs;
- }
- else if (TREE_CODE (TREE_TYPE (rhs)) == OFFSET_TYPE)
- {
- /* When does this happen? */
- my_friendly_abort (120);
- /* Conversion of a pointer-to-member type to void *. */
- rhs = build_unary_op (ADDR_EXPR, rhs, 0);
- TREE_TYPE (rhs) = type;
- return rhs;
- }
else
{
if (fndecl)
@@ -6877,7 +6903,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
return error_mark_node;
}
}
- return convert (type, rhs);
+ return cp_convert (type, rhs);
}
else if (codel == POINTER_TYPE && coder == INTEGER_TYPE)
{
@@ -6891,9 +6917,8 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
else
cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
errtype, type, rhstype);
- return convert (type, rhs);
}
- return null_pointer_node;
+ return cp_convert (type, rhs);
}
else if (codel == INTEGER_TYPE
&& (coder == POINTER_TYPE
@@ -6908,7 +6933,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
else
cp_pedwarn ("%s to `%T' from `%T' lacks a cast",
errtype, type, rhstype);
- return convert (type, rhs);
+ return cp_convert (type, rhs);
}
else if (codel == BOOLEAN_TYPE
&& (coder == POINTER_TYPE
@@ -6916,7 +6941,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
&& (IS_SIGNATURE_POINTER (rhstype)
|| TYPE_PTRMEMFUNC_FLAG (rhstype)
|| IS_SIGNATURE_REFERENCE (rhstype)))))
- return convert (type, rhs);
+ return cp_convert (type, rhs);
/* C++ */
else if (((coder == POINTER_TYPE
@@ -6926,9 +6951,11 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
&& TYPE_PTRMEMFUNC_P (type))
{
tree ttl = TYPE_PTRMEMFUNC_FN_TYPE (type);
- tree ttr = (TREE_CODE (rhstype) == POINTER_TYPE ? rhstype
- : TYPE_PTRMEMFUNC_FN_TYPE (type));
- int ctt = comp_target_types (ttl, ttr, 1);
+ tree ttr = (TYPE_PTRMEMFUNC_P (rhstype)
+ ? TYPE_PTRMEMFUNC_FN_TYPE (rhstype)
+ : rhstype);
+ int ctt = (TREE_CODE (rhstype) == INTEGER_TYPE ? 1
+ : comp_target_types (ttl, ttr, 1));
if (ctt < 0)
cp_pedwarn ("converting `%T' to `%T' is a contravariance violation",
@@ -6936,7 +6963,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
else if (ctt == 0)
cp_error ("%s to `%T' from `%T'", errtype, ttl, ttr);
- /* compatible pointer to member functions. */
+ /* compatible pointer to member functions. */
return build_ptrmemfunc (ttl, rhs, 0);
}
else if (codel == ERROR_MARK || coder == ERROR_MARK)
@@ -6954,7 +6981,14 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
return nrhs;
}
else if (TYPE_HAS_CONSTRUCTOR (type) || IS_AGGR_TYPE (TREE_TYPE (rhs)))
- return convert (type, rhs);
+ return cp_convert (type, rhs);
+ /* Handle anachronistic conversions from (::*)() to cv void* or (*)(). */
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+ || TYPE_MAIN_VARIANT (TREE_TYPE (type)) == void_type_node)
+ && TREE_TYPE (rhs)
+ && TYPE_PTRMEMFUNC_P (TREE_TYPE (rhs)))
+ return cp_convert (type, rhs);
cp_error ("%s to `%T' from `%T'", errtype, type, rhstype);
return error_mark_node;
@@ -6975,6 +7009,7 @@ convert_for_assignment (type, rhs, errtype, fndecl, parmnum)
exist, an ambiguity exists.
If flags doesn't include LOOKUP_COMPLAIN, don't complain about anything. */
+
tree
convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
tree exp, type, rhs;
@@ -7029,12 +7064,6 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
if (coder == ERROR_MARK)
return error_mark_node;
-#if 0
- /* This is *not* the quick way out! It is the way to disaster. */
- if (type == rhstype)
- goto converted;
-#endif
-
/* We accept references to incomplete types, so we can
return here before checking if RHS is of complete type. */
@@ -7042,7 +7071,7 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
{
/* This should eventually happen in convert_arguments. */
extern int warningcount, errorcount;
- int savew, savee;
+ int savew = 0, savee = 0;
if (fndecl)
savew = warningcount, savee = errorcount;
@@ -7069,84 +7098,14 @@ convert_for_initialization (exp, type, rhs, flags, errtype, fndecl, parmnum)
if (TREE_CODE (rhstype) == REFERENCE_TYPE)
rhstype = TREE_TYPE (rhstype);
+ type = complete_type (type);
+
if (TYPE_LANG_SPECIFIC (type)
&& (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type)))
return build_signature_pointer_constructor (type, rhs);
- if (IS_AGGR_TYPE (type)
- && (TYPE_NEEDS_CONSTRUCTING (type) || TREE_HAS_CONSTRUCTOR (rhs)))
- {
- if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype))
- {
- /* This is sufficient to perform initialization. No need,
- apparently, to go through X(X&) to do first-cut
- initialization. Return through a TARGET_EXPR so that we get
- cleanups if it is used. */
- if (TREE_CODE (rhs) == CALL_EXPR)
- {
- rhs = build_cplus_new (type, rhs, 0);
- return rhs;
- }
- /* Handle the case of default parameter initialization and
- initialization of static variables. */
- else if (TREE_CODE (rhs) == TARGET_EXPR)
- return rhs;
- else if (TREE_CODE (rhs) == INDIRECT_REF && TREE_HAS_CONSTRUCTOR (rhs))
- {
- my_friendly_assert (TREE_CODE (TREE_OPERAND (rhs, 0)) == CALL_EXPR, 318);
- if (exp)
- {
- my_friendly_assert (TREE_VALUE (TREE_OPERAND (TREE_OPERAND (rhs, 0), 1)) == NULL_TREE, 316);
- TREE_VALUE (TREE_OPERAND (TREE_OPERAND (rhs, 0), 1))
- = build_unary_op (ADDR_EXPR, exp, 0);
- }
- else
- rhs = build_cplus_new (type, TREE_OPERAND (rhs, 0), 0);
- return rhs;
- }
- else if (TYPE_HAS_TRIVIAL_INIT_REF (type))
- return rhs;
- }
- if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (rhstype)
- || (IS_AGGR_TYPE (rhstype) && UNIQUELY_DERIVED_FROM_P (type, rhstype)))
- {
- if (TYPE_HAS_INIT_REF (type))
- {
- tree init = build_method_call (exp, constructor_name_full (type),
- build_tree_list (NULL_TREE, rhs),
- TYPE_BINFO (type), LOOKUP_NORMAL);
-
- if (init == error_mark_node)
- return error_mark_node;
-
- if (exp == 0)
- {
- exp = build_cplus_new (type, init, 0);
- return exp;
- }
-
- return build (COMPOUND_EXPR, type, init, exp);
- }
-
- /* ??? The following warnings are turned off because
- this is another place where the default X(X&) constructor
- is implemented. */
- if (TYPE_HAS_ASSIGNMENT (type))
- cp_warning ("bitwise copy: `%T' defines operator=", type);
-
- if (TREE_CODE (TREE_TYPE (rhs)) == REFERENCE_TYPE)
- rhs = convert_from_reference (rhs);
- if (type != rhstype)
- {
- tree nrhs = build1 (NOP_EXPR, type, rhs);
- TREE_CONSTANT (nrhs) = TREE_CONSTANT (rhs);
- rhs = nrhs;
- }
- return rhs;
- }
-
- return cp_convert (type, rhs, CONV_OLD_CONVERT, flags);
- }
+ if (IS_AGGR_TYPE (type))
+ return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
if (type == TREE_TYPE (rhs))
{
@@ -7195,7 +7154,7 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
if (o[i] != TREE_VALUE (tail))
{
expand_expr (build_modify_expr (o[i], NOP_EXPR, TREE_VALUE (tail)),
- const0_rtx, VOIDmode, 0);
+ const0_rtx, VOIDmode, EXPAND_NORMAL);
free_temp_slots ();
}
/* Detect modification of read-only values.
@@ -7234,8 +7193,6 @@ c_expand_return (retval)
extern tree dtor_label, ctor_label;
tree result = DECL_RESULT (current_function_decl);
tree valtype = TREE_TYPE (result);
- register int use_temp = 0;
- int returns_value = 1;
if (TREE_THIS_VOLATILE (current_function_decl))
warning ("function declared `noreturn' has a `return' statement");
@@ -7246,19 +7203,28 @@ c_expand_return (retval)
return;
}
- if (retval == NULL_TREE)
+ if (processing_template_decl)
{
- /* A non-named return value does not count. */
+ add_tree (build_min_nt (RETURN_STMT, retval));
+ return;
+ }
+
+ if (dtor_label)
+ {
+ if (retval)
+ error ("returning a value from a destructor");
/* Can't just return from a destructor. */
- if (dtor_label)
- {
- expand_goto (dtor_label);
- return;
- }
+ expand_goto (dtor_label);
+ return;
+ }
+
+ if (retval == NULL_TREE)
+ {
+ /* A non-named return value does not count. */
if (DECL_CONSTRUCTOR_P (current_function_decl))
- retval = current_class_decl;
+ retval = current_class_ptr;
else if (DECL_NAME (result) != NULL_TREE
&& TREE_CODE (valtype) != VOID_TYPE)
retval = result;
@@ -7282,83 +7248,28 @@ c_expand_return (retval)
return;
}
}
- else if (DECL_CONSTRUCTOR_P (current_function_decl)
- && retval != current_class_decl)
+ else if (DECL_CONSTRUCTOR_P (current_function_decl))
{
- error ("return from a constructor: use `this = ...' instead");
- retval = current_class_decl;
+ if (flag_this_is_variable)
+ error ("return from a constructor: use `this = ...' instead");
+ else
+ error ("returning a value from a constructor");
+ retval = current_class_ptr;
}
+ /* Effective C++ rule 15. See also start_function. */
+ if (warn_ecpp
+ && DECL_NAME (current_function_decl) == ansi_opname[(int) MODIFY_EXPR]
+ && retval != current_class_ref)
+ cp_warning ("`operator=' should return a reference to `*this'");
+
if (valtype == NULL_TREE || TREE_CODE (valtype) == VOID_TYPE)
{
current_function_returns_null = 1;
- /* We do this here so we'll avoid a warning about how the function
- "may or may not return a value" in finish_function. */
- returns_value = 0;
-
- if (retval)
+ if (TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
pedwarn ("`return' with a value, in function returning void");
expand_return (retval);
- }
- /* Add some useful error checking for C++. */
- else if (TREE_CODE (valtype) == REFERENCE_TYPE)
- {
- tree whats_returned;
- tree tmp_result = result;
-
- /* Don't initialize directly into a non-BLKmode retval, since that
- could lose when being inlined by another caller. (GCC can't
- read the function return register in an inline function when
- the return value is being ignored). */
- if (result && TYPE_MODE (TREE_TYPE (tmp_result)) != BLKmode)
- tmp_result = 0;
-
- /* convert to reference now, so we can give error if we
- return an reference to a non-lvalue. */
- retval = convert_for_initialization (tmp_result, valtype, retval,
- LOOKUP_NORMAL, "return",
- NULL_TREE, 0);
-
- /* Sort through common things to see what it is
- we are returning. */
- whats_returned = retval;
- if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
- {
- whats_returned = TREE_OPERAND (whats_returned, 1);
- if (TREE_CODE (whats_returned) == ADDR_EXPR)
- whats_returned = TREE_OPERAND (whats_returned, 0);
- }
- if (TREE_CODE (whats_returned) == ADDR_EXPR)
- {
- whats_returned = TREE_OPERAND (whats_returned, 0);
- while (TREE_CODE (whats_returned) == NEW_EXPR
- || TREE_CODE (whats_returned) == TARGET_EXPR
- || TREE_CODE (whats_returned) == WITH_CLEANUP_EXPR)
- {
- /* Get the target. */
- whats_returned = TREE_OPERAND (whats_returned, 0);
- warning ("returning reference to temporary");
- }
- }
-
- if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned))
- {
- if (TEMP_NAME_P (DECL_NAME (whats_returned)))
- warning ("reference to non-lvalue returned");
- else if (! TREE_STATIC (whats_returned)
- && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned)))
- cp_warning_at ("reference to local variable `%D' returned", whats_returned);
- }
- }
- else if (TREE_CODE (retval) == ADDR_EXPR)
- {
- tree whats_returned = TREE_OPERAND (retval, 0);
-
- if (TREE_CODE (whats_returned) == VAR_DECL
- && DECL_NAME (whats_returned)
- && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
- && !TREE_STATIC (whats_returned))
- cp_warning_at ("address of local variable `%D' returned", whats_returned);
+ return;
}
/* Now deal with possible C++ hair:
@@ -7369,153 +7280,120 @@ c_expand_return (retval)
(3) If an X(X&) constructor is defined, the return
value must be returned via that. */
- /* If we're returning in a register, we can't initialize the
- return value from a TARGET_EXPR. */
- if (TREE_CODE (retval) == TARGET_EXPR
- && TYPE_MAIN_VARIANT (TREE_TYPE (retval)) == TYPE_MAIN_VARIANT (valtype)
- && ! current_function_returns_struct)
- retval = expand_target_expr (retval);
-
if (retval == result
- /* Watch out for constructors, which "return" aggregates
- via initialization, but which otherwise "return" a pointer. */
|| DECL_CONSTRUCTOR_P (current_function_decl))
+ /* It's already done for us. */;
+ else if (TREE_TYPE (retval) == void_type_node)
{
- /* This is just an error--it's already been reported. */
- if (TYPE_SIZE (valtype) == NULL_TREE)
- return;
-
- if (TYPE_MODE (valtype) != BLKmode
- && any_pending_cleanups (1))
- {
- retval = get_temp_regvar (valtype, retval);
- use_temp = obey_regdecls;
- }
- }
- else if (IS_AGGR_TYPE (valtype) && current_function_returns_struct)
- {
- expand_aggr_init (result, retval, 0, LOOKUP_ONLYCONVERTING);
- expand_cleanups_to (NULL_TREE);
- DECL_INITIAL (result) = NULL_TREE;
+ pedwarn ("return of void value in function returning non-void");
+ expand_expr_stmt (retval);
retval = 0;
}
else
{
- if (TYPE_MODE (valtype) == VOIDmode)
+ tree functype = TREE_TYPE (TREE_TYPE (current_function_decl));
+
+ /* First convert the value to the function's return type, then
+ to the type of return value's location to handle the
+ case that functype is thiner than the valtype. */
+
+ retval = convert_for_initialization
+ (NULL_TREE, functype, retval, LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING,
+ "return", NULL_TREE, 0);
+
+ retval = convert (valtype, retval);
+
+ if (retval == error_mark_node)
{
- if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode
- && warn_return_type)
- warning ("return of void value in function returning non-void");
- expand_expr_stmt (retval);
- retval = 0;
- result = 0;
+ /* Avoid warning about control reaching end of function. */
+ expand_null_return ();
+ return;
}
- else if (TYPE_MODE (valtype) != BLKmode
- && any_pending_cleanups (1))
+
+ /* We can't initialize a register from a AGGR_INIT_EXPR. */
+ else if (! current_function_returns_struct
+ && TREE_CODE (retval) == TARGET_EXPR
+ && TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
+ retval = build (COMPOUND_EXPR, TREE_TYPE (retval), retval,
+ TREE_OPERAND (retval, 0));
+
+ /* Add some useful error checking for C++. */
+ else if (TREE_CODE (valtype) == REFERENCE_TYPE)
{
- retval = get_temp_regvar (valtype, retval);
- expand_cleanups_to (NULL_TREE);
- use_temp = obey_regdecls;
- result = 0;
+ tree whats_returned;
+
+ /* Sort through common things to see what it is
+ we are returning. */
+ whats_returned = retval;
+ if (TREE_CODE (whats_returned) == COMPOUND_EXPR)
+ {
+ whats_returned = TREE_OPERAND (whats_returned, 1);
+ if (TREE_CODE (whats_returned) == ADDR_EXPR)
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ }
+ while (TREE_CODE (whats_returned) == CONVERT_EXPR
+ || TREE_CODE (whats_returned) == NOP_EXPR)
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ if (TREE_CODE (whats_returned) == ADDR_EXPR)
+ {
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ while (TREE_CODE (whats_returned) == AGGR_INIT_EXPR
+ || TREE_CODE (whats_returned) == TARGET_EXPR)
+ {
+ /* Get the target. */
+ whats_returned = TREE_OPERAND (whats_returned, 0);
+ warning ("returning reference to temporary");
+ }
+ }
+
+ if (TREE_CODE (whats_returned) == VAR_DECL && DECL_NAME (whats_returned))
+ {
+ if (TEMP_NAME_P (DECL_NAME (whats_returned)))
+ warning ("reference to non-lvalue returned");
+ else if (TREE_CODE (TREE_TYPE (whats_returned)) != REFERENCE_TYPE
+ && ! TREE_STATIC (whats_returned)
+ && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
+ && !TREE_PUBLIC (whats_returned))
+ cp_warning_at ("reference to local variable `%D' returned", whats_returned);
+ }
}
- else
+ else if (TREE_CODE (retval) == ADDR_EXPR)
{
- retval = convert_for_initialization (result, valtype, retval,
- LOOKUP_NORMAL,
- "return", NULL_TREE, 0);
- DECL_INITIAL (result) = NULL_TREE;
+ tree whats_returned = TREE_OPERAND (retval, 0);
+
+ if (TREE_CODE (whats_returned) == VAR_DECL
+ && DECL_NAME (whats_returned)
+ && IDENTIFIER_LOCAL_VALUE (DECL_NAME (whats_returned))
+ && !TREE_STATIC (whats_returned)
+ && !TREE_PUBLIC (whats_returned))
+ cp_warning_at ("address of local variable `%D' returned", whats_returned);
}
- if (retval == error_mark_node)
- return;
}
- emit_queue ();
-
if (retval != NULL_TREE
&& TREE_CODE_CLASS (TREE_CODE (retval)) == 'd'
&& cond_stack == 0 && loop_stack == 0 && case_stack == 0)
current_function_return_value = retval;
- if (result)
+ if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
{
- /* Everything's great--RETVAL is in RESULT. */
- if (original_result_rtx)
- {
- store_expr (result, original_result_rtx, 0);
- expand_cleanups_to (NULL_TREE);
- use_variable (DECL_RTL (result));
- if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
- expand_goto (ctor_label);
- else
- expand_null_return ();
- }
- else if (retval && retval != result)
- {
- /* Clear this out so the later call to decl_function_context
- won't end up bombing on us. */
- if (DECL_CONTEXT (result) == error_mark_node)
- DECL_CONTEXT (result) = NULL_TREE;
- /* Here is where we finally get RETVAL into RESULT.
- `expand_return' does the magic of protecting
- RESULT from cleanups. */
- retval = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (result),
- retval));
- /* This part _must_ come second, because expand_return looks for
- the INIT_EXPR as the toplevel node only. :-( */
- retval = build (INIT_EXPR, TREE_TYPE (result), result, retval);
- TREE_SIDE_EFFECTS (retval) = 1;
- expand_return (retval);
- }
- else
- expand_return (result);
+ /* Here RETVAL is CURRENT_CLASS_PTR, so there's nothing to do. */
+ expand_goto (ctor_label);
}
- else
+
+ if (retval && retval != result)
{
- /* We may still need to put RETVAL into RESULT. */
- result = DECL_RESULT (current_function_decl);
- if (original_result_rtx)
- {
- /* Here we have a named return value that went
- into memory. We can compute RETVAL into that. */
- if (retval)
- expand_assignment (result, retval, 0, 0);
- else
- store_expr (result, original_result_rtx, 0);
- result = make_tree (TREE_TYPE (result), original_result_rtx);
- }
- else if (ctor_label && TREE_CODE (ctor_label) != ERROR_MARK)
- {
- /* Here RETVAL is CURRENT_CLASS_DECL, so there's nothing to do. */
- expand_goto (ctor_label);
- }
- else if (retval)
- {
- /* Here is where we finally get RETVAL into RESULT.
- `expand_return' does the magic of protecting
- RESULT from cleanups. */
- result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
- TREE_SIDE_EFFECTS (result) = 1;
- expand_return (result);
- }
- else if (TYPE_MODE (TREE_TYPE (result)) != VOIDmode)
- expand_return (result);
+ result = build (INIT_EXPR, TREE_TYPE (result), result, retval);
+ TREE_SIDE_EFFECTS (result) = 1;
}
- current_function_returns_value = returns_value;
-#if 0
- /* These wind up after the BARRIER, which causes problems for
- expand_end_binding. What purpose were they supposed to serve? */
- if (original_result_rtx)
- use_variable (original_result_rtx);
- if (use_temp)
- use_variable (DECL_RTL (DECL_RESULT (current_function_decl)));
-#endif
+ expand_start_target_temps ();
+
+ expand_return (result);
- /* One way to clear out cleanups that EXPR might
- generate. Note that this code will really be
- dead code, but that is ok--cleanups that were
- needed were handled by the magic of `return'. */
- expand_cleanups_to (NULL_TREE);
+ expand_end_target_temps ();
+
+ current_function_returns_value = 1;
}
/* Start a C switch statement, testing expression EXP.
@@ -7551,18 +7429,18 @@ c_expand_start_case (exp)
}
else
{
- tree index;
+ tree idx;
exp = default_conversion (exp);
type = TREE_TYPE (exp);
- index = get_unwidened (exp, 0);
+ idx = get_unwidened (exp, 0);
/* We can't strip a conversion from a signed type to an unsigned,
because if we did, int_fits_type_p would do the wrong thing
when checking case values for being in range,
and it's too hard to do the right thing. */
if (TREE_UNSIGNED (TREE_TYPE (exp))
- == TREE_UNSIGNED (TREE_TYPE (index)))
- exp = index;
+ == TREE_UNSIGNED (TREE_TYPE (idx)))
+ exp = idx;
}
expand_start_case
@@ -7572,18 +7450,31 @@ c_expand_start_case (exp)
return exp;
}
-/* CONSTP remembers whether or not all the intervening pointers in the `to'
- type have been const. */
-int
+/* Returns non-zero if the pointer-type FROM can be converted to the
+ pointer-type TO via a qualification conversion. If CONSTP is -1,
+ then we return non-zero if the pointers are similar, and the
+ cv-qualification signature of FROM is a proper subset of that of TO.
+
+ If CONSTP is positive, then all outer pointers have been
+ const-qualified. */
+
+static int
comp_ptr_ttypes_real (to, from, constp)
tree to, from;
int constp;
{
+ int to_more_cv_qualified = 0;
+
for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
{
if (TREE_CODE (to) != TREE_CODE (from))
return 0;
+ if (TREE_CODE (from) == OFFSET_TYPE
+ && comptypes (TYPE_OFFSET_BASETYPE (from),
+ TYPE_OFFSET_BASETYPE (to), 1))
+ continue;
+
/* Const and volatile mean something different for function types,
so the usual checks are not appropriate. */
if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
@@ -7592,24 +7483,115 @@ comp_ptr_ttypes_real (to, from, constp)
|| TYPE_VOLATILE (from) > TYPE_VOLATILE (to))
return 0;
- if (! constp
- && (TYPE_READONLY (to) > TYPE_READONLY (from)
- || TYPE_VOLATILE (to) > TYPE_READONLY (from)))
- return 0;
- constp &= TYPE_READONLY (to);
+ if (TYPE_READONLY (to) > TYPE_READONLY (from)
+ || TYPE_VOLATILE (to) > TYPE_VOLATILE (from))
+ {
+ if (constp == 0)
+ return 0;
+ else
+ ++to_more_cv_qualified;
+ }
+
+ if (constp > 0)
+ constp &= TYPE_READONLY (to);
}
if (TREE_CODE (to) != POINTER_TYPE)
- return comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1);
+ return
+ comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1)
+ && (constp >= 0 || to_more_cv_qualified);
}
}
/* When comparing, say, char ** to char const **, this function takes the
'char *' and 'char const *'. Do not pass non-pointer types to this
function. */
+
int
comp_ptr_ttypes (to, from)
tree to, from;
{
return comp_ptr_ttypes_real (to, from, 1);
}
+
+/* Returns 1 if to and from are (possibly multi-level) pointers to the same
+ type or inheritance-related types, regardless of cv-quals. */
+
+int
+ptr_reasonably_similar (to, from)
+ tree to, from;
+{
+ for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+ {
+ if (TREE_CODE (to) != TREE_CODE (from))
+ return 0;
+
+ if (TREE_CODE (from) == OFFSET_TYPE
+ && comptypes (TYPE_OFFSET_BASETYPE (to),
+ TYPE_OFFSET_BASETYPE (from), -1))
+ continue;
+
+ if (TREE_CODE (to) != POINTER_TYPE)
+ return comptypes
+ (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), -1);
+ }
+}
+
+/* Like comp_ptr_ttypes, for const_cast. */
+
+static int
+comp_ptr_ttypes_const (to, from)
+ tree to, from;
+{
+ for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+ {
+ if (TREE_CODE (to) != TREE_CODE (from))
+ return 0;
+
+ if (TREE_CODE (from) == OFFSET_TYPE
+ && comptypes (TYPE_OFFSET_BASETYPE (from),
+ TYPE_OFFSET_BASETYPE (to), 1))
+ continue;
+
+ if (TREE_CODE (to) != POINTER_TYPE)
+ return comptypes (TYPE_MAIN_VARIANT (to), TYPE_MAIN_VARIANT (from), 1);
+ }
+}
+
+/* Like comp_ptr_ttypes, for reinterpret_cast. */
+
+static int
+comp_ptr_ttypes_reinterpret (to, from)
+ tree to, from;
+{
+ int constp = 1;
+
+ for (; ; to = TREE_TYPE (to), from = TREE_TYPE (from))
+ {
+ if (TREE_CODE (from) == OFFSET_TYPE)
+ from = TREE_TYPE (from);
+ if (TREE_CODE (to) == OFFSET_TYPE)
+ to = TREE_TYPE (to);
+
+ if (TREE_CODE (to) != TREE_CODE (from))
+ return 1;
+
+ /* Const and volatile mean something different for function types,
+ so the usual checks are not appropriate. */
+ if (TREE_CODE (to) != FUNCTION_TYPE && TREE_CODE (to) != METHOD_TYPE)
+ {
+ if (TYPE_READONLY (from) > TYPE_READONLY (to)
+ || TYPE_VOLATILE (from) > TYPE_VOLATILE (to))
+ return 0;
+
+ if (! constp
+ && (TYPE_READONLY (to) > TYPE_READONLY (from)
+ || TYPE_VOLATILE (to) > TYPE_READONLY (from)))
+ return 0;
+ constp &= TYPE_READONLY (to);
+ }
+
+ if (TREE_CODE (to) != POINTER_TYPE)
+ return 1;
+ }
+}
diff --git a/contrib/gcc/cp/typeck2.c b/contrib/gcc/cp/typeck2.c
index 653d6a5..39b0626 100644
--- a/contrib/gcc/cp/typeck2.c
+++ b/contrib/gcc/cp/typeck2.c
@@ -31,19 +31,20 @@ Boston, MA 02111-1307, USA. */
like a strange sort of assignment). */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "tree.h"
#include "cp-tree.h"
#include "flags.h"
+#include "toplev.h"
-static tree process_init_constructor ();
-extern void pedwarn (), error ();
+static tree process_init_constructor PROTO((tree, tree, tree *));
extern int errorcount;
extern int sorrycount;
/* Print an error message stemming from an attempt to use
BASETYPE as a base class for TYPE. */
+
tree
error_not_base_type (basetype, type)
tree basetype, type;
@@ -71,33 +72,11 @@ binfo_or_else (parent_or_type, type)
return NULL_TREE;
}
-/* Print an error message stemming from an invalid use of an
- aggregate type.
-
- TYPE is the type or binfo which draws the error.
- MSG is the message to print.
- ARG is an optional argument which may provide more information. */
-void
-error_with_aggr_type (type, msg, arg)
- tree type;
- char *msg;
- HOST_WIDE_INT arg;
-{
- tree name;
-
- if (TREE_CODE (type) == TREE_VEC)
- type = BINFO_TYPE (type);
-
- name = TYPE_NAME (type);
- if (TREE_CODE (name) == TYPE_DECL)
- name = DECL_NAME (name);
- error (msg, IDENTIFIER_POINTER (name), arg);
-}
-
/* According to ARM $7.1.6, "A `const' object may be initialized, but its
value may not be changed thereafter. Thus, we emit hard errors for these,
rather than just pedwarns. If `SOFT' is 1, then we just pedwarn. (For
example, conversions to references.) */
+
void
readonly_error (arg, string, soft)
tree arg;
@@ -108,52 +87,73 @@ readonly_error (arg, string, soft)
void (*fn)();
if (soft)
- fn = pedwarn;
+ fn = cp_pedwarn;
else
- fn = error;
+ fn = cp_error;
if (TREE_CODE (arg) == COMPONENT_REF)
{
if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
- fmt = "%s of member `%s' in read-only structure";
+ fmt = "%s of member `%D' in read-only structure";
else
- fmt = "%s of read-only member `%s'";
- (*fn) (fmt, string, lang_printable_name (TREE_OPERAND (arg, 1)));
+ fmt = "%s of read-only member `%D'";
+ (*fn) (fmt, string, TREE_OPERAND (arg, 1));
}
else if (TREE_CODE (arg) == VAR_DECL)
{
if (DECL_LANG_SPECIFIC (arg)
&& DECL_IN_AGGR_P (arg)
&& !TREE_STATIC (arg))
- fmt = "%s of constant field `%s'";
+ fmt = "%s of constant field `%D'";
else
- fmt = "%s of read-only variable `%s'";
- (*fn) (fmt, string, lang_printable_name (arg));
+ fmt = "%s of read-only variable `%D'";
+ (*fn) (fmt, string, arg);
}
else if (TREE_CODE (arg) == PARM_DECL)
- (*fn) ("%s of read-only parameter `%s'", string,
- lang_printable_name (arg));
+ (*fn) ("%s of read-only parameter `%D'", string, arg);
else if (TREE_CODE (arg) == INDIRECT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 0))) == REFERENCE_TYPE
&& (TREE_CODE (TREE_OPERAND (arg, 0)) == VAR_DECL
|| TREE_CODE (TREE_OPERAND (arg, 0)) == PARM_DECL))
- (*fn) ("%s of read-only reference `%s'",
- string, lang_printable_name (TREE_OPERAND (arg, 0)));
+ (*fn) ("%s of read-only reference `%D'", string, TREE_OPERAND (arg, 0));
else if (TREE_CODE (arg) == RESULT_DECL)
- (*fn) ("%s of read-only named return value `%s'",
- string, lang_printable_name (arg));
+ (*fn) ("%s of read-only named return value `%D'", string, arg);
else
(*fn) ("%s of read-only location", string);
}
/* Print an error message for invalid use of a type which declares
virtual functions which are not inheritable. */
+
void
abstract_virtuals_error (decl, type)
tree decl;
tree type;
{
tree u = CLASSTYPE_ABSTRACT_VIRTUALS (type);
+ int has_abstract_virtuals, needs_final_overriders;
+ tree tu;
+
+ /* Count how many abstract methods need to be defined. */
+ for (has_abstract_virtuals = 0, tu = u; tu; tu = TREE_CHAIN (tu))
+ {
+ if (DECL_ABSTRACT_VIRTUAL_P (TREE_VALUE (tu))
+ && ! DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu)))
+ {
+ has_abstract_virtuals = 1;
+ break;
+ }
+ }
+
+ /* Count how many virtual methods need a final overrider. */
+ for (needs_final_overriders = 0, tu = u; tu; tu = TREE_CHAIN (tu))
+ {
+ if (DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu)))
+ {
+ needs_final_overriders = 1;
+ break;
+ }
+ }
if (decl)
{
@@ -175,24 +175,58 @@ abstract_virtuals_error (decl, type)
else if (TREE_CODE (decl) == FUNCTION_DECL)
cp_error ("invalid return type for function `%#D'", decl);
}
- else cp_error ("cannot allocate an object of type `%T'", type);
+ else
+ cp_error ("cannot allocate an object of type `%T'", type);
+
/* Only go through this once. */
if (TREE_PURPOSE (u) == NULL_TREE)
{
- error (" since the following virtual functions are abstract:");
TREE_PURPOSE (u) = error_mark_node;
- while (u)
+
+ if (has_abstract_virtuals)
+ error (" since the following virtual functions are abstract:");
+ tu = u;
+ while (tu)
+ {
+ if (DECL_ABSTRACT_VIRTUAL_P (TREE_VALUE (tu))
+ && ! DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu)))
+ cp_error ("\t%#D", TREE_VALUE (tu));
+ tu = TREE_CHAIN (tu);
+ }
+
+ if (needs_final_overriders)
+ {
+ if (has_abstract_virtuals)
+ error (" and the following virtual functions need a final overrider:");
+ else
+ error (" since the following virtual functions need a final overrider:");
+ }
+ tu = u;
+ while (tu)
+ {
+ if (DECL_NEEDS_FINAL_OVERRIDER_P (TREE_VALUE (tu)))
+ cp_error ("\t%#D", TREE_VALUE (tu));
+ tu = TREE_CHAIN (tu);
+ }
+ }
+ else
+ {
+ if (has_abstract_virtuals)
{
- cp_error ("\t%#D", TREE_VALUE (u));
- u = TREE_CHAIN (u);
+ if (needs_final_overriders)
+ cp_error (" since type `%T' has abstract virtual functions and must override virtual functions", type);
+ else
+ cp_error (" since type `%T' has abstract virtual functions", type);
}
+ else
+ cp_error (" since type `%T' must override virtual functions", type);
}
- else cp_error (" since type `%T' has abstract virtual functions", type);
}
/* Print an error message for invalid use of a signature type.
Signatures are treated similar to abstract classes here, they
cannot be instantiated. */
+
void
signature_error (decl, type)
tree decl;
@@ -231,7 +265,7 @@ incomplete_type_error (value, type)
tree value;
tree type;
{
- char *errmsg;
+ char *errmsg = 0;
/* Avoid duplicate error message. */
if (TREE_CODE (type) == ERROR_MARK)
@@ -239,8 +273,7 @@ incomplete_type_error (value, type)
if (value != 0 && (TREE_CODE (value) == VAR_DECL
|| TREE_CODE (value) == PARM_DECL))
- error ("`%s' has an incomplete type",
- IDENTIFIER_POINTER (DECL_NAME (value)));
+ cp_error ("`%D' has incomplete type", value);
else
{
retry:
@@ -249,15 +282,9 @@ incomplete_type_error (value, type)
switch (TREE_CODE (type))
{
case RECORD_TYPE:
- errmsg = "invalid use of undefined type `struct %s'";
- break;
-
case UNION_TYPE:
- errmsg = "invalid use of undefined type `union %s'";
- break;
-
case ENUMERAL_TYPE:
- errmsg = "invalid use of undefined type `enum %s'";
+ errmsg = "invalid use of undefined type `%#T'";
break;
case VOID_TYPE:
@@ -277,15 +304,20 @@ incomplete_type_error (value, type)
error ("invalid use of member type (did you forget the `&' ?)");
return;
+ case TEMPLATE_TYPE_PARM:
+ error ("invalid use of template type parameter");
+ return;
+
default:
my_friendly_abort (108);
}
- error_with_aggr_type (type, errmsg);
+ cp_error (errmsg, type);
}
}
/* Like error(), but don't call report_error_function(). */
+
static void
ack (s, v, v2)
char *s;
@@ -330,7 +362,7 @@ ack (s, v, v2)
silly. So instead, we just do the equivalent of a call to fatal in the
same situation (call exit). */
-/* First used: 0 (reserved), Last used: 366. Free: */
+/* First used: 0 (reserved), Last used: 369. Free: */
static int abortcount = 0;
@@ -351,7 +383,8 @@ my_friendly_abort (i)
ack ("Internal compiler error.");
else
ack ("Internal compiler error %d.", i);
- ack ("Please submit a full bug report to `bug-g++@prep.ai.mit.edu'.");
+ ack ("Please submit a full bug report to `egcs-bugs@egcs.cygnus.com'.");
+ ack ("See <URL:http://egcs.cygnus.com/faq.html#bugreport> for details.");
}
else
error ("confused by earlier errors, bailing out");
@@ -365,7 +398,8 @@ my_friendly_abort (i)
else
error ("Internal compiler error %d.", i);
- fatal ("Please submit a full bug report to `bug-g++@prep.ai.mit.edu'.");
+ error ("Please submit a full bug report to `egcs-bugs@egcs.cygnus.com'.");
+ fatal ("See <URL:http://egcs.cygnus.com/faq.html#bugreport> for details.");
}
void
@@ -417,8 +451,8 @@ initializer_constant_valid_p (value, endtype)
case CONVERT_EXPR:
case NOP_EXPR:
/* Allow conversions between pointer types. */
- if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == POINTER_TYPE)
+ if (POINTER_TYPE_P (TREE_TYPE (value))
+ && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (value, 0))))
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
/* Allow conversions between real types. */
@@ -453,13 +487,18 @@ initializer_constant_valid_p (value, endtype)
return initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
- /* Likewise conversions from int to pointers. */
+ /* Likewise conversions from int to pointers, but also allow
+ conversions from 0. */
if (TREE_CODE (TREE_TYPE (value)) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE
- && (TYPE_PRECISION (TREE_TYPE (value))
- <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0)))))
- return initializer_constant_valid_p (TREE_OPERAND (value, 0),
- endtype);
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (value, 0))) == INTEGER_TYPE)
+ {
+ if (integer_zerop (TREE_OPERAND (value, 0)))
+ return null_pointer_node;
+ else if (TYPE_PRECISION (TREE_TYPE (value))
+ <= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (value, 0))))
+ return initializer_constant_valid_p (TREE_OPERAND (value, 0),
+ endtype);
+ }
/* Allow conversions to union types if the value inside is okay. */
if (TREE_CODE (TREE_TYPE (value)) == UNION_TYPE)
@@ -468,8 +507,8 @@ initializer_constant_valid_p (value, endtype)
return 0;
case PLUS_EXPR:
- if (TREE_CODE (endtype) == INTEGER_TYPE
- && TYPE_PRECISION (endtype) < POINTER_SIZE)
+ if ((TREE_CODE (endtype) == INTEGER_TYPE)
+ && (TYPE_PRECISION (endtype) < POINTER_SIZE))
return 0;
{
tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
@@ -485,8 +524,8 @@ initializer_constant_valid_p (value, endtype)
}
case MINUS_EXPR:
- if (TREE_CODE (endtype) == INTEGER_TYPE
- && TYPE_PRECISION (endtype) < POINTER_SIZE)
+ if ((TREE_CODE (endtype) == INTEGER_TYPE)
+ && (TYPE_PRECISION (endtype) < POINTER_SIZE))
return 0;
{
tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
@@ -502,6 +541,9 @@ initializer_constant_valid_p (value, endtype)
return null_pointer_node;
return 0;
}
+
+ default:
+ break;
}
return 0;
@@ -569,8 +611,6 @@ store_init_value (decl, init)
if (TREE_CODE (init) == CONSTRUCTOR)
{
tree field;
- tree funcs;
- int func;
/* Check that we're really an aggregate as ARM 8.4.1 defines it. */
if (CLASSTYPE_N_BASECLASSES (type))
@@ -588,16 +628,11 @@ store_init_value (decl, init)
cp_error_at ("initializer list construction invalid for `%D'", decl);
cp_error_at ("due to non-public access of member `%D'", field);
}
- funcs = TYPE_METHODS (type);
- if (funcs)
- for (func = 0; func < TREE_VEC_LENGTH (funcs); func++)
+ for (field = TYPE_METHODS (type); field; field = TREE_CHAIN (field))
+ if (TREE_PRIVATE (field) || TREE_PROTECTED (field))
{
- field = TREE_VEC_ELT (funcs, func);
- if (field && (TREE_PRIVATE (field) || TREE_PROTECTED (field)))
- {
- cp_error_at ("initializer list construction invalid for `%D'", decl);
- cp_error_at ("due to non-public access of member `%D'", field);
- }
+ cp_error_at ("initializer list construction invalid for `%D'", decl);
+ cp_error_at ("due to non-public access of member `%D'", field);
}
}
#endif
@@ -652,6 +687,11 @@ store_init_value (decl, init)
if (TREE_CODE (value) == ERROR_MARK)
;
+ /* Other code expects that initializers for objects of types that need
+ constructing never make it into DECL_INITIAL, and passes 'init' to
+ expand_aggr_init without checking DECL_INITIAL. So just return. */
+ else if (TYPE_NEEDS_CONSTRUCTING (type))
+ return value;
else if (TREE_STATIC (decl)
&& (! TREE_CONSTANT (value)
|| ! initializer_constant_valid_p (value, TREE_TYPE (value))
@@ -660,7 +700,7 @@ store_init_value (decl, init)
run time inited when doing pic. (mrs) */
/* Since ctors and dtors are the only things that can
reference vtables, and they are always written down
- the the vtable definition, we can leave the
+ the vtable definition, we can leave the
vtables in initialized data space.
However, other initialized data cannot be initialized
this way. Instead a global file-level initializer
@@ -705,7 +745,7 @@ digest_init (type, init, tail)
{
enum tree_code code = TREE_CODE (type);
tree element = NULL_TREE;
- tree old_tail_contents;
+ tree old_tail_contents = NULL_TREE;
/* Nonzero if INIT is a braced grouping, which comes in as a CONSTRUCTOR
tree node which has no TREE_TYPE. */
int raw_constructor;
@@ -727,24 +767,9 @@ digest_init (type, init, tail)
if (TREE_CODE (init) == NON_LVALUE_EXPR)
init = TREE_OPERAND (init, 0);
- if (init && TREE_TYPE (init) && TYPE_PTRMEMFUNC_P (type))
- init = default_conversion (init);
-
- if (init && TYPE_PTRMEMFUNC_P (type)
- && ((TREE_CODE (init) == ADDR_EXPR
- && ((TREE_CODE (TREE_TYPE (init)) == POINTER_TYPE
- && TREE_CODE (TREE_TYPE (TREE_TYPE (init))) == METHOD_TYPE)
- || TREE_CODE (TREE_OPERAND (init, 0)) == TREE_LIST))
- || TREE_CODE (init) == TREE_LIST
- || integer_zerop (init)
- || (TREE_TYPE (init) && TYPE_PTRMEMFUNC_P (TREE_TYPE (init)))))
- {
- return build_ptrmemfunc (TYPE_PTRMEMFUNC_FN_TYPE (type), init, 0);
- }
-
raw_constructor = TREE_CODE (init) == CONSTRUCTOR && TREE_TYPE (init) == 0;
- if (init && raw_constructor
+ if (raw_constructor
&& CONSTRUCTOR_ELTS (init) != 0
&& TREE_CHAIN (CONSTRUCTOR_ELTS (init)) == 0)
{
@@ -756,44 +781,20 @@ digest_init (type, init, tail)
return element;
}
- /* Any type can be initialized from an expression of the same type,
- optionally with braces. */
-
- if (init && TREE_TYPE (init)
- && (TYPE_MAIN_VARIANT (TREE_TYPE (init)) == type
- || (code == ARRAY_TYPE && comptypes (TREE_TYPE (init), type, 1))))
- {
- if (pedantic && code == ARRAY_TYPE
- && TREE_CODE (init) != STRING_CST)
- pedwarn ("ANSI C++ forbids initializing array from array expression");
- if (TREE_CODE (init) == CONST_DECL)
- init = DECL_INITIAL (init);
- else if (TREE_READONLY_DECL_P (init))
- init = decl_constant_value (init);
- return init;
- }
-
- if (element && (TREE_TYPE (element) == type
- || (code == ARRAY_TYPE && TREE_TYPE (element)
- && comptypes (TREE_TYPE (element), type, 1))))
- {
- if (pedantic && code == ARRAY_TYPE)
- pedwarn ("ANSI C++ forbids initializing array from array expression");
- if (pedantic && (code == RECORD_TYPE || code == UNION_TYPE))
- pedwarn ("ANSI C++ forbids single nonscalar initializer with braces");
- if (TREE_CODE (element) == CONST_DECL)
- element = DECL_INITIAL (element);
- else if (TREE_READONLY_DECL_P (element))
- element = decl_constant_value (element);
- return element;
- }
-
/* Initialization of an array of chars from a string constant
optionally enclosed in braces. */
if (code == ARRAY_TYPE)
{
- tree typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+ tree typ1;
+
+ if (TREE_CODE (init) == TREE_LIST)
+ {
+ error ("initializing array with parameter list");
+ return error_mark_node;
+ }
+
+ typ1 = TYPE_MAIN_VARIANT (TREE_TYPE (type));
if ((typ1 == char_type_node
|| typ1 == signed_char_type_node
|| typ1 == unsigned_char_type_node
@@ -819,11 +820,6 @@ digest_init (type, init, tail)
return error_mark_node;
}
- if (pedantic
- && typ1 != char_type_node
- && typ1 != signed_char_type_node
- && typ1 != unsigned_char_type_node)
- pedwarn ("ANSI C++ forbids string initializer except for `char' elements");
TREE_TYPE (string) = type;
if (TYPE_DOMAIN (type) != 0
&& TREE_CONSTANT (TYPE_SIZE (type)))
@@ -847,7 +843,8 @@ digest_init (type, init, tail)
if (code == INTEGER_TYPE || code == REAL_TYPE || code == POINTER_TYPE
|| code == ENUMERAL_TYPE || code == REFERENCE_TYPE
- || code == BOOLEAN_TYPE
+ || code == BOOLEAN_TYPE || code == COMPLEX_TYPE
+ || TYPE_PTRMEMFUNC_P (type)
|| (code == RECORD_TYPE && ! raw_constructor
&& (IS_SIGNATURE_POINTER (type) || IS_SIGNATURE_REFERENCE (type))))
{
@@ -860,7 +857,7 @@ digest_init (type, init, tail)
}
init = element;
}
- while (TREE_CODE (init) == CONSTRUCTOR)
+ while (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
{
cp_pedwarn ("braces around scalar initializer for `%T'", type);
init = CONSTRUCTOR_ELTS (init);
@@ -892,27 +889,25 @@ digest_init (type, init, tail)
}
else if (raw_constructor)
return process_init_constructor (type, init, (tree *)0);
- else if (TYPE_NON_AGGREGATE_CLASS (type))
- {
- /* This can only be reached when caller is initializing
- ARRAY_TYPE. In that case, we don't want to convert
- INIT to TYPE. We will let `expand_vec_init' do it. */
- return init;
- }
+ else if (can_convert_arg (type, TREE_TYPE (init), init)
+ || TYPE_NON_AGGREGATE_CLASS (type))
+ /* These are never initialized from multiple constructor elements. */;
else if (tail != 0)
{
*tail = old_tail_contents;
return process_init_constructor (type, 0, tail);
}
- else if (flag_traditional)
- /* Traditionally one can say `char x[100] = 0;'. */
- return process_init_constructor (type,
- build_nt (CONSTRUCTOR, 0,
- tree_cons (0, init, 0)),
- 0);
+
if (code != ARRAY_TYPE)
- return convert_for_initialization (0, type, init, LOOKUP_NORMAL,
- "initialization", NULL_TREE, 0);
+ {
+ int flags = LOOKUP_NORMAL;
+ /* Initialization from { } is copy-initialization. */
+ if (tail)
+ flags |= LOOKUP_ONLYCONVERTING;
+
+ return convert_for_initialization (NULL_TREE, type, init, flags,
+ "initialization", NULL_TREE, 0);
+ }
}
error ("invalid initializer");
@@ -980,10 +975,15 @@ process_init_constructor (type, init, elts)
{
register tree next1;
+ if (TREE_PURPOSE (tail)
+ && (TREE_CODE (TREE_PURPOSE (tail)) != INTEGER_CST
+ || TREE_INT_CST_LOW (TREE_PURPOSE (tail)) != i))
+ sorry ("non-trivial labeled initializers");
+
if (TREE_VALUE (tail) != 0)
{
tree tail1 = tail;
- next1 = digest_init (TYPE_MAIN_VARIANT (TREE_TYPE (type)),
+ next1 = digest_init (TREE_TYPE (type),
TREE_VALUE (tail), &tail1);
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (type))
&& TYPE_MAIN_VARIANT (TREE_TYPE (type)) != TYPE_MAIN_VARIANT (TREE_TYPE (next1)))
@@ -1014,7 +1014,7 @@ process_init_constructor (type, init, elts)
allconstant = 0;
else if (! initializer_constant_valid_p (next1, TREE_TYPE (next1)))
allsimple = 0;
- members = tree_cons (NULL_TREE, next1, members);
+ members = expr_tree_cons (NULL_TREE, next1, members);
}
}
if (TREE_CODE (type) == RECORD_TYPE)
@@ -1049,13 +1049,18 @@ process_init_constructor (type, init, elts)
if (! DECL_NAME (field))
{
- members = tree_cons (field, integer_zero_node, members);
+ members = expr_tree_cons (field, integer_zero_node, members);
continue;
}
if (TREE_CODE (field) != FIELD_DECL)
continue;
+ if (TREE_PURPOSE (tail)
+ && TREE_PURPOSE (tail) != field
+ && TREE_PURPOSE (tail) != DECL_NAME (field))
+ sorry ("non-trivial labeled initializers");
+
if (TREE_VALUE (tail) != 0)
{
tree tail1 = tail;
@@ -1078,7 +1083,7 @@ process_init_constructor (type, init, elts)
allconstant = 0;
else if (! initializer_constant_valid_p (next1, TREE_TYPE (next1)))
allsimple = 0;
- members = tree_cons (field, next1, members);
+ members = expr_tree_cons (field, next1, members);
}
for (; field; field = TREE_CHAIN (field))
{
@@ -1095,7 +1100,7 @@ process_init_constructor (type, init, elts)
allconstant = 0;
else if (! initializer_constant_valid_p (next1, TREE_TYPE (next1)))
allsimple = 0;
- members = tree_cons (field, next1, members);
+ members = expr_tree_cons (field, next1, members);
}
else if (TREE_READONLY (field))
error ("uninitialized const member `%s'",
@@ -1107,6 +1112,11 @@ process_init_constructor (type, init, elts)
else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
error ("member `%s' is uninitialized reference",
IDENTIFIER_POINTER (DECL_NAME (field)));
+ /* Warn when some struct elements are implicitly initialized
+ to zero. */
+ else if (extra_warnings)
+ warning ("missing initializer for member `%s'",
+ IDENTIFIER_POINTER (DECL_NAME (field)));
}
}
@@ -1117,7 +1127,8 @@ process_init_constructor (type, init, elts)
/* Find the first named field. ANSI decided in September 1990
that only named fields count here. */
- while (field && DECL_NAME (field) == 0)
+ while (field && (DECL_NAME (field) == 0
+ || TREE_CODE (field) != FIELD_DECL))
field = TREE_CHAIN (field);
/* If this element specifies a field, initialize via that field. */
@@ -1176,7 +1187,7 @@ process_init_constructor (type, init, elts)
allconstant = 0;
else if (initializer_constant_valid_p (next1, TREE_TYPE (next1)) == 0)
allsimple = 0;
- members = tree_cons (field, next1, members);
+ members = expr_tree_cons (field, next1, members);
}
/* If arguments were specified as a list, just remove the ones we used. */
@@ -1200,7 +1211,7 @@ process_init_constructor (type, init, elts)
/* Given a structure or union value DATUM, construct and return
the structure or union component which results from narrowing
- that value by the types specified in TYPES. For example, given the
+ that value by the type specified in BASETYPE. For example, given the
hierarchy
class L { int ii; };
@@ -1214,23 +1225,14 @@ process_init_constructor (type, init, elts)
then the expression
- x::C::A::L::ii refers to the ii member of the L part of
- of A part of the C object named by X. In this case,
- DATUM would be x, and TYPES would be a SCOPE_REF consisting of
-
- SCOPE_REF
- SCOPE_REF
- C A
- L
-
- The last entry in the SCOPE_REF is always an IDENTIFIER_NODE.
-
-*/
+ x.A::ii refers to the ii member of the L part of
+ the A part of the C object named by X. In this case,
+ DATUM would be x, and BASETYPE would be A. */
tree
-build_scoped_ref (datum, types)
+build_scoped_ref (datum, basetype)
tree datum;
- tree types;
+ tree basetype;
{
tree ref;
tree type = TREE_TYPE (datum);
@@ -1243,62 +1245,17 @@ build_scoped_ref (datum, types)
type = TYPE_MAIN_VARIANT (type);
- if (TREE_CODE (types) == SCOPE_REF)
- {
- /* We have some work to do. */
- struct type_chain
- { tree type; struct type_chain *next; }
- *chain = NULL, *head = NULL, scratch;
- ref = build_unary_op (ADDR_EXPR, datum, 0);
- while (TREE_CODE (types) == SCOPE_REF)
- {
- tree t = TREE_OPERAND (types, 1);
- if (is_aggr_typedef (t, 1))
- {
- head = (struct type_chain *)alloca (sizeof (struct type_chain));
- head->type = IDENTIFIER_TYPE_VALUE (t);
- head->next = chain;
- chain = head;
- types = TREE_OPERAND (types, 0);
- }
- else return error_mark_node;
- }
- if (! is_aggr_typedef (types, 1))
- return error_mark_node;
-
- head = &scratch;
- head->type = IDENTIFIER_TYPE_VALUE (types);
- head->next = chain;
- chain = head;
- while (chain)
- {
- tree binfo = chain->type;
- type = TREE_TYPE (TREE_TYPE (ref));
- if (binfo != TYPE_BINFO (type))
- {
- binfo = get_binfo (binfo, type, 1);
- if (binfo == error_mark_node)
- return error_mark_node;
- if (binfo == 0)
- return error_not_base_type (chain->type, type);
- ref = convert_pointer_to (binfo, ref);
- }
- chain = chain->next;
- }
- return build_indirect_ref (ref, "(compiler error in build_scoped_ref)");
- }
-
/* This is an easy conversion. */
- if (is_aggr_typedef (types, 1))
+ if (is_aggr_type (basetype, 1))
{
- tree binfo = TYPE_BINFO (IDENTIFIER_TYPE_VALUE (types));
+ tree binfo = TYPE_BINFO (basetype);
if (binfo != TYPE_BINFO (type))
{
binfo = get_binfo (binfo, type, 1);
if (binfo == error_mark_node)
return error_mark_node;
if (binfo == 0)
- return error_not_base_type (IDENTIFIER_TYPE_VALUE (types), type);
+ return error_not_base_type (basetype, type);
}
switch (TREE_CODE (datum))
@@ -1328,6 +1285,7 @@ build_scoped_ref (datum, types)
performed until an object which does not have the `->' operator
overloaded is found. An error is reported when circular pointer
delegation is detected. */
+
tree
build_x_arrow (datum)
tree datum;
@@ -1335,11 +1293,14 @@ build_x_arrow (datum)
tree types_memoized = NULL_TREE;
register tree rval = datum;
tree type = TREE_TYPE (rval);
- tree last_rval;
+ tree last_rval = NULL_TREE;
if (type == error_mark_node)
return error_mark_node;
+ if (processing_template_decl)
+ return build_min_nt (ARROW_EXPR, rval);
+
if (TREE_CODE (rval) == OFFSET_REF)
{
rval = resolve_offset_ref (datum);
@@ -1352,9 +1313,10 @@ build_x_arrow (datum)
type = TREE_TYPE (rval);
}
- if (IS_AGGR_TYPE (type) && TYPE_OVERLOADS_ARROW (type))
+ if (IS_AGGR_TYPE (type))
{
- while ((rval = build_opfncall (COMPONENT_REF, LOOKUP_NORMAL, rval, NULL_TREE, NULL_TREE)))
+ while ((rval = build_opfncall (COMPONENT_REF, LOOKUP_NORMAL, rval,
+ NULL_TREE, NULL_TREE)))
{
if (rval == error_mark_node)
return error_mark_node;
@@ -1371,6 +1333,13 @@ build_x_arrow (datum)
}
last_rval = rval;
}
+
+ if (last_rval == NULL_TREE)
+ {
+ cp_error ("base operand of `->' has non-pointer type `%T'", type);
+ return error_mark_node;
+ }
+
if (TREE_CODE (TREE_TYPE (last_rval)) == REFERENCE_TYPE)
last_rval = convert_from_reference (last_rval);
}
@@ -1403,6 +1372,7 @@ build_x_arrow (datum)
As a special case, if there is only one method by that name,
it is returned. Otherwise we return an expression which other
routines will have to know how to deal with later. */
+
tree
build_m_component_ref (datum, component)
tree datum, component;
@@ -1412,6 +1382,9 @@ build_m_component_ref (datum, component)
tree rettype;
tree binfo;
+ if (processing_template_decl)
+ return build_min_nt (DOTSTAR_EXPR, datum, component);
+
if (TYPE_PTRMEMFUNC_P (TREE_TYPE (component)))
{
type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (TREE_TYPE (component)));
@@ -1421,7 +1394,7 @@ build_m_component_ref (datum, component)
{
component = build_indirect_ref (component, NULL_PTR);
type = TREE_TYPE (component);
- rettype = TREE_TYPE (TREE_TYPE (component));
+ rettype = TREE_TYPE (type);
}
if (datum == error_mark_node || component == error_mark_node)
@@ -1454,14 +1427,14 @@ build_m_component_ref (datum, component)
else if (binfo == error_mark_node)
return error_mark_node;
- return build (OFFSET_REF, rettype, datum, component);
+ component = build (OFFSET_REF, rettype, datum, component);
+ if (TREE_CODE (type) == OFFSET_TYPE)
+ component = resolve_offset_ref (component);
+ return component;
}
-/* Return a tree node for the expression TYPENAME '(' PARMS ')'.
+/* Return a tree node for the expression TYPENAME '(' PARMS ')'. */
- Because we cannot tell whether this construct is really a call to a
- constructor or a request for a type conversion, we try both, and
- report any ambiguities we find. */
tree
build_functional_cast (exp, parms)
tree exp;
@@ -1469,16 +1442,13 @@ build_functional_cast (exp, parms)
{
/* This is either a call to a constructor,
or a C cast in C++'s `functional' notation. */
- tree type, name = NULL_TREE;
- tree expr_as_ctor = NULL_TREE;
+ tree type;
if (exp == error_mark_node || parms == error_mark_node)
return error_mark_node;
if (TREE_CODE (exp) == IDENTIFIER_NODE)
{
- name = exp;
-
if (IDENTIFIER_HAS_TYPE_VALUE (exp))
/* Either an enum or an aggregate type. */
type = IDENTIFIER_TYPE_VALUE (exp);
@@ -1487,35 +1457,26 @@ build_functional_cast (exp, parms)
type = lookup_name (exp, 1);
if (!type || TREE_CODE (type) != TYPE_DECL)
{
- cp_error ("`%T' fails to be a typedef or built-in type", name);
+ cp_error ("`%T' fails to be a typedef or built-in type", exp);
return error_mark_node;
}
type = TREE_TYPE (type);
}
}
+ else if (TREE_CODE (exp) == TYPE_DECL)
+ type = TREE_TYPE (exp);
else
type = exp;
+ if (processing_template_decl)
+ return build_min (CAST_EXPR, type, parms);
+
if (IS_SIGNATURE (type))
{
error ("signature type not allowed in cast or constructor expression");
return error_mark_node;
}
- /* Prepare to evaluate as a call to a constructor. If this expression
- is actually used, for example,
-
- return X (arg1, arg2, ...);
-
- then the slot being initialized will be filled in. */
-
- if (name == NULL_TREE)
- {
- name = TYPE_NAME (type);
- if (TREE_CODE (name) == TYPE_DECL)
- name = DECL_NESTED_TYPENAME (name);
- }
-
if (! IS_AGGR_TYPE (type))
{
/* this must build a C cast */
@@ -1528,29 +1489,46 @@ build_functional_cast (exp, parms)
parms = build_compound_expr (parms);
}
- return build_c_cast (type, parms, 1);
+ return build_c_cast (type, parms);
}
- if (TYPE_SIZE (type) == NULL_TREE)
+ /* Prepare to evaluate as a call to a constructor. If this expression
+ is actually used, for example,
+
+ return X (arg1, arg2, ...);
+
+ then the slot being initialized will be filled in. */
+
+ if (TYPE_SIZE (complete_type (type)) == NULL_TREE)
{
cp_error ("type `%T' is not yet defined", type);
return error_mark_node;
}
if (parms && TREE_CHAIN (parms) == NULL_TREE)
- return build_c_cast (type, parms, 1);
+ return build_c_cast (type, TREE_VALUE (parms));
- expr_as_ctor = build_method_call (NULL_TREE, name, parms,
- NULL_TREE, LOOKUP_NORMAL);
+ /* We need to zero-initialize POD types. Let's do that for everything
+ that doesn't need a constructor. */
+ if (parms == NULL_TREE && !TYPE_NEEDS_CONSTRUCTING (type)
+ && TYPE_HAS_DEFAULT_CONSTRUCTOR (type))
+ {
+ exp = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+ return get_target_expr (exp);
+ }
- if (expr_as_ctor == error_mark_node)
+ exp = build_method_call (NULL_TREE, ctor_identifier, parms,
+ TYPE_BINFO (type), LOOKUP_NORMAL);
+
+ if (exp == error_mark_node)
return error_mark_node;
- return build_cplus_new (type, expr_as_ctor, 1);
+ return build_cplus_new (type, exp);
}
/* Return the character string for the name that encodes the
enumeral value VALUE in the domain TYPE. */
+
char *
enum_name_string (value, type)
tree value;
@@ -1568,8 +1546,8 @@ enum_name_string (value, type)
char *buf = (char *)oballoc (16 + TYPE_NAME_LENGTH (type));
/* Value must have been cast. */
- sprintf (buf, "(enum %s)%d",
- TYPE_NAME_STRING (type), intval);
+ sprintf (buf, "(enum %s)%ld",
+ TYPE_NAME_STRING (type), (long) intval);
return buf;
}
return IDENTIFIER_POINTER (TREE_PURPOSE (values));
@@ -1582,6 +1560,7 @@ enum_name_string (value, type)
TYPE is the type of the switch index expression.
NEW is the new value that we were trying to add.
OLD is the old value that stopped us from adding it. */
+
void
report_case_error (code, type, new_value, old_value)
int code;
@@ -1679,3 +1658,12 @@ report_case_error (code, type, new_value, old_value)
}
}
#endif
+
+void
+check_for_new_type (string, inptree)
+ char *string;
+ flagged_type_tree inptree;
+{
+ if (pedantic && inptree.new_type_flag)
+ pedwarn ("ANSI C++ forbids defining types within %s",string);
+}
diff --git a/contrib/gcc/cp/xref.c b/contrib/gcc/cp/xref.c
index ec4b174..14915d6 100644
--- a/contrib/gcc/cp/xref.c
+++ b/contrib/gcc/cp/xref.c
@@ -1,5 +1,5 @@
/* Code for handling XREF output from GNU C++.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93-97, 1998 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -21,17 +21,13 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "tree.h"
-#include <stdio.h>
#include "cp-tree.h"
#include "input.h"
+#include "toplev.h"
-#include <ctype.h>
-
-extern char *getpwd ();
-
-extern char *index ();
-extern char *rindex ();
+extern char *getpwd PROTO((void));
/* The character(s) used to join a directory specification (obtained with
getwd or equivalent) with a non-absolute file name. */
@@ -61,9 +57,6 @@ int flag_gnu_xref;
#ifndef FALSE
#define FALSE 0
#endif
-#ifndef NULL
-#define NULL 0
-#endif
#define PALLOC(typ) ((typ *) calloc(1,sizeof(typ)))
@@ -128,30 +121,14 @@ static tree last_fndecl = NULL;
/* Forward definitions */
/* */
/************************************************************************/
-
-extern void GNU_xref_begin();
-extern void GNU_xref_end();
-extern void GNU_xref_file();
-extern void GNU_xref_start_scope();
-extern void GNU_xref_end_scope();
-extern void GNU_xref_ref();
-extern void GNU_xref_decl();
-extern void GNU_xref_call();
-extern void GNU_xref_function();
-extern void GNU_xref_assign();
-extern void GNU_xref_hier();
-extern void GNU_xref_member();
-
-static void gen_assign();
-static XREF_FILE find_file();
-static char * filename();
-static char * fctname();
-static char * declname();
-static void simplify_type();
-static char * fixname();
-static void open_xref_file();
-
-extern char * type_as_string();
+static void gen_assign PROTO((XREF_FILE, tree));
+static XREF_FILE find_file PROTO((char *));
+static char * filename PROTO((XREF_FILE));
+static char * fctname PROTO((tree));
+static char * declname PROTO((tree));
+static void simplify_type PROTO((char *));
+static char * fixname PROTO((char *, char *));
+static void open_xref_file PROTO((char *));
/* Start cross referencing. FILE is the name of the file we xref. */
@@ -183,7 +160,7 @@ GNU_xref_end (ect)
if (xf == NULL) return;
while (cur_scope != NULL)
- GNU_xref_end_scope(cur_scope->gid,0,0,0,0);
+ GNU_xref_end_scope(cur_scope->gid,0,0,0);
doing_xref = 0;
@@ -275,10 +252,10 @@ GNU_xref_start_scope (id)
TRNS is ??? */
void
-GNU_xref_end_scope (id,inid,prm,keep,trns)
+GNU_xref_end_scope (id,inid,prm,keep)
HOST_WIDE_INT id;
HOST_WIDE_INT inid;
- int prm,keep,trns;
+ int prm,keep;
{
XREF_FILE xf;
XREF_SCOPE xs,lxs,oxs;
@@ -309,8 +286,10 @@ GNU_xref_end_scope (id,inid,prm,keep,trns)
else if (keep == 2 || inid != 0) stype = "INTERN";
else stype = "EXTERN";
- fprintf (xref_file,"SCP %s %d %d %d %d %s\n",
- filename (xf), xs->start, lineno,xs->lid, inid, stype);
+ fprintf (xref_file, "SCP %s %d %d %d ",
+ filename (xf), xs->start, lineno,xs->lid);
+ fprintf (xref_file, HOST_WIDE_INT_PRINT_DEC, inid);
+ fprintf (xref_file, " %s\n", stype);
if (lxs == NULL) cur_scope = xs->outer;
else lxs->outer = xs->outer;
@@ -343,7 +322,7 @@ GNU_xref_decl (fndecl,decl)
tree decl;
{
XREF_FILE xf,xf1;
- char *cls;
+ char *cls = 0;
char *name;
char buf[10240];
int uselin;
@@ -400,7 +379,7 @@ GNU_xref_decl (fndecl,decl)
}
else if (TREE_CODE (decl) == TEMPLATE_DECL)
{
- if (DECL_TEMPLATE_IS_CLASS (decl))
+ if (TREE_CODE (DECL_RESULT (decl)) == TYPE_DECL)
cls = "CLASSTEMP";
else if (TREE_CODE (DECL_RESULT (decl)) == FUNCTION_DECL)
cls = "FUNCTEMP";
@@ -562,6 +541,19 @@ gen_assign(xf, name)
fprintf(xref_file, "ASG %s %d %s\n", filename(xf), lineno, s);
}
+static char*
+classname (cls)
+ tree cls;
+{
+ if (cls && TREE_CODE_CLASS (TREE_CODE (cls)) == 't')
+ cls = TYPE_NAME (cls);
+ if (cls && TREE_CODE_CLASS (TREE_CODE (cls)) == 'd')
+ cls = DECL_NAME (cls);
+ if (cls && TREE_CODE (cls) == IDENTIFIER_NODE)
+ return IDENTIFIER_POINTER (cls);
+ return "?";
+}
+
/* Output cross-reference info about a class hierarchy.
CLS is the class type of interest. BASE is a baseclass
for CLS. PUB and VIRT give the access info about
@@ -569,10 +561,11 @@ gen_assign(xf, name)
of CLS.
??? Needs to handle nested classes. */
+
void
GNU_xref_hier(cls, base, pub, virt, frnd)
- char *cls;
- char *base;
+ tree cls;
+ tree base;
int pub;
int virt;
int frnd;
@@ -584,7 +577,8 @@ GNU_xref_hier(cls, base, pub, virt, frnd)
if (xf == NULL) return;
fprintf(xref_file, "HIE %s %d %s %s %d %d %d\n",
- filename(xf), lineno, cls, base, pub, virt, frnd);
+ filename(xf), lineno, classname (cls), classname (base),
+ pub, virt, frnd);
}
/* Output cross-reference info about class members. CLS
@@ -599,7 +593,9 @@ GNU_xref_member(cls, fld)
char *prot;
int confg, pure;
char *d;
+#ifdef XREF_SHORT_MEMBER_NAMES
int i;
+#endif
char buf[1024], bufa[1024];
if (!doing_xref) return;
@@ -621,8 +617,10 @@ GNU_xref_member(cls, fld)
pure = 1;
d = IDENTIFIER_POINTER(cls);
- sprintf(buf, "%d%s", strlen(d), d);
+ sprintf(buf, "%d%s", (int) strlen(d), d);
+#ifdef XREF_SHORT_MEMBER_NAMES
i = strlen(buf);
+#endif
strcpy(bufa, declname(fld));
#ifdef XREF_SHORT_MEMBER_NAMES
@@ -643,7 +641,7 @@ GNU_xref_member(cls, fld)
filename(xf), fld->decl.linenum, d, bufa, prot,
(TREE_CODE (fld) == FUNCTION_DECL ? 0 : 1),
(DECL_INLINE (fld) ? 1 : 0),
- (DECL_FRIEND_P(fld) ? 1 : 0),
+ (DECL_LANG_SPECIFIC(fld) && DECL_FRIEND_P(fld) ? 1 : 0),
(DECL_VINDEX(fld) ? 1 : 0),
(TREE_STATIC(fld) ? 1 : 0),
pure, confg);
@@ -733,7 +731,7 @@ simplify_type(typ)
int lvl, i;
i = strlen(typ);
- while (i > 0 && isspace(typ[i-1])) typ[--i] = 0;
+ while (i > 0 && ISSPACE(typ[i-1])) typ[--i] = 0;
if (i > 7 && STREQL(&typ[i-5], "const"))
{
diff --git a/contrib/gcc/cplus-dem.c b/contrib/gcc/cplus-dem.c
index 3eb27cc..1a3ec90 100644
--- a/contrib/gcc/cplus-dem.c
+++ b/contrib/gcc/cplus-dem.c
@@ -1,5 +1,5 @@
/* Demangler for GNU C++
- Copyright 1989, 1991, 1994, 1995 Free Software Foundation, Inc.
+ Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp)
Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
@@ -23,12 +23,20 @@ Boston, MA 02111-1307, USA. */
This file imports xmalloc and xrealloc, which are like malloc and
realloc except that they generate a fatal error if there is no
- available memory. */
+ available memory. */
+
+/* This file lives in both GCC and libiberty. When making changes, please
+ try not to break either. */
#include <ctype.h>
+#include <sys/types.h>
#include <string.h>
#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
#include <demangle.h>
#undef CURRENT_DEMANGLING_STYLE
#define CURRENT_DEMANGLING_STYLE work->options
@@ -36,11 +44,13 @@ Boston, MA 02111-1307, USA. */
extern char *xmalloc PARAMS((unsigned));
extern char *xrealloc PARAMS((char *, unsigned));
-char *
+static const char *mystrstr PARAMS ((const char *, const char *));
+
+static const char *
mystrstr (s1, s2)
- char *s1, *s2;
+ const char *s1, *s2;
{
- register char *p = s1;
+ register const char *p = s1;
register int len = strlen (s2);
for (; (p = strchr (p, *s2)) != 0; p++)
@@ -67,7 +77,7 @@ mystrstr (s1, s2)
We could avoid this if we could just get g++ to tell us what the actual
cplus marker character is as part of the debug information, perhaps by
ensuring that it is the character that terminates the gcc<n>_compiled
- marker symbol (FIXME). */
+ marker symbol (FIXME). */
#if !defined (CPLUS_MARKER)
#define CPLUS_MARKER '$'
@@ -81,22 +91,43 @@ void
set_cplus_marker_for_demangling (ch)
int ch;
{
- cplus_markers[0] = ch;
+ cplus_markers[0] = ch;
}
+typedef struct string /* Beware: these aren't required to be */
+{ /* '\0' terminated. */
+ char *b; /* pointer to start of string */
+ char *p; /* pointer after last character */
+ char *e; /* pointer after end of allocated space */
+} string;
+
/* Stuff that is shared between sub-routines.
- * Using a shared structure allows cplus_demangle to be reentrant. */
+ Using a shared structure allows cplus_demangle to be reentrant. */
struct work_stuff
{
int options;
char **typevec;
+ char **ktypevec;
+ char **btypevec;
+ int numk;
+ int numb;
+ int ksize;
+ int bsize;
int ntypes;
int typevec_size;
int constructor;
int destructor;
int static_type; /* A static member function */
int const_type; /* A const member function */
+ int volatile_type; /* A volatile member function */
+ char **tmpl_argvec; /* Template function arguments. */
+ int ntmpl_args; /* The number of template function arguments. */
+ int forgetting_types; /* Nonzero if we are not remembering the types
+ we see. */
+ string* previous_argument; /* The last function argument demangled. */
+ int nrepeats; /* The number of times to repeat the previous
+ argument. */
};
#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI)
@@ -185,22 +216,20 @@ static const struct optable
{"min", "<?", 0}, /* old */
{"mn", "<?", DMGL_ANSI}, /* pseudo-ansi */
{"nop", "", 0}, /* old (for operator=) */
- {"rm", "->*", DMGL_ANSI} /* ansi */
+ {"rm", "->*", DMGL_ANSI}, /* ansi */
+ {"sz", "sizeof ", DMGL_ANSI} /* pseudo-ansi */
};
-typedef struct string /* Beware: these aren't required to be */
-{ /* '\0' terminated. */
- char *b; /* pointer to start of string */
- char *p; /* pointer after last character */
- char *e; /* pointer after end of allocated space */
-} string;
-
#define STRING_EMPTY(str) ((str) -> b == (str) -> p)
#define PREPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
- string_prepend(str, " ");}
+ string_prepend(str, " ");}
#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \
- string_append(str, " ");}
+ string_append(str, " ");}
+#define LEN_STRING(str) ( (STRING_EMPTY(str))?0:((str)->p - (str)->b))
+
+/* The scope separator appropriate for the language being demangled. */
+#define SCOPE_STRING(work) "::"
#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */
#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */
@@ -210,14 +239,34 @@ typedef struct string /* Beware: these aren't required to be */
static char *
mop_up PARAMS ((struct work_stuff *, string *, int));
+static void
+squangle_mop_up PARAMS ((struct work_stuff *));
+
#if 0
static int
-demangle_method_args PARAMS ((struct work_stuff *work, const char **, string *));
+demangle_method_args PARAMS ((struct work_stuff *, const char **, string *));
#endif
+static char *
+internal_cplus_demangle PARAMS ((struct work_stuff *, const char *));
+
+static int
+demangle_template_template_parm PARAMS ((struct work_stuff *work,
+ const char **, string *));
+
static int
demangle_template PARAMS ((struct work_stuff *work, const char **, string *,
- string *));
+ string *, int, int));
+
+static int
+arm_pt PARAMS ((struct work_stuff *, const char *, int, const char **,
+ const char **));
+
+static void
+demangle_arm_pt PARAMS ((struct work_stuff *, const char **, int, string *));
+
+static int
+demangle_class_name PARAMS ((struct work_stuff *, const char **, string *));
static int
demangle_qualified PARAMS ((struct work_stuff *, const char **, string *,
@@ -239,7 +288,7 @@ static int
gnu_special PARAMS ((struct work_stuff *, const char **, string *));
static int
-arm_special PARAMS ((struct work_stuff *, const char **, string *));
+arm_special PARAMS ((const char **, string *));
static void
string_need PARAMS ((string *, int));
@@ -279,10 +328,16 @@ get_count PARAMS ((const char **, int *));
static int
consume_count PARAMS ((const char **));
+static int
+consume_count_with_underscores PARAMS ((const char**));
+
static int
demangle_args PARAMS ((struct work_stuff *, const char **, string *));
static int
+demangle_nested_args PARAMS ((struct work_stuff*, const char**, string*));
+
+static int
do_type PARAMS ((struct work_stuff *, const char **, string *));
static int
@@ -296,38 +351,90 @@ static void
remember_type PARAMS ((struct work_stuff *, const char *, int));
static void
+remember_Btype PARAMS ((struct work_stuff *, const char *, int, int));
+
+static int
+register_Btype PARAMS ((struct work_stuff *));
+
+static void
+remember_Ktype PARAMS ((struct work_stuff *, const char *, int));
+
+static void
forget_types PARAMS ((struct work_stuff *));
static void
+forget_B_and_K_types PARAMS ((struct work_stuff *));
+
+static void
string_prepends PARAMS ((string *, string *));
+static int
+demangle_template_value_parm PARAMS ((struct work_stuff*,
+ const char**, string*));
+
/* Translate count to integer, consuming tokens in the process.
Conversion terminates on the first non-digit character.
Trying to consume something that isn't a count results in
- no consumption of input and a return of 0. */
+ no consumption of input and a return of 0. */
static int
consume_count (type)
- const char **type;
+ const char **type;
{
- int count = 0;
+ int count = 0;
- while (isdigit (**type))
- {
- count *= 10;
- count += **type - '0';
- (*type)++;
- }
- return (count);
+ while (isdigit (**type))
+ {
+ count *= 10;
+ count += **type - '0';
+ (*type)++;
+ }
+ return (count);
+}
+
+
+/* Like consume_count, but for counts that are preceded and followed
+ by '_' if they are greater than 10. Also, -1 is returned for
+ failure, since 0 can be a valid value. */
+
+static int
+consume_count_with_underscores (mangled)
+ const char **mangled;
+{
+ int idx;
+
+ if (**mangled == '_')
+ {
+ (*mangled)++;
+ if (!isdigit (**mangled))
+ return -1;
+
+ idx = consume_count (mangled);
+ if (**mangled != '_')
+ /* The trailing underscore was missing. */
+ return -1;
+
+ (*mangled)++;
+ }
+ else
+ {
+ if (**mangled < '0' || **mangled > '9')
+ return -1;
+
+ idx = **mangled - '0';
+ (*mangled)++;
+ }
+
+ return idx;
}
int
cplus_demangle_opname (opname, result, options)
- char *opname;
+ const char *opname;
char *result;
int options;
{
- int len, i, len1, ret;
+ int len, len1, ret;
string type;
struct work_stuff work[1];
const char *tem;
@@ -335,10 +442,11 @@ cplus_demangle_opname (opname, result, options)
len = strlen(opname);
result[0] = '\0';
ret = 0;
+ memset ((char *) work, 0, sizeof (work));
work->options = options;
if (opname[0] == '_' && opname[1] == '_'
- && opname[2] == 'o' && opname[3] == 'p')
+ && opname[2] == 'o' && opname[3] == 'p')
{
/* ANSI. */
/* type conversion operator. */
@@ -358,6 +466,7 @@ cplus_demangle_opname (opname, result, options)
if (opname[4] == '\0')
{
/* Operator. */
+ size_t i;
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
if (strlen (optable[i].in) == 2
@@ -374,7 +483,8 @@ cplus_demangle_opname (opname, result, options)
{
if (opname[2] == 'a' && opname[5] == '\0')
{
- /* Assignment. */
+ /* Assignment. */
+ size_t i;
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
if (strlen (optable[i].in) == 3
@@ -390,14 +500,15 @@ cplus_demangle_opname (opname, result, options)
}
}
else if (len >= 3
- && opname[0] == 'o'
- && opname[1] == 'p'
- && strchr (cplus_markers, opname[2]) != NULL)
+ && opname[0] == 'o'
+ && opname[1] == 'p'
+ && strchr (cplus_markers, opname[2]) != NULL)
{
/* see if it's an assignment expression */
if (len >= 10 /* op$assign_ */
&& memcmp (opname + 3, "assign_", 7) == 0)
{
+ size_t i;
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
len1 = len - 10;
@@ -414,6 +525,7 @@ cplus_demangle_opname (opname, result, options)
}
else
{
+ size_t i;
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
len1 = len - 3;
@@ -441,6 +553,7 @@ cplus_demangle_opname (opname, result, options)
ret = 1;
}
}
+ squangle_mop_up (work);
return ret;
}
@@ -450,12 +563,12 @@ cplus_demangle_opname (opname, result, options)
If OPTIONS & DMGL_ANSI == 1, return the ANSI name;
if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */
-char *
+const char *
cplus_mangle_opname (opname, options)
- char *opname;
+ const char *opname;
int options;
{
- int i;
+ size_t i;
int len;
len = strlen (opname);
@@ -464,26 +577,11 @@ cplus_mangle_opname (opname, options)
if (strlen (optable[i].out) == len
&& (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI)
&& memcmp (optable[i].out, opname, len) == 0)
- return ((char *)optable[i].in);
+ return optable[i].in;
}
return (0);
}
-/* check to see whether MANGLED can match TEXT in the first TEXT_LEN
- characters. */
-
-int cplus_match (mangled, text, text_len)
- const char *mangled;
- char *text;
- int text_len;
-{
- if (strncmp (mangled, text, text_len) != 0) {
- return(0); /* cannot match either */
- } else {
- return(1); /* matches mangled, may match demangled */
- }
-}
-
/* char *cplus_demangle (const char *mangled, int options)
If MANGLED is a mangled function name produced by GNU C++, then
@@ -517,18 +615,47 @@ cplus_demangle (mangled, options)
const char *mangled;
int options;
{
+ char *ret;
+ struct work_stuff work[1];
+ memset ((char *) work, 0, sizeof (work));
+ work -> options = options;
+ if ((work -> options & DMGL_STYLE_MASK) == 0)
+ work -> options |= (int) current_demangling_style & DMGL_STYLE_MASK;
+
+ ret = internal_cplus_demangle (work, mangled);
+ squangle_mop_up (work);
+ return (ret);
+}
+
+
+/* This function performs most of what cplus_demangle use to do, but
+ to be able to demangle a name with a B, K or n code, we need to
+ have a longer term memory of what types have been seen. The original
+ now intializes and cleans up the squangle code info, while internal
+ calls go directly to this routine to avoid resetting that info. */
+
+static char *
+internal_cplus_demangle (work, mangled)
+ struct work_stuff *work;
+ const char *mangled;
+{
+
string decl;
int success = 0;
- struct work_stuff work[1];
char *demangled = NULL;
+ int s1,s2,s3,s4;
+ int saved_volatile_type;
+ s1 = work->constructor;
+ s2 = work->destructor;
+ s3 = work->static_type;
+ s4 = work->const_type;
+ saved_volatile_type = work->volatile_type;
+ work->constructor = work->destructor = 0;
+ work->static_type = work->const_type = 0;
+ work->volatile_type = 0;
if ((mangled != NULL) && (*mangled != '\0'))
{
- memset ((char *) work, 0, sizeof (work));
- work -> options = options;
- if ((work->options & DMGL_STYLE_MASK) == 0)
- work->options |= (int)current_demangling_style & DMGL_STYLE_MASK;
-
string_init (&decl);
/* First check to see if gnu style demangling is active and if the
@@ -536,7 +663,7 @@ cplus_demangle (mangled, options)
recognize one of the gnu special forms rather than looking for a
standard prefix. In particular, don't worry about whether there
is a "__" string in the mangled string. Consider "_$_5__foo" for
- example. */
+ example. */
if ((AUTO_DEMANGLING || GNU_DEMANGLING))
{
@@ -552,19 +679,44 @@ cplus_demangle (mangled, options)
}
if (work->constructor == 2)
{
- string_prepend(&decl, "global constructors keyed to ");
+ string_prepend (&decl, "global constructors keyed to ");
work->constructor = 0;
}
else if (work->destructor == 2)
{
- string_prepend(&decl, "global destructors keyed to ");
+ string_prepend (&decl, "global destructors keyed to ");
work->destructor = 0;
}
demangled = mop_up (work, &decl, success);
}
+ work->constructor = s1;
+ work->destructor = s2;
+ work->static_type = s3;
+ work->const_type = s4;
+ work->volatile_type = saved_volatile_type;
return (demangled);
}
+
+/* Clear out and squangling related storage */
+static void
+squangle_mop_up (work)
+ struct work_stuff *work;
+{
+ /* clean up the B and K type mangling types. */
+ forget_B_and_K_types (work);
+ if (work -> btypevec != NULL)
+ {
+ free ((char *) work -> btypevec);
+ }
+ if (work -> ktypevec != NULL)
+ {
+ free ((char *) work -> ktypevec);
+ }
+}
+
+/* Clear out any mangled storage */
+
static char *
mop_up (work, declp, success)
struct work_stuff *work;
@@ -573,16 +725,33 @@ mop_up (work, declp, success)
{
char *demangled = NULL;
- /* Discard the remembered types, if any. */
+ /* Discard the remembered types, if any. */
forget_types (work);
if (work -> typevec != NULL)
{
free ((char *) work -> typevec);
+ work -> typevec = NULL;
}
-
+ if (work->tmpl_argvec)
+ {
+ int i;
+
+ for (i = 0; i < work->ntmpl_args; i++)
+ if (work->tmpl_argvec[i])
+ free ((char*) work->tmpl_argvec[i]);
+
+ free ((char*) work->tmpl_argvec);
+ work->tmpl_argvec = NULL;
+ }
+ if (work->previous_argument)
+ {
+ string_delete (work->previous_argument);
+ free ((char*) work->previous_argument);
+ }
+
/* If demangling was successful, ensure that the demangled string is null
- terminated and return it. Otherwise, free the demangling decl. */
+ terminated and return it. Otherwise, free the demangling decl. */
if (!success)
{
@@ -624,8 +793,7 @@ DESCRIPTION
Demangling GNU style mangled names is nasty because there is no
explicit token that marks the start of the outermost function
- argument list.
-*/
+ argument list. */
static int
demangle_signature (work, mangled, declp)
@@ -636,6 +804,7 @@ demangle_signature (work, mangled, declp)
int success = 1;
int func_done = 0;
int expect_func = 0;
+ int expect_return_type = 0;
const char *oldmangled = NULL;
string trawname;
string tname;
@@ -644,150 +813,208 @@ demangle_signature (work, mangled, declp)
{
switch (**mangled)
{
- case 'Q':
- oldmangled = *mangled;
- success = demangle_qualified (work, mangled, declp, 1, 0);
- if (success)
- {
- remember_type (work, oldmangled, *mangled - oldmangled);
- }
- if (AUTO_DEMANGLING || GNU_DEMANGLING)
- {
- expect_func = 1;
- }
- oldmangled = NULL;
- break;
+ case 'Q':
+ oldmangled = *mangled;
+ success = demangle_qualified (work, mangled, declp, 1, 0);
+ if (success)
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ expect_func = 1;
+ oldmangled = NULL;
+ break;
+
+ case 'K':
+ oldmangled = *mangled;
+ success = demangle_qualified (work, mangled, declp, 1, 0);
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ expect_func = 1;
+ }
+ oldmangled = NULL;
+ break;
- case 'S':
- /* Static member function */
- if (oldmangled == NULL)
- {
- oldmangled = *mangled;
- }
- (*mangled)++;
- work -> static_type = 1;
- break;
+ case 'S':
+ /* Static member function */
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ (*mangled)++;
+ work -> static_type = 1;
+ break;
- case 'C':
- /* a const member function */
- if (oldmangled == NULL)
- {
- oldmangled = *mangled;
- }
- (*mangled)++;
+ case 'C':
+ case 'V':
+ if (**mangled == 'C')
work -> const_type = 1;
- break;
+ else
+ work->volatile_type = 1;
+
+ /* a qualified member function */
+ if (oldmangled == NULL)
+ oldmangled = *mangled;
+ (*mangled)++;
+ break;
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- if (oldmangled == NULL)
- {
- oldmangled = *mangled;
- }
- success = demangle_class (work, mangled, declp);
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ success = demangle_class (work, mangled, declp);
+ if (success)
+ {
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ }
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ expect_func = 1;
+ }
+ oldmangled = NULL;
+ break;
+
+ case 'B':
+ {
+ string s;
+ success = do_type (work, mangled, &s);
if (success)
{
- remember_type (work, oldmangled, *mangled - oldmangled);
- }
- if (AUTO_DEMANGLING || GNU_DEMANGLING)
- {
- expect_func = 1;
+ string_append (&s, SCOPE_STRING (work));
+ string_prepends (declp, &s);
}
oldmangled = NULL;
- break;
-
- case 'F':
- /* Function */
- /* ARM style demangling includes a specific 'F' character after
+ expect_func = 1;
+ }
+ break;
+
+ case 'F':
+ /* Function */
+ /* ARM style demangling includes a specific 'F' character after
the class name. For GNU style, it is just implied. So we can
safely just consume any 'F' at this point and be compatible
- with either style. */
+ with either style. */
- oldmangled = NULL;
- func_done = 1;
- (*mangled)++;
+ oldmangled = NULL;
+ func_done = 1;
+ (*mangled)++;
- /* For lucid/ARM style we have to forget any types we might
- have remembered up to this point, since they were not argument
- types. GNU style considers all types seen as available for
- back references. See comment in demangle_args() */
+ /* For lucid/ARM style we have to forget any types we might
+ have remembered up to this point, since they were not argument
+ types. GNU style considers all types seen as available for
+ back references. See comment in demangle_args() */
- if (LUCID_DEMANGLING || ARM_DEMANGLING)
- {
- forget_types (work);
- }
- success = demangle_args (work, mangled, declp);
- break;
+ if (LUCID_DEMANGLING || ARM_DEMANGLING)
+ {
+ forget_types (work);
+ }
+ success = demangle_args (work, mangled, declp);
+ break;
- case 't':
- /* G++ Template */
- string_init(&trawname);
- string_init(&tname);
- if (oldmangled == NULL)
- {
- oldmangled = *mangled;
- }
- success = demangle_template (work, mangled, &tname, &trawname);
- if (success)
- {
- remember_type (work, oldmangled, *mangled - oldmangled);
- }
- string_append(&tname, "::");
- string_prepends(declp, &tname);
- if (work -> destructor & 1)
- {
- string_prepend (&trawname, "~");
- string_appends (declp, &trawname);
- work->destructor -= 1;
- }
- if ((work->constructor & 1) || (work->destructor & 1))
- {
- string_appends (declp, &trawname);
- work->constructor -= 1;
- }
- string_delete(&trawname);
- string_delete(&tname);
- oldmangled = NULL;
- expect_func = 1;
- break;
+ case 't':
+ /* G++ Template */
+ string_init(&trawname);
+ string_init(&tname);
+ if (oldmangled == NULL)
+ {
+ oldmangled = *mangled;
+ }
+ success = demangle_template (work, mangled, &tname,
+ &trawname, 1, 1);
+ if (success)
+ {
+ remember_type (work, oldmangled, *mangled - oldmangled);
+ }
+ string_append(&tname, SCOPE_STRING (work));
+ string_prepends(declp, &tname);
+ if (work -> destructor & 1)
+ {
+ string_prepend (&trawname, "~");
+ string_appends (declp, &trawname);
+ work->destructor -= 1;
+ }
+ if ((work->constructor & 1) || (work->destructor & 1))
+ {
+ string_appends (declp, &trawname);
+ work->constructor -= 1;
+ }
+ string_delete(&trawname);
+ string_delete(&tname);
+ oldmangled = NULL;
+ expect_func = 1;
+ break;
- case '_':
+ case '_':
+ if (GNU_DEMANGLING && expect_return_type)
+ {
+ /* Read the return type. */
+ string return_type;
+ string_init (&return_type);
+
+ (*mangled)++;
+ success = do_type (work, mangled, &return_type);
+ APPEND_BLANK (&return_type);
+
+ string_prepends (declp, &return_type);
+ string_delete (&return_type);
+ break;
+ }
+ else
/* At the outermost level, we cannot have a return type specified,
so if we run into another '_' at this point we are dealing with
a mangled name that is either bogus, or has been mangled by
some algorithm we don't know how to deal with. So just
- reject the entire demangling. */
+ reject the entire demangling. */
success = 0;
- break;
+ break;
- default:
- if (AUTO_DEMANGLING || GNU_DEMANGLING)
- {
- /* Assume we have stumbled onto the first outermost function
- argument token, and start processing args. */
- func_done = 1;
- success = demangle_args (work, mangled, declp);
- }
- else
- {
- /* Non-GNU demanglers use a specific token to mark the start
- of the outermost function argument tokens. Typically 'F',
- for ARM-demangling, for example. So if we find something
- we are not prepared for, it must be an error. */
- success = 0;
- }
- break;
- }
-/*
- if (AUTO_DEMANGLING || GNU_DEMANGLING)
-*/
- {
- if (success && expect_func)
+ case 'H':
+ if (GNU_DEMANGLING)
{
+ /* A G++ template function. Read the template arguments. */
+ success = demangle_template (work, mangled, declp, 0, 0,
+ 0);
+ if (!(work->constructor & 1))
+ expect_return_type = 1;
+ (*mangled)++;
+ break;
+ }
+ else
+ /* fall through */
+ {;}
+
+ default:
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ {
+ /* Assume we have stumbled onto the first outermost function
+ argument token, and start processing args. */
func_done = 1;
success = demangle_args (work, mangled, declp);
}
+ else
+ {
+ /* Non-GNU demanglers use a specific token to mark the start
+ of the outermost function argument tokens. Typically 'F',
+ for ARM-demangling, for example. So if we find something
+ we are not prepared for, it must be an error. */
+ success = 0;
+ }
+ break;
}
+ /*
+ if (AUTO_DEMANGLING || GNU_DEMANGLING)
+ */
+ {
+ if (success && expect_func)
+ {
+ func_done = 1;
+ success = demangle_args (work, mangled, declp);
+ /* Since template include the mangling of their return types,
+ we must set expect_func to 0 so that we don't try do
+ demangle more arguments the next time we get here. */
+ expect_func = 0;
+ }
+ }
}
if (success && !func_done)
{
@@ -798,18 +1025,17 @@ demangle_signature (work, mangled, declp)
first case, and need to ensure that the '(void)' gets added to
the current declp. Note that with ARM, the first case
represents the name of a static data member 'foo::bar',
- which is in the current declp, so we leave it alone. */
+ which is in the current declp, so we leave it alone. */
success = demangle_args (work, mangled, declp);
}
}
if (success && work -> static_type && PRINT_ARG_TYPES)
- {
- string_append (declp, " static");
- }
+ string_append (declp, " static");
if (success && work -> const_type && PRINT_ARG_TYPES)
- {
- string_append (declp, " const");
- }
+ string_append (declp, " const");
+ else if (success && work->volatile_type && PRINT_ARG_TYPES)
+ string_append (declp, " volatile");
+
return (success);
}
@@ -839,44 +1065,420 @@ demangle_method_args (work, mangled, declp)
#endif
static int
-demangle_template (work, mangled, tname, trawname)
+demangle_template_template_parm (work, mangled, tname)
+ struct work_stuff *work;
+ const char **mangled;
+ string *tname;
+{
+ int i;
+ int r;
+ int need_comma = 0;
+ int success = 1;
+ string temp;
+
+ string_append (tname, "template <");
+ /* get size of template parameter list */
+ if (get_count (mangled, &r))
+ {
+ for (i = 0; i < r; i++)
+ {
+ if (need_comma)
+ {
+ string_append (tname, ", ");
+ }
+
+ /* Z for type parameters */
+ if (**mangled == 'Z')
+ {
+ (*mangled)++;
+ string_append (tname, "class");
+ }
+ /* z for template parameters */
+ else if (**mangled == 'z')
+ {
+ (*mangled)++;
+ success =
+ demangle_template_template_parm (work, mangled, tname);
+ if (!success)
+ {
+ break;
+ }
+ }
+ else
+ {
+ /* temp is initialized in do_type */
+ success = do_type (work, mangled, &temp);
+ if (success)
+ {
+ string_appends (tname, &temp);
+ }
+ string_delete(&temp);
+ if (!success)
+ {
+ break;
+ }
+ }
+ need_comma = 1;
+ }
+
+ }
+ if (tname->p[-1] == '>')
+ string_append (tname, " ");
+ string_append (tname, "> class");
+ return (success);
+}
+
+static int
+demangle_integral_value (work, mangled, s)
+ struct work_stuff *work;
+ const char** mangled;
+ string* s;
+{
+ int success;
+
+ if (**mangled == 'E')
+ {
+ int need_operator = 0;
+
+ success = 1;
+ string_appendn (s, "(", 1);
+ (*mangled)++;
+ while (success && **mangled != 'W' && **mangled != '\0')
+ {
+ if (need_operator)
+ {
+ size_t i;
+ size_t len;
+
+ success = 0;
+
+ len = strlen (*mangled);
+
+ for (i = 0;
+ i < sizeof (optable) / sizeof (optable [0]);
+ ++i)
+ {
+ size_t l = strlen (optable[i].in);
+
+ if (l <= len
+ && memcmp (optable[i].in, *mangled, l) == 0)
+ {
+ string_appendn (s, " ", 1);
+ string_append (s, optable[i].out);
+ string_appendn (s, " ", 1);
+ success = 1;
+ (*mangled) += l;
+ break;
+ }
+ }
+
+ if (!success)
+ break;
+ }
+ else
+ need_operator = 1;
+
+ success = demangle_template_value_parm (work, mangled, s);
+ }
+
+ if (**mangled != 'W')
+ success = 0;
+ else
+ {
+ string_appendn (s, ")", 1);
+ (*mangled)++;
+ }
+ }
+ else if (**mangled == 'Q' || **mangled == 'K')
+ success = demangle_qualified (work, mangled, s, 0, 1);
+ else
+ {
+ success = 0;
+
+ if (**mangled == 'm')
+ {
+ string_appendn (s, "-", 1);
+ (*mangled)++;
+ }
+ while (isdigit (**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ success = 1;
+ }
+ }
+
+ return success;
+}
+
+static int
+demangle_template_value_parm (work, mangled, s)
+ struct work_stuff *work;
+ const char **mangled;
+ string* s;
+{
+ const char *old_p = *mangled;
+ int is_pointer = 0;
+ int is_real = 0;
+ int is_integral = 0;
+ int is_char = 0;
+ int is_bool = 0;
+ int done = 0;
+ int success = 1;
+
+ while (*old_p && !done)
+ {
+ switch (*old_p)
+ {
+ case 'P':
+ case 'p':
+ case 'R':
+ done = is_pointer = 1;
+ break;
+ case 'C': /* const */
+ case 'S': /* explicitly signed [char] */
+ case 'U': /* unsigned */
+ case 'V': /* volatile */
+ case 'F': /* function */
+ case 'M': /* member function */
+ case 'O': /* ??? */
+ case 'J': /* complex */
+ old_p++;
+ continue;
+ case 'E': /* expression */
+ case 'Q': /* qualified name */
+ case 'K': /* qualified name */
+ done = is_integral = 1;
+ break;
+ case 'B': /* remembered type */
+ case 'T': /* remembered type */
+ abort ();
+ break;
+ case 'v': /* void */
+ abort ();
+ break;
+ case 'x': /* long long */
+ case 'l': /* long */
+ case 'i': /* int */
+ case 's': /* short */
+ case 'w': /* wchar_t */
+ done = is_integral = 1;
+ break;
+ case 'b': /* bool */
+ done = is_bool = 1;
+ break;
+ case 'c': /* char */
+ done = is_char = 1;
+ break;
+ case 'r': /* long double */
+ case 'd': /* double */
+ case 'f': /* float */
+ done = is_real = 1;
+ break;
+ default:
+ /* it's probably user defined type, let's assume
+ it's integral, it seems hard to figure out
+ what it really is */
+ done = is_integral = 1;
+ }
+ }
+ if (**mangled == 'Y')
+ {
+ /* The next argument is a template parameter. */
+ int idx;
+
+ (*mangled)++;
+ idx = consume_count_with_underscores (mangled);
+ if (idx == -1
+ || (work->tmpl_argvec && idx >= work->ntmpl_args)
+ || consume_count_with_underscores (mangled) == -1)
+ return -1;
+ if (work->tmpl_argvec)
+ string_append (s, work->tmpl_argvec[idx]);
+ else
+ {
+ char buf[10];
+ sprintf(buf, "T%d", idx);
+ string_append (s, buf);
+ }
+ }
+ else if (is_integral)
+ success = demangle_integral_value (work, mangled, s);
+ else if (is_char)
+ {
+ char tmp[2];
+ int val;
+ if (**mangled == 'm')
+ {
+ string_appendn (s, "-", 1);
+ (*mangled)++;
+ }
+ string_appendn (s, "'", 1);
+ val = consume_count(mangled);
+ if (val == 0)
+ return -1;
+ tmp[0] = (char)val;
+ tmp[1] = '\0';
+ string_appendn (s, &tmp[0], 1);
+ string_appendn (s, "'", 1);
+ }
+ else if (is_bool)
+ {
+ int val = consume_count (mangled);
+ if (val == 0)
+ string_appendn (s, "false", 5);
+ else if (val == 1)
+ string_appendn (s, "true", 4);
+ else
+ success = 0;
+ }
+ else if (is_real)
+ {
+ if (**mangled == 'm')
+ {
+ string_appendn (s, "-", 1);
+ (*mangled)++;
+ }
+ while (isdigit (**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ }
+ if (**mangled == '.') /* fraction */
+ {
+ string_appendn (s, ".", 1);
+ (*mangled)++;
+ while (isdigit (**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ if (**mangled == 'e') /* exponent */
+ {
+ string_appendn (s, "e", 1);
+ (*mangled)++;
+ while (isdigit (**mangled))
+ {
+ string_appendn (s, *mangled, 1);
+ (*mangled)++;
+ }
+ }
+ }
+ else if (is_pointer)
+ {
+ int symbol_len = consume_count (mangled);
+ if (symbol_len == 0)
+ return -1;
+ if (symbol_len == 0)
+ string_appendn (s, "0", 1);
+ else
+ {
+ char *p = xmalloc (symbol_len + 1), *q;
+ strncpy (p, *mangled, symbol_len);
+ p [symbol_len] = '\0';
+ q = internal_cplus_demangle (work, p);
+ string_appendn (s, "&", 1);
+ if (q)
+ {
+ string_append (s, q);
+ free (q);
+ }
+ else
+ string_append (s, p);
+ free (p);
+ }
+ *mangled += symbol_len;
+ }
+
+ return success;
+}
+
+/* Demangle the template name in MANGLED. The full name of the
+ template (e.g., S<int>) is placed in TNAME. The name without the
+ template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is
+ non-NULL. If IS_TYPE is nonzero, this template is a type template,
+ not a function template. If both IS_TYPE and REMEMBER are nonzero,
+ the tmeplate is remembered in the list of back-referenceable
+ types. */
+
+static int
+demangle_template (work, mangled, tname, trawname, is_type, remember)
struct work_stuff *work;
const char **mangled;
string *tname;
string *trawname;
+ int is_type;
+ int remember;
{
int i;
- int is_pointer;
- int is_real;
- int is_integral;
- int is_char;
- int is_bool;
int r;
int need_comma = 0;
int success = 0;
- int done;
- const char *old_p;
const char *start;
- int symbol_len;
string temp;
+ int bindex;
(*mangled)++;
- start = *mangled;
- /* get template name */
- if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r)
+ if (is_type)
{
- return (0);
+ if (remember)
+ bindex = register_Btype (work);
+ start = *mangled;
+ /* get template name */
+ if (**mangled == 'z')
+ {
+ int idx;
+ (*mangled)++;
+ (*mangled)++;
+
+ idx = consume_count_with_underscores (mangled);
+ if (idx == -1
+ || (work->tmpl_argvec && idx >= work->ntmpl_args)
+ || consume_count_with_underscores (mangled) == -1)
+ return (0);
+
+ if (work->tmpl_argvec)
+ {
+ string_append (tname, work->tmpl_argvec[idx]);
+ if (trawname)
+ string_append (trawname, work->tmpl_argvec[idx]);
+ }
+ else
+ {
+ char buf[10];
+ sprintf(buf, "T%d", idx);
+ string_append (tname, buf);
+ if (trawname)
+ string_append (trawname, buf);
+ }
+ }
+ else
+ {
+ if ((r = consume_count (mangled)) == 0 || strlen (*mangled) < r)
+ {
+ return (0);
+ }
+ string_appendn (tname, *mangled, r);
+ if (trawname)
+ string_appendn (trawname, *mangled, r);
+ *mangled += r;
+ }
}
- if (trawname)
- string_appendn (trawname, *mangled, r);
- string_appendn (tname, *mangled, r);
- *mangled += r;
string_append (tname, "<");
/* get size of template parameter list */
if (!get_count (mangled, &r))
{
return (0);
}
+ if (!is_type)
+ {
+ /* Create an array for saving the template argument values. */
+ work->tmpl_argvec = (char**) xmalloc (r * sizeof (char *));
+ work->ntmpl_args = r;
+ for (i = 0; i < r; i++)
+ work->tmpl_argvec[i] = 0;
+ }
for (i = 0; i < r; i++)
{
if (need_comma)
@@ -892,6 +1494,15 @@ demangle_template (work, mangled, tname, trawname)
if (success)
{
string_appends (tname, &temp);
+
+ if (!is_type)
+ {
+ /* Save the template argument. */
+ int len = temp.p - temp.b;
+ work->tmpl_argvec[i] = xmalloc (len + 1);
+ memcpy (work->tmpl_argvec[i], temp.b, len);
+ work->tmpl_argvec[i][len] = '\0';
+ }
}
string_delete(&temp);
if (!success)
@@ -899,169 +1510,84 @@ demangle_template (work, mangled, tname, trawname)
break;
}
}
+ /* z for template parameters */
+ else if (**mangled == 'z')
+ {
+ int r2;
+ (*mangled)++;
+ success = demangle_template_template_parm (work, mangled, tname);
+
+ if (success
+ && (r2 = consume_count (mangled)) > 0 && strlen (*mangled) >= r2)
+ {
+ string_append (tname, " ");
+ string_appendn (tname, *mangled, r2);
+ if (!is_type)
+ {
+ /* Save the template argument. */
+ int len = r2;
+ work->tmpl_argvec[i] = xmalloc (len + 1);
+ memcpy (work->tmpl_argvec[i], *mangled, len);
+ work->tmpl_argvec[i][len] = '\0';
+ }
+ *mangled += r2;
+ }
+ if (!success)
+ {
+ break;
+ }
+ }
else
{
+ string param;
+ string* s;
+
/* otherwise, value parameter */
- old_p = *mangled;
- is_pointer = 0;
- is_real = 0;
- is_integral = 0;
- is_char = 0;
- done = 0;
+
/* temp is initialized in do_type */
success = do_type (work, mangled, &temp);
-/*
- if (success)
+ /*
+ if (success)
{
- string_appends (tname, &temp);
+ string_appends (s, &temp);
}
-*/
+ */
string_delete(&temp);
if (!success)
{
break;
}
-/*
- string_append (tname, "=");
-*/
- while (*old_p && !done)
- {
- switch (*old_p)
- {
- case 'P':
- case 'p':
- case 'R':
- done = is_pointer = 1;
- break;
- case 'C': /* const */
- case 'S': /* explicitly signed [char] */
- case 'U': /* unsigned */
- case 'V': /* volatile */
- case 'F': /* function */
- case 'M': /* member function */
- case 'O': /* ??? */
- old_p++;
- continue;
- case 'Q': /* qualified name */
- done = is_integral = 1;
- break;
- case 'T': /* remembered type */
- abort ();
- break;
- case 'v': /* void */
- abort ();
- break;
- case 'x': /* long long */
- case 'l': /* long */
- case 'i': /* int */
- case 's': /* short */
- case 'w': /* wchar_t */
- done = is_integral = 1;
- break;
- case 'b': /* bool */
- done = is_bool = 1;
- break;
- case 'c': /* char */
- done = is_char = 1;
- break;
- case 'r': /* long double */
- case 'd': /* double */
- case 'f': /* float */
- done = is_real = 1;
- break;
- default:
- /* it's probably user defined type, let's assume
- it's integral, it seems hard to figure out
- what it really is */
- done = is_integral = 1;
- }
- }
- if (is_integral)
- {
- if (**mangled == 'm')
- {
- string_appendn (tname, "-", 1);
- (*mangled)++;
- }
- while (isdigit (**mangled))
- {
- string_appendn (tname, *mangled, 1);
- (*mangled)++;
- }
- }
- else if (is_char)
+ /*
+ string_append (s, "=");
+ */
+
+ if (!is_type)
{
- char tmp[2];
- int val;
- if (**mangled == 'm')
- {
- string_appendn (tname, "-", 1);
- (*mangled)++;
- }
- string_appendn (tname, "'", 1);
- val = consume_count(mangled);
- if (val == 0)
- {
- success = 0;
- break;
- }
- tmp[0] = (char)val;
- tmp[1] = '\0';
- string_appendn (tname, &tmp[0], 1);
- string_appendn (tname, "'", 1);
- }
- else if (is_bool)
- {
- int val = consume_count (mangled);
- if (val == 0)
- string_appendn (tname, "false", 5);
- else if (val == 1)
- string_appendn (tname, "true", 4);
- else
- success = 0;
+ s = &param;
+ string_init (s);
}
- else if (is_real)
+ else
+ s = tname;
+
+ success = demangle_template_value_parm (work, mangled, s);
+
+ if (!success)
{
- if (**mangled == 'm')
- {
- string_appendn (tname, "-", 1);
- (*mangled)++;
- }
- while (isdigit (**mangled))
- {
- string_appendn (tname, *mangled, 1);
- (*mangled)++;
- }
- if (**mangled == '.') /* fraction */
- {
- string_appendn (tname, ".", 1);
- (*mangled)++;
- while (isdigit (**mangled))
- {
- string_appendn (tname, *mangled, 1);
- (*mangled)++;
- }
- }
- if (**mangled == 'e') /* exponent */
- {
- string_appendn (tname, "e", 1);
- (*mangled)++;
- while (isdigit (**mangled))
- {
- string_appendn (tname, *mangled, 1);
- (*mangled)++;
- }
- }
+ if (!is_type)
+ string_delete (s);
+ success = 0;
+ break;
}
- else if (is_pointer)
+
+ if (!is_type)
{
- if (!get_count (mangled, &symbol_len))
- {
- success = 0;
- break;
- }
- string_appendn (tname, *mangled, symbol_len);
- *mangled += symbol_len;
+ int len = s->p - s->b;
+ work->tmpl_argvec[i] = xmalloc (len + 1);
+ memcpy (work->tmpl_argvec[i], s->b, len);
+ work->tmpl_argvec[i][len] = '\0';
+
+ string_appends (tname, s);
+ string_delete (s);
}
}
need_comma = 1;
@@ -1070,19 +1596,22 @@ demangle_template (work, mangled, tname, trawname)
string_append (tname, " ");
string_append (tname, ">");
-/*
- if (work -> static_type)
- {
- string_append (declp, *mangled + 1);
- *mangled += strlen (*mangled);
- success = 1;
- }
- else
- {
- success = demangle_args (work, mangled, declp);
- }
+ if (is_type && remember)
+ remember_Btype (work, tname->b, LEN_STRING (tname), bindex);
+
+ /*
+ if (work -> static_type)
+ {
+ string_append (declp, *mangled + 1);
+ *mangled += strlen (*mangled);
+ success = 1;
}
-*/
+ else
+ {
+ success = demangle_args (work, mangled, declp);
+ }
+ }
+ */
return (success);
}
@@ -1096,14 +1625,14 @@ arm_pt (work, mangled, n, anchor, args)
/* ARM template? */
if (ARM_DEMANGLING && (*anchor = mystrstr (mangled, "__pt__")))
{
- int len;
- *args = *anchor + 6;
- len = consume_count (args);
- if (*args + len == mangled + n && **args == '_')
- {
- ++*args;
- return 1;
- }
+ int len;
+ *args = *anchor + 6;
+ len = consume_count (args);
+ if (*args + len == mangled + n && **args == '_')
+ {
+ ++*args;
+ return 1;
+ }
}
return 0;
}
@@ -1121,26 +1650,26 @@ demangle_arm_pt (work, mangled, n, declp)
/* ARM template? */
if (arm_pt (work, *mangled, n, &p, &args))
- {
- string arg;
- string_init (&arg);
- string_appendn (declp, *mangled, p - *mangled);
- string_append (declp, "<");
- /* should do error checking here */
- while (args < e) {
- string_clear (&arg);
- do_type (work, &args, &arg);
- string_appends (declp, &arg);
- string_append (declp, ",");
- }
- string_delete (&arg);
- --declp->p;
- string_append (declp, ">");
- }
+ {
+ string arg;
+ string_init (&arg);
+ string_appendn (declp, *mangled, p - *mangled);
+ string_append (declp, "<");
+ /* should do error checking here */
+ while (args < e) {
+ string_clear (&arg);
+ do_type (work, &args, &arg);
+ string_appends (declp, &arg);
+ string_append (declp, ",");
+ }
+ string_delete (&arg);
+ --declp->p;
+ string_append (declp, ">");
+ }
else
- {
- string_appendn (declp, *mangled, n);
- }
+ {
+ string_appendn (declp, *mangled, n);
+ }
*mangled += n;
}
@@ -1155,10 +1684,10 @@ demangle_class_name (work, mangled, declp)
n = consume_count (mangled);
if (strlen (*mangled) >= n)
- {
- demangle_arm_pt (work, mangled, n, declp);
- success = 1;
- }
+ {
+ demangle_arm_pt (work, mangled, n, declp);
+ success = 1;
+ }
return (success);
}
@@ -1205,9 +1734,11 @@ demangle_class (work, mangled, declp)
string *declp;
{
int success = 0;
+ int btype;
string class_name;
string_init (&class_name);
+ btype = register_Btype (work);
if (demangle_class_name (work, mangled, &class_name))
{
if ((work->constructor & 1) || (work->destructor & 1))
@@ -1223,7 +1754,9 @@ demangle_class (work, mangled, declp)
work -> constructor -= 1;
}
}
- string_prepend (declp, "::");
+ remember_Ktype (work, class_name.b, LEN_STRING(&class_name));
+ remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype);
+ string_prepend (declp, SCOPE_STRING (work));
string_prepends (declp, &class_name);
success = 1;
}
@@ -1308,9 +1841,9 @@ demangle_prefix (work, mangled, declp)
work->constructor = 2;
}
-/* This block of code is a reduction in strength time optimization
- of:
- scan = mystrstr (*mangled, "__"); */
+ /* This block of code is a reduction in strength time optimization
+ of:
+ scan = mystrstr (*mangled, "__"); */
{
scan = *mangled;
@@ -1325,7 +1858,7 @@ demangle_prefix (work, mangled, declp)
if (scan != NULL)
{
/* We found a sequence of two or more '_', ensure that we start at
- the last pair in the sequence. */
+ the last pair in the sequence. */
i = strspn (scan, "_");
if (i > 2)
{
@@ -1344,8 +1877,9 @@ demangle_prefix (work, mangled, declp)
success = 0;
}
}
- else if ((scan == *mangled) &&
- (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't')))
+ else if ((scan == *mangled)
+ && (isdigit (scan[2]) || (scan[2] == 'Q') || (scan[2] == 't')
+ || (scan[2] == 'K') || (scan[2] == 'H')))
{
/* The ARM says nothing about the mangling of local variables.
But cfront mangles local variables by prepending __<nesting_level>
@@ -1362,7 +1896,8 @@ demangle_prefix (work, mangled, declp)
{
/* A GNU style constructor starts with __[0-9Qt]. But cfront uses
names like __Q2_3foo3bar for nested type names. So don't accept
- this style of constructor for cfront demangling. */
+ this style of constructor for cfront demangling. A GNU
+ style member-template constructor starts with 'H'. */
if (!(LUCID_DEMANGLING || ARM_DEMANGLING))
work -> constructor += 1;
*mangled = scan + 2;
@@ -1374,7 +1909,7 @@ demangle_prefix (work, mangled, declp)
then find the next "__" that separates the prefix from the signature.
*/
if (!(ARM_DEMANGLING || LUCID_DEMANGLING)
- || (arm_special (work, mangled, declp) == 0))
+ || (arm_special (mangled, declp) == 0))
{
while (*scan == '_')
{
@@ -1388,13 +1923,21 @@ demangle_prefix (work, mangled, declp)
}
else
{
- demangle_function_name (work, mangled, declp, scan);
+ const char *tmp;
+ /* Look for the LAST occurrence of __, allowing names to have
+ the '__' sequence embedded in them.*/
+ while ((tmp = mystrstr (scan+2, "__")) != NULL)
+ scan = tmp;
+ if (*(scan + 2) == '\0')
+ success = 0;
+ else
+ demangle_function_name (work, mangled, declp, scan);
}
}
}
else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't')
{
- /* Cfront-style parameterized type. Handled later as a signature. */
+ /* Cfront-style parameterized type. Handled later as a signature. */
success = 1;
/* ARM template? */
@@ -1404,7 +1947,7 @@ demangle_prefix (work, mangled, declp)
{
/* Mangled name does not start with "__" but does have one somewhere
in there with non empty stuff after it. Looks like a global
- function name. */
+ function name. */
demangle_function_name (work, mangled, declp, scan);
}
else
@@ -1473,14 +2016,14 @@ gnu_special (work, mangled, declp)
&& (*mangled)[2] == 'v'
&& (*mangled)[3] == 't'
&& (*mangled)[4] == '_')
- || ((*mangled)[1] == 'v'
- && (*mangled)[2] == 't'
- && strchr (cplus_markers, (*mangled)[3]) != NULL)))
+ || ((*mangled)[1] == 'v'
+ && (*mangled)[2] == 't'
+ && strchr (cplus_markers, (*mangled)[3]) != NULL)))
{
/* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
and create the decl. Note that we consume the entire mangled
input string, which means that demangle_signature has no work
- to do. */
+ to do. */
if ((*mangled)[2] == 'v')
(*mangled) += 5; /* New style, with thunks: "__vt_" */
else
@@ -1491,15 +2034,26 @@ gnu_special (work, mangled, declp)
switch (**mangled)
{
case 'Q':
+ case 'K':
success = demangle_qualified (work, mangled, declp, 0, 1);
break;
case 't':
- success = demangle_template (work, mangled, declp, 0);
+ success = demangle_template (work, mangled, declp, 0, 1,
+ 1);
break;
default:
if (isdigit(*mangled[0]))
{
n = consume_count(mangled);
+ /* We may be seeing a too-large size, or else a
+ ".<digits>" indicating a static local symbol. In
+ any case, declare victory and move on; *don't* try
+ to use n to allocate. */
+ if (n > strlen (*mangled))
+ {
+ success = 1;
+ break;
+ }
}
else
{
@@ -1513,7 +2067,7 @@ gnu_special (work, mangled, declp)
{
if (p != NULL)
{
- string_append (declp, "::");
+ string_append (declp, SCOPE_STRING (work));
(*mangled)++;
}
}
@@ -1534,23 +2088,24 @@ gnu_special (work, mangled, declp)
(*mangled)++;
switch (**mangled)
{
- case 'Q':
- success = demangle_qualified (work, mangled, declp, 0, 1);
- break;
- case 't':
- success = demangle_template (work, mangled, declp, 0);
- break;
- default:
- n = consume_count (mangled);
- string_appendn (declp, *mangled, n);
- (*mangled) += n;
+ case 'Q':
+ case 'K':
+ success = demangle_qualified (work, mangled, declp, 0, 1);
+ break;
+ case 't':
+ success = demangle_template (work, mangled, declp, 0, 1, 1);
+ break;
+ default:
+ n = consume_count (mangled);
+ string_appendn (declp, *mangled, n);
+ (*mangled) += n;
}
if (success && (p == *mangled))
{
/* Consumed everything up to the cplus_marker, append the
- variable name. */
+ variable name. */
(*mangled)++;
- string_append (declp, "::");
+ string_append (declp, SCOPE_STRING (work));
n = strlen (*mangled);
string_appendn (declp, *mangled, n);
(*mangled) += n;
@@ -1563,7 +2118,7 @@ gnu_special (work, mangled, declp)
else if (strncmp (*mangled, "__thunk_", 8) == 0)
{
int delta = ((*mangled) += 8, consume_count (mangled));
- char *method = cplus_demangle (++*mangled, work->options);
+ char *method = internal_cplus_demangle (work, ++*mangled);
if (method)
{
char buf[50];
@@ -1579,6 +2134,29 @@ gnu_special (work, mangled, declp)
success = 0;
}
}
+ else if (strncmp (*mangled, "__t", 3) == 0
+ && ((*mangled)[3] == 'i' || (*mangled)[3] == 'f'))
+ {
+ p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function";
+ (*mangled) += 4;
+ switch (**mangled)
+ {
+ case 'Q':
+ case 'K':
+ success = demangle_qualified (work, mangled, declp, 0, 1);
+ break;
+ case 't':
+ success = demangle_template (work, mangled, declp, 0, 1, 1);
+ break;
+ default:
+ success = demangle_fund_type (work, mangled, declp);
+ break;
+ }
+ if (success && **mangled != '\0')
+ success = 0;
+ if (success)
+ string_append (declp, p);
+ }
else
{
success = 0;
@@ -1595,8 +2173,8 @@ LOCAL FUNCTION
SYNOPSIS
static int
- arm_special (struct work_stuff *work, const char **mangled,
- string *declp);
+ arm_special (const char **mangled,
+ string *declp);
DESCRIPTION
@@ -1610,8 +2188,7 @@ DESCRIPTION
*/
static int
-arm_special (work, mangled, declp)
- struct work_stuff *work;
+arm_special (mangled, declp)
const char **mangled;
string *declp;
{
@@ -1624,7 +2201,7 @@ arm_special (work, mangled, declp)
/* Found a ARM style virtual table, get past ARM_VTABLE_STRING
and create the decl. Note that we consume the entire mangled
input string, which means that demangle_signature has no work
- to do. */
+ to do. */
scan = *mangled + ARM_VTABLE_STRLEN;
while (*scan != '\0') /* first check it can be demangled */
{
@@ -1700,15 +2277,35 @@ demangle_qualified (work, mangled, result, isfuncname, append)
int isfuncname;
int append;
{
- int qualifiers;
- int namelength;
+ int qualifiers = 0;
int success = 1;
const char *p;
char num[2];
string temp;
+ string last_name;
+ int bindex = register_Btype (work);
+
+ /* We only make use of ISFUNCNAME if the entity is a constructor or
+ destructor. */
+ isfuncname = (isfuncname
+ && ((work->constructor & 1) || (work->destructor & 1)));
string_init (&temp);
- switch ((*mangled)[1])
+ string_init (&last_name);
+
+ if ((*mangled)[0] == 'K')
+ {
+ /* Squangling qualified name reuse */
+ int idx;
+ (*mangled)++;
+ idx = consume_count_with_underscores (mangled);
+ if (idx == -1 || idx > work -> numk)
+ success = 0;
+ else
+ string_append (&temp, work -> ktypevec[idx]);
+ }
+ else
+ switch ((*mangled)[1])
{
case '_':
/* GNU mangled name with more than 9 classes. The count is preceded
@@ -1762,66 +2359,85 @@ demangle_qualified (work, mangled, result, isfuncname, append)
return success;
/* Pick off the names and collect them in the temp buffer in the order
- in which they are found, separated by '::'. */
+ in which they are found, separated by '::'. */
while (qualifiers-- > 0)
{
+ int remember_K = 1;
+ string_clear (&last_name);
+
if (*mangled[0] == '_')
- *mangled = *mangled + 1;
+ (*mangled)++;
+
if (*mangled[0] == 't')
{
- success = demangle_template(work, mangled, &temp, 0);
+ /* Here we always append to TEMP since we will want to use
+ the template name without the template parameters as a
+ constructor or destructor name. The appropriate
+ (parameter-less) value is returned by demangle_template
+ in LAST_NAME. We do not remember the template type here,
+ in order to match the G++ mangling algorithm. */
+ success = demangle_template(work, mangled, &temp,
+ &last_name, 1, 0);
+ if (!success)
+ break;
+ }
+ else if (*mangled[0] == 'K')
+ {
+ int idx;
+ (*mangled)++;
+ idx = consume_count_with_underscores (mangled);
+ if (idx == -1 || idx > work->numk)
+ success = 0;
+ else
+ string_append (&temp, work->ktypevec[idx]);
+ remember_K = 0;
+
if (!success) break;
}
else
- {
- namelength = consume_count (mangled);
- if (strlen (*mangled) < namelength)
- {
- /* Simple sanity check failed */
- success = 0;
- break;
- }
- string_appendn (&temp, *mangled, namelength);
- *mangled += namelength;
+ {
+ success = do_type (work, mangled, &last_name);
+ if (!success)
+ break;
+ string_appends (&temp, &last_name);
}
+
+ if (remember_K)
+ remember_Ktype (work, temp.b, LEN_STRING (&temp));
+
if (qualifiers > 0)
- {
- string_appendn (&temp, "::", 2);
- }
+ string_append (&temp, SCOPE_STRING (work));
}
+ remember_Btype (work, temp.b, LEN_STRING (&temp), bindex);
+
/* If we are using the result as a function name, we need to append
the appropriate '::' separated constructor or destructor name.
We do this here because this is the most convenient place, where
- we already have a pointer to the name and the length of the name. */
+ we already have a pointer to the name and the length of the name. */
- if (isfuncname && (work->constructor & 1 || work->destructor & 1))
+ if (isfuncname)
{
- string_appendn (&temp, "::", 2);
+ string_append (&temp, SCOPE_STRING (work));
if (work -> destructor & 1)
- {
- string_append (&temp, "~");
- }
- string_appendn (&temp, (*mangled) - namelength, namelength);
+ string_append (&temp, "~");
+ string_appends (&temp, &last_name);
}
/* Now either prepend the temp buffer to the result, or append it,
- depending upon the state of the append flag. */
+ depending upon the state of the append flag. */
if (append)
- {
- string_appends (result, &temp);
- }
+ string_appends (result, &temp);
else
{
if (!STRING_EMPTY (result))
- {
- string_appendn (&temp, "::", 2);
- }
+ string_append (&temp, SCOPE_STRING (work));
string_prepends (result, &temp);
}
+ string_delete (&last_name);
string_delete (&temp);
return (success);
}
@@ -1894,7 +2510,9 @@ do_type (work, mangled, result)
const char *remembered_type;
int constp;
int volatilep;
+ string btype;
+ string_init (&btype);
string_init (&decl);
string_init (result);
@@ -1906,20 +2524,20 @@ do_type (work, mangled, result)
switch (**mangled)
{
- /* A pointer type */
+ /* A pointer type */
case 'P':
case 'p':
(*mangled)++;
string_prepend (&decl, "*");
break;
- /* A reference type */
+ /* A reference type */
case 'R':
(*mangled)++;
string_prepend (&decl, "&");
break;
- /* An array */
+ /* An array */
case 'A':
{
const char *p = ++(*mangled);
@@ -1955,7 +2573,7 @@ do_type (work, mangled, result)
}
break;
- /* A function */
+ /* A function */
case 'F':
(*mangled)++;
if (!STRING_EMPTY (&decl) && decl.b[0] == '*')
@@ -1965,16 +2583,15 @@ do_type (work, mangled, result)
}
/* After picking off the function args, we expect to either find the
function return type (preceded by an '_') or the end of the
- string. */
- if (!demangle_args (work, mangled, &decl)
+ string. */
+ if (!demangle_nested_args (work, mangled, &decl)
|| (**mangled != '_' && **mangled != '\0'))
{
success = 0;
+ break;
}
if (success && (**mangled == '_'))
- {
- (*mangled)++;
- }
+ (*mangled)++;
break;
case 'M':
@@ -1985,22 +2602,40 @@ do_type (work, mangled, result)
member = **mangled == 'M';
(*mangled)++;
- if (!isdigit (**mangled))
+ if (!isdigit (**mangled) && **mangled != 't')
{
success = 0;
break;
}
- n = consume_count (mangled);
- if (strlen (*mangled) < n)
+
+ string_append (&decl, ")");
+ string_prepend (&decl, SCOPE_STRING (work));
+ if (isdigit (**mangled))
{
- success = 0;
- break;
+ n = consume_count (mangled);
+ if (strlen (*mangled) < n)
+ {
+ success = 0;
+ break;
+ }
+ string_prependn (&decl, *mangled, n);
+ *mangled += n;
+ }
+ else
+ {
+ string temp;
+ string_init (&temp);
+ success = demangle_template (work, mangled, &temp,
+ NULL, 1, 1);
+ if (success)
+ {
+ string_prependn (&decl, temp.b, temp.p - temp.b);
+ string_clear (&temp);
+ }
+ else
+ break;
}
- string_append (&decl, ")");
- string_prepend (&decl, "::");
- string_prependn (&decl, *mangled, n);
string_prepend (&decl, "(");
- *mangled += n;
if (member)
{
if (**mangled == 'C')
@@ -2019,7 +2654,7 @@ do_type (work, mangled, result)
break;
}
}
- if ((member && !demangle_args (work, mangled, &decl))
+ if ((member && !demangle_nested_args (work, mangled, &decl))
|| **mangled != '_')
{
success = 0;
@@ -2043,27 +2678,29 @@ do_type (work, mangled, result)
break;
}
case 'G':
- (*mangled)++;
- break;
+ (*mangled)++;
+ break;
case 'C':
- (*mangled)++;
-/*
- if ((*mangled)[1] == 'P')
+ case 'V':
+ /*
+ if ((*mangled)[1] == 'P')
{
-*/
- if (PRINT_ANSI_QUALIFIERS)
+ */
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ if (!STRING_EMPTY (&decl))
{
- if (!STRING_EMPTY (&decl))
- {
- string_prepend (&decl, " ");
- }
- string_prepend (&decl, "const");
+ string_prepend (&decl, " ");
}
- break;
-/*
+ string_prepend (&decl,
+ (**mangled) == 'C' ? "const" : "volatile");
}
-*/
+ (*mangled)++;
+ break;
+ /*
+ }
+ */
/* fall through */
default:
@@ -2074,14 +2711,58 @@ do_type (work, mangled, result)
switch (**mangled)
{
- /* A qualified name, such as "Outer::Inner". */
- case 'Q':
+ /* A qualified name, such as "Outer::Inner". */
+ case 'Q':
+ case 'K':
+ {
success = demangle_qualified (work, mangled, result, 0, 1);
- break;
+ break;
+ }
+
+ /* A back reference to a previously seen squangled type */
+ case 'B':
+ (*mangled)++;
+ if (!get_count (mangled, &n) || n >= work -> numb)
+ success = 0;
+ else
+ {
+ string_append (result, work->btypevec[n]);
+ }
+ break;
+
+ case 'X':
+ case 'Y':
+ /* A template parm. We substitute the corresponding argument. */
+ {
+ int idx;
+
+ (*mangled)++;
+ idx = consume_count_with_underscores (mangled);
+
+ if (idx == -1
+ || (work->tmpl_argvec && idx >= work->ntmpl_args)
+ || consume_count_with_underscores (mangled) == -1)
+ {
+ success = 0;
+ break;
+ }
+
+ if (work->tmpl_argvec)
+ string_append (result, work->tmpl_argvec[idx]);
+ else
+ {
+ char buf[10];
+ sprintf(buf, "T%d", idx);
+ string_append (result, buf);
+ }
+
+ success = 1;
+ }
+ break;
- default:
- success = demangle_fund_type (work, mangled, result);
- break;
+ default:
+ success = demangle_fund_type (work, mangled, result);
+ break;
}
if (success)
@@ -2121,144 +2802,164 @@ demangle_fund_type (work, mangled, result)
{
int done = 0;
int success = 1;
+ string btype;
+ string_init (&btype);
- /* First pick off any type qualifiers. There can be more than one. */
+ /* First pick off any type qualifiers. There can be more than one. */
while (!done)
{
switch (**mangled)
{
- case 'C':
- (*mangled)++;
- if (PRINT_ANSI_QUALIFIERS)
- {
- APPEND_BLANK (result);
- string_append (result, "const");
- }
- break;
- case 'U':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "unsigned");
- break;
- case 'S': /* signed char only */
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "signed");
- break;
- case 'V':
- (*mangled)++;
- if (PRINT_ANSI_QUALIFIERS)
- {
- APPEND_BLANK (result);
- string_append (result, "volatile");
- }
- break;
- default:
- done = 1;
- break;
+ case 'C':
+ (*mangled)++;
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ APPEND_BLANK (result);
+ string_append (result, "const");
+ }
+ break;
+ case 'U':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "unsigned");
+ break;
+ case 'S': /* signed char only */
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "signed");
+ break;
+ case 'V':
+ (*mangled)++;
+ if (PRINT_ANSI_QUALIFIERS)
+ {
+ APPEND_BLANK (result);
+ string_append (result, "volatile");
+ }
+ break;
+ case 'J':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "__complex");
+ break;
+ default:
+ done = 1;
+ break;
}
}
- /* Now pick off the fundamental type. There can be only one. */
+ /* Now pick off the fundamental type. There can be only one. */
switch (**mangled)
{
- case '\0':
- case '_':
- break;
- case 'v':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "void");
- break;
- case 'x':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "long long");
- break;
- case 'l':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "long");
- break;
- case 'i':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "int");
- break;
- case 's':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "short");
- break;
- case 'b':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "bool");
- break;
- case 'c':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "char");
- break;
- case 'w':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "wchar_t");
- break;
- case 'r':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "long double");
- break;
- case 'd':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "double");
- break;
- case 'f':
- (*mangled)++;
- APPEND_BLANK (result);
- string_append (result, "float");
- break;
- case 'G':
- (*mangled)++;
- if (!isdigit (**mangled))
- {
- success = 0;
- break;
- }
- /* fall through */
- /* An explicit type, such as "6mytype" or "7integer" */
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- APPEND_BLANK (result);
- if (!demangle_class_name (work, mangled, result)) {
- --result->p;
+ case '\0':
+ case '_':
+ break;
+ case 'v':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "void");
+ break;
+ case 'x':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long long");
+ break;
+ case 'l':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long");
+ break;
+ case 'i':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "int");
+ break;
+ case 's':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "short");
+ break;
+ case 'b':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "bool");
+ break;
+ case 'c':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "char");
+ break;
+ case 'w':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "wchar_t");
+ break;
+ case 'r':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "long double");
+ break;
+ case 'd':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "double");
+ break;
+ case 'f':
+ (*mangled)++;
+ APPEND_BLANK (result);
+ string_append (result, "float");
+ break;
+ case 'G':
+ (*mangled)++;
+ if (!isdigit (**mangled))
+ {
success = 0;
+ break;
}
- break;
- case 't':
- success = demangle_template(work,mangled, result, 0);
+ /* fall through */
+ /* An explicit type, such as "6mytype" or "7integer" */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ {
+ int bindex = register_Btype (work);
+ string btype;
+ string_init (&btype);
+ if (demangle_class_name (work, mangled, &btype)) {
+ remember_Btype (work, btype.b, LEN_STRING (&btype), bindex);
+ APPEND_BLANK (result);
+ string_appends (result, &btype);
+ }
+ else
+ success = 0;
+ string_delete (&btype);
break;
- default:
- success = 0;
- break;
}
+ case 't':
+ {
+ success = demangle_template (work, mangled, &btype, 0, 1, 1);
+ string_appends (result, &btype);
+ break;
+ }
+ default:
+ success = 0;
+ break;
+ }
return (success);
}
-/* `result' will be initialized in do_type; it will be freed on failure */
+/* Demangle the next argument, given by MANGLED into RESULT, which
+ *should be an uninitialized* string. It will be initialized here,
+ and free'd should anything go wrong. */
static int
do_arg (work, mangled, result)
@@ -2266,17 +2967,67 @@ do_arg (work, mangled, result)
const char **mangled;
string *result;
{
+ /* Remember where we started so that we can record the type, for
+ non-squangling type remembering. */
const char *start = *mangled;
- if (!do_type (work, mangled, result))
+ string_init (result);
+
+ if (work->nrepeats > 0)
{
- return (0);
+ --work->nrepeats;
+
+ if (work->previous_argument == 0)
+ return 0;
+
+ /* We want to reissue the previous type in this argument list. */
+ string_appends (result, work->previous_argument);
+ return 1;
+ }
+
+ if (**mangled == 'n')
+ {
+ /* A squangling-style repeat. */
+ (*mangled)++;
+ work->nrepeats = consume_count(mangled);
+
+ if (work->nrepeats == 0)
+ /* This was not a repeat count after all. */
+ return 0;
+
+ if (work->nrepeats > 9)
+ {
+ if (**mangled != '_')
+ /* The repeat count should be followed by an '_' in this
+ case. */
+ return 0;
+ else
+ (*mangled)++;
+ }
+
+ /* Now, the repeat is all set up. */
+ return do_arg (work, mangled, result);
}
+
+ /* Save the result in WORK->previous_argument so that we can find it
+ if it's repeated. Note that saving START is not good enough: we
+ do not want to add additional types to the back-referenceable
+ type vector when processing a repeated type. */
+ if (work->previous_argument)
+ string_clear (work->previous_argument);
else
{
- remember_type (work, start, *mangled - start);
- return (1);
+ work->previous_argument = (string*) xmalloc (sizeof (string));
+ string_init (work->previous_argument);
}
+
+ if (!do_type (work, mangled, work->previous_argument))
+ return 0;
+
+ string_appends (result, work->previous_argument);
+
+ remember_type (work, start, *mangled - start);
+ return 1;
}
static void
@@ -2287,20 +3038,23 @@ remember_type (work, start, len)
{
char *tem;
+ if (work->forgetting_types)
+ return;
+
if (work -> ntypes >= work -> typevec_size)
{
if (work -> typevec_size == 0)
{
work -> typevec_size = 3;
- work -> typevec =
- (char **) xmalloc (sizeof (char *) * work -> typevec_size);
+ work -> typevec
+ = (char **) xmalloc (sizeof (char *) * work -> typevec_size);
}
else
{
work -> typevec_size *= 2;
- work -> typevec =
- (char **) xrealloc ((char *)work -> typevec,
- sizeof (char *) * work -> typevec_size);
+ work -> typevec
+ = (char **) xrealloc ((char *)work -> typevec,
+ sizeof (char *) * work -> typevec_size);
}
}
tem = xmalloc (len + 1);
@@ -2309,7 +3063,113 @@ remember_type (work, start, len)
work -> typevec[work -> ntypes++] = tem;
}
-/* Forget the remembered types, but not the type vector itself. */
+
+/* Remember a K type class qualifier. */
+static void
+remember_Ktype (work, start, len)
+ struct work_stuff *work;
+ const char *start;
+ int len;
+{
+ char *tem;
+
+ if (work -> numk >= work -> ksize)
+ {
+ if (work -> ksize == 0)
+ {
+ work -> ksize = 5;
+ work -> ktypevec
+ = (char **) xmalloc (sizeof (char *) * work -> ksize);
+ }
+ else
+ {
+ work -> ksize *= 2;
+ work -> ktypevec
+ = (char **) xrealloc ((char *)work -> ktypevec,
+ sizeof (char *) * work -> ksize);
+ }
+ }
+ tem = xmalloc (len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ work -> ktypevec[work -> numk++] = tem;
+}
+
+/* Register a B code, and get an index for it. B codes are registered
+ as they are seen, rather than as they are completed, so map<temp<char> >
+ registers map<temp<char> > as B0, and temp<char> as B1 */
+
+static int
+register_Btype (work)
+ struct work_stuff *work;
+{
+ int ret;
+
+ if (work -> numb >= work -> bsize)
+ {
+ if (work -> bsize == 0)
+ {
+ work -> bsize = 5;
+ work -> btypevec
+ = (char **) xmalloc (sizeof (char *) * work -> bsize);
+ }
+ else
+ {
+ work -> bsize *= 2;
+ work -> btypevec
+ = (char **) xrealloc ((char *)work -> btypevec,
+ sizeof (char *) * work -> bsize);
+ }
+ }
+ ret = work -> numb++;
+ work -> btypevec[ret] = NULL;
+ return(ret);
+}
+
+/* Store a value into a previously registered B code type. */
+
+static void
+remember_Btype (work, start, len, index)
+ struct work_stuff *work;
+ const char *start;
+ int len, index;
+{
+ char *tem;
+
+ tem = xmalloc (len + 1);
+ memcpy (tem, start, len);
+ tem[len] = '\0';
+ work -> btypevec[index] = tem;
+}
+
+/* Lose all the info related to B and K type codes. */
+static void
+forget_B_and_K_types (work)
+ struct work_stuff *work;
+{
+ int i;
+
+ while (work -> numk > 0)
+ {
+ i = --(work -> numk);
+ if (work -> ktypevec[i] != NULL)
+ {
+ free (work -> ktypevec[i]);
+ work -> ktypevec[i] = NULL;
+ }
+ }
+
+ while (work -> numb > 0)
+ {
+ i = --(work -> numb);
+ if (work -> btypevec[i] != NULL)
+ {
+ free (work -> btypevec[i]);
+ work -> btypevec[i] = NULL;
+ }
+ }
+}
+/* Forget the remembered types, but not the type vector itself. */
static void
forget_types (work)
@@ -2360,8 +3220,8 @@ forget_types (work)
foo__FiR3fooT1T2T1T2
__ct__3fooFiR3fooT1T2T1T2
- Note that g++ bases it's type numbers starting at zero and counts all
- previously seen types, while lucid/ARM bases it's type numbers starting
+ Note that g++ bases its type numbers starting at zero and counts all
+ previously seen types, while lucid/ARM bases its type numbers starting
at one and only considers types after it has seen the 'F' character
indicating the start of the function args. For lucid/ARM style, we
account for this difference by discarding any previously seen types when
@@ -2392,7 +3252,8 @@ demangle_args (work, mangled, declp)
}
}
- while (**mangled != '_' && **mangled != '\0' && **mangled != 'e')
+ while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e')
+ || work->nrepeats > 0)
{
if ((**mangled == 'N') || (**mangled == 'T'))
{
@@ -2434,12 +3295,12 @@ demangle_args (work, mangled, declp)
t--;
}
/* Validate the type index. Protect against illegal indices from
- malformed type strings. */
+ malformed type strings. */
if ((t < 0) || (t >= work -> ntypes))
{
return (0);
}
- while (--r >= 0)
+ while (work->nrepeats > 0 || --r >= 0)
{
tem = work -> typevec[t];
if (need_comma && PRINT_ARG_TYPES)
@@ -2460,18 +3321,12 @@ demangle_args (work, mangled, declp)
}
else
{
- if (need_comma & PRINT_ARG_TYPES)
- {
- string_append (declp, ", ");
- }
+ if (need_comma && PRINT_ARG_TYPES)
+ string_append (declp, ", ");
if (!do_arg (work, mangled, &arg))
- {
- return (0);
- }
+ return (0);
if (PRINT_ARG_TYPES)
- {
- string_appends (declp, &arg);
- }
+ string_appends (declp, &arg);
string_delete (&arg);
need_comma = 1;
}
@@ -2497,6 +3352,44 @@ demangle_args (work, mangled, declp)
return (1);
}
+/* Like demangle_args, but for demangling the argument lists of function
+ and method pointers or references, not top-level declarations. */
+
+static int
+demangle_nested_args (work, mangled, declp)
+ struct work_stuff *work;
+ const char **mangled;
+ string *declp;
+{
+ string* saved_previous_argument;
+ int result;
+ int saved_nrepeats;
+
+ /* The G++ name-mangling algorithm does not remember types on nested
+ argument lists, unless -fsquangling is used, and in that case the
+ type vector updated by remember_type is not used. So, we turn
+ off remembering of types here. */
+ ++work->forgetting_types;
+
+ /* For the repeat codes used with -fsquangling, we must keep track of
+ the last argument. */
+ saved_previous_argument = work->previous_argument;
+ saved_nrepeats = work->nrepeats;
+ work->previous_argument = 0;
+ work->nrepeats = 0;
+
+ /* Actually demangle the arguments. */
+ result = demangle_args (work, mangled, declp);
+
+ /* Restore the previous_argument field. */
+ if (work->previous_argument)
+ string_delete (work->previous_argument);
+ work->previous_argument = saved_previous_argument;
+ work->nrepeats = saved_nrepeats;
+
+ return result;
+}
+
static void
demangle_function_name (work, mangled, declp, scan)
struct work_stuff *work;
@@ -2504,8 +3397,7 @@ demangle_function_name (work, mangled, declp, scan)
string *declp;
const char *scan;
{
- int i;
- int len;
+ size_t i;
string type;
const char *tem;
@@ -2515,7 +3407,7 @@ demangle_function_name (work, mangled, declp, scan)
/* Consume the function name, including the "__" separating the name
from the signature. We are guaranteed that SCAN points to the
- separator. */
+ separator. */
(*mangled) = scan + 2;
@@ -2525,7 +3417,7 @@ demangle_function_name (work, mangled, declp, scan)
/* See if we have an ARM style constructor or destructor operator.
If so, then just record it, clear the decl, and return.
We can't build the actual constructor/destructor decl until later,
- when we recover the class name from the signature. */
+ when we recover the class name from the signature. */
if (strcmp (declp -> b, "__ct") == 0)
{
@@ -2552,7 +3444,7 @@ demangle_function_name (work, mangled, declp, scan)
{
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
- len = declp->p - declp->b - 10;
+ int len = declp->p - declp->b - 10;
if (strlen (optable[i].in) == len
&& memcmp (optable[i].in, declp->b + 10, len) == 0)
{
@@ -2594,7 +3486,7 @@ demangle_function_name (work, mangled, declp, scan)
}
}
else if (declp->b[0] == '_' && declp->b[1] == '_'
- && declp->b[2] == 'o' && declp->b[3] == 'p')
+ && declp->b[2] == 'o' && declp->b[3] == 'p')
{
/* ANSI. */
/* type conversion operator. */
@@ -2630,7 +3522,7 @@ demangle_function_name (work, mangled, declp, scan)
{
if (declp->b[2] == 'a' && declp->b[5] == '\0')
{
- /* Assignment. */
+ /* Assignment. */
for (i = 0; i < sizeof (optable) / sizeof (optable[0]); i++)
{
if (strlen (optable[i].in) == 3
@@ -2799,17 +3691,27 @@ string_prependn (p, s, n)
/* To generate a standalone demangler program for testing purposes,
just compile and link this file with -DMAIN and libiberty.a. When
run, it demangles each command line arg, or each stdin string, and
- prints the result on stdout. */
+ prints the result on stdout. */
#ifdef MAIN
+#include "getopt.h"
+
+static char *program_name;
+static char *program_version = VERSION;
+static int flags = DMGL_PARAMS | DMGL_ANSI;
+
+static void demangle_it PARAMS ((char *));
+static void usage PARAMS ((FILE *, int));
+static void fatal PARAMS ((char *));
+
static void
demangle_it (mangled_name)
- char *mangled_name;
+ char *mangled_name;
{
char *result;
- result = cplus_demangle (mangled_name, DMGL_PARAMS | DMGL_ANSI);
+ result = cplus_demangle (mangled_name, flags);
if (result == NULL)
{
printf ("%s\n", mangled_name);
@@ -2821,11 +3723,6 @@ demangle_it (mangled_name)
}
}
-#include "getopt.h"
-
-static char *program_name;
-static char *program_version = VERSION;
-
static void
usage (stream, status)
FILE *stream;
@@ -2833,16 +3730,16 @@ usage (stream, status)
{
fprintf (stream, "\
Usage: %s [-_] [-n] [-s {gnu,lucid,arm}] [--strip-underscores]\n\
- [--no-strip-underscores] [--format={gnu,lucid,arm}]\n\
- [--help] [--version] [arg...]\n",
+ [--no-strip-underscores] [--format={gnu,lucid,arm}]\n\
+ [--help] [--version] [arg...]\n",
program_name);
exit (status);
}
-#define MBUF_SIZE 512
+#define MBUF_SIZE 32767
char mbuffer[MBUF_SIZE];
-/* Defined in the automatically-generated underscore.c. */
+/* Defined in the automatically-generated underscore.c. */
extern int prepends_underscore;
int strip_underscore = 0;
@@ -2856,6 +3753,15 @@ static struct option long_options[] = {
{0, no_argument, 0, 0}
};
+/* More 'friendly' abort that prints the line and file.
+ config.h can #define abort fancy_abort if you like that sort of thing. */
+
+void
+fancy_abort ()
+{
+ fatal ("Internal gcc abort.");
+}
+
int
main (argc, argv)
int argc;
@@ -2868,44 +3774,44 @@ main (argc, argv)
strip_underscore = prepends_underscore;
- while ((c = getopt_long (argc, argv, "_ns:", long_options, (int *) 0)) != EOF)
+ while ((c = getopt_long (argc, argv, "_ns:j", long_options, (int *) 0)) != EOF)
{
switch (c)
{
- case '?':
- usage (stderr, 1);
- break;
- case 'h':
- usage (stdout, 0);
- case 'n':
- strip_underscore = 0;
- break;
- case 'v':
- printf ("GNU %s version %s\n", program_name, program_version);
- exit (0);
- case '_':
- strip_underscore = 1;
- break;
- case 's':
- if (strcmp (optarg, "gnu") == 0)
- {
- current_demangling_style = gnu_demangling;
- }
- else if (strcmp (optarg, "lucid") == 0)
- {
- current_demangling_style = lucid_demangling;
- }
- else if (strcmp (optarg, "arm") == 0)
- {
- current_demangling_style = arm_demangling;
- }
- else
- {
- fprintf (stderr, "%s: unknown demangling style `%s'\n",
- program_name, optarg);
- exit (1);
- }
- break;
+ case '?':
+ usage (stderr, 1);
+ break;
+ case 'h':
+ usage (stdout, 0);
+ case 'n':
+ strip_underscore = 0;
+ break;
+ case 'v':
+ printf ("GNU %s version %s\n", program_name, program_version);
+ exit (0);
+ case '_':
+ strip_underscore = 1;
+ break;
+ case 's':
+ if (strcmp (optarg, "gnu") == 0)
+ {
+ current_demangling_style = gnu_demangling;
+ }
+ else if (strcmp (optarg, "lucid") == 0)
+ {
+ current_demangling_style = lucid_demangling;
+ }
+ else if (strcmp (optarg, "arm") == 0)
+ {
+ current_demangling_style = arm_demangling;
+ }
+ else
+ {
+ fprintf (stderr, "%s: unknown demangling style `%s'\n",
+ program_name, optarg);
+ exit (1);
+ }
+ break;
}
}
@@ -2922,7 +3828,7 @@ main (argc, argv)
{
int i = 0;
c = getchar ();
- /* Try to read a label. */
+ /* Try to read a label. */
while (c != EOF && (isalnum(c) || c == '_' || c == '$' || c == '.'))
{
if (i >= MBUF_SIZE-1)
@@ -2944,8 +3850,7 @@ main (argc, argv)
mbuffer[i] = 0;
- result = cplus_demangle (mbuffer + skip_first,
- DMGL_PARAMS | DMGL_ANSI);
+ result = cplus_demangle (mbuffer + skip_first, flags);
if (result)
{
if (mbuffer[0] == '.')
diff --git a/contrib/gcc/cpp.texi b/contrib/gcc/cpp.texi
index 1de8371..e71b6e9 100644
--- a/contrib/gcc/cpp.texi
+++ b/contrib/gcc/cpp.texi
@@ -2,15 +2,12 @@
@setfilename cpp.info
@settitle The C Preprocessor
-@ignore
@ifinfo
-@format
-START-INFO-DIR-ENTRY
-* Cpp: (cpp). The C preprocessor.
-END-INFO-DIR-ENTRY
-@end format
+@dircategory Programming
+@direntry
+* Cpp: (cpp). The GNU C preprocessor.
+@end direntry
@end ifinfo
-@end ignore
@c @smallbook
@c @cropmarks
@@ -45,7 +42,7 @@ into another language, under the above conditions for modified versions.
@titlepage
@c @finalout
@title The C Preprocessor
-@subtitle Last revised July 1992
+@subtitle Last revised March 1997
@subtitle for GCC version 2
@author Richard M. Stallman
@page
@@ -54,7 +51,7 @@ This booklet is eventually intended to form the first chapter of a GNU
C Language manual.
@vskip 0pt plus 1filll
-Copyright @copyright{} 1987, 1989, 1991, 1992, 1993, 1994, 1995 Free
+Copyright @copyright{} 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997 Free
Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
@@ -105,7 +102,7 @@ to inform the compiler of where each source line originally came from.
C preprocessors vary in some details. This manual discusses the GNU C
preprocessor, the C Compatible Compiler Preprocessor. The GNU C
-preprocessor provides a superset of the features of ANSI Standard C.
+preprocessor provides a superset of the features of ANSI Standard C@.
ANSI Standard C requires the rejection of many harmless constructs commonly
used by today's C programs. Such incompatibility would be inconvenient for
@@ -115,6 +112,12 @@ options @samp{-trigraphs}, @samp{-undef} and @samp{-pedantic}, but in
practice the consequences of having strict ANSI Standard C make it
undesirable to do this. @xref{Invocation}.
+The C preprocessor is designed for C-like languages; you may run into
+problems if you apply it to other kinds of languages, because it assumes
+that it is dealing with C@. For example, the C preprocessor sometimes
+outputs extra white space to avoid inadvertent C token concatenation,
+and this may cause problems with other languages.
+
@menu
* Global Actions:: Actions made uniformly on all input files.
* Directives:: General syntax of preprocessing directives.
@@ -490,14 +493,14 @@ names, then inheritance is straightforward: simply write @samp{#include
Sometimes it is necessary to give the inheriting file the same name as
the base file. This is less straightforward.
-For example, suppose an application program uses the system header file
+For example, suppose an application program uses the system header
@file{sys/signal.h}, but the version of @file{/usr/include/sys/signal.h}
on a particular system doesn't do what the application program expects.
It might be convenient to define a ``local'' version, perhaps under the
name @file{/usr/local/include/sys/signal.h}, to override or add to the
one supplied by the system.
-You can do this by using the option @samp{-I.} for compilation, and
+You can do this by compiling with the option @samp{-I.}, and
writing a file @file{sys/signal.h} that does what the application
program expects. But making this file include the standard
@file{sys/signal.h} is not so easy---writing @samp{#include
@@ -521,8 +524,8 @@ file directories @emph{after} the directory in which the current file
was found.
Suppose you specify @samp{-I /usr/local/include}, and the list of
-directories to search also includes @file{/usr/include}; and suppose that
-both directories contain a file named @file{sys/signal.h}. Ordinary
+directories to search also includes @file{/usr/include}; and suppose
+both directories contain @file{sys/signal.h}. Ordinary
@samp{#include <sys/signal.h>} finds the file under
@file{/usr/local/include}. If that file contains @samp{#include_next
<sys/signal.h>}, it starts searching after that directory, and finds the
@@ -671,7 +674,7 @@ values, as it is defined in many C programs:
@end example
@noindent
-(This is not the best way to define a ``minimum'' macro in GNU C.
+(This is not the best way to define a ``minimum'' macro in GNU C@.
@xref{Side Effects}, for more information.)
To use a macro that expects arguments, you write the name of the macro
@@ -814,7 +817,7 @@ system-specific macros.
@cindex standard predefined macros
The standard predefined macros are available with the same meanings
-regardless of the machine or operating system on which you are using GNU C.
+regardless of the machine or operating system on which you are using GNU C@.
Their names all start and end with double underscores. Those preceding
@code{__GNUC__} in this table are standardized by ANSI C; the rest are
GNU C extensions.
@@ -859,8 +862,9 @@ if a @samp{#line} directive is used. @xref{Combining Sources}.
@findex __DATE__
This macro expands to a string constant that describes the date on
which the preprocessor is being run. The string constant contains
-eleven characters and looks like @samp{"Jan 29 1987"} or @w{@samp{"Apr
-1 1905"}}.
+eleven characters and looks like @w{@samp{"Feb 1 1996"}}.
+@c After reformatting the above, check that the date remains `Feb 1 1996',
+@c all on one line, with two spaces between the `Feb' and the `1'.
@item __TIME__
@findex __TIME__
@@ -871,9 +875,17 @@ eight characters and looks like @samp{"23:59:01"}.
@item __STDC__
@findex __STDC__
This macro expands to the constant 1, to signify that this is ANSI
-Standard C. (Whether that is actually true depends on what C compiler
+Standard C@. (Whether that is actually true depends on what C compiler
will operate on the output from the preprocessor.)
+On some hosts, system include files use a different convention, where
+@samp{__STDC__} is normally 0, but is 1 if the user specifies strict
+conformance to the C Standard. The preprocessor follows the host convention
+when processing system include files, but when processing user files it follows
+the usual GNU C convention.
+
+This macro is not defined if the @samp{-traditional} option is used.
+
@item __STDC_VERSION__
@findex __STDC_VERSION__
This macro expands to the C Standard's version number,
@@ -884,9 +896,11 @@ Like @samp{__STDC__}, whether this version number is accurate
for the entire implementation depends on what C compiler
will operate on the output from the preprocessor.
+This macro is not defined if the @samp{-traditional} option is used.
+
@item __GNUC__
@findex __GNUC__
-This macro is defined if and only if this is GNU C. This macro is
+This macro is defined if and only if this is GNU C@. This macro is
defined only when the entire GNU C compiler is in use; if you invoke the
preprocessor directly, @samp{__GNUC__} is undefined. The value
identifies the major version number of GNU CC (@samp{1} for GNU CC
@@ -917,11 +931,11 @@ to test whether a header is compiled by a C compiler or a C++ compiler.
@item __STRICT_ANSI__
@findex __STRICT_ANSI__
-This macro is defined if and only if the @samp{-ansi} switch was
+GNU C defines this macro if and only if the @samp{-ansi} switch was
specified when GNU C was invoked. Its definition is the null string.
This macro exists primarily to direct certain GNU header files not to
define certain traditional Unix constructs which are incompatible with
-ANSI C.
+ANSI C@.
@item __BASE_FILE__
@findex __BASE_FILE__
@@ -939,46 +953,46 @@ the nesting level is zero.
@item __VERSION__
@findex __VERSION__
-This macro expands to a string which describes the version number of
-GNU C. The string is normally a sequence of decimal numbers separated
-by periods, such as @samp{"2.6.0"}. The only reasonable use of this
-macro is to incorporate it into a string constant.
+This macro expands to a string constant which describes the version number of
+GNU C@. The string is normally a sequence of decimal numbers separated
+by periods, such as @samp{"2.6.0"}.
@item __OPTIMIZE__
@findex __OPTIMIZE__
-This macro is defined in optimizing compilations. It causes certain
-GNU header files to define alternative macro definitions for some
-system library functions. It is unwise to refer to or test the
-definition of this macro unless you make very sure that programs will
-execute with the same effect regardless.
+GNU CC defines this macro in optimizing compilations. It causes certain
+GNU header files to define alternative macro definitions for some system
+library functions. You should not refer to or test the definition of
+this macro unless you make very sure that programs will execute with the
+same effect regardless.
@item __CHAR_UNSIGNED__
@findex __CHAR_UNSIGNED__
-This macro is defined if and only if the data type @code{char} is
-unsigned on the target machine. It exists to cause the standard
-header file @file{limit.h} to work correctly. It is bad practice
-to refer to this macro yourself; instead, refer to the standard
-macros defined in @file{limit.h}. The preprocessor uses
-this macro to determine whether or not to sign-extend large character
-constants written in octal; see @ref{#if Directive,,The @samp{#if} Directive}.
+GNU C defines this macro if and only if the data type @code{char} is
+unsigned on the target machine. It exists to cause the standard header
+file @file{limits.h} to work correctly. You should not refer to this
+macro yourself; instead, refer to the standard macros defined in
+@file{limits.h}. The preprocessor uses this macro to determine whether
+or not to sign-extend large character constants written in octal; see
+@ref{#if Directive,,The @samp{#if} Directive}.
@item __REGISTER_PREFIX__
@findex __REGISTER_PREFIX__
-This macro expands to a string describing the prefix applied to cpu
-registers in assembler code. It can be used to write assembler code
-that is usable in multiple environments. For example, in the
-@samp{m68k-aout} environment it expands to the string @samp{""},
-but in the @samp{m68k-coff} environment it expands to the string
-@samp{"%"}.
+This macro expands to a string (not a string constant) describing the
+prefix applied to CPU registers in assembler code. You can use it to
+write assembler code that is usable in multiple environments. For
+example, in the @samp{m68k-aout} environment it expands to the null
+string, but in the @samp{m68k-coff} environment it expands to the string
+@samp{%}.
@item __USER_LABEL_PREFIX__
@findex __USER_LABEL_PREFIX__
-This macro expands to a string describing the prefix applied to
-user generated labels in assembler code. It can be used to write
-assembler code that is usable in multiple environments.
-For example, in the @samp{m68k-aout} environment it expands to the
-string @samp{"_"}, but in the @samp{m68k-coff} environment it expands
-to the string @samp{""}.
+Similar to @code{__REGISTER_PREFIX__}, but describes the prefix applied
+to user generated labels in assembler code. For example, in the
+@samp{m68k-aout} environment it expands to the string @samp{_}, but in
+the @samp{m68k-coff} environment it expands to the null string. This
+does not work with the @samp{-mno-underscores} option that the i386
+OSF/rose and m88k targets provide nor with the @samp{-mcall*} options of
+the rs6000 System V Release 4 target.
@end table
@node Nonstandard Predefined,, Standard Predefined, Predefined
@@ -1237,7 +1251,7 @@ possible to piece together a string constant. However, two pieces of text
that don't together form a valid lexical unit cannot be concatenated. For
example, concatenation with @samp{x} on one side and @samp{+} on the other
is not meaningful because those two characters can't fit together in any
-lexical unit of C. The ANSI standard says that such attempts at
+lexical unit of C@. The ANSI standard says that such attempts at
concatenation are undefined, but in the GNU C preprocessor it is well
defined: it puts the @samp{x} and @samp{+} side by side with no particular
special results.
@@ -1437,7 +1451,7 @@ Defining the macro as
@noindent
provides the desired result.
-However, unintended grouping can result in another way. Consider
+Unintended grouping can result in another way. Consider
@samp{sizeof ceil_div(1, 2)}. That has the appearance of a C expression
that would compute the size of the type of @samp{ceil_div (1, 2)}, but in
fact it means something very different. Here is what it expands to:
@@ -1958,7 +1972,7 @@ practice because it helps people match the @samp{#endif} to the
corresponding @samp{#if}. Such comments should always be used, except in
short conditionals that are not nested. In fact, you can put anything at
all after the @samp{#endif} and it will be ignored by the GNU C preprocessor,
-but only comments are acceptable in ANSI Standard C.
+but only comments are acceptable in ANSI Standard C@.
@var{expression} is a C expression of integer type, subject to stringent
restrictions. It may contain
@@ -2327,7 +2341,7 @@ when you run @code{gcc} or @code{cpp}. @xref{Invocation}.
@findex #error
The directive @samp{#error} causes the preprocessor to report a fatal
error. The rest of the line that follows @samp{#error} is used as the
-error message.
+error message. The line must consist of complete tokens.
You would use @samp{#error} inside of a conditional that detects a
combination of parameters which you know the program does not properly
@@ -2337,7 +2351,7 @@ properly on a Vax, you might write
@smallexample
@group
#ifdef __vax__
-#error Won't work on Vaxen. See comments at get_last_object.
+#error "Won't work on Vaxen. See comments at get_last_object."
#endif
@end group
@end smallexample
@@ -2441,8 +2455,8 @@ rather than a line of output containing just a @samp{#}. Supposedly
some old C programs contain such lines.
@findex #pragma
-The ANSI standard specifies that the @samp{#pragma} directive has an
-arbitrary, implementation-defined effect. In the GNU C preprocessor,
+The ANSI standard specifies that the effect of the @samp{#pragma}
+directive is implementation-defined. In the GNU C preprocessor,
@samp{#pragma} directives are not used, except for @samp{#pragma once}
(@pxref{Once-Only}). However, they are left in the preprocessor output,
so they are available to the compilation pass.
@@ -2462,7 +2476,8 @@ where it is meaningful.
The output from the C preprocessor looks much like the input, except
that all preprocessing directive lines have been replaced with blank lines
and all comments with spaces. Whitespace within a line is not altered;
-however, a space is inserted after the expansions of most macro calls.
+however, unless @samp{-traditional} is used, spaces may be inserted into
+the expansions of macro calls to prevent tokens from being concatenated.
Source file name and line number information is conveyed by lines of
the form
@@ -2489,7 +2504,7 @@ This indicates returning to a file (after having included another file).
This indicates that the following text comes from a system header file,
so certain warnings should be suppressed.
@item 4
-This indicates that the following text should be treated as C.
+This indicates that the following text should be treated as C@.
@c maybe cross reference NO_IMPLICIT_EXTERN_C
@end table
@@ -2534,7 +2549,7 @@ output before the expansion of the macro call.
@item -traditional
@findex -traditional
-Try to imitate the behavior of old-fashioned C, as opposed to ANSI C.
+Try to imitate the behavior of old-fashioned C, as opposed to ANSI C@.
@itemize @bullet
@item
@@ -2562,17 +2577,17 @@ It considers @samp{1.0e+4} to be three tokens: @samp{1.0e}, @samp{+},
and @samp{4}.
@item
-A macro is not suppressed within its own definition, in traditional C.
+A macro is not suppressed within its own definition, in traditional C@.
Thus, any macro that is used recursively inevitably causes an error.
@item
The character @samp{#} has no special meaning within a macro definition
-in traditional C.
+in traditional C@.
@item
In traditional C, the text at the end of a macro expansion can run
together with the text after the macro call, to produce a single token.
-(This is impossible in ANSI C.)
+(This is impossible in ANSI C@.)
@item
Traditionally, @samp{\} inside a macro argument suppresses the syntactic
@@ -2614,17 +2629,22 @@ Warn if any trigraphs are encountered (assuming they are enabled).
@itemx -Wcomments
(Both forms have the same effect).
@end ignore
-Warn whenever a comment-start sequence @samp{/*} appears in a comment.
+Warn whenever a comment-start sequence @samp{/*} appears in a @samp{/*}
+comment, or whenever a Backslash-Newline appears in a @samp{//} comment.
@item -Wall
@findex -Wall
Requests both @samp{-Wtrigraphs} and @samp{-Wcomment} (but not
-@samp{-Wtraditional}).
+@samp{-Wtraditional} or @samp{-Wundef}).
@item -Wtraditional
@findex -Wtraditional
Warn about certain constructs that behave differently in traditional and
-ANSI C.
+ANSI C@.
+
+@item -Wundef
+@findex -Wundef
+Warn if an undefined identifier is evaluated in an @samp{#if} directive.
@item -I @var{directory}
@findex -I
@@ -2662,7 +2682,16 @@ Only the directories you have specified with @samp{-I} options
@findex -nostdinc++
Do not search for header files in the C++-specific standard directories,
but do still search the other standard directories.
-(This option is used when building libg++.)
+(This option is used when building the C++ library.)
+
+@item -remap
+@findex -remap
+When searching for a header file in a directory, remap file names if a
+file named @file{header.gcc} exists in that directory. This can be used
+to work around limitations of file systems with file name restrictions.
+The @file{header.gcc} file should contain a series of lines with two
+tokens on each line: the first token is the name to map, and the second
+token is the actual name to use.
@item -D @var{name}
@findex -D
@@ -2718,6 +2747,10 @@ predefined macros, and it outputs @emph{both} the @samp{#define}
directives and the result of preprocessing. Both kinds of output go to
the standard output file.
+@item -dI
+@findex -dI
+Output @samp{#include} directives in addition to the result of preprocessing.
+
@item -M [-MG]
@findex -M
Instead of outputting the result of preprocessing, output a rule
@@ -2813,9 +2846,10 @@ is applied to the standard system directories.
@findex -lang-objc++
Specify the source language. @samp{-lang-c} is the default; it
allows recognition of C++ comments (comments that begin with
-@samp{//} and end at end of line), since this is
-a common feature and it will most likely be in the next C standard.
-@samp{-lang-c89} disables recognition of C++ comments. @samp{-lang-c++}
+@samp{//} and end at end of line) and hexadecimal floating-point constants,
+since these features will most likely appear in the next C standard.
+@samp{-lang-c89} disables recognition of C++ comments and
+hexadecimal floating-point constants. @samp{-lang-c++}
handles C++ comment syntax and includes extra default include
directories for C++. @samp{-lang-objc} enables the Objective C
@samp{#import} directive. @samp{-lang-objc++} enables both C++ and Objective C
@@ -2836,11 +2870,12 @@ This option is available only when you call @code{cpp} directly;
@item -$
@findex -$
-Forbid the use of @samp{$} in identifiers. This is required for ANSI
-conformance. @code{gcc} automatically supplies this option to the
-preprocessor if you specify @samp{-ansi}, but @code{gcc} doesn't
-recognize the @samp{-$} option itself---to use it without the other
-effects of @samp{-ansi}, you must call the preprocessor directly.
+Forbid the use of @samp{$} in identifiers. This was formerly required
+for strict conformance to the C Standard before the standard was
+corrected.
+
+This option is available only when you call @code{cpp} directly;
+@code{gcc} will not pass it from its command line.
@end table
diff --git a/contrib/gcc/cppalloc.c b/contrib/gcc/cppalloc.c
index f7b6019..bd3a605 100644
--- a/contrib/gcc/cppalloc.c
+++ b/contrib/gcc/cppalloc.c
@@ -1,7 +1,7 @@
/* Part of CPP library. (memory allocation - xmalloc etc)
- Copyright (C) 1986, 87, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1986, 87, 89, 92 - 95, 1998 Free Software Foundation, Inc.
Written by Per Bothner, 1994.
- Based on CCCP program by by Paul Rubin, June 1986
+ Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
This program is free software; you can redistribute it and/or modify it
@@ -23,11 +23,15 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
what you give them. Help stamp out software-hoarding! */
#include "config.h"
+#include "system.h"
+#include "gansidecl.h"
+#include "cpplib.h"
static void
memory_full ()
{
- fatal ("Memory exhausted.");
+ fprintf (stderr, "%s: Memory exhausted.\n", progname);
+ exit (FATAL_EXIT_CODE);
}
char *
@@ -35,10 +39,9 @@ xmalloc (size)
unsigned size;
{
register char *ptr = (char *) malloc (size);
- if (ptr != 0) return (ptr);
- memory_full ();
- /*NOTREACHED*/
- return 0;
+ if (ptr == 0)
+ memory_full ();
+ return ptr;
}
char *
@@ -51,14 +54,3 @@ xrealloc (old, size)
memory_full ();
return ptr;
}
-
-char *
-xcalloc (number, size)
- unsigned number, size;
-{
- register unsigned total = number * size;
- register char *ptr = (char *) calloc (number, size);
- if (ptr == 0)
- memory_full ();
- return ptr;
-}
diff --git a/contrib/gcc/cpperror.c b/contrib/gcc/cpperror.c
index 5ba3b78..c4cac06 100644
--- a/contrib/gcc/cpperror.c
+++ b/contrib/gcc/cpperror.c
@@ -1,7 +1,7 @@
/* Default error handlers for CPP Library.
- Copyright (C) 1986, 87, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1986, 87, 89, 92 - 95, 1998 Free Software Foundation, Inc.
Written by Per Bothner, 1994.
- Based on CCCP program by by Paul Rubin, June 1986
+ Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
This program is free software; you can redistribute it and/or modify it
@@ -24,10 +24,18 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef EMACS
#include "config.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
+#include "gansidecl.h"
+#else
+#include <stdio.h>
#endif /* not EMACS */
#include "cpplib.h"
-#include <stdio.h>
/* Print the file names and line numbers of the #include
commands which led to the current file. */
@@ -37,7 +45,6 @@ cpp_print_containing_files (pfile)
cpp_reader *pfile;
{
cpp_buffer *ip;
- int i;
int first = 1;
/* If stack of files hasn't changed since we last printed
@@ -67,7 +74,7 @@ cpp_print_containing_files (pfile)
fprintf (stderr, ",\n ");
}
- fprintf (stderr, " from %s:%d", ip->nominal_fname, line);
+ fprintf (stderr, " from %s:%ld", ip->nominal_fname, line);
}
if (! first)
fprintf (stderr, ":\n");
@@ -78,7 +85,7 @@ cpp_print_containing_files (pfile)
void
cpp_file_line_for_message (pfile, filename, line, column)
- cpp_reader *pfile;
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
char *filename;
int line, column;
{
@@ -88,36 +95,78 @@ cpp_file_line_for_message (pfile, filename, line, column)
fprintf (stderr, "%s:%d: ", filename, line);
}
-/* IS_ERROR is 1 for error, 0 for warning */
-void cpp_message (pfile, is_error, msg, arg1, arg2, arg3)
- int is_error;
- cpp_reader *pfile;
- char *msg;
- char *arg1, *arg2, *arg3;
+/* IS_ERROR is 2 for "fatal" error, 1 for error, 0 for warning */
+
+void
+v_cpp_message (pfile, is_error, msg, ap)
+ cpp_reader * pfile;
+ int is_error;
+ const char *msg;
+ va_list ap;
{
- if (is_error)
- pfile->errors++;
- else
+ if (!is_error)
fprintf (stderr, "warning: ");
- fprintf (stderr, msg, arg1, arg2, arg3);
+ else if (is_error == 2)
+ pfile->errors = CPP_FATAL_LIMIT;
+ else if (pfile->errors < CPP_FATAL_LIMIT)
+ pfile->errors++;
+ vfprintf (stderr, msg, ap);
fprintf (stderr, "\n");
}
void
-fatal (str, arg)
- char *str, *arg;
+cpp_message VPROTO ((cpp_reader *pfile, int is_error, const char *msg, ...))
{
- fprintf (stderr, "%s: ", progname);
- fprintf (stderr, str, arg);
- fprintf (stderr, "\n");
- exit (FATAL_EXIT_CODE);
+#ifndef __STDC__
+ cpp_reader *pfile;
+ int is_error;
+ const char *msg;
+#endif
+ va_list ap;
+
+ VA_START (ap, msg);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ is_error = va_arg (ap, int);
+ msg = va_arg (ap, const char *);
+#endif
+
+ v_cpp_message(pfile, is_error, msg, ap);
+ va_end(ap);
}
+/* Same as cpp_error, except we consider the error to be "fatal",
+ such as inconsistent options. I.e. there is little point in continuing.
+ (We do not exit, to support use of cpplib as a library.
+ Instead, it is the caller's responsibility to check
+ CPP_FATAL_ERRORS. */
+
+void
+cpp_fatal VPROTO ((cpp_reader *pfile, const char *str, ...))
+{
+#ifndef __STDC__
+ cpp_reader *pfile;
+ const char *str;
+#endif
+ va_list ap;
+
+ VA_START (ap, str);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ str = va_arg (ap, const char *);
+#endif
+
+ fprintf (stderr, "%s: ", progname);
+ v_cpp_message (pfile, 2, str, ap);
+ va_end(ap);
+}
void
cpp_pfatal_with_name (pfile, name)
cpp_reader *pfile;
- char *name;
+ const char *name;
{
cpp_perror_with_name (pfile, name);
#ifdef VMS
diff --git a/contrib/gcc/cppexp.c b/contrib/gcc/cppexp.c
index 6b73ad3..44f8a66 100644
--- a/contrib/gcc/cppexp.c
+++ b/contrib/gcc/cppexp.c
@@ -1,5 +1,5 @@
/* Parse C expressions for CCCP.
- Copyright (C) 1987, 1992, 1994, 1995 Free Software Foundation.
+ Copyright (C) 1987, 1992, 1994, 1995, 1997, 1998 Free Software Foundation.
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
@@ -20,23 +20,22 @@ Boston, MA 02111-1307, USA.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding!
-Written by Per Bothner 1994. */
+Written by Per Bothner 1994. */
/* Parse a C expression from text in a string */
#include "config.h"
+#include "system.h"
+#include "gansidecl.h"
#include "cpplib.h"
extern char *xmalloc PARAMS ((unsigned));
-extern char *xrealloc PARAMS ((char *, unsigned));
+extern char *xrealloc PARAMS ((void *, unsigned));
#ifdef MULTIBYTE_CHARS
-#include <stdlib.h>
#include <locale.h>
#endif
-#include <stdio.h>
-
/* This is used for communicating lists of keywords with cccp.c. */
struct arglist {
struct arglist *next;
@@ -45,26 +44,6 @@ struct arglist {
int argno;
};
-/* Define a generic NULL if one hasn't already been defined. */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
-#endif
-#endif
-
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
-#endif
-
-extern char *xmalloc ();
-
#ifndef CHAR_TYPE_SIZE
#define CHAR_TYPE_SIZE BITS_PER_UNIT
#endif
@@ -101,9 +80,9 @@ extern char *xmalloc ();
number with SUM's sign, where A, B, and SUM are all C integers. */
#define possible_sum_sign(a, b, sum) ((((a) ^ (b)) | ~ ((a) ^ (sum))) < 0)
-static void integer_overflow ();
-static long left_shift ();
-static long right_shift ();
+static void integer_overflow PARAMS ((cpp_reader *));
+static long left_shift PARAMS ((cpp_reader *, long, int, unsigned long));
+static long right_shift PARAMS ((cpp_reader *, long, int, unsigned long));
#define ERROR 299
#define OROR 300
@@ -121,26 +100,47 @@ static long right_shift ();
#define LEFT_OPERAND_REQUIRED 1
#define RIGHT_OPERAND_REQUIRED 2
#define HAVE_VALUE 4
-/*#define UNSIGNEDP 8*/
-
-#ifndef HOST_BITS_PER_WIDE_INT
+/* SKIP_OPERAND is set for '&&' '||' '?' and ':' when the
+ following operand should be short-circuited instead of evaluated. */
+#define SKIP_OPERAND 8
+/*#define UNSIGNEDP 16*/
+
+/* Find the largest host integer type and set its size and type.
+ Watch out: on some crazy hosts `long' is shorter than `int'. */
+
+#ifndef HOST_WIDE_INT
+# if HAVE_INTTYPES_H
+# include <inttypes.h>
+# define HOST_WIDE_INT intmax_t
+# else
+# if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT \
+ && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT)
+# define HOST_WIDE_INT int
+# else
+# if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG \
+ || ! (defined LONG_LONG_MAX || defined LLONG_MAX))
+# define HOST_WIDE_INT long
+# else
+# define HOST_WIDE_INT long long
+# endif
+# endif
+# endif
+#endif
-#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
-#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
-#define HOST_WIDE_INT long
-#else
-#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
-#define HOST_WIDE_INT int
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
#endif
+#ifndef HOST_BITS_PER_WIDE_INT
+#define HOST_BITS_PER_WIDE_INT (CHAR_BIT * sizeof (HOST_WIDE_INT))
#endif
struct operation {
short op;
- char rprio; /* Priority of op (relative to it right operand). */
+ char rprio; /* Priority of op (relative to it right operand). */
char flags;
char unsignedp; /* true if value should be treated as unsigned */
- HOST_WIDE_INT value; /* The value logically "right" of op. */
+ HOST_WIDE_INT value; /* The value logically "right" of op. */
};
/* Take care of parsing a number (anything that starts with a digit).
@@ -183,7 +183,7 @@ parse_number (pfile, start, olen)
else if (*p == '0')
base = 8;
- /* Some buggy compilers (e.g. MPW C) seem to need both casts. */
+ /* Some buggy compilers (e.g. MPW C) seem to need both casts. */
ULONG_MAX_over_base = ((unsigned long) -1) / ((unsigned long) base);
for (; len > 0; len--) {
@@ -223,7 +223,7 @@ parse_number (pfile, start, olen)
if (largest_digit < digit)
largest_digit = digit;
nd = n * base + digit;
- overflow |= ULONG_MAX_over_base < n | nd < n;
+ overflow |= ULONG_MAX_over_base < n || nd < n;
n = nd;
}
@@ -235,10 +235,10 @@ parse_number (pfile, start, olen)
}
if (base <= largest_digit)
- cpp_warning (pfile, "integer constant contains digits beyond the radix");
+ cpp_pedwarn (pfile, "integer constant contains digits beyond the radix");
if (overflow)
- cpp_warning (pfile, "integer constant out of range");
+ cpp_pedwarn (pfile, "integer constant out of range");
/* If too big to be signed, consider it unsigned. */
if ((long) n < 0 && ! op.unsignedp)
@@ -272,14 +272,14 @@ static struct token tokentab2[] = {
{NULL, ERROR}
};
-/* Read one token. */
+/* Read one token. */
struct operation
-cpp_lex (pfile)
-cpp_reader *pfile;
+cpp_lex (pfile, skip_evaluation)
+ cpp_reader *pfile;
+ int skip_evaluation;
{
register int c;
- register int namelen;
register struct token *toktab;
enum cpp_token token;
struct operation op;
@@ -307,16 +307,17 @@ cpp_reader *pfile;
pfile->limit = tok_start;
switch (token)
{
- case CPP_EOF: /* Should not happen ... */
+ case CPP_EOF: /* Should not happen ... */
+ case CPP_VSPACE:
op.op = 0;
return op;
- case CPP_VSPACE:
case CPP_POP:
if (CPP_BUFFER (pfile)->fname != NULL)
{
op.op = 0;
return op;
}
+ cpp_pop_buffer (pfile);
goto retry;
case CPP_HSPACE: case CPP_COMMENT:
goto retry;
@@ -332,7 +333,7 @@ cpp_reader *pfile;
It is mostly copied from c-lex.c. */
{
register int result = 0;
- register num_chars = 0;
+ register int num_chars = 0;
unsigned width = MAX_CHAR_TYPE_SIZE;
int wide_flag = 0;
int max_chars;
@@ -362,7 +363,7 @@ cpp_reader *pfile;
{
if (c == '\\')
{
- c = cpp_parse_escape (pfile, &ptr);
+ c = cpp_parse_escape (pfile, (char **) &ptr);
if (width < HOST_BITS_PER_INT
&& (unsigned) c >= (1 << width))
cpp_pedwarn (pfile,
@@ -401,7 +402,7 @@ cpp_reader *pfile;
{
int num_bits = num_chars * width;
- if (cpp_lookup (pfile, "__CHAR_UNSIGNED__",
+ if (cpp_lookup (pfile, (U_CHAR *)"__CHAR_UNSIGNED__",
sizeof ("__CHAR_UNSIGNED__")-1, -1)
|| ((result >> (num_bits - 1)) & 1) == 0)
op.value
@@ -425,7 +426,7 @@ cpp_reader *pfile;
if (mbtowc (& wc, token_buffer, num_chars) == num_chars)
result = wc;
else
- cpp_warning (pfile,"Ignoring invalid multibyte character");
+ cpp_pedwarn (pfile,"Ignoring invalid multibyte character");
}
#endif
op.value = result;
@@ -439,6 +440,9 @@ cpp_reader *pfile;
return op;
case CPP_NAME:
+ if (CPP_WARN_UNDEF (pfile) && !skip_evaluation)
+ cpp_warning (pfile, "`%.*s' is not defined",
+ (int) (tok_end - tok_start), tok_start);
return parse_number (pfile, "0", 0);
case CPP_OTHER:
@@ -538,7 +542,7 @@ cpp_parse_escape (pfile, string_ptr)
if ((i & ~((1 << MAX_CHAR_TYPE_SIZE) - 1)) != 0)
{
i &= (1 << MAX_CHAR_TYPE_SIZE) - 1;
- cpp_warning (pfile,
+ cpp_pedwarn (pfile,
"octal character constant does not fit in a byte");
}
return i;
@@ -569,7 +573,7 @@ cpp_parse_escape (pfile, string_ptr)
if (overflow | (i & ~((1 << BITS_PER_UNIT) - 1)))
{
i &= (1 << BITS_PER_UNIT) - 1;
- cpp_warning (pfile,
+ cpp_pedwarn (pfile,
"hex character constant does not fit in a byte");
}
return i;
@@ -613,7 +617,7 @@ left_shift (pfile, a, unsignedp, b)
static long
right_shift (pfile, a, unsignedp, b)
- cpp_reader *pfile;
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
long a;
int unsignedp;
unsigned long b;
@@ -626,7 +630,7 @@ right_shift (pfile, a, unsignedp, b)
return a >> b;
}
-/* These priorities are all even, so we can handle associatively. */
+/* These priorities are all even, so we can handle associatively. */
#define PAREN_INNER_PRIO 0
#define COMMA_PRIO 4
#define COND_PRIO (COMMA_PRIO+2)
@@ -670,6 +674,7 @@ cpp_parse_expr (pfile)
struct operation *limit = stack + INIT_STACK_SIZE;
register struct operation *top = stack;
int lprio, rprio;
+ int skip_evaluation = 0;
top->rprio = 0;
top->flags = 0;
@@ -679,17 +684,16 @@ cpp_parse_expr (pfile)
char flags = 0;
/* Read a token */
- op = cpp_lex (pfile);
+ op = cpp_lex (pfile, skip_evaluation);
/* See if the token is an operand, in which case go to set_value.
If the token is an operator, figure out its left and right
- priorities, and then goto maybe_reduce. */
+ priorities, and then goto maybe_reduce. */
switch (op.op)
{
case NAME:
- top->value = 0, top->unsignedp = 0;
- goto set_value;
+ abort ();
case INT: case CHAR:
top->value = op.value;
top->unsignedp = op.unsignedp;
@@ -740,7 +744,7 @@ cpp_parse_expr (pfile)
}
set_value:
- /* Push a value onto the stack. */
+ /* Push a value onto the stack. */
if (top->flags & HAVE_VALUE)
{
cpp_error (pfile, "syntax error in #if");
@@ -750,7 +754,7 @@ cpp_parse_expr (pfile)
continue;
maybe_reduce:
- /* Push an operator, and check if we can reduce now. */
+ /* Push an operator, and check if we can reduce now. */
while (top->rprio > lprio)
{
long v1 = top[-1].value, v2 = top[0].value;
@@ -782,7 +786,7 @@ cpp_parse_expr (pfile)
{
top->value = v1 + v2;
top->unsignedp = unsigned1 || unsigned2;
- if (! top->unsignedp
+ if (! top->unsignedp && ! skip_evaluation
&& ! possible_sum_sign (v1, v2, top->value))
integer_overflow (pfile);
}
@@ -791,7 +795,7 @@ cpp_parse_expr (pfile)
if (!(top->flags & HAVE_VALUE))
{ /* Unary '-' */
top->value = - v2;
- if ((top->value & v2) < 0 && ! unsigned2)
+ if (!skip_evaluation && (top->value & v2) < 0 && !unsigned2)
integer_overflow (pfile);
top->unsignedp = unsigned2;
top->flags |= HAVE_VALUE;
@@ -800,7 +804,7 @@ cpp_parse_expr (pfile)
{ /* Binary '-' */
top->value = v1 - v2;
top->unsignedp = unsigned1 || unsigned2;
- if (! top->unsignedp
+ if (! top->unsignedp && ! skip_evaluation
&& ! possible_sum_sign (top->value, v2, v1))
integer_overflow (pfile);
}
@@ -809,7 +813,7 @@ cpp_parse_expr (pfile)
top->unsignedp = unsigned1 || unsigned2;
if (top->unsignedp)
top->value = (unsigned long) v1 * v2;
- else
+ else if (!skip_evaluation)
{
top->value = v1 * v2;
if (v1
@@ -819,6 +823,8 @@ cpp_parse_expr (pfile)
}
break;
case '/':
+ if (skip_evaluation)
+ break;
if (v2 == 0)
{
cpp_error (pfile, "division by zero in #if");
@@ -835,6 +841,8 @@ cpp_parse_expr (pfile)
}
break;
case '%':
+ if (skip_evaluation)
+ break;
if (v2 == 0)
{
cpp_error (pfile, "division by zero in #if");
@@ -879,6 +887,8 @@ cpp_parse_expr (pfile)
top->unsignedp = 0;
break;
case LSH:
+ if (skip_evaluation)
+ break;
top->unsignedp = unsigned1;
if (v2 < 0 && ! unsigned2)
top->value = right_shift (pfile, v1, unsigned1, -v2);
@@ -886,6 +896,8 @@ cpp_parse_expr (pfile)
top->value = left_shift (pfile, v1, unsigned1, v2);
break;
case RSH:
+ if (skip_evaluation)
+ break;
top->unsignedp = unsigned1;
if (v2 < 0 && ! unsigned2)
top->value = left_shift (pfile, v1, unsigned1, -v2);
@@ -899,9 +911,13 @@ cpp_parse_expr (pfile)
case '^': LOGICAL(^); break;
case '|': LOGICAL(|); break;
case ANDAND:
- top->value = v1 && v2; top->unsignedp = 0; break;
+ top->value = v1 && v2; top->unsignedp = 0;
+ if (!v1) skip_evaluation--;
+ break;
case OROR:
- top->value = v1 || v2; top->unsignedp = 0; break;
+ top->value = v1 || v2; top->unsignedp = 0;
+ if (v1) skip_evaluation--;
+ break;
case ',':
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "comma operator in operand of `#if'");
@@ -928,6 +944,7 @@ cpp_parse_expr (pfile)
else
{
top--;
+ if (top->value) skip_evaluation--;
top->value = top->value ? v1 : v2;
top->unsignedp = unsigned1 || unsigned2;
}
@@ -967,27 +984,40 @@ cpp_parse_expr (pfile)
}
top++;
- /* Check for and handle stack overflow. */
+ /* Check for and handle stack overflow. */
if (top == limit)
{
struct operation *new_stack;
- int old_size = (char*)limit - (char*)stack;
+ int old_size = (char *) limit - (char *) stack;
int new_size = 2 * old_size;
if (stack != init_stack)
- new_stack = (struct operation*) xrealloc (stack, new_size);
+ new_stack = (struct operation *) xrealloc (stack, new_size);
else
{
- new_stack = (struct operation*) xmalloc (new_size);
+ new_stack = (struct operation *) xmalloc (new_size);
bcopy ((char *) stack, (char *) new_stack, old_size);
}
stack = new_stack;
- top = (struct operation*)((char*) new_stack + old_size);
- limit = (struct operation*)((char*) new_stack + new_size);
+ top = (struct operation *) ((char *) new_stack + old_size);
+ limit = (struct operation *) ((char *) new_stack + new_size);
}
top->flags = flags;
top->rprio = rprio;
top->op = op.op;
+ if ((op.op == OROR && top[-1].value)
+ || (op.op == ANDAND && !top[-1].value)
+ || (op.op == '?' && !top[-1].value))
+ {
+ skip_evaluation++;
+ }
+ else if (op.op == ':')
+ {
+ if (top[-2].value) /* Was condition true? */
+ skip_evaluation++;
+ else
+ skip_evaluation--;
+ }
}
syntax_error:
if (stack != init_stack)
diff --git a/contrib/gcc/cpphash.c b/contrib/gcc/cpphash.c
index bd06e95..6aa9e9c 100644
--- a/contrib/gcc/cpphash.c
+++ b/contrib/gcc/cpphash.c
@@ -1,7 +1,7 @@
/* Part of CPP library. (Macro hash table support.)
- Copyright (C) 1986, 87, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1986, 87, 89, 92-95, 1996 Free Software Foundation, Inc.
Written by Per Bothner, 1994.
- Based on CCCP program by by Paul Rubin, June 1986
+ Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
This program is free software; you can redistribute it and/or modify it
@@ -22,26 +22,17 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding! */
+#include "config.h"
+#include "system.h"
+#include "gansidecl.h"
#include "cpplib.h"
#include "cpphash.h"
extern char *xmalloc PARAMS ((unsigned));
-/* Define a generic NULL if one hasn't already been defined. */
+/* Return hash function on name. must be compatible with the one
+ computed a step at a time, elsewhere */
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef __STDC__
-#define const
-#define volatile
-#endif
-
-/*
- * return hash function on name. must be compatible with the one
- * computed a step at a time, elsewhere
- */
int
hashf (name, len, hashsize)
register const U_CHAR *name;
@@ -56,19 +47,18 @@ hashf (name, len, hashsize)
return MAKE_POS (r) % hashsize;
}
-/*
- * find the most recent hash node for name name (ending with first
- * non-identifier char) installed by install
- *
- * If LEN is >= 0, it is the length of the name.
- * Otherwise, compute the length by scanning the entire name.
- *
- * If HASH is >= 0, it is the precomputed hash code.
- * Otherwise, compute the hash code.
- */
+/* Find the most recent hash node for name "name" (ending with first
+ non-identifier char) installed by install
+
+ If LEN is >= 0, it is the length of the name.
+ Otherwise, compute the length by scanning the entire name.
+
+ If HASH is >= 0, it is the precomputed hash code.
+ Otherwise, compute the hash code. */
+
HASHNODE *
cpp_lookup (pfile, name, len, hash)
- struct parse_file *pfile;
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
const U_CHAR *name;
int len;
int hash;
@@ -91,7 +81,7 @@ cpp_lookup (pfile, name, len, hash)
return bucket;
bucket = bucket->next;
}
- return (HASHNODE*) 0;
+ return (HASHNODE *) 0;
}
/*
@@ -119,7 +109,7 @@ delete_macro (hp)
hp->next->prev = hp->prev;
/* make sure that the bucket chain header that
- the deleted guy was on points to the right thing afterwards. */
+ the deleted guy was on points to the right thing afterwards. */
if (hp == *hp->bucket_hdr)
*hp->bucket_hdr = hp->next;
@@ -140,20 +130,20 @@ delete_macro (hp)
free (hp);
}
-/*
- * install a name in the main hash table, even if it is already there.
- * name stops with first non alphanumeric, except leading '#'.
- * caller must check against redefinition if that is desired.
- * delete_macro () removes things installed by install () in fifo order.
- * this is important because of the `defined' special symbol used
- * in #if, and also if pushdef/popdef directives are ever implemented.
- *
- * If LEN is >= 0, it is the length of the name.
- * Otherwise, compute the length by scanning the entire name.
- *
- * If HASH is >= 0, it is the precomputed hash code.
- * Otherwise, compute the hash code.
- */
+
+/* Install a name in the main hash table, even if it is already there.
+ name stops with first non alphanumeric, except leading '#'.
+ caller must check against redefinition if that is desired.
+ delete_macro () removes things installed by install () in fifo order.
+ this is important because of the `defined' special symbol used
+ in #if, and also if pushdef/popdef directives are ever implemented.
+
+ If LEN is >= 0, it is the length of the name.
+ Otherwise, compute the length by scanning the entire name.
+
+ If HASH is >= 0, it is the precomputed hash code.
+ Otherwise, compute the hash code. */
+
HASHNODE *
install (name, len, type, ivalue, value, hash)
U_CHAR *name;
@@ -203,7 +193,7 @@ install (name, len, type, ivalue, value, hash)
void
cpp_hash_cleanup (pfile)
- cpp_reader *pfile;
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
{
register int i;
for (i = HASHSIZE; --i >= 0; )
diff --git a/contrib/gcc/cpphash.h b/contrib/gcc/cpphash.h
index 914a12f..2b0668d 100644
--- a/contrib/gcc/cpphash.h
+++ b/contrib/gcc/cpphash.h
@@ -35,4 +35,6 @@ static HASHNODE *hashtab[HASHSIZE];
#define HASHSTEP(old, c) ((old << 2) + c)
#define MAKE_POS(v) (v & 0x7fffffff) /* make number positive */
-extern HASHNODE* install PARAMS ((U_CHAR*,int,enum node_type, int,char*,int));
+extern HASHNODE *install PARAMS ((U_CHAR *,int,enum node_type, int,char *,int));
+extern int hashf PARAMS ((const U_CHAR *, int, int));
+extern void delete_macro PARAMS ((HASHNODE *));
diff --git a/contrib/gcc/cpplib.c b/contrib/gcc/cpplib.c
index 8e91a09..5b10349 100644
--- a/contrib/gcc/cpplib.c
+++ b/contrib/gcc/cpplib.c
@@ -1,7 +1,7 @@
/* CPP Library.
- Copyright (C) 1986, 87, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
- Written by Per Bothner, 1994-95.
- Based on CCCP program by by Paul Rubin, June 1986
+ Copyright (C) 1986, 87, 89, 92-97, 1998 Free Software Foundation, Inc.
+ Contributed by Per Bothner, 1994-95.
+ Based on CCCP program by Paul Rubin, June 1986
Adapted to ANSI C, Richard Stallman, Jan 1987
This program is free software; you can redistribute it and/or modify it
@@ -16,102 +16,65 @@ 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding! */
-
-#ifdef EMACS
-#define NO_SHORTNAMES
-#include "../src/config.h"
-#ifdef open
-#undef open
-#undef read
-#undef write
-#endif /* open */
-#endif /* EMACS */
-
-/* The macro EMACS is defined when cpp is distributed as part of Emacs,
- for the sake of machines with limited C compilers. */
-#ifndef EMACS
-#include "config.h"
-#endif /* not EMACS */
-
-#ifndef STANDARD_INCLUDE_DIR
-#define STANDARD_INCLUDE_DIR "/usr/include"
-#endif
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#ifndef LOCAL_INCLUDE_DIR
-#define LOCAL_INCLUDE_DIR "/usr/local/include"
-#endif
-
-#if 0 /* We can't get ptrdiff_t, so I arranged not to need PTR_INT_TYPE. */
+#include "config.h"
#ifdef __STDC__
-#define PTR_INT_TYPE ptrdiff_t
+#include <stdarg.h>
#else
-#define PTR_INT_TYPE long
+#include <varargs.h>
#endif
-#endif /* 0 */
-
-#include "cpplib.h"
-#include "cpphash.h"
+#include "system.h"
#ifndef STDC_VALUE
#define STDC_VALUE 1
#endif
-/* By default, colon separates directories in a path. */
-#ifndef PATH_SEPARATOR
-#define PATH_SEPARATOR ':'
-#endif
-
-#include <ctype.h>
-#include <stdio.h>
#include <signal.h>
-#ifdef __STDC__
-#include <stdlib.h>
-#endif
-#ifndef VMS
-#ifndef USG
-#include <sys/time.h> /* for __DATE__ and __TIME__ */
-#include <sys/resource.h>
-#else
-#include <sys/param.h> /* CYGNUS LOCAL: shebs -noquiet */
+#ifdef HAVE_SYS_TIMES_H
#include <sys/times.h>
-#include <time.h>
-#include <fcntl.h>
-#endif /* USG */
-#endif /* not VMS */
+#endif
-/* This defines "errno" properly for VMS, and gives us EACCES. */
-#include <errno.h>
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif
-extern char *index ();
-extern char *rindex ();
+#include "gansidecl.h"
+#include "cpplib.h"
+#include "cpphash.h"
-#ifndef O_RDONLY
-#define O_RDONLY 0
+#ifndef GET_ENVIRONMENT
+#define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ENV_VALUE = getenv (ENV_NAME)
#endif
+extern char *update_path PARAMS ((char *, char *));
+
#undef MIN
#undef MAX
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
-/* Find the largest host integer type and set its size and type. */
-
-#ifndef HOST_BITS_PER_WIDE_INT
-
-#if HOST_BITS_PER_LONG > HOST_BITS_PER_INT
-#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_LONG
-#define HOST_WIDE_INT long
-#else
-#define HOST_BITS_PER_WIDE_INT HOST_BITS_PER_INT
-#define HOST_WIDE_INT int
-#endif
-
+/* Find the largest host integer type and set its size and type.
+ Watch out: on some crazy hosts `long' is shorter than `int'. */
+
+#ifndef HOST_WIDE_INT
+# if HAVE_INTTYPES_H
+# include <inttypes.h>
+# define HOST_WIDE_INT intmax_t
+# else
+# if (HOST_BITS_PER_LONG <= HOST_BITS_PER_INT \
+ && HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_INT)
+# define HOST_WIDE_INT int
+# else
+# if (HOST_BITS_PER_LONGLONG <= HOST_BITS_PER_LONG \
+ || ! (defined LONG_LONG_MAX || defined LLONG_MAX))
+# define HOST_WIDE_INT long
+# else
+# define HOST_WIDE_INT long long
+# endif
+# endif
+# endif
#endif
#ifndef S_ISREG
@@ -122,24 +85,14 @@ extern char *rindex ();
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#endif
-/* Define a generic NULL if one hasn't already been defined. */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
-#endif
+/* By default, colon separates directories in a path. */
+#ifndef PATH_SEPARATOR
+#define PATH_SEPARATOR ':'
#endif
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
+#ifndef STANDARD_INCLUDE_DIR
+#define STANDARD_INCLUDE_DIR "/usr/include"
#endif
-
#ifndef INCLUDE_LEN_FUDGE
#define INCLUDE_LEN_FUDGE 0
#endif
@@ -205,7 +158,7 @@ struct assertion_hashnode {
struct assertion_hashnode *prev;
/* also, a back pointer to this node's hash
chain is kept, in case the node is the head
- of the chain and gets deleted. */
+ of the chain and gets deleted. */
struct assertion_hashnode **bucket_hdr;
int length; /* length of token, for quick comparison */
U_CHAR *name; /* the actual name */
@@ -234,7 +187,7 @@ struct assertion_hashnode {
#define NEWLINE_FIX \
do {while (PEEKC() == '\\' && PEEKN(1) == '\n') FORWARD(2); } while(0)
-/* Same, but assume we've already read the potential '\\' into C. */
+/* Same, but assume we've already read the potential '\\' into C. */
#define NEWLINE_FIX1(C) do { \
while ((C) == '\\' && PEEKC() == '\n') { FORWARD(1); (C) = GETC(); }\
} while(0)
@@ -247,87 +200,69 @@ struct cpp_pending {
/* Forward declarations. */
-extern char *xmalloc ();
-
-static void add_import ();
-static void append_include_chain ();
-static void make_undef ();
-static void make_assertion ();
-static void path_include ();
-static void initialize_builtins ();
-static void initialize_char_syntax ();
-static void dump_arg_n ();
-static void dump_defn_1 ();
-extern void delete_macro ();
+char *xmalloc ();
+extern void cpp_hash_cleanup PARAMS ((cpp_reader *));
+
+static char *my_strerror PROTO ((int));
+static void add_import PROTO ((cpp_reader *, int, char *));
+static void append_include_chain PROTO ((cpp_reader *,
+ struct file_name_list *,
+ struct file_name_list *));
+static void make_assertion PROTO ((cpp_reader *, char *, U_CHAR *));
+static void path_include PROTO ((cpp_reader *, char *));
+static void initialize_builtins PROTO ((cpp_reader *));
+static void initialize_char_syntax PROTO ((struct cpp_options *));
+#if 0
static void trigraph_pcp ();
-static int finclude ();
-static void validate_else ();
-static int comp_def_part ();
+#endif
+static int finclude PROTO ((cpp_reader *, int, char *,
+ int, struct file_name_list *));
+static void validate_else PROTO ((cpp_reader *, char *));
+static int comp_def_part PROTO ((int, U_CHAR *, int, U_CHAR *,
+ int, int));
+#ifdef abort
extern void fancy_abort ();
-static void pipe_closed ();
-static void print_containing_files ();
-static int lookup_import ();
-static int redundant_include_p ();
-static is_system_include ();
-static struct file_name_map *read_name_map ();
-static char *read_filename_string ();
-static int open_include_file ();
-static int check_preconditions ();
-static void pcfinclude ();
-static void pcstring_used ();
-static int check_macro_name ();
-static int compare_defs ();
-static int compare_token_lists ();
-static HOST_WIDE_INT eval_if_expression ();
-static int change_newlines ();
-extern int hashf ();
-static int file_size_and_mode ();
-static struct arglist *read_token_list ();
-static void free_token_list ();
-static int safe_read ();
+#endif
+static int lookup_import PROTO ((cpp_reader *, char *,
+ struct file_name_list *));
+static int redundant_include_p PROTO ((cpp_reader *, char *));
+static int is_system_include PROTO ((cpp_reader *, char *));
+static struct file_name_map *read_name_map PROTO ((cpp_reader *, char *));
+static char *read_filename_string PROTO ((int, FILE *));
+static int open_include_file PROTO ((cpp_reader *, char *,
+ struct file_name_list *));
+static int check_macro_name PROTO ((cpp_reader *, U_CHAR *, char *));
+static int compare_defs PROTO ((cpp_reader *,
+ DEFINITION *, DEFINITION *));
+static int compare_token_lists PROTO ((struct arglist *,
+ struct arglist *));
+static HOST_WIDE_INT eval_if_expression PROTO ((cpp_reader *, U_CHAR *, int));
+static int change_newlines PROTO ((U_CHAR *, int));
+static struct arglist *read_token_list PROTO ((cpp_reader *, int *));
+static void free_token_list PROTO ((struct arglist *));
+static int safe_read PROTO ((int, char *, int));
static void push_macro_expansion PARAMS ((cpp_reader *,
- U_CHAR*, int, HASHNODE*));
-static struct cpp_pending *nreverse_pending PARAMS ((struct cpp_pending*));
+ U_CHAR *, int, HASHNODE *));
+static struct cpp_pending *nreverse_pending PARAMS ((struct cpp_pending *));
extern char *xrealloc ();
-extern char *xcalloc ();
-static char *savestring ();
+static char *xcalloc PROTO ((unsigned, unsigned));
+static char *savestring PROTO ((char *));
-static void conditional_skip ();
-static void skip_if_group ();
+static void conditional_skip PROTO ((cpp_reader *, int,
+ enum node_type, U_CHAR *));
+static void skip_if_group PROTO ((cpp_reader *, int));
+static int parse_name PARAMS ((cpp_reader *, int));
+static void print_help PROTO ((void));
/* Last arg to output_line_command. */
enum file_change_code {same_file, enter_file, leave_file};
/* External declarations. */
-extern HOST_WIDE_INT cpp_parse_expr PARAMS ((cpp_reader*));
+extern HOST_WIDE_INT cpp_parse_expr PARAMS ((cpp_reader *));
-extern char *getenv ();
-extern FILE *fdopen ();
extern char *version_string;
extern struct tm *localtime ();
-
-/* These functions are declared to return int instead of void since they
- are going to be placed in a table and some old compilers have trouble with
- pointers to functions returning void. */
-
-static int do_define ();
-static int do_line ();
-static int do_include ();
-static int do_undef ();
-static int do_error ();
-static int do_pragma ();
-static int do_ident ();
-static int do_if ();
-static int do_xifdef ();
-static int do_else ();
-static int do_elif ();
-static int do_endif ();
-static int do_sccs ();
-static int do_once ();
-static int do_assert ();
-static int do_unassert ();
-static int do_warning ();
struct file_name_list
{
@@ -346,15 +281,16 @@ struct file_name_list
};
/* If a buffer's dir field is SELF_DIR_DUMMY, it means the file was found
- via the same directory as the file that #included it. */
-#define SELF_DIR_DUMMY ((struct file_name_list*)(~0))
+ via the same directory as the file that #included it. */
+#define SELF_DIR_DUMMY ((struct file_name_list *) (~0))
-/* #include "file" looks in source file dir, then stack. */
-/* #include <file> just looks in the stack. */
-/* -I directories are added to the end, then the defaults are added. */
+/* #include "file" looks in source file dir, then stack. */
+/* #include <file> just looks in the stack. */
+/* -I directories are added to the end, then the defaults are added. */
/* The */
static struct default_include {
char *fname; /* The name of the directory. */
+ char *component; /* The component containing the directory */
int cplusplus; /* Only look here if we're compiling C++. */
int cxx_aware; /* Includes in this directory don't need to
be wrapped in extern "C" when compiling
@@ -365,33 +301,43 @@ static struct default_include {
#else
= {
/* Pick up GNU C++ specific include files. */
- { GPLUSPLUS_INCLUDE_DIR, 1, 1 },
+ { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 },
+ { OLD_GPLUSPLUS_INCLUDE_DIR, 0, 1, 1 },
#ifdef CROSS_COMPILE
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
- { GCC_INCLUDE_DIR, 0, 0 },
+ { GCC_INCLUDE_DIR, "GCC", 0, 0 },
/* For cross-compilation, this dir name is generated
automatically in Makefile.in. */
- { CROSS_INCLUDE_DIR, 0, 0 },
+ { CROSS_INCLUDE_DIR, "GCC",0, 0 },
+#ifdef TOOL_INCLUDE_DIR
/* This is another place that the target system's headers might be. */
- { TOOL_INCLUDE_DIR, 0, 1 },
+ { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 },
+#endif
#else /* not CROSS_COMPILE */
+#ifdef LOCAL_INCLUDE_DIR
/* This should be /usr/local/include and should come before
the fixincludes-fixed header files. */
- { LOCAL_INCLUDE_DIR, 0, 1 },
+ { LOCAL_INCLUDE_DIR, 0, 0, 1 },
+#endif
+#ifdef TOOL_INCLUDE_DIR
/* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here.
Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h. */
- { TOOL_INCLUDE_DIR, 0, 1 },
+ { TOOL_INCLUDE_DIR, "BINUTILS", 0, 1 },
+#endif
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
- { GCC_INCLUDE_DIR, 0, 0 },
+ { GCC_INCLUDE_DIR, "GCC", 0, 0 },
/* Some systems have an extra dir of include files. */
#ifdef SYSTEM_INCLUDE_DIR
- { SYSTEM_INCLUDE_DIR, 0, 0 },
+ { SYSTEM_INCLUDE_DIR, 0, 0, 0 },
#endif
- { STANDARD_INCLUDE_DIR, 0, 0 },
+#ifndef STANDARD_INCLUDE_COMPONENT
+#define STANDARD_INCLUDE_COMPONENT 0
+#endif
+ { STANDARD_INCLUDE_DIR, STANDARD_INCLUDE_COMPONENT, 0, 0 },
#endif /* not CROSS_COMPILE */
- { 0, 0, 0 }
+ { 0, 0, 0, 0 }
};
#endif /* no INCLUDE_DEFAULTS */
@@ -399,19 +345,45 @@ static struct default_include {
struct directive {
int length; /* Length of name */
- int (*func)(); /* Function to handle directive */
+ int (*func) /* Function to handle directive */
+ PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
char *name; /* Name of directive */
- enum node_type type; /* Code which describes which directive. */
- char command_reads_line; /* One if rest of line is read by func. */
- char traditional_comments; /* Nonzero: keep comments if -traditional. */
- char pass_thru; /* Copy preprocessed directive to output file.*/
+ enum node_type type; /* Code which describes which directive. */
+ char command_reads_line; /* One if rest of line is read by func. */
};
+/* These functions are declared to return int instead of void since they
+ are going to be placed in a table and some old compilers have trouble with
+ pointers to functions returning void. */
+
+static int do_define PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_line PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_include PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_undef PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_error PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_pragma PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_ident PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_if PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_xifdef PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_else PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_elif PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_endif PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+#ifdef SCCS_DIRECTIVE
+static int do_sccs PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+#endif
+static int do_once PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_assert PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_unassert PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+static int do_warning PARAMS ((cpp_reader *, struct directive *, U_CHAR *, U_CHAR *));
+
+#define IS_INCLUDE_DIRECTIVE_TYPE(t) \
+((int) T_INCLUDE <= (int) (t) && (int) (t) <= (int) T_IMPORT)
+
/* Here is the actual list of #-directives, most-often-used first.
The initialize_builtins function assumes #define is the very first. */
static struct directive directive_table[] = {
- { 6, do_define, "define", T_DEFINE, 0, 1},
+ { 6, do_define, "define", T_DEFINE},
{ 5, do_xifdef, "ifdef", T_IFDEF, 1},
{ 6, do_xifdef, "ifndef", T_IFNDEF, 1},
{ 7, do_include, "include", T_INCLUDE, 1},
@@ -424,9 +396,9 @@ static struct directive directive_table[] = {
{ 5, do_undef, "undef", T_UNDEF},
{ 5, do_error, "error", T_ERROR},
{ 7, do_warning, "warning", T_WARNING},
- { 6, do_pragma, "pragma", T_PRAGMA, 0, 0, 1},
+ { 6, do_pragma, "pragma", T_PRAGMA},
{ 4, do_line, "line", T_LINE, 1},
- { 5, do_ident, "ident", T_IDENT, 1, 0, 1},
+ { 5, do_ident, "ident", T_IDENT, 1},
#ifdef SCCS_DIRECTIVE
{ 4, do_sccs, "sccs", T_SCCS},
#endif
@@ -435,9 +407,9 @@ static struct directive directive_table[] = {
{ -1, 0, "", T_UNUSED},
};
-/* table to tell if char can be part of a C identifier. */
+/* table to tell if char can be part of a C identifier. */
U_CHAR is_idchar[256];
-/* table to tell if char can be first char of a c identifier. */
+/* table to tell if char can be first char of a c identifier. */
U_CHAR is_idstart[256];
/* table to tell if c is horizontal space. */
U_CHAR is_hor_space[256];
@@ -488,7 +460,8 @@ initialize_char_syntax (opts)
/* Place into PFILE a quoted string representing the string SRC.
- Caller must reserve enough space in pfile->token_buffer. */
+ Caller must reserve enough space in pfile->token_buffer. */
+
static void
quote_string (pfile, src)
cpp_reader *pfile;
@@ -501,11 +474,11 @@ quote_string (pfile, src)
switch ((c = *src++))
{
default:
- if (isprint (c))
+ if (ISPRINT (c))
CPP_PUTC_Q (pfile, c);
else
{
- sprintf (CPP_PWRITTEN (pfile), "\\%03o", c);
+ sprintf ((char *)CPP_PWRITTEN (pfile), "\\%03o", c);
CPP_ADJUST_WRITTEN (pfile, 4);
}
break;
@@ -523,7 +496,7 @@ quote_string (pfile, src)
}
}
-/* Make sure PFILE->token_buffer will hold at least N more chars. */
+/* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */
void
cpp_grow_buffer (pfile, n)
@@ -532,7 +505,7 @@ cpp_grow_buffer (pfile, n)
{
long old_written = CPP_WRITTEN (pfile);
pfile->token_buffer_size = n + 2 * pfile->token_buffer_size;
- pfile->token_buffer = (U_CHAR*)
+ pfile->token_buffer = (U_CHAR *)
xrealloc(pfile->token_buffer, pfile->token_buffer_size);
CPP_SET_WRITTEN (pfile, old_written);
}
@@ -605,8 +578,6 @@ make_assertion (pfile, option, str)
char *option;
U_CHAR *str;
{
- cpp_buffer *ip;
- struct directive *kt;
U_CHAR *buf, *p, *q;
/* Copy the entire option so we can modify it. */
@@ -637,9 +608,11 @@ make_assertion (pfile, option, str)
return;
}
- ip = cpp_push_buffer (pfile, buf, strlen (buf));
- do_assert (pfile, NULL, NULL, NULL);
- cpp_pop_buffer (pfile);
+ if (cpp_push_buffer (pfile, buf, strlen (buf)) != NULL)
+ {
+ do_assert (pfile, NULL, NULL, NULL);
+ cpp_pop_buffer (pfile);
+ }
}
/* Append a chain of `struct file_name_list's
@@ -771,8 +744,8 @@ path_include (pfile, path)
}
void
-init_parse_options (opts)
- struct cpp_options *opts;
+cpp_options_init (opts)
+ cpp_options *opts;
{
bzero ((char *) opts, sizeof *opts);
opts->in_fname = NULL;
@@ -781,7 +754,6 @@ init_parse_options (opts)
/* Initialize is_idchar to allow $. */
opts->dollars_in_ident = 1;
initialize_char_syntax (opts);
- opts->dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 0;
opts->no_line_commands = 0;
opts->no_trigraphs = 1;
@@ -789,8 +761,9 @@ init_parse_options (opts)
opts->print_include_names = 0;
opts->dump_macros = dump_none;
opts->no_output = 0;
+ opts->remap = 0;
opts->cplusplus = 0;
- opts->cplusplus_comments = 0;
+ opts->cplusplus_comments = 1;
opts->verbose = 0;
opts->objc = 0;
@@ -806,15 +779,15 @@ init_parse_options (opts)
enum cpp_token
null_underflow (pfile)
- cpp_reader *pfile;
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
{
return CPP_EOF;
}
int
null_cleanup (pbuf, pfile)
- cpp_buffer *pbuf;
- cpp_reader *pfile;
+ cpp_buffer *pbuf ATTRIBUTE_UNUSED;
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
{
return 0;
}
@@ -822,9 +795,9 @@ null_cleanup (pbuf, pfile)
int
macro_cleanup (pbuf, pfile)
cpp_buffer *pbuf;
- cpp_reader *pfile;
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
{
- HASHNODE *macro = (HASHNODE*)pbuf->data;
+ HASHNODE *macro = (HASHNODE *) pbuf->data;
if (macro->type == T_DISABLED)
macro->type = T_MACRO;
if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion)
@@ -835,7 +808,7 @@ macro_cleanup (pbuf, pfile)
int
file_cleanup (pbuf, pfile)
cpp_buffer *pbuf;
- cpp_reader *pfile;
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
{
if (pbuf->buf)
{
@@ -845,52 +818,18 @@ file_cleanup (pbuf, pfile)
return 0;
}
-static void
-newline_fix (pfile)
- cpp_reader *pfile;
-{
-#if 1
- NEWLINE_FIX;
-#else
- register U_CHAR *p = bp;
-
- /* First count the backslash-newline pairs here. */
-
- while (p[0] == '\\' && p[1] == '\n')
- p += 2;
-
- /* What follows the backslash-newlines is not embarrassing. */
-
- if (*p != '/' && *p != '*')
- return;
-
- /* Copy all potentially embarrassing characters
- that follow the backslash-newline pairs
- down to where the pairs originally started. */
-
- while (*p == '*' || *p == '/')
- *bp++ = *p++;
-
- /* Now write the same number of pairs after the embarrassing chars. */
- while (bp < p) {
- *bp++ = '\\';
- *bp++ = '\n';
- }
-#endif
-}
-
/* Assuming we have read '/'.
If this is the start of a comment (followed by '*' or '/'),
skip to the end of the comment, and return ' '.
Return EOF if we reached the end of file before the end of the comment.
- If not the start of a comment, return '/'. */
+ If not the start of a comment, return '/'. */
static int
skip_comment (pfile, linep)
cpp_reader *pfile;
long *linep;
{
- int c;
+ int c = 0;
while (PEEKC() == '\\' && PEEKN(1) == '\n')
{
if (linep)
@@ -925,7 +864,7 @@ skip_comment (pfile, linep)
{
c = GETC ();
if (c == EOF)
- return ' '; /* Allow // to be terminated by EOF. */
+ return ' '; /* Allow // to be terminated by EOF. */
while (c == '\\' && PEEKC() == '\n')
{
FORWARD(1);
@@ -935,7 +874,7 @@ skip_comment (pfile, linep)
}
if (c == '\n')
{
- /* Don't consider final '\n' to be part of comment. */
+ /* Don't consider final '\n' to be part of comment. */
FORWARD(-1);
return ' ';
}
@@ -946,6 +885,7 @@ skip_comment (pfile, linep)
}
/* Skip whitespace \-newline and comments. Does not macro-expand. */
+
void
cpp_skip_hspace (pfile)
cpp_reader *pfile;
@@ -982,9 +922,9 @@ cpp_skip_hspace (pfile)
}
/* Read the rest of the current line.
- The line is appended to PFILE's output buffer. */
+ The line is appended to PFILE's output buffer. */
-void
+static void
copy_rest_of_line (pfile)
cpp_reader *pfile;
{
@@ -1009,7 +949,7 @@ copy_rest_of_line (pfile)
break;
case '/':
nextc = PEEKC();
- if (nextc == '*' || (opts->cplusplus_comments && nextc == '*'))
+ if (nextc == '*' || (opts->cplusplus_comments && nextc == '/'))
goto scan_directive_token;
break;
case '\f':
@@ -1063,11 +1003,11 @@ handle_directive (pfile)
/* Handle # followed by a line number. */
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "`#' followed by integer");
- do_line (pfile, NULL);
+ do_line (pfile, NULL, NULL, NULL);
goto done_a_directive;
}
- /* Now find the directive name. */
+ /* Now find the directive name. */
CPP_PUTC (pfile, '#');
parse_name (pfile, GETC());
ident = pfile->token_buffer + old_written + 1;
@@ -1113,11 +1053,13 @@ handle_directive (pfile)
break;
}
- if (! kt->command_reads_line)
+ if (kt->command_reads_line)
+ after_ident = 0;
+ else
{
/* Nonzero means do not delete comments within the directive.
#define needs this when -traditional. */
- int comments = CPP_TRADITIONAL (pfile) && kt->traditional_comments;
+ int comments = CPP_TRADITIONAL (pfile) && kt->type == T_DEFINE;
int save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments;
CPP_OPTIONS (pfile)->put_out_comments = comments;
after_ident = CPP_WRITTEN (pfile);
@@ -1125,37 +1067,39 @@ handle_directive (pfile)
CPP_OPTIONS (pfile)->put_out_comments = save_put_out_comments;
}
- /* For #pragma and #define, we may want to pass through the directive.
+ /* We may want to pass through #define, #pragma, and #include.
Other directives may create output, but we don't want the directive
- itself out, so we pop it now. For example #include may write a #line
- command (see comment in do_include), and conditionals may emit
+ itself out, so we pop it now. For example conditionals may emit
#failed ... #endfailed stuff. But note that popping the buffer
means the parameters to kt->func may point after pfile->limit
so these parameters are invalid as soon as something gets appended
to the token_buffer. */
line_end = CPP_PWRITTEN (pfile);
- if (!kt->pass_thru && kt->type != T_DEFINE)
+ if (! (kt->type == T_DEFINE
+ || kt->type == T_PRAGMA
+ || (IS_INCLUDE_DIRECTIVE_TYPE (kt->type)
+ && CPP_OPTIONS (pfile)->dump_includes)))
CPP_SET_WRITTEN (pfile, old_written);
(*kt->func) (pfile, kt, pfile->token_buffer + after_ident, line_end);
- if (kt->pass_thru
- || (kt->type == T_DEFINE
- && CPP_OPTIONS (pfile)->dump_macros == dump_definitions))
- {
- /* Just leave the entire #define in the output stack. */
- }
- else if (kt->type == T_DEFINE
- && CPP_OPTIONS (pfile)->dump_macros == dump_names)
+
+ if (kt->type == T_DEFINE)
{
- U_CHAR *p = pfile->token_buffer + old_written + 7; /* Skip "#define". */
- SKIP_WHITE_SPACE (p);
- while (is_idchar[*p]) p++;
- pfile->limit = p;
- CPP_PUTC (pfile, '\n');
+ if (CPP_OPTIONS (pfile)->dump_macros == dump_names)
+ {
+ /* Skip "#define". */
+ U_CHAR *p = pfile->token_buffer + old_written + 7;
+
+ SKIP_WHITE_SPACE (p);
+ while (is_idchar[*p]) p++;
+ pfile->limit = p;
+ CPP_PUTC (pfile, '\n');
+ }
+ else if (CPP_OPTIONS (pfile)->dump_macros != dump_definitions)
+ CPP_SET_WRITTEN (pfile, old_written);
}
- else if (kt->type == T_DEFINE)
- CPP_SET_WRITTEN (pfile, old_written);
+
done_a_directive:
return 1;
@@ -1199,7 +1143,7 @@ pass_thru_directive (buf, limit, pfile, keyword)
appeared. So the arglist is just convenience data passed
between these two routines. It is not kept around after
the current #define has been processed and entered into the
- hash table. */
+ hash table. */
struct arglist {
struct arglist *next;
@@ -1241,7 +1185,7 @@ collect_expansion (pfile, buf, limit, nargs, arglist)
/* Scan thru the replacement list, ignoring comments and quoted
strings, picking up on the macro calls. It does a linear search
thru the arg list on every potential symbol. Profiling might say
- that something smarter should happen. */
+ that something smarter should happen. */
if (limit < buf)
abort ();
@@ -1257,7 +1201,7 @@ collect_expansion (pfile, buf, limit, nargs, arglist)
leading and trailing newline-marker and final null. */
maxsize = (sizeof (DEFINITION)
+ (limit - p) + 5);
- /* Occurrences of '@' get doubled, so allocate extra space for them. */
+ /* Occurrences of '@' get doubled, so allocate extra space for them. */
while (p < limit)
if (*p++ == '@')
maxsize++;
@@ -1270,7 +1214,7 @@ collect_expansion (pfile, buf, limit, nargs, arglist)
p = buf;
/* Add one initial space escape-marker to prevent accidental
- token-pasting (often removed by macroexpand). */
+ token-pasting (often removed by macroexpand). */
*exp_p++ = '@';
*exp_p++ = ' ';
@@ -1307,7 +1251,7 @@ collect_expansion (pfile, buf, limit, nargs, arglist)
case '@':
/* An '@' in a string or character constant stands for itself,
- and does not need to be escaped. */
+ and does not need to be escaped. */
if (!expected_delimiter)
*exp_p++ = c;
break;
@@ -1334,7 +1278,8 @@ collect_expansion (pfile, buf, limit, nargs, arglist)
Don't leave the # in the expansion. */
exp_p--;
SKIP_WHITE_SPACE (p);
- if (p == limit || ! is_idstart[*p])
+ if (p == limit || ! is_idstart[*p]
+ || (*p == 'L' && p + 1 < limit && (p[1] == '\'' || p[1] == '"')))
cpp_error (pfile,
"`#' operator is not followed by a macro argument name");
else
@@ -1344,7 +1289,7 @@ collect_expansion (pfile, buf, limit, nargs, arglist)
}
} else {
/* In -traditional mode, recognize arguments inside strings and
- and character constants, and ignore special properties of #.
+ character constants, and ignore special properties of #.
Arguments inside strings are considered "stringified", but no
extra quote marks are supplied. */
switch (c) {
@@ -1395,7 +1340,8 @@ collect_expansion (pfile, buf, limit, nargs, arglist)
while (p != limit && is_idchar[*p]) p++;
id_len = p - id_beg;
- if (is_idstart[c]) {
+ if (is_idstart[c]
+ && ! (id_len == 1 && c == 'L' && (*p == '\'' || *p == '"'))) {
register struct arglist *arg;
for (arg = arglist; arg != NULL; arg = arg->next) {
@@ -1504,7 +1450,8 @@ static char rest_extension[] = "...";
#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1)
/* Create a DEFINITION node from a #define directive. Arguments are
- as for do_define. */
+ as for do_define. */
+
static MACRODEF
create_definition (buf, limit, pfile, predefinition)
U_CHAR *buf, *limit;
@@ -1535,7 +1482,7 @@ create_definition (buf, limit, pfile, predefinition)
/* Lossage will occur if identifiers or control keywords are broken
across lines using backslash. This is not the right place to take
- care of that. */
+ care of that. */
if (*bp == '(') {
struct arglist *arg_ptrs = NULL;
@@ -1565,8 +1512,8 @@ create_definition (buf, limit, pfile, predefinition)
while (is_idchar[*bp]) {
bp++;
/* do we have a "special" rest-args extension here? */
- if (limit - bp > REST_EXTENSION_LENGTH &&
- strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) {
+ if (limit - bp > REST_EXTENSION_LENGTH
+ && strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0) {
rest_args = 1;
temp->rest_args = 1;
break;
@@ -1593,8 +1540,8 @@ create_definition (buf, limit, pfile, predefinition)
struct arglist *otemp;
for (otemp = temp->next; otemp != NULL; otemp = otemp->next)
- if (temp->length == otemp->length &&
- strncmp (temp->name, otemp->name, temp->length) == 0) {
+ if (temp->length == otemp->length
+ && strncmp (temp->name, otemp->name, temp->length) == 0) {
U_CHAR *name;
name = (U_CHAR *) alloca (temp->length + 1);
@@ -1609,7 +1556,7 @@ create_definition (buf, limit, pfile, predefinition)
++bp; /* skip paren */
SKIP_WHITE_SPACE (bp);
- /* now everything from bp before limit is the definition. */
+ /* now everything from bp before limit is the definition. */
defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs);
defn->rest_args = rest_args;
@@ -1656,7 +1603,7 @@ create_definition (buf, limit, pfile, predefinition)
}
}
}
- /* now everything from bp before limit is the definition. */
+ /* now everything from bp before limit is the definition. */
defn = collect_expansion (pfile, bp, limit, -1, NULL_PTR);
defn->args.argnames = (U_CHAR *) "";
}
@@ -1692,10 +1639,11 @@ check_macro_name (pfile, symname, usage)
for (p = symname; is_idchar[*p]; p++)
;
sym_length = p - symname;
- if (sym_length == 0)
+ if (sym_length == 0
+ || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
cpp_error (pfile, "invalid %s name", usage);
else if (!is_idstart[*symname]) {
- U_CHAR *msg; /* what pain... */
+ U_CHAR *msg; /* what pain... */
msg = (U_CHAR *) alloca (sym_length + 1);
bcopy (symname, msg, sym_length);
msg[sym_length] = 0;
@@ -1707,11 +1655,11 @@ check_macro_name (pfile, symname, usage)
return sym_length;
}
-/*
- * return zero if two DEFINITIONs are isomorphic
- */
+/* Return zero if two DEFINITIONs are isomorphic. */
+
static int
-compare_defs (d1, d2)
+compare_defs (pfile, d1, d2)
+ cpp_reader *pfile;
DEFINITION *d1, *d2;
{
register struct reflist *a1, *a2;
@@ -1721,7 +1669,8 @@ compare_defs (d1, d2)
if (d1->nargs != d2->nargs)
return 1;
- if (strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames))
+ if (CPP_PEDANTIC (pfile)
+ && strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames))
return 1;
for (a1 = d1->pattern, a2 = d2->pattern; a1 && a2;
a1 = a1->next, a2 = a2->next) {
@@ -1817,14 +1766,14 @@ do_define (pfile, keyword, buf, limit)
ok = 1;
/* Redefining a macro is ok if the definitions are the same. */
else if (hp->type == T_MACRO)
- ok = ! compare_defs (mdef.defn, hp->value.defn);
+ ok = ! compare_defs (pfile, mdef.defn, hp->value.defn);
/* Redefining a constant is ok with -D. */
else if (hp->type == T_CONST)
ok = ! CPP_OPTIONS (pfile)->done_initializing;
/* Print the warning if it's not ok. */
if (!ok)
{
- U_CHAR *msg; /* what pain... */
+ U_CHAR *msg; /* what pain... */
/* If we are passing through #define and #undef directives, do
that for this re-definition now. */
@@ -1869,7 +1818,7 @@ nope:
if stringified.
`use_count' is the number of times this macro arg is substituted
into the macro. If the actual use count exceeds 10,
- the value stored is 10. */
+ the value stored is 10. */
/* raw and expanded are relative to ARG_BASE */
#define ARG_BASE ((pfile)->token_buffer)
@@ -1883,26 +1832,27 @@ struct argdata {
char use_count;
};
+/* Allocate a new cpp_buffer for PFILE, and push it on the input buffer stack.
+ If BUFFER != NULL, then use the LENGTH characters in BUFFER
+ as the new input buffer.
+ Return the new buffer, or NULL on failure. */
-cpp_buffer*
+cpp_buffer *
cpp_push_buffer (pfile, buffer, length)
cpp_reader *pfile;
U_CHAR *buffer;
long length;
{
-#ifdef STATIC_BUFFERS
register cpp_buffer *buf = CPP_BUFFER (pfile);
if (buf == pfile->buffer_stack)
- fatal ("%s: macro or `#include' recursion too deep", buf->fname);
+ {
+ cpp_fatal (pfile, "%s: macro or `#include' recursion too deep",
+ buf->fname);
+ return NULL;
+ }
buf--;
bzero ((char *) buf, sizeof (cpp_buffer));
CPP_BUFFER (pfile) = buf;
-#else
- register cpp_buffer *buf = (cpp_buffer*) xmalloc (sizeof(cpp_buffer));
- bzero ((char *) buf, sizeof (cpp_buffer));
- CPP_PREV_BUFFER (buf) = CPP_BUFFER (pfile);
- CPP_BUFFER (pfile) = buf;
-#endif
buf->if_stack = pfile->if_stack;
buf->cleanup = null_cleanup;
buf->underflow = null_underflow;
@@ -1912,25 +1862,17 @@ cpp_push_buffer (pfile, buffer, length)
return buf;
}
-cpp_buffer*
+cpp_buffer *
cpp_pop_buffer (pfile)
cpp_reader *pfile;
{
cpp_buffer *buf = CPP_BUFFER (pfile);
-#ifdef STATIC_BUFFERS
(*buf->cleanup) (buf, pfile);
return ++CPP_BUFFER (pfile);
-#else
- cpp_buffer *next_buf = CPP_PREV_BUFFER (buf);
- (*buf->cleanup) (buf, pfile);
- CPP_BUFFER (pfile) = next_buf;
- free (buf);
- return next_buf;
-#endif
}
/* Scan until CPP_BUFFER (PFILE) is exhausted into PFILE->token_buffer.
- Pop the buffer when done. */
+ Pop the buffer when done. */
void
cpp_scan_buffer (pfile)
@@ -1940,7 +1882,7 @@ cpp_scan_buffer (pfile)
for (;;)
{
enum cpp_token token = cpp_get_token (pfile);
- if (token == CPP_EOF) /* Should not happen ... */
+ if (token == CPP_EOF) /* Should not happen ... */
break;
if (token == CPP_POP && CPP_BUFFER (pfile) == buffer)
{
@@ -1966,7 +1908,9 @@ cpp_expand_to_buffer (pfile, buf, length)
int length;
{
register cpp_buffer *ip;
+#if 0
cpp_buffer obuf;
+#endif
U_CHAR *limit = buf + length;
U_CHAR *buf1;
#if 0
@@ -1989,6 +1933,8 @@ cpp_expand_to_buffer (pfile, buf, length)
buf1[length] = 0;
ip = cpp_push_buffer (pfile, buf1, length);
+ if (ip == NULL)
+ return;
ip->has_escapes = 1;
#if 0
ip->lineno = obuf.lineno = 1;
@@ -2023,7 +1969,7 @@ adjust_position (buf, limit, linep, colp)
}
}
-/* Move line_base forward, updating lineno and colno. */
+/* Move line_base forward, updating lineno and colno. */
static void
update_position (pbuf)
@@ -2062,9 +2008,9 @@ cpp_buf_line_and_col (pbuf, linep, colp)
}
}
-/* Return the cpp_buffer that corresponds to a file (not a macro). */
+/* Return the cpp_buffer that corresponds to a file (not a macro). */
-cpp_buffer*
+cpp_buffer *
cpp_file_buffer (pfile)
cpp_reader *pfile;
{
@@ -2105,16 +2051,18 @@ output_line_command (pfile, conditional, file_change)
int conditional;
enum file_change_code file_change;
{
- int len;
- char *line_cmd_buf, *line_end;
long line, col;
cpp_buffer *ip = CPP_BUFFER (pfile);
- if (ip->fname == NULL || CPP_OPTIONS (pfile)->no_output) {
+ if (ip->fname == NULL)
return;
- }
update_position (ip);
+
+ if (CPP_OPTIONS (pfile)->no_line_commands
+ || CPP_OPTIONS (pfile)->no_output)
+ return;
+
line = CPP_BUFFER (pfile)->lineno;
col = CPP_BUFFER (pfile)->colno;
adjust_position (CPP_LINE_BASE (ip), ip->cur, &line, &col);
@@ -2157,7 +2105,7 @@ output_line_command (pfile, conditional, file_change)
CPP_PUTS_Q (pfile, sharp_line, sizeof(sharp_line)-1);
}
- sprintf (CPP_PWRITTEN (pfile), "%d ", line);
+ sprintf ((char *) CPP_PWRITTEN (pfile), "%ld ", line);
CPP_ADJUST_WRITTEN (pfile, strlen (CPP_PWRITTEN (pfile)));
quote_string (pfile, ip->nominal_fname);
@@ -2194,7 +2142,6 @@ macarg (pfile, rest_args)
{
int paren = 0;
enum cpp_token token;
- long arg_start = CPP_WRITTEN (pfile);
char save_put_out_comments = CPP_OPTIONS (pfile)->put_out_comments;
CPP_OPTIONS (pfile)->put_out_comments = 0;
@@ -2229,7 +2176,7 @@ macarg (pfile, rest_args)
goto found;
break;
found:
- /* Remove ',' or ')' from argument buffer. */
+ /* Remove ',' or ')' from argument buffer. */
CPP_ADJUST_WRITTEN (pfile, -1);
goto done;
default: ;
@@ -2291,7 +2238,7 @@ timestamp (pfile)
cpp_reader *pfile;
{
if (!pfile->timebuf) {
- time_t t = time ((time_t *)0);
+ time_t t = time ((time_t *) 0);
pfile->timebuf = localtime (&t);
}
return pfile->timebuf;
@@ -2312,7 +2259,7 @@ special_symbol (hp, pfile)
cpp_reader *pfile;
{
char *buf;
- int i, len;
+ int len;
int true_indepth;
cpp_buffer *ip = NULL;
struct tm *timebuf;
@@ -2329,7 +2276,7 @@ special_symbol (hp, pfile)
for (ip = CPP_BUFFER (pfile); ; ip = CPP_PREV_BUFFER (ip))
{
- if (ip == NULL)
+ if (ip == CPP_NULL_BUFFER (pfile))
{
cpp_error (pfile, "cccp error: not in any file?!");
return; /* the show must go on */
@@ -2346,7 +2293,7 @@ special_symbol (hp, pfile)
char *string;
if (hp->type == T_BASE_FILE)
{
- while (CPP_PREV_BUFFER (ip))
+ while (CPP_PREV_BUFFER (ip) != CPP_NULL_BUFFER (pfile))
ip = CPP_PREV_BUFFER (ip);
}
string = ip->nominal_fname;
@@ -2360,7 +2307,8 @@ special_symbol (hp, pfile)
case T_INCLUDE_LEVEL:
true_indepth = 0;
- for (ip = CPP_BUFFER (pfile); ip != NULL; ip = CPP_PREV_BUFFER (ip))
+ ip = CPP_BUFFER (pfile);
+ for (; ip != CPP_NULL_BUFFER (pfile); ip = CPP_PREV_BUFFER (ip))
if (ip->fname != NULL)
true_indepth++;
@@ -2400,6 +2348,12 @@ special_symbol (hp, pfile)
case T_CONST:
buf = (char *) alloca (4 * sizeof (int));
sprintf (buf, "%d", hp->value.ival);
+#ifdef STDC_0_IN_SYSTEM_HEADERS
+ if (ip->system_header_p
+ && hp->length == 8 && bcmp (hp->name, "__STDC__", 8) == 0
+ && ! cpp_lookup (pfile, (U_CHAR *) "__STRICT_ANSI__", -1, -1))
+ strcpy (buf, "0");
+#endif
#if 0
if (pcp_inside_if && pcp_outfile)
/* Output a precondition for this macro use */
@@ -2414,7 +2368,7 @@ special_symbol (hp, pfile)
adjust_position (CPP_LINE_BASE (ip), ip->cur, &line, &col);
buf = (char *) alloca (10);
- sprintf (buf, "%d", line);
+ sprintf (buf, "%ld", line);
}
break;
@@ -2443,13 +2397,15 @@ special_symbol (hp, pfile)
if (!is_idstart[*ip->cur])
goto oops;
- if (hp = cpp_lookup (pfile, ip->cur, -1, -1))
+ if (ip->cur[0] == 'L' && (ip->cur[1] == '\'' || ip->cur[1] == '"'))
+ goto oops;
+ if ((hp = cpp_lookup (pfile, ip->cur, -1, -1)))
{
#if 0
if (pcp_outfile && pcp_inside_if
&& (hp->type == T_CONST
|| (hp->type == T_MACRO && hp->value.defn->predefined)))
- /* Output a precondition for this macro use. */
+ /* Output a precondition for this macro use. */
fprintf (pcp_outfile, "#define %s\n", hp->name);
#endif
buf = " 1 ";
@@ -2494,100 +2450,77 @@ special_symbol (hp, pfile)
return;
}
+/* Write out a #define command for the special named MACRO_NAME
+ to PFILE's token_buffer. */
+
+static void
+dump_special_to_buffer (pfile, macro_name)
+ cpp_reader *pfile;
+ char *macro_name;
+{
+ static char define_directive[] = "#define ";
+ int macro_name_length = strlen (macro_name);
+ output_line_command (pfile, 0, same_file);
+ CPP_RESERVE (pfile, sizeof(define_directive) + macro_name_length);
+ CPP_PUTS_Q (pfile, define_directive, sizeof(define_directive)-1);
+ CPP_PUTS_Q (pfile, macro_name, macro_name_length);
+ CPP_PUTC_Q (pfile, ' ');
+ cpp_expand_to_buffer (pfile, macro_name, macro_name_length);
+ CPP_PUTC (pfile, '\n');
+}
+
/* Initialize the built-in macros. */
static void
initialize_builtins (pfile)
cpp_reader *pfile;
{
- install ("__LINE__", -1, T_SPECLINE, 0, 0, -1);
- install ("__DATE__", -1, T_DATE, 0, 0, -1);
- install ("__FILE__", -1, T_FILE, 0, 0, -1);
- install ("__BASE_FILE__", -1, T_BASE_FILE, 0, 0, -1);
- install ("__INCLUDE_LEVEL__", -1, T_INCLUDE_LEVEL, 0, 0, -1);
- install ("__VERSION__", -1, T_VERSION, 0, 0, -1);
+ install ((U_CHAR *)"__LINE__", -1, T_SPECLINE, 0, 0, -1);
+ install ((U_CHAR *)"__DATE__", -1, T_DATE, 0, 0, -1);
+ install ((U_CHAR *)"__FILE__", -1, T_FILE, 0, 0, -1);
+ install ((U_CHAR *)"__BASE_FILE__", -1, T_BASE_FILE, 0, 0, -1);
+ install ((U_CHAR *)"__INCLUDE_LEVEL__", -1, T_INCLUDE_LEVEL, 0, 0, -1);
+ install ((U_CHAR *)"__VERSION__", -1, T_VERSION, 0, 0, -1);
#ifndef NO_BUILTIN_SIZE_TYPE
- install ("__SIZE_TYPE__", -1, T_SIZE_TYPE, 0, 0, -1);
+ install ((U_CHAR *)"__SIZE_TYPE__", -1, T_SIZE_TYPE, 0, 0, -1);
#endif
#ifndef NO_BUILTIN_PTRDIFF_TYPE
- install ("__PTRDIFF_TYPE__ ", -1, T_PTRDIFF_TYPE, 0, 0, -1);
+ install ((U_CHAR *)"__PTRDIFF_TYPE__ ", -1, T_PTRDIFF_TYPE, 0, 0, -1);
#endif
- install ("__WCHAR_TYPE__", -1, T_WCHAR_TYPE, 0, 0, -1);
- install ("__USER_LABEL_PREFIX__", -1, T_USER_LABEL_PREFIX_TYPE, 0, 0, -1);
- install ("__REGISTER_PREFIX__", -1, T_REGISTER_PREFIX_TYPE, 0, 0, -1);
- install ("__TIME__", -1, T_TIME, 0, 0, -1);
+ install ((U_CHAR *)"__WCHAR_TYPE__", -1, T_WCHAR_TYPE, 0, 0, -1);
+ install ((U_CHAR *)"__USER_LABEL_PREFIX__", -1, T_USER_LABEL_PREFIX_TYPE, 0, 0, -1);
+ install ((U_CHAR *)"__REGISTER_PREFIX__", -1, T_REGISTER_PREFIX_TYPE, 0, 0, -1);
+ install ((U_CHAR *)"__TIME__", -1, T_TIME, 0, 0, -1);
if (!CPP_TRADITIONAL (pfile))
- install ("__STDC__", -1, T_CONST, STDC_VALUE, 0, -1);
+ install ((U_CHAR *)"__STDC__", -1, T_CONST, STDC_VALUE, 0, -1);
if (CPP_OPTIONS (pfile)->objc)
- install ("__OBJC__", -1, T_CONST, 1, 0, -1);
+ install ((U_CHAR *)"__OBJC__", -1, T_CONST, 1, 0, -1);
/* This is supplied using a -D by the compiler driver
so that it is present only when truly compiling with GNU C. */
/* install ("__GNUC__", -1, T_CONST, 2, 0, -1); */
if (CPP_OPTIONS (pfile)->debug_output)
{
- char directive[2048];
- register struct directive *dp = &directive_table[0];
- struct tm *timebuf = timestamp (pfile);
- cpp_buffer *pbuffer = CPP_BUFFER (pfile);
-
- while (CPP_PREV_BUFFER (pbuffer))
- pbuffer = CPP_PREV_BUFFER (pbuffer);
- sprintf (directive, " __BASE_FILE__ \"%s\"\n",
- pbuffer->nominal_fname);
- output_line_command (pfile, 0, same_file);
- pass_thru_directive (directive, &directive[strlen (directive)], pfile, dp);
-
- sprintf (directive, " __VERSION__ \"%s\"\n", version_string);
- output_line_command (pfile, 0, same_file);
- pass_thru_directive (directive, &directive[strlen (directive)], pfile, dp);
-
+ dump_special_to_buffer (pfile, "__BASE_FILE__");
+ dump_special_to_buffer (pfile, "__VERSION__");
#ifndef NO_BUILTIN_SIZE_TYPE
- sprintf (directive, " __SIZE_TYPE__ %s\n", SIZE_TYPE);
- output_line_command (pfile, 0, same_file);
- pass_thru_directive (directive, &directive[strlen (directive)], pfile, dp);
+ dump_special_to_buffer (pfile, "__SIZE_TYPE__");
#endif
-
#ifndef NO_BUILTIN_PTRDIFF_TYPE
- sprintf (directive, " __PTRDIFF_TYPE__ %s\n", PTRDIFF_TYPE);
- output_line_command (pfile, 0, same_file);
- pass_thru_directive (directive, &directive[strlen (directive)], pfile, dp);
+ dump_special_to_buffer (pfile, "__PTRDIFF_TYPE__");
#endif
-
- sprintf (directive, " __WCHAR_TYPE__ %s\n", CPP_WCHAR_TYPE (pfile));
- output_line_command (pfile, 0, same_file);
- pass_thru_directive (directive, &directive[strlen (directive)], pfile, dp);
-
- sprintf (directive, " __DATE__ \"%s %2d %4d\"\n",
- monthnames[timebuf->tm_mon],
- timebuf->tm_mday, timebuf->tm_year + 1900);
- output_line_command (pfile, 0, same_file);
- pass_thru_directive (directive, &directive[strlen (directive)], pfile, dp);
-
- sprintf (directive, " __TIME__ \"%02d:%02d:%02d\"\n",
- timebuf->tm_hour, timebuf->tm_min, timebuf->tm_sec);
- output_line_command (pfile, 0, same_file);
- pass_thru_directive (directive, &directive[strlen (directive)], pfile, dp);
-
+ dump_special_to_buffer (pfile, "__WCHAR_TYPE__");
+ dump_special_to_buffer (pfile, "__DATE__");
+ dump_special_to_buffer (pfile, "__TIME__");
if (!CPP_TRADITIONAL (pfile))
- {
- sprintf (directive, " __STDC__ 1");
- output_line_command (pfile, 0, same_file);
- pass_thru_directive (directive, &directive[strlen (directive)],
- pfile, dp);
- }
+ dump_special_to_buffer (pfile, "__STDC__");
if (CPP_OPTIONS (pfile)->objc)
- {
- sprintf (directive, " __OBJC__ 1");
- output_line_command (pfile, 0, same_file);
- pass_thru_directive (directive, &directive[strlen (directive)],
- pfile, dp);
- }
+ dump_special_to_buffer (pfile, "__OBJC__");
}
}
/* Return 1 iff a token ending in C1 followed directly by a token C2
- could cause mis-tokenization. */
+ could cause mis-tokenization. */
static int
unsafe_chars (c1, c2)
@@ -2602,27 +2535,27 @@ unsafe_chars (c1, c2)
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
- case 'e': case 'E':
+ case 'e': case 'E': case 'p': case 'P':
if (c2 == '-' || c2 == '+')
return 1; /* could extend a pre-processing number */
goto letter;
case 'L':
if (c2 == '\'' || c2 == '\"')
- return 1; /* Could turn into L"xxx" or L'xxx'. */
+ return 1; /* Could turn into L"xxx" or L'xxx'. */
goto letter;
letter:
case '_':
case 'a': case 'b': case 'c': case 'd': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+ case 'm': case 'n': case 'o': case 'q': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K':
- case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+ case 'M': case 'N': case 'O': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
- /* We're in the middle of either a name or a pre-processing number. */
+ /* We're in the middle of either a name or a pre-processing number. */
return (is_idchar[c2] || c2 == '.');
case '<': case '>': case '!': case '%': case '#': case ':':
case '^': case '&': case '|': case '*': case '/': case '=':
@@ -2690,7 +2623,7 @@ macroexpand (pfile, hp)
/* Parse all the macro args that are supplied. I counts them.
The first NARGS args are stored in ARGS.
The rest are discarded. If rest_args is set then we assume
- macarg absorbed the rest of the args. */
+ macarg absorbed the rest of the args. */
i = 0;
rest_args = 0;
rest_args = 0;
@@ -2789,7 +2722,7 @@ macroexpand (pfile, hp)
if (ap->stringify)
{
register struct argdata *arg = &args[ap->argno];
- /* Stringify it it hasn't already been */
+ /* Stringify if it hasn't already been */
if (arg->stringified_length < 0)
{
int arglen = arg->raw_length;
@@ -2798,7 +2731,7 @@ macroexpand (pfile, hp)
int c;
/* Initially need_space is -1. Otherwise, 1 means the
previous character was a space, but we suppressed it;
- 0 means the previous character was a non-space. */
+ 0 means the previous character was a non-space. */
int need_space = -1;
i = 0;
arg->stringified = CPP_WRITTEN (pfile);
@@ -2848,12 +2781,12 @@ macroexpand (pfile, hp)
/* Escape these chars */
if (c == '\"' || (in_string && c == '\\'))
CPP_PUTC (pfile, '\\');
- if (isprint (c))
+ if (ISPRINT (c))
CPP_PUTC (pfile, c);
else
{
CPP_RESERVE (pfile, 4);
- sprintf (CPP_PWRITTEN (pfile), "\\%03o",
+ sprintf ((char *)CPP_PWRITTEN (pfile), "\\%03o",
(unsigned int) c);
CPP_ADJUST_WRITTEN (pfile, 4);
}
@@ -2941,6 +2874,11 @@ macroexpand (pfile, hp)
while (p1 != l1 && is_space[*p1]) p1++;
while (p1 != l1 && is_idchar[*p1])
xbuf[totlen++] = *p1++;
+ /* Delete any no-reexpansion marker that follows
+ an identifier at the beginning of the argument
+ if the argument is concatenated with what precedes it. */
+ if (p1[0] == '@' && p1[1] == '-')
+ p1 += 2;
}
if (ap->raw_after)
{
@@ -3008,7 +2946,7 @@ macroexpand (pfile, hp)
}
/* if there is anything left of the definition
- after handling the arg list, copy that in too. */
+ after handling the arg list, copy that in too. */
for (i = offset; i < defn->length; i++)
{
@@ -3032,7 +2970,7 @@ macroexpand (pfile, hp)
push_macro_expansion (pfile, xbuf, xbuf_len, hp);
CPP_BUFFER (pfile)->has_escapes = 1;
- /* Pop the space we've used in the token_buffer for argument expansion. */
+ /* Pop the space we've used in the token_buffer for argument expansion. */
CPP_SET_WRITTEN (pfile, old_written);
/* Recursive macro use sometimes works traditionally.
@@ -3051,6 +2989,8 @@ push_macro_expansion (pfile, xbuf, xbuf_len, hp)
HASHNODE *hp;
{
register cpp_buffer *mbuf = cpp_push_buffer (pfile, xbuf, xbuf_len);
+ if (mbuf == NULL)
+ return;
mbuf->cleanup = macro_cleanup;
mbuf->data = hp;
@@ -3098,7 +3038,7 @@ get_directive_token (pfile)
case CPP_POP:
if (! CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
return token;
- /* ... else fall though ... */
+ /* ... else fall though ... */
case CPP_HSPACE: case CPP_COMMENT:
CPP_SET_WRITTEN (pfile, old_written);
break;
@@ -3114,19 +3054,18 @@ get_directive_token (pfile)
The input is normally in part of the output_buffer following
CPP_WRITTEN, and will get overwritten by output_line_command.
I.e. in input file specification has been popped by handle_directive.
- This is safe. */
+ This is safe. */
static int
do_include (pfile, keyword, unused1, unused2)
cpp_reader *pfile;
struct directive *keyword;
- U_CHAR *unused1, *unused2;
+ U_CHAR *unused1 ATTRIBUTE_UNUSED, *unused2 ATTRIBUTE_UNUSED;
{
int importing = (keyword->type == T_IMPORT);
int skip_dirs = (keyword->type == T_INCLUDE_NEXT);
char *fname; /* Dynamically allocated fname buffer */
char *pcftry;
- char *pcfname;
U_CHAR *fbeg, *fend; /* Beginning and end of fname */
enum cpp_token token;
@@ -3140,15 +3079,23 @@ do_include (pfile, keyword, unused1, unused2)
int f; /* file number */
- int retried = 0; /* Have already tried macro
- expanding the include line*/
int angle_brackets = 0; /* 0 for "...", 1 for <...> */
- int pcf = -1;
char *pcfbuf;
+#if 0
+ int pcf = -1;
char *pcfbuflimit;
+#endif
int pcfnum;
f= -1; /* JF we iz paranoid! */
+ if (CPP_PEDANTIC (pfile) && !CPP_BUFFER (pfile)->system_header_p)
+ {
+ if (importing)
+ cpp_pedwarn (pfile, "ANSI C does not allow `#import'");
+ if (skip_dirs)
+ cpp_pedwarn (pfile, "ANSI C does not allow `#include_next'");
+ }
+
if (importing && CPP_OPTIONS (pfile)->warn_import
&& !CPP_OPTIONS (pfile)->inhibit_warnings
&& !CPP_BUFFER (pfile)->system_header_p && !pfile->import_warning)
@@ -3183,14 +3130,14 @@ do_include (pfile, keyword, unused1, unused2)
if (CPP_OPTIONS (pfile)->first_bracket_include)
search_start = CPP_OPTIONS (pfile)->first_bracket_include;
}
- /* If -I- was specified, don't search current dir, only spec'd ones. */
+ /* If -I- was specified, don't search current dir, only spec'd ones. */
else if (! CPP_OPTIONS (pfile)->ignore_srcdir)
{
- cpp_buffer *fp;
+ cpp_buffer *fp = CPP_BUFFER (pfile);
/* We have "filename". Figure out directory this source
- file is coming from and put it on the front of the list. */
+ file is coming from and put it on the front of the list. */
- for (fp = CPP_BUFFER (pfile); fp != NULL; fp = CPP_PREV_BUFFER (fp))
+ for ( ; fp != CPP_NULL_BUFFER (pfile); fp = CPP_PREV_BUFFER (fp))
{
int n;
char *ep,*nam;
@@ -3269,8 +3216,8 @@ do_include (pfile, keyword, unused1, unused2)
past the dir in which the containing file was found. */
if (skip_dirs)
{
- cpp_buffer *fp;
- for (fp = CPP_BUFFER (pfile); fp != NULL; fp = CPP_PREV_BUFFER (fp))
+ cpp_buffer *fp = CPP_BUFFER (pfile);
+ for (; fp != CPP_NULL_BUFFER (pfile); fp = CPP_PREV_BUFFER (fp))
if (fp->fname != NULL)
{
/* fp->dir is null if the containing file was specified with
@@ -3429,18 +3376,18 @@ do_include (pfile, keyword, unused1, unused2)
/* Check to see if this include file is a once-only include file.
If so, give up. */
- struct file_name_list* ptr;
+ struct file_name_list *ptr;
for (ptr = pfile->dont_repeat_files; ptr; ptr = ptr->next) {
if (!strcmp (ptr->fname, fname)) {
close (f);
- return 0; /* This file was once'd. */
+ return 0; /* This file was once'd. */
}
}
for (ptr = pfile->all_include_files; ptr; ptr = ptr->next) {
if (!strcmp (ptr->fname, fname))
- break; /* This file was included before. */
+ break; /* This file was included before. */
}
if (ptr == 0) {
@@ -3465,7 +3412,7 @@ do_include (pfile, keyword, unused1, unused2)
if (CPP_OPTIONS(pfile)->print_include_names)
{
cpp_buffer *buf = CPP_BUFFER (pfile);
- while ((buf = CPP_PREV_BUFFER (buf)) != NULL)
+ while ((buf = CPP_PREV_BUFFER (buf)) != CPP_NULL_BUFFER (pfile))
putc ('.', stderr);
fprintf (stderr, "%s\n", fname);
}
@@ -3475,7 +3422,7 @@ do_include (pfile, keyword, unused1, unused2)
/* Actually process the file. */
- /* Record file on "seen" list for #import. */
+ /* Record file on "seen" list for #import. */
add_import (pfile, f, fname);
pcftry = (char *) alloca (strlen (fname) + 30);
@@ -3518,7 +3465,8 @@ do_include (pfile, keyword, unused1, unused2)
#endif
/* Actually process the file */
- cpp_push_buffer (pfile, NULL, 0);
+ if (cpp_push_buffer (pfile, NULL, 0) == NULL)
+ return 0;
if (finclude (pfile, f, fname, is_system_include (pfile, fname),
searchptr != dsp ? searchptr : SELF_DIR_DUMMY))
{
@@ -3595,6 +3543,7 @@ is_system_include (pfile, filename)
* If HASH is >= 0, it is the precomputed hash code.
* Otherwise, compute the hash code.
*/
+
static ASSERTION_HASHNODE *
assertion_install (pfile, name, len, hash)
cpp_reader *pfile;
@@ -3626,7 +3575,7 @@ assertion_install (pfile, name, len, hash)
return hp;
}
/*
- * find the most recent hash node for name name (ending with first
+ * find the most recent hash node for name "name" (ending with first
* non-identifier char) installed by install
*
* If LEN is >= 0, it is the length of the name.
@@ -3672,8 +3621,8 @@ delete_assertion (hp)
tail = next;
}
- /* make sure that the bucket chain header that
- the deleted guy was on points to the right thing afterwards. */
+ /* Make sure that the bucket chain header that
+ the deleted guy was on points to the right thing afterwards. */
if (hp == *hp->bucket_hdr)
*hp->bucket_hdr = hp->next;
@@ -3686,7 +3635,7 @@ delete_assertion (hp)
The value returned in the end of the string written to RESULT,
or NULL on error. */
-static U_CHAR*
+static U_CHAR *
convert_string (pfile, result, in, limit, handle_escapes)
cpp_reader *pfile;
register U_CHAR *result, *in, *limit;
@@ -3732,21 +3681,21 @@ convert_string (pfile, result, in, limit, handle_escapes)
#define FNAME_HASHSIZE 37
static int
-do_line (pfile, keyword)
+do_line (pfile, keyword, unused1, unused2)
cpp_reader *pfile;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+ U_CHAR *unused1 ATTRIBUTE_UNUSED, *unused2 ATTRIBUTE_UNUSED;
{
cpp_buffer *ip = CPP_BUFFER (pfile);
int new_lineno;
long old_written = CPP_WRITTEN (pfile);
enum file_change_code file_change = same_file;
enum cpp_token token;
- int i;
token = get_directive_token (pfile);
if (token != CPP_NUMBER
- || !isdigit(pfile->token_buffer[old_written]))
+ || !ISDIGIT(pfile->token_buffer[old_written]))
{
cpp_error (pfile, "invalid format `#line' command");
goto bad_line_directive;
@@ -3755,7 +3704,7 @@ do_line (pfile, keyword)
/* The Newline at the end of this line remains to be processed.
To put the next line at the specified line number,
we must store a line number now that is one less. */
- new_lineno = atoi (pfile->token_buffer + old_written) - 1;
+ new_lineno = atoi ((char *)(pfile->token_buffer + old_written)) - 1;
CPP_SET_WRITTEN (pfile, old_written);
/* NEW_LINENO is one less than the actual line number here. */
@@ -3805,18 +3754,18 @@ do_line (pfile, keyword)
}
if (*p == '1')
file_change = enter_file;
- else if (*p == 2)
+ else if (*p == '2')
file_change = leave_file;
- else if (*p == 3)
+ else if (*p == '3')
ip->system_header_p = 1;
- else /* if (*p == 4) */
+ else /* if (*p == '4') */
ip->system_header_p = 2;
CPP_SET_WRITTEN (pfile, num_start);
token = get_directive_token (pfile);
p = pfile->token_buffer + num_start;
if (token == CPP_NUMBER && p[1] == '\0' && (*p == '3' || *p== '4')) {
- ip->system_header_p = *p == 3 ? 1 : 2;
+ ip->system_header_p = *p == '3' ? 1 : 2;
token = get_directive_token (pfile);
}
if (token != CPP_VSPACE) {
@@ -3825,11 +3774,10 @@ do_line (pfile, keyword)
}
}
- hash_bucket =
- &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)];
+ hash_bucket = &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)];
for (hp = *hash_bucket; hp != NULL; hp = hp->next)
- if (hp->length == fname_length &&
- strncmp (hp->value.cpval, fname, fname_length) == 0) {
+ if (hp->length == fname_length
+ && strncmp (hp->value.cpval, fname, fname_length) == 0) {
ip->nominal_fname = hp->value.cpval;
break;
}
@@ -3911,11 +3859,11 @@ do_undef (pfile, keyword, buf, limit)
static int
do_error (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
U_CHAR *buf, *limit;
{
int length = limit - buf;
- U_CHAR *copy = (U_CHAR *) xmalloc (length + 1);
+ U_CHAR *copy = (U_CHAR *) alloca (length + 1);
bcopy (buf, copy, length);
copy[length] = 0;
SKIP_WHITE_SPACE (copy);
@@ -3932,15 +3880,21 @@ do_error (pfile, keyword, buf, limit)
static int
do_warning (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
U_CHAR *buf, *limit;
{
int length = limit - buf;
- U_CHAR *copy = (U_CHAR *) xmalloc (length + 1);
+ U_CHAR *copy = (U_CHAR *) alloca (length + 1);
bcopy (buf, copy, length);
copy[length] = 0;
SKIP_WHITE_SPACE (copy);
- cpp_warning (pfile, "#warning %s", copy);
+
+ if (CPP_PEDANTIC (pfile) && !CPP_BUFFER (pfile)->system_header_p)
+ cpp_pedwarn (pfile, "ANSI C does not allow `#warning'");
+
+ /* Use `pedwarn' not `warning', because #warning isn't in the C Standard;
+ if -pedantic-errors is given, #warning should cause an error. */
+ cpp_pedwarn (pfile, "#warning %s", copy);
return 0;
}
@@ -3948,15 +3902,17 @@ do_warning (pfile, keyword, buf, limit)
avoid ever including it again. */
static int
-do_once (pfile)
+do_once (pfile, keyword, unused1, unused2)
cpp_reader *pfile;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+ U_CHAR *unused1 ATTRIBUTE_UNUSED, *unused2 ATTRIBUTE_UNUSED;
{
cpp_buffer *ip = NULL;
struct file_name_list *new;
for (ip = CPP_BUFFER (pfile); ; ip = CPP_PREV_BUFFER (ip))
{
- if (ip == NULL)
+ if (ip == CPP_NULL_BUFFER (pfile))
return 0;
if (ip->fname != NULL)
break;
@@ -3974,22 +3930,21 @@ do_once (pfile)
return 0;
}
-/* #ident has already been copied to the output file, so just ignore it. */
+/* Report program identification. */
static int
do_ident (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
- U_CHAR *buf, *limit;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+ U_CHAR *buf ATTRIBUTE_UNUSED, *limit ATTRIBUTE_UNUSED;
{
/* long old_written = CPP_WRITTEN (pfile);*/
- int len;
/* Allow #ident in system headers, since that's not user's fault. */
if (CPP_PEDANTIC (pfile) && !CPP_BUFFER (pfile)->system_header_p)
cpp_pedwarn (pfile, "ANSI C does not allow `#ident'");
- /* Leave rest of line to be read by later calls to cpp_get_token. */
+ /* Leave rest of line to be read by later calls to cpp_get_token. */
return 0;
}
@@ -4000,8 +3955,8 @@ do_ident (pfile, keyword, buf, limit)
static int
do_pragma (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
- U_CHAR *buf, *limit;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+ U_CHAR *buf, *limit ATTRIBUTE_UNUSED;
{
while (*buf == ' ' || *buf == '\t')
buf++;
@@ -4010,7 +3965,7 @@ do_pragma (pfile, keyword, buf, limit)
fault. */
if (!CPP_BUFFER (pfile)->system_header_p)
cpp_warning (pfile, "`#pragma once' is obsolete");
- do_once (pfile);
+ do_once (pfile, NULL, NULL, NULL);
}
if (!strncmp (buf, "implementation", 14)) {
@@ -4067,18 +4022,20 @@ nope:
}
#endif
+#ifdef SCCS_DIRECTIVE
/* Just ignore #sccs, on systems where we define it at all. */
static int
do_sccs (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
- U_CHAR *buf, *limit;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+ U_CHAR *buf ATTRIBUTE_UNUSED, *limit ATTRIBUTE_UNUSED;
{
if (CPP_PEDANTIC (pfile))
cpp_pedwarn (pfile, "ANSI C does not allow `#sccs'");
return 0;
}
+#endif
/*
* handle #if command by
@@ -4096,7 +4053,7 @@ do_sccs (pfile, keyword, buf, limit)
static int
do_if (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
U_CHAR *buf, *limit;
{
HOST_WIDE_INT value = eval_if_expression (pfile, buf, limit - buf);
@@ -4112,7 +4069,7 @@ do_if (pfile, keyword, buf, limit)
static int
do_elif (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
+ struct directive *keyword ATTRIBUTE_UNUSED;
U_CHAR *buf, *limit;
{
if (pfile->if_stack == CPP_BUFFER (pfile)->if_stack) {
@@ -4151,17 +4108,18 @@ do_elif (pfile, keyword, buf, limit)
* evaluate a #if expression in BUF, of length LENGTH,
* then parse the result as a C expression and return the value as an int.
*/
+
static HOST_WIDE_INT
eval_if_expression (pfile, buf, length)
cpp_reader *pfile;
- U_CHAR *buf;
- int length;
+ U_CHAR *buf ATTRIBUTE_UNUSED;
+ int length ATTRIBUTE_UNUSED;
{
HASHNODE *save_defined;
HOST_WIDE_INT value;
long old_written = CPP_WRITTEN (pfile);
- save_defined = install ("defined", -1, T_SPEC_DEFINED, 0, 0, -1);
+ save_defined = install ((U_CHAR *)"defined", -1, T_SPEC_DEFINED, 0, 0, -1);
pfile->pcp_inside_if = 1;
value = cpp_parse_expr (pfile);
@@ -4183,11 +4141,11 @@ static int
do_xifdef (pfile, keyword, unused1, unused2)
cpp_reader *pfile;
struct directive *keyword;
- U_CHAR *unused1, *unused2;
+ U_CHAR *unused1 ATTRIBUTE_UNUSED, *unused2 ATTRIBUTE_UNUSED;
{
int skip;
cpp_buffer *ip = CPP_BUFFER (pfile);
- U_CHAR* ident;
+ U_CHAR *ident;
int ident_length;
enum cpp_token token;
int start_of_file = 0;
@@ -4295,20 +4253,20 @@ conditional_skip (pfile, skip, type, control_macro)
* leaves input ptr at the sharp sign found.
* If ANY is nonzero, return at next directive of any sort.
*/
+
static void
skip_if_group (pfile, any)
cpp_reader *pfile;
int any;
{
int c;
- int at_beg_of_line = 1;
struct directive *kt;
IF_STACK_FRAME *save_if_stack = pfile->if_stack; /* don't pop past here */
#if 0
U_CHAR *beg_of_line = bp;
#endif
register int ident_length;
- U_CHAR *ident, *after_ident;
+ U_CHAR *ident;
struct parse_marker line_start_mark;
parse_set_mark (&line_start_mark, pfile);
@@ -4412,7 +4370,7 @@ skip_if_group (pfile, any)
}
c = GETC ();
}
- /* We're in the middle of a line. Skip the rest of it. */
+ /* We're in the middle of a line. Skip the rest of it. */
for (;;) {
switch (c)
{
@@ -4463,8 +4421,8 @@ skip_if_group (pfile, any)
static int
do_else (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
- U_CHAR *buf, *limit;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+ U_CHAR *buf ATTRIBUTE_UNUSED, *limit ATTRIBUTE_UNUSED;
{
cpp_buffer *ip = CPP_BUFFER (pfile);
@@ -4506,8 +4464,8 @@ do_else (pfile, keyword, buf, limit)
static int
do_endif (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
- U_CHAR *buf, *limit;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+ U_CHAR *buf ATTRIBUTE_UNUSED, *limit ATTRIBUTE_UNUSED;
{
if (CPP_PEDANTIC (pfile))
validate_else (pfile, "#endif");
@@ -4591,9 +4549,8 @@ validate_else (pfile, directive)
}
/* Get the next token, and add it to the text in pfile->token_buffer.
- Return the kind of token we got. */
+ Return the kind of token we got. */
-
enum cpp_token
cpp_get_token (pfile)
cpp_reader *pfile;
@@ -4621,11 +4578,12 @@ cpp_get_token (pfile)
cpp_buffer *next_buf
= CPP_PREV_BUFFER (CPP_BUFFER (pfile));
CPP_BUFFER (pfile)->seen_eof = 1;
- if (CPP_BUFFER (pfile)->nominal_fname && next_buf != 0)
+ if (CPP_BUFFER (pfile)->nominal_fname
+ && next_buf != CPP_NULL_BUFFER (pfile))
{
/* We're about to return from an #include file.
Emit #line information now (as part of the CPP_POP) result.
- But the #line refers to the file we will pop to. */
+ But the #line refers to the file we will pop to. */
cpp_buffer *cur_buffer = CPP_BUFFER (pfile);
CPP_BUFFER (pfile) = next_buf;
pfile->input_stack_listing_current = 0;
@@ -4660,14 +4618,13 @@ cpp_get_token (pfile)
"unterminated comment");
goto handle_eof;
}
- c = '/'; /* Initial letter of comment. */
+ c = '/'; /* Initial letter of comment. */
return_comment:
/* Comments are equivalent to spaces.
For -traditional, a comment is equivalent to nothing. */
if (opts->put_out_comments)
{
cpp_buffer *pbuf = CPP_BUFFER (pfile);
- long dummy;
U_CHAR *start = pbuf->buf + start_mark.position;
int len = pbuf->cur - start;
CPP_RESERVE(pfile, 1 + len);
@@ -4685,7 +4642,7 @@ cpp_get_token (pfile)
{
#if 0
/* This may not work if cpp_get_token is called recursively,
- since many places look for horizontal space. */
+ since many places look for horizontal space. */
if (newlines)
{
/* Copy the newlines into the output buffer, in order to
@@ -4725,8 +4682,8 @@ cpp_get_token (pfile)
}
/* OK, now bring us back to the state we were in before we entered
- this branch. We need #line b/c the newline for the pragma
- could fuck things up. */
+ this branch. We need #line because the newline for the pragma
+ could mess things up. */
output_line_command (pfile, 0, same_file);
*(obp++) = ' '; /* just in case, if comments are copied thru */
*(obp++) = '/';
@@ -4824,7 +4781,7 @@ cpp_get_token (pfile)
cc = GETC();
if (cc == '\n')
{
- /* Backslash newline is replaced by nothing at all. */
+ /* Backslash newline is replaced by nothing at all. */
CPP_ADJUST_WRITTEN (pfile, -1);
pfile->lineno++;
}
@@ -4888,7 +4845,7 @@ cpp_get_token (pfile)
/* Chill style comment */
if (opts->put_out_comments)
parse_set_mark (&start_mark, pfile);
- FORWARD(1); /* Skip second '-'. */
+ FORWARD(1); /* Skip second '-'. */
for (;;)
{
c = GETC ();
@@ -4896,7 +4853,7 @@ cpp_get_token (pfile)
break;
if (c == '\n')
{
- /* Don't consider final '\n' to be part of comment. */
+ /* Don't consider final '\n' to be part of comment. */
FORWARD(-1);
break;
}
@@ -4977,7 +4934,7 @@ cpp_get_token (pfile)
case '.':
NEWLINE_FIX;
c2 = PEEKC ();
- if (isdigit(c2))
+ if (ISDIGIT(c2))
{
CPP_RESERVE(pfile, 2);
CPP_PUTC_Q (pfile, '.');
@@ -5032,7 +4989,9 @@ cpp_get_token (pfile)
if (c == EOF)
break;
if (!is_idchar[c] && c != '.'
- && ((c2 != 'e' && c2 != 'E') || (c != '+' && c != '-')))
+ && ((c2 != 'e' && c2 != 'E'
+ && ((c2 != 'p' && c2 != 'P') || CPP_C89 (pfile)))
+ || (c != '+' && c != '-')))
break;
FORWARD(1);
c2= c;
@@ -5109,7 +5068,7 @@ cpp_get_token (pfile)
if (hp->type == T_DISABLED)
{
if (pfile->output_escapes)
- { /* Return "@-IDENT", followed by '\0'. */
+ { /* Return "@-IDENT", followed by '\0'. */
int i;
CPP_RESERVE (pfile, 3);
ident = pfile->token_buffer + before_name_written;
@@ -5155,7 +5114,7 @@ cpp_get_token (pfile)
if (!is_macro_call)
return CPP_NAME;
}
- /* This is now known to be a macro call. */
+ /* This is now known to be a macro call. */
/* it might not actually be a macro. */
if (hp->type != T_MACRO) {
@@ -5179,7 +5138,7 @@ cpp_get_token (pfile)
/* An extra "@ " is added to the end of a macro expansion
to prevent accidental token pasting. We prefer to avoid
unneeded extra spaces (for the sake of cpp-using tools like
- imake). Here we remove the space if it is safe to do so. */
+ imake). Here we remove the space if it is safe to do so. */
if (pfile->buffer->rlimit - pfile->buffer->cur >= 3
&& pfile->buffer->rlimit[-2] == '@'
&& pfile->buffer->rlimit[-1] == ' ')
@@ -5236,7 +5195,8 @@ cpp_get_token (pfile)
}
}
-/* Like cpp_get_token, but skip spaces and comments. */
+/* Like cpp_get_token, but skip spaces and comments. */
+
enum cpp_token
cpp_get_non_space_token (pfile)
cpp_reader *pfile;
@@ -5252,9 +5212,9 @@ cpp_get_non_space_token (pfile)
}
}
-/* Parse an identifier starting with C. */
+/* Parse an identifier starting with C. */
-int
+static int
parse_name (pfile, c)
cpp_reader *pfile; int c;
{
@@ -5271,7 +5231,10 @@ parse_name (pfile, c)
break;
}
- CPP_RESERVE(pfile, 2); /* One more for final NUL. */
+ if (c == '$' && CPP_PEDANTIC (pfile))
+ cpp_pedwarn (pfile, "`$' in identifier");
+
+ CPP_RESERVE(pfile, 2); /* One more for final NUL. */
CPP_PUTC_Q (pfile, c);
c = GETC();
if (c == EOF)
@@ -5416,7 +5379,8 @@ read_filename_string (ch, f)
return alloc;
}
-/* This structure holds a linked list of file name maps, one per directory. */
+/* This structure holds a linked list of file name maps, one per directory. */
+
struct file_name_map_list
{
struct file_name_map_list *map_list_next;
@@ -5513,65 +5477,68 @@ open_include_file (pfile, filename, searchptr)
char *filename;
struct file_name_list *searchptr;
{
- register struct file_name_map *map;
- register char *from;
- char *p, *dir;
-
- if (searchptr && ! searchptr->got_name_map)
+ if (CPP_OPTIONS (pfile)->remap)
{
- searchptr->name_map = read_name_map (pfile,
- searchptr->fname
- ? searchptr->fname : ".");
- searchptr->got_name_map = 1;
- }
+ register struct file_name_map *map;
+ register char *from;
+ char *p, *dir;
- /* First check the mapping for the directory we are using. */
- if (searchptr && searchptr->name_map)
- {
- from = filename;
- if (searchptr->fname)
- from += strlen (searchptr->fname) + 1;
- for (map = searchptr->name_map; map; map = map->map_next)
+ if (searchptr && ! searchptr->got_name_map)
+ {
+ searchptr->name_map = read_name_map (pfile,
+ searchptr->fname
+ ? searchptr->fname : ".");
+ searchptr->got_name_map = 1;
+ }
+
+ /* First check the mapping for the directory we are using. */
+ if (searchptr && searchptr->name_map)
{
- if (! strcmp (map->map_from, from))
+ from = filename;
+ if (searchptr->fname)
+ from += strlen (searchptr->fname) + 1;
+ for (map = searchptr->name_map; map; map = map->map_next)
{
- /* Found a match. */
- return open (map->map_to, O_RDONLY, 0666);
+ if (! strcmp (map->map_from, from))
+ {
+ /* Found a match. */
+ return open (map->map_to, O_RDONLY, 0666);
+ }
}
}
- }
- /* Try to find a mapping file for the particular directory we are
- looking in. Thus #include <sys/types.h> will look up sys/types.h
- in /usr/include/header.gcc and look up types.h in
- /usr/include/sys/header.gcc. */
- p = rindex (filename, '/');
- if (! p)
- p = filename;
- if (searchptr
- && searchptr->fname
- && strlen (searchptr->fname) == p - filename
- && ! strncmp (searchptr->fname, filename, p - filename))
- {
- /* FILENAME is in SEARCHPTR, which we've already checked. */
- return open (filename, O_RDONLY, 0666);
- }
+ /* Try to find a mapping file for the particular directory we are
+ looking in. Thus #include <sys/types.h> will look up sys/types.h
+ in /usr/include/header.gcc and look up types.h in
+ /usr/include/sys/header.gcc. */
+ p = rindex (filename, '/');
+ if (! p)
+ p = filename;
+ if (searchptr
+ && searchptr->fname
+ && strlen (searchptr->fname) == p - filename
+ && ! strncmp (searchptr->fname, filename, p - filename))
+ {
+ /* FILENAME is in SEARCHPTR, which we've already checked. */
+ return open (filename, O_RDONLY, 0666);
+ }
- if (p == filename)
- {
- dir = ".";
- from = filename;
- }
- else
- {
- dir = (char *) alloca (p - filename + 1);
- bcopy (filename, dir, p - filename);
- dir[p - filename] = '\0';
- from = p + 1;
+ if (p == filename)
+ {
+ dir = ".";
+ from = filename;
+ }
+ else
+ {
+ dir = (char *) alloca (p - filename + 1);
+ bcopy (filename, dir, p - filename);
+ dir[p - filename] = '\0';
+ from = p + 1;
+ }
+ for (map = read_name_map (pfile, dir); map; map = map->map_next)
+ if (! strcmp (map->map_from, from))
+ return open (map->map_to, O_RDONLY, 0666);
}
- for (map = read_name_map (pfile, dir); map; map = map->map_next)
- if (! strcmp (map->map_from, from))
- return open (map->map_to, O_RDONLY, 0666);
return open (filename, O_RDONLY, 0666);
}
@@ -5595,14 +5562,16 @@ finclude (pfile, f, fname, system_header_p, dirptr)
int system_header_p;
struct file_name_list *dirptr;
{
- int st_mode;
- long st_size;
+ struct stat st;
+ size_t st_size;
long i;
int length;
cpp_buffer *fp; /* For input stack frame */
+#if 0
int missing_newline = 0;
+#endif
- if (file_size_and_mode (f, &st_mode, &st_size) < 0)
+ if (fstat (f, &st) < 0)
{
cpp_perror_with_name (pfile, fname);
close (f);
@@ -5621,7 +5590,13 @@ finclude (pfile, f, fname, system_header_p, dirptr)
fp->colno = 1;
fp->cleanup = file_cleanup;
- if (S_ISREG (st_mode)) {
+ if (S_ISREG (st.st_mode)) {
+ st_size = (size_t) st.st_size;
+ if (st_size != st.st_size || st_size + 2 < st_size) {
+ cpp_error (pfile, "file `%s' too large", fname);
+ close (f);
+ return 0;
+ }
fp->buf = (U_CHAR *) xmalloc (st_size + 2);
fp->alimit = fp->buf + st_size + 2;
fp->cur = fp->buf;
@@ -5632,14 +5607,14 @@ finclude (pfile, f, fname, system_header_p, dirptr)
fp->rlimit = fp->buf + length;
if (length < 0) goto nope;
}
- else if (S_ISDIR (st_mode)) {
+ else if (S_ISDIR (st.st_mode)) {
cpp_error (pfile, "directory `%s' specified in #include", fname);
close (f);
return 0;
} else {
/* Cannot count its file size before reading.
First read the entire file into heap and
- copy them into buffer on stack. */
+ copy them into buffer on stack. */
int bsize = 2000;
@@ -5707,8 +5682,14 @@ finclude (pfile, f, fname, system_header_p, dirptr)
return 1;
}
+/* This is called after options have been processed.
+ * Check options for consistency, and setup for processing input
+ * from the file named FNAME. (Use standard input if FNAME==NULL.)
+ * Return 1 on success, 0 on failure.
+ */
+
int
-push_parse_file (pfile, fname)
+cpp_start_read (pfile, fname)
cpp_reader *pfile;
char *fname;
{
@@ -5729,7 +5710,7 @@ push_parse_file (pfile, fname)
/* Some people say that CPATH should replace the standard include dirs,
but that seems pointless: it comes before them, so it overrides them
anyway. */
- p = (char *) getenv ("CPATH");
+ GET_ENVIRONMENT (p, "CPATH");
if (p != 0 && ! opts->no_standard_includes)
path_include (pfile, p);
@@ -5739,6 +5720,8 @@ push_parse_file (pfile, fname)
/* Do partial setup of input buffer for the sake of generating
early #line directives (when -g is in effect). */
fp = cpp_push_buffer (pfile, NULL, 0);
+ if (!fp)
+ return 0;
if (opts->in_fname == NULL)
opts->in_fname = "";
fp->nominal_fname = fp->fname = opts->in_fname;
@@ -5823,7 +5806,7 @@ push_parse_file (pfile, fname)
/* Now handle the command line options. */
/* Do -U's, -D's and -A's in the order they were seen. */
- /* First reverse the list. */
+ /* First reverse the list. */
opts->pending = nreverse_pending (opts->pending);
for (pend = opts->pending; pend; pend = pend->next)
@@ -5851,22 +5834,22 @@ push_parse_file (pfile, fname)
opts->done_initializing = 1;
- { /* read the appropriate environment variable and if it exists
- replace include_defaults with the listed path. */
+ { /* Read the appropriate environment variable and if it exists
+ replace include_defaults with the listed path. */
char *epath = 0;
switch ((opts->objc << 1) + opts->cplusplus)
{
case 0:
- epath = getenv ("C_INCLUDE_PATH");
+ GET_ENVIRONMENT (epath, "C_INCLUDE_PATH");
break;
case 1:
- epath = getenv ("CPLUS_INCLUDE_PATH");
+ GET_ENVIRONMENT (epath, "CPLUS_INCLUDE_PATH");
break;
case 2:
- epath = getenv ("OBJC_INCLUDE_PATH");
+ GET_ENVIRONMENT (epath, "OBJC_INCLUDE_PATH");
break;
case 3:
- epath = getenv ("OBJCPLUS_INCLUDE_PATH");
+ GET_ENVIRONMENT (epath, "OBJCPLUS_INCLUDE_PATH");
break;
}
/* If the environment var for this language is set,
@@ -5896,6 +5879,7 @@ push_parse_file (pfile, fname)
nstore[endp-startp] = '\0';
include_defaults[num_dirs].fname = savestring (nstore);
+ include_defaults[num_dirs].component = 0;
include_defaults[num_dirs].cplusplus = opts->cplusplus;
include_defaults[num_dirs].cxx_aware = 1;
num_dirs++;
@@ -5962,7 +5946,7 @@ push_parse_file (pfile, fname)
= (struct file_name_list *) xmalloc (sizeof (struct file_name_list));
new->control_macro = 0;
new->c_system_include_path = !p->cxx_aware;
- new->fname = p->fname;
+ new->fname = update_path (p->fname, p->component);
new->got_name_map = 0;
append_include_chain (pfile, new, new);
if (opts->first_system_include == 0)
@@ -6001,9 +5985,10 @@ push_parse_file (pfile, fname)
if (fd < 0)
{
cpp_perror_with_name (pfile, pend->arg);
- return FATAL_EXIT_CODE;
+ return 0;
}
- cpp_push_buffer (pfile, NULL, 0);
+ if (!cpp_push_buffer (pfile, NULL, 0))
+ return 0;
finclude (pfile, fd, pend->arg, 0, NULL_PTR);
cpp_scan_buffer (pfile);
}
@@ -6023,7 +6008,10 @@ push_parse_file (pfile, fname)
inhibit compilation. */
if (opts->print_deps_missing_files
&& (opts->print_deps == 0 || !opts->no_output))
- fatal (pfile, "-MG must be specified with one of -M or -MM");
+ {
+ cpp_fatal (pfile, "-MG must be specified with one of -M or -MM");
+ return 0;
+ }
/* Either of two environment variables can specify output of deps.
Its value is either "OUTPUT_FILE" or "OUTPUT_FILE DEPS_TARGET",
@@ -6082,8 +6070,12 @@ push_parse_file (pfile, fname)
deps_output (pfile, "-", ':');
else
{
- char *p, *q;
- int len;
+ char *p, *q, *r;
+ int len, x;
+ static char *known_suffixes[] = { ".c", ".C", ".s", ".S", ".m",
+ ".cc", ".cxx", ".cpp", ".cp",
+ ".c++", 0
+ };
/* Discard all directory prefixes from filename. */
if ((q = rindex (opts->in_fname, '/')) != NULL
@@ -6102,27 +6094,21 @@ push_parse_file (pfile, fname)
/* Output P, but remove known suffixes. */
len = strlen (p);
q = p + len;
- if (len >= 2
- && p[len - 2] == '.'
- && index("cCsSm", p[len - 1]))
- q = p + (len - 2);
- else if (len >= 3
- && p[len - 3] == '.'
- && p[len - 2] == 'c'
- && p[len - 1] == 'c')
- q = p + (len - 3);
- else if (len >= 4
- && p[len - 4] == '.'
- && p[len - 3] == 'c'
- && p[len - 2] == 'x'
- && p[len - 1] == 'x')
- q = p + (len - 4);
- else if (len >= 4
- && p[len - 4] == '.'
- && p[len - 3] == 'c'
- && p[len - 2] == 'p'
- && p[len - 1] == 'p')
- q = p + (len - 4);
+ /* Point to the filename suffix. */
+ r = rindex (p, '.');
+ /* Compare against the known suffixes. */
+ x = 0;
+ while (known_suffixes[x] != 0)
+ {
+ if (strncmp (known_suffixes[x], r, q - r) == 0)
+ {
+ /* Make q point to the bit we're going to overwrite
+ with an object suffix. */
+ q = r;
+ break;
+ }
+ x++;
+ }
/* Supply our own suffix. */
#ifndef VMS
@@ -6166,15 +6152,16 @@ push_parse_file (pfile, fname)
if (fd < 0)
{
cpp_perror_with_name (pfile, pend->arg);
- return FATAL_EXIT_CODE;
+ return 0;
}
- cpp_push_buffer (pfile, NULL, 0);
+ if (!cpp_push_buffer (pfile, NULL, 0))
+ return 0;
finclude (pfile, fd, pend->arg, 0, NULL_PTR);
}
}
pfile->no_record_file--;
- /* Free the pending list. */
+ /* Free the pending list. */
for (pend = opts->pending; pend; )
{
struct cpp_pending *next = pend->next;
@@ -6197,18 +6184,18 @@ push_parse_file (pfile, fname)
#endif
if (finclude (pfile, f, fname, 0, NULL_PTR))
output_line_command (pfile, 0, same_file);
- return SUCCESS_EXIT_CODE;
+ return 1;
}
void
-init_parse_file (pfile)
+cpp_reader_init (pfile)
cpp_reader *pfile;
{
bzero ((char *) pfile, sizeof (cpp_reader));
pfile->get_token = cpp_get_token;
pfile->token_buffer_size = 200;
- pfile->token_buffer = (U_CHAR*)xmalloc (pfile->token_buffer_size);
+ pfile->token_buffer = (U_CHAR *) xmalloc (pfile->token_buffer_size);
CPP_SET_WRITTEN (pfile, 0);
pfile->system_include_depth = 0;
@@ -6242,479 +6229,609 @@ push_pending (pfile, cmd, arg)
char *arg;
{
struct cpp_pending *pend
- = (struct cpp_pending*)xmalloc (sizeof (struct cpp_pending));
+ = (struct cpp_pending *) xmalloc (sizeof (struct cpp_pending));
pend->cmd = cmd;
pend->arg = arg;
pend->next = CPP_OPTIONS (pfile)->pending;
CPP_OPTIONS (pfile)->pending = pend;
}
-/* Handle command-line options in (argc, argv).
- Can be called multiple times, to handle multiple sets of options.
- Returns if an unrecognized option is seen.
- Returns number of handled arguments. */
+
+static void
+print_help ()
+{
+ printf ("Usage: %s [switches] input output\n", progname);
+ printf ("Switches:\n");
+ printf (" -include <file> Include the contents of <file> before other files\n");
+ printf (" -imacros <file> Accept definition of marcos in <file>\n");
+ printf (" -iprefix <path> Specify <path> as a prefix for next two options\n");
+ printf (" -iwithprefix <dir> Add <dir> to the end of the system include paths\n");
+ printf (" -iwithprefixbefore <dir> Add <dir> to the end of the main include paths\n");
+ printf (" -isystem <dir> Add <dir> to the start of the system include paths\n");
+ printf (" -idirafter <dir> Add <dir> to the end of the system include paths\n");
+ printf (" -I <dir> Add <dir> to the end of the main include paths\n");
+ printf (" -nostdinc Do not search the system include directories\n");
+ printf (" -nostdinc++ Do not search the system include directories for C++\n");
+ printf (" -o <file> Put output into <file>\n");
+ printf (" -pedantic Issue all warnings demanded by strict ANSI C\n");
+ printf (" -traditional Follow K&R pre-processor behaviour\n");
+ printf (" -trigraphs Support ANSI C trigraphs\n");
+ printf (" -lang-c Assume that the input sources are in C\n");
+ printf (" -lang-c89 Assume that the input sources are in C89\n");
+ printf (" -lang-c++ Assume that the input sources are in C++\n");
+ printf (" -lang-objc Assume that the input sources are in ObjectiveC\n");
+ printf (" -lang-objc++ Assume that the input sources are in ObjectiveC++\n");
+ printf (" -lang-asm Assume that the input sources are in assembler\n");
+ printf (" -lang-chill Assume that the input sources are in Chill\n");
+ printf (" -+ Allow parsing of C++ style features\n");
+ printf (" -w Inhibit warning messages\n");
+ printf (" -Wtrigraphs Warn if trigraphs are encountered\n");
+ printf (" -Wno-trigraphs Do not warn about trigraphs\n");
+ printf (" -Wcomment{s} Warn if one comment starts inside another\n");
+ printf (" -Wno-comment{s} Do not warn about comments\n");
+ printf (" -Wtraditional Warn if a macro argument is/would be turned into\n");
+ printf (" a string if -tradtional is specified\n");
+ printf (" -Wno-traditional Do not warn about stringification\n");
+ printf (" -Wundef Warn if an undefined macro is used by #if\n");
+ printf (" -Wno-undef Do not warn about testing udefined macros\n");
+ printf (" -Wimport Warn about the use of the #import directive\n");
+ printf (" -Wno-import Do not warn about the use of #import\n");
+ printf (" -Werror Treat all warnings as errors\n");
+ printf (" -Wno-error Do not treat warnings as errors\n");
+ printf (" -Wall Enable all preprocessor warnings\n");
+ printf (" -M Generate make dependencies\n");
+ printf (" -MM As -M, but ignore system header files\n");
+ printf (" -MD As -M, but put output in a .d file\n");
+ printf (" -MMD As -MD, but ignore system header files\n");
+ printf (" -MG Treat missing header file as generated files\n");
+ printf (" -g Include #define and #undef directives in the output\n");
+ printf (" -D<macro> Define a <macro> with string '1' as its value\n");
+ printf (" -D<macro>=<val> Define a <macro> with <val> as its value\n");
+ printf (" -A<question> (<answer>) Assert the <answer> to <question>\n");
+ printf (" -U<macro> Undefine <macro> \n");
+ printf (" -u or -undef Do not predefine any macros\n");
+ printf (" -v Display the version number\n");
+ printf (" -H Print the name of header files as they are used\n");
+ printf (" -C Do not discard comments\n");
+ printf (" -dM Display a list of macro definitions active at end\n");
+ printf (" -dD Preserve macro definitions in output\n");
+ printf (" -dN As -dD except that only the names are preserved\n");
+ printf (" -dI Include #include directives in the output\n");
+ printf (" -ifoutput Describe skipped code blocks in output \n");
+ printf (" -P Do not generate #line directives\n");
+ printf (" -$ Do not include '$' in identifiers\n");
+ printf (" -remap Remap file names when including files.\n");
+ printf (" -h or --help Display this information\n");
+}
+
+/* Handle one command-line option in (argc, argv).
+ Can be called multiple times, to handle multiple sets of options.
+ Returns number of strings consumed. */
int
-cpp_handle_options (pfile, argc, argv)
+cpp_handle_option (pfile, argc, argv)
cpp_reader *pfile;
int argc;
char **argv;
{
- int i;
struct cpp_options *opts = CPP_OPTIONS (pfile);
- for (i = 0; i < argc; i++) {
- if (argv[i][0] != '-') {
- if (opts->out_fname != NULL)
- fatal ("Usage: %s [switches] input output", argv[0]);
- else if (opts->in_fname != NULL)
- opts->out_fname = argv[i];
- else
- opts->in_fname = argv[i];
- } else {
- switch (argv[i][1]) {
-
- case 'i':
- if (!strcmp (argv[i], "-include")
- || !strcmp (argv[i], "-imacros")) {
- if (i + 1 == argc)
- fatal ("Filename missing after `%s' option", argv[i]);
- else
- push_pending (pfile, argv[i], argv[i+1]), i++;
- }
- if (!strcmp (argv[i], "-iprefix")) {
- if (i + 1 == argc)
- fatal ("Filename missing after `-iprefix' option");
- else
- opts->include_prefix = argv[++i];
- }
- if (!strcmp (argv[i], "-ifoutput")) {
- opts->output_conditionals = 1;
- }
- if (!strcmp (argv[i], "-isystem")) {
- struct file_name_list *dirtmp;
-
- if (i + 1 == argc)
- fatal ("Filename missing after `-isystem' option");
-
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0;
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 1;
- dirtmp->fname = (char *) xmalloc (strlen (argv[i+1]) + 1);
- strcpy (dirtmp->fname, argv[++i]);
- dirtmp->got_name_map = 0;
-
- if (opts->before_system == 0)
- opts->before_system = dirtmp;
- else
- opts->last_before_system->next = dirtmp;
- opts->last_before_system = dirtmp; /* Tail follows the last one */
- }
- /* Add directory to end of path for includes,
- with the default prefix at the front of its name. */
- if (!strcmp (argv[i], "-iwithprefix")) {
- struct file_name_list *dirtmp;
- char *prefix;
-
- if (opts->include_prefix != 0)
- prefix = opts->include_prefix;
- else {
- prefix = savestring (GCC_INCLUDE_DIR);
- /* Remove the `include' from /usr/local/lib/gcc.../include. */
- if (!strcmp (prefix + strlen (prefix) - 8, "/include"))
- prefix[strlen (prefix) - 7] = 0;
- }
-
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0; /* New one goes on the end */
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 0;
- if (i + 1 == argc)
- fatal ("Directory name missing after `-iwithprefix' option");
-
- dirtmp->fname = (char *) xmalloc (strlen (argv[i+1])
- + strlen (prefix) + 1);
- strcpy (dirtmp->fname, prefix);
- strcat (dirtmp->fname, argv[++i]);
- dirtmp->got_name_map = 0;
-
- if (opts->after_include == 0)
- opts->after_include = dirtmp;
- else
- opts->last_after_include->next = dirtmp;
- opts->last_after_include = dirtmp; /* Tail follows the last one */
- }
- /* Add directory to main path for includes,
- with the default prefix at the front of its name. */
- if (!strcmp (argv[i], "-iwithprefixbefore")) {
- struct file_name_list *dirtmp;
- char *prefix;
-
- if (opts->include_prefix != 0)
- prefix = opts->include_prefix;
- else {
- prefix = savestring (GCC_INCLUDE_DIR);
- /* Remove the `include' from /usr/local/lib/gcc.../include. */
- if (!strcmp (prefix + strlen (prefix) - 8, "/include"))
- prefix[strlen (prefix) - 7] = 0;
- }
-
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0; /* New one goes on the end */
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 0;
- if (i + 1 == argc)
- fatal ("Directory name missing after `-iwithprefixbefore' option");
-
- dirtmp->fname = (char *) xmalloc (strlen (argv[i+1])
- + strlen (prefix) + 1);
- strcpy (dirtmp->fname, prefix);
- strcat (dirtmp->fname, argv[++i]);
- dirtmp->got_name_map = 0;
-
- append_include_chain (pfile, dirtmp, dirtmp);
+ int i = 0;
+ if (argv[i][0] != '-') {
+ if (opts->out_fname != NULL)
+ {
+ print_help ();
+ cpp_fatal (pfile, "Too many arguments");
+ }
+ else if (opts->in_fname != NULL)
+ opts->out_fname = argv[i];
+ else
+ opts->in_fname = argv[i];
+ } else {
+ switch (argv[i][1]) {
+
+ missing_filename:
+ cpp_fatal (pfile, "Filename missing after `%s' option", argv[i]);
+ return argc;
+ missing_dirname:
+ cpp_fatal (pfile, "Directory name missing after `%s' option", argv[i]);
+ return argc;
+
+ case 'i':
+ if (!strcmp (argv[i], "-include")
+ || !strcmp (argv[i], "-imacros")) {
+ if (i + 1 == argc)
+ goto missing_filename;
+ else
+ push_pending (pfile, argv[i], argv[i+1]), i++;
+ }
+ if (!strcmp (argv[i], "-iprefix")) {
+ if (i + 1 == argc)
+ goto missing_filename;
+ else
+ opts->include_prefix = argv[++i];
+ }
+ if (!strcmp (argv[i], "-ifoutput")) {
+ opts->output_conditionals = 1;
+ }
+ if (!strcmp (argv[i], "-isystem")) {
+ struct file_name_list *dirtmp;
+
+ if (i + 1 == argc)
+ goto missing_filename;
+
+ dirtmp = (struct file_name_list *)
+ xmalloc (sizeof (struct file_name_list));
+ dirtmp->next = 0;
+ dirtmp->control_macro = 0;
+ dirtmp->c_system_include_path = 1;
+ dirtmp->fname = (char *) xmalloc (strlen (argv[i+1]) + 1);
+ strcpy (dirtmp->fname, argv[++i]);
+ dirtmp->got_name_map = 0;
+
+ if (opts->before_system == 0)
+ opts->before_system = dirtmp;
+ else
+ opts->last_before_system->next = dirtmp;
+ opts->last_before_system = dirtmp; /* Tail follows the last one */
+ }
+ /* Add directory to end of path for includes,
+ with the default prefix at the front of its name. */
+ if (!strcmp (argv[i], "-iwithprefix")) {
+ struct file_name_list *dirtmp;
+ char *prefix;
+
+ if (opts->include_prefix != 0)
+ prefix = opts->include_prefix;
+ else {
+ prefix = savestring (GCC_INCLUDE_DIR);
+ /* Remove the `include' from /usr/local/lib/gcc.../include. */
+ if (!strcmp (prefix + strlen (prefix) - 8, "/include"))
+ prefix[strlen (prefix) - 7] = 0;
}
- /* Add directory to end of path for includes. */
- if (!strcmp (argv[i], "-idirafter")) {
- struct file_name_list *dirtmp;
-
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0; /* New one goes on the end */
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 0;
- if (i + 1 == argc)
- fatal ("Directory name missing after `-idirafter' option");
- else
- dirtmp->fname = argv[++i];
- dirtmp->got_name_map = 0;
-
- if (opts->after_include == 0)
- opts->after_include = dirtmp;
- else
- opts->last_after_include->next = dirtmp;
- opts->last_after_include = dirtmp; /* Tail follows the last one */
+
+ dirtmp = (struct file_name_list *)
+ xmalloc (sizeof (struct file_name_list));
+ dirtmp->next = 0; /* New one goes on the end */
+ dirtmp->control_macro = 0;
+ dirtmp->c_system_include_path = 0;
+ if (i + 1 == argc)
+ goto missing_dirname;
+
+ dirtmp->fname = (char *) xmalloc (strlen (argv[i+1])
+ + strlen (prefix) + 1);
+ strcpy (dirtmp->fname, prefix);
+ strcat (dirtmp->fname, argv[++i]);
+ dirtmp->got_name_map = 0;
+
+ if (opts->after_include == 0)
+ opts->after_include = dirtmp;
+ else
+ opts->last_after_include->next = dirtmp;
+ opts->last_after_include = dirtmp; /* Tail follows the last one */
+ }
+ /* Add directory to main path for includes,
+ with the default prefix at the front of its name. */
+ if (!strcmp (argv[i], "-iwithprefixbefore")) {
+ struct file_name_list *dirtmp;
+ char *prefix;
+
+ if (opts->include_prefix != 0)
+ prefix = opts->include_prefix;
+ else {
+ prefix = savestring (GCC_INCLUDE_DIR);
+ /* Remove the `include' from /usr/local/lib/gcc.../include. */
+ if (!strcmp (prefix + strlen (prefix) - 8, "/include"))
+ prefix[strlen (prefix) - 7] = 0;
}
- break;
-
- case 'o':
- if (opts->out_fname != NULL)
- fatal ("Output filename specified twice");
+
+ dirtmp = (struct file_name_list *)
+ xmalloc (sizeof (struct file_name_list));
+ dirtmp->next = 0; /* New one goes on the end */
+ dirtmp->control_macro = 0;
+ dirtmp->c_system_include_path = 0;
if (i + 1 == argc)
- fatal ("Filename missing after -o option");
- opts->out_fname = argv[++i];
- if (!strcmp (opts->out_fname, "-"))
- opts->out_fname = "";
- break;
-
- case 'p':
- if (!strcmp (argv[i], "-pedantic"))
- CPP_PEDANTIC (pfile) = 1;
- else if (!strcmp (argv[i], "-pedantic-errors")) {
- CPP_PEDANTIC (pfile) = 1;
- opts->pedantic_errors = 1;
+ goto missing_dirname;
+
+ dirtmp->fname = (char *) xmalloc (strlen (argv[i+1])
+ + strlen (prefix) + 1);
+ strcpy (dirtmp->fname, prefix);
+ strcat (dirtmp->fname, argv[++i]);
+ dirtmp->got_name_map = 0;
+
+ append_include_chain (pfile, dirtmp, dirtmp);
+ }
+ /* Add directory to end of path for includes. */
+ if (!strcmp (argv[i], "-idirafter")) {
+ struct file_name_list *dirtmp;
+
+ dirtmp = (struct file_name_list *)
+ xmalloc (sizeof (struct file_name_list));
+ dirtmp->next = 0; /* New one goes on the end */
+ dirtmp->control_macro = 0;
+ dirtmp->c_system_include_path = 0;
+ if (i + 1 == argc)
+ goto missing_dirname;
+ else
+ dirtmp->fname = argv[++i];
+ dirtmp->got_name_map = 0;
+
+ if (opts->after_include == 0)
+ opts->after_include = dirtmp;
+ else
+ opts->last_after_include->next = dirtmp;
+ opts->last_after_include = dirtmp; /* Tail follows the last one */
+ }
+ break;
+
+ case 'o':
+ if (opts->out_fname != NULL)
+ {
+ cpp_fatal (pfile, "Output filename specified twice");
+ return argc;
}
+ if (i + 1 == argc)
+ goto missing_filename;
+ opts->out_fname = argv[++i];
+ if (!strcmp (opts->out_fname, "-"))
+ opts->out_fname = "";
+ break;
+
+ case 'p':
+ if (!strcmp (argv[i], "-pedantic"))
+ CPP_PEDANTIC (pfile) = 1;
+ else if (!strcmp (argv[i], "-pedantic-errors")) {
+ CPP_PEDANTIC (pfile) = 1;
+ opts->pedantic_errors = 1;
+ }
#if 0
- else if (!strcmp (argv[i], "-pcp")) {
- char *pcp_fname = argv[++i];
- pcp_outfile =
- ((pcp_fname[0] != '-' || pcp_fname[1] != '\0')
- ? fopen (pcp_fname, "w")
- : fdopen (dup (fileno (stdout)), "w"));
- if (pcp_outfile == 0)
- cpp_pfatal_with_name (pfile, pcp_fname);
- no_precomp = 1;
- }
+ else if (!strcmp (argv[i], "-pcp")) {
+ char *pcp_fname = argv[++i];
+ pcp_outfile = ((pcp_fname[0] != '-' || pcp_fname[1] != '\0')
+ ? fopen (pcp_fname, "w")
+ : fdopen (dup (fileno (stdout)), "w"));
+ if (pcp_outfile == 0)
+ cpp_pfatal_with_name (pfile, pcp_fname);
+ no_precomp = 1;
+ }
#endif
- break;
-
- case 't':
- if (!strcmp (argv[i], "-traditional")) {
- opts->traditional = 1;
- if (opts->dollars_in_ident > 0)
- opts->dollars_in_ident = 1;
- } else if (!strcmp (argv[i], "-trigraphs")) {
- if (!opts->chill)
- opts->no_trigraphs = 0;
- }
- break;
-
- case 'l':
- if (! strcmp (argv[i], "-lang-c"))
- opts->cplusplus = 0, opts->cplusplus_comments = 0, opts->objc = 0;
- if (! strcmp (argv[i], "-lang-c++"))
- opts->cplusplus = 1, opts->cplusplus_comments = 1, opts->objc = 0;
- if (! strcmp (argv[i], "-lang-c-c++-comments"))
- opts->cplusplus = 0, opts->cplusplus_comments = 1, opts->objc = 0;
- if (! strcmp (argv[i], "-lang-objc"))
- opts->objc = 1, opts->cplusplus = 0, opts->cplusplus_comments = 1;
- if (! strcmp (argv[i], "-lang-objc++"))
- opts->objc = 1, opts->cplusplus = 1, opts->cplusplus_comments = 1;
- if (! strcmp (argv[i], "-lang-asm"))
- opts->lang_asm = 1;
- if (! strcmp (argv[i], "-lint"))
- opts->for_lint = 1;
- if (! strcmp (argv[i], "-lang-chill"))
- opts->objc = 0, opts->cplusplus = 0, opts->chill = 1,
+ break;
+
+ case 't':
+ if (!strcmp (argv[i], "-traditional")) {
+ opts->traditional = 1;
+ opts->cplusplus_comments = 0;
+ } else if (!strcmp (argv[i], "-trigraphs")) {
+ if (!opts->chill)
+ opts->no_trigraphs = 0;
+ }
+ break;
+
+ case 'l':
+ if (! strcmp (argv[i], "-lang-c"))
+ opts->cplusplus = 0, opts->cplusplus_comments = 1, opts->c89 = 0,
+ opts->objc = 0;
+ if (! strcmp (argv[i], "-lang-c89"))
+ opts->cplusplus = 0, opts->cplusplus_comments = 0, opts->c89 = 1,
+ opts->objc = 0;
+ if (! strcmp (argv[i], "-lang-c++"))
+ opts->cplusplus = 1, opts->cplusplus_comments = 1, opts->c89 = 0,
+ opts->objc = 0;
+ if (! strcmp (argv[i], "-lang-objc"))
+ opts->cplusplus = 0, opts->cplusplus_comments = 1, opts->c89 = 0,
+ opts->objc = 1;
+ if (! strcmp (argv[i], "-lang-objc++"))
+ opts->cplusplus = 1, opts->cplusplus_comments = 1, opts->c89 = 0,
+ opts->objc = 1;
+ if (! strcmp (argv[i], "-lang-asm"))
+ opts->lang_asm = 1;
+ if (! strcmp (argv[i], "-lint"))
+ opts->for_lint = 1;
+ if (! strcmp (argv[i], "-lang-chill"))
+ opts->objc = 0, opts->cplusplus = 0, opts->chill = 1,
opts->traditional = 1, opts->no_trigraphs = 1;
- break;
-
- case '+':
- opts->cplusplus = 1, opts->cplusplus_comments = 1;
- break;
-
- case 'w':
- opts->inhibit_warnings = 1;
- break;
-
- case 'W':
- if (!strcmp (argv[i], "-Wtrigraphs"))
+ break;
+
+ case '+':
+ opts->cplusplus = 1, opts->cplusplus_comments = 1;
+ break;
+
+ case 'w':
+ opts->inhibit_warnings = 1;
+ break;
+
+ case 'W':
+ if (!strcmp (argv[i], "-Wtrigraphs"))
+ opts->warn_trigraphs = 1;
+ else if (!strcmp (argv[i], "-Wno-trigraphs"))
+ opts->warn_trigraphs = 0;
+ else if (!strcmp (argv[i], "-Wcomment"))
+ opts->warn_comments = 1;
+ else if (!strcmp (argv[i], "-Wno-comment"))
+ opts->warn_comments = 0;
+ else if (!strcmp (argv[i], "-Wcomments"))
+ opts->warn_comments = 1;
+ else if (!strcmp (argv[i], "-Wno-comments"))
+ opts->warn_comments = 0;
+ else if (!strcmp (argv[i], "-Wtraditional"))
+ opts->warn_stringify = 1;
+ else if (!strcmp (argv[i], "-Wno-traditional"))
+ opts->warn_stringify = 0;
+ else if (!strcmp (argv[i], "-Wundef"))
+ opts->warn_undef = 1;
+ else if (!strcmp (argv[i], "-Wno-undef"))
+ opts->warn_undef = 0;
+ else if (!strcmp (argv[i], "-Wimport"))
+ opts->warn_import = 1;
+ else if (!strcmp (argv[i], "-Wno-import"))
+ opts->warn_import = 0;
+ else if (!strcmp (argv[i], "-Werror"))
+ opts->warnings_are_errors = 1;
+ else if (!strcmp (argv[i], "-Wno-error"))
+ opts->warnings_are_errors = 0;
+ else if (!strcmp (argv[i], "-Wall"))
+ {
opts->warn_trigraphs = 1;
- else if (!strcmp (argv[i], "-Wno-trigraphs"))
- opts->warn_trigraphs = 0;
- else if (!strcmp (argv[i], "-Wcomment"))
opts->warn_comments = 1;
- else if (!strcmp (argv[i], "-Wno-comment"))
- opts->warn_comments = 0;
- else if (!strcmp (argv[i], "-Wcomments"))
- opts->warn_comments = 1;
- else if (!strcmp (argv[i], "-Wno-comments"))
- opts->warn_comments = 0;
- else if (!strcmp (argv[i], "-Wtraditional"))
- opts->warn_stringify = 1;
- else if (!strcmp (argv[i], "-Wno-traditional"))
- opts->warn_stringify = 0;
- else if (!strcmp (argv[i], "-Wimport"))
- opts->warn_import = 1;
- else if (!strcmp (argv[i], "-Wno-import"))
- opts->warn_import = 0;
- else if (!strcmp (argv[i], "-Werror"))
- opts->warnings_are_errors = 1;
- else if (!strcmp (argv[i], "-Wno-error"))
- opts->warnings_are_errors = 0;
- else if (!strcmp (argv[i], "-Wall"))
- {
- opts->warn_trigraphs = 1;
- opts->warn_comments = 1;
- }
- break;
-
- case 'M':
- /* The style of the choices here is a bit mixed.
- The chosen scheme is a hybrid of keeping all options in one string
- and specifying each option in a separate argument:
- -M|-MM|-MD file|-MMD file [-MG]. An alternative is:
- -M|-MM|-MD file|-MMD file|-MG|-MMG; or more concisely:
- -M[M][G][D file]. This is awkward to handle in specs, and is not
- as extensible. */
- /* ??? -MG must be specified in addition to one of -M or -MM.
- This can be relaxed in the future without breaking anything.
- The converse isn't true. */
-
- /* -MG isn't valid with -MD or -MMD. This is checked for later. */
- if (!strcmp (argv[i], "-MG"))
- {
- opts->print_deps_missing_files = 1;
- break;
- }
- if (!strcmp (argv[i], "-M"))
- opts->print_deps = 2;
- else if (!strcmp (argv[i], "-MM"))
- opts->print_deps = 1;
- else if (!strcmp (argv[i], "-MD"))
- opts->print_deps = 2;
- else if (!strcmp (argv[i], "-MMD"))
- opts->print_deps = 1;
- /* For -MD and -MMD options, write deps on file named by next arg. */
- if (!strcmp (argv[i], "-MD") || !strcmp (argv[i], "-MMD"))
- {
- if (i+1 == argc)
- fatal ("Filename missing after %s option", argv[i]);
- opts->deps_file = argv[++i];
- }
- else
- {
- /* For -M and -MM, write deps on standard output
- and suppress the usual output. */
- opts->no_output = 1;
- }
- break;
-
- case 'd':
+ }
+ break;
+
+ case 'M':
+ /* The style of the choices here is a bit mixed.
+ The chosen scheme is a hybrid of keeping all options in one string
+ and specifying each option in a separate argument:
+ -M|-MM|-MD file|-MMD file [-MG]. An alternative is:
+ -M|-MM|-MD file|-MMD file|-MG|-MMG; or more concisely:
+ -M[M][G][D file]. This is awkward to handle in specs, and is not
+ as extensible. */
+ /* ??? -MG must be specified in addition to one of -M or -MM.
+ This can be relaxed in the future without breaking anything.
+ The converse isn't true. */
+
+ /* -MG isn't valid with -MD or -MMD. This is checked for later. */
+ if (!strcmp (argv[i], "-MG"))
{
- char *p = argv[i] + 2;
- char c;
- while ((c = *p++) != 0) {
- /* Arg to -d specifies what parts of macros to dump */
- switch (c) {
- case 'M':
- opts->dump_macros = dump_only;
- opts->no_output = 1;
- break;
- case 'N':
- opts->dump_macros = dump_names;
- break;
- case 'D':
- opts->dump_macros = dump_definitions;
- break;
- }
+ opts->print_deps_missing_files = 1;
+ break;
+ }
+ if (!strcmp (argv[i], "-M"))
+ opts->print_deps = 2;
+ else if (!strcmp (argv[i], "-MM"))
+ opts->print_deps = 1;
+ else if (!strcmp (argv[i], "-MD"))
+ opts->print_deps = 2;
+ else if (!strcmp (argv[i], "-MMD"))
+ opts->print_deps = 1;
+ /* For -MD and -MMD options, write deps on file named by next arg. */
+ if (!strcmp (argv[i], "-MD") || !strcmp (argv[i], "-MMD"))
+ {
+ if (i+1 == argc)
+ goto missing_filename;
+ opts->deps_file = argv[++i];
+ }
+ else
+ {
+ /* For -M and -MM, write deps on standard output
+ and suppress the usual output. */
+ opts->no_output = 1;
+ }
+ break;
+
+ case 'd':
+ {
+ char *p = argv[i] + 2;
+ char c;
+ while ((c = *p++) != 0) {
+ /* Arg to -d specifies what parts of macros to dump */
+ switch (c) {
+ case 'M':
+ opts->dump_macros = dump_only;
+ opts->no_output = 1;
+ break;
+ case 'N':
+ opts->dump_macros = dump_names;
+ break;
+ case 'D':
+ opts->dump_macros = dump_definitions;
+ break;
+ case 'I':
+ opts->dump_includes = 1;
+ break;
}
}
- break;
-
- case 'g':
- if (argv[i][2] == '3')
- opts->debug_output = 1;
- break;
-
- case 'v':
- fprintf (stderr, "GNU CPP version %s", version_string);
+ }
+ break;
+
+ case 'g':
+ if (argv[i][2] == '3')
+ opts->debug_output = 1;
+ break;
+
+ case '-':
+ if (strcmp (argv[i], "--help") != 0)
+ return i;
+ print_help ();
+ break;
+
+ case 'v':
+ fprintf (stderr, "GNU CPP version %s", version_string);
#ifdef TARGET_VERSION
- TARGET_VERSION;
+ TARGET_VERSION;
#endif
- fprintf (stderr, "\n");
- opts->verbose = 1;
- break;
-
- case 'H':
- opts->print_include_names = 1;
- break;
-
- case 'D':
+ fprintf (stderr, "\n");
+ opts->verbose = 1;
+ break;
+
+ case 'H':
+ opts->print_include_names = 1;
+ break;
+
+ case 'D':
+ if (argv[i][2] != 0)
+ push_pending (pfile, "-D", argv[i] + 2);
+ else if (i + 1 == argc)
+ {
+ cpp_fatal (pfile, "Macro name missing after -D option");
+ return argc;
+ }
+ else
+ i++, push_pending (pfile, "-D", argv[i]);
+ break;
+
+ case 'A':
+ {
+ char *p;
+
if (argv[i][2] != 0)
- push_pending (pfile, "-D", argv[i] + 2);
+ p = argv[i] + 2;
else if (i + 1 == argc)
- fatal ("Macro name missing after -D option");
+ {
+ cpp_fatal (pfile, "Assertion missing after -A option");
+ return argc;
+ }
else
- i++, push_pending (pfile, "-D", argv[i]);
- break;
-
- case 'A':
+ p = argv[++i];
+
+ if (!strcmp (p, "-")) {
+ struct cpp_pending **ptr;
+ /* -A- eliminates all predefined macros and assertions.
+ Let's include also any that were specified earlier
+ on the command line. That way we can get rid of any
+ that were passed automatically in from GCC. */
+ opts->inhibit_predefs = 1;
+ for (ptr = &opts->pending; *ptr != NULL; )
+ {
+ struct cpp_pending *pend = *ptr;
+ if (pend->cmd && pend->cmd[0] == '-'
+ && (pend->cmd[1] == 'D' || pend->cmd[1] == 'A'))
+ {
+ *ptr = pend->next;
+ free (pend);
+ }
+ else
+ ptr = &pend->next;
+ }
+ } else {
+ push_pending (pfile, "-A", p);
+ }
+ }
+ break;
+
+ case 'U': /* JF #undef something */
+ if (argv[i][2] != 0)
+ push_pending (pfile, "-U", argv[i] + 2);
+ else if (i + 1 == argc)
{
- char *p;
-
+ cpp_fatal (pfile, "Macro name missing after -U option");
+ return argc;
+ }
+ else
+ push_pending (pfile, "-U", argv[i+1]), i++;
+ break;
+
+ case 'C':
+ opts->put_out_comments = 1;
+ break;
+
+ case 'E': /* -E comes from cc -E; ignore it. */
+ break;
+
+ case 'P':
+ opts->no_line_commands = 1;
+ break;
+
+ case '$': /* Don't include $ in identifiers. */
+ opts->dollars_in_ident = 0;
+ break;
+
+ case 'I': /* Add directory to path for includes. */
+ {
+ struct file_name_list *dirtmp;
+
+ if (! CPP_OPTIONS(pfile)->ignore_srcdir
+ && !strcmp (argv[i] + 2, "-")) {
+ CPP_OPTIONS (pfile)->ignore_srcdir = 1;
+ /* Don't use any preceding -I directories for #include <...>. */
+ CPP_OPTIONS (pfile)->first_bracket_include = 0;
+ }
+ else {
+ dirtmp = (struct file_name_list *)
+ xmalloc (sizeof (struct file_name_list));
+ dirtmp->next = 0; /* New one goes on the end */
+ dirtmp->control_macro = 0;
+ dirtmp->c_system_include_path = 0;
if (argv[i][2] != 0)
- p = argv[i] + 2;
+ dirtmp->fname = argv[i] + 2;
else if (i + 1 == argc)
- fatal ("Assertion missing after -A option");
+ goto missing_dirname;
else
- p = argv[++i];
-
- if (!strcmp (p, "-")) {
- struct cpp_pending **ptr;
- /* -A- eliminates all predefined macros and assertions.
- Let's include also any that were specified earlier
- on the command line. That way we can get rid of any
- that were passed automatically in from GCC. */
- int j;
- opts->inhibit_predefs = 1;
- for (ptr = &opts->pending; *ptr != NULL; )
- {
- struct cpp_pending *pend = *ptr;
- if (pend->cmd && pend->cmd[0] == '-'
- && (pend->cmd[1] == 'D' || pend->cmd[1] == 'A'))
- {
- *ptr = pend->next;
- free (pend);
- }
- else
- ptr = &pend->next;
- }
- } else {
- push_pending (pfile, "-A", p);
- }
- }
- break;
-
- case 'U': /* JF #undef something */
- if (argv[i][2] != 0)
- push_pending (pfile, "-U", argv[i] + 2);
- else if (i + 1 == argc)
- fatal ("Macro name missing after -U option");
- else
- push_pending (pfile, "-U", argv[i+1]), i++;
- break;
-
- case 'C':
- opts->put_out_comments = 1;
- break;
-
- case 'E': /* -E comes from cc -E; ignore it. */
- break;
-
- case 'P':
- opts->no_line_commands = 1;
- break;
-
- case '$': /* Don't include $ in identifiers. */
- opts->dollars_in_ident = 0;
- break;
-
- case 'I': /* Add directory to path for includes. */
- {
- struct file_name_list *dirtmp;
-
- if (! CPP_OPTIONS(pfile)->ignore_srcdir
- && !strcmp (argv[i] + 2, "-")) {
- CPP_OPTIONS (pfile)->ignore_srcdir = 1;
- /* Don't use any preceding -I directories for #include <...>. */
- CPP_OPTIONS (pfile)->first_bracket_include = 0;
- }
- else {
- dirtmp = (struct file_name_list *)
- xmalloc (sizeof (struct file_name_list));
- dirtmp->next = 0; /* New one goes on the end */
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 0;
- if (argv[i][2] != 0)
- dirtmp->fname = argv[i] + 2;
- else if (i + 1 == argc)
- fatal ("Directory name missing after -I option");
- else
- dirtmp->fname = argv[++i];
- dirtmp->got_name_map = 0;
- append_include_chain (pfile, dirtmp, dirtmp);
- }
+ dirtmp->fname = argv[++i];
+ dirtmp->got_name_map = 0;
+ append_include_chain (pfile, dirtmp, dirtmp);
}
- break;
-
- case 'n':
- if (!strcmp (argv[i], "-nostdinc"))
- /* -nostdinc causes no default include directories.
- You must specify all include-file directories with -I. */
- opts->no_standard_includes = 1;
- else if (!strcmp (argv[i], "-nostdinc++"))
- /* -nostdinc++ causes no default C++-specific include directories. */
- opts->no_standard_cplusplus_includes = 1;
+ }
+ break;
+
+ case 'n':
+ if (!strcmp (argv[i], "-nostdinc"))
+ /* -nostdinc causes no default include directories.
+ You must specify all include-file directories with -I. */
+ opts->no_standard_includes = 1;
+ else if (!strcmp (argv[i], "-nostdinc++"))
+ /* -nostdinc++ causes no default C++-specific include directories. */
+ opts->no_standard_cplusplus_includes = 1;
#if 0
- else if (!strcmp (argv[i], "-noprecomp"))
- no_precomp = 1;
+ else if (!strcmp (argv[i], "-noprecomp"))
+ no_precomp = 1;
#endif
+ break;
+
+ case 'r':
+ if (!strcmp (argv[i], "-remap"))
+ opts->remap = 1;
+ break;
+
+ case 'u':
+ /* Sun compiler passes undocumented switch "-undef".
+ Let's assume it means to inhibit the predefined symbols. */
+ opts->inhibit_predefs = 1;
+ break;
+
+ case '\0': /* JF handle '-' as file name meaning stdin or stdout */
+ if (opts->in_fname == NULL) {
+ opts->in_fname = "";
break;
-
- case 'u':
- /* Sun compiler passes undocumented switch "-undef".
- Let's assume it means to inhibit the predefined symbols. */
- opts->inhibit_predefs = 1;
+ } else if (opts->out_fname == NULL) {
+ opts->out_fname = "";
break;
+ } /* else fall through into error */
+
+ default:
+ return i;
+ }
+ }
- case '\0': /* JF handle '-' as file name meaning stdin or stdout */
- if (opts->in_fname == NULL) {
- opts->in_fname = "";
- break;
- } else if (opts->out_fname == NULL) {
- opts->out_fname = "";
- break;
- } /* else fall through into error */
+ return i + 1;
+}
- default:
- return i;
- }
+/* Handle command-line options in (argc, argv).
+ Can be called multiple times, to handle multiple sets of options.
+ Returns if an unrecognized option is seen.
+ Returns number of strings consumed. */
+
+int
+cpp_handle_options (pfile, argc, argv)
+ cpp_reader *pfile;
+ int argc;
+ char **argv;
+{
+ int i;
+ int strings_processed;
+ for (i = 0; i < argc; i += strings_processed)
+ {
+ strings_processed = cpp_handle_option (pfile, argc - i, argv + i);
+ if (strings_processed == 0)
+ break;
}
- }
return i;
}
@@ -6742,13 +6859,14 @@ cpp_finish (pfile)
if (opts->deps_file)
{
if (ferror (deps_stream) || fclose (deps_stream) != 0)
- fatal ("I/O error on output");
+ cpp_fatal (pfile, "I/O error on output");
}
}
}
}
-/* Free resources used by PFILE. */
+/* Free resources used by PFILE.
+ This is the cpp_reader 'finalizer' or 'destructor' (in C++ terminology). */
void
cpp_cleanup (pfile)
@@ -6819,8 +6937,8 @@ cpp_cleanup (pfile)
static int
do_assert (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
- U_CHAR *buf, *limit;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+ U_CHAR *buf ATTRIBUTE_UNUSED, *limit ATTRIBUTE_UNUSED;
{
long symstart; /* remember where symbol name starts */
int c;
@@ -6892,8 +7010,8 @@ do_assert (pfile, keyword, buf, limit)
static int
do_unassert (pfile, keyword, buf, limit)
cpp_reader *pfile;
- struct directive *keyword;
- U_CHAR *buf, *limit;
+ struct directive *keyword ATTRIBUTE_UNUSED;
+ U_CHAR *buf ATTRIBUTE_UNUSED, *limit ATTRIBUTE_UNUSED;
{
long symstart; /* remember where symbol name starts */
int sym_length; /* and how long it is */
@@ -7079,7 +7197,7 @@ read_token_list (pfile, error_flag)
{
struct arglist *temp;
long name_written = CPP_WRITTEN (pfile);
- int eofp = 0; int c;
+ int c;
cpp_skip_hspace (pfile);
@@ -7154,25 +7272,9 @@ free_token_list (tokens)
}
}
-/* Get the file-mode and data size of the file open on FD
- and store them in *MODE_POINTER and *SIZE_POINTER. */
-
-static int
-file_size_and_mode (fd, mode_pointer, size_pointer)
- int fd;
- int *mode_pointer;
- long int *size_pointer;
-{
- struct stat sbuf;
-
- if (fstat (fd, &sbuf) < 0) return (-1);
- if (mode_pointer) *mode_pointer = sbuf.st_mode;
- if (size_pointer) *size_pointer = sbuf.st_size;
- return 0;
-}
-
/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
- retrying if necessary. Return a negative value if an error occurs,
+ retrying if necessary. If MAX_READ_LEN is defined, read at most
+ that bytes at a time. Return a negative value if an error occurs,
otherwise return the actual number of bytes read,
which must be LEN unless end-of-file was reached. */
@@ -7182,9 +7284,16 @@ safe_read (desc, ptr, len)
char *ptr;
int len;
{
- int left = len;
+ int left, rcount, nchars;
+
+ left = len;
while (left > 0) {
- int nchars = read (desc, ptr, left);
+ rcount = left;
+#ifdef MAX_READ_LEN
+ if (rcount > MAX_READ_LEN)
+ rcount = MAX_READ_LEN;
+#endif
+ nchars = read (desc, ptr, rcount);
if (nchars < 0)
{
#ifdef EINTR
@@ -7202,6 +7311,16 @@ safe_read (desc, ptr, len)
}
static char *
+xcalloc (number, size)
+ unsigned number, size;
+{
+ register unsigned total = number * size;
+ register char *ptr = (char *) xmalloc (total);
+ bzero (ptr, total);
+ return ptr;
+}
+
+static char *
savestring (input)
char *input;
{
@@ -7211,7 +7330,8 @@ savestring (input)
return output;
}
-/* Initialize PMARK to remember the current position of PFILE. */
+/* Initialize PMARK to remember the current position of PFILE. */
+
void
parse_set_mark (pmark, pfile)
struct parse_marker *pmark;
@@ -7224,20 +7344,21 @@ parse_set_mark (pmark, pfile)
pmark->position = pbuf->cur - pbuf->buf;
}
-/* Cleanup PMARK - we no longer need it. */
+/* Cleanup PMARK - we no longer need it. */
+
void
parse_clear_mark (pmark)
struct parse_marker *pmark;
{
struct parse_marker **pp = &pmark->buf->marks;
for (; ; pp = &(*pp)->next) {
- if (*pp == NULL) fatal ("internal error", "in parse_set_mark");
+ if (*pp == NULL) abort ();
if (*pp == pmark) break;
}
*pp = pmark->next;
}
-/* Backup the current position of PFILE to that saved in PMARK. */
+/* Backup the current position of PFILE to that saved in PMARK. */
void
parse_goto_mark (pmark, pfile)
@@ -7246,12 +7367,12 @@ parse_goto_mark (pmark, pfile)
{
cpp_buffer *pbuf = CPP_BUFFER (pfile);
if (pbuf != pmark->buf)
- fatal ("internal error %s", "parse_goto_mark");
+ cpp_fatal (pfile, "internal error %s", "parse_goto_mark");
pbuf->cur = pbuf->buf + pmark->position;
}
/* Reset PMARK to point to the current position of PFILE. (Same
- as parse_clear_mark (PMARK), parse_set_mark (PMARK, PFILE) but faster. */
+ as parse_clear_mark (PMARK), parse_set_mark (PMARK, PFILE) but faster. */
void
parse_move_mark (pmark, pfile)
@@ -7260,7 +7381,7 @@ parse_move_mark (pmark, pfile)
{
cpp_buffer *pbuf = CPP_BUFFER (pfile);
if (pbuf != pmark->buf)
- fatal ("internal error %s", "parse_move_mark");
+ cpp_fatal (pfile, "internal error %s", "parse_move_mark");
pmark->position = pbuf->cur - pbuf->buf;
}
@@ -7308,24 +7429,44 @@ cpp_print_file_and_line (pfile)
}
}
-void
-cpp_error (pfile, msg, arg1, arg2, arg3)
- cpp_reader *pfile;
- char *msg;
- char *arg1, *arg2, *arg3;
+static void
+v_cpp_error (pfile, msg, ap)
+ cpp_reader *pfile;
+ const char *msg;
+ va_list ap;
{
cpp_print_containing_files (pfile);
cpp_print_file_and_line (pfile);
- cpp_message (pfile, 1, msg, arg1, arg2, arg3);
+ v_cpp_message (pfile, 1, msg, ap);
+}
+
+void
+cpp_error VPROTO ((cpp_reader * pfile, const char *msg, ...))
+{
+#ifndef __STDC__
+ cpp_reader *pfile;
+ const char *msg;
+#endif
+ va_list ap;
+
+ VA_START(ap, msg);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ msg = va_arg (ap, const char *);
+#endif
+
+ v_cpp_error (pfile, msg, ap);
+ va_end(ap);
}
/* Print error message but don't count it. */
-void
-cpp_warning (pfile, msg, arg1, arg2, arg3)
- cpp_reader *pfile;
- char *msg;
- char *arg1, *arg2, *arg3;
+static void
+v_cpp_warning (pfile, msg, ap)
+ cpp_reader *pfile;
+ const char *msg;
+ va_list ap;
{
if (CPP_OPTIONS (pfile)->inhibit_warnings)
return;
@@ -7335,31 +7476,62 @@ cpp_warning (pfile, msg, arg1, arg2, arg3)
cpp_print_containing_files (pfile);
cpp_print_file_and_line (pfile);
- cpp_message (pfile, 0, msg, arg1, arg2, arg3);
+ v_cpp_message (pfile, 0, msg, ap);
+}
+
+void
+cpp_warning VPROTO ((cpp_reader * pfile, const char *msg, ...))
+{
+#ifndef __STDC__
+ cpp_reader *pfile;
+ const char *msg;
+#endif
+ va_list ap;
+
+ VA_START (ap, msg);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ msg = va_arg (ap, const char *);
+#endif
+
+ v_cpp_warning (pfile, msg, ap);
+ va_end(ap);
}
/* Print an error message and maybe count it. */
void
-cpp_pedwarn (pfile, msg, arg1, arg2, arg3)
- cpp_reader *pfile;
- char *msg;
- char *arg1, *arg2, *arg3;
+cpp_pedwarn VPROTO ((cpp_reader * pfile, const char *msg, ...))
{
+#ifndef __STDC__
+ cpp_reader *pfile;
+ const char *msg;
+#endif
+ va_list ap;
+
+ VA_START (ap, msg);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ msg = va_arg (ap, const char *);
+#endif
+
if (CPP_OPTIONS (pfile)->pedantic_errors)
- cpp_error (pfile, msg, arg1, arg2, arg3);
+ v_cpp_error (pfile, msg, ap);
else
- cpp_warning (pfile, msg, arg1, arg2, arg3);
+ v_cpp_warning (pfile, msg, ap);
+ va_end(ap);
}
-void
-cpp_error_with_line (pfile, line, column, msg, arg1, arg2, arg3)
- cpp_reader *pfile;
- int line, column;
- char *msg;
- char *arg1, *arg2, *arg3;
+static void
+v_cpp_error_with_line (pfile, line, column, msg, ap)
+ cpp_reader * pfile;
+ int line;
+ int column;
+ const char * msg;
+ va_list ap;
{
- int i;
cpp_buffer *ip = cpp_file_buffer (pfile);
cpp_print_containing_files (pfile);
@@ -7367,17 +7539,41 @@ cpp_error_with_line (pfile, line, column, msg, arg1, arg2, arg3)
if (ip != NULL)
cpp_file_line_for_message (pfile, ip->nominal_fname, line, column);
- cpp_message (pfile, 1, msg, arg1, arg2, arg3);
+ v_cpp_message (pfile, 1, msg, ap);
+}
+
+void
+cpp_error_with_line VPROTO ((cpp_reader * pfile, int line, int column, const char *msg, ...))
+{
+#ifndef __STDC__
+ cpp_reader *pfile;
+ int line;
+ int column;
+ const char *msg;
+#endif
+ va_list ap;
+
+ VA_START (ap, msg);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ line = va_arg (ap, int);
+ column = va_arg (ap, int);
+ msg = va_arg (ap, const char *);
+#endif
+
+ v_cpp_error_with_line(pfile, line, column, msg, ap);
+ va_end(ap);
}
static void
-cpp_warning_with_line (pfile, line, column, msg, arg1, arg2, arg3)
- cpp_reader *pfile;
- int line, column;
- char *msg;
- char *arg1, *arg2, *arg3;
+v_cpp_warning_with_line (pfile, line, column, msg, ap)
+ cpp_reader * pfile;
+ int line;
+ int column;
+ const char *msg;
+ va_list ap;
{
- int i;
cpp_buffer *ip;
if (CPP_OPTIONS (pfile)->inhibit_warnings)
@@ -7393,68 +7589,98 @@ cpp_warning_with_line (pfile, line, column, msg, arg1, arg2, arg3)
if (ip != NULL)
cpp_file_line_for_message (pfile, ip->nominal_fname, line, column);
- cpp_message (pfile, 0, msg, arg1, arg2, arg3);
+ v_cpp_message (pfile, 0, msg, ap);
+}
+
+#if 0
+static void
+cpp_warning_with_line VPROTO ((cpp_reader * pfile, int line, int column, const char *msg, ...))
+{
+#ifndef __STDC__
+ cpp_reader *pfile;
+ int line;
+ int column;
+ const char *msg;
+#endif
+ va_list ap;
+
+ VA_START (ap, msg);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ line = va_arg (ap, int);
+ column = va_arg (ap, int);
+ msg = va_arg (ap, const char *);
+#endif
+
+ v_cpp_warning_with_line (pfile, line, column, msg, ap);
+ va_end(ap);
}
+#endif
void
-cpp_pedwarn_with_line (pfile, line, column, msg, arg1, arg2, arg3)
- cpp_reader *pfile;
- int line;
- char *msg;
- char *arg1, *arg2, *arg3;
+cpp_pedwarn_with_line VPROTO ((cpp_reader * pfile, int line, int column, const char *msg, ...))
{
+#ifndef __STDC__
+ cpp_reader *pfile;
+ int line;
+ int column;
+ const char *msg;
+#endif
+ va_list ap;
+
+ VA_START (ap, msg);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ line = va_arg (ap, int);
+ column = va_arg (ap, int);
+ msg = va_arg (ap, const char *);
+#endif
+
if (CPP_OPTIONS (pfile)->pedantic_errors)
- cpp_error_with_line (pfile, column, line, msg, arg1, arg2, arg3);
+ v_cpp_error_with_line (pfile, column, line, msg, ap);
else
- cpp_warning_with_line (pfile, line, column, msg, arg1, arg2, arg3);
+ v_cpp_warning_with_line (pfile, line, column, msg, ap);
+ va_end(ap);
}
/* Report a warning (or an error if pedantic_errors)
giving specified file name and line number, not current. */
void
-cpp_pedwarn_with_file_and_line (pfile, file, line, msg, arg1, arg2, arg3)
- cpp_reader *pfile;
- char *file;
- int line;
- char *msg;
- char *arg1, *arg2, *arg3;
+cpp_pedwarn_with_file_and_line VPROTO ((cpp_reader *pfile, char *file, int line, const char *msg, ...))
{
+#ifndef __STDC__
+ cpp_reader *pfile;
+ char *file;
+ int line;
+ const char *msg;
+#endif
+ va_list ap;
+
+ VA_START (ap, msg);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ file = va_arg (ap, char *);
+ line = va_arg (ap, int);
+ msg = va_arg (ap, const char *);
+#endif
+
if (!CPP_OPTIONS (pfile)->pedantic_errors
&& CPP_OPTIONS (pfile)->inhibit_warnings)
return;
if (file != NULL)
cpp_file_line_for_message (pfile, file, line, -1);
- cpp_message (pfile, CPP_OPTIONS (pfile)->pedantic_errors,
- msg, arg1, arg2, arg3);
+ v_cpp_message (pfile, CPP_OPTIONS (pfile)->pedantic_errors, msg, ap);
+ va_end(ap);
}
-/* This defines "errno" properly for VMS, and gives us EACCES. */
-#include <errno.h>
-#ifndef errno
-extern int errno;
-#endif
-
-#ifndef VMS
-#ifndef HAVE_STRERROR
-extern int sys_nerr;
-#if defined(bsd4_4)
-extern const char *const sys_errlist[];
-#else
-extern char *sys_errlist[];
-#endif
-#else /* HAVE_STRERROR */
-char *strerror ();
-#endif
-#else /* VMS */
-char *strerror (int,...);
-#endif
-
-/*
- * my_strerror - return the descriptive text associated with an `errno' code.
- */
+/* my_strerror - return the descriptive text associated with an
+ `errno' code. */
-char *
+static char *
my_strerror (errnum)
int errnum;
{
@@ -7488,9 +7714,18 @@ my_strerror (errnum)
void
cpp_error_from_errno (pfile, name)
cpp_reader *pfile;
- char *name;
+ const char *name;
{
- int i;
+ cpp_message_from_errno (pfile, 1, name);
+}
+
+void
+cpp_message_from_errno (pfile, is_error, name)
+ cpp_reader *pfile;
+ int is_error;
+ const char *name;
+{
+ int e = errno;
cpp_buffer *ip = cpp_file_buffer (pfile);
cpp_print_containing_files (pfile);
@@ -7498,13 +7733,13 @@ cpp_error_from_errno (pfile, name)
if (ip != NULL)
cpp_file_line_for_message (pfile, ip->nominal_fname, ip->lineno, -1);
- cpp_message (pfile, 1, "%s: %s", name, my_strerror (errno));
+ cpp_message (pfile, is_error, "%s: %s", name, my_strerror (e));
}
void
cpp_perror_with_name (pfile, name)
cpp_reader *pfile;
- char *name;
+ const char *name;
{
cpp_message (pfile, 1, "%s: %s: %s", progname, name, my_strerror (errno));
}
diff --git a/contrib/gcc/cpplib.h b/contrib/gcc/cpplib.h
index 3075b79..65cb5da 100644
--- a/contrib/gcc/cpplib.h
+++ b/contrib/gcc/cpplib.h
@@ -1,5 +1,5 @@
/* Definitions for CPP library.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Written by Per Bothner, 1994-95.
This program is free software; you can redistribute it and/or modify it
@@ -22,16 +22,18 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <sys/types.h>
#include <sys/stat.h>
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
#ifdef __cplusplus
extern "C" {
#endif
-#define STATIC_BUFFERS
-
typedef unsigned char U_CHAR;
-struct parse_file;
typedef struct cpp_reader cpp_reader;
typedef struct cpp_buffer cpp_buffer;
typedef struct cpp_options cpp_options;
@@ -72,15 +74,11 @@ enum cpp_token {
};
#ifndef PARAMS
-#ifdef __STDC
-#define PARAMS(P) P
-#else
-#define PARAMS(P) ()
-#endif
+#define PARAMS(P) PROTO(P)
#endif /* !PARAMS */
-typedef enum cpp_token (*parse_underflow_t) PARAMS((cpp_reader*));
-typedef int (*parse_cleanup_t) PARAMS((cpp_buffer *, cpp_reader*));
+typedef enum cpp_token (*parse_underflow_t) PARAMS((cpp_reader *));
+typedef int (*parse_cleanup_t) PARAMS((cpp_buffer *, cpp_reader *));
/* A parse_marker indicates a previous position,
which we can backtrack to. */
@@ -91,16 +89,19 @@ struct parse_marker {
int position;
};
-extern void parse_set_mark PARAMS ((struct parse_marker*, cpp_reader*));
-extern void parse_clear_mark PARAMS ((struct parse_marker*));
-extern void parse_goto_mark PARAMS((struct parse_marker*, cpp_reader*));
-extern void parse_move_mark PARAMS((struct parse_marker*, cpp_reader*));
+extern void parse_set_mark PARAMS ((struct parse_marker *, cpp_reader *));
+extern void parse_clear_mark PARAMS ((struct parse_marker *));
+extern void parse_goto_mark PARAMS((struct parse_marker *, cpp_reader *));
+extern void parse_move_mark PARAMS((struct parse_marker *, cpp_reader *));
-extern int cpp_handle_options PARAMS ((cpp_reader*, int, char**));
-extern enum cpp_token cpp_get_token PARAMS ((struct parse_marker*));
-extern void cpp_skip_hspace PARAMS((cpp_reader*));
+extern int cpp_handle_option PARAMS ((cpp_reader *, int, char **));
+extern int cpp_handle_options PARAMS ((cpp_reader *, int, char **));
+extern enum cpp_token cpp_get_token PARAMS ((cpp_reader *));
+extern void cpp_skip_hspace PARAMS((cpp_reader *));
extern enum cpp_token cpp_get_non_space_token PARAMS ((cpp_reader *));
+/* This frees resources used by PFILE. */
+extern void cpp_cleanup PARAMS ((cpp_reader *PFILE));
/* Maintain and search list of included files, for #import. */
@@ -134,9 +135,6 @@ struct cpp_buffer {
long line_base;
long lineno; /* Line number at CPP_LINE_BASE. */
long colno; /* Column number at CPP_LINE_BASE. */
-#ifndef STATIC_BUFFERS
- cpp_buffer *chain;
-#endif
parse_underflow_t underflow;
parse_cleanup_t cleanup;
void *data;
@@ -150,7 +148,7 @@ struct cpp_buffer {
char seen_eof;
/* True if buffer contains escape sequences.
- Currently there are are only two kind:
+ Currently there are three kinds:
"@-" means following identifier should not be macro-expanded.
"@ " means a token-separator. This turns into " " in final output
if not stringizing and needed to separate tokens; otherwise nothing.
@@ -165,25 +163,28 @@ struct file_name_map_list;
typedef struct assertion_hashnode ASSERTION_HASHNODE;
#define ASSERTION_HASHSIZE 37
-#ifdef STATIC_BUFFERS
/* Maximum nesting of cpp_buffers. We use a static limit, partly for
efficiency, and partly to limit runaway recursion. */
#define CPP_STACK_MAX 200
-#endif
+
+/* A cpp_reader encapsulates the "state" of a pre-processor run.
+ Applying cpp_get_token repeatedly yields a stream of pre-processor
+ tokens. Usually, there is only one cpp_reader object active. */
struct cpp_reader {
- unsigned char *limit;
parse_underflow_t get_token;
cpp_buffer *buffer;
-#ifdef STATIC_BUFFERS
cpp_buffer buffer_stack[CPP_STACK_MAX];
-#endif
int errors; /* Error counter for exit code */
void *data;
- U_CHAR *token_buffer;
+ /* A buffer used for both for cpp_get_token's output, and also internally. */
+ unsigned char *token_buffer;
+ /* Allocated size of token_buffer. CPP_RESERVE allocates space. */
int token_buffer_size;
+ /* End of the written part of token_buffer. */
+ unsigned char *limit;
/* Line where a newline was first seen in a string constant. */
int multiline_string_line;
@@ -260,14 +261,26 @@ struct cpp_reader {
/* Number of bytes since the last newline. */
int deps_column;
+
+#ifdef __cplusplus
+ ~cpp_reader () { cpp_cleanup (this); }
+#endif
};
+#define CPP_FATAL_LIMIT 1000
+/* True if we have seen a "fatal" error. */
+#define CPP_FATAL_ERRORS(READER) ((READER)->errors >= CPP_FATAL_LIMIT)
+
#define CPP_BUF_PEEK(BUFFER) \
((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur : EOF)
#define CPP_BUF_GET(BUFFER) \
((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur++ : EOF)
#define CPP_FORWARD(BUFFER, N) ((BUFFER)->cur += (N))
+/* Macros for manipulating the token_buffer. */
+
+#define CPP_OUT_BUFFER(PFILE) ((PFILE)->token_buffer)
+
/* Number of characters currently in PFILE's output buffer. */
#define CPP_WRITTEN(PFILE) ((PFILE)->limit - (PFILE)->token_buffer)
#define CPP_PWRITTEN(PFILE) ((PFILE)->limit)
@@ -293,17 +306,14 @@ struct cpp_reader {
#define CPP_ADJUST_WRITTEN(PFILE,DELTA) ((PFILE)->limit += (DELTA))
#define CPP_SET_WRITTEN(PFILE,N) ((PFILE)->limit = (PFILE)->token_buffer + (N))
-#define CPP_OPTIONS(PFILE) ((cpp_options*)(PFILE)->data)
+#define CPP_OPTIONS(PFILE) ((cpp_options *) (PFILE)->data)
+
#define CPP_BUFFER(PFILE) ((PFILE)->buffer)
-#ifdef STATIC_BUFFERS
#define CPP_PREV_BUFFER(BUFFER) ((BUFFER)+1)
+/* The bottom of the buffer stack. */
#define CPP_NULL_BUFFER(PFILE) (&(PFILE)->buffer_stack[CPP_STACK_MAX])
-#else
-#define CPP_PREV_BUFFER(BUFFER) ((BUFFER)->chain)
-#define CPP_NULL_BUFFER(PFILE) ((cpp_buffer*)0)
-#endif
-/* Pointed to by parse_file::data. */
+/* Pointed to by cpp_reader::data. */
struct cpp_options {
char *in_fname;
@@ -402,6 +412,10 @@ struct cpp_options {
char no_output;
+ /* Nonzero means we should look for header.gcc files that remap file
+ names. */
+ char remap;
+
/* Nonzero means don't output line number information. */
char no_line_commands;
@@ -415,21 +429,20 @@ struct cpp_options {
so don't look for #include "foo" the source-file directory. */
char ignore_srcdir;
-/* Zero means dollar signs are punctuation.
- -$ stores 0; -traditional may store 1. Default is 1 for VMS, 0 otherwise.
- This must be 0 for correct processing of this ANSI C program:
- #define foo(a) #a
- #define lose(b) foo (b)
- #define test$
- lose (test) */
+ /* Zero means dollar signs are punctuation.
+ This used to be needed for conformance to the C Standard,
+ before the C Standard was corrected. */
char dollars_in_ident;
-#ifndef DOLLARS_IN_IDENTIFIERS
-#define DOLLARS_IN_IDENTIFIERS 1
-#endif
/* Nonzero means try to imitate old fashioned non-ANSI preprocessor. */
char traditional;
+ /* Nonzero means warn if undefined identifiers are evaluated in an #if. */
+ char warn_undef;
+
+ /* Nonzero for the 1989 C Standard, including corrigenda and amendments. */
+ char c89;
+
/* Nonzero means give all the error messages the ANSI standard requires. */
char pedantic;
@@ -479,6 +492,10 @@ struct cpp_options {
where they are defined. */
int debug_output;
+ /* Nonzero means pass #include lines through to the output,
+ even if they are ifdefed out. */
+ int dump_includes;
+
/* Pending -D, -U and -A options, in reverse order. */
struct cpp_pending *pending;
@@ -491,6 +508,8 @@ struct cpp_options {
};
#define CPP_TRADITIONAL(PFILE) (CPP_OPTIONS(PFILE)-> traditional)
+#define CPP_WARN_UNDEF(PFILE) (CPP_OPTIONS(PFILE)->warn_undef)
+#define CPP_C89(PFILE) (CPP_OPTIONS(PFILE)->c89)
#define CPP_PEDANTIC(PFILE) (CPP_OPTIONS (PFILE)->pedantic)
#define CPP_PRINT_DEPS(PFILE) (CPP_OPTIONS (PFILE)->print_deps)
@@ -551,7 +570,7 @@ typedef struct macrodef MACRODEF;
struct macrodef
{
struct definition *defn;
- U_CHAR *symnam;
+ unsigned char *symnam;
int symlen;
};
@@ -582,7 +601,7 @@ struct definition {
int length; /* length of expansion string */
int predefined; /* True if the macro was builtin or */
/* came from the command line */
- U_CHAR *expansion;
+ unsigned char *expansion;
int line; /* Line number of definition */
char *file; /* File of definition */
char rest_args; /* Nonzero if last arg. absorbs the rest */
@@ -602,11 +621,11 @@ struct definition {
with comma-space between them.
The only use of this is that we warn on redefinition
if this differs between the old and new definitions. */
- U_CHAR *argnames;
+ unsigned char *argnames;
} args;
};
-extern U_CHAR is_idchar[256];
+extern unsigned char is_idchar[256];
/* Stack of conditionals currently in progress
(including both successful and failing conditionals). */
@@ -617,34 +636,57 @@ struct if_stack {
int lineno; /* similarly */
int if_succeeded; /* true if a leg of this if-group
has been passed through rescan */
- U_CHAR *control_macro; /* For #ifndef at start of file,
+ unsigned char *control_macro; /* For #ifndef at start of file,
this is the macro name tested. */
enum node_type type; /* type of last directive seen in this group */
};
typedef struct if_stack IF_STACK_FRAME;
-extern void cpp_buf_line_and_col PARAMS((cpp_buffer*, long*, long*));
-extern cpp_buffer* cpp_file_buffer PARAMS((cpp_reader*));
-extern void cpp_define PARAMS ((cpp_reader*, U_CHAR*));
-
-extern void cpp_error ();
-extern void cpp_warning ();
-extern void cpp_pedwarn ();
-extern void cpp_error_with_line ();
-extern void cpp_pedwarn_with_line ();
-extern void cpp_pedwarn_with_file_and_line ();
-extern void fatal ();
-extern void cpp_error_from_errno ();
-extern void cpp_perror_with_name ();
-extern void cpp_pfatal_with_name ();
-
-extern void cpp_grow_buffer PARAMS ((cpp_reader*, long));
-extern int cpp_parse_escape PARAMS ((cpp_reader*, char**));
-extern cpp_buffer* cpp_push_buffer PARAMS ((cpp_reader *, U_CHAR*, long));
-extern cpp_buffer* cpp_pop_buffer PARAMS ((cpp_reader *));
-
-extern cpp_hashnode* cpp_lookup PARAMS ((cpp_reader*, const U_CHAR*,
+extern void cpp_buf_line_and_col PARAMS((cpp_buffer *, long *, long *));
+extern cpp_buffer* cpp_file_buffer PARAMS((cpp_reader *));
+extern void cpp_define PARAMS ((cpp_reader*, unsigned char *));
+
+extern void cpp_error PVPROTO ((cpp_reader *, const char *, ...))
+ ATTRIBUTE_PRINTF_2;
+extern void cpp_warning PVPROTO ((cpp_reader *, const char *, ...))
+ ATTRIBUTE_PRINTF_2;
+extern void cpp_pedwarn PVPROTO ((cpp_reader *, const char *, ...))
+ ATTRIBUTE_PRINTF_2;
+extern void cpp_error_with_line PVPROTO ((cpp_reader *, int, int, const char *, ...))
+ ATTRIBUTE_PRINTF_4;
+extern void cpp_pedwarn_with_line PVPROTO ((cpp_reader *, int, int, const char *, ...))
+ ATTRIBUTE_PRINTF_4;
+extern void cpp_pedwarn_with_file_and_line PVPROTO ((cpp_reader *, char *, int, const char *, ...))
+ ATTRIBUTE_PRINTF_4;
+extern void cpp_message_from_errno PROTO ((cpp_reader *, int, const char *));
+extern void cpp_error_from_errno PROTO ((cpp_reader *, const char *));
+extern void cpp_perror_with_name PROTO ((cpp_reader *, const char *));
+extern void v_cpp_message PROTO ((cpp_reader *, int, const char *, va_list));
+
+extern void cpp_grow_buffer PARAMS ((cpp_reader *, long));
+extern int cpp_parse_escape PARAMS ((cpp_reader *, char **));
+extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *,
+ unsigned char *, long));
+extern cpp_buffer *cpp_pop_buffer PARAMS ((cpp_reader *));
+
+extern cpp_hashnode *cpp_lookup PARAMS ((cpp_reader *, const unsigned char *,
int, int));
+extern void cpp_reader_init PARAMS ((cpp_reader *));
+extern void cpp_options_init PARAMS ((cpp_options *));
+extern int cpp_start_read PARAMS ((cpp_reader *, char *));
+extern int cpp_read_check_assertion PARAMS ((cpp_reader *));
+extern int scan_decls PARAMS ((cpp_reader *, int, char **));
+extern void skip_rest_of_line PARAMS ((cpp_reader *));
+extern void cpp_finish PARAMS ((cpp_reader *));
+
+/* From cpperror.c */
+extern void cpp_fatal PVPROTO ((cpp_reader *, const char *, ...))
+ ATTRIBUTE_PRINTF_2;
+extern void cpp_message PVPROTO ((cpp_reader *, int, const char *, ...))
+ ATTRIBUTE_PRINTF_3;
+extern void cpp_pfatal_with_name PROTO ((cpp_reader *, const char *));
+extern void cpp_file_line_for_message PROTO ((cpp_reader *, char *, int, int));
+extern void cpp_print_containing_files PROTO ((cpp_reader *));
#ifdef __cplusplus
}
diff --git a/contrib/gcc/cppmain.c b/contrib/gcc/cppmain.c
index 506ce05..0a45e86 100644
--- a/contrib/gcc/cppmain.c
+++ b/contrib/gcc/cppmain.c
@@ -1,5 +1,5 @@
/* CPP main program, using CPP Library.
- Copyright (C) 1995 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1997 Free Software Foundation, Inc.
Written by Per Bothner, 1994-95.
This program is free software; you can redistribute it and/or modify it
@@ -20,28 +20,40 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding! */
-#include "cpplib.h"
-#include <stdio.h>
-
#ifndef EMACS
#include "config.h"
-#endif /* not EMACS */
+#include "system.h"
+#include "gansidecl.h"
+#else
+#include <stdio.h>
extern char *getenv ();
+#endif /* not EMACS */
+
+#include "cpplib.h"
char *progname;
cpp_reader parse_in;
cpp_options options;
+#ifdef abort
/* More 'friendly' abort that prints the line and file.
config.h can #define abort fancy_abort if you like that sort of thing. */
+void
+fatal (s)
+ char *s;
+{
+ fputs (s, stderr);
+ exit (FATAL_EXIT_CODE);
+}
void
fancy_abort ()
{
fatal ("Internal gcc abort.");
}
+#endif
int
@@ -50,27 +62,28 @@ main (argc, argv)
char **argv;
{
char *p;
- int i;
- int argi = 1; /* Next argument to handle. */
+ int argi = 1; /* Next argument to handle. */
struct cpp_options *opts = &options;
p = argv[0] + strlen (argv[0]);
while (p != argv[0] && p[-1] != '/') --p;
progname = p;
- init_parse_file (&parse_in);
+ cpp_reader_init (&parse_in);
parse_in.data = opts;
- init_parse_options (opts);
+ cpp_options_init (opts);
argi += cpp_handle_options (&parse_in, argc - argi , argv + argi);
- if (argi < argc)
- fatal ("Invalid option `%s'", argv[argi]);
+ if (argi < argc && ! CPP_FATAL_ERRORS (&parse_in))
+ cpp_fatal (&parse_in, "Invalid option `%s'", argv[argi]);
+ if (CPP_FATAL_ERRORS (&parse_in))
+ exit (FATAL_EXIT_CODE);
+
parse_in.show_column = 1;
- i = push_parse_file (&parse_in, opts->in_fname);
- if (i != SUCCESS_EXIT_CODE)
- return i;
+ if (! cpp_start_read (&parse_in, opts->in_fname))
+ exit (FATAL_EXIT_CODE);
/* Now that we know the input file is valid, open the output. */
@@ -86,7 +99,7 @@ main (argc, argv)
{
fwrite (parse_in.token_buffer, 1, CPP_WRITTEN (&parse_in), stdout);
}
- parse_in.limit = parse_in.token_buffer;
+ CPP_SET_WRITTEN (&parse_in, 0);
kind = cpp_get_token (&parse_in);
if (kind == CPP_EOF)
break;
diff --git a/contrib/gcc/cross-make b/contrib/gcc/cross-make
index 33bf930..810f505 100644
--- a/contrib/gcc/cross-make
+++ b/contrib/gcc/cross-make
@@ -12,7 +12,8 @@ RANLIB = $(RANLIB_FOR_TARGET)
RANLIB_TEST = $(RANLIB_TEST_FOR_TARGET)
# Dir to search for system headers. Normally /usr/include.
-SYSTEM_HEADER_DIR = $(tooldir)/include
+# Use CROSS_INCLUDE_DIR not TOOL_INCLUDE_DIR for other vendor's headers.
+SYSTEM_HEADER_DIR = $(tooldir)/sys-include
# Don't try to compile the things we can't compile.
ALL = all.cross
@@ -22,6 +23,3 @@ FLOAT_H = $(CROSS_FLOAT_H)
# Don't install assert.h in /usr/local/include.
assertdir = $(tooldir)/include
-
-# Don't run fixproto
-STMP_FIXPROTO =
diff --git a/contrib/gcc/crtstuff.c b/contrib/gcc/crtstuff.c
index 8bd3b1a..a1b9ef8 100644
--- a/contrib/gcc/crtstuff.c
+++ b/contrib/gcc/crtstuff.c
@@ -1,9 +1,7 @@
/* Specialized bits of code needed to support construction and
destruction of file-scope objects in C++ code.
-
- Written by Ron Guilmette (rfg@netcom.com) with help from Richard Stallman.
-
-Copyright (C) 1991, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1991, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
+ Contributed by Ron Guilmette (rfg@monkeys.com).
This file is part of GNU CC.
@@ -54,6 +52,48 @@ Boston, MA 02111-1307, USA. */
do not apply. */
#include "tm.h"
+#include "defaults.h"
+#include <stddef.h>
+#include "frame.h"
+
+/* This really belongs in gansidecl.h, but for the egcs-1.1.x branch, the
+ only code which uses weak attributes is in this file and this file does
+ not include gansidecl.h. */
+#ifndef TARGET_ATTRIBUTE_WEAK
+# if SUPPORTS_WEAK
+# define TARGET_ATTRIBUTE_WEAK __attribute__ ((weak))
+# else
+# define TARGET_ATTRIBUTE_WEAK
+# endif
+#endif
+
+/* We do not want to add the weak attribute to the declarations of these
+ routines in frame.h because that will cause the definition of these
+ symbols to be weak as well.
+
+ This exposes a core issue, how to handle creating weak references vs
+ how to create weak definitions. Either we have to have the definition
+ of TARGET_WEAK_ATTRIBUTE be conditional in the shared header files or
+ have a second declaration if we want a function's references to be weak,
+ but not its definition.
+
+ Making TARGET_WEAK_ATTRIBUTE conditional seems like a good solution until
+ one thinks about scaling to larger problems -- ie, the condition under
+ which TARGET_WEAK_ATTRIBUTE is active will eventually get far too
+ complicated.
+
+ So, we take an approach similar to #pragma weak -- we have a second
+ declaration for functions that we want to have weak references.
+
+ Neither way is particularly good. */
+
+/* References to __register_frame_info and __deregister_frame_info should
+ be weak in this file if at all possible. */
+extern void __register_frame_info (void *, struct object *)
+ TARGET_ATTRIBUTE_WEAK;
+
+extern void *__deregister_frame_info (void *)
+ TARGET_ATTRIBUTE_WEAK;
/* Provide default definitions for the pseudo-ops used to switch to the
.ctors and .dtors sections.
@@ -77,6 +117,9 @@ Boston, MA 02111-1307, USA. */
#ifndef DTORS_SECTION_ASM_OP
#define DTORS_SECTION_ASM_OP ".section\t.dtors,\"aw\""
#endif
+#if !defined (EH_FRAME_SECTION_ASM_OP) && defined (DWARF2_UNWIND_INFO) && defined(ASM_OUTPUT_SECTION_NAME)
+#define EH_FRAME_SECTION_ASM_OP ".section\t.eh_frame,\"aw\""
+#endif
#ifdef OBJECT_FORMAT_ELF
@@ -113,19 +156,41 @@ typedef void (*func_ptr) (void);
functions in each root executable and one in each shared library, but
although they all have the same code, each one is unique in that it
refers to one particular associated `__DTOR_LIST__' which belongs to the
- same particular root executable or shared library file. */
+ same particular root executable or shared library file.
+ On some systems, this routine is run more than once from the .fini,
+ when exit is called recursively, so we arrange to remember where in
+ the list we left off processing, and we resume at that point,
+ should we be re-invoked. */
+
+static char __EH_FRAME_BEGIN__[];
static func_ptr __DTOR_LIST__[];
static void
__do_global_dtors_aux ()
{
- func_ptr *p;
- for (p = __DTOR_LIST__ + 1; *p; p++)
- (*p) ();
+ static func_ptr *p = __DTOR_LIST__ + 1;
+ static int completed = 0;
+
+ if (completed)
+ return;
+
+ while (*p)
+ {
+ p++;
+ (*(p-1)) ();
+ }
+
+#ifdef EH_FRAME_SECTION_ASM_OP
+ if (__deregister_frame_info)
+ __deregister_frame_info (__EH_FRAME_BEGIN__);
+#endif
+ completed = 1;
}
+
/* Stick a call to __do_global_dtors_aux into the .fini section. */
-static void
+
+static void __attribute__ ((__unused__))
fini_dummy ()
{
asm (FINI_SECTION_ASM_OP);
@@ -136,6 +201,31 @@ fini_dummy ()
asm (TEXT_SECTION_ASM_OP);
}
+#ifdef EH_FRAME_SECTION_ASM_OP
+/* Stick a call to __register_frame_info into the .init section. For some
+ reason calls with no arguments work more reliably in .init, so stick the
+ call in another function. */
+
+static void
+frame_dummy ()
+{
+ static struct object object;
+ if (__register_frame_info)
+ __register_frame_info (__EH_FRAME_BEGIN__, &object);
+}
+
+static void __attribute__ ((__unused__))
+init_dummy ()
+{
+ asm (INIT_SECTION_ASM_OP);
+ frame_dummy ();
+#ifdef FORCE_INIT_SECTION_ALIGN
+ FORCE_INIT_SECTION_ALIGN;
+#endif
+ asm (TEXT_SECTION_ASM_OP);
+}
+#endif /* EH_FRAME_SECTION_ASM_OP */
+
#else /* OBJECT_FORMAT_ELF */
/* The function __do_global_ctors_aux is compiled twice (once in crtbegin.o
@@ -144,6 +234,7 @@ fini_dummy ()
function. It is externally callable so that __main can invoke it when
INVOKE__main is defined. This has the additional effect of forcing cc1
to switch to the .text section. */
+
static void __do_global_ctors_aux ();
void __do_global_ctors ()
{
@@ -163,7 +254,7 @@ asm (INIT_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */
crti.o may do something, such as bump the stack, which we have to
undo before we reach the function prologue code for __do_global_ctors
(directly below). For such systems, define the macro INIT_SECTION_PREAMBLE
- to expand into the code needed to undo the actions of the crti.o file. */
+ to expand into the code needed to undo the actions of the crti.o file. */
#ifdef INIT_SECTION_PREAMBLE
INIT_SECTION_PREAMBLE;
@@ -186,10 +277,47 @@ __do_global_ctors_aux () /* prologue goes in .init section */
}
#endif /* OBJECT_FORMAT_ELF */
+
+#else /* defined(INIT_SECTION_ASM_OP) */
+
+#ifdef HAS_INIT_SECTION
+/* This case is used by the Irix 6 port, which supports named sections but
+ not an SVR4-style .fini section. __do_global_dtors can be non-static
+ in this case because we protect it with -hidden_symbol. */
+
+static char __EH_FRAME_BEGIN__[];
+static func_ptr __DTOR_LIST__[];
+void
+__do_global_dtors ()
+{
+ func_ptr *p;
+ for (p = __DTOR_LIST__ + 1; *p; p++)
+ (*p) ();
+
+#ifdef EH_FRAME_SECTION_ASM_OP
+ if (__deregister_frame_info)
+ __deregister_frame_info (__EH_FRAME_BEGIN__);
+#endif
+}
+
+#ifdef EH_FRAME_SECTION_ASM_OP
+/* Define a function here to call __register_frame. crtend.o is linked in
+ after libgcc.a, and hence can't call libgcc.a functions directly. That
+ can lead to unresolved function references. */
+void
+__frame_dummy ()
+{
+ static struct object object;
+ if (__register_frame_info)
+ __register_frame_info (__EH_FRAME_BEGIN__, &object);
+}
+#endif
+#endif
+
#endif /* defined(INIT_SECTION_ASM_OP) */
/* Force cc1 to switch to .data section. */
-static func_ptr force_to_data[0] = { };
+static func_ptr force_to_data[0] __attribute__ ((__unused__)) = { };
/* NOTE: In order to be able to support SVR4 shared libraries, we arrange
to have one set of symbols { __CTOR_LIST__, __DTOR_LIST__, __CTOR_END__,
@@ -209,7 +337,8 @@ static func_ptr force_to_data[0] = { };
CTOR_LIST_BEGIN;
#else
asm (CTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */
-STATIC func_ptr __CTOR_LIST__[1] = { (func_ptr) (-1) };
+STATIC func_ptr __CTOR_LIST__[1] __attribute__ ((__unused__))
+ = { (func_ptr) (-1) };
#endif
#ifdef DTOR_LIST_BEGIN
@@ -219,6 +348,17 @@ asm (DTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */
STATIC func_ptr __DTOR_LIST__[1] = { (func_ptr) (-1) };
#endif
+#ifdef EH_FRAME_SECTION_ASM_OP
+/* Stick a label at the beginning of the frame unwind info so we can register
+ and deregister it with the exception handling library code. */
+
+asm (EH_FRAME_SECTION_ASM_OP);
+#ifdef INIT_SECTION_ASM_OP
+STATIC
+#endif
+char __EH_FRAME_BEGIN__[] = { };
+#endif /* EH_FRAME_SECTION_ASM_OP */
+
#endif /* defined(CRT_BEGIN) */
#ifdef CRT_END
@@ -237,7 +377,8 @@ __do_global_ctors_aux ()
}
/* Stick a call to __do_global_ctors_aux into the .init section. */
-static void
+
+static void __attribute__ ((__unused__))
init_dummy ()
{
asm (INIT_SECTION_ASM_OP);
@@ -247,12 +388,12 @@ init_dummy ()
#endif
asm (TEXT_SECTION_ASM_OP);
-/* This is a kludge. The Linux dynamic linker needs ___brk_addr, __environ
- and atexit (). We have to make sure they are in the .dynsym section. We
- accomplish it by making a dummy call here. This
- code is never reached. */
+/* This is a kludge. The i386 GNU/Linux dynamic linker needs ___brk_addr,
+ __environ and atexit (). We have to make sure they are in the .dynsym
+ section. We accomplish it by making a dummy call here. This
+ code is never reached. */
-#if defined(__linux__) && defined(__PIC__)
+#if defined(__linux__) && defined(__PIC__) && defined(__i386__)
{
extern void *___brk_addr;
extern char **__environ;
@@ -284,7 +425,7 @@ init_dummy ()
other libraries, etc. That's because those other initializations may
include setup operations for very primitive things (e.g. initializing
the state of the floating-point coprocessor, etc.) which should be done
- before we start to execute any of the user's code. */
+ before we start to execute any of the user's code. */
static void
__do_global_ctors_aux () /* prologue goes in .text section */
@@ -294,12 +435,40 @@ __do_global_ctors_aux () /* prologue goes in .text section */
ON_EXIT (__do_global_dtors, 0);
} /* epilogue and body go in .init section */
+#ifdef FORCE_INIT_SECTION_ALIGN
+FORCE_INIT_SECTION_ALIGN;
+#endif
+
+asm (TEXT_SECTION_ASM_OP);
+
#endif /* OBJECT_FORMAT_ELF */
+#else /* defined(INIT_SECTION_ASM_OP) */
+
+#ifdef HAS_INIT_SECTION
+/* This case is used by the Irix 6 port, which supports named sections but
+ not an SVR4-style .init section. __do_global_ctors can be non-static
+ in this case because we protect it with -hidden_symbol. */
+static func_ptr __CTOR_END__[];
+#ifdef EH_FRAME_SECTION_ASM_OP
+extern void __frame_dummy (void);
+#endif
+void
+__do_global_ctors ()
+{
+ func_ptr *p;
+#ifdef EH_FRAME_SECTION_ASM_OP
+ __frame_dummy ();
+#endif
+ for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--)
+ (*p) ();
+}
+#endif
+
#endif /* defined(INIT_SECTION_ASM_OP) */
/* Force cc1 to switch to .data section. */
-static func_ptr force_to_data[0] = { };
+static func_ptr force_to_data[0] __attribute__ ((__unused__)) = { };
/* Put a word containing zero at the end of each of our two lists of function
addresses. Note that the words defined here go into the .ctors and .dtors
@@ -318,7 +487,17 @@ STATIC func_ptr __CTOR_END__[1] = { (func_ptr) 0 };
DTOR_LIST_END;
#else
asm (DTORS_SECTION_ASM_OP); /* cc1 doesn't know that we are switching! */
-STATIC func_ptr __DTOR_END__[1] = { (func_ptr) 0 };
+STATIC func_ptr __DTOR_END__[1] __attribute__ ((__unused__))
+ = { (func_ptr) 0 };
#endif
+#ifdef EH_FRAME_SECTION_ASM_OP
+/* Terminate the frame unwind info section with a 4byte 0 as a sentinel;
+ this would be the 'length' field in a real FDE. */
+
+typedef unsigned int ui32 __attribute__ ((mode (SI)));
+asm (EH_FRAME_SECTION_ASM_OP);
+STATIC ui32 __FRAME_END__[] __attribute__ ((__unused__)) = { 0 };
+#endif /* EH_FRAME_SECTION */
+
#endif /* defined(CRT_END) */
diff --git a/contrib/gcc/cse.c b/contrib/gcc/cse.c
index 00c5122..cfcc4fa 100644
--- a/contrib/gcc/cse.c
+++ b/contrib/gcc/cse.c
@@ -1,5 +1,5 @@
/* Common subexpression elimination for GNU compiler.
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,8 +20,9 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
-/* Must precede rtl.h for FFS. */
-#include <stdio.h>
+/* stdio.h must precede rtl.h for FFS. */
+#include "system.h"
+#include <setjmp.h>
#include "rtl.h"
#include "regs.h"
@@ -30,8 +31,9 @@ Boston, MA 02111-1307, USA. */
#include "real.h"
#include "insn-config.h"
#include "recog.h"
-
-#include <setjmp.h>
+#include "expr.h"
+#include "toplev.h"
+#include "output.h"
/* The basic idea of common subexpression elimination is to go
through the code, keeping a record of expressions that would
@@ -192,6 +194,11 @@ Related expressions:
static int max_reg;
+/* One plus largest instruction UID used in this function at time of
+ cse_main call. */
+
+static int max_insn_uid;
+
/* Length of vectors indexed by quantity number.
We know in advance we will not need a quantity number this big. */
@@ -202,7 +209,7 @@ static int max_qty;
static int next_qty;
-/* Indexed by quantity number, gives the first (or last) (pseudo) register
+/* Indexed by quantity number, gives the first (or last) register
in the chain of registers that currently contain this quantity. */
static int *qty_first_reg;
@@ -267,13 +274,13 @@ static rtx prev_insn;
static rtx this_insn;
-/* Index by (pseudo) register number, gives the quantity number
+/* Index by register number, gives the quantity number
of the register's current contents. */
static int *reg_qty;
-/* Index by (pseudo) register number, gives the number of the next (or
- previous) (pseudo) register in the chain of registers sharing the same
+/* Index by register number, gives the number of the next (or
+ previous) register in the chain of registers sharing the same
value.
Or -1 if this register is at the end of the chain.
@@ -283,12 +290,12 @@ static int *reg_qty;
static int *reg_next_eqv;
static int *reg_prev_eqv;
-/* Index by (pseudo) register number, gives the number of times
+/* Index by register number, gives the number of times
that register has been altered in the current basic block. */
static int *reg_tick;
-/* Index by (pseudo) register number, gives the reg_tick value at which
+/* Index by register number, gives the reg_tick value at which
rtx's containing this register are valid in the hash table.
If this does not equal the current reg_tick value, such expressions
existing in the hash table are invalid.
@@ -478,18 +485,28 @@ struct table_elt
((REG_USERVAR_P (N) && REGNO (N) < FIRST_PSEUDO_REGISTER) \
|| CHEAP_REGNO (REGNO (N)))
-#define COST(X) \
- (GET_CODE (X) == REG \
- ? (CHEAP_REG (X) ? 0 \
- : REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1 \
- : 2) \
- : rtx_cost (X, SET) * 2)
+#define COST(X) \
+ (GET_CODE (X) == REG \
+ ? (CHEAP_REG (X) ? 0 \
+ : REGNO (X) >= FIRST_PSEUDO_REGISTER ? 1 \
+ : 2) \
+ : notreg_cost(X))
/* Determine if the quantity number for register X represents a valid index
into the `qty_...' variables. */
#define REGNO_QTY_VALID_P(N) (reg_qty[N] != (N))
+#ifdef ADDRESS_COST
+/* The ADDRESS_COST macro does not deal with ADDRESSOF nodes. But,
+ during CSE, such nodes are present. Using an ADDRESSOF node which
+ refers to the address of a REG is a good thing because we can then
+ turn (MEM (ADDRESSSOF (REG))) into just plain REG. */
+#define CSE_ADDRESS_COST(RTX) \
+ ((GET_CODE (RTX) == ADDRESSOF && REG_P (XEXP ((RTX), 0))) \
+ ? -1 : ADDRESS_COST(RTX))
+#endif
+
static struct table_elt *table[NBUCKETS];
/* Chain of `struct table_elt's made so far for this function
@@ -519,27 +536,6 @@ static struct table_elt *last_jump_equiv_class;
static int constant_pool_entries_cost;
-/* Bits describing what kind of values in memory must be invalidated
- for a particular instruction. If all three bits are zero,
- no memory refs need to be invalidated. Each bit is more powerful
- than the preceding ones, and if a bit is set then the preceding
- bits are also set.
-
- Here is how the bits are set:
- Pushing onto the stack invalidates only the stack pointer,
- writing at a fixed address invalidates only variable addresses,
- writing in a structure element at variable address
- invalidates all but scalar variables,
- and writing in anything else at variable address invalidates everything. */
-
-struct write_data
-{
- int sp : 1; /* Invalidate stack pointer. */
- int var : 1; /* Invalidate variable addresses. */
- int nonscalar : 1; /* Invalidate all but scalar variables. */
- int all : 1; /* Invalidate all memory refs. */
-};
-
/* Define maximum length of a branch path. */
#define PATHLENGTH 10
@@ -559,7 +555,7 @@ struct cse_basic_block_data {
int path_size;
/* Current branch path, indicating which branches will be taken. */
struct branch_path {
- /* The branch insn. */
+ /* The branch insn. */
rtx branch;
/* Whether it should be taken or not. AROUND is the same as taken
except that it is used when the destination label is not preceded
@@ -582,7 +578,8 @@ struct cse_basic_block_data {
|| XEXP (X, 0) == hard_frame_pointer_rtx \
|| XEXP (X, 0) == arg_pointer_rtx \
|| XEXP (X, 0) == virtual_stack_vars_rtx \
- || XEXP (X, 0) == virtual_incoming_args_rtx)))
+ || XEXP (X, 0) == virtual_incoming_args_rtx)) \
+ || GET_CODE (X) == ADDRESSOF)
/* Similar, but also allows reference to the stack pointer.
@@ -606,8 +603,10 @@ struct cse_basic_block_data {
|| (GET_CODE (X) == PLUS && GET_CODE (XEXP (X, 1)) == CONST_INT \
&& (XEXP (X, 0) == stack_pointer_rtx \
|| XEXP (X, 0) == virtual_stack_dynamic_rtx \
- || XEXP (X, 0) == virtual_outgoing_args_rtx)))
+ || XEXP (X, 0) == virtual_outgoing_args_rtx)) \
+ || GET_CODE (X) == ADDRESSOF)
+static int notreg_cost PROTO((rtx));
static void new_basic_block PROTO((void));
static void make_new_qty PROTO((int));
static void make_regs_eqv PROTO((int, int));
@@ -625,9 +624,10 @@ static struct table_elt *insert PROTO((rtx, struct table_elt *, unsigned,
static void merge_equiv_classes PROTO((struct table_elt *,
struct table_elt *));
static void invalidate PROTO((rtx, enum machine_mode));
+static int cse_rtx_varies_p PROTO((rtx));
static void remove_invalid_refs PROTO((int));
static void rehash_using_reg PROTO((rtx));
-static void invalidate_memory PROTO((struct write_data *));
+static void invalidate_memory PROTO((void));
static void invalidate_for_call PROTO((void));
static rtx use_related_value PROTO((rtx, struct table_elt *));
static unsigned canon_hash PROTO((rtx, enum machine_mode));
@@ -637,9 +637,6 @@ static void set_nonvarying_address_components PROTO((rtx, int, rtx *,
HOST_WIDE_INT *,
HOST_WIDE_INT *));
static int refers_to_p PROTO((rtx, rtx));
-static int refers_to_mem_p PROTO((rtx, rtx, HOST_WIDE_INT,
- HOST_WIDE_INT));
-static int cse_rtx_addr_varies_p PROTO((rtx));
static rtx canon_reg PROTO((rtx, rtx));
static void find_best_addr PROTO((rtx, rtx *));
static enum rtx_code find_comparison_args PROTO((enum rtx_code, rtx *, rtx *,
@@ -654,9 +651,9 @@ static rtx equiv_constant PROTO((rtx));
static void record_jump_equiv PROTO((rtx, int));
static void record_jump_cond PROTO((enum rtx_code, enum machine_mode,
rtx, rtx, int));
-static void cse_insn PROTO((rtx, int));
-static void note_mem_written PROTO((rtx, struct write_data *));
-static void invalidate_from_clobbers PROTO((struct write_data *, rtx));
+static void cse_insn PROTO((rtx, rtx));
+static int note_mem_written PROTO((rtx));
+static void invalidate_from_clobbers PROTO((rtx));
static rtx cse_process_notes PROTO((rtx, rtx));
static void cse_around_loop PROTO((rtx));
static void invalidate_skipped_set PROTO((rtx, rtx));
@@ -673,6 +670,28 @@ extern int rtx_equal_function_value_matters;
Another is in rtl generation, to pick the cheapest way to multiply.
Other uses like the latter are expected in the future. */
+/* Internal function, to compute cost when X is not a register; called
+ from COST macro to keep it simple. */
+
+static int
+notreg_cost (x)
+ rtx x;
+{
+ return ((GET_CODE (x) == SUBREG
+ && GET_CODE (SUBREG_REG (x)) == REG
+ && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
+ && GET_MODE_CLASS (GET_MODE (SUBREG_REG (x))) == MODE_INT
+ && (GET_MODE_SIZE (GET_MODE (x))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
+ && subreg_lowpart_p (x)
+ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (GET_MODE (x)),
+ GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))))
+ ? (CHEAP_REG (SUBREG_REG (x)) ? 0
+ : (REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER ? 1
+ : 2))
+ : rtx_cost (x, SET) * 2);
+}
+
/* Return the right cost to give to an operation
to make the cost of the corresponding register-to-register instruction
N times that of a fast register-to-register instruction. */
@@ -742,7 +761,15 @@ rtx_cost (x, outer_code)
#ifdef RTX_COSTS
RTX_COSTS (x, code, outer_code);
#endif
+#ifdef CONST_COSTS
CONST_COSTS (x, code, outer_code);
+#endif
+
+ default:
+#ifdef DEFAULT_RTX_COSTS
+ DEFAULT_RTX_COSTS(x, code, outer_code);
+#endif
+ break;
}
/* Sum the costs of the sub-rtx's, plus cost of this operation,
@@ -850,11 +877,11 @@ make_regs_eqv (new, old)
&& ((new < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (new))
|| (new >= FIRST_PSEUDO_REGISTER
&& (firstr < FIRST_PSEUDO_REGISTER
- || ((uid_cuid[regno_last_uid[new]] > cse_basic_block_end
- || (uid_cuid[regno_first_uid[new]]
+ || ((uid_cuid[REGNO_LAST_UID (new)] > cse_basic_block_end
+ || (uid_cuid[REGNO_FIRST_UID (new)]
< cse_basic_block_start))
- && (uid_cuid[regno_last_uid[new]]
- > uid_cuid[regno_last_uid[firstr]]))))))
+ && (uid_cuid[REGNO_LAST_UID (new)]
+ > uid_cuid[REGNO_LAST_UID (firstr)]))))))
{
reg_prev_eqv[firstr] = new;
reg_next_eqv[new] = firstr;
@@ -1466,7 +1493,7 @@ merge_equiv_classes (class1, class2)
/* Remove old entry, make a new one in CLASS1's class.
Don't do this for invalid entries as we cannot find their
- hash code (it also isn't necessary). */
+ hash code (it also isn't necessary). */
if (GET_CODE (exp) == REG || exp_equiv_p (exp, exp, 1, 0))
{
hash_arg_in_memory = 0;
@@ -1511,8 +1538,6 @@ invalidate (x, full_mode)
{
register int i;
register struct table_elt *p;
- rtx base;
- HOST_WIDE_INT start, end;
/* If X is a register, dependencies on its contents
are recorded through the qty number mechanism.
@@ -1526,7 +1551,7 @@ invalidate (x, full_mode)
register unsigned hash = HASH (x, GET_MODE (x));
/* Remove REGNO from any quantity list it might be on and indicate
- that it's value might have changed. If it is a pseudo, remove its
+ that its value might have changed. If it is a pseudo, remove its
entry from the hash table.
For a hard register, we do the first two actions above for any
@@ -1544,7 +1569,7 @@ invalidate (x, full_mode)
struct table_elt *elt;
- while (elt = lookup_for_remove (x, hash, GET_MODE (x)))
+ while ((elt = lookup_for_remove (x, hash, GET_MODE (x))))
remove_from_table (elt, hash);
}
else
@@ -1594,6 +1619,24 @@ invalidate (x, full_mode)
return;
}
+ /* If X is a parallel, invalidate all of its elements. */
+
+ if (GET_CODE (x) == PARALLEL)
+ {
+ for (i = XVECLEN (x, 0) - 1; i >= 0 ; --i)
+ invalidate (XVECEXP (x, 0, i), VOIDmode);
+ return;
+ }
+
+ /* If X is an expr_list, this is part of a disjoint return value;
+ extract the location in question ignoring the offset. */
+
+ if (GET_CODE (x) == EXPR_LIST)
+ {
+ invalidate (XEXP (x, 0), VOIDmode);
+ return;
+ }
+
/* X is not a register; it must be a memory reference with
a nonvarying address. Remove all hash table elements
that refer to overlapping pieces of memory. */
@@ -1604,16 +1647,17 @@ invalidate (x, full_mode)
if (full_mode == VOIDmode)
full_mode = GET_MODE (x);
- set_nonvarying_address_components (XEXP (x, 0), GET_MODE_SIZE (full_mode),
- &base, &start, &end);
-
for (i = 0; i < NBUCKETS; i++)
{
register struct table_elt *next;
for (p = table[i]; p; p = next)
{
next = p->next_same_hash;
- if (refers_to_mem_p (p->exp, base, start, end))
+ /* Invalidate ASM_OPERANDS which reference memory (this is easier
+ than checking all the aliases). */
+ if (p->in_memory
+ && (GET_CODE (p->exp) != MEM
+ || true_dependence (x, full_mode, p->exp, cse_rtx_varies_p)))
remove_from_table (p, i);
}
}
@@ -1694,30 +1738,6 @@ rehash_using_reg (x)
}
}
-/* Remove from the hash table all expressions that reference memory,
- or some of them as specified by *WRITES. */
-
-static void
-invalidate_memory (writes)
- struct write_data *writes;
-{
- register int i;
- register struct table_elt *p, *next;
- int all = writes->all;
- int nonscalar = writes->nonscalar;
-
- for (i = 0; i < NBUCKETS; i++)
- for (p = table[i]; p; p = next)
- {
- next = p->next_same_hash;
- if (p->in_memory
- && (all
- || (nonscalar && p->in_struct)
- || cse_rtx_addr_varies_p (p->exp)))
- remove_from_table (p, i);
- }
-}
-
/* Remove from the hash table any expression that is a call-clobbered
register. Also update their TICK values. */
@@ -1755,6 +1775,12 @@ invalidate_for_call ()
{
next = p->next_same_hash;
+ if (p->in_memory)
+ {
+ remove_from_table (p, hash);
+ continue;
+ }
+
if (GET_CODE (p->exp) != REG
|| REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
continue;
@@ -1886,18 +1912,16 @@ canon_hash (x, mode)
/* On some machines, we can't record any non-fixed hard register,
because extending its life will cause reload problems. We
consider ap, fp, and sp to be fixed for this purpose.
- On all machines, we can't record any global registers. */
+ On all machines, we can't record any global registers. */
if (regno < FIRST_PSEUDO_REGISTER
&& (global_regs[regno]
-#ifdef SMALL_REGISTER_CLASSES
- || (! fixed_regs[regno]
+ || (SMALL_REGISTER_CLASSES
+ && ! fixed_regs[regno]
&& regno != FRAME_POINTER_REGNUM
&& regno != HARD_FRAME_POINTER_REGNUM
&& regno != ARG_POINTER_REGNUM
- && regno != STACK_POINTER_REGNUM)
-#endif
- ))
+ && regno != STACK_POINTER_REGNUM)))
{
do_not_record = 1;
return 0;
@@ -1931,12 +1955,12 @@ canon_hash (x, mode)
/* Assume there is only one rtx object for any given label. */
case LABEL_REF:
hash
- += ((unsigned) LABEL_REF << 7) + (unsigned HOST_WIDE_INT) XEXP (x, 0);
+ += ((unsigned) LABEL_REF << 7) + (unsigned long) XEXP (x, 0);
return hash;
case SYMBOL_REF:
hash
- += ((unsigned) SYMBOL_REF << 7) + (unsigned HOST_WIDE_INT) XSTR (x, 0);
+ += ((unsigned) SYMBOL_REF << 7) + (unsigned long) XSTR (x, 0);
return hash;
case MEM:
@@ -1945,7 +1969,7 @@ canon_hash (x, mode)
do_not_record = 1;
return 0;
}
- if (! RTX_UNCHANGING_P (x))
+ if (! RTX_UNCHANGING_P (x) || FIXED_BASE_PLUS_P (XEXP (x, 0)))
{
hash_arg_in_memory = 1;
if (MEM_IN_STRUCT_P (x)) hash_arg_in_struct = 1;
@@ -1973,6 +1997,10 @@ canon_hash (x, mode)
do_not_record = 1;
return 0;
}
+ break;
+
+ default:
+ break;
}
i = GET_RTX_LENGTH (code) - 1;
@@ -2009,6 +2037,8 @@ canon_hash (x, mode)
register unsigned tem = XINT (x, i);
hash += tem;
}
+ else if (fmt[i] == '0')
+ /* unused */;
else
abort ();
}
@@ -2045,7 +2075,7 @@ safe_hash (x, mode)
in all the places that search a hash table chain for an equivalent
for a given value. A possible equivalent that has different structure
has its hash code computed from different data. Whether the hash code
- is the same as that of the the given value is pure luck. */
+ is the same as that of the given value is pure luck. */
static int
exp_equiv_p (x, y, validate, equal_values)
@@ -2147,6 +2177,9 @@ exp_equiv_p (x, y, validate, equal_values)
validate, equal_values)
&& exp_equiv_p (XEXP (x, 1), XEXP (y, 0),
validate, equal_values)));
+
+ default:
+ break;
}
/* Compare the elements. If any pair of corresponding elements
@@ -2273,6 +2306,10 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
start = 0;
end = 0;
+ if (flag_pic && GET_CODE (base) == PLUS
+ && XEXP (base, 0) == pic_offset_table_rtx)
+ base = XEXP (base, 1);
+
/* Registers with nonvarying addresses usually have constant equivalents;
but the frame pointer register is also possible. */
if (GET_CODE (base) == REG
@@ -2375,6 +2412,9 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
base = *pbase;
}
break;
+
+ default:
+ break;
}
break;
@@ -2394,105 +2434,31 @@ set_nonvarying_address_components (addr, size, pbase, pstart, pend)
*pend = end;
}
-/* Return 1 iff any subexpression of X refers to memory
- at an address of BASE plus some offset
- such that any of the bytes' offsets fall between START (inclusive)
- and END (exclusive).
-
- The value is undefined if X is a varying address (as determined by
- cse_rtx_addr_varies_p). This function is not used in such cases.
-
- When used in the cse pass, `qty_const' is nonzero, and it is used
- to treat an address that is a register with a known constant value
- as if it were that constant value.
- In the loop pass, `qty_const' is zero, so this is not done. */
-
-static int
-refers_to_mem_p (x, base, start, end)
- rtx x, base;
- HOST_WIDE_INT start, end;
-{
- register HOST_WIDE_INT i;
- register enum rtx_code code;
- register char *fmt;
-
- repeat:
- if (x == 0)
- return 0;
-
- code = GET_CODE (x);
- if (code == MEM)
- {
- register rtx addr = XEXP (x, 0); /* Get the address. */
- rtx mybase;
- HOST_WIDE_INT mystart, myend;
-
- set_nonvarying_address_components (addr, GET_MODE_SIZE (GET_MODE (x)),
- &mybase, &mystart, &myend);
-
-
- /* refers_to_mem_p is never called with varying addresses.
- If the base addresses are not equal, there is no chance
- of the memory addresses conflicting. */
- if (! rtx_equal_p (mybase, base))
- return 0;
-
- return myend > start && mystart < end;
- }
-
- /* X does not match, so try its subexpressions. */
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- if (fmt[i] == 'e')
- {
- if (i == 0)
- {
- x = XEXP (x, 0);
- goto repeat;
- }
- else
- if (refers_to_mem_p (XEXP (x, i), base, start, end))
- return 1;
- }
- else if (fmt[i] == 'E')
- {
- int j;
- for (j = 0; j < XVECLEN (x, i); j++)
- if (refers_to_mem_p (XVECEXP (x, i, j), base, start, end))
- return 1;
- }
-
- return 0;
-}
-
-/* Nonzero if X refers to memory at a varying address;
- except that a register which has at the moment a known constant value
- isn't considered variable. */
+/* Return 1 if X has a value that can vary even between two
+ executions of the program. 0 means X can be compared reliably
+ against certain constants or near-constants. */
static int
-cse_rtx_addr_varies_p (x)
- rtx x;
+cse_rtx_varies_p (x)
+ register rtx x;
{
/* We need not check for X and the equivalence class being of the same
mode because if X is equivalent to a constant in some mode, it
doesn't vary in any mode. */
- if (GET_CODE (x) == MEM
- && GET_CODE (XEXP (x, 0)) == REG
- && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
- && GET_MODE (XEXP (x, 0)) == qty_mode[reg_qty[REGNO (XEXP (x, 0))]]
- && qty_const[reg_qty[REGNO (XEXP (x, 0))]] != 0)
+ if (GET_CODE (x) == REG
+ && REGNO_QTY_VALID_P (REGNO (x))
+ && GET_MODE (x) == qty_mode[reg_qty[REGNO (x)]]
+ && qty_const[reg_qty[REGNO (x)]] != 0)
return 0;
- if (GET_CODE (x) == MEM
- && GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
- && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 0)))
- && (GET_MODE (XEXP (XEXP (x, 0), 0))
- == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]])
- && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]])
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && GET_CODE (XEXP (x, 0)) == REG
+ && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
+ && (GET_MODE (XEXP (x, 0))
+ == qty_mode[reg_qty[REGNO (XEXP (x, 0))]])
+ && qty_const[reg_qty[REGNO (XEXP (x, 0))]])
return 0;
/* This can happen as the result of virtual register instantiation, if
@@ -2500,21 +2466,20 @@ cse_rtx_addr_varies_p (x)
us a three instruction sequence, load large offset into a register,
load fp minus a constant into a register, then a MEM which is the
sum of the two `constant' registers. */
- if (GET_CODE (x) == MEM
- && GET_CODE (XEXP (x, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
- && GET_CODE (XEXP (XEXP (x, 0), 1)) == REG
- && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 0)))
- && (GET_MODE (XEXP (XEXP (x, 0), 0))
- == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]])
- && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 0))]]
- && REGNO_QTY_VALID_P (REGNO (XEXP (XEXP (x, 0), 1)))
- && (GET_MODE (XEXP (XEXP (x, 0), 1))
- == qty_mode[reg_qty[REGNO (XEXP (XEXP (x, 0), 1))]])
- && qty_const[reg_qty[REGNO (XEXP (XEXP (x, 0), 1))]])
+ if (GET_CODE (x) == PLUS
+ && GET_CODE (XEXP (x, 0)) == REG
+ && GET_CODE (XEXP (x, 1)) == REG
+ && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
+ && (GET_MODE (XEXP (x, 0))
+ == qty_mode[reg_qty[REGNO (XEXP (x, 0))]])
+ && qty_const[reg_qty[REGNO (XEXP (x, 0))]]
+ && REGNO_QTY_VALID_P (REGNO (XEXP (x, 1)))
+ && (GET_MODE (XEXP (x, 1))
+ == qty_mode[reg_qty[REGNO (XEXP (x, 1))]])
+ && qty_const[reg_qty[REGNO (XEXP (x, 1))]])
return 0;
- return rtx_addr_varies_p (x);
+ return rtx_varies_p (x);
}
/* Canonicalize an expression:
@@ -2570,8 +2535,11 @@ canon_reg (x, insn)
first = qty_first_reg[reg_qty[REGNO (x)]];
return (first >= FIRST_PSEUDO_REGISTER ? regno_reg_rtx[first]
: REGNO_REG_CLASS (first) == NO_REGS ? x
- : gen_rtx (REG, qty_mode[reg_qty[REGNO (x)]], first));
+ : gen_rtx_REG (qty_mode[reg_qty[REGNO (x)]], first));
}
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -2582,6 +2550,7 @@ canon_reg (x, insn)
if (fmt[i] == 'e')
{
rtx new = canon_reg (XEXP (x, i), insn);
+ int insn_code;
/* If replacing pseudo with hard reg or vice versa, ensure the
insn remains valid. Likewise if the insn has MATCH_DUPs. */
@@ -2589,7 +2558,8 @@ canon_reg (x, insn)
&& GET_CODE (new) == REG && GET_CODE (XEXP (x, i)) == REG
&& (((REGNO (new) < FIRST_PSEUDO_REGISTER)
!= (REGNO (XEXP (x, i)) < FIRST_PSEUDO_REGISTER))
- || insn_n_dups[recog_memoized (insn)] > 0))
+ || (insn_code = recog_memoized (insn)) < 0
+ || insn_n_dups[insn_code] > 0))
validate_change (insn, &XEXP (x, i), new, 1);
else
XEXP (x, i) = new;
@@ -2602,7 +2572,7 @@ canon_reg (x, insn)
return x;
}
-/* LOC is a location with INSN that is an operand address (the contents of
+/* LOC is a location within INSN that is an operand address (the contents of
a MEM). Find the best equivalent address to use that is valid for this
insn.
@@ -2623,10 +2593,12 @@ find_best_addr (insn, loc)
rtx insn;
rtx *loc;
{
- struct table_elt *elt, *p;
+ struct table_elt *elt;
rtx addr = *loc;
- int our_cost;
+#ifdef ADDRESS_COST
+ struct table_elt *p;
int found_better = 1;
+#endif
int save_do_not_record = do_not_record;
int save_hash_arg_in_memory = hash_arg_in_memory;
int save_hash_arg_in_struct = hash_arg_in_struct;
@@ -2653,6 +2625,7 @@ find_best_addr (insn, loc)
&& (regno = REGNO (addr), regno == FRAME_POINTER_REGNUM
|| regno == HARD_FRAME_POINTER_REGNUM
|| regno == ARG_POINTER_REGNUM))
+ || GET_CODE (addr) == ADDRESSOF
|| CONSTANT_ADDRESS_P (addr))
return;
@@ -2660,9 +2633,21 @@ find_best_addr (insn, loc)
sometimes simplify the expression. Many simplifications
will not be valid, but some, usually applying the associative rule, will
be valid and produce better code. */
- if (GET_CODE (addr) != REG
- && validate_change (insn, loc, fold_rtx (addr, insn), 0))
- addr = *loc;
+ if (GET_CODE (addr) != REG)
+ {
+ rtx folded = fold_rtx (copy_rtx (addr), NULL_RTX);
+
+ if (1
+#ifdef ADDRESS_COST
+ && (CSE_ADDRESS_COST (folded) < CSE_ADDRESS_COST (addr)
+ || (CSE_ADDRESS_COST (folded) == CSE_ADDRESS_COST (addr)
+ && rtx_cost (folded, MEM) > rtx_cost (addr, MEM)))
+#else
+ && rtx_cost (folded, MEM) < rtx_cost (addr, MEM)
+#endif
+ && validate_change (insn, loc, folded, 0))
+ addr = folded;
+ }
/* If this address is not in the hash table, we can't look for equivalences
of the whole address. Also, ignore if volatile. */
@@ -2682,7 +2667,7 @@ find_best_addr (insn, loc)
#ifndef ADDRESS_COST
if (elt)
{
- our_cost = elt->cost;
+ int our_cost = elt->cost;
/* Find the lowest cost below ours that works. */
for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
@@ -2707,23 +2692,25 @@ find_best_addr (insn, loc)
while (found_better)
{
- int best_addr_cost = ADDRESS_COST (*loc);
+ int best_addr_cost = CSE_ADDRESS_COST (*loc);
int best_rtx_cost = (elt->cost + 1) >> 1;
struct table_elt *best_elt = elt;
found_better = 0;
for (p = elt->first_same_value; p; p = p->next_same_value)
- if (! p->flag
- && (GET_CODE (p->exp) == REG
- || exp_equiv_p (p->exp, p->exp, 1, 0))
- && (ADDRESS_COST (p->exp) < best_addr_cost
- || (ADDRESS_COST (p->exp) == best_addr_cost
- && (p->cost + 1) >> 1 > best_rtx_cost)))
+ if (! p->flag)
{
- found_better = 1;
- best_addr_cost = ADDRESS_COST (p->exp);
- best_rtx_cost = (p->cost + 1) >> 1;
- best_elt = p;
+ if ((GET_CODE (p->exp) == REG
+ || exp_equiv_p (p->exp, p->exp, 1, 0))
+ && (CSE_ADDRESS_COST (p->exp) < best_addr_cost
+ || (CSE_ADDRESS_COST (p->exp) == best_addr_cost
+ && (p->cost + 1) >> 1 > best_rtx_cost)))
+ {
+ found_better = 1;
+ best_addr_cost = CSE_ADDRESS_COST (p->exp);
+ best_rtx_cost = (p->cost + 1) >> 1;
+ best_elt = p;
+ }
}
if (found_better)
@@ -2775,7 +2762,7 @@ find_best_addr (insn, loc)
while (found_better)
{
- int best_addr_cost = ADDRESS_COST (*loc);
+ int best_addr_cost = CSE_ADDRESS_COST (*loc);
int best_rtx_cost = (COST (*loc) + 1) >> 1;
struct table_elt *best_elt = elt;
rtx best_rtx = *loc;
@@ -2796,12 +2783,12 @@ find_best_addr (insn, loc)
{
rtx new = cse_gen_binary (GET_CODE (*loc), Pmode, p->exp, c);
- if ((ADDRESS_COST (new) < best_addr_cost
- || (ADDRESS_COST (new) == best_addr_cost
+ if ((CSE_ADDRESS_COST (new) < best_addr_cost
+ || (CSE_ADDRESS_COST (new) == best_addr_cost
&& (COST (new) + 1) >> 1 > best_rtx_cost)))
{
found_better = 1;
- best_addr_cost = ADDRESS_COST (new);
+ best_addr_cost = CSE_ADDRESS_COST (new);
best_rtx_cost = (COST (new) + 1) >> 1;
best_elt = p;
best_rtx = new;
@@ -3016,7 +3003,7 @@ simplify_unary_operation (code, mode, op, op_mode)
lv = CONST_DOUBLE_LOW (op), hv = CONST_DOUBLE_HIGH (op);
#ifdef REAL_ARITHMETIC
- REAL_VALUE_FROM_INT (d, lv, hv);
+ REAL_VALUE_FROM_INT (d, lv, hv, mode);
#else
if (hv < 0)
{
@@ -3061,7 +3048,7 @@ simplify_unary_operation (code, mode, op, op_mode)
hv = 0, lv &= GET_MODE_MASK (op_mode);
#ifdef REAL_ARITHMETIC
- REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv);
+ REAL_VALUE_FROM_UNSIGNED_INT (d, lv, hv, mode);
#else
d = (double) (unsigned HOST_WIDE_INT) hv;
@@ -3167,7 +3154,7 @@ simplify_unary_operation (code, mode, op, op_mode)
}
/* We can do some operations on integer CONST_DOUBLEs. Also allow
- for a DImode operation on a CONST_INT. */
+ for a DImode operation on a CONST_INT. */
else if (GET_MODE (op) == VOIDmode && width <= HOST_BITS_PER_INT * 2
&& (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
{
@@ -3401,6 +3388,9 @@ simplify_unary_operation (code, mode, op, op_mode)
return convert_memory_address (Pmode, op);
break;
#endif
+
+ default:
+ break;
}
return 0;
@@ -3451,6 +3441,10 @@ simplify_binary_operation (code, mode, op0, op1)
f1 = real_value_truncate (mode, f1);
#ifdef REAL_ARITHMETIC
+#ifndef REAL_INFINITY
+ if (code == DIV && REAL_VALUES_EQUAL (f1, dconst0))
+ return 0;
+#endif
REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);
#else
switch (code)
@@ -3513,7 +3507,7 @@ simplify_binary_operation (code, mode, op0, op1)
neg_double (l2, h2, &lv, &hv);
l2 = lv, h2 = hv;
- /* .. fall through ... */
+ /* .. fall through ... */
case PLUS:
add_double (l1, h1, l2, h2, &lv, &hv);
@@ -3747,11 +3741,11 @@ simplify_binary_operation (code, mode, op0, op1)
/* Change subtraction from zero into negation. */
if (op0 == CONST0_RTX (mode))
- return gen_rtx (NEG, mode, op1);
+ return gen_rtx_NEG (mode, op1);
/* (-1 - a) is ~a. */
if (op0 == constm1_rtx)
- return gen_rtx (NOT, mode, op1);
+ return gen_rtx_NOT (mode, op1);
/* Subtracting 0 has no effect. */
if (op1 == CONST0_RTX (mode))
@@ -3835,9 +3829,9 @@ simplify_binary_operation (code, mode, op0, op1)
if (GET_CODE (op1) == AND)
{
if (rtx_equal_p (op0, XEXP (op1, 0)))
- return cse_gen_binary (AND, mode, op0, gen_rtx (NOT, mode, XEXP (op1, 1)));
+ return cse_gen_binary (AND, mode, op0, gen_rtx_NOT (mode, XEXP (op1, 1)));
if (rtx_equal_p (op0, XEXP (op1, 1)))
- return cse_gen_binary (AND, mode, op0, gen_rtx (NOT, mode, XEXP (op1, 0)));
+ return cse_gen_binary (AND, mode, op0, gen_rtx_NOT (mode, XEXP (op1, 0)));
}
break;
@@ -3846,7 +3840,7 @@ simplify_binary_operation (code, mode, op0, op1)
{
tem = simplify_unary_operation (NEG, mode, op0, mode);
- return tem ? tem : gen_rtx (NEG, mode, op0);
+ return tem ? tem : gen_rtx_NEG (mode, op0);
}
/* In IEEE floating point, x*0 is not always 0. */
@@ -3866,8 +3860,13 @@ simplify_binary_operation (code, mode, op0, op1)
we are still generating RTL. This test is a kludge. */
if (GET_CODE (op1) == CONST_INT
&& (val = exact_log2 (INTVAL (op1))) >= 0
+ /* If the mode is larger than the host word size, and the
+ uppermost bit is set, then this isn't a power of two due
+ to implicit sign extension. */
+ && (width <= HOST_BITS_PER_WIDE_INT
+ || val != HOST_BITS_PER_WIDE_INT - 1)
&& ! rtx_equal_function_value_matters)
- return gen_rtx (ASHIFT, mode, op0, GEN_INT (val));
+ return gen_rtx_ASHIFT (mode, op0, GEN_INT (val));
if (GET_CODE (op1) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (op1)) == MODE_FLOAT)
@@ -3887,10 +3886,10 @@ simplify_binary_operation (code, mode, op0, op1)
/* x*2 is x+x and x*(-1) is -x */
if (op1is2 && GET_MODE (op0) == mode)
- return gen_rtx (PLUS, mode, op0, copy_rtx (op0));
+ return gen_rtx_PLUS (mode, op0, copy_rtx (op0));
else if (op1ism1 && GET_MODE (op0) == mode)
- return gen_rtx (NEG, mode, op0);
+ return gen_rtx_NEG (mode, op0);
}
break;
@@ -3915,7 +3914,7 @@ simplify_binary_operation (code, mode, op0, op1)
return op0;
if (GET_CODE (op1) == CONST_INT
&& (INTVAL (op1) & GET_MODE_MASK (mode)) == GET_MODE_MASK (mode))
- return gen_rtx (NOT, mode, op0);
+ return gen_rtx_NOT (mode, op0);
if (op0 == op1 && ! side_effects_p (op0)
&& GET_MODE_CLASS (mode) != MODE_CC)
return const0_rtx;
@@ -3943,9 +3942,9 @@ simplify_binary_operation (code, mode, op0, op1)
below). */
if (GET_CODE (op1) == CONST_INT
&& (arg1 = exact_log2 (INTVAL (op1))) > 0)
- return gen_rtx (LSHIFTRT, mode, op0, GEN_INT (arg1));
+ return gen_rtx_LSHIFTRT (mode, op0, GEN_INT (arg1));
- /* ... fall through ... */
+ /* ... fall through ... */
case DIV:
if (op1 == CONST1_RTX (mode))
@@ -3974,11 +3973,11 @@ simplify_binary_operation (code, mode, op0, op1)
{
#if defined (REAL_ARITHMETIC)
REAL_ARITHMETIC (d, rtx_to_tree_code (DIV), dconst1, d);
- return gen_rtx (MULT, mode, op0,
- CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
+ return gen_rtx_MULT (mode, op0,
+ CONST_DOUBLE_FROM_REAL_VALUE (d, mode));
#else
- return gen_rtx (MULT, mode, op0,
- CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
+ return gen_rtx_MULT (mode, op0,
+ CONST_DOUBLE_FROM_REAL_VALUE (1./d, mode));
#endif
}
}
@@ -3989,9 +3988,9 @@ simplify_binary_operation (code, mode, op0, op1)
/* Handle modulus by power of two (mod with 1 handled below). */
if (GET_CODE (op1) == CONST_INT
&& exact_log2 (INTVAL (op1)) > 0)
- return gen_rtx (AND, mode, op0, GEN_INT (INTVAL (op1) - 1));
+ return gen_rtx_AND (mode, op0, GEN_INT (INTVAL (op1) - 1));
- /* ... fall through ... */
+ /* ... fall through ... */
case MOD:
if ((op0 == const0_rtx || op1 == const1_rtx)
@@ -4007,7 +4006,7 @@ simplify_binary_operation (code, mode, op0, op1)
&& ! side_effects_p (op1))
return op0;
- /* ... fall through ... */
+ /* ... fall through ... */
case ASHIFT:
case ASHIFTRT:
@@ -4323,6 +4322,9 @@ simplify_plus_minus (code, mode, op0, op1)
if (negs[i])
ops[i] = GEN_INT (- INTVAL (ops[i])), negs[i] = 0, changed = 1;
break;
+
+ default:
+ break;
}
}
@@ -4418,7 +4420,7 @@ simplify_plus_minus (code, mode, op0, op1)
for (i = 1; i < n_ops; i++)
result = cse_gen_binary (negs[i] ? MINUS : PLUS, mode, result, ops[i]);
- return negate ? gen_rtx (NEG, mode, result) : result;
+ return negate ? gen_rtx_NEG (mode, result) : result;
}
/* Make a binary operation by properly ordering the operands and
@@ -4458,7 +4460,7 @@ cse_gen_binary (code, mode, op0, op1)
&& GET_MODE (op0) != VOIDmode)
return plus_constant (op0, - INTVAL (op1));
else
- return gen_rtx (code, mode, op0, op1);
+ return gen_rtx_fmt_ee (code, mode, op0, op1);
}
/* Like simplify_binary_operation except used for relational operators.
@@ -4556,7 +4558,7 @@ simplify_relational_operation (code, mode, op0, op1)
else
{
l0u = l0s = INTVAL (op0);
- h0u = 0, h0s = l0s < 0 ? -1 : 0;
+ h0u = h0s = l0s < 0 ? -1 : 0;
}
if (GET_CODE (op1) == CONST_DOUBLE)
@@ -4567,7 +4569,7 @@ simplify_relational_operation (code, mode, op0, op1)
else
{
l1u = l1s = INTVAL (op1);
- h1u = 0, h1s = l1s < 0 ? -1 : 0;
+ h1u = h1s = l1s < 0 ? -1 : 0;
}
/* If WIDTH is nonzero and smaller than HOST_BITS_PER_WIDE_INT,
@@ -4648,6 +4650,9 @@ simplify_relational_operation (code, mode, op0, op1)
&& INTEGRAL_MODE_P (mode))
return const0_rtx;
break;
+
+ default:
+ break;
}
return 0;
@@ -4677,9 +4682,9 @@ simplify_relational_operation (code, mode, op0, op1)
return equal || op0ltu ? const_true_rtx : const0_rtx;
case GEU:
return equal || op1ltu ? const_true_rtx : const0_rtx;
+ default:
+ abort ();
}
-
- abort ();
}
/* Simplify CODE, an operation with result mode MODE and three operands,
@@ -4743,6 +4748,27 @@ simplify_ternary_operation (code, mode, op0_mode, op0, op1, op2)
case IF_THEN_ELSE:
if (GET_CODE (op0) == CONST_INT)
return op0 != const0_rtx ? op1 : op2;
+
+ /* Convert a == b ? b : a to "a". */
+ if (GET_CODE (op0) == NE && ! side_effects_p (op0)
+ && rtx_equal_p (XEXP (op0, 0), op1)
+ && rtx_equal_p (XEXP (op0, 1), op2))
+ return op1;
+ else if (GET_CODE (op0) == EQ && ! side_effects_p (op0)
+ && rtx_equal_p (XEXP (op0, 1), op1)
+ && rtx_equal_p (XEXP (op0, 0), op2))
+ return op2;
+ else if (GET_RTX_CLASS (GET_CODE (op0)) == '<' && ! side_effects_p (op0))
+ {
+ rtx temp;
+ temp = simplify_relational_operation (GET_CODE (op0), op0_mode,
+ XEXP (op0, 0), XEXP (op0, 1));
+ /* See if any simplifications were possible. */
+ if (temp == const0_rtx)
+ return op2;
+ else if (temp == const1_rtx)
+ return op1;
+ }
break;
default:
@@ -4809,6 +4835,10 @@ fold_rtx (x, insn)
since they are used only for lists of args
in a function call's REG_EQUAL note. */
case EXPR_LIST:
+ /* Changing anything inside an ADDRESSOF is incorrect; we don't
+ want to (e.g.,) make (addressof (const_int 0)) just because
+ the location is known to be zero. */
+ case ADDRESSOF:
return x;
#ifdef HAVE_cc0
@@ -4829,7 +4859,7 @@ fold_rtx (x, insn)
&& GET_CODE (NEXT_INSN (next)) == JUMP_INSN
&& (GET_CODE (PATTERN (NEXT_INSN (next))) == ADDR_VEC
|| GET_CODE (PATTERN (NEXT_INSN (next))) == ADDR_DIFF_VEC))
- return gen_rtx (LABEL_REF, Pmode, next);
+ return gen_rtx_LABEL_REF (Pmode, next);
}
break;
@@ -5058,6 +5088,8 @@ fold_rtx (x, insn)
else if (GET_CODE (addr) == LO_SUM
&& GET_CODE (XEXP (addr, 1)) == SYMBOL_REF)
base = XEXP (addr, 1);
+ else if (GET_CODE (addr) == ADDRESSOF)
+ return change_address (x, VOIDmode, addr);
/* If this is a constant pool reference, we can fold it into its
constant to allow better value tracking. */
@@ -5126,23 +5158,36 @@ fold_rtx (x, insn)
< XVECLEN (table, 1)))
{
offset /= GET_MODE_SIZE (GET_MODE (table));
- new = gen_rtx (MINUS, Pmode, XVECEXP (table, 1, offset),
- XEXP (table, 0));
+ new = gen_rtx_MINUS (Pmode, XVECEXP (table, 1, offset),
+ XEXP (table, 0));
if (GET_MODE (table) != Pmode)
- new = gen_rtx (TRUNCATE, GET_MODE (table), new);
+ new = gen_rtx_TRUNCATE (GET_MODE (table), new);
/* Indicate this is a constant. This isn't a
valid form of CONST, but it will only be used
to fold the next insns and then discarded, so
- it should be safe. */
- return gen_rtx (CONST, GET_MODE (new), new);
+ it should be safe.
+
+ Note this expression must be explicitly discarded,
+ by cse_insn, else it may end up in a REG_EQUAL note
+ and "escape" to cause problems elsewhere. */
+ return gen_rtx_CONST (GET_MODE (new), new);
}
}
}
return x;
}
+
+ case ASM_OPERANDS:
+ for (i = XVECLEN (x, 3) - 1; i >= 0; i--)
+ validate_change (insn, &XVECEXP (x, 3, i),
+ fold_rtx (XVECEXP (x, 3, i), insn), 0);
+ break;
+
+ default:
+ break;
}
const_arg0 = 0;
@@ -5270,10 +5315,13 @@ fold_rtx (x, insn)
}
}
- else if (fmt[i] == 'E')
- /* Don't try to fold inside of a vector of expressions.
- Doing nothing is harmless. */
- ;
+ else
+ {
+ if (fmt[i] == 'E')
+ /* Don't try to fold inside of a vector of expressions.
+ Doing nothing is harmless. */
+ {;}
+ }
/* If a commutative operation, place a constant integer as the second
operand unless the first operand is also a constant integer. Otherwise,
@@ -5327,7 +5375,7 @@ fold_rtx (x, insn)
const_arg0 ? const_arg0 : folded_arg0,
mode_arg0);
if (new != 0 && is_const)
- new = gen_rtx (CONST, mode, new);
+ new = gen_rtx_CONST (mode, new);
}
break;
@@ -5364,12 +5412,14 @@ fold_rtx (x, insn)
if (mode_arg0 == VOIDmode || GET_MODE_CLASS (mode_arg0) == MODE_CC)
break;
- /* If we do not now have two constants being compared, see if we
- can nevertheless deduce some things about the comparison. */
+ /* If we do not now have two constants being compared, see
+ if we can nevertheless deduce some things about the
+ comparison. */
if (const_arg0 == 0 || const_arg1 == 0)
{
- /* Is FOLDED_ARG0 frame-pointer plus a constant? Or non-explicit
- constant? These aren't zero, but we don't know their sign. */
+ /* Is FOLDED_ARG0 frame-pointer plus a constant? Or
+ non-explicit constant? These aren't zero, but we
+ don't know their sign. */
if (const_arg1 == const0_rtx
&& (NONZERO_BASE_PLUS_P (folded_arg0)
#if 0 /* Sad to say, on sysvr4, #pragma weak can make a symbol address
@@ -5476,6 +5526,8 @@ fold_rtx (x, insn)
if (has_sign)
return false;
break;
+ default:
+ break;
}
}
}
@@ -5541,11 +5593,17 @@ fold_rtx (x, insn)
/* If second operand is a register equivalent to a negative
CONST_INT, see if we can find a register equivalent to the
positive constant. Make a MINUS if so. Don't do this for
- a negative constant since we might then alternate between
+ a non-negative constant since we might then alternate between
chosing positive and negative constants. Having the positive
- constant previously-used is the more common case. */
- if (const_arg1 && GET_CODE (const_arg1) == CONST_INT
- && INTVAL (const_arg1) < 0 && GET_CODE (folded_arg1) == REG)
+ constant previously-used is the more common case. Be sure
+ the resulting constant is non-negative; if const_arg1 were
+ the smallest negative number this would overflow: depending
+ on the mode, this would either just be the same value (and
+ hence not save anything) or be incorrect. */
+ if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT
+ && INTVAL (const_arg1) < 0
+ && - INTVAL (const_arg1) >= 0
+ && GET_CODE (folded_arg1) == REG)
{
rtx new_const = GEN_INT (- INTVAL (const_arg1));
struct table_elt *p
@@ -5572,7 +5630,7 @@ fold_rtx (x, insn)
NULL_RTX);
}
- /* ... fall through ... */
+ /* ... fall through ... */
from_plus:
case SMIN: case SMAX: case UMIN: case UMAX:
@@ -5665,6 +5723,10 @@ fold_rtx (x, insn)
return cse_gen_binary (code, mode, y, new_const);
}
+ break;
+
+ default:
+ break;
}
new = simplify_binary_operation (code, mode,
@@ -5687,6 +5749,12 @@ fold_rtx (x, insn)
const_arg1 ? const_arg1 : folded_arg1,
const_arg2 ? const_arg2 : XEXP (x, 2));
break;
+
+ case 'x':
+ /* Always eliminate CONSTANT_P_RTX at this stage. */
+ if (code == CONSTANT_P_RTX)
+ return (const_arg0 ? const1_rtx : const0_rtx);
+ break;
}
return new ? new : x;
@@ -5764,7 +5832,7 @@ gen_lowpart_if_possible (mode, x)
unchanged. */
offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
- MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
- new = gen_rtx (MEM, mode, plus_constant (XEXP (x, 0), offset));
+ new = gen_rtx_MEM (mode, plus_constant (XEXP (x, 0), offset));
if (! memory_address_p (mode, XEXP (new, 0)))
return 0;
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (x);
@@ -5849,7 +5917,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
/* If OP0 and OP1 are known equal, and either is a paradoxical SUBREG,
we know that they are also equal in the smaller mode (this is also
true for all smaller modes whether or not there is a SUBREG, but
- is not worth testing for with no SUBREG. */
+ is not worth testing for with no SUBREG). */
/* Note that GET_MODE (op0) may not equal MODE. */
if (code == EQ && GET_CODE (op0) == SUBREG
@@ -5860,7 +5928,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
rtx tem = gen_lowpart_if_possible (inner_mode, op1);
record_jump_cond (code, mode, SUBREG_REG (op0),
- tem ? tem : gen_rtx (SUBREG, inner_mode, op1, 0),
+ tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0),
reversed_nonequality);
}
@@ -5872,7 +5940,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
rtx tem = gen_lowpart_if_possible (inner_mode, op0);
record_jump_cond (code, mode, SUBREG_REG (op1),
- tem ? tem : gen_rtx (SUBREG, inner_mode, op0, 0),
+ tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0),
reversed_nonequality);
}
@@ -5892,7 +5960,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
rtx tem = gen_lowpart_if_possible (inner_mode, op1);
record_jump_cond (code, mode, SUBREG_REG (op0),
- tem ? tem : gen_rtx (SUBREG, inner_mode, op1, 0),
+ tem ? tem : gen_rtx_SUBREG (inner_mode, op1, 0),
reversed_nonequality);
}
@@ -5905,7 +5973,7 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
rtx tem = gen_lowpart_if_possible (inner_mode, op0);
record_jump_cond (code, mode, SUBREG_REG (op1),
- tem ? tem : gen_rtx (SUBREG, inner_mode, op0, 0),
+ tem ? tem : gen_rtx_SUBREG (inner_mode, op0, 0),
reversed_nonequality);
}
@@ -6053,8 +6121,9 @@ record_jump_cond (code, mode, op0, op1, reversed_nonequality)
Then install the new sources and destinations in the table
of available values.
- If IN_LIBCALL_BLOCK is nonzero, don't record any equivalence made in
- the insn. */
+ If LIBCALL_INSN is nonzero, don't record any equivalence made in
+ the insn. It means that INSN is inside libcall block. In this
+ case LIBCALL_INSN is the corresponding insn with REG_LIBCALL. */
/* Data on one SET contained in the instruction. */
@@ -6092,20 +6161,20 @@ struct set
};
static void
-cse_insn (insn, in_libcall_block)
+cse_insn (insn, libcall_insn)
rtx insn;
- int in_libcall_block;
+ rtx libcall_insn;
{
register rtx x = PATTERN (insn);
register int i;
rtx tem;
register int n_sets = 0;
+#ifdef HAVE_cc0
/* Records what this insn does to set CC0. */
rtx this_insn_cc0 = 0;
- enum machine_mode this_insn_cc0_mode;
- struct write_data writes_memory;
- static struct write_data init = {0, 0, 0, 0};
+ enum machine_mode this_insn_cc0_mode = VOIDmode;
+#endif
rtx src_eqv = 0;
struct table_elt *src_eqv_elt = 0;
@@ -6117,7 +6186,6 @@ cse_insn (insn, in_libcall_block)
struct set *sets;
this_insn = insn;
- writes_memory = init;
/* Find all the SETs and CLOBBERs in this instruction.
Record all the SETs in the array `set' and count them.
@@ -6152,7 +6220,7 @@ cse_insn (insn, in_libcall_block)
someplace else, so it isn't worth cse'ing (and on 80386 is unsafe)!
Ensure we invalidate the destination register. On the 80386 no
other code would invalidate it since it is a fixed_reg.
- We need not check the return of apply_change_group; see canon_reg. */
+ We need not check the return of apply_change_group; see canon_reg. */
else if (GET_CODE (SET_SRC (x)) == CALL)
{
@@ -6219,15 +6287,11 @@ cse_insn (insn, in_libcall_block)
}
else if (GET_CODE (y) == CLOBBER)
{
- /* If we clobber memory, take note of that,
- and canon the address.
+ /* If we clobber memory, canon the address.
This does nothing when a register is clobbered
because we have already invalidated the reg. */
if (GET_CODE (XEXP (y, 0)) == MEM)
- {
- canon_reg (XEXP (y, 0), NULL_RTX);
- note_mem_written (XEXP (y, 0), &writes_memory);
- }
+ canon_reg (XEXP (y, 0), NULL_RTX);
}
else if (GET_CODE (y) == USE
&& ! (GET_CODE (XEXP (y, 0)) == REG
@@ -6246,10 +6310,7 @@ cse_insn (insn, in_libcall_block)
else if (GET_CODE (x) == CLOBBER)
{
if (GET_CODE (XEXP (x, 0)) == MEM)
- {
- canon_reg (XEXP (x, 0), NULL_RTX);
- note_mem_written (XEXP (x, 0), &writes_memory);
- }
+ canon_reg (XEXP (x, 0), NULL_RTX);
}
/* Canonicalize a USE of a pseudo register or memory location. */
@@ -6290,11 +6351,13 @@ cse_insn (insn, in_libcall_block)
rtx dest = SET_DEST (sets[i].rtl);
rtx src = SET_SRC (sets[i].rtl);
rtx new = canon_reg (src, insn);
+ int insn_code;
if ((GET_CODE (new) == REG && GET_CODE (src) == REG
&& ((REGNO (new) < FIRST_PSEUDO_REGISTER)
!= (REGNO (src) < FIRST_PSEUDO_REGISTER)))
- || insn_n_dups[recog_memoized (insn)] > 0)
+ || (insn_code = recog_memoized (insn)) < 0
+ || insn_n_dups[insn_code] > 0)
validate_change (insn, &SET_SRC (sets[i].rtl), new, 1);
else
SET_SRC (sets[i].rtl) = new;
@@ -6429,6 +6492,21 @@ cse_insn (insn, in_libcall_block)
sets[i].src_in_memory = hash_arg_in_memory;
sets[i].src_in_struct = hash_arg_in_struct;
+ /* If SRC is a MEM, there is a REG_EQUIV note for SRC, and DEST is
+ a pseudo that is set more than once, do not record SRC. Using
+ SRC as a replacement for anything else will be incorrect in that
+ situation. Note that this usually occurs only for stack slots,
+ in which case all the RTL would be referring to SRC, so we don't
+ lose any optimization opportunities by not having SRC in the
+ hash table. */
+
+ if (GET_CODE (src) == MEM
+ && find_reg_note (insn, REG_EQUIV, src) != 0
+ && GET_CODE (dest) == REG
+ && REGNO (dest) >= FIRST_PSEUDO_REGISTER
+ && REG_N_SETS (REGNO (dest)) != 1)
+ sets[i].src_volatile = 1;
+
#if 0
/* It is no longer clear why we used to do this, but it doesn't
appear to still be needed. So let's try without it since this
@@ -6596,7 +6674,7 @@ cse_insn (insn, in_libcall_block)
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
{
enum machine_mode tmode;
- rtx new_and = gen_rtx (AND, VOIDmode, NULL_RTX, XEXP (src, 1));
+ rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1));
for (tmode = GET_MODE_WIDER_MODE (mode);
GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
@@ -6699,6 +6777,18 @@ cse_insn (insn, in_libcall_block)
if (code != REG && ! exp_equiv_p (p->exp, p->exp, 1, 0))
continue;
+ /* Also skip paradoxical subregs, unless that's what we're
+ looking for. */
+ if (code == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (p->exp))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp))))
+ && ! (src != 0
+ && GET_CODE (src) == SUBREG
+ && GET_MODE (src) == GET_MODE (p->exp)
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (p->exp))))))
+ continue;
+
if (src && GET_CODE (src) == code && rtx_equal_p (src, p->exp))
src = 0;
else if (src_folded && GET_CODE (src_folded) == code
@@ -6724,7 +6814,7 @@ cse_insn (insn, in_libcall_block)
that are when they are equal cost. Note that we can never
worsen an insn as the current contents will also succeed.
If we find an equivalent identical to the destination, use it as best,
- since this insn will probably be eliminated in that case. */
+ since this insn will probably be eliminated in that case. */
if (src)
{
if (rtx_equal_p (src, dest))
@@ -6766,12 +6856,31 @@ cse_insn (insn, in_libcall_block)
the current contents will be tested and will always be valid. */
while (1)
{
- rtx trial;
+ rtx trial, old_src;
/* Skip invalid entries. */
while (elt && GET_CODE (elt->exp) != REG
&& ! exp_equiv_p (elt->exp, elt->exp, 1, 0))
elt = elt->next_same_value;
+
+ /* A paradoxical subreg would be bad here: it'll be the right
+ size, but later may be adjusted so that the upper bits aren't
+ what we want. So reject it. */
+ if (elt != 0
+ && GET_CODE (elt->exp) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (elt->exp))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp))))
+ /* It is okay, though, if the rtx we're trying to match
+ will ignore any of the bits we can't predict. */
+ && ! (src != 0
+ && GET_CODE (src) == SUBREG
+ && GET_MODE (src) == GET_MODE (elt->exp)
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (elt->exp))))))
+ {
+ elt = elt->next_same_value;
+ continue;
+ }
if (elt) src_elt_cost = elt->cost;
@@ -6813,6 +6922,10 @@ cse_insn (insn, in_libcall_block)
insert the substitution here and we will delete and re-emit
the insn later. */
+ /* Keep track of the original SET_SRC so that we can fix notes
+ on libcall instructions. */
+ old_src = SET_SRC (sets[i].rtl);
+
if (n_sets == 1 && dest == pc_rtx
&& (trial == pc_rtx
|| (GET_CODE (trial) == LABEL_REF
@@ -6827,7 +6940,7 @@ cse_insn (insn, in_libcall_block)
&& (GET_CODE (PATTERN (NEXT_INSN (trial))) == ADDR_DIFF_VEC
|| GET_CODE (PATTERN (NEXT_INSN (trial))) == ADDR_VEC))
- trial = gen_rtx (LABEL_REF, Pmode, get_label_after (trial));
+ trial = gen_rtx_LABEL_REF (Pmode, get_label_after (trial));
SET_SRC (sets[i].rtl) = trial;
cse_jumps_altered = 1;
@@ -6837,6 +6950,16 @@ cse_insn (insn, in_libcall_block)
/* Look for a substitution that makes a valid insn. */
else if (validate_change (insn, &SET_SRC (sets[i].rtl), trial, 0))
{
+ /* If we just made a substitution inside a libcall, then we
+ need to make the same substitution in any notes attached
+ to the RETVAL insn. */
+ if (libcall_insn
+ && (GET_CODE (old_src) == REG
+ || GET_CODE (old_src) == SUBREG
+ || GET_CODE (old_src) == MEM))
+ replace_rtx (REG_NOTES (libcall_insn), old_src,
+ canon_reg (SET_SRC (sets[i].rtl), insn));
+
/* The result of apply_change_group can be ignored; see
canon_reg. */
@@ -6859,7 +6982,8 @@ cse_insn (insn, in_libcall_block)
&& (src_folded == 0
|| (GET_CODE (src_folded) != MEM
&& ! src_folded_force_flag))
- && GET_MODE_CLASS (mode) != MODE_CC)
+ && GET_MODE_CLASS (mode) != MODE_CC
+ && mode != VOIDmode)
{
src_folded_force_flag = 1;
src_folded = trial;
@@ -6888,17 +7012,24 @@ cse_insn (insn, in_libcall_block)
SRC is a hard register. */
{
int first = qty_first_reg[reg_qty[REGNO (src)]];
-
- src = SET_SRC (sets[i].rtl)
- = first >= FIRST_PSEUDO_REGISTER ? regno_reg_rtx[first]
- : gen_rtx (REG, GET_MODE (src), first);
-
- /* If we had a constant that is cheaper than what we are now
- setting SRC to, use that constant. We ignored it when we
- thought we could make this into a no-op. */
- if (src_const && COST (src_const) < COST (src)
- && validate_change (insn, &SET_SRC (sets[i].rtl), src_const, 0))
- src = src_const;
+ rtx new_src
+ = (first >= FIRST_PSEUDO_REGISTER
+ ? regno_reg_rtx[first] : gen_rtx_REG (GET_MODE (src), first));
+
+ /* We must use validate-change even for this, because this
+ might be a special no-op instruction, suitable only to
+ tag notes onto. */
+ if (validate_change (insn, &SET_SRC (sets[i].rtl), new_src, 0))
+ {
+ src = new_src;
+ /* If we had a constant that is cheaper than what we are now
+ setting SRC to, use that constant. We ignored it when we
+ thought we could make this into a no-op. */
+ if (src_const && COST (src_const) < COST (src)
+ && validate_change (insn, &SET_SRC (sets[i].rtl), src_const,
+ 0))
+ src = src_const;
+ }
}
/* If we made a change, recompute SRC values. */
@@ -6919,9 +7050,18 @@ cse_insn (insn, in_libcall_block)
equivalent constant, we want to add a REG_NOTE. We don't want
to write a REG_EQUAL note for a constant pseudo since verifying that
that pseudo hasn't been eliminated is a pain. Such a note also
- won't help anything. */
+ won't help anything.
+
+ Avoid a REG_EQUAL note for (CONST (MINUS (LABEL_REF) (LABEL_REF)))
+ which can be created for a reference to a compile time computable
+ entry in a jump table. */
+
if (n_sets == 1 && src_const && GET_CODE (dest) == REG
- && GET_CODE (src_const) != REG)
+ && GET_CODE (src_const) != REG
+ && ! (GET_CODE (src_const) == CONST
+ && GET_CODE (XEXP (src_const, 0)) == MINUS
+ && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
+ && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
{
tem = find_reg_note (insn, REG_EQUAL, NULL_RTX);
@@ -6930,8 +7070,8 @@ cse_insn (insn, in_libcall_block)
if (tem)
XEXP (tem, 0) = src_const;
else
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL,
- src_const, REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL,
+ src_const, REG_NOTES (insn));
/* If storing a constant value in a register that
previously held the constant value 0,
@@ -6957,8 +7097,9 @@ cse_insn (insn, in_libcall_block)
if (note)
XEXP (note, 0) = const_insn;
else
- REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_WAS_0,
- const_insn, REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_WAS_0,
+ const_insn,
+ REG_NOTES (insn));
}
}
}
@@ -6982,13 +7123,15 @@ cse_insn (insn, in_libcall_block)
if (GET_CODE (dest) == MEM)
{
+#ifdef PUSH_ROUNDING
+ /* Stack pushes invalidate the stack pointer. */
+ rtx addr = XEXP (dest, 0);
+ if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
+ || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
+ && XEXP (addr, 0) == stack_pointer_rtx)
+ invalidate (stack_pointer_rtx, Pmode);
+#endif
dest = fold_rtx (dest, insn);
-
- /* Decide whether we invalidate everything in memory,
- or just things at non-fixed places.
- Writing a large aggregate must invalidate everything
- because we don't know how long it is. */
- note_mem_written (dest, &writes_memory);
}
/* Compute the hash code of the destination now,
@@ -7036,7 +7179,8 @@ cse_insn (insn, in_libcall_block)
NOTE_SOURCE_FILE (insn) = 0;
cse_jumps_altered = 1;
/* One less use of the label this insn used to jump to. */
- --LABEL_NUSES (JUMP_LABEL (insn));
+ if (JUMP_LABEL (insn) != 0)
+ --LABEL_NUSES (JUMP_LABEL (insn));
/* No more processing for this set. */
sets[i].rtl = 0;
}
@@ -7133,8 +7277,8 @@ cse_insn (insn, in_libcall_block)
this_insn_cc0 = src_const && mode != VOIDmode ? src_const : src;
this_insn_cc0_mode = mode;
if (FLOAT_MODE_P (mode))
- this_insn_cc0 = gen_rtx (COMPARE, VOIDmode, this_insn_cc0,
- CONST0_RTX (mode));
+ this_insn_cc0 = gen_rtx_COMPARE (VOIDmode, this_insn_cc0,
+ CONST0_RTX (mode));
}
#endif
}
@@ -7233,17 +7377,15 @@ cse_insn (insn, in_libcall_block)
so that the destination goes into that class. */
sets[i].src_elt = src_eqv_elt;
- invalidate_from_clobbers (&writes_memory, x);
+ invalidate_from_clobbers (x);
/* Some registers are invalidated by subroutine calls. Memory is
invalidated by non-constant calls. */
if (GET_CODE (insn) == CALL_INSN)
{
- static struct write_data everything = {0, 1, 1, 1};
-
if (! CONST_CALL_P (insn))
- invalidate_memory (&everything);
+ invalidate_memory ();
invalidate_for_call ();
}
@@ -7264,8 +7406,7 @@ cse_insn (insn, in_libcall_block)
Needed for memory if this is a nonvarying address, unless
we have just done an invalidate_memory that covers even those. */
if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
- || (GET_CODE (dest) == MEM && ! writes_memory.all
- && ! cse_rtx_addr_varies_p (dest)))
+ || GET_CODE (dest) == MEM)
invalidate (dest, VOIDmode);
else if (GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == ZERO_EXTRACT)
@@ -7311,6 +7452,7 @@ cse_insn (insn, in_libcall_block)
if (sets[i].rtl)
{
register rtx dest = SET_DEST (sets[i].rtl);
+ rtx inner_dest = sets[i].inner_dest;
register struct table_elt *elt;
/* Don't record value if we are not supposed to risk allocating
@@ -7319,11 +7461,15 @@ cse_insn (insn, in_libcall_block)
if ((flag_float_store
&& GET_CODE (dest) == MEM
&& FLOAT_MODE_P (GET_MODE (dest)))
+ /* Don't record BLKmode values, because we don't know the
+ size of it, and can't be sure that other BLKmode values
+ have the same or smaller size. */
+ || GET_MODE (dest) == BLKmode
/* Don't record values of destinations set inside a libcall block
since we might delete the libcall. Things should have been set
up so we won't want to reuse such a value, but we play it safe
here. */
- || in_libcall_block
+ || libcall_insn
/* If we didn't put a REG_EQUAL value or a source into the hash
table, there is no point is recording DEST. */
|| sets[i].src_elt == 0
@@ -7355,10 +7501,22 @@ cse_insn (insn, in_libcall_block)
sets[i].dest_hash = HASH (dest, GET_MODE (dest));
}
- elt = insert (dest, sets[i].src_elt,
- sets[i].dest_hash, GET_MODE (dest));
+ if (GET_CODE (inner_dest) == MEM
+ && GET_CODE (XEXP (inner_dest, 0)) == ADDRESSOF)
+ /* Given (SET (MEM (ADDRESSOF (X))) Y) we don't want to say
+ that (MEM (ADDRESSOF (X))) is equivalent to Y.
+ Consider the case in which the address of the MEM is
+ passed to a function, which alters the MEM. Then, if we
+ later use Y instead of the MEM we'll miss the update. */
+ elt = insert (dest, 0, sets[i].dest_hash, GET_MODE (dest));
+ else
+ elt = insert (dest, sets[i].src_elt,
+ sets[i].dest_hash, GET_MODE (dest));
+
elt->in_memory = (GET_CODE (sets[i].inner_dest) == MEM
- && ! RTX_UNCHANGING_P (sets[i].inner_dest));
+ && (! RTX_UNCHANGING_P (sets[i].inner_dest)
+ || FIXED_BASE_PLUS_P (XEXP (sets[i].inner_dest,
+ 0))));
if (elt->in_memory)
{
@@ -7409,7 +7567,7 @@ cse_insn (insn, in_libcall_block)
new_src = gen_lowpart_if_possible (new_mode, elt->exp);
if (new_src == 0)
- new_src = gen_rtx (SUBREG, new_mode, elt->exp, 0);
+ new_src = gen_rtx_SUBREG (new_mode, elt->exp, 0);
src_hash = HASH (new_src, new_mode);
src_elt = lookup (new_src, src_hash, new_mode);
@@ -7433,6 +7591,11 @@ cse_insn (insn, in_libcall_block)
merge_equiv_classes (src_elt, classp);
classp = src_elt->first_same_value;
+ /* Ignore invalid entries. */
+ while (classp
+ && GET_CODE (classp->exp) != REG
+ && ! exp_equiv_p (classp->exp, classp->exp, 1, 0))
+ classp = classp->next_same_value;
}
}
}
@@ -7531,51 +7694,43 @@ cse_insn (insn, in_libcall_block)
prev_insn = insn;
}
-/* Store 1 in *WRITES_PTR for those categories of memory ref
- that must be invalidated when the expression WRITTEN is stored in.
- If WRITTEN is null, say everything must be invalidated. */
-
+/* Remove from the ahsh table all expressions that reference memory. */
static void
-note_mem_written (written, writes_ptr)
- rtx written;
- struct write_data *writes_ptr;
+invalidate_memory ()
{
- static struct write_data everything = {0, 1, 1, 1};
+ register int i;
+ register struct table_elt *p, *next;
+
+ for (i = 0; i < NBUCKETS; i++)
+ for (p = table[i]; p; p = next)
+ {
+ next = p->next_same_hash;
+ if (p->in_memory)
+ remove_from_table (p, i);
+ }
+}
- if (written == 0)
- *writes_ptr = everything;
- else if (GET_CODE (written) == MEM)
+/* XXX ??? The name of this function bears little resemblance to
+ what this function actually does. FIXME. */
+static int
+note_mem_written (addr)
+ register rtx addr;
+{
+ /* Pushing or popping the stack invalidates just the stack pointer. */
+ if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
+ || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
+ && GET_CODE (XEXP (addr, 0)) == REG
+ && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
{
- /* Pushing or popping the stack invalidates just the stack pointer. */
- rtx addr = XEXP (written, 0);
- if ((GET_CODE (addr) == PRE_DEC || GET_CODE (addr) == PRE_INC
- || GET_CODE (addr) == POST_DEC || GET_CODE (addr) == POST_INC)
- && GET_CODE (XEXP (addr, 0)) == REG
- && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
- {
- writes_ptr->sp = 1;
- return;
- }
- else if (GET_MODE (written) == BLKmode)
- *writes_ptr = everything;
- /* (mem (scratch)) means clobber everything. */
- else if (GET_CODE (addr) == SCRATCH)
- *writes_ptr = everything;
- else if (cse_rtx_addr_varies_p (written))
- {
- /* A varying address that is a sum indicates an array element,
- and that's just as good as a structure element
- in implying that we need not invalidate scalar variables.
- However, we must allow QImode aliasing of scalars, because the
- ANSI C standard allows character pointers to alias anything. */
- if (! ((MEM_IN_STRUCT_P (written)
- || GET_CODE (XEXP (written, 0)) == PLUS)
- && GET_MODE (written) != QImode))
- writes_ptr->all = 1;
- writes_ptr->nonscalar = 1;
- }
- writes_ptr->var = 1;
+ if (reg_tick[STACK_POINTER_REGNUM] >= 0)
+ reg_tick[STACK_POINTER_REGNUM]++;
+
+ /* This should be *very* rare. */
+ if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
+ invalidate (stack_pointer_rtx, VOIDmode);
+ return 1;
}
+ return 0;
}
/* Perform invalidation on the basis of everything about an insn
@@ -7583,38 +7738,19 @@ note_mem_written (written, writes_ptr)
This includes the places CLOBBERed, and anything that might
alias with something that is SET or CLOBBERed.
- W points to the writes_memory for this insn, a struct write_data
- saying which kinds of memory references must be invalidated.
X is the pattern of the insn. */
static void
-invalidate_from_clobbers (w, x)
- struct write_data *w;
+invalidate_from_clobbers (x)
rtx x;
{
- /* If W->var is not set, W specifies no action.
- If W->all is set, this step gets all memory refs
- so they can be ignored in the rest of this function. */
- if (w->var)
- invalidate_memory (w);
-
- if (w->sp)
- {
- if (reg_tick[STACK_POINTER_REGNUM] >= 0)
- reg_tick[STACK_POINTER_REGNUM]++;
-
- /* This should be *very* rare. */
- if (TEST_HARD_REG_BIT (hard_regs_in_table, STACK_POINTER_REGNUM))
- invalidate (stack_pointer_rtx, VOIDmode);
- }
-
if (GET_CODE (x) == CLOBBER)
{
rtx ref = XEXP (x, 0);
if (ref)
{
if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
- || (GET_CODE (ref) == MEM && ! w->all))
+ || GET_CODE (ref) == MEM)
invalidate (ref, VOIDmode);
else if (GET_CODE (ref) == STRICT_LOW_PART
|| GET_CODE (ref) == ZERO_EXTRACT)
@@ -7630,15 +7766,12 @@ invalidate_from_clobbers (w, x)
if (GET_CODE (y) == CLOBBER)
{
rtx ref = XEXP (y, 0);
- if (ref)
- {
- if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
- || (GET_CODE (ref) == MEM && !w->all))
- invalidate (ref, VOIDmode);
- else if (GET_CODE (ref) == STRICT_LOW_PART
- || GET_CODE (ref) == ZERO_EXTRACT)
- invalidate (XEXP (ref, 0), GET_MODE (ref));
- }
+ if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
+ || GET_CODE (ref) == MEM)
+ invalidate (ref, VOIDmode);
+ else if (GET_CODE (ref) == STRICT_LOW_PART
+ || GET_CODE (ref) == ZERO_EXTRACT)
+ invalidate (XEXP (ref, 0), GET_MODE (ref));
}
}
}
@@ -7688,6 +7821,7 @@ cse_process_notes (x, object)
case SIGN_EXTEND:
case ZERO_EXTEND:
+ case SUBREG:
{
rtx new = cse_process_notes (XEXP (x, 0), object);
/* We don't substitute VOIDmode constants into these rtx,
@@ -7713,6 +7847,9 @@ cse_process_notes (x, object)
/* Otherwise, canonicalize this register. */
return canon_reg (x, NULL_RTX);
+
+ default:
+ break;
}
for (i = 0; i < GET_RTX_LENGTH (code); i++)
@@ -7764,23 +7901,31 @@ cse_around_loop (loop_start)
if (last_jump_equiv_class)
for (p = last_jump_equiv_class->first_same_value; p;
p = p->next_same_value)
- if (GET_CODE (p->exp) == MEM || GET_CODE (p->exp) == REG
- || (GET_CODE (p->exp) == SUBREG
- && GET_CODE (SUBREG_REG (p->exp)) == REG))
- invalidate (p->exp, VOIDmode);
- else if (GET_CODE (p->exp) == STRICT_LOW_PART
- || GET_CODE (p->exp) == ZERO_EXTRACT)
- invalidate (XEXP (p->exp, 0), GET_MODE (p->exp));
+ {
+ if (GET_CODE (p->exp) == MEM || GET_CODE (p->exp) == REG
+ || (GET_CODE (p->exp) == SUBREG
+ && GET_CODE (SUBREG_REG (p->exp)) == REG))
+ invalidate (p->exp, VOIDmode);
+ else if (GET_CODE (p->exp) == STRICT_LOW_PART
+ || GET_CODE (p->exp) == ZERO_EXTRACT)
+ invalidate (XEXP (p->exp, 0), GET_MODE (p->exp));
+ }
/* Process insns starting after LOOP_START until we hit a CALL_INSN or
a CODE_LABEL (we could handle a CALL_INSN, but it isn't worth it).
The only thing we do with SET_DEST is invalidate entries, so we
can safely process each SET in order. It is slightly less efficient
- to do so, but we only want to handle the most common cases. */
+ to do so, but we only want to handle the most common cases.
+
+ The gen_move_insn call in cse_set_around_loop may create new pseudos.
+ These pseudos won't have valid entries in any of the tables indexed
+ by register number, such as reg_qty. We avoid out-of-range array
+ accesses by not processing any instructions created after cse started. */
for (insn = NEXT_INSN (loop_start);
GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != CODE_LABEL
+ && INSN_UID (insn) < max_insn_uid
&& ! (GET_CODE (insn) == NOTE
&& NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END);
insn = NEXT_INSN (insn))
@@ -7799,10 +7944,6 @@ cse_around_loop (loop_start)
}
}
-/* Variable used for communications between the next two routines. */
-
-static struct write_data skipped_writes_memory;
-
/* Process one SET of an insn that was skipped. We ignore CLOBBERs
since they are done elsewhere. This function is called via note_stores. */
@@ -7811,14 +7952,21 @@ invalidate_skipped_set (dest, set)
rtx set;
rtx dest;
{
- if (GET_CODE (dest) == MEM)
- note_mem_written (dest, &skipped_writes_memory);
-
- /* There are times when an address can appear varying and be a PLUS
- during this scan when it would be a fixed address were we to know
- the proper equivalences. So promote "nonscalar" to be "all". */
- if (skipped_writes_memory.nonscalar)
- skipped_writes_memory.all = 1;
+ enum rtx_code code = GET_CODE (dest);
+
+ if (code == MEM
+ && ! note_mem_written (dest) /* If this is not a stack push ... */
+ /* There are times when an address can appear varying and be a PLUS
+ during this scan when it would be a fixed address were we to know
+ the proper equivalences. So invalidate all memory if there is
+ a BLKmode or nonscalar memory reference or a reference to a
+ variable address. */
+ && (MEM_IN_STRUCT_P (dest) || GET_MODE (dest) == BLKmode
+ || cse_rtx_varies_p (XEXP (dest, 0))))
+ {
+ invalidate_memory ();
+ return;
+ }
if (GET_CODE (set) == CLOBBER
#ifdef HAVE_cc0
@@ -7827,12 +7975,10 @@ invalidate_skipped_set (dest, set)
|| dest == pc_rtx)
return;
- if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG
- || (! skipped_writes_memory.all && ! cse_rtx_addr_varies_p (dest)))
- invalidate (dest, VOIDmode);
- else if (GET_CODE (dest) == STRICT_LOW_PART
- || GET_CODE (dest) == ZERO_EXTRACT)
+ if (code == STRICT_LOW_PART || code == ZERO_EXTRACT)
invalidate (XEXP (dest, 0), GET_MODE (dest));
+ else if (code == REG || code == SUBREG || code == MEM)
+ invalidate (dest, VOIDmode);
}
/* Invalidate all insns from START up to the end of the function or the
@@ -7844,8 +7990,6 @@ invalidate_skipped_block (start)
rtx start;
{
rtx insn;
- static struct write_data init = {0, 0, 0, 0};
- static struct write_data everything = {0, 1, 1, 1};
for (insn = start; insn && GET_CODE (insn) != CODE_LABEL;
insn = NEXT_INSN (insn))
@@ -7853,16 +7997,15 @@ invalidate_skipped_block (start)
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
continue;
- skipped_writes_memory = init;
-
if (GET_CODE (insn) == CALL_INSN)
{
+ if (! CONST_CALL_P (insn))
+ invalidate_memory ();
invalidate_for_call ();
- skipped_writes_memory = everything;
}
+ invalidate_from_clobbers (PATTERN (insn));
note_stores (PATTERN (insn), invalidate_skipped_set);
- invalidate_from_clobbers (&skipped_writes_memory, PATTERN (insn));
}
}
@@ -7877,7 +8020,7 @@ static rtx cse_check_loop_start_value;
static void
cse_check_loop_start (x, set)
rtx x;
- rtx set;
+ rtx set ATTRIBUTE_UNUSED;
{
if (cse_check_loop_start_value == 0
|| GET_CODE (x) == CC0 || GET_CODE (x) == PC)
@@ -7912,10 +8055,6 @@ cse_set_around_loop (x, insn, loop_start)
rtx loop_start;
{
struct table_elt *src_elt;
- static struct write_data init = {0, 0, 0, 0};
- struct write_data writes_memory;
-
- writes_memory = init;
/* If this is a SET, see if we can replace SET_SRC, but ignore SETs that
are setting PC or CC0 or whose SET_SRC is already a register. */
@@ -7966,24 +8105,35 @@ cse_set_around_loop (x, insn, loop_start)
if (cse_check_loop_start_value
&& validate_change (insn, &SET_SRC (x),
src_elt->exp, 0))
- emit_insn_after (gen_move_insn (src_elt->exp,
- SET_DEST (set)),
- p);
+ {
+ /* If this creates new pseudos, this is unsafe,
+ because the regno of new pseudo is unsuitable
+ to index into reg_qty when cse_insn processes
+ the new insn. Therefore, if a new pseudo was
+ created, discard this optimization. */
+ int nregs = max_reg_num ();
+ rtx move
+ = gen_move_insn (src_elt->exp, SET_DEST (set));
+ if (nregs != max_reg_num ())
+ {
+ if (! validate_change (insn, &SET_SRC (x),
+ SET_SRC (set), 0))
+ abort ();
+ }
+ else
+ emit_insn_after (move, p);
+ }
break;
}
}
}
/* Now invalidate anything modified by X. */
- note_mem_written (SET_DEST (x), &writes_memory);
+ note_mem_written (SET_DEST (x));
- if (writes_memory.var)
- invalidate_memory (&writes_memory);
-
- /* See comment on similar code in cse_insn for explanation of these tests. */
+ /* See comment on similar code in cse_insn for explanation of these tests. */
if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG
- || (GET_CODE (SET_DEST (x)) == MEM && ! writes_memory.all
- && ! cse_rtx_addr_varies_p (SET_DEST (x))))
+ || GET_CODE (SET_DEST (x)) == MEM)
invalidate (SET_DEST (x), VOIDmode);
else if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
|| GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
@@ -8103,6 +8253,7 @@ cse_end_of_basic_block (insn, data, follow_jumps, after_loop, skip_blocks)
&& GET_CODE (p) == JUMP_INSN
&& GET_CODE (PATTERN (p)) == SET
&& GET_CODE (SET_SRC (PATTERN (p))) == IF_THEN_ELSE
+ && JUMP_LABEL (p) != 0
&& LABEL_NUSES (JUMP_LABEL (p)) == 1
&& NEXT_INSN (JUMP_LABEL (p)) != 0)
{
@@ -8233,9 +8384,12 @@ cse_main (f, nregs, after_loop, file)
val.path_size = 0;
init_recog ();
+ init_alias_analysis ();
max_reg = nregs;
+ max_insn_uid = get_max_uid ();
+
all_minus_one = (int *) alloca (nregs * sizeof (int));
consec_ints = (int *) alloca (nregs * sizeof (int));
@@ -8255,7 +8409,7 @@ cse_main (f, nregs, after_loop, file)
/* Allocate scratch rtl here. cse_insn will fill in the memory reference
and change the code and mode as appropriate. */
- memory_extend_rtx = gen_rtx (ZERO_EXTEND, VOIDmode, 0);
+ memory_extend_rtx = gen_rtx_ZERO_EXTEND (VOIDmode, NULL_RTX);
#endif
/* Discard all the free elements of the previous function
@@ -8403,7 +8557,8 @@ cse_basic_block (from, to, next_branch, around_loop)
{
register rtx insn;
int to_usage = 0;
- int in_libcall_block = 0;
+ rtx libcall_insn = NULL_RTX;
+ int num_insns = 0;
/* Each of these arrays is undefined before max_reg, so only allocate
the space actually needed and adjust the start below. */
@@ -8435,7 +8590,34 @@ cse_basic_block (from, to, next_branch, around_loop)
for (insn = from; insn != to; insn = NEXT_INSN (insn))
{
- register enum rtx_code code;
+ register enum rtx_code code = GET_CODE (insn);
+ int i;
+ struct table_elt *p, *next;
+
+ /* If we have processed 1,000 insns, flush the hash table to
+ avoid extreme quadratic behavior. We must not include NOTEs
+ in the count since there may be more or them when generating
+ debugging information. If we clear the table at different
+ times, code generated with -g -O might be different than code
+ generated with -O but not -g.
+
+ ??? This is a real kludge and needs to be done some other way.
+ Perhaps for 2.9. */
+ if (code != NOTE && num_insns++ > 1000)
+ {
+ for (i = 0; i < NBUCKETS; i++)
+ for (p = table[i]; p; p = next)
+ {
+ next = p->next_same_hash;
+
+ if (GET_CODE (p->exp) == REG)
+ invalidate (p->exp, p->mode);
+ else
+ remove_from_table (p, i);
+ }
+
+ num_insns = 0;
+ }
/* See if this is a branch that is part of the path. If so, and it is
to be taken, do so. */
@@ -8460,12 +8642,13 @@ cse_basic_block (from, to, next_branch, around_loop)
}
}
- code = GET_CODE (insn);
if (GET_MODE (insn) == QImode)
PUT_MODE (insn, VOIDmode);
if (GET_RTX_CLASS (code) == 'i')
{
+ rtx p;
+
/* Process notes first so we have all notes in canonical forms when
looking for duplicate operations. */
@@ -8478,12 +8661,12 @@ cse_basic_block (from, to, next_branch, around_loop)
its destination is the result of the block and hence should be
recorded. */
- if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
- in_libcall_block = 1;
+ if (p = find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ libcall_insn = XEXP (p, 0);
else if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
- in_libcall_block = 0;
+ libcall_insn = NULL_RTX;
- cse_insn (insn, in_libcall_block);
+ cse_insn (insn, libcall_insn);
}
/* If INSN is now an unconditional jump, skip to the end of our
@@ -8619,7 +8802,13 @@ count_reg_usage (x, counts, dest, incr)
case CONST_DOUBLE:
case SYMBOL_REF:
case LABEL_REF:
- case CLOBBER:
+ return;
+
+ case CLOBBER:
+ /* If we are clobbering a MEM, mark any registers inside the address
+ as being used. */
+ if (GET_CODE (XEXP (x, 0)) == MEM)
+ count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
return;
case SET:
@@ -8655,10 +8844,13 @@ count_reg_usage (x, counts, dest, incr)
case EXPR_LIST:
case INSN_LIST:
if (REG_NOTE_KIND (x) == REG_EQUAL
- || GET_CODE (XEXP (x,0)) == USE)
+ || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE))
count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
return;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -8675,21 +8867,23 @@ count_reg_usage (x, counts, dest, incr)
/* Scan all the insns and delete any that are dead; i.e., they store a register
that is never used or they copy a register to itself.
- This is used to remove insns made obviously dead by cse. It improves the
- heuristics in loop since it won't try to move dead invariants out of loops
- or make givs for dead quantities. The remaining passes of the compilation
- are also sped up. */
+ This is used to remove insns made obviously dead by cse, loop or other
+ optimizations. It improves the heuristics in loop since it won't try to
+ move dead invariants out of loops or make givs for dead quantities. The
+ remaining passes of the compilation are also sped up. */
void
-delete_dead_from_cse (insns, nreg)
+delete_trivially_dead_insns (insns, nreg)
rtx insns;
int nreg;
{
int *counts = (int *) alloca (nreg * sizeof (int));
rtx insn, prev;
+#ifdef HAVE_cc0
rtx tem;
+#endif
int i;
- int in_libcall = 0;
+ int in_libcall = 0, dead_libcall = 0;
/* First count the number of times each register is used. */
bzero ((char *) counts, sizeof (int) * nreg);
@@ -8702,17 +8896,41 @@ delete_dead_from_cse (insns, nreg)
for (insn = prev_real_insn (get_last_insn ()); insn; insn = prev)
{
int live_insn = 0;
+ rtx note;
prev = prev_real_insn (insn);
- /* Don't delete any insns that are part of a libcall block.
+ /* Don't delete any insns that are part of a libcall block unless
+ we can delete the whole libcall block.
+
Flow or loop might get confused if we did that. Remember
that we are scanning backwards. */
if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
- in_libcall = 1;
+ {
+ in_libcall = 1;
+ live_insn = 1;
+ dead_libcall = 0;
- if (in_libcall)
- live_insn = 1;
+ /* See if there's a REG_EQUAL note on this insn and try to
+ replace the source with the REG_EQUAL expression.
+
+ We assume that insns with REG_RETVALs can only be reg->reg
+ copies at this point. */
+ note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+ if (note)
+ {
+ rtx set = single_set (insn);
+ if (set
+ && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0))
+ {
+ remove_note (insn,
+ find_reg_note (insn, REG_RETVAL, NULL_RTX));
+ dead_libcall = 1;
+ }
+ }
+ }
+ else if (in_libcall)
+ live_insn = ! dead_libcall;
else if (GET_CODE (PATTERN (insn)) == SET)
{
if (GET_CODE (SET_DEST (PATTERN (insn))) == REG
@@ -8774,6 +8992,9 @@ delete_dead_from_cse (insns, nreg)
}
if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
- in_libcall = 0;
+ {
+ in_libcall = 0;
+ dead_libcall = 0;
+ }
}
}
diff --git a/contrib/gcc/cstamp-h.in b/contrib/gcc/cstamp-h.in
new file mode 100644
index 0000000..9788f70
--- /dev/null
+++ b/contrib/gcc/cstamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/contrib/gcc/dbxout.c b/contrib/gcc/dbxout.c
index e322614..5e6f2a9 100644
--- a/contrib/gcc/dbxout.c
+++ b/contrib/gcc/dbxout.c
@@ -1,5 +1,5 @@
/* Output dbx-format symbol table information from GNU compiler.
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -67,11 +67,9 @@ Boston, MA 02111-1307, USA. */
For more on data type definitions, see `dbxout_type'. */
-/* Include these first, because they may define MIN and MAX. */
-#include <stdio.h>
-#include <errno.h>
-
#include "config.h"
+#include "system.h"
+
#include "tree.h"
#include "rtl.h"
#include "flags.h"
@@ -80,10 +78,8 @@ Boston, MA 02111-1307, USA. */
#include "reload.h"
#include "defaults.h"
#include "output.h" /* ASM_OUTPUT_SOURCE_LINE may refer to sdb functions. */
-
-#ifndef errno
-extern int errno;
-#endif
+#include "dbxout.h"
+#include "toplev.h"
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
@@ -127,9 +123,27 @@ extern int errno;
#endif
/* Nonzero means if the type has methods, only output debugging
- information if methods are actually written to the asm file. */
+ information if methods are actually written to the asm file. This
+ optimization only works if the debugger can detect the special C++
+ marker. */
+
+#define MINIMAL_DEBUG 1
+
+#ifdef NO_DOLLAR_IN_LABEL
+#ifdef NO_DOT_IN_LABEL
+#undef MINIMAL_DEBUG
+#define MINIMAL_DEBUG 0
+#endif
+#endif
+
+char *getpwd ();
-static int flag_minimal_debug = 1;
+/* Typical USG systems don't have stab.h, and they also have
+ no use for DBX-format debugging info. */
+
+#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
+
+static int flag_minimal_debug = MINIMAL_DEBUG;
/* Nonzero if we have actually used any of the GDB extensions
to the debugging format. The idea is that we use them for the
@@ -143,29 +157,24 @@ static int have_used_extensions = 0;
static int source_label_number = 1;
-char *getpwd ();
-
-/* Typical USG systems don't have stab.h, and they also have
- no use for DBX-format debugging info. */
-
-#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
-
#ifdef DEBUG_SYMS_TEXT
#define FORCE_TEXT text_section ();
#else
#define FORCE_TEXT
#endif
-#if defined (USG) || defined (NO_STAB_H)
-#include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */
+/* If there is a system stabs.h, use it. Otherwise, use our own. */
+
+#ifndef HAVE_STABS_H
+#include "gstab.h"
#else
-#include <stab.h> /* On BSD, use the system's stab.h. */
+#include <stab.h>
/* This is a GNU extension we need to reference in this file. */
#ifndef N_CATCH
#define N_CATCH 0x54
#endif
-#endif /* not USG */
+#endif
#ifdef __GNU_STAB__
#define STAB_CODE_TYPE enum __stab_debug_code
@@ -205,15 +214,28 @@ static char *cwd;
enum typestatus {TYPE_UNSEEN, TYPE_XREF, TYPE_DEFINED};
-/* Vector recording the status of describing C data types.
+/* Structure recording information about a C data type.
+ The status element says whether we have yet output
+ the definition of the type. TYPE_XREF says we have
+ output it as a cross-reference only.
+ The file_number and type_number elements are used if DBX_USE_BINCL
+ is defined. */
+
+struct typeinfo
+{
+ enum typestatus status;
+#ifdef DBX_USE_BINCL
+ int file_number;
+ int type_number;
+#endif
+};
+
+/* Vector recording information about C data types.
When we first notice a data type (a tree node),
we assign it a number using next_type_number.
- That is its index in this vector.
- The vector element says whether we have yet output
- the definition of the type. TYPE_XREF says we have
- output it as a cross-reference only. */
+ That is its index in this vector. */
-enum typestatus *typevec;
+struct typeinfo *typevec;
/* Number of elements of space allocated in `typevec'. */
@@ -225,6 +247,29 @@ static int typevec_len;
static int next_type_number;
+#ifdef DBX_USE_BINCL
+
+/* When using N_BINCL in dbx output, each type number is actually a
+ pair of the file number and the type number within the file.
+ This is a stack of input files. */
+
+struct dbx_file
+{
+ struct dbx_file *next;
+ int file_number;
+ int next_type_number;
+};
+
+/* This is the top of the stack. */
+
+static struct dbx_file *current_file;
+
+/* This is the next file number to use. */
+
+static int next_file_number;
+
+#endif /* DBX_USE_BINCL */
+
/* In dbx output, we must assign symbol-blocks id numbers
in the order in which their beginnings are encountered.
We output debugging info that refers to the beginning and
@@ -275,121 +320,53 @@ static int current_sym_nchars;
void dbxout_types ();
void dbxout_args ();
void dbxout_symbol ();
-static void dbxout_type_name ();
-static void dbxout_type ();
-static void dbxout_typedefs ();
-static void dbxout_symbol_name ();
-static void dbxout_symbol_location ();
-static void dbxout_prepare_symbol ();
-static void dbxout_finish_symbol ();
-static void dbxout_continue ();
-static void print_int_cst_octal ();
-static void print_octal ();
+
+#if defined(ASM_OUTPUT_SECTION_NAME)
+static void dbxout_function_end PROTO((void));
+#endif
+static void dbxout_typedefs PROTO((tree));
+static void dbxout_type_index PROTO((tree));
+#if DBX_CONTIN_LENGTH > 0
+static void dbxout_continue PROTO((void));
+#endif
+static void dbxout_type_fields PROTO((tree));
+static void dbxout_type_method_1 PROTO((tree, char *));
+static void dbxout_type_methods PROTO((tree));
+static void dbxout_range_type PROTO((tree));
+static void dbxout_type PROTO((tree, int, int));
+static void print_int_cst_octal PROTO((tree));
+static void print_octal PROTO((unsigned HOST_WIDE_INT, int));
+static void dbxout_type_name PROTO((tree));
+static void dbxout_symbol_location PROTO((tree, tree, char *, rtx));
+static void dbxout_symbol_name PROTO((tree, char *, int));
+static void dbxout_prepare_symbol PROTO((tree));
+static void dbxout_finish_symbol PROTO((tree));
+static void dbxout_block PROTO((tree, int, tree));
+static void dbxout_really_begin_function PROTO((tree));
-#if 0 /* Not clear we will actually need this. */
-
-/* Return the absolutized filename for the given relative
- filename. Note that if that filename is already absolute, it may
- still be returned in a modified form because this routine also
- eliminates redundant slashes and single dots and eliminates double
- dots to get a shortest possible filename from the given input
- filename. The absolutization of relative filenames is made by
- assuming that the given filename is to be taken as relative to
- the first argument (cwd) or to the current directory if cwd is
- NULL. */
-
-static char *
-abspath (rel_filename)
- char *rel_filename;
+#if defined(ASM_OUTPUT_SECTION_NAME)
+static void
+dbxout_function_end ()
{
- /* Setup the current working directory as needed. */
- char *abs_buffer
- = (char *) alloca (strlen (cwd) + strlen (rel_filename) + 1);
- char *endp = abs_buffer;
- char *outp, *inp;
- char *value;
-
- /* Copy the filename (possibly preceded by the current working
- directory name) into the absolutization buffer. */
-
- {
- char *src_p;
-
- if (rel_filename[0] != '/')
- {
- src_p = cwd;
- while (*endp++ = *src_p++)
- continue;
- *(endp-1) = '/'; /* overwrite null */
- }
- src_p = rel_filename;
- while (*endp++ = *src_p++)
- continue;
- if (endp[-1] == '/')
- *endp = '\0';
-
- /* Now make a copy of abs_buffer into abs_buffer, shortening the
- filename (by taking out slashes and dots) as we go. */
-
- outp = inp = abs_buffer;
- *outp++ = *inp++; /* copy first slash */
- for (;;)
- {
- if (!inp[0])
- break;
- else if (inp[0] == '/' && outp[-1] == '/')
- {
- inp++;
- continue;
- }
- else if (inp[0] == '.' && outp[-1] == '/')
- {
- if (!inp[1])
- break;
- else if (inp[1] == '/')
- {
- inp += 2;
- continue;
- }
- else if ((inp[1] == '.') && (inp[2] == 0 || inp[2] == '/'))
- {
- inp += (inp[2] == '/') ? 3 : 2;
- outp -= 2;
- while (outp >= abs_buffer && *outp != '/')
- outp--;
- if (outp < abs_buffer)
- {
- /* Catch cases like /.. where we try to backup to a
- point above the absolute root of the logical file
- system. */
-
- fprintf (stderr, "%s: invalid file name: %s\n",
- pname, rel_filename);
- exit (1);
- }
- *++outp = '\0';
- continue;
- }
- }
- *outp++ = *inp++;
- }
-
- /* On exit, make sure that there is a trailing null, and make sure that
- the last character of the returned string is *not* a slash. */
-
- *outp = '\0';
- if (outp[-1] == '/')
- *--outp = '\0';
-
- /* Make a copy (in the heap) of the stuff left in the absolutization
- buffer and return a pointer to the copy. */
-
- value = (char *) oballoc (strlen (abs_buffer) + 1);
- strcpy (value, abs_buffer);
- return value;
+ static int scope_labelno = 0;
+ char lscope_label_name[100];
+ /* Convert Ltext into the appropriate format for local labels in case
+ the system doesn't insert underscores in front of user generated
+ labels. */
+ ASM_GENERATE_INTERNAL_LABEL (lscope_label_name, "Lscope", scope_labelno);
+ ASM_OUTPUT_INTERNAL_LABEL (asmfile, "Lscope", scope_labelno);
+ scope_labelno++;
+
+ /* By convention, GCC will mark the end of a function with an N_FUN
+ symbol and an empty string. */
+ fprintf (asmfile, "%s \"\",%d,0,0,", ASM_STABS_OP, N_FUN);
+ assemble_name (asmfile, lscope_label_name);
+ fputc ('-', asmfile);
+ assemble_name (asmfile, XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0));
+ fprintf (asmfile, "\n");
}
-#endif /* 0 */
-
+#endif /* ! NO_DBX_FUNCTION_END */
+
/* At the beginning of compilation, start writing the symbol table.
Initialize `typevec' and output the standard data types of C. */
@@ -404,7 +381,7 @@ dbxout_init (asm_file, input_file_name, syms)
asmfile = asm_file;
typevec_len = 100;
- typevec = (enum typestatus *) xmalloc (typevec_len * sizeof typevec[0]);
+ typevec = (struct typeinfo *) xmalloc (typevec_len * sizeof typevec[0]);
bzero ((char *) typevec, typevec_len * sizeof typevec[0]);
/* Convert Ltext into the appropriate format for local labels in case
@@ -464,6 +441,14 @@ dbxout_init (asm_file, input_file_name, syms)
next_type_number = 1;
next_block_number = 2;
+#ifdef DBX_USE_BINCL
+ current_file = (struct dbx_file *) xmalloc (sizeof *current_file);
+ current_file->next = NULL;
+ current_file->file_number = 0;
+ current_file->next_type_number = 1;
+ next_file_number = 1;
+#endif
+
/* Make sure that types `int' and `char' have numbers 1 and 2.
Definitions of other integer types will refer to those numbers.
(Actually it should no longer matter what their numbers are.
@@ -499,12 +484,47 @@ dbxout_typedefs (syms)
tree type = TREE_TYPE (syms);
if (TYPE_NAME (type)
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && TYPE_SIZE (type) != NULL_TREE
&& ! TREE_ASM_WRITTEN (TYPE_NAME (type)))
dbxout_symbol (TYPE_NAME (type), 0);
}
}
}
+/* Change to reading from a new source file. Generate a N_BINCL stab. */
+
+void
+dbxout_start_new_source_file (filename)
+ char *filename;
+{
+#ifdef DBX_USE_BINCL
+ struct dbx_file *n = (struct dbx_file *) xmalloc (sizeof *n);
+
+ n->next = current_file;
+ n->file_number = next_file_number++;
+ n->next_type_number = 1;
+ current_file = n;
+ fprintf (asmfile, "%s ", ASM_STABS_OP);
+ output_quoted_string (asmfile, filename);
+ fprintf (asmfile, ",%d,0,0,0\n", N_BINCL);
+#endif
+}
+
+/* Revert to reading a previous source file. Generate a N_EINCL stab. */
+
+void
+dbxout_resume_previous_source_file ()
+{
+#ifdef DBX_USE_BINCL
+ struct dbx_file *next;
+
+ fprintf (asmfile, "%s %d,0,0,0\n", ASM_STABN_OP, N_EINCL);
+ next = current_file->next;
+ free (current_file);
+ current_file = next;
+#endif
+}
+
/* Output debugging info to FILE to switch to sourcefile FILENAME. */
void
@@ -556,7 +576,7 @@ dbxout_source_line (file, filename, lineno)
/* At the end of compilation, finish writing the symbol table.
Unless you define DBX_OUTPUT_MAIN_SOURCE_FILE_END, the default is
- to do nothing. */
+ to do nothing. */
void
dbxout_finish (file, filename)
@@ -568,6 +588,23 @@ dbxout_finish (file, filename)
#endif /* DBX_OUTPUT_MAIN_SOURCE_FILE_END */
}
+/* Output the index of a type. */
+
+static void
+dbxout_type_index (type)
+ tree type;
+{
+#ifndef DBX_USE_BINCL
+ fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type));
+ CHARS (3);
+#else
+ struct typeinfo *t = &typevec[TYPE_SYMTAB_ADDRESS (type)];
+ fprintf (asmfile, "(%d,%d)", t->file_number, t->type_number);
+ CHARS (7);
+#endif
+}
+
+#if DBX_CONTIN_LENGTH > 0
/* Continue a symbol-description that gets too big.
End one symbol table entry with a double-backslash
and start a new one, eventually producing something like
@@ -586,6 +623,7 @@ dbxout_continue ()
fprintf (asmfile, "%s \"", ASM_STABS_OP);
current_sym_nchars = 0;
}
+#endif /* DBX_CONTIN_LENGTH > 0 */
/* Subroutine of `dbxout_type'. Output the type fields of TYPE.
This must be a separate function because anonymous unions require
@@ -609,12 +647,16 @@ dbxout_type_fields (type)
|| TREE_CODE (DECL_SIZE (tem)) != INTEGER_CST))
continue;
/* Omit here the nameless fields that are used to skip bits. */
+ else if (DECL_IGNORED_P (tem))
+ continue;
else if (TREE_CODE (tem) != CONST_DECL)
{
/* Continue the line if necessary,
but not before the first field. */
if (tem != TYPE_FIELDS (type))
- CONTIN;
+ {
+ CONTIN;
+ }
if (use_gnu_debug_info_extensions
&& flag_minimal_debug
@@ -628,8 +670,10 @@ dbxout_type_fields (type)
dbxout_type (DECL_FCONTEXT (tem), 0, 0);
fprintf (asmfile, ":");
dbxout_type (TREE_TYPE (tem), 0, 0);
- fprintf (asmfile, ",%d;",
+ fputc (',', asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
TREE_INT_CST_LOW (DECL_FIELD_BITPOS (tem)));
+ fputc (';', asmfile);
continue;
}
@@ -678,9 +722,13 @@ dbxout_type_fields (type)
}
else if (TREE_CODE (DECL_FIELD_BITPOS (tem)) == INTEGER_CST)
{
- fprintf (asmfile, ",%d,%d;",
- TREE_INT_CST_LOW (DECL_FIELD_BITPOS (tem)),
+ fputc (',', asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
+ TREE_INT_CST_LOW (DECL_FIELD_BITPOS (tem)));
+ fputc (',', asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
TREE_INT_CST_LOW (DECL_SIZE (tem)));
+ fputc (';', asmfile);
}
CHARS (23);
}
@@ -725,8 +773,9 @@ dbxout_type_method_1 (decl, debug_name)
- (debug_name - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
if (DECL_VINDEX (decl))
{
- fprintf (asmfile, "%d;",
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
TREE_INT_CST_LOW (DECL_VINDEX (decl)));
+ fputc (';', asmfile);
dbxout_type (DECL_CONTEXT (decl), 0, 0);
fprintf (asmfile, ";");
CHARS (8);
@@ -765,13 +814,7 @@ dbxout_type_methods (type)
{
static int warned;
if (!warned)
- {
warned = 1;
-#ifdef HAVE_TEMPLATES
- if (warn_template_debugging)
- warning ("dbx info for template class methods not yet supported");
-#endif
- }
return;
}
}
@@ -781,7 +824,7 @@ dbxout_type_methods (type)
sprintf(formatted_type_identifier_length, "%d", type_identifier_length);
- if (TREE_CODE (methods) == FUNCTION_DECL)
+ if (TREE_CODE (methods) != TREE_VEC)
fndecl = methods;
else if (TREE_VEC_ELT (methods, 0) != NULL_TREE)
fndecl = TREE_VEC_ELT (methods, 0);
@@ -805,7 +848,7 @@ dbxout_type_methods (type)
/* This is the "mangled" name of the method.
It encodes the argument types. */
char *debug_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl));
- int destructor = 0;
+ int show_arg_types = 0;
CONTIN;
@@ -816,10 +859,23 @@ dbxout_type_methods (type)
if (flag_minimal_debug)
{
+ char marker;
+
+ /* We can't optimize a method which uses an anonymous
+ class, because the debugger will not be able to
+ associate the arbitrary class name with the actual
+ class. */
+#ifndef NO_DOLLAR_IN_LABEL
+ marker = '$';
+#else
+ marker = '.';
+#endif
+ if (strchr (debug_name, marker))
+ show_arg_types = 1;
/* Detect ordinary methods because their mangled names
start with the operation name. */
- if (!strncmp (IDENTIFIER_POINTER (name), debug_name,
- IDENTIFIER_LENGTH (name)))
+ else if (!strncmp (IDENTIFIER_POINTER (name), debug_name,
+ IDENTIFIER_LENGTH (name)))
{
debug_name += IDENTIFIER_LENGTH (name);
if (debug_name[0] == '_' && debug_name[1] == '_')
@@ -829,7 +885,7 @@ dbxout_type_methods (type)
/* Get past const and volatile qualifiers. */
while (*method_name == 'C' || *method_name == 'V')
method_name++;
- /* Skip digits for length of type_encoding. */
+ /* Skip digits for length of type_encoding. */
while (*method_name == *length_ptr && *length_ptr)
length_ptr++, method_name++;
if (! strncmp (method_name,
@@ -846,7 +902,7 @@ dbxout_type_methods (type)
char *length_ptr = formatted_type_identifier_length;
while (*ctor_name == 'C' || *ctor_name == 'V')
ctor_name++;
- /* Skip digits for length of type_encoding. */
+ /* Skip digits for length of type_encoding. */
while (*ctor_name == *length_ptr && *length_ptr)
length_ptr++, ctor_name++;
if (!strncmp (IDENTIFIER_POINTER (type_encoding), ctor_name,
@@ -855,7 +911,7 @@ dbxout_type_methods (type)
}
/* The other alternative is a destructor. */
else
- destructor = 1;
+ show_arg_types = 1;
/* Output the operation name just once, for the first method
that we output. */
@@ -867,7 +923,7 @@ dbxout_type_methods (type)
}
}
- dbxout_type (TREE_TYPE (fndecl), 0, destructor);
+ dbxout_type (TREE_TYPE (fndecl), 0, show_arg_types);
dbxout_type_method_1 (fndecl, debug_name);
}
@@ -881,7 +937,7 @@ dbxout_type_methods (type)
/* Emit a "range" type specification, which has the form:
"r<index type>;<lower bound>;<upper bound>;".
- TYPE is an INTEGER_TYPE. */
+ TYPE is an INTEGER_TYPE. */
static void
dbxout_range_type (type)
@@ -894,18 +950,39 @@ dbxout_range_type (type)
dbxout_type (type, 0, 0); /* E.g. Pascal's ARRAY [BOOLEAN] of INTEGER */
else
{
- /* This used to say `r1' and we used to take care
- to make sure that `int' was type number 1. */
- fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (integer_type_node));
+ /* Traditionally, we made sure 'int' was type 1, and builtin types
+ were defined to be sub-ranges of int. Unfortunately, this
+ does not allow us to distinguish true sub-ranges from integer
+ types. So, instead we define integer (non-sub-range) types as
+ sub-ranges of themselves. This matters for Chill. If this isn't
+ a subrange type, then we want to define it in terms of itself.
+ However, in C, this may be an anonymous integer type, and we don't
+ want to emit debug info referring to it. Just calling
+ dbxout_type_index won't work anyways, because the type hasn't been
+ defined yet. We make this work for both cases by checked to see
+ whether this is a defined type, referring to it if it is, and using
+ 'int' otherwise. */
+ if (TYPE_SYMTAB_ADDRESS (type) != 0)
+ dbxout_type_index (type);
+ else
+ dbxout_type_index (integer_type_node);
}
if (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST)
- fprintf (asmfile, ";%d",
- TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)));
+ {
+ fputc (';', asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
+ TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)));
+ }
else
fprintf (asmfile, ";0");
- if (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST)
- fprintf (asmfile, ";%d;",
- TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)));
+ if (TYPE_MAX_VALUE (type)
+ && TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST)
+ {
+ fputc (';', asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
+ TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)));
+ fputc (';', asmfile);
+ }
else
fprintf (asmfile, ";-1;");
}
@@ -939,7 +1016,18 @@ dbxout_type (type, full, show_arg_types)
type = integer_type_node;
else
{
- type = TYPE_MAIN_VARIANT (type);
+ /* Try to find the "main variant" with the same name but not const
+ or volatile. (Since stabs does not distinguish const and volatile,
+ there is no need to make them separate types. But types with
+ different names are usefully distinguished.) */
+
+ for (tem = TYPE_MAIN_VARIANT (type); tem; tem = TYPE_NEXT_VARIANT (tem))
+ if (!TYPE_READONLY (tem) && !TYPE_VOLATILE (tem)
+ && TYPE_NAME (tem) == TYPE_NAME (type))
+ {
+ type = tem;
+ break;
+ }
if (TYPE_NAME (type)
&& TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (type)))
@@ -955,18 +1043,24 @@ dbxout_type (type, full, show_arg_types)
if (next_type_number == typevec_len)
{
- typevec =
- (enum typestatus *) xrealloc (typevec,
- typevec_len * 2 * sizeof typevec[0]);
+ typevec
+ = (struct typeinfo *) xrealloc (typevec,
+ typevec_len * 2 * sizeof typevec[0]);
bzero ((char *) (typevec + typevec_len),
typevec_len * sizeof typevec[0]);
typevec_len *= 2;
}
+
+#ifdef DBX_USE_BINCL
+ typevec[TYPE_SYMTAB_ADDRESS (type)].file_number
+ = current_file->file_number;
+ typevec[TYPE_SYMTAB_ADDRESS (type)].type_number
+ = current_file->next_type_number++;
+#endif
}
/* Output the number of this type, to refer to it. */
- fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type));
- CHARS (3);
+ dbxout_type_index (type);
#ifdef DBX_TYPE_DEFINED
if (DBX_TYPE_DEFINED (type))
@@ -976,7 +1070,7 @@ dbxout_type (type, full, show_arg_types)
/* If this type's definition has been output or is now being output,
that is all. */
- switch (typevec[TYPE_SYMTAB_ADDRESS (type)])
+ switch (typevec[TYPE_SYMTAB_ADDRESS (type)].status)
{
case TYPE_UNSEEN:
break;
@@ -1014,7 +1108,7 @@ dbxout_type (type, full, show_arg_types)
/* No way in DBX fmt to describe a variable size. */
|| TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
{
- typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF;
+ typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF;
return;
}
#endif
@@ -1027,7 +1121,14 @@ dbxout_type (type, full, show_arg_types)
/* Mark it as defined, so that if it is self-referent
we will not get into an infinite recursion of definitions. */
- typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_DEFINED;
+ typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_DEFINED;
+
+ if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+ {
+ dbxout_type (DECL_ORIGINAL_TYPE (TYPE_NAME (type)), 0, 0);
+ return;
+ }
switch (TREE_CODE (type))
{
@@ -1038,25 +1139,33 @@ dbxout_type (type, full, show_arg_types)
without saying what it is. The debugger will make it
a void type when the reference is seen, and nothing will
ever override that default. */
- fprintf (asmfile, "%d", TYPE_SYMTAB_ADDRESS (type));
- CHARS (3);
+ dbxout_type_index (type);
break;
case INTEGER_TYPE:
if (type == char_type_node && ! TREE_UNSIGNED (type))
- /* Output the type `char' as a subrange of itself!
- I don't understand this definition, just copied it
- from the output of pcc.
- This used to use `r2' explicitly and we used to
- take care to make sure that `char' was type number 2. */
- fprintf (asmfile, "r%d;0;127;", TYPE_SYMTAB_ADDRESS (type));
+ {
+ /* Output the type `char' as a subrange of itself!
+ I don't understand this definition, just copied it
+ from the output of pcc.
+ This used to use `r2' explicitly and we used to
+ take care to make sure that `char' was type number 2. */
+ fprintf (asmfile, "r");
+ dbxout_type_index (type);
+ fprintf (asmfile, ";0;127;");
+ }
+ /* This used to check if the type's precision was more than
+ HOST_BITS_PER_WIDE_INT. That is wrong since gdb uses a
+ long (it has no concept of HOST_BITS_PER_WIDE_INT). */
else if (use_gnu_debug_info_extensions
&& (TYPE_PRECISION (type) > TYPE_PRECISION (integer_type_node)
- || TYPE_PRECISION (type) > HOST_BITS_PER_WIDE_INT))
+ || TYPE_PRECISION (type) >= HOST_BITS_PER_LONG))
{
/* This used to say `r1' and we used to take care
to make sure that `int' was type number 1. */
- fprintf (asmfile, "r%d;", TYPE_SYMTAB_ADDRESS (integer_type_node));
+ fprintf (asmfile, "r");
+ dbxout_type_index (integer_type_node);
+ fprintf (asmfile, ";");
print_int_cst_octal (TYPE_MIN_VALUE (type));
fprintf (asmfile, ";");
print_int_cst_octal (TYPE_MAX_VALUE (type));
@@ -1064,33 +1173,47 @@ dbxout_type (type, full, show_arg_types)
}
else /* Output other integer types as subranges of `int'. */
dbxout_range_type (type);
- CHARS (25);
+ CHARS (22);
break;
case REAL_TYPE:
/* This used to say `r1' and we used to take care
to make sure that `int' was type number 1. */
- fprintf (asmfile, "r%d;%d;0;", TYPE_SYMTAB_ADDRESS (integer_type_node),
- int_size_in_bytes (type));
- CHARS (16);
+ fprintf (asmfile, "r");
+ dbxout_type_index (integer_type_node);
+ fputc (';', asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, int_size_in_bytes (type));
+ fputs (";0;", asmfile);
+ CHARS (13);
break;
case CHAR_TYPE:
if (use_gnu_debug_info_extensions)
- fprintf (asmfile, "@s%d;-20;",
- BITS_PER_UNIT * int_size_in_bytes (type));
+ {
+ fputs ("@s", asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
+ BITS_PER_UNIT * int_size_in_bytes (type));
+ fputs (";-20;", asmfile);
+ }
else
- /* Output the type `char' as a subrange of itself.
- That is what pcc seems to do. */
- fprintf (asmfile, "r%d;0;%d;", TYPE_SYMTAB_ADDRESS (char_type_node),
- TREE_UNSIGNED (type) ? 255 : 127);
+ {
+ /* Output the type `char' as a subrange of itself.
+ That is what pcc seems to do. */
+ fprintf (asmfile, "r");
+ dbxout_type_index (char_type_node);
+ fprintf (asmfile, ";0;%d;", TREE_UNSIGNED (type) ? 255 : 127);
+ }
CHARS (9);
break;
case BOOLEAN_TYPE:
if (use_gnu_debug_info_extensions)
- fprintf (asmfile, "@s%d;-16;",
- BITS_PER_UNIT * int_size_in_bytes (type));
+ {
+ fputs ("@s", asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
+ BITS_PER_UNIT * int_size_in_bytes (type));
+ fputs (";-16;", asmfile);
+ }
else /* Define as enumeral type (False, True) */
fprintf (asmfile, "eFalse:0,True:1,;");
CHARS (17);
@@ -1107,16 +1230,20 @@ dbxout_type (type, full, show_arg_types)
if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
{
- fprintf (asmfile, "r%d;%d;0;",
- TYPE_SYMTAB_ADDRESS (type),
+ fprintf (asmfile, "r");
+ dbxout_type_index (type);
+ fputc (';', asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
int_size_in_bytes (TREE_TYPE (type)));
- CHARS (15); /* The number is probably incorrect here. */
+ fputs (";0;", asmfile);
+ CHARS (12); /* The number is probably incorrect here. */
}
else
{
/* Output a complex integer type as a structure,
pending some other way to do it. */
- fprintf (asmfile, "s%d", int_size_in_bytes (type));
+ fputc ('s', asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, int_size_in_bytes (type));
fprintf (asmfile, "real:");
CHARS (10);
@@ -1138,10 +1265,12 @@ dbxout_type (type, full, show_arg_types)
if (use_gnu_debug_info_extensions)
{
have_used_extensions = 1;
- fprintf (asmfile, "@s%d;",
+ fputs ("@s", asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
BITS_PER_UNIT * int_size_in_bytes (type));
+ fputc (';', asmfile);
/* Check if a bitstring type, which in Chill is
- different from a [power]set. */
+ different from a [power]set. */
if (TYPE_STRING_FLAG (type))
fprintf (asmfile, "@S;");
}
@@ -1151,12 +1280,26 @@ dbxout_type (type, full, show_arg_types)
break;
case ARRAY_TYPE:
+ /* Make arrays of packed bits look like bitstrings for chill. */
+ if (TYPE_PACKED (type) && use_gnu_debug_info_extensions)
+ {
+ have_used_extensions = 1;
+ fputs ("@s", asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
+ BITS_PER_UNIT * int_size_in_bytes (type));
+ fputc (';', asmfile);
+ fprintf (asmfile, "@S;");
+ putc ('S', asmfile);
+ CHARS (1);
+ dbxout_type (TYPE_DOMAIN (type), 0, 0);
+ break;
+ }
/* Output "a" followed by a range type definition
for the index type of the array
followed by a reference to the target-type.
ar1;0;N;M for a C array of type M and size N+1. */
/* Check if a character string type, which in Chill is
- different from an array of characters. */
+ different from an array of characters. */
if (TYPE_STRING_FLAG (type) && use_gnu_debug_info_extensions)
{
have_used_extensions = 1;
@@ -1164,14 +1307,17 @@ dbxout_type (type, full, show_arg_types)
}
tem = TYPE_DOMAIN (type);
if (tem == NULL)
- fprintf (asmfile, "ar%d;0;-1;",
- TYPE_SYMTAB_ADDRESS (integer_type_node));
+ {
+ fprintf (asmfile, "ar");
+ dbxout_type_index (integer_type_node);
+ fprintf (asmfile, ";0;-1;");
+ }
else
{
fprintf (asmfile, "a");
dbxout_range_type (tem);
}
- CHARS (17);
+ CHARS (14);
dbxout_type (TREE_TYPE (type), 0, 0);
break;
@@ -1181,7 +1327,9 @@ dbxout_type (type, full, show_arg_types)
{
int i, n_baseclasses = 0;
- if (TYPE_BINFO (type) != 0 && TYPE_BINFO_BASETYPES (type) != 0)
+ if (TYPE_BINFO (type) != 0
+ && TREE_CODE (TYPE_BINFO (type)) == TREE_VEC
+ && TYPE_BINFO_BASETYPES (type) != 0)
n_baseclasses = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type));
/* Output a structure type. We must use the same test here as we
@@ -1215,12 +1363,13 @@ dbxout_type (type, full, show_arg_types)
else
fprintf (asmfile, "$$%d", anonymous_type_number++);
fprintf (asmfile, ":");
- typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF;
+ typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF;
break;
}
/* Identify record or union, and print its size. */
- fprintf (asmfile, (TREE_CODE (type) == RECORD_TYPE) ? "s%d" : "u%d",
+ fputc (((TREE_CODE (type) == RECORD_TYPE) ? 's' : 'u'), asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
int_size_in_bytes (type));
if (use_gnu_debug_info_extensions)
@@ -1244,8 +1393,9 @@ dbxout_type (type, full, show_arg_types)
putc (TREE_VIA_PUBLIC (child) ? '2'
: '0',
asmfile);
- fprintf (asmfile, "%d,",
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
TREE_INT_CST_LOW (BINFO_OFFSET (child)) * BITS_PER_UNIT);
+ fputc (',', asmfile);
CHARS (15);
dbxout_type (BINFO_TYPE (child), 0, 0);
putc (';', asmfile);
@@ -1257,9 +1407,13 @@ dbxout_type (type, full, show_arg_types)
dbxout_type_name (BINFO_TYPE (child));
putc (':', asmfile);
dbxout_type (BINFO_TYPE (child), full, 0);
- fprintf (asmfile, ",%d,%d;",
- TREE_INT_CST_LOW (BINFO_OFFSET (child)) * BITS_PER_UNIT,
+ fputc (',', asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
+ TREE_INT_CST_LOW (BINFO_OFFSET (child)) * BITS_PER_UNIT);
+ fputc (',', asmfile);
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
TREE_INT_CST_LOW (DECL_SIZE (TYPE_NAME (BINFO_TYPE (child)))) * BITS_PER_UNIT);
+ fputc (';', asmfile);
CHARS (20);
}
}
@@ -1312,7 +1466,7 @@ dbxout_type (type, full, show_arg_types)
fprintf (asmfile, "xe");
CHARS (3);
dbxout_type_name (type);
- typevec[TYPE_SYMTAB_ADDRESS (type)] = TYPE_XREF;
+ typevec[TYPE_SYMTAB_ADDRESS (type)].status = TYPE_XREF;
fprintf (asmfile, ":");
return;
}
@@ -1328,18 +1482,20 @@ dbxout_type (type, full, show_arg_types)
{
fprintf (asmfile, "%s:", IDENTIFIER_POINTER (TREE_PURPOSE (tem)));
if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == 0)
- fprintf (asmfile, "%lu",
- (unsigned long) TREE_INT_CST_LOW (TREE_VALUE (tem)));
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_UNSIGNED,
+ TREE_INT_CST_LOW (TREE_VALUE (tem)));
else if (TREE_INT_CST_HIGH (TREE_VALUE (tem)) == -1
&& TREE_INT_CST_LOW (TREE_VALUE (tem)) < 0)
- fprintf (asmfile, "%ld",
- (long) TREE_INT_CST_LOW (TREE_VALUE (tem)));
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC,
+ TREE_INT_CST_LOW (TREE_VALUE (tem)));
else
print_int_cst_octal (TREE_VALUE (tem));
fprintf (asmfile, ",");
CHARS (20 + IDENTIFIER_LENGTH (TREE_PURPOSE (tem)));
if (TREE_CHAIN (tem) != 0)
- CONTIN;
+ {
+ CONTIN;
+ }
}
putc (';', asmfile);
CHARS (1);
@@ -1363,6 +1519,7 @@ dbxout_type (type, full, show_arg_types)
/* Normally, just output the return type.
The argument types are encoded in the method name. */
putc ('#', asmfile);
+ CHARS (1);
dbxout_type (TREE_TYPE (type), 0, 0);
putc (';', asmfile);
CHARS (1);
@@ -1467,7 +1624,7 @@ print_int_cst_octal (c)
<< (HOST_BITS_PER_WIDE_INT / 3 * 3))
- 1);
- fprintf (asmfile, "%o%01o", beg, middle);
+ fprintf (asmfile, "%o%01o", (int)beg, (int)middle);
print_octal (end, HOST_BITS_PER_WIDE_INT / 3);
}
}
@@ -1480,7 +1637,7 @@ print_octal (value, digits)
int i;
for (i = digits - 1; i >= 0; i--)
- fprintf (asmfile, "%01o", ((value >> (3 * i)) & 7));
+ fprintf (asmfile, "%01o", (int)((value >> (3 * i)) & 7));
}
/* Output the name of type TYPE, with no punctuation.
@@ -1593,7 +1750,7 @@ dbxout_symbol (decl, local)
/* If this typedef name was defined by outputting the type,
don't duplicate it. */
- if (typevec[TYPE_SYMTAB_ADDRESS (type)] == TYPE_DEFINED
+ if (typevec[TYPE_SYMTAB_ADDRESS (type)].status == TYPE_DEFINED
&& TYPE_NAME (TREE_TYPE (decl)) == decl)
return;
#endif
@@ -1625,10 +1782,7 @@ dbxout_symbol (decl, local)
&& !TREE_ASM_WRITTEN (TYPE_NAME (type))
/* Distinguish the implicit typedefs of C++
from explicit ones that might be found in C. */
- && (!strcmp (lang_identify (), "cplusplus")
- /* The following line maybe unnecessary;
- in 2.6, try removing it. */
- || DECL_SOURCE_LINE (decl) == 0))
+ && DECL_ARTIFICIAL (decl))
{
tree name = TYPE_NAME (type);
if (TREE_CODE (name) == TYPE_DECL)
@@ -1653,7 +1807,10 @@ dbxout_symbol (decl, local)
if ((TREE_CODE (type) == RECORD_TYPE
|| TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
- && TYPE_NAME (type) == decl)
+ && TYPE_NAME (type) == decl
+ /* Distinguish the implicit typedefs of C++
+ from explicit ones that might be found in C. */
+ && DECL_ARTIFICIAL (decl))
{
if (use_gnu_debug_info_extensions && have_used_extensions)
{
@@ -1760,8 +1917,10 @@ dbxout_symbol (decl, local)
#ifdef DBX_OUTPUT_CONSTANT_SYMBOL
DBX_OUTPUT_CONSTANT_SYMBOL (asmfile, name, ival);
#else
- fprintf (asmfile, "%s \"%s:c=i%d\",0x%x,0,0,0\n",
- ASM_STABS_OP, name, ival, N_LSYM);
+ fprintf (asmfile, "%s \"%s:c=i", ASM_STABS_OP, name);
+
+ fprintf (asmfile, HOST_WIDE_INT_PRINT_DEC, ival);
+ fprintf (asmfile, "\",0x%x,0,0,0\n", N_LSYM);
#endif
return;
}
@@ -1781,6 +1940,10 @@ dbxout_symbol (decl, local)
#endif
dbxout_symbol_location (decl, type, 0, DECL_RTL (decl));
+ break;
+
+ default:
+ break;
}
}
@@ -1801,7 +1964,7 @@ dbxout_symbol_location (decl, type, suffix, home)
/* Don't mention a variable at all
if it was completely optimized into nothingness.
- If the decl was from an inline function, then it's rtl
+ If the decl was from an inline function, then its rtl
is not identically the rtl that was used in this
particular compilation. */
if (GET_CODE (home) == REG)
@@ -1887,7 +2050,12 @@ dbxout_symbol_location (decl, type, suffix, home)
else if (GET_CODE (home) == MEM
&& (GET_CODE (XEXP (home, 0)) == MEM
|| (GET_CODE (XEXP (home, 0)) == REG
- && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM)))
+ && REGNO (XEXP (home, 0)) != HARD_FRAME_POINTER_REGNUM
+ && REGNO (XEXP (home, 0)) != STACK_POINTER_REGNUM
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ && REGNO (XEXP (home, 0)) != ARG_POINTER_REGNUM
+#endif
+ )))
/* If the value is indirect by memory or by a register
that isn't the frame pointer
then it means the object is variable-sized and address through
@@ -2129,7 +2297,21 @@ dbxout_parms (parms)
DBX_MEMPARM_STABS_LETTER);
}
- dbxout_type (DECL_ARG_TYPE (parms), 0, 0);
+ /* It is quite tempting to use:
+
+ dbxout_type (TREE_TYPE (parms), 0, 0);
+
+ as the next statement, rather than using DECL_ARG_TYPE(), so
+ that gcc reports the actual type of the parameter, rather
+ than the promoted type. This certainly makes GDB's life
+ easier, at least for some ports. The change is a bad idea
+ however, since GDB expects to be able access the type without
+ performing any conversions. So for example, if we were
+ passing a float to an unprototyped function, gcc will store a
+ double on the stack, but if we emit a stab saying the type is a
+ float, then gdb will only read in a single value, and this will
+ produce an erropneous value. */
+ dbxout_type (DECL_ARG_TYPE (parms), 0, 0);
current_sym_value = DEBUGGER_ARG_OFFSET (current_sym_value, addr);
dbxout_finish_symbol (parms);
}
@@ -2259,6 +2441,15 @@ dbxout_parms (parms)
current_sym_value = INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1));
current_sym_addr = 0;
+ /* Make a big endian correction if the mode of the type of the
+ parameter is not the same as the mode of the rtl. */
+ if (BYTES_BIG_ENDIAN
+ && TYPE_MODE (TREE_TYPE (parms)) != GET_MODE (DECL_RTL (parms))
+ && GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (parms))) < UNITS_PER_WORD)
+ {
+ current_sym_value += UNITS_PER_WORD - GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (parms)));
+ }
+
FORCE_TEXT;
if (DECL_NAME (parms))
{
@@ -2514,5 +2705,13 @@ dbxout_function (decl)
#ifdef DBX_OUTPUT_FUNCTION_END
DBX_OUTPUT_FUNCTION_END (asmfile, decl);
#endif
+#if defined(ASM_OUTPUT_SECTION_NAME)
+ if (use_gnu_debug_info_extensions
+#if defined(NO_DBX_FUNCTION_END)
+ && ! NO_DBX_FUNCTION_END
+#endif
+ )
+ dbxout_function_end ();
+#endif
}
-#endif /* DBX_DEBUGGING_INFO */
+#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
diff --git a/contrib/gcc/dbxout.h b/contrib/gcc/dbxout.h
new file mode 100644
index 0000000..1e45fa6
--- /dev/null
+++ b/contrib/gcc/dbxout.h
@@ -0,0 +1,33 @@
+/* dbxout.h - Various declarations for functions found in dbxout.c
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+extern void dbxout_init PROTO ((FILE *, char *, tree));
+extern void dbxout_finish PROTO ((FILE *, char *));
+
+extern void dbxout_start_new_source_file PROTO ((char *));
+extern void dbxout_resume_previous_source_file PROTO ((void));
+
+extern void dbxout_symbol PROTO ((tree, int));
+extern void dbxout_parms PROTO ((tree));
+extern void dbxout_reg_parms PROTO ((tree));
+extern void dbxout_syms PROTO ((tree));
+extern void dbxout_function PROTO ((tree));
+extern void dbxout_source_line PROTO ((FILE *, char*, int));
+extern void dbxout_begin_function PROTO ((tree));
diff --git a/contrib/gcc/demangle.h b/contrib/gcc/demangle.h
index 8dcd5fd..1e1e705 100644
--- a/contrib/gcc/demangle.h
+++ b/contrib/gcc/demangle.h
@@ -1,5 +1,5 @@
/* Defs for interface to demanglers.
- Copyright 1992, 1995 Free Software Foundation, Inc.
+ Copyright 1992, 1995, 1996 Free Software Foundation, Inc.
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
@@ -21,27 +21,8 @@
#define DEMANGLE_H
#ifdef IN_GCC
-
-/* Add prototype support. */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
+#include "gansidecl.h"
#define PARAMS(ARGS) PROTO(ARGS)
-
-#ifdef __STDC__
-#define PTR void *
-#else
-#ifndef const
-#define const
-#endif
-#define PTR char *
-#endif
-
#else /* ! IN_GCC */
#include <ansidecl.h>
#endif /* IN_GCC */
@@ -51,6 +32,7 @@
#define DMGL_NO_OPTS 0 /* For readability... */
#define DMGL_PARAMS (1 << 0) /* Include function args */
#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
#define DMGL_AUTO (1 << 8)
#define DMGL_GNU (1 << 9)
@@ -95,14 +77,32 @@ extern char *
cplus_demangle PARAMS ((const char *mangled, int options));
extern int
-cplus_demangle_opname PARAMS ((char *opname, char *result, int options));
+cplus_demangle_opname PARAMS ((const char *opname, char *result, int options));
-extern char *
-cplus_mangle_opname PARAMS ((char *opname, int options));
+extern const char *
+cplus_mangle_opname PARAMS ((const char *opname, int options));
/* Note: This sets global state. FIXME if you care about multi-threading. */
extern void
set_cplus_marker_for_demangling PARAMS ((int ch));
+extern void
+do_tlink PARAMS ((char **, char **));
+
+extern void
+collect_execute PARAMS ((char *, char **, char *));
+
+extern void
+collect_exit PARAMS ((int));
+
+extern int
+collect_wait PARAMS ((char *));
+
+extern void
+dump_file PARAMS ((char *));
+
+extern int
+file_exists PARAMS ((char *));
+
#endif /* DEMANGLE_H */
diff --git a/contrib/gcc/doprint.c b/contrib/gcc/doprint.c
new file mode 100644
index 0000000..dc36254
--- /dev/null
+++ b/contrib/gcc/doprint.c
@@ -0,0 +1,286 @@
+/* Provide a version _doprnt in terms of fprintf.
+ By Kaveh Ghazi (ghazi@caip.rutgers.edu) 3/29/98
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ */
+
+#include "config.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
+#include "gansidecl.h"
+#undef _doprnt
+
+#ifdef TEST /* Make sure to use the internal one. */
+#define _doprnt my_doprnt
+#endif
+
+#define COPY_VA_INT \
+ do { \
+ const int value = abs (va_arg (ap, int)); \
+ char buf[32]; \
+ ptr++; /* Go past the asterisk. */ \
+ *sptr = '\0'; /* NULL terminate sptr. */ \
+ sprintf(buf, "%d", value); \
+ strcat(sptr, buf); \
+ while (*sptr) sptr++; \
+ } while (0)
+
+#define PRINT_CHAR(CHAR) \
+ do { \
+ putc(CHAR, stream); \
+ ptr++; \
+ total_printed++; \
+ continue; \
+ } while (0)
+
+#define PRINT_TYPE(TYPE) \
+ do { \
+ int result; \
+ TYPE value = va_arg (ap, TYPE); \
+ *sptr++ = *ptr++; /* Copy the type specifier. */ \
+ *sptr = '\0'; /* NULL terminate sptr. */ \
+ result = fprintf(stream, specifier, value); \
+ if (result == -1) \
+ return -1; \
+ else \
+ { \
+ total_printed += result; \
+ continue; \
+ } \
+ } while (0)
+
+int
+_doprnt (format, ap, stream)
+ const char * format;
+ va_list ap;
+ FILE * stream;
+{
+ const char * ptr = format;
+ char specifier[128];
+ int total_printed = 0;
+
+ while (*ptr != '\0')
+ {
+ if (*ptr != '%') /* While we have regular characters, print them. */
+ PRINT_CHAR(*ptr);
+ else /* We got a format specifier! */
+ {
+ char * sptr = specifier;
+ int wide_width = 0, short_width = 0;
+
+ *sptr++ = *ptr++; /* Copy the % and move forward. */
+
+ while (strchr ("-+ #0", *ptr)) /* Move past flags. */
+ *sptr++ = *ptr++;
+
+ if (*ptr == '*')
+ COPY_VA_INT;
+ else
+ while (isdigit(*ptr)) /* Handle explicit numeric value. */
+ *sptr++ = *ptr++;
+
+ if (*ptr == '.')
+ {
+ *sptr++ = *ptr++; /* Copy and go past the period. */
+ if (*ptr == '*')
+ COPY_VA_INT;
+ else
+ while (isdigit(*ptr)) /* Handle explicit numeric value. */
+ *sptr++ = *ptr++;
+ }
+ while (strchr ("hlL", *ptr))
+ {
+ switch (*ptr)
+ {
+ case 'h':
+ short_width = 1;
+ break;
+ case 'l':
+ wide_width++;
+ break;
+ case 'L':
+ wide_width = 2;
+ break;
+ default:
+ abort();
+ }
+ *sptr++ = *ptr++;
+ }
+
+ switch (*ptr)
+ {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ case 'c':
+ {
+ /* Short values are promoted to int, so just copy it
+ as an int and trust the C library printf to cast it
+ to the right width. */
+ if (short_width)
+ PRINT_TYPE(int);
+ else
+ {
+ switch (wide_width)
+ {
+ case 0:
+ PRINT_TYPE(int);
+ break;
+ case 1:
+ PRINT_TYPE(long);
+ break;
+ case 2:
+ default:
+#if defined(__GNUC__) || defined(HAVE_LONG_LONG)
+ PRINT_TYPE(long long);
+#else
+ PRINT_TYPE(long); /* Fake it and hope for the best. */
+#endif
+ break;
+ } /* End of switch (wide_width) */
+ } /* End of else statement */
+ } /* End of integer case */
+ break;
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ {
+ if (wide_width == 0)
+ PRINT_TYPE(double);
+ else
+ {
+#if defined(__GNUC__) || defined(HAVE_LONG_DOUBLE)
+ PRINT_TYPE(long double);
+#else
+ PRINT_TYPE(double); /* Fake it and hope for the best. */
+#endif
+ }
+ }
+ break;
+ case 's':
+ PRINT_TYPE(char *);
+ break;
+ case 'p':
+ PRINT_TYPE(void *);
+ break;
+ case '%':
+ PRINT_CHAR('%');
+ break;
+ default:
+ abort();
+ } /* End of switch (*ptr) */
+ } /* End of else statement */
+ }
+
+ return total_printed;
+}
+
+#ifdef TEST
+
+#include <math.h>
+#ifndef M_PI
+#define M_PI (3.1415926535897932385)
+#endif
+
+#define RESULT(x) do \
+{ \
+ int i = (x); \
+ printf ("printed %d characters\n", i); \
+ fflush(stdin); \
+} while (0)
+
+static int checkit PVPROTO ((const char * format, ...)) ATTRIBUTE_PRINTF_1;
+
+static int
+checkit VPROTO ((const char* format, ...))
+{
+ va_list args;
+ int result;
+
+#ifndef __STDC__
+ char *format;
+#endif
+
+ VA_START (args, format);
+
+#ifndef __STDC__
+ format = va_arg (args, char *);
+#endif
+
+ result = _doprnt (format, args, stdout);
+ va_end(args);
+
+ return result;
+}
+
+int
+main ()
+{
+ RESULT(checkit ("<%d>\n", 0x12345678));
+ RESULT(printf ("<%d>\n", 0x12345678));
+
+ RESULT(checkit ("<%200d>\n", 5));
+ RESULT(printf ("<%200d>\n", 5));
+
+ RESULT(checkit ("<%.300d>\n", 6));
+ RESULT(printf ("<%.300d>\n", 6));
+
+ RESULT(checkit ("<%100.150d>\n", 7));
+ RESULT(printf ("<%100.150d>\n", 7));
+
+ RESULT(checkit ("<%s>\n",
+ "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
+777777777777777777333333333333366666666666622222222222777777777777733333"));
+ RESULT(printf ("<%s>\n",
+ "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
+777777777777777777333333333333366666666666622222222222777777777777733333"));
+
+ RESULT(checkit ("<%f><%0+#f>%s%d%s>\n",
+ 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
+ RESULT(printf ("<%f><%0+#f>%s%d%s>\n",
+ 1.0, 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"));
+
+ RESULT(checkit ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
+ RESULT(printf ("<%4f><%.4f><%%><%4.4f>\n", M_PI, M_PI, M_PI));
+
+ RESULT(checkit ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
+ RESULT(printf ("<%*f><%.*f><%%><%*.*f>\n", 3, M_PI, 3, M_PI, 3, 3, M_PI));
+
+ RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
+ 75, 75, 75, 75, 75, 75, 75));
+ RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
+ 75, 75, 75, 75, 75, 75, 75));
+
+ RESULT(checkit ("<%d><%i><%o><%u><%x><%X><%c>\n",
+ 75, 75, 75, 75, 75, 75, 75));
+ RESULT(printf ("<%d><%i><%o><%u><%x><%X><%c>\n",
+ 75, 75, 75, 75, 75, 75, 75));
+
+ RESULT(checkit ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
+ RESULT(printf ("Testing (hd) short: <%d><%ld><%hd><%hd><%d>\n", 123, (long)234, 345, 123456789, 456));
+
+#if defined(__GNUC__) || defined (HAVE_LONG_LONG)
+ RESULT(checkit ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
+ RESULT(printf ("Testing (lld) long long: <%d><%lld><%d>\n", 123, 234234234234234234LL, 345));
+ RESULT(checkit ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
+ RESULT(printf ("Testing (Ld) long long: <%d><%Ld><%d>\n", 123, 234234234234234234LL, 345));
+#endif
+
+#if defined(__GNUC__) || defined (HAVE_LONG_DOUBLE)
+ RESULT(checkit ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
+ 1.23456, 1.234567890123456789L, 1.23456));
+ RESULT(printf ("Testing (Lf) long double: <%.20f><%.20Lf><%0+#.20f>\n",
+ 1.23456, 1.234567890123456789L, 1.23456));
+#endif
+
+ return 0;
+}
+#endif /* TEST */
diff --git a/contrib/gcc/doschk.c b/contrib/gcc/doschk.c
index 7fbb733..ad553df 100644
--- a/contrib/gcc/doschk.c
+++ b/contrib/gcc/doschk.c
@@ -251,8 +251,8 @@ display_problems ()
first_err = 1;
for (i=0; i<ecount-1; i++)
{
- if ((strcmp (elist[i]->dos_name, elist[i+1]->dos_name) == 0) &&
- (strcmp (elist[i]->path, elist[i+1]->path) == 0))
+ if ((strcmp (elist[i]->dos_name, elist[i+1]->dos_name) == 0)
+ && (strcmp (elist[i]->path, elist[i+1]->path) == 0))
{
if (first_err)
{
@@ -280,8 +280,8 @@ display_problems ()
first_err = 1;
for (i=0; i<ecount-1; i++)
{
- if ((strncmp (elist[i]->full_name, elist[i+1]->full_name, 14) == 0) &&
- (strcmp (elist[i]->path, elist[i+1]->path) == 0))
+ if ((strncmp (elist[i]->full_name, elist[i+1]->full_name, 14) == 0)
+ && (strcmp (elist[i]->path, elist[i+1]->path) == 0))
{
if (first_err)
{
diff --git a/contrib/gcc/dwarf.h b/contrib/gcc/dwarf.h
index 014a4fc..6aca017 100644
--- a/contrib/gcc/dwarf.h
+++ b/contrib/gcc/dwarf.h
@@ -180,7 +180,11 @@ enum dwarf_location_atom {
OP_CONST = 0x04,
OP_DEREF2 = 0x05,
OP_DEREF4 = 0x06,
- OP_ADD = 0x07
+ OP_ADD = 0x07,
+
+ /* GNU extensions. */
+
+ OP_MULT = 0x80
};
#define OP_LO_USER 0x80 /* implementation-defined range start */
diff --git a/contrib/gcc/dwarf2.h b/contrib/gcc/dwarf2.h
new file mode 100644
index 0000000..db19904
--- /dev/null
+++ b/contrib/gcc/dwarf2.h
@@ -0,0 +1,548 @@
+/* Declarations and definitions of codes relating to the DWARF2 symbolic
+ debugging information format.
+ Copyright (C) 1992, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Gary Funck (gary@intrepid.com). Derived from the
+ DWARF 1 implementation written by Ron Guilmette (rfg@monkeys.com).
+
+ This file is part of GNU CC.
+
+ GNU CC 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, or (at your option)
+ any later version.
+
+ GNU CC 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 GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* This file is derived from the DWARF specification (a public document)
+ Revision 2.0.0 (July 27, 1993) developed by the UNIX International
+ Programming Languages Special Interest Group (UI/PLSIG) and distributed
+ by UNIX International. Copies of this specification are available from
+ UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. */
+
+/* This file is shared between GCC and GDB, and should not contain
+ prototypes. */
+
+/* Tag names and codes. */
+
+enum dwarf_tag
+ {
+ DW_TAG_padding = 0x00,
+ DW_TAG_array_type = 0x01,
+ DW_TAG_class_type = 0x02,
+ DW_TAG_entry_point = 0x03,
+ DW_TAG_enumeration_type = 0x04,
+ DW_TAG_formal_parameter = 0x05,
+ DW_TAG_imported_declaration = 0x08,
+ DW_TAG_label = 0x0a,
+ DW_TAG_lexical_block = 0x0b,
+ DW_TAG_member = 0x0d,
+ DW_TAG_pointer_type = 0x0f,
+ DW_TAG_reference_type = 0x10,
+ DW_TAG_compile_unit = 0x11,
+ DW_TAG_string_type = 0x12,
+ DW_TAG_structure_type = 0x13,
+ DW_TAG_subroutine_type = 0x15,
+ DW_TAG_typedef = 0x16,
+ DW_TAG_union_type = 0x17,
+ DW_TAG_unspecified_parameters = 0x18,
+ DW_TAG_variant = 0x19,
+ DW_TAG_common_block = 0x1a,
+ DW_TAG_common_inclusion = 0x1b,
+ DW_TAG_inheritance = 0x1c,
+ DW_TAG_inlined_subroutine = 0x1d,
+ DW_TAG_module = 0x1e,
+ DW_TAG_ptr_to_member_type = 0x1f,
+ DW_TAG_set_type = 0x20,
+ DW_TAG_subrange_type = 0x21,
+ DW_TAG_with_stmt = 0x22,
+ DW_TAG_access_declaration = 0x23,
+ DW_TAG_base_type = 0x24,
+ DW_TAG_catch_block = 0x25,
+ DW_TAG_const_type = 0x26,
+ DW_TAG_constant = 0x27,
+ DW_TAG_enumerator = 0x28,
+ DW_TAG_file_type = 0x29,
+ DW_TAG_friend = 0x2a,
+ DW_TAG_namelist = 0x2b,
+ DW_TAG_namelist_item = 0x2c,
+ DW_TAG_packed_type = 0x2d,
+ DW_TAG_subprogram = 0x2e,
+ DW_TAG_template_type_param = 0x2f,
+ DW_TAG_template_value_param = 0x30,
+ DW_TAG_thrown_type = 0x31,
+ DW_TAG_try_block = 0x32,
+ DW_TAG_variant_part = 0x33,
+ DW_TAG_variable = 0x34,
+ DW_TAG_volatile_type = 0x35,
+ /* SGI/MIPS Extensions */
+ DW_TAG_MIPS_loop = 0x4081,
+ /* GNU extensions */
+ DW_TAG_format_label = 0x4101, /* for FORTRAN 77 and Fortran 90 */
+ DW_TAG_function_template = 0x4102, /* for C++ */
+ DW_TAG_class_template = 0x4103 /* for C++ */
+ };
+
+#define DW_TAG_lo_user 0x4080
+#define DW_TAG_hi_user 0xffff
+
+/* flag that tells whether entry has a child or not */
+#define DW_children_no 0
+#define DW_children_yes 1
+
+/* Form names and codes. */
+enum dwarf_form
+ {
+ DW_FORM_addr = 0x01,
+ DW_FORM_block2 = 0x03,
+ DW_FORM_block4 = 0x04,
+ DW_FORM_data2 = 0x05,
+ DW_FORM_data4 = 0x06,
+ DW_FORM_data8 = 0x07,
+ DW_FORM_string = 0x08,
+ DW_FORM_block = 0x09,
+ DW_FORM_block1 = 0x0a,
+ DW_FORM_data1 = 0x0b,
+ DW_FORM_flag = 0x0c,
+ DW_FORM_sdata = 0x0d,
+ DW_FORM_strp = 0x0e,
+ DW_FORM_udata = 0x0f,
+ DW_FORM_ref_addr = 0x10,
+ DW_FORM_ref1 = 0x11,
+ DW_FORM_ref2 = 0x12,
+ DW_FORM_ref4 = 0x13,
+ DW_FORM_ref8 = 0x14,
+ DW_FORM_ref_udata = 0x15,
+ DW_FORM_indirect = 0x16
+ };
+
+/* Attribute names and codes. */
+
+enum dwarf_attribute
+ {
+ DW_AT_sibling = 0x01,
+ DW_AT_location = 0x02,
+ DW_AT_name = 0x03,
+ DW_AT_ordering = 0x09,
+ DW_AT_subscr_data = 0x0a,
+ DW_AT_byte_size = 0x0b,
+ DW_AT_bit_offset = 0x0c,
+ DW_AT_bit_size = 0x0d,
+ DW_AT_element_list = 0x0f,
+ DW_AT_stmt_list = 0x10,
+ DW_AT_low_pc = 0x11,
+ DW_AT_high_pc = 0x12,
+ DW_AT_language = 0x13,
+ DW_AT_member = 0x14,
+ DW_AT_discr = 0x15,
+ DW_AT_discr_value = 0x16,
+ DW_AT_visibility = 0x17,
+ DW_AT_import = 0x18,
+ DW_AT_string_length = 0x19,
+ DW_AT_common_reference = 0x1a,
+ DW_AT_comp_dir = 0x1b,
+ DW_AT_const_value = 0x1c,
+ DW_AT_containing_type = 0x1d,
+ DW_AT_default_value = 0x1e,
+ DW_AT_inline = 0x20,
+ DW_AT_is_optional = 0x21,
+ DW_AT_lower_bound = 0x22,
+ DW_AT_producer = 0x25,
+ DW_AT_prototyped = 0x27,
+ DW_AT_return_addr = 0x2a,
+ DW_AT_start_scope = 0x2c,
+ DW_AT_stride_size = 0x2e,
+ DW_AT_upper_bound = 0x2f,
+ DW_AT_abstract_origin = 0x31,
+ DW_AT_accessibility = 0x32,
+ DW_AT_address_class = 0x33,
+ DW_AT_artificial = 0x34,
+ DW_AT_base_types = 0x35,
+ DW_AT_calling_convention = 0x36,
+ DW_AT_count = 0x37,
+ DW_AT_data_member_location = 0x38,
+ DW_AT_decl_column = 0x39,
+ DW_AT_decl_file = 0x3a,
+ DW_AT_decl_line = 0x3b,
+ DW_AT_declaration = 0x3c,
+ DW_AT_discr_list = 0x3d,
+ DW_AT_encoding = 0x3e,
+ DW_AT_external = 0x3f,
+ DW_AT_frame_base = 0x40,
+ DW_AT_friend = 0x41,
+ DW_AT_identifier_case = 0x42,
+ DW_AT_macro_info = 0x43,
+ DW_AT_namelist_items = 0x44,
+ DW_AT_priority = 0x45,
+ DW_AT_segment = 0x46,
+ DW_AT_specification = 0x47,
+ DW_AT_static_link = 0x48,
+ DW_AT_type = 0x49,
+ DW_AT_use_location = 0x4a,
+ DW_AT_variable_parameter = 0x4b,
+ DW_AT_virtuality = 0x4c,
+ DW_AT_vtable_elem_location = 0x4d,
+ /* SGI/MIPS Extensions */
+ DW_AT_MIPS_fde = 0x2001,
+ DW_AT_MIPS_loop_begin = 0x2002,
+ DW_AT_MIPS_tail_loop_begin = 0x2003,
+ DW_AT_MIPS_epilog_begin = 0x2004,
+ DW_AT_MIPS_loop_unroll_factor = 0x2005,
+ DW_AT_MIPS_software_pipeline_depth = 0x2006,
+ DW_AT_MIPS_linkage_name = 0x2007,
+ DW_AT_MIPS_stride = 0x2008,
+ DW_AT_MIPS_abstract_name = 0x2009,
+ DW_AT_MIPS_clone_origin = 0x200a,
+ DW_AT_MIPS_has_inlines = 0x200b,
+ /* GNU extensions. */
+ DW_AT_sf_names = 0x2101,
+ DW_AT_src_info = 0x2102,
+ DW_AT_mac_info = 0x2103,
+ DW_AT_src_coords = 0x2104,
+ DW_AT_body_begin = 0x2105,
+ DW_AT_body_end = 0x2106
+ };
+
+#define DW_AT_lo_user 0x2000 /* implementation-defined range start */
+#define DW_AT_hi_user 0x3ff0 /* implementation-defined range end */
+
+/* Location atom names and codes. */
+
+enum dwarf_location_atom
+ {
+ DW_OP_addr = 0x03,
+ DW_OP_deref = 0x06,
+ DW_OP_const1u = 0x08,
+ DW_OP_const1s = 0x09,
+ DW_OP_const2u = 0x0a,
+ DW_OP_const2s = 0x0b,
+ DW_OP_const4u = 0x0c,
+ DW_OP_const4s = 0x0d,
+ DW_OP_const8u = 0x0e,
+ DW_OP_const8s = 0x0f,
+ DW_OP_constu = 0x10,
+ DW_OP_consts = 0x11,
+ DW_OP_dup = 0x12,
+ DW_OP_drop = 0x13,
+ DW_OP_over = 0x14,
+ DW_OP_pick = 0x15,
+ DW_OP_swap = 0x16,
+ DW_OP_rot = 0x17,
+ DW_OP_xderef = 0x18,
+ DW_OP_abs = 0x19,
+ DW_OP_and = 0x1a,
+ DW_OP_div = 0x1b,
+ DW_OP_minus = 0x1c,
+ DW_OP_mod = 0x1d,
+ DW_OP_mul = 0x1e,
+ DW_OP_neg = 0x1f,
+ DW_OP_not = 0x20,
+ DW_OP_or = 0x21,
+ DW_OP_plus = 0x22,
+ DW_OP_plus_uconst = 0x23,
+ DW_OP_shl = 0x24,
+ DW_OP_shr = 0x25,
+ DW_OP_shra = 0x26,
+ DW_OP_xor = 0x27,
+ DW_OP_bra = 0x28,
+ DW_OP_eq = 0x29,
+ DW_OP_ge = 0x2a,
+ DW_OP_gt = 0x2b,
+ DW_OP_le = 0x2c,
+ DW_OP_lt = 0x2d,
+ DW_OP_ne = 0x2e,
+ DW_OP_skip = 0x2f,
+ DW_OP_lit0 = 0x30,
+ DW_OP_lit1 = 0x31,
+ DW_OP_lit2 = 0x32,
+ DW_OP_lit3 = 0x33,
+ DW_OP_lit4 = 0x34,
+ DW_OP_lit5 = 0x35,
+ DW_OP_lit6 = 0x36,
+ DW_OP_lit7 = 0x37,
+ DW_OP_lit8 = 0x38,
+ DW_OP_lit9 = 0x39,
+ DW_OP_lit10 = 0x3a,
+ DW_OP_lit11 = 0x3b,
+ DW_OP_lit12 = 0x3c,
+ DW_OP_lit13 = 0x3d,
+ DW_OP_lit14 = 0x3e,
+ DW_OP_lit15 = 0x3f,
+ DW_OP_lit16 = 0x40,
+ DW_OP_lit17 = 0x41,
+ DW_OP_lit18 = 0x42,
+ DW_OP_lit19 = 0x43,
+ DW_OP_lit20 = 0x44,
+ DW_OP_lit21 = 0x45,
+ DW_OP_lit22 = 0x46,
+ DW_OP_lit23 = 0x47,
+ DW_OP_lit24 = 0x48,
+ DW_OP_lit25 = 0x49,
+ DW_OP_lit26 = 0x4a,
+ DW_OP_lit27 = 0x4b,
+ DW_OP_lit28 = 0x4c,
+ DW_OP_lit29 = 0x4d,
+ DW_OP_lit30 = 0x4e,
+ DW_OP_lit31 = 0x4f,
+ DW_OP_reg0 = 0x50,
+ DW_OP_reg1 = 0x51,
+ DW_OP_reg2 = 0x52,
+ DW_OP_reg3 = 0x53,
+ DW_OP_reg4 = 0x54,
+ DW_OP_reg5 = 0x55,
+ DW_OP_reg6 = 0x56,
+ DW_OP_reg7 = 0x57,
+ DW_OP_reg8 = 0x58,
+ DW_OP_reg9 = 0x59,
+ DW_OP_reg10 = 0x5a,
+ DW_OP_reg11 = 0x5b,
+ DW_OP_reg12 = 0x5c,
+ DW_OP_reg13 = 0x5d,
+ DW_OP_reg14 = 0x5e,
+ DW_OP_reg15 = 0x5f,
+ DW_OP_reg16 = 0x60,
+ DW_OP_reg17 = 0x61,
+ DW_OP_reg18 = 0x62,
+ DW_OP_reg19 = 0x63,
+ DW_OP_reg20 = 0x64,
+ DW_OP_reg21 = 0x65,
+ DW_OP_reg22 = 0x66,
+ DW_OP_reg23 = 0x67,
+ DW_OP_reg24 = 0x68,
+ DW_OP_reg25 = 0x69,
+ DW_OP_reg26 = 0x6a,
+ DW_OP_reg27 = 0x6b,
+ DW_OP_reg28 = 0x6c,
+ DW_OP_reg29 = 0x6d,
+ DW_OP_reg30 = 0x6e,
+ DW_OP_reg31 = 0x6f,
+ DW_OP_breg0 = 0x70,
+ DW_OP_breg1 = 0x71,
+ DW_OP_breg2 = 0x72,
+ DW_OP_breg3 = 0x73,
+ DW_OP_breg4 = 0x74,
+ DW_OP_breg5 = 0x75,
+ DW_OP_breg6 = 0x76,
+ DW_OP_breg7 = 0x77,
+ DW_OP_breg8 = 0x78,
+ DW_OP_breg9 = 0x79,
+ DW_OP_breg10 = 0x7a,
+ DW_OP_breg11 = 0x7b,
+ DW_OP_breg12 = 0x7c,
+ DW_OP_breg13 = 0x7d,
+ DW_OP_breg14 = 0x7e,
+ DW_OP_breg15 = 0x7f,
+ DW_OP_breg16 = 0x80,
+ DW_OP_breg17 = 0x81,
+ DW_OP_breg18 = 0x82,
+ DW_OP_breg19 = 0x83,
+ DW_OP_breg20 = 0x84,
+ DW_OP_breg21 = 0x85,
+ DW_OP_breg22 = 0x86,
+ DW_OP_breg23 = 0x87,
+ DW_OP_breg24 = 0x88,
+ DW_OP_breg25 = 0x89,
+ DW_OP_breg26 = 0x8a,
+ DW_OP_breg27 = 0x8b,
+ DW_OP_breg28 = 0x8c,
+ DW_OP_breg29 = 0x8d,
+ DW_OP_breg30 = 0x8e,
+ DW_OP_breg31 = 0x8f,
+ DW_OP_regx = 0x90,
+ DW_OP_fbreg = 0x91,
+ DW_OP_bregx = 0x92,
+ DW_OP_piece = 0x93,
+ DW_OP_deref_size = 0x94,
+ DW_OP_xderef_size = 0x95,
+ DW_OP_nop = 0x96
+ };
+
+#define DW_OP_lo_user 0x80 /* implementation-defined range start */
+#define DW_OP_hi_user 0xff /* implementation-defined range end */
+
+/* Type encodings. */
+
+enum dwarf_type
+ {
+ DW_ATE_void = 0x0,
+ DW_ATE_address = 0x1,
+ DW_ATE_boolean = 0x2,
+ DW_ATE_complex_float = 0x3,
+ DW_ATE_float = 0x4,
+ DW_ATE_signed = 0x5,
+ DW_ATE_signed_char = 0x6,
+ DW_ATE_unsigned = 0x7,
+ DW_ATE_unsigned_char = 0x8
+ };
+
+#define DW_ATE_lo_user 0x80
+#define DW_ATE_hi_user 0xff
+
+/* Array ordering names and codes. */
+enum dwarf_array_dim_ordering
+ {
+ DW_ORD_row_major = 0,
+ DW_ORD_col_major = 1
+ };
+
+/* access attribute */
+enum dwarf_access_attribute
+ {
+ DW_ACCESS_public = 1,
+ DW_ACCESS_protected = 2,
+ DW_ACCESS_private = 3
+ };
+
+/* visibility */
+enum dwarf_visibility_attribute
+ {
+ DW_VIS_local = 1,
+ DW_VIS_exported = 2,
+ DW_VIS_qualified = 3
+ };
+
+/* virtuality */
+enum dwarf_virtuality_attribute
+ {
+ DW_VIRTUALITY_none = 0,
+ DW_VIRTUALITY_virtual = 1,
+ DW_VIRTUALITY_pure_virtual = 2
+ };
+
+/* case sensitivity */
+enum dwarf_id_case
+ {
+ DW_ID_case_sensitive = 0,
+ DW_ID_up_case = 1,
+ DW_ID_down_case = 2,
+ DW_ID_case_insensitive = 3
+ };
+
+/* calling convention */
+enum dwarf_calling_convention
+ {
+ DW_CC_normal = 0x1,
+ DW_CC_program = 0x2,
+ DW_CC_nocall = 0x3
+ };
+
+#define DW_CC_lo_user 0x40
+#define DW_CC_hi_user 0xff
+
+/* inline attribute */
+enum dwarf_inline_attribute
+ {
+ DW_INL_not_inlined = 0,
+ DW_INL_inlined = 1,
+ DW_INL_declared_not_inlined = 2,
+ DW_INL_declared_inlined = 3
+ };
+
+/* discriminant lists */
+enum dwarf_discrim_list
+ {
+ DW_DSC_label = 0,
+ DW_DSC_range = 1
+ };
+
+/* line number opcodes */
+enum dwarf_line_number_ops
+ {
+ DW_LNS_extended_op = 0,
+ DW_LNS_copy = 1,
+ DW_LNS_advance_pc = 2,
+ DW_LNS_advance_line = 3,
+ DW_LNS_set_file = 4,
+ DW_LNS_set_column = 5,
+ DW_LNS_negate_stmt = 6,
+ DW_LNS_set_basic_block = 7,
+ DW_LNS_const_add_pc = 8,
+ DW_LNS_fixed_advance_pc = 9
+ };
+
+/* line number extended opcodes */
+enum dwarf_line_number_x_ops
+ {
+ DW_LNE_end_sequence = 1,
+ DW_LNE_set_address = 2,
+ DW_LNE_define_file = 3
+ };
+
+/* call frame information */
+enum dwarf_call_frame_info
+ {
+ DW_CFA_advance_loc = 0x40,
+ DW_CFA_offset = 0x80,
+ DW_CFA_restore = 0xc0,
+ DW_CFA_nop = 0x00,
+ DW_CFA_set_loc = 0x01,
+ DW_CFA_advance_loc1 = 0x02,
+ DW_CFA_advance_loc2 = 0x03,
+ DW_CFA_advance_loc4 = 0x04,
+ DW_CFA_offset_extended = 0x05,
+ DW_CFA_restore_extended = 0x06,
+ DW_CFA_undefined = 0x07,
+ DW_CFA_same_value = 0x08,
+ DW_CFA_register = 0x09,
+ DW_CFA_remember_state = 0x0a,
+ DW_CFA_restore_state = 0x0b,
+ DW_CFA_def_cfa = 0x0c,
+ DW_CFA_def_cfa_register = 0x0d,
+ DW_CFA_def_cfa_offset = 0x0e,
+ /* SGI/MIPS specific */
+ DW_CFA_MIPS_advance_loc8 = 0x1d,
+
+ /* GNU extensions */
+ DW_CFA_GNU_window_save = 0x2d,
+ DW_CFA_GNU_args_size = 0x2e
+ };
+
+#define DW_CIE_ID 0xffffffff
+#define DW_CIE_VERSION 1
+
+#define DW_CFA_extended 0
+#define DW_CFA_low_user 0x1c
+#define DW_CFA_high_user 0x3f
+
+#define DW_CHILDREN_no 0x00
+#define DW_CHILDREN_yes 0x01
+
+#define DW_ADDR_none 0
+
+/* Source language names and codes. */
+
+enum dwarf_source_language
+ {
+ DW_LANG_C89 = 0x0001,
+ DW_LANG_C = 0x0002,
+ DW_LANG_Ada83 = 0x0003,
+ DW_LANG_C_plus_plus = 0x0004,
+ DW_LANG_Cobol74 = 0x0005,
+ DW_LANG_Cobol85 = 0x0006,
+ DW_LANG_Fortran77 = 0x0007,
+ DW_LANG_Fortran90 = 0x0008,
+ DW_LANG_Pascal83 = 0x0009,
+ DW_LANG_Modula2 = 0x000a,
+ DW_LANG_Mips_Assembler = 0x8001
+ };
+
+
+#define DW_LANG_lo_user 0x8000 /* implementation-defined range start */
+#define DW_LANG_hi_user 0xffff /* implementation-defined range start */
+
+/* Names and codes for macro information. */
+
+enum dwarf_macinfo_record_type
+ {
+ DW_MACINFO_define = 1,
+ DW_MACINFO_undef = 2,
+ DW_MACINFO_start_file = 3,
+ DW_MACINFO_end_file = 4,
+ DW_MACINFO_vendor_ext = 255
+ };
diff --git a/contrib/gcc/dwarf2out.c b/contrib/gcc/dwarf2out.c
new file mode 100644
index 0000000..b72d861
--- /dev/null
+++ b/contrib/gcc/dwarf2out.c
@@ -0,0 +1,9884 @@
+/* Output Dwarf2 format symbol table information from the GNU C compiler.
+ Copyright (C) 1992, 93, 95, 96, 97, 1998 Free Software Foundation, Inc.
+ Contributed by Gary Funck (gary@intrepid.com).
+ Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
+ Extensively modified by Jason Merrill (jason@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The first part of this file deals with the DWARF 2 frame unwind
+ information, which is also used by the GCC efficient exception handling
+ mechanism. The second part, controlled only by an #ifdef
+ DWARF2_DEBUGGING_INFO, deals with the other DWARF 2 debugging
+ information. */
+
+#include "config.h"
+#include "system.h"
+#include "defaults.h"
+#include "tree.h"
+#include "flags.h"
+#include "rtl.h"
+#include "hard-reg-set.h"
+#include "regs.h"
+#include "insn-config.h"
+#include "reload.h"
+#include "output.h"
+#include "expr.h"
+#include "except.h"
+#include "dwarf2.h"
+#include "dwarf2out.h"
+#include "toplev.h"
+#include "dyn-string.h"
+
+/* We cannot use <assert.h> in GCC source, since that would include
+ GCC's assert.h, which may not be compatible with the host compiler. */
+#undef assert
+#ifdef NDEBUG
+# define assert(e)
+#else
+# define assert(e) do { if (! (e)) abort (); } while (0)
+#endif
+
+/* Decide whether we want to emit frame unwind information for the current
+ translation unit. */
+
+int
+dwarf2out_do_frame ()
+{
+ return (write_symbols == DWARF2_DEBUG
+#ifdef DWARF2_FRAME_INFO
+ || DWARF2_FRAME_INFO
+#endif
+#ifdef DWARF2_UNWIND_INFO
+ || (flag_exceptions && ! exceptions_via_longjmp)
+#endif
+ );
+}
+
+#if defined (DWARF2_DEBUGGING_INFO) || defined (DWARF2_UNWIND_INFO)
+
+#ifndef __GNUC__
+#define inline
+#endif
+
+/* How to start an assembler comment. */
+#ifndef ASM_COMMENT_START
+#define ASM_COMMENT_START ";#"
+#endif
+
+typedef struct dw_cfi_struct *dw_cfi_ref;
+typedef struct dw_fde_struct *dw_fde_ref;
+typedef union dw_cfi_oprnd_struct *dw_cfi_oprnd_ref;
+
+/* Call frames are described using a sequence of Call Frame
+ Information instructions. The register number, offset
+ and address fields are provided as possible operands;
+ their use is selected by the opcode field. */
+
+typedef union dw_cfi_oprnd_struct
+{
+ unsigned long dw_cfi_reg_num;
+ long int dw_cfi_offset;
+ char *dw_cfi_addr;
+}
+dw_cfi_oprnd;
+
+typedef struct dw_cfi_struct
+{
+ dw_cfi_ref dw_cfi_next;
+ enum dwarf_call_frame_info dw_cfi_opc;
+ dw_cfi_oprnd dw_cfi_oprnd1;
+ dw_cfi_oprnd dw_cfi_oprnd2;
+}
+dw_cfi_node;
+
+/* All call frame descriptions (FDE's) in the GCC generated DWARF
+ refer to a single Common Information Entry (CIE), defined at
+ the beginning of the .debug_frame section. This used of a single
+ CIE obviates the need to keep track of multiple CIE's
+ in the DWARF generation routines below. */
+
+typedef struct dw_fde_struct
+{
+ char *dw_fde_begin;
+ char *dw_fde_current_label;
+ char *dw_fde_end;
+ dw_cfi_ref dw_fde_cfi;
+}
+dw_fde_node;
+
+/* Maximum size (in bytes) of an artificially generated label. */
+#define MAX_ARTIFICIAL_LABEL_BYTES 30
+
+/* Make sure we know the sizes of the various types dwarf can describe. These
+ are only defaults. If the sizes are different for your target, you should
+ override these values by defining the appropriate symbols in your tm.h
+ file. */
+
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+#ifndef PTR_SIZE
+#define PTR_SIZE (POINTER_SIZE / BITS_PER_UNIT)
+#endif
+
+/* The size in bytes of a DWARF field indicating an offset or length
+ relative to a debug info section, specified to be 4 bytes in the DWARF-2
+ specification. The SGI/MIPS ABI defines it to be the same as PTR_SIZE. */
+
+#ifndef DWARF_OFFSET_SIZE
+#define DWARF_OFFSET_SIZE 4
+#endif
+
+#define DWARF_VERSION 2
+
+/* Round SIZE up to the nearest BOUNDARY. */
+#define DWARF_ROUND(SIZE,BOUNDARY) \
+ (((SIZE) + (BOUNDARY) - 1) & ~((BOUNDARY) - 1))
+
+/* Offsets recorded in opcodes are a multiple of this alignment factor. */
+#ifdef STACK_GROWS_DOWNWARD
+#define DWARF_CIE_DATA_ALIGNMENT (-UNITS_PER_WORD)
+#else
+#define DWARF_CIE_DATA_ALIGNMENT UNITS_PER_WORD
+#endif
+
+/* A pointer to the base of a table that contains frame description
+ information for each routine. */
+static dw_fde_ref fde_table;
+
+/* Number of elements currently allocated for fde_table. */
+static unsigned fde_table_allocated;
+
+/* Number of elements in fde_table currently in use. */
+static unsigned fde_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ fde_table. */
+#define FDE_TABLE_INCREMENT 256
+
+/* A list of call frame insns for the CIE. */
+static dw_cfi_ref cie_cfi_head;
+
+/* The number of the current function definition for which debugging
+ information is being generated. These numbers range from 1 up to the
+ maximum number of function definitions contained within the current
+ compilation unit. These numbers are used to create unique label id's
+ unique to each function definition. */
+static unsigned current_funcdef_number = 0;
+
+/* Some DWARF extensions (e.g., MIPS/SGI) implement a subprogram
+ attribute that accelerates the lookup of the FDE associated
+ with the subprogram. This variable holds the table index of the FDE
+ associated with the current function (body) definition. */
+static unsigned current_funcdef_fde;
+
+/* Forward declarations for functions defined in this file. */
+
+static char *stripattributes PROTO((char *));
+static char *dwarf_cfi_name PROTO((unsigned));
+static dw_cfi_ref new_cfi PROTO((void));
+static void add_cfi PROTO((dw_cfi_ref *, dw_cfi_ref));
+static unsigned long size_of_uleb128 PROTO((unsigned long));
+static unsigned long size_of_sleb128 PROTO((long));
+static void output_uleb128 PROTO((unsigned long));
+static void output_sleb128 PROTO((long));
+static void add_fde_cfi PROTO((char *, dw_cfi_ref));
+static void lookup_cfa_1 PROTO((dw_cfi_ref, unsigned long *,
+ long *));
+static void lookup_cfa PROTO((unsigned long *, long *));
+static void reg_save PROTO((char *, unsigned, unsigned,
+ long));
+static void initial_return_save PROTO((rtx));
+static void output_cfi PROTO((dw_cfi_ref, dw_fde_ref));
+static void output_call_frame_info PROTO((int));
+static unsigned reg_number PROTO((rtx));
+static void dwarf2out_stack_adjust PROTO((rtx));
+
+/* Definitions of defaults for assembler-dependent names of various
+ pseudo-ops and section names.
+ Theses may be overridden in the tm.h file (if necessary) for a particular
+ assembler. */
+
+#ifdef OBJECT_FORMAT_ELF
+#ifndef UNALIGNED_SHORT_ASM_OP
+#define UNALIGNED_SHORT_ASM_OP ".2byte"
+#endif
+#ifndef UNALIGNED_INT_ASM_OP
+#define UNALIGNED_INT_ASM_OP ".4byte"
+#endif
+#ifndef UNALIGNED_DOUBLE_INT_ASM_OP
+#define UNALIGNED_DOUBLE_INT_ASM_OP ".8byte"
+#endif
+#endif /* OBJECT_FORMAT_ELF */
+
+#ifndef ASM_BYTE_OP
+#define ASM_BYTE_OP ".byte"
+#endif
+
+/* Data and reference forms for relocatable data. */
+#define DW_FORM_data (DWARF_OFFSET_SIZE == 8 ? DW_FORM_data8 : DW_FORM_data4)
+#define DW_FORM_ref (DWARF_OFFSET_SIZE == 8 ? DW_FORM_ref8 : DW_FORM_ref4)
+
+/* Pseudo-op for defining a new section. */
+#ifndef SECTION_ASM_OP
+#define SECTION_ASM_OP ".section"
+#endif
+
+/* The default format used by the ASM_OUTPUT_SECTION macro (see below) to
+ print the SECTION_ASM_OP and the section name. The default here works for
+ almost all svr4 assemblers, except for the sparc, where the section name
+ must be enclosed in double quotes. (See sparcv4.h). */
+#ifndef SECTION_FORMAT
+#ifdef PUSHSECTION_FORMAT
+#define SECTION_FORMAT PUSHSECTION_FORMAT
+#else
+#define SECTION_FORMAT "\t%s\t%s\n"
+#endif
+#endif
+
+#ifndef FRAME_SECTION
+#define FRAME_SECTION ".debug_frame"
+#endif
+
+#ifndef FUNC_BEGIN_LABEL
+#define FUNC_BEGIN_LABEL "LFB"
+#endif
+#ifndef FUNC_END_LABEL
+#define FUNC_END_LABEL "LFE"
+#endif
+#define CIE_AFTER_SIZE_LABEL "LSCIE"
+#define CIE_END_LABEL "LECIE"
+#define CIE_LENGTH_LABEL "LLCIE"
+#define FDE_AFTER_SIZE_LABEL "LSFDE"
+#define FDE_END_LABEL "LEFDE"
+#define FDE_LENGTH_LABEL "LLFDE"
+
+/* Definitions of defaults for various types of primitive assembly language
+ output operations. These may be overridden from within the tm.h file,
+ but typically, that is unnecessary. */
+
+#ifndef ASM_OUTPUT_SECTION
+#define ASM_OUTPUT_SECTION(FILE, SECTION) \
+ fprintf ((FILE), SECTION_FORMAT, SECTION_ASM_OP, SECTION)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_DATA1
+#define ASM_OUTPUT_DWARF_DATA1(FILE,VALUE) \
+ fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) (VALUE))
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_DELTA1
+#define ASM_OUTPUT_DWARF_DELTA1(FILE,LABEL1,LABEL2) \
+ do { fprintf ((FILE), "\t%s\t", ASM_BYTE_OP); \
+ assemble_name (FILE, LABEL1); \
+ fprintf (FILE, "-"); \
+ assemble_name (FILE, LABEL2); \
+ } while (0)
+#endif
+
+#ifdef UNALIGNED_INT_ASM_OP
+
+#ifndef UNALIGNED_OFFSET_ASM_OP
+#define UNALIGNED_OFFSET_ASM_OP \
+ (DWARF_OFFSET_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
+#endif
+
+#ifndef UNALIGNED_WORD_ASM_OP
+#define UNALIGNED_WORD_ASM_OP \
+ (PTR_SIZE == 8 ? UNALIGNED_DOUBLE_INT_ASM_OP : UNALIGNED_INT_ASM_OP)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_DELTA2
+#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \
+ do { fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP); \
+ assemble_name (FILE, LABEL1); \
+ fprintf (FILE, "-"); \
+ assemble_name (FILE, LABEL2); \
+ } while (0)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_DELTA4
+#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \
+ do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \
+ assemble_name (FILE, LABEL1); \
+ fprintf (FILE, "-"); \
+ assemble_name (FILE, LABEL2); \
+ } while (0)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_DELTA
+#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \
+ do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \
+ assemble_name (FILE, LABEL1); \
+ fprintf (FILE, "-"); \
+ assemble_name (FILE, LABEL2); \
+ } while (0)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_ADDR_DELTA
+#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \
+ do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \
+ assemble_name (FILE, LABEL1); \
+ fprintf (FILE, "-"); \
+ assemble_name (FILE, LABEL2); \
+ } while (0)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_ADDR
+#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \
+ do { fprintf ((FILE), "\t%s\t", UNALIGNED_WORD_ASM_OP); \
+ assemble_name (FILE, LABEL); \
+ } while (0)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_ADDR_CONST
+#define ASM_OUTPUT_DWARF_ADDR_CONST(FILE,ADDR) \
+ fprintf ((FILE), "\t%s\t%s", UNALIGNED_WORD_ASM_OP, (ADDR))
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_OFFSET4
+#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \
+ do { fprintf ((FILE), "\t%s\t", UNALIGNED_INT_ASM_OP); \
+ assemble_name (FILE, LABEL); \
+ } while (0)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_OFFSET
+#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \
+ do { fprintf ((FILE), "\t%s\t", UNALIGNED_OFFSET_ASM_OP); \
+ assemble_name (FILE, LABEL); \
+ } while (0)
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_DATA2
+#define ASM_OUTPUT_DWARF_DATA2(FILE,VALUE) \
+ fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_SHORT_ASM_OP, (unsigned) (VALUE))
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_DATA4
+#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \
+ fprintf ((FILE), "\t%s\t0x%x", UNALIGNED_INT_ASM_OP, (unsigned) (VALUE))
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_DATA
+#define ASM_OUTPUT_DWARF_DATA(FILE,VALUE) \
+ fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_OFFSET_ASM_OP, \
+ (unsigned long) (VALUE))
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_ADDR_DATA
+#define ASM_OUTPUT_DWARF_ADDR_DATA(FILE,VALUE) \
+ fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_WORD_ASM_OP, \
+ (unsigned long) (VALUE))
+#endif
+
+#ifndef ASM_OUTPUT_DWARF_DATA8
+#define ASM_OUTPUT_DWARF_DATA8(FILE,HIGH_VALUE,LOW_VALUE) \
+ do { \
+ if (WORDS_BIG_ENDIAN) \
+ { \
+ fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (HIGH_VALUE));\
+ fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (LOW_VALUE));\
+ } \
+ else \
+ { \
+ fprintf ((FILE), "\t%s\t0x%lx\n", UNALIGNED_INT_ASM_OP, (LOW_VALUE)); \
+ fprintf ((FILE), "\t%s\t0x%lx", UNALIGNED_INT_ASM_OP, (HIGH_VALUE)); \
+ } \
+ } while (0)
+#endif
+
+#else /* UNALIGNED_INT_ASM_OP */
+
+/* We don't have unaligned support, let's hope the normal output works for
+ .debug_frame. */
+
+#define ASM_OUTPUT_DWARF_ADDR(FILE,LABEL) \
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, LABEL), PTR_SIZE, 1)
+
+#define ASM_OUTPUT_DWARF_OFFSET4(FILE,LABEL) \
+ assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1)
+
+#define ASM_OUTPUT_DWARF_OFFSET(FILE,LABEL) \
+ assemble_integer (gen_rtx_SYMBOL_REF (SImode, LABEL), 4, 1)
+
+#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \
+ assemble_integer (gen_rtx_MINUS (HImode, \
+ gen_rtx_SYMBOL_REF (Pmode, LABEL1), \
+ gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \
+ 2, 1)
+
+#define ASM_OUTPUT_DWARF_DELTA4(FILE,LABEL1,LABEL2) \
+ assemble_integer (gen_rtx_MINUS (SImode, \
+ gen_rtx_SYMBOL_REF (Pmode, LABEL1), \
+ gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \
+ 4, 1)
+
+#define ASM_OUTPUT_DWARF_ADDR_DELTA(FILE,LABEL1,LABEL2) \
+ assemble_integer (gen_rtx_MINUS (Pmode, \
+ gen_rtx_SYMBOL_REF (Pmode, LABEL1), \
+ gen_rtx_SYMBOL_REF (Pmode, LABEL2)), \
+ PTR_SIZE, 1)
+
+#define ASM_OUTPUT_DWARF_DELTA(FILE,LABEL1,LABEL2) \
+ ASM_OUTPUT_DWARF_DELTA4 (FILE,LABEL1,LABEL2)
+
+#define ASM_OUTPUT_DWARF_DATA4(FILE,VALUE) \
+ assemble_integer (GEN_INT (VALUE), 4, 1)
+
+#endif /* UNALIGNED_INT_ASM_OP */
+
+#ifdef SET_ASM_OP
+#ifndef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
+#define ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL(FILE, SY, HI, LO) \
+ do { \
+ fprintf (FILE, "\t%s\t", SET_ASM_OP); \
+ assemble_name (FILE, SY); \
+ fputc (',', FILE); \
+ assemble_name (FILE, HI); \
+ fputc ('-', FILE); \
+ assemble_name (FILE, LO); \
+ } while (0)
+#endif
+#endif /* SET_ASM_OP */
+
+/* This is similar to the default ASM_OUTPUT_ASCII, except that no trailing
+ newline is produced. When flag_debug_asm is asserted, we add commentary
+ at the end of the line, so we must avoid output of a newline here. */
+#ifndef ASM_OUTPUT_DWARF_STRING
+#define ASM_OUTPUT_DWARF_STRING(FILE,P) \
+ do { \
+ register int slen = strlen(P); \
+ register char *p = (P); \
+ register int i; \
+ fprintf (FILE, "\t.ascii \""); \
+ for (i = 0; i < slen; i++) \
+ { \
+ register int c = p[i]; \
+ if (c == '\"' || c == '\\') \
+ putc ('\\', FILE); \
+ if (c >= ' ' && c < 0177) \
+ putc (c, FILE); \
+ else \
+ { \
+ fprintf (FILE, "\\%o", c); \
+ } \
+ } \
+ fprintf (FILE, "\\0\""); \
+ } \
+ while (0)
+#endif
+
+/* The DWARF 2 CFA column which tracks the return address. Normally this
+ is the column for PC, or the first column after all of the hard
+ registers. */
+#ifndef DWARF_FRAME_RETURN_COLUMN
+#ifdef PC_REGNUM
+#define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (PC_REGNUM)
+#else
+#define DWARF_FRAME_RETURN_COLUMN FIRST_PSEUDO_REGISTER
+#endif
+#endif
+
+/* The mapping from gcc register number to DWARF 2 CFA column number. By
+ default, we just provide columns for all registers. */
+#ifndef DWARF_FRAME_REGNUM
+#define DWARF_FRAME_REGNUM(REG) DBX_REGISTER_NUMBER (REG)
+#endif
+
+/* Hook used by __throw. */
+
+rtx
+expand_builtin_dwarf_fp_regnum ()
+{
+ return GEN_INT (DWARF_FRAME_REGNUM (HARD_FRAME_POINTER_REGNUM));
+}
+
+/* The offset from the incoming value of %sp to the top of the stack frame
+ for the current function. */
+#ifndef INCOMING_FRAME_SP_OFFSET
+#define INCOMING_FRAME_SP_OFFSET 0
+#endif
+
+/* Return a pointer to a copy of the section string name S with all
+ attributes stripped off, and an asterisk prepended (for assemble_name). */
+
+static inline char *
+stripattributes (s)
+ char *s;
+{
+ char *stripped = xmalloc (strlen (s) + 2);
+ char *p = stripped;
+
+ *p++ = '*';
+
+ while (*s && *s != ',')
+ *p++ = *s++;
+
+ *p = '\0';
+ return stripped;
+}
+
+/* Return the register number described by a given RTL node. */
+
+static unsigned
+reg_number (rtl)
+ register rtx rtl;
+{
+ register unsigned regno = REGNO (rtl);
+
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ warning ("internal regno botch: regno = %d\n", regno);
+ regno = 0;
+ }
+
+ regno = DBX_REGISTER_NUMBER (regno);
+ return regno;
+}
+
+struct reg_size_range
+{
+ int beg;
+ int end;
+ int size;
+};
+
+/* Given a register number in REG_TREE, return an rtx for its size in bytes.
+ We do this in kind of a roundabout way, by building up a list of
+ register size ranges and seeing where our register falls in one of those
+ ranges. We need to do it this way because REG_TREE is not a constant,
+ and the target macros were not designed to make this task easy. */
+
+rtx
+expand_builtin_dwarf_reg_size (reg_tree, target)
+ tree reg_tree;
+ rtx target;
+{
+ enum machine_mode mode;
+ int size;
+ struct reg_size_range ranges[5];
+ tree t, t2;
+
+ int i = 0;
+ int n_ranges = 0;
+ int last_size = -1;
+
+ for (; i < FIRST_PSEUDO_REGISTER; ++i)
+ {
+ /* The return address is out of order on the MIPS, and we don't use
+ copy_reg for it anyway, so we don't care here how large it is. */
+ if (DWARF_FRAME_REGNUM (i) == DWARF_FRAME_RETURN_COLUMN)
+ continue;
+
+ mode = reg_raw_mode[i];
+
+ /* CCmode is arbitrarily given a size of 4 bytes. It is more useful
+ to use the same size as word_mode, since that reduces the number
+ of ranges we need. It should not matter, since the result should
+ never be used for a condition code register anyways. */
+ if (GET_MODE_CLASS (mode) == MODE_CC)
+ mode = word_mode;
+
+ size = GET_MODE_SIZE (mode);
+
+ /* If this register is not valid in the specified mode and
+ we have a previous size, use that for the size of this
+ register to avoid making junk tiny ranges. */
+ if (! HARD_REGNO_MODE_OK (i, mode) && last_size != -1)
+ size = last_size;
+
+ if (size != last_size)
+ {
+ ranges[n_ranges].beg = i;
+ ranges[n_ranges].size = last_size = size;
+ ++n_ranges;
+ if (n_ranges >= 5)
+ abort ();
+ }
+ ranges[n_ranges-1].end = i;
+ }
+
+ /* The usual case: fp regs surrounded by general regs. */
+ if (n_ranges == 3 && ranges[0].size == ranges[2].size)
+ {
+ if ((DWARF_FRAME_REGNUM (ranges[1].end)
+ - DWARF_FRAME_REGNUM (ranges[1].beg))
+ != ranges[1].end - ranges[1].beg)
+ abort ();
+ t = fold (build (GE_EXPR, integer_type_node, reg_tree,
+ build_int_2 (DWARF_FRAME_REGNUM (ranges[1].beg), 0)));
+ t2 = fold (build (LE_EXPR, integer_type_node, reg_tree,
+ build_int_2 (DWARF_FRAME_REGNUM (ranges[1].end), 0)));
+ t = fold (build (TRUTH_ANDIF_EXPR, integer_type_node, t, t2));
+ t = fold (build (COND_EXPR, integer_type_node, t,
+ build_int_2 (ranges[1].size, 0),
+ build_int_2 (ranges[0].size, 0)));
+ }
+ else
+ {
+ --n_ranges;
+ t = build_int_2 (ranges[n_ranges].size, 0);
+ size = DWARF_FRAME_REGNUM (ranges[n_ranges].beg);
+ for (; n_ranges--; )
+ {
+ if ((DWARF_FRAME_REGNUM (ranges[n_ranges].end)
+ - DWARF_FRAME_REGNUM (ranges[n_ranges].beg))
+ != ranges[n_ranges].end - ranges[n_ranges].beg)
+ abort ();
+ if (DWARF_FRAME_REGNUM (ranges[n_ranges].beg) >= size)
+ abort ();
+ size = DWARF_FRAME_REGNUM (ranges[n_ranges].beg);
+ t2 = fold (build (LE_EXPR, integer_type_node, reg_tree,
+ build_int_2 (DWARF_FRAME_REGNUM
+ (ranges[n_ranges].end), 0)));
+ t = fold (build (COND_EXPR, integer_type_node, t2,
+ build_int_2 (ranges[n_ranges].size, 0), t));
+ }
+ }
+ return expand_expr (t, target, Pmode, 0);
+}
+
+/* Convert a DWARF call frame info. operation to its string name */
+
+static char *
+dwarf_cfi_name (cfi_opc)
+ register unsigned cfi_opc;
+{
+ switch (cfi_opc)
+ {
+ case DW_CFA_advance_loc:
+ return "DW_CFA_advance_loc";
+ case DW_CFA_offset:
+ return "DW_CFA_offset";
+ case DW_CFA_restore:
+ return "DW_CFA_restore";
+ case DW_CFA_nop:
+ return "DW_CFA_nop";
+ case DW_CFA_set_loc:
+ return "DW_CFA_set_loc";
+ case DW_CFA_advance_loc1:
+ return "DW_CFA_advance_loc1";
+ case DW_CFA_advance_loc2:
+ return "DW_CFA_advance_loc2";
+ case DW_CFA_advance_loc4:
+ return "DW_CFA_advance_loc4";
+ case DW_CFA_offset_extended:
+ return "DW_CFA_offset_extended";
+ case DW_CFA_restore_extended:
+ return "DW_CFA_restore_extended";
+ case DW_CFA_undefined:
+ return "DW_CFA_undefined";
+ case DW_CFA_same_value:
+ return "DW_CFA_same_value";
+ case DW_CFA_register:
+ return "DW_CFA_register";
+ case DW_CFA_remember_state:
+ return "DW_CFA_remember_state";
+ case DW_CFA_restore_state:
+ return "DW_CFA_restore_state";
+ case DW_CFA_def_cfa:
+ return "DW_CFA_def_cfa";
+ case DW_CFA_def_cfa_register:
+ return "DW_CFA_def_cfa_register";
+ case DW_CFA_def_cfa_offset:
+ return "DW_CFA_def_cfa_offset";
+
+ /* SGI/MIPS specific */
+ case DW_CFA_MIPS_advance_loc8:
+ return "DW_CFA_MIPS_advance_loc8";
+
+ /* GNU extensions */
+ case DW_CFA_GNU_window_save:
+ return "DW_CFA_GNU_window_save";
+ case DW_CFA_GNU_args_size:
+ return "DW_CFA_GNU_args_size";
+
+ default:
+ return "DW_CFA_<unknown>";
+ }
+}
+
+/* Return a pointer to a newly allocated Call Frame Instruction. */
+
+static inline dw_cfi_ref
+new_cfi ()
+{
+ register dw_cfi_ref cfi = (dw_cfi_ref) xmalloc (sizeof (dw_cfi_node));
+
+ cfi->dw_cfi_next = NULL;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
+ cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0;
+
+ return cfi;
+}
+
+/* Add a Call Frame Instruction to list of instructions. */
+
+static inline void
+add_cfi (list_head, cfi)
+ register dw_cfi_ref *list_head;
+ register dw_cfi_ref cfi;
+{
+ register dw_cfi_ref *p;
+
+ /* Find the end of the chain. */
+ for (p = list_head; (*p) != NULL; p = &(*p)->dw_cfi_next)
+ ;
+
+ *p = cfi;
+}
+
+/* Generate a new label for the CFI info to refer to. */
+
+char *
+dwarf2out_cfi_label ()
+{
+ static char label[20];
+ static unsigned long label_num = 0;
+
+ ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", label_num++);
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+
+ return label;
+}
+
+/* Add CFI to the current fde at the PC value indicated by LABEL if specified,
+ or to the CIE if LABEL is NULL. */
+
+static void
+add_fde_cfi (label, cfi)
+ register char *label;
+ register dw_cfi_ref cfi;
+{
+ if (label)
+ {
+ register dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+
+ if (*label == 0)
+ label = dwarf2out_cfi_label ();
+
+ if (fde->dw_fde_current_label == NULL
+ || strcmp (label, fde->dw_fde_current_label) != 0)
+ {
+ register dw_cfi_ref xcfi;
+
+ fde->dw_fde_current_label = label = xstrdup (label);
+
+ /* Set the location counter to the new label. */
+ xcfi = new_cfi ();
+ xcfi->dw_cfi_opc = DW_CFA_advance_loc4;
+ xcfi->dw_cfi_oprnd1.dw_cfi_addr = label;
+ add_cfi (&fde->dw_fde_cfi, xcfi);
+ }
+
+ add_cfi (&fde->dw_fde_cfi, cfi);
+ }
+
+ else
+ add_cfi (&cie_cfi_head, cfi);
+}
+
+/* Subroutine of lookup_cfa. */
+
+static inline void
+lookup_cfa_1 (cfi, regp, offsetp)
+ register dw_cfi_ref cfi;
+ register unsigned long *regp;
+ register long *offsetp;
+{
+ switch (cfi->dw_cfi_opc)
+ {
+ case DW_CFA_def_cfa_offset:
+ *offsetp = cfi->dw_cfi_oprnd1.dw_cfi_offset;
+ break;
+ case DW_CFA_def_cfa_register:
+ *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
+ break;
+ case DW_CFA_def_cfa:
+ *regp = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
+ *offsetp = cfi->dw_cfi_oprnd2.dw_cfi_offset;
+ break;
+ default:
+ break;
+ }
+}
+
+/* Find the previous value for the CFA. */
+
+static void
+lookup_cfa (regp, offsetp)
+ register unsigned long *regp;
+ register long *offsetp;
+{
+ register dw_cfi_ref cfi;
+
+ *regp = (unsigned long) -1;
+ *offsetp = 0;
+
+ for (cfi = cie_cfi_head; cfi; cfi = cfi->dw_cfi_next)
+ lookup_cfa_1 (cfi, regp, offsetp);
+
+ if (fde_table_in_use)
+ {
+ register dw_fde_ref fde = &fde_table[fde_table_in_use - 1];
+ for (cfi = fde->dw_fde_cfi; cfi; cfi = cfi->dw_cfi_next)
+ lookup_cfa_1 (cfi, regp, offsetp);
+ }
+}
+
+/* The current rule for calculating the DWARF2 canonical frame address. */
+static unsigned long cfa_reg;
+static long cfa_offset;
+
+/* The register used for saving registers to the stack, and its offset
+ from the CFA. */
+static unsigned cfa_store_reg;
+static long cfa_store_offset;
+
+/* The running total of the size of arguments pushed onto the stack. */
+static long args_size;
+
+/* The last args_size we actually output. */
+static long old_args_size;
+
+/* Entry point to update the canonical frame address (CFA).
+ LABEL is passed to add_fde_cfi. The value of CFA is now to be
+ calculated from REG+OFFSET. */
+
+void
+dwarf2out_def_cfa (label, reg, offset)
+ register char *label;
+ register unsigned reg;
+ register long offset;
+{
+ register dw_cfi_ref cfi;
+ unsigned long old_reg;
+ long old_offset;
+
+ cfa_reg = reg;
+ cfa_offset = offset;
+ if (cfa_store_reg == reg)
+ cfa_store_offset = offset;
+
+ reg = DWARF_FRAME_REGNUM (reg);
+ lookup_cfa (&old_reg, &old_offset);
+
+ if (reg == old_reg && offset == old_offset)
+ return;
+
+ cfi = new_cfi ();
+
+ if (reg == old_reg)
+ {
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
+ cfi->dw_cfi_oprnd1.dw_cfi_offset = offset;
+ }
+
+#ifndef MIPS_DEBUGGING_INFO /* SGI dbx thinks this means no offset. */
+ else if (offset == old_offset && old_reg != (unsigned long) -1)
+ {
+ cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+ }
+#endif
+
+ else
+ {
+ cfi->dw_cfi_opc = DW_CFA_def_cfa;
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+ cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
+ }
+
+ add_fde_cfi (label, cfi);
+}
+
+/* Add the CFI for saving a register. REG is the CFA column number.
+ LABEL is passed to add_fde_cfi.
+ If SREG is -1, the register is saved at OFFSET from the CFA;
+ otherwise it is saved in SREG. */
+
+static void
+reg_save (label, reg, sreg, offset)
+ register char * label;
+ register unsigned reg;
+ register unsigned sreg;
+ register long offset;
+{
+ register dw_cfi_ref cfi = new_cfi ();
+
+ cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
+
+ /* The following comparison is correct. -1 is used to indicate that
+ the value isn't a register number. */
+ if (sreg == (unsigned int) -1)
+ {
+ if (reg & ~0x3f)
+ /* The register number won't fit in 6 bits, so we have to use
+ the long form. */
+ cfi->dw_cfi_opc = DW_CFA_offset_extended;
+ else
+ cfi->dw_cfi_opc = DW_CFA_offset;
+
+ offset /= DWARF_CIE_DATA_ALIGNMENT;
+ if (offset < 0)
+ abort ();
+ cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
+ }
+ else
+ {
+ cfi->dw_cfi_opc = DW_CFA_register;
+ cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
+ }
+
+ add_fde_cfi (label, cfi);
+}
+
+/* Add the CFI for saving a register window. LABEL is passed to reg_save.
+ This CFI tells the unwinder that it needs to restore the window registers
+ from the previous frame's window save area.
+
+ ??? Perhaps we should note in the CIE where windows are saved (instead of
+ assuming 0(cfa)) and what registers are in the window. */
+
+void
+dwarf2out_window_save (label)
+ register char * label;
+{
+ register dw_cfi_ref cfi = new_cfi ();
+ cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
+ add_fde_cfi (label, cfi);
+}
+
+/* Add a CFI to update the running total of the size of arguments
+ pushed onto the stack. */
+
+void
+dwarf2out_args_size (label, size)
+ char *label;
+ long size;
+{
+ register dw_cfi_ref cfi;
+
+ if (size == old_args_size)
+ return;
+ old_args_size = size;
+
+ cfi = new_cfi ();
+ cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
+ cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
+ add_fde_cfi (label, cfi);
+}
+
+/* Entry point for saving a register to the stack. REG is the GCC register
+ number. LABEL and OFFSET are passed to reg_save. */
+
+void
+dwarf2out_reg_save (label, reg, offset)
+ register char * label;
+ register unsigned reg;
+ register long offset;
+{
+ reg_save (label, DWARF_FRAME_REGNUM (reg), -1, offset);
+}
+
+/* Entry point for saving the return address in the stack.
+ LABEL and OFFSET are passed to reg_save. */
+
+void
+dwarf2out_return_save (label, offset)
+ register char * label;
+ register long offset;
+{
+ reg_save (label, DWARF_FRAME_RETURN_COLUMN, -1, offset);
+}
+
+/* Entry point for saving the return address in a register.
+ LABEL and SREG are passed to reg_save. */
+
+void
+dwarf2out_return_reg (label, sreg)
+ register char * label;
+ register unsigned sreg;
+{
+ reg_save (label, DWARF_FRAME_RETURN_COLUMN, sreg, 0);
+}
+
+/* Record the initial position of the return address. RTL is
+ INCOMING_RETURN_ADDR_RTX. */
+
+static void
+initial_return_save (rtl)
+ register rtx rtl;
+{
+ unsigned reg = -1;
+ long offset = 0;
+
+ switch (GET_CODE (rtl))
+ {
+ case REG:
+ /* RA is in a register. */
+ reg = reg_number (rtl);
+ break;
+ case MEM:
+ /* RA is on the stack. */
+ rtl = XEXP (rtl, 0);
+ switch (GET_CODE (rtl))
+ {
+ case REG:
+ if (REGNO (rtl) != STACK_POINTER_REGNUM)
+ abort ();
+ offset = 0;
+ break;
+ case PLUS:
+ if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM)
+ abort ();
+ offset = INTVAL (XEXP (rtl, 1));
+ break;
+ case MINUS:
+ if (REGNO (XEXP (rtl, 0)) != STACK_POINTER_REGNUM)
+ abort ();
+ offset = -INTVAL (XEXP (rtl, 1));
+ break;
+ default:
+ abort ();
+ }
+ break;
+ case PLUS:
+ /* The return address is at some offset from any value we can
+ actually load. For instance, on the SPARC it is in %i7+8. Just
+ ignore the offset for now; it doesn't matter for unwinding frames. */
+ if (GET_CODE (XEXP (rtl, 1)) != CONST_INT)
+ abort ();
+ initial_return_save (XEXP (rtl, 0));
+ return;
+ default:
+ abort ();
+ }
+
+ reg_save (NULL, DWARF_FRAME_RETURN_COLUMN, reg, offset - cfa_offset);
+}
+
+/* Check INSN to see if it looks like a push or a stack adjustment, and
+ make a note of it if it does. EH uses this information to find out how
+ much extra space it needs to pop off the stack. */
+
+static void
+dwarf2out_stack_adjust (insn)
+ rtx insn;
+{
+ long offset;
+ char *label;
+
+ if (! asynchronous_exceptions && GET_CODE (insn) == CALL_INSN)
+ {
+ /* Extract the size of the args from the CALL rtx itself. */
+
+ insn = PATTERN (insn);
+ if (GET_CODE (insn) == PARALLEL)
+ insn = XVECEXP (insn, 0, 0);
+ if (GET_CODE (insn) == SET)
+ insn = SET_SRC (insn);
+ assert (GET_CODE (insn) == CALL);
+ dwarf2out_args_size ("", INTVAL (XEXP (insn, 1)));
+ return;
+ }
+
+ /* If only calls can throw, and we have a frame pointer,
+ save up adjustments until we see the CALL_INSN. */
+ else if (! asynchronous_exceptions
+ && cfa_reg != STACK_POINTER_REGNUM)
+ return;
+
+ if (GET_CODE (insn) == BARRIER)
+ {
+ /* When we see a BARRIER, we know to reset args_size to 0. Usually
+ the compiler will have already emitted a stack adjustment, but
+ doesn't bother for calls to noreturn functions. */
+#ifdef STACK_GROWS_DOWNWARD
+ offset = -args_size;
+#else
+ offset = args_size;
+#endif
+ }
+ else if (GET_CODE (PATTERN (insn)) == SET)
+ {
+ rtx src, dest;
+ enum rtx_code code;
+
+ insn = PATTERN (insn);
+ src = SET_SRC (insn);
+ dest = SET_DEST (insn);
+
+ if (dest == stack_pointer_rtx)
+ {
+ /* (set (reg sp) (plus (reg sp) (const_int))) */
+ code = GET_CODE (src);
+ if (! (code == PLUS || code == MINUS)
+ || XEXP (src, 0) != stack_pointer_rtx
+ || GET_CODE (XEXP (src, 1)) != CONST_INT)
+ return;
+
+ offset = INTVAL (XEXP (src, 1));
+ }
+ else if (GET_CODE (dest) == MEM)
+ {
+ /* (set (mem (pre_dec (reg sp))) (foo)) */
+ src = XEXP (dest, 0);
+ code = GET_CODE (src);
+
+ if (! (code == PRE_DEC || code == PRE_INC)
+ || XEXP (src, 0) != stack_pointer_rtx)
+ return;
+
+ offset = GET_MODE_SIZE (GET_MODE (dest));
+ }
+ else
+ return;
+
+ if (code == PLUS || code == PRE_INC)
+ offset = -offset;
+ }
+ else
+ return;
+
+ if (offset == 0)
+ return;
+
+ if (cfa_reg == STACK_POINTER_REGNUM)
+ cfa_offset += offset;
+
+#ifndef STACK_GROWS_DOWNWARD
+ offset = -offset;
+#endif
+ args_size += offset;
+ if (args_size < 0)
+ args_size = 0;
+
+ label = dwarf2out_cfi_label ();
+ dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
+ dwarf2out_args_size (label, args_size);
+}
+
+/* Record call frame debugging information for INSN, which either
+ sets SP or FP (adjusting how we calculate the frame address) or saves a
+ register to the stack. If INSN is NULL_RTX, initialize our state. */
+
+void
+dwarf2out_frame_debug (insn)
+ rtx insn;
+{
+ char *label;
+ rtx src, dest;
+ long offset;
+
+ /* A temporary register used in adjusting SP or setting up the store_reg. */
+ static unsigned cfa_temp_reg;
+ static long cfa_temp_value;
+
+ if (insn == NULL_RTX)
+ {
+ /* Set up state for generating call frame debug info. */
+ lookup_cfa (&cfa_reg, &cfa_offset);
+ if (cfa_reg != DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM))
+ abort ();
+ cfa_reg = STACK_POINTER_REGNUM;
+ cfa_store_reg = cfa_reg;
+ cfa_store_offset = cfa_offset;
+ cfa_temp_reg = -1;
+ cfa_temp_value = 0;
+ return;
+ }
+
+ if (! RTX_FRAME_RELATED_P (insn))
+ {
+ dwarf2out_stack_adjust (insn);
+ return;
+ }
+
+ label = dwarf2out_cfi_label ();
+
+ insn = PATTERN (insn);
+ /* Assume that in a PARALLEL prologue insn, only the first elt is
+ significant. Currently this is true. */
+ if (GET_CODE (insn) == PARALLEL)
+ insn = XVECEXP (insn, 0, 0);
+ if (GET_CODE (insn) != SET)
+ abort ();
+
+ src = SET_SRC (insn);
+ dest = SET_DEST (insn);
+
+ switch (GET_CODE (dest))
+ {
+ case REG:
+ /* Update the CFA rule wrt SP or FP. Make sure src is
+ relative to the current CFA register. */
+ switch (GET_CODE (src))
+ {
+ /* Setting FP from SP. */
+ case REG:
+ if (cfa_reg != REGNO (src))
+ abort ();
+ if (REGNO (dest) != STACK_POINTER_REGNUM
+ && !(frame_pointer_needed
+ && REGNO (dest) == HARD_FRAME_POINTER_REGNUM))
+ abort ();
+ cfa_reg = REGNO (dest);
+ break;
+
+ case PLUS:
+ case MINUS:
+ if (dest == stack_pointer_rtx)
+ {
+ /* Adjusting SP. */
+ switch (GET_CODE (XEXP (src, 1)))
+ {
+ case CONST_INT:
+ offset = INTVAL (XEXP (src, 1));
+ break;
+ case REG:
+ if (REGNO (XEXP (src, 1)) != cfa_temp_reg)
+ abort ();
+ offset = cfa_temp_value;
+ break;
+ default:
+ abort ();
+ }
+
+ if (XEXP (src, 0) == hard_frame_pointer_rtx)
+ {
+ /* Restoring SP from FP in the epilogue. */
+ if (cfa_reg != HARD_FRAME_POINTER_REGNUM)
+ abort ();
+ cfa_reg = STACK_POINTER_REGNUM;
+ }
+ else if (XEXP (src, 0) != stack_pointer_rtx)
+ abort ();
+
+ if (GET_CODE (src) == PLUS)
+ offset = -offset;
+ if (cfa_reg == STACK_POINTER_REGNUM)
+ cfa_offset += offset;
+ if (cfa_store_reg == STACK_POINTER_REGNUM)
+ cfa_store_offset += offset;
+ }
+ else if (dest == hard_frame_pointer_rtx)
+ {
+ /* Either setting the FP from an offset of the SP,
+ or adjusting the FP */
+ if (! frame_pointer_needed
+ || REGNO (dest) != HARD_FRAME_POINTER_REGNUM)
+ abort ();
+
+ if (XEXP (src, 0) == stack_pointer_rtx
+ && GET_CODE (XEXP (src, 1)) == CONST_INT)
+ {
+ if (cfa_reg != STACK_POINTER_REGNUM)
+ abort ();
+ offset = INTVAL (XEXP (src, 1));
+ if (GET_CODE (src) == PLUS)
+ offset = -offset;
+ cfa_offset += offset;
+ cfa_reg = HARD_FRAME_POINTER_REGNUM;
+ }
+ else if (XEXP (src, 0) == hard_frame_pointer_rtx
+ && GET_CODE (XEXP (src, 1)) == CONST_INT)
+ {
+ if (cfa_reg != HARD_FRAME_POINTER_REGNUM)
+ abort ();
+ offset = INTVAL (XEXP (src, 1));
+ if (GET_CODE (src) == PLUS)
+ offset = -offset;
+ cfa_offset += offset;
+ }
+
+ else
+ abort();
+ }
+ else
+ {
+ if (GET_CODE (src) != PLUS
+ || XEXP (src, 1) != stack_pointer_rtx)
+ abort ();
+ if (GET_CODE (XEXP (src, 0)) != REG
+ || REGNO (XEXP (src, 0)) != cfa_temp_reg)
+ abort ();
+ if (cfa_reg != STACK_POINTER_REGNUM)
+ abort ();
+ cfa_store_reg = REGNO (dest);
+ cfa_store_offset = cfa_offset - cfa_temp_value;
+ }
+ break;
+
+ case CONST_INT:
+ cfa_temp_reg = REGNO (dest);
+ cfa_temp_value = INTVAL (src);
+ break;
+
+ case IOR:
+ if (GET_CODE (XEXP (src, 0)) != REG
+ || REGNO (XEXP (src, 0)) != cfa_temp_reg
+ || REGNO (dest) != cfa_temp_reg
+ || GET_CODE (XEXP (src, 1)) != CONST_INT)
+ abort ();
+ cfa_temp_value |= INTVAL (XEXP (src, 1));
+ break;
+
+ default:
+ abort ();
+ }
+ dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
+ break;
+
+ case MEM:
+ /* Saving a register to the stack. Make sure dest is relative to the
+ CFA register. */
+ if (GET_CODE (src) != REG)
+ abort ();
+ switch (GET_CODE (XEXP (dest, 0)))
+ {
+ /* With a push. */
+ case PRE_INC:
+ case PRE_DEC:
+ offset = GET_MODE_SIZE (GET_MODE (dest));
+ if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
+ offset = -offset;
+
+ if (REGNO (XEXP (XEXP (dest, 0), 0)) != STACK_POINTER_REGNUM
+ || cfa_store_reg != STACK_POINTER_REGNUM)
+ abort ();
+ cfa_store_offset += offset;
+ if (cfa_reg == STACK_POINTER_REGNUM)
+ cfa_offset = cfa_store_offset;
+
+ offset = -cfa_store_offset;
+ break;
+
+ /* With an offset. */
+ case PLUS:
+ case MINUS:
+ offset = INTVAL (XEXP (XEXP (dest, 0), 1));
+ if (GET_CODE (src) == MINUS)
+ offset = -offset;
+
+ if (cfa_store_reg != REGNO (XEXP (XEXP (dest, 0), 0)))
+ abort ();
+ offset -= cfa_store_offset;
+ break;
+
+ default:
+ abort ();
+ }
+ dwarf2out_def_cfa (label, cfa_reg, cfa_offset);
+ dwarf2out_reg_save (label, REGNO (src), offset);
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+/* Return the size of an unsigned LEB128 quantity. */
+
+static inline unsigned long
+size_of_uleb128 (value)
+ register unsigned long value;
+{
+ register unsigned long size = 0;
+ register unsigned byte;
+
+ do
+ {
+ byte = (value & 0x7f);
+ value >>= 7;
+ size += 1;
+ }
+ while (value != 0);
+
+ return size;
+}
+
+/* Return the size of a signed LEB128 quantity. */
+
+static inline unsigned long
+size_of_sleb128 (value)
+ register long value;
+{
+ register unsigned long size = 0;
+ register unsigned byte;
+
+ do
+ {
+ byte = (value & 0x7f);
+ value >>= 7;
+ size += 1;
+ }
+ while (!(((value == 0) && ((byte & 0x40) == 0))
+ || ((value == -1) && ((byte & 0x40) != 0))));
+
+ return size;
+}
+
+/* Output an unsigned LEB128 quantity. */
+
+static void
+output_uleb128 (value)
+ register unsigned long value;
+{
+ unsigned long save_value = value;
+
+ fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
+ do
+ {
+ register unsigned byte = (value & 0x7f);
+ value >>= 7;
+ if (value != 0)
+ /* More bytes to follow. */
+ byte |= 0x80;
+
+ fprintf (asm_out_file, "0x%x", byte);
+ if (value != 0)
+ fprintf (asm_out_file, ",");
+ }
+ while (value != 0);
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s ULEB128 0x%lx", ASM_COMMENT_START, save_value);
+}
+
+/* Output an signed LEB128 quantity. */
+
+static void
+output_sleb128 (value)
+ register long value;
+{
+ register int more;
+ register unsigned byte;
+ long save_value = value;
+
+ fprintf (asm_out_file, "\t%s\t", ASM_BYTE_OP);
+ do
+ {
+ byte = (value & 0x7f);
+ /* arithmetic shift */
+ value >>= 7;
+ more = !((((value == 0) && ((byte & 0x40) == 0))
+ || ((value == -1) && ((byte & 0x40) != 0))));
+ if (more)
+ byte |= 0x80;
+
+ fprintf (asm_out_file, "0x%x", byte);
+ if (more)
+ fprintf (asm_out_file, ",");
+ }
+
+ while (more);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s SLEB128 %ld", ASM_COMMENT_START, save_value);
+}
+
+/* Output a Call Frame Information opcode and its operand(s). */
+
+static void
+output_cfi (cfi, fde)
+ register dw_cfi_ref cfi;
+ register dw_fde_ref fde;
+{
+ if (cfi->dw_cfi_opc == DW_CFA_advance_loc)
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+ cfi->dw_cfi_opc
+ | (cfi->dw_cfi_oprnd1.dw_cfi_offset & 0x3f));
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_CFA_advance_loc 0x%lx",
+ ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_offset);
+ fputc ('\n', asm_out_file);
+ }
+
+ else if (cfi->dw_cfi_opc == DW_CFA_offset)
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+ cfi->dw_cfi_opc
+ | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f));
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_CFA_offset, column 0x%lx",
+ ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+
+ fputc ('\n', asm_out_file);
+ output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
+ fputc ('\n', asm_out_file);
+ }
+ else if (cfi->dw_cfi_opc == DW_CFA_restore)
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+ cfi->dw_cfi_opc
+ | (cfi->dw_cfi_oprnd1.dw_cfi_reg_num & 0x3f));
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_CFA_restore, column 0x%lx",
+ ASM_COMMENT_START, cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+
+ fputc ('\n', asm_out_file);
+ }
+ else
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, cfi->dw_cfi_opc);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START,
+ dwarf_cfi_name (cfi->dw_cfi_opc));
+
+ fputc ('\n', asm_out_file);
+ switch (cfi->dw_cfi_opc)
+ {
+ case DW_CFA_set_loc:
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, cfi->dw_cfi_oprnd1.dw_cfi_addr);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_CFA_advance_loc1:
+ ASM_OUTPUT_DWARF_DELTA1 (asm_out_file,
+ cfi->dw_cfi_oprnd1.dw_cfi_addr,
+ fde->dw_fde_current_label);
+ fputc ('\n', asm_out_file);
+ fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+ case DW_CFA_advance_loc2:
+ ASM_OUTPUT_DWARF_DELTA2 (asm_out_file,
+ cfi->dw_cfi_oprnd1.dw_cfi_addr,
+ fde->dw_fde_current_label);
+ fputc ('\n', asm_out_file);
+ fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+ case DW_CFA_advance_loc4:
+ ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
+ cfi->dw_cfi_oprnd1.dw_cfi_addr,
+ fde->dw_fde_current_label);
+ fputc ('\n', asm_out_file);
+ fde->dw_fde_current_label = cfi->dw_cfi_oprnd1.dw_cfi_addr;
+ break;
+#ifdef MIPS_DEBUGGING_INFO
+ case DW_CFA_MIPS_advance_loc8:
+ /* TODO: not currently implemented. */
+ abort ();
+ break;
+#endif
+ case DW_CFA_offset_extended:
+ case DW_CFA_def_cfa:
+ output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+ fputc ('\n', asm_out_file);
+ output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_offset);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_CFA_same_value:
+ case DW_CFA_def_cfa_register:
+ output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_CFA_register:
+ output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_reg_num);
+ fputc ('\n', asm_out_file);
+ output_uleb128 (cfi->dw_cfi_oprnd2.dw_cfi_reg_num);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_CFA_def_cfa_offset:
+ output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_CFA_GNU_window_save:
+ break;
+ case DW_CFA_GNU_args_size:
+ output_uleb128 (cfi->dw_cfi_oprnd1.dw_cfi_offset);
+ fputc ('\n', asm_out_file);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+#if !defined (EH_FRAME_SECTION)
+#if defined (EH_FRAME_SECTION_ASM_OP)
+#define EH_FRAME_SECTION() eh_frame_section();
+#else
+#if defined (ASM_OUTPUT_SECTION_NAME)
+#define EH_FRAME_SECTION() \
+ do { \
+ named_section (NULL_TREE, ".eh_frame", 0); \
+ } while (0)
+#endif
+#endif
+#endif
+
+/* If we aren't using crtstuff to run ctors, don't use it for EH. */
+#if !defined (HAS_INIT_SECTION) && !defined (INIT_SECTION_ASM_OP)
+#undef EH_FRAME_SECTION
+#endif
+
+/* Output the call frame information used to used to record information
+ that relates to calculating the frame pointer, and records the
+ location of saved registers. */
+
+static void
+output_call_frame_info (for_eh)
+ int for_eh;
+{
+ register unsigned long i;
+ register dw_fde_ref fde;
+ register dw_cfi_ref cfi;
+ char l1[20], l2[20];
+#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
+ char ld[20];
+#endif
+
+ /* Do we want to include a pointer to the exception table? */
+ int eh_ptr = for_eh && exception_table_p ();
+
+ fputc ('\n', asm_out_file);
+
+ /* We're going to be generating comments, so turn on app. */
+ if (flag_debug_asm)
+ app_enable ();
+
+ if (for_eh)
+ {
+#ifdef EH_FRAME_SECTION
+ EH_FRAME_SECTION ();
+#else
+ tree label = get_file_function_name ('F');
+
+ data_section ();
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+ ASM_GLOBALIZE_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+ ASM_OUTPUT_LABEL (asm_out_file, IDENTIFIER_POINTER (label));
+#endif
+ assemble_label ("__FRAME_BEGIN__");
+ }
+ else
+ ASM_OUTPUT_SECTION (asm_out_file, FRAME_SECTION);
+
+ /* Output the CIE. */
+ ASM_GENERATE_INTERNAL_LABEL (l1, CIE_AFTER_SIZE_LABEL, for_eh);
+ ASM_GENERATE_INTERNAL_LABEL (l2, CIE_END_LABEL, for_eh);
+#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
+ ASM_GENERATE_INTERNAL_LABEL (ld, CIE_LENGTH_LABEL, for_eh);
+ if (for_eh)
+ ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
+ else
+ ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
+#else
+ if (for_eh)
+ ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
+ else
+ ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
+#endif
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Length of Common Information Entry",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_LABEL (asm_out_file, l1);
+
+ if (for_eh)
+ /* Now that the CIE pointer is PC-relative for EH,
+ use 0 to identify the CIE. */
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
+ else
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s CIE Identifier Tag", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ if (! for_eh && DWARF_OFFSET_SIZE == 8)
+ {
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DW_CIE_ID);
+ fputc ('\n', asm_out_file);
+ }
+
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_CIE_VERSION);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s CIE Version", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ if (eh_ptr)
+ {
+ /* The CIE contains a pointer to the exception region info for the
+ frame. Make the augmentation string three bytes (including the
+ trailing null) so the pointer is 4-byte aligned. The Solaris ld
+ can't handle unaligned relocs. */
+ if (flag_debug_asm)
+ {
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, "eh");
+ fprintf (asm_out_file, "\t%s CIE Augmentation", ASM_COMMENT_START);
+ }
+ else
+ {
+ ASM_OUTPUT_ASCII (asm_out_file, "eh", 3);
+ }
+ fputc ('\n', asm_out_file);
+
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, "__EXCEPTION_TABLE__");
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s pointer to exception region info",
+ ASM_COMMENT_START);
+ }
+ else
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s CIE Augmentation (none)",
+ ASM_COMMENT_START);
+ }
+
+ fputc ('\n', asm_out_file);
+ output_uleb128 (1);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, " (CIE Code Alignment Factor)");
+
+ fputc ('\n', asm_out_file);
+ output_sleb128 (DWARF_CIE_DATA_ALIGNMENT);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, " (CIE Data Alignment Factor)");
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_FRAME_RETURN_COLUMN);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s CIE RA Column", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+
+ for (cfi = cie_cfi_head; cfi != NULL; cfi = cfi->dw_cfi_next)
+ output_cfi (cfi, NULL);
+
+ /* Pad the CIE out to an address sized boundary. */
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+ ASM_OUTPUT_LABEL (asm_out_file, l2);
+#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
+ ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s CIE Length Symbol", ASM_COMMENT_START);
+ fputc ('\n', asm_out_file);
+#endif
+
+ /* Loop through all of the FDE's. */
+ for (i = 0; i < fde_table_in_use; ++i)
+ {
+ fde = &fde_table[i];
+
+ ASM_GENERATE_INTERNAL_LABEL (l1, FDE_AFTER_SIZE_LABEL, for_eh + i*2);
+ ASM_GENERATE_INTERNAL_LABEL (l2, FDE_END_LABEL, for_eh + i*2);
+#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
+ ASM_GENERATE_INTERNAL_LABEL (ld, FDE_LENGTH_LABEL, for_eh + i*2);
+ if (for_eh)
+ ASM_OUTPUT_DWARF_OFFSET4 (asm_out_file, ld);
+ else
+ ASM_OUTPUT_DWARF_OFFSET (asm_out_file, ld);
+#else
+ if (for_eh)
+ ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, l2, l1);
+ else
+ ASM_OUTPUT_DWARF_DELTA (asm_out_file, l2, l1);
+#endif
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s FDE Length", ASM_COMMENT_START);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_LABEL (asm_out_file, l1);
+
+ if (for_eh)
+ ASM_OUTPUT_DWARF_DELTA (asm_out_file, l1, "__FRAME_BEGIN__");
+ else
+ ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (FRAME_SECTION));
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s FDE CIE offset", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, fde->dw_fde_begin);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s FDE initial location", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file,
+ fde->dw_fde_end, fde->dw_fde_begin);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s FDE address range", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+
+ /* Loop through the Call Frame Instructions associated with
+ this FDE. */
+ fde->dw_fde_current_label = fde->dw_fde_begin;
+ for (cfi = fde->dw_fde_cfi; cfi != NULL; cfi = cfi->dw_cfi_next)
+ output_cfi (cfi, fde);
+
+ /* Pad the FDE out to an address sized boundary. */
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (PTR_SIZE));
+ ASM_OUTPUT_LABEL (asm_out_file, l2);
+#ifdef ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
+ ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (asm_out_file, ld, l2, l1);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s FDE Length Symbol", ASM_COMMENT_START);
+ fputc ('\n', asm_out_file);
+#endif
+ }
+#ifndef EH_FRAME_SECTION
+ if (for_eh)
+ {
+ /* Emit terminating zero for table. */
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 0);
+ fputc ('\n', asm_out_file);
+ }
+#endif
+#ifdef MIPS_DEBUGGING_INFO
+ /* Work around Irix 6 assembler bug whereby labels at the end of a section
+ get a value of 0. Putting .align 0 after the label fixes it. */
+ ASM_OUTPUT_ALIGN (asm_out_file, 0);
+#endif
+
+ /* Turn off app to make assembly quicker. */
+ if (flag_debug_asm)
+ app_disable ();
+}
+
+/* Output a marker (i.e. a label) for the beginning of a function, before
+ the prologue. */
+
+void
+dwarf2out_begin_prologue ()
+{
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ register dw_fde_ref fde;
+
+ ++current_funcdef_number;
+
+ function_section (current_function_decl);
+ ASM_GENERATE_INTERNAL_LABEL (label, FUNC_BEGIN_LABEL,
+ current_funcdef_number);
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+
+ /* Expand the fde table if necessary. */
+ if (fde_table_in_use == fde_table_allocated)
+ {
+ fde_table_allocated += FDE_TABLE_INCREMENT;
+ fde_table
+ = (dw_fde_ref) xrealloc (fde_table,
+ fde_table_allocated * sizeof (dw_fde_node));
+ }
+
+ /* Record the FDE associated with this function. */
+ current_funcdef_fde = fde_table_in_use;
+
+ /* Add the new FDE at the end of the fde_table. */
+ fde = &fde_table[fde_table_in_use++];
+ fde->dw_fde_begin = xstrdup (label);
+ fde->dw_fde_current_label = NULL;
+ fde->dw_fde_end = NULL;
+ fde->dw_fde_cfi = NULL;
+
+ args_size = old_args_size = 0;
+}
+
+/* Output a marker (i.e. a label) for the absolute end of the generated code
+ for a function definition. This gets called *after* the epilogue code has
+ been generated. */
+
+void
+dwarf2out_end_epilogue ()
+{
+ dw_fde_ref fde;
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ /* Output a label to mark the endpoint of the code generated for this
+ function. */
+ ASM_GENERATE_INTERNAL_LABEL (label, FUNC_END_LABEL, current_funcdef_number);
+ ASM_OUTPUT_LABEL (asm_out_file, label);
+ fde = &fde_table[fde_table_in_use - 1];
+ fde->dw_fde_end = xstrdup (label);
+}
+
+void
+dwarf2out_frame_init ()
+{
+ /* Allocate the initial hunk of the fde_table. */
+ fde_table
+ = (dw_fde_ref) xmalloc (FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
+ bzero ((char *) fde_table, FDE_TABLE_INCREMENT * sizeof (dw_fde_node));
+ fde_table_allocated = FDE_TABLE_INCREMENT;
+ fde_table_in_use = 0;
+
+ /* Generate the CFA instructions common to all FDE's. Do it now for the
+ sake of lookup_cfa. */
+
+#ifdef DWARF2_UNWIND_INFO
+ /* On entry, the Canonical Frame Address is at SP. */
+ dwarf2out_def_cfa (NULL, STACK_POINTER_REGNUM, INCOMING_FRAME_SP_OFFSET);
+ initial_return_save (INCOMING_RETURN_ADDR_RTX);
+#endif
+}
+
+void
+dwarf2out_frame_finish ()
+{
+ /* Output call frame information. */
+#ifdef MIPS_DEBUGGING_INFO
+ if (write_symbols == DWARF2_DEBUG)
+ output_call_frame_info (0);
+ if (flag_exceptions && ! exceptions_via_longjmp)
+ output_call_frame_info (1);
+#else
+ if (write_symbols == DWARF2_DEBUG
+ || (flag_exceptions && ! exceptions_via_longjmp))
+ output_call_frame_info (1);
+#endif
+}
+
+#endif /* .debug_frame support */
+
+/* And now, the support for symbolic debugging information. */
+#ifdef DWARF2_DEBUGGING_INFO
+
+extern char *getpwd PROTO((void));
+
+/* NOTE: In the comments in this file, many references are made to
+ "Debugging Information Entries". This term is abbreviated as `DIE'
+ throughout the remainder of this file. */
+
+/* An internal representation of the DWARF output is built, and then
+ walked to generate the DWARF debugging info. The walk of the internal
+ representation is done after the entire program has been compiled.
+ The types below are used to describe the internal representation. */
+
+/* Each DIE may have a series of attribute/value pairs. Values
+ can take on several forms. The forms that are used in this
+ implementation are listed below. */
+
+typedef enum
+{
+ dw_val_class_addr,
+ dw_val_class_loc,
+ dw_val_class_const,
+ dw_val_class_unsigned_const,
+ dw_val_class_long_long,
+ dw_val_class_float,
+ dw_val_class_flag,
+ dw_val_class_die_ref,
+ dw_val_class_fde_ref,
+ dw_val_class_lbl_id,
+ dw_val_class_section_offset,
+ dw_val_class_str
+}
+dw_val_class;
+
+/* Various DIE's use offsets relative to the beginning of the
+ .debug_info section to refer to each other. */
+
+typedef long int dw_offset;
+
+/* Define typedefs here to avoid circular dependencies. */
+
+typedef struct die_struct *dw_die_ref;
+typedef struct dw_attr_struct *dw_attr_ref;
+typedef struct dw_val_struct *dw_val_ref;
+typedef struct dw_line_info_struct *dw_line_info_ref;
+typedef struct dw_separate_line_info_struct *dw_separate_line_info_ref;
+typedef struct dw_loc_descr_struct *dw_loc_descr_ref;
+typedef struct pubname_struct *pubname_ref;
+typedef dw_die_ref *arange_ref;
+
+/* Describe a double word constant value. */
+
+typedef struct dw_long_long_struct
+{
+ unsigned long hi;
+ unsigned long low;
+}
+dw_long_long_const;
+
+/* Describe a floating point constant value. */
+
+typedef struct dw_fp_struct
+{
+ long *array;
+ unsigned length;
+}
+dw_float_const;
+
+/* Each entry in the line_info_table maintains the file and
+ line number associated with the label generated for that
+ entry. The label gives the PC value associated with
+ the line number entry. */
+
+typedef struct dw_line_info_struct
+{
+ unsigned long dw_file_num;
+ unsigned long dw_line_num;
+}
+dw_line_info_entry;
+
+/* Line information for functions in separate sections; each one gets its
+ own sequence. */
+typedef struct dw_separate_line_info_struct
+{
+ unsigned long dw_file_num;
+ unsigned long dw_line_num;
+ unsigned long function;
+}
+dw_separate_line_info_entry;
+
+/* The dw_val_node describes an attribute's value, as it is
+ represented internally. */
+
+typedef struct dw_val_struct
+{
+ dw_val_class val_class;
+ union
+ {
+ char *val_addr;
+ dw_loc_descr_ref val_loc;
+ long int val_int;
+ long unsigned val_unsigned;
+ dw_long_long_const val_long_long;
+ dw_float_const val_float;
+ dw_die_ref val_die_ref;
+ unsigned val_fde_index;
+ char *val_str;
+ char *val_lbl_id;
+ char *val_section;
+ unsigned char val_flag;
+ }
+ v;
+}
+dw_val_node;
+
+/* Locations in memory are described using a sequence of stack machine
+ operations. */
+
+typedef struct dw_loc_descr_struct
+{
+ dw_loc_descr_ref dw_loc_next;
+ enum dwarf_location_atom dw_loc_opc;
+ dw_val_node dw_loc_oprnd1;
+ dw_val_node dw_loc_oprnd2;
+}
+dw_loc_descr_node;
+
+/* Each DIE attribute has a field specifying the attribute kind,
+ a link to the next attribute in the chain, and an attribute value.
+ Attributes are typically linked below the DIE they modify. */
+
+typedef struct dw_attr_struct
+{
+ enum dwarf_attribute dw_attr;
+ dw_attr_ref dw_attr_next;
+ dw_val_node dw_attr_val;
+}
+dw_attr_node;
+
+/* The Debugging Information Entry (DIE) structure */
+
+typedef struct die_struct
+{
+ enum dwarf_tag die_tag;
+ dw_attr_ref die_attr;
+ dw_attr_ref die_attr_last;
+ dw_die_ref die_parent;
+ dw_die_ref die_child;
+ dw_die_ref die_child_last;
+ dw_die_ref die_sib;
+ dw_offset die_offset;
+ unsigned long die_abbrev;
+}
+die_node;
+
+/* The pubname structure */
+
+typedef struct pubname_struct
+{
+ dw_die_ref die;
+ char * name;
+}
+pubname_entry;
+
+/* The limbo die list structure. */
+typedef struct limbo_die_struct
+{
+ dw_die_ref die;
+ struct limbo_die_struct *next;
+}
+limbo_die_node;
+
+/* How to start an assembler comment. */
+#ifndef ASM_COMMENT_START
+#define ASM_COMMENT_START ";#"
+#endif
+
+/* Define a macro which returns non-zero for a TYPE_DECL which was
+ implicitly generated for a tagged type.
+
+ Note that unlike the gcc front end (which generates a NULL named
+ TYPE_DECL node for each complete tagged type, each array type, and
+ each function type node created) the g++ front end generates a
+ _named_ TYPE_DECL node for each tagged type node created.
+ These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to
+ generate a DW_TAG_typedef DIE for them. */
+
+#define TYPE_DECL_IS_STUB(decl) \
+ (DECL_NAME (decl) == NULL_TREE \
+ || (DECL_ARTIFICIAL (decl) \
+ && is_tagged_type (TREE_TYPE (decl)) \
+ && ((decl == TYPE_STUB_DECL (TREE_TYPE (decl))) \
+ /* This is necessary for stub decls that \
+ appear in nested inline functions. */ \
+ || (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE \
+ && (decl_ultimate_origin (decl) \
+ == TYPE_STUB_DECL (TREE_TYPE (decl)))))))
+
+/* Information concerning the compilation unit's programming
+ language, and compiler version. */
+
+extern int flag_traditional;
+extern char *version_string;
+extern char *language_string;
+
+/* Fixed size portion of the DWARF compilation unit header. */
+#define DWARF_COMPILE_UNIT_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 3)
+
+/* Fixed size portion of debugging line information prolog. */
+#define DWARF_LINE_PROLOG_HEADER_SIZE 5
+
+/* Fixed size portion of public names info. */
+#define DWARF_PUBNAMES_HEADER_SIZE (2 * DWARF_OFFSET_SIZE + 2)
+
+/* Fixed size portion of the address range info. */
+#define DWARF_ARANGES_HEADER_SIZE \
+ (DWARF_ROUND (2 * DWARF_OFFSET_SIZE + 4, PTR_SIZE * 2) - DWARF_OFFSET_SIZE)
+
+/* Define the architecture-dependent minimum instruction length (in bytes).
+ In this implementation of DWARF, this field is used for information
+ purposes only. Since GCC generates assembly language, we have
+ no a priori knowledge of how many instruction bytes are generated
+ for each source line, and therefore can use only the DW_LNE_set_address
+ and DW_LNS_fixed_advance_pc line information commands. */
+
+#ifndef DWARF_LINE_MIN_INSTR_LENGTH
+#define DWARF_LINE_MIN_INSTR_LENGTH 4
+#endif
+
+/* Minimum line offset in a special line info. opcode.
+ This value was chosen to give a reasonable range of values. */
+#define DWARF_LINE_BASE -10
+
+/* First special line opcde - leave room for the standard opcodes. */
+#define DWARF_LINE_OPCODE_BASE 10
+
+/* Range of line offsets in a special line info. opcode. */
+#define DWARF_LINE_RANGE (254-DWARF_LINE_OPCODE_BASE+1)
+
+/* Flag that indicates the initial value of the is_stmt_start flag.
+ In the present implementation, we do not mark any lines as
+ the beginning of a source statement, because that information
+ is not made available by the GCC front-end. */
+#define DWARF_LINE_DEFAULT_IS_STMT_START 1
+
+/* This location is used by calc_die_sizes() to keep track
+ the offset of each DIE within the .debug_info section. */
+static unsigned long next_die_offset;
+
+/* Record the root of the DIE's built for the current compilation unit. */
+static dw_die_ref comp_unit_die;
+
+/* A list of DIEs with a NULL parent waiting to be relocated. */
+static limbo_die_node *limbo_die_list = 0;
+
+/* Pointer to an array of filenames referenced by this compilation unit. */
+static char **file_table;
+
+/* Total number of entries in the table (i.e. array) pointed to by
+ `file_table'. This is the *total* and includes both used and unused
+ slots. */
+static unsigned file_table_allocated;
+
+/* Number of entries in the file_table which are actually in use. */
+static unsigned file_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the filename
+ table. */
+#define FILE_TABLE_INCREMENT 64
+
+/* Local pointer to the name of the main input file. Initialized in
+ dwarf2out_init. */
+static char *primary_filename;
+
+/* For Dwarf output, we must assign lexical-blocks id numbers in the order in
+ which their beginnings are encountered. We output Dwarf debugging info
+ that refers to the beginnings and ends of the ranges of code for each
+ lexical block. The labels themselves are generated in final.c, which
+ assigns numbers to the blocks in the same way. */
+static unsigned next_block_number = 2;
+
+/* A pointer to the base of a table of references to DIE's that describe
+ declarations. The table is indexed by DECL_UID() which is a unique
+ number identifying each decl. */
+static dw_die_ref *decl_die_table;
+
+/* Number of elements currently allocated for the decl_die_table. */
+static unsigned decl_die_table_allocated;
+
+/* Number of elements in decl_die_table currently in use. */
+static unsigned decl_die_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ decl_die_table. */
+#define DECL_DIE_TABLE_INCREMENT 256
+
+/* Structure used for the decl_scope table. scope is the current declaration
+ scope, and previous is the entry that is the parent of this scope. This
+ is usually but not always the immediately preceeding entry. */
+
+typedef struct decl_scope_struct
+{
+ tree scope;
+ int previous;
+}
+decl_scope_node;
+
+/* A pointer to the base of a table of references to declaration
+ scopes. This table is a display which tracks the nesting
+ of declaration scopes at the current scope and containing
+ scopes. This table is used to find the proper place to
+ define type declaration DIE's. */
+static decl_scope_node *decl_scope_table;
+
+/* Number of elements currently allocated for the decl_scope_table. */
+static int decl_scope_table_allocated;
+
+/* Current level of nesting of declaration scopes. */
+static int decl_scope_depth;
+
+/* Size (in elements) of increments by which we may expand the
+ decl_scope_table. */
+#define DECL_SCOPE_TABLE_INCREMENT 64
+
+/* A pointer to the base of a list of references to DIE's that
+ are uniquely identified by their tag, presence/absence of
+ children DIE's, and list of attribute/value pairs. */
+static dw_die_ref *abbrev_die_table;
+
+/* Number of elements currently allocated for abbrev_die_table. */
+static unsigned abbrev_die_table_allocated;
+
+/* Number of elements in type_die_table currently in use. */
+static unsigned abbrev_die_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ abbrev_die_table. */
+#define ABBREV_DIE_TABLE_INCREMENT 256
+
+/* A pointer to the base of a table that contains line information
+ for each source code line in .text in the compilation unit. */
+static dw_line_info_ref line_info_table;
+
+/* Number of elements currently allocated for line_info_table. */
+static unsigned line_info_table_allocated;
+
+/* Number of elements in separate_line_info_table currently in use. */
+static unsigned separate_line_info_table_in_use;
+
+/* A pointer to the base of a table that contains line information
+ for each source code line outside of .text in the compilation unit. */
+static dw_separate_line_info_ref separate_line_info_table;
+
+/* Number of elements currently allocated for separate_line_info_table. */
+static unsigned separate_line_info_table_allocated;
+
+/* Number of elements in line_info_table currently in use. */
+static unsigned line_info_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ line_info_table. */
+#define LINE_INFO_TABLE_INCREMENT 1024
+
+/* A pointer to the base of a table that contains a list of publicly
+ accessible names. */
+static pubname_ref pubname_table;
+
+/* Number of elements currently allocated for pubname_table. */
+static unsigned pubname_table_allocated;
+
+/* Number of elements in pubname_table currently in use. */
+static unsigned pubname_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ pubname_table. */
+#define PUBNAME_TABLE_INCREMENT 64
+
+/* A pointer to the base of a table that contains a list of publicly
+ accessible names. */
+static arange_ref arange_table;
+
+/* Number of elements currently allocated for arange_table. */
+static unsigned arange_table_allocated;
+
+/* Number of elements in arange_table currently in use. */
+static unsigned arange_table_in_use;
+
+/* Size (in elements) of increments by which we may expand the
+ arange_table. */
+#define ARANGE_TABLE_INCREMENT 64
+
+/* A pointer to the base of a list of pending types which we haven't
+ generated DIEs for yet, but which we will have to come back to
+ later on. */
+
+static tree *pending_types_list;
+
+/* Number of elements currently allocated for the pending_types_list. */
+static unsigned pending_types_allocated;
+
+/* Number of elements of pending_types_list currently in use. */
+static unsigned pending_types;
+
+/* Size (in elements) of increments by which we may expand the pending
+ types list. Actually, a single hunk of space of this size should
+ be enough for most typical programs. */
+#define PENDING_TYPES_INCREMENT 64
+
+/* Record whether the function being analyzed contains inlined functions. */
+static int current_function_has_inlines;
+#if 0 && defined (MIPS_DEBUGGING_INFO)
+static int comp_unit_has_inlines;
+#endif
+
+/* A pointer to the ..._DECL node which we have most recently been working
+ on. We keep this around just in case something about it looks screwy and
+ we want to tell the user what the source coordinates for the actual
+ declaration are. */
+static tree dwarf_last_decl;
+
+/* Forward declarations for functions defined in this file. */
+
+static void addr_const_to_string PROTO((dyn_string_t, rtx));
+static char *addr_to_string PROTO((rtx));
+static int is_pseudo_reg PROTO((rtx));
+static tree type_main_variant PROTO((tree));
+static int is_tagged_type PROTO((tree));
+static char *dwarf_tag_name PROTO((unsigned));
+static char *dwarf_attr_name PROTO((unsigned));
+static char *dwarf_form_name PROTO((unsigned));
+static char *dwarf_stack_op_name PROTO((unsigned));
+#if 0
+static char *dwarf_type_encoding_name PROTO((unsigned));
+#endif
+static tree decl_ultimate_origin PROTO((tree));
+static tree block_ultimate_origin PROTO((tree));
+static tree decl_class_context PROTO((tree));
+static void add_dwarf_attr PROTO((dw_die_ref, dw_attr_ref));
+static void add_AT_flag PROTO((dw_die_ref,
+ enum dwarf_attribute,
+ unsigned));
+static void add_AT_int PROTO((dw_die_ref,
+ enum dwarf_attribute, long));
+static void add_AT_unsigned PROTO((dw_die_ref,
+ enum dwarf_attribute,
+ unsigned long));
+static void add_AT_long_long PROTO((dw_die_ref,
+ enum dwarf_attribute,
+ unsigned long, unsigned long));
+static void add_AT_float PROTO((dw_die_ref,
+ enum dwarf_attribute,
+ unsigned, long *));
+static void add_AT_string PROTO((dw_die_ref,
+ enum dwarf_attribute, char *));
+static void add_AT_die_ref PROTO((dw_die_ref,
+ enum dwarf_attribute,
+ dw_die_ref));
+static void add_AT_fde_ref PROTO((dw_die_ref,
+ enum dwarf_attribute,
+ unsigned));
+static void add_AT_loc PROTO((dw_die_ref,
+ enum dwarf_attribute,
+ dw_loc_descr_ref));
+static void add_AT_addr PROTO((dw_die_ref,
+ enum dwarf_attribute, char *));
+static void add_AT_lbl_id PROTO((dw_die_ref,
+ enum dwarf_attribute, char *));
+static void add_AT_section_offset PROTO((dw_die_ref,
+ enum dwarf_attribute, char *));
+static int is_extern_subr_die PROTO((dw_die_ref));
+static dw_attr_ref get_AT PROTO((dw_die_ref,
+ enum dwarf_attribute));
+static char *get_AT_low_pc PROTO((dw_die_ref));
+static char *get_AT_hi_pc PROTO((dw_die_ref));
+static char *get_AT_string PROTO((dw_die_ref,
+ enum dwarf_attribute));
+static int get_AT_flag PROTO((dw_die_ref,
+ enum dwarf_attribute));
+static unsigned get_AT_unsigned PROTO((dw_die_ref,
+ enum dwarf_attribute));
+static int is_c_family PROTO((void));
+static int is_fortran PROTO((void));
+static void remove_AT PROTO((dw_die_ref,
+ enum dwarf_attribute));
+static void remove_children PROTO((dw_die_ref));
+static void add_child_die PROTO((dw_die_ref, dw_die_ref));
+static dw_die_ref new_die PROTO((enum dwarf_tag, dw_die_ref));
+static dw_die_ref lookup_type_die PROTO((tree));
+static void equate_type_number_to_die PROTO((tree, dw_die_ref));
+static dw_die_ref lookup_decl_die PROTO((tree));
+static void equate_decl_number_to_die PROTO((tree, dw_die_ref));
+static dw_loc_descr_ref new_loc_descr PROTO((enum dwarf_location_atom,
+ unsigned long, unsigned long));
+static void add_loc_descr PROTO((dw_loc_descr_ref *,
+ dw_loc_descr_ref));
+static void print_spaces PROTO((FILE *));
+static void print_die PROTO((dw_die_ref, FILE *));
+static void print_dwarf_line_table PROTO((FILE *));
+static void add_sibling_attributes PROTO((dw_die_ref));
+static void build_abbrev_table PROTO((dw_die_ref));
+static unsigned long size_of_string PROTO((char *));
+static unsigned long size_of_loc_descr PROTO((dw_loc_descr_ref));
+static unsigned long size_of_locs PROTO((dw_loc_descr_ref));
+static int constant_size PROTO((long unsigned));
+static unsigned long size_of_die PROTO((dw_die_ref));
+static void calc_die_sizes PROTO((dw_die_ref));
+static unsigned long size_of_line_prolog PROTO((void));
+static unsigned long size_of_line_info PROTO((void));
+static unsigned long size_of_pubnames PROTO((void));
+static unsigned long size_of_aranges PROTO((void));
+static enum dwarf_form value_format PROTO((dw_val_ref));
+static void output_value_format PROTO((dw_val_ref));
+static void output_abbrev_section PROTO((void));
+static void output_loc_operands PROTO((dw_loc_descr_ref));
+static unsigned long sibling_offset PROTO((dw_die_ref));
+static void output_die PROTO((dw_die_ref));
+static void output_compilation_unit_header PROTO((void));
+static char *dwarf2_name PROTO((tree, int));
+static void add_pubname PROTO((tree, dw_die_ref));
+static void output_pubnames PROTO((void));
+static void add_arange PROTO((tree, dw_die_ref));
+static void output_aranges PROTO((void));
+static void output_line_info PROTO((void));
+static int is_body_block PROTO((tree));
+static dw_die_ref base_type_die PROTO((tree));
+static tree root_type PROTO((tree));
+static int is_base_type PROTO((tree));
+static dw_die_ref modified_type_die PROTO((tree, int, int, dw_die_ref));
+static int type_is_enum PROTO((tree));
+static dw_loc_descr_ref reg_loc_descriptor PROTO((rtx));
+static dw_loc_descr_ref based_loc_descr PROTO((unsigned, long));
+static int is_based_loc PROTO((rtx));
+static dw_loc_descr_ref mem_loc_descriptor PROTO((rtx));
+static dw_loc_descr_ref concat_loc_descriptor PROTO((rtx, rtx));
+static dw_loc_descr_ref loc_descriptor PROTO((rtx));
+static unsigned ceiling PROTO((unsigned, unsigned));
+static tree field_type PROTO((tree));
+static unsigned simple_type_align_in_bits PROTO((tree));
+static unsigned simple_type_size_in_bits PROTO((tree));
+static unsigned field_byte_offset PROTO((tree));
+static void add_AT_location_description PROTO((dw_die_ref,
+ enum dwarf_attribute, rtx));
+static void add_data_member_location_attribute PROTO((dw_die_ref, tree));
+static void add_const_value_attribute PROTO((dw_die_ref, rtx));
+static void add_location_or_const_value_attribute PROTO((dw_die_ref, tree));
+static void add_name_attribute PROTO((dw_die_ref, char *));
+static void add_bound_info PROTO((dw_die_ref,
+ enum dwarf_attribute, tree));
+static void add_subscript_info PROTO((dw_die_ref, tree));
+static void add_byte_size_attribute PROTO((dw_die_ref, tree));
+static void add_bit_offset_attribute PROTO((dw_die_ref, tree));
+static void add_bit_size_attribute PROTO((dw_die_ref, tree));
+static void add_prototyped_attribute PROTO((dw_die_ref, tree));
+static void add_abstract_origin_attribute PROTO((dw_die_ref, tree));
+static void add_pure_or_virtual_attribute PROTO((dw_die_ref, tree));
+static void add_src_coords_attributes PROTO((dw_die_ref, tree));
+static void add_name_and_src_coords_attributes PROTO((dw_die_ref, tree));
+static void push_decl_scope PROTO((tree));
+static dw_die_ref scope_die_for PROTO((tree, dw_die_ref));
+static void pop_decl_scope PROTO((void));
+static void add_type_attribute PROTO((dw_die_ref, tree, int, int,
+ dw_die_ref));
+static char *type_tag PROTO((tree));
+static tree member_declared_type PROTO((tree));
+#if 0
+static char *decl_start_label PROTO((tree));
+#endif
+static void gen_array_type_die PROTO((tree, dw_die_ref));
+static void gen_set_type_die PROTO((tree, dw_die_ref));
+#if 0
+static void gen_entry_point_die PROTO((tree, dw_die_ref));
+#endif
+static void pend_type PROTO((tree));
+static void output_pending_types_for_scope PROTO((dw_die_ref));
+static void gen_inlined_enumeration_type_die PROTO((tree, dw_die_ref));
+static void gen_inlined_structure_type_die PROTO((tree, dw_die_ref));
+static void gen_inlined_union_type_die PROTO((tree, dw_die_ref));
+static void gen_enumeration_type_die PROTO((tree, dw_die_ref));
+static dw_die_ref gen_formal_parameter_die PROTO((tree, dw_die_ref));
+static void gen_unspecified_parameters_die PROTO((tree, dw_die_ref));
+static void gen_formal_types_die PROTO((tree, dw_die_ref));
+static void gen_subprogram_die PROTO((tree, dw_die_ref));
+static void gen_variable_die PROTO((tree, dw_die_ref));
+static void gen_label_die PROTO((tree, dw_die_ref));
+static void gen_lexical_block_die PROTO((tree, dw_die_ref, int));
+static void gen_inlined_subroutine_die PROTO((tree, dw_die_ref, int));
+static void gen_field_die PROTO((tree, dw_die_ref));
+static void gen_ptr_to_mbr_type_die PROTO((tree, dw_die_ref));
+static void gen_compile_unit_die PROTO((char *));
+static void gen_string_type_die PROTO((tree, dw_die_ref));
+static void gen_inheritance_die PROTO((tree, dw_die_ref));
+static void gen_member_die PROTO((tree, dw_die_ref));
+static void gen_struct_or_union_type_die PROTO((tree, dw_die_ref));
+static void gen_subroutine_type_die PROTO((tree, dw_die_ref));
+static void gen_typedef_die PROTO((tree, dw_die_ref));
+static void gen_type_die PROTO((tree, dw_die_ref));
+static void gen_tagged_type_instantiation_die PROTO((tree, dw_die_ref));
+static void gen_block_die PROTO((tree, dw_die_ref, int));
+static void decls_for_scope PROTO((tree, dw_die_ref, int));
+static int is_redundant_typedef PROTO((tree));
+static void gen_decl_die PROTO((tree, dw_die_ref));
+static unsigned lookup_filename PROTO((char *));
+
+/* Section names used to hold DWARF debugging information. */
+#ifndef DEBUG_INFO_SECTION
+#define DEBUG_INFO_SECTION ".debug_info"
+#endif
+#ifndef ABBREV_SECTION
+#define ABBREV_SECTION ".debug_abbrev"
+#endif
+#ifndef ARANGES_SECTION
+#define ARANGES_SECTION ".debug_aranges"
+#endif
+#ifndef DW_MACINFO_SECTION
+#define DW_MACINFO_SECTION ".debug_macinfo"
+#endif
+#ifndef DEBUG_LINE_SECTION
+#define DEBUG_LINE_SECTION ".debug_line"
+#endif
+#ifndef LOC_SECTION
+#define LOC_SECTION ".debug_loc"
+#endif
+#ifndef PUBNAMES_SECTION
+#define PUBNAMES_SECTION ".debug_pubnames"
+#endif
+#ifndef STR_SECTION
+#define STR_SECTION ".debug_str"
+#endif
+
+/* Standard ELF section names for compiled code and data. */
+#ifndef TEXT_SECTION
+#define TEXT_SECTION ".text"
+#endif
+#ifndef DATA_SECTION
+#define DATA_SECTION ".data"
+#endif
+#ifndef BSS_SECTION
+#define BSS_SECTION ".bss"
+#endif
+
+
+/* Definitions of defaults for formats and names of various special
+ (artificial) labels which may be generated within this file (when the -g
+ options is used and DWARF_DEBUGGING_INFO is in effect.
+ If necessary, these may be overridden from within the tm.h file, but
+ typically, overriding these defaults is unnecessary. */
+
+static char text_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+#ifndef TEXT_END_LABEL
+#define TEXT_END_LABEL "Letext"
+#endif
+#ifndef DATA_END_LABEL
+#define DATA_END_LABEL "Ledata"
+#endif
+#ifndef BSS_END_LABEL
+#define BSS_END_LABEL "Lebss"
+#endif
+#ifndef INSN_LABEL_FMT
+#define INSN_LABEL_FMT "LI%u_"
+#endif
+#ifndef BLOCK_BEGIN_LABEL
+#define BLOCK_BEGIN_LABEL "LBB"
+#endif
+#ifndef BLOCK_END_LABEL
+#define BLOCK_END_LABEL "LBE"
+#endif
+#ifndef BODY_BEGIN_LABEL
+#define BODY_BEGIN_LABEL "Lbb"
+#endif
+#ifndef BODY_END_LABEL
+#define BODY_END_LABEL "Lbe"
+#endif
+#ifndef LINE_CODE_LABEL
+#define LINE_CODE_LABEL "LM"
+#endif
+#ifndef SEPARATE_LINE_CODE_LABEL
+#define SEPARATE_LINE_CODE_LABEL "LSM"
+#endif
+
+/* Convert a reference to the assembler name of a C-level name. This
+ macro has the same effect as ASM_OUTPUT_LABELREF, but copies to
+ a string rather than writing to a file. */
+#ifndef ASM_NAME_TO_STRING
+#define ASM_NAME_TO_STRING(STR, NAME) \
+ do { \
+ if ((NAME)[0] == '*') \
+ dyn_string_append (STR, NAME + 1); \
+ else \
+ dyn_string_append (STR, NAME); \
+ } \
+ while (0)
+#endif
+
+/* Convert an integer constant expression into assembler syntax. Addition
+ and subtraction are the only arithmetic that may appear in these
+ expressions. This is an adaptation of output_addr_const in final.c.
+ Here, the target of the conversion is a string buffer. We can't use
+ output_addr_const directly, because it writes to a file. */
+
+static void
+addr_const_to_string (str, x)
+ dyn_string_t str;
+ rtx x;
+{
+ char buf1[256];
+
+restart:
+ switch (GET_CODE (x))
+ {
+ case PC:
+ if (flag_pic)
+ dyn_string_append (str, ",");
+ else
+ abort ();
+ break;
+
+ case SYMBOL_REF:
+ ASM_NAME_TO_STRING (str, XSTR (x, 0));
+ break;
+
+ case LABEL_REF:
+ ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (XEXP (x, 0)));
+ ASM_NAME_TO_STRING (str, buf1);
+ break;
+
+ case CODE_LABEL:
+ ASM_GENERATE_INTERNAL_LABEL (buf1, "L", CODE_LABEL_NUMBER (x));
+ ASM_NAME_TO_STRING (str, buf1);
+ break;
+
+ case CONST_INT:
+ sprintf (buf1, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
+ dyn_string_append (str, buf1);
+ break;
+
+ case CONST:
+ /* This used to output parentheses around the expression, but that does
+ not work on the 386 (either ATT or BSD assembler). */
+ addr_const_to_string (str, XEXP (x, 0));
+ break;
+
+ case CONST_DOUBLE:
+ if (GET_MODE (x) == VOIDmode)
+ {
+ /* We can use %d if the number is one word and positive. */
+ if (CONST_DOUBLE_HIGH (x))
+ sprintf (buf1, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+ CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
+ else if (CONST_DOUBLE_LOW (x) < 0)
+ sprintf (buf1, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
+ else
+ sprintf (buf1, HOST_WIDE_INT_PRINT_DEC,
+ CONST_DOUBLE_LOW (x));
+ dyn_string_append (str, buf1);
+ }
+ else
+ /* We can't handle floating point constants; PRINT_OPERAND must
+ handle them. */
+ output_operand_lossage ("floating constant misused");
+ break;
+
+ case PLUS:
+ /* Some assemblers need integer constants to appear last (eg masm). */
+ if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+ {
+ addr_const_to_string (str, XEXP (x, 1));
+ if (INTVAL (XEXP (x, 0)) >= 0)
+ dyn_string_append (str, "+");
+
+ addr_const_to_string (str, XEXP (x, 0));
+ }
+ else
+ {
+ addr_const_to_string (str, XEXP (x, 0));
+ if (INTVAL (XEXP (x, 1)) >= 0)
+ dyn_string_append (str, "+");
+
+ addr_const_to_string (str, XEXP (x, 1));
+ }
+ break;
+
+ case MINUS:
+ /* Avoid outputting things like x-x or x+5-x, since some assemblers
+ can't handle that. */
+ x = simplify_subtraction (x);
+ if (GET_CODE (x) != MINUS)
+ goto restart;
+
+ addr_const_to_string (str, XEXP (x, 0));
+ dyn_string_append (str, "-");
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT
+ && INTVAL (XEXP (x, 1)) < 0)
+ {
+ dyn_string_append (str, ASM_OPEN_PAREN);
+ addr_const_to_string (str, XEXP (x, 1));
+ dyn_string_append (str, ASM_CLOSE_PAREN);
+ }
+ else
+ addr_const_to_string (str, XEXP (x, 1));
+ break;
+
+ case ZERO_EXTEND:
+ case SIGN_EXTEND:
+ addr_const_to_string (str, XEXP (x, 0));
+ break;
+
+ default:
+ output_operand_lossage ("invalid expression as operand");
+ }
+}
+
+/* Convert an address constant to a string, and return a pointer to
+ a copy of the result, located on the heap. */
+
+static char *
+addr_to_string (x)
+ rtx x;
+{
+ dyn_string_t ds = dyn_string_new (256);
+ char *s;
+
+ addr_const_to_string (ds, x);
+
+ /* Return the dynamically allocated string, but free the
+ dyn_string_t itself. */
+ s = ds->s;
+ free (ds);
+ return s;
+}
+
+/* Test if rtl node points to a pseudo register. */
+
+static inline int
+is_pseudo_reg (rtl)
+ register rtx rtl;
+{
+ return (((GET_CODE (rtl) == REG) && (REGNO (rtl) >= FIRST_PSEUDO_REGISTER))
+ || ((GET_CODE (rtl) == SUBREG)
+ && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)));
+}
+
+/* Return a reference to a type, with its const and volatile qualifiers
+ removed. */
+
+static inline tree
+type_main_variant (type)
+ register tree type;
+{
+ type = TYPE_MAIN_VARIANT (type);
+
+ /* There really should be only one main variant among any group of variants
+ of a given type (and all of the MAIN_VARIANT values for all members of
+ the group should point to that one type) but sometimes the C front-end
+ messes this up for array types, so we work around that bug here. */
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ while (type != TYPE_MAIN_VARIANT (type))
+ type = TYPE_MAIN_VARIANT (type);
+
+ return type;
+}
+
+/* Return non-zero if the given type node represents a tagged type. */
+
+static inline int
+is_tagged_type (type)
+ register tree type;
+{
+ register enum tree_code code = TREE_CODE (type);
+
+ return (code == RECORD_TYPE || code == UNION_TYPE
+ || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
+}
+
+/* Convert a DIE tag into its string name. */
+
+static char *
+dwarf_tag_name (tag)
+ register unsigned tag;
+{
+ switch (tag)
+ {
+ case DW_TAG_padding:
+ return "DW_TAG_padding";
+ case DW_TAG_array_type:
+ return "DW_TAG_array_type";
+ case DW_TAG_class_type:
+ return "DW_TAG_class_type";
+ case DW_TAG_entry_point:
+ return "DW_TAG_entry_point";
+ case DW_TAG_enumeration_type:
+ return "DW_TAG_enumeration_type";
+ case DW_TAG_formal_parameter:
+ return "DW_TAG_formal_parameter";
+ case DW_TAG_imported_declaration:
+ return "DW_TAG_imported_declaration";
+ case DW_TAG_label:
+ return "DW_TAG_label";
+ case DW_TAG_lexical_block:
+ return "DW_TAG_lexical_block";
+ case DW_TAG_member:
+ return "DW_TAG_member";
+ case DW_TAG_pointer_type:
+ return "DW_TAG_pointer_type";
+ case DW_TAG_reference_type:
+ return "DW_TAG_reference_type";
+ case DW_TAG_compile_unit:
+ return "DW_TAG_compile_unit";
+ case DW_TAG_string_type:
+ return "DW_TAG_string_type";
+ case DW_TAG_structure_type:
+ return "DW_TAG_structure_type";
+ case DW_TAG_subroutine_type:
+ return "DW_TAG_subroutine_type";
+ case DW_TAG_typedef:
+ return "DW_TAG_typedef";
+ case DW_TAG_union_type:
+ return "DW_TAG_union_type";
+ case DW_TAG_unspecified_parameters:
+ return "DW_TAG_unspecified_parameters";
+ case DW_TAG_variant:
+ return "DW_TAG_variant";
+ case DW_TAG_common_block:
+ return "DW_TAG_common_block";
+ case DW_TAG_common_inclusion:
+ return "DW_TAG_common_inclusion";
+ case DW_TAG_inheritance:
+ return "DW_TAG_inheritance";
+ case DW_TAG_inlined_subroutine:
+ return "DW_TAG_inlined_subroutine";
+ case DW_TAG_module:
+ return "DW_TAG_module";
+ case DW_TAG_ptr_to_member_type:
+ return "DW_TAG_ptr_to_member_type";
+ case DW_TAG_set_type:
+ return "DW_TAG_set_type";
+ case DW_TAG_subrange_type:
+ return "DW_TAG_subrange_type";
+ case DW_TAG_with_stmt:
+ return "DW_TAG_with_stmt";
+ case DW_TAG_access_declaration:
+ return "DW_TAG_access_declaration";
+ case DW_TAG_base_type:
+ return "DW_TAG_base_type";
+ case DW_TAG_catch_block:
+ return "DW_TAG_catch_block";
+ case DW_TAG_const_type:
+ return "DW_TAG_const_type";
+ case DW_TAG_constant:
+ return "DW_TAG_constant";
+ case DW_TAG_enumerator:
+ return "DW_TAG_enumerator";
+ case DW_TAG_file_type:
+ return "DW_TAG_file_type";
+ case DW_TAG_friend:
+ return "DW_TAG_friend";
+ case DW_TAG_namelist:
+ return "DW_TAG_namelist";
+ case DW_TAG_namelist_item:
+ return "DW_TAG_namelist_item";
+ case DW_TAG_packed_type:
+ return "DW_TAG_packed_type";
+ case DW_TAG_subprogram:
+ return "DW_TAG_subprogram";
+ case DW_TAG_template_type_param:
+ return "DW_TAG_template_type_param";
+ case DW_TAG_template_value_param:
+ return "DW_TAG_template_value_param";
+ case DW_TAG_thrown_type:
+ return "DW_TAG_thrown_type";
+ case DW_TAG_try_block:
+ return "DW_TAG_try_block";
+ case DW_TAG_variant_part:
+ return "DW_TAG_variant_part";
+ case DW_TAG_variable:
+ return "DW_TAG_variable";
+ case DW_TAG_volatile_type:
+ return "DW_TAG_volatile_type";
+ case DW_TAG_MIPS_loop:
+ return "DW_TAG_MIPS_loop";
+ case DW_TAG_format_label:
+ return "DW_TAG_format_label";
+ case DW_TAG_function_template:
+ return "DW_TAG_function_template";
+ case DW_TAG_class_template:
+ return "DW_TAG_class_template";
+ default:
+ return "DW_TAG_<unknown>";
+ }
+}
+
+/* Convert a DWARF attribute code into its string name. */
+
+static char *
+dwarf_attr_name (attr)
+ register unsigned attr;
+{
+ switch (attr)
+ {
+ case DW_AT_sibling:
+ return "DW_AT_sibling";
+ case DW_AT_location:
+ return "DW_AT_location";
+ case DW_AT_name:
+ return "DW_AT_name";
+ case DW_AT_ordering:
+ return "DW_AT_ordering";
+ case DW_AT_subscr_data:
+ return "DW_AT_subscr_data";
+ case DW_AT_byte_size:
+ return "DW_AT_byte_size";
+ case DW_AT_bit_offset:
+ return "DW_AT_bit_offset";
+ case DW_AT_bit_size:
+ return "DW_AT_bit_size";
+ case DW_AT_element_list:
+ return "DW_AT_element_list";
+ case DW_AT_stmt_list:
+ return "DW_AT_stmt_list";
+ case DW_AT_low_pc:
+ return "DW_AT_low_pc";
+ case DW_AT_high_pc:
+ return "DW_AT_high_pc";
+ case DW_AT_language:
+ return "DW_AT_language";
+ case DW_AT_member:
+ return "DW_AT_member";
+ case DW_AT_discr:
+ return "DW_AT_discr";
+ case DW_AT_discr_value:
+ return "DW_AT_discr_value";
+ case DW_AT_visibility:
+ return "DW_AT_visibility";
+ case DW_AT_import:
+ return "DW_AT_import";
+ case DW_AT_string_length:
+ return "DW_AT_string_length";
+ case DW_AT_common_reference:
+ return "DW_AT_common_reference";
+ case DW_AT_comp_dir:
+ return "DW_AT_comp_dir";
+ case DW_AT_const_value:
+ return "DW_AT_const_value";
+ case DW_AT_containing_type:
+ return "DW_AT_containing_type";
+ case DW_AT_default_value:
+ return "DW_AT_default_value";
+ case DW_AT_inline:
+ return "DW_AT_inline";
+ case DW_AT_is_optional:
+ return "DW_AT_is_optional";
+ case DW_AT_lower_bound:
+ return "DW_AT_lower_bound";
+ case DW_AT_producer:
+ return "DW_AT_producer";
+ case DW_AT_prototyped:
+ return "DW_AT_prototyped";
+ case DW_AT_return_addr:
+ return "DW_AT_return_addr";
+ case DW_AT_start_scope:
+ return "DW_AT_start_scope";
+ case DW_AT_stride_size:
+ return "DW_AT_stride_size";
+ case DW_AT_upper_bound:
+ return "DW_AT_upper_bound";
+ case DW_AT_abstract_origin:
+ return "DW_AT_abstract_origin";
+ case DW_AT_accessibility:
+ return "DW_AT_accessibility";
+ case DW_AT_address_class:
+ return "DW_AT_address_class";
+ case DW_AT_artificial:
+ return "DW_AT_artificial";
+ case DW_AT_base_types:
+ return "DW_AT_base_types";
+ case DW_AT_calling_convention:
+ return "DW_AT_calling_convention";
+ case DW_AT_count:
+ return "DW_AT_count";
+ case DW_AT_data_member_location:
+ return "DW_AT_data_member_location";
+ case DW_AT_decl_column:
+ return "DW_AT_decl_column";
+ case DW_AT_decl_file:
+ return "DW_AT_decl_file";
+ case DW_AT_decl_line:
+ return "DW_AT_decl_line";
+ case DW_AT_declaration:
+ return "DW_AT_declaration";
+ case DW_AT_discr_list:
+ return "DW_AT_discr_list";
+ case DW_AT_encoding:
+ return "DW_AT_encoding";
+ case DW_AT_external:
+ return "DW_AT_external";
+ case DW_AT_frame_base:
+ return "DW_AT_frame_base";
+ case DW_AT_friend:
+ return "DW_AT_friend";
+ case DW_AT_identifier_case:
+ return "DW_AT_identifier_case";
+ case DW_AT_macro_info:
+ return "DW_AT_macro_info";
+ case DW_AT_namelist_items:
+ return "DW_AT_namelist_items";
+ case DW_AT_priority:
+ return "DW_AT_priority";
+ case DW_AT_segment:
+ return "DW_AT_segment";
+ case DW_AT_specification:
+ return "DW_AT_specification";
+ case DW_AT_static_link:
+ return "DW_AT_static_link";
+ case DW_AT_type:
+ return "DW_AT_type";
+ case DW_AT_use_location:
+ return "DW_AT_use_location";
+ case DW_AT_variable_parameter:
+ return "DW_AT_variable_parameter";
+ case DW_AT_virtuality:
+ return "DW_AT_virtuality";
+ case DW_AT_vtable_elem_location:
+ return "DW_AT_vtable_elem_location";
+
+ case DW_AT_MIPS_fde:
+ return "DW_AT_MIPS_fde";
+ case DW_AT_MIPS_loop_begin:
+ return "DW_AT_MIPS_loop_begin";
+ case DW_AT_MIPS_tail_loop_begin:
+ return "DW_AT_MIPS_tail_loop_begin";
+ case DW_AT_MIPS_epilog_begin:
+ return "DW_AT_MIPS_epilog_begin";
+ case DW_AT_MIPS_loop_unroll_factor:
+ return "DW_AT_MIPS_loop_unroll_factor";
+ case DW_AT_MIPS_software_pipeline_depth:
+ return "DW_AT_MIPS_software_pipeline_depth";
+ case DW_AT_MIPS_linkage_name:
+ return "DW_AT_MIPS_linkage_name";
+ case DW_AT_MIPS_stride:
+ return "DW_AT_MIPS_stride";
+ case DW_AT_MIPS_abstract_name:
+ return "DW_AT_MIPS_abstract_name";
+ case DW_AT_MIPS_clone_origin:
+ return "DW_AT_MIPS_clone_origin";
+ case DW_AT_MIPS_has_inlines:
+ return "DW_AT_MIPS_has_inlines";
+
+ case DW_AT_sf_names:
+ return "DW_AT_sf_names";
+ case DW_AT_src_info:
+ return "DW_AT_src_info";
+ case DW_AT_mac_info:
+ return "DW_AT_mac_info";
+ case DW_AT_src_coords:
+ return "DW_AT_src_coords";
+ case DW_AT_body_begin:
+ return "DW_AT_body_begin";
+ case DW_AT_body_end:
+ return "DW_AT_body_end";
+ default:
+ return "DW_AT_<unknown>";
+ }
+}
+
+/* Convert a DWARF value form code into its string name. */
+
+static char *
+dwarf_form_name (form)
+ register unsigned form;
+{
+ switch (form)
+ {
+ case DW_FORM_addr:
+ return "DW_FORM_addr";
+ case DW_FORM_block2:
+ return "DW_FORM_block2";
+ case DW_FORM_block4:
+ return "DW_FORM_block4";
+ case DW_FORM_data2:
+ return "DW_FORM_data2";
+ case DW_FORM_data4:
+ return "DW_FORM_data4";
+ case DW_FORM_data8:
+ return "DW_FORM_data8";
+ case DW_FORM_string:
+ return "DW_FORM_string";
+ case DW_FORM_block:
+ return "DW_FORM_block";
+ case DW_FORM_block1:
+ return "DW_FORM_block1";
+ case DW_FORM_data1:
+ return "DW_FORM_data1";
+ case DW_FORM_flag:
+ return "DW_FORM_flag";
+ case DW_FORM_sdata:
+ return "DW_FORM_sdata";
+ case DW_FORM_strp:
+ return "DW_FORM_strp";
+ case DW_FORM_udata:
+ return "DW_FORM_udata";
+ case DW_FORM_ref_addr:
+ return "DW_FORM_ref_addr";
+ case DW_FORM_ref1:
+ return "DW_FORM_ref1";
+ case DW_FORM_ref2:
+ return "DW_FORM_ref2";
+ case DW_FORM_ref4:
+ return "DW_FORM_ref4";
+ case DW_FORM_ref8:
+ return "DW_FORM_ref8";
+ case DW_FORM_ref_udata:
+ return "DW_FORM_ref_udata";
+ case DW_FORM_indirect:
+ return "DW_FORM_indirect";
+ default:
+ return "DW_FORM_<unknown>";
+ }
+}
+
+/* Convert a DWARF stack opcode into its string name. */
+
+static char *
+dwarf_stack_op_name (op)
+ register unsigned op;
+{
+ switch (op)
+ {
+ case DW_OP_addr:
+ return "DW_OP_addr";
+ case DW_OP_deref:
+ return "DW_OP_deref";
+ case DW_OP_const1u:
+ return "DW_OP_const1u";
+ case DW_OP_const1s:
+ return "DW_OP_const1s";
+ case DW_OP_const2u:
+ return "DW_OP_const2u";
+ case DW_OP_const2s:
+ return "DW_OP_const2s";
+ case DW_OP_const4u:
+ return "DW_OP_const4u";
+ case DW_OP_const4s:
+ return "DW_OP_const4s";
+ case DW_OP_const8u:
+ return "DW_OP_const8u";
+ case DW_OP_const8s:
+ return "DW_OP_const8s";
+ case DW_OP_constu:
+ return "DW_OP_constu";
+ case DW_OP_consts:
+ return "DW_OP_consts";
+ case DW_OP_dup:
+ return "DW_OP_dup";
+ case DW_OP_drop:
+ return "DW_OP_drop";
+ case DW_OP_over:
+ return "DW_OP_over";
+ case DW_OP_pick:
+ return "DW_OP_pick";
+ case DW_OP_swap:
+ return "DW_OP_swap";
+ case DW_OP_rot:
+ return "DW_OP_rot";
+ case DW_OP_xderef:
+ return "DW_OP_xderef";
+ case DW_OP_abs:
+ return "DW_OP_abs";
+ case DW_OP_and:
+ return "DW_OP_and";
+ case DW_OP_div:
+ return "DW_OP_div";
+ case DW_OP_minus:
+ return "DW_OP_minus";
+ case DW_OP_mod:
+ return "DW_OP_mod";
+ case DW_OP_mul:
+ return "DW_OP_mul";
+ case DW_OP_neg:
+ return "DW_OP_neg";
+ case DW_OP_not:
+ return "DW_OP_not";
+ case DW_OP_or:
+ return "DW_OP_or";
+ case DW_OP_plus:
+ return "DW_OP_plus";
+ case DW_OP_plus_uconst:
+ return "DW_OP_plus_uconst";
+ case DW_OP_shl:
+ return "DW_OP_shl";
+ case DW_OP_shr:
+ return "DW_OP_shr";
+ case DW_OP_shra:
+ return "DW_OP_shra";
+ case DW_OP_xor:
+ return "DW_OP_xor";
+ case DW_OP_bra:
+ return "DW_OP_bra";
+ case DW_OP_eq:
+ return "DW_OP_eq";
+ case DW_OP_ge:
+ return "DW_OP_ge";
+ case DW_OP_gt:
+ return "DW_OP_gt";
+ case DW_OP_le:
+ return "DW_OP_le";
+ case DW_OP_lt:
+ return "DW_OP_lt";
+ case DW_OP_ne:
+ return "DW_OP_ne";
+ case DW_OP_skip:
+ return "DW_OP_skip";
+ case DW_OP_lit0:
+ return "DW_OP_lit0";
+ case DW_OP_lit1:
+ return "DW_OP_lit1";
+ case DW_OP_lit2:
+ return "DW_OP_lit2";
+ case DW_OP_lit3:
+ return "DW_OP_lit3";
+ case DW_OP_lit4:
+ return "DW_OP_lit4";
+ case DW_OP_lit5:
+ return "DW_OP_lit5";
+ case DW_OP_lit6:
+ return "DW_OP_lit6";
+ case DW_OP_lit7:
+ return "DW_OP_lit7";
+ case DW_OP_lit8:
+ return "DW_OP_lit8";
+ case DW_OP_lit9:
+ return "DW_OP_lit9";
+ case DW_OP_lit10:
+ return "DW_OP_lit10";
+ case DW_OP_lit11:
+ return "DW_OP_lit11";
+ case DW_OP_lit12:
+ return "DW_OP_lit12";
+ case DW_OP_lit13:
+ return "DW_OP_lit13";
+ case DW_OP_lit14:
+ return "DW_OP_lit14";
+ case DW_OP_lit15:
+ return "DW_OP_lit15";
+ case DW_OP_lit16:
+ return "DW_OP_lit16";
+ case DW_OP_lit17:
+ return "DW_OP_lit17";
+ case DW_OP_lit18:
+ return "DW_OP_lit18";
+ case DW_OP_lit19:
+ return "DW_OP_lit19";
+ case DW_OP_lit20:
+ return "DW_OP_lit20";
+ case DW_OP_lit21:
+ return "DW_OP_lit21";
+ case DW_OP_lit22:
+ return "DW_OP_lit22";
+ case DW_OP_lit23:
+ return "DW_OP_lit23";
+ case DW_OP_lit24:
+ return "DW_OP_lit24";
+ case DW_OP_lit25:
+ return "DW_OP_lit25";
+ case DW_OP_lit26:
+ return "DW_OP_lit26";
+ case DW_OP_lit27:
+ return "DW_OP_lit27";
+ case DW_OP_lit28:
+ return "DW_OP_lit28";
+ case DW_OP_lit29:
+ return "DW_OP_lit29";
+ case DW_OP_lit30:
+ return "DW_OP_lit30";
+ case DW_OP_lit31:
+ return "DW_OP_lit31";
+ case DW_OP_reg0:
+ return "DW_OP_reg0";
+ case DW_OP_reg1:
+ return "DW_OP_reg1";
+ case DW_OP_reg2:
+ return "DW_OP_reg2";
+ case DW_OP_reg3:
+ return "DW_OP_reg3";
+ case DW_OP_reg4:
+ return "DW_OP_reg4";
+ case DW_OP_reg5:
+ return "DW_OP_reg5";
+ case DW_OP_reg6:
+ return "DW_OP_reg6";
+ case DW_OP_reg7:
+ return "DW_OP_reg7";
+ case DW_OP_reg8:
+ return "DW_OP_reg8";
+ case DW_OP_reg9:
+ return "DW_OP_reg9";
+ case DW_OP_reg10:
+ return "DW_OP_reg10";
+ case DW_OP_reg11:
+ return "DW_OP_reg11";
+ case DW_OP_reg12:
+ return "DW_OP_reg12";
+ case DW_OP_reg13:
+ return "DW_OP_reg13";
+ case DW_OP_reg14:
+ return "DW_OP_reg14";
+ case DW_OP_reg15:
+ return "DW_OP_reg15";
+ case DW_OP_reg16:
+ return "DW_OP_reg16";
+ case DW_OP_reg17:
+ return "DW_OP_reg17";
+ case DW_OP_reg18:
+ return "DW_OP_reg18";
+ case DW_OP_reg19:
+ return "DW_OP_reg19";
+ case DW_OP_reg20:
+ return "DW_OP_reg20";
+ case DW_OP_reg21:
+ return "DW_OP_reg21";
+ case DW_OP_reg22:
+ return "DW_OP_reg22";
+ case DW_OP_reg23:
+ return "DW_OP_reg23";
+ case DW_OP_reg24:
+ return "DW_OP_reg24";
+ case DW_OP_reg25:
+ return "DW_OP_reg25";
+ case DW_OP_reg26:
+ return "DW_OP_reg26";
+ case DW_OP_reg27:
+ return "DW_OP_reg27";
+ case DW_OP_reg28:
+ return "DW_OP_reg28";
+ case DW_OP_reg29:
+ return "DW_OP_reg29";
+ case DW_OP_reg30:
+ return "DW_OP_reg30";
+ case DW_OP_reg31:
+ return "DW_OP_reg31";
+ case DW_OP_breg0:
+ return "DW_OP_breg0";
+ case DW_OP_breg1:
+ return "DW_OP_breg1";
+ case DW_OP_breg2:
+ return "DW_OP_breg2";
+ case DW_OP_breg3:
+ return "DW_OP_breg3";
+ case DW_OP_breg4:
+ return "DW_OP_breg4";
+ case DW_OP_breg5:
+ return "DW_OP_breg5";
+ case DW_OP_breg6:
+ return "DW_OP_breg6";
+ case DW_OP_breg7:
+ return "DW_OP_breg7";
+ case DW_OP_breg8:
+ return "DW_OP_breg8";
+ case DW_OP_breg9:
+ return "DW_OP_breg9";
+ case DW_OP_breg10:
+ return "DW_OP_breg10";
+ case DW_OP_breg11:
+ return "DW_OP_breg11";
+ case DW_OP_breg12:
+ return "DW_OP_breg12";
+ case DW_OP_breg13:
+ return "DW_OP_breg13";
+ case DW_OP_breg14:
+ return "DW_OP_breg14";
+ case DW_OP_breg15:
+ return "DW_OP_breg15";
+ case DW_OP_breg16:
+ return "DW_OP_breg16";
+ case DW_OP_breg17:
+ return "DW_OP_breg17";
+ case DW_OP_breg18:
+ return "DW_OP_breg18";
+ case DW_OP_breg19:
+ return "DW_OP_breg19";
+ case DW_OP_breg20:
+ return "DW_OP_breg20";
+ case DW_OP_breg21:
+ return "DW_OP_breg21";
+ case DW_OP_breg22:
+ return "DW_OP_breg22";
+ case DW_OP_breg23:
+ return "DW_OP_breg23";
+ case DW_OP_breg24:
+ return "DW_OP_breg24";
+ case DW_OP_breg25:
+ return "DW_OP_breg25";
+ case DW_OP_breg26:
+ return "DW_OP_breg26";
+ case DW_OP_breg27:
+ return "DW_OP_breg27";
+ case DW_OP_breg28:
+ return "DW_OP_breg28";
+ case DW_OP_breg29:
+ return "DW_OP_breg29";
+ case DW_OP_breg30:
+ return "DW_OP_breg30";
+ case DW_OP_breg31:
+ return "DW_OP_breg31";
+ case DW_OP_regx:
+ return "DW_OP_regx";
+ case DW_OP_fbreg:
+ return "DW_OP_fbreg";
+ case DW_OP_bregx:
+ return "DW_OP_bregx";
+ case DW_OP_piece:
+ return "DW_OP_piece";
+ case DW_OP_deref_size:
+ return "DW_OP_deref_size";
+ case DW_OP_xderef_size:
+ return "DW_OP_xderef_size";
+ case DW_OP_nop:
+ return "DW_OP_nop";
+ default:
+ return "OP_<unknown>";
+ }
+}
+
+/* Convert a DWARF type code into its string name. */
+
+#if 0
+static char *
+dwarf_type_encoding_name (enc)
+ register unsigned enc;
+{
+ switch (enc)
+ {
+ case DW_ATE_address:
+ return "DW_ATE_address";
+ case DW_ATE_boolean:
+ return "DW_ATE_boolean";
+ case DW_ATE_complex_float:
+ return "DW_ATE_complex_float";
+ case DW_ATE_float:
+ return "DW_ATE_float";
+ case DW_ATE_signed:
+ return "DW_ATE_signed";
+ case DW_ATE_signed_char:
+ return "DW_ATE_signed_char";
+ case DW_ATE_unsigned:
+ return "DW_ATE_unsigned";
+ case DW_ATE_unsigned_char:
+ return "DW_ATE_unsigned_char";
+ default:
+ return "DW_ATE_<unknown>";
+ }
+}
+#endif
+
+/* Determine the "ultimate origin" of a decl. The decl may be an inlined
+ instance of an inlined instance of a decl which is local to an inline
+ function, so we have to trace all of the way back through the origin chain
+ to find out what sort of node actually served as the original seed for the
+ given block. */
+
+static tree
+decl_ultimate_origin (decl)
+ register tree decl;
+{
+ register tree immediate_origin = DECL_ABSTRACT_ORIGIN (decl);
+
+ if (immediate_origin == NULL_TREE)
+ return NULL_TREE;
+ else
+ {
+ register tree ret_val;
+ register tree lookahead = immediate_origin;
+
+ do
+ {
+ ret_val = lookahead;
+ lookahead = DECL_ABSTRACT_ORIGIN (ret_val);
+ }
+ while (lookahead != NULL && lookahead != ret_val);
+
+ return ret_val;
+ }
+}
+
+/* Determine the "ultimate origin" of a block. The block may be an inlined
+ instance of an inlined instance of a block which is local to an inline
+ function, so we have to trace all of the way back through the origin chain
+ to find out what sort of node actually served as the original seed for the
+ given block. */
+
+static tree
+block_ultimate_origin (block)
+ register tree block;
+{
+ register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
+
+ if (immediate_origin == NULL_TREE)
+ return NULL_TREE;
+ else
+ {
+ register tree ret_val;
+ register tree lookahead = immediate_origin;
+
+ do
+ {
+ ret_val = lookahead;
+ lookahead = (TREE_CODE (ret_val) == BLOCK)
+ ? BLOCK_ABSTRACT_ORIGIN (ret_val)
+ : NULL;
+ }
+ while (lookahead != NULL && lookahead != ret_val);
+
+ return ret_val;
+ }
+}
+
+/* Get the class to which DECL belongs, if any. In g++, the DECL_CONTEXT
+ of a virtual function may refer to a base class, so we check the 'this'
+ parameter. */
+
+static tree
+decl_class_context (decl)
+ tree decl;
+{
+ tree context = NULL_TREE;
+
+ if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl))
+ context = DECL_CONTEXT (decl);
+ else
+ context = TYPE_MAIN_VARIANT
+ (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
+
+ if (context && TREE_CODE_CLASS (TREE_CODE (context)) != 't')
+ context = NULL_TREE;
+
+ return context;
+}
+
+/* Add an attribute/value pair to a DIE */
+
+static inline void
+add_dwarf_attr (die, attr)
+ register dw_die_ref die;
+ register dw_attr_ref attr;
+{
+ if (die != NULL && attr != NULL)
+ {
+ if (die->die_attr == NULL)
+ {
+ die->die_attr = attr;
+ die->die_attr_last = attr;
+ }
+ else
+ {
+ die->die_attr_last->dw_attr_next = attr;
+ die->die_attr_last = attr;
+ }
+ }
+}
+
+/* Add a flag value attribute to a DIE. */
+
+static inline void
+add_AT_flag (die, attr_kind, flag)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register unsigned flag;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_flag;
+ attr->dw_attr_val.v.val_flag = flag;
+ add_dwarf_attr (die, attr);
+}
+
+/* Add a signed integer attribute value to a DIE. */
+
+static inline void
+add_AT_int (die, attr_kind, int_val)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register long int int_val;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_const;
+ attr->dw_attr_val.v.val_int = int_val;
+ add_dwarf_attr (die, attr);
+}
+
+/* Add an unsigned integer attribute value to a DIE. */
+
+static inline void
+add_AT_unsigned (die, attr_kind, unsigned_val)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register unsigned long unsigned_val;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_unsigned_const;
+ attr->dw_attr_val.v.val_unsigned = unsigned_val;
+ add_dwarf_attr (die, attr);
+}
+
+/* Add an unsigned double integer attribute value to a DIE. */
+
+static inline void
+add_AT_long_long (die, attr_kind, val_hi, val_low)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register unsigned long val_hi;
+ register unsigned long val_low;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_long_long;
+ attr->dw_attr_val.v.val_long_long.hi = val_hi;
+ attr->dw_attr_val.v.val_long_long.low = val_low;
+ add_dwarf_attr (die, attr);
+}
+
+/* Add a floating point attribute value to a DIE and return it. */
+
+static inline void
+add_AT_float (die, attr_kind, length, array)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register unsigned length;
+ register long *array;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_float;
+ attr->dw_attr_val.v.val_float.length = length;
+ attr->dw_attr_val.v.val_float.array = array;
+ add_dwarf_attr (die, attr);
+}
+
+/* Add a string attribute value to a DIE. */
+
+static inline void
+add_AT_string (die, attr_kind, str)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register char *str;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_str;
+ attr->dw_attr_val.v.val_str = xstrdup (str);
+ add_dwarf_attr (die, attr);
+}
+
+/* Add a DIE reference attribute value to a DIE. */
+
+static inline void
+add_AT_die_ref (die, attr_kind, targ_die)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register dw_die_ref targ_die;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_die_ref;
+ attr->dw_attr_val.v.val_die_ref = targ_die;
+ add_dwarf_attr (die, attr);
+}
+
+/* Add an FDE reference attribute value to a DIE. */
+
+static inline void
+add_AT_fde_ref (die, attr_kind, targ_fde)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register unsigned targ_fde;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_fde_ref;
+ attr->dw_attr_val.v.val_fde_index = targ_fde;
+ add_dwarf_attr (die, attr);
+}
+
+/* Add a location description attribute value to a DIE. */
+
+static inline void
+add_AT_loc (die, attr_kind, loc)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register dw_loc_descr_ref loc;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_loc;
+ attr->dw_attr_val.v.val_loc = loc;
+ add_dwarf_attr (die, attr);
+}
+
+/* Add an address constant attribute value to a DIE. */
+
+static inline void
+add_AT_addr (die, attr_kind, addr)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ char *addr;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_addr;
+ attr->dw_attr_val.v.val_addr = addr;
+ add_dwarf_attr (die, attr);
+}
+
+/* Add a label identifier attribute value to a DIE. */
+
+static inline void
+add_AT_lbl_id (die, attr_kind, lbl_id)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register char *lbl_id;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_lbl_id;
+ attr->dw_attr_val.v.val_lbl_id = xstrdup (lbl_id);
+ add_dwarf_attr (die, attr);
+}
+
+/* Add a section offset attribute value to a DIE. */
+
+static inline void
+add_AT_section_offset (die, attr_kind, section)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+ register char *section;
+{
+ register dw_attr_ref attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = attr_kind;
+ attr->dw_attr_val.val_class = dw_val_class_section_offset;
+ attr->dw_attr_val.v.val_section = section;
+ add_dwarf_attr (die, attr);
+
+}
+
+/* Test if die refers to an external subroutine. */
+
+static inline int
+is_extern_subr_die (die)
+ register dw_die_ref die;
+{
+ register dw_attr_ref a;
+ register int is_subr = FALSE;
+ register int is_extern = FALSE;
+
+ if (die != NULL && die->die_tag == DW_TAG_subprogram)
+ {
+ is_subr = TRUE;
+ for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ {
+ if (a->dw_attr == DW_AT_external
+ && a->dw_attr_val.val_class == dw_val_class_flag
+ && a->dw_attr_val.v.val_flag != 0)
+ {
+ is_extern = TRUE;
+ break;
+ }
+ }
+ }
+
+ return is_subr && is_extern;
+}
+
+/* Get the attribute of type attr_kind. */
+
+static inline dw_attr_ref
+get_AT (die, attr_kind)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+{
+ register dw_attr_ref a;
+ register dw_die_ref spec = NULL;
+
+ if (die != NULL)
+ {
+ for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ {
+ if (a->dw_attr == attr_kind)
+ return a;
+
+ if (a->dw_attr == DW_AT_specification
+ || a->dw_attr == DW_AT_abstract_origin)
+ spec = a->dw_attr_val.v.val_die_ref;
+ }
+
+ if (spec)
+ return get_AT (spec, attr_kind);
+ }
+
+ return NULL;
+}
+
+/* Return the "low pc" attribute value, typically associated with
+ a subprogram DIE. Return null if the "low pc" attribute is
+ either not prsent, or if it cannot be represented as an
+ assembler label identifier. */
+
+static inline char *
+get_AT_low_pc (die)
+ register dw_die_ref die;
+{
+ register dw_attr_ref a = get_AT (die, DW_AT_low_pc);
+
+ if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id)
+ return a->dw_attr_val.v.val_lbl_id;
+
+ return NULL;
+}
+
+/* Return the "high pc" attribute value, typically associated with
+ a subprogram DIE. Return null if the "high pc" attribute is
+ either not prsent, or if it cannot be represented as an
+ assembler label identifier. */
+
+static inline char *
+get_AT_hi_pc (die)
+ register dw_die_ref die;
+{
+ register dw_attr_ref a = get_AT (die, DW_AT_high_pc);
+
+ if (a && a->dw_attr_val.val_class == dw_val_class_lbl_id)
+ return a->dw_attr_val.v.val_lbl_id;
+
+ return NULL;
+}
+
+/* Return the value of the string attribute designated by ATTR_KIND, or
+ NULL if it is not present. */
+
+static inline char *
+get_AT_string (die, attr_kind)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+{
+ register dw_attr_ref a = get_AT (die, attr_kind);
+
+ if (a && a->dw_attr_val.val_class == dw_val_class_str)
+ return a->dw_attr_val.v.val_str;
+
+ return NULL;
+}
+
+/* Return the value of the flag attribute designated by ATTR_KIND, or -1
+ if it is not present. */
+
+static inline int
+get_AT_flag (die, attr_kind)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+{
+ register dw_attr_ref a = get_AT (die, attr_kind);
+
+ if (a && a->dw_attr_val.val_class == dw_val_class_flag)
+ return a->dw_attr_val.v.val_flag;
+
+ return -1;
+}
+
+/* Return the value of the unsigned attribute designated by ATTR_KIND, or 0
+ if it is not present. */
+
+static inline unsigned
+get_AT_unsigned (die, attr_kind)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+{
+ register dw_attr_ref a = get_AT (die, attr_kind);
+
+ if (a && a->dw_attr_val.val_class == dw_val_class_unsigned_const)
+ return a->dw_attr_val.v.val_unsigned;
+
+ return 0;
+}
+
+static inline int
+is_c_family ()
+{
+ register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ return (lang == DW_LANG_C || lang == DW_LANG_C89
+ || lang == DW_LANG_C_plus_plus);
+}
+
+static inline int
+is_fortran ()
+{
+ register unsigned lang = get_AT_unsigned (comp_unit_die, DW_AT_language);
+
+ return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90);
+}
+
+/* Remove the specified attribute if present. */
+
+static inline void
+remove_AT (die, attr_kind)
+ register dw_die_ref die;
+ register enum dwarf_attribute attr_kind;
+{
+ register dw_attr_ref a;
+ register dw_attr_ref removed = NULL;;
+
+ if (die != NULL)
+ {
+ if (die->die_attr->dw_attr == attr_kind)
+ {
+ removed = die->die_attr;
+ if (die->die_attr_last == die->die_attr)
+ die->die_attr_last = NULL;
+
+ die->die_attr = die->die_attr->dw_attr_next;
+ }
+
+ else
+ for (a = die->die_attr; a->dw_attr_next != NULL;
+ a = a->dw_attr_next)
+ if (a->dw_attr_next->dw_attr == attr_kind)
+ {
+ removed = a->dw_attr_next;
+ if (die->die_attr_last == a->dw_attr_next)
+ die->die_attr_last = a;
+
+ a->dw_attr_next = a->dw_attr_next->dw_attr_next;
+ break;
+ }
+
+ if (removed != 0)
+ free (removed);
+ }
+}
+
+/* Discard the children of this DIE. */
+
+static inline void
+remove_children (die)
+ register dw_die_ref die;
+{
+ register dw_die_ref child_die = die->die_child;
+
+ die->die_child = NULL;
+ die->die_child_last = NULL;
+
+ while (child_die != NULL)
+ {
+ register dw_die_ref tmp_die = child_die;
+ register dw_attr_ref a;
+
+ child_die = child_die->die_sib;
+
+ for (a = tmp_die->die_attr; a != NULL; )
+ {
+ register dw_attr_ref tmp_a = a;
+
+ a = a->dw_attr_next;
+ free (tmp_a);
+ }
+
+ free (tmp_die);
+ }
+}
+
+/* Add a child DIE below its parent. */
+
+static inline void
+add_child_die (die, child_die)
+ register dw_die_ref die;
+ register dw_die_ref child_die;
+{
+ if (die != NULL && child_die != NULL)
+ {
+ if (die == child_die)
+ abort ();
+ child_die->die_parent = die;
+ child_die->die_sib = NULL;
+
+ if (die->die_child == NULL)
+ {
+ die->die_child = child_die;
+ die->die_child_last = child_die;
+ }
+ else
+ {
+ die->die_child_last->die_sib = child_die;
+ die->die_child_last = child_die;
+ }
+ }
+}
+
+/* Return a pointer to a newly created DIE node. */
+
+static inline dw_die_ref
+new_die (tag_value, parent_die)
+ register enum dwarf_tag tag_value;
+ register dw_die_ref parent_die;
+{
+ register dw_die_ref die = (dw_die_ref) xmalloc (sizeof (die_node));
+
+ die->die_tag = tag_value;
+ die->die_abbrev = 0;
+ die->die_offset = 0;
+ die->die_child = NULL;
+ die->die_parent = NULL;
+ die->die_sib = NULL;
+ die->die_child_last = NULL;
+ die->die_attr = NULL;
+ die->die_attr_last = NULL;
+
+ if (parent_die != NULL)
+ add_child_die (parent_die, die);
+ else
+ {
+ limbo_die_node *limbo_node;
+
+ limbo_node = (limbo_die_node *) xmalloc (sizeof (limbo_die_node));
+ limbo_node->die = die;
+ limbo_node->next = limbo_die_list;
+ limbo_die_list = limbo_node;
+ }
+
+ return die;
+}
+
+/* Return the DIE associated with the given type specifier. */
+
+static inline dw_die_ref
+lookup_type_die (type)
+ register tree type;
+{
+ return (dw_die_ref) TYPE_SYMTAB_POINTER (type);
+}
+
+/* Equate a DIE to a given type specifier. */
+
+static void
+equate_type_number_to_die (type, type_die)
+ register tree type;
+ register dw_die_ref type_die;
+{
+ TYPE_SYMTAB_POINTER (type) = (char *) type_die;
+}
+
+/* Return the DIE associated with a given declaration. */
+
+static inline dw_die_ref
+lookup_decl_die (decl)
+ register tree decl;
+{
+ register unsigned decl_id = DECL_UID (decl);
+
+ return (decl_id < decl_die_table_in_use
+ ? decl_die_table[decl_id] : NULL);
+}
+
+/* Equate a DIE to a particular declaration. */
+
+static void
+equate_decl_number_to_die (decl, decl_die)
+ register tree decl;
+ register dw_die_ref decl_die;
+{
+ register unsigned decl_id = DECL_UID (decl);
+ register unsigned num_allocated;
+
+ if (decl_id >= decl_die_table_allocated)
+ {
+ num_allocated
+ = ((decl_id + 1 + DECL_DIE_TABLE_INCREMENT - 1)
+ / DECL_DIE_TABLE_INCREMENT)
+ * DECL_DIE_TABLE_INCREMENT;
+
+ decl_die_table
+ = (dw_die_ref *) xrealloc (decl_die_table,
+ sizeof (dw_die_ref) * num_allocated);
+
+ bzero ((char *) &decl_die_table[decl_die_table_allocated],
+ (num_allocated - decl_die_table_allocated) * sizeof (dw_die_ref));
+ decl_die_table_allocated = num_allocated;
+ }
+
+ if (decl_id >= decl_die_table_in_use)
+ decl_die_table_in_use = (decl_id + 1);
+
+ decl_die_table[decl_id] = decl_die;
+}
+
+/* Return a pointer to a newly allocated location description. Location
+ descriptions are simple expression terms that can be strung
+ together to form more complicated location (address) descriptions. */
+
+static inline dw_loc_descr_ref
+new_loc_descr (op, oprnd1, oprnd2)
+ register enum dwarf_location_atom op;
+ register unsigned long oprnd1;
+ register unsigned long oprnd2;
+{
+ register dw_loc_descr_ref descr
+ = (dw_loc_descr_ref) xmalloc (sizeof (dw_loc_descr_node));
+
+ descr->dw_loc_next = NULL;
+ descr->dw_loc_opc = op;
+ descr->dw_loc_oprnd1.val_class = dw_val_class_unsigned_const;
+ descr->dw_loc_oprnd1.v.val_unsigned = oprnd1;
+ descr->dw_loc_oprnd2.val_class = dw_val_class_unsigned_const;
+ descr->dw_loc_oprnd2.v.val_unsigned = oprnd2;
+
+ return descr;
+}
+
+/* Add a location description term to a location description expression. */
+
+static inline void
+add_loc_descr (list_head, descr)
+ register dw_loc_descr_ref *list_head;
+ register dw_loc_descr_ref descr;
+{
+ register dw_loc_descr_ref *d;
+
+ /* Find the end of the chain. */
+ for (d = list_head; (*d) != NULL; d = &(*d)->dw_loc_next)
+ ;
+
+ *d = descr;
+}
+
+/* Keep track of the number of spaces used to indent the
+ output of the debugging routines that print the structure of
+ the DIE internal representation. */
+static int print_indent;
+
+/* Indent the line the number of spaces given by print_indent. */
+
+static inline void
+print_spaces (outfile)
+ FILE *outfile;
+{
+ fprintf (outfile, "%*s", print_indent, "");
+}
+
+/* Print the information associated with a given DIE, and its children.
+ This routine is a debugging aid only. */
+
+static void
+print_die (die, outfile)
+ dw_die_ref die;
+ FILE *outfile;
+{
+ register dw_attr_ref a;
+ register dw_die_ref c;
+
+ print_spaces (outfile);
+ fprintf (outfile, "DIE %4lu: %s\n",
+ die->die_offset, dwarf_tag_name (die->die_tag));
+ print_spaces (outfile);
+ fprintf (outfile, " abbrev id: %lu", die->die_abbrev);
+ fprintf (outfile, " offset: %lu\n", die->die_offset);
+
+ for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ {
+ print_spaces (outfile);
+ fprintf (outfile, " %s: ", dwarf_attr_name (a->dw_attr));
+
+ switch (a->dw_attr_val.val_class)
+ {
+ case dw_val_class_addr:
+ fprintf (outfile, "address");
+ break;
+ case dw_val_class_loc:
+ fprintf (outfile, "location descriptor");
+ break;
+ case dw_val_class_const:
+ fprintf (outfile, "%ld", a->dw_attr_val.v.val_int);
+ break;
+ case dw_val_class_unsigned_const:
+ fprintf (outfile, "%lu", a->dw_attr_val.v.val_unsigned);
+ break;
+ case dw_val_class_long_long:
+ fprintf (outfile, "constant (%lu,%lu)",
+ a->dw_attr_val.v.val_long_long.hi,
+ a->dw_attr_val.v.val_long_long.low);
+ break;
+ case dw_val_class_float:
+ fprintf (outfile, "floating-point constant");
+ break;
+ case dw_val_class_flag:
+ fprintf (outfile, "%u", a->dw_attr_val.v.val_flag);
+ break;
+ case dw_val_class_die_ref:
+ if (a->dw_attr_val.v.val_die_ref != NULL)
+ fprintf (outfile, "die -> %lu",
+ a->dw_attr_val.v.val_die_ref->die_offset);
+ else
+ fprintf (outfile, "die -> <null>");
+ break;
+ case dw_val_class_lbl_id:
+ fprintf (outfile, "label: %s", a->dw_attr_val.v.val_lbl_id);
+ break;
+ case dw_val_class_section_offset:
+ fprintf (outfile, "section: %s", a->dw_attr_val.v.val_section);
+ break;
+ case dw_val_class_str:
+ if (a->dw_attr_val.v.val_str != NULL)
+ fprintf (outfile, "\"%s\"", a->dw_attr_val.v.val_str);
+ else
+ fprintf (outfile, "<null>");
+ break;
+ default:
+ break;
+ }
+
+ fprintf (outfile, "\n");
+ }
+
+ if (die->die_child != NULL)
+ {
+ print_indent += 4;
+ for (c = die->die_child; c != NULL; c = c->die_sib)
+ print_die (c, outfile);
+
+ print_indent -= 4;
+ }
+}
+
+/* Print the contents of the source code line number correspondence table.
+ This routine is a debugging aid only. */
+
+static void
+print_dwarf_line_table (outfile)
+ FILE *outfile;
+{
+ register unsigned i;
+ register dw_line_info_ref line_info;
+
+ fprintf (outfile, "\n\nDWARF source line information\n");
+ for (i = 1; i < line_info_table_in_use; ++i)
+ {
+ line_info = &line_info_table[i];
+ fprintf (outfile, "%5d: ", i);
+ fprintf (outfile, "%-20s", file_table[line_info->dw_file_num]);
+ fprintf (outfile, "%6ld", line_info->dw_line_num);
+ fprintf (outfile, "\n");
+ }
+
+ fprintf (outfile, "\n\n");
+}
+
+/* Print the information collected for a given DIE. */
+
+void
+debug_dwarf_die (die)
+ dw_die_ref die;
+{
+ print_die (die, stderr);
+}
+
+/* Print all DWARF information collected for the compilation unit.
+ This routine is a debugging aid only. */
+
+void
+debug_dwarf ()
+{
+ print_indent = 0;
+ print_die (comp_unit_die, stderr);
+ print_dwarf_line_table (stderr);
+}
+
+/* Traverse the DIE, and add a sibling attribute if it may have the
+ effect of speeding up access to siblings. To save some space,
+ avoid generating sibling attributes for DIE's without children. */
+
+static void
+add_sibling_attributes(die)
+ register dw_die_ref die;
+{
+ register dw_die_ref c;
+ register dw_attr_ref attr;
+ if (die != comp_unit_die && die->die_child != NULL)
+ {
+ attr = (dw_attr_ref) xmalloc (sizeof (dw_attr_node));
+ attr->dw_attr_next = NULL;
+ attr->dw_attr = DW_AT_sibling;
+ attr->dw_attr_val.val_class = dw_val_class_die_ref;
+ attr->dw_attr_val.v.val_die_ref = die->die_sib;
+
+ /* Add the sibling link to the front of the attribute list. */
+ attr->dw_attr_next = die->die_attr;
+ if (die->die_attr == NULL)
+ die->die_attr_last = attr;
+
+ die->die_attr = attr;
+ }
+
+ for (c = die->die_child; c != NULL; c = c->die_sib)
+ add_sibling_attributes (c);
+}
+
+/* The format of each DIE (and its attribute value pairs)
+ is encoded in an abbreviation table. This routine builds the
+ abbreviation table and assigns a unique abbreviation id for
+ each abbreviation entry. The children of each die are visited
+ recursively. */
+
+static void
+build_abbrev_table (die)
+ register dw_die_ref die;
+{
+ register unsigned long abbrev_id;
+ register unsigned long n_alloc;
+ register dw_die_ref c;
+ register dw_attr_ref d_attr, a_attr;
+ for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+ {
+ register dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+
+ if (abbrev->die_tag == die->die_tag)
+ {
+ if ((abbrev->die_child != NULL) == (die->die_child != NULL))
+ {
+ a_attr = abbrev->die_attr;
+ d_attr = die->die_attr;
+
+ while (a_attr != NULL && d_attr != NULL)
+ {
+ if ((a_attr->dw_attr != d_attr->dw_attr)
+ || (value_format (&a_attr->dw_attr_val)
+ != value_format (&d_attr->dw_attr_val)))
+ break;
+
+ a_attr = a_attr->dw_attr_next;
+ d_attr = d_attr->dw_attr_next;
+ }
+
+ if (a_attr == NULL && d_attr == NULL)
+ break;
+ }
+ }
+ }
+
+ if (abbrev_id >= abbrev_die_table_in_use)
+ {
+ if (abbrev_die_table_in_use >= abbrev_die_table_allocated)
+ {
+ n_alloc = abbrev_die_table_allocated + ABBREV_DIE_TABLE_INCREMENT;
+ abbrev_die_table
+ = (dw_die_ref *) xrealloc (abbrev_die_table,
+ sizeof (dw_die_ref) * n_alloc);
+
+ bzero ((char *) &abbrev_die_table[abbrev_die_table_allocated],
+ (n_alloc - abbrev_die_table_allocated) * sizeof (dw_die_ref));
+ abbrev_die_table_allocated = n_alloc;
+ }
+
+ ++abbrev_die_table_in_use;
+ abbrev_die_table[abbrev_id] = die;
+ }
+
+ die->die_abbrev = abbrev_id;
+ for (c = die->die_child; c != NULL; c = c->die_sib)
+ build_abbrev_table (c);
+}
+
+/* Return the size of a string, including the null byte.
+
+ This used to treat backslashes as escapes, and hence they were not included
+ in the count. However, that conflicts with what ASM_OUTPUT_ASCII does,
+ which treats a backslash as a backslash, escaping it if necessary, and hence
+ we must include them in the count. */
+
+static unsigned long
+size_of_string (str)
+ register char *str;
+{
+ return strlen (str) + 1;
+}
+
+/* Return the size of a location descriptor. */
+
+static unsigned long
+size_of_loc_descr (loc)
+ register dw_loc_descr_ref loc;
+{
+ register unsigned long size = 1;
+
+ switch (loc->dw_loc_opc)
+ {
+ case DW_OP_addr:
+ size += PTR_SIZE;
+ break;
+ case DW_OP_const1u:
+ case DW_OP_const1s:
+ size += 1;
+ break;
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ size += 2;
+ break;
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ size += 4;
+ break;
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ size += 8;
+ break;
+ case DW_OP_constu:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ break;
+ case DW_OP_consts:
+ size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
+ break;
+ case DW_OP_pick:
+ size += 1;
+ break;
+ case DW_OP_plus_uconst:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ break;
+ case DW_OP_skip:
+ case DW_OP_bra:
+ size += 2;
+ break;
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
+ break;
+ case DW_OP_regx:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ break;
+ case DW_OP_fbreg:
+ size += size_of_sleb128 (loc->dw_loc_oprnd1.v.val_int);
+ break;
+ case DW_OP_bregx:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ size += size_of_sleb128 (loc->dw_loc_oprnd2.v.val_int);
+ break;
+ case DW_OP_piece:
+ size += size_of_uleb128 (loc->dw_loc_oprnd1.v.val_unsigned);
+ break;
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ size += 1;
+ break;
+ default:
+ break;
+ }
+
+ return size;
+}
+
+/* Return the size of a series of location descriptors. */
+
+static unsigned long
+size_of_locs (loc)
+ register dw_loc_descr_ref loc;
+{
+ register unsigned long size = 0;
+
+ for (; loc != NULL; loc = loc->dw_loc_next)
+ size += size_of_loc_descr (loc);
+
+ return size;
+}
+
+/* Return the power-of-two number of bytes necessary to represent VALUE. */
+
+static int
+constant_size (value)
+ long unsigned value;
+{
+ int log;
+
+ if (value == 0)
+ log = 0;
+ else
+ log = floor_log2 (value);
+
+ log = log / 8;
+ log = 1 << (floor_log2 (log) + 1);
+
+ return log;
+}
+
+/* Return the size of a DIE, as it is represented in the
+ .debug_info section. */
+
+static unsigned long
+size_of_die (die)
+ register dw_die_ref die;
+{
+ register unsigned long size = 0;
+ register dw_attr_ref a;
+
+ size += size_of_uleb128 (die->die_abbrev);
+ for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ {
+ switch (a->dw_attr_val.val_class)
+ {
+ case dw_val_class_addr:
+ size += PTR_SIZE;
+ break;
+ case dw_val_class_loc:
+ {
+ register unsigned long lsize
+ = size_of_locs (a->dw_attr_val.v.val_loc);
+
+ /* Block length. */
+ size += constant_size (lsize);
+ size += lsize;
+ }
+ break;
+ case dw_val_class_const:
+ size += 4;
+ break;
+ case dw_val_class_unsigned_const:
+ size += constant_size (a->dw_attr_val.v.val_unsigned);
+ break;
+ case dw_val_class_long_long:
+ size += 1 + 8; /* block */
+ break;
+ case dw_val_class_float:
+ size += 1 + a->dw_attr_val.v.val_float.length * 4; /* block */
+ break;
+ case dw_val_class_flag:
+ size += 1;
+ break;
+ case dw_val_class_die_ref:
+ size += DWARF_OFFSET_SIZE;
+ break;
+ case dw_val_class_fde_ref:
+ size += DWARF_OFFSET_SIZE;
+ break;
+ case dw_val_class_lbl_id:
+ size += PTR_SIZE;
+ break;
+ case dw_val_class_section_offset:
+ size += DWARF_OFFSET_SIZE;
+ break;
+ case dw_val_class_str:
+ size += size_of_string (a->dw_attr_val.v.val_str);
+ break;
+ default:
+ abort ();
+ }
+ }
+
+ return size;
+}
+
+/* Size the debugging information associated with a given DIE.
+ Visits the DIE's children recursively. Updates the global
+ variable next_die_offset, on each time through. Uses the
+ current value of next_die_offset to update the die_offset
+ field in each DIE. */
+
+static void
+calc_die_sizes (die)
+ dw_die_ref die;
+{
+ register dw_die_ref c;
+ die->die_offset = next_die_offset;
+ next_die_offset += size_of_die (die);
+
+ for (c = die->die_child; c != NULL; c = c->die_sib)
+ calc_die_sizes (c);
+
+ if (die->die_child != NULL)
+ /* Count the null byte used to terminate sibling lists. */
+ next_die_offset += 1;
+}
+
+/* Return the size of the line information prolog generated for the
+ compilation unit. */
+
+static unsigned long
+size_of_line_prolog ()
+{
+ register unsigned long size;
+ register unsigned long ft_index;
+
+ size = DWARF_LINE_PROLOG_HEADER_SIZE;
+
+ /* Count the size of the table giving number of args for each
+ standard opcode. */
+ size += DWARF_LINE_OPCODE_BASE - 1;
+
+ /* Include directory table is empty (at present). Count only the
+ null byte used to terminate the table. */
+ size += 1;
+
+ for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
+ {
+ /* File name entry. */
+ size += size_of_string (file_table[ft_index]);
+
+ /* Include directory index. */
+ size += size_of_uleb128 (0);
+
+ /* Modification time. */
+ size += size_of_uleb128 (0);
+
+ /* File length in bytes. */
+ size += size_of_uleb128 (0);
+ }
+
+ /* Count the file table terminator. */
+ size += 1;
+ return size;
+}
+
+/* Return the size of the line information generated for this
+ compilation unit. */
+
+static unsigned long
+size_of_line_info ()
+{
+ register unsigned long size;
+ register unsigned long lt_index;
+ register unsigned long current_line;
+ register long line_offset;
+ register long line_delta;
+ register unsigned long current_file;
+ register unsigned long function;
+ unsigned long size_of_set_address;
+
+ /* Size of a DW_LNE_set_address instruction. */
+ size_of_set_address = 1 + size_of_uleb128 (1 + PTR_SIZE) + 1 + PTR_SIZE;
+
+ /* Version number. */
+ size = 2;
+
+ /* Prolog length specifier. */
+ size += DWARF_OFFSET_SIZE;
+
+ /* Prolog. */
+ size += size_of_line_prolog ();
+
+ /* Set address register instruction. */
+ size += size_of_set_address;
+
+ current_file = 1;
+ current_line = 1;
+ for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
+ {
+ register dw_line_info_ref line_info;
+
+ /* Advance pc instruction. */
+ /* ??? See the DW_LNS_advance_pc comment in output_line_info. */
+ if (0)
+ size += 1 + 2;
+ else
+ size += size_of_set_address;
+
+ line_info = &line_info_table[lt_index];
+ if (line_info->dw_file_num != current_file)
+ {
+ /* Set file number instruction. */
+ size += 1;
+ current_file = line_info->dw_file_num;
+ size += size_of_uleb128 (current_file);
+ }
+
+ if (line_info->dw_line_num != current_line)
+ {
+ line_offset = line_info->dw_line_num - current_line;
+ line_delta = line_offset - DWARF_LINE_BASE;
+ current_line = line_info->dw_line_num;
+ if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+ /* 1-byte special line number instruction. */
+ size += 1;
+ else
+ {
+ /* Advance line instruction. */
+ size += 1;
+ size += size_of_sleb128 (line_offset);
+ /* Generate line entry instruction. */
+ size += 1;
+ }
+ }
+ }
+
+ /* Advance pc instruction. */
+ if (0)
+ size += 1 + 2;
+ else
+ size += size_of_set_address;
+
+ /* End of line number info. marker. */
+ size += 1 + size_of_uleb128 (1) + 1;
+
+ function = 0;
+ current_file = 1;
+ current_line = 1;
+ for (lt_index = 0; lt_index < separate_line_info_table_in_use; )
+ {
+ register dw_separate_line_info_ref line_info
+ = &separate_line_info_table[lt_index];
+ if (function != line_info->function)
+ {
+ function = line_info->function;
+ /* Set address register instruction. */
+ size += size_of_set_address;
+ }
+ else
+ {
+ /* Advance pc instruction. */
+ if (0)
+ size += 1 + 2;
+ else
+ size += size_of_set_address;
+ }
+
+ if (line_info->dw_file_num != current_file)
+ {
+ /* Set file number instruction. */
+ size += 1;
+ current_file = line_info->dw_file_num;
+ size += size_of_uleb128 (current_file);
+ }
+
+ if (line_info->dw_line_num != current_line)
+ {
+ line_offset = line_info->dw_line_num - current_line;
+ line_delta = line_offset - DWARF_LINE_BASE;
+ current_line = line_info->dw_line_num;
+ if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+ /* 1-byte special line number instruction. */
+ size += 1;
+ else
+ {
+ /* Advance line instruction. */
+ size += 1;
+ size += size_of_sleb128 (line_offset);
+
+ /* Generate line entry instruction. */
+ size += 1;
+ }
+ }
+
+ ++lt_index;
+
+ /* If we're done with a function, end its sequence. */
+ if (lt_index == separate_line_info_table_in_use
+ || separate_line_info_table[lt_index].function != function)
+ {
+ current_file = 1;
+ current_line = 1;
+
+ /* Advance pc instruction. */
+ if (0)
+ size += 1 + 2;
+ else
+ size += size_of_set_address;
+
+ /* End of line number info. marker. */
+ size += 1 + size_of_uleb128 (1) + 1;
+ }
+ }
+
+ return size;
+}
+
+/* Return the size of the .debug_pubnames table generated for the
+ compilation unit. */
+
+static unsigned long
+size_of_pubnames ()
+{
+ register unsigned long size;
+ register unsigned i;
+
+ size = DWARF_PUBNAMES_HEADER_SIZE;
+ for (i = 0; i < pubname_table_in_use; ++i)
+ {
+ register pubname_ref p = &pubname_table[i];
+ size += DWARF_OFFSET_SIZE + size_of_string (p->name);
+ }
+
+ size += DWARF_OFFSET_SIZE;
+ return size;
+}
+
+/* Return the size of the information in the .debug_aranges section. */
+
+static unsigned long
+size_of_aranges ()
+{
+ register unsigned long size;
+
+ size = DWARF_ARANGES_HEADER_SIZE;
+
+ /* Count the address/length pair for this compilation unit. */
+ size += 2 * PTR_SIZE;
+ size += 2 * PTR_SIZE * arange_table_in_use;
+
+ /* Count the two zero words used to terminated the address range table. */
+ size += 2 * PTR_SIZE;
+ return size;
+}
+
+/* Select the encoding of an attribute value. */
+
+static enum dwarf_form
+value_format (v)
+ dw_val_ref v;
+{
+ switch (v->val_class)
+ {
+ case dw_val_class_addr:
+ return DW_FORM_addr;
+ case dw_val_class_loc:
+ switch (constant_size (size_of_locs (v->v.val_loc)))
+ {
+ case 1:
+ return DW_FORM_block1;
+ case 2:
+ return DW_FORM_block2;
+ default:
+ abort ();
+ }
+ case dw_val_class_const:
+ return DW_FORM_data4;
+ case dw_val_class_unsigned_const:
+ switch (constant_size (v->v.val_unsigned))
+ {
+ case 1:
+ return DW_FORM_data1;
+ case 2:
+ return DW_FORM_data2;
+ case 4:
+ return DW_FORM_data4;
+ case 8:
+ return DW_FORM_data8;
+ default:
+ abort ();
+ }
+ case dw_val_class_long_long:
+ return DW_FORM_block1;
+ case dw_val_class_float:
+ return DW_FORM_block1;
+ case dw_val_class_flag:
+ return DW_FORM_flag;
+ case dw_val_class_die_ref:
+ return DW_FORM_ref;
+ case dw_val_class_fde_ref:
+ return DW_FORM_data;
+ case dw_val_class_lbl_id:
+ return DW_FORM_addr;
+ case dw_val_class_section_offset:
+ return DW_FORM_data;
+ case dw_val_class_str:
+ return DW_FORM_string;
+ default:
+ abort ();
+ }
+}
+
+/* Output the encoding of an attribute value. */
+
+static void
+output_value_format (v)
+ dw_val_ref v;
+{
+ enum dwarf_form form = value_format (v);
+
+ output_uleb128 (form);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, " (%s)", dwarf_form_name (form));
+
+ fputc ('\n', asm_out_file);
+}
+
+/* Output the .debug_abbrev section which defines the DIE abbreviation
+ table. */
+
+static void
+output_abbrev_section ()
+{
+ unsigned long abbrev_id;
+
+ dw_attr_ref a_attr;
+ for (abbrev_id = 1; abbrev_id < abbrev_die_table_in_use; ++abbrev_id)
+ {
+ register dw_die_ref abbrev = abbrev_die_table[abbrev_id];
+
+ output_uleb128 (abbrev_id);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, " (abbrev code)");
+
+ fputc ('\n', asm_out_file);
+ output_uleb128 (abbrev->die_tag);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, " (TAG: %s)",
+ dwarf_tag_name (abbrev->die_tag));
+
+ fputc ('\n', asm_out_file);
+ fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP,
+ abbrev->die_child != NULL ? DW_children_yes : DW_children_no);
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s %s",
+ ASM_COMMENT_START,
+ (abbrev->die_child != NULL
+ ? "DW_children_yes" : "DW_children_no"));
+
+ fputc ('\n', asm_out_file);
+
+ for (a_attr = abbrev->die_attr; a_attr != NULL;
+ a_attr = a_attr->dw_attr_next)
+ {
+ output_uleb128 (a_attr->dw_attr);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, " (%s)",
+ dwarf_attr_name (a_attr->dw_attr));
+
+ fputc ('\n', asm_out_file);
+ output_value_format (&a_attr->dw_attr_val);
+ }
+
+ fprintf (asm_out_file, "\t%s\t0,0\n", ASM_BYTE_OP);
+ }
+}
+
+/* Output location description stack opcode's operands (if any). */
+
+static void
+output_loc_operands (loc)
+ register dw_loc_descr_ref loc;
+{
+ register dw_val_ref val1 = &loc->dw_loc_oprnd1;
+ register dw_val_ref val2 = &loc->dw_loc_oprnd2;
+
+ switch (loc->dw_loc_opc)
+ {
+ case DW_OP_addr:
+ ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file, val1->v.val_addr);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_const1u:
+ case DW_OP_const1s:
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, val1->v.val_int);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ abort ();
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_constu:
+ output_uleb128 (val1->v.val_unsigned);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_consts:
+ output_sleb128 (val1->v.val_int);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_pick:
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_int);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_plus_uconst:
+ output_uleb128 (val1->v.val_unsigned);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_skip:
+ case DW_OP_bra:
+ ASM_OUTPUT_DWARF_DATA2 (asm_out_file, val1->v.val_int);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ output_sleb128 (val1->v.val_int);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_regx:
+ output_uleb128 (val1->v.val_unsigned);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_fbreg:
+ output_sleb128 (val1->v.val_int);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_bregx:
+ output_uleb128 (val1->v.val_unsigned);
+ fputc ('\n', asm_out_file);
+ output_sleb128 (val2->v.val_int);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_piece:
+ output_uleb128 (val1->v.val_unsigned);
+ fputc ('\n', asm_out_file);
+ break;
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, val1->v.val_flag);
+ fputc ('\n', asm_out_file);
+ break;
+ default:
+ break;
+ }
+}
+
+/* Compute the offset of a sibling. */
+
+static unsigned long
+sibling_offset (die)
+ dw_die_ref die;
+{
+ unsigned long offset;
+
+ if (die->die_child_last == NULL)
+ offset = die->die_offset + size_of_die (die);
+ else
+ offset = sibling_offset (die->die_child_last) + 1;
+
+ return offset;
+}
+
+/* Output the DIE and its attributes. Called recursively to generate
+ the definitions of each child DIE. */
+
+static void
+output_die (die)
+ register dw_die_ref die;
+{
+ register dw_attr_ref a;
+ register dw_die_ref c;
+ register unsigned long ref_offset;
+ register unsigned long size;
+ register dw_loc_descr_ref loc;
+ register int i;
+
+ output_uleb128 (die->die_abbrev);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, " (DIE (0x%lx) %s)",
+ die->die_offset, dwarf_tag_name (die->die_tag));
+
+ fputc ('\n', asm_out_file);
+
+ for (a = die->die_attr; a != NULL; a = a->dw_attr_next)
+ {
+ switch (a->dw_attr_val.val_class)
+ {
+ case dw_val_class_addr:
+ ASM_OUTPUT_DWARF_ADDR_CONST (asm_out_file,
+ a->dw_attr_val.v.val_addr);
+ break;
+
+ case dw_val_class_loc:
+ size = size_of_locs (a->dw_attr_val.v.val_loc);
+
+ /* Output the block length for this list of location operations. */
+ switch (constant_size (size))
+ {
+ case 1:
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, size);
+ break;
+ case 2:
+ ASM_OUTPUT_DWARF_DATA2 (asm_out_file, size);
+ break;
+ default:
+ abort ();
+ }
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s %s",
+ ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
+
+ fputc ('\n', asm_out_file);
+ for (loc = a->dw_attr_val.v.val_loc; loc != NULL;
+ loc = loc->dw_loc_next)
+ {
+ /* Output the opcode. */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, loc->dw_loc_opc);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s %s", ASM_COMMENT_START,
+ dwarf_stack_op_name (loc->dw_loc_opc));
+
+ fputc ('\n', asm_out_file);
+
+ /* Output the operand(s) (if any). */
+ output_loc_operands (loc);
+ }
+ break;
+
+ case dw_val_class_const:
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, a->dw_attr_val.v.val_int);
+ break;
+
+ case dw_val_class_unsigned_const:
+ switch (constant_size (a->dw_attr_val.v.val_unsigned))
+ {
+ case 1:
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+ a->dw_attr_val.v.val_unsigned);
+ break;
+ case 2:
+ ASM_OUTPUT_DWARF_DATA2 (asm_out_file,
+ a->dw_attr_val.v.val_unsigned);
+ break;
+ case 4:
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
+ a->dw_attr_val.v.val_unsigned);
+ break;
+ case 8:
+ ASM_OUTPUT_DWARF_DATA8 (asm_out_file,
+ a->dw_attr_val.v.val_long_long.hi,
+ a->dw_attr_val.v.val_long_long.low);
+ break;
+ default:
+ abort ();
+ }
+ break;
+
+ case dw_val_class_long_long:
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 8);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s %s",
+ ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA8 (asm_out_file,
+ a->dw_attr_val.v.val_long_long.hi,
+ a->dw_attr_val.v.val_long_long.low);
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file,
+ "\t%s long long constant", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ break;
+
+ case dw_val_class_float:
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+ a->dw_attr_val.v.val_float.length * 4);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s %s",
+ ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
+
+ fputc ('\n', asm_out_file);
+ for (i = 0; i < a->dw_attr_val.v.val_float.length; ++i)
+ {
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
+ a->dw_attr_val.v.val_float.array[i]);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s fp constant word %d",
+ ASM_COMMENT_START, i);
+
+ fputc ('\n', asm_out_file);
+ }
+ break;
+
+ case dw_val_class_flag:
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, a->dw_attr_val.v.val_flag);
+ break;
+
+ case dw_val_class_die_ref:
+ if (a->dw_attr_val.v.val_die_ref != NULL)
+ ref_offset = a->dw_attr_val.v.val_die_ref->die_offset;
+ else if (a->dw_attr == DW_AT_sibling)
+ ref_offset = sibling_offset(die);
+ else
+ abort ();
+
+ ASM_OUTPUT_DWARF_DATA (asm_out_file, ref_offset);
+ break;
+
+ case dw_val_class_fde_ref:
+ {
+ char l1[20];
+ ASM_GENERATE_INTERNAL_LABEL
+ (l1, FDE_AFTER_SIZE_LABEL, a->dw_attr_val.v.val_fde_index * 2);
+ ASM_OUTPUT_DWARF_OFFSET (asm_out_file, l1);
+ fprintf (asm_out_file, " - %d", DWARF_OFFSET_SIZE);
+ }
+ break;
+
+ case dw_val_class_lbl_id:
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, a->dw_attr_val.v.val_lbl_id);
+ break;
+
+ case dw_val_class_section_offset:
+ ASM_OUTPUT_DWARF_OFFSET (asm_out_file,
+ stripattributes
+ (a->dw_attr_val.v.val_section));
+ break;
+
+ case dw_val_class_str:
+ if (flag_debug_asm)
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, a->dw_attr_val.v.val_str);
+ else
+ ASM_OUTPUT_ASCII (asm_out_file,
+ a->dw_attr_val.v.val_str,
+ strlen (a->dw_attr_val.v.val_str) + 1);
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (a->dw_attr_val.val_class != dw_val_class_loc
+ && a->dw_attr_val.val_class != dw_val_class_long_long
+ && a->dw_attr_val.val_class != dw_val_class_float)
+ {
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s %s",
+ ASM_COMMENT_START, dwarf_attr_name (a->dw_attr));
+
+ fputc ('\n', asm_out_file);
+ }
+ }
+
+ for (c = die->die_child; c != NULL; c = c->die_sib)
+ output_die (c);
+
+ if (die->die_child != NULL)
+ {
+ /* Add null byte to terminate sibling list. */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s end of children of DIE 0x%lx",
+ ASM_COMMENT_START, die->die_offset);
+
+ fputc ('\n', asm_out_file);
+ }
+}
+
+/* Output the compilation unit that appears at the beginning of the
+ .debug_info section, and precedes the DIE descriptions. */
+
+static void
+output_compilation_unit_header ()
+{
+ ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset - DWARF_OFFSET_SIZE);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Length of Compilation Unit Info.",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DWARF version number", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (ABBREV_SECTION));
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Offset Into Abbrev. Section",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Pointer Size (in bytes)", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+}
+
+/* The DWARF2 pubname for a nested thingy looks like "A::f". The output
+ of decl_printable_name for C++ looks like "A::f(int)". Let's drop the
+ argument list, and maybe the scope. */
+
+static char *
+dwarf2_name (decl, scope)
+ tree decl;
+ int scope;
+{
+ return (*decl_printable_name) (decl, scope ? 1 : 0);
+}
+
+/* Add a new entry to .debug_pubnames if appropriate. */
+
+static void
+add_pubname (decl, die)
+ tree decl;
+ dw_die_ref die;
+{
+ pubname_ref p;
+
+ if (! TREE_PUBLIC (decl))
+ return;
+
+ if (pubname_table_in_use == pubname_table_allocated)
+ {
+ pubname_table_allocated += PUBNAME_TABLE_INCREMENT;
+ pubname_table = (pubname_ref) xrealloc
+ (pubname_table, pubname_table_allocated * sizeof (pubname_entry));
+ }
+
+ p = &pubname_table[pubname_table_in_use++];
+ p->die = die;
+
+ p->name = xstrdup (dwarf2_name (decl, 1));
+}
+
+/* Output the public names table used to speed up access to externally
+ visible names. For now, only generate entries for externally
+ visible procedures. */
+
+static void
+output_pubnames ()
+{
+ register unsigned i;
+ register unsigned long pubnames_length = size_of_pubnames ();
+
+ ASM_OUTPUT_DWARF_DATA (asm_out_file, pubnames_length);
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Length of Public Names Info.",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_INFO_SECTION));
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA (asm_out_file, next_die_offset);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Compilation Unit Length", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ for (i = 0; i < pubname_table_in_use; ++i)
+ {
+ register pubname_ref pub = &pubname_table[i];
+
+ ASM_OUTPUT_DWARF_DATA (asm_out_file, pub->die->die_offset);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DIE offset", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+
+ if (flag_debug_asm)
+ {
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, pub->name);
+ fprintf (asm_out_file, "%s external name", ASM_COMMENT_START);
+ }
+ else
+ {
+ ASM_OUTPUT_ASCII (asm_out_file, pub->name, strlen (pub->name) + 1);
+ }
+
+ fputc ('\n', asm_out_file);
+ }
+
+ ASM_OUTPUT_DWARF_DATA (asm_out_file, 0);
+ fputc ('\n', asm_out_file);
+}
+
+/* Add a new entry to .debug_aranges if appropriate. */
+
+static void
+add_arange (decl, die)
+ tree decl;
+ dw_die_ref die;
+{
+ if (! DECL_SECTION_NAME (decl))
+ return;
+
+ if (arange_table_in_use == arange_table_allocated)
+ {
+ arange_table_allocated += ARANGE_TABLE_INCREMENT;
+ arange_table
+ = (arange_ref) xrealloc (arange_table,
+ arange_table_allocated * sizeof (dw_die_ref));
+ }
+
+ arange_table[arange_table_in_use++] = die;
+}
+
+/* Output the information that goes into the .debug_aranges table.
+ Namely, define the beginning and ending address range of the
+ text section generated for this compilation unit. */
+
+static void
+output_aranges ()
+{
+ register unsigned i;
+ register unsigned long aranges_length = size_of_aranges ();
+
+ ASM_OUTPUT_DWARF_DATA (asm_out_file, aranges_length);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Length of Address Ranges Info.",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_OFFSET (asm_out_file, stripattributes (DEBUG_INFO_SECTION));
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Offset of Compilation Unit Info.",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, PTR_SIZE);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Size of Address", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Size of Segment Descriptor",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, 4);
+ if (PTR_SIZE == 8)
+ fprintf (asm_out_file, ",0,0");
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Pad to %d byte boundary",
+ ASM_COMMENT_START, 2 * PTR_SIZE);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_SECTION);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, text_end_label, TEXT_SECTION);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ for (i = 0; i < arange_table_in_use; ++i)
+ {
+ dw_die_ref a = arange_table[i];
+
+ if (a->die_tag == DW_TAG_subprogram)
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, get_AT_low_pc (a));
+ else
+ {
+ char *name = get_AT_string (a, DW_AT_MIPS_linkage_name);
+ if (! name)
+ name = get_AT_string (a, DW_AT_name);
+
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, name);
+ }
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Address", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ if (a->die_tag == DW_TAG_subprogram)
+ ASM_OUTPUT_DWARF_ADDR_DELTA (asm_out_file, get_AT_hi_pc (a),
+ get_AT_low_pc (a));
+ else
+ ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file,
+ get_AT_unsigned (a, DW_AT_byte_size));
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "%s Length", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ }
+
+ /* Output the terminator words. */
+ ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR_DATA (asm_out_file, 0);
+ fputc ('\n', asm_out_file);
+}
+
+/* Output the source line number correspondence information. This
+ information goes into the .debug_line section.
+
+ If the format of this data changes, then the function size_of_line_info
+ must also be adjusted the same way. */
+
+static void
+output_line_info ()
+{
+ char line_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ char prev_line_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ register unsigned opc;
+ register unsigned n_op_args;
+ register unsigned long ft_index;
+ register unsigned long lt_index;
+ register unsigned long current_line;
+ register long line_offset;
+ register long line_delta;
+ register unsigned long current_file;
+ register unsigned long function;
+
+ ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_info ());
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Length of Source Line Info.",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA2 (asm_out_file, DWARF_VERSION);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DWARF Version", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA (asm_out_file, size_of_line_prolog ());
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Prolog Length", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_MIN_INSTR_LENGTH);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Minimum Instruction Length",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DWARF_LINE_DEFAULT_IS_STMT_START);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Default is_stmt_start flag",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ fprintf (asm_out_file, "\t%s\t%d", ASM_BYTE_OP, DWARF_LINE_BASE);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Line Base Value (Special Opcodes)",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_RANGE);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Line Range Value (Special Opcodes)",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ fprintf (asm_out_file, "\t%s\t%u", ASM_BYTE_OP, DWARF_LINE_OPCODE_BASE);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s Special Opcode Base", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ for (opc = 1; opc < DWARF_LINE_OPCODE_BASE; ++opc)
+ {
+ switch (opc)
+ {
+ case DW_LNS_advance_pc:
+ case DW_LNS_advance_line:
+ case DW_LNS_set_file:
+ case DW_LNS_set_column:
+ case DW_LNS_fixed_advance_pc:
+ n_op_args = 1;
+ break;
+ default:
+ n_op_args = 0;
+ break;
+ }
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, n_op_args);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s opcode: 0x%x has %d args",
+ ASM_COMMENT_START, opc, n_op_args);
+ fputc ('\n', asm_out_file);
+ }
+
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "%s Include Directory Table\n", ASM_COMMENT_START);
+
+ /* Include directory table is empty, at present */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ fputc ('\n', asm_out_file);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "%s File Name Table\n", ASM_COMMENT_START);
+
+ for (ft_index = 1; ft_index < file_table_in_use; ++ft_index)
+ {
+ if (flag_debug_asm)
+ {
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, file_table[ft_index]);
+ fprintf (asm_out_file, "%s File Entry: 0x%lx",
+ ASM_COMMENT_START, ft_index);
+ }
+ else
+ {
+ ASM_OUTPUT_ASCII (asm_out_file,
+ file_table[ft_index],
+ strlen (file_table[ft_index]) + 1);
+ }
+
+ fputc ('\n', asm_out_file);
+
+ /* Include directory index */
+ output_uleb128 (0);
+ fputc ('\n', asm_out_file);
+
+ /* Modification time */
+ output_uleb128 (0);
+ fputc ('\n', asm_out_file);
+
+ /* File length in bytes */
+ output_uleb128 (0);
+ fputc ('\n', asm_out_file);
+ }
+
+ /* Terminate the file name table */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ fputc ('\n', asm_out_file);
+
+ /* Set the address register to the first location in the text section */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ output_uleb128 (1 + PTR_SIZE);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_SECTION);
+ fputc ('\n', asm_out_file);
+
+ /* Generate the line number to PC correspondence table, encoded as
+ a series of state machine operations. */
+ current_file = 1;
+ current_line = 1;
+ strcpy (prev_line_label, TEXT_SECTION);
+ for (lt_index = 1; lt_index < line_info_table_in_use; ++lt_index)
+ {
+ register dw_line_info_ref line_info;
+
+ /* Emit debug info for the address of the current line, choosing
+ the encoding that uses the least amount of space. */
+ /* ??? Unfortunately, we have little choice here currently, and must
+ always use the most general form. Gcc does not know the address
+ delta itself, so we can't use DW_LNS_advance_pc. There are no known
+ dwarf2 aware assemblers at this time, so we can't use any special
+ pseudo ops that would allow the assembler to optimally encode this for
+ us. Many ports do have length attributes which will give an upper
+ bound on the address range. We could perhaps use length attributes
+ to determine when it is safe to use DW_LNS_fixed_advance_pc. */
+ ASM_GENERATE_INTERNAL_LABEL (line_label, LINE_CODE_LABEL, lt_index);
+ if (0)
+ {
+ /* This can handle deltas up to 0xffff. This takes 3 bytes. */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label, prev_line_label);
+ fputc ('\n', asm_out_file);
+ }
+ else
+ {
+ /* This can handle any delta. This takes 4+PTR_SIZE bytes. */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNE_set_address",
+ ASM_COMMENT_START);
+ fputc ('\n', asm_out_file);
+ output_uleb128 (1 + PTR_SIZE);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
+ fputc ('\n', asm_out_file);
+ }
+ strcpy (prev_line_label, line_label);
+
+ /* Emit debug info for the source file of the current line, if
+ different from the previous line. */
+ line_info = &line_info_table[lt_index];
+ if (line_info->dw_file_num != current_file)
+ {
+ current_file = line_info->dw_file_num;
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ output_uleb128 (current_file);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
+
+ fputc ('\n', asm_out_file);
+ }
+
+ /* Emit debug info for the current line number, choosing the encoding
+ that uses the least amount of space. */
+ line_offset = line_info->dw_line_num - current_line;
+ line_delta = line_offset - DWARF_LINE_BASE;
+ current_line = line_info->dw_line_num;
+ if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+ {
+ /* This can handle deltas from -10 to 234, using the current
+ definitions of DWARF_LINE_BASE and DWARF_LINE_RANGE. This
+ takes 1 byte. */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+ DWARF_LINE_OPCODE_BASE + line_delta);
+ if (flag_debug_asm)
+ fprintf (asm_out_file,
+ "\t%s line %ld", ASM_COMMENT_START, current_line);
+
+ fputc ('\n', asm_out_file);
+ }
+ else
+ {
+ /* This can handle any delta. This takes at least 4 bytes, depending
+ on the value being encoded. */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s advance to line %ld",
+ ASM_COMMENT_START, current_line);
+
+ fputc ('\n', asm_out_file);
+ output_sleb128 (line_offset);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
+ fputc ('\n', asm_out_file);
+ }
+ }
+
+ /* Emit debug info for the address of the end of the function. */
+ if (0)
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, text_end_label, prev_line_label);
+ fputc ('\n', asm_out_file);
+ }
+ else
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNE_set_address", ASM_COMMENT_START);
+ fputc ('\n', asm_out_file);
+ output_uleb128 (1 + PTR_SIZE);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, text_end_label);
+ fputc ('\n', asm_out_file);
+ }
+
+ /* Output the marker for the end of the line number info. */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNE_end_sequence", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ output_uleb128 (1);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
+ fputc ('\n', asm_out_file);
+
+ function = 0;
+ current_file = 1;
+ current_line = 1;
+ for (lt_index = 0; lt_index < separate_line_info_table_in_use; )
+ {
+ register dw_separate_line_info_ref line_info
+ = &separate_line_info_table[lt_index];
+
+ /* Emit debug info for the address of the current line. If this is
+ a new function, or the first line of a function, then we need
+ to handle it differently. */
+ ASM_GENERATE_INTERNAL_LABEL (line_label, SEPARATE_LINE_CODE_LABEL,
+ lt_index);
+ if (function != line_info->function)
+ {
+ function = line_info->function;
+
+ /* Set the address register to the first line in the function */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNE_set_address",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ output_uleb128 (1 + PTR_SIZE);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
+ fputc ('\n', asm_out_file);
+ }
+ else
+ {
+ /* ??? See the DW_LNS_advance_pc comment above. */
+ if (0)
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label,
+ prev_line_label);
+ fputc ('\n', asm_out_file);
+ }
+ else
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNE_set_address",
+ ASM_COMMENT_START);
+ fputc ('\n', asm_out_file);
+ output_uleb128 (1 + PTR_SIZE);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
+ fputc ('\n', asm_out_file);
+ }
+ }
+ strcpy (prev_line_label, line_label);
+
+ /* Emit debug info for the source file of the current line, if
+ different from the previous line. */
+ if (line_info->dw_file_num != current_file)
+ {
+ current_file = line_info->dw_file_num;
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_set_file);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNS_set_file", ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ output_uleb128 (current_file);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, " (\"%s\")", file_table[current_file]);
+
+ fputc ('\n', asm_out_file);
+ }
+
+ /* Emit debug info for the current line number, choosing the encoding
+ that uses the least amount of space. */
+ if (line_info->dw_line_num != current_line)
+ {
+ line_offset = line_info->dw_line_num - current_line;
+ line_delta = line_offset - DWARF_LINE_BASE;
+ current_line = line_info->dw_line_num;
+ if (line_delta >= 0 && line_delta < (DWARF_LINE_RANGE - 1))
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file,
+ DWARF_LINE_OPCODE_BASE + line_delta);
+ if (flag_debug_asm)
+ fprintf (asm_out_file,
+ "\t%s line %ld", ASM_COMMENT_START, current_line);
+
+ fputc ('\n', asm_out_file);
+ }
+ else
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_advance_line);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s advance to line %ld",
+ ASM_COMMENT_START, current_line);
+
+ fputc ('\n', asm_out_file);
+ output_sleb128 (line_offset);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_copy);
+ fputc ('\n', asm_out_file);
+ }
+ }
+
+ ++lt_index;
+
+ /* If we're done with a function, end its sequence. */
+ if (lt_index == separate_line_info_table_in_use
+ || separate_line_info_table[lt_index].function != function)
+ {
+ current_file = 1;
+ current_line = 1;
+
+ /* Emit debug info for the address of the end of the function. */
+ ASM_GENERATE_INTERNAL_LABEL (line_label, FUNC_END_LABEL, function);
+ if (0)
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNS_fixed_advance_pc);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNS_fixed_advance_pc",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, line_label,
+ prev_line_label);
+ fputc ('\n', asm_out_file);
+ }
+ else
+ {
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNE_set_address",
+ ASM_COMMENT_START);
+ fputc ('\n', asm_out_file);
+ output_uleb128 (1 + PTR_SIZE);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_set_address);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, line_label);
+ fputc ('\n', asm_out_file);
+ }
+
+ /* Output the marker for the end of this sequence. */
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, 0);
+ if (flag_debug_asm)
+ fprintf (asm_out_file, "\t%s DW_LNE_end_sequence",
+ ASM_COMMENT_START);
+
+ fputc ('\n', asm_out_file);
+ output_uleb128 (1);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_DWARF_DATA1 (asm_out_file, DW_LNE_end_sequence);
+ fputc ('\n', asm_out_file);
+ }
+ }
+}
+
+/* Given a pointer to a BLOCK node return non-zero if (and only if) the node
+ in question represents the outermost pair of curly braces (i.e. the "body
+ block") of a function or method.
+
+ For any BLOCK node representing a "body block" of a function or method, the
+ BLOCK_SUPERCONTEXT of the node will point to another BLOCK node which
+ represents the outermost (function) scope for the function or method (i.e.
+ the one which includes the formal parameters). The BLOCK_SUPERCONTEXT of
+ *that* node in turn will point to the relevant FUNCTION_DECL node. */
+
+static inline int
+is_body_block (stmt)
+ register tree stmt;
+{
+ if (TREE_CODE (stmt) == BLOCK)
+ {
+ register tree parent = BLOCK_SUPERCONTEXT (stmt);
+
+ if (TREE_CODE (parent) == BLOCK)
+ {
+ register tree grandparent = BLOCK_SUPERCONTEXT (parent);
+
+ if (TREE_CODE (grandparent) == FUNCTION_DECL)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Given a pointer to a tree node for some base type, return a pointer to
+ a DIE that describes the given type.
+
+ This routine must only be called for GCC type nodes that correspond to
+ Dwarf base (fundamental) types. */
+
+static dw_die_ref
+base_type_die (type)
+ register tree type;
+{
+ register dw_die_ref base_type_result;
+ register char *type_name;
+ register enum dwarf_type encoding;
+ register tree name = TYPE_NAME (type);
+
+ if (TREE_CODE (type) == ERROR_MARK
+ || TREE_CODE (type) == VOID_TYPE)
+ return 0;
+
+ if (TREE_CODE (name) == TYPE_DECL)
+ name = DECL_NAME (name);
+ type_name = IDENTIFIER_POINTER (name);
+
+ switch (TREE_CODE (type))
+ {
+ case INTEGER_TYPE:
+ /* Carefully distinguish the C character types, without messing
+ up if the language is not C. Note that we check only for the names
+ that contain spaces; other names might occur by coincidence in other
+ languages. */
+ if (! (TYPE_PRECISION (type) == CHAR_TYPE_SIZE
+ && (type == char_type_node
+ || ! strcmp (type_name, "signed char")
+ || ! strcmp (type_name, "unsigned char"))))
+ {
+ if (TREE_UNSIGNED (type))
+ encoding = DW_ATE_unsigned;
+ else
+ encoding = DW_ATE_signed;
+ break;
+ }
+ /* else fall through */
+
+ case CHAR_TYPE:
+ /* GNU Pascal/Ada CHAR type. Not used in C. */
+ if (TREE_UNSIGNED (type))
+ encoding = DW_ATE_unsigned_char;
+ else
+ encoding = DW_ATE_signed_char;
+ break;
+
+ case REAL_TYPE:
+ encoding = DW_ATE_float;
+ break;
+
+ case COMPLEX_TYPE:
+ encoding = DW_ATE_complex_float;
+ break;
+
+ case BOOLEAN_TYPE:
+ /* GNU FORTRAN/Ada/C++ BOOLEAN type. */
+ encoding = DW_ATE_boolean;
+ break;
+
+ default:
+ abort (); /* No other TREE_CODEs are Dwarf fundamental types. */
+ }
+
+ base_type_result = new_die (DW_TAG_base_type, comp_unit_die);
+ add_AT_string (base_type_result, DW_AT_name, type_name);
+ add_AT_unsigned (base_type_result, DW_AT_byte_size,
+ int_size_in_bytes (type));
+ add_AT_unsigned (base_type_result, DW_AT_encoding, encoding);
+
+ return base_type_result;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return a pointer to
+ the Dwarf "root" type for the given input type. The Dwarf "root" type of
+ a given type is generally the same as the given type, except that if the
+ given type is a pointer or reference type, then the root type of the given
+ type is the root type of the "basis" type for the pointer or reference
+ type. (This definition of the "root" type is recursive.) Also, the root
+ type of a `const' qualified type or a `volatile' qualified type is the
+ root type of the given type without the qualifiers. */
+
+static tree
+root_type (type)
+ register tree type;
+{
+ if (TREE_CODE (type) == ERROR_MARK)
+ return error_mark_node;
+
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ return error_mark_node;
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ return type_main_variant (root_type (TREE_TYPE (type)));
+
+ default:
+ return type_main_variant (type);
+ }
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the
+ given input type is a Dwarf "fundamental" type. Otherwise return null. */
+
+static inline int
+is_base_type (type)
+ register tree type;
+{
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case COMPLEX_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ return 1;
+
+ case SET_TYPE:
+ case ARRAY_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case ENUMERAL_TYPE:
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case FILE_TYPE:
+ case OFFSET_TYPE:
+ case LANG_TYPE:
+ return 0;
+
+ default:
+ abort ();
+ }
+
+ return 0;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return a debugging
+ entry that chains various modifiers in front of the given type. */
+
+static dw_die_ref
+modified_type_die (type, is_const_type, is_volatile_type, context_die)
+ register tree type;
+ register int is_const_type;
+ register int is_volatile_type;
+ register dw_die_ref context_die;
+{
+ register enum tree_code code = TREE_CODE (type);
+ register dw_die_ref mod_type_die = NULL;
+ register dw_die_ref sub_die = NULL;
+ register tree item_type = NULL;
+
+ if (code != ERROR_MARK)
+ {
+ type = build_type_variant (type, is_const_type, is_volatile_type);
+
+ mod_type_die = lookup_type_die (type);
+ if (mod_type_die)
+ return mod_type_die;
+
+ /* Handle C typedef types. */
+ if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+ {
+ tree dtype = TREE_TYPE (TYPE_NAME (type));
+ if (type == dtype)
+ {
+ /* For a named type, use the typedef. */
+ gen_type_die (type, context_die);
+ mod_type_die = lookup_type_die (type);
+ }
+
+ else if (is_const_type < TYPE_READONLY (dtype)
+ || is_volatile_type < TYPE_VOLATILE (dtype))
+ /* cv-unqualified version of named type. Just use the unnamed
+ type to which it refers. */
+ mod_type_die
+ = modified_type_die (DECL_ORIGINAL_TYPE (TYPE_NAME (type)),
+ is_const_type, is_volatile_type,
+ context_die);
+ /* Else cv-qualified version of named type; fall through. */
+ }
+
+ if (mod_type_die)
+ /* OK */;
+ else if (is_const_type)
+ {
+ mod_type_die = new_die (DW_TAG_const_type, comp_unit_die);
+ sub_die = modified_type_die (type, 0, is_volatile_type, context_die);
+ }
+ else if (is_volatile_type)
+ {
+ mod_type_die = new_die (DW_TAG_volatile_type, comp_unit_die);
+ sub_die = modified_type_die (type, 0, 0, context_die);
+ }
+ else if (code == POINTER_TYPE)
+ {
+ mod_type_die = new_die (DW_TAG_pointer_type, comp_unit_die);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+#if 0
+ add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
+#endif
+ item_type = TREE_TYPE (type);
+ }
+ else if (code == REFERENCE_TYPE)
+ {
+ mod_type_die = new_die (DW_TAG_reference_type, comp_unit_die);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+#if 0
+ add_AT_unsigned (mod_type_die, DW_AT_address_class, 0);
+#endif
+ item_type = TREE_TYPE (type);
+ }
+ else if (is_base_type (type))
+ mod_type_die = base_type_die (type);
+ else
+ {
+ gen_type_die (type, context_die);
+
+ /* We have to get the type_main_variant here (and pass that to the
+ `lookup_type_die' routine) because the ..._TYPE node we have
+ might simply be a *copy* of some original type node (where the
+ copy was created to help us keep track of typedef names) and
+ that copy might have a different TYPE_UID from the original
+ ..._TYPE node. */
+ mod_type_die = lookup_type_die (type_main_variant (type));
+ if (mod_type_die == NULL)
+ abort ();
+ }
+ }
+
+ equate_type_number_to_die (type, mod_type_die);
+ if (item_type)
+ /* We must do this after the equate_type_number_to_die call, in case
+ this is a recursive type. This ensures that the modified_type_die
+ recursion will terminate even if the type is recursive. Recursive
+ types are possible in Ada. */
+ sub_die = modified_type_die (item_type,
+ TYPE_READONLY (item_type),
+ TYPE_VOLATILE (item_type),
+ context_die);
+
+ if (sub_die != NULL)
+ add_AT_die_ref (mod_type_die, DW_AT_type, sub_die);
+
+ return mod_type_die;
+}
+
+/* Given a pointer to an arbitrary ..._TYPE tree node, return true if it is
+ an enumerated type. */
+
+static inline int
+type_is_enum (type)
+ register tree type;
+{
+ return TREE_CODE (type) == ENUMERAL_TYPE;
+}
+
+/* Return a location descriptor that designates a machine register. */
+
+static dw_loc_descr_ref
+reg_loc_descriptor (rtl)
+ register rtx rtl;
+{
+ register dw_loc_descr_ref loc_result = NULL;
+ register unsigned reg = reg_number (rtl);
+
+ if (reg <= 31)
+ loc_result = new_loc_descr (DW_OP_reg0 + reg, 0, 0);
+ else
+ loc_result = new_loc_descr (DW_OP_regx, reg, 0);
+
+ return loc_result;
+}
+
+/* Return a location descriptor that designates a base+offset location. */
+
+static dw_loc_descr_ref
+based_loc_descr (reg, offset)
+ unsigned reg;
+ long int offset;
+{
+ register dw_loc_descr_ref loc_result;
+ /* For the "frame base", we use the frame pointer or stack pointer
+ registers, since the RTL for local variables is relative to one of
+ them. */
+ register unsigned fp_reg = DBX_REGISTER_NUMBER (frame_pointer_needed
+ ? HARD_FRAME_POINTER_REGNUM
+ : STACK_POINTER_REGNUM);
+
+ if (reg == fp_reg)
+ loc_result = new_loc_descr (DW_OP_fbreg, offset, 0);
+ else if (reg <= 31)
+ loc_result = new_loc_descr (DW_OP_breg0 + reg, offset, 0);
+ else
+ loc_result = new_loc_descr (DW_OP_bregx, reg, offset);
+
+ return loc_result;
+}
+
+/* Return true if this RTL expression describes a base+offset calculation. */
+
+static inline int
+is_based_loc (rtl)
+ register rtx rtl;
+{
+ return (GET_CODE (rtl) == PLUS
+ && ((GET_CODE (XEXP (rtl, 0)) == REG
+ && GET_CODE (XEXP (rtl, 1)) == CONST_INT)));
+}
+
+/* The following routine converts the RTL for a variable or parameter
+ (resident in memory) into an equivalent Dwarf representation of a
+ mechanism for getting the address of that same variable onto the top of a
+ hypothetical "address evaluation" stack.
+
+ When creating memory location descriptors, we are effectively transforming
+ the RTL for a memory-resident object into its Dwarf postfix expression
+ equivalent. This routine recursively descends an RTL tree, turning
+ it into Dwarf postfix code as it goes. */
+
+static dw_loc_descr_ref
+mem_loc_descriptor (rtl)
+ register rtx rtl;
+{
+ dw_loc_descr_ref mem_loc_result = NULL;
+ /* Note that for a dynamically sized array, the location we will generate a
+ description of here will be the lowest numbered location which is
+ actually within the array. That's *not* necessarily the same as the
+ zeroth element of the array. */
+
+ switch (GET_CODE (rtl))
+ {
+ case SUBREG:
+ /* The case of a subreg may arise when we have a local (register)
+ variable or a formal (register) parameter which doesn't quite fill
+ up an entire register. For now, just assume that it is
+ legitimate to make the Dwarf info refer to the whole register which
+ contains the given subreg. */
+ rtl = XEXP (rtl, 0);
+
+ /* ... fall through ... */
+
+ case REG:
+ /* Whenever a register number forms a part of the description of the
+ method for calculating the (dynamic) address of a memory resident
+ object, DWARF rules require the register number be referred to as
+ a "base register". This distinction is not based in any way upon
+ what category of register the hardware believes the given register
+ belongs to. This is strictly DWARF terminology we're dealing with
+ here. Note that in cases where the location of a memory-resident
+ data object could be expressed as: OP_ADD (OP_BASEREG (basereg),
+ OP_CONST (0)) the actual DWARF location descriptor that we generate
+ may just be OP_BASEREG (basereg). This may look deceptively like
+ the object in question was allocated to a register (rather than in
+ memory) so DWARF consumers need to be aware of the subtle
+ distinction between OP_REG and OP_BASEREG. */
+ mem_loc_result = based_loc_descr (reg_number (rtl), 0);
+ break;
+
+ case MEM:
+ mem_loc_result = mem_loc_descriptor (XEXP (rtl, 0));
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_deref, 0, 0));
+ break;
+
+ case CONST:
+ case SYMBOL_REF:
+ mem_loc_result = new_loc_descr (DW_OP_addr, 0, 0);
+ mem_loc_result->dw_loc_oprnd1.val_class = dw_val_class_addr;
+ mem_loc_result->dw_loc_oprnd1.v.val_addr = addr_to_string (rtl);
+ break;
+
+ case PLUS:
+ if (is_based_loc (rtl))
+ mem_loc_result = based_loc_descr (reg_number (XEXP (rtl, 0)),
+ INTVAL (XEXP (rtl, 1)));
+ else
+ {
+ add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0)));
+ add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1)));
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_plus, 0, 0));
+ }
+ break;
+
+ case MULT:
+ /* If a pseudo-reg is optimized away, it is possible for it to
+ be replaced with a MEM containing a multiply. */
+ add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 0)));
+ add_loc_descr (&mem_loc_result, mem_loc_descriptor (XEXP (rtl, 1)));
+ add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_mul, 0, 0));
+ break;
+
+ case CONST_INT:
+ mem_loc_result = new_loc_descr (DW_OP_constu, INTVAL (rtl), 0);
+ break;
+
+ default:
+ abort ();
+ }
+
+ return mem_loc_result;
+}
+
+/* Return a descriptor that describes the concatenation of two locations.
+ This is typically a complex variable. */
+
+static dw_loc_descr_ref
+concat_loc_descriptor (x0, x1)
+ register rtx x0, x1;
+{
+ dw_loc_descr_ref cc_loc_result = NULL;
+
+ if (!is_pseudo_reg (x0)
+ && (GET_CODE (x0) != MEM || !is_pseudo_reg (XEXP (x0, 0))))
+ add_loc_descr (&cc_loc_result, loc_descriptor (x0));
+ add_loc_descr (&cc_loc_result,
+ new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x0)), 0));
+
+ if (!is_pseudo_reg (x1)
+ && (GET_CODE (x1) != MEM || !is_pseudo_reg (XEXP (x1, 0))))
+ add_loc_descr (&cc_loc_result, loc_descriptor (x1));
+ add_loc_descr (&cc_loc_result,
+ new_loc_descr (DW_OP_piece, GET_MODE_SIZE (GET_MODE (x1)), 0));
+
+ return cc_loc_result;
+}
+
+/* Output a proper Dwarf location descriptor for a variable or parameter
+ which is either allocated in a register or in a memory location. For a
+ register, we just generate an OP_REG and the register number. For a
+ memory location we provide a Dwarf postfix expression describing how to
+ generate the (dynamic) address of the object onto the address stack. */
+
+static dw_loc_descr_ref
+loc_descriptor (rtl)
+ register rtx rtl;
+{
+ dw_loc_descr_ref loc_result = NULL;
+ switch (GET_CODE (rtl))
+ {
+ case SUBREG:
+ /* The case of a subreg may arise when we have a local (register)
+ variable or a formal (register) parameter which doesn't quite fill
+ up an entire register. For now, just assume that it is
+ legitimate to make the Dwarf info refer to the whole register which
+ contains the given subreg. */
+ rtl = XEXP (rtl, 0);
+
+ /* ... fall through ... */
+
+ case REG:
+ loc_result = reg_loc_descriptor (rtl);
+ break;
+
+ case MEM:
+ loc_result = mem_loc_descriptor (XEXP (rtl, 0));
+ break;
+
+ case CONCAT:
+ loc_result = concat_loc_descriptor (XEXP (rtl, 0), XEXP (rtl, 1));
+ break;
+
+ default:
+ abort ();
+ }
+
+ return loc_result;
+}
+
+/* Given an unsigned value, round it up to the lowest multiple of `boundary'
+ which is not less than the value itself. */
+
+static inline unsigned
+ceiling (value, boundary)
+ register unsigned value;
+ register unsigned boundary;
+{
+ return (((value + boundary - 1) / boundary) * boundary);
+}
+
+/* Given a pointer to what is assumed to be a FIELD_DECL node, return a
+ pointer to the declared type for the relevant field variable, or return
+ `integer_type_node' if the given node turns out to be an
+ ERROR_MARK node. */
+
+static inline tree
+field_type (decl)
+ register tree decl;
+{
+ register tree type;
+
+ if (TREE_CODE (decl) == ERROR_MARK)
+ return integer_type_node;
+
+ type = DECL_BIT_FIELD_TYPE (decl);
+ if (type == NULL_TREE)
+ type = TREE_TYPE (decl);
+
+ return type;
+}
+
+/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
+ node, return the alignment in bits for the type, or else return
+ BITS_PER_WORD if the node actually turns out to be an
+ ERROR_MARK node. */
+
+static inline unsigned
+simple_type_align_in_bits (type)
+ register tree type;
+{
+ return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
+}
+
+/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
+ node, return the size in bits for the type if it is a constant, or else
+ return the alignment for the type if the type's size is not constant, or
+ else return BITS_PER_WORD if the type actually turns out to be an
+ ERROR_MARK node. */
+
+static inline unsigned
+simple_type_size_in_bits (type)
+ register tree type;
+{
+ if (TREE_CODE (type) == ERROR_MARK)
+ return BITS_PER_WORD;
+ else
+ {
+ register tree type_size_tree = TYPE_SIZE (type);
+
+ if (TREE_CODE (type_size_tree) != INTEGER_CST)
+ return TYPE_ALIGN (type);
+
+ return (unsigned) TREE_INT_CST_LOW (type_size_tree);
+ }
+}
+
+/* Given a pointer to what is assumed to be a FIELD_DECL node, compute and
+ return the byte offset of the lowest addressed byte of the "containing
+ object" for the given FIELD_DECL, or return 0 if we are unable to
+ determine what that offset is, either because the argument turns out to
+ be a pointer to an ERROR_MARK node, or because the offset is actually
+ variable. (We can't handle the latter case just yet). */
+
+static unsigned
+field_byte_offset (decl)
+ register tree decl;
+{
+ register unsigned type_align_in_bytes;
+ register unsigned type_align_in_bits;
+ register unsigned type_size_in_bits;
+ register unsigned object_offset_in_align_units;
+ register unsigned object_offset_in_bits;
+ register unsigned object_offset_in_bytes;
+ register tree type;
+ register tree bitpos_tree;
+ register tree field_size_tree;
+ register unsigned bitpos_int;
+ register unsigned deepest_bitpos;
+ register unsigned field_size_in_bits;
+
+ if (TREE_CODE (decl) == ERROR_MARK)
+ return 0;
+
+ if (TREE_CODE (decl) != FIELD_DECL)
+ abort ();
+
+ type = field_type (decl);
+
+ bitpos_tree = DECL_FIELD_BITPOS (decl);
+ field_size_tree = DECL_SIZE (decl);
+
+ /* We cannot yet cope with fields whose positions or sizes are variable, so
+ for now, when we see such things, we simply return 0. Someday, we may
+ be able to handle such cases, but it will be damn difficult. */
+ if (TREE_CODE (bitpos_tree) != INTEGER_CST)
+ return 0;
+ bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree);
+
+ if (TREE_CODE (field_size_tree) != INTEGER_CST)
+ return 0;
+
+ field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree);
+ type_size_in_bits = simple_type_size_in_bits (type);
+ type_align_in_bits = simple_type_align_in_bits (type);
+ type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT;
+
+ /* Note that the GCC front-end doesn't make any attempt to keep track of
+ the starting bit offset (relative to the start of the containing
+ structure type) of the hypothetical "containing object" for a bit-
+ field. Thus, when computing the byte offset value for the start of the
+ "containing object" of a bit-field, we must deduce this information on
+ our own. This can be rather tricky to do in some cases. For example,
+ handling the following structure type definition when compiling for an
+ i386/i486 target (which only aligns long long's to 32-bit boundaries)
+ can be very tricky:
+
+ struct S { int field1; long long field2:31; };
+
+ Fortunately, there is a simple rule-of-thumb which can be
+ used in such cases. When compiling for an i386/i486, GCC will allocate
+ 8 bytes for the structure shown above. It decides to do this based upon
+ one simple rule for bit-field allocation. Quite simply, GCC allocates
+ each "containing object" for each bit-field at the first (i.e. lowest
+ addressed) legitimate alignment boundary (based upon the required
+ minimum alignment for the declared type of the field) which it can
+ possibly use, subject to the condition that there is still enough
+ available space remaining in the containing object (when allocated at
+ the selected point) to fully accommodate all of the bits of the
+ bit-field itself. This simple rule makes it obvious why GCC allocates
+ 8 bytes for each object of the structure type shown above. When looking
+ for a place to allocate the "containing object" for `field2', the
+ compiler simply tries to allocate a 64-bit "containing object" at each
+ successive 32-bit boundary (starting at zero) until it finds a place to
+ allocate that 64- bit field such that at least 31 contiguous (and
+ previously unallocated) bits remain within that selected 64 bit field.
+ (As it turns out, for the example above, the compiler finds that it is
+ OK to allocate the "containing object" 64-bit field at bit-offset zero
+ within the structure type.) Here we attempt to work backwards from the
+ limited set of facts we're given, and we try to deduce from those facts,
+ where GCC must have believed that the containing object started (within
+ the structure type). The value we deduce is then used (by the callers of
+ this routine) to generate DW_AT_location and DW_AT_bit_offset attributes
+ for fields (both bit-fields and, in the case of DW_AT_location, regular
+ fields as well). */
+
+ /* Figure out the bit-distance from the start of the structure to the
+ "deepest" bit of the bit-field. */
+ deepest_bitpos = bitpos_int + field_size_in_bits;
+
+ /* This is the tricky part. Use some fancy footwork to deduce where the
+ lowest addressed bit of the containing object must be. */
+ object_offset_in_bits
+ = ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits;
+
+ /* Compute the offset of the containing object in "alignment units". */
+ object_offset_in_align_units = object_offset_in_bits / type_align_in_bits;
+
+ /* Compute the offset of the containing object in bytes. */
+ object_offset_in_bytes = object_offset_in_align_units * type_align_in_bytes;
+
+ return object_offset_in_bytes;
+}
+
+/* The following routines define various Dwarf attributes and any data
+ associated with them. */
+
+/* Add a location description attribute value to a DIE.
+
+ This emits location attributes suitable for whole variables and
+ whole parameters. Note that the location attributes for struct fields are
+ generated by the routine `data_member_location_attribute' below. */
+
+static void
+add_AT_location_description (die, attr_kind, rtl)
+ dw_die_ref die;
+ enum dwarf_attribute attr_kind;
+ register rtx rtl;
+{
+ /* Handle a special case. If we are about to output a location descriptor
+ for a variable or parameter which has been optimized out of existence,
+ don't do that. A variable which has been optimized out
+ of existence will have a DECL_RTL value which denotes a pseudo-reg.
+ Currently, in some rare cases, variables can have DECL_RTL values which
+ look like (MEM (REG pseudo-reg#)). These cases are due to bugs
+ elsewhere in the compiler. We treat such cases as if the variable(s) in
+ question had been optimized out of existence. */
+
+ if (is_pseudo_reg (rtl)
+ || (GET_CODE (rtl) == MEM
+ && is_pseudo_reg (XEXP (rtl, 0)))
+ || (GET_CODE (rtl) == CONCAT
+ && is_pseudo_reg (XEXP (rtl, 0))
+ && is_pseudo_reg (XEXP (rtl, 1))))
+ return;
+
+ add_AT_loc (die, attr_kind, loc_descriptor (rtl));
+}
+
+/* Attach the specialized form of location attribute used for data
+ members of struct and union types. In the special case of a
+ FIELD_DECL node which represents a bit-field, the "offset" part
+ of this special location descriptor must indicate the distance
+ in bytes from the lowest-addressed byte of the containing struct
+ or union type to the lowest-addressed byte of the "containing
+ object" for the bit-field. (See the `field_byte_offset' function
+ above).. For any given bit-field, the "containing object" is a
+ hypothetical object (of some integral or enum type) within which
+ the given bit-field lives. The type of this hypothetical
+ "containing object" is always the same as the declared type of
+ the individual bit-field itself (for GCC anyway... the DWARF
+ spec doesn't actually mandate this). Note that it is the size
+ (in bytes) of the hypothetical "containing object" which will
+ be given in the DW_AT_byte_size attribute for this bit-field.
+ (See the `byte_size_attribute' function below.) It is also used
+ when calculating the value of the DW_AT_bit_offset attribute.
+ (See the `bit_offset_attribute' function below). */
+
+static void
+add_data_member_location_attribute (die, decl)
+ register dw_die_ref die;
+ register tree decl;
+{
+ register unsigned long offset;
+ register dw_loc_descr_ref loc_descr;
+ register enum dwarf_location_atom op;
+
+ if (TREE_CODE (decl) == TREE_VEC)
+ offset = TREE_INT_CST_LOW (BINFO_OFFSET (decl));
+ else
+ offset = field_byte_offset (decl);
+
+ /* The DWARF2 standard says that we should assume that the structure address
+ is already on the stack, so we can specify a structure field address
+ by using DW_OP_plus_uconst. */
+
+#ifdef MIPS_DEBUGGING_INFO
+ /* ??? The SGI dwarf reader does not handle the DW_OP_plus_uconst operator
+ correctly. It works only if we leave the offset on the stack. */
+ op = DW_OP_constu;
+#else
+ op = DW_OP_plus_uconst;
+#endif
+
+ loc_descr = new_loc_descr (op, offset, 0);
+ add_AT_loc (die, DW_AT_data_member_location, loc_descr);
+}
+
+/* Attach an DW_AT_const_value attribute for a variable or a parameter which
+ does not have a "location" either in memory or in a register. These
+ things can arise in GNU C when a constant is passed as an actual parameter
+ to an inlined function. They can also arise in C++ where declared
+ constants do not necessarily get memory "homes". */
+
+static void
+add_const_value_attribute (die, rtl)
+ register dw_die_ref die;
+ register rtx rtl;
+{
+ switch (GET_CODE (rtl))
+ {
+ case CONST_INT:
+ /* Note that a CONST_INT rtx could represent either an integer or a
+ floating-point constant. A CONST_INT is used whenever the constant
+ will fit into a single word. In all such cases, the original mode
+ of the constant value is wiped out, and the CONST_INT rtx is
+ assigned VOIDmode. */
+ add_AT_unsigned (die, DW_AT_const_value, (unsigned) INTVAL (rtl));
+ break;
+
+ case CONST_DOUBLE:
+ /* Note that a CONST_DOUBLE rtx could represent either an integer or a
+ floating-point constant. A CONST_DOUBLE is used whenever the
+ constant requires more than one word in order to be adequately
+ represented. We output CONST_DOUBLEs as blocks. */
+ {
+ register enum machine_mode mode = GET_MODE (rtl);
+
+ if (GET_MODE_CLASS (mode) == MODE_FLOAT)
+ {
+ register unsigned length = GET_MODE_SIZE (mode) / sizeof (long);
+ long array[4];
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, rtl);
+ switch (mode)
+ {
+ case SFmode:
+ REAL_VALUE_TO_TARGET_SINGLE (rv, array[0]);
+ break;
+
+ case DFmode:
+ REAL_VALUE_TO_TARGET_DOUBLE (rv, array);
+ break;
+
+ case XFmode:
+ case TFmode:
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, array);
+ break;
+
+ default:
+ abort ();
+ }
+
+ add_AT_float (die, DW_AT_const_value, length, array);
+ }
+ else
+ add_AT_long_long (die, DW_AT_const_value,
+ CONST_DOUBLE_HIGH (rtl), CONST_DOUBLE_LOW (rtl));
+ }
+ break;
+
+ case CONST_STRING:
+ add_AT_string (die, DW_AT_const_value, XSTR (rtl, 0));
+ break;
+
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case CONST:
+ add_AT_addr (die, DW_AT_const_value, addr_to_string (rtl));
+ break;
+
+ case PLUS:
+ /* In cases where an inlined instance of an inline function is passed
+ the address of an `auto' variable (which is local to the caller) we
+ can get a situation where the DECL_RTL of the artificial local
+ variable (for the inlining) which acts as a stand-in for the
+ corresponding formal parameter (of the inline function) will look
+ like (plus:SI (reg:SI FRAME_PTR) (const_int ...)). This is not
+ exactly a compile-time constant expression, but it isn't the address
+ of the (artificial) local variable either. Rather, it represents the
+ *value* which the artificial local variable always has during its
+ lifetime. We currently have no way to represent such quasi-constant
+ values in Dwarf, so for now we just punt and generate nothing. */
+ break;
+
+ default:
+ /* No other kinds of rtx should be possible here. */
+ abort ();
+ }
+
+}
+
+/* Generate *either* an DW_AT_location attribute or else an DW_AT_const_value
+ data attribute for a variable or a parameter. We generate the
+ DW_AT_const_value attribute only in those cases where the given variable
+ or parameter does not have a true "location" either in memory or in a
+ register. This can happen (for example) when a constant is passed as an
+ actual argument in a call to an inline function. (It's possible that
+ these things can crop up in other ways also.) Note that one type of
+ constant value which can be passed into an inlined function is a constant
+ pointer. This can happen for example if an actual argument in an inlined
+ function call evaluates to a compile-time constant address. */
+
+static void
+add_location_or_const_value_attribute (die, decl)
+ register dw_die_ref die;
+ register tree decl;
+{
+ register rtx rtl;
+ register tree declared_type;
+ register tree passed_type;
+
+ if (TREE_CODE (decl) == ERROR_MARK)
+ return;
+
+ if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != PARM_DECL)
+ abort ();
+
+ /* Here we have to decide where we are going to say the parameter "lives"
+ (as far as the debugger is concerned). We only have a couple of
+ choices. GCC provides us with DECL_RTL and with DECL_INCOMING_RTL.
+
+ DECL_RTL normally indicates where the parameter lives during most of the
+ activation of the function. If optimization is enabled however, this
+ could be either NULL or else a pseudo-reg. Both of those cases indicate
+ that the parameter doesn't really live anywhere (as far as the code
+ generation parts of GCC are concerned) during most of the function's
+ activation. That will happen (for example) if the parameter is never
+ referenced within the function.
+
+ We could just generate a location descriptor here for all non-NULL
+ non-pseudo values of DECL_RTL and ignore all of the rest, but we can be
+ a little nicer than that if we also consider DECL_INCOMING_RTL in cases
+ where DECL_RTL is NULL or is a pseudo-reg.
+
+ Note however that we can only get away with using DECL_INCOMING_RTL as
+ a backup substitute for DECL_RTL in certain limited cases. In cases
+ where DECL_ARG_TYPE (decl) indicates the same type as TREE_TYPE (decl),
+ we can be sure that the parameter was passed using the same type as it is
+ declared to have within the function, and that its DECL_INCOMING_RTL
+ points us to a place where a value of that type is passed.
+
+ In cases where DECL_ARG_TYPE (decl) and TREE_TYPE (decl) are different,
+ we cannot (in general) use DECL_INCOMING_RTL as a substitute for DECL_RTL
+ because in these cases DECL_INCOMING_RTL points us to a value of some
+ type which is *different* from the type of the parameter itself. Thus,
+ if we tried to use DECL_INCOMING_RTL to generate a location attribute in
+ such cases, the debugger would end up (for example) trying to fetch a
+ `float' from a place which actually contains the first part of a
+ `double'. That would lead to really incorrect and confusing
+ output at debug-time.
+
+ So, in general, we *do not* use DECL_INCOMING_RTL as a backup for DECL_RTL
+ in cases where DECL_ARG_TYPE (decl) != TREE_TYPE (decl). There
+ are a couple of exceptions however. On little-endian machines we can
+ get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE (decl) is
+ not the same as TREE_TYPE (decl), but only when DECL_ARG_TYPE (decl) is
+ an integral type that is smaller than TREE_TYPE (decl). These cases arise
+ when (on a little-endian machine) a non-prototyped function has a
+ parameter declared to be of type `short' or `char'. In such cases,
+ TREE_TYPE (decl) will be `short' or `char', DECL_ARG_TYPE (decl) will
+ be `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
+ passed `int' value. If the debugger then uses that address to fetch
+ a `short' or a `char' (on a little-endian machine) the result will be
+ the correct data, so we allow for such exceptional cases below.
+
+ Note that our goal here is to describe the place where the given formal
+ parameter lives during most of the function's activation (i.e. between
+ the end of the prologue and the start of the epilogue). We'll do that
+ as best as we can. Note however that if the given formal parameter is
+ modified sometime during the execution of the function, then a stack
+ backtrace (at debug-time) will show the function as having been
+ called with the *new* value rather than the value which was
+ originally passed in. This happens rarely enough that it is not
+ a major problem, but it *is* a problem, and I'd like to fix it.
+
+ A future version of dwarf2out.c may generate two additional
+ attributes for any given DW_TAG_formal_parameter DIE which will
+ describe the "passed type" and the "passed location" for the
+ given formal parameter in addition to the attributes we now
+ generate to indicate the "declared type" and the "active
+ location" for each parameter. This additional set of attributes
+ could be used by debuggers for stack backtraces. Separately, note
+ that sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL can be
+ NULL also. This happens (for example) for inlined-instances of
+ inline function formal parameters which are never referenced.
+ This really shouldn't be happening. All PARM_DECL nodes should
+ get valid non-NULL DECL_INCOMING_RTL values, but integrate.c
+ doesn't currently generate these values for inlined instances of
+ inline function parameters, so when we see such cases, we are
+ just out-of-luck for the time being (until integrate.c
+ gets fixed). */
+
+ /* Use DECL_RTL as the "location" unless we find something better. */
+ rtl = DECL_RTL (decl);
+
+ if (TREE_CODE (decl) == PARM_DECL)
+ {
+ if (rtl == NULL_RTX || is_pseudo_reg (rtl))
+ {
+ declared_type = type_main_variant (TREE_TYPE (decl));
+ passed_type = type_main_variant (DECL_ARG_TYPE (decl));
+
+ /* This decl represents a formal parameter which was optimized out.
+ Note that DECL_INCOMING_RTL may be NULL in here, but we handle
+ all* cases where (rtl == NULL_RTX) just below. */
+ if (declared_type == passed_type)
+ rtl = DECL_INCOMING_RTL (decl);
+ else if (! BYTES_BIG_ENDIAN
+ && TREE_CODE (declared_type) == INTEGER_TYPE
+ && TYPE_SIZE (declared_type) <= TYPE_SIZE (passed_type))
+ rtl = DECL_INCOMING_RTL (decl);
+ }
+ }
+
+ if (rtl == NULL_RTX)
+ return;
+
+ rtl = eliminate_regs (rtl, 0, NULL_RTX);
+#ifdef LEAF_REG_REMAP
+ if (leaf_function)
+ leaf_renumber_regs_insn (rtl);
+#endif
+
+ switch (GET_CODE (rtl))
+ {
+ case ADDRESSOF:
+ /* The address of a variable that was optimized away; don't emit
+ anything. */
+ break;
+
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CONST_STRING:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case CONST:
+ case PLUS:
+ /* DECL_RTL could be (plus (reg ...) (const_int ...)) */
+ add_const_value_attribute (die, rtl);
+ break;
+
+ case MEM:
+ case REG:
+ case SUBREG:
+ case CONCAT:
+ add_AT_location_description (die, DW_AT_location, rtl);
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+/* Generate an DW_AT_name attribute given some string value to be included as
+ the value of the attribute. */
+
+static inline void
+add_name_attribute (die, name_string)
+ register dw_die_ref die;
+ register char *name_string;
+{
+ if (name_string != NULL && *name_string != 0)
+ add_AT_string (die, DW_AT_name, name_string);
+}
+
+/* Given a tree node describing an array bound (either lower or upper) output
+ a representation for that bound. */
+
+static void
+add_bound_info (subrange_die, bound_attr, bound)
+ register dw_die_ref subrange_die;
+ register enum dwarf_attribute bound_attr;
+ register tree bound;
+{
+ register unsigned bound_value = 0;
+
+ /* If this is an Ada unconstrained array type, then don't emit any debug
+ info because the array bounds are unknown. They are parameterized when
+ the type is instantiated. */
+ if (contains_placeholder_p (bound))
+ return;
+
+ switch (TREE_CODE (bound))
+ {
+ case ERROR_MARK:
+ return;
+
+ /* All fixed-bounds are represented by INTEGER_CST nodes. */
+ case INTEGER_CST:
+ bound_value = TREE_INT_CST_LOW (bound);
+ if (bound_attr == DW_AT_lower_bound
+ && ((is_c_family () && bound_value == 0)
+ || (is_fortran () && bound_value == 1)))
+ /* use the default */;
+ else
+ add_AT_unsigned (subrange_die, bound_attr, bound_value);
+ break;
+
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ case NON_LVALUE_EXPR:
+ add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
+ break;
+
+ case SAVE_EXPR:
+ /* If optimization is turned on, the SAVE_EXPRs that describe how to
+ access the upper bound values may be bogus. If they refer to a
+ register, they may only describe how to get at these values at the
+ points in the generated code right after they have just been
+ computed. Worse yet, in the typical case, the upper bound values
+ will not even *be* computed in the optimized code (though the
+ number of elements will), so these SAVE_EXPRs are entirely
+ bogus. In order to compensate for this fact, we check here to see
+ if optimization is enabled, and if so, we don't add an attribute
+ for the (unknown and unknowable) upper bound. This should not
+ cause too much trouble for existing (stupid?) debuggers because
+ they have to deal with empty upper bounds location descriptions
+ anyway in order to be able to deal with incomplete array types.
+ Of course an intelligent debugger (GDB?) should be able to
+ comprehend that a missing upper bound specification in a array
+ type used for a storage class `auto' local array variable
+ indicates that the upper bound is both unknown (at compile- time)
+ and unknowable (at run-time) due to optimization.
+
+ We assume that a MEM rtx is safe because gcc wouldn't put the
+ value there unless it was going to be used repeatedly in the
+ function, i.e. for cleanups. */
+ if (! optimize || GET_CODE (SAVE_EXPR_RTL (bound)) == MEM)
+ {
+ register dw_die_ref ctx = lookup_decl_die (current_function_decl);
+ register dw_die_ref decl_die = new_die (DW_TAG_variable, ctx);
+ register rtx loc = SAVE_EXPR_RTL (bound);
+
+ /* If the RTL for the SAVE_EXPR is memory, handle the case where
+ it references an outer function's frame. */
+
+ if (GET_CODE (loc) == MEM)
+ {
+ rtx new_addr = fix_lexical_addr (XEXP (loc, 0), bound);
+
+ if (XEXP (loc, 0) != new_addr)
+ loc = gen_rtx (MEM, GET_MODE (loc), new_addr);
+ }
+
+ add_AT_flag (decl_die, DW_AT_artificial, 1);
+ add_type_attribute (decl_die, TREE_TYPE (bound), 1, 0, ctx);
+ add_AT_location_description (decl_die, DW_AT_location, loc);
+ add_AT_die_ref (subrange_die, bound_attr, decl_die);
+ }
+
+ /* Else leave out the attribute. */
+ break;
+
+ case MAX_EXPR:
+ case VAR_DECL:
+ case COMPONENT_REF:
+ /* ??? These types of bounds can be created by the Ada front end,
+ and it isn't clear how to emit debug info for them. */
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+/* Note that the block of subscript information for an array type also
+ includes information about the element type of type given array type. */
+
+static void
+add_subscript_info (type_die, type)
+ register dw_die_ref type_die;
+ register tree type;
+{
+#ifndef MIPS_DEBUGGING_INFO
+ register unsigned dimension_number;
+#endif
+ register tree lower, upper;
+ register dw_die_ref subrange_die;
+
+ /* The GNU compilers represent multidimensional array types as sequences of
+ one dimensional array types whose element types are themselves array
+ types. Here we squish that down, so that each multidimensional array
+ type gets only one array_type DIE in the Dwarf debugging info. The draft
+ Dwarf specification say that we are allowed to do this kind of
+ compression in C (because there is no difference between an array or
+ arrays and a multidimensional array in C) but for other source languages
+ (e.g. Ada) we probably shouldn't do this. */
+
+ /* ??? The SGI dwarf reader fails for multidimensional arrays with a
+ const enum type. E.g. const enum machine_mode insn_operand_mode[2][10].
+ We work around this by disabling this feature. See also
+ gen_array_type_die. */
+#ifndef MIPS_DEBUGGING_INFO
+ for (dimension_number = 0;
+ TREE_CODE (type) == ARRAY_TYPE;
+ type = TREE_TYPE (type), dimension_number++)
+ {
+#endif
+ register tree domain = TYPE_DOMAIN (type);
+
+ /* Arrays come in three flavors: Unspecified bounds, fixed bounds,
+ and (in GNU C only) variable bounds. Handle all three forms
+ here. */
+ subrange_die = new_die (DW_TAG_subrange_type, type_die);
+ if (domain)
+ {
+ /* We have an array type with specified bounds. */
+ lower = TYPE_MIN_VALUE (domain);
+ upper = TYPE_MAX_VALUE (domain);
+
+ /* define the index type. */
+ if (TREE_TYPE (domain))
+ {
+ /* ??? This is probably an Ada unnamed subrange type. Ignore the
+ TREE_TYPE field. We can't emit debug info for this
+ because it is an unnamed integral type. */
+ if (TREE_CODE (domain) == INTEGER_TYPE
+ && TYPE_NAME (domain) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (domain)) == INTEGER_TYPE
+ && TYPE_NAME (TREE_TYPE (domain)) == NULL_TREE)
+ ;
+ else
+ add_type_attribute (subrange_die, TREE_TYPE (domain), 0, 0,
+ type_die);
+ }
+
+ /* ??? If upper is NULL, the array has unspecified length,
+ but it does have a lower bound. This happens with Fortran
+ dimension arr(N:*)
+ Since the debugger is definitely going to need to know N
+ to produce useful results, go ahead and output the lower
+ bound solo, and hope the debugger can cope. */
+
+ add_bound_info (subrange_die, DW_AT_lower_bound, lower);
+ if (upper)
+ add_bound_info (subrange_die, DW_AT_upper_bound, upper);
+ }
+ else
+ /* We have an array type with an unspecified length. The DWARF-2
+ spec does not say how to handle this; let's just leave out the
+ bounds. */
+ {;}
+
+
+#ifndef MIPS_DEBUGGING_INFO
+ }
+#endif
+}
+
+static void
+add_byte_size_attribute (die, tree_node)
+ dw_die_ref die;
+ register tree tree_node;
+{
+ register unsigned size;
+
+ switch (TREE_CODE (tree_node))
+ {
+ case ERROR_MARK:
+ size = 0;
+ break;
+ case ENUMERAL_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ size = int_size_in_bytes (tree_node);
+ break;
+ case FIELD_DECL:
+ /* For a data member of a struct or union, the DW_AT_byte_size is
+ generally given as the number of bytes normally allocated for an
+ object of the *declared* type of the member itself. This is true
+ even for bit-fields. */
+ size = simple_type_size_in_bits (field_type (tree_node)) / BITS_PER_UNIT;
+ break;
+ default:
+ abort ();
+ }
+
+ /* Note that `size' might be -1 when we get to this point. If it is, that
+ indicates that the byte size of the entity in question is variable. We
+ have no good way of expressing this fact in Dwarf at the present time,
+ so just let the -1 pass on through. */
+
+ add_AT_unsigned (die, DW_AT_byte_size, size);
+}
+
+/* For a FIELD_DECL node which represents a bit-field, output an attribute
+ which specifies the distance in bits from the highest order bit of the
+ "containing object" for the bit-field to the highest order bit of the
+ bit-field itself.
+
+ For any given bit-field, the "containing object" is a hypothetical
+ object (of some integral or enum type) within which the given bit-field
+ lives. The type of this hypothetical "containing object" is always the
+ same as the declared type of the individual bit-field itself. The
+ determination of the exact location of the "containing object" for a
+ bit-field is rather complicated. It's handled by the
+ `field_byte_offset' function (above).
+
+ Note that it is the size (in bytes) of the hypothetical "containing object"
+ which will be given in the DW_AT_byte_size attribute for this bit-field.
+ (See `byte_size_attribute' above). */
+
+static inline void
+add_bit_offset_attribute (die, decl)
+ register dw_die_ref die;
+ register tree decl;
+{
+ register unsigned object_offset_in_bytes = field_byte_offset (decl);
+ register tree type = DECL_BIT_FIELD_TYPE (decl);
+ register tree bitpos_tree = DECL_FIELD_BITPOS (decl);
+ register unsigned bitpos_int;
+ register unsigned highest_order_object_bit_offset;
+ register unsigned highest_order_field_bit_offset;
+ register unsigned bit_offset;
+
+ /* Must be a field and a bit field. */
+ if (!type
+ || TREE_CODE (decl) != FIELD_DECL)
+ abort ();
+
+ /* We can't yet handle bit-fields whose offsets are variable, so if we
+ encounter such things, just return without generating any attribute
+ whatsoever. */
+ if (TREE_CODE (bitpos_tree) != INTEGER_CST)
+ return;
+
+ bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree);
+
+ /* Note that the bit offset is always the distance (in bits) from the
+ highest-order bit of the "containing object" to the highest-order bit of
+ the bit-field itself. Since the "high-order end" of any object or field
+ is different on big-endian and little-endian machines, the computation
+ below must take account of these differences. */
+ highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
+ highest_order_field_bit_offset = bitpos_int;
+
+ if (! BYTES_BIG_ENDIAN)
+ {
+ highest_order_field_bit_offset
+ += (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl));
+
+ highest_order_object_bit_offset += simple_type_size_in_bits (type);
+ }
+
+ bit_offset
+ = (! BYTES_BIG_ENDIAN
+ ? highest_order_object_bit_offset - highest_order_field_bit_offset
+ : highest_order_field_bit_offset - highest_order_object_bit_offset);
+
+ add_AT_unsigned (die, DW_AT_bit_offset, bit_offset);
+}
+
+/* For a FIELD_DECL node which represents a bit field, output an attribute
+ which specifies the length in bits of the given field. */
+
+static inline void
+add_bit_size_attribute (die, decl)
+ register dw_die_ref die;
+ register tree decl;
+{
+ /* Must be a field and a bit field. */
+ if (TREE_CODE (decl) != FIELD_DECL
+ || ! DECL_BIT_FIELD_TYPE (decl))
+ abort ();
+ add_AT_unsigned (die, DW_AT_bit_size,
+ (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl)));
+}
+
+/* If the compiled language is ANSI C, then add a 'prototyped'
+ attribute, if arg types are given for the parameters of a function. */
+
+static inline void
+add_prototyped_attribute (die, func_type)
+ register dw_die_ref die;
+ register tree func_type;
+{
+ if (get_AT_unsigned (comp_unit_die, DW_AT_language) == DW_LANG_C89
+ && TYPE_ARG_TYPES (func_type) != NULL)
+ add_AT_flag (die, DW_AT_prototyped, 1);
+}
+
+
+/* Add an 'abstract_origin' attribute below a given DIE. The DIE is found
+ by looking in either the type declaration or object declaration
+ equate table. */
+
+static inline void
+add_abstract_origin_attribute (die, origin)
+ register dw_die_ref die;
+ register tree origin;
+{
+ dw_die_ref origin_die = NULL;
+ if (TREE_CODE_CLASS (TREE_CODE (origin)) == 'd')
+ origin_die = lookup_decl_die (origin);
+ else if (TREE_CODE_CLASS (TREE_CODE (origin)) == 't')
+ origin_die = lookup_type_die (origin);
+
+ add_AT_die_ref (die, DW_AT_abstract_origin, origin_die);
+}
+
+/* We do not currently support the pure_virtual attribute. */
+
+static inline void
+add_pure_or_virtual_attribute (die, func_decl)
+ register dw_die_ref die;
+ register tree func_decl;
+{
+ if (DECL_VINDEX (func_decl))
+ {
+ add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
+ add_AT_loc (die, DW_AT_vtable_elem_location,
+ new_loc_descr (DW_OP_constu,
+ TREE_INT_CST_LOW (DECL_VINDEX (func_decl)),
+ 0));
+
+ /* GNU extension: Record what type this method came from originally. */
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ add_AT_die_ref (die, DW_AT_containing_type,
+ lookup_type_die (DECL_CONTEXT (func_decl)));
+ }
+}
+
+/* Add source coordinate attributes for the given decl. */
+
+static void
+add_src_coords_attributes (die, decl)
+ register dw_die_ref die;
+ register tree decl;
+{
+ register unsigned file_index = lookup_filename (DECL_SOURCE_FILE (decl));
+
+ add_AT_unsigned (die, DW_AT_decl_file, file_index);
+ add_AT_unsigned (die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
+}
+
+/* Add an DW_AT_name attribute and source coordinate attribute for the
+ given decl, but only if it actually has a name. */
+
+static void
+add_name_and_src_coords_attributes (die, decl)
+ register dw_die_ref die;
+ register tree decl;
+{
+ register tree decl_name;
+
+ decl_name = DECL_NAME (decl);
+ if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL)
+ {
+ add_name_attribute (die, dwarf2_name (decl, 0));
+ add_src_coords_attributes (die, decl);
+ if ((TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
+ && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
+ add_AT_string (die, DW_AT_MIPS_linkage_name,
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+ }
+}
+
+/* Push a new declaration scope. */
+
+static void
+push_decl_scope (scope)
+ tree scope;
+{
+ tree containing_scope;
+ int i;
+
+ /* Make room in the decl_scope_table, if necessary. */
+ if (decl_scope_table_allocated == decl_scope_depth)
+ {
+ decl_scope_table_allocated += DECL_SCOPE_TABLE_INCREMENT;
+ decl_scope_table
+ = (decl_scope_node *) xrealloc (decl_scope_table,
+ (decl_scope_table_allocated
+ * sizeof (decl_scope_node)));
+ }
+
+ decl_scope_table[decl_scope_depth].scope = scope;
+
+ /* Sometimes, while recursively emitting subtypes within a class type,
+ we end up recuring on a subtype at a higher level then the current
+ subtype. In such a case, we need to search the decl_scope_table to
+ find the parent of this subtype. */
+
+ if (TREE_CODE_CLASS (TREE_CODE (scope)) == 't')
+ containing_scope = TYPE_CONTEXT (scope);
+ else
+ containing_scope = NULL_TREE;
+
+ /* The normal case. */
+ if (decl_scope_depth == 0
+ || containing_scope == NULL_TREE
+ /* Ignore namespaces for the moment. */
+ || TREE_CODE (containing_scope) == NAMESPACE_DECL
+ || containing_scope == decl_scope_table[decl_scope_depth - 1].scope)
+ decl_scope_table[decl_scope_depth].previous = decl_scope_depth - 1;
+ else
+ {
+ /* We need to search for the containing_scope. */
+ for (i = 0; i < decl_scope_depth; i++)
+ if (decl_scope_table[i].scope == containing_scope)
+ break;
+
+ if (i == decl_scope_depth)
+ abort ();
+ else
+ decl_scope_table[decl_scope_depth].previous = i;
+ }
+
+ decl_scope_depth++;
+}
+
+/* Return the DIE for the scope that immediately contains this declaration. */
+
+static dw_die_ref
+scope_die_for (t, context_die)
+ register tree t;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref scope_die = NULL;
+ register tree containing_scope;
+ register int i;
+
+ /* Walk back up the declaration tree looking for a place to define
+ this type. */
+ if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
+ containing_scope = TYPE_CONTEXT (t);
+ else if (TREE_CODE (t) == FUNCTION_DECL && DECL_VINDEX (t))
+ containing_scope = decl_class_context (t);
+ else
+ containing_scope = DECL_CONTEXT (t);
+
+ /* Ignore namespaces for the moment. */
+ if (containing_scope && TREE_CODE (containing_scope) == NAMESPACE_DECL)
+ containing_scope = NULL_TREE;
+
+ /* Function-local tags and functions get stuck in limbo until they are
+ fixed up by decls_for_scope. */
+ if (context_die == NULL && containing_scope != NULL_TREE
+ && (TREE_CODE (t) == FUNCTION_DECL || is_tagged_type (t)))
+ return NULL;
+
+ if (containing_scope == NULL_TREE)
+ scope_die = comp_unit_die;
+ else
+ {
+ for (i = decl_scope_depth - 1, scope_die = context_die;
+ i >= 0 && decl_scope_table[i].scope != containing_scope;
+ (scope_die = scope_die->die_parent,
+ i = decl_scope_table[i].previous))
+ ;
+
+ /* ??? Integrate_decl_tree does not handle BLOCK_TYPE_TAGS, nor
+ does it try to handle types defined by TYPE_DECLs. Such types
+ thus have an incorrect TYPE_CONTEXT, which points to the block
+ they were originally defined in, instead of the current block
+ created by function inlining. We try to detect that here and
+ work around it. */
+
+ if (i < 0 && scope_die == comp_unit_die
+ && TREE_CODE (containing_scope) == BLOCK
+ && is_tagged_type (t)
+ && (block_ultimate_origin (decl_scope_table[decl_scope_depth - 1].scope)
+ == containing_scope))
+ {
+ scope_die = context_die;
+ /* Since the checks below are no longer applicable. */
+ i = 0;
+ }
+
+ if (i < 0)
+ {
+ if (scope_die != comp_unit_die
+ || TREE_CODE_CLASS (TREE_CODE (containing_scope)) != 't')
+ abort ();
+ if (debug_info_level > DINFO_LEVEL_TERSE
+ && !TREE_ASM_WRITTEN (containing_scope))
+ abort ();
+ }
+ }
+
+ return scope_die;
+}
+
+/* Pop a declaration scope. */
+static inline void
+pop_decl_scope ()
+{
+ if (decl_scope_depth <= 0)
+ abort ();
+ --decl_scope_depth;
+}
+
+/* Many forms of DIEs require a "type description" attribute. This
+ routine locates the proper "type descriptor" die for the type given
+ by 'type', and adds an DW_AT_type attribute below the given die. */
+
+static void
+add_type_attribute (object_die, type, decl_const, decl_volatile, context_die)
+ register dw_die_ref object_die;
+ register tree type;
+ register int decl_const;
+ register int decl_volatile;
+ register dw_die_ref context_die;
+{
+ register enum tree_code code = TREE_CODE (type);
+ register dw_die_ref type_die = NULL;
+
+ /* ??? If this type is an unnamed subrange type of an integral or
+ floating-point type, use the inner type. This is because we have no
+ support for unnamed types in base_type_die. This can happen if this is
+ an Ada subrange type. Correct solution is emit a subrange type die. */
+ if ((code == INTEGER_TYPE || code == REAL_TYPE)
+ && TREE_TYPE (type) != 0 && TYPE_NAME (type) == 0)
+ type = TREE_TYPE (type), code = TREE_CODE (type);
+
+ if (code == ERROR_MARK)
+ return;
+
+ /* Handle a special case. For functions whose return type is void, we
+ generate *no* type attribute. (Note that no object may have type
+ `void', so this only applies to function return types). */
+ if (code == VOID_TYPE)
+ return;
+
+ type_die = modified_type_die (type,
+ decl_const || TYPE_READONLY (type),
+ decl_volatile || TYPE_VOLATILE (type),
+ context_die);
+ if (type_die != NULL)
+ add_AT_die_ref (object_die, DW_AT_type, type_die);
+}
+
+/* Given a tree pointer to a struct, class, union, or enum type node, return
+ a pointer to the (string) tag name for the given type, or zero if the type
+ was declared without a tag. */
+
+static char *
+type_tag (type)
+ register tree type;
+{
+ register char *name = 0;
+
+ if (TYPE_NAME (type) != 0)
+ {
+ register tree t = 0;
+
+ /* Find the IDENTIFIER_NODE for the type name. */
+ if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+ t = TYPE_NAME (type);
+
+ /* The g++ front end makes the TYPE_NAME of *each* tagged type point to
+ a TYPE_DECL node, regardless of whether or not a `typedef' was
+ involved. */
+ else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && ! DECL_IGNORED_P (TYPE_NAME (type)))
+ t = DECL_NAME (TYPE_NAME (type));
+
+ /* Now get the name as a string, or invent one. */
+ if (t != 0)
+ name = IDENTIFIER_POINTER (t);
+ }
+
+ return (name == 0 || *name == '\0') ? 0 : name;
+}
+
+/* Return the type associated with a data member, make a special check
+ for bit field types. */
+
+static inline tree
+member_declared_type (member)
+ register tree member;
+{
+ return (DECL_BIT_FIELD_TYPE (member)
+ ? DECL_BIT_FIELD_TYPE (member)
+ : TREE_TYPE (member));
+}
+
+/* Get the decl's label, as described by its RTL. This may be different
+ from the DECL_NAME name used in the source file. */
+
+#if 0
+static char *
+decl_start_label (decl)
+ register tree decl;
+{
+ rtx x;
+ char *fnname;
+ x = DECL_RTL (decl);
+ if (GET_CODE (x) != MEM)
+ abort ();
+
+ x = XEXP (x, 0);
+ if (GET_CODE (x) != SYMBOL_REF)
+ abort ();
+
+ fnname = XSTR (x, 0);
+ return fnname;
+}
+#endif
+
+/* These routines generate the internal representation of the DIE's for
+ the compilation unit. Debugging information is collected by walking
+ the declaration trees passed in from dwarf2out_decl(). */
+
+static void
+gen_array_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref scope_die = scope_die_for (type, context_die);
+ register dw_die_ref array_die;
+ register tree element_type;
+
+ /* ??? The SGI dwarf reader fails for array of array of enum types unless
+ the inner array type comes before the outer array type. Thus we must
+ call gen_type_die before we call new_die. See below also. */
+#ifdef MIPS_DEBUGGING_INFO
+ gen_type_die (TREE_TYPE (type), context_die);
+#endif
+
+ array_die = new_die (DW_TAG_array_type, scope_die);
+
+#if 0
+ /* We default the array ordering. SDB will probably do
+ the right things even if DW_AT_ordering is not present. It's not even
+ an issue until we start to get into multidimensional arrays anyway. If
+ SDB is ever caught doing the Wrong Thing for multi-dimensional arrays,
+ then we'll have to put the DW_AT_ordering attribute back in. (But if
+ and when we find out that we need to put these in, we will only do so
+ for multidimensional arrays. */
+ add_AT_unsigned (array_die, DW_AT_ordering, DW_ORD_row_major);
+#endif
+
+#ifdef MIPS_DEBUGGING_INFO
+ /* The SGI compilers handle arrays of unknown bound by setting
+ AT_declaration and not emitting any subrange DIEs. */
+ if (! TYPE_DOMAIN (type))
+ add_AT_unsigned (array_die, DW_AT_declaration, 1);
+ else
+#endif
+ add_subscript_info (array_die, type);
+
+ equate_type_number_to_die (type, array_die);
+
+ /* Add representation of the type of the elements of this array type. */
+ element_type = TREE_TYPE (type);
+
+ /* ??? The SGI dwarf reader fails for multidimensional arrays with a
+ const enum type. E.g. const enum machine_mode insn_operand_mode[2][10].
+ We work around this by disabling this feature. See also
+ add_subscript_info. */
+#ifndef MIPS_DEBUGGING_INFO
+ while (TREE_CODE (element_type) == ARRAY_TYPE)
+ element_type = TREE_TYPE (element_type);
+
+ gen_type_die (element_type, context_die);
+#endif
+
+ add_type_attribute (array_die, element_type, 0, 0, context_die);
+}
+
+static void
+gen_set_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref type_die
+ = new_die (DW_TAG_set_type, scope_die_for (type, context_die));
+
+ equate_type_number_to_die (type, type_die);
+ add_type_attribute (type_die, TREE_TYPE (type), 0, 0, context_die);
+}
+
+#if 0
+static void
+gen_entry_point_die (decl, context_die)
+ register tree decl;
+ register dw_die_ref context_die;
+{
+ register tree origin = decl_ultimate_origin (decl);
+ register dw_die_ref decl_die = new_die (DW_TAG_entry_point, context_die);
+ if (origin != NULL)
+ add_abstract_origin_attribute (decl_die, origin);
+ else
+ {
+ add_name_and_src_coords_attributes (decl_die, decl);
+ add_type_attribute (decl_die, TREE_TYPE (TREE_TYPE (decl)),
+ 0, 0, context_die);
+ }
+
+ if (DECL_ABSTRACT (decl))
+ equate_decl_number_to_die (decl, decl_die);
+ else
+ add_AT_lbl_id (decl_die, DW_AT_low_pc, decl_start_label (decl));
+}
+#endif
+
+/* Remember a type in the pending_types_list. */
+
+static void
+pend_type (type)
+ register tree type;
+{
+ if (pending_types == pending_types_allocated)
+ {
+ pending_types_allocated += PENDING_TYPES_INCREMENT;
+ pending_types_list
+ = (tree *) xrealloc (pending_types_list,
+ sizeof (tree) * pending_types_allocated);
+ }
+
+ pending_types_list[pending_types++] = type;
+}
+
+/* Output any pending types (from the pending_types list) which we can output
+ now (taking into account the scope that we are working on now).
+
+ For each type output, remove the given type from the pending_types_list
+ *before* we try to output it. */
+
+static void
+output_pending_types_for_scope (context_die)
+ register dw_die_ref context_die;
+{
+ register tree type;
+
+ while (pending_types)
+ {
+ --pending_types;
+ type = pending_types_list[pending_types];
+ gen_type_die (type, context_die);
+ if (!TREE_ASM_WRITTEN (type))
+ abort ();
+ }
+}
+
+/* Generate a DIE to represent an inlined instance of an enumeration type. */
+
+static void
+gen_inlined_enumeration_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref type_die = new_die (DW_TAG_enumeration_type,
+ scope_die_for (type, context_die));
+
+ if (!TREE_ASM_WRITTEN (type))
+ abort ();
+ add_abstract_origin_attribute (type_die, type);
+}
+
+/* Generate a DIE to represent an inlined instance of a structure type. */
+
+static void
+gen_inlined_structure_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref type_die = new_die (DW_TAG_structure_type,
+ scope_die_for (type, context_die));
+
+ if (!TREE_ASM_WRITTEN (type))
+ abort ();
+ add_abstract_origin_attribute (type_die, type);
+}
+
+/* Generate a DIE to represent an inlined instance of a union type. */
+
+static void
+gen_inlined_union_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref type_die = new_die (DW_TAG_union_type,
+ scope_die_for (type, context_die));
+
+ if (!TREE_ASM_WRITTEN (type))
+ abort ();
+ add_abstract_origin_attribute (type_die, type);
+}
+
+/* Generate a DIE to represent an enumeration type. Note that these DIEs
+ include all of the information about the enumeration values also. Each
+ enumerated type name/value is listed as a child of the enumerated type
+ DIE. */
+
+static void
+gen_enumeration_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref type_die = lookup_type_die (type);
+
+ if (type_die == NULL)
+ {
+ type_die = new_die (DW_TAG_enumeration_type,
+ scope_die_for (type, context_die));
+ equate_type_number_to_die (type, type_die);
+ add_name_attribute (type_die, type_tag (type));
+ }
+ else if (! TYPE_SIZE (type))
+ return;
+ else
+ remove_AT (type_die, DW_AT_declaration);
+
+ /* Handle a GNU C/C++ extension, i.e. incomplete enum types. If the
+ given enum type is incomplete, do not generate the DW_AT_byte_size
+ attribute or the DW_AT_element_list attribute. */
+ if (TYPE_SIZE (type))
+ {
+ register tree link;
+
+ TREE_ASM_WRITTEN (type) = 1;
+ add_byte_size_attribute (type_die, type);
+ if (TYPE_STUB_DECL (type) != NULL_TREE)
+ add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
+
+ /* If the first reference to this type was as the return type of an
+ inline function, then it may not have a parent. Fix this now. */
+ if (type_die->die_parent == NULL)
+ add_child_die (scope_die_for (type, context_die), type_die);
+
+ for (link = TYPE_FIELDS (type);
+ link != NULL; link = TREE_CHAIN (link))
+ {
+ register dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die);
+
+ add_name_attribute (enum_die,
+ IDENTIFIER_POINTER (TREE_PURPOSE (link)));
+ add_AT_unsigned (enum_die, DW_AT_const_value,
+ (unsigned) TREE_INT_CST_LOW (TREE_VALUE (link)));
+ }
+ }
+ else
+ add_AT_flag (type_die, DW_AT_declaration, 1);
+}
+
+
+/* Generate a DIE to represent either a real live formal parameter decl or to
+ represent just the type of some formal parameter position in some function
+ type.
+
+ Note that this routine is a bit unusual because its argument may be a
+ ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which
+ represents an inlining of some PARM_DECL) or else some sort of a ..._TYPE
+ node. If it's the former then this function is being called to output a
+ DIE to represent a formal parameter object (or some inlining thereof). If
+ it's the latter, then this function is only being called to output a
+ DW_TAG_formal_parameter DIE to stand as a placeholder for some formal
+ argument type of some subprogram type. */
+
+static dw_die_ref
+gen_formal_parameter_die (node, context_die)
+ register tree node;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref parm_die
+ = new_die (DW_TAG_formal_parameter, context_die);
+ register tree origin;
+
+ switch (TREE_CODE_CLASS (TREE_CODE (node)))
+ {
+ case 'd':
+ origin = decl_ultimate_origin (node);
+ if (origin != NULL)
+ add_abstract_origin_attribute (parm_die, origin);
+ else
+ {
+ add_name_and_src_coords_attributes (parm_die, node);
+ add_type_attribute (parm_die, TREE_TYPE (node),
+ TREE_READONLY (node),
+ TREE_THIS_VOLATILE (node),
+ context_die);
+ if (DECL_ARTIFICIAL (node))
+ add_AT_flag (parm_die, DW_AT_artificial, 1);
+ }
+
+ equate_decl_number_to_die (node, parm_die);
+ if (! DECL_ABSTRACT (node))
+ add_location_or_const_value_attribute (parm_die, node);
+
+ break;
+
+ case 't':
+ /* We were called with some kind of a ..._TYPE node. */
+ add_type_attribute (parm_die, node, 0, 0, context_die);
+ break;
+
+ default:
+ abort ();
+ }
+
+ return parm_die;
+}
+
+/* Generate a special type of DIE used as a stand-in for a trailing ellipsis
+ at the end of an (ANSI prototyped) formal parameters list. */
+
+static void
+gen_unspecified_parameters_die (decl_or_type, context_die)
+ register tree decl_or_type;
+ register dw_die_ref context_die;
+{
+ new_die (DW_TAG_unspecified_parameters, context_die);
+}
+
+/* Generate a list of nameless DW_TAG_formal_parameter DIEs (and perhaps a
+ DW_TAG_unspecified_parameters DIE) to represent the types of the formal
+ parameters as specified in some function type specification (except for
+ those which appear as part of a function *definition*).
+
+ Note we must be careful here to output all of the parameter DIEs before*
+ we output any DIEs needed to represent the types of the formal parameters.
+ This keeps svr4 SDB happy because it (incorrectly) thinks that the first
+ non-parameter DIE it sees ends the formal parameter list. */
+
+static void
+gen_formal_types_die (function_or_method_type, context_die)
+ register tree function_or_method_type;
+ register dw_die_ref context_die;
+{
+ register tree link;
+ register tree formal_type = NULL;
+ register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
+
+#if 0
+ /* In the case where we are generating a formal types list for a C++
+ non-static member function type, skip over the first thing on the
+ TYPE_ARG_TYPES list because it only represents the type of the hidden
+ `this pointer'. The debugger should be able to figure out (without
+ being explicitly told) that this non-static member function type takes a
+ `this pointer' and should be able to figure what the type of that hidden
+ parameter is from the DW_AT_member attribute of the parent
+ DW_TAG_subroutine_type DIE. */
+ if (TREE_CODE (function_or_method_type) == METHOD_TYPE)
+ first_parm_type = TREE_CHAIN (first_parm_type);
+#endif
+
+ /* Make our first pass over the list of formal parameter types and output a
+ DW_TAG_formal_parameter DIE for each one. */
+ for (link = first_parm_type; link; link = TREE_CHAIN (link))
+ {
+ register dw_die_ref parm_die;
+
+ formal_type = TREE_VALUE (link);
+ if (formal_type == void_type_node)
+ break;
+
+ /* Output a (nameless) DIE to represent the formal parameter itself. */
+ parm_die = gen_formal_parameter_die (formal_type, context_die);
+ if (TREE_CODE (function_or_method_type) == METHOD_TYPE
+ && link == first_parm_type)
+ add_AT_flag (parm_die, DW_AT_artificial, 1);
+ }
+
+ /* If this function type has an ellipsis, add a
+ DW_TAG_unspecified_parameters DIE to the end of the parameter list. */
+ if (formal_type != void_type_node)
+ gen_unspecified_parameters_die (function_or_method_type, context_die);
+
+ /* Make our second (and final) pass over the list of formal parameter types
+ and output DIEs to represent those types (as necessary). */
+ for (link = TYPE_ARG_TYPES (function_or_method_type);
+ link;
+ link = TREE_CHAIN (link))
+ {
+ formal_type = TREE_VALUE (link);
+ if (formal_type == void_type_node)
+ break;
+
+ gen_type_die (formal_type, context_die);
+ }
+}
+
+/* Generate a DIE to represent a declared function (either file-scope or
+ block-local). */
+
+static void
+gen_subprogram_die (decl, context_die)
+ register tree decl;
+ register dw_die_ref context_die;
+{
+ char label_id[MAX_ARTIFICIAL_LABEL_BYTES];
+ register tree origin = decl_ultimate_origin (decl);
+ register dw_die_ref subr_die;
+ register rtx fp_reg;
+ register tree fn_arg_types;
+ register tree outer_scope;
+ register dw_die_ref old_die = lookup_decl_die (decl);
+ register int declaration
+ = (current_function_decl != decl
+ || (context_die
+ && (context_die->die_tag == DW_TAG_structure_type
+ || context_die->die_tag == DW_TAG_union_type)));
+
+ if (origin != NULL)
+ {
+ subr_die = new_die (DW_TAG_subprogram, context_die);
+ add_abstract_origin_attribute (subr_die, origin);
+ }
+ else if (old_die && DECL_ABSTRACT (decl)
+ && get_AT_unsigned (old_die, DW_AT_inline))
+ {
+ /* This must be a redefinition of an extern inline function.
+ We can just reuse the old die here. */
+ subr_die = old_die;
+
+ /* Clear out the inlined attribute and parm types. */
+ remove_AT (subr_die, DW_AT_inline);
+ remove_children (subr_die);
+ }
+ else if (old_die)
+ {
+ register unsigned file_index
+ = lookup_filename (DECL_SOURCE_FILE (decl));
+
+ if (get_AT_flag (old_die, DW_AT_declaration) != 1)
+ abort ();
+
+ /* If the definition comes from the same place as the declaration,
+ maybe use the old DIE. We always want the DIE for this function
+ that has the *_pc attributes to be under comp_unit_die so the
+ debugger can find it. For inlines, that is the concrete instance,
+ so we can use the old DIE here. For non-inline methods, we want a
+ specification DIE at toplevel, so we need a new DIE. For local
+ class methods, this does not apply. */
+ if ((DECL_ABSTRACT (decl) || old_die->die_parent == comp_unit_die
+ || context_die == NULL)
+ && get_AT_unsigned (old_die, DW_AT_decl_file) == file_index
+ && (get_AT_unsigned (old_die, DW_AT_decl_line)
+ == DECL_SOURCE_LINE (decl)))
+ {
+ subr_die = old_die;
+
+ /* Clear out the declaration attribute and the parm types. */
+ remove_AT (subr_die, DW_AT_declaration);
+ remove_children (subr_die);
+ }
+ else
+ {
+ subr_die = new_die (DW_TAG_subprogram, context_die);
+ add_AT_die_ref (subr_die, DW_AT_specification, old_die);
+ if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
+ add_AT_unsigned (subr_die, DW_AT_decl_file, file_index);
+ if (get_AT_unsigned (old_die, DW_AT_decl_line)
+ != DECL_SOURCE_LINE (decl))
+ add_AT_unsigned
+ (subr_die, DW_AT_decl_line, DECL_SOURCE_LINE (decl));
+ }
+ }
+ else
+ {
+ register dw_die_ref scope_die;
+
+ if (DECL_CONTEXT (decl))
+ scope_die = scope_die_for (decl, context_die);
+ else
+ /* Don't put block extern declarations under comp_unit_die. */
+ scope_die = context_die;
+
+ subr_die = new_die (DW_TAG_subprogram, scope_die);
+
+ if (TREE_PUBLIC (decl))
+ add_AT_flag (subr_die, DW_AT_external, 1);
+
+ add_name_and_src_coords_attributes (subr_die, decl);
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ {
+ register tree type = TREE_TYPE (decl);
+
+ add_prototyped_attribute (subr_die, type);
+ add_type_attribute (subr_die, TREE_TYPE (type), 0, 0, context_die);
+ }
+
+ add_pure_or_virtual_attribute (subr_die, decl);
+ if (DECL_ARTIFICIAL (decl))
+ add_AT_flag (subr_die, DW_AT_artificial, 1);
+ if (TREE_PROTECTED (decl))
+ add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_protected);
+ else if (TREE_PRIVATE (decl))
+ add_AT_unsigned (subr_die, DW_AT_accessibility, DW_ACCESS_private);
+ }
+
+ if (declaration)
+ {
+ add_AT_flag (subr_die, DW_AT_declaration, 1);
+
+ /* The first time we see a member function, it is in the context of
+ the class to which it belongs. We make sure of this by emitting
+ the class first. The next time is the definition, which is
+ handled above. The two may come from the same source text. */
+ if (DECL_CONTEXT (decl))
+ equate_decl_number_to_die (decl, subr_die);
+ }
+ else if (DECL_ABSTRACT (decl))
+ {
+ /* ??? Checking DECL_DEFER_OUTPUT is correct for static inline functions,
+ but not for extern inline functions. We can't get this completely
+ correct because information about whether the function was declared
+ inline is not saved anywhere. */
+ if (DECL_DEFER_OUTPUT (decl))
+ {
+ if (DECL_INLINE (decl))
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
+ else
+ add_AT_unsigned (subr_die, DW_AT_inline,
+ DW_INL_declared_not_inlined);
+ }
+ else if (DECL_INLINE (decl))
+ add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
+ else
+ abort ();
+
+ equate_decl_number_to_die (decl, subr_die);
+ }
+ else if (!DECL_EXTERNAL (decl))
+ {
+ if (origin == NULL_TREE)
+ equate_decl_number_to_die (decl, subr_die);
+
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_BEGIN_LABEL,
+ current_funcdef_number);
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, label_id);
+ ASM_GENERATE_INTERNAL_LABEL (label_id, FUNC_END_LABEL,
+ current_funcdef_number);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, label_id);
+
+ add_pubname (decl, subr_die);
+ add_arange (decl, subr_die);
+
+#ifdef MIPS_DEBUGGING_INFO
+ /* Add a reference to the FDE for this routine. */
+ add_AT_fde_ref (subr_die, DW_AT_MIPS_fde, current_funcdef_fde);
+#endif
+
+ /* Define the "frame base" location for this routine. We use the
+ frame pointer or stack pointer registers, since the RTL for local
+ variables is relative to one of them. */
+ fp_reg
+ = frame_pointer_needed ? hard_frame_pointer_rtx : stack_pointer_rtx;
+ add_AT_loc (subr_die, DW_AT_frame_base, reg_loc_descriptor (fp_reg));
+
+#if 0
+ /* ??? This fails for nested inline functions, because context_display
+ is not part of the state saved/restored for inline functions. */
+ if (current_function_needs_context)
+ add_AT_location_description (subr_die, DW_AT_static_link,
+ lookup_static_chain (decl));
+#endif
+ }
+
+ /* Now output descriptions of the arguments for this function. This gets
+ (unnecessarily?) complex because of the fact that the DECL_ARGUMENT list
+ for a FUNCTION_DECL doesn't indicate cases where there was a trailing
+ `...' at the end of the formal parameter list. In order to find out if
+ there was a trailing ellipsis or not, we must instead look at the type
+ associated with the FUNCTION_DECL. This will be a node of type
+ FUNCTION_TYPE. If the chain of type nodes hanging off of this
+ FUNCTION_TYPE node ends with a void_type_node then there should *not* be
+ an ellipsis at the end. */
+ push_decl_scope (decl);
+
+ /* In the case where we are describing a mere function declaration, all we
+ need to do here (and all we *can* do here) is to describe the *types* of
+ its formal parameters. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ ;
+ else if (declaration)
+ gen_formal_types_die (TREE_TYPE (decl), subr_die);
+ else
+ {
+ /* Generate DIEs to represent all known formal parameters */
+ register tree arg_decls = DECL_ARGUMENTS (decl);
+ register tree parm;
+
+ /* When generating DIEs, generate the unspecified_parameters DIE
+ instead if we come across the arg "__builtin_va_alist" */
+ for (parm = arg_decls; parm; parm = TREE_CHAIN (parm))
+ if (TREE_CODE (parm) == PARM_DECL)
+ {
+ if (DECL_NAME (parm)
+ && !strcmp (IDENTIFIER_POINTER (DECL_NAME (parm)),
+ "__builtin_va_alist"))
+ gen_unspecified_parameters_die (parm, subr_die);
+ else
+ gen_decl_die (parm, subr_die);
+ }
+
+ /* Decide whether we need a unspecified_parameters DIE at the end.
+ There are 2 more cases to do this for: 1) the ansi ... declaration -
+ this is detectable when the end of the arg list is not a
+ void_type_node 2) an unprototyped function declaration (not a
+ definition). This just means that we have no info about the
+ parameters at all. */
+ fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
+ if (fn_arg_types != NULL)
+ {
+ /* this is the prototyped case, check for ... */
+ if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node)
+ gen_unspecified_parameters_die (decl, subr_die);
+ }
+ else if (DECL_INITIAL (decl) == NULL_TREE)
+ gen_unspecified_parameters_die (decl, subr_die);
+ }
+
+ /* Output Dwarf info for all of the stuff within the body of the function
+ (if it has one - it may be just a declaration). */
+ outer_scope = DECL_INITIAL (decl);
+
+ /* Note that here, `outer_scope' is a pointer to the outermost BLOCK
+ node created to represent a function. This outermost BLOCK actually
+ represents the outermost binding contour for the function, i.e. the
+ contour in which the function's formal parameters and labels get
+ declared. Curiously, it appears that the front end doesn't actually
+ put the PARM_DECL nodes for the current function onto the BLOCK_VARS
+ list for this outer scope. (They are strung off of the DECL_ARGUMENTS
+ list for the function instead.) The BLOCK_VARS list for the
+ `outer_scope' does provide us with a list of the LABEL_DECL nodes for
+ the function however, and we output DWARF info for those in
+ decls_for_scope. Just within the `outer_scope' there will be a BLOCK
+ node representing the function's outermost pair of curly braces, and
+ any blocks used for the base and member initializers of a C++
+ constructor function. */
+ if (! declaration && TREE_CODE (outer_scope) != ERROR_MARK)
+ {
+ current_function_has_inlines = 0;
+ decls_for_scope (outer_scope, subr_die, 0);
+
+#if 0 && defined (MIPS_DEBUGGING_INFO)
+ if (current_function_has_inlines)
+ {
+ add_AT_flag (subr_die, DW_AT_MIPS_has_inlines, 1);
+ if (! comp_unit_has_inlines)
+ {
+ add_AT_flag (comp_unit_die, DW_AT_MIPS_has_inlines, 1);
+ comp_unit_has_inlines = 1;
+ }
+ }
+#endif
+ }
+
+ pop_decl_scope ();
+}
+
+/* Generate a DIE to represent a declared data object. */
+
+static void
+gen_variable_die (decl, context_die)
+ register tree decl;
+ register dw_die_ref context_die;
+{
+ register tree origin = decl_ultimate_origin (decl);
+ register dw_die_ref var_die = new_die (DW_TAG_variable, context_die);
+
+ dw_die_ref old_die = lookup_decl_die (decl);
+ int declaration
+ = (DECL_EXTERNAL (decl)
+ || current_function_decl != decl_function_context (decl)
+ || context_die->die_tag == DW_TAG_structure_type
+ || context_die->die_tag == DW_TAG_union_type);
+
+ if (origin != NULL)
+ add_abstract_origin_attribute (var_die, origin);
+ /* Loop unrolling can create multiple blocks that refer to the same
+ static variable, so we must test for the DW_AT_declaration flag. */
+ /* ??? Loop unrolling/reorder_blocks should perhaps be rewritten to
+ copy decls and set the DECL_ABSTRACT flag on them instead of
+ sharing them. */
+ else if (old_die && TREE_STATIC (decl)
+ && get_AT_flag (old_die, DW_AT_declaration) == 1)
+ {
+ /* ??? This is an instantiation of a C++ class level static. */
+ add_AT_die_ref (var_die, DW_AT_specification, old_die);
+ if (DECL_NAME (decl))
+ {
+ register unsigned file_index
+ = lookup_filename (DECL_SOURCE_FILE (decl));
+
+ if (get_AT_unsigned (old_die, DW_AT_decl_file) != file_index)
+ add_AT_unsigned (var_die, DW_AT_decl_file, file_index);
+
+ if (get_AT_unsigned (old_die, DW_AT_decl_line)
+ != DECL_SOURCE_LINE (decl))
+
+ add_AT_unsigned (var_die, DW_AT_decl_line,
+ DECL_SOURCE_LINE (decl));
+ }
+ }
+ else
+ {
+ add_name_and_src_coords_attributes (var_die, decl);
+ add_type_attribute (var_die, TREE_TYPE (decl),
+ TREE_READONLY (decl),
+ TREE_THIS_VOLATILE (decl), context_die);
+
+ if (TREE_PUBLIC (decl))
+ add_AT_flag (var_die, DW_AT_external, 1);
+
+ if (DECL_ARTIFICIAL (decl))
+ add_AT_flag (var_die, DW_AT_artificial, 1);
+
+ if (TREE_PROTECTED (decl))
+ add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_protected);
+
+ else if (TREE_PRIVATE (decl))
+ add_AT_unsigned (var_die, DW_AT_accessibility, DW_ACCESS_private);
+ }
+
+ if (declaration)
+ add_AT_flag (var_die, DW_AT_declaration, 1);
+
+ if ((declaration && decl_class_context (decl)) || DECL_ABSTRACT (decl))
+ equate_decl_number_to_die (decl, var_die);
+
+ if (! declaration && ! DECL_ABSTRACT (decl))
+ {
+ equate_decl_number_to_die (decl, var_die);
+ add_location_or_const_value_attribute (var_die, decl);
+ add_pubname (decl, var_die);
+ }
+}
+
+/* Generate a DIE to represent a label identifier. */
+
+static void
+gen_label_die (decl, context_die)
+ register tree decl;
+ register dw_die_ref context_die;
+{
+ register tree origin = decl_ultimate_origin (decl);
+ register dw_die_ref lbl_die = new_die (DW_TAG_label, context_die);
+ register rtx insn;
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ char label2[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ if (origin != NULL)
+ add_abstract_origin_attribute (lbl_die, origin);
+ else
+ add_name_and_src_coords_attributes (lbl_die, decl);
+
+ if (DECL_ABSTRACT (decl))
+ equate_decl_number_to_die (decl, lbl_die);
+ else
+ {
+ insn = DECL_RTL (decl);
+ if (GET_CODE (insn) == CODE_LABEL)
+ {
+ /* When optimization is enabled (via -O) some parts of the compiler
+ (e.g. jump.c and cse.c) may try to delete CODE_LABEL insns which
+ represent source-level labels which were explicitly declared by
+ the user. This really shouldn't be happening though, so catch
+ it if it ever does happen. */
+ if (INSN_DELETED_P (insn))
+ abort ();
+
+ sprintf (label2, INSN_LABEL_FMT, current_funcdef_number);
+ ASM_GENERATE_INTERNAL_LABEL (label, label2,
+ (unsigned) INSN_UID (insn));
+ add_AT_lbl_id (lbl_die, DW_AT_low_pc, label);
+ }
+ }
+}
+
+/* Generate a DIE for a lexical block. */
+
+static void
+gen_lexical_block_die (stmt, context_die, depth)
+ register tree stmt;
+ register dw_die_ref context_die;
+ int depth;
+{
+ register dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die);
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ if (! BLOCK_ABSTRACT (stmt))
+ {
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+ next_block_number);
+ add_AT_lbl_id (stmt_die, DW_AT_low_pc, label);
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number);
+ add_AT_lbl_id (stmt_die, DW_AT_high_pc, label);
+ }
+
+ push_decl_scope (stmt);
+ decls_for_scope (stmt, stmt_die, depth);
+ pop_decl_scope ();
+}
+
+/* Generate a DIE for an inlined subprogram. */
+
+static void
+gen_inlined_subroutine_die (stmt, context_die, depth)
+ register tree stmt;
+ register dw_die_ref context_die;
+ int depth;
+{
+ if (! BLOCK_ABSTRACT (stmt))
+ {
+ register dw_die_ref subr_die
+ = new_die (DW_TAG_inlined_subroutine, context_die);
+ register tree decl = block_ultimate_origin (stmt);
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ add_abstract_origin_attribute (subr_die, decl);
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
+ next_block_number);
+ add_AT_lbl_id (subr_die, DW_AT_low_pc, label);
+ ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_END_LABEL, next_block_number);
+ add_AT_lbl_id (subr_die, DW_AT_high_pc, label);
+ push_decl_scope (decl);
+ decls_for_scope (stmt, subr_die, depth);
+ pop_decl_scope ();
+ current_function_has_inlines = 1;
+ }
+}
+
+/* Generate a DIE for a field in a record, or structure. */
+
+static void
+gen_field_die (decl, context_die)
+ register tree decl;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref decl_die = new_die (DW_TAG_member, context_die);
+
+ add_name_and_src_coords_attributes (decl_die, decl);
+ add_type_attribute (decl_die, member_declared_type (decl),
+ TREE_READONLY (decl), TREE_THIS_VOLATILE (decl),
+ context_die);
+
+ /* If this is a bit field... */
+ if (DECL_BIT_FIELD_TYPE (decl))
+ {
+ add_byte_size_attribute (decl_die, decl);
+ add_bit_size_attribute (decl_die, decl);
+ add_bit_offset_attribute (decl_die, decl);
+ }
+
+ if (TREE_CODE (DECL_FIELD_CONTEXT (decl)) != UNION_TYPE)
+ add_data_member_location_attribute (decl_die, decl);
+
+ if (DECL_ARTIFICIAL (decl))
+ add_AT_flag (decl_die, DW_AT_artificial, 1);
+
+ if (TREE_PROTECTED (decl))
+ add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_protected);
+
+ else if (TREE_PRIVATE (decl))
+ add_AT_unsigned (decl_die, DW_AT_accessibility, DW_ACCESS_private);
+}
+
+#if 0
+/* Don't generate either pointer_type DIEs or reference_type DIEs here.
+ Use modified_type_die instead.
+ We keep this code here just in case these types of DIEs may be needed to
+ represent certain things in other languages (e.g. Pascal) someday. */
+static void
+gen_pointer_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref ptr_die
+ = new_die (DW_TAG_pointer_type, scope_die_for (type, context_die));
+
+ equate_type_number_to_die (type, ptr_die);
+ add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+}
+
+/* Don't generate either pointer_type DIEs or reference_type DIEs here.
+ Use modified_type_die instead.
+ We keep this code here just in case these types of DIEs may be needed to
+ represent certain things in other languages (e.g. Pascal) someday. */
+static void
+gen_reference_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref ref_die
+ = new_die (DW_TAG_reference_type, scope_die_for (type, context_die));
+
+ equate_type_number_to_die (type, ref_die);
+ add_type_attribute (ref_die, TREE_TYPE (type), 0, 0, context_die);
+ add_AT_unsigned (mod_type_die, DW_AT_byte_size, PTR_SIZE);
+}
+#endif
+
+/* Generate a DIE for a pointer to a member type. */
+static void
+gen_ptr_to_mbr_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref ptr_die
+ = new_die (DW_TAG_ptr_to_member_type, scope_die_for (type, context_die));
+
+ equate_type_number_to_die (type, ptr_die);
+ add_AT_die_ref (ptr_die, DW_AT_containing_type,
+ lookup_type_die (TYPE_OFFSET_BASETYPE (type)));
+ add_type_attribute (ptr_die, TREE_TYPE (type), 0, 0, context_die);
+}
+
+/* Generate the DIE for the compilation unit. */
+
+static void
+gen_compile_unit_die (main_input_filename)
+ register char *main_input_filename;
+{
+ char producer[250];
+ char *wd = getpwd ();
+
+ comp_unit_die = new_die (DW_TAG_compile_unit, NULL);
+ add_name_attribute (comp_unit_die, main_input_filename);
+
+ if (wd != NULL)
+ add_AT_string (comp_unit_die, DW_AT_comp_dir, wd);
+
+ sprintf (producer, "%s %s", language_string, version_string);
+
+#ifdef MIPS_DEBUGGING_INFO
+ /* The MIPS/SGI compilers place the 'cc' command line options in the producer
+ string. The SGI debugger looks for -g, -g1, -g2, or -g3; if they do
+ not appear in the producer string, the debugger reaches the conclusion
+ that the object file is stripped and has no debugging information.
+ To get the MIPS/SGI debugger to believe that there is debugging
+ information in the object file, we add a -g to the producer string. */
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ strcat (producer, " -g");
+#endif
+
+ add_AT_string (comp_unit_die, DW_AT_producer, producer);
+
+ if (strcmp (language_string, "GNU C++") == 0)
+ add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C_plus_plus);
+
+ else if (strcmp (language_string, "GNU Ada") == 0)
+ add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Ada83);
+
+ else if (strcmp (language_string, "GNU F77") == 0)
+ add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Fortran77);
+
+ else if (strcmp (language_string, "GNU Pascal") == 0)
+ add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_Pascal83);
+
+ else if (flag_traditional)
+ add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C);
+
+ else
+ add_AT_unsigned (comp_unit_die, DW_AT_language, DW_LANG_C89);
+
+#if 0 /* unimplemented */
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ add_AT_unsigned (comp_unit_die, DW_AT_macro_info, 0);
+#endif
+}
+
+/* Generate a DIE for a string type. */
+
+static void
+gen_string_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref type_die
+ = new_die (DW_TAG_string_type, scope_die_for (type, context_die));
+
+ equate_type_number_to_die (type, type_die);
+
+ /* Fudge the string length attribute for now. */
+
+ /* TODO: add string length info.
+ string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
+ bound_representation (upper_bound, 0, 'u'); */
+}
+
+/* Generate the DIE for a base class. */
+
+static void
+gen_inheritance_die (binfo, context_die)
+ register tree binfo;
+ register dw_die_ref context_die;
+{
+ dw_die_ref die = new_die (DW_TAG_inheritance, context_die);
+
+ add_type_attribute (die, BINFO_TYPE (binfo), 0, 0, context_die);
+ add_data_member_location_attribute (die, binfo);
+
+ if (TREE_VIA_VIRTUAL (binfo))
+ add_AT_unsigned (die, DW_AT_virtuality, DW_VIRTUALITY_virtual);
+ if (TREE_VIA_PUBLIC (binfo))
+ add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_public);
+ else if (TREE_VIA_PROTECTED (binfo))
+ add_AT_unsigned (die, DW_AT_accessibility, DW_ACCESS_protected);
+}
+
+/* Generate a DIE for a class member. */
+
+static void
+gen_member_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register tree member;
+
+ /* If this is not an incomplete type, output descriptions of each of its
+ members. Note that as we output the DIEs necessary to represent the
+ members of this record or union type, we will also be trying to output
+ DIEs to represent the *types* of those members. However the `type'
+ function (above) will specifically avoid generating type DIEs for member
+ types *within* the list of member DIEs for this (containing) type execpt
+ for those types (of members) which are explicitly marked as also being
+ members of this (containing) type themselves. The g++ front- end can
+ force any given type to be treated as a member of some other
+ (containing) type by setting the TYPE_CONTEXT of the given (member) type
+ to point to the TREE node representing the appropriate (containing)
+ type. */
+
+ /* First output info about the base classes. */
+ if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type))
+ {
+ register tree bases = TYPE_BINFO_BASETYPES (type);
+ register int n_bases = TREE_VEC_LENGTH (bases);
+ register int i;
+
+ for (i = 0; i < n_bases; i++)
+ gen_inheritance_die (TREE_VEC_ELT (bases, i), context_die);
+ }
+
+ /* Now output info about the data members and type members. */
+ for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
+ gen_decl_die (member, context_die);
+
+ /* Now output info about the function members (if any). */
+ for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member))
+ gen_decl_die (member, context_die);
+}
+
+/* Generate a DIE for a structure or union type. */
+
+static void
+gen_struct_or_union_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref type_die = lookup_type_die (type);
+ register dw_die_ref scope_die = 0;
+ register int nested = 0;
+
+ if (type_die && ! TYPE_SIZE (type))
+ return;
+
+ if (TYPE_CONTEXT (type) != NULL_TREE
+ && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't')
+ nested = 1;
+
+ scope_die = scope_die_for (type, context_die);
+
+ if (! type_die || (nested && scope_die == comp_unit_die))
+ /* First occurrence of type or toplevel definition of nested class. */
+ {
+ register dw_die_ref old_die = type_die;
+
+ type_die = new_die (TREE_CODE (type) == RECORD_TYPE
+ ? DW_TAG_structure_type : DW_TAG_union_type,
+ scope_die);
+ equate_type_number_to_die (type, type_die);
+ add_name_attribute (type_die, type_tag (type));
+ if (old_die)
+ add_AT_die_ref (type_die, DW_AT_specification, old_die);
+ }
+ else
+ remove_AT (type_die, DW_AT_declaration);
+
+ /* If we're not in the right context to be defining this type, defer to
+ avoid tricky recursion. */
+ if (TYPE_SIZE (type) && decl_scope_depth > 0 && scope_die == comp_unit_die)
+ {
+ add_AT_flag (type_die, DW_AT_declaration, 1);
+ pend_type (type);
+ }
+ /* If this type has been completed, then give it a byte_size attribute and
+ then give a list of members. */
+ else if (TYPE_SIZE (type))
+ {
+ /* Prevent infinite recursion in cases where the type of some member of
+ this type is expressed in terms of this type itself. */
+ TREE_ASM_WRITTEN (type) = 1;
+ add_byte_size_attribute (type_die, type);
+ if (TYPE_STUB_DECL (type) != NULL_TREE)
+ add_src_coords_attributes (type_die, TYPE_STUB_DECL (type));
+
+ /* If the first reference to this type was as the return type of an
+ inline function, then it may not have a parent. Fix this now. */
+ if (type_die->die_parent == NULL)
+ add_child_die (scope_die, type_die);
+
+ push_decl_scope (type);
+ gen_member_die (type, type_die);
+ pop_decl_scope ();
+
+ /* GNU extension: Record what type our vtable lives in. */
+ if (TYPE_VFIELD (type))
+ {
+ tree vtype = DECL_FCONTEXT (TYPE_VFIELD (type));
+
+ gen_type_die (vtype, context_die);
+ add_AT_die_ref (type_die, DW_AT_containing_type,
+ lookup_type_die (vtype));
+ }
+ }
+ else
+ add_AT_flag (type_die, DW_AT_declaration, 1);
+}
+
+/* Generate a DIE for a subroutine _type_. */
+
+static void
+gen_subroutine_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ register tree return_type = TREE_TYPE (type);
+ register dw_die_ref subr_die
+ = new_die (DW_TAG_subroutine_type, scope_die_for (type, context_die));
+
+ equate_type_number_to_die (type, subr_die);
+ add_prototyped_attribute (subr_die, type);
+ add_type_attribute (subr_die, return_type, 0, 0, context_die);
+ gen_formal_types_die (type, subr_die);
+}
+
+/* Generate a DIE for a type definition */
+
+static void
+gen_typedef_die (decl, context_die)
+ register tree decl;
+ register dw_die_ref context_die;
+{
+ register dw_die_ref type_die;
+ register tree origin;
+
+ if (TREE_ASM_WRITTEN (decl))
+ return;
+ TREE_ASM_WRITTEN (decl) = 1;
+
+ type_die = new_die (DW_TAG_typedef, scope_die_for (decl, context_die));
+ origin = decl_ultimate_origin (decl);
+ if (origin != NULL)
+ add_abstract_origin_attribute (type_die, origin);
+ else
+ {
+ register tree type;
+ add_name_and_src_coords_attributes (type_die, decl);
+ if (DECL_ORIGINAL_TYPE (decl))
+ {
+ type = DECL_ORIGINAL_TYPE (decl);
+ equate_type_number_to_die (TREE_TYPE (decl), type_die);
+ }
+ else
+ type = TREE_TYPE (decl);
+ add_type_attribute (type_die, type, TREE_READONLY (decl),
+ TREE_THIS_VOLATILE (decl), context_die);
+ }
+
+ if (DECL_ABSTRACT (decl))
+ equate_decl_number_to_die (decl, type_die);
+}
+
+/* Generate a type description DIE. */
+
+static void
+gen_type_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ if (type == NULL_TREE || type == error_mark_node)
+ return;
+
+ /* We are going to output a DIE to represent the unqualified version of
+ this type (i.e. without any const or volatile qualifiers) so get the
+ main variant (i.e. the unqualified version) of this type now. */
+ type = type_main_variant (type);
+
+ if (TREE_ASM_WRITTEN (type))
+ return;
+
+ if (TYPE_NAME (type) && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (TYPE_NAME (type)))
+ {
+ TREE_ASM_WRITTEN (type) = 1;
+ gen_decl_die (TYPE_NAME (type), context_die);
+ return;
+ }
+
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ break;
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ /* We must set TREE_ASM_WRITTEN in case this is a recursive type. This
+ ensures that the gen_type_die recursion will terminate even if the
+ type is recursive. Recursive types are possible in Ada. */
+ /* ??? We could perhaps do this for all types before the switch
+ statement. */
+ TREE_ASM_WRITTEN (type) = 1;
+
+ /* For these types, all that is required is that we output a DIE (or a
+ set of DIEs) to represent the "basis" type. */
+ gen_type_die (TREE_TYPE (type), context_die);
+ break;
+
+ case OFFSET_TYPE:
+ /* This code is used for C++ pointer-to-data-member types.
+ Output a description of the relevant class type. */
+ gen_type_die (TYPE_OFFSET_BASETYPE (type), context_die);
+
+ /* Output a description of the type of the object pointed to. */
+ gen_type_die (TREE_TYPE (type), context_die);
+
+ /* Now output a DIE to represent this pointer-to-data-member type
+ itself. */
+ gen_ptr_to_mbr_type_die (type, context_die);
+ break;
+
+ case SET_TYPE:
+ gen_type_die (TYPE_DOMAIN (type), context_die);
+ gen_set_type_die (type, context_die);
+ break;
+
+ case FILE_TYPE:
+ gen_type_die (TREE_TYPE (type), context_die);
+ abort (); /* No way to represent these in Dwarf yet! */
+ break;
+
+ case FUNCTION_TYPE:
+ /* Force out return type (in case it wasn't forced out already). */
+ gen_type_die (TREE_TYPE (type), context_die);
+ gen_subroutine_type_die (type, context_die);
+ break;
+
+ case METHOD_TYPE:
+ /* Force out return type (in case it wasn't forced out already). */
+ gen_type_die (TREE_TYPE (type), context_die);
+ gen_subroutine_type_die (type, context_die);
+ break;
+
+ case ARRAY_TYPE:
+ if (TYPE_STRING_FLAG (type) && TREE_CODE (TREE_TYPE (type)) == CHAR_TYPE)
+ {
+ gen_type_die (TREE_TYPE (type), context_die);
+ gen_string_type_die (type, context_die);
+ }
+ else
+ gen_array_type_die (type, context_die);
+ break;
+
+ case ENUMERAL_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ /* If this is a nested type whose containing class hasn't been
+ written out yet, writing it out will cover this one, too. */
+ if (TYPE_CONTEXT (type)
+ && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't'
+ && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
+ {
+ gen_type_die (TYPE_CONTEXT (type), context_die);
+
+ if (TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
+ return;
+
+ /* If that failed, attach ourselves to the stub. */
+ push_decl_scope (TYPE_CONTEXT (type));
+ context_die = lookup_type_die (TYPE_CONTEXT (type));
+ }
+
+ if (TREE_CODE (type) == ENUMERAL_TYPE)
+ gen_enumeration_type_die (type, context_die);
+ else
+ gen_struct_or_union_type_die (type, context_die);
+
+ if (TYPE_CONTEXT (type)
+ && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't'
+ && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
+ pop_decl_scope ();
+
+ /* Don't set TREE_ASM_WRITTEN on an incomplete struct; we want to fix
+ it up if it is ever completed. gen_*_type_die will set it for us
+ when appropriate. */
+ return;
+
+ case VOID_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case COMPLEX_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ /* No DIEs needed for fundamental types. */
+ break;
+
+ case LANG_TYPE:
+ /* No Dwarf representation currently defined. */
+ break;
+
+ default:
+ abort ();
+ }
+
+ TREE_ASM_WRITTEN (type) = 1;
+}
+
+/* Generate a DIE for a tagged type instantiation. */
+
+static void
+gen_tagged_type_instantiation_die (type, context_die)
+ register tree type;
+ register dw_die_ref context_die;
+{
+ if (type == NULL_TREE || type == error_mark_node)
+ return;
+
+ /* We are going to output a DIE to represent the unqualified version of
+ this type (i.e. without any const or volatile qualifiers) so make sure
+ that we have the main variant (i.e. the unqualified version) of this
+ type now. */
+ if (type != type_main_variant (type)
+ || !TREE_ASM_WRITTEN (type))
+ abort ();
+
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ break;
+
+ case ENUMERAL_TYPE:
+ gen_inlined_enumeration_type_die (type, context_die);
+ break;
+
+ case RECORD_TYPE:
+ gen_inlined_structure_type_die (type, context_die);
+ break;
+
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ gen_inlined_union_type_die (type, context_die);
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+/* Generate a DW_TAG_lexical_block DIE followed by DIEs to represent all of the
+ things which are local to the given block. */
+
+static void
+gen_block_die (stmt, context_die, depth)
+ register tree stmt;
+ register dw_die_ref context_die;
+ int depth;
+{
+ register int must_output_die = 0;
+ register tree origin;
+ register tree decl;
+ register enum tree_code origin_code;
+
+ /* Ignore blocks never really used to make RTL. */
+
+ if (stmt == NULL_TREE || !TREE_USED (stmt))
+ return;
+
+ /* Determine the "ultimate origin" of this block. This block may be an
+ inlined instance of an inlined instance of inline function, so we have
+ to trace all of the way back through the origin chain to find out what
+ sort of node actually served as the original seed for the creation of
+ the current block. */
+ origin = block_ultimate_origin (stmt);
+ origin_code = (origin != NULL) ? TREE_CODE (origin) : ERROR_MARK;
+
+ /* Determine if we need to output any Dwarf DIEs at all to represent this
+ block. */
+ if (origin_code == FUNCTION_DECL)
+ /* The outer scopes for inlinings *must* always be represented. We
+ generate DW_TAG_inlined_subroutine DIEs for them. (See below.) */
+ must_output_die = 1;
+ else
+ {
+ /* In the case where the current block represents an inlining of the
+ "body block" of an inline function, we must *NOT* output any DIE for
+ this block because we have already output a DIE to represent the
+ whole inlined function scope and the "body block" of any function
+ doesn't really represent a different scope according to ANSI C
+ rules. So we check here to make sure that this block does not
+ represent a "body block inlining" before trying to set the
+ `must_output_die' flag. */
+ if (! is_body_block (origin ? origin : stmt))
+ {
+ /* Determine if this block directly contains any "significant"
+ local declarations which we will need to output DIEs for. */
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ /* We are not in terse mode so *any* local declaration counts
+ as being a "significant" one. */
+ must_output_die = (BLOCK_VARS (stmt) != NULL);
+ else
+ /* We are in terse mode, so only local (nested) function
+ definitions count as "significant" local declarations. */
+ for (decl = BLOCK_VARS (stmt);
+ decl != NULL; decl = TREE_CHAIN (decl))
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_INITIAL (decl))
+ {
+ must_output_die = 1;
+ break;
+ }
+ }
+ }
+
+ /* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block
+ DIE for any block which contains no significant local declarations at
+ all. Rather, in such cases we just call `decls_for_scope' so that any
+ needed Dwarf info for any sub-blocks will get properly generated. Note
+ that in terse mode, our definition of what constitutes a "significant"
+ local declaration gets restricted to include only inlined function
+ instances and local (nested) function definitions. */
+ if (must_output_die)
+ {
+ if (origin_code == FUNCTION_DECL)
+ gen_inlined_subroutine_die (stmt, context_die, depth);
+ else
+ gen_lexical_block_die (stmt, context_die, depth);
+ }
+ else
+ decls_for_scope (stmt, context_die, depth);
+}
+
+/* Generate all of the decls declared within a given scope and (recursively)
+ all of its sub-blocks. */
+
+static void
+decls_for_scope (stmt, context_die, depth)
+ register tree stmt;
+ register dw_die_ref context_die;
+ int depth;
+{
+ register tree decl;
+ register tree subblocks;
+
+ /* Ignore blocks never really used to make RTL. */
+ if (stmt == NULL_TREE || ! TREE_USED (stmt))
+ return;
+
+ if (!BLOCK_ABSTRACT (stmt) && depth > 0)
+ next_block_number++;
+
+ /* Output the DIEs to represent all of the data objects and typedefs
+ declared directly within this block but not within any nested
+ sub-blocks. Also, nested function and tag DIEs have been
+ generated with a parent of NULL; fix that up now. */
+ for (decl = BLOCK_VARS (stmt);
+ decl != NULL; decl = TREE_CHAIN (decl))
+ {
+ register dw_die_ref die;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ die = lookup_decl_die (decl);
+ else if (TREE_CODE (decl) == TYPE_DECL && TYPE_DECL_IS_STUB (decl))
+ die = lookup_type_die (TREE_TYPE (decl));
+ else
+ die = NULL;
+
+ if (die != NULL && die->die_parent == NULL)
+ add_child_die (context_die, die);
+ else
+ gen_decl_die (decl, context_die);
+ }
+
+ /* Output the DIEs to represent all sub-blocks (and the items declared
+ therein) of this block. */
+ for (subblocks = BLOCK_SUBBLOCKS (stmt);
+ subblocks != NULL;
+ subblocks = BLOCK_CHAIN (subblocks))
+ gen_block_die (subblocks, context_die, depth + 1);
+}
+
+/* Is this a typedef we can avoid emitting? */
+
+static inline int
+is_redundant_typedef (decl)
+ register tree decl;
+{
+ if (TYPE_DECL_IS_STUB (decl))
+ return 1;
+
+ if (DECL_ARTIFICIAL (decl)
+ && DECL_CONTEXT (decl)
+ && is_tagged_type (DECL_CONTEXT (decl))
+ && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
+ && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
+ /* Also ignore the artificial member typedef for the class name. */
+ return 1;
+
+ return 0;
+}
+
+/* Generate Dwarf debug information for a decl described by DECL. */
+
+static void
+gen_decl_die (decl, context_die)
+ register tree decl;
+ register dw_die_ref context_die;
+{
+ register tree origin;
+
+ /* Make a note of the decl node we are going to be working on. We may need
+ to give the user the source coordinates of where it appeared in case we
+ notice (later on) that something about it looks screwy. */
+ dwarf_last_decl = decl;
+
+ if (TREE_CODE (decl) == ERROR_MARK)
+ return;
+
+ /* If this ..._DECL node is marked to be ignored, then ignore it. But don't
+ ignore a function definition, since that would screw up our count of
+ blocks, and that in turn will completely screw up the labels we will
+ reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for
+ subsequent blocks). */
+ if (DECL_IGNORED_P (decl) && TREE_CODE (decl) != FUNCTION_DECL)
+ return;
+
+ switch (TREE_CODE (decl))
+ {
+ case CONST_DECL:
+ /* The individual enumerators of an enum type get output when we output
+ the Dwarf representation of the relevant enum type itself. */
+ break;
+
+ case FUNCTION_DECL:
+ /* Don't output any DIEs to represent mere function declarations,
+ unless they are class members or explicit block externs. */
+ if (DECL_INITIAL (decl) == NULL_TREE && DECL_CONTEXT (decl) == NULL_TREE
+ && (current_function_decl == NULL_TREE || ! DECL_ARTIFICIAL (decl)))
+ break;
+
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ {
+ /* Before we describe the FUNCTION_DECL itself, make sure that we
+ have described its return type. */
+ gen_type_die (TREE_TYPE (TREE_TYPE (decl)), context_die);
+
+ /* And its containing type. */
+ origin = decl_class_context (decl);
+ if (origin != NULL_TREE)
+ gen_type_die (origin, context_die);
+
+ /* And its virtual context. */
+ if (DECL_VINDEX (decl) != NULL_TREE)
+ gen_type_die (DECL_CONTEXT (decl), context_die);
+ }
+
+ /* Now output a DIE to represent the function itself. */
+ gen_subprogram_die (decl, context_die);
+ break;
+
+ case TYPE_DECL:
+ /* If we are in terse mode, don't generate any DIEs to represent any
+ actual typedefs. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ break;
+
+ /* In the special case of a TYPE_DECL node representing the
+ declaration of some type tag, if the given TYPE_DECL is marked as
+ having been instantiated from some other (original) TYPE_DECL node
+ (e.g. one which was generated within the original definition of an
+ inline function) we have to generate a special (abbreviated)
+ DW_TAG_structure_type, DW_TAG_union_type, or DW_TAG_enumeration_type
+ DIE here. */
+ if (TYPE_DECL_IS_STUB (decl) && DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE)
+ {
+ gen_tagged_type_instantiation_die (TREE_TYPE (decl), context_die);
+ break;
+ }
+
+ if (is_redundant_typedef (decl))
+ gen_type_die (TREE_TYPE (decl), context_die);
+ else
+ /* Output a DIE to represent the typedef itself. */
+ gen_typedef_die (decl, context_die);
+ break;
+
+ case LABEL_DECL:
+ if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ gen_label_die (decl, context_die);
+ break;
+
+ case VAR_DECL:
+ /* If we are in terse mode, don't generate any DIEs to represent any
+ variable declarations or definitions. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ break;
+
+ /* Output any DIEs that are needed to specify the type of this data
+ object. */
+ gen_type_die (TREE_TYPE (decl), context_die);
+
+ /* And its containing type. */
+ origin = decl_class_context (decl);
+ if (origin != NULL_TREE)
+ gen_type_die (origin, context_die);
+
+ /* Now output the DIE to represent the data object itself. This gets
+ complicated because of the possibility that the VAR_DECL really
+ represents an inlined instance of a formal parameter for an inline
+ function. */
+ origin = decl_ultimate_origin (decl);
+ if (origin != NULL_TREE && TREE_CODE (origin) == PARM_DECL)
+ gen_formal_parameter_die (decl, context_die);
+ else
+ gen_variable_die (decl, context_die);
+ break;
+
+ case FIELD_DECL:
+ /* Ignore the nameless fields that are used to skip bits, but
+ handle C++ anonymous unions. */
+ if (DECL_NAME (decl) != NULL_TREE
+ || TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE)
+ {
+ gen_type_die (member_declared_type (decl), context_die);
+ gen_field_die (decl, context_die);
+ }
+ break;
+
+ case PARM_DECL:
+ gen_type_die (TREE_TYPE (decl), context_die);
+ gen_formal_parameter_die (decl, context_die);
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+/* Write the debugging output for DECL. */
+
+void
+dwarf2out_decl (decl)
+ register tree decl;
+{
+ register dw_die_ref context_die = comp_unit_die;
+
+ if (TREE_CODE (decl) == ERROR_MARK)
+ return;
+
+ /* If this ..._DECL node is marked to be ignored, then ignore it. We gotta
+ hope that the node in question doesn't represent a function definition.
+ If it does, then totally ignoring it is bound to screw up our count of
+ blocks, and that in turn will completely screw up the labels we will
+ reference in subsequent DW_AT_low_pc and DW_AT_high_pc attributes (for
+ subsequent blocks). (It's too bad that BLOCK nodes don't carry their
+ own sequence numbers with them!) */
+ if (DECL_IGNORED_P (decl))
+ {
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_INITIAL (decl) != NULL)
+ abort ();
+
+ return;
+ }
+
+ switch (TREE_CODE (decl))
+ {
+ case FUNCTION_DECL:
+ /* Ignore this FUNCTION_DECL if it refers to a builtin declaration of a
+ builtin function. Explicit programmer-supplied declarations of
+ these same functions should NOT be ignored however. */
+ if (DECL_EXTERNAL (decl) && DECL_FUNCTION_CODE (decl))
+ return;
+
+ /* What we would really like to do here is to filter out all mere
+ file-scope declarations of file-scope functions which are never
+ referenced later within this translation unit (and keep all of ones
+ that *are* referenced later on) but we aren't clairvoyant, so we have
+ no idea which functions will be referenced in the future (i.e. later
+ on within the current translation unit). So here we just ignore all
+ file-scope function declarations which are not also definitions. If
+ and when the debugger needs to know something about these functions,
+ it wil have to hunt around and find the DWARF information associated
+ with the definition of the function. Note that we can't just check
+ `DECL_EXTERNAL' to find out which FUNCTION_DECL nodes represent
+ definitions and which ones represent mere declarations. We have to
+ check `DECL_INITIAL' instead. That's because the C front-end
+ supports some weird semantics for "extern inline" function
+ definitions. These can get inlined within the current translation
+ unit (an thus, we need to generate DWARF info for their abstract
+ instances so that the DWARF info for the concrete inlined instances
+ can have something to refer to) but the compiler never generates any
+ out-of-lines instances of such things (despite the fact that they
+ *are* definitions). The important point is that the C front-end
+ marks these "extern inline" functions as DECL_EXTERNAL, but we need
+ to generate DWARF for them anyway. Note that the C++ front-end also
+ plays some similar games for inline function definitions appearing
+ within include files which also contain
+ `#pragma interface' pragmas. */
+ if (DECL_INITIAL (decl) == NULL_TREE)
+ return;
+
+ /* If we're a nested function, initially use a parent of NULL; if we're
+ a plain function, this will be fixed up in decls_for_scope. If
+ we're a method, it will be ignored, since we already have a DIE. */
+ if (decl_function_context (decl))
+ context_die = NULL;
+
+ break;
+
+ case VAR_DECL:
+ /* Ignore this VAR_DECL if it refers to a file-scope extern data object
+ declaration and if the declaration was never even referenced from
+ within this entire compilation unit. We suppress these DIEs in
+ order to save space in the .debug section (by eliminating entries
+ which are probably useless). Note that we must not suppress
+ block-local extern declarations (whether used or not) because that
+ would screw-up the debugger's name lookup mechanism and cause it to
+ miss things which really ought to be in scope at a given point. */
+ if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
+ return;
+
+ /* If we are in terse mode, don't generate any DIEs to represent any
+ variable declarations or definitions. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ return;
+ break;
+
+ case TYPE_DECL:
+ /* Don't bother trying to generate any DIEs to represent any of the
+ normal built-in types for the language we are compiling. */
+ if (DECL_SOURCE_LINE (decl) == 0)
+ {
+ /* OK, we need to generate one for `bool' so GDB knows what type
+ comparisons have. */
+ if ((get_AT_unsigned (comp_unit_die, DW_AT_language)
+ == DW_LANG_C_plus_plus)
+ && TREE_CODE (TREE_TYPE (decl)) == BOOLEAN_TYPE)
+ modified_type_die (TREE_TYPE (decl), 0, 0, NULL);
+
+ return;
+ }
+
+ /* If we are in terse mode, don't generate any DIEs for types. */
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ return;
+
+ /* If we're a function-scope tag, initially use a parent of NULL;
+ this will be fixed up in decls_for_scope. */
+ if (decl_function_context (decl))
+ context_die = NULL;
+
+ break;
+
+ default:
+ return;
+ }
+
+ gen_decl_die (decl, context_die);
+ output_pending_types_for_scope (comp_unit_die);
+}
+
+/* Output a marker (i.e. a label) for the beginning of the generated code for
+ a lexical block. */
+
+void
+dwarf2out_begin_block (blocknum)
+ register unsigned blocknum;
+{
+ function_section (current_function_decl);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_BEGIN_LABEL, blocknum);
+}
+
+/* Output a marker (i.e. a label) for the end of the generated code for a
+ lexical block. */
+
+void
+dwarf2out_end_block (blocknum)
+ register unsigned blocknum;
+{
+ function_section (current_function_decl);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BLOCK_END_LABEL, blocknum);
+}
+
+/* Output a marker (i.e. a label) at a point in the assembly code which
+ corresponds to a given source level label. */
+
+void
+dwarf2out_label (insn)
+ register rtx insn;
+{
+ char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ {
+ function_section (current_function_decl);
+ sprintf (label, INSN_LABEL_FMT, current_funcdef_number);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, label,
+ (unsigned) INSN_UID (insn));
+ }
+}
+
+/* Lookup a filename (in the list of filenames that we know about here in
+ dwarf2out.c) and return its "index". The index of each (known) filename is
+ just a unique number which is associated with only that one filename.
+ We need such numbers for the sake of generating labels
+ (in the .debug_sfnames section) and references to those
+ files numbers (in the .debug_srcinfo and.debug_macinfo sections).
+ If the filename given as an argument is not found in our current list,
+ add it to the list and assign it the next available unique index number.
+ In order to speed up searches, we remember the index of the filename
+ was looked up last. This handles the majority of all searches. */
+
+static unsigned
+lookup_filename (file_name)
+ char *file_name;
+{
+ static unsigned last_file_lookup_index = 0;
+ register unsigned i;
+
+ /* Check to see if the file name that was searched on the previous call
+ matches this file name. If so, return the index. */
+ if (last_file_lookup_index != 0)
+ if (strcmp (file_name, file_table[last_file_lookup_index]) == 0)
+ return last_file_lookup_index;
+
+ /* Didn't match the previous lookup, search the table */
+ for (i = 1; i < file_table_in_use; ++i)
+ if (strcmp (file_name, file_table[i]) == 0)
+ {
+ last_file_lookup_index = i;
+ return i;
+ }
+
+ /* Prepare to add a new table entry by making sure there is enough space in
+ the table to do so. If not, expand the current table. */
+ if (file_table_in_use == file_table_allocated)
+ {
+ file_table_allocated += FILE_TABLE_INCREMENT;
+ file_table
+ = (char **) xrealloc (file_table,
+ file_table_allocated * sizeof (char *));
+ }
+
+ /* Add the new entry to the end of the filename table. */
+ file_table[file_table_in_use] = xstrdup (file_name);
+ last_file_lookup_index = file_table_in_use++;
+
+ return last_file_lookup_index;
+}
+
+/* Output a label to mark the beginning of a source code line entry
+ and record information relating to this source line, in
+ 'line_info_table' for later output of the .debug_line section. */
+
+void
+dwarf2out_line (filename, line)
+ register char *filename;
+ register unsigned line;
+{
+ if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ {
+ function_section (current_function_decl);
+
+ if (DECL_SECTION_NAME (current_function_decl))
+ {
+ register dw_separate_line_info_ref line_info;
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, SEPARATE_LINE_CODE_LABEL,
+ separate_line_info_table_in_use);
+ fputc ('\n', asm_out_file);
+
+ /* expand the line info table if necessary */
+ if (separate_line_info_table_in_use
+ == separate_line_info_table_allocated)
+ {
+ separate_line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
+ separate_line_info_table
+ = (dw_separate_line_info_ref)
+ xrealloc (separate_line_info_table,
+ separate_line_info_table_allocated
+ * sizeof (dw_separate_line_info_entry));
+ }
+
+ /* Add the new entry at the end of the line_info_table. */
+ line_info
+ = &separate_line_info_table[separate_line_info_table_in_use++];
+ line_info->dw_file_num = lookup_filename (filename);
+ line_info->dw_line_num = line;
+ line_info->function = current_funcdef_number;
+ }
+ else
+ {
+ register dw_line_info_ref line_info;
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, LINE_CODE_LABEL,
+ line_info_table_in_use);
+ fputc ('\n', asm_out_file);
+
+ /* Expand the line info table if necessary. */
+ if (line_info_table_in_use == line_info_table_allocated)
+ {
+ line_info_table_allocated += LINE_INFO_TABLE_INCREMENT;
+ line_info_table
+ = (dw_line_info_ref)
+ xrealloc (line_info_table,
+ (line_info_table_allocated
+ * sizeof (dw_line_info_entry)));
+ }
+
+ /* Add the new entry at the end of the line_info_table. */
+ line_info = &line_info_table[line_info_table_in_use++];
+ line_info->dw_file_num = lookup_filename (filename);
+ line_info->dw_line_num = line;
+ }
+ }
+}
+
+/* Record the beginning of a new source file, for later output
+ of the .debug_macinfo section. At present, unimplemented. */
+
+void
+dwarf2out_start_source_file (filename)
+ register char *filename ATTRIBUTE_UNUSED;
+{
+}
+
+/* Record the end of a source file, for later output
+ of the .debug_macinfo section. At present, unimplemented. */
+
+void
+dwarf2out_end_source_file ()
+{
+}
+
+/* Called from check_newline in c-parse.y. The `buffer' parameter contains
+ the tail part of the directive line, i.e. the part which is past the
+ initial whitespace, #, whitespace, directive-name, whitespace part. */
+
+void
+dwarf2out_define (lineno, buffer)
+ register unsigned lineno;
+ register char *buffer;
+{
+ static int initialized = 0;
+ if (!initialized)
+ {
+ dwarf2out_start_source_file (primary_filename);
+ initialized = 1;
+ }
+}
+
+/* Called from check_newline in c-parse.y. The `buffer' parameter contains
+ the tail part of the directive line, i.e. the part which is past the
+ initial whitespace, #, whitespace, directive-name, whitespace part. */
+
+void
+dwarf2out_undef (lineno, buffer)
+ register unsigned lineno ATTRIBUTE_UNUSED;
+ register char *buffer ATTRIBUTE_UNUSED;
+{
+}
+
+/* Set up for Dwarf output at the start of compilation. */
+
+void
+dwarf2out_init (asm_out_file, main_input_filename)
+ register FILE *asm_out_file;
+ register char *main_input_filename;
+{
+ /* Remember the name of the primary input file. */
+ primary_filename = main_input_filename;
+
+ /* Allocate the initial hunk of the file_table. */
+ file_table = (char **) xmalloc (FILE_TABLE_INCREMENT * sizeof (char *));
+ bzero ((char *) file_table, FILE_TABLE_INCREMENT * sizeof (char *));
+ file_table_allocated = FILE_TABLE_INCREMENT;
+
+ /* Skip the first entry - file numbers begin at 1. */
+ file_table_in_use = 1;
+
+ /* Allocate the initial hunk of the decl_die_table. */
+ decl_die_table
+ = (dw_die_ref *) xmalloc (DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
+ bzero ((char *) decl_die_table,
+ DECL_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
+ decl_die_table_allocated = DECL_DIE_TABLE_INCREMENT;
+ decl_die_table_in_use = 0;
+
+ /* Allocate the initial hunk of the decl_scope_table. */
+ decl_scope_table
+ = (decl_scope_node *) xmalloc (DECL_SCOPE_TABLE_INCREMENT
+ * sizeof (decl_scope_node));
+ bzero ((char *) decl_scope_table,
+ DECL_SCOPE_TABLE_INCREMENT * sizeof (decl_scope_node));
+ decl_scope_table_allocated = DECL_SCOPE_TABLE_INCREMENT;
+ decl_scope_depth = 0;
+
+ /* Allocate the initial hunk of the abbrev_die_table. */
+ abbrev_die_table
+ = (dw_die_ref *) xmalloc (ABBREV_DIE_TABLE_INCREMENT
+ * sizeof (dw_die_ref));
+ bzero ((char *) abbrev_die_table,
+ ABBREV_DIE_TABLE_INCREMENT * sizeof (dw_die_ref));
+ abbrev_die_table_allocated = ABBREV_DIE_TABLE_INCREMENT;
+ /* Zero-th entry is allocated, but unused */
+ abbrev_die_table_in_use = 1;
+
+ /* Allocate the initial hunk of the line_info_table. */
+ line_info_table
+ = (dw_line_info_ref) xmalloc (LINE_INFO_TABLE_INCREMENT
+ * sizeof (dw_line_info_entry));
+ bzero ((char *) line_info_table,
+ LINE_INFO_TABLE_INCREMENT * sizeof (dw_line_info_entry));
+ line_info_table_allocated = LINE_INFO_TABLE_INCREMENT;
+ /* Zero-th entry is allocated, but unused */
+ line_info_table_in_use = 1;
+
+ /* Generate the initial DIE for the .debug section. Note that the (string)
+ value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE
+ will (typically) be a relative pathname and that this pathname should be
+ taken as being relative to the directory from which the compiler was
+ invoked when the given (base) source file was compiled. */
+ gen_compile_unit_die (main_input_filename);
+
+ ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
+}
+
+/* Output stuff that dwarf requires at the end of every file,
+ and generate the DWARF-2 debugging info. */
+
+void
+dwarf2out_finish ()
+{
+ limbo_die_node *node, *next_node;
+ dw_die_ref die;
+ dw_attr_ref a;
+
+ /* Traverse the limbo die list, and add parent/child links. The only
+ dies without parents that should be here are concrete instances of
+ inline functions, and the comp_unit_die. We can ignore the comp_unit_die.
+ For concrete instances, we can get the parent die from the abstract
+ instance. */
+ for (node = limbo_die_list; node; node = next_node)
+ {
+ next_node = node->next;
+ die = node->die;
+
+ if (die->die_parent == NULL)
+ {
+ a = get_AT (die, DW_AT_abstract_origin);
+ if (a)
+ add_child_die (a->dw_attr_val.v.val_die_ref->die_parent, die);
+ else if (die == comp_unit_die)
+ ;
+ else
+ abort ();
+ }
+ free (node);
+ }
+
+ /* Traverse the DIE tree and add sibling attributes to those DIE's
+ that have children. */
+ add_sibling_attributes (comp_unit_die);
+
+ /* Output a terminator label for the .text section. */
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_SECTION (asm_out_file, TEXT_SECTION);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, TEXT_END_LABEL, 0);
+
+#if 0
+ /* Output a terminator label for the .data section. */
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_SECTION (asm_out_file, DATA_SECTION);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, DATA_END_LABEL, 0);
+
+ /* Output a terminator label for the .bss section. */
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_SECTION (asm_out_file, BSS_SECTION);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, BSS_END_LABEL, 0);
+#endif
+
+ /* Output the source line correspondence table. */
+ if (line_info_table_in_use > 1 || separate_line_info_table_in_use)
+ {
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_LINE_SECTION);
+ output_line_info ();
+
+ /* We can only use the low/high_pc attributes if all of the code
+ was in .text. */
+ if (separate_line_info_table_in_use == 0)
+ {
+ add_AT_lbl_id (comp_unit_die, DW_AT_low_pc, TEXT_SECTION);
+ add_AT_lbl_id (comp_unit_die, DW_AT_high_pc, text_end_label);
+ }
+
+ add_AT_section_offset (comp_unit_die, DW_AT_stmt_list, DEBUG_LINE_SECTION);
+ }
+
+ /* Output the abbreviation table. */
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_SECTION (asm_out_file, ABBREV_SECTION);
+ build_abbrev_table (comp_unit_die);
+ output_abbrev_section ();
+
+ /* Initialize the beginning DIE offset - and calculate sizes/offsets. */
+ next_die_offset = DWARF_COMPILE_UNIT_HEADER_SIZE;
+ calc_die_sizes (comp_unit_die);
+
+ /* Output debugging information. */
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_SECTION (asm_out_file, DEBUG_INFO_SECTION);
+ output_compilation_unit_header ();
+ output_die (comp_unit_die);
+
+ if (pubname_table_in_use)
+ {
+ /* Output public names table. */
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_SECTION (asm_out_file, PUBNAMES_SECTION);
+ output_pubnames ();
+ }
+
+ if (fde_table_in_use)
+ {
+ /* Output the address range information. */
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_SECTION (asm_out_file, ARANGES_SECTION);
+ output_aranges ();
+ }
+}
+#endif /* DWARF2_DEBUGGING_INFO */
diff --git a/contrib/gcc/dwarf2out.h b/contrib/gcc/dwarf2out.h
new file mode 100644
index 0000000..ad6232e
--- /dev/null
+++ b/contrib/gcc/dwarf2out.h
@@ -0,0 +1,41 @@
+/* dwarf2out.h - Various declarations for functions found in dwarf2out.c
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+extern void dwarf2out_init PROTO ((FILE *asm_out_file,
+ char *main_input_filename));
+extern void dwarf2out_finish PROTO ((void));
+
+extern void dwarf2out_define PROTO ((unsigned, char *));
+extern void dwarf2out_undef PROTO ((unsigned, char *));
+extern void dwarf2out_start_source_file PROTO ((char *));
+extern void dwarf2out_end_source_file PROTO ((void));
+
+extern void dwarf2out_begin_block PROTO ((unsigned));
+extern void dwarf2out_end_block PROTO ((unsigned));
+extern void dwarf2out_label PROTO ((rtx));
+extern void dwarf2out_decl PROTO ((tree));
+extern void dwarf2out_line PROTO ((char *, unsigned));
+extern void dwarf2out_frame_init PROTO ((void));
+extern void dwarf2out_frame_debug PROTO ((rtx));
+extern void dwarf2out_frame_finish PROTO ((void));
+
+extern void debug_dwarf PROTO ((void));
+struct die_struct;
+extern void debug_dwarf_die PROTO ((struct die_struct *));
diff --git a/contrib/gcc/dwarfout.c b/contrib/gcc/dwarfout.c
index b484e5a..80475c6 100644
--- a/contrib/gcc/dwarfout.c
+++ b/contrib/gcc/dwarfout.c
@@ -1,9 +1,6 @@
/* Output Dwarf format symbol table information from the GNU C compiler.
- Copyright (C) 1992, 1993, 1995 Free Software Foundation, Inc.
-
- Written by Ron Guilmette (rfg@netcom.com) for
- Network Computing Devices, August, September, October, November 1990.
- Generously contributed by NCD to the Free Software Foundation.
+ Copyright (C) 1992, 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Ron Guilmette (rfg@monkeys.com) of Network Computing Devices.
This file is part of GNU CC.
@@ -25,7 +22,7 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
#ifdef DWARF_DEBUGGING_INFO
-#include <stdio.h>
+#include "system.h"
#include "dwarf.h"
#include "tree.h"
#include "flags.h"
@@ -35,31 +32,25 @@ Boston, MA 02111-1307, USA. */
#include "reload.h"
#include "output.h"
#include "defaults.h"
-
-#ifndef DWARF_VERSION
-#define DWARF_VERSION 1
-#endif
-
-/* #define NDEBUG 1 */
-#include "assert.h"
+#include "dwarfout.h"
+#include "toplev.h"
#if defined(DWARF_TIMESTAMPS)
-#if defined(POSIX)
-#include <time.h>
-#else /* !defined(POSIX) */
-#include <sys/types.h>
-#if defined(__STDC__)
-extern time_t time (time_t *);
-#else /* !defined(__STDC__) */
-extern time_t time ();
-#endif /* !defined(__STDC__) */
+#if !defined(POSIX)
+extern time_t time PROTO ((time_t *)); /* FIXME: use NEED_DECLARATION_TIME */
#endif /* !defined(POSIX) */
#endif /* defined(DWARF_TIMESTAMPS) */
-extern char *getpwd ();
+/* We cannot use <assert.h> in GCC source, since that would include
+ GCC's assert.h, which may not be compatible with the host compiler. */
+#undef assert
+#ifdef NDEBUG
+# define assert(e)
+#else
+# define assert(e) do { if (! (e)) abort (); } while (0)
+#endif
-extern char *index ();
-extern char *rindex ();
+extern char *getpwd PROTO((void));
/* IMPORTANT NOTE: Please see the file README.DWARF for important details
regarding the GNU implementation of Dwarf. */
@@ -72,10 +63,8 @@ extern char *rindex ();
/* Note that the implementation of C++ support herein is (as yet) unfinished.
If you want to try to complete it, more power to you. */
-#if defined(__GNUC__) && (NDEBUG == 1)
-#define inline static inline
-#else
-#define inline static
+#if !defined(__GNUC__) || (NDEBUG != 1)
+#define inline
#endif
/* How to start an assembler comment. */
@@ -106,6 +95,21 @@ extern char *rindex ();
#define TYPE_USED_FOR_FUNCTION(tagged_type) (TYPE_SIZE (tagged_type) == 0)
+/* Define a macro which returns non-zero for a TYPE_DECL which was
+ implicitly generated for a tagged type.
+
+ Note that unlike the gcc front end (which generates a NULL named
+ TYPE_DECL node for each complete tagged type, each array type, and
+ each function type node created) the g++ front end generates a
+ _named_ TYPE_DECL node for each tagged type node created.
+ These TYPE_DECLs have DECL_ARTIFICIAL set, so we know not to
+ generate a DW_TAG_typedef DIE for them. */
+#define TYPE_DECL_IS_STUB(decl) \
+ (DECL_NAME (decl) == NULL \
+ || (DECL_ARTIFICIAL (decl) \
+ && is_tagged_type (TREE_TYPE (decl)) \
+ && decl == TYPE_STUB_DECL (TREE_TYPE (decl))))
+
extern int flag_traditional;
extern char *version_string;
extern char *language_string;
@@ -168,7 +172,7 @@ struct filename_entry {
typedef struct filename_entry filename_entry;
-/* Pointer to an array of elements, each one having the structure above. */
+/* Pointer to an array of elements, each one having the structure above. */
static filename_entry *filename_table;
@@ -207,7 +211,7 @@ static char *last_filename;
static unsigned next_block_number = 2;
-/* Counter to generate unique names for DIEs. */
+/* Counter to generate unique names for DIEs. */
static unsigned next_unused_dienum = 1;
@@ -219,7 +223,7 @@ static unsigned current_dienum;
represents a function or data object defined in this compilation
unit which has "extern" linkage. */
-static next_pubname_number = 0;
+static int next_pubname_number = 0;
#define NEXT_DIE_NUM pending_sibling_stack[pending_siblings-1]
@@ -293,13 +297,146 @@ static unsigned current_funcdef_number = 1;
static tree dwarf_last_decl;
+/* A flag indicating that we are emitting the member declarations of a
+ class, so member functions and variables should not be entirely emitted.
+ This is a kludge to avoid passing a second argument to output_*_die. */
+
+static int in_class;
+
/* Forward declarations for functions defined in this file. */
-static void output_type ();
-static void type_attribute ();
-static void output_decls_for_scope ();
-static void output_decl ();
-static unsigned lookup_filename ();
+static char *dwarf_tag_name PROTO((unsigned));
+static char *dwarf_attr_name PROTO((unsigned));
+static char *dwarf_stack_op_name PROTO((unsigned));
+static char *dwarf_typemod_name PROTO((unsigned));
+static char *dwarf_fmt_byte_name PROTO((unsigned));
+static char *dwarf_fund_type_name PROTO((unsigned));
+static tree decl_ultimate_origin PROTO((tree));
+static tree block_ultimate_origin PROTO((tree));
+static tree decl_class_context PROTO((tree));
+#if 0
+static void output_unsigned_leb128 PROTO((unsigned long));
+static void output_signed_leb128 PROTO((long));
+#endif
+static inline int is_body_block PROTO((tree));
+static int fundamental_type_code PROTO((tree));
+static tree root_type_1 PROTO((tree, int));
+static tree root_type PROTO((tree));
+static void write_modifier_bytes_1 PROTO((tree, int, int, int));
+static void write_modifier_bytes PROTO((tree, int, int));
+static inline int type_is_fundamental PROTO((tree));
+static void equate_decl_number_to_die_number PROTO((tree));
+static inline void equate_type_number_to_die_number PROTO((tree));
+static void output_reg_number PROTO((rtx));
+static void output_mem_loc_descriptor PROTO((rtx));
+static void output_loc_descriptor PROTO((rtx));
+static void output_bound_representation PROTO((tree, unsigned, int));
+static void output_enumeral_list PROTO((tree));
+static inline unsigned ceiling PROTO((unsigned, unsigned));
+static inline tree field_type PROTO((tree));
+static inline unsigned simple_type_align_in_bits PROTO((tree));
+static inline unsigned simple_type_size_in_bits PROTO((tree));
+static unsigned field_byte_offset PROTO((tree));
+static inline void sibling_attribute PROTO((void));
+static void location_attribute PROTO((rtx));
+static void data_member_location_attribute PROTO((tree));
+static void const_value_attribute PROTO((rtx));
+static void location_or_const_value_attribute PROTO((tree));
+static inline void name_attribute PROTO((char *));
+static inline void fund_type_attribute PROTO((unsigned));
+static void mod_fund_type_attribute PROTO((tree, int, int));
+static inline void user_def_type_attribute PROTO((tree));
+static void mod_u_d_type_attribute PROTO((tree, int, int));
+#ifdef USE_ORDERING_ATTRIBUTE
+static inline void ordering_attribute PROTO((unsigned));
+#endif /* defined(USE_ORDERING_ATTRIBUTE) */
+static void subscript_data_attribute PROTO((tree));
+static void byte_size_attribute PROTO((tree));
+static inline void bit_offset_attribute PROTO((tree));
+static inline void bit_size_attribute PROTO((tree));
+static inline void element_list_attribute PROTO((tree));
+static inline void stmt_list_attribute PROTO((char *));
+static inline void low_pc_attribute PROTO((char *));
+static inline void high_pc_attribute PROTO((char *));
+static inline void body_begin_attribute PROTO((char *));
+static inline void body_end_attribute PROTO((char *));
+static inline void language_attribute PROTO((unsigned));
+static inline void member_attribute PROTO((tree));
+#if 0
+static inline void string_length_attribute PROTO((tree));
+#endif
+static inline void comp_dir_attribute PROTO((char *));
+static inline void sf_names_attribute PROTO((char *));
+static inline void src_info_attribute PROTO((char *));
+static inline void mac_info_attribute PROTO((char *));
+static inline void prototyped_attribute PROTO((tree));
+static inline void producer_attribute PROTO((char *));
+static inline void inline_attribute PROTO((tree));
+static inline void containing_type_attribute PROTO((tree));
+static inline void abstract_origin_attribute PROTO((tree));
+#ifdef DWARF_DECL_COORDINATES
+static inline void src_coords_attribute PROTO((unsigned, unsigned));
+#endif /* defined(DWARF_DECL_COORDINATES) */
+static inline void pure_or_virtual_attribute PROTO((tree));
+static void name_and_src_coords_attributes PROTO((tree));
+static void type_attribute PROTO((tree, int, int));
+static char *type_tag PROTO((tree));
+static inline void dienum_push PROTO((void));
+static inline void dienum_pop PROTO((void));
+static inline tree member_declared_type PROTO((tree));
+static char *function_start_label PROTO((tree));
+static void output_array_type_die PROTO((void *));
+static void output_set_type_die PROTO((void *));
+#if 0
+static void output_entry_point_die PROTO((void *));
+#endif
+static void output_inlined_enumeration_type_die PROTO((void *));
+static void output_inlined_structure_type_die PROTO((void *));
+static void output_inlined_union_type_die PROTO((void *));
+static void output_enumeration_type_die PROTO((void *));
+static void output_formal_parameter_die PROTO((void *));
+static void output_global_subroutine_die PROTO((void *));
+static void output_global_variable_die PROTO((void *));
+static void output_label_die PROTO((void *));
+static void output_lexical_block_die PROTO((void *));
+static void output_inlined_subroutine_die PROTO((void *));
+static void output_local_variable_die PROTO((void *));
+static void output_member_die PROTO((void *));
+#if 0
+static void output_pointer_type_die PROTO((void *));
+static void output_reference_type_die PROTO((void *));
+#endif
+static void output_ptr_to_mbr_type_die PROTO((void *));
+static void output_compile_unit_die PROTO((void *));
+static void output_string_type_die PROTO((void *));
+static void output_inheritance_die PROTO((void *));
+static void output_structure_type_die PROTO((void *));
+static void output_local_subroutine_die PROTO((void *));
+static void output_subroutine_type_die PROTO((void *));
+static void output_typedef_die PROTO((void *));
+static void output_union_type_die PROTO((void *));
+static void output_unspecified_parameters_die PROTO((void *));
+static void output_padded_null_die PROTO((void *));
+static void output_die PROTO((void (*) PROTO((void *)), void *));
+static void end_sibling_chain PROTO((void));
+static void output_formal_types PROTO((tree));
+static void pend_type PROTO((tree));
+static int type_ok_for_scope PROTO((tree, tree));
+static void output_pending_types_for_scope PROTO((tree));
+static void output_type PROTO((tree, tree));
+static void output_tagged_type_instantiation PROTO((tree));
+static void output_block PROTO((tree, int));
+static void output_decls_for_scope PROTO((tree, int));
+static void output_decl PROTO((tree, tree));
+static void shuffle_filename_entry PROTO((filename_entry *));
+static void generate_new_sfname_entry PROTO((void));
+static unsigned lookup_filename PROTO((char *));
+static void generate_srcinfo_entry PROTO((unsigned, unsigned));
+static void generate_macinfo_entry PROTO((char *, char *));
+static int is_pseudo_reg PROTO((rtx));
+static tree type_main_variant PROTO((tree));
+static int is_tagged_type PROTO((tree));
+static int is_redundant_typedef PROTO((tree));
/* Definitions of defaults for assembler-dependent names of various
pseudo-ops and section names.
@@ -410,153 +547,153 @@ static unsigned lookup_filename ();
*/
#ifndef TEXT_BEGIN_LABEL
-#define TEXT_BEGIN_LABEL ".L_text_b"
+#define TEXT_BEGIN_LABEL "*.L_text_b"
#endif
#ifndef TEXT_END_LABEL
-#define TEXT_END_LABEL ".L_text_e"
+#define TEXT_END_LABEL "*.L_text_e"
#endif
#ifndef DATA_BEGIN_LABEL
-#define DATA_BEGIN_LABEL ".L_data_b"
+#define DATA_BEGIN_LABEL "*.L_data_b"
#endif
#ifndef DATA_END_LABEL
-#define DATA_END_LABEL ".L_data_e"
+#define DATA_END_LABEL "*.L_data_e"
#endif
#ifndef DATA1_BEGIN_LABEL
-#define DATA1_BEGIN_LABEL ".L_data1_b"
+#define DATA1_BEGIN_LABEL "*.L_data1_b"
#endif
#ifndef DATA1_END_LABEL
-#define DATA1_END_LABEL ".L_data1_e"
+#define DATA1_END_LABEL "*.L_data1_e"
#endif
#ifndef RODATA_BEGIN_LABEL
-#define RODATA_BEGIN_LABEL ".L_rodata_b"
+#define RODATA_BEGIN_LABEL "*.L_rodata_b"
#endif
#ifndef RODATA_END_LABEL
-#define RODATA_END_LABEL ".L_rodata_e"
+#define RODATA_END_LABEL "*.L_rodata_e"
#endif
#ifndef RODATA1_BEGIN_LABEL
-#define RODATA1_BEGIN_LABEL ".L_rodata1_b"
+#define RODATA1_BEGIN_LABEL "*.L_rodata1_b"
#endif
#ifndef RODATA1_END_LABEL
-#define RODATA1_END_LABEL ".L_rodata1_e"
+#define RODATA1_END_LABEL "*.L_rodata1_e"
#endif
#ifndef BSS_BEGIN_LABEL
-#define BSS_BEGIN_LABEL ".L_bss_b"
+#define BSS_BEGIN_LABEL "*.L_bss_b"
#endif
#ifndef BSS_END_LABEL
-#define BSS_END_LABEL ".L_bss_e"
+#define BSS_END_LABEL "*.L_bss_e"
#endif
#ifndef LINE_BEGIN_LABEL
-#define LINE_BEGIN_LABEL ".L_line_b"
+#define LINE_BEGIN_LABEL "*.L_line_b"
#endif
#ifndef LINE_LAST_ENTRY_LABEL
-#define LINE_LAST_ENTRY_LABEL ".L_line_last"
+#define LINE_LAST_ENTRY_LABEL "*.L_line_last"
#endif
#ifndef LINE_END_LABEL
-#define LINE_END_LABEL ".L_line_e"
+#define LINE_END_LABEL "*.L_line_e"
#endif
#ifndef DEBUG_BEGIN_LABEL
-#define DEBUG_BEGIN_LABEL ".L_debug_b"
+#define DEBUG_BEGIN_LABEL "*.L_debug_b"
#endif
#ifndef SFNAMES_BEGIN_LABEL
-#define SFNAMES_BEGIN_LABEL ".L_sfnames_b"
+#define SFNAMES_BEGIN_LABEL "*.L_sfnames_b"
#endif
#ifndef SRCINFO_BEGIN_LABEL
-#define SRCINFO_BEGIN_LABEL ".L_srcinfo_b"
+#define SRCINFO_BEGIN_LABEL "*.L_srcinfo_b"
#endif
#ifndef MACINFO_BEGIN_LABEL
-#define MACINFO_BEGIN_LABEL ".L_macinfo_b"
+#define MACINFO_BEGIN_LABEL "*.L_macinfo_b"
#endif
#ifndef DIE_BEGIN_LABEL_FMT
-#define DIE_BEGIN_LABEL_FMT ".L_D%u"
+#define DIE_BEGIN_LABEL_FMT "*.L_D%u"
#endif
#ifndef DIE_END_LABEL_FMT
-#define DIE_END_LABEL_FMT ".L_D%u_e"
+#define DIE_END_LABEL_FMT "*.L_D%u_e"
#endif
#ifndef PUB_DIE_LABEL_FMT
-#define PUB_DIE_LABEL_FMT ".L_P%u"
+#define PUB_DIE_LABEL_FMT "*.L_P%u"
#endif
#ifndef INSN_LABEL_FMT
-#define INSN_LABEL_FMT ".L_I%u_%u"
+#define INSN_LABEL_FMT "*.L_I%u_%u"
#endif
#ifndef BLOCK_BEGIN_LABEL_FMT
-#define BLOCK_BEGIN_LABEL_FMT ".L_B%u"
+#define BLOCK_BEGIN_LABEL_FMT "*.L_B%u"
#endif
#ifndef BLOCK_END_LABEL_FMT
-#define BLOCK_END_LABEL_FMT ".L_B%u_e"
+#define BLOCK_END_LABEL_FMT "*.L_B%u_e"
#endif
#ifndef SS_BEGIN_LABEL_FMT
-#define SS_BEGIN_LABEL_FMT ".L_s%u"
+#define SS_BEGIN_LABEL_FMT "*.L_s%u"
#endif
#ifndef SS_END_LABEL_FMT
-#define SS_END_LABEL_FMT ".L_s%u_e"
+#define SS_END_LABEL_FMT "*.L_s%u_e"
#endif
#ifndef EE_BEGIN_LABEL_FMT
-#define EE_BEGIN_LABEL_FMT ".L_e%u"
+#define EE_BEGIN_LABEL_FMT "*.L_e%u"
#endif
#ifndef EE_END_LABEL_FMT
-#define EE_END_LABEL_FMT ".L_e%u_e"
+#define EE_END_LABEL_FMT "*.L_e%u_e"
#endif
#ifndef MT_BEGIN_LABEL_FMT
-#define MT_BEGIN_LABEL_FMT ".L_t%u"
+#define MT_BEGIN_LABEL_FMT "*.L_t%u"
#endif
#ifndef MT_END_LABEL_FMT
-#define MT_END_LABEL_FMT ".L_t%u_e"
+#define MT_END_LABEL_FMT "*.L_t%u_e"
#endif
#ifndef LOC_BEGIN_LABEL_FMT
-#define LOC_BEGIN_LABEL_FMT ".L_l%u"
+#define LOC_BEGIN_LABEL_FMT "*.L_l%u"
#endif
#ifndef LOC_END_LABEL_FMT
-#define LOC_END_LABEL_FMT ".L_l%u_e"
+#define LOC_END_LABEL_FMT "*.L_l%u_e"
#endif
#ifndef BOUND_BEGIN_LABEL_FMT
-#define BOUND_BEGIN_LABEL_FMT ".L_b%u_%u_%c"
+#define BOUND_BEGIN_LABEL_FMT "*.L_b%u_%u_%c"
#endif
#ifndef BOUND_END_LABEL_FMT
-#define BOUND_END_LABEL_FMT ".L_b%u_%u_%c_e"
+#define BOUND_END_LABEL_FMT "*.L_b%u_%u_%c_e"
#endif
#ifndef DERIV_BEGIN_LABEL_FMT
-#define DERIV_BEGIN_LABEL_FMT ".L_d%u"
+#define DERIV_BEGIN_LABEL_FMT "*.L_d%u"
#endif
#ifndef DERIV_END_LABEL_FMT
-#define DERIV_END_LABEL_FMT ".L_d%u_e"
+#define DERIV_END_LABEL_FMT "*.L_d%u_e"
#endif
#ifndef SL_BEGIN_LABEL_FMT
-#define SL_BEGIN_LABEL_FMT ".L_sl%u"
+#define SL_BEGIN_LABEL_FMT "*.L_sl%u"
#endif
#ifndef SL_END_LABEL_FMT
-#define SL_END_LABEL_FMT ".L_sl%u_e"
+#define SL_END_LABEL_FMT "*.L_sl%u_e"
#endif
#ifndef BODY_BEGIN_LABEL_FMT
-#define BODY_BEGIN_LABEL_FMT ".L_b%u"
+#define BODY_BEGIN_LABEL_FMT "*.L_b%u"
#endif
#ifndef BODY_END_LABEL_FMT
-#define BODY_END_LABEL_FMT ".L_b%u_e"
+#define BODY_END_LABEL_FMT "*.L_b%u_e"
#endif
#ifndef FUNC_END_LABEL_FMT
-#define FUNC_END_LABEL_FMT ".L_f%u_e"
+#define FUNC_END_LABEL_FMT "*.L_f%u_e"
#endif
#ifndef TYPE_NAME_FMT
-#define TYPE_NAME_FMT ".L_T%u"
+#define TYPE_NAME_FMT "*.L_T%u"
#endif
#ifndef DECL_NAME_FMT
-#define DECL_NAME_FMT ".L_E%u"
+#define DECL_NAME_FMT "*.L_E%u"
#endif
#ifndef LINE_CODE_LABEL_FMT
-#define LINE_CODE_LABEL_FMT ".L_LC%u"
+#define LINE_CODE_LABEL_FMT "*.L_LC%u"
#endif
#ifndef SFNAMES_ENTRY_LABEL_FMT
-#define SFNAMES_ENTRY_LABEL_FMT ".L_F%u"
+#define SFNAMES_ENTRY_LABEL_FMT "*.L_F%u"
#endif
#ifndef LINE_ENTRY_LABEL_FMT
-#define LINE_ENTRY_LABEL_FMT ".L_LE%u"
+#define LINE_ENTRY_LABEL_FMT "*.L_LE%u"
#endif
/* Definitions of defaults for various types of primitive assembly language
@@ -575,14 +712,6 @@ static unsigned lookup_filename ();
fprintf ((FILE), "\t%s\n", POPSECTION_ASM_OP)
#endif
-#ifndef ASM_OUTPUT_SOURCE_FILENAME
-#define ASM_OUTPUT_SOURCE_FILENAME(FILE,NAME) \
- do { fprintf (FILE, "\t%s\t", FILE_ASM_OP); \
- output_quoted_string (FILE, NAME); \
- fputc ('\n', FILE); \
- } while (0)
-#endif
-
#ifndef ASM_OUTPUT_DWARF_DELTA2
#define ASM_OUTPUT_DWARF_DELTA2(FILE,LABEL1,LABEL2) \
do { fprintf ((FILE), "\t%s\t", UNALIGNED_SHORT_ASM_OP); \
@@ -608,7 +737,7 @@ static unsigned lookup_filename ();
do { \
fprintf ((FILE), "\t%s\t0x%x", \
UNALIGNED_SHORT_ASM_OP, (unsigned) TAG); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_tag_name (TAG)); \
fputc ('\n', (FILE)); \
@@ -620,7 +749,7 @@ static unsigned lookup_filename ();
do { \
fprintf ((FILE), "\t%s\t0x%x", \
UNALIGNED_SHORT_ASM_OP, (unsigned) ATTR); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_attr_name (ATTR)); \
fputc ('\n', (FILE)); \
@@ -631,7 +760,7 @@ static unsigned lookup_filename ();
#define ASM_OUTPUT_DWARF_STACK_OP(FILE,OP) \
do { \
fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) OP); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_stack_op_name (OP)); \
fputc ('\n', (FILE)); \
@@ -643,7 +772,7 @@ static unsigned lookup_filename ();
do { \
fprintf ((FILE), "\t%s\t0x%x", \
UNALIGNED_SHORT_ASM_OP, (unsigned) FT); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_fund_type_name (FT)); \
fputc ('\n', (FILE)); \
@@ -654,7 +783,7 @@ static unsigned lookup_filename ();
#define ASM_OUTPUT_DWARF_FMT_BYTE(FILE,FMT) \
do { \
fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) FMT); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_fmt_byte_name (FMT)); \
fputc ('\n', (FILE)); \
@@ -665,7 +794,7 @@ static unsigned lookup_filename ();
#define ASM_OUTPUT_DWARF_TYPE_MODIFIER(FILE,MOD) \
do { \
fprintf ((FILE), "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) MOD); \
- if (flag_verbose_asm) \
+ if (flag_debug_asm) \
fprintf ((FILE), "\t%s %s", \
ASM_COMMENT_START, dwarf_typemod_name (MOD)); \
fputc ('\n', (FILE)); \
@@ -735,17 +864,7 @@ static unsigned lookup_filename ();
/************************ general utility functions **************************/
-inline char *
-xstrdup (s)
- register char *s;
-{
- register char *p = (char *) xmalloc (strlen (s) + 1);
-
- strcpy (p, s);
- return p;
-}
-
-inline int
+inline static int
is_pseudo_reg (rtl)
register rtx rtl;
{
@@ -754,7 +873,7 @@ is_pseudo_reg (rtl)
&& (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)));
}
-inline tree
+inline static tree
type_main_variant (type)
register tree type;
{
@@ -776,7 +895,7 @@ type_main_variant (type)
/* Return non-zero if the given type node represents a tagged type. */
-inline int
+inline static int
is_tagged_type (type)
register tree type;
{
@@ -963,6 +1082,7 @@ dwarf_fmt_byte_name (fmt)
default: return "FMT_<unknown>";
}
}
+
static char *
dwarf_fund_type_name (ft)
register unsigned ft;
@@ -1009,7 +1129,7 @@ dwarf_fund_type_name (ft)
case FT_unsigned_int32: return "FT_unsigned_int32";
case FT_int64: return "FT_int64";
case FT_signed_int64: return "FT_signed_int64";
- case FT_unsigned_int64: return "FT_signed_int64";
+ case FT_unsigned_int64: return "FT_unsigned_int64";
case FT_real32: return "FT_real32";
case FT_real64: return "FT_real64";
@@ -1080,6 +1200,28 @@ block_ultimate_origin (block)
}
}
+/* Get the class to which DECL belongs, if any. In g++, the DECL_CONTEXT
+ of a virtual function may refer to a base class, so we check the 'this'
+ parameter. */
+
+static tree
+decl_class_context (decl)
+ tree decl;
+{
+ tree context = NULL_TREE;
+ if (TREE_CODE (decl) != FUNCTION_DECL || ! DECL_VINDEX (decl))
+ context = DECL_CONTEXT (decl);
+ else
+ context = TYPE_MAIN_VARIANT
+ (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
+
+ if (context && TREE_CODE_CLASS (TREE_CODE (context)) != 't')
+ context = NULL_TREE;
+
+ return context;
+}
+
+#if 0
static void
output_unsigned_leb128 (value)
register unsigned long value;
@@ -1094,8 +1236,8 @@ output_unsigned_leb128 (value)
if (value != 0) /* more bytes to follow */
byte |= 0x80;
fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) byte);
- if (flag_verbose_asm && value == 0)
- fprintf (asm_out_file, "\t%s ULEB128 number - value = %u",
+ if (flag_debug_asm && value == 0)
+ fprintf (asm_out_file, "\t%s ULEB128 number - value = %lu",
ASM_COMMENT_START, orig_value);
fputc ('\n', asm_out_file);
}
@@ -1126,13 +1268,14 @@ output_signed_leb128 (value)
more = 1;
}
fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) byte);
- if (flag_verbose_asm && more == 0)
- fprintf (asm_out_file, "\t%s SLEB128 number - value = %d",
+ if (flag_debug_asm && more == 0)
+ fprintf (asm_out_file, "\t%s SLEB128 number - value = %ld",
ASM_COMMENT_START, orig_value);
fputc ('\n', asm_out_file);
}
while (more);
}
+#endif
/**************** utility functions for attribute functions ******************/
@@ -1148,7 +1291,7 @@ output_signed_leb128 (value)
FUNCTION_DECL node.
*/
-inline int
+static inline int
is_body_block (stmt)
register tree stmt;
{
@@ -1316,10 +1459,14 @@ fundamental_type_code (type)
qualifiers. */
static tree
-root_type (type)
+root_type_1 (type, count)
register tree type;
+ register int count;
{
- if (TREE_CODE (type) == ERROR_MARK)
+ /* Give up after searching 1000 levels, in case this is a recursive
+ pointer type. Such types are possible in Ada, but it is not possible
+ to represent them in DWARF1 debug info. */
+ if (count > 1000)
return error_mark_node;
switch (TREE_CODE (type))
@@ -1329,25 +1476,42 @@ root_type (type)
case POINTER_TYPE:
case REFERENCE_TYPE:
- return type_main_variant (root_type (TREE_TYPE (type)));
+ return root_type_1 (TREE_TYPE (type), count+1);
default:
- return type_main_variant (type);
+ return type;
}
}
+static tree
+root_type (type)
+ register tree type;
+{
+ type = root_type_1 (type, 0);
+ if (type != error_mark_node)
+ type = type_main_variant (type);
+ return type;
+}
+
/* Given a pointer to an arbitrary ..._TYPE tree node, write out a sequence
of zero or more Dwarf "type-modifier" bytes applicable to the type. */
static void
-write_modifier_bytes (type, decl_const, decl_volatile)
+write_modifier_bytes_1 (type, decl_const, decl_volatile, count)
register tree type;
register int decl_const;
register int decl_volatile;
+ register int count;
{
if (TREE_CODE (type) == ERROR_MARK)
return;
+ /* Give up after searching 1000 levels, in case this is a recursive
+ pointer type. Such types are possible in Ada, but it is not possible
+ to represent them in DWARF1 debug info. */
+ if (count > 1000)
+ return;
+
if (TYPE_READONLY (type) || decl_const)
ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_const);
if (TYPE_VOLATILE (type) || decl_volatile)
@@ -1356,12 +1520,12 @@ write_modifier_bytes (type, decl_const, decl_volatile)
{
case POINTER_TYPE:
ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_pointer_to);
- write_modifier_bytes (TREE_TYPE (type), 0, 0);
+ write_modifier_bytes_1 (TREE_TYPE (type), 0, 0, count+1);
return;
case REFERENCE_TYPE:
ASM_OUTPUT_DWARF_TYPE_MODIFIER (asm_out_file, MOD_reference_to);
- write_modifier_bytes (TREE_TYPE (type), 0, 0);
+ write_modifier_bytes_1 (TREE_TYPE (type), 0, 0, count+1);
return;
case ERROR_MARK:
@@ -1369,11 +1533,20 @@ write_modifier_bytes (type, decl_const, decl_volatile)
return;
}
}
+
+static void
+write_modifier_bytes (type, decl_const, decl_volatile)
+ register tree type;
+ register int decl_const;
+ register int decl_volatile;
+{
+ write_modifier_bytes_1 (type, decl_const, decl_volatile, 0);
+}
/* Given a pointer to an arbitrary ..._TYPE tree node, return non-zero if the
given input type is a Dwarf "fundamental" type. Otherwise return zero. */
-inline int
+static inline int
type_is_fundamental (type)
register tree type;
{
@@ -1454,7 +1627,7 @@ equate_decl_number_to_die_number (decl)
simply by re-generating the alternative name from the ..._TYPE node's
UID number. */
-inline void
+static inline void
equate_type_number_to_die_number (type)
register tree type;
{
@@ -1487,7 +1660,7 @@ output_reg_number (rtl)
}
fprintf (asm_out_file, "\t%s\t0x%x",
UNALIGNED_INT_ASM_OP, DBX_REGISTER_NUMBER (regno));
- if (flag_verbose_asm)
+ if (flag_debug_asm)
{
fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
PRINT_REG (rtl, 0, asm_out_file);
@@ -1574,6 +1747,15 @@ output_mem_loc_descriptor (rtl)
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, INTVAL (rtl));
break;
+ case MULT:
+ /* If a pseudo-reg is optimized away, it is possible for it to
+ be replaced with a MEM containing a multiply. Use a GNU extension
+ to describe it. */
+ output_mem_loc_descriptor (XEXP (rtl, 0));
+ output_mem_loc_descriptor (XEXP (rtl, 1));
+ ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_MULT);
+ break;
+
default:
abort ();
}
@@ -1628,79 +1810,73 @@ output_bound_representation (bound, dim_num, u_or_l)
switch (TREE_CODE (bound))
{
- case ERROR_MARK:
- return;
+ case ERROR_MARK:
+ return;
/* All fixed-bounds are represented by INTEGER_CST nodes. */
- case INTEGER_CST:
- ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
- (unsigned) TREE_INT_CST_LOW (bound));
- break;
-
- /* Dynamic bounds may be represented by NOP_EXPR nodes containing
- SAVE_EXPR nodes. */
-
- case NOP_EXPR:
- bound = TREE_OPERAND (bound, 0);
- /* ... fall thru... */
-
- case SAVE_EXPR:
- {
- char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
- char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
-
- sprintf (begin_label, BOUND_BEGIN_LABEL_FMT,
- current_dienum, dim_num, u_or_l);
-
- sprintf (end_label, BOUND_END_LABEL_FMT,
- current_dienum, dim_num, u_or_l);
-
- ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label);
- ASM_OUTPUT_LABEL (asm_out_file, begin_label);
-
- /* If we are working on a bound for a dynamic dimension in C,
- the dynamic dimension in question had better have a static
- (zero) lower bound and a dynamic *upper* bound. */
+ case INTEGER_CST:
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
+ (unsigned) TREE_INT_CST_LOW (bound));
+ break;
- if (u_or_l != 'u')
- abort ();
+ default:
- /* If optimization is turned on, the SAVE_EXPRs that describe
- how to access the upper bound values are essentially bogus.
- They only describe (at best) how to get at these values at
- the points in the generated code right after they have just
- been computed. Worse yet, in the typical case, the upper
- bound values will not even *be* computed in the optimized
- code, so these SAVE_EXPRs are entirely bogus.
-
- In order to compensate for this fact, we check here to see
- if optimization is enabled, and if so, we effectively create
- an empty location description for the (unknown and unknowable)
- upper bound.
-
- This should not cause too much trouble for existing (stupid?)
- debuggers because they have to deal with empty upper bounds
- location descriptions anyway in order to be able to deal with
- incomplete array types.
-
- Of course an intelligent debugger (GDB?) should be able to
- comprehend that a missing upper bound specification in a
- array type used for a storage class `auto' local array variable
- indicates that the upper bound is both unknown (at compile-
- time) and unknowable (at run-time) due to optimization.
- */
+ /* Dynamic bounds may be represented by NOP_EXPR nodes containing
+ SAVE_EXPR nodes, in which case we can do something, or as
+ an expression, which we cannot represent. */
+ {
+ char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+ sprintf (begin_label, BOUND_BEGIN_LABEL_FMT,
+ current_dienum, dim_num, u_or_l);
+
+ sprintf (end_label, BOUND_END_LABEL_FMT,
+ current_dienum, dim_num, u_or_l);
+
+ ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label);
+ ASM_OUTPUT_LABEL (asm_out_file, begin_label);
+
+ /* If optimization is turned on, the SAVE_EXPRs that describe
+ how to access the upper bound values are essentially bogus.
+ They only describe (at best) how to get at these values at
+ the points in the generated code right after they have just
+ been computed. Worse yet, in the typical case, the upper
+ bound values will not even *be* computed in the optimized
+ code, so these SAVE_EXPRs are entirely bogus.
+
+ In order to compensate for this fact, we check here to see
+ if optimization is enabled, and if so, we effectively create
+ an empty location description for the (unknown and unknowable)
+ upper bound.
+
+ This should not cause too much trouble for existing (stupid?)
+ debuggers because they have to deal with empty upper bounds
+ location descriptions anyway in order to be able to deal with
+ incomplete array types.
+
+ Of course an intelligent debugger (GDB?) should be able to
+ comprehend that a missing upper bound specification in a
+ array type used for a storage class `auto' local array variable
+ indicates that the upper bound is both unknown (at compile-
+ time) and unknowable (at run-time) due to optimization. */
+
+ if (! optimize)
+ {
+ while (TREE_CODE (bound) == NOP_EXPR
+ || TREE_CODE (bound) == CONVERT_EXPR)
+ bound = TREE_OPERAND (bound, 0);
- if (! optimize)
- output_loc_descriptor
- (eliminate_regs (SAVE_EXPR_RTL (bound), 0, NULL_RTX));
+ if (TREE_CODE (bound) == SAVE_EXPR)
+ output_loc_descriptor
+ (eliminate_regs (SAVE_EXPR_RTL (bound), 0, NULL_RTX));
+ }
- ASM_OUTPUT_LABEL (asm_out_file, end_label);
- }
- break;
+ ASM_OUTPUT_LABEL (asm_out_file, end_label);
+ }
+ break;
- default:
- abort ();
}
}
@@ -1725,7 +1901,7 @@ output_enumeral_list (link)
/* Given an unsigned value, round it up to the lowest multiple of `boundary'
which is not less than the value itself. */
-inline unsigned
+static inline unsigned
ceiling (value, boundary)
register unsigned value;
register unsigned boundary;
@@ -1737,7 +1913,7 @@ ceiling (value, boundary)
pointer to the declared type for the relevant field variable, or return
`integer_type_node' if the given node turns out to be an ERROR_MARK node. */
-inline tree
+static inline tree
field_type (decl)
register tree decl;
{
@@ -1756,7 +1932,7 @@ field_type (decl)
node, return the alignment in bits for the type, or else return
BITS_PER_WORD if the node actually turns out to be an ERROR_MARK node. */
-inline unsigned
+static inline unsigned
simple_type_align_in_bits (type)
register tree type;
{
@@ -1769,7 +1945,7 @@ simple_type_align_in_bits (type)
constant, or else return BITS_PER_WORD if the type actually turns out
to be an ERROR_MARK node. */
-inline unsigned
+static inline unsigned
simple_type_size_in_bits (type)
register tree type;
{
@@ -1901,6 +2077,25 @@ field_byte_offset (decl)
/* Compute the offset of the containing object in bytes. */
object_offset_in_bytes = object_offset_in_align_units * type_align_in_bytes;
+ /* The above code assumes that the field does not cross an alignment
+ boundary. This can happen if PCC_BITFIELD_TYPE_MATTERS is not defined,
+ or if the structure is packed. If this happens, then we get an object
+ which starts after the bitfield, which means that the bit offset is
+ negative. Gdb fails when given negative bit offsets. We avoid this
+ by recomputing using the first bit of the bitfield. This will give
+ us an object which does not completely contain the bitfield, but it
+ will be aligned, and it will contain the first bit of the bitfield. */
+ if (object_offset_in_bits > bitpos_int)
+ {
+ deepest_bitpos = bitpos_int + 1;
+ object_offset_in_bits
+ = ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits;
+ object_offset_in_align_units = (object_offset_in_bits
+ / type_align_in_bits);
+ object_offset_in_bytes = (object_offset_in_align_units
+ * type_align_in_bytes);
+ }
+
return object_offset_in_bytes;
}
@@ -1913,7 +2108,7 @@ field_byte_offset (decl)
/* Generate an AT_sibling attribute. */
-inline void
+static inline void
sibling_attribute ()
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
@@ -1964,7 +2159,7 @@ location_attribute (rtl)
if (! is_pseudo_reg (rtl)
&& (GET_CODE (rtl) != MEM || ! is_pseudo_reg (XEXP (rtl, 0))))
- output_loc_descriptor (eliminate_regs (rtl, 0, NULL_RTX));
+ output_loc_descriptor (rtl);
ASM_OUTPUT_LABEL (asm_out_file, end_label);
}
@@ -1988,17 +2183,21 @@ location_attribute (rtl)
object" which will be given in the AT_byte_size attribute for this
bit-field. (See the `byte_size_attribute' function below.) It is
also used when calculating the value of the AT_bit_offset attribute.
- (See the `bit_offset_attribute' function below.)
-*/
+ (See the `bit_offset_attribute' function below.) */
static void
-data_member_location_attribute (decl)
- register tree decl;
+data_member_location_attribute (t)
+ register tree t;
{
- register unsigned object_offset_in_bytes = field_byte_offset (decl);
+ register unsigned object_offset_in_bytes;
char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+ if (TREE_CODE (t) == TREE_VEC)
+ object_offset_in_bytes = TREE_INT_CST_LOW (BINFO_OFFSET (t));
+ else
+ object_offset_in_bytes = field_byte_offset (t);
+
ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_location);
sprintf (begin_label, LOC_BEGIN_LABEL_FMT, current_dienum);
sprintf (end_label, LOC_END_LABEL_FMT, current_dienum);
@@ -2186,7 +2385,7 @@ location_or_const_value_attribute (decl)
shouldn't be happening. All PARM_DECL nodes should get valid non-NULL
DECL_INCOMING_RTL values, but integrate.c doesn't currently generate
these values for inlined instances of inline function parameters, so
- when we see such cases, we are just SOL (shit-out-of-luck) for the time
+ when we see such cases, we are just out-of-luck for the time
being (until integrate.c gets fixed).
*/
@@ -2214,8 +2413,19 @@ location_or_const_value_attribute (decl)
if (rtl == NULL_RTX)
return;
+ rtl = eliminate_regs (rtl, 0, NULL_RTX);
+#ifdef LEAF_REG_REMAP
+ if (leaf_function)
+ leaf_renumber_regs_insn (rtl);
+#endif
+
switch (GET_CODE (rtl))
{
+ case ADDRESSOF:
+ /* The address of a variable that was optimized away; don't emit
+ anything. */
+ break;
+
case CONST_INT:
case CONST_DOUBLE:
case CONST_STRING:
@@ -2232,6 +2442,15 @@ location_or_const_value_attribute (decl)
location_attribute (rtl);
break;
+ case CONCAT:
+ /* ??? CONCAT is used for complex variables, which may have the real
+ part stored in one place and the imag part stored somewhere else.
+ DWARF1 has no way to describe a variable that lives in two different
+ places, so we just describe where the first part lives, and hope that
+ the second part is stored after it. */
+ location_attribute (XEXP (rtl, 0));
+ break;
+
default:
abort (); /* Should never happen. */
}
@@ -2240,7 +2459,7 @@ location_or_const_value_attribute (decl)
/* Generate an AT_name attribute given some string value to be included as
the value of the attribute. */
-inline void
+static inline void
name_attribute (name_string)
register char *name_string;
{
@@ -2251,7 +2470,7 @@ name_attribute (name_string)
}
}
-inline void
+static inline void
fund_type_attribute (ft_code)
register unsigned ft_code;
{
@@ -2279,7 +2498,7 @@ mod_fund_type_attribute (type, decl_const, decl_volatile)
ASM_OUTPUT_LABEL (asm_out_file, end_label);
}
-inline void
+static inline void
user_def_type_attribute (type)
register tree type;
{
@@ -2312,7 +2531,7 @@ mod_u_d_type_attribute (type, decl_const, decl_volatile)
}
#ifdef USE_ORDERING_ATTRIBUTE
-inline void
+static inline void
ordering_attribute (ordering)
register unsigned ordering;
{
@@ -2369,12 +2588,11 @@ subscript_data_attribute (type)
if (! type_is_fundamental (domain))
abort ();
- /* Output the representation format byte for this dimension. */
+ /* Output the representation format byte for this dimension. */
ASM_OUTPUT_DWARF_FMT_BYTE (asm_out_file,
- FMT_CODE (1,
- TREE_CODE (lower) == INTEGER_CST,
- TREE_CODE (upper) == INTEGER_CST));
+ FMT_CODE (1, TREE_CODE (lower) == INTEGER_CST,
+ (upper && TREE_CODE (upper) == INTEGER_CST)));
/* Output the index type for this dimension. */
@@ -2443,6 +2661,7 @@ byte_size_attribute (tree_node)
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
+ case ARRAY_TYPE:
size = int_size_in_bytes (tree_node);
break;
@@ -2483,10 +2702,9 @@ byte_size_attribute (tree_node)
Note that it is the size (in bytes) of the hypothetical "containing
object" which will be given in the AT_byte_size attribute for this
- bit-field. (See `byte_size_attribute' above.)
-*/
+ bit-field. (See `byte_size_attribute' above.) */
-inline void
+static inline void
bit_offset_attribute (decl)
register tree decl;
{
@@ -2498,8 +2716,10 @@ bit_offset_attribute (decl)
register unsigned highest_order_field_bit_offset;
register unsigned bit_offset;
- assert (TREE_CODE (decl) == FIELD_DECL); /* Must be a field. */
- assert (type); /* Must be a bit field. */
+ /* Must be a bit field. */
+ if (!type
+ || TREE_CODE (decl) != FIELD_DECL)
+ abort ();
/* We can't yet handle bit-fields whose offsets are variable, so if we
encounter such things, just return without generating any attribute
@@ -2538,12 +2758,14 @@ bit_offset_attribute (decl)
/* For a FIELD_DECL node which represents a bit field, output an attribute
which specifies the length in bits of the given field. */
-inline void
+static inline void
bit_size_attribute (decl)
register tree decl;
{
- assert (TREE_CODE (decl) == FIELD_DECL); /* Must be a field. */
- assert (DECL_BIT_FIELD_TYPE (decl)); /* Must be a bit field. */
+ /* Must be a field and a bit field. */
+ if (TREE_CODE (decl) != FIELD_DECL
+ || ! DECL_BIT_FIELD_TYPE (decl))
+ abort ();
ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_bit_size);
ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
@@ -2555,7 +2777,7 @@ bit_size_attribute (decl)
all of the enumeration constants associated with the given enumeration
type. */
-inline void
+static inline void
element_list_attribute (element)
register tree element;
{
@@ -2581,7 +2803,7 @@ element_list_attribute (element)
/* Generate an AT_stmt_list attribute. These are normally present only in
DIEs with a TAG_compile_unit tag. */
-inline void
+static inline void
stmt_list_attribute (label)
register char *label;
{
@@ -2593,7 +2815,7 @@ stmt_list_attribute (label)
/* Generate an AT_low_pc attribute for a label DIE, a lexical_block DIE or
for a subroutine DIE. */
-inline void
+static inline void
low_pc_attribute (asm_low_label)
register char *asm_low_label;
{
@@ -2604,7 +2826,7 @@ low_pc_attribute (asm_low_label)
/* Generate an AT_high_pc attribute for a lexical_block DIE or for a
subroutine DIE. */
-inline void
+static inline void
high_pc_attribute (asm_high_label)
register char *asm_high_label;
{
@@ -2614,7 +2836,7 @@ high_pc_attribute (asm_high_label)
/* Generate an AT_body_begin attribute for a subroutine DIE. */
-inline void
+static inline void
body_begin_attribute (asm_begin_label)
register char *asm_begin_label;
{
@@ -2624,7 +2846,7 @@ body_begin_attribute (asm_begin_label)
/* Generate an AT_body_end attribute for a subroutine DIE. */
-inline void
+static inline void
body_end_attribute (asm_end_label)
register char *asm_end_label;
{
@@ -2635,7 +2857,7 @@ body_end_attribute (asm_end_label)
/* Generate an AT_language attribute given a LANG value. These attributes
are used only within TAG_compile_unit DIEs. */
-inline void
+static inline void
language_attribute (language_code)
register unsigned language_code;
{
@@ -2643,7 +2865,7 @@ language_attribute (language_code)
ASM_OUTPUT_DWARF_DATA4 (asm_out_file, language_code);
}
-inline void
+static inline void
member_attribute (context)
register tree context;
{
@@ -2659,7 +2881,8 @@ member_attribute (context)
}
}
-inline void
+#if 0
+static inline void
string_length_attribute (upper_bound)
register tree upper_bound;
{
@@ -2674,8 +2897,9 @@ string_length_attribute (upper_bound)
output_bound_representation (upper_bound, 0, 'u');
ASM_OUTPUT_LABEL (asm_out_file, end_label);
}
+#endif
-inline void
+static inline void
comp_dir_attribute (dirname)
register char *dirname;
{
@@ -2683,7 +2907,7 @@ comp_dir_attribute (dirname)
ASM_OUTPUT_DWARF_STRING (asm_out_file, dirname);
}
-inline void
+static inline void
sf_names_attribute (sf_names_start_label)
register char *sf_names_start_label;
{
@@ -2692,7 +2916,7 @@ sf_names_attribute (sf_names_start_label)
ASM_OUTPUT_DWARF_ADDR (asm_out_file, sf_names_start_label);
}
-inline void
+static inline void
src_info_attribute (src_info_start_label)
register char *src_info_start_label;
{
@@ -2701,7 +2925,7 @@ src_info_attribute (src_info_start_label)
ASM_OUTPUT_DWARF_ADDR (asm_out_file, src_info_start_label);
}
-inline void
+static inline void
mac_info_attribute (mac_info_start_label)
register char *mac_info_start_label;
{
@@ -2710,7 +2934,7 @@ mac_info_attribute (mac_info_start_label)
ASM_OUTPUT_DWARF_ADDR (asm_out_file, mac_info_start_label);
}
-inline void
+static inline void
prototyped_attribute (func_type)
register tree func_type;
{
@@ -2722,7 +2946,7 @@ prototyped_attribute (func_type)
}
}
-inline void
+static inline void
producer_attribute (producer)
register char *producer;
{
@@ -2730,7 +2954,7 @@ producer_attribute (producer)
ASM_OUTPUT_DWARF_STRING (asm_out_file, producer);
}
-inline void
+static inline void
inline_attribute (decl)
register tree decl;
{
@@ -2741,7 +2965,7 @@ inline_attribute (decl)
}
}
-inline void
+static inline void
containing_type_attribute (containing_type)
register tree containing_type;
{
@@ -2752,7 +2976,7 @@ containing_type_attribute (containing_type)
ASM_OUTPUT_DWARF_REF (asm_out_file, label);
}
-inline void
+static inline void
abstract_origin_attribute (origin)
register tree origin;
{
@@ -2777,7 +3001,7 @@ abstract_origin_attribute (origin)
}
#ifdef DWARF_DECL_COORDINATES
-inline void
+static inline void
src_coords_attribute (src_fileno, src_lineno)
register unsigned src_fileno;
register unsigned src_lineno;
@@ -2788,7 +3012,7 @@ src_coords_attribute (src_fileno, src_lineno)
}
#endif /* defined(DWARF_DECL_COORDINATES) */
-inline void
+static inline void
pure_or_virtual_attribute (func_decl)
register tree func_decl;
{
@@ -2827,7 +3051,7 @@ name_and_src_coords_attributes (decl)
/* This is annoying, but we have to pop out of the .debug section
for a moment while we call `lookup_filename' because calling it
may cause a temporary switch into the .debug_sfnames section and
- most svr4 assemblers are not smart enough be be able to nest
+ most svr4 assemblers are not smart enough to be able to nest
section switches to any depth greater than one. Note that we
also can't skirt this issue by delaying all output to the
.debug_sfnames section unit the end of compilation because that
@@ -2856,29 +3080,38 @@ type_attribute (type, decl_const, decl_volatile)
register enum tree_code code = TREE_CODE (type);
register int root_type_modified;
- if (TREE_CODE (type) == ERROR_MARK)
+ if (code == ERROR_MARK)
return;
/* Handle a special case. For functions whose return type is void,
we generate *no* type attribute. (Note that no object may have
type `void', so this only applies to function return types. */
- if (TREE_CODE (type) == VOID_TYPE)
+ if (code == VOID_TYPE)
return;
+ /* If this is a subtype, find the underlying type. Eventually,
+ this should write out the appropriate subtype info. */
+ while ((code == INTEGER_TYPE || code == REAL_TYPE)
+ && TREE_TYPE (type) != 0)
+ type = TREE_TYPE (type), code = TREE_CODE (type);
+
root_type_modified = (code == POINTER_TYPE || code == REFERENCE_TYPE
|| decl_const || decl_volatile
|| TYPE_READONLY (type) || TYPE_VOLATILE (type));
if (type_is_fundamental (root_type (type)))
- if (root_type_modified)
+ {
+ if (root_type_modified)
mod_fund_type_attribute (type, decl_const, decl_volatile);
- else
+ else
fund_type_attribute (fundamental_type_code (type));
+ }
else
- if (root_type_modified)
+ {
+ if (root_type_modified)
mod_u_d_type_attribute (type, decl_const, decl_volatile);
- else
+ else
/* We have to get the type_main_variant here (and pass that to the
`user_def_type_attribute' routine) because the ..._TYPE node we
have might simply be a *copy* of some original type node (where
@@ -2889,6 +3122,7 @@ type_attribute (type, decl_const, decl_volatile)
only creates labels for DIEs representing *main variants*, and it
never even knows about non-main-variants.) */
user_def_type_attribute (type_main_variant (type));
+ }
}
/* Given a tree pointer to a struct, class, union, or enum type node, return
@@ -2908,25 +3142,14 @@ type_tag (type)
/* Find the IDENTIFIER_NODE for the type name. */
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
t = TYPE_NAME (type);
-#if 0
- /* The g++ front end makes the TYPE_NAME of *each* tagged type point
- to a TYPE_DECL node, regardless of whether or not a `typedef' was
- involved. This is distinctly different from what the gcc front-end
- does. It always makes the TYPE_NAME for each tagged type be either
- NULL (signifying an anonymous tagged type) or else a pointer to an
- IDENTIFIER_NODE. Obviously, we would like to generate correct Dwarf
- for both C and C++, but given this inconsistency in the TREE
- representation of tagged types for C and C++ in the GNU front-ends,
- we cannot support both languages correctly unless we introduce some
- front-end specific code here, and rms objects to that, so we can
- only generate correct Dwarf for one of these two languages. C is
- more important, so for now we'll do the right thing for C and let
- g++ go fish. */
- else
- if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL)
+ /* The g++ front end makes the TYPE_NAME of *each* tagged type point to
+ a TYPE_DECL node, regardless of whether or not a `typedef' was
+ involved. */
+ else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+ && ! DECL_IGNORED_P (TYPE_NAME (type)))
t = DECL_NAME (TYPE_NAME (type));
-#endif
+
/* Now get the name as a string, or invent one. */
if (t != 0)
name = IDENTIFIER_POINTER (t);
@@ -2935,7 +3158,7 @@ type_tag (type)
return (name == 0 || *name == '\0') ? 0 : name;
}
-inline void
+static inline void
dienum_push ()
{
/* Start by checking if the pending_sibling_stack needs to be expanded.
@@ -2956,13 +3179,13 @@ dienum_push ()
/* Pop the sibling stack so that the most recently pushed DIEnum becomes the
NEXT_DIE_NUM. */
-inline void
+static inline void
dienum_pop ()
{
pending_siblings--;
}
-inline tree
+static inline tree
member_declared_type (member)
register tree member;
{
@@ -3041,6 +3264,7 @@ output_set_type_die (arg)
#if 0
/* Implement this when there is a GNU FORTRAN or GNU Ada front end. */
+
static void
output_entry_point_die (arg)
register void *arg;
@@ -3076,7 +3300,8 @@ output_inlined_enumeration_type_die (arg)
ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_enumeration_type);
sibling_attribute ();
- assert (TREE_ASM_WRITTEN (type));
+ if (!TREE_ASM_WRITTEN (type))
+ abort ();
abstract_origin_attribute (type);
}
@@ -3090,7 +3315,8 @@ output_inlined_structure_type_die (arg)
ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_structure_type);
sibling_attribute ();
- assert (TREE_ASM_WRITTEN (type));
+ if (!TREE_ASM_WRITTEN (type))
+ abort ();
abstract_origin_attribute (type);
}
@@ -3104,7 +3330,8 @@ output_inlined_union_type_die (arg)
ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_union_type);
sibling_attribute ();
- assert (TREE_ASM_WRITTEN (type));
+ if (!TREE_ASM_WRITTEN (type))
+ abort ();
abstract_origin_attribute (type);
}
@@ -3217,17 +3444,21 @@ output_global_subroutine_die (arg)
equate_decl_number_to_die_number (decl);
else
{
- if (! DECL_EXTERNAL (decl))
+ if (! DECL_EXTERNAL (decl) && ! in_class
+ && decl == current_function_decl)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
low_pc_attribute (function_start_label (decl));
sprintf (label, FUNC_END_LABEL_FMT, current_funcdef_number);
high_pc_attribute (label);
- sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
- body_begin_attribute (label);
- sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
- body_end_attribute (label);
+ if (use_gnu_debug_info_extensions)
+ {
+ sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
+ body_begin_attribute (label);
+ sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
+ body_end_attribute (label);
+ }
}
}
}
@@ -3257,7 +3488,8 @@ output_global_variable_die (arg)
equate_decl_number_to_die_number (decl);
else
{
- if (!DECL_EXTERNAL (decl))
+ if (! DECL_EXTERNAL (decl) && ! in_class
+ && current_function_decl == decl_function_context (decl))
location_or_const_value_attribute (decl);
}
}
@@ -3383,7 +3615,7 @@ output_member_die (arg)
member_attribute (DECL_CONTEXT (decl));
type_attribute (member_declared_type (decl),
TREE_READONLY (decl), TREE_THIS_VOLATILE (decl));
- if (DECL_BIT_FIELD_TYPE (decl)) /* If this is a bit field... */
+ if (DECL_BIT_FIELD_TYPE (decl)) /* If this is a bit field... */
{
byte_size_attribute (decl);
bit_size_attribute (decl);
@@ -3396,9 +3628,9 @@ output_member_die (arg)
/* Don't generate either pointer_type DIEs or reference_type DIEs. Use
modified types instead.
- We keep this code here just in case these types of DIEs may be needed
- to represent certain things in other languages (e.g. Pascal) someday.
-*/
+ We keep this code here just in case these types of DIEs may be
+ needed to represent certain things in other languages (e.g. Pascal)
+ someday. */
static void
output_pointer_type_die (arg)
@@ -3465,6 +3697,8 @@ output_compile_unit_die (arg)
language_attribute (LANG_ADA83);
else if (strcmp (language_string, "GNU F77") == 0)
language_attribute (LANG_FORTRAN77);
+ else if (strcmp (language_string, "GNU Pascal") == 0)
+ language_attribute (LANG_PASCAL83);
else if (flag_traditional)
language_attribute (LANG_C);
else
@@ -3481,7 +3715,7 @@ output_compile_unit_die (arg)
comp_dir_attribute (wd);
}
- if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ if (debug_info_level >= DINFO_LEVEL_NORMAL && use_gnu_debug_info_extensions)
{
sf_names_attribute (SFNAMES_BEGIN_LABEL);
src_info_attribute (SRCINFO_BEGIN_LABEL);
@@ -3498,12 +3732,38 @@ output_string_type_die (arg)
ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_string_type);
sibling_attribute ();
+ equate_type_number_to_die_number (type);
member_attribute (TYPE_CONTEXT (type));
+ /* this is a fixed length string */
+ byte_size_attribute (type);
+}
- /* Fudge the string length attribute for now. */
+static void
+output_inheritance_die (arg)
+ register void *arg;
+{
+ register tree binfo = arg;
- string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
-}
+ ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_inheritance);
+ sibling_attribute ();
+ type_attribute (BINFO_TYPE (binfo), 0, 0);
+ data_member_location_attribute (binfo);
+ if (TREE_VIA_VIRTUAL (binfo))
+ {
+ ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_virtual);
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, "");
+ }
+ if (TREE_VIA_PUBLIC (binfo))
+ {
+ ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_public);
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, "");
+ }
+ else if (TREE_VIA_PROTECTED (binfo))
+ {
+ ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_protected);
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, "");
+ }
+}
static void
output_structure_type_die (arg)
@@ -3569,10 +3829,13 @@ output_local_subroutine_die (arg)
low_pc_attribute (function_start_label (decl));
sprintf (label, FUNC_END_LABEL_FMT, current_funcdef_number);
high_pc_attribute (label);
- sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
- body_begin_attribute (label);
- sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
- body_end_attribute (label);
+ if (use_gnu_debug_info_extensions)
+ {
+ sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
+ body_begin_attribute (label);
+ sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
+ body_end_attribute (label);
+ }
}
}
}
@@ -3671,7 +3934,7 @@ output_unspecified_parameters_die (arg)
static void
output_padded_null_die (arg)
- register void *arg;
+ register void *arg ATTRIBUTE_UNUSED;
{
ASM_OUTPUT_ALIGN (asm_out_file, 2); /* 2**2 == 4 */
}
@@ -3686,7 +3949,7 @@ output_padded_null_die (arg)
static void
output_die (die_specific_output_function, param)
- register void (*die_specific_output_function)();
+ register void (*die_specific_output_function) PROTO ((void *));
register void *param;
{
char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
@@ -3742,11 +4005,11 @@ end_sibling_chain ()
parameters as specified in some function type specification (except
for those which appear as part of a function *definition*).
- Note that we must be careful here to output all of the parameter DIEs
- *before* we output any DIEs needed to represent the types of the formal
- parameters. This keeps svr4 SDB happy because it (incorrectly) thinks
- that the first non-parameter DIE it sees ends the formal parameter list.
-*/
+ Note that we must be careful here to output all of the parameter
+ DIEs *before* we output any DIEs needed to represent the types of
+ the formal parameters. This keeps svr4 SDB happy because it
+ (incorrectly) thinks that the first non-parameter DIE it sees ends
+ the formal parameter list. */
static void
output_formal_types (function_or_method_type)
@@ -3756,6 +4019,12 @@ output_formal_types (function_or_method_type)
register tree formal_type = NULL;
register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
+ /* Set TREE_ASM_WRITTEN while processing the parameters, lest we
+ get bogus recursion when outputting tagged types local to a
+ function declaration. */
+ int save_asm_written = TREE_ASM_WRITTEN (function_or_method_type);
+ TREE_ASM_WRITTEN (function_or_method_type) = 1;
+
/* In the case where we are generating a formal types list for a C++
non-static member function type, skip over the first thing on the
TYPE_ARG_TYPES list because it only represents the type of the
@@ -3801,6 +4070,8 @@ output_formal_types (function_or_method_type)
output_type (formal_type, function_or_method_type);
}
+
+ TREE_ASM_WRITTEN (function_or_method_type) = save_asm_written;
}
/* Remember a type in the pending_types_list. */
@@ -3859,10 +4130,9 @@ pend_type (type)
been output are instead placed onto the pending_types_list. Later on,
we force these (temporarily pended) types to be output simply by calling
`output_pending_types_for_scope' with an actual argument equal to the
- true scope of the types we temporarily pended.
-*/
+ true scope of the types we temporarily pended. */
-inline int
+static inline int
type_ok_for_scope (type, scope)
register tree type;
register tree scope;
@@ -3879,7 +4149,12 @@ type_ok_for_scope (type, scope)
(for C and C++ anyway) will be array types and function types. */
return is_tagged_type (type)
- ? (TYPE_CONTEXT (type) == scope)
+ ? (TYPE_CONTEXT (type) == scope
+ /* Ignore namespaces for the moment. */
+ || (scope == NULL_TREE
+ && TREE_CODE (TYPE_CONTEXT (type)) == NAMESPACE_DECL)
+ || (scope == NULL_TREE && is_tagged_type (TYPE_CONTEXT (type))
+ && TREE_ASM_WRITTEN (TYPE_CONTEXT (type))))
: (scope == NULL_TREE || ! is_tagged_type (scope));
}
@@ -3892,8 +4167,7 @@ type_ok_for_scope (type, scope)
Note that we have to process the list in beginning-to-end order,
because the call made here to output_type may cause yet more types
to be added to the end of the list, and we may have to output some
- of them too.
-*/
+ of them too. */
static void
output_pending_types_for_scope (containing_scope)
@@ -3940,13 +4214,39 @@ output_type (type, containing_scope)
return;
/* We are going to output a DIE to represent the unqualified version of
- of this type (i.e. without any const or volatile qualifiers) so get
+ this type (i.e. without any const or volatile qualifiers) so get
the main variant (i.e. the unqualified version) of this type now. */
type = type_main_variant (type);
if (TREE_ASM_WRITTEN (type))
- return;
+ {
+ if (finalizing && AGGREGATE_TYPE_P (type))
+ {
+ register tree member;
+
+ /* Some of our nested types might not have been defined when we
+ were written out before; force them out now. */
+
+ for (member = TYPE_FIELDS (type); member;
+ member = TREE_CHAIN (member))
+ if (TREE_CODE (member) == TYPE_DECL
+ && ! TREE_ASM_WRITTEN (TREE_TYPE (member)))
+ output_type (TREE_TYPE (member), containing_scope);
+ }
+ return;
+ }
+
+ /* If this is a nested type whose containing class hasn't been
+ written out yet, writing it out will cover this one, too. */
+
+ if (TYPE_CONTEXT (type)
+ && TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't'
+ && ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
+ {
+ output_type (TYPE_CONTEXT (type), containing_scope);
+ return;
+ }
/* Don't generate any DIEs for this type now unless it is OK to do so
(based upon what `type_ok_for_scope' tells us). */
@@ -3964,6 +4264,9 @@ output_type (type, containing_scope)
case POINTER_TYPE:
case REFERENCE_TYPE:
+ /* Prevent infinite recursion in cases where this is a recursive
+ type. Recursive types are possible in Ada. */
+ TREE_ASM_WRITTEN (type) = 1;
/* For these types, all that is required is that we output a DIE
(or a set of DIEs) to represent the "basis" type. */
output_type (TREE_TYPE (type), containing_scope);
@@ -4058,10 +4361,14 @@ output_type (type, containing_scope)
time, we will certainly know as much about each file-scope tagged
type as we are ever going to know, so at that point in time, we
can safely generate correct Dwarf descriptions for these file-
- scope tagged types.
- */
-
- if (TYPE_SIZE (type) == 0 && TYPE_CONTEXT (type) == NULL && !finalizing)
+ scope tagged types. */
+
+ if (TYPE_SIZE (type) == 0
+ && (TYPE_CONTEXT (type) == NULL
+ || (TREE_CODE_CLASS (TREE_CODE (TYPE_CONTEXT (type))) == 't'
+ && TREE_CODE (TYPE_CONTEXT (type)) != FUNCTION_TYPE
+ && TREE_CODE (TYPE_CONTEXT (type)) != METHOD_TYPE))
+ && !finalizing)
return; /* EARLY EXIT! Avoid setting TREE_ASM_WRITTEN. */
/* Prevent infinite recursion in cases where the type of some
@@ -4109,10 +4416,23 @@ output_type (type, containing_scope)
if (TYPE_SIZE (type))
{
+ /* First output info about the base classes. */
+ if (TYPE_BINFO (type) && TYPE_BINFO_BASETYPES (type))
+ {
+ register tree bases = TYPE_BINFO_BASETYPES (type);
+ register int n_bases = TREE_VEC_LENGTH (bases);
+ register int i;
+
+ for (i = 0; i < n_bases; i++)
+ output_die (output_inheritance_die, TREE_VEC_ELT (bases, i));
+ }
+
+ ++in_class;
+
{
register tree normal_member;
- /* First output info about the data members and type members. */
+ /* Now output info about the data members and type members. */
for (normal_member = TYPE_FIELDS (type);
normal_member;
@@ -4121,32 +4441,18 @@ output_type (type, containing_scope)
}
{
- register tree vec_base;
+ register tree func_member;
/* Now output info about the function members (if any). */
- vec_base = TYPE_METHODS (type);
- if (vec_base)
- {
- register tree first_func_member = TREE_VEC_ELT (vec_base, 0);
- register tree func_member;
-
- /* This isn't documented, but the first element of the
- vector of member functions can be NULL in cases where
- the class type in question didn't have either a
- constructor or a destructor declared for it. We have
- to make allowances for that here. */
-
- if (first_func_member == NULL)
- first_func_member = TREE_VEC_ELT (vec_base, 1);
-
- for (func_member = first_func_member;
- func_member;
- func_member = TREE_CHAIN (func_member))
- output_decl (func_member, type);
- }
+ for (func_member = TYPE_METHODS (type);
+ func_member;
+ func_member = TREE_CHAIN (func_member))
+ output_decl (func_member, type);
}
+ --in_class;
+
/* RECORD_TYPEs, UNION_TYPEs, and QUAL_UNION_TYPEs are themselves
scopes (at least in C++) so we must now output any nested
pending types which are local just to this type. */
@@ -4184,13 +4490,15 @@ output_tagged_type_instantiation (type)
return;
/* We are going to output a DIE to represent the unqualified version of
- of this type (i.e. without any const or volatile qualifiers) so make
+ this type (i.e. without any const or volatile qualifiers) so make
sure that we have the main variant (i.e. the unqualified version) of
this type now. */
- assert (type == type_main_variant (type));
+ if (type != type_main_variant (type))
+ abort ();
- assert (TREE_ASM_WRITTEN (type));
+ if (!TREE_ASM_WRITTEN (type))
+ abort ();
switch (TREE_CODE (type))
{
@@ -4219,8 +4527,9 @@ output_tagged_type_instantiation (type)
the things which are local to the given block. */
static void
-output_block (stmt)
+output_block (stmt, depth)
register tree stmt;
+ int depth;
{
register int must_output_die = 0;
register tree origin;
@@ -4258,7 +4567,7 @@ output_block (stmt)
not represent a "body block inlining" before trying to set the
`must_output_die' flag. */
- if (origin == NULL || ! is_body_block (origin))
+ if (! is_body_block (origin ? origin : stmt))
{
/* Determine if this block directly contains any "significant"
local declarations which we will need to output DIEs for. */
@@ -4292,32 +4601,35 @@ output_block (stmt)
a "significant" local declaration gets restricted to include only
inlined function instances and local (nested) function definitions. */
- if (must_output_die)
+ if (origin_code == FUNCTION_DECL && BLOCK_ABSTRACT (stmt))
+ /* We don't care about an abstract inlined subroutine. */;
+ else if (must_output_die)
{
output_die ((origin_code == FUNCTION_DECL)
? output_inlined_subroutine_die
: output_lexical_block_die,
stmt);
- output_decls_for_scope (stmt);
+ output_decls_for_scope (stmt, depth);
end_sibling_chain ();
}
else
- output_decls_for_scope (stmt);
+ output_decls_for_scope (stmt, depth);
}
/* Output all of the decls declared within a given scope (also called
a `binding contour') and (recursively) all of it's sub-blocks. */
static void
-output_decls_for_scope (stmt)
+output_decls_for_scope (stmt, depth)
register tree stmt;
+ int depth;
{
/* Ignore blocks never really used to make RTL. */
if (! stmt || ! TREE_USED (stmt))
return;
- if (! BLOCK_ABSTRACT (stmt))
+ if (! BLOCK_ABSTRACT (stmt) && depth > 0)
next_block_number++;
/* Output the DIEs to represent all of the data objects, functions,
@@ -4342,10 +4654,28 @@ output_decls_for_scope (stmt)
for (subblocks = BLOCK_SUBBLOCKS (stmt);
subblocks;
subblocks = BLOCK_CHAIN (subblocks))
- output_block (subblocks);
+ output_block (subblocks, depth + 1);
}
}
+/* Is this a typedef we can avoid emitting? */
+
+inline static int
+is_redundant_typedef (decl)
+ register tree decl;
+{
+ if (TYPE_DECL_IS_STUB (decl))
+ return 1;
+ if (DECL_ARTIFICIAL (decl)
+ && DECL_CONTEXT (decl)
+ && is_tagged_type (DECL_CONTEXT (decl))
+ && TREE_CODE (TYPE_NAME (DECL_CONTEXT (decl))) == TYPE_DECL
+ && DECL_NAME (decl) == DECL_NAME (TYPE_NAME (DECL_CONTEXT (decl))))
+ /* Also ignore the artificial member typedef for the class name. */
+ return 1;
+ return 0;
+}
+
/* Output Dwarf .debug information for a decl described by DECL. */
static void
@@ -4376,7 +4706,7 @@ output_decl (decl, containing_scope)
/* If this ..._DECL node is marked to be ignored, then ignore it.
But don't ignore a function definition, since that would screw
up our count of blocks, and that it turn will completely screw up the
- the labels we will reference in subsequent AT_low_pc and AT_high_pc
+ labels we will reference in subsequent AT_low_pc and AT_high_pc
attributes (for subsequent blocks). */
if (DECL_IGNORED_P (decl) && TREE_CODE (decl) != FUNCTION_DECL)
@@ -4406,6 +4736,13 @@ output_decl (decl, containing_scope)
output_type (TREE_TYPE (TREE_TYPE (decl)), containing_scope);
+ {
+ /* And its containing type. */
+ register tree origin = decl_class_context (decl);
+ if (origin)
+ output_type (origin, containing_scope);
+ }
+
/* If the following DIE will represent a function definition for a
function with "extern" linkage, output a special "pubnames" DIE
label just ahead of the actual DIE. A reference to this label
@@ -4442,7 +4779,7 @@ output_decl (decl, containing_scope)
we need to do here (and all we *can* do here) is to describe
the *types* of its formal parameters. */
- if (DECL_INITIAL (decl) == NULL_TREE)
+ if (decl != current_function_decl || in_class)
output_formal_types (TREE_TYPE (decl));
else
{
@@ -4521,7 +4858,7 @@ output_decl (decl, containing_scope)
if (fn_arg_types)
{
- /* this is the prototyped case, check for ... */
+ /* this is the prototyped case, check for ... */
if (TREE_VALUE (tree_last (fn_arg_types)) != void_type_node)
output_die (output_unspecified_parameters_die, decl);
}
@@ -4532,61 +4869,45 @@ output_decl (decl, containing_scope)
output_die (output_unspecified_parameters_die, decl);
}
}
- }
- /* Output Dwarf info for all of the stuff within the body of the
- function (if it has one - it may be just a declaration). */
+ /* Output Dwarf info for all of the stuff within the body of the
+ function (if it has one - it may be just a declaration). */
- {
- register tree outer_scope = DECL_INITIAL (decl);
-
- if (outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
{
- /* Note that here, `outer_scope' is a pointer to the outermost
- BLOCK node created to represent a function.
- This outermost BLOCK actually represents the outermost
- binding contour for the function, i.e. the contour in which
- the function's formal parameters and labels get declared.
-
- Curiously, it appears that the front end doesn't actually
- put the PARM_DECL nodes for the current function onto the
- BLOCK_VARS list for this outer scope. (They are strung
- off of the DECL_ARGUMENTS list for the function instead.)
- The BLOCK_VARS list for the `outer_scope' does provide us
- with a list of the LABEL_DECL nodes for the function however,
- and we output DWARF info for those here.
-
- Just within the `outer_scope' there will be another BLOCK
- node representing the function's outermost pair of curly
- braces. We mustn't generate a lexical_block DIE for this
- outermost pair of curly braces because that is not really an
- independent scope according to ANSI C rules. Rather, it is
- the same scope in which the parameters were declared. */
-
- {
- register tree label;
+ register tree outer_scope = DECL_INITIAL (decl);
- for (label = BLOCK_VARS (outer_scope);
- label;
- label = TREE_CHAIN (label))
- output_decl (label, outer_scope);
- }
-
- /* Note here that `BLOCK_SUBBLOCKS (outer_scope)' points to a
- list of BLOCK nodes which is always only one element long.
- That one element represents the outermost pair of curley
- braces for the function body. */
-
- output_decls_for_scope (BLOCK_SUBBLOCKS (outer_scope));
-
- /* Finally, force out any pending types which are local to the
- outermost block of this function definition. These will
- all have a TYPE_CONTEXT which points to the FUNCTION_DECL
- node itself. */
-
- output_pending_types_for_scope (decl);
+ if (outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
+ {
+ /* Note that here, `outer_scope' is a pointer to the outermost
+ BLOCK node created to represent a function.
+ This outermost BLOCK actually represents the outermost
+ binding contour for the function, i.e. the contour in which
+ the function's formal parameters and labels get declared.
+
+ Curiously, it appears that the front end doesn't actually
+ put the PARM_DECL nodes for the current function onto the
+ BLOCK_VARS list for this outer scope. (They are strung
+ off of the DECL_ARGUMENTS list for the function instead.)
+ The BLOCK_VARS list for the `outer_scope' does provide us
+ with a list of the LABEL_DECL nodes for the function however,
+ and we output DWARF info for those here.
+
+ Just within the `outer_scope' there will be a BLOCK node
+ representing the function's outermost pair of curly braces,
+ and any blocks used for the base and member initializers of
+ a C++ constructor function. */
+
+ output_decls_for_scope (outer_scope, 0);
+
+ /* Finally, force out any pending types which are local to the
+ outermost block of this function definition. These will
+ all have a TYPE_CONTEXT which points to the FUNCTION_DECL
+ node itself. */
+
+ output_pending_types_for_scope (decl);
+ }
}
- }
+ }
/* Generate a terminator for the list of stuff `owned' by this
function. */
@@ -4603,19 +4924,19 @@ output_decl (decl, containing_scope)
a return type or a formal parameter type of some function. */
if (debug_info_level <= DINFO_LEVEL_TERSE)
- if (DECL_NAME (decl) != NULL
- || ! TYPE_USED_FOR_FUNCTION (TREE_TYPE (decl)))
+ if (! TYPE_DECL_IS_STUB (decl)
+ || (! TYPE_USED_FOR_FUNCTION (TREE_TYPE (decl)) && ! in_class))
return;
- /* In the special case of a null-named TYPE_DECL node (representing
- the declaration of some type tag), if the given TYPE_DECL is
+ /* In the special case of a TYPE_DECL node representing
+ the declaration of some type tag, if the given TYPE_DECL is
marked as having been instantiated from some other (original)
TYPE_DECL node (e.g. one which was generated within the original
definition of an inline function) we have to generate a special
(abbreviated) TAG_structure_type, TAG_union_type, or
TAG_enumeration-type DIE here. */
- if (! DECL_NAME (decl) && DECL_ABSTRACT_ORIGIN (decl))
+ if (TYPE_DECL_IS_STUB (decl) && DECL_ABSTRACT_ORIGIN (decl))
{
output_tagged_type_instantiation (TREE_TYPE (decl));
return;
@@ -4623,16 +4944,7 @@ output_decl (decl, containing_scope)
output_type (TREE_TYPE (decl), containing_scope);
- /* Note that unlike the gcc front end (which generates a NULL named
- TYPE_DECL node for each complete tagged type, each array type,
- and each function type node created) the g++ front end generates
- a *named* TYPE_DECL node for each tagged type node created.
- Unfortunately, these g++ TYPE_DECL nodes cause us to output many
- superfluous and unnecessary TAG_typedef DIEs here. When g++ is
- fixed to stop generating these superfluous named TYPE_DECL nodes,
- the superfluous TAG_typedef DIEs will likewise cease. */
-
- if (DECL_NAME (decl))
+ if (! is_redundant_typedef (decl))
/* Output a DIE to represent the typedef itself. */
output_die (output_typedef_die, decl);
break;
@@ -4662,6 +4974,13 @@ output_decl (decl, containing_scope)
output_type (TREE_TYPE (decl), containing_scope);
+ {
+ /* And its containing type. */
+ register tree origin = decl_class_context (decl);
+ if (origin)
+ output_type (origin, containing_scope);
+ }
+
/* If the following DIE will represent a data object definition for a
data object with "extern" linkage, output a special "pubnames" DIE
label just ahead of the actual DIE. A reference to this label
@@ -4682,7 +5001,7 @@ output_decl (decl, containing_scope)
function. */
{
- register void (*func) ();
+ register void (*func) PROTO((void *));
register tree origin = decl_ultimate_origin (decl);
if (origin != NULL && TREE_CODE (origin) == PARM_DECL)
@@ -4734,7 +5053,7 @@ dwarfout_file_scope_decl (decl, set_finalizing)
gotta hope that the node in question doesn't represent a function
definition. If it does, then totally ignoring it is bound to screw
up our count of blocks, and that it turn will completely screw up the
- the labels we will reference in subsequent AT_low_pc and AT_high_pc
+ labels we will reference in subsequent AT_low_pc and AT_high_pc
attributes (for subsequent blocks). (It's too bad that BLOCK nodes
don't carry their own sequence numbers with them!) */
@@ -4779,7 +5098,7 @@ dwarfout_file_scope_decl (decl, set_finalizing)
the compiler never generates any out-of-lines instances of such
things (despite the fact that they *are* definitions). The
important point is that the C front-end marks these "extern inline"
- functions as DECL_EXTERNAL, but we need to generate DWARf for them
+ functions as DECL_EXTERNAL, but we need to generate DWARF for them
anyway.
Note that the C++ front-end also plays some similar games for inline
@@ -4879,8 +5198,18 @@ dwarfout_file_scope_decl (decl, set_finalizing)
really need to output these (non-fundamental) types because other
DIEs may contain references to them. */
+ /* Also ignore language dependent types here, because they are probably
+ also built-in types. If we didn't ignore them, then we would get
+ references to undefined labels because output_type doesn't support
+ them. So, for now, we need to ignore them to avoid assembler
+ errors. */
+
+ /* ??? This code is different than the equivalent code in dwarf2out.c.
+ The dwarf2out.c code is probably more correct. */
+
if (DECL_SOURCE_LINE (decl) == 0
- && type_is_fundamental (TREE_TYPE (decl)))
+ && (type_is_fundamental (TREE_TYPE (decl))
+ || TREE_CODE (TREE_TYPE (decl)) == LANG_TYPE))
return;
/* If we are in terse mode, don't generate any DIEs to represent
@@ -4890,7 +5219,7 @@ dwarfout_file_scope_decl (decl, set_finalizing)
a return type or a formal parameter type of some function. */
if (debug_info_level <= DINFO_LEVEL_TERSE)
- if (DECL_NAME (decl) != NULL
+ if (! TYPE_DECL_IS_STUB (decl)
|| ! TYPE_USED_FOR_FUNCTION (TREE_TYPE (decl)))
return;
@@ -4920,7 +5249,8 @@ dwarfout_file_scope_decl (decl, set_finalizing)
/* The above call should have totally emptied the pending_types_list. */
- assert (pending_types == 0);
+ if (pending_types != 0)
+ abort ();
ASM_OUTPUT_POP_SECTION (asm_out_file);
@@ -4983,6 +5313,8 @@ dwarfout_begin_function ()
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ if (! use_gnu_debug_info_extensions)
+ return;
function_section (current_function_decl);
sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
ASM_OUTPUT_LABEL (asm_out_file, label);
@@ -4996,6 +5328,8 @@ dwarfout_end_function ()
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
+ if (! use_gnu_debug_info_extensions)
+ return;
function_section (current_function_decl);
sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
ASM_OUTPUT_LABEL (asm_out_file, label);
@@ -5088,8 +5422,7 @@ generate_new_sfname_entry ()
calculated, and where at least one of the two symbol references is a
forward reference. (This bug could be tickled by our .debug_srcinfo
entries if we don't output their corresponding .debug_sfnames entries
- before them.)
-*/
+ before them.) */
static unsigned
lookup_filename (file_name)
@@ -5163,20 +5496,28 @@ dwarfout_line (filename, line)
register char *filename;
register unsigned line;
{
- if (debug_info_level >= DINFO_LEVEL_NORMAL)
+ if (debug_info_level >= DINFO_LEVEL_NORMAL
+ /* We can't emit line number info for functions in separate sections,
+ because the assembler can't subtract labels in different sections. */
+ && DECL_SECTION_NAME (current_function_decl) == NULL_TREE)
{
char label[MAX_ARTIFICIAL_LABEL_BYTES];
static unsigned last_line_entry_num = 0;
static unsigned prev_file_entry_num = (unsigned) -1;
- register unsigned this_file_entry_num = lookup_filename (filename);
+ register unsigned this_file_entry_num;
function_section (current_function_decl);
sprintf (label, LINE_CODE_LABEL_FMT, ++last_line_entry_num);
ASM_OUTPUT_LABEL (asm_out_file, label);
fputc ('\n', asm_out_file);
- ASM_OUTPUT_PUSH_SECTION (asm_out_file, LINE_SECTION);
+ if (use_gnu_debug_info_extensions)
+ this_file_entry_num = lookup_filename (filename);
+ else
+ this_file_entry_num = (unsigned) -1;
+
+ ASM_OUTPUT_PUSH_SECTION (asm_out_file, LINE_SECTION);
if (this_file_entry_num != prev_file_entry_num)
{
char line_entry_label[MAX_ARTIFICIAL_LABEL_BYTES];
@@ -5212,6 +5553,9 @@ generate_macinfo_entry (type_and_offset, string)
register char *type_and_offset;
register char *string;
{
+ if (! use_gnu_debug_info_extensions)
+ return;
+
fputc ('\n', asm_out_file);
ASM_OUTPUT_PUSH_SECTION (asm_out_file, MACINFO_SECTION);
fprintf (asm_out_file, "\t%s\t%s\n", UNALIGNED_INT_ASM_OP, type_and_offset);
@@ -5228,7 +5572,10 @@ dwarfout_start_new_source_file (filename)
sprintf (label, SFNAMES_ENTRY_LABEL_FMT, lookup_filename (filename));
sprintf (type_and_offset, "0x%08x+%s-%s",
- ((unsigned) MACINFO_start << 24), label, SFNAMES_BEGIN_LABEL);
+ ((unsigned) MACINFO_start << 24),
+ /* Hack: skip leading '*' . */
+ (*label == '*') + label,
+ (*SFNAMES_BEGIN_LABEL == '*') + SFNAMES_BEGIN_LABEL);
generate_macinfo_entry (type_and_offset, "");
}
@@ -5371,32 +5718,36 @@ dwarfout_init (asm_out_file, main_input_filename)
if (debug_info_level >= DINFO_LEVEL_NORMAL)
{
- /* Output a starting label and an initial (compilation directory)
- entry for the .debug_sfnames section. The starting label will be
- referenced by the initial entry in the .debug_srcinfo section. */
+ if (use_gnu_debug_info_extensions)
+ {
+ /* Output a starting label and an initial (compilation directory)
+ entry for the .debug_sfnames section. The starting label will be
+ referenced by the initial entry in the .debug_srcinfo section. */
- fputc ('\n', asm_out_file);
- ASM_OUTPUT_PUSH_SECTION (asm_out_file, SFNAMES_SECTION);
- ASM_OUTPUT_LABEL (asm_out_file, SFNAMES_BEGIN_LABEL);
- {
- register char *pwd;
- register unsigned len;
- register char *dirname;
-
- pwd = getpwd ();
- if (!pwd)
- pfatal_with_name ("getpwd");
- len = strlen (pwd);
- dirname = (char *) xmalloc (len + 2);
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_PUSH_SECTION (asm_out_file, SFNAMES_SECTION);
+ ASM_OUTPUT_LABEL (asm_out_file, SFNAMES_BEGIN_LABEL);
+ {
+ register char *pwd;
+ register unsigned len;
+ register char *dirname;
+
+ pwd = getpwd ();
+ if (!pwd)
+ pfatal_with_name ("getpwd");
+ len = strlen (pwd);
+ dirname = (char *) xmalloc (len + 2);
- strcpy (dirname, pwd);
- strcpy (dirname + len, "/");
- ASM_OUTPUT_DWARF_STRING (asm_out_file, dirname);
- free (dirname);
- }
- ASM_OUTPUT_POP_SECTION (asm_out_file);
+ strcpy (dirname, pwd);
+ strcpy (dirname + len, "/");
+ ASM_OUTPUT_DWARF_STRING (asm_out_file, dirname);
+ free (dirname);
+ }
+ ASM_OUTPUT_POP_SECTION (asm_out_file);
+ }
- if (debug_info_level >= DINFO_LEVEL_VERBOSE)
+ if (debug_info_level >= DINFO_LEVEL_VERBOSE
+ && use_gnu_debug_info_extensions)
{
/* Output a starting label for the .debug_macinfo section. This
label will be referenced by the AT_mac_info attribute in the
@@ -5417,21 +5768,24 @@ dwarfout_init (asm_out_file, main_input_filename)
ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL);
ASM_OUTPUT_POP_SECTION (asm_out_file);
- /* Generate the initial entry for the .debug_srcinfo section. */
-
- fputc ('\n', asm_out_file);
- ASM_OUTPUT_PUSH_SECTION (asm_out_file, SRCINFO_SECTION);
- ASM_OUTPUT_LABEL (asm_out_file, SRCINFO_BEGIN_LABEL);
- ASM_OUTPUT_DWARF_ADDR (asm_out_file, LINE_BEGIN_LABEL);
- ASM_OUTPUT_DWARF_ADDR (asm_out_file, SFNAMES_BEGIN_LABEL);
- ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL);
- ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_END_LABEL);
+ if (use_gnu_debug_info_extensions)
+ {
+ /* Generate the initial entry for the .debug_srcinfo section. */
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_PUSH_SECTION (asm_out_file, SRCINFO_SECTION);
+ ASM_OUTPUT_LABEL (asm_out_file, SRCINFO_BEGIN_LABEL);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, LINE_BEGIN_LABEL);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, SFNAMES_BEGIN_LABEL);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_BEGIN_LABEL);
+ ASM_OUTPUT_DWARF_ADDR (asm_out_file, TEXT_END_LABEL);
#ifdef DWARF_TIMESTAMPS
- ASM_OUTPUT_DWARF_DATA4 (asm_out_file, time (NULL));
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, time (NULL));
#else
- ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1);
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1);
#endif
- ASM_OUTPUT_POP_SECTION (asm_out_file);
+ ASM_OUTPUT_POP_SECTION (asm_out_file);
+ }
/* Generate the initial entry for the .debug_pubnames section. */
@@ -5503,7 +5857,7 @@ dwarfout_finish ()
(or blame). I didn't think of this scheme. I just conformed to it.
*/
- output_die (output_padded_null_die, (void *)0);
+ output_die (output_padded_null_die, (void *) 0);
dienum_pop ();
sprintf (label, DIE_BEGIN_LABEL_FMT, NEXT_DIE_NUM);
@@ -5569,14 +5923,17 @@ dwarfout_finish ()
ASM_OUTPUT_LABEL (asm_out_file, LINE_END_LABEL);
ASM_OUTPUT_POP_SECTION (asm_out_file);
- /* Output a terminating entry for the .debug_srcinfo section. */
-
- fputc ('\n', asm_out_file);
- ASM_OUTPUT_PUSH_SECTION (asm_out_file, SRCINFO_SECTION);
- ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
- LINE_LAST_ENTRY_LABEL, LINE_BEGIN_LABEL);
- ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1);
- ASM_OUTPUT_POP_SECTION (asm_out_file);
+ if (use_gnu_debug_info_extensions)
+ {
+ /* Output a terminating entry for the .debug_srcinfo section. */
+
+ fputc ('\n', asm_out_file);
+ ASM_OUTPUT_PUSH_SECTION (asm_out_file, SRCINFO_SECTION);
+ ASM_OUTPUT_DWARF_DELTA4 (asm_out_file,
+ LINE_LAST_ENTRY_LABEL, LINE_BEGIN_LABEL);
+ ASM_OUTPUT_DWARF_DATA4 (asm_out_file, -1);
+ ASM_OUTPUT_POP_SECTION (asm_out_file);
+ }
if (debug_info_level >= DINFO_LEVEL_VERBOSE)
{
diff --git a/contrib/gcc/dwarfout.h b/contrib/gcc/dwarfout.h
new file mode 100644
index 0000000..b4bb9b9
--- /dev/null
+++ b/contrib/gcc/dwarfout.h
@@ -0,0 +1,40 @@
+/* dwarfout.h - Various declarations for functions found in dwarfout.c
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+extern void dwarfout_init PROTO ((FILE *asm_out_file,
+ char *main_input_filename));
+extern void dwarfout_finish PROTO ((void));
+
+extern void dwarfout_define PROTO ((unsigned, char *));
+extern void dwarfout_undef PROTO ((unsigned, char *));
+extern void dwarfout_file_scope_decl PROTO ((tree , int));
+extern void dwarfout_start_new_source_file PROTO ((char *));
+extern void dwarfout_resume_previous_source_file PROTO((unsigned));
+
+extern void dwarfout_begin_function PROTO ((void));
+extern void dwarfout_end_function PROTO ((void));
+extern void dwarfout_begin_epilogue PROTO ((void));
+extern void dwarfout_end_epilogue PROTO ((void));
+extern void dwarfout_begin_block PROTO ((unsigned));
+extern void dwarfout_end_block PROTO ((unsigned));
+
+extern void dwarfout_label PROTO ((rtx));
+extern void dwarfout_line PROTO ((char *, unsigned));
+
diff --git a/contrib/gcc/dyn-string.c b/contrib/gcc/dyn-string.c
new file mode 100644
index 0000000..cfcace9
--- /dev/null
+++ b/contrib/gcc/dyn-string.c
@@ -0,0 +1,100 @@
+/* An abstract string datatype.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by Mark Mitchell (mark@markmitchell.com).
+
+ This file is part of GNU CC.
+
+ GNU CC 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, or (at your option)
+ any later version.
+
+ GNU CC 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 GNU CC; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "gansidecl.h"
+#include "dyn-string.h"
+
+extern char *xmalloc ();
+extern char *xrealloc ();
+
+/* Create a new dynamic string capable of holding at least SPACE
+ characters, including the terminating NUL. If SPACE is 0, it
+ will be silently increased to 1. */
+
+dyn_string_t
+dyn_string_new (space)
+ int space;
+{
+ dyn_string_t result = (dyn_string_t) xmalloc (sizeof (struct dyn_string));
+
+ if (space == 0)
+ /* We need at least one byte in which to store the terminating
+ NUL. */
+ space = 1;
+
+ result->allocated = space;
+ result->s = (char*) xmalloc (space);
+ result->length = 0;
+ result->s[0] = '\0';
+
+ return result;
+}
+
+/* Free the memory used by DS. */
+
+void
+dyn_string_delete (ds)
+ dyn_string_t ds;
+{
+ free (ds->s);
+ free (ds);
+}
+
+/* Append the NUL-terminated string S to DS, resizing DS if
+ necessary. */
+
+dyn_string_t
+dyn_string_append (ds, s)
+ dyn_string_t ds;
+ char *s;
+{
+ int len = strlen (s);
+ dyn_string_resize (ds, ds->length + len + 1 /* '\0' */);
+ strcpy (ds->s + ds->length, s);
+ ds->length += len;
+
+ return ds;
+}
+
+/* Increase the capacity of DS so that it can hold at least SPACE
+ characters, including the terminating NUL. This function will not
+ (at present) reduce the capacity of DS. */
+
+dyn_string_t
+dyn_string_resize (ds, space)
+ dyn_string_t ds;
+ int space;
+{
+ int new_allocated = ds->allocated;
+
+ while (space > new_allocated)
+ new_allocated *= 2;
+
+ if (new_allocated != ds->allocated)
+ {
+ /* We actually need more space. */
+ ds->allocated = new_allocated;
+ ds->s = (char*) xrealloc (ds->s, ds->allocated);
+ }
+
+ return ds;
+}
diff --git a/contrib/gcc/dyn-string.h b/contrib/gcc/dyn-string.h
new file mode 100644
index 0000000..ed8071f
--- /dev/null
+++ b/contrib/gcc/dyn-string.h
@@ -0,0 +1,31 @@
+/* An abstract string datatype.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by Mark Mitchell (mark@markmitchell.com).
+
+ This file is part of GNU CC.
+
+ GNU CC 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, or (at your option)
+ any later version.
+
+ GNU CC 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 GNU CC; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+typedef struct dyn_string
+{
+ int allocated; /* The amount of space allocated for the string. */
+ int length; /* The actual length of the string. */
+ char *s; /* The string itself, NUL-terminated. */
+}* dyn_string_t;
+
+extern dyn_string_t dyn_string_new PROTO((int));
+extern void dyn_string_delete PROTO((dyn_string_t));
+extern dyn_string_t dyn_string_append PROTO((dyn_string_t, char*));
+extern dyn_string_t dyn_string_resize PROTO((dyn_string_t, int));
diff --git a/contrib/gcc/eh-common.h b/contrib/gcc/eh-common.h
new file mode 100644
index 0000000..143ddff
--- /dev/null
+++ b/contrib/gcc/eh-common.h
@@ -0,0 +1,125 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+ This file is part of GNU CC. */
+
+/* This file contains the structures required for the language
+ independant exception handling model. Both the static compiler and
+ the runtime library share this file. */
+
+/* The runtime flag flag_new_exceptions is used to determine whether the
+ compiler supports the new runtime typechecking mechanism or not. Under
+ the new model, runtime info is contained in the exception table, and
+ the __throw() library routine determines which handler to call based
+ on the results of a call to a matching function provided by the expcetion
+ thrower. Otherwise the old scheme of calling any handler which matches
+ an exception range is used, and the handler is responsible for all
+ checking of runtime conditions. If the handler wasn't suppose to
+ get the exception, it performs a re-throw. */
+
+#include "gansidecl.h"
+
+
+/* The handler_label field MUST be the first field in this structure. The
+ __throw() library routine expects uses __eh_stub() from except.c, which
+ simply dereferences the context pointer to get the handler.
+ The routine get_dynamic_handler_chain() also has a dependancy on
+ the location of 'dynamic_handler_chain'. If its location is changed,
+ that routine must be modified as well. */
+
+struct eh_context
+{
+ void *handler_label;
+ void **dynamic_handler_chain;
+ /* This is language dependent part of the eh context. */
+ void *info;
+};
+
+#ifndef EH_TABLE_LOOKUP
+
+typedef struct old_exception_table
+{
+ void *start_region;
+ void *end_region;
+ void *exception_handler;
+} old_exception_table;
+
+typedef struct exception_table
+{
+ void *start_region;
+ void *end_region;
+ void *exception_handler;
+ void *match_info; /* runtime type info */
+} exception_table;
+
+
+/* The language identifying portion of an exception table */
+
+typedef struct exception_lang_info
+{
+ short language;
+ short version;
+} exception_lang_info;
+
+/* This value in the first field of the exception descriptor
+ identifies the descriptor as the new model format. This value would never
+ be present in this location under the old model */
+
+#define NEW_EH_RUNTIME ((void *) -2)
+
+/* Each function has an exception_descriptor which contains the
+ language info, and a table of exception ranges and handlers */
+
+typedef struct exception_descriptor
+{
+ void *runtime_id_field;
+ exception_lang_info lang;
+ exception_table table[1];
+} exception_descriptor;
+
+
+/* A pointer to a matching function is initialized at runtime by the
+ specific language if run-time exceptions are supported.
+ The function takes 3 parameters
+ 1 - runtime exception that has been thrown info. (__eh_info *)
+ 2 - Match info pointer from the region being considered (void *)
+ 3 - exception table region is in (exception descriptor *)
+*/
+
+typedef void * (*__eh_matcher) PROTO ((void *, void *, void *));
+
+/* This value is to be checked as a 'match all' case in the runtime field. */
+
+#define CATCH_ALL_TYPE ((void *) -1)
+
+/* This is the runtime exception information. This forms the minimum required
+ information for an exception info pointer in an eh_context structure. */
+
+
+typedef struct __eh_info
+{
+ __eh_matcher match_function;
+ short language;
+ short version;
+} __eh_info;
+
+/* Convienient language codes for ID the originating language. Similar
+ to the codes in dwarf2.h. */
+
+enum exception_source_language
+ {
+ EH_LANG_C89 = 0x0001,
+ EH_LANG_C = 0x0002,
+ EH_LANG_Ada83 = 0x0003,
+ EH_LANG_C_plus_plus = 0x0004,
+ EH_LANG_Cobol74 = 0x0005,
+ EH_LANG_Cobol85 = 0x0006,
+ EH_LANG_Fortran77 = 0x0007,
+ EH_LANG_Fortran90 = 0x0008,
+ EH_LANG_Pascal83 = 0x0009,
+ EH_LANG_Modula2 = 0x000a,
+ EH_LANG_Java = 0x000b,
+ EH_LANG_Mips_Assembler = 0x8001
+ };
+
+#endif /* EH_TABLE_LOOKUP */
+
+
diff --git a/contrib/gcc/emit-rtl.c b/contrib/gcc/emit-rtl.c
index 9600f2f..2ca007a 100644
--- a/contrib/gcc/emit-rtl.c
+++ b/contrib/gcc/emit-rtl.c
@@ -1,5 +1,5 @@
/* Emit RTL for the GNU C-Compiler expander.
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -40,42 +40,27 @@ Boston, MA 02111-1307, USA. */
#else
#include <varargs.h>
#endif
+#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
+#include "except.h"
#include "function.h"
#include "expr.h"
#include "regs.h"
+#include "hard-reg-set.h"
#include "insn-config.h"
+#include "recog.h"
#include "real.h"
#include "obstack.h"
-
-#include "bytecode.h"
-#include "machmode.h"
-#include "bc-opcode.h"
-#include "bc-typecd.h"
-#include "bc-optab.h"
-#include "bc-emit.h"
-
-#include <stdio.h>
-
-
-/* Opcode names */
-#ifdef BCDEBUG_PRINT_CODE
-char *opcode_name[] =
-{
-#include "bc-opname.h"
-
-"***END***"
-};
-#endif
-
+#include "bitmap.h"
/* Commonly used modes. */
-enum machine_mode byte_mode; /* Mode whose width is BITS_PER_UNIT. */
-enum machine_mode word_mode; /* Mode whose width is BITS_PER_WORD. */
-enum machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */
+enum machine_mode byte_mode; /* Mode whose width is BITS_PER_UNIT. */
+enum machine_mode word_mode; /* Mode whose width is BITS_PER_WORD. */
+enum machine_mode double_mode; /* Mode whose width is DOUBLE_TYPE_SIZE. */
+enum machine_mode ptr_mode; /* Mode whose width is POINTER_SIZE. */
/* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function.
After rtl generation, it is 1 plus the largest register number used. */
@@ -111,14 +96,19 @@ static int no_line_numbers;
All of these except perhaps the floating-point CONST_DOUBLEs
are unique; no other rtx-object will be equal to any of these. */
-rtx pc_rtx; /* (PC) */
-rtx cc0_rtx; /* (CC0) */
-rtx cc1_rtx; /* (CC1) (not actually used nowadays) */
-rtx const0_rtx; /* (CONST_INT 0) */
-rtx const1_rtx; /* (CONST_INT 1) */
-rtx const2_rtx; /* (CONST_INT 2) */
-rtx constm1_rtx; /* (CONST_INT -1) */
-rtx const_true_rtx; /* (CONST_INT STORE_FLAG_VALUE) */
+struct _global_rtl global_rtl =
+{
+ {PC, VOIDmode}, /* pc_rtx */
+ {CC0, VOIDmode}, /* cc0_rtx */
+ {REG}, /* stack_pointer_rtx */
+ {REG}, /* frame_pointer_rtx */
+ {REG}, /* hard_frame_pointer_rtx */
+ {REG}, /* arg_pointer_rtx */
+ {REG}, /* virtual_incoming_args_rtx */
+ {REG}, /* virtual_stack_vars_rtx */
+ {REG}, /* virtual_stack_dynamic_rtx */
+ {REG}, /* virtual_outgoing_args_rtx */
+};
/* We record floating-point CONST_DOUBLEs in each floating-point mode for
the values of 0, 1, and 2. For the integer entries and VOIDmode, we
@@ -126,6 +116,8 @@ rtx const_true_rtx; /* (CONST_INT STORE_FLAG_VALUE) */
rtx const_tiny_rtx[3][(int) MAX_MACHINE_MODE];
+rtx const_true_rtx;
+
REAL_VALUE_TYPE dconst0;
REAL_VALUE_TYPE dconst1;
REAL_VALUE_TYPE dconst2;
@@ -149,29 +141,22 @@ REAL_VALUE_TYPE dconstm1;
In an inline procedure, the stack and frame pointer rtxs may not be
used for anything else. */
-rtx stack_pointer_rtx; /* (REG:Pmode STACK_POINTER_REGNUM) */
-rtx frame_pointer_rtx; /* (REG:Pmode FRAME_POINTER_REGNUM) */
-rtx hard_frame_pointer_rtx; /* (REG:Pmode HARD_FRAME_POINTER_REGNUM) */
-rtx arg_pointer_rtx; /* (REG:Pmode ARG_POINTER_REGNUM) */
rtx struct_value_rtx; /* (REG:Pmode STRUCT_VALUE_REGNUM) */
rtx struct_value_incoming_rtx; /* (REG:Pmode STRUCT_VALUE_INCOMING_REGNUM) */
rtx static_chain_rtx; /* (REG:Pmode STATIC_CHAIN_REGNUM) */
rtx static_chain_incoming_rtx; /* (REG:Pmode STATIC_CHAIN_INCOMING_REGNUM) */
rtx pic_offset_table_rtx; /* (REG:Pmode PIC_OFFSET_TABLE_REGNUM) */
-rtx virtual_incoming_args_rtx; /* (REG:Pmode VIRTUAL_INCOMING_ARGS_REGNUM) */
-rtx virtual_stack_vars_rtx; /* (REG:Pmode VIRTUAL_STACK_VARS_REGNUM) */
-rtx virtual_stack_dynamic_rtx; /* (REG:Pmode VIRTUAL_STACK_DYNAMIC_REGNUM) */
-rtx virtual_outgoing_args_rtx; /* (REG:Pmode VIRTUAL_OUTGOING_ARGS_REGNUM) */
+/* This is used to implement __builtin_return_address for some machines.
+ See for instance the MIPS port. */
+rtx return_address_pointer_rtx; /* (REG:Pmode RETURN_ADDRESS_POINTER_REGNUM) */
/* We make one copy of (const_int C) where C is in
[- MAX_SAVED_CONST_INT, MAX_SAVED_CONST_INT]
to save space during the compilation and simplify comparisons of
integers. */
-#define MAX_SAVED_CONST_INT 64
-
-static rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
+struct rtx_def const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
/* The ends of the doubly-linked chain of rtl for the current function.
Both are reset to null at the start of rtl generation for the function.
@@ -208,6 +193,11 @@ static char *last_filename = 0;
char *regno_pointer_flag;
int regno_pointer_flag_length;
+/* Indexed by pseudo register number, if nonzero gives the known alignment
+ for that pseudo (if regno_pointer_flag is set).
+ Allocated in parallel with regno_pointer_flag. */
+char *regno_pointer_align;
+
/* Indexed by pseudo register number, gives the rtx for that pseudo.
Allocated in parallel with regno_pointer_flag. */
@@ -240,6 +230,9 @@ struct sequence_stack *sequence_stack;
static struct sequence_stack *sequence_element_free_list;
static rtx sequence_result[SEQUENCE_RESULT_SIZE];
+/* During RTL generation, we also keep a list of free INSN rtl codes. */
+static rtx free_insn;
+
extern int rtx_equal_function_value_matters;
/* Filename and line number of last line-number note,
@@ -247,14 +240,82 @@ extern int rtx_equal_function_value_matters;
extern char *emit_filename;
extern int emit_lineno;
-rtx change_address ();
-void init_emit ();
+static rtx make_jump_insn_raw PROTO((rtx));
+static rtx make_call_insn_raw PROTO((rtx));
+static rtx find_line_note PROTO((rtx));
-extern struct obstack *rtl_obstack;
+rtx
+gen_rtx_CONST_INT (mode, arg)
+ enum machine_mode mode;
+ HOST_WIDE_INT arg;
+{
+ if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT)
+ return &const_int_rtx[arg + MAX_SAVED_CONST_INT];
+
+#if STORE_FLAG_VALUE != 1 && STORE_FLAG_VALUE != -1
+ if (const_true_rtx && arg == STORE_FLAG_VALUE)
+ return const_true_rtx;
+#endif
+
+ return gen_rtx_raw_CONST_INT (mode, arg);
+}
+
+rtx
+gen_rtx_REG (mode, regno)
+ enum machine_mode mode;
+ int regno;
+{
+ /* In case the MD file explicitly references the frame pointer, have
+ all such references point to the same frame pointer. This is
+ used during frame pointer elimination to distinguish the explicit
+ references to these registers from pseudos that happened to be
+ assigned to them.
+
+ If we have eliminated the frame pointer or arg pointer, we will
+ be using it as a normal register, for example as a spill
+ register. In such cases, we might be accessing it in a mode that
+ is not Pmode and therefore cannot use the pre-allocated rtx.
+
+ Also don't do this when we are making new REGs in reload, since
+ we don't want to get confused with the real pointers. */
+
+ if (mode == Pmode && !reload_in_progress)
+ {
+ if (regno == FRAME_POINTER_REGNUM)
+ return frame_pointer_rtx;
+#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ if (regno == HARD_FRAME_POINTER_REGNUM)
+ return hard_frame_pointer_rtx;
+#endif
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ if (regno == ARG_POINTER_REGNUM)
+ return arg_pointer_rtx;
+#endif
+#ifdef RETURN_ADDRESS_POINTER_REGNUM
+ if (regno == RETURN_ADDRESS_POINTER_REGNUM)
+ return return_address_pointer_rtx;
+#endif
+ if (regno == STACK_POINTER_REGNUM)
+ return stack_pointer_rtx;
+ }
+
+ return gen_rtx_raw_REG (mode, regno);
+}
+
+rtx
+gen_rtx_MEM (mode, addr)
+ enum machine_mode mode;
+ rtx addr;
+{
+ rtx rt = gen_rtx_raw_MEM (mode, addr);
+
+ /* This field is not cleared by the mere allocation of the rtx, so
+ we clear it here. */
+ MEM_ALIAS_SET (rt) = 0;
+
+ return rt;
+}
-extern int stack_depth;
-extern int max_stack_depth;
-
/* rtx gen_rtx (code, mode, [element1, ..., elementn])
**
** This routine generates an RTX of the size specified by
@@ -302,60 +363,11 @@ gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...))
#endif
if (code == CONST_INT)
- {
- HOST_WIDE_INT arg = va_arg (p, HOST_WIDE_INT);
-
- if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT)
- return const_int_rtx[arg + MAX_SAVED_CONST_INT];
-
- if (const_true_rtx && arg == STORE_FLAG_VALUE)
- return const_true_rtx;
-
- rt_val = rtx_alloc (code);
- INTVAL (rt_val) = arg;
- }
+ rt_val = gen_rtx_CONST_INT (mode, va_arg (p, HOST_WIDE_INT));
else if (code == REG)
- {
- int regno = va_arg (p, int);
-
- /* In case the MD file explicitly references the frame pointer, have
- all such references point to the same frame pointer. This is used
- during frame pointer elimination to distinguish the explicit
- references to these registers from pseudos that happened to be
- assigned to them.
-
- If we have eliminated the frame pointer or arg pointer, we will
- be using it as a normal register, for example as a spill register.
- In such cases, we might be accessing it in a mode that is not
- Pmode and therefore cannot use the pre-allocated rtx.
-
- Also don't do this when we are making new REGs in reload,
- since we don't want to get confused with the real pointers. */
-
- if (frame_pointer_rtx && regno == FRAME_POINTER_REGNUM && mode == Pmode
- && ! reload_in_progress)
- return frame_pointer_rtx;
-#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
- if (hard_frame_pointer_rtx && regno == HARD_FRAME_POINTER_REGNUM
- && mode == Pmode && ! reload_in_progress)
- return hard_frame_pointer_rtx;
-#endif
-#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
- if (arg_pointer_rtx && regno == ARG_POINTER_REGNUM && mode == Pmode
- && ! reload_in_progress)
- return arg_pointer_rtx;
-#endif
- if (stack_pointer_rtx && regno == STACK_POINTER_REGNUM && mode == Pmode
- && ! reload_in_progress)
- return stack_pointer_rtx;
- else
- {
- rt_val = rtx_alloc (code);
- rt_val->mode = mode;
- REGNO (rt_val) = regno;
- return rt_val;
- }
- }
+ rt_val = gen_rtx_REG (mode, va_arg (p, int));
+ else if (code == MEM)
+ rt_val = gen_rtx_MEM (mode, va_arg (p, rtx));
else
{
rt_val = rtx_alloc (code); /* Allocate the storage space. */
@@ -390,6 +402,14 @@ gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...))
XVEC (rt_val, i) = va_arg (p, rtvec);
break;
+ case 'b': /* A bitmap? */
+ XBITMAP (rt_val, i) = va_arg (p, bitmap);
+ break;
+
+ case 't': /* A tree? */
+ XTREE (rt_val, i) = va_arg (p, tree);
+ break;
+
default:
abort ();
}
@@ -452,6 +472,25 @@ gen_rtvec_v (n, argp)
return rt_val;
}
+
+rtvec
+gen_rtvec_vv (n, argp)
+ int n;
+ rtunion *argp;
+{
+ register int i;
+ register rtvec rt_val;
+
+ if (n == 0)
+ return NULL_RTVEC; /* Don't allocate an empty rtvec... */
+
+ rt_val = rtvec_alloc (n); /* Allocate an rtvec... */
+
+ for (i = 0; i < n; i++)
+ rt_val->elem[i].rtx = (argp++)->rtx;
+
+ return rt_val;
+}
/* Generate a REG rtx for a new pseudo register of mode MODE.
This pseudo is assigned the next sequential register number. */
@@ -487,7 +526,7 @@ gen_reg_rtx (mode)
realpart = gen_reg_rtx (partmode);
imagpart = gen_reg_rtx (partmode);
- return gen_rtx (CONCAT, mode, realpart, imagpart);
+ return gen_rtx_CONCAT (mode, realpart, imagpart);
}
/* Make sure regno_pointer_flag and regno_reg_rtx are large
@@ -497,12 +536,17 @@ gen_reg_rtx (mode)
{
rtx *new1;
char *new =
- (char *) oballoc (regno_pointer_flag_length * 2);
+ (char *) savealloc (regno_pointer_flag_length * 2);
bcopy (regno_pointer_flag, new, regno_pointer_flag_length);
bzero (&new[regno_pointer_flag_length], regno_pointer_flag_length);
regno_pointer_flag = new;
- new1 = (rtx *) oballoc (regno_pointer_flag_length * 2 * sizeof (rtx));
+ new = (char *) savealloc (regno_pointer_flag_length * 2);
+ bcopy (regno_pointer_align, new, regno_pointer_flag_length);
+ bzero (&new[regno_pointer_flag_length], regno_pointer_flag_length);
+ regno_pointer_align = new;
+
+ new1 = (rtx *) savealloc (regno_pointer_flag_length * 2 * sizeof (rtx));
bcopy ((char *) regno_reg_rtx, (char *) new1,
regno_pointer_flag_length * sizeof (rtx));
bzero ((char *) &new1[regno_pointer_flag_length],
@@ -512,18 +556,40 @@ gen_reg_rtx (mode)
regno_pointer_flag_length *= 2;
}
- val = gen_rtx (REG, mode, reg_rtx_no);
+ val = gen_rtx_raw_REG (mode, reg_rtx_no);
regno_reg_rtx[reg_rtx_no++] = val;
return val;
}
-/* Identify REG as a probable pointer register. */
+/* Identify REG (which may be a CONCAT) as a user register. */
+
+void
+mark_user_reg (reg)
+ rtx reg;
+{
+ if (GET_CODE (reg) == CONCAT)
+ {
+ REG_USERVAR_P (XEXP (reg, 0)) = 1;
+ REG_USERVAR_P (XEXP (reg, 1)) = 1;
+ }
+ else if (GET_CODE (reg) == REG)
+ REG_USERVAR_P (reg) = 1;
+ else
+ abort ();
+}
+
+/* Identify REG as a probable pointer register and show its alignment
+ as ALIGN, if nonzero. */
void
-mark_reg_pointer (reg)
+mark_reg_pointer (reg, align)
rtx reg;
+ int align;
{
REGNO_POINTER_FLAG (REGNO (reg)) = 1;
+
+ if (align)
+ REGNO_POINTER_ALIGN (REGNO (reg)) = align;
}
/* Return 1 plus largest pseudo reg number used in the current function. */
@@ -602,16 +668,27 @@ gen_lowpart_common (mode, x)
else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (XEXP (x, 0))))
return gen_lowpart_common (mode, XEXP (x, 0));
else if (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x)))
- return gen_rtx (GET_CODE (x), mode, XEXP (x, 0));
+ return gen_rtx_fmt_e (GET_CODE (x), mode, XEXP (x, 0));
}
else if (GET_CODE (x) == SUBREG
&& (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
|| GET_MODE_SIZE (mode) == GET_MODE_UNIT_SIZE (GET_MODE (x))))
return (GET_MODE (SUBREG_REG (x)) == mode && SUBREG_WORD (x) == 0
? SUBREG_REG (x)
- : gen_rtx (SUBREG, mode, SUBREG_REG (x), SUBREG_WORD (x)));
+ : gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + word));
else if (GET_CODE (x) == REG)
{
+ /* Let the backend decide how many registers to skip. This is needed
+ in particular for Sparc64 where fp regs are smaller than a word. */
+ /* ??? Note that subregs are now ambiguous, in that those against
+ pseudos are sized by the Word Size, while those against hard
+ regs are sized by the underlying register size. Better would be
+ to always interpret the subreg offset parameter as bytes or bits. */
+
+ if (WORDS_BIG_ENDIAN && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x))
+ - HARD_REGNO_NREGS (REGNO (x), mode));
+
/* If the register is not valid for MODE, return 0. If we don't
do this, there is no way to fix up the resulting REG later.
But we do do this if the current REG is not valid for its
@@ -626,6 +703,14 @@ gen_lowpart_common (mode, x)
/* integrate.c can't handle parts of a return value register. */
&& (! REG_FUNCTION_VALUE_P (x)
|| ! rtx_equal_function_value_matters)
+#ifdef CLASS_CANNOT_CHANGE_SIZE
+ && ! (GET_MODE_SIZE (mode) != GET_MODE_SIZE (GET_MODE (x))
+ && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_INT
+ && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_FLOAT
+ && (TEST_HARD_REG_BIT
+ (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
+ REGNO (x))))
+#endif
/* We want to keep the stack, frame, and arg pointers
special. */
&& x != frame_pointer_rtx
@@ -633,9 +718,9 @@ gen_lowpart_common (mode, x)
&& x != arg_pointer_rtx
#endif
&& x != stack_pointer_rtx)
- return gen_rtx (REG, mode, REGNO (x) + word);
+ return gen_rtx_REG (mode, REGNO (x) + word);
else
- return gen_rtx (SUBREG, mode, x, word);
+ return gen_rtx_SUBREG (mode, x, word);
}
/* If X is a CONST_INT or a CONST_DOUBLE, extract the appropriate bits
from the low-order part of the constant. */
@@ -661,14 +746,13 @@ gen_lowpart_common (mode, x)
: GEN_INT (CONST_DOUBLE_LOW (x)));
else
{
- /* MODE must be narrower than HOST_BITS_PER_INT. */
+ /* MODE must be narrower than HOST_BITS_PER_WIDE_INT. */
int width = GET_MODE_BITSIZE (mode);
HOST_WIDE_INT val = (GET_CODE (x) == CONST_INT ? INTVAL (x)
: CONST_DOUBLE_LOW (x));
- if (((val & ((HOST_WIDE_INT) (-1) << (width - 1)))
- != ((HOST_WIDE_INT) (-1) << (width - 1))))
- val &= ((HOST_WIDE_INT) 1 << width) - 1;
+ /* Sign extend to HOST_WIDE_INT. */
+ val = val << (HOST_BITS_PER_WIDE_INT - width) >> (HOST_BITS_PER_WIDE_INT - width);
return (GET_CODE (x) == CONST_INT && INTVAL (x) == val ? x
: GEN_INT (val));
@@ -726,7 +810,7 @@ gen_lowpart_common (mode, x)
low = CONST_DOUBLE_LOW (x), high = CONST_DOUBLE_HIGH (x);
/* REAL_VALUE_TARGET_DOUBLE takes the addressing order of the
- target machine. */
+ target machine. */
if (WORDS_BIG_ENDIAN)
i[0] = high, i[1] = low;
else
@@ -754,6 +838,22 @@ gen_lowpart_common (mode, x)
return CONST_DOUBLE_FROM_REAL_VALUE (u.d, mode);
}
#endif
+
+ /* We need an extra case for machines where HOST_BITS_PER_WIDE_INT is the
+ same as sizeof (double) or when sizeof (float) is larger than the
+ size of a word on the target machine. */
+#ifdef REAL_ARITHMETIC
+ else if (mode == SFmode && GET_CODE (x) == CONST_INT)
+ {
+ REAL_VALUE_TYPE r;
+ HOST_WIDE_INT i;
+
+ i = INTVAL (x);
+ r = REAL_VALUE_FROM_TARGET_SINGLE (i);
+ return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
+ }
+#endif
+
/* Similarly, if this is converting a floating-point value into a
single-word integer. Only do this is the host and target parameters are
compatible. */
@@ -766,7 +866,7 @@ gen_lowpart_common (mode, x)
&& GET_CODE (x) == CONST_DOUBLE
&& GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) == BITS_PER_WORD)
- return operand_subword (x, 0, 0, GET_MODE (x));
+ return operand_subword (x, word, 0, GET_MODE (x));
/* Similarly, if this is converting a floating-point value into a
two-word integer, we can do this one word at a time and make an
@@ -782,8 +882,10 @@ gen_lowpart_common (mode, x)
&& GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) == 2 * BITS_PER_WORD)
{
- rtx lowpart = operand_subword (x, WORDS_BIG_ENDIAN, 0, GET_MODE (x));
- rtx highpart = operand_subword (x, ! WORDS_BIG_ENDIAN, 0, GET_MODE (x));
+ rtx lowpart
+ = operand_subword (x, word + WORDS_BIG_ENDIAN, 0, GET_MODE (x));
+ rtx highpart
+ = operand_subword (x, word + ! WORDS_BIG_ENDIAN, 0, GET_MODE (x));
if (lowpart && GET_CODE (lowpart) == CONST_INT
&& highpart && GET_CODE (highpart) == CONST_INT)
@@ -863,6 +965,7 @@ gen_lowpart (mode, x)
result = gen_lowpart_common (mode, copy_to_reg (x));
if (result == 0)
abort ();
+ return result;
}
else if (GET_CODE (x) == MEM)
{
@@ -880,6 +983,8 @@ gen_lowpart (mode, x)
return change_address (x, mode, plus_constant (XEXP (x, 0), offset));
}
+ else if (GET_CODE (x) == ADDRESSOF)
+ return gen_lowpart (mode, force_reg (GET_MODE (x), x));
else
abort ();
}
@@ -902,10 +1007,13 @@ gen_highpart (mode, x)
&& GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT
#endif
)
- return gen_rtx (CONST_INT, VOIDmode,
- CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode));
+ return GEN_INT (CONST_DOUBLE_HIGH (x) & GET_MODE_MASK (mode));
else if (GET_CODE (x) == CONST_INT)
- return const0_rtx;
+ {
+ if (HOST_BITS_PER_WIDE_INT <= BITS_PER_WORD)
+ return const0_rtx;
+ return GEN_INT (INTVAL (x) >> (HOST_BITS_PER_WIDE_INT - BITS_PER_WORD));
+ }
else if (GET_CODE (x) == MEM)
{
register int offset = 0;
@@ -932,22 +1040,27 @@ gen_highpart (mode, x)
}
else if (GET_CODE (x) == REG)
{
- int word = 0;
+ int word;
+
+ /* Let the backend decide how many registers to skip. This is needed
+ in particular for sparc64 where fp regs are smaller than a word. */
+ /* ??? Note that subregs are now ambiguous, in that those against
+ pseudos are sized by the word size, while those against hard
+ regs are sized by the underlying register size. Better would be
+ to always interpret the subreg offset parameter as bytes or bits. */
- if (! WORDS_BIG_ENDIAN
- && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
+ if (WORDS_BIG_ENDIAN)
+ word = 0;
+ else if (REGNO (x) < FIRST_PSEUDO_REGISTER)
+ word = (HARD_REGNO_NREGS (REGNO (x), GET_MODE (x))
+ - HARD_REGNO_NREGS (REGNO (x), mode));
+ else
word = ((GET_MODE_SIZE (GET_MODE (x))
- MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD))
/ UNITS_PER_WORD);
- /*
- * ??? This fails miserably for complex values being passed in registers
- * where the sizeof the real and imaginary part are not equal to the
- * sizeof SImode. FIXME
- */
-
if (REGNO (x) < FIRST_PSEUDO_REGISTER
- /* integrate.c can't handle parts of a return value register. */
+ /* integrate.c can't handle parts of a return value register. */
&& (! REG_FUNCTION_VALUE_P (x)
|| ! rtx_equal_function_value_matters)
/* We want to keep the stack, frame, and arg pointers special. */
@@ -956,9 +1069,9 @@ gen_highpart (mode, x)
&& x != arg_pointer_rtx
#endif
&& x != stack_pointer_rtx)
- return gen_rtx (REG, mode, REGNO (x) + word);
+ return gen_rtx_REG (mode, REGNO (x) + word);
else
- return gen_rtx (SUBREG, mode, x, word);
+ return gen_rtx_SUBREG (mode, x, word);
}
else
abort ();
@@ -974,6 +1087,8 @@ subreg_lowpart_p (x)
{
if (GET_CODE (x) != SUBREG)
return 1;
+ else if (GET_MODE (SUBREG_REG (x)) == VOIDmode)
+ return 0;
if (WORDS_BIG_ENDIAN
&& GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) > UNITS_PER_WORD)
@@ -1011,6 +1126,7 @@ operand_subword (op, i, validate_address, mode)
{
HOST_WIDE_INT val;
int size_ratio = HOST_BITS_PER_WIDE_INT / BITS_PER_WORD;
+ int bits_per_word = BITS_PER_WORD;
if (mode == VOIDmode)
mode = GET_MODE (op);
@@ -1047,12 +1163,12 @@ operand_subword (op, i, validate_address, mode)
|| op == arg_pointer_rtx
#endif
|| op == stack_pointer_rtx)
- return gen_rtx (SUBREG, word_mode, op, i);
+ return gen_rtx_SUBREG (word_mode, op, i);
else
- return gen_rtx (REG, word_mode, REGNO (op) + i);
+ return gen_rtx_REG (word_mode, REGNO (op) + i);
}
else if (GET_CODE (op) == SUBREG)
- return gen_rtx (SUBREG, word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
+ return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
else if (GET_CODE (op) == CONCAT)
{
int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;
@@ -1079,7 +1195,7 @@ operand_subword (op, i, validate_address, mode)
addr = memory_address (word_mode, addr);
}
- new = gen_rtx (MEM, word_mode, addr);
+ new = gen_rtx_MEM (word_mode, addr);
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (op);
MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (op);
@@ -1124,7 +1240,7 @@ operand_subword (op, i, validate_address, mode)
{
long value;
value = k[i >> 1];
- if ((i & 0x1) == 0)
+ if ((i & 0x1) == !WORDS_BIG_ENDIAN)
value >>= 16;
value &= 0xffff;
return GEN_INT ((HOST_WIDE_INT) value);
@@ -1132,6 +1248,20 @@ operand_subword (op, i, validate_address, mode)
else
abort ();
}
+ else if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
+ && GET_MODE_CLASS (mode) == MODE_FLOAT
+ && GET_MODE_BITSIZE (mode) > 64
+ && GET_CODE (op) == CONST_DOUBLE)
+ {
+ long k[4];
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+
+ if (BITS_PER_WORD == 32)
+ return GEN_INT ((HOST_WIDE_INT) k[i]);
+ }
#else /* no REAL_ARITHMETIC */
if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
@@ -1167,12 +1297,20 @@ operand_subword (op, i, validate_address, mode)
REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+
+ if (BITS_PER_WORD == 16)
+ {
+ if ((i & 0x1) == !WORDS_BIG_ENDIAN)
+ l >>= 16;
+ l &= 0xffff;
+ }
return GEN_INT ((HOST_WIDE_INT) l);
}
#else
if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
|| flag_pretend_float)
+ && sizeof (float) * 8 == HOST_BITS_PER_WIDE_INT
&& GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_SIZE (mode) == UNITS_PER_WORD
&& GET_CODE (op) == CONST_DOUBLE)
@@ -1185,6 +1323,22 @@ operand_subword (op, i, validate_address, mode)
u.f = d;
return GEN_INT (u.i);
}
+ if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
+ && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
+ || flag_pretend_float)
+ && sizeof (double) * 8 == HOST_BITS_PER_WIDE_INT
+ && GET_MODE_CLASS (mode) == MODE_FLOAT
+ && GET_MODE_SIZE (mode) == UNITS_PER_WORD
+ && GET_CODE (op) == CONST_DOUBLE)
+ {
+ double d;
+ union {double d; HOST_WIDE_INT i; } u;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (d, op);
+
+ u.d = d;
+ return GEN_INT (u.i);
+ }
#endif /* no REAL_ARITHMETIC */
/* The only remaining cases that we can handle are integers.
@@ -1213,11 +1367,30 @@ operand_subword (op, i, validate_address, mode)
: (GET_CODE (op) == CONST_INT
? (INTVAL (op) < 0 ? ~0 : 0) : CONST_DOUBLE_HIGH (op)));
- /* If BITS_PER_WORD is smaller than an int, get the appropriate bits. */
+ /* Get the value we want into the low bits of val. */
if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT)
- val = ((val >> ((i % size_ratio) * BITS_PER_WORD))
- & (((HOST_WIDE_INT) 1
- << (BITS_PER_WORD % HOST_BITS_PER_WIDE_INT)) - 1));
+ val = ((val >> ((i % size_ratio) * BITS_PER_WORD)));
+
+ /* Clear the bits that don't belong in our mode, unless they and our sign
+ bit are all one. So we get either a reasonable negative value or a
+ reasonable unsigned value for this mode. */
+ if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
+ && ((val & ((HOST_WIDE_INT) (-1) << (bits_per_word - 1)))
+ != ((HOST_WIDE_INT) (-1) << (bits_per_word - 1))))
+ val &= ((HOST_WIDE_INT) 1 << bits_per_word) - 1;
+
+ /* If this would be an entire word for the target, but is not for
+ the host, then sign-extend on the host so that the number will look
+ the same way on the host that it would on the target.
+
+ For example, when building a 64 bit alpha hosted 32 bit sparc
+ targeted compiler, then we want the 32 bit unsigned value -1 to be
+ represented as a 64 bit value -1, and not as 0x00000000ffffffff.
+ The later confuses the sparc backend. */
+
+ if (BITS_PER_WORD < HOST_BITS_PER_WIDE_INT
+ && (val & ((HOST_WIDE_INT) 1 << (bits_per_word - 1))))
+ val |= ((HOST_WIDE_INT) (-1) << bits_per_word);
return GEN_INT (val);
}
@@ -1242,7 +1415,14 @@ operand_subword_force (op, i, mode)
return result;
if (mode != BLKmode && mode != VOIDmode)
- op = force_reg (mode, op);
+ {
+ /* If this is a register which can not be accessed by words, copy it
+ to a pseudo register. */
+ if (GET_CODE (op) == REG)
+ op = copy_to_reg (op);
+ else
+ op = force_reg (mode, op);
+ }
result = operand_subword (op, i, 1, mode);
if (result == 0)
@@ -1275,8 +1455,7 @@ reverse_comparison (insn)
}
else
{
- rtx new = gen_rtx (COMPARE, VOIDmode,
- CONST0_RTX (GET_MODE (comp)), comp);
+ rtx new = gen_rtx_COMPARE (VOIDmode, CONST0_RTX (GET_MODE (comp)), comp);
if (GET_CODE (body) == SET)
SET_SRC (body) = new;
else
@@ -1314,7 +1493,10 @@ change_address (memref, mode, addr)
else
addr = memory_address (mode, addr);
- new = gen_rtx (MEM, mode, addr);
+ if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref))
+ return memref;
+
+ new = gen_rtx_MEM (mode, addr);
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (memref);
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (memref);
MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (memref);
@@ -1328,9 +1510,8 @@ gen_label_rtx ()
{
register rtx label;
- label = (output_bytecode
- ? gen_rtx (CODE_LABEL, VOIDmode, NULL, bc_get_bytecode_label ())
- : gen_rtx (CODE_LABEL, VOIDmode, 0, 0, 0, label_num++, NULL_PTR));
+ label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX,
+ NULL_RTX, label_num++, NULL_PTR);
LABEL_NUSES (label) = 0;
return label;
@@ -1346,7 +1527,8 @@ gen_inline_header_rtx (first_insn, first_parm_insn, first_labelno,
last_labelno, max_parm_regnum, max_regnum, args_size,
pops_args, stack_slots, forced_labels, function_flags,
outgoing_args_size, original_arg_vector,
- original_decl_initial)
+ original_decl_initial, regno_rtx, regno_flag,
+ regno_align, parm_reg_stack_loc)
rtx first_insn, first_parm_insn;
int first_labelno, last_labelno, max_parm_regnum, max_regnum, args_size;
int pops_args;
@@ -1356,27 +1538,43 @@ gen_inline_header_rtx (first_insn, first_parm_insn, first_labelno,
int outgoing_args_size;
rtvec original_arg_vector;
rtx original_decl_initial;
-{
- rtx header = gen_rtx (INLINE_HEADER, VOIDmode,
- cur_insn_uid++, NULL_RTX,
- first_insn, first_parm_insn,
- first_labelno, last_labelno,
- max_parm_regnum, max_regnum, args_size, pops_args,
- stack_slots, forced_labels, function_flags,
- outgoing_args_size,
- original_arg_vector, original_decl_initial);
+ rtvec regno_rtx;
+ char *regno_flag;
+ char *regno_align;
+ rtvec parm_reg_stack_loc;
+{
+ rtx header = gen_rtx_INLINE_HEADER (VOIDmode,
+ cur_insn_uid++, NULL_RTX,
+ first_insn, first_parm_insn,
+ first_labelno, last_labelno,
+ max_parm_regnum, max_regnum, args_size,
+ pops_args, stack_slots, forced_labels,
+ function_flags, outgoing_args_size,
+ original_arg_vector,
+ original_decl_initial,
+ regno_rtx, regno_flag, regno_align,
+ parm_reg_stack_loc);
return header;
}
/* Install new pointers to the first and last insns in the chain.
+ Also, set cur_insn_uid to one higher than the last in use.
Used for an inline-procedure after copying the insn chain. */
void
set_new_first_and_last_insn (first, last)
rtx first, last;
{
+ rtx insn;
+
first_insn = first;
last_insn = last;
+ cur_insn_uid = 0;
+
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ cur_insn_uid = MAX (cur_insn_uid, INSN_UID (insn));
+
+ cur_insn_uid++;
}
/* Set the range of label numbers found in the current function.
@@ -1408,6 +1606,7 @@ save_emit_status (p)
p->last_linenum = last_linenum;
p->last_filename = last_filename;
p->regno_pointer_flag = regno_pointer_flag;
+ p->regno_pointer_align = regno_pointer_align;
p->regno_pointer_flag_length = regno_pointer_flag_length;
p->regno_reg_rtx = regno_reg_rtx;
}
@@ -1432,13 +1631,17 @@ restore_emit_status (p)
last_linenum = p->last_linenum;
last_filename = p->last_filename;
regno_pointer_flag = p->regno_pointer_flag;
+ regno_pointer_align = p->regno_pointer_align;
regno_pointer_flag_length = p->regno_pointer_flag_length;
regno_reg_rtx = p->regno_reg_rtx;
- /* Clear our cache of rtx expressions for start_sequence and gen_sequence. */
+ /* Clear our cache of rtx expressions for start_sequence and
+ gen_sequence. */
sequence_element_free_list = 0;
for (i = 0; i < SEQUENCE_RESULT_SIZE; i++)
sequence_result[i] = 0;
+
+ free_insn = 0;
}
/* Go through all the RTL insn bodies and copy any invalid shared structure.
@@ -1500,7 +1703,7 @@ copy_rtx_if_shared (orig)
case PC:
case CC0:
case SCRATCH:
- /* SCRATCH must be shared because they represent distinct values. */
+ /* SCRATCH must be shared because they represent distinct values. */
return x;
case CONST:
@@ -1540,6 +1743,10 @@ copy_rtx_if_shared (orig)
x->used = 1;
return x;
}
+ break;
+
+ default:
+ break;
}
/* This rtx may not be shared. If it has already been seen,
@@ -1580,7 +1787,7 @@ copy_rtx_if_shared (orig)
int len = XVECLEN (x, i);
if (copied && len > 0)
- XVEC (x, i) = gen_rtvec_v (len, &XVECEXP (x, i, 0));
+ XVEC (x, i) = gen_rtvec_vv (len, XVEC (x, i)->elem);
for (j = 0; j < len; j++)
XVECEXP (x, i, j) = copy_rtx_if_shared (XVECEXP (x, i, j));
}
@@ -1629,6 +1836,9 @@ reset_used_flags (x)
case BARRIER:
/* The chain of insns is not being copied. */
return;
+
+ default:
+ break;
}
x->used = 0;
@@ -1811,7 +2021,7 @@ prev_nonnote_insn (insn)
/* Return the next INSN, CALL_INSN or JUMP_INSN after INSN;
or 0, if there is none. This routine does not look inside
- SEQUENCEs. */
+ SEQUENCEs. */
rtx
next_real_insn (insn)
@@ -1938,9 +2148,8 @@ link_cc0_insns (insn)
if (GET_CODE (user) == INSN && GET_CODE (PATTERN (user)) == SEQUENCE)
user = XVECEXP (PATTERN (user), 0, 0);
- REG_NOTES (user) = gen_rtx (INSN_LIST, REG_CC_SETTER, insn,
- REG_NOTES (user));
- REG_NOTES (insn) = gen_rtx (INSN_LIST, REG_CC_USER, user, REG_NOTES (insn));
+ REG_NOTES (user) = gen_rtx_INSN_LIST (REG_CC_SETTER, insn, REG_NOTES (user));
+ REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_CC_USER, user, REG_NOTES (insn));
}
/* Return the next insn that uses CC0 after INSN, which is assumed to
@@ -1980,7 +2189,6 @@ prev_cc0_setter (insn)
rtx insn;
{
rtx note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
- rtx link;
if (note)
return XEXP (note, 0);
@@ -2086,9 +2294,17 @@ make_insn_raw (pattern)
{
register rtx insn;
- insn = rtx_alloc (INSN);
- INSN_UID (insn) = cur_insn_uid++;
+ /* If in RTL generation phase, see if FREE_INSN can be used. */
+ if (free_insn != 0 && rtx_equal_function_value_matters)
+ {
+ insn = free_insn;
+ free_insn = NEXT_INSN (free_insn);
+ PUT_CODE (insn, INSN);
+ }
+ else
+ insn = rtx_alloc (INSN);
+ INSN_UID (insn) = cur_insn_uid++;
PATTERN (insn) = pattern;
INSN_CODE (insn) = -1;
LOG_LINKS (insn) = NULL;
@@ -2776,13 +2992,6 @@ emit_line_note (file, line)
char *file;
int line;
{
- if (output_bytecode)
- {
- /* FIXME: for now we do nothing, but eventually we will have to deal with
- debugging information. */
- return 0;
- }
-
emit_filename = file;
emit_lineno = line;
@@ -2975,7 +3184,7 @@ push_to_sequence (first)
void
push_topmost_sequence ()
{
- struct sequence_stack *stack, *top;
+ struct sequence_stack *stack, *top = NULL;
start_sequence ();
@@ -2993,7 +3202,7 @@ push_topmost_sequence ()
void
pop_topmost_sequence ()
{
- struct sequence_stack *stack, *top;
+ struct sequence_stack *stack, *top = NULL;
for (stack = sequence_stack; stack; stack = stack->next)
top = stack;
@@ -3055,12 +3264,17 @@ gen_sequence ()
(Now that we cache SEQUENCE expressions, it isn't worth special-casing
the case of an empty list.) */
if (len == 1
+ && ! RTX_FRAME_RELATED_P (first_insn)
&& (GET_CODE (first_insn) == INSN
|| GET_CODE (first_insn) == JUMP_INSN
/* Don't discard the call usage field. */
|| (GET_CODE (first_insn) == CALL_INSN
&& CALL_INSN_FUNCTION_USAGE (first_insn) == NULL_RTX)))
- return PATTERN (first_insn);
+ {
+ NEXT_INSN (first_insn) = free_insn;
+ free_insn = first_insn;
+ return PATTERN (first_insn);
+ }
/* Put them in a vector. See if we already have a SEQUENCE of the
appropriate length around. */
@@ -3072,7 +3286,7 @@ gen_sequence ()
cache it. */
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
- result = gen_rtx (SEQUENCE, VOIDmode, rtvec_alloc (len));
+ result = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (len));
pop_obstacks ();
}
@@ -3082,145 +3296,6 @@ gen_sequence ()
return result;
}
-/* Set up regno_reg_rtx, reg_rtx_no and regno_pointer_flag
- according to the chain of insns starting with FIRST.
-
- Also set cur_insn_uid to exceed the largest uid in that chain.
-
- This is used when an inline function's rtl is saved
- and passed to rest_of_compilation later. */
-
-static void restore_reg_data_1 ();
-
-void
-restore_reg_data (first)
- rtx first;
-{
- register rtx insn;
- int i;
- register int max_uid = 0;
-
- for (insn = first; insn; insn = NEXT_INSN (insn))
- {
- if (INSN_UID (insn) >= max_uid)
- max_uid = INSN_UID (insn);
-
- switch (GET_CODE (insn))
- {
- case NOTE:
- case CODE_LABEL:
- case BARRIER:
- break;
-
- case JUMP_INSN:
- case CALL_INSN:
- case INSN:
- restore_reg_data_1 (PATTERN (insn));
- break;
- }
- }
-
- /* Don't duplicate the uids already in use. */
- cur_insn_uid = max_uid + 1;
-
- /* If any regs are missing, make them up.
-
- ??? word_mode is not necessarily the right mode. Most likely these REGs
- are never used. At some point this should be checked. */
-
- for (i = FIRST_PSEUDO_REGISTER; i < reg_rtx_no; i++)
- if (regno_reg_rtx[i] == 0)
- regno_reg_rtx[i] = gen_rtx (REG, word_mode, i);
-}
-
-static void
-restore_reg_data_1 (orig)
- rtx orig;
-{
- register rtx x = orig;
- register int i;
- register enum rtx_code code;
- register char *format_ptr;
-
- code = GET_CODE (x);
-
- switch (code)
- {
- case QUEUED:
- case CONST_INT:
- case CONST_DOUBLE:
- case SYMBOL_REF:
- case CODE_LABEL:
- case PC:
- case CC0:
- case LABEL_REF:
- return;
-
- case REG:
- if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
- {
- /* Make sure regno_pointer_flag and regno_reg_rtx are large
- enough to have an element for this pseudo reg number. */
- if (REGNO (x) >= reg_rtx_no)
- {
- reg_rtx_no = REGNO (x);
-
- if (reg_rtx_no >= regno_pointer_flag_length)
- {
- int newlen = MAX (regno_pointer_flag_length * 2,
- reg_rtx_no + 30);
- rtx *new1;
- char *new = (char *) oballoc (newlen);
- bzero (new, newlen);
- bcopy (regno_pointer_flag, new, regno_pointer_flag_length);
-
- new1 = (rtx *) oballoc (newlen * sizeof (rtx));
- bzero ((char *) new1, newlen * sizeof (rtx));
- bcopy ((char *) regno_reg_rtx, (char *) new1,
- regno_pointer_flag_length * sizeof (rtx));
-
- regno_pointer_flag = new;
- regno_reg_rtx = new1;
- regno_pointer_flag_length = newlen;
- }
- reg_rtx_no ++;
- }
- regno_reg_rtx[REGNO (x)] = x;
- }
- return;
-
- case MEM:
- if (GET_CODE (XEXP (x, 0)) == REG)
- mark_reg_pointer (XEXP (x, 0));
- restore_reg_data_1 (XEXP (x, 0));
- return;
- }
-
- /* Now scan the subexpressions recursively. */
-
- format_ptr = GET_RTX_FORMAT (code);
-
- for (i = 0; i < GET_RTX_LENGTH (code); i++)
- {
- switch (*format_ptr++)
- {
- case 'e':
- restore_reg_data_1 (XEXP (x, i));
- break;
-
- case 'E':
- if (XVEC (x, i) != NULL)
- {
- register int j;
-
- for (j = 0; j < XVECLEN (x, i); j++)
- restore_reg_data_1 (XVECEXP (x, i, j));
- }
- break;
- }
- }
-}
-
/* Initialize data structures and variables in this file
before generating rtl for each function. */
@@ -3244,17 +3319,22 @@ init_emit ()
sequence_element_free_list = 0;
for (i = 0; i < SEQUENCE_RESULT_SIZE; i++)
sequence_result[i] = 0;
+ free_insn = 0;
/* Init the tables that describe all the pseudo regs. */
regno_pointer_flag_length = LAST_VIRTUAL_REGISTER + 101;
regno_pointer_flag
- = (char *) oballoc (regno_pointer_flag_length);
+ = (char *) savealloc (regno_pointer_flag_length);
bzero (regno_pointer_flag, regno_pointer_flag_length);
+ regno_pointer_align
+ = (char *) savealloc (regno_pointer_flag_length);
+ bzero (regno_pointer_align, regno_pointer_flag_length);
+
regno_reg_rtx
- = (rtx *) oballoc (regno_pointer_flag_length * sizeof (rtx));
+ = (rtx *) savealloc (regno_pointer_flag_length * sizeof (rtx));
bzero ((char *) regno_reg_rtx, regno_pointer_flag_length * sizeof (rtx));
/* Put copies of all the virtual register rtx into regno_reg_rtx. */
@@ -3275,6 +3355,23 @@ init_emit ()
REGNO_POINTER_FLAG (VIRTUAL_STACK_DYNAMIC_REGNUM) = 1;
REGNO_POINTER_FLAG (VIRTUAL_OUTGOING_ARGS_REGNUM) = 1;
+#ifdef STACK_BOUNDARY
+ REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
+ REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
+ REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM)
+ = STACK_BOUNDARY / BITS_PER_UNIT;
+ REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
+
+ REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM)
+ = STACK_BOUNDARY / BITS_PER_UNIT;
+ REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM)
+ = STACK_BOUNDARY / BITS_PER_UNIT;
+ REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM)
+ = STACK_BOUNDARY / BITS_PER_UNIT;
+ REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM)
+ = STACK_BOUNDARY / BITS_PER_UNIT;
+#endif
+
#ifdef INIT_EXPANDERS
INIT_EXPANDERS;
#endif
@@ -3289,6 +3386,7 @@ init_emit_once (line_numbers)
{
int i;
enum machine_mode mode;
+ enum machine_mode double_mode;
no_line_numbers = ! line_numbers;
@@ -3298,6 +3396,7 @@ init_emit_once (line_numbers)
byte_mode = VOIDmode;
word_mode = VOIDmode;
+ double_mode = VOIDmode;
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
@@ -3311,35 +3410,39 @@ init_emit_once (line_numbers)
word_mode = mode;
}
+#ifndef DOUBLE_TYPE_SIZE
+#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE
+ && double_mode == VOIDmode)
+ double_mode = mode;
+ }
+
ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0);
/* Create the unique rtx's for certain rtx codes and operand values. */
- pc_rtx = gen_rtx (PC, VOIDmode);
- cc0_rtx = gen_rtx (CC0, VOIDmode);
-
- /* Don't use gen_rtx here since gen_rtx in this case
- tries to use these variables. */
for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
{
- const_int_rtx[i + MAX_SAVED_CONST_INT] = rtx_alloc (CONST_INT);
- PUT_MODE (const_int_rtx[i + MAX_SAVED_CONST_INT], VOIDmode);
- INTVAL (const_int_rtx[i + MAX_SAVED_CONST_INT]) = i;
+ PUT_CODE (&const_int_rtx[i + MAX_SAVED_CONST_INT], CONST_INT);
+ PUT_MODE (&const_int_rtx[i + MAX_SAVED_CONST_INT], VOIDmode);
+ INTVAL (&const_int_rtx[i + MAX_SAVED_CONST_INT]) = i;
}
- /* These four calls obtain some of the rtx expressions made above. */
- const0_rtx = GEN_INT (0);
- const1_rtx = GEN_INT (1);
- const2_rtx = GEN_INT (2);
- constm1_rtx = GEN_INT (-1);
-
- /* This will usually be one of the above constants, but may be a new rtx. */
- const_true_rtx = GEN_INT (STORE_FLAG_VALUE);
+ if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT
+ && STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT)
+ const_true_rtx = &const_int_rtx[STORE_FLAG_VALUE + MAX_SAVED_CONST_INT];
+ else
+ const_true_rtx = gen_rtx_CONST_INT (VOIDmode, STORE_FLAG_VALUE);
- dconst0 = REAL_VALUE_ATOF ("0", DFmode);
- dconst1 = REAL_VALUE_ATOF ("1", DFmode);
- dconst2 = REAL_VALUE_ATOF ("2", DFmode);
- dconstm1 = REAL_VALUE_ATOF ("-1", DFmode);
+ dconst0 = REAL_VALUE_ATOF ("0", double_mode);
+ dconst1 = REAL_VALUE_ATOF ("1", double_mode);
+ dconst2 = REAL_VALUE_ATOF ("2", double_mode);
+ dconstm1 = REAL_VALUE_ATOF ("-1", double_mode);
for (i = 0; i <= 2; i++)
{
@@ -3375,39 +3478,42 @@ init_emit_once (line_numbers)
mode = GET_MODE_WIDER_MODE (mode))
const_tiny_rtx[0][(int) mode] = const0_rtx;
- stack_pointer_rtx = gen_rtx (REG, Pmode, STACK_POINTER_REGNUM);
- frame_pointer_rtx = gen_rtx (REG, Pmode, FRAME_POINTER_REGNUM);
- if (HARD_FRAME_POINTER_REGNUM == FRAME_POINTER_REGNUM)
- hard_frame_pointer_rtx = frame_pointer_rtx;
- else
- hard_frame_pointer_rtx = gen_rtx (REG, Pmode, HARD_FRAME_POINTER_REGNUM);
-
- if (FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM)
- arg_pointer_rtx = frame_pointer_rtx;
- else if (HARD_FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM)
- arg_pointer_rtx = hard_frame_pointer_rtx;
- else if (STACK_POINTER_REGNUM == ARG_POINTER_REGNUM)
- arg_pointer_rtx = stack_pointer_rtx;
- else
- arg_pointer_rtx = gen_rtx (REG, Pmode, ARG_POINTER_REGNUM);
+ /* Assign register numbers to the globally defined register rtx.
+ This must be done at runtime because the register number field
+ is in a union and some compilers can't initialize unions. */
- /* Create the virtual registers. Do so here since the following objects
- might reference them. */
+ REGNO (stack_pointer_rtx) = STACK_POINTER_REGNUM;
+ PUT_MODE (stack_pointer_rtx, Pmode);
+ REGNO (frame_pointer_rtx) = FRAME_POINTER_REGNUM;
+ PUT_MODE (frame_pointer_rtx, Pmode);
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ REGNO (hard_frame_pointer_rtx) = HARD_FRAME_POINTER_REGNUM;
+ PUT_MODE (hard_frame_pointer_rtx, Pmode);
+#endif
+#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM && HARD_FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
+ REGNO (arg_pointer_rtx) = ARG_POINTER_REGNUM;
+ PUT_MODE (arg_pointer_rtx, Pmode);
+#endif
- virtual_incoming_args_rtx = gen_rtx (REG, Pmode,
- VIRTUAL_INCOMING_ARGS_REGNUM);
- virtual_stack_vars_rtx = gen_rtx (REG, Pmode,
- VIRTUAL_STACK_VARS_REGNUM);
- virtual_stack_dynamic_rtx = gen_rtx (REG, Pmode,
- VIRTUAL_STACK_DYNAMIC_REGNUM);
- virtual_outgoing_args_rtx = gen_rtx (REG, Pmode,
- VIRTUAL_OUTGOING_ARGS_REGNUM);
+ REGNO (virtual_incoming_args_rtx) = VIRTUAL_INCOMING_ARGS_REGNUM;
+ PUT_MODE (virtual_incoming_args_rtx, Pmode);
+ REGNO (virtual_stack_vars_rtx) = VIRTUAL_STACK_VARS_REGNUM;
+ PUT_MODE (virtual_stack_vars_rtx, Pmode);
+ REGNO (virtual_stack_dynamic_rtx) = VIRTUAL_STACK_DYNAMIC_REGNUM;
+ PUT_MODE (virtual_stack_dynamic_rtx, Pmode);
+ REGNO (virtual_outgoing_args_rtx) = VIRTUAL_OUTGOING_ARGS_REGNUM;
+ PUT_MODE (virtual_outgoing_args_rtx, Pmode);
+
+#ifdef RETURN_ADDRESS_POINTER_REGNUM
+ return_address_pointer_rtx
+ = gen_rtx_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
+#endif
#ifdef STRUCT_VALUE
struct_value_rtx = STRUCT_VALUE;
#else
- struct_value_rtx = gen_rtx (REG, Pmode, STRUCT_VALUE_REGNUM);
+ struct_value_rtx = gen_rtx_REG (Pmode, STRUCT_VALUE_REGNUM);
#endif
#ifdef STRUCT_VALUE_INCOMING
@@ -3415,18 +3521,18 @@ init_emit_once (line_numbers)
#else
#ifdef STRUCT_VALUE_INCOMING_REGNUM
struct_value_incoming_rtx
- = gen_rtx (REG, Pmode, STRUCT_VALUE_INCOMING_REGNUM);
+ = gen_rtx_REG (Pmode, STRUCT_VALUE_INCOMING_REGNUM);
#else
struct_value_incoming_rtx = struct_value_rtx;
#endif
#endif
#ifdef STATIC_CHAIN_REGNUM
- static_chain_rtx = gen_rtx (REG, Pmode, STATIC_CHAIN_REGNUM);
+ static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
#ifdef STATIC_CHAIN_INCOMING_REGNUM
if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM)
- static_chain_incoming_rtx = gen_rtx (REG, Pmode, STATIC_CHAIN_INCOMING_REGNUM);
+ static_chain_incoming_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
else
#endif
static_chain_incoming_rtx = static_chain_rtx;
@@ -3443,6 +3549,28 @@ init_emit_once (line_numbers)
#endif
#ifdef PIC_OFFSET_TABLE_REGNUM
- pic_offset_table_rtx = gen_rtx (REG, Pmode, PIC_OFFSET_TABLE_REGNUM);
+ pic_offset_table_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
#endif
}
+
+/* Query and clear/ restore no_line_numbers. This is used by the
+ switch / case handling in stmt.c to give proper line numbers in
+ warnings about unreachable code. */
+
+int
+force_line_numbers ()
+{
+ int old = no_line_numbers;
+
+ no_line_numbers = 0;
+ if (old)
+ force_next_line_note ();
+ return old;
+}
+
+void
+restore_line_number_status (old_value)
+ int old_value;
+{
+ no_line_numbers = old_value;
+}
diff --git a/contrib/gcc/enquire.c b/contrib/gcc/enquire.c
index 763b1a4..bb5ea0b 100644
--- a/contrib/gcc/enquire.c
+++ b/contrib/gcc/enquire.c
@@ -1,5 +1,5 @@
/* Everything you wanted to know about your machine and C compiler,
- but didn't know who to ask. */
+ but didn't know who to ask. */
#ifndef VERSION
#define VERSION "4.3"
@@ -34,6 +34,9 @@
Changes by Stephen Moshier, installed Sep 93:
(FPROP): Recognize 80387 or 68881 XFmode format.
+ Change by Manfred Hollstein, installed Mar 98:
+ (bitpattern): Change type of variable i to unsigned int.
+
COMPILING
With luck and a following wind, just the following will work:
@@ -307,7 +310,7 @@
#endif /* NO_FILE */
#endif /* FILENAME */
-/* If PASS isn't defined, then this is the first pass over this file. */
+/* If PASS isn't defined, then this is the first pass over this file. */
#ifndef PASS
#ifndef SEP
#define PASS 1
@@ -387,6 +390,11 @@
#endif /* STDC */
/* include files */
+/* Stdio.h might include limits.h, and limits.h might include float.h, and
+ float.h is probably the float.h put together by the gcc makefile to
+ cause errors. We use our special define to assure float.h that we don't
+ really need it. */
+#define __GCC_FLOAT_NOT_NEEDED
#include <stdio.h>
#ifdef STDC
@@ -416,6 +424,13 @@
#ifdef VERIFY
#include "limits.h"
+#endif
+
+#ifndef SYS_FLOAT_H_WRAP
+#define SYS_FLOAT_H_WRAP 0
+#endif
+
+#if SYS_FLOAT_H_WRAP || defined VERIFY
#include "float.h"
#endif
@@ -472,7 +487,8 @@ Procedure endian ARGS((int bits_per_byte));
int exponent ARGS((Long_double x, double *fract, int *exp));
int floor_log ARGS((int base, Long_double x));
Procedure f_define ARGS((char *desc, char *extra, char *sort, char *name,
- int prec, Long_double val, char *mark));
+ int prec, Long_double val, Long_double req,
+ char *mark));
Procedure i_define ARGS((char *desc, char *extra, char *sort, char *name,
long val, long lim, long req, char *mark));
Procedure u_define ARGS((char *desc, char *extra, char *sort, char *name,
@@ -615,7 +631,7 @@ Procedure croak(place) int place; {
farewell(bugs+1); /* An exit isn't essential here, but avoids loops */
}
-/* This is here in case alloca.c is used, which calls this. */
+/* This is here in case alloca.c is used, which calls this. */
char *xmalloc(size) unsigned size; {
char *value = (char *)malloc(size);
if (value == 0) {
@@ -699,6 +715,8 @@ int main(argc, argv) int argc; char *argv[]; {
if (F) {
printf ("#ifndef _FLOAT_H___\n");
printf ("#define _FLOAT_H___\n");
+ if (SYS_FLOAT_H_WRAP)
+ printf ("#include_next <float.h>\n");
}
#ifdef ID
printf("%sProduced on %s by enquire version %s, CWI, Amsterdam%s\n",
@@ -767,7 +785,7 @@ int main(argc, argv) int argc; char *argv[]; {
size/=2;
}
- Vprintf("%sMemory mallocatable ~= %ld Kbytes%s\n",
+ Vprintf("%sMemory allocable ~= %ld Kbytes%s\n",
co, (total+511)/512, oc);
}
#endif
@@ -793,6 +811,8 @@ Procedure describe(description, extra) char *description, *extra; {
Procedure i_define(desc, extra, sort, name, val, lim, req, mark)
char *desc, *extra, *sort, *name; long val, lim, req; char *mark; {
+ if (SYS_FLOAT_H_WRAP && F && val == req)
+ return;
/* Produce a #define for a signed int type */
describe(desc, extra);
printf("#undef %s%s\n", sort, name);
@@ -801,21 +821,19 @@ Procedure i_define(desc, extra, sort, name, val, lim, req, mark)
} else if (val + lim < 0) {
/* We may not produce a constant like -1024 if the max
allowable value is 1023. It has then to be output as
- -1023-1. lim is the max allowable value. */
+ -1023-1. lim is the max allowable value. */
printf("#define %s%s (%ld%s%ld%s)\n",
sort, name, -lim, mark, val+lim, mark);
} else {
printf("#define %s%s (%ld%s)\n", sort, name, val, mark);
}
- /* If VERIFY is not set, val and req are just the same value;
- if it is set, val is the value as calculated, and req is
- the #defined constant
- */
+#ifdef VERIFY
if (val != req) {
printf("%s*** Verify failed for above #define!\n", co);
printf(" Compiler has %ld for value%s\n\n", req, oc);
bugs++;
}
+#endif
Vprintf("\n");
}
@@ -825,17 +843,21 @@ Procedure u_define(desc, extra, sort, name, val, req, mark)
describe(desc, extra);
printf("#undef %s%s\n", sort, name);
printf("#define %s%s %lu%s%s\n", sort, name, val, U, mark);
+#ifdef VERIFY
if (val != req) {
printf("%s*** Verify failed for above #define!\n", co);
printf(" Compiler has %lu for value%s\n\n", req, oc);
bugs++;
}
+#endif
Vprintf("\n");
}
-Procedure f_define(desc, extra, sort, name, precision, val, mark)
+Procedure f_define(desc, extra, sort, name, precision, val, req, mark)
char *desc, *extra, *sort, *name; int precision;
- Long_double val; char *mark; {
+ Long_double val, req; char *mark; {
+ if (SYS_FLOAT_H_WRAP && F && val == req)
+ return;
/* Produce a #define for a float/double/long double */
describe(desc, extra);
printf ("#undef %s%s\n", sort, name);
@@ -927,7 +949,7 @@ char *fake_f_rep(type, val) char *type; Long_double val; {
union { unsigned int i[4]; Long_double ld;} u;
u.i[0] = u.i[1] = u.i[2] = u.i[3] = 0;
u.ld = val;
- sprintf(buf, "(__extension__ ((union __convert_long_double) {0x%x, 0x%x, 0x%x, 0x%x}).__convert_long_double_d)",
+ sprintf(buf, "(__extension__ ((union __convert_long_double) {__convert_long_double_i: {0x%x, 0x%x, 0x%x, 0x%x}}).__convert_long_double_d)",
u.i[0], u.i[1], u.i[2], u.i[3]);
return buf;
}
@@ -955,7 +977,8 @@ char *f_rep(precision, val) int precision; Long_double val; {
Procedure bitpattern(p, size) char *p; unsigned int size; {
/* Printf the bit-pattern of p */
char c;
- int i, j;
+ unsigned int i;
+ int j;
for (i=1; i<=size; i++) {
c= *p;
@@ -1085,7 +1108,7 @@ int promotions() {
eek_a_bug("promotions don't work properly in conditional expressions\n");
}
- showtype("unsigned short promotes to", Promoted((unsigned short)0));
+ showtype("unsigned short promotes to", Promoted((unsigned short) 0));
showtype("long+unsigned gives", sl+ui);
return 0;
}
@@ -1103,7 +1126,7 @@ Procedure check_defines() {
usign= Signed;
#else
/* Implementations promote unsigned short differently */
- usign= is_signed((unsigned short)0);
+ usign= is_signed((unsigned short) 0);
#endif
if (L) {
@@ -1389,21 +1412,42 @@ int cprop() {
c=0; char_max=0;
c++;
- if (setjmp(lab)==0) { /* Yields char_max */
- while (c>char_max) {
- char_max=c;
- c++;
- }
+ if (bits_per_byte <= 16) {
+ if (setjmp(lab)==0) { /* Yields char_max */
+ while (c>char_max) {
+ char_max=c;
+ c++;
+ }
+ } else {
+ Vprintf("%sCharacter overflow generates a trap!%s\n",
+ co, oc);
+ }
+ c=0; char_min=0;
+ c--;
+ if (setjmp(lab)==0) { /* Yields char_min */
+ while (c<char_min) {
+ char_min=c;
+ c--;
+ }
+ }
} else {
- Vprintf("%sCharacter overflow generates a trap!%s\n", co, oc);
- }
- c=0; char_min=0;
- c--;
- if (setjmp(lab)==0) { /* Yields char_min */
- while (c<char_min) {
- char_min=c;
- c--;
- }
+ /* An exhaustive search here is impracticable ;-) */
+ c = (1 << (bits_per_byte - 1)) - 1;
+ char_max = c;
+ c++;
+ if (c > char_max)
+ char_max = ~0;
+ c = 0;
+ char_min = 0;
+ c--;
+ if (c < char_min) {
+ c = (1 << (bits_per_byte - 1)) - 1;
+ c = -c;
+ char_min = c;
+ c--;
+ if (c < char_min)
+ char_min = c;
+ }
}
if (c_signed && char_min == 0) {
Vprintf("%sBEWARE! Chars are pseudo-unsigned:%s\n", co, oc);
@@ -1549,7 +1593,7 @@ if (V) printf ("%s%s %s %s%s\n", co, "Type size_t is",
/* Alignment constants ********************************************/
#define alignment(TYPE) \
- ((long)((char *)&((struct{char c; TYPE d;}*)0)->d - (char *)0))
+ ((long)((char *)&((struct{char c; TYPE d;}*)0)->d - (char *) 0))
Vprintf("\n%sALIGNMENTS%s\n", co, oc);
@@ -1585,18 +1629,20 @@ if (V) printf ("%s%s %s %s%s\n", co, "Type size_t is",
Vprintf("\n%sPROPERTIES OF POINTERS%s\n", co, oc);
- if ((long) (char *) &variable == (long) (int *) &variable)
+ if ((long) (char *) &variable == (long) (int *) &variable) {
Vprintf("%sChar and int pointer formats seem identical%s\n",
co, oc);
- else
+ } else {
Vprintf("%sChar and int pointer formats are different%s\n",
co, oc);
- if ((long) (char *) &variable == (long) (function *) &variable)
+ }
+ if ((long) (char *) &variable == (long) (function *) &variable) {
Vprintf("%sChar and function pointer formats seem identical%s\n",
co, oc);
- else
+ } else {
Vprintf("%sChar and function pointer formats are different%s\n",
co, oc);
+ }
if (V) {
if ("abcd"=="abcd")
@@ -1740,7 +1786,6 @@ extern char *f_rep();
#define UPROP usprop
#define Uname "USHRT"
-#ifdef VERIFY
#ifdef SHRT_MAX
#define I_MAX SHRT_MAX
#endif
@@ -1784,7 +1829,6 @@ extern char *f_rep();
#ifdef FLT_MAX_10_EXP
#define F_MAX_10_EXP FLT_MAX_10_EXP
#endif
-#endif /* VERIFY */
#endif /* PASS1 */
@@ -1826,7 +1870,6 @@ extern char *f_rep();
#define UPROP uiprop
#define Uname "UINT"
-#ifdef VERIFY
#ifdef INT_MAX
#define I_MAX INT_MAX
#endif
@@ -1864,7 +1907,6 @@ extern char *f_rep();
#ifdef DBL_MAX_10_EXP
#define F_MAX_10_EXP DBL_MAX_10_EXP
#endif
-#endif /* VERIFY */
#endif /* PASS2 */
@@ -1912,7 +1954,6 @@ extern char *f_rep();
#define UPROP ulprop
#define Uname "ULONG"
-#ifdef VERIFY
#ifdef LONG_MAX
#define I_MAX LONG_MAX
#endif
@@ -1950,52 +1991,53 @@ extern char *f_rep();
#ifdef LDBL_MAX_10_EXP
#define F_MAX_10_EXP LDBL_MAX_10_EXP
#endif
-#endif /* VERIFY */
#endif /* PASS3 */
+#define UNDEFINED (-2)
+
#ifndef I_MAX
-#define I_MAX int_max
+#define I_MAX ((unsigned long) UNDEFINED)
#endif
#ifndef I_MIN
-#define I_MIN int_min
+#define I_MIN ((unsigned long) UNDEFINED)
#endif
#ifndef U_MAX
-#define U_MAX u_max
+#define U_MAX ((unsigned long) UNDEFINED)
#endif
#ifndef F_RADIX
-#define F_RADIX f_radix
+#define F_RADIX UNDEFINED
#endif
#ifndef F_MANT_DIG
-#define F_MANT_DIG f_mant_dig
+#define F_MANT_DIG UNDEFINED
#endif
#ifndef F_DIG
-#define F_DIG f_dig
+#define F_DIG UNDEFINED
#endif
#ifndef F_ROUNDS
-#define F_ROUNDS f_rounds
+#define F_ROUNDS UNDEFINED
#endif
#ifndef F_EPSILON
-#define F_EPSILON f_epsilon
+#define F_EPSILON ((Number) UNDEFINED)
#endif
#ifndef F_MIN_EXP
-#define F_MIN_EXP f_min_exp
+#define F_MIN_EXP UNDEFINED
#endif
#ifndef F_MIN
-#define F_MIN f_min
+#define F_MIN ((Number) UNDEFINED)
#endif
#ifndef F_MIN_10_EXP
-#define F_MIN_10_EXP f_min_10_exp
+#define F_MIN_10_EXP UNDEFINED
#endif
#ifndef F_MAX_EXP
-#define F_MAX_EXP f_max_exp
+#define F_MAX_EXP UNDEFINED
#endif
#ifndef F_MAX
-#define F_MAX f_max
+#define F_MAX ((Number) UNDEFINED)
#endif
#ifndef F_MAX_10_EXP
-#define F_MAX_10_EXP f_max_10_exp
+#define F_MAX_10_EXP UNDEFINED
#endif
#ifndef VERIFY
@@ -2400,7 +2442,9 @@ int FPROP(bits_per_byte) int bits_per_byte; {
}
if (PASS == 1) { /* only for FLT */
flt_rounds= f_rounds;
- if (F)
+ /* Prefer system float.h definition of F_ROUNDS,
+ since it's more likely to be right than our "1". */
+ if (F && (!SYS_FLOAT_H_WRAP || F_ROUNDS == UNDEFINED))
i_define(D_FLT_ROUNDS, "", "FLT", "_ROUNDS",
(long) f_rounds, 1L, (long) F_ROUNDS, "");
} else if (f_rounds != flt_rounds) {
@@ -2487,7 +2531,9 @@ int FPROP(bits_per_byte) int bits_per_byte; {
/* Possible loss of precision warnings here from non-stdc compilers */
if (F) f_define(D_EPSILON, thing,
- Fname, "_EPSILON", digs, (Long_double) f_epsilon, MARK);
+ Fname, "_EPSILON", digs,
+ (Long_double) f_epsilon,
+ (Long_double) F_EPSILON, MARK);
if (V || F) F_check(digs, (Long_double) f_epsilon);
Unexpected(21);
if (F) Validate(digs, (Long_double) f_epsilon, (Long_double) F_EPSILON,
@@ -2565,7 +2611,9 @@ int FPROP(bits_per_byte) int bits_per_byte; {
/* Possible loss of precision warnings here from non-stdc compilers */
if (setjmp(lab) == 0) {
if (F) f_define(D_MIN, thing,
- Fname, "_MIN", digs, (Long_double) f_min, MARK);
+ Fname, "_MIN", digs,
+ (Long_double) f_min,
+ (Long_double) F_MIN, MARK);
if (V || F) F_check(digs, (Long_double) f_min);
} else {
eek_a_bug("xxx_MIN caused a trap");
@@ -2659,7 +2707,9 @@ int FPROP(bits_per_byte) int bits_per_byte; {
if (setjmp(lab)==0) {
/* Possible loss of precision warnings here from non-stdc compilers */
if (F) f_define(D_MAX, thing,
- Fname, "_MAX", digs, (Long_double) f_max, MARK);
+ Fname, "_MAX", digs,
+ (Long_double) f_max,
+ (Long_double) F_MAX, MARK);
if (V || F) F_check(digs, (Long_double) f_max);
} else {
eek_a_bug("xxx_MAX caused a trap");
@@ -2686,7 +2736,7 @@ int FPROP(bits_per_byte) int bits_per_byte; {
mantbits=floor_log(2, (Long_double)f_radix)*f_mant_dig;
if (mantbits == 64
&& iexp == 15
- && f_max_exp+f_min_exp > 0 /* ??? f_min_exp may be wrong. */
+ && f_max_exp+f_min_exp > 0 /* ??? f_min_exp may be wrong. */
&& mantbits+iexp+17 == (int)sizeof(Number)*bits_per_byte) {
Vprintf("%sArithmetic probably doesn't use a hidden bit%s\n", co, oc);
Vprintf("%sIt's probably 80387 or 68881 extended real%s\n", co, oc);
diff --git a/contrib/gcc/except.c b/contrib/gcc/except.c
new file mode 100644
index 0000000..ccd5a6b
--- /dev/null
+++ b/contrib/gcc/except.c
@@ -0,0 +1,2694 @@
+/* Implements exception handling.
+ Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
+ Contributed by Mike Stump <mrs@cygnus.com>.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* An exception is an event that can be signaled from within a
+ function. This event can then be "caught" or "trapped" by the
+ callers of this function. This potentially allows program flow to
+ be transferred to any arbitrary code associated with a function call
+ several levels up the stack.
+
+ The intended use for this mechanism is for signaling "exceptional
+ events" in an out-of-band fashion, hence its name. The C++ language
+ (and many other OO-styled or functional languages) practically
+ requires such a mechanism, as otherwise it becomes very difficult
+ or even impossible to signal failure conditions in complex
+ situations. The traditional C++ example is when an error occurs in
+ the process of constructing an object; without such a mechanism, it
+ is impossible to signal that the error occurs without adding global
+ state variables and error checks around every object construction.
+
+ The act of causing this event to occur is referred to as "throwing
+ an exception". (Alternate terms include "raising an exception" or
+ "signaling an exception".) The term "throw" is used because control
+ is returned to the callers of the function that is signaling the
+ exception, and thus there is the concept of "throwing" the
+ exception up the call stack.
+
+ There are two major codegen options for exception handling. The
+ flag -fsjlj-exceptions can be used to select the setjmp/longjmp
+ approach, which is the default. -fno-sjlj-exceptions can be used to
+ get the PC range table approach. While this is a compile time
+ flag, an entire application must be compiled with the same codegen
+ option. The first is a PC range table approach, the second is a
+ setjmp/longjmp based scheme. We will first discuss the PC range
+ table approach, after that, we will discuss the setjmp/longjmp
+ based approach.
+
+ It is appropriate to speak of the "context of a throw". This
+ context refers to the address where the exception is thrown from,
+ and is used to determine which exception region will handle the
+ exception.
+
+ Regions of code within a function can be marked such that if it
+ contains the context of a throw, control will be passed to a
+ designated "exception handler". These areas are known as "exception
+ regions". Exception regions cannot overlap, but they can be nested
+ to any arbitrary depth. Also, exception regions cannot cross
+ function boundaries.
+
+ Exception handlers can either be specified by the user (which we
+ will call a "user-defined handler") or generated by the compiler
+ (which we will designate as a "cleanup"). Cleanups are used to
+ perform tasks such as destruction of objects allocated on the
+ stack.
+
+ In the current implementation, cleanups are handled by allocating an
+ exception region for the area that the cleanup is designated for,
+ and the handler for the region performs the cleanup and then
+ rethrows the exception to the outer exception region. From the
+ standpoint of the current implementation, there is little
+ distinction made between a cleanup and a user-defined handler, and
+ the phrase "exception handler" can be used to refer to either one
+ equally well. (The section "Future Directions" below discusses how
+ this will change).
+
+ Each object file that is compiled with exception handling contains
+ a static array of exception handlers named __EXCEPTION_TABLE__.
+ Each entry contains the starting and ending addresses of the
+ exception region, and the address of the handler designated for
+ that region.
+
+ If the target does not use the DWARF 2 frame unwind information, at
+ program startup each object file invokes a function named
+ __register_exceptions with the address of its local
+ __EXCEPTION_TABLE__. __register_exceptions is defined in libgcc2.c, and
+ is responsible for recording all of the exception regions into one list
+ (which is kept in a static variable named exception_table_list).
+
+ On targets that support crtstuff.c, the unwind information
+ is stored in a section named .eh_frame and the information for the
+ entire shared object or program is registered with a call to
+ __register_frame_info. On other targets, the information for each
+ translation unit is registered from the file generated by collect2.
+ __register_frame_info is defined in frame.c, and is responsible for
+ recording all of the unwind regions into one list (which is kept in a
+ static variable named unwind_table_list).
+
+ The function __throw is actually responsible for doing the
+ throw. On machines that have unwind info support, __throw is generated
+ by code in libgcc2.c, otherwise __throw is generated on a
+ per-object-file basis for each source file compiled with
+ -fexceptions by the C++ frontend. Before __throw is invoked,
+ the current context of the throw needs to be placed in the global
+ variable __eh_pc.
+
+ __throw attempts to find the appropriate exception handler for the
+ PC value stored in __eh_pc by calling __find_first_exception_table_match
+ (which is defined in libgcc2.c). If __find_first_exception_table_match
+ finds a relevant handler, __throw transfers control directly to it.
+
+ If a handler for the context being thrown from can't be found, __throw
+ walks (see Walking the stack below) the stack up the dynamic call chain to
+ continue searching for an appropriate exception handler based upon the
+ caller of the function it last sought a exception handler for. It stops
+ then either an exception handler is found, or when the top of the
+ call chain is reached.
+
+ If no handler is found, an external library function named
+ __terminate is called. If a handler is found, then we restart
+ our search for a handler at the end of the call chain, and repeat
+ the search process, but instead of just walking up the call chain,
+ we unwind the call chain as we walk up it.
+
+ Internal implementation details:
+
+ To associate a user-defined handler with a block of statements, the
+ function expand_start_try_stmts is used to mark the start of the
+ block of statements with which the handler is to be associated
+ (which is known as a "try block"). All statements that appear
+ afterwards will be associated with the try block.
+
+ A call to expand_start_all_catch marks the end of the try block,
+ and also marks the start of the "catch block" (the user-defined
+ handler) associated with the try block.
+
+ This user-defined handler will be invoked for *every* exception
+ thrown with the context of the try block. It is up to the handler
+ to decide whether or not it wishes to handle any given exception,
+ as there is currently no mechanism in this implementation for doing
+ this. (There are plans for conditionally processing an exception
+ based on its "type", which will provide a language-independent
+ mechanism).
+
+ If the handler chooses not to process the exception (perhaps by
+ looking at an "exception type" or some other additional data
+ supplied with the exception), it can fall through to the end of the
+ handler. expand_end_all_catch and expand_leftover_cleanups
+ add additional code to the end of each handler to take care of
+ rethrowing to the outer exception handler.
+
+ The handler also has the option to continue with "normal flow of
+ code", or in other words to resume executing at the statement
+ immediately after the end of the exception region. The variable
+ caught_return_label_stack contains a stack of labels, and jumping
+ to the topmost entry's label via expand_goto will resume normal
+ flow to the statement immediately after the end of the exception
+ region. If the handler falls through to the end, the exception will
+ be rethrown to the outer exception region.
+
+ The instructions for the catch block are kept as a separate
+ sequence, and will be emitted at the end of the function along with
+ the handlers specified via expand_eh_region_end. The end of the
+ catch block is marked with expand_end_all_catch.
+
+ Any data associated with the exception must currently be handled by
+ some external mechanism maintained in the frontend. For example,
+ the C++ exception mechanism passes an arbitrary value along with
+ the exception, and this is handled in the C++ frontend by using a
+ global variable to hold the value. (This will be changing in the
+ future.)
+
+ The mechanism in C++ for handling data associated with the
+ exception is clearly not thread-safe. For a thread-based
+ environment, another mechanism must be used (possibly using a
+ per-thread allocation mechanism if the size of the area that needs
+ to be allocated isn't known at compile time.)
+
+ Internally-generated exception regions (cleanups) are marked by
+ calling expand_eh_region_start to mark the start of the region,
+ and expand_eh_region_end (handler) is used to both designate the
+ end of the region and to associate a specified handler/cleanup with
+ the region. The rtl code in HANDLER will be invoked whenever an
+ exception occurs in the region between the calls to
+ expand_eh_region_start and expand_eh_region_end. After HANDLER is
+ executed, additional code is emitted to handle rethrowing the
+ exception to the outer exception handler. The code for HANDLER will
+ be emitted at the end of the function.
+
+ TARGET_EXPRs can also be used to designate exception regions. A
+ TARGET_EXPR gives an unwind-protect style interface commonly used
+ in functional languages such as LISP. The associated expression is
+ evaluated, and whether or not it (or any of the functions that it
+ calls) throws an exception, the protect expression is always
+ invoked. This implementation takes care of the details of
+ associating an exception table entry with the expression and
+ generating the necessary code (it actually emits the protect
+ expression twice, once for normal flow and once for the exception
+ case). As for the other handlers, the code for the exception case
+ will be emitted at the end of the function.
+
+ Cleanups can also be specified by using add_partial_entry (handler)
+ and end_protect_partials. add_partial_entry creates the start of
+ a new exception region; HANDLER will be invoked if an exception is
+ thrown with the context of the region between the calls to
+ add_partial_entry and end_protect_partials. end_protect_partials is
+ used to mark the end of these regions. add_partial_entry can be
+ called as many times as needed before calling end_protect_partials.
+ However, end_protect_partials should only be invoked once for each
+ group of calls to add_partial_entry as the entries are queued
+ and all of the outstanding entries are processed simultaneously
+ when end_protect_partials is invoked. Similarly to the other
+ handlers, the code for HANDLER will be emitted at the end of the
+ function.
+
+ The generated RTL for an exception region includes
+ NOTE_INSN_EH_REGION_BEG and NOTE_INSN_EH_REGION_END notes that mark
+ the start and end of the exception region. A unique label is also
+ generated at the start of the exception region, which is available
+ by looking at the ehstack variable. The topmost entry corresponds
+ to the current region.
+
+ In the current implementation, an exception can only be thrown from
+ a function call (since the mechanism used to actually throw an
+ exception involves calling __throw). If an exception region is
+ created but no function calls occur within that region, the region
+ can be safely optimized away (along with its exception handlers)
+ since no exceptions can ever be caught in that region. This
+ optimization is performed unless -fasynchronous-exceptions is
+ given. If the user wishes to throw from a signal handler, or other
+ asynchronous place, -fasynchronous-exceptions should be used when
+ compiling for maximally correct code, at the cost of additional
+ exception regions. Using -fasynchronous-exceptions only produces
+ code that is reasonably safe in such situations, but a correct
+ program cannot rely upon this working. It can be used in failsafe
+ code, where trying to continue on, and proceeding with potentially
+ incorrect results is better than halting the program.
+
+
+ Walking the stack:
+
+ The stack is walked by starting with a pointer to the current
+ frame, and finding the pointer to the callers frame. The unwind info
+ tells __throw how to find it.
+
+ Unwinding the stack:
+
+ When we use the term unwinding the stack, we mean undoing the
+ effects of the function prologue in a controlled fashion so that we
+ still have the flow of control. Otherwise, we could just return
+ (jump to the normal end of function epilogue).
+
+ This is done in __throw in libgcc2.c when we know that a handler exists
+ in a frame higher up the call stack than its immediate caller.
+
+ To unwind, we find the unwind data associated with the frame, if any.
+ If we don't find any, we call the library routine __terminate. If we do
+ find it, we use the information to copy the saved register values from
+ that frame into the register save area in the frame for __throw, return
+ into a stub which updates the stack pointer, and jump to the handler.
+ The normal function epilogue for __throw handles restoring the saved
+ values into registers.
+
+ When unwinding, we use this method if we know it will
+ work (if DWARF2_UNWIND_INFO is defined). Otherwise, we know that
+ an inline unwinder will have been emitted for any function that
+ __unwind_function cannot unwind. The inline unwinder appears as a
+ normal exception handler for the entire function, for any function
+ that we know cannot be unwound by __unwind_function. We inform the
+ compiler of whether a function can be unwound with
+ __unwind_function by having DOESNT_NEED_UNWINDER evaluate to true
+ when the unwinder isn't needed. __unwind_function is used as an
+ action of last resort. If no other method can be used for
+ unwinding, __unwind_function is used. If it cannot unwind, it
+ should call __terminate.
+
+ By default, if the target-specific backend doesn't supply a definition
+ for __unwind_function and doesn't support DWARF2_UNWIND_INFO, inlined
+ unwinders will be used instead. The main tradeoff here is in text space
+ utilization. Obviously, if inline unwinders have to be generated
+ repeatedly, this uses much more space than if a single routine is used.
+
+ However, it is simply not possible on some platforms to write a
+ generalized routine for doing stack unwinding without having some
+ form of additional data associated with each function. The current
+ implementation can encode this data in the form of additional
+ machine instructions or as static data in tabular form. The later
+ is called the unwind data.
+
+ The backend macro DOESNT_NEED_UNWINDER is used to conditionalize whether
+ or not per-function unwinders are needed. If DOESNT_NEED_UNWINDER is
+ defined and has a non-zero value, a per-function unwinder is not emitted
+ for the current function. If the static unwind data is supported, then
+ a per-function unwinder is not emitted.
+
+ On some platforms it is possible that neither __unwind_function
+ nor inlined unwinders are available. For these platforms it is not
+ possible to throw through a function call, and abort will be
+ invoked instead of performing the throw.
+
+ The reason the unwind data may be needed is that on some platforms
+ the order and types of data stored on the stack can vary depending
+ on the type of function, its arguments and returned values, and the
+ compilation options used (optimization versus non-optimization,
+ -fomit-frame-pointer, processor variations, etc).
+
+ Unfortunately, this also means that throwing through functions that
+ aren't compiled with exception handling support will still not be
+ possible on some platforms. This problem is currently being
+ investigated, but no solutions have been found that do not imply
+ some unacceptable performance penalties.
+
+ Future directions:
+
+ Currently __throw makes no differentiation between cleanups and
+ user-defined exception regions. While this makes the implementation
+ simple, it also implies that it is impossible to determine if a
+ user-defined exception handler exists for a given exception without
+ completely unwinding the stack in the process. This is undesirable
+ from the standpoint of debugging, as ideally it would be possible
+ to trap unhandled exceptions in the debugger before the process of
+ unwinding has even started.
+
+ This problem can be solved by marking user-defined handlers in a
+ special way (probably by adding additional bits to exception_table_list).
+ A two-pass scheme could then be used by __throw to iterate
+ through the table. The first pass would search for a relevant
+ user-defined handler for the current context of the throw, and if
+ one is found, the second pass would then invoke all needed cleanups
+ before jumping to the user-defined handler.
+
+ Many languages (including C++ and Ada) make execution of a
+ user-defined handler conditional on the "type" of the exception
+ thrown. (The type of the exception is actually the type of the data
+ that is thrown with the exception.) It will thus be necessary for
+ __throw to be able to determine if a given user-defined
+ exception handler will actually be executed, given the type of
+ exception.
+
+ One scheme is to add additional information to exception_table_list
+ as to the types of exceptions accepted by each handler. __throw
+ can do the type comparisons and then determine if the handler is
+ actually going to be executed.
+
+ There is currently no significant level of debugging support
+ available, other than to place a breakpoint on __throw. While
+ this is sufficient in most cases, it would be helpful to be able to
+ know where a given exception was going to be thrown to before it is
+ actually thrown, and to be able to choose between stopping before
+ every exception region (including cleanups), or just user-defined
+ exception regions. This should be possible to do in the two-pass
+ scheme by adding additional labels to __throw for appropriate
+ breakpoints, and additional debugger commands could be added to
+ query various state variables to determine what actions are to be
+ performed next.
+
+ Another major problem that is being worked on is the issue with stack
+ unwinding on various platforms. Currently the only platforms that have
+ support for the generation of a generic unwinder are the SPARC and MIPS.
+ All other ports require per-function unwinders, which produce large
+ amounts of code bloat.
+
+ For setjmp/longjmp based exception handling, some of the details
+ are as above, but there are some additional details. This section
+ discusses the details.
+
+ We don't use NOTE_INSN_EH_REGION_{BEG,END} pairs. We don't
+ optimize EH regions yet. We don't have to worry about machine
+ specific issues with unwinding the stack, as we rely upon longjmp
+ for all the machine specific details. There is no variable context
+ of a throw, just the one implied by the dynamic handler stack
+ pointed to by the dynamic handler chain. There is no exception
+ table, and no calls to __register_exceptions. __sjthrow is used
+ instead of __throw, and it works by using the dynamic handler
+ chain, and longjmp. -fasynchronous-exceptions has no effect, as
+ the elimination of trivial exception regions is not yet performed.
+
+ A frontend can set protect_cleanup_actions_with_terminate when all
+ the cleanup actions should be protected with an EH region that
+ calls terminate when an unhandled exception is throw. C++ does
+ this, Ada does not. */
+
+
+#include "config.h"
+#include "defaults.h"
+#include "eh-common.h"
+#include "system.h"
+#include "rtl.h"
+#include "tree.h"
+#include "flags.h"
+#include "except.h"
+#include "function.h"
+#include "insn-flags.h"
+#include "expr.h"
+#include "insn-codes.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "output.h"
+#include "toplev.h"
+
+/* One to use setjmp/longjmp method of generating code for exception
+ handling. */
+
+int exceptions_via_longjmp = 2;
+
+/* One to enable asynchronous exception support. */
+
+int asynchronous_exceptions = 0;
+
+/* One to protect cleanup actions with a handler that calls
+ __terminate, zero otherwise. */
+
+int protect_cleanup_actions_with_terminate;
+
+/* A list of labels used for exception handlers. Created by
+ find_exception_handler_labels for the optimization passes. */
+
+rtx exception_handler_labels;
+
+/* The EH context. Nonzero if the function has already
+ fetched a pointer to the EH context for exception handling. */
+
+rtx current_function_ehc;
+
+/* A stack used for keeping track of the currently active exception
+ handling region. As each exception region is started, an entry
+ describing the region is pushed onto this stack. The current
+ region can be found by looking at the top of the stack, and as we
+ exit regions, the corresponding entries are popped.
+
+ Entries cannot overlap; they can be nested. So there is only one
+ entry at most that corresponds to the current instruction, and that
+ is the entry on the top of the stack. */
+
+static struct eh_stack ehstack;
+
+
+/* This stack is used to represent what the current eh region is
+ for the catch blocks beings processed */
+
+static struct eh_stack catchstack;
+
+/* A queue used for tracking which exception regions have closed but
+ whose handlers have not yet been expanded. Regions are emitted in
+ groups in an attempt to improve paging performance.
+
+ As we exit a region, we enqueue a new entry. The entries are then
+ dequeued during expand_leftover_cleanups and expand_start_all_catch,
+
+ We should redo things so that we either take RTL for the handler,
+ or we expand the handler expressed as a tree immediately at region
+ end time. */
+
+static struct eh_queue ehqueue;
+
+/* Insns for all of the exception handlers for the current function.
+ They are currently emitted by the frontend code. */
+
+rtx catch_clauses;
+
+/* A TREE_CHAINed list of handlers for regions that are not yet
+ closed. The TREE_VALUE of each entry contains the handler for the
+ corresponding entry on the ehstack. */
+
+static tree protect_list;
+
+/* Stacks to keep track of various labels. */
+
+/* Keeps track of the label to resume to should one want to resume
+ normal control flow out of a handler (instead of, say, returning to
+ the caller of the current function or exiting the program). */
+
+struct label_node *caught_return_label_stack = NULL;
+
+/* Keeps track of the label used as the context of a throw to rethrow an
+ exception to the outer exception region. */
+
+struct label_node *outer_context_label_stack = NULL;
+
+/* A random data area for the front end's own use. */
+
+struct label_node *false_label_stack = NULL;
+
+static void push_eh_entry PROTO((struct eh_stack *));
+static struct eh_entry * pop_eh_entry PROTO((struct eh_stack *));
+static void enqueue_eh_entry PROTO((struct eh_queue *, struct eh_entry *));
+static struct eh_entry * dequeue_eh_entry PROTO((struct eh_queue *));
+static rtx call_get_eh_context PROTO((void));
+static void start_dynamic_cleanup PROTO((tree, tree));
+static void start_dynamic_handler PROTO((void));
+static void expand_rethrow PROTO((rtx));
+static void output_exception_table_entry PROTO((FILE *, int));
+static int can_throw PROTO((rtx));
+static rtx scan_region PROTO((rtx, int, int *));
+static void eh_regs PROTO((rtx *, rtx *, int));
+static void set_insn_eh_region PROTO((rtx *, int));
+#ifdef DONT_USE_BUILTIN_SETJMP
+static void jumpif_rtx PROTO((rtx, rtx));
+#endif
+
+
+rtx expand_builtin_return_addr PROTO((enum built_in_function, int, rtx));
+
+/* Various support routines to manipulate the various data structures
+ used by the exception handling code. */
+
+/* Push a label entry onto the given STACK. */
+
+void
+push_label_entry (stack, rlabel, tlabel)
+ struct label_node **stack;
+ rtx rlabel;
+ tree tlabel;
+{
+ struct label_node *newnode
+ = (struct label_node *) xmalloc (sizeof (struct label_node));
+
+ if (rlabel)
+ newnode->u.rlabel = rlabel;
+ else
+ newnode->u.tlabel = tlabel;
+ newnode->chain = *stack;
+ *stack = newnode;
+}
+
+/* Pop a label entry from the given STACK. */
+
+rtx
+pop_label_entry (stack)
+ struct label_node **stack;
+{
+ rtx label;
+ struct label_node *tempnode;
+
+ if (! *stack)
+ return NULL_RTX;
+
+ tempnode = *stack;
+ label = tempnode->u.rlabel;
+ *stack = (*stack)->chain;
+ free (tempnode);
+
+ return label;
+}
+
+/* Return the top element of the given STACK. */
+
+tree
+top_label_entry (stack)
+ struct label_node **stack;
+{
+ if (! *stack)
+ return NULL_TREE;
+
+ return (*stack)->u.tlabel;
+}
+
+/* get an exception label. These must be on the permanent obstack */
+
+rtx
+gen_exception_label ()
+{
+ rtx lab;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ lab = gen_label_rtx ();
+ pop_obstacks ();
+ return lab;
+}
+
+/* Push a new eh_node entry onto STACK. */
+
+static void
+push_eh_entry (stack)
+ struct eh_stack *stack;
+{
+ struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
+ struct eh_entry *entry = (struct eh_entry *) xmalloc (sizeof (struct eh_entry));
+
+ entry->outer_context = gen_label_rtx ();
+ entry->finalization = NULL_TREE;
+ entry->label_used = 0;
+ entry->exception_handler_label = gen_exception_label ();
+
+ node->entry = entry;
+ node->chain = stack->top;
+ stack->top = node;
+}
+
+/* push an existing entry onto a stack. */
+static void
+push_entry (stack, entry)
+ struct eh_stack *stack;
+ struct eh_entry *entry;
+{
+ struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
+ node->entry = entry;
+ node->chain = stack->top;
+ stack->top = node;
+}
+
+/* Pop an entry from the given STACK. */
+
+static struct eh_entry *
+pop_eh_entry (stack)
+ struct eh_stack *stack;
+{
+ struct eh_node *tempnode;
+ struct eh_entry *tempentry;
+
+ tempnode = stack->top;
+ tempentry = tempnode->entry;
+ stack->top = stack->top->chain;
+ free (tempnode);
+
+ return tempentry;
+}
+
+/* Enqueue an ENTRY onto the given QUEUE. */
+
+static void
+enqueue_eh_entry (queue, entry)
+ struct eh_queue *queue;
+ struct eh_entry *entry;
+{
+ struct eh_node *node = (struct eh_node *) xmalloc (sizeof (struct eh_node));
+
+ node->entry = entry;
+ node->chain = NULL;
+
+ if (queue->head == NULL)
+ {
+ queue->head = node;
+ }
+ else
+ {
+ queue->tail->chain = node;
+ }
+ queue->tail = node;
+}
+
+/* Dequeue an entry from the given QUEUE. */
+
+static struct eh_entry *
+dequeue_eh_entry (queue)
+ struct eh_queue *queue;
+{
+ struct eh_node *tempnode;
+ struct eh_entry *tempentry;
+
+ if (queue->head == NULL)
+ return NULL;
+
+ tempnode = queue->head;
+ queue->head = queue->head->chain;
+
+ tempentry = tempnode->entry;
+ free (tempnode);
+
+ return tempentry;
+}
+
+static void
+receive_exception_label (handler_label)
+ rtx handler_label;
+{
+ emit_label (handler_label);
+
+#ifdef HAVE_exception_receiver
+ if (! exceptions_via_longjmp)
+ if (HAVE_exception_receiver)
+ emit_insn (gen_exception_receiver ());
+#endif
+
+#ifdef HAVE_nonlocal_goto_receiver
+ if (! exceptions_via_longjmp)
+ if (HAVE_nonlocal_goto_receiver)
+ emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+}
+
+
+struct func_eh_entry
+{
+ int range_number; /* EH region number from EH NOTE insn's */
+ struct handler_info *handlers;
+};
+
+
+/* table of function eh regions */
+static struct func_eh_entry *function_eh_regions = NULL;
+static int num_func_eh_entries = 0;
+static int current_func_eh_entry = 0;
+
+#define SIZE_FUNC_EH(X) (sizeof (struct func_eh_entry) * X)
+
+/* Add a new eh_entry for this function, and base it off of the information
+ in the EH_ENTRY parameter. A NULL parameter is invalid. The number
+ returned is an number which uniquely identifies this exception range. */
+
+int
+new_eh_region_entry (note_eh_region)
+ int note_eh_region;
+{
+ if (current_func_eh_entry == num_func_eh_entries)
+ {
+ if (num_func_eh_entries == 0)
+ {
+ function_eh_regions =
+ (struct func_eh_entry *) malloc (SIZE_FUNC_EH (50));
+ num_func_eh_entries = 50;
+ }
+ else
+ {
+ num_func_eh_entries = num_func_eh_entries * 3 / 2;
+ function_eh_regions = (struct func_eh_entry *)
+ realloc (function_eh_regions, SIZE_FUNC_EH (num_func_eh_entries));
+ }
+ }
+ function_eh_regions[current_func_eh_entry].range_number = note_eh_region;
+ function_eh_regions[current_func_eh_entry].handlers = NULL;
+
+ return current_func_eh_entry++;
+}
+
+/* Add new handler information to an exception range. The first parameter
+ specifies the range number (returned from new_eh_entry()). The second
+ parameter specifies the handler. By default the handler is inserted at
+ the end of the list. A handler list may contain only ONE NULL_TREE
+ typeinfo entry. Regardless where it is positioned, a NULL_TREE entry
+ is always output as the LAST handler in the exception table for a region. */
+
+void
+add_new_handler (region, newhandler)
+ int region;
+ struct handler_info *newhandler;
+{
+ struct handler_info *last;
+
+ newhandler->next = NULL;
+ last = function_eh_regions[region].handlers;
+ if (last == NULL)
+ function_eh_regions[region].handlers = newhandler;
+ else
+ {
+ for ( ; last->next != NULL; last = last->next)
+ ;
+ last->next = newhandler;
+ }
+}
+
+/* Remove a handler label. The handler label is being deleted, so all
+ regions which reference this handler should have it removed from their
+ list of possible handlers. Any region which has the final handler
+ removed can be deleted. */
+
+void remove_handler (removing_label)
+ rtx removing_label;
+{
+ struct handler_info *handler, *last;
+ int x;
+ for (x = 0 ; x < current_func_eh_entry; ++x)
+ {
+ last = NULL;
+ handler = function_eh_regions[x].handlers;
+ for ( ; handler; last = handler, handler = handler->next)
+ if (handler->handler_label == removing_label)
+ {
+ if (last)
+ {
+ last->next = handler->next;
+ handler = last;
+ }
+ else
+ function_eh_regions[x].handlers = handler->next;
+ }
+ }
+}
+
+/* This function will return a malloc'd pointer to an array of
+ void pointer representing the runtime match values that
+ currently exist in all regions. */
+
+int
+find_all_handler_type_matches (array)
+ void ***array;
+{
+ struct handler_info *handler, *last;
+ int x,y;
+ void *val;
+ void **ptr;
+ int max_ptr;
+ int n_ptr = 0;
+
+ *array = NULL;
+
+ if (!doing_eh (0) || ! flag_new_exceptions)
+ return 0;
+
+ max_ptr = 100;
+ ptr = (void **)malloc (max_ptr * sizeof (void *));
+
+ if (ptr == NULL)
+ return 0;
+
+ for (x = 0 ; x < current_func_eh_entry; x++)
+ {
+ last = NULL;
+ handler = function_eh_regions[x].handlers;
+ for ( ; handler; last = handler, handler = handler->next)
+ {
+ val = handler->type_info;
+ if (val != NULL && val != CATCH_ALL_TYPE)
+ {
+ /* See if this match value has already been found. */
+ for (y = 0; y < n_ptr; y++)
+ if (ptr[y] == val)
+ break;
+
+ /* If we break early, we already found this value. */
+ if (y < n_ptr)
+ continue;
+
+ /* Do we need to allocate more space? */
+ if (n_ptr >= max_ptr)
+ {
+ max_ptr += max_ptr / 2;
+ ptr = (void **)realloc (ptr, max_ptr * sizeof (void *));
+ if (ptr == NULL)
+ return 0;
+ }
+ ptr[n_ptr] = val;
+ n_ptr++;
+ }
+ }
+ }
+ *array = ptr;
+ return n_ptr;
+}
+
+/* Create a new handler structure initialized with the handler label and
+ typeinfo fields passed in. */
+
+struct handler_info *
+get_new_handler (handler, typeinfo)
+ rtx handler;
+ void *typeinfo;
+{
+ struct handler_info* ptr;
+ ptr = (struct handler_info *) malloc (sizeof (struct handler_info));
+ ptr->handler_label = handler;
+ ptr->type_info = typeinfo;
+ ptr->next = NULL;
+
+ return ptr;
+}
+
+
+
+/* Find the index in function_eh_regions associated with a NOTE region. If
+ the region cannot be found, a -1 is returned. This should never happen! */
+
+int
+find_func_region (insn_region)
+ int insn_region;
+{
+ int x;
+ for (x = 0; x < current_func_eh_entry; x++)
+ if (function_eh_regions[x].range_number == insn_region)
+ return x;
+
+ return -1;
+}
+
+/* Get a pointer to the first handler in an exception region's list. */
+
+struct handler_info *
+get_first_handler (region)
+ int region;
+{
+ return function_eh_regions[find_func_region (region)].handlers;
+}
+
+/* Clean out the function_eh_region table and free all memory */
+
+static void
+clear_function_eh_region ()
+{
+ int x;
+ struct handler_info *ptr, *next;
+ for (x = 0; x < current_func_eh_entry; x++)
+ for (ptr = function_eh_regions[x].handlers; ptr != NULL; ptr = next)
+ {
+ next = ptr->next;
+ free (ptr);
+ }
+ free (function_eh_regions);
+ num_func_eh_entries = 0;
+ current_func_eh_entry = 0;
+}
+
+/* Make a duplicate of an exception region by copying all the handlers
+ for an exception region. Return the new handler index. */
+
+int
+duplicate_handlers (old_note_eh_region, new_note_eh_region)
+ int old_note_eh_region, new_note_eh_region;
+{
+ struct handler_info *ptr, *new_ptr;
+ int new_region, region;
+
+ region = find_func_region (old_note_eh_region);
+ if (region == -1)
+ error ("Cannot duplicate non-existant exception region.");
+
+ if (find_func_region (new_note_eh_region) != -1)
+ error ("Cannot duplicate EH region because new note region already exists");
+
+ new_region = new_eh_region_entry (new_note_eh_region);
+ ptr = function_eh_regions[region].handlers;
+
+ for ( ; ptr; ptr = ptr->next)
+ {
+ new_ptr = get_new_handler (ptr->handler_label, ptr->type_info);
+ add_new_handler (new_region, new_ptr);
+ }
+
+ return new_region;
+}
+
+
+/* Routine to see if exception handling is turned on.
+ DO_WARN is non-zero if we want to inform the user that exception
+ handling is turned off.
+
+ This is used to ensure that -fexceptions has been specified if the
+ compiler tries to use any exception-specific functions. */
+
+int
+doing_eh (do_warn)
+ int do_warn;
+{
+ if (! flag_exceptions)
+ {
+ static int warned = 0;
+ if (! warned && do_warn)
+ {
+ error ("exception handling disabled, use -fexceptions to enable");
+ warned = 1;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+/* Given a return address in ADDR, determine the address we should use
+ to find the corresponding EH region. */
+
+rtx
+eh_outer_context (addr)
+ rtx addr;
+{
+ /* First mask out any unwanted bits. */
+#ifdef MASK_RETURN_ADDR
+ expand_and (addr, MASK_RETURN_ADDR, addr);
+#endif
+
+ /* Then adjust to find the real return address. */
+#if defined (RETURN_ADDR_OFFSET)
+ addr = plus_constant (addr, RETURN_ADDR_OFFSET);
+#endif
+
+ return addr;
+}
+
+/* Start a new exception region for a region of code that has a
+ cleanup action and push the HANDLER for the region onto
+ protect_list. All of the regions created with add_partial_entry
+ will be ended when end_protect_partials is invoked. */
+
+void
+add_partial_entry (handler)
+ tree handler;
+{
+ expand_eh_region_start ();
+
+ /* Make sure the entry is on the correct obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+
+ /* Because this is a cleanup action, we may have to protect the handler
+ with __terminate. */
+ handler = protect_with_terminate (handler);
+
+ protect_list = tree_cons (NULL_TREE, handler, protect_list);
+ pop_obstacks ();
+}
+
+/* Emit code to get EH context to current function. */
+
+static rtx
+call_get_eh_context ()
+{
+ static tree fn;
+ tree expr;
+
+ if (fn == NULL_TREE)
+ {
+ tree fntype;
+ fn = get_identifier ("__get_eh_context");
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ fntype = build_pointer_type (build_pointer_type
+ (build_pointer_type (void_type_node)));
+ fntype = build_function_type (fntype, NULL_TREE);
+ fn = build_decl (FUNCTION_DECL, fn, fntype);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ TREE_READONLY (fn) = 1;
+ make_decl_rtl (fn, NULL_PTR, 1);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+ expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ expr, NULL_TREE, NULL_TREE);
+ TREE_SIDE_EFFECTS (expr) = 1;
+
+ return copy_to_reg (expand_expr (expr, NULL_RTX, VOIDmode, 0));
+}
+
+/* Get a reference to the EH context.
+ We will only generate a register for the current function EH context here,
+ and emit a USE insn to mark that this is a EH context register.
+
+ Later, emit_eh_context will emit needed call to __get_eh_context
+ in libgcc2, and copy the value to the register we have generated. */
+
+rtx
+get_eh_context ()
+{
+ if (current_function_ehc == 0)
+ {
+ rtx insn;
+
+ current_function_ehc = gen_reg_rtx (Pmode);
+
+ insn = gen_rtx_USE (GET_MODE (current_function_ehc),
+ current_function_ehc);
+ insn = emit_insn_before (insn, get_first_nonparm_insn ());
+
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_EH_CONTEXT, current_function_ehc,
+ REG_NOTES (insn));
+ }
+ return current_function_ehc;
+}
+
+/* Get a reference to the dynamic handler chain. It points to the
+ pointer to the next element in the dynamic handler chain. It ends
+ when there are no more elements in the dynamic handler chain, when
+ the value is &top_elt from libgcc2.c. Immediately after the
+ pointer, is an area suitable for setjmp/longjmp when
+ DONT_USE_BUILTIN_SETJMP is defined, and an area suitable for
+ __builtin_setjmp/__builtin_longjmp when DONT_USE_BUILTIN_SETJMP
+ isn't defined. */
+
+rtx
+get_dynamic_handler_chain ()
+{
+ rtx ehc, dhc, result;
+
+ ehc = get_eh_context ();
+
+ /* This is the offset of dynamic_handler_chain in the eh_context struct
+ declared in eh-common.h. If its location is change, change this offset */
+ dhc = plus_constant (ehc, POINTER_SIZE / BITS_PER_UNIT);
+
+ result = copy_to_reg (dhc);
+
+ /* We don't want a copy of the dcc, but rather, the single dcc. */
+ return gen_rtx_MEM (Pmode, result);
+}
+
+/* Get a reference to the dynamic cleanup chain. It points to the
+ pointer to the next element in the dynamic cleanup chain.
+ Immediately after the pointer, are two Pmode variables, one for a
+ pointer to a function that performs the cleanup action, and the
+ second, the argument to pass to that function. */
+
+rtx
+get_dynamic_cleanup_chain ()
+{
+ rtx dhc, dcc, result;
+
+ dhc = get_dynamic_handler_chain ();
+ dcc = plus_constant (dhc, POINTER_SIZE / BITS_PER_UNIT);
+
+ result = copy_to_reg (dcc);
+
+ /* We don't want a copy of the dcc, but rather, the single dcc. */
+ return gen_rtx_MEM (Pmode, result);
+}
+
+#ifdef DONT_USE_BUILTIN_SETJMP
+/* Generate code to evaluate X and jump to LABEL if the value is nonzero.
+ LABEL is an rtx of code CODE_LABEL, in this function. */
+
+static void
+jumpif_rtx (x, label)
+ rtx x;
+ rtx label;
+{
+ jumpif (make_tree (type_for_mode (GET_MODE (x), 0), x), label);
+}
+#endif
+
+/* Start a dynamic cleanup on the EH runtime dynamic cleanup stack.
+ We just need to create an element for the cleanup list, and push it
+ into the chain.
+
+ A dynamic cleanup is a cleanup action implied by the presence of an
+ element on the EH runtime dynamic cleanup stack that is to be
+ performed when an exception is thrown. The cleanup action is
+ performed by __sjthrow when an exception is thrown. Only certain
+ actions can be optimized into dynamic cleanup actions. For the
+ restrictions on what actions can be performed using this routine,
+ see expand_eh_region_start_tree. */
+
+static void
+start_dynamic_cleanup (func, arg)
+ tree func;
+ tree arg;
+{
+ rtx dcc;
+ rtx new_func, new_arg;
+ rtx x, buf;
+ int size;
+
+ /* We allocate enough room for a pointer to the function, and
+ one argument. */
+ size = 2;
+
+ /* XXX, FIXME: The stack space allocated this way is too long lived,
+ but there is no allocation routine that allocates at the level of
+ the last binding contour. */
+ buf = assign_stack_local (BLKmode,
+ GET_MODE_SIZE (Pmode)*(size+1),
+ 0);
+
+ buf = change_address (buf, Pmode, NULL_RTX);
+
+ /* Store dcc into the first word of the newly allocated buffer. */
+
+ dcc = get_dynamic_cleanup_chain ();
+ emit_move_insn (buf, dcc);
+
+ /* Store func and arg into the cleanup list element. */
+
+ new_func = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0),
+ GET_MODE_SIZE (Pmode)));
+ new_arg = gen_rtx_MEM (Pmode, plus_constant (XEXP (buf, 0),
+ GET_MODE_SIZE (Pmode)*2));
+ x = expand_expr (func, new_func, Pmode, 0);
+ if (x != new_func)
+ emit_move_insn (new_func, x);
+
+ x = expand_expr (arg, new_arg, Pmode, 0);
+ if (x != new_arg)
+ emit_move_insn (new_arg, x);
+
+ /* Update the cleanup chain. */
+
+ emit_move_insn (dcc, XEXP (buf, 0));
+}
+
+/* Emit RTL to start a dynamic handler on the EH runtime dynamic
+ handler stack. This should only be used by expand_eh_region_start
+ or expand_eh_region_start_tree. */
+
+static void
+start_dynamic_handler ()
+{
+ rtx dhc, dcc;
+ rtx x, arg, buf;
+ int size;
+
+#ifndef DONT_USE_BUILTIN_SETJMP
+ /* The number of Pmode words for the setjmp buffer, when using the
+ builtin setjmp/longjmp, see expand_builtin, case
+ BUILT_IN_LONGJMP. */
+ size = 5;
+#else
+#ifdef JMP_BUF_SIZE
+ size = JMP_BUF_SIZE;
+#else
+ /* Should be large enough for most systems, if it is not,
+ JMP_BUF_SIZE should be defined with the proper value. It will
+ also tend to be larger than necessary for most systems, a more
+ optimal port will define JMP_BUF_SIZE. */
+ size = FIRST_PSEUDO_REGISTER+2;
+#endif
+#endif
+ /* XXX, FIXME: The stack space allocated this way is too long lived,
+ but there is no allocation routine that allocates at the level of
+ the last binding contour. */
+ arg = assign_stack_local (BLKmode,
+ GET_MODE_SIZE (Pmode)*(size+1),
+ 0);
+
+ arg = change_address (arg, Pmode, NULL_RTX);
+
+ /* Store dhc into the first word of the newly allocated buffer. */
+
+ dhc = get_dynamic_handler_chain ();
+ dcc = gen_rtx_MEM (Pmode, plus_constant (XEXP (arg, 0),
+ GET_MODE_SIZE (Pmode)));
+ emit_move_insn (arg, dhc);
+
+ /* Zero out the start of the cleanup chain. */
+ emit_move_insn (dcc, const0_rtx);
+
+ /* The jmpbuf starts two words into the area allocated. */
+ buf = plus_constant (XEXP (arg, 0), GET_MODE_SIZE (Pmode)*2);
+
+#ifdef DONT_USE_BUILTIN_SETJMP
+ x = emit_library_call_value (setjmp_libfunc, NULL_RTX, 1, SImode, 1,
+ buf, Pmode);
+ /* If we come back here for a catch, transfer control to the handler. */
+ jumpif_rtx (x, ehstack.top->entry->exception_handler_label);
+#else
+ {
+ /* A label to continue execution for the no exception case. */
+ rtx noex = gen_label_rtx();
+ x = expand_builtin_setjmp (buf, NULL_RTX, noex,
+ ehstack.top->entry->exception_handler_label);
+ emit_label (noex);
+ }
+#endif
+
+ /* We are committed to this, so update the handler chain. */
+
+ emit_move_insn (dhc, XEXP (arg, 0));
+}
+
+/* Start an exception handling region for the given cleanup action.
+ All instructions emitted after this point are considered to be part
+ of the region until expand_eh_region_end is invoked. CLEANUP is
+ the cleanup action to perform. The return value is true if the
+ exception region was optimized away. If that case,
+ expand_eh_region_end does not need to be called for this cleanup,
+ nor should it be.
+
+ This routine notices one particular common case in C++ code
+ generation, and optimizes it so as to not need the exception
+ region. It works by creating a dynamic cleanup action, instead of
+ a using an exception region. */
+
+int
+expand_eh_region_start_tree (decl, cleanup)
+ tree decl;
+ tree cleanup;
+{
+ /* This is the old code. */
+ if (! doing_eh (0))
+ return 0;
+
+ /* The optimization only applies to actions protected with
+ terminate, and only applies if we are using the setjmp/longjmp
+ codegen method. */
+ if (exceptions_via_longjmp
+ && protect_cleanup_actions_with_terminate)
+ {
+ tree func, arg;
+ tree args;
+
+ /* Ignore any UNSAVE_EXPR. */
+ if (TREE_CODE (cleanup) == UNSAVE_EXPR)
+ cleanup = TREE_OPERAND (cleanup, 0);
+
+ /* Further, it only applies if the action is a call, if there
+ are 2 arguments, and if the second argument is 2. */
+
+ if (TREE_CODE (cleanup) == CALL_EXPR
+ && (args = TREE_OPERAND (cleanup, 1))
+ && (func = TREE_OPERAND (cleanup, 0))
+ && (arg = TREE_VALUE (args))
+ && (args = TREE_CHAIN (args))
+
+ /* is the second argument 2? */
+ && TREE_CODE (TREE_VALUE (args)) == INTEGER_CST
+ && TREE_INT_CST_LOW (TREE_VALUE (args)) == 2
+ && TREE_INT_CST_HIGH (TREE_VALUE (args)) == 0
+
+ /* Make sure there are no other arguments. */
+ && TREE_CHAIN (args) == NULL_TREE)
+ {
+ /* Arrange for returns and gotos to pop the entry we make on the
+ dynamic cleanup stack. */
+ expand_dcc_cleanup (decl);
+ start_dynamic_cleanup (func, arg);
+ return 1;
+ }
+ }
+
+ expand_eh_region_start_for_decl (decl);
+ ehstack.top->entry->finalization = cleanup;
+
+ return 0;
+}
+
+/* Just like expand_eh_region_start, except if a cleanup action is
+ entered on the cleanup chain, the TREE_PURPOSE of the element put
+ on the chain is DECL. DECL should be the associated VAR_DECL, if
+ any, otherwise it should be NULL_TREE. */
+
+void
+expand_eh_region_start_for_decl (decl)
+ tree decl;
+{
+ rtx note;
+
+ /* This is the old code. */
+ if (! doing_eh (0))
+ return;
+
+ if (exceptions_via_longjmp)
+ {
+ /* We need a new block to record the start and end of the
+ dynamic handler chain. We could always do this, but we
+ really want to permit jumping into such a block, and we want
+ to avoid any errors or performance impact in the SJ EH code
+ for now. */
+ expand_start_bindings (0);
+
+ /* But we don't need or want a new temporary level. */
+ pop_temp_slots ();
+
+ /* Mark this block as created by expand_eh_region_start. This
+ is so that we can pop the block with expand_end_bindings
+ automatically. */
+ mark_block_as_eh_region ();
+
+ /* Arrange for returns and gotos to pop the entry we make on the
+ dynamic handler stack. */
+ expand_dhc_cleanup (decl);
+ }
+
+ push_eh_entry (&ehstack);
+ note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_BEG);
+ NOTE_BLOCK_NUMBER (note)
+ = CODE_LABEL_NUMBER (ehstack.top->entry->exception_handler_label);
+ if (exceptions_via_longjmp)
+ start_dynamic_handler ();
+}
+
+/* Start an exception handling region. All instructions emitted after
+ this point are considered to be part of the region until
+ expand_eh_region_end is invoked. */
+
+void
+expand_eh_region_start ()
+{
+ expand_eh_region_start_for_decl (NULL_TREE);
+}
+
+/* End an exception handling region. The information about the region
+ is found on the top of ehstack.
+
+ HANDLER is either the cleanup for the exception region, or if we're
+ marking the end of a try block, HANDLER is integer_zero_node.
+
+ HANDLER will be transformed to rtl when expand_leftover_cleanups
+ is invoked. */
+
+void
+expand_eh_region_end (handler)
+ tree handler;
+{
+ struct eh_entry *entry;
+ rtx note;
+
+ if (! doing_eh (0))
+ return;
+
+ entry = pop_eh_entry (&ehstack);
+
+ note = emit_note (NULL_PTR, NOTE_INSN_EH_REGION_END);
+ NOTE_BLOCK_NUMBER (note)
+ = CODE_LABEL_NUMBER (entry->exception_handler_label);
+ if (exceptions_via_longjmp == 0
+ /* We share outer_context between regions; only emit it once. */
+ && INSN_UID (entry->outer_context) == 0)
+ {
+ rtx label;
+
+ label = gen_label_rtx ();
+ emit_jump (label);
+
+ /* Emit a label marking the end of this exception region that
+ is used for rethrowing into the outer context. */
+ emit_label (entry->outer_context);
+ expand_internal_throw ();
+
+ emit_label (label);
+ }
+
+ entry->finalization = handler;
+
+ /* create region entry in final exception table */
+ new_eh_region_entry (NOTE_BLOCK_NUMBER (note));
+
+ enqueue_eh_entry (&ehqueue, entry);
+
+ /* If we have already started ending the bindings, don't recurse.
+ This only happens when exceptions_via_longjmp is true. */
+ if (is_eh_region ())
+ {
+ /* Because we don't need or want a new temporary level and
+ because we didn't create one in expand_eh_region_start,
+ create a fake one now to avoid removing one in
+ expand_end_bindings. */
+ push_temp_slots ();
+
+ mark_block_as_not_eh_region ();
+
+ /* Maybe do this to prevent jumping in and so on... */
+ expand_end_bindings (NULL_TREE, 0, 0);
+ }
+}
+
+/* End the EH region for a goto fixup. We only need them in the region-based
+ EH scheme. */
+
+void
+expand_fixup_region_start ()
+{
+ if (! doing_eh (0) || exceptions_via_longjmp)
+ return;
+
+ expand_eh_region_start ();
+}
+
+/* End the EH region for a goto fixup. CLEANUP is the cleanup we just
+ expanded; to avoid running it twice if it throws, we look through the
+ ehqueue for a matching region and rethrow from its outer_context. */
+
+void
+expand_fixup_region_end (cleanup)
+ tree cleanup;
+{
+ struct eh_node *node;
+ int dont_issue;
+
+ if (! doing_eh (0) || exceptions_via_longjmp)
+ return;
+
+ for (node = ehstack.top; node && node->entry->finalization != cleanup; )
+ node = node->chain;
+ if (node == 0)
+ for (node = ehqueue.head; node && node->entry->finalization != cleanup; )
+ node = node->chain;
+ if (node == 0)
+ abort ();
+
+ /* If the outer context label has not been issued yet, we don't want
+ to issue it as a part of this region, unless this is the
+ correct region for the outer context. If we did, then the label for
+ the outer context will be WITHIN the begin/end labels,
+ and we could get an infinte loop when it tried to rethrow, or just
+ generally incorrect execution following a throw. */
+
+ dont_issue = ((INSN_UID (node->entry->outer_context) == 0)
+ && (ehstack.top->entry != node->entry));
+
+ ehstack.top->entry->outer_context = node->entry->outer_context;
+
+ /* Since we are rethrowing to the OUTER region, we know we don't need
+ a jump around sequence for this region, so we'll pretend the outer
+ context label has been issued by setting INSN_UID to 1, then clearing
+ it again afterwards. */
+
+ if (dont_issue)
+ INSN_UID (node->entry->outer_context) = 1;
+
+ /* Just rethrow. size_zero_node is just a NOP. */
+ expand_eh_region_end (size_zero_node);
+
+ if (dont_issue)
+ INSN_UID (node->entry->outer_context) = 0;
+}
+
+/* If we are using the setjmp/longjmp EH codegen method, we emit a
+ call to __sjthrow.
+
+ Otherwise, we emit a call to __throw and note that we threw
+ something, so we know we need to generate the necessary code for
+ __throw.
+
+ Before invoking throw, the __eh_pc variable must have been set up
+ to contain the PC being thrown from. This address is used by
+ __throw to determine which exception region (if any) is
+ responsible for handling the exception. */
+
+void
+emit_throw ()
+{
+ if (exceptions_via_longjmp)
+ {
+ emit_library_call (sjthrow_libfunc, 0, VOIDmode, 0);
+ }
+ else
+ {
+#ifdef JUMP_TO_THROW
+ emit_indirect_jump (throw_libfunc);
+#else
+ emit_library_call (throw_libfunc, 0, VOIDmode, 0);
+#endif
+ }
+ emit_barrier ();
+}
+
+/* Throw the current exception. If appropriate, this is done by jumping
+ to the next handler. */
+
+void
+expand_internal_throw ()
+{
+ emit_throw ();
+}
+
+/* Called from expand_exception_blocks and expand_end_catch_block to
+ emit any pending handlers/cleanups queued from expand_eh_region_end. */
+
+void
+expand_leftover_cleanups ()
+{
+ struct eh_entry *entry;
+
+ while ((entry = dequeue_eh_entry (&ehqueue)) != 0)
+ {
+ rtx prev;
+
+ /* A leftover try block. Shouldn't be one here. */
+ if (entry->finalization == integer_zero_node)
+ abort ();
+
+ /* Output the label for the start of the exception handler. */
+
+ receive_exception_label (entry->exception_handler_label);
+
+ /* register a handler for this cleanup region */
+ add_new_handler (
+ find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)),
+ get_new_handler (entry->exception_handler_label, NULL));
+
+ /* And now generate the insns for the handler. */
+ expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
+
+ prev = get_last_insn ();
+ if (prev == NULL || GET_CODE (prev) != BARRIER)
+ /* Emit code to throw to the outer context if we fall off
+ the end of the handler. */
+ expand_rethrow (entry->outer_context);
+
+ do_pending_stack_adjust ();
+ free (entry);
+ }
+}
+
+/* Called at the start of a block of try statements. */
+void
+expand_start_try_stmts ()
+{
+ if (! doing_eh (1))
+ return;
+
+ expand_eh_region_start ();
+}
+
+/* Called to begin a catch clause. The parameter is the object which
+ will be passed to the runtime type check routine. */
+void
+start_catch_handler (rtime)
+ tree rtime;
+{
+ rtx handler_label;
+ int insn_region_num;
+ int eh_region_entry;
+
+ if (! doing_eh (1))
+ return;
+
+ handler_label = catchstack.top->entry->exception_handler_label;
+ insn_region_num = CODE_LABEL_NUMBER (handler_label);
+ eh_region_entry = find_func_region (insn_region_num);
+
+ /* If we've already issued this label, pick a new one */
+ if (catchstack.top->entry->label_used)
+ handler_label = gen_exception_label ();
+ else
+ catchstack.top->entry->label_used = 1;
+
+ receive_exception_label (handler_label);
+
+ add_new_handler (eh_region_entry, get_new_handler (handler_label, rtime));
+}
+
+/* Generate RTL for the start of a group of catch clauses.
+
+ It is responsible for starting a new instruction sequence for the
+ instructions in the catch block, and expanding the handlers for the
+ internally-generated exception regions nested within the try block
+ corresponding to this catch block. */
+
+void
+expand_start_all_catch ()
+{
+ struct eh_entry *entry;
+ tree label;
+ rtx outer_context;
+
+ if (! doing_eh (1))
+ return;
+
+ outer_context = ehstack.top->entry->outer_context;
+
+ /* End the try block. */
+ expand_eh_region_end (integer_zero_node);
+
+ emit_line_note (input_filename, lineno);
+ label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ /* The label for the exception handling block that we will save.
+ This is Lresume in the documentation. */
+ expand_label (label);
+
+ /* Push the label that points to where normal flow is resumed onto
+ the top of the label stack. */
+ push_label_entry (&caught_return_label_stack, NULL_RTX, label);
+
+ /* Start a new sequence for all the catch blocks. We will add this
+ to the global sequence catch_clauses when we have completed all
+ the handlers in this handler-seq. */
+ start_sequence ();
+
+ entry = dequeue_eh_entry (&ehqueue);
+ for ( ; entry->finalization != integer_zero_node;
+ entry = dequeue_eh_entry (&ehqueue))
+ {
+ rtx prev;
+
+ /* Emit the label for the cleanup handler for this region, and
+ expand the code for the handler.
+
+ Note that a catch region is handled as a side-effect here;
+ for a try block, entry->finalization will contain
+ integer_zero_node, so no code will be generated in the
+ expand_expr call below. But, the label for the handler will
+ still be emitted, so any code emitted after this point will
+ end up being the handler. */
+
+ receive_exception_label (entry->exception_handler_label);
+
+ /* register a handler for this cleanup region */
+ add_new_handler (
+ find_func_region (CODE_LABEL_NUMBER (entry->exception_handler_label)),
+ get_new_handler (entry->exception_handler_label, NULL));
+
+ /* And now generate the insns for the cleanup handler. */
+ expand_expr (entry->finalization, const0_rtx, VOIDmode, 0);
+
+ prev = get_last_insn ();
+ if (prev == NULL || GET_CODE (prev) != BARRIER)
+ /* Code to throw out to outer context when we fall off end
+ of the handler. We can't do this here for catch blocks,
+ so it's done in expand_end_all_catch instead. */
+ expand_rethrow (entry->outer_context);
+
+ do_pending_stack_adjust ();
+ free (entry);
+ }
+
+ /* At this point, all the cleanups are done, and the ehqueue now has
+ the current exception region at its head. We dequeue it, and put it
+ on the catch stack. */
+
+ push_entry (&catchstack, entry);
+
+ /* If we are not doing setjmp/longjmp EH, because we are reordered
+ out of line, we arrange to rethrow in the outer context. We need to
+ do this because we are not physically within the region, if any, that
+ logically contains this catch block. */
+ if (! exceptions_via_longjmp)
+ {
+ expand_eh_region_start ();
+ ehstack.top->entry->outer_context = outer_context;
+ }
+
+ /* We also have to start the handler if we aren't using the new model. */
+ if (! flag_new_exceptions)
+ start_catch_handler (NULL);
+}
+
+/* Finish up the catch block. At this point all the insns for the
+ catch clauses have already been generated, so we only have to add
+ them to the catch_clauses list. We also want to make sure that if
+ we fall off the end of the catch clauses that we rethrow to the
+ outer EH region. */
+
+void
+expand_end_all_catch ()
+{
+ rtx new_catch_clause, outer_context = NULL_RTX;
+ struct eh_entry *entry;
+
+ if (! doing_eh (1))
+ return;
+
+ /* Dequeue the current catch clause region. */
+ entry = pop_eh_entry (&catchstack);
+ free (entry);
+
+ if (! exceptions_via_longjmp)
+ {
+ outer_context = ehstack.top->entry->outer_context;
+
+ /* Finish the rethrow region. size_zero_node is just a NOP. */
+ expand_eh_region_end (size_zero_node);
+ }
+
+ /* Code to throw out to outer context, if we fall off end of catch
+ handlers. This is rethrow (Lresume, same id, same obj) in the
+ documentation. We use Lresume because we know that it will throw
+ to the correct context.
+
+ In other words, if the catch handler doesn't exit or return, we
+ do a "throw" (using the address of Lresume as the point being
+ thrown from) so that the outer EH region can then try to process
+ the exception. */
+ expand_rethrow (outer_context);
+
+ /* Now we have the complete catch sequence. */
+ new_catch_clause = get_insns ();
+ end_sequence ();
+
+ /* This level of catch blocks is done, so set up the successful
+ catch jump label for the next layer of catch blocks. */
+ pop_label_entry (&caught_return_label_stack);
+ pop_label_entry (&outer_context_label_stack);
+
+ /* Add the new sequence of catches to the main one for this function. */
+ push_to_sequence (catch_clauses);
+ emit_insns (new_catch_clause);
+ catch_clauses = get_insns ();
+ end_sequence ();
+
+ /* Here we fall through into the continuation code. */
+}
+
+/* Rethrow from the outer context LABEL. */
+
+static void
+expand_rethrow (label)
+ rtx label;
+{
+ if (exceptions_via_longjmp)
+ emit_throw ();
+ else
+ emit_jump (label);
+}
+
+/* End all the pending exception regions on protect_list. The handlers
+ will be emitted when expand_leftover_cleanups is invoked. */
+
+void
+end_protect_partials ()
+{
+ while (protect_list)
+ {
+ expand_eh_region_end (TREE_VALUE (protect_list));
+ protect_list = TREE_CHAIN (protect_list);
+ }
+}
+
+/* Arrange for __terminate to be called if there is an unhandled throw
+ from within E. */
+
+tree
+protect_with_terminate (e)
+ tree e;
+{
+ /* We only need to do this when using setjmp/longjmp EH and the
+ language requires it, as otherwise we protect all of the handlers
+ at once, if we need to. */
+ if (exceptions_via_longjmp && protect_cleanup_actions_with_terminate)
+ {
+ tree handler, result;
+
+ /* All cleanups must be on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+
+ handler = make_node (RTL_EXPR);
+ TREE_TYPE (handler) = void_type_node;
+ RTL_EXPR_RTL (handler) = const0_rtx;
+ TREE_SIDE_EFFECTS (handler) = 1;
+ start_sequence_for_rtl_expr (handler);
+
+ emit_library_call (terminate_libfunc, 0, VOIDmode, 0);
+ emit_barrier ();
+
+ RTL_EXPR_SEQUENCE (handler) = get_insns ();
+ end_sequence ();
+
+ result = build (TRY_CATCH_EXPR, TREE_TYPE (e), e, handler);
+ TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (e);
+ TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (e);
+ TREE_READONLY (result) = TREE_READONLY (e);
+
+ pop_obstacks ();
+
+ e = result;
+ }
+
+ return e;
+}
+
+/* The exception table that we build that is used for looking up and
+ dispatching exceptions, the current number of entries, and its
+ maximum size before we have to extend it.
+
+ The number in eh_table is the code label number of the exception
+ handler for the region. This is added by add_eh_table_entry and
+ used by output_exception_table_entry. */
+
+static int *eh_table = NULL;
+static int eh_table_size = 0;
+static int eh_table_max_size = 0;
+
+/* Note the need for an exception table entry for region N. If we
+ don't need to output an explicit exception table, avoid all of the
+ extra work.
+
+ Called from final_scan_insn when a NOTE_INSN_EH_REGION_BEG is seen.
+ (Or NOTE_INSN_EH_REGION_END sometimes)
+ N is the NOTE_BLOCK_NUMBER of the note, which comes from the code
+ label number of the exception handler for the region. */
+
+void
+add_eh_table_entry (n)
+ int n;
+{
+#ifndef OMIT_EH_TABLE
+ if (eh_table_size >= eh_table_max_size)
+ {
+ if (eh_table)
+ {
+ eh_table_max_size += eh_table_max_size>>1;
+
+ if (eh_table_max_size < 0)
+ abort ();
+
+ eh_table = (int *) xrealloc (eh_table,
+ eh_table_max_size * sizeof (int));
+ }
+ else
+ {
+ eh_table_max_size = 252;
+ eh_table = (int *) xmalloc (eh_table_max_size * sizeof (int));
+ }
+ }
+ eh_table[eh_table_size++] = n;
+#endif
+}
+
+/* Return a non-zero value if we need to output an exception table.
+
+ On some platforms, we don't have to output a table explicitly.
+ This routine doesn't mean we don't have one. */
+
+int
+exception_table_p ()
+{
+ if (eh_table)
+ return 1;
+
+ return 0;
+}
+
+/* Output the entry of the exception table corresponding to the
+ exception region numbered N to file FILE.
+
+ N is the code label number corresponding to the handler of the
+ region. */
+
+static void
+output_exception_table_entry (file, n)
+ FILE *file;
+ int n;
+{
+ char buf[256];
+ rtx sym;
+ struct handler_info *handler;
+
+ handler = get_first_handler (n);
+
+ for ( ; handler != NULL; handler = handler->next)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LEHB", n);
+ sym = gen_rtx_SYMBOL_REF (Pmode, buf);
+ assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+ ASM_GENERATE_INTERNAL_LABEL (buf, "LEHE", n);
+ sym = gen_rtx_SYMBOL_REF (Pmode, buf);
+ assemble_integer (sym, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+ assemble_integer (handler->handler_label,
+ POINTER_SIZE / BITS_PER_UNIT, 1);
+
+ if (flag_new_exceptions)
+ {
+ if (handler->type_info == NULL)
+ assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+ else
+ if (handler->type_info == CATCH_ALL_TYPE)
+ assemble_integer (GEN_INT (CATCH_ALL_TYPE),
+ POINTER_SIZE / BITS_PER_UNIT, 1);
+ else
+ output_constant ((tree)(handler->type_info),
+ POINTER_SIZE / BITS_PER_UNIT);
+ }
+ putc ('\n', file); /* blank line */
+ }
+}
+
+/* Output the exception table if we have and need one. */
+
+static short language_code = 0;
+static short version_code = 0;
+
+/* This routine will set the language code for exceptions. */
+void set_exception_lang_code (code)
+ short code;
+{
+ language_code = code;
+}
+
+/* This routine will set the language version code for exceptions. */
+void set_exception_version_code (code)
+ short code;
+{
+ version_code = code;
+}
+
+
+void
+output_exception_table ()
+{
+ int i;
+ extern FILE *asm_out_file;
+
+ if (! doing_eh (0) || ! eh_table)
+ return;
+
+ exception_section ();
+
+ /* Beginning marker for table. */
+ assemble_align (GET_MODE_ALIGNMENT (ptr_mode));
+ assemble_label ("__EXCEPTION_TABLE__");
+
+ if (flag_new_exceptions)
+ {
+ assemble_integer (GEN_INT (NEW_EH_RUNTIME),
+ POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_integer (GEN_INT (language_code), 2 , 1);
+ assemble_integer (GEN_INT (version_code), 2 , 1);
+
+ /* Add enough padding to make sure table aligns on a pointer boundry. */
+ i = GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT - 4;
+ for ( ; i < 0; i = i + GET_MODE_ALIGNMENT (ptr_mode) / BITS_PER_UNIT)
+ ;
+ if (i != 0)
+ assemble_integer (const0_rtx, i , 1);
+ }
+
+ for (i = 0; i < eh_table_size; ++i)
+ output_exception_table_entry (asm_out_file, eh_table[i]);
+
+ free (eh_table);
+ clear_function_eh_region ();
+
+ /* Ending marker for table. */
+ assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+ /* for binary compatability, the old __throw checked the second
+ position for a -1, so we should output at least 2 -1's */
+ if (! flag_new_exceptions)
+ assemble_integer (constm1_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+
+ putc ('\n', asm_out_file); /* blank line */
+}
+
+/* Emit code to get EH context.
+
+ We have to scan thru the code to find possible EH context registers.
+ Inlined functions may use it too, and thus we'll have to be able
+ to change them too.
+
+ This is done only if using exceptions_via_longjmp. */
+
+void
+emit_eh_context ()
+{
+ rtx insn;
+ rtx ehc = 0;
+
+ if (! doing_eh (0))
+ return;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == USE)
+ {
+ rtx reg = find_reg_note (insn, REG_EH_CONTEXT, 0);
+ if (reg)
+ {
+ rtx insns;
+
+ start_sequence ();
+
+ /* If this is the first use insn, emit the call here. This
+ will always be at the top of our function, because if
+ expand_inline_function notices a REG_EH_CONTEXT note, it
+ adds a use insn to this function as well. */
+ if (ehc == 0)
+ ehc = call_get_eh_context ();
+
+ emit_move_insn (XEXP (reg, 0), ehc);
+ insns = get_insns ();
+ end_sequence ();
+
+ emit_insns_before (insns, insn);
+ }
+ }
+}
+
+/* Scan the current insns and build a list of handler labels. The
+ resulting list is placed in the global variable exception_handler_labels.
+
+ It is called after the last exception handling region is added to
+ the current function (when the rtl is almost all built for the
+ current function) and before the jump optimization pass. */
+
+void
+find_exception_handler_labels ()
+{
+ rtx insn;
+
+ exception_handler_labels = NULL_RTX;
+
+ /* If we aren't doing exception handling, there isn't much to check. */
+ if (! doing_eh (0))
+ return;
+
+ /* For each start of a region, add its label to the list. */
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ struct handler_info* ptr;
+ if (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+ {
+ ptr = get_first_handler (NOTE_BLOCK_NUMBER (insn));
+ for ( ; ptr; ptr = ptr->next)
+ {
+ /* make sure label isn't in the list already */
+ rtx x;
+ for (x = exception_handler_labels; x; x = XEXP (x, 1))
+ if (XEXP (x, 0) == ptr->handler_label)
+ break;
+ if (! x)
+ exception_handler_labels = gen_rtx_EXPR_LIST (VOIDmode,
+ ptr->handler_label, exception_handler_labels);
+ }
+ }
+ }
+}
+
+/* Return a value of 1 if the parameter label number is an exception handler
+ label. Return 0 otherwise. */
+
+int
+is_exception_handler_label (lab)
+ int lab;
+{
+ rtx x;
+ for (x = exception_handler_labels ; x ; x = XEXP (x, 1))
+ if (lab == CODE_LABEL_NUMBER (XEXP (x, 0)))
+ return 1;
+ return 0;
+}
+
+/* Perform sanity checking on the exception_handler_labels list.
+
+ Can be called after find_exception_handler_labels is called to
+ build the list of exception handlers for the current function and
+ before we finish processing the current function. */
+
+void
+check_exception_handler_labels ()
+{
+ rtx insn, insn2;
+
+ /* If we aren't doing exception handling, there isn't much to check. */
+ if (! doing_eh (0))
+ return;
+
+ /* Make sure there is no more than 1 copy of a label */
+ for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
+ {
+ int count = 0;
+ for (insn2 = exception_handler_labels; insn2; insn2 = XEXP (insn2, 1))
+ if (XEXP (insn, 0) == XEXP (insn2, 0))
+ count++;
+ if (count != 1)
+ warning ("Counted %d copies of EH region %d in list.\n", count,
+ CODE_LABEL_NUMBER (insn));
+ }
+
+}
+
+/* This group of functions initializes the exception handling data
+ structures at the start of the compilation, initializes the data
+ structures at the start of a function, and saves and restores the
+ exception handling data structures for the start/end of a nested
+ function. */
+
+/* Toplevel initialization for EH things. */
+
+void
+init_eh ()
+{
+}
+
+/* Initialize the per-function EH information. */
+
+void
+init_eh_for_function ()
+{
+ ehstack.top = 0;
+ catchstack.top = 0;
+ ehqueue.head = ehqueue.tail = 0;
+ catch_clauses = NULL_RTX;
+ false_label_stack = 0;
+ caught_return_label_stack = 0;
+ protect_list = NULL_TREE;
+ current_function_ehc = NULL_RTX;
+}
+
+/* Save some of the per-function EH info into the save area denoted by
+ P.
+
+ This is currently called from save_stmt_status. */
+
+void
+save_eh_status (p)
+ struct function *p;
+{
+ if (p == NULL)
+ abort ();
+
+ p->ehstack = ehstack;
+ p->catchstack = catchstack;
+ p->ehqueue = ehqueue;
+ p->catch_clauses = catch_clauses;
+ p->false_label_stack = false_label_stack;
+ p->caught_return_label_stack = caught_return_label_stack;
+ p->protect_list = protect_list;
+ p->ehc = current_function_ehc;
+
+ init_eh_for_function ();
+}
+
+/* Restore the per-function EH info saved into the area denoted by P.
+
+ This is currently called from restore_stmt_status. */
+
+void
+restore_eh_status (p)
+ struct function *p;
+{
+ if (p == NULL)
+ abort ();
+
+ protect_list = p->protect_list;
+ caught_return_label_stack = p->caught_return_label_stack;
+ false_label_stack = p->false_label_stack;
+ catch_clauses = p->catch_clauses;
+ ehqueue = p->ehqueue;
+ ehstack = p->ehstack;
+ catchstack = p->catchstack;
+ current_function_ehc = p->ehc;
+}
+
+/* This section is for the exception handling specific optimization
+ pass. First are the internal routines, and then the main
+ optimization pass. */
+
+/* Determine if the given INSN can throw an exception. */
+
+static int
+can_throw (insn)
+ rtx insn;
+{
+ /* Calls can always potentially throw exceptions. */
+ if (GET_CODE (insn) == CALL_INSN)
+ return 1;
+
+ if (asynchronous_exceptions)
+ {
+ /* If we wanted asynchronous exceptions, then everything but NOTEs
+ and CODE_LABELs could throw. */
+ if (GET_CODE (insn) != NOTE && GET_CODE (insn) != CODE_LABEL)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Scan a exception region looking for the matching end and then
+ remove it if possible. INSN is the start of the region, N is the
+ region number, and DELETE_OUTER is to note if anything in this
+ region can throw.
+
+ Regions are removed if they cannot possibly catch an exception.
+ This is determined by invoking can_throw on each insn within the
+ region; if can_throw returns true for any of the instructions, the
+ region can catch an exception, since there is an insn within the
+ region that is capable of throwing an exception.
+
+ Returns the NOTE_INSN_EH_REGION_END corresponding to this region, or
+ calls abort if it can't find one.
+
+ Can abort if INSN is not a NOTE_INSN_EH_REGION_BEGIN, or if N doesn't
+ correspond to the region number, or if DELETE_OUTER is NULL. */
+
+static rtx
+scan_region (insn, n, delete_outer)
+ rtx insn;
+ int n;
+ int *delete_outer;
+{
+ rtx start = insn;
+
+ /* Assume we can delete the region. */
+ int delete = 1;
+
+ if (insn == NULL_RTX
+ || GET_CODE (insn) != NOTE
+ || NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
+ || NOTE_BLOCK_NUMBER (insn) != n
+ || delete_outer == NULL)
+ abort ();
+
+ insn = NEXT_INSN (insn);
+
+ /* Look for the matching end. */
+ while (! (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
+ {
+ /* If anything can throw, we can't remove the region. */
+ if (delete && can_throw (insn))
+ {
+ delete = 0;
+ }
+
+ /* Watch out for and handle nested regions. */
+ if (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+ {
+ insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &delete);
+ }
+
+ insn = NEXT_INSN (insn);
+ }
+
+ /* The _BEG/_END NOTEs must match and nest. */
+ if (NOTE_BLOCK_NUMBER (insn) != n)
+ abort ();
+
+ /* If anything in this exception region can throw, we can throw. */
+ if (! delete)
+ *delete_outer = 0;
+ else
+ {
+ /* Delete the start and end of the region. */
+ delete_insn (start);
+ delete_insn (insn);
+
+/* We no longer removed labels here, since flow will now remove any
+ handler which cannot be called any more. */
+
+#if 0
+ /* Only do this part if we have built the exception handler
+ labels. */
+ if (exception_handler_labels)
+ {
+ rtx x, *prev = &exception_handler_labels;
+
+ /* Find it in the list of handlers. */
+ for (x = exception_handler_labels; x; x = XEXP (x, 1))
+ {
+ rtx label = XEXP (x, 0);
+ if (CODE_LABEL_NUMBER (label) == n)
+ {
+ /* If we are the last reference to the handler,
+ delete it. */
+ if (--LABEL_NUSES (label) == 0)
+ delete_insn (label);
+
+ if (optimize)
+ {
+ /* Remove it from the list of exception handler
+ labels, if we are optimizing. If we are not, then
+ leave it in the list, as we are not really going to
+ remove the region. */
+ *prev = XEXP (x, 1);
+ XEXP (x, 1) = 0;
+ XEXP (x, 0) = 0;
+ }
+
+ break;
+ }
+ prev = &XEXP (x, 1);
+ }
+ }
+#endif
+ }
+ return insn;
+}
+
+/* Perform various interesting optimizations for exception handling
+ code.
+
+ We look for empty exception regions and make them go (away). The
+ jump optimization code will remove the handler if nothing else uses
+ it. */
+
+void
+exception_optimize ()
+{
+ rtx insn;
+ int n;
+
+ /* Remove empty regions. */
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ {
+ if (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+ {
+ /* Since scan_region will return the NOTE_INSN_EH_REGION_END
+ insn, we will indirectly skip through all the insns
+ inbetween. We are also guaranteed that the value of insn
+ returned will be valid, as otherwise scan_region won't
+ return. */
+ insn = scan_region (insn, NOTE_BLOCK_NUMBER (insn), &n);
+ }
+ }
+}
+
+/* Various hooks for the DWARF 2 __throw routine. */
+
+/* Do any necessary initialization to access arbitrary stack frames.
+ On the SPARC, this means flushing the register windows. */
+
+void
+expand_builtin_unwind_init ()
+{
+ /* Set this so all the registers get saved in our frame; we need to be
+ able to copy the saved values for any registers from frames we unwind. */
+ current_function_has_nonlocal_label = 1;
+
+#ifdef SETUP_FRAME_ADDRESSES
+ SETUP_FRAME_ADDRESSES ();
+#endif
+}
+
+/* Given a value extracted from the return address register or stack slot,
+ return the actual address encoded in that value. */
+
+rtx
+expand_builtin_extract_return_addr (addr_tree)
+ tree addr_tree;
+{
+ rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
+ return eh_outer_context (addr);
+}
+
+/* Given an actual address in addr_tree, do any necessary encoding
+ and return the value to be stored in the return address register or
+ stack slot so the epilogue will return to that address. */
+
+rtx
+expand_builtin_frob_return_addr (addr_tree)
+ tree addr_tree;
+{
+ rtx addr = expand_expr (addr_tree, NULL_RTX, Pmode, 0);
+#ifdef RETURN_ADDR_OFFSET
+ addr = plus_constant (addr, -RETURN_ADDR_OFFSET);
+#endif
+ return addr;
+}
+
+/* Given an actual address in addr_tree, set the return address register up
+ so the epilogue will return to that address. If the return address is
+ not in a register, do nothing. */
+
+void
+expand_builtin_set_return_addr_reg (addr_tree)
+ tree addr_tree;
+{
+ rtx tmp;
+ rtx ra = expand_builtin_return_addr (BUILT_IN_RETURN_ADDRESS,
+ 0, hard_frame_pointer_rtx);
+
+ if (GET_CODE (ra) != REG || REGNO (ra) >= FIRST_PSEUDO_REGISTER)
+ return;
+
+ tmp = force_operand (expand_builtin_frob_return_addr (addr_tree), ra);
+ if (tmp != ra)
+ emit_move_insn (ra, tmp);
+}
+
+/* Choose two registers for communication between the main body of
+ __throw and the stub for adjusting the stack pointer. The first register
+ is used to pass the address of the exception handler; the second register
+ is used to pass the stack pointer offset.
+
+ For register 1 we use the return value register for a void *.
+ For register 2 we use the static chain register if it exists and is
+ different from register 1, otherwise some arbitrary call-clobbered
+ register. */
+
+static void
+eh_regs (r1, r2, outgoing)
+ rtx *r1, *r2;
+ int outgoing;
+{
+ rtx reg1, reg2;
+
+#ifdef FUNCTION_OUTGOING_VALUE
+ if (outgoing)
+ reg1 = FUNCTION_OUTGOING_VALUE (build_pointer_type (void_type_node),
+ current_function_decl);
+ else
+#endif
+ reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node),
+ current_function_decl);
+
+#ifdef STATIC_CHAIN_REGNUM
+ if (outgoing)
+ reg2 = static_chain_incoming_rtx;
+ else
+ reg2 = static_chain_rtx;
+ if (REGNO (reg2) == REGNO (reg1))
+#endif /* STATIC_CHAIN_REGNUM */
+ reg2 = NULL_RTX;
+
+ if (reg2 == NULL_RTX)
+ {
+ int i;
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+ if (call_used_regs[i] && ! fixed_regs[i] && i != REGNO (reg1))
+ {
+ reg2 = gen_rtx_REG (Pmode, i);
+ break;
+ }
+
+ if (reg2 == NULL_RTX)
+ abort ();
+ }
+
+ *r1 = reg1;
+ *r2 = reg2;
+}
+
+
+/* Retrieve the register which contains the pointer to the eh_context
+ structure set the __throw. */
+
+rtx
+get_reg_for_handler ()
+{
+ rtx reg1;
+ reg1 = FUNCTION_VALUE (build_pointer_type (void_type_node),
+ current_function_decl);
+ return reg1;
+}
+
+
+/* Emit inside of __throw a stub which adjusts the stack pointer and jumps
+ to the exception handler. __throw will set up the necessary values
+ and then return to the stub. */
+
+rtx
+expand_builtin_eh_stub_old ()
+{
+ rtx stub_start = gen_label_rtx ();
+ rtx after_stub = gen_label_rtx ();
+ rtx handler, offset;
+
+ emit_jump (after_stub);
+ emit_label (stub_start);
+
+ eh_regs (&handler, &offset, 0);
+
+ adjust_stack (offset);
+ emit_indirect_jump (handler);
+ emit_label (after_stub);
+ return gen_rtx_LABEL_REF (Pmode, stub_start);
+}
+
+rtx
+expand_builtin_eh_stub ()
+{
+ rtx stub_start = gen_label_rtx ();
+ rtx after_stub = gen_label_rtx ();
+ rtx handler, offset;
+ rtx temp;
+
+ emit_jump (after_stub);
+ emit_label (stub_start);
+
+ eh_regs (&handler, &offset, 0);
+
+ adjust_stack (offset);
+
+ /* Handler is in fact a pointer to the _eh_context structure, we need
+ to pick out the handler field (first element), and jump to there,
+ leaving the pointer to _eh_conext in the same hardware register. */
+
+ temp = gen_rtx_MEM (Pmode, handler);
+ MEM_IN_STRUCT_P (temp) = 1;
+ RTX_UNCHANGING_P (temp) = 1;
+ emit_move_insn (offset, temp);
+ emit_insn (gen_rtx_USE (Pmode, handler));
+
+ emit_indirect_jump (offset);
+
+ emit_label (after_stub);
+ return gen_rtx_LABEL_REF (Pmode, stub_start);
+}
+
+/* Set up the registers for passing the handler address and stack offset
+ to the stub above. */
+
+void
+expand_builtin_set_eh_regs (handler, offset)
+ tree handler, offset;
+{
+ rtx reg1, reg2;
+
+ eh_regs (&reg1, &reg2, 1);
+
+ store_expr (offset, reg2, 0);
+ store_expr (handler, reg1, 0);
+
+ /* These will be used by the stub. */
+ emit_insn (gen_rtx_USE (VOIDmode, reg1));
+ emit_insn (gen_rtx_USE (VOIDmode, reg2));
+}
+
+
+
+/* This contains the code required to verify whether arbitrary instructions
+ are in the same exception region. */
+
+static int *insn_eh_region = (int *)0;
+static int maximum_uid;
+
+static void
+set_insn_eh_region (first, region_num)
+ rtx *first;
+ int region_num;
+{
+ rtx insn;
+ int rnum;
+
+ for (insn = *first; insn; insn = NEXT_INSN (insn))
+ {
+ if ((GET_CODE (insn) == NOTE) &&
+ (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG))
+ {
+ rnum = NOTE_BLOCK_NUMBER (insn);
+ insn_eh_region[INSN_UID (insn)] = rnum;
+ insn = NEXT_INSN (insn);
+ set_insn_eh_region (&insn, rnum);
+ /* Upon return, insn points to the EH_REGION_END of nested region */
+ continue;
+ }
+ insn_eh_region[INSN_UID (insn)] = region_num;
+ if ((GET_CODE (insn) == NOTE) &&
+ (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
+ break;
+ }
+ *first = insn;
+}
+
+/* Free the insn table, an make sure it cannot be used again. */
+
+void
+free_insn_eh_region ()
+{
+ if (!doing_eh (0))
+ return;
+
+ if (insn_eh_region)
+ {
+ free (insn_eh_region);
+ insn_eh_region = (int *)0;
+ }
+}
+
+/* Initialize the table. max_uid must be calculated and handed into
+ this routine. If it is unavailable, passing a value of 0 will
+ cause this routine to calculate it as well. */
+
+void
+init_insn_eh_region (first, max_uid)
+ rtx first;
+ int max_uid;
+{
+ rtx insn;
+
+ if (!doing_eh (0))
+ return;
+
+ if (insn_eh_region)
+ free_insn_eh_region();
+
+ if (max_uid == 0)
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ if (INSN_UID (insn) > max_uid) /* find largest UID */
+ max_uid = INSN_UID (insn);
+
+ maximum_uid = max_uid;
+ insn_eh_region = (int *) malloc ((max_uid + 1) * sizeof (int));
+ insn = first;
+ set_insn_eh_region (&insn, 0);
+}
+
+
+/* Check whether 2 instructions are within the same region. */
+
+int
+in_same_eh_region (insn1, insn2)
+ rtx insn1, insn2;
+{
+ int ret, uid1, uid2;
+
+ /* If no exceptions, instructions are always in same region. */
+ if (!doing_eh (0))
+ return 1;
+
+ /* If the table isn't allocated, assume the worst. */
+ if (!insn_eh_region)
+ return 0;
+
+ uid1 = INSN_UID (insn1);
+ uid2 = INSN_UID (insn2);
+
+ /* if instructions have been allocated beyond the end, either
+ the table is out of date, or this is a late addition, or
+ something... Assume the worst. */
+ if (uid1 > maximum_uid || uid2 > maximum_uid)
+ return 0;
+
+ ret = (insn_eh_region[uid1] == insn_eh_region[uid2]);
+ return ret;
+}
+
diff --git a/contrib/gcc/except.h b/contrib/gcc/except.h
new file mode 100644
index 0000000..c08d0c5
--- /dev/null
+++ b/contrib/gcc/except.h
@@ -0,0 +1,385 @@
+/* Exception Handling interface routines.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Mike Stump <mrs@cygnus.com>.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#if !defined(NULL_RTX) && !defined(rtx)
+typedef struct rtx_def *_except_rtx;
+#define rtx _except_rtx
+#endif
+
+#ifdef TREE_CODE
+
+/* A stack of labels. CHAIN points to the next entry in the stack. */
+
+struct label_node {
+ union {
+ rtx rlabel;
+ tree tlabel;
+ } u;
+ struct label_node *chain;
+};
+
+/* An eh_entry is used to describe one exception handling region.
+
+ OUTER_CONTEXT is the label used for rethrowing into the outer context.
+
+ EXCEPTION_HANDLER_LABEL is the label corresponding to the handler
+ for this region.
+
+ LABEL_USED indicates whether a CATCH block has already used this
+ label or not. New ones are needed for additional catch blocks if
+ it has.
+
+ FINALIZATION is the tree codes for the handler, or is NULL_TREE if
+ one hasn't been generated yet, or is integer_zero_node to mark the
+ end of a group of try blocks. */
+
+struct eh_entry {
+ rtx outer_context;
+ rtx exception_handler_label;
+ tree finalization;
+ int label_used;
+};
+
+/* A list of EH_ENTRYs. ENTRY is the entry; CHAIN points to the next
+ entry in the list, or is NULL if this is the last entry. */
+
+struct eh_node {
+ struct eh_entry *entry;
+ struct eh_node *chain;
+};
+
+/* A stack of EH_ENTRYs. TOP is the topmost entry on the stack. TOP is
+ NULL if the stack is empty. */
+
+struct eh_stack {
+ struct eh_node *top;
+};
+
+/* A queue of EH_ENTRYs. HEAD is the front of the queue; TAIL is the
+ end (the latest entry). HEAD and TAIL are NULL if the queue is
+ empty. */
+
+struct eh_queue {
+ struct eh_node *head;
+ struct eh_node *tail;
+};
+
+
+/* Start an exception handling region. All instructions emitted after
+ this point are considered to be part of the region until
+ expand_eh_region_end () is invoked. */
+
+extern void expand_eh_region_start PROTO((void));
+
+/* Just like expand_eh_region_start, except if a cleanup action is
+ entered on the cleanup chain, the TREE_PURPOSE of the element put
+ on the chain is DECL. DECL should be the associated VAR_DECL, if
+ any, otherwise it should be NULL_TREE. */
+
+extern void expand_eh_region_start_for_decl PROTO((tree));
+
+/* Start an exception handling region for the given cleanup action.
+ All instructions emitted after this point are considered to be part
+ of the region until expand_eh_region_end () is invoked. CLEANUP is
+ the cleanup action to perform. The return value is true if the
+ exception region was optimized away. If that case,
+ expand_eh_region_end does not need to be called for this cleanup,
+ nor should it be.
+
+ This routine notices one particular common case in C++ code
+ generation, and optimizes it so as to not need the exception
+ region. */
+
+extern int expand_eh_region_start_tree PROTO((tree, tree));
+
+/* End an exception handling region. The information about the region
+ is found on the top of ehstack.
+
+ HANDLER is either the cleanup for the exception region, or if we're
+ marking the end of a try block, HANDLER is integer_zero_node.
+
+ HANDLER will be transformed to rtl when expand_leftover_cleanups ()
+ is invoked. */
+
+extern void expand_eh_region_end PROTO((tree));
+
+/* Push RLABEL or TLABEL onto LABELSTACK. Only one of RLABEL or TLABEL
+ should be set; the other must be NULL. */
+
+extern void push_label_entry PROTO((struct label_node **labelstack, rtx rlabel, tree tlabel));
+
+/* Pop the topmost entry from LABELSTACK and return its value as an
+ rtx node. If LABELSTACK is empty, return NULL. */
+
+extern rtx pop_label_entry PROTO((struct label_node **labelstack));
+
+/* Return the topmost entry of LABELSTACK as a tree node, or return
+ NULL_TREE if LABELSTACK is empty. */
+
+extern tree top_label_entry PROTO((struct label_node **labelstack));
+
+/* A set of insns for the catch clauses in the current function. They
+ will be emitted at the end of the current function. */
+
+extern rtx catch_clauses;
+
+#endif
+
+/* Test: is exception handling turned on? */
+
+extern int doing_eh PROTO ((int));
+
+/* Toplevel initialization for EH. */
+
+void set_exception_lang_code PROTO((short));
+void set_exception_version_code PROTO((short));
+
+/* A list of handlers asocciated with an exception region. HANDLER_LABEL
+ is the the label that control should be transfered to if the data
+ in TYPE_INFO matches an exception. a value of NULL_TREE for TYPE_INFO
+ means This is a cleanup, and must always be called. A value of
+ CATCH_ALL_TYPE works like a cleanup, but a call to the runtime matcher
+ is still performed to avoid being caught by a different language
+ exception. NEXT is a pointer to the next handler for this region.
+ NULL means there are no more. */
+
+typedef struct handler_info
+{
+ rtx handler_label;
+ void *type_info;
+ struct handler_info *next;
+} handler_info;
+
+
+/* Add a new eh_entry for this function, The parameter specifies what
+ exception region number NOTE insns use to delimit this range.
+ The integer returned is uniquely identifies this exception range
+ within an internal table. */
+
+int new_eh_region_entry PROTO((int));
+
+/* Add new handler information to an exception range. The first parameter
+ specifies the range number (returned from new_eh_entry()). The second
+ parameter specifies the handler. By default the handler is inserted at
+ the end of the list. A handler list may contain only ONE NULL_TREE
+ typeinfo entry. Regardless where it is positioned, a NULL_TREE entry
+ is always output as the LAST handler in the exception table for a region. */
+
+void add_new_handler PROTO((int, struct handler_info *));
+
+/* Remove a handler label. The handler label is being deleted, so all
+ regions which reference this handler should have it removed from their
+ list of possible handlers. Any region which has the final handler
+ removed can be deleted. */
+
+void remove_handler PROTO((rtx));
+
+/* Create a new handler structure initialized with the handler label and
+ typeinfo fields passed in. */
+
+struct handler_info *get_new_handler PROTO((rtx, void *));
+
+/* Make a duplicate of an exception region by copying all the handlers
+ for an exception region. Return the new handler index. */
+
+int duplicate_handlers PROTO((int, int));
+
+
+/* Get a pointer to the first handler in an exception region's list. */
+
+struct handler_info *get_first_handler PROTO((int));
+
+/* Find all the runtime handlers type matches currently referenced */
+
+int find_all_handler_type_matches PROTO((void ***));
+
+extern void init_eh PROTO((void));
+
+/* Initialization for the per-function EH data. */
+
+extern void init_eh_for_function PROTO((void));
+
+/* Generate an exception label. Use instead of gen_label_rtx */
+
+extern rtx gen_exception_label PROTO((void));
+
+/* Adds an EH table entry for EH entry number N. Called from
+ final_scan_insn for NOTE_INSN_EH_REGION_BEG. */
+
+extern void add_eh_table_entry PROTO((int n));
+
+/* Start a catch clause, triggered by runtime value paramter. */
+
+#ifdef TREE_CODE
+extern void start_catch_handler PROTO((tree));
+#endif
+
+/* Returns a non-zero value if we need to output an exception table. */
+
+extern int exception_table_p PROTO((void));
+
+/* Outputs the exception table if we have one. */
+
+extern void output_exception_table PROTO((void));
+
+/* Given a return address in ADDR, determine the address we should use
+ to find the corresponding EH region. */
+
+extern rtx eh_outer_context PROTO((rtx addr));
+
+/* Called at the start of a block of try statements for which there is
+ a supplied catch handler. */
+
+extern void expand_start_try_stmts PROTO((void));
+
+/* Called at the start of a block of catch statements. It terminates the
+ previous set of try statements. */
+
+extern void expand_start_all_catch PROTO((void));
+
+/* Called at the end of a block of catch statements. */
+
+extern void expand_end_all_catch PROTO((void));
+
+#ifdef TREE_CODE
+/* Create a new exception region and add the handler for the region
+ onto a list. These regions will be ended (and their handlers
+ emitted) when end_protect_partials is invoked. */
+
+extern void add_partial_entry PROTO((tree handler));
+#endif
+
+/* End all of the pending exception regions that have handlers added with
+ push_protect_entry (). */
+
+extern void end_protect_partials PROTO((void));
+
+/* An internal throw. */
+
+extern void expand_internal_throw PROTO((void));
+
+/* Called from expand_exception_blocks and expand_end_catch_block to
+ expand and pending handlers. */
+
+extern void expand_leftover_cleanups PROTO((void));
+
+/* If necessary, emit insns to get EH context for the current
+ function. */
+
+extern void emit_eh_context PROTO((void));
+
+/* Builds a list of handler labels and puts them in the global
+ variable exception_handler_labels. */
+
+extern void find_exception_handler_labels PROTO((void));
+
+/* Determine if an arbitrary label is an exception label */
+
+extern int is_exception_handler_label PROTO((int));
+
+/* Performs sanity checking on the check_exception_handler_labels
+ list. */
+
+extern void check_exception_handler_labels PROTO((void));
+
+/* A stack used to keep track of the label used to resume normal program
+ flow out of the current exception handler region. */
+
+extern struct label_node *caught_return_label_stack;
+
+/* Keeps track of the label used as the context of a throw to rethrow an
+ exception to the outer exception region. */
+
+extern struct label_node *outer_context_label_stack;
+
+/* A random area used for purposes elsewhere. */
+
+extern struct label_node *false_label_stack;
+
+/* A list of labels used for exception handlers. It is created by
+ find_exception_handler_labels for the optimization passes. */
+
+extern rtx exception_handler_labels;
+
+/* Performs optimizations for exception handling, such as removing
+ unnecessary exception regions. Invoked from jump_optimize (). */
+
+extern void exception_optimize PROTO((void));
+
+/* Return EH context (and set it up once per fn). */
+extern rtx get_eh_context PROTO((void));
+
+/* Get the dynamic handler chain. */
+extern rtx get_dynamic_handler_chain PROTO((void));
+
+/* Get the dynamic cleanup chain. */
+extern rtx get_dynamic_cleanup_chain PROTO((void));
+
+/* Throw an exception. */
+
+extern void emit_throw PROTO((void));
+
+/* One to use setjmp/longjmp method of generating code. */
+
+extern int exceptions_via_longjmp;
+
+/* One to enable asynchronous exception support. */
+
+extern int asynchronous_exceptions;
+
+/* One to protect cleanup actions with a handler that calls
+ __terminate, zero otherwise. */
+
+extern int protect_cleanup_actions_with_terminate;
+
+#ifdef TREE_CODE
+extern tree protect_with_terminate PROTO((tree));
+#endif
+
+extern void expand_fixup_region_start PROTO((void));
+#ifdef TREE_CODE
+extern void expand_fixup_region_end PROTO((tree));
+#endif
+
+/* Various hooks for the DWARF 2 __throw routine. */
+
+void expand_builtin_unwind_init PROTO((void));
+rtx expand_builtin_dwarf_fp_regnum PROTO((void));
+rtx expand_builtin_eh_stub PROTO((void));
+rtx expand_builtin_eh_stub_old PROTO((void));
+#ifdef TREE_CODE
+rtx expand_builtin_frob_return_addr PROTO((tree));
+rtx expand_builtin_extract_return_addr PROTO((tree));
+void expand_builtin_set_return_addr_reg PROTO((tree));
+void expand_builtin_set_eh_regs PROTO((tree, tree));
+rtx expand_builtin_dwarf_reg_size PROTO((tree, rtx));
+#endif
+
+
+/* Checking whether 2 instructions are within the same exception region. */
+
+int in_same_eh_region PROTO((rtx, rtx));
+void free_insn_eh_region PROTO((void));
+void init_insn_eh_region PROTO((rtx, int));
+
+#ifdef rtx
+#undef rtx
+#endif
diff --git a/contrib/gcc/explow.c b/contrib/gcc/explow.c
index 1491217..fc7ebf2 100644
--- a/contrib/gcc/explow.c
+++ b/contrib/gcc/explow.c
@@ -1,5 +1,5 @@
/* Subroutines for manipulating rtx's in semantically interesting ways.
- Copyright (C) 1987, 1991, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 91, 94-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,6 +20,7 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
@@ -31,7 +32,7 @@ Boston, MA 02111-1307, USA. */
#include "insn-codes.h"
static rtx break_out_memory_refs PROTO((rtx));
-
+static void emit_stack_probe PROTO((rtx));
/* Return an rtx for the sum of X and the integer C.
This function should be used via the `plus_constant' macro. */
@@ -78,10 +79,15 @@ plus_constant_wide (x, c)
if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
{
+ /* Any rtl we create here must go in a saveable obstack, since
+ we might have been called from within combine. */
+ push_obstacks_nochange ();
+ rtl_in_saveable_obstack ();
tem
= force_const_mem (GET_MODE (x),
plus_constant (get_pool_constant (XEXP (x, 0)),
c));
+ pop_obstacks ();
if (memory_address_p (GET_MODE (tem), XEXP (tem, 0)))
return tem;
}
@@ -112,22 +118,26 @@ plus_constant_wide (x, c)
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
return plus_constant (XEXP (x, 0), c + INTVAL (XEXP (x, 1)));
else if (CONSTANT_P (XEXP (x, 0)))
- return gen_rtx (PLUS, mode,
- plus_constant (XEXP (x, 0), c),
- XEXP (x, 1));
+ return gen_rtx_PLUS (mode,
+ plus_constant (XEXP (x, 0), c),
+ XEXP (x, 1));
else if (CONSTANT_P (XEXP (x, 1)))
- return gen_rtx (PLUS, mode,
- XEXP (x, 0),
- plus_constant (XEXP (x, 1), c));
+ return gen_rtx_PLUS (mode,
+ XEXP (x, 0),
+ plus_constant (XEXP (x, 1), c));
+ break;
+
+ default:
+ break;
}
if (c != 0)
- x = gen_rtx (PLUS, mode, x, GEN_INT (c));
+ x = gen_rtx_PLUS (mode, x, GEN_INT (c));
if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
return x;
else if (all_constant)
- return gen_rtx (CONST, mode, x);
+ return gen_rtx_CONST (mode, x);
else
return x;
}
@@ -141,12 +151,10 @@ plus_constant_for_output_wide (x, c)
register rtx x;
register HOST_WIDE_INT c;
{
- register RTX_CODE code = GET_CODE (x);
register enum machine_mode mode = GET_MODE (x);
- int all_constant = 0;
if (GET_CODE (x) == LO_SUM)
- return gen_rtx (LO_SUM, mode, XEXP (x, 0),
+ return gen_rtx_LO_SUM (mode, XEXP (x, 0),
plus_constant_for_output (XEXP (x, 1), c));
else
@@ -188,7 +196,7 @@ eliminate_constant_term (x, constptr)
&& GET_CODE (tem) == CONST_INT)
{
*constptr = tem;
- return gen_rtx (PLUS, GET_MODE (x), x0, x1);
+ return gen_rtx_PLUS (GET_MODE (x), x0, x1);
}
return x;
@@ -251,7 +259,8 @@ expr_size (exp)
&& contains_placeholder_p (size))
size = build (WITH_RECORD_EXPR, sizetype, size, exp);
- return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype), 0);
+ return expand_expr (size, NULL_RTX, TYPE_MODE (sizetype),
+ EXPAND_MEMORY_USE_BAD);
}
/* Return a copy of X in which all memory references
@@ -285,7 +294,7 @@ break_out_memory_refs (x)
register rtx op1 = break_out_memory_refs (XEXP (x, 1));
if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
- x = gen_rtx (GET_CODE (x), Pmode, op0, op1);
+ x = gen_rtx_fmt_ee (GET_CODE (x), Pmode, op0, op1);
}
return x;
@@ -304,8 +313,11 @@ convert_memory_address (to_mode, x)
enum machine_mode to_mode;
rtx x;
{
+ enum machine_mode from_mode = to_mode == ptr_mode ? Pmode : ptr_mode;
rtx temp;
+ /* Here we handle some special cases. If none of them apply, fall through
+ to the default case. */
switch (GET_CODE (x))
{
case CONST_INT:
@@ -313,28 +325,41 @@ convert_memory_address (to_mode, x)
return x;
case LABEL_REF:
- return gen_rtx (LABEL_REF, to_mode, XEXP (x, 0));
+ temp = gen_rtx_LABEL_REF (to_mode, XEXP (x, 0));
+ LABEL_REF_NONLOCAL_P (temp) = LABEL_REF_NONLOCAL_P (x);
+ return temp;
case SYMBOL_REF:
- temp = gen_rtx (SYMBOL_REF, to_mode, XSTR (x, 0));
+ temp = gen_rtx_SYMBOL_REF (to_mode, XSTR (x, 0));
SYMBOL_REF_FLAG (temp) = SYMBOL_REF_FLAG (x);
+ CONSTANT_POOL_ADDRESS_P (temp) = CONSTANT_POOL_ADDRESS_P (x);
return temp;
- case PLUS:
- case MULT:
- return gen_rtx (GET_CODE (x), to_mode,
- convert_memory_address (to_mode, XEXP (x, 0)),
- convert_memory_address (to_mode, XEXP (x, 1)));
-
case CONST:
- return gen_rtx (CONST, to_mode,
- convert_memory_address (to_mode, XEXP (x, 0)));
+ return gen_rtx_CONST (to_mode,
+ convert_memory_address (to_mode, XEXP (x, 0)));
+ case PLUS:
+ case MULT:
+ /* For addition the second operand is a small constant, we can safely
+ permute the conversion and addition operation. We can always safely
+ permute them if we are making the address narrower. In addition,
+ always permute the operations if this is a constant. */
+ if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode)
+ || (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && (INTVAL (XEXP (x, 1)) + 20000 < 40000
+ || CONSTANT_P (XEXP (x, 0)))))
+ return gen_rtx_fmt_ee (GET_CODE (x), to_mode,
+ convert_memory_address (to_mode, XEXP (x, 0)),
+ convert_memory_address (to_mode, XEXP (x, 1)));
+ break;
+
default:
- return convert_modes (to_mode,
- to_mode == ptr_mode ? Pmode : ptr_mode,
- x, POINTERS_EXTEND_UNSIGNED);
+ break;
}
+
+ return convert_modes (to_mode, from_mode,
+ x, POINTERS_EXTEND_UNSIGNED);
}
#endif
@@ -372,7 +397,7 @@ copy_all_regs (x)
register rtx op0 = copy_all_regs (XEXP (x, 0));
register rtx op1 = copy_all_regs (XEXP (x, 1));
if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1))
- x = gen_rtx (GET_CODE (x), Pmode, op0, op1);
+ x = gen_rtx_fmt_ee (GET_CODE (x), Pmode, op0, op1);
}
return x;
}
@@ -388,6 +413,9 @@ memory_address (mode, x)
{
register rtx oldx = x;
+ if (GET_CODE (x) == ADDRESSOF)
+ return x;
+
#ifdef POINTERS_EXTEND_UNSIGNED
if (GET_MODE (x) == ptr_mode)
x = convert_memory_address (Pmode, x);
@@ -447,7 +475,7 @@ memory_address (mode, x)
x = force_operand (x, NULL_RTX);
else
{
- y = gen_rtx (PLUS, GET_MODE (x), copy_to_reg (y), constant_term);
+ y = gen_rtx_PLUS (GET_MODE (x), copy_to_reg (y), constant_term);
if (! memory_address_p (mode, y))
x = force_operand (x, NULL_RTX);
else
@@ -493,11 +521,11 @@ memory_address (mode, x)
if (oldx == x)
return x;
else if (GET_CODE (x) == REG)
- mark_reg_pointer (x);
+ mark_reg_pointer (x, 1);
else if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == REG
&& GET_CODE (XEXP (x, 1)) == CONST_INT)
- mark_reg_pointer (XEXP (x, 0));
+ mark_reg_pointer (XEXP (x, 0), 1);
/* OLDX may have been the address on a temporary. Update the address
to indicate that X is now used. */
@@ -556,7 +584,7 @@ stabilize (x)
rtx mem;
if (GET_CODE (temp) != REG)
temp = copy_to_reg (temp);
- mem = gen_rtx (MEM, GET_MODE (x), temp);
+ mem = gen_rtx_MEM (GET_MODE (x), temp);
/* Mark returned memref with in_struct if it's in an array or
structure. Copy const and volatile from original memref. */
@@ -564,6 +592,11 @@ stabilize (x)
MEM_IN_STRUCT_P (mem) = MEM_IN_STRUCT_P (x) || GET_CODE (addr) == PLUS;
RTX_UNCHANGING_P (mem) = RTX_UNCHANGING_P (x);
MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (x);
+
+ /* Since the new MEM is just like the old X, it can alias only
+ the things that X could. */
+ MEM_ALIAS_SET (mem) = MEM_ALIAS_SET (x);
+
return mem;
}
return x;
@@ -652,7 +685,7 @@ force_reg (mode, x)
if (note)
XEXP (note, 0) = x;
else
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, x, REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, x, REG_NOTES (insn));
}
return temp;
}
@@ -723,11 +756,15 @@ promote_mode (type, mode, punsignedp, for_call)
#endif
#ifdef POINTERS_EXTEND_UNSIGNED
+ case REFERENCE_TYPE:
case POINTER_TYPE:
mode = Pmode;
unsignedp = POINTERS_EXTEND_UNSIGNED;
break;
#endif
+
+ default:
+ break;
}
*punsignedp = unsignedp;
@@ -806,7 +843,8 @@ round_push (size)
else
{
/* CEIL_DIV_EXPR needs to worry about the addition overflowing,
- but we know it can't. So add ourselves and then do TRUNC_DIV_EXPR. */
+ but we know it can't. So add ourselves and then do
+ TRUNC_DIV_EXPR. */
size = expand_binop (Pmode, add_optab, size, GEN_INT (align - 1),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, GEN_INT (align),
@@ -833,8 +871,8 @@ emit_stack_save (save_level, psave, after)
{
rtx sa = *psave;
/* The default is that we use a move insn and save in a Pmode object. */
- rtx (*fcn) () = gen_move_insn;
- enum machine_mode mode = Pmode;
+ rtx (*fcn) PROTO ((rtx, rtx)) = gen_move_insn;
+ enum machine_mode mode = STACK_SAVEAREA_MODE (save_level);
/* See if this machine has anything special to do for this kind of save. */
switch (save_level)
@@ -842,30 +880,23 @@ emit_stack_save (save_level, psave, after)
#ifdef HAVE_save_stack_block
case SAVE_BLOCK:
if (HAVE_save_stack_block)
- {
- fcn = gen_save_stack_block;
- mode = insn_operand_mode[CODE_FOR_save_stack_block][0];
- }
+ fcn = gen_save_stack_block;
break;
#endif
#ifdef HAVE_save_stack_function
case SAVE_FUNCTION:
if (HAVE_save_stack_function)
- {
- fcn = gen_save_stack_function;
- mode = insn_operand_mode[CODE_FOR_save_stack_function][0];
- }
+ fcn = gen_save_stack_function;
break;
#endif
#ifdef HAVE_save_stack_nonlocal
case SAVE_NONLOCAL:
if (HAVE_save_stack_nonlocal)
- {
- fcn = gen_save_stack_nonlocal;
- mode = insn_operand_mode[(int) CODE_FOR_save_stack_nonlocal][0];
- }
+ fcn = gen_save_stack_nonlocal;
break;
#endif
+ default:
+ break;
}
/* If there is no save area and we have to allocate one, do so. Otherwise
@@ -922,7 +953,7 @@ emit_stack_restore (save_level, sa, after)
rtx sa;
{
/* The default is that we use a move insn. */
- rtx (*fcn) () = gen_move_insn;
+ rtx (*fcn) PROTO ((rtx, rtx)) = gen_move_insn;
/* See if this machine has anything special to do for this kind of save. */
switch (save_level)
@@ -940,12 +971,13 @@ emit_stack_restore (save_level, sa, after)
break;
#endif
#ifdef HAVE_restore_stack_nonlocal
-
case SAVE_NONLOCAL:
if (HAVE_restore_stack_nonlocal)
fcn = gen_restore_stack_nonlocal;
break;
#endif
+ default:
+ break;
}
if (sa != 0)
@@ -965,6 +997,86 @@ emit_stack_restore (save_level, sa, after)
emit_insn (fcn (stack_pointer_rtx, sa));
}
+#ifdef SETJMP_VIA_SAVE_AREA
+/* Optimize RTL generated by allocate_dynamic_stack_space for targets
+ where SETJMP_VIA_SAVE_AREA is true. The problem is that on these
+ platforms, the dynamic stack space used can corrupt the original
+ frame, thus causing a crash if a longjmp unwinds to it. */
+
+void
+optimize_save_area_alloca (insns)
+ rtx insns;
+{
+ rtx insn;
+
+ for (insn = insns; insn; insn = NEXT_INSN(insn))
+ {
+ rtx note;
+
+ if (GET_CODE (insn) != INSN)
+ continue;
+
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ {
+ if (REG_NOTE_KIND (note) != REG_SAVE_AREA)
+ continue;
+
+ if (!current_function_calls_setjmp)
+ {
+ rtx pat = PATTERN (insn);
+
+ /* If we do not see the note in a pattern matching
+ these precise characteristics, we did something
+ entirely wrong in allocate_dynamic_stack_space.
+
+ Note, one way this could happen is if SETJMP_VIA_SAVE_AREA
+ was defined on a machine where stacks grow towards higher
+ addresses.
+
+ Right now only supported port with stack that grow upward
+ is the HPPA and it does not define SETJMP_VIA_SAVE_AREA. */
+ if (GET_CODE (pat) != SET
+ || SET_DEST (pat) != stack_pointer_rtx
+ || GET_CODE (SET_SRC (pat)) != MINUS
+ || XEXP (SET_SRC (pat), 0) != stack_pointer_rtx)
+ abort ();
+
+ /* This will now be transformed into a (set REG REG)
+ so we can just blow away all the other notes. */
+ XEXP (SET_SRC (pat), 1) = XEXP (note, 0);
+ REG_NOTES (insn) = NULL_RTX;
+ }
+ else
+ {
+ /* setjmp was called, we must remove the REG_SAVE_AREA
+ note so that later passes do not get confused by its
+ presence. */
+ if (note == REG_NOTES (insn))
+ {
+ REG_NOTES (insn) = XEXP (note, 1);
+ }
+ else
+ {
+ rtx srch;
+
+ for (srch = REG_NOTES (insn); srch; srch = XEXP (srch, 1))
+ if (XEXP (srch, 1) == note)
+ break;
+
+ if (srch == NULL_RTX)
+ abort();
+
+ XEXP (srch, 1) = XEXP (note, 1);
+ }
+ }
+ /* Once we've seen the note of interest, we need not look at
+ the rest of them. */
+ break;
+ }
+ }
+}
+#endif /* SETJMP_VIA_SAVE_AREA */
+
/* Return an rtx representing the address of an area of memory dynamically
pushed on the stack. This region of memory is always aligned to
a multiple of BIGGEST_ALIGNMENT.
@@ -982,6 +1094,10 @@ allocate_dynamic_stack_space (size, target, known_align)
rtx target;
int known_align;
{
+#ifdef SETJMP_VIA_SAVE_AREA
+ rtx setjmpless_size = NULL_RTX;
+#endif
+
/* If we're asking for zero bytes, it doesn't matter what we point
to since we can't dereference it. But return a reasonable
address anyway. */
@@ -1008,7 +1124,7 @@ allocate_dynamic_stack_space (size, target, known_align)
If we have to align, we must leave space in SIZE for the hole
that might result from the alignment operation. */
-#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET) || defined (ALLOCATE_OUTGOING_ARGS) || ! defined (STACK_BOUNDARY)
+#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET) || ! defined (STACK_BOUNDARY)
#define MUST_ALIGN 1
#else
#define MUST_ALIGN (STACK_BOUNDARY < BIGGEST_ALIGNMENT)
@@ -1035,6 +1151,45 @@ allocate_dynamic_stack_space (size, target, known_align)
rtx dynamic_offset
= expand_binop (Pmode, sub_optab, virtual_stack_dynamic_rtx,
stack_pointer_rtx, NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+ if (!current_function_calls_setjmp)
+ {
+ int align = STACK_BOUNDARY / BITS_PER_UNIT;
+
+ /* See optimize_save_area_alloca to understand what is being
+ set up here. */
+
+#if !defined(STACK_BOUNDARY) || !defined(MUST_ALIGN) || (STACK_BOUNDARY != BIGGEST_ALIGNMENT)
+ /* If anyone creates a target with these characteristics, let them
+ know that our optimization cannot work correctly in such a case. */
+ abort();
+#endif
+
+ if (GET_CODE (size) == CONST_INT)
+ {
+ int new = INTVAL (size) / align * align;
+
+ if (INTVAL (size) != new)
+ setjmpless_size = GEN_INT (new);
+ else
+ setjmpless_size = size;
+ }
+ else
+ {
+ /* Since we know overflow is not possible, we avoid using
+ CEIL_DIV_EXPR and use TRUNC_DIV_EXPR instead. */
+ setjmpless_size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size,
+ GEN_INT (align), NULL_RTX, 1);
+ setjmpless_size = expand_mult (Pmode, setjmpless_size,
+ GEN_INT (align), NULL_RTX, 1);
+ }
+ /* Our optimization works based upon being able to perform a simple
+ transformation of this RTL into a (set REG REG) so make sure things
+ did in fact end up in a REG. */
+ if (!register_operand (setjmpless_size, Pmode))
+ setjmpless_size = force_reg (Pmode, setjmpless_size);
+ }
+
size = expand_binop (Pmode, add_optab, size, dynamic_offset,
NULL_RTX, 1, OPTAB_LIB_WIDEN);
}
@@ -1065,50 +1220,66 @@ allocate_dynamic_stack_space (size, target, known_align)
do_pending_stack_adjust ();
+ /* If needed, check that we have the required amount of stack. Take into
+ account what has already been checked. */
+ if (flag_stack_check && ! STACK_CHECK_BUILTIN)
+ probe_stack_range (STACK_CHECK_MAX_FRAME_SIZE + STACK_CHECK_PROTECT, size);
+
/* Don't use a TARGET that isn't a pseudo. */
if (target == 0 || GET_CODE (target) != REG
|| REGNO (target) < FIRST_PSEUDO_REGISTER)
target = gen_reg_rtx (Pmode);
- mark_reg_pointer (target);
-
-#ifndef STACK_GROWS_DOWNWARD
- emit_move_insn (target, virtual_stack_dynamic_rtx);
-#endif
+ mark_reg_pointer (target, known_align / BITS_PER_UNIT);
/* Perform the required allocation from the stack. Some systems do
this differently than simply incrementing/decrementing from the
- stack pointer. */
+ stack pointer, such as acquiring the space by calling malloc(). */
#ifdef HAVE_allocate_stack
if (HAVE_allocate_stack)
{
- enum machine_mode mode
- = insn_operand_mode[(int) CODE_FOR_allocate_stack][0];
-
- size = convert_modes (mode, ptr_mode, size, 1);
+ enum machine_mode mode = STACK_SIZE_MODE;
if (insn_operand_predicate[(int) CODE_FOR_allocate_stack][0]
&& ! ((*insn_operand_predicate[(int) CODE_FOR_allocate_stack][0])
+ (target, Pmode)))
+ target = copy_to_mode_reg (Pmode, target);
+ size = convert_modes (mode, ptr_mode, size, 1);
+ if (insn_operand_predicate[(int) CODE_FOR_allocate_stack][1]
+ && ! ((*insn_operand_predicate[(int) CODE_FOR_allocate_stack][1])
(size, mode)))
size = copy_to_mode_reg (mode, size);
- emit_insn (gen_allocate_stack (size));
+ emit_insn (gen_allocate_stack (target, size));
}
else
#endif
{
+#ifndef STACK_GROWS_DOWNWARD
+ emit_move_insn (target, virtual_stack_dynamic_rtx);
+#endif
size = convert_modes (Pmode, ptr_mode, size, 1);
anti_adjust_stack (size);
- }
+#ifdef SETJMP_VIA_SAVE_AREA
+ if (setjmpless_size != NULL_RTX)
+ {
+ rtx note_target = get_last_insn ();
+ REG_NOTES (note_target)
+ = gen_rtx_EXPR_LIST (REG_SAVE_AREA, setjmpless_size,
+ REG_NOTES (note_target));
+ }
+#endif /* SETJMP_VIA_SAVE_AREA */
#ifdef STACK_GROWS_DOWNWARD
emit_move_insn (target, virtual_stack_dynamic_rtx);
#endif
+ }
if (MUST_ALIGN)
{
/* CEIL_DIV_EXPR needs to worry about the addition overflowing,
- but we know it can't. So add ourselves and then do TRUNC_DIV_EXPR. */
+ but we know it can't. So add ourselves and then do
+ TRUNC_DIV_EXPR. */
target = expand_binop (Pmode, add_optab, target,
GEN_INT (BIGGEST_ALIGNMENT / BITS_PER_UNIT - 1),
NULL_RTX, 1, OPTAB_LIB_WIDEN);
@@ -1134,6 +1305,142 @@ allocate_dynamic_stack_space (size, target, known_align)
return target;
}
+/* Emit one stack probe at ADDRESS, an address within the stack. */
+
+static void
+emit_stack_probe (address)
+ rtx address;
+{
+ rtx memref = gen_rtx_MEM (word_mode, address);
+
+ MEM_VOLATILE_P (memref) = 1;
+
+ if (STACK_CHECK_PROBE_LOAD)
+ emit_move_insn (gen_reg_rtx (word_mode), memref);
+ else
+ emit_move_insn (memref, const0_rtx);
+}
+
+/* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive.
+ FIRST is a constant and size is a Pmode RTX. These are offsets from the
+ current stack pointer. STACK_GROWS_DOWNWARD says whether to add or
+ subtract from the stack. If SIZE is constant, this is done
+ with a fixed number of probes. Otherwise, we must make a loop. */
+
+#ifdef STACK_GROWS_DOWNWARD
+#define STACK_GROW_OP MINUS
+#else
+#define STACK_GROW_OP PLUS
+#endif
+
+void
+probe_stack_range (first, size)
+ HOST_WIDE_INT first;
+ rtx size;
+{
+ /* First see if we have an insn to check the stack. Use it if so. */
+#ifdef HAVE_check_stack
+ if (HAVE_check_stack)
+ {
+ rtx last_addr
+ = force_operand (gen_rtx_STACK_GROW_OP (Pmode,
+ stack_pointer_rtx,
+ plus_constant (size, first)),
+ NULL_RTX);
+
+ if (insn_operand_predicate[(int) CODE_FOR_check_stack][0]
+ && ! ((*insn_operand_predicate[(int) CODE_FOR_check_stack][0])
+ (last_address, Pmode)))
+ last_address = copy_to_mode_reg (Pmode, last_address);
+
+ emit_insn (gen_check_stack (last_address));
+ return;
+ }
+#endif
+
+ /* If we have to generate explicit probes, see if we have a constant
+ small number of them to generate. If so, that's the easy case. */
+ if (GET_CODE (size) == CONST_INT
+ && INTVAL (size) < 10 * STACK_CHECK_PROBE_INTERVAL)
+ {
+ HOST_WIDE_INT offset;
+
+ /* Start probing at FIRST + N * STACK_CHECK_PROBE_INTERVAL
+ for values of N from 1 until it exceeds LAST. If only one
+ probe is needed, this will not generate any code. Then probe
+ at LAST. */
+ for (offset = first + STACK_CHECK_PROBE_INTERVAL;
+ offset < INTVAL (size);
+ offset = offset + STACK_CHECK_PROBE_INTERVAL)
+ emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+ stack_pointer_rtx,
+ GEN_INT (offset)));
+
+ emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+ stack_pointer_rtx,
+ plus_constant (size, first)));
+ }
+
+ /* In the variable case, do the same as above, but in a loop. We emit loop
+ notes so that loop optimization can be done. */
+ else
+ {
+ rtx test_addr
+ = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+ stack_pointer_rtx,
+ GEN_INT (first + STACK_CHECK_PROBE_INTERVAL)),
+ NULL_RTX);
+ rtx last_addr
+ = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+ stack_pointer_rtx,
+ plus_constant (size, first)),
+ NULL_RTX);
+ rtx incr = GEN_INT (STACK_CHECK_PROBE_INTERVAL);
+ rtx loop_lab = gen_label_rtx ();
+ rtx test_lab = gen_label_rtx ();
+ rtx end_lab = gen_label_rtx ();
+ rtx temp;
+
+ if (GET_CODE (test_addr) != REG
+ || REGNO (test_addr) < FIRST_PSEUDO_REGISTER)
+ test_addr = force_reg (Pmode, test_addr);
+
+ emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG);
+ emit_jump (test_lab);
+
+ emit_label (loop_lab);
+ emit_stack_probe (test_addr);
+
+ emit_note (NULL_PTR, NOTE_INSN_LOOP_CONT);
+
+#ifdef STACK_GROWS_DOWNWARD
+#define CMP_OPCODE GTU
+ temp = expand_binop (Pmode, sub_optab, test_addr, incr, test_addr,
+ 1, OPTAB_WIDEN);
+#else
+#define CMP_OPCODE LTU
+ temp = expand_binop (Pmode, add_optab, test_addr, incr, test_addr,
+ 1, OPTAB_WIDEN);
+#endif
+
+ if (temp != test_addr)
+ abort ();
+
+ emit_label (test_lab);
+ emit_cmp_insn (test_addr, last_addr, CMP_OPCODE, NULL_RTX, Pmode, 1, 0);
+ emit_jump_insn ((*bcc_gen_fctn[(int) CMP_OPCODE]) (loop_lab));
+ emit_jump (end_lab);
+ emit_note (NULL_PTR, NOTE_INSN_LOOP_END);
+ emit_label (end_lab);
+
+ /* If will be doing stupid optimization, show test_addr is still live. */
+ if (obey_regdecls)
+ emit_insn (gen_rtx_USE (VOIDmode, test_addr));
+
+ emit_stack_probe (last_addr);
+ }
+}
+
/* Return an rtx representing the register or memory location
in which a scalar value of data type VALTYPE
was returned by a function call to function FUNC.
diff --git a/contrib/gcc/expmed.c b/contrib/gcc/expmed.c
index 8006e8b..2f656c2 100644
--- a/contrib/gcc/expmed.c
+++ b/contrib/gcc/expmed.c
@@ -1,6 +1,6 @@
/* Medium-level subroutines: convert bit-field store and extract
and shifts, multiplies and divides to rtl instructions.
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -21,6 +21,7 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
@@ -40,6 +41,8 @@ static rtx mask_rtx PROTO((enum machine_mode, int,
static rtx lshift_value PROTO((enum machine_mode, rtx,
int, int));
static rtx extract_split_bit_field PROTO((rtx, int, int, int, int));
+static void do_cmp_and_jump PROTO((rtx, rtx, enum rtx_code,
+ enum machine_mode, rtx));
#define CEIL(x,y) (((x) + (y) - 1) / (y))
@@ -79,7 +82,7 @@ init_expmed ()
char *free_point;
/* This is "some random pseudo register" for purposes of calling recog
to see what insns exist. */
- rtx reg = gen_rtx (REG, word_mode, 10000);
+ rtx reg = gen_rtx_REG (word_mode, 10000);
rtx shift_insn, shiftadd_insn, shiftsub_insn;
int dummy;
int m;
@@ -90,34 +93,37 @@ init_expmed ()
/* Since we are on the permanent obstack, we must be sure we save this
spot AFTER we call start_sequence, since it will reuse the rtl it
makes. */
-
free_point = (char *) oballoc (0);
- zero_cost = rtx_cost (const0_rtx, 0);
- add_cost = rtx_cost (gen_rtx (PLUS, word_mode, reg, reg), SET);
-
- shift_insn = emit_insn (gen_rtx (SET, VOIDmode, reg,
- gen_rtx (ASHIFT, word_mode, reg,
- const0_rtx)));
+ reg = gen_rtx (REG, word_mode, 10000);
- shiftadd_insn = emit_insn (gen_rtx (SET, VOIDmode, reg,
- gen_rtx (PLUS, word_mode,
- gen_rtx (MULT, word_mode,
- reg, const0_rtx),
- reg)));
-
- shiftsub_insn = emit_insn (gen_rtx (SET, VOIDmode, reg,
- gen_rtx (MINUS, word_mode,
- gen_rtx (MULT, word_mode,
- reg, const0_rtx),
- reg)));
+ zero_cost = rtx_cost (const0_rtx, 0);
+ add_cost = rtx_cost (gen_rtx_PLUS (word_mode, reg, reg), SET);
+
+ shift_insn = emit_insn (gen_rtx_SET (VOIDmode, reg,
+ gen_rtx_ASHIFT (word_mode, reg,
+ const0_rtx)));
+
+ shiftadd_insn
+ = emit_insn (gen_rtx_SET (VOIDmode, reg,
+ gen_rtx_PLUS (word_mode,
+ gen_rtx_MULT (word_mode,
+ reg, const0_rtx),
+ reg)));
+
+ shiftsub_insn
+ = emit_insn (gen_rtx_SET (VOIDmode, reg,
+ gen_rtx_MINUS (word_mode,
+ gen_rtx_MULT (word_mode,
+ reg, const0_rtx),
+ reg)));
init_recog ();
shift_cost[0] = 0;
shiftadd_cost[0] = shiftsub_cost[0] = add_cost;
- for (m = 1; m < BITS_PER_WORD; m++)
+ for (m = 1; m < MAX_BITS_PER_WORD; m++)
{
shift_cost[m] = shiftadd_cost[m] = shiftsub_cost[m] = 32000;
@@ -136,37 +142,39 @@ init_expmed ()
shiftsub_cost[m] = rtx_cost (SET_SRC (PATTERN (shiftsub_insn)), SET);
}
- negate_cost = rtx_cost (gen_rtx (NEG, word_mode, reg), SET);
+ negate_cost = rtx_cost (gen_rtx_NEG (word_mode, reg), SET);
sdiv_pow2_cheap
- = (rtx_cost (gen_rtx (DIV, word_mode, reg, GEN_INT (32)), SET)
+ = (rtx_cost (gen_rtx_DIV (word_mode, reg, GEN_INT (32)), SET)
<= 2 * add_cost);
smod_pow2_cheap
- = (rtx_cost (gen_rtx (MOD, word_mode, reg, GEN_INT (32)), SET)
+ = (rtx_cost (gen_rtx_MOD (word_mode, reg, GEN_INT (32)), SET)
<= 2 * add_cost);
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
- reg = gen_rtx (REG, mode, 10000);
- div_cost[(int) mode] = rtx_cost (gen_rtx (UDIV, mode, reg, reg), SET);
- mul_cost[(int) mode] = rtx_cost (gen_rtx (MULT, mode, reg, reg), SET);
+ reg = gen_rtx_REG (mode, 10000);
+ div_cost[(int) mode] = rtx_cost (gen_rtx_UDIV (mode, reg, reg), SET);
+ mul_cost[(int) mode] = rtx_cost (gen_rtx_MULT (mode, reg, reg), SET);
wider_mode = GET_MODE_WIDER_MODE (mode);
if (wider_mode != VOIDmode)
{
mul_widen_cost[(int) wider_mode]
- = rtx_cost (gen_rtx (MULT, wider_mode,
- gen_rtx (ZERO_EXTEND, wider_mode, reg),
- gen_rtx (ZERO_EXTEND, wider_mode, reg)),
+ = rtx_cost (gen_rtx_MULT (wider_mode,
+ gen_rtx_ZERO_EXTEND (wider_mode, reg),
+ gen_rtx_ZERO_EXTEND (wider_mode, reg)),
SET);
mul_highpart_cost[(int) mode]
- = rtx_cost (gen_rtx (TRUNCATE, mode,
- gen_rtx (LSHIFTRT, wider_mode,
- gen_rtx (MULT, wider_mode,
- gen_rtx (ZERO_EXTEND, wider_mode, reg),
- gen_rtx (ZERO_EXTEND, wider_mode, reg)),
- GEN_INT (GET_MODE_BITSIZE (mode)))),
+ = rtx_cost (gen_rtx_TRUNCATE
+ (mode,
+ gen_rtx_LSHIFTRT
+ (wider_mode,
+ gen_rtx_MULT (wider_mode,
+ gen_rtx_ZERO_EXTEND (wider_mode, reg),
+ gen_rtx_ZERO_EXTEND (wider_mode, reg)),
+ GEN_INT (GET_MODE_BITSIZE (mode)))),
SET);
}
}
@@ -185,21 +193,12 @@ negate_rtx (mode, x)
enum machine_mode mode;
rtx x;
{
- if (GET_CODE (x) == CONST_INT)
- {
- HOST_WIDE_INT val = - INTVAL (x);
- if (GET_MODE_BITSIZE (mode) < HOST_BITS_PER_WIDE_INT)
- {
- /* Sign extend the value from the bits that are significant. */
- if (val & ((HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))
- val |= (HOST_WIDE_INT) (-1) << GET_MODE_BITSIZE (mode);
- else
- val &= ((HOST_WIDE_INT) 1 << GET_MODE_BITSIZE (mode)) - 1;
- }
- return GEN_INT (val);
- }
- else
- return expand_unop (GET_MODE (x), neg_optab, x, NULL_RTX, 0);
+ rtx result = simplify_unary_operation (NEG, mode, x, mode);
+
+ if (result == 0)
+ result = expand_unop (mode, neg_optab, x, NULL_RTX, 0);
+
+ return result;
}
/* Generate code to store value from rtx VALUE
@@ -281,7 +280,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
if (GET_MODE (op0) != fieldmode)
{
if (GET_CODE (op0) == REG)
- op0 = gen_rtx (SUBREG, fieldmode, op0, offset);
+ op0 = gen_rtx_SUBREG (fieldmode, op0, offset);
else
op0 = change_address (op0, fieldmode,
plus_constant (XEXP (op0, 0), offset));
@@ -316,7 +315,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
if(! (*insn_operand_predicate[icode][1]) (value, fieldmode))
value = copy_to_mode_reg (fieldmode, value);
emit_insn (GEN_FCN (icode)
- (gen_rtx (SUBREG, fieldmode, op0, offset), value));
+ (gen_rtx_SUBREG (fieldmode, op0, offset), value));
}
return value;
}
@@ -373,7 +372,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
{
if (offset != 0
|| GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
- op0 = gen_rtx (SUBREG, TYPE_MODE (type_for_size (BITS_PER_WORD, 0)),
+ op0 = gen_rtx_SUBREG (TYPE_MODE (type_for_size (BITS_PER_WORD, 0)),
op0, offset);
offset = 0;
}
@@ -390,7 +389,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
{
if (GET_CODE (value) != REG)
value = copy_to_reg (value);
- value = gen_rtx (SUBREG, word_mode, value, 0);
+ value = gen_rtx_SUBREG (word_mode, value, 0);
}
/* Now OFFSET is nonzero only if OP0 is memory
@@ -398,6 +397,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
#ifdef HAVE_insv
if (HAVE_insv
+ && GET_MODE (value) != BLKmode
&& !(bitsize == 1 && GET_CODE (value) == CONST_INT)
/* Ensure insv's size is wide enough for this field. */
&& (GET_MODE_BITSIZE (insn_operand_mode[(int) CODE_FOR_insv][3])
@@ -417,13 +417,13 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
int save_volatile_ok = volatile_ok;
volatile_ok = 1;
- /* If this machine's insv can only insert into a register, or if we
- are to force MEMs into a register, copy OP0 into a register and
- save it back later. */
+ /* If this machine's insv can only insert into a register, copy OP0
+ into a register and save it back later. */
+ /* This used to check flag_force_mem, but that was a serious
+ de-optimization now that flag_force_mem is enabled by -O2. */
if (GET_CODE (op0) == MEM
- && (flag_force_mem
- || ! ((*insn_operand_predicate[(int) CODE_FOR_insv][0])
- (op0, VOIDmode))))
+ && ! ((*insn_operand_predicate[(int) CODE_FOR_insv][0])
+ (op0, VOIDmode)))
{
rtx tempreg;
enum machine_mode bestmode;
@@ -472,9 +472,9 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
if (GET_CODE (xop0) == SUBREG)
/* We can't just change the mode, because this might clobber op0,
and we will need the original value of op0 if insv fails. */
- xop0 = gen_rtx (SUBREG, maxmode, SUBREG_REG (xop0), SUBREG_WORD (xop0));
+ xop0 = gen_rtx_SUBREG (maxmode, SUBREG_REG (xop0), SUBREG_WORD (xop0));
if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
- xop0 = gen_rtx (SUBREG, maxmode, xop0, 0);
+ xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
/* On big-endian machines, we count bits from the most significant.
If the bit field insn does not, we must invert. */
@@ -504,7 +504,7 @@ store_bit_field (str_rtx, bitsize, bitnum, fieldmode, value, align, total_size)
/* Avoid making subreg of a subreg, or of a mem. */
if (GET_CODE (value1) != REG)
value1 = copy_to_reg (value1);
- value1 = gen_rtx (SUBREG, maxmode, value1, 0);
+ value1 = gen_rtx_SUBREG (maxmode, value1, 0);
}
else
value1 = gen_lowpart (maxmode, value1);
@@ -565,6 +565,9 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align)
int all_zero = 0;
int all_one = 0;
+ if (! SLOW_UNALIGNED_ACCESS)
+ struct_align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+
/* There is a case not handled here:
a structure with a known alignment of just a halfword
and a field split across two aligned halfwords within the structure.
@@ -607,7 +610,7 @@ store_fixed_bit_field (op0, offset, bitsize, bitpos, value, struct_align)
total_bits = GET_MODE_BITSIZE (mode);
/* Make sure bitpos is valid for the chosen mode. Adjust BITPOS to
- be be in the range 0 to total_bits-1, and put any excess bytes in
+ be in the range 0 to total_bits-1, and put any excess bytes in
OFFSET. */
if (bitpos >= total_bits)
{
@@ -752,6 +755,8 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
? GET_MODE (value)
: word_mode, value));
}
+ else if (GET_CODE (value) == ADDRESSOF)
+ value = copy_to_reg (value);
while (bitsdone < bitsize)
{
@@ -776,7 +781,7 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
/* We must do an endian conversion exactly the same way as it is
done in extract_bit_field, so that the two calls to
extract_fixed_bit_field will have comparable arguments. */
- if (GET_CODE (value) != MEM)
+ if (GET_CODE (value) != MEM || GET_MODE (value) == BLKmode)
total_bits = BITS_PER_WORD;
else
total_bits = GET_MODE_BITSIZE (GET_MODE (value));
@@ -789,10 +794,19 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
else
/* The args are chosen so that the last part includes the
lsb. Give extract_bit_field the value it needs (with
- endianness compensation) to fetch the piece we want. */
- part = extract_fixed_bit_field (word_mode, value, 0, thissize,
- total_bits - bitsize + bitsdone,
- NULL_RTX, 1, align);
+ endianness compensation) to fetch the piece we want.
+
+ ??? We have no idea what the alignment of VALUE is, so
+ we have to use a guess. */
+ part
+ = extract_fixed_bit_field
+ (word_mode, value, 0, thissize,
+ total_bits - bitsize + bitsdone, NULL_RTX, 1,
+ GET_MODE (value) == VOIDmode
+ ? UNITS_PER_WORD
+ : (GET_MODE (value) == BLKmode
+ ? 1
+ : GET_MODE_ALIGNMENT (GET_MODE (value)) / BITS_PER_UNIT));
}
else
{
@@ -802,8 +816,14 @@ store_split_bit_field (op0, bitsize, bitpos, value, align)
>> bitsdone)
& (((HOST_WIDE_INT) 1 << thissize) - 1));
else
- part = extract_fixed_bit_field (word_mode, value, 0, thissize,
- bitsdone, NULL_RTX, 1, align);
+ part
+ = extract_fixed_bit_field
+ (word_mode, value, 0, thissize, bitsdone, NULL_RTX, 1,
+ GET_MODE (value) == VOIDmode
+ ? UNITS_PER_WORD
+ : (GET_MODE (value) == BLKmode
+ ? 1
+ : GET_MODE_ALIGNMENT (GET_MODE (value)) / BITS_PER_UNIT));
}
/* If OP0 is a register, then handle OFFSET here.
@@ -875,9 +895,6 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
rtx spec_target = target;
rtx spec_target_subreg = 0;
- if (GET_CODE (str_rtx) == MEM && ! MEM_IN_STRUCT_P (str_rtx))
- abort ();
-
/* Discount the part of the structure before the desired byte.
We need to know how many bytes are safe to reference after it. */
if (total_size >= 0)
@@ -893,6 +910,8 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
offset += SUBREG_WORD (op0);
+ inner_size = MIN (inner_size, BITS_PER_WORD);
+
if (BYTES_BIG_ENDIAN && (outer_size < inner_size))
{
bitpos += inner_size - outer_size;
@@ -913,8 +932,8 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
/* If OP0 is a register, BITPOS must count within a word.
But as we have it, it counts within whatever size OP0 now has.
On a bigendian machine, these are not the same, so convert. */
- if (BYTES_BIG_ENDIAN &&
- GET_CODE (op0) != MEM
+ if (BYTES_BIG_ENDIAN
+ && GET_CODE (op0) != MEM
&& unit > GET_MODE_BITSIZE (GET_MODE (op0)))
bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
@@ -924,7 +943,9 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
So too extracting a subword value in
the least significant part of the register. */
- if ((GET_CODE (op0) == REG
+ if (((GET_CODE (op0) == REG
+ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+ GET_MODE_BITSIZE (GET_MODE (op0))))
|| (GET_CODE (op0) == MEM
&& (! SLOW_UNALIGNED_ACCESS
|| (offset * BITS_PER_UNIT % bitsize == 0
@@ -942,7 +963,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
if (mode1 != GET_MODE (op0))
{
if (GET_CODE (op0) == REG)
- op0 = gen_rtx (SUBREG, mode1, op0, offset);
+ op0 = gen_rtx_SUBREG (mode1, op0, offset);
else
op0 = change_address (op0, mode1,
plus_constant (XEXP (op0, 0), offset));
@@ -967,6 +988,9 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
if (target == 0 || GET_CODE (target) != REG)
target = gen_reg_rtx (mode);
+ /* Indicate for flow that the entire target reg is being set. */
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+
for (i = 0; i < nwords; i++)
{
/* If I is 0, use the low-order word in both field and target;
@@ -1034,7 +1058,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
{
if (offset != 0
|| GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
- op0 = gen_rtx (SUBREG, TYPE_MODE (type_for_size (BITS_PER_WORD, 0)),
+ op0 = gen_rtx_SUBREG (TYPE_MODE (type_for_size (BITS_PER_WORD, 0)),
op0, offset);
offset = 0;
}
@@ -1057,7 +1081,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
{
int xbitpos = bitpos, xoffset = offset;
rtx bitsize_rtx, bitpos_rtx;
- rtx last = get_last_insn();
+ rtx last = get_last_insn ();
rtx xop0 = op0;
rtx xtarget = target;
rtx xspec_target = spec_target;
@@ -1072,9 +1096,8 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
volatile_ok = 1;
/* Is the memory operand acceptable? */
- if (flag_force_mem
- || ! ((*insn_operand_predicate[(int) CODE_FOR_extzv][1])
- (xop0, GET_MODE (xop0))))
+ if (! ((*insn_operand_predicate[(int) CODE_FOR_extzv][1])
+ (xop0, GET_MODE (xop0))))
{
/* No, load into a reg and extract from there. */
enum machine_mode bestmode;
@@ -1122,9 +1145,9 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
/* If op0 is a register, we need it in MAXMODE (which is usually
SImode). to make it acceptable to the format of extzv. */
if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != maxmode)
- abort ();
+ goto extzv_loses;
if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
- xop0 = gen_rtx (SUBREG, maxmode, xop0, 0);
+ xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
/* On big-endian machines, we count bits from the most significant.
If the bit field insn does not, we must invert. */
@@ -1198,7 +1221,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
{
int xbitpos = bitpos, xoffset = offset;
rtx bitsize_rtx, bitpos_rtx;
- rtx last = get_last_insn();
+ rtx last = get_last_insn ();
rtx xop0 = op0, xtarget = target;
rtx xspec_target = spec_target;
rtx xspec_target_subreg = spec_target_subreg;
@@ -1256,9 +1279,9 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
/* If op0 is a register, we need it in MAXMODE (which is usually
SImode) to make it acceptable to the format of extv. */
if (GET_CODE (xop0) == SUBREG && GET_MODE (xop0) != maxmode)
- abort ();
+ goto extv_loses;
if (GET_CODE (xop0) == REG && GET_MODE (xop0) != maxmode)
- xop0 = gen_rtx (SUBREG, maxmode, xop0, 0);
+ xop0 = gen_rtx_SUBREG (maxmode, xop0, 0);
/* On big-endian machines, we count bits from the most significant.
If the bit field insn does not, we must invert. */
@@ -1337,7 +1360,7 @@ extract_bit_field (str_rtx, bitsize, bitnum, unsignedp,
target, unsignedp);
if (GET_CODE (target) != REG)
target = copy_to_reg (target);
- return gen_rtx (SUBREG, tmode, target, 0);
+ return gen_rtx_SUBREG (tmode, target, 0);
}
else
return convert_to_mode (tmode, target, unsignedp);
@@ -1402,7 +1425,7 @@ extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
total_bits = GET_MODE_BITSIZE (mode);
/* Make sure bitpos is valid for the chosen mode. Adjust BITPOS to
- be be in the range 0 to total_bits-1, and put any excess bytes in
+ be in the range 0 to total_bits-1, and put any excess bytes in
OFFSET. */
if (bitpos >= total_bits)
{
@@ -1461,7 +1484,7 @@ extract_fixed_bit_field (tmode, op0, offset, bitsize, bitpos,
#ifdef SLOW_ZERO_EXTEND
/* Always generate an `and' if
we just zero-extended op0 and SLOW_ZERO_EXTEND, since it
- will combine fruitfully with the zero-extend. */
+ will combine fruitfully with the zero-extend. */
|| tmode != mode
#endif
#endif
@@ -1592,7 +1615,7 @@ extract_split_bit_field (op0, bitsize, bitpos, unsignedp, align)
{
int unit;
int bitsdone = 0;
- rtx result;
+ rtx result = NULL_RTX;
int first = 1;
/* Make sure UNIT isn't larger than BITS_PER_WORD, we can only handle that
@@ -1738,11 +1761,16 @@ expand_shift (code, mode, shifted, amount, target, unsignedp)
op1 = expand_expr (amount, NULL_RTX, VOIDmode, 0);
#ifdef SHIFT_COUNT_TRUNCATED
- if (SHIFT_COUNT_TRUNCATED
- && GET_CODE (op1) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (op1) >= GET_MODE_BITSIZE (mode))
- op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
- % GET_MODE_BITSIZE (mode));
+ if (SHIFT_COUNT_TRUNCATED)
+ {
+ if (GET_CODE (op1) == CONST_INT
+ && (unsigned HOST_WIDE_INT) INTVAL (op1) >= GET_MODE_BITSIZE (mode))
+ op1 = GEN_INT ((unsigned HOST_WIDE_INT) INTVAL (op1)
+ % GET_MODE_BITSIZE (mode));
+ else if (GET_CODE (op1) == SUBREG
+ && SUBREG_WORD (op1) == 0)
+ op1 = SUBREG_REG (op1);
+ }
#endif
if (op1 == const0_rtx)
@@ -1889,6 +1917,15 @@ struct algorithm
char log[MAX_BITS_PER_WORD];
};
+static void synth_mult PROTO((struct algorithm *,
+ unsigned HOST_WIDE_INT,
+ int));
+static unsigned HOST_WIDE_INT choose_multiplier PROTO((unsigned HOST_WIDE_INT,
+ int, int,
+ unsigned HOST_WIDE_INT *,
+ int *, int *));
+static unsigned HOST_WIDE_INT invert_mod2n PROTO((unsigned HOST_WIDE_INT,
+ int));
/* Compute and return the best algorithm for multiplying by T.
The algorithm must cost less than cost_limit
If retval.cost >= COST_LIMIT, no algorithm was found and all
@@ -1969,10 +2006,16 @@ synth_mult (alg_out, t, cost_limit)
for (w = 1; (w & t) != 0; w <<= 1)
;
- if (w > 2
- /* Reject the case where t is 3.
- Thus we prefer addition in that case. */
- && t != 3)
+ /* If T was -1, then W will be zero after the loop. This is another
+ case where T ends with ...111. Handling this with (T + 1) and
+ subtract 1 produces slightly better code and results in algorithm
+ selection much faster than treating it like the ...0111 case
+ below. */
+ if (w == 0
+ || (w > 2
+ /* Reject the case where t is 3.
+ Thus we prefer addition in that case. */
+ && t != 3))
{
/* T ends with ...111. Multiply by (T + 1) and subtract 1. */
@@ -2178,7 +2221,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
and then negate, do the multiplication directly, or do multiplication
by OP1 - 1. */
- mult_cost = rtx_cost (gen_rtx (MULT, mode, op0, op1), SET);
+ mult_cost = rtx_cost (gen_rtx_MULT (mode, op0, op1), SET);
mult_cost = MIN (12 * add_cost, mult_cost);
synth_mult (&alg, val, mult_cost);
@@ -2235,7 +2278,8 @@ expand_mult (mode, op0, op1, target, unsignedp)
rtx shift_subtarget = preserve ? 0 : accum;
rtx add_target
= (opno == alg.ops - 1 && target != 0 && variant != add_variant
- ? target : 0);
+ && ! preserve)
+ ? target : 0;
rtx accum_target = preserve ? 0 : accum;
switch (alg.op[opno])
@@ -2249,7 +2293,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
case alg_add_t_m2:
tem = expand_shift (LSHIFT_EXPR, mode, op0,
build_int_2 (log, 0), NULL_RTX, 0);
- accum = force_operand (gen_rtx (PLUS, mode, accum, tem),
+ accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
add_target ? add_target : accum_target);
val_so_far += (HOST_WIDE_INT) 1 << log;
break;
@@ -2257,7 +2301,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
case alg_sub_t_m2:
tem = expand_shift (LSHIFT_EXPR, mode, op0,
build_int_2 (log, 0), NULL_RTX, 0);
- accum = force_operand (gen_rtx (MINUS, mode, accum, tem),
+ accum = force_operand (gen_rtx_MINUS (mode, accum, tem),
add_target ? add_target : accum_target);
val_so_far -= (HOST_WIDE_INT) 1 << log;
break;
@@ -2266,7 +2310,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
accum = expand_shift (LSHIFT_EXPR, mode, accum,
build_int_2 (log, 0), shift_subtarget,
0);
- accum = force_operand (gen_rtx (PLUS, mode, accum, op0),
+ accum = force_operand (gen_rtx_PLUS (mode, accum, op0),
add_target ? add_target : accum_target);
val_so_far = (val_so_far << log) + 1;
break;
@@ -2275,7 +2319,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
accum = expand_shift (LSHIFT_EXPR, mode, accum,
build_int_2 (log, 0), shift_subtarget,
0);
- accum = force_operand (gen_rtx (MINUS, mode, accum, op0),
+ accum = force_operand (gen_rtx_MINUS (mode, accum, op0),
add_target ? add_target : accum_target);
val_so_far = (val_so_far << log) - 1;
break;
@@ -2283,7 +2327,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
case alg_add_factor:
tem = expand_shift (LSHIFT_EXPR, mode, accum,
build_int_2 (log, 0), NULL_RTX, 0);
- accum = force_operand (gen_rtx (PLUS, mode, accum, tem),
+ accum = force_operand (gen_rtx_PLUS (mode, accum, tem),
add_target ? add_target : accum_target);
val_so_far += val_so_far << log;
break;
@@ -2291,7 +2335,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
case alg_sub_factor:
tem = expand_shift (LSHIFT_EXPR, mode, accum,
build_int_2 (log, 0), NULL_RTX, 0);
- accum = force_operand (gen_rtx (MINUS, mode, tem, accum),
+ accum = force_operand (gen_rtx_MINUS (mode, tem, accum),
(add_target ? add_target
: preserve ? 0 : tem));
val_so_far = (val_so_far << log) - val_so_far;
@@ -2306,9 +2350,9 @@ expand_mult (mode, op0, op1, target, unsignedp)
insn = get_last_insn ();
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (MULT, mode, op0, GEN_INT (val_so_far)),
- REG_NOTES (insn));
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ gen_rtx_MULT (mode, op0, GEN_INT (val_so_far)),
+ REG_NOTES (insn));
}
if (variant == negate_variant)
@@ -2319,7 +2363,7 @@ expand_mult (mode, op0, op1, target, unsignedp)
else if (variant == add_variant)
{
val_so_far = val_so_far + 1;
- accum = force_operand (gen_rtx (PLUS, mode, accum, op0), target);
+ accum = force_operand (gen_rtx_PLUS (mode, accum, op0), target);
}
if (val != val_so_far)
@@ -2465,7 +2509,7 @@ invert_mod2n (x, n)
unsigned HOST_WIDE_INT x;
int n;
{
- /* Solve x*y == 1 (mod 2^n), where x is odd. Return y. */
+ /* Solve x*y == 1 (mod 2^n), where x is odd. Return y. */
/* The algorithm notes that the choice y = x satisfies
x*y == 1 mod 2^3, since x is assumed odd.
@@ -2510,14 +2554,16 @@ expand_mult_highpart_adjust (mode, adj_operand, op0, op1, target, unsignedp)
build_int_2 (GET_MODE_BITSIZE (mode) - 1, 0),
NULL_RTX, 0);
tem = expand_and (tem, op1, NULL_RTX);
- adj_operand = force_operand (gen_rtx (adj_code, mode, adj_operand, tem),
- adj_operand);
+ adj_operand
+ = force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem),
+ adj_operand);
tem = expand_shift (RSHIFT_EXPR, mode, op1,
build_int_2 (GET_MODE_BITSIZE (mode) - 1, 0),
NULL_RTX, 0);
tem = expand_and (tem, op0, NULL_RTX);
- target = force_operand (gen_rtx (adj_code, mode, adj_operand, tem), target);
+ target = force_operand (gen_rtx_fmt_ee (adj_code, mode, adj_operand, tem),
+ target);
return target;
}
@@ -2609,13 +2655,19 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
moptab = unsignedp ? umul_widen_optab : smul_widen_optab;
if (moptab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
&& mul_widen_cost[(int) wider_mode] < max_cost)
- goto try;
+ {
+ op1 = force_reg (mode, op1);
+ goto try;
+ }
/* Try widening the mode and perform a non-widening multiplication. */
moptab = smul_optab;
if (smul_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing
&& mul_cost[(int) wider_mode] + shift_cost[size-1] < max_cost)
- goto try;
+ {
+ op1 = wide_op1;
+ goto try;
+ }
/* Try widening multiplication of opposite signedness, and adjust. */
moptab = unsignedp ? smul_widen_optab : umul_widen_optab;
@@ -2623,7 +2675,8 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
&& (mul_widen_cost[(int) wider_mode]
+ 2 * shift_cost[size-1] + 4 * add_cost < max_cost))
{
- tem = expand_binop (wider_mode, moptab, op0, wide_op1,
+ rtx regop1 = force_reg (mode, op1);
+ tem = expand_binop (wider_mode, moptab, op0, regop1,
NULL_RTX, ! unsignedp, OPTAB_WIDEN);
if (tem != 0)
{
@@ -2641,15 +2694,22 @@ expand_mult_highpart (mode, op0, cnst1, target, unsignedp, max_cost)
try:
/* Pass NULL_RTX as target since TARGET has wrong mode. */
- tem = expand_binop (wider_mode, moptab, op0, wide_op1,
+ tem = expand_binop (wider_mode, moptab, op0, op1,
NULL_RTX, unsignedp, OPTAB_WIDEN);
if (tem == 0)
return 0;
/* Extract the high half of the just generated product. */
- tem = expand_shift (RSHIFT_EXPR, wider_mode, tem,
- build_int_2 (size, 0), NULL_RTX, 1);
- return convert_modes (mode, wider_mode, tem, unsignedp);
+ if (mode == word_mode)
+ {
+ return gen_highpart (mode, tem);
+ }
+ else
+ {
+ tem = expand_shift (RSHIFT_EXPR, wider_mode, tem,
+ build_int_2 (size, 0), NULL_RTX, 1);
+ return convert_modes (mode, wider_mode, tem, unsignedp);
+ }
}
/* Emit the code to divide OP0 by OP1, putting the result in TARGET
@@ -2688,11 +2748,12 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
optab optab1, optab2;
int op1_is_constant, op1_is_pow2;
int max_cost, extra_cost;
+ static HOST_WIDE_INT last_div_const = 0;
op1_is_constant = GET_CODE (op1) == CONST_INT;
op1_is_pow2 = (op1_is_constant
&& ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))
- || EXACT_POWER_OF_2_OR_ZERO_P (-INTVAL (op1)))));
+ || (! unsignedp && EXACT_POWER_OF_2_OR_ZERO_P (-INTVAL (op1))))));
/*
This is the structure of expand_divmod:
@@ -2797,14 +2858,29 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
size = GET_MODE_BITSIZE (mode);
#endif
+ /* Only deduct something for a REM if the last divide done was
+ for a different constant. Then set the constant of the last
+ divide. */
max_cost = div_cost[(int) compute_mode]
- - (rem_flag ? mul_cost[(int) compute_mode] + add_cost : 0);
+ - (rem_flag && ! (last_div_const != 0 && op1_is_constant
+ && INTVAL (op1) == last_div_const)
+ ? mul_cost[(int) compute_mode] + add_cost : 0);
+
+ last_div_const = ! rem_flag && op1_is_constant ? INTVAL (op1) : 0;
/* Now convert to the best mode to use. */
if (compute_mode != mode)
{
op0 = convert_modes (compute_mode, mode, op0, unsignedp);
op1 = convert_modes (compute_mode, mode, op1, unsignedp);
+
+ /* convert_modes may have placed op1 into a register, so we
+ must recompute the following. */
+ op1_is_constant = GET_CODE (op1) == CONST_INT;
+ op1_is_pow2 = (op1_is_constant
+ && ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))
+ || (! unsignedp
+ && EXACT_POWER_OF_2_OR_ZERO_P (-INTVAL (op1)))))) ;
}
/* If one of the operands is a volatile MEM, copy it into a register. */
@@ -2828,6 +2904,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
code = TRUNC_DIV_EXPR;
if (code == FLOOR_MOD_EXPR)
code = TRUNC_MOD_EXPR;
+ if (code == EXACT_DIV_EXPR && op1_is_pow2)
+ code = TRUNC_DIV_EXPR;
}
if (op1 != const0_rtx)
@@ -2835,7 +2913,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
{
case TRUNC_MOD_EXPR:
case TRUNC_DIV_EXPR:
- if (op1_is_constant && HOST_BITS_PER_WIDE_INT >= size)
+ if (op1_is_constant)
{
if (unsignedp)
{
@@ -2849,10 +2927,11 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
pre_shift = floor_log2 (d);
if (rem_flag)
{
- remainder = expand_binop (compute_mode, and_optab, op0,
- GEN_INT (((HOST_WIDE_INT) 1 << pre_shift) - 1),
- remainder, 1,
- OPTAB_LIB_WIDEN);
+ remainder
+ = expand_binop (compute_mode, and_optab, op0,
+ GEN_INT (((HOST_WIDE_INT) 1 << pre_shift) - 1),
+ remainder, 1,
+ OPTAB_LIB_WIDEN);
if (remainder)
return gen_lowpart (mode, remainder);
}
@@ -2860,91 +2939,96 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
build_int_2 (pre_shift, 0),
tquotient, 1);
}
- else if (d >= ((unsigned HOST_WIDE_INT) 1 << (size - 1)))
+ else if (size <= HOST_BITS_PER_WIDE_INT)
{
- /* Most significant bit of divisor is set, emit a scc insn.
- emit_store_flag needs to be passed a place for the
- result. */
- quotient = emit_store_flag (tquotient, GEU, op0, op1,
- compute_mode, 1, 1);
- if (quotient == 0)
- goto fail1;
- }
- else
- {
- /* Find a suitable multiplier and right shift count instead
- of multiplying with D. */
-
- mh = choose_multiplier (d, size, size,
- &ml, &post_shift, &dummy);
-
- /* If the suggested multiplier is more than SIZE bits, we
- can do better for even divisors, using an initial right
- shift. */
- if (mh != 0 && (d & 1) == 0)
+ if (d >= ((unsigned HOST_WIDE_INT) 1 << (size - 1)))
{
- pre_shift = floor_log2 (d & -d);
- mh = choose_multiplier (d >> pre_shift, size,
- size - pre_shift,
- &ml, &post_shift, &dummy);
- if (mh)
- abort ();
- }
- else
- pre_shift = 0;
-
- if (mh != 0)
- {
- rtx t1, t2, t3, t4;
-
- extra_cost = (shift_cost[post_shift - 1]
- + shift_cost[1] + 2 * add_cost);
- t1 = expand_mult_highpart (compute_mode, op0, ml,
- NULL_RTX, 1,
- max_cost - extra_cost);
- if (t1 == 0)
+ /* Most significant bit of divisor is set; emit an scc
+ insn. */
+ quotient = emit_store_flag (tquotient, GEU, op0, op1,
+ compute_mode, 1, 1);
+ if (quotient == 0)
goto fail1;
- t2 = force_operand (gen_rtx (MINUS, compute_mode,
- op0, t1),
- NULL_RTX);
- t3 = expand_shift (RSHIFT_EXPR, compute_mode, t2,
- build_int_2 (1, 0), NULL_RTX, 1);
- t4 = force_operand (gen_rtx (PLUS, compute_mode,
- t1, t3),
- NULL_RTX);
- quotient = expand_shift (RSHIFT_EXPR, compute_mode, t4,
- build_int_2 (post_shift - 1,
- 0),
- tquotient, 1);
}
else
{
- rtx t1, t2;
+ /* Find a suitable multiplier and right shift count
+ instead of multiplying with D. */
- t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
- build_int_2 (pre_shift, 0),
- NULL_RTX, 1);
- extra_cost = (shift_cost[pre_shift]
- + shift_cost[post_shift]);
- t2 = expand_mult_highpart (compute_mode, t1, ml,
- NULL_RTX, 1,
- max_cost - extra_cost);
- if (t2 == 0)
- goto fail1;
- quotient = expand_shift (RSHIFT_EXPR, compute_mode, t2,
- build_int_2 (post_shift, 0),
- tquotient, 1);
+ mh = choose_multiplier (d, size, size,
+ &ml, &post_shift, &dummy);
+
+ /* If the suggested multiplier is more than SIZE bits,
+ we can do better for even divisors, using an
+ initial right shift. */
+ if (mh != 0 && (d & 1) == 0)
+ {
+ pre_shift = floor_log2 (d & -d);
+ mh = choose_multiplier (d >> pre_shift, size,
+ size - pre_shift,
+ &ml, &post_shift, &dummy);
+ if (mh)
+ abort ();
+ }
+ else
+ pre_shift = 0;
+
+ if (mh != 0)
+ {
+ rtx t1, t2, t3, t4;
+
+ extra_cost = (shift_cost[post_shift - 1]
+ + shift_cost[1] + 2 * add_cost);
+ t1 = expand_mult_highpart (compute_mode, op0, ml,
+ NULL_RTX, 1,
+ max_cost - extra_cost);
+ if (t1 == 0)
+ goto fail1;
+ t2 = force_operand (gen_rtx_MINUS (compute_mode,
+ op0, t1),
+ NULL_RTX);
+ t3 = expand_shift (RSHIFT_EXPR, compute_mode, t2,
+ build_int_2 (1, 0), NULL_RTX,1);
+ t4 = force_operand (gen_rtx_PLUS (compute_mode,
+ t1, t3),
+ NULL_RTX);
+ quotient
+ = expand_shift (RSHIFT_EXPR, compute_mode, t4,
+ build_int_2 (post_shift - 1, 0),
+ tquotient, 1);
+ }
+ else
+ {
+ rtx t1, t2;
+
+ t1 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
+ build_int_2 (pre_shift, 0),
+ NULL_RTX, 1);
+ extra_cost = (shift_cost[pre_shift]
+ + shift_cost[post_shift]);
+ t2 = expand_mult_highpart (compute_mode, t1, ml,
+ NULL_RTX, 1,
+ max_cost - extra_cost);
+ if (t2 == 0)
+ goto fail1;
+ quotient
+ = expand_shift (RSHIFT_EXPR, compute_mode, t2,
+ build_int_2 (post_shift, 0),
+ tquotient, 1);
+ }
}
}
+ else /* Too wide mode to use tricky code */
+ break;
insn = get_last_insn ();
if (insn != last
&& (set = single_set (insn)) != 0
&& SET_DEST (set) == quotient)
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (UDIV, compute_mode, op0, op1),
- REG_NOTES (insn));
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ gen_rtx_UDIV (compute_mode, op0, op1),
+ REG_NOTES (insn));
}
else /* TRUNC_DIV, signed */
{
@@ -2985,9 +3069,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
rtx t1;
t1 = copy_to_mode_reg (compute_mode, op0);
- emit_cmp_insn (t1, const0_rtx, GE,
- NULL_RTX, compute_mode, 0, 0);
- emit_jump_insn (gen_bge (label));
+ do_cmp_and_jump (t1, const0_rtx, GE,
+ compute_mode, label);
expand_inc (t1, GEN_INT (abs_d - 1));
emit_label (label);
quotient = expand_shift (RSHIFT_EXPR, compute_mode, t1,
@@ -3003,8 +3086,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
t2 = expand_shift (RSHIFT_EXPR, compute_mode, t1,
build_int_2 (size - lgup, 0),
NULL_RTX, 1);
- t3 = force_operand (gen_rtx (PLUS, compute_mode,
- op0, t2),
+ t3 = force_operand (gen_rtx_PLUS (compute_mode,
+ op0, t2),
NULL_RTX);
quotient = expand_shift (RSHIFT_EXPR, compute_mode, t3,
build_int_2 (lgup, 0),
@@ -3020,16 +3103,17 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
&& (set = single_set (insn)) != 0
&& SET_DEST (set) == quotient)
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (DIV, compute_mode, op0,
- GEN_INT (abs_d)),
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ gen_rtx_DIV (compute_mode,
+ op0,
+ GEN_INT (abs_d)),
REG_NOTES (insn));
quotient = expand_unop (compute_mode, neg_optab,
quotient, quotient, 0);
}
}
- else
+ else if (size <= HOST_BITS_PER_WIDE_INT)
{
choose_multiplier (abs_d, size, size - 1,
&ml, &post_shift, &lgup);
@@ -3049,10 +3133,10 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
t3 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
build_int_2 (size - 1, 0), NULL_RTX, 0);
if (d < 0)
- quotient = force_operand (gen_rtx (MINUS, compute_mode, t3, t2),
+ quotient = force_operand (gen_rtx_MINUS (compute_mode, t3, t2),
tquotient);
else
- quotient = force_operand (gen_rtx (MINUS, compute_mode, t2, t3),
+ quotient = force_operand (gen_rtx_MINUS (compute_mode, t2, t3),
tquotient);
}
else
@@ -3067,29 +3151,31 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
max_cost - extra_cost);
if (t1 == 0)
goto fail1;
- t2 = force_operand (gen_rtx (PLUS, compute_mode, t1, op0),
+ t2 = force_operand (gen_rtx_PLUS (compute_mode, t1, op0),
NULL_RTX);
t3 = expand_shift (RSHIFT_EXPR, compute_mode, t2,
build_int_2 (post_shift, 0), NULL_RTX, 0);
t4 = expand_shift (RSHIFT_EXPR, compute_mode, op0,
build_int_2 (size - 1, 0), NULL_RTX, 0);
if (d < 0)
- quotient = force_operand (gen_rtx (MINUS, compute_mode, t4, t3),
+ quotient = force_operand (gen_rtx_MINUS (compute_mode, t4, t3),
tquotient);
else
- quotient = force_operand (gen_rtx (MINUS, compute_mode, t3, t4),
+ quotient = force_operand (gen_rtx_MINUS (compute_mode, t3, t4),
tquotient);
}
}
+ else /* Too wide mode to use tricky code */
+ break;
insn = get_last_insn ();
if (insn != last
&& (set = single_set (insn)) != 0
&& SET_DEST (set) == quotient)
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (DIV, compute_mode, op0, op1),
- REG_NOTES (insn));
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ gen_rtx_DIV (compute_mode, op0, op1),
+ REG_NOTES (insn));
}
break;
}
@@ -3157,13 +3243,13 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
else
{
rtx nsign, t1, t2, t3, t4;
- t1 = force_operand (gen_rtx (PLUS, compute_mode,
- op0, constm1_rtx), NULL_RTX);
+ t1 = force_operand (gen_rtx_PLUS (compute_mode,
+ op0, constm1_rtx), NULL_RTX);
t2 = expand_binop (compute_mode, ior_optab, op0, t1, NULL_RTX,
0, OPTAB_WIDEN);
nsign = expand_shift (RSHIFT_EXPR, compute_mode, t2,
build_int_2 (size - 1, 0), NULL_RTX, 0);
- t3 = force_operand (gen_rtx (MINUS, compute_mode, t1, nsign),
+ t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign),
NULL_RTX);
t4 = expand_divmod (0, TRUNC_DIV_EXPR, compute_mode, t3, op1,
NULL_RTX, 0);
@@ -3172,8 +3258,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
rtx t5;
t5 = expand_unop (compute_mode, one_cmpl_optab, nsign,
NULL_RTX, 0);
- quotient = force_operand (gen_rtx (PLUS, compute_mode,
- t4, t5),
+ quotient = force_operand (gen_rtx_PLUS (compute_mode,
+ t4, t5),
tquotient);
}
}
@@ -3188,7 +3274,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
or remainder to get floor rounding, once we have the remainder.
Notice that we compute also the final remainder value here,
and return the result right away. */
- if (target == 0)
+ if (target == 0 || GET_MODE (target) != compute_mode)
target = gen_reg_rtx (compute_mode);
if (rem_flag)
@@ -3211,13 +3297,10 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
Save that for later. */
rtx tem;
rtx label = gen_label_rtx ();
- emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_beq (label));
+ do_cmp_and_jump (remainder, const0_rtx, EQ, compute_mode, label);
tem = expand_binop (compute_mode, xor_optab, op0, op1,
NULL_RTX, 0, OPTAB_WIDEN);
- emit_cmp_insn (tem, const0_rtx, GE, NULL_RTX, compute_mode, 0, 0);
- emit_jump_insn (gen_bge (label));
+ do_cmp_and_jump (tem, const0_rtx, GE, compute_mode, label);
expand_dec (quotient, const1_rtx);
expand_inc (remainder, op1);
emit_label (label);
@@ -3238,11 +3321,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
label3 = gen_label_rtx ();
label4 = gen_label_rtx ();
label5 = gen_label_rtx ();
- emit_cmp_insn (op1, const0_rtx, LT, NULL_RTX, compute_mode, 0, 0);
- emit_jump_insn (gen_blt (label2));
- emit_cmp_insn (adjusted_op0, const0_rtx, LT, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_blt (label1));
+ do_cmp_and_jump (op1, const0_rtx, LT, compute_mode, label2);
+ do_cmp_and_jump (adjusted_op0, const0_rtx, LT, compute_mode, label1);
tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
quotient, 0, OPTAB_LIB_WIDEN);
if (tem != quotient)
@@ -3254,9 +3334,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
emit_jump_insn (gen_jump (label4));
emit_barrier ();
emit_label (label2);
- emit_cmp_insn (adjusted_op0, const0_rtx, GT, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_bgt (label3));
+ do_cmp_and_jump (adjusted_op0, const0_rtx, GT, compute_mode, label3);
tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
quotient, 0, OPTAB_LIB_WIDEN);
if (tem != quotient)
@@ -3296,16 +3374,14 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
{
rtx lab;
lab = gen_label_rtx ();
- emit_cmp_insn (t2, const0_rtx, EQ, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_beq (lab));
+ do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab);
expand_inc (t1, const1_rtx);
emit_label (lab);
quotient = t1;
}
else
- quotient = force_operand (gen_rtx (PLUS, compute_mode,
- t1, t3),
+ quotient = force_operand (gen_rtx_PLUS (compute_mode,
+ t1, t3),
tquotient);
break;
}
@@ -3315,7 +3391,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
quotient or remainder to get ceiling rounding, once we have the
remainder. Notice that we compute also the final remainder
value here, and return the result right away. */
- if (target == 0)
+ if (target == 0 || GET_MODE (target) != compute_mode)
target = gen_reg_rtx (compute_mode);
if (rem_flag)
@@ -3337,9 +3413,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
/* This could be computed with a branch-less sequence.
Save that for later. */
rtx label = gen_label_rtx ();
- emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_beq (label));
+ do_cmp_and_jump (remainder, const0_rtx, EQ,
+ compute_mode, label);
expand_inc (quotient, const1_rtx);
expand_dec (remainder, op1);
emit_label (label);
@@ -3356,9 +3431,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
adjusted_op0 = copy_to_mode_reg (compute_mode, op0);
label1 = gen_label_rtx ();
label2 = gen_label_rtx ();
- emit_cmp_insn (adjusted_op0, const0_rtx, NE, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_bne (label1));
+ do_cmp_and_jump (adjusted_op0, const0_rtx, NE,
+ compute_mode, label1);
emit_move_insn (quotient, const0_rtx);
emit_jump_insn (gen_jump (label2));
emit_barrier ();
@@ -3398,16 +3472,14 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
{
rtx lab;
lab = gen_label_rtx ();
- emit_cmp_insn (t2, const0_rtx, EQ, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_beq (lab));
+ do_cmp_and_jump (t2, const0_rtx, EQ, compute_mode, lab);
expand_inc (t1, const1_rtx);
emit_label (lab);
quotient = t1;
}
else
- quotient = force_operand (gen_rtx (PLUS, compute_mode,
- t1, t3),
+ quotient = force_operand (gen_rtx_PLUS (compute_mode,
+ t1, t3),
tquotient);
break;
}
@@ -3417,7 +3489,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
quotient or remainder to get ceiling rounding, once we have the
remainder. Notice that we compute also the final remainder
value here, and return the result right away. */
- if (target == 0)
+ if (target == 0 || GET_MODE (target) != compute_mode)
target = gen_reg_rtx (compute_mode);
if (rem_flag)
{
@@ -3439,14 +3511,11 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
Save that for later. */
rtx tem;
rtx label = gen_label_rtx ();
- emit_cmp_insn (remainder, const0_rtx, EQ, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_beq (label));
+ do_cmp_and_jump (remainder, const0_rtx, EQ,
+ compute_mode, label);
tem = expand_binop (compute_mode, xor_optab, op0, op1,
NULL_RTX, 0, OPTAB_WIDEN);
- emit_cmp_insn (tem, const0_rtx, LT, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_blt (label));
+ do_cmp_and_jump (tem, const0_rtx, LT, compute_mode, label);
expand_inc (quotient, const1_rtx);
expand_dec (remainder, op1);
emit_label (label);
@@ -3467,12 +3536,9 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
label3 = gen_label_rtx ();
label4 = gen_label_rtx ();
label5 = gen_label_rtx ();
- emit_cmp_insn (op1, const0_rtx, LT, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_blt (label2));
- emit_cmp_insn (adjusted_op0, const0_rtx, GT, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_bgt (label1));
+ do_cmp_and_jump (op1, const0_rtx, LT, compute_mode, label2);
+ do_cmp_and_jump (adjusted_op0, const0_rtx, GT,
+ compute_mode, label1);
tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
quotient, 0, OPTAB_LIB_WIDEN);
if (tem != quotient)
@@ -3484,9 +3550,8 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
emit_jump_insn (gen_jump (label4));
emit_barrier ();
emit_label (label2);
- emit_cmp_insn (adjusted_op0, const0_rtx, LT, NULL_RTX,
- compute_mode, 0, 0);
- emit_jump_insn (gen_blt (label3));
+ do_cmp_and_jump (adjusted_op0, const0_rtx, LT,
+ compute_mode, label3);
tem = expand_binop (compute_mode, sdiv_optab, adjusted_op0, op1,
quotient, 0, OPTAB_LIB_WIDEN);
if (tem != quotient)
@@ -3524,10 +3589,11 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
insn = get_last_insn ();
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (unsignedp ? UDIV : DIV, compute_mode,
- op0, op1),
- REG_NOTES (insn));
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ gen_rtx_fmt_ee (unsignedp ? UDIV : DIV,
+ compute_mode,
+ op0, op1),
+ REG_NOTES (insn));
}
break;
@@ -3552,8 +3618,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
tem = plus_constant (op1, -1);
tem = expand_shift (RSHIFT_EXPR, compute_mode, tem,
build_int_2 (1, 0), NULL_RTX, 1);
- emit_cmp_insn (remainder, tem, LEU, NULL_RTX, compute_mode, 0, 0);
- emit_jump_insn (gen_bleu (label));
+ do_cmp_and_jump (remainder, tem, LEU, compute_mode, label);
expand_inc (quotient, const1_rtx);
expand_dec (remainder, op1);
emit_label (label);
@@ -3578,8 +3643,7 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
abs_op1 = expand_abs (compute_mode, op1, NULL_RTX, 0, 0);
tem = expand_shift (LSHIFT_EXPR, compute_mode, abs_rem,
build_int_2 (1, 0), NULL_RTX, 1);
- emit_cmp_insn (tem, abs_op1, LTU, NULL_RTX, compute_mode, 0, 0);
- emit_jump_insn (gen_bltu (label));
+ do_cmp_and_jump (tem, abs_op1, LTU, compute_mode, label);
tem = expand_binop (compute_mode, xor_optab, op0, op1,
NULL_RTX, 0, OPTAB_WIDEN);
mask = expand_shift (RSHIFT_EXPR, compute_mode, tem,
@@ -3597,10 +3661,16 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
emit_label (label);
}
return gen_lowpart (mode, rem_flag ? remainder : quotient);
+
+ default:
+ abort ();
}
if (quotient == 0)
{
+ if (target && GET_MODE (target) != compute_mode)
+ target = 0;
+
if (rem_flag)
{
/* Try to produce the remainder directly without a library call. */
@@ -3624,11 +3694,18 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
return gen_lowpart (mode, remainder);
}
- /* Produce the quotient. */
- /* Try a quotient insn, but not a library call. */
- quotient = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab,
- op0, op1, rem_flag ? NULL_RTX : target,
- unsignedp, OPTAB_WIDEN);
+ /* Produce the quotient. Try a quotient insn, but not a library call.
+ If we have a divmod in this mode, use it in preference to widening
+ the div (for this test we assume it will not fail). Note that optab2
+ is set to the one of the two optabs that the call below will use. */
+ quotient
+ = sign_expand_binop (compute_mode, udiv_optab, sdiv_optab,
+ op0, op1, rem_flag ? NULL_RTX : target,
+ unsignedp,
+ ((optab2->handlers[(int) compute_mode].insn_code
+ != CODE_FOR_nothing)
+ ? OPTAB_DIRECT : OPTAB_WIDEN));
+
if (quotient == 0)
{
/* No luck there. Try a quotient-and-remainder insn,
@@ -3652,6 +3729,9 @@ expand_divmod (rem_flag, code, mode, op0, op1, target, unsignedp)
if (rem_flag)
{
+ if (target && GET_MODE (target) != compute_mode)
+ target = 0;
+
if (quotient == 0)
/* No divide instruction either. Use library for remainder. */
remainder = sign_expand_binop (compute_mode, umod_optab, smod_optab,
@@ -3834,7 +3914,7 @@ expand_and (op0, op1, target)
to perform the operation. It says to use zero-extension.
NORMALIZEP is 1 if we should convert the result to be either zero
- or one one. Normalize is -1 if we should convert the result to be
+ or one. Normalize is -1 if we should convert the result to be
either zero or -1. If NORMALIZEP is zero, the result will be left
"raw" out of the scc insn. */
@@ -3872,7 +3952,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
/* For some comparisons with 1 and -1, we can convert this to
comparisons with zero. This will often produce more opportunities for
- store-flag insns. */
+ store-flag insns. */
switch (code)
{
@@ -3900,6 +3980,8 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
if (op1 == const1_rtx)
op1 = const0_rtx, code = EQ;
break;
+ default:
+ break;
}
/* From now on, we won't change CODE, so set ICODE now. */
@@ -3911,7 +3993,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
&& GET_MODE_CLASS (mode) == MODE_INT
&& (normalizep || STORE_FLAG_VALUE == 1
|| (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (STORE_FLAG_VALUE
+ && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
== (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))))
{
subtarget = target;
@@ -3930,9 +4012,11 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
subtarget = 0;
if (code == GE)
- op0 = expand_unop (mode, one_cmpl_optab, op0, subtarget, 0);
+ op0 = expand_unop (mode, one_cmpl_optab, op0,
+ ((STORE_FLAG_VALUE == 1 || normalizep)
+ ? 0 : subtarget), 0);
- if (normalizep || STORE_FLAG_VALUE == 1)
+ if (STORE_FLAG_VALUE == 1 || normalizep)
/* If we are supposed to produce a 0/1 value, we want to do
a logical shift from the sign bit to the low-order bit; for
a -1/0 value, we do an arithmetic shift. */
@@ -4103,7 +4187,7 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
normalizep = STORE_FLAG_VALUE;
else if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
- && (STORE_FLAG_VALUE
+ && ((STORE_FLAG_VALUE & GET_MODE_MASK (mode))
== (HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (mode) - 1)))
;
else
@@ -4221,3 +4305,119 @@ emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep)
return tem;
}
+
+/* Like emit_store_flag, but always succeeds. */
+
+rtx
+emit_store_flag_force (target, code, op0, op1, mode, unsignedp, normalizep)
+ rtx target;
+ enum rtx_code code;
+ rtx op0, op1;
+ enum machine_mode mode;
+ int unsignedp;
+ int normalizep;
+{
+ rtx tem, label;
+
+ /* First see if emit_store_flag can do the job. */
+ tem = emit_store_flag (target, code, op0, op1, mode, unsignedp, normalizep);
+ if (tem != 0)
+ return tem;
+
+ if (normalizep == 0)
+ normalizep = 1;
+
+ /* If this failed, we have to do this with set/compare/jump/set code. */
+
+ if (GET_CODE (target) != REG
+ || reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
+ target = gen_reg_rtx (GET_MODE (target));
+
+ emit_move_insn (target, const1_rtx);
+ tem = compare_from_rtx (op0, op1, code, unsignedp, mode, NULL_RTX, 0);
+ if (GET_CODE (tem) == CONST_INT)
+ return tem;
+
+ label = gen_label_rtx ();
+ if (bcc_gen_fctn[(int) code] == 0)
+ abort ();
+
+ emit_jump_insn ((*bcc_gen_fctn[(int) code]) (label));
+ emit_move_insn (target, const0_rtx);
+ emit_label (label);
+
+ return target;
+}
+
+/* Perform possibly multi-word comparison and conditional jump to LABEL
+ if ARG1 OP ARG2 true where ARG1 and ARG2 are of mode MODE
+
+ The algorithm is based on the code in expr.c:do_jump.
+
+ Note that this does not perform a general comparison. Only variants
+ generated within expmed.c are correctly handled, others abort (but could
+ be handled if needed). */
+
+static void
+do_cmp_and_jump (arg1, arg2, op, mode, label)
+ rtx arg1, arg2, label;
+ enum rtx_code op;
+ enum machine_mode mode;
+{
+ /* If this mode is an integer too wide to compare properly,
+ compare word by word. Rely on cse to optimize constant cases. */
+
+ if (GET_MODE_CLASS (mode) == MODE_INT && !can_compare_p (mode))
+ {
+ rtx label2 = gen_label_rtx ();
+
+ switch (op)
+ {
+ case LTU:
+ do_jump_by_parts_greater_rtx (mode, 1, arg2, arg1, label2, label);
+ break;
+
+ case LEU:
+ do_jump_by_parts_greater_rtx (mode, 1, arg1, arg2, label, label2);
+ break;
+
+ case LT:
+ do_jump_by_parts_greater_rtx (mode, 0, arg2, arg1, label2, label);
+ break;
+
+ case GT:
+ do_jump_by_parts_greater_rtx (mode, 0, arg1, arg2, label2, label);
+ break;
+
+ case GE:
+ do_jump_by_parts_greater_rtx (mode, 0, arg2, arg1, label, label2);
+ break;
+
+ /* do_jump_by_parts_equality_rtx compares with zero. Luckily
+ that's the only equality operations we do */
+ case EQ:
+ if (arg2 != const0_rtx || mode != GET_MODE(arg1))
+ abort();
+ do_jump_by_parts_equality_rtx (arg1, label2, label);
+ break;
+
+ case NE:
+ if (arg2 != const0_rtx || mode != GET_MODE(arg1))
+ abort();
+ do_jump_by_parts_equality_rtx (arg1, label, label2);
+ break;
+
+ default:
+ abort();
+ }
+
+ emit_label (label2);
+ }
+ else
+ {
+ emit_cmp_insn(arg1, arg2, op, NULL_RTX, mode, 0, 0);
+ if (bcc_gen_fctn[(int) op] == 0)
+ abort ();
+ emit_jump_insn ((*bcc_gen_fctn[(int) op]) (label));
+ }
+}
diff --git a/contrib/gcc/expr.c b/contrib/gcc/expr.c
index 39591c9..0457b87 100644
--- a/contrib/gcc/expr.c
+++ b/contrib/gcc/expr.c
@@ -1,5 +1,5 @@
/* Convert tree expression to rtl instructions, for GNU compiler.
- Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1988, 92-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,27 +20,26 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "machmode.h"
#include "rtl.h"
#include "tree.h"
#include "obstack.h"
#include "flags.h"
#include "regs.h"
+#include "hard-reg-set.h"
+#include "except.h"
#include "function.h"
#include "insn-flags.h"
#include "insn-codes.h"
-#include "expr.h"
#include "insn-config.h"
+/* Include expr.h after insn-config.h so we get HAVE_conditional_move. */
+#include "expr.h"
#include "recog.h"
#include "output.h"
#include "typeclass.h"
-
-#include "bytecode.h"
-#include "bc-opcode.h"
-#include "bc-typecd.h"
-#include "bc-optab.h"
-#include "bc-emit.h"
-
+#include "defaults.h"
+#include "toplev.h"
#define CEIL(x,y) (((x) + (y) - 1) / (y))
@@ -69,6 +68,11 @@ Boston, MA 02111-1307, USA. */
/* Like STACK_BOUNDARY but in units of bytes, not bits. */
#define STACK_BYTES (STACK_BOUNDARY / BITS_PER_UNIT)
+/* Assume that case vectors are not pc-relative. */
+#ifndef CASE_VECTOR_PC_RELATIVE
+#define CASE_VECTOR_PC_RELATIVE 0
+#endif
+
/* If this is nonzero, we do not bother generating VOLATILE
around volatile memory references, and we are willing to
output indirect addresses. If cse is to follow, we reject
@@ -92,16 +96,6 @@ int pending_stack_adjust;
and in other cases as well. */
int inhibit_defer_pop;
-/* A list of all cleanups which belong to the arguments of
- function calls being expanded by expand_call. */
-tree cleanups_this_call;
-
-/* When temporaries are created by TARGET_EXPRs, they are created at
- this level of temp_slot_level, so that they can remain allocated
- until no longer needed. CLEANUP_POINT_EXPRs define the lifetime
- of TARGET_EXPRs. */
-int target_temp_slot_level;
-
/* Nonzero means __builtin_saveregs has already been done in this function.
The value is the pseudoreg containing the value __builtin_saveregs
returned. */
@@ -110,9 +104,21 @@ static rtx saveregs_value;
/* Similarly for __builtin_apply_args. */
static rtx apply_args_value;
+/* Nonzero if the machine description has been fixed to accept
+ CONSTANT_P_RTX patterns. We will emit a warning and continue
+ if we find we must actually use such a beast. */
+static int can_handle_constant_p;
+
+/* Don't check memory usage, since code is being emitted to check a memory
+ usage. Used when flag_check_memory_usage is true, to avoid infinite
+ recursion. */
+static int in_check_memory_usage;
+
+/* Postincrements that still need to be expanded. */
+static rtx pending_chain;
+
/* This structure is used by move_by_pieces to describe the move to
be performed. */
-
struct move_by_pieces
{
rtx to;
@@ -130,34 +136,54 @@ struct move_by_pieces
int reverse;
};
-/* Used to generate bytecodes: keep track of size of local variables,
- as well as depth of arithmetic stack. (Notice that variables are
- stored on the machine's stack, not the arithmetic stack.) */
+/* This structure is used by clear_by_pieces to describe the clear to
+ be performed. */
+
+struct clear_by_pieces
+{
+ rtx to;
+ rtx to_addr;
+ int autinc_to;
+ int explicit_inc_to;
+ int to_struct;
+ int len;
+ int offset;
+ int reverse;
+};
-extern int local_vars_size;
-extern int stack_depth;
-extern int max_stack_depth;
extern struct obstack permanent_obstack;
+extern rtx arg_pointer_save_area;
+static rtx get_push_address PROTO ((int));
static rtx enqueue_insn PROTO((rtx, rtx));
static int queued_subexp_p PROTO((rtx));
static void init_queue PROTO((void));
static void move_by_pieces PROTO((rtx, rtx, int, int));
static int move_by_pieces_ninsns PROTO((unsigned int, int));
-static void move_by_pieces_1 PROTO((rtx (*) (), enum machine_mode,
+static void move_by_pieces_1 PROTO((rtx (*) (rtx, ...), enum machine_mode,
struct move_by_pieces *));
-static void store_constructor PROTO((tree, rtx));
+static void clear_by_pieces PROTO((rtx, int, int));
+static void clear_by_pieces_1 PROTO((rtx (*) (rtx, ...), enum machine_mode,
+ struct clear_by_pieces *));
+static int is_zeros_p PROTO((tree));
+static int mostly_zeros_p PROTO((tree));
+static void store_constructor_field PROTO((rtx, int, int, enum machine_mode,
+ tree, tree, int));
+static void store_constructor PROTO((tree, rtx, int));
static rtx store_field PROTO((rtx, int, int, enum machine_mode, tree,
enum machine_mode, int, int, int));
-static int get_inner_unaligned_p PROTO((tree));
+static enum memory_use_mode
+ get_memory_usage_from_modifier PROTO((enum expand_modifier));
static tree save_noncopied_parts PROTO((tree, tree));
static tree init_noncopied_parts PROTO((tree, tree));
-static int safe_from_p PROTO((rtx, tree));
+static int safe_from_p PROTO((rtx, tree, int));
static int fixed_type_p PROTO((tree));
+static rtx var_rtx PROTO((tree));
static int get_pointer_alignment PROTO((tree, unsigned));
static tree string_constant PROTO((tree, tree *));
static tree c_strlen PROTO((tree));
+static rtx get_memory_rtx PROTO((tree));
static rtx expand_builtin PROTO((tree, rtx, rtx,
enum machine_mode, int));
static int apply_args_size PROTO((void));
@@ -166,32 +192,13 @@ static rtx result_vector PROTO((int, rtx));
static rtx expand_builtin_apply_args PROTO((void));
static rtx expand_builtin_apply PROTO((rtx, rtx, rtx));
static void expand_builtin_return PROTO((rtx));
-static rtx expand_increment PROTO((tree, int));
-rtx bc_expand_increment PROTO((struct increment_operator *, tree));
-tree bc_runtime_type_code PROTO((tree));
-rtx bc_allocate_local PROTO((int, int));
-void bc_store_memory PROTO((tree, tree));
-tree bc_expand_component_address PROTO((tree));
-tree bc_expand_address PROTO((tree));
-void bc_expand_constructor PROTO((tree));
-void bc_adjust_stack PROTO((int));
-tree bc_canonicalize_array_ref PROTO((tree));
-void bc_load_memory PROTO((tree, tree));
-void bc_load_externaddr PROTO((rtx));
-void bc_load_externaddr_id PROTO((tree, int));
-void bc_load_localaddr PROTO((rtx));
-void bc_load_parmaddr PROTO((rtx));
+static rtx expand_increment PROTO((tree, int, int));
static void preexpand_calls PROTO((tree));
static void do_jump_by_parts_greater PROTO((tree, int, rtx, rtx));
-void do_jump_by_parts_greater_rtx PROTO((enum machine_mode, int, rtx, rtx, rtx, rtx));
static void do_jump_by_parts_equality PROTO((tree, rtx, rtx));
-static void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx));
static void do_jump_for_compare PROTO((rtx, rtx, rtx));
static rtx compare PROTO((tree, enum rtx_code, enum rtx_code));
static rtx do_store_flag PROTO((tree, rtx, enum machine_mode, int));
-static tree defer_cleanups_to PROTO((tree));
-extern void (*interim_eh_hook) PROTO((tree));
-extern tree truthvalue_conversion PROTO((tree));
/* Record for each mode whether we can move a register directly to or
from an object of that mode in memory. If we can't, we won't try
@@ -207,16 +214,18 @@ static char direct_store[NUM_MACHINE_MODES];
#if defined (HAVE_movstrqi) || defined (HAVE_movstrhi) || defined (HAVE_movstrsi) || defined (HAVE_movstrdi) || defined (HAVE_movstrti)
#define MOVE_RATIO 2
#else
-/* A value of around 6 would minimize code size; infinity would minimize
- execution time. */
-#define MOVE_RATIO 15
+/* If we are optimizing for space (-Os), cut down the default move ratio */
+#define MOVE_RATIO (optimize_size ? 3 : 15)
#endif
#endif
/* This array records the insn_code of insns to perform block moves. */
enum insn_code movstr_optab[NUM_MACHINE_MODES];
-/* SLOW_UNALIGNED_ACCESS is non-zero if unaligned accesses are very slow. */
+/* This array records the insn_code of insns to perform block clears. */
+enum insn_code clrstr_optab[NUM_MACHINE_MODES];
+
+/* SLOW_UNALIGNED_ACCESS is non-zero if unaligned accesses are very slow. */
#ifndef SLOW_UNALIGNED_ACCESS
#define SLOW_UNALIGNED_ACCESS STRICT_ALIGNMENT
@@ -230,32 +239,6 @@ enum insn_code movstr_optab[NUM_MACHINE_MODES];
#define OUTGOING_REGNO(IN) (IN)
#endif
-/* Maps used to convert modes to const, load, and store bytecodes. */
-enum bytecode_opcode mode_to_const_map[MAX_MACHINE_MODE];
-enum bytecode_opcode mode_to_load_map[MAX_MACHINE_MODE];
-enum bytecode_opcode mode_to_store_map[MAX_MACHINE_MODE];
-
-/* Initialize maps used to convert modes to const, load, and store
- bytecodes. */
-void
-bc_init_mode_to_opcode_maps ()
-{
- int mode;
-
- for (mode = 0; mode < (int) MAX_MACHINE_MODE; mode++)
- mode_to_const_map[mode] =
- mode_to_load_map[mode] =
- mode_to_store_map[mode] = neverneverland;
-
-#define DEF_MODEMAP(SYM, CODE, UCODE, CONST, LOAD, STORE) \
- mode_to_const_map[(int) SYM] = CONST; \
- mode_to_load_map[(int) SYM] = LOAD; \
- mode_to_store_map[(int) SYM] = STORE;
-
-#include "modemap.def"
-#undef DEF_MODEMAP
-}
-
/* This is run once per compilation to set up which modes can be used
directly in memory and to initialize the block move optab. */
@@ -264,14 +247,24 @@ init_expr_once ()
{
rtx insn, pat;
enum machine_mode mode;
+ int num_clobbers;
+ rtx mem, mem1;
+ char *free_point;
+
+ start_sequence ();
+
+ /* Since we are on the permanent obstack, we must be sure we save this
+ spot AFTER we call start_sequence, since it will reuse the rtl it
+ makes. */
+ free_point = (char *) oballoc (0);
+
/* Try indexing by frame ptr and try by stack ptr.
It is known that on the Convex the stack ptr isn't a valid index.
With luck, one or the other is valid on any machine. */
- rtx mem = gen_rtx (MEM, VOIDmode, stack_pointer_rtx);
- rtx mem1 = gen_rtx (MEM, VOIDmode, frame_pointer_rtx);
+ mem = gen_rtx_MEM (VOIDmode, stack_pointer_rtx);
+ mem1 = gen_rtx_MEM (VOIDmode, frame_pointer_rtx);
- start_sequence ();
- insn = emit_insn (gen_rtx (SET, 0, 0));
+ insn = emit_insn (gen_rtx_SET (0, NULL_RTX, NULL_RTX));
pat = PATTERN (insn);
for (mode = VOIDmode; (int) mode < NUM_MACHINE_MODES;
@@ -279,7 +272,6 @@ init_expr_once ()
{
int regno;
rtx reg;
- int num_clobbers;
direct_load[(int) mode] = direct_store[(int) mode] = 0;
PUT_MODE (mem, mode);
@@ -296,7 +288,7 @@ init_expr_once ()
if (! HARD_REGNO_MODE_OK (regno, mode))
continue;
- reg = gen_rtx (REG, mode, regno);
+ reg = gen_rtx_REG (mode, regno);
SET_SRC (pat) = mem;
SET_DEST (pat) = reg;
@@ -320,9 +312,18 @@ init_expr_once ()
}
}
+ /* Find out if CONSTANT_P_RTX is accepted. */
+ SET_DEST (pat) = gen_rtx_REG (TYPE_MODE (integer_type_node),
+ FIRST_PSEUDO_REGISTER);
+ SET_SRC (pat) = gen_rtx_CONSTANT_P_RTX (TYPE_MODE (integer_type_node),
+ SET_DEST (pat));
+ if (recog (pat, insn, &num_clobbers) >= 0)
+ can_handle_constant_p = 1;
+
end_sequence ();
+ obfree (free_point);
}
-
+
/* This is run at the start of compiling a function. */
void
@@ -332,7 +333,6 @@ init_expr ()
pending_stack_adjust = 0;
inhibit_defer_pop = 0;
- cleanups_this_call = 0;
saveregs_value = 0;
apply_args_value = 0;
forced_labels = 0;
@@ -345,19 +345,16 @@ void
save_expr_status (p)
struct function *p;
{
- /* Instead of saving the postincrement queue, empty it. */
- emit_queue ();
-
+ p->pending_chain = pending_chain;
p->pending_stack_adjust = pending_stack_adjust;
p->inhibit_defer_pop = inhibit_defer_pop;
- p->cleanups_this_call = cleanups_this_call;
p->saveregs_value = saveregs_value;
p->apply_args_value = apply_args_value;
p->forced_labels = forced_labels;
+ pending_chain = NULL_RTX;
pending_stack_adjust = 0;
inhibit_defer_pop = 0;
- cleanups_this_call = 0;
saveregs_value = 0;
apply_args_value = 0;
forced_labels = 0;
@@ -370,9 +367,9 @@ void
restore_expr_status (p)
struct function *p;
{
+ pending_chain = p->pending_chain;
pending_stack_adjust = p->pending_stack_adjust;
inhibit_defer_pop = p->inhibit_defer_pop;
- cleanups_this_call = p->cleanups_this_call;
saveregs_value = p->saveregs_value;
apply_args_value = p->apply_args_value;
forced_labels = p->forced_labels;
@@ -381,8 +378,6 @@ restore_expr_status (p)
/* Manage the queue of increment instructions to be output
for POSTINCREMENT_EXPR expressions, etc. */
-static rtx pending_chain;
-
/* Queue up to increment (or change) VAR later. BODY says how:
BODY should be the same thing you would pass to emit_insn
to increment right away. It will go to emit_insn later on.
@@ -394,8 +389,9 @@ static rtx
enqueue_insn (var, body)
rtx var, body;
{
- pending_chain = gen_rtx (QUEUED, GET_MODE (var),
- var, NULL_RTX, NULL_RTX, body, pending_chain);
+ pending_chain = gen_rtx_QUEUED (GET_MODE (var),
+ var, NULL_RTX, NULL_RTX, body,
+ pending_chain);
return pending_chain;
}
@@ -438,11 +434,12 @@ protect_from_queue (x, modify)
&& GET_CODE (XEXP (x, 0)) == QUEUED && !modify)
{
register rtx y = XEXP (x, 0);
- register rtx new = gen_rtx (MEM, GET_MODE (x), QUEUED_VAR (y));
+ register rtx new = gen_rtx_MEM (GET_MODE (x), QUEUED_VAR (y));
MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (x);
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (x);
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (x);
+ MEM_ALIAS_SET (new) = MEM_ALIAS_SET (x);
if (QUEUED_INSN (y))
{
@@ -511,10 +508,11 @@ queued_subexp_p (x)
case MULT:
case PLUS:
case MINUS:
- return queued_subexp_p (XEXP (x, 0))
- || queued_subexp_p (XEXP (x, 1));
+ return (queued_subexp_p (XEXP (x, 0))
+ || queued_subexp_p (XEXP (x, 1)));
+ default:
+ return 0;
}
- return 0;
}
/* Perform all the pending incrementations. */
@@ -523,9 +521,17 @@ void
emit_queue ()
{
register rtx p;
- while (p = pending_chain)
+ while ((p = pending_chain))
{
- QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p));
+ rtx body = QUEUED_BODY (p);
+
+ if (GET_CODE (body) == SEQUENCE)
+ {
+ QUEUED_INSN (p) = XVECEXP (QUEUED_BODY (p), 0, 0);
+ emit_insn (QUEUED_BODY (p));
+ }
+ else
+ QUEUED_INSN (p) = emit_insn (QUEUED_BODY (p));
pending_chain = QUEUED_NEXT (p);
}
}
@@ -587,119 +593,28 @@ convert_move (to, from, unsignedp)
{
rtx value;
-#ifdef HAVE_extendqfhf2
- if (HAVE_extendqfsf2 && from_mode == QFmode && to_mode == HFmode)
+ if (GET_MODE_BITSIZE (from_mode) < GET_MODE_BITSIZE (to_mode))
{
- emit_unop_insn (CODE_FOR_extendqfsf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendqfsf2
- if (HAVE_extendqfsf2 && from_mode == QFmode && to_mode == SFmode)
- {
- emit_unop_insn (CODE_FOR_extendqfsf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendqfdf2
- if (HAVE_extendqfdf2 && from_mode == QFmode && to_mode == DFmode)
- {
- emit_unop_insn (CODE_FOR_extendqfdf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendqfxf2
- if (HAVE_extendqfxf2 && from_mode == QFmode && to_mode == XFmode)
- {
- emit_unop_insn (CODE_FOR_extendqfxf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendqftf2
- if (HAVE_extendqftf2 && from_mode == QFmode && to_mode == TFmode)
- {
- emit_unop_insn (CODE_FOR_extendqftf2, to, from, UNKNOWN);
- return;
- }
-#endif
-
-#ifdef HAVE_extendhftqf2
- if (HAVE_extendhftqf2 && from_mode == HFmode && to_mode == TQFmode)
- {
- emit_unop_insn (CODE_FOR_extendhftqf2, to, from, UNKNOWN);
- return;
- }
-#endif
-
-#ifdef HAVE_extendhfsf2
- if (HAVE_extendhfsf2 && from_mode == HFmode && to_mode == SFmode)
- {
- emit_unop_insn (CODE_FOR_extendhfsf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendhfdf2
- if (HAVE_extendhfdf2 && from_mode == HFmode && to_mode == DFmode)
- {
- emit_unop_insn (CODE_FOR_extendhfdf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendhfxf2
- if (HAVE_extendhfxf2 && from_mode == HFmode && to_mode == XFmode)
- {
- emit_unop_insn (CODE_FOR_extendhfxf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendhftf2
- if (HAVE_extendhftf2 && from_mode == HFmode && to_mode == TFmode)
- {
- emit_unop_insn (CODE_FOR_extendhftf2, to, from, UNKNOWN);
- return;
- }
-#endif
-
-#ifdef HAVE_extendsfdf2
- if (HAVE_extendsfdf2 && from_mode == SFmode && to_mode == DFmode)
- {
- emit_unop_insn (CODE_FOR_extendsfdf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendsfxf2
- if (HAVE_extendsfxf2 && from_mode == SFmode && to_mode == XFmode)
- {
- emit_unop_insn (CODE_FOR_extendsfxf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extendsftf2
- if (HAVE_extendsftf2 && from_mode == SFmode && to_mode == TFmode)
- {
- emit_unop_insn (CODE_FOR_extendsftf2, to, from, UNKNOWN);
- return;
- }
-#endif
-#ifdef HAVE_extenddfxf2
- if (HAVE_extenddfxf2 && from_mode == DFmode && to_mode == XFmode)
- {
- emit_unop_insn (CODE_FOR_extenddfxf2, to, from, UNKNOWN);
- return;
+ /* Try converting directly if the insn is supported. */
+ if ((code = can_extend_p (to_mode, from_mode, 0))
+ != CODE_FOR_nothing)
+ {
+ emit_unop_insn (code, to, from, UNKNOWN);
+ return;
+ }
}
-#endif
-#ifdef HAVE_extenddftf2
- if (HAVE_extenddftf2 && from_mode == DFmode && to_mode == TFmode)
+
+#ifdef HAVE_trunchfqf2
+ if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
{
- emit_unop_insn (CODE_FOR_extenddftf2, to, from, UNKNOWN);
+ emit_unop_insn (CODE_FOR_trunchfqf2, to, from, UNKNOWN);
return;
}
#endif
-
-#ifdef HAVE_trunchfqf2
- if (HAVE_trunchfqf2 && from_mode == HFmode && to_mode == QFmode)
+#ifdef HAVE_trunctqfqf2
+ if (HAVE_trunctqfqf2 && from_mode == TQFmode && to_mode == QFmode)
{
- emit_unop_insn (CODE_FOR_trunchfqf2, to, from, UNKNOWN);
+ emit_unop_insn (CODE_FOR_trunctqfqf2, to, from, UNKNOWN);
return;
}
#endif
@@ -767,6 +682,36 @@ convert_move (to, from, unsignedp)
return;
}
#endif
+
+#ifdef HAVE_truncsftqf2
+ if (HAVE_truncsftqf2 && from_mode == SFmode && to_mode == TQFmode)
+ {
+ emit_unop_insn (CODE_FOR_truncsftqf2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+#ifdef HAVE_truncdftqf2
+ if (HAVE_truncdftqf2 && from_mode == DFmode && to_mode == TQFmode)
+ {
+ emit_unop_insn (CODE_FOR_truncdftqf2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+#ifdef HAVE_truncxftqf2
+ if (HAVE_truncxftqf2 && from_mode == XFmode && to_mode == TQFmode)
+ {
+ emit_unop_insn (CODE_FOR_truncxftqf2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+#ifdef HAVE_trunctftqf2
+ if (HAVE_trunctftqf2 && from_mode == TFmode && to_mode == TQFmode)
+ {
+ emit_unop_insn (CODE_FOR_trunctftqf2, to, from, UNKNOWN);
+ return;
+ }
+#endif
+
#ifdef HAVE_truncdfsf2
if (HAVE_truncdfsf2 && from_mode == DFmode && to_mode == SFmode)
{
@@ -820,6 +765,9 @@ convert_move (to, from, unsignedp)
case TFmode:
libcall = extendsftf2_libfunc;
break;
+
+ default:
+ break;
}
break;
@@ -837,6 +785,9 @@ convert_move (to, from, unsignedp)
case TFmode:
libcall = extenddftf2_libfunc;
break;
+
+ default:
+ break;
}
break;
@@ -850,6 +801,9 @@ convert_move (to, from, unsignedp)
case DFmode:
libcall = truncxfdf2_libfunc;
break;
+
+ default:
+ break;
}
break;
@@ -863,8 +817,14 @@ convert_move (to, from, unsignedp)
case DFmode:
libcall = trunctfdf2_libfunc;
break;
+
+ default:
+ break;
}
break;
+
+ default:
+ break;
}
if (libcall == (rtx) 0)
@@ -910,7 +870,7 @@ convert_move (to, from, unsignedp)
!= CODE_FOR_nothing))
{
if (GET_CODE (to) == REG)
- emit_insn (gen_rtx (CLOBBER, VOIDmode, to));
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, to));
convert_move (gen_lowpart (word_mode, to), from, unsignedp);
emit_unop_insn (code, to,
gen_lowpart (word_mode, to), equiv_code);
@@ -980,7 +940,7 @@ convert_move (to, from, unsignedp)
end_sequence ();
emit_no_conflict_block (insns, to, from, NULL_RTX,
- gen_rtx (equiv_code, to_mode, copy_rtx (from)));
+ gen_rtx_fmt_e (equiv_code, to_mode, copy_rtx (from)));
return;
}
@@ -1000,6 +960,41 @@ convert_move (to, from, unsignedp)
}
/* Handle pointer conversion */ /* SPEE 900220 */
+ if (to_mode == PQImode)
+ {
+ if (from_mode != QImode)
+ from = convert_to_mode (QImode, from, unsignedp);
+
+#ifdef HAVE_truncqipqi2
+ if (HAVE_truncqipqi2)
+ {
+ emit_unop_insn (CODE_FOR_truncqipqi2, to, from, UNKNOWN);
+ return;
+ }
+#endif /* HAVE_truncqipqi2 */
+ abort ();
+ }
+
+ if (from_mode == PQImode)
+ {
+ if (to_mode != QImode)
+ {
+ from = convert_to_mode (QImode, from, unsignedp);
+ from_mode = QImode;
+ }
+ else
+ {
+#ifdef HAVE_extendpqiqi2
+ if (HAVE_extendpqiqi2)
+ {
+ emit_unop_insn (CODE_FOR_extendpqiqi2, to, from, UNKNOWN);
+ return;
+ }
+#endif /* HAVE_extendpqiqi2 */
+ abort ();
+ }
+ }
+
if (to_mode == PSImode)
{
if (from_mode != SImode)
@@ -1335,7 +1330,20 @@ convert_modes (mode, oldmode, x, unsignedp)
if (unsignedp && GET_MODE_CLASS (mode) == MODE_INT
&& GET_MODE_BITSIZE (mode) == 2 * HOST_BITS_PER_WIDE_INT
&& GET_CODE (x) == CONST_INT && INTVAL (x) < 0)
- return immed_double_const (INTVAL (x), (HOST_WIDE_INT) 0, mode);
+ {
+ HOST_WIDE_INT val = INTVAL (x);
+
+ if (oldmode != VOIDmode
+ && HOST_BITS_PER_WIDE_INT > GET_MODE_BITSIZE (oldmode))
+ {
+ int width = GET_MODE_BITSIZE (oldmode);
+
+ /* We need to zero extend VAL. */
+ val &= ((HOST_WIDE_INT) 1 << width) - 1;
+ }
+
+ return immed_double_const (val, (HOST_WIDE_INT) 0, mode);
+ }
/* We can do this with a gen_lowpart if both desired and current modes
are integer, and this is either a constant integer, a register, or a
@@ -1493,7 +1501,7 @@ move_by_pieces (to, from, len, align)
}
/* The code above should have handled everything. */
- if (data.len != 0)
+ if (data.len > 0)
abort ();
}
@@ -1543,7 +1551,7 @@ move_by_pieces_ninsns (l, align)
static void
move_by_pieces_1 (genfun, mode, data)
- rtx (*genfun) ();
+ rtx (*genfun) PROTO ((rtx, ...));
enum machine_mode mode;
struct move_by_pieces *data;
{
@@ -1555,15 +1563,18 @@ move_by_pieces_1 (genfun, mode, data)
if (data->reverse) data->offset -= size;
to1 = (data->autinc_to
- ? gen_rtx (MEM, mode, data->to_addr)
- : change_address (data->to, mode,
- plus_constant (data->to_addr, data->offset)));
+ ? gen_rtx_MEM (mode, data->to_addr)
+ : copy_rtx (change_address (data->to, mode,
+ plus_constant (data->to_addr,
+ data->offset))));
MEM_IN_STRUCT_P (to1) = data->to_struct;
- from1 =
- (data->autinc_from
- ? gen_rtx (MEM, mode, data->from_addr)
- : change_address (data->from, mode,
- plus_constant (data->from_addr, data->offset)));
+
+ from1
+ = (data->autinc_from
+ ? gen_rtx_MEM (mode, data->from_addr)
+ : copy_rtx (change_address (data->from, mode,
+ plus_constant (data->from_addr,
+ data->offset))));
MEM_IN_STRUCT_P (from1) = data->from_struct;
#ifdef HAVE_PRE_DECREMENT
@@ -1595,14 +1606,23 @@ move_by_pieces_1 (genfun, mode, data)
with mode BLKmode.
SIZE is an rtx that says how long they are.
ALIGN is the maximum alignment we can assume they have,
- measured in bytes. */
+ measured in bytes.
-void
+ Return the address of the new block, if memcpy is called and returns it,
+ 0 otherwise. */
+
+rtx
emit_block_move (x, y, size, align)
rtx x, y;
rtx size;
int align;
{
+ rtx retval = 0;
+#ifdef TARGET_MEM_FUNCTIONS
+ static tree fn;
+ tree call_expr, arg_list;
+#endif
+
if (GET_MODE (x) != BLKmode)
abort ();
@@ -1644,7 +1664,7 @@ emit_block_move (x, y, size, align)
actual mode mask. */
&& ((GET_CODE (size) == CONST_INT
&& ((unsigned HOST_WIDE_INT) INTVAL (size)
- <= GET_MODE_MASK (mode)))
+ <= (GET_MODE_MASK (mode) >> 1)))
|| GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
&& (insn_operand_predicate[(int) code][0] == 0
|| (*insn_operand_predicate[(int) code][0]) (x, BLKmode))
@@ -1667,7 +1687,7 @@ emit_block_move (x, y, size, align)
if (pat)
{
emit_insn (pat);
- return;
+ return 0;
}
else
delete_insns_since (last);
@@ -1675,21 +1695,71 @@ emit_block_move (x, y, size, align)
}
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (memcpy_libfunc, 0,
- VOIDmode, 3, XEXP (x, 0), Pmode,
- XEXP (y, 0), Pmode,
- convert_to_mode (TYPE_MODE (sizetype), size,
- TREE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
+ /* It is incorrect to use the libcall calling conventions to call
+ memcpy in this context.
+
+ This could be a user call to memcpy and the user may wish to
+ examine the return value from memcpy.
+
+ For targets where libcalls and normal calls have different conventions
+ for returning pointers, we could end up generating incorrect code.
+
+ So instead of using a libcall sequence we build up a suitable
+ CALL_EXPR and expand the call in the normal fashion. */
+ if (fn == NULL_TREE)
+ {
+ tree fntype;
+
+ /* This was copied from except.c, I don't know if all this is
+ necessary in this context or not. */
+ fn = get_identifier ("memcpy");
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ fntype = build_pointer_type (void_type_node);
+ fntype = build_function_type (fntype, NULL_TREE);
+ fn = build_decl (FUNCTION_DECL, fn, fntype);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ make_decl_rtl (fn, NULL_PTR, 1);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ /* We need to make an argument list for the function call.
+
+ memcpy has three arguments, the first two are void * addresses and
+ the last is a size_t byte count for the copy. */
+ arg_list
+ = build_tree_list (NULL_TREE,
+ make_tree (build_pointer_type (void_type_node),
+ XEXP (x, 0)));
+ TREE_CHAIN (arg_list)
+ = build_tree_list (NULL_TREE,
+ make_tree (build_pointer_type (void_type_node),
+ XEXP (y, 0)));
+ TREE_CHAIN (TREE_CHAIN (arg_list))
+ = build_tree_list (NULL_TREE, make_tree (sizetype, size));
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
+
+ /* Now we have to build up the CALL_EXPR itself. */
+ call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+ call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ call_expr, arg_list, NULL_TREE);
+ TREE_SIDE_EFFECTS (call_expr) = 1;
+
+ retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
#else
emit_library_call (bcopy_libfunc, 0,
VOIDmode, 3, XEXP (y, 0), Pmode,
XEXP (x, 0), Pmode,
- convert_to_mode (TYPE_MODE (sizetype), size,
- TREE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
+ convert_to_mode (TYPE_MODE (integer_type_node), size,
+ TREE_UNSIGNED (integer_type_node)),
+ TYPE_MODE (integer_type_node));
#endif
}
+
+ return retval;
}
/* Copy all or part of a value X into registers starting at REGNO.
@@ -1703,7 +1773,10 @@ move_block_to_reg (regno, x, nregs, mode)
enum machine_mode mode;
{
int i;
- rtx pat, last;
+#ifdef HAVE_load_multiple
+ rtx pat;
+ rtx last;
+#endif
if (nregs == 0)
return;
@@ -1716,7 +1789,7 @@ move_block_to_reg (regno, x, nregs, mode)
if (HAVE_load_multiple)
{
last = get_last_insn ();
- pat = gen_load_multiple (gen_rtx (REG, word_mode, regno), x,
+ pat = gen_load_multiple (gen_rtx_REG (word_mode, regno), x,
GEN_INT (nregs));
if (pat)
{
@@ -1729,7 +1802,7 @@ move_block_to_reg (regno, x, nregs, mode)
#endif
for (i = 0; i < nregs; i++)
- emit_move_insn (gen_rtx (REG, word_mode, regno + i),
+ emit_move_insn (gen_rtx_REG (word_mode, regno + i),
operand_subword_force (x, i, mode));
}
@@ -1746,10 +1819,25 @@ move_block_from_reg (regno, x, nregs, size)
int size;
{
int i;
- rtx pat, last;
+#ifdef HAVE_store_multiple
+ rtx pat;
+ rtx last;
+#endif
+ enum machine_mode mode;
+ /* If SIZE is that of a mode no bigger than a word, just use that
+ mode's store operation. */
+ if (size <= UNITS_PER_WORD
+ && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode)
+ {
+ emit_move_insn (change_address (x, mode, NULL),
+ gen_rtx_REG (mode, regno));
+ return;
+ }
+
/* Blocks smaller than a word on a BYTES_BIG_ENDIAN machine must be aligned
- to the left before storing to memory. */
+ to the left before storing to memory. Note that the previous test
+ doesn't handle all cases (e.g. SIZE == 3). */
if (size < UNITS_PER_WORD && BYTES_BIG_ENDIAN)
{
rtx tem = operand_subword (x, 0, 1, BLKmode);
@@ -1759,7 +1847,7 @@ move_block_from_reg (regno, x, nregs, size)
abort ();
shift = expand_shift (LSHIFT_EXPR, word_mode,
- gen_rtx (REG, word_mode, regno),
+ gen_rtx_REG (word_mode, regno),
build_int_2 ((UNITS_PER_WORD - size)
* BITS_PER_UNIT, 0), NULL_RTX, 0);
emit_move_insn (tem, shift);
@@ -1771,7 +1859,7 @@ move_block_from_reg (regno, x, nregs, size)
if (HAVE_store_multiple)
{
last = get_last_insn ();
- pat = gen_store_multiple (x, gen_rtx (REG, word_mode, regno),
+ pat = gen_store_multiple (x, gen_rtx_REG (word_mode, regno),
GEN_INT (nregs));
if (pat)
{
@@ -1790,8 +1878,191 @@ move_block_from_reg (regno, x, nregs, size)
if (tem == 0)
abort ();
- emit_move_insn (tem, gen_rtx (REG, word_mode, regno + i));
+ emit_move_insn (tem, gen_rtx_REG (word_mode, regno + i));
+ }
+}
+
+/* Emit code to move a block SRC to a block DST, where DST is non-consecutive
+ registers represented by a PARALLEL. SSIZE represents the total size of
+ block SRC in bytes, or -1 if not known. ALIGN is the known alignment of
+ SRC in bits. */
+/* ??? If SSIZE % UNITS_PER_WORD != 0, we make the blatent assumption that
+ the balance will be in what would be the low-order memory addresses, i.e.
+ left justified for big endian, right justified for little endian. This
+ happens to be true for the targets currently using this support. If this
+ ever changes, a new target macro along the lines of FUNCTION_ARG_PADDING
+ would be needed. */
+
+void
+emit_group_load (dst, orig_src, ssize, align)
+ rtx dst, orig_src;
+ int align, ssize;
+{
+ rtx *tmps, src;
+ int start, i;
+
+ if (GET_CODE (dst) != PARALLEL)
+ abort ();
+
+ /* Check for a NULL entry, used to indicate that the parameter goes
+ both on the stack and in registers. */
+ if (XEXP (XVECEXP (dst, 0, 0), 0))
+ start = 0;
+ else
+ start = 1;
+
+ tmps = (rtx *) alloca (sizeof(rtx) * XVECLEN (dst, 0));
+
+ /* If we won't be loading directly from memory, protect the real source
+ from strange tricks we might play. */
+ src = orig_src;
+ if (GET_CODE (src) != MEM)
+ {
+ src = gen_reg_rtx (GET_MODE (orig_src));
+ emit_move_insn (src, orig_src);
+ }
+
+ /* Process the pieces. */
+ for (i = start; i < XVECLEN (dst, 0); i++)
+ {
+ enum machine_mode mode = GET_MODE (XEXP (XVECEXP (dst, 0, i), 0));
+ int bytepos = INTVAL (XEXP (XVECEXP (dst, 0, i), 1));
+ int bytelen = GET_MODE_SIZE (mode);
+ int shift = 0;
+
+ /* Handle trailing fragments that run over the size of the struct. */
+ if (ssize >= 0 && bytepos + bytelen > ssize)
+ {
+ shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
+ bytelen = ssize - bytepos;
+ if (bytelen <= 0)
+ abort();
+ }
+
+ /* Optimize the access just a bit. */
+ if (GET_CODE (src) == MEM
+ && align*BITS_PER_UNIT >= GET_MODE_ALIGNMENT (mode)
+ && bytepos*BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
+ && bytelen == GET_MODE_SIZE (mode))
+ {
+ tmps[i] = gen_reg_rtx (mode);
+ emit_move_insn (tmps[i],
+ change_address (src, mode,
+ plus_constant (XEXP (src, 0),
+ bytepos)));
+ }
+ else
+ {
+ tmps[i] = extract_bit_field (src, bytelen*BITS_PER_UNIT,
+ bytepos*BITS_PER_UNIT, 1, NULL_RTX,
+ mode, mode, align, ssize);
+ }
+
+ if (BYTES_BIG_ENDIAN && shift)
+ {
+ expand_binop (mode, ashl_optab, tmps[i], GEN_INT (shift),
+ tmps[i], 0, OPTAB_WIDEN);
+ }
+ }
+ emit_queue();
+
+ /* Copy the extracted pieces into the proper (probable) hard regs. */
+ for (i = start; i < XVECLEN (dst, 0); i++)
+ emit_move_insn (XEXP (XVECEXP (dst, 0, i), 0), tmps[i]);
+}
+
+/* Emit code to move a block SRC to a block DST, where SRC is non-consecutive
+ registers represented by a PARALLEL. SSIZE represents the total size of
+ block DST, or -1 if not known. ALIGN is the known alignment of DST. */
+
+void
+emit_group_store (orig_dst, src, ssize, align)
+ rtx orig_dst, src;
+ int ssize, align;
+{
+ rtx *tmps, dst;
+ int start, i;
+
+ if (GET_CODE (src) != PARALLEL)
+ abort ();
+
+ /* Check for a NULL entry, used to indicate that the parameter goes
+ both on the stack and in registers. */
+ if (XEXP (XVECEXP (src, 0, 0), 0))
+ start = 0;
+ else
+ start = 1;
+
+ tmps = (rtx *) alloca (sizeof(rtx) * XVECLEN (src, 0));
+
+ /* Copy the (probable) hard regs into pseudos. */
+ for (i = start; i < XVECLEN (src, 0); i++)
+ {
+ rtx reg = XEXP (XVECEXP (src, 0, i), 0);
+ tmps[i] = gen_reg_rtx (GET_MODE (reg));
+ emit_move_insn (tmps[i], reg);
+ }
+ emit_queue();
+
+ /* If we won't be storing directly into memory, protect the real destination
+ from strange tricks we might play. */
+ dst = orig_dst;
+ if (GET_CODE (dst) != MEM)
+ {
+ dst = gen_reg_rtx (GET_MODE (orig_dst));
+ /* Make life a bit easier for combine. */
+ emit_move_insn (dst, const0_rtx);
+ }
+ else if (! MEM_IN_STRUCT_P (dst))
+ {
+ /* store_bit_field requires that memory operations have
+ mem_in_struct_p set; we might not. */
+
+ dst = copy_rtx (orig_dst);
+ MEM_IN_STRUCT_P (dst) = 1;
+ }
+
+ /* Process the pieces. */
+ for (i = start; i < XVECLEN (src, 0); i++)
+ {
+ int bytepos = INTVAL (XEXP (XVECEXP (src, 0, i), 1));
+ enum machine_mode mode = GET_MODE (tmps[i]);
+ int bytelen = GET_MODE_SIZE (mode);
+
+ /* Handle trailing fragments that run over the size of the struct. */
+ if (ssize >= 0 && bytepos + bytelen > ssize)
+ {
+ if (BYTES_BIG_ENDIAN)
+ {
+ int shift = (bytelen - (ssize - bytepos)) * BITS_PER_UNIT;
+ expand_binop (mode, ashr_optab, tmps[i], GEN_INT (shift),
+ tmps[i], 0, OPTAB_WIDEN);
+ }
+ bytelen = ssize - bytepos;
+ }
+
+ /* Optimize the access just a bit. */
+ if (GET_CODE (dst) == MEM
+ && align*BITS_PER_UNIT >= GET_MODE_ALIGNMENT (mode)
+ && bytepos*BITS_PER_UNIT % GET_MODE_ALIGNMENT (mode) == 0
+ && bytelen == GET_MODE_SIZE (mode))
+ {
+ emit_move_insn (change_address (dst, mode,
+ plus_constant (XEXP (dst, 0),
+ bytepos)),
+ tmps[i]);
+ }
+ else
+ {
+ store_bit_field (dst, bytelen*BITS_PER_UNIT, bytepos*BITS_PER_UNIT,
+ mode, tmps[i], align, ssize);
+ }
}
+ emit_queue();
+
+ /* Copy from the pseudo into the (probable) hard reg. */
+ if (GET_CODE (dst) == REG)
+ emit_move_insn (orig_dst, dst);
}
/* Add a USE expression for REG to the (possibly empty) list pointed
@@ -1806,8 +2077,8 @@ use_reg (call_fusage, reg)
abort();
*call_fusage
- = gen_rtx (EXPR_LIST, VOIDmode,
- gen_rtx (USE, VOIDmode, reg), *call_fusage);
+ = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_USE (VOIDmode, reg), *call_fusage);
}
/* Add USE expressions to *CALL_FUSAGE for each of NREGS consecutive regs,
@@ -1825,37 +2096,311 @@ use_regs (call_fusage, regno, nregs)
abort ();
for (i = 0; i < nregs; i++)
- use_reg (call_fusage, gen_rtx (REG, reg_raw_mode[regno + i], regno + i));
+ use_reg (call_fusage, gen_rtx_REG (reg_raw_mode[regno + i], regno + i));
+}
+
+/* Add USE expressions to *CALL_FUSAGE for each REG contained in the
+ PARALLEL REGS. This is for calls that pass values in multiple
+ non-contiguous locations. The Irix 6 ABI has examples of this. */
+
+void
+use_group_regs (call_fusage, regs)
+ rtx *call_fusage;
+ rtx regs;
+{
+ int i;
+
+ for (i = 0; i < XVECLEN (regs, 0); i++)
+ {
+ rtx reg = XEXP (XVECEXP (regs, 0, i), 0);
+
+ /* A NULL entry means the parameter goes both on the stack and in
+ registers. This can also be a MEM for targets that pass values
+ partially on the stack and partially in registers. */
+ if (reg != 0 && GET_CODE (reg) == REG)
+ use_reg (call_fusage, reg);
+ }
+}
+
+/* Generate several move instructions to clear LEN bytes of block TO.
+ (A MEM rtx with BLKmode). The caller must pass TO through
+ protect_from_queue before calling. ALIGN (in bytes) is maximum alignment
+ we can assume. */
+
+static void
+clear_by_pieces (to, len, align)
+ rtx to;
+ int len, align;
+{
+ struct clear_by_pieces data;
+ rtx to_addr = XEXP (to, 0);
+ int max_size = MOVE_MAX + 1;
+
+ data.offset = 0;
+ data.to_addr = to_addr;
+ data.to = to;
+ data.autinc_to
+ = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC
+ || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC);
+
+ data.explicit_inc_to = 0;
+ data.reverse
+ = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC);
+ if (data.reverse) data.offset = len;
+ data.len = len;
+
+ data.to_struct = MEM_IN_STRUCT_P (to);
+
+ /* If copying requires more than two move insns,
+ copy addresses to registers (to make displacements shorter)
+ and use post-increment if available. */
+ if (!data.autinc_to
+ && move_by_pieces_ninsns (len, align) > 2)
+ {
+#ifdef HAVE_PRE_DECREMENT
+ if (data.reverse && ! data.autinc_to)
+ {
+ data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len));
+ data.autinc_to = 1;
+ data.explicit_inc_to = -1;
+ }
+#endif
+#ifdef HAVE_POST_INCREMENT
+ if (! data.reverse && ! data.autinc_to)
+ {
+ data.to_addr = copy_addr_to_reg (to_addr);
+ data.autinc_to = 1;
+ data.explicit_inc_to = 1;
+ }
+#endif
+ if (!data.autinc_to && CONSTANT_P (to_addr))
+ data.to_addr = copy_addr_to_reg (to_addr);
+ }
+
+ if (! SLOW_UNALIGNED_ACCESS
+ || align > MOVE_MAX || align >= BIGGEST_ALIGNMENT / BITS_PER_UNIT)
+ align = MOVE_MAX;
+
+ /* First move what we can in the largest integer mode, then go to
+ successively smaller modes. */
+
+ while (max_size > 1)
+ {
+ enum machine_mode mode = VOIDmode, tmode;
+ enum insn_code icode;
+
+ for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode))
+ if (GET_MODE_SIZE (tmode) < max_size)
+ mode = tmode;
+
+ if (mode == VOIDmode)
+ break;
+
+ icode = mov_optab->handlers[(int) mode].insn_code;
+ if (icode != CODE_FOR_nothing
+ && align >= MIN (BIGGEST_ALIGNMENT / BITS_PER_UNIT,
+ GET_MODE_SIZE (mode)))
+ clear_by_pieces_1 (GEN_FCN (icode), mode, &data);
+
+ max_size = GET_MODE_SIZE (mode);
+ }
+
+ /* The code above should have handled everything. */
+ if (data.len != 0)
+ abort ();
+}
+
+/* Subroutine of clear_by_pieces. Clear as many bytes as appropriate
+ with move instructions for mode MODE. GENFUN is the gen_... function
+ to make a move insn for that mode. DATA has all the other info. */
+
+static void
+clear_by_pieces_1 (genfun, mode, data)
+ rtx (*genfun) PROTO ((rtx, ...));
+ enum machine_mode mode;
+ struct clear_by_pieces *data;
+{
+ register int size = GET_MODE_SIZE (mode);
+ register rtx to1;
+
+ while (data->len >= size)
+ {
+ if (data->reverse) data->offset -= size;
+
+ to1 = (data->autinc_to
+ ? gen_rtx_MEM (mode, data->to_addr)
+ : copy_rtx (change_address (data->to, mode,
+ plus_constant (data->to_addr,
+ data->offset))));
+ MEM_IN_STRUCT_P (to1) = data->to_struct;
+
+#ifdef HAVE_PRE_DECREMENT
+ if (data->explicit_inc_to < 0)
+ emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size)));
+#endif
+
+ emit_insn ((*genfun) (to1, const0_rtx));
+#ifdef HAVE_POST_INCREMENT
+ if (data->explicit_inc_to > 0)
+ emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size)));
+#endif
+
+ if (! data->reverse) data->offset += size;
+
+ data->len -= size;
+ }
}
/* Write zeros through the storage of OBJECT.
- If OBJECT has BLKmode, SIZE is its length in bytes. */
+ If OBJECT has BLKmode, SIZE is its length in bytes and ALIGN is
+ the maximum alignment we can is has, measured in bytes.
-void
-clear_storage (object, size)
+ If we call a function that returns the length of the block, return it. */
+
+rtx
+clear_storage (object, size, align)
rtx object;
rtx size;
+ int align;
{
+#ifdef TARGET_MEM_FUNCTIONS
+ static tree fn;
+ tree call_expr, arg_list;
+#endif
+ rtx retval = 0;
+
if (GET_MODE (object) == BLKmode)
{
+ object = protect_from_queue (object, 1);
+ size = protect_from_queue (size, 0);
+
+ if (GET_CODE (size) == CONST_INT
+ && (move_by_pieces_ninsns (INTVAL (size), align) < MOVE_RATIO))
+ clear_by_pieces (object, INTVAL (size), align);
+
+ else
+ {
+ /* Try the most limited insn first, because there's no point
+ including more than one in the machine description unless
+ the more limited one has some advantage. */
+
+ rtx opalign = GEN_INT (align);
+ enum machine_mode mode;
+
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ enum insn_code code = clrstr_optab[(int) mode];
+
+ if (code != CODE_FOR_nothing
+ /* We don't need MODE to be narrower than
+ BITS_PER_HOST_WIDE_INT here because if SIZE is less than
+ the mode mask, as it is returned by the macro, it will
+ definitely be less than the actual mode mask. */
+ && ((GET_CODE (size) == CONST_INT
+ && ((unsigned HOST_WIDE_INT) INTVAL (size)
+ <= (GET_MODE_MASK (mode) >> 1)))
+ || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
+ && (insn_operand_predicate[(int) code][0] == 0
+ || (*insn_operand_predicate[(int) code][0]) (object,
+ BLKmode))
+ && (insn_operand_predicate[(int) code][2] == 0
+ || (*insn_operand_predicate[(int) code][2]) (opalign,
+ VOIDmode)))
+ {
+ rtx op1;
+ rtx last = get_last_insn ();
+ rtx pat;
+
+ op1 = convert_to_mode (mode, size, 1);
+ if (insn_operand_predicate[(int) code][1] != 0
+ && ! (*insn_operand_predicate[(int) code][1]) (op1,
+ mode))
+ op1 = copy_to_mode_reg (mode, op1);
+
+ pat = GEN_FCN ((int) code) (object, op1, opalign);
+ if (pat)
+ {
+ emit_insn (pat);
+ return 0;
+ }
+ else
+ delete_insns_since (last);
+ }
+ }
+
+
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (memset_libfunc, 0,
- VOIDmode, 3,
- XEXP (object, 0), Pmode, const0_rtx, ptr_mode,
- convert_to_mode (TYPE_MODE (sizetype),
- size, TREE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
+ /* It is incorrect to use the libcall calling conventions to call
+ memset in this context.
+
+ This could be a user call to memset and the user may wish to
+ examine the return value from memset.
+
+ For targets where libcalls and normal calls have different conventions
+ for returning pointers, we could end up generating incorrect code.
+
+ So instead of using a libcall sequence we build up a suitable
+ CALL_EXPR and expand the call in the normal fashion. */
+ if (fn == NULL_TREE)
+ {
+ tree fntype;
+
+ /* This was copied from except.c, I don't know if all this is
+ necessary in this context or not. */
+ fn = get_identifier ("memset");
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ fntype = build_pointer_type (void_type_node);
+ fntype = build_function_type (fntype, NULL_TREE);
+ fn = build_decl (FUNCTION_DECL, fn, fntype);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ make_decl_rtl (fn, NULL_PTR, 1);
+ assemble_external (fn);
+ pop_obstacks ();
+ }
+
+ /* We need to make an argument list for the function call.
+
+ memset has three arguments, the first is a void * addresses, the
+ second a integer with the initialization value, the last is a size_t
+ byte count for the copy. */
+ arg_list
+ = build_tree_list (NULL_TREE,
+ make_tree (build_pointer_type (void_type_node),
+ XEXP (object, 0)));
+ TREE_CHAIN (arg_list)
+ = build_tree_list (NULL_TREE,
+ make_tree (integer_type_node, const0_rtx));
+ TREE_CHAIN (TREE_CHAIN (arg_list))
+ = build_tree_list (NULL_TREE, make_tree (sizetype, size));
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_list))) = NULL_TREE;
+
+ /* Now we have to build up the CALL_EXPR itself. */
+ call_expr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (fn)), fn);
+ call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ call_expr, arg_list, NULL_TREE);
+ TREE_SIDE_EFFECTS (call_expr) = 1;
+
+ retval = expand_expr (call_expr, NULL_RTX, VOIDmode, 0);
#else
- emit_library_call (bzero_libfunc, 0,
- VOIDmode, 2,
- XEXP (object, 0), Pmode,
- convert_to_mode (TYPE_MODE (sizetype),
- size, TREE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
+ emit_library_call (bzero_libfunc, 0,
+ VOIDmode, 2,
+ XEXP (object, 0), Pmode,
+ convert_to_mode
+ (TYPE_MODE (integer_type_node), size,
+ TREE_UNSIGNED (integer_type_node)),
+ TYPE_MODE (integer_type_node));
#endif
+ }
}
else
- emit_move_insn (object, const0_rtx);
+ emit_move_insn (object, CONST0_RTX (GET_MODE (object)));
+
+ return retval;
}
/* Generate code to copy Y into X.
@@ -1930,7 +2475,6 @@ emit_move_insn_1 (x, y)
{
/* Don't split destination if it is a stack push. */
int stack = push_operand (x, GET_MODE (x));
- rtx insns;
/* If this is a stack, push the highpart first, so it
will be in the argument order.
@@ -1943,22 +2487,26 @@ emit_move_insn_1 (x, y)
regardless of machine's endianness. */
#ifdef STACK_GROWS_DOWNWARD
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
- (gen_rtx (MEM, submode, (XEXP (x, 0))),
+ (gen_rtx_MEM (submode, (XEXP (x, 0))),
gen_imagpart (submode, y)));
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
- (gen_rtx (MEM, submode, (XEXP (x, 0))),
+ (gen_rtx_MEM (submode, (XEXP (x, 0))),
gen_realpart (submode, y)));
#else
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
- (gen_rtx (MEM, submode, (XEXP (x, 0))),
+ (gen_rtx_MEM (submode, (XEXP (x, 0))),
gen_realpart (submode, y)));
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
- (gen_rtx (MEM, submode, (XEXP (x, 0))),
+ (gen_rtx_MEM (submode, (XEXP (x, 0))),
gen_imagpart (submode, y)));
#endif
}
else
{
+ /* Show the output dies here. */
+ if (x != y)
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
+
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
(gen_realpart (submode, x), gen_realpart (submode, y)));
emit_insn (GEN_FCN (mov_optab->handlers[(int) submode].insn_code)
@@ -1974,7 +2522,6 @@ emit_move_insn_1 (x, y)
else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
{
rtx last_insn = 0;
- rtx insns;
#ifdef PUSH_ROUNDING
@@ -1988,7 +2535,8 @@ emit_move_insn_1 (x, y)
#endif
/* Show the output dies here. */
- emit_insn (gen_rtx (CLOBBER, VOIDmode, x));
+ if (x != y)
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, x));
for (i = 0;
i < (GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD;
@@ -2061,10 +2609,10 @@ push_block (size, extra, below)
temp = plus_constant (virtual_outgoing_args_rtx,
- INTVAL (size) - (below ? 0 : extra));
else if (extra != 0 && !below)
- temp = gen_rtx (PLUS, Pmode, virtual_outgoing_args_rtx,
+ temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
negate_rtx (Pmode, plus_constant (size, extra)));
else
- temp = gen_rtx (PLUS, Pmode, virtual_outgoing_args_rtx,
+ temp = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx,
negate_rtx (Pmode, size));
#endif
@@ -2074,7 +2622,26 @@ push_block (size, extra, below)
rtx
gen_push_operand ()
{
- return gen_rtx (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
+ return gen_rtx_fmt_e (STACK_PUSH_CODE, Pmode, stack_pointer_rtx);
+}
+
+/* Return an rtx for the address of the beginning of a as-if-it-was-pushed
+ block of SIZE bytes. */
+
+static rtx
+get_push_address (size)
+ int size;
+{
+ register rtx temp;
+
+ if (STACK_PUSH_CODE == POST_DEC)
+ temp = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (size));
+ else if (STACK_PUSH_CODE == POST_INC)
+ temp = gen_rtx_MINUS (Pmode, stack_pointer_rtx, GEN_INT (size));
+ else
+ temp = stack_pointer_rtx;
+
+ return copy_to_reg (temp);
}
/* Generate code to push X onto the stack, assuming it has mode MODE and
@@ -2103,11 +2670,15 @@ gen_push_operand ()
to store the arg. On machines with push insns, ARGS_ADDR is 0 when a
argument block has not been preallocated.
- ARGS_SO_FAR is the size of args previously pushed for this call. */
+ ARGS_SO_FAR is the size of args previously pushed for this call.
+
+ REG_PARM_STACK_SPACE is nonzero if functions require stack space
+ for arguments passed in registers. If nonzero, it will be the number
+ of bytes required. */
void
emit_push_insn (x, mode, type, size, align, partial, reg, extra,
- args_addr, args_so_far)
+ args_addr, args_so_far, reg_parm_stack_space)
register rtx x;
enum machine_mode mode;
tree type;
@@ -2118,6 +2689,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
int extra;
rtx args_addr;
rtx args_so_far;
+ int reg_parm_stack_space;
{
rtx xinner;
enum direction stack_direction
@@ -2164,11 +2736,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
skip the part of stack space corresponding to the registers.
Otherwise, start copying to the beginning of the stack space,
by setting SKIP to 0. */
-#ifndef REG_PARM_STACK_SPACE
- skip = 0;
-#else
- skip = used;
-#endif
+ skip = (reg_parm_stack_space == 0) ? 0 : used;
#ifdef PUSH_ROUNDING
/* Do it with several push insns if that doesn't take lots of insns
@@ -2194,8 +2762,30 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
&& where_pad != none && where_pad != stack_direction)
anti_adjust_stack (GEN_INT (extra));
- move_by_pieces (gen_rtx (MEM, BLKmode, gen_push_operand ()), xinner,
+ move_by_pieces (gen_rtx_MEM (BLKmode, gen_push_operand ()), xinner,
INTVAL (size) - used, align);
+
+ if (flag_check_memory_usage && ! in_check_memory_usage)
+ {
+ rtx temp;
+
+ in_check_memory_usage = 1;
+ temp = get_push_address (INTVAL(size) - used);
+ if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
+ emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
+ temp, ptr_mode,
+ XEXP (xinner, 0), ptr_mode,
+ GEN_INT (INTVAL(size) - used),
+ TYPE_MODE (sizetype));
+ else
+ emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ temp, ptr_mode,
+ GEN_INT (INTVAL(size) - used),
+ TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_RW),
+ TYPE_MODE (integer_type_node));
+ in_check_memory_usage = 0;
+ }
}
else
#endif /* PUSH_ROUNDING */
@@ -2228,76 +2818,87 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
skip + INTVAL (args_so_far)));
else
temp = memory_address (BLKmode,
- plus_constant (gen_rtx (PLUS, Pmode,
- args_addr, args_so_far),
+ plus_constant (gen_rtx_PLUS (Pmode,
+ args_addr,
+ args_so_far),
skip));
+ if (flag_check_memory_usage && ! in_check_memory_usage)
+ {
+ rtx target;
+
+ in_check_memory_usage = 1;
+ target = copy_to_reg (temp);
+ if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
+ emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
+ target, ptr_mode,
+ XEXP (xinner, 0), ptr_mode,
+ size, TYPE_MODE (sizetype));
+ else
+ emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ target, ptr_mode,
+ size, TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_RW),
+ TYPE_MODE (integer_type_node));
+ in_check_memory_usage = 0;
+ }
/* TEMP is the address of the block. Copy the data there. */
if (GET_CODE (size) == CONST_INT
&& (move_by_pieces_ninsns ((unsigned) INTVAL (size), align)
< MOVE_RATIO))
{
- move_by_pieces (gen_rtx (MEM, BLKmode, temp), xinner,
+ move_by_pieces (gen_rtx_MEM (BLKmode, temp), xinner,
INTVAL (size), align);
goto ret;
}
- /* Try the most limited insn first, because there's no point
- including more than one in the machine description unless
- the more limited one has some advantage. */
-#ifdef HAVE_movstrqi
- if (HAVE_movstrqi
- && GET_CODE (size) == CONST_INT
- && ((unsigned) INTVAL (size)
- < (1 << (GET_MODE_BITSIZE (QImode) - 1))))
- {
- rtx pat = gen_movstrqi (gen_rtx (MEM, BLKmode, temp),
- xinner, size, GEN_INT (align));
- if (pat != 0)
- {
- emit_insn (pat);
- goto ret;
- }
- }
-#endif
-#ifdef HAVE_movstrhi
- if (HAVE_movstrhi
- && GET_CODE (size) == CONST_INT
- && ((unsigned) INTVAL (size)
- < (1 << (GET_MODE_BITSIZE (HImode) - 1))))
- {
- rtx pat = gen_movstrhi (gen_rtx (MEM, BLKmode, temp),
- xinner, size, GEN_INT (align));
- if (pat != 0)
- {
- emit_insn (pat);
- goto ret;
- }
- }
-#endif
-#ifdef HAVE_movstrsi
- if (HAVE_movstrsi)
- {
- rtx pat = gen_movstrsi (gen_rtx (MEM, BLKmode, temp),
- xinner, size, GEN_INT (align));
- if (pat != 0)
- {
- emit_insn (pat);
- goto ret;
- }
- }
-#endif
-#ifdef HAVE_movstrdi
- if (HAVE_movstrdi)
+ else
{
- rtx pat = gen_movstrdi (gen_rtx (MEM, BLKmode, temp),
- xinner, size, GEN_INT (align));
- if (pat != 0)
+ rtx opalign = GEN_INT (align);
+ enum machine_mode mode;
+ rtx target = gen_rtx_MEM (BLKmode, temp);
+
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
{
- emit_insn (pat);
- goto ret;
+ enum insn_code code = movstr_optab[(int) mode];
+
+ if (code != CODE_FOR_nothing
+ && ((GET_CODE (size) == CONST_INT
+ && ((unsigned HOST_WIDE_INT) INTVAL (size)
+ <= (GET_MODE_MASK (mode) >> 1)))
+ || GET_MODE_BITSIZE (mode) >= BITS_PER_WORD)
+ && (insn_operand_predicate[(int) code][0] == 0
+ || ((*insn_operand_predicate[(int) code][0])
+ (target, BLKmode)))
+ && (insn_operand_predicate[(int) code][1] == 0
+ || ((*insn_operand_predicate[(int) code][1])
+ (xinner, BLKmode)))
+ && (insn_operand_predicate[(int) code][3] == 0
+ || ((*insn_operand_predicate[(int) code][3])
+ (opalign, VOIDmode))))
+ {
+ rtx op2 = convert_to_mode (mode, size, 1);
+ rtx last = get_last_insn ();
+ rtx pat;
+
+ if (insn_operand_predicate[(int) code][2] != 0
+ && ! ((*insn_operand_predicate[(int) code][2])
+ (op2, mode)))
+ op2 = copy_to_mode_reg (mode, op2);
+
+ pat = GEN_FCN ((int) code) (target, xinner,
+ op2, opalign);
+ if (pat)
+ {
+ emit_insn (pat);
+ goto ret;
+ }
+ else
+ delete_insns_since (last);
+ }
}
}
-#endif
#ifndef ACCUMULATE_OUTGOING_ARGS
/* If the source is referenced relative to the stack pointer,
@@ -2321,9 +2922,10 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
#else
emit_library_call (bcopy_libfunc, 0,
VOIDmode, 3, XEXP (xinner, 0), Pmode, temp, Pmode,
- convert_to_mode (TYPE_MODE (sizetype),
- size, TREE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
+ convert_to_mode (TYPE_MODE (integer_type_node),
+ size,
+ TREE_UNSIGNED (integer_type_node)),
+ TYPE_MODE (integer_type_node));
#endif
OK_DEFER_POP;
}
@@ -2362,11 +2964,7 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
skip the part of stack space corresponding to the registers.
Otherwise, start copying to the beginning of the stack space,
by setting SKIP to 0. */
-#ifndef REG_PARM_STACK_SPACE
- skip = 0;
-#else
- skip = not_stack;
-#endif
+ skip = (reg_parm_stack_space == 0) ? 0 : not_stack;
if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x))
x = validize_mem (force_const_mem (mode, x));
@@ -2390,11 +2988,13 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX,
0, args_addr,
GEN_INT (args_offset + ((i - not_stack + skip)
- * UNITS_PER_WORD)));
+ * UNITS_PER_WORD)),
+ reg_parm_stack_space);
}
else
{
rtx addr;
+ rtx target = NULL_RTX;
/* Push padding now if padding above and stack grows down,
or if padding below and stack grows up.
@@ -2408,15 +3008,41 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
addr = gen_push_operand ();
else
#endif
- if (GET_CODE (args_so_far) == CONST_INT)
- addr
- = memory_address (mode,
- plus_constant (args_addr, INTVAL (args_so_far)));
- else
- addr = memory_address (mode, gen_rtx (PLUS, Pmode, args_addr,
- args_so_far));
+ {
+ if (GET_CODE (args_so_far) == CONST_INT)
+ addr
+ = memory_address (mode,
+ plus_constant (args_addr,
+ INTVAL (args_so_far)));
+ else
+ addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
+ args_so_far));
+ target = addr;
+ }
- emit_move_insn (gen_rtx (MEM, mode, addr), x);
+ emit_move_insn (gen_rtx_MEM (mode, addr), x);
+
+ if (flag_check_memory_usage && ! in_check_memory_usage)
+ {
+ in_check_memory_usage = 1;
+ if (target == 0)
+ target = get_push_address (GET_MODE_SIZE (mode));
+
+ if (GET_CODE (x) == MEM && type && AGGREGATE_TYPE_P (type))
+ emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
+ target, ptr_mode,
+ XEXP (x, 0), ptr_mode,
+ GEN_INT (GET_MODE_SIZE (mode)),
+ TYPE_MODE (sizetype));
+ else
+ emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ target, ptr_mode,
+ GEN_INT (GET_MODE_SIZE (mode)),
+ TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_RW),
+ TYPE_MODE (integer_type_node));
+ in_check_memory_usage = 0;
+ }
}
ret:
@@ -2424,7 +3050,14 @@ emit_push_insn (x, mode, type, size, align, partial, reg, extra,
into the appropriate registers. Do this now, at the end,
since mem-to-mem copies above may do function calls. */
if (partial > 0 && reg != 0)
- move_block_to_reg (REGNO (reg), x, partial, mode);
+ {
+ /* Handle calls that pass values in multiple non-contiguous locations.
+ The Irix 6 ABI has examples of this. */
+ if (GET_CODE (reg) == PARALLEL)
+ emit_group_load (reg, x, -1, align); /* ??? size? */
+ else
+ move_block_to_reg (REGNO (reg), x, partial, mode);
+ }
if (extra && args_addr == 0 && where_pad == stack_direction)
anti_adjust_stack (GEN_INT (extra));
@@ -2458,34 +3091,14 @@ expand_assignment (to, from, want_value, suggest_reg)
return want_value ? result : NULL_RTX;
}
- if (output_bytecode)
- {
- tree dest_innermost;
-
- bc_expand_expr (from);
- bc_emit_instruction (duplicate);
-
- dest_innermost = bc_expand_address (to);
-
- /* Can't deduce from TYPE that we're dealing with a bitfield, so
- take care of it here. */
-
- bc_store_memory (TREE_TYPE (to), dest_innermost);
- return NULL;
- }
-
/* Assignment of a structure component needs special treatment
if the structure component's rtx is not simply a MEM.
Assignment of an array element at a constant index, and assignment of
an array element in an unaligned packed structure field, has the same
problem. */
- if (TREE_CODE (to) == COMPONENT_REF
- || TREE_CODE (to) == BIT_FIELD_REF
- || (TREE_CODE (to) == ARRAY_REF
- && ((TREE_CODE (TREE_OPERAND (to, 1)) == INTEGER_CST
- && TREE_CODE (TYPE_SIZE (TREE_TYPE (to))) == INTEGER_CST)
- || (SLOW_UNALIGNED_ACCESS && get_inner_unaligned_p (to)))))
+ if (TREE_CODE (to) == COMPONENT_REF || TREE_CODE (to) == BIT_FIELD_REF
+ || TREE_CODE (to) == ARRAY_REF)
{
enum machine_mode mode1;
int bitsize;
@@ -2497,8 +3110,8 @@ expand_assignment (to, from, want_value, suggest_reg)
int alignment;
push_temp_slots ();
- tem = get_inner_reference (to, &bitsize, &bitpos, &offset,
- &mode1, &unsignedp, &volatilep);
+ tem = get_inner_reference (to, &bitsize, &bitpos, &offset, &mode1,
+ &unsignedp, &volatilep, &alignment);
/* If we are going to use store_bit_field and extract_bit_field,
make sure to_rtx will be safe for multiple use. */
@@ -2506,25 +3119,46 @@ expand_assignment (to, from, want_value, suggest_reg)
if (mode1 == VOIDmode && want_value)
tem = stabilize_reference (tem);
- alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
- to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, 0);
+ to_rtx = expand_expr (tem, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_DONT);
if (offset != 0)
{
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
if (GET_CODE (to_rtx) != MEM)
abort ();
+
+ if (GET_MODE (offset_rtx) != ptr_mode)
+ {
+#ifdef POINTERS_EXTEND_UNSIGNED
+ offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
+#else
+ offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+#endif
+ }
+
+ if (GET_CODE (to_rtx) == MEM
+ && GET_MODE (to_rtx) == BLKmode
+ && bitsize
+ && (bitpos % bitsize) == 0
+ && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
+ && (alignment * BITS_PER_UNIT) == GET_MODE_ALIGNMENT (mode1))
+ {
+ rtx temp = change_address (to_rtx, mode1,
+ plus_constant (XEXP (to_rtx, 0),
+ (bitpos /
+ BITS_PER_UNIT)));
+ if (GET_CODE (XEXP (temp, 0)) == REG)
+ to_rtx = temp;
+ else
+ to_rtx = change_address (to_rtx, mode1,
+ force_reg (GET_MODE (XEXP (temp, 0)),
+ XEXP (temp, 0)));
+ bitpos = 0;
+ }
+
to_rtx = change_address (to_rtx, VOIDmode,
- gen_rtx (PLUS, ptr_mode, XEXP (to_rtx, 0),
- force_reg (ptr_mode, offset_rtx)));
- /* If we have a variable offset, the known alignment
- is only that of the innermost structure containing the field.
- (Actually, we could sometimes do better by using the
- align of an element of the innermost array, but no need.) */
- if (TREE_CODE (to) == COMPONENT_REF
- || TREE_CODE (to) == BIT_FIELD_REF)
- alignment
- = TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (to, 0))) / BITS_PER_UNIT;
+ gen_rtx_PLUS (ptr_mode, XEXP (to_rtx, 0),
+ force_reg (ptr_mode, offset_rtx)));
}
if (volatilep)
{
@@ -2534,7 +3168,8 @@ expand_assignment (to, from, want_value, suggest_reg)
structure we are storing into, and hence may be shared.
We must make a new MEM before setting the volatile bit. */
if (offset == 0)
- to_rtx = change_address (to_rtx, VOIDmode, XEXP (to_rtx, 0));
+ to_rtx = copy_rtx (to_rtx);
+
MEM_VOLATILE_P (to_rtx) = 1;
}
#if 0 /* This was turned off because, when a field is volatile
@@ -2545,6 +3180,43 @@ expand_assignment (to, from, want_value, suggest_reg)
#endif
}
+ if (TREE_CODE (to) == COMPONENT_REF
+ && TREE_READONLY (TREE_OPERAND (to, 1)))
+ {
+ if (offset == 0)
+ to_rtx = copy_rtx (to_rtx);
+
+ RTX_UNCHANGING_P (to_rtx) = 1;
+ }
+
+ /* Check the access. */
+ if (flag_check_memory_usage && GET_CODE (to_rtx) == MEM)
+ {
+ rtx to_addr;
+ int size;
+ int best_mode_size;
+ enum machine_mode best_mode;
+
+ best_mode = get_best_mode (bitsize, bitpos,
+ TYPE_ALIGN (TREE_TYPE (tem)),
+ mode1, volatilep);
+ if (best_mode == VOIDmode)
+ best_mode = QImode;
+
+ best_mode_size = GET_MODE_BITSIZE (best_mode);
+ to_addr = plus_constant (XEXP (to_rtx, 0), (bitpos / BITS_PER_UNIT));
+ size = CEIL ((bitpos % best_mode_size) + bitsize, best_mode_size);
+ size *= GET_MODE_SIZE (best_mode);
+
+ /* Check the access right of the pointer. */
+ if (size)
+ emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ to_addr, ptr_mode,
+ GEN_INT (size), TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_WO),
+ TYPE_MODE (integer_type_node));
+ }
+
result = store_field (to_rtx, bitsize, bitpos, mode1, from,
(want_value
/* Spurious cast makes HPUX compiler happy. */
@@ -2578,6 +3250,7 @@ expand_assignment (to, from, want_value, suggest_reg)
Handling this in the normal way is safe because no computation is done
before the call. */
if (TREE_CODE (from) == CALL_EXPR && ! aggregate_value_p (from)
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (from))) == INTEGER_CST
&& ! (TREE_CODE (to) == VAR_DECL && GET_CODE (DECL_RTL (to)) == REG))
{
rtx value;
@@ -2585,13 +3258,16 @@ expand_assignment (to, from, want_value, suggest_reg)
push_temp_slots ();
value = expand_expr (from, NULL_RTX, VOIDmode, 0);
if (to_rtx == 0)
- to_rtx = expand_expr (to, NULL_RTX, VOIDmode, 0);
-
- if (GET_MODE (to_rtx) == BLKmode)
- {
- int align = MIN (TYPE_ALIGN (TREE_TYPE (from)), BITS_PER_WORD);
- emit_block_move (to_rtx, value, expr_size (from), align);
- }
+ to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_WO);
+
+ /* Handle calls that return values in multiple non-contiguous locations.
+ The Irix 6 ABI has examples of this. */
+ if (GET_CODE (to_rtx) == PARALLEL)
+ emit_group_load (to_rtx, value, int_size_in_bytes (TREE_TYPE (from)),
+ TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
+ else if (GET_MODE (to_rtx) == BLKmode)
+ emit_block_move (to_rtx, value, expr_size (from),
+ TYPE_ALIGN (TREE_TYPE (from)) / BITS_PER_UNIT);
else
emit_move_insn (to_rtx, value);
preserve_temp_slots (to_rtx);
@@ -2604,7 +3280,11 @@ expand_assignment (to, from, want_value, suggest_reg)
Don't re-expand if it was expanded already (in COMPONENT_REF case). */
if (to_rtx == 0)
- to_rtx = expand_expr (to, NULL_RTX, VOIDmode, 0);
+ {
+ to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_WO);
+ if (GET_CODE (to_rtx) == MEM)
+ MEM_ALIAS_SET (to_rtx) = get_alias_set (to);
+ }
/* Don't move directly into a return register. */
if (TREE_CODE (to) == RESULT_DECL && GET_CODE (to_rtx) == REG)
@@ -2631,7 +3311,17 @@ expand_assignment (to, from, want_value, suggest_reg)
push_temp_slots ();
size = expr_size (from);
- from_rtx = expand_expr (from, NULL_RTX, VOIDmode, 0);
+ from_rtx = expand_expr (from, NULL_RTX, VOIDmode,
+ EXPAND_MEMORY_USE_DONT);
+
+ /* Copy the rights of the bitmap. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
+ XEXP (to_rtx, 0), ptr_mode,
+ XEXP (from_rtx, 0), ptr_mode,
+ convert_to_mode (TYPE_MODE (sizetype),
+ size, TREE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
#ifdef TARGET_MEM_FUNCTIONS
emit_library_call (memcpy_libfunc, 0,
@@ -2644,9 +3334,9 @@ expand_assignment (to, from, want_value, suggest_reg)
emit_library_call (bcopy_libfunc, 0,
VOIDmode, 3, XEXP (from_rtx, 0), Pmode,
XEXP (to_rtx, 0), Pmode,
- convert_to_mode (TYPE_MODE (sizetype),
- size, TREE_UNSIGNED (sizetype)),
- TYPE_MODE (sizetype));
+ convert_to_mode (TYPE_MODE (integer_type_node),
+ size, TREE_UNSIGNED (integer_type_node)),
+ TYPE_MODE (integer_type_node));
#endif
preserve_temp_slots (to_rtx);
@@ -2720,32 +3410,22 @@ store_expr (exp, target, want_value)
do_pending_stack_adjust ();
NO_DEFER_POP;
jumpifnot (TREE_OPERAND (exp, 0), lab1);
+ start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 1), target, 0);
+ end_cleanup_deferral ();
emit_queue ();
emit_jump_insn (gen_jump (lab2));
emit_barrier ();
emit_label (lab1);
+ start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 2), target, 0);
+ end_cleanup_deferral ();
emit_queue ();
emit_label (lab2);
OK_DEFER_POP;
+
return want_value ? target : NULL_RTX;
}
- else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
- && GET_MODE (target) != BLKmode)
- /* If target is in memory and caller wants value in a register instead,
- arrange that. Pass TARGET as target for expand_expr so that,
- if EXP is another assignment, WANT_VALUE will be nonzero for it.
- We know expand_expr will not use the target in that case.
- Don't do this if TARGET is volatile because we are supposed
- to write it and then read it. */
- {
- temp = expand_expr (exp, cse_not_expected ? NULL_RTX : target,
- GET_MODE (target), 0);
- if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
- temp = copy_to_reg (temp);
- dont_return_target = 1;
- }
else if (queued_subexp_p (target))
/* If target contains a postincrement, let's not risk
using it as the place to generate the rhs. */
@@ -2765,6 +3445,21 @@ store_expr (exp, target, want_value)
if (! MEM_VOLATILE_P (target) && want_value)
dont_return_target = 1;
}
+ else if (want_value && GET_CODE (target) == MEM && ! MEM_VOLATILE_P (target)
+ && GET_MODE (target) != BLKmode)
+ /* If target is in memory and caller wants value in a register instead,
+ arrange that. Pass TARGET as target for expand_expr so that,
+ if EXP is another assignment, WANT_VALUE will be nonzero for it.
+ We know expand_expr will not use the target in that case.
+ Don't do this if TARGET is volatile because we are supposed
+ to write it and then read it. */
+ {
+ temp = expand_expr (exp, cse_not_expected ? NULL_RTX : target,
+ GET_MODE (target), 0);
+ if (GET_MODE (temp) != BLKmode && GET_MODE (temp) != VOIDmode)
+ temp = copy_to_reg (temp);
+ dont_return_target = 1;
+ }
else if (GET_CODE (target) == SUBREG && SUBREG_PROMOTED_VAR_P (target))
/* If this is an scalar in a register that is stored in a wider mode
than the declared mode, compute the result into its declared mode
@@ -2774,8 +3469,11 @@ store_expr (exp, target, want_value)
/* If we don't want a value, we can do the conversion inside EXP,
which will often result in some optimizations. Do the conversion
in two steps: first change the signedness, if needed, then
- the extend. */
- if (! want_value)
+ the extend. But don't do this if the type of EXP is a subtype
+ of something else since then the conversion might involve
+ more than just converting modes. */
+ if (! want_value && INTEGRAL_TYPE_P (TREE_TYPE (exp))
+ && TREE_TYPE (TREE_TYPE (exp)) == 0)
{
if (TREE_UNSIGNED (TREE_TYPE (exp))
!= SUBREG_PROMOTED_UNSIGNED_P (target))
@@ -2824,7 +3522,7 @@ store_expr (exp, target, want_value)
if (!(target && GET_CODE (target) == REG
&& REGNO (target) < FIRST_PSEUDO_REGISTER)
&& !(GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
- && temp != target
+ && ! rtx_equal_p (temp, target)
&& (CONSTANT_P (temp) || want_value))
dont_return_target = 1;
}
@@ -2839,10 +3537,41 @@ store_expr (exp, target, want_value)
temp = convert_modes (GET_MODE (target), TYPE_MODE (TREE_TYPE (exp)),
temp, TREE_UNSIGNED (TREE_TYPE (exp)));
+ if (flag_check_memory_usage
+ && GET_CODE (target) == MEM
+ && AGGREGATE_TYPE_P (TREE_TYPE (exp)))
+ {
+ if (GET_CODE (temp) == MEM)
+ emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
+ XEXP (target, 0), ptr_mode,
+ XEXP (temp, 0), ptr_mode,
+ expr_size (exp), TYPE_MODE (sizetype));
+ else
+ emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ XEXP (target, 0), ptr_mode,
+ expr_size (exp), TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_WO),
+ TYPE_MODE (integer_type_node));
+ }
+
/* If value was not generated in the target, store it there.
Convert the value to TARGET's type first if nec. */
-
- if (temp != target && TREE_CODE (exp) != ERROR_MARK)
+ /* If TEMP and TARGET compare equal according to rtx_equal_p, but
+ one or both of them are volatile memory refs, we have to distinguish
+ two cases:
+ - expand_expr has used TARGET. In this case, we must not generate
+ another copy. This can be detected by TARGET being equal according
+ to == .
+ - expand_expr has not used TARGET - that means that the source just
+ happens to have the same RTX form. Since temp will have been created
+ by expand_expr, it will compare unequal according to == .
+ We must generate a copy in this case, to reach the correct number
+ of volatile memory references. */
+
+ if ((! rtx_equal_p (temp, target)
+ || (temp != target && (side_effects_p (temp)
+ || side_effects_p (target))))
+ && TREE_CODE (exp) != ERROR_MARK)
{
target = protect_from_queue (target, 1);
if (GET_MODE (temp) != GET_MODE (target)
@@ -2922,12 +3651,28 @@ store_expr (exp, target, want_value)
if (size != const0_rtx)
{
+ /* Be sure we can write on ADDR. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ addr, ptr_mode,
+ size, TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_WO),
+ TYPE_MODE (integer_type_node));
#ifdef TARGET_MEM_FUNCTIONS
- emit_library_call (memset_libfunc, 0, VOIDmode, 3, addr,
- Pmode, const0_rtx, Pmode, size, ptr_mode);
+ emit_library_call (memset_libfunc, 0, VOIDmode, 3,
+ addr, ptr_mode,
+ const0_rtx, TYPE_MODE (integer_type_node),
+ convert_to_mode (TYPE_MODE (sizetype),
+ size,
+ TREE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
#else
emit_library_call (bzero_libfunc, 0, VOIDmode, 2,
- addr, Pmode, size, ptr_mode);
+ addr, ptr_mode,
+ convert_to_mode (TYPE_MODE (integer_type_node),
+ size,
+ TREE_UNSIGNED (integer_type_node)),
+ TYPE_MODE (integer_type_node));
#endif
}
@@ -2935,6 +3680,11 @@ store_expr (exp, target, want_value)
emit_label (label);
}
}
+ /* Handle calls that return values in multiple non-contiguous locations.
+ The Irix 6 ABI has examples of this. */
+ else if (GET_CODE (target) == PARALLEL)
+ emit_group_load (target, temp, int_size_in_bytes (TREE_TYPE (exp)),
+ TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
else if (GET_MODE (temp) == BLKmode)
emit_block_move (target, temp, expr_size (exp),
TYPE_ALIGN (TREE_TYPE (exp)) / BITS_PER_UNIT);
@@ -2961,13 +3711,125 @@ store_expr (exp, target, want_value)
return target;
}
+/* Return 1 if EXP just contains zeros. */
+
+static int
+is_zeros_p (exp)
+ tree exp;
+{
+ tree elt;
+
+ switch (TREE_CODE (exp))
+ {
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ case NON_LVALUE_EXPR:
+ return is_zeros_p (TREE_OPERAND (exp, 0));
+
+ case INTEGER_CST:
+ return TREE_INT_CST_LOW (exp) == 0 && TREE_INT_CST_HIGH (exp) == 0;
+
+ case COMPLEX_CST:
+ return
+ is_zeros_p (TREE_REALPART (exp)) && is_zeros_p (TREE_IMAGPART (exp));
+
+ case REAL_CST:
+ return REAL_VALUES_IDENTICAL (TREE_REAL_CST (exp), dconst0);
+
+ case CONSTRUCTOR:
+ if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
+ return CONSTRUCTOR_ELTS (exp) == NULL_TREE;
+ for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
+ if (! is_zeros_p (TREE_VALUE (elt)))
+ return 0;
+
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Return 1 if EXP contains mostly (3/4) zeros. */
+
+static int
+mostly_zeros_p (exp)
+ tree exp;
+{
+ if (TREE_CODE (exp) == CONSTRUCTOR)
+ {
+ int elts = 0, zeros = 0;
+ tree elt = CONSTRUCTOR_ELTS (exp);
+ if (TREE_TYPE (exp) && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
+ {
+ /* If there are no ranges of true bits, it is all zero. */
+ return elt == NULL_TREE;
+ }
+ for (; elt; elt = TREE_CHAIN (elt))
+ {
+ /* We do not handle the case where the index is a RANGE_EXPR,
+ so the statistic will be somewhat inaccurate.
+ We do make a more accurate count in store_constructor itself,
+ so since this function is only used for nested array elements,
+ this should be close enough. */
+ if (mostly_zeros_p (TREE_VALUE (elt)))
+ zeros++;
+ elts++;
+ }
+
+ return 4 * zeros >= 3 * elts;
+ }
+
+ return is_zeros_p (exp);
+}
+
+/* Helper function for store_constructor.
+ TARGET, BITSIZE, BITPOS, MODE, EXP are as for store_field.
+ TYPE is the type of the CONSTRUCTOR, not the element type.
+ CLEARED is as for store_constructor.
+
+ This provides a recursive shortcut back to store_constructor when it isn't
+ necessary to go through store_field. This is so that we can pass through
+ the cleared field to let store_constructor know that we may not have to
+ clear a substructure if the outer structure has already been cleared. */
+
+static void
+store_constructor_field (target, bitsize, bitpos,
+ mode, exp, type, cleared)
+ rtx target;
+ int bitsize, bitpos;
+ enum machine_mode mode;
+ tree exp, type;
+ int cleared;
+{
+ if (TREE_CODE (exp) == CONSTRUCTOR
+ && bitpos % BITS_PER_UNIT == 0
+ /* If we have a non-zero bitpos for a register target, then we just
+ let store_field do the bitfield handling. This is unlikely to
+ generate unnecessary clear instructions anyways. */
+ && (bitpos == 0 || GET_CODE (target) == MEM))
+ {
+ if (bitpos != 0)
+ target = change_address (target, VOIDmode,
+ plus_constant (XEXP (target, 0),
+ bitpos / BITS_PER_UNIT));
+ store_constructor (exp, target, cleared);
+ }
+ else
+ store_field (target, bitsize, bitpos, mode, exp,
+ VOIDmode, 0, TYPE_ALIGN (type) / BITS_PER_UNIT,
+ int_size_in_bytes (type));
+}
+
/* Store the value of constructor EXP into the rtx TARGET.
- TARGET is either a REG or a MEM. */
+ TARGET is either a REG or a MEM.
+ CLEARED is true if TARGET is known to have been zero'd. */
static void
-store_constructor (exp, target)
+store_constructor (exp, target, cleared)
tree exp;
rtx target;
+ int cleared;
{
tree type = TREE_TYPE (exp);
@@ -2979,7 +3841,7 @@ store_constructor (exp, target)
if (GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)
{
rtx temp = gen_reg_rtx (GET_MODE (target));
- store_constructor (exp, temp);
+ store_constructor (exp, temp, 0);
emit_move_insn (target, temp);
return;
}
@@ -2993,7 +3855,7 @@ store_constructor (exp, target)
/* Inform later passes that the whole union value is dead. */
if (TREE_CODE (type) == UNION_TYPE
|| TREE_CODE (type) == QUAL_UNION_TYPE)
- emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
/* If we are building a static constructor into a register,
set the initial value as zero so we can fold the value into
@@ -3001,16 +3863,29 @@ store_constructor (exp, target)
this probably loses. */
else if (GET_CODE (target) == REG && TREE_STATIC (exp)
&& GET_MODE_SIZE (GET_MODE (target)) <= UNITS_PER_WORD)
- emit_move_insn (target, const0_rtx);
+ {
+ if (! cleared)
+ emit_move_insn (target, CONST0_RTX (GET_MODE (target)));
+
+ cleared = 1;
+ }
- /* If the constructor has fewer fields than the structure,
+ /* If the constructor has fewer fields than the structure
+ or if we are initializing the structure to mostly zeros,
clear the whole structure first. */
- else if (list_length (CONSTRUCTOR_ELTS (exp))
- != list_length (TYPE_FIELDS (type)))
- clear_storage (target, expr_size (exp));
+ else if ((list_length (CONSTRUCTOR_ELTS (exp))
+ != list_length (TYPE_FIELDS (type)))
+ || mostly_zeros_p (exp))
+ {
+ if (! cleared)
+ clear_storage (target, expr_size (exp),
+ TYPE_ALIGN (type) / BITS_PER_UNIT);
+
+ cleared = 1;
+ }
else
/* Inform later passes that the old value is dead. */
- emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
/* Store each element of the constructor into
the corresponding field of TARGET. */
@@ -3031,6 +3906,9 @@ store_constructor (exp, target)
if (field == 0)
continue;
+ if (cleared && is_zeros_p (TREE_VALUE (elt)))
+ continue;
+
bitsize = TREE_INT_CST_LOW (DECL_SIZE (field));
unsignedp = TREE_UNSIGNED (field);
mode = DECL_MODE (field);
@@ -3055,7 +3933,7 @@ store_constructor (exp, target)
if (contains_placeholder_p (offset))
offset = build (WITH_RECORD_EXPR, sizetype,
- offset, exp);
+ offset, make_tree (TREE_TYPE (exp), target));
offset = size_binop (FLOOR_DIV_EXPR, offset,
size_int (BITS_PER_UNIT));
@@ -3064,39 +3942,95 @@ store_constructor (exp, target)
if (GET_CODE (to_rtx) != MEM)
abort ();
+ if (GET_MODE (offset_rtx) != ptr_mode)
+ {
+#ifdef POINTERS_EXTEND_UNSIGNED
+ offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
+#else
+ offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+#endif
+ }
+
to_rtx
= change_address (to_rtx, VOIDmode,
- gen_rtx (PLUS, ptr_mode, XEXP (to_rtx, 0),
+ gen_rtx_PLUS (ptr_mode, XEXP (to_rtx, 0),
force_reg (ptr_mode, offset_rtx)));
}
+ if (TREE_READONLY (field))
+ {
+ if (GET_CODE (to_rtx) == MEM)
+ to_rtx = copy_rtx (to_rtx);
+
+ RTX_UNCHANGING_P (to_rtx) = 1;
+ }
- store_field (to_rtx, bitsize, bitpos, mode, TREE_VALUE (elt),
- /* The alignment of TARGET is
- at least what its type requires. */
- VOIDmode, 0,
- TYPE_ALIGN (type) / BITS_PER_UNIT,
- int_size_in_bytes (type));
+ store_constructor_field (to_rtx, bitsize, bitpos,
+ mode, TREE_VALUE (elt), type, cleared);
}
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
register tree elt;
register int i;
+ int need_to_clear;
tree domain = TYPE_DOMAIN (type);
HOST_WIDE_INT minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
HOST_WIDE_INT maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
tree elttype = TREE_TYPE (type);
- /* If the constructor has fewer fields than the structure,
- clear the whole structure first. Similarly if this this is
- static constructor of a non-BLKmode object. */
-
- if (list_length (CONSTRUCTOR_ELTS (exp)) < maxelt - minelt + 1
- || (GET_CODE (target) == REG && TREE_STATIC (exp)))
- clear_storage (target, expr_size (exp));
+ /* If the constructor has fewer elements than the array,
+ clear the whole array first. Similarly if this is
+ static constructor of a non-BLKmode object. */
+ if (cleared || (GET_CODE (target) == REG && TREE_STATIC (exp)))
+ need_to_clear = 1;
+ else
+ {
+ HOST_WIDE_INT count = 0, zero_count = 0;
+ need_to_clear = 0;
+ /* This loop is a more accurate version of the loop in
+ mostly_zeros_p (it handles RANGE_EXPR in an index).
+ It is also needed to check for missing elements. */
+ for (elt = CONSTRUCTOR_ELTS (exp);
+ elt != NULL_TREE;
+ elt = TREE_CHAIN (elt))
+ {
+ tree index = TREE_PURPOSE (elt);
+ HOST_WIDE_INT this_node_count;
+ if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
+ {
+ tree lo_index = TREE_OPERAND (index, 0);
+ tree hi_index = TREE_OPERAND (index, 1);
+ if (TREE_CODE (lo_index) != INTEGER_CST
+ || TREE_CODE (hi_index) != INTEGER_CST)
+ {
+ need_to_clear = 1;
+ break;
+ }
+ this_node_count = TREE_INT_CST_LOW (hi_index)
+ - TREE_INT_CST_LOW (lo_index) + 1;
+ }
+ else
+ this_node_count = 1;
+ count += this_node_count;
+ if (mostly_zeros_p (TREE_VALUE (elt)))
+ zero_count += this_node_count;
+ }
+ /* Clear the entire array first if there are any missing elements,
+ or if the incidence of zero elements is >= 75%. */
+ if (count < maxelt - minelt + 1
+ || 4 * zero_count >= 3 * count)
+ need_to_clear = 1;
+ }
+ if (need_to_clear)
+ {
+ if (! cleared)
+ clear_storage (target, expr_size (exp),
+ TYPE_ALIGN (type) / BITS_PER_UNIT);
+ cleared = 1;
+ }
else
/* Inform later passes that the old value is dead. */
- emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
/* Store each element of the constructor into
the corresponding element of TARGET, determined
@@ -3109,29 +4043,121 @@ store_constructor (exp, target)
int bitsize;
int bitpos;
int unsignedp;
+ tree value = TREE_VALUE (elt);
tree index = TREE_PURPOSE (elt);
rtx xtarget = target;
+ if (cleared && is_zeros_p (value))
+ continue;
+
mode = TYPE_MODE (elttype);
bitsize = GET_MODE_BITSIZE (mode);
unsignedp = TREE_UNSIGNED (elttype);
- if ((index != 0 && TREE_CODE (index) != INTEGER_CST)
+ if (index != NULL_TREE && TREE_CODE (index) == RANGE_EXPR)
+ {
+ tree lo_index = TREE_OPERAND (index, 0);
+ tree hi_index = TREE_OPERAND (index, 1);
+ rtx index_r, pos_rtx, addr, hi_r, loop_top, loop_end;
+ struct nesting *loop;
+ HOST_WIDE_INT lo, hi, count;
+ tree position;
+
+ /* If the range is constant and "small", unroll the loop. */
+ if (TREE_CODE (lo_index) == INTEGER_CST
+ && TREE_CODE (hi_index) == INTEGER_CST
+ && (lo = TREE_INT_CST_LOW (lo_index),
+ hi = TREE_INT_CST_LOW (hi_index),
+ count = hi - lo + 1,
+ (GET_CODE (target) != MEM
+ || count <= 2
+ || (TREE_CODE (TYPE_SIZE (elttype)) == INTEGER_CST
+ && TREE_INT_CST_LOW (TYPE_SIZE (elttype)) * count
+ <= 40 * 8))))
+ {
+ lo -= minelt; hi -= minelt;
+ for (; lo <= hi; lo++)
+ {
+ bitpos = lo * TREE_INT_CST_LOW (TYPE_SIZE (elttype));
+ store_constructor_field (target, bitsize, bitpos,
+ mode, value, type, cleared);
+ }
+ }
+ else
+ {
+ hi_r = expand_expr (hi_index, NULL_RTX, VOIDmode, 0);
+ loop_top = gen_label_rtx ();
+ loop_end = gen_label_rtx ();
+
+ unsignedp = TREE_UNSIGNED (domain);
+
+ index = build_decl (VAR_DECL, NULL_TREE, domain);
+
+ DECL_RTL (index) = index_r
+ = gen_reg_rtx (promote_mode (domain, DECL_MODE (index),
+ &unsignedp, 0));
+
+ if (TREE_CODE (value) == SAVE_EXPR
+ && SAVE_EXPR_RTL (value) == 0)
+ {
+ /* Make sure value gets expanded once before the
+ loop. */
+ expand_expr (value, const0_rtx, VOIDmode, 0);
+ emit_queue ();
+ }
+ store_expr (lo_index, index_r, 0);
+ loop = expand_start_loop (0);
+
+ /* Assign value to element index. */
+ position = size_binop (EXACT_DIV_EXPR, TYPE_SIZE (elttype),
+ size_int (BITS_PER_UNIT));
+ position = size_binop (MULT_EXPR,
+ size_binop (MINUS_EXPR, index,
+ TYPE_MIN_VALUE (domain)),
+ position);
+ pos_rtx = expand_expr (position, 0, VOIDmode, 0);
+ addr = gen_rtx_PLUS (Pmode, XEXP (target, 0), pos_rtx);
+ xtarget = change_address (target, mode, addr);
+ if (TREE_CODE (value) == CONSTRUCTOR)
+ store_constructor (value, xtarget, cleared);
+ else
+ store_expr (value, xtarget, 0);
+
+ expand_exit_loop_if_false (loop,
+ build (LT_EXPR, integer_type_node,
+ index, hi_index));
+
+ expand_increment (build (PREINCREMENT_EXPR,
+ TREE_TYPE (index),
+ index, integer_one_node), 0, 0);
+ expand_end_loop ();
+ emit_label (loop_end);
+
+ /* Needed by stupid register allocation. to extend the
+ lifetime of pseudo-regs used by target past the end
+ of the loop. */
+ emit_insn (gen_rtx_USE (GET_MODE (target), target));
+ }
+ }
+ else if ((index != 0 && TREE_CODE (index) != INTEGER_CST)
|| TREE_CODE (TYPE_SIZE (elttype)) != INTEGER_CST)
{
- rtx pos_rtx, addr, xtarget;
+ rtx pos_rtx, addr;
tree position;
if (index == 0)
index = size_int (i);
+ if (minelt)
+ index = size_binop (MINUS_EXPR, index,
+ TYPE_MIN_VALUE (domain));
position = size_binop (EXACT_DIV_EXPR, TYPE_SIZE (elttype),
size_int (BITS_PER_UNIT));
position = size_binop (MULT_EXPR, index, position);
pos_rtx = expand_expr (position, 0, VOIDmode, 0);
- addr = gen_rtx (PLUS, Pmode, XEXP (target, 0), pos_rtx);
+ addr = gen_rtx_PLUS (Pmode, XEXP (target, 0), pos_rtx);
xtarget = change_address (target, mode, addr);
- store_expr (TREE_VALUE (elt), xtarget, 0);
+ store_expr (value, xtarget, 0);
}
else
{
@@ -3140,25 +4166,16 @@ store_constructor (exp, target)
* TREE_INT_CST_LOW (TYPE_SIZE (elttype)));
else
bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype)));
-
- store_field (xtarget, bitsize, bitpos, mode, TREE_VALUE (elt),
- /* The alignment of TARGET is
- at least what its type requires. */
- VOIDmode, 0,
- TYPE_ALIGN (type) / BITS_PER_UNIT,
- int_size_in_bytes (type));
+ store_constructor_field (target, bitsize, bitpos,
+ mode, value, type, cleared);
}
}
}
/* set constructor assignments */
else if (TREE_CODE (type) == SET_TYPE)
{
- tree elt;
- rtx xtarget = XEXP (target, 0);
- int set_word_size = TYPE_ALIGN (type);
- int nbytes = int_size_in_bytes (type);
- tree non_const_elements;
- int need_to_clear_first;
+ tree elt = CONSTRUCTOR_ELTS (exp);
+ int nbytes = int_size_in_bytes (type), nbits;
tree domain = TYPE_DOMAIN (type);
tree domain_min, domain_max, bitlength;
@@ -3170,44 +4187,41 @@ store_constructor (exp, target)
probably better to set it using memset (if available) or bzero.
Also, if a large set has just a single range, it may also be
better to first clear all the first clear the set (using
- bzero/memset), and set the bits we want. */
+ bzero/memset), and set the bits we want. */
- /* Check for all zeros. */
- if (CONSTRUCTOR_ELTS (exp) == NULL_TREE)
+ /* Check for all zeros. */
+ if (elt == NULL_TREE)
{
- clear_storage (target, expr_size (exp));
+ if (!cleared)
+ clear_storage (target, expr_size (exp),
+ TYPE_ALIGN (type) / BITS_PER_UNIT);
return;
}
- if (nbytes < 0)
- abort ();
-
domain_min = convert (sizetype, TYPE_MIN_VALUE (domain));
domain_max = convert (sizetype, TYPE_MAX_VALUE (domain));
bitlength = size_binop (PLUS_EXPR,
size_binop (MINUS_EXPR, domain_max, domain_min),
size_one_node);
- /* Check for range all ones, or at most a single range.
- (This optimization is only a win for big sets.) */
- if (GET_MODE (target) == BLKmode && nbytes > 16
- && TREE_CHAIN (CONSTRUCTOR_ELTS (exp)) == NULL_TREE)
- {
- need_to_clear_first = 1;
- non_const_elements = CONSTRUCTOR_ELTS (exp);
- }
- else
+ if (nbytes < 0 || TREE_CODE (bitlength) != INTEGER_CST)
+ abort ();
+ nbits = TREE_INT_CST_LOW (bitlength);
+
+ /* For "small" sets, or "medium-sized" (up to 32 bytes) sets that
+ are "complicated" (more than one range), initialize (the
+ constant parts) by copying from a constant. */
+ if (GET_MODE (target) != BLKmode || nbits <= 2 * BITS_PER_WORD
+ || (nbytes <= 32 && TREE_CHAIN (elt) != NULL_TREE))
{
- int nbits = nbytes * BITS_PER_UNIT;
int set_word_size = TYPE_ALIGN (TREE_TYPE (exp));
enum machine_mode mode = mode_for_size (set_word_size, MODE_INT, 1);
- char *bit_buffer = (char*) alloca (nbits);
+ char *bit_buffer = (char *) alloca (nbits);
HOST_WIDE_INT word = 0;
int bit_pos = 0;
int ibit = 0;
- int offset = 0; /* In bytes from beginning of set. */
- non_const_elements = get_set_constructor_bits (exp,
- bit_buffer, nbits);
+ int offset = 0; /* In bytes from beginning of set. */
+ elt = get_set_constructor_bits (exp, bit_buffer, nbits);
for (;;)
{
if (bit_buffer[ibit])
@@ -3220,19 +4234,24 @@ store_constructor (exp, target)
bit_pos++; ibit++;
if (bit_pos >= set_word_size || ibit == nbits)
{
- rtx datum = GEN_INT (word);
- rtx to_rtx;
- /* The assumption here is that it is safe to use XEXP if
- the set is multi-word, but not if it's single-word. */
- if (GET_CODE (target) == MEM)
- to_rtx = change_address (target, mode,
- plus_constant (XEXP (target, 0),
- offset));
- else if (offset == 0)
- to_rtx = target;
- else
- abort ();
- emit_move_insn (to_rtx, datum);
+ if (word != 0 || ! cleared)
+ {
+ rtx datum = GEN_INT (word);
+ rtx to_rtx;
+ /* The assumption here is that it is safe to use
+ XEXP if the set is multi-word, but not if
+ it's single-word. */
+ if (GET_CODE (target) == MEM)
+ {
+ to_rtx = plus_constant (XEXP (target, 0), offset);
+ to_rtx = change_address (target, mode, to_rtx);
+ }
+ else if (offset == 0)
+ to_rtx = target;
+ else
+ abort ();
+ emit_move_insn (to_rtx, datum);
+ }
if (ibit == nbits)
break;
word = 0;
@@ -3240,16 +4259,31 @@ store_constructor (exp, target)
offset += set_word_size / BITS_PER_UNIT;
}
}
- need_to_clear_first = 0;
}
-
- for (elt = non_const_elements; elt != NULL_TREE; elt = TREE_CHAIN (elt))
+ else if (!cleared)
+ {
+ /* Don't bother clearing storage if the set is all ones. */
+ if (TREE_CHAIN (elt) != NULL_TREE
+ || (TREE_PURPOSE (elt) == NULL_TREE
+ ? nbits != 1
+ : (TREE_CODE (TREE_VALUE (elt)) != INTEGER_CST
+ || TREE_CODE (TREE_PURPOSE (elt)) != INTEGER_CST
+ || (TREE_INT_CST_LOW (TREE_VALUE (elt))
+ - TREE_INT_CST_LOW (TREE_PURPOSE (elt)) + 1
+ != nbits))))
+ clear_storage (target, expr_size (exp),
+ TYPE_ALIGN (type) / BITS_PER_UNIT);
+ }
+
+ for (; elt != NULL_TREE; elt = TREE_CHAIN (elt))
{
/* start of range of element or NULL */
tree startbit = TREE_PURPOSE (elt);
/* end of range of element, or element value */
tree endbit = TREE_VALUE (elt);
+#ifdef TARGET_MEM_FUNCTIONS
HOST_WIDE_INT startb, endb;
+#endif
rtx bitlength_rtx, startbit_rtx, endbit_rtx, targetx;
bitlength_rtx = expand_expr (bitlength,
@@ -3288,34 +4322,25 @@ store_constructor (exp, target)
#ifdef TARGET_MEM_FUNCTIONS
/* Optimization: If startbit and endbit are
constants divisible by BITS_PER_UNIT,
- call memset instead. */
+ call memset instead. */
if (TREE_CODE (startbit) == INTEGER_CST
&& TREE_CODE (endbit) == INTEGER_CST
&& (startb = TREE_INT_CST_LOW (startbit)) % BITS_PER_UNIT == 0
- && (endb = TREE_INT_CST_LOW (endbit)) % BITS_PER_UNIT == 0)
+ && (endb = TREE_INT_CST_LOW (endbit) + 1) % BITS_PER_UNIT == 0)
{
-
- if (need_to_clear_first
- && endb - startb != nbytes * BITS_PER_UNIT)
- clear_storage (target, expr_size (exp));
- need_to_clear_first = 0;
emit_library_call (memset_libfunc, 0,
VOIDmode, 3,
- plus_constant (XEXP (targetx, 0), startb),
+ plus_constant (XEXP (targetx, 0),
+ startb / BITS_PER_UNIT),
Pmode,
- constm1_rtx, Pmode,
+ constm1_rtx, TYPE_MODE (integer_type_node),
GEN_INT ((endb - startb) / BITS_PER_UNIT),
- Pmode);
+ TYPE_MODE (sizetype));
}
else
#endif
{
- if (need_to_clear_first)
- {
- clear_storage (target, expr_size (exp));
- need_to_clear_first = 0;
- }
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__setbits"),
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__setbits"),
0, VOIDmode, 4, XEXP (targetx, 0), Pmode,
bitlength_rtx, TYPE_MODE (sizetype),
startbit_rtx, TYPE_MODE (sizetype),
@@ -3359,6 +4384,9 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
{
HOST_WIDE_INT width_mask = 0;
+ if (TREE_CODE (exp) == ERROR_MARK)
+ return const0_rtx;
+
if (bitsize < HOST_BITS_PER_WIDE_INT)
width_mask = ((HOST_WIDE_INT) 1 << bitsize) - 1;
@@ -3413,12 +4441,45 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
{
rtx temp = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+ /* If BITSIZE is narrower than the size of the type of EXP
+ we will be narrowing TEMP. Normally, what's wanted are the
+ low-order bits. However, if EXP's type is a record and this is
+ big-endian machine, we want the upper BITSIZE bits. */
+ if (BYTES_BIG_ENDIAN && GET_MODE_CLASS (GET_MODE (temp)) == MODE_INT
+ && bitsize < GET_MODE_BITSIZE (GET_MODE (temp))
+ && TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
+ temp = expand_shift (RSHIFT_EXPR, GET_MODE (temp), temp,
+ size_int (GET_MODE_BITSIZE (GET_MODE (temp))
+ - bitsize),
+ temp, 1);
+
/* Unless MODE is VOIDmode or BLKmode, convert TEMP to
MODE. */
if (mode != VOIDmode && mode != BLKmode
&& mode != TYPE_MODE (TREE_TYPE (exp)))
temp = convert_modes (mode, TYPE_MODE (TREE_TYPE (exp)), temp, 1);
+ /* If the modes of TARGET and TEMP are both BLKmode, both
+ must be in memory and BITPOS must be aligned on a byte
+ boundary. If so, we simply do a block copy. */
+ if (GET_MODE (target) == BLKmode && GET_MODE (temp) == BLKmode)
+ {
+ if (GET_CODE (target) != MEM || GET_CODE (temp) != MEM
+ || bitpos % BITS_PER_UNIT != 0)
+ abort ();
+
+ target = change_address (target, VOIDmode,
+ plus_constant (XEXP (target, 0),
+ bitpos / BITS_PER_UNIT));
+
+ emit_block_move (target, temp,
+ GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+ / BITS_PER_UNIT),
+ 1);
+
+ return value_mode == VOIDmode ? const0_rtx : target;
+ }
+
/* Store the value in the bitfield. */
store_bit_field (target, bitsize, bitpos, mode, temp, align, total_size);
if (value_mode != VOIDmode)
@@ -3465,45 +4526,16 @@ store_field (target, bitsize, bitpos, mode, exp, value_mode,
/* Now build a reference to just the desired component. */
- to_rtx = change_address (target, mode,
- plus_constant (addr, (bitpos / BITS_PER_UNIT)));
+ to_rtx = copy_rtx (change_address (target, mode,
+ plus_constant (addr,
+ (bitpos
+ / BITS_PER_UNIT))));
MEM_IN_STRUCT_P (to_rtx) = 1;
return store_expr (exp, to_rtx, value_mode != VOIDmode);
}
}
-/* Return true if any object containing the innermost array is an unaligned
- packed structure field. */
-
-static int
-get_inner_unaligned_p (exp)
- tree exp;
-{
- int needed_alignment = TYPE_ALIGN (TREE_TYPE (exp));
-
- while (1)
- {
- if (TREE_CODE (exp) == COMPONENT_REF || TREE_CODE (exp) == BIT_FIELD_REF)
- {
- if (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
- < needed_alignment)
- return 1;
- }
- else if (TREE_CODE (exp) != ARRAY_REF
- && TREE_CODE (exp) != NON_LVALUE_EXPR
- && ! ((TREE_CODE (exp) == NOP_EXPR
- || TREE_CODE (exp) == CONVERT_EXPR)
- && (TYPE_MODE (TREE_TYPE (exp))
- == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))))
- break;
-
- exp = TREE_OPERAND (exp, 0);
- }
-
- return 0;
-}
-
/* Given an expression EXP that may be a COMPONENT_REF, a BIT_FIELD_REF,
or an ARRAY_REF, look for nested COMPONENT_REFs, BIT_FIELD_REFs, or
ARRAY_REFs and find the ultimate containing object, which we return.
@@ -3514,6 +4546,9 @@ get_inner_unaligned_p (exp)
giving the variable offset (in units) in *POFFSET.
This offset is in addition to the bit position.
If the position is not variable, we store 0 in *POFFSET.
+ We set *PALIGNMENT to the alignment in bytes of the address that will be
+ computed. This is the alignment of the thing we return if *POFFSET
+ is zero, but can be more less strictly aligned if *POFFSET is nonzero.
If any of the extraction expressions is volatile,
we store 1 in *PVOLATILEP. Otherwise we don't change that.
@@ -3524,11 +4559,11 @@ get_inner_unaligned_p (exp)
If the field describes a variable-sized object, *PMODE is set to
VOIDmode and *PBITSIZE is set to -1. An access cannot be made in
- this case, but the address of the object can be found. */
+ this case, but the address of the object can be found. */
tree
get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
- punsignedp, pvolatilep)
+ punsignedp, pvolatilep, palignment)
tree exp;
int *pbitsize;
int *pbitpos;
@@ -3536,11 +4571,13 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
enum machine_mode *pmode;
int *punsignedp;
int *pvolatilep;
+ int *palignment;
{
tree orig_exp = exp;
tree size_tree = 0;
enum machine_mode mode = VOIDmode;
tree offset = integer_zero_node;
+ int alignment = BIGGEST_ALIGNMENT;
if (TREE_CODE (exp) == COMPONENT_REF)
{
@@ -3598,11 +4635,9 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
constant = pos, var = integer_zero_node;
*pbitpos += TREE_INT_CST_LOW (constant);
-
- if (var)
- offset = size_binop (PLUS_EXPR, offset,
- size_binop (EXACT_DIV_EXPR, var,
- size_int (BITS_PER_UNIT)));
+ offset = size_binop (PLUS_EXPR, offset,
+ size_binop (EXACT_DIV_EXPR, var,
+ size_int (BITS_PER_UNIT)));
}
else if (TREE_CODE (exp) == ARRAY_REF)
@@ -3616,9 +4651,7 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
tree low_bound
= domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
tree index_type = TREE_TYPE (index);
-
- if (! integer_zerop (low_bound))
- index = fold (build (MINUS_EXPR, index_type, index, low_bound));
+ tree xindex;
if (TYPE_PRECISION (index_type) != TYPE_PRECISION (sizetype))
{
@@ -3627,16 +4660,37 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
index_type = TREE_TYPE (index);
}
- index = fold (build (MULT_EXPR, index_type, index,
- TYPE_SIZE (TREE_TYPE (exp))));
+ if (! integer_zerop (low_bound))
+ index = fold (build (MINUS_EXPR, index_type, index, low_bound));
+
+ if (TREE_CODE (index) == INTEGER_CST)
+ {
+ index = convert (sbitsizetype, index);
+ index_type = TREE_TYPE (index);
+ }
- if (TREE_CODE (index) == INTEGER_CST
- && TREE_INT_CST_HIGH (index) == 0)
- *pbitpos += TREE_INT_CST_LOW (index);
+ xindex = fold (build (MULT_EXPR, sbitsizetype, index,
+ convert (sbitsizetype,
+ TYPE_SIZE (TREE_TYPE (exp)))));
+
+ if (TREE_CODE (xindex) == INTEGER_CST
+ && TREE_INT_CST_HIGH (xindex) == 0)
+ *pbitpos += TREE_INT_CST_LOW (xindex);
else
- offset = size_binop (PLUS_EXPR, offset,
- size_binop (FLOOR_DIV_EXPR, index,
- size_int (BITS_PER_UNIT)));
+ {
+ /* Either the bit offset calculated above is not constant, or
+ it overflowed. In either case, redo the multiplication
+ against the size in units. This is especially important
+ in the non-constant case to avoid a division at runtime. */
+ xindex = fold (build (MULT_EXPR, ssizetype, index,
+ convert (ssizetype,
+ TYPE_SIZE_UNIT (TREE_TYPE (exp)))));
+
+ if (contains_placeholder_p (xindex))
+ xindex = build (WITH_RECORD_EXPR, sizetype, xindex, exp);
+
+ offset = size_binop (PLUS_EXPR, offset, xindex);
+ }
}
else if (TREE_CODE (exp) != NON_LVALUE_EXPR
&& ! ((TREE_CODE (exp) == NOP_EXPR
@@ -3651,17 +4705,19 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
/* If any reference in the chain is volatile, the effect is volatile. */
if (TREE_THIS_VOLATILE (exp))
*pvolatilep = 1;
+
+ /* If the offset is non-constant already, then we can't assume any
+ alignment more than the alignment here. */
+ if (! integer_zerop (offset))
+ alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
+
exp = TREE_OPERAND (exp, 0);
}
- /* If this was a bit-field, see if there is a mode that allows direct
- access in case EXP is in memory. */
- if (mode == VOIDmode && *pbitsize != 0 && *pbitpos % *pbitsize == 0)
- {
- mode = mode_for_size (*pbitsize, MODE_INT, 0);
- if (mode == BLKmode)
- mode = VOIDmode;
- }
+ if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'd')
+ alignment = MIN (alignment, DECL_ALIGN (exp));
+ else if (TREE_TYPE (exp) != 0)
+ alignment = MIN (alignment, TYPE_ALIGN (TREE_TYPE (exp)));
if (integer_zerop (offset))
offset = 0;
@@ -3671,8 +4727,39 @@ get_inner_reference (exp, pbitsize, pbitpos, poffset, pmode,
*pmode = mode;
*poffset = offset;
+ *palignment = alignment / BITS_PER_UNIT;
return exp;
}
+
+/* Subroutine of expand_exp: compute memory_usage from modifier. */
+static enum memory_use_mode
+get_memory_usage_from_modifier (modifier)
+ enum expand_modifier modifier;
+{
+ switch (modifier)
+ {
+ case EXPAND_NORMAL:
+ case EXPAND_SUM:
+ return MEMORY_USE_RO;
+ break;
+ case EXPAND_MEMORY_USE_WO:
+ return MEMORY_USE_WO;
+ break;
+ case EXPAND_MEMORY_USE_RW:
+ return MEMORY_USE_RW;
+ break;
+ case EXPAND_MEMORY_USE_DONT:
+ /* EXPAND_CONST_ADDRESS and EXPAND_INITIALIZER are converted into
+ MEMORY_USE_DONT, because they are modifiers to a call of
+ expand_expr in the ADDR_EXPR case of expand_expr. */
+ case EXPAND_CONST_ADDRESS:
+ case EXPAND_INITIALIZER:
+ return MEMORY_USE_DONT;
+ case EXPAND_MEMORY_USE_BAD:
+ default:
+ abort ();
+ }
+}
/* Given an rtx VALUE that may contain additions and multiplications,
return an equivalent value that just refers to a register or memory.
@@ -3693,6 +4780,20 @@ force_operand (value, target)
/* Use subtarget as the target for operand 0 of a binary operation. */
register rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
+ /* Check for a PIC address load. */
+ if (flag_pic
+ && (GET_CODE (value) == PLUS || GET_CODE (value) == MINUS)
+ && XEXP (value, 0) == pic_offset_table_rtx
+ && (GET_CODE (XEXP (value, 1)) == SYMBOL_REF
+ || GET_CODE (XEXP (value, 1)) == LABEL_REF
+ || GET_CODE (XEXP (value, 1)) == CONST))
+ {
+ if (!subtarget)
+ subtarget = gen_reg_rtx (GET_MODE (value));
+ emit_move_insn (subtarget, value);
+ return subtarget;
+ }
+
if (GET_CODE (value) == PLUS)
binoptab = add_optab;
else if (GET_CODE (value) == MINUS)
@@ -3772,9 +4873,7 @@ save_noncopied_parts (lhs, list)
tree part = TREE_VALUE (tail);
tree part_type = TREE_TYPE (part);
tree to_be_saved = build (COMPONENT_REF, part_type, lhs, part);
- rtx target = assign_stack_temp (TYPE_MODE (part_type),
- int_size_in_bytes (part_type), 0);
- MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (part_type);
+ rtx target = assign_temp (part_type, 0, 1, 1);
if (! memory_address_p (TYPE_MODE (part_type), XEXP (target, 0)))
target = change_address (target, TYPE_MODE (part_type), NULL_RTX);
parts = tree_cons (to_be_saved,
@@ -3812,27 +4911,64 @@ init_noncopied_parts (lhs, list)
}
/* Subroutine of expand_expr: return nonzero iff there is no way that
- EXP can reference X, which is being modified. */
+ EXP can reference X, which is being modified. TOP_P is nonzero if this
+ call is going to be used to determine whether we need a temporary
+ for EXP, as opposed to a recursive call to this function.
+
+ It is always safe for this routine to return zero since it merely
+ searches for optimization opportunities. */
static int
-safe_from_p (x, exp)
+safe_from_p (x, exp, top_p)
rtx x;
tree exp;
+ int top_p;
{
rtx exp_rtl = 0;
int i, nops;
+ static int save_expr_count;
+ static int save_expr_size = 0;
+ static tree *save_expr_rewritten;
+ static tree save_expr_trees[256];
if (x == 0
/* If EXP has varying size, we MUST use a target since we currently
- have no way of allocating temporaries of variable size. So we
- assume here that something at a higher level has prevented a
+ have no way of allocating temporaries of variable size
+ (except for arrays that have TYPE_ARRAY_MAX_SIZE set).
+ So we assume here that something at a higher level has prevented a
clash. This is somewhat bogus, but the best we can do. Only
- do this when X is BLKmode. */
- || (TREE_TYPE (exp) != 0 && TYPE_SIZE (TREE_TYPE (exp)) != 0
+ do this when X is BLKmode and when we are at the top level. */
+ || (top_p && TREE_TYPE (exp) != 0 && TYPE_SIZE (TREE_TYPE (exp)) != 0
&& TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST
+ && (TREE_CODE (TREE_TYPE (exp)) != ARRAY_TYPE
+ || TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)) == NULL_TREE
+ || TREE_CODE (TYPE_ARRAY_MAX_SIZE (TREE_TYPE (exp)))
+ != INTEGER_CST)
&& GET_MODE (x) == BLKmode))
return 1;
+ if (top_p && save_expr_size == 0)
+ {
+ int rtn;
+
+ save_expr_count = 0;
+ save_expr_size = sizeof (save_expr_trees) / sizeof (save_expr_trees[0]);
+ save_expr_rewritten = &save_expr_trees[0];
+
+ rtn = safe_from_p (x, exp, 1);
+
+ for (i = 0; i < save_expr_count; ++i)
+ {
+ if (TREE_CODE (save_expr_trees[i]) != ERROR_MARK)
+ abort ();
+ TREE_SET_CODE (save_expr_trees[i], SAVE_EXPR);
+ }
+
+ save_expr_size = 0;
+
+ return rtn;
+ }
+
/* If this is a subreg of a hard register, declare it unsafe, otherwise,
find the underlying pseudo. */
if (GET_CODE (x) == SUBREG)
@@ -3861,19 +4997,21 @@ safe_from_p (x, exp)
case 'x':
if (TREE_CODE (exp) == TREE_LIST)
return ((TREE_VALUE (exp) == 0
- || safe_from_p (x, TREE_VALUE (exp)))
+ || safe_from_p (x, TREE_VALUE (exp), 0))
&& (TREE_CHAIN (exp) == 0
- || safe_from_p (x, TREE_CHAIN (exp))));
+ || safe_from_p (x, TREE_CHAIN (exp), 0)));
+ else if (TREE_CODE (exp) == ERROR_MARK)
+ return 1; /* An already-visited SAVE_EXPR? */
else
return 0;
case '1':
- return safe_from_p (x, TREE_OPERAND (exp, 0));
+ return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
case '2':
case '<':
- return (safe_from_p (x, TREE_OPERAND (exp, 0))
- && safe_from_p (x, TREE_OPERAND (exp, 1)));
+ return (safe_from_p (x, TREE_OPERAND (exp, 0), 0)
+ && safe_from_p (x, TREE_OPERAND (exp, 1), 0));
case 'e':
case 'r':
@@ -3886,7 +5024,8 @@ safe_from_p (x, exp)
{
case ADDR_EXPR:
return (staticp (TREE_OPERAND (exp, 0))
- || safe_from_p (x, TREE_OPERAND (exp, 0)));
+ || safe_from_p (x, TREE_OPERAND (exp, 0), 0)
+ || TREE_STATIC (exp));
case INDIRECT_REF:
if (GET_CODE (x) == MEM)
@@ -3921,20 +5060,51 @@ safe_from_p (x, exp)
break;
case CLEANUP_POINT_EXPR:
- return safe_from_p (x, TREE_OPERAND (exp, 0));
+ return safe_from_p (x, TREE_OPERAND (exp, 0), 0);
case SAVE_EXPR:
exp_rtl = SAVE_EXPR_RTL (exp);
- break;
+ if (exp_rtl)
+ break;
+
+ /* This SAVE_EXPR might appear many times in the top-level
+ safe_from_p() expression, and if it has a complex
+ subexpression, examining it multiple times could result
+ in a combinatorial explosion. E.g. on an Alpha
+ running at least 200MHz, a Fortran test case compiled with
+ optimization took about 28 minutes to compile -- even though
+ it was only a few lines long, and the complicated line causing
+ so much time to be spent in the earlier version of safe_from_p()
+ had only 293 or so unique nodes.
+
+ So, turn this SAVE_EXPR into an ERROR_MARK for now, but remember
+ where it is so we can turn it back in the top-level safe_from_p()
+ when we're done. */
+
+ /* For now, don't bother re-sizing the array. */
+ if (save_expr_count >= save_expr_size)
+ return 0;
+ save_expr_rewritten[save_expr_count++] = exp;
+ TREE_SET_CODE (exp, ERROR_MARK);
+
+ nops = tree_code_length[(int) SAVE_EXPR];
+ for (i = 0; i < nops; i++)
+ if (TREE_OPERAND (exp, i) != 0
+ && ! safe_from_p (x, TREE_OPERAND (exp, i), 0))
+ return 0;
+ return 1;
case BIND_EXPR:
/* The only operand we look at is operand 1. The rest aren't
part of the expression. */
- return safe_from_p (x, TREE_OPERAND (exp, 1));
+ return safe_from_p (x, TREE_OPERAND (exp, 1), 0);
case METHOD_CALL_EXPR:
- /* This takes a rtx argument, but shouldn't appear here. */
+ /* This takes a rtx argument, but shouldn't appear here. */
abort ();
+
+ default:
+ break;
}
/* If we have an rtx, we do not need to scan our operands. */
@@ -3944,7 +5114,7 @@ safe_from_p (x, exp)
nops = tree_code_length[(int) TREE_CODE (exp)];
for (i = 0; i < nops; i++)
if (TREE_OPERAND (exp, i) != 0
- && ! safe_from_p (x, TREE_OPERAND (exp, i)))
+ && ! safe_from_p (x, TREE_OPERAND (exp, i), 0))
return 0;
}
@@ -3986,6 +5156,70 @@ fixed_type_p (exp)
return 1;
return 0;
}
+
+/* Subroutine of expand_expr: return rtx if EXP is a
+ variable or parameter; else return 0. */
+
+static rtx
+var_rtx (exp)
+ tree exp;
+{
+ STRIP_NOPS (exp);
+ switch (TREE_CODE (exp))
+ {
+ case PARM_DECL:
+ case VAR_DECL:
+ return DECL_RTL (exp);
+ default:
+ return 0;
+ }
+}
+
+#ifdef MAX_INTEGER_COMPUTATION_MODE
+void
+check_max_integer_computation_mode (exp)
+ tree exp;
+{
+ enum tree_code code = TREE_CODE (exp);
+ enum machine_mode mode;
+
+ /* First check the type of the overall operation. We need only look at
+ unary, binary and relational operations. */
+ if (TREE_CODE_CLASS (code) == '1'
+ || TREE_CODE_CLASS (code) == '2'
+ || TREE_CODE_CLASS (code) == '<')
+ {
+ mode = TYPE_MODE (TREE_TYPE (exp));
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && mode > MAX_INTEGER_COMPUTATION_MODE)
+ fatal ("unsupported wide integer operation");
+ }
+
+ /* Check operand of a unary op. */
+ if (TREE_CODE_CLASS (code) == '1')
+ {
+ mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && mode > MAX_INTEGER_COMPUTATION_MODE)
+ fatal ("unsupported wide integer operation");
+ }
+
+ /* Check operands of a binary/comparison op. */
+ if (TREE_CODE_CLASS (code) == '2' || TREE_CODE_CLASS (code) == '<')
+ {
+ mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && mode > MAX_INTEGER_COMPUTATION_MODE)
+ fatal ("unsupported wide integer operation");
+
+ mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 1)));
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && mode > MAX_INTEGER_COMPUTATION_MODE)
+ fatal ("unsupported wide integer operation");
+ }
+}
+#endif
+
/* expand_expr: generate code for computing expression EXP.
An rtx for the computed value is returned. The value is never null.
@@ -4041,20 +5275,21 @@ expand_expr (exp, target, tmode, modifier)
/* Use subtarget as the target for operand 0 of a binary operation. */
rtx subtarget = (target != 0 && GET_CODE (target) == REG ? target : 0);
rtx original_target = target;
- /* Maybe defer this until sure not doing bytecode? */
int ignore = (target == const0_rtx
|| ((code == NON_LVALUE_EXPR || code == NOP_EXPR
|| code == CONVERT_EXPR || code == REFERENCE_EXPR
|| code == COND_EXPR)
&& TREE_CODE (type) == VOID_TYPE));
tree context;
+ /* Used by check-memory-usage to make modifier read only. */
+ enum expand_modifier ro_modifier;
-
- if (output_bytecode && modifier != EXPAND_INITIALIZER)
- {
- bc_expand_expr (exp);
- return NULL;
- }
+ /* Make a read-only version of the modifier. */
+ if (modifier == EXPAND_NORMAL || modifier == EXPAND_SUM
+ || modifier == EXPAND_CONST_ADDRESS || modifier == EXPAND_INITIALIZER)
+ ro_modifier = modifier;
+ else
+ ro_modifier = EXPAND_NORMAL;
/* Don't use hard regs as subtargets, because the combiner
can only handle pseudo regs. */
@@ -4081,7 +5316,7 @@ expand_expr (exp, target, tmode, modifier)
&& TREE_CODE (exp) != FUNCTION_DECL
&& mode != VOIDmode && mode != BLKmode)
{
- temp = expand_expr (exp, NULL_RTX, VOIDmode, modifier);
+ temp = expand_expr (exp, NULL_RTX, VOIDmode, ro_modifier);
if (GET_CODE (temp) == MEM)
temp = copy_to_reg (temp);
return const0_rtx;
@@ -4089,24 +5324,41 @@ expand_expr (exp, target, tmode, modifier)
if (TREE_CODE_CLASS (code) == '1')
return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
- VOIDmode, modifier);
+ VOIDmode, ro_modifier);
else if (TREE_CODE_CLASS (code) == '2'
|| TREE_CODE_CLASS (code) == '<')
{
- expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, modifier);
- expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, modifier);
+ expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, ro_modifier);
+ expand_expr (TREE_OPERAND (exp, 1), const0_rtx, VOIDmode, ro_modifier);
return const0_rtx;
}
else if ((code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
&& ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 1)))
/* If the second operand has no side effects, just evaluate
- the first. */
+ the first. */
return expand_expr (TREE_OPERAND (exp, 0), const0_rtx,
- VOIDmode, modifier);
+ VOIDmode, ro_modifier);
target = 0;
}
+#ifdef MAX_INTEGER_COMPUTATION_MODE
+ if (target)
+ {
+ enum machine_mode mode = GET_MODE (target);
+
+ if (GET_MODE_CLASS (mode) == MODE_INT
+ && mode > MAX_INTEGER_COMPUTATION_MODE)
+ fatal ("unsupported wide integer operation");
+ }
+
+ if (GET_MODE_CLASS (tmode) == MODE_INT
+ && tmode > MAX_INTEGER_COMPUTATION_MODE)
+ fatal ("unsupported wide integer operation");
+
+ check_max_integer_computation_mode (exp);
+#endif
+
/* If will do cse, generate all results into pseudo registers
since 1) that allows cse to find more things
and 2) otherwise cse could produce an insn the machine
@@ -4122,7 +5374,8 @@ expand_expr (exp, target, tmode, modifier)
{
tree function = decl_function_context (exp);
/* Handle using a label in a containing function. */
- if (function != current_function_decl && function != 0)
+ if (function != current_function_decl
+ && function != inline_function_decl && function != 0)
{
struct function *p = find_function_data (function);
/* Allocate in the memory associated with the function
@@ -4130,16 +5383,18 @@ expand_expr (exp, target, tmode, modifier)
push_obstacks (p->function_obstack,
p->function_maybepermanent_obstack);
- p->forced_labels = gen_rtx (EXPR_LIST, VOIDmode,
- label_rtx (exp), p->forced_labels);
+ p->forced_labels = gen_rtx_EXPR_LIST (VOIDmode,
+ label_rtx (exp),
+ p->forced_labels);
pop_obstacks ();
}
else if (modifier == EXPAND_INITIALIZER)
- forced_labels = gen_rtx (EXPR_LIST, VOIDmode,
- label_rtx (exp), forced_labels);
- temp = gen_rtx (MEM, FUNCTION_MODE,
- gen_rtx (LABEL_REF, Pmode, label_rtx (exp)));
- if (function != current_function_decl && function != 0)
+ forced_labels = gen_rtx_EXPR_LIST (VOIDmode,
+ label_rtx (exp), forced_labels);
+ temp = gen_rtx_MEM (FUNCTION_MODE,
+ gen_rtx_LABEL_REF (Pmode, label_rtx (exp)));
+ if (function != current_function_decl
+ && function != inline_function_decl && function != 0)
LABEL_REF_NONLOCAL_P (XEXP (temp, 0)) = 1;
return temp;
}
@@ -4151,7 +5406,7 @@ expand_expr (exp, target, tmode, modifier)
return CONST0_RTX (mode);
}
- /* ... fall through ... */
+ /* ... fall through ... */
case VAR_DECL:
/* If a static var's type was incomplete when the decl was written,
@@ -4166,7 +5421,28 @@ expand_expr (exp, target, tmode, modifier)
pop_obstacks ();
}
- /* ... fall through ... */
+ /* Only check automatic variables. Currently, function arguments are
+ not checked (this can be done at compile-time with prototypes).
+ Aggregates are not checked. */
+ if (flag_check_memory_usage && code == VAR_DECL
+ && GET_CODE (DECL_RTL (exp)) == MEM
+ && DECL_CONTEXT (exp) != NULL_TREE
+ && ! TREE_STATIC (exp)
+ && ! AGGREGATE_TYPE_P (TREE_TYPE (exp)))
+ {
+ enum memory_use_mode memory_usage;
+ memory_usage = get_memory_usage_from_modifier (modifier);
+
+ if (memory_usage != MEMORY_USE_DONT)
+ emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ XEXP (DECL_RTL (exp), 0), ptr_mode,
+ GEN_INT (int_size_in_bytes (type)),
+ TYPE_MODE (sizetype),
+ GEN_INT (memory_usage),
+ TYPE_MODE (integer_type_node));
+ }
+
+ /* ... fall through ... */
case FUNCTION_DECL:
case RESULT_DECL:
@@ -4182,6 +5458,9 @@ expand_expr (exp, target, tmode, modifier)
TREE_USED (exp) = 1;
}
+ /* Show we haven't gotten RTL for this yet. */
+ temp = 0;
+
/* Handle variables inherited from containing functions. */
context = decl_function_context (exp);
@@ -4200,41 +5479,55 @@ expand_expr (exp, target, tmode, modifier)
/* Mark as non-local and addressable. */
DECL_NONLOCAL (exp) = 1;
+ if (DECL_NO_STATIC_CHAIN (current_function_decl))
+ abort ();
mark_addressable (exp);
if (GET_CODE (DECL_RTL (exp)) != MEM)
abort ();
addr = XEXP (DECL_RTL (exp), 0);
if (GET_CODE (addr) == MEM)
- addr = gen_rtx (MEM, Pmode,
- fix_lexical_addr (XEXP (addr, 0), exp));
+ addr = gen_rtx_MEM (Pmode,
+ fix_lexical_addr (XEXP (addr, 0), exp));
else
addr = fix_lexical_addr (addr, exp);
- return change_address (DECL_RTL (exp), mode, addr);
+ temp = change_address (DECL_RTL (exp), mode, addr);
}
/* This is the case of an array whose size is to be determined
from its initializer, while the initializer is still being parsed.
See expand_decl. */
- if (GET_CODE (DECL_RTL (exp)) == MEM
- && GET_CODE (XEXP (DECL_RTL (exp), 0)) == REG)
- return change_address (DECL_RTL (exp), GET_MODE (DECL_RTL (exp)),
+ else if (GET_CODE (DECL_RTL (exp)) == MEM
+ && GET_CODE (XEXP (DECL_RTL (exp), 0)) == REG)
+ temp = change_address (DECL_RTL (exp), GET_MODE (DECL_RTL (exp)),
XEXP (DECL_RTL (exp), 0));
/* If DECL_RTL is memory, we are in the normal case and either
the address is not valid or it is not a register and -fforce-addr
is specified, get the address into a register. */
- if (GET_CODE (DECL_RTL (exp)) == MEM
- && modifier != EXPAND_CONST_ADDRESS
- && modifier != EXPAND_SUM
- && modifier != EXPAND_INITIALIZER
- && (! memory_address_p (DECL_MODE (exp), XEXP (DECL_RTL (exp), 0))
- || (flag_force_addr
- && GET_CODE (XEXP (DECL_RTL (exp), 0)) != REG)))
- return change_address (DECL_RTL (exp), VOIDmode,
+ else if (GET_CODE (DECL_RTL (exp)) == MEM
+ && modifier != EXPAND_CONST_ADDRESS
+ && modifier != EXPAND_SUM
+ && modifier != EXPAND_INITIALIZER
+ && (! memory_address_p (DECL_MODE (exp),
+ XEXP (DECL_RTL (exp), 0))
+ || (flag_force_addr
+ && GET_CODE (XEXP (DECL_RTL (exp), 0)) != REG)))
+ temp = change_address (DECL_RTL (exp), VOIDmode,
copy_rtx (XEXP (DECL_RTL (exp), 0)));
+ /* If we got something, return it. But first, set the alignment
+ the address is a register. */
+ if (temp != 0)
+ {
+ if (GET_CODE (temp) == MEM && GET_CODE (XEXP (temp, 0)) == REG)
+ mark_reg_pointer (XEXP (temp, 0),
+ DECL_ALIGN (exp) / BITS_PER_UNIT);
+
+ return temp;
+ }
+
/* If the mode of DECL_RTL does not match that of the decl, it
must be a promoted value. We return a SUBREG of the wanted mode,
but mark it so that we know that it was already extended. */
@@ -4248,7 +5541,7 @@ expand_expr (exp, target, tmode, modifier)
!= promote_mode (type, DECL_MODE (exp), &unsignedp, 0))
abort ();
- temp = gen_rtx (SUBREG, mode, DECL_RTL (exp), 0);
+ temp = gen_rtx_SUBREG (mode, DECL_RTL (exp), 0);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
return temp;
@@ -4262,7 +5555,8 @@ expand_expr (exp, target, tmode, modifier)
mode);
case CONST_DECL:
- return expand_expr (DECL_INITIAL (exp), target, VOIDmode, 0);
+ return expand_expr (DECL_INITIAL (exp), target, VOIDmode,
+ EXPAND_MEMORY_USE_BAD);
case REAL_CST:
/* If optimized, generate immediate CONST_DOUBLE
@@ -4296,9 +5590,30 @@ expand_expr (exp, target, tmode, modifier)
copy_rtx (XEXP (TREE_CST_RTL (exp), 0)));
return TREE_CST_RTL (exp);
+ case EXPR_WITH_FILE_LOCATION:
+ {
+ rtx to_return;
+ char *saved_input_filename = input_filename;
+ int saved_lineno = lineno;
+ input_filename = EXPR_WFL_FILENAME (exp);
+ lineno = EXPR_WFL_LINENO (exp);
+ if (EXPR_WFL_EMIT_LINE_NOTE (exp))
+ emit_line_note (input_filename, lineno);
+ /* Possibly avoid switching back and force here */
+ to_return = expand_expr (EXPR_WFL_NODE (exp), target, tmode, modifier);
+ input_filename = saved_input_filename;
+ lineno = saved_lineno;
+ return to_return;
+ }
+
case SAVE_EXPR:
context = decl_function_context (exp);
+ /* If this SAVE_EXPR was at global context, assume we are an
+ initialization function and move it into our context. */
+ if (context == 0)
+ SAVE_EXPR_CONTEXT (exp) = current_function_decl;
+
/* We treat inline_function_decl as an alias for the current function
because that is the inline function whose vars, types, etc.
are being merged into the current function.
@@ -4309,6 +5624,10 @@ expand_expr (exp, target, tmode, modifier)
/* If this is non-local, handle it. */
if (context)
{
+ /* The following call just exists to abort if the context is
+ not of a containing function. */
+ find_function_data (context);
+
temp = SAVE_EXPR_RTL (exp);
if (temp && GET_CODE (temp) == REG)
{
@@ -4322,21 +5641,15 @@ expand_expr (exp, target, tmode, modifier)
}
if (SAVE_EXPR_RTL (exp) == 0)
{
- if (mode == BLKmode)
- {
- temp
- = assign_stack_temp (mode, int_size_in_bytes (type), 0);
- MEM_IN_STRUCT_P (temp) = AGGREGATE_TYPE_P (type);
- }
- else if (mode == VOIDmode)
+ if (mode == VOIDmode)
temp = const0_rtx;
else
- temp = gen_reg_rtx (promote_mode (type, mode, &unsignedp, 0));
+ temp = assign_temp (type, 3, 0, 0);
SAVE_EXPR_RTL (exp) = temp;
if (!optimize && GET_CODE (temp) == REG)
- save_expr_regs = gen_rtx (EXPR_LIST, VOIDmode, temp,
- save_expr_regs);
+ save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, temp,
+ save_expr_regs);
/* If the mode of TEMP does not match that of the expression, it
must be a promoted value. We pass store_expr a SUBREG of the
@@ -4346,27 +5659,30 @@ expand_expr (exp, target, tmode, modifier)
if (GET_CODE (temp) == REG && GET_MODE (temp) != mode)
{
- temp = gen_rtx (SUBREG, mode, SAVE_EXPR_RTL (exp), 0);
+ temp = gen_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
}
if (temp == const0_rtx)
- expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
+ expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
+ EXPAND_MEMORY_USE_BAD);
else
store_expr (TREE_OPERAND (exp, 0), temp, 0);
+
+ TREE_USED (exp) = 1;
}
/* If the mode of SAVE_EXPR_RTL does not match that of the expression, it
must be a promoted value. We return a SUBREG of the wanted mode,
- but mark it so that we know that it was already extended. */
+ but mark it so that we know that it was already extended. */
if (GET_CODE (SAVE_EXPR_RTL (exp)) == REG
&& GET_MODE (SAVE_EXPR_RTL (exp)) != mode)
{
/* Compute the signedness and make the proper SUBREG. */
promote_mode (type, mode, &unsignedp, 0);
- temp = gen_rtx (SUBREG, mode, SAVE_EXPR_RTL (exp), 0);
+ temp = gen_rtx_SUBREG (mode, SAVE_EXPR_RTL (exp), 0);
SUBREG_PROMOTED_VAR_P (temp) = 1;
SUBREG_PROMOTED_UNSIGNED_P (temp) = unsignedp;
return temp;
@@ -4374,39 +5690,77 @@ expand_expr (exp, target, tmode, modifier)
return SAVE_EXPR_RTL (exp);
+ case UNSAVE_EXPR:
+ {
+ rtx temp;
+ temp = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
+ TREE_OPERAND (exp, 0) = unsave_expr_now (TREE_OPERAND (exp, 0));
+ return temp;
+ }
+
case PLACEHOLDER_EXPR:
- /* If there is an object on the head of the placeholder list,
- see if some object in it's references is of type TYPE. For
- further information, see tree.def. */
- if (placeholder_list)
- {
- tree object;
- tree old_list = placeholder_list;
-
- for (object = TREE_PURPOSE (placeholder_list);
- (TYPE_MAIN_VARIANT (TREE_TYPE (object))
- != TYPE_MAIN_VARIANT (type))
- && (TREE_CODE_CLASS (TREE_CODE (object)) == 'r'
- || TREE_CODE_CLASS (TREE_CODE (object)) == '1'
- || TREE_CODE_CLASS (TREE_CODE (object)) == '2'
- || TREE_CODE_CLASS (TREE_CODE (object)) == 'e');
- object = TREE_OPERAND (object, 0))
- ;
-
- if (object != 0
- && (TYPE_MAIN_VARIANT (TREE_TYPE (object))
- == TYPE_MAIN_VARIANT (type)))
- {
- /* Expand this object skipping the list entries before
- it was found in case it is also a PLACEHOLDER_EXPR.
- In that case, we want to translate it using subsequent
- entries. */
- placeholder_list = TREE_CHAIN (placeholder_list);
- temp = expand_expr (object, original_target, tmode, modifier);
- placeholder_list = old_list;
- return temp;
- }
- }
+ {
+ tree placeholder_expr;
+
+ /* If there is an object on the head of the placeholder list,
+ see if some object in it of type TYPE or a pointer to it. For
+ further information, see tree.def. */
+ for (placeholder_expr = placeholder_list;
+ placeholder_expr != 0;
+ placeholder_expr = TREE_CHAIN (placeholder_expr))
+ {
+ tree need_type = TYPE_MAIN_VARIANT (type);
+ tree object = 0;
+ tree old_list = placeholder_list;
+ tree elt;
+
+ /* Find the outermost reference that is of the type we want.
+ If none, see if any object has a type that is a pointer to
+ the type we want. */
+ for (elt = TREE_PURPOSE (placeholder_expr);
+ elt != 0 && object == 0;
+ elt
+ = ((TREE_CODE (elt) == COMPOUND_EXPR
+ || TREE_CODE (elt) == COND_EXPR)
+ ? TREE_OPERAND (elt, 1)
+ : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+ ? TREE_OPERAND (elt, 0) : 0))
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
+ object = elt;
+
+ for (elt = TREE_PURPOSE (placeholder_expr);
+ elt != 0 && object == 0;
+ elt
+ = ((TREE_CODE (elt) == COMPOUND_EXPR
+ || TREE_CODE (elt) == COND_EXPR)
+ ? TREE_OPERAND (elt, 1)
+ : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+ ? TREE_OPERAND (elt, 0) : 0))
+ if (POINTER_TYPE_P (TREE_TYPE (elt))
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
+ == need_type))
+ object = build1 (INDIRECT_REF, need_type, elt);
+
+ if (object != 0)
+ {
+ /* Expand this object skipping the list entries before
+ it was found in case it is also a PLACEHOLDER_EXPR.
+ In that case, we want to translate it using subsequent
+ entries. */
+ placeholder_list = TREE_CHAIN (placeholder_expr);
+ temp = expand_expr (object, original_target, tmode,
+ ro_modifier);
+ placeholder_list = old_list;
+ return temp;
+ }
+ }
+ }
/* We can't find the object or there was a missing WITH_RECORD_EXPR. */
abort ();
@@ -4417,7 +5771,7 @@ expand_expr (exp, target, tmode, modifier)
placeholder_list = tree_cons (TREE_OPERAND (exp, 1), NULL_TREE,
placeholder_list);
target = expand_expr (TREE_OPERAND (exp, 0), original_target,
- tmode, modifier);
+ tmode, ro_modifier);
placeholder_list = TREE_CHAIN (placeholder_list);
return target;
@@ -4441,7 +5795,7 @@ expand_expr (exp, target, tmode, modifier)
int vars_need_expansion = 0;
/* Need to open a binding contour here because
- if there are any cleanups they most be contained here. */
+ if there are any cleanups they must be contained here. */
expand_start_bindings (0);
/* Mark the corresponding BLOCK for output in its proper place. */
@@ -4461,7 +5815,7 @@ expand_expr (exp, target, tmode, modifier)
vars = TREE_CHAIN (vars);
}
- temp = expand_expr (TREE_OPERAND (exp, 1), target, tmode, modifier);
+ temp = expand_expr (TREE_OPERAND (exp, 1), target, tmode, ro_modifier);
expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
@@ -4469,10 +5823,13 @@ expand_expr (exp, target, tmode, modifier)
}
case RTL_EXPR:
- if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
- abort ();
- emit_insns (RTL_EXPR_SEQUENCE (exp));
- RTL_EXPR_SEQUENCE (exp) = const0_rtx;
+ if (RTL_EXPR_SEQUENCE (exp))
+ {
+ if (RTL_EXPR_SEQUENCE (exp) == const0_rtx)
+ abort ();
+ emit_insns (RTL_EXPR_SEQUENCE (exp));
+ RTL_EXPR_SEQUENCE (exp) = const0_rtx;
+ }
preserve_rtl_expr_result (RTL_EXPR_RTL (exp));
free_temps_for_rtl_expr (exp);
return RTL_EXPR_RTL (exp);
@@ -4484,7 +5841,8 @@ expand_expr (exp, target, tmode, modifier)
{
tree elt;
for (elt = CONSTRUCTOR_ELTS (exp); elt; elt = TREE_CHAIN (elt))
- expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode, 0);
+ expand_expr (TREE_VALUE (elt), const0_rtx, VOIDmode,
+ EXPAND_MEMORY_USE_BAD);
return const0_rtx;
}
@@ -4497,13 +5855,14 @@ expand_expr (exp, target, tmode, modifier)
all operands are constant, put it in memory as well. */
else if ((TREE_STATIC (exp)
&& ((mode == BLKmode
- && ! (target != 0 && safe_from_p (target, exp)))
+ && ! (target != 0 && safe_from_p (target, exp, 1)))
|| TREE_ADDRESSABLE (exp)
|| (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
&& (move_by_pieces_ninsns
(TREE_INT_CST_LOW (TYPE_SIZE (type))/BITS_PER_UNIT,
TYPE_ALIGN (type) / BITS_PER_UNIT)
- > MOVE_RATIO))))
+ > MOVE_RATIO)
+ && ! mostly_zeros_p (exp))))
|| (modifier == EXPAND_INITIALIZER && TREE_CONSTANT (exp)))
{
rtx constructor = output_constant_def (exp);
@@ -4521,19 +5880,26 @@ expand_expr (exp, target, tmode, modifier)
else
{
- if (target == 0 || ! safe_from_p (target, exp))
+ /* Handle calls that pass values in multiple non-contiguous
+ locations. The Irix 6 ABI has examples of this. */
+ if (target == 0 || ! safe_from_p (target, exp, 1)
+ || GET_CODE (target) == PARALLEL)
{
if (mode != BLKmode && ! TREE_ADDRESSABLE (exp))
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
else
- {
- target
- = assign_stack_temp (mode, int_size_in_bytes (type), 0);
- if (AGGREGATE_TYPE_P (type))
- MEM_IN_STRUCT_P (target) = 1;
- }
+ target = assign_temp (type, 0, 1, 1);
+ }
+
+ if (TREE_READONLY (exp))
+ {
+ if (GET_CODE (target) == MEM)
+ target = copy_rtx (target);
+
+ RTX_UNCHANGING_P (target) = 1;
}
- store_constructor (exp, target);
+
+ store_constructor (exp, target, 0);
return target;
}
@@ -4541,41 +5907,75 @@ expand_expr (exp, target, tmode, modifier)
{
tree exp1 = TREE_OPERAND (exp, 0);
tree exp2;
-
- /* A SAVE_EXPR as the address in an INDIRECT_EXPR is generated
- for *PTR += ANYTHING where PTR is put inside the SAVE_EXPR.
- This code has the same general effect as simply doing
- expand_expr on the save expr, except that the expression PTR
- is computed for use as a memory address. This means different
- code, suitable for indexing, may be generated. */
- if (TREE_CODE (exp1) == SAVE_EXPR
- && SAVE_EXPR_RTL (exp1) == 0
- && TYPE_MODE (TREE_TYPE (exp1)) == ptr_mode)
- {
- temp = expand_expr (TREE_OPERAND (exp1, 0), NULL_RTX,
- VOIDmode, EXPAND_SUM);
- op0 = memory_address (mode, temp);
- op0 = copy_all_regs (op0);
- SAVE_EXPR_RTL (exp1) = op0;
- }
- else
+ tree index;
+ tree string = string_constant (exp1, &index);
+ int i;
+
+ /* Try to optimize reads from const strings. */
+ if (string
+ && TREE_CODE (string) == STRING_CST
+ && TREE_CODE (index) == INTEGER_CST
+ && !TREE_INT_CST_HIGH (index)
+ && (i = TREE_INT_CST_LOW (index)) < TREE_STRING_LENGTH (string)
+ && GET_MODE_CLASS (mode) == MODE_INT
+ && GET_MODE_SIZE (mode) == 1
+ && modifier != EXPAND_MEMORY_USE_WO)
+ return GEN_INT (TREE_STRING_POINTER (string)[i]);
+
+ op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
+ op0 = memory_address (mode, op0);
+
+ if (flag_check_memory_usage && !AGGREGATE_TYPE_P (TREE_TYPE (exp)))
{
- op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM);
- op0 = memory_address (mode, op0);
+ enum memory_use_mode memory_usage;
+ memory_usage = get_memory_usage_from_modifier (modifier);
+
+ if (memory_usage != MEMORY_USE_DONT)
+ {
+ in_check_memory_usage = 1;
+ emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ op0, ptr_mode,
+ GEN_INT (int_size_in_bytes (type)),
+ TYPE_MODE (sizetype),
+ GEN_INT (memory_usage),
+ TYPE_MODE (integer_type_node));
+ in_check_memory_usage = 0;
+ }
}
- temp = gen_rtx (MEM, mode, op0);
+ temp = gen_rtx_MEM (mode, op0);
/* If address was computed by addition,
mark this as an element of an aggregate. */
- if (TREE_CODE (TREE_OPERAND (exp, 0)) == PLUS_EXPR
- || (TREE_CODE (TREE_OPERAND (exp, 0)) == SAVE_EXPR
- && TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) == PLUS_EXPR)
+ if (TREE_CODE (exp1) == PLUS_EXPR
+ || (TREE_CODE (exp1) == SAVE_EXPR
+ && TREE_CODE (TREE_OPERAND (exp1, 0)) == PLUS_EXPR)
|| AGGREGATE_TYPE_P (TREE_TYPE (exp))
|| (TREE_CODE (exp1) == ADDR_EXPR
&& (exp2 = TREE_OPERAND (exp1, 0))
&& AGGREGATE_TYPE_P (TREE_TYPE (exp2))))
MEM_IN_STRUCT_P (temp) = 1;
+
+ /* If the pointer is actually a REFERENCE_TYPE, this could be pointing
+ into some aggregate too. In theory we could fold this into the
+ previous check and use rtx_addr_varies_p there too.
+
+ However, this seems safer. */
+ if (!MEM_IN_STRUCT_P (temp)
+ && (TREE_CODE (TREE_TYPE (exp1)) == REFERENCE_TYPE
+ /* This may have been an array reference to the first element
+ that was optimized away from being an addition. */
+ || (TREE_CODE (exp1) == NOP_EXPR
+ && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp1, 0)))
+ == REFERENCE_TYPE)
+ || ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp1, 0)))
+ == POINTER_TYPE)
+ && (AGGREGATE_TYPE_P
+ (TREE_TYPE (TREE_TYPE
+ (TREE_OPERAND (exp1, 0))))))))))
+ MEM_IN_STRUCT_P (temp) = ! rtx_addr_varies_p (temp);
+
MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp) | flag_volatile;
+ MEM_ALIAS_SET (temp) = get_alias_set (exp);
/* It is incorrect to set RTX_UNCHANGING_P from TREE_READONLY
here, because, in C and C++, the fact that a location is accessed
@@ -4596,11 +5996,7 @@ expand_expr (exp, target, tmode, modifier)
tree low_bound = domain ? TYPE_MIN_VALUE (domain) : integer_zero_node;
tree index = TREE_OPERAND (exp, 1);
tree index_type = TREE_TYPE (index);
- int i;
-
- if (TREE_CODE (low_bound) != INTEGER_CST
- && contains_placeholder_p (low_bound))
- low_bound = build (WITH_RECORD_EXPR, sizetype, low_bound, exp);
+ HOST_WIDE_INT i;
/* Optimize the special-case of a zero lower bound.
@@ -4617,69 +6013,6 @@ expand_expr (exp, target, tmode, modifier)
index = fold (build (MINUS_EXPR, index_type, index,
convert (sizetype, low_bound)));
- if ((TREE_CODE (index) != INTEGER_CST
- || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
- && (! SLOW_UNALIGNED_ACCESS || ! get_inner_unaligned_p (exp)))
- {
- /* Nonconstant array index or nonconstant element size, and
- not an array in an unaligned (packed) structure field.
- Generate the tree for *(&array+index) and expand that,
- except do it in a language-independent way
- and don't complain about non-lvalue arrays.
- `mark_addressable' should already have been called
- for any array for which this case will be reached. */
-
- /* Don't forget the const or volatile flag from the array
- element. */
- tree variant_type = build_type_variant (type,
- TREE_READONLY (exp),
- TREE_THIS_VOLATILE (exp));
- tree array_adr = build1 (ADDR_EXPR,
- build_pointer_type (variant_type), array);
- tree elt;
- tree size = size_in_bytes (type);
-
- /* Convert the integer argument to a type the same size as sizetype
- so the multiply won't overflow spuriously. */
- if (TYPE_PRECISION (index_type) != TYPE_PRECISION (sizetype))
- index = convert (type_for_size (TYPE_PRECISION (sizetype), 0),
- index);
-
- if (TREE_CODE (size) != INTEGER_CST
- && contains_placeholder_p (size))
- size = build (WITH_RECORD_EXPR, sizetype, size, exp);
-
- /* Don't think the address has side effects
- just because the array does.
- (In some cases the address might have side effects,
- and we fail to record that fact here. However, it should not
- matter, since expand_expr should not care.) */
- TREE_SIDE_EFFECTS (array_adr) = 0;
-
- elt
- = build1
- (INDIRECT_REF, type,
- fold (build (PLUS_EXPR,
- TYPE_POINTER_TO (variant_type),
- array_adr,
- fold
- (build1
- (NOP_EXPR,
- TYPE_POINTER_TO (variant_type),
- fold (build (MULT_EXPR, TREE_TYPE (index),
- index,
- convert (TREE_TYPE (index),
- size))))))));;
-
- /* Volatility, etc., of new expression is same as old
- expression. */
- TREE_SIDE_EFFECTS (elt) = TREE_SIDE_EFFECTS (exp);
- TREE_THIS_VOLATILE (elt) = TREE_THIS_VOLATILE (exp);
- TREE_READONLY (elt) = TREE_READONLY (exp);
-
- return expand_expr (elt, target, tmode, modifier);
- }
-
/* Fold an expression like: "foo"[2].
This is not done in fold so it won't happen inside &.
Don't fold if this is for wide characters since it's too
@@ -4710,7 +6043,7 @@ expand_expr (exp, target, tmode, modifier)
elem = TREE_CHAIN (elem);
if (elem)
return expand_expr (fold (TREE_VALUE (elem)), target,
- tmode, modifier);
+ tmode, ro_modifier);
}
}
@@ -4719,8 +6052,7 @@ expand_expr (exp, target, tmode, modifier)
&& TREE_CODE (array) == VAR_DECL && DECL_INITIAL (array)
&& TREE_CODE (DECL_INITIAL (array)) != ERROR_MARK)
{
- if (TREE_CODE (index) == INTEGER_CST
- && TREE_INT_CST_HIGH (index) == 0)
+ if (TREE_CODE (index) == INTEGER_CST)
{
tree init = DECL_INITIAL (array);
@@ -4734,16 +6066,20 @@ expand_expr (exp, target, tmode, modifier)
elem = TREE_CHAIN (elem);
if (elem)
return expand_expr (fold (TREE_VALUE (elem)), target,
- tmode, modifier);
+ tmode, ro_modifier);
}
else if (TREE_CODE (init) == STRING_CST
- && i < TREE_STRING_LENGTH (init))
- return GEN_INT (TREE_STRING_POINTER (init)[i]);
+ && TREE_INT_CST_HIGH (index) == 0
+ && (TREE_INT_CST_LOW (index)
+ < TREE_STRING_LENGTH (init)))
+ return (GEN_INT
+ (TREE_STRING_POINTER
+ (init)[TREE_INT_CST_LOW (index)]));
}
}
}
- /* Treat array-ref with constant index as a component-ref. */
+ /* ... fall through ... */
case COMPONENT_REF:
case BIT_FIELD_REF:
@@ -4759,8 +6095,47 @@ expand_expr (exp, target, tmode, modifier)
for (elt = CONSTRUCTOR_ELTS (TREE_OPERAND (exp, 0)); elt;
elt = TREE_CHAIN (elt))
- if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1))
- return expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+ if (TREE_PURPOSE (elt) == TREE_OPERAND (exp, 1)
+ /* We can normally use the value of the field in the
+ CONSTRUCTOR. However, if this is a bitfield in
+ an integral mode that we can fit in a HOST_WIDE_INT,
+ we must mask only the number of bits in the bitfield,
+ since this is done implicitly by the constructor. If
+ the bitfield does not meet either of those conditions,
+ we can't do this optimization. */
+ && (! DECL_BIT_FIELD (TREE_PURPOSE (elt))
+ || ((GET_MODE_CLASS (DECL_MODE (TREE_PURPOSE (elt)))
+ == MODE_INT)
+ && (GET_MODE_BITSIZE (DECL_MODE (TREE_PURPOSE (elt)))
+ <= HOST_BITS_PER_WIDE_INT))))
+ {
+ op0 = expand_expr (TREE_VALUE (elt), target, tmode, modifier);
+ if (DECL_BIT_FIELD (TREE_PURPOSE (elt)))
+ {
+ int bitsize = DECL_FIELD_SIZE (TREE_PURPOSE (elt));
+
+ if (TREE_UNSIGNED (TREE_TYPE (TREE_PURPOSE (elt))))
+ {
+ op1 = GEN_INT (((HOST_WIDE_INT) 1 << bitsize) - 1);
+ op0 = expand_and (op0, op1, target);
+ }
+ else
+ {
+ enum machine_mode imode
+ = TYPE_MODE (TREE_TYPE (TREE_PURPOSE (elt)));
+ tree count
+ = build_int_2 (GET_MODE_BITSIZE (imode) - bitsize,
+ 0);
+
+ op0 = expand_shift (LSHIFT_EXPR, imode, op0, count,
+ target, 0);
+ op0 = expand_shift (RSHIFT_EXPR, imode, op0, count,
+ target, 0);
+ }
+ }
+
+ return op0;
+ }
}
{
@@ -4769,9 +6144,10 @@ expand_expr (exp, target, tmode, modifier)
int bitpos;
tree offset;
int volatilep = 0;
- tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
- &mode1, &unsignedp, &volatilep);
int alignment;
+ tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+ &mode1, &unsignedp, &volatilep,
+ &alignment);
/* If we got back the original object, something is wrong. Perhaps
we are evaluating an expression too early. In any event, don't
@@ -4779,11 +6155,7 @@ expand_expr (exp, target, tmode, modifier)
if (tem == exp)
abort ();
- /* In some cases, we will be offsetting OP0's address by a constant.
- So get it as a sum, if possible. If we will be using it
- directly in an insn, we validate it.
-
- If TEM's type is a union of variable size, pass TARGET to the inner
+ /* If TEM's type is a union of variable size, pass TARGET to the inner
computation, since it will need a temporary and TARGET is known
to have to do. This occurs in unchecked conversion in Ada. */
@@ -4792,7 +6164,9 @@ expand_expr (exp, target, tmode, modifier)
&& (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
!= INTEGER_CST)
? target : NULL_RTX),
- VOIDmode, EXPAND_SUM);
+ VOIDmode,
+ modifier == EXPAND_INITIALIZER
+ ? modifier : EXPAND_NORMAL);
/* If this is a constant, put it into a register if it is a
legitimate constant and memory if it isn't. */
@@ -4805,24 +6179,46 @@ expand_expr (exp, target, tmode, modifier)
op0 = validize_mem (force_const_mem (mode, op0));
}
- alignment = TYPE_ALIGN (TREE_TYPE (tem)) / BITS_PER_UNIT;
if (offset != 0)
{
rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, 0);
if (GET_CODE (op0) != MEM)
abort ();
+
+ if (GET_MODE (offset_rtx) != ptr_mode)
+ {
+#ifdef POINTERS_EXTEND_UNSIGNED
+ offset_rtx = convert_memory_address (ptr_mode, offset_rtx);
+#else
+ offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0);
+#endif
+ }
+
+ if (GET_CODE (op0) == MEM
+ && GET_MODE (op0) == BLKmode
+ && bitsize
+ && (bitpos % bitsize) == 0
+ && (bitsize % GET_MODE_ALIGNMENT (mode1)) == 0
+ && (alignment * BITS_PER_UNIT) == GET_MODE_ALIGNMENT (mode1))
+ {
+ rtx temp = change_address (op0, mode1,
+ plus_constant (XEXP (op0, 0),
+ (bitpos /
+ BITS_PER_UNIT)));
+ if (GET_CODE (XEXP (temp, 0)) == REG)
+ op0 = temp;
+ else
+ op0 = change_address (op0, mode1,
+ force_reg (GET_MODE (XEXP (temp, 0)),
+ XEXP (temp, 0)));
+ bitpos = 0;
+ }
+
+
op0 = change_address (op0, VOIDmode,
- gen_rtx (PLUS, ptr_mode, XEXP (op0, 0),
- force_reg (ptr_mode, offset_rtx)));
- /* If we have a variable offset, the known alignment
- is only that of the innermost structure containing the field.
- (Actually, we could sometimes do better by using the
- size of an element of the innermost array, but no need.) */
- if (TREE_CODE (exp) == COMPONENT_REF
- || TREE_CODE (exp) == BIT_FIELD_REF)
- alignment = (TYPE_ALIGN (TREE_TYPE (TREE_OPERAND (exp, 0)))
- / BITS_PER_UNIT);
+ gen_rtx_PLUS (ptr_mode, XEXP (op0, 0),
+ force_reg (ptr_mode, offset_rtx)));
}
/* Don't forget about volatility even if this is a bitfield. */
@@ -4832,18 +6228,46 @@ expand_expr (exp, target, tmode, modifier)
MEM_VOLATILE_P (op0) = 1;
}
+ /* Check the access. */
+ if (flag_check_memory_usage && GET_CODE (op0) == MEM)
+ {
+ enum memory_use_mode memory_usage;
+ memory_usage = get_memory_usage_from_modifier (modifier);
+
+ if (memory_usage != MEMORY_USE_DONT)
+ {
+ rtx to;
+ int size;
+
+ to = plus_constant (XEXP (op0, 0), (bitpos / BITS_PER_UNIT));
+ size = (bitpos % BITS_PER_UNIT) + bitsize + BITS_PER_UNIT - 1;
+
+ /* Check the access right of the pointer. */
+ if (size > BITS_PER_UNIT)
+ emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ to, ptr_mode,
+ GEN_INT (size / BITS_PER_UNIT),
+ TYPE_MODE (sizetype),
+ GEN_INT (memory_usage),
+ TYPE_MODE (integer_type_node));
+ }
+ }
+
/* In cases where an aligned union has an unaligned object
as a field, we might be extracting a BLKmode value from
an integer-mode (e.g., SImode) object. Handle this case
by doing the extract into an object as wide as the field
(which we know to be the width of a basic mode), then
- storing into memory, and changing the mode to BLKmode. */
+ storing into memory, and changing the mode to BLKmode.
+ If we ultimately want the address (EXPAND_CONST_ADDRESS or
+ EXPAND_INITIALIZER), then we must not copy to a temporary. */
if (mode1 == VOIDmode
|| GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
|| (modifier != EXPAND_CONST_ADDRESS
- && modifier != EXPAND_SUM
&& modifier != EXPAND_INITIALIZER
- && ((mode1 != BLKmode && ! direct_load[(int) mode1])
+ && ((mode1 != BLKmode && ! direct_load[(int) mode1]
+ && GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+ && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
/* If the field isn't aligned enough to fetch as a memref,
fetch it as a bit field. */
|| (SLOW_UNALIGNED_ACCESS
@@ -4856,12 +6280,49 @@ expand_expr (exp, target, tmode, modifier)
ext_mode = mode_for_size (bitsize, MODE_INT, 1);
if (ext_mode == BLKmode)
- abort ();
+ {
+ /* In this case, BITPOS must start at a byte boundary and
+ TARGET, if specified, must be a MEM. */
+ if (GET_CODE (op0) != MEM
+ || (target != 0 && GET_CODE (target) != MEM)
+ || bitpos % BITS_PER_UNIT != 0)
+ abort ();
+
+ op0 = change_address (op0, VOIDmode,
+ plus_constant (XEXP (op0, 0),
+ bitpos / BITS_PER_UNIT));
+ if (target == 0)
+ target = assign_temp (type, 0, 1, 1);
+
+ emit_block_move (target, op0,
+ GEN_INT ((bitsize + BITS_PER_UNIT - 1)
+ / BITS_PER_UNIT),
+ 1);
+
+ return target;
+ }
+
+ op0 = validize_mem (op0);
- op0 = extract_bit_field (validize_mem (op0), bitsize, bitpos,
+ if (GET_CODE (op0) == MEM && GET_CODE (XEXP (op0, 0)) == REG)
+ mark_reg_pointer (XEXP (op0, 0), alignment);
+
+ op0 = extract_bit_field (op0, bitsize, bitpos,
unsignedp, target, ext_mode, ext_mode,
alignment,
int_size_in_bytes (TREE_TYPE (tem)));
+
+ /* If the result is a record type and BITSIZE is narrower than
+ the mode of OP0, an integral mode, and this is a big endian
+ machine, we must put the field into the high-order bits. */
+ if (TREE_CODE (type) == RECORD_TYPE && BYTES_BIG_ENDIAN
+ && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
+ && bitsize < GET_MODE_BITSIZE (GET_MODE (op0)))
+ op0 = expand_shift (LSHIFT_EXPR, GET_MODE (op0), op0,
+ size_int (GET_MODE_BITSIZE (GET_MODE (op0))
+ - bitsize),
+ op0, 1);
+
if (mode == BLKmode)
{
rtx new = assign_stack_temp (ext_mode,
@@ -4876,41 +6337,40 @@ expand_expr (exp, target, tmode, modifier)
return op0;
}
+ /* If the result is BLKmode, use that to access the object
+ now as well. */
+ if (mode == BLKmode)
+ mode1 = BLKmode;
+
/* Get a reference to just this component. */
if (modifier == EXPAND_CONST_ADDRESS
|| modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER)
- op0 = gen_rtx (MEM, mode1, plus_constant (XEXP (op0, 0),
- (bitpos / BITS_PER_UNIT)));
+ op0 = gen_rtx_MEM (mode1, plus_constant (XEXP (op0, 0),
+ (bitpos / BITS_PER_UNIT)));
else
op0 = change_address (op0, mode1,
plus_constant (XEXP (op0, 0),
(bitpos / BITS_PER_UNIT)));
+
+ if (GET_CODE (op0) == MEM)
+ MEM_ALIAS_SET (op0) = get_alias_set (exp);
+
+ if (GET_CODE (XEXP (op0, 0)) == REG)
+ mark_reg_pointer (XEXP (op0, 0), alignment);
+
MEM_IN_STRUCT_P (op0) = 1;
MEM_VOLATILE_P (op0) |= volatilep;
- if (mode == mode1 || mode1 == BLKmode || mode1 == tmode)
+ if (mode == mode1 || mode1 == BLKmode || mode1 == tmode
+ || modifier == EXPAND_CONST_ADDRESS
+ || modifier == EXPAND_INITIALIZER)
return op0;
- if (target == 0)
+ else if (target == 0)
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
+
convert_move (target, op0, unsignedp);
return target;
}
- case OFFSET_REF:
- {
- tree base = build1 (ADDR_EXPR, type, TREE_OPERAND (exp, 0));
- tree addr = build (PLUS_EXPR, type, base, TREE_OPERAND (exp, 1));
- op0 = expand_expr (addr, NULL_RTX, VOIDmode, EXPAND_SUM);
- temp = gen_rtx (MEM, mode, memory_address (mode, op0));
- MEM_IN_STRUCT_P (temp) = 1;
- MEM_VOLATILE_P (temp) = TREE_THIS_VOLATILE (exp);
-#if 0 /* It is incorrect to set RTX_UNCHANGING_P here, because the fact that
- a location is accessed through a pointer to const does not mean
- that the value there can never change. */
- RTX_UNCHANGING_P (temp) = TREE_READONLY (exp);
-#endif
- return temp;
- }
-
/* Intended for a reference to a buffer of a file-object in Pascal.
But it's not certain that a special tree code will really be
necessary for these. INDIRECT_REF might work for them. */
@@ -4947,9 +6407,9 @@ expand_expr (exp, target, tmode, modifier)
/* If domain is empty, answer is no. Likewise if index is constant
and out of bounds. */
- if ((TREE_CODE (set_high_bound) == INTEGER_CST
+ if (((TREE_CODE (set_high_bound) == INTEGER_CST
&& TREE_CODE (set_low_bound) == INTEGER_CST
- && tree_int_cst_lt (set_high_bound, set_low_bound)
+ && tree_int_cst_lt (set_high_bound, set_low_bound))
|| (TREE_CODE (index) == INTEGER_CST
&& TREE_CODE (set_low_bound) == INTEGER_CST
&& tree_int_cst_lt (index, set_low_bound))
@@ -5008,7 +6468,7 @@ expand_expr (exp, target, tmode, modifier)
/* Extract the bit we want to examine */
bit = expand_shift (RSHIFT_EXPR, byte_mode,
- gen_rtx (MEM, byte_mode, addr),
+ gen_rtx_MEM (byte_mode, addr),
make_tree (TREE_TYPE (index), rem),
NULL_RTX, 1);
result = expand_binop (byte_mode, and_optab, bit, const1_rtx,
@@ -5030,31 +6490,29 @@ expand_expr (exp, target, tmode, modifier)
if (RTL_EXPR_RTL (exp) == 0)
{
RTL_EXPR_RTL (exp)
- = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
- cleanups_this_call
- = tree_cons (NULL_TREE, TREE_OPERAND (exp, 2), cleanups_this_call);
+ = expand_expr (TREE_OPERAND (exp, 0), target, tmode, ro_modifier);
+ expand_decl_cleanup (NULL_TREE, TREE_OPERAND (exp, 2));
+
/* That's it for this cleanup. */
TREE_OPERAND (exp, 2) = 0;
- (*interim_eh_hook) (NULL_TREE);
}
return RTL_EXPR_RTL (exp);
case CLEANUP_POINT_EXPR:
{
extern int temp_slot_level;
- tree old_cleanups = cleanups_this_call;
- int old_temp_level = target_temp_slot_level;
- push_temp_slots ();
+ /* Start a new binding layer that will keep track of all cleanup
+ actions to be performed. */
+ expand_start_bindings (0);
+
target_temp_slot_level = temp_slot_level;
- op0 = expand_expr (TREE_OPERAND (exp, 0), target, tmode, modifier);
+
+ op0 = expand_expr (TREE_OPERAND (exp, 0), target, tmode, ro_modifier);
/* If we're going to use this value, load it up now. */
if (! ignore)
op0 = force_not_mem (op0);
- expand_cleanups_to (old_cleanups);
preserve_temp_slots (op0);
- free_temp_slots ();
- pop_temp_slots ();
- target_temp_slot_level = old_temp_level;
+ expand_end_bindings (NULL_TREE, 0, 0);
}
return op0;
@@ -5082,19 +6540,10 @@ expand_expr (exp, target, tmode, modifier)
tree valtype = TREE_TYPE (TREE_OPERAND (exp, 0));
if (target == 0)
{
- if (mode == BLKmode)
- {
- if (TYPE_SIZE (type) == 0
- || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
- abort ();
- target = assign_stack_temp (BLKmode,
- (TREE_INT_CST_LOW (TYPE_SIZE (type))
- + BITS_PER_UNIT - 1)
- / BITS_PER_UNIT, 0);
- MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (type);
- }
- else
+ if (mode != BLKmode)
target = gen_reg_rtx (tmode != VOIDmode ? tmode : mode);
+ else
+ target = assign_temp (type, 0, 1, 1);
}
if (GET_CODE (target) == MEM)
@@ -5118,7 +6567,7 @@ expand_expr (exp, target, tmode, modifier)
if (mode == TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))))
{
op0 = expand_expr (TREE_OPERAND (exp, 0), target, VOIDmode,
- modifier);
+ ro_modifier);
/* If the signedness of the conversion differs and OP0 is
a promoted SUBREG, clear that indication since we now
@@ -5141,10 +6590,7 @@ expand_expr (exp, target, tmode, modifier)
op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
if (modifier == EXPAND_INITIALIZER)
- return gen_rtx (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
-
- if (flag_force_mem && GET_CODE (op0) == MEM)
- op0 = copy_to_reg (op0);
+ return gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
if (target == 0)
return
@@ -5156,7 +6602,8 @@ expand_expr (exp, target, tmode, modifier)
return target;
case PLUS_EXPR:
- /* We come here from MINUS_EXPR when the second operand is a constant. */
+ /* We come here from MINUS_EXPR when the second operand is a
+ constant. */
plus_expr:
this_optab = add_optab;
@@ -5239,11 +6686,11 @@ expand_expr (exp, target, tmode, modifier)
goto binop;
preexpand_calls (exp);
- if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
+ if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
- op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, modifier);
- op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, modifier);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, ro_modifier);
+ op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, ro_modifier);
both_summands:
/* Make sure any term that's a sum with a constant comes last. */
@@ -5266,9 +6713,9 @@ expand_expr (exp, target, tmode, modifier)
op0 = temp;
/* Ensure that MULT comes first if there is one. */
else if (GET_CODE (op0) == MULT)
- op0 = gen_rtx (PLUS, mode, op0, XEXP (op1, 0));
+ op0 = gen_rtx_PLUS (mode, op0, XEXP (op1, 0));
else
- op0 = gen_rtx (PLUS, mode, XEXP (op1, 0), op0);
+ op0 = gen_rtx_PLUS (mode, XEXP (op1, 0), op0);
/* Let's also eliminate constants from op0 if possible. */
op0 = eliminate_constant_term (op0, &constant_term);
@@ -5282,7 +6729,7 @@ expand_expr (exp, target, tmode, modifier)
if (temp != 0)
op1 = temp;
else
- op1 = gen_rtx (PLUS, mode, constant_term, XEXP (op1, 1));
+ op1 = gen_rtx_PLUS (mode, constant_term, XEXP (op1, 1));
}
/* Put a constant term last and put a multiplication first. */
@@ -5290,7 +6737,7 @@ expand_expr (exp, target, tmode, modifier)
temp = op1, op1 = op0, op0 = temp;
temp = simplify_binary_operation (PLUS, mode, op0, op1);
- return temp ? temp : gen_rtx (PLUS, mode, op0, op1);
+ return temp ? temp : gen_rtx_PLUS (mode, op0, op1);
case MINUS_EXPR:
/* For initializers, we are allowed to return a MINUS of two
@@ -5303,16 +6750,16 @@ expand_expr (exp, target, tmode, modifier)
&& really_constant_p (TREE_OPERAND (exp, 1)))
{
rtx op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX,
- VOIDmode, modifier);
+ VOIDmode, ro_modifier);
rtx op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
- VOIDmode, modifier);
+ VOIDmode, ro_modifier);
/* If the last operand is a CONST_INT, use plus_constant of
the negated constant. Else make the MINUS. */
if (GET_CODE (op1) == CONST_INT)
return plus_constant (op0, - INTVAL (op1));
else
- return gen_rtx (MINUS, mode, op0, op1);
+ return gen_rtx_MINUS (mode, op0, op1);
}
/* Convert A - const to A + (-const). */
if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
@@ -5333,7 +6780,7 @@ expand_expr (exp, target, tmode, modifier)
return expand_expr (convert (type,
build (PLUS_EXPR, newtype,
newop0, newneg)),
- target, tmode, modifier);
+ target, tmode, ro_modifier);
}
else
{
@@ -5363,14 +6810,15 @@ expand_expr (exp, target, tmode, modifier)
&& TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST
&& GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
{
- op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, EXPAND_SUM);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode,
+ EXPAND_SUM);
/* Apply distributive law if OP0 is x+c. */
if (GET_CODE (op0) == PLUS
&& GET_CODE (XEXP (op0, 1)) == CONST_INT)
- return gen_rtx (PLUS, mode,
- gen_rtx (MULT, mode, XEXP (op0, 0),
- GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))),
+ return gen_rtx_PLUS (mode,
+ gen_rtx_MULT (mode, XEXP (op0, 0),
+ GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)))),
GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))
* INTVAL (XEXP (op0, 1))));
@@ -5379,11 +6827,11 @@ expand_expr (exp, target, tmode, modifier)
if (GET_CODE (op0) != REG)
op0 = copy_to_mode_reg (mode, op0);
- return gen_rtx (MULT, mode, op0,
- GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))));
+ return gen_rtx_MULT (mode, op0,
+ GEN_INT (TREE_INT_CST_LOW (TREE_OPERAND (exp, 1))));
}
- if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
+ if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
/* Check for multiplying things that have been extended
@@ -5414,20 +6862,46 @@ expand_expr (exp, target, tmode, modifier)
{
enum machine_mode innermode
= TYPE_MODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)));
+ optab other_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
+ ? smul_widen_optab : umul_widen_optab);
this_optab = (TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
? umul_widen_optab : smul_widen_optab);
- if (mode == GET_MODE_WIDER_MODE (innermode)
- && this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ if (mode == GET_MODE_WIDER_MODE (innermode))
{
- op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
- NULL_RTX, VOIDmode, 0);
- if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
- op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
- VOIDmode, 0);
- else
- op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
- NULL_RTX, VOIDmode, 0);
- goto binop2;
+ if (this_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ {
+ op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
+ NULL_RTX, VOIDmode, 0);
+ if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
+ op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
+ VOIDmode, 0);
+ else
+ op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
+ NULL_RTX, VOIDmode, 0);
+ goto binop2;
+ }
+ else if (other_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
+ && innermode == word_mode)
+ {
+ rtx htem;
+ op0 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
+ NULL_RTX, VOIDmode, 0);
+ if (TREE_CODE (TREE_OPERAND (exp, 1)) == INTEGER_CST)
+ op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX,
+ VOIDmode, 0);
+ else
+ op1 = expand_expr (TREE_OPERAND (TREE_OPERAND (exp, 1), 0),
+ NULL_RTX, VOIDmode, 0);
+ temp = expand_binop (mode, other_optab, op0, op1, target,
+ unsignedp, OPTAB_LIB_WIDEN);
+ htem = expand_mult_highpart_adjust (innermode,
+ gen_highpart (innermode, temp),
+ op0, op1,
+ gen_highpart (innermode, temp),
+ unsignedp);
+ emit_move_insn (gen_highpart (innermode, temp), htem);
+ return temp;
+ }
}
}
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
@@ -5440,7 +6914,7 @@ expand_expr (exp, target, tmode, modifier)
case ROUND_DIV_EXPR:
case EXACT_DIV_EXPR:
preexpand_calls (exp);
- if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
+ if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
/* Possible optimization: compute the dividend with EXPAND_SUM
then if the divisor is constant can optimize the case
@@ -5458,7 +6932,7 @@ expand_expr (exp, target, tmode, modifier)
case CEIL_MOD_EXPR:
case ROUND_MOD_EXPR:
preexpand_calls (exp);
- if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
+ if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
@@ -5510,12 +6984,12 @@ expand_expr (exp, target, tmode, modifier)
return op0;
return expand_abs (mode, op0, target, unsignedp,
- safe_from_p (target, TREE_OPERAND (exp, 0)));
+ safe_from_p (target, TREE_OPERAND (exp, 0), 1));
case MAX_EXPR:
case MIN_EXPR:
target = original_target;
- if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 1))
+ if (target == 0 || ! safe_from_p (target, TREE_OPERAND (exp, 1), 1)
|| (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
|| GET_MODE (target) != mode
|| (GET_CODE (target) == REG
@@ -5630,7 +7104,7 @@ expand_expr (exp, target, tmode, modifier)
case LROTATE_EXPR:
case RROTATE_EXPR:
preexpand_calls (exp);
- if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
+ if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
return expand_shift (code, mode, op0, TREE_OPERAND (exp, 1), target,
@@ -5649,7 +7123,7 @@ expand_expr (exp, target, tmode, modifier)
if (temp != 0)
return temp;
- /* For foo != 0, load foo, and if it is nonzero load 1 instead. */
+ /* For foo != 0, load foo, and if it is nonzero load 1 instead. */
if (code == NE_EXPR && integer_zerop (TREE_OPERAND (exp, 1))
&& original_target
&& GET_CODE (original_target) == REG
@@ -5678,7 +7152,7 @@ expand_expr (exp, target, tmode, modifier)
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
if (! ignore
- && (target == 0 || ! safe_from_p (target, exp)
+ && (target == 0 || ! safe_from_p (target, exp, 1)
/* Make sure we don't have a hard reg (such as function's return
value) live across basic blocks, if not optimizing. */
|| (!optimize && GET_CODE (target) == REG
@@ -5715,18 +7189,32 @@ expand_expr (exp, target, tmode, modifier)
VOIDmode, 0);
case COND_EXPR:
- {
- rtx flag = NULL_RTX;
- tree left_cleanups = NULL_TREE;
- tree right_cleanups = NULL_TREE;
-
- /* Used to save a pointer to the place to put the setting of
- the flag that indicates if this side of the conditional was
- taken. We backpatch the code, if we find out later that we
- have any conditional cleanups that need to be performed. */
- rtx dest_right_flag = NULL_RTX;
- rtx dest_left_flag = NULL_RTX;
+ /* If we would have a "singleton" (see below) were it not for a
+ conversion in each arm, bring that conversion back out. */
+ if (TREE_CODE (TREE_OPERAND (exp, 1)) == NOP_EXPR
+ && TREE_CODE (TREE_OPERAND (exp, 2)) == NOP_EXPR
+ && (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 1), 0))
+ == TREE_TYPE (TREE_OPERAND (TREE_OPERAND (exp, 2), 0))))
+ {
+ tree true = TREE_OPERAND (TREE_OPERAND (exp, 1), 0);
+ tree false = TREE_OPERAND (TREE_OPERAND (exp, 2), 0);
+
+ if ((TREE_CODE_CLASS (TREE_CODE (true)) == '2'
+ && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (false)) == '2'
+ && operand_equal_p (true, TREE_OPERAND (false, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (true)) == '1'
+ && operand_equal_p (false, TREE_OPERAND (true, 0), 0))
+ || (TREE_CODE_CLASS (TREE_CODE (false)) == '1'
+ && operand_equal_p (true, TREE_OPERAND (false, 0), 0)))
+ return expand_expr (build1 (NOP_EXPR, type,
+ build (COND_EXPR, TREE_TYPE (true),
+ TREE_OPERAND (exp, 0),
+ true, false)),
+ target, tmode, modifier);
+ }
+ {
/* Note that COND_EXPRs whose type is a structure or union
are required to be constructed to contain assignments of
a temporary variable, so that we can evaluate them here
@@ -5737,7 +7225,6 @@ expand_expr (exp, target, tmode, modifier)
tree singleton = 0;
tree binary_op = 0, unary_op = 0;
- tree old_cleanups = cleanups_this_call;
/* If this is (A ? 1 : 0) and A is a condition, just evaluate it and
convert it to our mode, if necessary. */
@@ -5748,11 +7235,11 @@ expand_expr (exp, target, tmode, modifier)
if (ignore)
{
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode,
- modifier);
+ ro_modifier);
return const0_rtx;
}
- op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, modifier);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), target, mode, ro_modifier);
if (GET_MODE (op0) == mode)
return op0;
@@ -5762,39 +7249,11 @@ expand_expr (exp, target, tmode, modifier)
return target;
}
- /* If we are not to produce a result, we have no target. Otherwise,
- if a target was specified use it; it will not be used as an
- intermediate target unless it is safe. If no target, use a
- temporary. */
-
- if (ignore)
- temp = 0;
- else if (original_target
- && safe_from_p (original_target, TREE_OPERAND (exp, 0))
- && GET_MODE (original_target) == mode
- && ! (GET_CODE (original_target) == MEM
- && MEM_VOLATILE_P (original_target)))
- temp = original_target;
- else if (mode == BLKmode)
- {
- if (TYPE_SIZE (type) == 0
- || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
- abort ();
-
- temp = assign_stack_temp (BLKmode,
- (TREE_INT_CST_LOW (TYPE_SIZE (type))
- + BITS_PER_UNIT - 1)
- / BITS_PER_UNIT, 0);
- MEM_IN_STRUCT_P (temp) = AGGREGATE_TYPE_P (type);
- }
- else
- temp = gen_reg_rtx (mode);
-
- /* Check for X ? A + B : A. If we have this, we can copy
- A to the output and conditionally add B. Similarly for unary
- operations. Don't do this if X has side-effects because
- those side effects might affect A or B and the "?" operation is
- a sequence point in ANSI. (We test for side effects later.) */
+ /* Check for X ? A + B : A. If we have this, we can copy A to the
+ output and conditionally add B. Similarly for unary operations.
+ Don't do this if X has side-effects because those side effects
+ might affect A or B and the "?" operation is a sequence point in
+ ANSI. (operand_equal_p tests for side effects.) */
if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 1))) == '2'
&& operand_equal_p (TREE_OPERAND (exp, 2),
@@ -5813,16 +7272,43 @@ expand_expr (exp, target, tmode, modifier)
TREE_OPERAND (TREE_OPERAND (exp, 2), 0), 0))
singleton = TREE_OPERAND (exp, 1), unary_op = TREE_OPERAND (exp, 2);
- /* If we had X ? A + 1 : A and we can do the test of X as a store-flag
- operation, do this as A + (X != 0). Similarly for other simple
- binary operators. */
+ /* If we are not to produce a result, we have no target. Otherwise,
+ if a target was specified use it; it will not be used as an
+ intermediate target unless it is safe. If no target, use a
+ temporary. */
+
+ if (ignore)
+ temp = 0;
+ else if (original_target
+ && (safe_from_p (original_target, TREE_OPERAND (exp, 0), 1)
+ || (singleton && GET_CODE (original_target) == REG
+ && REGNO (original_target) >= FIRST_PSEUDO_REGISTER
+ && original_target == var_rtx (singleton)))
+ && GET_MODE (original_target) == mode
+#ifdef HAVE_conditional_move
+ && (! can_conditionally_move_p (mode)
+ || GET_CODE (original_target) == REG
+ || TREE_ADDRESSABLE (type))
+#endif
+ && ! (GET_CODE (original_target) == MEM
+ && MEM_VOLATILE_P (original_target)))
+ temp = original_target;
+ else if (TREE_ADDRESSABLE (type))
+ abort ();
+ else
+ temp = assign_temp (type, 0, 0, 1);
+
+ /* If we had X ? A + C : A, with C a constant power of 2, and we can
+ do the test of X as a store-flag operation, do this as
+ A + ((X != 0) << log C). Similarly for other simple binary
+ operators. Only do for C == 1 if BRANCH_COST is low. */
if (temp && singleton && binary_op
- && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
&& (TREE_CODE (binary_op) == PLUS_EXPR
|| TREE_CODE (binary_op) == MINUS_EXPR
|| TREE_CODE (binary_op) == BIT_IOR_EXPR
|| TREE_CODE (binary_op) == BIT_XOR_EXPR)
- && integer_onep (TREE_OPERAND (binary_op, 1))
+ && (BRANCH_COST >= 3 ? integer_pow2p (TREE_OPERAND (binary_op, 1))
+ : integer_onep (TREE_OPERAND (binary_op, 1)))
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<')
{
rtx result;
@@ -5843,10 +7329,19 @@ expand_expr (exp, target, tmode, modifier)
= invert_truthvalue (TREE_OPERAND (exp, 0));
result = do_store_flag (TREE_OPERAND (exp, 0),
- (safe_from_p (temp, singleton)
+ (safe_from_p (temp, singleton, 1)
? temp : NULL_RTX),
mode, BRANCH_COST <= 1);
+ if (result != 0 && ! integer_onep (TREE_OPERAND (binary_op, 1)))
+ result = expand_shift (LSHIFT_EXPR, mode, result,
+ build_int_2 (tree_log2
+ (TREE_OPERAND
+ (binary_op, 1)),
+ 0),
+ (safe_from_p (temp, singleton, 1)
+ ? temp : NULL_RTX), 0);
+
if (result)
{
op1 = expand_expr (singleton, NULL_RTX, VOIDmode, 0);
@@ -5862,7 +7357,6 @@ expand_expr (exp, target, tmode, modifier)
NO_DEFER_POP;
op0 = gen_label_rtx ();
- flag = gen_reg_rtx (word_mode);
if (singleton && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0)))
{
if (temp != 0)
@@ -5872,7 +7366,7 @@ expand_expr (exp, target, tmode, modifier)
if it is a hard register, because evaluating the condition
might clobber it. */
if ((binary_op
- && ! safe_from_p (temp, TREE_OPERAND (binary_op, 1)))
+ && ! safe_from_p (temp, TREE_OPERAND (binary_op, 1), 1))
|| (GET_CODE (temp) == REG
&& REGNO (temp) < FIRST_PSEUDO_REGISTER))
temp = gen_reg_rtx (mode);
@@ -5881,14 +7375,12 @@ expand_expr (exp, target, tmode, modifier)
else
expand_expr (singleton,
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
- dest_left_flag = get_last_insn ();
if (singleton == TREE_OPERAND (exp, 1))
jumpif (TREE_OPERAND (exp, 0), op0);
else
jumpifnot (TREE_OPERAND (exp, 0), op0);
- /* Allows cleanups up to here. */
- old_cleanups = cleanups_this_call;
+ start_cleanup_deferral ();
if (binary_op && temp == 0)
/* Just touch the other operand. */
expand_expr (TREE_OPERAND (binary_op, 1),
@@ -5903,43 +7395,7 @@ expand_expr (exp, target, tmode, modifier)
make_tree (type, temp)),
temp, 0);
op1 = op0;
- dest_right_flag = get_last_insn ();
}
-#if 0
- /* This is now done in jump.c and is better done there because it
- produces shorter register lifetimes. */
-
- /* Check for both possibilities either constants or variables
- in registers (but not the same as the target!). If so, can
- save branches by assigning one, branching, and assigning the
- other. */
- else if (temp && GET_MODE (temp) != BLKmode
- && (TREE_CONSTANT (TREE_OPERAND (exp, 1))
- || ((TREE_CODE (TREE_OPERAND (exp, 1)) == PARM_DECL
- || TREE_CODE (TREE_OPERAND (exp, 1)) == VAR_DECL)
- && DECL_RTL (TREE_OPERAND (exp, 1))
- && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 1))) == REG
- && DECL_RTL (TREE_OPERAND (exp, 1)) != temp))
- && (TREE_CONSTANT (TREE_OPERAND (exp, 2))
- || ((TREE_CODE (TREE_OPERAND (exp, 2)) == PARM_DECL
- || TREE_CODE (TREE_OPERAND (exp, 2)) == VAR_DECL)
- && DECL_RTL (TREE_OPERAND (exp, 2))
- && GET_CODE (DECL_RTL (TREE_OPERAND (exp, 2))) == REG
- && DECL_RTL (TREE_OPERAND (exp, 2)) != temp)))
- {
- if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
- temp = gen_reg_rtx (mode);
- store_expr (TREE_OPERAND (exp, 2), temp, 0);
- dest_left_flag = get_last_insn ();
- jumpifnot (TREE_OPERAND (exp, 0), op0);
-
- /* Allows cleanups up to here. */
- old_cleanups = cleanups_this_call;
- store_expr (TREE_OPERAND (exp, 1), temp, 0);
- op1 = op0;
- dest_right_flag = get_last_insn ();
- }
-#endif
/* Check for A op 0 ? A : FOO and A op 0 ? FOO : A where OP is any
comparison operator. If we have one of these cases, set the
output to A, branch on A (cse will merge these two references),
@@ -5949,128 +7405,72 @@ expand_expr (exp, target, tmode, modifier)
&& integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
&& operand_equal_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
TREE_OPERAND (exp, 1), 0)
- && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
- && safe_from_p (temp, TREE_OPERAND (exp, 2)))
+ && (! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
+ || TREE_CODE (TREE_OPERAND (exp, 1)) == SAVE_EXPR)
+ && safe_from_p (temp, TREE_OPERAND (exp, 2), 1))
{
if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
temp = gen_reg_rtx (mode);
store_expr (TREE_OPERAND (exp, 1), temp, 0);
- dest_left_flag = get_last_insn ();
jumpif (TREE_OPERAND (exp, 0), op0);
- /* Allows cleanups up to here. */
- old_cleanups = cleanups_this_call;
+ start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 2), temp, 0);
op1 = op0;
- dest_right_flag = get_last_insn ();
}
else if (temp
&& TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, 0))) == '<'
&& integer_zerop (TREE_OPERAND (TREE_OPERAND (exp, 0), 1))
&& operand_equal_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0),
TREE_OPERAND (exp, 2), 0)
- && ! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
- && safe_from_p (temp, TREE_OPERAND (exp, 1)))
+ && (! TREE_SIDE_EFFECTS (TREE_OPERAND (exp, 0))
+ || TREE_CODE (TREE_OPERAND (exp, 2)) == SAVE_EXPR)
+ && safe_from_p (temp, TREE_OPERAND (exp, 1), 1))
{
if (GET_CODE (temp) == REG && REGNO (temp) < FIRST_PSEUDO_REGISTER)
temp = gen_reg_rtx (mode);
store_expr (TREE_OPERAND (exp, 2), temp, 0);
- dest_left_flag = get_last_insn ();
jumpifnot (TREE_OPERAND (exp, 0), op0);
- /* Allows cleanups up to here. */
- old_cleanups = cleanups_this_call;
+ start_cleanup_deferral ();
store_expr (TREE_OPERAND (exp, 1), temp, 0);
op1 = op0;
- dest_right_flag = get_last_insn ();
}
else
{
op1 = gen_label_rtx ();
jumpifnot (TREE_OPERAND (exp, 0), op0);
- /* Allows cleanups up to here. */
- old_cleanups = cleanups_this_call;
+ start_cleanup_deferral ();
if (temp != 0)
store_expr (TREE_OPERAND (exp, 1), temp, 0);
else
expand_expr (TREE_OPERAND (exp, 1),
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
- dest_left_flag = get_last_insn ();
-
- /* Handle conditional cleanups, if any. */
- left_cleanups = defer_cleanups_to (old_cleanups);
-
+ end_cleanup_deferral ();
emit_queue ();
emit_jump_insn (gen_jump (op1));
emit_barrier ();
emit_label (op0);
+ start_cleanup_deferral ();
if (temp != 0)
store_expr (TREE_OPERAND (exp, 2), temp, 0);
else
expand_expr (TREE_OPERAND (exp, 2),
ignore ? const0_rtx : NULL_RTX, VOIDmode, 0);
- dest_right_flag = get_last_insn ();
}
- /* Handle conditional cleanups, if any. */
- right_cleanups = defer_cleanups_to (old_cleanups);
+ end_cleanup_deferral ();
emit_queue ();
emit_label (op1);
OK_DEFER_POP;
- /* Add back in, any conditional cleanups. */
- if (left_cleanups || right_cleanups)
- {
- tree new_cleanups;
- tree cond;
- rtx last;
-
- /* Now that we know that a flag is needed, go back and add in the
- setting of the flag. */
-
- /* Do the left side flag. */
- last = get_last_insn ();
- /* Flag left cleanups as needed. */
- emit_move_insn (flag, const1_rtx);
- /* ??? deprecated, use sequences instead. */
- reorder_insns (NEXT_INSN (last), get_last_insn (), dest_left_flag);
-
- /* Do the right side flag. */
- last = get_last_insn ();
- /* Flag left cleanups as needed. */
- emit_move_insn (flag, const0_rtx);
- /* ??? deprecated, use sequences instead. */
- reorder_insns (NEXT_INSN (last), get_last_insn (), dest_right_flag);
-
- /* convert flag, which is an rtx, into a tree. */
- cond = make_node (RTL_EXPR);
- TREE_TYPE (cond) = integer_type_node;
- RTL_EXPR_RTL (cond) = flag;
- RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
- cond = save_expr (cond);
-
- if (! left_cleanups)
- left_cleanups = integer_zero_node;
- if (! right_cleanups)
- right_cleanups = integer_zero_node;
- new_cleanups = build (COND_EXPR, void_type_node,
- truthvalue_conversion (cond),
- left_cleanups, right_cleanups);
- new_cleanups = fold (new_cleanups);
-
- /* Now add in the conditionalized cleanups. */
- cleanups_this_call
- = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
- (*interim_eh_hook) (NULL_TREE);
- }
return temp;
}
case TARGET_EXPR:
{
- int need_exception_region = 0;
/* Something needs to be initialized, but we didn't know
where that thing was when building the tree. For example,
it could be the return value of a function, or a parameter
@@ -6081,8 +7481,8 @@ expand_expr (exp, target, tmode, modifier)
or copied into our original target. */
tree slot = TREE_OPERAND (exp, 0);
+ tree cleanups = NULL_TREE;
tree exp1;
- rtx temp;
if (TREE_CODE (slot) != VAR_DECL)
abort ();
@@ -6102,11 +7502,15 @@ expand_expr (exp, target, tmode, modifier)
}
else
{
- target = assign_stack_temp (mode, int_size_in_bytes (type), 2);
- MEM_IN_STRUCT_P (target) = AGGREGATE_TYPE_P (type);
+ target = assign_temp (type, 2, 0, 1);
/* All temp slots at this level must not conflict. */
preserve_temp_slots (target);
DECL_RTL (slot) = target;
+ if (TREE_ADDRESSABLE (slot))
+ {
+ TREE_ADDRESSABLE (slot) = 0;
+ mark_addressable (slot);
+ }
/* Since SLOT is not known to the called function
to belong to its stack frame, we must build an explicit
@@ -6117,13 +7521,7 @@ expand_expr (exp, target, tmode, modifier)
if (TREE_OPERAND (exp, 2) == 0)
TREE_OPERAND (exp, 2) = maybe_build_cleanup (slot);
- if (TREE_OPERAND (exp, 2))
- {
- cleanups_this_call = tree_cons (NULL_TREE,
- TREE_OPERAND (exp, 2),
- cleanups_this_call);
- need_exception_region = 1;
- }
+ cleanups = TREE_OPERAND (exp, 2);
}
}
else
@@ -6144,20 +7542,29 @@ expand_expr (exp, target, tmode, modifier)
if (TREE_OPERAND (exp, 1) == NULL_TREE)
return target;
}
-
- DECL_RTL (slot) = target;
+ else
+ {
+ DECL_RTL (slot) = target;
+ /* If we must have an addressable slot, then make sure that
+ the RTL that we just stored in slot is OK. */
+ if (TREE_ADDRESSABLE (slot))
+ {
+ TREE_ADDRESSABLE (slot) = 0;
+ mark_addressable (slot);
+ }
+ }
}
- exp1 = TREE_OPERAND (exp, 1);
+ exp1 = TREE_OPERAND (exp, 3) = TREE_OPERAND (exp, 1);
/* Mark it as expanded. */
TREE_OPERAND (exp, 1) = NULL_TREE;
- temp = expand_expr (exp1, target, tmode, modifier);
+ TREE_USED (slot) = 1;
+ store_expr (exp1, target, 0);
- if (need_exception_region)
- (*interim_eh_hook) (NULL_TREE);
+ expand_decl_cleanup (NULL_TREE, cleanups);
- return temp;
+ return target;
}
case INIT_EXPR:
@@ -6198,7 +7605,9 @@ expand_expr (exp, target, tmode, modifier)
if (TREE_CODE (lhs) != VAR_DECL
&& TREE_CODE (lhs) != RESULT_DECL
- && TREE_CODE (lhs) != PARM_DECL)
+ && TREE_CODE (lhs) != PARM_DECL
+ && ! (TREE_CODE (lhs) == INDIRECT_REF
+ && TYPE_READONLY (TREE_TYPE (TREE_OPERAND (lhs, 0)))))
preexpand_calls (exp);
/* Check for |= or &= of a bitfield of size one into another bitfield
@@ -6250,21 +7659,23 @@ expand_expr (exp, target, tmode, modifier)
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
- return expand_increment (exp, 0);
+ return expand_increment (exp, 0, ignore);
case POSTINCREMENT_EXPR:
case POSTDECREMENT_EXPR:
/* Faster to treat as pre-increment if result is not used. */
- return expand_increment (exp, ! ignore);
+ return expand_increment (exp, ! ignore, ignore);
case ADDR_EXPR:
/* If nonzero, TEMP will be set to the address of something that might
- be a MEM corresponding to a stack slot. */
+ be a MEM corresponding to a stack slot. */
temp = 0;
/* Are we taking the address of a nested function? */
if (TREE_CODE (TREE_OPERAND (exp, 0)) == FUNCTION_DECL
- && decl_function_context (TREE_OPERAND (exp, 0)) != 0)
+ && decl_function_context (TREE_OPERAND (exp, 0)) != 0
+ && ! DECL_NO_STATIC_CHAIN (TREE_OPERAND (exp, 0))
+ && ! TREE_STATIC (exp))
{
op0 = trampoline_address (TREE_OPERAND (exp, 0));
op0 = force_operand (op0, target);
@@ -6288,6 +7699,8 @@ expand_expr (exp, target, tmode, modifier)
if (ignore)
return op0;
+ op0 = protect_from_queue (op0, 0);
+
/* We would like the object in memory. If it is a constant,
we can have it be statically allocated into memory. For
a non-constant (REG, SUBREG or CONCAT), we need to allocate some
@@ -6303,16 +7716,12 @@ expand_expr (exp, target, tmode, modifier)
}
else if (GET_CODE (op0) == REG || GET_CODE (op0) == SUBREG
- || GET_CODE (op0) == CONCAT)
+ || GET_CODE (op0) == CONCAT || GET_CODE (op0) == ADDRESSOF)
{
/* If this object is in a register, it must be not
- be BLKmode. */
+ be BLKmode. */
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
- enum machine_mode inner_mode = TYPE_MODE (inner_type);
- rtx memloc
- = assign_stack_temp (inner_mode,
- int_size_in_bytes (inner_type), 1);
- MEM_IN_STRUCT_P (memloc) = AGGREGATE_TYPE_P (inner_type);
+ rtx memloc = assign_temp (inner_type, 1, 1, 1);
mark_temp_addr_taken (memloc);
emit_move_insn (memloc, op0);
@@ -6339,8 +7748,9 @@ expand_expr (exp, target, tmode, modifier)
if (flag_force_addr && GET_CODE (op0) != REG)
op0 = force_reg (Pmode, op0);
- if (GET_CODE (op0) == REG)
- mark_reg_pointer (op0);
+ if (GET_CODE (op0) == REG
+ && ! REG_USERVAR_P (op0))
+ mark_reg_pointer (op0, TYPE_ALIGN (TREE_TYPE (type)) / BITS_PER_UNIT);
/* If we might have had a temp slot, add an equivalent address
for it. */
@@ -6438,6 +7848,33 @@ expand_expr (exp, target, tmode, modifier)
return target;
}
+ case TRY_CATCH_EXPR:
+ {
+ tree handler = TREE_OPERAND (exp, 1);
+
+ expand_eh_region_start ();
+
+ op0 = expand_expr (TREE_OPERAND (exp, 0), 0, VOIDmode, 0);
+
+ expand_eh_region_end (handler);
+
+ return op0;
+ }
+
+ case POPDCC_EXPR:
+ {
+ rtx dcc = get_dynamic_cleanup_chain ();
+ emit_move_insn (dcc, validize_mem (gen_rtx_MEM (Pmode, dcc)));
+ return const0_rtx;
+ }
+
+ case POPDHC_EXPR:
+ {
+ rtx dhc = get_dynamic_handler_chain ();
+ emit_move_insn (dhc, validize_mem (gen_rtx_MEM (Pmode, dhc)));
+ return const0_rtx;
+ }
+
case ERROR_MARK:
op0 = CONST0_RTX (tmode);
if (op0 != 0)
@@ -6452,7 +7889,7 @@ expand_expr (exp, target, tmode, modifier)
from the optab already placed in `this_optab'. */
binop:
preexpand_calls (exp);
- if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1)))
+ if (! safe_from_p (subtarget, TREE_OPERAND (exp, 1), 1))
subtarget = 0;
op0 = expand_expr (TREE_OPERAND (exp, 0), subtarget, VOIDmode, 0);
op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
@@ -6465,515 +7902,6 @@ expand_expr (exp, target, tmode, modifier)
}
-/* Emit bytecode to evaluate the given expression EXP to the stack. */
-void
-bc_expand_expr (exp)
- tree exp;
-{
- enum tree_code code;
- tree type, arg0;
- rtx r;
- struct binary_operator *binoptab;
- struct unary_operator *unoptab;
- struct increment_operator *incroptab;
- struct bc_label *lab, *lab1;
- enum bytecode_opcode opcode;
-
-
- code = TREE_CODE (exp);
-
- switch (code)
- {
- case PARM_DECL:
-
- if (DECL_RTL (exp) == 0)
- {
- error_with_decl (exp, "prior parameter's size depends on `%s'");
- return;
- }
-
- bc_load_parmaddr (DECL_RTL (exp));
- bc_load_memory (TREE_TYPE (exp), exp);
-
- return;
-
- case VAR_DECL:
-
- if (DECL_RTL (exp) == 0)
- abort ();
-
-#if 0
- if (BYTECODE_LABEL (DECL_RTL (exp)))
- bc_load_externaddr (DECL_RTL (exp));
- else
- bc_load_localaddr (DECL_RTL (exp));
-#endif
- if (TREE_PUBLIC (exp))
- bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp),
- BYTECODE_BC_LABEL (DECL_RTL (exp))->offset);
- else
- bc_load_localaddr (DECL_RTL (exp));
-
- bc_load_memory (TREE_TYPE (exp), exp);
- return;
-
- case INTEGER_CST:
-
-#ifdef DEBUG_PRINT_CODE
- fprintf (stderr, " [%x]\n", TREE_INT_CST_LOW (exp));
-#endif
- bc_emit_instruction (mode_to_const_map[(int) (DECL_BIT_FIELD (exp)
- ? SImode
- : TYPE_MODE (TREE_TYPE (exp)))],
- (HOST_WIDE_INT) TREE_INT_CST_LOW (exp));
- return;
-
- case REAL_CST:
-
-#if 0
-#ifdef DEBUG_PRINT_CODE
- fprintf (stderr, " [%g]\n", (double) TREE_INT_CST_LOW (exp));
-#endif
- /* FIX THIS: find a better way to pass real_cst's. -bson */
- bc_emit_instruction (mode_to_const_map[TYPE_MODE (TREE_TYPE (exp))],
- (double) TREE_REAL_CST (exp));
-#else
- abort ();
-#endif
-
- return;
-
- case CALL_EXPR:
-
- /* We build a call description vector describing the type of
- the return value and of the arguments; this call vector,
- together with a pointer to a location for the return value
- and the base of the argument list, is passed to the low
- level machine dependent call subroutine, which is responsible
- for putting the arguments wherever real functions expect
- them, as well as getting the return value back. */
- {
- tree calldesc = 0, arg;
- int nargs = 0, i;
- rtx retval;
-
- /* Push the evaluated args on the evaluation stack in reverse
- order. Also make an entry for each arg in the calldesc
- vector while we're at it. */
-
- TREE_OPERAND (exp, 1) = nreverse (TREE_OPERAND (exp, 1));
-
- for (arg = TREE_OPERAND (exp, 1); arg; arg = TREE_CHAIN (arg))
- {
- ++nargs;
- bc_expand_expr (TREE_VALUE (arg));
-
- calldesc = tree_cons ((tree) 0,
- size_in_bytes (TREE_TYPE (TREE_VALUE (arg))),
- calldesc);
- calldesc = tree_cons ((tree) 0,
- bc_runtime_type_code (TREE_TYPE (TREE_VALUE (arg))),
- calldesc);
- }
-
- TREE_OPERAND (exp, 1) = nreverse (TREE_OPERAND (exp, 1));
-
- /* Allocate a location for the return value and push its
- address on the evaluation stack. Also make an entry
- at the front of the calldesc for the return value type. */
-
- type = TREE_TYPE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))));
- retval = bc_allocate_local (int_size_in_bytes (type), TYPE_ALIGN (type));
- bc_load_localaddr (retval);
-
- calldesc = tree_cons ((tree) 0, size_in_bytes (type), calldesc);
- calldesc = tree_cons ((tree) 0, bc_runtime_type_code (type), calldesc);
-
- /* Prepend the argument count. */
- calldesc = tree_cons ((tree) 0,
- build_int_2 (nargs, 0),
- calldesc);
-
- /* Push the address of the call description vector on the stack. */
- calldesc = build_nt (CONSTRUCTOR, (tree) 0, calldesc);
- TREE_TYPE (calldesc) = build_array_type (integer_type_node,
- build_index_type (build_int_2 (nargs * 2, 0)));
- r = output_constant_def (calldesc);
- bc_load_externaddr (r);
-
- /* Push the address of the function to be called. */
- bc_expand_expr (TREE_OPERAND (exp, 0));
-
- /* Call the function, popping its address and the calldesc vector
- address off the evaluation stack in the process. */
- bc_emit_instruction (call);
-
- /* Pop the arguments off the stack. */
- bc_adjust_stack (nargs);
-
- /* Load the return value onto the stack. */
- bc_load_localaddr (retval);
- bc_load_memory (type, TREE_OPERAND (exp, 0));
- }
- return;
-
- case SAVE_EXPR:
-
- if (!SAVE_EXPR_RTL (exp))
- {
- /* First time around: copy to local variable */
- SAVE_EXPR_RTL (exp) = bc_allocate_local (int_size_in_bytes (TREE_TYPE (exp)),
- TYPE_ALIGN (TREE_TYPE(exp)));
- bc_expand_expr (TREE_OPERAND (exp, 0));
- bc_emit_instruction (duplicate);
-
- bc_load_localaddr (SAVE_EXPR_RTL (exp));
- bc_store_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
- }
- else
- {
- /* Consecutive reference: use saved copy */
- bc_load_localaddr (SAVE_EXPR_RTL (exp));
- bc_load_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
- }
- return;
-
-#if 0
- /* FIXME: the XXXX_STMT codes have been removed in GCC2, but
- how are they handled instead? */
- case LET_STMT:
-
- TREE_USED (exp) = 1;
- bc_expand_expr (STMT_BODY (exp));
- return;
-#endif
-
- case NOP_EXPR:
- case CONVERT_EXPR:
-
- bc_expand_expr (TREE_OPERAND (exp, 0));
- bc_expand_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)), TREE_TYPE (exp));
- return;
-
- case MODIFY_EXPR:
-
- expand_assignment (TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1), 0, 0);
- return;
-
- case ADDR_EXPR:
-
- bc_expand_address (TREE_OPERAND (exp, 0));
- return;
-
- case INDIRECT_REF:
-
- bc_expand_expr (TREE_OPERAND (exp, 0));
- bc_load_memory (TREE_TYPE (exp), TREE_OPERAND (exp, 0));
- return;
-
- case ARRAY_REF:
-
- bc_expand_expr (bc_canonicalize_array_ref (exp));
- return;
-
- case COMPONENT_REF:
-
- bc_expand_component_address (exp);
-
- /* If we have a bitfield, generate a proper load */
- bc_load_memory (TREE_TYPE (TREE_OPERAND (exp, 1)), TREE_OPERAND (exp, 1));
- return;
-
- case COMPOUND_EXPR:
-
- bc_expand_expr (TREE_OPERAND (exp, 0));
- bc_emit_instruction (drop);
- bc_expand_expr (TREE_OPERAND (exp, 1));
- return;
-
- case COND_EXPR:
-
- bc_expand_expr (TREE_OPERAND (exp, 0));
- bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)));
- lab = bc_get_bytecode_label ();
- bc_emit_bytecode (xjumpifnot);
- bc_emit_bytecode_labelref (lab);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
- bc_expand_expr (TREE_OPERAND (exp, 1));
- lab1 = bc_get_bytecode_label ();
- bc_emit_bytecode (jump);
- bc_emit_bytecode_labelref (lab1);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-
- bc_emit_bytecode_labeldef (lab);
- bc_expand_expr (TREE_OPERAND (exp, 2));
- bc_emit_bytecode_labeldef (lab1);
- return;
-
- case TRUTH_ANDIF_EXPR:
-
- opcode = xjumpifnot;
- goto andorif;
-
- case TRUTH_ORIF_EXPR:
-
- opcode = xjumpif;
- goto andorif;
-
- case PLUS_EXPR:
-
- binoptab = optab_plus_expr;
- goto binop;
-
- case MINUS_EXPR:
-
- binoptab = optab_minus_expr;
- goto binop;
-
- case MULT_EXPR:
-
- binoptab = optab_mult_expr;
- goto binop;
-
- case TRUNC_DIV_EXPR:
- case FLOOR_DIV_EXPR:
- case CEIL_DIV_EXPR:
- case ROUND_DIV_EXPR:
- case EXACT_DIV_EXPR:
-
- binoptab = optab_trunc_div_expr;
- goto binop;
-
- case TRUNC_MOD_EXPR:
- case FLOOR_MOD_EXPR:
- case CEIL_MOD_EXPR:
- case ROUND_MOD_EXPR:
-
- binoptab = optab_trunc_mod_expr;
- goto binop;
-
- case FIX_ROUND_EXPR:
- case FIX_FLOOR_EXPR:
- case FIX_CEIL_EXPR:
- abort (); /* Not used for C. */
-
- case FIX_TRUNC_EXPR:
- case FLOAT_EXPR:
- case MAX_EXPR:
- case MIN_EXPR:
- case FFS_EXPR:
- case LROTATE_EXPR:
- case RROTATE_EXPR:
- abort (); /* FIXME */
-
- case RDIV_EXPR:
-
- binoptab = optab_rdiv_expr;
- goto binop;
-
- case BIT_AND_EXPR:
-
- binoptab = optab_bit_and_expr;
- goto binop;
-
- case BIT_IOR_EXPR:
-
- binoptab = optab_bit_ior_expr;
- goto binop;
-
- case BIT_XOR_EXPR:
-
- binoptab = optab_bit_xor_expr;
- goto binop;
-
- case LSHIFT_EXPR:
-
- binoptab = optab_lshift_expr;
- goto binop;
-
- case RSHIFT_EXPR:
-
- binoptab = optab_rshift_expr;
- goto binop;
-
- case TRUTH_AND_EXPR:
-
- binoptab = optab_truth_and_expr;
- goto binop;
-
- case TRUTH_OR_EXPR:
-
- binoptab = optab_truth_or_expr;
- goto binop;
-
- case LT_EXPR:
-
- binoptab = optab_lt_expr;
- goto binop;
-
- case LE_EXPR:
-
- binoptab = optab_le_expr;
- goto binop;
-
- case GE_EXPR:
-
- binoptab = optab_ge_expr;
- goto binop;
-
- case GT_EXPR:
-
- binoptab = optab_gt_expr;
- goto binop;
-
- case EQ_EXPR:
-
- binoptab = optab_eq_expr;
- goto binop;
-
- case NE_EXPR:
-
- binoptab = optab_ne_expr;
- goto binop;
-
- case NEGATE_EXPR:
-
- unoptab = optab_negate_expr;
- goto unop;
-
- case BIT_NOT_EXPR:
-
- unoptab = optab_bit_not_expr;
- goto unop;
-
- case TRUTH_NOT_EXPR:
-
- unoptab = optab_truth_not_expr;
- goto unop;
-
- case PREDECREMENT_EXPR:
-
- incroptab = optab_predecrement_expr;
- goto increment;
-
- case PREINCREMENT_EXPR:
-
- incroptab = optab_preincrement_expr;
- goto increment;
-
- case POSTDECREMENT_EXPR:
-
- incroptab = optab_postdecrement_expr;
- goto increment;
-
- case POSTINCREMENT_EXPR:
-
- incroptab = optab_postincrement_expr;
- goto increment;
-
- case CONSTRUCTOR:
-
- bc_expand_constructor (exp);
- return;
-
- case ERROR_MARK:
- case RTL_EXPR:
-
- return;
-
- case BIND_EXPR:
- {
- tree vars = TREE_OPERAND (exp, 0);
- int vars_need_expansion = 0;
-
- /* Need to open a binding contour here because
- if there are any cleanups they most be contained here. */
- expand_start_bindings (0);
-
- /* Mark the corresponding BLOCK for output. */
- if (TREE_OPERAND (exp, 2) != 0)
- TREE_USED (TREE_OPERAND (exp, 2)) = 1;
-
- /* If VARS have not yet been expanded, expand them now. */
- while (vars)
- {
- if (DECL_RTL (vars) == 0)
- {
- vars_need_expansion = 1;
- expand_decl (vars);
- }
- expand_decl_init (vars);
- vars = TREE_CHAIN (vars);
- }
-
- bc_expand_expr (TREE_OPERAND (exp, 1));
-
- expand_end_bindings (TREE_OPERAND (exp, 0), 0, 0);
-
- return;
- }
- }
-
- abort ();
-
- binop:
-
- bc_expand_binary_operation (binoptab, TREE_TYPE (exp),
- TREE_OPERAND (exp, 0), TREE_OPERAND (exp, 1));
- return;
-
-
- unop:
-
- bc_expand_unary_operation (unoptab, TREE_TYPE (exp), TREE_OPERAND (exp, 0));
- return;
-
-
- andorif:
-
- bc_expand_expr (TREE_OPERAND (exp, 0));
- bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 0)));
- lab = bc_get_bytecode_label ();
-
- bc_emit_instruction (duplicate);
- bc_emit_bytecode (opcode);
- bc_emit_bytecode_labelref (lab);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-
- bc_emit_instruction (drop);
-
- bc_expand_expr (TREE_OPERAND (exp, 1));
- bc_expand_truth_conversion (TREE_TYPE (TREE_OPERAND (exp, 1)));
- bc_emit_bytecode_labeldef (lab);
- return;
-
-
- increment:
-
- type = TREE_TYPE (TREE_OPERAND (exp, 0));
-
- /* Push the quantum. */
- bc_expand_expr (TREE_OPERAND (exp, 1));
-
- /* Convert it to the lvalue's type. */
- bc_expand_conversion (TREE_TYPE (TREE_OPERAND (exp, 1)), type);
-
- /* Push the address of the lvalue */
- bc_expand_expr (build1 (ADDR_EXPR, TYPE_POINTER_TO (type), TREE_OPERAND (exp, 0)));
-
- /* Perform actual increment */
- bc_expand_increment (incroptab, type);
- return;
-}
/* Return the alignment in bits of EXP, a pointer valued expression.
But don't return more than MAX_ALIGN no matter what.
@@ -7154,8 +8082,8 @@ c_strlen (src)
rtx
expand_builtin_return_addr (fndecl_code, count, tem)
enum built_in_function fndecl_code;
- rtx tem;
int count;
+ rtx tem;
{
int i;
@@ -7163,7 +8091,8 @@ expand_builtin_return_addr (fndecl_code, count, tem)
arbitrary frames. For example, on the sparc, we must first flush
all register windows to the stack. */
#ifdef SETUP_FRAME_ADDRESSES
- SETUP_FRAME_ADDRESSES ();
+ if (count > 0)
+ SETUP_FRAME_ADDRESSES ();
#endif
/* On the sparc, the return address is not in the frame, it is in a
@@ -7184,7 +8113,7 @@ expand_builtin_return_addr (fndecl_code, count, tem)
tem = DYNAMIC_CHAIN_ADDRESS (tem);
#endif
tem = memory_address (Pmode, tem);
- tem = copy_to_reg (gen_rtx (MEM, Pmode, tem));
+ tem = copy_to_reg (gen_rtx_MEM (Pmode, tem));
}
/* For __builtin_frame_address, return what we've got. */
@@ -7198,10 +8127,252 @@ expand_builtin_return_addr (fndecl_code, count, tem)
#else
tem = memory_address (Pmode,
plus_constant (tem, GET_MODE_SIZE (Pmode)));
- tem = gen_rtx (MEM, Pmode, tem);
+ tem = gen_rtx_MEM (Pmode, tem);
#endif
return tem;
}
+
+/* __builtin_setjmp is passed a pointer to an array of five words (not
+ all will be used on all machines). It operates similarly to the C
+ library function of the same name, but is more efficient. Much of
+ the code below (and for longjmp) is copied from the handling of
+ non-local gotos.
+
+ NOTE: This is intended for use by GNAT and the exception handling
+ scheme in the compiler and will only work in the method used by
+ them. */
+
+rtx
+expand_builtin_setjmp (buf_addr, target, first_label, next_label)
+ rtx buf_addr;
+ rtx target;
+ rtx first_label, next_label;
+{
+ rtx lab1 = gen_label_rtx ();
+ enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
+ enum machine_mode value_mode;
+ rtx stack_save;
+
+ value_mode = TYPE_MODE (integer_type_node);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+ buf_addr = convert_memory_address (Pmode, buf_addr);
+#endif
+
+ buf_addr = force_reg (Pmode, buf_addr);
+
+ if (target == 0 || GET_CODE (target) != REG
+ || REGNO (target) < FIRST_PSEUDO_REGISTER)
+ target = gen_reg_rtx (value_mode);
+
+ emit_queue ();
+
+ /* We store the frame pointer and the address of lab1 in the buffer
+ and use the rest of it for the stack save area, which is
+ machine-dependent. */
+
+#ifndef BUILTIN_SETJMP_FRAME_VALUE
+#define BUILTIN_SETJMP_FRAME_VALUE virtual_stack_vars_rtx
+#endif
+
+ emit_move_insn (gen_rtx_MEM (Pmode, buf_addr),
+ BUILTIN_SETJMP_FRAME_VALUE);
+ emit_move_insn (validize_mem
+ (gen_rtx_MEM (Pmode,
+ plus_constant (buf_addr,
+ GET_MODE_SIZE (Pmode)))),
+ gen_rtx_LABEL_REF (Pmode, lab1));
+
+ stack_save = gen_rtx_MEM (sa_mode,
+ plus_constant (buf_addr,
+ 2 * GET_MODE_SIZE (Pmode)));
+ emit_stack_save (SAVE_NONLOCAL, &stack_save, NULL_RTX);
+
+ /* If there is further processing to do, do it. */
+#ifdef HAVE_builtin_setjmp_setup
+ if (HAVE_builtin_setjmp_setup)
+ emit_insn (gen_builtin_setjmp_setup (buf_addr));
+#endif
+
+ /* Set TARGET to zero and branch to the first-time-through label. */
+ emit_move_insn (target, const0_rtx);
+ emit_jump_insn (gen_jump (first_label));
+ emit_barrier ();
+ emit_label (lab1);
+
+ /* Tell flow about the strange goings on. */
+ current_function_has_nonlocal_label = 1;
+
+ /* Clobber the FP when we get here, so we have to make sure it's
+ marked as used by this function. */
+ emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
+
+ /* Mark the static chain as clobbered here so life information
+ doesn't get messed up for it. */
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, static_chain_rtx));
+
+ /* Now put in the code to restore the frame pointer, and argument
+ pointer, if needed. The code below is from expand_end_bindings
+ in stmt.c; see detailed documentation there. */
+#ifdef HAVE_nonlocal_goto
+ if (! HAVE_nonlocal_goto)
+#endif
+ emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
+
+#if ARG_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
+ if (fixed_regs[ARG_POINTER_REGNUM])
+ {
+#ifdef ELIMINABLE_REGS
+ int i;
+ static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
+
+ for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
+ if (elim_regs[i].from == ARG_POINTER_REGNUM
+ && elim_regs[i].to == HARD_FRAME_POINTER_REGNUM)
+ break;
+
+ if (i == sizeof elim_regs / sizeof elim_regs [0])
+#endif
+ {
+ /* Now restore our arg pointer from the address at which it
+ was saved in our stack frame.
+ If there hasn't be space allocated for it yet, make
+ some now. */
+ if (arg_pointer_save_area == 0)
+ arg_pointer_save_area
+ = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
+ emit_move_insn (virtual_incoming_args_rtx,
+ copy_to_reg (arg_pointer_save_area));
+ }
+ }
+#endif
+
+#ifdef HAVE_builtin_setjmp_receiver
+ if (HAVE_builtin_setjmp_receiver)
+ emit_insn (gen_builtin_setjmp_receiver (lab1));
+ else
+#endif
+#ifdef HAVE_nonlocal_goto_receiver
+ if (HAVE_nonlocal_goto_receiver)
+ emit_insn (gen_nonlocal_goto_receiver ());
+ else
+#endif
+ {
+ ; /* Nothing */
+ }
+
+ /* Set TARGET, and branch to the next-time-through label. */
+ emit_move_insn (target, const1_rtx);
+ emit_jump_insn (gen_jump (next_label));
+ emit_barrier ();
+
+ return target;
+}
+
+void
+expand_builtin_longjmp (buf_addr, value)
+ rtx buf_addr, value;
+{
+ rtx fp, lab, stack;
+ enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+ buf_addr = convert_memory_address (Pmode, buf_addr);
+#endif
+ buf_addr = force_reg (Pmode, buf_addr);
+
+ /* We used to store value in static_chain_rtx, but that fails if pointers
+ are smaller than integers. We instead require that the user must pass
+ a second argument of 1, because that is what builtin_setjmp will
+ return. This also makes EH slightly more efficient, since we are no
+ longer copying around a value that we don't care about. */
+ if (value != const1_rtx)
+ abort ();
+
+#ifdef HAVE_builtin_longjmp
+ if (HAVE_builtin_longjmp)
+ emit_insn (gen_builtin_longjmp (buf_addr));
+ else
+#endif
+ {
+ fp = gen_rtx_MEM (Pmode, buf_addr);
+ lab = gen_rtx_MEM (Pmode, plus_constant (buf_addr,
+ GET_MODE_SIZE (Pmode)));
+
+ stack = gen_rtx_MEM (sa_mode, plus_constant (buf_addr,
+ 2 * GET_MODE_SIZE (Pmode)));
+
+ /* Pick up FP, label, and SP from the block and jump. This code is
+ from expand_goto in stmt.c; see there for detailed comments. */
+#if HAVE_nonlocal_goto
+ if (HAVE_nonlocal_goto)
+ /* We have to pass a value to the nonlocal_goto pattern that will
+ get copied into the static_chain pointer, but it does not matter
+ what that value is, because builtin_setjmp does not use it. */
+ emit_insn (gen_nonlocal_goto (value, fp, stack, lab));
+ else
+#endif
+ {
+ lab = copy_to_reg (lab);
+
+ emit_move_insn (hard_frame_pointer_rtx, fp);
+ emit_stack_restore (SAVE_NONLOCAL, stack, NULL_RTX);
+
+ emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
+ emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
+ emit_indirect_jump (lab);
+ }
+ }
+}
+
+static rtx
+get_memory_rtx (exp)
+ tree exp;
+{
+ rtx mem;
+ int is_aggregate;
+
+ mem = gen_rtx_MEM (BLKmode,
+ memory_address (BLKmode,
+ expand_expr (exp, NULL_RTX,
+ ptr_mode, EXPAND_SUM)));
+
+ RTX_UNCHANGING_P (mem) = TREE_READONLY (exp);
+
+ /* Figure out the type of the object pointed to. Set MEM_IN_STRUCT_P
+ if the value is the address of a structure or if the expression is
+ cast to a pointer to structure type. */
+ is_aggregate = 0;
+
+ while (TREE_CODE (exp) == NOP_EXPR)
+ {
+ tree cast_type = TREE_TYPE (exp);
+ if (TREE_CODE (cast_type) == POINTER_TYPE
+ && AGGREGATE_TYPE_P (TREE_TYPE (cast_type)))
+ {
+ is_aggregate = 1;
+ break;
+ }
+ exp = TREE_OPERAND (exp, 0);
+ }
+
+ if (is_aggregate == 0)
+ {
+ tree type;
+
+ if (TREE_CODE (exp) == ADDR_EXPR)
+ /* If this is the address of an object, check whether the
+ object is an array. */
+ type = TREE_TYPE (TREE_OPERAND (exp, 0));
+ else
+ type = TREE_TYPE (TREE_TYPE (exp));
+ is_aggregate = AGGREGATE_TYPE_P (type);
+ }
+
+ MEM_IN_STRUCT_P (mem) = is_aggregate;
+ return mem;
+}
+
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
@@ -7237,7 +8408,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
case BUILT_IN_SIN:
case BUILT_IN_COS:
- /* Treat these like sqrt, but only if the user asks for them. */
+ /* Treat these like sqrt, but only if the user asks for them. */
if (! flag_fast_math)
break;
case BUILT_IN_FSQRT:
@@ -7286,7 +8457,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
/* If we were unable to expand via the builtin, stop the
sequence (without outputting the insns) and break, causing
- a call the the library function. */
+ a call to the library function. */
if (target == 0)
{
end_sequence ();
@@ -7316,14 +8487,14 @@ expand_builtin (exp, target, subtarget, mode, ignore)
rtx errno_rtx = GEN_ERRNO_RTX;
#else
rtx errno_rtx
- = gen_rtx (MEM, word_mode, gen_rtx (SYMBOL_REF, Pmode, "errno"));
+ = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
#endif
emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
}
#else
/* We can't set errno=EDOM directly; let the library call do it.
- Pop the arguments right away in case the call gets deleted. */
+ Pop the arguments right away in case the call gets deleted. */
NO_DEFER_POP;
expand_call (exp, target, 0);
OK_DEFER_POP;
@@ -7332,13 +8503,16 @@ expand_builtin (exp, target, subtarget, mode, ignore)
emit_label (lab1);
}
- /* Output the entire sequence. */
+ /* Output the entire sequence. */
insns = get_insns ();
end_sequence ();
emit_insns (insns);
return target;
+ case BUILT_IN_FMOD:
+ break;
+
/* __builtin_apply_args returns block of memory allocated on
the stack into which is stored the arg pointer, structure
value address, static chain, and all the registers that might
@@ -7387,7 +8561,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
case BUILT_IN_APPLY:
if (arglist == 0
/* Arg could be non-pointer if user redeclared this fcn wrong. */
- || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+ || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
|| TREE_CHAIN (arglist) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
|| TREE_CHAIN (TREE_CHAIN (arglist)) == 0
@@ -7475,9 +8649,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
case BUILT_IN_ARGS_INFO:
{
int nwords = sizeof (CUMULATIVE_ARGS) / sizeof (int);
- int i;
int *word_ptr = (int *) &current_function_args_info;
+#if 0
+ /* These are used by the code below that is if 0'ed away */
+ int i;
tree type, elts, result;
+#endif
if (sizeof (CUMULATIVE_ARGS) % sizeof (int) != 0)
fatal ("CUMULATIVE_ARGS type defined badly; see %s, line %d",
@@ -7514,7 +8691,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
TREE_STATIC (result) = 1;
result = build (INDIRECT_REF, build_pointer_type (type), result);
TREE_CONSTANT (result) = 1;
- return expand_expr (result, NULL_RTX, VOIDmode, 0);
+ return expand_expr (result, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD);
#endif
}
@@ -7538,10 +8715,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
tree arg = TREE_VALUE (arglist);
/* Strip off all nops for the sake of the comparison. This
- is not quite the same as STRIP_NOPS. It does more. */
+ is not quite the same as STRIP_NOPS. It does more.
+ We must also strip off INDIRECT_EXPR for C++ reference
+ parameters. */
while (TREE_CODE (arg) == NOP_EXPR
|| TREE_CODE (arg) == CONVERT_EXPR
- || TREE_CODE (arg) == NON_LVALUE_EXPR)
+ || TREE_CODE (arg) == NON_LVALUE_EXPR
+ || TREE_CODE (arg) == INDIRECT_REF)
arg = TREE_OPERAND (arg, 0);
if (arg != last_parm)
warning ("second parameter of `va_start' not last named argument");
@@ -7614,10 +8794,34 @@ expand_builtin (exp, target, subtarget, mode, ignore)
tree arg = TREE_VALUE (arglist);
STRIP_NOPS (arg);
- return (TREE_CODE_CLASS (TREE_CODE (arg)) == 'c'
- || (TREE_CODE (arg) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST)
- ? const1_rtx : const0_rtx);
+ if (really_constant_p (arg)
+ || (TREE_CODE (arg) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (arg, 0)) == STRING_CST))
+ return const1_rtx;
+
+ /* Only emit CONSTANT_P_RTX if CSE will be run.
+ Moreover, we don't want to expand trees that have side effects,
+ as the original __builtin_constant_p did not evaluate its
+ argument at all, and we would break existing usage by changing
+ this. This quirk was generally useful, eliminating a bit of hair
+ in the writing of the macros that use this function. Now the
+ same thing can be better accomplished in an inline function. */
+
+ if (! cse_not_expected && ! TREE_SIDE_EFFECTS (arg))
+ {
+ /* Lazy fixup of old code: issue a warning and fail the test. */
+ if (! can_handle_constant_p)
+ {
+ warning ("Delayed evaluation of __builtin_constant_p not supported on this target.");
+ warning ("Please report this as a bug to egcs-bugs@egcs.cygnus.com.");
+ return const0_rtx;
+ }
+ return gen_rtx_CONSTANT_P_RTX (TYPE_MODE (integer_type_node),
+ expand_expr (arg, NULL_RTX,
+ VOIDmode, 0));
+ }
+
+ return const0_rtx;
}
case BUILT_IN_FRAME_ADDRESS:
@@ -7631,14 +8835,13 @@ expand_builtin (exp, target, subtarget, mode, ignore)
if (arglist == 0)
/* Warning about missing arg was already issued. */
return const0_rtx;
- else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST)
- {
- error ("invalid arg to `__builtin_return_address'");
- return const0_rtx;
- }
- else if (tree_int_cst_sgn (TREE_VALUE (arglist)) < 0)
+ else if (TREE_CODE (TREE_VALUE (arglist)) != INTEGER_CST
+ || tree_int_cst_sgn (TREE_VALUE (arglist)) < 0)
{
- error ("invalid arg to `__builtin_return_address'");
+ if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
+ error ("invalid arg to `__builtin_frame_address'");
+ else
+ error ("invalid arg to `__builtin_return_address'");
return const0_rtx;
}
else
@@ -7647,6 +8850,16 @@ expand_builtin (exp, target, subtarget, mode, ignore)
TREE_INT_CST_LOW (TREE_VALUE (arglist)),
hard_frame_pointer_rtx);
+ /* Some ports cannot access arbitrary stack frames. */
+ if (tem == NULL)
+ {
+ if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
+ warning ("unsupported arg to `__builtin_frame_address'");
+ else
+ warning ("unsupported arg to `__builtin_return_address'");
+ return const0_rtx;
+ }
+
/* For __builtin_frame_address, return what we've got. */
if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS)
return tem;
@@ -7656,6 +8869,16 @@ expand_builtin (exp, target, subtarget, mode, ignore)
return tem;
}
+ /* Returns the address of the area where the structure is returned.
+ 0 otherwise. */
+ case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
+ if (arglist != 0
+ || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
+ || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
+ return const0_rtx;
+ else
+ return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
+
case BUILT_IN_ALLOCA:
if (arglist == 0
/* Arg could be non-integer if user redeclared this fcn wrong. */
@@ -7709,15 +8932,15 @@ expand_builtin (exp, target, subtarget, mode, ignore)
enum machine_mode insn_mode = value_mode, char_mode;
enum insn_code icode;
- /* If the length is known, just return it. */
+ /* If the length is known, just return it. */
if (len != 0)
- return expand_expr (len, target, mode, 0);
+ return expand_expr (len, target, mode, EXPAND_MEMORY_USE_BAD);
- /* If SRC is not a pointer type, don't do this operation inline. */
+ /* If SRC is not a pointer type, don't do this operation inline. */
if (align == 0)
break;
- /* Call a function if we can't compute strlen in the right mode. */
+ /* Call a function if we can't compute strlen in the right mode. */
while (insn_mode != VOIDmode)
{
@@ -7742,20 +8965,27 @@ expand_builtin (exp, target, subtarget, mode, ignore)
if (! (*insn_operand_predicate[(int)icode][0]) (result, insn_mode))
result = gen_reg_rtx (insn_mode);
-
src_rtx = memory_address (BLKmode,
expand_expr (src, NULL_RTX, ptr_mode,
EXPAND_NORMAL));
+
if (! (*insn_operand_predicate[(int)icode][1]) (src_rtx, Pmode))
src_rtx = copy_to_mode_reg (Pmode, src_rtx);
+ /* Check the string is readable and has an end. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_check_str_libfunc, 1, VOIDmode, 2,
+ src_rtx, ptr_mode,
+ GEN_INT (MEMORY_USE_RO),
+ TYPE_MODE (integer_type_node));
+
char_rtx = const0_rtx;
char_mode = insn_operand_mode[(int)icode][2];
if (! (*insn_operand_predicate[(int)icode][2]) (char_rtx, char_mode))
char_rtx = copy_to_mode_reg (char_mode, char_rtx);
emit_insn (GEN_FCN (icode) (result,
- gen_rtx (MEM, BLKmode, src_rtx),
+ gen_rtx_MEM (BLKmode, src_rtx),
char_rtx, GEN_INT (align)));
/* Return the value in the proper mode for this function. */
@@ -7803,22 +9033,24 @@ expand_builtin (exp, target, subtarget, mode, ignore)
/* Arg could be non-pointer if user redeclared this fcn wrong. */
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
- || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
+ || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
+ != POINTER_TYPE)
|| TREE_CHAIN (TREE_CHAIN (arglist)) == 0
- || TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
+ || (TREE_CODE (TREE_TYPE (TREE_VALUE
+ (TREE_CHAIN (TREE_CHAIN (arglist)))))
+ != INTEGER_TYPE))
break;
else
{
tree dest = TREE_VALUE (arglist);
tree src = TREE_VALUE (TREE_CHAIN (arglist));
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
- tree type;
int src_align
= get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
int dest_align
= get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
- rtx dest_rtx, dest_mem, src_mem;
+ rtx dest_mem, src_mem, dest_addr, len_rtx;
/* If either SRC or DEST is not a pointer type, don't do
this operation in-line. */
@@ -7829,30 +9061,96 @@ expand_builtin (exp, target, subtarget, mode, ignore)
break;
}
- dest_rtx = expand_expr (dest, NULL_RTX, ptr_mode, EXPAND_SUM);
- dest_mem = gen_rtx (MEM, BLKmode,
- memory_address (BLKmode, dest_rtx));
- /* There could be a void* cast on top of the object. */
- while (TREE_CODE (dest) == NOP_EXPR)
- dest = TREE_OPERAND (dest, 0);
- type = TREE_TYPE (TREE_TYPE (dest));
- MEM_IN_STRUCT_P (dest_mem) = AGGREGATE_TYPE_P (type);
- src_mem = gen_rtx (MEM, BLKmode,
- memory_address (BLKmode,
- expand_expr (src, NULL_RTX,
- ptr_mode,
- EXPAND_SUM)));
- /* There could be a void* cast on top of the object. */
- while (TREE_CODE (src) == NOP_EXPR)
- src = TREE_OPERAND (src, 0);
- type = TREE_TYPE (TREE_TYPE (src));
- MEM_IN_STRUCT_P (src_mem) = AGGREGATE_TYPE_P (type);
+ dest_mem = get_memory_rtx (dest);
+ src_mem = get_memory_rtx (src);
+ len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+
+ /* Just copy the rights of SRC to the rights of DEST. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_copy_bitmap_libfunc, 1, VOIDmode, 3,
+ XEXP (dest_mem, 0), ptr_mode,
+ XEXP (src_mem, 0), ptr_mode,
+ len_rtx, TYPE_MODE (sizetype));
/* Copy word part most expediently. */
- emit_block_move (dest_mem, src_mem,
- expand_expr (len, NULL_RTX, VOIDmode, 0),
- MIN (src_align, dest_align));
- return force_operand (dest_rtx, NULL_RTX);
+ dest_addr
+ = emit_block_move (dest_mem, src_mem, len_rtx,
+ MIN (src_align, dest_align));
+
+ if (dest_addr == 0)
+ dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+
+ return dest_addr;
+ }
+
+ case BUILT_IN_MEMSET:
+ /* If not optimizing, call the library function. */
+ if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
+ break;
+
+ if (arglist == 0
+ /* Arg could be non-pointer if user redeclared this fcn wrong. */
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
+ || TREE_CHAIN (arglist) == 0
+ || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
+ != INTEGER_TYPE)
+ || TREE_CHAIN (TREE_CHAIN (arglist)) == 0
+ || (INTEGER_TYPE
+ != (TREE_CODE (TREE_TYPE
+ (TREE_VALUE
+ (TREE_CHAIN (TREE_CHAIN (arglist))))))))
+ break;
+ else
+ {
+ tree dest = TREE_VALUE (arglist);
+ tree val = TREE_VALUE (TREE_CHAIN (arglist));
+ tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+ int dest_align
+ = get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
+ rtx dest_mem, dest_addr, len_rtx;
+
+ /* If DEST is not a pointer type, don't do this
+ operation in-line. */
+ if (dest_align == 0)
+ break;
+
+ /* If the arguments have side-effects, then we can only evaluate
+ them at most once. The following code evaluates them twice if
+ they are not constants because we break out to expand_call
+ in that case. They can't be constants if they have side-effects
+ so we can check for that first. Alternatively, we could call
+ save_expr to make multiple evaluation safe. */
+ if (TREE_SIDE_EFFECTS (val) || TREE_SIDE_EFFECTS (len))
+ break;
+
+ /* If VAL is not 0, don't do this operation in-line. */
+ if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx)
+ break;
+
+ /* If LEN does not expand to a constant, don't do this
+ operation in-line. */
+ len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+ if (GET_CODE (len_rtx) != CONST_INT)
+ break;
+
+ dest_mem = get_memory_rtx (dest);
+
+ /* Just check DST is writable and mark it as readable. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_check_addr_libfunc, 1, VOIDmode, 3,
+ XEXP (dest_mem, 0), ptr_mode,
+ len_rtx, TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_WO),
+ TYPE_MODE (integer_type_node));
+
+
+ dest_addr = clear_storage (dest_mem, len_rtx, dest_align);
+
+ if (dest_addr == 0)
+ dest_addr = force_operand (XEXP (dest_mem, 0), NULL_RTX);
+
+ return dest_addr;
}
/* These comparison functions need an instruction that returns an actual
@@ -7864,6 +9162,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
+ /* If we need to check memory accesses, call the library function. */
+ if (flag_check_memory_usage)
+ break;
+
if (arglist == 0
/* Arg could be non-pointer if user redeclared this fcn wrong. */
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
@@ -7875,7 +9177,6 @@ expand_builtin (exp, target, subtarget, mode, ignore)
{
tree arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
- tree offset;
tree len, len2;
len = c_strlen (arg1);
@@ -7917,6 +9218,10 @@ expand_builtin (exp, target, subtarget, mode, ignore)
if (!optimize && ! CALLED_AS_BUILT_IN (fndecl))
break;
+ /* If we need to check memory accesses, call the library function. */
+ if (flag_check_memory_usage)
+ break;
+
if (arglist == 0
/* Arg could be non-pointer if user redeclared this fcn wrong. */
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
@@ -7955,15 +9260,8 @@ expand_builtin (exp, target, subtarget, mode, ignore)
&& REGNO (result) >= FIRST_PSEUDO_REGISTER))
result = gen_reg_rtx (insn_mode);
- emit_insn (gen_cmpstrsi (result,
- gen_rtx (MEM, BLKmode,
- expand_expr (arg1, NULL_RTX,
- ptr_mode,
- EXPAND_NORMAL)),
- gen_rtx (MEM, BLKmode,
- expand_expr (arg2, NULL_RTX,
- ptr_mode,
- EXPAND_NORMAL)),
+ emit_insn (gen_cmpstrsi (result, get_memory_rtx (arg1),
+ get_memory_rtx (arg2),
expand_expr (len, NULL_RTX, VOIDmode, 0),
GEN_INT (MIN (arg1_align, arg2_align))));
@@ -7985,6 +9283,84 @@ expand_builtin (exp, target, subtarget, mode, ignore)
break;
#endif
+ case BUILT_IN_SETJMP:
+ if (arglist == 0
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
+ break;
+ else
+ {
+ rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
+ VOIDmode, 0);
+ rtx lab = gen_label_rtx ();
+ rtx ret = expand_builtin_setjmp (buf_addr, target, lab, lab);
+ emit_label (lab);
+ return ret;
+ }
+
+ /* __builtin_longjmp is passed a pointer to an array of five words.
+ It's similar to the C library longjmp function but works with
+ __builtin_setjmp above. */
+ case BUILT_IN_LONGJMP:
+ if (arglist == 0 || TREE_CHAIN (arglist) == 0
+ || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
+ break;
+ else
+ {
+ rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
+ VOIDmode, 0);
+ rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)),
+ NULL_RTX, VOIDmode, 0);
+
+ if (value != const1_rtx)
+ {
+ error ("__builtin_longjmp second argument must be 1");
+ return const0_rtx;
+ }
+
+ expand_builtin_longjmp (buf_addr, value);
+ return const0_rtx;
+ }
+
+ case BUILT_IN_TRAP:
+#ifdef HAVE_trap
+ if (HAVE_trap)
+ emit_insn (gen_trap ());
+ else
+#endif
+ error ("__builtin_trap not supported by this target");
+ emit_barrier ();
+ return const0_rtx;
+
+ /* Various hooks for the DWARF 2 __throw routine. */
+ case BUILT_IN_UNWIND_INIT:
+ expand_builtin_unwind_init ();
+ return const0_rtx;
+ case BUILT_IN_FP:
+ return frame_pointer_rtx;
+ case BUILT_IN_SP:
+ return stack_pointer_rtx;
+#ifdef DWARF2_UNWIND_INFO
+ case BUILT_IN_DWARF_FP_REGNUM:
+ return expand_builtin_dwarf_fp_regnum ();
+ case BUILT_IN_DWARF_REG_SIZE:
+ return expand_builtin_dwarf_reg_size (TREE_VALUE (arglist), target);
+#endif
+ case BUILT_IN_FROB_RETURN_ADDR:
+ return expand_builtin_frob_return_addr (TREE_VALUE (arglist));
+ case BUILT_IN_EXTRACT_RETURN_ADDR:
+ return expand_builtin_extract_return_addr (TREE_VALUE (arglist));
+ case BUILT_IN_SET_RETURN_ADDR_REG:
+ expand_builtin_set_return_addr_reg (TREE_VALUE (arglist));
+ return const0_rtx;
+ case BUILT_IN_EH_STUB_OLD:
+ return expand_builtin_eh_stub_old ();
+ case BUILT_IN_EH_STUB:
+ return expand_builtin_eh_stub ();
+ case BUILT_IN_SET_EH_REGS:
+ expand_builtin_set_eh_regs (TREE_VALUE (arglist),
+ TREE_VALUE (TREE_CHAIN (arglist)));
+ return const0_rtx;
+
default: /* just do library call, if unknown builtin */
error ("built-in function `%s' not currently supported",
IDENTIFIER_POINTER (DECL_NAME (fndecl)));
@@ -8015,12 +9391,12 @@ static enum machine_mode apply_result_mode[FIRST_PSEUDO_REGISTER];
/* For each register that may be used for calling a function, this
gives the offset of that register into the block returned by
__builtin_apply_args. 0 indicates that the register is not
- used for calling a function. */
+ used for calling a function. */
static int apply_args_reg_offset[FIRST_PSEUDO_REGISTER];
/* Return the offset of register REGNO into the block returned by
__builtin_apply_args. This is not declared static, since it is
- needed in objc-act.c. */
+ needed in objc-act.c. */
int
apply_args_register_offset (regno)
@@ -8029,7 +9405,7 @@ apply_args_register_offset (regno)
apply_args_size ();
/* Arguments are always put in outgoing registers (in the argument
- block) if such make sense. */
+ block) if such make sense. */
#ifdef OUTGOING_REGNO
regno = OUTGOING_REGNO(regno);
#endif
@@ -8181,15 +9557,15 @@ result_vector (savep, result)
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
size = CEIL (size, align) * align;
- reg = gen_rtx (REG, mode, savep ? regno : INCOMING_REGNO (regno));
+ reg = gen_rtx_REG (mode, savep ? regno : INCOMING_REGNO (regno));
mem = change_address (result, mode,
plus_constant (XEXP (result, 0), size));
savevec[nelts++] = (savep
- ? gen_rtx (SET, VOIDmode, mem, reg)
- : gen_rtx (SET, VOIDmode, reg, mem));
+ ? gen_rtx_SET (VOIDmode, mem, reg)
+ : gen_rtx_SET (VOIDmode, reg, mem));
size += GET_MODE_SIZE (mode);
}
- return gen_rtx (PARALLEL, VOIDmode, gen_rtvec_v (nelts, savevec));
+ return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nelts, savevec));
}
#endif /* HAVE_untyped_call or HAVE_untyped_return */
@@ -8222,13 +9598,13 @@ expand_builtin_apply_args ()
if (size % align != 0)
size = CEIL (size, align) * align;
- tem = gen_rtx (REG, mode, INCOMING_REGNO (regno));
+ tem = gen_rtx_REG (mode, INCOMING_REGNO (regno));
#ifdef STACK_REGS
/* For reg-stack.c's stack register household.
Compare with a similar piece of code in function.c. */
- emit_insn (gen_rtx (USE, mode, tem));
+ emit_insn (gen_rtx_USE (mode, tem));
#endif
emit_move_insn (change_address (registers, mode,
@@ -8279,7 +9655,7 @@ expand_builtin_apply (function, arguments, argsize)
/* Fetch the arg pointer from the ARGUMENTS block. */
incoming_args = gen_reg_rtx (Pmode);
emit_move_insn (incoming_args,
- gen_rtx (MEM, Pmode, arguments));
+ gen_rtx_MEM (Pmode, arguments));
#ifndef STACK_GROWS_DOWNWARD
incoming_args = expand_binop (Pmode, sub_optab, incoming_args, argsize,
incoming_args, 0, OPTAB_LIB_WIDEN);
@@ -8290,22 +9666,29 @@ expand_builtin_apply (function, arguments, argsize)
/* Push a new argument block and copy the arguments. */
do_pending_stack_adjust ();
- emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
+
+ /* Save the stack with nonlocal if available */
+#ifdef HAVE_save_stack_nonlocal
+ if (HAVE_save_stack_nonlocal)
+ emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX);
+ else
+#endif
+ emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
/* Push a block of memory onto the stack to store the memory arguments.
Save the address in a register, and copy the memory arguments. ??? I
haven't figured out how the calling convention macros effect this,
but it's likely that the source and/or destination addresses in
the block copy will need updating in machine specific ways. */
- dest = copy_addr_to_reg (push_block (argsize, 0, 0));
- emit_block_move (gen_rtx (MEM, BLKmode, dest),
- gen_rtx (MEM, BLKmode, incoming_args),
+ dest = allocate_dynamic_stack_space (argsize, 0, 0);
+ emit_block_move (gen_rtx_MEM (BLKmode, dest),
+ gen_rtx_MEM (BLKmode, incoming_args),
argsize,
PARM_BOUNDARY / BITS_PER_UNIT);
/* Refer to the argument block. */
apply_args_size ();
- arguments = gen_rtx (MEM, BLKmode, arguments);
+ arguments = gen_rtx_MEM (BLKmode, arguments);
/* Walk past the arg-pointer and structure value address. */
size = GET_MODE_SIZE (Pmode);
@@ -8320,7 +9703,7 @@ expand_builtin_apply (function, arguments, argsize)
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
size = CEIL (size, align) * align;
- reg = gen_rtx (REG, mode, regno);
+ reg = gen_rtx_REG (mode, regno);
emit_move_insn (reg,
change_address (arguments, mode,
plus_constant (XEXP (arguments, 0),
@@ -8358,7 +9741,7 @@ expand_builtin_apply (function, arguments, argsize)
/* Generate the actual call instruction and save the return value. */
#ifdef HAVE_untyped_call
if (HAVE_untyped_call)
- emit_call_insn (gen_untyped_call (gen_rtx (MEM, FUNCTION_MODE, function),
+ emit_call_insn (gen_untyped_call (gen_rtx_MEM (FUNCTION_MODE, function),
result, result_vector (1, result)));
else
#endif
@@ -8376,11 +9759,11 @@ expand_builtin_apply (function, arguments, argsize)
{
if (valreg)
abort (); /* HAVE_untyped_call required. */
- valreg = gen_rtx (REG, mode, regno);
+ valreg = gen_rtx_REG (mode, regno);
}
emit_call_insn (gen_call_value (valreg,
- gen_rtx (MEM, FUNCTION_MODE, function),
+ gen_rtx_MEM (FUNCTION_MODE, function),
const0_rtx, NULL_RTX, const0_rtx));
emit_move_insn (change_address (result, GET_MODE (valreg),
@@ -8416,7 +9799,12 @@ expand_builtin_apply (function, arguments, argsize)
CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
/* Restore the stack. */
- emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
+#ifdef HAVE_save_stack_nonlocal
+ if (HAVE_save_stack_nonlocal)
+ emit_stack_restore (SAVE_NONLOCAL, old_stack_level, NULL_RTX);
+ else
+#endif
+ emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
/* Return the address of the result block. */
return copy_addr_to_reg (XEXP (result, 0));
@@ -8434,7 +9822,7 @@ expand_builtin_return (result)
rtx call_fusage = 0;
apply_result_size ();
- result = gen_rtx (MEM, BLKmode, result);
+ result = gen_rtx_MEM (BLKmode, result);
#ifdef HAVE_untyped_return
if (HAVE_untyped_return)
@@ -8453,14 +9841,14 @@ expand_builtin_return (result)
align = GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT;
if (size % align != 0)
size = CEIL (size, align) * align;
- reg = gen_rtx (REG, mode, INCOMING_REGNO (regno));
+ reg = gen_rtx_REG (mode, INCOMING_REGNO (regno));
emit_move_insn (reg,
change_address (result, mode,
plus_constant (XEXP (result, 0),
size)));
push_to_sequence (call_fusage);
- emit_insn (gen_rtx (USE, VOIDmode, reg));
+ emit_insn (gen_rtx_USE (VOIDmode, reg));
call_fusage = get_insns ();
end_sequence ();
size += GET_MODE_SIZE (mode);
@@ -8479,9 +9867,9 @@ expand_builtin_return (result)
POST is 1 for postinc/decrements and 0 for preinc/decrements. */
static rtx
-expand_increment (exp, post)
+expand_increment (exp, post, ignore)
register tree exp;
- int post;
+ int post, ignore;
{
register rtx op0, op1;
register rtx temp, value;
@@ -8496,12 +9884,6 @@ expand_increment (exp, post)
and we don't dare clobber the rest of the word. */
int bad_subreg = 0;
- if (output_bytecode)
- {
- bc_expand_expr (exp);
- return NULL_RTX;
- }
-
/* Stabilize any component ref that might need to be
evaluated more than once below. */
if (!post
@@ -8523,7 +9905,7 @@ expand_increment (exp, post)
and insns were generated in computing it. */
temp = get_last_insn ();
- op0 = expand_expr (incremented, NULL_RTX, VOIDmode, 0);
+ op0 = expand_expr (incremented, NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_RW);
/* If OP0 is a SUBREG made for a promoted variable, we cannot increment
in place but instead must do sign- or zero-extension during assignment,
@@ -8554,7 +9936,8 @@ expand_increment (exp, post)
op0_is_copy = ((GET_CODE (op0) == SUBREG || GET_CODE (op0) == REG)
&& temp != get_last_insn ());
- op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode, 0);
+ op1 = expand_expr (TREE_OPERAND (exp, 1), NULL_RTX, VOIDmode,
+ EXPAND_MEMORY_USE_BAD);
/* Decide whether incrementing or decrementing. */
if (TREE_CODE (exp) == POSTDECREMENT_EXPR
@@ -8612,7 +9995,7 @@ expand_increment (exp, post)
incremented = TREE_OPERAND (incremented, 0);
}
- temp = expand_assignment (incremented, newexp, ! post, 0);
+ temp = expand_assignment (incremented, newexp, ! post && ! ignore , 0);
return post ? op0 : temp;
}
@@ -8640,6 +10023,24 @@ expand_increment (exp, post)
return enqueue_insn (op0, GEN_FCN (icode) (op0, op0, op1));
}
+ if (icode != (int) CODE_FOR_nothing && GET_CODE (op0) == MEM)
+ {
+ rtx addr = (general_operand (XEXP (op0, 0), mode)
+ ? force_reg (Pmode, XEXP (op0, 0))
+ : copy_to_reg (XEXP (op0, 0)));
+ rtx temp, result;
+
+ op0 = change_address (op0, VOIDmode, addr);
+ temp = force_reg (GET_MODE (op0), op0);
+ if (! (*insn_operand_predicate[icode][2]) (op1, mode))
+ op1 = force_reg (mode, op1);
+
+ /* The increment queue is LIFO, thus we have to `queue'
+ the instructions in reverse order. */
+ enqueue_insn (op0, gen_move_insn (op0, temp));
+ result = enqueue_insn (temp, GEN_FCN (icode) (temp, temp, op1));
+ return result;
+ }
}
/* Preincrement, or we can't increment with one simple insn. */
@@ -8654,7 +10055,8 @@ expand_increment (exp, post)
temp = copy_rtx (value = op0);
/* Increment however we can. */
- op1 = expand_binop (mode, this_optab, value, op1, op0,
+ op1 = expand_binop (mode, this_optab, value, op1,
+ flag_check_memory_usage ? NULL_RTX : op0,
TREE_UNSIGNED (TREE_TYPE (exp)), OPTAB_LIB_WIDEN);
/* Make sure the value is stored into OP0. */
if (op1 != op0)
@@ -8687,16 +10089,17 @@ preexpand_calls (exp)
{
case CALL_EXPR:
/* Do nothing if already expanded. */
- if (CALL_EXPR_RTL (exp) != 0)
+ if (CALL_EXPR_RTL (exp) != 0
+ /* Do nothing if the call returns a variable-sized object. */
+ || TREE_CODE (TYPE_SIZE (TREE_TYPE(exp))) != INTEGER_CST
+ /* Do nothing to built-in functions. */
+ || (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+ && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+ == FUNCTION_DECL)
+ && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))))
return;
- /* Do nothing to built-in functions. */
- if (TREE_CODE (TREE_OPERAND (exp, 0)) != ADDR_EXPR
- || TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) != FUNCTION_DECL
- || ! DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
- /* Do nothing if the call returns a variable-sized object. */
- || TREE_CODE (TYPE_SIZE (TREE_TYPE(exp))) != INTEGER_CST)
- CALL_EXPR_RTL (exp) = expand_call (exp, NULL_RTX, 0);
+ CALL_EXPR_RTL (exp) = expand_call (exp, NULL_RTX, 0);
return;
case COMPOUND_EXPR:
@@ -8715,11 +10118,15 @@ preexpand_calls (exp)
case RTL_EXPR:
case WITH_CLEANUP_EXPR:
case CLEANUP_POINT_EXPR:
+ case TRY_CATCH_EXPR:
return;
case SAVE_EXPR:
if (SAVE_EXPR_RTL (exp) != 0)
return;
+
+ default:
+ break;
}
nops = tree_code_length[(int) TREE_CODE (exp)];
@@ -8743,13 +10150,18 @@ init_pending_stack_adjust ()
}
/* When exiting from function, if safe, clear out any pending stack adjust
- so the adjustment won't get done. */
+ so the adjustment won't get done.
+
+ Note, if the current function calls alloca, then it must have a
+ frame pointer regardless of the value of flag_omit_frame_pointer. */
void
clear_pending_stack_adjust ()
{
#ifdef EXIT_IGNORE_STACK
- if (! flag_omit_frame_pointer && EXIT_IGNORE_STACK
+ if (optimize > 0
+ && (! flag_omit_frame_pointer || current_function_calls_alloca)
+ && EXIT_IGNORE_STACK
&& ! (DECL_INLINE (current_function_decl) && ! flag_no_inline)
&& ! flag_inline_functions)
pending_stack_adjust = 0;
@@ -8768,62 +10180,6 @@ do_pending_stack_adjust ()
pending_stack_adjust = 0;
}
}
-
-/* Defer the expansion all cleanups up to OLD_CLEANUPS.
- Returns the cleanups to be performed. */
-
-static tree
-defer_cleanups_to (old_cleanups)
- tree old_cleanups;
-{
- tree new_cleanups = NULL_TREE;
- tree cleanups = cleanups_this_call;
- tree last = NULL_TREE;
-
- while (cleanups_this_call != old_cleanups)
- {
- (*interim_eh_hook) (TREE_VALUE (cleanups_this_call));
- last = cleanups_this_call;
- cleanups_this_call = TREE_CHAIN (cleanups_this_call);
- }
-
- if (last)
- {
- /* Remove the list from the chain of cleanups. */
- TREE_CHAIN (last) = NULL_TREE;
-
- /* reverse them so that we can build them in the right order. */
- cleanups = nreverse (cleanups);
-
- while (cleanups)
- {
- if (new_cleanups)
- new_cleanups = build (COMPOUND_EXPR, TREE_TYPE (new_cleanups),
- TREE_VALUE (cleanups), new_cleanups);
- else
- new_cleanups = TREE_VALUE (cleanups);
-
- cleanups = TREE_CHAIN (cleanups);
- }
- }
-
- return new_cleanups;
-}
-
-/* Expand all cleanups up to OLD_CLEANUPS.
- Needed here, and also for language-dependent calls. */
-
-void
-expand_cleanups_to (old_cleanups)
- tree old_cleanups;
-{
- while (cleanups_this_call != old_cleanups)
- {
- (*interim_eh_hook) (TREE_VALUE (cleanups_this_call));
- expand_expr (TREE_VALUE (cleanups_this_call), const0_rtx, VOIDmode, 0);
- cleanups_this_call = TREE_CHAIN (cleanups_this_call);
- }
-}
/* Expand conditional expressions. */
@@ -8877,6 +10233,10 @@ do_jump (exp, if_false_label, if_true_label)
tree type;
enum machine_mode mode;
+#ifdef MAX_INTEGER_COMPUTATION_MODE
+ check_max_integer_computation_mode (exp);
+#endif
+
emit_queue ();
switch (code)
@@ -8968,124 +10328,27 @@ do_jump (exp, if_false_label, if_true_label)
break;
case TRUTH_ANDIF_EXPR:
- {
- rtx seq1, seq2;
- tree cleanups, old_cleanups;
-
- if (if_false_label == 0)
- if_false_label = drop_through_label = gen_label_rtx ();
- start_sequence ();
- do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
- seq1 = get_insns ();
- end_sequence ();
-
- old_cleanups = cleanups_this_call;
- start_sequence ();
- do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
- seq2 = get_insns ();
- end_sequence ();
-
- cleanups = defer_cleanups_to (old_cleanups);
- if (cleanups)
- {
- rtx flag = gen_reg_rtx (word_mode);
- tree new_cleanups;
- tree cond;
-
- /* Flag cleanups as not needed. */
- emit_move_insn (flag, const0_rtx);
- emit_insns (seq1);
-
- /* Flag cleanups as needed. */
- emit_move_insn (flag, const1_rtx);
- emit_insns (seq2);
-
- /* convert flag, which is an rtx, into a tree. */
- cond = make_node (RTL_EXPR);
- TREE_TYPE (cond) = integer_type_node;
- RTL_EXPR_RTL (cond) = flag;
- RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
- cond = save_expr (cond);
-
- new_cleanups = build (COND_EXPR, void_type_node,
- truthvalue_conversion (cond),
- cleanups, integer_zero_node);
- new_cleanups = fold (new_cleanups);
-
- /* Now add in the conditionalized cleanups. */
- cleanups_this_call
- = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
- (*interim_eh_hook) (NULL_TREE);
- }
- else
- {
- emit_insns (seq1);
- emit_insns (seq2);
- }
- }
+ if (if_false_label == 0)
+ if_false_label = drop_through_label = gen_label_rtx ();
+ do_jump (TREE_OPERAND (exp, 0), if_false_label, NULL_RTX);
+ start_cleanup_deferral ();
+ do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+ end_cleanup_deferral ();
break;
case TRUTH_ORIF_EXPR:
- {
- rtx seq1, seq2;
- tree cleanups, old_cleanups;
-
- if (if_true_label == 0)
- if_true_label = drop_through_label = gen_label_rtx ();
- start_sequence ();
- do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
- seq1 = get_insns ();
- end_sequence ();
-
- old_cleanups = cleanups_this_call;
- start_sequence ();
- do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
- seq2 = get_insns ();
- end_sequence ();
-
- cleanups = defer_cleanups_to (old_cleanups);
- if (cleanups)
- {
- rtx flag = gen_reg_rtx (word_mode);
- tree new_cleanups;
- tree cond;
-
- /* Flag cleanups as not needed. */
- emit_move_insn (flag, const0_rtx);
- emit_insns (seq1);
-
- /* Flag cleanups as needed. */
- emit_move_insn (flag, const1_rtx);
- emit_insns (seq2);
-
- /* convert flag, which is an rtx, into a tree. */
- cond = make_node (RTL_EXPR);
- TREE_TYPE (cond) = integer_type_node;
- RTL_EXPR_RTL (cond) = flag;
- RTL_EXPR_SEQUENCE (cond) = NULL_RTX;
- cond = save_expr (cond);
-
- new_cleanups = build (COND_EXPR, void_type_node,
- truthvalue_conversion (cond),
- cleanups, integer_zero_node);
- new_cleanups = fold (new_cleanups);
-
- /* Now add in the conditionalized cleanups. */
- cleanups_this_call
- = tree_cons (NULL_TREE, new_cleanups, cleanups_this_call);
- (*interim_eh_hook) (NULL_TREE);
- }
- else
- {
- emit_insns (seq1);
- emit_insns (seq2);
- }
- }
+ if (if_true_label == 0)
+ if_true_label = drop_through_label = gen_label_rtx ();
+ do_jump (TREE_OPERAND (exp, 0), NULL_RTX, if_true_label);
+ start_cleanup_deferral ();
+ do_jump (TREE_OPERAND (exp, 1), if_false_label, if_true_label);
+ end_cleanup_deferral ();
break;
case COMPOUND_EXPR:
push_temp_slots ();
expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, 0);
+ preserve_temp_slots (NULL_RTX);
free_temp_slots ();
pop_temp_slots ();
emit_queue ();
@@ -9102,11 +10365,13 @@ do_jump (exp, if_false_label, if_true_label)
tree type;
tree offset;
int volatilep = 0;
+ int alignment;
/* Get description of this reference. We don't actually care
about the underlying object here. */
get_inner_reference (exp, &bitsize, &bitpos, &offset,
- &mode, &unsignedp, &volatilep);
+ &mode, &unsignedp, &volatilep,
+ &alignment);
type = type_for_size (bitsize, unsignedp);
if (! SLOW_BYTE_ACCESS
@@ -9135,7 +10400,10 @@ do_jump (exp, if_false_label, if_true_label)
{
register rtx label1 = gen_label_rtx ();
drop_through_label = gen_label_rtx ();
+
do_jump (TREE_OPERAND (exp, 0), label1, NULL_RTX);
+
+ start_cleanup_deferral ();
/* Now the THEN-expression. */
do_jump (TREE_OPERAND (exp, 1),
if_false_label ? if_false_label : drop_through_label,
@@ -9143,10 +10411,12 @@ do_jump (exp, if_false_label, if_true_label)
/* In case the do_jump just above never jumps. */
do_pending_stack_adjust ();
emit_label (label1);
+
/* Now the ELSE-expression. */
do_jump (TREE_OPERAND (exp, 2),
if_false_label ? if_false_label : drop_through_label,
if_true_label ? if_true_label : drop_through_label);
+ end_cleanup_deferral ();
}
break;
@@ -9154,28 +10424,34 @@ do_jump (exp, if_false_label, if_true_label)
{
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
- if (integer_zerop (TREE_OPERAND (exp, 1)))
+ if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
+ || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
+ {
+ tree exp0 = save_expr (TREE_OPERAND (exp, 0));
+ tree exp1 = save_expr (TREE_OPERAND (exp, 1));
+ do_jump
+ (fold
+ (build (TRUTH_ANDIF_EXPR, TREE_TYPE (exp),
+ fold (build (EQ_EXPR, TREE_TYPE (exp),
+ fold (build1 (REALPART_EXPR,
+ TREE_TYPE (inner_type),
+ exp0)),
+ fold (build1 (REALPART_EXPR,
+ TREE_TYPE (inner_type),
+ exp1)))),
+ fold (build (EQ_EXPR, TREE_TYPE (exp),
+ fold (build1 (IMAGPART_EXPR,
+ TREE_TYPE (inner_type),
+ exp0)),
+ fold (build1 (IMAGPART_EXPR,
+ TREE_TYPE (inner_type),
+ exp1)))))),
+ if_false_label, if_true_label);
+ }
+
+ else if (integer_zerop (TREE_OPERAND (exp, 1)))
do_jump (TREE_OPERAND (exp, 0), if_true_label, if_false_label);
- else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
- || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
- do_jump
- (fold
- (build (TRUTH_ANDIF_EXPR, TREE_TYPE (exp),
- fold (build (EQ_EXPR, TREE_TYPE (exp),
- fold (build1 (REALPART_EXPR,
- TREE_TYPE (inner_type),
- TREE_OPERAND (exp, 0))),
- fold (build1 (REALPART_EXPR,
- TREE_TYPE (inner_type),
- TREE_OPERAND (exp, 1))))),
- fold (build (EQ_EXPR, TREE_TYPE (exp),
- fold (build1 (IMAGPART_EXPR,
- TREE_TYPE (inner_type),
- TREE_OPERAND (exp, 0))),
- fold (build1 (IMAGPART_EXPR,
- TREE_TYPE (inner_type),
- TREE_OPERAND (exp, 1))))))),
- if_false_label, if_true_label);
+
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
&& !can_compare_p (TYPE_MODE (inner_type)))
do_jump_by_parts_equality (exp, if_false_label, if_true_label);
@@ -9188,28 +10464,34 @@ do_jump (exp, if_false_label, if_true_label)
{
tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
- if (integer_zerop (TREE_OPERAND (exp, 1)))
+ if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
+ || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
+ {
+ tree exp0 = save_expr (TREE_OPERAND (exp, 0));
+ tree exp1 = save_expr (TREE_OPERAND (exp, 1));
+ do_jump
+ (fold
+ (build (TRUTH_ORIF_EXPR, TREE_TYPE (exp),
+ fold (build (NE_EXPR, TREE_TYPE (exp),
+ fold (build1 (REALPART_EXPR,
+ TREE_TYPE (inner_type),
+ exp0)),
+ fold (build1 (REALPART_EXPR,
+ TREE_TYPE (inner_type),
+ exp1)))),
+ fold (build (NE_EXPR, TREE_TYPE (exp),
+ fold (build1 (IMAGPART_EXPR,
+ TREE_TYPE (inner_type),
+ exp0)),
+ fold (build1 (IMAGPART_EXPR,
+ TREE_TYPE (inner_type),
+ exp1)))))),
+ if_false_label, if_true_label);
+ }
+
+ else if (integer_zerop (TREE_OPERAND (exp, 1)))
do_jump (TREE_OPERAND (exp, 0), if_false_label, if_true_label);
- else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_FLOAT
- || GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_COMPLEX_INT)
- do_jump
- (fold
- (build (TRUTH_ORIF_EXPR, TREE_TYPE (exp),
- fold (build (NE_EXPR, TREE_TYPE (exp),
- fold (build1 (REALPART_EXPR,
- TREE_TYPE (inner_type),
- TREE_OPERAND (exp, 0))),
- fold (build1 (REALPART_EXPR,
- TREE_TYPE (inner_type),
- TREE_OPERAND (exp, 1))))),
- fold (build (NE_EXPR, TREE_TYPE (exp),
- fold (build1 (IMAGPART_EXPR,
- TREE_TYPE (inner_type),
- TREE_OPERAND (exp, 0))),
- fold (build1 (IMAGPART_EXPR,
- TREE_TYPE (inner_type),
- TREE_OPERAND (exp, 1))))))),
- if_false_label, if_true_label);
+
else if (GET_MODE_CLASS (TYPE_MODE (inner_type)) == MODE_INT
&& !can_compare_p (TYPE_MODE (inner_type)))
do_jump_by_parts_equality (exp, if_true_label, if_false_label);
@@ -9483,15 +10765,44 @@ do_jump_by_parts_equality (exp, if_false_label, if_true_label)
We assume that OP0 has an integer mode that is too wide
for the available compare insns. */
-static void
+void
do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
rtx op0;
rtx if_false_label, if_true_label;
{
int nwords = GET_MODE_SIZE (GET_MODE (op0)) / UNITS_PER_WORD;
+ rtx part;
int i;
rtx drop_through_label = 0;
+ /* The fastest way of doing this comparison on almost any machine is to
+ "or" all the words and compare the result. If all have to be loaded
+ from memory and this is a very wide item, it's possible this may
+ be slower, but that's highly unlikely. */
+
+ part = gen_reg_rtx (word_mode);
+ emit_move_insn (part, operand_subword_force (op0, 0, GET_MODE (op0)));
+ for (i = 1; i < nwords && part != 0; i++)
+ part = expand_binop (word_mode, ior_optab, part,
+ operand_subword_force (op0, i, GET_MODE (op0)),
+ part, 1, OPTAB_WIDEN);
+
+ if (part != 0)
+ {
+ rtx comp = compare_from_rtx (part, const0_rtx, EQ, 1, word_mode,
+ NULL_RTX, 0);
+
+ if (comp == const_true_rtx)
+ emit_jump (if_false_label);
+ else if (comp == const0_rtx)
+ emit_jump (if_true_label);
+ else
+ do_jump_for_compare (comp, if_false_label, if_true_label);
+
+ return;
+ }
+
+ /* If we couldn't do the "or" simply, do this with a series of compares. */
if (! if_false_label)
drop_through_label = if_false_label = gen_label_rtx ();
@@ -9508,6 +10819,7 @@ do_jump_by_parts_equality_rtx (op0, if_false_label, if_true_label)
if (if_true_label)
emit_jump (if_true_label);
+
if (drop_through_label)
emit_label (drop_through_label);
}
@@ -9603,6 +10915,32 @@ compare (exp, signed_code, unsigned_code)
int unsignedp = TREE_UNSIGNED (type);
enum rtx_code code = unsignedp ? unsigned_code : signed_code;
+#ifdef HAVE_canonicalize_funcptr_for_compare
+ /* If function pointers need to be "canonicalized" before they can
+ be reliably compared, then canonicalize them. */
+ if (HAVE_canonicalize_funcptr_for_compare
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
+ == FUNCTION_TYPE))
+ {
+ rtx new_op0 = gen_reg_rtx (mode);
+
+ emit_insn (gen_canonicalize_funcptr_for_compare (new_op0, op0));
+ op0 = new_op0;
+ }
+
+ if (HAVE_canonicalize_funcptr_for_compare
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
+ == FUNCTION_TYPE))
+ {
+ rtx new_op1 = gen_reg_rtx (mode);
+
+ emit_insn (gen_canonicalize_funcptr_for_compare (new_op1, op1));
+ op1 = new_op1;
+ }
+#endif
+
return compare_from_rtx (op0, op1, code, unsignedp, mode,
((mode == BLKmode)
? expr_size (TREE_OPERAND (exp, 0)) : NULL_RTX),
@@ -9656,7 +10994,7 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
#if 0
/* There's no need to do this now that combine.c can eliminate lots of
sign extensions. This can be less efficient in certain cases on other
- machines. */
+ machines. */
/* If this is a signed equality comparison, we can do it as an
unsigned comparison since zero-extension is cheaper than sign
@@ -9677,7 +11015,7 @@ compare_from_rtx (op0, op1, code, unsignedp, mode, size, align)
emit_cmp_insn (op0, op1, code, size, mode, unsignedp, align);
- return gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
+ return gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
}
/* Generate code to calculate EXP using a store-flag instruction
@@ -9716,7 +11054,7 @@ do_store_flag (exp, target, mode, only_cheap)
rtx op0, op1;
enum insn_code icode;
rtx subtarget = target;
- rtx result, label, pattern, jump_pat;
+ rtx result, label;
/* If this is a TRUTH_NOT_EXPR, set a flag indicating we must invert the
result at the end. We can't simply invert the test since it would
@@ -9737,6 +11075,19 @@ do_store_flag (exp, target, mode, only_cheap)
if (operand_mode == BLKmode)
return 0;
+ /* We won't bother with store-flag operations involving function pointers
+ when function pointers must be canonicalized before comparisons. */
+#ifdef HAVE_canonicalize_funcptr_for_compare
+ if (HAVE_canonicalize_funcptr_for_compare
+ && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 0))))
+ == FUNCTION_TYPE))
+ || (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 1))) == POINTER_TYPE
+ && (TREE_CODE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (exp, 1))))
+ == FUNCTION_TYPE))))
+ return 0;
+#endif
+
STRIP_NOPS (arg0);
STRIP_NOPS (arg1);
@@ -9798,12 +11149,10 @@ do_store_flag (exp, target, mode, only_cheap)
if ((code == NE || code == EQ)
&& TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)
- && integer_pow2p (TREE_OPERAND (arg0, 1))
- && TYPE_PRECISION (type) <= HOST_BITS_PER_WIDE_INT)
+ && integer_pow2p (TREE_OPERAND (arg0, 1)))
{
tree inner = TREE_OPERAND (arg0, 0);
- int bitnum = exact_log2 (INTVAL (expand_expr (TREE_OPERAND (arg0, 1),
- NULL_RTX, VOIDmode, 0)));
+ int bitnum = tree_log2 (TREE_OPERAND (arg0, 1));
int ops_unsignedp;
/* If INNER is a right shift of a constant and it plus BITNUM does
@@ -9815,7 +11164,7 @@ do_store_flag (exp, target, mode, only_cheap)
&& (bitnum + TREE_INT_CST_LOW (TREE_OPERAND (inner, 1))
< TYPE_PRECISION (type)))
{
- bitnum +=TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
+ bitnum += TREE_INT_CST_LOW (TREE_OPERAND (inner, 1));
inner = TREE_OPERAND (inner, 0);
}
@@ -9832,7 +11181,7 @@ do_store_flag (exp, target, mode, only_cheap)
if (subtarget == 0 || GET_CODE (subtarget) != REG
|| GET_MODE (subtarget) != operand_mode
- || ! safe_from_p (subtarget, inner))
+ || ! safe_from_p (subtarget, inner, 1))
subtarget = 0;
op0 = expand_expr (inner, subtarget, VOIDmode, 0);
@@ -9882,7 +11231,7 @@ do_store_flag (exp, target, mode, only_cheap)
preexpand_calls (exp);
if (subtarget == 0 || GET_CODE (subtarget) != REG
|| GET_MODE (subtarget) != operand_mode
- || ! safe_from_p (subtarget, arg1))
+ || ! safe_from_p (subtarget, arg1, 1))
subtarget = 0;
op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
@@ -9909,7 +11258,7 @@ do_store_flag (exp, target, mode, only_cheap)
}
/* If this failed, we have to do this with set/compare/jump/set code. */
- if (target == 0 || GET_CODE (target) != REG
+ if (GET_CODE (target) != REG
|| reg_mentioned_p (target, op0) || reg_mentioned_p (target, op1))
target = gen_reg_rtx (GET_MODE (target));
@@ -9984,10 +11333,10 @@ do_tablejump (index, mode, range, table_label, default_label)
GET_MODE_SIZE, because this indicates how large insns are. The other
uses should all be Pmode, because they are addresses. This code
could fail if addresses and insns are not the same size. */
- index = gen_rtx (PLUS, Pmode,
- gen_rtx (MULT, Pmode, index,
- GEN_INT (GET_MODE_SIZE (CASE_VECTOR_MODE))),
- gen_rtx (LABEL_REF, Pmode, table_label));
+ index = gen_rtx_PLUS (Pmode,
+ gen_rtx_MULT (Pmode, index,
+ GEN_INT (GET_MODE_SIZE (CASE_VECTOR_MODE))),
+ gen_rtx_LABEL_REF (Pmode, table_label));
#ifdef PIC_CASE_VECTOR_ADDRESS
if (flag_pic)
index = PIC_CASE_VECTOR_ADDRESS (index);
@@ -9995,753 +11344,16 @@ do_tablejump (index, mode, range, table_label, default_label)
#endif
index = memory_address_noforce (CASE_VECTOR_MODE, index);
temp = gen_reg_rtx (CASE_VECTOR_MODE);
- vector = gen_rtx (MEM, CASE_VECTOR_MODE, index);
+ vector = gen_rtx_MEM (CASE_VECTOR_MODE, index);
RTX_UNCHANGING_P (vector) = 1;
convert_move (temp, vector, 0);
emit_jump_insn (gen_tablejump (temp, table_label));
-#ifndef CASE_VECTOR_PC_RELATIVE
/* If we are generating PIC code or if the table is PC-relative, the
table and JUMP_INSN must be adjacent, so don't output a BARRIER. */
- if (! flag_pic)
+ if (! CASE_VECTOR_PC_RELATIVE && ! flag_pic)
emit_barrier ();
-#endif
}
#endif /* HAVE_tablejump */
-
-
-/* Emit a suitable bytecode to load a value from memory, assuming a pointer
- to that value is on the top of the stack. The resulting type is TYPE, and
- the source declaration is DECL. */
-
-void
-bc_load_memory (type, decl)
- tree type, decl;
-{
- enum bytecode_opcode opcode;
-
-
- /* Bit fields are special. We only know about signed and
- unsigned ints, and enums. The latter are treated as
- signed integers. */
-
- if (DECL_BIT_FIELD (decl))
- if (TREE_CODE (type) == ENUMERAL_TYPE
- || TREE_CODE (type) == INTEGER_TYPE)
- opcode = TREE_UNSIGNED (type) ? zxloadBI : sxloadBI;
- else
- abort ();
- else
- /* See corresponding comment in bc_store_memory(). */
- if (TYPE_MODE (type) == BLKmode
- || TYPE_MODE (type) == VOIDmode)
- return;
- else
- opcode = mode_to_load_map [(int) TYPE_MODE (type)];
-
- if (opcode == neverneverland)
- abort ();
-
- bc_emit_bytecode (opcode);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-}
-
-
-/* Store the contents of the second stack slot to the address in the
- top stack slot. DECL is the declaration of the destination and is used
- to determine whether we're dealing with a bitfield. */
-
-void
-bc_store_memory (type, decl)
- tree type, decl;
-{
- enum bytecode_opcode opcode;
-
-
- if (DECL_BIT_FIELD (decl))
- {
- if (TREE_CODE (type) == ENUMERAL_TYPE
- || TREE_CODE (type) == INTEGER_TYPE)
- opcode = sstoreBI;
- else
- abort ();
- }
- else
- if (TYPE_MODE (type) == BLKmode)
- {
- /* Copy structure. This expands to a block copy instruction, storeBLK.
- In addition to the arguments expected by the other store instructions,
- it also expects a type size (SImode) on top of the stack, which is the
- structure size in size units (usually bytes). The two first arguments
- are already on the stack; so we just put the size on level 1. For some
- other languages, the size may be variable, this is why we don't encode
- it as a storeBLK literal, but rather treat it as a full-fledged expression. */
-
- bc_expand_expr (TYPE_SIZE (type));
- opcode = storeBLK;
- }
- else
- opcode = mode_to_store_map [(int) TYPE_MODE (type)];
-
- if (opcode == neverneverland)
- abort ();
-
- bc_emit_bytecode (opcode);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-}
-
-
-/* Allocate local stack space sufficient to hold a value of the given
- SIZE at alignment boundary ALIGNMENT bits. ALIGNMENT must be an
- integral power of 2. A special case is locals of type VOID, which
- have size 0 and alignment 1 - any "voidish" SIZE or ALIGNMENT is
- remapped into the corresponding attribute of SI. */
-
-rtx
-bc_allocate_local (size, alignment)
- int size, alignment;
-{
- rtx retval;
- int byte_alignment;
-
- if (size < 0)
- abort ();
-
- /* Normalize size and alignment */
- if (!size)
- size = UNITS_PER_WORD;
-
- if (alignment < BITS_PER_UNIT)
- byte_alignment = 1 << (INT_ALIGN - 1);
- else
- /* Align */
- byte_alignment = alignment / BITS_PER_UNIT;
-
- if (local_vars_size & (byte_alignment - 1))
- local_vars_size += byte_alignment - (local_vars_size & (byte_alignment - 1));
-
- retval = bc_gen_rtx ((char *) 0, local_vars_size, (struct bc_label *) 0);
- local_vars_size += size;
-
- return retval;
-}
-
-
-/* Allocate variable-sized local array. Variable-sized arrays are
- actually pointers to the address in memory where they are stored. */
-
-rtx
-bc_allocate_variable_array (size)
- tree size;
-{
- rtx retval;
- const int ptralign = (1 << (PTR_ALIGN - 1));
-
- /* Align pointer */
- if (local_vars_size & ptralign)
- local_vars_size += ptralign - (local_vars_size & ptralign);
-
- /* Note down local space needed: pointer to block; also return
- dummy rtx */
-
- retval = bc_gen_rtx ((char *) 0, local_vars_size, (struct bc_label *) 0);
- local_vars_size += POINTER_SIZE / BITS_PER_UNIT;
- return retval;
-}
-
-
-/* Push the machine address for the given external variable offset. */
-void
-bc_load_externaddr (externaddr)
- rtx externaddr;
-{
- bc_emit_bytecode (constP);
- bc_emit_code_labelref (BYTECODE_LABEL (externaddr),
- BYTECODE_BC_LABEL (externaddr)->offset);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-}
-
-
-static char *
-bc_strdup (s)
- char *s;
-{
- char *new = (char *) xmalloc ((strlen (s) + 1) * sizeof *s);
- strcpy (new, s);
- return new;
-}
-
-
-/* Like above, but expects an IDENTIFIER. */
-void
-bc_load_externaddr_id (id, offset)
- tree id;
- int offset;
-{
- if (!IDENTIFIER_POINTER (id))
- abort ();
-
- bc_emit_bytecode (constP);
- bc_emit_code_labelref (bc_xstrdup (IDENTIFIER_POINTER (id)), offset);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-}
-
-
-/* Push the machine address for the given local variable offset. */
-void
-bc_load_localaddr (localaddr)
- rtx localaddr;
-{
- bc_emit_instruction (localP, (HOST_WIDE_INT) BYTECODE_BC_LABEL (localaddr)->offset);
-}
-
-
-/* Push the machine address for the given parameter offset.
- NOTE: offset is in bits. */
-void
-bc_load_parmaddr (parmaddr)
- rtx parmaddr;
-{
- bc_emit_instruction (argP, ((HOST_WIDE_INT) BYTECODE_BC_LABEL (parmaddr)->offset
- / BITS_PER_UNIT));
-}
-
-
-/* Convert a[i] into *(a + i). */
-tree
-bc_canonicalize_array_ref (exp)
- tree exp;
-{
- tree type = TREE_TYPE (exp);
- tree array_adr = build1 (ADDR_EXPR, TYPE_POINTER_TO (type),
- TREE_OPERAND (exp, 0));
- tree index = TREE_OPERAND (exp, 1);
-
-
- /* Convert the integer argument to a type the same size as a pointer
- so the multiply won't overflow spuriously. */
-
- if (TYPE_PRECISION (TREE_TYPE (index)) != POINTER_SIZE)
- index = convert (type_for_size (POINTER_SIZE, 0), index);
-
- /* The array address isn't volatile even if the array is.
- (Of course this isn't terribly relevant since the bytecode
- translator treats nearly everything as volatile anyway.) */
- TREE_THIS_VOLATILE (array_adr) = 0;
-
- return build1 (INDIRECT_REF, type,
- fold (build (PLUS_EXPR,
- TYPE_POINTER_TO (type),
- array_adr,
- fold (build (MULT_EXPR,
- TYPE_POINTER_TO (type),
- index,
- size_in_bytes (type))))));
-}
-
-
-/* Load the address of the component referenced by the given
- COMPONENT_REF expression.
-
- Returns innermost lvalue. */
-
-tree
-bc_expand_component_address (exp)
- tree exp;
-{
- tree tem, chain;
- enum machine_mode mode;
- int bitpos = 0;
- HOST_WIDE_INT SIval;
-
-
- tem = TREE_OPERAND (exp, 1);
- mode = DECL_MODE (tem);
-
-
- /* Compute cumulative bit offset for nested component refs
- and array refs, and find the ultimate containing object. */
-
- for (tem = exp;; tem = TREE_OPERAND (tem, 0))
- {
- if (TREE_CODE (tem) == COMPONENT_REF)
- bitpos += TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (tem, 1)));
- else
- if (TREE_CODE (tem) == ARRAY_REF
- && TREE_CODE (TREE_OPERAND (tem, 1)) == INTEGER_CST
- && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) == INTEGER_CST)
-
- bitpos += (TREE_INT_CST_LOW (TREE_OPERAND (tem, 1))
- * TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tem)))
- /* * TYPE_SIZE_UNIT (TREE_TYPE (tem)) */);
- else
- break;
- }
-
- bc_expand_expr (tem);
-
-
- /* For bitfields also push their offset and size */
- if (DECL_BIT_FIELD (TREE_OPERAND (exp, 1)))
- bc_push_offset_and_size (bitpos, /* DECL_SIZE_UNIT */ (TREE_OPERAND (exp, 1)));
- else
- if (SIval = bitpos / BITS_PER_UNIT)
- bc_emit_instruction (addconstPSI, SIval);
-
- return (TREE_OPERAND (exp, 1));
-}
-
-
-/* Emit code to push two SI constants */
-void
-bc_push_offset_and_size (offset, size)
- HOST_WIDE_INT offset, size;
-{
- bc_emit_instruction (constSI, offset);
- bc_emit_instruction (constSI, size);
-}
-
-
-/* Emit byte code to push the address of the given lvalue expression to
- the stack. If it's a bit field, we also push offset and size info.
-
- Returns innermost component, which allows us to determine not only
- its type, but also whether it's a bitfield. */
-
-tree
-bc_expand_address (exp)
- tree exp;
-{
- /* Safeguard */
- if (!exp || TREE_CODE (exp) == ERROR_MARK)
- return (exp);
-
-
- switch (TREE_CODE (exp))
- {
- case ARRAY_REF:
-
- return (bc_expand_address (bc_canonicalize_array_ref (exp)));
-
- case COMPONENT_REF:
-
- return (bc_expand_component_address (exp));
-
- case INDIRECT_REF:
-
- bc_expand_expr (TREE_OPERAND (exp, 0));
-
- /* For variable-sized types: retrieve pointer. Sometimes the
- TYPE_SIZE tree is NULL. Is this a bug or a feature? Let's
- also make sure we have an operand, just in case... */
-
- if (TREE_OPERAND (exp, 0)
- && TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0)))
- && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0)))) != INTEGER_CST)
- bc_emit_instruction (loadP);
-
- /* If packed, also return offset and size */
- if (DECL_BIT_FIELD (TREE_OPERAND (exp, 0)))
-
- bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (TREE_OPERAND (exp, 0))),
- TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (exp, 0))));
-
- return (TREE_OPERAND (exp, 0));
-
- case FUNCTION_DECL:
-
- bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp),
- BYTECODE_BC_LABEL (DECL_RTL (exp))->offset);
- break;
-
- case PARM_DECL:
-
- bc_load_parmaddr (DECL_RTL (exp));
-
- /* For variable-sized types: retrieve pointer */
- if (TYPE_SIZE (TREE_TYPE (exp))
- && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST)
- bc_emit_instruction (loadP);
-
- /* If packed, also return offset and size */
- if (DECL_BIT_FIELD (exp))
- bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (exp)),
- TREE_INT_CST_LOW (DECL_SIZE (exp)));
-
- break;
-
- case RESULT_DECL:
-
- bc_emit_instruction (returnP);
- break;
-
- case VAR_DECL:
-
-#if 0
- if (BYTECODE_LABEL (DECL_RTL (exp)))
- bc_load_externaddr (DECL_RTL (exp));
-#endif
-
- if (DECL_EXTERNAL (exp))
- bc_load_externaddr_id (DECL_ASSEMBLER_NAME (exp),
- (BYTECODE_BC_LABEL (DECL_RTL (exp)))->offset);
- else
- bc_load_localaddr (DECL_RTL (exp));
-
- /* For variable-sized types: retrieve pointer */
- if (TYPE_SIZE (TREE_TYPE (exp))
- && TREE_CODE (TYPE_SIZE (TREE_TYPE (exp))) != INTEGER_CST)
- bc_emit_instruction (loadP);
-
- /* If packed, also return offset and size */
- if (DECL_BIT_FIELD (exp))
- bc_push_offset_and_size (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (exp)),
- TREE_INT_CST_LOW (DECL_SIZE (exp)));
-
- break;
-
- case STRING_CST:
- {
- rtx r;
-
- bc_emit_bytecode (constP);
- r = output_constant_def (exp);
- bc_emit_code_labelref (BYTECODE_LABEL (r), BYTECODE_BC_LABEL (r)->offset);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
- }
- break;
-
- default:
-
- abort();
- break;
- }
-
- /* Most lvalues don't have components. */
- return (exp);
-}
-
-
-/* Emit a type code to be used by the runtime support in handling
- parameter passing. The type code consists of the machine mode
- plus the minimal alignment shifted left 8 bits. */
-
-tree
-bc_runtime_type_code (type)
- tree type;
-{
- int val;
-
- switch (TREE_CODE (type))
- {
- case VOID_TYPE:
- case INTEGER_TYPE:
- case REAL_TYPE:
- case COMPLEX_TYPE:
- case ENUMERAL_TYPE:
- case POINTER_TYPE:
- case RECORD_TYPE:
-
- val = (int) TYPE_MODE (type) | TYPE_ALIGN (type) << 8;
- break;
-
- case ERROR_MARK:
-
- val = 0;
- break;
-
- default:
-
- abort ();
- }
- return build_int_2 (val, 0);
-}
-
-
-/* Generate constructor label */
-char *
-bc_gen_constr_label ()
-{
- static int label_counter;
- static char label[20];
-
- sprintf (label, "*LR%d", label_counter++);
-
- return (obstack_copy0 (&permanent_obstack, label, strlen (label)));
-}
-
-
-/* Evaluate constructor CONSTR and return pointer to it on level one. We
- expand the constructor data as static data, and push a pointer to it.
- The pointer is put in the pointer table and is retrieved by a constP
- bytecode instruction. We then loop and store each constructor member in
- the corresponding component. Finally, we return the original pointer on
- the stack. */
-
-void
-bc_expand_constructor (constr)
- tree constr;
-{
- char *l;
- HOST_WIDE_INT ptroffs;
- rtx constr_rtx;
-
-
- /* Literal constructors are handled as constants, whereas
- non-literals are evaluated and stored element by element
- into the data segment. */
-
- /* Allocate space in proper segment and push pointer to space on stack.
- */
-
- l = bc_gen_constr_label ();
-
- if (TREE_CONSTANT (constr))
- {
- text_section ();
-
- bc_emit_const_labeldef (l);
- bc_output_constructor (constr, int_size_in_bytes (TREE_TYPE (constr)));
- }
- else
- {
- data_section ();
-
- bc_emit_data_labeldef (l);
- bc_output_data_constructor (constr);
- }
-
-
- /* Add reference to pointer table and recall pointer to stack;
- this code is common for both types of constructors: literals
- and non-literals. */
-
- ptroffs = bc_define_pointer (l);
- bc_emit_instruction (constP, ptroffs);
-
- /* This is all that has to be done if it's a literal. */
- if (TREE_CONSTANT (constr))
- return;
-
-
- /* At this point, we have the pointer to the structure on top of the stack.
- Generate sequences of store_memory calls for the constructor. */
-
- /* constructor type is structure */
- if (TREE_CODE (TREE_TYPE (constr)) == RECORD_TYPE)
- {
- register tree elt;
-
- /* If the constructor has fewer fields than the structure,
- clear the whole structure first. */
-
- if (list_length (CONSTRUCTOR_ELTS (constr))
- != list_length (TYPE_FIELDS (TREE_TYPE (constr))))
- {
- bc_emit_instruction (duplicate);
- bc_emit_instruction (constSI, (HOST_WIDE_INT) int_size_in_bytes (TREE_TYPE (constr)));
- bc_emit_instruction (clearBLK);
- }
-
- /* Store each element of the constructor into the corresponding
- field of TARGET. */
-
- for (elt = CONSTRUCTOR_ELTS (constr); elt; elt = TREE_CHAIN (elt))
- {
- register tree field = TREE_PURPOSE (elt);
- register enum machine_mode mode;
- int bitsize;
- int bitpos;
- int unsignedp;
-
- bitsize = TREE_INT_CST_LOW (DECL_SIZE (field)) /* * DECL_SIZE_UNIT (field) */;
- mode = DECL_MODE (field);
- unsignedp = TREE_UNSIGNED (field);
-
- bitpos = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field));
-
- bc_store_field (elt, bitsize, bitpos, mode, TREE_VALUE (elt), TREE_TYPE (TREE_VALUE (elt)),
- /* The alignment of TARGET is
- at least what its type requires. */
- VOIDmode, 0,
- TYPE_ALIGN (TREE_TYPE (constr)) / BITS_PER_UNIT,
- int_size_in_bytes (TREE_TYPE (constr)));
- }
- }
- else
-
- /* Constructor type is array */
- if (TREE_CODE (TREE_TYPE (constr)) == ARRAY_TYPE)
- {
- register tree elt;
- register int i;
- tree domain = TYPE_DOMAIN (TREE_TYPE (constr));
- int minelt = TREE_INT_CST_LOW (TYPE_MIN_VALUE (domain));
- int maxelt = TREE_INT_CST_LOW (TYPE_MAX_VALUE (domain));
- tree elttype = TREE_TYPE (TREE_TYPE (constr));
-
- /* If the constructor has fewer fields than the structure,
- clear the whole structure first. */
-
- if (list_length (CONSTRUCTOR_ELTS (constr)) < maxelt - minelt + 1)
- {
- bc_emit_instruction (duplicate);
- bc_emit_instruction (constSI, (HOST_WIDE_INT) int_size_in_bytes (TREE_TYPE (constr)));
- bc_emit_instruction (clearBLK);
- }
-
-
- /* Store each element of the constructor into the corresponding
- element of TARGET, determined by counting the elements. */
-
- for (elt = CONSTRUCTOR_ELTS (constr), i = 0;
- elt;
- elt = TREE_CHAIN (elt), i++)
- {
- register enum machine_mode mode;
- int bitsize;
- int bitpos;
- int unsignedp;
-
- mode = TYPE_MODE (elttype);
- bitsize = GET_MODE_BITSIZE (mode);
- unsignedp = TREE_UNSIGNED (elttype);
-
- bitpos = (i * TREE_INT_CST_LOW (TYPE_SIZE (elttype))
- /* * TYPE_SIZE_UNIT (elttype) */ );
-
- bc_store_field (elt, bitsize, bitpos, mode,
- TREE_VALUE (elt), TREE_TYPE (TREE_VALUE (elt)),
- /* The alignment of TARGET is
- at least what its type requires. */
- VOIDmode, 0,
- TYPE_ALIGN (TREE_TYPE (constr)) / BITS_PER_UNIT,
- int_size_in_bytes (TREE_TYPE (constr)));
- }
-
- }
-}
-
-
-/* Store the value of EXP (an expression tree) into member FIELD of
- structure at address on stack, which has type TYPE, mode MODE and
- occupies BITSIZE bits, starting BITPOS bits from the beginning of the
- structure.
-
- ALIGN is the alignment that TARGET is known to have, measured in bytes.
- TOTAL_SIZE is its size in bytes, or -1 if variable. */
-
-void
-bc_store_field (field, bitsize, bitpos, mode, exp, type,
- value_mode, unsignedp, align, total_size)
- int bitsize, bitpos;
- enum machine_mode mode;
- tree field, exp, type;
- enum machine_mode value_mode;
- int unsignedp;
- int align;
- int total_size;
-{
-
- /* Expand expression and copy pointer */
- bc_expand_expr (exp);
- bc_emit_instruction (over);
-
-
- /* If the component is a bit field, we cannot use addressing to access
- it. Use bit-field techniques to store in it. */
-
- if (DECL_BIT_FIELD (field))
- {
- bc_store_bit_field (bitpos, bitsize, unsignedp);
- return;
- }
- else
- /* Not bit field */
- {
- HOST_WIDE_INT offset = bitpos / BITS_PER_UNIT;
-
- /* Advance pointer to the desired member */
- if (offset)
- bc_emit_instruction (addconstPSI, offset);
-
- /* Store */
- bc_store_memory (type, field);
- }
-}
-
-
-/* Store SI/SU in bitfield */
-void
-bc_store_bit_field (offset, size, unsignedp)
- int offset, size, unsignedp;
-{
- /* Push bitfield offset and size */
- bc_push_offset_and_size (offset, size);
-
- /* Store */
- bc_emit_instruction (sstoreBI);
-}
-
-
-/* Load SI/SU from bitfield */
-void
-bc_load_bit_field (offset, size, unsignedp)
- int offset, size, unsignedp;
-{
- /* Push bitfield offset and size */
- bc_push_offset_and_size (offset, size);
-
- /* Load: sign-extend if signed, else zero-extend */
- bc_emit_instruction (unsignedp ? zxloadBI : sxloadBI);
-}
-
-
-/* Adjust interpreter stack by NLEVELS. Positive means drop NLEVELS
- (adjust stack pointer upwards), negative means add that number of
- levels (adjust the stack pointer downwards). Only positive values
- normally make sense. */
-
-void
-bc_adjust_stack (nlevels)
- int nlevels;
-{
- switch (nlevels)
- {
- case 0:
- break;
-
- case 2:
- bc_emit_instruction (drop);
-
- case 1:
- bc_emit_instruction (drop);
- break;
-
- default:
-
- bc_emit_instruction (adjstackSI, (HOST_WIDE_INT) nlevels);
- stack_depth -= nlevels;
- }
-
-#if defined (VALIDATE_STACK_FOR_BC)
- VALIDATE_STACK_FOR_BC ();
-#endif
-}
diff --git a/contrib/gcc/expr.h b/contrib/gcc/expr.h
index cac7381..a53a036 100644
--- a/contrib/gcc/expr.h
+++ b/contrib/gcc/expr.h
@@ -1,5 +1,5 @@
/* Definitions for code generation pass of GNU compiler.
- Copyright (C) 1987, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 91-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -18,13 +18,6 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-
-#ifndef __STDC__
-#ifndef const
-#define const
-#endif
-#endif
-
/* The default branch cost is 1. */
#ifndef BRANCH_COST
#define BRANCH_COST 1
@@ -37,7 +30,8 @@ Boston, MA 02111-1307, USA. */
/* The variable for which an increment is queued. */
#define QUEUED_VAR(P) XEXP (P, 0)
/* If the increment has been emitted, this is the insn
- that does the increment. It is zero before the increment is emitted. */
+ that does the increment. It is zero before the increment is emitted.
+ If more than one insn is emitted, this is the first insn. */
#define QUEUED_INSN(P) XEXP (P, 1)
/* If a pre-increment copy has been generated, this is the copy
(it is a temporary reg). Zero if no copy made yet. */
@@ -52,9 +46,27 @@ Boston, MA 02111-1307, USA. */
EXPAND_SUM means it is ok to return a PLUS rtx or MULT rtx.
EXPAND_INITIALIZER is similar but also record any labels on forced_labels.
EXPAND_CONST_ADDRESS means it is ok to return a MEM whose address
- is a constant that is not a legitimate address. */
+ is a constant that is not a legitimate address.
+ EXPAND_MEMORY_USE_* are explained below. */
enum expand_modifier {EXPAND_NORMAL, EXPAND_SUM,
- EXPAND_CONST_ADDRESS, EXPAND_INITIALIZER};
+ EXPAND_CONST_ADDRESS, EXPAND_INITIALIZER,
+ EXPAND_MEMORY_USE_WO, EXPAND_MEMORY_USE_RW,
+ EXPAND_MEMORY_USE_BAD, EXPAND_MEMORY_USE_DONT};
+
+/* Argument for chkr_* functions.
+ MEMORY_USE_RO: the pointer reads memory.
+ MEMORY_USE_WO: the pointer writes to memory.
+ MEMORY_USE_RW: the pointer modifies memory (ie it reads and writes). An
+ example is (*ptr)++
+ MEMORY_USE_BAD: use this if you don't know the behavior of the pointer, or
+ if you know there are no pointers. Using an INDIRECT_REF
+ with MEMORY_USE_BAD will abort.
+ MEMORY_USE_TW: just test for writing, without update. Special.
+ MEMORY_USE_DONT: the memory is neither read nor written. This is used by
+ '->' and '.'. */
+enum memory_use_mode {MEMORY_USE_BAD = 0, MEMORY_USE_RO = 1,
+ MEMORY_USE_WO = 2, MEMORY_USE_RW = 3,
+ MEMORY_USE_TW = 6, MEMORY_USE_DONT = 99};
/* List of labels that must never be deleted. */
extern rtx forced_labels;
@@ -115,17 +127,15 @@ extern tree nonlocal_labels;
These are the arguments to function calls that have already returned. */
extern int pending_stack_adjust;
-/* A list of all cleanups which belong to the arguments of
- function calls being expanded by expand_call. */
-#ifdef TREE_CODE /* Don't lose if tree.h not included. */
-extern tree cleanups_this_call;
-#endif
-
/* When temporaries are created by TARGET_EXPRs, they are created at
this level of temp_slot_level, so that they can remain allocated
until no longer needed. CLEANUP_POINT_EXPRs define the lifetime
of TARGET_EXPRs. */
extern int target_temp_slot_level;
+
+/* Current level for normal temporaries. */
+
+extern int temp_slot_level;
#ifdef TREE_CODE /* Don't lose if tree.h not included. */
/* Structure to record the size of a sequence of arguments
@@ -133,7 +143,7 @@ extern int target_temp_slot_level;
struct args_size
{
- int constant;
+ HOST_WIDE_INT constant;
tree var;
};
#endif
@@ -163,7 +173,7 @@ struct args_size
((SIZE).var == 0 ? GEN_INT ((SIZE).constant) \
: expand_expr (size_binop (PLUS_EXPR, (SIZE).var, \
size_int ((SIZE).constant)), \
- NULL_RTX, VOIDmode, 0))
+ NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD))
/* Convert the implicit sum in a `struct args_size' into a tree. */
#define ARGS_SIZE_TREE(SIZE) \
@@ -195,6 +205,11 @@ enum direction {none, upward, downward}; /* Value has this type. */
#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) PARM_BOUNDARY
#endif
+/* Provide a default value for STRICT_ARGUMENT_NAMING. */
+#ifndef STRICT_ARGUMENT_NAMING
+#define STRICT_ARGUMENT_NAMING 0
+#endif
+
/* Nonzero if we do not know how to pass TYPE solely in registers.
We cannot do so in the following cases:
@@ -211,6 +226,7 @@ enum direction {none, upward, downward}; /* Value has this type. */
So a value padded in memory at the upper end can't go in a register.
For a little-endian machine, the reverse is true. */
+#ifndef MUST_PASS_IN_STACK
#define MUST_PASS_IN_STACK(MODE,TYPE) \
((TYPE) != 0 \
&& (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \
@@ -221,6 +237,7 @@ enum direction {none, upward, downward}; /* Value has this type. */
% (PARM_BOUNDARY / BITS_PER_UNIT))) \
&& (FUNCTION_ARG_PADDING (MODE, TYPE) \
== (BYTES_BIG_ENDIAN ? upward : downward)))))
+#endif
/* Nonzero if type TYPE should be returned in memory.
Most machines can use the following default definition. */
@@ -228,6 +245,60 @@ enum direction {none, upward, downward}; /* Value has this type. */
#ifndef RETURN_IN_MEMORY
#define RETURN_IN_MEMORY(TYPE) (TYPE_MODE (TYPE) == BLKmode)
#endif
+
+/* Supply a default definition of STACK_SAVEAREA_MODE for emit_stack_save.
+ Normally move_insn, so Pmode stack pointer. */
+
+#ifndef STACK_SAVEAREA_MODE
+#define STACK_SAVEAREA_MODE(LEVEL) Pmode
+#endif
+
+/* Supply a default definition of STACK_SIZE_MODE for
+ allocate_dynamic_stack_space. Normally PLUS/MINUS, so word_mode. */
+
+#ifndef STACK_SIZE_MODE
+#define STACK_SIZE_MODE word_mode
+#endif
+
+/* Provide default values for the macros controlling stack checking. */
+
+#ifndef STACK_CHECK_BUILTIN
+#define STACK_CHECK_BUILTIN 0
+#endif
+
+/* The default interval is one page. */
+#ifndef STACK_CHECK_PROBE_INTERVAL
+#define STACK_CHECK_PROBE_INTERVAL 4096
+#endif
+
+/* The default is to do a store into the stack. */
+#ifndef STACK_CHECK_PROBE_LOAD
+#define STACK_CHECK_PROBE_LOAD 0
+#endif
+
+/* This value is arbitrary, but should be sufficient for most machines. */
+#ifndef STACK_CHECK_PROTECT
+#define STACK_CHECK_PROTECT (75 * UNITS_PER_WORD)
+#endif
+
+/* Make the maximum frame size be the largest we can and still only need
+ one probe per function. */
+#ifndef STACK_CHECK_MAX_FRAME_SIZE
+#define STACK_CHECK_MAX_FRAME_SIZE \
+ (STACK_CHECK_PROBE_INTERVAL - UNITS_PER_WORD)
+#endif
+
+/* This is arbitrary, but should be large enough everywhere. */
+#ifndef STACK_CHECK_FIXED_FRAME_SIZE
+#define STACK_CHECK_FIXED_FRAME_SIZE (4 * UNITS_PER_WORD)
+#endif
+
+/* Provide a reasonable default for the maximum size of an object to
+ allocate in the fixed frame. We may need to be able to make this
+ controllable by the user at some point. */
+#ifndef STACK_CHECK_MAX_VAR_SIZE
+#define STACK_CHECK_MAX_VAR_SIZE (STACK_CHECK_MAX_FRAME_SIZE / 100)
+#endif
/* Optabs are tables saying how to generate insn bodies
for various machine modes and numbers of operands.
@@ -270,7 +341,7 @@ typedef struct optab
#define GEN_FCN(CODE) (*insn_gen_function[(int) (CODE)])
#endif
-extern rtx (*const insn_gen_function[]) ();
+extern rtx (*const insn_gen_function[]) PROTO ((rtx, ...));
extern optab add_optab;
extern optab sub_optab;
@@ -365,6 +436,13 @@ extern rtx bcmp_libfunc;
extern rtx memset_libfunc;
extern rtx bzero_libfunc;
+extern rtx throw_libfunc;
+extern rtx sjthrow_libfunc;
+extern rtx sjpopnthrow_libfunc;
+extern rtx terminate_libfunc;
+extern rtx setjmp_libfunc;
+extern rtx longjmp_libfunc;
+
extern rtx eqhf2_libfunc;
extern rtx nehf2_libfunc;
extern rtx gthf2_libfunc;
@@ -447,8 +525,15 @@ extern rtx fixunsxfti_libfunc;
extern rtx fixunstfsi_libfunc;
extern rtx fixunstfdi_libfunc;
extern rtx fixunstfti_libfunc;
+
+/* For check-memory-usage. */
+extern rtx chkr_check_addr_libfunc;
+extern rtx chkr_set_right_libfunc;
+extern rtx chkr_copy_bitmap_libfunc;
+extern rtx chkr_check_exec_libfunc;
+extern rtx chkr_check_str_libfunc;
-typedef rtx (*rtxfun) ();
+typedef rtx (*rtxfun) PROTO ((rtx));
/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
gives the gen_function to make a branch to test that condition. */
@@ -462,7 +547,7 @@ extern rtxfun bcc_gen_fctn[NUM_RTX_CODE];
extern enum insn_code setcc_gen_code[NUM_RTX_CODE];
#ifdef HAVE_conditional_move
-/* Indexed by the the machine mode, gives the insn code to make a conditional
+/* Indexed by the machine mode, gives the insn code to make a conditional
move insn. */
extern enum insn_code movcc_gen_code[NUM_MACHINE_MODES];
@@ -471,6 +556,9 @@ extern enum insn_code movcc_gen_code[NUM_MACHINE_MODES];
/* This array records the insn_code of insns to perform block moves. */
extern enum insn_code movstr_optab[NUM_MACHINE_MODES];
+/* This array records the insn_code of insns to perform block clears. */
+extern enum insn_code clrstr_optab[NUM_MACHINE_MODES];
+
/* Define functions given in optabs.c. */
/* Expand a binary operation given optab and rtx operands. */
@@ -533,6 +621,7 @@ rtx emit_conditional_move PROTO((rtx, enum rtx_code, rtx, rtx,
/* Return non-zero if the conditional move is supported. */
int can_conditionally_move_p PROTO((enum machine_mode mode));
+
#endif
/* Create but don't emit one rtl instruction to add one rtx into another.
@@ -582,10 +671,17 @@ extern rtx expand_and PROTO((rtx, rtx, rtx));
extern rtx emit_store_flag PROTO((rtx, enum rtx_code, rtx, rtx,
enum machine_mode, int, int));
+/* Like emit_store_flag, but always succeeds. */
+extern rtx emit_store_flag_force PROTO((rtx, enum rtx_code, rtx, rtx,
+ enum machine_mode, int, int));
+
/* Functions from loop.c: */
/* Given a JUMP_INSN, return a description of the test being made. */
extern rtx get_condition PROTO((rtx, rtx *));
+
+/* Generate a conditional trap instruction. */
+extern rtx gen_cond_trap PROTO((enum rtx_code, rtx, rtx, rtx));
/* Functions from expr.c: */
@@ -614,7 +710,7 @@ extern rtx convert_to_mode PROTO((enum machine_mode, rtx, int));
extern rtx convert_modes PROTO((enum machine_mode, enum machine_mode, rtx, int));
/* Emit code to move a block Y to a block X. */
-extern void emit_block_move PROTO((rtx, rtx, rtx, int));
+extern rtx emit_block_move PROTO((rtx, rtx, rtx, int));
/* Copy all or part of a value X into registers starting at REGNO.
The number of registers to be filled is NREGS. */
@@ -624,15 +720,25 @@ extern void move_block_to_reg PROTO((int, rtx, int, enum machine_mode));
The number of registers to be filled is NREGS. */
extern void move_block_from_reg PROTO((int, rtx, int, int));
+/* Load a BLKmode value into non-consecutive registers represented by a
+ PARALLEL. */
+extern void emit_group_load PROTO((rtx, rtx, int, int));
+/* Store a BLKmode value from non-consecutive registers represented by a
+ PARALLEL. */
+extern void emit_group_store PROTO((rtx, rtx, int, int));
+
/* Mark REG as holding a parameter for the next CALL_INSN. */
-extern void use_reg PROTO((rtx*, rtx));
+extern void use_reg PROTO((rtx *, rtx));
/* Mark NREGS consecutive regs, starting at REGNO, as holding parameters
for the next CALL_INSN. */
-extern void use_regs PROTO((rtx*, int, int));
+extern void use_regs PROTO((rtx *, int, int));
+/* Mark a PARALLEL as holding a parameter for the next CALL_INSN. */
+extern void use_group_regs PROTO((rtx *, rtx));
/* Write zeros through the storage of OBJECT.
- If OBJECT has BLKmode, SIZE is its length in bytes. */
-extern void clear_storage PROTO((rtx, rtx));
+ If OBJECT has BLKmode, SIZE is its length in bytes and ALIGN is its
+ alignment. */
+extern rtx clear_storage PROTO((rtx, rtx, int));
/* Emit insns to set X from Y. */
extern rtx emit_move_insn PROTO((rtx, rtx));
@@ -650,7 +756,7 @@ extern rtx gen_push_operand PROTO((void));
#ifdef TREE_CODE
/* Generate code to push something onto the stack, given its mode and type. */
extern void emit_push_insn PROTO((rtx, enum machine_mode, tree, rtx, int,
- int, rtx, int, rtx, rtx));
+ int, rtx, int, rtx, rtx, int));
/* Emit library call. */
extern void emit_library_call PVPROTO((rtx orgfun, int no_queue,
@@ -673,6 +779,8 @@ extern rtx store_expr PROTO((tree, rtx, int));
Useful after calling expand_expr with 1 as sum_ok. */
extern rtx force_operand PROTO((rtx, rtx));
+extern rtx expand_builtin_setjmp PROTO((rtx, rtx, rtx, rtx));
+
#ifdef TREE_CODE
/* Generate code for computing expression EXP.
An rtx for the computed value is returned. The value is never null.
@@ -693,9 +801,6 @@ extern void clear_pending_stack_adjust PROTO((void));
extern void do_pending_stack_adjust PROTO((void));
#ifdef TREE_CODE
-/* Expand all cleanups up to OLD_CLEANUPS. */
-extern void expand_cleanups_to PROTO((tree));
-
/* Generate code to evaluate EXP and jump to LABEL if the value is zero. */
extern void jumpifnot PROTO((tree, rtx));
@@ -828,8 +933,12 @@ extern void emit_stack_restore PROTO((enum save_level, rtx, rtx));
says how many bytes. */
extern rtx allocate_dynamic_stack_space PROTO((rtx, rtx, int));
-/* Emit code to copy function value to a new temp reg and return that reg. */
-extern rtx function_value ();
+/* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive.
+ FIRST is a constant and size is a Pmode RTX. These are offsets from the
+ current stack pointer. STACK_GROWS_DOWNWARD says whether to add or
+ subtract from the stack. If SIZE is constant, this is done
+ with a fixed number of probes. Otherwise, we must make a loop. */
+extern void probe_stack_range PROTO((HOST_WIDE_INT, rtx));
/* Return an rtx that refers to the value returned by a library call
in its original home. This becomes invalid if any more code is emitted. */
@@ -839,16 +948,28 @@ extern rtx hard_libcall_value PROTO((enum machine_mode));
of STACK_BOUNDARY / BITS_PER_UNIT. */
extern rtx round_push PROTO((rtx));
-extern void emit_block_move PROTO((rtx, rtx, rtx, int));
-
extern rtx store_bit_field PROTO((rtx, int, int, enum machine_mode, rtx, int, int));
extern rtx extract_bit_field PROTO((rtx, int, int, int, rtx, enum machine_mode, enum machine_mode, int, int));
extern rtx expand_mult PROTO((enum machine_mode, rtx, rtx, rtx, int));
extern rtx expand_mult_add PROTO((rtx, rtx, rtx, rtx,enum machine_mode, int));
+extern rtx expand_mult_highpart_adjust PROTO((enum machine_mode, rtx, rtx, rtx, rtx, int));
extern rtx assemble_static_space PROTO((int));
/* Hook called by expand_expr for language-specific tree codes.
It is up to the language front end to install a hook
if it has any such codes that expand_expr needs to know about. */
-extern rtx (*lang_expand_expr) ();
+extern rtx (*lang_expand_expr) PROTO ((union tree_node *, rtx,
+ enum machine_mode,
+ enum expand_modifier modifier));
+
+extern void init_all_optabs PROTO ((void));
+extern void init_mov_optab PROTO ((void));
+extern void do_jump_by_parts_equality_rtx PROTO((rtx, rtx, rtx));
+extern void do_jump_by_parts_greater_rtx PROTO ((enum machine_mode, int,
+ rtx, rtx, rtx, rtx));
+
+#ifdef TREE_CODE /* Don't lose if tree.h not included. */
+extern void mark_seen_cases PROTO ((tree, unsigned char *,
+ long, int));
+#endif
diff --git a/contrib/gcc/extend.texi b/contrib/gcc/extend.texi
index e85799c..5cf1b24 100644
--- a/contrib/gcc/extend.texi
+++ b/contrib/gcc/extend.texi
@@ -1,4 +1,4 @@
-@c Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+@c Copyright (C) 1988,89,92,93,94,96 Free Software Foundation, Inc.
@c This is part of the GCC manual.
@c For copying conditions, see the file gcc.texi.
@@ -62,6 +62,7 @@ C++ Language}, for extensions that apply @emph{only} to C++.
* Incomplete Enums:: @code{enum foo;}, with details to follow.
* Function Names:: Printable strings which are the name of the current
function.
+* Return Address:: Getting the return or frame address of a function.
@end menu
@end ifset
@ifclear INTERNALS
@@ -107,6 +108,7 @@ C++ Language}, for extensions that apply @emph{only} to C++.
* Incomplete Enums:: @code{enum foo;}, with details to follow.
* Function Names:: Printable strings which are the name of the current
function.
+* Return Address:: Getting the return or frame address of a function.
@end menu
@end ifclear
@@ -235,12 +237,12 @@ example:
@section Labels as Values
@cindex labels as values
@cindex computed gotos
-@cindex goto with computed label
+@cindex goto with computed label
@cindex address of a label
You can get the address of a label defined in the current function
(or a containing function) with the unary operator @samp{&&}. The
-value has type @code{void *}. This value is a constant and can be used
+value has type @code{void *}. This value is a constant and can be used
wherever a constant of that type is valid. For example:
@example
@@ -286,7 +288,7 @@ use that rather than an array unless the problem does not fit a
Another use of label values is in an interpreter for threaded code.
The labels within the interpreter function can be stored in the
-threaded code for super-fast dispatching.
+threaded code for super-fast dispatching.
You can use this mechanism to jump to code in a different function. If
you do that, totally unpredictable things will happen. The best way to
@@ -364,9 +366,8 @@ does not refer to anything that has gone out of scope, you should be
safe.
GNU CC implements taking the address of a nested function using a
-technique called @dfn{trampolines}. A paper describing them is
-available from @samp{maya.idiap.ch} in directory @file{pub/tmb},
-file @file{usenix88-lexic.ps.Z}.
+technique called @dfn{trampolines}. A paper describing them is
+available as @samp{http://master.debian.org/~karlheg/Usenix88-lexic.pdf}.
A nested function can jump to a label inherited from a containing
function, provided the label was explicitly declared in the containing
@@ -727,11 +728,11 @@ effects of recomputing it.
@cindex multiprecision arithmetic
GNU C supports data types for integers that are twice as long as
-@code{long int}. Simply write @code{long long int} for a signed
-integer, or @code{unsigned long long int} for an unsigned integer.
-To make an integer constant of type @code{long long int}, add the suffix
-@code{LL} to the integer. To make an integer constant of type
-@code{unsigned long long int}, add the suffix @code{ULL} to the integer.
+@code{int}. Simply write @code{long long int} for a signed integer, or
+@code{unsigned long long int} for an unsigned integer. To make an
+integer constant of type @code{long long int}, add the suffix @code{LL}
+to the integer. To make an integer constant of type @code{unsigned long
+long int}, add the suffix @code{ULL} to the integer.
You can use these types in arithmetic like any other integer types.
Addition, subtraction, and bitwise boolean operations on these types
@@ -783,7 +784,7 @@ the imaginary part is on the stack (or vice-versa). None of the
supported debugging info formats has a way to represent noncontiguous
allocation like this, so GNU CC describes a noncontiguous complex
variable as if it were two separate variables of noncomplex type.
-If the variable's actual name is @code{foo}, the two fictitious
+If the variable's actual name is @code{foo}, the two fictitious
variables are named @code{foo$real} and @code{foo$imag}. You can
examine and set these two fictitious variables with your debugger.
@@ -1017,7 +1018,7 @@ foo (float f, float g)
@cindex constructor expressions
@cindex initializations in expressions
@cindex structures, constructor expression
-@cindex expressions, constructor
+@cindex expressions, constructor
GNU C supports constructor expressions. A constructor looks like
a cast containing an initializer. Its value is an object of the
@@ -1118,7 +1119,7 @@ plus one.
In a structure initializer, specify the name of a field to initialize
with @samp{@var{fieldname}:} before the element value. For example,
-given the following structure,
+given the following structure,
@example
struct point @{ int x, y; @};
@@ -1217,7 +1218,7 @@ write this:
case 1 ... 5:
@end example
-@noindent
+@noindent
rather than this:
@example
@@ -1227,7 +1228,7 @@ case 1...5:
@node Cast to Union
@section Cast to a Union Type
@cindex cast to a union
-@cindex union, casting to a
+@cindex union, casting to a
A cast to union type is similar to other casts, except that the type
specified is a union type. You can specify the type either with
@@ -1274,7 +1275,7 @@ hack ((union foo) x);
@cindex functions in arbitrary sections
@cindex @code{volatile} applied to function
@cindex @code{const} applied to function
-@cindex functions with @code{printf} or @code{scanf} style arguments
+@cindex functions with @code{printf}, @code{scanf} or @code{strftime} style arguments
@cindex functions that are passed arguments in registers on the 386
@cindex functions that pop the argument stack on the 386
@cindex functions that do not pop the argument stack on the 386
@@ -1333,7 +1334,7 @@ earlier than 2.5. An alternative way to declare that a function does
not return, which works in the current version and in some older
versions, is as follows:
-@smallexample
+@smallexample
typedef void voidfn ();
volatile voidfn fatal;
@@ -1378,9 +1379,9 @@ return @code{void}.
@item format (@var{archetype}, @var{string-index}, @var{first-to-check})
@cindex @code{format} function attribute
-The @code{format} attribute specifies that a function takes @code{printf}
-or @code{scanf} style arguments which should be type-checked against a
-format string. For example, the declaration:
+The @code{format} attribute specifies that a function takes @code{printf},
+@code{scanf}, or @code{strftime} style arguments which should be type-checked
+against a format string. For example, the declaration:
@smallexample
extern int
@@ -1394,7 +1395,8 @@ for consistency with the @code{printf} style format string argument
@code{my_format}.
The parameter @var{archetype} determines how the format string is
-interpreted, and should be either @code{printf} or @code{scanf}. The
+interpreted, and should be either @code{printf}, @code{scanf}, or
+@code{strftime}. The
parameter @var{string-index} specifies which argument is the format
string argument (starting from 1), while @var{first-to-check} is the
number of the first argument to check against the format string. For
@@ -1411,11 +1413,40 @@ The @code{format} attribute allows you to identify your own functions
which take format strings as arguments, so that GNU CC can check the
calls to these functions for errors. The compiler always checks formats
for the ANSI library functions @code{printf}, @code{fprintf},
-@code{sprintf}, @code{scanf}, @code{fscanf}, @code{sscanf},
+@code{sprintf}, @code{scanf}, @code{fscanf}, @code{sscanf}, @code{strftime},
@code{vprintf}, @code{vfprintf} and @code{vsprintf} whenever such
warnings are requested (using @samp{-Wformat}), so there is no need to
modify the header file @file{stdio.h}.
+@item format_arg (@var{string-index})
+@cindex @code{format_arg} function attribute
+The @code{format_arg} attribute specifies that a function takes
+@code{printf} or @code{scanf} style arguments, modifies it (for example,
+to translate it into another language), and passes it to a @code{printf}
+or @code{scanf} style function. For example, the declaration:
+
+@smallexample
+extern char *
+my_dgettext (char *my_domain, const char *my_format)
+ __attribute__ ((format_arg (2)));
+@end smallexample
+
+@noindent
+causes the compiler to check the arguments in calls to
+@code{my_dgettext} whose result is passed to a @code{printf},
+@code{scanf}, or @code{strftime} type function for consistency with the
+@code{printf} style format string argument @code{my_format}.
+
+The parameter @var{string-index} specifies which argument is the format
+string argument (starting from 1).
+
+The @code{format-arg} attribute allows you to identify your own
+functions which modify format strings, so that GNU CC can check the
+calls to @code{printf}, @code{scanf}, or @code{strftime} function whose
+operands are a call to one of your own function. The compiler always
+treats @code{gettext}, @code{dgettext}, and @code{dcgettext} in this
+manner.
+
@item section ("section-name")
@cindex @code{section} function attribute
Normally, the compiler places the code it generates in the @code{text} section.
@@ -1453,7 +1484,8 @@ These attributes are not currently implemented for Objective C.
@item unused
This attribute, attached to a function, means that the function is meant
to be possibly unused. GNU CC will not produce a warning for this
-function.
+function. GNU C++ does not currently support this attribute as
+definitions without parameters are valid in C++.
@item weak
@cindex @code{weak} attribute
@@ -1477,6 +1509,8 @@ void f () __attribute__ ((weak, alias ("__f")));
declares @samp{f} to be a weak alias for @samp{__f}. In C++, the
mangled name for the target must be used.
+Not all target machines support this attribute.
+
@item regparm (@var{number})
@cindex functions that are passed arguments in registers on the 386
On the Intel 386, the @code{regparm} attribute causes the compiler to
@@ -1491,12 +1525,115 @@ On the Intel 386, the @code{stdcall} attribute causes the compiler to
assume that the called function will pop off the stack space used to
pass arguments, unless it takes a variable number of arguments.
+The PowerPC compiler for Windows NT currently ignores the @code{stdcall}
+attribute.
+
@item cdecl
@cindex functions that do pop the argument stack on the 386
On the Intel 386, the @code{cdecl} attribute causes the compiler to
-assume that the called function will pop off the stack space used to
-pass arguments, unless it takes a variable number of arguments. This is
+assume that the calling function will pop off the stack space used to
+pass arguments. This is
useful to override the effects of the @samp{-mrtd} switch.
+
+The PowerPC compiler for Windows NT currently ignores the @code{cdecl}
+attribute.
+
+@item longcall
+@cindex functions called via pointer on the RS/6000 and PowerPC
+On the RS/6000 and PowerPC, the @code{longcall} attribute causes the
+compiler to always call the function via a pointer, so that functions
+which reside further than 64 megabytes (67,108,864 bytes) from the
+current location can be called.
+
+@item dllimport
+@cindex functions which are imported from a dll on PowerPC Windows NT
+On the PowerPC running Windows NT, the @code{dllimport} attribute causes
+the compiler to call the function via a global pointer to the function
+pointer that is set up by the Windows NT dll library. The pointer name
+is formed by combining @code{__imp_} and the function name.
+
+@item dllexport
+@cindex functions which are exported from a dll on PowerPC Windows NT
+On the PowerPC running Windows NT, the @code{dllexport} attribute causes
+the compiler to provide a global pointer to the function pointer, so
+that it can be called with the @code{dllimport} attribute. The pointer
+name is formed by combining @code{__imp_} and the function name.
+
+@item exception (@var{except-func} [, @var{except-arg}])
+@cindex functions which specify exception handling on PowerPC Windows NT
+On the PowerPC running Windows NT, the @code{exception} attribute causes
+the compiler to modify the structured exception table entry it emits for
+the declared function. The string or identifier @var{except-func} is
+placed in the third entry of the structured exception table. It
+represents a function, which is called by the exception handling
+mechanism if an exception occurs. If it was specified, the string or
+identifier @var{except-arg} is placed in the fourth entry of the
+structured exception table.
+
+@item function_vector
+@cindex calling functions through the function vector on the H8/300 processors
+Use this option on the H8/300 and H8/300H to indicate that the specified
+function should be called through the function vector. Calling a
+function through the function vector will reduce code size, however;
+the function vector has a limited size (maximum 128 entries on the H8/300
+and 64 entries on the H8/300H) and shares space with the interrupt vector.
+
+You must use GAS and GLD from GNU binutils version 2.7 or later for
+this option to work correctly.
+
+@item interrupt_handler
+@cindex interrupt handler functions on the H8/300 processors
+Use this option on the H8/300 and H8/300H to indicate that the specified
+function is an interrupt handler. The compiler will generate function
+entry and exit sequences suitable for use in an interrupt handler when this
+attribute is present.
+
+@item eightbit_data
+@cindex eight bit data on the H8/300 and H8/300H
+Use this option on the H8/300 and H8/300H to indicate that the specified
+variable should be placed into the eight bit data section.
+The compiler will generate more efficient code for certain operations
+on data in the eight bit data area. Note the eight bit data area is limited to
+256 bytes of data.
+
+You must use GAS and GLD from GNU binutils version 2.7 or later for
+this option to work correctly.
+
+@item tiny_data
+@cindex tiny data section on the H8/300H
+Use this option on the H8/300H to indicate that the specified
+variable should be placed into the tiny data section.
+The compiler will generate more efficient code for loads and stores
+on data in the tiny data section. Note the tiny data area is limited to
+slightly under 32kbytes of data.
+
+@item interrupt
+@cindex interrupt handlers on the M32R/D
+Use this option on the M32R/D to indicate that the specified
+function is an interrupt handler. The compiler will generate function
+entry and exit sequences suitable for use in an interrupt handler when this
+attribute is present.
+
+@item model (@var{model-name})
+@cindex function addressability on the M32R/D
+Use this attribute on the M32R/D to set the addressability of an object,
+and the code generated for a function.
+The identifier @var{model-name} is one of @code{small}, @code{medium},
+or @code{large}, representing each of the code models.
+
+Small model objects live in the lower 16MB of memory (so that their
+addresses can be loaded with the @code{ld24} instruction), and are
+callable with the @code{bl} instruction.
+
+Medium model objects may live anywhere in the 32 bit address space (the
+compiler will generate @code{seth/add3} instructions to load their addresses),
+and are callable with the @code{bl} instruction.
+
+Large model objects may live anywhere in the 32 bit address space (the
+compiler will generate @code{seth/add3} instructions to load their addresses),
+and may not be reachable with the @code{bl} instruction (the compiler will
+generate the much slower @code{seth/add3/jl} instruction sequence).
+
@end table
You can specify multiple attributes in a declaration by separating them
@@ -1533,7 +1670,7 @@ old-style non-prototype definition. Consider the following example:
@example
/* @r{Use prototypes unless the compiler is old-fashioned.} */
-#if __STDC__
+#ifdef __STDC__
#define P(x) x
#else
#define P(x) ()
@@ -1599,24 +1736,10 @@ with traditional constructs like @code{dividend//*comment*/divisor}.
@cindex dollar signs in identifier names
@cindex identifier names, dollar signs in
-In GNU C, you may use dollar signs in identifier names. This is because
-many traditional C implementations allow such identifiers.
-
-On some machines, dollar signs are allowed in identifiers if you specify
-@w{@samp{-traditional}}. On a few systems they are allowed by default,
-even if you do not use @w{@samp{-traditional}}. But they are never
-allowed if you specify @w{@samp{-ansi}}.
-
-There are certain ANSI C programs (obscure, to be sure) that would
-compile incorrectly if dollar signs were permitted in identifiers. For
-example:
-
-@example
-#define foo(a) #a
-#define lose(b) foo (b)
-#define test$
-lose (test)
-@end example
+In GNU C, you may normally use dollar signs in identifier names.
+This is because many traditional C implementations allow such identifiers.
+However, dollar signs in identifiers are not supported on a few target
+machines, typically because the target assembler does not allow them.
@node Character Escapes
@section The Character @key{ESC} in Constants
@@ -1797,7 +1920,7 @@ section. For example, this small program uses several specific section names:
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_copy __attribute__ ((section ("INITDATACOPY"))) = 0;
+int init_data __attribute__ ((section ("INITDATA"))) = 0;
main()
@{
@@ -1805,7 +1928,7 @@ main()
init_sp (stack + sizeof (stack));
/* Initialize initialized data */
- memcpy (&init_data_copy, &data, &edata - &data);
+ memcpy (&init_data, &data, &edata - &data);
/* Turn on the serial ports */
init_duart (&a);
@@ -1833,11 +1956,12 @@ If you need to map the entire contents of a module to a particular
section, consider using the facilities of the linker instead.
@item transparent_union
-This attribute, attached to a function argument variable which is a
-union, means to pass the argument in the same way that the first union
-member would be passed. You can also use this attribute on a
-@code{typedef} for a union data type; then it applies to all function
-arguments with that type.
+This attribute, attached to a function parameter which is a union, means
+that the corresponding argument may have the type of any union member,
+but the argument is passed as if its type were that of the first union
+member. For more details see @xref{Type Attributes}. You can also use
+this attribute on a @code{typedef} for a union data type; then it
+applies to all function parameters with that type.
@item unused
This attribute, attached to a variable, means that the variable is meant
@@ -1846,6 +1970,20 @@ variable.
@item weak
The @code{weak} attribute is described in @xref{Function Attributes}.
+
+@item model (@var{model-name})
+@cindex variable addressability on the M32R/D
+Use this attribute on the M32R/D to set the addressability of an object.
+The identifier @var{model-name} is one of @code{small}, @code{medium},
+or @code{large}, representing each of the code models.
+
+Small model objects live in the lower 16MB of memory (so that their
+addresses can be loaded with the @code{ld24} instruction).
+
+Medium and large model objects may live anywhere in the 32 bit address space
+(the compiler will generate @code{seth/add3} instructions to load their
+addresses).
+
@end table
To specify multiple attributes, separate them by commas within the
@@ -1877,6 +2015,9 @@ closing curly brace of a complete enum, struct or union type
@emph{definition} and the @code{packed} attribute only past the closing
brace of a definition.
+You may also specify attributes between the enum, struct or union
+tag and the name of the type rather than after the closing brace.
+
@table @code
@cindex @code{aligned} attribute
@item aligned (@var{alignment})
@@ -1884,12 +2025,12 @@ This attribute specifies a minimum alignment (in bytes) for variables
of the specified type. For example, the declarations:
@smallexample
-struct S @{ short f[3]; @} __attribute__ ((aligned (8));
-typedef int more_aligned_int __attribute__ ((aligned (8));
+struct S @{ short f[3]; @} __attribute__ ((aligned (8)));
+typedef int more_aligned_int __attribute__ ((aligned (8)));
@end smallexample
@noindent
-force the compiler to insure (as fas as it can) that each variable whose
+force the compiler to insure (as far as it can) that each variable whose
type is @code{struct S} or @code{more_aligned_int} will be allocated and
aligned @emph{at least} on a 8-byte boundary. On a Sparc, having all
variables of type @code{struct S} aligned to 8-byte boundaries allows
@@ -1969,21 +2110,76 @@ flag on the line is equivalent to specifying the @code{packed}
attribute on all @code{enum} definitions.
You may only specify this attribute after a closing curly brace on an
-@code{enum} definition, not in a @code{typedef} declaration.
+@code{enum} definition, not in a @code{typedef} declaration, unless that
+declaration also contains the definition of the @code{enum}.
@item transparent_union
This attribute, attached to a @code{union} type definition, indicates
-that any variable having that union type should, if passed to a
-function, be passed in the same way that the first union member would be
-passed. For example:
+that any function parameter having that union type causes calls to that
+function to be treated in a special way.
+
+First, the argument corresponding to a transparent union type can be of
+any type in the union; no cast is required. Also, if the union contains
+a pointer type, the corresponding argument can be a null pointer
+constant or a void pointer expression; and if the union contains a void
+pointer type, the corresponding argument can be any pointer expression.
+If the union member type is a pointer, qualifiers like @code{const} on
+the referenced type must be respected, just as with normal pointer
+conversions.
+
+Second, the argument is passed to the function using the calling
+conventions of first member of the transparent union, not the calling
+conventions of the union itself. All members of the union must have the
+same machine representation; this is necessary for this argument passing
+to work properly.
+
+Transparent unions are designed for library functions that have multiple
+interfaces for compatibility reasons. For example, suppose the
+@code{wait} function must accept either a value of type @code{int *} to
+comply with Posix, or a value of type @code{union wait *} to comply with
+the 4.1BSD interface. If @code{wait}'s parameter were @code{void *},
+@code{wait} would accept both kinds of arguments, but it would also
+accept any other pointer type and this would make argument type checking
+less useful. Instead, @code{<sys/wait.h>} might define the interface
+as follows:
+
+@smallexample
+typedef union
+ @{
+ int *__ip;
+ union wait *__up;
+ @} wait_status_ptr_t __attribute__ ((__transparent_union__));
+
+pid_t wait (wait_status_ptr_t);
+@end smallexample
+
+This interface allows either @code{int *} or @code{union wait *}
+arguments to be passed, using the @code{int *} calling convention.
+The program can call @code{wait} with arguments of either type:
+
+@example
+int w1 () @{ int w; return wait (&w); @}
+int w2 () @{ union wait w; return wait (&w); @}
+@end example
+
+With this interface, @code{wait}'s implementation might look like this:
@example
-union foo
+pid_t wait (wait_status_ptr_t p)
@{
- char a;
- int x[2];
-@} __attribute__ ((transparent_union));
+ return waitpid (-1, p.__ip, 0);
+@}
@end example
+
+@item unused
+When attached to a type (including a @code{union} or a @code{struct}),
+this attribute means that variables of that type are meant to appear
+possibly unused. GNU CC will not produce a warning for any variables of
+that type, even if the variable appears to do nothing. This is often
+the case with lock or thread classes, which are usually defined and then
+not referenced, but contain constructors and destructors that have
+nontrivial bookkeeping functions.
+
@end table
To specify multiple attributes, separate them by commas within the
@@ -2085,14 +2281,14 @@ did the easy thing, and turned it off.
@cindex assembler instructions
@cindex registers
-In an assembler instruction using @code{asm}, you can now specify the
-operands of the instruction using C expressions. This means no more
-guessing which registers or memory locations will contain the data you want
+In an assembler instruction using @code{asm}, you can specify the
+operands of the instruction using C expressions. This means you need not
+guess which registers or memory locations will contain the data you want
to use.
-You must specify an assembler instruction template much like what appears
-in a machine description, plus an operand constraint string for each
-operand.
+You must specify an assembler instruction template much like what
+appears in a machine description, plus an operand constraint string for
+each operand.
For example, here is how to use the 68881's @code{fsinx} instruction:
@@ -2103,64 +2299,66 @@ asm ("fsinx %1,%0" : "=f" (result) : "f" (angle));
@noindent
Here @code{angle} is the C expression for the input operand while
@code{result} is that of the output operand. Each has @samp{"f"} as its
-operand constraint, saying that a floating point register is required. The
-@samp{=} in @samp{=f} indicates that the operand is an output; all output
-operands' constraints must use @samp{=}. The constraints use the same
-language used in the machine description (@pxref{Constraints}).
-
-Each operand is described by an operand-constraint string followed by the C
-expression in parentheses. A colon separates the assembler template from
-the first output operand, and another separates the last output operand
-from the first input, if any. Commas separate output operands and separate
-inputs. The total number of operands is limited to ten or to the maximum
-number of operands in any instruction pattern in the machine description,
-whichever is greater.
-
-If there are no output operands, and there are input operands, then there
-must be two consecutive colons surrounding the place where the output
+operand constraint, saying that a floating point register is required.
+The @samp{=} in @samp{=f} indicates that the operand is an output; all
+output operands' constraints must use @samp{=}. The constraints use the
+same language used in the machine description (@pxref{Constraints}).
+
+Each operand is described by an operand-constraint string followed by
+the C expression in parentheses. A colon separates the assembler
+template from the first output operand and another separates the last
+output operand from the first input, if any. Commas separate the
+operands within each group. The total number of operands is limited to
+ten or to the maximum number of operands in any instruction pattern in
+the machine description, whichever is greater.
+
+If there are no output operands but there are input operands, you must
+place two consecutive colons surrounding the place where the output
operands would go.
Output operand expressions must be lvalues; the compiler can check this.
-The input operands need not be lvalues. The compiler cannot check whether
-the operands have data types that are reasonable for the instruction being
-executed. It does not parse the assembler instruction template and does
-not know what it means, or whether it is valid assembler input. The
-extended @code{asm} feature is most often used for machine instructions
-that the compiler itself does not know exist. If the output expression
-cannot be directly addressed (for example, it is a bit field), your
-constraint must allow a register. In that case, GNU CC will use
-the register as the output of the @code{asm}, and then store that
-register into the output.
-
-The output operands must be write-only; GNU CC will assume that the values
-in these operands before the instruction are dead and need not be
-generated. Extended asm does not support input-output or read-write
-operands. For this reason, the constraint character @samp{+}, which
-indicates such an operand, may not be used.
-
-When the assembler instruction has a read-write operand, or an operand
-in which only some of the bits are to be changed, you must logically
-split its function into two separate operands, one input operand and one
-write-only output operand. The connection between them is expressed by
-constraints which say they need to be in the same location when the
-instruction executes. You can use the same C expression for both
-operands, or different expressions. For example, here we write the
-(fictitious) @samp{combine} instruction with @code{bar} as its read-only
-source operand and @code{foo} as its read-write destination:
+The input operands need not be lvalues. The compiler cannot check
+whether the operands have data types that are reasonable for the
+instruction being executed. It does not parse the assembler instruction
+template and does not know what it means or even whether it is valid
+assembler input. The extended @code{asm} feature is most often used for
+machine instructions the compiler itself does not know exist. If
+the output expression cannot be directly addressed (for example, it is a
+bit field), your constraint must allow a register. In that case, GNU CC
+will use the register as the output of the @code{asm}, and then store
+that register into the output.
+
+The ordinary output operands must be write-only; GNU CC will assume that
+the values in these operands before the instruction are dead and need
+not be generated. Extended asm supports input-output or read-write
+operands. Use the constraint character @samp{+} to indicate such an
+operand and list it with the output operands.
+
+When the constraints for the read-write operand (or the operand in which
+only some of the bits are to be changed) allows a register, you may, as
+an alternative, logically split its function into two separate operands,
+one input operand and one write-only output operand. The connection
+between them is expressed by constraints which say they need to be in
+the same location when the instruction executes. You can use the same C
+expression for both operands, or different expressions. For example,
+here we write the (fictitious) @samp{combine} instruction with
+@code{bar} as its read-only source operand and @code{foo} as its
+read-write destination:
@example
asm ("combine %2,%0" : "=r" (foo) : "0" (foo), "g" (bar));
@end example
@noindent
-The constraint @samp{"0"} for operand 1 says that it must occupy the same
-location as operand 0. A digit in constraint is allowed only in an input
-operand, and it must refer to an output operand.
+The constraint @samp{"0"} for operand 1 says that it must occupy the
+same location as operand 0. A digit in constraint is allowed only in an
+input operand and it must refer to an output operand.
Only a digit in the constraint can guarantee that one operand will be in
-the same place as another. The mere fact that @code{foo} is the value of
-both operands is not enough to guarantee that they will be in the same
-place in the generated assembler code. The following would not work:
+the same place as another. The mere fact that @code{foo} is the value
+of both operands is not enough to guarantee that they will be in the
+same place in the generated assembler code. The following would not
+work reliably:
@example
asm ("combine %2,%0" : "=r" (foo) : "r" (foo), "g" (bar));
@@ -2174,10 +2372,10 @@ register (copying it afterward to @code{foo}'s own address). Of course,
since the register for operand 1 is not even mentioned in the assembler
code, the result will not work, but GNU CC can't tell that.
-Some instructions clobber specific hard registers. To describe this, write
-a third colon after the input operands, followed by the names of the
-clobbered hard registers (given as strings). Here is a realistic example
-for the Vax:
+Some instructions clobber specific hard registers. To describe this,
+write a third colon after the input operands, followed by the names of
+the clobbered hard registers (given as strings). Here is a realistic
+example for the VAX:
@example
asm volatile ("movc3 %0,%1,%2"
@@ -2187,32 +2385,32 @@ asm volatile ("movc3 %0,%1,%2"
@end example
If you refer to a particular hardware register from the assembler code,
-then you will probably have to list the register after the third colon
-to tell the compiler that the register's value is modified. In many
-assemblers, the register names begin with @samp{%}; to produce one
-@samp{%} in the assembler code, you must write @samp{%%} in the input.
-
-If your assembler instruction can alter the condition code register,
-add @samp{cc} to the list of clobbered registers. GNU CC on some
-machines represents the condition codes as a specific hardware
-register; @samp{cc} serves to name this register. On other machines,
-the condition code is handled differently, and specifying @samp{cc}
-has no effect. But it is valid no matter what the machine.
+you will probably have to list the register after the third colon to
+tell the compiler the register's value is modified. In some assemblers,
+the register names begin with @samp{%}; to produce one @samp{%} in the
+assembler code, you must write @samp{%%} in the input.
+
+If your assembler instruction can alter the condition code register, add
+@samp{cc} to the list of clobbered registers. GNU CC on some machines
+represents the condition codes as a specific hardware register;
+@samp{cc} serves to name this register. On other machines, the
+condition code is handled differently, and specifying @samp{cc} has no
+effect. But it is valid no matter what the machine.
If your assembler instruction modifies memory in an unpredictable
-fashion, add @samp{memory} to the list of clobbered registers.
-This will cause GNU CC to not keep memory values cached in
-registers across the assembler instruction.
+fashion, add @samp{memory} to the list of clobbered registers. This
+will cause GNU CC to not keep memory values cached in registers across
+the assembler instruction.
-You can put multiple assembler instructions together in a single @code{asm}
-template, separated either with newlines (written as @samp{\n}) or with
-semicolons if the assembler allows such semicolons. The GNU assembler
-allows semicolons and all Unix assemblers seem to do so. The input
-operands are guaranteed not to use any of the clobbered registers, and
-neither will the output operands' addresses, so you can read and write the
-clobbered registers as many times as you like. Here is an example of
-multiple instructions in a template; it assumes that the subroutine
-@code{_foo} accepts arguments in registers 9 and 10:
+You can put multiple assembler instructions together in a single
+@code{asm} template, separated either with newlines (written as
+@samp{\n}) or with semicolons if the assembler allows such semicolons.
+The GNU assembler allows semicolons and most Unix assemblers seem to do
+so. The input operands are guaranteed not to use any of the clobbered
+registers, and neither will the output operands' addresses, so you can
+read and write the clobbered registers as many times as you like. Here
+is an example of multiple instructions in a template; it assumes the
+subroutine @code{_foo} accepts arguments in registers 9 and 10:
@example
asm ("movl %0,r9;movl %1,r10;call _foo"
@@ -2221,16 +2419,16 @@ asm ("movl %0,r9;movl %1,r10;call _foo"
: "r9", "r10");
@end example
-Unless an output operand has the @samp{&} constraint modifier, GNU CC may
-allocate it in the same register as an unrelated input operand, on the
-assumption that the inputs are consumed before the outputs are produced.
+Unless an output operand has the @samp{&} constraint modifier, GNU CC
+may allocate it in the same register as an unrelated input operand, on
+the assumption the inputs are consumed before the outputs are produced.
This assumption may be false if the assembler code actually consists of
more than one instruction. In such a case, use @samp{&} for each output
-operand that may not overlap an input.
-@xref{Modifiers}.
+operand that may not overlap an input. @xref{Modifiers}.
-If you want to test the condition code produced by an assembler instruction,
-you must include a branch and a label in the @code{asm} construct, as follows:
+If you want to test the condition code produced by an assembler
+instruction, you must include a branch and a label in the @code{asm}
+construct, as follows:
@example
asm ("clr %0;frob %1;beq 0f;mov #1,%0;0:"
@@ -2243,8 +2441,8 @@ This assumes your assembler supports local labels, as the GNU assembler
and most Unix assemblers do.
Speaking of labels, jumps from one @code{asm} to another are not
-supported. The compiler's optimizers do not know about these jumps,
-and therefore they cannot take account of them when deciding how to
+supported. The compiler's optimizers do not know about these jumps, and
+therefore they cannot take account of them when deciding how to
optimize.
@cindex macros containing @code{asm}
@@ -2263,8 +2461,8 @@ Here the variable @code{__arg} is used to make sure that the instruction
operates on a proper @code{double} value, and to accept only those
arguments @code{x} which can convert automatically to a @code{double}.
-Another way to make sure the instruction operates on the correct data type
-is to use a cast in the @code{asm}. This is different from using a
+Another way to make sure the instruction operates on the correct data
+type is to use a cast in the @code{asm}. This is different from using a
variable @code{__arg} in that it converts more different types. For
example, if the desired type were @code{int}, casting the argument to
@code{int} would accept a pointer with no complaint, while assigning the
@@ -2272,27 +2470,40 @@ argument to an @code{int} variable named @code{__arg} would warn about
using a pointer unless the caller explicitly casts it.
If an @code{asm} has output operands, GNU CC assumes for optimization
-purposes that the instruction has no side effects except to change the
-output operands. This does not mean that instructions with a side effect
-cannot be used, but you must be careful, because the compiler may eliminate
-them if the output operands aren't used, or move them out of loops, or
-replace two with one if they constitute a common subexpression. Also, if
-your instruction does have a side effect on a variable that otherwise
-appears not to change, the old value of the variable may be reused later if
-it happens to be found in a register.
+purposes the instruction has no side effects except to change the output
+operands. This does not mean instructions with a side effect cannot be
+used, but you must be careful, because the compiler may eliminate them
+if the output operands aren't used, or move them out of loops, or
+replace two with one if they constitute a common subexpression. Also,
+if your instruction does have a side effect on a variable that otherwise
+appears not to change, the old value of the variable may be reused later
+if it happens to be found in a register.
You can prevent an @code{asm} instruction from being deleted, moved
significantly, or combined, by writing the keyword @code{volatile} after
the @code{asm}. For example:
@example
-#define set_priority(x) \
-asm volatile ("set_priority %0": /* no outputs */ : "g" (x))
-@end example
+#define get_and_set_priority(new) \
+(@{ int __old; \
+ asm volatile ("get_and_set_priority %0, %1": "=g" (__old) : "g" (new)); \
+ __old; @})
+b@end example
@noindent
-An instruction without output operands will not be deleted or moved
-significantly, regardless, unless it is unreachable.
+If you write an @code{asm} instruction with no outputs, GNU CC will know
+the instruction has side-effects and will not delete the instruction or
+move it outside of loops. If the side-effects of your instruction are
+not purely external, but will affect variables in your program in ways
+other than reading the inputs and clobbering the specified registers or
+memory, you should write the @code{volatile} keyword to prevent future
+versions of GNU CC from moving the instruction around within a core
+region.
+
+An @code{asm} instruction without any operands or clobbers (and ``old
+style'' @code{asm}) will not be deleted or moved significantly,
+regardless, unless it is unreachable, the same wasy as if you had
+written a @code{volatile} keyword.
Note that even a volatile @code{asm} instruction can be moved in ways
that appear insignificant to the compiler, such as across jump
@@ -2495,7 +2706,7 @@ Of course, it will not do to use more than a few of those.
@node Local Reg Vars
@subsection Specifying Registers for Local Variables
-@cindex local variables, specifying registers
+@cindex local variables, specifying registers
@cindex specifying registers for local variables
@cindex registers for local variables
@@ -2521,16 +2732,17 @@ In addition, operating systems on one type of cpu may differ in how they
name the registers; then you would need additional conditionals. For
example, some 68000 operating systems call this register @code{%a5}.
-Eventually there may be a way of asking the compiler to choose a register
-automatically, but first we need to figure out how it should choose and
-how to enable you to guide the choice. No solution is evident.
-
Defining such a register variable does not reserve the register; it
remains available for other uses in places where flow control determines
the variable's value is not live. However, these registers are made
-unavailable for use in the reload pass. I would not be surprised if
-excessive use of this feature leaves the compiler too few available
-registers to compile certain functions.
+unavailable for use in the reload pass; excessive use of this feature
+leaves the compiler too few available registers to compile certain
+functions.
+
+This option does not guarantee that GNU CC will generate code that has
+this variable in the register you specify at all times. You may not
+code an explicit reference to this register in an @code{asm} statement
+and assume it will always refer to this variable.
@node Alternate Keywords
@section Alternate Keywords
@@ -2631,6 +2843,49 @@ For example, @samp{#ifdef __FUNCTION__} does not have any special
meaning inside a function, since the preprocessor does not do anything
special with the identifier @code{__FUNCTION__}.
+@node Return Address
+@section Getting the Return or Frame Address of a Function
+
+These functions may be used to get information about the callers of a
+function.
+
+@table @code
+@item __builtin_return_address (@var{level})
+This function returns the return address of the current function, or of
+one of its callers. The @var{level} argument is number of frames to
+scan up the call stack. A value of @code{0} yields the return address
+of the current function, a value of @code{1} yields the return address
+of the caller of the current function, and so forth.
+
+The @var{level} argument must be a constant integer.
+
+On some machines it may be impossible to determine the return address of
+any function other than the current one; in such cases, or when the top
+of the stack has been reached, this function will return @code{0}.
+
+This function should only be used with a non-zero argument for debugging
+purposes.
+
+@item __builtin_frame_address (@var{level})
+This function is similar to @code{__builtin_return_address}, but it
+returns the address of the function frame rather than the return address
+of the function. Calling @code{__builtin_frame_address} with a value of
+@code{0} yields the frame address of the current function, a value of
+@code{1} yields the frame address of the caller of the current function,
+and so forth.
+
+The frame is the area on the stack which holds local variables and saved
+registers. The frame address is normally the address of the first word
+pushed on to the stack by the function. However, the exact definition
+depends upon the processor and the calling convention. If the processor
+has a dedicated frame pointer register, and the function has a frame,
+then @code{__builtin_frame_address} will return the value of the frame
+pointer register.
+
+The caveats that apply to @code{__builtin_return_address} apply to this
+function as well.
+@end table
+
@node C++ Extensions
@chapter Extensions to the C++ Language
@cindex extensions, C++ language
@@ -2672,7 +2927,7 @@ C++ programs:
@group
@var{type}
@var{functionname} (@var{args}) return @var{resultname};
-@{
+@{
@dots{}
@var{body}
@dots{}
@@ -2691,7 +2946,7 @@ m ()
@{
X b;
b.a = 23;
- return b;
+ return b;
@}
@end example
@@ -2720,7 +2975,7 @@ at the outset, and assigning to its @code{a} field directly:
X
m () return r;
@{
- r.a = 23;
+ r.a = 23;
@}
@end example
@@ -2731,13 +2986,13 @@ are executed @strong{before} any of the body of @code{m}.
Functions of this type impose no additional restrictions; in particular,
you can execute @code{return} statements, or return implicitly by
reaching the end of the function body (``falling off the edge'').
-Cases like
+Cases like
@example
X
m () return r (23);
@{
- return;
+ return;
@}
@end example
@@ -2751,7 +3006,7 @@ X
m () return r;
@{
X b;
- return b;
+ return b;
@}
@end example
@@ -2807,7 +3062,7 @@ behavior. For example, @code{MIN (i++, j++)} will fail, incrementing
the smaller counter twice. A GNU C extension allows you to write safe
macros that avoid this kind of problem (@pxref{Naming Types,,Naming an
Expression's Type}). However, writing @code{MIN} and @code{MAX} as
-macros also forces you to use function-call notation notation for a
+macros also forces you to use function-call notation for a
fundamental arithmetic operation. Using GNU C++ extensions, you can
write @w{@samp{int min = i <? j;}} instead.
@@ -2822,9 +3077,7 @@ works correctly.
@cindex destructors vs @code{goto}
In C++ programs, you can safely use the @code{goto} statement. When you
use it to exit a block which contains aggregates requiring destructors,
-the destructors will run before the @code{goto} transfers control. (In
-ANSI C++, @code{goto} is restricted to targets within the current
-block.)
+the destructors will run before the @code{goto} transfers control.
@cindex constructors vs @code{goto}
The compiler still forbids using @code{goto} to @emph{enter} a scope
@@ -2901,7 +3154,8 @@ If you use @samp{#pragma implementation} with no argument, it applies to
an include file with the same basename@footnote{A file's @dfn{basename}
was the name stripped of all leading path information and of trailing
suffixes, such as @samp{.h} or @samp{.C} or @samp{.cc}.} as your source
-file. For example, in @file{allclass.cc}, @samp{#pragma implementation}
+file. For example, in @file{allclass.cc}, giving just
+@samp{#pragma implementation}
by itself is equivalent to @samp{#pragma implementation "allclass.h"}.
In versions of GNU C++ prior to 2.6.0 @file{allclass.h} was treated as
@@ -2958,41 +3212,123 @@ problem, which I will refer to as the Borland model and the Cfront model.
@table @asis
@item Borland model
Borland C++ solved the template instantiation problem by adding the code
-equivalent of common blocks to their linker; template instances
-are emitted in each translation unit that uses them, and they are
-collapsed together at run time. The advantage of this model is that the
-linker only has to consider the object files themselves; there is no
-external complexity to worry about. This disadvantage is that
-compilation time is increased because the template code is being
-compiled repeatedly. Code written for this model tends to include
-definitions of all member templates in the header file, since they must
-be seen to be compiled.
+equivalent of common blocks to their linker; the compiler emits template
+instances in each translation unit that uses them, and the linker
+collapses them together. The advantage of this model is that the linker
+only has to consider the object files themselves; there is no external
+complexity to worry about. This disadvantage is that compilation time
+is increased because the template code is being compiled repeatedly.
+Code written for this model tends to include definitions of all
+templates in the header file, since they must be seen to be
+instantiated.
@item Cfront model
The AT&T C++ translator, Cfront, solved the template instantiation
problem by creating the notion of a template repository, an
-automatically maintained place where template instances are stored. As
-individual object files are built, notes are placed in the repository to
-record where templates and potential type arguments were seen so that
-the subsequent instantiation step knows where to find them. At link
-time, any needed instances are generated and linked in. The advantages
-of this model are more optimal compilation speed and the ability to use
-the system linker; to implement the Borland model a compiler vendor also
+automatically maintained place where template instances are stored. A
+more modern version of the repository works as follows: As individual
+object files are built, the compiler places any template definitions and
+instantiations encountered in the repository. At link time, the link
+wrapper adds in the objects in the repository and compiles any needed
+instances that were not previously emitted. The advantages of this
+model are more optimal compilation speed and the ability to use the
+system linker; to implement the Borland model a compiler vendor also
needs to replace the linker. The disadvantages are vastly increased
-complexity, and thus potential for error; theoretically, this should be
-just as transparent, but in practice it has been very difficult to build
+complexity, and thus potential for error; for some code this can be
+just as transparent, but in practice it can been very difficult to build
multiple programs in one directory and one program in multiple
-directories using Cfront. Code written for this model tends to separate
-definitions of non-inline member templates into a separate file, which
-is magically found by the link preprocessor when a template needs to be
-instantiated.
+directories. Code written for this model tends to separate definitions
+of non-inline member templates into a separate file, which should be
+compiled separately.
@end table
-Currently, g++ implements neither automatic model. In the mean time,
-you have three options for dealing with template instantiations:
+When used with GNU ld version 2.8 or later on an ELF system such as
+Linux/GNU or Solaris 2, or on Microsoft Windows, g++ supports the
+Borland model. On other systems, g++ implements neither automatic
+model.
+
+A future version of g++ will support a hybrid model whereby the compiler
+will emit any instantiations for which the template definition is
+included in the compile, and store template definitions and
+instantiation context information into the object file for the rest.
+The link wrapper will extract that information as necessary and invoke
+the compiler to produce the remaining instantiations. The linker will
+then combine duplicate instantiations.
+
+In the mean time, you have the following options for dealing with
+template instantiations:
@enumerate
@item
+Compile your template-using code with @samp{-frepo}. The compiler will
+generate files with the extension @samp{.rpo} listing all of the
+template instantiations used in the corresponding object files which
+could be instantiated there; the link wrapper, @samp{collect2}, will
+then update the @samp{.rpo} files to tell the compiler where to place
+those instantiations and rebuild any affected object files. The
+link-time overhead is negligible after the first pass, as the compiler
+will continue to place the instantiations in the same files.
+
+This is your best option for application code written for the Borland
+model, as it will just work. Code written for the Cfront model will
+need to be modified so that the template definitions are available at
+one or more points of instantiation; usually this is as simple as adding
+@code{#include <tmethods.cc>} to the end of each template header.
+
+For library code, if you want the library to provide all of the template
+instantiations it needs, just try to link all of its object files
+together; the link will fail, but cause the instantiations to be
+generated as a side effect. Be warned, however, that this may cause
+conflicts if multiple libraries try to provide the same instantiations.
+For greater control, use explicit instantiation as described in the next
+option.
+
+@item
+Compile your code with @samp{-fno-implicit-templates} to disable the
+implicit generation of template instances, and explicitly instantiate
+all the ones you use. This approach requires more knowledge of exactly
+which instances you need than do the others, but it's less
+mysterious and allows greater control. You can scatter the explicit
+instantiations throughout your program, perhaps putting them in the
+translation units where the instances are used or the translation units
+that define the templates themselves; you can put all of the explicit
+instantiations you need into one big file; or you can create small files
+like
+
+@example
+#include "Foo.h"
+#include "Foo.cc"
+
+template class Foo<int>;
+template ostream& operator <<
+ (ostream&, const Foo<int>&);
+@end example
+
+for each of the instances you need, and create a template instantiation
+library from those.
+
+If you are using Cfront-model code, you can probably get away with not
+using @samp{-fno-implicit-templates} when compiling files that don't
+@samp{#include} the member template definitions.
+
+If you use one big file to do the instantiations, you may want to
+compile it without @samp{-fno-implicit-templates} so you get all of the
+instances required by your explicit instantiations (but not by any
+other files) without having to specify them as well.
+
+g++ has extended the template instantiation syntax outlined in the
+Working Paper to allow forward declaration of explicit instantiations,
+explicit instantiation of members of template classes and instantiation
+of the compiler support data for a template class (i.e. the vtable)
+without instantiating any of its members:
+
+@example
+extern template int max (int, int);
+template void Foo<int>::f ();
+inline template class Foo<int>;
+@end example
+
+@item
Do nothing. Pretend g++ does implement automatic instantiation
management. Code written for the Borland model will work fine, but
each translation unit will contain instances of each of the templates it
@@ -3003,16 +3339,16 @@ duplication.
Add @samp{#pragma interface} to all files containing template
definitions. For each of these files, add @samp{#pragma implementation
"@var{filename}"} to the top of some @samp{.C} file which
-@samp{#include}s it. Then compile everything with -fexternal-templates.
-The templates will then only be expanded in the translation unit which
-implements them (i.e. has a @samp{#pragma implementation} line for the
-file where they live); all other files will use external references. If
-you're lucky, everything should work properly. If you get undefined
-symbol errors, you need to make sure that each template instance which
-is used in the program is used in the file which implements that
-template. If you don't have any use for a particular instance in that
-file, you can just instantiate it explicitly, using the syntax from the
-latest C++ working paper:
+@samp{#include}s it. Then compile everything with
+@samp{-fexternal-templates}. The templates will then only be expanded
+in the translation unit which implements them (i.e. has a @samp{#pragma
+implementation} line for the file where they live); all other files will
+use external references. If you're lucky, everything should work
+properly. If you get undefined symbol errors, you need to make sure
+that each template instance which is used in the program is used in the
+file which implements that template. If you don't have any use for a
+particular instance in that file, you can just instantiate it
+explicitly, using the syntax from the latest C++ working paper:
@example
template class A<int>;
@@ -3024,37 +3360,15 @@ using code written for the Cfront model, the file containing a class
template and the file containing its member templates should be
implemented in the same translation unit.
-A slight variation on this approach is to use the flag
--falt-external-templates instead; this flag causes template instances to
-be emitted in the translation unit that implements the header where they
-are first instantiated, rather than the one which implements the file
-where the templates are defined. This header must be the same in all
-translation units, or things are likely to break.
+A slight variation on this approach is to instead use the flag
+@samp{-falt-external-templates}; this flag causes template
+instances to be emitted in the translation unit that implements the
+header where they are first instantiated, rather than the one which
+implements the file where the templates are defined. This header must
+be the same in all translation units, or things are likely to break.
@xref{C++ Interface,,Declarations and Definitions in One Header}, for
more discussion of these pragmas.
-
-@item
-Explicitly instantiate all the template instances you use, and compile
-with -fno-implicit-templates. This is probably your best bet; it may
-require more knowledge of exactly which templates you are using, but
-it's less mysterious than the previous approach, and it doesn't require
-any @samp{#pragma}s or other g++-specific code. You can scatter the
-instantiations throughout your program, you can create one big file to
-do all the instantiations, or you can create tiny files like
-
-@example
-#include "Foo.h"
-#include "Foo.cc"
-
-template class Foo<int>;
-@end example
-
-for each instance you need, and create a template instantiation library
-from those. I'm partial to the last, but your mileage may vary. If you
-are using Cfront-model code, you can probably get away with not using
--fno-implicit-templates when compiling files that don't @samp{#include}
-the member template definitions.
@end enumerate
@node C++ Signatures
@@ -3128,7 +3442,7 @@ S * p = &obj;
@noindent
defines a signature pointer @code{p} and initializes it to point to an
-object of type @code{C}.
+object of type @code{C}.
The member function call @w{@samp{int i = p->foo ();}}
executes @samp{obj.foo ()}.
diff --git a/contrib/gcc/f/BUGS b/contrib/gcc/f/BUGS
new file mode 100644
index 0000000..ae6efd9
--- /dev/null
+++ b/contrib/gcc/f/BUGS
@@ -0,0 +1,211 @@
+This file lists known bugs in the GNU Fortran compiler. Copyright (C)
+1995, 1996 Free Software Foundation, Inc. You may copy, distribute,
+and modify it freely as long as you preserve this copyright notice and
+permission notice.
+
+Bugs in GNU Fortran
+*******************
+
+ This section identifies bugs that `g77' *users* might run into in
+the `egcs'-1.1.2 version of `g77'. This includes bugs that are
+actually in the `gcc' back end (GBE) or in `libf2c', because those sets
+of code are at least somewhat under the control of (and necessarily
+intertwined with) `g77', so it isn't worth separating them out.
+
+ For information on bugs in *other* versions of `g77', see
+`egcs/gcc/f/NEWS'.
+
+ An online, "live" version of this document (derived directly from
+the up-to-date mainline version of `g77' within `egcs') is available at
+`http://egcs.cygnus.com/onlinedocs/g77_bugs.html'.
+
+ For information on bugs that might afflict people who configure,
+port, build, and install `g77', see "Problems Installing" in
+`egcs/gcc/f/INSTALL'.
+
+ * `g77' generates bad code for assignments, or other conversions, of
+ `REAL' or `COMPLEX' constant expressions to type `INTEGER(KIND=2)'
+ (often referred to as `INTEGER*8').
+
+ For example, `INTEGER*8 J; J = 4E10' is miscompiled on some
+ systems--the wrong value is stored in J.
+
+ * The `IDate' Intrinsic (VXT) fails to return the year in the
+ documented, non-Y2K-compliant range of 0-99, instead returning 100
+ for the year 2000.
+
+ * Year 2000 (Y2K) compliance information is missing from the
+ documentation.
+
+ * `g77' crashes when compiling I/O statements using keywords that
+ define `INTEGER' values, such as `IOSTAT=J', where J is other than
+ default `INTEGER' (such as `INTEGER*2').
+
+ * The `-ax' option is not obeyed when compiling Fortran programs.
+ (It is not passed to the `f771' driver.)
+
+ * `g77' fails to warn about a reference to a function when the
+ corresponding *subsequent* function program unit disagrees with
+ the reference concerning the type of the function.
+
+ * Automatic arrays possibly aren't working on HP-UX systems, at
+ least in HP-UX version 10.20. Writing into them apparently causes
+ over-writing of statically declared data in the main program.
+ This probably means the arrays themselves are being
+ under-allocated, or pointers to them being improperly handled,
+ e.g. not passed to other procedures as they should be.
+
+ * `g77' fails to warn about use of a "live" iterative-DO variable as
+ an implied-DO variable in a `WRITE' or `PRINT' statement (although
+ it does warn about this in a `READ' statement).
+
+ * Something about `g77''s straightforward handling of label
+ references and definitions sometimes prevents the GBE from
+ unrolling loops. Until this is solved, try inserting or removing
+ `CONTINUE' statements as the terminal statement, using the `END DO'
+ form instead, and so on.
+
+ * Some confusion in diagnostics concerning failing `INCLUDE'
+ statements from within `INCLUDE''d or `#include''d files.
+
+ * `g77' assumes that `INTEGER(KIND=1)' constants range from `-2**31'
+ to `2**31-1' (the range for two's-complement 32-bit values),
+ instead of determining their range from the actual range of the
+ type for the configuration (and, someday, for the constant).
+
+ Further, it generally doesn't implement the handling of constants
+ very well in that it makes assumptions about the configuration
+ that it no longer makes regarding variables (types).
+
+ Included with this item is the fact that `g77' doesn't recognize
+ that, on IEEE-754/854-compliant systems, `0./0.' should produce a
+ NaN and no warning instead of the value `0.' and a warning. This
+ is to be fixed in version 0.6, when `g77' will use the `gcc' back
+ end's constant-handling mechanisms to replace its own.
+
+ * `g77' uses way too much memory and CPU time to process large
+ aggregate areas having any initialized elements.
+
+ For example, `REAL A(1000000)' followed by `DATA A(1)/1/' takes up
+ way too much time and space, including the size of the generated
+ assembler file. This is to be mitigated somewhat in version 0.6.
+
+ Version 0.5.18 improves cases like this--specifically, cases of
+ *sparse* initialization that leave large, contiguous areas
+ uninitialized--significantly. However, even with the
+ improvements, these cases still require too much memory and CPU
+ time.
+
+ (Version 0.5.18 also improves cases where the initial values are
+ zero to a much greater degree, so if the above example ends with
+ `DATA A(1)/0/', the compile-time performance will be about as good
+ as it will ever get, aside from unrelated improvements to the
+ compiler.)
+
+ Note that `g77' does display a warning message to notify the user
+ before the compiler appears to hang.
+
+ * `g77' doesn't emit variable and array members of common blocks for
+ use with a debugger (the `-g' command-line option). The code is
+ present to do this, but doesn't work with at least one debug
+ format--perhaps it works with others. And it turns out there's a
+ similar bug for local equivalence areas, so that has been disabled
+ as well.
+
+ As of Version 0.5.19, a temporary kludge solution is provided
+ whereby some rudimentary information on a member is written as a
+ string that is the member's value as a character string.
+
+ * When debugging, after starting up the debugger but before being
+ able to see the source code for the main program unit, the user
+ must currently set a breakpoint at `MAIN__' (or `MAIN___' or
+ `MAIN_' if `MAIN__' doesn't exist) and run the program until it
+ hits the breakpoint. At that point, the main program unit is
+ activated and about to execute its first executable statement, but
+ that's the state in which the debugger should start up, as is the
+ case for languages like C.
+
+ * Debugging `g77'-compiled code using debuggers other than `gdb' is
+ likely not to work.
+
+ Getting `g77' and `gdb' to work together is a known
+ problem--getting `g77' to work properly with other debuggers, for
+ which source code often is unavailable to `g77' developers, seems
+ like a much larger, unknown problem, and is a lower priority than
+ making `g77' and `gdb' work together properly.
+
+ On the other hand, information about problems other debuggers have
+ with `g77' output might make it easier to properly fix `g77', and
+ perhaps even improve `gdb', so it is definitely welcome. Such
+ information might even lead to all relevant products working
+ together properly sooner.
+
+ * `g77' doesn't work perfectly on 64-bit configurations such as the
+ Digital Semiconductor ("DEC") Alpha.
+
+ This problem is largely resolved as of version 0.5.23. Version
+ 0.6 should solve most or all remaining problems (such as
+ cross-compiling involving 64-bit machines).
+
+ * Maintainers of gcc report that the back end definitely has "broken"
+ support for `COMPLEX' types. Based on their input, it seems many
+ of the problems affect only the more-general facilities for gcc's
+ `__complex__' type, such as `__complex__ int' (where the real and
+ imaginary parts are integers) that GNU Fortran does not use.
+
+ Version 0.5.20 of `g77' works around this problem by not using the
+ back end's support for `COMPLEX'. The new option
+ `-fno-emulate-complex' avoids the work-around, reverting to using
+ the same "broken" mechanism as that used by versions of `g77'
+ prior to 0.5.20.
+
+ * `g77' currently inserts needless padding for things like `COMMON
+ A,IPAD' where `A' is `CHARACTER*1' and `IPAD' is `INTEGER(KIND=1)'
+ on machines like x86, because the back end insists that `IPAD' be
+ aligned to a 4-byte boundary, but the processor has no such
+ requirement (though it is usually good for performance).
+
+ The `gcc' back end needs to provide a wider array of
+ specifications of alignment requirements and preferences for
+ targets, and front ends like `g77' should take advantage of this
+ when it becomes available.
+
+ * The x86 target's `-malign-double' option no longer reliably aligns
+ double-precision variables and arrays when they are placed in the
+ stack frame.
+
+ This can significantly reduce the performance of some applications,
+ even on a run-to-run basis (that is, performance measurements can
+ vary fairly widely depending on whether frequently used variables
+ are properly aligned, and that can change from one program run to
+ the next, even from one procedure call to the next).
+
+ Versions 0.5.22 and earlier of `g77' included a patch to `gcc'
+ that enabled this, but that patch has been deemed an improper
+ (probably buggy) one for version 2.8 of `gcc' and for `egcs'.
+
+ Note that version 1.1 of `egcs' aligns double-precision variables
+ and arrays when they are in static storage even if
+ `-malign-double' is not specified.
+
+ There is ongoing investigation into how to make `-malign-double'
+ work properly, also into how to make it unnecessary to get all
+ double-precision variables and arrays aligned when such alignment
+ would not violate the relevant specifications for processor and
+ inter-procedural interfaces.
+
+ For a suite of programs to test double-precision alignment, see
+ `ftp://alpha.gnu.org/gnu/g77/align/'.
+
+ * The `libf2c' routines that perform some run-time arithmetic on
+ `COMPLEX' operands were modified circa version 0.5.20 of `g77' to
+ work properly even in the presence of aliased operands.
+
+ While the `g77' and `netlib' versions of `libf2c' differ on how
+ this is accomplished, the main differences are that we believe the
+ `g77' version works properly even in the presence of *partially*
+ aliased operands.
+
+ However, these modifications have reduced performance on targets
+ such as x86, due to the extra copies of operands involved.
+
diff --git a/contrib/gcc/f/ChangeLog b/contrib/gcc/f/ChangeLog
new file mode 100644
index 0000000..bc8637d
--- /dev/null
+++ b/contrib/gcc/f/ChangeLog
@@ -0,0 +1,4804 @@
+Sun Mar 14 02:38:07 PST 1999 Jeff Law (law@cygnus.com)
+
+ * egcs-1.1.2 Released.
+
+1999-03-13 Craig Burley <craig@jcb-sc.com>
+
+ * bugs.texi: Document newly discovered bug (19990313-*.f tests).
+
+1999-03-13 Craig Burley <craig@jcb-sc.com>
+
+ * bugs.texi: Editorial fixes.
+
+1999-03-11 Craig Burley <craig@jcb-sc.com>
+
+ * bugs.texi, g77.texi, news.texi: Point to URLs for live
+ versions of docs.
+ Clarify which versions to which these docs apply.
+ Other minor fix-ups.
+
+1999-03-05 Craig Burley <craig@jcb-sc.com>
+
+ * news.texi: IDATE (VXT) fixed to return year as 0..99.
+
+1999-03-03 Craig Burley <craig@jcb-sc.com>
+
+ * bugs.texi: Update with latest bug-fixes from 1.2.
+ Remove fixed bugs.
+
+1999-02-26 Craig Burley <craig@jcb-sc.com>
+
+ * news.texi: List fixes to Date_and_Time and LStat, plus
+ the docs, under a new heading for egcs 1.1.2.
+
+1999-02-26 Craig Burley <craig@jcb-sc.com>
+
+ * intdoc.in (STAT_func, STAT_subr,
+ FSTAT_func, FSTAT_subr, LSTAT_func, LSTAT_subr):
+ Properly order array elements. Specify N/A return values.
+
+1999-02-26 Craig Burley <craig@jcb-sc.com>
+
+ * intdoc.in (DATE_AND_TIME): Explain that VALUES(7) holds
+ seconds, and VALUES(8), therefore, the milliseconds.
+
+1999-02-26 Craig Burley <craig@jcb-sc.com>
+
+ * bugs.texi: Mention bugs known fixed in egcs 1.2 as of now.
+
+1999-02-26 Craig Burley <craig@jcb-sc.com>
+
+ Fix what evidently remains of these, for 4.4bsd:
+ Tue Aug 18 21:41:31 1998 Jeffrey A Law (law@cygnus.com)
+ * Make-lang.in: Add several "else true" clauses to deal with lame
+ systems.
+
+1999-02-25 Andreas Jaeger <aj@arthur.rhein-neckar.de>
+
+ * f/intdoc.in: Add missing `,' after cross references.
+
+1999-02-20 Craig Burley <craig@jcb-sc.com>
+
+ * g77.texi: Properly attribute Priest document; clarify
+ that it is in the .ps version of the Goldberg document.
+
+1999-02-18 Craig Burley <craig@jcb-sc.com>
+
+ * intdoc.in (LOG10): Fix typo.
+
+1999-02-17 Dave Love <fx@gnu.org>
+
+ * intdoc.in: Say `common' logarithm for log10.
+
+1999-02-15 Craig Burley <craig@jcb-sc.com>
+
+ * g77.texi: Change my email address in a couple of places.
+
+1999-02-14 Craig Burley <craig@jcb-sc.com>
+
+ * version.c: Bump for 1998-10-02 change (forgot to do this
+ before).
+
+1999-02-14 Craig Burley <craig@jcb-sc.com>
+
+ * intdoc.in (LOG10): Fix description.
+
+1999-02-14 Craig Burley <craig@jcb-sc.com>
+
+ * news.texi: Mention fix for SIGNAL invocation circa egcs-1.1.
+
+1999-02-14 Craig Burley <craig@jcb-sc.com>
+
+ * intdoc.in (MCLOCK8, TIME8): Warn about lower range on
+ 32-bit systems.
+
+Sat Feb 6 17:17:09 1999 Jeffrey A Law (law@cygnus.com)
+
+ * g77.texi: Update email addresses.
+
+1998-11-20 Dave Love <d.love@dl.ac.uk>
+
+ * g77.texi: Assorted minor changes.
+
+1998-11-19 Dave Love <d.love@dl.ac.uk>
+
+ * intdoc.in: Terminate some @xrefs with `,'.
+
+Mon Nov 9 23:13:30 1998 Jeffrey A Law (law@cygnus.com)
+
+ * g77.texi: Updates from Craig.
+
+1998-10-09 Dave Love <d.love@dl.ac.uk>
+
+ * g77.texi: Various updates.
+
+1998-10-02 Dave Love <d.love@dl.ac.uk>
+
+ * com.c (ffecom_expr_intrinsic_): Fix return type for RAND.
+
+Fri Oct 2 01:27:06 1998 Kamil Iskra <iskra@student.uci.agh.edu.pl>
+
+ * Make-lang.in (f77.install-common): Add missing "else true;".
+
+Sat Sep 5 23:55:15 1998 Jeffrey A Law (law@cygnus.com)
+
+ * news.texi: Tweaks from Craig.
+
+Tue Sep 1 10:00:21 1998 Craig Burley <burley@gnu.org>
+
+ * bugs.texi, g77.1, g77.texi, intdoc.in, news.texi: Doc updates
+ from Craig.
+
+1998-08-23 Dave Love <d.love@dl.ac.uk>
+
+ * g77.texi: Increment `version-g77' and fix a few typos.
+
+Tue Aug 11 08:12:14 1998 H.J. Lu (hjl@gnu.org)
+
+ * Make-lang.in (g77.o): Touch lang-f77 before checking it.
+
+1998-08-09 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in (f/g77.dvi): Replace non-working use of texi2dvi
+ with explicit use of tex.
+ (f77.mostlyclean): Remove TeX index files.
+
+ * g77install.texi (Prerequisites): Kluge round TeX lossage with
+ hyphen in @value in @code.
+
+Tue Aug 4 16:59:39 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_convert_narrow_, ffecom_convert_widen_):
+ Allow conversion from pointer to same-sized integer,
+ to fix invoking SIGNAL as a function.
+
+1998-07-26 Dave Love <d.love@dl.ac.uk>
+
+ * BUGS, INSTALL, NEWS: Rebuilt.
+
+Sat Jul 25 17:23:55 1998 Craig Burley <burley@gnu.org>
+
+ Fix 980615-0.f:
+ * stc.c (ffestc_R1229_start): Set info to ANY as well.
+
+Tue Jul 21 04:33:37 1998 Craig Burley <burley@gnu.org>
+
+ * g77spec.c (lang_specific_driver): Return unmolested
+ command line when --help seen.
+ Comment out code that printed g77-specific --help info.
+
+Sat Jul 18 19:16:48 1998 Craig Burley <burley@gnu.org>
+
+ * lang-options.h: Fix up doc strings.
+ Remove the unimplemented -fdcp-intrinsics-* options.
+
+ * str-1t.fin: Change mixed-case spelling of `GoTo' from
+ `Goto'.
+
+Thu Jul 16 13:26:36 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_finish_symbol_transform_): Revert change
+ of 1998-05-23, as it was too aggressive, in that it
+ prevented transformation of (used) functions before
+ primary code generation.
+
+1998-07-15 Dave Love <d.love@dl.ac.uk>
+
+ * intdoc.texi: Regenerated.
+
+Mon Jul 13 18:45:06 1998 Craig Burley <burley@gnu.org>
+
+ * Make-lang.in (f77.rebuilt): Fix to depend on
+ build-dir-based, not source-based, g77.info.
+
+ * g77.texi: Merge docs with 0.5.24.
+ * g77install.texi: Ditto.
+
+Mon Jul 13 18:02:29 1998 Craig Burley <burley@gnu.org>
+
+ Cleanups vis-a-vis g77-0.5.24:
+ * g77spec.c (lang_specific_driver): Tabify source.
+ * top.c (ffe_decode_option): Use fixed macro to set
+ internal-checking flag.
+ * top.h (ffe_set_is_do_internal_checks): Fix macro.
+
+Mon Jul 13 17:33:44 1998 Craig Burley <burley@gnu.org>
+
+ Cleanups vis-a-vis system.h cutover and g77-0.5.24:
+ * Makefile.in (fini.o): Define USE_HCONFIG macro
+ so source code doesn't have to.
+ * fini.c: Don't define USE_HCONFIG here, since
+ source code usually shouldn't care about this.
+ * ansify.c: Include stddef.h only if we have it.
+ * intdoc.c: Ditto.
+ * proj.h: Ditto.
+
+Mon Jul 13 17:30:29 1998 Nick Clifton <nickc@cygnus.com>
+
+ * lang-options.h: Format changed to work with --help support added
+ to gcc/toplev.c
+
+Mon Jul 13 11:54:03 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_push_tempvar): Replace kludge that
+ munged back-end globals directly with proper calls
+ to push_topmost_sequence and pop_topmost_sequence.
+
+1998-07-12 Dave Love <d.love@dl.ac.uk>
+
+ * version.c: Bump version.
+
+Sat Jul 11 19:24:32 1998 Craig Burley <burley@gnu.org>
+
+ Fix 980616-0.f:
+ * equiv.c (ffeequiv_offset_): Don't crash on various
+ possible ANY operands.
+
+Sat Jul 11 18:24:37 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_expr_) [FFEBLD_opCONTER]: Die if padding
+ for constant is non-zero.
+
+ * com.c (__eprintf): Delete this function, it is obsolete.
+
+1998-07-09 Dave Love <d.love@dl.ac.uk>
+
+ * intdoc.in (HOSTNM_func, HOSTNM_subr): Update last change.
+
+Thu Jul 9 00:45:59 1998 Craig Burley <burley@gnu.org>
+
+ Fix debugging of CHARACTER*(*), etc., which requires
+ emitting debug info on types like `ftnlen':
+ * com.c (ffecom_start_progunit_): Don't bother
+ resetting "invented" flag for identifier.
+ (ffecom_transform_equiv_): Don't bother zeroing
+ "ignored" flag for decl.
+ (pushdecl): No longer set "ignored", "used", or
+ "suppressed debug" flags for decls having "invented"
+ identifiers.
+
+1998-07-06 Mike Stump <mrs@wrs.com>
+
+ * Make-lang.in (f77.stage?): Use mv -f instead of just mv so that
+ we can move g77.c.
+
+1998-07-06 Dave Love <d.love@dl.ac.uk>
+
+ * intdoc.in (HOSTNM_func, HOSTNM_subr): Note possible need for
+ -lsocket.
+
+1998-07-05 Dave Love <d.love@dl.ac.uk>
+
+ * intdoc.in: Add entry for DATE_AND_TIME.
+
+ * intrin.def: Add implementation for DATE_AND_TIME. Make second
+ and third args of SYSTEM_CLOCK optional.
+
+ * com.c (ffecom_expr_intrinsic_): New case for DATE_AND_TIME.
+
+ * com-rt.def (FFECOM_gfrtSYSTEM_CLOCK): Call G77_system_clock_0,
+ not system_clock_.
+ (FFECOM_gfrtDATE_AND_TIME): New DEFGFRT.
+
+Wed Jul 1 11:19:13 1998 Craig Burley <burley@gnu.org>
+
+ Fix 980701-1.f (which was producing "unaligned trap"
+ on an Alpha running GNU/Linux, as predicted):
+ * equiv.c (ffeequiv_layout_local_): Don't bother
+ coping with pre-padding of entire area while building
+ it; do that instead after the building is done, and
+ do it by modifying only the modulo field. This covers
+ the case of alignment stringency being increased without
+ lowering the starting offset, unlike the previous changes,
+ and even more elegantly than those.
+
+ * target.c (ffetarget_align): Make sure alignments
+ are non-zero, just in case.
+
+Mon Jun 29 09:47:33 1998 Craig Burley <burley@gnu.org>
+
+ Fix 980628-*.f:
+ * bld.h: New `pad' field and accessor macros for
+ ACCTER, ARRTER, and CONTER ops.
+ * bld.c (ffebld_new_accter, ffebld_new_arrter,
+ ffebld_new_conter_with_orig): Initialize `pad' field
+ to zero.
+ * com.c (ffecom_transform_common_): Include initial
+ padding (aka modulo aka offset) in size calculation.
+ Copy initial padding value into FFE initialization expression
+ so the GBE transformation of that expression includes it.
+ Make array low bound 0 instead of 1, for consistency.
+ (ffecom_transform_equiv_): Include initial
+ padding (aka modulo aka offset) in size calculation.
+ Copy initial padding value into FFE initialization expression
+ so the GBE transformation of that expression includes it.
+ Make array low bound 0 instead of 1, for consistency.
+ (ffecom_expr_, case FFEBLD_opACCTER): Delete unused `size'
+ variable.
+ Track destination offset separately, allowing for
+ initial padding.
+ Don't bother setting initial PURPOSE offset if zero.
+ Include initial padding in size calculation.
+ (ffecom_expr_, case FFEBLD_opARRTER): Allow for
+ initial padding.
+ Include initial padding in size calculation.
+ Make array low bound 0 instead of 1, for consistency.
+ (ffecom_finish_global_): Make array low bound 0 instead
+ of 1, for consistency.
+ (ffecom_notify_init_storage): Copy `pad' field from old
+ ACCTER to new ARRTER.
+ (ffecom_notify_init_symbol): Ditto.
+ * data.c (ffedata_gather_): Initialize `pad' field in new
+ ARRTER to 0.
+ (ffedata_value_): Ditto.
+ * equiv.c (ffeequiv_layout_local_): When lowering start
+ of equiv area, extend lowering to maintain needed alignment.
+ * target.c (ffetarget_align): Handle negative offset correctly.
+
+ * global.c (ffeglobal_pad_common): Warn about non-zero
+ padding only the first time its seen.
+ If new padding larger than old, update old.
+ (ffeglobal_save_common): Use correct type for size throughout.
+ * global.h: Use correct type for size throughout.
+ (ffeglobal_common_pad): New macro.
+ (ffeglobal_pad): Delete this unused and broken macro.
+
+Fri Jun 26 11:54:19 1998 Craig Burley <burley@gnu.org>
+
+ * g77spec.c (lang_specific_driver): Put `-lg2c' in
+ front of any `-lm' that is seen.
+
+Mon Jun 22 23:12:05 1998 H.J. Lu (hjl@gnu.org)
+
+ * Make-lang.in (G77STAGESTUFF): Add g77.c.
+
+Mon Jun 15 23:39:24 1998 Craig Burley <burley@gnu.org>
+
+ * Make-lang.in (f/g77.info): Use -f when removing
+ pre-existing Info files, if any. (This rm command
+ can go away once makeinfo has been changed to delete
+ .info-N files beyond the last one it creates.)
+
+ * Make-lang.in ($(srcdir)/f/intdoc.texi): Compile
+ using $(INCLUDES) macro to get the new hconfig.h
+ and system.h headers.
+
+Mon Jun 15 22:21:57 1998 Craig Burley <burley@gnu.org>
+
+ Cutover to system.h:
+ * Make-lang.in:
+ * Makefile.in:
+ * ansify.c:
+ * bad.c:
+ * bld.c:
+ * com.c:
+ * com.h:
+ * expr.c:
+ * fini.c:
+ * g77spec.c:
+ * implic.c:
+ * intdoc.c:
+ * intrin.c:
+ * lex.c:
+ * lex.h:
+ * parse.c:
+ * proj.c:
+ * proj.h:
+ * src.c:
+ * src.h:
+ * stb.c:
+ * ste.c:
+ * target.c:
+ * top.c:
+ * system.j: New file.
+
+ Use toplev.h where appropriate:
+ * Make-lang.in:
+ * Makefile.in:
+ * bad.c:
+ * bld.c:
+ * com.c:
+ * lex.c:
+ * ste.c:
+ * top.c:
+ * toplev.j: New file.
+
+ Conditionalize all dumping/reporting routines so they don't
+ get built for gcc/egcs:
+ * bld.c:
+ * bld.h:
+ * com.c:
+ * equiv.c:
+ * equiv.h:
+ * sta.c:
+ * stt.c:
+ * stt.h:
+ * symbol.c:
+ * symbol.h:
+
+ Use hconfig.h instead of config.h where appropriate:
+ * Makefile.in (proj-h.o): Compile with -DUSE_HCONFIG.
+ * fini.c: Define USE_HCONFIG before including proj.h.
+
+ * Makefile.in (deps-kinda): Redirect stderr to stdout,
+ to eliminate diagnostics vis-a-vis g77spec.c.
+
+ * Makefile.in: Regenerate dependencies via deps-kinda.
+
+ * lex.c (ffelex_file_fixed, ffelex_file_free): Eliminate
+ apparently spurious warnings about uninitialized variables
+ `c', `column', and so on.
+
+Sat Jun 13 03:13:18 1998 Craig Burley <burley@gnu.org>
+
+ * g77spec.c (lang_specific_driver): Print out egcs
+ version info first, to be compatible with what some
+ test facilities expect.
+
+Wed Jun 10 13:17:32 1998 Dave Brolley <brolley@cygnus.com>
+
+ * top.h (ffe_decode_option): New argc/argv interface.
+ * top.c (ffe_decode_option): New argc/argv interface.
+ * parse.c (yyparse): New argc/argv interface for ffe_decode_option.
+ * com.c (lang_decode_option): New argc/argv interface.
+
+Mon Jun 1 19:37:42 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_init_0): Fix setup of INTEGER(KIND=7)
+ pointer type.
+ * info.c (ffeinfo_type): Don't crash on null type.
+ * expr.c (ffeexpr_fulfill_call_): Don't special-case
+ %LOC(expr) or LOC(expr).
+ Delete FFEGLOBAL_argsummaryPTR.
+ * global.c, global.h: Delete FFEGLOBAL_argsummaryPTR.
+
+Thu May 28 21:32:18 1998 Craig Burley <burley@gnu.org>
+
+ Restore circa-0.5.22 capabilities of `g77' driver:
+ * Make-lang.in (g77spec.o): Depend on f/version.h.
+ (g77version.o): New rule to compile g77 version info.
+ (g77$(exeext)): Depend on and link in g77version.o.
+ * g77spec.c: Rewrite to be more like 0.5.22 version
+ of g77.c, making filtering of command line smarter
+ so mixed Fortran and C (etc.) can be compiled, verbose
+ version info can be obtained, etc.
+ * lang-specs.h (f77-version): New "language" to support
+ "g77 -v" command under new gcc 2.8 regime.
+ * lex.c (ffelex_file_fixed): If -fnull-version, just
+ substitute a "source file" that prints out version info.
+ * top.c, top.h: Support -fnull-version.
+
+ * lang-specs.h: Use "%O" instead of OO macro to specify
+ object extension. Remove old stringizing cruft.
+
+ * Make-lang.in (g77.c, g77spec.o, g77.o, g77$(exeext),
+ g77-cross$(exeext), f771,
+ $(srcdir)/f/g77.info, $(srcdir)/f/g77.dvi,
+ $(srcdir)/f/intdoc.texi,
+ f77.install-common, f77.install-info, f77.install-man,
+ f77.uninstall, $(G77STAGESTUFF), f77.stage1, f77.stage2,
+ f77.stage3, f77.stage4, f77.distdir): Don't do anything
+ unless user specified "f77" or "F77" in $LANGUAGES either
+ during configuration or explicitly. For convenience of
+ various tests and to work around lack of the assignment
+ "LANGUAGES=$(BOOT_LANGUAGES)" in the "make stage1" command
+ of "make bootstrap" in gcc, use a touch file named "lang-f77"
+ to communicate whether this is the case.
+
+ * Make-lang.in (F77_FLAGS_TO_PASS): Delete this macro,
+ replace with minimal expansion of its former self in
+ each of the two instances where it was used.
+
+ * Makefile.in (HOST_CC): Delete this definition.
+
+ * com.c (index, rindex): Delete these declarations.
+
+ * proj.h: (isascii): Delete this.
+
+ * Make-lang.in (f77.install-common): Warn if `f77-install-ok'
+ flag-file exists, since it no longer triggers any activity.
+
+ Rename libf2c.a and f2c.h to libg2c.a and g2c.h,
+ normalize and simplify g77/libg2c build process:
+ * Make-lang.in: Remove all support for overwriting
+ /usr/bin/f77 etc., or whatever the actual names are
+ via $(prefix) and $(local_prefix). (g++ overwrites
+ /usr/bin/c++, but then it's often the only C++ compiler
+ on the system; f77 often exists on systems that are
+ installing g77.)
+ (f77.realclean): Remove obsolete target.
+ (g77.c, g77$(exeext)): Minor changes to look more like g++'s
+ stuff.
+ (f771): Now built with srcdir=gcc/f, not srcdir=gcc, to be
+ more like g++ and such.
+ (f/Makefile): Removed, as g++ doesn't need this rule.
+ (f77.install-common): No longer install f77, etc.
+ (f77.install-man): No longer install f77.1.
+ (f77.uninstall): No longer uninstall f77, f77.1, etc.
+ (f77.stage1, f77.stage2, f77.stage3, f77.stage4): Do work
+ only if "f77" appears in $(LANGUAGES).
+ (Note: gcc's Makefile.in's bootstrap target should set
+ LANGUAGES=$(BOOT_LANGUAGES) when making the stage1 target.)
+ * Makefile.in: Update vis-a-vis gcc/cp/Makefile.in.
+ (none): Remove.
+ (g77-only): Relocate.
+ (all.indirect, f771, *.o): Now assumes current directory
+ is this dir (gcc/f), not the parent directory.
+ (TAGS): Remove "echo 'parse.y,0' >> TAGS ;" line.
+ * config-lang.in: Delete commented-out code.
+ Fix stagestuff definition. Add more stuff to
+ diff_excludes definition. Don't create any directories.
+ Set outputs to f/Makefile, to get variable substition
+ to happen (what does that really do, anyway?!).
+ * g77spec.c: Rename libf2c to libg2c.
+
+ * com.h: Remove all of the gcc back-end decls,
+ since egcs should have all of them correct.
+
+ * com.c: Include "proj.h" before anything else,
+ as that's how things are supposed to work.
+ * ste.c: Ditto.
+
+ * bad.c: Include "flags.j" here, since some diagnostics
+ check flag_pedantic_errors.
+
+ * Makefile.in (f/*.o): Rebuild dependencies via
+ deps-kinda.
+
+ * output.j: New source file.
+ * Make-lang.in (F77_SRCS): Update accordingly.
+ * Makefile.in (OUTPUT_H): Ditto.
+ (deps-kinda): Ditto.
+ * com.c: Include "output.j" here.
+ * lex.c: Ditto.
+
+Mon May 25 03:34:42 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_expr_): Fix D**I and Z**I cases to
+ not convert (DOUBLE PRECISION) D and (DOUBLE COMPLEX) Z
+ to INTEGER. (This is dead code here anyway.)
+
+Sat May 23 06:32:52 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_finish_symbol_transform_): Don't transform
+ statement (nested) functions, to avoid gcc compiling them
+ and thus producing linker errors if they refer to undefined
+ external functions. But warn if they're unused and -Wunused.
+ * bad.def (FFEBAD_SFUNC_UNUSED): New diagnostic.
+
+Wed May 20 12:12:55 1998 Craig Burley <burley@gnu.org>
+
+ * Version 0.5.23 released.
+
+Tue May 19 14:52:41 1998 Craig Burley <burley@gnu.org>
+
+ * bad.def (FFEBAD_OPEN_UNSUPPORTED, FFEBAD_INQUIRE_UNSUPPORTED,
+ FFEBAD_READ_UNSUPPORTED, FFEBAD_WRITE_UNSUPPORTED,
+ FFEBAD_QUAD_UNSUPPORTED, FFEBAD_BLOCKDATA_STMT,
+ FFEBAD_TRUNCATING_CHARACTER, FFEBAD_TRUNCATING_HOLLERITH,
+ FFEBAD_TRUNCATING_NUMERIC, FFEBAD_TRUNCATING_TYPELESS,
+ FFEBAD_TYPELESS_OVERFLOW): Change these from warnings
+ to errors.
+
+Tue May 19 14:51:59 1998 Craig Burley <burley@gnu.org>
+
+ * Make-lang.in (f77.install-info, f77.uninstall):
+ Use install-info as appropriate.
+
+Tue May 19 12:56:54 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_init_0): Rename xargc to f__xargc,
+ in accord with same-dated change to f/runtime.
+
+Fri May 15 10:52:49 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_convert_narrow_, ffecom_convert_widen_):
+ Be even more persnickety in checking for internal bugs.
+ Also, if precision isn't changing, just return the expr.
+
+ * expr.c (ffeexpr_token_number_): Call
+ ffeexpr_make_float_const_ to make an integer.
+ (ffeexpr_make_float_const_): Handle making an integer.
+
+ * intrin.c (ffeintrin_init_0): Distinguish between
+ crashes on bad arg base and kind types.
+
+Thu May 14 13:30:59 1998 Craig Burley <burley@gnu.org>
+
+ * Make-lang.in (f/expr.c): Now depends on f/stamp-str.
+ * expr.c: Use ffestrOther in place of ffeexprDotdot_.
+ * str-ot.fin: Add more keywords for expr.c.
+
+ * intdoc.c (dumpimp): Trivial fix.
+
+ * com.c (ffecom_expr_): Add ltkt variable for clarity.
+
+Wed May 13 13:05:34 1998 Craig Burley <burley@gnu.org>
+
+ * Make-lang.in (G77STAGESTUFF): Add g77.o, g77spec.o,
+ and g77version.o.
+ (f77.clean): Add removal of g77.c, g77.o, g77spec.o,
+ and g77version.o.
+ (f77.distclean): Delete removal of g77.c.
+
+Thu Apr 30 18:59:43 1998 Jim Wilson <wilson@cygnus.com>
+
+ * Make-lang.in (g77.info, g77.dvi, BUGS, INSTALL, NEWS): Put -o
+ option before input file.
+
+Tue Apr 28 09:23:10 1998 Craig Burley <burley@gnu.org>
+
+ Fix 980427-0.f:
+ * global.c (ffeglobal_ref_progunit_): When transitioning
+ from EXT to FUNC, discard hook, since the decl, if any, is
+ probably wrong.
+
+Sun Apr 26 09:05:50 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_char_enhance_arg_): Wrap the upper bound
+ (the PARM_DECL specifying the length of the CHARACTER*(*)
+ dummy arg) in a variable_size invocation, to prevent
+ dwarf2out.c crashing when compiling code with -g.
+
+Sat Apr 18 05:03:21 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_check_size_overflow_): Ignore overflow
+ as well if dummy argument.
+
+Fri Apr 17 17:18:04 1998 Craig Burley <burley@gnu.org>
+
+ * version.h: Get rid of the overly large headers
+ here too, as done in version.c.
+
+Tue Apr 14 14:40:40 1998 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_start_progunit_): Mark function decl
+ as used, to avoid spurious warning (-Wunused) for ENTRY.
+
+Tue Apr 14 14:19:34 1998 Craig Burley <burley@gnu.org>
+
+ * sta.c (ffesta_second_): Check for CASE DEFAULT
+ as well as CASE, or it won't be recognized.
+
+Mon Mar 23 21:20:35 1998 Craig Burley <burley@gnu.org>
+
+ * version.c: Reduce to a one-line file, like
+ gcc's version.c, since there's really no content
+ there.
+
+Mon Mar 23 11:58:43 1998 Craig Burley <burley@gnu.org>
+
+ * bugs.texi: Various updates.
+
+ * com.c (ffecom_tree_canonize_ptr_): Fix up spacing a bit.
+
+Mon Mar 16 21:20:35 1998 Craig Burley <burley@gnu.org>
+
+ * expr.c (ffeexpr_sym_impdoitem_): Don't blindly
+ reset symbol info after calling ffesymbol_error,
+ to avoid crash.
+
+Mon Mar 16 15:38:50 1998 Craig Burley <burley@gnu.org>
+
+ * Version 0.5.22 released.
+
+Mon Mar 16 14:36:02 1998 Craig Burley <burley@gnu.org>
+
+ Make -g work better for ENTRY:
+ * com.c (ffecom_start_progunit_): Master function
+ for ENTRY-laden procedure is not really invented,
+ so it can be debugged.
+ (ffecom_do_entry_): Push/set/pop lineno for each
+ entry point.
+
+Sun Mar 15 05:48:49 1998 Craig Burley <burley@gnu.org>
+
+ * intrin.def: Fix spelling of mixed-case form
+ of `CPU_Time' (was `Cpu_Time').
+
+Thu Mar 12 13:50:21 1998 Craig Burley <burley@gnu.org>
+
+ * lang-options.h: Sort all -f*-intrinsics-* options,
+ for consistency with other g77 versions.
+
+1998-03-09 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in: Set CONFIG_SITE to a non-existent file since
+ /dev/null loses with bash 2.0/autoconf 2.12. Put
+ F77_FLAGS_TO_PASS before CC.
+
+Sun Mar 8 16:35:34 1998 Craig Burley <burley@gnu.org>
+
+ * intrin.def: Use tabs instead of blanks more
+ consistently (excepting DEFGEN section for now).
+
+Sat Feb 28 15:24:38 1998 Craig Burley <burley@gnu.org>
+
+ * intrin.def: Make CPU_TIME's arg generic real to be just
+ like SECOND_subr.
+
+Fri Feb 20 12:45:53 1998 Craig Burley <burley@gnu.org>
+
+ * expr.c (ffeexpr_token_arguments_): Make sure
+ outer exprstack isn't null.
+
+1998-02-16 Dave Love <d.love@dl.ac.uk>
+
+ * Makefile.in (f/fini): Don't use -W -Wall with HOST_CC.
+
+Fri Feb 13 00:14:56 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * com.c (type_for_mode): Add explicit braces to avoid ambiguous `else'.
+
+ * expr.c (ffeexpr_type_combine): Likewise.
+ (ffeexpr_reduce_): Likewise.
+ (ffeexpr_declare_parenthesized_): Likewise.
+
+ * src.c (ffesrc_strcmp_1ns2i): Likewise.
+ (ffesrc_strcmp_2c): Likewise.
+ (ffesrc_strncmp_2c): Likewise.
+
+ * stb.c (ffestb_halt1_): Likewise.
+ (ffestb_R90910_): Likewise.
+ (ffestb_R9109_): Likewise.
+
+ * stc.c (ffestc_R544_equiv_): Likewise.
+
+ * std.c (ffestd_subr_copy_easy_): Likewise.
+ (ffestd_R1001dump_): Likewise.
+ (ffestd_R1001dump_1005_1_): Likewise.
+ (ffestd_R1001dump_1005_2_): Likewise.
+ (ffestd_R1001dump_1005_3_): Likewise.
+ (ffestd_R1001dump_1005_4_): Likewise.
+ (ffestd_R1001dump_1005_5_): Likewise.
+ (ffestd_R1001dump_1010_2_): Likewise.
+
+ * ste.c (ffeste_R840): Likewise.
+
+ * sts.c (ffests_puttext): Likewise.
+
+ * symbol.c (ffesymbol_check_token_): Likewise.
+
+ * target.c (ffetarget_real1): Likewise.
+ (ffetarget_real2): Likewise.
+
+Sun Jan 25 12:32:15 1998 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
+
+ * Make-lang.in (f77.stage1): Depend on stage1-start so parallel
+ make works better.
+ * (f77.stage2): Likewise for stage2-start.
+ * (f77.stage3): Likewise for stage3-start.
+ * (f77.stage4): Likewise for stage4-start.
+
+Sun Jan 11 02:14:47 1998 Craig Burley <burley@gnu.org>
+
+ Support FORMAT(I<1+2>) (constant variable-FORMAT
+ expressions):
+ * bad.def (FFEBAD_FORMAT_VARIABLE): New diagnostic.
+ * std.c (ffestd_R1001rtexpr_): New function.
+ (ffestd_R1001dump_, ffestd_R1001dump_1005_1_,
+ ffestd_R1001dump_1005_2_, ffestd_R1001dump_1005_3_,
+ ffestd_R1001dump_1005_4_, ffestd_R1001dump_1005_5_,
+ ffestd_R1001dump_1010_2_, ffestd_R1001dump_1010_3_,
+ ffestd_R1001dump_1010_4_, ffestd_R1001dump_1010_5_):
+ Use new function instead of ffestd_R1001error_.
+
+ * stb.c (ffestb_R10014_, ffestb_R10016_, ffestb_R10018_,
+ ffestb_R100110_): Restructure `for' loop for style.
+
+ Fix 970626-2.f by not doing most back-end processing
+ when current_function_decl is an ERROR_MARK, and by
+ making that the case when its type would be an ERROR_MARK:
+ * com.c (ffecom_start_progunit_, finish_function,
+ lang_printable_name, start_function,
+ ffecom_finish_symbol_transform_): Test for ERROR_MARK.
+ * std.c (ffestd_stmt_pass_): Don't do any downstream
+ processing if ERROR_MARK.
+
+ * Make-lang.in (f77.install-common): Don't install, and
+ don't uninstall existing, Info files if f/g77.info
+ doesn't exit. (This is a somewhat modified version
+ of an egcs patch on 1998-01-07 12:05:51 by Bruno Haible
+ <bruno@linuix.mathematik.uni-karlsruhe.de>.)
+
+Fri Jan 9 19:09:07 1998 Craig Burley <burley@gnu.org>
+
+ Fix -fpedantic combined with `F()' invocation,
+ also -fugly-comma combined with `IARGC()' invocation:
+ * bad.def (FFEBAD_NULL_ARGUMENT_W): New diagnostic.
+ * expr.c (ffeexpr_finished_): Don't reject null expressions
+ in the argument-expression context -- let outer context
+ handle that.
+ (ffeexpr_token_arguments_): Warn about null expressions
+ here if -fpedantic (as appropriate).
+ Obey -fugly-comma for only external-procedure invocations.
+ * intrin.c (ffeintrin_check_): No longer ignore explicit
+ omitted trailing args.
+
+Tue Dec 23 14:58:04 1997 Craig Burley <burley@gnu.org>
+
+ * intrin.c (ffeintrin_fulfill_generic): Don't generate
+ FFEBAD_INTRINSIC_TYPE for CHARACTER*(*) intrinsic.
+
+ * com.c (ffecom_gfrt_basictype):
+ (ffecom_gfrt_kindtype):
+ (ffecom_make_gfrt_):
+ (FFECOM_rttypeVOIDSTAR_): New return type `void *', for
+ the SIGNAL intrinsic.
+ * com-rt.def (FFECOM_rttypeSIGNAL): Now returns `void *'.
+ * intdoc.c: Replace `p' kind specifier with `7'.
+ * intrin.c (ffeintrin_check_, ffeintrin_init_0): Replace
+ `p' kind specifier with `7'.
+ * intrin.def (FFEINTRIN_impLOC, FFEINTRIN_impSIGNAL_func,
+ FFEINTRIN_impSIGNAL_subr): Replace `p' specifier with `7'.
+ Also, SIGNAL now returns a `void *' status, not `int'.
+
+ Improve run-time diagnostic for "PRINT '(I1', 42":
+ * com.c (ffecom_char_args_x_): Renamed from ffecom_char_args_,
+ which is now a macro (to avoid lots of changes to other code)
+ with new arg, ffecom_char_args_with_null_ being another new
+ macro to call same function with different value for new arg.
+ This function now appends a null byte to opCONTER expression
+ if the new arg is TRUE.
+ (ffecom_arg_ptr_to_expr): Support NULL length pointer.
+ * ste.c (ffeste_io_cilist_):
+ (ffeste_io_icilist_): Pass NULL length ptr for
+ FORMAT expression, so null byte gets appended where
+ feasible.
+ * target.c (ffetarget_character1):
+ (ffetarget_concatenate_character1):
+ (ffetarget_substr_character1):
+ (ffetarget_convert_character1_character1):
+ (ffetarget_convert_character1_hollerith):
+ (ffetarget_convert_character1_integer4):
+ (ffetarget_convert_character1_logical4):
+ (ffetarget_convert_character1_typeless):
+ (ffetarget_hollerith): Append extra phantom null byte as
+ part of FFETARGET-NULL-BYTE kludge.
+
+ * intrin.def (FFEINTRIN_impCPU_TIME): Point to
+ FFECOM_gfrtSECOND as primary run-time routine.
+
+Mon Dec 22 12:41:07 1997 Craig Burley <burley@gnu.org>
+
+ * intrin.c (ffeintrin_init_0): Remove duplicate
+ check for `!'.
+
+Sun Dec 14 02:49:58 1997 Craig Burley <burley@gnu.org>
+
+ * intrin.c (ffeintrin_init_0): Fix up indentation a bit.
+ Fix bug that prevented checking of arguments other
+ than the first.
+
+ * intdoc.c: Fix up indentation a bit.
+
+Tue Dec 9 16:20:57 1997 Richard Henderson <rth@cygnus.com>
+
+ * com.c (ffecom_type_vardesc_): Vardesc.dims is a `ftnlen*'.
+
+Mon Dec 1 19:12:36 1997 Craig Burley <burley@gnu.org>
+
+ * intrin.c (ffeintrin_check_): Fix up indentation a bit more.
+
+Mon Dec 1 16:21:08 1997 Craig Burley <burley@gnu.org>
+
+ * com.c (ffecom_arglist_expr_): Crash if non-supplied
+ optional arg isn't passed as an address.
+ Pass null pointer explicitly, instead of via ffecom routine.
+ If incoming argstring is NULL, substitute pointer to "0".
+ Recognize '0' as ending the usual arg stuff, just like '\0'.
+
+Sun Nov 30 22:22:22 1997 Craig Burley <burley@gnu.org>
+
+ * intdoc.c: Minor fix-ups.
+
+ * intrin.c (ffeintrin_check_): Fix up indentation a bit.
+
+ * intrin.def: Fix up spacing a bit.
+
+1997-11-17 Dave Love <d.love@dl.ac.uk>
+
+ * com.c (ffecom_arglist_expr_): Pass null pointers for optional
+ args which aren't supplied.
+
+Sun Nov 16 21:45:43 1997 H.J. Lu (hjl@gnu.ai.mit.edu)
+
+ * Make-lang.in (f77.install-info): Depend on f77.info.
+
+1997-11-06 Dave Love <d.love@dl.ac.uk>
+
+ * intrin.def: Allow non-integer args for INT2 and INT8 (per
+ documentation).
+
+Tue Oct 28 02:21:25 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * lang-options.h: Add -fgnu-intrinsics-* and
+ -fbadu77-intrinsics-* options.
+
+Sun Oct 26 02:36:21 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (lang_print_error_function): Fix to more
+ reliably notice when the diagnosed region changes.
+
+Sat Oct 25 23:43:36 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix 950327-0.f:
+ * sta.c, sta.h (ffesta_outpooldisp): New function.
+ * std.c (ffestd_stmt_pass_): Don't kill NULL pool.
+ (ffestd_R842): If pool already preserved, save NULL
+ for pool, because it should be killed only once.
+
+ * malloc.c [MALLOC_DEBUG]: Put initializer for `name'
+ component in braces, to avoid compiler warning.
+
+Fri Oct 10 13:00:48 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * ste.c (ffeste_begin_iterdo_): Fix loop setup so iteration
+ variable is modified only after the #iterations is calculated;
+ otherwise if the iteration variable is aliased to any of the
+ operands in the start, end, or increment expressions, the
+ wrong #iterations might be calculated.
+
+ * com.c (ffecom_save_tree): Fix indentation.
+
+1997-10-05 Dave Love <d.love@dl.ac.uk>
+
+ * intrin.def: Make SECOND_subr's arg generic real for people
+ porting from Cray and making everything double precision.
+
+Mon Sep 29 16:18:21 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * stu.c (ffestu_list_exec_transition_,
+ ffestu_dummies_transition_): Specify `bool' type for
+ `in_progress' variables.
+
+ * com.h (assemble_string): Declare this routine (instead
+ of #include'ing "output.h" from gcc) to eliminate warnings
+ from lex.c.
+
+Fri Sep 19 01:12:27 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * expr.c (ffeexpr_reduced_eqop2_):
+ (ffeexpr_reduced_relop2_): Minor fixes to diagnostic code.
+
+ * fini.c (main): Change return type to `int'.
+
+Wed Sep 17 10:47:08 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com-rt.def (FFECOM_gfrtDSIGN, FFECOM_gfrtISIGN,
+ FFECOM_gfrtSIGN): Add second argument.
+
+ * expr.c (ffeexpr_cb_comma_c_): Trivial fixes.
+
+Tue Sep 9 01:59:35 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Version 0.5.21 released.
+
+Tue Sep 9 00:31:01 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * intdoc.c (dumpem): Put appropriate commentary in
+ output file, so readers know it isn't source.
+
+Wed Aug 27 08:08:25 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * proj.h: Always #include "config.j" first, to pick up
+ gcc's configuration.
+ * com.c: Change bcopy() and bzero() calls to memcpy()
+ and memset() calls, to make more of g77 ANSI C.
+
+1997-08-26 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in ($(srcdir)/f/runtime/configure,
+ $(srcdir)/f/runtime/libU77/configure): Fix for when srcdir isn't
+ relative.
+
+Tue Aug 26 05:59:21 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * ansify.c (main): Make sure readers of stdout know
+ it's derived from stdin; omit comment text; get source
+ line numbers in future stderr output to be correct.
+
+Tue Aug 26 01:36:01 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix 970825-0.f:
+ * stb.c (ffestb_R5284_): Allow OPEN_PAREN after closing
+ SLASH as well as NAME.
+
+Mon Aug 25 23:48:17 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Changes to allow g77 docs to be built entirely from scratch
+ using any ANSI C compiler, not requiring GNU C:
+ * Make-lang.in ($(srcdir)/f/intdoc.texi): "Pipe" new
+ location of intrinsic documentation data base, f/intdoc.in,
+ through new `ansify' program to append `\n\' to quoted
+ newlines, into f/intdoc.h0. Do appropriate cleanups. Explain.
+ (f77.mostlyclean): Add f/ansify and f/intdoc.h0 to cleanups.
+ * f/ansify.c: New program.
+ * f/intdoc.c: Fix so it conforms to ANSI C.
+ #include f/intdoc.h0 instead of f/intdoc.h.
+ Avoid some warnings.
+ * f/intdoc.h, f/intdoc.in: Rename the former to the latter; no
+ changes made to the content in this patch!
+ * f/intrin.h (ffeintrinFamily): Fix to conform to ANSI C.
+
+Sun Aug 24 06:52:48 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix up g77 compiler data base for libf2c routines:
+ * com-rt.def (FFECOM_gfrtSIGNAL): Change return type to
+ FTNINT to match actual code.
+
+ * com.c (ffecomRttype_): Replace FFECOM_rttypeINT_ with
+ FFECOM_rttypeFTNINT_.
+ Add and fix up comments.
+ (ffecom_make_gfrt_, ffecom_gfrt_basictype,
+ ffecom_gfrt_kindtype): Replace FFECOM_rttypeINT_ with
+ FFECOM_rttypeFTNINT_; add FFECOM_rttypeDOUBLEREAL_.
+
+Wed Aug 20 17:18:40 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * global.c (ffeglobal_ref_progunit_): It's okay to have
+ a different CHARACTER*n length for a reference if the
+ existing length is for another reference, not a definition.
+
+Mon Aug 18 14:27:18 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix 970814-0.f:
+ * global.c (ffeglobal_new_progunit_): Distinguish
+ between previously defined, versus inferred, filewide
+ when it comes to diagnostics.
+
+ Fix 970816-1.f:
+ * global.c (ffeglobal_ref_progunit_): Change BDATA into EXT
+ right at the beginning, so EXTERNAL FOO followed later
+ by SUBROUTINE FOO is not diagnosed.
+
+ Fix 970813-0.f:
+ * com-rt.def (FFECOM_gfrtALARM): Returns `integer', not
+ `void'.
+
+Sun Aug 17 03:32:44 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix up problems when virtual memory exhausted:
+ * malloc.c (malloc_new_): Use gcc's xmalloc(), so we
+ print a nicer message when malloc returns no memory.
+ (malloc_resize_): Ditto for xrealloc().
+
+ * Make-lang.in, Makefile.in: Comment out lines containing
+ just formfeeds.
+
+Sat Aug 16 19:41:33 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_make_gfrt_): For rttypeREAL_F2C_, return
+ double_type_node; for rttypeREAL_GNU_, return
+ _real_type_node.
+
+1997-08-13 Dave Love <d.love@dl.ac.uk>
+
+ * config-lang.in (diff_excludes): Add some hints about known
+ problematic platforms.
+
+1997-08-13 Dave Love <d.love@dl.ac.uk>
+
+ * intdoc.h: Document `alarm'.
+
+Mon Aug 11 21:19:22 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Make-lang.in ($(RUNTIMESTAGESTUFF)): Add
+ f/runtime/stamp-lib.
+
+Mon Aug 11 01:52:03 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_build_complex_constant_): Go with the
+ new build_complex() approach used in gcc-2.8.
+
+ * com.c (ffecom_sym_transform_): Don't set
+ DECL_IN_SYSTEM_HEADER for a tree node that isn't
+ a VAR_DECL, which happens when var is in common!
+
+ * com.c (ffecom_expr_intrinsic_) (case FFEINTRIN_impALARM):
+ No need to test codegen_imp -- there's only one valid here.
+
+ * intrin.def (FFEINTRIN_impALARM): Specify `Status' argument
+ as write-only.
+
+Fri Aug 8 05:40:23 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Substantial changes to accommodate distinctions among
+ run-time routines that support intrinsics, and between
+ routines that compute and return the same type vs. those
+ that compute one type and return another (or `void'):
+ * com-rt.def: Specify new return type REAL_F2C_ instead
+ of many DOUBLE_, COMPLEX_F2C_ instead of COMPLEX_, and
+ so on.
+ Clear up the *BES* routines "once and for all".
+ * com.c: New return types.
+ (ffecom_convert_narrow_, ffecom_convert_widen_):
+ New functions that are "safe" variants of convert(),
+ to catch errors that ffecom_expr_intrinsic_() now
+ no longer catches.
+ (ffecom_arglist_expr_): Ensure arguments are not
+ converted to narrower types.
+ (ffecom_call_): Ensure return value is not converted
+ to a wider type.
+ (ffecom_char_args_): Use new ffeintrin_gfrt_direct()
+ routine.
+ (ffecom_expr_intrinsic_): Simplify how run-time
+ routine is selected (via `gfrt' only now; lose the
+ redundant `ix' variable).
+ Eliminate the `library' label; any code that doesn't
+ return directly just `break's out now with `gfrt'
+ set appropriately.
+ Set `gfrt' to default choice initially, either a
+ fast direct form or, if not available, a slower
+ indirect-callable form.
+ (ffecom_make_gfrt_): No longer need to do special
+ check for complex; it's built into the new return-type
+ regime.
+ (ffecom_ptr_to_expr): Use new ffeintrin_gfrt_indirect()
+ routine.
+ * intrin.c, intrin.h: `gfrt' field replaced with three fields,
+ so it is easier to provide faster direct-callable and
+ GNU-convention indirect-callable routines in the future.
+ DEFIMP macro adjusted accordingly, along with all its uses.
+ (ffeintrin_gfrt_direct): New function.
+ (ffeintrin_gfrt_indirect): Ditto.
+ (ffeintrin_is_actualarg): If `-fno-f2c' is in effect,
+ require a GNU-callable version of intrinsic instead of
+ an f2c-callable version, so indirect calling is still checked.
+ * intrin.def: Replace one GFRT field with the three new fields,
+ as appropriate for each DEFIMP intrinsic.
+
+ * com.c (ffecom_stabilize_aggregate_,
+ ffecom_convert_to_complex_): Make these `static'.
+
+Thu Aug 7 11:24:34 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Provide means for front end to determine actual
+ "standard" return type for an intrinsic if it is
+ passed as an actual argument:
+ * com.h, com.c (ffecom_gfrt_basictype,
+ ffecom_gfrt_kindtype): New functions.
+ (ffecom_gfrt_kind_type_): Replaced with new function.
+ All callers updated.
+ (ffecom_make_gfrt_): No longer need do anything
+ with kind type.
+
+ * intrin.c (ffeintrin_basictype, ffeintrin_kindtype):
+ Now returns correct type info for specific intrinsic
+ (based on type of run-time-library implementation).
+
+Wed Aug 6 23:08:46 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * global.c (ffeglobal_ref_progunit_): Don't reset
+ number of arguments just due to new type info,
+ so useful warnings can be issued.
+
+1997-08-06 Dave Love <d.love@dl.ac.uk>
+
+ * intrin.def: Fix IDATE_vxt argument order.
+ * intdoc.h: Likewise.
+
+Thu Jul 31 22:22:03 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * global.c (ffeglobal_proc_ref_arg): If REF/DESCR
+ disagreement, DESCR is CHARACTER, and types disagree,
+ pretend the argsummary agrees so the message ends up
+ being about type disagreement.
+ (ffeglobal_proc_def_arg): Ditto.
+
+ * expr.c (ffeexpr_token_first_rhs_3_): Set info for LABTOK
+ to NONE of everything, to avoid misdiagnosing filewide
+ usage of alternate returns.
+
+Sun Jul 20 23:07:47 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_sym_transform_): If type gets set
+ to error_mark_node, just return that for transformed symbol.
+ (ffecom_member_phase2_): If type gets set to error_mark_node,
+ just return.
+ (ffecom_check_size_overflow_): Add `dummy' argument to
+ flag that type is for a dummy, update all callers.
+
+Sun Jul 13 17:40:53 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix 970712-1.f:
+ * where.c (ffewhere_set_from_track): If start point
+ is too large, just use initial start point. 0.6 should
+ fix all this properly.
+
+ Fix 970712-2.f:
+ * com.c (ffecom_sym_transform_): Preserve error_mark_node for type.
+ (ffecom_type_localvar_): Ditto.
+ (ffecom_sym_transform_): If type is error_mark_node,
+ don't error-check decl size, because back end responds by
+ setting that to an integer 0 instead of error_mark_node.
+ (ffecom_transform_common_): Same as earlier fix to _transform_
+ in that size is checked by dividing BITS_PER_UNIT instead of
+ multiplying.
+ (ffecom_transform_equiv_): Ditto.
+
+ Fix 970712-3.f:
+ * stb.c (ffestb_R10014_): Fix flaky fall-through in error
+ test for FFELEX_typeCONCAT by just replicating the code,
+ and do FFELEX_typeCOLONCOLON while at it.
+
+1997-07-07 Dave Love <d.love@dl.ac.uk>
+
+ * intdoc.h: Add various missing pieces; correct GMTIME, LTIME
+ result ordering.
+
+ * intrin.def, com-rt.def: Add alarm.
+
+ * com.c (ffecom_expr_intrinsic_): Add case for alarm.
+
+Thu Jun 26 04:19:40 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix 970302-3.f:
+ * com.c (ffecom_sym_transform_): For sanity-check compare
+ of gbe size of local variable to g77 expectation,
+ use varasm.c/assemble_variable technique of dividing
+ BITS_PER_UNIT out of gbe info instead of multiplying
+ g77 info up, to avoid crash when size in bytes is very
+ large, and overflows an `int' or similar when multiplied.
+
+ Fix 970626-2.f:
+ * com.c (ffecom_finish_symbol_transform_): Don't bother
+ transforming a dummy argument, to avoid a crash.
+ * ste.c (ffeste_R1227): Don't return a value if the
+ result decl, or its type, is error_mark_node.
+
+ Fix 970626-4.f:
+ * lex.c (ffelex_splice_tokens): `-fdollar-ok' is
+ irrelevant to whether a DOLLAR token should be made
+ from an initial character of `$'.
+
+ Fix 970626-6.f:
+ * stb.c (ffestb_do3_): DO iteration variable is an
+ lhs, not rhs, expression.
+
+ Fix 970626-7.f and 970626-8.f:
+ * expr.c (ffeexpr_cb_comma_i_1_): Set IMPDO expression
+ to have clean info, because undefined rank, for example,
+ caused crash on mangled source on UltraSPARC but not
+ on Alpha for a series of weird reasons.
+ (ffeexpr_cb_close_paren_): If not CLOSE_PAREN, push
+ opANY expression onto stack instead of attempting
+ to mimic what program might have wanted.
+ (ffeexpr_cb_close_paren_): Don't wrap opPAREN around
+ opIMPDO, just warn that it's gratuitous.
+ * bad.def (FFEBAD_IMPDO_PAREN): New warning.
+
+ Fix 970626-9.f:
+ * expr.c (ffeexpr_declare_parenthesized_): Must shut down
+ parsing in kindANY case, otherwise the parsing engine might
+ decide there's an ambiguity.
+ (ffeexpr_token_name_rhs_): Eliminate parentypeSUBROUTINE_
+ case, so we crash right away if it comes through.
+ * st.c, st.h, sta.c, sta.h (ffest_shutdown, ffesta_shutdown):
+ New functions.
+
+Tue Jun 24 19:47:29 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_check_size_overflow_): New function
+ catches some cases of the size of a type getting
+ too large. varasm.c must catch the rest.
+ (ffecom_sym_transform_): Use new function.
+ (ffecom_type_localvar_): Ditto.
+
+Mon Jun 23 01:09:28 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * global.c (ffeglobal_proc_def_arg): Fix comparison
+ of argno to #args.
+ (ffeglobal_proc_ref_arg): Ditto.
+
+ * lang-options.h, top.c: Rename `-fdebug' to `-fxyzzy',
+ since it's an unsupported internals option and some
+ poor user might guess that it does something.
+
+ * bad.def: Make a warning for each filewide diagnostic.
+ Put all filewides together.
+ * com.c (ffecom_sym_transform_): Don't substitute
+ known global tree for global entities when `-fno-globals'.
+ * global.c (ffeglobal_new_progunit_): Don't produce
+ fatal diagnostics about globals when `-fno-globals'.
+ Instead, produce equivalent warning when `-Wglobals'.
+ (ffeglobal_proc_ref_arg): Ditto.
+ (ffeglobal_proc_ref_nargs): Ditto.
+ (ffeglobal_ref_progunit_): Ditto.
+ * lang-options.h, top.c, top.h: New `-fno-globals' option.
+
+Sat Jun 21 12:32:54 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * expr.c (ffeexpr_fulfill_call_): Set array variable
+ to avoid warning about uninitialized variable.
+
+ * Make-lang.in: Get rid of any setting of HOST_* macros,
+ since these will break gcc's build!
+ * makefile: New file to make building derived files
+ easier.
+
+Thu Jun 19 18:19:28 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * g77.c (main): Install Emilio Lopes' patch to support
+ Ratfor, and to fix the printing of the version string
+ to go to stderr, not stdout.
+ * lang-specs.h: Install Emilio Lopes' patch to support
+ Ratfor, and patch the result to support picking up
+ `*f771' from the `specs' file.
+
+Thu Jun 12 14:36:25 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * storag.c (ffestorag_update_init, ffestorag_update_save):
+ Also update parent, in case equivalence processing
+ has already eliminated pointers to it via the
+ local equivalence info.
+
+Tue Jun 10 14:08:26 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * intdoc.c: Add cross-reference to end of description
+ of any generic intrinsic pointing to other intrinsics
+ with the same name.
+
+ Warn about explicit type declaration for intrinsic
+ that disagrees with invocation:
+ * expr.c (ffeexpr_paren_rhs_let_): Preserve type info
+ for intrinsic functions.
+ (ffeexpr_token_funsubstr_): Ditto.
+ * intrin.c (ffeintrin_fulfill_generic): Warn if type
+ info of fulfilled intrinsic invocation disagrees with
+ explicit type info given symbol.
+ (ffeintrin_fulfill_specific): Ditto.
+ * stc.c (ffestc_R1208_item): Preserve type info
+ for intrinsics.
+ (ffestc_R501_item): Ditto.
+
+Mon Jun 9 17:45:44 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_expr_intrinsic_): Fix several of the
+ libU77/libF77-unix handlers to properly convert their
+ arguments.
+
+ * com-rt.def (FFECOM_gfrtFSTAT): Append missing "i" to
+ arg string.
+
+Fri Jun 6 14:37:30 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_expr_intrinsic_): Have a case statement
+ for every intrinsic implementation, so missing ones
+ are caught via gcc warnings.
+ Don't call ffeintrin_codegen_imp anymore.
+ * intrin.c (ffeintrin_fulfill_generic): Remove cg_imp
+ stuff from here.
+ (ffeintrin_codegen_imp): Delete this function.
+ * intrin.def, intrin.h: Remove DEFIMQ stuff from here
+ as well.
+
+Thu Jun 5 13:03:07 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * top.c (ffe_decode_option): New -fbadu77-intrinsics-*
+ options.
+ * top.h: Ditto.
+ * intrin.h: New BADU77 family.
+ * intrin.c (ffeintrin_state_family): Ditto.
+
+ Implement new scheme to track intrinsic names vs. forms:
+ * intrin.c (ffeintrin_fulfill_generic),
+ (ffeintrin_fulfill_specific), (ffeintrin_is_intrinsic),
+ intrin.def: The documented name is now either in the
+ generic info or, if no generic, in the specific info.
+ For a generic, the specific info contains merely the
+ distinguishing form (usually "function" or "subroutine"),
+ used for diagnostics about ambiguous references and
+ in the documentation.
+
+ * intrin.def: Clean up formatting of DEFNAME block.
+ Convert many libU77 intrinsics into generics that
+ support both subroutine and function forms.
+ Put the function forms of side-effect routines into
+ the new BADU77 family.
+ Make MCLOCK and TIME return INTEGER*4 again, and add
+ INTEGER*8 equivalents called MCLOCK8 and TIME8.
+ Fix up more status return values to be written and
+ insist on them being I1 as well.
+ * com.c (ffecom_expr_intrinsic_): Lots of changes to
+ support new libU77 intrinsic interfaces.
+
+Mon Jun 2 00:37:53 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_init_0): Pointer type is now INTEGER(KIND=7),
+ not INTEGER(KIND=0), since we want to reserve KIND=0 for
+ future use.
+
+Thu May 29 14:30:33 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix bugs preventing CTIME(I*4) from working correctly:
+ * com.c (ffecom_char_args_): For FUNCREF case, process
+ args to intrinsic just as they would be in
+ ffecom_expr_intrinsic_.
+ * com-rt.def (FFECOM_gfrtCTIME, FFECOM_gfrtTTYNAM): Fix
+ argument decls to specify `&'.
+
+Wed May 28 22:19:49 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix gratuitous warnings exposed by dophot aka 970528-1:
+ * global.c (ffeglobal_proc_def_arg, ffeglobal_proc_ref_arg):
+ Support distinct function/subroutine arguments instead of
+ just procedures.
+ * global.h: Ditto.
+ * expr.c (ffeexpr_fulfill_call_): A SYMTER with kindNONE
+ also is a procedure (either function or subroutine).
+
+Mon May 26 20:25:31 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * bad.def: Have several lexer diagnostics refer to
+ documentation for people who need more info on what Fortran
+ source code is supposed to look like.
+
+ * expr.c (ffeexpr_reduced_bool1_), bad.def: New diagnostics
+ specific to .NOT. now mention only one operand instead
+ of two.
+
+ * g77.c: Recognize -fsyntax-only, similar to -c etc.
+ (lookup_option): Fix bug that prevented non-`--' options
+ from being recognized.
+
+Sun May 25 04:29:04 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * intrin.def (FFEINTRIN_impCTIME): Accept `I*' expression
+ for STime instead of requiring `I2'.
+
+Tue May 20 16:14:40 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * symbol.c (ffesymbol_reference): All references to
+ standard intrinsics are considered explicit, so as
+ to avoid generating basically useless warnings.
+ * intrin.c, intrin.h (ffeintrin_is_standard): Returns TRUE
+ if intrinsic is standard.
+
+Sun May 18 21:14:59 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com-rt.def: Changed all external names of the
+ form `"\([a-z0-9]*\)_' to `"G77_\1_0"' so as to
+ allow any name valid as an intrinsic to be used
+ as such and as a user-defined external procedure
+ name or common block as well.
+
+Thu May 8 13:07:10 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * expr.c (ffeexpr_cb_end_notloc_): For %VAL, %REF, and
+ %DESCR, copy arg info into new node.
+
+Mon May 5 14:42:17 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ From Uwe F. Mayer <mayer@math.Vanderbilt.Edu>:
+ * Make-lang.in (g77-cross): Fix typo in g77.c path.
+
+ From Brian McIlwrath <bkm@star.rl.ac.uk>:
+ * lang-specs.h: Have g77 pick up options from a section
+ labeled `*f771' of the `specs' file.
+
+Sat May 3 02:46:08 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * intrin.def (FFEINTRIN_defSIGNAL): Add optional `Status'
+ argument that com.c already expects (per Dave Love).
+
+ More changes to support better tracking of (filewide)
+ globals, in particular, the arguments to procedures:
+ * bad.def (FFEBAD_FILEWIDE_NARGS, FFEBAD_FILEWIDE_NARGS_W,
+ FFEBAD_FILEWIDE_ARG, FFEBAD_FILEWIDE_ARG_W): New diagnostics.
+ * expr.c (ffebad_fulfill_call_): Provide info on each
+ argument to ffeglobal.
+ * global.c, global.h (ffeglobal_proc_def_arg,
+ ffeglobal_proc_def_nargs, ffeglobal_proc_ref_arg,
+ ffeglobal_proc_ref_args): New functions.
+ (ffeglobalArgSummary, ffeglobalArgInfo_): New types.
+
+Tue Apr 29 18:35:41 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ More changes to support better tracking of (filewide)
+ globals:
+ * expr.c (ffeexpr_fulfill_call_): New function.
+ (ffeexpr_token_name_lhs_): Call after building procedure
+ reference expression. Also leave info field for ANY-ized
+ expression alone.
+ (ffeexpr_token_arguments_): Ditto.
+
+Mon Apr 28 20:04:18 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Changes to support better tracking of (filewide)
+ globals, mainly to avoid crashes due to inlining:
+ * bad.def: Go back to quoting intrinsic names,
+ (FFEBAD_FILEWIDE_DISAGREEMENT, FFEBAD_FILEWIDE_TIFF,
+ FFEBAD_FILEWIDE_TYPE_MISMATCH): New diagnostics.
+ (FFEBAD_INTRINSIC_EXPIMP, FFEBAD_INTRINSIC_GLOBAL): Reword
+ for clarity.
+ * com.c (ffecom_do_entry_, ffecom_start_progunit_,
+ ffecom_sym_transform_): Accommodate new FFEGLOBAL_typeEXT
+ possibility.
+ * expr.c (ffeexpr_sym_lhs_call_, ffeexpr_sym_lhs_extfunc_,
+ ffeexpr_sym_rhs_actualarg_, ffeexpr_declare_parenthesized_,
+ ffeexpr_paren_rhs_let_, ffeexpr_token_funsubstr_):
+ Fill in real kind info instead of leaving NONE where
+ appropriate.
+ Register references to intrinsics and globals with ffesymbol
+ using new ffesymbol_reference function instead of
+ ffesymbol_globalize.
+ * global.c (ffeglobal_type_string_): New array for
+ new diagnostics.
+ * global.h, global.c:
+ Replace ->init mechanism with ->tick mechanism.
+ Move other common-related members into a substructure of
+ a union, so the proc substructure can be introduced
+ to include members related to externals other than commons.
+ Don't complain about ANY-ized globals; ANY-ize globals
+ once they're complained about, in any case where code
+ generation could become a problem.
+ Handle global entries that have NONE type (seen as
+ intrinsics), EXT type (seen as EXTERNAL), and so on.
+ Keep track of kind and type of externals, both via
+ definition and via reference.
+ Diagnose disagreements about kind or type of externals
+ (such as functions).
+ (ffeglobal_ref_intrinsic, ffeglobal_ref_progunit_): New
+ functions.
+ * stc.c (ffestc_R1207_item, ffestc_R1208_item,
+ ffestc_R1219, ffestc_R1226):
+ Call ffesymbol_reference, not ffesymbol_globalize.
+ * stu.c (ffestu_sym_end_transition,
+ ffestu_sym_exec_transition):
+ Call ffesymbol_reference, not ffesymbol_globalize.
+ * symbol.c (ffesymbol_globalize): Removed...
+ (ffesymbol_reference): ...to this new function,
+ which more generally registers references to symbols,
+ globalizes globals, and calls on the ffeglobal module
+ to check globals filewide.
+
+ * global.h, global.c: Rename some macros and functions
+ to more clearly distinguish common from other globals.
+ All callers changed.
+
+ * com.c (ffecom_sym_transform_): Trees describing
+ filewide globals must be allocated on permanent obstack.
+
+ * expr.c (ffeexpr_token_name_lhs_): Don't generate
+ gratuitous diagnostics for FFEINFO_whereANY case.
+
+Thu Apr 17 03:27:18 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * global.c: Add support for flagging intrinsic/global
+ confusion via warnings.
+ * bad.def (FFEBAD_INTRINSIC_EXPIMP,
+ FFEBAD_INTRINSIC_GLOBAL): New diagnostics.
+ * expr.c (ffeexpr_token_funsubstr_): Ditto.
+ (ffeexpr_sym_lhs_call_): Ditto.
+ (ffeexpr_paren_rhs_let_): Ditto.
+ * stc.c (ffestc_R1208_item): Ditto.
+
+Wed Apr 16 22:40:56 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * expr.c (ffeexpr_declare_parenthesized_): INCLUDE
+ context can't be an intrinsic invocation either.
+
+Fri Mar 28 10:43:28 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * expr.c (ffeexpr_token_arguments_): Make sure top of
+ exprstack is operand before dereferencing operand field.
+
+ * lex.c (ffelex_prepare_eos_): Fill up truncated
+ hollerith token, so crash on null ->text field doesn't
+ happen later.
+
+ * stb.c (ffestb_R10014_): If NAMES isn't recognized (or
+ the recognized part is followed in the token by a
+ non-digit), don't try and collect digits, as there
+ might be more than FFEWHERE_indexMAX letters to skip
+ past to do so -- and the code is diagnosed anyway.
+
+Thu Mar 27 00:02:48 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_sym_transform_): Force local
+ adjustable array onto stack.
+
+ * stc.c (ffestc_R547_item_object): Don't actually put
+ the symbol in COMMON if the symbol has already been
+ EQUIVALENCE'd to a different COMMON area.
+
+ * equiv.c (ffeequiv_add): Don't actually do anything
+ if there's a disagreement over which COMMON area is
+ involved.
+
+Tue Mar 25 03:35:19 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_transform_common_): If no explicit init
+ of COMMON area, don't actually init it even though
+ storage area suggests it.
+
+Mon Mar 24 12:10:08 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * lex.c (ffelex_image_char_): Avoid overflowing the
+ column counter itself, as well as the card image.
+
+ * where.c (ffewhere_line_new): Cast ffelex_line_length()
+ to (size_t) so 255 doesn't overflow to 0!
+
+ * stc.c (ffestc_labeldef_notloop_begin_): Don't gratuitously
+ terminate loop before processing statement, so block
+ doesn't disappear out from under EXIT/CYCLE processing.
+ (ffestc_labeldef_notloop_): Has old code from above
+ function, instead of just calling it.
+
+ * expr.c (ffeexpr_cb_comma_i_4_): Don't skip over
+ arbitrary token (such as EOS).
+
+ * com.c (ffecom_init_zero_): Handle RECORD_TYPE and
+ UNION_TYPE so -fno-zeros works with -femulated-complex.
+
+1997-03-12 Dave Love <d.love@dl.ac.uk>
+
+ * intrin.def: New intrinsics INT2, INT8, CPU_TIME. Fix AND, OR,
+ XOR. [Integrated by burley, AND/OR/XOR already fixed, INT8
+ implementation changed/fixed.]
+
+Wed Mar 12 10:40:08 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Make-lang.in ($(srcdir)/f/intdoc.texi): Simplify rules
+ so building f/intdoc is not always necessary; remove
+ f/intdoc after running it if it is built.
+
+Tue Mar 11 23:42:00 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * intrin.def (FFEINTRIN_impAND, FFEINTRIN_impOR,
+ FFEINTRIN_impXOR): Use the IAND, IOR, and IEOR implementations
+ of these, instead of crashing in ffecom_expr_intrinsic_
+ or adding case labels there.
+
+Mon Mar 10 22:51:23 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * intdoc.c: Fix so any C compiler can compile this.
+
+Fri Feb 28 13:16:50 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Version 0.5.20 released.
+
+Fri Feb 28 01:45:25 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Make-lang.in (RUNTIMESTAGESTUFF, LIBU77STAGESTUFF):
+ Move some files incorrectly in the former to the latter,
+ and add another file or two to the latter.
+
+ New meanings for (KIND=n), and new denotations in the
+ little language describing intrinsics:
+ * com.c (ffecom_init_0): Assign new meanings.
+ * intdoc.c: Document new meanings.
+ Support the new denotations.
+ * intrin.c: Employ new meanings, mapping them to internal
+ values (which are the same as they ever were for now).
+ Support the new denotations.
+ * intrin.def: Switch DEFIMP table to the new denotations.
+
+ * intrin.c (ffeintrin_check_): Fix bug that was leaving
+ LOC() and %LOC() returning INTEGER*4 on systems where
+ it should return INTEGER*8.
+
+ * type.c: Canonicalize function definitions, for etags
+ and such.
+
+Wed Feb 26 20:43:03 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_init_0): Choose INTEGER(KIND=n) types,
+ where n is 2, 3, and 4, according to the new docs
+ instead of according to the old C correspondences
+ (which seem less useful at this point).
+
+ * equiv.c (ffeequiv_destroy_): New function.
+ (ffeequiv_layout_local_): Use this new function
+ whenever the laying out of a local equivalence chain
+ is aborted for any reason.
+ Otherwise ensure that symbols no longer reference
+ the stale ffeequiv entries that result when they
+ are killed off in this procedure.
+ Also, the rooted symbol is one that has storage,
+ it really is irrelevant whether it has an equiv entry
+ at this point (though the code to remove the equiv
+ entry was put in at the end, just in case).
+ (ffeequiv_kill): When doing internal checks, make
+ sure the victim isn't named by any symbols it points
+ to. Not as complete a check as looking through the
+ entire symbol table (which does matter, since some
+ code in equiv.c used to remove symbols from the lists
+ for an ffeequiv victim but not remove that victim as the
+ symbol's equiv info), but this check did find some
+ real bugs in the code (that were fixed).
+
+Mon Feb 24 16:42:13 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_expr_intrinsic_): Fix a couple of
+ warnings about uninitialized variables.
+ * intrin.c (ffeintrin_check_): Ditto, but there were
+ a couple of _real_ uninitialized-variable _bugs_ here!
+ (ffeintrin_fulfill_specific): Ditto, no real bug here.
+
+Sun Feb 23 15:01:20 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Clean up diagnostics (especially about intrinsics):
+ * bad.def (FFEBAD_UNIMPL_STMT): Remove.
+ (FFEBAD_INTRINSIC_*, FFEBAD_NEED_INTRINSIC): Clean these
+ up so they're friendlier.
+ (FFEBAD_INTRINSIC_CMPAMBIG): New.
+ * intrin.c (ffeintrin_fulfill_generic,
+ ffeintrin_fulfill_specific, ffeintrin_is_intrinsic):
+ Always choose
+ generic or specific name text (which is for doc purposes
+ anyway) over implementation name text (which is for
+ internal use).
+ * intrin.def: Use more descriptive name texts for generics
+ and specifics in cases where the names themselves are not
+ enough (e.g. IDATE, which has two forms).
+
+ Fix some intrinsic mappings:
+ * intrin.def (FFEINTRIN_specIDINT, FFEINTRIN_specAND,
+ FFEINTRIN_specDFLOAT, FFEINTRIN_specDREAL, FFEINTRIN_specOR,
+ FFEINTRIN_specXOR): Now have their own implementations,
+ instead of borrowing from others.
+ (FFEINTRIN_specAJMAX0, FFEINTRIN_specAJMIN0, FFEINTRIN_specBJTEST,
+ FFEINTRIN_specDFLOTJ, FFEINTRIN_specFLOATJ, FFEINTRIN_specJIABS,
+ FFEINTRIN_specJIAND, FFEINTRIN_specJIBCLR, FFEINTRIN_specJIBITS,
+ FFEINTRIN_specJIBSET, FFEINTRIN_specJIDIM, FFEINTRIN_specJIDINT,
+ FFEINTRIN_specJIDNNT, FFEINTRIN_specJIEOR, FFEINTRIN_specJIFIX,
+ FFEINTRIN_specJINT, FFEINTRIN_specJIOR, FFEINTRIN_specJISHFT,
+ FFEINTRIN_specJISHFTC, FFEINTRIN_specJISIN, FFEINTRIN_specJMAX0,
+ FFEINTRIN_specJMAX1, FFEINTRIN_specJMIN0, FFEINTRIN_specJMIN1,
+ FFEINTRIN_specJMOD, FFEINTRIN_specJNINT, FFEINTRIN_specJNOT,):
+ Turn these implementations off, since it's not clear
+ just what types they expect in the context of portable Fortran.
+ (DFLOAT): Now in FVZ family, since f2c supports them
+
+ Support intrinsic inquiry functions (BIT_SIZE, LEN):
+ * intrin.c: Allow `i' in <arg_extra>.
+ * intrin.def (FFEINTRIN_impBIT_SIZE, FFEINTRIN_impLEN):
+ Mark args with `i'.
+
+Sat Feb 22 13:34:09 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Only warn, don't error, for reference to unimplemented
+ intrinsic:
+ * bad.def (FFEBAD_INTRINSIC_UNIMPLW): Warning version
+ of _UNIMPL.
+ * intrin.c (ffeintrin_is_intrinsic): Use new warning
+ version of _UNIMPL (FFEBAD_INTRINSIC_UNIMPLW).
+
+ Complain about REAL(Z) and AIMAG(Z) (Z is DOUBLE COMPLEX):
+ * bad.def (FFEBAD_INTRINSIC_CMPAMBIG): New diagnostic.
+ * expr.c: Needed #include "intrin.h" anyway.
+ (ffeexpr_token_intrincheck_): New function handles delayed
+ diagnostic for "REAL(REAL(expr)" if next token isn't ")".
+ (ffeexpr_token_arguments_): Do most of the actual checking here.
+ * intrin.h, intrin.c (ffeintrin_fulfill_specific): New
+ argument, check_intrin, to tell caller that intrin is REAL(Z)
+ or AIMAG(Z). All callers updated, mostly to pass NULL in
+ for this.
+ (ffeintrin_check_): Also has new arg check_intrin for same
+ purpose. All callers updated the same way.
+ * intrin.def (FFEINTRIN_impAIMAG): Change return type
+ from "R0" to "RC", to accommodate f2c (and perhaps other
+ non-F90 F77 compilers).
+ * top.h, top.c: New option -fugly-complex.
+
+ New GNU intrinsics REALPART, IMAGPART, and COMPLEX:
+ * com.c (ffecom_expr_intrinsic_): Implement impCOMPLEX
+ and impREALPART here. (specIMAGPART => specAIMAG.)
+ * intrin.def: Add the intrinsics here.
+
+ Rename implementations of VXTIDATE and VXTTIME to IDATEVXT
+ and TIMEVXT, so they sort more consistently:
+ * com.c (ffecom_expr_intrinsic_):
+ * intrin.def:
+
+ Delete intrinsic group `dcp', add `gnu', etc.:
+ * intrin.c (ffeintrin_state_family): FFEINTRIN_familyGNU
+ replaces FFEINTRIN_familyDCP, and gets state from `gnu'
+ group.
+ Get rid of FFEINTRIN_familyF2Z, nobody needs it.
+ Move FFEINTRIN_specDCMPLX from DCP family to FVZ family,
+ as f2c has it.
+ Move FFEINTRIN_specDFLOAT from F2C family to FVZ family.
+ (FFEINTRIN_specZABS, FFEINTRIN_specZCOS, FFEINTRIN_specZEXP,
+ FFEINTRIN_specZLOG, FFEINTRIN_specZSIN, FFEINTRIN_specZSQRT):
+ Move these from F2Z family to F2C family.
+ * intrin.h (FFEINTRIN_familyF2Z, FFEINTRIN_familyDCP): Remove.
+ (FFEINTRIN_familyGNU): Add.
+ * top.h, top.c: Replace `dcp' with `gnu'.
+
+ * com.c (ffecom_expr_intrinsic_): Clean up by collecting
+ simple conversions into one nice, conceptual place.
+ Fix up some intrinsic subroutines (MVBITS, KILL, UMASK) to
+ properly push and pop call temps, to avoid wasting temp
+ registers.
+
+ * g77.c (doit): Toon says variables should be defined
+ before being referenced. Spoilsport.
+
+ * intrin.c (ffeintrin_check_): Now Dave's worried about
+ warnings about uninitialized variables. Okay, so for
+ basic return values 'g' and 's', they _were_
+ uninitialized -- is determinism really _that_ useful?
+
+ * intrin.def (FFEINTRIN_impFGETC): Fix STATUS argument
+ so that it is INTENT(OUT) instead of INTENT(IN).
+
+1997-02-21 Dave Love <d.love@dl.ac.uk>
+
+ * intrin.def, com.c: Support Sun-type `short' and `long'
+ intrinsics. Perhaps should also do Microcruft-style `int2'.
+
+Thu Feb 20 15:16:53 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_expr_intrinsic_): Clean up indentation.
+ Support SECONDSUBR intrinsic implementation.
+ Rename SECOND to SECONDFUNC for direct support via library.
+
+ * g77.c: Fix to return proper status value to shell,
+ by obtaining it from processes it spawns.
+
+ * intdoc.c: Fix minor typo.
+
+ * intrin.def: Turn SECOND into generic that maps into
+ function and subroutine forms.
+
+ * intrin.def: Make FLOAT and SNGL into specific intrinsics.
+
+ * intrin.def, intrin.h: Change the way DEFGEN and DEFSPEC
+ macros work, to save on verbage.
+
+Mon Feb 17 02:08:04 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ New subsystem to automatically generate documentation
+ on intrinsics:
+ * Make-lang.in ($(srcdir)/f/g77.info,
+ $(srcdir)/f/g77.dvi): Move g77 doc rules around.
+ Add to g77 doc rules the new subsystem.
+ (f77.mostlyclean, f77.maintainer-clean): Also clean up
+ after new doc subsystem.
+ * intdoc.c, intdoc.h: New doc subsystem code.
+ * intrin.h [FFEINTRIN_DOC]: When 1, don't pull in
+ stuff not needed by doc subsystem.
+
+ Improve on intrinsics mechanism to both be more
+ self-documenting and to catch more user errors:
+ * intrin.c (ffeintrin_check_): Recognize new arg-len
+ and arg-rank information, and check it.
+ Move goto and signal indicators to the basic type.
+ Permit reference to arbitrary argument number, not
+ just first argument (for BESJN and BESYN).
+ (ffeintrin_init_0): Check and accept new notations.
+ * intrin.c, intrin.def: Value in COL now identifies
+ arguments starting with number 0 being the first.
+
+ Some minor intrinsics cleanups (resulting from doc work):
+ * com.c (ffecom_expr_intrinsic_): Implement FLUSH
+ directly once again, handle its optional argument,
+ so it need not be a generic (awkward to handle in docs).
+ * intrin.def (BESJ0, BESJ1, BESJN, BESY0, BESY1, BESYN,
+ CHDIR, CHMOD, CTIME, DBESJ0, DBESJ1, DBESJN, DBESY0,
+ DBESY1, DBESYN, DDIM, ETIME, FGETC, FNUM, FPUTC, FSTAT,
+ GERROR, GETCWD, GETGID, GETLOG, GETPID, GETUID, GMTIME,
+ HOSTNM, IDATE, IERRNO, IIDINT, IRAND, ISATTY, ITIME, JIDINT,
+ LNBLNK, LSTAT, LTIME, MCLOCK, PERROR, SRAND, SYMLNK, TTYNAM,
+ UMASK): Change capitalization of initcaps (official) name
+ to be consistent with Burley's somewhat arbitrary rules.
+ (BESJN, BESYN): These have return arguments of same type
+ as their _second_ argument.
+ (FLUSH): Now a specific, not generic, intrinsic, with one
+ optional argument.
+ (FLUSH1): Eliminated.
+ Add arg-len and arg-rank info to several intrinsics.
+ (ITIME): Change argument type from REAL to INTEGER.
+
+Tue Feb 11 14:04:42 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Make-lang.in (f771): Invocation of Makefile now done
+ with $(srcdir)=gcc to go along with $(VPATH)=gcc.
+ ($(srcdir)/f/runtime/configure,
+ $(srcdir)/f/runtime/libU77/configure): Break these out
+ so spurious triggers of this rule don't happen (as when
+ configure.in is more recent than libU77/configure).
+ (f77.rebuilt): Distinguish source versus build files,
+ so this target can be invoked from build directory and
+ still work.
+ * Makefile.in: This now expects $(srcdir) to be the gcc
+ source directory, not gcc/f, to agree with $(VPATH).
+ Accordingly, $(INCLUDES) has been fixed, various cruft
+ removed, the removal of f771 has been fixed to remove
+ the _real_ f771 (not the one in gcc's parent directory),
+ and so on.
+
+ * lex.c: Part of ffelex_finish_statement_() now done
+ by new function ffelex_prepare_eos_(), so that, in one
+ popular case, the EOS can be prepared while the pointer
+ is at the end of the non-continued line instead of the
+ end of the line that marks no continuation. This improves
+ the appearance of diagnostics substantially.
+
+Mon Feb 10 12:44:06 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Make-lang.in: runtime Makefile's, and include/f2c.h,
+ also depend on f/runtime/configure and f/runtime/libU77/configure.
+
+ Fix various libU77 routines:
+ * com-rt.def (FFECOM_gfrtCTIME, FFECOM_gfrtMCLOCK,
+ FFECOM_gfrtTIME): These now use INTEGER*8 for time values,
+ for compatibility with systems like Alpha.
+ (FFECOM_gfrtSYSTEM_CLOCK, FFECOM_gfrtTTYNAM): Delete incorrect
+ trailing underscore in routine names.
+ * intrin.c, intrin.def: Support INTEGER*8 return values and
+ arguments ('4'). Change FFEINTRIN_impCTIME, FFEINTRIN_impMCLOCK,
+ and FFEINTRIN_impTIME accordingly.
+ (ffeintrin_is_intrinsic): Don't give caller a clue about
+ form of intrinsic -- shouldn't be needed at this point.
+
+ Cope with generic intrinsics that are subroutines and functions:
+ * com.c (ffecom_finish_symbol_transform_, ffecom_expr_transform_):
+ Don't transform an intrinsic that is not known to be a subroutine
+ or a function. (Maybe someday have to avoid transforming
+ any intrinsic with an undecided or unknown implementation.)
+ * expr.c (ffeexpr_declare_unadorned_,
+ ffeexpr_declare_parenthesized_): Ok to invoke generic
+ intrinsic that has at least one subroutine form as a
+ subroutine.
+ Ok to pass intrinsic as actual arg if it has a known specific
+ intrinsic form that is valid as actual arg.
+ (ffeexpr_declare_parenthesized_): An unknown kind of
+ intrinsic has a paren_type chosen based on context.
+ (ffeexpr_token_arguments_): Build funcref/subrref based
+ on context, not on kind of procedure being called.
+ * intrin.h, intrin.c (ffeintrin_is_intrinsic): Undo changes of
+ Tue Feb 4 23:12:04 1997 by me, change all callers to leave
+ intrinsics as FFEINFO_kindNONE at this point. (Some callers
+ also had unused variables deleted as a result.)
+
+ Enable all intrinsic groups (especially f90 and vxt):
+ * target.h (FFETARGET_defaultSTATE_DCP, FFETARGET_defaultSTATE_F2C,
+ FFETARGET_defaultSTATE_F90, FFETARGET_defaultSTATE_MIL,
+ FFETARGET_defaultSTATE_UNIX, FFETARGET_defaultSTATE_VXT):
+ Delete these macros, let top.c set them directly.
+ * top.c (ffeintrinsic_state_dcp_, ffe_intrinsic_state_f2c_,
+ ffe_intrinsic_state_f90_, ffe_intrinsic_state_mil_,
+ ffe_intrinsic_state_unix_, ffe_intrinsic_state_vxt_):
+ Enable all these directly.
+
+Sat Feb 8 03:21:50 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * g77.c: Incorporate recent changes to ../gcc.c.
+ For version magic (e.g. `g77 -v'), instead of compiling
+ /dev/null, write, compile, run, and then delete a small
+ program that prints the version numbers of the three
+ components of libf2c (libF77, libI77, and libU77),
+ so we get this info with bug reports.
+ Also, this change reduces the chances of accidentally
+ linking to an old (complex-alias-problem) libf2c.
+ Fix `-L' so the argument is expected in `-Larg'.
+
+ * com.h (FFECOM_f2cLONGINT): For INTEGER*8 support in f2c.h,
+ dynamically determine proper type here, instead of
+ assuming `long long int' is correct.
+
+Tue Feb 4 23:12:04 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Add libU77 library from Dave Love <d.love@dl.ac.uk>:
+ * Make-lang.in (f77-runtime): Depend on new Makefile.
+ (f/runtime/libU77/Makefile): New rule.
+ Also configure libU77.
+ ($(srcdir)/f/runtime/configure: Use Makefile.in,
+ so configuration doesn't have to have happened.
+ (f77.mostlyclean, f77.clean, f77.distclean,
+ f77.maintainer-clean): Some fixups here, but more work
+ needed.
+ (RUNTIMESTAGESTUFF): Add libU77's config.status.
+ (LIBU77STAGESTUFF, f77.stage1, f77.stage2, f77.stage3,
+ f77.stage4): New macro, appropriate uses added.
+ * com-rt.def: Add libU77 procedures.
+ * com.c (ffecom_f2c_ptr_to_integer_type_node,
+ ffecom_f2c_ptr_to_real_type_node): New type nodes.
+ (FFECOM_rttypeCHARACTER_): New type of run-time function.
+ (ffecom_char_args_): Handle CHARACTER*n intrinsics
+ where n != 1 here, instead of in ffecom_expr_intrinsic_.
+ (ffecom_expr_intrinsic_): New code to handle new
+ intrinsics.
+ In particular, change how FFEINTRIN_impFLUSH is handled.
+ (ffecom_make_gfrt_): Handle new type of run-time function.
+ (ffecom_init_0): Initialize new type nodes.
+ * config-lang.in: New libU77 directory.
+ * intrin.h, intrin.c (ffeintrin_is_intrinsic): Handle
+ potential generic for subroutine _and_ function
+ specifics via two new arguments. All callers changed.
+ Properly ignore deleted/disabled intrinsics in resolving
+ generics.
+ (ffeintrin_check_, ffeintrin_init_0): Handle CHARACTER intrinsics of (*)
+ length.
+ * intrin.def: Permission granted by FSF to place this in
+ public domain, which will allow it to serve as source
+ for both g77 program and its documentation.
+ Add libU77 intrinsics.
+ (FLUSH): Now a generic, not specific, intrinsic.
+ (DEFIMP): Now support return modifier for CHARACTER intrinsics.
+
+ * com-rt.def (FFECOM_gfrtDIM, FFECOM_gfrtERF,
+ FFECOM_gfrtERFC, FFECOM_gfrtEXP, FFECOM_gfrtSIGN,
+ FFECOM_gfrtSIN, FFECOM_gfrtSINH, FFECOM_gfrtTAN,
+ FFECOM_gfrtTANH, FFECOM_gfrtPOW_RI): Change "&r" to "&f".
+
+Sat Feb 1 12:15:09 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Version 0.5.19.1 released.
+
+ * com.c (ffecom_expr_, ffecom_expr_intrinsic_,
+ ffecom_tree_divide_): FFECOM_gfrtPOW_ZI,
+ FFECOM_gfrtCONJG, FFECOM_gfrtDCONJG,
+ FFECOM_gfrtCCOS, FFECOM_gfrtCDCOS,
+ FFECOM_gfrtCLOG, FFECOM_gfrtCDLOG,
+ FFECOM_gfrtCSIN, FFECOM_gfrtCDSIN,
+ FFECOM_gfrtCSQRT, FFECOM_gfrtCDSQRT,
+ FFECOM_gfrtDIV_CC, FFECOM_gfrtDIV_ZZ: These all require
+ result to _not_ overlap one or more inputs.
+
+Sat Feb 1 00:25:55 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_init_0): Do internal checks only if
+ -fset-g77-defaults not specified.
+
+ Fix %LOC(), LOC() to return sufficiently wide type:
+ * com.h, com.c (ffecom_pointer_kind_, ffecom_label_kind_,
+ ffecom_pointer_kind(), ffecom_label_kind()): New globals
+ and accessor macros hold kind for integer pointers on target
+ machine.
+ (ffecom_init_0): Determine narrowest INTEGER type that
+ can hold a pointer (usually INTEGER*4 or INTEGER*8),
+ store it in ffecom_pointer_kind_, etc.
+ * expr.c (ffeexpr_cb_end_loc_): Use right type for %LOC().
+ * intrin.c (ffeintrin_check_, ffeintrin_init_0): Support
+ new 'p' kind for type of intrinsic.
+ * intrin.def (FFEINTRIN_impLOC): Returns "Ip" instead of "I1",
+ so LOC() type is correct for target machine.
+
+ Support -fugly-assign:
+ * lang-options.h, top.h, top.c (ffe_decode_option):
+ Accept -fugly-assign and -fno-ugly-assign.
+ * com.c (ffecom_expr_): Handle -fugly-assign.
+ * expr.c (ffeexpr_finished_): Check right type for ASSIGN
+ contexts.
+
+Fri Jan 31 14:30:00 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Remove last vestiges of -fvxt-not-f90:
+ * stb.c (ffestb_R10012_, ffestb_R10014_, ffestb_V0201_):
+ top.c, top.h:
+
+Fri Jan 31 02:13:54 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * top.c (ffe_decode_option): Warn if -fugly is specified,
+ it'll go away soon.
+
+ * symbol.h: No need to #include "bad.h".
+
+ Reorganize features from -fvxt-not-f90 to -fvxt:
+ * lang-options.h, top.h, top.c:
+ Accept -fvxt and -fno-vxt, but not -fvxt-not-f90 or -ff90-not-vxt.
+ Warn if the latter two are used.
+ * expr.c (ffeexpr_nil_rhs_): Double-quote means octal constant.
+ (ffeexpr_token_rhs_): Double-quote means octal constant.
+ * target.h (FFETARGET_defaultIS_VXT_NOT_90): Delete macro
+ definition, no longer needed.
+
+ Make some -ff90 features the default:
+ * data.c (ffedata_value): DATA implies SAVE.
+ * src.h (ffesrc_is_name_noninit): Underscores always okay.
+
+ Fix up some more #error directives by quoting their text:
+ * bld.c (ffebld_constant_is_zero):
+ * target.h:
+
+Sat Jan 18 18:22:09 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * g77.c (lookup_option, main): Recognize `-Xlinker',
+ `-Wl,', `-l', `-L', `--library-directory', `-o',
+ `--output'.
+ (lookup_option): Don't depend on SWITCH_TAKES_ARG
+ being correct, it might or might not have `-x' in
+ it depending on host.
+ Return NULL argument if it would be an empty string.
+ (main): If no input files (by gcc.c's definition)
+ but `-o' or `--output' specified, produce diagnostic
+ to avoid overwriting output via gcc.
+ Recognize C++ `+e' options.
+ Treat -L as another non-magical option (like -B).
+ Don't append_arg `-x' twice.
+
+Fri Jan 10 23:36:00 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * top.c [BUILT_FOR_270] (ffe_decode_option): Make
+ -fargument-noalias-global the default.
+
+Fri Jan 10 07:42:27 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Enable inlining of previously-compiled program units:
+ * com.c (ffecom_do_entry_, ffecom_start_progunit_):
+ Register new public function in ffeglobal database.
+ (ffecom_sym_transform_): Any GLOBAL or potentially GLOBAL
+ symbol should be looked up in ffeglobal database and
+ that tree node used, if found. That way, gcc knows
+ the references are to those earlier definitions, so it
+ can emit shorter branches/calls, inline, etc.
+ (ffecom_transform_common_): Minor change for clarity.
+ * expr.c (ffeexpr_sym-lhs_call_, ffeexpr_sym_lhs_extfunc_,
+ ffeexpr_sym_rhs_actualarg_, ffeexpr_paren_rhs_let_,
+ ffeexpr_token_funsubstr_): Globalize symbol as needed.
+ * global.c (ffeglobal_promoted): New function to look up
+ existing local symbol in ffeglobal database.
+ * global.h: Declare new function.
+ * name.h (ffename_token): New macro, plus alphabetize.
+ * stc.c (ffestc_R1207_item): Globalize EXTERNAL symbol.
+ * stu.c (ffestu_sym_end_transition, ffestu_sym_exec_transition):
+ Globalize symbol as needed.
+ * symbol.h, symbol.c (ffesymbol_globalize): New function.
+
+Thu Jan 9 14:20:00 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * ste.c (ffeste_R809): Produce a diagnostic for SELECT CASE
+ on CHARACTER type, instead of crashing.
+
+Thu Jan 9 00:52:45 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * stc.c (ffestc_order_entry_, ffestc_order_format_,
+ ffestc_R1226): Allow ENTRY and FORMAT before IMPLICIT
+ NONE, by having them transition only to state 1 instead
+ of state 2 (which is disallowed by IMPLICIT NONE).
+
+Mon Jan 6 22:44:53 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix AXP bug found by Rick Niles (961201-1.f):
+ * com.c (ffecom_init_0): Undo my 1996-05-14 change, as
+ it is incorrect and prevented easily finding this bug.
+ * target.h [__alpha__] (ffetargetReal1, ffetargetReal2):
+ Use int instead of long.
+ (ffetarget_cvt_r1_to_rv_, ffetarget_cvt_rv_to_r1_,
+ ffetarget_cvt_r2_to_rv_, ffetarget_cvt_rv_to_r2_):
+ New functions that intercede for callers of
+ REAL_VALUE_(TO|UNTO)_TARGET_(SINGLE|DOUBLE).
+ All callers changed, and damaging casts to (long *) removed.
+
+Sun Jan 5 03:26:11 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Make-lang.in (g77, g77-cross): Depend on both g77.c and
+ zzz.c, in $(srcdir)/f/.
+
+ Better design for -fugly-assumed:
+ * stc.c (ffestc_R501_item, ffestc_R524_item,
+ ffestc_R547_item_object): Pass new is_ugly_assumed flag.
+ * stt.c, stt.h (ffestt_dimlist_as_expr,
+ ffestt_dimlist_type): New is_ugly_assumed flag now
+ controls whether "1" is treated as "*".
+ Don't treat "2-1" or other collapsed constants as "*".
+
+Sat Jan 4 15:26:22 1997 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * stb.c (ffestb_R10012_): Don't confirm on FORMAT(A,)
+ or even FORMAT(A,,B), as R1229 only warns about the
+ former currently, and this seems reasonable.
+
+ Improvements to diagnostics:
+ * sta.c (ffesta_second_): Don't add any ffestb parsers
+ unless they're specifically called for.
+ Set up ffesta_tokens[0] before calling ffestc_exec_transition,
+ else stale info might get used.
+ (ffesta_save_): Do a better job picking which parser to run
+ after running all parsers with no confirmed possibles.
+ (FFESTA_maxPOSSIBLES_): Decrease from 100 now that so few
+ possibles are ever on the list at a given time.
+ (struct _ffesta_possible): Add named attribute.
+ (ffesta_add_possible_exec_, ffesta_add_possible_nonexec_):
+ Make these into macros that call a single function that now
+ sets the named attribute.
+ (ffesta_add_possible_unnamed_exec_,
+ ffeseta_add_possible_unnamed_nonexec_): New macros.
+ (ffesta_second_): Designate unnamed possibles as
+ appropriate.
+ * stb.c (ffestb_R1229, ffestb_R12291_): Use more general
+ diagnostic, so things like "POINTER (FOO, BAR)" are
+ diagnosed as unrecognized statements, not invalid statement
+ functions.
+ * stb.h, stb.c (ffestb_unimplemented): Remove function.
+
+1996-12-30 Dave Love <d.love@dl.ac.uk>
+
+ * com.c: #include libU77/config.h
+ (ffecom_f2c_ptr_to_integer_type_node,
+ ffecom_f2c_ptr_to_integer_type_node): New variables.
+ (ffecom_init_0): Use them.
+ (ffecom_expr_intrinsic_): Many news cases for libU77 intrinsics.
+
+ * com-rt.def: New definitions for libU77.
+ * intrin.def: Likewise. Also correct ftell arg spec.
+
+ * Makefile.in (f/runtime/libU77/config.h): New target for com.c
+ dependency.
+ * Make-lang.in (f771): Depend on f/runtime/Makefile for the above.
+
+Sat Dec 28 12:28:29 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * stt.c (ffestt_dimlist_type): Treat ([...,]1) in dimlist
+ as ([...,]*) if -fugly-assumed, so assumed-size array
+ detected early enough.
+
+Thu Dec 19 14:01:57 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * target.h (FFETARGET_REAL_VALUE_FROM_INT_): Conditionalize
+ definition on BUILT_FOR_280, not BUILT_WITH_280, since
+ the name of the macro was (properly) changed since 0.5.19.
+
+ Fix warnings/errors resulting from ffetargetOffset becoming
+ `long long int' instead of `unsigned long' as of 0.5.19,
+ while ffebitCount remains `unsigned long':
+ * bld.c (ffebld_constantarray_dump): Avoid warnings by
+ using loop var of appropriate type, and using casts.
+ * com.c (ffecom_expr_): Use right type for loop var.
+ (ffecom_sym_transform_, ffecom_transform_equiv_):
+ Cast to right type in assertions.
+ * data.c (ffedata_gather_, ffedata_value_): Cast to right
+ type in assertions and comparisons.
+
+Wed Dec 18 12:07:11 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Patch from Alexandre Oliva <oliva@dcc.unicamp.br>:
+ * Makefile.in (all.indirect): Don't pass -bbigtoc option
+ to GNU ld.
+
+ Cope with new versions of gcc:
+ * com.h (BUILT_FOR_280): New macro.
+ * com.c (ffecom_ptr_to_expr): Conditionalize test of
+ OFFSET_REF.
+ (ffecom_build_complex_constant_): Conditionalize calling
+ sequence for build_complex.
+
+Sat Dec 7 07:15:17 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Version 0.5.19 released.
+
+Fri Dec 6 12:23:55 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * g77.c: Default to assuming "f77" is in $LANGUAGES, since
+ the LANGUAGE_F77 macro isn't defined by anyone anymore (but
+ might as well leave the no-f77 code in just in case).
+ * Make-lang.in (g77, g77-cross): Don't define LANGUAGE_F77
+ anymore.
+
+1996-12-06 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in (g77, g77-cross): Revert to building `g77' or not
+ conditional on `f77' in LANGUAGES.
+
+Wed Dec 4 13:08:44 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Make-lang.in (g77, g77-cross): No libs or lib dependencies
+ in case where "f77" is not in $LANGUAGES.
+
+ * lex.c (ffelex_image_char_, ffelex_file_fixed,
+ ffelex_file_free): Fixes to properly handle lines with
+ null character, and too-long lines as well.
+
+ * lex.c: Call ffebad_start_msg_lex instead of
+ ffebad_start_msg throughout.
+
+Sun Dec 1 21:19:55 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Fix-up for 1996-11-25 changes:
+ * com.c (ffecom_member_phase2_): Subtract out 0 offset for
+ elegance and consistency with EQUIVALENCE aggregates.
+ (ffecom_sym_transform_): Ditto for LOCAL/COMMON, and
+ ensure we get the same parent storage area.
+ * data.c (ffedata_gather_, ffedata_value_): Subtract out
+ aggregate offset.
+
+Wed Nov 27 13:55:57 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * proj.h: Quote the text of the #error message, to avoid
+ strange-looking diagnostics from non-gcc ANSI compilers.
+
+ * top.c: Make -fno-debug-kludge the default.
+
+Mon Nov 25 20:13:45 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Provide more info on EQUIVALENCE mismatches:
+ * bad.def (FFEBAD_EQUIV_MISMATCH): More detailed message.
+ * equiv.c (ffeequiv_layout_local_, ffeequiv_layout_cblock):
+ More details for FFEBAD_EQUIV_MISMATCH.
+
+ Fix problem with EQUIVALENCE handling:
+ * equiv.c (ffeequiv_layout_local_): Redesign algorithm --
+ old one was broken, resulting in rejection of good code.
+ (ffeequiv_offset_): Add argument, change callers.
+ Clean up the code, fix up the (probably unused) negative-value
+ case for SYMTER.
+ * com.c (ffecom_sym_transform_): For local EQUIVALENCE
+ member, subtract out aggregate offset (which is <= 0).
+
+Thu Nov 21 12:44:56 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Change type of ffetargetOffset from `unsigned long' to `long long':
+ * bld.c (ffebld_constantarray_dump): Change printf formats.
+ * storag.c (ffestorag_dump): Ditto.
+ * symbol.c (ffesymbol_report): Ditto.
+ * target.h (ffetargetOffset_f): Ditto and change type itself.
+
+ Handle situation where list of languages does not include f77:
+ * Make-lang.in: Define LANGUAGE_F77 to 1 only if `f77' is in
+ the $LANGUAGES macro for the build.
+ * g77.c: Compile to a (nearly) no-op program if LANGUAGE_F77
+ is not defined to 1.
+
+ Fixes to delay confirmation of READ, WRITE, and GOTO statements
+ so the corresponding assignments to same-named CHAR*(*) arrays
+ work:
+ * stb.c (ffestb_R90915_, ffestb_91014_): New functions.
+ (ffestb_goto3_, ffestb_goto5_): Move confirmation from 3 to 5
+ for the OPEN_PAREN case.
+ (ffestb_R9091_, ffestb_R9094_, ffestb_R90913_, ffestb_R90914_,
+ ffestb_R91012_, ffestb_R91013_): Use new functions, and confirm
+ except for the OPEN_PAREN case.
+
+ Fixes to not confirm declarations with an open paren where
+ an equal sign or other assignment-like token might be, so the
+ corresponding assignments to same-named CHAR*(*) arrays work:
+ (ffestb_decl_entsp_5_): Move assertion so we crash on that first,
+ if it turns out to be wrong, before the less-debuggable crash
+ on mistaken confirmation.
+ (ffestb_decl_entsp_6_, ffestb_decl_entsp_7_, ffestb_decl_entsp_8_):
+ Include OPEN_PAREN in list of assignment-only tokens.
+
+ Fix more diagnosed-crash bugs:
+ * stu.c (ffestu_sym_end_transition): ANY-ize an adjustable array
+ with bad dimension expressions even if still stateUNCERTAIN.
+ (ffestu_symter_end_transition_, ffestu_symter_exec_transition_):
+ Return TRUE for opANY as well.
+ For code elegance, move opSYMTER case into first switch.
+
+1996-11-17 Dave Love <d.love@dl.ac.uk>
+
+ * lex.c: Fix last change.
+
+1996-11-14 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in, config-lang.in: Remove the (broken) libU77 stuff,
+ pending 0.5.20.
+
+Thu Nov 14 15:40:59 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * bad.def (FFEBAD_UNIMPL_STMT): Explain that invalid
+ intrinsic references can trigger this message, too.
+
+1996-11-12 Dave Love <d.love@dl.ac.uk>
+
+ * lex.c: Declare dwarfout routines.
+
+ * config-lang.in: Sink grep o/p.
+
+Mon Nov 11 14:21:13 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * g77.c (main): Might as well print version number
+ for --verbose as well.
+
+Thu Nov 7 18:41:41 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * expr.c, lang-options.h, target.h, top.c, top.h: Split out
+ remaining -fugly stuff into -fugly-logint and -fugly-comma,
+ leaving -fugly as simply a `macro' that expands into other
+ options, and eliminate defaults for some of the ugly stuff
+ in target.h.
+
+ * Make-lang.in (gcc-cross): Compile zzz.c, not version.o (!),
+ in to get version info for this target.
+
+ * config-lang.in: Test for GBE patch application based
+ on whether 2.6.x or 2.7.x GBE is detected.
+
+Wed Nov 6 14:19:45 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Make-lang.in (g77): Compile zzz.c in to get version info.
+ * g77.c: Add support for --help and --version.
+
+ * g77.c (lookup_option): Short-circuit long-winded tests
+ when second char is not hyphen, just to save a spot of time.
+
+Sat Nov 2 13:50:31 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * intrin.def: Add FTELL and FSEEK intrinsics, plus new
+ `g' codes for alternate-return (GOTO) arguments.
+ * intrin.c (ffeintrin_check_): Support `g' codes.
+ * com-rt.def: Add ftell_() and fseek_() to database.
+ * com.c (ffecom_expr_intrinsic_): Ditto. Also, let each
+ subroutine intrinsic decide for itself what to do with
+ tree_type, the default being NULL_TREE once again (so
+ ffecom_call_ doesn't think it's supposed to cast the
+ function call to the type in the fall-through case).
+
+ * ste.c (ffeste_R909_finish): Don't special-case list-directed
+ I/O, now that libf2c can return non-zero status codes.
+ (ffeste_R910_finish): Ditto.
+ (ffeste_io_call_): Simplify logic.
+ (ffeste_io_impdo_):
+ (ffeste_subr_beru_):
+ (ffeste_R904):
+ (ffeste_R907):
+ (ffeste_R909_start):
+ (ffeste_R909_item):
+ (ffeste_R909_finish):
+ (ffeste_R910_start):
+ (ffeste_R910_item):
+ (ffeste_R910_finish):
+ (ffeste_R911_start):
+ (ffeste_R923A): Ditto all the above.
+
+Thu Oct 31 20:56:28 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * config-lang.in, Make-lang.in: Rename flag file
+ build-u77 to build-libu77, for consistency with
+ install-libf2c and such.
+
+ * config-lang.in: Don't complain about failure to patch
+ if pre-2.7.0 gcc is involved (since our patch for that
+ doesn't add support for tooning).
+
+Sat Oct 26 05:56:51 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * bad.def (FFEBAD_TYPELESS_TOO_LARGE): Remove this
+ unused and redundant diagnostic.
+
+Sat Oct 26 00:45:42 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * target.c (ffetarget_integerhex): Fix dumb bug.
+
+1996-10-20 Dave Love <d.love@dl.ac.uk>
+
+ * gbe/2.7.2.1.diff: New file.
+
+ * Makefile.in (F771_LDFLAGS): Add -bbigtoc for AIX4.1 up, suggested by
+ endo@material.tohoku.ac.jp [among others!].
+
+Sat Oct 19 03:11:14 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * bad.def, bld.c, bld.h, expr.c, lang-options.h, target.c,
+ target.h, top.c, top.h (ffebld_constant_new_integerbinary,
+ ffebld_constant_new_integerhex, ffebld_constant_new_integeroctal,
+ ffeexpr_token_name_apos_name_, ffetarget_integerbinary,
+ ffetarget_integerhex, ffetarget_integeroctal): Support
+ new -fno-typeless-boz option with new functions, mods to
+ existing octal-handling functions, new macros, new error
+ messages, and so on.
+
+ * com.c, lang-options.h, top.c, top.h (ffecom_notify_primary_entry):
+ Print program unit name on stderr if -fno-silent (new option).
+
+ * lang-options.h, top.c, top.h, stt.c (ffestt_dimlist_as_expr):
+ Treat ([...,]1) in dimlist as ([...,]*) if -fugly-assumed
+ (new option).
+
+ * lang-options.h: Comment out options duplicated in gcc/toplev.c,
+ because, somehow, having them commented in and building on my
+ DEC Alpha results in a cc1 that always segfaults, and gdb that
+ also segfaults whenever it debugs it up to init_lex() calling
+ xmalloc() or so.
+
+Thu Oct 17 00:39:27 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * stb.c (ffestb_R10013_): Don't change meaning of .sign until
+ after previous meaning/value used to set sign of value
+ (960507-1.f).
+
+Sun Oct 13 22:15:23 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * top.c (ffe_decode_option): Don't set back-end flags
+ that are nonexistent prior to gcc 2.7.0.
+
+Sun Oct 13 12:48:45 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (convert): Don't convert emulated complex expr to
+ real (via REALPART_EXPR) if the target type is (emulated)
+ complex.
+
+Wed Oct 2 21:57:12 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_debug_kludge_): Set DECL_IN_SYSTEM_HEADER so
+ -Wunused doesn't complain about these manufactured decls.
+ (ffecom_expr_): Ditto, for original (non-ASSIGN'ed) variable.
+ (ffecom_transform_equiv_): Clear DECL_IGNORED_P for aggregate
+ area so it shows up as a debug-accessible symbol.
+ (pushdecl): Default for "invented" identifiers (a g77-specific
+ concept for now) is that they are artificial, in system header,
+ ignored for debugging purposes, used, and (for types) suppressed.
+ This ought to be overkill.
+
+Fri Sep 27 23:13:07 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * ste.c (ffeste_begin_iterdo_, ffeste_end_iterdo_): Support
+ one-trip DO loops (F66-style).
+ * lang-options.h, top.c, top.h (-fonetrip): New option.
+
+Thu Sep 26 00:18:40 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_debug_kludge_): New function.
+ (ffecom_sym_transform_): Use new function for COMMON and EQUIVALENCE
+ members.
+
+ * lang-options.h, top.c, top.h (-fno-debug-kludge):
+ New option.
+
+1996-09-24 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in (include/f2c.h):
+ Remove dependencies on xmake_file and tmake_file.
+ They expand inconsistently in 2.8 c.f. 2.7; $(GCC_PARTS) depends on
+ them anyhow.
+
+1996-09-22 Dave Love <d.love@dl.ac.uk>
+
+ * config-lang.in: Add --enable-libu77 option handling.
+
+ * Make-lang.in:
+ Conditionally add --enable-libu77 when running runtime configure.
+ Define LIBU77STAGESTUFF and use it in relevant rules.
+
+1996-08-21 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in (f77-runtime):
+ `stmp-hdrs' should have been `stmp-headers'.
+
+1996-08-20 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in (f77-runtime):
+ Depend on stmp-hdrs, not stmp-int-hdrs, since libF77
+ needs float.h.
+
+Sat Jun 22 18:17:11 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_tree_divide_): Fix RECORD_TYPE case to
+ look at type of first field, properly, to determine
+ whether to call c_div or z_div.
+
+Tue Jun 4 04:27:18 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_build_complex_constant_): Explicitly specify
+ TREE_PURPOSE.
+ (ffecom_expr_): Fix thinko.
+ (ffecom_2): For COMPLEX_EXPR, explicitly specify TREE_PURPOSE.
+
+Mon May 27 16:23:43 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Changes to optionally avoid gcc's back-end complex support:
+ * com.c (ffecom_stabilize_aggregate_): New function.
+ (ffecom_convert_to_complex_): New function.
+ (ffecom_make_complex_type_): New function.
+ (ffecom_build_complex_constant_): New function.
+ (ffecom_expr_): For opCONVERT of non-COMPLEX to COMPLEX,
+ don't bother explicitly converting to the subtype first,
+ because gcc does that anyway, and more code would have
+ to be added to find the subtype for the emulated-complex
+ case.
+ (ffecom_f2c_make_type_): Use ffecom_make_complex_type_
+ instead of make_node etc. to make a complex type.
+ (ffecom_1, ffecom_2): Translate operations on COMPLEX operands
+ to appropriate operations when emulating complex.
+ (ffecom_constantunion): Use ffecom_build_complex_constant_
+ instead of build_complex to build a complex constant.
+ (ffecom_init_0): Change point at which types are laid out
+ for improved consistency.
+ Use ffecom_make_complex_type_ instead of make_node etc.
+ to make a complex type.
+ Always calculate storage sizes from TYPE_SIZE, never TYPE_PRECISION.
+ (convert): Use e, not expr, since we've copied into that anyway.
+ For RECORD_TYPE cases, do emulated-complex conversions.
+ (ffecom_f2c_set_lio_code_): Always calculate storage sizes
+ from TYPE_SIZE, never TYPE_PRECISION.
+ (ffecom_tree_divide_): Allow RECORD_TYPE to also be handled
+ by run-time library.
+ (ffecom_expr_intrinsic_): Handle possible RECORD_TYPE as argument
+ to AIMAG intrinsic.
+
+ * top.h, top.c, lang-options.h: Support new -f(no-)emulate-complex option.
+
+ * com.c (ffecom_sym_transform_): Clarify and fix typos in comments.
+
+Mon May 20 02:06:27 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * target.h: Use new REAL_VALUE_UNTO_TARGET_* macros instead
+ of REAL_VALUE_FROM_TARGET_DOUBLE and _SINGLE.
+ Explicitly use long instead of HOST_WIDE_INT for emulation
+ of ffetargetReal1 and ffetargetReal2.
+
+1996-05-20 Dave Love <d.love@dl.ac.uk>
+
+ * config-lang.in:
+ Test for patch being applied with flag_move_all_movables in toplev.c.
+
+ * install.texi (Patching GNU Fortran):
+ Mention overriding X_CFLAGS rather than
+ editing proj.h on SunOS4.
+
+ * Make-lang.in (F77_FLAGS_TO_PASS):
+ Add X_CFLAGS (convenient for SunOS4 kluge, in
+ particular).
+ (f77.{,mostly,dist}clean): Reorder things, in particular not to delete
+ Makefiles too early.
+
+ * g77.c (DEFAULT_SWITCH_TAKES_ARG): Define a la gcc.c in the
+ current GCC snapshot.
+
+Tue May 14 00:24:07 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ Changes for DEC Alpha AXP support:
+ * com.c (ffecom_init_0): REAL_ARITHMETIC means internal
+ REAL/DOUBLE PRECISION might well have a different size
+ than the compiled type, so don't crash if this is the
+ case.
+ * target.h: Use `int' for ffetargetInteger1,
+ ffetargetLogical1, and magical tests. Set _f format
+ strings accordingly.
+
+Tue Apr 16 14:08:28 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * top.c (ffe_decode_option): -Wall no longer implies
+ -Wsurprising.
+
+Sat Apr 13 14:50:06 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_char_args_): If item is error_mark_node,
+ set *length that way, too.
+
+ * com.c (ffecom_expr_power_integer_): If either operand
+ is error_mark_node, return that.
+
+ * com.c (ffecom_intrinsic_len_): If item is error_mark_node,
+ return that for length.
+
+ * expr.c (ffeexpr_declare_unadorned_,
+ ffeexpr_declare_parenthesized_): Instead of crashing
+ on unexpected contexts, produce a diagnostic.
+
+ * intrin.c (ffeintrin_check_), intrin.def (impSIGNAL):
+ Allow procedure as second arg to SIGNAL intrinsic.
+
+ * stu.c (ffestu_symter_end_transition_): New function.
+ (ffestu_symter_exec_transition_): Return bool arg.
+ Always transition symbol (don't inhibit when !whereNONE).
+ (ffestu_sym_end_transition): If DUMMY/LOCAL arg has any
+ opANY exprs in its dimlist, diagnose it so it doesn't
+ make it through to later stages that try to deal with
+ dimlist stuff.
+ (ffestu_sym_exec_transition): If sym has any opANY exprs
+ in its dimlist, diagnose it so it becomes opANY itself.
+
+ * symbol.c (ffesymbol_error): If token arg is NULL,
+ just ANY-ize the symbol -- don't produce diagnostic.
+
+Mon Apr 1 10:14:02 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Version 0.5.18 released.
+
+Mon Mar 25 20:52:24 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_expr_power_integer_): Don't generate code
+ that compares COMPLEX (or, as it happens, REAL) via "LT_EXPR",
+ since the back end crashes on that. (This code would never
+ be executed anyway, but the test that avoids it has now been
+ translated to control whether the code gets generated at all.)
+ Fixes 960323-3.f.
+
+ * com.c (ffecom_type_localvar_): Handle variable-sized
+ dimension bounds expressions here, so they get calculated
+ and saved on procedure entry. Fixes 960323-4.f.
+
+ * com.c (ffecom_notify_init_symbol): Symbol has no init
+ info at all if only zeros have been used to initialize it.
+ Fixes 960324-0.f.
+
+ * expr.c, expr.h (ffeexpr_type_combine): Renamed from
+ ffeexpr_type_combine_ and now a public procedure; last arg now
+ a token, instead of an internal structure used to extract a token.
+ Now allows the outputs to be aliased with the inputs.
+ Now allows a NULL token to mean "don't report error".
+ (ffeexpr_reduced_bool2_, ffeexpr_reduced_eqop2_,
+ ffeexpr_reduced_math2_, ffeexpr_reduced_power_,
+ ffeexpr_reduced_relop2_): Handle new calling sequence for
+ ffeexpr_type_combine.
+ * (ffeexpr_convert): Don't put an opCONVERT node
+ in just because the size is unknown; all downstream code
+ should be able to deal without it being there anyway, and
+ getting rid of it allows new intrinsic code to more easily
+ combine types and such without generating bad code.
+ * info.c, info.h (ffeinfo_kindtype_max): Rewrite to do
+ proper comparison of size of types, not just comparison
+ of their internal kind numbers (so I2.eq.I1 doesn't promote
+ I1 to I2, rather the other way around).
+ * intrin.c (ffeintrin_check_): Combine types of arguments
+ in COL a la expression handling, for greater flexibility
+ and permissiveness (though, someday, -fpedantic should
+ report use of this kind of thing).
+ Make sure Hollerith/typeless where CHARACTER expected is
+ rejected. This all fixes 960323-2.f.
+
+ * ste.c (ffeste_begin_iterdo_): Fix some more type conversions
+ so INTEGER*2-laden DO loops don't crash at compile time on
+ certain machines. Believed to fix 960323-1.f.
+
+ * stu.c (ffestu_sym_end_transition): Certainly reject
+ whereDUMMY not in any dummy list, whether stateUNCERTAIN
+ or stateUNDERSTOOD. Fixes 960323-0.f.
+
+Tue Mar 19 13:12:40 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * data.c (ffedata_value): Fix crash on opANY, and simplify
+ the code at the same time.
+
+ * Make-lang.in (f77-runtime): Also depends on lib[FI]77/Makefile...
+ (include/f2c.h...): ...which in turn depend on */Makefile.in.
+ (f77.rebuilt): Rebuild runtime stuff too.
+
+ * intrin.c (ffeintrin_check_): Accommodate TYPELESS/HOLLERITH
+ types, convert args as necessary, etc.
+
+ * expr.c (ffeexpr_convert): Fix test for TYPELESS/HOLLERITH
+ to obey the docs; crash if no source token when error.
+ (ffeexpr_collapse_convert): Crash if no token when error.
+
+Mon Mar 18 15:51:30 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_init_zero_): Renamed from
+ ffecom_init_local_zero_; now handles top-level
+ (COMMON) initializations too.
+
+ * bld.c (ffebld_constant_is_zero):
+ * com.c (ffecom_symbol_transform_, ffecom_sym_transform_assign_,
+ ffecom_transform_common_, ffecom_transform_equiv_):
+ * data.c:
+ * equiv.c:
+ * equiv.h:
+ * lang-options.h:
+ * stc.c:
+ * storag.c:
+ * storag.h:
+ * symbol.c:
+ * symbol.h:
+ * target.c:
+ * target.h:
+ * top.c:
+ * top.h: All of this is mostly housekeeping-type changes
+ to support -f(no-)zeros, i.e. not always stuff zero
+ values into the initializer fields of symbol/storage objects,
+ but still track that they have been given initial values.
+
+ * bad.def: Fix wording for DATA-related diagnostics.
+
+ * com.c (ffecom_sym_transform_assign_): Don't check
+ any EQUIVALENCE stuff for local ASSIGN, the check was
+ bad (crashing), and it's not necessary, anyway.
+
+ * com.c (ffecom_expr_intrinsic_): For MAX and MIN,
+ ignore null arguments as far arg[123], and fix handling
+ of ANY arguments. (New intrinsic support now allows
+ spurious trailing null arguments.)
+
+ * com.c (ffecom_init_0): Add HOLLERITH (unsigned)
+ equivalents for INTEGER*2, *4, and *8, so shift intrinsics
+ and other things that need unsigned versions of signed
+ types work.
+
+Sat Mar 16 12:11:40 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * storag.c (ffestorag_exec_layout): Treat adjustable
+ local array like dummy -- don't create storage object.
+ * com.c (ffecom_sym_transform_): Allow for NULL storage
+ object in LOCAL case (adjustable array).
+
+Fri Mar 15 13:09:41 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_sym_transform_): Allow local symbols
+ with nonconstant sizes (adjustable local arrays).
+ (ffecom_type_localvar_): Allow dimensions with nonconstant
+ component (adjustable local arrays).
+ * expr.c: Various minor changes to handle adjustable
+ local arrays (a new case of stateUNCERTAIN).
+ * stu.c (ffestu_sym_end_transition,
+ ffestu_sym_exec_transition): Ditto.
+ * symbol.def: Update docs to reflect these changes.
+
+ * com.c (ffecom_expr_): Reduce space/time needed for
+ opACCTER case by handling it here instead of converting
+ it to opARRTER earlier on.
+ (ffecom_notify_init_storage): Don't convert ACCTER to ARRTER.
+ (ffecom_notify_init_symbol): Ditto.
+
+ * com.c (ffecom_init_0): Crash and burn if any of the types'
+ sizes, according to the GBE, disagrees with the sizes of
+ the FFE's internal implementation. This might catch
+ Alpha/SGI bugs earlier.
+
+Fri Mar 15 01:09:41 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com-rt.def, com.c, com.h: Changes for rewrite of intrinsic
+ handling.
+ * com.c (ffecom_arglist_expr_): New function.
+ (ffecom_widest_expr_type_): New function.
+ (ffecom_expr_intrinsic_): Reorganize, some rewriting.
+ (ffecom_f2c_make_type_): Layout complex types.
+ (ffecom_gfrt_args_): New function.
+ (ffecom_list_expr): Trivial change for consistency.
+
+ * expr.c (ffeexpr_token_name_rhs_): Go back to getting
+ type from specific, not implementation, info.
+ (ffeexpr_token_funsubstr_): Set intrinsic implementation too!
+ * intrin.c: Major rewrite of most portions.
+ * intrin.def: Major rearchitecting of tables.
+ * intrin.h (ffeintrin_basictype, ffeintrin_kindtype):
+ Now (once again) take ffeintrinSpec as arg, not ffeintrinImp;
+ for now, these return NONE, since they're not really needed
+ and adding the necessary info to the tables is not trivial.
+ (ffeintrin_codegen_imp): New function.
+ * stc.c (ffestc_R1208_item): Change way ffeintrin funcs called,
+ back to original per above; but comment out the code anyway.
+
+ * intrin.c (ffe_init_0): Do internal checks only if
+ -fset-g77-defaults not specified.
+
+ * lang-options.h: Add -fset-g77-defaults option.
+ * lang-specs.h: Always pass -fset-g77-defaults.
+ * top.c, top.h: New option.
+
+Sat Mar 9 17:49:50 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Make-lang.in (stmp-int-hdrs): Use --no-validate when
+ generating the f77.rebuilt files (BUGS, INSTALL, NEWS)
+ so cross-references can work properly in g77.info
+ without a lot of hassle. Users can probably deal with
+ the way they end up looking in the f77.rebuilt files.
+
+ * bld.c (ffebld_constant_new_integer4_val): INTEGER*8
+ support -- new function.
+ (ffebld_constant_new_logical4_val): New function.
+ * com.c (ffecom_f2c_longint_type_node): New type.
+ (FFECOM_rttypeLONGINT_): New return type code.
+ (ffecom_expr_): Add code to invoke pow_qq instead
+ of pow_ii for INTEGER4 (INTEGER*8) case.
+ If ffecom_expr_power_integer_ returns NULL_TREE, just do
+ the usual work.
+ (ffecom_make_gfrt_): Handle new type.
+ (ffecom_expr_power_integer_): Let caller do the work if in
+ dummy-transforming case, since
+ caller now knows about INTEGER*8 and such, by returning
+ NULL_TREE.
+ * expr.c (ffeexpr_reduced_power_): Complain about non-INTEGER
+ raised to INTEGER4 (INTEGER*8) power.
+
+ * target.c (ffetarget_power_integerdefault_integerdefault):
+ Fix any**negative.
+ * com.c (ffecom_expr_power_integer_): Fix (-1)**(-8) and similar
+ to ABS() the integral result if the exponent is negative
+ and even.
+
+ * ste.c (ffeste_begin_iterdo_): Clean up a type ref.
+ Always convert iteration count to _default_ INTEGER.
+
+ * sta.c (ffesta_second_): Add BYTE and WORD type/stmts;
+ changes by Scott Snyder <snyder@d0sgif.fnal.gov>.
+ * stb.c (ffestb_decl_recursive): Ditto.
+ (ffestb_decl_recursive): Ditto.
+ (ffestb_decl_entsp_2_): Ditto.
+ (ffestb_decl_entsp_3_): Ditto.
+ (ffestb_decl_funcname_2_): Ditto.
+ (ffestb_decl_R539): Ditto.
+ (ffestb_decl_R5395_): Ditto.
+ * stc.c (ffestc_establish_declstmt_): Ditto.
+ * std.c (ffestd_R539item): Ditto.
+ (ffestd_R1219): Ditto.
+ * stp.h: Ditto.
+ * str-1t.fin: Ditto.
+ * str-2t.fin: Ditto.
+
+ * expr.c (ffeexpr_finished_): For DO loops, allow
+ any INTEGER type; convert LOGICAL (assuming -fugly)
+ to corresponding INTEGER type instead of always default
+ INTEGER; let later phases do conversion of DO start,
+ end, incr vars for implied-DO; change checks for non-integral
+ DO vars to be -Wsurprising warnings.
+ * ste.c (ffeste_io_impdo_): Convert start, end, and incr
+ to type of DO variable.
+
+ * com.c (ffecom_init_0): Add new types for [IL][234],
+ much of which was done by Scott Snyder <snyder@d0sgif.fnal.gov>.
+ * target.c: Ditto.
+ * target.h: Ditto.
+
+Wed Mar 6 14:08:45 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * top.c (ffe_init_gbe_): Make -frerun-loop-opt the default.
+
+Mon Mar 4 12:27:00 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * expr.c (ffeexpr_exprstack_push_unary_): Really warn only
+ about two successive _arithmetic_ operators.
+
+ * stc.c (ffestc_R522item_object): Allow SAVE of (understood)
+ local entity.
+
+ * top.c (ffe_decode_option): New -f(no-)second-underscore options.
+ * top.h: New options.
+ * com.c (ffecom_get_external_identifier_, ffecom_get_identifier_):
+ New options.
+
+ * Make-lang.in (f77.maintainer-clean): Clean f/BUGS, f/INSTALL,
+ f/NEWS.
+ ($(srcdir)/f/BUGS, $(srcdir)/f/INSTALL, $(srcdir)/f/NEWS):
+ New rules.
+ ($(srcdir)/f/g77.info, $(srcdir)/f/g77.dvi): Depend on
+ f/bugs.texi and f/news.texi.
+ (f77.install-man): Install f77 man pages (if enabled).
+ (f77.uninstall): Uninstall info docs, f77 man pages (if enabled).
+
+ * top.c (ffe_init_gbe_): New function.
+ (ffe_decode_option, ffe_file): Call ffe_init_gbe_ to
+ set defaults for gcc options.
+
+Sat Jan 20 13:57:19 1996 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_get_identifier_): Eliminate needless
+ comparison of results of strchr.
+
+Tue Dec 26 11:41:56 1995 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * Make-lang.in: Add rules for new files g77.texi, g77.info,
+ and g77.dvi.
+ Reorganize the *clean rules to more closely parallel gcc's.
+
+ * config-lang.in: Exclude g77.info from diffs.
+
+Sun Dec 10 02:29:13 1995 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * expr.c (ffeexpr_declare_unadorned_,
+ ffeexpr_declare_parenthesized_): Break out handling of
+ contextDATAIMPDO[INDEX,CTRL] so it's independent of symbol state.
+ Don't exec-transition these here (let ffeexpr_sym_impdoitem_
+ handle that when appropriate). Don't "declare" them twice.
+
+Tue Dec 5 06:48:26 1995 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * stc.c (ffestc_promote_sfdummy_): Allow whereNONE parent
+ symbol, since it is not necessarily known whether it will
+ become LOCAL or DUMMY.
+
+Mon Dec 4 03:46:55 1995 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * lex.c (ffelex_display_token, ffelex_type_string_): Resurrect
+ these from their old versions and update them for possible invocation
+ from debugger.
+ * lex.h (ffelex_display_token): Declare this in case anyone
+ else wants to call it.
+
+ * lex.c (ffelex_total_tokens_): Have this reflect actual allocated
+ tokens, no longer include outstanding "uses" of tokens.
+
+ * malloc.c, malloc.h (MALLOC_DEBUG): New macro to control
+ checking of whether callers follow rules, now defaults to 0
+ for "no checking" to improve compile times.
+
+ * malloc.c (malloc_pool_kill): Fix bug that could prevent
+ subpool from actually being killed (wasn't setting its use
+ count to 1).
+
+ * proj.h, *.c (dmpout): Replace all occurrences of `stdout'
+ and some of `stderr' with `dmpout', so where to dump debugging
+ output can be easily controlled during build; add default
+ for `dmpout' of `stderr' to proj.h.
+
+Sun Dec 3 00:56:29 1995 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * com.c (ffecom_return_expr): Eliminate attempt at warning
+ about unset return values, since the back end does this better,
+ with better wording, and is not triggered by clearly working
+ (but spaghetti) code as easily as this test.
+
+Sat Dec 2 08:28:56 1995 Craig Burley <burley@gnu.ai.mit.edu>
+
+ * target.c (ffetarget_power_*_integerdefault): Raising 0 to
+ integer constant power should not be an error condition;
+ if so, other code should catch 0 to any power, etc.
+
+ * bad.def (FFEBAD_BAD_POWER): 0**integer now a warning instead
+ of an error.
+
+Fri Dec 1 00:12:03 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * bad.def: Clarify diagnostic regarding complex constant elements.
+ * expr.c (ffeexpr_cb_comma_c_): Capitalize real/imaginary
+ for clarified diagnostic.
+
+ * com.c (ffecom_close_include_): Close the file!
+
+ * lex.c (ffelex_file_fixed): Update line info if the line
+ has any content, not just if it finishes a previous line
+ or has a label.
+ (ffelex_file_free): Clarify switch statement code.
+
+Sat Nov 18 19:37:22 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.17 released.
+
+Fri Nov 17 14:27:24 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Make-lang.in: Fix typo in comment.
+
+ * Makefile.in (f/fini.o, f/proj-h.o): Don't use `$<' since
+ not all makes support it (e.g. NeXT make), use explicit
+ source name instead (with $(srcdir) and munging).
+ (ASSERT_H): assert.h lives in source dir, not build dir.
+
+Thu Nov 16 12:47:50 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_init_0): Fix dumb bug in code to produce
+ warning message about non-32-bit-systems.
+
+ * stc.c (ffestc_R501_item): Parenthesize test to make
+ warning go away (and perhaps fix bug).
+
+Thu Nov 16 03:43:33 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * g77.c: Upgrade to 2.7.0's gcc.c.
+ Fix -v to pass a temp name instead of "/dev/null" for "-o".
+
+Fri Nov 10 19:16:05 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * ste.c (ffeste_begin_iterdo_): Add Toon's change to
+ make loops faster on some machines (implement termination
+ condition as "--i >= 0" instead of "i-- > 0").
+
+Thu Nov 2 03:58:17 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Make-lang.in: Remove unnecessary $(exeext) a la cp/Make-lang.in.
+
+ * com.c (ffecom_expr_): Restore old strategy for assignp variant
+ of opSYMTER case...always return the ASSIGN version of var.
+ That way, `-O -Wuninitialized' will catch "I=3;GOTO I;END"
+ (though the diagnostic will refer to `__g77_ASSIGN_i').
+
+ * com.c (ffecom_expr_power_integer_): For constant rhs case,
+ wrap every new eval of lhs in save_expr() so it is clear to
+ back end that MULT_EXPR(lhs,lhs) has identical operands,
+ otherwise for an rhs like 32767 it generates around 65K pseudo
+ registers, with which stupid_life_analysis cannot cope
+ (due to reg_renumber in regs.h being `short *' instead of
+ `int *').
+
+ * com.c (ffecom_expr_): Speed up implementation of LOGICAL
+ versions of opNOT, opAND, opOR, opXOR/opNEQV, and opEQV by
+ assuming the values actually are kosher LOGICAL bit patterns.
+ Also simplify code that implements some of the INTEGER versions
+ of these.
+
+ * com.c (skip_redundant_dir_prefix, read_name_map,
+ ffecom_open_include_, signed_type, unsigned_type): Fold in
+ changes to cccp.c made from 2.7.0 through ss-950826.
+
+ * equiv.c (ffeequiv_layout_local_): Kill the equiv list
+ if no syms in list.
+
+ * expr.c (ffeexpr_reduced_eqop2_): Issue specific diagnostic
+ regarding usage of .EQV./.NEQV. in preference to .EQ./.NE..
+
+ * intrin.c: Add ERF and ERFC as generic intrinsics.
+ intrin.def: Same.
+
+ * sta.c (ffesta_save_, ffesta_second_): Whoever calls
+ ffestd_exec_begin must also set ffesta_seen_first_exec = TRUE,
+ and anytime stc sees an exec transition, it must do both.
+ stc.c (ffestc_eof): Same.
+
+ * stc.c (ffestc_promote_sfdummy_): If failed implicit typing
+ or CHARACTER*(*) arg, after calling ffesymbol_error, don't
+ reset info to ENTITY/DUMMY, because ffecom_sym_transform_
+ doesn't expect such a thing with ANY/ANY type.
+
+ * target.h (*logical*): Change some of these so they parallel
+ changes in com.c, e.g. for _eqv_, use (l)==(r) instead of
+ !!(l)==!!(r), to get a more faithful result.
+
+Fri Oct 27 07:06:59 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_sym_transform_): Simplify code for local
+ EQUIVALENCE case.
+
+ * expr.c (ffeexpr_exprstack_push_unary_): Warn about two
+ successive operators.
+ (ffeexpr_exprstack_push_binary_): Warn about "surprising"
+ operator precedence, as in "-2**2".
+
+ * lang-options.h: Add -W(no-)surprising options.
+
+ * parse.c (yyparse): Don't reset -fpedantic if not -pedantic.
+
+ * top.c (ffe_decode_option): Support new -Wsurprising option.
+ * top.h: Ditto.
+
+Mon Oct 23 09:14:15 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_finish_symbol_transform_): Don't transform
+ NONE/NONE (CHARACTER*(*)) vars, as these don't mean anything
+ in debugging terms, and can't be turned into anything
+ in the back end (so ffecom_sym_transform_ crashes on them).
+
+ * com.c (ffecom_expr_): Change strategy for assignp variant
+ of opSYMTER case...always return the original var unless
+ it is not wide enough.
+
+ * ste.c (ffeste_io_cilist_): Clarify diagnostic for ASSIGN
+ involving too-narrow variable. This shouldn't happen, though.
+ (ffeste_io_icilist_): Ditto.
+ (ffeste_R838): Ditto.
+ (ffeste_R839): Ditto.
+
+Thu Oct 19 03:21:20 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_sym_transform_assign_): Set TREE_STATIC
+ using the same decision-making process as used for their twin
+ variables, so ASSIGN can last across RETURN/CALL as appropriate.
+
+Fri Sep 22 20:21:18 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Makefile.in: fini is a host program, so it needs a host-compiled
+ version of proj.o, named proj-h.o. f/fini, f/fini.o, and
+ f/proj-h.o targets updated accordingly.
+
+ * com.c (__eprintf): New function.
+
+Wed Sep 20 02:26:36 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * lang-options.h: Add omitted -funix-intrinsics-* options.
+
+ * malloc.c (malloc_find_inpool_): Check for infinite
+ loop, crash if detected (user reports encountering
+ them in some large programs, this might help track
+ down the bugs).
+
+Thu Sep 7 13:00:32 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (lang_print_error_function): Don't dereference null
+ pointer when outside any program unit.
+ (ffecom_let_char_, ffecom_arg_ptr_to_expr): If catlist
+ item or length ever error_mark_node, don't continue processing,
+ since back-end functions like build_pointer_type crash on
+ error_mark_node's (due to pushing bad obstacks, etc.).
+
+Wed Aug 30 15:58:35 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.16 released.
+
+Mon Aug 28 12:24:20 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * bad.c (ffebad_finish): Fix botched message when no places
+ are printed (due to unknown line info, etc.).
+
+ * std.c (ffestd_subr_labels_): Do a better job finding
+ line info in the case of typeANY and diagnostics.
+
+Fri Aug 25 15:19:29 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (DECL_ARTIFICIAL): Surround all references to this
+ macro with #if !BUILT_FOR_270 and #endif.
+ (init_lex): Surround print_error_function decl with
+ #if !BUILT_FOR_270 and #endif.
+ (lang_init): Call new ffelex_hash_kludge function to solve
+ problem with preprocessed files that have INCLUDE statements.
+
+ * lex.c (ffelex_getc_): New function.
+ (ffelex_cfelex_): Use ffelex_getc_ instead of getc in any
+ paths of code that can be affected by ffelex_hash_kludge.
+ Don't make an EOF token for unrecognized token; set token
+ to NULL instead, to avoid problems when not initialized.
+ (ffelex_hash_): Use ffelex_getc_ instead of getc in any
+ paths of code that can be affected by ffelex_hash_kludge.
+ Test token returned by ffelex_cfelex_ for NULL, meaning
+ unrecognized token.
+ Get rid of useless used_up variable.
+ Don't do ffewhere stuff or kill any tokens if in
+ ffelex_hash_kludge.
+ (ffelex_file_fixed, ffelex_file_free): Use ffelex_getc_
+ instead of getc in any paths of code that can be affected
+ by ffelex_hash_kludge.
+ (ffelex_hash_kludge): New function.
+
+ * lex.h (ffelex_hash_kludge): New function.
+
+Wed Aug 23 15:17:40 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c: Implement -f(no-)underscoring options by always
+ compiling in code to do it, and having that code inhibit
+ itself when -fno-underscoring is in effect. This option
+ overrides -f(no-)f2c for this purpose; -f(no-)f2c returns
+ to it's <=0.5.15 behavior of affecting only how code
+ is generated, not how/whether names are mangled.
+
+ * target.h: Redo specification of appending underscores so
+ the macros are named "_default" instead of "_is" and the
+ two-underscore macro defaults to 1.
+
+ * top.c, top.h (underscoring): Add appropriate stuff
+ for the -f(no-)underscoring options.
+
+Tue Aug 22 10:25:01 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * bad.c (ffebad_finish): Call report_error_function (in toplev.c)
+ to better identify location of problem.
+ Say "(continued):" instead of "(continued:)" for consistency.
+
+ * com.c (ffecom_gen_sfuncdef_): Set and reset new
+ ffecom_nested_entry_ variable to hold ffesymbol being compiled.
+ (lang_print_error_function): New function from toplev.c.
+ Use ffecom_nested_entry_ to help determine which name
+ and kind-string to print.
+ (ffecom_expr_intrinsic_): Handle EXIT and FLUSH invocations
+ with different calling sequences than library functions.
+ Have SIGNAL and SYSTEM push and pop calltemps, and convert
+ their return values to the destination type (just in case).
+ (FFECOM_rttypeINT_): New return type for `int', in case
+ gcc/f/runtime/libF77/system_.c(system_) is really supposed
+ to return `int' instead of `ftnint'.
+
+ * com.h (report_error_function): Declare this.
+
+ * equiv.c (ffeequiv_layout_local_): Don't forget to consider
+ root variable itself as possible "first rooted variable",
+ else might never set symbol and then crash later.
+
+ * intrin.c (ffeintrin_check_exit_): Change to allow no args
+ and rename to ffeintrin_check_int_1_o_ for `optional'.
+ #define ffeintrin_check_exit_ and _flush_ to this new
+ function, so intrin.def can refer to the appropriate names.
+
+ * intrin.def (FFEINTRIN_impFLUSH): Validate using
+ ffeintrin_check_flush_ so passing an INTEGER arg is allowed.
+
+ * lex.c (ffelex_file_push_, ffelex_file_pop_): New functions
+ to manage input_file_stack in gbe.
+ (ffelex_hash_): Call new functions (instead of doing code).
+ (ffelex_include_): Call new functions to update stack for
+ INCLUDE (_hash_ handles cpp output of #include).
+
+Mon Aug 21 08:09:04 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Makefile.in: Put `-W' in front of every `-Wall', since
+ 2.7.0 requires that to engage `-Wunused' for parameters.
+
+ * com.c: Mark all parameters as artificial, so
+ `-W -Wunused' doesn't complain about unused ones (since
+ there's no way right not to individually specify attributes
+ like `unused').
+
+ * proj.h: Don't #define UNUSED if already defined, regardless
+ of host compiler.
+
+Sun Aug 20 16:03:56 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * gbe/2.7.0.diff: Regenerate.
+
+ * lang-options.h, lang-specs.h: If not __STDC__ (ANSI C),
+ avoid doing anything, especially the stringizing in -specs.h.
+
+Thu Aug 17 03:36:12 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * lang-specs.h: Remove useless optional settings of -traditional,
+ since -traditional is always set anyway.
+
+Wed Aug 16 16:56:46 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Make-lang.in (F2C_INSTALL_FLAG, F2CLIBOK): More
+ control over whether to install f2c-related stuff.
+ (install-f2c-*): New targets to install f2c-related
+ stuff in system, not just gcc, directories.
+
+ * com.c: Change calls to ffecom_get_invented_identifier
+ to use generally more predictable names.
+ Change calls to build_range_type to ensure consistency
+ of types of operands.
+ (ffecom_get_external_identifier_): Change to accept
+ symbol info, not just text, so it can use f2c flag for
+ symbol to decide whether to append underscore(s).
+ (ffecom_get_identifier_): Don't change names if f2c flag
+ off for compilation.
+ (ffecom_type_permanent_copy_): Use same type for new max as
+ used for min.
+ (ffecom_notify_init_storage): Offline fixups for stand-alone.
+
+ * data.c (ffedata_gather): Explicitly test for common block,
+ since it's no longer always the case that a local EQUIVALENCE
+ group has no symbol ptr (it now can, if a user-predictable
+ "rooted" symbol has been identified).
+
+ * equiv.c: Add some debugging stuff.
+ (ffeequiv_layout_local_): Set symbol ptr with user-predictable
+ "rooted" symbol, for giving the invented aggregate a
+ predictable name.
+
+ * g77.c (append_arg): Allow for 20 extra args instead of 10.
+ (main): For version-only case, add `-fnull-version' and, unless
+ explicitly omitted, `-lf2c -lm'.
+
+ * lang-options.h: New "-fnull-version" option.
+
+ * lang-specs.h: Support ".fpp" suffix for preprocessed source
+ (useful for OS/2, MS-DOS, other case-insensitive systems).
+
+ * stc.c (ffestc_R544_equiv_): Swap way lists are merged so this
+ is consistent with the order in which lists are built, making
+ user predictability of invented aggregate name much higher.
+
+ * storag.c, storag.h (FFESTORAG_typeDUMMY): Delete this enum.
+
+ * top.c: Accept, but otherwise ignore, `-fnull-version'.
+
+Tue Aug 15 07:01:07 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * DOC, INSTALL, PROJECTS: Extensive improvements to documentation.
+
+Sun Aug 13 01:55:18 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * INSTALL (f77-install-ok): Document the use of this file.
+
+ * Make-lang.in (F77_INSTALL_FLAG): New flag to control
+ whether to install an `f77' command (based on whether
+ a file named `f77-install-ok' exists in the source or
+ build directory) to replace the broken attempt to use
+ comment lines to avoid installing `f77' (broken in the
+ sense that it prevented installation of `g77').
+
+Mon Aug 7 06:14:26 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * DOC: Add new sections for g77 & gcc compiler options,
+ source code form, and types, sizes and precisions.
+ Remove lots of old "delta-version" info, or at least
+ summarize it.
+
+ * INSTALL: Add info here that used to be in DOC.
+ Other changes.
+
+ * g77.c (lookup_option, main): Check for --print-* options,
+ so we avoid adding version-determining stuff.
+
+Wed Jul 26 15:51:03 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Make-lang.in, Makefile.in (input.j, INPUT_H): New file.
+ Update dependencies accordingly.
+
+ * bad.c (ffebad_here): Okay to use unknown line/col.
+
+ * compilers.h (@f77-cpp-input): Remove -P option now that
+ # directives are handled by f771. Update other options
+ to be more consistent with @c in gcc/gcc.c. Don't run f771
+ if -E specified, etc., a la @c.
+ (@f77): Don't run f771 if -E specified, etc., a la @c.
+
+ * config-lang.in: Avoid use of word "guaranteed".
+
+ * input.j: New file to wrap around gcc/input.h.
+
+ * lex.j: Add support for parsing # directives output by cpp.
+ (ffelex_cfebackslash_): New function.
+ (ffelex_cfelex_): New function.
+ (ffelex_get_directive_line_): New function.
+ (ffelex_hash_): New function.
+ (ffelex_include_): Change to not use ffewhere_file_(begin|end).
+ Also fix bug in pointing to next line (for diagnostics, &c)
+ following successful INCLUDE.
+ (ffelex_next_line_): New function that does chunk of code
+ seen in several places elsewhere in the lexers.
+ (ffelex_file_fixed): Delay finishing statement until source
+ line is registered with ffewhere, so INCLUDE processing
+ picks up the info correctly.
+ Okay to kill or use unknown line/col objects now.
+ Handle HASH (#) lines.
+ Reorder tests for insubstantial lines to put most frequent
+ occurrences at top, for possible minor speedup.
+ Some general consolidation of code.
+ (ffelex_file_free): Handle HASH (#) lines.
+ Okay to kill or use unknown line/col objects now.
+ Some general consolidation of code.
+ (ffelex_init_1): Detect HASH (#) lines.
+ (ffelex_set_expecting_hollerith): Okay to kill or use unknown
+ line/col objects now.
+
+ * lex.h (FFELEX_typeHASH): New enum.
+
+ * options-lang.h (-fident, -fno-ident): New options.
+
+ * stw.c (ffestw_update): Okay to kill unknown line/col objects
+ now.
+
+ * target.h (FFETARGET_okREALQUAD, FFETARGET_okCOMPLEXDOUBLE,
+ FFETARGET_okCOMPLEXQUAD): #define these appropriately.
+
+ * top.c: Include flag.j wrapper, not flags.h directly.
+ (ffe_is_ident_): New flag.
+ (ffe_decode_option): Handle -fident and -fno-ident.
+ (ffe_file): Replace obsolete ffewhere_file_(begin|end) with
+ ffewhere_file_set.
+
+ * top.h (ffe_is_ident_, ffe_is_ident, ffe_set_is_ident):
+ New flag and access functions.
+
+ * where.c, where.h: Remove all tracking of parent file.
+ (ffewhere_file_begin, ffewhere_file_end): Delete these.
+ (ffewhere_line_use): Make it work with unknown line object.
+
+Mon Jul 17 03:04:09 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_sym_transform_): Set DECL_IN_SYSTEM_HEADER
+ flag for any local vars used as stmtfunc dummies or DATA
+ implied-DO iter vars, so no -Wunused warnings are produced
+ for them (a la f2c).
+ (ffecom_init_0): Do "extern int xargc;" for IARGC() intrinsic.
+ Warn if target machine not 32 bits, since g77 isn't yet
+ working on them at all well.
+
+ * expr.c (ffeexpr_sym_lhs_call_, ffeexpr_sym_lhs_data_,
+ ffeexpr_sym_lhs_extfunc_, ffeexpr_sym_rhs_actualarg_,
+ ffeexpr_sym_rhs_let_, ffeexpr_paren_rhs_let_): Don't
+ gratuitously set attr bits that don't apply just
+ to avoid null set meaning error; instead, use explicit
+ error flag, and allow null attr set, to
+ fix certain bugs discovered by looking at this code.
+
+ * g77.c: Major changes to improve support for gcc long options,
+ to make `g77 -v' report more useful info, and so on.
+
+Mon Jul 3 14:49:16 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * DOC, com.c, intrin.h, intrin.c, intrin.def, target.h, top.c,
+ top.h: Add new `unix' group of intrinsics, which includes the
+ newly added ERF, ERFC, EXIT, plus even newer ABORT, DERF, DERFC,
+ FLUSH, GETARG, GETENV, SIGNAL, and SYSTEM.
+
+Tue Jun 27 23:01:05 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * bld.c, bld.h (ffebld_constant_pool,
+ ffebld_constant_character_pool): Use a single macro (the
+ former) to access the pool for allocating constants, instead
+ of latter in public and FFEBLD_CONSTANT_POOL_ internally
+ in bld.c (which was the only one that was correct before
+ these changes). Add verification of integrity of certain
+ heap-allocated areas.
+
+ * com.c (ffecom_overlap_, ffecom_args_overlap_,
+ ffecom_tree_canonize_ptr_, ffecom_tree_canonize_ref_): New
+ functions to optimize calling COMPLEX and, someday, CHARACTER
+ functions requiring additional argument to be passed.
+ (ffecom_call_, ffecom_call_binop_, ffecom_expr_,
+ ffecom_expr_intrinsic_): Change calling
+ sequences to include more info on possible destination.
+ (ffecom_expr_intrinsic_): Add ERF(), ERFC(), and EXIT()
+ intrinsic code.
+ (ffecom_sym_transform_): For assumed-size arrays, set high
+ bound to highest possible value instead of low bound, to
+ improve validity of overlap checking.
+ (duplicate_decls): If olddecl and newdecl are the same,
+ don't do any munging, just return affirmative.
+
+ * expr.c: Change ffecom_constant_character_pool() to
+ ffecom_constant_pool().
+
+ * info.c (ffeinfo_new): Compile this version if not being
+ compiled by GNU C.
+
+ * info.h (ffeinfo_new): Don't define macro if not being
+ compiled by GNU C.
+
+ * intrin.c, intrin.def: Add ERF(), ERFC(), and EXIT() intrinsics.
+ (ffeintrin_check_exit_): New for EXIT() subroutine intrinsic.
+
+ * malloc.c, malloc.h (malloc_verify_*): New functions to verify
+ integrity of heap-storage areas.
+
+ * stc.c (ffestc_R834, ffestc_R835): Handle possibility that
+ an enclosing DO won't have a construct name even when the
+ CYCLE/EXIT does (i.e. without dereferencing NULL).
+
+ * target.c, target.h (ffetarget_verify_character1): New function
+ to verify integrity of heap storage used to hold character constant.
+
+Thu Jun 22 15:36:39 1995 Howard Gordon (flash@super.org)
+
+ * stp.h (ffestpVxtcodeIx): Fix typo in typedef for this.
+
+Mon May 29 15:22:31 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * *: Make all sorts of changes to accommodate upcoming gcc-2.7.0.
+ I didn't keep track of them, nor just when I made them, nor
+ when I (much later, probably in early August 1995) modified
+ them so they could properly handle both 2.7.0 and 2.6.x.
+
+ * com.c (ffecom_expr_power_integer_): Don't expand_start_stmt_expr
+ if transforming dummy args, because the back end cannot handle
+ that (it's rejected by the gcc front end), just generate
+ call to run-time library.
+ Back out changes in 0.5.15 because more temporaries might be
+ needed anyway (for COMPLEX**INTEGER).
+ (ffecom_push_tempvar): Remove inhibitor.
+ Around start_decl and finish_decl (in particular, arround
+ expand_decl, which is called by them), push NULL_TREE into
+ sequence_rtl_expr, an external published by gcc/function.c.
+ This makes sure the temporary is truly in the function's
+ context, not the inner context of a statement-valued expression.
+ (I think the back end is inconsistent here, but am not
+ interested in convincing the gbe maintainers about this now.)
+ (pushdecl): Make sure that when pushing PARM_DECLs, nothing
+ other than them are pushed, as happened for 0.5.15 and which,
+ if done for other reasons not fixed here, might well indicate
+ some other problem -- so crash if it happens.
+
+ * equiv.c (ffeequiv_layout_local_): If the local equiv group
+ has a non-nil COMMON field, it should mean that an error has
+ occurred and been reported, so just trash the local equiv
+ group and do nothing.
+
+ * stc.c (ffestc_promote_sfdummy_): Set sfdummy arg state to
+ UNDERSTOOD so above checking for duplicate args actually
+ works, and so we don't crash later in pushdecl.
+
+ * ste.c (ffeste_R1001): Set initial value only for VAR_DECLs,
+ not for, e.g., LABEL_DECLs, which the FORMAT label can be
+ if it was previously treated as an executable label.
+
+Sat May 20 01:53:53 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_sym_transform_): For adjustable arrays,
+ pass high bound through variable_size in case its primaries
+ are changed (dumb0.f, and this might also improve
+ performance so it approaches f2c|gcc).
+
+Fri May 19 11:00:36 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.15 released.
+
+ * com.c (ffecom_expr_power_integer_): Push temp vars
+ before expanding a statement expression, since that seems
+ to cause temp vars to be "forgotten" after the end of the
+ expansion in the back end. Disallow more temp-var
+ pushing during such an expansion, just in case.
+ (ffecom_push_tempvar): Crash if a new variable needs to be
+ pushed but cannot be at this point (should never happen).
+
+Wed May 17 12:26:16 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * expr.c (ffeexpr_collapse_convert): Add code to convert
+ LOGICAL to CHARACTER. Reject conversion of REAL or COMPLEX
+ to CHARACTER entirely, as it cannot be supported with all
+ configurations.
+
+ * target.h, target.c (ffetarget_convert_character1_logical1):
+ New function.
+
+Sun May 14 00:00:09 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_do_entry_, ffecom_gen_sfuncdef_,
+ ffecom_start_progunit_, ffecom_sym_transform_,
+ ffecom_init_0, start_function): Changes to have REAL
+ external functions return same type as DOUBLE PRECISION
+ external functions when -ff2c is in force; while at it,
+ some code cleanups done.
+
+ * stc.c (ffestc_R547_item_object): Disallow array declarator
+ if one already exists for symbol.
+
+ * ste.c (ffeste_R1227): Convert result variable to type
+ of function result as seen by back end (e.g. for when REAL
+ external function actually returns result as double).
+
+ * target.h (FFETARGET_defaultFIXED_LINE_LENGTH): New
+ macro for default for -ffixed-line-length-N option.
+
+ * top.c (ffe_fixed_line_length_): Initialize this to new
+ target.h macro instead of constant 72.
+
+Tue May 9 01:20:03 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * lex.c (ffelex_send_token_): If sending CHARACTER token with
+ null text field, put a single '\0' in it and set length/size
+ fields to 0 (to fix 950508-0.f).
+ (ffelex_image_char_): When setting ffelex_bad_line_ to TRUE,
+ always "close" card image by appending a null char and setting
+ ffelex_card_length_. As part of this, append useful text
+ to identify the two kinds of problems that involve this.
+ (ffelex_file_fixed): Reset ffelex_bad_line_ to FALSE after
+ seeing a line with invalid first character (fixes 950508-1.f).
+ If final nontab column is zero, assume tab seen in line.
+ (ffelex_card_image_): Always make this array 8 characters
+ longer than reflected by ffelex_card_size_.
+ (ffelex_init_1): Get final nontab column info from top instead
+ of assuming 72.
+
+ * options-lang.h: Add -ffixed-line-length- prefix.
+
+ * top.h: Add ffe_fixed_line_length() and _set_ version, plus
+ corresponding extern.
+
+ * top.c: Handle -ffixed-line-length- option prefix.
+
+Fri Apr 28 05:40:25 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.14 released.
+
+ * Make-lang.in: Add assert.j.
+
+ * Makefile.in: Add assert.j.
+
+ * assert.j: New file.
+
+Thu Apr 27 16:24:22 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * bad.h (ffebad_severity): New function.
+
+ * bad.c (ffebad_severity): New function.
+
+ * bad.def (FFEBAD_OPEN_INCLUDE): Change severity from SEVERE
+ to FATAL, since processing continues, and that seems fine.
+
+ * com.c: Add facility to handle -I.
+ (ffecom_file, ffecom_close_include, ffecom_open_include,
+ ffecom_decode_include_option): New global functions for -I.
+ (ffecom_file_, ffecom_initialize_char_syntax_,
+ ffecom_close_include_, ffecom_decode_include_option_,
+ ffecom_open_include_, append_include_chain, open_include_file,
+ print_containing_files, read_filename_string, file_name_map,
+ savestring): New internal functions for -I.
+
+ * compilers.h: Pass -I flag(s) to f771 (via "%{I*}").
+
+ * lex.c (ffelex_include_): Call ffecom_close_include
+ to close include file, for its tracking needs for -I,
+ instead of using fclose.
+
+ * options-lang.h: Add -I prefix.
+
+ * parse.c (yyparse): Call ffecom_file for main input file,
+ so -I handling works (diagnostics).
+
+ * std.c (ffestd_S3P4): Have ffecom_open_include handle
+ opening and diagnosing errors with INCLUDE files.
+
+ * ste.c (ffeste_begin_iterdo_): Use correct algorithm for
+ calculating # of iterations -- mathematically similar but
+ computationally different algorithm was not handling cases
+ like "DO I=6,5,2" correctly, because (5-6)/2+1 => 1, not 0.
+
+ * top.c (ffe_decode_option): Allow -I, restructure a bit
+ for clarity and, maybe, speed.
+
+Mon Apr 17 13:31:11 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * g77.c: Remove -lc, turns out not all systems has it, but
+ leave other changes in for clarity of code.
+
+Sun Apr 16 21:50:33 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_expr_): Implement ARRAY_EXPR as INDIRECT_REF
+ of appropriate PLUS_EXPRs of ptr_to_expr of array, to see
+ if this generates better code. (Conditional on
+ FFECOM_FASTER_ARRAY_REFS.)
+
+Sun Apr 16 00:22:48 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Make-lang.in (F77_SRCS): Remove g77.c, since it doesn't
+ contribute to building f771.
+
+ * Makefile.in (dircheck): Remove/replace with f/Makefile, because
+ phony targets that are referenced in other real targets get run
+ when those targets are specified, which is a waste of time (e.g.
+ when rebuilding and only g77.c has changed, f771 was being linked
+ anyway).
+
+ * g77.c: Include -lc between -lf2c and -lm throughout.
+
+ * implic.c (ffeimplic_establish_symbol): If -Wimplicit, warn if
+ implicit type given to symbol.
+
+ * lex.c (ffelex_include_): Don't gratuitously increment line
+ number here.
+
+ * top.h, top.c (ffe_is_warn_implicit_): New global variable and
+ related access macros.
+ (ffe_decode_option): Handle -W options, including -Wall and
+ -Wimplicit.
+
+ * where.c (ffewhere_line_new): Don't muck with root line (was
+ crashing on null input since lexer changes over the past week
+ or so).
+
+Thu Apr 13 16:48:30 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_init_0): Register built-in functions for cos,
+ sin, and sqrt.
+ (ffecom_tree_fun_type_double): New variable.
+ (ffecom_expr_intrinsic_): Update f2c input and output files
+ to latest version of f2c (no important g77-related changes
+ noted, just bug fixes to f2c and such).
+ (builtin_function): New function from c-decl.c.
+
+ * com-rt.def: Refer to built-in functions for cos, sin, and sqrt.
+
+Thu Apr 13 10:25:09 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_expr_intrinsic_): Convert 0. to appropriate
+ type to keep DCMPLX(I) from crashing the compiler.
+ (ffecom_expr_): Don't convert result from ffecom_tree_divide_.
+ (ffecom_tree_divide_): Add tree_type argument, have all callers
+ pass one, and don't convert right-hand operand to it (this is
+ to make this new function work as much like the old in-line
+ code used in ffecom_expr_ as possible).
+
+ * lex.c: Maintain lineno and input_filename the way the gcc
+ lexer does.
+
+ * std.c (ffestd_exec_end): Save and restore lineno and
+ input_filename around the second pass, which sets them
+ appropriately for each saved statement.
+
+Wed Apr 12 09:44:45 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_expr_power_integer_): New function.
+ (ffecom_expr_): Call new function for power op with integer second
+ argument, for generating better code. Also replace divide
+ code with call to new ffecom_tree_divide_ function.
+ Canonicalize calls to ffecom_truth_value(_invert).
+ (ffecom_tree_divide_): New function.
+
+Wed Apr 5 14:15:44 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * lex.c: Change to allocate text for tokens only when actually
+ needed, which should speed compilation up somewhat.
+ Change to allow INCLUDE at any point where a statement
+ can end, i.e. in ffelex_finish_statement_ or when a SEMICOLON
+ token is sent.
+ Remove some old, obsolete code.
+ Clean up layout of entire file to improve formatting,
+ readability, etc.
+ (ffelex_set_expecting_hollerith): Remove include argument.
+
+Fri Mar 31 23:19:08 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * bad.h, bad.c (ffebad_start_msg, ffebad_start_msg_lex):
+ New functions to generate arbitrary messages.
+ (FFEBAD_severityPEDANTIC): New severity, to correspond
+ to toplev's pedwarn() function.
+
+ * lex.c (ffelex_backslash_): New function to implement
+ backslash processing.
+ (ffelex_file_fixed, ffelex_file_free): Implement new
+ backslash processing.
+
+ * std.c (ffestd_R1001dump_): Don't assume CHARACTER and
+ HOLLERITH tokens stop at '\0' characters, now that backslash
+ processing is supported -- use their advertised lengths instead,
+ and double up the '\002' character for libf2c.
+
+Mon Mar 27 17:10:33 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_init_local_zero_): Implement -finit-local-zero.
+ (ffecom_sym_transform_): Same.
+ (ffecom_transform_equiv_): Same.
+
+ * options-lang.h: Add -f(no-)(init-local-zero,backslash,ugly-init).
+
+ * stb.c (ffestb_V020): Reject "TYPEblah(...", which might be
+ an array assignment.
+
+ * target.h, top.h, top.c: Implement -finit-local-zero.
+
+Fri Mar 24 19:56:22 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Make-lang.in, Makefile.in: Remove conf-proj(.in) and
+ proj.h(.in) rules, plus related config.log, config.cache,
+ and config.status stuff.
+
+ * com.c (ffecom_init_0): Change messages when atof(), bsearch(),
+ or strtoul() do not work as expected in the start-up test.
+
+ * conf-proj, conf-proj.in: Delete.
+
+ * lex.c (ffelex_file_fixed): Allow f2c's '&' in column 1
+ to mean continuation line.
+
+ * options-lang.h: New file, #include'd by ../toplev.c.
+
+ * proj.h.in: Rename back to proj.h.
+
+ * proj.h (LAME_ASSERT): Remove.
+ (LAME_STDIO): Remove.
+ (NO_STDDEF): Remove.
+ (NO_STDLIB): Remove.
+ (NO_BSEARCH): Remove auto detection, rename to !FFEPROJ_BSEARCH.
+ (NO_STRTOUL): Remove auto detection, rename to !FFEPROJ_STRTOUL.
+ (USE_HOST_LIMITS): Remove (maybe still needed by stand-alone?).
+ (STR, STRX): Do only ANSI C definitions.
+
+Mon Mar 13 10:46:13 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * BUGS: Add item about g77 requiring gcc to compile it.
+
+ * NEWS: New file listing user-visible changes in the release.
+
+ * PROJECTS: Update to include a new item or two, and modify
+ or delete items that are addressed in this or previous releases.
+
+ * bad.c (ffebad_finish): Don't crash if missing string &c,
+ just substitute obviously distressed string "[REPORT BUG!!]"
+ for cases where the message/caller are fudgy.
+
+ * bad.def: Clean up error messages in a major way, add new ones
+ for use by changes in target.c.
+
+ * com.c (ffecom_expr_): Handle opANY in opCONVERT.
+ (ffecom_let_char_): Disregard destinations with ERROR_MARK.
+ (ffecom_1, ffecom_1_fn, ffecom_2, ffecom_2s, ffecom_3,
+ ffecom_3s, &c): Check all inputs for error_mark_node.
+ (ffecom_start_progunit_): Don't transform all symbols
+ in BLOCK DATA, since it never executes, and it is silly
+ to, e.g., generate all the structures for NAMELIST.
+ (ffecom_char_length_expr_): Rename to ffecom_intrinsic_len_.
+ (ffecom_intrinsic_ichar_): New function to handle ICHAR of
+ arbitrary expression with possible 0-length operands.
+ (ffecom_expr_intrinsic_): Use ffecom_intrinsic_char_.
+ For MVBITS, set tree_type to void_type_node.
+ (ffecom_start_progunit_): Name master function for entry points
+ after primary entry point so users can easily guess it while
+ debugging.
+ (ffecom_arg_ptr_to_expr): Change treatment of Hollerith,
+ Typeless, and %DESCR.
+ (ffecom_expr_): Change treatment of Hollerith.
+
+ * data.c (ffedata_gather_): Handle opANY in opCONVERT.
+
+ * expr.c (ffeexpr_token_apostrophe_): Issue FFEBAD_NULL_CHAR_CONST
+ warning as necessary.
+ (ffeexpr_token_name_rhs_): Set context for args to intrinsic
+ so that assignment-like concatenation is allowed for ICHAR(),
+ IACHAR(), and LEN() intrinsics.
+ (ffeexpr_reduced_*_): Say "an array" instead of "an entity" in
+ diagnostics, since it's more informative.
+ (ffeexpr_finished_): For many contexts, check for null expression
+ and array before trying to do a conversion, to avoid redundant
+ diagnostics.
+
+ * g77.1: Fix typo for preprocessed suffix (.F, not .f).
+
+ * global.c (ffeglobal_init_common): Warn if initializing
+ blank common.
+ (ffeglobal_pad_common): Enable code to warn if initial
+ padding needed.
+ (ffeglobal_size_common): Complain if enlarging already-
+ initialized common, since it won't work right anyway.
+
+ * intrin.c: Add IMAG() intrinsic.
+ (ffeintrin_check_loc_): Allow opSUBSTR in LOC().
+
+ * intrin.def: Add IMAG() intrinsic.
+
+ * lex.c: Don't report FFEBAD_NULL_CHAR_CONST errors.
+
+ * sta.c, sta.h, stb.c: Changes to clean up error messages (see
+ bad.def).
+
+ * stb.c (ffestb_R100113_): Issue FFEBAD_NULL_CHAR_CONST
+ warning as necessary.
+
+ * stc.c (ffestc_shriek_do_): Don't try to reference doref_line
+ stuff in ANY case, since it won't be valid.
+ (ffestc_R1227): Allow RETURN in main program unit, with
+ appropriate warnings/errors.
+ (ffestc_subr_format_): Array of any type is a CHAREXPR (F77 C5).
+
+ * ste.c (ffeste_begin_doiter_): Couple of fixes to accurately
+ determine if loop never executes.
+
+ * target.c (ffetarget_convert_*_hollerith_): Append spaces,
+ not zeros, to follow F77 Appendix C, and to warn when
+ truncation of non-blanks done.
+ (ffetarget_convert_*_typeless): Rewrite to do typeless
+ conversions properly, and warn when truncation done.
+ (ffetarget_print_binary, ffetarget_print_octal,
+ ffetarget_print_hex): Rewrite to use new implementation of
+ typeless.
+ (ffetarget_typeless_*): Rewrite to use new implementation
+ of typeless, and to warn about overflow.
+
+ * target.h (ffetargetTypeless): New implementation of
+ this type.
+
+ * type.h, type.c (ffetype_size_typeless): Remove (incorrect)
+ implementation of this function and its extern.
+
+Sun Mar 5 18:46:42 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * BUGS: Clarify that constant handling would also fix lack of
+ adequate IEEE-754/854 support to some degree, and typeless
+ and non-decimal constants.
+
+ * com.c (ffecom_type_permanent_copy_): Comment out to avoid
+ warnings.
+ (duplicate_decls): New function a la gcc/c-decl.c.
+ (pushdecl): Use duplicate_decls to decide whether to return
+ existing decl or new one, instead of always returning existing
+ decl.
+ (ffecom_expr_): opPERCENT_LOC now supports CHARACTER arguments.
+ (ffecom_init_0): Give f2c I/O code 0 for basictypeANY/kindtypeANY.
+ (ffecom_sym_transform_): For adjustable arrays, pass low bound
+ through variable_size in case its primaries are changed (950302-1.f).
+
+ * com.h: More decls that belong in tree.h &c.
+
+ * data.c (ffedata_eval_integer1_): Fix opPAREN case to not
+ treat value of expression as an error code.
+
+ * expr.c (ffeexpr_finished_): Allow opSUBSTR in contextLOC case.
+
+ * proj.c: Add "const" as appropriate.
+
+Mon Feb 27 10:04:03 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * bad.def (FFEBAD_BAD_SUBSTR): Fix bad grammar in message.
+
+Fri Feb 24 16:21:31 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.13 released.
+
+ * INSTALL: Warn that f/zzz.o will compare differently between
+ stages, since it puts the __TIME__ macro into a string.
+
+ * com.c (ffecom_sym_transform_): Transform kindFUNCTION/whereDUMMY
+ to pointer-to-function, not function.
+ (ffecom_expr_): Use ffecom_arg_ptr_to_expr instead of
+ ffecom_char_args_ to handle comparison between CHARACTER
+ types, so either operand can be a CONCATENATE.
+ (ffecom_transform_common_): Set size of initialized common area
+ to global (largest-known) size, even though size of init might
+ be smaller.
+
+ * equiv.c (ffeequiv_offset_): Check symbol info for ANY.
+
+ * expr.c (ffeexpr_find_close_paren_, ffeexpr_nil_*): New functions
+ to handle following the contour of a rejected expression, so
+ statements like "PRINT(I,I,I)=0" don't cause the PRINT statement
+ code to get the second passed back to it as if there was a
+ missing close-paren before it, the comma causing the PRINT code
+ to confirm the statement, resulting in an ambiguity vis-a-vis
+ the let statement code.
+ Use the new ffecom_find_close_paren_ handler when an expected
+ close-paren is missing.
+ (ffeexpr_isdigits_): New function, use in all places that
+ currently use isdigit in repetitive code.
+ (ffeexpr_collapse_symter): Collapse to ANY if init-expr is ANY,
+ so as to avoid having symbol get "transformed" if used to
+ dimension an array.
+ (ffeexpr_token_real_, ffeexpr_token_number_real_): Don't issue
+ diagnostic about exponent, since it'll be passed along the
+ handler path, resulting in a diagnostic anyway.
+ (ffeexpr_token_apos_char_): Use consistent handler path
+ regardless of whether diagnostics inhibited.
+ (ffeexpr_token_name_apos_name_): Skip past closing quote/apos
+ even if not a match or other diagnostic issued.
+ (ffeexpr_sym_impdoitem_): Exec-transition local SEEN symbol.
+
+ * lex.c (ffelex_image_char_): Set ffelex_saw_tab_ if TAB
+ seen, not if anything other than TAB seen!
+
+ * stc.c (ffestc_R537_item): If source is ANY but dest isn't,
+ set dest symbol's init expr to ANY.
+ (ffestc_R501_attrib, ffestc_R522, ffestc_R522start): Complain
+ about conflict between "SAVE" by itself and other uses of
+ SAVE only in pedantic mode.
+
+ * ste.c (ffeste_R1212): Fix loop over labels to always
+ increment caseno, to avoid pushcase returning 2 for duplicate
+ values when one of the labels is invalid.
+
+Thu Feb 23 12:42:04 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.12 released.
+
+ * Make-lang.in (f77.install-common): Add "else true;" before outer
+ "fi" per Makefile.in patch.
+
+ * Makefile.in (dircheck): Add "else true;" before "fi" per
+ patch from chs1pm@surrey.ac.uk.
+
+ * com.c (ffecom_push_tempvar): If type desired is ERROR_MARK,
+ return error_mark_node, to avoid crash that results from
+ making a VAR_DECL with error_mark_node as its type.
+
+ * ste.c (ffeste_begin_iterdo_): Convert itercount to INTEGER
+ anytime calculation of number of iterations ends up with type
+ other than INTEGER (e.g. DOUBLE PRECISION, REAL).
+
+Thu Feb 23 02:48:38 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.11 released.
+
+ * DOC: Explain -fugly-args.
+
+ * bad.def (FFEBAD_ACTUALARG): Explain -fugly-args and how to
+ rewrite code to not require it.
+
+ * com.c (ffecom_vardesc_): Handle negative type code, just in
+ case.
+ (ffecom_arg_ptr_to_expr): Let ffecom_expr handle hollerith
+ and typeless constants (move code to ffecom_constantunion).
+ (ffecom_constantunion): Handle hollerith and typeless constants.
+
+ * expr.c (ffecom_finished_): Check -fugly-args in actual-arg
+ context where hollerith/typeless provided.
+
+ * intrin.def (FFEINTRIN_genDFLOAT): Add FFEINTRIN_specDFLOAT.
+ (FFEINTRIN_specDFLOAT): Add as f2c intrinsic.
+
+ * target.h (ffetarget_convert_real[12]_integer,
+ ffetarget_convert_complex[12]_integer): Pass -1 for high integer
+ value if low part is negative.
+ (FFETARGET_defaultIS_UGLY_ARGS): New macro.
+
+ * top.c (ffe_is_ugly_args_): New variable.
+ (ffe_decode_option): Handle -fugly-args and -fno-ugly-args.
+
+ * top.h (ffe_is_ugly_args_, ffe_is_ugly_args(),
+ ffe_set_is_ugly_args()): New variable and macros.
+
+Thu Feb 23 02:48:38 1995 Pedro A M Vazquez (vazquez@iqm.unicamp.br)
+
+ * g77.c (sys_errlist): Use const for __FreeBSD__ systems
+ as well.
+
+Wed Feb 22 13:33:43 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.10 released.
+
+ * CREDITS: Add Rick Niles.
+
+ * INSTALL: Note how to get around lack of makeinfo.
+
+ * Make-lang.in (f/proj.h): Remove # comment.
+
+ * Makefile.in (f/proj.h): Remove # comment.
+
+ * com.c (ffecom_expr_): Simplify opFUNCREF/opSUBRREF conversion.
+ (ffecom_sym_transform_): For whereGLOBAL and whereDUMMY
+ kindFUNCTION, use ffecom_tree_fun_type[][] only for non-constant
+ (non-statement-function) f2c functions.
+ (ffecom_init_0): ffecom_tree_fun_type[][] and _ptr_to_*_* are
+ really f2c-interface arrays, so use base type void for COMPLEX
+ (like CHARACTER).
+
+Tue Feb 21 19:01:18 1995 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in (f77.install-common): Expurgate the test for and
+ possible installation of f2c in line with elsewhere. Seems to have
+ been missing a semicolon anyhow!
+
+Tue Feb 21 11:45:25 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.9 released.
+
+ * Make-lang.in (f/proj.h): touch file to register update,
+ because the previous commands won't necessarily modify it.
+
+ * Makefile.in (f/proj.h): touch file to register update,
+ because the previous commands won't necessarily modify it.
+
+ * Makefile.in (f/str-*.h, f/str-*.j): Explicitly specify
+ output file names, so these targets go in build, not source,
+ directory.
+
+ * bits.c, bits.h: Switch to valid ANSI C replacement for
+ ARRAY_ZERO.
+
+ * com.c (ffecom_expr_): Add assignp arg to support ASSIGN better.
+ If assignp is TRUE, use different tree for FFEBLD_opSYMTER case.
+ (ffecom_sym_transform_assign_): New function.
+ (ffecom_expr_assign): New function.
+ (ffecom_expr_assign_w): New function.
+
+ * com.c (ffecom_f2c_make_type_): Do make_signed_type instead
+ of make_unsigned_type throughout.
+
+ * com.c (ffecom_finish_symbol_transform_): Expand scope of
+ commented-out code to probably produce faster compiler code.
+
+ * com.c (ffecom_gen_sfuncdef_): Push/pop calltemps so
+ COMPLEX works right.
+ Remove obsolete comment.
+
+ * com.c (ffecom_start_progunit_): If non-multi alt-entry
+ COMPLEX function, primary (static) entry point returns result
+ directory, not via extra arg -- to agree with ffecom_return_expr
+ and others.
+ Pretransform all symbols so statement functions are defined
+ before any code emitted.
+
+ * com.c (ffecom_finish_progunit): Don't posttransform all
+ symbols here -- pretransform them instead.
+
+ * com.c (ffecom_init_0): Don't warn about possible ASSIGN
+ crash, as this shouldn't happen now.
+
+ * com.c (ffecom_push_tempvar): Fix to handle temp vars
+ pushed while context is a statement (nested) function, and
+ add appropriate commentary.
+
+ * com.c (ffecom_return_expr): Check TREE_USED to determine
+ where return value is unset.
+
+ * com.h (struct _ffecom_symbol_): Add note about length_tree
+ now being used to keep tree for ASSIGN version of symbol.
+
+ * com.h (ffecom_expr_assign, ffecom_expr_assign_rw): New decls.
+ (error): Add this prototype for back-end function.
+
+ * fini.c (main): Grab input, output, and include names
+ directly off the command line instead of making the latter
+ two out of the first.
+
+ * lex.c: Improve tab handling for both fixed and free source
+ forms, and ignore carriage-returns on input, while generally
+ improving the code. ffelex_handle_tab_ has been renamed and
+ reinvented as ffelex_image_char_, among other things.
+
+ * malloc.c, malloc.h: Switch to valid ANSI C replacement for
+ ARRAY_ZERO, and kill the full number of bytes in pools and
+ areas.
+
+ * proj.h.in (ARRAY_ZERO, ARRAY_ZERO_SIZE): Remove.
+
+ * ste.c (ffeste_io_cilist_, ffeste_io_icilist_, ffeste_R838,
+ ffeste_R839): Issue diagnostic if a too-narrow variable used in an
+ ASSIGN context despite changes to this code and code in com.c.
+
+ * where.c, where.h: Switch to valid ANSI C replacement for
+ ARRAY_ZERO.
+
+Fri Feb 17 03:35:19 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.8 released.
+
+ * INSTALL: In quick-build case, list g77 target first so g77
+ gets installed. Also, explain that gcc gets built and installed
+ as well, even though this isn't really what we want (and maybe
+ we'll find a way around this someday).
+
+Fri Feb 17 02:35:41 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.7 released.
+
+ * Makefile.in (CONFIG_H, HCONFIG_H, TCONFIG_H, TM_H): Remove
+ ../ prefix in front of .h files, since they're in the cd.
+
+Fri Feb 17 01:50:48 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.6 released.
+
+Thu Feb 16 20:26:54 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * ../README.g77: Remove description of g77 as "not-yet-published".
+
+ * CREDITS: More changes.
+
+ * Make-lang.in (G77STAGESTUFF): Remove cktyps stuff.
+
+ * Makefile.in (CONFIG_H, HCONFIG_H, TCONFIG_H, TM_H): Don't
+ prefix gcc dir with $(srcdir) since these don't live there,
+ they are created in the build dir by gcc's configure. Add
+ a note explaining what these macros are about.
+ Update dependencies via deps-kinda.
+
+ * README.NEXTSTEP: Credit Toon, and per his request, add his
+ email address.
+
+ * com.h (FFECOM_DETERMINE_TYPES): #include "config.j".
+
+ * config.j, convert.j, flags.j, hconfig.j, rtl.j, tconfig.j,
+ tm.j, tree.j: Don't #include if already done.
+
+ * convert.j: #include "tree.j" first, as convert.h clearly depends
+ on trees being defined.
+
+ * rtl.j: #include "config.j" first, since there's some stuff
+ in rtl.h that assumes it has been #included.
+
+ * tree.j: #include "config.j" first, or real.h makes inconsistent
+ decision about return type of ereal_atof, leading to bugs, and
+ because tree.h/real.h assume config.h already included.
+
+Wed Feb 15 14:40:20 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.5 released.
+
+ * Copyright notices updated to be FSF-style.
+
+ * INSTALL: Some more clarification regarding building just f77.
+
+ * Make-lang.in (F77_SRCS): Update wrt changing some .h to .j.
+ (install-libf77): Fix typo in new parenthetical note.
+
+ * Makefile.in (f/*.o): Update.
+ (CONFIG_H, CONVERT_H, FLAGS_H, GLIMITS_H, HCONFIG_H, RTL_H,
+ TCONFIG_H, TM_H, TREE_H): Update/new symbols.
+ (deps-kinda): More fixes wrt changing some .h to .j.
+ Document and explain this rule a bit better.
+ Accommodate changes in output of gcc -MM.
+
+ * *.h, *.c: Change #include's so proj.h not assumed to #include
+ malloc.h or config.h (now config.j), and so new .j files are
+ used instead of old .h ones.
+
+ * com.c (ffecom_init_0): Use FLOAT_TYPE_SIZE for f2c's
+ TYLONG/TYLOGICAL type codes, to get g77 working on Alpha.
+
+ * com.h: Make all f2c-related integral types "int", not "long
+ int".
+
+ * config.j, convert.j, flags.j, glimits.j, hconfig.j, rtl.j,
+ tconfig.j, tm.j, tree.j: New files wrapping around gbe
+ .h files.
+
+ * config.h, convert.h, flags.h, glimits.h, hconfig.h, rtl.h,
+ tconfig.h, tm.h, tree.h: Deleted so new .j files
+ can #include the gbe files directly, instead of using "../",
+ and thus do better with various kinds of builds.
+
+ * proj.h: Delete unused NO_STDDEF and related stuff.
+
+Tue Feb 14 08:28:08 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * BUGS: Remove item #12, cross-compiling & autoconf scripts
+ reportedly expected to work properly (according to d.love).
+
+ * INSTALL: Add explanation of d.love's patch to config-lang.in.
+ Add explanation of how to install just g77 when gcc already installed.
+ Add note about usability of "-Wall". Add note about bug-
+ reporting.
+
+ * Make-lang.in ($(srcdir)/f/conf-proj): Add comment about why
+ conf-proj.out.
+ (install-libf77): Echo parenthetical note to user about how to do
+ just the (aborted) libf2c installation.
+ (deps-kinda): Update to work with new configuration/build stuff.
+
+ * bad.c (ffebad_finish): Put capitalized "warning:" &c message
+ as prefix on any diagnostic without pointers into source.
+
+ * bad.def (FFEBAD_TOO_BIG_INIT): Add this warning message.
+
+ * config-lang.in: Add Dave Love's patch to catch case where
+ back-end patches not applied and abort configuration.
+
+ * data.c (ffedata_gather_, ffedata_value_): Warn when about
+ to initialize a large aggregate area, due to design flaw resulting
+ in too much time/space used to handle such cases.
+ Use COMMON area name, and first notice of symbol, for multiple-
+ initialization diagnostic, instead of member symbol and unknown
+ location.
+ (FFEDATA_sizeTOO_BIG_INIT_): New macro per above.
+
+Mon Feb 13 13:54:26 1995 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in (F77_SRCS): Use $(srcdir)/f/proj.h.in, not
+ $(srcdir)/f/proj.h for build outside srcdir.
+
+Sun Feb 12 13:37:11 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * ../README.g77: Clarify procedures for unpacking, add asterisks
+ to mark important things the user must do.
+
+ * Fix dates in/add dates to ../README.g77, BUGS, CREDITS, DOC,
+ INSTALL, PROJECTS, README.
+
+Sun Feb 12 00:26:10 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.4 released.
+
+ * Make-lang.in (f/proj.h): Reproduce this rule here from
+ Makefile.in.
+ ($(srcdir)/f/conf-proj): Put autoconf's stdout in temp file
+ conf-proj.out, then mv to conf-proj only if successful, so
+ conf-proj not touched if autoconf not installed.
+
+ * Makefile.in ($(srcdir)/conf-proj): See Make-lang.in's similar
+ rule.
+
+Sat Feb 11 20:56:02 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * BUGS: Clarify some bugs.
+
+ * DOC: Many improvements and fixes.
+
+ * README: Move bulk of text, edited, to ../README.g77, and
+ replace with pointer to that file.
+
+ * com.c (ffecom_init_0): Comment out warning about sizeof(ftnlen)
+ as per ste.c change. Add text about ASSIGN to help user understand
+ what is being warned about.
+
+ * conf-proj.in: Fix typos in comments.
+
+ * proj.h.in: Add ARRAY_ZERO_SIZE to parallel malloc.h's version,
+ in case it proves to be needed.
+
+ * ste.c: Comment out assertions requiring sizeof(ftnlen) >=
+ sizeof(char *), in the hopes that overflow will never happen.
+ (ffeste_R838): Change assertion to fatal() with at least
+ partially helpful message.
+
+Sat Feb 11 12:38:00 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * com.c (ffecom_vardesc_): Crash if typecode is -1.
+
+ * ste.c (ffeste_io_dolio_): Crash if typecode is -1.
+
+Sat Feb 11 09:51:57 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * ste.c: In I/O code tests for item arrayness, sort of revert
+ to much earlier code that tests original exp, but also check
+ in newer way just in case. Newer way alone treated FOO(1:40)
+ as an array, not sure why older way alone didn't work, but I
+ think maybe it was when diagnosed code was involved, and
+ since there are now checks for error_mark_node, maybe the old
+ way alone would work. But better to be safe; both original
+ ffebld exp _and_ the transformed tree must indicate an array
+ for the size-determination code to be used, else just 1/2 elements
+ assumed. And this text is for EMACS: (foo at bar).
+
+Fri Feb 10 11:05:50 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * ste.c: In many cases, surround statement-expansion code
+ with ffecom_push_calltemps () and ffecom_pop_calltemps ()
+ so COMPLEX-returning functions can have temporaries pushed
+ in "auto-pop" mode and have them auto-popped at the end of
+ the statement.
+
+Wed Feb 8 14:35:10 1995 Dave Love <d.love@dl.ac.uk>
+
+ * runtime/f2c.h.in (ftnlen, ftnint): Make same size as integer.
+
+ * runtime/libI77/err.c (f_init): Thinko in MISSING_FILE_ELEMS
+ conditional.
+ * runtime/libI77/wrtfmt.c (mv_cur): Likewise.
+ * runtime/libI77/wsfe.c (x_putc): Likewise.
+
+ * runtime/libF77/signal_.c (signal_): Return 0 (this is a
+ subroutine).
+
+ * Makefile.in (f/proj.h): Depend on com.h.
+ * Make-lang.in (include/f2c.h): Likewise (and proj.h).
+ (install-libf77): Also install f2c.h.
+
+ * runtime/libI77/Makefile.in (*.o): Add f2c.h dependency.
+ * runtime/libF77/Makefile.in: Likewise.
+
+Wed Feb 8 13:56:47 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * stc.c (ffestc_R501_item): Don't reset kind/where to NONE when
+ setting basictype/kindtype info for symbol, or especially
+ its function/result twin, because kind/where might not be NONE.
+
+Tue Feb 7 14:47:26 1995 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in (include/f2c.h:): Set shell variable src more
+ robustly (independent of whether srcdir is relative or absolute).
+ * Makefile.in (f/proj.h:): Likewise.
+
+ * conf-proj.in: Check need for LAME_ASSERT. Fix indentation in
+ check for LAME_STDIO (cosmetic only with ANSI C).
+
+ * com.h: Extra ...SIZE stuff taken from com.c.
+
+ * com.c (FFECOM_DETERMINE_TYPES): Define before including com.h.
+ (BITS_PER_WORD etc.) Remove and use conditional definitions to com.h.
+
+ * runtime/configure.in: #define FFECOM_DETERMINE_TYPES for com.h in
+ f2c type determination.
+
+ * tm.h: Remove (at least pro tem) because of relative path and use
+ top-level one.
+
+ * Make-lang.in (include/f2c.h:): Set shell variable src more
+ robustly (independent of whether srcdir is relative or absolute).
+ * Makefile.in (f/proj.h:): Likewise.
+
+Mon Feb 6 19:58:32 1995 Dave Love <d.love@dl.ac.uk>
+
+ * g77.c (append_arg): Use K&R declaration for, e.g. SunOS4 build.
+
+Fri Feb 3 20:33:14 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * g77.c (main): Treat -l like filename in terms of -x handling.
+ Rewrite arglist mechanism for ease of maintenance.
+ Make sure every -lf2c is followed by -lm and vice versa.
+
+ * Make-lang.in: Put complete list of sources in F77_SRCS def
+ so changing a .h file, for example, causes rebuild.
+
+ * Makefile.in: Change test for nextstep to m68k-next-nextstep* so
+ all versions of nextstep on m68k get the necessary flag.
+
+Fri Feb 3 19:10:32 1995 Dave Love <d.love@dl.ac.uk>
+
+ * INSTALL: Note about possible conflict with existing libf2c.a and
+ f2c.h.
+
+ * Make-lang.in (f77.distclean): Tidy and move deletion of
+ f/config.cache to mostlyclean.
+ (install-libf77): Test for $(libdir)/libf2c.* and barf if found
+ unless F2CLIBOK defined.
+
+ * runtime/Makefile.in (all): Change path to include directory (and
+ elsewhere).
+ (INCLUDES): Remove (unused/misleading).
+ (distclean): Include f2c.h.
+ (clean): Include config.cache.
+
+ * runtime/libF77/Makefile.in (.SUFFIXES): Correct typo.
+ (ALL_CFLAGS) Fix up include search path to find f2c.h in top level
+ includes always.
+ (all): Depend on f2c.h.
+ * runtime/libI77/Makefile.in (.SUFFIXES): Likewise.
+
+Thu Feb 2 17:17:06 1995 Dave Love <d.love@dl.ac.uk>
+
+ * INSTALL: Note about --srcdir and GNU make.
+
+ * runtime/f2c.h.in (Pad_UDread, ALWAYS_FLUSH): Reomve the #defines
+ per below.
+
+ * runtime/configure.in (Pad_UDread, ALWAYS_FLUSH): Define these
+ here, not in f2c.h as they'r eonly relevant for building.
+ * runtime/configure: Regenerated.
+
+ * config-lang.in: Warn about using GNU make outside source tree
+ since I can't get Irix5 or SunOS4 makes to work in this case.
+
+ * Makefile.in (VPATH): Don't set it here.
+ (srcdir): Make it the normal `.' (overridden) at top level.
+ (all.indirect): New dependency `dircheck'.
+ (f771): Likewise
+ (dircheck): New target for foolproofing.
+ (f/proj.h:): Change finding source.
+ (CONFIG_H): Don't use this as the relative path in the include loses
+ f builddir != srcdir.
+
+ * config.h: Remove per CONFIG_H change above.
+
+ * Make-lang.in (F77_FLAGS_TO_PASS): Remove GCC_FOR_TARGET.
+ (f771:): Pass VPATH, srcdir to sub-make.
+ (f/Makefile:): New target.
+ (stmp-int-hdrs): new variable for cheating build.
+ (f77-runtime:): Alter GCC_FOR_TARGET treatment.
+ (include/f2c.h f/runtime/Makefile:) Likewise.
+ (f77-runtime-unsafe:): New (cheating) target.
+
+Thu Feb 2 12:09:51 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * BUGS: Update regarding losing EQUIVALENCE members in -g, and
+ regarding RS/6000 problems in the back end.
+
+ * CREDITS: Make some changes as requested.
+
+ * com.c (ffecom_member_trunk_): Remove unused static variable.
+ (ffecom_finish_symbol_transform_): Improve comments.
+ (ffecom_let_char_): Fix size of temp address-type var.
+ (ffecom_member_phase2_): Try fixing problem fixed by change
+ to ffecom_transform_equiv_ (f_m_p2_ function currently not used).
+ (ffecom_transform_equiv_): Remove def of unused static variable.
+ Comment-out use of ffecom_member_phase2_, until problems with
+ back end fixed.
+ (ffecom_push_tempvar): Fix assertion to not crash okay code.
+
+ * com.h: Remove old, commented-out code.
+ Add prototype for warning() in back end.
+
+ * ste.c (ffeste_io_dofio_, ffeste_io_dolio_, ffeste_io_douio_,
+ ffeste_io_icilist_): Check correct type of variable for arrayness.
+
+Sun Jan 29 14:41:42 1995 Dave Love <d.love@dl.ac.uk>
+
+ * BUGS: Remove references to my configure bugs; add another.
+
+ * runtime/Makefile.in (AR_FLAGS): Provide default value.
+
+ * runtime/f2c.h.in (integer, logical): Take typedefs from
+ F2C_INTEGER configuration parameter again.
+ (NON_UNIX_STDIO): don't define it.
+
+ * runtime/configure.in: Bring type checks for f2c.h in line with
+ com.h.
+ (MISSING_FILE_ELEMS): New variable to determine whether the relevant
+ elements of the FILE struct exist, independent of NON_UNIX_STDIO.
+ * runtime/libI77/{err,wrtfmt,wsfe}.c (MISSING_FILE_ELEMS): Use new
+ parameter.
+
+ * config-lang.in: Comment out more of f2c rules (c.f. Make-lang.in).
+ (This stuff is relevant iff you gave configure --enable-f2c.)
+ Create f/runtime directory tree iff not building in source
+ directory.
+
+ * Makefile.in (srcdir): Append slash so we get the right value when
+ not building in the source directory. This is a consequence of not
+ building the `f' sources in `f'.
+ (VPATH): Override configure's value for reasons above.
+ (f/proj.h f/conf-proj): New rules to build proj.h by
+ autoconfiguration.
+
+ * proj.h: Rename to proj.h.in for autoconfiguration.
+ * proj.h.in: New as above.
+ * conf-proj conf-proj.in: New files for autoconfiguration.
+
+ * Make-lang.in (include/f2c.h f/runtime/Makefile:): Change the order
+ of setting the sh variables so that the right GCC_FOR_TARGET is
+ used.
+ (f77.*clean:) Add products of new configuration files and make sure
+ all the *clean targets do something (unlike the ones in
+ cp/Make-lange.in).
+
+ * com.h (FFECOM_f2cINTEGER, FFECOM_f2cLOGICAL): Define as long or
+ int appropriately to ensure sizeof(real) == sizeof(integer).
+
+ * PROJECTS: Library section.
+
+ * runtime/libI77/endfile.c: Don't #include sys/types.h conditional
+ on NON_UNIX_STDIO since rawio.h needs size_t.
+ * runtime/libI77/uio.c: #include <sys/types.h> for size_t if not
+ KR_headers.
+
+Wed Jan 25 03:31:51 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.3 released.
+
+ * INSTALL: Revise.
+
+ * Make-lang.in: Comment out rules for building f2c itself (f/f2c/).
+
+ * README: Revise.
+
+ * com.c (ffecom_init_0): Warn if ftnlen or INTEGER not big enough
+ to hold a char *.
+
+ * gbe/2.6.2.diff: Update.
+
+Mon Jan 23 17:10:49 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * TODO: Remove.
+ BUGS: New file.
+ PROJECTS: New file.
+ CREDITS: New file.
+
+ * cktyps*: Remove.
+ Make-lang.in: Remove cktyps stuff.
+ Makefile.in: Remove cktyps stuff.
+
+ * DOC: Add info on changes for 0.5.3.
+
+ * bad.c: Put "warning:" &c on diagnostic messages.
+ Don't output informational messages if warnings disabled.
+
+Thu Jan 19 12:38:13 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * g77.c: Avoid putting out useless "-xnone -xf77" pairs so
+ larger command lines can be accommodated.
+ Recognize both `-xlang' and `-x lang'.
+ Recognize `-xnone' and `-x none' to mean what it does, instead
+ of treating "none" as any other language.
+ Some minor, slight improvements in the way args are handled
+ (hopefully for clearer, more maintainable code), including
+ consistency checks on arg count just in case.
+
+Wed Jan 18 16:41:57 1995 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * DOC: Explain -fautomatic better.
+
+ * INSTALL: Describe libf2c.a better.
+
+ * Make-lang.in, Makefile.in: Build f771 &c with gcc/ as cd instead
+ of gcc/f/ so debugging info is better (source file tracking).
+ Add new source file type.c.
+
+ * Makefile.in: For nextstep3, link f771 with -segaddr __DATA
+ 6000000. Fix typo. Change deps-kinda target to handle building
+ from gcc/. Update dependencies.
+
+ * bld-op.def, bld.h, bld.c: Remove opBACKEND and all related
+ stuff.
+ Remove consistency tests that cause compiler warnings.
+
+ * cktyps.c: Remove all typing checking.
+
+ * com-rt.def: Change all rttypeFLOAT_ intrinsics to rttypeDOUBLE_,
+ to precisely match how they're declared in libf2c.
+
+ * com.h, com.c: Revise to more elegantly track related stuff
+ in the version of f2c.h used to build libf2c.
+
+ * com.c: Increase FFECOM_sizeMAXSTACKITEM, and if 0 or undefined
+ when checked to determine where to put entity, treat as infinite.
+ Rewrite temporary mechanism to be based on trees instead of
+ ffeinfo stuff, and make it much simpler. Change interface
+ accordingly.
+ Fixes to better track types of things, make appropriate
+ conversions, etc. E.g. when making an arg for a libf2c
+ function, make sure it's of the right type (such as ftnlen).
+ Delete opBACKEND transformation code.
+ (ffecom_init_0): Smoother initialization of types, especially
+ paying attention to using consistent rules for making INTEGER,
+ REAL, DOUBLE PRECISION, etc., and for deciding their "*N"
+ and kind values that will work across all g77 platforms.
+ No longer require per-target configuration info in target.h
+ or config/*/*; use new type module to store size, alignment.
+ (ffecom_member_phase2): Declare COMMON/EQUIVALENCE group members
+ so debugger sees them.
+ (ffecom_finish_progunit): Transform all symbols in program unit,
+ so -g will show they all exist.
+
+ * expr.c (ffeexpr_collapse_substr): Handle strange substring
+ range values.
+
+ * info.h, info.c: Provide connection to new type module.
+ Remove tests that yield compiler warnings.
+
+ * intrin.c (ffeintrin_is_intrinsic): Properly handle deleted
+ intrinsic.
+
+ * lex.c (ffelex_file_fixed): Remove redundant/buggy code.
+
+ * stc.c (ffestc_kindtype_kind_, ffestc_kindtype_star_): Replace
+ boring switch stmt with simple call to new type module. This
+ sort of thing is a reason to get up in the morning.
+
+ * ste.c: Update to handle new interface for
+ ffecom_push/pop_tempvar.
+ Fixes to better track types of things.
+ Fixes to not crash for certain diagnosed constructs.
+ (ffeste_begin_iterdo_): Check only constants for overflow to avoid
+ spurious diagnostics.
+ Don't convert larger integer (say, INTEGER*8) to canonical integer
+ for iteration count.
+
+ * stw.h: Track DO iteration count temporary variable.
+
+ * symbol.c: Remove consistency tests that cause compiler warnings.
+
+ * target.c (ffetarget_aggregate_info): Replace big switch with
+ little call to new type module.
+ (ffetarget_layout): Remove consistency tests that cause
+ compiler warnings.
+ (ffetarget_convert_character1_typeless): Pick up length of
+ typeless type from new type module.
+
+ * target.h: Crash build if target float bit pattern cannot be
+ precisely determined.
+ Remove all the type cruft now determined by ffecom_init_0
+ at invocation time and maintained in new type module.
+ Put casts on second arg of all REAL_VALUE_TO_TARGET_DOUBLE
+ uses so compiler warnings avoided (requires target float bit
+ pattern to be precisely determined, hence code to crash build).
+
+ * top.c: Add inits/terminates for new type module.
+
+ * type.h, type.c: New module.
+
+ * gbe/2.6.2.diff: Remove all patches to files in gcc/config/
+ directory and its subdirectories.
+
+Mon Jan 9 19:23:25 1995 Dave Love <d.love@dl.ac.uk>
+
+ * com.h (FFECOM_F2C_INTEGER_TYPE_NODE): Define and use instead of
+ long_integer_type_node where appropriate.
+
+Tue Jan 3 14:56:18 1995 Dave Love <d.love@dl.ac.uk>
+
+ * com.h: Make ffecom_f2c_logical_type_node long, consistent with
+ integer.
+
+Fri Dec 2 20:07:37 1994 Dave Love <d.love@dl.ac.uk>
+
+ * config-lang.in (stagestuff): Add f2c conditionally.
+ * Make-lang.in: Add f2c and related targets.
+ * f2c: Add the directory.
+
+Fri Nov 25 22:17:26 1994 Dave Love <d.love@dl.ac.uk>
+
+ * Makefile.in (FLAGS_TO_PASS): pass $(CROSS)
+ * Make-lang.in: more changes to runtime targets
+
+Thu Nov 24 18:03:21 1994 Dave Love <d.love@dl.ac.uk>
+
+ * Makefile.in (FLAGS_TO_PASS): define for sub-makes
+
+ * g77.c (main): change f77-cpp-output to f77-cpp-input (.F files)
+
+Wed Nov 23 15:22:53 1994 Dave Love <d.love@dl.ac.uk>
+
+ * bad.c (ffebad_finish): kluge to fool emacs19 into finding errors:
+ add trailing space to <file>:<line>:
+
+Tue Nov 22 11:30:50 1994 Dave Love <d.love@dl.ac.uk>
+
+ * runtime/libF77/signal_.c (RETSIGTYPE): added
+
+Mon Nov 21 13:04:13 1994 Dave Love <d.love@dl.ac.uk>
+
+ * Makefile.in (compiler): add runtime
+
+ * config-lang.in (stagestuff): add libf2c.a to stagestuff
+
+ * Make-lang.in:
+ G77STAGESTUFF <- MORESTAGESTUFF
+ f77-runtime: new target, plus supporting ones
+
+ * runtime: add the directory, containing libI77, libF77 and autoconf
+ stuff
+
+ * g++.1: remove
+
+ * g77.1: minor fixes
+
+Thu Nov 17 15:18:05 1994 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.2 released.
+
+ * bad.def: Modify wording of FFEBAD_UNIMPL_STMT to indicate
+ that it covers a wide array of possible problems (that, someday,
+ should be handled via separate diagnostics).
+
+ * lex.c: Allow $ in identifiers if -fdollar-ok.
+ * top.c: Support -fdollar-ok.
+ * top.h: Support -fdollar-ok.
+ * target.h: Support -fdollar-ok.
+ * DOC: Describe -fdollar-ok.
+
+ * std.c (ffestd_R1229_finish): Fix bug so stand-alone build works.
+ * ste.c (ffeste_R819A): Fix bug so stand-alone build works.
+
+ * Make: Improvements for stand-alone build.
+
+ * Makefile.in: Fix copyright text at top of file.
+
+ * LINK, SRCS, UNLINK: Removed. Not particularly useful now that
+ g77 sources live in their own subdirectory.
+
+ * g77.c (main): Cast arg to bzero to avoid warning. (This is
+ identical to Kenner's fix to cp/g++.c.)
+
+ * gbe/: New subdirectory, to contain .diff files for various
+ versions of the GNU CC back end.
+
+ * gbe/README: New file.
+ * gbe/2.6.2.diff: New file.
+
+Tue Nov 8 10:23:10 1994 Dave Love <d.love@dl.ac.uk>
+
+ * Make-lang.in: don't install as f77 as well as g77 to avoid
+ confusion with system's compiler (especially while testing)
+
+ * g77.c (main): use -lf2c and -lm; fix sense of test for .f/.F files
+
+Fri Oct 28 09:45:00 1994 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.1 released.
+
+ * gcc.c: Invoke f771 instead of f-771.
+
+Fri Oct 28 02:00:44 1994 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Version 0.5.0 released.
+
+Fri Oct 14 15:03:35 1994 Craig Burley (burley@gnu.ai.mit.edu)
+
+ * Makefile.in: Handle the Fortran-77 front-end in a subdirectory.
+ * f-*: Move Fortran-77 front-end to f/*.
diff --git a/contrib/gcc/f/Make-lang.in b/contrib/gcc/f/Make-lang.in
new file mode 100644
index 0000000..38712fd
--- /dev/null
+++ b/contrib/gcc/f/Make-lang.in
@@ -0,0 +1,472 @@
+# Top level makefile fragment for GNU Fortran. -*-makefile-*-
+# Copyright (C) 1995-1998 Free Software Foundation, Inc.
+
+#This file is part of GNU Fortran.
+
+#GNU Fortran 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, or (at your option)
+#any later version.
+
+#GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+#the Free Software Foundation, 59 Temple Place - Suite 330,
+#Boston, MA 02111-1307, USA.
+
+# This file provides the language dependent support in the main Makefile.
+# Each language makefile fragment must provide the following targets:
+#
+# foo.all.build, foo.all.cross, foo.start.encap, foo.rest.encap,
+# foo.info, foo.dvi,
+# foo.install-normal, foo.install-common, foo.install-info, foo.install-man,
+# foo.uninstall, foo.distdir,
+# foo.mostlyclean, foo.clean, foo.distclean, foo.extraclean,
+# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
+#
+# where `foo' is the name of the language.
+#
+# It should also provide rules for:
+#
+# - making any compiler driver (eg: g++)
+# - the compiler proper (eg: cc1plus)
+# - define the names for selecting the language in LANGUAGES.
+#
+# $(srcdir) must be set to the gcc/ source directory (not gcc/f/).
+#
+# Actual name to use when installing a native compiler.
+G77_INSTALL_NAME = `t='$(program_transform_name)'; echo g77 | sed $$t`
+
+# Actual name to use when installing a cross-compiler.
+G77_CROSS_NAME = `t='$(program_transform_cross_name)'; echo g77 | sed $$t`
+#
+# Define the names for selecting f77 in LANGUAGES.
+# Note that it would be nice to move the dependency on g77
+# into the F77 rule, but that needs a little bit of work
+# to do the right thing within all.cross.
+F77 f77: f771$(exeext)
+
+# Tell GNU make to ignore these if they exist.
+.PHONY: F77 f77 f77.all.build f77.all.cross \
+ f77.start.encap f77.rest.encap f77.info f77.dvi \
+ f77.install-normal \
+ f77.install-common f77.install-info f77.install-man \
+ f77.uninstall f77.mostlyclean f77.clean f77.distclean \
+ f77.extraclean f77.maintainer-clean f77.distdir f77.rebuilt \
+ f77.stage1 f77.stage2 f77.stage3 f77.stage4
+
+g77.c: $(srcdir)/gcc.c
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ if [ -f lang-f77 ]; then \
+ rm -f g77.c; \
+ $(LN_S) $(srcdir)/gcc.c g77.c; \
+ else true; fi
+
+g77spec.o: $(srcdir)/f/g77spec.c $(srcdir)/f/version.h
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ if [ -f lang-f77 ]; then \
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(srcdir)/f/g77spec.c; \
+ else true; fi
+
+g77version.o: $(srcdir)/f/version.c
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ if [ -f lang-f77 ]; then \
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -o g77version.o \
+ $(srcdir)/f/version.c; \
+ else true; fi
+
+# N.B.: This is a copy of the gcc.o rule, with -DLANG_SPECIFIC_DRIVER added.
+# It'd be nice if we could find an easier way to do this---rather than have
+# to track changes to the toplevel gcc Makefile as well.
+# We depend on g77.c last, to make it obvious where it came from.
+g77.o: $(CONFIG_H) multilib.h config.status $(lang_specs_files) g77.c
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ if [ -f lang-f77 ]; then \
+ $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $(DRIVER_DEFINES) \
+ -DLANG_SPECIFIC_DRIVER -c g77.c; \
+ else true; fi
+
+# Create the compiler driver for g77.
+g77$(exeext): g77.o g77spec.o g77version.o version.o choose-temp.o pexecute.o prefix.o mkstemp.o \
+ $(LIBDEPS) $(EXTRA_GCC_OBJS)
+ if [ -f lang-f77 ]; then \
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ g77.o g77spec.o g77version.o \
+ version.o choose-temp.o pexecute.o prefix.o mkstemp.o $(EXTRA_GCC_OBJS) $(LIBS); \
+ else true; fi
+
+# Create a version of the g77 driver which calls the cross-compiler.
+g77-cross$(exeext): g77$(exeext)
+ if [ -f lang-f77 ]; then \
+ rm -f g77-cross$(exeext); \
+ cp g77$(exeext) g77-cross$(exeext); \
+ else true; fi
+
+F77_SRCS = \
+ $(srcdir)/f/assert.j \
+ $(srcdir)/f/bad.c \
+ $(srcdir)/f/bad.def \
+ $(srcdir)/f/bad.h \
+ $(srcdir)/f/bit.c \
+ $(srcdir)/f/bit.h \
+ $(srcdir)/f/bld-op.def \
+ $(srcdir)/f/bld.c \
+ $(srcdir)/f/bld.h \
+ $(srcdir)/f/com-rt.def \
+ $(srcdir)/f/com.c \
+ $(srcdir)/f/com.h \
+ $(srcdir)/f/config.j \
+ $(srcdir)/f/convert.j \
+ $(srcdir)/f/data.c \
+ $(srcdir)/f/data.h \
+ $(srcdir)/f/equiv.c \
+ $(srcdir)/f/equiv.h \
+ $(srcdir)/f/expr.c \
+ $(srcdir)/f/expr.h \
+ $(srcdir)/f/fini.c \
+ $(srcdir)/f/flags.j \
+ $(srcdir)/f/glimits.j \
+ $(srcdir)/f/global.c \
+ $(srcdir)/f/global.h \
+ $(srcdir)/f/hconfig.j \
+ $(srcdir)/f/implic.c \
+ $(srcdir)/f/implic.h \
+ $(srcdir)/f/input.j \
+ $(srcdir)/f/info-b.def \
+ $(srcdir)/f/info-k.def \
+ $(srcdir)/f/info-w.def \
+ $(srcdir)/f/info.c \
+ $(srcdir)/f/info.h \
+ $(srcdir)/f/intrin.c \
+ $(srcdir)/f/intrin.def \
+ $(srcdir)/f/intrin.h \
+ $(srcdir)/f/lab.c \
+ $(srcdir)/f/lab.h \
+ $(srcdir)/f/lex.c \
+ $(srcdir)/f/lex.h \
+ $(srcdir)/f/malloc.c \
+ $(srcdir)/f/malloc.h \
+ $(srcdir)/f/name.c \
+ $(srcdir)/f/name.h \
+ $(srcdir)/f/output.j \
+ $(srcdir)/f/parse.c \
+ $(srcdir)/f/proj.c \
+ $(srcdir)/f/proj.h \
+ $(srcdir)/f/rtl.j \
+ $(srcdir)/f/src.c \
+ $(srcdir)/f/src.h \
+ $(srcdir)/f/st.c \
+ $(srcdir)/f/st.h \
+ $(srcdir)/f/sta.c \
+ $(srcdir)/f/sta.h \
+ $(srcdir)/f/stb.c \
+ $(srcdir)/f/stb.h \
+ $(srcdir)/f/stc.c \
+ $(srcdir)/f/stc.h \
+ $(srcdir)/f/std.c \
+ $(srcdir)/f/std.h \
+ $(srcdir)/f/ste.c \
+ $(srcdir)/f/ste.h \
+ $(srcdir)/f/storag.c \
+ $(srcdir)/f/storag.h \
+ $(srcdir)/f/stp.c \
+ $(srcdir)/f/stp.h \
+ $(srcdir)/f/str-1t.fin \
+ $(srcdir)/f/str-2t.fin \
+ $(srcdir)/f/str-fo.fin \
+ $(srcdir)/f/str-io.fin \
+ $(srcdir)/f/str-nq.fin \
+ $(srcdir)/f/str-op.fin \
+ $(srcdir)/f/str-ot.fin \
+ $(srcdir)/f/str.c \
+ $(srcdir)/f/str.h \
+ $(srcdir)/f/sts.c \
+ $(srcdir)/f/sts.h \
+ $(srcdir)/f/stt.c \
+ $(srcdir)/f/stt.h \
+ $(srcdir)/f/stu.c \
+ $(srcdir)/f/stu.h \
+ $(srcdir)/f/stv.c \
+ $(srcdir)/f/stv.h \
+ $(srcdir)/f/stw.c \
+ $(srcdir)/f/stw.h \
+ $(srcdir)/f/symbol.c \
+ $(srcdir)/f/symbol.def \
+ $(srcdir)/f/symbol.h \
+ $(srcdir)/f/system.j \
+ $(srcdir)/f/target.c \
+ $(srcdir)/f/target.h \
+ $(srcdir)/f/tconfig.j \
+ $(srcdir)/f/tm.j \
+ $(srcdir)/f/top.c \
+ $(srcdir)/f/top.h \
+ $(srcdir)/f/toplev.j \
+ $(srcdir)/f/tree.j \
+ $(srcdir)/f/type.c \
+ $(srcdir)/f/type.h \
+ $(srcdir)/f/version.c \
+ $(srcdir)/f/version.h \
+ $(srcdir)/f/where.c \
+ $(srcdir)/f/where.h
+
+f771$(exeext): $(P) $(F77_SRCS) $(LIBDEPS) stamp-objlist
+ touch lang-f77
+ cd f; $(MAKE) $(FLAGS_TO_PASS) \
+ HOST_CC="$(HOST_CC)" HOST_CFLAGS="$(HOST_CFLAGS)" HOST_CPPFLAGS="$(HOST_CPPFLAGS)" \
+ ../f771$(exeext)
+
+#
+# Build hooks:
+
+f77.all.build: g77$(exeext)
+f77.all.cross: g77-cross$(exeext)
+f77.start.encap: g77$(exeext)
+f77.rest.encap:
+
+f77.info: f/g77.info
+f77.dvi: f/g77.dvi
+
+# g77 documentation.
+f/g77.info: $(srcdir)/f/g77.texi $(srcdir)/f/bugs.texi \
+ $(srcdir)/f/g77install.texi $(srcdir)/f/news.texi \
+ $(srcdir)/f/intdoc.texi
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ if [ -f lang-f77 ]; then \
+ rm -f $(srcdir)/f/g77.info-*; \
+ $(MAKEINFO) -I$(srcdir)/f -o f/g77.info $(srcdir)/f/g77.texi; \
+ else true; fi
+
+f/g77.dvi: $(srcdir)/f/g77.texi $(srcdir)/f/bugs.texi \
+ $(srcdir)/f/g77install.texi $(srcdir)/f/news.texi \
+ $(srcdir)/f/intdoc.texi
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+# `tex2dvi' was used below, but the Texinfo 3.12 one won't work properly
+# with the include files from $(srcdir). This use of TEXINPUTS may not
+# be universally valid. `$(TEX)' should be used if it gets defined in
+# gcc/Makefile.in.
+ if [ -f lang-f77 ]; then \
+ TEXINPUTS=$(srcdir)/f:$$TEXINPUTS tex $(srcdir)/f/g77.texi; \
+ texindex g77.??; \
+ TEXINPUTS=$(srcdir)/f:$$TEXINPUTS tex $(srcdir)/f/g77.texi; \
+ mv g77.dvi f; \
+ else true; fi
+
+# This dance is all about producing accurate documentation for g77's
+# intrinsics with minimum fuss. f/ansify appends "\n\" to C strings
+# so ANSI C compilers can compile f/intdoc.h -- gcc can compile f/intdoc.in
+# directly, if f/intdoc.c #include'd that, but we don't want to force
+# people to install gcc just to build the documentation. We use the
+# C format for f/intdoc.in in the first place to allow a fairly "free",
+# but widely known format for documentation -- basically anyone who knows
+# how to write texinfo source and enclose it in C constants can handle
+# it, and f/ansify allows them to not even end lines with "\n\". So,
+# essentially, the C preprocessor and compiler are used to enter the
+# document snippets into a data base via name lookup, rather than duplicating
+# that kind of code here. And we use f/intdoc.c instead of straight
+# texinfo in the first place so that as much information as possible
+# contained in f/intrin.def can be inserted directly and reliably into
+# the documentation. That's better than replicating it, because it
+# reduces the likelihood of discrepancies between the docs and the compiler
+# itself, which uses f/intrin.def; in fact, many bugs in f/intrin.def have
+# been found only upon reading the documentation that was automatically
+# produced from it.
+$(srcdir)/f/intdoc.texi: f/intdoc.c f/intdoc.in f/ansify.c f/intrin.def f/intrin.h
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ if [ -f lang-f77 ]; then \
+ $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $(INCLUDES) \
+ `echo $(srcdir)/f/ansify.c | sed 's,^\./,,'` -o f/ansify; \
+ f/ansify < $(srcdir)/f/intdoc.in > f/intdoc.h0 $(srcdir)/f/intdoc.in; \
+ $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) $(INCLUDES) -I./f \
+ `echo $(srcdir)/f/intdoc.c | sed 's,^\./,,'` -o f/intdoc; \
+ f/intdoc > $(srcdir)/f/intdoc.texi; \
+ rm f/intdoc f/ansify f/intdoc.h0; \
+ else true; fi
+
+$(srcdir)/f/BUGS: f/bugs0.texi f/bugs.texi
+ cd $(srcdir)/f; $(MAKEINFO) -D BUGSONLY --no-header --no-split \
+ --no-validate -o BUGS bugs0.texi
+
+$(srcdir)/f/INSTALL: f/install0.texi f/g77install.texi
+ cd $(srcdir)/f; $(MAKEINFO) -D INSTALLONLY --no-header --no-split \
+ --no-validate -o INSTALL install0.texi
+
+$(srcdir)/f/NEWS: f/news0.texi f/news.texi
+ cd $(srcdir)/f; $(MAKEINFO) -D NEWSONLY --no-header --no-split \
+ --no-validate -o NEWS news0.texi
+
+f77.rebuilt: f/g77.info $(srcdir)/f/BUGS $(srcdir)/f/INSTALL \
+ $(srcdir)/f/NEWS
+
+#
+# Install hooks:
+# f771 is installed elsewhere as part of $(COMPILERS).
+
+f77.install-normal:
+
+# Install the driver program as $(target)-g77
+# and also as either g77 (if native) or $(tooldir)/bin/g77.
+f77.install-common:
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ -if [ -f lang-f77 -a -f f771$(exeext) ] ; then \
+ if [ -f g77-cross$(exeext) ] ; then \
+ rm -f $(bindir)/$(G77_CROSS_NAME)$(exeext); \
+ $(INSTALL_PROGRAM) g77-cross$(exeext) $(bindir)/$(G77_CROSS_NAME)$(exeext); \
+ chmod a+x $(bindir)/$(G77_CROSS_NAME)$(exeext); \
+ else \
+ rm -f $(bindir)/$(G77_INSTALL_NAME)$(exeext); \
+ $(INSTALL_PROGRAM) g77$(exeext) $(bindir)/$(G77_INSTALL_NAME)$(exeext); \
+ chmod a+x $(bindir)/$(G77_INSTALL_NAME)$(exeext); \
+ fi ; \
+ else true; fi
+ @if [ -f f77-install-ok -o -f $(srcdir)/f77-install-ok ]; then \
+ echo ''; \
+ echo 'Warning: egcs no longer installs an f77 command.'; \
+ echo ' You must do so yourself. For more information,'; \
+ echo ' read "Distributing Binaries" in the egcs g77 docs.'; \
+ echo ' (To turn off this warning, delete the file'; \
+ echo ' f77-install-ok in the source or build directory.)'; \
+ echo ''; \
+ else true; fi
+
+# $(INSTALL_DATA) might be a relative pathname, so we can't cd into srcdir
+# to do the install. The sed rule was copied from stmp-int-hdrs.
+f77.install-info: f77.info
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ if [ -f lang-f77 -a -f f/g77.info ] ; then \
+ rm -f $(infodir)/g77.info*; \
+ for f in f/g77.info*; do \
+ realfile=`echo $$f | sed -e 's|.*/\([^/]*\)$$|\1|'`; \
+ $(INSTALL_DATA) $$f $(infodir)/$$realfile; \
+ done; \
+ chmod a-x $(infodir)/g77.info*; \
+ fi
+ @if [ -f lang-f77 -a -f $(srcdir)/f/g77.info ] ; then \
+ if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
+ echo " install-info --info-dir=$(infodir) $(infodir)/g77.info"; \
+ install-info --info-dir=$(infodir) $(infodir)/g77.info || : ; \
+ else : ; fi; \
+ else : ; fi
+
+f77.install-man: $(srcdir)/f/g77.1
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ -if [ -f lang-f77 -a -f f771$(exeext) ] ; then \
+ if [ -f g77-cross$(exeext) ] ; then \
+ rm -f $(mandir)/$(G77_CROSS_NAME)$(manext); \
+ $(INSTALL_DATA) $(srcdir)/f/g77.1 $(mandir)/$(G77_CROSS_NAME)$(manext); \
+ chmod a-x $(mandir)/$(G77_CROSS_NAME)$(manext); \
+ else \
+ rm -f $(mandir)/$(G77_INSTALL_NAME)$(manext); \
+ $(INSTALL_DATA) $(srcdir)/f/g77.1 $(mandir)/$(G77_INSTALL_NAME)$(manext); \
+ chmod a-x $(mandir)/$(G77_INSTALL_NAME)$(manext); \
+ fi; \
+ else true; fi
+
+f77.uninstall:
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ @if [ -f lang-f77 ] ; then \
+ if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \
+ echo " install-info --delete --info-dir=$(infodir) $(infodir)/g77.info"; \
+ install-info --delete --info-dir=$(infodir) $(infodir)/g77.info || : ; \
+ else : ; fi; \
+ else : ; fi
+ -if [ -f lang-f77 ]; then \
+ rm -rf $(bindir)/$(G77_INSTALL_NAME)$(exeext); \
+ rm -rf $(bindir)/$(G77_CROSS_NAME)$(exeext); \
+ rm -rf $(mandir)/$(G77_INSTALL_NAME)$(manext); \
+ rm -rf $(mandir)/$(G77_CROSS_NAME)$(manext); \
+ rm -rf $(infodir)/g77.info*; \
+ fi
+#
+# Clean hooks:
+# A lot of the ancillary files are deleted by the main makefile.
+# We just have to delete files specific to us.
+
+f77.mostlyclean:
+ -rm -f f/*$(objext)
+ -rm -f f/fini f/stamp-str f/str-*.h f/str-*.j
+ -rm -f f/intdoc f/ansify f/intdoc.h0
+ -rm -f g77.aux g77.cps g77.ky g77.toc g77.vr g77.fn g77.kys \
+ g77.pg g77.tp g77.vrs g77.cp g77.fns g77.log g77.pgs g77.tps
+f77.clean:
+ -rm -f g77.c g77.o g77spec.o g77version.o
+f77.distclean:
+ -rm -f lang-f77 f/Makefile
+f77.extraclean:
+f77.maintainer-clean:
+ -rm -f f/g77.info* f/g77.*aux f/TAGS f/BUGS f/INSTALL f/NEWS f/intdoc.texi
+#
+# Stage hooks:
+# The main makefile has already created stage?/f.
+
+G77STAGESTUFF = f/*$(objext) f/fini f/stamp-str f/str-*.h f/str-*.j \
+ lang-f77 g77.c g77.o g77spec.o g77version.o
+
+f77.stage1: stage1-start
+ -if [ -f lang-f77 ]; then \
+ mv -f $(G77STAGESTUFF) stage1/f; \
+ fi
+f77.stage2: stage2-start
+ -if [ -f lang-f77 ]; then \
+ mv -f $(G77STAGESTUFF) stage2/f; \
+ fi
+f77.stage3: stage3-start
+ -if [ -f lang-f77 ]; then \
+ mv -f $(G77STAGESTUFF) stage3/f; \
+ fi
+f77.stage4: stage4-start
+ -if [ -f lang-f77 ]; then \
+ mv -f $(G77STAGESTUFF) stage4/f; \
+ fi
+#
+# Maintenance hooks:
+
+# This target creates the files that can be rebuilt, but go in the
+# distribution anyway. It then copies the files to the distdir directory.
+f77.distdir: f77.rebuilt
+ case "$(LANGUAGES)" in \
+ *[fF]77*) touch lang-f77;; \
+ *) rm -f lang-f77;; \
+ esac
+ -if [ -f lang-f77 ]; then \
+ mkdir tmp/f; \
+ cd f; \
+ for file in *[0-9a-zA-Z+]; do \
+ $(LN_S) $$file ../tmp/f; \
+ done; \
+ fi
diff --git a/contrib/gcc/f/Makefile.in b/contrib/gcc/f/Makefile.in
new file mode 100644
index 0000000..4f9733b
--- /dev/null
+++ b/contrib/gcc/f/Makefile.in
@@ -0,0 +1,530 @@
+# Makefile for GNU F77 compiler.
+# Copyright (C) 1995-1998 Free Software Foundation, Inc.
+
+#This file is part of GNU Fortran.
+
+#GNU Fortran 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, or (at your option)
+#any later version.
+
+#GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+#the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+#02111-1307, USA.
+
+# The makefile built from this file lives in the language subdirectory.
+# Its purpose is to provide support for:
+#
+# 1) recursion where necessary, and only then (building .o's), and
+# 2) building and debugging f771 from the language subdirectory, and
+# 3) nothing else.
+#
+# The parent makefile handles all other chores, with help from the
+# language makefile fragment, of course.
+#
+# The targets for external use are:
+# all, TAGS, ???mostlyclean, ???clean.
+
+# Suppress smart makes who think they know how to automake Yacc files
+.y.c:
+
+# Variables that exist for you to override.
+# See below for how to change them for certain systems.
+
+ALLOCA =
+
+# Various ways of specifying flags for compilations:
+# CFLAGS is for the user to override to, e.g., do a bootstrap with -O2.
+# BOOT_CFLAGS is the value of CFLAGS to pass
+# to the stage2 and stage3 compilations
+# XCFLAGS is used for most compilations but not when using the GCC just built.
+XCFLAGS =
+CFLAGS = -g
+BOOT_CFLAGS = -O $(CFLAGS)
+# These exists to be overridden by the x-* and t-* files, respectively.
+X_CFLAGS =
+T_CFLAGS =
+
+X_CPPFLAGS =
+T_CPPFLAGS =
+
+CC = @CC@
+BISON = bison
+BISONFLAGS =
+LEX = flex
+LEXFLAGS =
+AR = ar
+AR_FLAGS = rc
+SHELL = /bin/sh
+MAKEINFO = makeinfo
+TEXI2DVI = texi2dvi
+
+# Define this as & to perform parallel make on a Sequent.
+# Note that this has some bugs, and it seems currently necessary
+# to compile all the gen* files first by hand to avoid erroneous results.
+P =
+
+# This is used in the definition of SUBDIR_USE_ALLOCA.
+# ??? Perhaps it would be better if it just looked for *gcc*.
+OLDCC = cc
+
+# This is used instead of ALL_CFLAGS when compiling with GCC_FOR_TARGET.
+# It omits XCFLAGS, and specifies -B./.
+# It also specifies -B$(tooldir)/ to find as and ld for a cross compiler.
+GCC_CFLAGS=$(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS)
+
+# Tools to use when building a cross-compiler.
+# These are used because `configure' appends `cross-make'
+# to the makefile when making a cross-compiler.
+
+target=@target@
+xmake_file=@dep_host_xmake_file@
+tmake_file=@dep_tmake_file@
+
+# Directory where sources are, from where we are.
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+# Additional system libraries to link with.
+CLIB=
+
+# Change this to a null string if obstacks are installed in the
+# system library.
+OBSTACK=obstack.o
+
+# Choose the real default target.
+ALL=all
+
+# End of variables for you to override.
+
+# Definition of `all' is here so that new rules inserted by sed
+# do not specify the default target.
+all: all.indirect
+
+# This tells GNU Make version 3 not to put all variables in the environment.
+.NOEXPORT:
+
+# sed inserts variable overrides after the following line.
+####target overrides
+@target_overrides@
+####host overrides
+@host_overrides@
+####cross overrides
+@cross_defines@
+@cross_overrides@
+####build overrides
+@build_overrides@
+#
+# Now figure out from those variables how to compile and link.
+
+all.indirect: Makefile ../f771$(exeext)
+
+# IN_GCC tells obstack.h that we are using gcc's <stddef.h> file.
+INTERNAL_CFLAGS = $(CROSS) -DIN_GCC @extra_c_flags@
+
+# This is the variable actually used when we compile.
+ALL_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS) -W -Wall
+
+# Likewise.
+ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS)
+
+# f771 is so big, need to tell linker on m68k-next-nextstep* to make enough
+# room for it. On AIX, linking f771 overflows the linker TOC;
+# `-bbigtoc' is appropriate for the linker on AIX 4.1 and above.
+F771_LDFLAGS = `case "${target}" in\
+ m68k-next-nextstep*) echo -segaddr __DATA 6000000;;\
+ *-*-aix[4-9]*) \`$(CC) --print-prog-name=ld\` -v 2>&1 | grep BFD >/dev/null || echo -Wl,-bbigtoc;; esac`
+
+# Even if ALLOCA is set, don't use it if compiling with GCC.
+
+SUBDIR_OBSTACK = `if [ x$(OBSTACK) != x ]; then echo ../$(OBSTACK); else true; fi`
+SUBDIR_USE_ALLOCA = `case "${CC}" in "${OLDCC}") if [ x$(ALLOCA) != x ]; then echo ../$(ALLOCA); else true; fi ;; esac`
+SUBDIR_MALLOC = `if [ x$(MALLOC) != x ]; then echo ../$(MALLOC); else true; fi`
+
+# How to link with both our special library facilities
+# and the system's installed libraries.
+LIBS = $(SUBDIR_OBSTACK) $(SUBDIR_USE_ALLOCA) $(SUBDIR_MALLOC) $(CLIB)
+
+# Specify the directories to be searched for header files.
+# Both . and srcdir are used, in that order,
+# so that tm.h and config.h will be found in the compilation
+# subdirectory rather than in the source directory.
+INCLUDES = -I. -I.. -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../config
+
+# Always use -I$(srcdir)/config when compiling.
+.c.o:
+ $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<
+
+#
+# Lists of files for various purposes.
+
+# Language-specific object files for g77
+
+F77_OBJS = \
+ bad.o \
+ bit.o \
+ bld.o \
+ com.o \
+ data.o \
+ equiv.o \
+ expr.o \
+ global.o \
+ implic.o \
+ info.o \
+ intrin.o \
+ lab.o \
+ lex.o \
+ malloc.o \
+ name.o \
+ parse.o \
+ proj.o \
+ src.o \
+ st.o \
+ sta.o \
+ stb.o \
+ stc.o \
+ std.o \
+ ste.o \
+ storag.o \
+ stp.o \
+ str.o \
+ sts.o \
+ stt.o \
+ stu.o \
+ stv.o \
+ stw.o \
+ symbol.o \
+ target.o \
+ top.o \
+ type.o \
+ version.o \
+ where.o
+
+# Language-independent object files.
+OBJS = `cat ../stamp-objlist`
+OBJDEPS = ../stamp-objlist
+
+compiler: ../f771$(exeext)
+../f771$(exeext): $(P) $(F77_OBJS) $(OBJDEPS) $(LIBDEPS)
+ rm -f f771$(exeext)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) $(F771_LDFLAGS) -o $@ \
+ $(F77_OBJS) $(OBJS) $(LIBS)
+
+Makefile: $(srcdir)/Makefile.in $(srcdir)/../configure
+ cd ..; $(SHELL) config.status
+
+native: config.status ../f771$(exeext)
+#
+# Compiling object files from source files.
+
+# Note that dependencies on obstack.h are not written
+# because that file is not part of GCC.
+
+# F77 language-specific files.
+
+# These macros expand to the corresponding g77-source .j files plus
+# the gcc-source files involved (each file itself, plus whatever
+# files on which it depends, but without including stuff resulting
+# from configuration, since we can't guess at that). The files
+# that live in a distclean'd gcc source directory have "$(srcdir)/"
+# prefixes, while the others don't because they'll be created
+# only in the build directory.
+ASSERT_H = $(srcdir)/assert.j $(srcdir)/../assert.h
+CONFIG_H = $(srcdir)/config.j ../config.h
+CONVERT_H = $(srcdir)/convert.j $(srcdir)/../convert.h
+FLAGS_H = $(srcdir)/flags.j $(srcdir)/../flags.h
+GLIMITS_H = $(srcdir)/glimits.j $(srcdir)/../glimits.h
+HCONFIG_H = $(srcdir)/hconfig.j ../hconfig.h
+INPUT_H = $(srcdir)/input.j $(srcdir)/../input.h
+OUTPUT_H = $(srcdir)/output.j $(srcdir)/../output.h
+RTL_H = $(srcdir)/rtl.j $(srcdir)/../rtl.h $(srcdir)/../rtl.def \
+ $(srcdir)/../machmode.h $(srcdir)/../machmode.def
+SYSTEM_H = $(srcdir)/system.j $(srcdir)/../system.h
+TCONFIG_H = $(srcdir)/tconfig.j ../tconfig.h
+TM_H = $(srcdir)/tm.j ../tm.h
+TOPLEV_H = $(srcdir)/toplev.j $(srcdir)/../toplev.h
+TREE_H = $(srcdir)/tree.j $(srcdir)/../tree.h $(srcdir)/../real.h \
+ $(srcdir)/../tree.def $(srcdir)/../machmode.h $(srcdir)/../machmode.def
+
+#Build the first part of this list with the command line:
+# cd gcc/; make deps-kinda -f f/Makefile.in
+#Note that this command uses the host C compiler;
+# use HOST_CC="./xgcc -B./" to use GCC in the build directory, for example.
+#Also note that this particular build file seems to want to use
+# substitions: $(CONFIG_H) for config.h; $(TREE_H) for tree.h;
+# $(RTL_H) for rtl.h; etc.. deps-kinda uses a sed script to do those
+# substitutions, plus others for elegance.
+
+ansify.o: ansify.c $(HCONFIG_H) $(SYSTEM_H) $(ASSERT_H)
+bad.o: bad.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) bad.h bad.def where.h \
+ $(GLIMITS_H) top.h malloc.h $(FLAGS_H) com.h com-rt.def $(TREE_H) bld.h \
+ bld-op.def bit.h info.h info-b.def info-k.def info-w.def target.h \
+ lex.h type.h intrin.h intrin.def lab.h symbol.h symbol.def equiv.h \
+ storag.h global.h name.h $(TOPLEV_H)
+bit.o: bit.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) $(GLIMITS_H) bit.h \
+ malloc.h
+bld.o: bld.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) bld.h bld-op.def bit.h \
+ malloc.h com.h com-rt.def $(TREE_H) info.h info-b.def info-k.def \
+ info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h lex.h \
+ type.h lab.h storag.h symbol.h symbol.def equiv.h global.h name.h \
+ intrin.h intrin.def
+com.o: com.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) $(FLAGS_H) $(RTL_H) $(TOPLEV_H) \
+ $(TREE_H) $(OUTPUT_H) $(CONVERT_H) com.h com-rt.def bld.h bld-op.def bit.h \
+ malloc.h info.h info-b.def info-k.def info-w.def target.h bad.h \
+ bad.def where.h $(GLIMITS_H) top.h lex.h type.h intrin.h intrin.def \
+ lab.h symbol.h symbol.def equiv.h storag.h global.h name.h expr.h \
+ implic.h src.h st.h
+data.o: data.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) data.h bld.h \
+ bld-op.def bit.h malloc.h com.h com-rt.def $(TREE_H) info.h info-b.def \
+ info-k.def info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h \
+ lex.h type.h lab.h storag.h symbol.h symbol.def equiv.h global.h \
+ name.h intrin.h intrin.def expr.h st.h
+equiv.o: equiv.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) equiv.h bld.h \
+ bld-op.def bit.h malloc.h com.h com-rt.def $(TREE_H) info.h info-b.def \
+ info-k.def info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h \
+ lex.h type.h lab.h storag.h symbol.h symbol.def global.h name.h \
+ intrin.h intrin.def data.h
+expr.o: expr.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) expr.h bld.h \
+ bld-op.def bit.h malloc.h com.h com-rt.def $(TREE_H) info.h info-b.def \
+ info-k.def info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h \
+ lex.h type.h lab.h storag.h symbol.h symbol.def equiv.h global.h \
+ name.h intrin.h intrin.def implic.h src.h st.h stamp-str
+fini.o: fini.c proj.h $(HCONFIG_H) $(SYSTEM_H) $(ASSERT_H) malloc.h
+global.o: global.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) global.h info.h \
+ info-b.def info-k.def info-w.def target.h $(TREE_H) bad.h bad.def \
+ where.h $(GLIMITS_H) top.h malloc.h lex.h type.h name.h symbol.h \
+ symbol.def bld.h bld-op.def bit.h com.h com-rt.def lab.h storag.h \
+ intrin.h intrin.def equiv.h
+implic.o: implic.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) implic.h info.h \
+ info-b.def info-k.def info-w.def target.h $(TREE_H) bad.h bad.def \
+ where.h $(GLIMITS_H) top.h malloc.h lex.h type.h symbol.h symbol.def \
+ bld.h bld-op.def bit.h com.h com-rt.def lab.h storag.h intrin.h \
+ intrin.def equiv.h global.h name.h src.h
+info.o: info.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) info.h info-b.def \
+ info-k.def info-w.def target.h $(TREE_H) bad.h bad.def where.h $(GLIMITS_H) \
+ top.h malloc.h lex.h type.h
+intdoc.o: intdoc.c $(HCONFIG_H) $(SYSTEM_H) $(ASSERT_H) intrin.h intrin.def \
+ intdoc.h0 intdoc.h0
+intrin.o: intrin.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) intrin.h \
+ intrin.def bld.h bld-op.def bit.h malloc.h com.h com-rt.def $(TREE_H) \
+ info.h info-b.def info-k.def info-w.def target.h bad.h bad.def \
+ where.h $(GLIMITS_H) top.h lex.h type.h lab.h storag.h symbol.h \
+ symbol.def equiv.h global.h name.h expr.h src.h
+lab.o: lab.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) lab.h com.h com-rt.def \
+ $(TREE_H) bld.h bld-op.def bit.h malloc.h info.h info-b.def info-k.def \
+ info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h lex.h \
+ type.h intrin.h intrin.def symbol.h symbol.def equiv.h storag.h \
+ global.h name.h
+lex.o: lex.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) top.h malloc.h where.h \
+ $(GLIMITS_H) bad.h bad.def com.h com-rt.def $(TREE_H) bld.h bld-op.def \
+ bit.h info.h info-b.def info-k.def info-w.def target.h lex.h type.h \
+ intrin.h intrin.def lab.h symbol.h symbol.def equiv.h storag.h \
+ global.h name.h src.h $(FLAGS_H) $(INPUT_H) $(TOPLEV_H) $(OUTPUT_H)
+malloc.o: malloc.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) malloc.h
+name.o: name.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) bad.h bad.def where.h \
+ $(GLIMITS_H) top.h malloc.h name.h global.h info.h info-b.def info-k.def \
+ info-w.def target.h $(TREE_H) lex.h type.h symbol.h symbol.def bld.h \
+ bld-op.def bit.h com.h com-rt.def lab.h storag.h intrin.h intrin.def \
+ equiv.h src.h
+parse.o: parse.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) top.h malloc.h \
+ where.h $(GLIMITS_H) com.h com-rt.def $(TREE_H) bld.h bld-op.def bit.h \
+ info.h info-b.def info-k.def info-w.def target.h bad.h bad.def lex.h \
+ type.h intrin.h intrin.def lab.h symbol.h symbol.def equiv.h storag.h \
+ global.h name.h version.h $(FLAGS_H)
+proj.o: proj.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) $(GLIMITS_H)
+src.o: src.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) src.h bad.h bad.def \
+ where.h $(GLIMITS_H) top.h malloc.h
+st.o: st.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) st.h bad.h bad.def \
+ where.h $(GLIMITS_H) top.h malloc.h lex.h symbol.h symbol.def bld.h \
+ bld-op.def bit.h com.h com-rt.def $(TREE_H) info.h info-b.def info-k.def \
+ info-w.def target.h type.h lab.h storag.h intrin.h intrin.def equiv.h \
+ global.h name.h sta.h stamp-str stb.h expr.h stp.h stt.h stc.h std.h \
+ stv.h stw.h ste.h sts.h stu.h
+sta.o: sta.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) sta.h bad.h bad.def \
+ where.h $(GLIMITS_H) top.h malloc.h lex.h stamp-str symbol.h symbol.def \
+ bld.h bld-op.def bit.h com.h com-rt.def $(TREE_H) info.h info-b.def \
+ info-k.def info-w.def target.h type.h lab.h storag.h intrin.h \
+ intrin.def equiv.h global.h name.h implic.h stb.h expr.h stp.h stt.h \
+ stc.h std.h stv.h stw.h
+stb.o: stb.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) stb.h bad.h bad.def \
+ where.h $(GLIMITS_H) top.h malloc.h expr.h bld.h bld-op.def bit.h com.h \
+ com-rt.def $(TREE_H) info.h info-b.def info-k.def info-w.def target.h \
+ lex.h type.h lab.h storag.h symbol.h symbol.def equiv.h global.h \
+ name.h intrin.h intrin.def stp.h stt.h stamp-str src.h sta.h stc.h
+stc.o: stc.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) stc.h bad.h bad.def \
+ where.h $(GLIMITS_H) top.h malloc.h bld.h bld-op.def bit.h com.h \
+ com-rt.def $(TREE_H) info.h info-b.def info-k.def info-w.def target.h \
+ lex.h type.h lab.h storag.h symbol.h symbol.def equiv.h global.h \
+ name.h intrin.h intrin.def expr.h stp.h stt.h stamp-str data.h implic.h \
+ src.h sta.h std.h stv.h stw.h
+std.o: std.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) std.h bld.h bld-op.def \
+ bit.h malloc.h com.h com-rt.def $(TREE_H) info.h info-b.def info-k.def \
+ info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h lex.h \
+ type.h lab.h storag.h symbol.h symbol.def equiv.h global.h name.h \
+ intrin.h intrin.def stp.h stt.h stamp-str stv.h stw.h sta.h ste.h sts.h
+ste.o: ste.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) $(RTL_H) $(TOPLEV_H) ste.h \
+ bld.h bld-op.def bit.h malloc.h com.h com-rt.def $(TREE_H) info.h \
+ info-b.def info-k.def info-w.def target.h bad.h bad.def where.h \
+ $(GLIMITS_H) top.h lex.h type.h lab.h storag.h symbol.h symbol.def \
+ equiv.h global.h name.h intrin.h intrin.def stp.h stt.h stamp-str sts.h \
+ stv.h stw.h expr.h sta.h
+storag.o: storag.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) storag.h bld.h \
+ bld-op.def bit.h malloc.h com.h com-rt.def $(TREE_H) info.h info-b.def \
+ info-k.def info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h \
+ lex.h type.h lab.h symbol.h symbol.def equiv.h global.h name.h \
+ intrin.h intrin.def data.h
+stp.o: stp.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) stp.h bld.h bld-op.def \
+ bit.h malloc.h com.h com-rt.def $(TREE_H) info.h info-b.def info-k.def \
+ info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h lex.h \
+ type.h lab.h storag.h symbol.h symbol.def equiv.h global.h name.h \
+ intrin.h intrin.def stt.h
+str.o: str.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) src.h bad.h bad.def \
+ where.h $(GLIMITS_H) top.h malloc.h stamp-str lex.h
+sts.o: sts.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) sts.h malloc.h com.h \
+ com-rt.def $(TREE_H) bld.h bld-op.def bit.h info.h info-b.def info-k.def \
+ info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h lex.h \
+ type.h intrin.h intrin.def lab.h symbol.h symbol.def equiv.h storag.h \
+ global.h name.h
+stt.o: stt.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) stt.h top.h malloc.h \
+ where.h $(GLIMITS_H) bld.h bld-op.def bit.h com.h com-rt.def $(TREE_H) \
+ info.h info-b.def info-k.def info-w.def target.h bad.h bad.def lex.h \
+ type.h lab.h storag.h symbol.h symbol.def equiv.h global.h name.h \
+ intrin.h intrin.def stp.h expr.h sta.h stamp-str
+stu.o: stu.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) bld.h bld-op.def bit.h \
+ malloc.h com.h com-rt.def $(TREE_H) info.h info-b.def info-k.def \
+ info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h lex.h \
+ type.h lab.h storag.h symbol.h symbol.def equiv.h global.h name.h \
+ intrin.h intrin.def implic.h stu.h sta.h stamp-str
+stv.o: stv.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) stv.h lab.h com.h \
+ com-rt.def $(TREE_H) bld.h bld-op.def bit.h malloc.h info.h info-b.def \
+ info-k.def info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h \
+ lex.h type.h intrin.h intrin.def symbol.h symbol.def equiv.h storag.h \
+ global.h name.h
+stw.o: stw.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) stw.h bld.h bld-op.def \
+ bit.h malloc.h com.h com-rt.def $(TREE_H) info.h info-b.def info-k.def \
+ info-w.def target.h bad.h bad.def where.h $(GLIMITS_H) top.h lex.h \
+ type.h lab.h storag.h symbol.h symbol.def equiv.h global.h name.h \
+ intrin.h intrin.def stv.h sta.h stamp-str
+symbol.o: symbol.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) symbol.h \
+ symbol.def bld.h bld-op.def bit.h malloc.h com.h com-rt.def $(TREE_H) \
+ info.h info-b.def info-k.def info-w.def target.h bad.h bad.def \
+ where.h $(GLIMITS_H) top.h lex.h type.h lab.h storag.h intrin.h \
+ intrin.def equiv.h global.h name.h src.h st.h
+target.o: target.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) $(GLIMITS_H) \
+ target.h $(TREE_H) bad.h bad.def where.h top.h malloc.h info.h \
+ info-b.def info-k.def info-w.def type.h lex.h
+top.o: top.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) top.h malloc.h where.h \
+ $(GLIMITS_H) bad.h bad.def bit.h bld.h bld-op.def com.h com-rt.def \
+ $(TREE_H) info.h info-b.def info-k.def info-w.def target.h lex.h type.h \
+ lab.h storag.h symbol.h symbol.def equiv.h global.h name.h intrin.h \
+ intrin.def data.h expr.h implic.h src.h st.h $(FLAGS_H) $(TOPLEV_H)
+type.o: type.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) type.h malloc.h
+version.o: version.c
+where.o: where.c proj.h $(CONFIG_H) $(SYSTEM_H) $(ASSERT_H) where.h $(GLIMITS_H) \
+ top.h malloc.h lex.h
+
+# The rest of this list (Fortran 77 language-specific files) is hand-generated.
+
+stamp-str: str-1t.h str-1t.j str-2t.h str-2t.j \
+ str-fo.h str-fo.j str-io.h str-io.j str-nq.h str-nq.j \
+ str-op.h str-op.j str-ot.h str-ot.j
+ touch stamp-str
+
+str-1t.h str-1t.j: fini str-1t.fin
+ ./fini `echo $(srcdir)/str-1t.fin | sed 's,^\./,,'` str-1t.j str-1t.h
+
+str-2t.h str-2t.j: fini str-2t.fin
+ ./fini `echo $(srcdir)/str-2t.fin | sed 's,^\./,,'` str-2t.j str-2t.h
+
+str-fo.h str-fo.j: fini str-fo.fin
+ ./fini `echo $(srcdir)/str-fo.fin | sed 's,^\./,,'` str-fo.j str-fo.h
+
+str-io.h str-io.j: fini str-io.fin
+ ./fini `echo $(srcdir)/str-io.fin | sed 's,^\./,,'` str-io.j str-io.h
+
+str-nq.h str-nq.j: fini str-nq.fin
+ ./fini `echo $(srcdir)/str-nq.fin | sed 's,^\./,,'` str-nq.j str-nq.h
+
+str-op.h str-op.j: fini str-op.fin
+ ./fini `echo $(srcdir)/str-op.fin | sed 's,^\./,,'` str-op.j str-op.h
+
+str-ot.h str-ot.j: fini str-ot.fin
+ ./fini `echo $(srcdir)/str-ot.fin | sed 's,^\./,,'` str-ot.j str-ot.h
+
+fini: fini.o proj-h.o
+ $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o fini fini.o proj-h.o
+
+fini.o:
+ $(HOST_CC) -c -DUSE_HCONFIG $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \
+ `echo $(srcdir)/fini.c | sed 's,^\./,,'` -o $@
+
+proj-h.o: proj.o
+ $(HOST_CC) -c -DUSE_HCONFIG $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) \
+ `echo $(srcdir)/proj.c | sed 's,^\./,,'` -o $@
+
+# Other than str-*.j, the *.j files are dummy #include files
+# that normally just #include the corresponding back-end *.h
+# files, but not if MAKING_DEPENDENCIES is #defined. The str-*.j
+# files also are not actually included if MAKING_DEPENDENCIES
+# is #defined. The point of all this is to come up with a clean
+# dependencies list whether working in a clean directory, such
+# that str-*.j and such do not exist, or in a directory full
+# of already-built files. Any dependency on a str-*.j file
+# implies a dependency on str.h, so we key on that to replace
+# it with stamp-str, and dependencies on the other *.j files
+# are generally left alone (modulo special macros like RTL_H)
+# because we might not want to recompile all of g77 just
+# because a back-end file changes. MG is usually "-MG" but
+# should be defined with "make MG= deps-kinda..." if using
+# a compiler that doesn't support -MG (gcc does as of 2.6) --
+# it prevents diagnostics when an #include file is missing,
+# as will be the case with proj.h in a clean directory.
+MG=-MG
+deps-kinda:
+ $(HOST_CC) -DMAKING_DEPENDENCIES -MM $(MG) *.c 2>&1 | \
+ sed -e 's: \([.]/\)*assert[.]j: $$(ASSERT_H):g' \
+ -e 's: \([.]/\)*config[.]j: $$(CONFIG_H):g' \
+ -e 's: \([.]/\)*convert[.]j: $$(CONVERT_H):g' \
+ -e 's: \([.]/\)*flags[.]j: $$(FLAGS_H):g' \
+ -e 's: \([.]/\)*glimits[.]j: $$(GLIMITS_H):g' \
+ -e 's: \([.]/\)*hconfig[.]j: $$(HCONFIG_H):g' \
+ -e 's: \([.]/\)*input[.]j: $$(INPUT_H):g' \
+ -e 's: \([.]/\)*output[.]j: $$(OUTPUT_H):g' \
+ -e 's: \([.]/\)*rtl[.]j: $$(RTL_H):g' \
+ -e 's: \([.]/\)*system[.]j: $$(SYSTEM_H):g' \
+ -e 's: \([.]/\)*tconfig[.]j: $$(TCONFIG_H):g' \
+ -e 's: \([.]/\)*tm[.]j: $$(TM_H):g' \
+ -e 's: \([.]/\)*toplev[.]j: $$(TOPLEV_H):g' \
+ -e 's: \([.]/\)*tree[.]j: $$(TREE_H):g' \
+ -e 's: \([.]/\)*str[.]h: stamp-str:g' \
+ -e 's:.*g77spec.*::g' \
+ -e 's%^\(.*\)[ ]*: %\1: %g'
+
+# This rule is just a handy way to build the g77 derived files without
+# having the gcc source tree around.
+g77-only: force
+ if [ -f g77.texi ] ; then \
+ (cd ..; $(MAKE) srcdir=. HOST_CC=cc HOST_CFLAGS=-g -f f/Make-lang.in f77.rebuilt); \
+ else \
+ $(MAKE) srcdir=. HOST_CC=cc HOST_CFLAGS=-g -f f/Make-lang.in f77.rebuilt; \
+ fi
+
+#
+# These exist for maintenance purposes.
+
+# Update the tags table.
+TAGS: force
+ cd $(srcdir)/f ; \
+ etags *.c *.h ; \
+ echo 'l' | tr 'l' '\f' >> TAGS ; \
+ etags -a ../*.h ../*.c;
+
+.PHONY: none all all.indirect f77.rebuilt compiler native deps-kinda g77-only TAGS force
+
+force:
diff --git a/contrib/gcc/f/NEWS b/contrib/gcc/f/NEWS
new file mode 100644
index 0000000..ff1bb45
--- /dev/null
+++ b/contrib/gcc/f/NEWS
@@ -0,0 +1,1623 @@
+This file lists recent changes to the GNU Fortran compiler. Copyright
+(C) 1995, 1996 Free Software Foundation, Inc. You may copy,
+distribute, and modify it freely as long as you preserve this copyright
+notice and permission notice.
+
+News About GNU Fortran
+**********************
+
+ Changes made to recent versions of GNU Fortran are listed below,
+with the most recent version first.
+
+ The changes are generally listed in order:
+
+ 1. Code-generation and run-time-library bug-fixes
+
+ 2. Compiler and run-time-library crashes involving valid code that
+ have been fixed
+
+ 3. New features
+
+ 4. Fixes and enhancements to existing features
+
+ 5. New diagnostics
+
+ 6. Internal improvements
+
+ 7. Miscellany
+
+ This order is not strict--for example, some items involve a
+combination of these elements.
+
+ Note that two variants of `g77' are tracked below. The `egcs'
+variant is described vis-a-vis previous versions of `egcs' and/or an
+official FSF version, as appropriate.
+
+ Therefore, `egcs' versions sometimes have multiple listings to help
+clarify how they differ from other versions, though this can make
+getting a complete picture of what a particular `egcs' version contains
+somewhat more difficult.
+
+ An online, "live" version of this document (derived directly from
+the up-to-date mainline version of `g77' within `egcs') is available at
+`http://egcs.cygnus.com/onlinedocs/g77_news.html'.
+
+In 0.5.24 and `egcs' 1.1.2 (versus 0.5.23 and 1.1.1):
+=====================================================
+
+ * Fix the `IDate' Intrinsic (VXT) so the returned year is in the
+ documented, non-Y2K-compliant range of 0-99, instead of being
+ returned as 100 in the year 2000.
+
+ * Fix the `Date_and_Time' intrinsic (in `libg2c') to return the
+ milliseconds value properly in VALUES(8).
+
+ * Fix the `LStat' intrinsic (in `libg2c') to return device-ID
+ information properly in SARRAY(7).
+
+ * Improve documentation.
+
+In 0.5.24 and `egcs' 1.1.1 (versus 0.5.23 and 1.1):
+===================================================
+
+ * Fix `libg2c' so it performs an implicit `ENDFILE' operation (as
+ appropriate) whenever a `REWIND' is done.
+
+ (This bug was introduced in 0.5.23 and `egcs' 1.1 in `g77''s
+ version of `libf2c'.)
+
+ * Fix `libg2c' so it no longer crashes with a spurious diagnostic
+ upon doing any I/O following a direct formatted write.
+
+ (This bug was introduced in 0.5.23 and `egcs' 1.1 in `g77''s
+ version of `libf2c'.)
+
+ * Fix `g77' so it no longer crashes compiling references to the
+ `Rand' intrinsic on some systems.
+
+ * Fix `g77' portion of installation process so it works better on
+ some systems (those with shells requiring `else true' clauses on
+ `if' constructs for the completion code to be set properly).
+
+In `egcs' 1.1 (versus 0.5.24):
+==============================
+
+ * Fix `g77' crash compiling code containing the construct
+ `CMPLX(0.)' or similar.
+
+ * Fix `g77' crash (or apparently infinite run-time) when compiling
+ certain complicated expressions involving `COMPLEX' arithmetic
+ (especially multiplication).
+
+ * Fix a code-generation bug that afflicted Intel x86 targets when
+ `-O2' was specified compiling, for example, an old version of the
+ `DNRM2' routine.
+
+ The x87 coprocessor stack was being mismanaged in cases involving
+ assigned `GOTO' and `ASSIGN'.
+
+ * Align static double-precision variables and arrays on Intel x86
+ targets regardless of whether `-malign-double' is specified.
+
+ Generally, this affects only local variables and arrays having the
+ `SAVE' attribute or given initial values via `DATA'.
+
+In `egcs' 1.1 (versus `egcs' 1.0.3):
+====================================
+
+ * Fix bugs in the `libU77' intrinsic `HostNm' that wrote one byte
+ beyond the end of its `CHARACTER' argument, and in the `libU77'
+ intrinsics `GMTime' and `LTime' that overwrote their arguments.
+
+ * Assumed arrays with negative bounds (such as `REAL A(-1:*)') no
+ longer elicit spurious diagnostics from `g77', even on systems
+ with pointers having different sizes than integers.
+
+ This bug is not known to have existed in any recent version of
+ `gcc'. It was introduced in an early release of `egcs'.
+
+ * Valid combinations of `EXTERNAL', passing that external as a dummy
+ argument without explicitly giving it a type, and, in a subsequent
+ program unit, referencing that external as an external function
+ with a different type no longer crash `g77'.
+
+ * `CASE DEFAULT' no longer crashes `g77'.
+
+ * The `-Wunused' option no longer issues a spurious warning about
+ the "master" procedure generated by `g77' for procedures
+ containing `ENTRY' statements.
+
+ * Support `FORMAT(I<EXPR>)' when EXPR is a compile-time constant
+ `INTEGER' expression.
+
+ * Fix `g77' `-g' option so procedures that use `ENTRY' can be
+ stepped through, line by line, in `gdb'.
+
+ * Allow any `REAL' argument to intrinsics `Second' and `CPU_Time'.
+
+ * Use `tempnam', if available, to open scratch files (as in
+ `OPEN(STATUS='SCRATCH')') so that the `TMPDIR' environment
+ variable, if present, is used.
+
+ * `g77''s version of `libf2c' separates out the setting of global
+ state (such as command-line arguments and signal handling) from
+ `main.o' into distinct, new library archive members.
+
+ This should make it easier to write portable applications that
+ have their own (non-Fortran) `main()' routine properly set up the
+ `libf2c' environment, even when `libf2c' (now `libg2c') is a
+ shared library.
+
+ * `g77' no longer installs the `f77' command and `f77.1' man page in
+ the `/usr' or `/usr/local' heirarchy, even if the `f77-install-ok'
+ file exists in the source or build directory. See the
+ installation documentation for more information.
+
+ * `g77' no longer installs the `libf2c.a' library and `f2c.h'
+ include file in the `/usr' or `/usr/local' heirarchy, even if the
+ `f2c-install-ok' or `f2c-exists-ok' files exist in the source or
+ build directory. See the installation documentation for more
+ information.
+
+ * The `libf2c.a' library produced by `g77' has been renamed to
+ `libg2c.a'. It is installed only in the `gcc' "private" directory
+ heirarchy, `gcc-lib'. This allows system administrators and users
+ to choose which version of the `libf2c' library from `netlib' they
+ wish to use on a case-by-case basis. See the installation
+ documentation for more information.
+
+ * The `f2c.h' include (header) file produced by `g77' has been
+ renamed to `g2c.h'. It is installed only in the `gcc' "private"
+ directory heirarchy, `gcc-lib'. This allows system administrators
+ and users to choose which version of the include file from
+ `netlib' they wish to use on a case-by-case basis. See the
+ installation documentation for more information.
+
+ * The `g77' command now expects the run-time library to be named
+ `libg2c.a' instead of `libf2c.a', to ensure that a version other
+ than the one built and installed as part of the same `g77' version
+ is picked up.
+
+ * During the configuration and build process, `g77' creates
+ subdirectories it needs only as it needs them. Other cleaning up
+ of the configuration and build process has been performed as well.
+
+ * `install-info' now used to update the directory of Info
+ documentation to contain an entry for `g77' (during installation).
+
+ * Some diagnostics have been changed from warnings to errors, to
+ prevent inadvertent use of the resulting, probably buggy, programs.
+ These mostly include diagnostics about use of unsupported features
+ in the `OPEN', `INQUIRE', `READ', and `WRITE' statements, and
+ about truncations of various sorts of constants.
+
+ * Improve compilation of `FORMAT' expressions so that a null byte is
+ appended to the last operand if it is a constant. This provides a
+ cleaner run-time diagnostic as provided by `libf2c' for statements
+ like `PRINT '(I1', 42'.
+
+ * Improve documentation and indexing.
+
+ * The upgrade to `libf2c' as of 1998-06-18 should fix a variety of
+ problems, including those involving some uses of the `T' format
+ specifier, and perhaps some build (porting) problems as well.
+
+In 0.5.24 and `egcs' 1.1 (versus 0.5.23):
+=========================================
+
+ * `g77' no longer produces incorrect code and initial values for
+ `EQUIVALENCE' and `COMMON' aggregates that, due to "unnatural"
+ ordering of members vis-a-vis their types, require initial padding.
+
+ * `g77' no longer crashes when compiling code containing
+ specification statements such as `INTEGER(KIND=7) PTR'.
+
+ * `g77' no longer crashes when compiling code such as `J = SIGNAL(1,
+ 2)'.
+
+ * `g77' now treats `%LOC(EXPR)' and `LOC(EXPR)' as "ordinary"
+ expressions when they are used as arguments in procedure calls.
+ This change applies only to global (filewide) analysis, making it
+ consistent with how `g77' actually generates code for these cases.
+
+ Previously, `g77' treated these expressions as denoting special
+ "pointer" arguments for the purposes of filewide analysis.
+
+ * The `g77' driver now ensures that `-lg2c' is specified in the link
+ phase prior to any occurrence of `-lm'. This prevents
+ accidentally linking to a routine in the SunOS4 `-lm' library when
+ the generated code wants to link to the one in `libf2c' (`libg2c').
+
+ * `g77' emits more debugging information when `-g' is used.
+
+ This new information allows, for example, `which __g77_length_a'
+ to be used in `gdb' to determine the type of the phantom length
+ argument supplied with `CHARACTER' variables.
+
+ This information pertains to internally-generated type, variable,
+ and other information, not to the longstanding deficiencies
+ vis-a-vis `COMMON' and `EQUIVALENCE'.
+
+ * The F90 `Date_and_Time' intrinsic now is supported.
+
+ * The F90 `System_Clock' intrinsic allows the optional arguments
+ (except for the `Count' argument) to be omitted.
+
+ * Upgrade to `libf2c' as of 1998-06-18.
+
+ * Improve documentation and indexing.
+
+In 0.5.23 (versus 0.5.22):
+==========================
+
+ * This release contains several regressions against version 0.5.22
+ of `g77', due to using the "vanilla" `gcc' back end instead of
+ patching it to fix a few bugs and improve performance in a few
+ cases.
+
+ See `egcs/gcc/f/BUGS', for information on the known bugs in this
+ version, including the regressions.
+
+ Features that have been dropped from this version of `g77' due to
+ their being implemented via `g77'-specific patches to the `gcc'
+ back end in previous releases include:
+
+ - Support for `__restrict__' keyword, the options
+ `-fargument-alias', `-fargument-noalias', and
+ `-fargument-noalias-global', and the corresponding
+ alias-analysis code.
+
+ (`egcs' has the alias-analysis code, but not the
+ `__restrict__' keyword. `egcs' `g77' users benefit from the
+ alias-analysis code despite the lack of the `__restrict__'
+ keyword, which is a C-language construct.)
+
+ - Support for the GNU compiler options `-fmove-all-movables',
+ `-freduce-all-givs', and `-frerun-loop-opt'.
+
+ (`egcs' supports these options. `g77' users of `egcs'
+ benefit from them even if they are not explicitly specified,
+ because the defaults are optimized for `g77' users.)
+
+ - Support for the `-W' option warning about integer division by
+ zero.
+
+ - The Intel x86-specific option `-malign-double' applying to
+ stack-allocated data as well as statically-allocate data.
+
+ Note that the `gcc/f/gbe/' subdirectory has been removed from this
+ distribution as a result of `g77' no longer including patches for
+ the `gcc' back end.
+
+ * Fix bugs in the `libU77' intrinsic `HostNm' that wrote one byte
+ beyond the end of its `CHARACTER' argument, and in the `libU77'
+ intrinsics `GMTime' and `LTime' that overwrote their arguments.
+
+ * Support `gcc' version 2.8, and remove support for prior versions
+ of `gcc'.
+
+ * Remove support for the `--driver' option, as `g77' now does all
+ the driving, just like `gcc'.
+
+ * `CASE DEFAULT' no longer crashes `g77'.
+
+ * Valid combinations of `EXTERNAL', passing that external as a dummy
+ argument without explicitly giving it a type, and, in a subsequent
+ program unit, referencing that external as an external function
+ with a different type no longer crash `g77'.
+
+ * `g77' no longer installs the `f77' command and `f77.1' man page in
+ the `/usr' or `/usr/local' heirarchy, even if the `f77-install-ok'
+ file exists in the source or build directory. See the
+ installation documentation for more information.
+
+ * `g77' no longer installs the `libf2c.a' library and `f2c.h'
+ include file in the `/usr' or `/usr/local' heirarchy, even if the
+ `f2c-install-ok' or `f2c-exists-ok' files exist in the source or
+ build directory. See the installation documentation for more
+ information.
+
+ * The `libf2c.a' library produced by `g77' has been renamed to
+ `libg2c.a'. It is installed only in the `gcc' "private" directory
+ heirarchy, `gcc-lib'. This allows system administrators and users
+ to choose which version of the `libf2c' library from `netlib' they
+ wish to use on a case-by-case basis. See the installation
+ documentation for more information.
+
+ * The `f2c.h' include (header) file produced by `g77' has been
+ renamed to `g2c.h'. It is installed only in the `gcc' "private"
+ directory heirarchy, `gcc-lib'. This allows system administrators
+ and users to choose which version of the include file from
+ `netlib' they wish to use on a case-by-case basis. See the
+ installation documentation for more information.
+
+ * The `g77' command now expects the run-time library to be named
+ `libg2c.a' instead of `libf2c.a', to ensure that a version other
+ than the one built and installed as part of the same `g77' version
+ is picked up.
+
+ * The `-Wunused' option no longer issues a spurious warning about
+ the "master" procedure generated by `g77' for procedures
+ containing `ENTRY' statements.
+
+ * `g77''s version of `libf2c' separates out the setting of global
+ state (such as command-line arguments and signal handling) from
+ `main.o' into distinct, new library archive members.
+
+ This should make it easier to write portable applications that
+ have their own (non-Fortran) `main()' routine properly set up the
+ `libf2c' environment, even when `libf2c' (now `libg2c') is a
+ shared library.
+
+ * During the configuration and build process, `g77' creates
+ subdirectories it needs only as it needs them, thus avoiding
+ unnecessary creation of, for example, `stage1/f/runtime' when
+ doing a non-bootstrap build. Other cleaning up of the
+ configuration and build process has been performed as well.
+
+ * `install-info' now used to update the directory of Info
+ documentation to contain an entry for `g77' (during installation).
+
+ * Some diagnostics have been changed from warnings to errors, to
+ prevent inadvertent use of the resulting, probably buggy, programs.
+ These mostly include diagnostics about use of unsupported features
+ in the `OPEN', `INQUIRE', `READ', and `WRITE' statements, and
+ about truncations of various sorts of constants.
+
+ * Improve documentation and indexing.
+
+ * Upgrade to `libf2c' as of 1998-04-20.
+
+ This should fix a variety of problems, including those involving
+ some uses of the `T' format specifier, and perhaps some build
+ (porting) problems as well.
+
+In 0.5.22 (versus 0.5.21):
+==========================
+
+ * Fix code generation for iterative `DO' loops that have one or more
+ references to the iteration variable, or to aliases of it, in
+ their control expressions. For example, `DO 10 J=2,J' now is
+ compiled correctly.
+
+ * Fix a code-generation bug that afflicted Intel x86 targets when
+ `-O2' was specified compiling, for example, an old version of the
+ `DNRM2' routine.
+
+ The x87 coprocessor stack was being mismanaged in cases involving
+ assigned `GOTO' and `ASSIGN'.
+
+ * Fix `DTime' intrinsic so as not to truncate results to integer
+ values (on some systems).
+
+ * Fix `Signal' intrinsic so it offers portable support for 64-bit
+ systems (such as Digital Alphas running GNU/Linux).
+
+ * Fix run-time crash involving `NAMELIST' on 64-bit machines such as
+ Alphas.
+
+ * Fix `g77' version of `libf2c' so it no longer produces a spurious
+ `I/O recursion' diagnostic at run time when an I/O operation (such
+ as `READ *,I') is interrupted in a manner that causes the program
+ to be terminated via the `f_exit' routine (such as via `C-c').
+
+ * Fix `g77' crash triggered by `CASE' statement with an omitted
+ lower or upper bound.
+
+ * Fix `g77' crash compiling references to `CPU_Time' intrinsic.
+
+ * Fix `g77' crash (or apparently infinite run-time) when compiling
+ certain complicated expressions involving `COMPLEX' arithmetic
+ (especially multiplication).
+
+ * Fix `g77' crash on statements such as `PRINT *,
+ (REAL(Z(I)),I=1,2)', where `Z' is `DOUBLE COMPLEX'.
+
+ * Fix a `g++' crash.
+
+ * Support `FORMAT(I<EXPR>)' when EXPR is a compile-time constant
+ `INTEGER' expression.
+
+ * Fix `g77' `-g' option so procedures that use `ENTRY' can be
+ stepped through, line by line, in `gdb'.
+
+ * Fix a profiling-related bug in `gcc' back end for Intel x86
+ architecture.
+
+ * Allow any `REAL' argument to intrinsics `Second' and `CPU_Time'.
+
+ * Allow any numeric argument to intrinsics `Int2' and `Int8'.
+
+ * Use `tempnam', if available, to open scratch files (as in
+ `OPEN(STATUS='SCRATCH')') so that the `TMPDIR' environment
+ variable, if present, is used.
+
+ * Rename the `gcc' keyword `restrict' to `__restrict__', to avoid
+ rejecting valid, existing, C programs. Support for `restrict' is
+ now more like support for `complex'.
+
+ * Fix `-fpedantic' to not reject procedure invocations such as
+ `I=J()' and `CALL FOO()'.
+
+ * Fix `-fugly-comma' to affect invocations of only external
+ procedures. Restore rejection of gratuitous trailing omitted
+ arguments to intrinsics, as in `I=MAX(3,4,,)'.
+
+ * Fix compiler so it accepts `-fgnu-intrinsics-*' and
+ `-fbadu77-intrinsics-*' options.
+
+ * Improve diagnostic messages from `libf2c' so it is more likely
+ that the printing of the active format string is limited to the
+ string, with no trailing garbage being printed.
+
+ (Unlike `f2c', `g77' did not append a null byte to its compiled
+ form of every format string specified via a `FORMAT' statement.
+ However, `f2c' would exhibit the problem anyway for a statement
+ like `PRINT '(I)garbage', 1' by printing `(I)garbage' as the
+ format string.)
+
+ * Improve compilation of `FORMAT' expressions so that a null byte is
+ appended to the last operand if it is a constant. This provides a
+ cleaner run-time diagnostic as provided by `libf2c' for statements
+ like `PRINT '(I1', 42'.
+
+ * Fix various crashes involving code with diagnosed errors.
+
+ * Fix cross-compilation bug when configuring `libf2c'.
+
+ * Improve diagnostics.
+
+ * Improve documentation and indexing.
+
+ * Upgrade to `libf2c' as of 1997-09-23. This fixes a formatted-I/O
+ bug that afflicted 64-bit systems with 32-bit integers (such as
+ Digital Alpha running GNU/Linux).
+
+In `egcs' 1.0.2 (versus `egcs' 1.0.1):
+======================================
+
+ * Fix `g77' crash triggered by `CASE' statement with an omitted
+ lower or upper bound.
+
+ * Fix `g77' crash on statements such as `PRINT *,
+ (REAL(Z(I)),I=1,2)', where `Z' is `DOUBLE COMPLEX'.
+
+ * Fix `-fPIC' (such as compiling for ELF targets) on the Intel x86
+ architecture target so invalid assembler code is no longer
+ produced.
+
+ * Fix `-fpedantic' to not reject procedure invocations such as
+ `I=J()' and `CALL FOO()'.
+
+ * Fix `-fugly-comma' to affect invocations of only external
+ procedures. Restore rejection of gratuitous trailing omitted
+ arguments to intrinsics, as in `I=MAX(3,4,,)'.
+
+ * Fix compiler so it accepts `-fgnu-intrinsics-*' and
+ `-fbadu77-intrinsics-*' options.
+
+In `egcs' 1.0.1 (versus `egcs' 1.0):
+====================================
+
+ * Fix run-time crash involving `NAMELIST' on 64-bit machines such as
+ Alphas.
+
+In `egcs' 1.0 (versus 0.5.21):
+==============================
+
+ * Version 1.0 of `egcs' contains several regressions against version
+ 0.5.21 of `g77', due to using the "vanilla" `gcc' back end instead
+ of patching it to fix a few bugs and improve performance in a few
+ cases.
+
+ See `egcs/gcc/f/BUGS', for information on the known bugs in this
+ version, including the regressions.
+
+ Features that have been dropped from this version of `g77' due to
+ their being implemented via `g77'-specific patches to the `gcc'
+ back end in previous releases include:
+
+ - Support for the C-language `restrict' keyword.
+
+ - Support for the `-W' option warning about integer division by
+ zero.
+
+ - The Intel x86-specific option `-malign-double' applying to
+ stack-allocated data as well as statically-allocate data.
+
+ Note that the `gcc/f/gbe/' subdirectory has been removed from this
+ distribution as a result of `g77' being fully integrated with the
+ `egcs' variant of the `gcc' back end.
+
+ * Fix code generation for iterative `DO' loops that have one or more
+ references to the iteration variable, or to aliases of it, in
+ their control expressions. For example, `DO 10 J=2,J' now is
+ compiled correctly.
+
+ * Fix `DTime' intrinsic so as not to truncate results to integer
+ values (on some systems).
+
+ * Remove support for non-`egcs' versions of `gcc'.
+
+ * Remove support for the `--driver' option, as `g77' now does all
+ the driving, just like `gcc'.
+
+ * Allow any numeric argument to intrinsics `Int2' and `Int8'.
+
+ * Improve diagnostic messages from `libf2c' so it is more likely
+ that the printing of the active format string is limited to the
+ string, with no trailing garbage being printed.
+
+ (Unlike `f2c', `g77' did not append a null byte to its compiled
+ form of every format string specified via a `FORMAT' statement.
+ However, `f2c' would exhibit the problem anyway for a statement
+ like `PRINT '(I)garbage', 1' by printing `(I)garbage' as the
+ format string.)
+
+ * Upgrade to `libf2c' as of 1997-09-23. This fixes a formatted-I/O
+ bug that afflicted 64-bit systems with 32-bit integers (such as
+ Digital Alpha running GNU/Linux).
+
+In 0.5.21:
+==========
+
+ * Fix a code-generation bug introduced by 0.5.20 caused by loop
+ unrolling (by specifying `-funroll-loops' or similar). This bug
+ afflicted all code compiled by version 2.7.2.2.f.2 of `gcc' (C,
+ C++, Fortran, and so on).
+
+ * Fix a code-generation bug manifested when combining local
+ `EQUIVALENCE' with a `DATA' statement that follows the first
+ executable statement (or is treated as an executable-context
+ statement as a result of using the `-fpedantic' option).
+
+ * Fix a compiler crash that occured when an integer division by a
+ constant zero is detected. Instead, when the `-W' option is
+ specified, the `gcc' back end issues a warning about such a case.
+ This bug afflicted all code compiled by version 2.7.2.2.f.2 of
+ `gcc' (C, C++, Fortran, and so on).
+
+ * Fix a compiler crash that occurred in some cases of procedure
+ inlining. (Such cases became more frequent in 0.5.20.)
+
+ * Fix a compiler crash resulting from using `DATA' or similar to
+ initialize a `COMPLEX' variable or array to zero.
+
+ * Fix compiler crashes involving use of `AND', `OR', or `XOR'
+ intrinsics.
+
+ * Fix compiler bug triggered when using a `COMMON' or `EQUIVALENCE'
+ variable as the target of an `ASSIGN' or assigned-`GOTO' statement.
+
+ * Fix compiler crashes due to using the name of a some non-standard
+ intrinsics (such as `FTELL' or `FPUTC') as such and as the name of
+ a procedure or common block. Such dual use of a name in a program
+ is allowed by the standard.
+
+ * Place automatic arrays on the stack, even if `SAVE' or the
+ `-fno-automatic' option is in effect. This avoids a compiler
+ crash in some cases.
+
+ * The `-malign-double' option now reliably aligns `DOUBLE PRECISION'
+ optimally on Pentium and Pentium Pro architectures (586 and 686 in
+ `gcc').
+
+ * New option `-Wno-globals' disables warnings about "suspicious" use
+ of a name both as a global name and as the implicit name of an
+ intrinsic, and warnings about disagreements over the number or
+ natures of arguments passed to global procedures, or the natures
+ of the procedures themselves.
+
+ The default is to issue such warnings, which are new as of this
+ version of `g77'.
+
+ * New option `-fno-globals' disables diagnostics about potentially
+ fatal disagreements analysis problems, such as disagreements over
+ the number or natures of arguments passed to global procedures, or
+ the natures of those procedures themselves.
+
+ The default is to issue such diagnostics and flag the compilation
+ as unsuccessful. With this option, the diagnostics are issued as
+ warnings, or, if `-Wno-globals' is specified, are not issued at
+ all.
+
+ This option also disables inlining of global procedures, to avoid
+ compiler crashes resulting from coding errors that these
+ diagnostics normally would identify.
+
+ * Diagnose cases where a reference to a procedure disagrees with the
+ type of that procedure, or where disagreements about the number or
+ nature of arguments exist. This avoids a compiler crash.
+
+ * Fix parsing bug whereby `g77' rejected a second initialization
+ specification immediately following the first's closing `/' without
+ an intervening comma in a `DATA' statement, and the second
+ specification was an implied-DO list.
+
+ * Improve performance of the `gcc' back end so certain complicated
+ expressions involving `COMPLEX' arithmetic (especially
+ multiplication) don't appear to take forever to compile.
+
+ * Fix a couple of profiling-related bugs in `gcc' back end.
+
+ * Integrate GNU Ada's (GNAT's) changes to the back end, which
+ consist almost entirely of bug fixes. These fixes are circa
+ version 3.10p of GNAT.
+
+ * Include some other `gcc' fixes that seem useful in `g77''s version
+ of `gcc'. (See `gcc/ChangeLog' for details--compare it to that
+ file in the vanilla `gcc-2.7.2.3.tar.gz' distribution.)
+
+ * Fix `libU77' routines that accept file and other names to strip
+ trailing blanks from them, for consistency with other
+ implementations. Blanks may be forcibly appended to such names by
+ appending a single null character (`CHAR(0)') to the significant
+ trailing blanks.
+
+ * Fix `CHMOD' intrinsic to work with file names that have embedded
+ blanks, commas, and so on.
+
+ * Fix `SIGNAL' intrinsic so it accepts an optional third `Status'
+ argument.
+
+ * Fix `IDATE()' intrinsic subroutine (VXT form) so it accepts
+ arguments in the correct order. Documentation fixed accordingly,
+ and for `GMTIME()' and `LTIME()' as well.
+
+ * Make many changes to `libU77' intrinsics to support existing code
+ more directly.
+
+ Such changes include allowing both subroutine and function forms
+ of many routines, changing `MCLOCK()' and `TIME()' to return
+ `INTEGER(KIND=1)' values, introducing `MCLOCK8()' and `TIME8()' to
+ return `INTEGER(KIND=2)' values, and placing functions that are
+ intended to perform side effects in a new intrinsic group,
+ `badu77'.
+
+ * Improve `libU77' so it is more portable.
+
+ * Add options `-fbadu77-intrinsics-delete',
+ `-fbadu77-intrinsics-hide', and so on.
+
+ * Fix crashes involving diagnosed or invalid code.
+
+ * `g77' and `gcc' now do a somewhat better job detecting and
+ diagnosing arrays that are too large to handle before these cause
+ diagnostics during the assembler or linker phase, a compiler
+ crash, or generation of incorrect code.
+
+ * Make some fixes to alias analysis code.
+
+ * Add support for `restrict' keyword in `gcc' front end.
+
+ * Support `gcc' version 2.7.2.3 (modified by `g77' into version
+ 2.7.2.3.f.1), and remove support for prior versions of `gcc'.
+
+ * Incorporate GNAT's patches to the `gcc' back end into `g77''s, so
+ GNAT users do not need to apply GNAT's patches to build both GNAT
+ and `g77' from the same source tree.
+
+ * Modify `make' rules and related code so that generation of Info
+ documentation doesn't require compilation using `gcc'. Now, any
+ ANSI C compiler should be adequate to produce the `g77'
+ documentation (in particular, the tables of intrinsics) from
+ scratch.
+
+ * Add `INT2' and `INT8' intrinsics.
+
+ * Add `CPU_TIME' intrinsic.
+
+ * Add `ALARM' intrinsic.
+
+ * `CTIME' intrinsic now accepts any `INTEGER' argument, not just
+ `INTEGER(KIND=2)'.
+
+ * Warn when explicit type declaration disagrees with the type of an
+ intrinsic invocation.
+
+ * Support `*f771' entry in `gcc' `specs' file.
+
+ * Fix typo in `make' rule `g77-cross', used only for cross-compiling.
+
+ * Fix `libf2c' build procedure to re-archive library if previous
+ attempt to archive was interrupted.
+
+ * Change `gcc' to unroll loops only during the last invocation (of
+ as many as two invocations) of loop optimization.
+
+ * Improve handling of `-fno-f2c' so that code that attempts to pass
+ an intrinsic as an actual argument, such as `CALL FOO(ABS)', is
+ rejected due to the fact that the run-time-library routine is,
+ effectively, compiled with `-ff2c' in effect.
+
+ * Fix `g77' driver to recognize `-fsyntax-only' as an option that
+ inhibits linking, just like `-c' or `-S', and to recognize and
+ properly handle the `-nostdlib', `-M', `-MM', `-nodefaultlibs',
+ and `-Xlinker' options.
+
+ * Upgrade to `libf2c' as of 1997-08-16.
+
+ * Modify `libf2c' to consistently and clearly diagnose recursive I/O
+ (at run time).
+
+ * `g77' driver now prints version information (such as produced by
+ `g77 -v') to `stderr' instead of `stdout'.
+
+ * The `.r' suffix now designates a Ratfor source file, to be
+ preprocessed via the `ratfor' command, available separately.
+
+ * Fix some aspects of how `gcc' determines what kind of system is
+ being configured and what kinds are supported. For example, GNU
+ Linux/Alpha ELF systems now are directly supported.
+
+ * Improve diagnostics.
+
+ * Improve documentation and indexing.
+
+ * Include all pertinent files for `libf2c' that come from
+ `netlib.bell-labs.com'; give any such files that aren't quite
+ accurate in `g77''s version of `libf2c' the suffix `.netlib'.
+
+ * Reserve `INTEGER(KIND=0)' for future use.
+
+In 0.5.20:
+==========
+
+ * The `-fno-typeless-boz' option is now the default.
+
+ This option specifies that non-decimal-radix constants using the
+ prefixed-radix form (such as `Z'1234'') are to be interpreted as
+ `INTEGER' constants. Specify `-ftypeless-boz' to cause such
+ constants to be interpreted as typeless.
+
+ (Version 0.5.19 introduced `-fno-typeless-boz' and its inverse.)
+
+ * Options `-ff90-intrinsics-enable' and `-fvxt-intrinsics-enable'
+ now are the defaults.
+
+ Some programs might use names that clash with intrinsic names
+ defined (and now enabled) by these options or by the new `libU77'
+ intrinsics. Users of such programs might need to compile them
+ differently (using, for example, `-ff90-intrinsics-disable') or,
+ better yet, insert appropriate `EXTERNAL' statements specifying
+ that these names are not intended to be names of intrinsics.
+
+ * The `ALWAYS_FLUSH' macro is no longer defined when building
+ `libf2c', which should result in improved I/O performance,
+ especially over NFS.
+
+ *Note:* If you have code that depends on the behavior of `libf2c'
+ when built with `ALWAYS_FLUSH' defined, you will have to modify
+ `libf2c' accordingly before building it from this and future
+ versions of `g77'.
+
+ * Dave Love's implementation of `libU77' has been added to the
+ version of `libf2c' distributed with and built as part of `g77'.
+ `g77' now knows about the routines in this library as intrinsics.
+
+ * New option `-fvxt' specifies that the source file is written in
+ VXT Fortran, instead of GNU Fortran.
+
+ * The `-fvxt-not-f90' option has been deleted, along with its
+ inverse, `-ff90-not-vxt'.
+
+ If you used one of these deleted options, you should re-read the
+ pertinent documentation to determine which options, if any, are
+ appropriate for compiling your code with this version of `g77'.
+
+ * The `-fugly' option now issues a warning, as it likely will be
+ removed in a future version.
+
+ (Enabling all the `-fugly-*' options is unlikely to be feasible,
+ or sensible, in the future, so users should learn to specify only
+ those `-fugly-*' options they really need for a particular source
+ file.)
+
+ * The `-fugly-assumed' option, introduced in version 0.5.19, has
+ been changed to better accommodate old and new code.
+
+ * Make a number of fixes to the `g77' front end and the `gcc' back
+ end to better support Alpha (AXP) machines. This includes
+ providing at least one bug-fix to the `gcc' back end for Alphas.
+
+ * Related to supporting Alpha (AXP) machines, the `LOC()' intrinsic
+ and `%LOC()' construct now return values of integer type that is
+ the same width (holds the same number of bits) as the pointer type
+ on the machine.
+
+ On most machines, this won't make a difference, whereas on Alphas,
+ the type these constructs return is `INTEGER*8' instead of the
+ more common `INTEGER*4'.
+
+ * Emulate `COMPLEX' arithmetic in the `g77' front end, to avoid bugs
+ in `complex' support in the `gcc' back end. New option
+ `-fno-emulate-complex' causes `g77' to revert the 0.5.19 behavior.
+
+ * Fix bug whereby `REAL A(1)', for example, caused a compiler crash
+ if `-fugly-assumed' was in effect and A was a local (automatic)
+ array. That case is no longer affected by the new handling of
+ `-fugly-assumed'.
+
+ * Fix `g77' command driver so that `g77 -o foo.f' no longer deletes
+ `foo.f' before issuing other diagnostics, and so the `-x' option
+ is properly handled.
+
+ * Enable inlining of subroutines and functions by the `gcc' back end.
+ This works as it does for `gcc' itself--program units may be
+ inlined for invocations that follow them in the same program unit,
+ as long as the appropriate compile-time options are specified.
+
+ * Dummy arguments are no longer assumed to potentially alias
+ (overlap) other dummy arguments or `COMMON' areas when any of
+ these are defined (assigned to) by Fortran code.
+
+ This can result in faster and/or smaller programs when compiling
+ with optimization enabled, though on some systems this effect is
+ observed only when `-fforce-addr' also is specified.
+
+ New options `-falias-check', `-fargument-alias',
+ `-fargument-noalias', and `-fno-argument-noalias-global' control
+ the way `g77' handles potential aliasing.
+
+ * The `CONJG()' and `DCONJG()' intrinsics now are compiled in-line.
+
+ * The bug-fix for 0.5.19.1 has been re-done. The `g77' compiler has
+ been changed back to assume `libf2c' has no aliasing problems in
+ its implementations of the `COMPLEX' (and `DOUBLE COMPLEX')
+ intrinsics. The `libf2c' has been changed to have no such
+ problems.
+
+ As a result, 0.5.20 is expected to offer improved performance over
+ 0.5.19.1, perhaps as good as 0.5.19 in most or all cases, due to
+ this change alone.
+
+ *Note:* This change requires version 0.5.20 of `libf2c', at least,
+ when linking code produced by any versions of `g77' other than
+ 0.5.19.1. Use `g77 -v' to determine the version numbers of the
+ `libF77', `libI77', and `libU77' components of the `libf2c'
+ library. (If these version numbers are not printed--in
+ particular, if the linker complains about unresolved references to
+ names like `g77__fvers__'--that strongly suggests your
+ installation has an obsolete version of `libf2c'.)
+
+ * New option `-fugly-assign' specifies that the same memory
+ locations are to be used to hold the values assigned by both
+ statements `I = 3' and `ASSIGN 10 TO I', for example. (Normally,
+ `g77' uses a separate memory location to hold assigned statement
+ labels.)
+
+ * `FORMAT' and `ENTRY' statements now are allowed to precede
+ `IMPLICIT NONE' statements.
+
+ * Produce diagnostic for unsupported `SELECT CASE' on `CHARACTER'
+ type, instead of crashing, at compile time.
+
+ * Fix crashes involving diagnosed or invalid code.
+
+ * Change approach to building `libf2c' archive (`libf2c.a') so that
+ members are added to it only when truly necessary, so the user
+ that installs an already-built `g77' doesn't need to have write
+ access to the build tree (whereas the user doing the build might
+ not have access to install new software on the system).
+
+ * Support `gcc' version 2.7.2.2 (modified by `g77' into version
+ 2.7.2.2.f.2), and remove support for prior versions of `gcc'.
+
+ * Upgrade to `libf2c' as of 1997-02-08, and fix up some of the build
+ procedures.
+
+ * Improve general build procedures for `g77', fixing minor bugs
+ (such as deletion of any file named `f771' in the parent directory
+ of `gcc/').
+
+ * Enable full support of `INTEGER*8' available in `libf2c' and
+ `f2c.h' so that `f2c' users may make full use of its features via
+ the `g77' version of `f2c.h' and the `INTEGER*8' support routines
+ in the `g77' version of `libf2c'.
+
+ * Improve `g77' driver and `libf2c' so that `g77 -v' yields version
+ information on the library.
+
+ * The `SNGL' and `FLOAT' intrinsics now are specific intrinsics,
+ instead of synonyms for the generic intrinsic `REAL'.
+
+ * New intrinsics have been added. These are `REALPART', `IMAGPART',
+ `COMPLEX', `LONG', and `SHORT'.
+
+ * A new group of intrinsics, `gnu', has been added to contain the
+ new `REALPART', `IMAGPART', and `COMPLEX' intrinsics. An old
+ group, `dcp', has been removed.
+
+ * Complain about industry-wide ambiguous references `REAL(EXPR)' and
+ `AIMAG(EXPR)', where EXPR is `DOUBLE COMPLEX' (or any complex type
+ other than `COMPLEX'), unless `-ff90' option specifies Fortran 90
+ interpretation or new `-fugly-complex' option, in conjunction with
+ `-fnot-f90', specifies `f2c' interpretation.
+
+ * Make improvements to diagnostics.
+
+ * Speed up compiler a bit.
+
+ * Improvements to documentation and indexing, including a new
+ chapter containing information on one, later more, diagnostics
+ that users are directed to pull up automatically via a message in
+ the diagnostic itself.
+
+ (Hence the menu item `M' for the node `Diagnostics' in the
+ top-level menu of the Info documentation.)
+
+In 0.5.19.1:
+============
+
+ * Code-generation bugs afflicting operations on complex data have
+ been fixed.
+
+ These bugs occurred when assigning the result of an operation to a
+ complex variable (or array element) that also served as an input
+ to that operation.
+
+ The operations affected by this bug were: `CONJG()', `DCONJG()',
+ `CCOS()', `CDCOS()', `CLOG()', `CDLOG()', `CSIN()', `CDSIN()',
+ `CSQRT()', `CDSQRT()', complex division, and raising a `DOUBLE
+ COMPLEX' operand to an `INTEGER' power. (The related generic and
+ `Z'-prefixed intrinsics, such as `ZSIN()', also were affected.)
+
+ For example, `C = CSQRT(C)', `Z = Z/C', and `Z = Z**I' (where `C'
+ is `COMPLEX' and `Z' is `DOUBLE COMPLEX') have been fixed.
+
+In 0.5.19:
+==========
+
+ * Fix `FORMAT' statement parsing so negative values for specifiers
+ such as `P' (e.g. `FORMAT(-1PF8.1)') are correctly processed as
+ negative.
+
+ * Fix `SIGNAL' intrinsic so it once again accepts a procedure as its
+ second argument.
+
+ * A temporary kludge option provides bare-bones information on
+ `COMMON' and `EQUIVALENCE' members at debug time.
+
+ * New `-fonetrip' option specifies FORTRAN-66-style one-trip `DO'
+ loops.
+
+ * New `-fno-silent' option causes names of program units to be
+ printed as they are compiled, in a fashion similar to UNIX `f77'
+ and `f2c'.
+
+ * New `-fugly-assumed' option specifies that arrays dimensioned via
+ `DIMENSION X(1)', for example, are to be treated as assumed-size.
+
+ * New `-fno-typeless-boz' option specifies that non-decimal-radix
+ constants using the prefixed-radix form (such as `Z'1234'') are to
+ be interpreted as `INTEGER' constants.
+
+ * New `-ff66' option is a "shorthand" option that specifies
+ behaviors considered appropriate for FORTRAN 66 programs.
+
+ * New `-ff77' option is a "shorthand" option that specifies
+ behaviors considered appropriate for UNIX `f77' programs.
+
+ * New `-fugly-comma' and `-fugly-logint' options provided to perform
+ some of what `-fugly' used to do. `-fugly' and `-fno-ugly' are
+ now "shorthand" options, in that they do nothing more than enable
+ (or disable) other `-fugly-*' options.
+
+ * Fix parsing of assignment statements involving targets that are
+ substrings of elements of `CHARACTER' arrays having names such as
+ `READ', `WRITE', `GOTO', and `REALFUNCTIONFOO'.
+
+ * Fix crashes involving diagnosed code.
+
+ * Fix handling of local `EQUIVALENCE' areas so certain cases of
+ valid Fortran programs are not misdiagnosed as improperly
+ extending the area backwards.
+
+ * Support `gcc' version 2.7.2.1.
+
+ * Upgrade to `libf2c' as of 1996-09-26, and fix up some of the build
+ procedures.
+
+ * Change code generation for list-directed I/O so it allows for new
+ versions of `libf2c' that might return non-zero status codes for
+ some operations previously assumed to always return zero.
+
+ This change not only affects how `IOSTAT=' variables are set by
+ list-directed I/O, it also affects whether `END=' and `ERR='
+ labels are reached by these operations.
+
+ * Add intrinsic support for new `FTELL' and `FSEEK' procedures in
+ `libf2c'.
+
+ * Modify `fseek_()' in `libf2c' to be more portable (though, in
+ practice, there might be no systems where this matters) and to
+ catch invalid `whence' arguments.
+
+ * Some useless warnings from the `-Wunused' option have been
+ eliminated.
+
+ * Fix a problem building the `f771' executable on AIX systems by
+ linking with the `-bbigtoc' option.
+
+ * Abort configuration if `gcc' has not been patched using the patch
+ file provided in the `gcc/f/gbe/' subdirectory.
+
+ * Add options `--help' and `--version' to the `g77' command, to
+ conform to GNU coding guidelines. Also add printing of `g77'
+ version number when the `--verbose' (`-v') option is used.
+
+ * Change internally generated name for local `EQUIVALENCE' areas to
+ one based on the alphabetically sorted first name in the list of
+ names for entities placed at the beginning of the areas.
+
+ * Improvements to documentation and indexing.
+
+In 0.5.18:
+==========
+
+ * Add some rudimentary support for `INTEGER*1', `INTEGER*2',
+ `INTEGER*8', and their `LOGICAL' equivalents. (This support works
+ on most, maybe all, `gcc' targets.)
+
+ Thanks to Scott Snyder (<snyder@d0sgif.fnal.gov>) for providing
+ the patch for this!
+
+ Among the missing elements from the support for these features are
+ full intrinsic support and constants.
+
+ * Add some rudimentary support for the `BYTE' and `WORD'
+ type-declaration statements. `BYTE' corresponds to `INTEGER*1',
+ while `WORD' corresponds to `INTEGER*2'.
+
+ Thanks to Scott Snyder (<snyder@d0sgif.fnal.gov>) for providing
+ the patch for this!
+
+ * The compiler code handling intrinsics has been largely rewritten
+ to accommodate the new types. No new intrinsics or arguments for
+ existing intrinsics have been added, so there is, at this point,
+ no intrinsic to convert to `INTEGER*8', for example.
+
+ * Support automatic arrays in procedures.
+
+ * Reduce space/time requirements for handling large *sparsely*
+ initialized aggregate arrays. This improvement applies to only a
+ subset of the general problem to be addressed in 0.6.
+
+ * Treat initial values of zero as if they weren't specified (in DATA
+ and type-declaration statements). The initial values will be set
+ to zero anyway, but the amount of compile time processing them
+ will be reduced, in some cases significantly (though, again, this
+ is only a subset of the general problem to be addressed in 0.6).
+
+ A new option, `-fzeros', is introduced to enable the traditional
+ treatment of zeros as any other value.
+
+ * With `-ff90' in force, `g77' incorrectly interpreted `REAL(Z)' as
+ returning a `REAL' result, instead of as a `DOUBLE PRECISION'
+ result. (Here, `Z' is `DOUBLE COMPLEX'.)
+
+ With `-fno-f90' in force, the interpretation remains unchanged,
+ since this appears to be how at least some F77 code using the
+ `DOUBLE COMPLEX' extension expected it to work.
+
+ Essentially, `REAL(Z)' in F90 is the same as `DBLE(Z)', while in
+ extended F77, it appears to be the same as `REAL(REAL(Z))'.
+
+ * An expression involving exponentiation, where both operands were
+ type `INTEGER' and the right-hand operand was negative, was
+ erroneously evaluated.
+
+ * Fix bugs involving `DATA' implied-`DO' constructs (these involved
+ an errant diagnostic and a crash, both on good code, one involving
+ subsequent statement-function definition).
+
+ * Close `INCLUDE' files after processing them, so compiling source
+ files with lots of `INCLUDE' statements does not result in being
+ unable to open `INCLUDE' files after all the available file
+ descriptors are used up.
+
+ * Speed up compiling, especially of larger programs, and perhaps
+ slightly reduce memory utilization while compiling (this is *not*
+ the improvement planned for 0.6 involving large aggregate
+ areas)--these improvements result from simply turning off some
+ low-level code to do self-checking that hasn't been triggered in a
+ long time.
+
+ * Introduce three new options that implement optimizations in the
+ `gcc' back end (GBE). These options are `-fmove-all-movables',
+ `-freduce-all-givs', and `-frerun-loop-opt', which are enabled, by
+ default, for Fortran compilations. These optimizations are
+ intended to help toon Fortran programs.
+
+ * Patch the GBE to do a better job optimizing certain kinds of
+ references to array elements.
+
+ * Due to patches to the GBE, the version number of `gcc' also is
+ patched to make it easier to manage installations, especially
+ useful if it turns out a `g77' change to the GBE has a bug.
+
+ The `g77'-modified version number is the `gcc' version number with
+ the string `.f.N' appended, where `f' identifies the version as
+ enhanced for Fortran, and N is `1' for the first Fortran patch for
+ that version of `gcc', `2' for the second, and so on.
+
+ So, this introduces version 2.7.2.f.1 of `gcc'.
+
+ * Make several improvements and fixes to diagnostics, including the
+ removal of two that were inappropriate or inadequate.
+
+ * Warning about two successive arithmetic operators, produced by
+ `-Wsurprising', now produced *only* when both operators are,
+ indeed, arithmetic (not relational/boolean).
+
+ * `-Wsurprising' now warns about the remaining cases of using
+ non-integral variables for implied-`DO' loops, instead of these
+ being rejected unless `-fpedantic' or `-fugly' specified.
+
+ * Allow `SAVE' of a local variable or array, even after it has been
+ given an initial value via `DATA', for example.
+
+ * Introduce an Info version of `g77' documentation, which supercedes
+ `gcc/f/CREDITS', `gcc/f/DOC', and `gcc/f/PROJECTS'. These files
+ will be removed in a future release. The files `gcc/f/BUGS',
+ `gcc/f/INSTALL', and `gcc/f/NEWS' now are automatically built from
+ the texinfo source when distributions are made.
+
+ This effort was inspired by a first pass at translating
+ `g77-0.5.16/f/DOC' that was contributed to Craig by David Ronis
+ (<ronis@onsager.chem.mcgill.ca>).
+
+ * New `-fno-second-underscore' option to specify that, when
+ `-funderscoring' is in effect, a second underscore is not to be
+ appended to Fortran names already containing an underscore.
+
+ * Change the way iterative `DO' loops work to follow the F90
+ standard. In particular, calculation of the iteration count is
+ still done by converting the start, end, and increment parameters
+ to the type of the `DO' variable, but the result of the
+ calculation is always converted to the default `INTEGER' type.
+
+ (This should have no effect on existing code compiled by `g77',
+ but code written to assume that use of a *wider* type for the `DO'
+ variable will result in an iteration count being fully calculated
+ using that wider type (wider than default `INTEGER') must be
+ rewritten.)
+
+ * Support `gcc' version 2.7.2.
+
+ * Upgrade to `libf2c' as of 1996-03-23, and fix up some of the build
+ procedures.
+
+ Note that the email addresses related to `f2c' have changed--the
+ distribution site now is named `netlib.bell-labs.com', and the
+ maintainer's new address is <dmg@bell-labs.com>.
+
+In 0.5.17:
+==========
+
+ * *Fix serious bug* in `g77 -v' command that can cause removal of a
+ system's `/dev/null' special file if run by user `root'.
+
+ *All users* of version 0.5.16 should ensure that they have not
+ removed `/dev/null' or replaced it with an ordinary file (e.g. by
+ comparing the output of `ls -l /dev/null' with `ls -l /dev/zero'.
+ If the output isn't basically the same, contact your system
+ administrator about restoring `/dev/null' to its proper status).
+
+ This bug is particularly insidious because removing `/dev/null' as
+ a special file can go undetected for quite a while, aside from
+ various applications and programs exhibiting sudden, strange
+ behaviors.
+
+ I sincerely apologize for not realizing the implications of the
+ fact that when `g77 -v' runs the `ld' command with `-o /dev/null'
+ that `ld' tries to *remove* the executable it is supposed to build
+ (especially if it reports unresolved references, which it should
+ in this case)!
+
+ * Fix crash on `CHARACTER*(*) FOO' in a main or block data program
+ unit.
+
+ * Fix crash that can occur when diagnostics given outside of any
+ program unit (such as when input file contains `@foo').
+
+ * Fix crashes, infinite loops (hangs), and such involving diagnosed
+ code.
+
+ * Fix `ASSIGN''ed variables so they can be `SAVE''d or dummy
+ arguments, and issue clearer error message in cases where target
+ of `ASSIGN' or `ASSIGN'ed `GOTO'/`FORMAT' is too small (which
+ should never happen).
+
+ * Make `libf2c' build procedures work on more systems again by
+ eliminating unnecessary invocations of `ld -r -x' and `mv'.
+
+ * Fix omission of `-funix-intrinsics-...' options in list of
+ permitted options to compiler.
+
+ * Fix failure to always diagnose missing type declaration for
+ `IMPLICIT NONE'.
+
+ * Fix compile-time performance problem (which could sometimes crash
+ the compiler, cause a hang, or whatever, due to a bug in the back
+ end) involving exponentiation with a large `INTEGER' constant for
+ the right-hand operator (e.g. `I**32767').
+
+ * Fix build procedures so cross-compiling `g77' (the `fini' utility
+ in particular) is properly built using the host compiler.
+
+ * Add new `-Wsurprising' option to warn about constructs that are
+ interpreted by the Fortran standard (and `g77') in ways that are
+ surprising to many programmers.
+
+ * Add `ERF()' and `ERFC()' as generic intrinsics mapping to existing
+ `ERF'/`DERF' and `ERFC'/`DERFC' specific intrinsics.
+
+ *Note:* You should specify `INTRINSIC ERF,ERFC' in any code where
+ you might use these as generic intrinsics, to improve likelihood
+ of diagnostics (instead of subtle run-time bugs) when using a
+ compiler that doesn't support these as intrinsics (e.g. `f2c').
+
+ * Remove from `-fno-pedantic' the diagnostic about `DO' with
+ non-`INTEGER' index variable; issue that under `-Wsurprising'
+ instead.
+
+ * Clarify some diagnostics that say things like "ignored" when that's
+ misleading.
+
+ * Clarify diagnostic on use of `.EQ.'/`.NE.' on `LOGICAL' operands.
+
+ * Minor improvements to code generation for various operations on
+ `LOGICAL' operands.
+
+ * Minor improvement to code generation for some `DO' loops on some
+ machines.
+
+ * Support `gcc' version 2.7.1.
+
+ * Upgrade to `libf2c' as of 1995-11-15.
+
+In 0.5.16:
+==========
+
+ * Fix a code-generation bug involving complicated `EQUIVALENCE'
+ statements not involving `COMMON'.
+
+ * Fix code-generation bugs involving invoking "gratis" library
+ procedures in `libf2c' from code compiled with `-fno-f2c' by
+ making these procedures known to `g77' as intrinsics (not affected
+ by -fno-f2c). This is known to fix code invoking `ERF()',
+ `ERFC()', `DERF()', and `DERFC()'.
+
+ * Update `libf2c' to include netlib patches through 1995-08-16, and
+ `#define' `WANT_LEAD_0' to 1 to make `g77'-compiled code more
+ consistent with other Fortran implementations by outputting
+ leading zeros in formatted and list-directed output.
+
+ * Fix a code-generation bug involving adjustable dummy arrays with
+ high bounds whose primaries are changed during procedure
+ execution, and which might well improve code-generation
+ performance for such arrays compared to `f2c' plus `gcc' (but
+ apparently only when using `gcc-2.7.0' or later).
+
+ * Fix a code-generation bug involving invocation of `COMPLEX' and
+ `DOUBLE COMPLEX' `FUNCTION's and doing `COMPLEX' and `DOUBLE
+ COMPLEX' divides, when the result of the invocation or divide is
+ assigned directly to a variable that overlaps one or more of the
+ arguments to the invocation or divide.
+
+ * Fix crash by not generating new optimal code for `X**I' if `I' is
+ nonconstant and the expression is used to dimension a dummy array,
+ since the `gcc' back end does not support the necessary mechanics
+ (and the `gcc' front end rejects the equivalent construct, as it
+ turns out).
+
+ * Fix crash on expressions like `COMPLEX**INTEGER'.
+
+ * Fix crash on expressions like `(1D0,2D0)**2', i.e. raising a
+ `DOUBLE COMPLEX' constant to an `INTEGER' constant power.
+
+ * Fix crashes and such involving diagnosed code.
+
+ * Diagnose, instead of crashing on, statement function definitions
+ having duplicate dummy argument names.
+
+ * Fix bug causing rejection of good code involving statement function
+ definitions.
+
+ * Fix bug resulting in debugger not knowing size of local equivalence
+ area when any member of area has initial value (via `DATA', for
+ example).
+
+ * Fix installation bug that prevented installation of `g77' driver.
+ Provide for easy selection of whether to install copy of `g77' as
+ `f77' to replace the broken code.
+
+ * Fix `gcc' driver (affects `g77' thereby) to not gratuitously
+ invoke the `f771' program (e.g. when `-E' is specified).
+
+ * Fix diagnostic to point to correct source line when it immediately
+ follows an `INCLUDE' statement.
+
+ * Support more compiler options in `gcc'/`g77' when compiling
+ Fortran files. These options include `-p', `-pg', `-aux-info',
+ `-P', correct setting of version-number macros for preprocessing,
+ full recognition of `-O0', and automatic insertion of
+ configuration-specific linker specs.
+
+ * Add new intrinsics that interface to existing routines in `libf2c':
+ `ABORT', `DERF', `DERFC', `ERF', `ERFC', `EXIT', `FLUSH',
+ `GETARG', `GETENV', `IARGC', `SIGNAL', and `SYSTEM'. Note that
+ `ABORT', `EXIT', `FLUSH', `SIGNAL', and `SYSTEM' are intrinsic
+ subroutines, not functions (since they have side effects), so to
+ get the return values from `SIGNAL' and `SYSTEM', append a final
+ argument specifying an `INTEGER' variable or array element (e.g.
+ `CALL SYSTEM('rm foo',ISTAT)').
+
+ * Add new intrinsic group named `unix' to contain the new intrinsics,
+ and by default enable this new group.
+
+ * Move `LOC()' intrinsic out of the `vxt' group to the new `unix'
+ group.
+
+ * Improve `g77' so that `g77 -v' by itself (or with certain other
+ options, including `-B', `-b', `-i', `-nostdlib', and `-V')
+ reports lots more useful version info, and so that long-form
+ options `gcc' accepts are understood by `g77' as well (even in
+ truncated, unambiguous forms).
+
+ * Add new `g77' option `--driver=name' to specify driver when
+ default, `gcc', isn't appropriate.
+
+ * Add support for `#' directives (as output by the preprocessor) in
+ the compiler, and enable generation of those directives by the
+ preprocessor (when compiling `.F' files) so diagnostics and
+ debugging info are more useful to users of the preprocessor.
+
+ * Produce better diagnostics, more like `gcc', with info such as `In
+ function `foo':' and `In file included from...:'.
+
+ * Support `gcc''s `-fident' and `-fno-ident' options.
+
+ * When `-Wunused' in effect, don't warn about local variables used as
+ statement-function dummy arguments or `DATA' implied-`DO' iteration
+ variables, even though, strictly speaking, these are not uses of
+ the variables themselves.
+
+ * When `-W -Wunused' in effect, don't warn about unused dummy
+ arguments at all, since there's no way to turn this off for
+ individual cases (`g77' might someday start warning about
+ these)--applies to `gcc' versions 2.7.0 and later, since earlier
+ versions didn't warn about unused dummy arguments.
+
+ * New option `-fno-underscoring' that inhibits transformation of
+ names (by appending one or two underscores) so users may experiment
+ with implications of such an environment.
+
+ * Minor improvement to `gcc/f/info' module to make it easier to build
+ `g77' using the native (non-`gcc') compiler on certain machines
+ (but definitely not all machines nor all non-`gcc' compilers).
+ Please do not report bugs showing problems compilers have with
+ macros defined in `gcc/f/target.h' and used in places like
+ `gcc/f/expr.c'.
+
+ * Add warning to be printed for each invocation of the compiler if
+ the target machine `INTEGER', `REAL', or `LOGICAL' size is not 32
+ bits, since `g77' is known to not work well for such cases (to be
+ fixed in Version 0.6--*note Actual Bugs We Haven't Fixed Yet:
+ Actual Bugs.).
+
+ * Lots of new documentation (though work is still needed to put it
+ into canonical GNU format).
+
+ * Build `libf2c' with `-g0', not `-g2', in effect (by default), to
+ produce smaller library without lots of debugging clutter.
+
+In 0.5.15:
+==========
+
+ * Fix bad code generation involving `X**I' and temporary, internal
+ variables generated by `g77' and the back end (such as for `DO'
+ loops).
+
+ * Fix crash given `CHARACTER A;DATA A/.TRUE./'.
+
+ * Replace crash with diagnostic given `CHARACTER A;DATA A/1.0/'.
+
+ * Fix crash or other erratic behavior when null character constant
+ (`''') is encountered.
+
+ * Fix crash or other erratic behavior involving diagnosed code.
+
+ * Fix code generation for external functions returning type `REAL'
+ when the `-ff2c' option is in force (which it is by default) so
+ that `f2c' compatibility is indeed provided.
+
+ * Disallow `COMMON I(10)' if `I' has previously been specified with
+ an array declarator.
+
+ * New `-ffixed-line-length-N' option, where N is the maximum length
+ of a typical fixed-form line, defaulting to 72 columns, such that
+ characters beyond column N are ignored, or N is `none', meaning no
+ characters are ignored. does not affect lines with `&' in column
+ 1, which are always processed as if `-ffixed-line-length-none' was
+ in effect.
+
+ * No longer generate better code for some kinds of array references,
+ as `gcc' back end is to be fixed to do this even better, and it
+ turned out to slow down some code in some cases after all.
+
+ * In `COMMON' and `EQUIVALENCE' areas with any members given initial
+ values (e.g. via `DATA'), uninitialized members now always
+ initialized to binary zeros (though this is not required by the
+ standard, and might not be done in future versions of `g77').
+ Previously, in some `COMMON'/`EQUIVALENCE' areas (essentially
+ those with members of more than one type), the uninitialized
+ members were initialized to spaces, to cater to `CHARACTER' types,
+ but it seems no existing code expects that, while much existing
+ code expects binary zeros.
+
+In 0.5.14:
+==========
+
+ * Don't emit bad code when low bound of adjustable array is
+ nonconstant and thus might vary as an expression at run time.
+
+ * Emit correct code for calculation of number of trips in `DO' loops
+ for cases where the loop should not execute at all. (This bug
+ affected cases where the difference between the begin and end
+ values was less than the step count, though probably not for
+ floating-point cases.)
+
+ * Fix crash when extra parentheses surround item in `DATA'
+ implied-`DO' list.
+
+ * Fix crash over minor internal inconsistencies in handling
+ diagnostics, just substitute dummy strings where necessary.
+
+ * Fix crash on some systems when compiling call to `MVBITS()'
+ intrinsic.
+
+ * Fix crash on array assignment `TYPEDDD(...)=...', where DDD is a
+ string of one or more digits.
+
+ * Fix crash on `DCMPLX()' with a single `INTEGER' argument.
+
+ * Fix various crashes involving code with diagnosed errors.
+
+ * Support `-I' option for `INCLUDE' statement, plus `gcc''s
+ `header.gcc' facility for handling systems like MS-DOS.
+
+ * Allow `INCLUDE' statement to be continued across multiple lines,
+ even allow it to coexist with other statements on the same line.
+
+ * Incorporate Bellcore fixes to `libf2c' through 1995-03-15--this
+ fixes a bug involving infinite loops reading EOF with empty
+ list-directed I/O list.
+
+ * Remove all the `g77'-specific auto-configuration scripts, code,
+ and so on, except for temporary substitutes for bsearch() and
+ strtoul(), as too many configure/build problems were reported in
+ these areas. People will have to fix their systems' problems
+ themselves, or at least somewhere other than `g77', which expects
+ a working ANSI C environment (and, for now, a GNU C compiler to
+ compile `g77' itself).
+
+ * Complain if initialized common redeclared as larger in subsequent
+ program unit.
+
+ * Warn if blank common initialized, since its size can vary and hence
+ related warnings that might be helpful won't be seen.
+
+ * New `-fbackslash' option, on by default, that causes `\' within
+ `CHARACTER' and Hollerith constants to be interpreted a la GNU C.
+ Note that this behavior is somewhat different from `f2c''s, which
+ supports only a limited subset of backslash (escape) sequences.
+
+ * Make `-fugly-args' the default.
+
+ * New `-fugly-init' option, on by default, that allows
+ typeless/Hollerith to be specified as initial values for variables
+ or named constants (`PARAMETER'), and also allows
+ character<->numeric conversion in those contexts--turn off via
+ `-fno-ugly-init'.
+
+ * New `-finit-local-zero' option to initialize local variables to
+ binary zeros. This does not affect whether they are `SAVE'd, i.e.
+ made automatic or static.
+
+ * New `-Wimplicit' option to warn about implicitly typed variables,
+ arrays, and functions. (Basically causes all program units to
+ default to `IMPLICIT NONE'.)
+
+ * `-Wall' now implies `-Wuninitialized' as with `gcc' (i.e. unless
+ `-O' not specified, since `-Wuninitialized' requires `-O'), and
+ implies `-Wunused' as well.
+
+ * `-Wunused' no longer gives spurious messages for unused `EXTERNAL'
+ names (since they are assumed to refer to block data program
+ units, to make use of libraries more reliable).
+
+ * Support `%LOC()' and `LOC()' of character arguments.
+
+ * Support null (zero-length) character constants and expressions.
+
+ * Support `f2c''s `IMAG()' generic intrinsic.
+
+ * Support `ICHAR()', `IACHAR()', and `LEN()' of character
+ expressions that are valid in assignments but not normally as
+ actual arguments.
+
+ * Support `f2c'-style `&' in column 1 to mean continuation line.
+
+ * Allow `NAMELIST', `EXTERNAL', `INTRINSIC', and `VOLATILE' in
+ `BLOCK DATA', even though these are not allowed by the standard.
+
+ * Allow `RETURN' in main program unit.
+
+ * Changes to Hollerith-constant support to obey Appendix C of the
+ standard:
+
+ - Now padded on the right with zeros, not spaces.
+
+ - Hollerith "format specifications" in the form of arrays of
+ non-character allowed.
+
+ - Warnings issued when non-space truncation occurs when
+ converting to another type.
+
+ - When specified as actual argument, now passed by reference to
+ `INTEGER' (padded on right with spaces if constant too small,
+ otherwise fully intact if constant wider the `INTEGER' type)
+ instead of by value.
+
+ *Warning:* `f2c' differs on the interpretation of `CALL FOO(1HX)',
+ which it treats exactly the same as `CALL FOO('X')', but which the
+ standard and `g77' treat as `CALL FOO(%REF('X '))' (padded with
+ as many spaces as necessary to widen to `INTEGER'), essentially.
+
+ * Changes and fixes to typeless-constant support:
+
+ - Now treated as a typeless double-length `INTEGER' value.
+
+ - Warnings issued when overflow occurs.
+
+ - Padded on the left with zeros when converting to a larger
+ type.
+
+ - Should be properly aligned and ordered on the target machine
+ for whatever type it is turned into.
+
+ - When specified as actual argument, now passed as reference to
+ a default `INTEGER' constant.
+
+ * `%DESCR()' of a non-`CHARACTER' expression now passes a pointer to
+ the expression plus a length for the expression just as if it were
+ a `CHARACTER' expression. For example, `CALL FOO(%DESCR(D))',
+ where `D' is `REAL*8', is the same as `CALL FOO(D,%VAL(8)))'.
+
+ * Name of multi-entrypoint master function changed to incorporate
+ the name of the primary entry point instead of a decimal value, so
+ the name of the master function for `SUBROUTINE X' with alternate
+ entry points is now `__g77_masterfun_x'.
+
+ * Remove redundant message about zero-step-count `DO' loops.
+
+ * Clean up diagnostic messages, shortening many of them.
+
+ * Fix typo in `g77' man page.
+
+ * Clarify implications of constant-handling bugs in `f/BUGS'.
+
+ * Generate better code for `**' operator with a right-hand operand of
+ type `INTEGER'.
+
+ * Generate better code for `SQRT()' and `DSQRT()', also when
+ `-ffast-math' specified, enable better code generation for `SIN()'
+ and `COS()'.
+
+ * Generate better code for some kinds of array references.
+
+ * Speed up lexing somewhat (this makes the compilation phase
+ noticeably faster).
+
diff --git a/contrib/gcc/f/README b/contrib/gcc/f/README
new file mode 100644
index 0000000..fdebfdc
--- /dev/null
+++ b/contrib/gcc/f/README
@@ -0,0 +1,7 @@
+1995-02-15
+
+This directory is the f/ subdirectory, which is designed to
+be a subdirectory in a gcc development tree, i.e. named gcc/f/.
+
+Please see gcc/README.g77 for information on the contents of this
+directory.
diff --git a/contrib/gcc/f/ansify.c b/contrib/gcc/f/ansify.c
new file mode 100644
index 0000000..3af68e5
--- /dev/null
+++ b/contrib/gcc/f/ansify.c
@@ -0,0 +1,208 @@
+/* ansify.c
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+/* From f/proj.h, which uses #error -- not all C compilers
+ support that, and we want *this* program to be compilable
+ by pretty much any C compiler. */
+#include "hconfig.j"
+#include "system.j"
+#include "assert.j"
+#if HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+typedef enum
+ {
+#if !defined(false) || !defined(true)
+ false = 0, true = 1,
+#endif
+#if !defined(FALSE) || !defined(TRUE)
+ FALSE = 0, TRUE = 1,
+#endif
+ Doggone_Trailing_Comma_Dont_Work = 1
+ } bool;
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+#define die_unless(c) \
+ do if (!(c)) \
+ { \
+ fprintf (stderr, "%s:%lu: " #c "\n", argv[1], lineno); \
+ die (); \
+ } \
+ while(0)
+
+static void
+die ()
+{
+ exit (1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ static unsigned long lineno = 1;
+
+ die_unless (argc == 2);
+
+ printf ("\
+/* This file is automatically generated from `%s',\n\
+ which you should modify instead. */\n\
+# 1 \"%s\"\n\
+",
+ argv[1], argv[1]);
+
+ while ((c = getchar ()) != EOF)
+ {
+ switch (c)
+ {
+ default:
+ putchar (c);
+ break;
+
+ case '\n':
+ ++lineno;
+ putchar (c);
+ break;
+
+ case '"':
+ putchar (c);
+ for (;;)
+ {
+ c = getchar ();
+ die_unless (c != EOF);
+ switch (c)
+ {
+ case '"':
+ putchar (c);
+ goto next_char;
+
+ case '\n':
+ putchar ('\\');
+ putchar ('n');
+ putchar ('\\');
+ putchar ('\n');
+ ++lineno;
+ break;
+
+ case '\\':
+ putchar (c);
+ c = getchar ();
+ die_unless (c != EOF);
+ putchar (c);
+ if (c == '\n')
+ ++lineno;
+ break;
+
+ default:
+ putchar (c);
+ break;
+ }
+ }
+ break;
+
+ case '\'':
+ putchar (c);
+ for (;;)
+ {
+ c = getchar ();
+ die_unless (c != EOF);
+ switch (c)
+ {
+ case '\'':
+ putchar (c);
+ goto next_char;
+
+ case '\n':
+ putchar ('\\');
+ putchar ('n');
+ putchar ('\\');
+ putchar ('\n');
+ ++lineno;
+ break;
+
+ case '\\':
+ putchar (c);
+ c = getchar ();
+ die_unless (c != EOF);
+ putchar (c);
+ if (c == '\n')
+ ++lineno;
+ break;
+
+ default:
+ putchar (c);
+ break;
+ }
+ }
+ break;
+
+ case '/':
+ putchar (c);
+ c = getchar ();
+ putchar (c);
+ if (c != '*')
+ break;
+ for (;;)
+ {
+ c = getchar ();
+ die_unless (c != EOF);
+
+ switch (c)
+ {
+ case '\n':
+ ++lineno;
+ putchar (c);
+ break;
+
+ case '*':
+ c = getchar ();
+ die_unless (c != EOF);
+ if (c == '/')
+ {
+ putchar ('*');
+ putchar ('/');
+ goto next_char;
+ }
+ if (c == '\n')
+ {
+ ++lineno;
+ putchar (c);
+ }
+ break;
+
+ default:
+ /* Don't bother outputting content of comments. */
+ break;
+ }
+ }
+ break;
+ }
+
+ next_char:
+ ;
+ }
+
+ die_unless (c == EOF);
+
+ return 0;
+}
diff --git a/contrib/gcc/f/assert.j b/contrib/gcc/f/assert.j
new file mode 100644
index 0000000..a24b66f
--- /dev/null
+++ b/contrib/gcc/f/assert.j
@@ -0,0 +1,27 @@
+/* assert.j -- Wrapper for GCC's assert.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_assert
+#define _J_f_assert
+#include "assert.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/bad.c b/contrib/gcc/f/bad.c
new file mode 100644
index 0000000..a2a4832
--- /dev/null
+++ b/contrib/gcc/f/bad.c
@@ -0,0 +1,544 @@
+/* bad.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Handles the displaying of diagnostic messages regarding the user's source
+ files.
+
+ Modifications:
+*/
+
+/* If there's a %E or %4 in the messages, set this to at least 5,
+ for example. */
+
+#define FFEBAD_MAX_ 6
+
+/* Include files. */
+
+#include "proj.h"
+#include "bad.h"
+#include "flags.j"
+#include "com.h"
+#include "toplev.j"
+#include "where.h"
+
+/* Externals defined here. */
+
+bool ffebad_is_inhibited_ = FALSE;
+
+/* Simple definitions and enumerations. */
+
+#define FFEBAD_LONG_MSGS_ 1 /* 0 to use short (or same) messages. */
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+struct _ffebad_message_
+ {
+ ffebadSeverity severity;
+ char *message;
+ };
+
+/* Static objects accessed by functions in this module. */
+
+static struct _ffebad_message_ ffebad_messages_[]
+=
+{
+#define FFEBAD_MSGS1(KWD,SEV,MSG) { SEV, MSG },
+#if FFEBAD_LONG_MSGS_ == 0
+#define FFEBAD_MSGS2(KWD,SEV,LMSG,SMSG) { SEV, SMSG },
+#else
+#define FFEBAD_MSGS2(KWD,SEV,LMSG,SMSG) { SEV, LMSG },
+#endif
+#include "bad.def"
+#undef FFEBAD_MSGS1
+#undef FFEBAD_MSGS2
+};
+
+static struct
+ {
+ ffewhereLine line;
+ ffewhereColumn col;
+ ffebadIndex tag;
+ }
+
+ffebad_here_[FFEBAD_MAX_];
+static char *ffebad_string_[FFEBAD_MAX_];
+static ffebadIndex ffebad_order_[FFEBAD_MAX_];
+static ffebad ffebad_errnum_;
+static ffebadSeverity ffebad_severity_;
+static char *ffebad_message_;
+static unsigned char ffebad_index_;
+static ffebadIndex ffebad_places_;
+static bool ffebad_is_temp_inhibited_; /* Effective setting of
+ _is_inhibited_ for this
+ _start/_finish invocation. */
+
+/* Static functions (internal). */
+
+static int ffebad_bufputs_ (char buf[], int bufi, char *s);
+
+/* Internal macros. */
+
+#define ffebad_bufflush_(buf, bufi) \
+ (((buf)[bufi] = '\0'), fputs ((buf), stderr), 0)
+#define ffebad_bufputc_(buf, bufi, c) \
+ (((bufi) == ARRAY_SIZE (buf)) \
+ ? (ffebad_bufflush_ ((buf), (bufi)), ((buf)[0] = (c)), 1) \
+ : (((buf)[bufi] = (c)), (bufi) + 1))
+
+
+static int
+ffebad_bufputs_ (char buf[], int bufi, char *s)
+{
+ for (; *s != '\0'; ++s)
+ bufi = ffebad_bufputc_ (buf, bufi, *s);
+ return bufi;
+}
+
+/* ffebad_init_0 -- Initialize
+
+ ffebad_init_0(); */
+
+void
+ffebad_init_0 ()
+{
+ assert (FFEBAD == ARRAY_SIZE (ffebad_messages_));
+}
+
+ffebadSeverity
+ffebad_severity (ffebad errnum)
+{
+ return ffebad_messages_[errnum].severity;
+}
+
+/* ffebad_start_ -- Start displaying an error message
+
+ ffebad_start(FFEBAD_SOME_ERROR_CODE);
+
+ Call ffebad_start to establish the message, ffebad_here and ffebad_string
+ to send run-time data to it as necessary, then ffebad_finish when through
+ to actually get it to print (to stderr).
+
+ Note: ffebad_start(errnum) turns into ffebad_start_(FALSE,errnum). No
+ outside caller should call ffebad_start_ directly (as indicated by the
+ trailing underscore).
+
+ Call ffebad_start to start a normal message, one that might be inhibited
+ by the current state of statement guessing. Call ffebad_start_lex
+ instead to start a message that is global to all statement guesses and
+ happens only once for all guesses (i.e. the lexer).
+
+ sev and message are overrides for the severity and messages when errnum
+ is FFEBAD, meaning the caller didn't want to have to put a message in
+ bad.def to produce a diagnostic. */
+
+bool
+ffebad_start_ (bool lex_override, ffebad errnum, ffebadSeverity sev,
+ char *message)
+{
+ unsigned char i;
+
+ if (ffebad_is_inhibited_ && !lex_override)
+ {
+ ffebad_is_temp_inhibited_ = TRUE;
+ return FALSE;
+ }
+
+ if (errnum != FFEBAD)
+ {
+ ffebad_severity_ = ffebad_messages_[errnum].severity;
+ ffebad_message_ = ffebad_messages_[errnum].message;
+ }
+ else
+ {
+ ffebad_severity_ = sev;
+ ffebad_message_ = message;
+ }
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ extern int inhibit_warnings; /* From toplev.c. */
+
+ switch (ffebad_severity_)
+ { /* Tell toplev.c about this message. */
+ case FFEBAD_severityINFORMATIONAL:
+ case FFEBAD_severityTRIVIAL:
+ if (inhibit_warnings)
+ { /* User wants no warnings. */
+ ffebad_is_temp_inhibited_ = TRUE;
+ return FALSE;
+ }
+ /* Fall through. */
+ case FFEBAD_severityWARNING:
+ case FFEBAD_severityPECULIAR:
+ case FFEBAD_severityPEDANTIC:
+ if ((ffebad_severity_ != FFEBAD_severityPEDANTIC)
+ || !flag_pedantic_errors)
+ {
+ if (count_error (1) == 0)
+ { /* User wants no warnings. */
+ ffebad_is_temp_inhibited_ = TRUE;
+ return FALSE;
+ }
+ break;
+ }
+ /* Fall through (PEDANTIC && flag_pedantic_errors). */
+ case FFEBAD_severityFATAL:
+ case FFEBAD_severityWEIRD:
+ case FFEBAD_severitySEVERE:
+ case FFEBAD_severityDISASTER:
+ count_error (0);
+ break;
+
+ default:
+ break;
+ }
+ }
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+ ffebad_is_temp_inhibited_ = FALSE;
+ ffebad_errnum_ = errnum;
+ ffebad_index_ = 0;
+ ffebad_places_ = 0;
+ for (i = 0; i < FFEBAD_MAX_; ++i)
+ {
+ ffebad_string_[i] = NULL;
+ ffebad_here_[i].line = ffewhere_line_unknown ();
+ ffebad_here_[i].col = ffewhere_column_unknown ();
+ }
+
+ return TRUE;
+}
+
+/* ffebad_here -- Establish source location of some diagnostic concern
+
+ ffebad_here(ffebadIndex i,ffewhereLine line,ffewhereColumn col);
+
+ Call ffebad_start to establish the message, ffebad_here and ffebad_string
+ to send run-time data to it as necessary, then ffebad_finish when through
+ to actually get it to print (to stderr). */
+
+void
+ffebad_here (ffebadIndex index, ffewhereLine line, ffewhereColumn col)
+{
+ ffewhereLineNumber line_num;
+ ffewhereLineNumber ln;
+ ffewhereColumnNumber col_num;
+ ffewhereColumnNumber cn;
+ ffebadIndex i;
+ ffebadIndex j;
+
+ if (ffebad_is_temp_inhibited_)
+ return;
+
+ assert (index < FFEBAD_MAX_);
+ ffebad_here_[index].line = ffewhere_line_use (line);
+ ffebad_here_[index].col = ffewhere_column_use (col);
+ if (ffewhere_line_is_unknown (line)
+ || ffewhere_column_is_unknown (col))
+ {
+ ffebad_here_[index].tag = FFEBAD_MAX_;
+ return;
+ }
+ ffebad_here_[index].tag = 0; /* For now, though it shouldn't matter. */
+
+ /* Sort the source line/col points into the order they occur in the source
+ file. Deal with duplicates appropriately. */
+
+ line_num = ffewhere_line_number (line);
+ col_num = ffewhere_column_number (col);
+
+ /* Determine where in the ffebad_order_ array this new place should go. */
+
+ for (i = 0; i < ffebad_places_; ++i)
+ {
+ ln = ffewhere_line_number (ffebad_here_[ffebad_order_[i]].line);
+ cn = ffewhere_column_number (ffebad_here_[ffebad_order_[i]].col);
+ if (line_num < ln)
+ break;
+ if (line_num == ln)
+ {
+ if (col_num == cn)
+ {
+ ffebad_here_[index].tag = i;
+ return; /* Shouldn't go in, has equivalent. */
+ }
+ else if (col_num < cn)
+ break;
+ }
+ }
+
+ /* Before putting new place in ffebad_order_[i], first increment all tags
+ that are i or greater. */
+
+ if (i != ffebad_places_)
+ {
+ for (j = 0; j < FFEBAD_MAX_; ++j)
+ {
+ if (ffebad_here_[j].tag >= i)
+ ++ffebad_here_[j].tag;
+ }
+ }
+
+ /* Then slide all ffebad_order_[] entries at and above i up one entry. */
+
+ for (j = ffebad_places_; j > i; --j)
+ ffebad_order_[j] = ffebad_order_[j - 1];
+
+ /* Finally can put new info in ffebad_order_[i]. */
+
+ ffebad_order_[i] = index;
+ ffebad_here_[index].tag = i;
+ ++ffebad_places_;
+}
+
+/* Establish string for next index (always in order) of message
+
+ ffebad_string(char *string);
+
+ Call ffebad_start to establish the message, ffebad_here and ffebad_string
+ to send run-time data to it as necessary, then ffebad_finish when through
+ to actually get it to print (to stderr). Note: don't trash the string
+ until after calling ffebad_finish, since we just maintain a pointer to
+ the argument passed in until then. */
+
+void
+ffebad_string (char *string)
+{
+ if (ffebad_is_temp_inhibited_)
+ return;
+
+ assert (ffebad_index_ != FFEBAD_MAX_);
+ ffebad_string_[ffebad_index_++] = string;
+}
+
+/* ffebad_finish -- Display error message with where & run-time info
+
+ ffebad_finish();
+
+ Call ffebad_start to establish the message, ffebad_here and ffebad_string
+ to send run-time data to it as necessary, then ffebad_finish when through
+ to actually get it to print (to stderr). */
+
+void
+ffebad_finish ()
+{
+#define MAX_SPACES 132
+ static char *spaces
+ = "...>\
+\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
+\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
+\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
+\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
+\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
+\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
+\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
+\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\040\
+\040\040\040"; /* MAX_SPACES - 1 spaces. */
+ ffewhereLineNumber last_line_num;
+ ffewhereLineNumber ln;
+ ffewhereLineNumber rn;
+ ffewhereColumnNumber last_col_num;
+ ffewhereColumnNumber cn;
+ ffewhereColumnNumber cnt;
+ ffewhereLine l;
+ ffebadIndex bi;
+ unsigned short i;
+ char pointer;
+ char c;
+ char *s;
+ char *fn;
+ static char buf[1024];
+ int bufi;
+ int index;
+
+ if (ffebad_is_temp_inhibited_)
+ return;
+
+ switch (ffebad_severity_)
+ {
+ case FFEBAD_severityINFORMATIONAL:
+ s = "note:";
+ break;
+
+ case FFEBAD_severityWARNING:
+ s = "warning:";
+ break;
+
+ case FFEBAD_severitySEVERE:
+ s = "fatal:";
+ break;
+
+ default:
+ s = "";
+ break;
+ }
+
+ /* Display the annoying source references. */
+
+ last_line_num = 0;
+ last_col_num = 0;
+
+ for (bi = 0; bi < ffebad_places_; ++bi)
+ {
+ if (ffebad_places_ == 1)
+ pointer = '^';
+ else
+ pointer = '1' + bi;
+
+ l = ffebad_here_[ffebad_order_[bi]].line;
+ ln = ffewhere_line_number (l);
+ rn = ffewhere_line_filelinenum (l);
+ cn = ffewhere_column_number (ffebad_here_[ffebad_order_[bi]].col);
+ fn = ffewhere_line_filename (l);
+ if (ln != last_line_num)
+ {
+ if (bi != 0)
+ fputc ('\n', stderr);
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ report_error_function (fn);
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+ fprintf (stderr,
+#if 0
+ "Line %" ffewhereLineNumber_f "u of %s:\n %s\n %s%c",
+ rn, fn,
+#else
+ /* the trailing space on the <file>:<line>: line
+ fools emacs19 compilation mode into finding the
+ report */
+ "%s:%" ffewhereLineNumber_f "u: %s\n %s\n %s%c",
+ fn, rn,
+#endif
+ s,
+ ffewhere_line_content (l),
+ &spaces[cn > MAX_SPACES ? 0 : MAX_SPACES - cn + 4],
+ pointer);
+ last_line_num = ln;
+ last_col_num = cn;
+ s = "(continued):";
+ }
+ else
+ {
+ cnt = cn - last_col_num;
+ fprintf (stderr,
+ "%s%c", &spaces[cnt > MAX_SPACES
+ ? 0 : MAX_SPACES - cnt + 4],
+ pointer);
+ last_col_num = cn;
+ }
+ }
+ if (ffebad_places_ == 0)
+ {
+ /* Didn't output "warning:" string, capitalize it for message. */
+ if ((s[0] != '\0') && ISALPHA (s[0]) && ISLOWER (s[0]))
+ {
+ char c;
+
+ c = toupper (s[0]);
+ fprintf (stderr, "%c%s ", c, &s[1]);
+ }
+ else if (s[0] != '\0')
+ fprintf (stderr, "%s ", s);
+ }
+ else
+ fputc ('\n', stderr);
+
+ /* Release the ffewhere info. */
+
+ for (bi = 0; bi < FFEBAD_MAX_; ++bi)
+ {
+ ffewhere_line_kill (ffebad_here_[bi].line);
+ ffewhere_column_kill (ffebad_here_[bi].col);
+ }
+
+ /* Now display the message. */
+
+ bufi = 0;
+ for (i = 0; (c = ffebad_message_[i]) != '\0'; ++i)
+ {
+ if (c == '%')
+ {
+ c = ffebad_message_[++i];
+ if (ISALPHA (c) && ISUPPER (c))
+ {
+ index = c - 'A';
+
+ if ((index < 0) || (index >= FFEBAD_MAX_))
+ {
+ bufi = ffebad_bufputs_ (buf, bufi, "[REPORT BUG!!] %");
+ bufi = ffebad_bufputc_ (buf, bufi, c);
+ }
+ else
+ {
+ s = ffebad_string_[index];
+ if (s == NULL)
+ bufi = ffebad_bufputs_ (buf, bufi, "[REPORT BUG!!]");
+ else
+ bufi = ffebad_bufputs_ (buf, bufi, s);
+ }
+ }
+ else if (ISDIGIT (c))
+ {
+ index = c - '0';
+
+ if ((index < 0) || (index >= FFEBAD_MAX_))
+ {
+ bufi = ffebad_bufputs_ (buf, bufi, "[REPORT BUG!!] %");
+ bufi = ffebad_bufputc_ (buf, bufi, c);
+ }
+ else
+ {
+ pointer = ffebad_here_[index].tag + '1';
+ if (pointer == FFEBAD_MAX_ + '1')
+ pointer = '?';
+ else if (ffebad_places_ == 1)
+ pointer = '^';
+ bufi = ffebad_bufputc_ (buf, bufi, '(');
+ bufi = ffebad_bufputc_ (buf, bufi, pointer);
+ bufi = ffebad_bufputc_ (buf, bufi, ')');
+ }
+ }
+ else if (c == '\0')
+ break;
+ else if (c == '%')
+ bufi = ffebad_bufputc_ (buf, bufi, '%');
+ else
+ {
+ bufi = ffebad_bufputs_ (buf, bufi, "[REPORT BUG!!]");
+ bufi = ffebad_bufputc_ (buf, bufi, '%');
+ bufi = ffebad_bufputc_ (buf, bufi, c);
+ }
+ }
+ else
+ bufi = ffebad_bufputc_ (buf, bufi, c);
+ }
+ bufi = ffebad_bufputc_ (buf, bufi, '\n');
+ bufi = ffebad_bufflush_ (buf, bufi);
+}
diff --git a/contrib/gcc/f/bad.def b/contrib/gcc/f/bad.def
new file mode 100644
index 0000000..3a86a1f
--- /dev/null
+++ b/contrib/gcc/f/bad.def
@@ -0,0 +1,711 @@
+/* bad.def -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ bad.c
+
+ Modifications:
+*/
+
+#define INFORM FFEBAD_severityINFORMATIONAL
+#define TRIVIAL FFEBAD_severityTRIVIAL
+#define WARN FFEBAD_severityWARNING
+#define PECULIAR FFEBAD_severityPECULIAR
+#define FATAL FFEBAD_severityFATAL
+#define WEIRD FFEBAD_severityWEIRD
+#define SEVERE FFEBAD_severitySEVERE
+#define DISASTER FFEBAD_severityDISASTER
+
+FFEBAD_MSGS1 (FFEBAD_MISSING_FIRST_BINARY_OPERAND, FATAL,
+"Missing first operand for binary operator at %0")
+FFEBAD_MSGS1 (FFEBAD_NULL_CHAR_CONST, WARN,
+"Zero-length character constant at %0")
+FFEBAD_MSGS1 (FFEBAD_INVALID_TOKEN_IN_EXPRESSION, FATAL,
+"Invalid token at %0 in expression or subexpression at %1")
+FFEBAD_MSGS1 (FFEBAD_MISSING_OPERAND_FOR_OPERATOR, FATAL,
+"Missing operand for operator at %1 at end of expression at %0")
+FFEBAD_MSGS1 (FFEBAD_LABEL_ALREADY_DEFINED, FATAL,
+"Label %A already defined at %1 when redefined at %0")
+FFEBAD_MSGS1 (FFEBAD_UNRECOGNIZED_CHARACTER, FATAL,
+"Unrecognized character at %0 [info -f g77 M LEX]")
+FFEBAD_MSGS1 (FFEBAD_LABEL_WITHOUT_STMT, WARN,
+"Label definition %A at %0 on empty statement (as of %1)")
+FFEBAD_MSGS2 (FFEBAD_EXTRA_LABEL_DEF, FATAL,
+"Extra label definition %A at %0 -- perhaps previous label definition %B at %1 should have CONTINUE statement?",
+"Extra label definition %A at %0 following label definition %B at %1")
+FFEBAD_MSGS1 (FFEBAD_FIRST_CHAR_INVALID, FATAL,
+"Invalid first character at %0 [info -f g77 M LEX]")
+FFEBAD_MSGS1 (FFEBAD_LINE_TOO_LONG, FATAL,
+"Line too long as of %0 [info -f g77 M LEX]")
+FFEBAD_MSGS1 (FFEBAD_LABEL_FIELD_NOT_NUMERIC, FATAL,
+"Non-numeric character at %0 in label field [info -f g77 M LEX]")
+FFEBAD_MSGS1 (FFEBAD_LABEL_NUMBER_INVALID, FATAL,
+"Label number at %0 not in range 1-99999")
+FFEBAD_MSGS1 (FFEBAD_NON_ANSI_COMMENT, WARN,
+"At %0, '!' and '/*' are not valid comment delimiters")
+FFEBAD_MSGS1 (FFEBAD_NON_ANSI_CONTINUATION_COLUMN, WARN,
+"Continuation indicator at %0 must appear in column 6 [info -f g77 M LEX]")
+FFEBAD_MSGS1 (FFEBAD_LABEL_ON_CONTINUATION, FATAL,
+"Label at %0 invalid with continuation line indicator at %1 [info -f g77 M LEX]")
+FFEBAD_MSGS2 (FFEBAD_INVALID_CONTINUATION, FATAL,
+"Continuation indicator at %0 invalid on first non-comment line of file or following END or INCLUDE [info -f g77 M LEX]",
+"Continuation indicator at %0 invalid here [info -f g77 M LEX]")
+FFEBAD_MSGS1 (FFEBAD_NO_CLOSING_APOSTROPHE, FATAL,
+"Character constant at %0 has no closing apostrophe at %1")
+FFEBAD_MSGS1 (FFEBAD_NOT_ENOUGH_HOLLERITH_CHARS, FATAL,
+"Hollerith constant at %0 specified %A more characters than are present as of %1")
+FFEBAD_MSGS1 (FFEBAD_MISSING_CLOSE_PAREN, FATAL,
+"Missing close parenthese at %0 needed to match open parenthese at %1")
+FFEBAD_MSGS1 (FFEBAD_INTEGER_TOO_LARGE, FATAL,
+"Integer at %0 too large")
+FFEBAD_MSGS2 (FFEBAD_BAD_MAGICAL, WARN,
+"Integer at %0 too large except as negative number (preceded by unary minus sign)",
+"Non-negative integer at %0 too large")
+FFEBAD_MSGS2 (FFEBAD_BAD_MAGICAL_PRECEDENCE, WARN,
+"Integer at %0 too large; even though preceded by unary minus sign at %1, subsequent operator at %2 has precedence over unary minus -- enclose unary minus sign and integer in parentheses to force precedence",
+"Integer at %0 too large (%2 has precedence over %1)")
+FFEBAD_MSGS2 (FFEBAD_BAD_MAGICAL_BINARY, WARN,
+"Integer at %0 too large; even though preceded by minus sign at %1, because minus sign is a binary, not unary, operator -- insert plus sign before minus sign to change it to a unary minus sign",
+"Integer at %0 too large (needs unary, not binary, minus at %1)")
+FFEBAD_MSGS2 (FFEBAD_BAD_MAGICAL_PRECEDENCE_BINARY, WARN,
+"Integer at %0 too large; even though preceded by minus sign at %1, subsequent operator at %2 has precedence over minus, and that minus sign should be a unary minus rather than a binary minus -- insert plus sign before minus sign to change it to a unary minus sign, and enclose unary minus sign and integer in parentheses to force precedence",
+"Integer at %0 too large (%2 has precedence over %1, which needs to be unary, not binary, minus)")
+FFEBAD_MSGS1 (FFEBAD_IGNORING_PERIOD, FATAL,
+"Period at %0 not followed by digits for floating-point number or by `NOT.', `TRUE.', or `FALSE.'")
+FFEBAD_MSGS1 (FFEBAD_INSERTING_PERIOD, FATAL,
+"Missing close-period between `.%A' at %0 and %1")
+FFEBAD_MSGS1 (FFEBAD_INVALID_EXPONENT, FATAL,
+"Invalid exponent at %0 for real constant at %1; nondigit `%A' in exponent field")
+FFEBAD_MSGS1 (FFEBAD_MISSING_EXPONENT_VALUE, FATAL,
+"Missing value at %1 for real-number exponent at %0")
+FFEBAD_MSGS1 (FFEBAD_MISSING_BINARY_OPERATOR, FATAL,
+"Expected binary operator between expressions at %0 and at %1")
+FFEBAD_MSGS2 (FFEBAD_INVALID_DOTDOT, FATAL,
+"Period at %0 not followed by valid keyword forming a valid binary operator; `.%A.' is not a valid binary operator",
+"`.%A.' at %0 not a binary operator")
+FFEBAD_MSGS2 (FFEBAD_QUOTE_MISSES_DIGITS, FATAL,
+"Double-quote at %0 not followed by a string of valid octal digits at %1",
+"Invalid octal constant at %0")
+FFEBAD_MSGS2 (FFEBAD_INVALID_BINARY_DIGIT, FATAL,
+"Invalid binary digit(s) found in string of digits at %0",
+"Invalid binary constant at %0")
+FFEBAD_MSGS2 (FFEBAD_INVALID_HEX_DIGIT, FATAL,
+"Invalid hexadecimal digit(s) found in string of digits at %0",
+"Invalid hexadecimal constant at %0")
+FFEBAD_MSGS2 (FFEBAD_INVALID_OCTAL_DIGIT, FATAL,
+"Invalid octal digit(s) found in string of digits at %0",
+"Invalid octal constant at %0")
+FFEBAD_MSGS2 (FFEBAD_INVALID_RADIX_SPECIFIER, FATAL,
+"Invalid radix specifier `%A' at %0 for typeless constant at %1",
+"Invalid typeless constant at %1")
+FFEBAD_MSGS2 (FFEBAD_INVALID_TYPELESS_BINARY_DIGIT, FATAL,
+"Invalid binary digit(s) found in string of digits at %0",
+"Invalid binary constant at %0")
+FFEBAD_MSGS2 (FFEBAD_INVALID_TYPELESS_OCTAL_DIGIT, FATAL,
+"Invalid octal digit(s) found in string of digits at %0",
+"Invalid octal constant at %0")
+FFEBAD_MSGS2 (FFEBAD_INVALID_TYPELESS_HEX_DIGIT, FATAL,
+"Invalid hexadecimal digit(s) found in string of digits at %0",
+"Invalid hexadecimal constant at %0")
+FFEBAD_MSGS2 (FFEBAD_INVALID_COMPLEX_PART, FATAL,
+"%A part of complex constant at %0 must be a real or integer constant -- otherwise use CMPLX() or COMPLEX() in place of ()",
+"%A part of complex constant at %0 not a real or integer constant")
+FFEBAD_MSGS2 (FFEBAD_INVALID_PERCENT, FATAL,
+"Invalid keyword `%%%A' at %0 in this context",
+"Invalid keyword `%%%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_NULL_EXPRESSION, FATAL,
+"Null expression between %0 and %1 invalid in this context",
+"Invalid null expression between %0 and %1")
+FFEBAD_MSGS2 (FFEBAD_CONCAT_ARGS_TYPE, FATAL,
+"Concatenation operator at %0 must operate on two subexpressions of character type, but neither subexpression at %1 or %2 is of character type",
+"Invalid operands at %1 and %2 for concatenation operator at %0")
+FFEBAD_MSGS2 (FFEBAD_CONCAT_ARG_TYPE, FATAL,
+"Concatenation operator at %0 must operate on two subexpressions of character type, but the subexpression at %1 is not of character type",
+"Invalid operand at %1 for concatenation operator at %0")
+FFEBAD_MSGS2 (FFEBAD_CONCAT_ARG_KIND, FATAL,
+"Concatenation operator at %0 must operate on two scalar (not array) subexpressions, two function invocations returning character scalars, or a combination of both -- but the subexpression at %1 is %A",
+"Invalid operand (is %A) at %1 for concatenation operator at %0")
+FFEBAD_MSGS2 (FFEBAD_MATH_ARGS_TYPE, FATAL,
+"Arithmetic operator at %0 must operate on two subexpressions of arithmetic type, but neither subexpression at %1 or %2 is of arithmetic type",
+"Invalid operands at %1 and %2 for arithmetic operator at %0")
+FFEBAD_MSGS2 (FFEBAD_MATH_ARG_TYPE, FATAL,
+"Arithmetic operator at %0 must operate on two subexpressions of arithmetic type, but the subexpression at %1 is not of arithmetic type",
+"Invalid operand at %1 for arithmetic operator at %0")
+FFEBAD_MSGS2 (FFEBAD_MATH_ARG_KIND, FATAL,
+"Arithmetic operator at %0 must operate on two scalar (not array) subexpressions, two function invocations returning arithmetic scalars, or a combination of both -- but the subexpression at %1 is %A",
+"Invalid operand (is %A) at %1 for arithmetic operator at %0")
+FFEBAD_MSGS2 (FFEBAD_NO_CLOSING_QUOTE, FATAL,
+"Character constant at %0 has no closing quote at %1 [info -f g77 M LEX]",
+"Unterminated character constant at %0 [info -f g77 M LEX]")
+FFEBAD_MSGS2 (FFEBAD_BAD_CHAR_CONTINUE, FATAL,
+"Continuation line at %0 must have initial `&' since it continues a character context [info -f g77 M LEX]",
+"Missing initial `&' on continuation line at %0 [info -f g77 M LEX]")
+FFEBAD_MSGS2 (FFEBAD_BAD_LEXTOK_CONTINUE, FATAL,
+"Continuation line at %0 must have initial `&' since it continues a split lexical token [info -f g77 M LEX]",
+"Missing initial `&' on continuation line at %0 [info -f g77 M LEX]")
+FFEBAD_MSGS2 (FFEBAD_BAD_FREE_CONTINUE, FATAL,
+"Continuation line at %0 invalid because it consists only of a single `&' as the only nonblank character",
+"Invalid continuation line at %0")
+FFEBAD_MSGS2 (FFEBAD_STMT_BEGINS_BAD, FATAL,
+"Statement at %0 begins with invalid token [info -f g77 M LEX]",
+"Invalid statement at %0 [info -f g77 M LEX]")
+FFEBAD_MSGS1 (FFEBAD_SEMICOLON, FATAL,
+"Semicolon at %0 is an invalid token")
+FFEBAD_MSGS2 (FFEBAD_UNREC_STMT, FATAL,
+"Unrecognized statement name at %0 and invalid form for assignment or statement-function definition at %1",
+"Invalid statement at %0")
+FFEBAD_MSGS2 (FFEBAD_INVALID_STMT_FORM, FATAL,
+"Invalid form for %A statement at %0",
+"Invalid %A statement at %0")
+FFEBAD_MSGS2 (FFEBAD_INVALID_HOLL_IN_STMT, FATAL,
+"Invalid use of hollerith constant in statement at %0 -- enclose the constant in parentheses (for example, change BACKSPACE 2HAB to BACKSPACE (2HAB))",
+"Enclose hollerith constant in statement at %0 in parentheses")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_EXTRA_COMMA, FATAL,
+"Extraneous comma in FORMAT statement at %0")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_MISSING_COMMA, WARN,
+"Missing comma in FORMAT statement at %0")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_SPURIOUS_SIGN, FATAL,
+"Spurious sign in FORMAT statement at %0")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_SPURIOUS_NUMBER, FATAL,
+"Spurious number in FORMAT statement at %0")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_TEXT_IN_NUMBER, FATAL,
+"Spurious text trailing number in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_P_NOCOMMA, FATAL,
+"nP control edit descriptor not followed by comma but followed by edit descriptor at %0 other than D, E, EN, F, or G",
+"Invalid edit descriptor at %0 following nP control edit descriptor")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_BAD_SPEC, FATAL,
+"Unrecognized FORMAT specifier at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_I_SPEC, FATAL,
+"Invalid I specifier in FORMAT statement at %0 -- correct form: [r]Iw.[m]",
+"Invalid I specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_B_SPEC, FATAL,
+"Invalid B specifier in FORMAT statement at %0 -- correct form: [r]Bw.[m]",
+"Invalid B specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_O_SPEC, FATAL,
+"Invalid O specifier in FORMAT statement at %0 -- correct form: [r]Ow.[m]",
+"Invalid O specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_Z_SPEC, FATAL,
+"Invalid Z specifier in FORMAT statement at %0 -- correct form: [r]Zw.[m]",
+"Invalid Z specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_F_SPEC, FATAL,
+"Invalid F specifier in FORMAT statement at %0 -- correct form: [r]Fw.d",
+"Invalid F specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_E_SPEC, FATAL,
+"Invalid E specifier in FORMAT statement at %0 -- correct form: [r]Ew.d[Ee]",
+"Invalid E specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_EN_SPEC, FATAL,
+"Invalid EN specifier in FORMAT statement at %0 -- correct form: [r]ENw.d[Ee]",
+"Invalid EN specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_G_SPEC, FATAL,
+"Invalid G specifier in FORMAT statement at %0 -- correct form: [r]Gw.d[Ee]",
+"Invalid G specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_L_SPEC, FATAL,
+"Invalid L specifier in FORMAT statement at %0 -- correct form: [r]Lw",
+"Invalid L specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_A_SPEC, FATAL,
+"Invalid A specifier in FORMAT statement at %0 -- correct form: [r]A[w]",
+"Invalid A specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_D_SPEC, FATAL,
+"Invalid D specifier in FORMAT statement at %0 -- correct form: [r]Dw.d",
+"Invalid D specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_Q_SPEC, FATAL,
+"Invalid Q specifier in FORMAT statement at %0 -- correct form: Q",
+"Invalid Q specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_DOLLAR_SPEC, FATAL,
+"Invalid $ specifier in FORMAT statement at %0 -- correct form: $",
+"Invalid $ specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_P_SPEC, FATAL,
+"Invalid P specifier in FORMAT statement at %0 -- correct form: kP",
+"Invalid P specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_T_SPEC, FATAL,
+"Invalid T specifier in FORMAT statement at %0 -- correct form: Tn",
+"Invalid T specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_TL_SPEC, FATAL,
+"Invalid TL specifier in FORMAT statement at %0 -- correct form: TLn",
+"Invalid TL specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_TR_SPEC, FATAL,
+"Invalid TR specifier in FORMAT statement at %0 -- correct form: TRn",
+"Invalid TR specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_X_SPEC, FATAL,
+"Invalid X specifier in FORMAT statement at %0 -- correct form: nX",
+"Invalid X specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_S_SPEC, FATAL,
+"Invalid S specifier in FORMAT statement at %0 -- correct form: S",
+"Invalid S specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_SP_SPEC, FATAL,
+"Invalid SP specifier in FORMAT statement at %0 -- correct form: SP",
+"Invalid SP specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_SS_SPEC, FATAL,
+"Invalid SS specifier in FORMAT statement at %0 -- correct form: SS",
+"Invalid SS specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_BN_SPEC, FATAL,
+"Invalid BN specifier in FORMAT statement at %0 -- correct form: BN",
+"Invalid BN specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_BZ_SPEC, FATAL,
+"Invalid BZ specifier in FORMAT statement at %0 -- correct form: BZ",
+"Invalid BZ specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_COLON_SPEC, FATAL,
+"Invalid : specifier in FORMAT statement at %0 -- correct form: :",
+"Invalid : specifier in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_BAD_H_SPEC, FATAL,
+"Invalid H specifier in FORMAT statement at %0 -- correct form: nHcharacters !where n is an unsigned decimal constant, and characters !contains exactly n characters (including spaces)",
+"Invalid H specifier in FORMAT statement at %0")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_MISSING_PAREN, FATAL,
+"Missing close-parenthese(s) in FORMAT statement at %0")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_MISSING_DOT, FATAL,
+"Missing number following period in FORMAT statement at %0")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_MISSING_EXP, FATAL,
+"Missing number following `E' in FORMAT statement at %0")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_EXPR_TOKEN, FATAL,
+"Invalid token with FORMAT run-time expression at %0 -- use the traditional operators .LT., .LE., .GT., .GE., .EQ., and .NE. in place of the newer tokens <, <=, >, >=, ==, and !=, because > ends an expression within a FORMAT statement",
+"Invalid token with FORMAT run-time expression at %0")
+FFEBAD_MSGS1 (FFEBAD_TRAILING_COMMA, WARN,
+"Spurious trailing comma preceding terminator at %0")
+FFEBAD_MSGS1 (FFEBAD_INTERFACE_ASSIGNMENT, WARN,
+"At %0, specify OPERATOR instead of ASSIGNMENT for INTERFACE statement not specifying the assignment operator (=)")
+FFEBAD_MSGS1 (FFEBAD_INTERFACE_OPERATOR, WARN,
+"At %0, specify ASSIGNMENT instead of OPERATOR for INTERFACE statement specifying the assignment operator (=)")
+FFEBAD_MSGS2 (FFEBAD_INTERFACE_NONLETTER, FATAL,
+"Defined operator at %0 contains a nonletter -- must contain only letters A-Z (or a-z)",
+"Nonletter in defined operator at %0")
+FFEBAD_MSGS2 (FFEBAD_INVALID_TYPEDECL_ATTR, FATAL,
+"Invalid type-declaration attribute at %0 -- must be one of: DIMENSION(array-spec), EXTERNAL, INTRINSIC, PARAMETER, or SAVE",
+"Invalid type-declaration attribute at %0")
+FFEBAD_MSGS1 (FFEBAD_INVALID_TYPEDECL_INIT, FATAL,
+"Cannot specify =initialization-expr at %0 unless `::' appears before list of objects")
+FFEBAD_MSGS1 (FFEBAD_LABEL_USE_DEF, FATAL,
+"Reference to label at %1 inconsistent with its definition at %0")
+FFEBAD_MSGS1 (FFEBAD_LABEL_USE_USE, FATAL,
+"Reference to label at %1 inconsistent with earlier reference at %0")
+FFEBAD_MSGS1 (FFEBAD_LABEL_DEF_DO, FATAL,
+"DO-statement reference to label at %1 follows its definition at %0")
+FFEBAD_MSGS1 (FFEBAD_LABEL_BLOCK, WARN,
+"Reference to label at %1 is outside block containing definition at %0")
+FFEBAD_MSGS1 (FFEBAD_LABEL_DO_BLOCK_DO, FATAL,
+"DO-statement references to label at %0 and %2 separated by unterminated block starting at %1")
+FFEBAD_MSGS1 (FFEBAD_LABEL_DO_BLOCK_END, FATAL,
+"DO-statement reference to label at %0 and label definition at %2 separated by unterminated block starting at %1")
+FFEBAD_MSGS1 (FFEBAD_INVALID_LABEL_DEF, FATAL,
+"Label definition at %0 invalid on this kind of statement")
+FFEBAD_MSGS1 (FFEBAD_ORDER_1, FATAL,
+"Statement at %0 invalid in this context")
+FFEBAD_MSGS1 (FFEBAD_ORDER_2, FATAL,
+"Statement at %0 invalid in context established by statement at %1")
+FFEBAD_MSGS1 (FFEBAD_CONSTRUCT_NAMED, FATAL,
+"Statement at %0 must specify construct name specified at %1")
+FFEBAD_MSGS1 (FFEBAD_CONSTRUCT_NOT_NAMED, FATAL,
+"Construct name at %0 superfluous, no construct name specified at %1")
+FFEBAD_MSGS1 (FFEBAD_CONSTRUCT_WRONG_NAME, FATAL,
+"Construct name at %0 not the same as construct name at %1")
+FFEBAD_MSGS1 (FFEBAD_CONSTRUCT_NO_DO_NAME, FATAL,
+"Construct name at %0 does not match construct name for any containing DO constructs")
+FFEBAD_MSGS1 (FFEBAD_DO_HAD_LABEL, FATAL,
+"Label definition missing at %0 for DO construct specifying label at %1")
+FFEBAD_MSGS1 (FFEBAD_AFTER_ELSE, FATAL,
+"Statement at %0 follows ELSE block for IF construct at %1")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_NO_LABEL_DEF, FATAL,
+"No label definition for FORMAT statement at %0")
+FFEBAD_MSGS1 (FFEBAD_SECOND_ELSE_WHERE, FATAL,
+"Second occurrence of ELSE WHERE at %0 within WHERE at %1")
+FFEBAD_MSGS1 (FFEBAD_END_WO, WARN,
+"END statement at %0 missing `%A' keyword required for internal or module procedure(s) bounded by %1")
+FFEBAD_MSGS1 (FFEBAD_INVALID_MODULE_PROCEDURE, FATAL,
+"MODULE PROCEDURE statement at %0 disallowed because INTERFACE at %1 specifies no generic name, operator, or assignment")
+FFEBAD_MSGS1 (FFEBAD_BLOCKDATA_NOT_NAMED, FATAL,
+"BLOCK DATA name at %0 superfluous, no name specified at %1")
+FFEBAD_MSGS1 (FFEBAD_PROGRAM_NOT_NAMED, FATAL,
+"Program name at %0 superfluous, no PROGRAM statement specified at %1")
+FFEBAD_MSGS1 (FFEBAD_UNIT_WRONG_NAME, FATAL,
+"Program unit name at %0 not the same as name at %1")
+FFEBAD_MSGS1 (FFEBAD_TYPE_WRONG_NAME, FATAL,
+"Type name at %0 not the same as name at %1")
+FFEBAD_MSGS1 (FFEBAD_EOF_BEFORE_BLOCK_END, FATAL,
+"End of source file before end of block started at %0")
+FFEBAD_MSGS1 (FFEBAD_UNDEF_LABEL, FATAL,
+"Undefined label, first referenced at %0")
+FFEBAD_MSGS1 (FFEBAD_CONFLICTING_SAVES, WARN,
+"SAVE statement or attribute at %1 cannot be specified along with SAVE statement or attribute at %0")
+FFEBAD_MSGS1 (FFEBAD_CONFLICTING_ACCESSES, FATAL,
+"PUBLIC or PRIVATE statement at %1 cannot be specified along with PUBLIC or PRIVATE statement at %0")
+FFEBAD_MSGS1 (FFEBAD_RETURN_IN_MAIN, WARN,
+"RETURN statement at %0 invalid within a main program unit")
+FFEBAD_MSGS1 (FFEBAD_ALTRETURN_IN_PROGRAM, FATAL,
+"Alternate return specifier at %0 invalid within a main program unit")
+FFEBAD_MSGS1 (FFEBAD_ALTRETURN_IN_FUNCTION, FATAL,
+"Alternate return specifier at %0 invalid within a function")
+FFEBAD_MSGS1 (FFEBAD_DERIVTYP_ACCESS, FATAL,
+"Access specifier or PRIVATE statement at %0 invalid for derived-type definition within other than the specification part of a module")
+FFEBAD_MSGS1 (FFEBAD_DERIVTYP_ACCESS_FIRST, FATAL,
+"Access specifier at %0 must immediately follow derived-type statement at %1 with no intervening statements")
+FFEBAD_MSGS1 (FFEBAD_DERIVTYP_NO_COMPONENTS, FATAL,
+"No components specified as of %0 for derived-type definition beginning at %1")
+FFEBAD_MSGS1 (FFEBAD_STRUCT_NO_COMPONENTS, FATAL,
+"No components specified as of %0 for structure definition beginning at %1")
+FFEBAD_MSGS1 (FFEBAD_STRUCT_MISSING_NAME, FATAL,
+"Missing structure name for outer structure definition at %0")
+FFEBAD_MSGS1 (FFEBAD_STRUCT_IGNORING_FIELD, FATAL,
+"Field names at %0 for outer structure definition -- specify them in a subsequent RECORD statement instead")
+FFEBAD_MSGS1 (FFEBAD_STRUCT_MISSING_FIELD, FATAL,
+"Missing field name(s) for structure definition at %0 within structure definition at %1")
+FFEBAD_MSGS1 (FFEBAD_MAP_NO_COMPONENTS, FATAL,
+"No components specified as of %0 for map beginning at %1")
+FFEBAD_MSGS1 (FFEBAD_UNION_NO_TWO_MAPS, FATAL,
+"Zero or one maps specified as of %0 for union beginning at %1 -- at least two are required")
+FFEBAD_MSGS1 (FFEBAD_MISSING_SPECIFIER, FATAL,
+"Missing %A specifier in statement at %0")
+FFEBAD_MSGS1 (FFEBAD_NAMELIST_ITEMS, FATAL,
+"Items in I/O list starting at %0 invalid for namelist-directed I/O")
+FFEBAD_MSGS1 (FFEBAD_CONFLICTING_SPECS, FATAL,
+"Conflicting I/O control specifications at %0 and %1")
+FFEBAD_MSGS1 (FFEBAD_NO_UNIT_SPEC, FATAL,
+"No UNIT= specifier in I/O control list at %0")
+FFEBAD_MSGS1 (FFEBAD_MISSING_ADVANCE_SPEC, FATAL,
+"Specification at %0 requires ADVANCE=`NO' specification in same I/O control list")
+FFEBAD_MSGS1 (FFEBAD_MISSING_FORMAT_SPEC, FATAL,
+"Specification at %0 requires explicit FMT= specification in same I/O control list")
+FFEBAD_MSGS2 (FFEBAD_SPEC_VALUE, FATAL,
+"Unrecognized value for character constant at %0 -- expecting %A",
+"Unrecognized value for character constant at %0")
+FFEBAD_MSGS1 (FFEBAD_CASE_SECOND_DEFAULT, FATAL,
+"Second occurrence of CASE DEFAULT at %0 within SELECT CASE at %1")
+FFEBAD_MSGS1 (FFEBAD_CASE_DUPLICATE, FATAL,
+"Duplicate or overlapping case values/ranges at %0 and %1")
+FFEBAD_MSGS1 (FFEBAD_CASE_TYPE_DISAGREE, FATAL,
+"Type and/or kind-type parameter disagreement between CASE value or value within range at %0 and SELECT CASE at %1")
+FFEBAD_MSGS1 (FFEBAD_CASE_LOGICAL_RANGE, FATAL,
+"Range specification at %0 invalid for CASE statement within logical-type SELECT CASE statement")
+FFEBAD_MSGS2 (FFEBAD_CASE_BAD_RANGE, FATAL,
+"Range specification at %0 invalid -- at least one expression must be specified, or use CASE DEFAULT",
+"Range specification at %0 invalid")
+FFEBAD_MSGS2 (FFEBAD_CASE_RANGE_USELESS, INFORM,
+"Range specification at %0 useless; first expression greater than second expression in range, so range can never be matched by any selection expression",
+"Useless range at %0")
+FFEBAD_MSGS1 (FFEBAD_F90, FATAL,
+"Fortran 90 feature at %0 unsupported")
+FFEBAD_MSGS2 (FFEBAD_KINDTYPE, FATAL,
+"Invalid kind at %0 for type at %1 -- unsupported or not permitted",
+"Invalid kind at %0 for type at %1")
+FFEBAD_MSGS2 (FFEBAD_BAD_IMPLICIT, FATAL,
+"Cannot establish implicit type for initial letter `%A' at %0 -- already explicitly established or used to set implicit type of some name, or backwards order of letters in letter range",
+"Cannot establish implicit type for initial letter `%A' at %0")
+FFEBAD_MSGS1 (FFEBAD_SYMERR, FATAL,
+"Invalid declaration of or reference to symbol `%A' at %0 [initially seen at %1]")
+FFEBAD_MSGS2 (FFEBAD_LABEL_WRONG_PLACE, FATAL,
+"Label definition %A (at %0) invalid -- must be in columns 1-5",
+"Invalid label definition %A (at %0)")
+FFEBAD_MSGS1 (FFEBAD_NULL_ELEMENT, FATAL,
+"Null element at %0 for array reference at %1")
+FFEBAD_MSGS1 (FFEBAD_TOO_FEW_ELEMENTS, FATAL,
+"Too few elements (%A missing) as of %0 for array reference at %1")
+FFEBAD_MSGS1 (FFEBAD_TOO_MANY_ELEMENTS, FATAL,
+"Too many elements as of %0 for array reference at %1")
+FFEBAD_MSGS1 (FFEBAD_MISSING_COLON_IN_SUBSTR, FATAL,
+"Missing colon as of %0 in substring reference for %1")
+FFEBAD_MSGS1 (FFEBAD_BAD_SUBSTR, FATAL,
+"Invalid use at %0 of substring operator on %1")
+FFEBAD_MSGS1 (FFEBAD_RANGE_SUBSTR, WARN,
+"Substring begin/end point at %0 out of defined range")
+FFEBAD_MSGS1 (FFEBAD_RANGE_ARRAY, WARN,
+"Array element value at %0 out of defined range")
+FFEBAD_MSGS1 (FFEBAD_EXPR_WRONG, FATAL,
+"Expression at %0 has incorrect data type or rank for its context")
+FFEBAD_MSGS1 (FFEBAD_DIV_BY_ZERO, WARN,
+"Division by 0 (zero) at %0 (IEEE not yet supported)")
+FFEBAD_MSGS1 (FFEBAD_DO_STEP_ZERO, FATAL,
+"%A step count known to be 0 (zero) at %0")
+FFEBAD_MSGS1 (FFEBAD_DO_END_OVERFLOW, WARN,
+"%A end value plus step count known to overflow at %0")
+FFEBAD_MSGS1 (FFEBAD_DO_IMP_OVERFLOW, WARN,
+"%A begin, end, and step-count values known to result in implementation-dependent behavior due to overflow(s) in intermediate calculations at %0")
+FFEBAD_MSGS1 (FFEBAD_DO_NULL, WARN,
+"%A begin, end, and step-count values known to result in no iterations at %0")
+FFEBAD_MSGS1 (FFEBAD_BAD_TYPES, FATAL,
+"Type disagreement between expressions at %0 and %1")
+FFEBAD_MSGS2 (FFEBAD_FORMAT_EXPR_SPEC, FATAL,
+"Run-time expression at %0 in FORMAT statement that does not follow the first executable statement in the program unit -- move the statement",
+"FORMAT at %0 with run-time expression must follow first executable statement")
+FFEBAD_MSGS2 (FFEBAD_BAD_IMPDO, FATAL,
+"Unexpected token at %0 in implied-DO construct at %1 -- form of implied-DO is `(item-list,do-var=start,end[,incr])'",
+"Unexpected token at %0 in implied-DO construct at %1")
+FFEBAD_MSGS1 (FFEBAD_BAD_IMPDCL, FATAL,
+"No specification for implied-DO iterator `%A' at %0")
+FFEBAD_MSGS1 (FFEBAD_IMPDO_PAREN, WARN,
+"Gratuitous parentheses surround implied-DO construct at %0")
+FFEBAD_MSGS1 (FFEBAD_ZERO_SIZE, FATAL,
+"Zero-size specification invalid at %0")
+FFEBAD_MSGS1 (FFEBAD_ZERO_ARRAY, FATAL,
+"Zero-size array at %0")
+FFEBAD_MSGS1 (FFEBAD_BAD_COMPLEX, FATAL,
+"Target machine does not support complex entity of kind specified at %0")
+FFEBAD_MSGS1 (FFEBAD_BAD_DBLCMPLX, FATAL,
+"Target machine does not support DOUBLE COMPLEX, specified at %0")
+FFEBAD_MSGS1 (FFEBAD_BAD_POWER, WARN,
+"Attempt to raise constant zero to a power at %0")
+FFEBAD_MSGS2 (FFEBAD_BOOL_ARGS_TYPE, FATAL,
+"Boolean/logical operator at %0 must operate on two subexpressions of logical type, but neither subexpression at %1 or %2 is of logical type",
+"Invalid operands at %1 and %2 for boolean operator at %0")
+FFEBAD_MSGS2 (FFEBAD_BOOL_ARG_TYPE, FATAL,
+"Boolean/logical operator at %0 must operate on two subexpressions of logical type, but the subexpression at %1 is not of logical type",
+"Invalid operand at %1 for boolean operator at %0")
+FFEBAD_MSGS2 (FFEBAD_BOOL_ARG_KIND, FATAL,
+"Boolean/logical operator at %0 must operate on two scalar (not array) subexpressions, two function invocations returning logical scalars, or a combination of both -- but the subexpression at %1 is %A",
+"Invalid operand (is %A) at %1 for boolean operator at %0")
+FFEBAD_MSGS2 (FFEBAD_NOT_ARG_TYPE, FATAL,
+".NOT. operator at %0 must operate on subexpression of logical type, but the subexpression at %1 is not of logical type",
+"Invalid operand at %1 for .NOT. operator at %0")
+FFEBAD_MSGS2 (FFEBAD_NOT_ARG_KIND, FATAL,
+".NOT. operator at %0 must operate on scalar subexpressions -- but the subexpression at %1 is %A",
+"Invalid operand (is %A) at %1 for .NOT. operator at %0")
+FFEBAD_MSGS2 (FFEBAD_EQOP_ARGS_TYPE, FATAL,
+"Equality operator at %0 must operate on two subexpressions of arithmetic or character type, but neither subexpression at %1 or %2 is of arithmetic or character type",
+"Invalid operands at %1 and %2 for equality operator at %0")
+FFEBAD_MSGS2 (FFEBAD_EQOP_ARG_TYPE, FATAL,
+"Equality operator at %0 must operate on two subexpressions of arithmetic or character type, but the subexpression at %1 is not of arithmetic or character type",
+"Invalid operand at %1 for equality operator at %0")
+FFEBAD_MSGS2 (FFEBAD_EQOP_ARG_KIND, FATAL,
+"Equality operator at %0 must operate on two scalar (not array) subexpressions, two function invocations returning arithmetic or character scalars, or a combination of both -- but the subexpression at %1 is %A",
+"Invalid operand (is %A) at %1 for equality operator at %0")
+FFEBAD_MSGS2 (FFEBAD_RELOP_ARGS_TYPE, FATAL,
+"Relational operator at %0 must operate on two subexpressions of integer, real, or character type, but neither subexpression at %1 or %2 is of integer, real, or character type",
+"Invalid operands at %1 and %2 for relational operator at %0")
+FFEBAD_MSGS2 (FFEBAD_RELOP_ARG_TYPE, FATAL,
+"Relational operator at %0 must operate on two subexpressions of integer, real, or character type, but the subexpression at %1 is not of integer, real, or character type",
+"Invalid operand at %1 for relational operator at %0")
+FFEBAD_MSGS2 (FFEBAD_RELOP_ARG_KIND, FATAL,
+"Relational operator at %0 must operate on two scalar (not array) subexpressions, two function invocations returning integer, real, or character scalars, or a combination of both -- but the subexpression at %1 is %A",
+"Invalid operand (is %A) at %1 for relational operator at %0")
+FFEBAD_MSGS2 (FFEBAD_INTRINSIC_REF, FATAL,
+"Reference to intrinsic `%A' at %0 invalid -- one or more arguments have incorrect type",
+"Invalid reference to intrinsic `%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_INTRINSIC_TOOFEW, FATAL,
+"Too few arguments passed to intrinsic `%A' at %0",
+"Too few arguments for intrinsic `%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_INTRINSIC_TOOMANY, FATAL,
+"Too many arguments passed to intrinsic `%A' at %0",
+"Too many arguments for intrinsic `%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_INTRINSIC_DISABLED, FATAL,
+"Reference to disabled intrinsic `%A' at %0",
+"Disabled intrinsic `%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_INTRINSIC_IS_SUBR, FATAL,
+"Reference to intrinsic subroutine `%A' as if it were a function at %0",
+"Function reference to intrinsic subroutine `%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_INTRINSIC_IS_FUNC, FATAL,
+"Reference to intrinsic function `%A' as if it were a subroutine at %0",
+"Subroutine reference to intrinsic function `%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_INTRINSIC_UNIMPL, FATAL,
+"Reference to unimplemented intrinsic `%A' at %0 -- use EXTERNAL to reference user-written procedure with this name",
+"Unimplemented intrinsic `%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_INTRINSIC_UNIMPLW, WARN,
+"Reference to unimplemented intrinsic `%A' at %0 (assumed EXTERNAL)",
+"Unimplemented intrinsic `%A' at %0 (assumed EXTERNAL)")
+FFEBAD_MSGS1 (FFEBAD_INTRINSIC_AMBIG, FATAL,
+"Reference to generic intrinsic `%A' at %0 could be to form %B or %C")
+FFEBAD_MSGS1 (FFEBAD_INTRINSIC_CMPAMBIG, FATAL,
+"Ambiguous use of intrinsic `%A' at %0 [info -f g77 M CMPAMBIG]")
+FFEBAD_MSGS1 (FFEBAD_INTRINSIC_EXPIMP, WARN,
+"Intrinsic `%A' referenced %Bly at %0, %Cly at %1 [info -f g77 M EXPIMP]")
+FFEBAD_MSGS1 (FFEBAD_INTRINSIC_GLOBAL, WARN,
+"Same name `%A' used for %B at %0 and %C at %1 [info -f g77 M INTGLOB]")
+FFEBAD_MSGS1 (FFEBAD_INTRINSIC_TYPE, WARN,
+"Explicit type declaration for intrinsic `%A' disagrees with invocation at %0")
+FFEBAD_MSGS1 (FFEBAD_OPEN_INCLUDE, FATAL,
+"Unable to open INCLUDE file `%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_DOITER, FATAL,
+"Attempt to modify variable `%A' at %0 while it serves as DO-loop iterator at %1",
+"Modification of DO-loop iterator `%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_DOITER_IMPDO, FATAL,
+"Attempt to modify variable `%A' via item #%B in list at %0 while it serves as implied-DO iterator at %1",
+"Modification of DO-loop iterator `%A' at %0")
+FFEBAD_MSGS2 (FFEBAD_TOO_MANY_DIMS, FATAL,
+"Array has too many dimensions, as of dimension specifier at %0",
+"Too many dimensions at %0")
+FFEBAD_MSGS1 (FFEBAD_NULL_ARGUMENT, FATAL,
+"Null argument at %0 for statement function reference at %1")
+FFEBAD_MSGS1 (FFEBAD_NULL_ARGUMENT_W, WARN,
+"Null argument at %0 for procedure invocation at %1")
+FFEBAD_MSGS1 (FFEBAD_TOO_FEW_ARGUMENTS, FATAL,
+"%A too few arguments (starting with dummy argument `%B') as of %0 for statement function reference at %1")
+FFEBAD_MSGS1 (FFEBAD_TOO_MANY_ARGUMENTS, FATAL,
+"%A too many arguments as of %0 for statement function reference at %1")
+FFEBAD_MSGS1 (FFEBAD_ARRAY_AS_SFARG, FATAL,
+"Array supplied at %1 for dummy argument `%A' in statement function reference at %0")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_UNSUPPORTED, FATAL,
+"Unsupported FORMAT specifier at %0")
+FFEBAD_MSGS1 (FFEBAD_FORMAT_VARIABLE, FATAL,
+"Variable-expression FORMAT specifier at %0 -- unsupported")
+FFEBAD_MSGS2 (FFEBAD_OPEN_UNSUPPORTED, FATAL,
+"Unsupported OPEN control item at %0 -- ACTION=, ASSOCIATEVARIABLE=, BLOCKSIZE=, BUFFERCOUNT=, CARRIAGECONTROL=, DEFAULTFILE=, DELIM=, DISPOSE=, EXTENDSIZE=, INITIALSIZE=, KEY=, MAXREC=, NOSPANBLOCKS, ORGANIZATION=, PAD=, POSITION=, READONLY=, RECORDTYPE=, SHARED=, and USEROPEN= are not supported",
+"Unsupported OPEN control item at %0")
+FFEBAD_MSGS2 (FFEBAD_INQUIRE_UNSUPPORTED, FATAL,
+"Unsupported INQUIRE control item at %0 -- ACTION=, CARRIAGECONTROL=, DEFAULTFILE=, DELIM=, KEYED=, ORGANIZATION=, PAD=, POSITION=, READ=, READWRITE=, RECORDTYPE=, and WRITE= are not supported",
+"Unsupported INQUIRE control item at %0")
+FFEBAD_MSGS2 (FFEBAD_READ_UNSUPPORTED, FATAL,
+"Unsupported READ control item at %0 -- ADVANCE=, EOR=, KEYEQ=, KEYGE=, KEYGT=, KEYID=, NULLS=, and SIZE= are not supported",
+"Unsupported READ control item at %0")
+FFEBAD_MSGS2 (FFEBAD_WRITE_UNSUPPORTED, FATAL,
+"Unsupported WRITE control item at %0 -- ADVANCE= and EOR= are not supported",
+"Unsupported WRITE control item at %0")
+FFEBAD_MSGS1 (FFEBAD_VXT_UNSUPPORTED, FATAL,
+"Unsupported VXT statement at %0")
+FFEBAD_MSGS1 (FFEBAD_DATA_REINIT, FATAL,
+"Attempt to specify second initial value for `%A' at %0")
+FFEBAD_MSGS1 (FFEBAD_DATA_TOOFEW, FATAL,
+"Too few initial values in list of initializers for `%A' at %0")
+FFEBAD_MSGS1 (FFEBAD_DATA_TOOMANY, FATAL,
+"Too many initial values in list of initializers starting at %0")
+FFEBAD_MSGS1 (FFEBAD_DATA_RANGE, FATAL,
+"Array or substring specification for `%A' out of range in statement at %0")
+FFEBAD_MSGS1 (FFEBAD_DATA_SUBSCRIPT, FATAL,
+"Array subscript #%B out of range for initialization of `%A' in statement at %0")
+FFEBAD_MSGS1 (FFEBAD_DATA_ZERO, FATAL,
+"Implied do-loop step count of 0 (zero) for iteration variable `%A' in statement at %0")
+FFEBAD_MSGS1 (FFEBAD_DATA_EMPTY, FATAL,
+"Implied do-loop iteration count of 0 (zero) for iteration variable `%A' in statement at %0")
+FFEBAD_MSGS1 (FFEBAD_DATA_EVAL, FATAL,
+"Not an integer constant expression in implied do-loop in statement at %0")
+FFEBAD_MSGS1 (FFEBAD_DATA_MULTIPLE, FATAL,
+"Attempt to specify second initial value for element of `%A' at %0")
+FFEBAD_MSGS1 (FFEBAD_EQUIV_COMMON, FATAL,
+"Attempt to EQUIVALENCE common areas `%A' and `%B' at %0")
+FFEBAD_MSGS1 (FFEBAD_EQUIV_ALIGN, FATAL,
+"Can't place `%A' as directed by EQUIVALENCE due to alignment restrictions")
+FFEBAD_MSGS1 (FFEBAD_EQUIV_MISMATCH, FATAL,
+"Mismatched EQUIVALENCE requirements for placement of `%A' at both %C and %D bytes offset from `%B'")
+FFEBAD_MSGS1 (FFEBAD_EQUIV_RANGE, FATAL,
+"Array or substring specification for `%A' out of range in EQUIVALENCE statement")
+FFEBAD_MSGS1 (FFEBAD_EQUIV_SUBSTR, FATAL,
+"Substring of non-CHARACTER entity `%A' in EQUIVALENCE statement")
+FFEBAD_MSGS1 (FFEBAD_EQUIV_ARRAY, FATAL,
+"Array reference to scalar variable `%A' in EQUIVALENCE statement")
+FFEBAD_MSGS1 (FFEBAD_EQUIV_SUBSCRIPT, WARN,
+"Array subscript #%B out of range for EQUIVALENCE of `%A'")
+FFEBAD_MSGS2 (FFEBAD_COMMON_PAD, WARN,
+"Padding of %A %D required before `%B' in common block `%C' at %0 -- consider reordering members, largest-type-size first",
+"Padding of %A %D required before `%B' in common block `%C' at %0")
+FFEBAD_MSGS1 (FFEBAD_COMMON_NEG, FATAL,
+"Attempt to extend COMMON area beyond its starting point via EQUIVALENCE of `%A'")
+FFEBAD_MSGS1 (FFEBAD_EQUIV_FEW, FATAL,
+"Too few elements in reference to array `%A' in EQUIVALENCE statement")
+FFEBAD_MSGS1 (FFEBAD_EQUIV_MANY, FATAL,
+"Too many elements in reference to array `%A' in EQUIVALENCE statement")
+FFEBAD_MSGS1 (FFEBAD_MIXED_TYPES, WARN,
+"Mixed CHARACTER and non-CHARACTER types via COMMON/EQUIVALENCE -- for example, `%A' and `%B'")
+FFEBAD_MSGS2 (FFEBAD_IMPLICIT_ADJLEN, FATAL,
+"Invalid length specification at %0 for IMPLICIT statement -- must be integer constant expression",
+"Invalid length specification at %0")
+FFEBAD_MSGS2 (FFEBAD_ENTRY_CONFLICTS, FATAL,
+"Type of ENTRY point at %0 to function conflicts with type(s) of previous entrypoint(s) -- must all be identical-length CHARACTER or none be CHARACTER type",
+"Type of ENTRY point at %0 to function conflicts with type(s) of previous entrypoint(s)")
+FFEBAD_MSGS1 (FFEBAD_RETURN_VALUE_UNSET, WARN,
+"Return value `%A' for FUNCTION at %0 not referenced in subprogram")
+FFEBAD_MSGS2 (FFEBAD_COMMON_ALREADY_INIT, FATAL,
+"Common block `%A' initialized at %0 already initialized at %1 -- only one program unit may specify initial values for a particular common block",
+"Common block `%A' initialized at %0 already initialized at %1")
+FFEBAD_MSGS2 (FFEBAD_COMMON_INIT_PAD, WARN,
+"Initial padding for common block `%A' is %B %C at %0 -- consider reordering members, largest-type-size first",
+"Initial padding for common block `%A' is %B %C at %0")
+FFEBAD_MSGS2 (FFEBAD_COMMON_DIFF_PAD, FATAL,
+"Initial padding for common block `%A' is %B %D at %0 but %C %E at %1 -- consider reordering members, largest-type-size first",
+"Initial padding for common block `%A' is %B %D at %0 but %C %E at %1")
+FFEBAD_MSGS1 (FFEBAD_COMMON_DIFF_SAVE, WARN,
+"Common block `%A' is SAVEd, explicitly or implicitly, at %0 but not SAVEd at %1")
+FFEBAD_MSGS1 (FFEBAD_COMMON_DIFF_SIZE, WARN,
+"Common block `%A' is %B %D in length at %0 but %C %E at %1")
+FFEBAD_MSGS2 (FFEBAD_COMMON_ENLARGED, FATAL,
+"Common block `%A' is initialized to %B %D long at %0 but enlarged to %C %E at %1 -- use consistent definitions or reorder program units in source file",
+"Common block `%A' is initialized to %B %D long at %0 but enlarged to %C %E at %1")
+FFEBAD_MSGS1 (FFEBAD_COMMON_BLANK_INIT, WARN,
+"Blank common initialized at %0")
+FFEBAD_MSGS1 (FFEBAD_NEED_INTRINSIC, WARN,
+"Intrinsic `%A' is passed as actual argument at %0 but not explicitly declared INTRINSIC")
+FFEBAD_MSGS1 (FFEBAD_NEED_EXTERNAL, WARN,
+"External procedure `%A' is passed as actual argument at %0 but not explicitly declared EXTERNAL")
+FFEBAD_MSGS1 (FFEBAD_SYMBOL_UPPER_CASE, WARN,
+"Character `%A' (for example) is upper-case in symbol name at %0")
+FFEBAD_MSGS1 (FFEBAD_SYMBOL_LOWER_CASE, WARN,
+"Character `%A' (for example) is lower-case in symbol name at %0")
+FFEBAD_MSGS1 (FFEBAD_SYMBOL_NOLOWER_INITCAP, WARN,
+"Character `%A' not followed at some point by lower-case character in symbol name at %0")
+FFEBAD_MSGS1 (FFEBAD_SYMBOL_LOWER_INITCAP, WARN,
+"Initial character `%A' is lower-case in symbol name at %0")
+FFEBAD_MSGS2 (FFEBAD_DO_REAL, WARN,
+"DO-variable `%A' is type REAL or DOUBLE PRECISION at %0 -- unexpected behavior likely",
+"DO-variable `%A' is type REAL or DOUBLE PRECISION at %0")
+FFEBAD_MSGS1 (FFEBAD_NAMELIST_CASE, WARN,
+"NAMELIST not adequately supported by run-time library for source files with case preserved")
+FFEBAD_MSGS1 (FFEBAD_NESTED_PERCENT, WARN,
+"Nested %% construct (%%VAL, %%REF, or %%DESCR) at %0")
+FFEBAD_MSGS2 (FFEBAD_ACTUALARG, WARN,
+"Invalid actual argument at %0 -- replace hollerith constants with %%REF('string') and typeless constants with INTEGER constant equivalents, or use -fugly-args or -fugly",
+"Invalid actual argument at %0")
+FFEBAD_MSGS2 (FFEBAD_QUAD_UNSUPPORTED, FATAL,
+"Quadruple-precision floating-point unsupported -- treating constant at %0 as double-precision",
+"Quadruple-precision floating-point unsupported")
+FFEBAD_MSGS2 (FFEBAD_TOO_BIG_INIT, WARN,
+"Initialization of large (%B-unit) aggregate area `%A' at %0 currently very slow and takes lots of memory during g77 compile -- to be improved in 0.6",
+"This could take a while (initializing `%A' at %0)...")
+FFEBAD_MSGS1 (FFEBAD_BLOCKDATA_STMT, FATAL,
+"Statement at %0 invalid in BLOCK DATA program unit at %1")
+FFEBAD_MSGS1 (FFEBAD_TRUNCATING_CHARACTER, FATAL,
+"Truncating characters on right side of character constant at %0")
+FFEBAD_MSGS1 (FFEBAD_TRUNCATING_HOLLERITH, FATAL,
+"Truncating characters on right side of hollerith constant at %0")
+FFEBAD_MSGS1 (FFEBAD_TRUNCATING_NUMERIC, FATAL,
+"Truncating non-zero data on left side of numeric constant at %0")
+FFEBAD_MSGS1 (FFEBAD_TRUNCATING_TYPELESS, FATAL,
+"Truncating non-zero data on left side of typeless constant at %0")
+FFEBAD_MSGS1 (FFEBAD_TYPELESS_OVERFLOW, FATAL,
+"Typeless constant at %0 too large")
+FFEBAD_MSGS1 (FFEBAD_AMPERSAND, WARN,
+"First-column ampersand continuation at %0")
+FFEBAD_MSGS1 (FFEBAD_FILEWIDE_ALREADY_SEEN, FATAL,
+"Global name `%A' defined at %0 already defined at %1 [info -f g77 M GLOBALS]")
+FFEBAD_MSGS1 (FFEBAD_FILEWIDE_ALREADY_SEEN_W, WARN,
+"Global name `%A' defined at %0 already defined at %1 [info -f g77 M GLOBALS]")
+FFEBAD_MSGS1 (FFEBAD_FILEWIDE_DISAGREEMENT, FATAL,
+"Global name `%A' is %B at %0 but is %C at %1 [info -f g77 M GLOBALS]")
+FFEBAD_MSGS1 (FFEBAD_FILEWIDE_DISAGREEMENT_W, WARN,
+"Global name `%A' is %B at %0 but is %C at %1 [info -f g77 M GLOBALS]")
+FFEBAD_MSGS1 (FFEBAD_FILEWIDE_TYPE_MISMATCH, FATAL,
+"Global name `%A' at %0 has different type at %1 [info -f g77 M GLOBALS]")
+FFEBAD_MSGS1 (FFEBAD_FILEWIDE_TYPE_MISMATCH_W, WARN,
+"Global name `%A' at %0 has different type at %1 [info -f g77 M GLOBALS]")
+FFEBAD_MSGS1 (FFEBAD_FILEWIDE_NARGS, FATAL,
+"Too %B arguments passed to `%A' at %0 versus definition at %1 [info -f g77 M GLOBALS]")
+FFEBAD_MSGS1 (FFEBAD_FILEWIDE_NARGS_W, WARN,
+"Too %B arguments for `%A' at %0 versus invocation at %1 [info -f g77 M GLOBALS]")
+FFEBAD_MSGS1 (FFEBAD_FILEWIDE_ARG, FATAL,
+"Argument #%B of `%A' is %C at %0 but is %D at %1 [info -f g77 M GLOBALS]")
+FFEBAD_MSGS1 (FFEBAD_FILEWIDE_ARG_W, WARN,
+"Argument #%B of `%A' is %C at %0 but is %D at %1 [info -f g77 M GLOBALS]")
+FFEBAD_MSGS1 (FFEBAD_ARRAY_LARGE, FATAL,
+"Array `%A' at %0 is too large to handle")
+FFEBAD_MSGS1 (FFEBAD_SFUNC_UNUSED, WARN,
+"Statement function `%A' defined at %0 is not used")
+
+#undef INFORM
+#undef TRIVIAL
+#undef WARN
+#undef PECULIAR
+#undef FATAL
+#undef WEIRD
+#undef SEVERE
+#undef DISASTER
diff --git a/contrib/gcc/f/bad.h b/contrib/gcc/f/bad.h
new file mode 100644
index 0000000..a52ff1f
--- /dev/null
+++ b/contrib/gcc/f/bad.h
@@ -0,0 +1,108 @@
+/* bad.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ bad.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_bad
+#define _H_f_bad
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+#define FFEBAD_MSGS1(KWD,SEV,MSG) KWD,
+#define FFEBAD_MSGS2(KWD,SEV,LMSG,SMSG) KWD,
+#include "bad.def"
+#undef FFEBAD_MSGS1
+#undef FFEBAD_MSGS2
+ FFEBAD
+ } ffebad;
+
+typedef enum
+ {
+
+ /* Order important; must be increasing severity. */
+
+ FFEBAD_severityINFORMATIONAL, /* User notice. */
+ FFEBAD_severityTRIVIAL, /* Internal notice. */
+ FFEBAD_severityWARNING, /* User warning. */
+ FFEBAD_severityPECULIAR, /* Internal warning. */
+ FFEBAD_severityPEDANTIC, /* Pedantic, could be warning or error. */
+ FFEBAD_severityFATAL, /* User error. */
+ FFEBAD_severityWEIRD, /* Internal error. */
+ FFEBAD_severitySEVERE, /* User error, cannot continue. */
+ FFEBAD_severityDISASTER, /* Internal error, cannot continue. */
+ FFEBAD_severity
+ } ffebadSeverity;
+
+/* Typedefs. */
+
+typedef unsigned char ffebadIndex;
+
+/* Include files needed by this one. */
+
+#include "where.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+extern bool ffebad_is_inhibited_;
+
+/* Declare functions with prototypes. */
+
+void ffebad_finish (void);
+void ffebad_here (ffebadIndex i, ffewhereLine wl, ffewhereColumn wc);
+void ffebad_init_0 (void);
+bool ffebad_is_fatal (ffebad errnum);
+ffebadSeverity ffebad_severity (ffebad errnum);
+bool ffebad_start_ (bool lex_override, ffebad errnum, ffebadSeverity sev,
+ char *message);
+void ffebad_string (char *string);
+
+/* Define macros. */
+
+#define ffebad_inhibit() (ffebad_is_inhibited_)
+#define ffebad_init_1()
+#define ffebad_init_2()
+#define ffebad_init_3()
+#define ffebad_init_4()
+#define ffebad_set_inhibit(f) (ffebad_is_inhibited_ = (f))
+#define ffebad_start(e) ffebad_start_ (FALSE, (e), FFEBAD_severity, NULL)
+#define ffebad_start_lex(e) ffebad_start_ (TRUE, (e), FFEBAD_severity, NULL)
+#define ffebad_start_msg(m,s) ffebad_start_ (FALSE, FFEBAD, (s), (m))
+#define ffebad_start_msg_lex(m,s) ffebad_start_ (TRUE, FFEBAD, (s), (m))
+#define ffebad_terminate_0()
+#define ffebad_terminate_1()
+#define ffebad_terminate_2()
+#define ffebad_terminate_3()
+#define ffebad_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/bit.c b/contrib/gcc/f/bit.c
new file mode 100644
index 0000000..71e74d7
--- /dev/null
+++ b/contrib/gcc/f/bit.c
@@ -0,0 +1,201 @@
+/* bit.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Tracks arrays of booleans in useful ways.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "glimits.j"
+#include "bit.h"
+#include "malloc.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+
+/* ffebit_count -- Count # of bits set a particular way
+
+ ffebit b; // the ffebit object
+ ffebitCount offset; // 0..size-1
+ bool value; // FALSE (0), TRUE (1)
+ ffebitCount range; // # bits to test
+ ffebitCount number; // # bits equal to value
+ ffebit_count(b,offset,value,range,&number);
+
+ Sets <number> to # bits at <offset> through <offset + range - 1> set to
+ <value>. If <range> is 0, <number> is set to 0. */
+
+void
+ffebit_count (ffebit b, ffebitCount offset, bool value, ffebitCount range,
+ ffebitCount *number)
+{
+ ffebitCount element;
+ ffebitCount bitno;
+
+ assert (offset + range <= b->size);
+
+ for (*number = 0; range != 0; --range, ++offset)
+ {
+ element = offset / CHAR_BIT;
+ bitno = offset % CHAR_BIT;
+ if (value
+ == ((b->bits[element] & ((unsigned char) 1 << bitno)) == 0 ? FALSE : TRUE))
+ ++ * number;
+ }
+}
+
+/* ffebit_new -- Create a new ffebit object
+
+ ffebit b;
+ ffebit_kill(b);
+
+ Destroys an ffebit object obtained via ffebit_new. */
+
+void
+ffebit_kill (ffebit b)
+{
+ malloc_kill_ks (b->pool, b,
+ offsetof (struct _ffebit_, bits)
+ + (b->size + CHAR_BIT - 1) / CHAR_BIT);
+}
+
+/* ffebit_new -- Create a new ffebit object
+
+ ffebit b;
+ mallocPool pool;
+ ffebitCount size;
+ b = ffebit_new(pool,size);
+
+ Allocates an ffebit object that holds the values of <size> bits in pool
+ <pool>. */
+
+ffebit
+ffebit_new (mallocPool pool, ffebitCount size)
+{
+ ffebit b;
+
+ b = malloc_new_zks (pool, "ffebit",
+ offsetof (struct _ffebit_, bits)
+ + (size + CHAR_BIT - 1) / CHAR_BIT,
+ 0);
+ b->pool = pool;
+ b->size = size;
+
+ return b;
+}
+
+/* ffebit_set -- Set value of # of bits
+
+ ffebit b; // the ffebit object
+ ffebitCount offset; // 0..size-1
+ bool value; // FALSE (0), TRUE (1)
+ ffebitCount length; // # bits to set starting at offset (usually 1)
+ ffebit_set(b,offset,value,length);
+
+ Sets bit #s <offset> through <offset + length - 1> to <value>. */
+
+void
+ffebit_set (ffebit b, ffebitCount offset, bool value, ffebitCount length)
+{
+ ffebitCount i;
+ ffebitCount element;
+ ffebitCount bitno;
+
+ assert (offset + length <= b->size);
+
+ for (i = 0; i < length; ++i, ++offset)
+ {
+ element = offset / CHAR_BIT;
+ bitno = offset % CHAR_BIT;
+ b->bits[element] = (((unsigned char) (value ? 1 : 0)) << bitno)
+ | (b->bits[element] & ~((unsigned char) 1 << bitno));
+ }
+}
+
+/* ffebit_test -- Test value of # of bits
+
+ ffebit b; // the ffebit object
+ ffebitCount offset; // 0..size-1
+ bool value; // FALSE (0), TRUE (1)
+ ffebitCount length; // # bits with same value
+ ffebit_test(b,offset,&value,&length);
+
+ Returns value of bits at <offset> through <offset + length - 1> in
+ <value>. If <offset> is already at the end of the bit array (if
+ offset == ffebit_size(b)), <length> is set to 0 and <value> is
+ undefined. */
+
+void
+ffebit_test (ffebit b, ffebitCount offset, bool *value, ffebitCount *length)
+{
+ ffebitCount i;
+ ffebitCount element;
+ ffebitCount bitno;
+
+ if (offset >= b->size)
+ {
+ assert (offset == b->size);
+ *length = 0;
+ return;
+ }
+
+ element = offset / CHAR_BIT;
+ bitno = offset % CHAR_BIT;
+ *value = (b->bits[element] & ((unsigned char) 1 << bitno)) == 0 ? FALSE : TRUE;
+ *length = 1;
+
+ for (i = b->size - offset - 1, ++offset; i != 0; --i, ++offset, ++*length)
+ {
+ element = offset / CHAR_BIT;
+ bitno = offset % CHAR_BIT;
+ if (*value
+ != ((b->bits[element] & ((unsigned char) 1 << bitno)) == 0 ? FALSE : TRUE))
+ break;
+ }
+}
diff --git a/contrib/gcc/f/bit.h b/contrib/gcc/f/bit.h
new file mode 100644
index 0000000..0e84499
--- /dev/null
+++ b/contrib/gcc/f/bit.h
@@ -0,0 +1,84 @@
+/* bit.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ bit.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_bit
+#define _H_f_bit
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+typedef struct _ffebit_ *ffebit;
+typedef unsigned long ffebitCount;
+#define ffebitCount_f "l"
+
+/* Include files needed by this one. */
+
+#include "malloc.h"
+
+/* Structure definitions. */
+
+struct _ffebit_
+ {
+ mallocPool pool;
+ ffebitCount size;
+ unsigned char bits[1];
+ };
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+void ffebit_count (ffebit b, ffebitCount offset, bool value, ffebitCount range,
+ ffebitCount *number);
+void ffebit_kill (ffebit b);
+ffebit ffebit_new (mallocPool pool, ffebitCount size);
+void ffebit_set (ffebit b, ffebitCount offset, bool value, ffebitCount length);
+void ffebit_test (ffebit b, ffebitCount offset, bool *value, ffebitCount *length);
+
+/* Define macros. */
+
+#define ffebit_init_0()
+#define ffebit_init_1()
+#define ffebit_init_2()
+#define ffebit_init_3()
+#define ffebit_init_4()
+#define ffebit_pool(b) ((b)->pool)
+#define ffebit_size(b) ((b)->size)
+#define ffebit_terminate_0()
+#define ffebit_terminate_1()
+#define ffebit_terminate_2()
+#define ffebit_terminate_3()
+#define ffebit_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/bld-op.def b/contrib/gcc/f/bld-op.def
new file mode 100644
index 0000000..44cde44
--- /dev/null
+++ b/contrib/gcc/f/bld-op.def
@@ -0,0 +1,69 @@
+/* bld-op.def -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ bad.c
+
+ Modifications:
+*/
+
+FFEBLD_OP (FFEBLD_opANY, "ANY", 0)
+FFEBLD_OP (FFEBLD_opSTAR, "STAR", 0) /* For adjustable arrays, alternate return dummies, etc. */
+FFEBLD_OP (FFEBLD_opCONTER, "CONTER", 0)
+FFEBLD_OP (FFEBLD_opARRTER, "ARRTER", 0) /* Array of constants (DATA...). */
+FFEBLD_OP (FFEBLD_opACCTER, "ACCTER", 0) /* Accreting ARRTER. */
+FFEBLD_OP (FFEBLD_opSYMTER, "SYMTER", 0)
+FFEBLD_OP (FFEBLD_opITEM, "ITEM", 0)
+FFEBLD_OP (FFEBLD_opUPLUS, "UPLUS", 1)
+FFEBLD_OP (FFEBLD_opUMINUS, "UMINUS", 1)
+FFEBLD_OP (FFEBLD_opADD, "ADD", 2)
+FFEBLD_OP (FFEBLD_opSUBTRACT, "SUBTRACT", 2)
+FFEBLD_OP (FFEBLD_opMULTIPLY, "MULTIPLY", 2)
+FFEBLD_OP (FFEBLD_opDIVIDE, "DIVIDE", 2)
+FFEBLD_OP (FFEBLD_opPOWER, "POWER", 2)
+FFEBLD_OP (FFEBLD_opCONCATENATE, "CONCATENATE", 2)
+FFEBLD_OP (FFEBLD_opNOT, "NOT", 1)
+FFEBLD_OP (FFEBLD_opLT, "LT", 2)
+FFEBLD_OP (FFEBLD_opLE, "LE", 2)
+FFEBLD_OP (FFEBLD_opEQ, "EQ", 2)
+FFEBLD_OP (FFEBLD_opNE, "NE", 2)
+FFEBLD_OP (FFEBLD_opGT, "GT", 2)
+FFEBLD_OP (FFEBLD_opGE, "GE", 2)
+FFEBLD_OP (FFEBLD_opAND, "AND", 2)
+FFEBLD_OP (FFEBLD_opOR, "OR", 2)
+FFEBLD_OP (FFEBLD_opXOR, "XOR", 2)
+FFEBLD_OP (FFEBLD_opEQV, "EQV", 2)
+FFEBLD_OP (FFEBLD_opNEQV, "NEQV", 2)
+FFEBLD_OP (FFEBLD_opPAREN, "PAREN", 1)
+FFEBLD_OP (FFEBLD_opPERCENT_LOC, "%LOC", 1)
+FFEBLD_OP (FFEBLD_opPERCENT_VAL, "%VAL", 1)
+FFEBLD_OP (FFEBLD_opPERCENT_REF, "%REF", 1)
+FFEBLD_OP (FFEBLD_opPERCENT_DESCR, "%DESCR", 1)
+FFEBLD_OP (FFEBLD_opCONVERT, "CONVERT", 1)
+FFEBLD_OP (FFEBLD_opREPEAT, "REPEAT", 2)
+FFEBLD_OP (FFEBLD_opBOUNDS, "BOUNDS", 2) /* For low:high in dimension lists. */
+FFEBLD_OP (FFEBLD_opFUNCREF, "FUNCREF", 2)
+FFEBLD_OP (FFEBLD_opSUBRREF, "SUBRREF", 2)
+FFEBLD_OP (FFEBLD_opARRAYREF, "ARRAYREF", 2)
+FFEBLD_OP (FFEBLD_opSUBSTR, "SUBSTR", 2)
+FFEBLD_OP (FFEBLD_opLABTER, "LABTER", 0)
+FFEBLD_OP (FFEBLD_opLABTOK, "LABTOK", 0) /* Like LABTER but contains ffelexToken instead. */
+FFEBLD_OP (FFEBLD_opIMPDO, "IMPDO", 2)
diff --git a/contrib/gcc/f/bld.c b/contrib/gcc/f/bld.c
new file mode 100644
index 0000000..6e75692
--- /dev/null
+++ b/contrib/gcc/f/bld.c
@@ -0,0 +1,5794 @@
+/* bld.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ The primary "output" of the FFE includes ffebld objects, which
+ connect expressions, operators, and operands together, along with
+ connecting lists of expressions together for argument or dimension
+ lists.
+
+ Modifications:
+ 30-Aug-92 JCB 1.1
+ Change names of some things for consistency.
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "bld.h"
+#include "bit.h"
+#include "info.h"
+#include "lex.h"
+#include "malloc.h"
+#include "target.h"
+#include "where.h"
+
+/* Externals defined here. */
+
+ffebldArity ffebld_arity_op_[]
+=
+{
+#define FFEBLD_OP(KWD,NAME,ARITY) ARITY,
+#include "bld-op.def"
+#undef FFEBLD_OP
+};
+struct _ffebld_pool_stack_ ffebld_pool_stack_;
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+#if FFEBLD_BLANK_
+static struct _ffebld_ ffebld_blank_
+=
+{
+ 0,
+ {FFEINFO_basictypeNONE, FFEINFO_kindtypeNONE, 0, FFEINFO_kindNONE,
+ FFEINFO_whereNONE, FFETARGET_charactersizeNONE},
+ {NULL, NULL}
+};
+#endif
+#if FFETARGET_okCHARACTER1
+static ffebldConstant ffebld_constant_character1_;
+#endif
+#if FFETARGET_okCHARACTER2
+static ffebldConstant ffebld_constant_character2_;
+#endif
+#if FFETARGET_okCHARACTER3
+static ffebldConstant ffebld_constant_character3_;
+#endif
+#if FFETARGET_okCHARACTER4
+static ffebldConstant ffebld_constant_character4_;
+#endif
+#if FFETARGET_okCHARACTER5
+static ffebldConstant ffebld_constant_character5_;
+#endif
+#if FFETARGET_okCHARACTER6
+static ffebldConstant ffebld_constant_character6_;
+#endif
+#if FFETARGET_okCHARACTER7
+static ffebldConstant ffebld_constant_character7_;
+#endif
+#if FFETARGET_okCHARACTER8
+static ffebldConstant ffebld_constant_character8_;
+#endif
+#if FFETARGET_okCOMPLEX1
+static ffebldConstant ffebld_constant_complex1_;
+#endif
+#if FFETARGET_okCOMPLEX2
+static ffebldConstant ffebld_constant_complex2_;
+#endif
+#if FFETARGET_okCOMPLEX3
+static ffebldConstant ffebld_constant_complex3_;
+#endif
+#if FFETARGET_okCOMPLEX4
+static ffebldConstant ffebld_constant_complex4_;
+#endif
+#if FFETARGET_okCOMPLEX5
+static ffebldConstant ffebld_constant_complex5_;
+#endif
+#if FFETARGET_okCOMPLEX6
+static ffebldConstant ffebld_constant_complex6_;
+#endif
+#if FFETARGET_okCOMPLEX7
+static ffebldConstant ffebld_constant_complex7_;
+#endif
+#if FFETARGET_okCOMPLEX8
+static ffebldConstant ffebld_constant_complex8_;
+#endif
+#if FFETARGET_okINTEGER1
+static ffebldConstant ffebld_constant_integer1_;
+#endif
+#if FFETARGET_okINTEGER2
+static ffebldConstant ffebld_constant_integer2_;
+#endif
+#if FFETARGET_okINTEGER3
+static ffebldConstant ffebld_constant_integer3_;
+#endif
+#if FFETARGET_okINTEGER4
+static ffebldConstant ffebld_constant_integer4_;
+#endif
+#if FFETARGET_okINTEGER5
+static ffebldConstant ffebld_constant_integer5_;
+#endif
+#if FFETARGET_okINTEGER6
+static ffebldConstant ffebld_constant_integer6_;
+#endif
+#if FFETARGET_okINTEGER7
+static ffebldConstant ffebld_constant_integer7_;
+#endif
+#if FFETARGET_okINTEGER8
+static ffebldConstant ffebld_constant_integer8_;
+#endif
+#if FFETARGET_okLOGICAL1
+static ffebldConstant ffebld_constant_logical1_;
+#endif
+#if FFETARGET_okLOGICAL2
+static ffebldConstant ffebld_constant_logical2_;
+#endif
+#if FFETARGET_okLOGICAL3
+static ffebldConstant ffebld_constant_logical3_;
+#endif
+#if FFETARGET_okLOGICAL4
+static ffebldConstant ffebld_constant_logical4_;
+#endif
+#if FFETARGET_okLOGICAL5
+static ffebldConstant ffebld_constant_logical5_;
+#endif
+#if FFETARGET_okLOGICAL6
+static ffebldConstant ffebld_constant_logical6_;
+#endif
+#if FFETARGET_okLOGICAL7
+static ffebldConstant ffebld_constant_logical7_;
+#endif
+#if FFETARGET_okLOGICAL8
+static ffebldConstant ffebld_constant_logical8_;
+#endif
+#if FFETARGET_okREAL1
+static ffebldConstant ffebld_constant_real1_;
+#endif
+#if FFETARGET_okREAL2
+static ffebldConstant ffebld_constant_real2_;
+#endif
+#if FFETARGET_okREAL3
+static ffebldConstant ffebld_constant_real3_;
+#endif
+#if FFETARGET_okREAL4
+static ffebldConstant ffebld_constant_real4_;
+#endif
+#if FFETARGET_okREAL5
+static ffebldConstant ffebld_constant_real5_;
+#endif
+#if FFETARGET_okREAL6
+static ffebldConstant ffebld_constant_real6_;
+#endif
+#if FFETARGET_okREAL7
+static ffebldConstant ffebld_constant_real7_;
+#endif
+#if FFETARGET_okREAL8
+static ffebldConstant ffebld_constant_real8_;
+#endif
+static ffebldConstant ffebld_constant_hollerith_;
+static ffebldConstant ffebld_constant_typeless_[FFEBLD_constTYPELESS_LAST
+ - FFEBLD_constTYPELESS_FIRST + 1];
+
+static char *ffebld_op_string_[]
+=
+{
+#define FFEBLD_OP(KWD,NAME,ARITY) NAME,
+#include "bld-op.def"
+#undef FFEBLD_OP
+};
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+#define integerdefault_ CATX(integer,FFETARGET_ktINTEGERDEFAULT)
+#define logicaldefault_ CATX(logical,FFETARGET_ktLOGICALDEFAULT)
+#define realdefault_ CATX(real,FFETARGET_ktREALDEFAULT)
+#define realdouble_ CATX(real,FFETARGET_ktREALDOUBLE)
+#define realquad_ CATX(real,FFETARGET_ktREALQUAD)
+
+/* ffebld_constant_cmp -- Compare two constants a la strcmp
+
+ ffebldConstant c1, c2;
+ if (ffebld_constant_cmp(c1,c2) == 0)
+ // they're equal, else they're not.
+
+ Returns -1 if c1 < c2, 0 if c1 == c2, +1 if c1 == c2. */
+
+int
+ffebld_constant_cmp (ffebldConstant c1, ffebldConstant c2)
+{
+ if (c1 == c2)
+ return 0;
+
+ assert (ffebld_constant_type (c1) == ffebld_constant_type (c2));
+
+ switch (ffebld_constant_type (c1))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEBLD_constINTEGER1:
+ return ffetarget_cmp_integer1 (ffebld_constant_integer1 (c1),
+ ffebld_constant_integer1 (c2));
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEBLD_constINTEGER2:
+ return ffetarget_cmp_integer2 (ffebld_constant_integer2 (c1),
+ ffebld_constant_integer2 (c2));
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEBLD_constINTEGER3:
+ return ffetarget_cmp_integer3 (ffebld_constant_integer3 (c1),
+ ffebld_constant_integer3 (c2));
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEBLD_constINTEGER4:
+ return ffetarget_cmp_integer4 (ffebld_constant_integer4 (c1),
+ ffebld_constant_integer4 (c2));
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEBLD_constINTEGER5:
+ return ffetarget_cmp_integer5 (ffebld_constant_integer5 (c1),
+ ffebld_constant_integer5 (c2));
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEBLD_constINTEGER6:
+ return ffetarget_cmp_integer6 (ffebld_constant_integer6 (c1),
+ ffebld_constant_integer6 (c2));
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEBLD_constINTEGER7:
+ return ffetarget_cmp_integer7 (ffebld_constant_integer7 (c1),
+ ffebld_constant_integer7 (c2));
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEBLD_constINTEGER8:
+ return ffetarget_cmp_integer8 (ffebld_constant_integer8 (c1),
+ ffebld_constant_integer8 (c2));
+#endif
+
+#if FFETARGET_okLOGICAL1
+ case FFEBLD_constLOGICAL1:
+ return ffetarget_cmp_logical1 (ffebld_constant_logical1 (c1),
+ ffebld_constant_logical1 (c2));
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEBLD_constLOGICAL2:
+ return ffetarget_cmp_logical2 (ffebld_constant_logical2 (c1),
+ ffebld_constant_logical2 (c2));
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEBLD_constLOGICAL3:
+ return ffetarget_cmp_logical3 (ffebld_constant_logical3 (c1),
+ ffebld_constant_logical3 (c2));
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEBLD_constLOGICAL4:
+ return ffetarget_cmp_logical4 (ffebld_constant_logical4 (c1),
+ ffebld_constant_logical4 (c2));
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEBLD_constLOGICAL5:
+ return ffetarget_cmp_logical5 (ffebld_constant_logical5 (c1),
+ ffebld_constant_logical5 (c2));
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEBLD_constLOGICAL6:
+ return ffetarget_cmp_logical6 (ffebld_constant_logical6 (c1),
+ ffebld_constant_logical6 (c2));
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEBLD_constLOGICAL7:
+ return ffetarget_cmp_logical7 (ffebld_constant_logical7 (c1),
+ ffebld_constant_logical7 (c2));
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEBLD_constLOGICAL8:
+ return ffetarget_cmp_logical8 (ffebld_constant_logical8 (c1),
+ ffebld_constant_logical8 (c2));
+#endif
+
+#if FFETARGET_okREAL1
+ case FFEBLD_constREAL1:
+ return ffetarget_cmp_real1 (ffebld_constant_real1 (c1),
+ ffebld_constant_real1 (c2));
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEBLD_constREAL2:
+ return ffetarget_cmp_real2 (ffebld_constant_real2 (c1),
+ ffebld_constant_real2 (c2));
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEBLD_constREAL3:
+ return ffetarget_cmp_real3 (ffebld_constant_real3 (c1),
+ ffebld_constant_real3 (c2));
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEBLD_constREAL4:
+ return ffetarget_cmp_real4 (ffebld_constant_real4 (c1),
+ ffebld_constant_real4 (c2));
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEBLD_constREAL5:
+ return ffetarget_cmp_real5 (ffebld_constant_real5 (c1),
+ ffebld_constant_real5 (c2));
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEBLD_constREAL6:
+ return ffetarget_cmp_real6 (ffebld_constant_real6 (c1),
+ ffebld_constant_real6 (c2));
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEBLD_constREAL7:
+ return ffetarget_cmp_real7 (ffebld_constant_real7 (c1),
+ ffebld_constant_real7 (c2));
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEBLD_constREAL8:
+ return ffetarget_cmp_real8 (ffebld_constant_real8 (c1),
+ ffebld_constant_real8 (c2));
+#endif
+
+#if FFETARGET_okCHARACTER1
+ case FFEBLD_constCHARACTER1:
+ return ffetarget_cmp_character1 (ffebld_constant_character1 (c1),
+ ffebld_constant_character1 (c2));
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEBLD_constCHARACTER2:
+ return ffetarget_cmp_character2 (ffebld_constant_character2 (c1),
+ ffebld_constant_character2 (c2));
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEBLD_constCHARACTER3:
+ return ffetarget_cmp_character3 (ffebld_constant_character3 (c1),
+ ffebld_constant_character3 (c2));
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEBLD_constCHARACTER4:
+ return ffetarget_cmp_character4 (ffebld_constant_character4 (c1),
+ ffebld_constant_character4 (c2));
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEBLD_constCHARACTER5:
+ return ffetarget_cmp_character5 (ffebld_constant_character5 (c1),
+ ffebld_constant_character5 (c2));
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEBLD_constCHARACTER6:
+ return ffetarget_cmp_character6 (ffebld_constant_character6 (c1),
+ ffebld_constant_character6 (c2));
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEBLD_constCHARACTER7:
+ return ffetarget_cmp_character7 (ffebld_constant_character7 (c1),
+ ffebld_constant_character7 (c2));
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEBLD_constCHARACTER8:
+ return ffetarget_cmp_character8 (ffebld_constant_character8 (c1),
+ ffebld_constant_character8 (c2));
+#endif
+
+ default:
+ assert ("bad constant type" == NULL);
+ return 0;
+ }
+}
+
+/* ffebld_constant_dump -- Display summary of constant's contents
+
+ ffebldConstant c;
+ ffebld_constant_dump(c);
+
+ Displays the constant in summary form. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffebld_constant_dump (ffebldConstant c)
+{
+ switch (ffebld_constant_type (c))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEBLD_constINTEGER1:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGER1);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER1);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEBLD_constINTEGER2:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGER2);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER2);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEBLD_constINTEGER3:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGER3);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER3);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEBLD_constINTEGER4:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGER4);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER4);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEBLD_constINTEGER5:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGER5);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER5);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEBLD_constINTEGER6:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGER6);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER6);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEBLD_constINTEGER7:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGER7);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER7);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEBLD_constINTEGER8:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGER8);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER8);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL1
+ case FFEBLD_constLOGICAL1:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICAL1);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL1);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEBLD_constLOGICAL2:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICAL2);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL2);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEBLD_constLOGICAL3:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICAL3);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL3);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEBLD_constLOGICAL4:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICAL4);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL4);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEBLD_constLOGICAL5:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICAL5);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL5);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEBLD_constLOGICAL6:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICAL6);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL6);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEBLD_constLOGICAL7:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICAL7);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL7);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEBLD_constLOGICAL8:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICAL8);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL8);
+ break;
+#endif
+
+#if FFETARGET_okREAL1
+ case FFEBLD_constREAL1:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREAL1);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeREAL, FFEINFO_kindtypeREAL1);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEBLD_constREAL2:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREAL2);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeREAL, FFEINFO_kindtypeREAL2);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEBLD_constREAL3:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREAL3);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeREAL, FFEINFO_kindtypeREAL3);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEBLD_constREAL4:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREAL4);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeREAL, FFEINFO_kindtypeREAL4);
+ break;
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEBLD_constREAL5:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREAL5);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeREAL, FFEINFO_kindtypeREAL5);
+ break;
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEBLD_constREAL6:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREAL6);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeREAL, FFEINFO_kindtypeREAL6);
+ break;
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEBLD_constREAL7:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREAL7);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeREAL, FFEINFO_kindtypeREAL7);
+ break;
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEBLD_constREAL8:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREAL8);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeREAL, FFEINFO_kindtypeREAL8);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX1
+ case FFEBLD_constCOMPLEX1:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCOMPLEX,
+ FFEINFO_kindtypeREAL1);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREAL1);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEBLD_constCOMPLEX2:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCOMPLEX,
+ FFEINFO_kindtypeREAL2);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREAL2);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEBLD_constCOMPLEX3:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCOMPLEX,
+ FFEINFO_kindtypeREAL3);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREAL3);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEBLD_constCOMPLEX4:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCOMPLEX,
+ FFEINFO_kindtypeREAL4);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREAL4);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEBLD_constCOMPLEX5:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCOMPLEX,
+ FFEINFO_kindtypeREAL5);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREAL5);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEBLD_constCOMPLEX6:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCOMPLEX,
+ FFEINFO_kindtypeREAL6);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREAL6);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEBLD_constCOMPLEX7:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCOMPLEX,
+ FFEINFO_kindtypeREAL7);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREAL7);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEBLD_constCOMPLEX8:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCOMPLEX,
+ FFEINFO_kindtypeREAL8);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREAL8);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER1
+ case FFEBLD_constCHARACTER1:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTER1);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCHARACTER, FFEINFO_kindtypeCHARACTER1);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEBLD_constCHARACTER2:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTER2);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCHARACTER, FFEINFO_kindtypeCHARACTER2);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEBLD_constCHARACTER3:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTER3);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCHARACTER, FFEINFO_kindtypeCHARACTER3);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEBLD_constCHARACTER4:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTER4);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCHARACTER, FFEINFO_kindtypeCHARACTER4);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEBLD_constCHARACTER5:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTER5);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCHARACTER, FFEINFO_kindtypeCHARACTER5);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEBLD_constCHARACTER6:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTER6);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCHARACTER, FFEINFO_kindtypeCHARACTER6);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEBLD_constCHARACTER7:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTER7);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCHARACTER, FFEINFO_kindtypeCHARACTER7);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEBLD_constCHARACTER8:
+ ffebld_dump_prefix (dmpout, FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTER8);
+ ffebld_constantunion_dump (ffebld_constant_union (c),
+ FFEINFO_basictypeCHARACTER, FFEINFO_kindtypeCHARACTER8);
+ break;
+#endif
+
+ case FFEBLD_constHOLLERITH:
+ fprintf (dmpout, "H%" ffetargetHollerithSize_f "u/",
+ ffebld_constant_hollerith (c).length);
+ ffetarget_print_hollerith (dmpout, ffebld_constant_hollerith (c));
+ break;
+
+ case FFEBLD_constBINARY_MIL:
+ fprintf (dmpout, "BM/");
+ ffetarget_print_binarymil (dmpout, ffebld_constant_typeless (c));
+ break;
+
+ case FFEBLD_constBINARY_VXT:
+ fprintf (dmpout, "BV/");
+ ffetarget_print_binaryvxt (dmpout, ffebld_constant_typeless (c));
+ break;
+
+ case FFEBLD_constOCTAL_MIL:
+ fprintf (dmpout, "OM/");
+ ffetarget_print_octalmil (dmpout, ffebld_constant_typeless (c));
+ break;
+
+ case FFEBLD_constOCTAL_VXT:
+ fprintf (dmpout, "OV/");
+ ffetarget_print_octalvxt (dmpout, ffebld_constant_typeless (c));
+ break;
+
+ case FFEBLD_constHEX_X_MIL:
+ fprintf (dmpout, "XM/");
+ ffetarget_print_hexxmil (dmpout, ffebld_constant_typeless (c));
+ break;
+
+ case FFEBLD_constHEX_X_VXT:
+ fprintf (dmpout, "XV/");
+ ffetarget_print_hexxvxt (dmpout, ffebld_constant_typeless (c));
+ break;
+
+ case FFEBLD_constHEX_Z_MIL:
+ fprintf (dmpout, "ZM/");
+ ffetarget_print_hexzmil (dmpout, ffebld_constant_typeless (c));
+ break;
+
+ case FFEBLD_constHEX_Z_VXT:
+ fprintf (dmpout, "ZV/");
+ ffetarget_print_hexzvxt (dmpout, ffebld_constant_typeless (c));
+ break;
+
+ default:
+ assert ("bad constant type" == NULL);
+ fprintf (dmpout, "?/?");
+ break;
+ }
+}
+#endif
+
+/* ffebld_constant_is_magical -- Determine if integer is "magical"
+
+ ffebldConstant c;
+ if (ffebld_constant_is_magical(c))
+ // it is 2**(n-1), where n is # bits in ffetargetIntegerDefault type
+ // (this test is important for 2's-complement machines only). */
+
+bool
+ffebld_constant_is_magical (ffebldConstant c)
+{
+ switch (ffebld_constant_type (c))
+ {
+ case FFEBLD_constINTEGERDEFAULT:
+ return ffetarget_integerdefault_is_magical (ffebld_constant_integer1 (c));
+
+ default:
+ return FALSE;
+ }
+}
+
+/* Determine if constant is zero. Used to ensure step count
+ for DO loops isn't zero, also to determine if values will
+ be binary zeros, so not entirely portable at this point. */
+
+bool
+ffebld_constant_is_zero (ffebldConstant c)
+{
+ switch (ffebld_constant_type (c))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEBLD_constINTEGER1:
+ return ffebld_constant_integer1 (c) == 0;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEBLD_constINTEGER2:
+ return ffebld_constant_integer2 (c) == 0;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEBLD_constINTEGER3:
+ return ffebld_constant_integer3 (c) == 0;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEBLD_constINTEGER4:
+ return ffebld_constant_integer4 (c) == 0;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEBLD_constINTEGER5:
+ return ffebld_constant_integer5 (c) == 0;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEBLD_constINTEGER6:
+ return ffebld_constant_integer6 (c) == 0;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEBLD_constINTEGER7:
+ return ffebld_constant_integer7 (c) == 0;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEBLD_constINTEGER8:
+ return ffebld_constant_integer8 (c) == 0;
+#endif
+
+#if FFETARGET_okLOGICAL1
+ case FFEBLD_constLOGICAL1:
+ return ffebld_constant_logical1 (c) == 0;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEBLD_constLOGICAL2:
+ return ffebld_constant_logical2 (c) == 0;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEBLD_constLOGICAL3:
+ return ffebld_constant_logical3 (c) == 0;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEBLD_constLOGICAL4:
+ return ffebld_constant_logical4 (c) == 0;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEBLD_constLOGICAL5:
+ return ffebld_constant_logical5 (c) == 0;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEBLD_constLOGICAL6:
+ return ffebld_constant_logical6 (c) == 0;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEBLD_constLOGICAL7:
+ return ffebld_constant_logical7 (c) == 0;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEBLD_constLOGICAL8:
+ return ffebld_constant_logical8 (c) == 0;
+#endif
+
+#if FFETARGET_okREAL1
+ case FFEBLD_constREAL1:
+ return ffetarget_iszero_real1 (ffebld_constant_real1 (c));
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEBLD_constREAL2:
+ return ffetarget_iszero_real2 (ffebld_constant_real2 (c));
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEBLD_constREAL3:
+ return ffetarget_iszero_real3 (ffebld_constant_real3 (c));
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEBLD_constREAL4:
+ return ffetarget_iszero_real4 (ffebld_constant_real4 (c));
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEBLD_constREAL5:
+ return ffetarget_iszero_real5 (ffebld_constant_real5 (c));
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEBLD_constREAL6:
+ return ffetarget_iszero_real6 (ffebld_constant_real6 (c));
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEBLD_constREAL7:
+ return ffetarget_iszero_real7 (ffebld_constant_real7 (c));
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEBLD_constREAL8:
+ return ffetarget_iszero_real8 (ffebld_constant_real8 (c));
+#endif
+
+#if FFETARGET_okCOMPLEX1
+ case FFEBLD_constCOMPLEX1:
+ return ffetarget_iszero_real1 (ffebld_constant_complex1 (c).real)
+ && ffetarget_iszero_real1 (ffebld_constant_complex1 (c).imaginary);
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEBLD_constCOMPLEX2:
+ return ffetarget_iszero_real2 (ffebld_constant_complex2 (c).real)
+ && ffetarget_iszero_real2 (ffebld_constant_complex2 (c).imaginary);
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEBLD_constCOMPLEX3:
+ return ffetarget_iszero_real3 (ffebld_constant_complex3 (c).real)
+ && ffetarget_iszero_real3 (ffebld_constant_complex3 (c).imaginary);
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEBLD_constCOMPLEX4:
+ return ffetarget_iszero_real4 (ffebld_constant_complex4 (c).real)
+ && ffetarget_iszero_real4 (ffebld_constant_complex4 (c).imaginary);
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEBLD_constCOMPLEX5:
+ return ffetarget_iszero_real5 (ffebld_constant_complex5 (c).real)
+ && ffetarget_iszero_real5 (ffebld_constant_complex5 (c).imaginary);
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEBLD_constCOMPLEX6:
+ return ffetarget_iszero_real6 (ffebld_constant_complex6 (c).real)
+ && ffetarget_iszero_real6 (ffebld_constant_complex6 (c).imaginary);
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEBLD_constCOMPLEX7:
+ return ffetarget_iszero_real7 (ffebld_constant_complex7 (c).real)
+ && ffetarget_iszero_real7 (ffebld_constant_complex7 (c).imaginary);
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEBLD_constCOMPLEX8:
+ return ffetarget_iszero_real8 (ffebld_constant_complex8 (c).real)
+ && ffetarget_iszero_real8 (ffebld_constant_complex8 (c).imaginary);
+#endif
+
+#if FFETARGET_okCHARACTER1
+ case FFEBLD_constCHARACTER1:
+ return ffetarget_iszero_character1 (ffebld_constant_character1 (c));
+#endif
+
+#if FFETARGET_okCHARACTER2 || FFETARGET_okCHARACTER3 /* ... */
+#error "no support for these!!"
+#endif
+
+ case FFEBLD_constHOLLERITH:
+ return ffetarget_iszero_hollerith (ffebld_constant_hollerith (c));
+
+ case FFEBLD_constBINARY_MIL:
+ case FFEBLD_constBINARY_VXT:
+ case FFEBLD_constOCTAL_MIL:
+ case FFEBLD_constOCTAL_VXT:
+ case FFEBLD_constHEX_X_MIL:
+ case FFEBLD_constHEX_X_VXT:
+ case FFEBLD_constHEX_Z_MIL:
+ case FFEBLD_constHEX_Z_VXT:
+ return ffetarget_iszero_typeless (ffebld_constant_typeless (c));
+
+ default:
+ return FALSE;
+ }
+}
+
+/* ffebld_constant_new_character1 -- Return character1 constant object from token
+
+ See prototype. */
+
+#if FFETARGET_okCHARACTER1
+ffebldConstant
+ffebld_constant_new_character1 (ffelexToken t)
+{
+ ffetargetCharacter1 val;
+
+ ffetarget_character1 (&val, t, ffebld_constant_pool());
+ return ffebld_constant_new_character1_val (val);
+}
+
+#endif
+/* ffebld_constant_new_character1_val -- Return an character1 constant object
+
+ See prototype. */
+
+#if FFETARGET_okCHARACTER1
+ffebldConstant
+ffebld_constant_new_character1_val (ffetargetCharacter1 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ ffetarget_verify_character1 (ffebld_constant_pool(), val);
+
+ for (c = (ffebldConstant) &ffebld_constant_character1_;
+ c->next != NULL;
+ c = c->next)
+ {
+ malloc_verify_kp (ffebld_constant_pool(),
+ c->next,
+ sizeof (*(c->next)));
+ ffetarget_verify_character1 (ffebld_constant_pool(),
+ ffebld_constant_character1 (c->next));
+ cmp = ffetarget_cmp_character1 (val,
+ ffebld_constant_character1 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constCHARACTER1",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constCHARACTER1;
+ nc->u.character1 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_complex1 -- Return complex1 constant object from token
+
+ See prototype. */
+
+#if FFETARGET_okCOMPLEX1
+ffebldConstant
+ffebld_constant_new_complex1 (ffebldConstant real,
+ ffebldConstant imaginary)
+{
+ ffetargetComplex1 val;
+
+ val.real = ffebld_constant_real1 (real);
+ val.imaginary = ffebld_constant_real1 (imaginary);
+ return ffebld_constant_new_complex1_val (val);
+}
+
+#endif
+/* ffebld_constant_new_complex1_val -- Return a complex1 constant object
+
+ See prototype. */
+
+#if FFETARGET_okCOMPLEX1
+ffebldConstant
+ffebld_constant_new_complex1_val (ffetargetComplex1 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_complex1_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_real1 (val.real, ffebld_constant_complex1 (c->next).real);
+ if (cmp == 0)
+ cmp = ffetarget_cmp_real1 (val.imaginary,
+ ffebld_constant_complex1 (c->next).imaginary);
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constCOMPLEX1",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constCOMPLEX1;
+ nc->u.complex1 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_complex2 -- Return complex2 constant object from token
+
+ See prototype. */
+
+#if FFETARGET_okCOMPLEX2
+ffebldConstant
+ffebld_constant_new_complex2 (ffebldConstant real,
+ ffebldConstant imaginary)
+{
+ ffetargetComplex2 val;
+
+ val.real = ffebld_constant_real2 (real);
+ val.imaginary = ffebld_constant_real2 (imaginary);
+ return ffebld_constant_new_complex2_val (val);
+}
+
+#endif
+/* ffebld_constant_new_complex2_val -- Return a complex2 constant object
+
+ See prototype. */
+
+#if FFETARGET_okCOMPLEX2
+ffebldConstant
+ffebld_constant_new_complex2_val (ffetargetComplex2 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_complex2_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_real2 (val.real, ffebld_constant_complex2 (c->next).real);
+ if (cmp == 0)
+ cmp = ffetarget_cmp_real2 (val.imaginary,
+ ffebld_constant_complex2 (c->next).imaginary);
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constCOMPLEX2",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constCOMPLEX2;
+ nc->u.complex2 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_hollerith -- Return hollerith constant object from token
+
+ See prototype. */
+
+ffebldConstant
+ffebld_constant_new_hollerith (ffelexToken t)
+{
+ ffetargetHollerith val;
+
+ ffetarget_hollerith (&val, t, ffebld_constant_pool());
+ return ffebld_constant_new_hollerith_val (val);
+}
+
+/* ffebld_constant_new_hollerith_val -- Return an hollerith constant object
+
+ See prototype. */
+
+ffebldConstant
+ffebld_constant_new_hollerith_val (ffetargetHollerith val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_hollerith_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_hollerith (val, ffebld_constant_hollerith (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constHOLLERITH",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constHOLLERITH;
+ nc->u.hollerith = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+/* ffebld_constant_new_integer1 -- Return integer1 constant object from token
+
+ See prototype.
+
+ Parses the token as a decimal integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+#if FFETARGET_okINTEGER1
+ffebldConstant
+ffebld_constant_new_integer1 (ffelexToken t)
+{
+ ffetargetInteger1 val;
+
+ assert (ffelex_token_type (t) == FFELEX_typeNUMBER);
+
+ ffetarget_integer1 (&val, t);
+ return ffebld_constant_new_integer1_val (val);
+}
+
+#endif
+/* ffebld_constant_new_integer1_val -- Return an integer1 constant object
+
+ See prototype. */
+
+#if FFETARGET_okINTEGER1
+ffebldConstant
+ffebld_constant_new_integer1_val (ffetargetInteger1 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_integer1_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_integer1 (val, ffebld_constant_integer1 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constINTEGER1",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constINTEGER1;
+ nc->u.integer1 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_integer2_val -- Return an integer2 constant object
+
+ See prototype. */
+
+#if FFETARGET_okINTEGER2
+ffebldConstant
+ffebld_constant_new_integer2_val (ffetargetInteger2 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_integer2_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_integer2 (val, ffebld_constant_integer2 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constINTEGER2",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constINTEGER2;
+ nc->u.integer2 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_integer3_val -- Return an integer3 constant object
+
+ See prototype. */
+
+#if FFETARGET_okINTEGER3
+ffebldConstant
+ffebld_constant_new_integer3_val (ffetargetInteger3 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_integer3_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_integer3 (val, ffebld_constant_integer3 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constINTEGER3",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constINTEGER3;
+ nc->u.integer3 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_integer4_val -- Return an integer4 constant object
+
+ See prototype. */
+
+#if FFETARGET_okINTEGER4
+ffebldConstant
+ffebld_constant_new_integer4_val (ffetargetInteger4 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_integer4_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_integer4 (val, ffebld_constant_integer4 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constINTEGER4",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constINTEGER4;
+ nc->u.integer4 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_integerbinary -- Return binary constant object from token
+
+ See prototype.
+
+ Parses the token as a binary integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_integerbinary (ffelexToken t)
+{
+ ffetargetIntegerDefault val;
+
+ assert ((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNUMBER));
+
+ ffetarget_integerbinary (&val, t);
+ return ffebld_constant_new_integerdefault_val (val);
+}
+
+/* ffebld_constant_new_integerhex -- Return hex constant object from token
+
+ See prototype.
+
+ Parses the token as a hex integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_integerhex (ffelexToken t)
+{
+ ffetargetIntegerDefault val;
+
+ assert ((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNUMBER));
+
+ ffetarget_integerhex (&val, t);
+ return ffebld_constant_new_integerdefault_val (val);
+}
+
+/* ffebld_constant_new_integeroctal -- Return octal constant object from token
+
+ See prototype.
+
+ Parses the token as a octal integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_integeroctal (ffelexToken t)
+{
+ ffetargetIntegerDefault val;
+
+ assert ((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNUMBER));
+
+ ffetarget_integeroctal (&val, t);
+ return ffebld_constant_new_integerdefault_val (val);
+}
+
+/* ffebld_constant_new_logical1 -- Return logical1 constant object from token
+
+ See prototype.
+
+ Parses the token as a decimal logical constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+#if FFETARGET_okLOGICAL1
+ffebldConstant
+ffebld_constant_new_logical1 (bool truth)
+{
+ ffetargetLogical1 val;
+
+ ffetarget_logical1 (&val, truth);
+ return ffebld_constant_new_logical1_val (val);
+}
+
+#endif
+/* ffebld_constant_new_logical1_val -- Return a logical1 constant object
+
+ See prototype. */
+
+#if FFETARGET_okLOGICAL1
+ffebldConstant
+ffebld_constant_new_logical1_val (ffetargetLogical1 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_logical1_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_logical1 (val, ffebld_constant_logical1 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constLOGICAL1",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constLOGICAL1;
+ nc->u.logical1 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_logical2_val -- Return a logical2 constant object
+
+ See prototype. */
+
+#if FFETARGET_okLOGICAL2
+ffebldConstant
+ffebld_constant_new_logical2_val (ffetargetLogical2 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_logical2_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_logical2 (val, ffebld_constant_logical2 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constLOGICAL2",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constLOGICAL2;
+ nc->u.logical2 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_logical3_val -- Return a logical3 constant object
+
+ See prototype. */
+
+#if FFETARGET_okLOGICAL3
+ffebldConstant
+ffebld_constant_new_logical3_val (ffetargetLogical3 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_logical3_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_logical3 (val, ffebld_constant_logical3 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constLOGICAL3",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constLOGICAL3;
+ nc->u.logical3 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_logical4_val -- Return a logical4 constant object
+
+ See prototype. */
+
+#if FFETARGET_okLOGICAL4
+ffebldConstant
+ffebld_constant_new_logical4_val (ffetargetLogical4 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_logical4_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_logical4 (val, ffebld_constant_logical4 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constLOGICAL4",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constLOGICAL4;
+ nc->u.logical4 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_real1 -- Return real1 constant object from token
+
+ See prototype. */
+
+#if FFETARGET_okREAL1
+ffebldConstant
+ffebld_constant_new_real1 (ffelexToken integer, ffelexToken decimal,
+ ffelexToken fraction, ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits)
+{
+ ffetargetReal1 val;
+
+ ffetarget_real1 (&val,
+ integer, decimal, fraction, exponent, exponent_sign, exponent_digits);
+ return ffebld_constant_new_real1_val (val);
+}
+
+#endif
+/* ffebld_constant_new_real1_val -- Return an real1 constant object
+
+ See prototype. */
+
+#if FFETARGET_okREAL1
+ffebldConstant
+ffebld_constant_new_real1_val (ffetargetReal1 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_real1_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_real1 (val, ffebld_constant_real1 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constREAL1",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constREAL1;
+ nc->u.real1 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_real2 -- Return real2 constant object from token
+
+ See prototype. */
+
+#if FFETARGET_okREAL2
+ffebldConstant
+ffebld_constant_new_real2 (ffelexToken integer, ffelexToken decimal,
+ ffelexToken fraction, ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits)
+{
+ ffetargetReal2 val;
+
+ ffetarget_real2 (&val,
+ integer, decimal, fraction, exponent, exponent_sign, exponent_digits);
+ return ffebld_constant_new_real2_val (val);
+}
+
+#endif
+/* ffebld_constant_new_real2_val -- Return an real2 constant object
+
+ See prototype. */
+
+#if FFETARGET_okREAL2
+ffebldConstant
+ffebld_constant_new_real2_val (ffetargetReal2 val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_real2_;
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_real2 (val, ffebld_constant_real2 (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constREAL2",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = FFEBLD_constREAL2;
+ nc->u.real2 = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+#endif
+/* ffebld_constant_new_typeless_bm -- Return typeless constant object from token
+
+ See prototype.
+
+ Parses the token as a decimal integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_typeless_bm (ffelexToken t)
+{
+ ffetargetTypeless val;
+
+ ffetarget_binarymil (&val, t);
+ return ffebld_constant_new_typeless_val (FFEBLD_constBINARY_MIL, val);
+}
+
+/* ffebld_constant_new_typeless_bv -- Return typeless constant object from token
+
+ See prototype.
+
+ Parses the token as a decimal integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_typeless_bv (ffelexToken t)
+{
+ ffetargetTypeless val;
+
+ ffetarget_binaryvxt (&val, t);
+ return ffebld_constant_new_typeless_val (FFEBLD_constBINARY_VXT, val);
+}
+
+/* ffebld_constant_new_typeless_hxm -- Return typeless constant object from token
+
+ See prototype.
+
+ Parses the token as a decimal integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_typeless_hxm (ffelexToken t)
+{
+ ffetargetTypeless val;
+
+ ffetarget_hexxmil (&val, t);
+ return ffebld_constant_new_typeless_val (FFEBLD_constHEX_X_MIL, val);
+}
+
+/* ffebld_constant_new_typeless_hxv -- Return typeless constant object from token
+
+ See prototype.
+
+ Parses the token as a decimal integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_typeless_hxv (ffelexToken t)
+{
+ ffetargetTypeless val;
+
+ ffetarget_hexxvxt (&val, t);
+ return ffebld_constant_new_typeless_val (FFEBLD_constHEX_X_VXT, val);
+}
+
+/* ffebld_constant_new_typeless_hzm -- Return typeless constant object from token
+
+ See prototype.
+
+ Parses the token as a decimal integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_typeless_hzm (ffelexToken t)
+{
+ ffetargetTypeless val;
+
+ ffetarget_hexzmil (&val, t);
+ return ffebld_constant_new_typeless_val (FFEBLD_constHEX_Z_MIL, val);
+}
+
+/* ffebld_constant_new_typeless_hzv -- Return typeless constant object from token
+
+ See prototype.
+
+ Parses the token as a decimal integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_typeless_hzv (ffelexToken t)
+{
+ ffetargetTypeless val;
+
+ ffetarget_hexzvxt (&val, t);
+ return ffebld_constant_new_typeless_val (FFEBLD_constHEX_Z_VXT, val);
+}
+
+/* ffebld_constant_new_typeless_om -- Return typeless constant object from token
+
+ See prototype.
+
+ Parses the token as a decimal integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_typeless_om (ffelexToken t)
+{
+ ffetargetTypeless val;
+
+ ffetarget_octalmil (&val, t);
+ return ffebld_constant_new_typeless_val (FFEBLD_constOCTAL_MIL, val);
+}
+
+/* ffebld_constant_new_typeless_ov -- Return typeless constant object from token
+
+ See prototype.
+
+ Parses the token as a decimal integer constant, thus it must be an
+ FFELEX_typeNUMBER. */
+
+ffebldConstant
+ffebld_constant_new_typeless_ov (ffelexToken t)
+{
+ ffetargetTypeless val;
+
+ ffetarget_octalvxt (&val, t);
+ return ffebld_constant_new_typeless_val (FFEBLD_constOCTAL_VXT, val);
+}
+
+/* ffebld_constant_new_typeless_val -- Return a typeless constant object
+
+ See prototype. */
+
+ffebldConstant
+ffebld_constant_new_typeless_val (ffebldConst type, ffetargetTypeless val)
+{
+ ffebldConstant c;
+ ffebldConstant nc;
+ int cmp;
+
+ for (c = (ffebldConstant) &ffebld_constant_typeless_[type
+ - FFEBLD_constTYPELESS_FIRST];
+ c->next != NULL;
+ c = c->next)
+ {
+ cmp = ffetarget_cmp_typeless (val, ffebld_constant_typeless (c->next));
+ if (cmp == 0)
+ return c->next;
+ if (cmp > 0)
+ break;
+ }
+
+ nc = malloc_new_kp (ffebld_constant_pool(),
+ "FFEBLD_constTYPELESS",
+ sizeof (*nc));
+ nc->next = c->next;
+ nc->consttype = type;
+ nc->u.typeless = val;
+#ifdef FFECOM_constantHOOK
+ nc->hook = FFECOM_constantNULL;
+#endif
+ c->next = nc;
+
+ return nc;
+}
+
+/* ffebld_constantarray_dump -- Display summary of array's contents
+
+ ffebldConstantArray a;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffetargetOffset size;
+ ffebld_constant_dump(a,bt,kt,size,NULL);
+
+ Displays the constant array in summary form. The fifth argument, if
+ supplied, is an ffebit object that is consulted as to whether the
+ constant at a particular offset is valid. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffebld_constantarray_dump (ffebldConstantArray array, ffeinfoBasictype bt,
+ ffeinfoKindtype kt, ffetargetOffset size, ffebit bits)
+{
+ ffetargetOffset i;
+ ffebitCount j;
+
+ ffebld_dump_prefix (dmpout, bt, kt);
+
+ fprintf (dmpout, "\\(");
+
+ if (bits == NULL)
+ {
+ for (i = 0; i < size; ++i)
+ {
+ ffebld_constantunion_dump (ffebld_constantarray_get (array, bt, kt, i), bt,
+ kt);
+ if (i != size - 1)
+ fputc (',', dmpout);
+ }
+ }
+ else
+ {
+ bool value;
+ ffebitCount length;
+ ffetargetOffset offset = 0;
+
+ do
+ {
+ ffebit_test (bits, offset, &value, &length);
+ if (value && (length != 0))
+ {
+ if (length == 1)
+ fprintf (dmpout, "[%" ffetargetOffset_f "d]:", offset);
+ else
+ fprintf (dmpout,
+ "[%" ffetargetOffset_f "u..%" ffetargetOffset_f "d]:",
+ offset, offset + (ffetargetOffset) length - 1);
+ for (j = 0; j < length; ++j, ++offset)
+ {
+ ffebld_constantunion_dump (ffebld_constantarray_get (array, bt, kt,
+ offset), bt, kt);
+ if (j != length - 1)
+ fputc (',', dmpout);
+ }
+ fprintf (dmpout, ";");
+ }
+ else
+ offset += length;
+ }
+ while (length != 0);
+ }
+ fprintf (dmpout, "\\)");
+
+}
+#endif
+
+/* ffebld_constantarray_get -- Get a value from an array of constants
+
+ See prototype. */
+
+ffebldConstantUnion
+ffebld_constantarray_get (ffebldConstantArray array, ffeinfoBasictype bt,
+ ffeinfoKindtype kt, ffetargetOffset offset)
+{
+ ffebldConstantUnion u;
+
+ switch (bt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (kt)
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ u.integer1 = *(array.integer1 + offset);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ u.integer2 = *(array.integer2 + offset);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ u.integer3 = *(array.integer3 + offset);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ u.integer4 = *(array.integer4 + offset);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEINFO_kindtypeINTEGER5:
+ u.integer5 = *(array.integer5 + offset);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEINFO_kindtypeINTEGER6:
+ u.integer6 = *(array.integer6 + offset);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEINFO_kindtypeINTEGER7:
+ u.integer7 = *(array.integer7 + offset);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEINFO_kindtypeINTEGER8:
+ u.integer8 = *(array.integer8 + offset);
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt)
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ u.logical1 = *(array.logical1 + offset);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ u.logical2 = *(array.logical2 + offset);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ u.logical3 = *(array.logical3 + offset);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ u.logical4 = *(array.logical4 + offset);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEINFO_kindtypeLOGICAL5:
+ u.logical5 = *(array.logical5 + offset);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEINFO_kindtypeLOGICAL6:
+ u.logical6 = *(array.logical6 + offset);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEINFO_kindtypeLOGICAL7:
+ u.logical7 = *(array.logical7 + offset);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEINFO_kindtypeLOGICAL8:
+ u.logical8 = *(array.logical8 + offset);
+ break;
+#endif
+
+ default:
+ assert ("bad LOGICAL kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt)
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ u.real1 = *(array.real1 + offset);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ u.real2 = *(array.real2 + offset);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ u.real3 = *(array.real3 + offset);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ u.real4 = *(array.real4 + offset);
+ break;
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEINFO_kindtypeREAL5:
+ u.real5 = *(array.real5 + offset);
+ break;
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEINFO_kindtypeREAL6:
+ u.real6 = *(array.real6 + offset);
+ break;
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEINFO_kindtypeREAL7:
+ u.real7 = *(array.real7 + offset);
+ break;
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEINFO_kindtypeREAL8:
+ u.real8 = *(array.real8 + offset);
+ break;
+#endif
+
+ default:
+ assert ("bad REAL kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ u.complex1 = *(array.complex1 + offset);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ u.complex2 = *(array.complex2 + offset);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ u.complex3 = *(array.complex3 + offset);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ u.complex4 = *(array.complex4 + offset);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEINFO_kindtypeREAL5:
+ u.complex5 = *(array.complex5 + offset);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEINFO_kindtypeREAL6:
+ u.complex6 = *(array.complex6 + offset);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEINFO_kindtypeREAL7:
+ u.complex7 = *(array.complex7 + offset);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEINFO_kindtypeREAL8:
+ u.complex8 = *(array.complex8 + offset);
+ break;
+#endif
+
+ default:
+ assert ("bad COMPLEX kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (kt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ u.character1.length = 1;
+ u.character1.text = array.character1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ u.character2.length = 1;
+ u.character2.text = array.character2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ u.character3.length = 1;
+ u.character3.text = array.character3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ u.character4.length = 1;
+ u.character4.text = array.character4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEINFO_kindtypeCHARACTER5:
+ u.character5.length = 1;
+ u.character5.text = array.character5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEINFO_kindtypeCHARACTER6:
+ u.character6.length = 1;
+ u.character6.text = array.character6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEINFO_kindtypeCHARACTER7:
+ u.character7.length = 1;
+ u.character7.text = array.character7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEINFO_kindtypeCHARACTER8:
+ u.character8.length = 1;
+ u.character8.text = array.character8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad CHARACTER kindtype" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad basictype" == NULL);
+ break;
+ }
+
+ return u;
+}
+
+/* ffebld_constantarray_new -- Make an array of constants
+
+ See prototype. */
+
+ffebldConstantArray
+ffebld_constantarray_new (ffeinfoBasictype bt,
+ ffeinfoKindtype kt, ffetargetOffset size)
+{
+ ffebldConstantArray ptr;
+
+ switch (bt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (kt)
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ ptr.integer1 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetInteger1),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ ptr.integer2 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetInteger2),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ ptr.integer3 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetInteger3),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ ptr.integer4 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetInteger4),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEINFO_kindtypeINTEGER5:
+ ptr.integer5 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetInteger5),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEINFO_kindtypeINTEGER6:
+ ptr.integer6 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetInteger6),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEINFO_kindtypeINTEGER7:
+ ptr.integer7 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetInteger7),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEINFO_kindtypeINTEGER8:
+ ptr.integer8 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetInteger8),
+ 0);
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt)
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ ptr.logical1 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetLogical1),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ ptr.logical2 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetLogical2),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ ptr.logical3 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetLogical3),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ ptr.logical4 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetLogical4),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEINFO_kindtypeLOGICAL5:
+ ptr.logical5 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetLogical5),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEINFO_kindtypeLOGICAL6:
+ ptr.logical6 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetLogical6),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEINFO_kindtypeLOGICAL7:
+ ptr.logical7 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetLogical7),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEINFO_kindtypeLOGICAL8:
+ ptr.logical8 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetLogical8),
+ 0);
+ break;
+#endif
+
+ default:
+ assert ("bad LOGICAL kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt)
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ ptr.real1 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetReal1),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ ptr.real2 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetReal2),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ ptr.real3 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetReal3),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ ptr.real4 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetReal4),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEINFO_kindtypeREAL5:
+ ptr.real5 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetReal5),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEINFO_kindtypeREAL6:
+ ptr.real6 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetReal6),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEINFO_kindtypeREAL7:
+ ptr.real7 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetReal7),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEINFO_kindtypeREAL8:
+ ptr.real8 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetReal8),
+ 0);
+ break;
+#endif
+
+ default:
+ assert ("bad REAL kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ ptr.complex1 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetComplex1),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ ptr.complex2 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetComplex2),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ ptr.complex3 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetComplex3),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ ptr.complex4 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetComplex4),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEINFO_kindtypeREAL5:
+ ptr.complex5 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetComplex5),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEINFO_kindtypeREAL6:
+ ptr.complex6 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetComplex6),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEINFO_kindtypeREAL7:
+ ptr.complex7 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetComplex7),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEINFO_kindtypeREAL8:
+ ptr.complex8 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size *= sizeof (ffetargetComplex8),
+ 0);
+ break;
+#endif
+
+ default:
+ assert ("bad COMPLEX kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (kt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ ptr.character1 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size
+ *= sizeof (ffetargetCharacterUnit1),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ ptr.character2 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size
+ *= sizeof (ffetargetCharacterUnit2),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ ptr.character3 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size
+ *= sizeof (ffetargetCharacterUnit3),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ ptr.character4 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size
+ *= sizeof (ffetargetCharacterUnit4),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEINFO_kindtypeCHARACTER5:
+ ptr.character5 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size
+ *= sizeof (ffetargetCharacterUnit5),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEINFO_kindtypeCHARACTER6:
+ ptr.character6 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size
+ *= sizeof (ffetargetCharacterUnit6),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEINFO_kindtypeCHARACTER7:
+ ptr.character7 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size
+ *= sizeof (ffetargetCharacterUnit7),
+ 0);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEINFO_kindtypeCHARACTER8:
+ ptr.character8 = malloc_new_zkp (ffebld_constant_pool(),
+ "ffebldConstantArray",
+ size
+ *= sizeof (ffetargetCharacterUnit8),
+ 0);
+ break;
+#endif
+
+ default:
+ assert ("bad CHARACTER kindtype" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad basictype" == NULL);
+ break;
+ }
+
+ return ptr;
+}
+
+/* ffebld_constantarray_preparray -- Prepare for copy between arrays
+
+ See prototype.
+
+ Like _prepare, but the source is an array instead of a single-value
+ constant. */
+
+void
+ffebld_constantarray_preparray (void **aptr, void **cptr, size_t *size,
+ ffebldConstantArray array, ffeinfoBasictype abt, ffeinfoKindtype akt,
+ ffetargetOffset offset, ffebldConstantArray source_array,
+ ffeinfoBasictype cbt, ffeinfoKindtype ckt)
+{
+ switch (abt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (akt)
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ *aptr = array.integer1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ *aptr = array.integer2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ *aptr = array.integer3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ *aptr = array.integer4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEINFO_kindtypeINTEGER5:
+ *aptr = array.integer5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEINFO_kindtypeINTEGER6:
+ *aptr = array.integer6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEINFO_kindtypeINTEGER7:
+ *aptr = array.integer7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEINFO_kindtypeINTEGER8:
+ *aptr = array.integer8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER akindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (akt)
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ *aptr = array.logical1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ *aptr = array.logical2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ *aptr = array.logical3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ *aptr = array.logical4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEINFO_kindtypeLOGICAL5:
+ *aptr = array.logical5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEINFO_kindtypeLOGICAL6:
+ *aptr = array.logical6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEINFO_kindtypeLOGICAL7:
+ *aptr = array.logical7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEINFO_kindtypeLOGICAL8:
+ *aptr = array.logical8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad LOGICAL akindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (akt)
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ *aptr = array.real1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ *aptr = array.real2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ *aptr = array.real3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ *aptr = array.real4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEINFO_kindtypeREAL5:
+ *aptr = array.real5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEINFO_kindtypeREAL6:
+ *aptr = array.real6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEINFO_kindtypeREAL7:
+ *aptr = array.real7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEINFO_kindtypeREAL8:
+ *aptr = array.real8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad REAL akindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (akt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ *aptr = array.complex1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ *aptr = array.complex2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ *aptr = array.complex3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ *aptr = array.complex4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEINFO_kindtypeREAL5:
+ *aptr = array.complex5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEINFO_kindtypeREAL6:
+ *aptr = array.complex6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEINFO_kindtypeREAL7:
+ *aptr = array.complex7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEINFO_kindtypeREAL8:
+ *aptr = array.complex8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad COMPLEX akindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (akt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ *aptr = array.character1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ *aptr = array.character2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ *aptr = array.character3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ *aptr = array.character4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEINFO_kindtypeCHARACTER5:
+ *aptr = array.character5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEINFO_kindtypeCHARACTER6:
+ *aptr = array.character6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEINFO_kindtypeCHARACTER7:
+ *aptr = array.character7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEINFO_kindtypeCHARACTER8:
+ *aptr = array.character8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad CHARACTER akindtype" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad abasictype" == NULL);
+ break;
+ }
+
+ switch (cbt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ckt)
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ *cptr = source_array.integer1;
+ *size = sizeof (*source_array.integer1);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ *cptr = source_array.integer2;
+ *size = sizeof (*source_array.integer2);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ *cptr = source_array.integer3;
+ *size = sizeof (*source_array.integer3);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ *cptr = source_array.integer4;
+ *size = sizeof (*source_array.integer4);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEINFO_kindtypeINTEGER5:
+ *cptr = source_array.integer5;
+ *size = sizeof (*source_array.integer5);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEINFO_kindtypeINTEGER6:
+ *cptr = source_array.integer6;
+ *size = sizeof (*source_array.integer6);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEINFO_kindtypeINTEGER7:
+ *cptr = source_array.integer7;
+ *size = sizeof (*source_array.integer7);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEINFO_kindtypeINTEGER8:
+ *cptr = source_array.integer8;
+ *size = sizeof (*source_array.integer8);
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER ckindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (ckt)
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ *cptr = source_array.logical1;
+ *size = sizeof (*source_array.logical1);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ *cptr = source_array.logical2;
+ *size = sizeof (*source_array.logical2);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ *cptr = source_array.logical3;
+ *size = sizeof (*source_array.logical3);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ *cptr = source_array.logical4;
+ *size = sizeof (*source_array.logical4);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEINFO_kindtypeLOGICAL5:
+ *cptr = source_array.logical5;
+ *size = sizeof (*source_array.logical5);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEINFO_kindtypeLOGICAL6:
+ *cptr = source_array.logical6;
+ *size = sizeof (*source_array.logical6);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEINFO_kindtypeLOGICAL7:
+ *cptr = source_array.logical7;
+ *size = sizeof (*source_array.logical7);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEINFO_kindtypeLOGICAL8:
+ *cptr = source_array.logical8;
+ *size = sizeof (*source_array.logical8);
+ break;
+#endif
+
+ default:
+ assert ("bad LOGICAL ckindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ckt)
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ *cptr = source_array.real1;
+ *size = sizeof (*source_array.real1);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ *cptr = source_array.real2;
+ *size = sizeof (*source_array.real2);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ *cptr = source_array.real3;
+ *size = sizeof (*source_array.real3);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ *cptr = source_array.real4;
+ *size = sizeof (*source_array.real4);
+ break;
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEINFO_kindtypeREAL5:
+ *cptr = source_array.real5;
+ *size = sizeof (*source_array.real5);
+ break;
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEINFO_kindtypeREAL6:
+ *cptr = source_array.real6;
+ *size = sizeof (*source_array.real6);
+ break;
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEINFO_kindtypeREAL7:
+ *cptr = source_array.real7;
+ *size = sizeof (*source_array.real7);
+ break;
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEINFO_kindtypeREAL8:
+ *cptr = source_array.real8;
+ *size = sizeof (*source_array.real8);
+ break;
+#endif
+
+ default:
+ assert ("bad REAL ckindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ckt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ *cptr = source_array.complex1;
+ *size = sizeof (*source_array.complex1);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ *cptr = source_array.complex2;
+ *size = sizeof (*source_array.complex2);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ *cptr = source_array.complex3;
+ *size = sizeof (*source_array.complex3);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ *cptr = source_array.complex4;
+ *size = sizeof (*source_array.complex4);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEINFO_kindtypeREAL5:
+ *cptr = source_array.complex5;
+ *size = sizeof (*source_array.complex5);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEINFO_kindtypeREAL6:
+ *cptr = source_array.complex6;
+ *size = sizeof (*source_array.complex6);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEINFO_kindtypeREAL7:
+ *cptr = source_array.complex7;
+ *size = sizeof (*source_array.complex7);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEINFO_kindtypeREAL8:
+ *cptr = source_array.complex8;
+ *size = sizeof (*source_array.complex8);
+ break;
+#endif
+
+ default:
+ assert ("bad COMPLEX ckindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (ckt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ *cptr = source_array.character1;
+ *size = sizeof (*source_array.character1);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ *cptr = source_array.character2;
+ *size = sizeof (*source_array.character2);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ *cptr = source_array.character3;
+ *size = sizeof (*source_array.character3);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ *cptr = source_array.character4;
+ *size = sizeof (*source_array.character4);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEINFO_kindtypeCHARACTER5:
+ *cptr = source_array.character5;
+ *size = sizeof (*source_array.character5);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEINFO_kindtypeCHARACTER6:
+ *cptr = source_array.character6;
+ *size = sizeof (*source_array.character6);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEINFO_kindtypeCHARACTER7:
+ *cptr = source_array.character7;
+ *size = sizeof (*source_array.character7);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEINFO_kindtypeCHARACTER8:
+ *cptr = source_array.character8;
+ *size = sizeof (*source_array.character8);
+ break;
+#endif
+
+ default:
+ assert ("bad CHARACTER ckindtype" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad cbasictype" == NULL);
+ break;
+ }
+}
+
+/* ffebld_constantarray_prepare -- Prepare for copy between value and array
+
+ See prototype.
+
+ Like _put, but just returns the pointers to the beginnings of the
+ array and the constant and returns the size (the amount of info to
+ copy). The idea is that the caller can use memcpy to accomplish the
+ same thing as _put (though slower), or the caller can use a different
+ function that swaps bytes, words, etc for a different target machine.
+ Also, the type of the array may be different from the type of the
+ constant; the array type is used to determine the meaning (scale) of
+ the offset field (to calculate the array pointer), the constant type is
+ used to determine the constant pointer and the size (amount of info to
+ copy). */
+
+void
+ffebld_constantarray_prepare (void **aptr, void **cptr, size_t *size,
+ ffebldConstantArray array, ffeinfoBasictype abt, ffeinfoKindtype akt,
+ ffetargetOffset offset, ffebldConstantUnion *constant,
+ ffeinfoBasictype cbt, ffeinfoKindtype ckt)
+{
+ switch (abt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (akt)
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ *aptr = array.integer1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ *aptr = array.integer2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ *aptr = array.integer3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ *aptr = array.integer4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEINFO_kindtypeINTEGER5:
+ *aptr = array.integer5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEINFO_kindtypeINTEGER6:
+ *aptr = array.integer6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEINFO_kindtypeINTEGER7:
+ *aptr = array.integer7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEINFO_kindtypeINTEGER8:
+ *aptr = array.integer8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER akindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (akt)
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ *aptr = array.logical1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ *aptr = array.logical2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ *aptr = array.logical3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ *aptr = array.logical4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEINFO_kindtypeLOGICAL5:
+ *aptr = array.logical5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEINFO_kindtypeLOGICAL6:
+ *aptr = array.logical6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEINFO_kindtypeLOGICAL7:
+ *aptr = array.logical7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEINFO_kindtypeLOGICAL8:
+ *aptr = array.logical8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad LOGICAL akindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (akt)
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ *aptr = array.real1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ *aptr = array.real2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ *aptr = array.real3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ *aptr = array.real4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEINFO_kindtypeREAL5:
+ *aptr = array.real5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEINFO_kindtypeREAL6:
+ *aptr = array.real6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEINFO_kindtypeREAL7:
+ *aptr = array.real7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEINFO_kindtypeREAL8:
+ *aptr = array.real8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad REAL akindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (akt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ *aptr = array.complex1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ *aptr = array.complex2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ *aptr = array.complex3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ *aptr = array.complex4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEINFO_kindtypeREAL5:
+ *aptr = array.complex5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEINFO_kindtypeREAL6:
+ *aptr = array.complex6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEINFO_kindtypeREAL7:
+ *aptr = array.complex7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEINFO_kindtypeREAL8:
+ *aptr = array.complex8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad COMPLEX akindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (akt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ *aptr = array.character1 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ *aptr = array.character2 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ *aptr = array.character3 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ *aptr = array.character4 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEINFO_kindtypeCHARACTER5:
+ *aptr = array.character5 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEINFO_kindtypeCHARACTER6:
+ *aptr = array.character6 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEINFO_kindtypeCHARACTER7:
+ *aptr = array.character7 + offset;
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEINFO_kindtypeCHARACTER8:
+ *aptr = array.character8 + offset;
+ break;
+#endif
+
+ default:
+ assert ("bad CHARACTER akindtype" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad abasictype" == NULL);
+ break;
+ }
+
+ switch (cbt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ckt)
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ *cptr = &constant->integer1;
+ *size = sizeof (constant->integer1);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ *cptr = &constant->integer2;
+ *size = sizeof (constant->integer2);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ *cptr = &constant->integer3;
+ *size = sizeof (constant->integer3);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ *cptr = &constant->integer4;
+ *size = sizeof (constant->integer4);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEINFO_kindtypeINTEGER5:
+ *cptr = &constant->integer5;
+ *size = sizeof (constant->integer5);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEINFO_kindtypeINTEGER6:
+ *cptr = &constant->integer6;
+ *size = sizeof (constant->integer6);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEINFO_kindtypeINTEGER7:
+ *cptr = &constant->integer7;
+ *size = sizeof (constant->integer7);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEINFO_kindtypeINTEGER8:
+ *cptr = &constant->integer8;
+ *size = sizeof (constant->integer8);
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER ckindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (ckt)
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ *cptr = &constant->logical1;
+ *size = sizeof (constant->logical1);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ *cptr = &constant->logical2;
+ *size = sizeof (constant->logical2);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ *cptr = &constant->logical3;
+ *size = sizeof (constant->logical3);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ *cptr = &constant->logical4;
+ *size = sizeof (constant->logical4);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEINFO_kindtypeLOGICAL5:
+ *cptr = &constant->logical5;
+ *size = sizeof (constant->logical5);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEINFO_kindtypeLOGICAL6:
+ *cptr = &constant->logical6;
+ *size = sizeof (constant->logical6);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEINFO_kindtypeLOGICAL7:
+ *cptr = &constant->logical7;
+ *size = sizeof (constant->logical7);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEINFO_kindtypeLOGICAL8:
+ *cptr = &constant->logical8;
+ *size = sizeof (constant->logical8);
+ break;
+#endif
+
+ default:
+ assert ("bad LOGICAL ckindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ckt)
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ *cptr = &constant->real1;
+ *size = sizeof (constant->real1);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ *cptr = &constant->real2;
+ *size = sizeof (constant->real2);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ *cptr = &constant->real3;
+ *size = sizeof (constant->real3);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ *cptr = &constant->real4;
+ *size = sizeof (constant->real4);
+ break;
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEINFO_kindtypeREAL5:
+ *cptr = &constant->real5;
+ *size = sizeof (constant->real5);
+ break;
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEINFO_kindtypeREAL6:
+ *cptr = &constant->real6;
+ *size = sizeof (constant->real6);
+ break;
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEINFO_kindtypeREAL7:
+ *cptr = &constant->real7;
+ *size = sizeof (constant->real7);
+ break;
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEINFO_kindtypeREAL8:
+ *cptr = &constant->real8;
+ *size = sizeof (constant->real8);
+ break;
+#endif
+
+ default:
+ assert ("bad REAL ckindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ckt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ *cptr = &constant->complex1;
+ *size = sizeof (constant->complex1);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ *cptr = &constant->complex2;
+ *size = sizeof (constant->complex2);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ *cptr = &constant->complex3;
+ *size = sizeof (constant->complex3);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ *cptr = &constant->complex4;
+ *size = sizeof (constant->complex4);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEINFO_kindtypeREAL5:
+ *cptr = &constant->complex5;
+ *size = sizeof (constant->complex5);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEINFO_kindtypeREAL6:
+ *cptr = &constant->complex6;
+ *size = sizeof (constant->complex6);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEINFO_kindtypeREAL7:
+ *cptr = &constant->complex7;
+ *size = sizeof (constant->complex7);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEINFO_kindtypeREAL8:
+ *cptr = &constant->complex8;
+ *size = sizeof (constant->complex8);
+ break;
+#endif
+
+ default:
+ assert ("bad COMPLEX ckindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (ckt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ *cptr = ffetarget_text_character1 (constant->character1);
+ *size = ffetarget_length_character1 (constant->character1);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ *cptr = ffetarget_text_character2 (constant->character2);
+ *size = ffetarget_length_character2 (constant->character2);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ *cptr = ffetarget_text_character3 (constant->character3);
+ *size = ffetarget_length_character3 (constant->character3);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ *cptr = ffetarget_text_character4 (constant->character4);
+ *size = ffetarget_length_character4 (constant->character4);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEINFO_kindtypeCHARACTER5:
+ *cptr = ffetarget_text_character5 (constant->character5);
+ *size = ffetarget_length_character5 (constant->character5);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEINFO_kindtypeCHARACTER6:
+ *cptr = ffetarget_text_character6 (constant->character6);
+ *size = ffetarget_length_character6 (constant->character6);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEINFO_kindtypeCHARACTER7:
+ *cptr = ffetarget_text_character7 (constant->character7);
+ *size = ffetarget_length_character7 (constant->character7);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEINFO_kindtypeCHARACTER8:
+ *cptr = ffetarget_text_character8 (constant->character8);
+ *size = ffetarget_length_character8 (constant->character8);
+ break;
+#endif
+
+ default:
+ assert ("bad CHARACTER ckindtype" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad cbasictype" == NULL);
+ break;
+ }
+}
+
+/* ffebld_constantarray_put -- Put a value into an array of constants
+
+ See prototype. */
+
+void
+ffebld_constantarray_put (ffebldConstantArray array, ffeinfoBasictype bt,
+ ffeinfoKindtype kt, ffetargetOffset offset, ffebldConstantUnion constant)
+{
+ switch (bt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (kt)
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ *(array.integer1 + offset) = constant.integer1;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ *(array.integer2 + offset) = constant.integer2;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ *(array.integer3 + offset) = constant.integer3;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ *(array.integer4 + offset) = constant.integer4;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEINFO_kindtypeINTEGER5:
+ *(array.integer5 + offset) = constant.integer5;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEINFO_kindtypeINTEGER6:
+ *(array.integer6 + offset) = constant.integer6;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEINFO_kindtypeINTEGER7:
+ *(array.integer7 + offset) = constant.integer7;
+ break;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEINFO_kindtypeINTEGER8:
+ *(array.integer8 + offset) = constant.integer8;
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt)
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ *(array.logical1 + offset) = constant.logical1;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ *(array.logical2 + offset) = constant.logical2;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ *(array.logical3 + offset) = constant.logical3;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ *(array.logical4 + offset) = constant.logical4;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEINFO_kindtypeLOGICAL5:
+ *(array.logical5 + offset) = constant.logical5;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEINFO_kindtypeLOGICAL6:
+ *(array.logical6 + offset) = constant.logical6;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEINFO_kindtypeLOGICAL7:
+ *(array.logical7 + offset) = constant.logical7;
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEINFO_kindtypeLOGICAL8:
+ *(array.logical8 + offset) = constant.logical8;
+ break;
+#endif
+
+ default:
+ assert ("bad LOGICAL kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt)
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ *(array.real1 + offset) = constant.real1;
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ *(array.real2 + offset) = constant.real2;
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ *(array.real3 + offset) = constant.real3;
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ *(array.real4 + offset) = constant.real4;
+ break;
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEINFO_kindtypeREAL5:
+ *(array.real5 + offset) = constant.real5;
+ break;
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEINFO_kindtypeREAL6:
+ *(array.real6 + offset) = constant.real6;
+ break;
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEINFO_kindtypeREAL7:
+ *(array.real7 + offset) = constant.real7;
+ break;
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEINFO_kindtypeREAL8:
+ *(array.real8 + offset) = constant.real8;
+ break;
+#endif
+
+ default:
+ assert ("bad REAL kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ *(array.complex1 + offset) = constant.complex1;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ *(array.complex2 + offset) = constant.complex2;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ *(array.complex3 + offset) = constant.complex3;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ *(array.complex4 + offset) = constant.complex4;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEINFO_kindtypeREAL5:
+ *(array.complex5 + offset) = constant.complex5;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEINFO_kindtypeREAL6:
+ *(array.complex6 + offset) = constant.complex6;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEINFO_kindtypeREAL7:
+ *(array.complex7 + offset) = constant.complex7;
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEINFO_kindtypeREAL8:
+ *(array.complex8 + offset) = constant.complex8;
+ break;
+#endif
+
+ default:
+ assert ("bad COMPLEX kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (kt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ memcpy (array.character1 + offset,
+ ffetarget_text_character1 (constant.character1),
+ ffetarget_length_character1 (constant.character1));
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ memcpy (array.character2 + offset,
+ ffetarget_text_character2 (constant.character2),
+ ffetarget_length_character2 (constant.character2));
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ memcpy (array.character3 + offset,
+ ffetarget_text_character3 (constant.character3),
+ ffetarget_length_character3 (constant.character3));
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ memcpy (array.character4 + offset,
+ ffetarget_text_character4 (constant.character4),
+ ffetarget_length_character4 (constant.character4));
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEINFO_kindtypeCHARACTER5:
+ memcpy (array.character5 + offset,
+ ffetarget_text_character5 (constant.character5),
+ ffetarget_length_character5 (constant.character5));
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEINFO_kindtypeCHARACTER6:
+ memcpy (array.character6 + offset,
+ ffetarget_text_character6 (constant.character6),
+ ffetarget_length_character6 (constant.character6));
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEINFO_kindtypeCHARACTER7:
+ memcpy (array.character7 + offset,
+ ffetarget_text_character7 (constant.character7),
+ ffetarget_length_character7 (constant.character7));
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEINFO_kindtypeCHARACTER8:
+ memcpy (array.character8 + offset,
+ ffetarget_text_character8 (constant.character8),
+ ffetarget_length_character8 (constant.character8));
+ break;
+#endif
+
+ default:
+ assert ("bad CHARACTER kindtype" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad basictype" == NULL);
+ break;
+ }
+}
+
+/* ffebld_constantunion_dump -- Dump a constant
+
+ See prototype. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffebld_constantunion_dump (ffebldConstantUnion u, ffeinfoBasictype bt,
+ ffeinfoKindtype kt)
+{
+ switch (bt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (kt)
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ ffetarget_print_integer1 (dmpout, u.integer1);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ ffetarget_print_integer2 (dmpout, u.integer2);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ ffetarget_print_integer3 (dmpout, u.integer3);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ ffetarget_print_integer4 (dmpout, u.integer4);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEINFO_kindtypeINTEGER5:
+ ffetarget_print_integer5 (dmpout, u.integer5);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEINFO_kindtypeINTEGER6:
+ ffetarget_print_integer6 (dmpout, u.integer6);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEINFO_kindtypeINTEGER7:
+ ffetarget_print_integer7 (dmpout, u.integer7);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEINFO_kindtypeINTEGER8:
+ ffetarget_print_integer8 (dmpout, u.integer8);
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt)
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ ffetarget_print_logical1 (dmpout, u.logical1);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ ffetarget_print_logical2 (dmpout, u.logical2);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ ffetarget_print_logical3 (dmpout, u.logical3);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ ffetarget_print_logical4 (dmpout, u.logical4);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEINFO_kindtypeLOGICAL5:
+ ffetarget_print_logical5 (dmpout, u.logical5);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEINFO_kindtypeLOGICAL6:
+ ffetarget_print_logical6 (dmpout, u.logical6);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEINFO_kindtypeLOGICAL7:
+ ffetarget_print_logical7 (dmpout, u.logical7);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEINFO_kindtypeLOGICAL8:
+ ffetarget_print_logical8 (dmpout, u.logical8);
+ break;
+#endif
+
+ default:
+ assert ("bad LOGICAL kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt)
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ ffetarget_print_real1 (dmpout, u.real1);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ ffetarget_print_real2 (dmpout, u.real2);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ ffetarget_print_real3 (dmpout, u.real3);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ ffetarget_print_real4 (dmpout, u.real4);
+ break;
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEINFO_kindtypeREAL5:
+ ffetarget_print_real5 (dmpout, u.real5);
+ break;
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEINFO_kindtypeREAL6:
+ ffetarget_print_real6 (dmpout, u.real6);
+ break;
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEINFO_kindtypeREAL7:
+ ffetarget_print_real7 (dmpout, u.real7);
+ break;
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEINFO_kindtypeREAL8:
+ ffetarget_print_real8 (dmpout, u.real8);
+ break;
+#endif
+
+ default:
+ assert ("bad REAL kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ fprintf (dmpout, "(");
+ ffetarget_print_real1 (dmpout, u.complex1.real);
+ fprintf (dmpout, ",");
+ ffetarget_print_real1 (dmpout, u.complex1.imaginary);
+ fprintf (dmpout, ")");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ fprintf (dmpout, "(");
+ ffetarget_print_real2 (dmpout, u.complex2.real);
+ fprintf (dmpout, ",");
+ ffetarget_print_real2 (dmpout, u.complex2.imaginary);
+ fprintf (dmpout, ")");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ fprintf (dmpout, "(");
+ ffetarget_print_real3 (dmpout, u.complex3.real);
+ fprintf (dmpout, ",");
+ ffetarget_print_real3 (dmpout, u.complex3.imaginary);
+ fprintf (dmpout, ")");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ fprintf (dmpout, "(");
+ ffetarget_print_real4 (dmpout, u.complex4.real);
+ fprintf (dmpout, ",");
+ ffetarget_print_real4 (dmpout, u.complex4.imaginary);
+ fprintf (dmpout, ")");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEINFO_kindtypeREAL5:
+ fprintf (dmpout, "(");
+ ffetarget_print_real5 (dmpout, u.complex5.real);
+ fprintf (dmpout, ",");
+ ffetarget_print_real5 (dmpout, u.complex5.imaginary);
+ fprintf (dmpout, ")");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEINFO_kindtypeREAL6:
+ fprintf (dmpout, "(");
+ ffetarget_print_real6 (dmpout, u.complex6.real);
+ fprintf (dmpout, ",");
+ ffetarget_print_real6 (dmpout, u.complex6.imaginary);
+ fprintf (dmpout, ")");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEINFO_kindtypeREAL7:
+ fprintf (dmpout, "(");
+ ffetarget_print_real7 (dmpout, u.complex7.real);
+ fprintf (dmpout, ",");
+ ffetarget_print_real7 (dmpout, u.complex7.imaginary);
+ fprintf (dmpout, ")");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEINFO_kindtypeREAL8:
+ fprintf (dmpout, "(");
+ ffetarget_print_real8 (dmpout, u.complex8.real);
+ fprintf (dmpout, ",");
+ ffetarget_print_real8 (dmpout, u.complex8.imaginary);
+ fprintf (dmpout, ")");
+ break;
+#endif
+
+ default:
+ assert ("bad COMPLEX kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (kt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ ffetarget_print_character1 (dmpout, u.character1);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ ffetarget_print_character2 (dmpout, u.character2);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ ffetarget_print_character3 (dmpout, u.character3);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ ffetarget_print_character4 (dmpout, u.character4);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEINFO_kindtypeCHARACTER5:
+ ffetarget_print_character5 (dmpout, u.character5);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEINFO_kindtypeCHARACTER6:
+ ffetarget_print_character6 (dmpout, u.character6);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEINFO_kindtypeCHARACTER7:
+ ffetarget_print_character7 (dmpout, u.character7);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEINFO_kindtypeCHARACTER8:
+ ffetarget_print_character8 (dmpout, u.character8);
+ break;
+#endif
+
+ default:
+ assert ("bad CHARACTER kindtype" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad basictype" == NULL);
+ break;
+ }
+}
+#endif
+
+/* ffebld_dump -- Dump expression tree in concise form
+
+ ffebld b;
+ ffebld_dump(b); */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffebld_dump (ffebld b)
+{
+ ffeinfoKind k;
+ ffeinfoWhere w;
+
+ if (b == NULL)
+ {
+ fprintf (dmpout, "(null)");
+ return;
+ }
+
+ switch (ffebld_op (b))
+ {
+ case FFEBLD_opITEM:
+ fputs ("[", dmpout);
+ while (b != NULL)
+ {
+ ffebld_dump (ffebld_head (b));
+ if ((b = ffebld_trail (b)) != NULL)
+ fputs (",", dmpout);
+ }
+ fputs ("]", dmpout);
+ return;
+
+ case FFEBLD_opSTAR:
+ case FFEBLD_opBOUNDS:
+ case FFEBLD_opREPEAT:
+ case FFEBLD_opLABTER:
+ case FFEBLD_opLABTOK:
+ case FFEBLD_opIMPDO:
+ fputs (ffebld_op_string (ffebld_op (b)), dmpout);
+ break;
+
+ default:
+ if (ffeinfo_size (ffebld_info (b)) != FFETARGET_charactersizeNONE)
+ fprintf (dmpout, "%s%d%s%s*%" ffetargetCharacterSize_f "u",
+ ffebld_op_string (ffebld_op (b)),
+ (int) ffeinfo_rank (ffebld_info (b)),
+ ffeinfo_basictype_string (ffeinfo_basictype (ffebld_info (b))),
+ ffeinfo_kindtype_string (ffeinfo_kindtype (ffebld_info (b))),
+ ffeinfo_size (ffebld_info (b)));
+ else
+ fprintf (dmpout, "%s%d%s%s", ffebld_op_string (ffebld_op (b)),
+ (int) ffeinfo_rank (ffebld_info (b)),
+ ffeinfo_basictype_string (ffeinfo_basictype (ffebld_info (b))),
+ ffeinfo_kindtype_string (ffeinfo_kindtype (ffebld_info (b))));
+ if ((k = ffeinfo_kind (ffebld_info (b))) != FFEINFO_kindNONE)
+ fprintf (dmpout, "/%s", ffeinfo_kind_string (k));
+ if ((w = ffeinfo_where (ffebld_info (b))) != FFEINFO_whereNONE)
+ fprintf (dmpout, "@%s", ffeinfo_where_string (w));
+ break;
+ }
+
+ switch (ffebld_arity (b))
+ {
+ case 2:
+ fputs ("(", dmpout);
+ ffebld_dump (ffebld_left (b));
+ fputs (",", dmpout);
+ ffebld_dump (ffebld_right (b));
+ fputs (")", dmpout);
+ break;
+
+ case 1:
+ fputs ("(", dmpout);
+ ffebld_dump (ffebld_left (b));
+ fputs (")", dmpout);
+ break;
+
+ default:
+ switch (ffebld_op (b))
+ {
+ case FFEBLD_opCONTER:
+ fprintf (dmpout, "<");
+ ffebld_constant_dump (b->u.conter.expr);
+ fprintf (dmpout, ">");
+ break;
+
+ case FFEBLD_opACCTER:
+ fprintf (dmpout, "<");
+ ffebld_constantarray_dump (b->u.accter.array,
+ ffeinfo_basictype (ffebld_info (b)),
+ ffeinfo_kindtype (ffebld_info (b)),
+ ffebit_size (b->u.accter.bits), b->u.accter.bits);
+ fprintf (dmpout, ">");
+ break;
+
+ case FFEBLD_opARRTER:
+ fprintf (dmpout, "<");
+ ffebld_constantarray_dump (b->u.arrter.array,
+ ffeinfo_basictype (ffebld_info (b)),
+ ffeinfo_kindtype (ffebld_info (b)),
+ b->u.arrter.size, NULL);
+ fprintf (dmpout, ">");
+ break;
+
+ case FFEBLD_opLABTER:
+ if (b->u.labter == NULL)
+ fprintf (dmpout, "<>");
+ else
+ fprintf (dmpout, "<%" ffelabValue_f "u>", ffelab_value (b->u.labter));
+ break;
+
+ case FFEBLD_opLABTOK:
+ fprintf (dmpout, "<%s>", ffelex_token_text (b->u.labtok));
+ break;
+
+ case FFEBLD_opSYMTER:
+ fprintf (dmpout, "<");
+ ffesymbol_dump (b->u.symter.symbol);
+ if ((b->u.symter.generic != FFEINTRIN_genNONE)
+ || (b->u.symter.specific != FFEINTRIN_specNONE))
+ fprintf (dmpout, "{%s:%s:%s}",
+ ffeintrin_name_generic (b->u.symter.generic),
+ ffeintrin_name_specific (b->u.symter.specific),
+ ffeintrin_name_implementation (b->u.symter.implementation));
+ if (b->u.symter.do_iter)
+ fprintf (dmpout, "{/do-iter}");
+ fprintf (dmpout, ">");
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+#endif
+
+/* ffebld_dump_prefix -- Dump the prefix for a constant of a given type
+
+ ffebld_dump_prefix(dmpout,FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGER1); */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffebld_dump_prefix (FILE *out, ffeinfoBasictype bt, ffeinfoKindtype kt)
+{
+ switch (bt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (kt)
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ fprintf (out, "I" STRX (FFETARGET_kindINTEGER1) "/");
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ fprintf (out, "I" STRX (FFETARGET_kindINTEGER2) "/");
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ fprintf (out, "I" STRX (FFETARGET_kindINTEGER3) "/");
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ fprintf (out, "I" STRX (FFETARGET_kindINTEGER4) "/");
+ break;
+#endif
+
+#if FFETARGET_okINTEGER5
+ case FFEINFO_kindtypeINTEGER5:
+ fprintf (out, "I" STRX (FFETARGET_kindINTEGER5) "/");
+ break;
+#endif
+
+#if FFETARGET_okINTEGER6
+ case FFEINFO_kindtypeINTEGER6:
+ fprintf (out, "I" STRX (FFETARGET_kindINTEGER6) "/");
+ break;
+#endif
+
+#if FFETARGET_okINTEGER7
+ case FFEINFO_kindtypeINTEGER7:
+ fprintf (out, "I" STRX (FFETARGET_kindINTEGER7) "/");
+ break;
+#endif
+
+#if FFETARGET_okINTEGER8
+ case FFEINFO_kindtypeINTEGER8:
+ fprintf (out, "I" STRX (FFETARGET_kindINTEGER8) "/");
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt)
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ fprintf (out, "L" STRX (FFETARGET_kindLOGICAL1) "/");
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ fprintf (out, "L" STRX (FFETARGET_kindLOGICAL2) "/");
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ fprintf (out, "L" STRX (FFETARGET_kindLOGICAL3) "/");
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ fprintf (out, "L" STRX (FFETARGET_kindLOGICAL4) "/");
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL5
+ case FFEINFO_kindtypeLOGICAL5:
+ fprintf (out, "L" STRX (FFETARGET_kindLOGICAL5) "/");
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL6
+ case FFEINFO_kindtypeLOGICAL6:
+ fprintf (out, "L" STRX (FFETARGET_kindLOGICAL6) "/");
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL7
+ case FFEINFO_kindtypeLOGICAL7:
+ fprintf (out, "L" STRX (FFETARGET_kindLOGICAL7) "/");
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL8
+ case FFEINFO_kindtypeLOGICAL8:
+ fprintf (out, "L" STRX (FFETARGET_kindLOGICAL8) "/");
+ break;
+#endif
+
+ default:
+ assert ("bad LOGICAL kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt)
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ fprintf (out, "R" STRX (FFETARGET_kindREAL1) "/");
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ fprintf (out, "R" STRX (FFETARGET_kindREAL2) "/");
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ fprintf (out, "R" STRX (FFETARGET_kindREAL3) "/");
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ fprintf (out, "R" STRX (FFETARGET_kindREAL4) "/");
+ break;
+#endif
+
+#if FFETARGET_okREAL5
+ case FFEINFO_kindtypeREAL5:
+ fprintf (out, "R" STRX (FFETARGET_kindREAL5) "/");
+ break;
+#endif
+
+#if FFETARGET_okREAL6
+ case FFEINFO_kindtypeREAL6:
+ fprintf (out, "R" STRX (FFETARGET_kindREAL6) "/");
+ break;
+#endif
+
+#if FFETARGET_okREAL7
+ case FFEINFO_kindtypeREAL7:
+ fprintf (out, "R" STRX (FFETARGET_kindREAL7) "/");
+ break;
+#endif
+
+#if FFETARGET_okREAL8
+ case FFEINFO_kindtypeREAL8:
+ fprintf (out, "R" STRX (FFETARGET_kindREAL8) "/");
+ break;
+#endif
+
+ default:
+ assert ("bad REAL kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ fprintf (out, "C" STRX (FFETARGET_kindCOMPLEX1) "/");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ fprintf (out, "C" STRX (FFETARGET_kindCOMPLEX2) "/");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ fprintf (out, "C" STRX (FFETARGET_kindCOMPLEX3) "/");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ fprintf (out, "C" STRX (FFETARGET_kindCOMPLEX4) "/");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX5
+ case FFEINFO_kindtypeREAL5:
+ fprintf (out, "C" STRX (FFETARGET_kindCOMPLEX5) "/");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX6
+ case FFEINFO_kindtypeREAL6:
+ fprintf (out, "C" STRX (FFETARGET_kindCOMPLEX6) "/");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX7
+ case FFEINFO_kindtypeREAL7:
+ fprintf (out, "C" STRX (FFETARGET_kindCOMPLEX7) "/");
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX8
+ case FFEINFO_kindtypeREAL8:
+ fprintf (out, "C" STRX (FFETARGET_kindCOMPLEX8) "/");
+ break;
+#endif
+
+ default:
+ assert ("bad COMPLEX kindtype" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (kt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ fprintf (out, "A" STRX (FFETARGET_kindCHARACTER1) "/");
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ fprintf (out, "A" STRX (FFETARGET_kindCHARACTER2) "/");
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ fprintf (out, "A" STRX (FFETARGET_kindCHARACTER3) "/");
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ fprintf (out, "A" STRX (FFETARGET_kindCHARACTER4) "/");
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER5
+ case FFEINFO_kindtypeCHARACTER5:
+ fprintf (out, "A" STRX (FFETARGET_kindCHARACTER5) "/");
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER6
+ case FFEINFO_kindtypeCHARACTER6:
+ fprintf (out, "A" STRX (FFETARGET_kindCHARACTER6) "/");
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER7
+ case FFEINFO_kindtypeCHARACTER7:
+ fprintf (out, "A" STRX (FFETARGET_kindCHARACTER7) "/");
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER8
+ case FFEINFO_kindtypeCHARACTER8:
+ fprintf (out, "A" STRX (FFETARGET_kindCHARACTER8) "/");
+ break;
+#endif
+
+ default:
+ assert ("bad CHARACTER kindtype" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad basictype" == NULL);
+ fprintf (out, "?/?");
+ break;
+ }
+}
+#endif
+
+/* ffebld_init_0 -- Initialize the module
+
+ ffebld_init_0(); */
+
+void
+ffebld_init_0 ()
+{
+ assert (FFEBLD_op == ARRAY_SIZE (ffebld_op_string_));
+ assert (FFEBLD_op == ARRAY_SIZE (ffebld_arity_op_));
+}
+
+/* ffebld_init_1 -- Initialize the module for a file
+
+ ffebld_init_1(); */
+
+void
+ffebld_init_1 ()
+{
+#if FFEBLD_whereconstCURRENT_ == FFEBLD_whereconstFILE_
+ int i;
+
+#if FFETARGET_okCHARACTER1
+ ffebld_constant_character1_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER2
+ ffebld_constant_character2_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER3
+ ffebld_constant_character3_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER4
+ ffebld_constant_character4_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER5
+ ffebld_constant_character5_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER6
+ ffebld_constant_character6_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER7
+ ffebld_constant_character7_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER8
+ ffebld_constant_character8_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX1
+ ffebld_constant_complex1_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX2
+ ffebld_constant_complex2_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX3
+ ffebld_constant_complex3_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX4
+ ffebld_constant_complex4_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX5
+ ffebld_constant_complex5_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX6
+ ffebld_constant_complex6_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX7
+ ffebld_constant_complex7_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX8
+ ffebld_constant_complex8_ = NULL;
+#endif
+#if FFETARGET_okINTEGER1
+ ffebld_constant_integer1_ = NULL;
+#endif
+#if FFETARGET_okINTEGER2
+ ffebld_constant_integer2_ = NULL;
+#endif
+#if FFETARGET_okINTEGER3
+ ffebld_constant_integer3_ = NULL;
+#endif
+#if FFETARGET_okINTEGER4
+ ffebld_constant_integer4_ = NULL;
+#endif
+#if FFETARGET_okINTEGER5
+ ffebld_constant_integer5_ = NULL;
+#endif
+#if FFETARGET_okINTEGER6
+ ffebld_constant_integer6_ = NULL;
+#endif
+#if FFETARGET_okINTEGER7
+ ffebld_constant_integer7_ = NULL;
+#endif
+#if FFETARGET_okINTEGER8
+ ffebld_constant_integer8_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL1
+ ffebld_constant_logical1_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL2
+ ffebld_constant_logical2_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL3
+ ffebld_constant_logical3_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL4
+ ffebld_constant_logical4_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL5
+ ffebld_constant_logical5_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL6
+ ffebld_constant_logical6_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL7
+ ffebld_constant_logical7_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL8
+ ffebld_constant_logical8_ = NULL;
+#endif
+#if FFETARGET_okREAL1
+ ffebld_constant_real1_ = NULL;
+#endif
+#if FFETARGET_okREAL2
+ ffebld_constant_real2_ = NULL;
+#endif
+#if FFETARGET_okREAL3
+ ffebld_constant_real3_ = NULL;
+#endif
+#if FFETARGET_okREAL4
+ ffebld_constant_real4_ = NULL;
+#endif
+#if FFETARGET_okREAL5
+ ffebld_constant_real5_ = NULL;
+#endif
+#if FFETARGET_okREAL6
+ ffebld_constant_real6_ = NULL;
+#endif
+#if FFETARGET_okREAL7
+ ffebld_constant_real7_ = NULL;
+#endif
+#if FFETARGET_okREAL8
+ ffebld_constant_real8_ = NULL;
+#endif
+ ffebld_constant_hollerith_ = NULL;
+ for (i = FFEBLD_constTYPELESS_FIRST; i <= FFEBLD_constTYPELESS_LAST; ++i)
+ ffebld_constant_typeless_[i - FFEBLD_constTYPELESS_FIRST] = NULL;
+#endif
+}
+
+/* ffebld_init_2 -- Initialize the module
+
+ ffebld_init_2(); */
+
+void
+ffebld_init_2 ()
+{
+#if FFEBLD_whereconstCURRENT_ == FFEBLD_whereconstPROGUNIT_
+ int i;
+#endif
+
+ ffebld_pool_stack_.next = NULL;
+ ffebld_pool_stack_.pool = ffe_pool_program_unit ();
+#if FFEBLD_whereconstCURRENT_ == FFEBLD_whereconstPROGUNIT_
+#if FFETARGET_okCHARACTER1
+ ffebld_constant_character1_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER2
+ ffebld_constant_character2_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER3
+ ffebld_constant_character3_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER4
+ ffebld_constant_character4_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER5
+ ffebld_constant_character5_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER6
+ ffebld_constant_character6_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER7
+ ffebld_constant_character7_ = NULL;
+#endif
+#if FFETARGET_okCHARACTER8
+ ffebld_constant_character8_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX1
+ ffebld_constant_complex1_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX2
+ ffebld_constant_complex2_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX3
+ ffebld_constant_complex3_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX4
+ ffebld_constant_complex4_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX5
+ ffebld_constant_complex5_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX6
+ ffebld_constant_complex6_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX7
+ ffebld_constant_complex7_ = NULL;
+#endif
+#if FFETARGET_okCOMPLEX8
+ ffebld_constant_complex8_ = NULL;
+#endif
+#if FFETARGET_okINTEGER1
+ ffebld_constant_integer1_ = NULL;
+#endif
+#if FFETARGET_okINTEGER2
+ ffebld_constant_integer2_ = NULL;
+#endif
+#if FFETARGET_okINTEGER3
+ ffebld_constant_integer3_ = NULL;
+#endif
+#if FFETARGET_okINTEGER4
+ ffebld_constant_integer4_ = NULL;
+#endif
+#if FFETARGET_okINTEGER5
+ ffebld_constant_integer5_ = NULL;
+#endif
+#if FFETARGET_okINTEGER6
+ ffebld_constant_integer6_ = NULL;
+#endif
+#if FFETARGET_okINTEGER7
+ ffebld_constant_integer7_ = NULL;
+#endif
+#if FFETARGET_okINTEGER8
+ ffebld_constant_integer8_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL1
+ ffebld_constant_logical1_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL2
+ ffebld_constant_logical2_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL3
+ ffebld_constant_logical3_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL4
+ ffebld_constant_logical4_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL5
+ ffebld_constant_logical5_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL6
+ ffebld_constant_logical6_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL7
+ ffebld_constant_logical7_ = NULL;
+#endif
+#if FFETARGET_okLOGICAL8
+ ffebld_constant_logical8_ = NULL;
+#endif
+#if FFETARGET_okREAL1
+ ffebld_constant_real1_ = NULL;
+#endif
+#if FFETARGET_okREAL2
+ ffebld_constant_real2_ = NULL;
+#endif
+#if FFETARGET_okREAL3
+ ffebld_constant_real3_ = NULL;
+#endif
+#if FFETARGET_okREAL4
+ ffebld_constant_real4_ = NULL;
+#endif
+#if FFETARGET_okREAL5
+ ffebld_constant_real5_ = NULL;
+#endif
+#if FFETARGET_okREAL6
+ ffebld_constant_real6_ = NULL;
+#endif
+#if FFETARGET_okREAL7
+ ffebld_constant_real7_ = NULL;
+#endif
+#if FFETARGET_okREAL8
+ ffebld_constant_real8_ = NULL;
+#endif
+ ffebld_constant_hollerith_ = NULL;
+ for (i = FFEBLD_constTYPELESS_FIRST; i <= FFEBLD_constTYPELESS_LAST; ++i)
+ ffebld_constant_typeless_[i - FFEBLD_constTYPELESS_FIRST] = NULL;
+#endif
+}
+
+/* ffebld_list_length -- Return # of opITEMs in list
+
+ ffebld list; // Must be NULL or opITEM
+ ffebldListLength length;
+ length = ffebld_list_length(list);
+
+ Returns 0 if list is NULL, 1 if it's ffebld_trail is NULL, and so on. */
+
+ffebldListLength
+ffebld_list_length (ffebld list)
+{
+ ffebldListLength length;
+
+ for (length = 0; list != NULL; ++length, list = ffebld_trail (list))
+ ;
+
+ return length;
+}
+
+/* ffebld_new_accter -- Create an ffebld object that is an array
+
+ ffebld x;
+ ffebldConstantArray a;
+ ffebit b;
+ x = ffebld_new_accter(a,b); */
+
+ffebld
+ffebld_new_accter (ffebldConstantArray a, ffebit b)
+{
+ ffebld x;
+
+ x = ffebld_new ();
+#if FFEBLD_BLANK_
+ *x = ffebld_blank_;
+#endif
+ x->op = FFEBLD_opACCTER;
+ x->u.accter.array = a;
+ x->u.accter.bits = b;
+ x->u.accter.pad = 0;
+ return x;
+}
+
+/* ffebld_new_arrter -- Create an ffebld object that is an array
+
+ ffebld x;
+ ffebldConstantArray a;
+ ffetargetOffset size;
+ x = ffebld_new_arrter(a,size); */
+
+ffebld
+ffebld_new_arrter (ffebldConstantArray a, ffetargetOffset size)
+{
+ ffebld x;
+
+ x = ffebld_new ();
+#if FFEBLD_BLANK_
+ *x = ffebld_blank_;
+#endif
+ x->op = FFEBLD_opARRTER;
+ x->u.arrter.array = a;
+ x->u.arrter.size = size;
+ x->u.arrter.pad = 0;
+ return x;
+}
+
+/* ffebld_new_conter_with_orig -- Create an ffebld object that is a constant
+
+ ffebld x;
+ ffebldConstant c;
+ x = ffebld_new_conter_with_orig(c,NULL); */
+
+ffebld
+ffebld_new_conter_with_orig (ffebldConstant c, ffebld o)
+{
+ ffebld x;
+
+ x = ffebld_new ();
+#if FFEBLD_BLANK_
+ *x = ffebld_blank_;
+#endif
+ x->op = FFEBLD_opCONTER;
+ x->u.conter.expr = c;
+ x->u.conter.orig = o;
+ x->u.conter.pad = 0;
+ return x;
+}
+
+/* ffebld_new_item -- Create an ffebld item object
+
+ ffebld x,y,z;
+ x = ffebld_new_item(y,z); */
+
+ffebld
+ffebld_new_item (ffebld head, ffebld trail)
+{
+ ffebld x;
+
+ x = ffebld_new ();
+#if FFEBLD_BLANK_
+ *x = ffebld_blank_;
+#endif
+ x->op = FFEBLD_opITEM;
+ x->u.item.head = head;
+ x->u.item.trail = trail;
+ return x;
+}
+
+/* ffebld_new_labter -- Create an ffebld object that is a label
+
+ ffebld x;
+ ffelab l;
+ x = ffebld_new_labter(c); */
+
+ffebld
+ffebld_new_labter (ffelab l)
+{
+ ffebld x;
+
+ x = ffebld_new ();
+#if FFEBLD_BLANK_
+ *x = ffebld_blank_;
+#endif
+ x->op = FFEBLD_opLABTER;
+ x->u.labter = l;
+ return x;
+}
+
+/* ffebld_new_labtok -- Create object that is a label's NUMBER token
+
+ ffebld x;
+ ffelexToken t;
+ x = ffebld_new_labter(c);
+
+ Like the other ffebld_new_ functions, the
+ supplied argument is stored exactly as is: ffelex_token_use is NOT
+ called, so the token is "consumed", if one is indeed supplied (it may
+ be NULL). */
+
+ffebld
+ffebld_new_labtok (ffelexToken t)
+{
+ ffebld x;
+
+ x = ffebld_new ();
+#if FFEBLD_BLANK_
+ *x = ffebld_blank_;
+#endif
+ x->op = FFEBLD_opLABTOK;
+ x->u.labtok = t;
+ return x;
+}
+
+/* ffebld_new_none -- Create an ffebld object with no arguments
+
+ ffebld x;
+ x = ffebld_new_none(FFEBLD_opWHATEVER); */
+
+ffebld
+ffebld_new_none (ffebldOp o)
+{
+ ffebld x;
+
+ x = ffebld_new ();
+#if FFEBLD_BLANK_
+ *x = ffebld_blank_;
+#endif
+ x->op = o;
+ return x;
+}
+
+/* ffebld_new_one -- Create an ffebld object with one argument
+
+ ffebld x,y;
+ x = ffebld_new_one(FFEBLD_opWHATEVER,y); */
+
+ffebld
+ffebld_new_one (ffebldOp o, ffebld left)
+{
+ ffebld x;
+
+ x = ffebld_new ();
+#if FFEBLD_BLANK_
+ *x = ffebld_blank_;
+#endif
+ x->op = o;
+ x->u.nonter.left = left;
+ return x;
+}
+
+/* ffebld_new_symter -- Create an ffebld object that is a symbol
+
+ ffebld x;
+ ffesymbol s;
+ ffeintrinGen gen; // Generic intrinsic id, if any
+ ffeintrinSpec spec; // Specific intrinsic id, if any
+ ffeintrinImp imp; // Implementation intrinsic id, if any
+ x = ffebld_new_symter (s, gen, spec, imp); */
+
+ffebld
+ffebld_new_symter (ffesymbol s, ffeintrinGen gen, ffeintrinSpec spec,
+ ffeintrinImp imp)
+{
+ ffebld x;
+
+ x = ffebld_new ();
+#if FFEBLD_BLANK_
+ *x = ffebld_blank_;
+#endif
+ x->op = FFEBLD_opSYMTER;
+ x->u.symter.symbol = s;
+ x->u.symter.generic = gen;
+ x->u.symter.specific = spec;
+ x->u.symter.implementation = imp;
+ x->u.symter.do_iter = FALSE;
+ return x;
+}
+
+/* ffebld_new_two -- Create an ffebld object with two arguments
+
+ ffebld x,y,z;
+ x = ffebld_new_two(FFEBLD_opWHATEVER,y,z); */
+
+ffebld
+ffebld_new_two (ffebldOp o, ffebld left, ffebld right)
+{
+ ffebld x;
+
+ x = ffebld_new ();
+#if FFEBLD_BLANK_
+ *x = ffebld_blank_;
+#endif
+ x->op = o;
+ x->u.nonter.left = left;
+ x->u.nonter.right = right;
+ return x;
+}
+
+/* ffebld_pool_pop -- Pop ffebld's pool stack
+
+ ffebld_pool_pop(); */
+
+void
+ffebld_pool_pop ()
+{
+ ffebldPoolstack_ ps;
+
+ assert (ffebld_pool_stack_.next != NULL);
+ ps = ffebld_pool_stack_.next;
+ ffebld_pool_stack_.next = ps->next;
+ ffebld_pool_stack_.pool = ps->pool;
+ malloc_kill_ks (malloc_pool_image (), ps, sizeof (*ps));
+}
+
+/* ffebld_pool_push -- Push ffebld's pool stack
+
+ ffebld_pool_push(); */
+
+void
+ffebld_pool_push (mallocPool pool)
+{
+ ffebldPoolstack_ ps;
+
+ ps = malloc_new_ks (malloc_pool_image (), "Pool stack", sizeof (*ps));
+ ps->next = ffebld_pool_stack_.next;
+ ps->pool = ffebld_pool_stack_.pool;
+ ffebld_pool_stack_.next = ps;
+ ffebld_pool_stack_.pool = pool;
+}
+
+/* ffebld_op_string -- Return short string describing op
+
+ ffebldOp o;
+ ffebld_op_string(o);
+
+ Returns a short string (uppercase) containing the name of the op. */
+
+char *
+ffebld_op_string (ffebldOp o)
+{
+ if (o >= ARRAY_SIZE (ffebld_op_string_))
+ return "?\?\?";
+ return ffebld_op_string_[o];
+}
+
+/* ffebld_size_max -- Return maximum possible size of CHARACTER-type expr
+
+ ffetargetCharacterSize sz;
+ ffebld b;
+ sz = ffebld_size_max (b);
+
+ Like ffebld_size_known, but if that would return NONE and the expression
+ is opSUBSTR, opCONVERT, opPAREN, or opCONCATENATE, returns ffebld_size_max
+ of the subexpression(s). */
+
+ffetargetCharacterSize
+ffebld_size_max (ffebld b)
+{
+ ffetargetCharacterSize sz;
+
+recurse: /* :::::::::::::::::::: */
+
+ sz = ffebld_size_known (b);
+
+ if (sz != FFETARGET_charactersizeNONE)
+ return sz;
+
+ switch (ffebld_op (b))
+ {
+ case FFEBLD_opSUBSTR:
+ case FFEBLD_opCONVERT:
+ case FFEBLD_opPAREN:
+ b = ffebld_left (b);
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFEBLD_opCONCATENATE:
+ sz = ffebld_size_max (ffebld_left (b))
+ + ffebld_size_max (ffebld_right (b));
+ return sz;
+
+ default:
+ return sz;
+ }
+}
diff --git a/contrib/gcc/f/bld.h b/contrib/gcc/f/bld.h
new file mode 100644
index 0000000..d3b613ef
--- /dev/null
+++ b/contrib/gcc/f/bld.h
@@ -0,0 +1,1024 @@
+/* bld.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ bld.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_bld
+#define _H_f_bld
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFEBLD_constNONE,
+ FFEBLD_constINTEGER1,
+ FFEBLD_constINTEGER2,
+ FFEBLD_constINTEGER3,
+ FFEBLD_constINTEGER4,
+ FFEBLD_constINTEGER5,
+ FFEBLD_constINTEGER6,
+ FFEBLD_constINTEGER7,
+ FFEBLD_constINTEGER8,
+ FFEBLD_constLOGICAL1,
+ FFEBLD_constLOGICAL2,
+ FFEBLD_constLOGICAL3,
+ FFEBLD_constLOGICAL4,
+ FFEBLD_constLOGICAL5,
+ FFEBLD_constLOGICAL6,
+ FFEBLD_constLOGICAL7,
+ FFEBLD_constLOGICAL8,
+ FFEBLD_constREAL1,
+ FFEBLD_constREAL2,
+ FFEBLD_constREAL3,
+ FFEBLD_constREAL4,
+ FFEBLD_constREAL5,
+ FFEBLD_constREAL6,
+ FFEBLD_constREAL7,
+ FFEBLD_constREAL8,
+ FFEBLD_constCOMPLEX1,
+ FFEBLD_constCOMPLEX2,
+ FFEBLD_constCOMPLEX3,
+ FFEBLD_constCOMPLEX4,
+ FFEBLD_constCOMPLEX5,
+ FFEBLD_constCOMPLEX6,
+ FFEBLD_constCOMPLEX7,
+ FFEBLD_constCOMPLEX8,
+ FFEBLD_constCHARACTER1,
+ FFEBLD_constCHARACTER2,
+ FFEBLD_constCHARACTER3,
+ FFEBLD_constCHARACTER4,
+ FFEBLD_constCHARACTER5,
+ FFEBLD_constCHARACTER6,
+ FFEBLD_constCHARACTER7,
+ FFEBLD_constCHARACTER8,
+ FFEBLD_constHOLLERITH,
+ FFEBLD_constTYPELESS_FIRST,
+ FFEBLD_constBINARY_MIL = FFEBLD_constTYPELESS_FIRST,
+ FFEBLD_constBINARY_VXT,
+ FFEBLD_constOCTAL_MIL,
+ FFEBLD_constOCTAL_VXT,
+ FFEBLD_constHEX_X_MIL,
+ FFEBLD_constHEX_X_VXT,
+ FFEBLD_constHEX_Z_MIL,
+ FFEBLD_constHEX_Z_VXT,
+ FFEBLD_constTYPELESS_LAST = FFEBLD_constHEX_Z_VXT,
+ FFEBLD_const
+ } ffebldConst;
+
+typedef enum
+ {
+#define FFEBLD_OP(KWD,NAME,ARITY) KWD,
+#include "bld-op.def"
+#undef FFEBLD_OP
+ FFEBLD_op
+ } ffebldOp;
+
+/* Typedefs. */
+
+typedef struct _ffebld_ *ffebld;
+typedef unsigned char ffebldArity;
+typedef union _ffebld_constant_array_ ffebldConstantArray;
+typedef struct _ffebld_constant_ *ffebldConstant;
+typedef union _ffebld_constant_union_ ffebldConstantUnion;
+typedef ffebld *ffebldListBottom;
+typedef unsigned int ffebldListLength;
+#define ffebldListLength_f ""
+typedef struct _ffebld_pool_stack_ *ffebldPoolstack_;
+
+/* Include files needed by this one. */
+
+#include "bit.h"
+#include "com.h"
+#include "info.h"
+#include "intrin.h"
+#include "lab.h"
+#include "lex.h"
+#include "malloc.h"
+#include "symbol.h"
+#include "target.h"
+
+#define FFEBLD_whereconstPROGUNIT_ 1
+#define FFEBLD_whereconstFILE_ 2
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+#define FFEBLD_whereconstCURRENT_ FFEBLD_whereconstPROGUNIT_
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#define FFEBLD_whereconstCURRENT_ FFEBLD_whereconstFILE_
+#else
+#error
+#endif
+
+/* Structure definitions. */
+
+#define FFEBLD_constINTEGERDEFAULT FFEBLD_constINTEGER1
+#define FFEBLD_constLOGICALDEFAULT FFEBLD_constLOGICAL1
+#define FFEBLD_constREALDEFAULT FFEBLD_constREAL1
+#define FFEBLD_constREALDOUBLE FFEBLD_constREAL2
+#define FFEBLD_constREALQUAD FFEBLD_constREAL3
+#define FFEBLD_constCOMPLEX FFEBLD_constCOMPLEX1
+#define FFEBLD_constCOMPLEXDOUBLE FFEBLD_constCOMPLEX2
+#define FFEBLD_constCOMPLEXQUAD FFEBLD_constCOMPLEX3
+#define FFEBLD_constCHARACTERDEFAULT FFEBLD_constCHARACTER1
+
+union _ffebld_constant_union_
+ {
+ ffetargetTypeless typeless;
+ ffetargetHollerith hollerith;
+#if FFETARGET_okINTEGER1
+ ffetargetInteger1 integer1;
+#endif
+#if FFETARGET_okINTEGER2
+ ffetargetInteger2 integer2;
+#endif
+#if FFETARGET_okINTEGER3
+ ffetargetInteger3 integer3;
+#endif
+#if FFETARGET_okINTEGER4
+ ffetargetInteger4 integer4;
+#endif
+#if FFETARGET_okINTEGER5
+ ffetargetInteger5 integer5;
+#endif
+#if FFETARGET_okINTEGER6
+ ffetargetInteger6 integer6;
+#endif
+#if FFETARGET_okINTEGER7
+ ffetargetInteger7 integer7;
+#endif
+#if FFETARGET_okINTEGER8
+ ffetargetInteger8 integer8;
+#endif
+#if FFETARGET_okLOGICAL1
+ ffetargetLogical1 logical1;
+#endif
+#if FFETARGET_okLOGICAL2
+ ffetargetLogical2 logical2;
+#endif
+#if FFETARGET_okLOGICAL3
+ ffetargetLogical3 logical3;
+#endif
+#if FFETARGET_okLOGICAL4
+ ffetargetLogical4 logical4;
+#endif
+#if FFETARGET_okLOGICAL5
+ ffetargetLogical5 logical5;
+#endif
+#if FFETARGET_okLOGICAL6
+ ffetargetLogical6 logical6;
+#endif
+#if FFETARGET_okLOGICAL7
+ ffetargetLogical7 logical7;
+#endif
+#if FFETARGET_okLOGICAL8
+ ffetargetLogical8 logical8;
+#endif
+#if FFETARGET_okREAL1
+ ffetargetReal1 real1;
+#endif
+#if FFETARGET_okREAL2
+ ffetargetReal2 real2;
+#endif
+#if FFETARGET_okREAL3
+ ffetargetReal3 real3;
+#endif
+#if FFETARGET_okREAL4
+ ffetargetReal4 real4;
+#endif
+#if FFETARGET_okREAL5
+ ffetargetReal5 real5;
+#endif
+#if FFETARGET_okREAL6
+ ffetargetReal6 real6;
+#endif
+#if FFETARGET_okREAL7
+ ffetargetReal7 real7;
+#endif
+#if FFETARGET_okREAL8
+ ffetargetReal8 real8;
+#endif
+#if FFETARGET_okCOMPLEX1
+ ffetargetComplex1 complex1;
+#endif
+#if FFETARGET_okCOMPLEX2
+ ffetargetComplex2 complex2;
+#endif
+#if FFETARGET_okCOMPLEX3
+ ffetargetComplex3 complex3;
+#endif
+#if FFETARGET_okCOMPLEX4
+ ffetargetComplex4 complex4;
+#endif
+#if FFETARGET_okCOMPLEX5
+ ffetargetComplex5 complex5;
+#endif
+#if FFETARGET_okCOMPLEX6
+ ffetargetComplex6 complex6;
+#endif
+#if FFETARGET_okCOMPLEX7
+ ffetargetComplex7 complex7;
+#endif
+#if FFETARGET_okCOMPLEX8
+ ffetargetComplex8 complex8;
+#endif
+#if FFETARGET_okCHARACTER1
+ ffetargetCharacter1 character1;
+#endif
+#if FFETARGET_okCHARACTER2
+ ffetargetCharacter2 character2;
+#endif
+#if FFETARGET_okCHARACTER3
+ ffetargetCharacter3 character3;
+#endif
+#if FFETARGET_okCHARACTER4
+ ffetargetCharacter4 character4;
+#endif
+#if FFETARGET_okCHARACTER5
+ ffetargetCharacter5 character5;
+#endif
+#if FFETARGET_okCHARACTER6
+ ffetargetCharacter6 character6;
+#endif
+#if FFETARGET_okCHARACTER7
+ ffetargetCharacter7 character7;
+#endif
+#if FFETARGET_okCHARACTER8
+ ffetargetCharacter8 character8;
+#endif
+ };
+
+union _ffebld_constant_array_
+ {
+#if FFETARGET_okINTEGER1
+ ffetargetInteger1 *integer1;
+#endif
+#if FFETARGET_okINTEGER2
+ ffetargetInteger2 *integer2;
+#endif
+#if FFETARGET_okINTEGER3
+ ffetargetInteger3 *integer3;
+#endif
+#if FFETARGET_okINTEGER4
+ ffetargetInteger4 *integer4;
+#endif
+#if FFETARGET_okINTEGER5
+ ffetargetInteger5 *integer5;
+#endif
+#if FFETARGET_okINTEGER6
+ ffetargetInteger6 *integer6;
+#endif
+#if FFETARGET_okINTEGER7
+ ffetargetInteger7 *integer7;
+#endif
+#if FFETARGET_okINTEGER8
+ ffetargetInteger8 *integer8;
+#endif
+#if FFETARGET_okLOGICAL1
+ ffetargetLogical1 *logical1;
+#endif
+#if FFETARGET_okLOGICAL2
+ ffetargetLogical2 *logical2;
+#endif
+#if FFETARGET_okLOGICAL3
+ ffetargetLogical3 *logical3;
+#endif
+#if FFETARGET_okLOGICAL4
+ ffetargetLogical4 *logical4;
+#endif
+#if FFETARGET_okLOGICAL5
+ ffetargetLogical5 *logical5;
+#endif
+#if FFETARGET_okLOGICAL6
+ ffetargetLogical6 *logical6;
+#endif
+#if FFETARGET_okLOGICAL7
+ ffetargetLogical7 *logical7;
+#endif
+#if FFETARGET_okLOGICAL8
+ ffetargetLogical8 *logical8;
+#endif
+#if FFETARGET_okREAL1
+ ffetargetReal1 *real1;
+#endif
+#if FFETARGET_okREAL2
+ ffetargetReal2 *real2;
+#endif
+#if FFETARGET_okREAL3
+ ffetargetReal3 *real3;
+#endif
+#if FFETARGET_okREAL4
+ ffetargetReal4 *real4;
+#endif
+#if FFETARGET_okREAL5
+ ffetargetReal5 *real5;
+#endif
+#if FFETARGET_okREAL6
+ ffetargetReal6 *real6;
+#endif
+#if FFETARGET_okREAL7
+ ffetargetReal7 *real7;
+#endif
+#if FFETARGET_okREAL8
+ ffetargetReal8 *real8;
+#endif
+#if FFETARGET_okCOMPLEX1
+ ffetargetComplex1 *complex1;
+#endif
+#if FFETARGET_okCOMPLEX2
+ ffetargetComplex2 *complex2;
+#endif
+#if FFETARGET_okCOMPLEX3
+ ffetargetComplex3 *complex3;
+#endif
+#if FFETARGET_okCOMPLEX4
+ ffetargetComplex4 *complex4;
+#endif
+#if FFETARGET_okCOMPLEX5
+ ffetargetComplex5 *complex5;
+#endif
+#if FFETARGET_okCOMPLEX6
+ ffetargetComplex6 *complex6;
+#endif
+#if FFETARGET_okCOMPLEX7
+ ffetargetComplex7 *complex7;
+#endif
+#if FFETARGET_okCOMPLEX8
+ ffetargetComplex8 *complex8;
+#endif
+#if FFETARGET_okCHARACTER1
+ ffetargetCharacterUnit1 *character1;
+#endif
+#if FFETARGET_okCHARACTER2
+ ffetargetCharacterUnit2 *character2;
+#endif
+#if FFETARGET_okCHARACTER3
+ ffetargetCharacterUnit3 *character3;
+#endif
+#if FFETARGET_okCHARACTER4
+ ffetargetCharacterUnit4 *character4;
+#endif
+#if FFETARGET_okCHARACTER5
+ ffetargetCharacterUnit5 *character5;
+#endif
+#if FFETARGET_okCHARACTER6
+ ffetargetCharacterUnit6 *character6;
+#endif
+#if FFETARGET_okCHARACTER7
+ ffetargetCharacterUnit7 *character7;
+#endif
+#if FFETARGET_okCHARACTER8
+ ffetargetCharacterUnit8 *character8;
+#endif
+ };
+
+struct _ffebld_
+ {
+ ffebldOp op;
+ ffeinfo info; /* Not used or valid for
+ op=={STAR,ITEM,BOUNDS,REPEAT,LABTER,
+ LABTOK,IMPDO}. */
+ union
+ {
+ struct
+ {
+ ffebld left;
+ ffebld right;
+ }
+ nonter;
+ struct
+ {
+ ffebld head;
+ ffebld trail;
+ }
+ item;
+ struct
+ {
+ ffebldConstant expr;
+ ffebld orig; /* Original expression, or NULL if none. */
+ ffetargetAlign pad; /* Initial padding (for DATA, etc.). */
+ }
+ conter;
+ struct
+ {
+ ffebldConstantArray array;
+ ffetargetOffset size;
+ ffetargetAlign pad; /* Initial padding (for DATA, etc.). */
+ }
+ arrter;
+ struct
+ {
+ ffebldConstantArray array;
+ ffebit bits;
+ ffetargetAlign pad; /* Initial padding (for DATA, etc.). */
+ }
+ accter;
+ struct
+ {
+ ffesymbol symbol;
+ ffeintrinGen generic; /* Id for generic intrinsic. */
+ ffeintrinSpec specific; /* Id for specific intrinsic. */
+ ffeintrinImp implementation; /* Id for implementation. */
+ bool do_iter; /* TRUE if this ref is a read-only ref by
+ definition (ref within DO loop using this
+ var as iterator). */
+ }
+ symter;
+ ffelab labter;
+ ffelexToken labtok;
+ }
+ u;
+ };
+
+struct _ffebld_constant_
+ {
+ ffebldConstant next;
+ ffebldConstant first_complex; /* First complex const with me as
+ real. */
+ ffebldConstant negated; /* We point to each other through here. */
+ ffebldConst consttype;
+#ifdef FFECOM_constantHOOK
+ ffecomConstant hook; /* Whatever the compiler/backend wants! */
+#endif
+ bool numeric; /* A numeric kind of constant. */
+ ffebldConstantUnion u;
+ };
+
+struct _ffebld_pool_stack_
+ {
+ ffebldPoolstack_ next;
+ mallocPool pool;
+ };
+
+/* Global objects accessed by users of this module. */
+
+extern ffebldArity ffebld_arity_op_[];
+extern struct _ffebld_pool_stack_ ffebld_pool_stack_;
+
+/* Declare functions with prototypes. */
+
+int ffebld_constant_cmp (ffebldConstant c1, ffebldConstant c2);
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffebld_constant_dump (ffebldConstant c);
+#endif
+bool ffebld_constant_is_magical (ffebldConstant c);
+bool ffebld_constant_is_zero (ffebldConstant c);
+#if FFETARGET_okCHARACTER1
+ffebldConstant ffebld_constant_new_character1 (ffelexToken t);
+ffebldConstant ffebld_constant_new_character1_val (ffetargetCharacter1 val);
+#endif
+#if FFETARGET_okCHARACTER2
+ffebldConstant ffebld_constant_new_character2 (ffelexToken t);
+ffebldConstant ffebld_constant_new_character2_val (ffetargetCharacter2 val);
+#endif
+#if FFETARGET_okCHARACTER3
+ffebldConstant ffebld_constant_new_character3 (ffelexToken t);
+ffebldConstant ffebld_constant_new_character3_val (ffetargetCharacter3 val);
+#endif
+#if FFETARGET_okCHARACTER4
+ffebldConstant ffebld_constant_new_character4 (ffelexToken t);
+ffebldConstant ffebld_constant_new_character4_val (ffetargetCharacter4 val);
+#endif
+#if FFETARGET_okCHARACTER5
+ffebldConstant ffebld_constant_new_character5 (ffelexToken t);
+ffebldConstant ffebld_constant_new_character5_val (ffetargetCharacter5 val);
+#endif
+#if FFETARGET_okCHARACTER6
+ffebldConstant ffebld_constant_new_character6 (ffelexToken t);
+ffebldConstant ffebld_constant_new_character6_val (ffetargetCharacter6 val);
+#endif
+#if FFETARGET_okCHARACTER7
+ffebldConstant ffebld_constant_new_character7 (ffelexToken t);
+ffebldConstant ffebld_constant_new_character7_val (ffetargetCharacter7 val);
+#endif
+#if FFETARGET_okCHARACTER8
+ffebldConstant ffebld_constant_new_character8 (ffelexToken t);
+ffebldConstant ffebld_constant_new_character8_val (ffetargetCharacter8 val);
+#endif
+#if FFETARGET_okCOMPLEX1
+ffebldConstant ffebld_constant_new_complex1 (ffebldConstant real,
+ ffebldConstant imaginary);
+ffebldConstant ffebld_constant_new_complex1_val (ffetargetComplex1 val);
+#endif
+#if FFETARGET_okCOMPLEX2
+ffebldConstant ffebld_constant_new_complex2 (ffebldConstant real,
+ ffebldConstant imaginary);
+ffebldConstant ffebld_constant_new_complex2_val (ffetargetComplex2 val);
+#endif
+#if FFETARGET_okCOMPLEX3
+ffebldConstant ffebld_constant_new_complex3 (ffebldConstant real,
+ ffebldConstant imaginary);
+ffebldConstant ffebld_constant_new_complex3_val (ffetargetComplex3 val);
+#endif
+#if FFETARGET_okCOMPLEX4
+ffebldConstant ffebld_constant_new_complex4 (ffebldConstant real,
+ ffebldConstant imaginary);
+ffebldConstant ffebld_constant_new_complex4_val (ffetargetComplex4 val);
+#endif
+#if FFETARGET_okCOMPLEX5
+ffebldConstant ffebld_constant_new_complex5 (ffebldConstant real,
+ ffebldConstant imaginary);
+ffebldConstant ffebld_constant_new_complex5_val (ffetargetComplex5 val);
+#endif
+#if FFETARGET_okCOMPLEX6
+ffebldConstant ffebld_constant_new_complex6 (ffebldConstant real,
+ ffebldConstant imaginary);
+ffebldConstant ffebld_constant_new_complex6_val (ffetargetComplex6 val);
+#endif
+#if FFETARGET_okCOMPLEX7
+ffebldConstant ffebld_constant_new_complex7 (ffebldConstant real,
+ ffebldConstant imaginary);
+ffebldConstant ffebld_constant_new_complex7_val (ffetargetComplex7 val);
+#endif
+#if FFETARGET_okCOMPLEX8
+ffebldConstant ffebld_constant_new_complex8 (ffebldConstant real,
+ ffebldConstant imaginary);
+ffebldConstant ffebld_constant_new_complex8_val (ffetargetComplex8 val);
+#endif
+ffebldConstant ffebld_constant_new_hollerith (ffelexToken t);
+ffebldConstant ffebld_constant_new_hollerith_val (ffetargetHollerith val);
+#if FFETARGET_okINTEGER1
+ffebldConstant ffebld_constant_new_integer1 (ffelexToken t);
+ffebldConstant ffebld_constant_new_integer1_val (ffetargetInteger1 val);
+#endif
+#if FFETARGET_okINTEGER2
+ffebldConstant ffebld_constant_new_integer2 (ffelexToken t);
+ffebldConstant ffebld_constant_new_integer2_val (ffetargetInteger2 val);
+#endif
+#if FFETARGET_okINTEGER3
+ffebldConstant ffebld_constant_new_integer3 (ffelexToken t);
+ffebldConstant ffebld_constant_new_integer3_val (ffetargetInteger3 val);
+#endif
+#if FFETARGET_okINTEGER4
+ffebldConstant ffebld_constant_new_integer4 (ffelexToken t);
+ffebldConstant ffebld_constant_new_integer4_val (ffetargetInteger4 val);
+#endif
+#if FFETARGET_okINTEGER5
+ffebldConstant ffebld_constant_new_integer5 (ffelexToken t);
+ffebldConstant ffebld_constant_new_integer5_val (ffetargetInteger5 val);
+#endif
+#if FFETARGET_okINTEGER6
+ffebldConstant ffebld_constant_new_integer6 (ffelexToken t);
+ffebldConstant ffebld_constant_new_integer6_val (ffetargetInteger6 val);
+#endif
+#if FFETARGET_okINTEGER7
+ffebldConstant ffebld_constant_new_integer7 (ffelexToken t);
+ffebldConstant ffebld_constant_new_integer7_val (ffetargetInteger7 val);
+#endif
+#if FFETARGET_okINTEGER8
+ffebldConstant ffebld_constant_new_integer8 (ffelexToken t);
+ffebldConstant ffebld_constant_new_integer8_val (ffetargetInteger8 val);
+#endif
+ffebldConstant ffebld_constant_new_integerbinary (ffelexToken t);
+ffebldConstant ffebld_constant_new_integerhex (ffelexToken t);
+ffebldConstant ffebld_constant_new_integeroctal (ffelexToken t);
+#if FFETARGET_okLOGICAL1
+ffebldConstant ffebld_constant_new_logical1 (bool truth);
+ffebldConstant ffebld_constant_new_logical1_val (ffetargetLogical1 val);
+#endif
+#if FFETARGET_okLOGICAL2
+ffebldConstant ffebld_constant_new_logical2 (bool truth);
+ffebldConstant ffebld_constant_new_logical2_val (ffetargetLogical2 val);
+#endif
+#if FFETARGET_okLOGICAL3
+ffebldConstant ffebld_constant_new_logical3 (bool truth);
+ffebldConstant ffebld_constant_new_logical3_val (ffetargetLogical3 val);
+#endif
+#if FFETARGET_okLOGICAL4
+ffebldConstant ffebld_constant_new_logical4 (bool truth);
+ffebldConstant ffebld_constant_new_logical4_val (ffetargetLogical4 val);
+#endif
+#if FFETARGET_okLOGICAL5
+ffebldConstant ffebld_constant_new_logical5 (bool truth);
+ffebldConstant ffebld_constant_new_logical5_val (ffetargetLogical5 val);
+#endif
+#if FFETARGET_okLOGICAL6
+ffebldConstant ffebld_constant_new_logical6 (bool truth);
+ffebldConstant ffebld_constant_new_logical6_val (ffetargetLogical6 val);
+#endif
+#if FFETARGET_okLOGICAL7
+ffebldConstant ffebld_constant_new_logical7 (bool truth);
+ffebldConstant ffebld_constant_new_logical7_val (ffetargetLogical7 val);
+#endif
+#if FFETARGET_okLOGICAL8
+ffebldConstant ffebld_constant_new_logical8 (bool truth);
+ffebldConstant ffebld_constant_new_logical8_val (ffetargetLogical8 val);
+#endif
+#if FFETARGET_okREAL1
+ffebldConstant ffebld_constant_new_real1 (ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction, ffelexToken exponent,
+ ffelexToken exponent_sign, ffelexToken exponent_digits);
+ffebldConstant ffebld_constant_new_real1_val (ffetargetReal1 val);
+#endif
+#if FFETARGET_okREAL2
+ffebldConstant ffebld_constant_new_real2 (ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction, ffelexToken exponent,
+ ffelexToken exponent_sign, ffelexToken exponent_digits);
+ffebldConstant ffebld_constant_new_real2_val (ffetargetReal2 val);
+#endif
+#if FFETARGET_okREAL3
+ffebldConstant ffebld_constant_new_real3 (ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction, ffelexToken exponent,
+ ffelexToken exponent_sign, ffelexToken exponent_digits);
+ffebldConstant ffebld_constant_new_real3_val (ffetargetReal3 val);
+#endif
+#if FFETARGET_okREAL4
+ffebldConstant ffebld_constant_new_real4 (ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction, ffelexToken exponent,
+ ffelexToken exponent_sign, ffelexToken exponent_digits);
+ffebldConstant ffebld_constant_new_real4_val (ffetargetReal4 val);
+#endif
+#if FFETARGET_okREAL5
+ffebldConstant ffebld_constant_new_real5 (ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction, ffelexToken exponent,
+ ffelexToken exponent_sign, ffelexToken exponent_digits);
+ffebldConstant ffebld_constant_new_real5_val (ffetargetReal5 val);
+#endif
+#if FFETARGET_okREAL6
+ffebldConstant ffebld_constant_new_real6 (ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction, ffelexToken exponent,
+ ffelexToken exponent_sign, ffelexToken exponent_digits);
+ffebldConstant ffebld_constant_new_real6_val (ffetargetReal6 val);
+#endif
+#if FFETARGET_okREAL7
+ffebldConstant ffebld_constant_new_real7 (ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction, ffelexToken exponent,
+ ffelexToken exponent_sign, ffelexToken exponent_digits);
+ffebldConstant ffebld_constant_new_real7_val (ffetargetReal7 val);
+#endif
+#if FFETARGET_okREAL8
+ffebldConstant ffebld_constant_new_real8 (ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction, ffelexToken exponent,
+ ffelexToken exponent_sign, ffelexToken exponent_digits);
+ffebldConstant ffebld_constant_new_real8_val (ffetargetReal8 val);
+#endif
+ffebldConstant ffebld_constant_new_typeless_bm (ffelexToken t);
+ffebldConstant ffebld_constant_new_typeless_bv (ffelexToken t);
+ffebldConstant ffebld_constant_new_typeless_hxm (ffelexToken t);
+ffebldConstant ffebld_constant_new_typeless_hxv (ffelexToken t);
+ffebldConstant ffebld_constant_new_typeless_hzm (ffelexToken t);
+ffebldConstant ffebld_constant_new_typeless_hzv (ffelexToken t);
+ffebldConstant ffebld_constant_new_typeless_om (ffelexToken t);
+ffebldConstant ffebld_constant_new_typeless_ov (ffelexToken t);
+ffebldConstant ffebld_constant_new_typeless_val (ffebldConst type,
+ ffetargetTypeless val);
+ffebldConstant ffebld_constant_negated (ffebldConstant c);
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffebld_constantarray_dump (ffebldConstantArray array, ffeinfoBasictype bt,
+ ffeinfoKindtype kt, ffetargetOffset size, ffebit bits);
+#endif
+ffebldConstantUnion ffebld_constantarray_get (ffebldConstantArray array,
+ ffeinfoBasictype bt, ffeinfoKindtype kt, ffetargetOffset offset);
+void ffebld_constantarray_kill (ffebldConstantArray array, ffeinfoBasictype bt,
+ ffeinfoKindtype kt, ffetargetOffset size);
+ffebldConstantArray ffebld_constantarray_new (ffeinfoBasictype bt,
+ ffeinfoKindtype kt, ffetargetOffset size);
+void ffebld_constantarray_prepare (void **aptr, void **cptr, size_t *size,
+ ffebldConstantArray array, ffeinfoBasictype abt, ffeinfoKindtype akt,
+ ffetargetOffset offset, ffebldConstantUnion *constant,
+ ffeinfoBasictype cbt, ffeinfoKindtype ckt);
+void ffebld_constantarray_preparray (void **aptr, void **cptr, size_t *size,
+ ffebldConstantArray array, ffeinfoBasictype abt, ffeinfoKindtype akt,
+ ffetargetOffset offset, ffebldConstantArray source_array,
+ ffeinfoBasictype cbt, ffeinfoKindtype ckt);
+void ffebld_constantarray_put (ffebldConstantArray array, ffeinfoBasictype bt,
+ ffeinfoKindtype kt, ffetargetOffset offset, ffebldConstantUnion constant);
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffebld_constantunion_dump (ffebldConstantUnion u, ffeinfoBasictype bt,
+ ffeinfoKindtype kt);
+void ffebld_dump (ffebld b);
+void ffebld_dump_prefix (FILE *out, ffeinfoBasictype bt, ffeinfoKindtype kt);
+#endif
+void ffebld_init_0 (void);
+void ffebld_init_1 (void);
+void ffebld_init_2 (void);
+ffebldListLength ffebld_list_length (ffebld l);
+ffebld ffebld_new_accter (ffebldConstantArray array, ffebit b);
+ffebld ffebld_new_arrter (ffebldConstantArray array, ffetargetOffset size);
+ffebld ffebld_new_conter_with_orig (ffebldConstant c, ffebld orig);
+ffebld ffebld_new_item (ffebld head, ffebld trail);
+ffebld ffebld_new_labter (ffelab l);
+ffebld ffebld_new_labtok (ffelexToken t);
+ffebld ffebld_new_none (ffebldOp o);
+ffebld ffebld_new_symter (ffesymbol s, ffeintrinGen gen, ffeintrinSpec spec,
+ ffeintrinImp imp);
+ffebld ffebld_new_one (ffebldOp o, ffebld left);
+ffebld ffebld_new_two (ffebldOp o, ffebld left, ffebld right);
+char *ffebld_op_string (ffebldOp o);
+void ffebld_pool_pop (void);
+void ffebld_pool_push (mallocPool pool);
+ffetargetCharacterSize ffebld_size_max (ffebld b);
+
+/* Define macros. */
+
+#define ffebld_accter(b) ((b)->u.accter.array)
+#define ffebld_accter_bits(b) ((b)->u.accter.bits)
+#define ffebld_accter_pad(b) ((b)->u.accter.pad)
+#define ffebld_accter_set_bits(b,bt) ((b)->u.accter.bits = (bt))
+#define ffebld_accter_set_pad(b,p) ((b)->u.accter.pad = (p))
+#define ffebld_accter_size(b) ffebit_size((b)->u.accter.bits)
+#define ffebld_append_item(b,i) (**(b) = ffebld_new_item((i),NULL), \
+ *(b) = &((**(b))->u.item.trail))
+#define ffebld_arity(b) ffebld_arity_op(ffebld_op(b))
+#define ffebld_arity_op(o) (ffebld_arity_op_[o])
+#define ffebld_arrter(b) ((b)->u.arrter.array)
+#define ffebld_arrter_pad(b) ((b)->u.arrter.pad)
+#define ffebld_arrter_set_pad(b,p) ((b)->u.arrter.pad = (p))
+#define ffebld_arrter_set_size(b,s) ((b)->u.arrter.size = (s))
+#define ffebld_arrter_size(b) ((b)->u.arrter.size)
+#if FFEBLD_whereconstCURRENT_ == FFEBLD_whereconstPROGUNIT_
+#define ffebld_constant_pool() ffe_pool_program_unit()
+#elif FFEBLD_whereconstCURRENT_ == FFEBLD_whereconstFILE_
+#define ffebld_constant_pool() ffe_pool_file()
+#else
+#error
+#endif
+#define ffebld_constant_character1(c) ((c)->u.character1)
+#define ffebld_constant_character2(c) ((c)->u.character2)
+#define ffebld_constant_character3(c) ((c)->u.character3)
+#define ffebld_constant_character4(c) ((c)->u.character4)
+#define ffebld_constant_character5(c) ((c)->u.character5)
+#define ffebld_constant_character6(c) ((c)->u.character6)
+#define ffebld_constant_character7(c) ((c)->u.character7)
+#define ffebld_constant_character8(c) ((c)->u.character8)
+#define ffebld_constant_characterdefault ffebld_constant_character1
+#define ffebld_constant_complex1(c) ((c)->u.complex1)
+#define ffebld_constant_complex2(c) ((c)->u.complex2)
+#define ffebld_constant_complex3(c) ((c)->u.complex3)
+#define ffebld_constant_complex4(c) ((c)->u.complex4)
+#define ffebld_constant_complex5(c) ((c)->u.complex5)
+#define ffebld_constant_complex6(c) ((c)->u.complex6)
+#define ffebld_constant_complex7(c) ((c)->u.complex7)
+#define ffebld_constant_complex8(c) ((c)->u.complex8)
+#define ffebld_constant_complexdefault ffebld_constant_complex1
+#define ffebld_constant_complexdouble ffebld_constant_complex2
+#define ffebld_constant_complexquad ffebld_constant_complex3
+#define ffebld_constant_copy(c) (c)
+#define ffebld_constant_hollerith(c) ((c)->u.hollerith)
+#define ffebld_constant_hook(c) ((c)->hook)
+#define ffebld_constant_integer1(c) ((c)->u.integer1)
+#define ffebld_constant_integer2(c) ((c)->u.integer2)
+#define ffebld_constant_integer3(c) ((c)->u.integer3)
+#define ffebld_constant_integer4(c) ((c)->u.integer4)
+#define ffebld_constant_integer5(c) ((c)->u.integer5)
+#define ffebld_constant_integer6(c) ((c)->u.integer6)
+#define ffebld_constant_integer7(c) ((c)->u.integer7)
+#define ffebld_constant_integer8(c) ((c)->u.integer8)
+#define ffebld_constant_integerdefault ffebld_constant_integer1
+#define ffebld_constant_is_numeric(c) ((c)->numeric)
+#define ffebld_constant_logical1(c) ((c)->u.logical1)
+#define ffebld_constant_logical2(c) ((c)->u.logical2)
+#define ffebld_constant_logical3(c) ((c)->u.logical3)
+#define ffebld_constant_logical4(c) ((c)->u.logical4)
+#define ffebld_constant_logical5(c) ((c)->u.logical5)
+#define ffebld_constant_logical6(c) ((c)->u.logical6)
+#define ffebld_constant_logical7(c) ((c)->u.logical7)
+#define ffebld_constant_logical8(c) ((c)->u.logical8)
+#define ffebld_constant_logicaldefault ffebld_constant_logical1
+#define ffebld_constant_new_characterdefault ffebld_constant_new_character1
+#define ffebld_constant_new_characterdefault_val ffebld_constant_new_character1_val
+#define ffebld_constant_new_complexdefault ffebld_constant_new_complex1
+#define ffebld_constant_new_complexdefault_val ffebld_constant_new_complex1_val
+#define ffebld_constant_new_complexdouble ffebld_constant_new_complex2
+#define ffebld_constant_new_complexdouble_val ffebld_constant_new_complex2_val
+#define ffebld_constant_new_complexquad ffebld_constant_new_complex3
+#define ffebld_constant_new_complexquad_valffebld_constant_new_complex3_val
+#define ffebld_constant_new_integerdefault ffebld_constant_new_integer1
+#define ffebld_constant_new_integerdefault_val ffebld_constant_new_integer1_val
+#define ffebld_constant_new_logicaldefault ffebld_constant_new_logical1
+#define ffebld_constant_new_logicaldefault_val ffebld_constant_new_logical1_val
+#define ffebld_constant_new_realdefault ffebld_constant_new_real1
+#define ffebld_constant_new_realdefault_val ffebld_constant_new_real1_val
+#define ffebld_constant_new_realdouble ffebld_constant_new_real2
+#define ffebld_constant_new_realdouble_val ffebld_constant_new_real2_val
+#define ffebld_constant_new_realquad ffebld_constant_new_real3
+#define ffebld_constant_new_realquad_val ffebld_constant_new_real3_val
+#define ffebld_constant_ptr_to_union(c) (&(c)->u)
+#define ffebld_constant_real1(c) ((c)->u.real1)
+#define ffebld_constant_real2(c) ((c)->u.real2)
+#define ffebld_constant_real3(c) ((c)->u.real3)
+#define ffebld_constant_real4(c) ((c)->u.real4)
+#define ffebld_constant_real5(c) ((c)->u.real5)
+#define ffebld_constant_real6(c) ((c)->u.real6)
+#define ffebld_constant_real7(c) ((c)->u.real7)
+#define ffebld_constant_real8(c) ((c)->u.real8)
+#define ffebld_constant_realdefault ffebld_constant_real1
+#define ffebld_constant_realdouble ffebld_constant_real2
+#define ffebld_constant_realquad ffebld_constant_real3
+#define ffebld_constant_set_hook(c,h) ((c)->hook = (h))
+#define ffebld_constant_set_union(c,un) ((c)->u = (un))
+#define ffebld_constant_type(c) ((c)->consttype)
+#define ffebld_constant_typeless(c) ((c)->u.typeless)
+#define ffebld_constant_union(c) ((c)->u)
+#define ffebld_conter(b) ((b)->u.conter.expr)
+#define ffebld_conter_orig(b) ((b)->u.conter.orig)
+#define ffebld_conter_pad(b) ((b)->u.conter.pad)
+#define ffebld_conter_set_orig(b,o) ((b)->u.conter.orig = (o))
+#define ffebld_conter_set_pad(b,p) ((b)->u.conter.pad = (p))
+#define ffebld_copy(b) (b) /* ~~~Someday really make a copy. */
+#define ffebld_cu_ptr_typeless(u) &(u).typeless
+#define ffebld_cu_ptr_hollerith(u) &(u).hollerith
+#define ffebld_cu_ptr_integer1(u) &(u).integer1
+#define ffebld_cu_ptr_integer2(u) &(u).integer2
+#define ffebld_cu_ptr_integer3(u) &(u).integer3
+#define ffebld_cu_ptr_integer4(u) &(u).integer4
+#define ffebld_cu_ptr_integer5(u) &(u).integer5
+#define ffebld_cu_ptr_integer6(u) &(u).integer6
+#define ffebld_cu_ptr_integer7(u) &(u).integer7
+#define ffebld_cu_ptr_integer8(u) &(u).integer8
+#define ffebld_cu_ptr_integerdefault ffebld_cu_ptr_integer1
+#define ffebld_cu_ptr_logical1(u) &(u).logical1
+#define ffebld_cu_ptr_logical2(u) &(u).logical2
+#define ffebld_cu_ptr_logical3(u) &(u).logical3
+#define ffebld_cu_ptr_logical4(u) &(u).logical4
+#define ffebld_cu_ptr_logical5(u) &(u).logical5
+#define ffebld_cu_ptr_logical6(u) &(u).logical6
+#define ffebld_cu_ptr_logical7(u) &(u).logical7
+#define ffebld_cu_ptr_logical8(u) &(u).logical8
+#define ffebld_cu_ptr_logicaldefault ffebld_cu_ptr_logical1
+#define ffebld_cu_ptr_real1(u) &(u).real1
+#define ffebld_cu_ptr_real2(u) &(u).real2
+#define ffebld_cu_ptr_real3(u) &(u).real3
+#define ffebld_cu_ptr_real4(u) &(u).real4
+#define ffebld_cu_ptr_real5(u) &(u).real5
+#define ffebld_cu_ptr_real6(u) &(u).real6
+#define ffebld_cu_ptr_real7(u) &(u).real7
+#define ffebld_cu_ptr_real8(u) &(u).real8
+#define ffebld_cu_ptr_realdefault ffebld_cu_ptr_real1
+#define ffebld_cu_ptr_realdouble ffebld_cu_ptr_real2
+#define ffebld_cu_ptr_realquad ffebld_cu_ptr_real3
+#define ffebld_cu_ptr_complex1(u) &(u).complex1
+#define ffebld_cu_ptr_complex2(u) &(u).complex2
+#define ffebld_cu_ptr_complex3(u) &(u).complex3
+#define ffebld_cu_ptr_complex4(u) &(u).complex4
+#define ffebld_cu_ptr_complex5(u) &(u).complex5
+#define ffebld_cu_ptr_complex6(u) &(u).complex6
+#define ffebld_cu_ptr_complex7(u) &(u).complex7
+#define ffebld_cu_ptr_complex8(u) &(u).complex8
+#define ffebld_cu_ptr_complexdefault ffebld_cu_ptr_complex1
+#define ffebld_cu_ptr_complexdouble ffebld_cu_ptr_complex2
+#define ffebld_cu_ptr_complexquad ffebld_cu_ptr_complex3
+#define ffebld_cu_ptr_character1(u) &(u).character1
+#define ffebld_cu_ptr_character2(u) &(u).character2
+#define ffebld_cu_ptr_character3(u) &(u).character3
+#define ffebld_cu_ptr_character4(u) &(u).character4
+#define ffebld_cu_ptr_character5(u) &(u).character5
+#define ffebld_cu_ptr_character6(u) &(u).character6
+#define ffebld_cu_ptr_character7(u) &(u).character7
+#define ffebld_cu_ptr_character8(u) &(u).character8
+#define ffebld_cu_val_typeless(u) (u).typeless
+#define ffebld_cu_val_hollerith(u) (u).hollerith
+#define ffebld_cu_val_integer1(u) (u).integer1
+#define ffebld_cu_val_integer2(u) (u).integer2
+#define ffebld_cu_val_integer3(u) (u).integer3
+#define ffebld_cu_val_integer4(u) (u).integer4
+#define ffebld_cu_val_integer5(u) (u).integer5
+#define ffebld_cu_val_integer6(u) (u).integer6
+#define ffebld_cu_val_integer7(u) (u).integer7
+#define ffebld_cu_val_integer8(u) (u).integer8
+#define ffebld_cu_val_integerdefault ffebld_cu_val_integer1
+#define ffebld_cu_val_logical1(u) (u).logical1
+#define ffebld_cu_val_logical2(u) (u).logical2
+#define ffebld_cu_val_logical3(u) (u).logical3
+#define ffebld_cu_val_logical4(u) (u).logical4
+#define ffebld_cu_val_logical5(u) (u).logical5
+#define ffebld_cu_val_logical6(u) (u).logical6
+#define ffebld_cu_val_logical7(u) (u).logical7
+#define ffebld_cu_val_logical8(u) (u).logical8
+#define ffebld_cu_val_logicaldefault ffebld_cu_val_logical
+#define ffebld_cu_val_real1(u) (u).real1
+#define ffebld_cu_val_real2(u) (u).real2
+#define ffebld_cu_val_real3(u) (u).real3
+#define ffebld_cu_val_real4(u) (u).real4
+#define ffebld_cu_val_real5(u) (u).real5
+#define ffebld_cu_val_real6(u) (u).real6
+#define ffebld_cu_val_real7(u) (u).real7
+#define ffebld_cu_val_real8(u) (u).real8
+#define ffebld_cu_val_realdefault ffebld_cu_val_real1
+#define ffebld_cu_val_realdouble ffebld_cu_val_real2
+#define ffebld_cu_val_realquad ffebld_cu_val_real3
+#define ffebld_cu_val_complex1(u) (u).complex1
+#define ffebld_cu_val_complex2(u) (u).complex2
+#define ffebld_cu_val_complex3(u) (u).complex3
+#define ffebld_cu_val_complex4(u) (u).complex4
+#define ffebld_cu_val_complex5(u) (u).complex5
+#define ffebld_cu_val_complex6(u) (u).complex6
+#define ffebld_cu_val_complex7(u) (u).complex7
+#define ffebld_cu_val_complex8(u) (u).complex8
+#define ffebld_cu_val_complexdefault ffebld_cu_val_complex1
+#define ffebld_cu_val_complexdouble ffebld_cu_val_complex2
+#define ffebld_cu_val_complexquad ffebld_cu_val_complex3
+#define ffebld_cu_val_character1(u) (u).character1
+#define ffebld_cu_val_character2(u) (u).character2
+#define ffebld_cu_val_character3(u) (u).character3
+#define ffebld_cu_val_character4(u) (u).character4
+#define ffebld_cu_val_character5(u) (u).character5
+#define ffebld_cu_val_character6(u) (u).character6
+#define ffebld_cu_val_character7(u) (u).character7
+#define ffebld_cu_val_character8(u) (u).character8
+#define ffebld_end_list(b) (*(b) = NULL)
+#define ffebld_head(b) ((b)->u.item.head)
+#define ffebld_info(b) ((b)->info)
+#define ffebld_init_3()
+#define ffebld_init_4()
+#define ffebld_init_list(l,b) (*(l) = NULL, *(b) = (l))
+#define ffebld_labter(b) ((b)->u.labter)
+#define ffebld_labtok(b) ((b)->u.labtok)
+#define ffebld_left(b) ((b)->u.nonter.left)
+#define ffebld_name_string(n) ((n)->name)
+#define ffebld_new() \
+ ((ffebld) malloc_new_kp(ffebld_pool(), "FFEBLD",sizeof(struct _ffebld_)))
+#define ffebld_new_any() ffebld_new_none(FFEBLD_opANY)
+#define ffebld_new_conter(c) ffebld_new_conter_with_orig((c),NULL)
+#define ffebld_new_star() ffebld_new_none(FFEBLD_opSTAR)
+#define ffebld_new_uplus(l) ffebld_new_one(FFEBLD_opUPLUS,(l))
+#define ffebld_new_uminus(l) ffebld_new_one(FFEBLD_opUMINUS,(l))
+#define ffebld_new_add(l,r) ffebld_new_two(FFEBLD_opADD,(l),(r))
+#define ffebld_new_subtract(l,r) ffebld_new_two(FFEBLD_opSUBTRACT,(l),(r))
+#define ffebld_new_multiply(l,r) ffebld_new_two(FFEBLD_opMULTIPLY,(l),(r))
+#define ffebld_new_divide(l,r) ffebld_new_two(FFEBLD_opDIVIDE,(l),(r))
+#define ffebld_new_power(l,r) ffebld_new_two(FFEBLD_opPOWER,(l),(r))
+#define ffebld_new_bounds(l,r) ffebld_new_two(FFEBLD_opBOUNDS,(l),(r))
+#define ffebld_new_concatenate(l,r) ffebld_new_two(FFEBLD_opCONCATENATE,(l),(r))
+#define ffebld_new_not(l) ffebld_new_one(FFEBLD_opNOT,(l))
+#define ffebld_new_lt(l,r) ffebld_new_two(FFEBLD_opLT,(l),(r))
+#define ffebld_new_le(l,r) ffebld_new_two(FFEBLD_opLE,(l),(r))
+#define ffebld_new_eq(l,r) ffebld_new_two(FFEBLD_opEQ,(l),(r))
+#define ffebld_new_ne(l,r) ffebld_new_two(FFEBLD_opNE,(l),(r))
+#define ffebld_new_gt(l,r) ffebld_new_two(FFEBLD_opGT,(l),(r))
+#define ffebld_new_ge(l,r) ffebld_new_two(FFEBLD_opGE,(l),(r))
+#define ffebld_new_and(l,r) ffebld_new_two(FFEBLD_opAND,(l),(r))
+#define ffebld_new_or(l,r) ffebld_new_two(FFEBLD_opOR,(l),(r))
+#define ffebld_new_xor(l,r) ffebld_new_two(FFEBLD_opXOR,(l),(r))
+#define ffebld_new_eqv(l,r) ffebld_new_two(FFEBLD_opEQV,(l),(r))
+#define ffebld_new_neqv(l,r) ffebld_new_two(FFEBLD_opNEQV,(l),(r))
+#define ffebld_new_paren(l) ffebld_new_one(FFEBLD_opPAREN,(l))
+#define ffebld_new_repeat(l,r) ffebld_new_two(FFEBLD_opREPEAT,(l),(r))
+#define ffebld_new_percent_descr(l) ffebld_new_one(FFEBLD_opPERCENT_DESCR,(l))
+#define ffebld_new_percent_loc(l) ffebld_new_one(FFEBLD_opPERCENT_LOC,(l))
+#define ffebld_new_percent_ref(l) ffebld_new_one(FFEBLD_opPERCENT_REF,(l))
+#define ffebld_new_percent_val(l) ffebld_new_one(FFEBLD_opPERCENT_VAL,(l))
+#define ffebld_new_complex(l,r) ffebld_new_two(FFEBLD_opCOMPLEX,(l),(r))
+#define ffebld_new_convert(l) ffebld_new_one(FFEBLD_opCONVERT,(l))
+#define ffebld_new_funcref(l,r) ffebld_new_two(FFEBLD_opFUNCREF,(l),(r))
+#define ffebld_new_subrref(l,r) ffebld_new_two(FFEBLD_opSUBRREF,(l),(r))
+#define ffebld_new_arrayref(l,r) ffebld_new_two(FFEBLD_opARRAYREF,(l),(r))
+#define ffebld_new_substr(l,r) ffebld_new_two(FFEBLD_opSUBSTR,(l),(r))
+#define ffebld_new_impdo(l,r) ffebld_new_two(FFEBLD_opIMPDO,(l),(r))
+#define ffebld_op(b) ((b)->op)
+#define ffebld_pool() (ffebld_pool_stack_.pool)
+#define ffebld_right(b) ((b)->u.nonter.right)
+#define ffebld_set_accter(b,a) ((b)->u.accter.array = (a))
+#define ffebld_set_arrter(b,a) ((b)->u.arrter.array = (a))
+#define ffebld_set_conter(b,c) ((b)->u.conter.expr = (c))
+#define ffebld_set_info(b,i) ((b)->info = (i))
+#define ffebld_set_labter(b,l) ((b)->u.labter = (l))
+#define ffebld_set_op(b,o) ((b)->op = (o))
+#define ffebld_set_head(b,h) ((b)->u.item.head = (h))
+#define ffebld_set_left(b,l) ((b)->u.nonter.left = (l))
+#define ffebld_set_right(b,r) ((b)->u.nonter.right = (r))
+#define ffebld_set_trail(b,t) ((b)->u.item.trail = (t))
+#define ffebld_size(b) (ffeinfo_size((b)->info))
+#define ffebld_size_known(b) ffebld_size(b)
+#define ffebld_symter(b) ((b)->u.symter.symbol)
+#define ffebld_symter_generic(b) ((b)->u.symter.generic)
+#define ffebld_symter_doiter(b) ((b)->u.symter.do_iter)
+#define ffebld_symter_implementation(b) ((b)->u.symter.implementation)
+#define ffebld_symter_specific(b) ((b)->u.symter.specific)
+#define ffebld_symter_set_generic(b,g) ((b)->u.symter.generic = (g))
+#define ffebld_symter_set_implementation(b,i) \
+ ((b)->u.symter.implementation = (i))
+#define ffebld_symter_set_is_doiter(b,f) ((b)->u.symter.do_iter = (f))
+#define ffebld_symter_set_specific(b,s) ((b)->u.symter.specific = (s))
+#define ffebld_terminate_0()
+#define ffebld_terminate_1()
+#define ffebld_terminate_2()
+#define ffebld_terminate_3()
+#define ffebld_terminate_4()
+#define ffebld_trail(b) ((b)->u.item.trail)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/bugs.texi b/contrib/gcc/f/bugs.texi
new file mode 100644
index 0000000..52c9287
--- /dev/null
+++ b/contrib/gcc/f/bugs.texi
@@ -0,0 +1,341 @@
+@c Copyright (C) 1995-1998 Free Software Foundation, Inc.
+@c This is part of the G77 manual.
+@c For copying conditions, see the file g77.texi.
+
+@c The text of this file appears in the file BUGS
+@c in the G77 distribution, as well as in the G77 manual.
+
+@c 1999-03-13
+
+@ifset BUGSONLY
+@set which-g77 @code{egcs}-1.1.2
+@end ifset
+
+@ifclear BUGSONLY
+@node Actual Bugs
+@section Actual Bugs We Haven't Fixed Yet
+@end ifclear
+
+This section identifies bugs that @code{g77} @emph{users}
+might run into in the @value{which-g77} version
+of @code{g77}.
+This includes bugs that are actually in the @code{gcc}
+back end (GBE) or in @code{libf2c}, because those
+sets of code are at least somewhat under the control
+of (and necessarily intertwined with) @code{g77},
+so it isn't worth separating them out.
+
+@ifset last-up-date
+For information on bugs in @emph{other} versions of @code{g77},
+@ref{News,,News About GNU Fortran}.
+@end ifset
+
+@ifset BUGSONLY
+For information on bugs in @emph{other} versions of @code{g77},
+see @file{egcs/gcc/f/NEWS}.
+@end ifset
+
+An online, ``live'' version of this document
+(derived directly from the up-to-date mainline version
+of @code{g77} within @code{egcs})
+is available at
+@uref{http://egcs.cygnus.com/onlinedocs/g77_bugs.html}.
+
+@ifset last-up-date
+For information on bugs that might afflict people who
+configure, port, build, and install @code{g77},
+@ref{Problems Installing}.
+@end ifset
+
+@ifset BUGSONLY
+For information on bugs that might afflict people who
+configure, port, build, and install @code{g77},
+see ``Problems Installing'' in @file{egcs/gcc/f/INSTALL}.
+@end ifset
+
+@itemize @bullet
+@item
+@code{g77} generates bad code for assignments,
+or other conversions,
+of @code{REAL} or @code{COMPLEX} constant expressions
+to type @code{INTEGER(KIND=2)}
+(often referred to as @code{INTEGER*8}).
+
+For example, @samp{INTEGER*8 J; J = 4E10} is miscompiled
+on some systems---the wrong value is stored in @var{J}.
+
+@item
+The @code{IDate} Intrinsic (VXT)
+fails to return the year in the documented, non-Y2K-compliant range
+of 0--99,
+instead returning 100 for the year 2000.
+
+@c Fixed in @code{egcs} 1.2.
+
+@item
+Year 2000 (Y2K) compliance information
+is missing from the documentation.
+
+@c Fixed in @code{egcs} 1.2.
+
+@item
+@code{g77} crashes when compiling
+I/O statements using keywords that define @code{INTEGER} values,
+such as @samp{IOSTAT=@var{j}},
+where @var{j} is other than default @code{INTEGER}
+(such as @code{INTEGER*2}).
+
+@c Fixed in @code{egcs} 1.2.
+
+@item
+The @samp{-ax} option is not obeyed when compiling Fortran programs.
+(It is not passed to the @file{f771} driver.)
+
+@c Fixed in @code{egcs} 1.2.
+
+@item
+@code{g77} fails to warn about a reference to a function
+when the corresponding @emph{subsequent} function program unit
+disagrees with the reference concerning the type of the function.
+
+@c Fixed in @code{egcs} 1.2.
+
+@item
+@c Tim Prince discovered this.
+Automatic arrays possibly aren't working on HP-UX systems,
+at least in HP-UX version 10.20.
+Writing into them apparently causes over-writing
+of statically declared data in the main program.
+This probably means the arrays themselves are being under-allocated,
+or pointers to them being improperly handled,
+e.g. not passed to other procedures as they should be.
+
+@item
+@code{g77} fails to warn about
+use of a ``live'' iterative-DO variable
+as an implied-DO variable
+in a @samp{WRITE} or @samp{PRINT} statement
+(although it does warn about this in a @samp{READ} statement).
+
+@item
+Something about @code{g77}'s straightforward handling of
+label references and definitions sometimes prevents the GBE
+from unrolling loops.
+Until this is solved, try inserting or removing @code{CONTINUE}
+statements as the terminal statement, using the @code{END DO}
+form instead, and so on.
+
+@item
+Some confusion in diagnostics concerning failing @code{INCLUDE}
+statements from within @code{INCLUDE}'d or @code{#include}'d files.
+
+@cindex integer constants
+@cindex constants, integer
+@item
+@code{g77} assumes that @code{INTEGER(KIND=1)} constants range
+from @samp{-2**31} to @samp{2**31-1} (the range for
+two's-complement 32-bit values),
+instead of determining their range from the actual range of the
+type for the configuration (and, someday, for the constant).
+
+Further, it generally doesn't implement the handling
+of constants very well in that it makes assumptions about the
+configuration that it no longer makes regarding variables (types).
+
+Included with this item is the fact that @code{g77} doesn't recognize
+that, on IEEE-754/854-compliant systems, @samp{0./0.} should produce a NaN
+and no warning instead of the value @samp{0.} and a warning.
+This is to be fixed in version 0.6, when @code{g77} will use the
+@code{gcc} back end's constant-handling mechanisms to replace its own.
+
+@cindex compiler speed
+@cindex speed, of compiler
+@cindex compiler memory usage
+@cindex memory usage, of compiler
+@cindex large aggregate areas
+@cindex initialization
+@cindex DATA statement
+@cindex statements, DATA
+@item
+@code{g77} uses way too much memory and CPU time to process large aggregate
+areas having any initialized elements.
+
+For example, @samp{REAL A(1000000)} followed by @samp{DATA A(1)/1/}
+takes up way too much time and space, including
+the size of the generated assembler file.
+This is to be mitigated somewhat in version 0.6.
+
+Version 0.5.18 improves cases like this---specifically,
+cases of @emph{sparse} initialization that leave large, contiguous
+areas uninitialized---significantly.
+However, even with the improvements, these cases still
+require too much memory and CPU time.
+
+(Version 0.5.18 also improves cases where the initial values are
+zero to a much greater degree, so if the above example
+ends with @samp{DATA A(1)/0/}, the compile-time performance
+will be about as good as it will ever get, aside from unrelated
+improvements to the compiler.)
+
+Note that @code{g77} does display a warning message to
+notify the user before the compiler appears to hang.
+@ifset last-up-date
+@xref{Large Initialization,,Initialization of Large Aggregate Areas},
+for information on how to change the point at which
+@code{g77} decides to issue this warning.
+@end ifset
+
+@cindex debugging
+@cindex common blocks
+@cindex equivalence areas
+@cindex local equivalence areas
+@item
+@code{g77} doesn't emit variable and array members of common blocks for use
+with a debugger (the @samp{-g} command-line option).
+The code is present to do this, but doesn't work with at least
+one debug format---perhaps it works with others.
+And it turns out there's a similar bug for
+local equivalence areas, so that has been disabled as well.
+
+As of Version 0.5.19, a temporary kludge solution is provided whereby
+some rudimentary information on a member is written as a string that
+is the member's value as a character string.
+
+@ifset last-up-date
+@xref{Code Gen Options,,Options for Code Generation Conventions},
+for information on the @samp{-fdebug-kludge} option.
+@end ifset
+
+@cindex code, displaying main source
+@cindex displaying main source code
+@cindex debugging main source code
+@cindex printing main source
+@item
+When debugging, after starting up the debugger but before being able
+to see the source code for the main program unit, the user must currently
+set a breakpoint at @samp{MAIN__} (or @samp{MAIN___} or @samp{MAIN_} if
+@samp{MAIN__} doesn't exist)
+and run the program until it hits the breakpoint.
+At that point, the
+main program unit is activated and about to execute its first
+executable statement, but that's the state in which the debugger should
+start up, as is the case for languages like C.
+
+@cindex debugger
+@item
+Debugging @code{g77}-compiled code using debuggers other than
+@code{gdb} is likely not to work.
+
+Getting @code{g77} and @code{gdb} to work together is a known
+problem---getting @code{g77} to work properly with other
+debuggers, for which source code often is unavailable to @code{g77}
+developers, seems like a much larger, unknown problem,
+and is a lower priority than making @code{g77} and @code{gdb}
+work together properly.
+
+On the other hand, information about problems other debuggers
+have with @code{g77} output might make it easier to properly
+fix @code{g77}, and perhaps even improve @code{gdb}, so it
+is definitely welcome.
+Such information might even lead to all relevant products
+working together properly sooner.
+
+@cindex Alpha, support
+@cindex support, Alpha
+@item
+@code{g77} doesn't work perfectly on 64-bit configurations
+such as the Digital Semiconductor (``DEC'') Alpha.
+
+This problem is largely resolved as of version 0.5.23.
+Version 0.6 should solve most or all remaining problems
+(such as cross-compiling involving 64-bit machines).
+
+@cindex COMPLEX support
+@cindex support, COMPLEX
+@item
+Maintainers of gcc report that the back end definitely has ``broken''
+support for @code{COMPLEX} types.
+Based on their input, it seems many of
+the problems affect only the more-general facilities for gcc's
+@code{__complex__} type, such as @code{__complex__ int}
+(where the real and imaginary parts are integers) that GNU
+Fortran does not use.
+
+Version 0.5.20 of @code{g77} works around this
+problem by not using the back end's support for @code{COMPLEX}.
+The new option @samp{-fno-emulate-complex} avoids the work-around,
+reverting to using the same ``broken'' mechanism as that used
+by versions of @code{g77} prior to 0.5.20.
+
+@cindex padding
+@cindex structures
+@cindex common blocks
+@cindex equivalence areas
+@item
+@code{g77} currently inserts needless padding for things like
+@samp{COMMON A,IPAD} where @samp{A} is @code{CHARACTER*1} and @samp{IPAD}
+is @code{INTEGER(KIND=1)} on machines like x86,
+because the back end insists that @samp{IPAD}
+be aligned to a 4-byte boundary,
+but the processor has no such requirement
+(though it is usually good for performance).
+
+The @code{gcc} back end needs to provide a wider array
+of specifications of alignment requirements and preferences for targets,
+and front ends like @code{g77} should take advantage of this
+when it becomes available.
+
+@cindex alignment
+@cindex double-precision performance
+@cindex -malign-double
+@item
+The x86 target's @samp{-malign-double} option
+no longer reliably aligns double-precision variables and arrays
+when they are placed in the stack frame.
+
+This can significantly reduce the performance of some applications,
+even on a run-to-run basis
+(that is, performance measurements can vary fairly widely
+depending on whether frequently used variables are properly aligned,
+and that can change from one program run to the next,
+even from one procedure call to the next).
+
+Versions 0.5.22 and earlier of @code{g77}
+included a patch to @code{gcc} that enabled this,
+but that patch has been deemed an improper (probably buggy) one
+for version 2.8 of @code{gcc} and for @code{egcs}.
+
+Note that version 1.1 of @code{egcs}
+aligns double-precision variables and arrays
+when they are in static storage
+even if @samp{-malign-double} is not specified.
+
+There is ongoing investigation into
+how to make @samp{-malign-double} work properly,
+also into how to make it unnecessary to get
+all double-precision variables and arrays aligned
+when such alignment would not violate
+the relevant specifications for processor
+and inter-procedural interfaces.
+
+For a suite of programs to test double-precision alignment,
+see @uref{ftp://alpha.gnu.org/gnu/g77/align/}.
+
+@cindex complex performance
+@cindex aliasing
+@item
+The @code{libf2c} routines that perform some run-time
+arithmetic on @code{COMPLEX} operands
+were modified circa version 0.5.20 of @code{g77}
+to work properly even in the presence of aliased operands.
+
+While the @code{g77} and @code{netlib} versions of @code{libf2c}
+differ on how this is accomplished,
+the main differences are that we believe
+the @code{g77} version works properly
+even in the presence of @emph{partially} aliased operands.
+
+However, these modifications have reduced performance
+on targets such as x86,
+due to the extra copies of operands involved.
+@end itemize
diff --git a/contrib/gcc/f/bugs0.texi b/contrib/gcc/f/bugs0.texi
new file mode 100644
index 0000000..e8f6d22
--- /dev/null
+++ b/contrib/gcc/f/bugs0.texi
@@ -0,0 +1,17 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename BUGS
+@set BUGSONLY
+@c %**end of header
+
+@c The immediately following lines apply to the BUGS file
+@c which is generated using this file.
+This file lists known bugs in the GNU Fortran compiler.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+You may copy, distribute, and modify it freely as long as you preserve
+this copyright notice and permission notice.
+
+@node Top,,, (dir)
+@chapter Bugs in GNU Fortran
+@include bugs.texi
+@bye
diff --git a/contrib/gcc/f/com-rt.def b/contrib/gcc/f/com-rt.def
new file mode 100644
index 0000000..6ceaf17
--- /dev/null
+++ b/contrib/gcc/f/com-rt.def
@@ -0,0 +1,282 @@
+/* com-rt.def -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ com.c
+
+ Modifications:
+*/
+
+/* DEFGFRT(CODE,NAME,TYPE,VOLATILE,COMPLEX):
+
+ CODE -- the #define name to use to refer to the function in g77 code
+
+ NAME -- the name as seen by the back end and, with whatever massaging
+ is normal, the linker
+
+ TYPE -- a code for the tree for the type, assigned when first encountered
+ (NOTE: There's a distinction made between the semantic return
+ value for the function, and the actual return mechanism; e.g.
+ `r_abs()' computes a single-precision `float' return value
+ but returns it as a `double'. This distinction is important
+ and is flagged via the _F2C_ versus _GNU_ suffix.)
+
+ ARGS -- a string of codes representing the types of the arguments; the
+ last type specifies the type for that and all following args,
+ and the null pointer (0) means the same as "0":
+
+ 0 Not applicable at and beyond this point
+ & Pointer to type that follows
+ a char
+ c complex
+ d doublereal
+ e doublecomplex
+ f real
+ i integer
+ j longint
+
+ VOLATILE -- TRUE if the function never returns (gen's emit_barrier in
+ g77 back end)
+
+ COMPLEX -- TRUE if the return value is COMPLEX or DOUBLE COMPLEX and
+ thus might need to be returned as ptr-to-1st-arg
+
+*/
+
+DEFGFRT (FFECOM_gfrtCAT, "s_cat", FFECOM_rttypeVOID_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtCMP, "s_cmp", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtCOPY, "s_copy", FFECOM_rttypeVOID_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtPAUSE, "s_paus", FFECOM_rttypeVOID_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSTOP, "s_stop", FFECOM_rttypeVOID_, 0, TRUE, FALSE)
+
+DEFGFRT (FFECOM_gfrtSRDUE, "s_rdue", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtERDUE, "e_rdue", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSRSUE, "s_rsue", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtERSUE, "e_rsue", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSRDFE, "s_rdfe", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtERDFE, "e_rdfe", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSRSFI, "s_rsfi", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtERSFI, "e_rsfi", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSRSFE, "s_rsfe", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtERSFE, "e_rsfe", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSRSLI, "s_rsli", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtERSLI, "e_rsli", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSRSLE, "s_rsle", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtERSLE, "e_rsle", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSRSNE, "s_rsne", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+
+DEFGFRT (FFECOM_gfrtSWDUE, "s_wdue", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtEWDUE, "e_wdue", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSWSUE, "s_wsue", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtEWSUE, "e_wsue", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSWDFE, "s_wdfe", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtEWDFE, "e_wdfe", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSWSFI, "s_wsfi", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtEWSFI, "e_wsfi", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSWSFE, "s_wsfe", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtEWSFE, "e_wsfe", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSWSLI, "s_wsli", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtEWSLI, "e_wsli", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSWSLE, "s_wsle", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtEWSLE, "e_wsle", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSWSNE, "s_wsne", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+
+DEFGFRT (FFECOM_gfrtDOFIO, "do_fio", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDOLIO, "do_lio", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDOUIO, "do_uio", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+
+DEFGFRT (FFECOM_gfrtFOPEN, "f_open", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFCLOS, "f_clos", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFINQU, "f_inqu", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+
+DEFGFRT (FFECOM_gfrtFBACK, "f_back", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFEND, "f_end", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFREW, "f_rew", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+
+DEFGFRT (FFECOM_gfrtABORT, "G77_abort_0", FFECOM_rttypeVOID_, 0, TRUE, FALSE)
+DEFGFRT (FFECOM_gfrtABS, "r_abs", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtACCESS, "G77_access_0", FFECOM_rttypeINTEGER_, "&a&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtACOS, "r_acos", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtAIMAG, "r_imag", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtAINT, "r_int", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtALARM, "G77_alarm_0", FFECOM_rttypeINTEGER_, "&i0", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtALOG, "r_log", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtALOG10, "r_lg10", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtAMOD, "r_mod", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtANINT, "r_nint", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtASIN, "r_asin", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtATAN, "r_atan", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtATAN2, "r_atn2", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtCABS, "c_abs", FFECOM_rttypeREAL_F2C_, "&c", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtCCOS, "c_cos", FFECOM_rttypeCOMPLEX_F2C_, "&c", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtCEXP, "c_exp", FFECOM_rttypeCOMPLEX_F2C_, "&c", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtCHDIR, "G77_chdir_0", FFECOM_rttypeINTEGER_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtCLOG, "c_log", FFECOM_rttypeCOMPLEX_F2C_, "&c", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtCHMOD, "G77_chmod_0", FFECOM_rttypeINTEGER_, "&a&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtCONJG, "r_cnjg", FFECOM_rttypeCOMPLEX_F2C_, "&c", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtCOS, "r_cos", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtCOSH, "r_cosh", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtCSIN, "c_sin", FFECOM_rttypeCOMPLEX_F2C_, "&c", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtCSQRT, "c_sqrt", FFECOM_rttypeCOMPLEX_F2C_, "&c", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtCTIME, "G77_ctime_0", FFECOM_rttypeCHARACTER_, "&j", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDABS, "d_abs", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDACOS, "d_acos", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDASIN, "d_asin", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDATAN, "d_atan", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDATAN2, "d_atn2", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDATE, "G77_date_0", FFECOM_rttypeVOID_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDATE_AND_TIME, "G77_date_and_time_0", FFECOM_rttypeVOID_, "&a&a&a&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_BESJ0, "j0", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_BESJ1, "j1", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_BESJN, "jn", FFECOM_rttypeDOUBLE_, "id", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_BESY0, "y0", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_BESY1, "y1", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_BESYN, "yn", FFECOM_rttypeDOUBLE_, "id", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDCOS, "d_cos", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDCOSH, "d_cosh", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDDIM, "d_dim", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDERF, "G77_derf_0", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDERFC, "G77_derfc_0", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDEXP, "d_exp", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDIM, "r_dim", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDINT, "d_int", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDLOG, "d_log", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDLOG10, "d_lg10", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDMOD, "d_mod", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDNINT, "d_nint", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDPROD, "d_prod", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDSIGN, "d_sign", FFECOM_rttypeDOUBLE_, "&d&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDSIN, "d_sin", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDSINH, "d_sinh", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDSQRT, "d_sqrt", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDTAN, "d_tan", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDTANH, "d_tanh", FFECOM_rttypeDOUBLE_, "&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtDTIME, "G77_dtime_0", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtERF, "G77_erf_0", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtERFC, "G77_erfc_0", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtETIME, "G77_etime_0", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtEXIT, "G77_exit_0", FFECOM_rttypeVOID_, "&i", TRUE, FALSE)
+DEFGFRT (FFECOM_gfrtEXP, "r_exp", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFDATE, "G77_fdate_0", FFECOM_rttypeCHARACTER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFGET, "G77_fget_0", FFECOM_rttypeINTEGER_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFGETC, "G77_fgetc_0", FFECOM_rttypeINTEGER_, "&i&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFLUSH, "G77_flush_0", FFECOM_rttypeVOID_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFLUSH1, "G77_flush1_0", FFECOM_rttypeVOID_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFNUM, "G77_fnum_0", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFPUT, "G77_fput_0", FFECOM_rttypeINTEGER_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFPUTC, "G77_fputc_0", FFECOM_rttypeINTEGER_, "&i&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFSTAT, "G77_fstat_0", FFECOM_rttypeINTEGER_, "&i&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFTELL, "G77_ftell_0", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtFSEEK, "G77_fseek_0", FFECOM_rttypeINTEGER_, "&i&i&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtGERROR, "G77_gerror_0", FFECOM_rttypeVOID_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtGETARG, "G77_getarg_0", FFECOM_rttypeVOID_, "&i&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtGETCWD, "G77_getcwd_0", FFECOM_rttypeINTEGER_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtGETGID, "G77_getgid_0", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtGETLOG, "G77_getlog_0", FFECOM_rttypeVOID_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtGETPID, "G77_getpid_0", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtGETUID, "G77_getuid_0", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtGETENV, "G77_getenv_0", FFECOM_rttypeVOID_, "&a&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtGMTIME, "G77_gmtime_0", FFECOM_rttypeVOID_, "&i&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtHOSTNM, "G77_hostnm_0", FFECOM_rttypeINTEGER_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtIABS, "i_abs", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtIARGC, "G77_iargc_0", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtIDATE, "G77_idate_0", FFECOM_rttypeVOID_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtIDIM, "i_dim", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtIDNINT, "i_dnnt", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtIERRNO, "G77_ierrno_0", FFECOM_rttypeINTEGER_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtINDEX, "i_indx", FFECOM_rttypeINTEGER_, "&a&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtIRAND, "G77_irand_0", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtISIGN, "i_sign", FFECOM_rttypeINTEGER_, "&i&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtISATTY, "G77_isatty_0", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtITIME, "G77_itime_0", FFECOM_rttypeVOID_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtKILL, "G77_kill_0", FFECOM_rttypeINTEGER_, "&i&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtLEN, "i_len", FFECOM_rttypeINTEGER_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtLGE, "l_ge", FFECOM_rttypeLOGICAL_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtLGT, "l_gt", FFECOM_rttypeLOGICAL_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtLINK, "G77_link_0", FFECOM_rttypeINTEGER_, "&a&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtLLE, "l_le", FFECOM_rttypeLOGICAL_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtLLT, "l_lt", FFECOM_rttypeLOGICAL_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtLNBLNK, "G77_lnblnk_0", FFECOM_rttypeINTEGER_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtLSTAT, "G77_lstat_0", FFECOM_rttypeINTEGER_, "&a&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtLTIME, "G77_ltime_0", FFECOM_rttypeVOID_, "&i&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtMCLOCK, "G77_mclock_0", FFECOM_rttypeLONGINT_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtMOD, "i_mod", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtNINT, "i_nint", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtPERROR, "G77_perror_0", FFECOM_rttypeVOID_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtRAND, "G77_rand_0", FFECOM_rttypeREAL_F2C_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtRENAME, "G77_rename_0", FFECOM_rttypeINTEGER_, "&a&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSECNDS, "G77_secnds_0", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSECOND, "G77_second_0", FFECOM_rttypeREAL_F2C_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSIGN, "r_sign", FFECOM_rttypeREAL_F2C_, "&f&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_SIGNAL, "G77_signal_0", FFECOM_rttypeVOIDSTAR_, "&i0", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSIN, "r_sin", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSINH, "r_sinh", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSLEEP, "G77_sleep_0", FFECOM_rttypeVOID_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSQRT, "r_sqrt", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSRAND, "G77_srand_0", FFECOM_rttypeVOID_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSTAT, "G77_stat_0", FFECOM_rttypeINTEGER_, "&a&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSYMLNK, "G77_symlnk_0", FFECOM_rttypeINTEGER_, "&a&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSYSTEM, "G77_system_0", FFECOM_rttypeINTEGER_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtSYSTEM_CLOCK, "G77_system_clock_0", FFECOM_rttypeVOID_, "&i&i&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtTAN, "r_tan", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtTANH, "r_tanh", FFECOM_rttypeREAL_F2C_, "&f", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtTIME, "G77_time_0", FFECOM_rttypeLONGINT_, 0, FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtTTYNAM, "G77_ttynam_0", FFECOM_rttypeCHARACTER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtUNLINK, "G77_unlink_0", FFECOM_rttypeINTEGER_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtUMASK, "G77_umask_0", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtVXTIDATE, "G77_vxtidate_0", FFECOM_rttypeVOID_, "&i&i&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtVXTTIME, "G77_vxttime_0", FFECOM_rttypeVOID_, "&a", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtCDABS, "z_abs", FFECOM_rttypeDOUBLE_, "&e", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtCDCOS, "z_cos", FFECOM_rttypeDBLCMPLX_F2C_, "&e", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtCDEXP, "z_exp", FFECOM_rttypeDBLCMPLX_F2C_, "&e", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtCDLOG, "z_log", FFECOM_rttypeDBLCMPLX_F2C_, "&e", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtDCONJG, "d_cnjg", FFECOM_rttypeDBLCMPLX_F2C_, "&e", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtCDSIN, "z_sin", FFECOM_rttypeDBLCMPLX_F2C_, "&e", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtCDSQRT, "z_sqrt", FFECOM_rttypeDBLCMPLX_F2C_, "&e", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtDIMAG, "d_imag", FFECOM_rttypeDOUBLE_, "&e", FALSE, FALSE)
+
+DEFGFRT (FFECOM_gfrtL_ACOS, "acos", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_ASIN, "asin", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_ATAN, "atan", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_ATAN2, "atan2", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_COS, "__builtin_cos", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_COSH, "cosh", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_ERF, "erf", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_ERFC, "erfc", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_EXP, "exp", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_FLOOR, "floor", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_LOG, "log", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_SIN, "__builtin_sin", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_SINH, "sinh", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_SQRT, "__builtin_fsqrt", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_TAN, "tan", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtL_TANH, "tanh", FFECOM_rttypeDOUBLE_, "d", FALSE, FALSE)
+
+DEFGFRT (FFECOM_gfrtPOW_CI, "pow_ci", FFECOM_rttypeCOMPLEX_F2C_, "&c&i", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtPOW_DD, "pow_dd", FFECOM_rttypeDOUBLE_, "&d&d", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtPOW_DI, "pow_di", FFECOM_rttypeDOUBLE_, "&d&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtPOW_II, "pow_ii", FFECOM_rttypeINTEGER_, "&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtPOW_QQ, "pow_qq", FFECOM_rttypeLONGINT_, "&j&j", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtPOW_RI, "pow_ri", FFECOM_rttypeREAL_F2C_, "&f&i", FALSE, FALSE)
+DEFGFRT (FFECOM_gfrtPOW_ZI, "pow_zi", FFECOM_rttypeDBLCMPLX_F2C_, "&e&i", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtPOW_ZZ, "pow_zz", FFECOM_rttypeDBLCMPLX_F2C_, "&e&e", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtDIV_CC, "c_div", FFECOM_rttypeCOMPLEX_F2C_, "&c", FALSE, TRUE)
+DEFGFRT (FFECOM_gfrtDIV_ZZ, "z_div", FFECOM_rttypeDBLCMPLX_F2C_, "&e", FALSE, TRUE)
diff --git a/contrib/gcc/f/com.c b/contrib/gcc/f/com.c
new file mode 100644
index 0000000..9db1f84
--- /dev/null
+++ b/contrib/gcc/f/com.c
@@ -0,0 +1,16510 @@
+/* com.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995-1998 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Contains compiler-specific functions.
+
+ Modifications:
+*/
+
+/* Understanding this module means understanding the interface between
+ the g77 front end and the gcc back end (or, perhaps, some other
+ back end). In here are the functions called by the front end proper
+ to notify whatever back end is in place about certain things, and
+ also the back-end-specific functions. It's a bear to deal with, so
+ lately I've been trying to simplify things, especially with regard
+ to the gcc-back-end-specific stuff.
+
+ Building expressions generally seems quite easy, but building decls
+ has been challenging and is undergoing revision. gcc has several
+ kinds of decls:
+
+ TYPE_DECL -- a type (int, float, struct, function, etc.)
+ CONST_DECL -- a constant of some type other than function
+ LABEL_DECL -- a variable or a constant?
+ PARM_DECL -- an argument to a function (a variable that is a dummy)
+ RESULT_DECL -- the return value of a function (a variable)
+ VAR_DECL -- other variable (can hold a ptr-to-function, struct, int, etc.)
+ FUNCTION_DECL -- a function (either the actual function or an extern ref)
+ FIELD_DECL -- a field in a struct or union (goes into types)
+
+ g77 has a set of functions that somewhat parallels the gcc front end
+ when it comes to building decls:
+
+ Internal Function (one we define, not just declare as extern):
+ int yes;
+ yes = suspend_momentary ();
+ if (is_nested) push_f_function_context ();
+ start_function (get_identifier ("function_name"), function_type,
+ is_nested, is_public);
+ // for each arg, build PARM_DECL and call push_parm_decl (decl) with it;
+ store_parm_decls (is_main_program);
+ ffecom_start_compstmt_ ();
+ // for stmts and decls inside function, do appropriate things;
+ ffecom_end_compstmt_ ();
+ finish_function (is_nested);
+ if (is_nested) pop_f_function_context ();
+ if (is_nested) resume_momentary (yes);
+
+ Everything Else:
+ int yes;
+ tree d;
+ tree init;
+ yes = suspend_momentary ();
+ // fill in external, public, static, &c for decl, and
+ // set DECL_INITIAL to error_mark_node if going to initialize
+ // set is_top_level TRUE only if not at top level and decl
+ // must go in top level (i.e. not within current function decl context)
+ d = start_decl (decl, is_top_level);
+ init = ...; // if have initializer
+ finish_decl (d, init, is_top_level);
+ resume_momentary (yes);
+
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#include "flags.j"
+#include "rtl.j"
+#include "toplev.j"
+#include "tree.j"
+#include "output.j" /* Must follow tree.j so TREE_CODE is defined! */
+#include "convert.j"
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+#define FFECOM_GCC_INCLUDE 1 /* Enable -I. */
+
+/* BEGIN stuff from gcc/cccp.c. */
+
+/* The following symbols should be autoconfigured:
+ HAVE_FCNTL_H
+ HAVE_STDLIB_H
+ HAVE_SYS_TIME_H
+ HAVE_UNISTD_H
+ STDC_HEADERS
+ TIME_WITH_SYS_TIME
+ In the mean time, we'll get by with approximations based
+ on existing GCC configuration symbols. */
+
+#ifdef POSIX
+# ifndef HAVE_STDLIB_H
+# define HAVE_STDLIB_H 1
+# endif
+# ifndef HAVE_UNISTD_H
+# define HAVE_UNISTD_H 1
+# endif
+# ifndef STDC_HEADERS
+# define STDC_HEADERS 1
+# endif
+#endif /* defined (POSIX) */
+
+#if defined (POSIX) || (defined (USG) && !defined (VMS))
+# ifndef HAVE_FCNTL_H
+# define HAVE_FCNTL_H 1
+# endif
+#endif
+
+#ifndef RLIMIT_STACK
+# include <time.h>
+#else
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+# include <sys/resource.h>
+#endif
+
+#if HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+
+/* This defines "errno" properly for VMS, and gives us EACCES. */
+#include <errno.h>
+
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#else
+char *getenv ();
+#endif
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* VMS-specific definitions */
+#ifdef VMS
+#include <descrip.h>
+#define O_RDONLY 0 /* Open arg for Read/Only */
+#define O_WRONLY 1 /* Open arg for Write/Only */
+#define read(fd,buf,size) VMS_read (fd,buf,size)
+#define write(fd,buf,size) VMS_write (fd,buf,size)
+#define open(fname,mode,prot) VMS_open (fname,mode,prot)
+#define fopen(fname,mode) VMS_fopen (fname,mode)
+#define freopen(fname,mode,ofile) VMS_freopen (fname,mode,ofile)
+#define strncat(dst,src,cnt) VMS_strncat (dst,src,cnt)
+#define fstat(fd,stbuf) VMS_fstat (fd,stbuf)
+static int VMS_fstat (), VMS_stat ();
+static char * VMS_strncat ();
+static int VMS_read ();
+static int VMS_write ();
+static int VMS_open ();
+static FILE * VMS_fopen ();
+static FILE * VMS_freopen ();
+static void hack_vms_include_specification ();
+typedef struct { unsigned :16, :16, :16; } vms_ino_t;
+#define ino_t vms_ino_t
+#define INCLUDE_LEN_FUDGE 10 /* leave room for VMS syntax conversion */
+#ifdef __GNUC__
+#define BSTRING /* VMS/GCC supplies the bstring routines */
+#endif /* __GNUC__ */
+#endif /* VMS */
+
+#ifndef O_RDONLY
+#define O_RDONLY 0
+#endif
+
+/* END stuff from gcc/cccp.c. */
+
+#define FFECOM_DETERMINE_TYPES 1 /* for com.h */
+#include "com.h"
+#include "bad.h"
+#include "bld.h"
+#include "equiv.h"
+#include "expr.h"
+#include "implic.h"
+#include "info.h"
+#include "malloc.h"
+#include "src.h"
+#include "st.h"
+#include "storag.h"
+#include "symbol.h"
+#include "target.h"
+#include "top.h"
+#include "type.h"
+
+/* Externals defined here. */
+
+#define FFECOM_FASTER_ARRAY_REFS 0 /* Generates faster code? */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+
+/* tree.h declares a bunch of stuff that it expects the front end to
+ define. Here are the definitions, which in the C front end are
+ found in the file c-decl.c. */
+
+tree integer_zero_node;
+tree integer_one_node;
+tree null_pointer_node;
+tree error_mark_node;
+tree void_type_node;
+tree integer_type_node;
+tree unsigned_type_node;
+tree char_type_node;
+tree current_function_decl;
+
+/* ~~tree.h SHOULD declare this, because toplev.c and dwarfout.c reference
+ it. */
+
+char *language_string = "GNU F77";
+
+/* Stream for reading from the input file. */
+FILE *finput;
+
+/* These definitions parallel those in c-decl.c so that code from that
+ module can be used pretty much as is. Much of these defs aren't
+ otherwise used, i.e. by g77 code per se, except some of them are used
+ to build some of them that are. The ones that are global (i.e. not
+ "static") are those that ste.c and such might use (directly
+ or by using com macros that reference them in their definitions). */
+
+static tree short_integer_type_node;
+tree long_integer_type_node;
+static tree long_long_integer_type_node;
+
+static tree short_unsigned_type_node;
+static tree long_unsigned_type_node;
+static tree long_long_unsigned_type_node;
+
+static tree unsigned_char_type_node;
+static tree signed_char_type_node;
+
+static tree float_type_node;
+static tree double_type_node;
+static tree complex_float_type_node;
+tree complex_double_type_node;
+static tree long_double_type_node;
+static tree complex_integer_type_node;
+static tree complex_long_double_type_node;
+
+tree string_type_node;
+
+static tree double_ftype_double;
+static tree float_ftype_float;
+static tree ldouble_ftype_ldouble;
+
+/* The rest of these are inventions for g77, though there might be
+ similar things in the C front end. As they are found, these
+ inventions should be renamed to be canonical. Note that only
+ the ones currently required to be global are so. */
+
+static tree ffecom_tree_fun_type_void;
+static tree ffecom_tree_ptr_to_fun_type_void;
+
+tree ffecom_integer_type_node; /* Abbrev for _tree_type[blah][blah]. */
+tree ffecom_integer_zero_node; /* Like *_*_* with g77's integer type. */
+tree ffecom_integer_one_node; /* " */
+tree ffecom_tree_type[FFEINFO_basictype][FFEINFO_kindtype];
+
+/* _fun_type things are the f2c-specific versions. For -fno-f2c,
+ just use build_function_type and build_pointer_type on the
+ appropriate _tree_type array element. */
+
+static tree ffecom_tree_fun_type[FFEINFO_basictype][FFEINFO_kindtype];
+static tree ffecom_tree_ptr_to_fun_type[FFEINFO_basictype][FFEINFO_kindtype];
+static tree ffecom_tree_subr_type;
+static tree ffecom_tree_ptr_to_subr_type;
+static tree ffecom_tree_blockdata_type;
+
+static tree ffecom_tree_xargc_;
+
+ffecomSymbol ffecom_symbol_null_
+=
+{
+ NULL_TREE,
+ NULL_TREE,
+ NULL_TREE,
+};
+ffeinfoKindtype ffecom_pointer_kind_ = FFEINFO_basictypeNONE;
+ffeinfoKindtype ffecom_label_kind_ = FFEINFO_basictypeNONE;
+
+int ffecom_f2c_typecode_[FFEINFO_basictype][FFEINFO_kindtype];
+tree ffecom_f2c_integer_type_node;
+tree ffecom_f2c_ptr_to_integer_type_node;
+tree ffecom_f2c_address_type_node;
+tree ffecom_f2c_real_type_node;
+tree ffecom_f2c_ptr_to_real_type_node;
+tree ffecom_f2c_doublereal_type_node;
+tree ffecom_f2c_complex_type_node;
+tree ffecom_f2c_doublecomplex_type_node;
+tree ffecom_f2c_longint_type_node;
+tree ffecom_f2c_logical_type_node;
+tree ffecom_f2c_flag_type_node;
+tree ffecom_f2c_ftnlen_type_node;
+tree ffecom_f2c_ftnlen_zero_node;
+tree ffecom_f2c_ftnlen_one_node;
+tree ffecom_f2c_ftnlen_two_node;
+tree ffecom_f2c_ptr_to_ftnlen_type_node;
+tree ffecom_f2c_ftnint_type_node;
+tree ffecom_f2c_ptr_to_ftnint_type_node;
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+/* Simple definitions and enumerations. */
+
+#ifndef FFECOM_sizeMAXSTACKITEM
+#define FFECOM_sizeMAXSTACKITEM 32*1024 /* Keep user-declared things
+ larger than this # bytes
+ off stack if possible. */
+#endif
+
+/* For systems that have large enough stacks, they should define
+ this to 0, and here, for ease of use later on, we just undefine
+ it if it is 0. */
+
+#if FFECOM_sizeMAXSTACKITEM == 0
+#undef FFECOM_sizeMAXSTACKITEM
+#endif
+
+typedef enum
+ {
+ FFECOM_rttypeVOID_,
+ FFECOM_rttypeVOIDSTAR_, /* C's `void *' type. */
+ FFECOM_rttypeFTNINT_, /* f2c's `ftnint' type. */
+ FFECOM_rttypeINTEGER_, /* f2c's `integer' type. */
+ FFECOM_rttypeLONGINT_, /* f2c's `longint' type. */
+ FFECOM_rttypeLOGICAL_, /* f2c's `logical' type. */
+ FFECOM_rttypeREAL_F2C_, /* f2c's `real' returned as `double'. */
+ FFECOM_rttypeREAL_GNU_, /* `real' returned as such. */
+ FFECOM_rttypeCOMPLEX_F2C_, /* f2c's `complex' returned via 1st arg. */
+ FFECOM_rttypeCOMPLEX_GNU_, /* f2c's `complex' returned directly. */
+ FFECOM_rttypeDOUBLE_, /* C's `double' type. */
+ FFECOM_rttypeDOUBLEREAL_, /* f2c's `doublereal' type. */
+ FFECOM_rttypeDBLCMPLX_F2C_, /* f2c's `doublecomplex' returned via 1st arg. */
+ FFECOM_rttypeDBLCMPLX_GNU_, /* f2c's `doublecomplex' returned directly. */
+ FFECOM_rttypeCHARACTER_, /* f2c `char *'/`ftnlen' pair. */
+ FFECOM_rttype_
+ } ffecomRttype_;
+
+/* Internal typedefs. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+typedef struct _ffecom_concat_list_ ffecomConcatList_;
+typedef struct _ffecom_temp_ *ffecomTemp_;
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+struct _ffecom_concat_list_
+ {
+ ffebld *exprs;
+ int count;
+ int max;
+ ffetargetCharacterSize minlen;
+ ffetargetCharacterSize maxlen;
+ };
+
+struct _ffecom_temp_
+ {
+ ffecomTemp_ next;
+ tree type; /* Base type (w/o size/array applied). */
+ tree t;
+ ffetargetCharacterSize size;
+ int elements;
+ bool in_use;
+ bool auto_pop;
+ };
+
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+/* Static functions (internal). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree ffecom_arglist_expr_ (char *argstring, ffebld args);
+static tree ffecom_widest_expr_type_ (ffebld list);
+static bool ffecom_overlap_ (tree dest_decl, tree dest_offset,
+ tree dest_size, tree source_tree,
+ ffebld source, bool scalar_arg);
+static bool ffecom_args_overlapping_ (tree dest_tree, ffebld dest,
+ tree args, tree callee_commons,
+ bool scalar_args);
+static tree ffecom_build_f2c_string_ (int i, char *s);
+static tree ffecom_call_ (tree fn, ffeinfoKindtype kt,
+ bool is_f2c_complex, tree type,
+ tree args, tree dest_tree,
+ ffebld dest, bool *dest_used,
+ tree callee_commons, bool scalar_args);
+static tree ffecom_call_binop_ (tree fn, ffeinfoKindtype kt,
+ bool is_f2c_complex, tree type,
+ ffebld left, ffebld right,
+ tree dest_tree, ffebld dest,
+ bool *dest_used, tree callee_commons,
+ bool scalar_args);
+static void ffecom_char_args_x_ (tree *xitem, tree *length,
+ ffebld expr, bool with_null);
+static tree ffecom_check_size_overflow_ (ffesymbol s, tree type, bool dummy);
+static tree ffecom_char_enhance_arg_ (tree *xtype, ffesymbol s);
+static ffecomConcatList_
+ ffecom_concat_list_gather_ (ffecomConcatList_ catlist,
+ ffebld expr,
+ ffetargetCharacterSize max);
+static void ffecom_concat_list_kill_ (ffecomConcatList_ catlist);
+static ffecomConcatList_ ffecom_concat_list_new_ (ffebld expr,
+ ffetargetCharacterSize max);
+static void ffecom_debug_kludge_ (tree aggr, char *aggr_type, ffesymbol member,
+ tree member_type, ffetargetOffset offset);
+static void ffecom_do_entry_ (ffesymbol fn, int entrynum);
+static tree ffecom_expr_ (ffebld expr, tree dest_tree, ffebld dest,
+ bool *dest_used, bool assignp, bool widenp);
+static tree ffecom_expr_intrinsic_ (ffebld expr, tree dest_tree,
+ ffebld dest, bool *dest_used);
+static tree ffecom_expr_power_integer_ (ffebld left, ffebld right);
+static void ffecom_expr_transform_ (ffebld expr);
+static void ffecom_f2c_make_type_ (tree *type, int tcode, char *name);
+static void ffecom_f2c_set_lio_code_ (ffeinfoBasictype bt, int size,
+ int code);
+static ffeglobal ffecom_finish_global_ (ffeglobal global);
+static ffesymbol ffecom_finish_symbol_transform_ (ffesymbol s);
+static tree ffecom_get_appended_identifier_ (char us, char *text);
+static tree ffecom_get_external_identifier_ (ffesymbol s);
+static tree ffecom_get_identifier_ (char *text);
+static tree ffecom_gen_sfuncdef_ (ffesymbol s,
+ ffeinfoBasictype bt,
+ ffeinfoKindtype kt);
+static char *ffecom_gfrt_args_ (ffecomGfrt ix);
+static tree ffecom_gfrt_tree_ (ffecomGfrt ix);
+static tree ffecom_init_zero_ (tree decl);
+static tree ffecom_intrinsic_ichar_ (tree tree_type, ffebld arg,
+ tree *maybe_tree);
+static tree ffecom_intrinsic_len_ (ffebld expr);
+static void ffecom_let_char_ (tree dest_tree,
+ tree dest_length,
+ ffetargetCharacterSize dest_size,
+ ffebld source);
+static void ffecom_make_gfrt_ (ffecomGfrt ix);
+static void ffecom_member_phase1_ (ffestorag mst, ffestorag st);
+#ifdef SOMEONE_GETS_DEBUG_SUPPORT_WORKING
+static void ffecom_member_phase2_ (ffestorag mst, ffestorag st);
+#endif
+static void ffecom_push_dummy_decls_ (ffebld dumlist,
+ bool stmtfunc);
+static void ffecom_start_progunit_ (void);
+static ffesymbol ffecom_sym_transform_ (ffesymbol s);
+static ffesymbol ffecom_sym_transform_assign_ (ffesymbol s);
+static void ffecom_transform_common_ (ffesymbol s);
+static void ffecom_transform_equiv_ (ffestorag st);
+static tree ffecom_transform_namelist_ (ffesymbol s);
+static void ffecom_tree_canonize_ptr_ (tree *decl, tree *offset,
+ tree t);
+static void ffecom_tree_canonize_ref_ (tree *decl, tree *offset,
+ tree *size, tree tree);
+static tree ffecom_tree_divide_ (tree tree_type, tree left, tree right,
+ tree dest_tree, ffebld dest,
+ bool *dest_used);
+static tree ffecom_type_localvar_ (ffesymbol s,
+ ffeinfoBasictype bt,
+ ffeinfoKindtype kt);
+static tree ffecom_type_namelist_ (void);
+#if 0
+static tree ffecom_type_permanent_copy_ (tree t);
+#endif
+static tree ffecom_type_vardesc_ (void);
+static tree ffecom_vardesc_ (ffebld expr);
+static tree ffecom_vardesc_array_ (ffesymbol s);
+static tree ffecom_vardesc_dims_ (ffesymbol s);
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+/* These are static functions that parallel those found in the C front
+ end and thus have the same names. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void bison_rule_compstmt_ (void);
+static void bison_rule_pushlevel_ (void);
+static tree builtin_function (char *name, tree type,
+ enum built_in_function function_code,
+ char *library_name);
+static int duplicate_decls (tree newdecl, tree olddecl);
+static void finish_decl (tree decl, tree init, bool is_top_level);
+static void finish_function (int nested);
+static char *lang_printable_name (tree decl, int v);
+static tree lookup_name_current_level (tree name);
+static struct binding_level *make_binding_level (void);
+static void pop_f_function_context (void);
+static void push_f_function_context (void);
+static void push_parm_decl (tree parm);
+static tree pushdecl_top_level (tree decl);
+static tree storedecls (tree decls);
+static void store_parm_decls (int is_main_program);
+static tree start_decl (tree decl, bool is_top_level);
+static void start_function (tree name, tree type, int nested, int public);
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+#if FFECOM_GCC_INCLUDE
+static void ffecom_file_ (char *name);
+static void ffecom_initialize_char_syntax_ (void);
+static void ffecom_close_include_ (FILE *f);
+static int ffecom_decode_include_option_ (char *spec);
+static FILE *ffecom_open_include_ (char *name, ffewhereLine l,
+ ffewhereColumn c);
+#endif /* FFECOM_GCC_INCLUDE */
+
+/* Static objects accessed by functions in this module. */
+
+static ffesymbol ffecom_primary_entry_ = NULL;
+static ffesymbol ffecom_nested_entry_ = NULL;
+static ffeinfoKind ffecom_primary_entry_kind_;
+static bool ffecom_primary_entry_is_proc_;
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree ffecom_outer_function_decl_;
+static tree ffecom_previous_function_decl_;
+static tree ffecom_which_entrypoint_decl_;
+static ffecomTemp_ ffecom_latest_temp_;
+static int ffecom_pending_calls_ = 0;
+static tree ffecom_float_zero_ = NULL_TREE;
+static tree ffecom_float_half_ = NULL_TREE;
+static tree ffecom_double_zero_ = NULL_TREE;
+static tree ffecom_double_half_ = NULL_TREE;
+static tree ffecom_func_result_;/* For functions. */
+static tree ffecom_func_length_;/* For CHARACTER fns. */
+static ffebld ffecom_list_blockdata_;
+static ffebld ffecom_list_common_;
+static ffebld ffecom_master_arglist_;
+static ffeinfoBasictype ffecom_master_bt_;
+static ffeinfoKindtype ffecom_master_kt_;
+static ffetargetCharacterSize ffecom_master_size_;
+static int ffecom_num_fns_ = 0;
+static int ffecom_num_entrypoints_ = 0;
+static bool ffecom_is_altreturning_ = FALSE;
+static tree ffecom_multi_type_node_;
+static tree ffecom_multi_retval_;
+static tree
+ ffecom_multi_fields_[FFEINFO_basictype][FFEINFO_kindtype];
+static bool ffecom_member_namelisted_; /* _member_phase1_ namelisted? */
+static bool ffecom_doing_entry_ = FALSE;
+static bool ffecom_transform_only_dummies_ = FALSE;
+
+/* Holds pointer-to-function expressions. */
+
+static tree ffecom_gfrt_[FFECOM_gfrt]
+=
+{
+#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX) NULL_TREE,
+#include "com-rt.def"
+#undef DEFGFRT
+};
+
+/* Holds the external names of the functions. */
+
+static char *ffecom_gfrt_name_[FFECOM_gfrt]
+=
+{
+#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX) NAME,
+#include "com-rt.def"
+#undef DEFGFRT
+};
+
+/* Whether the function returns. */
+
+static bool ffecom_gfrt_volatile_[FFECOM_gfrt]
+=
+{
+#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX) VOLATILE,
+#include "com-rt.def"
+#undef DEFGFRT
+};
+
+/* Whether the function returns type complex. */
+
+static bool ffecom_gfrt_complex_[FFECOM_gfrt]
+=
+{
+#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX) COMPLEX,
+#include "com-rt.def"
+#undef DEFGFRT
+};
+
+/* Type code for the function return value. */
+
+static ffecomRttype_ ffecom_gfrt_type_[FFECOM_gfrt]
+=
+{
+#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX) TYPE,
+#include "com-rt.def"
+#undef DEFGFRT
+};
+
+/* String of codes for the function's arguments. */
+
+static char *ffecom_gfrt_argstring_[FFECOM_gfrt]
+=
+{
+#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX) ARGS,
+#include "com-rt.def"
+#undef DEFGFRT
+};
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+/* Internal macros. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+
+/* We let tm.h override the types used here, to handle trivial differences
+ such as the choice of unsigned int or long unsigned int for size_t.
+ When machines start needing nontrivial differences in the size type,
+ it would be best to do something here to figure out automatically
+ from other information what type to use. */
+
+/* NOTE: g77 currently doesn't use these; see setting of sizetype and
+ change that if you need to. -- jcb 09/01/91. */
+
+#define ffecom_concat_list_count_(catlist) ((catlist).count)
+#define ffecom_concat_list_expr_(catlist,i) ((catlist).exprs[(i)])
+#define ffecom_concat_list_maxlen_(catlist) ((catlist).maxlen)
+#define ffecom_concat_list_minlen_(catlist) ((catlist).minlen)
+
+#define ffecom_start_compstmt_ bison_rule_pushlevel_
+#define ffecom_end_compstmt_ bison_rule_compstmt_
+
+#define ffecom_char_args_(i,l,e) ffecom_char_args_x_((i),(l),(e),FALSE)
+#define ffecom_char_args_with_null_(i,l,e) ffecom_char_args_x_((i),(l),(e),TRUE)
+
+/* For each binding contour we allocate a binding_level structure
+ * which records the names defined in that contour.
+ * Contours include:
+ * 0) the global one
+ * 1) one for each function definition,
+ * where internal declarations of the parameters appear.
+ *
+ * The current meaning of a name can be found by searching the levels from
+ * the current one out to the global one.
+ */
+
+/* Note that the information in the `names' component of the global contour
+ is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers. */
+
+struct binding_level
+ {
+ /* A chain of _DECL nodes for all variables, constants, functions, and
+ typedef types. These are in the reverse of the order supplied. */
+ tree names;
+
+ /* For each level (except not the global one), a chain of BLOCK nodes for
+ all the levels that were entered and exited one level down. */
+ tree blocks;
+
+ /* The BLOCK node for this level, if one has been preallocated. If 0, the
+ BLOCK is allocated (if needed) when the level is popped. */
+ tree this_block;
+
+ /* The binding level which this one is contained in (inherits from). */
+ struct binding_level *level_chain;
+ };
+
+#define NULL_BINDING_LEVEL (struct binding_level *) NULL
+
+/* The binding level currently in effect. */
+
+static struct binding_level *current_binding_level;
+
+/* A chain of binding_level structures awaiting reuse. */
+
+static struct binding_level *free_binding_level;
+
+/* The outermost binding level, for names of file scope.
+ This is created when the compiler is started and exists
+ through the entire run. */
+
+static struct binding_level *global_binding_level;
+
+/* Binding level structures are initialized by copying this one. */
+
+static struct binding_level clear_binding_level
+=
+{NULL, NULL, NULL, NULL_BINDING_LEVEL};
+
+/* Language-dependent contents of an identifier. */
+
+struct lang_identifier
+ {
+ struct tree_identifier ignore;
+ tree global_value, local_value, label_value;
+ bool invented;
+ };
+
+/* Macros for access to language-specific slots in an identifier. */
+/* Each of these slots contains a DECL node or null. */
+
+/* This represents the value which the identifier has in the
+ file-scope namespace. */
+#define IDENTIFIER_GLOBAL_VALUE(NODE) \
+ (((struct lang_identifier *)(NODE))->global_value)
+/* This represents the value which the identifier has in the current
+ scope. */
+#define IDENTIFIER_LOCAL_VALUE(NODE) \
+ (((struct lang_identifier *)(NODE))->local_value)
+/* This represents the value which the identifier has as a label in
+ the current label scope. */
+#define IDENTIFIER_LABEL_VALUE(NODE) \
+ (((struct lang_identifier *)(NODE))->label_value)
+/* This is nonzero if the identifier was "made up" by g77 code. */
+#define IDENTIFIER_INVENTED(NODE) \
+ (((struct lang_identifier *)(NODE))->invented)
+
+/* In identifiers, C uses the following fields in a special way:
+ TREE_PUBLIC to record that there was a previous local extern decl.
+ TREE_USED to record that such a decl was used.
+ TREE_ADDRESSABLE to record that the address of such a decl was used. */
+
+/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function
+ that have names. Here so we can clear out their names' definitions
+ at the end of the function. */
+
+static tree named_labels;
+
+/* A list of LABEL_DECLs from outer contexts that are currently shadowed. */
+
+static tree shadowed_labels;
+
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+
+/* This is like gcc's stabilize_reference -- in fact, most of the code
+ comes from that -- but it handles the situation where the reference
+ is going to have its subparts picked at, and it shouldn't change
+ (or trigger extra invocations of functions in the subtrees) due to
+ this. save_expr is a bit overzealous, because we don't need the
+ entire thing calculated and saved like a temp. So, for DECLs, no
+ change is needed, because these are stable aggregates, and ARRAY_REF
+ and such might well be stable too, but for things like calculations,
+ we do need to calculate a snapshot of a value before picking at it. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_stabilize_aggregate_ (tree ref)
+{
+ tree result;
+ enum tree_code code = TREE_CODE (ref);
+
+ switch (code)
+ {
+ case VAR_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ /* No action is needed in this case. */
+ return ref;
+
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ case FIX_CEIL_EXPR:
+ result = build_nt (code, stabilize_reference (TREE_OPERAND (ref, 0)));
+ break;
+
+ case INDIRECT_REF:
+ result = build_nt (INDIRECT_REF,
+ stabilize_reference_1 (TREE_OPERAND (ref, 0)));
+ break;
+
+ case COMPONENT_REF:
+ result = build_nt (COMPONENT_REF,
+ stabilize_reference (TREE_OPERAND (ref, 0)),
+ TREE_OPERAND (ref, 1));
+ break;
+
+ case BIT_FIELD_REF:
+ result = build_nt (BIT_FIELD_REF,
+ stabilize_reference (TREE_OPERAND (ref, 0)),
+ stabilize_reference_1 (TREE_OPERAND (ref, 1)),
+ stabilize_reference_1 (TREE_OPERAND (ref, 2)));
+ break;
+
+ case ARRAY_REF:
+ result = build_nt (ARRAY_REF,
+ stabilize_reference (TREE_OPERAND (ref, 0)),
+ stabilize_reference_1 (TREE_OPERAND (ref, 1)));
+ break;
+
+ case COMPOUND_EXPR:
+ result = build_nt (COMPOUND_EXPR,
+ stabilize_reference_1 (TREE_OPERAND (ref, 0)),
+ stabilize_reference (TREE_OPERAND (ref, 1)));
+ break;
+
+ case RTL_EXPR:
+ result = build1 (INDIRECT_REF, TREE_TYPE (ref),
+ save_expr (build1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (ref)),
+ ref)));
+ break;
+
+
+ default:
+ return save_expr (ref);
+
+ case ERROR_MARK:
+ return error_mark_node;
+ }
+
+ TREE_TYPE (result) = TREE_TYPE (ref);
+ TREE_READONLY (result) = TREE_READONLY (ref);
+ TREE_SIDE_EFFECTS (result) = TREE_SIDE_EFFECTS (ref);
+ TREE_THIS_VOLATILE (result) = TREE_THIS_VOLATILE (ref);
+ TREE_RAISES (result) = TREE_RAISES (ref);
+
+ return result;
+}
+#endif
+
+/* A rip-off of gcc's convert.c convert_to_complex function,
+ reworked to handle complex implemented as C structures
+ (RECORD_TYPE with two fields, real and imaginary `r' and `i'). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_convert_to_complex_ (tree type, tree expr)
+{
+ register enum tree_code form = TREE_CODE (TREE_TYPE (expr));
+ tree subtype;
+
+ assert (TREE_CODE (type) == RECORD_TYPE);
+
+ subtype = TREE_TYPE (TYPE_FIELDS (type));
+
+ if (form == REAL_TYPE || form == INTEGER_TYPE || form == ENUMERAL_TYPE)
+ {
+ expr = convert (subtype, expr);
+ return ffecom_2 (COMPLEX_EXPR, type, expr,
+ convert (subtype, integer_zero_node));
+ }
+
+ if (form == RECORD_TYPE)
+ {
+ tree elt_type = TREE_TYPE (TYPE_FIELDS (TREE_TYPE (expr)));
+ if (TYPE_MAIN_VARIANT (elt_type) == TYPE_MAIN_VARIANT (subtype))
+ return expr;
+ else
+ {
+ expr = save_expr (expr);
+ return ffecom_2 (COMPLEX_EXPR,
+ type,
+ convert (subtype,
+ ffecom_1 (REALPART_EXPR,
+ TREE_TYPE (TYPE_FIELDS (TREE_TYPE (expr))),
+ expr)),
+ convert (subtype,
+ ffecom_1 (IMAGPART_EXPR,
+ TREE_TYPE (TYPE_FIELDS (TREE_TYPE (expr))),
+ expr)));
+ }
+ }
+
+ if (form == POINTER_TYPE || form == REFERENCE_TYPE)
+ error ("pointer value used where a complex was expected");
+ else
+ error ("aggregate value used where a complex was expected");
+
+ return ffecom_2 (COMPLEX_EXPR, type,
+ convert (subtype, integer_zero_node),
+ convert (subtype, integer_zero_node));
+}
+#endif
+
+/* Like gcc's convert(), but crashes if widening might happen. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_convert_narrow_ (type, expr)
+ tree type, expr;
+{
+ register tree e = expr;
+ register enum tree_code code = TREE_CODE (type);
+
+ if (type == TREE_TYPE (e)
+ || TREE_CODE (e) == ERROR_MARK)
+ return e;
+ if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
+ return fold (build1 (NOP_EXPR, type, e));
+ if (TREE_CODE (TREE_TYPE (e)) == ERROR_MARK
+ || code == ERROR_MARK)
+ return error_mark_node;
+ if (TREE_CODE (TREE_TYPE (e)) == VOID_TYPE)
+ {
+ assert ("void value not ignored as it ought to be" == NULL);
+ return error_mark_node;
+ }
+ assert (code != VOID_TYPE);
+ if ((code != RECORD_TYPE)
+ && (TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE))
+ assert ("converting COMPLEX to REAL" == NULL);
+ assert (code != ENUMERAL_TYPE);
+ if (code == INTEGER_TYPE)
+ {
+ assert ((TREE_CODE (TREE_TYPE (e)) == INTEGER_TYPE
+ && TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (e)))
+ || (TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE
+ && (TYPE_PRECISION (type)
+ == TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (e))))));
+ return fold (convert_to_integer (type, e));
+ }
+ if (code == POINTER_TYPE)
+ {
+ assert (TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE);
+ return fold (convert_to_pointer (type, e));
+ }
+ if (code == REAL_TYPE)
+ {
+ assert (TREE_CODE (TREE_TYPE (e)) == REAL_TYPE);
+ assert (TYPE_PRECISION (type) <= TYPE_PRECISION (TREE_TYPE (e)));
+ return fold (convert_to_real (type, e));
+ }
+ if (code == COMPLEX_TYPE)
+ {
+ assert (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE);
+ assert (TYPE_PRECISION (TREE_TYPE (type)) <= TYPE_PRECISION (TREE_TYPE (TREE_TYPE (e))));
+ return fold (convert_to_complex (type, e));
+ }
+ if (code == RECORD_TYPE)
+ {
+ assert (TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE);
+ /* Check that at least the first field name agrees. */
+ assert (DECL_NAME (TYPE_FIELDS (type))
+ == DECL_NAME (TYPE_FIELDS (TREE_TYPE (e))));
+ assert (TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (type)))
+ <= TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (e)))));
+ if (TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (type)))
+ == TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (e)))))
+ return e;
+ return fold (ffecom_convert_to_complex_ (type, e));
+ }
+
+ assert ("conversion to non-scalar type requested" == NULL);
+ return error_mark_node;
+}
+#endif
+
+/* Like gcc's convert(), but crashes if narrowing might happen. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_convert_widen_ (type, expr)
+ tree type, expr;
+{
+ register tree e = expr;
+ register enum tree_code code = TREE_CODE (type);
+
+ if (type == TREE_TYPE (e)
+ || TREE_CODE (e) == ERROR_MARK)
+ return e;
+ if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
+ return fold (build1 (NOP_EXPR, type, e));
+ if (TREE_CODE (TREE_TYPE (e)) == ERROR_MARK
+ || code == ERROR_MARK)
+ return error_mark_node;
+ if (TREE_CODE (TREE_TYPE (e)) == VOID_TYPE)
+ {
+ assert ("void value not ignored as it ought to be" == NULL);
+ return error_mark_node;
+ }
+ assert (code != VOID_TYPE);
+ if ((code != RECORD_TYPE)
+ && (TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE))
+ assert ("narrowing COMPLEX to REAL" == NULL);
+ assert (code != ENUMERAL_TYPE);
+ if (code == INTEGER_TYPE)
+ {
+ assert ((TREE_CODE (TREE_TYPE (e)) == INTEGER_TYPE
+ && TYPE_PRECISION (type) >= TYPE_PRECISION (TREE_TYPE (e)))
+ || (TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE
+ && (TYPE_PRECISION (type)
+ == TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (e))))));
+ return fold (convert_to_integer (type, e));
+ }
+ if (code == POINTER_TYPE)
+ {
+ assert (TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE);
+ return fold (convert_to_pointer (type, e));
+ }
+ if (code == REAL_TYPE)
+ {
+ assert (TREE_CODE (TREE_TYPE (e)) == REAL_TYPE);
+ assert (TYPE_PRECISION (type) >= TYPE_PRECISION (TREE_TYPE (e)));
+ return fold (convert_to_real (type, e));
+ }
+ if (code == COMPLEX_TYPE)
+ {
+ assert (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE);
+ assert (TYPE_PRECISION (TREE_TYPE (type)) >= TYPE_PRECISION (TREE_TYPE (TREE_TYPE (e))));
+ return fold (convert_to_complex (type, e));
+ }
+ if (code == RECORD_TYPE)
+ {
+ assert (TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE);
+ /* Check that at least the first field name agrees. */
+ assert (DECL_NAME (TYPE_FIELDS (type))
+ == DECL_NAME (TYPE_FIELDS (TREE_TYPE (e))));
+ assert (TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (type)))
+ >= TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (e)))));
+ if (TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (type)))
+ == TYPE_PRECISION (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (e)))))
+ return e;
+ return fold (ffecom_convert_to_complex_ (type, e));
+ }
+
+ assert ("conversion to non-scalar type requested" == NULL);
+ return error_mark_node;
+}
+#endif
+
+/* Handles making a COMPLEX type, either the standard
+ (but buggy?) gbe way, or the safer (but less elegant?)
+ f2c way. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_make_complex_type_ (tree subtype)
+{
+ tree type;
+ tree realfield;
+ tree imagfield;
+
+ if (ffe_is_emulate_complex ())
+ {
+ type = make_node (RECORD_TYPE);
+ realfield = ffecom_decl_field (type, NULL_TREE, "r", subtype);
+ imagfield = ffecom_decl_field (type, realfield, "i", subtype);
+ TYPE_FIELDS (type) = realfield;
+ layout_type (type);
+ }
+ else
+ {
+ type = make_node (COMPLEX_TYPE);
+ TREE_TYPE (type) = subtype;
+ layout_type (type);
+ }
+
+ return type;
+}
+#endif
+
+/* Chooses either the gbe or the f2c way to build a
+ complex constant. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_build_complex_constant_ (tree type, tree realpart, tree imagpart)
+{
+ tree bothparts;
+
+ if (ffe_is_emulate_complex ())
+ {
+ bothparts = build_tree_list (TYPE_FIELDS (type), realpart);
+ TREE_CHAIN (bothparts) = build_tree_list (TREE_CHAIN (TYPE_FIELDS (type)), imagpart);
+ bothparts = build (CONSTRUCTOR, type, NULL_TREE, bothparts);
+ }
+ else
+ {
+ bothparts = build_complex (type, realpart, imagpart);
+ }
+
+ return bothparts;
+}
+#endif
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_arglist_expr_ (char *c, ffebld expr)
+{
+ tree list;
+ tree *plist = &list;
+ tree trail = NULL_TREE; /* Append char length args here. */
+ tree *ptrail = &trail;
+ tree length;
+ ffebld exprh;
+ tree item;
+ bool ptr = FALSE;
+ tree wanted = NULL_TREE;
+ static char zed[] = "0";
+
+ if (c == NULL)
+ c = &zed[0];
+
+ while (expr != NULL)
+ {
+ if (*c != '\0')
+ {
+ ptr = FALSE;
+ if (*c == '&')
+ {
+ ptr = TRUE;
+ ++c;
+ }
+ switch (*(c++))
+ {
+ case '\0':
+ ptr = TRUE;
+ wanted = NULL_TREE;
+ break;
+
+ case 'a':
+ assert (ptr);
+ wanted = NULL_TREE;
+ break;
+
+ case 'c':
+ wanted = ffecom_f2c_complex_type_node;
+ break;
+
+ case 'd':
+ wanted = ffecom_f2c_doublereal_type_node;
+ break;
+
+ case 'e':
+ wanted = ffecom_f2c_doublecomplex_type_node;
+ break;
+
+ case 'f':
+ wanted = ffecom_f2c_real_type_node;
+ break;
+
+ case 'i':
+ wanted = ffecom_f2c_integer_type_node;
+ break;
+
+ case 'j':
+ wanted = ffecom_f2c_longint_type_node;
+ break;
+
+ default:
+ assert ("bad argstring code" == NULL);
+ wanted = NULL_TREE;
+ break;
+ }
+ }
+
+ exprh = ffebld_head (expr);
+ if (exprh == NULL)
+ wanted = NULL_TREE;
+
+ if ((wanted == NULL_TREE)
+ || (ptr
+ && (TYPE_MODE
+ (ffecom_tree_type[ffeinfo_basictype (ffebld_info (exprh))]
+ [ffeinfo_kindtype (ffebld_info (exprh))])
+ == TYPE_MODE (wanted))))
+ *plist
+ = build_tree_list (NULL_TREE,
+ ffecom_arg_ptr_to_expr (exprh,
+ &length));
+ else
+ {
+ item = ffecom_arg_expr (exprh, &length);
+ item = ffecom_convert_widen_ (wanted, item);
+ if (ptr)
+ {
+ item = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (item)),
+ item);
+ }
+ *plist
+ = build_tree_list (NULL_TREE,
+ item);
+ }
+
+ plist = &TREE_CHAIN (*plist);
+ expr = ffebld_trail (expr);
+ if (length != NULL_TREE)
+ {
+ *ptrail = build_tree_list (NULL_TREE, length);
+ ptrail = &TREE_CHAIN (*ptrail);
+ }
+ }
+
+ /* We've run out of args in the call; if the implementation expects
+ more, supply null pointers for them, which the implementation can
+ check to see if an arg was omitted. */
+
+ while (*c != '\0' && *c != '0')
+ {
+ if (*c == '&')
+ ++c;
+ else
+ assert ("missing arg to run-time routine!" == NULL);
+
+ switch (*(c++))
+ {
+ case '\0':
+ case 'a':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'i':
+ case 'j':
+ break;
+
+ default:
+ assert ("bad arg string code" == NULL);
+ break;
+ }
+ *plist
+ = build_tree_list (NULL_TREE,
+ null_pointer_node);
+ plist = &TREE_CHAIN (*plist);
+ }
+
+ *plist = trail;
+
+ return list;
+}
+#endif
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_widest_expr_type_ (ffebld list)
+{
+ ffebld item;
+ ffebld widest = NULL;
+ ffetype type;
+ ffetype widest_type = NULL;
+ tree t;
+
+ for (; list != NULL; list = ffebld_trail (list))
+ {
+ item = ffebld_head (list);
+ if (item == NULL)
+ continue;
+ if ((widest != NULL)
+ && (ffeinfo_basictype (ffebld_info (item))
+ != ffeinfo_basictype (ffebld_info (widest))))
+ continue;
+ type = ffeinfo_type (ffeinfo_basictype (ffebld_info (item)),
+ ffeinfo_kindtype (ffebld_info (item)));
+ if ((widest == FFEINFO_kindtypeNONE)
+ || (ffetype_size (type)
+ > ffetype_size (widest_type)))
+ {
+ widest = item;
+ widest_type = type;
+ }
+ }
+
+ assert (widest != NULL);
+ t = ffecom_tree_type[ffeinfo_basictype (ffebld_info (widest))]
+ [ffeinfo_kindtype (ffebld_info (widest))];
+ assert (t != NULL_TREE);
+ return t;
+}
+#endif
+
+/* Check whether dest and source might overlap. ffebld versions of these
+ might or might not be passed, will be NULL if not.
+
+ The test is really whether source_tree is modifiable and, if modified,
+ might overlap destination such that the value(s) in the destination might
+ change before it is finally modified. dest_* are the canonized
+ destination itself. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static bool
+ffecom_overlap_ (tree dest_decl, tree dest_offset, tree dest_size,
+ tree source_tree, ffebld source UNUSED,
+ bool scalar_arg)
+{
+ tree source_decl;
+ tree source_offset;
+ tree source_size;
+ tree t;
+
+ if (source_tree == NULL_TREE)
+ return FALSE;
+
+ switch (TREE_CODE (source_tree))
+ {
+ case ERROR_MARK:
+ case IDENTIFIER_NODE:
+ case INTEGER_CST:
+ case REAL_CST:
+ case COMPLEX_CST:
+ case STRING_CST:
+ case CONST_DECL:
+ case VAR_DECL:
+ case RESULT_DECL:
+ case FIELD_DECL:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ case CEIL_MOD_EXPR:
+ case FLOOR_MOD_EXPR:
+ case ROUND_MOD_EXPR:
+ case RDIV_EXPR:
+ case EXACT_DIV_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIX_CEIL_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ case FLOAT_EXPR:
+ case EXPON_EXPR:
+ case NEGATE_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
+ case ABS_EXPR:
+ case FFS_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_ANDTC_EXPR:
+ case BIT_NOT_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ case TRUTH_NOT_EXPR:
+ case LT_EXPR:
+ case LE_EXPR:
+ case GT_EXPR:
+ case GE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case COMPLEX_EXPR:
+ case CONJ_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case LABEL_EXPR:
+ case COMPONENT_REF:
+ return FALSE;
+
+ case COMPOUND_EXPR:
+ return ffecom_overlap_ (dest_decl, dest_offset, dest_size,
+ TREE_OPERAND (source_tree, 1), NULL,
+ scalar_arg);
+
+ case MODIFY_EXPR:
+ return ffecom_overlap_ (dest_decl, dest_offset, dest_size,
+ TREE_OPERAND (source_tree, 0), NULL,
+ scalar_arg);
+
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ case NON_LVALUE_EXPR:
+ case PLUS_EXPR:
+ if (TREE_CODE (TREE_TYPE (source_tree)) != POINTER_TYPE)
+ return TRUE;
+
+ ffecom_tree_canonize_ptr_ (&source_decl, &source_offset,
+ source_tree);
+ source_size = TYPE_SIZE (TREE_TYPE (TREE_TYPE (source_tree)));
+ break;
+
+ case COND_EXPR:
+ return
+ ffecom_overlap_ (dest_decl, dest_offset, dest_size,
+ TREE_OPERAND (source_tree, 1), NULL,
+ scalar_arg)
+ || ffecom_overlap_ (dest_decl, dest_offset, dest_size,
+ TREE_OPERAND (source_tree, 2), NULL,
+ scalar_arg);
+
+
+ case ADDR_EXPR:
+ ffecom_tree_canonize_ref_ (&source_decl, &source_offset,
+ &source_size,
+ TREE_OPERAND (source_tree, 0));
+ break;
+
+ case PARM_DECL:
+ if (TREE_CODE (TREE_TYPE (source_tree)) != POINTER_TYPE)
+ return TRUE;
+
+ source_decl = source_tree;
+ source_offset = size_zero_node;
+ source_size = TYPE_SIZE (TREE_TYPE (TREE_TYPE (source_tree)));
+ break;
+
+ case SAVE_EXPR:
+ case REFERENCE_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case INDIRECT_REF:
+ case ARRAY_REF:
+ case CALL_EXPR:
+ default:
+ return TRUE;
+ }
+
+ /* Come here when source_decl, source_offset, and source_size filled
+ in appropriately. */
+
+ if (source_decl == NULL_TREE)
+ return FALSE; /* No decl involved, so no overlap. */
+
+ if (source_decl != dest_decl)
+ return FALSE; /* Different decl, no overlap. */
+
+ if (TREE_CODE (dest_size) == ERROR_MARK)
+ return TRUE; /* Assignment into entire assumed-size
+ array? Shouldn't happen.... */
+
+ t = ffecom_2 (LE_EXPR, integer_type_node,
+ ffecom_2 (PLUS_EXPR, TREE_TYPE (dest_offset),
+ dest_offset,
+ convert (TREE_TYPE (dest_offset),
+ dest_size)),
+ convert (TREE_TYPE (dest_offset),
+ source_offset));
+
+ if (integer_onep (t))
+ return FALSE; /* Destination precedes source. */
+
+ if (!scalar_arg
+ || (source_size == NULL_TREE)
+ || (TREE_CODE (source_size) == ERROR_MARK)
+ || integer_zerop (source_size))
+ return TRUE; /* No way to tell if dest follows source. */
+
+ t = ffecom_2 (LE_EXPR, integer_type_node,
+ ffecom_2 (PLUS_EXPR, TREE_TYPE (source_offset),
+ source_offset,
+ convert (TREE_TYPE (source_offset),
+ source_size)),
+ convert (TREE_TYPE (source_offset),
+ dest_offset));
+
+ if (integer_onep (t))
+ return FALSE; /* Destination follows source. */
+
+ return TRUE; /* Destination and source overlap. */
+}
+#endif
+
+/* Check whether dest might overlap any of a list of arguments or is
+ in a COMMON area the callee might know about (and thus modify). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static bool
+ffecom_args_overlapping_ (tree dest_tree, ffebld dest UNUSED,
+ tree args, tree callee_commons,
+ bool scalar_args)
+{
+ tree arg;
+ tree dest_decl;
+ tree dest_offset;
+ tree dest_size;
+
+ ffecom_tree_canonize_ref_ (&dest_decl, &dest_offset, &dest_size,
+ dest_tree);
+
+ if (dest_decl == NULL_TREE)
+ return FALSE; /* Seems unlikely! */
+
+ /* If the decl cannot be determined reliably, or if its in COMMON
+ and the callee isn't known to not futz with COMMON via other
+ means, overlap might happen. */
+
+ if ((TREE_CODE (dest_decl) == ERROR_MARK)
+ || ((callee_commons != NULL_TREE)
+ && TREE_PUBLIC (dest_decl)))
+ return TRUE;
+
+ for (; args != NULL_TREE; args = TREE_CHAIN (args))
+ {
+ if (((arg = TREE_VALUE (args)) != NULL_TREE)
+ && ffecom_overlap_ (dest_decl, dest_offset, dest_size,
+ arg, NULL, scalar_args))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
+/* Build a string for a variable name as used by NAMELIST. This means that
+ if we're using the f2c library, we build an uppercase string, since
+ f2c does this. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_build_f2c_string_ (int i, char *s)
+{
+ if (!ffe_is_f2c_library ())
+ return build_string (i, s);
+
+ {
+ char *tmp;
+ char *p;
+ char *q;
+ char space[34];
+ tree t;
+
+ if (((size_t) i) > ARRAY_SIZE (space))
+ tmp = malloc_new_ks (malloc_pool_image (), "f2c_string", i);
+ else
+ tmp = &space[0];
+
+ for (p = s, q = tmp; *p != '\0'; ++p, ++q)
+ *q = ffesrc_toupper (*p);
+ *q = '\0';
+
+ t = build_string (i, tmp);
+
+ if (((size_t) i) > ARRAY_SIZE (space))
+ malloc_kill_ks (malloc_pool_image (), tmp, i);
+
+ return t;
+ }
+}
+
+#endif
+/* Returns CALL_EXPR or equivalent with given type (pass NULL_TREE for
+ type to just get whatever the function returns), handling the
+ f2c value-returning convention, if required, by prepending
+ to the arglist a pointer to a temporary to receive the return value. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_call_ (tree fn, ffeinfoKindtype kt, bool is_f2c_complex,
+ tree type, tree args, tree dest_tree,
+ ffebld dest, bool *dest_used, tree callee_commons,
+ bool scalar_args)
+{
+ tree item;
+ tree tempvar;
+
+ if (dest_used != NULL)
+ *dest_used = FALSE;
+
+ if (is_f2c_complex)
+ {
+ if ((dest_used == NULL)
+ || (dest == NULL)
+ || (ffeinfo_basictype (ffebld_info (dest))
+ != FFEINFO_basictypeCOMPLEX)
+ || (ffeinfo_kindtype (ffebld_info (dest)) != kt)
+ || ((type != NULL_TREE) && (TREE_TYPE (dest_tree) != type))
+ || ffecom_args_overlapping_ (dest_tree, dest, args,
+ callee_commons,
+ scalar_args))
+ {
+ tempvar = ffecom_push_tempvar (ffecom_tree_type
+ [FFEINFO_basictypeCOMPLEX][kt],
+ FFETARGET_charactersizeNONE,
+ -1, TRUE);
+ }
+ else
+ {
+ *dest_used = TRUE;
+ tempvar = dest_tree;
+ type = NULL_TREE;
+ }
+
+ item
+ = build_tree_list (NULL_TREE,
+ ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (tempvar)),
+ tempvar));
+ TREE_CHAIN (item) = args;
+
+ item = ffecom_3s (CALL_EXPR, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), fn,
+ item, NULL_TREE);
+
+ if (tempvar != dest_tree)
+ item = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (tempvar), item, tempvar);
+ }
+ else
+ item = ffecom_3s (CALL_EXPR, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), fn,
+ args, NULL_TREE);
+
+ if ((type != NULL_TREE) && (TREE_TYPE (item) != type))
+ item = ffecom_convert_narrow_ (type, item);
+
+ return item;
+}
+#endif
+
+/* Given two arguments, transform them and make a call to the given
+ function via ffecom_call_. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_call_binop_ (tree fn, ffeinfoKindtype kt, bool is_f2c_complex,
+ tree type, ffebld left, ffebld right,
+ tree dest_tree, ffebld dest, bool *dest_used,
+ tree callee_commons, bool scalar_args)
+{
+ tree left_tree;
+ tree right_tree;
+ tree left_length;
+ tree right_length;
+
+ ffecom_push_calltemps ();
+ left_tree = ffecom_arg_ptr_to_expr (left, &left_length);
+ right_tree = ffecom_arg_ptr_to_expr (right, &right_length);
+ ffecom_pop_calltemps ();
+
+ left_tree = build_tree_list (NULL_TREE, left_tree);
+ right_tree = build_tree_list (NULL_TREE, right_tree);
+ TREE_CHAIN (left_tree) = right_tree;
+
+ if (left_length != NULL_TREE)
+ {
+ left_length = build_tree_list (NULL_TREE, left_length);
+ TREE_CHAIN (right_tree) = left_length;
+ }
+
+ if (right_length != NULL_TREE)
+ {
+ right_length = build_tree_list (NULL_TREE, right_length);
+ if (left_length != NULL_TREE)
+ TREE_CHAIN (left_length) = right_length;
+ else
+ TREE_CHAIN (right_tree) = right_length;
+ }
+
+ return ffecom_call_ (fn, kt, is_f2c_complex, type, left_tree,
+ dest_tree, dest, dest_used, callee_commons,
+ scalar_args);
+}
+#endif
+
+/* ffecom_char_args_x_ -- Return ptr/length args for char subexpression
+
+ tree ptr_arg;
+ tree length_arg;
+ ffebld expr;
+ bool with_null;
+ ffecom_char_args_x_(&ptr_arg,&length_arg,expr,with_null);
+
+ Handles CHARACTER-type CONTER, SYMTER, SUBSTR, ARRAYREF, and FUNCREF
+ subexpressions by constructing the appropriate trees for the ptr-to-
+ character-text and length-of-character-text arguments in a calling
+ sequence.
+
+ Note that if with_null is TRUE, and the expression is an opCONTER,
+ a null byte is appended to the string. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_char_args_x_ (tree *xitem, tree *length, ffebld expr, bool with_null)
+{
+ tree item;
+ tree high;
+ ffetargetCharacter1 val;
+ ffetargetCharacterSize newlen;
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opCONTER:
+ val = ffebld_constant_character1 (ffebld_conter (expr));
+ newlen = ffetarget_length_character1 (val);
+ if (with_null)
+ {
+ if (newlen != 0)
+ ++newlen; /* begin FFETARGET-NULL-KLUDGE. */
+ }
+ *length = build_int_2 (newlen, 0);
+ TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node;
+ high = build_int_2 (newlen, 0);
+ TREE_TYPE (high) = ffecom_f2c_ftnlen_type_node;
+ item = build_string (newlen, /* end FFETARGET-NULL-KLUDGE. */
+ ffetarget_text_character1 (val));
+ TREE_TYPE (item)
+ = build_type_variant
+ (build_array_type
+ (char_type_node,
+ build_range_type
+ (ffecom_f2c_ftnlen_type_node,
+ ffecom_f2c_ftnlen_one_node,
+ high)),
+ 1, 0);
+ TREE_CONSTANT (item) = 1;
+ TREE_STATIC (item) = 1;
+ item = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (item)),
+ item);
+ break;
+
+ case FFEBLD_opSYMTER:
+ {
+ ffesymbol s = ffebld_symter (expr);
+
+ item = ffesymbol_hook (s).decl_tree;
+ if (item == NULL_TREE)
+ {
+ s = ffecom_sym_transform_ (s);
+ item = ffesymbol_hook (s).decl_tree;
+ }
+ if (ffesymbol_kind (s) == FFEINFO_kindENTITY)
+ {
+ if (ffesymbol_size (s) == FFETARGET_charactersizeNONE)
+ *length = ffesymbol_hook (s).length_tree;
+ else
+ {
+ *length = build_int_2 (ffesymbol_size (s), 0);
+ TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node;
+ }
+ }
+ else if (item == error_mark_node)
+ *length = error_mark_node;
+ else /* FFEINFO_kindFUNCTION: */
+ *length = NULL_TREE;
+ if (!ffesymbol_hook (s).addr
+ && (item != error_mark_node))
+ item = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (item)),
+ item);
+ }
+ break;
+
+ case FFEBLD_opARRAYREF:
+ {
+ ffebld dims[FFECOM_dimensionsMAX];
+ tree array;
+ int i;
+
+ ffecom_push_calltemps ();
+ ffecom_char_args_ (&item, length, ffebld_left (expr));
+ ffecom_pop_calltemps ();
+
+ if (item == error_mark_node || *length == error_mark_node)
+ {
+ item = *length = error_mark_node;
+ break;
+ }
+
+ /* Build up ARRAY_REFs in reverse order (since we're column major
+ here in Fortran land). */
+
+ for (i = 0, expr = ffebld_right (expr);
+ expr != NULL;
+ expr = ffebld_trail (expr))
+ dims[i++] = ffebld_head (expr);
+
+ for (--i, array = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (item)));
+ i >= 0;
+ --i, array = TYPE_MAIN_VARIANT (TREE_TYPE (array)))
+ {
+ item = ffecom_2 (PLUS_EXPR, build_pointer_type (TREE_TYPE (array)),
+ item,
+ size_binop (MULT_EXPR,
+ size_in_bytes (TREE_TYPE (array)),
+ size_binop (MINUS_EXPR,
+ ffecom_expr (dims[i]),
+ TYPE_MIN_VALUE (TYPE_DOMAIN (array)))));
+ }
+ }
+ break;
+
+ case FFEBLD_opSUBSTR:
+ {
+ ffebld start;
+ ffebld end;
+ ffebld thing = ffebld_right (expr);
+ tree start_tree;
+ tree end_tree;
+
+ assert (ffebld_op (thing) == FFEBLD_opITEM);
+ start = ffebld_head (thing);
+ thing = ffebld_trail (thing);
+ assert (ffebld_trail (thing) == NULL);
+ end = ffebld_head (thing);
+
+ ffecom_push_calltemps ();
+ ffecom_char_args_ (&item, length, ffebld_left (expr));
+ ffecom_pop_calltemps ();
+
+ if (item == error_mark_node || *length == error_mark_node)
+ {
+ item = *length = error_mark_node;
+ break;
+ }
+
+ if (start == NULL)
+ {
+ if (end == NULL)
+ ;
+ else
+ {
+ end_tree = convert (ffecom_f2c_ftnlen_type_node,
+ ffecom_expr (end));
+
+ if (end_tree == error_mark_node)
+ {
+ item = *length = error_mark_node;
+ break;
+ }
+
+ *length = end_tree;
+ }
+ }
+ else
+ {
+ start_tree = convert (ffecom_f2c_ftnlen_type_node,
+ ffecom_expr (start));
+
+ if (start_tree == error_mark_node)
+ {
+ item = *length = error_mark_node;
+ break;
+ }
+
+ start_tree = ffecom_save_tree (start_tree);
+
+ item = ffecom_2 (PLUS_EXPR, TREE_TYPE (item),
+ item,
+ ffecom_2 (MINUS_EXPR,
+ TREE_TYPE (start_tree),
+ start_tree,
+ ffecom_f2c_ftnlen_one_node));
+
+ if (end == NULL)
+ {
+ *length = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node,
+ ffecom_f2c_ftnlen_one_node,
+ ffecom_2 (MINUS_EXPR,
+ ffecom_f2c_ftnlen_type_node,
+ *length,
+ start_tree));
+ }
+ else
+ {
+ end_tree = convert (ffecom_f2c_ftnlen_type_node,
+ ffecom_expr (end));
+
+ if (end_tree == error_mark_node)
+ {
+ item = *length = error_mark_node;
+ break;
+ }
+
+ *length = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node,
+ ffecom_f2c_ftnlen_one_node,
+ ffecom_2 (MINUS_EXPR,
+ ffecom_f2c_ftnlen_type_node,
+ end_tree, start_tree));
+ }
+ }
+ }
+ break;
+
+ case FFEBLD_opFUNCREF:
+ {
+ ffesymbol s = ffebld_symter (ffebld_left (expr));
+ tree tempvar;
+ tree args;
+ ffetargetCharacterSize size = ffeinfo_size (ffebld_info (expr));
+ ffecomGfrt ix;
+
+ if (size == FFETARGET_charactersizeNONE)
+ size = 24; /* ~~~~ Kludge alert! This should someday be fixed. */
+
+ *length = build_int_2 (size, 0);
+ TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node;
+
+ if (ffeinfo_where (ffebld_info (ffebld_left (expr)))
+ == FFEINFO_whereINTRINSIC)
+ {
+ if (size == 1)
+ { /* Invocation of an intrinsic returning CHARACTER*1. */
+ item = ffecom_expr_intrinsic_ (expr, NULL_TREE,
+ NULL, NULL);
+ break;
+ }
+ ix = ffeintrin_gfrt_direct (ffebld_symter_implementation (ffebld_left (expr)));
+ assert (ix != FFECOM_gfrt);
+ item = ffecom_gfrt_tree_ (ix);
+ }
+ else
+ {
+ ix = FFECOM_gfrt;
+ item = ffesymbol_hook (s).decl_tree;
+ if (item == NULL_TREE)
+ {
+ s = ffecom_sym_transform_ (s);
+ item = ffesymbol_hook (s).decl_tree;
+ }
+ if (item == error_mark_node)
+ {
+ item = *length = error_mark_node;
+ break;
+ }
+
+ if (!ffesymbol_hook (s).addr)
+ item = ffecom_1_fn (item);
+ }
+
+ assert (ffecom_pending_calls_ != 0);
+ tempvar = ffecom_push_tempvar (char_type_node, size, -1, TRUE);
+ tempvar = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (tempvar)),
+ tempvar);
+
+ ffecom_push_calltemps ();
+
+ args = build_tree_list (NULL_TREE, tempvar);
+
+ if (ffesymbol_where (s) == FFEINFO_whereCONSTANT) /* Sfunc args by value. */
+ TREE_CHAIN (args) = ffecom_list_expr (ffebld_right (expr));
+ else
+ {
+ TREE_CHAIN (args) = build_tree_list (NULL_TREE, *length);
+ if (ffesymbol_where (s) == FFEINFO_whereINTRINSIC)
+ {
+ TREE_CHAIN (TREE_CHAIN (args))
+ = ffecom_arglist_expr_ (ffecom_gfrt_args_ (ix),
+ ffebld_right (expr));
+ }
+ else
+ {
+ TREE_CHAIN (TREE_CHAIN (args))
+ = ffecom_list_ptr_to_expr (ffebld_right (expr));
+ }
+ }
+
+ item = ffecom_3s (CALL_EXPR,
+ TREE_TYPE (TREE_TYPE (TREE_TYPE (item))),
+ item, args, NULL_TREE);
+ item = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (tempvar), item,
+ tempvar);
+
+ ffecom_pop_calltemps ();
+ }
+ break;
+
+ case FFEBLD_opCONVERT:
+
+ ffecom_push_calltemps ();
+ ffecom_char_args_ (&item, length, ffebld_left (expr));
+ ffecom_pop_calltemps ();
+
+ if (item == error_mark_node || *length == error_mark_node)
+ {
+ item = *length = error_mark_node;
+ break;
+ }
+
+ if ((ffebld_size_known (ffebld_left (expr))
+ == FFETARGET_charactersizeNONE)
+ || (ffebld_size_known (ffebld_left (expr)) < (ffebld_size (expr))))
+ { /* Possible blank-padding needed, copy into
+ temporary. */
+ tree tempvar;
+ tree args;
+ tree newlen;
+
+ assert (ffecom_pending_calls_ != 0);
+ tempvar = ffecom_push_tempvar (char_type_node,
+ ffebld_size (expr), -1, TRUE);
+ tempvar = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (tempvar)),
+ tempvar);
+
+ newlen = build_int_2 (ffebld_size (expr), 0);
+ TREE_TYPE (newlen) = ffecom_f2c_ftnlen_type_node;
+
+ args = build_tree_list (NULL_TREE, tempvar);
+ TREE_CHAIN (args) = build_tree_list (NULL_TREE, item);
+ TREE_CHAIN (TREE_CHAIN (args)) = build_tree_list (NULL_TREE, newlen);
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (args)))
+ = build_tree_list (NULL_TREE, *length);
+
+ item = ffecom_call_gfrt (FFECOM_gfrtCOPY, args);
+ TREE_SIDE_EFFECTS (item) = 1;
+ item = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (tempvar), fold (item),
+ tempvar);
+ *length = newlen;
+ }
+ else
+ { /* Just truncate the length. */
+ *length = build_int_2 (ffebld_size (expr), 0);
+ TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node;
+ }
+ break;
+
+ default:
+ assert ("bad op for single char arg expr" == NULL);
+ item = NULL_TREE;
+ break;
+ }
+
+ *xitem = item;
+}
+#endif
+
+/* Check the size of the type to be sure it doesn't overflow the
+ "portable" capacities of the compiler back end. `dummy' types
+ can generally overflow the normal sizes as long as the computations
+ themselves don't overflow. A particular target of the back end
+ must still enforce its size requirements, though, and the back
+ end takes care of this in stor-layout.c. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_check_size_overflow_ (ffesymbol s, tree type, bool dummy)
+{
+ if (TREE_CODE (type) == ERROR_MARK)
+ return type;
+
+ if (TYPE_SIZE (type) == NULL_TREE)
+ return type;
+
+ if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ return type;
+
+ if ((tree_int_cst_sgn (TYPE_SIZE (type)) < 0)
+ || (!dummy && (((TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0))
+ || TREE_OVERFLOW (TYPE_SIZE (type)))))
+ {
+ ffebad_start (FFEBAD_ARRAY_LARGE);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_here (0, ffesymbol_where_line (s), ffesymbol_where_column (s));
+ ffebad_finish ();
+
+ return error_mark_node;
+ }
+
+ return type;
+}
+#endif
+
+/* Builds a length argument (PARM_DECL). Also wraps type in an array type
+ where the dimension info is (1:size) where <size> is ffesymbol_size(s) if
+ known, length_arg if not known (FFETARGET_charactersizeNONE). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_char_enhance_arg_ (tree *xtype, ffesymbol s)
+{
+ ffetargetCharacterSize sz = ffesymbol_size (s);
+ tree highval;
+ tree tlen;
+ tree type = *xtype;
+
+ if (ffesymbol_where (s) == FFEINFO_whereCONSTANT)
+ tlen = NULL_TREE; /* A statement function, no length passed. */
+ else
+ {
+ if (ffesymbol_where (s) == FFEINFO_whereDUMMY)
+ tlen = ffecom_get_invented_identifier ("__g77_length_%s",
+ ffesymbol_text (s), 0);
+ else
+ tlen = ffecom_get_invented_identifier ("__g77_%s",
+ "length", 0);
+ tlen = build_decl (PARM_DECL, tlen, ffecom_f2c_ftnlen_type_node);
+#if BUILT_FOR_270
+ DECL_ARTIFICIAL (tlen) = 1;
+#endif
+ }
+
+ if (sz == FFETARGET_charactersizeNONE)
+ {
+ assert (tlen != NULL_TREE);
+ highval = variable_size (tlen);
+ }
+ else
+ {
+ highval = build_int_2 (sz, 0);
+ TREE_TYPE (highval) = ffecom_f2c_ftnlen_type_node;
+ }
+
+ type = build_array_type (type,
+ build_range_type (ffecom_f2c_ftnlen_type_node,
+ ffecom_f2c_ftnlen_one_node,
+ highval));
+
+ *xtype = type;
+ return tlen;
+}
+
+#endif
+/* ffecom_concat_list_gather_ -- Gather list of concatenated string exprs
+
+ ffecomConcatList_ catlist;
+ ffebld expr; // expr of CHARACTER basictype.
+ ffetargetCharacterSize max; // max chars to gather or _...NONE if no max
+ catlist = ffecom_concat_list_gather_(catlist,expr,max);
+
+ Scans expr for character subexpressions, updates and returns catlist
+ accordingly. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static ffecomConcatList_
+ffecom_concat_list_gather_ (ffecomConcatList_ catlist, ffebld expr,
+ ffetargetCharacterSize max)
+{
+ ffetargetCharacterSize sz;
+
+recurse: /* :::::::::::::::::::: */
+
+ if (expr == NULL)
+ return catlist;
+
+ if ((max != FFETARGET_charactersizeNONE) && (catlist.minlen >= max))
+ return catlist; /* Don't append any more items. */
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opCONTER:
+ case FFEBLD_opSYMTER:
+ case FFEBLD_opARRAYREF:
+ case FFEBLD_opFUNCREF:
+ case FFEBLD_opSUBSTR:
+ case FFEBLD_opCONVERT: /* Callers should strip this off beforehand
+ if they don't need to preserve it. */
+ if (catlist.count == catlist.max)
+ { /* Make a (larger) list. */
+ ffebld *newx;
+ int newmax;
+
+ newmax = (catlist.max == 0) ? 8 : catlist.max * 2;
+ newx = malloc_new_ks (malloc_pool_image (), "catlist",
+ newmax * sizeof (newx[0]));
+ if (catlist.max != 0)
+ {
+ memcpy (newx, catlist.exprs, catlist.max * sizeof (newx[0]));
+ malloc_kill_ks (malloc_pool_image (), catlist.exprs,
+ catlist.max * sizeof (newx[0]));
+ }
+ catlist.max = newmax;
+ catlist.exprs = newx;
+ }
+ if ((sz = ffebld_size_known (expr)) != FFETARGET_charactersizeNONE)
+ catlist.minlen += sz;
+ else
+ ++catlist.minlen; /* Not true for F90; can be 0 length. */
+ if ((sz = ffebld_size_max (expr)) == FFETARGET_charactersizeNONE)
+ catlist.maxlen = sz;
+ else
+ catlist.maxlen += sz;
+ if ((max != FFETARGET_charactersizeNONE) && (catlist.minlen > max))
+ { /* This item overlaps (or is beyond) the end
+ of the destination. */
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opCONTER:
+ case FFEBLD_opSYMTER:
+ case FFEBLD_opARRAYREF:
+ case FFEBLD_opFUNCREF:
+ case FFEBLD_opSUBSTR:
+ break; /* ~~Do useful truncations here. */
+
+ default:
+ assert ("op changed or inconsistent switches!" == NULL);
+ break;
+ }
+ }
+ catlist.exprs[catlist.count++] = expr;
+ return catlist;
+
+ case FFEBLD_opPAREN:
+ expr = ffebld_left (expr);
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFEBLD_opCONCATENATE:
+ catlist = ffecom_concat_list_gather_ (catlist, ffebld_left (expr), max);
+ expr = ffebld_right (expr);
+ goto recurse; /* :::::::::::::::::::: */
+
+#if 0 /* Breaks passing small actual arg to larger
+ dummy arg of sfunc */
+ case FFEBLD_opCONVERT:
+ expr = ffebld_left (expr);
+ {
+ ffetargetCharacterSize cmax;
+
+ cmax = catlist.len + ffebld_size_known (expr);
+
+ if ((max == FFETARGET_charactersizeNONE) || (max > cmax))
+ max = cmax;
+ }
+ goto recurse; /* :::::::::::::::::::: */
+#endif
+
+ case FFEBLD_opANY:
+ return catlist;
+
+ default:
+ assert ("bad op in _gather_" == NULL);
+ return catlist;
+ }
+}
+
+#endif
+/* ffecom_concat_list_kill_ -- Kill list of concatenated string exprs
+
+ ffecomConcatList_ catlist;
+ ffecom_concat_list_kill_(catlist);
+
+ Anything allocated within the list info is deallocated. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_concat_list_kill_ (ffecomConcatList_ catlist)
+{
+ if (catlist.max != 0)
+ malloc_kill_ks (malloc_pool_image (), catlist.exprs,
+ catlist.max * sizeof (catlist.exprs[0]));
+}
+
+#endif
+/* ffecom_concat_list_new_ -- Make list of concatenated string exprs
+
+ ffecomConcatList_ catlist;
+ ffebld expr; // Root expr of CHARACTER basictype.
+ ffetargetCharacterSize max; // max chars to gather or _...NONE if no max
+ catlist = ffecom_concat_list_new_(expr,max);
+
+ Returns a flattened list of concatenated subexpressions given a
+ tree of such expressions. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static ffecomConcatList_
+ffecom_concat_list_new_ (ffebld expr, ffetargetCharacterSize max)
+{
+ ffecomConcatList_ catlist;
+
+ catlist.maxlen = catlist.minlen = catlist.max = catlist.count = 0;
+ return ffecom_concat_list_gather_ (catlist, expr, max);
+}
+
+#endif
+
+/* Provide some kind of useful info on member of aggregate area,
+ since current g77/gcc technology does not provide debug info
+ on these members. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_debug_kludge_ (tree aggr, char *aggr_type, ffesymbol member,
+ tree member_type UNUSED, ffetargetOffset offset)
+{
+ tree value;
+ tree decl;
+ int len;
+ char *buff;
+ char space[120];
+#if 0
+ tree type_id;
+
+ for (type_id = member_type;
+ TREE_CODE (type_id) != IDENTIFIER_NODE;
+ )
+ {
+ switch (TREE_CODE (type_id))
+ {
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ type_id = TYPE_NAME (type_id);
+ break;
+
+ case ARRAY_TYPE:
+ case COMPLEX_TYPE:
+ type_id = TREE_TYPE (type_id);
+ break;
+
+ default:
+ assert ("no IDENTIFIER_NODE for type!" == NULL);
+ type_id = error_mark_node;
+ break;
+ }
+ }
+#endif
+
+ if (ffecom_transform_only_dummies_
+ || !ffe_is_debug_kludge ())
+ return; /* Can't do this yet, maybe later. */
+
+ len = 60
+ + strlen (aggr_type)
+ + IDENTIFIER_LENGTH (DECL_NAME (aggr));
+#if 0
+ + IDENTIFIER_LENGTH (type_id);
+#endif
+
+ if (((size_t) len) >= ARRAY_SIZE (space))
+ buff = malloc_new_ks (malloc_pool_image (), "debug_kludge", len + 1);
+ else
+ buff = &space[0];
+
+ sprintf (&buff[0], "At (%s) `%s' plus %ld bytes",
+ aggr_type,
+ IDENTIFIER_POINTER (DECL_NAME (aggr)),
+ (long int) offset);
+
+ value = build_string (len, buff);
+ TREE_TYPE (value)
+ = build_type_variant (build_array_type (char_type_node,
+ build_range_type
+ (integer_type_node,
+ integer_one_node,
+ build_int_2 (strlen (buff), 0))),
+ 1, 0);
+ decl = build_decl (VAR_DECL,
+ ffecom_get_identifier_ (ffesymbol_text (member)),
+ TREE_TYPE (value));
+ TREE_CONSTANT (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ DECL_INITIAL (decl) = error_mark_node;
+ DECL_IN_SYSTEM_HEADER (decl) = 1; /* Don't let -Wunused complain. */
+ decl = start_decl (decl, FALSE);
+ finish_decl (decl, value, FALSE);
+
+ if (buff != &space[0])
+ malloc_kill_ks (malloc_pool_image (), buff, len + 1);
+}
+#endif
+
+/* ffecom_do_entry_ -- Do compilation of a particular entrypoint
+
+ ffesymbol fn; // the SUBROUTINE, FUNCTION, or ENTRY symbol itself
+ int i; // entry# for this entrypoint (used by master fn)
+ ffecom_do_entrypoint_(s,i);
+
+ Makes a public entry point that calls our private master fn (already
+ compiled). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_do_entry_ (ffesymbol fn, int entrynum)
+{
+ ffebld item;
+ tree type; /* Type of function. */
+ tree multi_retval; /* Var holding return value (union). */
+ tree result; /* Var holding result. */
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffeglobal g;
+ ffeglobalType gt;
+ bool charfunc; /* All entry points return same type
+ CHARACTER. */
+ bool cmplxfunc; /* Use f2c way of returning COMPLEX. */
+ bool multi; /* Master fn has multiple return types. */
+ bool altreturning = FALSE; /* This entry point has alternate returns. */
+ int yes;
+ int old_lineno = lineno;
+ char *old_input_filename = input_filename;
+
+ input_filename = ffesymbol_where_filename (fn);
+ lineno = ffesymbol_where_filelinenum (fn);
+
+ /* c-parse.y indeed does call suspend_momentary and not only ignores the
+ return value, but also never calls resume_momentary, when starting an
+ outer function (see "fndef:", "setspecs:", and so on). So g77 does the
+ same thing. It shouldn't be a problem since start_function calls
+ temporary_allocation, but it might be necessary. If it causes a problem
+ here, then maybe there's a bug lurking in gcc. NOTE: This identical
+ comment appears twice in thist file. */
+
+ suspend_momentary ();
+
+ ffecom_doing_entry_ = TRUE; /* Don't bother with array dimensions. */
+
+ switch (ffecom_primary_entry_kind_)
+ {
+ case FFEINFO_kindFUNCTION:
+
+ /* Determine actual return type for function. */
+
+ gt = FFEGLOBAL_typeFUNC;
+ bt = ffesymbol_basictype (fn);
+ kt = ffesymbol_kindtype (fn);
+ if (bt == FFEINFO_basictypeNONE)
+ {
+ ffeimplic_establish_symbol (fn);
+ if (ffesymbol_funcresult (fn) != NULL)
+ ffeimplic_establish_symbol (ffesymbol_funcresult (fn));
+ bt = ffesymbol_basictype (fn);
+ kt = ffesymbol_kindtype (fn);
+ }
+
+ if (bt == FFEINFO_basictypeCHARACTER)
+ charfunc = TRUE, cmplxfunc = FALSE;
+ else if ((bt == FFEINFO_basictypeCOMPLEX)
+ && ffesymbol_is_f2c (fn))
+ charfunc = FALSE, cmplxfunc = TRUE;
+ else
+ charfunc = cmplxfunc = FALSE;
+
+ if (charfunc)
+ type = ffecom_tree_fun_type_void;
+ else if (ffesymbol_is_f2c (fn))
+ type = ffecom_tree_fun_type[bt][kt];
+ else
+ type = build_function_type (ffecom_tree_type[bt][kt], NULL_TREE);
+
+ if ((type == NULL_TREE)
+ || (TREE_TYPE (type) == NULL_TREE))
+ type = ffecom_tree_fun_type_void; /* _sym_exec_transition. */
+
+ multi = (ffecom_master_bt_ == FFEINFO_basictypeNONE);
+ break;
+
+ case FFEINFO_kindSUBROUTINE:
+ gt = FFEGLOBAL_typeSUBR;
+ bt = FFEINFO_basictypeNONE;
+ kt = FFEINFO_kindtypeNONE;
+ if (ffecom_is_altreturning_)
+ { /* Am _I_ altreturning? */
+ for (item = ffesymbol_dummyargs (fn);
+ item != NULL;
+ item = ffebld_trail (item))
+ {
+ if (ffebld_op (ffebld_head (item)) == FFEBLD_opSTAR)
+ {
+ altreturning = TRUE;
+ break;
+ }
+ }
+ if (altreturning)
+ type = ffecom_tree_subr_type;
+ else
+ type = ffecom_tree_fun_type_void;
+ }
+ else
+ type = ffecom_tree_fun_type_void;
+ charfunc = FALSE;
+ cmplxfunc = FALSE;
+ multi = FALSE;
+ break;
+
+ default:
+ assert ("say what??" == NULL);
+ /* Fall through. */
+ case FFEINFO_kindANY:
+ gt = FFEGLOBAL_typeANY;
+ bt = FFEINFO_basictypeNONE;
+ kt = FFEINFO_kindtypeNONE;
+ type = error_mark_node;
+ charfunc = FALSE;
+ cmplxfunc = FALSE;
+ multi = FALSE;
+ break;
+ }
+
+ /* build_decl uses the current lineno and input_filename to set the decl
+ source info. So, I've putzed with ffestd and ffeste code to update that
+ source info to point to the appropriate statement just before calling
+ ffecom_do_entrypoint (which calls this fn). */
+
+ start_function (ffecom_get_external_identifier_ (fn),
+ type,
+ 0, /* nested/inline */
+ 1); /* TREE_PUBLIC */
+
+ if (((g = ffesymbol_global (fn)) != NULL)
+ && ((ffeglobal_type (g) == gt)
+ || (ffeglobal_type (g) == FFEGLOBAL_typeEXT)))
+ {
+ ffeglobal_set_hook (g, current_function_decl);
+ }
+
+ /* Reset args in master arg list so they get retransitioned. */
+
+ for (item = ffecom_master_arglist_;
+ item != NULL;
+ item = ffebld_trail (item))
+ {
+ ffebld arg;
+ ffesymbol s;
+
+ arg = ffebld_head (item);
+ if (ffebld_op (arg) != FFEBLD_opSYMTER)
+ continue; /* Alternate return or some such thing. */
+ s = ffebld_symter (arg);
+ ffesymbol_hook (s).decl_tree = NULL_TREE;
+ ffesymbol_hook (s).length_tree = NULL_TREE;
+ }
+
+ /* Build dummy arg list for this entry point. */
+
+ yes = suspend_momentary ();
+
+ if (charfunc || cmplxfunc)
+ { /* Prepend arg for where result goes. */
+ tree type;
+ tree length;
+
+ if (charfunc)
+ type = ffecom_tree_type[FFEINFO_basictypeCHARACTER][kt];
+ else
+ type = ffecom_tree_type[FFEINFO_basictypeCOMPLEX][kt];
+
+ result = ffecom_get_invented_identifier ("__g77_%s",
+ "result", 0);
+
+ /* Make length arg _and_ enhance type info for CHAR arg itself. */
+
+ if (charfunc)
+ length = ffecom_char_enhance_arg_ (&type, fn);
+ else
+ length = NULL_TREE; /* Not ref'd if !charfunc. */
+
+ type = build_pointer_type (type);
+ result = build_decl (PARM_DECL, result, type);
+
+ push_parm_decl (result);
+ ffecom_func_result_ = result;
+
+ if (charfunc)
+ {
+ push_parm_decl (length);
+ ffecom_func_length_ = length;
+ }
+ }
+ else
+ result = DECL_RESULT (current_function_decl);
+
+ ffecom_push_dummy_decls_ (ffesymbol_dummyargs (fn), FALSE);
+
+ resume_momentary (yes);
+
+ store_parm_decls (0);
+
+ ffecom_start_compstmt_ ();
+
+ /* Make local var to hold return type for multi-type master fn. */
+
+ if (multi)
+ {
+ yes = suspend_momentary ();
+
+ multi_retval = ffecom_get_invented_identifier ("__g77_%s",
+ "multi_retval", 0);
+ multi_retval = build_decl (VAR_DECL, multi_retval,
+ ffecom_multi_type_node_);
+ multi_retval = start_decl (multi_retval, FALSE);
+ finish_decl (multi_retval, NULL_TREE, FALSE);
+
+ resume_momentary (yes);
+ }
+ else
+ multi_retval = NULL_TREE; /* Not actually ref'd if !multi. */
+
+ /* Here we emit the actual code for the entry point. */
+
+ {
+ ffebld list;
+ ffebld arg;
+ ffesymbol s;
+ tree arglist = NULL_TREE;
+ tree *plist = &arglist;
+ tree prepend;
+ tree call;
+ tree actarg;
+ tree master_fn;
+
+ /* Prepare actual arg list based on master arg list. */
+
+ for (list = ffecom_master_arglist_;
+ list != NULL;
+ list = ffebld_trail (list))
+ {
+ arg = ffebld_head (list);
+ if (ffebld_op (arg) != FFEBLD_opSYMTER)
+ continue;
+ s = ffebld_symter (arg);
+ if (ffesymbol_hook (s).decl_tree == NULL_TREE)
+ actarg = null_pointer_node; /* We don't have this arg. */
+ else
+ actarg = ffesymbol_hook (s).decl_tree;
+ *plist = build_tree_list (NULL_TREE, actarg);
+ plist = &TREE_CHAIN (*plist);
+ }
+
+ /* This code appends the length arguments for character
+ variables/arrays. */
+
+ for (list = ffecom_master_arglist_;
+ list != NULL;
+ list = ffebld_trail (list))
+ {
+ arg = ffebld_head (list);
+ if (ffebld_op (arg) != FFEBLD_opSYMTER)
+ continue;
+ s = ffebld_symter (arg);
+ if (ffesymbol_basictype (s) != FFEINFO_basictypeCHARACTER)
+ continue; /* Only looking for CHARACTER arguments. */
+ if (ffesymbol_kind (s) != FFEINFO_kindENTITY)
+ continue; /* Only looking for variables and arrays. */
+ if (ffesymbol_hook (s).length_tree == NULL_TREE)
+ actarg = ffecom_f2c_ftnlen_zero_node; /* We don't have this arg. */
+ else
+ actarg = ffesymbol_hook (s).length_tree;
+ *plist = build_tree_list (NULL_TREE, actarg);
+ plist = &TREE_CHAIN (*plist);
+ }
+
+ /* Prepend character-value return info to actual arg list. */
+
+ if (charfunc)
+ {
+ prepend = build_tree_list (NULL_TREE, ffecom_func_result_);
+ TREE_CHAIN (prepend)
+ = build_tree_list (NULL_TREE, ffecom_func_length_);
+ TREE_CHAIN (TREE_CHAIN (prepend)) = arglist;
+ arglist = prepend;
+ }
+
+ /* Prepend multi-type return value to actual arg list. */
+
+ if (multi)
+ {
+ prepend
+ = build_tree_list (NULL_TREE,
+ ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (multi_retval)),
+ multi_retval));
+ TREE_CHAIN (prepend) = arglist;
+ arglist = prepend;
+ }
+
+ /* Prepend my entry-point number to the actual arg list. */
+
+ prepend = build_tree_list (NULL_TREE, build_int_2 (entrynum, 0));
+ TREE_CHAIN (prepend) = arglist;
+ arglist = prepend;
+
+ /* Build the call to the master function. */
+
+ master_fn = ffecom_1_fn (ffecom_previous_function_decl_);
+ call = ffecom_3s (CALL_EXPR,
+ TREE_TYPE (TREE_TYPE (TREE_TYPE (master_fn))),
+ master_fn, arglist, NULL_TREE);
+
+ /* Decide whether the master function is a function or subroutine, and
+ handle the return value for my entry point. */
+
+ if (charfunc || ((ffecom_primary_entry_kind_ == FFEINFO_kindSUBROUTINE)
+ && !altreturning))
+ {
+ expand_expr_stmt (call);
+ expand_null_return ();
+ }
+ else if (multi && cmplxfunc)
+ {
+ expand_expr_stmt (call);
+ result
+ = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (result))),
+ result);
+ result = ffecom_modify (NULL_TREE, result,
+ ffecom_2 (COMPONENT_REF, TREE_TYPE (result),
+ multi_retval,
+ ffecom_multi_fields_[bt][kt]));
+ expand_expr_stmt (result);
+ expand_null_return ();
+ }
+ else if (multi)
+ {
+ expand_expr_stmt (call);
+ result
+ = ffecom_modify (NULL_TREE, result,
+ convert (TREE_TYPE (result),
+ ffecom_2 (COMPONENT_REF,
+ ffecom_tree_type[bt][kt],
+ multi_retval,
+ ffecom_multi_fields_[bt][kt])));
+ expand_return (result);
+ }
+ else if (cmplxfunc)
+ {
+ result
+ = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (result))),
+ result);
+ result = ffecom_modify (NULL_TREE, result, call);
+ expand_expr_stmt (result);
+ expand_null_return ();
+ }
+ else
+ {
+ result = ffecom_modify (NULL_TREE,
+ result,
+ convert (TREE_TYPE (result),
+ call));
+ expand_return (result);
+ }
+
+ clear_momentary ();
+ }
+
+ ffecom_end_compstmt_ ();
+
+ finish_function (0);
+
+ lineno = old_lineno;
+ input_filename = old_input_filename;
+
+ ffecom_doing_entry_ = FALSE;
+}
+
+#endif
+/* Transform expr into gcc tree with possible destination
+
+ Recursive descent on expr while making corresponding tree nodes and
+ attaching type info and such. If destination supplied and compatible
+ with temporary that would be made in certain cases, temporary isn't
+ made, destination used instead, and dest_used flag set TRUE. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_expr_ (ffebld expr, tree dest_tree, ffebld dest,
+ bool *dest_used, bool assignp, bool widenp)
+{
+ tree item;
+ tree list;
+ tree args;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ tree t;
+ tree dt; /* decl_tree for an ffesymbol. */
+ tree tree_type, tree_type_x;
+ tree left, right;
+ ffesymbol s;
+ enum tree_code code;
+
+ assert (expr != NULL);
+
+ if (dest_used != NULL)
+ *dest_used = FALSE;
+
+ bt = ffeinfo_basictype (ffebld_info (expr));
+ kt = ffeinfo_kindtype (ffebld_info (expr));
+ tree_type = ffecom_tree_type[bt][kt];
+
+ /* Widen integral arithmetic as desired while preserving signedness. */
+ tree_type_x = NULL_TREE;
+ if (widenp && tree_type
+ && GET_MODE_CLASS (TYPE_MODE (tree_type)) == MODE_INT
+ && TYPE_PRECISION (tree_type) < TYPE_PRECISION (sizetype))
+ tree_type_x = (TREE_UNSIGNED (tree_type) ? usizetype : ssizetype);
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opACCTER:
+ {
+ ffebitCount i;
+ ffebit bits = ffebld_accter_bits (expr);
+ ffetargetOffset source_offset = 0;
+ ffetargetOffset dest_offset = ffebld_accter_pad (expr);
+ tree purpose;
+
+ assert (dest_offset == 0
+ || (bt == FFEINFO_basictypeCHARACTER
+ && kt == FFEINFO_kindtypeCHARACTER1));
+
+ list = item = NULL;
+ for (;;)
+ {
+ ffebldConstantUnion cu;
+ ffebitCount length;
+ bool value;
+ ffebldConstantArray ca = ffebld_accter (expr);
+
+ ffebit_test (bits, source_offset, &value, &length);
+ if (length == 0)
+ break;
+
+ if (value)
+ {
+ for (i = 0; i < length; ++i)
+ {
+ cu = ffebld_constantarray_get (ca, bt, kt,
+ source_offset + i);
+
+ t = ffecom_constantunion (&cu, bt, kt, tree_type);
+
+ if (i == 0
+ && dest_offset != 0)
+ purpose = build_int_2 (dest_offset, 0);
+ else
+ purpose = NULL_TREE;
+
+ if (list == NULL_TREE)
+ list = item = build_tree_list (purpose, t);
+ else
+ {
+ TREE_CHAIN (item) = build_tree_list (purpose, t);
+ item = TREE_CHAIN (item);
+ }
+ }
+ }
+ source_offset += length;
+ dest_offset += length;
+ }
+ }
+
+ item = build_int_2 ((ffebld_accter_size (expr)
+ + ffebld_accter_pad (expr)) - 1, 0);
+ ffebit_kill (ffebld_accter_bits (expr));
+ TREE_TYPE (item) = ffecom_integer_type_node;
+ item
+ = build_array_type
+ (tree_type,
+ build_range_type (ffecom_integer_type_node,
+ ffecom_integer_zero_node,
+ item));
+ list = build (CONSTRUCTOR, item, NULL_TREE, list);
+ TREE_CONSTANT (list) = 1;
+ TREE_STATIC (list) = 1;
+ return list;
+
+ case FFEBLD_opARRTER:
+ {
+ ffetargetOffset i;
+
+ list = NULL_TREE;
+ if (ffebld_arrter_pad (expr) == 0)
+ item = NULL_TREE;
+ else
+ {
+ assert (bt == FFEINFO_basictypeCHARACTER
+ && kt == FFEINFO_kindtypeCHARACTER1);
+
+ /* Becomes PURPOSE first time through loop. */
+ item = build_int_2 (ffebld_arrter_pad (expr), 0);
+ }
+
+ for (i = 0; i < ffebld_arrter_size (expr); ++i)
+ {
+ ffebldConstantUnion cu
+ = ffebld_constantarray_get (ffebld_arrter (expr), bt, kt, i);
+
+ t = ffecom_constantunion (&cu, bt, kt, tree_type);
+
+ if (list == NULL_TREE)
+ /* Assume item is PURPOSE first time through loop. */
+ list = item = build_tree_list (item, t);
+ else
+ {
+ TREE_CHAIN (item) = build_tree_list (NULL_TREE, t);
+ item = TREE_CHAIN (item);
+ }
+ }
+ }
+
+ item = build_int_2 ((ffebld_arrter_size (expr)
+ + ffebld_arrter_pad (expr)) - 1, 0);
+ TREE_TYPE (item) = ffecom_integer_type_node;
+ item
+ = build_array_type
+ (tree_type,
+ build_range_type (ffecom_integer_type_node,
+ ffecom_integer_zero_node,
+ item));
+ list = build (CONSTRUCTOR, item, NULL_TREE, list);
+ TREE_CONSTANT (list) = 1;
+ TREE_STATIC (list) = 1;
+ return list;
+
+ case FFEBLD_opCONTER:
+ assert (ffebld_conter_pad (expr) == 0);
+ item
+ = ffecom_constantunion (&ffebld_constant_union (ffebld_conter (expr)),
+ bt, kt, tree_type);
+ return item;
+
+ case FFEBLD_opSYMTER:
+ if ((ffebld_symter_generic (expr) != FFEINTRIN_genNONE)
+ || (ffebld_symter_specific (expr) != FFEINTRIN_specNONE))
+ return ffecom_ptr_to_expr (expr); /* Same as %REF(intrinsic). */
+ s = ffebld_symter (expr);
+ t = ffesymbol_hook (s).decl_tree;
+
+ if (assignp)
+ { /* ASSIGN'ed-label expr. */
+ if (ffe_is_ugly_assign ())
+ {
+ /* User explicitly wants ASSIGN'ed variables to be at the same
+ memory address as the variables when used in non-ASSIGN
+ contexts. That can make old, arcane, non-standard code
+ work, but don't try to do it when a pointer wouldn't fit
+ in the normal variable (take other approach, and warn,
+ instead). */
+
+ if (t == NULL_TREE)
+ {
+ s = ffecom_sym_transform_ (s);
+ t = ffesymbol_hook (s).decl_tree;
+ assert (t != NULL_TREE);
+ }
+
+ if (t == error_mark_node)
+ return t;
+
+ if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (t)))
+ >= GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (null_pointer_node))))
+ {
+ if (ffesymbol_hook (s).addr)
+ t = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (t))), t);
+ return t;
+ }
+
+ if (ffesymbol_hook (s).assign_tree == NULL_TREE)
+ {
+ ffebad_start_msg ("ASSIGN'ed label cannot fit into `%A' at %0 -- using wider sibling",
+ FFEBAD_severityWARNING);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_here (0, ffesymbol_where_line (s),
+ ffesymbol_where_column (s));
+ ffebad_finish ();
+ }
+ }
+
+ /* Don't use the normal variable's tree for ASSIGN, though mark
+ it as in the system header (housekeeping). Use an explicit,
+ specially created sibling that is known to be wide enough
+ to hold pointers to labels. */
+
+ if (t != NULL_TREE
+ && TREE_CODE (t) == VAR_DECL)
+ DECL_IN_SYSTEM_HEADER (t) = 1; /* Don't let -Wunused complain. */
+
+ t = ffesymbol_hook (s).assign_tree;
+ if (t == NULL_TREE)
+ {
+ s = ffecom_sym_transform_assign_ (s);
+ t = ffesymbol_hook (s).assign_tree;
+ assert (t != NULL_TREE);
+ }
+ }
+ else
+ {
+ if (t == NULL_TREE)
+ {
+ s = ffecom_sym_transform_ (s);
+ t = ffesymbol_hook (s).decl_tree;
+ assert (t != NULL_TREE);
+ }
+ if (ffesymbol_hook (s).addr)
+ t = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (t))), t);
+ }
+ return t;
+
+ case FFEBLD_opARRAYREF:
+ {
+ ffebld dims[FFECOM_dimensionsMAX];
+#if FFECOM_FASTER_ARRAY_REFS
+ tree array;
+#endif
+ int i;
+
+#if FFECOM_FASTER_ARRAY_REFS
+ t = ffecom_ptr_to_expr (ffebld_left (expr));
+#else
+ t = ffecom_expr (ffebld_left (expr));
+#endif
+ if (t == error_mark_node)
+ return t;
+
+ if ((ffeinfo_where (ffebld_info (expr)) == FFEINFO_whereFLEETING)
+ && !mark_addressable (t))
+ return error_mark_node; /* Make sure non-const ref is to
+ non-reg. */
+
+ /* Build up ARRAY_REFs in reverse order (since we're column major
+ here in Fortran land). */
+
+ for (i = 0, expr = ffebld_right (expr);
+ expr != NULL;
+ expr = ffebld_trail (expr))
+ dims[i++] = ffebld_head (expr);
+
+#if FFECOM_FASTER_ARRAY_REFS
+ for (--i, array = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (t)));
+ i >= 0;
+ --i, array = TYPE_MAIN_VARIANT (TREE_TYPE (array)))
+ t = ffecom_2 (PLUS_EXPR,
+ build_pointer_type (TREE_TYPE (array)),
+ t,
+ size_binop (MULT_EXPR,
+ size_in_bytes (TREE_TYPE (array)),
+ size_binop (MINUS_EXPR,
+ ffecom_expr (dims[i]),
+ TYPE_MIN_VALUE (TYPE_DOMAIN (array)))));
+ t = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (t))),
+ t);
+#else
+ while (i > 0)
+ t = ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (t))),
+ t,
+ ffecom_expr_ (dims[--i], NULL, NULL, NULL, FALSE, TRUE));
+#endif
+
+ return t;
+ }
+
+ case FFEBLD_opUPLUS:
+ left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp);
+ return ffecom_1 (NOP_EXPR, tree_type, left);
+
+ case FFEBLD_opPAREN: /* ~~~Make sure Fortran rules respected here */
+ left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp);
+ return ffecom_1 (NOP_EXPR, tree_type, left);
+
+ case FFEBLD_opUMINUS:
+ left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp);
+ if (tree_type_x)
+ {
+ tree_type = tree_type_x;
+ left = convert (tree_type, left);
+ }
+ return ffecom_1 (NEGATE_EXPR, tree_type, left);
+
+ case FFEBLD_opADD:
+ left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp);
+ right = ffecom_expr_ (ffebld_right (expr), NULL, NULL, NULL, FALSE, widenp);
+ if (tree_type_x)
+ {
+ tree_type = tree_type_x;
+ left = convert (tree_type, left);
+ right = convert (tree_type, right);
+ }
+ return ffecom_2 (PLUS_EXPR, tree_type, left, right);
+
+ case FFEBLD_opSUBTRACT:
+ left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp);
+ right = ffecom_expr_ (ffebld_right (expr), NULL, NULL, NULL, FALSE, widenp);
+ if (tree_type_x)
+ {
+ tree_type = tree_type_x;
+ left = convert (tree_type, left);
+ right = convert (tree_type, right);
+ }
+ return ffecom_2 (MINUS_EXPR, tree_type, left, right);
+
+ case FFEBLD_opMULTIPLY:
+ left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp);
+ right = ffecom_expr_ (ffebld_right (expr), NULL, NULL, NULL, FALSE, widenp);
+ if (tree_type_x)
+ {
+ tree_type = tree_type_x;
+ left = convert (tree_type, left);
+ right = convert (tree_type, right);
+ }
+ return ffecom_2 (MULT_EXPR, tree_type, left, right);
+
+ case FFEBLD_opDIVIDE:
+ left = ffecom_expr_ (ffebld_left (expr), NULL, NULL, NULL, FALSE, widenp);
+ right = ffecom_expr_ (ffebld_right (expr), NULL, NULL, NULL, FALSE, widenp);
+ if (tree_type_x)
+ {
+ tree_type = tree_type_x;
+ left = convert (tree_type, left);
+ right = convert (tree_type, right);
+ }
+ return ffecom_tree_divide_ (tree_type, left, right,
+ dest_tree, dest, dest_used);
+
+ case FFEBLD_opPOWER:
+ {
+ ffebld left = ffebld_left (expr);
+ ffebld right = ffebld_right (expr);
+ ffecomGfrt code;
+ ffeinfoKindtype rtkt;
+ ffeinfoKindtype ltkt;
+
+ switch (ffeinfo_basictype (ffebld_info (right)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ if (1 || optimize)
+ {
+ item = ffecom_expr_power_integer_ (left, right);
+ if (item != NULL_TREE)
+ return item;
+ }
+
+ rtkt = FFEINFO_kindtypeINTEGER1;
+ switch (ffeinfo_basictype (ffebld_info (left)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ if ((ffeinfo_kindtype (ffebld_info (left))
+ == FFEINFO_kindtypeINTEGER4)
+ || (ffeinfo_kindtype (ffebld_info (right))
+ == FFEINFO_kindtypeINTEGER4))
+ {
+ code = FFECOM_gfrtPOW_QQ;
+ ltkt = FFEINFO_kindtypeINTEGER4;
+ rtkt = FFEINFO_kindtypeINTEGER4;
+ }
+ else
+ {
+ code = FFECOM_gfrtPOW_II;
+ ltkt = FFEINFO_kindtypeINTEGER1;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ if (ffeinfo_kindtype (ffebld_info (left))
+ == FFEINFO_kindtypeREAL1)
+ {
+ code = FFECOM_gfrtPOW_RI;
+ ltkt = FFEINFO_kindtypeREAL1;
+ }
+ else
+ {
+ code = FFECOM_gfrtPOW_DI;
+ ltkt = FFEINFO_kindtypeREAL2;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ if (ffeinfo_kindtype (ffebld_info (left))
+ == FFEINFO_kindtypeREAL1)
+ {
+ code = FFECOM_gfrtPOW_CI; /* Overlapping result okay. */
+ ltkt = FFEINFO_kindtypeREAL1;
+ }
+ else
+ {
+ code = FFECOM_gfrtPOW_ZI; /* Overlapping result okay. */
+ ltkt = FFEINFO_kindtypeREAL2;
+ }
+ break;
+
+ default:
+ assert ("bad pow_*i" == NULL);
+ code = FFECOM_gfrtPOW_CI; /* Overlapping result okay. */
+ ltkt = FFEINFO_kindtypeREAL1;
+ break;
+ }
+ if (ffeinfo_kindtype (ffebld_info (left)) != ltkt)
+ left = ffeexpr_convert (left, NULL, NULL,
+ ffeinfo_basictype (ffebld_info (left)),
+ ltkt, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ if (ffeinfo_kindtype (ffebld_info (right)) != rtkt)
+ right = ffeexpr_convert (right, NULL, NULL,
+ FFEINFO_basictypeINTEGER,
+ rtkt, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ case FFEINFO_basictypeREAL:
+ if (ffeinfo_kindtype (ffebld_info (left)) == FFEINFO_kindtypeREAL1)
+ left = ffeexpr_convert (left, NULL, NULL, FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREALDOUBLE, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ if (ffeinfo_kindtype (ffebld_info (right))
+ == FFEINFO_kindtypeREAL1)
+ right = ffeexpr_convert (right, NULL, NULL,
+ FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREALDOUBLE, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ code = FFECOM_gfrtPOW_DD;
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ if (ffeinfo_kindtype (ffebld_info (left)) == FFEINFO_kindtypeREAL1)
+ left = ffeexpr_convert (left, NULL, NULL,
+ FFEINFO_basictypeCOMPLEX,
+ FFEINFO_kindtypeREALDOUBLE, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ if (ffeinfo_kindtype (ffebld_info (right))
+ == FFEINFO_kindtypeREAL1)
+ right = ffeexpr_convert (right, NULL, NULL,
+ FFEINFO_basictypeCOMPLEX,
+ FFEINFO_kindtypeREALDOUBLE, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ code = FFECOM_gfrtPOW_ZZ; /* Overlapping result okay. */
+ break;
+
+ default:
+ assert ("bad pow_x*" == NULL);
+ code = FFECOM_gfrtPOW_II;
+ break;
+ }
+ return ffecom_call_binop_ (ffecom_gfrt_tree_ (code),
+ ffecom_gfrt_kindtype (code),
+ (ffe_is_f2c_library ()
+ && ffecom_gfrt_complex_[code]),
+ tree_type, left, right,
+ dest_tree, dest, dest_used,
+ NULL_TREE, FALSE);
+ }
+
+ case FFEBLD_opNOT:
+ switch (bt)
+ {
+ case FFEINFO_basictypeLOGICAL:
+ item = ffecom_truth_value_invert (ffecom_expr (ffebld_left (expr)));
+ return convert (tree_type, item);
+
+ case FFEINFO_basictypeINTEGER:
+ return ffecom_1 (BIT_NOT_EXPR, tree_type,
+ ffecom_expr (ffebld_left (expr)));
+
+ default:
+ assert ("NOT bad basictype" == NULL);
+ /* Fall through. */
+ case FFEINFO_basictypeANY:
+ return error_mark_node;
+ }
+ break;
+
+ case FFEBLD_opFUNCREF:
+ assert (ffeinfo_basictype (ffebld_info (expr))
+ != FFEINFO_basictypeCHARACTER);
+ /* Fall through. */
+ case FFEBLD_opSUBRREF:
+ if (ffeinfo_where (ffebld_info (ffebld_left (expr)))
+ == FFEINFO_whereINTRINSIC)
+ { /* Invocation of an intrinsic. */
+ item = ffecom_expr_intrinsic_ (expr, dest_tree, dest,
+ dest_used);
+ return item;
+ }
+ s = ffebld_symter (ffebld_left (expr));
+ dt = ffesymbol_hook (s).decl_tree;
+ if (dt == NULL_TREE)
+ {
+ s = ffecom_sym_transform_ (s);
+ dt = ffesymbol_hook (s).decl_tree;
+ }
+ if (dt == error_mark_node)
+ return dt;
+
+ if (ffesymbol_hook (s).addr)
+ item = dt;
+ else
+ item = ffecom_1_fn (dt);
+
+ ffecom_push_calltemps ();
+ if (ffesymbol_where (s) == FFEINFO_whereCONSTANT)
+ args = ffecom_list_expr (ffebld_right (expr));
+ else
+ args = ffecom_list_ptr_to_expr (ffebld_right (expr));
+ ffecom_pop_calltemps ();
+
+ item = ffecom_call_ (item, kt,
+ ffesymbol_is_f2c (s)
+ && (bt == FFEINFO_basictypeCOMPLEX)
+ && (ffesymbol_where (s)
+ != FFEINFO_whereCONSTANT),
+ tree_type,
+ args,
+ dest_tree, dest, dest_used,
+ error_mark_node, FALSE);
+ TREE_SIDE_EFFECTS (item) = 1;
+ return item;
+
+ case FFEBLD_opAND:
+ switch (bt)
+ {
+ case FFEINFO_basictypeLOGICAL:
+ item
+ = ffecom_2 (TRUTH_ANDIF_EXPR, integer_type_node,
+ ffecom_truth_value (ffecom_expr (ffebld_left (expr))),
+ ffecom_truth_value (ffecom_expr (ffebld_right (expr))));
+ return convert (tree_type, item);
+
+ case FFEINFO_basictypeINTEGER:
+ return ffecom_2 (BIT_AND_EXPR, tree_type,
+ ffecom_expr (ffebld_left (expr)),
+ ffecom_expr (ffebld_right (expr)));
+
+ default:
+ assert ("AND bad basictype" == NULL);
+ /* Fall through. */
+ case FFEINFO_basictypeANY:
+ return error_mark_node;
+ }
+ break;
+
+ case FFEBLD_opOR:
+ switch (bt)
+ {
+ case FFEINFO_basictypeLOGICAL:
+ item
+ = ffecom_2 (TRUTH_ORIF_EXPR, integer_type_node,
+ ffecom_truth_value (ffecom_expr (ffebld_left (expr))),
+ ffecom_truth_value (ffecom_expr (ffebld_right (expr))));
+ return convert (tree_type, item);
+
+ case FFEINFO_basictypeINTEGER:
+ return ffecom_2 (BIT_IOR_EXPR, tree_type,
+ ffecom_expr (ffebld_left (expr)),
+ ffecom_expr (ffebld_right (expr)));
+
+ default:
+ assert ("OR bad basictype" == NULL);
+ /* Fall through. */
+ case FFEINFO_basictypeANY:
+ return error_mark_node;
+ }
+ break;
+
+ case FFEBLD_opXOR:
+ case FFEBLD_opNEQV:
+ switch (bt)
+ {
+ case FFEINFO_basictypeLOGICAL:
+ item
+ = ffecom_2 (NE_EXPR, integer_type_node,
+ ffecom_expr (ffebld_left (expr)),
+ ffecom_expr (ffebld_right (expr)));
+ return convert (tree_type, ffecom_truth_value (item));
+
+ case FFEINFO_basictypeINTEGER:
+ return ffecom_2 (BIT_XOR_EXPR, tree_type,
+ ffecom_expr (ffebld_left (expr)),
+ ffecom_expr (ffebld_right (expr)));
+
+ default:
+ assert ("XOR/NEQV bad basictype" == NULL);
+ /* Fall through. */
+ case FFEINFO_basictypeANY:
+ return error_mark_node;
+ }
+ break;
+
+ case FFEBLD_opEQV:
+ switch (bt)
+ {
+ case FFEINFO_basictypeLOGICAL:
+ item
+ = ffecom_2 (EQ_EXPR, integer_type_node,
+ ffecom_expr (ffebld_left (expr)),
+ ffecom_expr (ffebld_right (expr)));
+ return convert (tree_type, ffecom_truth_value (item));
+
+ case FFEINFO_basictypeINTEGER:
+ return
+ ffecom_1 (BIT_NOT_EXPR, tree_type,
+ ffecom_2 (BIT_XOR_EXPR, tree_type,
+ ffecom_expr (ffebld_left (expr)),
+ ffecom_expr (ffebld_right (expr))));
+
+ default:
+ assert ("EQV bad basictype" == NULL);
+ /* Fall through. */
+ case FFEINFO_basictypeANY:
+ return error_mark_node;
+ }
+ break;
+
+ case FFEBLD_opCONVERT:
+ if (ffebld_op (ffebld_left (expr)) == FFEBLD_opANY)
+ return error_mark_node;
+
+ switch (bt)
+ {
+ case FFEINFO_basictypeLOGICAL:
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeREAL:
+ return convert (tree_type, ffecom_expr (ffebld_left (expr)));
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr))))
+ {
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeLOGICAL:
+ case FFEINFO_basictypeREAL:
+ item = ffecom_expr (ffebld_left (expr));
+ if (item == error_mark_node)
+ return error_mark_node;
+ /* convert() takes care of converting to the subtype first,
+ at least in gcc-2.7.2. */
+ item = convert (tree_type, item);
+ return item;
+
+ case FFEINFO_basictypeCOMPLEX:
+ return convert (tree_type, ffecom_expr (ffebld_left (expr)));
+
+ default:
+ assert ("CONVERT COMPLEX bad basictype" == NULL);
+ /* Fall through. */
+ case FFEINFO_basictypeANY:
+ return error_mark_node;
+ }
+ break;
+
+ default:
+ assert ("CONVERT bad basictype" == NULL);
+ /* Fall through. */
+ case FFEINFO_basictypeANY:
+ return error_mark_node;
+ }
+ break;
+
+ case FFEBLD_opLT:
+ code = LT_EXPR;
+ goto relational; /* :::::::::::::::::::: */
+
+ case FFEBLD_opLE:
+ code = LE_EXPR;
+ goto relational; /* :::::::::::::::::::: */
+
+ case FFEBLD_opEQ:
+ code = EQ_EXPR;
+ goto relational; /* :::::::::::::::::::: */
+
+ case FFEBLD_opNE:
+ code = NE_EXPR;
+ goto relational; /* :::::::::::::::::::: */
+
+ case FFEBLD_opGT:
+ code = GT_EXPR;
+ goto relational; /* :::::::::::::::::::: */
+
+ case FFEBLD_opGE:
+ code = GE_EXPR;
+
+ relational: /* :::::::::::::::::::: */
+ switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr))))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeREAL:
+ item = ffecom_2 (code, integer_type_node,
+ ffecom_expr (ffebld_left (expr)),
+ ffecom_expr (ffebld_right (expr)));
+ return convert (tree_type, item);
+
+ case FFEINFO_basictypeCOMPLEX:
+ assert (code == EQ_EXPR || code == NE_EXPR);
+ {
+ tree real_type;
+ tree arg1 = ffecom_expr (ffebld_left (expr));
+ tree arg2 = ffecom_expr (ffebld_right (expr));
+
+ if (arg1 == error_mark_node || arg2 == error_mark_node)
+ return error_mark_node;
+
+ arg1 = ffecom_save_tree (arg1);
+ arg2 = ffecom_save_tree (arg2);
+
+ if (TREE_CODE (TREE_TYPE (arg1)) == COMPLEX_TYPE)
+ {
+ real_type = TREE_TYPE (TREE_TYPE (arg1));
+ assert (real_type == TREE_TYPE (TREE_TYPE (arg2)));
+ }
+ else
+ {
+ real_type = TREE_TYPE (TYPE_FIELDS (TREE_TYPE (arg1)));
+ assert (real_type == TREE_TYPE (TYPE_FIELDS (TREE_TYPE (arg2))));
+ }
+
+ item
+ = ffecom_2 (TRUTH_ANDIF_EXPR, integer_type_node,
+ ffecom_2 (EQ_EXPR, integer_type_node,
+ ffecom_1 (REALPART_EXPR, real_type, arg1),
+ ffecom_1 (REALPART_EXPR, real_type, arg2)),
+ ffecom_2 (EQ_EXPR, integer_type_node,
+ ffecom_1 (IMAGPART_EXPR, real_type, arg1),
+ ffecom_1 (IMAGPART_EXPR, real_type,
+ arg2)));
+ if (code == EQ_EXPR)
+ item = ffecom_truth_value (item);
+ else
+ item = ffecom_truth_value_invert (item);
+ return convert (tree_type, item);
+ }
+
+ case FFEINFO_basictypeCHARACTER:
+ ffecom_push_calltemps (); /* Even though we might not call. */
+
+ {
+ ffebld left = ffebld_left (expr);
+ ffebld right = ffebld_right (expr);
+ tree left_tree;
+ tree right_tree;
+ tree left_length;
+ tree right_length;
+
+ /* f2c run-time functions do the implicit blank-padding for us,
+ so we don't usually have to implement blank-padding ourselves.
+ (The exception is when we pass an argument to a separately
+ compiled statement function -- if we know the arg is not the
+ same length as the dummy, we must truncate or extend it. If
+ we "inline" statement functions, that necessity goes away as
+ well.)
+
+ Strip off the CONVERT operators that blank-pad. (Truncation by
+ CONVERT shouldn't happen here, but it can happen in
+ assignments.) */
+
+ while (ffebld_op (left) == FFEBLD_opCONVERT)
+ left = ffebld_left (left);
+ while (ffebld_op (right) == FFEBLD_opCONVERT)
+ right = ffebld_left (right);
+
+ left_tree = ffecom_arg_ptr_to_expr (left, &left_length);
+ right_tree = ffecom_arg_ptr_to_expr (right, &right_length);
+
+ if (left_tree == error_mark_node || left_length == error_mark_node
+ || right_tree == error_mark_node
+ || right_length == error_mark_node)
+ {
+ ffecom_pop_calltemps ();
+ return error_mark_node;
+ }
+
+ if ((ffebld_size_known (left) == 1)
+ && (ffebld_size_known (right) == 1))
+ {
+ left_tree
+ = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (left_tree))),
+ left_tree);
+ right_tree
+ = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (right_tree))),
+ right_tree);
+
+ item
+ = ffecom_2 (code, integer_type_node,
+ ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (left_tree))),
+ left_tree,
+ integer_one_node),
+ ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (right_tree))),
+ right_tree,
+ integer_one_node));
+ }
+ else
+ {
+ item = build_tree_list (NULL_TREE, left_tree);
+ TREE_CHAIN (item) = build_tree_list (NULL_TREE, right_tree);
+ TREE_CHAIN (TREE_CHAIN (item)) = build_tree_list (NULL_TREE,
+ left_length);
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (item)))
+ = build_tree_list (NULL_TREE, right_length);
+ item = ffecom_call_gfrt (FFECOM_gfrtCMP, item);
+ item = ffecom_2 (code, integer_type_node,
+ item,
+ convert (TREE_TYPE (item),
+ integer_zero_node));
+ }
+ item = convert (tree_type, item);
+ }
+
+ ffecom_pop_calltemps ();
+ return item;
+
+ default:
+ assert ("relational bad basictype" == NULL);
+ /* Fall through. */
+ case FFEINFO_basictypeANY:
+ return error_mark_node;
+ }
+ break;
+
+ case FFEBLD_opPERCENT_LOC:
+ item = ffecom_arg_ptr_to_expr (ffebld_left (expr), &list);
+ return convert (tree_type, item);
+
+ case FFEBLD_opITEM:
+ case FFEBLD_opSTAR:
+ case FFEBLD_opBOUNDS:
+ case FFEBLD_opREPEAT:
+ case FFEBLD_opLABTER:
+ case FFEBLD_opLABTOK:
+ case FFEBLD_opIMPDO:
+ case FFEBLD_opCONCATENATE:
+ case FFEBLD_opSUBSTR:
+ default:
+ assert ("bad op" == NULL);
+ /* Fall through. */
+ case FFEBLD_opANY:
+ return error_mark_node;
+ }
+
+#if 1
+ assert ("didn't think anything got here anymore!!" == NULL);
+#else
+ switch (ffebld_arity (expr))
+ {
+ case 2:
+ TREE_OPERAND (item, 0) = ffecom_expr (ffebld_left (expr));
+ TREE_OPERAND (item, 1) = ffecom_expr (ffebld_right (expr));
+ if (TREE_OPERAND (item, 0) == error_mark_node
+ || TREE_OPERAND (item, 1) == error_mark_node)
+ return error_mark_node;
+ break;
+
+ case 1:
+ TREE_OPERAND (item, 0) = ffecom_expr (ffebld_left (expr));
+ if (TREE_OPERAND (item, 0) == error_mark_node)
+ return error_mark_node;
+ break;
+
+ default:
+ break;
+ }
+
+ return fold (item);
+#endif
+}
+
+#endif
+/* Returns the tree that does the intrinsic invocation.
+
+ Note: this function applies only to intrinsics returning
+ CHARACTER*1 or non-CHARACTER results, and to intrinsic
+ subroutines. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_expr_intrinsic_ (ffebld expr, tree dest_tree,
+ ffebld dest, bool *dest_used)
+{
+ tree expr_tree;
+ tree saved_expr1; /* For those who need it. */
+ tree saved_expr2; /* For those who need it. */
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ tree tree_type;
+ tree arg1_type;
+ tree real_type; /* REAL type corresponding to COMPLEX. */
+ tree tempvar;
+ ffebld list = ffebld_right (expr); /* List of (some) args. */
+ ffebld arg1; /* For handy reference. */
+ ffebld arg2;
+ ffebld arg3;
+ ffeintrinImp codegen_imp;
+ ffecomGfrt gfrt;
+
+ assert (ffebld_op (ffebld_left (expr)) == FFEBLD_opSYMTER);
+
+ if (dest_used != NULL)
+ *dest_used = FALSE;
+
+ bt = ffeinfo_basictype (ffebld_info (expr));
+ kt = ffeinfo_kindtype (ffebld_info (expr));
+ tree_type = ffecom_tree_type[bt][kt];
+
+ if (list != NULL)
+ {
+ arg1 = ffebld_head (list);
+ if (arg1 != NULL && ffebld_op (arg1) == FFEBLD_opANY)
+ return error_mark_node;
+ if ((list = ffebld_trail (list)) != NULL)
+ {
+ arg2 = ffebld_head (list);
+ if (arg2 != NULL && ffebld_op (arg2) == FFEBLD_opANY)
+ return error_mark_node;
+ if ((list = ffebld_trail (list)) != NULL)
+ {
+ arg3 = ffebld_head (list);
+ if (arg3 != NULL && ffebld_op (arg3) == FFEBLD_opANY)
+ return error_mark_node;
+ }
+ else
+ arg3 = NULL;
+ }
+ else
+ arg2 = arg3 = NULL;
+ }
+ else
+ arg1 = arg2 = arg3 = NULL;
+
+ /* <list> ends up at the opITEM of the 3rd arg, or NULL if there are < 3
+ args. This is used by the MAX/MIN expansions. */
+
+ if (arg1 != NULL)
+ arg1_type = ffecom_tree_type
+ [ffeinfo_basictype (ffebld_info (arg1))]
+ [ffeinfo_kindtype (ffebld_info (arg1))];
+ else
+ arg1_type = NULL_TREE; /* Really not needed, but might catch bugs
+ here. */
+
+ /* There are several ways for each of the cases in the following switch
+ statements to exit (from simplest to use to most complicated):
+
+ break; (when expr_tree == NULL)
+
+ A standard call is made to the specific intrinsic just as if it had been
+ passed in as a dummy procedure and called as any old procedure. This
+ method can produce slower code but in some cases it's the easiest way for
+ now. However, if a (presumably faster) direct call is available,
+ that is used, so this is the easiest way in many more cases now.
+
+ gfrt = FFECOM_gfrtWHATEVER;
+ break;
+
+ gfrt contains the gfrt index of a library function to call, passing the
+ argument(s) by value rather than by reference. Used when a more
+ careful choice of library function is needed than that provided
+ by the vanilla `break;'.
+
+ return expr_tree;
+
+ The expr_tree has been completely set up and is ready to be returned
+ as is. No further actions are taken. Use this when the tree is not
+ in the simple form for one of the arity_n labels. */
+
+ /* For info on how the switch statement cases were written, see the files
+ enclosed in comments below the switch statement. */
+
+ codegen_imp = ffebld_symter_implementation (ffebld_left (expr));
+ gfrt = ffeintrin_gfrt_direct (codegen_imp);
+ if (gfrt == FFECOM_gfrt)
+ gfrt = ffeintrin_gfrt_indirect (codegen_imp);
+
+ switch (codegen_imp)
+ {
+ case FFEINTRIN_impABS:
+ case FFEINTRIN_impCABS:
+ case FFEINTRIN_impCDABS:
+ case FFEINTRIN_impDABS:
+ case FFEINTRIN_impIABS:
+ if (ffeinfo_basictype (ffebld_info (arg1))
+ == FFEINFO_basictypeCOMPLEX)
+ {
+ if (kt == FFEINFO_kindtypeREAL1)
+ gfrt = FFECOM_gfrtCABS;
+ else if (kt == FFEINFO_kindtypeREAL2)
+ gfrt = FFECOM_gfrtCDABS;
+ break;
+ }
+ return ffecom_1 (ABS_EXPR, tree_type,
+ convert (tree_type, ffecom_expr (arg1)));
+
+ case FFEINTRIN_impACOS:
+ case FFEINTRIN_impDACOS:
+ break;
+
+ case FFEINTRIN_impAIMAG:
+ case FFEINTRIN_impDIMAG:
+ case FFEINTRIN_impIMAGPART:
+ if (TREE_CODE (arg1_type) == COMPLEX_TYPE)
+ arg1_type = TREE_TYPE (arg1_type);
+ else
+ arg1_type = TREE_TYPE (TYPE_FIELDS (arg1_type));
+
+ return
+ convert (tree_type,
+ ffecom_1 (IMAGPART_EXPR, arg1_type,
+ ffecom_expr (arg1)));
+
+ case FFEINTRIN_impAINT:
+ case FFEINTRIN_impDINT:
+#if 0 /* ~~ someday implement FIX_TRUNC_EXPR
+ yielding same type as arg */
+ return ffecom_1 (FIX_TRUNC_EXPR, tree_type, ffecom_expr (arg1));
+#else /* in the meantime, must use floor to avoid range problems with ints */
+ /* r__1 = r1 >= 0 ? floor(r1) : -floor(-r1); */
+ saved_expr1 = ffecom_save_tree (ffecom_expr (arg1));
+ return
+ convert (tree_type,
+ ffecom_3 (COND_EXPR, double_type_node,
+ ffecom_truth_value
+ (ffecom_2 (GE_EXPR, integer_type_node,
+ saved_expr1,
+ convert (arg1_type,
+ ffecom_float_zero_))),
+ ffecom_call_gfrt (FFECOM_gfrtL_FLOOR,
+ build_tree_list (NULL_TREE,
+ convert (double_type_node,
+ saved_expr1))),
+ ffecom_1 (NEGATE_EXPR, double_type_node,
+ ffecom_call_gfrt (FFECOM_gfrtL_FLOOR,
+ build_tree_list (NULL_TREE,
+ convert (double_type_node,
+ ffecom_1 (NEGATE_EXPR,
+ arg1_type,
+ saved_expr1))))
+ ))
+ );
+#endif
+
+ case FFEINTRIN_impANINT:
+ case FFEINTRIN_impDNINT:
+#if 0 /* This way of doing it won't handle real
+ numbers of large magnitudes. */
+ saved_expr1 = ffecom_save_tree (ffecom_expr (arg1));
+ expr_tree = convert (tree_type,
+ convert (integer_type_node,
+ ffecom_3 (COND_EXPR, tree_type,
+ ffecom_truth_value
+ (ffecom_2 (GE_EXPR,
+ integer_type_node,
+ saved_expr1,
+ ffecom_float_zero_)),
+ ffecom_2 (PLUS_EXPR,
+ tree_type,
+ saved_expr1,
+ ffecom_float_half_),
+ ffecom_2 (MINUS_EXPR,
+ tree_type,
+ saved_expr1,
+ ffecom_float_half_))));
+ return expr_tree;
+#else /* So we instead call floor. */
+ /* r__1 = r1 >= 0 ? floor(r1 + .5) : -floor(.5 - r1) */
+ saved_expr1 = ffecom_save_tree (ffecom_expr (arg1));
+ return
+ convert (tree_type,
+ ffecom_3 (COND_EXPR, double_type_node,
+ ffecom_truth_value
+ (ffecom_2 (GE_EXPR, integer_type_node,
+ saved_expr1,
+ convert (arg1_type,
+ ffecom_float_zero_))),
+ ffecom_call_gfrt (FFECOM_gfrtL_FLOOR,
+ build_tree_list (NULL_TREE,
+ convert (double_type_node,
+ ffecom_2 (PLUS_EXPR,
+ arg1_type,
+ saved_expr1,
+ convert (arg1_type,
+ ffecom_float_half_))))),
+ ffecom_1 (NEGATE_EXPR, double_type_node,
+ ffecom_call_gfrt (FFECOM_gfrtL_FLOOR,
+ build_tree_list (NULL_TREE,
+ convert (double_type_node,
+ ffecom_2 (MINUS_EXPR,
+ arg1_type,
+ convert (arg1_type,
+ ffecom_float_half_),
+ saved_expr1)))))
+ )
+ );
+#endif
+
+ case FFEINTRIN_impASIN:
+ case FFEINTRIN_impDASIN:
+ case FFEINTRIN_impATAN:
+ case FFEINTRIN_impDATAN:
+ case FFEINTRIN_impATAN2:
+ case FFEINTRIN_impDATAN2:
+ break;
+
+ case FFEINTRIN_impCHAR:
+ case FFEINTRIN_impACHAR:
+ assert (ffecom_pending_calls_ != 0);
+ tempvar = ffecom_push_tempvar (char_type_node,
+ 1, -1, TRUE);
+ {
+ tree tmv = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (tempvar)));
+
+ expr_tree = ffecom_modify (tmv,
+ ffecom_2 (ARRAY_REF, tmv, tempvar,
+ integer_one_node),
+ convert (tmv, ffecom_expr (arg1)));
+ }
+ expr_tree = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (tempvar),
+ expr_tree,
+ tempvar);
+ expr_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (expr_tree)),
+ expr_tree);
+ return expr_tree;
+
+ case FFEINTRIN_impCMPLX:
+ case FFEINTRIN_impDCMPLX:
+ if (arg2 == NULL)
+ return
+ convert (tree_type, ffecom_expr (arg1));
+
+ real_type = ffecom_tree_type[FFEINFO_basictypeREAL][kt];
+ return
+ ffecom_2 (COMPLEX_EXPR, tree_type,
+ convert (real_type, ffecom_expr (arg1)),
+ convert (real_type,
+ ffecom_expr (arg2)));
+
+ case FFEINTRIN_impCOMPLEX:
+ return
+ ffecom_2 (COMPLEX_EXPR, tree_type,
+ ffecom_expr (arg1),
+ ffecom_expr (arg2));
+
+ case FFEINTRIN_impCONJG:
+ case FFEINTRIN_impDCONJG:
+ {
+ tree arg1_tree;
+
+ real_type = ffecom_tree_type[FFEINFO_basictypeREAL][kt];
+ arg1_tree = ffecom_save_tree (ffecom_expr (arg1));
+ return
+ ffecom_2 (COMPLEX_EXPR, tree_type,
+ ffecom_1 (REALPART_EXPR, real_type, arg1_tree),
+ ffecom_1 (NEGATE_EXPR, real_type,
+ ffecom_1 (IMAGPART_EXPR, real_type, arg1_tree)));
+ }
+
+ case FFEINTRIN_impCOS:
+ case FFEINTRIN_impCCOS:
+ case FFEINTRIN_impCDCOS:
+ case FFEINTRIN_impDCOS:
+ if (bt == FFEINFO_basictypeCOMPLEX)
+ {
+ if (kt == FFEINFO_kindtypeREAL1)
+ gfrt = FFECOM_gfrtCCOS; /* Overlapping result okay. */
+ else if (kt == FFEINFO_kindtypeREAL2)
+ gfrt = FFECOM_gfrtCDCOS; /* Overlapping result okay. */
+ }
+ break;
+
+ case FFEINTRIN_impCOSH:
+ case FFEINTRIN_impDCOSH:
+ break;
+
+ case FFEINTRIN_impDBLE:
+ case FFEINTRIN_impDFLOAT:
+ case FFEINTRIN_impDREAL:
+ case FFEINTRIN_impFLOAT:
+ case FFEINTRIN_impIDINT:
+ case FFEINTRIN_impIFIX:
+ case FFEINTRIN_impINT2:
+ case FFEINTRIN_impINT8:
+ case FFEINTRIN_impINT:
+ case FFEINTRIN_impLONG:
+ case FFEINTRIN_impREAL:
+ case FFEINTRIN_impSHORT:
+ case FFEINTRIN_impSNGL:
+ return convert (tree_type, ffecom_expr (arg1));
+
+ case FFEINTRIN_impDIM:
+ case FFEINTRIN_impDDIM:
+ case FFEINTRIN_impIDIM:
+ saved_expr1 = ffecom_save_tree (convert (tree_type,
+ ffecom_expr (arg1)));
+ saved_expr2 = ffecom_save_tree (convert (tree_type,
+ ffecom_expr (arg2)));
+ return
+ ffecom_3 (COND_EXPR, tree_type,
+ ffecom_truth_value
+ (ffecom_2 (GT_EXPR, integer_type_node,
+ saved_expr1,
+ saved_expr2)),
+ ffecom_2 (MINUS_EXPR, tree_type,
+ saved_expr1,
+ saved_expr2),
+ convert (tree_type, ffecom_float_zero_));
+
+ case FFEINTRIN_impDPROD:
+ return
+ ffecom_2 (MULT_EXPR, tree_type,
+ convert (tree_type, ffecom_expr (arg1)),
+ convert (tree_type, ffecom_expr (arg2)));
+
+ case FFEINTRIN_impEXP:
+ case FFEINTRIN_impCDEXP:
+ case FFEINTRIN_impCEXP:
+ case FFEINTRIN_impDEXP:
+ if (bt == FFEINFO_basictypeCOMPLEX)
+ {
+ if (kt == FFEINFO_kindtypeREAL1)
+ gfrt = FFECOM_gfrtCEXP; /* Overlapping result okay. */
+ else if (kt == FFEINFO_kindtypeREAL2)
+ gfrt = FFECOM_gfrtCDEXP; /* Overlapping result okay. */
+ }
+ break;
+
+ case FFEINTRIN_impICHAR:
+ case FFEINTRIN_impIACHAR:
+#if 0 /* The simple approach. */
+ ffecom_char_args_ (&expr_tree, &saved_expr1 /* Ignored */ , arg1);
+ expr_tree
+ = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (expr_tree))),
+ expr_tree);
+ expr_tree
+ = ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (expr_tree))),
+ expr_tree,
+ integer_one_node);
+ return convert (tree_type, expr_tree);
+#else /* The more interesting (and more optimal) approach. */
+ expr_tree = ffecom_intrinsic_ichar_ (tree_type, arg1, &saved_expr1);
+ expr_tree = ffecom_3 (COND_EXPR, tree_type,
+ saved_expr1,
+ expr_tree,
+ convert (tree_type, integer_zero_node));
+ return expr_tree;
+#endif
+
+ case FFEINTRIN_impINDEX:
+ break;
+
+ case FFEINTRIN_impLEN:
+#if 0
+ break; /* The simple approach. */
+#else
+ return ffecom_intrinsic_len_ (arg1); /* The more optimal approach. */
+#endif
+
+ case FFEINTRIN_impLGE:
+ case FFEINTRIN_impLGT:
+ case FFEINTRIN_impLLE:
+ case FFEINTRIN_impLLT:
+ break;
+
+ case FFEINTRIN_impLOG:
+ case FFEINTRIN_impALOG:
+ case FFEINTRIN_impCDLOG:
+ case FFEINTRIN_impCLOG:
+ case FFEINTRIN_impDLOG:
+ if (bt == FFEINFO_basictypeCOMPLEX)
+ {
+ if (kt == FFEINFO_kindtypeREAL1)
+ gfrt = FFECOM_gfrtCLOG; /* Overlapping result okay. */
+ else if (kt == FFEINFO_kindtypeREAL2)
+ gfrt = FFECOM_gfrtCDLOG; /* Overlapping result okay. */
+ }
+ break;
+
+ case FFEINTRIN_impLOG10:
+ case FFEINTRIN_impALOG10:
+ case FFEINTRIN_impDLOG10:
+ if (gfrt != FFECOM_gfrt)
+ break; /* Already picked one, stick with it. */
+
+ if (kt == FFEINFO_kindtypeREAL1)
+ gfrt = FFECOM_gfrtALOG10;
+ else if (kt == FFEINFO_kindtypeREAL2)
+ gfrt = FFECOM_gfrtDLOG10;
+ break;
+
+ case FFEINTRIN_impMAX:
+ case FFEINTRIN_impAMAX0:
+ case FFEINTRIN_impAMAX1:
+ case FFEINTRIN_impDMAX1:
+ case FFEINTRIN_impMAX0:
+ case FFEINTRIN_impMAX1:
+ if (bt != ffeinfo_basictype (ffebld_info (arg1)))
+ arg1_type = ffecom_widest_expr_type_ (ffebld_right (expr));
+ else
+ arg1_type = tree_type;
+ expr_tree = ffecom_2 (MAX_EXPR, arg1_type,
+ convert (arg1_type, ffecom_expr (arg1)),
+ convert (arg1_type, ffecom_expr (arg2)));
+ for (; list != NULL; list = ffebld_trail (list))
+ {
+ if ((ffebld_head (list) == NULL)
+ || (ffebld_op (ffebld_head (list)) == FFEBLD_opANY))
+ continue;
+ expr_tree = ffecom_2 (MAX_EXPR, arg1_type,
+ expr_tree,
+ convert (arg1_type,
+ ffecom_expr (ffebld_head (list))));
+ }
+ return convert (tree_type, expr_tree);
+
+ case FFEINTRIN_impMIN:
+ case FFEINTRIN_impAMIN0:
+ case FFEINTRIN_impAMIN1:
+ case FFEINTRIN_impDMIN1:
+ case FFEINTRIN_impMIN0:
+ case FFEINTRIN_impMIN1:
+ if (bt != ffeinfo_basictype (ffebld_info (arg1)))
+ arg1_type = ffecom_widest_expr_type_ (ffebld_right (expr));
+ else
+ arg1_type = tree_type;
+ expr_tree = ffecom_2 (MIN_EXPR, arg1_type,
+ convert (arg1_type, ffecom_expr (arg1)),
+ convert (arg1_type, ffecom_expr (arg2)));
+ for (; list != NULL; list = ffebld_trail (list))
+ {
+ if ((ffebld_head (list) == NULL)
+ || (ffebld_op (ffebld_head (list)) == FFEBLD_opANY))
+ continue;
+ expr_tree = ffecom_2 (MIN_EXPR, arg1_type,
+ expr_tree,
+ convert (arg1_type,
+ ffecom_expr (ffebld_head (list))));
+ }
+ return convert (tree_type, expr_tree);
+
+ case FFEINTRIN_impMOD:
+ case FFEINTRIN_impAMOD:
+ case FFEINTRIN_impDMOD:
+ if (bt != FFEINFO_basictypeREAL)
+ return ffecom_2 (TRUNC_MOD_EXPR, tree_type,
+ convert (tree_type, ffecom_expr (arg1)),
+ convert (tree_type, ffecom_expr (arg2)));
+
+ if (kt == FFEINFO_kindtypeREAL1)
+ gfrt = FFECOM_gfrtAMOD;
+ else if (kt == FFEINFO_kindtypeREAL2)
+ gfrt = FFECOM_gfrtDMOD;
+ break;
+
+ case FFEINTRIN_impNINT:
+ case FFEINTRIN_impIDNINT:
+#if 0 /* ~~ ideally FIX_ROUND_EXPR would be
+ implemented, but it ain't yet */
+ return ffecom_1 (FIX_ROUND_EXPR, tree_type, ffecom_expr (arg1));
+#else
+ /* i__1 = r1 >= 0 ? floor(r1 + .5) : -floor(.5 - r1); */
+ saved_expr1 = ffecom_save_tree (ffecom_expr (arg1));
+ return
+ convert (ffecom_integer_type_node,
+ ffecom_3 (COND_EXPR, arg1_type,
+ ffecom_truth_value
+ (ffecom_2 (GE_EXPR, integer_type_node,
+ saved_expr1,
+ convert (arg1_type,
+ ffecom_float_zero_))),
+ ffecom_2 (PLUS_EXPR, arg1_type,
+ saved_expr1,
+ convert (arg1_type,
+ ffecom_float_half_)),
+ ffecom_2 (MINUS_EXPR, arg1_type,
+ saved_expr1,
+ convert (arg1_type,
+ ffecom_float_half_))));
+#endif
+
+ case FFEINTRIN_impSIGN:
+ case FFEINTRIN_impDSIGN:
+ case FFEINTRIN_impISIGN:
+ {
+ tree arg2_tree = ffecom_expr (arg2);
+
+ saved_expr1
+ = ffecom_save_tree
+ (ffecom_1 (ABS_EXPR, tree_type,
+ convert (tree_type,
+ ffecom_expr (arg1))));
+ expr_tree
+ = ffecom_3 (COND_EXPR, tree_type,
+ ffecom_truth_value
+ (ffecom_2 (GE_EXPR, integer_type_node,
+ arg2_tree,
+ convert (TREE_TYPE (arg2_tree),
+ integer_zero_node))),
+ saved_expr1,
+ ffecom_1 (NEGATE_EXPR, tree_type, saved_expr1));
+ /* Make sure SAVE_EXPRs get referenced early enough. */
+ expr_tree
+ = ffecom_2 (COMPOUND_EXPR, tree_type,
+ convert (void_type_node, saved_expr1),
+ expr_tree);
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impSIN:
+ case FFEINTRIN_impCDSIN:
+ case FFEINTRIN_impCSIN:
+ case FFEINTRIN_impDSIN:
+ if (bt == FFEINFO_basictypeCOMPLEX)
+ {
+ if (kt == FFEINFO_kindtypeREAL1)
+ gfrt = FFECOM_gfrtCSIN; /* Overlapping result okay. */
+ else if (kt == FFEINFO_kindtypeREAL2)
+ gfrt = FFECOM_gfrtCDSIN; /* Overlapping result okay. */
+ }
+ break;
+
+ case FFEINTRIN_impSINH:
+ case FFEINTRIN_impDSINH:
+ break;
+
+ case FFEINTRIN_impSQRT:
+ case FFEINTRIN_impCDSQRT:
+ case FFEINTRIN_impCSQRT:
+ case FFEINTRIN_impDSQRT:
+ if (bt == FFEINFO_basictypeCOMPLEX)
+ {
+ if (kt == FFEINFO_kindtypeREAL1)
+ gfrt = FFECOM_gfrtCSQRT; /* Overlapping result okay. */
+ else if (kt == FFEINFO_kindtypeREAL2)
+ gfrt = FFECOM_gfrtCDSQRT; /* Overlapping result okay. */
+ }
+ break;
+
+ case FFEINTRIN_impTAN:
+ case FFEINTRIN_impDTAN:
+ case FFEINTRIN_impTANH:
+ case FFEINTRIN_impDTANH:
+ break;
+
+ case FFEINTRIN_impREALPART:
+ if (TREE_CODE (arg1_type) == COMPLEX_TYPE)
+ arg1_type = TREE_TYPE (arg1_type);
+ else
+ arg1_type = TREE_TYPE (TYPE_FIELDS (arg1_type));
+
+ return
+ convert (tree_type,
+ ffecom_1 (REALPART_EXPR, arg1_type,
+ ffecom_expr (arg1)));
+
+ case FFEINTRIN_impIAND:
+ case FFEINTRIN_impAND:
+ return ffecom_2 (BIT_AND_EXPR, tree_type,
+ convert (tree_type,
+ ffecom_expr (arg1)),
+ convert (tree_type,
+ ffecom_expr (arg2)));
+
+ case FFEINTRIN_impIOR:
+ case FFEINTRIN_impOR:
+ return ffecom_2 (BIT_IOR_EXPR, tree_type,
+ convert (tree_type,
+ ffecom_expr (arg1)),
+ convert (tree_type,
+ ffecom_expr (arg2)));
+
+ case FFEINTRIN_impIEOR:
+ case FFEINTRIN_impXOR:
+ return ffecom_2 (BIT_XOR_EXPR, tree_type,
+ convert (tree_type,
+ ffecom_expr (arg1)),
+ convert (tree_type,
+ ffecom_expr (arg2)));
+
+ case FFEINTRIN_impLSHIFT:
+ return ffecom_2 (LSHIFT_EXPR, tree_type,
+ ffecom_expr (arg1),
+ convert (integer_type_node,
+ ffecom_expr (arg2)));
+
+ case FFEINTRIN_impRSHIFT:
+ return ffecom_2 (RSHIFT_EXPR, tree_type,
+ ffecom_expr (arg1),
+ convert (integer_type_node,
+ ffecom_expr (arg2)));
+
+ case FFEINTRIN_impNOT:
+ return ffecom_1 (BIT_NOT_EXPR, tree_type, ffecom_expr (arg1));
+
+ case FFEINTRIN_impBIT_SIZE:
+ return convert (tree_type, TYPE_SIZE (arg1_type));
+
+ case FFEINTRIN_impBTEST:
+ {
+ ffetargetLogical1 true;
+ ffetargetLogical1 false;
+ tree true_tree;
+ tree false_tree;
+
+ ffetarget_logical1 (&true, TRUE);
+ ffetarget_logical1 (&false, FALSE);
+ if (true == 1)
+ true_tree = convert (tree_type, integer_one_node);
+ else
+ true_tree = convert (tree_type, build_int_2 (true, 0));
+ if (false == 0)
+ false_tree = convert (tree_type, integer_zero_node);
+ else
+ false_tree = convert (tree_type, build_int_2 (false, 0));
+
+ return
+ ffecom_3 (COND_EXPR, tree_type,
+ ffecom_truth_value
+ (ffecom_2 (EQ_EXPR, integer_type_node,
+ ffecom_2 (BIT_AND_EXPR, arg1_type,
+ ffecom_expr (arg1),
+ ffecom_2 (LSHIFT_EXPR, arg1_type,
+ convert (arg1_type,
+ integer_one_node),
+ convert (integer_type_node,
+ ffecom_expr (arg2)))),
+ convert (arg1_type,
+ integer_zero_node))),
+ false_tree,
+ true_tree);
+ }
+
+ case FFEINTRIN_impIBCLR:
+ return
+ ffecom_2 (BIT_AND_EXPR, tree_type,
+ ffecom_expr (arg1),
+ ffecom_1 (BIT_NOT_EXPR, tree_type,
+ ffecom_2 (LSHIFT_EXPR, tree_type,
+ convert (tree_type,
+ integer_one_node),
+ convert (integer_type_node,
+ ffecom_expr (arg2)))));
+
+ case FFEINTRIN_impIBITS:
+ {
+ tree arg3_tree = ffecom_save_tree (convert (integer_type_node,
+ ffecom_expr (arg3)));
+ tree uns_type
+ = ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt];
+
+ expr_tree
+ = ffecom_2 (BIT_AND_EXPR, tree_type,
+ ffecom_2 (RSHIFT_EXPR, tree_type,
+ ffecom_expr (arg1),
+ convert (integer_type_node,
+ ffecom_expr (arg2))),
+ convert (tree_type,
+ ffecom_2 (RSHIFT_EXPR, uns_type,
+ ffecom_1 (BIT_NOT_EXPR,
+ uns_type,
+ convert (uns_type,
+ integer_zero_node)),
+ ffecom_2 (MINUS_EXPR,
+ integer_type_node,
+ TYPE_SIZE (uns_type),
+ arg3_tree))));
+#if !defined(TREE_SHIFT_FULLWIDTH) || !TREE_SHIFT_FULLWIDTH
+ expr_tree
+ = ffecom_3 (COND_EXPR, tree_type,
+ ffecom_truth_value
+ (ffecom_2 (NE_EXPR, integer_type_node,
+ arg3_tree,
+ integer_zero_node)),
+ expr_tree,
+ convert (tree_type, integer_zero_node));
+#endif
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impIBSET:
+ return
+ ffecom_2 (BIT_IOR_EXPR, tree_type,
+ ffecom_expr (arg1),
+ ffecom_2 (LSHIFT_EXPR, tree_type,
+ convert (tree_type, integer_one_node),
+ convert (integer_type_node,
+ ffecom_expr (arg2))));
+
+ case FFEINTRIN_impISHFT:
+ {
+ tree arg1_tree = ffecom_save_tree (ffecom_expr (arg1));
+ tree arg2_tree = ffecom_save_tree (convert (integer_type_node,
+ ffecom_expr (arg2)));
+ tree uns_type
+ = ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt];
+
+ expr_tree
+ = ffecom_3 (COND_EXPR, tree_type,
+ ffecom_truth_value
+ (ffecom_2 (GE_EXPR, integer_type_node,
+ arg2_tree,
+ integer_zero_node)),
+ ffecom_2 (LSHIFT_EXPR, tree_type,
+ arg1_tree,
+ arg2_tree),
+ convert (tree_type,
+ ffecom_2 (RSHIFT_EXPR, uns_type,
+ convert (uns_type, arg1_tree),
+ ffecom_1 (NEGATE_EXPR,
+ integer_type_node,
+ arg2_tree))));
+#if !defined(TREE_SHIFT_FULLWIDTH) || !TREE_SHIFT_FULLWIDTH
+ expr_tree
+ = ffecom_3 (COND_EXPR, tree_type,
+ ffecom_truth_value
+ (ffecom_2 (NE_EXPR, integer_type_node,
+ arg2_tree,
+ TYPE_SIZE (uns_type))),
+ expr_tree,
+ convert (tree_type, integer_zero_node));
+#endif
+ /* Make sure SAVE_EXPRs get referenced early enough. */
+ expr_tree
+ = ffecom_2 (COMPOUND_EXPR, tree_type,
+ convert (void_type_node, arg1_tree),
+ ffecom_2 (COMPOUND_EXPR, tree_type,
+ convert (void_type_node, arg2_tree),
+ expr_tree));
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impISHFTC:
+ {
+ tree arg1_tree = ffecom_save_tree (ffecom_expr (arg1));
+ tree arg2_tree = ffecom_save_tree (convert (integer_type_node,
+ ffecom_expr (arg2)));
+ tree arg3_tree = (arg3 == NULL) ? TYPE_SIZE (tree_type)
+ : ffecom_save_tree (convert (integer_type_node, ffecom_expr (arg3)));
+ tree shift_neg;
+ tree shift_pos;
+ tree mask_arg1;
+ tree masked_arg1;
+ tree uns_type
+ = ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt];
+
+ mask_arg1
+ = ffecom_2 (LSHIFT_EXPR, tree_type,
+ ffecom_1 (BIT_NOT_EXPR, tree_type,
+ convert (tree_type, integer_zero_node)),
+ arg3_tree);
+#if !defined(TREE_SHIFT_FULLWIDTH) || !TREE_SHIFT_FULLWIDTH
+ mask_arg1
+ = ffecom_3 (COND_EXPR, tree_type,
+ ffecom_truth_value
+ (ffecom_2 (NE_EXPR, integer_type_node,
+ arg3_tree,
+ TYPE_SIZE (uns_type))),
+ mask_arg1,
+ convert (tree_type, integer_zero_node));
+#endif
+ mask_arg1 = ffecom_save_tree (mask_arg1);
+ masked_arg1
+ = ffecom_2 (BIT_AND_EXPR, tree_type,
+ arg1_tree,
+ ffecom_1 (BIT_NOT_EXPR, tree_type,
+ mask_arg1));
+ masked_arg1 = ffecom_save_tree (masked_arg1);
+ shift_neg
+ = ffecom_2 (BIT_IOR_EXPR, tree_type,
+ convert (tree_type,
+ ffecom_2 (RSHIFT_EXPR, uns_type,
+ convert (uns_type, masked_arg1),
+ ffecom_1 (NEGATE_EXPR,
+ integer_type_node,
+ arg2_tree))),
+ ffecom_2 (LSHIFT_EXPR, tree_type,
+ arg1_tree,
+ ffecom_2 (PLUS_EXPR, integer_type_node,
+ arg2_tree,
+ arg3_tree)));
+ shift_pos
+ = ffecom_2 (BIT_IOR_EXPR, tree_type,
+ ffecom_2 (LSHIFT_EXPR, tree_type,
+ arg1_tree,
+ arg2_tree),
+ convert (tree_type,
+ ffecom_2 (RSHIFT_EXPR, uns_type,
+ convert (uns_type, masked_arg1),
+ ffecom_2 (MINUS_EXPR,
+ integer_type_node,
+ arg3_tree,
+ arg2_tree))));
+ expr_tree
+ = ffecom_3 (COND_EXPR, tree_type,
+ ffecom_truth_value
+ (ffecom_2 (LT_EXPR, integer_type_node,
+ arg2_tree,
+ integer_zero_node)),
+ shift_neg,
+ shift_pos);
+ expr_tree
+ = ffecom_2 (BIT_IOR_EXPR, tree_type,
+ ffecom_2 (BIT_AND_EXPR, tree_type,
+ mask_arg1,
+ arg1_tree),
+ ffecom_2 (BIT_AND_EXPR, tree_type,
+ ffecom_1 (BIT_NOT_EXPR, tree_type,
+ mask_arg1),
+ expr_tree));
+ expr_tree
+ = ffecom_3 (COND_EXPR, tree_type,
+ ffecom_truth_value
+ (ffecom_2 (TRUTH_ORIF_EXPR, integer_type_node,
+ ffecom_2 (EQ_EXPR, integer_type_node,
+ ffecom_1 (ABS_EXPR,
+ integer_type_node,
+ arg2_tree),
+ arg3_tree),
+ ffecom_2 (EQ_EXPR, integer_type_node,
+ arg2_tree,
+ integer_zero_node))),
+ arg1_tree,
+ expr_tree);
+ /* Make sure SAVE_EXPRs get referenced early enough. */
+ expr_tree
+ = ffecom_2 (COMPOUND_EXPR, tree_type,
+ convert (void_type_node, arg1_tree),
+ ffecom_2 (COMPOUND_EXPR, tree_type,
+ convert (void_type_node, arg2_tree),
+ ffecom_2 (COMPOUND_EXPR, tree_type,
+ convert (void_type_node,
+ mask_arg1),
+ ffecom_2 (COMPOUND_EXPR, tree_type,
+ convert (void_type_node,
+ masked_arg1),
+ expr_tree))));
+ expr_tree
+ = ffecom_2 (COMPOUND_EXPR, tree_type,
+ convert (void_type_node,
+ arg3_tree),
+ expr_tree);
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impLOC:
+ {
+ tree arg1_tree = ffecom_expr (arg1);
+
+ expr_tree
+ = convert (tree_type,
+ ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (arg1_tree)),
+ arg1_tree));
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impMVBITS:
+ {
+ tree arg1_tree;
+ tree arg2_tree;
+ tree arg3_tree;
+ ffebld arg4 = ffebld_head (ffebld_trail (list));
+ tree arg4_tree;
+ tree arg4_type;
+ ffebld arg5 = ffebld_head (ffebld_trail (ffebld_trail (list)));
+ tree arg5_tree;
+ tree prep_arg1;
+ tree prep_arg4;
+ tree arg5_plus_arg3;
+
+ ffecom_push_calltemps ();
+
+ arg2_tree = convert (integer_type_node,
+ ffecom_expr (arg2));
+ arg3_tree = ffecom_save_tree (convert (integer_type_node,
+ ffecom_expr (arg3)));
+ arg4_tree = ffecom_expr_rw (arg4);
+ arg4_type = TREE_TYPE (arg4_tree);
+
+ arg1_tree = ffecom_save_tree (convert (arg4_type,
+ ffecom_expr (arg1)));
+
+ arg5_tree = ffecom_save_tree (convert (integer_type_node,
+ ffecom_expr (arg5)));
+
+ ffecom_pop_calltemps ();
+
+ prep_arg1
+ = ffecom_2 (LSHIFT_EXPR, arg4_type,
+ ffecom_2 (BIT_AND_EXPR, arg4_type,
+ ffecom_2 (RSHIFT_EXPR, arg4_type,
+ arg1_tree,
+ arg2_tree),
+ ffecom_1 (BIT_NOT_EXPR, arg4_type,
+ ffecom_2 (LSHIFT_EXPR, arg4_type,
+ ffecom_1 (BIT_NOT_EXPR,
+ arg4_type,
+ convert
+ (arg4_type,
+ integer_zero_node)),
+ arg3_tree))),
+ arg5_tree);
+ arg5_plus_arg3
+ = ffecom_save_tree (ffecom_2 (PLUS_EXPR, arg4_type,
+ arg5_tree,
+ arg3_tree));
+ prep_arg4
+ = ffecom_2 (LSHIFT_EXPR, arg4_type,
+ ffecom_1 (BIT_NOT_EXPR, arg4_type,
+ convert (arg4_type,
+ integer_zero_node)),
+ arg5_plus_arg3);
+#if !defined(TREE_SHIFT_FULLWIDTH) || !TREE_SHIFT_FULLWIDTH
+ prep_arg4
+ = ffecom_3 (COND_EXPR, arg4_type,
+ ffecom_truth_value
+ (ffecom_2 (NE_EXPR, integer_type_node,
+ arg5_plus_arg3,
+ convert (TREE_TYPE (arg5_plus_arg3),
+ TYPE_SIZE (arg4_type)))),
+ prep_arg4,
+ convert (arg4_type, integer_zero_node));
+#endif
+ prep_arg4
+ = ffecom_2 (BIT_AND_EXPR, arg4_type,
+ arg4_tree,
+ ffecom_2 (BIT_IOR_EXPR, arg4_type,
+ prep_arg4,
+ ffecom_1 (BIT_NOT_EXPR, arg4_type,
+ ffecom_2 (LSHIFT_EXPR, arg4_type,
+ ffecom_1 (BIT_NOT_EXPR,
+ arg4_type,
+ convert
+ (arg4_type,
+ integer_zero_node)),
+ arg5_tree))));
+ prep_arg1
+ = ffecom_2 (BIT_IOR_EXPR, arg4_type,
+ prep_arg1,
+ prep_arg4);
+#if !defined(TREE_SHIFT_FULLWIDTH) || !TREE_SHIFT_FULLWIDTH
+ prep_arg1
+ = ffecom_3 (COND_EXPR, arg4_type,
+ ffecom_truth_value
+ (ffecom_2 (NE_EXPR, integer_type_node,
+ arg3_tree,
+ convert (TREE_TYPE (arg3_tree),
+ integer_zero_node))),
+ prep_arg1,
+ arg4_tree);
+ prep_arg1
+ = ffecom_3 (COND_EXPR, arg4_type,
+ ffecom_truth_value
+ (ffecom_2 (NE_EXPR, integer_type_node,
+ arg3_tree,
+ convert (TREE_TYPE (arg3_tree),
+ TYPE_SIZE (arg4_type)))),
+ prep_arg1,
+ arg1_tree);
+#endif
+ expr_tree
+ = ffecom_2s (MODIFY_EXPR, void_type_node,
+ arg4_tree,
+ prep_arg1);
+ /* Make sure SAVE_EXPRs get referenced early enough. */
+ expr_tree
+ = ffecom_2 (COMPOUND_EXPR, void_type_node,
+ arg1_tree,
+ ffecom_2 (COMPOUND_EXPR, void_type_node,
+ arg3_tree,
+ ffecom_2 (COMPOUND_EXPR, void_type_node,
+ arg5_tree,
+ ffecom_2 (COMPOUND_EXPR, void_type_node,
+ arg5_plus_arg3,
+ expr_tree))));
+ expr_tree
+ = ffecom_2 (COMPOUND_EXPR, void_type_node,
+ arg4_tree,
+ expr_tree);
+
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impDERF:
+ case FFEINTRIN_impERF:
+ case FFEINTRIN_impDERFC:
+ case FFEINTRIN_impERFC:
+ break;
+
+ case FFEINTRIN_impIARGC:
+ /* extern int xargc; i__1 = xargc - 1; */
+ expr_tree = ffecom_2 (MINUS_EXPR, TREE_TYPE (ffecom_tree_xargc_),
+ ffecom_tree_xargc_,
+ convert (TREE_TYPE (ffecom_tree_xargc_),
+ integer_one_node));
+ return expr_tree;
+
+ case FFEINTRIN_impSIGNAL_func:
+ case FFEINTRIN_impSIGNAL_subr:
+ {
+ tree arg1_tree;
+ tree arg2_tree;
+ tree arg3_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = convert (ffecom_f2c_integer_type_node,
+ ffecom_expr (arg1));
+ arg1_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (arg1_tree)),
+ arg1_tree);
+
+ /* Pass procedure as a pointer to it, anything else by value. */
+ if (ffeinfo_kind (ffebld_info (arg2)) == FFEINFO_kindENTITY)
+ arg2_tree = convert (integer_type_node, ffecom_expr (arg2));
+ else
+ arg2_tree = ffecom_ptr_to_expr (arg2);
+ arg2_tree = convert (TREE_TYPE (null_pointer_node),
+ arg2_tree);
+
+ if (arg3 != NULL)
+ arg3_tree = ffecom_expr_rw (arg3);
+ else
+ arg3_tree = NULL_TREE;
+
+ ffecom_pop_calltemps ();
+
+ arg1_tree = build_tree_list (NULL_TREE, arg1_tree);
+ arg2_tree = build_tree_list (NULL_TREE, arg2_tree);
+ TREE_CHAIN (arg1_tree) = arg2_tree;
+
+ expr_tree
+ = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ ((codegen_imp == FFEINTRIN_impSIGNAL_subr) ?
+ NULL_TREE :
+ tree_type),
+ arg1_tree,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+
+ if (arg3_tree != NULL_TREE)
+ expr_tree
+ = ffecom_modify (NULL_TREE, arg3_tree,
+ convert (TREE_TYPE (arg3_tree),
+ expr_tree));
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impALARM:
+ {
+ tree arg1_tree;
+ tree arg2_tree;
+ tree arg3_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = convert (ffecom_f2c_integer_type_node,
+ ffecom_expr (arg1));
+ arg1_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (arg1_tree)),
+ arg1_tree);
+
+ /* Pass procedure as a pointer to it, anything else by value. */
+ if (ffeinfo_kind (ffebld_info (arg2)) == FFEINFO_kindENTITY)
+ arg2_tree = convert (integer_type_node, ffecom_expr (arg2));
+ else
+ arg2_tree = ffecom_ptr_to_expr (arg2);
+ arg2_tree = convert (TREE_TYPE (null_pointer_node),
+ arg2_tree);
+
+ if (arg3 != NULL)
+ arg3_tree = ffecom_expr_rw (arg3);
+ else
+ arg3_tree = NULL_TREE;
+
+ ffecom_pop_calltemps ();
+
+ arg1_tree = build_tree_list (NULL_TREE, arg1_tree);
+ arg2_tree = build_tree_list (NULL_TREE, arg2_tree);
+ TREE_CHAIN (arg1_tree) = arg2_tree;
+
+ expr_tree
+ = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ arg1_tree,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+
+ if (arg3_tree != NULL_TREE)
+ expr_tree
+ = ffecom_modify (NULL_TREE, arg3_tree,
+ convert (TREE_TYPE (arg3_tree),
+ expr_tree));
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impCHDIR_subr:
+ case FFEINTRIN_impFDATE_subr:
+ case FFEINTRIN_impFGET_subr:
+ case FFEINTRIN_impFPUT_subr:
+ case FFEINTRIN_impGETCWD_subr:
+ case FFEINTRIN_impHOSTNM_subr:
+ case FFEINTRIN_impSYSTEM_subr:
+ case FFEINTRIN_impUNLINK_subr:
+ {
+ tree arg1_len = integer_zero_node;
+ tree arg1_tree;
+ tree arg2_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = ffecom_arg_ptr_to_expr (arg1, &arg1_len);
+
+ if (arg2 != NULL)
+ arg2_tree = ffecom_expr_rw (arg2);
+ else
+ arg2_tree = NULL_TREE;
+
+ ffecom_pop_calltemps ();
+
+ arg1_tree = build_tree_list (NULL_TREE, arg1_tree);
+ arg1_len = build_tree_list (NULL_TREE, arg1_len);
+ TREE_CHAIN (arg1_tree) = arg1_len;
+
+ expr_tree
+ = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ arg1_tree,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+
+ if (arg2_tree != NULL_TREE)
+ expr_tree
+ = ffecom_modify (NULL_TREE, arg2_tree,
+ convert (TREE_TYPE (arg2_tree),
+ expr_tree));
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impEXIT:
+ if (arg1 != NULL)
+ break;
+
+ expr_tree = build_tree_list (NULL_TREE,
+ ffecom_1 (ADDR_EXPR,
+ build_pointer_type
+ (ffecom_integer_type_node),
+ integer_zero_node));
+
+ return
+ ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ void_type_node,
+ expr_tree,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+
+ case FFEINTRIN_impFLUSH:
+ if (arg1 == NULL)
+ gfrt = FFECOM_gfrtFLUSH;
+ else
+ gfrt = FFECOM_gfrtFLUSH1;
+ break;
+
+ case FFEINTRIN_impCHMOD_subr:
+ case FFEINTRIN_impLINK_subr:
+ case FFEINTRIN_impRENAME_subr:
+ case FFEINTRIN_impSYMLNK_subr:
+ {
+ tree arg1_len = integer_zero_node;
+ tree arg1_tree;
+ tree arg2_len = integer_zero_node;
+ tree arg2_tree;
+ tree arg3_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = ffecom_arg_ptr_to_expr (arg1, &arg1_len);
+ arg2_tree = ffecom_arg_ptr_to_expr (arg2, &arg2_len);
+ if (arg3 != NULL)
+ arg3_tree = ffecom_expr_rw (arg3);
+ else
+ arg3_tree = NULL_TREE;
+
+ ffecom_pop_calltemps ();
+
+ arg1_tree = build_tree_list (NULL_TREE, arg1_tree);
+ arg1_len = build_tree_list (NULL_TREE, arg1_len);
+ arg2_tree = build_tree_list (NULL_TREE, arg2_tree);
+ arg2_len = build_tree_list (NULL_TREE, arg2_len);
+ TREE_CHAIN (arg1_tree) = arg2_tree;
+ TREE_CHAIN (arg2_tree) = arg1_len;
+ TREE_CHAIN (arg1_len) = arg2_len;
+ expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ arg1_tree,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+ if (arg3_tree != NULL_TREE)
+ expr_tree = ffecom_modify (NULL_TREE, arg3_tree,
+ convert (TREE_TYPE (arg3_tree),
+ expr_tree));
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impLSTAT_subr:
+ case FFEINTRIN_impSTAT_subr:
+ {
+ tree arg1_len = integer_zero_node;
+ tree arg1_tree;
+ tree arg2_tree;
+ tree arg3_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = ffecom_arg_ptr_to_expr (arg1, &arg1_len);
+
+ arg2_tree = ffecom_ptr_to_expr (arg2);
+
+ if (arg3 != NULL)
+ arg3_tree = ffecom_expr_rw (arg3);
+ else
+ arg3_tree = NULL_TREE;
+
+ ffecom_pop_calltemps ();
+
+ arg1_tree = build_tree_list (NULL_TREE, arg1_tree);
+ arg1_len = build_tree_list (NULL_TREE, arg1_len);
+ arg2_tree = build_tree_list (NULL_TREE, arg2_tree);
+ TREE_CHAIN (arg1_tree) = arg2_tree;
+ TREE_CHAIN (arg2_tree) = arg1_len;
+ expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ arg1_tree,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+ if (arg3_tree != NULL_TREE)
+ expr_tree = ffecom_modify (NULL_TREE, arg3_tree,
+ convert (TREE_TYPE (arg3_tree),
+ expr_tree));
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impFGETC_subr:
+ case FFEINTRIN_impFPUTC_subr:
+ {
+ tree arg1_tree;
+ tree arg2_tree;
+ tree arg2_len = integer_zero_node;
+ tree arg3_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = convert (ffecom_f2c_integer_type_node,
+ ffecom_expr (arg1));
+ arg1_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (arg1_tree)),
+ arg1_tree);
+
+ arg2_tree = ffecom_arg_ptr_to_expr (arg2, &arg2_len);
+ arg3_tree = ffecom_expr_rw (arg3);
+
+ ffecom_pop_calltemps ();
+
+ arg1_tree = build_tree_list (NULL_TREE, arg1_tree);
+ arg2_tree = build_tree_list (NULL_TREE, arg2_tree);
+ arg2_len = build_tree_list (NULL_TREE, arg2_len);
+ TREE_CHAIN (arg1_tree) = arg2_tree;
+ TREE_CHAIN (arg2_tree) = arg2_len;
+
+ expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ arg1_tree,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+ expr_tree = ffecom_modify (NULL_TREE, arg3_tree,
+ convert (TREE_TYPE (arg3_tree),
+ expr_tree));
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impFSTAT_subr:
+ {
+ tree arg1_tree;
+ tree arg2_tree;
+ tree arg3_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = convert (ffecom_f2c_integer_type_node,
+ ffecom_expr (arg1));
+ arg1_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (arg1_tree)),
+ arg1_tree);
+
+ arg2_tree = convert (ffecom_f2c_ptr_to_integer_type_node,
+ ffecom_ptr_to_expr (arg2));
+
+ if (arg3 == NULL)
+ arg3_tree = NULL_TREE;
+ else
+ arg3_tree = ffecom_expr_rw (arg3);
+
+ ffecom_pop_calltemps ();
+
+ arg1_tree = build_tree_list (NULL_TREE, arg1_tree);
+ arg2_tree = build_tree_list (NULL_TREE, arg2_tree);
+ TREE_CHAIN (arg1_tree) = arg2_tree;
+ expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ arg1_tree,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+ if (arg3_tree != NULL_TREE) {
+ expr_tree = ffecom_modify (NULL_TREE, arg3_tree,
+ convert (TREE_TYPE (arg3_tree),
+ expr_tree));
+ }
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impKILL_subr:
+ {
+ tree arg1_tree;
+ tree arg2_tree;
+ tree arg3_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = convert (ffecom_f2c_integer_type_node,
+ ffecom_expr (arg1));
+ arg1_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (arg1_tree)),
+ arg1_tree);
+
+ arg2_tree = convert (ffecom_f2c_integer_type_node,
+ ffecom_expr (arg2));
+ arg2_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (arg2_tree)),
+ arg2_tree);
+
+ if (arg3 == NULL)
+ arg3_tree = NULL_TREE;
+ else
+ arg3_tree = ffecom_expr_rw (arg3);
+
+ ffecom_pop_calltemps ();
+
+ arg1_tree = build_tree_list (NULL_TREE, arg1_tree);
+ arg2_tree = build_tree_list (NULL_TREE, arg2_tree);
+ TREE_CHAIN (arg1_tree) = arg2_tree;
+ expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ arg1_tree,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+ if (arg3_tree != NULL_TREE) {
+ expr_tree = ffecom_modify (NULL_TREE, arg3_tree,
+ convert (TREE_TYPE (arg3_tree),
+ expr_tree));
+ }
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impCTIME_subr:
+ case FFEINTRIN_impTTYNAM_subr:
+ {
+ tree arg1_len = integer_zero_node;
+ tree arg1_tree;
+ tree arg2_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = ffecom_arg_ptr_to_expr (arg1, &arg1_len);
+
+ arg2_tree = convert (((gfrt == FFEINTRIN_impCTIME_subr) ?
+ ffecom_f2c_longint_type_node :
+ ffecom_f2c_integer_type_node),
+ ffecom_expr (arg2));
+ arg2_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (arg2_tree)),
+ arg2_tree);
+
+ ffecom_pop_calltemps ();
+
+ arg1_tree = build_tree_list (NULL_TREE, arg1_tree);
+ arg1_len = build_tree_list (NULL_TREE, arg1_len);
+ arg2_tree = build_tree_list (NULL_TREE, arg2_tree);
+ TREE_CHAIN (arg1_len) = arg2_tree;
+ TREE_CHAIN (arg1_tree) = arg1_len;
+
+ expr_tree
+ = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ arg1_tree,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impIRAND:
+ case FFEINTRIN_impRAND:
+ /* Arg defaults to 0 (normal random case) */
+ {
+ tree arg1_tree;
+
+ if (arg1 == NULL)
+ arg1_tree = ffecom_integer_zero_node;
+ else
+ arg1_tree = ffecom_expr (arg1);
+ arg1_tree = convert (ffecom_f2c_integer_type_node,
+ arg1_tree);
+ arg1_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (arg1_tree)),
+ arg1_tree);
+ arg1_tree = build_tree_list (NULL_TREE, arg1_tree);
+
+ expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ ((codegen_imp == FFEINTRIN_impIRAND) ?
+ ffecom_f2c_integer_type_node :
+ ffecom_f2c_real_type_node),
+ arg1_tree,
+ dest_tree, dest, dest_used,
+ NULL_TREE, TRUE);
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impFTELL_subr:
+ case FFEINTRIN_impUMASK_subr:
+ {
+ tree arg1_tree;
+ tree arg2_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = convert (ffecom_f2c_integer_type_node,
+ ffecom_expr (arg1));
+ arg1_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (arg1_tree)),
+ arg1_tree);
+
+ if (arg2 == NULL)
+ arg2_tree = NULL_TREE;
+ else
+ arg2_tree = ffecom_expr_rw (arg2);
+
+ ffecom_pop_calltemps ();
+
+ expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ build_tree_list (NULL_TREE, arg1_tree),
+ NULL_TREE, NULL, NULL, NULL_TREE,
+ TRUE);
+ if (arg2_tree != NULL_TREE) {
+ expr_tree = ffecom_modify (NULL_TREE, arg2_tree,
+ convert (TREE_TYPE (arg2_tree),
+ expr_tree));
+ }
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impCPU_TIME:
+ case FFEINTRIN_impSECOND_subr:
+ {
+ tree arg1_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = ffecom_expr_rw (arg1);
+
+ ffecom_pop_calltemps ();
+
+ expr_tree
+ = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ NULL_TREE,
+ NULL_TREE, NULL, NULL, NULL_TREE, TRUE);
+
+ expr_tree
+ = ffecom_modify (NULL_TREE, arg1_tree,
+ convert (TREE_TYPE (arg1_tree),
+ expr_tree));
+ }
+ return expr_tree;
+
+ case FFEINTRIN_impDTIME_subr:
+ case FFEINTRIN_impETIME_subr:
+ {
+ tree arg1_tree;
+ tree arg2_tree;
+
+ ffecom_push_calltemps ();
+
+ arg1_tree = ffecom_expr_rw (arg1);
+
+ arg2_tree = ffecom_ptr_to_expr (arg2);
+
+ ffecom_pop_calltemps ();
+
+ expr_tree = ffecom_call_ (ffecom_gfrt_tree_ (gfrt),
+ ffecom_gfrt_kindtype (gfrt),
+ FALSE,
+ NULL_TREE,
+ build_tree_list (NULL_TREE, arg2_tree),
+ NULL_TREE, NULL, NULL, NULL_TREE,
+ TRUE);
+ expr_tree = ffecom_modify (NULL_TREE, arg1_tree,
+ convert (TREE_TYPE (arg1_tree),
+ expr_tree));
+ }
+ return expr_tree;
+
+ /* Straightforward calls of libf2c routines: */
+ case FFEINTRIN_impABORT:
+ case FFEINTRIN_impACCESS:
+ case FFEINTRIN_impBESJ0:
+ case FFEINTRIN_impBESJ1:
+ case FFEINTRIN_impBESJN:
+ case FFEINTRIN_impBESY0:
+ case FFEINTRIN_impBESY1:
+ case FFEINTRIN_impBESYN:
+ case FFEINTRIN_impCHDIR_func:
+ case FFEINTRIN_impCHMOD_func:
+ case FFEINTRIN_impDATE:
+ case FFEINTRIN_impDATE_AND_TIME:
+ case FFEINTRIN_impDBESJ0:
+ case FFEINTRIN_impDBESJ1:
+ case FFEINTRIN_impDBESJN:
+ case FFEINTRIN_impDBESY0:
+ case FFEINTRIN_impDBESY1:
+ case FFEINTRIN_impDBESYN:
+ case FFEINTRIN_impDTIME_func:
+ case FFEINTRIN_impETIME_func:
+ case FFEINTRIN_impFGETC_func:
+ case FFEINTRIN_impFGET_func:
+ case FFEINTRIN_impFNUM:
+ case FFEINTRIN_impFPUTC_func:
+ case FFEINTRIN_impFPUT_func:
+ case FFEINTRIN_impFSEEK:
+ case FFEINTRIN_impFSTAT_func:
+ case FFEINTRIN_impFTELL_func:
+ case FFEINTRIN_impGERROR:
+ case FFEINTRIN_impGETARG:
+ case FFEINTRIN_impGETCWD_func:
+ case FFEINTRIN_impGETENV:
+ case FFEINTRIN_impGETGID:
+ case FFEINTRIN_impGETLOG:
+ case FFEINTRIN_impGETPID:
+ case FFEINTRIN_impGETUID:
+ case FFEINTRIN_impGMTIME:
+ case FFEINTRIN_impHOSTNM_func:
+ case FFEINTRIN_impIDATE_unix:
+ case FFEINTRIN_impIDATE_vxt:
+ case FFEINTRIN_impIERRNO:
+ case FFEINTRIN_impISATTY:
+ case FFEINTRIN_impITIME:
+ case FFEINTRIN_impKILL_func:
+ case FFEINTRIN_impLINK_func:
+ case FFEINTRIN_impLNBLNK:
+ case FFEINTRIN_impLSTAT_func:
+ case FFEINTRIN_impLTIME:
+ case FFEINTRIN_impMCLOCK8:
+ case FFEINTRIN_impMCLOCK:
+ case FFEINTRIN_impPERROR:
+ case FFEINTRIN_impRENAME_func:
+ case FFEINTRIN_impSECNDS:
+ case FFEINTRIN_impSECOND_func:
+ case FFEINTRIN_impSLEEP:
+ case FFEINTRIN_impSRAND:
+ case FFEINTRIN_impSTAT_func:
+ case FFEINTRIN_impSYMLNK_func:
+ case FFEINTRIN_impSYSTEM_CLOCK:
+ case FFEINTRIN_impSYSTEM_func:
+ case FFEINTRIN_impTIME8:
+ case FFEINTRIN_impTIME_unix:
+ case FFEINTRIN_impTIME_vxt:
+ case FFEINTRIN_impUMASK_func:
+ case FFEINTRIN_impUNLINK_func:
+ break;
+
+ case FFEINTRIN_impCTIME_func: /* CHARACTER functions not handled here. */
+ case FFEINTRIN_impFDATE_func: /* CHARACTER functions not handled here. */
+ case FFEINTRIN_impTTYNAM_func: /* CHARACTER functions not handled here. */
+ case FFEINTRIN_impNONE:
+ case FFEINTRIN_imp: /* Hush up gcc warning. */
+ fprintf (stderr, "No %s implementation.\n",
+ ffeintrin_name_implementation (ffebld_symter_implementation (ffebld_left (expr))));
+ assert ("unimplemented intrinsic" == NULL);
+ return error_mark_node;
+ }
+
+ assert (gfrt != FFECOM_gfrt); /* Must have an implementation! */
+
+ ffecom_push_calltemps ();
+ expr_tree = ffecom_arglist_expr_ (ffecom_gfrt_args_ (gfrt),
+ ffebld_right (expr));
+ ffecom_pop_calltemps ();
+
+ return ffecom_call_ (ffecom_gfrt_tree_ (gfrt), ffecom_gfrt_kindtype (gfrt),
+ (ffe_is_f2c_library () && ffecom_gfrt_complex_[gfrt]),
+ tree_type,
+ expr_tree, dest_tree, dest, dest_used,
+ NULL_TREE, TRUE);
+
+ /**INDENT* (Do not reformat this comment even with -fca option.)
+ Data-gathering files: Given the source file listed below, compiled with
+ f2c I obtained the output file listed after that, and from the output
+ file I derived the above code.
+
+-------- (begin input file to f2c)
+ implicit none
+ character*10 A1,A2
+ complex C1,C2
+ integer I1,I2
+ real R1,R2
+ double precision D1,D2
+C
+ call getem(A1,A2,C1,C2,I1,I2,R1,R2,D1,D2)
+c /
+ call fooI(I1/I2)
+ call fooR(R1/I1)
+ call fooD(D1/I1)
+ call fooC(C1/I1)
+ call fooR(R1/R2)
+ call fooD(R1/D1)
+ call fooD(D1/D2)
+ call fooD(D1/R1)
+ call fooC(C1/C2)
+ call fooC(C1/R1)
+ call fooZ(C1/D1)
+c **
+ call fooI(I1**I2)
+ call fooR(R1**I1)
+ call fooD(D1**I1)
+ call fooC(C1**I1)
+ call fooR(R1**R2)
+ call fooD(R1**D1)
+ call fooD(D1**D2)
+ call fooD(D1**R1)
+ call fooC(C1**C2)
+ call fooC(C1**R1)
+ call fooZ(C1**D1)
+c FFEINTRIN_impABS
+ call fooR(ABS(R1))
+c FFEINTRIN_impACOS
+ call fooR(ACOS(R1))
+c FFEINTRIN_impAIMAG
+ call fooR(AIMAG(C1))
+c FFEINTRIN_impAINT
+ call fooR(AINT(R1))
+c FFEINTRIN_impALOG
+ call fooR(ALOG(R1))
+c FFEINTRIN_impALOG10
+ call fooR(ALOG10(R1))
+c FFEINTRIN_impAMAX0
+ call fooR(AMAX0(I1,I2))
+c FFEINTRIN_impAMAX1
+ call fooR(AMAX1(R1,R2))
+c FFEINTRIN_impAMIN0
+ call fooR(AMIN0(I1,I2))
+c FFEINTRIN_impAMIN1
+ call fooR(AMIN1(R1,R2))
+c FFEINTRIN_impAMOD
+ call fooR(AMOD(R1,R2))
+c FFEINTRIN_impANINT
+ call fooR(ANINT(R1))
+c FFEINTRIN_impASIN
+ call fooR(ASIN(R1))
+c FFEINTRIN_impATAN
+ call fooR(ATAN(R1))
+c FFEINTRIN_impATAN2
+ call fooR(ATAN2(R1,R2))
+c FFEINTRIN_impCABS
+ call fooR(CABS(C1))
+c FFEINTRIN_impCCOS
+ call fooC(CCOS(C1))
+c FFEINTRIN_impCEXP
+ call fooC(CEXP(C1))
+c FFEINTRIN_impCHAR
+ call fooA(CHAR(I1))
+c FFEINTRIN_impCLOG
+ call fooC(CLOG(C1))
+c FFEINTRIN_impCONJG
+ call fooC(CONJG(C1))
+c FFEINTRIN_impCOS
+ call fooR(COS(R1))
+c FFEINTRIN_impCOSH
+ call fooR(COSH(R1))
+c FFEINTRIN_impCSIN
+ call fooC(CSIN(C1))
+c FFEINTRIN_impCSQRT
+ call fooC(CSQRT(C1))
+c FFEINTRIN_impDABS
+ call fooD(DABS(D1))
+c FFEINTRIN_impDACOS
+ call fooD(DACOS(D1))
+c FFEINTRIN_impDASIN
+ call fooD(DASIN(D1))
+c FFEINTRIN_impDATAN
+ call fooD(DATAN(D1))
+c FFEINTRIN_impDATAN2
+ call fooD(DATAN2(D1,D2))
+c FFEINTRIN_impDCOS
+ call fooD(DCOS(D1))
+c FFEINTRIN_impDCOSH
+ call fooD(DCOSH(D1))
+c FFEINTRIN_impDDIM
+ call fooD(DDIM(D1,D2))
+c FFEINTRIN_impDEXP
+ call fooD(DEXP(D1))
+c FFEINTRIN_impDIM
+ call fooR(DIM(R1,R2))
+c FFEINTRIN_impDINT
+ call fooD(DINT(D1))
+c FFEINTRIN_impDLOG
+ call fooD(DLOG(D1))
+c FFEINTRIN_impDLOG10
+ call fooD(DLOG10(D1))
+c FFEINTRIN_impDMAX1
+ call fooD(DMAX1(D1,D2))
+c FFEINTRIN_impDMIN1
+ call fooD(DMIN1(D1,D2))
+c FFEINTRIN_impDMOD
+ call fooD(DMOD(D1,D2))
+c FFEINTRIN_impDNINT
+ call fooD(DNINT(D1))
+c FFEINTRIN_impDPROD
+ call fooD(DPROD(R1,R2))
+c FFEINTRIN_impDSIGN
+ call fooD(DSIGN(D1,D2))
+c FFEINTRIN_impDSIN
+ call fooD(DSIN(D1))
+c FFEINTRIN_impDSINH
+ call fooD(DSINH(D1))
+c FFEINTRIN_impDSQRT
+ call fooD(DSQRT(D1))
+c FFEINTRIN_impDTAN
+ call fooD(DTAN(D1))
+c FFEINTRIN_impDTANH
+ call fooD(DTANH(D1))
+c FFEINTRIN_impEXP
+ call fooR(EXP(R1))
+c FFEINTRIN_impIABS
+ call fooI(IABS(I1))
+c FFEINTRIN_impICHAR
+ call fooI(ICHAR(A1))
+c FFEINTRIN_impIDIM
+ call fooI(IDIM(I1,I2))
+c FFEINTRIN_impIDNINT
+ call fooI(IDNINT(D1))
+c FFEINTRIN_impINDEX
+ call fooI(INDEX(A1,A2))
+c FFEINTRIN_impISIGN
+ call fooI(ISIGN(I1,I2))
+c FFEINTRIN_impLEN
+ call fooI(LEN(A1))
+c FFEINTRIN_impLGE
+ call fooL(LGE(A1,A2))
+c FFEINTRIN_impLGT
+ call fooL(LGT(A1,A2))
+c FFEINTRIN_impLLE
+ call fooL(LLE(A1,A2))
+c FFEINTRIN_impLLT
+ call fooL(LLT(A1,A2))
+c FFEINTRIN_impMAX0
+ call fooI(MAX0(I1,I2))
+c FFEINTRIN_impMAX1
+ call fooI(MAX1(R1,R2))
+c FFEINTRIN_impMIN0
+ call fooI(MIN0(I1,I2))
+c FFEINTRIN_impMIN1
+ call fooI(MIN1(R1,R2))
+c FFEINTRIN_impMOD
+ call fooI(MOD(I1,I2))
+c FFEINTRIN_impNINT
+ call fooI(NINT(R1))
+c FFEINTRIN_impSIGN
+ call fooR(SIGN(R1,R2))
+c FFEINTRIN_impSIN
+ call fooR(SIN(R1))
+c FFEINTRIN_impSINH
+ call fooR(SINH(R1))
+c FFEINTRIN_impSQRT
+ call fooR(SQRT(R1))
+c FFEINTRIN_impTAN
+ call fooR(TAN(R1))
+c FFEINTRIN_impTANH
+ call fooR(TANH(R1))
+c FFEINTRIN_imp_CMPLX_C
+ call fooC(cmplx(C1,C2))
+c FFEINTRIN_imp_CMPLX_D
+ call fooZ(cmplx(D1,D2))
+c FFEINTRIN_imp_CMPLX_I
+ call fooC(cmplx(I1,I2))
+c FFEINTRIN_imp_CMPLX_R
+ call fooC(cmplx(R1,R2))
+c FFEINTRIN_imp_DBLE_C
+ call fooD(dble(C1))
+c FFEINTRIN_imp_DBLE_D
+ call fooD(dble(D1))
+c FFEINTRIN_imp_DBLE_I
+ call fooD(dble(I1))
+c FFEINTRIN_imp_DBLE_R
+ call fooD(dble(R1))
+c FFEINTRIN_imp_INT_C
+ call fooI(int(C1))
+c FFEINTRIN_imp_INT_D
+ call fooI(int(D1))
+c FFEINTRIN_imp_INT_I
+ call fooI(int(I1))
+c FFEINTRIN_imp_INT_R
+ call fooI(int(R1))
+c FFEINTRIN_imp_REAL_C
+ call fooR(real(C1))
+c FFEINTRIN_imp_REAL_D
+ call fooR(real(D1))
+c FFEINTRIN_imp_REAL_I
+ call fooR(real(I1))
+c FFEINTRIN_imp_REAL_R
+ call fooR(real(R1))
+c
+c FFEINTRIN_imp_INT_D:
+c
+c FFEINTRIN_specIDINT
+ call fooI(IDINT(D1))
+c
+c FFEINTRIN_imp_INT_R:
+c
+c FFEINTRIN_specIFIX
+ call fooI(IFIX(R1))
+c FFEINTRIN_specINT
+ call fooI(INT(R1))
+c
+c FFEINTRIN_imp_REAL_D:
+c
+c FFEINTRIN_specSNGL
+ call fooR(SNGL(D1))
+c
+c FFEINTRIN_imp_REAL_I:
+c
+c FFEINTRIN_specFLOAT
+ call fooR(FLOAT(I1))
+c FFEINTRIN_specREAL
+ call fooR(REAL(I1))
+c
+ end
+-------- (end input file to f2c)
+
+-------- (begin output from providing above input file as input to:
+-------- `f2c | gcc -E -C - | sed -e "s:/[*]*://:g" -e "s:[*]*[/]://:g" \
+-------- -e "s:^#.*$::g"')
+
+// -- translated by f2c (version 19950223).
+ You must link the resulting object file with the libraries:
+ -lf2c -lm (in that order)
+//
+
+
+// f2c.h -- Standard Fortran to C header file //
+
+/// barf [ba:rf] 2. "He suggested using FORTRAN, and everybody barfed."
+
+ - From The Shogakukan DICTIONARY OF NEW ENGLISH (Second edition) //
+
+
+
+
+// F2C_INTEGER will normally be `int' but would be `long' on 16-bit systems //
+// we assume short, float are OK //
+typedef long int // long int // integer;
+typedef char *address;
+typedef short int shortint;
+typedef float real;
+typedef double doublereal;
+typedef struct { real r, i; } complex;
+typedef struct { doublereal r, i; } doublecomplex;
+typedef long int // long int // logical;
+typedef short int shortlogical;
+typedef char logical1;
+typedef char integer1;
+// typedef long long longint; // // system-dependent //
+
+
+
+
+// Extern is for use with -E //
+
+
+
+
+// I/O stuff //
+
+
+
+
+
+
+
+
+typedef long int // int or long int // flag;
+typedef long int // int or long int // ftnlen;
+typedef long int // int or long int // ftnint;
+
+
+//external read, write//
+typedef struct
+{ flag cierr;
+ ftnint ciunit;
+ flag ciend;
+ char *cifmt;
+ ftnint cirec;
+} cilist;
+
+//internal read, write//
+typedef struct
+{ flag icierr;
+ char *iciunit;
+ flag iciend;
+ char *icifmt;
+ ftnint icirlen;
+ ftnint icirnum;
+} icilist;
+
+//open//
+typedef struct
+{ flag oerr;
+ ftnint ounit;
+ char *ofnm;
+ ftnlen ofnmlen;
+ char *osta;
+ char *oacc;
+ char *ofm;
+ ftnint orl;
+ char *oblnk;
+} olist;
+
+//close//
+typedef struct
+{ flag cerr;
+ ftnint cunit;
+ char *csta;
+} cllist;
+
+//rewind, backspace, endfile//
+typedef struct
+{ flag aerr;
+ ftnint aunit;
+} alist;
+
+// inquire //
+typedef struct
+{ flag inerr;
+ ftnint inunit;
+ char *infile;
+ ftnlen infilen;
+ ftnint *inex; //parameters in standard's order//
+ ftnint *inopen;
+ ftnint *innum;
+ ftnint *innamed;
+ char *inname;
+ ftnlen innamlen;
+ char *inacc;
+ ftnlen inacclen;
+ char *inseq;
+ ftnlen inseqlen;
+ char *indir;
+ ftnlen indirlen;
+ char *infmt;
+ ftnlen infmtlen;
+ char *inform;
+ ftnint informlen;
+ char *inunf;
+ ftnlen inunflen;
+ ftnint *inrecl;
+ ftnint *innrec;
+ char *inblank;
+ ftnlen inblanklen;
+} inlist;
+
+
+
+union Multitype { // for multiple entry points //
+ integer1 g;
+ shortint h;
+ integer i;
+ // longint j; //
+ real r;
+ doublereal d;
+ complex c;
+ doublecomplex z;
+ };
+
+typedef union Multitype Multitype;
+
+typedef long Long; // No longer used; formerly in Namelist //
+
+struct Vardesc { // for Namelist //
+ char *name;
+ char *addr;
+ ftnlen *dims;
+ int type;
+ };
+typedef struct Vardesc Vardesc;
+
+struct Namelist {
+ char *name;
+ Vardesc **vars;
+ int nvars;
+ };
+typedef struct Namelist Namelist;
+
+
+
+
+
+
+
+
+// procedure parameter types for -A and -C++ //
+
+
+
+
+typedef int // Unknown procedure type // (*U_fp)();
+typedef shortint (*J_fp)();
+typedef integer (*I_fp)();
+typedef real (*R_fp)();
+typedef doublereal (*D_fp)(), (*E_fp)();
+typedef // Complex // void (*C_fp)();
+typedef // Double Complex // void (*Z_fp)();
+typedef logical (*L_fp)();
+typedef shortlogical (*K_fp)();
+typedef // Character // void (*H_fp)();
+typedef // Subroutine // int (*S_fp)();
+
+// E_fp is for real functions when -R is not specified //
+typedef void C_f; // complex function //
+typedef void H_f; // character function //
+typedef void Z_f; // double complex function //
+typedef doublereal E_f; // real function with -R not specified //
+
+// undef any lower-case symbols that your C compiler predefines, e.g.: //
+
+
+// (No such symbols should be defined in a strict ANSI C compiler.
+ We can avoid trouble with f2c-translated code by using
+ gcc -ansi [-traditional].) //
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// Main program // MAIN__()
+{
+ // System generated locals //
+ integer i__1;
+ real r__1, r__2;
+ doublereal d__1, d__2;
+ complex q__1;
+ doublecomplex z__1, z__2, z__3;
+ logical L__1;
+ char ch__1[1];
+
+ // Builtin functions //
+ void c_div();
+ integer pow_ii();
+ double pow_ri(), pow_di();
+ void pow_ci();
+ double pow_dd();
+ void pow_zz();
+ double acos(), r_imag(), r_int(), log(), r_lg10(), r_mod(), r_nint(),
+ asin(), atan(), atan2(), c_abs();
+ void c_cos(), c_exp(), c_log(), r_cnjg();
+ double cos(), cosh();
+ void c_sin(), c_sqrt();
+ double d_dim(), exp(), r_dim(), d_int(), d_lg10(), d_mod(), d_nint(),
+ d_sign(), sin(), sinh(), sqrt(), tan(), tanh();
+ integer i_dim(), i_dnnt(), i_indx(), i_sign(), i_len();
+ logical l_ge(), l_gt(), l_le(), l_lt();
+ integer i_nint();
+ double r_sign();
+
+ // Local variables //
+ extern // Subroutine // int fooa_(), fooc_(), food_(), fooi_(), foor_(),
+ fool_(), fooz_(), getem_();
+ static char a1[10], a2[10];
+ static complex c1, c2;
+ static doublereal d1, d2;
+ static integer i1, i2;
+ static real r1, r2;
+
+
+ getem_(a1, a2, &c1, &c2, &i1, &i2, &r1, &r2, &d1, &d2, 10L, 10L);
+// / //
+ i__1 = i1 / i2;
+ fooi_(&i__1);
+ r__1 = r1 / i1;
+ foor_(&r__1);
+ d__1 = d1 / i1;
+ food_(&d__1);
+ d__1 = (doublereal) i1;
+ q__1.r = c1.r / d__1, q__1.i = c1.i / d__1;
+ fooc_(&q__1);
+ r__1 = r1 / r2;
+ foor_(&r__1);
+ d__1 = r1 / d1;
+ food_(&d__1);
+ d__1 = d1 / d2;
+ food_(&d__1);
+ d__1 = d1 / r1;
+ food_(&d__1);
+ c_div(&q__1, &c1, &c2);
+ fooc_(&q__1);
+ q__1.r = c1.r / r1, q__1.i = c1.i / r1;
+ fooc_(&q__1);
+ z__1.r = c1.r / d1, z__1.i = c1.i / d1;
+ fooz_(&z__1);
+// ** //
+ i__1 = pow_ii(&i1, &i2);
+ fooi_(&i__1);
+ r__1 = pow_ri(&r1, &i1);
+ foor_(&r__1);
+ d__1 = pow_di(&d1, &i1);
+ food_(&d__1);
+ pow_ci(&q__1, &c1, &i1);
+ fooc_(&q__1);
+ d__1 = (doublereal) r1;
+ d__2 = (doublereal) r2;
+ r__1 = pow_dd(&d__1, &d__2);
+ foor_(&r__1);
+ d__2 = (doublereal) r1;
+ d__1 = pow_dd(&d__2, &d1);
+ food_(&d__1);
+ d__1 = pow_dd(&d1, &d2);
+ food_(&d__1);
+ d__2 = (doublereal) r1;
+ d__1 = pow_dd(&d1, &d__2);
+ food_(&d__1);
+ z__2.r = c1.r, z__2.i = c1.i;
+ z__3.r = c2.r, z__3.i = c2.i;
+ pow_zz(&z__1, &z__2, &z__3);
+ q__1.r = z__1.r, q__1.i = z__1.i;
+ fooc_(&q__1);
+ z__2.r = c1.r, z__2.i = c1.i;
+ z__3.r = r1, z__3.i = 0.;
+ pow_zz(&z__1, &z__2, &z__3);
+ q__1.r = z__1.r, q__1.i = z__1.i;
+ fooc_(&q__1);
+ z__2.r = c1.r, z__2.i = c1.i;
+ z__3.r = d1, z__3.i = 0.;
+ pow_zz(&z__1, &z__2, &z__3);
+ fooz_(&z__1);
+// FFEINTRIN_impABS //
+ r__1 = (doublereal)(( r1 ) >= 0 ? ( r1 ) : -( r1 )) ;
+ foor_(&r__1);
+// FFEINTRIN_impACOS //
+ r__1 = acos(r1);
+ foor_(&r__1);
+// FFEINTRIN_impAIMAG //
+ r__1 = r_imag(&c1);
+ foor_(&r__1);
+// FFEINTRIN_impAINT //
+ r__1 = r_int(&r1);
+ foor_(&r__1);
+// FFEINTRIN_impALOG //
+ r__1 = log(r1);
+ foor_(&r__1);
+// FFEINTRIN_impALOG10 //
+ r__1 = r_lg10(&r1);
+ foor_(&r__1);
+// FFEINTRIN_impAMAX0 //
+ r__1 = (real) (( i1 ) >= ( i2 ) ? ( i1 ) : ( i2 )) ;
+ foor_(&r__1);
+// FFEINTRIN_impAMAX1 //
+ r__1 = (doublereal)(( r1 ) >= ( r2 ) ? ( r1 ) : ( r2 )) ;
+ foor_(&r__1);
+// FFEINTRIN_impAMIN0 //
+ r__1 = (real) (( i1 ) <= ( i2 ) ? ( i1 ) : ( i2 )) ;
+ foor_(&r__1);
+// FFEINTRIN_impAMIN1 //
+ r__1 = (doublereal)(( r1 ) <= ( r2 ) ? ( r1 ) : ( r2 )) ;
+ foor_(&r__1);
+// FFEINTRIN_impAMOD //
+ r__1 = r_mod(&r1, &r2);
+ foor_(&r__1);
+// FFEINTRIN_impANINT //
+ r__1 = r_nint(&r1);
+ foor_(&r__1);
+// FFEINTRIN_impASIN //
+ r__1 = asin(r1);
+ foor_(&r__1);
+// FFEINTRIN_impATAN //
+ r__1 = atan(r1);
+ foor_(&r__1);
+// FFEINTRIN_impATAN2 //
+ r__1 = atan2(r1, r2);
+ foor_(&r__1);
+// FFEINTRIN_impCABS //
+ r__1 = c_abs(&c1);
+ foor_(&r__1);
+// FFEINTRIN_impCCOS //
+ c_cos(&q__1, &c1);
+ fooc_(&q__1);
+// FFEINTRIN_impCEXP //
+ c_exp(&q__1, &c1);
+ fooc_(&q__1);
+// FFEINTRIN_impCHAR //
+ *(unsigned char *)&ch__1[0] = i1;
+ fooa_(ch__1, 1L);
+// FFEINTRIN_impCLOG //
+ c_log(&q__1, &c1);
+ fooc_(&q__1);
+// FFEINTRIN_impCONJG //
+ r_cnjg(&q__1, &c1);
+ fooc_(&q__1);
+// FFEINTRIN_impCOS //
+ r__1 = cos(r1);
+ foor_(&r__1);
+// FFEINTRIN_impCOSH //
+ r__1 = cosh(r1);
+ foor_(&r__1);
+// FFEINTRIN_impCSIN //
+ c_sin(&q__1, &c1);
+ fooc_(&q__1);
+// FFEINTRIN_impCSQRT //
+ c_sqrt(&q__1, &c1);
+ fooc_(&q__1);
+// FFEINTRIN_impDABS //
+ d__1 = (( d1 ) >= 0 ? ( d1 ) : -( d1 )) ;
+ food_(&d__1);
+// FFEINTRIN_impDACOS //
+ d__1 = acos(d1);
+ food_(&d__1);
+// FFEINTRIN_impDASIN //
+ d__1 = asin(d1);
+ food_(&d__1);
+// FFEINTRIN_impDATAN //
+ d__1 = atan(d1);
+ food_(&d__1);
+// FFEINTRIN_impDATAN2 //
+ d__1 = atan2(d1, d2);
+ food_(&d__1);
+// FFEINTRIN_impDCOS //
+ d__1 = cos(d1);
+ food_(&d__1);
+// FFEINTRIN_impDCOSH //
+ d__1 = cosh(d1);
+ food_(&d__1);
+// FFEINTRIN_impDDIM //
+ d__1 = d_dim(&d1, &d2);
+ food_(&d__1);
+// FFEINTRIN_impDEXP //
+ d__1 = exp(d1);
+ food_(&d__1);
+// FFEINTRIN_impDIM //
+ r__1 = r_dim(&r1, &r2);
+ foor_(&r__1);
+// FFEINTRIN_impDINT //
+ d__1 = d_int(&d1);
+ food_(&d__1);
+// FFEINTRIN_impDLOG //
+ d__1 = log(d1);
+ food_(&d__1);
+// FFEINTRIN_impDLOG10 //
+ d__1 = d_lg10(&d1);
+ food_(&d__1);
+// FFEINTRIN_impDMAX1 //
+ d__1 = (( d1 ) >= ( d2 ) ? ( d1 ) : ( d2 )) ;
+ food_(&d__1);
+// FFEINTRIN_impDMIN1 //
+ d__1 = (( d1 ) <= ( d2 ) ? ( d1 ) : ( d2 )) ;
+ food_(&d__1);
+// FFEINTRIN_impDMOD //
+ d__1 = d_mod(&d1, &d2);
+ food_(&d__1);
+// FFEINTRIN_impDNINT //
+ d__1 = d_nint(&d1);
+ food_(&d__1);
+// FFEINTRIN_impDPROD //
+ d__1 = (doublereal) r1 * r2;
+ food_(&d__1);
+// FFEINTRIN_impDSIGN //
+ d__1 = d_sign(&d1, &d2);
+ food_(&d__1);
+// FFEINTRIN_impDSIN //
+ d__1 = sin(d1);
+ food_(&d__1);
+// FFEINTRIN_impDSINH //
+ d__1 = sinh(d1);
+ food_(&d__1);
+// FFEINTRIN_impDSQRT //
+ d__1 = sqrt(d1);
+ food_(&d__1);
+// FFEINTRIN_impDTAN //
+ d__1 = tan(d1);
+ food_(&d__1);
+// FFEINTRIN_impDTANH //
+ d__1 = tanh(d1);
+ food_(&d__1);
+// FFEINTRIN_impEXP //
+ r__1 = exp(r1);
+ foor_(&r__1);
+// FFEINTRIN_impIABS //
+ i__1 = (( i1 ) >= 0 ? ( i1 ) : -( i1 )) ;
+ fooi_(&i__1);
+// FFEINTRIN_impICHAR //
+ i__1 = *(unsigned char *)a1;
+ fooi_(&i__1);
+// FFEINTRIN_impIDIM //
+ i__1 = i_dim(&i1, &i2);
+ fooi_(&i__1);
+// FFEINTRIN_impIDNINT //
+ i__1 = i_dnnt(&d1);
+ fooi_(&i__1);
+// FFEINTRIN_impINDEX //
+ i__1 = i_indx(a1, a2, 10L, 10L);
+ fooi_(&i__1);
+// FFEINTRIN_impISIGN //
+ i__1 = i_sign(&i1, &i2);
+ fooi_(&i__1);
+// FFEINTRIN_impLEN //
+ i__1 = i_len(a1, 10L);
+ fooi_(&i__1);
+// FFEINTRIN_impLGE //
+ L__1 = l_ge(a1, a2, 10L, 10L);
+ fool_(&L__1);
+// FFEINTRIN_impLGT //
+ L__1 = l_gt(a1, a2, 10L, 10L);
+ fool_(&L__1);
+// FFEINTRIN_impLLE //
+ L__1 = l_le(a1, a2, 10L, 10L);
+ fool_(&L__1);
+// FFEINTRIN_impLLT //
+ L__1 = l_lt(a1, a2, 10L, 10L);
+ fool_(&L__1);
+// FFEINTRIN_impMAX0 //
+ i__1 = (( i1 ) >= ( i2 ) ? ( i1 ) : ( i2 )) ;
+ fooi_(&i__1);
+// FFEINTRIN_impMAX1 //
+ i__1 = (integer) (doublereal)(( r1 ) >= ( r2 ) ? ( r1 ) : ( r2 )) ;
+ fooi_(&i__1);
+// FFEINTRIN_impMIN0 //
+ i__1 = (( i1 ) <= ( i2 ) ? ( i1 ) : ( i2 )) ;
+ fooi_(&i__1);
+// FFEINTRIN_impMIN1 //
+ i__1 = (integer) (doublereal)(( r1 ) <= ( r2 ) ? ( r1 ) : ( r2 )) ;
+ fooi_(&i__1);
+// FFEINTRIN_impMOD //
+ i__1 = i1 % i2;
+ fooi_(&i__1);
+// FFEINTRIN_impNINT //
+ i__1 = i_nint(&r1);
+ fooi_(&i__1);
+// FFEINTRIN_impSIGN //
+ r__1 = r_sign(&r1, &r2);
+ foor_(&r__1);
+// FFEINTRIN_impSIN //
+ r__1 = sin(r1);
+ foor_(&r__1);
+// FFEINTRIN_impSINH //
+ r__1 = sinh(r1);
+ foor_(&r__1);
+// FFEINTRIN_impSQRT //
+ r__1 = sqrt(r1);
+ foor_(&r__1);
+// FFEINTRIN_impTAN //
+ r__1 = tan(r1);
+ foor_(&r__1);
+// FFEINTRIN_impTANH //
+ r__1 = tanh(r1);
+ foor_(&r__1);
+// FFEINTRIN_imp_CMPLX_C //
+ r__1 = c1.r;
+ r__2 = c2.r;
+ q__1.r = r__1, q__1.i = r__2;
+ fooc_(&q__1);
+// FFEINTRIN_imp_CMPLX_D //
+ z__1.r = d1, z__1.i = d2;
+ fooz_(&z__1);
+// FFEINTRIN_imp_CMPLX_I //
+ r__1 = (real) i1;
+ r__2 = (real) i2;
+ q__1.r = r__1, q__1.i = r__2;
+ fooc_(&q__1);
+// FFEINTRIN_imp_CMPLX_R //
+ q__1.r = r1, q__1.i = r2;
+ fooc_(&q__1);
+// FFEINTRIN_imp_DBLE_C //
+ d__1 = (doublereal) c1.r;
+ food_(&d__1);
+// FFEINTRIN_imp_DBLE_D //
+ d__1 = d1;
+ food_(&d__1);
+// FFEINTRIN_imp_DBLE_I //
+ d__1 = (doublereal) i1;
+ food_(&d__1);
+// FFEINTRIN_imp_DBLE_R //
+ d__1 = (doublereal) r1;
+ food_(&d__1);
+// FFEINTRIN_imp_INT_C //
+ i__1 = (integer) c1.r;
+ fooi_(&i__1);
+// FFEINTRIN_imp_INT_D //
+ i__1 = (integer) d1;
+ fooi_(&i__1);
+// FFEINTRIN_imp_INT_I //
+ i__1 = i1;
+ fooi_(&i__1);
+// FFEINTRIN_imp_INT_R //
+ i__1 = (integer) r1;
+ fooi_(&i__1);
+// FFEINTRIN_imp_REAL_C //
+ r__1 = c1.r;
+ foor_(&r__1);
+// FFEINTRIN_imp_REAL_D //
+ r__1 = (real) d1;
+ foor_(&r__1);
+// FFEINTRIN_imp_REAL_I //
+ r__1 = (real) i1;
+ foor_(&r__1);
+// FFEINTRIN_imp_REAL_R //
+ r__1 = r1;
+ foor_(&r__1);
+
+// FFEINTRIN_imp_INT_D: //
+
+// FFEINTRIN_specIDINT //
+ i__1 = (integer) d1;
+ fooi_(&i__1);
+
+// FFEINTRIN_imp_INT_R: //
+
+// FFEINTRIN_specIFIX //
+ i__1 = (integer) r1;
+ fooi_(&i__1);
+// FFEINTRIN_specINT //
+ i__1 = (integer) r1;
+ fooi_(&i__1);
+
+// FFEINTRIN_imp_REAL_D: //
+
+// FFEINTRIN_specSNGL //
+ r__1 = (real) d1;
+ foor_(&r__1);
+
+// FFEINTRIN_imp_REAL_I: //
+
+// FFEINTRIN_specFLOAT //
+ r__1 = (real) i1;
+ foor_(&r__1);
+// FFEINTRIN_specREAL //
+ r__1 = (real) i1;
+ foor_(&r__1);
+
+} // MAIN__ //
+
+-------- (end output file from f2c)
+
+*/
+}
+
+#endif
+/* For power (exponentiation) where right-hand operand is type INTEGER,
+ generate in-line code to do it the fast way (which, if the operand
+ is a constant, might just mean a series of multiplies). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_expr_power_integer_ (ffebld left, ffebld right)
+{
+ tree l = ffecom_expr (left);
+ tree r = ffecom_expr (right);
+ tree ltype = TREE_TYPE (l);
+ tree rtype = TREE_TYPE (r);
+ tree result = NULL_TREE;
+
+ if (l == error_mark_node
+ || r == error_mark_node)
+ return error_mark_node;
+
+ if (TREE_CODE (r) == INTEGER_CST)
+ {
+ int sgn = tree_int_cst_sgn (r);
+
+ if (sgn == 0)
+ return convert (ltype, integer_one_node);
+
+ if ((TREE_CODE (ltype) == INTEGER_TYPE)
+ && (sgn < 0))
+ {
+ /* Reciprocal of integer is either 0, -1, or 1, so after
+ calculating that (which we leave to the back end to do
+ or not do optimally), don't bother with any multiplying. */
+
+ result = ffecom_tree_divide_ (ltype,
+ convert (ltype, integer_one_node),
+ l,
+ NULL_TREE, NULL, NULL);
+ r = ffecom_1 (NEGATE_EXPR,
+ rtype,
+ r);
+ if ((TREE_INT_CST_LOW (r) & 1) == 0)
+ result = ffecom_1 (ABS_EXPR, rtype,
+ result);
+ }
+
+ /* Generate appropriate series of multiplies, preceded
+ by divide if the exponent is negative. */
+
+ l = save_expr (l);
+
+ if (sgn < 0)
+ {
+ l = ffecom_tree_divide_ (ltype,
+ convert (ltype, integer_one_node),
+ l,
+ NULL_TREE, NULL, NULL);
+ r = ffecom_1 (NEGATE_EXPR, rtype, r);
+ assert (TREE_CODE (r) == INTEGER_CST);
+
+ if (tree_int_cst_sgn (r) < 0)
+ { /* The "most negative" number. */
+ r = ffecom_1 (NEGATE_EXPR, rtype,
+ ffecom_2 (RSHIFT_EXPR, rtype,
+ r,
+ integer_one_node));
+ l = save_expr (l);
+ l = ffecom_2 (MULT_EXPR, ltype,
+ l,
+ l);
+ }
+ }
+
+ for (;;)
+ {
+ if (TREE_INT_CST_LOW (r) & 1)
+ {
+ if (result == NULL_TREE)
+ result = l;
+ else
+ result = ffecom_2 (MULT_EXPR, ltype,
+ result,
+ l);
+ }
+
+ r = ffecom_2 (RSHIFT_EXPR, rtype,
+ r,
+ integer_one_node);
+ if (integer_zerop (r))
+ break;
+ assert (TREE_CODE (r) == INTEGER_CST);
+
+ l = save_expr (l);
+ l = ffecom_2 (MULT_EXPR, ltype,
+ l,
+ l);
+ }
+ return result;
+ }
+
+ /* Though rhs isn't a constant, in-line code cannot be expanded
+ while transforming dummies
+ because the back end cannot be easily convinced to generate
+ stores (MODIFY_EXPR), handle temporaries, and so on before
+ all the appropriate rtx's have been generated for things like
+ dummy args referenced in rhs -- which doesn't happen until
+ store_parm_decls() is called (expand_function_start, I believe,
+ does the actual rtx-stuffing of PARM_DECLs).
+
+ So, in this case, let the caller generate the call to the
+ run-time-library function to evaluate the power for us. */
+
+ if (ffecom_transform_only_dummies_)
+ return NULL_TREE;
+
+ /* Right-hand operand not a constant, expand in-line code to figure
+ out how to do the multiplies, &c.
+
+ The returned expression is expressed this way in GNU C, where l and
+ r are the "inputs":
+
+ ({ typeof (r) rtmp = r;
+ typeof (l) ltmp = l;
+ typeof (l) result;
+
+ if (rtmp == 0)
+ result = 1;
+ else
+ {
+ if ((basetypeof (l) == basetypeof (int))
+ && (rtmp < 0))
+ {
+ result = ((typeof (l)) 1) / ltmp;
+ if ((ltmp < 0) && (((-rtmp) & 1) == 0))
+ result = -result;
+ }
+ else
+ {
+ result = 1;
+ if ((basetypeof (l) != basetypeof (int))
+ && (rtmp < 0))
+ {
+ ltmp = ((typeof (l)) 1) / ltmp;
+ rtmp = -rtmp;
+ if (rtmp < 0)
+ {
+ rtmp = -(rtmp >> 1);
+ ltmp *= ltmp;
+ }
+ }
+ for (;;)
+ {
+ if (rtmp & 1)
+ result *= ltmp;
+ if ((rtmp >>= 1) == 0)
+ break;
+ ltmp *= ltmp;
+ }
+ }
+ }
+ result;
+ })
+
+ Note that some of the above is compile-time collapsable, such as
+ the first part of the if statements that checks the base type of
+ l against int. The if statements are phrased that way to suggest
+ an easy way to generate the if/else constructs here, knowing that
+ the back end should (and probably does) eliminate the resulting
+ dead code (either the int case or the non-int case), something
+ it couldn't do without the redundant phrasing, requiring explicit
+ dead-code elimination here, which would be kind of difficult to
+ read. */
+
+ {
+ tree rtmp;
+ tree ltmp;
+ tree basetypeof_l_is_int;
+ tree se;
+
+ basetypeof_l_is_int
+ = build_int_2 ((TREE_CODE (ltype) == INTEGER_TYPE), 0);
+
+ se = expand_start_stmt_expr ();
+ ffecom_push_calltemps ();
+
+ rtmp = ffecom_push_tempvar (rtype, FFETARGET_charactersizeNONE, -1,
+ TRUE);
+ ltmp = ffecom_push_tempvar (ltype, FFETARGET_charactersizeNONE, -1,
+ TRUE);
+ result = ffecom_push_tempvar (ltype, FFETARGET_charactersizeNONE, -1,
+ TRUE);
+
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ rtmp,
+ r));
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ ltmp,
+ l));
+ expand_start_cond (ffecom_truth_value
+ (ffecom_2 (EQ_EXPR, integer_type_node,
+ rtmp,
+ convert (rtype, integer_zero_node))),
+ 0);
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ result,
+ convert (ltype, integer_one_node)));
+ expand_start_else ();
+ if (!integer_zerop (basetypeof_l_is_int))
+ {
+ expand_start_cond (ffecom_2 (LT_EXPR, integer_type_node,
+ rtmp,
+ convert (rtype,
+ integer_zero_node)),
+ 0);
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ result,
+ ffecom_tree_divide_
+ (ltype,
+ convert (ltype, integer_one_node),
+ ltmp,
+ NULL_TREE, NULL, NULL)));
+ expand_start_cond (ffecom_truth_value
+ (ffecom_2 (TRUTH_ANDIF_EXPR, integer_type_node,
+ ffecom_2 (LT_EXPR, integer_type_node,
+ ltmp,
+ convert (ltype,
+ integer_zero_node)),
+ ffecom_2 (EQ_EXPR, integer_type_node,
+ ffecom_2 (BIT_AND_EXPR,
+ rtype,
+ ffecom_1 (NEGATE_EXPR,
+ rtype,
+ rtmp),
+ convert (rtype,
+ integer_one_node)),
+ convert (rtype,
+ integer_zero_node)))),
+ 0);
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ result,
+ ffecom_1 (NEGATE_EXPR,
+ ltype,
+ result)));
+ expand_end_cond ();
+ expand_start_else ();
+ }
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ result,
+ convert (ltype, integer_one_node)));
+ expand_start_cond (ffecom_truth_value
+ (ffecom_2 (TRUTH_ANDIF_EXPR, integer_type_node,
+ ffecom_truth_value_invert
+ (basetypeof_l_is_int),
+ ffecom_2 (LT_EXPR, integer_type_node,
+ rtmp,
+ convert (rtype,
+ integer_zero_node)))),
+ 0);
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ ltmp,
+ ffecom_tree_divide_
+ (ltype,
+ convert (ltype, integer_one_node),
+ ltmp,
+ NULL_TREE, NULL, NULL)));
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ rtmp,
+ ffecom_1 (NEGATE_EXPR, rtype,
+ rtmp)));
+ expand_start_cond (ffecom_truth_value
+ (ffecom_2 (LT_EXPR, integer_type_node,
+ rtmp,
+ convert (rtype, integer_zero_node))),
+ 0);
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ rtmp,
+ ffecom_1 (NEGATE_EXPR, rtype,
+ ffecom_2 (RSHIFT_EXPR,
+ rtype,
+ rtmp,
+ integer_one_node))));
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ ltmp,
+ ffecom_2 (MULT_EXPR, ltype,
+ ltmp,
+ ltmp)));
+ expand_end_cond ();
+ expand_end_cond ();
+ expand_start_loop (1);
+ expand_start_cond (ffecom_truth_value
+ (ffecom_2 (BIT_AND_EXPR, rtype,
+ rtmp,
+ convert (rtype, integer_one_node))),
+ 0);
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ result,
+ ffecom_2 (MULT_EXPR, ltype,
+ result,
+ ltmp)));
+ expand_end_cond ();
+ expand_exit_loop_if_false (NULL,
+ ffecom_truth_value
+ (ffecom_modify (rtype,
+ rtmp,
+ ffecom_2 (RSHIFT_EXPR,
+ rtype,
+ rtmp,
+ integer_one_node))));
+ expand_expr_stmt (ffecom_modify (void_type_node,
+ ltmp,
+ ffecom_2 (MULT_EXPR, ltype,
+ ltmp,
+ ltmp)));
+ expand_end_loop ();
+ expand_end_cond ();
+ if (!integer_zerop (basetypeof_l_is_int))
+ expand_end_cond ();
+ expand_expr_stmt (result);
+
+ ffecom_pop_calltemps ();
+ result = expand_end_stmt_expr (se);
+ TREE_SIDE_EFFECTS (result) = 1;
+ }
+
+ return result;
+}
+
+#endif
+/* ffecom_expr_transform_ -- Transform symbols in expr
+
+ ffebld expr; // FFE expression.
+ ffecom_expr_transform_ (expr);
+
+ Recursive descent on expr while transforming any untransformed SYMTERs. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_expr_transform_ (ffebld expr)
+{
+ tree t;
+ ffesymbol s;
+
+tail_recurse: /* :::::::::::::::::::: */
+
+ if (expr == NULL)
+ return;
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opSYMTER:
+ s = ffebld_symter (expr);
+ t = ffesymbol_hook (s).decl_tree;
+ if ((t == NULL_TREE)
+ && ((ffesymbol_kind (s) != FFEINFO_kindNONE)
+ || ((ffesymbol_where (s) != FFEINFO_whereNONE)
+ && (ffesymbol_where (s) != FFEINFO_whereINTRINSIC))))
+ {
+ s = ffecom_sym_transform_ (s);
+ t = ffesymbol_hook (s).decl_tree; /* Sfunc expr non-dummy,
+ DIMENSION expr? */
+ }
+ break; /* Ok if (t == NULL) here. */
+
+ case FFEBLD_opITEM:
+ ffecom_expr_transform_ (ffebld_head (expr));
+ expr = ffebld_trail (expr);
+ goto tail_recurse; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+
+ switch (ffebld_arity (expr))
+ {
+ case 2:
+ ffecom_expr_transform_ (ffebld_left (expr));
+ expr = ffebld_right (expr);
+ goto tail_recurse; /* :::::::::::::::::::: */
+
+ case 1:
+ expr = ffebld_left (expr);
+ goto tail_recurse; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+#endif
+/* Make a type based on info in live f2c.h file. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_f2c_make_type_ (tree *type, int tcode, char *name)
+{
+ switch (tcode)
+ {
+ case FFECOM_f2ccodeCHAR:
+ *type = make_signed_type (CHAR_TYPE_SIZE);
+ break;
+
+ case FFECOM_f2ccodeSHORT:
+ *type = make_signed_type (SHORT_TYPE_SIZE);
+ break;
+
+ case FFECOM_f2ccodeINT:
+ *type = make_signed_type (INT_TYPE_SIZE);
+ break;
+
+ case FFECOM_f2ccodeLONG:
+ *type = make_signed_type (LONG_TYPE_SIZE);
+ break;
+
+ case FFECOM_f2ccodeLONGLONG:
+ *type = make_signed_type (LONG_LONG_TYPE_SIZE);
+ break;
+
+ case FFECOM_f2ccodeCHARPTR:
+ *type = build_pointer_type (DEFAULT_SIGNED_CHAR
+ ? signed_char_type_node
+ : unsigned_char_type_node);
+ break;
+
+ case FFECOM_f2ccodeFLOAT:
+ *type = make_node (REAL_TYPE);
+ TYPE_PRECISION (*type) = FLOAT_TYPE_SIZE;
+ layout_type (*type);
+ break;
+
+ case FFECOM_f2ccodeDOUBLE:
+ *type = make_node (REAL_TYPE);
+ TYPE_PRECISION (*type) = DOUBLE_TYPE_SIZE;
+ layout_type (*type);
+ break;
+
+ case FFECOM_f2ccodeLONGDOUBLE:
+ *type = make_node (REAL_TYPE);
+ TYPE_PRECISION (*type) = LONG_DOUBLE_TYPE_SIZE;
+ layout_type (*type);
+ break;
+
+ case FFECOM_f2ccodeTWOREALS:
+ *type = ffecom_make_complex_type_ (ffecom_f2c_real_type_node);
+ break;
+
+ case FFECOM_f2ccodeTWODOUBLEREALS:
+ *type = ffecom_make_complex_type_ (ffecom_f2c_doublereal_type_node);
+ break;
+
+ default:
+ assert ("unexpected FFECOM_f2ccodeXYZZY!" == NULL);
+ *type = error_mark_node;
+ return;
+ }
+
+ pushdecl (build_decl (TYPE_DECL,
+ ffecom_get_invented_identifier ("__g77_f2c_%s",
+ name, 0),
+ *type));
+}
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+/* Set the f2c list-directed-I/O code for whatever (integral) type has the
+ given size. */
+
+static void
+ffecom_f2c_set_lio_code_ (ffeinfoBasictype bt, int size,
+ int code)
+{
+ int j;
+ tree t;
+
+ for (j = 0; ((size_t) j) < ARRAY_SIZE (ffecom_tree_type[0]); ++j)
+ if (((t = ffecom_tree_type[bt][j]) != NULL_TREE)
+ && (TREE_INT_CST_LOW (TYPE_SIZE (t)) == size))
+ {
+ assert (code != -1);
+ ffecom_f2c_typecode_[bt][j] = code;
+ code = -1;
+ }
+}
+
+#endif
+/* Finish up globals after doing all program units in file
+
+ Need to handle only uninitialized COMMON areas. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static ffeglobal
+ffecom_finish_global_ (ffeglobal global)
+{
+ tree cbtype;
+ tree cbt;
+ tree size;
+
+ if (ffeglobal_type (global) != FFEGLOBAL_typeCOMMON)
+ return global;
+
+ if (ffeglobal_common_init (global))
+ return global;
+
+ cbt = ffeglobal_hook (global);
+ if ((cbt == NULL_TREE)
+ || !ffeglobal_common_have_size (global))
+ return global; /* No need to make common, never ref'd. */
+
+ suspend_momentary ();
+
+ DECL_EXTERNAL (cbt) = 0;
+
+ /* Give the array a size now. */
+
+ size = build_int_2 ((ffeglobal_common_size (global)
+ + ffeglobal_common_pad (global)) - 1,
+ 0);
+
+ cbtype = TREE_TYPE (cbt);
+ TYPE_DOMAIN (cbtype) = build_range_type (integer_type_node,
+ integer_zero_node,
+ size);
+ if (!TREE_TYPE (size))
+ TREE_TYPE (size) = TYPE_DOMAIN (cbtype);
+ layout_type (cbtype);
+
+ cbt = start_decl (cbt, FALSE);
+ assert (cbt == ffeglobal_hook (global));
+
+ finish_decl (cbt, NULL_TREE, FALSE);
+
+ return global;
+}
+
+#endif
+/* Finish up any untransformed symbols. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static ffesymbol
+ffecom_finish_symbol_transform_ (ffesymbol s)
+{
+ if ((s == NULL) || (TREE_CODE (current_function_decl) == ERROR_MARK))
+ return s;
+
+ /* It's easy to know to transform an untransformed symbol, to make sure
+ we put out debugging info for it. But COMMON variables, unlike
+ EQUIVALENCE ones, aren't given declarations in addition to the
+ tree expressions that specify offsets, because COMMON variables
+ can be referenced in the outer scope where only dummy arguments
+ (PARM_DECLs) should really be seen. To be safe, just don't do any
+ VAR_DECLs for COMMON variables when we transform them for real
+ use, and therefore we do all the VAR_DECL creating here. */
+
+ if (ffesymbol_hook (s).decl_tree == NULL_TREE)
+ {
+ if (ffesymbol_kind (s) != FFEINFO_kindNONE
+ || (ffesymbol_where (s) != FFEINFO_whereNONE
+ && ffesymbol_where (s) != FFEINFO_whereINTRINSIC
+ && ffesymbol_where (s) != FFEINFO_whereDUMMY))
+ /* Not transformed, and not CHARACTER*(*), and not a dummy
+ argument, which can happen only if the entry point names
+ it "rides in on" are all invalidated for other reasons. */
+ s = ffecom_sym_transform_ (s);
+ }
+
+ if ((ffesymbol_where (s) == FFEINFO_whereCOMMON)
+ && (ffesymbol_hook (s).decl_tree != error_mark_node))
+ {
+#ifdef SOMEONE_GETS_DEBUG_SUPPORT_WORKING
+ int yes = suspend_momentary ();
+
+ /* This isn't working, at least for dbxout. The .s file looks
+ okay to me (burley), but in gdb 4.9 at least, the variables
+ appear to reside somewhere outside of the common area, so
+ it doesn't make sense to mislead anyone by generating the info
+ on those variables until this is fixed. NOTE: Same problem
+ with EQUIVALENCE, sadly...see similar #if later. */
+ ffecom_member_phase2_ (ffesymbol_storage (ffesymbol_common (s)),
+ ffesymbol_storage (s));
+
+ resume_momentary (yes);
+#endif
+ }
+
+ return s;
+}
+
+#endif
+/* Append underscore(s) to name before calling get_identifier. "us"
+ is nonzero if the name already contains an underscore and thus
+ needs two underscores appended. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_get_appended_identifier_ (char us, char *name)
+{
+ int i;
+ char *newname;
+ tree id;
+
+ newname = xmalloc ((i = strlen (name)) + 1
+ + ffe_is_underscoring ()
+ + us);
+ memcpy (newname, name, i);
+ newname[i] = '_';
+ newname[i + us] = '_';
+ newname[i + 1 + us] = '\0';
+ id = get_identifier (newname);
+
+ free (newname);
+
+ return id;
+}
+
+#endif
+/* Decide whether to append underscore to name before calling
+ get_identifier. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_get_external_identifier_ (ffesymbol s)
+{
+ char us;
+ char *name = ffesymbol_text (s);
+
+ /* If name is a built-in name, just return it as is. */
+
+ if (!ffe_is_underscoring ()
+ || (strcmp (name, FFETARGET_nameBLANK_COMMON) == 0)
+#if FFETARGET_isENFORCED_MAIN_NAME
+ || (strcmp (name, FFETARGET_nameENFORCED_NAME) == 0)
+#else
+ || (strcmp (name, FFETARGET_nameUNNAMED_MAIN) == 0)
+#endif
+ || (strcmp (name, FFETARGET_nameUNNAMED_BLOCK_DATA) == 0))
+ return get_identifier (name);
+
+ us = ffe_is_second_underscore ()
+ ? (strchr (name, '_') != NULL)
+ : 0;
+
+ return ffecom_get_appended_identifier_ (us, name);
+}
+
+#endif
+/* Decide whether to append underscore to internal name before calling
+ get_identifier.
+
+ This is for non-external, top-function-context names only. Transform
+ identifier so it doesn't conflict with the transformed result
+ of using a _different_ external name. E.g. if "CALL FOO" is
+ transformed into "FOO_();", then the variable in "FOO_ = 3"
+ must be transformed into something that does not conflict, since
+ these two things should be independent.
+
+ The transformation is as follows. If the name does not contain
+ an underscore, there is no possible conflict, so just return.
+ If the name does contain an underscore, then transform it just
+ like we transform an external identifier. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_get_identifier_ (char *name)
+{
+ /* If name does not contain an underscore, just return it as is. */
+
+ if (!ffe_is_underscoring ()
+ || (strchr (name, '_') == NULL))
+ return get_identifier (name);
+
+ return ffecom_get_appended_identifier_ (ffe_is_second_underscore (),
+ name);
+}
+
+#endif
+/* ffecom_gen_sfuncdef_ -- Generate definition of statement function
+
+ tree t;
+ ffesymbol s; // kindFUNCTION, whereIMMEDIATE.
+ t = ffecom_gen_sfuncdef_(s,ffesymbol_basictype(s),
+ ffesymbol_kindtype(s));
+
+ Call after setting up containing function and getting trees for all
+ other symbols. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_gen_sfuncdef_ (ffesymbol s, ffeinfoBasictype bt, ffeinfoKindtype kt)
+{
+ ffebld expr = ffesymbol_sfexpr (s);
+ tree type;
+ tree func;
+ tree result;
+ bool charfunc = (bt == FFEINFO_basictypeCHARACTER);
+ static bool recurse = FALSE;
+ int yes;
+ int old_lineno = lineno;
+ char *old_input_filename = input_filename;
+
+ ffecom_nested_entry_ = s;
+
+ /* For now, we don't have a handy pointer to where the sfunc is actually
+ defined, though that should be easy to add to an ffesymbol. (The
+ token/where info available might well point to the place where the type
+ of the sfunc is declared, especially if that precedes the place where
+ the sfunc itself is defined, which is typically the case.) We should
+ put out a null pointer rather than point somewhere wrong, but I want to
+ see how it works at this point. */
+
+ input_filename = ffesymbol_where_filename (s);
+ lineno = ffesymbol_where_filelinenum (s);
+
+ /* Pretransform the expression so any newly discovered things belong to the
+ outer program unit, not to the statement function. */
+
+ ffecom_expr_transform_ (expr);
+
+ /* Make sure no recursive invocation of this fn (a specific case of failing
+ to pretransform an sfunc's expression, i.e. where its expression
+ references another untransformed sfunc) happens. */
+
+ assert (!recurse);
+ recurse = TRUE;
+
+ yes = suspend_momentary ();
+
+ push_f_function_context ();
+
+ ffecom_push_calltemps ();
+
+ if (charfunc)
+ type = void_type_node;
+ else
+ {
+ type = ffecom_tree_type[bt][kt];
+ if (type == NULL_TREE)
+ type = integer_type_node; /* _sym_exec_transition reports
+ error. */
+ }
+
+ start_function (ffecom_get_identifier_ (ffesymbol_text (s)),
+ build_function_type (type, NULL_TREE),
+ 1, /* nested/inline */
+ 0); /* TREE_PUBLIC */
+
+ /* We don't worry about COMPLEX return values here, because this is
+ entirely internal to our code, and gcc has the ability to return COMPLEX
+ directly as a value. */
+
+ yes = suspend_momentary ();
+
+ if (charfunc)
+ { /* Prepend arg for where result goes. */
+ tree type;
+
+ type = ffecom_tree_type[FFEINFO_basictypeCHARACTER][kt];
+
+ result = ffecom_get_invented_identifier ("__g77_%s",
+ "result", 0);
+
+ ffecom_char_enhance_arg_ (&type, s); /* Ignore returned length. */
+
+ type = build_pointer_type (type);
+ result = build_decl (PARM_DECL, result, type);
+
+ push_parm_decl (result);
+ }
+ else
+ result = NULL_TREE; /* Not ref'd if !charfunc. */
+
+ ffecom_push_dummy_decls_ (ffesymbol_dummyargs (s), TRUE);
+
+ resume_momentary (yes);
+
+ store_parm_decls (0);
+
+ ffecom_start_compstmt_ ();
+
+ if (expr != NULL)
+ {
+ if (charfunc)
+ {
+ ffetargetCharacterSize sz = ffesymbol_size (s);
+ tree result_length;
+
+ result_length = build_int_2 (sz, 0);
+ TREE_TYPE (result_length) = ffecom_f2c_ftnlen_type_node;
+
+ ffecom_let_char_ (result, result_length, sz, expr);
+ expand_null_return ();
+ }
+ else
+ expand_return (ffecom_modify (NULL_TREE,
+ DECL_RESULT (current_function_decl),
+ ffecom_expr (expr)));
+
+ clear_momentary ();
+ }
+
+ ffecom_end_compstmt_ ();
+
+ func = current_function_decl;
+ finish_function (1);
+
+ ffecom_pop_calltemps ();
+
+ pop_f_function_context ();
+
+ resume_momentary (yes);
+
+ recurse = FALSE;
+
+ lineno = old_lineno;
+ input_filename = old_input_filename;
+
+ ffecom_nested_entry_ = NULL;
+
+ return func;
+}
+
+#endif
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static char *
+ffecom_gfrt_args_ (ffecomGfrt ix)
+{
+ return ffecom_gfrt_argstring_[ix];
+}
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_gfrt_tree_ (ffecomGfrt ix)
+{
+ if (ffecom_gfrt_[ix] == NULL_TREE)
+ ffecom_make_gfrt_ (ix);
+
+ return ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (ffecom_gfrt_[ix])),
+ ffecom_gfrt_[ix]);
+}
+
+#endif
+/* Return initialize-to-zero expression for this VAR_DECL. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_init_zero_ (tree decl)
+{
+ tree init;
+ int incremental = TREE_STATIC (decl);
+ tree type = TREE_TYPE (decl);
+
+ if (incremental)
+ {
+ int momentary = suspend_momentary ();
+ push_obstacks_nochange ();
+ if (TREE_PERMANENT (decl))
+ end_temporary_allocation ();
+ make_decl_rtl (decl, NULL, TREE_PUBLIC (decl) ? 1 : 0);
+ assemble_variable (decl, TREE_PUBLIC (decl) ? 1 : 0, 0, 1);
+ pop_obstacks ();
+ resume_momentary (momentary);
+ }
+
+ push_momentary ();
+
+ if ((TREE_CODE (type) != ARRAY_TYPE)
+ && (TREE_CODE (type) != RECORD_TYPE)
+ && (TREE_CODE (type) != UNION_TYPE)
+ && !incremental)
+ init = convert (type, integer_zero_node);
+ else if (!incremental)
+ {
+ int momentary = suspend_momentary ();
+
+ init = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
+ TREE_CONSTANT (init) = 1;
+ TREE_STATIC (init) = 1;
+
+ resume_momentary (momentary);
+ }
+ else
+ {
+ int momentary = suspend_momentary ();
+
+ assemble_zeros (int_size_in_bytes (type));
+ init = error_mark_node;
+
+ resume_momentary (momentary);
+ }
+
+ pop_momentary_nofree ();
+
+ return init;
+}
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_intrinsic_ichar_ (tree tree_type, ffebld arg,
+ tree *maybe_tree)
+{
+ tree expr_tree;
+ tree length_tree;
+
+ switch (ffebld_op (arg))
+ {
+ case FFEBLD_opCONTER: /* For F90, check 0-length. */
+ if (ffetarget_length_character1
+ (ffebld_constant_character1
+ (ffebld_conter (arg))) == 0)
+ {
+ *maybe_tree = integer_zero_node;
+ return convert (tree_type, integer_zero_node);
+ }
+
+ *maybe_tree = integer_one_node;
+ expr_tree = build_int_2 (*ffetarget_text_character1
+ (ffebld_constant_character1
+ (ffebld_conter (arg))),
+ 0);
+ TREE_TYPE (expr_tree) = tree_type;
+ return expr_tree;
+
+ case FFEBLD_opSYMTER:
+ case FFEBLD_opARRAYREF:
+ case FFEBLD_opFUNCREF:
+ case FFEBLD_opSUBSTR:
+ ffecom_push_calltemps ();
+ ffecom_char_args_ (&expr_tree, &length_tree, arg);
+ ffecom_pop_calltemps ();
+
+ if ((expr_tree == error_mark_node)
+ || (length_tree == error_mark_node))
+ {
+ *maybe_tree = error_mark_node;
+ return error_mark_node;
+ }
+
+ if (integer_zerop (length_tree))
+ {
+ *maybe_tree = integer_zero_node;
+ return convert (tree_type, integer_zero_node);
+ }
+
+ expr_tree
+ = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (expr_tree))),
+ expr_tree);
+ expr_tree
+ = ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (expr_tree))),
+ expr_tree,
+ integer_one_node);
+ expr_tree = convert (tree_type, expr_tree);
+
+ if (TREE_CODE (length_tree) == INTEGER_CST)
+ *maybe_tree = integer_one_node;
+ else /* Must check length at run time. */
+ *maybe_tree
+ = ffecom_truth_value
+ (ffecom_2 (GT_EXPR, integer_type_node,
+ length_tree,
+ ffecom_f2c_ftnlen_zero_node));
+ return expr_tree;
+
+ case FFEBLD_opPAREN:
+ case FFEBLD_opCONVERT:
+ if (ffeinfo_size (ffebld_info (arg)) == 0)
+ {
+ *maybe_tree = integer_zero_node;
+ return convert (tree_type, integer_zero_node);
+ }
+ return ffecom_intrinsic_ichar_ (tree_type, ffebld_left (arg),
+ maybe_tree);
+
+ case FFEBLD_opCONCATENATE:
+ {
+ tree maybe_left;
+ tree maybe_right;
+ tree expr_left;
+ tree expr_right;
+
+ expr_left = ffecom_intrinsic_ichar_ (tree_type, ffebld_left (arg),
+ &maybe_left);
+ expr_right = ffecom_intrinsic_ichar_ (tree_type, ffebld_right (arg),
+ &maybe_right);
+ *maybe_tree = ffecom_2 (TRUTH_ORIF_EXPR, integer_type_node,
+ maybe_left,
+ maybe_right);
+ expr_tree = ffecom_3 (COND_EXPR, tree_type,
+ maybe_left,
+ expr_left,
+ expr_right);
+ return expr_tree;
+ }
+
+ default:
+ assert ("bad op in ICHAR" == NULL);
+ return error_mark_node;
+ }
+}
+
+#endif
+/* ffecom_intrinsic_len_ -- Return length info for char arg (LEN())
+
+ tree length_arg;
+ ffebld expr;
+ length_arg = ffecom_intrinsic_len_ (expr);
+
+ Handles CHARACTER-type CONTER, SYMTER, SUBSTR, ARRAYREF, and FUNCREF
+ subexpressions by constructing the appropriate tree for the
+ length-of-character-text argument in a calling sequence. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_intrinsic_len_ (ffebld expr)
+{
+ ffetargetCharacter1 val;
+ tree length;
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opCONTER:
+ val = ffebld_constant_character1 (ffebld_conter (expr));
+ length = build_int_2 (ffetarget_length_character1 (val), 0);
+ TREE_TYPE (length) = ffecom_f2c_ftnlen_type_node;
+ break;
+
+ case FFEBLD_opSYMTER:
+ {
+ ffesymbol s = ffebld_symter (expr);
+ tree item;
+
+ item = ffesymbol_hook (s).decl_tree;
+ if (item == NULL_TREE)
+ {
+ s = ffecom_sym_transform_ (s);
+ item = ffesymbol_hook (s).decl_tree;
+ }
+ if (ffesymbol_kind (s) == FFEINFO_kindENTITY)
+ {
+ if (ffesymbol_size (s) == FFETARGET_charactersizeNONE)
+ length = ffesymbol_hook (s).length_tree;
+ else
+ {
+ length = build_int_2 (ffesymbol_size (s), 0);
+ TREE_TYPE (length) = ffecom_f2c_ftnlen_type_node;
+ }
+ }
+ else if (item == error_mark_node)
+ length = error_mark_node;
+ else /* FFEINFO_kindFUNCTION: */
+ length = NULL_TREE;
+ }
+ break;
+
+ case FFEBLD_opARRAYREF:
+ length = ffecom_intrinsic_len_ (ffebld_left (expr));
+ break;
+
+ case FFEBLD_opSUBSTR:
+ {
+ ffebld start;
+ ffebld end;
+ ffebld thing = ffebld_right (expr);
+ tree start_tree;
+ tree end_tree;
+
+ assert (ffebld_op (thing) == FFEBLD_opITEM);
+ start = ffebld_head (thing);
+ thing = ffebld_trail (thing);
+ assert (ffebld_trail (thing) == NULL);
+ end = ffebld_head (thing);
+
+ length = ffecom_intrinsic_len_ (ffebld_left (expr));
+
+ if (length == error_mark_node)
+ break;
+
+ if (start == NULL)
+ {
+ if (end == NULL)
+ ;
+ else
+ {
+ length = convert (ffecom_f2c_ftnlen_type_node,
+ ffecom_expr (end));
+ }
+ }
+ else
+ {
+ start_tree = convert (ffecom_f2c_ftnlen_type_node,
+ ffecom_expr (start));
+
+ if (start_tree == error_mark_node)
+ {
+ length = error_mark_node;
+ break;
+ }
+
+ if (end == NULL)
+ {
+ length = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node,
+ ffecom_f2c_ftnlen_one_node,
+ ffecom_2 (MINUS_EXPR,
+ ffecom_f2c_ftnlen_type_node,
+ length,
+ start_tree));
+ }
+ else
+ {
+ end_tree = convert (ffecom_f2c_ftnlen_type_node,
+ ffecom_expr (end));
+
+ if (end_tree == error_mark_node)
+ {
+ length = error_mark_node;
+ break;
+ }
+
+ length = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node,
+ ffecom_f2c_ftnlen_one_node,
+ ffecom_2 (MINUS_EXPR,
+ ffecom_f2c_ftnlen_type_node,
+ end_tree, start_tree));
+ }
+ }
+ }
+ break;
+
+ case FFEBLD_opCONCATENATE:
+ length
+ = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node,
+ ffecom_intrinsic_len_ (ffebld_left (expr)),
+ ffecom_intrinsic_len_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opFUNCREF:
+ case FFEBLD_opCONVERT:
+ length = build_int_2 (ffebld_size (expr), 0);
+ TREE_TYPE (length) = ffecom_f2c_ftnlen_type_node;
+ break;
+
+ default:
+ assert ("bad op for single char arg expr" == NULL);
+ length = ffecom_f2c_ftnlen_zero_node;
+ break;
+ }
+
+ assert (length != NULL_TREE);
+
+ return length;
+}
+
+#endif
+/* ffecom_let_char_ -- Do assignment stuff for character type
+
+ tree dest_tree; // destination (ADDR_EXPR)
+ tree dest_length; // length (INT_CST/INDIRECT_REF(PARM_DECL))
+ ffetargetCharacterSize dest_size; // length
+ ffebld source; // source expression
+ ffecom_let_char_(dest_tree,dest_length,dest_size,source);
+
+ Generates code to do the assignment. Used by ordinary assignment
+ statement handler ffecom_let_stmt and by statement-function
+ handler to generate code for a statement function. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_let_char_ (tree dest_tree, tree dest_length,
+ ffetargetCharacterSize dest_size, ffebld source)
+{
+ ffecomConcatList_ catlist;
+ tree source_length;
+ tree source_tree;
+ tree expr_tree;
+
+ if ((dest_tree == error_mark_node)
+ || (dest_length == error_mark_node))
+ return;
+
+ assert (dest_tree != NULL_TREE);
+ assert (dest_length != NULL_TREE);
+
+ /* Source might be an opCONVERT, which just means it is a different size
+ than the destination. Since the underlying implementation here handles
+ that (directly or via the s_copy or s_cat run-time-library functions),
+ we don't need the "convenience" of an opCONVERT that tells us to
+ truncate or blank-pad, particularly since the resulting implementation
+ would probably be slower than otherwise. */
+
+ while (ffebld_op (source) == FFEBLD_opCONVERT)
+ source = ffebld_left (source);
+
+ catlist = ffecom_concat_list_new_ (source, dest_size);
+ switch (ffecom_concat_list_count_ (catlist))
+ {
+ case 0: /* Shouldn't happen, but in case it does... */
+ ffecom_concat_list_kill_ (catlist);
+ source_tree = null_pointer_node;
+ source_length = ffecom_f2c_ftnlen_zero_node;
+ expr_tree = build_tree_list (NULL_TREE, dest_tree);
+ TREE_CHAIN (expr_tree) = build_tree_list (NULL_TREE, source_tree);
+ TREE_CHAIN (TREE_CHAIN (expr_tree))
+ = build_tree_list (NULL_TREE, dest_length);
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (expr_tree)))
+ = build_tree_list (NULL_TREE, source_length);
+
+ expr_tree = ffecom_call_gfrt (FFECOM_gfrtCOPY, expr_tree);
+ TREE_SIDE_EFFECTS (expr_tree) = 1;
+
+ expand_expr_stmt (expr_tree);
+
+ return;
+
+ case 1: /* The (fairly) easy case. */
+ ffecom_char_args_ (&source_tree, &source_length,
+ ffecom_concat_list_expr_ (catlist, 0));
+ ffecom_concat_list_kill_ (catlist);
+ assert (source_tree != NULL_TREE);
+ assert (source_length != NULL_TREE);
+
+ if ((source_tree == error_mark_node)
+ || (source_length == error_mark_node))
+ return;
+
+ if (dest_size == 1)
+ {
+ dest_tree
+ = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE
+ (dest_tree))),
+ dest_tree);
+ dest_tree
+ = ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE
+ (dest_tree))),
+ dest_tree,
+ integer_one_node);
+ source_tree
+ = ffecom_1 (INDIRECT_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE
+ (source_tree))),
+ source_tree);
+ source_tree
+ = ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE
+ (source_tree))),
+ source_tree,
+ integer_one_node);
+
+ expr_tree = ffecom_modify (void_type_node, dest_tree, source_tree);
+
+ expand_expr_stmt (expr_tree);
+
+ return;
+ }
+
+ expr_tree = build_tree_list (NULL_TREE, dest_tree);
+ TREE_CHAIN (expr_tree) = build_tree_list (NULL_TREE, source_tree);
+ TREE_CHAIN (TREE_CHAIN (expr_tree))
+ = build_tree_list (NULL_TREE, dest_length);
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (expr_tree)))
+ = build_tree_list (NULL_TREE, source_length);
+
+ expr_tree = ffecom_call_gfrt (FFECOM_gfrtCOPY, expr_tree);
+ TREE_SIDE_EFFECTS (expr_tree) = 1;
+
+ expand_expr_stmt (expr_tree);
+
+ return;
+
+ default: /* Must actually concatenate things. */
+ break;
+ }
+
+ /* Heavy-duty concatenation. */
+
+ {
+ int count = ffecom_concat_list_count_ (catlist);
+ int i;
+ tree lengths;
+ tree items;
+ tree length_array;
+ tree item_array;
+ tree citem;
+ tree clength;
+
+ length_array
+ = lengths
+ = ffecom_push_tempvar (ffecom_f2c_ftnlen_type_node,
+ FFETARGET_charactersizeNONE, count, TRUE);
+ item_array = items = ffecom_push_tempvar (ffecom_f2c_address_type_node,
+ FFETARGET_charactersizeNONE,
+ count, TRUE);
+
+ for (i = 0; i < count; ++i)
+ {
+ ffecom_char_args_ (&citem, &clength,
+ ffecom_concat_list_expr_ (catlist, i));
+ if ((citem == error_mark_node)
+ || (clength == error_mark_node))
+ {
+ ffecom_concat_list_kill_ (catlist);
+ return;
+ }
+
+ items
+ = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (items),
+ ffecom_modify (void_type_node,
+ ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (item_array))),
+ item_array,
+ build_int_2 (i, 0)),
+ citem),
+ items);
+ lengths
+ = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (lengths),
+ ffecom_modify (void_type_node,
+ ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (length_array))),
+ length_array,
+ build_int_2 (i, 0)),
+ clength),
+ lengths);
+ }
+
+ expr_tree = build_tree_list (NULL_TREE, dest_tree);
+ TREE_CHAIN (expr_tree)
+ = build_tree_list (NULL_TREE,
+ ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (items)),
+ items));
+ TREE_CHAIN (TREE_CHAIN (expr_tree))
+ = build_tree_list (NULL_TREE,
+ ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (lengths)),
+ lengths));
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (expr_tree)))
+ = build_tree_list
+ (NULL_TREE,
+ ffecom_1 (ADDR_EXPR, ffecom_f2c_ptr_to_ftnlen_type_node,
+ convert (ffecom_f2c_ftnlen_type_node,
+ build_int_2 (count, 0))));
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (expr_tree))))
+ = build_tree_list (NULL_TREE, dest_length);
+
+ expr_tree = ffecom_call_gfrt (FFECOM_gfrtCAT, expr_tree);
+ TREE_SIDE_EFFECTS (expr_tree) = 1;
+
+ expand_expr_stmt (expr_tree);
+ }
+
+ ffecom_concat_list_kill_ (catlist);
+}
+
+#endif
+/* ffecom_make_gfrt_ -- Make initial info for run-time routine
+
+ ffecomGfrt ix;
+ ffecom_make_gfrt_(ix);
+
+ Assumes gfrt_[ix] is NULL_TREE, and replaces it with the FUNCTION_DECL
+ for the indicated run-time routine (ix). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_make_gfrt_ (ffecomGfrt ix)
+{
+ tree t;
+ tree ttype;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ switch (ffecom_gfrt_type_[ix])
+ {
+ case FFECOM_rttypeVOID_:
+ ttype = void_type_node;
+ break;
+
+ case FFECOM_rttypeVOIDSTAR_:
+ ttype = TREE_TYPE (null_pointer_node); /* `void *'. */
+ break;
+
+ case FFECOM_rttypeFTNINT_:
+ ttype = ffecom_f2c_ftnint_type_node;
+ break;
+
+ case FFECOM_rttypeINTEGER_:
+ ttype = ffecom_f2c_integer_type_node;
+ break;
+
+ case FFECOM_rttypeLONGINT_:
+ ttype = ffecom_f2c_longint_type_node;
+ break;
+
+ case FFECOM_rttypeLOGICAL_:
+ ttype = ffecom_f2c_logical_type_node;
+ break;
+
+ case FFECOM_rttypeREAL_F2C_:
+ ttype = double_type_node;
+ break;
+
+ case FFECOM_rttypeREAL_GNU_:
+ ttype = float_type_node;
+ break;
+
+ case FFECOM_rttypeCOMPLEX_F2C_:
+ ttype = void_type_node;
+ break;
+
+ case FFECOM_rttypeCOMPLEX_GNU_:
+ ttype = ffecom_f2c_complex_type_node;
+ break;
+
+ case FFECOM_rttypeDOUBLE_:
+ ttype = double_type_node;
+ break;
+
+ case FFECOM_rttypeDOUBLEREAL_:
+ ttype = ffecom_f2c_doublereal_type_node;
+ break;
+
+ case FFECOM_rttypeDBLCMPLX_F2C_:
+ ttype = void_type_node;
+ break;
+
+ case FFECOM_rttypeDBLCMPLX_GNU_:
+ ttype = ffecom_f2c_doublecomplex_type_node;
+ break;
+
+ case FFECOM_rttypeCHARACTER_:
+ ttype = void_type_node;
+ break;
+
+ default:
+ ttype = NULL;
+ assert ("bad rttype" == NULL);
+ break;
+ }
+
+ ttype = build_function_type (ttype, NULL_TREE);
+ t = build_decl (FUNCTION_DECL,
+ get_identifier (ffecom_gfrt_name_[ix]),
+ ttype);
+ DECL_EXTERNAL (t) = 1;
+ TREE_PUBLIC (t) = 1;
+ TREE_THIS_VOLATILE (t) = ffecom_gfrt_volatile_[ix] ? 1 : 0;
+
+ t = start_decl (t, TRUE);
+
+ finish_decl (t, NULL_TREE, TRUE);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ ffecom_gfrt_[ix] = t;
+}
+
+#endif
+/* Phase 1 pass over each member of a COMMON/EQUIVALENCE group. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_member_phase1_ (ffestorag mst UNUSED, ffestorag st)
+{
+ ffesymbol s = ffestorag_symbol (st);
+
+ if (ffesymbol_namelisted (s))
+ ffecom_member_namelisted_ = TRUE;
+}
+
+#endif
+/* Phase 2 pass over each member of a COMMON/EQUIVALENCE group. Declare
+ the member so debugger will see it. Otherwise nobody should be
+ referencing the member. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#ifdef SOMEONE_GETS_DEBUG_SUPPORT_WORKING
+static void
+ffecom_member_phase2_ (ffestorag mst, ffestorag st)
+{
+ ffesymbol s;
+ tree t;
+ tree mt;
+ tree type;
+
+ if ((mst == NULL)
+ || ((mt = ffestorag_hook (mst)) == NULL)
+ || (mt == error_mark_node))
+ return;
+
+ if ((st == NULL)
+ || ((s = ffestorag_symbol (st)) == NULL))
+ return;
+
+ type = ffecom_type_localvar_ (s,
+ ffesymbol_basictype (s),
+ ffesymbol_kindtype (s));
+ if (type == error_mark_node)
+ return;
+
+ t = build_decl (VAR_DECL,
+ ffecom_get_identifier_ (ffesymbol_text (s)),
+ type);
+
+ TREE_STATIC (t) = TREE_STATIC (mt);
+ DECL_INITIAL (t) = NULL_TREE;
+ TREE_ASM_WRITTEN (t) = 1;
+
+ DECL_RTL (t)
+ = gen_rtx (MEM, TYPE_MODE (type),
+ plus_constant (XEXP (DECL_RTL (mt), 0),
+ ffestorag_modulo (mst)
+ + ffestorag_offset (st)
+ - ffestorag_offset (mst)));
+
+ t = start_decl (t, FALSE);
+
+ finish_decl (t, NULL_TREE, FALSE);
+}
+
+#endif
+#endif
+/* ffecom_push_dummy_decls_ -- Transform dummy args, push parm decls in order
+
+ Ignores STAR (alternate-return) dummies. All other get exec-transitioned
+ (which generates their trees) and then their trees get push_parm_decl'd.
+
+ The second arg is TRUE if the dummies are for a statement function, in
+ which case lengths are not pushed for character arguments (since they are
+ always known by both the caller and the callee, though the code allows
+ for someday permitting CHAR*(*) stmtfunc dummies). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_push_dummy_decls_ (ffebld dummy_list, bool stmtfunc)
+{
+ ffebld dummy;
+ ffebld dumlist;
+ ffesymbol s;
+ tree parm;
+
+ ffecom_transform_only_dummies_ = TRUE;
+
+ /* First push the parms corresponding to actual dummy "contents". */
+
+ for (dumlist = dummy_list; dumlist != NULL; dumlist = ffebld_trail (dumlist))
+ {
+ dummy = ffebld_head (dumlist);
+ switch (ffebld_op (dummy))
+ {
+ case FFEBLD_opSTAR:
+ case FFEBLD_opANY:
+ continue; /* Forget alternate returns. */
+
+ default:
+ break;
+ }
+ assert (ffebld_op (dummy) == FFEBLD_opSYMTER);
+ s = ffebld_symter (dummy);
+ parm = ffesymbol_hook (s).decl_tree;
+ if (parm == NULL_TREE)
+ {
+ s = ffecom_sym_transform_ (s);
+ parm = ffesymbol_hook (s).decl_tree;
+ assert (parm != NULL_TREE);
+ }
+ if (parm != error_mark_node)
+ push_parm_decl (parm);
+ }
+
+ /* Then, for CHARACTER dummies, push the parms giving their lengths. */
+
+ for (dumlist = dummy_list; dumlist != NULL; dumlist = ffebld_trail (dumlist))
+ {
+ dummy = ffebld_head (dumlist);
+ switch (ffebld_op (dummy))
+ {
+ case FFEBLD_opSTAR:
+ case FFEBLD_opANY:
+ continue; /* Forget alternate returns, they mean
+ NOTHING! */
+
+ default:
+ break;
+ }
+ s = ffebld_symter (dummy);
+ if (ffesymbol_basictype (s) != FFEINFO_basictypeCHARACTER)
+ continue; /* Only looking for CHARACTER arguments. */
+ if (stmtfunc && (ffesymbol_size (s) != FFETARGET_charactersizeNONE))
+ continue; /* Stmtfunc arg with known size needs no
+ length param. */
+ if (ffesymbol_kind (s) != FFEINFO_kindENTITY)
+ continue; /* Only looking for variables and arrays. */
+ parm = ffesymbol_hook (s).length_tree;
+ assert (parm != NULL_TREE);
+ if (parm != error_mark_node)
+ push_parm_decl (parm);
+ }
+
+ ffecom_transform_only_dummies_ = FALSE;
+}
+
+#endif
+/* ffecom_start_progunit_ -- Beginning of program unit
+
+ Does GNU back end stuff necessary to teach it about the start of its
+ equivalent of a Fortran program unit. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_start_progunit_ ()
+{
+ ffesymbol fn = ffecom_primary_entry_;
+ ffebld arglist;
+ tree id; /* Identifier (name) of function. */
+ tree type; /* Type of function. */
+ tree result; /* Result of function. */
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffeglobal g;
+ ffeglobalType gt;
+ ffeglobalType egt = FFEGLOBAL_type;
+ bool charfunc;
+ bool cmplxfunc;
+ bool altentries = (ffecom_num_entrypoints_ != 0);
+ bool multi
+ = altentries
+ && (ffecom_primary_entry_kind_ == FFEINFO_kindFUNCTION)
+ && (ffecom_master_bt_ == FFEINFO_basictypeNONE);
+ bool main_program = FALSE;
+ int old_lineno = lineno;
+ char *old_input_filename = input_filename;
+ int yes;
+
+ assert (fn != NULL);
+ assert (ffesymbol_hook (fn).decl_tree == NULL_TREE);
+
+ input_filename = ffesymbol_where_filename (fn);
+ lineno = ffesymbol_where_filelinenum (fn);
+
+ /* c-parse.y indeed does call suspend_momentary and not only ignores the
+ return value, but also never calls resume_momentary, when starting an
+ outer function (see "fndef:", "setspecs:", and so on). So g77 does the
+ same thing. It shouldn't be a problem since start_function calls
+ temporary_allocation, but it might be necessary. If it causes a problem
+ here, then maybe there's a bug lurking in gcc. NOTE: This identical
+ comment appears twice in thist file. */
+
+ suspend_momentary ();
+
+ switch (ffecom_primary_entry_kind_)
+ {
+ case FFEINFO_kindPROGRAM:
+ main_program = TRUE;
+ gt = FFEGLOBAL_typeMAIN;
+ bt = FFEINFO_basictypeNONE;
+ kt = FFEINFO_kindtypeNONE;
+ type = ffecom_tree_fun_type_void;
+ charfunc = FALSE;
+ cmplxfunc = FALSE;
+ break;
+
+ case FFEINFO_kindBLOCKDATA:
+ gt = FFEGLOBAL_typeBDATA;
+ bt = FFEINFO_basictypeNONE;
+ kt = FFEINFO_kindtypeNONE;
+ type = ffecom_tree_fun_type_void;
+ charfunc = FALSE;
+ cmplxfunc = FALSE;
+ break;
+
+ case FFEINFO_kindFUNCTION:
+ gt = FFEGLOBAL_typeFUNC;
+ egt = FFEGLOBAL_typeEXT;
+ bt = ffesymbol_basictype (fn);
+ kt = ffesymbol_kindtype (fn);
+ if (bt == FFEINFO_basictypeNONE)
+ {
+ ffeimplic_establish_symbol (fn);
+ if (ffesymbol_funcresult (fn) != NULL)
+ ffeimplic_establish_symbol (ffesymbol_funcresult (fn));
+ bt = ffesymbol_basictype (fn);
+ kt = ffesymbol_kindtype (fn);
+ }
+
+ if (multi)
+ charfunc = cmplxfunc = FALSE;
+ else if (bt == FFEINFO_basictypeCHARACTER)
+ charfunc = TRUE, cmplxfunc = FALSE;
+ else if ((bt == FFEINFO_basictypeCOMPLEX)
+ && ffesymbol_is_f2c (fn)
+ && !altentries)
+ charfunc = FALSE, cmplxfunc = TRUE;
+ else
+ charfunc = cmplxfunc = FALSE;
+
+ if (multi || charfunc)
+ type = ffecom_tree_fun_type_void;
+ else if (ffesymbol_is_f2c (fn) && !altentries)
+ type = ffecom_tree_fun_type[bt][kt];
+ else
+ type = build_function_type (ffecom_tree_type[bt][kt], NULL_TREE);
+
+ if ((type == NULL_TREE)
+ || (TREE_TYPE (type) == NULL_TREE))
+ type = ffecom_tree_fun_type_void; /* _sym_exec_transition. */
+ break;
+
+ case FFEINFO_kindSUBROUTINE:
+ gt = FFEGLOBAL_typeSUBR;
+ egt = FFEGLOBAL_typeEXT;
+ bt = FFEINFO_basictypeNONE;
+ kt = FFEINFO_kindtypeNONE;
+ if (ffecom_is_altreturning_)
+ type = ffecom_tree_subr_type;
+ else
+ type = ffecom_tree_fun_type_void;
+ charfunc = FALSE;
+ cmplxfunc = FALSE;
+ break;
+
+ default:
+ assert ("say what??" == NULL);
+ /* Fall through. */
+ case FFEINFO_kindANY:
+ gt = FFEGLOBAL_typeANY;
+ bt = FFEINFO_basictypeNONE;
+ kt = FFEINFO_kindtypeNONE;
+ type = error_mark_node;
+ charfunc = FALSE;
+ cmplxfunc = FALSE;
+ break;
+ }
+
+ if (altentries)
+ {
+ id = ffecom_get_invented_identifier ("__g77_masterfun_%s",
+ ffesymbol_text (fn),
+ 0);
+ }
+#if FFETARGET_isENFORCED_MAIN
+ else if (main_program)
+ id = get_identifier (FFETARGET_nameENFORCED_MAIN_NAME);
+#endif
+ else
+ id = ffecom_get_external_identifier_ (fn);
+
+ start_function (id,
+ type,
+ 0, /* nested/inline */
+ !altentries); /* TREE_PUBLIC */
+
+ TREE_USED (current_function_decl) = 1; /* Avoid spurious warning if altentries. */
+
+ if (!altentries
+ && ((g = ffesymbol_global (fn)) != NULL)
+ && ((ffeglobal_type (g) == gt)
+ || (ffeglobal_type (g) == egt)))
+ {
+ ffeglobal_set_hook (g, current_function_decl);
+ }
+
+ yes = suspend_momentary ();
+
+ /* Arg handling needs exec-transitioned ffesymbols to work with. But
+ exec-transitioning needs current_function_decl to be filled in. So we
+ do these things in two phases. */
+
+ if (altentries)
+ { /* 1st arg identifies which entrypoint. */
+ ffecom_which_entrypoint_decl_
+ = build_decl (PARM_DECL,
+ ffecom_get_invented_identifier ("__g77_%s",
+ "which_entrypoint",
+ 0),
+ integer_type_node);
+ push_parm_decl (ffecom_which_entrypoint_decl_);
+ }
+
+ if (charfunc
+ || cmplxfunc
+ || multi)
+ { /* Arg for result (return value). */
+ tree type;
+ tree length;
+
+ if (charfunc)
+ type = ffecom_tree_type[FFEINFO_basictypeCHARACTER][kt];
+ else if (cmplxfunc)
+ type = ffecom_tree_type[FFEINFO_basictypeCOMPLEX][kt];
+ else
+ type = ffecom_multi_type_node_;
+
+ result = ffecom_get_invented_identifier ("__g77_%s",
+ "result", 0);
+
+ /* Make length arg _and_ enhance type info for CHAR arg itself. */
+
+ if (charfunc)
+ length = ffecom_char_enhance_arg_ (&type, fn);
+ else
+ length = NULL_TREE; /* Not ref'd if !charfunc. */
+
+ type = build_pointer_type (type);
+ result = build_decl (PARM_DECL, result, type);
+
+ push_parm_decl (result);
+ if (multi)
+ ffecom_multi_retval_ = result;
+ else
+ ffecom_func_result_ = result;
+
+ if (charfunc)
+ {
+ push_parm_decl (length);
+ ffecom_func_length_ = length;
+ }
+ }
+
+ if (ffecom_primary_entry_is_proc_)
+ {
+ if (altentries)
+ arglist = ffecom_master_arglist_;
+ else
+ arglist = ffesymbol_dummyargs (fn);
+ ffecom_push_dummy_decls_ (arglist, FALSE);
+ }
+
+ resume_momentary (yes);
+
+ if (TREE_CODE (current_function_decl) != ERROR_MARK)
+ store_parm_decls (main_program ? 1 : 0);
+
+ ffecom_start_compstmt_ ();
+
+ lineno = old_lineno;
+ input_filename = old_input_filename;
+
+ /* This handles any symbols still untransformed, in case -g specified.
+ This used to be done in ffecom_finish_progunit, but it turns out to
+ be necessary to do it here so that statement functions are
+ expanded before code. But don't bother for BLOCK DATA. */
+
+ if (ffecom_primary_entry_kind_ != FFEINFO_kindBLOCKDATA)
+ ffesymbol_drive (ffecom_finish_symbol_transform_);
+}
+
+#endif
+/* ffecom_sym_transform_ -- Transform FFE sym into backend sym
+
+ ffesymbol s;
+ ffecom_sym_transform_(s);
+
+ The ffesymbol_hook info for s is updated with appropriate backend info
+ on the symbol. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static ffesymbol
+ffecom_sym_transform_ (ffesymbol s)
+{
+ tree t; /* Transformed thingy. */
+ tree tlen; /* Length if CHAR*(*). */
+ bool addr; /* Is t the address of the thingy? */
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffeglobal g;
+ int yes;
+ int old_lineno = lineno;
+ char *old_input_filename = input_filename;
+
+ if (ffesymbol_sfdummyparent (s) == NULL)
+ {
+ input_filename = ffesymbol_where_filename (s);
+ lineno = ffesymbol_where_filelinenum (s);
+ }
+ else
+ {
+ ffesymbol sf = ffesymbol_sfdummyparent (s);
+
+ input_filename = ffesymbol_where_filename (sf);
+ lineno = ffesymbol_where_filelinenum (sf);
+ }
+
+ bt = ffeinfo_basictype (ffebld_info (s));
+ kt = ffeinfo_kindtype (ffebld_info (s));
+
+ t = NULL_TREE;
+ tlen = NULL_TREE;
+ addr = FALSE;
+
+ switch (ffesymbol_kind (s))
+ {
+ case FFEINFO_kindNONE:
+ switch (ffesymbol_where (s))
+ {
+ case FFEINFO_whereDUMMY: /* Subroutine or function. */
+ assert (ffecom_transform_only_dummies_);
+
+ /* Before 0.4, this could be ENTITY/DUMMY, but see
+ ffestu_sym_end_transition -- no longer true (in particular, if
+ it could be an ENTITY, it _will_ be made one, so that
+ possibility won't come through here). So we never make length
+ arg for CHARACTER type. */
+
+ t = build_decl (PARM_DECL,
+ ffecom_get_identifier_ (ffesymbol_text (s)),
+ ffecom_tree_ptr_to_subr_type);
+#if BUILT_FOR_270
+ DECL_ARTIFICIAL (t) = 1;
+#endif
+ addr = TRUE;
+ break;
+
+ case FFEINFO_whereGLOBAL: /* Subroutine or function. */
+ assert (!ffecom_transform_only_dummies_);
+
+ if (((g = ffesymbol_global (s)) != NULL)
+ && ((ffeglobal_type (g) == FFEGLOBAL_typeSUBR)
+ || (ffeglobal_type (g) == FFEGLOBAL_typeFUNC)
+ || (ffeglobal_type (g) == FFEGLOBAL_typeEXT))
+ && (ffeglobal_hook (g) != NULL_TREE)
+ && ffe_is_globals ())
+ {
+ t = ffeglobal_hook (g);
+ break;
+ }
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ t = build_decl (FUNCTION_DECL,
+ ffecom_get_external_identifier_ (s),
+ ffecom_tree_subr_type); /* Assume subr. */
+ DECL_EXTERNAL (t) = 1;
+ TREE_PUBLIC (t) = 1;
+
+ t = start_decl (t, FALSE);
+ finish_decl (t, NULL_TREE, FALSE);
+
+ if ((g != NULL)
+ && ((ffeglobal_type (g) == FFEGLOBAL_typeSUBR)
+ || (ffeglobal_type (g) == FFEGLOBAL_typeFUNC)
+ || (ffeglobal_type (g) == FFEGLOBAL_typeEXT)))
+ ffeglobal_set_hook (g, t);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ break;
+
+ default:
+ assert ("NONE where unexpected" == NULL);
+ /* Fall through. */
+ case FFEINFO_whereANY:
+ break;
+ }
+ break;
+
+ case FFEINFO_kindENTITY:
+ switch (ffeinfo_where (ffesymbol_info (s)))
+ {
+
+ case FFEINFO_whereCONSTANT: /* ~~debugging info needed? */
+ assert (!ffecom_transform_only_dummies_);
+ t = error_mark_node; /* Shouldn't ever see this in expr. */
+ break;
+
+ case FFEINFO_whereLOCAL:
+ assert (!ffecom_transform_only_dummies_);
+
+ {
+ ffestorag st = ffesymbol_storage (s);
+ tree type;
+
+ if ((st != NULL)
+ && (ffestorag_size (st) == 0))
+ {
+ t = error_mark_node;
+ break;
+ }
+
+ yes = suspend_momentary ();
+ type = ffecom_type_localvar_ (s, bt, kt);
+ resume_momentary (yes);
+
+ if (type == error_mark_node)
+ {
+ t = error_mark_node;
+ break;
+ }
+
+ if ((st != NULL)
+ && (ffestorag_parent (st) != NULL))
+ { /* Child of EQUIVALENCE parent. */
+ ffestorag est;
+ tree et;
+ int yes;
+ ffetargetOffset offset;
+
+ est = ffestorag_parent (st);
+ ffecom_transform_equiv_ (est);
+
+ et = ffestorag_hook (est);
+ assert (et != NULL_TREE);
+
+ if (! TREE_STATIC (et))
+ put_var_into_stack (et);
+
+ yes = suspend_momentary ();
+
+ offset = ffestorag_modulo (est)
+ + ffestorag_offset (ffesymbol_storage (s))
+ - ffestorag_offset (est);
+
+ ffecom_debug_kludge_ (et, "EQUIVALENCE", s, type, offset);
+
+ /* (t_type *) (((char *) &et) + offset) */
+
+ t = convert (string_type_node, /* (char *) */
+ ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (et)),
+ et));
+ t = ffecom_2 (PLUS_EXPR, TREE_TYPE (t),
+ t,
+ build_int_2 (offset, 0));
+ t = convert (build_pointer_type (type),
+ t);
+
+ addr = TRUE;
+
+ resume_momentary (yes);
+ }
+ else
+ {
+ tree initexpr;
+ bool init = ffesymbol_is_init (s);
+
+ yes = suspend_momentary ();
+
+ t = build_decl (VAR_DECL,
+ ffecom_get_identifier_ (ffesymbol_text (s)),
+ type);
+
+ if (init
+ || ffesymbol_namelisted (s)
+#ifdef FFECOM_sizeMAXSTACKITEM
+ || ((st != NULL)
+ && (ffestorag_size (st) > FFECOM_sizeMAXSTACKITEM))
+#endif
+ || ((ffecom_primary_entry_kind_ != FFEINFO_kindPROGRAM)
+ && (ffecom_primary_entry_kind_
+ != FFEINFO_kindBLOCKDATA)
+ && (ffesymbol_is_save (s) || ffe_is_saveall ())))
+ TREE_STATIC (t) = !ffesymbol_attr (s, FFESYMBOL_attrADJUSTABLE);
+ else
+ TREE_STATIC (t) = 0; /* No need to make static. */
+
+ if (init || ffe_is_init_local_zero ())
+ DECL_INITIAL (t) = error_mark_node;
+
+ /* Keep -Wunused from complaining about var if it
+ is used as sfunc arg or DATA implied-DO. */
+ if (ffesymbol_attrs (s) & FFESYMBOL_attrsSFARG)
+ DECL_IN_SYSTEM_HEADER (t) = 1;
+
+ t = start_decl (t, FALSE);
+
+ if (init)
+ {
+ if (ffesymbol_init (s) != NULL)
+ initexpr = ffecom_expr (ffesymbol_init (s));
+ else
+ initexpr = ffecom_init_zero_ (t);
+ }
+ else if (ffe_is_init_local_zero ())
+ initexpr = ffecom_init_zero_ (t);
+ else
+ initexpr = NULL_TREE; /* Not ref'd if !init. */
+
+ finish_decl (t, initexpr, FALSE);
+
+ if ((st != NULL) && (DECL_SIZE (t) != error_mark_node))
+ {
+ tree size_tree;
+
+ size_tree = size_binop (CEIL_DIV_EXPR,
+ DECL_SIZE (t),
+ size_int (BITS_PER_UNIT));
+ assert (TREE_INT_CST_HIGH (size_tree) == 0);
+ assert (TREE_INT_CST_LOW (size_tree) == ffestorag_size (st));
+ }
+
+ resume_momentary (yes);
+ }
+ }
+ break;
+
+ case FFEINFO_whereRESULT:
+ assert (!ffecom_transform_only_dummies_);
+
+ if (bt == FFEINFO_basictypeCHARACTER)
+ { /* Result is already in list of dummies, use
+ it (& length). */
+ t = ffecom_func_result_;
+ tlen = ffecom_func_length_;
+ addr = TRUE;
+ break;
+ }
+ if ((ffecom_num_entrypoints_ == 0)
+ && (bt == FFEINFO_basictypeCOMPLEX)
+ && (ffesymbol_is_f2c (ffecom_primary_entry_)))
+ { /* Result is already in list of dummies, use
+ it. */
+ t = ffecom_func_result_;
+ addr = TRUE;
+ break;
+ }
+ if (ffecom_func_result_ != NULL_TREE)
+ {
+ t = ffecom_func_result_;
+ break;
+ }
+ if ((ffecom_num_entrypoints_ != 0)
+ && (ffecom_master_bt_ == FFEINFO_basictypeNONE))
+ {
+ yes = suspend_momentary ();
+
+ assert (ffecom_multi_retval_ != NULL_TREE);
+ t = ffecom_1 (INDIRECT_REF, ffecom_multi_type_node_,
+ ffecom_multi_retval_);
+ t = ffecom_2 (COMPONENT_REF, ffecom_tree_type[bt][kt],
+ t, ffecom_multi_fields_[bt][kt]);
+
+ resume_momentary (yes);
+ break;
+ }
+
+ yes = suspend_momentary ();
+
+ t = build_decl (VAR_DECL,
+ ffecom_get_identifier_ (ffesymbol_text (s)),
+ ffecom_tree_type[bt][kt]);
+ TREE_STATIC (t) = 0; /* Put result on stack. */
+ t = start_decl (t, FALSE);
+ finish_decl (t, NULL_TREE, FALSE);
+
+ ffecom_func_result_ = t;
+
+ resume_momentary (yes);
+ break;
+
+ case FFEINFO_whereDUMMY:
+ {
+ tree type;
+ ffebld dl;
+ ffebld dim;
+ tree low;
+ tree high;
+ tree old_sizes;
+ bool adjustable = FALSE; /* Conditionally adjustable? */
+
+ type = ffecom_tree_type[bt][kt];
+ if (ffesymbol_sfdummyparent (s) != NULL)
+ {
+ if (current_function_decl == ffecom_outer_function_decl_)
+ { /* Exec transition before sfunc
+ context; get it later. */
+ break;
+ }
+ t = ffecom_get_identifier_ (ffesymbol_text
+ (ffesymbol_sfdummyparent (s)));
+ }
+ else
+ t = ffecom_get_identifier_ (ffesymbol_text (s));
+
+ assert (ffecom_transform_only_dummies_);
+
+ old_sizes = get_pending_sizes ();
+ put_pending_sizes (old_sizes);
+
+ if (bt == FFEINFO_basictypeCHARACTER)
+ tlen = ffecom_char_enhance_arg_ (&type, s);
+ type = ffecom_check_size_overflow_ (s, type, TRUE);
+
+ for (dl = ffesymbol_dims (s); dl != NULL; dl = ffebld_trail (dl))
+ {
+ if (type == error_mark_node)
+ break;
+
+ dim = ffebld_head (dl);
+ assert (ffebld_op (dim) == FFEBLD_opBOUNDS);
+ if ((ffebld_left (dim) == NULL) || ffecom_doing_entry_)
+ low = ffecom_integer_one_node;
+ else
+ low = ffecom_expr (ffebld_left (dim));
+ assert (ffebld_right (dim) != NULL);
+ if ((ffebld_op (ffebld_right (dim)) == FFEBLD_opSTAR)
+ || ffecom_doing_entry_)
+ {
+ /* Used to just do high=low. But for ffecom_tree_
+ canonize_ref_, it probably is important to correctly
+ assess the size. E.g. given COMPLEX C(*),CFUNC and
+ C(2)=CFUNC(C), overlap can happen, while it can't
+ for, say, C(1)=CFUNC(C(2)). */
+ /* Even more recently used to set to INT_MAX, but that
+ broke when some overflow checking went into the back
+ end. Now we just leave the upper bound unspecified. */
+ high = NULL;
+ }
+ else
+ high = ffecom_expr (ffebld_right (dim));
+
+ /* Determine whether array is conditionally adjustable,
+ to decide whether back-end magic is needed.
+
+ Normally the front end uses the back-end function
+ variable_size to wrap SAVE_EXPR's around expressions
+ affecting the size/shape of an array so that the
+ size/shape info doesn't change during execution
+ of the compiled code even though variables and
+ functions referenced in those expressions might.
+
+ variable_size also makes sure those saved expressions
+ get evaluated immediately upon entry to the
+ compiled procedure -- the front end normally doesn't
+ have to worry about that.
+
+ However, there is a problem with this that affects
+ g77's implementation of entry points, and that is
+ that it is _not_ true that each invocation of the
+ compiled procedure is permitted to evaluate
+ array size/shape info -- because it is possible
+ that, for some invocations, that info is invalid (in
+ which case it is "promised" -- i.e. a violation of
+ the Fortran standard -- that the compiled code
+ won't reference the array or its size/shape
+ during that particular invocation).
+
+ To phrase this in C terms, consider this gcc function:
+
+ void foo (int *n, float (*a)[*n])
+ {
+ // a is "pointer to array ...", fyi.
+ }
+
+ Suppose that, for some invocations, it is permitted
+ for a caller of foo to do this:
+
+ foo (NULL, NULL);
+
+ Now the _written_ code for foo can take such a call
+ into account by either testing explicitly for whether
+ (a == NULL) || (n == NULL) -- presumably it is
+ not permitted to reference *a in various fashions
+ if (n == NULL) I suppose -- or it can avoid it by
+ looking at other info (other arguments, static/global
+ data, etc.).
+
+ However, this won't work in gcc 2.5.8 because it'll
+ automatically emit the code to save the "*n"
+ expression, which'll yield a NULL dereference for
+ the "foo (NULL, NULL)" call, something the code
+ for foo cannot prevent.
+
+ g77 definitely needs to avoid executing such
+ code anytime the pointer to the adjustable array
+ is NULL, because even if its bounds expressions
+ don't have any references to possible "absent"
+ variables like "*n" -- say all variable references
+ are to COMMON variables, i.e. global (though in C,
+ local static could actually make sense) -- the
+ expressions could yield other run-time problems
+ for allowably "dead" values in those variables.
+
+ For example, let's consider a more complicated
+ version of foo:
+
+ extern int i;
+ extern int j;
+
+ void foo (float (*a)[i/j])
+ {
+ ...
+ }
+
+ The above is (essentially) quite valid for Fortran
+ but, again, for a call like "foo (NULL);", it is
+ permitted for i and j to be undefined when the
+ call is made. If j happened to be zero, for
+ example, emitting the code to evaluate "i/j"
+ could result in a run-time error.
+
+ Offhand, though I don't have my F77 or F90
+ standards handy, it might even be valid for a
+ bounds expression to contain a function reference,
+ in which case I doubt it is permitted for an
+ implementation to invoke that function in the
+ Fortran case involved here (invocation of an
+ alternate ENTRY point that doesn't have the adjustable
+ array as one of its arguments).
+
+ So, the code that the compiler would normally emit
+ to preevaluate the size/shape info for an
+ adjustable array _must not_ be executed at run time
+ in certain cases. Specifically, for Fortran,
+ the case is when the pointer to the adjustable
+ array == NULL. (For gnu-ish C, it might be nice
+ for the source code itself to specify an expression
+ that, if TRUE, inhibits execution of the code. Or
+ reverse the sense for elegance.)
+
+ (Note that g77 could use a different test than NULL,
+ actually, since it happens to always pass an
+ integer to the called function that specifies which
+ entry point is being invoked. Hmm, this might
+ solve the next problem.)
+
+ One way a user could, I suppose, write "foo" so
+ it works is to insert COND_EXPR's for the
+ size/shape info so the dangerous stuff isn't
+ actually done, as in:
+
+ void foo (int *n, float (*a)[(a == NULL) ? 0 : *n])
+ {
+ ...
+ }
+
+ The next problem is that the front end needs to
+ be able to tell the back end about the array's
+ decl _before_ it tells it about the conditional
+ expression to inhibit evaluation of size/shape info,
+ as shown above.
+
+ To solve this, the front end needs to be able
+ to give the back end the expression to inhibit
+ generation of the preevaluation code _after_
+ it makes the decl for the adjustable array.
+
+ Until then, the above example using the COND_EXPR
+ doesn't pass muster with gcc because the "(a == NULL)"
+ part has a reference to "a", which is still
+ undefined at that point.
+
+ g77 will therefore use a different mechanism in the
+ meantime. */
+
+ if (!adjustable
+ && ((TREE_CODE (low) != INTEGER_CST)
+ || (high && TREE_CODE (high) != INTEGER_CST)))
+ adjustable = TRUE;
+
+#if 0 /* Old approach -- see below. */
+ if (TREE_CODE (low) != INTEGER_CST)
+ low = ffecom_3 (COND_EXPR, integer_type_node,
+ ffecom_adjarray_passed_ (s),
+ low,
+ ffecom_integer_zero_node);
+
+ if (high && TREE_CODE (high) != INTEGER_CST)
+ high = ffecom_3 (COND_EXPR, integer_type_node,
+ ffecom_adjarray_passed_ (s),
+ high,
+ ffecom_integer_zero_node);
+#endif
+
+ /* ~~~gcc/stor-layout.c/layout_type should do this,
+ probably. Fixes 950302-1.f. */
+
+ if (TREE_CODE (low) != INTEGER_CST)
+ low = variable_size (low);
+
+ /* ~~~similarly, this fixes dumb0.f. The C front end
+ does this, which is why dumb0.c would work. */
+
+ if (high && TREE_CODE (high) != INTEGER_CST)
+ high = variable_size (high);
+
+ type
+ = build_array_type
+ (type,
+ build_range_type (ffecom_integer_type_node,
+ low, high));
+ type = ffecom_check_size_overflow_ (s, type, TRUE);
+ }
+
+ if (type == error_mark_node)
+ {
+ t = error_mark_node;
+ break;
+ }
+
+ if ((ffesymbol_sfdummyparent (s) == NULL)
+ || (ffesymbol_basictype (s) == FFEINFO_basictypeCHARACTER))
+ {
+ type = build_pointer_type (type);
+ addr = TRUE;
+ }
+
+ t = build_decl (PARM_DECL, t, type);
+#if BUILT_FOR_270
+ DECL_ARTIFICIAL (t) = 1;
+#endif
+
+ /* If this arg is present in every entry point's list of
+ dummy args, then we're done. */
+
+ if (ffesymbol_numentries (s)
+ == (ffecom_num_entrypoints_ + 1))
+ break;
+
+#if 1
+
+ /* If variable_size in stor-layout has been called during
+ the above, then get_pending_sizes should have the
+ yet-to-be-evaluated saved expressions pending.
+ Make the whole lot of them get emitted, conditionally
+ on whether the array decl ("t" above) is not NULL. */
+
+ {
+ tree sizes = get_pending_sizes ();
+ tree tem;
+
+ for (tem = sizes;
+ tem != old_sizes;
+ tem = TREE_CHAIN (tem))
+ {
+ tree temv = TREE_VALUE (tem);
+
+ if (sizes == tem)
+ sizes = temv;
+ else
+ sizes
+ = ffecom_2 (COMPOUND_EXPR,
+ TREE_TYPE (sizes),
+ temv,
+ sizes);
+ }
+
+ if (sizes != tem)
+ {
+ sizes
+ = ffecom_3 (COND_EXPR,
+ TREE_TYPE (sizes),
+ ffecom_2 (NE_EXPR,
+ integer_type_node,
+ t,
+ null_pointer_node),
+ sizes,
+ convert (TREE_TYPE (sizes),
+ integer_zero_node));
+ sizes = ffecom_save_tree (sizes);
+
+ sizes
+ = tree_cons (NULL_TREE, sizes, tem);
+ }
+
+ if (sizes)
+ put_pending_sizes (sizes);
+ }
+
+#else
+#if 0
+ if (adjustable
+ && (ffesymbol_numentries (s)
+ != ffecom_num_entrypoints_ + 1))
+ DECL_SOMETHING (t)
+ = ffecom_2 (NE_EXPR, integer_type_node,
+ t,
+ null_pointer_node);
+#else
+#if 0
+ if (adjustable
+ && (ffesymbol_numentries (s)
+ != ffecom_num_entrypoints_ + 1))
+ {
+ ffebad_start (FFEBAD_MISSING_ADJARRAY_UNSUPPORTED);
+ ffebad_here (0, ffesymbol_where_line (s),
+ ffesymbol_where_column (s));
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ }
+#endif
+#endif
+#endif
+ }
+ break;
+
+ case FFEINFO_whereCOMMON:
+ {
+ ffesymbol cs;
+ ffeglobal cg;
+ tree ct;
+ ffestorag st = ffesymbol_storage (s);
+ tree type;
+ int yes;
+
+ cs = ffesymbol_common (s); /* The COMMON area itself. */
+ if (st != NULL) /* Else not laid out. */
+ {
+ ffecom_transform_common_ (cs);
+ st = ffesymbol_storage (s);
+ }
+
+ yes = suspend_momentary ();
+
+ type = ffecom_type_localvar_ (s, bt, kt);
+
+ cg = ffesymbol_global (cs); /* The global COMMON info. */
+ if ((cg == NULL)
+ || (ffeglobal_type (cg) != FFEGLOBAL_typeCOMMON))
+ ct = NULL_TREE;
+ else
+ ct = ffeglobal_hook (cg); /* The common area's tree. */
+
+ if ((ct == NULL_TREE)
+ || (st == NULL)
+ || (type == error_mark_node))
+ t = error_mark_node;
+ else
+ {
+ ffetargetOffset offset;
+ ffestorag cst;
+
+ cst = ffestorag_parent (st);
+ assert (cst == ffesymbol_storage (cs));
+
+ offset = ffestorag_modulo (cst)
+ + ffestorag_offset (st)
+ - ffestorag_offset (cst);
+
+ ffecom_debug_kludge_ (ct, "COMMON", s, type, offset);
+
+ /* (t_type *) (((char *) &ct) + offset) */
+
+ t = convert (string_type_node, /* (char *) */
+ ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (ct)),
+ ct));
+ t = ffecom_2 (PLUS_EXPR, TREE_TYPE (t),
+ t,
+ build_int_2 (offset, 0));
+ t = convert (build_pointer_type (type),
+ t);
+
+ addr = TRUE;
+ }
+
+ resume_momentary (yes);
+ }
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ case FFEINFO_whereGLOBAL:
+ case FFEINFO_whereFLEETING:
+ case FFEINFO_whereFLEETING_CADDR:
+ case FFEINFO_whereFLEETING_IADDR:
+ case FFEINFO_whereINTRINSIC:
+ case FFEINFO_whereCONSTANT_SUBOBJECT:
+ default:
+ assert ("ENTITY where unheard of" == NULL);
+ /* Fall through. */
+ case FFEINFO_whereANY:
+ t = error_mark_node;
+ break;
+ }
+ break;
+
+ case FFEINFO_kindFUNCTION:
+ switch (ffeinfo_where (ffesymbol_info (s)))
+ {
+ case FFEINFO_whereLOCAL: /* Me. */
+ assert (!ffecom_transform_only_dummies_);
+ t = current_function_decl;
+ break;
+
+ case FFEINFO_whereGLOBAL:
+ assert (!ffecom_transform_only_dummies_);
+
+ if (((g = ffesymbol_global (s)) != NULL)
+ && ((ffeglobal_type (g) == FFEGLOBAL_typeFUNC)
+ || (ffeglobal_type (g) == FFEGLOBAL_typeEXT))
+ && (ffeglobal_hook (g) != NULL_TREE)
+ && ffe_is_globals ())
+ {
+ t = ffeglobal_hook (g);
+ break;
+ }
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ if (ffesymbol_is_f2c (s)
+ && (ffesymbol_where (s) != FFEINFO_whereCONSTANT))
+ t = ffecom_tree_fun_type[bt][kt];
+ else
+ t = build_function_type (ffecom_tree_type[bt][kt], NULL_TREE);
+
+ t = build_decl (FUNCTION_DECL,
+ ffecom_get_external_identifier_ (s),
+ t);
+ DECL_EXTERNAL (t) = 1;
+ TREE_PUBLIC (t) = 1;
+
+ t = start_decl (t, FALSE);
+ finish_decl (t, NULL_TREE, FALSE);
+
+ if ((g != NULL)
+ && ((ffeglobal_type (g) == FFEGLOBAL_typeFUNC)
+ || (ffeglobal_type (g) == FFEGLOBAL_typeEXT)))
+ ffeglobal_set_hook (g, t);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ break;
+
+ case FFEINFO_whereDUMMY:
+ assert (ffecom_transform_only_dummies_);
+
+ if (ffesymbol_is_f2c (s)
+ && (ffesymbol_where (s) != FFEINFO_whereCONSTANT))
+ t = ffecom_tree_ptr_to_fun_type[bt][kt];
+ else
+ t = build_pointer_type
+ (build_function_type (ffecom_tree_type[bt][kt], NULL_TREE));
+
+ t = build_decl (PARM_DECL,
+ ffecom_get_identifier_ (ffesymbol_text (s)),
+ t);
+#if BUILT_FOR_270
+ DECL_ARTIFICIAL (t) = 1;
+#endif
+ addr = TRUE;
+ break;
+
+ case FFEINFO_whereCONSTANT: /* Statement function. */
+ assert (!ffecom_transform_only_dummies_);
+ t = ffecom_gen_sfuncdef_ (s, bt, kt);
+ break;
+
+ case FFEINFO_whereINTRINSIC:
+ assert (!ffecom_transform_only_dummies_);
+ break; /* Let actual references generate their
+ decls. */
+
+ default:
+ assert ("FUNCTION where unheard of" == NULL);
+ /* Fall through. */
+ case FFEINFO_whereANY:
+ t = error_mark_node;
+ break;
+ }
+ break;
+
+ case FFEINFO_kindSUBROUTINE:
+ switch (ffeinfo_where (ffesymbol_info (s)))
+ {
+ case FFEINFO_whereLOCAL: /* Me. */
+ assert (!ffecom_transform_only_dummies_);
+ t = current_function_decl;
+ break;
+
+ case FFEINFO_whereGLOBAL:
+ assert (!ffecom_transform_only_dummies_);
+
+ if (((g = ffesymbol_global (s)) != NULL)
+ && ((ffeglobal_type (g) == FFEGLOBAL_typeSUBR)
+ || (ffeglobal_type (g) == FFEGLOBAL_typeEXT))
+ && (ffeglobal_hook (g) != NULL_TREE)
+ && ffe_is_globals ())
+ {
+ t = ffeglobal_hook (g);
+ break;
+ }
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ t = build_decl (FUNCTION_DECL,
+ ffecom_get_external_identifier_ (s),
+ ffecom_tree_subr_type);
+ DECL_EXTERNAL (t) = 1;
+ TREE_PUBLIC (t) = 1;
+
+ t = start_decl (t, FALSE);
+ finish_decl (t, NULL_TREE, FALSE);
+
+ if ((g != NULL)
+ && ((ffeglobal_type (g) == FFEGLOBAL_typeSUBR)
+ || (ffeglobal_type (g) == FFEGLOBAL_typeEXT)))
+ ffeglobal_set_hook (g, t);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ break;
+
+ case FFEINFO_whereDUMMY:
+ assert (ffecom_transform_only_dummies_);
+
+ t = build_decl (PARM_DECL,
+ ffecom_get_identifier_ (ffesymbol_text (s)),
+ ffecom_tree_ptr_to_subr_type);
+#if BUILT_FOR_270
+ DECL_ARTIFICIAL (t) = 1;
+#endif
+ addr = TRUE;
+ break;
+
+ case FFEINFO_whereINTRINSIC:
+ assert (!ffecom_transform_only_dummies_);
+ break; /* Let actual references generate their
+ decls. */
+
+ default:
+ assert ("SUBROUTINE where unheard of" == NULL);
+ /* Fall through. */
+ case FFEINFO_whereANY:
+ t = error_mark_node;
+ break;
+ }
+ break;
+
+ case FFEINFO_kindPROGRAM:
+ switch (ffeinfo_where (ffesymbol_info (s)))
+ {
+ case FFEINFO_whereLOCAL: /* Me. */
+ assert (!ffecom_transform_only_dummies_);
+ t = current_function_decl;
+ break;
+
+ case FFEINFO_whereCOMMON:
+ case FFEINFO_whereDUMMY:
+ case FFEINFO_whereGLOBAL:
+ case FFEINFO_whereRESULT:
+ case FFEINFO_whereFLEETING:
+ case FFEINFO_whereFLEETING_CADDR:
+ case FFEINFO_whereFLEETING_IADDR:
+ case FFEINFO_whereIMMEDIATE:
+ case FFEINFO_whereINTRINSIC:
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereCONSTANT_SUBOBJECT:
+ default:
+ assert ("PROGRAM where unheard of" == NULL);
+ /* Fall through. */
+ case FFEINFO_whereANY:
+ t = error_mark_node;
+ break;
+ }
+ break;
+
+ case FFEINFO_kindBLOCKDATA:
+ switch (ffeinfo_where (ffesymbol_info (s)))
+ {
+ case FFEINFO_whereLOCAL: /* Me. */
+ assert (!ffecom_transform_only_dummies_);
+ t = current_function_decl;
+ break;
+
+ case FFEINFO_whereGLOBAL:
+ assert (!ffecom_transform_only_dummies_);
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ t = build_decl (FUNCTION_DECL,
+ ffecom_get_external_identifier_ (s),
+ ffecom_tree_blockdata_type);
+ DECL_EXTERNAL (t) = 1;
+ TREE_PUBLIC (t) = 1;
+
+ t = start_decl (t, FALSE);
+ finish_decl (t, NULL_TREE, FALSE);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ break;
+
+ case FFEINFO_whereCOMMON:
+ case FFEINFO_whereDUMMY:
+ case FFEINFO_whereRESULT:
+ case FFEINFO_whereFLEETING:
+ case FFEINFO_whereFLEETING_CADDR:
+ case FFEINFO_whereFLEETING_IADDR:
+ case FFEINFO_whereIMMEDIATE:
+ case FFEINFO_whereINTRINSIC:
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereCONSTANT_SUBOBJECT:
+ default:
+ assert ("BLOCKDATA where unheard of" == NULL);
+ /* Fall through. */
+ case FFEINFO_whereANY:
+ t = error_mark_node;
+ break;
+ }
+ break;
+
+ case FFEINFO_kindCOMMON:
+ switch (ffeinfo_where (ffesymbol_info (s)))
+ {
+ case FFEINFO_whereLOCAL:
+ assert (!ffecom_transform_only_dummies_);
+ ffecom_transform_common_ (s);
+ break;
+
+ case FFEINFO_whereNONE:
+ case FFEINFO_whereCOMMON:
+ case FFEINFO_whereDUMMY:
+ case FFEINFO_whereGLOBAL:
+ case FFEINFO_whereRESULT:
+ case FFEINFO_whereFLEETING:
+ case FFEINFO_whereFLEETING_CADDR:
+ case FFEINFO_whereFLEETING_IADDR:
+ case FFEINFO_whereIMMEDIATE:
+ case FFEINFO_whereINTRINSIC:
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereCONSTANT_SUBOBJECT:
+ default:
+ assert ("COMMON where unheard of" == NULL);
+ /* Fall through. */
+ case FFEINFO_whereANY:
+ t = error_mark_node;
+ break;
+ }
+ break;
+
+ case FFEINFO_kindCONSTRUCT:
+ switch (ffeinfo_where (ffesymbol_info (s)))
+ {
+ case FFEINFO_whereLOCAL:
+ assert (!ffecom_transform_only_dummies_);
+ break;
+
+ case FFEINFO_whereNONE:
+ case FFEINFO_whereCOMMON:
+ case FFEINFO_whereDUMMY:
+ case FFEINFO_whereGLOBAL:
+ case FFEINFO_whereRESULT:
+ case FFEINFO_whereFLEETING:
+ case FFEINFO_whereFLEETING_CADDR:
+ case FFEINFO_whereFLEETING_IADDR:
+ case FFEINFO_whereIMMEDIATE:
+ case FFEINFO_whereINTRINSIC:
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereCONSTANT_SUBOBJECT:
+ default:
+ assert ("CONSTRUCT where unheard of" == NULL);
+ /* Fall through. */
+ case FFEINFO_whereANY:
+ t = error_mark_node;
+ break;
+ }
+ break;
+
+ case FFEINFO_kindNAMELIST:
+ switch (ffeinfo_where (ffesymbol_info (s)))
+ {
+ case FFEINFO_whereLOCAL:
+ assert (!ffecom_transform_only_dummies_);
+ t = ffecom_transform_namelist_ (s);
+ break;
+
+ case FFEINFO_whereNONE:
+ case FFEINFO_whereCOMMON:
+ case FFEINFO_whereDUMMY:
+ case FFEINFO_whereGLOBAL:
+ case FFEINFO_whereRESULT:
+ case FFEINFO_whereFLEETING:
+ case FFEINFO_whereFLEETING_CADDR:
+ case FFEINFO_whereFLEETING_IADDR:
+ case FFEINFO_whereIMMEDIATE:
+ case FFEINFO_whereINTRINSIC:
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereCONSTANT_SUBOBJECT:
+ default:
+ assert ("NAMELIST where unheard of" == NULL);
+ /* Fall through. */
+ case FFEINFO_whereANY:
+ t = error_mark_node;
+ break;
+ }
+ break;
+
+ default:
+ assert ("kind unheard of" == NULL);
+ /* Fall through. */
+ case FFEINFO_kindANY:
+ t = error_mark_node;
+ break;
+ }
+
+ ffesymbol_hook (s).decl_tree = t;
+ ffesymbol_hook (s).length_tree = tlen;
+ ffesymbol_hook (s).addr = addr;
+
+ lineno = old_lineno;
+ input_filename = old_input_filename;
+
+ return s;
+}
+
+#endif
+/* Transform into ASSIGNable symbol.
+
+ Symbol has already been transformed, but for whatever reason, the
+ resulting decl_tree has been deemed not usable for an ASSIGN target.
+ (E.g. it isn't wide enough to hold a pointer.) So, here we invent
+ another local symbol of type void * and stuff that in the assign_tree
+ argument. The F77/F90 standards allow this implementation. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static ffesymbol
+ffecom_sym_transform_assign_ (ffesymbol s)
+{
+ tree t; /* Transformed thingy. */
+ int yes;
+ int old_lineno = lineno;
+ char *old_input_filename = input_filename;
+
+ if (ffesymbol_sfdummyparent (s) == NULL)
+ {
+ input_filename = ffesymbol_where_filename (s);
+ lineno = ffesymbol_where_filelinenum (s);
+ }
+ else
+ {
+ ffesymbol sf = ffesymbol_sfdummyparent (s);
+
+ input_filename = ffesymbol_where_filename (sf);
+ lineno = ffesymbol_where_filelinenum (sf);
+ }
+
+ assert (!ffecom_transform_only_dummies_);
+
+ yes = suspend_momentary ();
+
+ t = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_ASSIGN_%s",
+ ffesymbol_text (s),
+ 0),
+ TREE_TYPE (null_pointer_node));
+
+ switch (ffesymbol_where (s))
+ {
+ case FFEINFO_whereLOCAL:
+ /* Unlike for regular vars, SAVE status is easy to determine for
+ ASSIGNed vars, since there's no initialization, there's no
+ effective storage association (so "SAVE J" does not apply to
+ K even given "EQUIVALENCE (J,K)"), there's no size issue
+ to worry about, etc. */
+ if ((ffesymbol_is_save (s) || ffe_is_saveall ())
+ && (ffecom_primary_entry_kind_ != FFEINFO_kindPROGRAM)
+ && (ffecom_primary_entry_kind_ != FFEINFO_kindBLOCKDATA))
+ TREE_STATIC (t) = 1; /* SAVEd in proc, make static. */
+ else
+ TREE_STATIC (t) = 0; /* No need to make static. */
+ break;
+
+ case FFEINFO_whereCOMMON:
+ TREE_STATIC (t) = 1; /* Assume COMMONs always SAVEd. */
+ break;
+
+ case FFEINFO_whereDUMMY:
+ /* Note that twinning a DUMMY means the caller won't see
+ the ASSIGNed value. But both F77 and F90 allow implementations
+ to do this, i.e. disallow Fortran code that would try and
+ take advantage of actually putting a label into a variable
+ via a dummy argument (or any other storage association, for
+ that matter). */
+ TREE_STATIC (t) = 0;
+ break;
+
+ default:
+ TREE_STATIC (t) = 0;
+ break;
+ }
+
+ t = start_decl (t, FALSE);
+ finish_decl (t, NULL_TREE, FALSE);
+
+ resume_momentary (yes);
+
+ ffesymbol_hook (s).assign_tree = t;
+
+ lineno = old_lineno;
+ input_filename = old_input_filename;
+
+ return s;
+}
+
+#endif
+/* Implement COMMON area in back end.
+
+ Because COMMON-based variables can be referenced in the dimension
+ expressions of dummy (adjustable) arrays, and because dummies
+ (in the gcc back end) need to be put in the outer binding level
+ of a function (which has two binding levels, the outer holding
+ the dummies and the inner holding the other vars), special care
+ must be taken to handle COMMON areas.
+
+ The current strategy is basically to always tell the back end about
+ the COMMON area as a top-level external reference to just a block
+ of storage of the master type of that area (e.g. integer, real,
+ character, whatever -- not a structure). As a distinct action,
+ if initial values are provided, tell the back end about the area
+ as a top-level non-external (initialized) area and remember not to
+ allow further initialization or expansion of the area. Meanwhile,
+ if no initialization happens at all, tell the back end about
+ the largest size we've seen declared so the space does get reserved.
+ (This function doesn't handle all that stuff, but it does some
+ of the important things.)
+
+ Meanwhile, for COMMON variables themselves, just keep creating
+ references like *((float *) (&common_area + offset)) each time
+ we reference the variable. In other words, don't make a VAR_DECL
+ or any kind of component reference (like we used to do before 0.4),
+ though we might do that as well just for debugging purposes (and
+ stuff the rtl with the appropriate offset expression). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_transform_common_ (ffesymbol s)
+{
+ ffestorag st = ffesymbol_storage (s);
+ ffeglobal g = ffesymbol_global (s);
+ tree cbt;
+ tree cbtype;
+ tree init;
+ tree high;
+ bool is_init = ffestorag_is_init (st);
+
+ assert (st != NULL);
+
+ if ((g == NULL)
+ || (ffeglobal_type (g) != FFEGLOBAL_typeCOMMON))
+ return;
+
+ /* First update the size of the area in global terms. */
+
+ ffeglobal_size_common (s, ffestorag_size (st));
+
+ if (!ffeglobal_common_init (g))
+ is_init = FALSE; /* No explicit init, don't let erroneous joins init. */
+
+ cbt = ffeglobal_hook (g);
+
+ /* If we already have declared this common block for a previous program
+ unit, and either we already initialized it or we don't have new
+ initialization for it, just return what we have without changing it. */
+
+ if ((cbt != NULL_TREE)
+ && (!is_init
+ || !DECL_EXTERNAL (cbt)))
+ return;
+
+ /* Process inits. */
+
+ if (is_init)
+ {
+ if (ffestorag_init (st) != NULL)
+ {
+ ffebld sexp;
+
+ /* Set the padding for the expression, so ffecom_expr
+ knows to insert that many zeros. */
+ switch (ffebld_op (sexp = ffestorag_init (st)))
+ {
+ case FFEBLD_opCONTER:
+ ffebld_conter_set_pad (sexp, ffestorag_modulo (st));
+ break;
+
+ case FFEBLD_opARRTER:
+ ffebld_arrter_set_pad (sexp, ffestorag_modulo (st));
+ break;
+
+ case FFEBLD_opACCTER:
+ ffebld_accter_set_pad (sexp, ffestorag_modulo (st));
+ break;
+
+ default:
+ assert ("bad op for cmn init (pad)" == NULL);
+ break;
+ }
+
+ init = ffecom_expr (sexp);
+ if (init == error_mark_node)
+ { /* Hopefully the back end complained! */
+ init = NULL_TREE;
+ if (cbt != NULL_TREE)
+ return;
+ }
+ }
+ else
+ init = error_mark_node;
+ }
+ else
+ init = NULL_TREE;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ /* cbtype must be permanently allocated! */
+
+ /* Allocate the MAX of the areas so far, seen filewide. */
+ high = build_int_2 ((ffeglobal_common_size (g)
+ + ffeglobal_common_pad (g)) - 1, 0);
+ TREE_TYPE (high) = ffecom_integer_type_node;
+
+ if (init)
+ cbtype = build_array_type (char_type_node,
+ build_range_type (integer_type_node,
+ integer_zero_node,
+ high));
+ else
+ cbtype = build_array_type (char_type_node, NULL_TREE);
+
+ if (cbt == NULL_TREE)
+ {
+ cbt
+ = build_decl (VAR_DECL,
+ ffecom_get_external_identifier_ (s),
+ cbtype);
+ TREE_STATIC (cbt) = 1;
+ TREE_PUBLIC (cbt) = 1;
+ }
+ else
+ {
+ assert (is_init);
+ TREE_TYPE (cbt) = cbtype;
+ }
+ DECL_EXTERNAL (cbt) = init ? 0 : 1;
+ DECL_INITIAL (cbt) = init ? error_mark_node : NULL_TREE;
+
+ cbt = start_decl (cbt, TRUE);
+ if (ffeglobal_hook (g) != NULL)
+ assert (cbt == ffeglobal_hook (g));
+
+ assert (!init || !DECL_EXTERNAL (cbt));
+
+ /* Make sure that any type can live in COMMON and be referenced
+ without getting a bus error. We could pick the most restrictive
+ alignment of all entities actually placed in the COMMON, but
+ this seems easy enough. */
+
+ DECL_ALIGN (cbt) = BIGGEST_ALIGNMENT;
+
+ if (is_init && (ffestorag_init (st) == NULL))
+ init = ffecom_init_zero_ (cbt);
+
+ finish_decl (cbt, init, TRUE);
+
+ if (is_init)
+ ffestorag_set_init (st, ffebld_new_any ());
+
+ if (init)
+ {
+ tree size_tree;
+
+ assert (DECL_SIZE (cbt) != NULL_TREE);
+ assert (TREE_CODE (DECL_SIZE (cbt)) == INTEGER_CST);
+ size_tree = size_binop (CEIL_DIV_EXPR,
+ DECL_SIZE (cbt),
+ size_int (BITS_PER_UNIT));
+ assert (TREE_INT_CST_HIGH (size_tree) == 0);
+ assert (TREE_INT_CST_LOW (size_tree)
+ == ffeglobal_common_size (g) + ffeglobal_common_pad (g));
+ }
+
+ ffeglobal_set_hook (g, cbt);
+
+ ffestorag_set_hook (st, cbt);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+}
+
+#endif
+/* Make master area for local EQUIVALENCE. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_transform_equiv_ (ffestorag eqst)
+{
+ tree eqt;
+ tree eqtype;
+ tree init;
+ tree high;
+ bool is_init = ffestorag_is_init (eqst);
+ int yes;
+
+ assert (eqst != NULL);
+
+ eqt = ffestorag_hook (eqst);
+
+ if (eqt != NULL_TREE)
+ return;
+
+ /* Process inits. */
+
+ if (is_init)
+ {
+ if (ffestorag_init (eqst) != NULL)
+ {
+ ffebld sexp;
+
+ /* Set the padding for the expression, so ffecom_expr
+ knows to insert that many zeros. */
+ switch (ffebld_op (sexp = ffestorag_init (eqst)))
+ {
+ case FFEBLD_opCONTER:
+ ffebld_conter_set_pad (sexp, ffestorag_modulo (eqst));
+ break;
+
+ case FFEBLD_opARRTER:
+ ffebld_arrter_set_pad (sexp, ffestorag_modulo (eqst));
+ break;
+
+ case FFEBLD_opACCTER:
+ ffebld_accter_set_pad (sexp, ffestorag_modulo (eqst));
+ break;
+
+ default:
+ assert ("bad op for eqv init (pad)" == NULL);
+ break;
+ }
+
+ init = ffecom_expr (sexp);
+ if (init == error_mark_node)
+ init = NULL_TREE; /* Hopefully the back end complained! */
+ }
+ else
+ init = error_mark_node;
+ }
+ else if (ffe_is_init_local_zero ())
+ init = error_mark_node;
+ else
+ init = NULL_TREE;
+
+ ffecom_member_namelisted_ = FALSE;
+ ffestorag_drive (ffestorag_list_equivs (eqst),
+ &ffecom_member_phase1_,
+ eqst);
+
+ yes = suspend_momentary ();
+
+ high = build_int_2 ((ffestorag_size (eqst)
+ + ffestorag_modulo (eqst)) - 1, 0);
+ TREE_TYPE (high) = ffecom_integer_type_node;
+
+ eqtype = build_array_type (char_type_node,
+ build_range_type (ffecom_integer_type_node,
+ ffecom_integer_zero_node,
+ high));
+
+ eqt = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_equiv_%s",
+ ffesymbol_text
+ (ffestorag_symbol
+ (eqst)),
+ 0),
+ eqtype);
+ DECL_EXTERNAL (eqt) = 0;
+ if (is_init
+ || ffecom_member_namelisted_
+#ifdef FFECOM_sizeMAXSTACKITEM
+ || (ffestorag_size (eqst) > FFECOM_sizeMAXSTACKITEM)
+#endif
+ || ((ffecom_primary_entry_kind_ != FFEINFO_kindPROGRAM)
+ && (ffecom_primary_entry_kind_ != FFEINFO_kindBLOCKDATA)
+ && (ffestorag_is_save (eqst) || ffe_is_saveall ())))
+ TREE_STATIC (eqt) = 1;
+ else
+ TREE_STATIC (eqt) = 0;
+ TREE_PUBLIC (eqt) = 0;
+ DECL_CONTEXT (eqt) = current_function_decl;
+ if (init)
+ DECL_INITIAL (eqt) = error_mark_node;
+ else
+ DECL_INITIAL (eqt) = NULL_TREE;
+
+ eqt = start_decl (eqt, FALSE);
+
+ /* Make sure that any type can live in EQUIVALENCE and be referenced
+ without getting a bus error. We could pick the most restrictive
+ alignment of all entities actually placed in the EQUIVALENCE, but
+ this seems easy enough. */
+
+ DECL_ALIGN (eqt) = BIGGEST_ALIGNMENT;
+
+ if ((!is_init && ffe_is_init_local_zero ())
+ || (is_init && (ffestorag_init (eqst) == NULL)))
+ init = ffecom_init_zero_ (eqt);
+
+ finish_decl (eqt, init, FALSE);
+
+ if (is_init)
+ ffestorag_set_init (eqst, ffebld_new_any ());
+
+ {
+ tree size_tree;
+
+ size_tree = size_binop (CEIL_DIV_EXPR,
+ DECL_SIZE (eqt),
+ size_int (BITS_PER_UNIT));
+ assert (TREE_INT_CST_HIGH (size_tree) == 0);
+ assert (TREE_INT_CST_LOW (size_tree)
+ == ffestorag_size (eqst) + ffestorag_modulo (eqst));
+ }
+
+ ffestorag_set_hook (eqst, eqt);
+
+#ifdef SOMEONE_GETS_DEBUG_SUPPORT_WORKING
+ ffestorag_drive (ffestorag_list_equivs (eqst),
+ &ffecom_member_phase2_,
+ eqst);
+#endif
+
+ resume_momentary (yes);
+}
+
+#endif
+/* Implement NAMELIST in back end. See f2c/format.c for more info. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_transform_namelist_ (ffesymbol s)
+{
+ tree nmlt;
+ tree nmltype = ffecom_type_namelist_ ();
+ tree nmlinits;
+ tree nameinit;
+ tree varsinit;
+ tree nvarsinit;
+ tree field;
+ tree high;
+ int yes;
+ int i;
+ static int mynumber = 0;
+
+ yes = suspend_momentary ();
+
+ nmlt = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_namelist_%d",
+ NULL, mynumber++),
+ nmltype);
+ TREE_STATIC (nmlt) = 1;
+ DECL_INITIAL (nmlt) = error_mark_node;
+
+ nmlt = start_decl (nmlt, FALSE);
+
+ /* Process inits. */
+
+ i = strlen (ffesymbol_text (s));
+
+ high = build_int_2 (i, 0);
+ TREE_TYPE (high) = ffecom_f2c_ftnlen_type_node;
+
+ nameinit = ffecom_build_f2c_string_ (i + 1,
+ ffesymbol_text (s));
+ TREE_TYPE (nameinit)
+ = build_type_variant
+ (build_array_type
+ (char_type_node,
+ build_range_type (ffecom_f2c_ftnlen_type_node,
+ ffecom_f2c_ftnlen_one_node,
+ high)),
+ 1, 0);
+ TREE_CONSTANT (nameinit) = 1;
+ TREE_STATIC (nameinit) = 1;
+ nameinit = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (nameinit)),
+ nameinit);
+
+ varsinit = ffecom_vardesc_array_ (s);
+ varsinit = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (varsinit)),
+ varsinit);
+ TREE_CONSTANT (varsinit) = 1;
+ TREE_STATIC (varsinit) = 1;
+
+ {
+ ffebld b;
+
+ for (i = 0, b = ffesymbol_namelist (s); b != NULL; b = ffebld_trail (b))
+ ++i;
+ }
+ nvarsinit = build_int_2 (i, 0);
+ TREE_TYPE (nvarsinit) = integer_type_node;
+ TREE_CONSTANT (nvarsinit) = 1;
+ TREE_STATIC (nvarsinit) = 1;
+
+ nmlinits = build_tree_list ((field = TYPE_FIELDS (nmltype)), nameinit);
+ TREE_CHAIN (nmlinits) = build_tree_list ((field = TREE_CHAIN (field)),
+ varsinit);
+ TREE_CHAIN (TREE_CHAIN (nmlinits))
+ = build_tree_list ((field = TREE_CHAIN (field)), nvarsinit);
+
+ nmlinits = build (CONSTRUCTOR, nmltype, NULL_TREE, nmlinits);
+ TREE_CONSTANT (nmlinits) = 1;
+ TREE_STATIC (nmlinits) = 1;
+
+ finish_decl (nmlt, nmlinits, FALSE);
+
+ nmlt = ffecom_1 (ADDR_EXPR, build_pointer_type (nmltype), nmlt);
+
+ resume_momentary (yes);
+
+ return nmlt;
+}
+
+#endif
+
+/* A subroutine of ffecom_tree_canonize_ref_. The incoming tree is
+ analyzed on the assumption it is calculating a pointer to be
+ indirected through. It must return the proper decl and offset,
+ taking into account different units of measurements for offsets. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_tree_canonize_ptr_ (tree *decl, tree *offset,
+ tree t)
+{
+ switch (TREE_CODE (t))
+ {
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ ffecom_tree_canonize_ptr_ (decl, offset, TREE_OPERAND (t, 0));
+ break;
+
+ case PLUS_EXPR:
+ ffecom_tree_canonize_ptr_ (decl, offset, TREE_OPERAND (t, 0));
+ if ((*decl == NULL_TREE)
+ || (*decl == error_mark_node))
+ break;
+
+ if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST)
+ {
+ /* An offset into COMMON. */
+ *offset = size_binop (PLUS_EXPR,
+ *offset,
+ TREE_OPERAND (t, 1));
+ /* Convert offset (presumably in bytes) into canonical units
+ (presumably bits). */
+ *offset = size_binop (MULT_EXPR,
+ TYPE_SIZE (TREE_TYPE (TREE_TYPE (t))),
+ *offset);
+ break;
+ }
+ /* Not a COMMON reference, so an unrecognized pattern. */
+ *decl = error_mark_node;
+ break;
+
+ case PARM_DECL:
+ *decl = t;
+ *offset = bitsize_int (0L, 0L);
+ break;
+
+ case ADDR_EXPR:
+ if (TREE_CODE (TREE_OPERAND (t, 0)) == VAR_DECL)
+ {
+ /* A reference to COMMON. */
+ *decl = TREE_OPERAND (t, 0);
+ *offset = bitsize_int (0L, 0L);
+ break;
+ }
+ /* Fall through. */
+ default:
+ /* Not a COMMON reference, so an unrecognized pattern. */
+ *decl = error_mark_node;
+ break;
+ }
+}
+#endif
+
+/* Given a tree that is possibly intended for use as an lvalue, return
+ information representing a canonical view of that tree as a decl, an
+ offset into that decl, and a size for the lvalue.
+
+ If there's no applicable decl, NULL_TREE is returned for the decl,
+ and the other fields are left undefined.
+
+ If the tree doesn't fit the recognizable forms, an ERROR_MARK node
+ is returned for the decl, and the other fields are left undefined.
+
+ Otherwise, the decl returned currently is either a VAR_DECL or a
+ PARM_DECL.
+
+ The offset returned is always valid, but of course not necessarily
+ a constant, and not necessarily converted into the appropriate
+ type, leaving that up to the caller (so as to avoid that overhead
+ if the decls being looked at are different anyway).
+
+ If the size cannot be determined (e.g. an adjustable array),
+ an ERROR_MARK node is returned for the size. Otherwise, the
+ size returned is valid, not necessarily a constant, and not
+ necessarily converted into the appropriate type as with the
+ offset.
+
+ Note that the offset and size expressions are expressed in the
+ base storage units (usually bits) rather than in the units of
+ the type of the decl, because two decls with different types
+ might overlap but with apparently non-overlapping array offsets,
+ whereas converting the array offsets to consistant offsets will
+ reveal the overlap. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffecom_tree_canonize_ref_ (tree *decl, tree *offset,
+ tree *size, tree t)
+{
+ /* The default path is to report a nonexistant decl. */
+ *decl = NULL_TREE;
+
+ if (t == NULL_TREE)
+ return;
+
+ switch (TREE_CODE (t))
+ {
+ case ERROR_MARK:
+ case IDENTIFIER_NODE:
+ case INTEGER_CST:
+ case REAL_CST:
+ case COMPLEX_CST:
+ case STRING_CST:
+ case CONST_DECL:
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case TRUNC_MOD_EXPR:
+ case CEIL_MOD_EXPR:
+ case FLOOR_MOD_EXPR:
+ case ROUND_MOD_EXPR:
+ case RDIV_EXPR:
+ case EXACT_DIV_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIX_CEIL_EXPR:
+ case FIX_FLOOR_EXPR:
+ case FIX_ROUND_EXPR:
+ case FLOAT_EXPR:
+ case EXPON_EXPR:
+ case NEGATE_EXPR:
+ case MIN_EXPR:
+ case MAX_EXPR:
+ case ABS_EXPR:
+ case FFS_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_ANDTC_EXPR:
+ case BIT_NOT_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ case TRUTH_NOT_EXPR:
+ case LT_EXPR:
+ case LE_EXPR:
+ case GT_EXPR:
+ case GE_EXPR:
+ case EQ_EXPR:
+ case NE_EXPR:
+ case COMPLEX_EXPR:
+ case CONJ_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case LABEL_EXPR:
+ case COMPONENT_REF:
+ case COMPOUND_EXPR:
+ case ADDR_EXPR:
+ return;
+
+ case VAR_DECL:
+ case PARM_DECL:
+ *decl = t;
+ *offset = bitsize_int (0L, 0L);
+ *size = TYPE_SIZE (TREE_TYPE (t));
+ return;
+
+ case ARRAY_REF:
+ {
+ tree array = TREE_OPERAND (t, 0);
+ tree element = TREE_OPERAND (t, 1);
+ tree init_offset;
+
+ if ((array == NULL_TREE)
+ || (element == NULL_TREE))
+ {
+ *decl = error_mark_node;
+ return;
+ }
+
+ ffecom_tree_canonize_ref_ (decl, &init_offset, size,
+ array);
+ if ((*decl == NULL_TREE)
+ || (*decl == error_mark_node))
+ return;
+
+ *offset = size_binop (MULT_EXPR,
+ TYPE_SIZE (TREE_TYPE (TREE_TYPE (array))),
+ size_binop (MINUS_EXPR,
+ element,
+ TYPE_MIN_VALUE
+ (TYPE_DOMAIN
+ (TREE_TYPE (array)))));
+
+ *offset = size_binop (PLUS_EXPR,
+ init_offset,
+ *offset);
+
+ *size = TYPE_SIZE (TREE_TYPE (t));
+ return;
+ }
+
+ case INDIRECT_REF:
+
+ /* Most of this code is to handle references to COMMON. And so
+ far that is useful only for calling library functions, since
+ external (user) functions might reference common areas. But
+ even calling an external function, it's worthwhile to decode
+ COMMON references because if not storing into COMMON, we don't
+ want COMMON-based arguments to gratuitously force use of a
+ temporary. */
+
+ *size = TYPE_SIZE (TREE_TYPE (t));
+
+ ffecom_tree_canonize_ptr_ (decl, offset,
+ TREE_OPERAND (t, 0));
+
+ return;
+
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+ case MODIFY_EXPR:
+ case NON_LVALUE_EXPR:
+ case RESULT_DECL:
+ case FIELD_DECL:
+ case COND_EXPR: /* More cases than we can handle. */
+ case SAVE_EXPR:
+ case REFERENCE_EXPR:
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case CALL_EXPR:
+ default:
+ *decl = error_mark_node;
+ return;
+ }
+}
+#endif
+
+/* Do divide operation appropriate to type of operands. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_tree_divide_ (tree tree_type, tree left, tree right,
+ tree dest_tree, ffebld dest, bool *dest_used)
+{
+ if ((left == error_mark_node)
+ || (right == error_mark_node))
+ return error_mark_node;
+
+ switch (TREE_CODE (tree_type))
+ {
+ case INTEGER_TYPE:
+ return ffecom_2 (TRUNC_DIV_EXPR, tree_type,
+ left,
+ right);
+
+ case COMPLEX_TYPE:
+ {
+ ffecomGfrt ix;
+
+ if (TREE_TYPE (tree_type)
+ == ffecom_tree_type [FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1])
+ ix = FFECOM_gfrtDIV_CC; /* Overlapping result okay. */
+ else
+ ix = FFECOM_gfrtDIV_ZZ; /* Overlapping result okay. */
+
+ left = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (left)),
+ left);
+ left = build_tree_list (NULL_TREE, left);
+ right = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (right)),
+ right);
+ right = build_tree_list (NULL_TREE, right);
+ TREE_CHAIN (left) = right;
+
+ return ffecom_call_ (ffecom_gfrt_tree_ (ix),
+ ffecom_gfrt_kindtype (ix),
+ ffe_is_f2c_library (),
+ tree_type,
+ left,
+ dest_tree, dest, dest_used,
+ NULL_TREE, TRUE);
+ }
+ break;
+
+ case RECORD_TYPE:
+ {
+ ffecomGfrt ix;
+
+ if (TREE_TYPE (TYPE_FIELDS (tree_type))
+ == ffecom_tree_type [FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1])
+ ix = FFECOM_gfrtDIV_CC; /* Overlapping result okay. */
+ else
+ ix = FFECOM_gfrtDIV_ZZ; /* Overlapping result okay. */
+
+ left = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (left)),
+ left);
+ left = build_tree_list (NULL_TREE, left);
+ right = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (right)),
+ right);
+ right = build_tree_list (NULL_TREE, right);
+ TREE_CHAIN (left) = right;
+
+ return ffecom_call_ (ffecom_gfrt_tree_ (ix),
+ ffecom_gfrt_kindtype (ix),
+ ffe_is_f2c_library (),
+ tree_type,
+ left,
+ dest_tree, dest, dest_used,
+ NULL_TREE, TRUE);
+ }
+ break;
+
+ default:
+ return ffecom_2 (RDIV_EXPR, tree_type,
+ left,
+ right);
+ }
+}
+
+#endif
+/* ffecom_type_localvar_ -- Build type info for non-dummy variable
+
+ tree type;
+ ffesymbol s; // the variable's symbol
+ ffeinfoBasictype bt; // it's basictype
+ ffeinfoKindtype kt; // it's kindtype
+
+ type = ffecom_type_localvar_(s,bt,kt);
+
+ Handles static arrays, CHARACTER type, etc. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_type_localvar_ (ffesymbol s, ffeinfoBasictype bt,
+ ffeinfoKindtype kt)
+{
+ tree type;
+ ffebld dl;
+ ffebld dim;
+ tree lowt;
+ tree hight;
+
+ type = ffecom_tree_type[bt][kt];
+ if (bt == FFEINFO_basictypeCHARACTER)
+ {
+ hight = build_int_2 (ffesymbol_size (s), 0);
+ TREE_TYPE (hight) = ffecom_f2c_ftnlen_type_node;
+
+ type
+ = build_array_type
+ (type,
+ build_range_type (ffecom_f2c_ftnlen_type_node,
+ ffecom_f2c_ftnlen_one_node,
+ hight));
+ type = ffecom_check_size_overflow_ (s, type, FALSE);
+ }
+
+ for (dl = ffesymbol_dims (s); dl != NULL; dl = ffebld_trail (dl))
+ {
+ if (type == error_mark_node)
+ break;
+
+ dim = ffebld_head (dl);
+ assert (ffebld_op (dim) == FFEBLD_opBOUNDS);
+
+ if (ffebld_left (dim) == NULL)
+ lowt = integer_one_node;
+ else
+ lowt = ffecom_expr (ffebld_left (dim));
+
+ if (TREE_CODE (lowt) != INTEGER_CST)
+ lowt = variable_size (lowt);
+
+ assert (ffebld_right (dim) != NULL);
+ hight = ffecom_expr (ffebld_right (dim));
+
+ if (TREE_CODE (hight) != INTEGER_CST)
+ hight = variable_size (hight);
+
+ type = build_array_type (type,
+ build_range_type (ffecom_integer_type_node,
+ lowt, hight));
+ type = ffecom_check_size_overflow_ (s, type, FALSE);
+ }
+
+ return type;
+}
+
+#endif
+/* Build Namelist type. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_type_namelist_ ()
+{
+ static tree type = NULL_TREE;
+
+ if (type == NULL_TREE)
+ {
+ static tree namefield, varsfield, nvarsfield;
+ tree vardesctype;
+
+ vardesctype = ffecom_type_vardesc_ ();
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ type = make_node (RECORD_TYPE);
+
+ vardesctype = build_pointer_type (build_pointer_type (vardesctype));
+
+ namefield = ffecom_decl_field (type, NULL_TREE, "name",
+ string_type_node);
+ varsfield = ffecom_decl_field (type, namefield, "vars", vardesctype);
+ nvarsfield = ffecom_decl_field (type, varsfield, "nvars",
+ integer_type_node);
+
+ TYPE_FIELDS (type) = namefield;
+ layout_type (type);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+ }
+
+ return type;
+}
+
+#endif
+
+/* Make a copy of a type, assuming caller has switched to the permanent
+ obstacks and that the type is for an aggregate (array) initializer. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC && 0 /* Not used now. */
+static tree
+ffecom_type_permanent_copy_ (tree t)
+{
+ tree domain;
+ tree max;
+
+ assert (TREE_TYPE (t) != NULL_TREE);
+
+ domain = TYPE_DOMAIN (t);
+
+ assert (TREE_CODE (t) == ARRAY_TYPE);
+ assert (TREE_PERMANENT (TREE_TYPE (t)));
+ assert (TREE_PERMANENT (TREE_TYPE (domain)));
+ assert (TREE_PERMANENT (TYPE_MIN_VALUE (domain)));
+
+ max = TYPE_MAX_VALUE (domain);
+ if (!TREE_PERMANENT (max))
+ {
+ assert (TREE_CODE (max) == INTEGER_CST);
+
+ max = build_int_2 (TREE_INT_CST_LOW (max), TREE_INT_CST_HIGH (max));
+ TREE_TYPE (max) = TREE_TYPE (TYPE_MIN_VALUE (domain));
+ }
+
+ return build_array_type (TREE_TYPE (t),
+ build_range_type (TREE_TYPE (domain),
+ TYPE_MIN_VALUE (domain),
+ max));
+}
+#endif
+
+/* Build Vardesc type. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_type_vardesc_ ()
+{
+ static tree type = NULL_TREE;
+ static tree namefield, addrfield, dimsfield, typefield;
+
+ if (type == NULL_TREE)
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ type = make_node (RECORD_TYPE);
+
+ namefield = ffecom_decl_field (type, NULL_TREE, "name",
+ string_type_node);
+ addrfield = ffecom_decl_field (type, namefield, "addr",
+ string_type_node);
+ dimsfield = ffecom_decl_field (type, addrfield, "dims",
+ ffecom_f2c_ptr_to_ftnlen_type_node);
+ typefield = ffecom_decl_field (type, dimsfield, "type",
+ integer_type_node);
+
+ TYPE_FIELDS (type) = namefield;
+ layout_type (type);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+ }
+
+ return type;
+}
+
+#endif
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_vardesc_ (ffebld expr)
+{
+ ffesymbol s;
+
+ assert (ffebld_op (expr) == FFEBLD_opSYMTER);
+ s = ffebld_symter (expr);
+
+ if (ffesymbol_hook (s).vardesc_tree == NULL_TREE)
+ {
+ int i;
+ tree vardesctype = ffecom_type_vardesc_ ();
+ tree var;
+ tree nameinit;
+ tree dimsinit;
+ tree addrinit;
+ tree typeinit;
+ tree field;
+ tree varinits;
+ int yes;
+ static int mynumber = 0;
+
+ yes = suspend_momentary ();
+
+ var = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_vardesc_%d",
+ NULL, mynumber++),
+ vardesctype);
+ TREE_STATIC (var) = 1;
+ DECL_INITIAL (var) = error_mark_node;
+
+ var = start_decl (var, FALSE);
+
+ /* Process inits. */
+
+ nameinit = ffecom_build_f2c_string_ ((i = strlen (ffesymbol_text (s)))
+ + 1,
+ ffesymbol_text (s));
+ TREE_TYPE (nameinit)
+ = build_type_variant
+ (build_array_type
+ (char_type_node,
+ build_range_type (integer_type_node,
+ integer_one_node,
+ build_int_2 (i, 0))),
+ 1, 0);
+ TREE_CONSTANT (nameinit) = 1;
+ TREE_STATIC (nameinit) = 1;
+ nameinit = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (nameinit)),
+ nameinit);
+
+ addrinit = ffecom_arg_ptr_to_expr (expr, &typeinit);
+
+ dimsinit = ffecom_vardesc_dims_ (s);
+
+ if (typeinit == NULL_TREE)
+ {
+ ffeinfoBasictype bt = ffesymbol_basictype (s);
+ ffeinfoKindtype kt = ffesymbol_kindtype (s);
+ int tc = ffecom_f2c_typecode (bt, kt);
+
+ assert (tc != -1);
+ typeinit = build_int_2 (tc, (tc < 0) ? -1 : 0);
+ }
+ else
+ typeinit = ffecom_1 (NEGATE_EXPR, TREE_TYPE (typeinit), typeinit);
+
+ varinits = build_tree_list ((field = TYPE_FIELDS (vardesctype)),
+ nameinit);
+ TREE_CHAIN (varinits) = build_tree_list ((field = TREE_CHAIN (field)),
+ addrinit);
+ TREE_CHAIN (TREE_CHAIN (varinits))
+ = build_tree_list ((field = TREE_CHAIN (field)), dimsinit);
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (varinits)))
+ = build_tree_list ((field = TREE_CHAIN (field)), typeinit);
+
+ varinits = build (CONSTRUCTOR, vardesctype, NULL_TREE, varinits);
+ TREE_CONSTANT (varinits) = 1;
+ TREE_STATIC (varinits) = 1;
+
+ finish_decl (var, varinits, FALSE);
+
+ var = ffecom_1 (ADDR_EXPR, build_pointer_type (vardesctype), var);
+
+ resume_momentary (yes);
+
+ ffesymbol_hook (s).vardesc_tree = var;
+ }
+
+ return ffesymbol_hook (s).vardesc_tree;
+}
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_vardesc_array_ (ffesymbol s)
+{
+ ffebld b;
+ tree list;
+ tree item = NULL_TREE;
+ tree var;
+ int i;
+ int yes;
+ static int mynumber = 0;
+
+ for (i = 0, list = NULL_TREE, b = ffesymbol_namelist (s);
+ b != NULL;
+ b = ffebld_trail (b), ++i)
+ {
+ tree t;
+
+ t = ffecom_vardesc_ (ffebld_head (b));
+
+ if (list == NULL_TREE)
+ list = item = build_tree_list (NULL_TREE, t);
+ else
+ {
+ TREE_CHAIN (item) = build_tree_list (NULL_TREE, t);
+ item = TREE_CHAIN (item);
+ }
+ }
+
+ yes = suspend_momentary ();
+
+ item = build_array_type (build_pointer_type (ffecom_type_vardesc_ ()),
+ build_range_type (integer_type_node,
+ integer_one_node,
+ build_int_2 (i, 0)));
+ list = build (CONSTRUCTOR, item, NULL_TREE, list);
+ TREE_CONSTANT (list) = 1;
+ TREE_STATIC (list) = 1;
+
+ var = ffecom_get_invented_identifier ("__g77_vardesc_array_%d", NULL,
+ mynumber++);
+ var = build_decl (VAR_DECL, var, item);
+ TREE_STATIC (var) = 1;
+ DECL_INITIAL (var) = error_mark_node;
+ var = start_decl (var, FALSE);
+ finish_decl (var, list, FALSE);
+
+ resume_momentary (yes);
+
+ return var;
+}
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffecom_vardesc_dims_ (ffesymbol s)
+{
+ if (ffesymbol_dims (s) == NULL)
+ return convert (ffecom_f2c_ptr_to_ftnlen_type_node,
+ integer_zero_node);
+
+ {
+ ffebld b;
+ ffebld e;
+ tree list;
+ tree backlist;
+ tree item = NULL_TREE;
+ tree var;
+ int yes;
+ tree numdim;
+ tree numelem;
+ tree baseoff = NULL_TREE;
+ static int mynumber = 0;
+
+ numdim = build_int_2 ((int) ffesymbol_rank (s), 0);
+ TREE_TYPE (numdim) = ffecom_f2c_ftnlen_type_node;
+
+ numelem = ffecom_expr (ffesymbol_arraysize (s));
+ TREE_TYPE (numelem) = ffecom_f2c_ftnlen_type_node;
+
+ list = NULL_TREE;
+ backlist = NULL_TREE;
+ for (b = ffesymbol_dims (s), e = ffesymbol_extents (s);
+ b != NULL;
+ b = ffebld_trail (b), e = ffebld_trail (e))
+ {
+ tree t;
+ tree low;
+ tree back;
+
+ if (ffebld_trail (b) == NULL)
+ t = NULL_TREE;
+ else
+ {
+ t = convert (ffecom_f2c_ftnlen_type_node,
+ ffecom_expr (ffebld_head (e)));
+
+ if (list == NULL_TREE)
+ list = item = build_tree_list (NULL_TREE, t);
+ else
+ {
+ TREE_CHAIN (item) = build_tree_list (NULL_TREE, t);
+ item = TREE_CHAIN (item);
+ }
+ }
+
+ if (ffebld_left (ffebld_head (b)) == NULL)
+ low = ffecom_integer_one_node;
+ else
+ low = ffecom_expr (ffebld_left (ffebld_head (b)));
+ low = convert (ffecom_f2c_ftnlen_type_node, low);
+
+ back = build_tree_list (low, t);
+ TREE_CHAIN (back) = backlist;
+ backlist = back;
+ }
+
+ for (item = backlist; item != NULL_TREE; item = TREE_CHAIN (item))
+ {
+ if (TREE_VALUE (item) == NULL_TREE)
+ baseoff = TREE_PURPOSE (item);
+ else
+ baseoff = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node,
+ TREE_PURPOSE (item),
+ ffecom_2 (MULT_EXPR,
+ ffecom_f2c_ftnlen_type_node,
+ TREE_VALUE (item),
+ baseoff));
+ }
+
+ /* backlist now dead, along with all TREE_PURPOSEs on it. */
+
+ baseoff = build_tree_list (NULL_TREE, baseoff);
+ TREE_CHAIN (baseoff) = list;
+
+ numelem = build_tree_list (NULL_TREE, numelem);
+ TREE_CHAIN (numelem) = baseoff;
+
+ numdim = build_tree_list (NULL_TREE, numdim);
+ TREE_CHAIN (numdim) = numelem;
+
+ yes = suspend_momentary ();
+
+ item = build_array_type (ffecom_f2c_ftnlen_type_node,
+ build_range_type (integer_type_node,
+ integer_zero_node,
+ build_int_2
+ ((int) ffesymbol_rank (s)
+ + 2, 0)));
+ list = build (CONSTRUCTOR, item, NULL_TREE, numdim);
+ TREE_CONSTANT (list) = 1;
+ TREE_STATIC (list) = 1;
+
+ var = ffecom_get_invented_identifier ("__g77_dims_%d", NULL,
+ mynumber++);
+ var = build_decl (VAR_DECL, var, item);
+ TREE_STATIC (var) = 1;
+ DECL_INITIAL (var) = error_mark_node;
+ var = start_decl (var, FALSE);
+ finish_decl (var, list, FALSE);
+
+ var = ffecom_1 (ADDR_EXPR, build_pointer_type (item), var);
+
+ resume_momentary (yes);
+
+ return var;
+ }
+}
+
+#endif
+/* Essentially does a "fold (build1 (code, type, node))" while checking
+ for certain housekeeping things.
+
+ NOTE: for building an ADDR_EXPR around a FUNCTION_DECL, use
+ ffecom_1_fn instead. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_1 (enum tree_code code, tree type, tree node)
+{
+ tree item;
+
+ if ((node == error_mark_node)
+ || (type == error_mark_node))
+ return error_mark_node;
+
+ if (code == ADDR_EXPR)
+ {
+ if (!mark_addressable (node))
+ assert ("can't mark_addressable this node!" == NULL);
+ }
+
+ switch (ffe_is_emulate_complex () ? code : NOP_EXPR)
+ {
+ tree realtype;
+
+ case REALPART_EXPR:
+ item = build (COMPONENT_REF, type, node, TYPE_FIELDS (TREE_TYPE (node)));
+ break;
+
+ case IMAGPART_EXPR:
+ item = build (COMPONENT_REF, type, node, TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (node))));
+ break;
+
+
+ case NEGATE_EXPR:
+ if (TREE_CODE (type) != RECORD_TYPE)
+ {
+ item = build1 (code, type, node);
+ break;
+ }
+ node = ffecom_stabilize_aggregate_ (node);
+ realtype = TREE_TYPE (TYPE_FIELDS (type));
+ item =
+ ffecom_2 (COMPLEX_EXPR, type,
+ ffecom_1 (NEGATE_EXPR, realtype,
+ ffecom_1 (REALPART_EXPR, realtype,
+ node)),
+ ffecom_1 (NEGATE_EXPR, realtype,
+ ffecom_1 (IMAGPART_EXPR, realtype,
+ node)));
+ break;
+
+ default:
+ item = build1 (code, type, node);
+ break;
+ }
+
+ if (TREE_SIDE_EFFECTS (node))
+ TREE_SIDE_EFFECTS (item) = 1;
+ if ((code == ADDR_EXPR) && staticp (node))
+ TREE_CONSTANT (item) = 1;
+ return fold (item);
+}
+#endif
+
+/* Like ffecom_1 (ADDR_EXPR, TREE_TYPE (node), node), except
+ handles TREE_CODE (node) == FUNCTION_DECL. In particular,
+ does not set TREE_ADDRESSABLE (because calling an inline
+ function does not mean the function needs to be separately
+ compiled). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_1_fn (tree node)
+{
+ tree item;
+ tree type;
+
+ if (node == error_mark_node)
+ return error_mark_node;
+
+ type = build_type_variant (TREE_TYPE (node),
+ TREE_READONLY (node),
+ TREE_THIS_VOLATILE (node));
+ item = build1 (ADDR_EXPR,
+ build_pointer_type (type), node);
+ if (TREE_SIDE_EFFECTS (node))
+ TREE_SIDE_EFFECTS (item) = 1;
+ if (staticp (node))
+ TREE_CONSTANT (item) = 1;
+ return fold (item);
+}
+#endif
+
+/* Essentially does a "fold (build (code, type, node1, node2))" while
+ checking for certain housekeeping things. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_2 (enum tree_code code, tree type, tree node1,
+ tree node2)
+{
+ tree item;
+
+ if ((node1 == error_mark_node)
+ || (node2 == error_mark_node)
+ || (type == error_mark_node))
+ return error_mark_node;
+
+ switch (ffe_is_emulate_complex () ? code : NOP_EXPR)
+ {
+ tree a, b, c, d, realtype;
+
+ case CONJ_EXPR:
+ assert ("no CONJ_EXPR support yet" == NULL);
+ return error_mark_node;
+
+ case COMPLEX_EXPR:
+ item = build_tree_list (TYPE_FIELDS (type), node1);
+ TREE_CHAIN (item) = build_tree_list (TREE_CHAIN (TYPE_FIELDS (type)), node2);
+ item = build (CONSTRUCTOR, type, NULL_TREE, item);
+ break;
+
+ case PLUS_EXPR:
+ if (TREE_CODE (type) != RECORD_TYPE)
+ {
+ item = build (code, type, node1, node2);
+ break;
+ }
+ node1 = ffecom_stabilize_aggregate_ (node1);
+ node2 = ffecom_stabilize_aggregate_ (node2);
+ realtype = TREE_TYPE (TYPE_FIELDS (type));
+ item =
+ ffecom_2 (COMPLEX_EXPR, type,
+ ffecom_2 (PLUS_EXPR, realtype,
+ ffecom_1 (REALPART_EXPR, realtype,
+ node1),
+ ffecom_1 (REALPART_EXPR, realtype,
+ node2)),
+ ffecom_2 (PLUS_EXPR, realtype,
+ ffecom_1 (IMAGPART_EXPR, realtype,
+ node1),
+ ffecom_1 (IMAGPART_EXPR, realtype,
+ node2)));
+ break;
+
+ case MINUS_EXPR:
+ if (TREE_CODE (type) != RECORD_TYPE)
+ {
+ item = build (code, type, node1, node2);
+ break;
+ }
+ node1 = ffecom_stabilize_aggregate_ (node1);
+ node2 = ffecom_stabilize_aggregate_ (node2);
+ realtype = TREE_TYPE (TYPE_FIELDS (type));
+ item =
+ ffecom_2 (COMPLEX_EXPR, type,
+ ffecom_2 (MINUS_EXPR, realtype,
+ ffecom_1 (REALPART_EXPR, realtype,
+ node1),
+ ffecom_1 (REALPART_EXPR, realtype,
+ node2)),
+ ffecom_2 (MINUS_EXPR, realtype,
+ ffecom_1 (IMAGPART_EXPR, realtype,
+ node1),
+ ffecom_1 (IMAGPART_EXPR, realtype,
+ node2)));
+ break;
+
+ case MULT_EXPR:
+ if (TREE_CODE (type) != RECORD_TYPE)
+ {
+ item = build (code, type, node1, node2);
+ break;
+ }
+ node1 = ffecom_stabilize_aggregate_ (node1);
+ node2 = ffecom_stabilize_aggregate_ (node2);
+ realtype = TREE_TYPE (TYPE_FIELDS (type));
+ a = save_expr (ffecom_1 (REALPART_EXPR, realtype,
+ node1));
+ b = save_expr (ffecom_1 (IMAGPART_EXPR, realtype,
+ node1));
+ c = save_expr (ffecom_1 (REALPART_EXPR, realtype,
+ node2));
+ d = save_expr (ffecom_1 (IMAGPART_EXPR, realtype,
+ node2));
+ item =
+ ffecom_2 (COMPLEX_EXPR, type,
+ ffecom_2 (MINUS_EXPR, realtype,
+ ffecom_2 (MULT_EXPR, realtype,
+ a,
+ c),
+ ffecom_2 (MULT_EXPR, realtype,
+ b,
+ d)),
+ ffecom_2 (PLUS_EXPR, realtype,
+ ffecom_2 (MULT_EXPR, realtype,
+ a,
+ d),
+ ffecom_2 (MULT_EXPR, realtype,
+ c,
+ b)));
+ break;
+
+ case EQ_EXPR:
+ if ((TREE_CODE (node1) != RECORD_TYPE)
+ && (TREE_CODE (node2) != RECORD_TYPE))
+ {
+ item = build (code, type, node1, node2);
+ break;
+ }
+ assert (TREE_CODE (node1) == RECORD_TYPE);
+ assert (TREE_CODE (node2) == RECORD_TYPE);
+ node1 = ffecom_stabilize_aggregate_ (node1);
+ node2 = ffecom_stabilize_aggregate_ (node2);
+ realtype = TREE_TYPE (TYPE_FIELDS (type));
+ item =
+ ffecom_2 (TRUTH_ANDIF_EXPR, type,
+ ffecom_2 (code, type,
+ ffecom_1 (REALPART_EXPR, realtype,
+ node1),
+ ffecom_1 (REALPART_EXPR, realtype,
+ node2)),
+ ffecom_2 (code, type,
+ ffecom_1 (IMAGPART_EXPR, realtype,
+ node1),
+ ffecom_1 (IMAGPART_EXPR, realtype,
+ node2)));
+ break;
+
+ case NE_EXPR:
+ if ((TREE_CODE (node1) != RECORD_TYPE)
+ && (TREE_CODE (node2) != RECORD_TYPE))
+ {
+ item = build (code, type, node1, node2);
+ break;
+ }
+ assert (TREE_CODE (node1) == RECORD_TYPE);
+ assert (TREE_CODE (node2) == RECORD_TYPE);
+ node1 = ffecom_stabilize_aggregate_ (node1);
+ node2 = ffecom_stabilize_aggregate_ (node2);
+ realtype = TREE_TYPE (TYPE_FIELDS (type));
+ item =
+ ffecom_2 (TRUTH_ORIF_EXPR, type,
+ ffecom_2 (code, type,
+ ffecom_1 (REALPART_EXPR, realtype,
+ node1),
+ ffecom_1 (REALPART_EXPR, realtype,
+ node2)),
+ ffecom_2 (code, type,
+ ffecom_1 (IMAGPART_EXPR, realtype,
+ node1),
+ ffecom_1 (IMAGPART_EXPR, realtype,
+ node2)));
+ break;
+
+ default:
+ item = build (code, type, node1, node2);
+ break;
+ }
+
+ if (TREE_SIDE_EFFECTS (node1) || TREE_SIDE_EFFECTS (node2))
+ TREE_SIDE_EFFECTS (item) = 1;
+ return fold (item);
+}
+
+#endif
+/* ffecom_2pass_advise_entrypoint -- Advise that there's this entrypoint
+
+ ffesymbol s; // the ENTRY point itself
+ if (ffecom_2pass_advise_entrypoint(s))
+ // the ENTRY point has been accepted
+
+ Does whatever compiler needs to do when it learns about the entrypoint,
+ like determine the return type of the master function, count the
+ number of entrypoints, etc. Returns FALSE if the return type is
+ not compatible with the return type(s) of other entrypoint(s).
+
+ NOTE: for every call to this fn that returns TRUE, _do_entrypoint must
+ later (after _finish_progunit) be called with the same entrypoint(s)
+ as passed to this fn for which TRUE was returned.
+
+ 03-Jan-92 JCB 2.0
+ Return FALSE if the return type conflicts with previous entrypoints. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+bool
+ffecom_2pass_advise_entrypoint (ffesymbol entry)
+{
+ ffebld list; /* opITEM. */
+ ffebld mlist; /* opITEM. */
+ ffebld plist; /* opITEM. */
+ ffebld arg; /* ffebld_head(opITEM). */
+ ffebld item; /* opITEM. */
+ ffesymbol s; /* ffebld_symter(arg). */
+ ffeinfoBasictype bt = ffesymbol_basictype (entry);
+ ffeinfoKindtype kt = ffesymbol_kindtype (entry);
+ ffetargetCharacterSize size = ffesymbol_size (entry);
+ bool ok;
+
+ if (ffecom_num_entrypoints_ == 0)
+ { /* First entrypoint, make list of main
+ arglist's dummies. */
+ assert (ffecom_primary_entry_ != NULL);
+
+ ffecom_master_bt_ = ffesymbol_basictype (ffecom_primary_entry_);
+ ffecom_master_kt_ = ffesymbol_kindtype (ffecom_primary_entry_);
+ ffecom_master_size_ = ffesymbol_size (ffecom_primary_entry_);
+
+ for (plist = NULL, list = ffesymbol_dummyargs (ffecom_primary_entry_);
+ list != NULL;
+ list = ffebld_trail (list))
+ {
+ arg = ffebld_head (list);
+ if (ffebld_op (arg) != FFEBLD_opSYMTER)
+ continue; /* Alternate return or some such thing. */
+ item = ffebld_new_item (arg, NULL);
+ if (plist == NULL)
+ ffecom_master_arglist_ = item;
+ else
+ ffebld_set_trail (plist, item);
+ plist = item;
+ }
+ }
+
+ /* If necessary, scan entry arglist for alternate returns. Do this scan
+ apparently redundantly (it's done below to UNIONize the arglists) so
+ that we don't complain about RETURN 1 if an offending ENTRY is the only
+ one with an alternate return. */
+
+ if (!ffecom_is_altreturning_)
+ {
+ for (list = ffesymbol_dummyargs (entry);
+ list != NULL;
+ list = ffebld_trail (list))
+ {
+ arg = ffebld_head (list);
+ if (ffebld_op (arg) == FFEBLD_opSTAR)
+ {
+ ffecom_is_altreturning_ = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Now check type compatibility. */
+
+ switch (ffecom_master_bt_)
+ {
+ case FFEINFO_basictypeNONE:
+ ok = (bt != FFEINFO_basictypeCHARACTER);
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ ok
+ = (bt == FFEINFO_basictypeCHARACTER)
+ && (kt == ffecom_master_kt_)
+ && (size == ffecom_master_size_);
+ break;
+
+ case FFEINFO_basictypeANY:
+ return FALSE; /* Just don't bother. */
+
+ default:
+ if (bt == FFEINFO_basictypeCHARACTER)
+ {
+ ok = FALSE;
+ break;
+ }
+ ok = TRUE;
+ if ((bt != ffecom_master_bt_) || (kt != ffecom_master_kt_))
+ {
+ ffecom_master_bt_ = FFEINFO_basictypeNONE;
+ ffecom_master_kt_ = FFEINFO_kindtypeNONE;
+ }
+ break;
+ }
+
+ if (!ok)
+ {
+ ffebad_start (FFEBAD_ENTRY_CONFLICTS);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_finish ();
+ return FALSE; /* Can't handle entrypoint. */
+ }
+
+ /* Entrypoint type compatible with previous types. */
+
+ ++ffecom_num_entrypoints_;
+
+ /* Master-arg-list = UNION(Master-arg-list,entry-arg-list). */
+
+ for (list = ffesymbol_dummyargs (entry);
+ list != NULL;
+ list = ffebld_trail (list))
+ {
+ arg = ffebld_head (list);
+ if (ffebld_op (arg) != FFEBLD_opSYMTER)
+ continue; /* Alternate return or some such thing. */
+ s = ffebld_symter (arg);
+ for (plist = NULL, mlist = ffecom_master_arglist_;
+ mlist != NULL;
+ plist = mlist, mlist = ffebld_trail (mlist))
+ { /* plist points to previous item for easy
+ appending of arg. */
+ if (ffebld_symter (ffebld_head (mlist)) == s)
+ break; /* Already have this arg in the master list. */
+ }
+ if (mlist != NULL)
+ continue; /* Already have this arg in the master list. */
+
+ /* Append this arg to the master list. */
+
+ item = ffebld_new_item (arg, NULL);
+ if (plist == NULL)
+ ffecom_master_arglist_ = item;
+ else
+ ffebld_set_trail (plist, item);
+ }
+
+ return TRUE;
+}
+
+#endif
+/* ffecom_2pass_do_entrypoint -- Do compilation of entrypoint
+
+ ffesymbol s; // the ENTRY point itself
+ ffecom_2pass_do_entrypoint(s);
+
+ Does whatever compiler needs to do to make the entrypoint actually
+ happen. Must be called for each entrypoint after
+ ffecom_finish_progunit is called. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_2pass_do_entrypoint (ffesymbol entry)
+{
+ static int mfn_num = 0;
+ static int ent_num;
+
+ if (mfn_num != ffecom_num_fns_)
+ { /* First entrypoint for this program unit. */
+ ent_num = 1;
+ mfn_num = ffecom_num_fns_;
+ ffecom_do_entry_ (ffecom_primary_entry_, 0);
+ }
+ else
+ ++ent_num;
+
+ --ffecom_num_entrypoints_;
+
+ ffecom_do_entry_ (entry, ent_num);
+}
+
+#endif
+
+/* Essentially does a "fold (build (code, type, node1, node2))" while
+ checking for certain housekeeping things. Always sets
+ TREE_SIDE_EFFECTS. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_2s (enum tree_code code, tree type, tree node1,
+ tree node2)
+{
+ tree item;
+
+ if ((node1 == error_mark_node)
+ || (node2 == error_mark_node)
+ || (type == error_mark_node))
+ return error_mark_node;
+
+ item = build (code, type, node1, node2);
+ TREE_SIDE_EFFECTS (item) = 1;
+ return fold (item);
+}
+
+#endif
+/* Essentially does a "fold (build (code, type, node1, node2, node3))" while
+ checking for certain housekeeping things. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_3 (enum tree_code code, tree type, tree node1,
+ tree node2, tree node3)
+{
+ tree item;
+
+ if ((node1 == error_mark_node)
+ || (node2 == error_mark_node)
+ || (node3 == error_mark_node)
+ || (type == error_mark_node))
+ return error_mark_node;
+
+ item = build (code, type, node1, node2, node3);
+ if (TREE_SIDE_EFFECTS (node1) || TREE_SIDE_EFFECTS (node2)
+ || (node3 != NULL_TREE && TREE_SIDE_EFFECTS (node3)))
+ TREE_SIDE_EFFECTS (item) = 1;
+ return fold (item);
+}
+
+#endif
+/* Essentially does a "fold (build (code, type, node1, node2, node3))" while
+ checking for certain housekeeping things. Always sets
+ TREE_SIDE_EFFECTS. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_3s (enum tree_code code, tree type, tree node1,
+ tree node2, tree node3)
+{
+ tree item;
+
+ if ((node1 == error_mark_node)
+ || (node2 == error_mark_node)
+ || (node3 == error_mark_node)
+ || (type == error_mark_node))
+ return error_mark_node;
+
+ item = build (code, type, node1, node2, node3);
+ TREE_SIDE_EFFECTS (item) = 1;
+ return fold (item);
+}
+
+#endif
+/* ffecom_arg_expr -- Transform argument expr into gcc tree
+
+ See use by ffecom_list_expr.
+
+ If expression is NULL, returns an integer zero tree. If it is not
+ a CHARACTER expression, returns whatever ffecom_expr
+ returns and sets the length return value to NULL_TREE. Otherwise
+ generates code to evaluate the character expression, returns the proper
+ pointer to the result, but does NOT set the length return value to a tree
+ that specifies the length of the result. (In other words, the length
+ variable is always set to NULL_TREE, because a length is never passed.)
+
+ 21-Dec-91 JCB 1.1
+ Don't set returned length, since nobody needs it (yet; someday if
+ we allow CHARACTER*(*) dummies to statement functions, we'll need
+ it). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_arg_expr (ffebld expr, tree *length)
+{
+ tree ign;
+
+ *length = NULL_TREE;
+
+ if (expr == NULL)
+ return integer_zero_node;
+
+ if (ffeinfo_basictype (ffebld_info (expr)) != FFEINFO_basictypeCHARACTER)
+ return ffecom_expr (expr);
+
+ return ffecom_arg_ptr_to_expr (expr, &ign);
+}
+
+#endif
+/* ffecom_arg_ptr_to_expr -- Transform argument expr into gcc tree
+
+ See use by ffecom_list_ptr_to_expr.
+
+ If expression is NULL, returns an integer zero tree. If it is not
+ a CHARACTER expression, returns whatever ffecom_ptr_to_expr
+ returns and sets the length return value to NULL_TREE. Otherwise
+ generates code to evaluate the character expression, returns the proper
+ pointer to the result, AND sets the length return value to a tree that
+ specifies the length of the result.
+
+ If the length argument is NULL, this is a slightly special
+ case of building a FORMAT expression, that is, an expression that
+ will be used at run time without regard to length. For the current
+ implementation, which uses the libf2c library, this means it is nice
+ to append a null byte to the end of the expression, where feasible,
+ to make sure any diagnostic about the FORMAT string terminates at
+ some useful point.
+
+ For now, treat %REF(char-expr) as the same as char-expr with a NULL
+ length argument. This might even be seen as a feature, if a null
+ byte can always be appended. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_arg_ptr_to_expr (ffebld expr, tree *length)
+{
+ tree item;
+ tree ign_length;
+ ffecomConcatList_ catlist;
+
+ if (length != NULL)
+ *length = NULL_TREE;
+
+ if (expr == NULL)
+ return integer_zero_node;
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opPERCENT_VAL:
+ if (ffeinfo_basictype (ffebld_info (expr)) != FFEINFO_basictypeCHARACTER)
+ return ffecom_expr (ffebld_left (expr));
+ {
+ tree temp_exp;
+ tree temp_length;
+
+ temp_exp = ffecom_arg_ptr_to_expr (ffebld_left (expr), &temp_length);
+ return ffecom_1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (temp_exp)),
+ temp_exp);
+ }
+
+ case FFEBLD_opPERCENT_REF:
+ if (ffeinfo_basictype (ffebld_info (expr)) != FFEINFO_basictypeCHARACTER)
+ return ffecom_ptr_to_expr (ffebld_left (expr));
+ if (length != NULL)
+ {
+ ign_length = NULL_TREE;
+ length = &ign_length;
+ }
+ expr = ffebld_left (expr);
+ break;
+
+ case FFEBLD_opPERCENT_DESCR:
+ switch (ffeinfo_basictype (ffebld_info (expr)))
+ {
+#ifdef PASS_HOLLERITH_BY_DESCRIPTOR
+ case FFEINFO_basictypeHOLLERITH:
+#endif
+ case FFEINFO_basictypeCHARACTER:
+ break; /* Passed by descriptor anyway. */
+
+ default:
+ item = ffecom_ptr_to_expr (expr);
+ if (item != error_mark_node)
+ *length = TYPE_SIZE (TREE_TYPE (TREE_TYPE (item)));
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+#ifdef PASS_HOLLERITH_BY_DESCRIPTOR
+ if ((ffeinfo_basictype (ffebld_info (expr)) == FFEINFO_basictypeHOLLERITH)
+ && (length != NULL))
+ { /* Pass Hollerith by descriptor. */
+ ffetargetHollerith h;
+
+ assert (ffebld_op (expr) == FFEBLD_opCONTER);
+ h = ffebld_cu_val_hollerith (ffebld_constant_union
+ (ffebld_conter (expr)));
+ *length
+ = build_int_2 (h.length, 0);
+ TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node;
+ }
+#endif
+
+ if (ffeinfo_basictype (ffebld_info (expr)) != FFEINFO_basictypeCHARACTER)
+ return ffecom_ptr_to_expr (expr);
+
+ assert (ffeinfo_kindtype (ffebld_info (expr))
+ == FFEINFO_kindtypeCHARACTER1);
+
+ catlist = ffecom_concat_list_new_ (expr, FFETARGET_charactersizeNONE);
+ switch (ffecom_concat_list_count_ (catlist))
+ {
+ case 0: /* Shouldn't happen, but in case it does... */
+ if (length != NULL)
+ {
+ *length = ffecom_f2c_ftnlen_zero_node;
+ TREE_TYPE (*length) = ffecom_f2c_ftnlen_type_node;
+ }
+ ffecom_concat_list_kill_ (catlist);
+ return null_pointer_node;
+
+ case 1: /* The (fairly) easy case. */
+ if (length == NULL)
+ ffecom_char_args_with_null_ (&item, &ign_length,
+ ffecom_concat_list_expr_ (catlist, 0));
+ else
+ ffecom_char_args_ (&item, length,
+ ffecom_concat_list_expr_ (catlist, 0));
+ ffecom_concat_list_kill_ (catlist);
+ assert (item != NULL_TREE);
+ return item;
+
+ default: /* Must actually concatenate things. */
+ break;
+ }
+
+ {
+ int count = ffecom_concat_list_count_ (catlist);
+ int i;
+ tree lengths;
+ tree items;
+ tree length_array;
+ tree item_array;
+ tree citem;
+ tree clength;
+ tree temporary;
+ tree num;
+ tree known_length;
+ ffetargetCharacterSize sz;
+
+ length_array
+ = lengths
+ = ffecom_push_tempvar (ffecom_f2c_ftnlen_type_node,
+ FFETARGET_charactersizeNONE, count, TRUE);
+ item_array
+ = items
+ = ffecom_push_tempvar (ffecom_f2c_address_type_node,
+ FFETARGET_charactersizeNONE, count, TRUE);
+
+ known_length = ffecom_f2c_ftnlen_zero_node;
+
+ for (i = 0; i < count; ++i)
+ {
+ if ((i == count)
+ && (length == NULL))
+ ffecom_char_args_with_null_ (&citem, &clength,
+ ffecom_concat_list_expr_ (catlist, i));
+ else
+ ffecom_char_args_ (&citem, &clength,
+ ffecom_concat_list_expr_ (catlist, i));
+ if ((citem == error_mark_node)
+ || (clength == error_mark_node))
+ {
+ ffecom_concat_list_kill_ (catlist);
+ *length = error_mark_node;
+ return error_mark_node;
+ }
+
+ items
+ = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (items),
+ ffecom_modify (void_type_node,
+ ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (item_array))),
+ item_array,
+ build_int_2 (i, 0)),
+ citem),
+ items);
+ clength = ffecom_save_tree (clength);
+ if (length != NULL)
+ known_length
+ = ffecom_2 (PLUS_EXPR, ffecom_f2c_ftnlen_type_node,
+ known_length,
+ clength);
+ lengths
+ = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (lengths),
+ ffecom_modify (void_type_node,
+ ffecom_2 (ARRAY_REF,
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (length_array))),
+ length_array,
+ build_int_2 (i, 0)),
+ clength),
+ lengths);
+ }
+
+ sz = ffecom_concat_list_maxlen_ (catlist);
+ assert (sz != FFETARGET_charactersizeNONE);
+
+ temporary = ffecom_push_tempvar (char_type_node,
+ sz, -1, TRUE);
+ temporary = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (temporary)),
+ temporary);
+
+ item = build_tree_list (NULL_TREE, temporary);
+ TREE_CHAIN (item)
+ = build_tree_list (NULL_TREE,
+ ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (items)),
+ items));
+ TREE_CHAIN (TREE_CHAIN (item))
+ = build_tree_list (NULL_TREE,
+ ffecom_1 (ADDR_EXPR,
+ build_pointer_type (TREE_TYPE (lengths)),
+ lengths));
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (item)))
+ = build_tree_list
+ (NULL_TREE,
+ ffecom_1 (ADDR_EXPR, ffecom_f2c_ptr_to_ftnlen_type_node,
+ convert (ffecom_f2c_ftnlen_type_node,
+ build_int_2 (count, 0))));
+ num = build_int_2 (sz, 0);
+ TREE_TYPE (num) = ffecom_f2c_ftnlen_type_node;
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (item))))
+ = build_tree_list (NULL_TREE, num);
+
+ item = ffecom_call_gfrt (FFECOM_gfrtCAT, item);
+ TREE_SIDE_EFFECTS (item) = 1;
+ item = ffecom_2 (COMPOUND_EXPR, TREE_TYPE (temporary),
+ item,
+ temporary);
+
+ if (length != NULL)
+ *length = known_length;
+ }
+
+ ffecom_concat_list_kill_ (catlist);
+ assert (item != NULL_TREE);
+ return item;
+}
+
+#endif
+/* ffecom_call_gfrt -- Generate call to run-time function
+
+ tree expr;
+ expr = ffecom_call_gfrt(FFECOM_gfrtSTOPNIL,NULL_TREE);
+
+ The first arg is the GNU Fortran Run-Time function index, the second
+ arg is the list of arguments to pass to it. Returned is the expression
+ (WITHOUT TREE_SIDE_EFFECTS set!) that makes the call and returns the
+ result (which may be void). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_call_gfrt (ffecomGfrt ix, tree args)
+{
+ return ffecom_call_ (ffecom_gfrt_tree_ (ix),
+ ffecom_gfrt_kindtype (ix),
+ ffe_is_f2c_library () && ffecom_gfrt_complex_[ix],
+ NULL_TREE, args, NULL_TREE, NULL,
+ NULL, NULL_TREE, TRUE);
+}
+#endif
+
+/* ffecom_constantunion -- Transform constant-union to tree
+
+ ffebldConstantUnion cu; // the constant to transform
+ ffeinfoBasictype bt; // its basic type
+ ffeinfoKindtype kt; // its kind type
+ tree tree_type; // ffecom_tree_type[bt][kt]
+ ffecom_constantunion(&cu,bt,kt,tree_type); */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_constantunion (ffebldConstantUnion *cu, ffeinfoBasictype bt,
+ ffeinfoKindtype kt, tree tree_type)
+{
+ tree item;
+
+ switch (bt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ {
+ int val;
+
+ switch (kt)
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ val = ffebld_cu_val_integer1 (*cu);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ val = ffebld_cu_val_integer2 (*cu);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ val = ffebld_cu_val_integer3 (*cu);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ val = ffebld_cu_val_integer4 (*cu);
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER constant kind type" == NULL);
+ /* Fall through. */
+ case FFEINFO_kindtypeANY:
+ return error_mark_node;
+ }
+ item = build_int_2 (val, (val < 0) ? -1 : 0);
+ TREE_TYPE (item) = tree_type;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ {
+ int val;
+
+ switch (kt)
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ val = ffebld_cu_val_logical1 (*cu);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ val = ffebld_cu_val_logical2 (*cu);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ val = ffebld_cu_val_logical3 (*cu);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ val = ffebld_cu_val_logical4 (*cu);
+ break;
+#endif
+
+ default:
+ assert ("bad LOGICAL constant kind type" == NULL);
+ /* Fall through. */
+ case FFEINFO_kindtypeANY:
+ return error_mark_node;
+ }
+ item = build_int_2 (val, (val < 0) ? -1 : 0);
+ TREE_TYPE (item) = tree_type;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ {
+ REAL_VALUE_TYPE val;
+
+ switch (kt)
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ val = ffetarget_value_real1 (ffebld_cu_val_real1 (*cu));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ val = ffetarget_value_real2 (ffebld_cu_val_real2 (*cu));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ val = ffetarget_value_real3 (ffebld_cu_val_real3 (*cu));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ val = ffetarget_value_real4 (ffebld_cu_val_real4 (*cu));
+ break;
+#endif
+
+ default:
+ assert ("bad REAL constant kind type" == NULL);
+ /* Fall through. */
+ case FFEINFO_kindtypeANY:
+ return error_mark_node;
+ }
+ item = build_real (tree_type, val);
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ {
+ REAL_VALUE_TYPE real;
+ REAL_VALUE_TYPE imag;
+ tree el_type = ffecom_tree_type[FFEINFO_basictypeREAL][kt];
+
+ switch (kt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ real = ffetarget_value_real1 (ffebld_cu_val_complex1 (*cu).real);
+ imag = ffetarget_value_real1 (ffebld_cu_val_complex1 (*cu).imaginary);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ real = ffetarget_value_real2 (ffebld_cu_val_complex2 (*cu).real);
+ imag = ffetarget_value_real2 (ffebld_cu_val_complex2 (*cu).imaginary);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ real = ffetarget_value_real3 (ffebld_cu_val_complex3 (*cu).real);
+ imag = ffetarget_value_real3 (ffebld_cu_val_complex3 (*cu).imaginary);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ real = ffetarget_value_real4 (ffebld_cu_val_complex4 (*cu).real);
+ imag = ffetarget_value_real4 (ffebld_cu_val_complex4 (*cu).imaginary);
+ break;
+#endif
+
+ default:
+ assert ("bad REAL constant kind type" == NULL);
+ /* Fall through. */
+ case FFEINFO_kindtypeANY:
+ return error_mark_node;
+ }
+ item = ffecom_build_complex_constant_ (tree_type,
+ build_real (el_type, real),
+ build_real (el_type, imag));
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ { /* Happens only in DATA and similar contexts. */
+ ffetargetCharacter1 val;
+
+ switch (kt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeLOGICAL1:
+ val = ffebld_cu_val_character1 (*cu);
+ break;
+#endif
+
+ default:
+ assert ("bad CHARACTER constant kind type" == NULL);
+ /* Fall through. */
+ case FFEINFO_kindtypeANY:
+ return error_mark_node;
+ }
+ item = build_string (ffetarget_length_character1 (val),
+ ffetarget_text_character1 (val));
+ TREE_TYPE (item)
+ = build_type_variant (build_array_type (char_type_node,
+ build_range_type
+ (integer_type_node,
+ integer_one_node,
+ build_int_2
+ (ffetarget_length_character1
+ (val), 0))),
+ 1, 0);
+ }
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ {
+ ffetargetHollerith h;
+
+ h = ffebld_cu_val_hollerith (*cu);
+
+ /* If not at least as wide as default INTEGER, widen it. */
+ if (h.length >= FLOAT_TYPE_SIZE / CHAR_TYPE_SIZE)
+ item = build_string (h.length, h.text);
+ else
+ {
+ char str[FLOAT_TYPE_SIZE / CHAR_TYPE_SIZE];
+
+ memcpy (str, h.text, h.length);
+ memset (&str[h.length], ' ',
+ FLOAT_TYPE_SIZE / CHAR_TYPE_SIZE
+ - h.length);
+ item = build_string (FLOAT_TYPE_SIZE / CHAR_TYPE_SIZE,
+ str);
+ }
+ TREE_TYPE (item)
+ = build_type_variant (build_array_type (char_type_node,
+ build_range_type
+ (integer_type_node,
+ integer_one_node,
+ build_int_2
+ (h.length, 0))),
+ 1, 0);
+ }
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ {
+ ffetargetInteger1 ival;
+ ffetargetTypeless tless;
+ ffebad error;
+
+ tless = ffebld_cu_val_typeless (*cu);
+ error = ffetarget_convert_integer1_typeless (&ival, tless);
+ assert (error == FFEBAD);
+
+ item = build_int_2 ((int) ival, 0);
+ }
+ break;
+
+ default:
+ assert ("not yet on constant type" == NULL);
+ /* Fall through. */
+ case FFEINFO_basictypeANY:
+ return error_mark_node;
+ }
+
+ TREE_CONSTANT (item) = 1;
+
+ return item;
+}
+
+#endif
+
+/* Handy way to make a field in a struct/union. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_decl_field (tree context, tree prevfield,
+ char *name, tree type)
+{
+ tree field;
+
+ field = build_decl (FIELD_DECL, get_identifier (name), type);
+ DECL_CONTEXT (field) = context;
+ DECL_FRAME_SIZE (field) = 0;
+ if (prevfield != NULL_TREE)
+ TREE_CHAIN (prevfield) = field;
+
+ return field;
+}
+
+#endif
+
+void
+ffecom_close_include (FILE *f)
+{
+#if FFECOM_GCC_INCLUDE
+ ffecom_close_include_ (f);
+#endif
+}
+
+int
+ffecom_decode_include_option (char *spec)
+{
+#if FFECOM_GCC_INCLUDE
+ return ffecom_decode_include_option_ (spec);
+#else
+ return 1;
+#endif
+}
+
+/* ffecom_end_transition -- Perform end transition on all symbols
+
+ ffecom_end_transition();
+
+ Calls ffecom_sym_end_transition for each global and local symbol. */
+
+void
+ffecom_end_transition ()
+{
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffebld item;
+#endif
+
+ if (ffe_is_ffedebug ())
+ fprintf (dmpout, "; end_stmt_transition\n");
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffecom_list_blockdata_ = NULL;
+ ffecom_list_common_ = NULL;
+#endif
+
+ ffesymbol_drive (ffecom_sym_end_transition);
+ if (ffe_is_ffedebug ())
+ {
+ ffestorag_report ();
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffesymbol_report_all ();
+#endif
+ }
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffecom_start_progunit_ ();
+
+ for (item = ffecom_list_blockdata_;
+ item != NULL;
+ item = ffebld_trail (item))
+ {
+ ffebld callee;
+ ffesymbol s;
+ tree dt;
+ tree t;
+ tree var;
+ int yes;
+ static int number = 0;
+
+ callee = ffebld_head (item);
+ s = ffebld_symter (callee);
+ t = ffesymbol_hook (s).decl_tree;
+ if (t == NULL_TREE)
+ {
+ s = ffecom_sym_transform_ (s);
+ t = ffesymbol_hook (s).decl_tree;
+ }
+
+ yes = suspend_momentary ();
+
+ dt = build_pointer_type (TREE_TYPE (t));
+
+ var = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_forceload_%d",
+ NULL, number++),
+ dt);
+ DECL_EXTERNAL (var) = 0;
+ TREE_STATIC (var) = 1;
+ TREE_PUBLIC (var) = 0;
+ DECL_INITIAL (var) = error_mark_node;
+ TREE_USED (var) = 1;
+
+ var = start_decl (var, FALSE);
+
+ t = ffecom_1 (ADDR_EXPR, dt, t);
+
+ finish_decl (var, t, FALSE);
+
+ resume_momentary (yes);
+ }
+
+ /* This handles any COMMON areas that weren't referenced but have, for
+ example, important initial data. */
+
+ for (item = ffecom_list_common_;
+ item != NULL;
+ item = ffebld_trail (item))
+ ffecom_transform_common_ (ffebld_symter (ffebld_head (item)));
+
+ ffecom_list_common_ = NULL;
+#endif
+}
+
+/* ffecom_exec_transition -- Perform exec transition on all symbols
+
+ ffecom_exec_transition();
+
+ Calls ffecom_sym_exec_transition for each global and local symbol.
+ Make sure error updating not inhibited. */
+
+void
+ffecom_exec_transition ()
+{
+ bool inhibited;
+
+ if (ffe_is_ffedebug ())
+ fprintf (dmpout, "; exec_stmt_transition\n");
+
+ inhibited = ffebad_inhibit ();
+ ffebad_set_inhibit (FALSE);
+
+ ffesymbol_drive (ffecom_sym_exec_transition); /* Don't retract! */
+ ffeequiv_exec_transition (); /* Handle all pending EQUIVALENCEs. */
+ if (ffe_is_ffedebug ())
+ {
+ ffestorag_report ();
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffesymbol_report_all ();
+#endif
+ }
+
+ if (inhibited)
+ ffebad_set_inhibit (TRUE);
+}
+
+/* ffecom_expand_let_stmt -- Compile let (assignment) statement
+
+ ffebld dest;
+ ffebld source;
+ ffecom_expand_let_stmt(dest,source);
+
+ Convert dest and source using ffecom_expr, then join them
+ with an ASSIGN op and pass the whole thing to expand_expr_stmt. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_expand_let_stmt (ffebld dest, ffebld source)
+{
+ tree dest_tree;
+ tree dest_length;
+ tree source_tree;
+ tree expr_tree;
+
+ if (ffeinfo_basictype (ffebld_info (dest)) != FFEINFO_basictypeCHARACTER)
+ {
+ bool dest_used;
+
+ dest_tree = ffecom_expr_rw (dest);
+ if (dest_tree == error_mark_node)
+ return;
+
+ if ((TREE_CODE (dest_tree) != VAR_DECL)
+ || TREE_ADDRESSABLE (dest_tree))
+ source_tree = ffecom_expr_ (source, dest_tree, dest, &dest_used,
+ FALSE, FALSE);
+ else
+ {
+ source_tree = ffecom_expr (source);
+ dest_used = FALSE;
+ }
+ if (source_tree == error_mark_node)
+ return;
+
+ if (dest_used)
+ expr_tree = source_tree;
+ else
+ expr_tree = ffecom_2s (MODIFY_EXPR, void_type_node,
+ dest_tree,
+ source_tree);
+
+ expand_expr_stmt (expr_tree);
+ return;
+ }
+
+ ffecom_push_calltemps ();
+ ffecom_char_args_ (&dest_tree, &dest_length, dest);
+ ffecom_let_char_ (dest_tree, dest_length, ffebld_size_known (dest),
+ source);
+ ffecom_pop_calltemps ();
+}
+
+#endif
+/* ffecom_expr -- Transform expr into gcc tree
+
+ tree t;
+ ffebld expr; // FFE expression.
+ tree = ffecom_expr(expr);
+
+ Recursive descent on expr while making corresponding tree nodes and
+ attaching type info and such. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_expr (ffebld expr)
+{
+ return ffecom_expr_ (expr, NULL_TREE, NULL, NULL, FALSE, FALSE);
+}
+
+#endif
+/* Like ffecom_expr, but return tree usable for assigned GOTO or FORMAT. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_expr_assign (ffebld expr)
+{
+ return ffecom_expr_ (expr, NULL_TREE, NULL, NULL, TRUE, FALSE);
+}
+
+#endif
+/* Like ffecom_expr_rw, but return tree usable for ASSIGN. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_expr_assign_w (ffebld expr)
+{
+ return ffecom_expr_ (expr, NULL_TREE, NULL, NULL, TRUE, FALSE);
+}
+
+#endif
+/* Transform expr for use as into read/write tree and stabilize the
+ reference. Not for use on CHARACTER expressions.
+
+ Recursive descent on expr while making corresponding tree nodes and
+ attaching type info and such. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_expr_rw (ffebld expr)
+{
+ assert (expr != NULL);
+
+ return stabilize_reference (ffecom_expr (expr));
+}
+
+#endif
+/* Do global stuff. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_finish_compile ()
+{
+ assert (ffecom_outer_function_decl_ == NULL_TREE);
+ assert (current_function_decl == NULL_TREE);
+
+ ffeglobal_drive (ffecom_finish_global_);
+}
+
+#endif
+/* Public entry point for front end to access finish_decl. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_finish_decl (tree decl, tree init, bool is_top_level)
+{
+ assert (!is_top_level);
+ finish_decl (decl, init, FALSE);
+}
+
+#endif
+/* Finish a program unit. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_finish_progunit ()
+{
+ ffecom_end_compstmt_ ();
+
+ ffecom_previous_function_decl_ = current_function_decl;
+ ffecom_which_entrypoint_decl_ = NULL_TREE;
+
+ finish_function (0);
+}
+
+#endif
+/* Wrapper for get_identifier. pattern is like "...%s...", text is
+ inserted into final name in place of "%s", or if text is NULL,
+ pattern is like "...%d..." and text form of number is inserted
+ in place of "%d". */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_get_invented_identifier (char *pattern, char *text, int number)
+{
+ tree decl;
+ char *nam;
+ mallocSize lenlen;
+ char space[66];
+
+ if (text == NULL)
+ lenlen = strlen (pattern) + 20;
+ else
+ lenlen = strlen (pattern) + strlen (text) - 1;
+ if (lenlen > ARRAY_SIZE (space))
+ nam = malloc_new_ks (malloc_pool_image (), pattern, lenlen);
+ else
+ nam = &space[0];
+ if (text == NULL)
+ sprintf (&nam[0], pattern, number);
+ else
+ sprintf (&nam[0], pattern, text);
+ decl = get_identifier (nam);
+ if (lenlen > ARRAY_SIZE (space))
+ malloc_kill_ks (malloc_pool_image (), nam, lenlen);
+
+ IDENTIFIER_INVENTED (decl) = 1;
+
+ return decl;
+}
+
+ffeinfoBasictype
+ffecom_gfrt_basictype (ffecomGfrt gfrt)
+{
+ assert (gfrt < FFECOM_gfrt);
+
+ switch (ffecom_gfrt_type_[gfrt])
+ {
+ case FFECOM_rttypeVOID_:
+ case FFECOM_rttypeVOIDSTAR_:
+ return FFEINFO_basictypeNONE;
+
+ case FFECOM_rttypeFTNINT_:
+ return FFEINFO_basictypeINTEGER;
+
+ case FFECOM_rttypeINTEGER_:
+ return FFEINFO_basictypeINTEGER;
+
+ case FFECOM_rttypeLONGINT_:
+ return FFEINFO_basictypeINTEGER;
+
+ case FFECOM_rttypeLOGICAL_:
+ return FFEINFO_basictypeLOGICAL;
+
+ case FFECOM_rttypeREAL_F2C_:
+ case FFECOM_rttypeREAL_GNU_:
+ return FFEINFO_basictypeREAL;
+
+ case FFECOM_rttypeCOMPLEX_F2C_:
+ case FFECOM_rttypeCOMPLEX_GNU_:
+ return FFEINFO_basictypeCOMPLEX;
+
+ case FFECOM_rttypeDOUBLE_:
+ case FFECOM_rttypeDOUBLEREAL_:
+ return FFEINFO_basictypeREAL;
+
+ case FFECOM_rttypeDBLCMPLX_F2C_:
+ case FFECOM_rttypeDBLCMPLX_GNU_:
+ return FFEINFO_basictypeCOMPLEX;
+
+ case FFECOM_rttypeCHARACTER_:
+ return FFEINFO_basictypeCHARACTER;
+
+ default:
+ return FFEINFO_basictypeANY;
+ }
+}
+
+ffeinfoKindtype
+ffecom_gfrt_kindtype (ffecomGfrt gfrt)
+{
+ assert (gfrt < FFECOM_gfrt);
+
+ switch (ffecom_gfrt_type_[gfrt])
+ {
+ case FFECOM_rttypeVOID_:
+ case FFECOM_rttypeVOIDSTAR_:
+ return FFEINFO_kindtypeNONE;
+
+ case FFECOM_rttypeFTNINT_:
+ return FFEINFO_kindtypeINTEGER1;
+
+ case FFECOM_rttypeINTEGER_:
+ return FFEINFO_kindtypeINTEGER1;
+
+ case FFECOM_rttypeLONGINT_:
+ return FFEINFO_kindtypeINTEGER4;
+
+ case FFECOM_rttypeLOGICAL_:
+ return FFEINFO_kindtypeLOGICAL1;
+
+ case FFECOM_rttypeREAL_F2C_:
+ case FFECOM_rttypeREAL_GNU_:
+ return FFEINFO_kindtypeREAL1;
+
+ case FFECOM_rttypeCOMPLEX_F2C_:
+ case FFECOM_rttypeCOMPLEX_GNU_:
+ return FFEINFO_kindtypeREAL1;
+
+ case FFECOM_rttypeDOUBLE_:
+ case FFECOM_rttypeDOUBLEREAL_:
+ return FFEINFO_kindtypeREAL2;
+
+ case FFECOM_rttypeDBLCMPLX_F2C_:
+ case FFECOM_rttypeDBLCMPLX_GNU_:
+ return FFEINFO_kindtypeREAL2;
+
+ case FFECOM_rttypeCHARACTER_:
+ return FFEINFO_kindtypeCHARACTER1;
+
+ default:
+ return FFEINFO_kindtypeANY;
+ }
+}
+
+void
+ffecom_init_0 ()
+{
+ tree endlink;
+ int i;
+ int j;
+ tree t;
+ tree field;
+ ffetype type;
+ ffetype base_type;
+
+ /* This block of code comes from the now-obsolete cktyps.c. It checks
+ whether the compiler environment is buggy in known ways, some of which
+ would, if not explicitly checked here, result in subtle bugs in g77. */
+
+ if (ffe_is_do_internal_checks ())
+ {
+ static char names[][12]
+ =
+ {"bar", "bletch", "foo", "foobar"};
+ char *name;
+ unsigned long ul;
+ double fl;
+
+ name = bsearch ("foo", &names[0], ARRAY_SIZE (names), sizeof (names[0]),
+ (int (*)()) strcmp);
+ if (name != (char *) &names[2])
+ {
+ assert ("bsearch doesn't work, #define FFEPROJ_BSEARCH 0 in proj.h"
+ == NULL);
+ abort ();
+ }
+
+ ul = strtoul ("123456789", NULL, 10);
+ if (ul != 123456789L)
+ {
+ assert ("strtoul doesn't have enough range, #define FFEPROJ_STRTOUL 0\
+ in proj.h" == NULL);
+ abort ();
+ }
+
+ fl = atof ("56.789");
+ if ((fl < 56.788) || (fl > 56.79))
+ {
+ assert ("atof not type double, fix your #include <stdio.h>"
+ == NULL);
+ abort ();
+ }
+ }
+
+ /* Set the sizetype before we do anything else. This _should_ be the
+ first type we create. */
+
+ t = make_unsigned_type (POINTER_SIZE);
+ assert (t == sizetype);
+
+#if FFECOM_GCC_INCLUDE
+ ffecom_initialize_char_syntax_ ();
+#endif
+
+ ffecom_outer_function_decl_ = NULL_TREE;
+ current_function_decl = NULL_TREE;
+ named_labels = NULL_TREE;
+ current_binding_level = NULL_BINDING_LEVEL;
+ free_binding_level = NULL_BINDING_LEVEL;
+ pushlevel (0); /* make the binding_level structure for
+ global names */
+ global_binding_level = current_binding_level;
+
+ /* Define `int' and `char' first so that dbx will output them first. */
+
+ integer_type_node = make_signed_type (INT_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("int"),
+ integer_type_node));
+
+ char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("char"),
+ char_type_node));
+
+ long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("long int"),
+ long_integer_type_node));
+
+ unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned int"),
+ unsigned_type_node));
+
+ long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("long unsigned int"),
+ long_unsigned_type_node));
+
+ long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("long long int"),
+ long_long_integer_type_node));
+
+ long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("long long unsigned int"),
+ long_long_unsigned_type_node));
+
+ error_mark_node = make_node (ERROR_MARK);
+ TREE_TYPE (error_mark_node) = error_mark_node;
+
+ short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"),
+ short_integer_type_node));
+
+ short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"),
+ short_unsigned_type_node));
+
+ /* Define both `signed char' and `unsigned char'. */
+ signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("signed char"),
+ signed_char_type_node));
+
+ unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned char"),
+ unsigned_char_type_node));
+
+ float_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
+ layout_type (float_type_node);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("float"),
+ float_type_node));
+
+ double_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
+ layout_type (double_type_node);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("double"),
+ double_type_node));
+
+ long_double_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
+ layout_type (long_double_type_node);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("long double"),
+ long_double_type_node));
+
+ complex_integer_type_node = ffecom_make_complex_type_ (integer_type_node);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"),
+ complex_integer_type_node));
+
+ complex_float_type_node = ffecom_make_complex_type_ (float_type_node);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
+ complex_float_type_node));
+
+ complex_double_type_node = ffecom_make_complex_type_ (double_type_node);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"),
+ complex_double_type_node));
+
+ complex_long_double_type_node = ffecom_make_complex_type_ (long_double_type_node);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"),
+ complex_long_double_type_node));
+
+ integer_zero_node = build_int_2 (0, 0);
+ TREE_TYPE (integer_zero_node) = integer_type_node;
+ integer_one_node = build_int_2 (1, 0);
+ TREE_TYPE (integer_one_node) = integer_type_node;
+
+ size_zero_node = build_int_2 (0, 0);
+ TREE_TYPE (size_zero_node) = sizetype;
+ size_one_node = build_int_2 (1, 0);
+ TREE_TYPE (size_one_node) = sizetype;
+
+ void_type_node = make_node (VOID_TYPE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("void"),
+ void_type_node));
+ layout_type (void_type_node); /* Uses integer_zero_node */
+ /* We are not going to have real types in C with less than byte alignment,
+ so we might as well not have any types that claim to have it. */
+ TYPE_ALIGN (void_type_node) = BITS_PER_UNIT;
+
+ null_pointer_node = build_int_2 (0, 0);
+ TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
+ layout_type (TREE_TYPE (null_pointer_node));
+
+ string_type_node = build_pointer_type (char_type_node);
+
+ ffecom_tree_fun_type_void
+ = build_function_type (void_type_node, NULL_TREE);
+
+ ffecom_tree_ptr_to_fun_type_void
+ = build_pointer_type (ffecom_tree_fun_type_void);
+
+ endlink = tree_cons (NULL_TREE, void_type_node, NULL_TREE);
+
+ float_ftype_float
+ = build_function_type (float_type_node,
+ tree_cons (NULL_TREE, float_type_node, endlink));
+
+ double_ftype_double
+ = build_function_type (double_type_node,
+ tree_cons (NULL_TREE, double_type_node, endlink));
+
+ ldouble_ftype_ldouble
+ = build_function_type (long_double_type_node,
+ tree_cons (NULL_TREE, long_double_type_node,
+ endlink));
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (ffecom_tree_type); ++i)
+ for (j = 0; ((size_t) j) < ARRAY_SIZE (ffecom_tree_type[0]); ++j)
+ {
+ ffecom_tree_type[i][j] = NULL_TREE;
+ ffecom_tree_fun_type[i][j] = NULL_TREE;
+ ffecom_tree_ptr_to_fun_type[i][j] = NULL_TREE;
+ ffecom_f2c_typecode_[i][j] = -1;
+ }
+
+ /* Set up standard g77 types. Note that INTEGER and LOGICAL are set
+ to size FLOAT_TYPE_SIZE because they have to be the same size as
+ REAL, which also is FLOAT_TYPE_SIZE, according to the standard.
+ Compiler options and other such stuff that change the ways these
+ types are set should not affect this particular setup. */
+
+ ffecom_tree_type[FFEINFO_basictypeINTEGER][FFEINFO_kindtypeINTEGER1]
+ = t = make_signed_type (FLOAT_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("integer"),
+ t));
+ type = ffetype_new ();
+ base_type = type;
+ ffeinfo_set_type (FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER1,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 1, type);
+ assert (ffetype_size (type) == sizeof (ffetargetInteger1));
+
+ ffecom_tree_type[FFEINFO_basictypeHOLLERITH][FFEINFO_kindtypeINTEGER1]
+ = t = make_unsigned_type (FLOAT_TYPE_SIZE); /* HOLLERITH means unsigned. */
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned"),
+ t));
+
+ ffecom_tree_type[FFEINFO_basictypeINTEGER][FFEINFO_kindtypeINTEGER2]
+ = t = make_signed_type (CHAR_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("byte"),
+ t));
+ type = ffetype_new ();
+ ffeinfo_set_type (FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER2,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 3, type);
+ assert (ffetype_size (type) == sizeof (ffetargetInteger2));
+
+ ffecom_tree_type[FFEINFO_basictypeHOLLERITH][FFEINFO_kindtypeINTEGER2]
+ = t = make_unsigned_type (CHAR_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned byte"),
+ t));
+
+ ffecom_tree_type[FFEINFO_basictypeINTEGER][FFEINFO_kindtypeINTEGER3]
+ = t = make_signed_type (CHAR_TYPE_SIZE * 2);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("word"),
+ t));
+ type = ffetype_new ();
+ ffeinfo_set_type (FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER3,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 6, type);
+ assert (ffetype_size (type) == sizeof (ffetargetInteger3));
+
+ ffecom_tree_type[FFEINFO_basictypeHOLLERITH][FFEINFO_kindtypeINTEGER3]
+ = t = make_unsigned_type (CHAR_TYPE_SIZE * 2);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned word"),
+ t));
+
+ ffecom_tree_type[FFEINFO_basictypeINTEGER][FFEINFO_kindtypeINTEGER4]
+ = t = make_signed_type (FLOAT_TYPE_SIZE * 2);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("integer4"),
+ t));
+ type = ffetype_new ();
+ ffeinfo_set_type (FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGER4,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 2, type);
+ assert (ffetype_size (type) == sizeof (ffetargetInteger4));
+
+ ffecom_tree_type[FFEINFO_basictypeHOLLERITH][FFEINFO_kindtypeINTEGER4]
+ = t = make_unsigned_type (FLOAT_TYPE_SIZE * 2);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned4"),
+ t));
+
+#if 0
+ if (ffe_is_do_internal_checks ()
+ && LONG_TYPE_SIZE != FLOAT_TYPE_SIZE
+ && LONG_TYPE_SIZE != CHAR_TYPE_SIZE
+ && LONG_TYPE_SIZE != SHORT_TYPE_SIZE
+ && LONG_TYPE_SIZE != LONG_LONG_TYPE_SIZE)
+ {
+ fprintf (stderr, "Sorry, no g77 support for LONG_TYPE_SIZE (%d bits) yet.\n",
+ LONG_TYPE_SIZE);
+ }
+#endif
+
+ ffecom_tree_type[FFEINFO_basictypeLOGICAL][FFEINFO_kindtypeLOGICAL1]
+ = t = make_signed_type (FLOAT_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("logical"),
+ t));
+ type = ffetype_new ();
+ base_type = type;
+ ffeinfo_set_type (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL1,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 1, type);
+ assert (ffetype_size (type) == sizeof (ffetargetLogical1));
+
+ ffecom_tree_type[FFEINFO_basictypeLOGICAL][FFEINFO_kindtypeLOGICAL2]
+ = t = make_signed_type (CHAR_TYPE_SIZE);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("logical2"),
+ t));
+ type = ffetype_new ();
+ ffeinfo_set_type (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL2,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 3, type);
+ assert (ffetype_size (type) == sizeof (ffetargetLogical2));
+
+ ffecom_tree_type[FFEINFO_basictypeLOGICAL][FFEINFO_kindtypeLOGICAL3]
+ = t = make_signed_type (CHAR_TYPE_SIZE * 2);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("logical3"),
+ t));
+ type = ffetype_new ();
+ ffeinfo_set_type (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL3,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 6, type);
+ assert (ffetype_size (type) == sizeof (ffetargetLogical3));
+
+ ffecom_tree_type[FFEINFO_basictypeLOGICAL][FFEINFO_kindtypeLOGICAL4]
+ = t = make_signed_type (FLOAT_TYPE_SIZE * 2);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("logical4"),
+ t));
+ type = ffetype_new ();
+ ffeinfo_set_type (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICAL4,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 2, type);
+ assert (ffetype_size (type) == sizeof (ffetargetLogical4));
+
+ ffecom_tree_type[FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1]
+ = t = make_node (REAL_TYPE);
+ TYPE_PRECISION (t) = FLOAT_TYPE_SIZE;
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("real"),
+ t));
+ layout_type (t);
+ type = ffetype_new ();
+ base_type = type;
+ ffeinfo_set_type (FFEINFO_basictypeREAL, FFEINFO_kindtypeREAL1,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 1, type);
+ ffecom_f2c_typecode_[FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1]
+ = FFETARGET_f2cTYREAL;
+ assert (ffetype_size (type) == sizeof (ffetargetReal1));
+
+ ffecom_tree_type[FFEINFO_basictypeREAL][FFEINFO_kindtypeREALDOUBLE]
+ = t = make_node (REAL_TYPE);
+ TYPE_PRECISION (t) = FLOAT_TYPE_SIZE * 2; /* Always twice REAL. */
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("double precision"),
+ t));
+ layout_type (t);
+ type = ffetype_new ();
+ ffeinfo_set_type (FFEINFO_basictypeREAL, FFEINFO_kindtypeREALDOUBLE,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 2, type);
+ ffecom_f2c_typecode_[FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL2]
+ = FFETARGET_f2cTYDREAL;
+ assert (ffetype_size (type) == sizeof (ffetargetReal2));
+
+ ffecom_tree_type[FFEINFO_basictypeCOMPLEX][FFEINFO_kindtypeREAL1]
+ = t = ffecom_make_complex_type_ (ffecom_tree_type[FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL1]);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("complex"),
+ t));
+ type = ffetype_new ();
+ base_type = type;
+ ffeinfo_set_type (FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREAL1,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 1, type);
+ ffecom_f2c_typecode_[FFEINFO_basictypeCOMPLEX][FFEINFO_kindtypeREAL1]
+ = FFETARGET_f2cTYCOMPLEX;
+ assert (ffetype_size (type) == sizeof (ffetargetComplex1));
+
+ ffecom_tree_type[FFEINFO_basictypeCOMPLEX][FFEINFO_kindtypeREALDOUBLE]
+ = t = ffecom_make_complex_type_ (ffecom_tree_type[FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL2]);
+ pushdecl (build_decl (TYPE_DECL, get_identifier ("double complex"),
+ t));
+ type = ffetype_new ();
+ ffeinfo_set_type (FFEINFO_basictypeCOMPLEX, FFEINFO_kindtypeREALDOUBLE,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_star (base_type,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / CHAR_TYPE_SIZE,
+ type);
+ ffetype_set_kind (base_type, 2,
+ type);
+ ffecom_f2c_typecode_[FFEINFO_basictypeCOMPLEX][FFEINFO_kindtypeREAL2]
+ = FFETARGET_f2cTYDCOMPLEX;
+ assert (ffetype_size (type) == sizeof (ffetargetComplex2));
+
+ /* Make function and ptr-to-function types for non-CHARACTER types. */
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (ffecom_tree_type); ++i)
+ for (j = 0; ((size_t) j) < ARRAY_SIZE (ffecom_tree_type[0]); ++j)
+ {
+ if ((t = ffecom_tree_type[i][j]) != NULL_TREE)
+ {
+ if (i == FFEINFO_basictypeINTEGER)
+ {
+ /* Figure out the smallest INTEGER type that can hold
+ a pointer on this machine. */
+ if (GET_MODE_SIZE (TYPE_MODE (t))
+ >= GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (null_pointer_node))))
+ {
+ if ((ffecom_pointer_kind_ == FFEINFO_kindtypeNONE)
+ || (GET_MODE_SIZE (TYPE_MODE (ffecom_tree_type[i][ffecom_pointer_kind_]))
+ > GET_MODE_SIZE (TYPE_MODE (t))))
+ ffecom_pointer_kind_ = j;
+ }
+ }
+ else if (i == FFEINFO_basictypeCOMPLEX)
+ t = void_type_node;
+ /* For f2c compatibility, REAL functions are really
+ implemented as DOUBLE PRECISION. */
+ else if ((i == FFEINFO_basictypeREAL)
+ && (j == FFEINFO_kindtypeREAL1))
+ t = ffecom_tree_type
+ [FFEINFO_basictypeREAL][FFEINFO_kindtypeREAL2];
+
+ t = ffecom_tree_fun_type[i][j] = build_function_type (t,
+ NULL_TREE);
+ ffecom_tree_ptr_to_fun_type[i][j] = build_pointer_type (t);
+ }
+ }
+
+ /* Set up pointer types. */
+
+ if (ffecom_pointer_kind_ == FFEINFO_basictypeNONE)
+ fatal ("no INTEGER type can hold a pointer on this configuration");
+ else if (0 && ffe_is_do_internal_checks ())
+ fprintf (stderr, "Pointer type kt=%d\n", ffecom_pointer_kind_);
+ ffetype_set_kind (ffeinfo_type (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT),
+ 7,
+ ffeinfo_type (FFEINFO_basictypeINTEGER,
+ ffecom_pointer_kind_));
+
+ if (ffe_is_ugly_assign ())
+ ffecom_label_kind_ = ffecom_pointer_kind_; /* Require ASSIGN etc to this. */
+ else
+ ffecom_label_kind_ = FFEINFO_kindtypeINTEGERDEFAULT;
+ if (0 && ffe_is_do_internal_checks ())
+ fprintf (stderr, "Label type kt=%d\n", ffecom_label_kind_);
+
+ ffecom_integer_type_node
+ = ffecom_tree_type[FFEINFO_basictypeINTEGER][FFEINFO_kindtypeINTEGER1];
+ ffecom_integer_zero_node = convert (ffecom_integer_type_node,
+ integer_zero_node);
+ ffecom_integer_one_node = convert (ffecom_integer_type_node,
+ integer_one_node);
+
+ /* Yes, the "FLOAT_TYPE_SIZE" references below are intentional.
+ Turns out that by TYLONG, runtime/libI77/lio.h really means
+ "whatever size an ftnint is". For consistency and sanity,
+ com.h and runtime/f2c.h.in agree that flag, ftnint, and ftlen
+ all are INTEGER, which we also make out of whatever back-end
+ integer type is FLOAT_TYPE_SIZE bits wide. This change, from
+ LONG_TYPE_SIZE, for TYLONG and TYLOGICAL, was necessary to
+ accommodate machines like the Alpha. Note that this suggests
+ f2c and libf2c are missing a distinction perhaps needed on
+ some machines between "int" and "long int". -- burley 0.5.5 950215 */
+
+ ffecom_f2c_set_lio_code_ (FFEINFO_basictypeINTEGER, FLOAT_TYPE_SIZE,
+ FFETARGET_f2cTYLONG);
+ ffecom_f2c_set_lio_code_ (FFEINFO_basictypeINTEGER, SHORT_TYPE_SIZE,
+ FFETARGET_f2cTYSHORT);
+ ffecom_f2c_set_lio_code_ (FFEINFO_basictypeINTEGER, CHAR_TYPE_SIZE,
+ FFETARGET_f2cTYINT1);
+ ffecom_f2c_set_lio_code_ (FFEINFO_basictypeINTEGER, LONG_LONG_TYPE_SIZE,
+ FFETARGET_f2cTYQUAD);
+ ffecom_f2c_set_lio_code_ (FFEINFO_basictypeLOGICAL, FLOAT_TYPE_SIZE,
+ FFETARGET_f2cTYLOGICAL);
+ ffecom_f2c_set_lio_code_ (FFEINFO_basictypeLOGICAL, SHORT_TYPE_SIZE,
+ FFETARGET_f2cTYLOGICAL2);
+ ffecom_f2c_set_lio_code_ (FFEINFO_basictypeLOGICAL, CHAR_TYPE_SIZE,
+ FFETARGET_f2cTYLOGICAL1);
+ ffecom_f2c_set_lio_code_ (FFEINFO_basictypeLOGICAL, LONG_LONG_TYPE_SIZE,
+ FFETARGET_f2cTYQUAD /* ~~~ */);
+
+ /* CHARACTER stuff is all special-cased, so it is not handled in the above
+ loop. CHARACTER items are built as arrays of unsigned char. */
+
+ ffecom_tree_type[FFEINFO_basictypeCHARACTER]
+ [FFEINFO_kindtypeCHARACTER1] = t = char_type_node;
+ type = ffetype_new ();
+ base_type = type;
+ ffeinfo_set_type (FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTER1,
+ type);
+ ffetype_set_ams (type,
+ TYPE_ALIGN (t) / BITS_PER_UNIT, 0,
+ TREE_INT_CST_LOW (TYPE_SIZE (t)) / BITS_PER_UNIT);
+ ffetype_set_kind (base_type, 1, type);
+ assert (ffetype_size (type)
+ == sizeof (((ffetargetCharacter1) { 0, NULL }).text[0]));
+
+ ffecom_tree_fun_type[FFEINFO_basictypeCHARACTER]
+ [FFEINFO_kindtypeCHARACTER1] = ffecom_tree_fun_type_void;
+ ffecom_tree_ptr_to_fun_type[FFEINFO_basictypeCHARACTER]
+ [FFEINFO_kindtypeCHARACTER1]
+ = ffecom_tree_ptr_to_fun_type_void;
+ ffecom_f2c_typecode_[FFEINFO_basictypeCHARACTER][FFEINFO_kindtypeCHARACTER1]
+ = FFETARGET_f2cTYCHAR;
+
+ ffecom_f2c_typecode_[FFEINFO_basictypeANY][FFEINFO_kindtypeANY]
+ = 0;
+
+ /* Make multi-return-value type and fields. */
+
+ ffecom_multi_type_node_ = make_node (UNION_TYPE);
+
+ field = NULL_TREE;
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (ffecom_tree_type); ++i)
+ for (j = 0; ((size_t) j) < ARRAY_SIZE (ffecom_tree_type[0]); ++j)
+ {
+ char name[30];
+
+ if (ffecom_tree_type[i][j] == NULL_TREE)
+ continue; /* Not supported. */
+ sprintf (&name[0], "bt_%s_kt_%s",
+ ffeinfo_basictype_string ((ffeinfoBasictype) i),
+ ffeinfo_kindtype_string ((ffeinfoKindtype) j));
+ ffecom_multi_fields_[i][j] = build_decl (FIELD_DECL,
+ get_identifier (name),
+ ffecom_tree_type[i][j]);
+ DECL_CONTEXT (ffecom_multi_fields_[i][j])
+ = ffecom_multi_type_node_;
+ DECL_FRAME_SIZE (ffecom_multi_fields_[i][j]) = 0;
+ TREE_CHAIN (ffecom_multi_fields_[i][j]) = field;
+ field = ffecom_multi_fields_[i][j];
+ }
+
+ TYPE_FIELDS (ffecom_multi_type_node_) = field;
+ layout_type (ffecom_multi_type_node_);
+
+ /* Subroutines usually return integer because they might have alternate
+ returns. */
+
+ ffecom_tree_subr_type
+ = build_function_type (integer_type_node, NULL_TREE);
+ ffecom_tree_ptr_to_subr_type
+ = build_pointer_type (ffecom_tree_subr_type);
+ ffecom_tree_blockdata_type
+ = build_function_type (void_type_node, NULL_TREE);
+
+ builtin_function ("__builtin_sqrtf", float_ftype_float,
+ BUILT_IN_FSQRT, "sqrtf");
+ builtin_function ("__builtin_fsqrt", double_ftype_double,
+ BUILT_IN_FSQRT, "sqrt");
+ builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble,
+ BUILT_IN_FSQRT, "sqrtl");
+ builtin_function ("__builtin_sinf", float_ftype_float,
+ BUILT_IN_SIN, "sinf");
+ builtin_function ("__builtin_sin", double_ftype_double,
+ BUILT_IN_SIN, "sin");
+ builtin_function ("__builtin_sinl", ldouble_ftype_ldouble,
+ BUILT_IN_SIN, "sinl");
+ builtin_function ("__builtin_cosf", float_ftype_float,
+ BUILT_IN_COS, "cosf");
+ builtin_function ("__builtin_cos", double_ftype_double,
+ BUILT_IN_COS, "cos");
+ builtin_function ("__builtin_cosl", ldouble_ftype_ldouble,
+ BUILT_IN_COS, "cosl");
+
+#if BUILT_FOR_270
+ pedantic_lvalues = FALSE;
+#endif
+
+ ffecom_f2c_make_type_ (&ffecom_f2c_integer_type_node,
+ FFECOM_f2cINTEGER,
+ "integer");
+ ffecom_f2c_make_type_ (&ffecom_f2c_address_type_node,
+ FFECOM_f2cADDRESS,
+ "address");
+ ffecom_f2c_make_type_ (&ffecom_f2c_real_type_node,
+ FFECOM_f2cREAL,
+ "real");
+ ffecom_f2c_make_type_ (&ffecom_f2c_doublereal_type_node,
+ FFECOM_f2cDOUBLEREAL,
+ "doublereal");
+ ffecom_f2c_make_type_ (&ffecom_f2c_complex_type_node,
+ FFECOM_f2cCOMPLEX,
+ "complex");
+ ffecom_f2c_make_type_ (&ffecom_f2c_doublecomplex_type_node,
+ FFECOM_f2cDOUBLECOMPLEX,
+ "doublecomplex");
+ ffecom_f2c_make_type_ (&ffecom_f2c_longint_type_node,
+ FFECOM_f2cLONGINT,
+ "longint");
+ ffecom_f2c_make_type_ (&ffecom_f2c_logical_type_node,
+ FFECOM_f2cLOGICAL,
+ "logical");
+ ffecom_f2c_make_type_ (&ffecom_f2c_flag_type_node,
+ FFECOM_f2cFLAG,
+ "flag");
+ ffecom_f2c_make_type_ (&ffecom_f2c_ftnlen_type_node,
+ FFECOM_f2cFTNLEN,
+ "ftnlen");
+ ffecom_f2c_make_type_ (&ffecom_f2c_ftnint_type_node,
+ FFECOM_f2cFTNINT,
+ "ftnint");
+
+ ffecom_f2c_ftnlen_zero_node
+ = convert (ffecom_f2c_ftnlen_type_node, integer_zero_node);
+
+ ffecom_f2c_ftnlen_one_node
+ = convert (ffecom_f2c_ftnlen_type_node, integer_one_node);
+
+ ffecom_f2c_ftnlen_two_node = build_int_2 (2, 0);
+ TREE_TYPE (ffecom_f2c_ftnlen_two_node) = ffecom_integer_type_node;
+
+ ffecom_f2c_ptr_to_ftnlen_type_node
+ = build_pointer_type (ffecom_f2c_ftnlen_type_node);
+
+ ffecom_f2c_ptr_to_ftnint_type_node
+ = build_pointer_type (ffecom_f2c_ftnint_type_node);
+
+ ffecom_f2c_ptr_to_integer_type_node
+ = build_pointer_type (ffecom_f2c_integer_type_node);
+
+ ffecom_f2c_ptr_to_real_type_node
+ = build_pointer_type (ffecom_f2c_real_type_node);
+
+ ffecom_float_zero_ = build_real (float_type_node, dconst0);
+ ffecom_double_zero_ = build_real (double_type_node, dconst0);
+ {
+ REAL_VALUE_TYPE point_5;
+
+#ifdef REAL_ARITHMETIC
+ REAL_ARITHMETIC (point_5, RDIV_EXPR, dconst1, dconst2);
+#else
+ point_5 = .5;
+#endif
+ ffecom_float_half_ = build_real (float_type_node, point_5);
+ ffecom_double_half_ = build_real (double_type_node, point_5);
+ }
+
+ /* Do "extern int xargc;". */
+
+ ffecom_tree_xargc_ = build_decl (VAR_DECL,
+ get_identifier ("f__xargc"),
+ integer_type_node);
+ DECL_EXTERNAL (ffecom_tree_xargc_) = 1;
+ TREE_STATIC (ffecom_tree_xargc_) = 1;
+ TREE_PUBLIC (ffecom_tree_xargc_) = 1;
+ ffecom_tree_xargc_ = start_decl (ffecom_tree_xargc_, FALSE);
+ finish_decl (ffecom_tree_xargc_, NULL_TREE, FALSE);
+
+#if 0 /* This is being fixed, and seems to be working now. */
+ if ((FLOAT_TYPE_SIZE != 32)
+ || (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (null_pointer_node))) != 32))
+ {
+ warning ("configuration: REAL, INTEGER, and LOGICAL are %d bits wide,",
+ (int) FLOAT_TYPE_SIZE);
+ warning ("and pointers are %d bits wide, but g77 doesn't yet work",
+ (int) TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (null_pointer_node))));
+ warning ("properly unless they all are 32 bits wide.");
+ warning ("Please keep this in mind before you report bugs. g77 should");
+ warning ("support non-32-bit machines better as of version 0.6.");
+ }
+#endif
+
+#if 0 /* Code in ste.c that would crash has been commented out. */
+ if (TYPE_PRECISION (ffecom_f2c_ftnlen_type_node)
+ < TYPE_PRECISION (string_type_node))
+ /* I/O will probably crash. */
+ warning ("configuration: char * holds %d bits, but ftnlen only %d",
+ TYPE_PRECISION (string_type_node),
+ TYPE_PRECISION (ffecom_f2c_ftnlen_type_node));
+#endif
+
+#if 0 /* ASSIGN-related stuff has been changed to accommodate this. */
+ if (TYPE_PRECISION (ffecom_integer_type_node)
+ < TYPE_PRECISION (string_type_node))
+ /* ASSIGN 10 TO I will crash. */
+ warning ("configuration: char * holds %d bits, but INTEGER only %d --\n\
+ ASSIGN statement might fail",
+ TYPE_PRECISION (string_type_node),
+ TYPE_PRECISION (ffecom_integer_type_node));
+#endif
+}
+
+#endif
+/* ffecom_init_2 -- Initialize
+
+ ffecom_init_2(); */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_init_2 ()
+{
+ assert (ffecom_outer_function_decl_ == NULL_TREE);
+ assert (current_function_decl == NULL_TREE);
+ assert (ffecom_which_entrypoint_decl_ == NULL_TREE);
+
+ ffecom_master_arglist_ = NULL;
+ ++ffecom_num_fns_;
+ ffecom_latest_temp_ = NULL;
+ ffecom_primary_entry_ = NULL;
+ ffecom_is_altreturning_ = FALSE;
+ ffecom_func_result_ = NULL_TREE;
+ ffecom_multi_retval_ = NULL_TREE;
+}
+
+#endif
+/* ffecom_list_expr -- Transform list of exprs into gcc tree
+
+ tree t;
+ ffebld expr; // FFE opITEM list.
+ tree = ffecom_list_expr(expr);
+
+ List of actual args is transformed into corresponding gcc backend list. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_list_expr (ffebld expr)
+{
+ tree list;
+ tree *plist = &list;
+ tree trail = NULL_TREE; /* Append char length args here. */
+ tree *ptrail = &trail;
+ tree length;
+
+ while (expr != NULL)
+ {
+ *plist
+ = build_tree_list (NULL_TREE, ffecom_arg_expr (ffebld_head (expr),
+ &length));
+ plist = &TREE_CHAIN (*plist);
+ expr = ffebld_trail (expr);
+ if (length != NULL_TREE)
+ {
+ *ptrail = build_tree_list (NULL_TREE, length);
+ ptrail = &TREE_CHAIN (*ptrail);
+ }
+ }
+
+ *plist = trail;
+
+ return list;
+}
+
+#endif
+/* ffecom_list_ptr_to_expr -- Transform list of exprs into gcc tree
+
+ tree t;
+ ffebld expr; // FFE opITEM list.
+ tree = ffecom_list_ptr_to_expr(expr);
+
+ List of actual args is transformed into corresponding gcc backend list for
+ use in calling an external procedure (vs. a statement function). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_list_ptr_to_expr (ffebld expr)
+{
+ tree list;
+ tree *plist = &list;
+ tree trail = NULL_TREE; /* Append char length args here. */
+ tree *ptrail = &trail;
+ tree length;
+
+ while (expr != NULL)
+ {
+ *plist
+ = build_tree_list (NULL_TREE,
+ ffecom_arg_ptr_to_expr (ffebld_head (expr),
+ &length));
+ plist = &TREE_CHAIN (*plist);
+ expr = ffebld_trail (expr);
+ if (length != NULL_TREE)
+ {
+ *ptrail = build_tree_list (NULL_TREE, length);
+ ptrail = &TREE_CHAIN (*ptrail);
+ }
+ }
+
+ *plist = trail;
+
+ return list;
+}
+
+#endif
+/* Obtain gcc's LABEL_DECL tree for label. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_lookup_label (ffelab label)
+{
+ tree glabel;
+
+ if (ffelab_hook (label) == NULL_TREE)
+ {
+ char labelname[16];
+
+ switch (ffelab_type (label))
+ {
+ case FFELAB_typeLOOPEND:
+ case FFELAB_typeNOTLOOP:
+ case FFELAB_typeENDIF:
+ sprintf (labelname, "%" ffelabValue_f "u", ffelab_value (label));
+ glabel = build_decl (LABEL_DECL, get_identifier (labelname),
+ void_type_node);
+ DECL_CONTEXT (glabel) = current_function_decl;
+ DECL_MODE (glabel) = VOIDmode;
+ break;
+
+ case FFELAB_typeFORMAT:
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ glabel = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier
+ ("__g77_format_%d", NULL,
+ (int) ffelab_value (label)),
+ build_type_variant (build_array_type
+ (char_type_node,
+ NULL_TREE),
+ 1, 0));
+ TREE_CONSTANT (glabel) = 1;
+ TREE_STATIC (glabel) = 1;
+ DECL_CONTEXT (glabel) = 0;
+ DECL_INITIAL (glabel) = NULL;
+ make_decl_rtl (glabel, NULL, 0);
+ expand_decl (glabel);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ break;
+
+ case FFELAB_typeANY:
+ glabel = error_mark_node;
+ break;
+
+ default:
+ assert ("bad label type" == NULL);
+ glabel = NULL;
+ break;
+ }
+ ffelab_set_hook (label, glabel);
+ }
+ else
+ {
+ glabel = ffelab_hook (label);
+ }
+
+ return glabel;
+}
+
+#endif
+/* Stabilizes the arguments. Don't use this if the lhs and rhs come from
+ a single source specification (as in the fourth argument of MVBITS).
+ If the type is NULL_TREE, the type of lhs is used to make the type of
+ the MODIFY_EXPR. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_modify (tree newtype, tree lhs,
+ tree rhs)
+{
+ if (lhs == error_mark_node || rhs == error_mark_node)
+ return error_mark_node;
+
+ if (newtype == NULL_TREE)
+ newtype = TREE_TYPE (lhs);
+
+ if (TREE_SIDE_EFFECTS (lhs))
+ lhs = stabilize_reference (lhs);
+
+ return ffecom_2s (MODIFY_EXPR, newtype, lhs, rhs);
+}
+
+#endif
+
+/* Register source file name. */
+
+void
+ffecom_file (char *name)
+{
+#if FFECOM_GCC_INCLUDE
+ ffecom_file_ (name);
+#endif
+}
+
+/* ffecom_notify_init_storage -- An aggregate storage is now fully init'ed
+
+ ffestorag st;
+ ffecom_notify_init_storage(st);
+
+ Gets called when all possible units in an aggregate storage area (a LOCAL
+ with equivalences or a COMMON) have been initialized. The initialization
+ info either is in ffestorag_init or, if that is NULL,
+ ffestorag_accretion:
+
+ ffestorag_init may contain an opCONTER or opARRTER. opCONTER may occur
+ even for an array if the array is one element in length!
+
+ ffestorag_accretion will contain an opACCTER. It is much like an
+ opARRTER except it has an ffebit object in it instead of just a size.
+ The back end can use the info in the ffebit object, if it wants, to
+ reduce the amount of actual initialization, but in any case it should
+ kill the ffebit object when done. Also, set accretion to NULL but
+ init to a non-NULL value.
+
+ After performing initialization, DO NOT set init to NULL, because that'll
+ tell the front end it is ok for more initialization to happen. Instead,
+ set init to an opANY expression or some such thing that you can use to
+ tell that you've already initialized the object.
+
+ 27-Oct-91 JCB 1.1
+ Support two-pass FFE. */
+
+void
+ffecom_notify_init_storage (ffestorag st)
+{
+ ffebld init; /* The initialization expression. */
+#if 0 && FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffetargetOffset size; /* The size of the entity. */
+ ffetargetAlign pad; /* Its initial padding. */
+#endif
+
+ if (ffestorag_init (st) == NULL)
+ {
+ init = ffestorag_accretion (st);
+ assert (init != NULL);
+ ffestorag_set_accretion (st, NULL);
+ ffestorag_set_accretes (st, 0);
+
+#if 0 && FFECOM_targetCURRENT == FFECOM_targetGCC
+ /* For GNU backend, just turn ACCTER into ARRTER and proceed. */
+ size = ffebld_accter_size (init);
+ pad = ffebld_accter_pad (init);
+ ffebit_kill (ffebld_accter_bits (init));
+ ffebld_set_op (init, FFEBLD_opARRTER);
+ ffebld_set_arrter (init, ffebld_accter (init));
+ ffebld_arrter_set_size (init, size);
+ ffebld_arrter_set_pad (init, size);
+#endif
+
+#if FFECOM_TWOPASS
+ ffestorag_set_init (st, init);
+#endif
+ }
+#if FFECOM_ONEPASS
+ else
+ init = ffestorag_init (st);
+#endif
+
+#if FFECOM_ONEPASS /* Process the inits, wipe 'em out. */
+ ffestorag_set_init (st, ffebld_new_any ());
+
+ if (ffebld_op (init) == FFEBLD_opANY)
+ return; /* Oh, we already did this! */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ {
+ ffesymbol s;
+
+ if (ffestorag_symbol (st) != NULL)
+ s = ffestorag_symbol (st);
+ else
+ s = ffestorag_typesymbol (st);
+
+ fprintf (dmpout, "= initialize_storage \"%s\" ",
+ (s != NULL) ? ffesymbol_text (s) : "(unnamed)");
+ ffebld_dump (init);
+ fputc ('\n', dmpout);
+ }
+#endif
+
+#endif /* if FFECOM_ONEPASS */
+}
+
+/* ffecom_notify_init_symbol -- A symbol is now fully init'ed
+
+ ffesymbol s;
+ ffecom_notify_init_symbol(s);
+
+ Gets called when all possible units in a symbol (not placed in COMMON
+ or involved in EQUIVALENCE, unless it as yet has no ffestorag object)
+ have been initialized. The initialization info either is in
+ ffesymbol_init or, if that is NULL, ffesymbol_accretion:
+
+ ffesymbol_init may contain an opCONTER or opARRTER. opCONTER may occur
+ even for an array if the array is one element in length!
+
+ ffesymbol_accretion will contain an opACCTER. It is much like an
+ opARRTER except it has an ffebit object in it instead of just a size.
+ The back end can use the info in the ffebit object, if it wants, to
+ reduce the amount of actual initialization, but in any case it should
+ kill the ffebit object when done. Also, set accretion to NULL but
+ init to a non-NULL value.
+
+ After performing initialization, DO NOT set init to NULL, because that'll
+ tell the front end it is ok for more initialization to happen. Instead,
+ set init to an opANY expression or some such thing that you can use to
+ tell that you've already initialized the object.
+
+ 27-Oct-91 JCB 1.1
+ Support two-pass FFE. */
+
+void
+ffecom_notify_init_symbol (ffesymbol s)
+{
+ ffebld init; /* The initialization expression. */
+#if 0 && FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffetargetOffset size; /* The size of the entity. */
+ ffetargetAlign pad; /* Its initial padding. */
+#endif
+
+ if (ffesymbol_storage (s) == NULL)
+ return; /* Do nothing until COMMON/EQUIVALENCE
+ possibilities checked. */
+
+ if ((ffesymbol_init (s) == NULL)
+ && ((init = ffesymbol_accretion (s)) != NULL))
+ {
+ ffesymbol_set_accretion (s, NULL);
+ ffesymbol_set_accretes (s, 0);
+
+#if 0 && FFECOM_targetCURRENT == FFECOM_targetGCC
+ /* For GNU backend, just turn ACCTER into ARRTER and proceed. */
+ size = ffebld_accter_size (init);
+ pad = ffebld_accter_pad (init);
+ ffebit_kill (ffebld_accter_bits (init));
+ ffebld_set_op (init, FFEBLD_opARRTER);
+ ffebld_set_arrter (init, ffebld_accter (init));
+ ffebld_arrter_set_size (init, size);
+ ffebld_arrter_set_pad (init, size);
+#endif
+
+#if FFECOM_TWOPASS
+ ffesymbol_set_init (s, init);
+#endif
+ }
+#if FFECOM_ONEPASS
+ else
+ init = ffesymbol_init (s);
+#endif
+
+#if FFECOM_ONEPASS
+ ffesymbol_set_init (s, ffebld_new_any ());
+
+ if (ffebld_op (init) == FFEBLD_opANY)
+ return; /* Oh, we already did this! */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "= initialize_symbol \"%s\" ", ffesymbol_text (s));
+ ffebld_dump (init);
+ fputc ('\n', dmpout);
+#endif
+
+#endif /* if FFECOM_ONEPASS */
+}
+
+/* ffecom_notify_primary_entry -- Learn which is the primary entry point
+
+ ffesymbol s;
+ ffecom_notify_primary_entry(s);
+
+ Gets called when implicit or explicit PROGRAM statement seen or when
+ FUNCTION, SUBROUTINE, or BLOCK DATA statement seen, with the primary
+ global symbol that serves as the entry point. */
+
+void
+ffecom_notify_primary_entry (ffesymbol s)
+{
+ ffecom_primary_entry_ = s;
+ ffecom_primary_entry_kind_ = ffesymbol_kind (s);
+
+ if ((ffecom_primary_entry_kind_ == FFEINFO_kindFUNCTION)
+ || (ffecom_primary_entry_kind_ == FFEINFO_kindSUBROUTINE))
+ ffecom_primary_entry_is_proc_ = TRUE;
+ else
+ ffecom_primary_entry_is_proc_ = FALSE;
+
+ if (!ffe_is_silent ())
+ {
+ if (ffecom_primary_entry_kind_ == FFEINFO_kindPROGRAM)
+ fprintf (stderr, "%s:\n", ffesymbol_text (s));
+ else
+ fprintf (stderr, " %s:\n", ffesymbol_text (s));
+ }
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ if (ffecom_primary_entry_kind_ == FFEINFO_kindSUBROUTINE)
+ {
+ ffebld list;
+ ffebld arg;
+
+ for (list = ffesymbol_dummyargs (s);
+ list != NULL;
+ list = ffebld_trail (list))
+ {
+ arg = ffebld_head (list);
+ if (ffebld_op (arg) == FFEBLD_opSTAR)
+ {
+ ffecom_is_altreturning_ = TRUE;
+ break;
+ }
+ }
+ }
+#endif
+}
+
+FILE *
+ffecom_open_include (char *name, ffewhereLine l, ffewhereColumn c)
+{
+#if FFECOM_GCC_INCLUDE
+ return ffecom_open_include_ (name, l, c);
+#else
+ return fopen (name, "r");
+#endif
+}
+
+/* Clean up after making automatically popped call-arg temps.
+
+ Call this in pairs with push_calltemps around calls to
+ ffecom_arg_ptr_to_expr if the latter might use temporaries.
+ Any temporaries made within the outermost sequence of
+ push_calltemps and pop_calltemps, that are marked as "auto-pop"
+ meaning they won't be explicitly popped (freed), are popped
+ at this point so they can be reused later.
+
+ NOTE: when called by ffecom_gen_sfuncdef_, ffecom_pending_calls_
+ should come in == 1, and all of the in-use auto-pop temps
+ should have DECL_CONTEXT (temp->t) == current_function_decl.
+ Moreover, these temps should _never_ be re-used in future
+ calls to ffecom_push_tempvar -- since current_function_decl will
+ never be the same again.
+
+ SO, it could be a minor win in terms of compile time to just
+ strip these temps off the list. That is, if the above assumptions
+ are correct, just remove from the list of temps any temp
+ that is both in-use and has DECL_CONTEXT (temp->t)
+ == current_function_decl, when called from ffecom_gen_sfuncdef_. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_pop_calltemps ()
+{
+ ffecomTemp_ temp;
+
+ assert (ffecom_pending_calls_ > 0);
+
+ if (--ffecom_pending_calls_ == 0)
+ for (temp = ffecom_latest_temp_; temp != NULL; temp = temp->next)
+ if (temp->auto_pop)
+ temp->in_use = FALSE;
+}
+
+#endif
+/* Mark latest temp with given tree as no longer in use. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_pop_tempvar (tree t)
+{
+ ffecomTemp_ temp;
+
+ for (temp = ffecom_latest_temp_; temp != NULL; temp = temp->next)
+ if (temp->in_use && (temp->t == t))
+ {
+ assert (!temp->auto_pop);
+ temp->in_use = FALSE;
+ return;
+ }
+ else
+ assert (temp->t != t);
+
+ assert ("couldn't ffecom_pop_tempvar!" != NULL);
+}
+
+#endif
+/* ffecom_ptr_to_expr -- Transform expr into gcc tree with & in front
+
+ tree t;
+ ffebld expr; // FFE expression.
+ tree = ffecom_ptr_to_expr(expr);
+
+ Like ffecom_expr, but sticks address-of in front of most things. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_ptr_to_expr (ffebld expr)
+{
+ tree item;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffesymbol s;
+
+ assert (expr != NULL);
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opSYMTER:
+ s = ffebld_symter (expr);
+ if (ffesymbol_where (s) == FFEINFO_whereINTRINSIC)
+ {
+ ffecomGfrt ix;
+
+ ix = ffeintrin_gfrt_indirect (ffebld_symter_implementation (expr));
+ assert (ix != FFECOM_gfrt);
+ if ((item = ffecom_gfrt_[ix]) == NULL_TREE)
+ {
+ ffecom_make_gfrt_ (ix);
+ item = ffecom_gfrt_[ix];
+ }
+ }
+ else
+ {
+ item = ffesymbol_hook (s).decl_tree;
+ if (item == NULL_TREE)
+ {
+ s = ffecom_sym_transform_ (s);
+ item = ffesymbol_hook (s).decl_tree;
+ }
+ }
+ assert (item != NULL);
+ if (item == error_mark_node)
+ return item;
+ if (!ffesymbol_hook (s).addr)
+ item = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (item)),
+ item);
+ return item;
+
+ case FFEBLD_opARRAYREF:
+ {
+ ffebld dims[FFECOM_dimensionsMAX];
+ tree array;
+ int i;
+
+ item = ffecom_ptr_to_expr (ffebld_left (expr));
+
+ if (item == error_mark_node)
+ return item;
+
+ if ((ffeinfo_where (ffebld_info (expr)) == FFEINFO_whereFLEETING)
+ && !mark_addressable (item))
+ return error_mark_node; /* Make sure non-const ref is to
+ non-reg. */
+
+ /* Build up ARRAY_REFs in reverse order (since we're column major
+ here in Fortran land). */
+
+ for (i = 0, expr = ffebld_right (expr);
+ expr != NULL;
+ expr = ffebld_trail (expr))
+ dims[i++] = ffebld_head (expr);
+
+ for (--i, array = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (item)));
+ i >= 0;
+ --i, array = TYPE_MAIN_VARIANT (TREE_TYPE (array)))
+ {
+ /* The initial subtraction should happen in the original type so
+ that (possible) negative values are handled appropriately. */
+ item
+ = ffecom_2 (PLUS_EXPR,
+ build_pointer_type (TREE_TYPE (array)),
+ item,
+ size_binop (MULT_EXPR,
+ size_in_bytes (TREE_TYPE (array)),
+ convert (sizetype,
+ fold (build (MINUS_EXPR,
+ TREE_TYPE (TYPE_MIN_VALUE (TYPE_DOMAIN (array))),
+ ffecom_expr (dims[i]),
+ TYPE_MIN_VALUE (TYPE_DOMAIN (array)))))));
+ }
+ }
+ return item;
+
+ case FFEBLD_opCONTER:
+
+ bt = ffeinfo_basictype (ffebld_info (expr));
+ kt = ffeinfo_kindtype (ffebld_info (expr));
+
+ item = ffecom_constantunion (&ffebld_constant_union
+ (ffebld_conter (expr)), bt, kt,
+ ffecom_tree_type[bt][kt]);
+ if (item == error_mark_node)
+ return error_mark_node;
+ item = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (item)),
+ item);
+ return item;
+
+ case FFEBLD_opANY:
+ return error_mark_node;
+
+ default:
+ assert (ffecom_pending_calls_ > 0);
+
+ bt = ffeinfo_basictype (ffebld_info (expr));
+ kt = ffeinfo_kindtype (ffebld_info (expr));
+
+ item = ffecom_expr (expr);
+ if (item == error_mark_node)
+ return error_mark_node;
+
+ /* The back end currently optimizes a bit too zealously for us, in that
+ we fail JCB001 if the following block of code is omitted. It checks
+ to see if the transformed expression is a symbol or array reference,
+ and encloses it in a SAVE_EXPR if that is the case. */
+
+ STRIP_NOPS (item);
+ if ((TREE_CODE (item) == VAR_DECL)
+ || (TREE_CODE (item) == PARM_DECL)
+ || (TREE_CODE (item) == RESULT_DECL)
+ || (TREE_CODE (item) == INDIRECT_REF)
+ || (TREE_CODE (item) == ARRAY_REF)
+ || (TREE_CODE (item) == COMPONENT_REF)
+#ifdef OFFSET_REF
+ || (TREE_CODE (item) == OFFSET_REF)
+#endif
+ || (TREE_CODE (item) == BUFFER_REF)
+ || (TREE_CODE (item) == REALPART_EXPR)
+ || (TREE_CODE (item) == IMAGPART_EXPR))
+ {
+ item = ffecom_save_tree (item);
+ }
+
+ item = ffecom_1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (item)),
+ item);
+ return item;
+ }
+
+ assert ("fall-through error" == NULL);
+ return error_mark_node;
+}
+
+#endif
+/* Prepare to make call-arg temps.
+
+ Call this in pairs with pop_calltemps around calls to
+ ffecom_arg_ptr_to_expr if the latter might use temporaries. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_push_calltemps ()
+{
+ ffecom_pending_calls_++;
+}
+
+#endif
+/* Obtain a temp var with given data type.
+
+ Returns a VAR_DECL tree of a currently (that is, at the current
+ statement being compiled) not in use and having the given data type,
+ making a new one if necessary. size is FFETARGET_charactersizeNONE
+ for a non-CHARACTER type or >= 0 for a CHARACTER type. elements is
+ -1 for a scalar or > 0 for an array of type. auto_pop is TRUE if
+ ffecom_pop_tempvar won't be called, meaning temp will be freed
+ when #pending calls goes to zero. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_push_tempvar (tree type, ffetargetCharacterSize size, int elements,
+ bool auto_pop)
+{
+ ffecomTemp_ temp;
+ int yes;
+ tree t;
+ static int mynumber;
+
+ assert (!auto_pop || (ffecom_pending_calls_ > 0));
+
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ for (temp = ffecom_latest_temp_; temp != NULL; temp = temp->next)
+ {
+ if (temp->in_use
+ || (temp->type != type)
+ || (temp->size != size)
+ || (temp->elements != elements)
+ || (DECL_CONTEXT (temp->t) != current_function_decl))
+ continue;
+
+ temp->in_use = TRUE;
+ temp->auto_pop = auto_pop;
+ return temp->t;
+ }
+
+ /* Create a new temp. */
+
+ yes = suspend_momentary ();
+
+ if (size != FFETARGET_charactersizeNONE)
+ type = build_array_type (type,
+ build_range_type (ffecom_f2c_ftnlen_type_node,
+ ffecom_f2c_ftnlen_one_node,
+ build_int_2 (size, 0)));
+ if (elements != -1)
+ type = build_array_type (type,
+ build_range_type (integer_type_node,
+ integer_zero_node,
+ build_int_2 (elements - 1,
+ 0)));
+ t = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_expr_%d", NULL,
+ mynumber++),
+ type);
+
+ /* This temp must be put in the same scope as the containing BLOCK
+ (aka function), but for reasons that should be explained elsewhere,
+ the GBE normally decides it should be in a "phantom BLOCK" associated
+ with the expand_start_stmt_expr() call. So push the topmost
+ sequence back onto the GBE's internal stack before telling it
+ about the decl, then restore it afterwards. */
+ push_topmost_sequence ();
+
+ t = start_decl (t, FALSE);
+ finish_decl (t, NULL_TREE, FALSE);
+
+ pop_topmost_sequence ();
+
+ resume_momentary (yes);
+
+ temp = malloc_new_kp (ffe_pool_program_unit (), "ffecomTemp_",
+ sizeof (*temp));
+
+ temp->next = ffecom_latest_temp_;
+ temp->type = type;
+ temp->t = t;
+ temp->size = size;
+ temp->elements = elements;
+ temp->in_use = TRUE;
+ temp->auto_pop = auto_pop;
+
+ ffecom_latest_temp_ = temp;
+
+ return t;
+}
+
+#endif
+/* ffecom_return_expr -- Returns return-value expr given alt return expr
+
+ tree rtn; // NULL_TREE means use expand_null_return()
+ ffebld expr; // NULL if no alt return expr to RETURN stmt
+ rtn = ffecom_return_expr(expr);
+
+ Based on the program unit type and other info (like return function
+ type, return master function type when alternate ENTRY points,
+ whether subroutine has any alternate RETURN points, etc), returns the
+ appropriate expression to be returned to the caller, or NULL_TREE
+ meaning no return value or the caller expects it to be returned somewhere
+ else (which is handled by other parts of this module). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_return_expr (ffebld expr)
+{
+ tree rtn;
+
+ switch (ffecom_primary_entry_kind_)
+ {
+ case FFEINFO_kindPROGRAM:
+ case FFEINFO_kindBLOCKDATA:
+ rtn = NULL_TREE;
+ break;
+
+ case FFEINFO_kindSUBROUTINE:
+ if (!ffecom_is_altreturning_)
+ rtn = NULL_TREE; /* No alt returns, never an expr. */
+ else if (expr == NULL)
+ rtn = integer_zero_node;
+ else
+ rtn = ffecom_expr (expr);
+ break;
+
+ case FFEINFO_kindFUNCTION:
+ if ((ffecom_multi_retval_ != NULL_TREE)
+ || (ffesymbol_basictype (ffecom_primary_entry_)
+ == FFEINFO_basictypeCHARACTER)
+ || ((ffesymbol_basictype (ffecom_primary_entry_)
+ == FFEINFO_basictypeCOMPLEX)
+ && (ffecom_num_entrypoints_ == 0)
+ && ffesymbol_is_f2c (ffecom_primary_entry_)))
+ { /* Value is returned by direct assignment
+ into (implicit) dummy. */
+ rtn = NULL_TREE;
+ break;
+ }
+ rtn = ffecom_func_result_;
+#if 0
+ /* Spurious error if RETURN happens before first reference! So elide
+ this code. In particular, for debugging registry, rtn should always
+ be non-null after all, but TREE_USED won't be set until we encounter
+ a reference in the code. Perfectly okay (but weird) code that,
+ e.g., has "GOTO 20;10 RETURN;20 RTN=0;GOTO 10", would result in
+ this diagnostic for no reason. Have people use -O -Wuninitialized
+ and leave it to the back end to find obviously weird cases. */
+
+ /* Used to "assert(rtn != NULL_TREE);" here, but it's kind of a valid
+ situation; if the return value has never been referenced, it won't
+ have a tree under 2pass mode. */
+ if ((rtn == NULL_TREE)
+ || !TREE_USED (rtn))
+ {
+ ffebad_start (FFEBAD_RETURN_VALUE_UNSET);
+ ffebad_here (0, ffesymbol_where_line (ffecom_primary_entry_),
+ ffesymbol_where_column (ffecom_primary_entry_));
+ ffebad_string (ffesymbol_text (ffesymbol_funcresult
+ (ffecom_primary_entry_)));
+ ffebad_finish ();
+ }
+#endif
+ break;
+
+ default:
+ assert ("bad unit kind" == NULL);
+ case FFEINFO_kindANY:
+ rtn = error_mark_node;
+ break;
+ }
+
+ return rtn;
+}
+
+#endif
+/* Do save_expr only if tree is not error_mark_node. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_save_tree (tree t)
+{
+ return save_expr (t);
+}
+#endif
+
+/* Public entry point for front end to access start_decl. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_start_decl (tree decl, bool is_initialized)
+{
+ DECL_INITIAL (decl) = is_initialized ? error_mark_node : NULL_TREE;
+ return start_decl (decl, FALSE);
+}
+
+#endif
+/* ffecom_sym_commit -- Symbol's state being committed to reality
+
+ ffesymbol s;
+ ffecom_sym_commit(s);
+
+ Does whatever the backend needs when a symbol is committed after having
+ been backtrackable for a period of time. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_sym_commit (ffesymbol s UNUSED)
+{
+ assert (!ffesymbol_retractable ());
+}
+
+#endif
+/* ffecom_sym_end_transition -- Perform end transition on all symbols
+
+ ffecom_sym_end_transition();
+
+ Does backend-specific stuff and also calls ffest_sym_end_transition
+ to do the necessary FFE stuff.
+
+ Backtracking is never enabled when this fn is called, so don't worry
+ about it. */
+
+ffesymbol
+ffecom_sym_end_transition (ffesymbol s)
+{
+ ffestorag st;
+
+ assert (!ffesymbol_retractable ());
+
+ s = ffest_sym_end_transition (s);
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ if ((ffesymbol_kind (s) == FFEINFO_kindBLOCKDATA)
+ && (ffesymbol_where (s) == FFEINFO_whereGLOBAL))
+ {
+ ffecom_list_blockdata_
+ = ffebld_new_item (ffebld_new_symter (s, FFEINTRIN_genNONE,
+ FFEINTRIN_specNONE,
+ FFEINTRIN_impNONE),
+ ffecom_list_blockdata_);
+ }
+#endif
+
+ /* This is where we finally notice that a symbol has partial initialization
+ and finalize it. */
+
+ if (ffesymbol_accretion (s) != NULL)
+ {
+ assert (ffesymbol_init (s) == NULL);
+ ffecom_notify_init_symbol (s);
+ }
+ else if (((st = ffesymbol_storage (s)) != NULL)
+ && ((st = ffestorag_parent (st)) != NULL)
+ && (ffestorag_accretion (st) != NULL))
+ {
+ assert (ffestorag_init (st) == NULL);
+ ffecom_notify_init_storage (st);
+ }
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ if ((ffesymbol_kind (s) == FFEINFO_kindCOMMON)
+ && (ffesymbol_where (s) == FFEINFO_whereLOCAL)
+ && (ffesymbol_storage (s) != NULL))
+ {
+ ffecom_list_common_
+ = ffebld_new_item (ffebld_new_symter (s, FFEINTRIN_genNONE,
+ FFEINTRIN_specNONE,
+ FFEINTRIN_impNONE),
+ ffecom_list_common_);
+ }
+#endif
+
+ return s;
+}
+
+/* ffecom_sym_exec_transition -- Perform exec transition on all symbols
+
+ ffecom_sym_exec_transition();
+
+ Does backend-specific stuff and also calls ffest_sym_exec_transition
+ to do the necessary FFE stuff.
+
+ See the long-winded description in ffecom_sym_learned for info
+ on handling the situation where backtracking is inhibited. */
+
+ffesymbol
+ffecom_sym_exec_transition (ffesymbol s)
+{
+ s = ffest_sym_exec_transition (s);
+
+ return s;
+}
+
+/* ffecom_sym_learned -- Initial or more info gained on symbol after exec
+
+ ffesymbol s;
+ s = ffecom_sym_learned(s);
+
+ Called when a new symbol is seen after the exec transition or when more
+ info (perhaps) is gained for an UNCERTAIN symbol. The symbol state when
+ it arrives here is that all its latest info is updated already, so its
+ state may be UNCERTAIN or UNDERSTOOD, it might already have the hook
+ field filled in if its gone through here or exec_transition first, and
+ so on.
+
+ The backend probably wants to check ffesymbol_retractable() to see if
+ backtracking is in effect. If so, the FFE's changes to the symbol may
+ be retracted (undone) or committed (ratified), at which time the
+ appropriate ffecom_sym_retract or _commit function will be called
+ for that function.
+
+ If the backend has its own backtracking mechanism, great, use it so that
+ committal is a simple operation. Though it doesn't make much difference,
+ I suppose: the reason for tentative symbol evolution in the FFE is to
+ enable error detection in weird incorrect statements early and to disable
+ incorrect error detection on a correct statement. The backend is not
+ likely to introduce any information that'll get involved in these
+ considerations, so it is probably just fine that the implementation
+ model for this fn and for _exec_transition is to not do anything
+ (besides the required FFE stuff) if ffesymbol_retractable() returns TRUE
+ and instead wait until ffecom_sym_commit is called (which it never
+ will be as long as we're using ambiguity-detecting statement analysis in
+ the FFE, which we are initially to shake out the code, but don't depend
+ on this), otherwise go ahead and do whatever is needed.
+
+ In essence, then, when this fn and _exec_transition get called while
+ backtracking is enabled, a general mechanism would be to flag which (or
+ both) of these were called (and in what order? neat question as to what
+ might happen that I'm too lame to think through right now) and then when
+ _commit is called reproduce the original calling sequence, if any, for
+ the two fns (at which point backtracking will, of course, be disabled). */
+
+ffesymbol
+ffecom_sym_learned (ffesymbol s)
+{
+ ffestorag_exec_layout (s);
+
+ return s;
+}
+
+/* ffecom_sym_retract -- Symbol's state being retracted from reality
+
+ ffesymbol s;
+ ffecom_sym_retract(s);
+
+ Does whatever the backend needs when a symbol is retracted after having
+ been backtrackable for a period of time. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffecom_sym_retract (ffesymbol s UNUSED)
+{
+ assert (!ffesymbol_retractable ());
+
+#if 0 /* GCC doesn't commit any backtrackable sins,
+ so nothing needed here. */
+ switch (ffesymbol_hook (s).state)
+ {
+ case 0: /* nothing happened yet. */
+ break;
+
+ case 1: /* exec transition happened. */
+ break;
+
+ case 2: /* learned happened. */
+ break;
+
+ case 3: /* learned then exec. */
+ break;
+
+ case 4: /* exec then learned. */
+ break;
+
+ default:
+ assert ("bad hook state" == NULL);
+ break;
+ }
+#endif
+}
+
+#endif
+/* Create temporary gcc label. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_temp_label ()
+{
+ tree glabel;
+ static int mynumber = 0;
+
+ glabel = build_decl (LABEL_DECL,
+ ffecom_get_invented_identifier ("__g77_label_%d",
+ NULL,
+ mynumber++),
+ void_type_node);
+ DECL_CONTEXT (glabel) = current_function_decl;
+ DECL_MODE (glabel) = VOIDmode;
+
+ return glabel;
+}
+
+#endif
+/* Return an expression that is usable as an arg in a conditional context
+ (IF, DO WHILE, .NOT., and so on).
+
+ Use the one provided for the back end as of >2.6.0. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_truth_value (tree expr)
+{
+ return truthvalue_conversion (expr);
+}
+
+#endif
+/* Return the inversion of a truth value (the inversion of what
+ ffecom_truth_value builds).
+
+ Apparently invert_truthvalue, which is properly in the back end, is
+ enough for now, so just use it. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_truth_value_invert (tree expr)
+{
+ return invert_truthvalue (ffecom_truth_value (expr));
+}
+
+#endif
+/* Return PARM_DECL for arg#1 of master fn containing alternate ENTRY points
+
+ If the PARM_DECL already exists, return it, else create it. It's an
+ integer_type_node argument for the master function that implements a
+ subroutine or function with more than one entrypoint and is bound at
+ run time with the entrypoint number (0 for SUBROUTINE/FUNCTION, 1 for
+ first ENTRY statement, and so on). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree
+ffecom_which_entrypoint_decl ()
+{
+ assert (ffecom_which_entrypoint_decl_ != NULL_TREE);
+
+ return ffecom_which_entrypoint_decl_;
+}
+
+#endif
+
+/* The following sections consists of private and public functions
+ that have the same names and perform roughly the same functions
+ as counterparts in the C front end. Changes in the C front end
+ might affect how things should be done here. Only functions
+ needed by the back end should be public here; the rest should
+ be private (static in the C sense). Functions needed by other
+ g77 front-end modules should be accessed by them via public
+ ffecom_* names, which should themselves call private versions
+ in this section so the private versions are easy to recognize
+ when upgrading to a new gcc and finding interesting changes
+ in the front end.
+
+ Functions named after rule "foo:" in c-parse.y are named
+ "bison_rule_foo_" so they are easy to find. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+
+static void
+bison_rule_compstmt_ ()
+{
+ emit_line_note (input_filename, lineno);
+ expand_end_bindings (getdecls (), 1, 1);
+ poplevel (1, 1, 0);
+ pop_momentary ();
+}
+
+static void
+bison_rule_pushlevel_ ()
+{
+ emit_line_note (input_filename, lineno);
+ pushlevel (0);
+ clear_last_expr ();
+ push_momentary ();
+ expand_start_bindings (0);
+}
+
+/* Return a definition for a builtin function named NAME and whose data type
+ is TYPE. TYPE should be a function type with argument types.
+ FUNCTION_CODE tells later passes how to compile calls to this function.
+ See tree.h for its possible values.
+
+ If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
+ the name to be called if we can't opencode the function. */
+
+static tree
+builtin_function (char *name, tree type,
+ enum built_in_function function_code, char *library_name)
+{
+ tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type);
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ if (library_name)
+ DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name);
+ make_decl_rtl (decl, NULL_PTR, 1);
+ pushdecl (decl);
+ if (function_code != NOT_BUILT_IN)
+ {
+ DECL_BUILT_IN (decl) = 1;
+ DECL_FUNCTION_CODE (decl) = function_code;
+ }
+
+ return decl;
+}
+
+/* Handle when a new declaration NEWDECL
+ has the same name as an old one OLDDECL
+ in the same binding contour.
+ Prints an error message if appropriate.
+
+ If safely possible, alter OLDDECL to look like NEWDECL, and return 1.
+ Otherwise, return 0. */
+
+static int
+duplicate_decls (tree newdecl, tree olddecl)
+{
+ int types_match = 1;
+ int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
+ && DECL_INITIAL (newdecl) != 0);
+ tree oldtype = TREE_TYPE (olddecl);
+ tree newtype = TREE_TYPE (newdecl);
+
+ if (olddecl == newdecl)
+ return 1;
+
+ if (TREE_CODE (newtype) == ERROR_MARK
+ || TREE_CODE (oldtype) == ERROR_MARK)
+ types_match = 0;
+
+ /* New decl is completely inconsistent with the old one =>
+ tell caller to replace the old one.
+ This is always an error except in the case of shadowing a builtin. */
+ if (TREE_CODE (olddecl) != TREE_CODE (newdecl))
+ return 0;
+
+ /* For real parm decl following a forward decl,
+ return 1 so old decl will be reused. */
+ if (types_match && TREE_CODE (newdecl) == PARM_DECL
+ && TREE_ASM_WRITTEN (olddecl) && ! TREE_ASM_WRITTEN (newdecl))
+ return 1;
+
+ /* The new declaration is the same kind of object as the old one.
+ The declarations may partially match. Print warnings if they don't
+ match enough. Ultimately, copy most of the information from the new
+ decl to the old one, and keep using the old one. */
+
+ if (TREE_CODE (olddecl) == FUNCTION_DECL
+ && DECL_BUILT_IN (olddecl))
+ {
+ /* A function declaration for a built-in function. */
+ if (!TREE_PUBLIC (newdecl))
+ return 0;
+ else if (!types_match)
+ {
+ /* Accept the return type of the new declaration if same modes. */
+ tree oldreturntype = TREE_TYPE (TREE_TYPE (olddecl));
+ tree newreturntype = TREE_TYPE (TREE_TYPE (newdecl));
+
+ /* Make sure we put the new type in the same obstack as the old ones.
+ If the old types are not both in the same obstack, use the
+ permanent one. */
+ if (TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype))
+ push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype));
+ else
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ }
+
+ if (TYPE_MODE (oldreturntype) == TYPE_MODE (newreturntype))
+ {
+ /* Function types may be shared, so we can't just modify
+ the return type of olddecl's function type. */
+ tree newtype
+ = build_function_type (newreturntype,
+ TYPE_ARG_TYPES (TREE_TYPE (olddecl)));
+
+ types_match = 1;
+ if (types_match)
+ TREE_TYPE (olddecl) = newtype;
+ }
+
+ pop_obstacks ();
+ }
+ if (!types_match)
+ return 0;
+ }
+ else if (TREE_CODE (olddecl) == FUNCTION_DECL
+ && DECL_SOURCE_LINE (olddecl) == 0)
+ {
+ /* A function declaration for a predeclared function
+ that isn't actually built in. */
+ if (!TREE_PUBLIC (newdecl))
+ return 0;
+ else if (!types_match)
+ {
+ /* If the types don't match, preserve volatility indication.
+ Later on, we will discard everything else about the
+ default declaration. */
+ TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+ }
+ }
+
+ /* Copy all the DECL_... slots specified in the new decl
+ except for any that we copy here from the old type.
+
+ Past this point, we don't change OLDTYPE and NEWTYPE
+ even if we change the types of NEWDECL and OLDDECL. */
+
+ if (types_match)
+ {
+ /* Make sure we put the new type in the same obstack as the old ones.
+ If the old types are not both in the same obstack, use the permanent
+ one. */
+ if (TYPE_OBSTACK (oldtype) == TYPE_OBSTACK (newtype))
+ push_obstacks (TYPE_OBSTACK (oldtype), TYPE_OBSTACK (oldtype));
+ else
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ }
+
+ /* Merge the data types specified in the two decls. */
+ if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
+ TREE_TYPE (newdecl)
+ = TREE_TYPE (olddecl)
+ = TREE_TYPE (newdecl);
+
+ /* Lay the type out, unless already done. */
+ if (oldtype != TREE_TYPE (newdecl))
+ {
+ if (TREE_TYPE (newdecl) != error_mark_node)
+ layout_type (TREE_TYPE (newdecl));
+ if (TREE_CODE (newdecl) != FUNCTION_DECL
+ && TREE_CODE (newdecl) != TYPE_DECL
+ && TREE_CODE (newdecl) != CONST_DECL)
+ layout_decl (newdecl, 0);
+ }
+ else
+ {
+ /* Since the type is OLDDECL's, make OLDDECL's size go with. */
+ DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
+ if (TREE_CODE (olddecl) != FUNCTION_DECL)
+ if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
+ DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
+ }
+
+ /* Keep the old rtl since we can safely use it. */
+ DECL_RTL (newdecl) = DECL_RTL (olddecl);
+
+ /* Merge the type qualifiers. */
+ if (DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl)
+ && !TREE_THIS_VOLATILE (newdecl))
+ TREE_THIS_VOLATILE (olddecl) = 0;
+ if (TREE_READONLY (newdecl))
+ TREE_READONLY (olddecl) = 1;
+ if (TREE_THIS_VOLATILE (newdecl))
+ {
+ TREE_THIS_VOLATILE (olddecl) = 1;
+ if (TREE_CODE (newdecl) == VAR_DECL)
+ make_var_volatile (newdecl);
+ }
+
+ /* Keep source location of definition rather than declaration.
+ Likewise, keep decl at outer scope. */
+ if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
+ || (DECL_CONTEXT (newdecl) != 0 && DECL_CONTEXT (olddecl) == 0))
+ {
+ DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl);
+ DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl);
+
+ if (DECL_CONTEXT (olddecl) == 0
+ && TREE_CODE (newdecl) != FUNCTION_DECL)
+ DECL_CONTEXT (newdecl) = 0;
+ }
+
+ /* Merge the unused-warning information. */
+ if (DECL_IN_SYSTEM_HEADER (olddecl))
+ DECL_IN_SYSTEM_HEADER (newdecl) = 1;
+ else if (DECL_IN_SYSTEM_HEADER (newdecl))
+ DECL_IN_SYSTEM_HEADER (olddecl) = 1;
+
+ /* Merge the initialization information. */
+ if (DECL_INITIAL (newdecl) == 0)
+ DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+
+ /* Merge the section attribute.
+ We want to issue an error if the sections conflict but that must be
+ done later in decl_attributes since we are called before attributes
+ are assigned. */
+ if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
+ DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
+
+#if BUILT_FOR_270
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
+ {
+ DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
+ DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
+ }
+#endif
+
+ pop_obstacks ();
+ }
+ /* If cannot merge, then use the new type and qualifiers,
+ and don't preserve the old rtl. */
+ else
+ {
+ TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
+ TREE_READONLY (olddecl) = TREE_READONLY (newdecl);
+ TREE_THIS_VOLATILE (olddecl) = TREE_THIS_VOLATILE (newdecl);
+ TREE_SIDE_EFFECTS (olddecl) = TREE_SIDE_EFFECTS (newdecl);
+ }
+
+ /* Merge the storage class information. */
+ /* For functions, static overrides non-static. */
+ if (TREE_CODE (newdecl) == FUNCTION_DECL)
+ {
+ TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
+ /* This is since we don't automatically
+ copy the attributes of NEWDECL into OLDDECL. */
+ TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
+ /* If this clears `static', clear it in the identifier too. */
+ if (! TREE_PUBLIC (olddecl))
+ TREE_PUBLIC (DECL_NAME (olddecl)) = 0;
+ }
+ if (DECL_EXTERNAL (newdecl))
+ {
+ TREE_STATIC (newdecl) = TREE_STATIC (olddecl);
+ DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl);
+ /* An extern decl does not override previous storage class. */
+ TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
+ }
+ else
+ {
+ TREE_STATIC (olddecl) = TREE_STATIC (newdecl);
+ TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
+ }
+
+ /* If either decl says `inline', this fn is inline,
+ unless its definition was passed already. */
+ if (DECL_INLINE (newdecl) && DECL_INITIAL (olddecl) == 0)
+ DECL_INLINE (olddecl) = 1;
+ DECL_INLINE (newdecl) = DECL_INLINE (olddecl);
+
+ /* Get rid of any built-in function if new arg types don't match it
+ or if we have a function definition. */
+ if (TREE_CODE (newdecl) == FUNCTION_DECL
+ && DECL_BUILT_IN (olddecl)
+ && (!types_match || new_is_definition))
+ {
+ TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
+ DECL_BUILT_IN (olddecl) = 0;
+ }
+
+ /* If redeclaring a builtin function, and not a definition,
+ it stays built in.
+ Also preserve various other info from the definition. */
+ if (TREE_CODE (newdecl) == FUNCTION_DECL && !new_is_definition)
+ {
+ if (DECL_BUILT_IN (olddecl))
+ {
+ DECL_BUILT_IN (newdecl) = 1;
+ DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+ }
+ else
+ DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl);
+
+ DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
+ DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+ DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
+ DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+ }
+
+ /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
+ But preserve olddecl's DECL_UID. */
+ {
+ register unsigned olddecl_uid = DECL_UID (olddecl);
+
+ memcpy ((char *) olddecl + sizeof (struct tree_common),
+ (char *) newdecl + sizeof (struct tree_common),
+ sizeof (struct tree_decl) - sizeof (struct tree_common));
+ DECL_UID (olddecl) = olddecl_uid;
+ }
+
+ return 1;
+}
+
+/* Finish processing of a declaration;
+ install its initial value.
+ If the length of an array type is not known before,
+ it must be determined now, from the initial value, or it is an error. */
+
+static void
+finish_decl (tree decl, tree init, bool is_top_level)
+{
+ register tree type = TREE_TYPE (decl);
+ int was_incomplete = (DECL_SIZE (decl) == 0);
+ int temporary = allocation_temporary_p ();
+ bool at_top_level = (current_binding_level == global_binding_level);
+ bool top_level = is_top_level || at_top_level;
+
+ /* Caller should pass TRUE for is_top_level only if we wouldn't be at top
+ level anyway. */
+ assert (!is_top_level || !at_top_level);
+
+ if (TREE_CODE (decl) == PARM_DECL)
+ assert (init == NULL_TREE);
+ /* Remember that PARM_DECL doesn't have a DECL_INITIAL field per se -- it
+ overlaps DECL_ARG_TYPE. */
+ else if (init == NULL_TREE)
+ assert (DECL_INITIAL (decl) == NULL_TREE);
+ else
+ assert (DECL_INITIAL (decl) == error_mark_node);
+
+ if (init != NULL_TREE)
+ {
+ if (TREE_CODE (decl) != TYPE_DECL)
+ DECL_INITIAL (decl) = init;
+ else
+ {
+ /* typedef foo = bar; store the type of bar as the type of foo. */
+ TREE_TYPE (decl) = TREE_TYPE (init);
+ DECL_INITIAL (decl) = init = 0;
+ }
+ }
+
+ /* Pop back to the obstack that is current for this binding level. This is
+ because MAXINDEX, rtl, etc. to be made below must go in the permanent
+ obstack. But don't discard the temporary data yet. */
+ pop_obstacks ();
+
+ /* Deduce size of array from initialization, if not already known */
+
+ if (TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_DOMAIN (type) == 0
+ && TREE_CODE (decl) != TYPE_DECL)
+ {
+ assert (top_level);
+ assert (was_incomplete);
+
+ layout_decl (decl, 0);
+ }
+
+ if (TREE_CODE (decl) == VAR_DECL)
+ {
+ if (DECL_SIZE (decl) == NULL_TREE
+ && TYPE_SIZE (TREE_TYPE (decl)) != NULL_TREE)
+ layout_decl (decl, 0);
+
+ if (DECL_SIZE (decl) == NULL_TREE
+ && (TREE_STATIC (decl)
+ ?
+ /* A static variable with an incomplete type is an error if it is
+ initialized. Also if it is not file scope. Otherwise, let it
+ through, but if it is not `extern' then it may cause an error
+ message later. */
+ (DECL_INITIAL (decl) != 0 || DECL_CONTEXT (decl) != 0)
+ :
+ /* An automatic variable with an incomplete type is an error. */
+ !DECL_EXTERNAL (decl)))
+ {
+ assert ("storage size not known" == NULL);
+ abort ();
+ }
+
+ if ((DECL_EXTERNAL (decl) || TREE_STATIC (decl))
+ && (DECL_SIZE (decl) != 0)
+ && (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST))
+ {
+ assert ("storage size not constant" == NULL);
+ abort ();
+ }
+ }
+
+ /* Output the assembler code and/or RTL code for variables and functions,
+ unless the type is an undefined structure or union. If not, it will get
+ done when the type is completed. */
+
+ if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ rest_of_decl_compilation (decl, NULL,
+ DECL_CONTEXT (decl) == 0,
+ 0);
+
+ if (DECL_CONTEXT (decl) != 0)
+ {
+ /* Recompute the RTL of a local array now if it used to be an
+ incomplete type. */
+ if (was_incomplete
+ && !TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+ {
+ /* If we used it already as memory, it must stay in memory. */
+ TREE_ADDRESSABLE (decl) = TREE_USED (decl);
+ /* If it's still incomplete now, no init will save it. */
+ if (DECL_SIZE (decl) == 0)
+ DECL_INITIAL (decl) = 0;
+ expand_decl (decl);
+ }
+ /* Compute and store the initial value. */
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ expand_decl_init (decl);
+ }
+ }
+ else if (TREE_CODE (decl) == TYPE_DECL)
+ {
+ rest_of_decl_compilation (decl, NULL_PTR,
+ DECL_CONTEXT (decl) == 0,
+ 0);
+ }
+
+ /* This test used to include TREE_PERMANENT, however, we have the same
+ problem with initializers at the function level. Such initializers get
+ saved until the end of the function on the momentary_obstack. */
+ if (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_INLINE (decl))
+ && temporary
+ /* DECL_INITIAL is not defined in PARM_DECLs, since it shares space with
+ DECL_ARG_TYPE. */
+ && TREE_CODE (decl) != PARM_DECL)
+ {
+ /* We need to remember that this array HAD an initialization, but
+ discard the actual temporary nodes, since we can't have a permanent
+ node keep pointing to them. */
+ /* We make an exception for inline functions, since it's normal for a
+ local extern redeclaration of an inline function to have a copy of
+ the top-level decl's DECL_INLINE. */
+ if ((DECL_INITIAL (decl) != 0)
+ && (DECL_INITIAL (decl) != error_mark_node))
+ {
+ /* If this is a const variable, then preserve the
+ initializer instead of discarding it so that we can optimize
+ references to it. */
+ /* This test used to include TREE_STATIC, but this won't be set
+ for function level initializers. */
+ if (TREE_READONLY (decl))
+ {
+ preserve_initializer ();
+ /* Hack? Set the permanent bit for something that is
+ permanent, but not on the permenent obstack, so as to
+ convince output_constant_def to make its rtl on the
+ permanent obstack. */
+ TREE_PERMANENT (DECL_INITIAL (decl)) = 1;
+
+ /* The initializer and DECL must have the same (or equivalent
+ types), but if the initializer is a STRING_CST, its type
+ might not be on the right obstack, so copy the type
+ of DECL. */
+ TREE_TYPE (DECL_INITIAL (decl)) = type;
+ }
+ else
+ DECL_INITIAL (decl) = error_mark_node;
+ }
+ }
+
+ /* If requested, warn about definitions of large data objects. */
+
+ if (warn_larger_than
+ && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL)
+ && !DECL_EXTERNAL (decl))
+ {
+ register tree decl_size = DECL_SIZE (decl);
+
+ if (decl_size && TREE_CODE (decl_size) == INTEGER_CST)
+ {
+ unsigned units = TREE_INT_CST_LOW (decl_size) / BITS_PER_UNIT;
+
+ if (units > larger_than_size)
+ warning_with_decl (decl, "size of `%s' is %u bytes", units);
+ }
+ }
+
+ /* If we have gone back from temporary to permanent allocation, actually
+ free the temporary space that we no longer need. */
+ if (temporary && !allocation_temporary_p ())
+ permanent_allocation (0);
+
+ /* At the end of a declaration, throw away any variable type sizes of types
+ defined inside that declaration. There is no use computing them in the
+ following function definition. */
+ if (current_binding_level == global_binding_level)
+ get_pending_sizes ();
+}
+
+/* Finish up a function declaration and compile that function
+ all the way to assembler language output. The free the storage
+ for the function definition.
+
+ This is called after parsing the body of the function definition.
+
+ NESTED is nonzero if the function being finished is nested in another. */
+
+static void
+finish_function (int nested)
+{
+ register tree fndecl = current_function_decl;
+
+ assert (fndecl != NULL_TREE);
+ if (TREE_CODE (fndecl) != ERROR_MARK)
+ {
+ if (nested)
+ assert (DECL_CONTEXT (fndecl) != NULL_TREE);
+ else
+ assert (DECL_CONTEXT (fndecl) == NULL_TREE);
+ }
+
+/* TREE_READONLY (fndecl) = 1;
+ This caused &foo to be of type ptr-to-const-function
+ which then got a warning when stored in a ptr-to-function variable. */
+
+ poplevel (1, 0, 1);
+
+ if (TREE_CODE (fndecl) != ERROR_MARK)
+ {
+ BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
+
+ /* Must mark the RESULT_DECL as being in this function. */
+
+ DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
+
+ /* Obey `register' declarations if `setjmp' is called in this fn. */
+ /* Generate rtl for function exit. */
+ expand_function_end (input_filename, lineno, 0);
+
+ /* So we can tell if jump_optimize sets it to 1. */
+ can_reach_end = 0;
+
+ /* Run the optimizers and output the assembler code for this function. */
+ rest_of_compilation (fndecl);
+ }
+
+ /* Free all the tree nodes making up this function. */
+ /* Switch back to allocating nodes permanently until we start another
+ function. */
+ if (!nested)
+ permanent_allocation (1);
+
+ if (DECL_SAVED_INSNS (fndecl) == 0 && !nested && (TREE_CODE (fndecl) != ERROR_MARK))
+ {
+ /* Stop pointing to the local nodes about to be freed. */
+ /* But DECL_INITIAL must remain nonzero so we know this was an actual
+ function definition. */
+ /* For a nested function, this is done in pop_f_function_context. */
+ /* If rest_of_compilation set this to 0, leave it 0. */
+ if (DECL_INITIAL (fndecl) != 0)
+ DECL_INITIAL (fndecl) = error_mark_node;
+ DECL_ARGUMENTS (fndecl) = 0;
+ }
+
+ if (!nested)
+ {
+ /* Let the error reporting routines know that we're outside a function.
+ For a nested function, this value is used in pop_c_function_context
+ and then reset via pop_function_context. */
+ ffecom_outer_function_decl_ = current_function_decl = NULL;
+ }
+}
+
+/* Plug-in replacement for identifying the name of a decl and, for a
+ function, what we call it in diagnostics. For now, "program unit"
+ should suffice, since it's a bit of a hassle to figure out which
+ of several kinds of things it is. Note that it could conceivably
+ be a statement function, which probably isn't really a program unit
+ per se, but if that comes up, it should be easy to check (being a
+ nested function and all). */
+
+static char *
+lang_printable_name (tree decl, int v)
+{
+ /* Just to keep GCC quiet about the unused variable.
+ In theory, differing values of V should produce different
+ output. */
+ switch (v)
+ {
+ default:
+ if (TREE_CODE (decl) == ERROR_MARK)
+ return "erroneous code";
+ return IDENTIFIER_POINTER (DECL_NAME (decl));
+ }
+}
+
+/* g77's function to print out name of current function that caused
+ an error. */
+
+#if BUILT_FOR_270
+void
+lang_print_error_function (file)
+ char *file;
+{
+ static ffeglobal last_g = NULL;
+ static ffesymbol last_s = NULL;
+ ffeglobal g;
+ ffesymbol s;
+ char *kind;
+
+ if ((ffecom_primary_entry_ == NULL)
+ || (ffesymbol_global (ffecom_primary_entry_) == NULL))
+ {
+ g = NULL;
+ s = NULL;
+ kind = NULL;
+ }
+ else
+ {
+ g = ffesymbol_global (ffecom_primary_entry_);
+ if (ffecom_nested_entry_ == NULL)
+ {
+ s = ffecom_primary_entry_;
+ switch (ffesymbol_kind (s))
+ {
+ case FFEINFO_kindFUNCTION:
+ kind = "function";
+ break;
+
+ case FFEINFO_kindSUBROUTINE:
+ kind = "subroutine";
+ break;
+
+ case FFEINFO_kindPROGRAM:
+ kind = "program";
+ break;
+
+ case FFEINFO_kindBLOCKDATA:
+ kind = "block-data";
+ break;
+
+ default:
+ kind = ffeinfo_kind_message (ffesymbol_kind (s));
+ break;
+ }
+ }
+ else
+ {
+ s = ffecom_nested_entry_;
+ kind = "statement function";
+ }
+ }
+
+ if ((last_g != g) || (last_s != s))
+ {
+ if (file)
+ fprintf (stderr, "%s: ", file);
+
+ if (s == NULL)
+ fprintf (stderr, "Outside of any program unit:\n");
+ else
+ {
+ char *name = ffesymbol_text (s);
+
+ fprintf (stderr, "In %s `%s':\n", kind, name);
+ }
+
+ last_g = g;
+ last_s = s;
+ }
+}
+#endif
+
+/* Similar to `lookup_name' but look only at current binding level. */
+
+static tree
+lookup_name_current_level (tree name)
+{
+ register tree t;
+
+ if (current_binding_level == global_binding_level)
+ return IDENTIFIER_GLOBAL_VALUE (name);
+
+ if (IDENTIFIER_LOCAL_VALUE (name) == 0)
+ return 0;
+
+ for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
+ if (DECL_NAME (t) == name)
+ break;
+
+ return t;
+}
+
+/* Create a new `struct binding_level'. */
+
+static struct binding_level *
+make_binding_level ()
+{
+ /* NOSTRICT */
+ return (struct binding_level *) xmalloc (sizeof (struct binding_level));
+}
+
+/* Save and restore the variables in this file and elsewhere
+ that keep track of the progress of compilation of the current function.
+ Used for nested functions. */
+
+struct f_function
+{
+ struct f_function *next;
+ tree named_labels;
+ tree shadowed_labels;
+ struct binding_level *binding_level;
+};
+
+struct f_function *f_function_chain;
+
+/* Restore the variables used during compilation of a C function. */
+
+static void
+pop_f_function_context ()
+{
+ struct f_function *p = f_function_chain;
+ tree link;
+
+ /* Bring back all the labels that were shadowed. */
+ for (link = shadowed_labels; link; link = TREE_CHAIN (link))
+ if (DECL_NAME (TREE_VALUE (link)) != 0)
+ IDENTIFIER_LABEL_VALUE (DECL_NAME (TREE_VALUE (link)))
+ = TREE_VALUE (link);
+
+ if (DECL_SAVED_INSNS (current_function_decl) == 0)
+ {
+ /* Stop pointing to the local nodes about to be freed. */
+ /* But DECL_INITIAL must remain nonzero so we know this was an actual
+ function definition. */
+ DECL_INITIAL (current_function_decl) = error_mark_node;
+ DECL_ARGUMENTS (current_function_decl) = 0;
+ }
+
+ pop_function_context ();
+
+ f_function_chain = p->next;
+
+ named_labels = p->named_labels;
+ shadowed_labels = p->shadowed_labels;
+ current_binding_level = p->binding_level;
+
+ free (p);
+}
+
+/* Save and reinitialize the variables
+ used during compilation of a C function. */
+
+static void
+push_f_function_context ()
+{
+ struct f_function *p
+ = (struct f_function *) xmalloc (sizeof (struct f_function));
+
+ push_function_context ();
+
+ p->next = f_function_chain;
+ f_function_chain = p;
+
+ p->named_labels = named_labels;
+ p->shadowed_labels = shadowed_labels;
+ p->binding_level = current_binding_level;
+}
+
+static void
+push_parm_decl (tree parm)
+{
+ int old_immediate_size_expand = immediate_size_expand;
+
+ /* Don't try computing parm sizes now -- wait till fn is called. */
+
+ immediate_size_expand = 0;
+
+ push_obstacks_nochange ();
+
+ /* Fill in arg stuff. */
+
+ DECL_ARG_TYPE (parm) = TREE_TYPE (parm);
+ DECL_ARG_TYPE_AS_WRITTEN (parm) = TREE_TYPE (parm);
+ TREE_READONLY (parm) = 1; /* All implementation args are read-only. */
+
+ parm = pushdecl (parm);
+
+ immediate_size_expand = old_immediate_size_expand;
+
+ finish_decl (parm, NULL_TREE, FALSE);
+}
+
+/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, if appropriate. */
+
+static tree
+pushdecl_top_level (x)
+ tree x;
+{
+ register tree t;
+ register struct binding_level *b = current_binding_level;
+ register tree f = current_function_decl;
+
+ current_binding_level = global_binding_level;
+ current_function_decl = NULL_TREE;
+ t = pushdecl (x);
+ current_binding_level = b;
+ current_function_decl = f;
+ return t;
+}
+
+/* Store the list of declarations of the current level.
+ This is done for the parameter declarations of a function being defined,
+ after they are modified in the light of any missing parameters. */
+
+static tree
+storedecls (decls)
+ tree decls;
+{
+ return current_binding_level->names = decls;
+}
+
+/* Store the parameter declarations into the current function declaration.
+ This is called after parsing the parameter declarations, before
+ digesting the body of the function.
+
+ For an old-style definition, modify the function's type
+ to specify at least the number of arguments. */
+
+static void
+store_parm_decls (int is_main_program UNUSED)
+{
+ register tree fndecl = current_function_decl;
+
+ /* This is a chain of PARM_DECLs from old-style parm declarations. */
+ DECL_ARGUMENTS (fndecl) = storedecls (nreverse (getdecls ()));
+
+ /* Initialize the RTL code for the function. */
+
+ init_function_start (fndecl, input_filename, lineno);
+
+ /* Set up parameters and prepare for return, for the function. */
+
+ expand_function_start (fndecl, 0);
+}
+
+static tree
+start_decl (tree decl, bool is_top_level)
+{
+ register tree tem;
+ bool at_top_level = (current_binding_level == global_binding_level);
+ bool top_level = is_top_level || at_top_level;
+
+ /* Caller should pass TRUE for is_top_level only if we wouldn't be at top
+ level anyway. */
+ assert (!is_top_level || !at_top_level);
+
+ /* The corresponding pop_obstacks is in finish_decl. */
+ push_obstacks_nochange ();
+
+ if (DECL_INITIAL (decl) != NULL_TREE)
+ {
+ assert (DECL_INITIAL (decl) == error_mark_node);
+ assert (!DECL_EXTERNAL (decl));
+ }
+ else if (top_level)
+ assert ((TREE_STATIC (decl) == 1) || DECL_EXTERNAL (decl) == 1);
+
+ /* For Fortran, we by default put things in .common when possible. */
+ DECL_COMMON (decl) = 1;
+
+ /* Add this decl to the current binding level. TEM may equal DECL or it may
+ be a previous decl of the same name. */
+ if (is_top_level)
+ tem = pushdecl_top_level (decl);
+ else
+ tem = pushdecl (decl);
+
+ /* For a local variable, define the RTL now. */
+ if (!top_level
+ /* But not if this is a duplicate decl and we preserved the rtl from the
+ previous one (which may or may not happen). */
+ && DECL_RTL (tem) == 0)
+ {
+ if (TYPE_SIZE (TREE_TYPE (tem)) != 0)
+ expand_decl (tem);
+ else if (TREE_CODE (TREE_TYPE (tem)) == ARRAY_TYPE
+ && DECL_INITIAL (tem) != 0)
+ expand_decl (tem);
+ }
+
+ if (DECL_INITIAL (tem) != NULL_TREE)
+ {
+ /* When parsing and digesting the initializer, use temporary storage.
+ Do this even if we will ignore the value. */
+ if (at_top_level)
+ temporary_allocation ();
+ }
+
+ return tem;
+}
+
+/* Create the FUNCTION_DECL for a function definition.
+ DECLSPECS and DECLARATOR are the parts of the declaration;
+ they describe the function's name and the type it returns,
+ but twisted together in a fashion that parallels the syntax of C.
+
+ This function creates a binding context for the function body
+ as well as setting up the FUNCTION_DECL in current_function_decl.
+
+ Returns 1 on success. If the DECLARATOR is not suitable for a function
+ (it defines a datum instead), we return 0, which tells
+ yyparse to report a parse error.
+
+ NESTED is nonzero for a function nested within another function. */
+
+static void
+start_function (tree name, tree type, int nested, int public)
+{
+ tree decl1;
+ tree restype;
+ int old_immediate_size_expand = immediate_size_expand;
+
+ named_labels = 0;
+ shadowed_labels = 0;
+
+ /* Don't expand any sizes in the return type of the function. */
+ immediate_size_expand = 0;
+
+ if (nested)
+ {
+ assert (!public);
+ assert (current_function_decl != NULL_TREE);
+ assert (DECL_CONTEXT (current_function_decl) == NULL_TREE);
+ }
+ else
+ {
+ assert (current_function_decl == NULL_TREE);
+ }
+
+ if (TREE_CODE (type) == ERROR_MARK)
+ decl1 = current_function_decl = error_mark_node;
+ else
+ {
+ decl1 = build_decl (FUNCTION_DECL,
+ name,
+ type);
+ TREE_PUBLIC (decl1) = public ? 1 : 0;
+ if (nested)
+ DECL_INLINE (decl1) = 1;
+ TREE_STATIC (decl1) = 1;
+ DECL_EXTERNAL (decl1) = 0;
+
+ announce_function (decl1);
+
+ /* Make the init_value nonzero so pushdecl knows this is not tentative.
+ error_mark_node is replaced below (in poplevel) with the BLOCK. */
+ DECL_INITIAL (decl1) = error_mark_node;
+
+ /* Record the decl so that the function name is defined. If we already have
+ a decl for this name, and it is a FUNCTION_DECL, use the old decl. */
+
+ current_function_decl = pushdecl (decl1);
+ }
+
+ if (!nested)
+ ffecom_outer_function_decl_ = current_function_decl;
+
+ pushlevel (0);
+
+ if (TREE_CODE (current_function_decl) != ERROR_MARK)
+ {
+ make_function_rtl (current_function_decl);
+
+ restype = TREE_TYPE (TREE_TYPE (current_function_decl));
+ DECL_RESULT (current_function_decl)
+ = build_decl (RESULT_DECL, NULL_TREE, restype);
+ }
+
+ if (!nested)
+ /* Allocate further tree nodes temporarily during compilation of this
+ function only. */
+ temporary_allocation ();
+
+ if (!nested && (TREE_CODE (current_function_decl) != ERROR_MARK))
+ TREE_ADDRESSABLE (current_function_decl) = 1;
+
+ immediate_size_expand = old_immediate_size_expand;
+}
+
+/* Here are the public functions the GNU back end needs. */
+
+tree
+convert (type, expr)
+ tree type, expr;
+{
+ register tree e = expr;
+ register enum tree_code code = TREE_CODE (type);
+
+ if (type == TREE_TYPE (e)
+ || TREE_CODE (e) == ERROR_MARK)
+ return e;
+ if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (e)))
+ return fold (build1 (NOP_EXPR, type, e));
+ if (TREE_CODE (TREE_TYPE (e)) == ERROR_MARK
+ || code == ERROR_MARK)
+ return error_mark_node;
+ if (TREE_CODE (TREE_TYPE (e)) == VOID_TYPE)
+ {
+ assert ("void value not ignored as it ought to be" == NULL);
+ return error_mark_node;
+ }
+ if (code == VOID_TYPE)
+ return build1 (CONVERT_EXPR, type, e);
+ if ((code != RECORD_TYPE)
+ && (TREE_CODE (TREE_TYPE (e)) == RECORD_TYPE))
+ e = ffecom_1 (REALPART_EXPR, TREE_TYPE (TYPE_FIELDS (TREE_TYPE (e))),
+ e);
+ if (code == INTEGER_TYPE || code == ENUMERAL_TYPE)
+ return fold (convert_to_integer (type, e));
+ if (code == POINTER_TYPE)
+ return fold (convert_to_pointer (type, e));
+ if (code == REAL_TYPE)
+ return fold (convert_to_real (type, e));
+ if (code == COMPLEX_TYPE)
+ return fold (convert_to_complex (type, e));
+ if (code == RECORD_TYPE)
+ return fold (ffecom_convert_to_complex_ (type, e));
+
+ assert ("conversion to non-scalar type requested" == NULL);
+ return error_mark_node;
+}
+
+/* integrate_decl_tree calls this function, but since we don't use the
+ DECL_LANG_SPECIFIC field, this is a no-op. */
+
+void
+copy_lang_decl (node)
+ tree node UNUSED;
+{
+}
+
+/* Return the list of declarations of the current level.
+ Note that this list is in reverse order unless/until
+ you nreverse it; and when you do nreverse it, you must
+ store the result back using `storedecls' or you will lose. */
+
+tree
+getdecls ()
+{
+ return current_binding_level->names;
+}
+
+/* Nonzero if we are currently in the global binding level. */
+
+int
+global_bindings_p ()
+{
+ return current_binding_level == global_binding_level;
+}
+
+/* Insert BLOCK at the end of the list of subblocks of the
+ current binding level. This is used when a BIND_EXPR is expanded,
+ to handle the BLOCK node inside the BIND_EXPR. */
+
+void
+incomplete_type_error (value, type)
+ tree value UNUSED;
+ tree type;
+{
+ if (TREE_CODE (type) == ERROR_MARK)
+ return;
+
+ assert ("incomplete type?!?" == NULL);
+}
+
+void
+init_decl_processing ()
+{
+ malloc_init ();
+ ffe_init_0 ();
+}
+
+char *
+init_parse (filename)
+ char *filename;
+{
+#if BUILT_FOR_270
+ extern void (*print_error_function) (char *);
+#endif
+
+ /* Open input file. */
+ if (filename == 0 || !strcmp (filename, "-"))
+ {
+ finput = stdin;
+ filename = "stdin";
+ }
+ else
+ finput = fopen (filename, "r");
+ if (finput == 0)
+ pfatal_with_name (filename);
+
+#ifdef IO_BUFFER_SIZE
+ setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE);
+#endif
+
+ /* Make identifier nodes long enough for the language-specific slots. */
+ set_identifier_size (sizeof (struct lang_identifier));
+ decl_printable_name = lang_printable_name;
+#if BUILT_FOR_270
+ print_error_function = lang_print_error_function;
+#endif
+
+ return filename;
+}
+
+void
+finish_parse ()
+{
+ fclose (finput);
+}
+
+void
+insert_block (block)
+ tree block;
+{
+ TREE_USED (block) = 1;
+ current_binding_level->blocks
+ = chainon (current_binding_level->blocks, block);
+}
+
+int
+lang_decode_option (argc, argv)
+ int argc;
+ char **argv;
+{
+ return ffe_decode_option (argc, argv);
+}
+
+/* used by print-tree.c */
+
+void
+lang_print_xnode (file, node, indent)
+ FILE *file UNUSED;
+ tree node UNUSED;
+ int indent UNUSED;
+{
+}
+
+void
+lang_finish ()
+{
+ ffe_terminate_0 ();
+
+ if (ffe_is_ffedebug ())
+ malloc_pool_display (malloc_pool_image ());
+}
+
+char *
+lang_identify ()
+{
+ return "f77";
+}
+
+void
+lang_init_options ()
+{
+ /* Set default options for Fortran. */
+ flag_move_all_movables = 1;
+ flag_reduce_all_givs = 1;
+ flag_argument_noalias = 2;
+}
+
+void
+lang_init ()
+{
+ /* If the file is output from cpp, it should contain a first line
+ `# 1 "real-filename"', and the current design of gcc (toplev.c
+ in particular and the way it sets up information relied on by
+ INCLUDE) requires that we read this now, and store the
+ "real-filename" info in master_input_filename. Ask the lexer
+ to try doing this. */
+ ffelex_hash_kludge (finput);
+}
+
+int
+mark_addressable (exp)
+ tree exp;
+{
+ register tree x = exp;
+ while (1)
+ switch (TREE_CODE (x))
+ {
+ case ADDR_EXPR:
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ x = TREE_OPERAND (x, 0);
+ break;
+
+ case CONSTRUCTOR:
+ TREE_ADDRESSABLE (x) = 1;
+ return 1;
+
+ case VAR_DECL:
+ case CONST_DECL:
+ case PARM_DECL:
+ case RESULT_DECL:
+ if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x)
+ && DECL_NONLOCAL (x))
+ {
+ if (TREE_PUBLIC (x))
+ {
+ assert ("address of global register var requested" == NULL);
+ return 0;
+ }
+ assert ("address of register variable requested" == NULL);
+ }
+ else if (DECL_REGISTER (x) && !TREE_ADDRESSABLE (x))
+ {
+ if (TREE_PUBLIC (x))
+ {
+ assert ("address of global register var requested" == NULL);
+ return 0;
+ }
+ assert ("address of register var requested" == NULL);
+ }
+ put_var_into_stack (x);
+
+ /* drops in */
+ case FUNCTION_DECL:
+ TREE_ADDRESSABLE (x) = 1;
+#if 0 /* poplevel deals with this now. */
+ if (DECL_CONTEXT (x) == 0)
+ TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
+#endif
+
+ default:
+ return 1;
+ }
+}
+
+/* If DECL has a cleanup, build and return that cleanup here.
+ This is a callback called by expand_expr. */
+
+tree
+maybe_build_cleanup (decl)
+ tree decl UNUSED;
+{
+ /* There are no cleanups in Fortran. */
+ return NULL_TREE;
+}
+
+/* Exit a binding level.
+ Pop the level off, and restore the state of the identifier-decl mappings
+ that were in effect when this level was entered.
+
+ If KEEP is nonzero, this level had explicit declarations, so
+ and create a "block" (a BLOCK node) for the level
+ to record its declarations and subblocks for symbol table output.
+
+ If FUNCTIONBODY is nonzero, this level is the body of a function,
+ so create a block as if KEEP were set and also clear out all
+ label names.
+
+ If REVERSE is nonzero, reverse the order of decls before putting
+ them into the BLOCK. */
+
+tree
+poplevel (keep, reverse, functionbody)
+ int keep;
+ int reverse;
+ int functionbody;
+{
+ register tree link;
+ /* The chain of decls was accumulated in reverse order. Put it into forward
+ order, just for cleanliness. */
+ tree decls;
+ tree subblocks = current_binding_level->blocks;
+ tree block = 0;
+ tree decl;
+ int block_previously_created;
+
+ /* Get the decls in the order they were written. Usually
+ current_binding_level->names is in reverse order. But parameter decls
+ were previously put in forward order. */
+
+ if (reverse)
+ current_binding_level->names
+ = decls = nreverse (current_binding_level->names);
+ else
+ decls = current_binding_level->names;
+
+ /* Output any nested inline functions within this block if they weren't
+ already output. */
+
+ for (decl = decls; decl; decl = TREE_CHAIN (decl))
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && !TREE_ASM_WRITTEN (decl)
+ && DECL_INITIAL (decl) != 0
+ && TREE_ADDRESSABLE (decl))
+ {
+ /* If this decl was copied from a file-scope decl on account of a
+ block-scope extern decl, propagate TREE_ADDRESSABLE to the
+ file-scope decl. */
+ if (DECL_ABSTRACT_ORIGIN (decl) != 0)
+ TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1;
+ else
+ {
+ push_function_context ();
+ output_inline_function (decl);
+ pop_function_context ();
+ }
+ }
+
+ /* If there were any declarations or structure tags in that level, or if
+ this level is a function body, create a BLOCK to record them for the
+ life of this function. */
+
+ block = 0;
+ block_previously_created = (current_binding_level->this_block != 0);
+ if (block_previously_created)
+ block = current_binding_level->this_block;
+ else if (keep || functionbody)
+ block = make_node (BLOCK);
+ if (block != 0)
+ {
+ BLOCK_VARS (block) = decls;
+ BLOCK_SUBBLOCKS (block) = subblocks;
+ remember_end_note (block);
+ }
+
+ /* In each subblock, record that this is its superior. */
+
+ for (link = subblocks; link; link = TREE_CHAIN (link))
+ BLOCK_SUPERCONTEXT (link) = block;
+
+ /* Clear out the meanings of the local variables of this level. */
+
+ for (link = decls; link; link = TREE_CHAIN (link))
+ {
+ if (DECL_NAME (link) != 0)
+ {
+ /* If the ident. was used or addressed via a local extern decl,
+ don't forget that fact. */
+ if (DECL_EXTERNAL (link))
+ {
+ if (TREE_USED (link))
+ TREE_USED (DECL_NAME (link)) = 1;
+ if (TREE_ADDRESSABLE (link))
+ TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1;
+ }
+ IDENTIFIER_LOCAL_VALUE (DECL_NAME (link)) = 0;
+ }
+ }
+
+ /* If the level being exited is the top level of a function, check over all
+ the labels, and clear out the current (function local) meanings of their
+ names. */
+
+ if (functionbody)
+ {
+ /* If this is the top level block of a function, the vars are the
+ function's parameters. Don't leave them in the BLOCK because they
+ are found in the FUNCTION_DECL instead. */
+
+ BLOCK_VARS (block) = 0;
+ }
+
+ /* Pop the current level, and free the structure for reuse. */
+
+ {
+ register struct binding_level *level = current_binding_level;
+ current_binding_level = current_binding_level->level_chain;
+
+ level->level_chain = free_binding_level;
+ free_binding_level = level;
+ }
+
+ /* Dispose of the block that we just made inside some higher level. */
+ if (functionbody)
+ DECL_INITIAL (current_function_decl) = block;
+ else if (block)
+ {
+ if (!block_previously_created)
+ current_binding_level->blocks
+ = chainon (current_binding_level->blocks, block);
+ }
+ /* If we did not make a block for the level just exited, any blocks made
+ for inner levels (since they cannot be recorded as subblocks in that
+ level) must be carried forward so they will later become subblocks of
+ something else. */
+ else if (subblocks)
+ current_binding_level->blocks
+ = chainon (current_binding_level->blocks, subblocks);
+
+ /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this
+ binding contour so that they point to the appropriate construct, i.e.
+ either to the current FUNCTION_DECL node, or else to the BLOCK node we
+ just constructed.
+
+ Note that for tagged types whose scope is just the formal parameter list
+ for some function type specification, we can't properly set their
+ TYPE_CONTEXTs here, because we don't have a pointer to the appropriate
+ FUNCTION_TYPE node readily available to us. For those cases, the
+ TYPE_CONTEXTs of the relevant tagged type nodes get set in
+ `grokdeclarator' as soon as we have created the FUNCTION_TYPE node which
+ will represent the "scope" for these "parameter list local" tagged
+ types. */
+
+ if (block)
+ TREE_USED (block) = 1;
+ return block;
+}
+
+void
+print_lang_decl (file, node, indent)
+ FILE *file UNUSED;
+ tree node UNUSED;
+ int indent UNUSED;
+{
+}
+
+void
+print_lang_identifier (file, node, indent)
+ FILE *file;
+ tree node;
+ int indent;
+{
+ print_node (file, "global", IDENTIFIER_GLOBAL_VALUE (node), indent + 4);
+ print_node (file, "local", IDENTIFIER_LOCAL_VALUE (node), indent + 4);
+}
+
+void
+print_lang_statistics ()
+{
+}
+
+void
+print_lang_type (file, node, indent)
+ FILE *file UNUSED;
+ tree node UNUSED;
+ int indent UNUSED;
+{
+}
+
+/* Record a decl-node X as belonging to the current lexical scope.
+ Check for errors (such as an incompatible declaration for the same
+ name already seen in the same scope).
+
+ Returns either X or an old decl for the same name.
+ If an old decl is returned, it may have been smashed
+ to agree with what X says. */
+
+tree
+pushdecl (x)
+ tree x;
+{
+ register tree t;
+ register tree name = DECL_NAME (x);
+ register struct binding_level *b = current_binding_level;
+
+ if ((TREE_CODE (x) == FUNCTION_DECL)
+ && (DECL_INITIAL (x) == 0)
+ && DECL_EXTERNAL (x))
+ DECL_CONTEXT (x) = NULL_TREE;
+ else
+ DECL_CONTEXT (x) = current_function_decl;
+
+ if (name)
+ {
+ if (IDENTIFIER_INVENTED (name))
+ {
+#if BUILT_FOR_270
+ DECL_ARTIFICIAL (x) = 1;
+#endif
+ DECL_IN_SYSTEM_HEADER (x) = 1;
+ }
+
+ t = lookup_name_current_level (name);
+
+ assert ((t == NULL_TREE) || (DECL_CONTEXT (x) == NULL_TREE));
+
+ /* Don't push non-parms onto list for parms until we understand
+ why we're doing this and whether it works. */
+
+ assert ((b == global_binding_level)
+ || !ffecom_transform_only_dummies_
+ || TREE_CODE (x) == PARM_DECL);
+
+ if ((t != NULL_TREE) && duplicate_decls (x, t))
+ return t;
+
+ /* If we are processing a typedef statement, generate a whole new
+ ..._TYPE node (which will be just an variant of the existing
+ ..._TYPE node with identical properties) and then install the
+ TYPE_DECL node generated to represent the typedef name as the
+ TYPE_NAME of this brand new (duplicate) ..._TYPE node.
+
+ The whole point here is to end up with a situation where each and every
+ ..._TYPE node the compiler creates will be uniquely associated with
+ AT MOST one node representing a typedef name. This way, even though
+ the compiler substitutes corresponding ..._TYPE nodes for TYPE_DECL
+ (i.e. "typedef name") nodes very early on, later parts of the
+ compiler can always do the reverse translation and get back the
+ corresponding typedef name. For example, given:
+
+ typedef struct S MY_TYPE; MY_TYPE object;
+
+ Later parts of the compiler might only know that `object' was of type
+ `struct S' if it were not for code just below. With this code
+ however, later parts of the compiler see something like:
+
+ struct S' == struct S typedef struct S' MY_TYPE; struct S' object;
+
+ And they can then deduce (from the node for type struct S') that the
+ original object declaration was:
+
+ MY_TYPE object;
+
+ Being able to do this is important for proper support of protoize, and
+ also for generating precise symbolic debugging information which
+ takes full account of the programmer's (typedef) vocabulary.
+
+ Obviously, we don't want to generate a duplicate ..._TYPE node if the
+ TYPE_DECL node that we are now processing really represents a
+ standard built-in type.
+
+ Since all standard types are effectively declared at line zero in the
+ source file, we can easily check to see if we are working on a
+ standard type by checking the current value of lineno. */
+
+ if (TREE_CODE (x) == TYPE_DECL)
+ {
+ if (DECL_SOURCE_LINE (x) == 0)
+ {
+ if (TYPE_NAME (TREE_TYPE (x)) == 0)
+ TYPE_NAME (TREE_TYPE (x)) = x;
+ }
+ else if (TREE_TYPE (x) != error_mark_node)
+ {
+ tree tt = TREE_TYPE (x);
+
+ tt = build_type_copy (tt);
+ TYPE_NAME (tt) = x;
+ TREE_TYPE (x) = tt;
+ }
+ }
+
+ /* This name is new in its binding level. Install the new declaration
+ and return it. */
+ if (b == global_binding_level)
+ IDENTIFIER_GLOBAL_VALUE (name) = x;
+ else
+ IDENTIFIER_LOCAL_VALUE (name) = x;
+ }
+
+ /* Put decls on list in reverse order. We will reverse them later if
+ necessary. */
+ TREE_CHAIN (x) = b->names;
+ b->names = x;
+
+ return x;
+}
+
+/* Enter a new binding level.
+ If TAG_TRANSPARENT is nonzero, do so only for the name space of variables,
+ not for that of tags. */
+
+void
+pushlevel (tag_transparent)
+ int tag_transparent;
+{
+ register struct binding_level *newlevel = NULL_BINDING_LEVEL;
+
+ assert (!tag_transparent);
+
+ /* Reuse or create a struct for this binding level. */
+
+ if (free_binding_level)
+ {
+ newlevel = free_binding_level;
+ free_binding_level = free_binding_level->level_chain;
+ }
+ else
+ {
+ newlevel = make_binding_level ();
+ }
+
+ /* Add this level to the front of the chain (stack) of levels that are
+ active. */
+
+ *newlevel = clear_binding_level;
+ newlevel->level_chain = current_binding_level;
+ current_binding_level = newlevel;
+}
+
+/* Set the BLOCK node for the innermost scope
+ (the one we are currently in). */
+
+void
+set_block (block)
+ register tree block;
+{
+ current_binding_level->this_block = block;
+}
+
+/* ~~tree.h SHOULD declare this, because toplev.c references it. */
+
+/* Can't 'yydebug' a front end not generated by yacc/bison! */
+
+void
+set_yydebug (value)
+ int value;
+{
+ if (value)
+ fprintf (stderr, "warning: no yacc/bison-generated output to debug!\n");
+}
+
+tree
+signed_or_unsigned_type (unsignedp, type)
+ int unsignedp;
+ tree type;
+{
+ tree type2;
+
+ if (! INTEGRAL_TYPE_P (type))
+ return type;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+ if (TYPE_PRECISION (type) == TYPE_PRECISION (long_long_integer_type_node))
+ return (unsignedp ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+
+ type2 = type_for_size (TYPE_PRECISION (type), unsignedp);
+ if (type2 == NULL_TREE)
+ return type;
+
+ return type2;
+}
+
+tree
+signed_type (type)
+ tree type;
+{
+ tree type1 = TYPE_MAIN_VARIANT (type);
+ ffeinfoKindtype kt;
+ tree type2;
+
+ if (type1 == unsigned_char_type_node || type1 == char_type_node)
+ return signed_char_type_node;
+ if (type1 == unsigned_type_node)
+ return integer_type_node;
+ if (type1 == short_unsigned_type_node)
+ return short_integer_type_node;
+ if (type1 == long_unsigned_type_node)
+ return long_integer_type_node;
+ if (type1 == long_long_unsigned_type_node)
+ return long_long_integer_type_node;
+#if 0 /* gcc/c-* files only */
+ if (type1 == unsigned_intDI_type_node)
+ return intDI_type_node;
+ if (type1 == unsigned_intSI_type_node)
+ return intSI_type_node;
+ if (type1 == unsigned_intHI_type_node)
+ return intHI_type_node;
+ if (type1 == unsigned_intQI_type_node)
+ return intQI_type_node;
+#endif
+
+ type2 = type_for_size (TYPE_PRECISION (type1), 0);
+ if (type2 != NULL_TREE)
+ return type2;
+
+ for (kt = 0; kt < ARRAY_SIZE (ffecom_tree_type[0]); ++kt)
+ {
+ type2 = ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt];
+
+ if (type1 == type2)
+ return ffecom_tree_type[FFEINFO_basictypeINTEGER][kt];
+ }
+
+ return type;
+}
+
+/* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
+ or validate its data type for an `if' or `while' statement or ?..: exp.
+
+ This preparation consists of taking the ordinary
+ representation of an expression expr and producing a valid tree
+ boolean expression describing whether expr is nonzero. We could
+ simply always do build_binary_op (NE_EXPR, expr, integer_zero_node, 1),
+ but we optimize comparisons, &&, ||, and !.
+
+ The resulting type should always be `integer_type_node'. */
+
+tree
+truthvalue_conversion (expr)
+ tree expr;
+{
+ if (TREE_CODE (expr) == ERROR_MARK)
+ return expr;
+
+#if 0 /* This appears to be wrong for C++. */
+ /* These really should return error_mark_node after 2.4 is stable.
+ But not all callers handle ERROR_MARK properly. */
+ switch (TREE_CODE (TREE_TYPE (expr)))
+ {
+ case RECORD_TYPE:
+ error ("struct type value used where scalar is required");
+ return integer_zero_node;
+
+ case UNION_TYPE:
+ error ("union type value used where scalar is required");
+ return integer_zero_node;
+
+ case ARRAY_TYPE:
+ error ("array type value used where scalar is required");
+ return integer_zero_node;
+
+ default:
+ break;
+ }
+#endif /* 0 */
+
+ switch (TREE_CODE (expr))
+ {
+ /* It is simpler and generates better code to have only TRUTH_*_EXPR
+ or comparison expressions as truth values at this level. */
+#if 0
+ case COMPONENT_REF:
+ /* A one-bit unsigned bit-field is already acceptable. */
+ if (1 == TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (expr, 1)))
+ && TREE_UNSIGNED (TREE_OPERAND (expr, 1)))
+ return expr;
+ break;
+#endif
+
+ case EQ_EXPR:
+ /* It is simpler and generates better code to have only TRUTH_*_EXPR
+ or comparison expressions as truth values at this level. */
+#if 0
+ if (integer_zerop (TREE_OPERAND (expr, 1)))
+ return build_unary_op (TRUTH_NOT_EXPR, TREE_OPERAND (expr, 0), 0);
+#endif
+ case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_XOR_EXPR:
+ TREE_TYPE (expr) = integer_type_node;
+ return expr;
+
+ case ERROR_MARK:
+ return expr;
+
+ case INTEGER_CST:
+ return integer_zerop (expr) ? integer_zero_node : integer_one_node;
+
+ case REAL_CST:
+ return real_zerop (expr) ? integer_zero_node : integer_one_node;
+
+ case ADDR_EXPR:
+ if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))
+ return build (COMPOUND_EXPR, integer_type_node,
+ TREE_OPERAND (expr, 0), integer_one_node);
+ else
+ return integer_one_node;
+
+ case COMPLEX_EXPR:
+ return ffecom_2 ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
+ ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
+ integer_type_node,
+ truthvalue_conversion (TREE_OPERAND (expr, 0)),
+ truthvalue_conversion (TREE_OPERAND (expr, 1)));
+
+ case NEGATE_EXPR:
+ case ABS_EXPR:
+ case FLOAT_EXPR:
+ case FFS_EXPR:
+ /* These don't change whether an object is non-zero or zero. */
+ return truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
+ /* These don't change whether an object is zero or non-zero, but
+ we can't ignore them if their second arg has side-effects. */
+ if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
+ return build (COMPOUND_EXPR, integer_type_node, TREE_OPERAND (expr, 1),
+ truthvalue_conversion (TREE_OPERAND (expr, 0)));
+ else
+ return truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+ case COND_EXPR:
+ /* Distribute the conversion into the arms of a COND_EXPR. */
+ return fold (build (COND_EXPR, integer_type_node, TREE_OPERAND (expr, 0),
+ truthvalue_conversion (TREE_OPERAND (expr, 1)),
+ truthvalue_conversion (TREE_OPERAND (expr, 2))));
+
+ case CONVERT_EXPR:
+ /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
+ since that affects how `default_conversion' will behave. */
+ if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
+ || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
+ break;
+ /* fall through... */
+ case NOP_EXPR:
+ /* If this is widening the argument, we can ignore it. */
+ if (TYPE_PRECISION (TREE_TYPE (expr))
+ >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
+ return truthvalue_conversion (TREE_OPERAND (expr, 0));
+ break;
+
+ case MINUS_EXPR:
+ /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize
+ this case. */
+ if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+ && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
+ break;
+ /* fall through... */
+ case BIT_XOR_EXPR:
+ /* This and MINUS_EXPR can be changed into a comparison of the
+ two objects. */
+ if (TREE_TYPE (TREE_OPERAND (expr, 0))
+ == TREE_TYPE (TREE_OPERAND (expr, 1)))
+ return ffecom_2 (NE_EXPR, integer_type_node,
+ TREE_OPERAND (expr, 0),
+ TREE_OPERAND (expr, 1));
+ return ffecom_2 (NE_EXPR, integer_type_node,
+ TREE_OPERAND (expr, 0),
+ fold (build1 (NOP_EXPR,
+ TREE_TYPE (TREE_OPERAND (expr, 0)),
+ TREE_OPERAND (expr, 1))));
+
+ case BIT_AND_EXPR:
+ if (integer_onep (TREE_OPERAND (expr, 1)))
+ return expr;
+ break;
+
+ case MODIFY_EXPR:
+#if 0 /* No such thing in Fortran. */
+ if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR)
+ warning ("suggest parentheses around assignment used as truth value");
+#endif
+ break;
+
+ default:
+ break;
+ }
+
+ if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
+ return (ffecom_2
+ ((TREE_SIDE_EFFECTS (expr)
+ ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
+ integer_type_node,
+ truthvalue_conversion (ffecom_1 (REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr)),
+ truthvalue_conversion (ffecom_1 (IMAGPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr))));
+
+ return ffecom_2 (NE_EXPR, integer_type_node,
+ expr,
+ convert (TREE_TYPE (expr), integer_zero_node));
+}
+
+tree
+type_for_mode (mode, unsignedp)
+ enum machine_mode mode;
+ int unsignedp;
+{
+ int i;
+ int j;
+ tree t;
+
+ if (mode == TYPE_MODE (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+
+ if (mode == TYPE_MODE (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+
+ if (mode == TYPE_MODE (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+
+ if (mode == TYPE_MODE (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+ if (mode == TYPE_MODE (long_long_integer_type_node))
+ return unsignedp ? long_long_unsigned_type_node : long_long_integer_type_node;
+
+ if (mode == TYPE_MODE (float_type_node))
+ return float_type_node;
+
+ if (mode == TYPE_MODE (double_type_node))
+ return double_type_node;
+
+ if (mode == TYPE_MODE (build_pointer_type (char_type_node)))
+ return build_pointer_type (char_type_node);
+
+ if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
+ return build_pointer_type (integer_type_node);
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (ffecom_tree_type); ++i)
+ for (j = 0; ((size_t) j) < ARRAY_SIZE (ffecom_tree_type[0]); ++j)
+ {
+ if (((t = ffecom_tree_type[i][j]) != NULL_TREE)
+ && (mode == TYPE_MODE (t)))
+ {
+ if ((i == FFEINFO_basictypeINTEGER) && unsignedp)
+ return ffecom_tree_type[FFEINFO_basictypeHOLLERITH][j];
+ else
+ return t;
+ }
+ }
+
+ return 0;
+}
+
+tree
+type_for_size (bits, unsignedp)
+ unsigned bits;
+ int unsignedp;
+{
+ ffeinfoKindtype kt;
+ tree type_node;
+
+ if (bits == TYPE_PRECISION (integer_type_node))
+ return unsignedp ? unsigned_type_node : integer_type_node;
+
+ if (bits == TYPE_PRECISION (signed_char_type_node))
+ return unsignedp ? unsigned_char_type_node : signed_char_type_node;
+
+ if (bits == TYPE_PRECISION (short_integer_type_node))
+ return unsignedp ? short_unsigned_type_node : short_integer_type_node;
+
+ if (bits == TYPE_PRECISION (long_integer_type_node))
+ return unsignedp ? long_unsigned_type_node : long_integer_type_node;
+
+ if (bits == TYPE_PRECISION (long_long_integer_type_node))
+ return (unsignedp ? long_long_unsigned_type_node
+ : long_long_integer_type_node);
+
+ for (kt = 0; kt < ARRAY_SIZE (ffecom_tree_type[0]); ++kt)
+ {
+ type_node = ffecom_tree_type[FFEINFO_basictypeINTEGER][kt];
+
+ if ((type_node != NULL_TREE) && (bits == TYPE_PRECISION (type_node)))
+ return unsignedp ? ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt]
+ : type_node;
+ }
+
+ return 0;
+}
+
+tree
+unsigned_type (type)
+ tree type;
+{
+ tree type1 = TYPE_MAIN_VARIANT (type);
+ ffeinfoKindtype kt;
+ tree type2;
+
+ if (type1 == signed_char_type_node || type1 == char_type_node)
+ return unsigned_char_type_node;
+ if (type1 == integer_type_node)
+ return unsigned_type_node;
+ if (type1 == short_integer_type_node)
+ return short_unsigned_type_node;
+ if (type1 == long_integer_type_node)
+ return long_unsigned_type_node;
+ if (type1 == long_long_integer_type_node)
+ return long_long_unsigned_type_node;
+#if 0 /* gcc/c-* files only */
+ if (type1 == intDI_type_node)
+ return unsigned_intDI_type_node;
+ if (type1 == intSI_type_node)
+ return unsigned_intSI_type_node;
+ if (type1 == intHI_type_node)
+ return unsigned_intHI_type_node;
+ if (type1 == intQI_type_node)
+ return unsigned_intQI_type_node;
+#endif
+
+ type2 = type_for_size (TYPE_PRECISION (type1), 1);
+ if (type2 != NULL_TREE)
+ return type2;
+
+ for (kt = 0; kt < ARRAY_SIZE (ffecom_tree_type[0]); ++kt)
+ {
+ type2 = ffecom_tree_type[FFEINFO_basictypeINTEGER][kt];
+
+ if (type1 == type2)
+ return ffecom_tree_type[FFEINFO_basictypeHOLLERITH][kt];
+ }
+
+ return type;
+}
+
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+#if FFECOM_GCC_INCLUDE
+
+/* From gcc/cccp.c, the code to handle -I. */
+
+/* Skip leading "./" from a directory name.
+ This may yield the empty string, which represents the current directory. */
+
+static char *
+skip_redundant_dir_prefix (char *dir)
+{
+ while (dir[0] == '.' && dir[1] == '/')
+ for (dir += 2; *dir == '/'; dir++)
+ continue;
+ if (dir[0] == '.' && !dir[1])
+ dir++;
+ return dir;
+}
+
+/* The file_name_map structure holds a mapping of file names for a
+ particular directory. This mapping is read from the file named
+ FILE_NAME_MAP_FILE in that directory. Such a file can be used to
+ map filenames on a file system with severe filename restrictions,
+ such as DOS. The format of the file name map file is just a series
+ of lines with two tokens on each line. The first token is the name
+ to map, and the second token is the actual name to use. */
+
+struct file_name_map
+{
+ struct file_name_map *map_next;
+ char *map_from;
+ char *map_to;
+};
+
+#define FILE_NAME_MAP_FILE "header.gcc"
+
+/* Current maximum length of directory names in the search path
+ for include files. (Altered as we get more of them.) */
+
+static int max_include_len = 0;
+
+struct file_name_list
+ {
+ struct file_name_list *next;
+ char *fname;
+ /* Mapping of file names for this directory. */
+ struct file_name_map *name_map;
+ /* Non-zero if name_map is valid. */
+ int got_name_map;
+ };
+
+static struct file_name_list *include = NULL; /* First dir to search */
+static struct file_name_list *last_include = NULL; /* Last in chain */
+
+/* I/O buffer structure.
+ The `fname' field is nonzero for source files and #include files
+ and for the dummy text used for -D and -U.
+ It is zero for rescanning results of macro expansion
+ and for expanding macro arguments. */
+#define INPUT_STACK_MAX 400
+static struct file_buf {
+ char *fname;
+ /* Filename specified with #line command. */
+ char *nominal_fname;
+ /* Record where in the search path this file was found.
+ For #include_next. */
+ struct file_name_list *dir;
+ ffewhereLine line;
+ ffewhereColumn column;
+} instack[INPUT_STACK_MAX];
+
+static int last_error_tick = 0; /* Incremented each time we print it. */
+static int input_file_stack_tick = 0; /* Incremented when status changes. */
+
+/* Current nesting level of input sources.
+ `instack[indepth]' is the level currently being read. */
+static int indepth = -1;
+
+typedef struct file_buf FILE_BUF;
+
+typedef unsigned char U_CHAR;
+
+/* table to tell if char can be part of a C identifier. */
+U_CHAR is_idchar[256];
+/* table to tell if char can be first char of a c identifier. */
+U_CHAR is_idstart[256];
+/* table to tell if c is horizontal space. */
+U_CHAR is_hor_space[256];
+/* table to tell if c is horizontal or vertical space. */
+static U_CHAR is_space[256];
+
+#define SKIP_WHITE_SPACE(p) do { while (is_hor_space[*p]) p++; } while (0)
+#define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*p]) p++; } while (0)
+
+/* Nonzero means -I- has been seen,
+ so don't look for #include "foo" the source-file directory. */
+static int ignore_srcdir;
+
+#ifndef INCLUDE_LEN_FUDGE
+#define INCLUDE_LEN_FUDGE 0
+#endif
+
+static void append_include_chain (struct file_name_list *first,
+ struct file_name_list *last);
+static FILE *open_include_file (char *filename,
+ struct file_name_list *searchptr);
+static void print_containing_files (ffebadSeverity sev);
+static char *skip_redundant_dir_prefix (char *);
+static char *read_filename_string (int ch, FILE *f);
+static struct file_name_map *read_name_map (char *dirname);
+static char *savestring (char *input);
+
+/* Append a chain of `struct file_name_list's
+ to the end of the main include chain.
+ FIRST is the beginning of the chain to append, and LAST is the end. */
+
+static void
+append_include_chain (first, last)
+ struct file_name_list *first, *last;
+{
+ struct file_name_list *dir;
+
+ if (!first || !last)
+ return;
+
+ if (include == 0)
+ include = first;
+ else
+ last_include->next = first;
+
+ for (dir = first; ; dir = dir->next) {
+ int len = strlen (dir->fname) + INCLUDE_LEN_FUDGE;
+ if (len > max_include_len)
+ max_include_len = len;
+ if (dir == last)
+ break;
+ }
+
+ last->next = NULL;
+ last_include = last;
+}
+
+/* Try to open include file FILENAME. SEARCHPTR is the directory
+ being tried from the include file search path. This function maps
+ filenames on file systems based on information read by
+ read_name_map. */
+
+static FILE *
+open_include_file (filename, searchptr)
+ char *filename;
+ struct file_name_list *searchptr;
+{
+ register struct file_name_map *map;
+ register char *from;
+ char *p, *dir;
+
+ if (searchptr && ! searchptr->got_name_map)
+ {
+ searchptr->name_map = read_name_map (searchptr->fname
+ ? searchptr->fname : ".");
+ searchptr->got_name_map = 1;
+ }
+
+ /* First check the mapping for the directory we are using. */
+ if (searchptr && searchptr->name_map)
+ {
+ from = filename;
+ if (searchptr->fname)
+ from += strlen (searchptr->fname) + 1;
+ for (map = searchptr->name_map; map; map = map->map_next)
+ {
+ if (! strcmp (map->map_from, from))
+ {
+ /* Found a match. */
+ return fopen (map->map_to, "r");
+ }
+ }
+ }
+
+ /* Try to find a mapping file for the particular directory we are
+ looking in. Thus #include <sys/types.h> will look up sys/types.h
+ in /usr/include/header.gcc and look up types.h in
+ /usr/include/sys/header.gcc. */
+ p = rindex (filename, '/');
+#ifdef DIR_SEPARATOR
+ if (! p) p = rindex (filename, DIR_SEPARATOR);
+ else {
+ char *tmp = rindex (filename, DIR_SEPARATOR);
+ if (tmp != NULL && tmp > p) p = tmp;
+ }
+#endif
+ if (! p)
+ p = filename;
+ if (searchptr
+ && searchptr->fname
+ && strlen (searchptr->fname) == (size_t) (p - filename)
+ && ! strncmp (searchptr->fname, filename, (int) (p - filename)))
+ {
+ /* FILENAME is in SEARCHPTR, which we've already checked. */
+ return fopen (filename, "r");
+ }
+
+ if (p == filename)
+ {
+ from = filename;
+ map = read_name_map (".");
+ }
+ else
+ {
+ dir = (char *) xmalloc (p - filename + 1);
+ memcpy (dir, filename, p - filename);
+ dir[p - filename] = '\0';
+ from = p + 1;
+ map = read_name_map (dir);
+ free (dir);
+ }
+ for (; map; map = map->map_next)
+ if (! strcmp (map->map_from, from))
+ return fopen (map->map_to, "r");
+
+ return fopen (filename, "r");
+}
+
+/* Print the file names and line numbers of the #include
+ commands which led to the current file. */
+
+static void
+print_containing_files (ffebadSeverity sev)
+{
+ FILE_BUF *ip = NULL;
+ int i;
+ int first = 1;
+ char *str1;
+ char *str2;
+
+ /* If stack of files hasn't changed since we last printed
+ this info, don't repeat it. */
+ if (last_error_tick == input_file_stack_tick)
+ return;
+
+ for (i = indepth; i >= 0; i--)
+ if (instack[i].fname != NULL) {
+ ip = &instack[i];
+ break;
+ }
+
+ /* Give up if we don't find a source file. */
+ if (ip == NULL)
+ return;
+
+ /* Find the other, outer source files. */
+ for (i--; i >= 0; i--)
+ if (instack[i].fname != NULL)
+ {
+ ip = &instack[i];
+ if (first)
+ {
+ first = 0;
+ str1 = "In file included";
+ }
+ else
+ {
+ str1 = "... ...";
+ }
+
+ if (i == 1)
+ str2 = ":";
+ else
+ str2 = "";
+
+ ffebad_start_msg ("%A from %B at %0%C", sev);
+ ffebad_here (0, ip->line, ip->column);
+ ffebad_string (str1);
+ ffebad_string (ip->nominal_fname);
+ ffebad_string (str2);
+ ffebad_finish ();
+ }
+
+ /* Record we have printed the status as of this time. */
+ last_error_tick = input_file_stack_tick;
+}
+
+/* Read a space delimited string of unlimited length from a stdio
+ file. */
+
+static char *
+read_filename_string (ch, f)
+ int ch;
+ FILE *f;
+{
+ char *alloc, *set;
+ int len;
+
+ len = 20;
+ set = alloc = xmalloc (len + 1);
+ if (! is_space[ch])
+ {
+ *set++ = ch;
+ while ((ch = getc (f)) != EOF && ! is_space[ch])
+ {
+ if (set - alloc == len)
+ {
+ len *= 2;
+ alloc = xrealloc (alloc, len + 1);
+ set = alloc + len / 2;
+ }
+ *set++ = ch;
+ }
+ }
+ *set = '\0';
+ ungetc (ch, f);
+ return alloc;
+}
+
+/* Read the file name map file for DIRNAME. */
+
+static struct file_name_map *
+read_name_map (dirname)
+ char *dirname;
+{
+ /* This structure holds a linked list of file name maps, one per
+ directory. */
+ struct file_name_map_list
+ {
+ struct file_name_map_list *map_list_next;
+ char *map_list_name;
+ struct file_name_map *map_list_map;
+ };
+ static struct file_name_map_list *map_list;
+ register struct file_name_map_list *map_list_ptr;
+ char *name;
+ FILE *f;
+ size_t dirlen;
+ int separator_needed;
+
+ dirname = skip_redundant_dir_prefix (dirname);
+
+ for (map_list_ptr = map_list; map_list_ptr;
+ map_list_ptr = map_list_ptr->map_list_next)
+ if (! strcmp (map_list_ptr->map_list_name, dirname))
+ return map_list_ptr->map_list_map;
+
+ map_list_ptr = ((struct file_name_map_list *)
+ xmalloc (sizeof (struct file_name_map_list)));
+ map_list_ptr->map_list_name = savestring (dirname);
+ map_list_ptr->map_list_map = NULL;
+
+ dirlen = strlen (dirname);
+ separator_needed = dirlen != 0 && dirname[dirlen - 1] != '/';
+ name = (char *) xmalloc (dirlen + strlen (FILE_NAME_MAP_FILE) + 2);
+ strcpy (name, dirname);
+ name[dirlen] = '/';
+ strcpy (name + dirlen + separator_needed, FILE_NAME_MAP_FILE);
+ f = fopen (name, "r");
+ free (name);
+ if (!f)
+ map_list_ptr->map_list_map = NULL;
+ else
+ {
+ int ch;
+
+ while ((ch = getc (f)) != EOF)
+ {
+ char *from, *to;
+ struct file_name_map *ptr;
+
+ if (is_space[ch])
+ continue;
+ from = read_filename_string (ch, f);
+ while ((ch = getc (f)) != EOF && is_hor_space[ch])
+ ;
+ to = read_filename_string (ch, f);
+
+ ptr = ((struct file_name_map *)
+ xmalloc (sizeof (struct file_name_map)));
+ ptr->map_from = from;
+
+ /* Make the real filename absolute. */
+ if (*to == '/')
+ ptr->map_to = to;
+ else
+ {
+ ptr->map_to = xmalloc (dirlen + strlen (to) + 2);
+ strcpy (ptr->map_to, dirname);
+ ptr->map_to[dirlen] = '/';
+ strcpy (ptr->map_to + dirlen + separator_needed, to);
+ free (to);
+ }
+
+ ptr->map_next = map_list_ptr->map_list_map;
+ map_list_ptr->map_list_map = ptr;
+
+ while ((ch = getc (f)) != '\n')
+ if (ch == EOF)
+ break;
+ }
+ fclose (f);
+ }
+
+ map_list_ptr->map_list_next = map_list;
+ map_list = map_list_ptr;
+
+ return map_list_ptr->map_list_map;
+}
+
+static char *
+savestring (input)
+ char *input;
+{
+ unsigned size = strlen (input);
+ char *output = xmalloc (size + 1);
+ strcpy (output, input);
+ return output;
+}
+
+static void
+ffecom_file_ (char *name)
+{
+ FILE_BUF *fp;
+
+ /* Do partial setup of input buffer for the sake of generating
+ early #line directives (when -g is in effect). */
+
+ fp = &instack[++indepth];
+ memset ((char *) fp, 0, sizeof (FILE_BUF));
+ if (name == NULL)
+ name = "";
+ fp->nominal_fname = fp->fname = name;
+}
+
+/* Initialize syntactic classifications of characters. */
+
+static void
+ffecom_initialize_char_syntax_ ()
+{
+ register int i;
+
+ /*
+ * Set up is_idchar and is_idstart tables. These should be
+ * faster than saying (is_alpha (c) || c == '_'), etc.
+ * Set up these things before calling any routines tthat
+ * refer to them.
+ */
+ for (i = 'a'; i <= 'z'; i++) {
+ is_idchar[i - 'a' + 'A'] = 1;
+ is_idchar[i] = 1;
+ is_idstart[i - 'a' + 'A'] = 1;
+ is_idstart[i] = 1;
+ }
+ for (i = '0'; i <= '9'; i++)
+ is_idchar[i] = 1;
+ is_idchar['_'] = 1;
+ is_idstart['_'] = 1;
+
+ /* horizontal space table */
+ is_hor_space[' '] = 1;
+ is_hor_space['\t'] = 1;
+ is_hor_space['\v'] = 1;
+ is_hor_space['\f'] = 1;
+ is_hor_space['\r'] = 1;
+
+ is_space[' '] = 1;
+ is_space['\t'] = 1;
+ is_space['\v'] = 1;
+ is_space['\f'] = 1;
+ is_space['\n'] = 1;
+ is_space['\r'] = 1;
+}
+
+static void
+ffecom_close_include_ (FILE *f)
+{
+ fclose (f);
+
+ indepth--;
+ input_file_stack_tick++;
+
+ ffewhere_line_kill (instack[indepth].line);
+ ffewhere_column_kill (instack[indepth].column);
+}
+
+static int
+ffecom_decode_include_option_ (char *spec)
+{
+ struct file_name_list *dirtmp;
+
+ if (! ignore_srcdir && !strcmp (spec, "-"))
+ ignore_srcdir = 1;
+ else
+ {
+ dirtmp = (struct file_name_list *)
+ xmalloc (sizeof (struct file_name_list));
+ dirtmp->next = 0; /* New one goes on the end */
+ if (spec[0] != 0)
+ dirtmp->fname = spec;
+ else
+ fatal ("Directory name must immediately follow -I option with no intervening spaces, as in `-Idir', not `-I dir'");
+ dirtmp->got_name_map = 0;
+ append_include_chain (dirtmp, dirtmp);
+ }
+ return 1;
+}
+
+/* Open INCLUDEd file. */
+
+static FILE *
+ffecom_open_include_ (char *name, ffewhereLine l, ffewhereColumn c)
+{
+ char *fbeg = name;
+ size_t flen = strlen (fbeg);
+ struct file_name_list *search_start = include; /* Chain of dirs to search */
+ struct file_name_list dsp[1]; /* First in chain, if #include "..." */
+ struct file_name_list *searchptr = 0;
+ char *fname; /* Dynamically allocated fname buffer */
+ FILE *f;
+ FILE_BUF *fp;
+
+ if (flen == 0)
+ return NULL;
+
+ dsp[0].fname = NULL;
+
+ /* If -I- was specified, don't search current dir, only spec'd ones. */
+ if (!ignore_srcdir)
+ {
+ for (fp = &instack[indepth]; fp >= instack; fp--)
+ {
+ int n;
+ char *ep;
+ char *nam;
+
+ if ((nam = fp->nominal_fname) != NULL)
+ {
+ /* Found a named file. Figure out dir of the file,
+ and put it in front of the search list. */
+ dsp[0].next = search_start;
+ search_start = dsp;
+#ifndef VMS
+ ep = rindex (nam, '/');
+#ifdef DIR_SEPARATOR
+ if (ep == NULL) ep = rindex (nam, DIR_SEPARATOR);
+ else {
+ char *tmp = rindex (nam, DIR_SEPARATOR);
+ if (tmp != NULL && tmp > ep) ep = tmp;
+ }
+#endif
+#else /* VMS */
+ ep = rindex (nam, ']');
+ if (ep == NULL) ep = rindex (nam, '>');
+ if (ep == NULL) ep = rindex (nam, ':');
+ if (ep != NULL) ep++;
+#endif /* VMS */
+ if (ep != NULL)
+ {
+ n = ep - nam;
+ dsp[0].fname = (char *) xmalloc (n + 1);
+ strncpy (dsp[0].fname, nam, n);
+ dsp[0].fname[n] = '\0';
+ if (n + INCLUDE_LEN_FUDGE > max_include_len)
+ max_include_len = n + INCLUDE_LEN_FUDGE;
+ }
+ else
+ dsp[0].fname = NULL; /* Current directory */
+ dsp[0].got_name_map = 0;
+ break;
+ }
+ }
+ }
+
+ /* Allocate this permanently, because it gets stored in the definitions
+ of macros. */
+ fname = xmalloc (max_include_len + flen + 4);
+ /* + 2 above for slash and terminating null. */
+ /* + 2 added for '.h' on VMS (to support '#include filename') (NOT USED
+ for g77 yet). */
+
+ /* If specified file name is absolute, just open it. */
+
+ if (*fbeg == '/'
+#ifdef DIR_SEPARATOR
+ || *fbeg == DIR_SEPARATOR
+#endif
+ )
+ {
+ strncpy (fname, (char *) fbeg, flen);
+ fname[flen] = 0;
+ f = open_include_file (fname, NULL_PTR);
+ }
+ else
+ {
+ f = NULL;
+
+ /* Search directory path, trying to open the file.
+ Copy each filename tried into FNAME. */
+
+ for (searchptr = search_start; searchptr; searchptr = searchptr->next)
+ {
+ if (searchptr->fname)
+ {
+ /* The empty string in a search path is ignored.
+ This makes it possible to turn off entirely
+ a standard piece of the list. */
+ if (searchptr->fname[0] == 0)
+ continue;
+ strcpy (fname, skip_redundant_dir_prefix (searchptr->fname));
+ if (fname[0] && fname[strlen (fname) - 1] != '/')
+ strcat (fname, "/");
+ fname[strlen (fname) + flen] = 0;
+ }
+ else
+ fname[0] = 0;
+
+ strncat (fname, fbeg, flen);
+#ifdef VMS
+ /* Change this 1/2 Unix 1/2 VMS file specification into a
+ full VMS file specification */
+ if (searchptr->fname && (searchptr->fname[0] != 0))
+ {
+ /* Fix up the filename */
+ hack_vms_include_specification (fname);
+ }
+ else
+ {
+ /* This is a normal VMS filespec, so use it unchanged. */
+ strncpy (fname, (char *) fbeg, flen);
+ fname[flen] = 0;
+#if 0 /* Not for g77. */
+ /* if it's '#include filename', add the missing .h */
+ if (index (fname, '.') == NULL)
+ strcat (fname, ".h");
+#endif
+ }
+#endif /* VMS */
+ f = open_include_file (fname, searchptr);
+#ifdef EACCES
+ if (f == NULL && errno == EACCES)
+ {
+ print_containing_files (FFEBAD_severityWARNING);
+ ffebad_start_msg ("At %0, INCLUDE file %A exists, but is not readable",
+ FFEBAD_severityWARNING);
+ ffebad_string (fname);
+ ffebad_here (0, l, c);
+ ffebad_finish ();
+ }
+#endif
+ if (f != NULL)
+ break;
+ }
+ }
+
+ if (f == NULL)
+ {
+ /* A file that was not found. */
+
+ strncpy (fname, (char *) fbeg, flen);
+ fname[flen] = 0;
+ print_containing_files (ffebad_severity (FFEBAD_OPEN_INCLUDE));
+ ffebad_start (FFEBAD_OPEN_INCLUDE);
+ ffebad_here (0, l, c);
+ ffebad_string (fname);
+ ffebad_finish ();
+ }
+
+ if (dsp[0].fname != NULL)
+ free (dsp[0].fname);
+
+ if (f == NULL)
+ return NULL;
+
+ if (indepth >= (INPUT_STACK_MAX - 1))
+ {
+ print_containing_files (FFEBAD_severityFATAL);
+ ffebad_start_msg ("At %0, INCLUDE nesting too deep",
+ FFEBAD_severityFATAL);
+ ffebad_string (fname);
+ ffebad_here (0, l, c);
+ ffebad_finish ();
+ return NULL;
+ }
+
+ instack[indepth].line = ffewhere_line_use (l);
+ instack[indepth].column = ffewhere_column_use (c);
+
+ fp = &instack[indepth + 1];
+ memset ((char *) fp, 0, sizeof (FILE_BUF));
+ fp->nominal_fname = fp->fname = fname;
+ fp->dir = searchptr;
+
+ indepth++;
+ input_file_stack_tick++;
+
+ return f;
+}
+#endif /* FFECOM_GCC_INCLUDE */
diff --git a/contrib/gcc/f/com.h b/contrib/gcc/f/com.h
new file mode 100644
index 0000000..db8f469
--- /dev/null
+++ b/contrib/gcc/f/com.h
@@ -0,0 +1,376 @@
+/* com.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ com.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_com
+#define _H_f_com
+
+/* Simple definitions and enumerations. */
+
+#define FFECOM_dimensionsMAX 7 /* Max # dimensions (quick hack). */
+
+#define FFECOM_targetFFE 1
+#define FFECOM_targetGCC 2
+
+#ifndef FFE_STANDALONE
+#define FFECOM_targetCURRENT FFECOM_targetGCC /* Backend! */
+#define FFECOM_ONEPASS 0
+#else
+#define FFECOM_targetCURRENT FFECOM_targetFFE
+#define FFECOM_ONEPASS 0
+#endif
+
+#if FFECOM_ONEPASS
+#define FFECOM_TWOPASS 0
+#else
+#define FFECOM_TWOPASS 1
+#endif
+
+#define FFECOM_SIZE_UNIT "byte" /* Singular form. */
+#define FFECOM_SIZE_UNITS "bytes" /* Plural form. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define FFECOM_constantNULL NULL_TREE
+#define FFECOM_globalNULL NULL_TREE
+#define FFECOM_labelNULL NULL_TREE
+#define FFECOM_storageNULL NULL_TREE
+#define FFECOM_symbolNULL ffecom_symbol_null_
+
+/* Shorthand for types used in f2c.h and that g77 perhaps allows some
+ flexibility regarding in the section below. I.e. the actual numbers
+ below aren't important, as long as they're unique. */
+
+#define FFECOM_f2ccodeCHAR 1
+#define FFECOM_f2ccodeSHORT 2
+#define FFECOM_f2ccodeINT 3
+#define FFECOM_f2ccodeLONG 4
+#define FFECOM_f2ccodeLONGLONG 5
+#define FFECOM_f2ccodeCHARPTR 6 /* char * */
+#define FFECOM_f2ccodeFLOAT 7
+#define FFECOM_f2ccodeDOUBLE 8
+#define FFECOM_f2ccodeLONGDOUBLE 9
+#define FFECOM_f2ccodeTWOREALS 10
+#define FFECOM_f2ccodeTWODOUBLEREALS 11
+
+#if FFECOM_DETERMINE_TYPES /* only for com.c and configure */
+
+/* Begin f2c.h information. This must match the info in the f2c.h used
+ to build the libf2c with which g77-generated code is linked, or there
+ will probably be bugs, some of them difficult to detect or even trigger. */
+
+/* Do we need int (for 32-bit or 64-bit systems) or long (16-bit or
+ normally 32-bit) for f2c-type integers? */
+
+#ifndef BITS_PER_WORD
+#define BITS_PER_WORD 32
+#endif
+
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+
+#ifndef SHORT_TYPE_SIZE
+#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
+#endif
+
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_LONG_TYPE_SIZE
+#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef WCHAR_UNSIGNED
+#define WCHAR_UNSIGNED 0
+#endif
+
+#ifndef FLOAT_TYPE_SIZE
+#define FLOAT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef DOUBLE_TYPE_SIZE
+#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#if LONG_TYPE_SIZE == FLOAT_TYPE_SIZE
+# define FFECOM_f2cINTEGER FFECOM_f2ccodeLONG
+# define FFECOM_f2cLOGICAL FFECOM_f2ccodeLONG
+#elif INT_TYPE_SIZE == FLOAT_TYPE_SIZE
+# define FFECOM_f2cINTEGER FFECOM_f2ccodeINT
+# define FFECOM_f2cLOGICAL FFECOM_f2ccodeINT
+#else
+# error Cannot find a suitable type for FFECOM_f2cINTEGER
+#endif
+
+#if LONG_TYPE_SIZE == (FLOAT_TYPE_SIZE * 2)
+# define FFECOM_f2cLONGINT FFECOM_f2ccodeLONG
+#elif LONG_LONG_TYPE_SIZE == (FLOAT_TYPE_SIZE * 2)
+# define FFECOM_f2cLONGINT FFECOM_f2ccodeLONGLONG
+#else
+# error Cannot find a suitable type for FFECOM_f2cLONGINT
+#endif
+
+#define FFECOM_f2cADDRESS FFECOM_f2ccodeCHARPTR
+#define FFECOM_f2cSHORTINT FFECOM_f2ccodeSHORT
+#define FFECOM_f2cREAL FFECOM_f2ccodeFLOAT
+#define FFECOM_f2cDOUBLEREAL FFECOM_f2ccodeDOUBLE
+#define FFECOM_f2cCOMPLEX FFECOM_f2ccodeTWOREALS
+#define FFECOM_f2cDOUBLECOMPLEX FFECOM_f2ccodeTWODOUBLEREALS
+#define FFECOM_f2cSHORTLOGICAL FFECOM_f2ccodeSHORT
+#define FFECOM_f2cLOGICAL1 FFECOM_f2ccodeCHAR
+#define FFECOM_f2cINTEGER1 FFECOM_f2ccodeCHAR
+
+/* These must be f2c's INTEGER type, to match runtime/f2c.h.in. */
+
+#define FFECOM_f2cFLAG FFECOM_f2cINTEGER
+#define FFECOM_f2cFTNINT FFECOM_f2cINTEGER
+#define FFECOM_f2cFTNLEN FFECOM_f2cINTEGER
+
+#endif /* #if FFECOM_DETERMINE_TYPES */
+
+/* Everything else in f2c.h, specifically the structures used in
+ interfacing compiled code with the library, must remain exactly
+ as delivered, or g77 internals (mostly com.c and ste.c) must
+ be modified accordingly to compensate. Or there will be...trouble. */
+
+typedef enum
+ {
+#define DEFGFRT(CODE,NAME,TYPE,ARGS,VOLATILE,COMPLEX) CODE,
+#include "com-rt.def"
+#undef DEFGFRT
+ FFECOM_gfrt
+ } ffecomGfrt;
+
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+/* Typedefs. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#ifndef TREE_CODE
+#include "tree.j"
+#endif
+
+#ifndef BUILT_FOR_270
+#ifdef DECL_STATIC_CONSTRUCTOR /* In gcc/tree.h. */
+#define BUILT_FOR_270 1
+#else
+#define BUILT_FOR_270 0
+#endif
+#endif /* !defined (BUILT_FOR_270) */
+
+#ifndef BUILT_FOR_280
+#ifdef DECL_ONE_ONLY /* In gcc/tree.h. */
+#define BUILT_FOR_280 1
+#else
+#define BUILT_FOR_280 0
+#endif
+#endif /* !defined (BUILT_FOR_280) */
+
+typedef tree ffecomConstant;
+#define FFECOM_constantHOOK
+typedef tree ffecomLabel;
+#define FFECOM_globalHOOK
+typedef tree ffecomGlobal;
+#define FFECOM_labelHOOK
+typedef tree ffecomStorage;
+#define FFECOM_storageHOOK
+typedef struct _ffecom_symbol_ ffecomSymbol;
+#define FFECOM_symbolHOOK
+
+struct _ffecom_symbol_
+ {
+ tree decl_tree;
+ tree length_tree; /* For CHARACTER dummies. */
+ tree vardesc_tree; /* For NAMELIST. */
+ tree assign_tree; /* For ASSIGN'ed vars. */
+ bool addr; /* Is address of item instead of item. */
+ };
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+/* Include files needed by this one. */
+
+#include "bld.h"
+#include "info.h"
+#include "lab.h"
+#include "storag.h"
+#include "symbol.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+extern tree long_integer_type_node;
+extern tree complex_double_type_node;
+extern tree string_type_node;
+extern tree ffecom_integer_type_node;
+extern tree ffecom_integer_zero_node;
+extern tree ffecom_integer_one_node;
+extern tree ffecom_tree_type[FFEINFO_basictype][FFEINFO_kindtype];
+extern ffecomSymbol ffecom_symbol_null_;
+extern ffeinfoKindtype ffecom_pointer_kind_;
+extern ffeinfoKindtype ffecom_label_kind_;
+
+extern int ffecom_f2c_typecode_[FFEINFO_basictype][FFEINFO_kindtype];
+extern tree ffecom_f2c_integer_type_node;
+extern tree ffecom_f2c_address_type_node;
+extern tree ffecom_f2c_real_type_node;
+extern tree ffecom_f2c_doublereal_type_node;
+extern tree ffecom_f2c_complex_type_node;
+extern tree ffecom_f2c_doublecomplex_type_node;
+extern tree ffecom_f2c_longint_type_node;
+extern tree ffecom_f2c_logical_type_node;
+extern tree ffecom_f2c_flag_type_node;
+extern tree ffecom_f2c_ftnlen_type_node;
+extern tree ffecom_f2c_ftnlen_zero_node;
+extern tree ffecom_f2c_ftnlen_one_node;
+extern tree ffecom_f2c_ftnlen_two_node;
+extern tree ffecom_f2c_ptr_to_ftnlen_type_node;
+extern tree ffecom_f2c_ftnint_type_node;
+extern tree ffecom_f2c_ptr_to_ftnint_type_node;
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+/* Declare functions with prototypes. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree ffecom_1 (enum tree_code code, tree type, tree node);
+tree ffecom_1_fn (tree node);
+tree ffecom_2 (enum tree_code code, tree type, tree node1, tree node2);
+bool ffecom_2pass_advise_entrypoint (ffesymbol entry);
+void ffecom_2pass_do_entrypoint (ffesymbol entry);
+tree ffecom_2s (enum tree_code code, tree type, tree node1, tree node2);
+tree ffecom_3 (enum tree_code code, tree type, tree node1, tree node2,
+ tree node3);
+tree ffecom_3s (enum tree_code code, tree type, tree node1, tree node2,
+ tree node3);
+tree ffecom_arg_expr (ffebld expr, tree *length);
+tree ffecom_arg_ptr_to_expr (ffebld expr, tree *length);
+tree ffecom_call_gfrt (ffecomGfrt ix, tree args);
+tree ffecom_constantunion (ffebldConstantUnion *cu, ffeinfoBasictype bt,
+ ffeinfoKindtype kt, tree tree_type);
+tree ffecom_decl_field (tree context, tree prevfield, char *name,
+ tree type);
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+void ffecom_close_include (FILE *f);
+int ffecom_decode_include_option (char *spec);
+void ffecom_end_transition (void);
+void ffecom_exec_transition (void);
+void ffecom_expand_let_stmt (ffebld dest, ffebld source);
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+tree ffecom_expr (ffebld expr);
+tree ffecom_expr_assign (ffebld expr);
+tree ffecom_expr_assign_w (ffebld expr);
+tree ffecom_expr_rw (ffebld expr);
+void ffecom_finish_compile (void);
+void ffecom_finish_decl (tree decl, tree init, bool is_top_level);
+void ffecom_finish_progunit (void);
+tree ffecom_get_invented_identifier (char *pattern, char *text,
+ int number);
+ffeinfoKindtype ffecom_gfrt_basictype (ffecomGfrt ix);
+ffeinfoKindtype ffecom_gfrt_kindtype (ffecomGfrt ix);
+void ffecom_init_0 (void);
+void ffecom_init_2 (void);
+tree ffecom_list_expr (ffebld list);
+tree ffecom_list_ptr_to_expr (ffebld list);
+tree ffecom_lookup_label (ffelab label);
+tree ffecom_modify (tree newtype, tree lhs, tree rhs);
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+void ffecom_file (char *name);
+void ffecom_notify_init_storage (ffestorag st);
+void ffecom_notify_init_symbol (ffesymbol s);
+void ffecom_notify_primary_entry (ffesymbol fn);
+FILE *ffecom_open_include (char *name, ffewhereLine l, ffewhereColumn c);
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void ffecom_pop_calltemps (void);
+void ffecom_pop_tempvar (tree var);
+tree ffecom_ptr_to_expr (ffebld expr);
+void ffecom_push_calltemps (void);
+tree ffecom_push_tempvar (tree type, ffetargetCharacterSize size,
+ int elements, bool auto_pop);
+tree ffecom_return_expr (ffebld expr);
+tree ffecom_save_tree (tree t);
+tree ffecom_start_decl (tree decl, bool is_init);
+void ffecom_sym_commit (ffesymbol s);
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+ffesymbol ffecom_sym_end_transition (ffesymbol s);
+ffesymbol ffecom_sym_exec_transition (ffesymbol s);
+ffesymbol ffecom_sym_learned (ffesymbol s);
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void ffecom_sym_retract (ffesymbol s);
+tree ffecom_temp_label (void);
+tree ffecom_truth_value (tree expr);
+tree ffecom_truth_value_invert (tree expr);
+tree ffecom_which_entrypoint_decl (void);
+
+/* These need to be in the front end with exactly these interfaces,
+ as they're called by the back end. */
+
+int mark_addressable (tree expr);
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+/* Define macros. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+#define ffecom_expr(e) (e)
+#define ffecom_init_0()
+#define ffecom_init_2()
+#define ffecom_label_kind() FFEINFO_kindtypeINTEGERDEFAULT
+#define ffecom_pointer_kind() FFEINFO_kindtypeINTEGERDEFAULT
+#define ffecom_ptr_to_expr(e) (e)
+#define ffecom_sym_commit(s)
+#define ffecom_sym_retract(s)
+#endif /* FFECOM_targetCURRENT == FFECOM_targetFFE */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define ffecom_f2c_typecode(bt,kt) ffecom_f2c_typecode_[(bt)][(kt)]
+#define ffecom_label_kind() ffecom_label_kind_
+#define ffecom_pointer_kind() ffecom_pointer_kind_
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+#define ffecom_init_1()
+#define ffecom_init_3()
+#define ffecom_init_4()
+#define ffecom_terminate_0()
+#define ffecom_terminate_1()
+#define ffecom_terminate_2()
+#define ffecom_terminate_3()
+#define ffecom_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/config-lang.in b/contrib/gcc/f/config-lang.in
new file mode 100644
index 0000000..504bc20
--- /dev/null
+++ b/contrib/gcc/f/config-lang.in
@@ -0,0 +1,37 @@
+# Top level configure fragment for GNU FORTRAN.
+# Copyright (C) 1995-1997 Free Software Foundation, Inc.
+
+#This file is part of GNU Fortran.
+
+#GNU Fortran 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, or (at your option)
+#any later version.
+
+#GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+#the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+#02111-1307, USA.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language - name of language as it would appear in $(LANGUAGES)
+# compilers - value to add to $(COMPILERS)
+# stagestuff - files to add to $(STAGESTUFF)
+# diff_excludes - files to ignore when building diffs between two versions.
+
+language="f77"
+
+compilers="f771\$(exeext)"
+
+stagestuff="g77\$(exeext) g77-cross\$(exeext) f771\$(exeext)"
+
+diff_excludes="-x f/BUGS -x f/NEWS -x f/INSTALL -x f/intdoc.texi"
+
+outputs=f/Makefile
diff --git a/contrib/gcc/f/config.j b/contrib/gcc/f/config.j
new file mode 100644
index 0000000..3fd1c11
--- /dev/null
+++ b/contrib/gcc/f/config.j
@@ -0,0 +1,27 @@
+/* config.j -- Wrapper for GCC's config.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_config
+#define _J_f_config
+#include "config.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/convert.j b/contrib/gcc/f/convert.j
new file mode 100644
index 0000000..85e3af8
--- /dev/null
+++ b/contrib/gcc/f/convert.j
@@ -0,0 +1,28 @@
+/* convert.j -- Wrapper for GCC's convert.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_convert
+#define _J_f_convert
+#include "tree.j"
+#include "convert.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/data.c b/contrib/gcc/f/data.c
new file mode 100644
index 0000000..a8acd5c
--- /dev/null
+++ b/contrib/gcc/f/data.c
@@ -0,0 +1,1816 @@
+/* data.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+
+ Description:
+ Do the tough things for DATA statement (and INTEGER FOO/.../-style
+ initializations), like implied-DO and suchlike.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "data.h"
+#include "bit.h"
+#include "bld.h"
+#include "com.h"
+#include "expr.h"
+#include "global.h"
+#include "malloc.h"
+#include "st.h"
+#include "storag.h"
+#include "top.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+/* I picked this value as one that, when plugged into a couple of small
+ but nearly identical test cases I have called BIG-0.f and BIG-1.f,
+ causes BIG-1.f to take about 10 times as long (elapsed) to compile
+ (in f771 only) as BIG-0.f. These test cases differ in that BIG-0.f
+ doesn't put the one initialized variable in a common area that has
+ a large uninitialized array in it, while BIG-1.f does. The size of
+ the array is this many elements, as long as they all are INTEGER
+ type. Note that, as of 0.5.18, sparse cases are better handled,
+ so BIG-2.f now is used; it provides nonzero initial
+ values for all elements of the same array BIG-0 has. */
+#ifndef FFEDATA_sizeTOO_BIG_INIT_
+#define FFEDATA_sizeTOO_BIG_INIT_ 75*1024
+#endif
+
+/* Internal typedefs. */
+
+typedef struct _ffedata_convert_cache_ *ffedataConvertCache_;
+typedef struct _ffedata_impdo_ *ffedataImpdo_;
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+struct _ffedata_convert_cache_
+ {
+ ffebld converted; /* Results of converting expr to following
+ type. */
+ ffeinfoBasictype basic_type;
+ ffeinfoKindtype kind_type;
+ ffetargetCharacterSize size;
+ ffeinfoRank rank;
+ };
+
+struct _ffedata_impdo_
+ {
+ ffedataImpdo_ outer; /* Enclosing IMPDO construct. */
+ ffebld outer_list; /* Item after my IMPDO on the outer list. */
+ ffebld my_list; /* Beginning of list in my IMPDO. */
+ ffesymbol itervar; /* Iteration variable. */
+ ffetargetIntegerDefault increment;
+ ffetargetIntegerDefault final;
+ };
+
+/* Static objects accessed by functions in this module. */
+
+static ffedataImpdo_ ffedata_stack_ = NULL;
+static ffebld ffedata_list_ = NULL;
+static bool ffedata_reinit_; /* value_ should report REINIT error. */
+static bool ffedata_reported_error_; /* Error has been reported. */
+static ffesymbol ffedata_symbol_ = NULL; /* Symbol being initialized. */
+static ffeinfoBasictype ffedata_basictype_; /* Info on symbol. */
+static ffeinfoKindtype ffedata_kindtype_;
+static ffestorag ffedata_storage_; /* If non-NULL, inits go into this parent. */
+static ffeinfoBasictype ffedata_storage_bt_; /* Info on storage. */
+static ffeinfoKindtype ffedata_storage_kt_;
+static ffetargetOffset ffedata_storage_size_; /* Size of entire storage. */
+static ffetargetAlign ffedata_storage_units_; /* #units per storage unit. */
+static ffetargetOffset ffedata_arraysize_; /* Size of array being
+ inited. */
+static ffetargetOffset ffedata_expected_; /* Number of elements to
+ init. */
+static ffetargetOffset ffedata_number_; /* #elements inited so far. */
+static ffetargetOffset ffedata_offset_; /* Offset of next element. */
+static ffetargetOffset ffedata_symbolsize_; /* Size of entire sym. */
+static ffetargetCharacterSize ffedata_size_; /* Size of an element. */
+static ffetargetCharacterSize ffedata_charexpected_; /* #char to init. */
+static ffetargetCharacterSize ffedata_charnumber_; /* #chars inited. */
+static ffetargetCharacterSize ffedata_charoffset_; /* Offset of next char. */
+static ffedataConvertCache_ ffedata_convert_cache_; /* Fewer conversions. */
+static int ffedata_convert_cache_max_ = 0; /* #entries available. */
+static int ffedata_convert_cache_use_ = 0; /* #entries in use. */
+
+/* Static functions (internal). */
+
+static bool ffedata_advance_ (void);
+static ffebld ffedata_convert_ (ffebld source, ffelexToken source_token,
+ ffelexToken dest_token, ffeinfoBasictype bt, ffeinfoKindtype kt,
+ ffeinfoRank rk, ffetargetCharacterSize sz);
+static ffetargetInteger1 ffedata_eval_integer1_ (ffebld expr);
+static ffetargetOffset ffedata_eval_offset_ (ffebld subscripts,
+ ffebld dims);
+static ffetargetCharacterSize ffedata_eval_substr_begin_ (ffebld expr);
+static ffetargetCharacterSize ffedata_eval_substr_end_ (ffebld expr,
+ ffetargetCharacterSize min, ffetargetCharacterSize max);
+static void ffedata_gather_ (ffestorag mst, ffestorag st);
+static void ffedata_pop_ (void);
+static void ffedata_push_ (void);
+static bool ffedata_value_ (ffebld value, ffelexToken token);
+
+/* Internal macros. */
+
+
+/* ffedata_begin -- Initialize with list of targets
+
+ ffebld list;
+ ffedata_begin(list); // ITEM... list of SYMTERs, ARRAYs, SUBSTRs, ...
+
+ Remember the list. After this call, 0...n calls to ffedata_value must
+ follow, and then a single call to ffedata_end. */
+
+void
+ffedata_begin (ffebld list)
+{
+ assert (ffedata_list_ == NULL);
+ ffedata_list_ = list;
+ ffedata_symbol_ = NULL;
+ ffedata_reported_error_ = FALSE;
+ ffedata_reinit_ = FALSE;
+ ffedata_advance_ ();
+}
+
+/* ffedata_end -- End of initialization sequence
+
+ if (ffedata_end(FALSE))
+ // everything's ok
+
+ Make sure the end of the list is valid here. */
+
+bool
+ffedata_end (bool reported_error, ffelexToken t)
+{
+ reported_error |= ffedata_reported_error_;
+
+ /* If still targets to initialize, too few initializers, so complain. */
+
+ if ((ffedata_symbol_ != NULL) && !reported_error)
+ {
+ reported_error = TRUE;
+ ffebad_start (FFEBAD_DATA_TOOFEW);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ }
+
+ /* Pop off any impdo stacks (present only if ffedata_symbol_ != NULL). */
+
+ while (ffedata_stack_ != NULL)
+ ffedata_pop_ ();
+
+ if (ffedata_list_ != NULL)
+ {
+ assert (reported_error);
+ ffedata_list_ = NULL;
+ }
+
+ return TRUE;
+}
+
+/* ffedata_gather -- Gather previously disparate initializations into one place
+
+ ffestorag st; // A typeCBLOCK or typeLOCAL aggregate.
+ ffedata_gather(st);
+
+ Prior to this call, st has no init or accretion info, but (presumably
+ at least one of) its subordinate storage areas has init or accretion
+ info. After this call, none of the subordinate storage areas has inits,
+ because they've all been moved into the newly created init/accretion
+ info for st. During this call, conflicting inits produce only one
+ error message. */
+
+void
+ffedata_gather (ffestorag st)
+{
+ ffesymbol s;
+ ffebld b;
+
+ /* Prepare info on the storage area we're putting init info into. */
+
+ ffetarget_aggregate_info (&ffedata_storage_bt_, &ffedata_storage_kt_,
+ &ffedata_storage_units_, ffestorag_basictype (st),
+ ffestorag_kindtype (st));
+ ffedata_storage_size_ = ffestorag_size (st) / ffedata_storage_units_;
+ assert (ffestorag_size (st) % ffedata_storage_units_ == 0);
+
+ /* If a CBLOCK, gather all the init info for its explicit members. */
+
+ if ((ffestorag_type (st) == FFESTORAG_typeCBLOCK)
+ && (ffestorag_symbol (st) != NULL))
+ {
+ s = ffestorag_symbol (st);
+ for (b = ffesymbol_commonlist (s); b != NULL; b = ffebld_trail (b))
+ ffedata_gather_ (st,
+ ffesymbol_storage (ffebld_symter (ffebld_head (b))));
+ }
+
+ /* For CBLOCK or LOCAL, gather all the init info for equivalenced members. */
+
+ ffestorag_drive (ffestorag_list_equivs (st), ffedata_gather_, st);
+}
+
+/* ffedata_value -- Provide some number of initial values
+
+ ffebld value;
+ ffelexToken t; // Points to the value.
+ if (ffedata_value(1,value,t))
+ // Everything's ok
+
+ Makes sure the value is ok, then remembers it according to the list
+ provided to ffedata_begin. As many instances of the value may be
+ supplied as desired, as indicated by the first argument. */
+
+bool
+ffedata_value (ffetargetIntegerDefault rpt, ffebld value, ffelexToken token)
+{
+ ffetargetIntegerDefault i;
+
+ /* Maybe ignore zero values, to speed up compiling, even though we lose
+ checking for multiple initializations for now. */
+
+ if (!ffe_is_zeros ()
+ && (value != NULL)
+ && (ffebld_op (value) == FFEBLD_opCONTER)
+ && ffebld_constant_is_zero (ffebld_conter (value)))
+ value = NULL;
+ else if ((value != NULL)
+ && (ffebld_op (value) == FFEBLD_opANY))
+ value = NULL;
+ else
+ {
+ /* Must be a constant. */
+ assert (value != NULL);
+ assert (ffebld_op (value) == FFEBLD_opCONTER);
+ }
+
+ /* Later we can optimize certain cases by seeing that the target array can
+ take some number of values, and provide this number to _value_. */
+
+ if (rpt == 1)
+ ffedata_convert_cache_use_ = -1; /* Don't bother caching. */
+ else
+ ffedata_convert_cache_use_ = 0; /* Maybe use the cache. */
+
+ for (i = 0; i < rpt; ++i)
+ {
+ if ((ffedata_symbol_ != NULL)
+ && !ffesymbol_is_init (ffedata_symbol_))
+ {
+ ffesymbol_signal_change (ffedata_symbol_);
+ ffesymbol_update_init (ffedata_symbol_);
+ if (1 || ffe_is_90 ())
+ ffesymbol_update_save (ffedata_symbol_);
+#if FFEGLOBAL_ENABLED
+ if (ffesymbol_common (ffedata_symbol_) != NULL)
+ ffeglobal_init_common (ffesymbol_common (ffedata_symbol_),
+ token);
+#endif
+ ffesymbol_signal_unreported (ffedata_symbol_);
+ }
+ if (!ffedata_value_ (value, token))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* ffedata_advance_ -- Advance initialization target to next item in list
+
+ if (ffedata_advance_())
+ // everything's ok
+
+ Sets common info to characterize the next item in the list. Handles
+ IMPDO constructs accordingly. Does not handle advances within a single
+ item, as in the common extension "DATA CHARTYPE/33,34,35/", where
+ CHARTYPE is CHARACTER*3, for example. */
+
+static bool
+ffedata_advance_ ()
+{
+ ffebld next;
+
+ /* Come here after handling an IMPDO. */
+
+tail_recurse: /* :::::::::::::::::::: */
+
+ /* Assume we're not going to find a new target for now. */
+
+ ffedata_symbol_ = NULL;
+
+ /* If at the end of the list, we're done. */
+
+ if (ffedata_list_ == NULL)
+ {
+ ffetargetIntegerDefault newval;
+
+ if (ffedata_stack_ == NULL)
+ return TRUE; /* No IMPDO in progress, we is done! */
+
+ /* Iterate the IMPDO. */
+
+ newval = ffesymbol_value (ffedata_stack_->itervar)
+ + ffedata_stack_->increment;
+
+ /* See if we're still in the loop. */
+
+ if (((ffedata_stack_->increment > 0)
+ ? newval > ffedata_stack_->final
+ : newval < ffedata_stack_->final)
+ || (((ffesymbol_value (ffedata_stack_->itervar) < 0)
+ == (ffedata_stack_->increment < 0))
+ && ((ffesymbol_value (ffedata_stack_->itervar) < 0)
+ != (newval < 0)))) /* Overflow/underflow? */
+ { /* Done with the loop. */
+ ffedata_list_ = ffedata_stack_->outer_list; /* Restore list. */
+ ffedata_pop_ (); /* Pop me off the impdo stack. */
+ }
+ else
+ { /* Still in the loop, reset the list and
+ update the iter var. */
+ ffedata_list_ = ffedata_stack_->my_list; /* Reset list. */
+ ffesymbol_set_value (ffedata_stack_->itervar, newval);
+ }
+ goto tail_recurse; /* :::::::::::::::::::: */
+ }
+
+ /* Move to the next item in the list. */
+
+ next = ffebld_head (ffedata_list_);
+ ffedata_list_ = ffebld_trail (ffedata_list_);
+
+ /* Really shouldn't happen. */
+
+ if (next == NULL)
+ return TRUE;
+
+ /* See what kind of target this is. */
+
+ switch (ffebld_op (next))
+ {
+ case FFEBLD_opSYMTER: /* Simple reference to scalar or array. */
+ ffedata_symbol_ = ffebld_symter (next);
+ ffedata_storage_ = (ffesymbol_storage (ffedata_symbol_) == NULL) ? NULL
+ : ffestorag_parent (ffesymbol_storage (ffedata_symbol_));
+ if (ffedata_storage_ != NULL)
+ {
+ ffetarget_aggregate_info (&ffedata_storage_bt_, &ffedata_storage_kt_,
+ &ffedata_storage_units_,
+ ffestorag_basictype (ffedata_storage_),
+ ffestorag_kindtype (ffedata_storage_));
+ ffedata_storage_size_ = ffestorag_size (ffedata_storage_)
+ / ffedata_storage_units_;
+ assert (ffestorag_size (ffedata_storage_) % ffedata_storage_units_ == 0);
+ }
+
+ if ((ffesymbol_init (ffedata_symbol_) != NULL)
+ || (ffesymbol_accretion (ffedata_symbol_) != NULL)
+ || ((ffedata_storage_ != NULL)
+ && (ffestorag_init (ffedata_storage_) != NULL)))
+ {
+#if 0
+ ffebad_start (FFEBAD_DATA_REINIT);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+#else
+ ffedata_reinit_ = TRUE;
+ return TRUE;
+#endif
+ }
+ ffedata_basictype_ = ffesymbol_basictype (ffedata_symbol_);
+ ffedata_kindtype_ = ffesymbol_kindtype (ffedata_symbol_);
+ if (ffesymbol_rank (ffedata_symbol_) == 0)
+ ffedata_arraysize_ = 1;
+ else
+ {
+ ffebld size = ffesymbol_arraysize (ffedata_symbol_);
+
+ assert (size != NULL);
+ assert (ffebld_op (size) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (size))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (size))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_arraysize_ = ffebld_constant_integerdefault (ffebld_conter
+ (size));
+ }
+ ffedata_expected_ = ffedata_arraysize_;
+ ffedata_number_ = 0;
+ ffedata_offset_ = 0;
+ ffedata_size_ = (ffedata_basictype_ == FFEINFO_basictypeCHARACTER)
+ ? ffesymbol_size (ffedata_symbol_) : 1;
+ ffedata_symbolsize_ = ffedata_size_ * ffedata_arraysize_;
+ ffedata_charexpected_ = ffedata_size_;
+ ffedata_charnumber_ = 0;
+ ffedata_charoffset_ = 0;
+ break;
+
+ case FFEBLD_opARRAYREF: /* Reference to element of array. */
+ ffedata_symbol_ = ffebld_symter (ffebld_left (next));
+ ffedata_storage_ = (ffesymbol_storage (ffedata_symbol_) == NULL) ? NULL
+ : ffestorag_parent (ffesymbol_storage (ffedata_symbol_));
+ if (ffedata_storage_ != NULL)
+ {
+ ffetarget_aggregate_info (&ffedata_storage_bt_, &ffedata_storage_kt_,
+ &ffedata_storage_units_,
+ ffestorag_basictype (ffedata_storage_),
+ ffestorag_kindtype (ffedata_storage_));
+ ffedata_storage_size_ = ffestorag_size (ffedata_storage_)
+ / ffedata_storage_units_;
+ assert (ffestorag_size (ffedata_storage_) % ffedata_storage_units_ == 0);
+ }
+
+ if ((ffesymbol_init (ffedata_symbol_) != NULL)
+ || ((ffedata_storage_ != NULL)
+ && (ffestorag_init (ffedata_storage_) != NULL)))
+ {
+#if 0
+ ffebad_start (FFEBAD_DATA_REINIT);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+#else
+ ffedata_reinit_ = TRUE;
+ return TRUE;
+#endif
+ }
+ ffedata_basictype_ = ffesymbol_basictype (ffedata_symbol_);
+ ffedata_kindtype_ = ffesymbol_kindtype (ffedata_symbol_);
+ if (ffesymbol_rank (ffedata_symbol_) == 0)
+ ffedata_arraysize_ = 1; /* Shouldn't happen in this case... */
+ else
+ {
+ ffebld size = ffesymbol_arraysize (ffedata_symbol_);
+
+ assert (size != NULL);
+ assert (ffebld_op (size) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (size))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (size))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_arraysize_ = ffebld_constant_integerdefault (ffebld_conter
+ (size));
+ }
+ ffedata_expected_ = 1;
+ ffedata_number_ = 0;
+ ffedata_offset_ = ffedata_eval_offset_ (ffebld_right (next),
+ ffesymbol_dims (ffedata_symbol_));
+ ffedata_size_ = (ffedata_basictype_ == FFEINFO_basictypeCHARACTER)
+ ? ffesymbol_size (ffedata_symbol_) : 1;
+ ffedata_symbolsize_ = ffedata_size_ * ffedata_arraysize_;
+ ffedata_charexpected_ = ffedata_size_;
+ ffedata_charnumber_ = 0;
+ ffedata_charoffset_ = 0;
+ break;
+
+ case FFEBLD_opSUBSTR: /* Substring reference to scalar or array
+ element. */
+ {
+ bool arrayref = ffebld_op (ffebld_left (next)) == FFEBLD_opARRAYREF;
+ ffebld colon = ffebld_right (next);
+
+ assert (colon != NULL);
+
+ ffedata_symbol_ = ffebld_symter (ffebld_left (arrayref
+ ? ffebld_left (next) : next));
+ ffedata_storage_ = (ffesymbol_storage (ffedata_symbol_) == NULL) ? NULL
+ : ffestorag_parent (ffesymbol_storage (ffedata_symbol_));
+ if (ffedata_storage_ != NULL)
+ {
+ ffetarget_aggregate_info (&ffedata_storage_bt_, &ffedata_storage_kt_,
+ &ffedata_storage_units_,
+ ffestorag_basictype (ffedata_storage_),
+ ffestorag_kindtype (ffedata_storage_));
+ ffedata_storage_size_ = ffestorag_size (ffedata_storage_)
+ / ffedata_storage_units_;
+ assert (ffestorag_size (ffedata_storage_) % ffedata_storage_units_ == 0);
+ }
+
+ if ((ffesymbol_init (ffedata_symbol_) != NULL)
+ || ((ffedata_storage_ != NULL)
+ && (ffestorag_init (ffedata_storage_) != NULL)))
+ {
+#if 0
+ ffebad_start (FFEBAD_DATA_REINIT);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+#else
+ ffedata_reinit_ = TRUE;
+ return TRUE;
+#endif
+ }
+ ffedata_basictype_ = ffesymbol_basictype (ffedata_symbol_);
+ ffedata_kindtype_ = ffesymbol_kindtype (ffedata_symbol_);
+ if (ffesymbol_rank (ffedata_symbol_) == 0)
+ ffedata_arraysize_ = 1;
+ else
+ {
+ ffebld size = ffesymbol_arraysize (ffedata_symbol_);
+
+ assert (size != NULL);
+ assert (ffebld_op (size) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (size))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (size))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_arraysize_ = ffebld_constant_integerdefault (ffebld_conter
+ (size));
+ }
+ ffedata_expected_ = arrayref ? 1 : ffedata_arraysize_;
+ ffedata_number_ = 0;
+ ffedata_offset_ = arrayref ? ffedata_eval_offset_ (ffebld_right
+ (ffebld_left (next)), ffesymbol_dims (ffedata_symbol_)) : 0;
+ ffedata_size_ = ffesymbol_size (ffedata_symbol_);
+ ffedata_symbolsize_ = ffedata_size_ * ffedata_arraysize_;
+ ffedata_charnumber_ = 0;
+ ffedata_charoffset_ = ffedata_eval_substr_begin_ (ffebld_head (colon));
+ ffedata_charexpected_ = ffedata_eval_substr_end_ (ffebld_head
+ (ffebld_trail (colon)), ffedata_charoffset_,
+ ffedata_size_) - ffedata_charoffset_ + 1;
+ }
+ break;
+
+ case FFEBLD_opIMPDO: /* Implied-DO construct. */
+ {
+ ffebld itervar;
+ ffebld start;
+ ffebld end;
+ ffebld incr;
+ ffebld item = ffebld_right (next);
+
+ itervar = ffebld_head (item);
+ item = ffebld_trail (item);
+ start = ffebld_head (item);
+ item = ffebld_trail (item);
+ end = ffebld_head (item);
+ item = ffebld_trail (item);
+ incr = ffebld_head (item);
+
+ ffedata_push_ ();
+ ffedata_stack_->outer_list = ffedata_list_;
+ ffedata_stack_->my_list = ffedata_list_ = ffebld_left (next);
+
+ assert (ffeinfo_basictype (ffebld_info (itervar))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (itervar))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_stack_->itervar = ffebld_symter (itervar);
+
+ assert (ffeinfo_basictype (ffebld_info (start))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (start))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffesymbol_set_value (ffedata_stack_->itervar, ffedata_eval_integer1_ (start));
+
+ assert (ffeinfo_basictype (ffebld_info (end))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (end))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_stack_->final = ffedata_eval_integer1_ (end);
+
+ if (incr == NULL)
+ ffedata_stack_->increment = 1;
+ else
+ {
+ assert (ffeinfo_basictype (ffebld_info (incr))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (incr))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ ffedata_stack_->increment = ffedata_eval_integer1_ (incr);
+ if (ffedata_stack_->increment == 0)
+ {
+ ffebad_start (FFEBAD_DATA_ZERO);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_stack_->itervar));
+ ffebad_finish ();
+ ffedata_pop_ ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+ }
+
+ if ((ffedata_stack_->increment > 0)
+ ? ffesymbol_value (ffedata_stack_->itervar)
+ > ffedata_stack_->final
+ : ffesymbol_value (ffedata_stack_->itervar)
+ < ffedata_stack_->final)
+ {
+ ffedata_reported_error_ = TRUE;
+ ffebad_start (FFEBAD_DATA_EMPTY);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_stack_->itervar));
+ ffebad_finish ();
+ ffedata_pop_ ();
+ return FALSE;
+ }
+ }
+ goto tail_recurse; /* :::::::::::::::::::: */
+
+ case FFEBLD_opANY:
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+
+ default:
+ assert ("bad op" == NULL);
+ break;
+ }
+
+ return TRUE;
+}
+
+/* ffedata_convert_ -- Convert source expression to given type using cache
+
+ ffebld source;
+ ffelexToken source_token;
+ ffelexToken dest_token; // Any appropriate token for "destination".
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffetargetCharactersize sz;
+ source = ffedata_convert_(source,source_token,dest_token,bt,kt,sz);
+
+ Like ffeexpr_convert, but calls it only if necessary (if the converted
+ expression doesn't already exist in the cache) and then puts the result
+ in the cache. */
+
+ffebld
+ffedata_convert_ (ffebld source, ffelexToken source_token,
+ ffelexToken dest_token, ffeinfoBasictype bt,
+ ffeinfoKindtype kt, ffeinfoRank rk,
+ ffetargetCharacterSize sz)
+{
+ ffebld converted;
+ int i;
+ int max;
+ ffedataConvertCache_ cache;
+
+ for (i = 0; i < ffedata_convert_cache_use_; ++i)
+ if ((bt == ffedata_convert_cache_[i].basic_type)
+ && (kt == ffedata_convert_cache_[i].kind_type)
+ && (sz == ffedata_convert_cache_[i].size)
+ && (rk == ffedata_convert_cache_[i].rank))
+ return ffedata_convert_cache_[i].converted;
+
+ converted = ffeexpr_convert (source, source_token, dest_token, bt, kt, rk,
+ sz, FFEEXPR_contextDATA);
+
+ if (ffedata_convert_cache_use_ >= ffedata_convert_cache_max_)
+ {
+ if (ffedata_convert_cache_max_ == 0)
+ max = 4;
+ else
+ max = ffedata_convert_cache_max_ << 1;
+
+ if (max > ffedata_convert_cache_max_)
+ {
+ cache = (ffedataConvertCache_) malloc_new_ks (malloc_pool_image (),
+ "FFEDATA cache", max * sizeof (*cache));
+ if (ffedata_convert_cache_max_ != 0)
+ {
+ memcpy (cache, ffedata_convert_cache_,
+ ffedata_convert_cache_max_ * sizeof (*cache));
+ malloc_kill_ks (malloc_pool_image (), ffedata_convert_cache_,
+ ffedata_convert_cache_max_ * sizeof (*cache));
+ }
+ ffedata_convert_cache_ = cache;
+ ffedata_convert_cache_max_ = max;
+ }
+ else
+ return converted; /* In case int overflows! */
+ }
+
+ i = ffedata_convert_cache_use_++;
+
+ ffedata_convert_cache_[i].converted = converted;
+ ffedata_convert_cache_[i].basic_type = bt;
+ ffedata_convert_cache_[i].kind_type = kt;
+ ffedata_convert_cache_[i].size = sz;
+ ffedata_convert_cache_[i].rank = rk;
+
+ return converted;
+}
+
+/* ffedata_eval_integer1_ -- Evaluate expression
+
+ ffetargetIntegerDefault result;
+ ffebld expr; // must be kindtypeINTEGER1.
+
+ result = ffedata_eval_integer1_(expr);
+
+ Evalues the expression (which yields a kindtypeINTEGER1 result) and
+ returns the result. */
+
+static ffetargetIntegerDefault
+ffedata_eval_integer1_ (ffebld expr)
+{
+ ffetargetInteger1 result;
+ ffebad error;
+
+ assert (expr != NULL);
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opCONTER:
+ return ffebld_constant_integer1 (ffebld_conter (expr));
+
+ case FFEBLD_opSYMTER:
+ return ffesymbol_value (ffebld_symter (expr));
+
+ case FFEBLD_opUPLUS:
+ return ffedata_eval_integer1_ (ffebld_left (expr));
+
+ case FFEBLD_opUMINUS:
+ error = ffetarget_uminus_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)));
+ break;
+
+ case FFEBLD_opADD:
+ error = ffetarget_add_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opSUBTRACT:
+ error = ffetarget_subtract_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opMULTIPLY:
+ error = ffetarget_multiply_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opDIVIDE:
+ error = ffetarget_divide_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opPOWER:
+ {
+ ffebld r = ffebld_right (expr);
+
+ if ((ffeinfo_basictype (ffebld_info (r)) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kindtype (ffebld_info (r)) != FFEINFO_kindtypeINTEGERDEFAULT))
+ error = FFEBAD_DATA_EVAL;
+ else
+ error = ffetarget_power_integerdefault_integerdefault (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (r));
+ }
+ break;
+
+#if 0 /* Only for character basictype. */
+ case FFEBLD_opCONCATENATE:
+ error =;
+ break;
+#endif
+
+ case FFEBLD_opNOT:
+ error = ffetarget_not_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)));
+ break;
+
+#if 0 /* Only for logical basictype. */
+ case FFEBLD_opLT:
+ error =;
+ break;
+
+ case FFEBLD_opLE:
+ error =;
+ break;
+
+ case FFEBLD_opEQ:
+ error =;
+ break;
+
+ case FFEBLD_opNE:
+ error =;
+ break;
+
+ case FFEBLD_opGT:
+ error =;
+ break;
+
+ case FFEBLD_opGE:
+ error =;
+ break;
+#endif
+
+ case FFEBLD_opAND:
+ error = ffetarget_and_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opOR:
+ error = ffetarget_or_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opXOR:
+ error = ffetarget_xor_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opEQV:
+ error = ffetarget_eqv_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opNEQV:
+ error = ffetarget_neqv_integer1 (&result,
+ ffedata_eval_integer1_ (ffebld_left (expr)),
+ ffedata_eval_integer1_ (ffebld_right (expr)));
+ break;
+
+ case FFEBLD_opPAREN:
+ return ffedata_eval_integer1_ (ffebld_left (expr));
+
+#if 0 /* ~~ no idea how to do this */
+ case FFEBLD_opPERCENT_LOC:
+ error =;
+ break;
+#endif
+
+#if 0 /* not allowed by ANSI, but perhaps as an
+ extension someday? */
+ case FFEBLD_opCONVERT:
+ switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr))))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+ default:
+ error = FFEBAD_DATA_EVAL;
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+ default:
+ error = FFEBAD_DATA_EVAL;
+ break;
+ }
+ break;
+ }
+ break;
+#endif
+
+#if 0 /* not valid ops */
+ case FFEBLD_opREPEAT:
+ error =;
+ break;
+
+ case FFEBLD_opBOUNDS:
+ error =;
+ break;
+#endif
+
+#if 0 /* not allowed by ANSI, but perhaps as an
+ extension someday? */
+ case FFEBLD_opFUNCREF:
+ error =;
+ break;
+#endif
+
+#if 0 /* not valid ops */
+ case FFEBLD_opSUBRREF:
+ error =;
+ break;
+
+ case FFEBLD_opARRAYREF:
+ error =;
+ break;
+#endif
+
+#if 0 /* not valid for integer1 */
+ case FFEBLD_opSUBSTR:
+ error =;
+ break;
+#endif
+
+ default:
+ error = FFEBAD_DATA_EVAL;
+ break;
+ }
+
+ if (error != FFEBAD)
+ {
+ ffebad_start (error);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_finish ();
+ result = 0;
+ }
+
+ return result;
+}
+
+/* ffedata_eval_offset_ -- Evaluate offset info array
+
+ ffetargetOffset offset; // 0...max-1.
+ ffebld subscripts; // an opITEM list of subscript exprs.
+ ffebld dims; // an opITEM list of opBOUNDS exprs.
+
+ result = ffedata_eval_offset_(expr);
+
+ Evalues the expression (which yields a kindtypeINTEGER1 result) and
+ returns the result. */
+
+static ffetargetOffset
+ffedata_eval_offset_ (ffebld subscripts, ffebld dims)
+{
+ ffetargetIntegerDefault offset = 0;
+ ffetargetIntegerDefault width = 1;
+ ffetargetIntegerDefault value;
+ ffetargetIntegerDefault lowbound;
+ ffetargetIntegerDefault highbound;
+ ffetargetOffset final;
+ ffebld subscript;
+ ffebld dim;
+ ffebld low;
+ ffebld high;
+ int rank = 0;
+ bool ok;
+
+ while (subscripts != NULL)
+ {
+ ++rank;
+ assert (dims != NULL);
+
+ subscript = ffebld_head (subscripts);
+ dim = ffebld_head (dims);
+
+ assert (ffeinfo_basictype (ffebld_info (subscript)) == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (subscript)) == FFEINFO_kindtypeINTEGER1);
+ value = ffedata_eval_integer1_ (subscript);
+
+ assert (ffebld_op (dim) == FFEBLD_opBOUNDS);
+ low = ffebld_left (dim);
+ high = ffebld_right (dim);
+
+ if (low == NULL)
+ lowbound = 1;
+ else
+ {
+ assert (ffeinfo_basictype (ffebld_info (low)) == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (low)) == FFEINFO_kindtypeINTEGERDEFAULT);
+ lowbound = ffedata_eval_integer1_ (low);
+ }
+
+ assert (ffeinfo_basictype (ffebld_info (high)) == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (high)) == FFEINFO_kindtypeINTEGERDEFAULT);
+ highbound = ffedata_eval_integer1_ (high);
+
+ if ((value < lowbound) || (value > highbound))
+ {
+ char rankstr[10];
+
+ sprintf (rankstr, "%d", rank);
+ value = lowbound;
+ ffebad_start (FFEBAD_DATA_SUBSCRIPT);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_string (rankstr);
+ ffebad_finish ();
+ }
+
+ subscripts = ffebld_trail (subscripts);
+ dims = ffebld_trail (dims);
+
+ offset += width * (value - lowbound);
+ if (subscripts != NULL)
+ width *= highbound - lowbound + 1;
+ }
+
+ assert (dims == NULL);
+
+ ok = ffetarget_offset (&final, offset);
+ assert (ok);
+
+ return final;
+}
+
+/* ffedata_eval_substr_begin_ -- Evaluate begin-point of substr reference
+
+ ffetargetCharacterSize beginpoint;
+ ffebld endval; // head(colon).
+
+ beginpoint = ffedata_eval_substr_end_(endval);
+
+ If beginval is NULL, returns 0. Otherwise makes sure beginval is
+ kindtypeINTEGERDEFAULT, makes sure its value is > 0,
+ and returns its value minus one, or issues an error message. */
+
+static ffetargetCharacterSize
+ffedata_eval_substr_begin_ (ffebld expr)
+{
+ ffetargetIntegerDefault val;
+
+ if (expr == NULL)
+ return 0;
+
+ assert (ffeinfo_basictype (ffebld_info (expr)) == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (expr)) == FFEINFO_kindtypeINTEGERDEFAULT);
+
+ val = ffedata_eval_integer1_ (expr);
+
+ if (val < 1)
+ {
+ val = 1;
+ ffebad_start (FFEBAD_DATA_RANGE);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ }
+
+ return val - 1;
+}
+
+/* ffedata_eval_substr_end_ -- Evaluate end-point of substr reference
+
+ ffetargetCharacterSize endpoint;
+ ffebld endval; // head(trail(colon)).
+ ffetargetCharacterSize min; // beginpoint of substr reference.
+ ffetargetCharacterSize max; // size of entity.
+
+ endpoint = ffedata_eval_substr_end_(endval,dflt);
+
+ If endval is NULL, returns max. Otherwise makes sure endval is
+ kindtypeINTEGERDEFAULT, makes sure its value is > min and <= max,
+ and returns its value minus one, or issues an error message. */
+
+static ffetargetCharacterSize
+ffedata_eval_substr_end_ (ffebld expr, ffetargetCharacterSize min,
+ ffetargetCharacterSize max)
+{
+ ffetargetIntegerDefault val;
+
+ if (expr == NULL)
+ return max - 1;
+
+ assert (ffeinfo_basictype (ffebld_info (expr)) == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (expr)) == FFEINFO_kindtypeINTEGER1);
+
+ val = ffedata_eval_integer1_ (expr);
+
+ if ((val < (ffetargetIntegerDefault) min)
+ || (val > (ffetargetIntegerDefault) max))
+ {
+ val = 1;
+ ffebad_start (FFEBAD_DATA_RANGE);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ }
+
+ return val - 1;
+}
+
+/* ffedata_gather_ -- Gather initial values for sym into master sym inits
+
+ ffestorag mst; // A typeCBLOCK or typeLOCAL aggregate.
+ ffestorag st; // A typeCOMMON or typeEQUIV member.
+ ffedata_gather_(mst,st);
+
+ If st has any initialization info, transfer that info into mst and
+ clear st's info. */
+
+void
+ffedata_gather_ (ffestorag mst, ffestorag st)
+{
+ ffesymbol s;
+ ffesymbol s_whine; /* Symbol to complain about in diagnostics. */
+ ffebld b;
+ ffetargetOffset offset;
+ ffetargetOffset units_expected;
+ ffebitCount actual;
+ ffebldConstantArray array;
+ ffebld accter;
+ ffetargetCopyfunc fn;
+ void *ptr1;
+ void *ptr2;
+ size_t size;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffeinfoBasictype ign_bt;
+ ffeinfoKindtype ign_kt;
+ ffetargetAlign units;
+ ffebit bits;
+ ffetargetOffset source_offset;
+ bool whine = FALSE;
+
+ if (st == NULL)
+ return; /* Nothing to do. */
+
+ s = ffestorag_symbol (st);
+
+ assert (s != NULL); /* Must have a corresponding symbol (else how
+ inited?). */
+ assert (ffestorag_init (st) == NULL); /* No init info on storage itself. */
+ assert (ffestorag_accretion (st) == NULL);
+
+ if ((((b = ffesymbol_init (s)) == NULL)
+ && ((b = ffesymbol_accretion (s)) == NULL))
+ || (ffebld_op (b) == FFEBLD_opANY)
+ || ((ffebld_op (b) == FFEBLD_opCONVERT)
+ && (ffebld_op (ffebld_left (b)) == FFEBLD_opANY)))
+ return; /* Nothing to do. */
+
+ /* b now holds the init/accretion expr. */
+
+ ffesymbol_set_init (s, NULL);
+ ffesymbol_set_accretion (s, NULL);
+ ffesymbol_set_accretes (s, 0);
+
+ s_whine = ffestorag_symbol (mst);
+ if (s_whine == NULL)
+ s_whine = s;
+
+ /* Make sure we haven't fully accreted during an array init. */
+
+ if (ffestorag_init (mst) != NULL)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffewhere_line_unknown (), ffewhere_column_unknown ());
+ ffebad_string (ffesymbol_text (s_whine));
+ ffebad_finish ();
+ return;
+ }
+
+ bt = ffeinfo_basictype (ffebld_info (b));
+ kt = ffeinfo_kindtype (ffebld_info (b));
+
+ /* Calculate offset for aggregate area. */
+
+ ffedata_charexpected_ = (bt == FFEINFO_basictypeCHARACTER)
+ ? ffebld_size (b) : 1;
+ ffetarget_aggregate_info (&ign_bt, &ign_kt, &units, bt,
+ kt);/* Find out unit size of source datum. */
+ assert (units % ffedata_storage_units_ == 0);
+ units_expected = ffedata_charexpected_ * units / ffedata_storage_units_;
+ offset = (ffestorag_offset (st) - ffestorag_offset (mst))
+ / ffedata_storage_units_;
+
+ /* Does an accretion array exist? If not, create it. */
+
+ if (ffestorag_accretion (mst) == NULL)
+ {
+#if FFEDATA_sizeTOO_BIG_INIT_ != 0
+ if (ffedata_storage_size_ >= FFEDATA_sizeTOO_BIG_INIT_)
+ {
+ char bignum[40];
+
+ sprintf (&bignum[0], "%ld", (long) ffedata_storage_size_);
+ ffebad_start (FFEBAD_TOO_BIG_INIT);
+ ffebad_here (0, ffesymbol_where_line (s_whine),
+ ffesymbol_where_column (s_whine));
+ ffebad_string (ffesymbol_text (s_whine));
+ ffebad_string (bignum);
+ ffebad_finish ();
+ }
+#endif
+ array = ffebld_constantarray_new (ffedata_storage_bt_,
+ ffedata_storage_kt_, ffedata_storage_size_);
+ accter = ffebld_new_accter (array, ffebit_new (ffe_pool_program_unit (),
+ ffedata_storage_size_));
+ ffebld_set_info (accter, ffeinfo_new
+ (ffedata_storage_bt_,
+ ffedata_storage_kt_,
+ 1,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ (ffedata_basictype_ == FFEINFO_basictypeCHARACTER)
+ ? 1 : FFETARGET_charactersizeNONE));
+ ffestorag_set_accretion (mst, accter);
+ ffestorag_set_accretes (mst, ffedata_storage_size_);
+ }
+ else
+ {
+ accter = ffestorag_accretion (mst);
+ assert (ffedata_storage_size_ == (ffetargetOffset) ffebld_accter_size (accter));
+ array = ffebld_accter (accter);
+ }
+
+ /* Put value in accretion array at desired offset. */
+
+ fn = ffetarget_aggregate_ptr_memcpy (ffedata_storage_bt_, ffedata_storage_kt_,
+ bt, kt);
+
+ switch (ffebld_op (b))
+ {
+ case FFEBLD_opCONTER:
+ ffebld_constantarray_prepare (&ptr1, &ptr2, &size, array, ffedata_storage_bt_,
+ ffedata_storage_kt_, offset,
+ ffebld_constant_ptr_to_union (ffebld_conter (b)),
+ bt, kt);
+ (*fn) (ptr1, ptr2, size); /* Does the appropriate memcpy-like
+ operation. */
+ ffebit_count (ffebld_accter_bits (accter),
+ offset, FALSE, units_expected, &actual); /* How many FALSE? */
+ if (units_expected != (ffetargetOffset) actual)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffewhere_line_unknown (), ffewhere_column_unknown ());
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ }
+ ffestorag_set_accretes (mst,
+ ffestorag_accretes (mst)
+ - actual); /* Decrement # of values
+ actually accreted. */
+ ffebit_set (ffebld_accter_bits (accter), offset, 1, units_expected);
+
+ /* If done accreting for this storage area, establish as initialized. */
+
+ if (ffestorag_accretes (mst) == 0)
+ {
+ ffestorag_set_init (mst, accter);
+ ffestorag_set_accretion (mst, NULL);
+ ffebit_kill (ffebld_accter_bits (ffestorag_init (mst)));
+ ffebld_set_op (ffestorag_init (mst), FFEBLD_opARRTER);
+ ffebld_set_arrter (ffestorag_init (mst),
+ ffebld_accter (ffestorag_init (mst)));
+ ffebld_arrter_set_size (ffestorag_init (mst),
+ ffedata_storage_size_);
+ ffebld_arrter_set_pad (ffestorag_init (mst), 0);
+ ffecom_notify_init_storage (mst);
+ }
+
+ return;
+
+ case FFEBLD_opARRTER:
+ ffebld_constantarray_preparray (&ptr1, &ptr2, &size, array, ffedata_storage_bt_,
+ ffedata_storage_kt_, offset, ffebld_arrter (b),
+ bt, kt);
+ size *= ffebld_arrter_size (b);
+ units_expected *= ffebld_arrter_size (b);
+ (*fn) (ptr1, ptr2, size); /* Does the appropriate memcpy-like
+ operation. */
+ ffebit_count (ffebld_accter_bits (accter),
+ offset, FALSE, units_expected, &actual); /* How many FALSE? */
+ if (units_expected != (ffetargetOffset) actual)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffewhere_line_unknown (), ffewhere_column_unknown ());
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ }
+ ffestorag_set_accretes (mst,
+ ffestorag_accretes (mst)
+ - actual); /* Decrement # of values
+ actually accreted. */
+ ffebit_set (ffebld_accter_bits (accter), offset, 1, units_expected);
+
+ /* If done accreting for this storage area, establish as initialized. */
+
+ if (ffestorag_accretes (mst) == 0)
+ {
+ ffestorag_set_init (mst, accter);
+ ffestorag_set_accretion (mst, NULL);
+ ffebit_kill (ffebld_accter_bits (ffestorag_init (mst)));
+ ffebld_set_op (ffestorag_init (mst), FFEBLD_opARRTER);
+ ffebld_set_arrter (ffestorag_init (mst),
+ ffebld_accter (ffestorag_init (mst)));
+ ffebld_arrter_set_size (ffestorag_init (mst),
+ ffedata_storage_size_);
+ ffebld_arrter_set_pad (ffestorag_init (mst), 0);
+ ffecom_notify_init_storage (mst);
+ }
+
+ return;
+
+ case FFEBLD_opACCTER:
+ ffebld_constantarray_preparray (&ptr1, &ptr2, &size, array, ffedata_storage_bt_,
+ ffedata_storage_kt_, offset, ffebld_accter (b),
+ bt, kt);
+ bits = ffebld_accter_bits (b);
+ source_offset = 0;
+
+ for (;;)
+ {
+ ffetargetOffset unexp;
+ ffetargetOffset siz;
+ ffebitCount length;
+ bool value;
+
+ ffebit_test (bits, source_offset, &value, &length);
+ if (length == 0)
+ break; /* Exit the loop early. */
+ siz = size * length;
+ unexp = units_expected * length;
+ if (value)
+ {
+ (*fn) (ptr1, ptr2, siz); /* Does memcpy-like operation. */
+ ffebit_count (ffebld_accter_bits (accter), /* How many FALSE? */
+ offset, FALSE, unexp, &actual);
+ if (!whine && (unexp != (ffetargetOffset) actual))
+ {
+ whine = TRUE; /* Don't whine more than once for one gather. */
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffewhere_line_unknown (), ffewhere_column_unknown ());
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ }
+ ffestorag_set_accretes (mst,
+ ffestorag_accretes (mst)
+ - actual); /* Decrement # of values
+ actually accreted. */
+ ffebit_set (ffebld_accter_bits (accter), offset, 1, unexp);
+ }
+ source_offset += length;
+ offset += unexp;
+ ptr1 = ((char *) ptr1) + siz;
+ ptr2 = ((char *) ptr2) + siz;
+ }
+
+ /* If done accreting for this storage area, establish as initialized. */
+
+ if (ffestorag_accretes (mst) == 0)
+ {
+ ffestorag_set_init (mst, accter);
+ ffestorag_set_accretion (mst, NULL);
+ ffebit_kill (ffebld_accter_bits (ffestorag_init (mst)));
+ ffebld_set_op (ffestorag_init (mst), FFEBLD_opARRTER);
+ ffebld_set_arrter (ffestorag_init (mst),
+ ffebld_accter (ffestorag_init (mst)));
+ ffebld_arrter_set_size (ffestorag_init (mst),
+ ffedata_storage_size_);
+ ffebld_arrter_set_pad (ffestorag_init (mst), 0);
+ ffecom_notify_init_storage (mst);
+ }
+
+ return;
+
+ default:
+ assert ("bad init op in gather_" == NULL);
+ return;
+ }
+}
+
+/* ffedata_pop_ -- Pop an impdo stack entry
+
+ ffedata_pop_(); */
+
+static void
+ffedata_pop_ ()
+{
+ ffedataImpdo_ victim = ffedata_stack_;
+
+ assert (victim != NULL);
+
+ ffedata_stack_ = ffedata_stack_->outer;
+
+ malloc_kill_ks (ffe_pool_program_unit (), victim, sizeof (*victim));
+}
+
+/* ffedata_push_ -- Push an impdo stack entry
+
+ ffedata_push_(); */
+
+static void
+ffedata_push_ ()
+{
+ ffedataImpdo_ baby;
+
+ baby = malloc_new_ks (ffe_pool_program_unit (), "ffedataImpdo_", sizeof (*baby));
+
+ baby->outer = ffedata_stack_;
+ ffedata_stack_ = baby;
+}
+
+/* ffedata_value_ -- Provide an initial value
+
+ ffebld value;
+ ffelexToken t; // Points to the value.
+ if (ffedata_value(value,t))
+ // Everything's ok
+
+ Makes sure the value is ok, then remembers it according to the list
+ provided to ffedata_begin. */
+
+static bool
+ffedata_value_ (ffebld value, ffelexToken token)
+{
+
+ /* If already reported an error, don't do anything. */
+
+ if (ffedata_reported_error_)
+ return FALSE;
+
+ /* If the value is an error marker, remember we've seen one and do nothing
+ else. */
+
+ if ((value != NULL)
+ && (ffebld_op (value) == FFEBLD_opANY))
+ {
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* If too many values (no more targets), complain. */
+
+ if (ffedata_symbol_ == NULL)
+ {
+ ffebad_start (FFEBAD_DATA_TOOMANY);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* If ffedata_advance_ wanted to register a complaint, do it now
+ that we have the token to point at instead of just the start
+ of the whole statement. */
+
+ if (ffedata_reinit_)
+ {
+ ffebad_start (FFEBAD_DATA_REINIT);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+#if FFEGLOBAL_ENABLED
+ if (ffesymbol_common (ffedata_symbol_) != NULL)
+ ffeglobal_init_common (ffesymbol_common (ffedata_symbol_), token);
+#endif
+
+ /* Convert value to desired type. */
+
+ if (value != NULL)
+ {
+ if (ffedata_convert_cache_use_ == -1)
+ value = ffeexpr_convert
+ (value, token, NULL, ffedata_basictype_,
+ ffedata_kindtype_, 0,
+ (ffedata_basictype_ == FFEINFO_basictypeCHARACTER)
+ ? ffedata_charexpected_ : FFETARGET_charactersizeNONE,
+ FFEEXPR_contextDATA);
+ else /* Use the cache. */
+ value = ffedata_convert_
+ (value, token, NULL, ffedata_basictype_,
+ ffedata_kindtype_, 0,
+ (ffedata_basictype_ == FFEINFO_basictypeCHARACTER)
+ ? ffedata_charexpected_ : FFETARGET_charactersizeNONE);
+ }
+
+ /* If we couldn't, bug out. */
+
+ if ((value != NULL) && (ffebld_op (value) == FFEBLD_opANY))
+ {
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* Handle the case where initializes go to a parent's storage area. */
+
+ if (ffedata_storage_ != NULL)
+ {
+ ffetargetOffset offset;
+ ffetargetOffset units_expected;
+ ffebitCount actual;
+ ffebldConstantArray array;
+ ffebld accter;
+ ffetargetCopyfunc fn;
+ void *ptr1;
+ void *ptr2;
+ size_t size;
+ ffeinfoBasictype ign_bt;
+ ffeinfoKindtype ign_kt;
+ ffetargetAlign units;
+
+ /* Make sure we haven't fully accreted during an array init. */
+
+ if (ffestorag_init (ffedata_storage_) != NULL)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* Calculate offset. */
+
+ offset = ffedata_offset_ * ffedata_size_ + ffedata_charoffset_;
+
+ /* Is offset within range? If not, whine, but don't do anything else. */
+
+ if (offset + ffedata_charexpected_ - 1 > ffedata_symbolsize_)
+ {
+ ffebad_start (FFEBAD_DATA_RANGE);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* Now calculate offset for aggregate area. */
+
+ ffetarget_aggregate_info (&ign_bt, &ign_kt, &units, ffedata_basictype_,
+ ffedata_kindtype_); /* Find out unit size of
+ source datum. */
+ assert (units % ffedata_storage_units_ == 0);
+ units_expected = ffedata_charexpected_ * units / ffedata_storage_units_;
+ offset *= units / ffedata_storage_units_;
+ offset += (ffestorag_offset (ffesymbol_storage (ffedata_symbol_))
+ - ffestorag_offset (ffedata_storage_))
+ / ffedata_storage_units_;
+
+ assert (offset + units_expected - 1 <= ffedata_storage_size_);
+
+ /* Does an accretion array exist? If not, create it. */
+
+ if (value != NULL)
+ {
+ if (ffestorag_accretion (ffedata_storage_) == NULL)
+ {
+#if FFEDATA_sizeTOO_BIG_INIT_ != 0
+ if (ffedata_storage_size_ >= FFEDATA_sizeTOO_BIG_INIT_)
+ {
+ char bignum[40];
+
+ sprintf (&bignum[0], "%ld", (long) ffedata_storage_size_);
+ ffebad_start (FFEBAD_TOO_BIG_INIT);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_string (bignum);
+ ffebad_finish ();
+ }
+#endif
+ array = ffebld_constantarray_new
+ (ffedata_storage_bt_, ffedata_storage_kt_,
+ ffedata_storage_size_);
+ accter = ffebld_new_accter (array,
+ ffebit_new (ffe_pool_program_unit (),
+ ffedata_storage_size_));
+ ffebld_set_info (accter, ffeinfo_new
+ (ffedata_storage_bt_,
+ ffedata_storage_kt_,
+ 1,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ (ffedata_basictype_
+ == FFEINFO_basictypeCHARACTER)
+ ? 1 : FFETARGET_charactersizeNONE));
+ ffestorag_set_accretion (ffedata_storage_, accter);
+ ffestorag_set_accretes (ffedata_storage_, ffedata_storage_size_);
+ }
+ else
+ {
+ accter = ffestorag_accretion (ffedata_storage_);
+ assert (ffedata_storage_size_ == (ffetargetOffset) ffebld_accter_size (accter));
+ array = ffebld_accter (accter);
+ }
+
+ /* Put value in accretion array at desired offset. */
+
+ fn = ffetarget_aggregate_ptr_memcpy
+ (ffedata_storage_bt_, ffedata_storage_kt_,
+ ffedata_basictype_, ffedata_kindtype_);
+ ffebld_constantarray_prepare
+ (&ptr1, &ptr2, &size, array, ffedata_storage_bt_,
+ ffedata_storage_kt_, offset,
+ ffebld_constant_ptr_to_union (ffebld_conter (value)),
+ ffedata_basictype_, ffedata_kindtype_);
+ (*fn) (ptr1, ptr2, size); /* Does the appropriate memcpy-like
+ operation. */
+ ffebit_count (ffebld_accter_bits (accter),
+ offset, FALSE, units_expected,
+ &actual); /* How many FALSE? */
+ if (units_expected != (ffetargetOffset) actual)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ }
+ ffestorag_set_accretes (ffedata_storage_,
+ ffestorag_accretes (ffedata_storage_)
+ - actual); /* Decrement # of values
+ actually accreted. */
+ ffebit_set (ffebld_accter_bits (accter), offset,
+ 1, units_expected);
+
+ /* If done accreting for this storage area, establish as
+ initialized. */
+
+ if (ffestorag_accretes (ffedata_storage_) == 0)
+ {
+ ffestorag_set_init (ffedata_storage_, accter);
+ ffestorag_set_accretion (ffedata_storage_, NULL);
+ ffebit_kill (ffebld_accter_bits
+ (ffestorag_init (ffedata_storage_)));
+ ffebld_set_op (ffestorag_init (ffedata_storage_),
+ FFEBLD_opARRTER);
+ ffebld_set_arrter
+ (ffestorag_init (ffedata_storage_),
+ ffebld_accter (ffestorag_init (ffedata_storage_)));
+ ffebld_arrter_set_size (ffestorag_init (ffedata_storage_),
+ ffedata_storage_size_);
+ ffebld_arrter_set_pad (ffestorag_init (ffedata_storage_),
+ 0);
+ ffecom_notify_init_storage (ffedata_storage_);
+ }
+ }
+
+ /* If still accreting, adjust specs accordingly and return. */
+
+ if (++ffedata_number_ < ffedata_expected_)
+ {
+ ++ffedata_offset_;
+ return TRUE;
+ }
+
+ return ffedata_advance_ ();
+ }
+
+ /* Figure out where the value goes -- in an accretion array or directly
+ into the final initial-value slot for the symbol. */
+
+ if ((ffedata_number_ != 0)
+ || (ffedata_arraysize_ > 1)
+ || (ffedata_charnumber_ != 0)
+ || (ffedata_size_ > ffedata_charexpected_))
+ { /* Accrete this value. */
+ ffetargetOffset offset;
+ ffebitCount actual;
+ ffebldConstantArray array;
+ ffebld accter = NULL;
+
+ /* Calculate offset. */
+
+ offset = ffedata_offset_ * ffedata_size_ + ffedata_charoffset_;
+
+ /* Is offset within range? If not, whine, but don't do anything else. */
+
+ if (offset + ffedata_charexpected_ - 1 > ffedata_symbolsize_)
+ {
+ ffebad_start (FFEBAD_DATA_RANGE);
+ ffest_ffebad_here_current_stmt (0);
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ ffedata_reported_error_ = TRUE;
+ return FALSE;
+ }
+
+ /* Does an accretion array exist? If not, create it. */
+
+ if (value != NULL)
+ {
+ if (ffesymbol_accretion (ffedata_symbol_) == NULL)
+ {
+#if FFEDATA_sizeTOO_BIG_INIT_ != 0
+ if (ffedata_symbolsize_ >= FFEDATA_sizeTOO_BIG_INIT_ )
+ {
+ char bignum[40];
+
+ sprintf (&bignum[0], "%ld", (long) ffedata_symbolsize_);
+ ffebad_start (FFEBAD_TOO_BIG_INIT);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_string (bignum);
+ ffebad_finish ();
+ }
+#endif
+ array = ffebld_constantarray_new
+ (ffedata_basictype_, ffedata_kindtype_,
+ ffedata_symbolsize_);
+ accter = ffebld_new_accter (array,
+ ffebit_new (ffe_pool_program_unit (),
+ ffedata_symbolsize_));
+ ffebld_set_info (accter, ffeinfo_new
+ (ffedata_basictype_,
+ ffedata_kindtype_,
+ 1,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ (ffedata_basictype_
+ == FFEINFO_basictypeCHARACTER)
+ ? 1 : FFETARGET_charactersizeNONE));
+ ffesymbol_set_accretion (ffedata_symbol_, accter);
+ ffesymbol_set_accretes (ffedata_symbol_, ffedata_symbolsize_);
+ }
+ else
+ {
+ accter = ffesymbol_accretion (ffedata_symbol_);
+ assert (ffedata_symbolsize_
+ == (ffetargetOffset) ffebld_accter_size (accter));
+ array = ffebld_accter (accter);
+ }
+
+ /* Put value in accretion array at desired offset. */
+
+ ffebld_constantarray_put
+ (array, ffedata_basictype_, ffedata_kindtype_,
+ offset, ffebld_constant_union (ffebld_conter (value)));
+ ffebit_count (ffebld_accter_bits (accter), offset, FALSE,
+ ffedata_charexpected_,
+ &actual); /* How many FALSE? */
+ if (actual != (unsigned long int) ffedata_charexpected_)
+ {
+ ffebad_start (FFEBAD_DATA_MULTIPLE);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_string (ffesymbol_text (ffedata_symbol_));
+ ffebad_finish ();
+ }
+ ffesymbol_set_accretes (ffedata_symbol_,
+ ffesymbol_accretes (ffedata_symbol_)
+ - actual); /* Decrement # of values
+ actually accreted. */
+ ffebit_set (ffebld_accter_bits (accter), offset,
+ 1, ffedata_charexpected_);
+ ffesymbol_signal_unreported (ffedata_symbol_);
+ }
+
+ /* If still accreting, adjust specs accordingly and return. */
+
+ if (++ffedata_number_ < ffedata_expected_)
+ {
+ ++ffedata_offset_;
+ return TRUE;
+ }
+
+ /* Else, if done accreting for this symbol, establish as initialized. */
+
+ if ((value != NULL)
+ && (ffesymbol_accretes (ffedata_symbol_) == 0))
+ {
+ ffesymbol_set_init (ffedata_symbol_, accter);
+ ffesymbol_set_accretion (ffedata_symbol_, NULL);
+ ffebit_kill (ffebld_accter_bits (ffesymbol_init (ffedata_symbol_)));
+ ffebld_set_op (ffesymbol_init (ffedata_symbol_), FFEBLD_opARRTER);
+ ffebld_set_arrter (ffesymbol_init (ffedata_symbol_),
+ ffebld_accter (ffesymbol_init (ffedata_symbol_)));
+ ffebld_arrter_set_size (ffesymbol_init (ffedata_symbol_),
+ ffedata_symbolsize_);
+ ffebld_arrter_set_pad (ffestorag_init (ffedata_symbol_), 0);
+ ffecom_notify_init_symbol (ffedata_symbol_);
+ }
+ }
+ else if (value != NULL)
+ {
+ /* Simple, direct, one-shot assignment. */
+ ffesymbol_set_init (ffedata_symbol_, value);
+ ffecom_notify_init_symbol (ffedata_symbol_);
+ }
+
+ /* Call on advance function to get next target in list. */
+
+ return ffedata_advance_ ();
+}
diff --git a/contrib/gcc/f/data.h b/contrib/gcc/f/data.h
new file mode 100644
index 0000000..26c4f54
--- /dev/null
+++ b/contrib/gcc/f/data.h
@@ -0,0 +1,74 @@
+/* data.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ data.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_data
+#define _H_f_data
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "bld.h"
+#include "lex.h"
+#include "storag.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+void ffedata_begin (ffebld list);
+bool ffedata_end (bool report_errors, ffelexToken t);
+void ffedata_gather (ffestorag st);
+bool ffedata_value (ffetargetIntegerDefault rpt, ffebld value,
+ ffelexToken value_token);
+
+/* Define macros. */
+
+#define ffedata_init_0()
+#define ffedata_init_1()
+#define ffedata_init_2()
+#define ffedata_init_3()
+#define ffedata_init_4()
+#define ffedata_terminate_0()
+#define ffedata_terminate_1()
+#define ffedata_terminate_2()
+#define ffedata_terminate_3()
+#define ffedata_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/equiv.c b/contrib/gcc/f/equiv.c
new file mode 100644
index 0000000..a9de49d
--- /dev/null
+++ b/contrib/gcc/f/equiv.c
@@ -0,0 +1,1498 @@
+/* equiv.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995-1998 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Handles the EQUIVALENCE relationships in a program unit.
+
+ Modifications:
+*/
+
+#define FFEEQUIV_DEBUG 0
+
+/* Include files. */
+
+#include "proj.h"
+#include "equiv.h"
+#include "bad.h"
+#include "bld.h"
+#include "com.h"
+#include "data.h"
+#include "global.h"
+#include "lex.h"
+#include "malloc.h"
+#include "symbol.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+struct _ffeequiv_list_
+ {
+ ffeequiv first;
+ ffeequiv last;
+ };
+
+/* Static objects accessed by functions in this module. */
+
+static struct _ffeequiv_list_ ffeequiv_list_;
+
+/* Static functions (internal). */
+
+static void ffeequiv_destroy_ (ffeequiv eq);
+static void ffeequiv_layout_local_ (ffeequiv eq);
+static bool ffeequiv_offset_ (ffetargetOffset *offset, ffesymbol s,
+ ffebld expr, bool subtract,
+ ffetargetOffset adjust, bool no_precede);
+
+/* Internal macros. */
+
+
+static void
+ffeequiv_destroy_ (ffeequiv victim)
+{
+ ffebld list;
+ ffebld item;
+ ffebld expr;
+
+ for (list = victim->list; list != NULL; list = ffebld_trail (list))
+ {
+ for (item = ffebld_head (list); item != NULL; item = ffebld_trail (item))
+ {
+ ffesymbol sym;
+
+ expr = ffebld_head (item);
+ sym = ffeequiv_symbol (expr);
+ if (sym == NULL)
+ continue;
+ if (ffesymbol_equiv (sym) != NULL)
+ ffesymbol_set_equiv (sym, NULL);
+ }
+ }
+ ffeequiv_kill (victim);
+}
+
+/* ffeequiv_layout_local_ -- Lay out storage for local equivalenced vars
+
+ ffeequiv eq;
+ ffeequiv_layout_local_(eq);
+
+ Makes a single master ffestorag object that contains all the vars
+ in the equivalence, and makes subordinate ffestorag objects for the
+ vars with the correct offsets.
+
+ The resulting var offsets are relative not necessarily to 0 -- the
+ are relative to the offset of the master area, which might be 0 or
+ negative, but should never be positive. */
+
+static void
+ffeequiv_layout_local_ (ffeequiv eq)
+{
+ ffestorag st; /* Equivalence storage area. */
+ ffebld list; /* List of list of equivalences. */
+ ffebld item; /* List of equivalences. */
+ ffebld root_exp; /* Expression for root sym. */
+ ffestorag root_st; /* Storage for root. */
+ ffesymbol root_sym; /* Root itself. */
+ ffebld rooted_exp; /* Expression for rooted sym in an eqlist. */
+ ffestorag rooted_st; /* Storage for rooted. */
+ ffesymbol rooted_sym; /* Rooted symbol itself. */
+ ffetargetOffset eqlist_offset;/* Offset for eqlist from rooted sym. */
+ ffetargetAlign alignment;
+ ffetargetAlign modulo;
+ ffetargetAlign pad;
+ ffetargetOffset size;
+ ffetargetOffset num_elements;
+ bool new_storage; /* Established new storage info. */
+ bool need_storage; /* Have need for more storage info. */
+ bool init;
+
+ assert (eq != NULL);
+
+ if (ffeequiv_common (eq) != NULL)
+ { /* Put in common due to programmer error. */
+ ffeequiv_destroy_ (eq);
+ return;
+ }
+
+ /* Find the symbol for the first valid item in the list of lists, use that
+ as the root symbol. Doesn't matter if it won't end up at the beginning
+ of the list, though. */
+
+#if FFEEQUIV_DEBUG
+ fprintf (stderr, "Equiv1:\n");
+#endif
+
+ root_sym = NULL;
+ root_exp = NULL;
+
+ for (list = ffeequiv_list (eq);
+ list != NULL;
+ list = ffebld_trail (list))
+ { /* For every equivalence list in the list of
+ equivs */
+ for (item = ffebld_head (list);
+ item != NULL;
+ item = ffebld_trail (item))
+ { /* For every equivalence item in the list */
+ ffetargetOffset ign; /* Ignored. */
+
+ root_exp = ffebld_head (item);
+ root_sym = ffeequiv_symbol (root_exp);
+ if (root_sym == NULL)
+ continue; /* Ignore me. */
+
+ assert (ffesymbol_storage (root_sym) == NULL); /* No storage yet. */
+
+ if (!ffeequiv_offset_ (&ign, root_sym, root_exp, FALSE, 0, FALSE))
+ {
+ /* We can't just eliminate this one symbol from the list
+ of candidates, because it might be the only one that
+ ties all these equivs together. So just destroy the
+ whole list. */
+
+ ffeequiv_destroy_ (eq);
+ return;
+ }
+
+ break; /* Use first valid eqv expr for root exp/sym. */
+ }
+ if (root_sym != NULL)
+ break;
+ }
+
+ if (root_sym == NULL)
+ {
+ ffeequiv_destroy_ (eq);
+ return;
+ }
+
+
+#if FFEEQUIV_DEBUG
+ fprintf (stderr, " Root: `%s'\n", ffesymbol_text (root_sym));
+#endif
+
+ /* We've got work to do, so make the LOCAL storage object that'll hold all
+ the equivalenced vars inside it. */
+
+ st = ffestorag_new (ffestorag_list_master ());
+ ffestorag_set_parent (st, NULL); /* Initializations happen here. */
+ ffestorag_set_init (st, NULL);
+ ffestorag_set_accretion (st, NULL);
+ ffestorag_set_offset (st, 0); /* Assume equiv will be at root offset 0 for now. */
+ ffestorag_set_alignment (st, 1);
+ ffestorag_set_modulo (st, 0);
+ ffestorag_set_type (st, FFESTORAG_typeLOCAL);
+ ffestorag_set_basictype (st, ffesymbol_basictype (root_sym));
+ ffestorag_set_kindtype (st, ffesymbol_kindtype (root_sym));
+ ffestorag_set_typesymbol (st, root_sym);
+ ffestorag_set_is_save (st, ffeequiv_is_save (eq));
+ if (ffesymbol_is_save (root_sym))
+ ffestorag_update_save (st);
+ ffestorag_set_is_init (st, ffeequiv_is_init (eq));
+ if (ffesymbol_is_init (root_sym))
+ ffestorag_update_init (st);
+ ffestorag_set_symbol (st, root_sym); /* Assume this will be the root until
+ we know better (used only to generate
+ the internal name for the aggregate area,
+ e.g. for debugging). */
+
+ /* Make the EQUIV storage object for the root symbol. */
+
+ if (ffesymbol_rank (root_sym) == 0)
+ num_elements = 1;
+ else
+ num_elements = ffebld_constant_integerdefault (ffebld_conter
+ (ffesymbol_arraysize (root_sym)));
+ ffetarget_layout (ffesymbol_text (root_sym), &alignment, &modulo, &size,
+ ffesymbol_basictype (root_sym), ffesymbol_kindtype (root_sym),
+ ffesymbol_size (root_sym), num_elements);
+ ffestorag_set_size (st, size); /* Set initial size of aggregate area. */
+
+ pad = ffetarget_align (ffestorag_ptr_to_alignment (st),
+ ffestorag_ptr_to_modulo (st), 0, alignment,
+ modulo);
+ assert (pad == 0);
+
+ root_st = ffestorag_new (ffestorag_list_equivs (st));
+ ffestorag_set_parent (root_st, st); /* Initializations happen there. */
+ ffestorag_set_init (root_st, NULL);
+ ffestorag_set_accretion (root_st, NULL);
+ ffestorag_set_symbol (root_st, root_sym);
+ ffestorag_set_size (root_st, size);
+ ffestorag_set_offset (root_st, 0); /* Will not change; always 0 relative to itself! */
+ ffestorag_set_alignment (root_st, alignment);
+ ffestorag_set_modulo (root_st, modulo);
+ ffestorag_set_type (root_st, FFESTORAG_typeEQUIV);
+ ffestorag_set_basictype (root_st, ffesymbol_basictype (root_sym));
+ ffestorag_set_kindtype (root_st, ffesymbol_kindtype (root_sym));
+ ffestorag_set_typesymbol (root_st, root_sym);
+ ffestorag_set_is_save (root_st, FALSE); /* Assume FALSE, then... */
+ if (ffestorag_is_save (st)) /* ...update to TRUE if needed. */
+ ffestorag_update_save (root_st);
+ ffestorag_set_is_init (root_st, FALSE); /* Assume FALSE, then... */
+ if (ffestorag_is_init (st)) /* ...update to TRUE if needed. */
+ ffestorag_update_init (root_st);
+ ffesymbol_set_storage (root_sym, root_st);
+ ffesymbol_signal_unreported (root_sym);
+ init = ffesymbol_is_init (root_sym);
+
+ /* Now that we know the root (offset=0) symbol, revisit all the lists and
+ do the actual storage allocation. Keep doing this until we've gone
+ through them all without making any new storage objects. */
+
+ do
+ {
+ new_storage = FALSE;
+ need_storage = FALSE;
+ for (list = ffeequiv_list (eq);
+ list != NULL;
+ list = ffebld_trail (list))
+ { /* For every equivalence list in the list of
+ equivs */
+ /* Now find a "rooted" symbol in this list. That is, find the
+ first item we can that is valid and whose symbol already
+ has a storage area, because that means we know where it
+ belongs in the equivalence area and can then allocate the
+ rest of the items in the list accordingly. */
+
+ rooted_sym = NULL;
+ rooted_exp = NULL;
+ eqlist_offset = 0;
+
+ for (item = ffebld_head (list);
+ item != NULL;
+ item = ffebld_trail (item))
+ { /* For every equivalence item in the list */
+ rooted_exp = ffebld_head (item);
+ rooted_sym = ffeequiv_symbol (rooted_exp);
+ if ((rooted_sym == NULL)
+ || ((rooted_st = ffesymbol_storage (rooted_sym)) == NULL))
+ {
+ rooted_sym = NULL;
+ continue; /* Ignore me. */
+ }
+
+ need_storage = TRUE; /* Somebody is likely to need
+ storage. */
+
+#if FFEEQUIV_DEBUG
+ fprintf (stderr, " Rooted: `%s' at %" ffetargetOffset_f "d\n",
+ ffesymbol_text (rooted_sym),
+ ffestorag_offset (rooted_st));
+#endif
+
+ /* The offset of this symbol from the equiv's root symbol
+ is already known, and the size of this symbol is already
+ incorporated in the size of the equiv's aggregate area.
+ What we now determine is the offset of this equivalence
+ _list_ from the equiv's root symbol.
+
+ For example, if we know that A is at offset 16 from the
+ root symbol, given EQUIVALENCE (B(24),A(2)), we're looking
+ at A(2), meaning that the offset for this equivalence list
+ is 20 (4 bytes beyond the beginning of A, assuming typical
+ array types, dimensions, and type info). */
+
+ if (!ffeequiv_offset_ (&eqlist_offset, rooted_sym, rooted_exp, FALSE,
+ ffestorag_offset (rooted_st), FALSE))
+
+ { /* Can't use this one. */
+ ffesymbol_set_equiv (rooted_sym, NULL);/* Equiv area slated for
+ death. */
+ rooted_sym = NULL;
+ continue; /* Something's wrong with eqv expr, try another. */
+ }
+
+#if FFEEQUIV_DEBUG
+ fprintf (stderr, " Eqlist offset: %" ffetargetOffset_f "d\n",
+ eqlist_offset);
+#endif
+
+ break;
+ }
+
+ /* If no rooted symbol, it means this list has no roots -- yet.
+ So, forget this list this time around, but we'll get back
+ to it after the outer loop iterates at least one more time,
+ and, ultimately, it will have a root. */
+
+ if (rooted_sym == NULL)
+ {
+#if FFEEQUIV_DEBUG
+ fprintf (stderr, "No roots.\n");
+#endif
+ continue;
+ }
+
+ /* We now have a rooted symbol/expr and the offset of this equivalence
+ list from the root symbol. The other expressions in this
+ list all identify an initial storage unit that must have the
+ same offset. */
+
+ for (item = ffebld_head (list);
+ item != NULL;
+ item = ffebld_trail (item))
+ { /* For every equivalence item in the list */
+ ffebld item_exp; /* Expression for equivalence. */
+ ffestorag item_st; /* Storage for var. */
+ ffesymbol item_sym; /* Var itself. */
+ ffetargetOffset item_offset; /* Offset for var from root. */
+ ffetargetOffset new_size;
+
+ item_exp = ffebld_head (item);
+ item_sym = ffeequiv_symbol (item_exp);
+ if ((item_sym == NULL)
+ || (ffesymbol_equiv (item_sym) == NULL))
+ continue; /* Ignore me. */
+
+ if (item_sym == rooted_sym)
+ continue; /* Rooted sym already set up. */
+
+ if (!ffeequiv_offset_ (&item_offset, item_sym, item_exp, TRUE,
+ eqlist_offset, FALSE))
+ {
+ ffesymbol_set_equiv (item_sym, NULL); /* Don't bother with me anymore. */
+ continue;
+ }
+
+#if FFEEQUIV_DEBUG
+ fprintf (stderr, " Item `%s' at %" ffetargetOffset_f "d",
+ ffesymbol_text (item_sym), item_offset);
+#endif
+
+ if (ffesymbol_rank (item_sym) == 0)
+ num_elements = 1;
+ else
+ num_elements = ffebld_constant_integerdefault (ffebld_conter
+ (ffesymbol_arraysize (item_sym)));
+ ffetarget_layout (ffesymbol_text (item_sym), &alignment, &modulo,
+ &size, ffesymbol_basictype (item_sym),
+ ffesymbol_kindtype (item_sym), ffesymbol_size (item_sym),
+ num_elements);
+ pad = ffetarget_align (ffestorag_ptr_to_alignment (st),
+ ffestorag_ptr_to_modulo (st),
+ item_offset, alignment, modulo);
+ if (pad != 0)
+ {
+ ffebad_start (FFEBAD_EQUIV_ALIGN);
+ ffebad_string (ffesymbol_text (item_sym));
+ ffebad_finish ();
+ ffesymbol_set_equiv (item_sym, NULL); /* Don't bother with me anymore. */
+ continue;
+ }
+
+ /* If the variable's offset is less than the offset for the
+ aggregate storage area, it means it has to expand backwards
+ -- i.e. the new known starting point of the area precedes the
+ old one. This can't happen with COMMON areas (the standard,
+ and common sense, disallow it), but it is normal for local
+ EQUIVALENCE areas.
+
+ Also handle choosing the "documented" rooted symbol for this
+ area here. It's the symbol at the bottom (lowest offset)
+ of the aggregate area, with ties going to the name that would
+ sort to the top of the list of ties. */
+
+ if (item_offset == ffestorag_offset (st))
+ {
+ if ((item_sym != ffestorag_symbol (st))
+ && (strcmp (ffesymbol_text (item_sym),
+ ffesymbol_text (ffestorag_symbol (st)))
+ < 0))
+ ffestorag_set_symbol (st, item_sym);
+ }
+ else if (item_offset < ffestorag_offset (st))
+ {
+ /* Increase size of equiv area to start for lower offset
+ relative to root symbol. */
+ if (! ffetarget_offset_add (&new_size,
+ ffestorag_offset (st)
+ - item_offset,
+ ffestorag_size (st)))
+ ffetarget_offset_overflow (ffesymbol_text (s));
+ else
+ ffestorag_set_size (st, new_size);
+
+ ffestorag_set_symbol (st, item_sym);
+ ffestorag_set_offset (st, item_offset);
+
+#if FFEEQUIV_DEBUG
+ fprintf (stderr, " [eq offset=%" ffetargetOffset_f
+ "d, size=%" ffetargetOffset_f "d]",
+ item_offset, new_size);
+#endif
+ }
+
+ if ((item_st = ffesymbol_storage (item_sym)) == NULL)
+ { /* Create new ffestorag object, extend equiv
+ area. */
+#if FFEEQUIV_DEBUG
+ fprintf (stderr, ".\n");
+#endif
+ new_storage = TRUE;
+ item_st = ffestorag_new (ffestorag_list_equivs (st));
+ ffestorag_set_parent (item_st, st); /* Initializations
+ happen there. */
+ ffestorag_set_init (item_st, NULL);
+ ffestorag_set_accretion (item_st, NULL);
+ ffestorag_set_symbol (item_st, item_sym);
+ ffestorag_set_size (item_st, size);
+ ffestorag_set_offset (item_st, item_offset);
+ ffestorag_set_alignment (item_st, alignment);
+ ffestorag_set_modulo (item_st, modulo);
+ ffestorag_set_type (item_st, FFESTORAG_typeEQUIV);
+ ffestorag_set_basictype (item_st, ffesymbol_basictype (item_sym));
+ ffestorag_set_kindtype (item_st, ffesymbol_kindtype (item_sym));
+ ffestorag_set_typesymbol (item_st, item_sym);
+ ffestorag_set_is_save (item_st, FALSE); /* Assume FALSE... */
+ if (ffestorag_is_save (st)) /* ...update TRUE */
+ ffestorag_update_save (item_st); /* if needed. */
+ ffestorag_set_is_init (item_st, FALSE); /* Assume FALSE... */
+ if (ffestorag_is_init (st)) /* ...update TRUE */
+ ffestorag_update_init (item_st); /* if needed. */
+ ffesymbol_set_storage (item_sym, item_st);
+ ffesymbol_signal_unreported (item_sym);
+ if (ffesymbol_is_init (item_sym))
+ init = TRUE;
+
+ /* Determine new size of equiv area, complain if overflow. */
+
+ if (!ffetarget_offset_add (&size, item_offset, size)
+ || !ffetarget_offset_add (&size, -ffestorag_offset (st), size))
+ ffetarget_offset_overflow (ffesymbol_text (s));
+ else if (size > ffestorag_size (st))
+ ffestorag_set_size (st, size);
+ ffestorag_update (st, item_sym, ffesymbol_basictype (item_sym),
+ ffesymbol_kindtype (item_sym));
+ }
+ else
+ {
+#if FFEEQUIV_DEBUG
+ fprintf (stderr, " (was %" ffetargetOffset_f "d).\n",
+ ffestorag_offset (item_st));
+#endif
+ /* Make sure offset agrees with known offset. */
+ if (item_offset != ffestorag_offset (item_st))
+ {
+ char io1[40];
+ char io2[40];
+
+ sprintf (&io1[0], "%" ffetargetOffset_f "d", item_offset);
+ sprintf (&io2[0], "%" ffetargetOffset_f "d", ffestorag_offset (item_st));
+ ffebad_start (FFEBAD_EQUIV_MISMATCH);
+ ffebad_string (ffesymbol_text (item_sym));
+ ffebad_string (ffesymbol_text (root_sym));
+ ffebad_string (io1);
+ ffebad_string (io2);
+ ffebad_finish ();
+ }
+ }
+ ffesymbol_set_equiv (item_sym, NULL); /* Don't bother with me anymore. */
+ } /* (For every equivalence item in the list) */
+ ffebld_set_head (list, NULL); /* Don't do this list again. */
+ } /* (For every equivalence list in the list of
+ equivs) */
+ } while (new_storage && need_storage);
+
+ ffesymbol_set_equiv (root_sym, NULL); /* This one has storage now. */
+
+ ffeequiv_kill (eq); /* Fully processed, no longer needed. */
+
+ /* If the offset for this storage area is zero (it cannot be positive),
+ that means the alignment/modulo info is already correct. Otherwise,
+ the alignment info is correct, but the modulo info reflects a
+ zero offset, so fix it. */
+
+ if (ffestorag_offset (st) < 0)
+ {
+ /* Calculate the initial padding necessary to preserve
+ the alignment/modulo requirements for the storage area.
+ These requirements are themselves kept track of in the
+ record for the storage area as a whole, but really pertain
+ to offset 0 of that area, which is where the root symbol
+ was originally placed.
+
+ The goal here is to have the offset and size for the area
+ faithfully reflect the area itself, not extra requirements
+ like alignment. So to meet the alignment requirements,
+ the modulo for the area should be set as if the area had an
+ alignment requirement of alignment/0 and was aligned/padded
+ downward to meet the alignment requirements of the area at
+ offset zero, the amount of padding needed being the desired
+ value for the modulo of the area. */
+
+ alignment = ffestorag_alignment (st);
+ modulo = ffestorag_modulo (st);
+
+ /* Since we want to move the whole area *down* (lower memory
+ addresses) as required by the alignment/modulo paid, negate
+ the offset to ffetarget_align, which assumes aligning *up*
+ is desired. */
+ pad = ffetarget_align (&alignment, &modulo,
+ - ffestorag_offset (st),
+ alignment, 0);
+ ffestorag_set_modulo (st, pad);
+ }
+
+ if (init)
+ ffedata_gather (st); /* Gather subordinate inits into one init. */
+}
+
+/* ffeequiv_offset_ -- Determine offset from start of symbol
+
+ ffetargetOffset offset;
+ ffesymbol s; // Symbol for error reporting.
+ ffebld expr; // opSUBSTR, opARRAYREF, opSYMTER, opANY.
+ bool subtract; // FALSE means add to adjust, TRUE means subtract from it.
+ ffetargetOffset adjust; // Helps keep answer in pos range (unsigned).
+ if (!ffeequiv_offset_(&offset,s,expr,subtract,adjust))
+ // error doing the calculation, message already printed
+
+ Returns the offset represented by the SUBSTR, ARRAYREF, or SUBSTR/ARRAYREF
+ combination added-to/subtracted-from the adjustment specified. If there
+ is an error of some kind, returns FALSE, else returns TRUE. Note that
+ only the first storage unit specified is considered; A(1:1) and A(1:2000)
+ have the same first storage unit and so return the same offset. */
+
+static bool
+ffeequiv_offset_ (ffetargetOffset *offset, ffesymbol s UNUSED,
+ ffebld expr, bool subtract, ffetargetOffset adjust,
+ bool no_precede)
+{
+ ffetargetIntegerDefault value = 0;
+ ffetargetOffset cval; /* Converted value. */
+ ffesymbol sym;
+
+ if (expr == NULL)
+ return FALSE;
+
+again: /* :::::::::::::::::::: */
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opANY:
+ return FALSE;
+
+ case FFEBLD_opSYMTER:
+ {
+ ffetargetOffset size; /* Size of a single unit. */
+ ffetargetAlign a; /* Ignored. */
+ ffetargetAlign m; /* Ignored. */
+
+ sym = ffebld_symter (expr);
+ if (ffesymbol_basictype (sym) == FFEINFO_basictypeANY)
+ return FALSE;
+
+ ffetarget_layout (ffesymbol_text (sym), &a, &m, &size,
+ ffesymbol_basictype (sym),
+ ffesymbol_kindtype (sym), 1, 1);
+
+ if (value < 0)
+ { /* Really invalid, as in A(-2:5), but in case
+ it's wanted.... */
+ if (!ffetarget_offset (&cval, -value))
+ return FALSE;
+
+ if (!ffetarget_offset_multiply (&cval, cval, size))
+ return FALSE;
+
+ if (subtract)
+ return ffetarget_offset_add (offset, cval, adjust);
+
+ if (no_precede && (cval > adjust))
+ {
+ neg: /* :::::::::::::::::::: */
+ ffebad_start (FFEBAD_COMMON_NEG);
+ ffebad_string (ffesymbol_text (sym));
+ ffebad_finish ();
+ return FALSE;
+ }
+ return ffetarget_offset_add (offset, -cval, adjust);
+ }
+
+ if (!ffetarget_offset (&cval, value))
+ return FALSE;
+
+ if (!ffetarget_offset_multiply (&cval, cval, size))
+ return FALSE;
+
+ if (!subtract)
+ return ffetarget_offset_add (offset, cval, adjust);
+
+ if (no_precede && (cval > adjust))
+ goto neg; /* :::::::::::::::::::: */
+
+ return ffetarget_offset_add (offset, -cval, adjust);
+ }
+
+ case FFEBLD_opARRAYREF:
+ {
+ ffebld symexp = ffebld_left (expr);
+ ffebld subscripts = ffebld_right (expr);
+ ffebld dims;
+ ffetargetIntegerDefault width;
+ ffetargetIntegerDefault arrayval;
+ ffetargetIntegerDefault lowbound;
+ ffetargetIntegerDefault highbound;
+ ffebld subscript;
+ ffebld dim;
+ ffebld low;
+ ffebld high;
+ int rank = 0;
+
+ if (ffebld_op (symexp) != FFEBLD_opSYMTER)
+ return FALSE;
+
+ sym = ffebld_symter (symexp);
+ if (ffesymbol_basictype (sym) == FFEINFO_basictypeANY)
+ return FALSE;
+
+ if (ffesymbol_size (sym) == FFETARGET_charactersizeNONE)
+ width = 1;
+ else
+ width = ffesymbol_size (sym);
+ dims = ffesymbol_dims (sym);
+
+ while (subscripts != NULL)
+ {
+ ++rank;
+ if (dims == NULL)
+ {
+ ffebad_start (FFEBAD_EQUIV_MANY);
+ ffebad_string (ffesymbol_text (sym));
+ ffebad_finish ();
+ return FALSE;
+ }
+
+ subscript = ffebld_head (subscripts);
+ dim = ffebld_head (dims);
+
+ if (ffebld_op (subscript) == FFEBLD_opANY)
+ return FALSE;
+
+ assert (ffebld_op (subscript) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (subscript))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (subscript))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ arrayval = ffebld_constant_integerdefault (ffebld_conter
+ (subscript));
+
+ if (ffebld_op (dim) == FFEBLD_opANY)
+ return FALSE;
+
+ assert (ffebld_op (dim) == FFEBLD_opBOUNDS);
+ low = ffebld_left (dim);
+ high = ffebld_right (dim);
+
+ if (low == NULL)
+ lowbound = 1;
+ else
+ {
+ if (ffebld_op (low) == FFEBLD_opANY)
+ return FALSE;
+
+ assert (ffebld_op (low) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (low))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (low))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ lowbound
+ = ffebld_constant_integerdefault (ffebld_conter (low));
+ }
+
+ if (ffebld_op (high) == FFEBLD_opANY)
+ return FALSE;
+
+ assert (ffebld_op (high) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (high))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (high))
+ == FFEINFO_kindtypeINTEGER1);
+ highbound
+ = ffebld_constant_integerdefault (ffebld_conter (high));
+
+ if ((arrayval < lowbound) || (arrayval > highbound))
+ {
+ char rankstr[10];
+
+ sprintf (rankstr, "%d", rank);
+ ffebad_start (FFEBAD_EQUIV_SUBSCRIPT);
+ ffebad_string (ffesymbol_text (sym));
+ ffebad_string (rankstr);
+ ffebad_finish ();
+ }
+
+ subscripts = ffebld_trail (subscripts);
+ dims = ffebld_trail (dims);
+
+ value += width * (arrayval - lowbound);
+ if (subscripts != NULL)
+ width *= highbound - lowbound + 1;
+ }
+
+ if (dims != NULL)
+ {
+ ffebad_start (FFEBAD_EQUIV_FEW);
+ ffebad_string (ffesymbol_text (sym));
+ ffebad_finish ();
+ return FALSE;
+ }
+
+ expr = symexp;
+ }
+ goto again; /* :::::::::::::::::::: */
+
+ case FFEBLD_opSUBSTR:
+ {
+ ffebld begin = ffebld_head (ffebld_right (expr));
+
+ expr = ffebld_left (expr);
+ if (ffebld_op (expr) == FFEBLD_opANY)
+ return FALSE;
+ if (ffebld_op (expr) == FFEBLD_opARRAYREF)
+ sym = ffebld_symter (ffebld_left (expr));
+ else if (ffebld_op (expr) == FFEBLD_opSYMTER)
+ sym = ffebld_symter (expr);
+ else
+ sym = NULL;
+
+ if ((sym != NULL)
+ && (ffesymbol_basictype (sym) == FFEINFO_basictypeANY))
+ return FALSE;
+
+ if (begin == NULL)
+ value = 0;
+ else
+ {
+ if (ffebld_op (begin) == FFEBLD_opANY)
+ return FALSE;
+ assert (ffebld_op (begin) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (begin))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (begin))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+
+ value = ffebld_constant_integerdefault (ffebld_conter (begin));
+
+ if ((value < 1)
+ || ((sym != NULL)
+ && (value > ffesymbol_size (sym))))
+ {
+ ffebad_start (FFEBAD_EQUIV_RANGE);
+ ffebad_string (ffesymbol_text (sym));
+ ffebad_finish ();
+ }
+
+ --value;
+ }
+ if ((sym != NULL)
+ && (ffesymbol_basictype (sym) != FFEINFO_basictypeCHARACTER))
+ {
+ ffebad_start (FFEBAD_EQUIV_SUBSTR);
+ ffebad_string (ffesymbol_text (sym));
+ ffebad_finish ();
+ value = 0;
+ }
+ }
+ goto again; /* :::::::::::::::::::: */
+
+ default:
+ assert ("bad op" == NULL);
+ return FALSE;
+ }
+
+}
+
+/* ffeequiv_add -- Add list of equivalences to list of lists for eq object
+
+ ffeequiv eq;
+ ffebld list;
+ ffelexToken t; // points to first item in equivalence list
+ ffeequiv_add(eq,list,t);
+
+ Check the list to make sure only one common symbol is involved (even
+ if multiple times) and agrees with the common symbol for the equivalence
+ object (or it has no common symbol until now). Prepend (or append, it
+ doesn't matter) the list to the list of lists for the equivalence object.
+ Otherwise report an error and return. */
+
+void
+ffeequiv_add (ffeequiv eq, ffebld list, ffelexToken t)
+{
+ ffebld item;
+ ffesymbol symbol;
+ ffesymbol common = ffeequiv_common (eq);
+
+ for (item = list; item != NULL; item = ffebld_trail (item))
+ {
+ symbol = ffeequiv_symbol (ffebld_head (item));
+
+ if (ffesymbol_common (symbol) != NULL) /* Is symbol known in COMMON yet? */
+ {
+ if (common == NULL)
+ common = ffesymbol_common (symbol);
+ else if (common != ffesymbol_common (symbol))
+ {
+ /* Yes, and symbol disagrees with others on the COMMON area. */
+ ffebad_start (FFEBAD_EQUIV_COMMON);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_string (ffesymbol_text (common));
+ ffebad_string (ffesymbol_text (ffesymbol_common (symbol)));
+ ffebad_finish ();
+ return;
+ }
+ }
+ }
+
+ if ((common != NULL)
+ && (ffeequiv_common (eq) == NULL)) /* Is COMMON involved already? */
+ ffeequiv_set_common (eq, common); /* No, but it is now. */
+
+ for (item = list; item != NULL; item = ffebld_trail (item))
+ {
+ symbol = ffeequiv_symbol (ffebld_head (item));
+
+ if (ffesymbol_equiv (symbol) == NULL)
+ ffesymbol_set_equiv (symbol, eq);
+ else
+ assert (ffesymbol_equiv (symbol) == eq);
+
+ if (ffesymbol_common (symbol) == NULL) /* Is symbol in a COMMON
+ area? */
+ { /* No (at least not yet). */
+ if (ffesymbol_is_save (symbol))
+ ffeequiv_update_save (eq); /* EQUIVALENCE has >=1 SAVEd entity. */
+ if (ffesymbol_is_init (symbol))
+ ffeequiv_update_init (eq); /* EQUIVALENCE has >=1 init'd entity. */
+ continue; /* Nothing more to do here. */
+ }
+
+#if FFEGLOBAL_ENABLED
+ if (ffesymbol_is_init (symbol))
+ ffeglobal_init_common (ffesymbol_common (symbol), t);
+#endif
+
+ if (ffesymbol_is_save (ffesymbol_common (symbol)))
+ ffeequiv_update_save (eq); /* EQUIVALENCE is in a SAVEd COMMON block. */
+ if (ffesymbol_is_init (ffesymbol_common (symbol)))
+ ffeequiv_update_init (eq); /* EQUIVALENCE is in a init'd COMMON block. */
+ }
+
+ ffeequiv_set_list (eq, ffebld_new_item (list, ffeequiv_list (eq)));
+}
+
+/* ffeequiv_dump -- Dump info on equivalence object
+
+ ffeequiv eq;
+ ffeequiv_dump(eq); */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffeequiv_dump (ffeequiv eq)
+{
+ if (ffeequiv_common (eq) != NULL)
+ fprintf (dmpout, "(common %s) ", ffesymbol_text (ffeequiv_common (eq)));
+ ffebld_dump (ffeequiv_list (eq));
+}
+#endif
+
+/* ffeequiv_exec_transition -- Do the hard work on all the equivalence objects
+
+ ffeequiv_exec_transition(); */
+
+void
+ffeequiv_exec_transition ()
+{
+ while (ffeequiv_list_.first != (ffeequiv) &ffeequiv_list_.first)
+ ffeequiv_layout_local_ (ffeequiv_list_.first);
+}
+
+/* ffeequiv_init_2 -- Initialize for new program unit
+
+ ffeequiv_init_2();
+
+ Initializes the list of equivalences. */
+
+void
+ffeequiv_init_2 ()
+{
+ ffeequiv_list_.first = (ffeequiv) &ffeequiv_list_.first;
+ ffeequiv_list_.last = (ffeequiv) &ffeequiv_list_.first;
+}
+
+/* ffeequiv_kill -- Kill equivalence object after removing from list
+
+ ffeequiv eq;
+ ffeequiv_kill(eq);
+
+ Removes equivalence object from master list, then kills it. */
+
+void
+ffeequiv_kill (ffeequiv victim)
+{
+ victim->next->previous = victim->previous;
+ victim->previous->next = victim->next;
+ if (ffe_is_do_internal_checks ())
+ {
+ ffebld list;
+ ffebld item;
+ ffebld expr;
+
+ /* Assert that nobody our victim points to still points to it. */
+
+ assert ((victim->common == NULL)
+ || (ffesymbol_equiv (victim->common) == NULL));
+
+ for (list = victim->list; list != NULL; list = ffebld_trail (list))
+ {
+ for (item = ffebld_head (list); item != NULL; item = ffebld_trail (item))
+ {
+ ffesymbol sym;
+
+ expr = ffebld_head (item);
+ sym = ffeequiv_symbol (expr);
+ if (sym == NULL)
+ continue;
+ assert (ffesymbol_equiv (sym) != victim);
+ }
+ }
+ }
+ malloc_kill_ks (ffe_pool_program_unit (), victim, sizeof (*victim));
+}
+
+/* ffeequiv_layout_cblock -- Lay out storage for common area
+
+ ffestorag st;
+ if (ffeequiv_layout_cblock(st))
+ // at least one equiv'd symbol has init/accretion expr.
+
+ Now that the explicitly COMMONed variables in the common area (whose
+ ffestorag object is passed) have been laid out, lay out the storage
+ for all variables equivalenced into the area by making subordinate
+ ffestorag objects for them. */
+
+bool
+ffeequiv_layout_cblock (ffestorag st)
+{
+ ffesymbol s = ffestorag_symbol (st); /* CBLOCK symbol. */
+ ffebld list; /* List of explicit common vars, in order, in
+ s. */
+ ffebld item; /* List of list of equivalences in a given
+ explicit common var. */
+ ffebld root; /* Expression for (1st) explicit common var
+ in list of eqs. */
+ ffestorag rst; /* Storage for root. */
+ ffetargetOffset root_offset; /* Offset for root into common area. */
+ ffesymbol sr; /* Root itself. */
+ ffeequiv seq; /* Its equivalence object, if any. */
+ ffebld var; /* Expression for equivalence. */
+ ffestorag vst; /* Storage for var. */
+ ffetargetOffset var_offset; /* Offset for var into common area. */
+ ffesymbol sv; /* Var itself. */
+ ffebld altroot; /* Alternate root. */
+ ffesymbol altrootsym; /* Alternate root symbol. */
+ ffetargetAlign alignment;
+ ffetargetAlign modulo;
+ ffetargetAlign pad;
+ ffetargetOffset size;
+ ffetargetOffset num_elements;
+ bool new_storage; /* Established new storage info. */
+ bool need_storage; /* Have need for more storage info. */
+ bool ok;
+ bool init = FALSE;
+
+ assert (st != NULL);
+ assert (ffestorag_type (st) == FFESTORAG_typeCBLOCK);
+ assert (ffesymbol_kind (ffestorag_symbol (st)) == FFEINFO_kindCOMMON);
+
+ for (list = ffesymbol_commonlist (ffestorag_symbol (st));
+ list != NULL;
+ list = ffebld_trail (list))
+ { /* For every variable in the common area */
+ assert (ffebld_op (ffebld_head (list)) == FFEBLD_opSYMTER);
+ sr = ffebld_symter (ffebld_head (list));
+ if ((seq = ffesymbol_equiv (sr)) == NULL)
+ continue; /* No equivalences to process. */
+ rst = ffesymbol_storage (sr);
+ if (rst == NULL)
+ {
+ assert (ffesymbol_kind (sr) == FFEINFO_kindANY);
+ continue;
+ }
+ ffesymbol_set_equiv (sr, NULL); /* Cancel ref to equiv obj. */
+ do
+ {
+ new_storage = FALSE;
+ need_storage = FALSE;
+ for (item = ffeequiv_list (seq); /* Get list of equivs. */
+ item != NULL;
+ item = ffebld_trail (item))
+ { /* For every eqv list in the list of equivs
+ for the variable */
+ altroot = NULL;
+ altrootsym = NULL;
+ for (root = ffebld_head (item);
+ root != NULL;
+ root = ffebld_trail (root))
+ { /* For every equivalence item in the list */
+ sv = ffeequiv_symbol (ffebld_head (root));
+ if (sv == sr)
+ break; /* Found first mention of "rooted" symbol. */
+ if (ffesymbol_storage (sv) != NULL)
+ {
+ altroot = root; /* If no mention, use this guy
+ instead. */
+ altrootsym = sv;
+ }
+ }
+ if (root != NULL)
+ {
+ root = ffebld_head (root); /* Lose its opITEM. */
+ ok = ffeequiv_offset_ (&root_offset, sr, root, FALSE,
+ ffestorag_offset (rst), TRUE);
+ /* Equiv point prior to start of common area? */
+ }
+ else if (altroot != NULL)
+ {
+ /* Equiv point prior to start of common area? */
+ root = ffebld_head (altroot);
+ ok = ffeequiv_offset_ (&root_offset, altrootsym, root,
+ FALSE,
+ ffestorag_offset (ffesymbol_storage (altrootsym)),
+ TRUE);
+ ffesymbol_set_equiv (altrootsym, NULL);
+ }
+ else
+ /* No rooted symbol in list of equivalences! */
+ { /* Assume this was due to opANY and ignore
+ this list for now. */
+ need_storage = TRUE;
+ continue;
+ }
+
+ /* We now know the root symbol and the operating offset of that
+ root into the common area. The other expressions in the
+ list all identify an initial storage unit that must have the
+ same offset. */
+
+ for (var = ffebld_head (item);
+ var != NULL;
+ var = ffebld_trail (var))
+ { /* For every equivalence item in the list */
+ if (ffebld_head (var) == root)
+ continue; /* Except root, of course. */
+ sv = ffeequiv_symbol (ffebld_head (var));
+ if (sv == NULL)
+ continue; /* Except erroneous stuff (opANY). */
+ ffesymbol_set_equiv (sv, NULL); /* Don't need this ref
+ anymore. */
+ if (!ok
+ || !ffeequiv_offset_ (&var_offset, sv,
+ ffebld_head (var), TRUE,
+ root_offset, TRUE))
+ continue; /* Can't do negative offset wrt COMMON. */
+
+ if (ffesymbol_rank (sv) == 0)
+ num_elements = 1;
+ else
+ num_elements = ffebld_constant_integerdefault
+ (ffebld_conter (ffesymbol_arraysize (sv)));
+ ffetarget_layout (ffesymbol_text (sv), &alignment,
+ &modulo, &size,
+ ffesymbol_basictype (sv),
+ ffesymbol_kindtype (sv),
+ ffesymbol_size (sv), num_elements);
+ pad = ffetarget_align (ffestorag_ptr_to_alignment (st),
+ ffestorag_ptr_to_modulo (st),
+ var_offset, alignment, modulo);
+ if (pad != 0)
+ {
+ ffebad_start (FFEBAD_EQUIV_ALIGN);
+ ffebad_string (ffesymbol_text (sv));
+ ffebad_finish ();
+ continue;
+ }
+
+ if ((vst = ffesymbol_storage (sv)) == NULL)
+ { /* Create new ffestorag object, extend
+ cblock. */
+ new_storage = TRUE;
+ vst = ffestorag_new (ffestorag_list_equivs (st));
+ ffestorag_set_parent (vst, st); /* Initializations
+ happen there. */
+ ffestorag_set_init (vst, NULL);
+ ffestorag_set_accretion (vst, NULL);
+ ffestorag_set_symbol (vst, sv);
+ ffestorag_set_size (vst, size);
+ ffestorag_set_offset (vst, var_offset);
+ ffestorag_set_alignment (vst, alignment);
+ ffestorag_set_modulo (vst, modulo);
+ ffestorag_set_type (vst, FFESTORAG_typeEQUIV);
+ ffestorag_set_basictype (vst, ffesymbol_basictype (sv));
+ ffestorag_set_kindtype (vst, ffesymbol_kindtype (sv));
+ ffestorag_set_typesymbol (vst, sv);
+ ffestorag_set_is_save (vst, FALSE); /* Assume FALSE... */
+ if (ffestorag_is_save (st)) /* ...update TRUE */
+ ffestorag_update_save (vst); /* if needed. */
+ ffestorag_set_is_init (vst, FALSE); /* Assume FALSE... */
+ if (ffestorag_is_init (st)) /* ...update TRUE */
+ ffestorag_update_init (vst); /* if needed. */
+ if (!ffetarget_offset_add (&size, var_offset, size))
+ /* Find one size of common block, complain if
+ overflow. */
+ ffetarget_offset_overflow (ffesymbol_text (s));
+ else if (size > ffestorag_size (st))
+ /* Extend common. */
+ ffestorag_set_size (st, size);
+ ffesymbol_set_storage (sv, vst);
+ ffesymbol_set_common (sv, s);
+ ffesymbol_signal_unreported (sv);
+ ffestorag_update (st, sv, ffesymbol_basictype (sv),
+ ffesymbol_kindtype (sv));
+ if (ffesymbol_is_init (sv))
+ init = TRUE;
+ }
+ else
+ {
+ /* Make sure offset agrees with known offset. */
+ if (var_offset != ffestorag_offset (vst))
+ {
+ char io1[40];
+ char io2[40];
+
+ sprintf (&io1[0], "%" ffetargetOffset_f "d", var_offset);
+ sprintf (&io2[0], "%" ffetargetOffset_f "d", ffestorag_offset (vst));
+ ffebad_start (FFEBAD_EQUIV_MISMATCH);
+ ffebad_string (ffesymbol_text (sv));
+ ffebad_string (ffesymbol_text (s));
+ ffebad_string (io1);
+ ffebad_string (io2);
+ ffebad_finish ();
+ }
+ }
+ } /* (For every equivalence item in the list) */
+ } /* (For every eqv list in the list of equivs
+ for the variable) */
+ }
+ while (new_storage && need_storage);
+
+ ffeequiv_kill (seq); /* Kill equiv obj. */
+ } /* (For every variable in the common area) */
+
+ return init;
+}
+
+/* ffeequiv_merge -- Merge two equivalence objects, return the merged result
+
+ ffeequiv eq1;
+ ffeequiv eq2;
+ ffelexToken t; // points to current equivalence item forcing the merge.
+ eq1 = ffeequiv_merge(eq1,eq2,t);
+
+ If the two equivalence objects can be merged, they are, all the
+ ffesymbols in their lists of lists are adjusted to point to the merged
+ equivalence object, and the merged object is returned.
+
+ Otherwise, the two equivalence objects have different non-NULL common
+ symbols, so the merge cannot take place. An error message is issued and
+ NULL is returned. */
+
+ffeequiv
+ffeequiv_merge (ffeequiv eq1, ffeequiv eq2, ffelexToken t)
+{
+ ffebld list;
+ ffebld eqs;
+ ffesymbol symbol;
+ ffebld last = NULL;
+
+ /* If both equivalence objects point to different common-based symbols,
+ complain. Of course, one or both might have NULL common symbols now,
+ and get COMMONed later, but the COMMON statement handler checks for
+ this. */
+
+ if ((ffeequiv_common (eq1) != NULL) && (ffeequiv_common (eq2) != NULL)
+ && (ffeequiv_common (eq1) != ffeequiv_common (eq2)))
+ {
+ ffebad_start (FFEBAD_EQUIV_COMMON);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_string (ffesymbol_text (ffeequiv_common (eq1)));
+ ffebad_string (ffesymbol_text (ffeequiv_common (eq2)));
+ ffebad_finish ();
+ return NULL;
+ }
+
+ /* Make eq1 the new, merged object (arbitrarily). */
+
+ if (ffeequiv_common (eq1) == NULL)
+ ffeequiv_set_common (eq1, ffeequiv_common (eq2));
+
+ /* If the victim object has any init'ed entities, so does the new object. */
+
+ if (eq2->is_init)
+ eq1->is_init = TRUE;
+
+#if FFEGLOBAL_ENABLED
+ if (eq1->is_init && (ffeequiv_common (eq1) != NULL))
+ ffeglobal_init_common (ffeequiv_common (eq1), t);
+#endif
+
+ /* If the victim object has any SAVEd entities, then the new object has
+ some. */
+
+ if (ffeequiv_is_save (eq2))
+ ffeequiv_update_save (eq1);
+
+ /* If the victim object has any init'd entities, then the new object has
+ some. */
+
+ if (ffeequiv_is_init (eq2))
+ ffeequiv_update_init (eq1);
+
+ /* Adjust all the symbols in the list of lists of equivalences for the
+ victim equivalence object so they point to the new merged object
+ instead. */
+
+ for (list = ffeequiv_list (eq2); list != NULL; list = ffebld_trail (list))
+ {
+ for (eqs = ffebld_head (list); eqs != NULL; eqs = ffebld_trail (eqs))
+ {
+ symbol = ffeequiv_symbol (ffebld_head (eqs));
+ if (ffesymbol_equiv (symbol) == eq2)
+ ffesymbol_set_equiv (symbol, eq1);
+ else
+ assert (ffesymbol_equiv (symbol) == eq1); /* Can see a sym > once. */
+ }
+
+ /* For convenience, remember where the last ITEM in the outer list is. */
+
+ if (ffebld_trail (list) == NULL)
+ {
+ last = list;
+ break;
+ }
+ }
+
+ /* Append the list of lists in the new, merged object to the list of lists
+ in the victim object, then use the new combined list in the new merged
+ object. */
+
+ ffebld_set_trail (last, ffeequiv_list (eq1));
+ ffeequiv_set_list (eq1, ffeequiv_list (eq2));
+
+ /* Unlink and kill the victim object. */
+
+ ffeequiv_kill (eq2);
+
+ return eq1; /* Return the new merged object. */
+}
+
+/* ffeequiv_new -- Create new equivalence object, put in list
+
+ ffeequiv eq;
+ eq = ffeequiv_new();
+
+ Creates a new equivalence object and adds it to the list of equivalence
+ objects. */
+
+ffeequiv
+ffeequiv_new ()
+{
+ ffeequiv eq;
+
+ eq = malloc_new_ks (ffe_pool_program_unit (), "ffeequiv", sizeof (*eq));
+ eq->next = (ffeequiv) &ffeequiv_list_.first;
+ eq->previous = ffeequiv_list_.last;
+ ffeequiv_set_common (eq, NULL); /* No COMMON area yet. */
+ ffeequiv_set_list (eq, NULL); /* No list of lists of equivalences yet. */
+ ffeequiv_set_is_save (eq, FALSE);
+ ffeequiv_set_is_init (eq, FALSE);
+ eq->next->previous = eq;
+ eq->previous->next = eq;
+
+ return eq;
+}
+
+/* ffeequiv_symbol -- Return symbol for equivalence expression
+
+ ffesymbol symbol;
+ ffebld expr;
+ symbol = ffeequiv_symbol(expr);
+
+ Finds the terminal SYMTER in an equivalence expression and returns the
+ ffesymbol for it. */
+
+ffesymbol
+ffeequiv_symbol (ffebld expr)
+{
+ assert (expr != NULL);
+
+again: /* :::::::::::::::::::: */
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opARRAYREF:
+ case FFEBLD_opSUBSTR:
+ expr = ffebld_left (expr);
+ goto again; /* :::::::::::::::::::: */
+
+ case FFEBLD_opSYMTER:
+ return ffebld_symter (expr);
+
+ case FFEBLD_opANY:
+ return NULL;
+
+ default:
+ assert ("bad eq expr" == NULL);
+ return NULL;
+ }
+}
+
+/* ffeequiv_update_init -- Update the INIT flag for the area to TRUE
+
+ ffeequiv eq;
+ ffeequiv_update_init(eq);
+
+ If the INIT flag for the <eq> object is already set, return. Else,
+ set it TRUE and call ffe*_update_init for all objects contained in
+ this one. */
+
+void
+ffeequiv_update_init (ffeequiv eq)
+{
+ ffebld list; /* Current list in list of lists. */
+ ffebld item; /* Current item in current list. */
+ ffebld expr; /* Expression in head of current item. */
+
+ if (eq->is_init)
+ return;
+
+ eq->is_init = TRUE;
+
+ if ((eq->common != NULL)
+ && !ffesymbol_is_init (eq->common))
+ ffesymbol_update_init (eq->common); /* Shouldn't be needed. */
+
+ for (list = eq->list; list != NULL; list = ffebld_trail (list))
+ {
+ for (item = ffebld_head (list); item != NULL; item = ffebld_trail (item))
+ {
+ expr = ffebld_head (item);
+
+ again: /* :::::::::::::::::::: */
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opANY:
+ break;
+
+ case FFEBLD_opSYMTER:
+ if (!ffesymbol_is_init (ffebld_symter (expr)))
+ ffesymbol_update_init (ffebld_symter (expr));
+ break;
+
+ case FFEBLD_opARRAYREF:
+ expr = ffebld_left (expr);
+ goto again; /* :::::::::::::::::::: */
+
+ case FFEBLD_opSUBSTR:
+ expr = ffebld_left (expr);
+ goto again; /* :::::::::::::::::::: */
+
+ default:
+ assert ("bad op for ffeequiv_update_init" == NULL);
+ break;
+ }
+ }
+ }
+}
+
+/* ffeequiv_update_save -- Update the SAVE flag for the area to TRUE
+
+ ffeequiv eq;
+ ffeequiv_update_save(eq);
+
+ If the SAVE flag for the <eq> object is already set, return. Else,
+ set it TRUE and call ffe*_update_save for all objects contained in
+ this one. */
+
+void
+ffeequiv_update_save (ffeequiv eq)
+{
+ ffebld list; /* Current list in list of lists. */
+ ffebld item; /* Current item in current list. */
+ ffebld expr; /* Expression in head of current item. */
+
+ if (eq->is_save)
+ return;
+
+ eq->is_save = TRUE;
+
+ if ((eq->common != NULL)
+ && !ffesymbol_is_save (eq->common))
+ ffesymbol_update_save (eq->common); /* Shouldn't be needed. */
+
+ for (list = eq->list; list != NULL; list = ffebld_trail (list))
+ {
+ for (item = ffebld_head (list); item != NULL; item = ffebld_trail (item))
+ {
+ expr = ffebld_head (item);
+
+ again: /* :::::::::::::::::::: */
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opANY:
+ break;
+
+ case FFEBLD_opSYMTER:
+ if (!ffesymbol_is_save (ffebld_symter (expr)))
+ ffesymbol_update_save (ffebld_symter (expr));
+ break;
+
+ case FFEBLD_opARRAYREF:
+ expr = ffebld_left (expr);
+ goto again; /* :::::::::::::::::::: */
+
+ case FFEBLD_opSUBSTR:
+ expr = ffebld_left (expr);
+ goto again; /* :::::::::::::::::::: */
+
+ default:
+ assert ("bad op for ffeequiv_update_save" == NULL);
+ break;
+ }
+ }
+ }
+}
diff --git a/contrib/gcc/f/equiv.h b/contrib/gcc/f/equiv.h
new file mode 100644
index 0000000..daf0cee
--- /dev/null
+++ b/contrib/gcc/f/equiv.h
@@ -0,0 +1,103 @@
+/* equiv.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ equiv.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_equiv
+#define _H_f_equiv
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+typedef struct _ffeequiv_ *ffeequiv;
+
+/* Include files needed by this one. */
+
+#include "bld.h"
+#include "lex.h"
+#include "storag.h"
+#include "symbol.h"
+
+/* Structure definitions. */
+
+struct _ffeequiv_
+ {
+ ffeequiv next;
+ ffeequiv previous;
+ ffesymbol common; /* Common area for this equiv, if any. */
+ ffebld list; /* List of lists of equiv exprs. */
+ bool is_save; /* Any SAVEd members? */
+ bool is_init; /* Any initialized members? */
+ };
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+void ffeequiv_add (ffeequiv eq, ffebld list, ffelexToken t);
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffeequiv_dump (ffeequiv eq);
+#endif
+void ffeequiv_exec_transition (void);
+void ffeequiv_init_2 (void);
+void ffeequiv_kill (ffeequiv victim);
+bool ffeequiv_layout_cblock (ffestorag st);
+ffeequiv ffeequiv_merge (ffeequiv eq1, ffeequiv eq2, ffelexToken t);
+ffeequiv ffeequiv_new (void);
+ffesymbol ffeequiv_symbol (ffebld expr);
+void ffeequiv_update_init (ffeequiv eq);
+void ffeequiv_update_save (ffeequiv eq);
+
+/* Define macros. */
+
+#define ffeequiv_common(e) ((e)->common)
+#define ffeequiv_init_0()
+#define ffeequiv_init_1()
+#define ffeequiv_init_3()
+#define ffeequiv_init_4()
+#define ffeequiv_is_init(e) ((e)->is_init)
+#define ffeequiv_is_save(e) ((e)->is_save)
+#define ffeequiv_list(e) ((e)->list)
+#define ffeequiv_next(e) ((e)->next)
+#define ffeequiv_previous(e) ((e)->previous)
+#define ffeequiv_set_common(e,c) ((e)->common = (c))
+#define ffeequiv_set_init(e,i) ((e)->init = (i))
+#define ffeequiv_set_is_init(e,in) ((e)->is_init = (in))
+#define ffeequiv_set_is_save(e,sa) ((e)->is_save = (sa))
+#define ffeequiv_set_list(e,l) ((e)->list = (l))
+#define ffeequiv_terminate_0()
+#define ffeequiv_terminate_1()
+#define ffeequiv_terminate_2()
+#define ffeequiv_terminate_3()
+#define ffeequiv_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/expr.c b/contrib/gcc/f/expr.c
new file mode 100644
index 0000000..7e7bf867
--- /dev/null
+++ b/contrib/gcc/f/expr.c
@@ -0,0 +1,19304 @@
+/* expr.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995-1998 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None.
+
+ Description:
+ Handles syntactic and semantic analysis of Fortran expressions.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "expr.h"
+#include "bad.h"
+#include "bld.h"
+#include "com.h"
+#include "global.h"
+#include "implic.h"
+#include "intrin.h"
+#include "info.h"
+#include "lex.h"
+#include "malloc.h"
+#include "src.h"
+#include "st.h"
+#include "symbol.h"
+#include "str.h"
+#include "target.h"
+#include "where.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFEEXPR_exprtypeUNKNOWN_,
+ FFEEXPR_exprtypeOPERAND_,
+ FFEEXPR_exprtypeUNARY_,
+ FFEEXPR_exprtypeBINARY_,
+ FFEEXPR_exprtype_
+ } ffeexprExprtype_;
+
+typedef enum
+ {
+ FFEEXPR_operatorPOWER_,
+ FFEEXPR_operatorMULTIPLY_,
+ FFEEXPR_operatorDIVIDE_,
+ FFEEXPR_operatorADD_,
+ FFEEXPR_operatorSUBTRACT_,
+ FFEEXPR_operatorCONCATENATE_,
+ FFEEXPR_operatorLT_,
+ FFEEXPR_operatorLE_,
+ FFEEXPR_operatorEQ_,
+ FFEEXPR_operatorNE_,
+ FFEEXPR_operatorGT_,
+ FFEEXPR_operatorGE_,
+ FFEEXPR_operatorNOT_,
+ FFEEXPR_operatorAND_,
+ FFEEXPR_operatorOR_,
+ FFEEXPR_operatorXOR_,
+ FFEEXPR_operatorEQV_,
+ FFEEXPR_operatorNEQV_,
+ FFEEXPR_operator_
+ } ffeexprOperator_;
+
+typedef enum
+ {
+ FFEEXPR_operatorprecedenceHIGHEST_ = 1,
+ FFEEXPR_operatorprecedencePOWER_ = 1,
+ FFEEXPR_operatorprecedenceMULTIPLY_ = 2,
+ FFEEXPR_operatorprecedenceDIVIDE_ = 2,
+ FFEEXPR_operatorprecedenceADD_ = 3,
+ FFEEXPR_operatorprecedenceSUBTRACT_ = 3,
+ FFEEXPR_operatorprecedenceLOWARITH_ = 3,
+ FFEEXPR_operatorprecedenceCONCATENATE_ = 3,
+ FFEEXPR_operatorprecedenceLT_ = 4,
+ FFEEXPR_operatorprecedenceLE_ = 4,
+ FFEEXPR_operatorprecedenceEQ_ = 4,
+ FFEEXPR_operatorprecedenceNE_ = 4,
+ FFEEXPR_operatorprecedenceGT_ = 4,
+ FFEEXPR_operatorprecedenceGE_ = 4,
+ FFEEXPR_operatorprecedenceNOT_ = 5,
+ FFEEXPR_operatorprecedenceAND_ = 6,
+ FFEEXPR_operatorprecedenceOR_ = 7,
+ FFEEXPR_operatorprecedenceXOR_ = 8,
+ FFEEXPR_operatorprecedenceEQV_ = 8,
+ FFEEXPR_operatorprecedenceNEQV_ = 8,
+ FFEEXPR_operatorprecedenceLOWEST_ = 8,
+ FFEEXPR_operatorprecedence_
+ } ffeexprOperatorPrecedence_;
+
+#define FFEEXPR_operatorassociativityL2R_ TRUE
+#define FFEEXPR_operatorassociativityR2L_ FALSE
+#define FFEEXPR_operatorassociativityPOWER_ FFEEXPR_operatorassociativityR2L_
+#define FFEEXPR_operatorassociativityMULTIPLY_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityDIVIDE_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityADD_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativitySUBTRACT_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityCONCATENATE_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityLT_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityLE_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityEQ_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityNE_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityGT_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityGE_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityNOT_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityAND_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityOR_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityXOR_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityEQV_ FFEEXPR_operatorassociativityL2R_
+#define FFEEXPR_operatorassociativityNEQV_ FFEEXPR_operatorassociativityL2R_
+
+typedef enum
+ {
+ FFEEXPR_parentypeFUNCTION_,
+ FFEEXPR_parentypeSUBROUTINE_,
+ FFEEXPR_parentypeARRAY_,
+ FFEEXPR_parentypeSUBSTRING_,
+ FFEEXPR_parentypeFUNSUBSTR_,/* Ambig: check for colon after first expr. */
+ FFEEXPR_parentypeEQUIVALENCE_, /* Ambig: ARRAY_ or SUBSTRING_. */
+ FFEEXPR_parentypeANY_, /* Allow basically anything. */
+ FFEEXPR_parentype_
+ } ffeexprParenType_;
+
+typedef enum
+ {
+ FFEEXPR_percentNONE_,
+ FFEEXPR_percentLOC_,
+ FFEEXPR_percentVAL_,
+ FFEEXPR_percentREF_,
+ FFEEXPR_percentDESCR_,
+ FFEEXPR_percent_
+ } ffeexprPercent_;
+
+/* Internal typedefs. */
+
+typedef struct _ffeexpr_expr_ *ffeexprExpr_;
+typedef bool ffeexprOperatorAssociativity_;
+typedef struct _ffeexpr_stack_ *ffeexprStack_;
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+struct _ffeexpr_expr_
+ {
+ ffeexprExpr_ previous;
+ ffelexToken token;
+ ffeexprExprtype_ type;
+ union
+ {
+ struct
+ {
+ ffeexprOperator_ op;
+ ffeexprOperatorPrecedence_ prec;
+ ffeexprOperatorAssociativity_ as;
+ }
+ operator;
+ ffebld operand;
+ }
+ u;
+ };
+
+struct _ffeexpr_stack_
+ {
+ ffeexprStack_ previous;
+ mallocPool pool;
+ ffeexprContext context;
+ ffeexprCallback callback;
+ ffelexToken first_token;
+ ffeexprExpr_ exprstack;
+ ffelexToken tokens[10]; /* Used in certain cases, like (unary)
+ open-paren. */
+ ffebld expr; /* For first of
+ complex/implied-do/substring/array-elements
+ / actual-args expression. */
+ ffebld bound_list; /* For tracking dimension bounds list of
+ array. */
+ ffebldListBottom bottom; /* For building lists. */
+ ffeinfoRank rank; /* For elements in an array reference. */
+ bool constant; /* TRUE while elements seen so far are
+ constants. */
+ bool immediate; /* TRUE while elements seen so far are
+ immediate/constants. */
+ ffebld next_dummy; /* Next SFUNC dummy arg in arg list. */
+ ffebldListLength num_args; /* Number of dummy args expected in arg list. */
+ bool is_rhs; /* TRUE if rhs context, FALSE otherwise. */
+ ffeexprPercent_ percent; /* Current %FOO keyword. */
+ };
+
+struct _ffeexpr_find_
+ {
+ ffelexToken t;
+ ffelexHandler after;
+ int level;
+ };
+
+/* Static objects accessed by functions in this module. */
+
+static ffeexprStack_ ffeexpr_stack_; /* Expression stack for semantic. */
+static ffelexToken ffeexpr_tokens_[10]; /* Scratchpad tokens for syntactic. */
+static ffestrOther ffeexpr_current_dotdot_; /* Current .FOO. keyword. */
+static long ffeexpr_hollerith_count_; /* ffeexpr_token_number_ and caller. */
+static int ffeexpr_level_; /* Level of DATA implied-DO construct. */
+static bool ffeexpr_is_substr_ok_; /* If OPEN_PAREN as binary "op" ok. */
+static struct _ffeexpr_find_ ffeexpr_find_;
+
+/* Static functions (internal). */
+
+static ffelexHandler ffeexpr_cb_close_paren_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_close_paren_ambig_ (ffelexToken ft,
+ ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_close_paren_ambig_1_ (ffelexToken t);
+static ffelexHandler ffeexpr_cb_close_paren_c_ (ffelexToken ft,
+ ffebld expr, ffelexToken t);
+static ffelexHandler ffeexpr_cb_comma_c_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_close_paren_ci_ (ffelexToken ft,
+ ffebld expr, ffelexToken t);
+static ffelexHandler ffeexpr_cb_comma_ci_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_comma_i_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_comma_i_1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_comma_i_2_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_comma_i_3_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_comma_i_4_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_comma_i_5_ (ffelexToken t);
+static ffelexHandler ffeexpr_cb_end_loc_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_end_notloc_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_cb_end_notloc_1_ (ffelexToken t);
+static ffesymbol ffeexpr_check_impctrl_ (ffesymbol s);
+static void ffeexpr_check_impdo_ (ffebld list, ffelexToken list_t,
+ ffebld dovar, ffelexToken dovar_t);
+static void ffeexpr_update_impdo_ (ffebld expr, ffebld dovar);
+static void ffeexpr_update_impdo_sym_ (ffebld expr, ffesymbol dovar);
+static ffeexprContext ffeexpr_context_outer_ (ffeexprStack_ s);
+static ffeexprExpr_ ffeexpr_expr_new_ (void);
+static void ffeexpr_fulfill_call_ (ffebld *expr, ffelexToken t);
+static bool ffeexpr_isdigits_ (char *p);
+static ffelexHandler ffeexpr_token_first_lhs_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_first_lhs_1_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_first_rhs_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_first_rhs_1_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_first_rhs_2_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_first_rhs_3_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_first_rhs_4_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_first_rhs_5_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_first_rhs_6_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_namelist_ (ffelexToken t);
+static void ffeexpr_expr_kill_ (ffeexprExpr_ e);
+static void ffeexpr_exprstack_push_ (ffeexprExpr_ e);
+static void ffeexpr_exprstack_push_binary_ (ffeexprExpr_ e);
+static void ffeexpr_exprstack_push_operand_ (ffeexprExpr_ e);
+static void ffeexpr_exprstack_push_unary_ (ffeexprExpr_ e);
+static void ffeexpr_reduce_ (void);
+static ffebld ffeexpr_reduced_bool1_ (ffebld reduced, ffeexprExpr_ op,
+ ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_bool2_ (ffebld reduced, ffeexprExpr_ l,
+ ffeexprExpr_ op, ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_concatenate_ (ffebld reduced, ffeexprExpr_ l,
+ ffeexprExpr_ op, ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_eqop2_ (ffebld reduced, ffeexprExpr_ l,
+ ffeexprExpr_ op, ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_math1_ (ffebld reduced, ffeexprExpr_ op,
+ ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_math2_ (ffebld reduced, ffeexprExpr_ l,
+ ffeexprExpr_ op, ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_power_ (ffebld reduced, ffeexprExpr_ l,
+ ffeexprExpr_ op, ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_relop2_ (ffebld reduced, ffeexprExpr_ l,
+ ffeexprExpr_ op, ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_ugly1_ (ffebld reduced, ffeexprExpr_ op, ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_ugly1log_ (ffebld reduced, ffeexprExpr_ op,
+ ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_ugly2_ (ffebld reduced, ffeexprExpr_ l,
+ ffeexprExpr_ op, ffeexprExpr_ r);
+static ffebld ffeexpr_reduced_ugly2log_ (ffebld reduced, ffeexprExpr_ l,
+ ffeexprExpr_ op, ffeexprExpr_ r);
+static ffelexHandler ffeexpr_find_close_paren_ (ffelexToken t,
+ ffelexHandler after);
+static ffelexHandler ffeexpr_nil_finished_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_rhs_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_period_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_end_period_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_swallow_period_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_real_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_real_exponent_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_real_exp_sign_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_number_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_number_exponent_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_number_exp_sign_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_number_period_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_number_per_exp_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_number_real_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_num_per_exp_sign_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_number_real_exp_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_num_real_exp_sn_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_binary_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_binary_period_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_binary_end_per_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_binary_sw_per_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_quote_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_apostrophe_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_apos_char_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_name_rhs_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_name_apos_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_name_apos_name_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_percent_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_percent_name_ (ffelexToken t);
+static ffelexHandler ffeexpr_nil_substrp_ (ffelexToken t);
+static ffelexHandler ffeexpr_finished_ (ffelexToken t);
+static ffebld ffeexpr_finished_ambig_ (ffelexToken t, ffebld expr);
+static ffelexHandler ffeexpr_token_lhs_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_rhs_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_binary_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_period_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_end_period_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_swallow_period_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_real_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_real_exponent_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_real_exp_sign_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_number_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_number_exponent_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_number_exp_sign_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_number_period_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_number_per_exp_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_number_real_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_num_per_exp_sign_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_number_real_exp_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_num_real_exp_sn_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_binary_period_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_binary_end_per_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_binary_sw_per_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_quote_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_apostrophe_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_apos_char_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_name_lhs_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_name_arg_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_name_rhs_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_name_apos_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_name_apos_name_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_percent_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_percent_name_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_arguments_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_token_elements_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_token_equivalence_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_token_substring_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_token_substring_1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_token_substrp_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_intrincheck_ (ffelexToken t);
+static ffelexHandler ffeexpr_token_funsubstr_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffeexpr_token_anything_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static void ffeexpr_make_float_const_ (char exp_letter, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction, ffelexToken exponent,
+ ffelexToken exponent_sign, ffelexToken exponent_digits);
+static ffesymbol ffeexpr_declare_unadorned_ (ffelexToken t, bool maybe_intrin);
+static ffesymbol ffeexpr_sym_impdoitem_ (ffesymbol s, ffelexToken t);
+static ffesymbol ffeexpr_sym_lhs_call_ (ffesymbol s, ffelexToken t);
+static ffesymbol ffeexpr_sym_lhs_data_ (ffesymbol s, ffelexToken t);
+static ffesymbol ffeexpr_sym_lhs_equivalence_ (ffesymbol s, ffelexToken t);
+static ffesymbol ffeexpr_sym_lhs_extfunc_ (ffesymbol s, ffelexToken t);
+static ffesymbol ffeexpr_sym_lhs_impdoctrl_ (ffesymbol s, ffelexToken t);
+static ffesymbol ffeexpr_sym_lhs_parameter_ (ffesymbol s, ffelexToken t);
+static ffesymbol ffeexpr_sym_rhs_actualarg_ (ffesymbol s, ffelexToken t);
+static ffesymbol ffeexpr_sym_rhs_dimlist_ (ffesymbol s, ffelexToken t);
+static ffesymbol ffeexpr_sym_rhs_let_ (ffesymbol s, ffelexToken t);
+static ffesymbol ffeexpr_declare_parenthesized_ (ffelexToken t,
+ bool maybe_intrin,
+ ffeexprParenType_ *paren_type);
+static ffesymbol ffeexpr_paren_rhs_let_ (ffesymbol s, ffelexToken t);
+
+/* Internal macros. */
+
+#define ffeexpr_paren_lhs_let_(s,t) ffeexpr_sym_rhs_let_(s,t)
+#define ffeexpr_sym_lhs_let_(s,t) ffeexpr_sym_rhs_let_(s,t)
+
+/* ffeexpr_collapse_convert -- Collapse convert expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_convert(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_convert (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffetargetCharacterSize sz;
+ ffetargetCharacterSize sz2;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ sz = FFETARGET_charactersizeNONE;
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_integer1_integer2
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_integer1_integer3
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_integer1_integer4
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER1/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_integer1_real1
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_integer1_real2
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_integer1_real3
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_integer1_real4
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER1/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_integer1_complex1
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_integer1_complex2
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_integer1_complex3
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_integer1_complex4
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER1/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_convert_integer1_logical1
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_convert_integer1_logical2
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_convert_integer1_logical3
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_convert_integer1_logical4
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER1/LOGICAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_integer1_character1
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_integer1_hollerith
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_integer1_typeless
+ (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("INTEGER1 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_integer2_integer1
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_integer2_integer3
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_integer2_integer4
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER2/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_integer2_real1
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_integer2_real2
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_integer2_real3
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_integer2_real4
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER2/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_integer2_complex1
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_integer2_complex2
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_integer2_complex3
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_integer2_complex4
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER2/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_convert_integer2_logical1
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_convert_integer2_logical2
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_convert_integer2_logical3
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_convert_integer2_logical4
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER2/LOGICAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_integer2_character1
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_integer2_hollerith
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_integer2_typeless
+ (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("INTEGER2 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_integer3_integer1
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_integer3_integer2
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_integer3_integer4
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER3/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_integer3_real1
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_integer3_real2
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_integer3_real3
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_integer3_real4
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER3/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_integer3_complex1
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_integer3_complex2
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_integer3_complex3
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_integer3_complex4
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER3/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_convert_integer3_logical1
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_convert_integer3_logical2
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_convert_integer3_logical3
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_convert_integer3_logical4
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER3/LOGICAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_integer3_character1
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_integer3_hollerith
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_integer3_typeless
+ (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("INTEGER3 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_integer4_integer1
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_integer4_integer2
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_integer4_integer3
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER4/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_integer4_real1
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_integer4_real2
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_integer4_real3
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_integer4_real4
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER4/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_integer4_complex1
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_integer4_complex2
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_integer4_complex3
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_integer4_complex4
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER3/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_convert_integer4_logical1
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_convert_integer4_logical2
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_convert_integer4_logical3
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_convert_integer4_logical4
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("INTEGER4/LOGICAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_integer4_character1
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_integer4_hollerith
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_integer4_typeless
+ (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("INTEGER4 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ sz = FFETARGET_charactersizeNONE;
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_convert_logical1_logical2
+ (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_convert_logical1_logical3
+ (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_convert_logical1_logical4
+ (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("LOGICAL1/LOGICAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_logical1_integer1
+ (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_logical1_integer2
+ (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_logical1_integer3
+ (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_logical1_integer4
+ (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("LOGICAL1/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_logical1_character1
+ (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_logical1_hollerith
+ (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_logical1_typeless
+ (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("LOGICAL1 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logical1_val
+ (ffebld_cu_val_logical1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_convert_logical2_logical1
+ (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_convert_logical2_logical3
+ (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_convert_logical2_logical4
+ (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("LOGICAL2/LOGICAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_logical2_integer1
+ (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_logical2_integer2
+ (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_logical2_integer3
+ (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_logical2_integer4
+ (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("LOGICAL2/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_logical2_character1
+ (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_logical2_hollerith
+ (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_logical2_typeless
+ (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("LOGICAL2 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logical2_val
+ (ffebld_cu_val_logical2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_convert_logical3_logical1
+ (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_convert_logical3_logical2
+ (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_convert_logical3_logical4
+ (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("LOGICAL3/LOGICAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_logical3_integer1
+ (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_logical3_integer2
+ (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_logical3_integer3
+ (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_logical3_integer4
+ (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("LOGICAL3/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_logical3_character1
+ (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_logical3_hollerith
+ (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_logical3_typeless
+ (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("LOGICAL3 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logical3_val
+ (ffebld_cu_val_logical3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_convert_logical4_logical1
+ (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_convert_logical4_logical2
+ (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_convert_logical4_logical3
+ (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("LOGICAL4/LOGICAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_logical4_integer1
+ (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_logical4_integer2
+ (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_logical4_integer3
+ (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_logical4_integer4
+ (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("LOGICAL4/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_logical4_character1
+ (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_logical4_hollerith
+ (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_logical4_typeless
+ (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("LOGICAL4 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logical4_val
+ (ffebld_cu_val_logical4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad logical kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ sz = FFETARGET_charactersizeNONE;
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_real1_integer1
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_real1_integer2
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_real1_integer3
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_real1_integer4
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL1/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_real1_real2
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_real1_real3
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_real1_real4
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL1/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_real1_complex1
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_real1_complex2
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_real1_complex3
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_real1_complex4
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL1/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_real1_character1
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_real1_hollerith
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_real1_typeless
+ (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("REAL1 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_real1_val
+ (ffebld_cu_val_real1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_real2_integer1
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_real2_integer2
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_real2_integer3
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_real2_integer4
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL2/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_real2_real1
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_real2_real3
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_real2_real4
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL2/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_real2_complex1
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_real2_complex2
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_real2_complex3
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_real2_complex4
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL2/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_real2_character1
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_real2_hollerith
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_real2_typeless
+ (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("REAL2 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_real2_val
+ (ffebld_cu_val_real2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_real3_integer1
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_real3_integer2
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_real3_integer3
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_real3_integer4
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL3/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_real3_real1
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_real3_real2
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_real3_real4
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL3/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_real3_complex1
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_real3_complex2
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_real3_complex3
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_real3_complex4
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL3/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_real3_character1
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_real3_hollerith
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_real3_typeless
+ (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("REAL3 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_real3_val
+ (ffebld_cu_val_real3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_real4_integer1
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_real4_integer2
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_real4_integer3
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_real4_integer4
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL4/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_real4_real1
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_real4_real2
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_real4_real3
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL4/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_real4_complex1
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_real4_complex2
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_real4_complex3
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_real4_complex4
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("REAL4/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_real4_character1
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_real4_hollerith
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_real4_typeless
+ (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("REAL4 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_real4_val
+ (ffebld_cu_val_real4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ sz = FFETARGET_charactersizeNONE;
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_complex1_integer1
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_complex1_integer2
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_complex1_integer3
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_complex1_integer4
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX1/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_complex1_real1
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_complex1_real2
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_complex1_real3
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_complex1_real4
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX1/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_complex1_complex2
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_complex1_complex3
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_complex1_complex4
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX1/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_complex1_character1
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_complex1_hollerith
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_complex1_typeless
+ (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("COMPLEX1 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_complex1_val
+ (ffebld_cu_val_complex1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_complex2_integer1
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_complex2_integer2
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_complex2_integer3
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_complex2_integer4
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX2/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_complex2_real1
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_complex2_real2
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_complex2_real3
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_complex2_real4
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX2/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_complex2_complex1
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_complex2_complex3
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_complex2_complex4
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX2/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_complex2_character1
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_complex2_hollerith
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_complex2_typeless
+ (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("COMPLEX2 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_complex2_val
+ (ffebld_cu_val_complex2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_complex3_integer1
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_complex3_integer2
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_complex3_integer3
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_complex3_integer4
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX3/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_complex3_real1
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_complex3_real2
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_complex3_real3
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_complex3_real4
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX3/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_complex3_complex1
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_complex3_complex2
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_complex3_complex4
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX3/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_complex3_character1
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_complex3_hollerith
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_complex3_typeless
+ (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("COMPLEX3 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_complex3_val
+ (ffebld_cu_val_complex3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_convert_complex4_integer1
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_convert_complex4_integer2
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_convert_complex4_integer3
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_convert_complex4_integer4
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX4/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_complex4_real1
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_real1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_complex4_real2
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_real2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_complex4_real3
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_real3 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_convert_complex4_real4
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_real4 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX4/REAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_convert_complex4_complex1
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_convert_complex4_complex2
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_convert_complex4_complex3
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)));
+ break;
+#endif
+
+ default:
+ assert ("COMPLEX4/COMPLEX bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = ffetarget_convert_complex4_character1
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_character1 (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error = ffetarget_convert_complex4_hollerith
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_hollerith (ffebld_conter (l)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error = ffetarget_convert_complex4_typeless
+ (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_typeless (ffebld_conter (l)));
+ break;
+
+ default:
+ assert ("COMPLEX4 bad type" == NULL);
+ break;
+ }
+
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_complex4_val
+ (ffebld_cu_val_complex4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad complex kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ if ((sz = ffebld_size (expr)) == FFETARGET_charactersizeNONE)
+ return expr;
+ kt = ffeinfo_kindtype (ffebld_info (expr));
+ switch (kt)
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ switch (ffeinfo_basictype (ffebld_info (l)))
+ {
+ case FFEINFO_basictypeCHARACTER:
+ if ((sz2 = ffebld_size (l)) == FFETARGET_charactersizeNONE)
+ return expr;
+ assert (kt == ffeinfo_kindtype (ffebld_info (l)));
+ assert (sz2 == ffetarget_length_character1
+ (ffebld_constant_character1
+ (ffebld_conter (l))));
+ error
+ = ffetarget_convert_character1_character1
+ (ffebld_cu_ptr_character1 (u), sz,
+ ffebld_constant_character1 (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error
+ = ffetarget_convert_character1_integer1
+ (ffebld_cu_ptr_character1 (u),
+ sz,
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error
+ = ffetarget_convert_character1_integer2
+ (ffebld_cu_ptr_character1 (u),
+ sz,
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error
+ = ffetarget_convert_character1_integer3
+ (ffebld_cu_ptr_character1 (u),
+ sz,
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error
+ = ffetarget_convert_character1_integer4
+ (ffebld_cu_ptr_character1 (u),
+ sz,
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+#endif
+
+ default:
+ assert ("CHARACTER1/INTEGER bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (ffeinfo_kindtype (ffebld_info (l)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error
+ = ffetarget_convert_character1_logical1
+ (ffebld_cu_ptr_character1 (u),
+ sz,
+ ffebld_constant_logical1 (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error
+ = ffetarget_convert_character1_logical2
+ (ffebld_cu_ptr_character1 (u),
+ sz,
+ ffebld_constant_logical2 (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error
+ = ffetarget_convert_character1_logical3
+ (ffebld_cu_ptr_character1 (u),
+ sz,
+ ffebld_constant_logical3 (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error
+ = ffetarget_convert_character1_logical4
+ (ffebld_cu_ptr_character1 (u),
+ sz,
+ ffebld_constant_logical4 (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+#endif
+
+ default:
+ assert ("CHARACTER1/LOGICAL bad source kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ error
+ = ffetarget_convert_character1_hollerith
+ (ffebld_cu_ptr_character1 (u),
+ sz,
+ ffebld_constant_hollerith (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ error
+ = ffetarget_convert_character1_typeless
+ (ffebld_cu_ptr_character1 (u),
+ sz,
+ ffebld_constant_typeless (ffebld_conter (l)),
+ ffebld_constant_pool ());
+ break;
+
+ default:
+ assert ("CHARACTER1 bad type" == NULL);
+ }
+
+ expr
+ = ffebld_new_conter_with_orig
+ (ffebld_constant_new_character1_val
+ (ffebld_cu_val_character1 (u)),
+ expr);
+ break;
+#endif
+
+ default:
+ assert ("bad character kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ sz));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ assert (t != NULL);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_paren -- Collapse paren expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_paren(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_paren (ffebld expr, ffelexToken t UNUSED)
+{
+ ffebld r;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffetargetCharacterSize len;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ r = ffebld_left (expr);
+
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ bt = ffeinfo_basictype (ffebld_info (r));
+ kt = ffeinfo_kindtype (ffebld_info (r));
+ len = ffebld_size (r);
+
+ expr = ffebld_new_conter_with_orig (ffebld_constant_copy (ffebld_conter (r)),
+ expr);
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ len));
+
+ return expr;
+}
+
+/* ffeexpr_collapse_uplus -- Collapse uplus expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_uplus(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_uplus (ffebld expr, ffelexToken t UNUSED)
+{
+ ffebld r;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffetargetCharacterSize len;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ r = ffebld_left (expr);
+
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ bt = ffeinfo_basictype (ffebld_info (r));
+ kt = ffeinfo_kindtype (ffebld_info (r));
+ len = ffebld_size (r);
+
+ expr = ffebld_new_conter_with_orig (ffebld_constant_copy (ffebld_conter (r)),
+ expr);
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ len));
+
+ return expr;
+}
+
+/* ffeexpr_collapse_uminus -- Collapse uminus expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_uminus(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_uminus (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ r = ffebld_left (expr);
+
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_uminus_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_uminus_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_uminus_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_uminus_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_uminus_real1 (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real1_val
+ (ffebld_cu_val_real1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_uminus_real2 (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real2_val
+ (ffebld_cu_val_real2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_uminus_real3 (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real3_val
+ (ffebld_cu_val_real3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_uminus_real4 (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real4_val
+ (ffebld_cu_val_real4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_uminus_complex1 (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_complex1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex1_val
+ (ffebld_cu_val_complex1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_uminus_complex2 (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_complex2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex2_val
+ (ffebld_cu_val_complex2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_uminus_complex3 (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_complex3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex3_val
+ (ffebld_cu_val_complex3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_uminus_complex4 (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_complex4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex4_val
+ (ffebld_cu_val_complex4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad complex kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_not -- Collapse not expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_not(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_not (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ r = ffebld_left (expr);
+
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_not_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_not_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_not_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_not_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_not_logical1 (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_logical1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical1_val
+ (ffebld_cu_val_logical1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_not_logical2 (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_logical2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical2_val
+ (ffebld_cu_val_logical2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_not_logical3 (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_logical3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical3_val
+ (ffebld_cu_val_logical3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_not_logical4 (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_logical4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical4_val
+ (ffebld_cu_val_logical4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad logical kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_add -- Collapse add expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_add(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_add (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_add_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_add_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_add_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_add_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_add_real1 (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_real1 (ffebld_conter (l)),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real1_val
+ (ffebld_cu_val_real1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_add_real2 (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_real2 (ffebld_conter (l)),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real2_val
+ (ffebld_cu_val_real2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_add_real3 (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_real3 (ffebld_conter (l)),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real3_val
+ (ffebld_cu_val_real3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_add_real4 (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_real4 (ffebld_conter (l)),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real4_val
+ (ffebld_cu_val_real4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_add_complex1 (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)),
+ ffebld_constant_complex1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex1_val
+ (ffebld_cu_val_complex1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_add_complex2 (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)),
+ ffebld_constant_complex2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex2_val
+ (ffebld_cu_val_complex2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_add_complex3 (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)),
+ ffebld_constant_complex3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex3_val
+ (ffebld_cu_val_complex3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_add_complex4 (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)),
+ ffebld_constant_complex4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex4_val
+ (ffebld_cu_val_complex4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad complex kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_subtract -- Collapse subtract expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_subtract(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_subtract (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_subtract_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_subtract_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_subtract_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_subtract_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_subtract_real1 (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_real1 (ffebld_conter (l)),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real1_val
+ (ffebld_cu_val_real1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_subtract_real2 (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_real2 (ffebld_conter (l)),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real2_val
+ (ffebld_cu_val_real2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_subtract_real3 (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_real3 (ffebld_conter (l)),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real3_val
+ (ffebld_cu_val_real3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_subtract_real4 (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_real4 (ffebld_conter (l)),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real4_val
+ (ffebld_cu_val_real4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_subtract_complex1 (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)),
+ ffebld_constant_complex1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex1_val
+ (ffebld_cu_val_complex1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_subtract_complex2 (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)),
+ ffebld_constant_complex2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex2_val
+ (ffebld_cu_val_complex2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_subtract_complex3 (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)),
+ ffebld_constant_complex3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex3_val
+ (ffebld_cu_val_complex3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_subtract_complex4 (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)),
+ ffebld_constant_complex4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex4_val
+ (ffebld_cu_val_complex4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad complex kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_multiply -- Collapse multiply expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_multiply(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_multiply (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_multiply_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_multiply_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_multiply_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_multiply_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_multiply_real1 (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_real1 (ffebld_conter (l)),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real1_val
+ (ffebld_cu_val_real1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_multiply_real2 (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_real2 (ffebld_conter (l)),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real2_val
+ (ffebld_cu_val_real2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_multiply_real3 (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_real3 (ffebld_conter (l)),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real3_val
+ (ffebld_cu_val_real3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_multiply_real4 (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_real4 (ffebld_conter (l)),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real4_val
+ (ffebld_cu_val_real4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_multiply_complex1 (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)),
+ ffebld_constant_complex1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex1_val
+ (ffebld_cu_val_complex1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_multiply_complex2 (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)),
+ ffebld_constant_complex2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex2_val
+ (ffebld_cu_val_complex2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_multiply_complex3 (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)),
+ ffebld_constant_complex3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex3_val
+ (ffebld_cu_val_complex3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_multiply_complex4 (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)),
+ ffebld_constant_complex4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex4_val
+ (ffebld_cu_val_complex4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad complex kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_divide -- Collapse divide expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_divide(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_divide (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_divide_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_divide_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_divide_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_divide_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_divide_real1 (ffebld_cu_ptr_real1 (u),
+ ffebld_constant_real1 (ffebld_conter (l)),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real1_val
+ (ffebld_cu_val_real1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_divide_real2 (ffebld_cu_ptr_real2 (u),
+ ffebld_constant_real2 (ffebld_conter (l)),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real2_val
+ (ffebld_cu_val_real2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_divide_real3 (ffebld_cu_ptr_real3 (u),
+ ffebld_constant_real3 (ffebld_conter (l)),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real3_val
+ (ffebld_cu_val_real3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_divide_real4 (ffebld_cu_ptr_real4 (u),
+ ffebld_constant_real4 (ffebld_conter (l)),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_real4_val
+ (ffebld_cu_val_real4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_divide_complex1 (ffebld_cu_ptr_complex1 (u),
+ ffebld_constant_complex1 (ffebld_conter (l)),
+ ffebld_constant_complex1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex1_val
+ (ffebld_cu_val_complex1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_divide_complex2 (ffebld_cu_ptr_complex2 (u),
+ ffebld_constant_complex2 (ffebld_conter (l)),
+ ffebld_constant_complex2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex2_val
+ (ffebld_cu_val_complex2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_divide_complex3 (ffebld_cu_ptr_complex3 (u),
+ ffebld_constant_complex3 (ffebld_conter (l)),
+ ffebld_constant_complex3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex3_val
+ (ffebld_cu_val_complex3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_divide_complex4 (ffebld_cu_ptr_complex4 (u),
+ ffebld_constant_complex4 (ffebld_conter (l)),
+ ffebld_constant_complex4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_complex4_val
+ (ffebld_cu_val_complex4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad complex kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_power -- Collapse power expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_power(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_power (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ if ((ffeinfo_basictype (ffebld_info (r)) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kindtype (ffebld_info (r)) != FFEINFO_kindtypeINTEGERDEFAULT))
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+ case FFEINFO_kindtypeINTEGERDEFAULT:
+ error = ffetarget_power_integerdefault_integerdefault
+ (ffebld_cu_ptr_integerdefault (u),
+ ffebld_constant_integerdefault (ffebld_conter (l)),
+ ffebld_constant_integerdefault (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_integerdefault_val
+ (ffebld_cu_val_integerdefault (u)), expr);
+ break;
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+ case FFEINFO_kindtypeREALDEFAULT:
+ error = ffetarget_power_realdefault_integerdefault
+ (ffebld_cu_ptr_realdefault (u),
+ ffebld_constant_realdefault (ffebld_conter (l)),
+ ffebld_constant_integerdefault (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_realdefault_val
+ (ffebld_cu_val_realdefault (u)), expr);
+ break;
+
+ case FFEINFO_kindtypeREALDOUBLE:
+ error = ffetarget_power_realdouble_integerdefault
+ (ffebld_cu_ptr_realdouble (u),
+ ffebld_constant_realdouble (ffebld_conter (l)),
+ ffebld_constant_integerdefault (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_realdouble_val
+ (ffebld_cu_val_realdouble (u)), expr);
+ break;
+
+#if FFETARGET_okREALQUAD
+ case FFEINFO_kindtypeREALQUAD:
+ error = ffetarget_power_realquad_integerdefault
+ (ffebld_cu_ptr_realquad (u),
+ ffebld_constant_realquad (ffebld_conter (l)),
+ ffebld_constant_integerdefault (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_realquad_val
+ (ffebld_cu_val_realquad (u)), expr);
+ break;
+#endif
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+ case FFEINFO_kindtypeREALDEFAULT:
+ error = ffetarget_power_complexdefault_integerdefault
+ (ffebld_cu_ptr_complexdefault (u),
+ ffebld_constant_complexdefault (ffebld_conter (l)),
+ ffebld_constant_integerdefault (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_complexdefault_val
+ (ffebld_cu_val_complexdefault (u)), expr);
+ break;
+
+#if FFETARGET_okCOMPLEXDOUBLE
+ case FFEINFO_kindtypeREALDOUBLE:
+ error = ffetarget_power_complexdouble_integerdefault
+ (ffebld_cu_ptr_complexdouble (u),
+ ffebld_constant_complexdouble (ffebld_conter (l)),
+ ffebld_constant_integerdefault (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_complexdouble_val
+ (ffebld_cu_val_complexdouble (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEXQUAD
+ case FFEINFO_kindtypeREALQUAD:
+ error = ffetarget_power_complexquad_integerdefault
+ (ffebld_cu_ptr_complexquad (u),
+ ffebld_constant_complexquad (ffebld_conter (l)),
+ ffebld_constant_integerdefault (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_complexquad_val
+ (ffebld_cu_val_complexquad (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad complex kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_concatenate -- Collapse concatenate expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_concatenate(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_concatenate (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoKindtype kt;
+ ffetargetCharacterSize len;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ error = ffetarget_concatenate_character1 (ffebld_cu_ptr_character1 (u),
+ ffebld_constant_character1 (ffebld_conter (l)),
+ ffebld_constant_character1 (ffebld_conter (r)),
+ ffebld_constant_pool (), &len);
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_character1_val
+ (ffebld_cu_val_character1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ error = ffetarget_concatenate_character2 (ffebld_cu_ptr_character2 (u),
+ ffebld_constant_character2 (ffebld_conter (l)),
+ ffebld_constant_character2 (ffebld_conter (r)),
+ ffebld_constant_pool (), &len);
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_character2_val
+ (ffebld_cu_val_character2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ error = ffetarget_concatenate_character3 (ffebld_cu_ptr_character3 (u),
+ ffebld_constant_character3 (ffebld_conter (l)),
+ ffebld_constant_character3 (ffebld_conter (r)),
+ ffebld_constant_pool (), &len);
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_character3_val
+ (ffebld_cu_val_character3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ error = ffetarget_concatenate_character4 (ffebld_cu_ptr_character4 (u),
+ ffebld_constant_character4 (ffebld_conter (l)),
+ ffebld_constant_character4 (ffebld_conter (r)),
+ ffebld_constant_pool (), &len);
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_character4_val
+ (ffebld_cu_val_character4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad character kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (FFEINFO_basictypeCHARACTER,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ len));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_eq -- Collapse eq expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_eq(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_eq (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ bool val;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr))))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_eq_integer1 (&val,
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_eq_integer2 (&val,
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_eq_integer3 (&val,
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_eq_integer4 (&val,
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_eq_real1 (&val,
+ ffebld_constant_real1 (ffebld_conter (l)),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_eq_real2 (&val,
+ ffebld_constant_real2 (ffebld_conter (l)),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_eq_real3 (&val,
+ ffebld_constant_real3 (ffebld_conter (l)),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_eq_real4 (&val,
+ ffebld_constant_real4 (ffebld_conter (l)),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_eq_complex1 (&val,
+ ffebld_constant_complex1 (ffebld_conter (l)),
+ ffebld_constant_complex1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_eq_complex2 (&val,
+ ffebld_constant_complex2 (ffebld_conter (l)),
+ ffebld_constant_complex2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_eq_complex3 (&val,
+ ffebld_constant_complex3 (ffebld_conter (l)),
+ ffebld_constant_complex3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_eq_complex4 (&val,
+ ffebld_constant_complex4 (ffebld_conter (l)),
+ ffebld_constant_complex4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad complex kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ error = ffetarget_eq_character1 (&val,
+ ffebld_constant_character1 (ffebld_conter (l)),
+ ffebld_constant_character1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ error = ffetarget_eq_character2 (&val,
+ ffebld_constant_character2 (ffebld_conter (l)),
+ ffebld_constant_character2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ error = ffetarget_eq_character3 (&val,
+ ffebld_constant_character3 (ffebld_conter (l)),
+ ffebld_constant_character3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ error = ffetarget_eq_character4 (&val,
+ ffebld_constant_character4 (ffebld_conter (l)),
+ ffebld_constant_character4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad character kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_ne -- Collapse ne expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_ne(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_ne (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ bool val;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr))))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_ne_integer1 (&val,
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_ne_integer2 (&val,
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_ne_integer3 (&val,
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_ne_integer4 (&val,
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_ne_real1 (&val,
+ ffebld_constant_real1 (ffebld_conter (l)),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_ne_real2 (&val,
+ ffebld_constant_real2 (ffebld_conter (l)),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_ne_real3 (&val,
+ ffebld_constant_real3 (ffebld_conter (l)),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_ne_real4 (&val,
+ ffebld_constant_real4 (ffebld_conter (l)),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCOMPLEX:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_ne_complex1 (&val,
+ ffebld_constant_complex1 (ffebld_conter (l)),
+ ffebld_constant_complex1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_ne_complex2 (&val,
+ ffebld_constant_complex2 (ffebld_conter (l)),
+ ffebld_constant_complex2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_ne_complex3 (&val,
+ ffebld_constant_complex3 (ffebld_conter (l)),
+ ffebld_constant_complex3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_ne_complex4 (&val,
+ ffebld_constant_complex4 (ffebld_conter (l)),
+ ffebld_constant_complex4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad complex kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ error = ffetarget_ne_character1 (&val,
+ ffebld_constant_character1 (ffebld_conter (l)),
+ ffebld_constant_character1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ error = ffetarget_ne_character2 (&val,
+ ffebld_constant_character2 (ffebld_conter (l)),
+ ffebld_constant_character2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ error = ffetarget_ne_character3 (&val,
+ ffebld_constant_character3 (ffebld_conter (l)),
+ ffebld_constant_character3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ error = ffetarget_ne_character4 (&val,
+ ffebld_constant_character4 (ffebld_conter (l)),
+ ffebld_constant_character4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad character kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_ge -- Collapse ge expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_ge(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_ge (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ bool val;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr))))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_ge_integer1 (&val,
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_ge_integer2 (&val,
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_ge_integer3 (&val,
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_ge_integer4 (&val,
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_ge_real1 (&val,
+ ffebld_constant_real1 (ffebld_conter (l)),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_ge_real2 (&val,
+ ffebld_constant_real2 (ffebld_conter (l)),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_ge_real3 (&val,
+ ffebld_constant_real3 (ffebld_conter (l)),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_ge_real4 (&val,
+ ffebld_constant_real4 (ffebld_conter (l)),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ error = ffetarget_ge_character1 (&val,
+ ffebld_constant_character1 (ffebld_conter (l)),
+ ffebld_constant_character1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ error = ffetarget_ge_character2 (&val,
+ ffebld_constant_character2 (ffebld_conter (l)),
+ ffebld_constant_character2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ error = ffetarget_ge_character3 (&val,
+ ffebld_constant_character3 (ffebld_conter (l)),
+ ffebld_constant_character3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ error = ffetarget_ge_character4 (&val,
+ ffebld_constant_character4 (ffebld_conter (l)),
+ ffebld_constant_character4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad character kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_gt -- Collapse gt expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_gt(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_gt (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ bool val;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr))))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_gt_integer1 (&val,
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_gt_integer2 (&val,
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_gt_integer3 (&val,
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_gt_integer4 (&val,
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_gt_real1 (&val,
+ ffebld_constant_real1 (ffebld_conter (l)),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_gt_real2 (&val,
+ ffebld_constant_real2 (ffebld_conter (l)),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_gt_real3 (&val,
+ ffebld_constant_real3 (ffebld_conter (l)),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_gt_real4 (&val,
+ ffebld_constant_real4 (ffebld_conter (l)),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ error = ffetarget_gt_character1 (&val,
+ ffebld_constant_character1 (ffebld_conter (l)),
+ ffebld_constant_character1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ error = ffetarget_gt_character2 (&val,
+ ffebld_constant_character2 (ffebld_conter (l)),
+ ffebld_constant_character2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ error = ffetarget_gt_character3 (&val,
+ ffebld_constant_character3 (ffebld_conter (l)),
+ ffebld_constant_character3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ error = ffetarget_gt_character4 (&val,
+ ffebld_constant_character4 (ffebld_conter (l)),
+ ffebld_constant_character4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad character kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_le -- Collapse le expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_le(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_le (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ bool val;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr))))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_le_integer1 (&val,
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_le_integer2 (&val,
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_le_integer3 (&val,
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_le_integer4 (&val,
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_le_real1 (&val,
+ ffebld_constant_real1 (ffebld_conter (l)),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_le_real2 (&val,
+ ffebld_constant_real2 (ffebld_conter (l)),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_le_real3 (&val,
+ ffebld_constant_real3 (ffebld_conter (l)),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_le_real4 (&val,
+ ffebld_constant_real4 (ffebld_conter (l)),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ error = ffetarget_le_character1 (&val,
+ ffebld_constant_character1 (ffebld_conter (l)),
+ ffebld_constant_character1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ error = ffetarget_le_character2 (&val,
+ ffebld_constant_character2 (ffebld_conter (l)),
+ ffebld_constant_character2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ error = ffetarget_le_character3 (&val,
+ ffebld_constant_character3 (ffebld_conter (l)),
+ ffebld_constant_character3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ error = ffetarget_le_character4 (&val,
+ ffebld_constant_character4 (ffebld_conter (l)),
+ ffebld_constant_character4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad character kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_lt -- Collapse lt expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_lt(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_lt (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ bool val;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (ffeinfo_basictype (ffebld_info (ffebld_left (expr))))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_lt_integer1 (&val,
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_lt_integer2 (&val,
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_lt_integer3 (&val,
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_lt_integer4 (&val,
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okREAL1
+ case FFEINFO_kindtypeREAL1:
+ error = ffetarget_lt_real1 (&val,
+ ffebld_constant_real1 (ffebld_conter (l)),
+ ffebld_constant_real1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL2
+ case FFEINFO_kindtypeREAL2:
+ error = ffetarget_lt_real2 (&val,
+ ffebld_constant_real2 (ffebld_conter (l)),
+ ffebld_constant_real2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL3
+ case FFEINFO_kindtypeREAL3:
+ error = ffetarget_lt_real3 (&val,
+ ffebld_constant_real3 (ffebld_conter (l)),
+ ffebld_constant_real3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okREAL4
+ case FFEINFO_kindtypeREAL4:
+ error = ffetarget_lt_real4 (&val,
+ ffebld_constant_real4 (ffebld_conter (l)),
+ ffebld_constant_real4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad real kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (ffeinfo_kindtype (ffebld_info (ffebld_left (expr))))
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ error = ffetarget_lt_character1 (&val,
+ ffebld_constant_character1 (ffebld_conter (l)),
+ ffebld_constant_character1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ error = ffetarget_lt_character2 (&val,
+ ffebld_constant_character2 (ffebld_conter (l)),
+ ffebld_constant_character2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ error = ffetarget_lt_character3 (&val,
+ ffebld_constant_character3 (ffebld_conter (l)),
+ ffebld_constant_character3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ error = ffetarget_lt_character4 (&val,
+ ffebld_constant_character4 (ffebld_conter (l)),
+ ffebld_constant_character4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig
+ (ffebld_constant_new_logicaldefault (val), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad character kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_and -- Collapse and expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_and(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_and (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_and_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_and_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_and_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_and_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_and_logical1 (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)),
+ ffebld_constant_logical1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical1_val
+ (ffebld_cu_val_logical1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_and_logical2 (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)),
+ ffebld_constant_logical2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical2_val
+ (ffebld_cu_val_logical2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_and_logical3 (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)),
+ ffebld_constant_logical3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical3_val
+ (ffebld_cu_val_logical3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_and_logical4 (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)),
+ ffebld_constant_logical4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical4_val
+ (ffebld_cu_val_logical4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad logical kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_or -- Collapse or expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_or(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_or (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_or_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_or_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_or_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_or_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_or_logical1 (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)),
+ ffebld_constant_logical1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical1_val
+ (ffebld_cu_val_logical1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_or_logical2 (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)),
+ ffebld_constant_logical2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical2_val
+ (ffebld_cu_val_logical2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_or_logical3 (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)),
+ ffebld_constant_logical3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical3_val
+ (ffebld_cu_val_logical3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_or_logical4 (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)),
+ ffebld_constant_logical4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical4_val
+ (ffebld_cu_val_logical4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad logical kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_xor -- Collapse xor expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_xor(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_xor (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_xor_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_xor_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_xor_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_xor_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_xor_logical1 (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)),
+ ffebld_constant_logical1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical1_val
+ (ffebld_cu_val_logical1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_xor_logical2 (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)),
+ ffebld_constant_logical2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical2_val
+ (ffebld_cu_val_logical2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_xor_logical3 (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)),
+ ffebld_constant_logical3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical3_val
+ (ffebld_cu_val_logical3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_xor_logical4 (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)),
+ ffebld_constant_logical4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical4_val
+ (ffebld_cu_val_logical4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad logical kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_eqv -- Collapse eqv expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_eqv(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_eqv (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_eqv_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_eqv_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_eqv_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_eqv_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_eqv_logical1 (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)),
+ ffebld_constant_logical1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical1_val
+ (ffebld_cu_val_logical1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_eqv_logical2 (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)),
+ ffebld_constant_logical2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical2_val
+ (ffebld_cu_val_logical2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_eqv_logical3 (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)),
+ ffebld_constant_logical3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical3_val
+ (ffebld_cu_val_logical3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_eqv_logical4 (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)),
+ ffebld_constant_logical4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical4_val
+ (ffebld_cu_val_logical4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad logical kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_neqv -- Collapse neqv expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_neqv(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_neqv (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebldConstantUnion u;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr);
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+ if (ffebld_op (r) != FFEBLD_opCONTER)
+ return expr;
+
+ switch (bt = ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ error = ffetarget_neqv_integer1 (ffebld_cu_ptr_integer1 (u),
+ ffebld_constant_integer1 (ffebld_conter (l)),
+ ffebld_constant_integer1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer1_val
+ (ffebld_cu_val_integer1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ error = ffetarget_neqv_integer2 (ffebld_cu_ptr_integer2 (u),
+ ffebld_constant_integer2 (ffebld_conter (l)),
+ ffebld_constant_integer2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer2_val
+ (ffebld_cu_val_integer2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ error = ffetarget_neqv_integer3 (ffebld_cu_ptr_integer3 (u),
+ ffebld_constant_integer3 (ffebld_conter (l)),
+ ffebld_constant_integer3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer3_val
+ (ffebld_cu_val_integer3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okINTEGER4
+ case FFEINFO_kindtypeINTEGER4:
+ error = ffetarget_neqv_integer4 (ffebld_cu_ptr_integer4 (u),
+ ffebld_constant_integer4 (ffebld_conter (l)),
+ ffebld_constant_integer4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_integer4_val
+ (ffebld_cu_val_integer4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad integer kind type" == NULL);
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okLOGICAL1
+ case FFEINFO_kindtypeLOGICAL1:
+ error = ffetarget_neqv_logical1 (ffebld_cu_ptr_logical1 (u),
+ ffebld_constant_logical1 (ffebld_conter (l)),
+ ffebld_constant_logical1 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical1_val
+ (ffebld_cu_val_logical1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL2
+ case FFEINFO_kindtypeLOGICAL2:
+ error = ffetarget_neqv_logical2 (ffebld_cu_ptr_logical2 (u),
+ ffebld_constant_logical2 (ffebld_conter (l)),
+ ffebld_constant_logical2 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical2_val
+ (ffebld_cu_val_logical2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL3
+ case FFEINFO_kindtypeLOGICAL3:
+ error = ffetarget_neqv_logical3 (ffebld_cu_ptr_logical3 (u),
+ ffebld_constant_logical3 (ffebld_conter (l)),
+ ffebld_constant_logical3 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical3_val
+ (ffebld_cu_val_logical3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okLOGICAL4
+ case FFEINFO_kindtypeLOGICAL4:
+ error = ffetarget_neqv_logical4 (ffebld_cu_ptr_logical4 (u),
+ ffebld_constant_logical4 (ffebld_conter (l)),
+ ffebld_constant_logical4 (ffebld_conter (r)));
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_logical4_val
+ (ffebld_cu_val_logical4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad logical kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_collapse_symter -- Collapse symter expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_symter(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_symter (ffebld expr, ffelexToken t UNUSED)
+{
+ ffebld r;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffetargetCharacterSize len;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ if ((r = ffesymbol_init (ffebld_symter (expr))) == NULL)
+ return expr; /* A PARAMETER lhs in progress. */
+
+ switch (ffebld_op (r))
+ {
+ case FFEBLD_opCONTER:
+ break;
+
+ case FFEBLD_opANY:
+ return r;
+
+ default:
+ return expr;
+ }
+
+ bt = ffeinfo_basictype (ffebld_info (r));
+ kt = ffeinfo_kindtype (ffebld_info (r));
+ len = ffebld_size (r);
+
+ expr = ffebld_new_conter_with_orig (ffebld_constant_copy (ffebld_conter (r)),
+ expr);
+
+ ffebld_set_info (expr, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ len));
+
+ return expr;
+}
+
+/* ffeexpr_collapse_funcref -- Collapse funcref expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_funcref(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_funcref (ffebld expr, ffelexToken t UNUSED)
+{
+ return expr; /* ~~someday go ahead and collapse these,
+ though not required */
+}
+
+/* ffeexpr_collapse_arrayref -- Collapse arrayref expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_arrayref(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_arrayref (ffebld expr, ffelexToken t UNUSED)
+{
+ return expr;
+}
+
+/* ffeexpr_collapse_substr -- Collapse substr expr
+
+ ffebld expr;
+ ffelexToken token;
+ expr = ffeexpr_collapse_substr(expr,token);
+
+ If the result of the expr is a constant, replaces the expr with the
+ computed constant. */
+
+ffebld
+ffeexpr_collapse_substr (ffebld expr, ffelexToken t)
+{
+ ffebad error = FFEBAD;
+ ffebld l;
+ ffebld r;
+ ffebld start;
+ ffebld stop;
+ ffebldConstantUnion u;
+ ffeinfoKindtype kt;
+ ffetargetCharacterSize len;
+ ffetargetIntegerDefault first;
+ ffetargetIntegerDefault last;
+
+ if (ffeinfo_where (ffebld_info (expr)) != FFEINFO_whereCONSTANT)
+ return expr;
+
+ l = ffebld_left (expr);
+ r = ffebld_right (expr); /* opITEM. */
+
+ if (ffebld_op (l) != FFEBLD_opCONTER)
+ return expr;
+
+ kt = ffeinfo_kindtype (ffebld_info (l));
+ len = ffebld_size (l);
+
+ start = ffebld_head (r);
+ stop = ffebld_head (ffebld_trail (r));
+ if (start == NULL)
+ first = 1;
+ else
+ {
+ if ((ffebld_op (start) != FFEBLD_opCONTER)
+ || (ffeinfo_basictype (ffebld_info (start)) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kindtype (ffebld_info (start))
+ != FFEINFO_kindtypeINTEGERDEFAULT))
+ return expr;
+ first = ffebld_constant_integerdefault (ffebld_conter (start));
+ }
+ if (stop == NULL)
+ last = len;
+ else
+ {
+ if ((ffebld_op (stop) != FFEBLD_opCONTER)
+ || (ffeinfo_basictype (ffebld_info (stop)) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kindtype (ffebld_info (stop))
+ != FFEINFO_kindtypeINTEGERDEFAULT))
+ return expr;
+ last = ffebld_constant_integerdefault (ffebld_conter (stop));
+ }
+
+ /* Handle problems that should have already been diagnosed, but
+ left in the expression tree. */
+
+ if (first <= 0)
+ first = 1;
+ if (last < first)
+ last = first + len - 1;
+
+ if ((first == 1) && (last == len))
+ { /* Same as original. */
+ expr = ffebld_new_conter_with_orig (ffebld_constant_copy
+ (ffebld_conter (l)), expr);
+ ffebld_set_info (expr, ffeinfo_new
+ (FFEINFO_basictypeCHARACTER,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ len));
+
+ return expr;
+ }
+
+ switch (ffeinfo_basictype (ffebld_info (expr)))
+ {
+ case FFEINFO_basictypeANY:
+ return expr;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (kt = ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okCHARACTER1
+ case FFEINFO_kindtypeCHARACTER1:
+ error = ffetarget_substr_character1 (ffebld_cu_ptr_character1 (u),
+ ffebld_constant_character1 (ffebld_conter (l)), first, last,
+ ffebld_constant_pool (), &len);
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_character1_val
+ (ffebld_cu_val_character1 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER2
+ case FFEINFO_kindtypeCHARACTER2:
+ error = ffetarget_substr_character2 (ffebld_cu_ptr_character2 (u),
+ ffebld_constant_character2 (ffebld_conter (l)), first, last,
+ ffebld_constant_pool (), &len);
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_character2_val
+ (ffebld_cu_val_character2 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER3
+ case FFEINFO_kindtypeCHARACTER3:
+ error = ffetarget_substr_character3 (ffebld_cu_ptr_character3 (u),
+ ffebld_constant_character3 (ffebld_conter (l)), first, last,
+ ffebld_constant_pool (), &len);
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_character3_val
+ (ffebld_cu_val_character3 (u)), expr);
+ break;
+#endif
+
+#if FFETARGET_okCHARACTER4
+ case FFEINFO_kindtypeCHARACTER4:
+ error = ffetarget_substr_character4 (ffebld_cu_ptr_character4 (u),
+ ffebld_constant_character4 (ffebld_conter (l)), first, last,
+ ffebld_constant_pool (), &len);
+ expr = ffebld_new_conter_with_orig (ffebld_constant_new_character4_val
+ (ffebld_cu_val_character4 (u)), expr);
+ break;
+#endif
+
+ default:
+ assert ("bad character kind type" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad type" == NULL);
+ return expr;
+ }
+
+ ffebld_set_info (expr, ffeinfo_new
+ (FFEINFO_basictypeCHARACTER,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ len));
+
+ if ((error != FFEBAD)
+ && ffebad_start (error))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ return expr;
+}
+
+/* ffeexpr_convert -- Convert source expression to given type
+
+ ffebld source;
+ ffelexToken source_token;
+ ffelexToken dest_token; // Any appropriate token for "destination".
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffetargetCharactersize sz;
+ ffeexprContext context; // Mainly LET or DATA.
+ source = ffeexpr_convert(source,source_token,dest_token,bt,kt,sz,context);
+
+ If the expression conforms, returns the source expression. Otherwise
+ returns source wrapped in a convert node doing the conversion, or
+ ANY wrapped in convert if there is a conversion error (and issues an
+ error message). Be sensitive to the context for certain aspects of
+ the conversion. */
+
+ffebld
+ffeexpr_convert (ffebld source, ffelexToken source_token, ffelexToken dest_token,
+ ffeinfoBasictype bt, ffeinfoKindtype kt, ffeinfoRank rk,
+ ffetargetCharacterSize sz, ffeexprContext context)
+{
+ bool bad;
+ ffeinfo info;
+ ffeinfoWhere wh;
+
+ info = ffebld_info (source);
+ if ((bt != ffeinfo_basictype (info))
+ || (kt != ffeinfo_kindtype (info))
+ || (rk != 0) /* Can't convert from or to arrays yet. */
+ || (ffeinfo_rank (info) != 0)
+ || (sz != ffebld_size_known (source)))
+#if 0 /* Nobody seems to need this spurious CONVERT node. */
+ || ((context != FFEEXPR_contextLET)
+ && (bt == FFEINFO_basictypeCHARACTER)
+ && (sz == FFETARGET_charactersizeNONE)))
+#endif
+ {
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ switch (bt)
+ {
+ case FFEINFO_basictypeLOGICAL:
+ bad = FALSE;
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ bad = !ffe_is_ugly_logint ();
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ bad = ffe_is_pedantic ()
+ || !(ffe_is_ugly_init ()
+ && (context == FFEEXPR_contextDATA));
+ break;
+
+ default:
+ bad = TRUE;
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ switch (bt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ bad = FALSE;
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ bad = !ffe_is_ugly_logint ();
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ bad = ffe_is_pedantic ()
+ || !(ffe_is_ugly_init ()
+ && (context == FFEEXPR_contextDATA));
+ break;
+
+ default:
+ bad = TRUE;
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ switch (bt)
+ {
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ bad = FALSE;
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ bad = TRUE;
+ break;
+
+ default:
+ bad = TRUE;
+ break;
+ }
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ bad = (bt != FFEINFO_basictypeCHARACTER)
+ && (ffe_is_pedantic ()
+ || (bt != FFEINFO_basictypeINTEGER)
+ || !(ffe_is_ugly_init ()
+ && (context == FFEEXPR_contextDATA)));
+ break;
+
+ case FFEINFO_basictypeTYPELESS:
+ case FFEINFO_basictypeHOLLERITH:
+ bad = ffe_is_pedantic ()
+ || !(ffe_is_ugly_init ()
+ && ((context == FFEEXPR_contextDATA)
+ || (context == FFEEXPR_contextLET)));
+ break;
+
+ default:
+ bad = TRUE;
+ break;
+ }
+
+ if (!bad && ((rk != 0) || (ffeinfo_rank (info) != 0)))
+ bad = TRUE;
+
+ if (bad && (bt != FFEINFO_basictypeANY) && (kt != FFEINFO_kindtypeANY)
+ && (ffeinfo_basictype (info) != FFEINFO_basictypeANY)
+ && (ffeinfo_kindtype (info) != FFEINFO_kindtypeANY)
+ && (ffeinfo_where (info) != FFEINFO_whereANY))
+ {
+ if (ffebad_start (FFEBAD_BAD_TYPES))
+ {
+ if (dest_token == NULL)
+ ffebad_here (0, ffewhere_line_unknown (),
+ ffewhere_column_unknown ());
+ else
+ ffebad_here (0, ffelex_token_where_line (dest_token),
+ ffelex_token_where_column (dest_token));
+ assert (source_token != NULL);
+ ffebad_here (1, ffelex_token_where_line (source_token),
+ ffelex_token_where_column (source_token));
+ ffebad_finish ();
+ }
+
+ source = ffebld_new_any ();
+ ffebld_set_info (source, ffeinfo_new_any ());
+ }
+ else
+ {
+ switch (ffeinfo_where (info))
+ {
+ case FFEINFO_whereCONSTANT:
+ wh = FFEINFO_whereCONSTANT;
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ wh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ wh = FFEINFO_whereFLEETING;
+ break;
+ }
+ source = ffebld_new_convert (source);
+ ffebld_set_info (source, ffeinfo_new
+ (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ wh,
+ sz));
+ source = ffeexpr_collapse_convert (source, source_token);
+ }
+ }
+
+ return source;
+}
+
+/* ffeexpr_convert_expr -- Convert source expr to conform to dest expr
+
+ ffebld source;
+ ffebld dest;
+ ffelexToken source_token;
+ ffelexToken dest_token;
+ ffeexprContext context;
+ source = ffeexpr_convert_expr(source,source_token,dest,dest_token,context);
+
+ If the expressions conform, returns the source expression. Otherwise
+ returns source wrapped in a convert node doing the conversion, or
+ ANY wrapped in convert if there is a conversion error (and issues an
+ error message). Be sensitive to the context, such as LET or DATA. */
+
+ffebld
+ffeexpr_convert_expr (ffebld source, ffelexToken source_token, ffebld dest,
+ ffelexToken dest_token, ffeexprContext context)
+{
+ ffeinfo info;
+
+ info = ffebld_info (dest);
+ return ffeexpr_convert (source, source_token, dest_token,
+ ffeinfo_basictype (info),
+ ffeinfo_kindtype (info),
+ ffeinfo_rank (info),
+ ffebld_size_known (dest),
+ context);
+}
+
+/* ffeexpr_convert_to_sym -- Convert source expression to conform to symbol
+
+ ffebld source;
+ ffesymbol dest;
+ ffelexToken source_token;
+ ffelexToken dest_token;
+ source = ffeexpr_convert_to_sym(source,source_token,dest,dest_token);
+
+ If the expressions conform, returns the source expression. Otherwise
+ returns source wrapped in a convert node doing the conversion, or
+ ANY wrapped in convert if there is a conversion error (and issues an
+ error message). */
+
+ffebld
+ffeexpr_convert_to_sym (ffebld source, ffelexToken source_token,
+ ffesymbol dest, ffelexToken dest_token)
+{
+ return ffeexpr_convert (source, source_token, dest_token, ffesymbol_basictype (dest),
+ ffesymbol_kindtype (dest), ffesymbol_rank (dest), ffesymbol_size (dest),
+ FFEEXPR_contextLET);
+}
+
+/* Initializes the module. */
+
+void
+ffeexpr_init_2 ()
+{
+ ffeexpr_stack_ = NULL;
+ ffeexpr_level_ = 0;
+}
+
+/* ffeexpr_lhs -- Begin processing left-hand-side-context expression
+
+ Prepares cluster for delivery of lexer tokens representing an expression
+ in a left-hand-side context (A in A=B, for example). ffebld is used
+ to build expressions in the given pool. The appropriate lexer-token
+ handling routine within ffeexpr is returned. When the end of the
+ expression is detected, mycallbackroutine is called with the resulting
+ single ffebld object specifying the entire expression and the first
+ lexer token that is not considered part of the expression. This caller-
+ supplied routine itself returns a lexer-token handling routine. Thus,
+ if necessary, ffeexpr can return several tokens as end-of-expression
+ tokens if it needs to scan forward more than one in any instance. */
+
+ffelexHandler
+ffeexpr_lhs (mallocPool pool, ffeexprContext context, ffeexprCallback callback)
+{
+ ffeexprStack_ s;
+
+ ffebld_pool_push (pool);
+ s = malloc_new_ks (ffe_pool_program_unit (), "FFEEXPR stack", sizeof (*s));
+ s->previous = ffeexpr_stack_;
+ s->pool = pool;
+ s->context = context;
+ s->callback = callback;
+ s->first_token = NULL;
+ s->exprstack = NULL;
+ s->is_rhs = FALSE;
+ ffeexpr_stack_ = s;
+ return (ffelexHandler) ffeexpr_token_first_lhs_;
+}
+
+/* ffeexpr_rhs -- Begin processing right-hand-side-context expression
+
+ return ffeexpr_rhs(malloc_pool_image(),mycallbackroutine); // to lexer.
+
+ Prepares cluster for delivery of lexer tokens representing an expression
+ in a right-hand-side context (B in A=B, for example). ffebld is used
+ to build expressions in the given pool. The appropriate lexer-token
+ handling routine within ffeexpr is returned. When the end of the
+ expression is detected, mycallbackroutine is called with the resulting
+ single ffebld object specifying the entire expression and the first
+ lexer token that is not considered part of the expression. This caller-
+ supplied routine itself returns a lexer-token handling routine. Thus,
+ if necessary, ffeexpr can return several tokens as end-of-expression
+ tokens if it needs to scan forward more than one in any instance. */
+
+ffelexHandler
+ffeexpr_rhs (mallocPool pool, ffeexprContext context, ffeexprCallback callback)
+{
+ ffeexprStack_ s;
+
+ ffebld_pool_push (pool);
+ s = malloc_new_ks (ffe_pool_program_unit (), "FFEEXPR stack", sizeof (*s));
+ s->previous = ffeexpr_stack_;
+ s->pool = pool;
+ s->context = context;
+ s->callback = callback;
+ s->first_token = NULL;
+ s->exprstack = NULL;
+ s->is_rhs = TRUE;
+ ffeexpr_stack_ = s;
+ return (ffelexHandler) ffeexpr_token_first_rhs_;
+}
+
+/* ffeexpr_cb_close_paren_ -- OPEN_PAREN expr
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ Makes sure the end token is close-paren and swallows it, else issues
+ an error message and doesn't swallow the token (passing it along instead).
+ In either case wraps up subexpression construction by enclosing the
+ ffebld expression in a paren. */
+
+static ffelexHandler
+ffeexpr_cb_close_paren_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffeexprExpr_ e;
+
+ if (ffelex_token_type (t) != FFELEX_typeCLOSE_PAREN)
+ {
+ /* Oops, naughty user didn't specify the close paren! */
+
+ if (ffest_ffebad_start (FFEBAD_MISSING_CLOSE_PAREN))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_finish ();
+ }
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->u.operand = ffebld_new_any ();
+ ffebld_set_info (e->u.operand, ffeinfo_new_any ());
+ ffeexpr_exprstack_push_operand_ (e);
+
+ return
+ (ffelexHandler) ffeexpr_find_close_paren_ (t,
+ (ffelexHandler)
+ ffeexpr_token_binary_);
+ }
+
+ if (expr->op == FFEBLD_opIMPDO)
+ {
+ if (ffest_ffebad_start (FFEBAD_IMPDO_PAREN))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ expr = ffebld_new_paren (expr);
+ ffebld_set_info (expr, ffeinfo_use (ffebld_info (ffebld_left (expr))));
+ }
+
+ /* Now push the (parenthesized) expression as an operand onto the
+ expression stack. */
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->u.operand = expr;
+ e->u.operand = ffeexpr_collapse_paren (e->u.operand, ft);
+ e->token = ffeexpr_stack_->tokens[0];
+ ffeexpr_exprstack_push_operand_ (e);
+
+ return (ffelexHandler) ffeexpr_token_binary_;
+}
+
+/* ffeexpr_cb_close_paren_ambig_ -- OPEN_PAREN expr
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ We get here in the READ/BACKEND/ENDFILE/REWIND case "READ(expr)"
+ with the next token in t. If the next token is possibly a binary
+ operator, continue processing the outer expression. If the next
+ token is COMMA, then the expression is a unit specifier, and
+ parentheses should not be added to it because it surrounds the
+ I/O control list that starts with the unit specifier (and continues
+ on from here -- we haven't seen the CLOSE_PAREN that matches the
+ OPEN_PAREN, it is up to the callback function to expect to see it
+ at some point). In this case, we notify the callback function that
+ the COMMA is inside, not outside, the parens by wrapping the expression
+ in an opITEM (with a NULL trail) -- the callback function presumably
+ unwraps it after seeing this kludgey indicator.
+
+ If the next token is CLOSE_PAREN, then we go to the _1_ state to
+ decide what to do with the token after that.
+
+ 15-Feb-91 JCB 1.1
+ Use an extra state for the CLOSE_PAREN case to make READ &co really
+ work right. */
+
+static ffelexHandler
+ffeexpr_cb_close_paren_ambig_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffeexprCallback callback;
+ ffeexprStack_ s;
+
+ if (ffelex_token_type (t) == FFELEX_typeCLOSE_PAREN)
+ { /* Need to see the next token before we
+ decide anything. */
+ ffeexpr_stack_->expr = expr;
+ ffeexpr_tokens_[0] = ffelex_token_use (ft);
+ ffeexpr_tokens_[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_cb_close_paren_ambig_1_;
+ }
+
+ expr = ffeexpr_finished_ambig_ (ft, expr);
+
+ /* Let the callback function handle the case where t isn't COMMA. */
+
+ /* Here is a kludge whereby we tell the callback function the OPEN_PAREN
+ that preceded the expression starts a list of expressions, and the expr
+ hasn't been wrapped in a corresponding (and possibly collapsed) opPAREN
+ node. The callback function should extract the real expr from the head
+ of this opITEM node after testing it. */
+
+ expr = ffebld_new_item (expr, NULL);
+
+ ffebld_pool_pop ();
+ callback = ffeexpr_stack_->callback;
+ ffelex_token_kill (ffeexpr_stack_->first_token);
+ s = ffeexpr_stack_->previous;
+ malloc_kill_ks (ffe_pool_program_unit (), ffeexpr_stack_, sizeof (*ffeexpr_stack_));
+ ffeexpr_stack_ = s;
+ return (ffelexHandler) (*callback) (ft, expr, t);
+}
+
+/* ffeexpr_cb_close_paren_ambig_1_ -- OPEN_PAREN expr CLOSE_PAREN
+
+ See ffeexpr_cb_close_paren_ambig_.
+
+ We get here in the READ/BACKEND/ENDFILE/REWIND case "READ(expr)"
+ with the next token in t. If the next token is possibly a binary
+ operator, continue processing the outer expression. If the next
+ token is COMMA, the expression is a parenthesized format specifier.
+ If the next token is not EOS or SEMICOLON, then because it is not a
+ binary operator (it is NAME, OPEN_PAREN, &c), the expression is
+ a unit specifier, and parentheses should not be added to it because
+ they surround the I/O control list that consists of only the unit
+ specifier. If the next token is EOS or SEMICOLON, the statement
+ must be disambiguated by looking at the type of the expression -- a
+ character expression is a parenthesized format specifier, while a
+ non-character expression is a unit specifier.
+
+ Another issue is how to do the callback so the recipient of the
+ next token knows how to handle it if it is a COMMA. In all other
+ cases, disambiguation is straightforward: the same approach as the
+ above is used.
+
+ EXTENSION: in COMMA case, if not pedantic, use same disambiguation
+ as for EOS/SEMICOLON case; f2c allows "READ (cilist) [[,]iolist]"
+ and apparently other compilers do, as well, and some code out there
+ uses this "feature".
+
+ 19-Feb-91 JCB 1.1
+ Extend to allow COMMA as nondisambiguating by itself. Remember
+ to not try and check info field for opSTAR, since that expr doesn't
+ have a valid info field. */
+
+static ffelexHandler
+ffeexpr_cb_close_paren_ambig_1_ (ffelexToken t)
+{
+ ffeexprCallback callback;
+ ffeexprStack_ s;
+ ffelexHandler next;
+ ffelexToken orig_ft = ffeexpr_tokens_[0]; /* In case callback clobbers
+ these. */
+ ffelexToken orig_t = ffeexpr_tokens_[1];
+ ffebld expr = ffeexpr_stack_->expr;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA: /* Subexpr is parenthesized format specifier. */
+ if (ffe_is_pedantic ())
+ goto pedantic_comma; /* :::::::::::::::::::: */
+ /* Fall through. */
+ case FFELEX_typeEOS: /* Ambiguous; use type of expr to
+ disambiguate. */
+ case FFELEX_typeSEMICOLON:
+ if ((expr == NULL) || (ffebld_op (expr) == FFEBLD_opANY)
+ || (ffebld_op (expr) == FFEBLD_opSTAR)
+ || (ffeinfo_basictype (ffebld_info (expr))
+ != FFEINFO_basictypeCHARACTER))
+ break; /* Not a valid CHARACTER entity, can't be a
+ format spec. */
+ /* Fall through. */
+ default: /* Binary op (we assume; error otherwise);
+ format specifier. */
+
+ pedantic_comma: /* :::::::::::::::::::: */
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFILENUMAMBIG:
+ ffeexpr_stack_->context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFEEXPR_contextFILEUNITAMBIG:
+ ffeexpr_stack_->context = FFEEXPR_contextFILEFORMAT;
+ break;
+
+ default:
+ assert ("bad context" == NULL);
+ break;
+ }
+
+ ffeexpr_stack_->tokens[0] = ffelex_token_use (ffeexpr_stack_->first_token);
+ next = (ffelexHandler) ffeexpr_cb_close_paren_ (orig_ft, expr, orig_t);
+ ffelex_token_kill (orig_ft);
+ ffelex_token_kill (orig_t);
+ return (ffelexHandler) (*next) (t);
+
+ case FFELEX_typeOPEN_PAREN:/* Non-binary op; beginning of I/O list. */
+ case FFELEX_typeNAME:
+ break;
+ }
+
+ expr = ffeexpr_finished_ambig_ (orig_ft, expr);
+
+ /* Here is a kludge whereby we tell the callback function the OPEN_PAREN
+ that preceded the expression starts a list of expressions, and the expr
+ hasn't been wrapped in a corresponding (and possibly collapsed) opPAREN
+ node. The callback function should extract the real expr from the head
+ of this opITEM node after testing it. */
+
+ expr = ffebld_new_item (expr, NULL);
+
+ ffebld_pool_pop ();
+ callback = ffeexpr_stack_->callback;
+ ffelex_token_kill (ffeexpr_stack_->first_token);
+ s = ffeexpr_stack_->previous;
+ malloc_kill_ks (ffe_pool_program_unit (), ffeexpr_stack_, sizeof (*ffeexpr_stack_));
+ ffeexpr_stack_ = s;
+ next = (ffelexHandler) (*callback) (orig_ft, expr, orig_t);
+ ffelex_token_kill (orig_ft);
+ ffelex_token_kill (orig_t);
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffeexpr_cb_close_paren_c_ -- OPEN_PAREN expr (possible complex)
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ Makes sure the end token is close-paren and swallows it, or a comma
+ and handles complex/implied-do possibilities, else issues
+ an error message and doesn't swallow the token (passing it along instead). */
+
+static ffelexHandler
+ffeexpr_cb_close_paren_c_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ /* First check to see if this is a possible complex entity. It is if the
+ token is a comma. */
+
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ {
+ ffeexpr_stack_->tokens[1] = ffelex_token_use (ft);
+ ffeexpr_stack_->expr = expr;
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextPAREN_, ffeexpr_cb_comma_c_);
+ }
+
+ return (ffelexHandler) ffeexpr_cb_close_paren_ (ft, expr, t);
+}
+
+/* ffeexpr_cb_comma_c_ -- OPEN_PAREN expr COMMA expr
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ If this token is not a comma, we have a complex constant (or an attempt
+ at one), so handle it accordingly, displaying error messages if the token
+ is not a close-paren. */
+
+static ffelexHandler
+ffeexpr_cb_comma_c_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffeexprExpr_ e;
+ ffeinfoBasictype lty = (ffeexpr_stack_->expr == NULL)
+ ? FFEINFO_basictypeNONE : ffeinfo_basictype (ffebld_info (ffeexpr_stack_->expr));
+ ffeinfoBasictype rty = (expr == NULL)
+ ? FFEINFO_basictypeNONE : ffeinfo_basictype (ffebld_info (expr));
+ ffeinfoKindtype lkt;
+ ffeinfoKindtype rkt;
+ ffeinfoKindtype nkt;
+ bool ok = TRUE;
+ ffebld orig;
+
+ if ((ffeexpr_stack_->expr == NULL)
+ || (ffebld_op (ffeexpr_stack_->expr) != FFEBLD_opCONTER)
+ || (((orig = ffebld_conter_orig (ffeexpr_stack_->expr)) != NULL)
+ && (((ffebld_op (orig) != FFEBLD_opUMINUS)
+ && (ffebld_op (orig) != FFEBLD_opUPLUS))
+ || (ffebld_conter_orig (ffebld_left (orig)) != NULL)))
+ || ((lty != FFEINFO_basictypeINTEGER)
+ && (lty != FFEINFO_basictypeREAL)))
+ {
+ if ((lty != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_INVALID_COMPLEX_PART))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_stack_->tokens[1]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[1]));
+ ffebad_string ("Real");
+ ffebad_finish ();
+ }
+ ok = FALSE;
+ }
+ if ((expr == NULL)
+ || (ffebld_op (expr) != FFEBLD_opCONTER)
+ || (((orig = ffebld_conter_orig (expr)) != NULL)
+ && (((ffebld_op (orig) != FFEBLD_opUMINUS)
+ && (ffebld_op (orig) != FFEBLD_opUPLUS))
+ || (ffebld_conter_orig (ffebld_left (orig)) != NULL)))
+ || ((rty != FFEINFO_basictypeINTEGER)
+ && (rty != FFEINFO_basictypeREAL)))
+ {
+ if ((rty != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_INVALID_COMPLEX_PART))
+ {
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_string ("Imaginary");
+ ffebad_finish ();
+ }
+ ok = FALSE;
+ }
+
+ ffelex_token_kill (ffeexpr_stack_->tokens[1]);
+
+ /* Push the (parenthesized) expression as an operand onto the expression
+ stack. */
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_stack_->tokens[0];
+
+ if (ok)
+ {
+ if (lty == FFEINFO_basictypeINTEGER)
+ lkt = FFEINFO_kindtypeREALDEFAULT;
+ else
+ lkt = ffeinfo_kindtype (ffebld_info (ffeexpr_stack_->expr));
+ if (rty == FFEINFO_basictypeINTEGER)
+ rkt = FFEINFO_kindtypeREALDEFAULT;
+ else
+ rkt = ffeinfo_kindtype (ffebld_info (expr));
+
+ nkt = ffeinfo_kindtype_max (FFEINFO_basictypeCOMPLEX, lkt, rkt);
+ ffeexpr_stack_->expr = ffeexpr_convert (ffeexpr_stack_->expr,
+ ffeexpr_stack_->tokens[1], ffeexpr_stack_->tokens[0],
+ FFEINFO_basictypeREAL, nkt, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ expr = ffeexpr_convert (expr,
+ ffeexpr_stack_->tokens[1], ffeexpr_stack_->tokens[0],
+ FFEINFO_basictypeREAL, nkt, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ }
+ else
+ nkt = FFEINFO_kindtypeANY;
+
+ switch (nkt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_complex1
+ (ffebld_conter (ffeexpr_stack_->expr), ffebld_conter (expr)));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeCOMPLEX, nkt, 0,
+ FFEINFO_kindENTITY, FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_complex2
+ (ffebld_conter (ffeexpr_stack_->expr), ffebld_conter (expr)));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeCOMPLEX, nkt, 0,
+ FFEINFO_kindENTITY, FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_complex3
+ (ffebld_conter (ffeexpr_stack_->expr), ffebld_conter (expr)));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeCOMPLEX, nkt, 0,
+ FFEINFO_kindENTITY, FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ break;
+#endif
+
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_complex4
+ (ffebld_conter (ffeexpr_stack_->expr), ffebld_conter (expr)));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeCOMPLEX, nkt, 0,
+ FFEINFO_kindENTITY, FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ break;
+#endif
+
+ default:
+ if (ffebad_start ((nkt == FFEINFO_kindtypeREALDOUBLE)
+ ? FFEBAD_BAD_DBLCMPLX : FFEBAD_BAD_COMPLEX))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_finish ();
+ }
+ /* Fall through. */
+ case FFEINFO_kindtypeANY:
+ e->u.operand = ffebld_new_any ();
+ ffebld_set_info (e->u.operand, ffeinfo_new_any ());
+ break;
+ }
+ ffeexpr_exprstack_push_operand_ (e);
+
+ /* Now, if the token is a close parenthese, we're in great shape so return
+ the next handler. */
+
+ if (ffelex_token_type (t) == FFELEX_typeCLOSE_PAREN)
+ return (ffelexHandler) ffeexpr_token_binary_;
+
+ /* Oops, naughty user didn't specify the close paren! */
+
+ if (ffest_ffebad_start (FFEBAD_MISSING_CLOSE_PAREN))
+ {
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_finish ();
+ }
+
+ return
+ (ffelexHandler) ffeexpr_find_close_paren_ (t,
+ (ffelexHandler)
+ ffeexpr_token_binary_);
+}
+
+/* ffeexpr_cb_close_paren_ci_ -- OPEN_PAREN expr (possible complex or
+ implied-DO construct)
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ Makes sure the end token is close-paren and swallows it, or a comma
+ and handles complex/implied-do possibilities, else issues
+ an error message and doesn't swallow the token (passing it along instead). */
+
+static ffelexHandler
+ffeexpr_cb_close_paren_ci_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffeexprContext ctx;
+
+ /* First check to see if this is a possible complex or implied-DO entity.
+ It is if the token is a comma. */
+
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ {
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIMPDOITEM_:
+ ctx = FFEEXPR_contextIMPDOITEM_;
+ break;
+
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ ctx = FFEEXPR_contextIMPDOITEMDF_;
+ break;
+
+ default:
+ assert ("bad context" == NULL);
+ ctx = FFEEXPR_contextIMPDOITEM_;
+ break;
+ }
+
+ ffeexpr_stack_->tokens[0] = ffelex_token_use (ft);
+ ffeexpr_stack_->expr = expr;
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ ctx, ffeexpr_cb_comma_ci_);
+ }
+
+ ffeexpr_stack_->tokens[0] = ffelex_token_use (ffeexpr_stack_->first_token);
+ return (ffelexHandler) ffeexpr_cb_close_paren_ (ft, expr, t);
+}
+
+/* ffeexpr_cb_comma_ci_ -- OPEN_PAREN expr COMMA expr
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ If this token is not a comma, we have a complex constant (or an attempt
+ at one), so handle it accordingly, displaying error messages if the token
+ is not a close-paren. If we have a comma here, it is an attempt at an
+ implied-DO, so start making a list accordingly. Oh, it might be an
+ equal sign also, meaning an implied-DO with only one item in its list. */
+
+static ffelexHandler
+ffeexpr_cb_comma_ci_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffebld fexpr;
+
+ /* First check to see if this is a possible complex constant. It is if the
+ token is not a comma or an equals sign, in which case it should be a
+ close-paren. */
+
+ if ((ffelex_token_type (t) != FFELEX_typeCOMMA)
+ && (ffelex_token_type (t) != FFELEX_typeEQUALS))
+ {
+ ffeexpr_stack_->tokens[1] = ffeexpr_stack_->tokens[0];
+ ffeexpr_stack_->tokens[0] = ffelex_token_use (ffeexpr_stack_->first_token);
+ return (ffelexHandler) ffeexpr_cb_comma_c_ (ft, expr, t);
+ }
+
+ /* Here we have either EQUALS or COMMA, meaning we are in an implied-DO
+ construct. Make a list and handle accordingly. */
+
+ ffelex_token_kill (ffeexpr_stack_->tokens[0]);
+ fexpr = ffeexpr_stack_->expr;
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ ffebld_append_item (&ffeexpr_stack_->bottom, fexpr);
+ return (ffelexHandler) ffeexpr_cb_comma_i_1_ (ft, expr, t);
+}
+
+/* ffeexpr_cb_comma_i_ -- OPEN_PAREN expr
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ Handle first item in an implied-DO construct. */
+
+static ffelexHandler
+ffeexpr_cb_comma_i_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeCOMMA)
+ {
+ if (ffest_ffebad_start (FFEBAD_BAD_IMPDO))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->first_token),
+ ffelex_token_where_column (ffeexpr_stack_->first_token));
+ ffebad_finish ();
+ }
+ ffebld_end_list (&ffeexpr_stack_->bottom);
+ ffeexpr_stack_->expr = ffebld_new_any ();
+ ffebld_set_info (ffeexpr_stack_->expr, ffeinfo_new_any ());
+ if (ffelex_token_type (t) != FFELEX_typeCLOSE_PAREN)
+ return (ffelexHandler) ffeexpr_cb_comma_i_5_ (t);
+ return (ffelexHandler) ffeexpr_cb_comma_i_5_;
+ }
+
+ return (ffelexHandler) ffeexpr_cb_comma_i_1_ (ft, expr, t);
+}
+
+/* ffeexpr_cb_comma_i_1_ -- OPEN_PAREN expr
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ Handle first item in an implied-DO construct. */
+
+static ffelexHandler
+ffeexpr_cb_comma_i_1_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffeexprContext ctxi;
+ ffeexprContext ctxc;
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextDATA:
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ ctxi = FFEEXPR_contextDATAIMPDOITEM_;
+ ctxc = FFEEXPR_contextDATAIMPDOCTRL_;
+ break;
+
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIMPDOITEM_:
+ ctxi = FFEEXPR_contextIMPDOITEM_;
+ ctxc = FFEEXPR_contextIMPDOCTRL_;
+ break;
+
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ ctxi = FFEEXPR_contextIMPDOITEMDF_;
+ ctxc = FFEEXPR_contextIMPDOCTRL_;
+ break;
+
+ default:
+ assert ("bad context" == NULL);
+ ctxi = FFEEXPR_context;
+ ctxc = FFEEXPR_context;
+ break;
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ if (ffeexpr_stack_->is_rhs)
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ ctxi, ffeexpr_cb_comma_i_1_);
+ return (ffelexHandler) ffeexpr_lhs (ffeexpr_stack_->pool,
+ ctxi, ffeexpr_cb_comma_i_1_);
+
+ case FFELEX_typeEQUALS:
+ ffebld_end_list (&ffeexpr_stack_->bottom);
+
+ /* Complain if implied-DO variable in list of items to be read. */
+
+ if ((ctxc == FFEEXPR_contextIMPDOCTRL_) && !ffeexpr_stack_->is_rhs)
+ ffeexpr_check_impdo_ (ffeexpr_stack_->expr,
+ ffeexpr_stack_->first_token, expr, ft);
+
+ /* Set doiter flag for all appropriate SYMTERs. */
+
+ ffeexpr_update_impdo_ (ffeexpr_stack_->expr, expr);
+
+ ffeexpr_stack_->expr = ffebld_new_impdo (ffeexpr_stack_->expr, NULL);
+ ffebld_set_info (ffeexpr_stack_->expr,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereNONE,
+ FFETARGET_charactersizeNONE));
+ ffebld_init_list (&(ffebld_right (ffeexpr_stack_->expr)),
+ &ffeexpr_stack_->bottom);
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ ctxc, ffeexpr_cb_comma_i_2_);
+
+ default:
+ if (ffest_ffebad_start (FFEBAD_BAD_IMPDO))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->first_token),
+ ffelex_token_where_column (ffeexpr_stack_->first_token));
+ ffebad_finish ();
+ }
+ ffebld_end_list (&ffeexpr_stack_->bottom);
+ ffeexpr_stack_->expr = ffebld_new_any ();
+ ffebld_set_info (ffeexpr_stack_->expr, ffeinfo_new_any ());
+ if (ffelex_token_type (t) != FFELEX_typeCLOSE_PAREN)
+ return (ffelexHandler) ffeexpr_cb_comma_i_5_ (t);
+ return (ffelexHandler) ffeexpr_cb_comma_i_5_;
+ }
+}
+
+/* ffeexpr_cb_comma_i_2_ -- OPEN_PAREN expr-list EQUALS expr
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ Handle start-value in an implied-DO construct. */
+
+static ffelexHandler
+ffeexpr_cb_comma_i_2_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ ffeexprContext ctx;
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextDATA:
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ ctx = FFEEXPR_contextDATAIMPDOCTRL_;
+ break;
+
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextIMPDOITEM_:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ ctx = FFEEXPR_contextIMPDOCTRL_;
+ break;
+
+ default:
+ assert ("bad context" == NULL);
+ ctx = FFEEXPR_context;
+ break;
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ ctx, ffeexpr_cb_comma_i_3_);
+ break;
+
+ default:
+ if (ffest_ffebad_start (FFEBAD_BAD_IMPDO))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->first_token),
+ ffelex_token_where_column (ffeexpr_stack_->first_token));
+ ffebad_finish ();
+ }
+ ffebld_end_list (&ffeexpr_stack_->bottom);
+ ffeexpr_stack_->expr = ffebld_new_any ();
+ ffebld_set_info (ffeexpr_stack_->expr, ffeinfo_new_any ());
+ if (ffelex_token_type (t) != FFELEX_typeCLOSE_PAREN)
+ return (ffelexHandler) ffeexpr_cb_comma_i_5_ (t);
+ return (ffelexHandler) ffeexpr_cb_comma_i_5_;
+ }
+}
+
+/* ffeexpr_cb_comma_i_3_ -- OPEN_PAREN expr-list EQUALS expr COMMA expr
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ Handle end-value in an implied-DO construct. */
+
+static ffelexHandler
+ffeexpr_cb_comma_i_3_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ ffeexprContext ctx;
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextDATA:
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ ctx = FFEEXPR_contextDATAIMPDOCTRL_;
+ break;
+
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextIMPDOITEM_:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ ctx = FFEEXPR_contextIMPDOCTRL_;
+ break;
+
+ default:
+ assert ("bad context" == NULL);
+ ctx = FFEEXPR_context;
+ break;
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ ctx, ffeexpr_cb_comma_i_4_);
+ break;
+
+ case FFELEX_typeCLOSE_PAREN:
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ return (ffelexHandler) ffeexpr_cb_comma_i_4_ (NULL, NULL, t);
+ break;
+
+ default:
+ if (ffest_ffebad_start (FFEBAD_BAD_IMPDO))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->first_token),
+ ffelex_token_where_column (ffeexpr_stack_->first_token));
+ ffebad_finish ();
+ }
+ ffebld_end_list (&ffeexpr_stack_->bottom);
+ ffeexpr_stack_->expr = ffebld_new_any ();
+ ffebld_set_info (ffeexpr_stack_->expr, ffeinfo_new_any ());
+ if (ffelex_token_type (t) != FFELEX_typeCLOSE_PAREN)
+ return (ffelexHandler) ffeexpr_cb_comma_i_5_ (t);
+ return (ffelexHandler) ffeexpr_cb_comma_i_5_;
+ }
+}
+
+/* ffeexpr_cb_comma_i_4_ -- OPEN_PAREN expr-list EQUALS expr COMMA expr
+ [COMMA expr]
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ Handle incr-value in an implied-DO construct. */
+
+static ffelexHandler
+ffeexpr_cb_comma_i_4_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ ffebld_end_list (&ffeexpr_stack_->bottom);
+ {
+ ffebld item;
+
+ for (item = ffebld_left (ffeexpr_stack_->expr);
+ item != NULL;
+ item = ffebld_trail (item))
+ if (ffebld_op (ffebld_head (item)) == FFEBLD_opANY)
+ goto replace_with_any; /* :::::::::::::::::::: */
+
+ for (item = ffebld_right (ffeexpr_stack_->expr);
+ item != NULL;
+ item = ffebld_trail (item))
+ if ((ffebld_head (item) != NULL) /* Increment may be NULL. */
+ && (ffebld_op (ffebld_head (item)) == FFEBLD_opANY))
+ goto replace_with_any; /* :::::::::::::::::::: */
+ }
+ break;
+
+ default:
+ if (ffest_ffebad_start (FFEBAD_BAD_IMPDO))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->first_token),
+ ffelex_token_where_column (ffeexpr_stack_->first_token));
+ ffebad_finish ();
+ }
+ ffebld_end_list (&ffeexpr_stack_->bottom);
+
+ replace_with_any: /* :::::::::::::::::::: */
+
+ ffeexpr_stack_->expr = ffebld_new_any ();
+ ffebld_set_info (ffeexpr_stack_->expr, ffeinfo_new_any ());
+ break;
+ }
+
+ if (ffelex_token_type (t) == FFELEX_typeCLOSE_PAREN)
+ return (ffelexHandler) ffeexpr_cb_comma_i_5_;
+ return (ffelexHandler) ffeexpr_cb_comma_i_5_ (t);
+}
+
+/* ffeexpr_cb_comma_i_5_ -- OPEN_PAREN expr-list EQUALS expr COMMA expr
+ [COMMA expr] CLOSE_PAREN
+
+ Pass it to ffeexpr_rhs as the callback routine.
+
+ Collects token following implied-DO construct for callback function. */
+
+static ffelexHandler
+ffeexpr_cb_comma_i_5_ (ffelexToken t)
+{
+ ffeexprCallback callback;
+ ffeexprStack_ s;
+ ffelexHandler next;
+ ffelexToken ft;
+ ffebld expr;
+ bool terminate;
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextDATA:
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ terminate = TRUE;
+ break;
+
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextIMPDOITEM_:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ terminate = FALSE;
+ break;
+
+ default:
+ assert ("bad context" == NULL);
+ terminate = FALSE;
+ break;
+ }
+
+ ffebld_pool_pop ();
+ callback = ffeexpr_stack_->callback;
+ ft = ffeexpr_stack_->first_token;
+ expr = ffeexpr_stack_->expr;
+ s = ffeexpr_stack_->previous;
+ malloc_kill_ks (ffe_pool_program_unit (), ffeexpr_stack_,
+ sizeof (*ffeexpr_stack_));
+ ffeexpr_stack_ = s;
+ next = (ffelexHandler) (*callback) (ft, expr, t);
+ ffelex_token_kill (ft);
+ if (terminate)
+ {
+ ffesymbol_drive_sfnames (ffeexpr_check_impctrl_);
+ --ffeexpr_level_;
+ if (ffeexpr_level_ == 0)
+ ffe_terminate_4 ();
+ }
+ return (ffelexHandler) next;
+}
+
+/* ffeexpr_cb_end_loc_ -- Handle end of %LOC subexpression
+
+ Makes sure the end token is close-paren and swallows it, else issues
+ an error message and doesn't swallow the token (passing it along instead).
+ In either case wraps up subexpression construction by enclosing the
+ ffebld expression in a %LOC. */
+
+static ffelexHandler
+ffeexpr_cb_end_loc_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ ffeexprExpr_ e;
+
+ /* First push the (%LOC) expression as an operand onto the expression
+ stack. */
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_stack_->tokens[0];
+ e->u.operand = ffebld_new_percent_loc (expr);
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeINTEGER,
+ ffecom_pointer_kind (),
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereFLEETING,
+ FFETARGET_charactersizeNONE));
+#if 0 /* ~~ */
+ e->u.operand = ffeexpr_collapse_percent_loc (e->u.operand, ft);
+#endif
+ ffeexpr_exprstack_push_operand_ (e);
+
+ /* Now, if the token is a close parenthese, we're in great shape so return
+ the next handler. */
+
+ if (ffelex_token_type (t) == FFELEX_typeCLOSE_PAREN)
+ {
+ ffelex_token_kill (ffeexpr_stack_->tokens[1]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+ }
+
+ /* Oops, naughty user didn't specify the close paren! */
+
+ if (ffest_ffebad_start (FFEBAD_MISSING_CLOSE_PAREN))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->tokens[1]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[1]));
+ ffebad_finish ();
+ }
+
+ ffelex_token_kill (ffeexpr_stack_->tokens[1]);
+ return
+ (ffelexHandler) ffeexpr_find_close_paren_ (t,
+ (ffelexHandler)
+ ffeexpr_token_binary_);
+}
+
+/* ffeexpr_cb_end_notloc_ -- PERCENT NAME(VAL,REF,DESCR) OPEN_PAREN expr
+
+ Should be CLOSE_PAREN, and make sure expr isn't a %(VAL,REF,DESCR). */
+
+static ffelexHandler
+ffeexpr_cb_end_notloc_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffeexprExpr_ e;
+ ffebldOp op;
+
+ /* If expression is itself a %(VAL,REF,DESCR), complain and strip off all
+ such things until the lowest-level expression is reached. */
+
+ op = ffebld_op (expr);
+ if ((op == FFEBLD_opPERCENT_VAL) || (op == FFEBLD_opPERCENT_REF)
+ || (op == FFEBLD_opPERCENT_DESCR))
+ {
+ if (ffebad_start (FFEBAD_NESTED_PERCENT))
+ {
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_finish ();
+ }
+
+ do
+ {
+ expr = ffebld_left (expr);
+ op = ffebld_op (expr);
+ }
+ while ((op == FFEBLD_opPERCENT_VAL) || (op == FFEBLD_opPERCENT_REF)
+ || (op == FFEBLD_opPERCENT_DESCR));
+ }
+
+ /* Push the expression as an operand onto the expression stack. */
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_stack_->tokens[0];
+ switch (ffeexpr_stack_->percent)
+ {
+ case FFEEXPR_percentVAL_:
+ e->u.operand = ffebld_new_percent_val (expr);
+ break;
+
+ case FFEEXPR_percentREF_:
+ e->u.operand = ffebld_new_percent_ref (expr);
+ break;
+
+ case FFEEXPR_percentDESCR_:
+ e->u.operand = ffebld_new_percent_descr (expr);
+ break;
+
+ default:
+ assert ("%lossage" == NULL);
+ e->u.operand = expr;
+ break;
+ }
+ ffebld_set_info (e->u.operand, ffebld_info (expr));
+#if 0 /* ~~ */
+ e->u.operand = ffeexpr_collapse_percent_ ? ? ? (e->u.operand, ft);
+#endif
+ ffeexpr_exprstack_push_operand_ (e);
+
+ /* Now, if the token is a close parenthese, we're in great shape so return
+ the next handler. */
+
+ if (ffelex_token_type (t) == FFELEX_typeCLOSE_PAREN)
+ return (ffelexHandler) ffeexpr_cb_end_notloc_1_;
+
+ /* Oops, naughty user didn't specify the close paren! */
+
+ if (ffest_ffebad_start (FFEBAD_MISSING_CLOSE_PAREN))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->tokens[1]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[1]));
+ ffebad_finish ();
+ }
+
+ ffebld_set_op (e->u.operand, FFEBLD_opPERCENT_LOC);
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextINDEXORACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_;
+ break;
+
+ default:
+ assert ("bad context?!?!" == NULL);
+ break;
+ }
+
+ ffelex_token_kill (ffeexpr_stack_->tokens[1]);
+ return
+ (ffelexHandler) ffeexpr_find_close_paren_ (t,
+ (ffelexHandler)
+ ffeexpr_cb_end_notloc_1_);
+}
+
+/* ffeexpr_cb_end_notloc_1_ -- PERCENT NAME(VAL,REF,DESCR) OPEN_PAREN expr
+ CLOSE_PAREN
+
+ Should be COMMA or CLOSE_PAREN, else change back to %LOC. */
+
+static ffelexHandler
+ffeexpr_cb_end_notloc_1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ break;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARG_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARG_;
+ break;
+
+ default:
+ assert ("bad context?!?!" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ if (ffebad_start (FFEBAD_INVALID_PERCENT))
+ {
+ ffebad_here (0,
+ ffelex_token_where_line (ffeexpr_stack_->first_token),
+ ffelex_token_where_column (ffeexpr_stack_->first_token));
+ ffebad_string (ffelex_token_text (ffeexpr_stack_->tokens[1]));
+ ffebad_finish ();
+ }
+
+ ffebld_set_op (ffeexpr_stack_->exprstack->u.operand,
+ FFEBLD_opPERCENT_LOC);
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextINDEXORACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_;
+ break;
+
+ default:
+ assert ("bad context?!?!" == NULL);
+ break;
+ }
+ }
+
+ ffelex_token_kill (ffeexpr_stack_->tokens[1]);
+ return
+ (ffelexHandler) ffeexpr_token_binary_ (t);
+}
+
+/* Process DATA implied-DO iterator variables as this implied-DO level
+ terminates. At this point, ffeexpr_level_ == 1 when we see the
+ last right-paren in "DATA (A(I),I=1,10)/.../". */
+
+static ffesymbol
+ffeexpr_check_impctrl_ (ffesymbol s)
+{
+ assert (s != NULL);
+ assert (ffesymbol_sfdummyparent (s) != NULL);
+
+ switch (ffesymbol_state (s))
+ {
+ case FFESYMBOL_stateNONE: /* Used as iterator already. Now let symbol
+ be used as iterator at any level at or
+ innermore than the outermost of the
+ current level and the symbol's current
+ level. */
+ if (ffeexpr_level_ < ffesymbol_maxentrynum (s))
+ {
+ ffesymbol_signal_change (s);
+ ffesymbol_set_maxentrynum (s, ffeexpr_level_);
+ ffesymbol_signal_unreported (s);
+ }
+ break;
+
+ case FFESYMBOL_stateSEEN: /* Seen already in this or other implied-DO.
+ Error if at outermost level, else it can
+ still become an iterator. */
+ if ((ffeexpr_level_ == 1)
+ && ffebad_start (FFEBAD_BAD_IMPDCL))
+ {
+ ffebad_string (ffesymbol_text (s));
+ ffebad_here (0, ffesymbol_where_line (s), ffesymbol_where_column (s));
+ ffebad_finish ();
+ }
+ break;
+
+ case FFESYMBOL_stateUNCERTAIN: /* Iterator. */
+ assert (ffeexpr_level_ <= ffesymbol_maxentrynum (s));
+ ffesymbol_signal_change (s);
+ ffesymbol_set_state (s, FFESYMBOL_stateNONE);
+ ffesymbol_signal_unreported (s);
+ break;
+
+ case FFESYMBOL_stateUNDERSTOOD:
+ break; /* ANY. */
+
+ default:
+ assert ("Sasha Foo!!" == NULL);
+ break;
+ }
+
+ return s;
+}
+
+/* Issue diagnostic if implied-DO variable appears in list of lhs
+ expressions (as in "READ *, (I,I=1,10)"). */
+
+static void
+ffeexpr_check_impdo_ (ffebld list, ffelexToken list_t,
+ ffebld dovar, ffelexToken dovar_t)
+{
+ ffebld item;
+ ffesymbol dovar_sym;
+ int itemnum;
+
+ if (ffebld_op (dovar) != FFEBLD_opSYMTER)
+ return; /* Presumably opANY. */
+
+ dovar_sym = ffebld_symter (dovar);
+
+ for (itemnum = 1; list != NULL; list = ffebld_trail (list), ++itemnum)
+ {
+ if (((item = ffebld_head (list)) != NULL)
+ && (ffebld_op (item) == FFEBLD_opSYMTER)
+ && (ffebld_symter (item) == dovar_sym))
+ {
+ char itemno[20];
+
+ sprintf (&itemno[0], "%d", itemnum);
+ if (ffebad_start (FFEBAD_DOITER_IMPDO))
+ {
+ ffebad_here (0, ffelex_token_where_line (list_t),
+ ffelex_token_where_column (list_t));
+ ffebad_here (1, ffelex_token_where_line (dovar_t),
+ ffelex_token_where_column (dovar_t));
+ ffebad_string (ffesymbol_text (dovar_sym));
+ ffebad_string (itemno);
+ ffebad_finish ();
+ }
+ }
+ }
+}
+
+/* Decorate any SYMTERs referencing the DO variable with the "doiter"
+ flag. */
+
+static void
+ffeexpr_update_impdo_ (ffebld list, ffebld dovar)
+{
+ ffesymbol dovar_sym;
+
+ if (ffebld_op (dovar) != FFEBLD_opSYMTER)
+ return; /* Presumably opANY. */
+
+ dovar_sym = ffebld_symter (dovar);
+
+ ffeexpr_update_impdo_sym_ (list, dovar_sym); /* Recurse! */
+}
+
+/* Recursive function to update any expr so SYMTERs have "doiter" flag
+ if they refer to the given variable. */
+
+static void
+ffeexpr_update_impdo_sym_ (ffebld expr, ffesymbol dovar)
+{
+ tail_recurse: /* :::::::::::::::::::: */
+
+ if (expr == NULL)
+ return;
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opSYMTER:
+ if (ffebld_symter (expr) == dovar)
+ ffebld_symter_set_is_doiter (expr, TRUE);
+ break;
+
+ case FFEBLD_opITEM:
+ ffeexpr_update_impdo_sym_ (ffebld_head (expr), dovar);
+ expr = ffebld_trail (expr);
+ goto tail_recurse; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+
+ switch (ffebld_arity (expr))
+ {
+ case 2:
+ ffeexpr_update_impdo_sym_ (ffebld_left (expr), dovar);
+ expr = ffebld_right (expr);
+ goto tail_recurse; /* :::::::::::::::::::: */
+
+ case 1:
+ expr = ffebld_left (expr);
+ goto tail_recurse; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+/* ffeexpr_context_outer_ -- Determine context of stack entry, skipping PARENs
+
+ if (ffeexpr_context_outer_(ffeexpr_stack_) == FFEEXPR_contextIF)
+ // After zero or more PAREN_ contexts, an IF context exists */
+
+static ffeexprContext
+ffeexpr_context_outer_ (ffeexprStack_ s)
+{
+ assert (s != NULL);
+
+ for (;;)
+ {
+ switch (s->context)
+ {
+ case FFEEXPR_contextPAREN_:
+ case FFEEXPR_contextPARENFILENUM_:
+ case FFEEXPR_contextPARENFILEUNIT_:
+ break;
+
+ default:
+ return s->context;
+ }
+ s = s->previous;
+ assert (s != NULL);
+ }
+}
+
+/* ffeexpr_percent_ -- Look up name in list of %FOO possibilities
+
+ ffeexprPercent_ p;
+ ffelexToken t;
+ p = ffeexpr_percent_(t);
+
+ Returns the identifier for the name, or the NONE identifier. */
+
+static ffeexprPercent_
+ffeexpr_percent_ (ffelexToken t)
+{
+ char *p;
+
+ switch (ffelex_token_length (t))
+ {
+ case 3:
+ switch (*(p = ffelex_token_text (t)))
+ {
+ case FFESRC_CASE_MATCH_INIT ('L', 'l', match_3l, no_match_3):
+ if ((ffesrc_char_match_noninit (*++p, 'O', 'o'))
+ && (ffesrc_char_match_noninit (*++p, 'C', 'c')))
+ return FFEEXPR_percentLOC_;
+ return FFEEXPR_percentNONE_;
+
+ case FFESRC_CASE_MATCH_INIT ('R', 'r', match_3r, no_match_3):
+ if ((ffesrc_char_match_noninit (*++p, 'E', 'e'))
+ && (ffesrc_char_match_noninit (*++p, 'F', 'f')))
+ return FFEEXPR_percentREF_;
+ return FFEEXPR_percentNONE_;
+
+ case FFESRC_CASE_MATCH_INIT ('V', 'v', match_3v, no_match_3):
+ if ((ffesrc_char_match_noninit (*++p, 'A', 'a'))
+ && (ffesrc_char_match_noninit (*++p, 'L', 'l')))
+ return FFEEXPR_percentVAL_;
+ return FFEEXPR_percentNONE_;
+
+ default:
+ no_match_3: /* :::::::::::::::::::: */
+ return FFEEXPR_percentNONE_;
+ }
+
+ case 5:
+ if (ffesrc_strcmp_2c (ffe_case_match (), ffelex_token_text (t), "DESCR",
+ "descr", "Descr") == 0)
+ return FFEEXPR_percentDESCR_;
+ return FFEEXPR_percentNONE_;
+
+ default:
+ return FFEEXPR_percentNONE_;
+ }
+}
+
+/* ffeexpr_type_combine -- Binop combine types, check for mythical new COMPLEX
+
+ See prototype.
+
+ If combining the two basictype/kindtype pairs produces a COMPLEX with an
+ unsupported kind type, complain and use the default kind type for
+ COMPLEX. */
+
+void
+ffeexpr_type_combine (ffeinfoBasictype *xnbt, ffeinfoKindtype *xnkt,
+ ffeinfoBasictype lbt, ffeinfoKindtype lkt,
+ ffeinfoBasictype rbt, ffeinfoKindtype rkt,
+ ffelexToken t)
+{
+ ffeinfoBasictype nbt;
+ ffeinfoKindtype nkt;
+
+ nbt = ffeinfo_basictype_combine (lbt, rbt);
+ if ((nbt == FFEINFO_basictypeCOMPLEX)
+ && ((lbt == nbt) || (lbt == FFEINFO_basictypeREAL))
+ && ((rbt == nbt) || (rbt == FFEINFO_basictypeREAL)))
+ {
+ nkt = ffeinfo_kindtype_max (nbt, lkt, rkt);
+ if (ffe_is_pedantic_not_90 () && (nkt == FFEINFO_kindtypeREALDOUBLE))
+ nkt = FFEINFO_kindtypeNONE; /* Force error. */
+ switch (nkt)
+ {
+#if FFETARGET_okCOMPLEX1
+ case FFEINFO_kindtypeREAL1:
+#endif
+#if FFETARGET_okCOMPLEX2
+ case FFEINFO_kindtypeREAL2:
+#endif
+#if FFETARGET_okCOMPLEX3
+ case FFEINFO_kindtypeREAL3:
+#endif
+#if FFETARGET_okCOMPLEX4
+ case FFEINFO_kindtypeREAL4:
+#endif
+ break; /* Fine and dandy. */
+
+ default:
+ if (t != NULL)
+ {
+ ffebad_start ((nkt == FFEINFO_kindtypeREALDOUBLE)
+ ? FFEBAD_BAD_DBLCMPLX : FFEBAD_BAD_COMPLEX);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ nbt = FFEINFO_basictypeNONE;
+ nkt = FFEINFO_kindtypeNONE;
+ break;
+
+ case FFEINFO_kindtypeANY:
+ nkt = FFEINFO_kindtypeREALDEFAULT;
+ break;
+ }
+ }
+ else
+ { /* The normal stuff. */
+ if (nbt == lbt)
+ {
+ if (nbt == rbt)
+ nkt = ffeinfo_kindtype_max (nbt, lkt, rkt);
+ else
+ nkt = lkt;
+ }
+ else if (nbt == rbt)
+ nkt = rkt;
+ else
+ { /* Let the caller do the complaining. */
+ nbt = FFEINFO_basictypeNONE;
+ nkt = FFEINFO_kindtypeNONE;
+ }
+ }
+
+ /* Always a good idea to avoid aliasing problems. */
+
+ *xnbt = nbt;
+ *xnkt = nkt;
+}
+
+/* ffeexpr_token_first_lhs_ -- First state for lhs expression
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Record line and column of first token in expression, then invoke the
+ initial-state lhs handler. */
+
+static ffelexHandler
+ffeexpr_token_first_lhs_ (ffelexToken t)
+{
+ ffeexpr_stack_->first_token = ffelex_token_use (t);
+
+ /* When changing the list of valid initial lhs tokens, check whether to
+ update a corresponding list in ffeexpr_cb_close_paren_ambig_1_ for the
+ READ (expr) <token> case -- it assumes it knows which tokens <token> can
+ be to indicate an lhs (or implied DO), which right now is the set
+ {NAME,OPEN_PAREN}.
+
+ This comment also appears in ffeexpr_token_lhs_. */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextDATA:
+ ffe_init_4 ();
+ ffeexpr_level_ = 1; /* Level of DATA implied-DO construct. */
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ return (ffelexHandler) ffeexpr_lhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextDATAIMPDOITEM_, ffeexpr_cb_comma_i_);
+
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ ++ffeexpr_level_; /* Level of DATA implied-DO construct. */
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ return (ffelexHandler) ffeexpr_lhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextDATAIMPDOITEM_, ffeexpr_cb_comma_i_);
+
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIMPDOITEM_:
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ return (ffelexHandler) ffeexpr_lhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextIMPDOITEM_, ffeexpr_cb_comma_i_);
+
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ return (ffelexHandler) ffeexpr_lhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextIMPDOITEMDF_, ffeexpr_cb_comma_i_);
+
+ case FFEEXPR_contextFILEEXTFUNC:
+ assert (ffeexpr_stack_->exprstack == NULL);
+ return (ffelexHandler) ffeexpr_token_first_lhs_1_;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFELEX_typeNAME:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFILENAMELIST:
+ assert (ffeexpr_stack_->exprstack == NULL);
+ return (ffelexHandler) ffeexpr_token_namelist_;
+
+ case FFEEXPR_contextFILEEXTFUNC:
+ assert (ffeexpr_stack_->exprstack == NULL);
+ return (ffelexHandler) ffeexpr_token_first_lhs_1_;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFILEEXTFUNC:
+ assert (ffeexpr_stack_->exprstack == NULL);
+ return (ffelexHandler) ffeexpr_token_first_lhs_1_;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ return (ffelexHandler) ffeexpr_token_lhs_ (t);
+}
+
+/* ffeexpr_token_first_lhs_1_ -- NAME
+
+ return ffeexpr_token_first_lhs_1_; // to lexer
+
+ Handle NAME as an external function (USEROPEN= VXT extension to OPEN
+ statement). */
+
+static ffelexHandler
+ffeexpr_token_first_lhs_1_ (ffelexToken t)
+{
+ ffeexprCallback callback;
+ ffeexprStack_ s;
+ ffelexHandler next;
+ ffelexToken ft;
+ ffesymbol sy = NULL;
+ ffebld expr;
+
+ ffebld_pool_pop ();
+ callback = ffeexpr_stack_->callback;
+ ft = ffeexpr_stack_->first_token;
+ s = ffeexpr_stack_->previous;
+
+ if ((ffelex_token_type (ft) != FFELEX_typeNAME)
+ || (ffesymbol_attrs (sy = ffeexpr_declare_unadorned_ (ft, FALSE))
+ & FFESYMBOL_attrANY))
+ {
+ if ((ffelex_token_type (ft) != FFELEX_typeNAME)
+ || !(ffesymbol_attrs (sy) & FFESYMBOL_attrsANY))
+ {
+ ffebad_start (FFEBAD_EXPR_WRONG);
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_finish ();
+ }
+ expr = ffebld_new_any ();
+ ffebld_set_info (expr, ffeinfo_new_any ());
+ }
+ else
+ {
+ expr = ffebld_new_symter (sy, FFEINTRIN_genNONE, FFEINTRIN_specNONE,
+ FFEINTRIN_impNONE);
+ ffebld_set_info (expr, ffesymbol_info (sy));
+ }
+
+ malloc_kill_ks (ffe_pool_program_unit (), ffeexpr_stack_,
+ sizeof (*ffeexpr_stack_));
+ ffeexpr_stack_ = s;
+
+ next = (ffelexHandler) (*callback) (ft, expr, t);
+ ffelex_token_kill (ft);
+ return (ffelexHandler) next;
+}
+
+/* ffeexpr_token_first_rhs_ -- First state for rhs expression
+
+ Record line and column of first token in expression, then invoke the
+ initial-state rhs handler.
+
+ 19-Feb-91 JCB 1.1
+ Allow ASTERISK in PARENFILEUNIT_ case, but only on second level only
+ (i.e. only as in READ(*), not READ((*))). */
+
+static ffelexHandler
+ffeexpr_token_first_rhs_ (ffelexToken t)
+{
+ ffesymbol s;
+
+ ffeexpr_stack_->first_token = ffelex_token_use (t);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeASTERISK:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFILEFORMATNML:
+ ffeexpr_stack_->context = FFEEXPR_contextFILEFORMAT;
+ /* Fall through. */
+ case FFEEXPR_contextFILEUNIT:
+ case FFEEXPR_contextDIMLIST:
+ case FFEEXPR_contextFILEFORMAT:
+ case FFEEXPR_contextCHARACTERSIZE:
+ if (ffeexpr_stack_->previous != NULL)
+ break; /* Valid only on first level. */
+ assert (ffeexpr_stack_->exprstack == NULL);
+ return (ffelexHandler) ffeexpr_token_first_rhs_1_;
+
+ case FFEEXPR_contextPARENFILEUNIT_:
+ if (ffeexpr_stack_->previous->previous != NULL)
+ break; /* Valid only on second level. */
+ assert (ffeexpr_stack_->exprstack == NULL);
+ return (ffelexHandler) ffeexpr_token_first_rhs_1_;
+
+ case FFEEXPR_contextACTUALARG_:
+ if (ffeexpr_stack_->previous->context
+ != FFEEXPR_contextSUBROUTINEREF)
+ {
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARGEXPR_;
+ break;
+ }
+ assert (ffeexpr_stack_->exprstack == NULL);
+ return (ffelexHandler) ffeexpr_token_first_rhs_3_;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextINDEXORACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFELEX_typeOPEN_PAREN:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFILENUMAMBIG:
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextPARENFILENUM_,
+ ffeexpr_cb_close_paren_ambig_);
+
+ case FFEEXPR_contextFILEUNITAMBIG:
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextPARENFILEUNIT_,
+ ffeexpr_cb_close_paren_ambig_);
+
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIMPDOITEM_:
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextIMPDOITEM_,
+ ffeexpr_cb_close_paren_ci_);
+
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextIMPDOITEMDF_,
+ ffeexpr_cb_close_paren_ci_);
+
+ case FFEEXPR_contextFILEFORMATNML:
+ ffeexpr_stack_->context = FFEEXPR_contextFILEFORMAT;
+ break;
+
+ case FFEEXPR_contextACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextINDEXORACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFELEX_typeNUMBER:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFILEFORMATNML:
+ ffeexpr_stack_->context = FFEEXPR_contextFILEFORMAT;
+ /* Fall through. */
+ case FFEEXPR_contextFILEFORMAT:
+ if (ffeexpr_stack_->previous != NULL)
+ break; /* Valid only on first level. */
+ assert (ffeexpr_stack_->exprstack == NULL);
+ return (ffelexHandler) ffeexpr_token_first_rhs_2_;
+
+ case FFEEXPR_contextACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextINDEXORACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFELEX_typeNAME:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFILEFORMATNML:
+ assert (ffeexpr_stack_->exprstack == NULL);
+ s = ffesymbol_lookup_local (t);
+ if ((s != NULL) && (ffesymbol_kind (s) == FFEINFO_kindNAMELIST))
+ return (ffelexHandler) ffeexpr_token_namelist_;
+ ffeexpr_stack_->context = FFEEXPR_contextFILEFORMAT;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFELEX_typePERCENT:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextACTUALARG_:
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ return (ffelexHandler) ffeexpr_token_first_rhs_5_;
+
+ case FFEEXPR_contextFILEFORMATNML:
+ ffeexpr_stack_->context = FFEEXPR_contextFILEFORMAT;
+ break;
+
+ default:
+ break;
+ }
+
+ default:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextINDEXORACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextFILEFORMATNML:
+ ffeexpr_stack_->context = FFEEXPR_contextFILEFORMAT;
+ break;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ return (ffelexHandler) ffeexpr_token_rhs_ (t);
+}
+
+/* ffeexpr_token_first_rhs_1_ -- ASTERISK
+
+ return ffeexpr_token_first_rhs_1_; // to lexer
+
+ Return STAR as expression. */
+
+static ffelexHandler
+ffeexpr_token_first_rhs_1_ (ffelexToken t)
+{
+ ffebld expr;
+ ffeexprCallback callback;
+ ffeexprStack_ s;
+ ffelexHandler next;
+ ffelexToken ft;
+
+ expr = ffebld_new_star ();
+ ffebld_pool_pop ();
+ callback = ffeexpr_stack_->callback;
+ ft = ffeexpr_stack_->first_token;
+ s = ffeexpr_stack_->previous;
+ malloc_kill_ks (ffe_pool_program_unit (), ffeexpr_stack_, sizeof (*ffeexpr_stack_));
+ ffeexpr_stack_ = s;
+ next = (ffelexHandler) (*callback) (ft, expr, t);
+ ffelex_token_kill (ft);
+ return (ffelexHandler) next;
+}
+
+/* ffeexpr_token_first_rhs_2_ -- NUMBER
+
+ return ffeexpr_token_first_rhs_2_; // to lexer
+
+ Return NULL as expression; NUMBER as first (and only) token, unless the
+ current token is not a terminating token, in which case run normal
+ expression handling. */
+
+static ffelexHandler
+ffeexpr_token_first_rhs_2_ (ffelexToken t)
+{
+ ffeexprCallback callback;
+ ffeexprStack_ s;
+ ffelexHandler next;
+ ffelexToken ft;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+
+ default:
+ next = (ffelexHandler) ffeexpr_token_rhs_ (ffeexpr_stack_->first_token);
+ return (ffelexHandler) (*next) (t);
+ }
+
+ ffebld_pool_pop ();
+ callback = ffeexpr_stack_->callback;
+ ft = ffeexpr_stack_->first_token;
+ s = ffeexpr_stack_->previous;
+ malloc_kill_ks (ffe_pool_program_unit (), ffeexpr_stack_,
+ sizeof (*ffeexpr_stack_));
+ ffeexpr_stack_ = s;
+ next = (ffelexHandler) (*callback) (ft, NULL, t);
+ ffelex_token_kill (ft);
+ return (ffelexHandler) next;
+}
+
+/* ffeexpr_token_first_rhs_3_ -- ASTERISK
+
+ return ffeexpr_token_first_rhs_3_; // to lexer
+
+ Expect NUMBER, make LABTOK (with copy of token if not inhibited after
+ confirming, else NULL). */
+
+static ffelexHandler
+ffeexpr_token_first_rhs_3_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ { /* An error, but let normal processing handle
+ it. */
+ next = (ffelexHandler) ffeexpr_token_rhs_ (ffeexpr_stack_->first_token);
+ return (ffelexHandler) (*next) (t);
+ }
+
+ /* Special case: when we see "*10" as an argument to a subroutine
+ reference, we confirm the current statement and, if not inhibited at
+ this point, put a copy of the token into a LABTOK node. We do this
+ instead of just resolving the label directly via ffelab and putting it
+ into a LABTER simply to improve error reporting and consistency in
+ ffestc. We put NULL in the LABTOK if we're still inhibited, so ffestb
+ doesn't have to worry about killing off any tokens when retracting. */
+
+ ffest_confirmed ();
+ if (ffest_is_inhibited ())
+ ffeexpr_stack_->expr = ffebld_new_labtok (NULL);
+ else
+ ffeexpr_stack_->expr = ffebld_new_labtok (ffelex_token_use (t));
+ ffebld_set_info (ffeexpr_stack_->expr,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereNONE,
+ FFETARGET_charactersizeNONE));
+
+ return (ffelexHandler) ffeexpr_token_first_rhs_4_;
+}
+
+/* ffeexpr_token_first_rhs_4_ -- ASTERISK NUMBER
+
+ return ffeexpr_token_first_rhs_4_; // to lexer
+
+ Collect/flush appropriate stuff, send token to callback function. */
+
+static ffelexHandler
+ffeexpr_token_first_rhs_4_ (ffelexToken t)
+{
+ ffebld expr;
+ ffeexprCallback callback;
+ ffeexprStack_ s;
+ ffelexHandler next;
+ ffelexToken ft;
+
+ expr = ffeexpr_stack_->expr;
+ ffebld_pool_pop ();
+ callback = ffeexpr_stack_->callback;
+ ft = ffeexpr_stack_->first_token;
+ s = ffeexpr_stack_->previous;
+ malloc_kill_ks (ffe_pool_program_unit (), ffeexpr_stack_, sizeof (*ffeexpr_stack_));
+ ffeexpr_stack_ = s;
+ next = (ffelexHandler) (*callback) (ft, expr, t);
+ ffelex_token_kill (ft);
+ return (ffelexHandler) next;
+}
+
+/* ffeexpr_token_first_rhs_5_ -- PERCENT
+
+ Should be NAME, or pass through original mechanism. If NAME is LOC,
+ pass through original mechanism, otherwise must be VAL, REF, or DESCR,
+ in which case handle the argument (in parentheses), etc. */
+
+static ffelexHandler
+ffeexpr_token_first_rhs_5_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ if (ffelex_token_type (t) == FFELEX_typeNAME)
+ {
+ ffeexprPercent_ p = ffeexpr_percent_ (t);
+
+ switch (p)
+ {
+ case FFEEXPR_percentNONE_:
+ case FFEEXPR_percentLOC_:
+ break; /* Treat %LOC as any other expression. */
+
+ case FFEEXPR_percentVAL_:
+ case FFEEXPR_percentREF_:
+ case FFEEXPR_percentDESCR_:
+ ffeexpr_stack_->percent = p;
+ ffeexpr_stack_->tokens[0] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_first_rhs_6_;
+
+ default:
+ assert ("bad percent?!?" == NULL);
+ break;
+ }
+ }
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextINDEXORACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_;
+ break;
+
+ default:
+ assert ("bad context?!?!" == NULL);
+ break;
+ }
+
+ next = (ffelexHandler) ffeexpr_token_rhs_ (ffeexpr_stack_->first_token);
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffeexpr_token_first_rhs_6_ -- PERCENT NAME(VAL,REF,DESCR)
+
+ Should be OPEN_PAREN, or pass through original mechanism. */
+
+static ffelexHandler
+ffeexpr_token_first_rhs_6_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken ft;
+
+ if (ffelex_token_type (t) == FFELEX_typeOPEN_PAREN)
+ {
+ ffeexpr_stack_->tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ ffeexpr_stack_->context,
+ ffeexpr_cb_end_notloc_);
+ }
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextINDEXORACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_;
+ break;
+
+ default:
+ assert ("bad context?!?!" == NULL);
+ break;
+ }
+
+ ft = ffeexpr_stack_->tokens[0];
+ next = (ffelexHandler) ffeexpr_token_rhs_ (ffeexpr_stack_->first_token);
+ next = (ffelexHandler) (*next) (ft);
+ ffelex_token_kill (ft);
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffeexpr_token_namelist_ -- NAME
+
+ return ffeexpr_token_namelist_; // to lexer
+
+ Make sure NAME was a valid namelist object, wrap it in a SYMTER and
+ return. */
+
+static ffelexHandler
+ffeexpr_token_namelist_ (ffelexToken t)
+{
+ ffeexprCallback callback;
+ ffeexprStack_ s;
+ ffelexHandler next;
+ ffelexToken ft;
+ ffesymbol sy;
+ ffebld expr;
+
+ ffebld_pool_pop ();
+ callback = ffeexpr_stack_->callback;
+ ft = ffeexpr_stack_->first_token;
+ s = ffeexpr_stack_->previous;
+ malloc_kill_ks (ffe_pool_program_unit (), ffeexpr_stack_, sizeof (*ffeexpr_stack_));
+ ffeexpr_stack_ = s;
+
+ sy = ffesymbol_lookup_local (ft);
+ if ((sy == NULL) || (ffesymbol_kind (sy) != FFEINFO_kindNAMELIST))
+ {
+ ffebad_start (FFEBAD_EXPR_WRONG);
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_finish ();
+ expr = ffebld_new_any ();
+ ffebld_set_info (expr, ffeinfo_new_any ());
+ }
+ else
+ {
+ expr = ffebld_new_symter (sy, FFEINTRIN_genNONE, FFEINTRIN_specNONE,
+ FFEINTRIN_impNONE);
+ ffebld_set_info (expr, ffesymbol_info (sy));
+ }
+ next = (ffelexHandler) (*callback) (ft, expr, t);
+ ffelex_token_kill (ft);
+ return (ffelexHandler) next;
+}
+
+/* ffeexpr_expr_kill_ -- Kill an existing internal expression object
+
+ ffeexprExpr_ e;
+ ffeexpr_expr_kill_(e);
+
+ Kills the ffewhere info, if necessary, then kills the object. */
+
+static void
+ffeexpr_expr_kill_ (ffeexprExpr_ e)
+{
+ if (e->token != NULL)
+ ffelex_token_kill (e->token);
+ malloc_kill_ks (ffe_pool_program_unit (), e, sizeof (*e));
+}
+
+/* ffeexpr_expr_new_ -- Make a new internal expression object
+
+ ffeexprExpr_ e;
+ e = ffeexpr_expr_new_();
+
+ Allocates and initializes a new expression object, returns it. */
+
+static ffeexprExpr_
+ffeexpr_expr_new_ ()
+{
+ ffeexprExpr_ e;
+
+ e = (ffeexprExpr_) malloc_new_ks (ffe_pool_program_unit (), "FFEEXPR expr",
+ sizeof (*e));
+ e->previous = NULL;
+ e->type = FFEEXPR_exprtypeUNKNOWN_;
+ e->token = NULL;
+ return e;
+}
+
+/* Verify that call to global is valid, and register whatever
+ new information about a global might be discoverable by looking
+ at the call. */
+
+static void
+ffeexpr_fulfill_call_ (ffebld *expr, ffelexToken t)
+{
+ int n_args;
+ ffebld list;
+ ffebld item;
+ ffesymbol s;
+
+ assert ((ffebld_op (*expr) == FFEBLD_opSUBRREF)
+ || (ffebld_op (*expr) == FFEBLD_opFUNCREF));
+
+ if (ffebld_op (ffebld_left (*expr)) != FFEBLD_opSYMTER)
+ return;
+
+ if (ffesymbol_retractable ())
+ return;
+
+ s = ffebld_symter (ffebld_left (*expr));
+ if (ffesymbol_global (s) == NULL)
+ return;
+
+ for (n_args = 0, list = ffebld_right (*expr);
+ list != NULL;
+ list = ffebld_trail (list), ++n_args)
+ ;
+
+ if (ffeglobal_proc_ref_nargs (s, n_args, t))
+ {
+ ffeglobalArgSummary as;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ bool array;
+ bool fail = FALSE;
+
+ for (n_args = 0, list = ffebld_right (*expr);
+ list != NULL;
+ list = ffebld_trail (list), ++n_args)
+ {
+ item = ffebld_head (list);
+ if (item != NULL)
+ {
+ bt = ffeinfo_basictype (ffebld_info (item));
+ kt = ffeinfo_kindtype (ffebld_info (item));
+ array = (ffeinfo_rank (ffebld_info (item)) > 0);
+ switch (ffebld_op (item))
+ {
+ case FFEBLD_opLABTOK:
+ case FFEBLD_opLABTER:
+ as = FFEGLOBAL_argsummaryALTRTN;
+ break;
+
+#if 0
+ /* No, %LOC(foo) is just like any INTEGER(KIND=7)
+ expression, so don't treat it specially. */
+ case FFEBLD_opPERCENT_LOC:
+ as = FFEGLOBAL_argsummaryPTR;
+ break;
+#endif
+
+ case FFEBLD_opPERCENT_VAL:
+ as = FFEGLOBAL_argsummaryVAL;
+ break;
+
+ case FFEBLD_opPERCENT_REF:
+ as = FFEGLOBAL_argsummaryREF;
+ break;
+
+ case FFEBLD_opPERCENT_DESCR:
+ as = FFEGLOBAL_argsummaryDESCR;
+ break;
+
+ case FFEBLD_opFUNCREF:
+#if 0
+ /* No, LOC(foo) is just like any INTEGER(KIND=7)
+ expression, so don't treat it specially. */
+ if ((ffebld_op (ffebld_left (item)) == FFEBLD_opSYMTER)
+ && (ffesymbol_specific (ffebld_symter (ffebld_left (item)))
+ == FFEINTRIN_specLOC))
+ {
+ as = FFEGLOBAL_argsummaryPTR;
+ break;
+ }
+#endif
+ /* Fall through. */
+ default:
+ if (ffebld_op (item) == FFEBLD_opSYMTER)
+ {
+ as = FFEGLOBAL_argsummaryNONE;
+
+ switch (ffeinfo_kind (ffebld_info (item)))
+ {
+ case FFEINFO_kindFUNCTION:
+ as = FFEGLOBAL_argsummaryFUNC;
+ break;
+
+ case FFEINFO_kindSUBROUTINE:
+ as = FFEGLOBAL_argsummarySUBR;
+ break;
+
+ case FFEINFO_kindNONE:
+ as = FFEGLOBAL_argsummaryPROC;
+ break;
+
+ default:
+ break;
+ }
+
+ if (as != FFEGLOBAL_argsummaryNONE)
+ break;
+ }
+
+ if (bt == FFEINFO_basictypeCHARACTER)
+ as = FFEGLOBAL_argsummaryDESCR;
+ else
+ as = FFEGLOBAL_argsummaryREF;
+ break;
+ }
+ }
+ else
+ {
+ array = FALSE;
+ as = FFEGLOBAL_argsummaryNONE;
+ bt = FFEINFO_basictypeNONE;
+ kt = FFEINFO_kindtypeNONE;
+ }
+
+ if (! ffeglobal_proc_ref_arg (s, n_args, as, bt, kt, array, t))
+ fail = TRUE;
+ }
+ if (! fail)
+ return;
+ }
+
+ *expr = ffebld_new_any ();
+ ffebld_set_info (*expr, ffeinfo_new_any ());
+}
+
+/* Check whether rest of string is all decimal digits. */
+
+static bool
+ffeexpr_isdigits_ (char *p)
+{
+ for (; *p != '\0'; ++p)
+ if (! ISDIGIT (*p))
+ return FALSE;
+ return TRUE;
+}
+
+/* ffeexpr_exprstack_push_ -- Push an arbitrary expression object onto the stack
+
+ ffeexprExpr_ e;
+ ffeexpr_exprstack_push_(e);
+
+ Pushes the expression onto the stack without any analysis of the existing
+ contents of the stack. */
+
+static void
+ffeexpr_exprstack_push_ (ffeexprExpr_ e)
+{
+ e->previous = ffeexpr_stack_->exprstack;
+ ffeexpr_stack_->exprstack = e;
+}
+
+/* ffeexpr_exprstack_push_operand_ -- Push an operand onto the stack, reduce?
+
+ ffeexprExpr_ e;
+ ffeexpr_exprstack_push_operand_(e);
+
+ Pushes the expression already containing an operand (a constant, variable,
+ or more complicated expression that has already been fully resolved) after
+ analyzing the stack and checking for possible reduction (which will never
+ happen here since the highest precedence operator is ** and it has right-
+ to-left associativity). */
+
+static void
+ffeexpr_exprstack_push_operand_ (ffeexprExpr_ e)
+{
+ ffeexpr_exprstack_push_ (e);
+#ifdef WEIRD_NONFORTRAN_RULES
+ if ((ffeexpr_stack_->exprstack != NULL)
+ && (ffeexpr_stack_->exprstack->expr->type == FFEEXPR_exprtypeBINARY_)
+ && (ffeexpr_stack_->exprstack->expr->u.operator.prec
+ == FFEEXPR_operatorprecedenceHIGHEST_)
+ && (ffeexpr_stack_->exprstack->expr->u.operator.as
+ == FFEEXPR_operatorassociativityL2R_))
+ ffeexpr_reduce_ ();
+#endif
+}
+
+/* ffeexpr_exprstack_push_unary_ -- Push a unary operator onto the stack
+
+ ffeexprExpr_ e;
+ ffeexpr_exprstack_push_unary_(e);
+
+ Pushes the expression already containing a unary operator. Reduction can
+ never happen since unary operators are themselves always R-L; that is, the
+ top of the expression stack is not an operand, in that it is either empty,
+ has a binary operator at the top, or a unary operator at the top. In any
+ of these cases, reduction is impossible. */
+
+static void
+ffeexpr_exprstack_push_unary_ (ffeexprExpr_ e)
+{
+ if ((ffe_is_pedantic ()
+ || ffe_is_warn_surprising ())
+ && (ffeexpr_stack_->exprstack != NULL)
+ && (ffeexpr_stack_->exprstack->type != FFEEXPR_exprtypeOPERAND_)
+ && (ffeexpr_stack_->exprstack->u.operator.prec
+ <= FFEEXPR_operatorprecedenceLOWARITH_)
+ && (e->u.operator.prec <= FFEEXPR_operatorprecedenceLOWARITH_))
+ {
+ ffebad_start_msg ("Two arithmetic operators in a row at %0 and %1 -- use parentheses",
+ ffe_is_pedantic ()
+ ? FFEBAD_severityPEDANTIC
+ : FFEBAD_severityWARNING);
+ ffebad_here (0,
+ ffelex_token_where_line (ffeexpr_stack_->exprstack->token),
+ ffelex_token_where_column (ffeexpr_stack_->exprstack->token));
+ ffebad_here (1,
+ ffelex_token_where_line (e->token),
+ ffelex_token_where_column (e->token));
+ ffebad_finish ();
+ }
+
+ ffeexpr_exprstack_push_ (e);
+}
+
+/* ffeexpr_exprstack_push_binary_ -- Push a binary operator onto the stack, reduce?
+
+ ffeexprExpr_ e;
+ ffeexpr_exprstack_push_binary_(e);
+
+ Pushes the expression already containing a binary operator after checking
+ whether reduction is possible. If the stack is not empty, the top of the
+ stack must be an operand or syntactic analysis has failed somehow. If
+ the operand is preceded by a unary operator of higher (or equal and L-R
+ associativity) precedence than the new binary operator, then reduce that
+ preceding operator and its operand(s) before pushing the new binary
+ operator. */
+
+static void
+ffeexpr_exprstack_push_binary_ (ffeexprExpr_ e)
+{
+ ffeexprExpr_ ce;
+
+ if (ffe_is_warn_surprising ()
+ /* These next two are always true (see assertions below). */
+ && (ffeexpr_stack_->exprstack != NULL)
+ && (ffeexpr_stack_->exprstack->type == FFEEXPR_exprtypeOPERAND_)
+ /* If the previous operator is a unary minus, and the binary op
+ is of higher precedence, might not do what user expects,
+ e.g. "-2**2" is "-(2**2)", i.e. "-4", not "(-2)**2", which would
+ yield "4". */
+ && (ffeexpr_stack_->exprstack->previous != NULL)
+ && (ffeexpr_stack_->exprstack->previous->type == FFEEXPR_exprtypeUNARY_)
+ && (ffeexpr_stack_->exprstack->previous->u.operator.op
+ == FFEEXPR_operatorSUBTRACT_)
+ && (e->u.operator.prec
+ < ffeexpr_stack_->exprstack->previous->u.operator.prec))
+ {
+ ffebad_start_msg ("Operator at %0 has lower precedence than that at %1 -- use parentheses", FFEBAD_severityWARNING);
+ ffebad_here (0,
+ ffelex_token_where_line (ffeexpr_stack_->exprstack->previous->token),
+ ffelex_token_where_column (ffeexpr_stack_->exprstack->previous->token));
+ ffebad_here (1,
+ ffelex_token_where_line (e->token),
+ ffelex_token_where_column (e->token));
+ ffebad_finish ();
+ }
+
+again:
+ assert (ffeexpr_stack_->exprstack != NULL);
+ assert (ffeexpr_stack_->exprstack->type == FFEEXPR_exprtypeOPERAND_);
+ if ((ce = ffeexpr_stack_->exprstack->previous) != NULL)
+ {
+ assert (ce->type != FFEEXPR_exprtypeOPERAND_);
+ if ((ce->u.operator.prec < e->u.operator.prec)
+ || ((ce->u.operator.prec == e->u.operator.prec)
+ && (e->u.operator.as == FFEEXPR_operatorassociativityL2R_)))
+ {
+ ffeexpr_reduce_ ();
+ goto again; /* :::::::::::::::::::: */
+ }
+ }
+
+ ffeexpr_exprstack_push_ (e);
+}
+
+/* ffeexpr_reduce_ -- Reduce highest operator w/operands on stack
+
+ ffeexpr_reduce_();
+
+ Converts operand binop operand or unop operand at top of stack to a
+ single operand having the appropriate ffebld expression, and makes
+ sure that the expression is proper (like not trying to add two character
+ variables, not trying to concatenate two numbers). Also does the
+ requisite type-assignment. */
+
+static void
+ffeexpr_reduce_ ()
+{
+ ffeexprExpr_ operand; /* This is B in -B or A+B. */
+ ffeexprExpr_ left_operand; /* When operator is binary, this is A in A+B. */
+ ffeexprExpr_ operator; /* This is + in A+B. */
+ ffebld reduced; /* This is +(A,B) in A+B or u-(B) in -B. */
+ ffebldConstant constnode; /* For checking magical numbers (where mag ==
+ -mag). */
+ ffebld expr;
+ ffebld left_expr;
+ bool submag = FALSE;
+
+ operand = ffeexpr_stack_->exprstack;
+ assert (operand != NULL);
+ assert (operand->type == FFEEXPR_exprtypeOPERAND_);
+ operator = operand->previous;
+ assert (operator != NULL);
+ assert (operator->type != FFEEXPR_exprtypeOPERAND_);
+ if (operator->type == FFEEXPR_exprtypeUNARY_)
+ {
+ expr = operand->u.operand;
+ switch (operator->u.operator.op)
+ {
+ case FFEEXPR_operatorADD_:
+ reduced = ffebld_new_uplus (expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly1_ (reduced, operator, operand);
+ reduced = ffeexpr_reduced_math1_ (reduced, operator, operand);
+ reduced = ffeexpr_collapse_uplus (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorSUBTRACT_:
+ submag = TRUE; /* Ok to negate a magic number. */
+ reduced = ffebld_new_uminus (expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly1_ (reduced, operator, operand);
+ reduced = ffeexpr_reduced_math1_ (reduced, operator, operand);
+ reduced = ffeexpr_collapse_uminus (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorNOT_:
+ reduced = ffebld_new_not (expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly1log_ (reduced, operator, operand);
+ reduced = ffeexpr_reduced_bool1_ (reduced, operator, operand);
+ reduced = ffeexpr_collapse_not (reduced, operator->token);
+ break;
+
+ default:
+ assert ("unexpected unary op" != NULL);
+ reduced = NULL;
+ break;
+ }
+ if (!submag
+ && (ffebld_op (expr) == FFEBLD_opCONTER)
+ && (ffebld_conter_orig (expr) == NULL)
+ && ffebld_constant_is_magical (constnode = ffebld_conter (expr)))
+ {
+ ffetarget_integer_bad_magical (operand->token);
+ }
+ ffeexpr_stack_->exprstack = operator->previous; /* Pops unary-op operand
+ off stack. */
+ ffeexpr_expr_kill_ (operand);
+ operator->type = FFEEXPR_exprtypeOPERAND_; /* Convert operator, but
+ save */
+ operator->u.operand = reduced; /* the line/column ffewhere info. */
+ ffeexpr_exprstack_push_operand_ (operator); /* Push it back on
+ stack. */
+ }
+ else
+ {
+ assert (operator->type == FFEEXPR_exprtypeBINARY_);
+ left_operand = operator->previous;
+ assert (left_operand != NULL);
+ assert (left_operand->type == FFEEXPR_exprtypeOPERAND_);
+ expr = operand->u.operand;
+ left_expr = left_operand->u.operand;
+ switch (operator->u.operator.op)
+ {
+ case FFEEXPR_operatorADD_:
+ reduced = ffebld_new_add (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_math2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_add (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorSUBTRACT_:
+ submag = TRUE; /* Just to pick the right error if magic
+ number. */
+ reduced = ffebld_new_subtract (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_math2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_subtract (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorMULTIPLY_:
+ reduced = ffebld_new_multiply (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_math2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_multiply (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorDIVIDE_:
+ reduced = ffebld_new_divide (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_math2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_divide (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorPOWER_:
+ reduced = ffebld_new_power (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_power_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_power (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorCONCATENATE_:
+ reduced = ffebld_new_concatenate (left_expr, expr);
+ reduced = ffeexpr_reduced_concatenate_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_concatenate (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorLT_:
+ reduced = ffebld_new_lt (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_relop2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_lt (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorLE_:
+ reduced = ffebld_new_le (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_relop2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_le (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorEQ_:
+ reduced = ffebld_new_eq (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_eqop2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_eq (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorNE_:
+ reduced = ffebld_new_ne (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_eqop2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_ne (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorGT_:
+ reduced = ffebld_new_gt (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_relop2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_gt (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorGE_:
+ reduced = ffebld_new_ge (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_relop2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_ge (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorAND_:
+ reduced = ffebld_new_and (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2log_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_bool2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_and (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorOR_:
+ reduced = ffebld_new_or (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2log_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_bool2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_or (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorXOR_:
+ reduced = ffebld_new_xor (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2log_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_bool2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_xor (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorEQV_:
+ reduced = ffebld_new_eqv (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2log_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_bool2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_eqv (reduced, operator->token);
+ break;
+
+ case FFEEXPR_operatorNEQV_:
+ reduced = ffebld_new_neqv (left_expr, expr);
+ if (ffe_is_ugly_logint ())
+ reduced = ffeexpr_reduced_ugly2log_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_reduced_bool2_ (reduced, left_operand, operator,
+ operand);
+ reduced = ffeexpr_collapse_neqv (reduced, operator->token);
+ break;
+
+ default:
+ assert ("bad bin op" == NULL);
+ reduced = expr;
+ break;
+ }
+ if ((ffebld_op (left_expr) == FFEBLD_opCONTER)
+ && (ffebld_conter_orig (expr) == NULL)
+ && ffebld_constant_is_magical (constnode = ffebld_conter (left_expr)))
+ {
+ if ((left_operand->previous != NULL)
+ && (left_operand->previous->type != FFEEXPR_exprtypeOPERAND_)
+ && (left_operand->previous->u.operator.op
+ == FFEEXPR_operatorSUBTRACT_))
+ {
+ if (left_operand->previous->type == FFEEXPR_exprtypeUNARY_)
+ ffetarget_integer_bad_magical_precedence (left_operand->token,
+ left_operand->previous->token,
+ operator->token);
+ else
+ ffetarget_integer_bad_magical_precedence_binary
+ (left_operand->token,
+ left_operand->previous->token,
+ operator->token);
+ }
+ else
+ ffetarget_integer_bad_magical (left_operand->token);
+ }
+ if ((ffebld_op (expr) == FFEBLD_opCONTER)
+ && (ffebld_conter_orig (expr) == NULL)
+ && ffebld_constant_is_magical (constnode = ffebld_conter (expr)))
+ {
+ if (submag)
+ ffetarget_integer_bad_magical_binary (operand->token,
+ operator->token);
+ else
+ ffetarget_integer_bad_magical (operand->token);
+ }
+ ffeexpr_stack_->exprstack = left_operand->previous; /* Pops binary-op
+ operands off stack. */
+ ffeexpr_expr_kill_ (left_operand);
+ ffeexpr_expr_kill_ (operand);
+ operator->type = FFEEXPR_exprtypeOPERAND_; /* Convert operator, but
+ save */
+ operator->u.operand = reduced; /* the line/column ffewhere info. */
+ ffeexpr_exprstack_push_operand_ (operator); /* Push it back on
+ stack. */
+ }
+}
+
+/* ffeexpr_reduced_bool1_ -- Wrap up reduction of NOT operator
+
+ reduced = ffeexpr_reduced_bool1_(reduced,op,r);
+
+ Makes sure the argument for reduced has basictype of
+ LOGICAL or (ugly) INTEGER. If
+ argument has where of CONSTANT, assign where CONSTANT to
+ reduced, else assign where FLEETING.
+
+ If these requirements cannot be met, generate error message. */
+
+static ffebld
+ffeexpr_reduced_bool1_ (ffebld reduced, ffeexprExpr_ op, ffeexprExpr_ r)
+{
+ ffeinfo rinfo, ninfo;
+ ffeinfoBasictype rbt;
+ ffeinfoKindtype rkt;
+ ffeinfoRank rrk;
+ ffeinfoKind rkd;
+ ffeinfoWhere rwh, nwh;
+
+ rinfo = ffebld_info (ffebld_left (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+
+ if (((rbt == FFEINFO_basictypeLOGICAL)
+ || (ffe_is_ugly_logint () && (rbt == FFEINFO_basictypeINTEGER)))
+ && (rrk == 0))
+ {
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ nwh = FFEINFO_whereCONSTANT;
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+
+ ninfo = ffeinfo_new (rbt, rkt, 0, FFEINFO_kindENTITY, nwh,
+ FFETARGET_charactersizeNONE);
+ ffebld_set_info (reduced, ninfo);
+ return reduced;
+ }
+
+ if ((rbt != FFEINFO_basictypeLOGICAL)
+ && (!ffe_is_ugly_logint () || (rbt != FFEINFO_basictypeINTEGER)))
+ {
+ if ((rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_NOT_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((rkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_NOT_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ return reduced;
+}
+
+/* ffeexpr_reduced_bool2_ -- Wrap up reduction of boolean operators
+
+ reduced = ffeexpr_reduced_bool2_(reduced,l,op,r);
+
+ Makes sure the left and right arguments for reduced have basictype of
+ LOGICAL or (ugly) INTEGER. Determine common basictype and
+ size for reduction (flag expression for combined hollerith/typeless
+ situations for later determination of effective basictype). If both left
+ and right arguments have where of CONSTANT, assign where CONSTANT to
+ reduced, else assign where FLEETING. Create CONVERT ops for args where
+ needed. Convert typeless
+ constants to the desired type/size explicitly.
+
+ If these requirements cannot be met, generate error message. */
+
+static ffebld
+ffeexpr_reduced_bool2_ (ffebld reduced, ffeexprExpr_ l, ffeexprExpr_ op,
+ ffeexprExpr_ r)
+{
+ ffeinfo linfo, rinfo, ninfo;
+ ffeinfoBasictype lbt, rbt, nbt;
+ ffeinfoKindtype lkt, rkt, nkt;
+ ffeinfoRank lrk, rrk;
+ ffeinfoKind lkd, rkd;
+ ffeinfoWhere lwh, rwh, nwh;
+
+ linfo = ffebld_info (ffebld_left (reduced));
+ lbt = ffeinfo_basictype (linfo);
+ lkt = ffeinfo_kindtype (linfo);
+ lrk = ffeinfo_rank (linfo);
+ lkd = ffeinfo_kind (linfo);
+ lwh = ffeinfo_where (linfo);
+
+ rinfo = ffebld_info (ffebld_right (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+
+ ffeexpr_type_combine (&nbt, &nkt, lbt, lkt, rbt, rkt, op->token);
+
+ if (((nbt == FFEINFO_basictypeLOGICAL)
+ || (ffe_is_ugly_logint () && (nbt == FFEINFO_basictypeINTEGER)))
+ && (lrk == 0) && (rrk == 0))
+ {
+ switch (lwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ nwh = FFEINFO_whereCONSTANT;
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+
+ ninfo = ffeinfo_new (nbt, nkt, 0, FFEINFO_kindENTITY, nwh,
+ FFETARGET_charactersizeNONE);
+ ffebld_set_info (reduced, ninfo);
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ l->token, op->token, nbt, nkt, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ ffebld_set_right (reduced, ffeexpr_convert (ffebld_right (reduced),
+ r->token, op->token, nbt, nkt, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ return reduced;
+ }
+
+ if ((lbt != FFEINFO_basictypeLOGICAL)
+ && (!ffe_is_ugly_logint () || (lbt != FFEINFO_basictypeINTEGER)))
+ {
+ if ((rbt != FFEINFO_basictypeLOGICAL)
+ && (!ffe_is_ugly_logint () || (rbt != FFEINFO_basictypeINTEGER)))
+ {
+ if ((lbt != FFEINFO_basictypeANY) && (rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_BOOL_ARGS_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_here (2, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((lbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_BOOL_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_finish ();
+ }
+ }
+ }
+ else if ((rbt != FFEINFO_basictypeLOGICAL)
+ && (!ffe_is_ugly_logint () || (rbt != FFEINFO_basictypeINTEGER)))
+ {
+ if ((rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_BOOL_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else if (lrk != 0)
+ {
+ if ((lkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_BOOL_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((rkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_BOOL_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ return reduced;
+}
+
+/* ffeexpr_reduced_concatenate_ -- Wrap up reduction of concatenate operator
+
+ reduced = ffeexpr_reduced_concatenate_(reduced,l,op,r);
+
+ Makes sure the left and right arguments for reduced have basictype of
+ CHARACTER and kind of SCALAR, FUNCTION, or STATEMENT FUNCTION. Assign
+ basictype of CHARACTER and kind of SCALAR to reduced. Calculate effective
+ size of concatenation and assign that size to reduced. If both left and
+ right arguments have where of CONSTANT, assign where CONSTANT to reduced,
+ else assign where FLEETING.
+
+ If these requirements cannot be met, generate error message using the
+ info in l, op, and r arguments and assign basictype, size, kind, and where
+ of ANY. */
+
+static ffebld
+ffeexpr_reduced_concatenate_ (ffebld reduced, ffeexprExpr_ l, ffeexprExpr_ op,
+ ffeexprExpr_ r)
+{
+ ffeinfo linfo, rinfo, ninfo;
+ ffeinfoBasictype lbt, rbt, nbt;
+ ffeinfoKindtype lkt, rkt, nkt;
+ ffeinfoRank lrk, rrk;
+ ffeinfoKind lkd, rkd, nkd;
+ ffeinfoWhere lwh, rwh, nwh;
+ ffetargetCharacterSize lszm, lszk, rszm, rszk, nszk;
+
+ linfo = ffebld_info (ffebld_left (reduced));
+ lbt = ffeinfo_basictype (linfo);
+ lkt = ffeinfo_kindtype (linfo);
+ lrk = ffeinfo_rank (linfo);
+ lkd = ffeinfo_kind (linfo);
+ lwh = ffeinfo_where (linfo);
+ lszk = ffeinfo_size (linfo); /* Known size. */
+ lszm = ffebld_size_max (ffebld_left (reduced));
+
+ rinfo = ffebld_info (ffebld_right (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+ rszk = ffeinfo_size (rinfo); /* Known size. */
+ rszm = ffebld_size_max (ffebld_right (reduced));
+
+ if ((lbt == FFEINFO_basictypeCHARACTER) && (rbt == FFEINFO_basictypeCHARACTER)
+ && (lkt == rkt) && (lrk == 0) && (rrk == 0)
+ && (((lszm != FFETARGET_charactersizeNONE)
+ && (rszm != FFETARGET_charactersizeNONE))
+ || (ffeexpr_context_outer_ (ffeexpr_stack_)
+ == FFEEXPR_contextLET)
+ || (ffeexpr_context_outer_ (ffeexpr_stack_)
+ == FFEEXPR_contextSFUNCDEF)))
+ {
+ nbt = FFEINFO_basictypeCHARACTER;
+ nkd = FFEINFO_kindENTITY;
+ if ((lszk == FFETARGET_charactersizeNONE)
+ || (rszk == FFETARGET_charactersizeNONE))
+ nszk = FFETARGET_charactersizeNONE; /* Ok only in rhs of LET
+ stmt. */
+ else
+ nszk = lszk + rszk;
+
+ switch (lwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ nwh = FFEINFO_whereCONSTANT;
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+
+ nkt = lkt;
+ ninfo = ffeinfo_new (nbt, nkt, 0, nkd, nwh, nszk);
+ ffebld_set_info (reduced, ninfo);
+ return reduced;
+ }
+
+ if ((lbt != FFEINFO_basictypeCHARACTER) && (rbt != FFEINFO_basictypeCHARACTER))
+ {
+ if ((lbt != FFEINFO_basictypeANY) && (rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_CONCAT_ARGS_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_here (2, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else if (lbt != FFEINFO_basictypeCHARACTER)
+ {
+ if ((lbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_CONCAT_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_finish ();
+ }
+ }
+ else if (rbt != FFEINFO_basictypeCHARACTER)
+ {
+ if ((rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_CONCAT_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else if ((lrk != 0) || (lszm == FFETARGET_charactersizeNONE))
+ {
+ if ((lkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_CONCAT_ARG_KIND))
+ {
+ char *what;
+
+ if (lrk != 0)
+ what = "an array";
+ else
+ what = "of indeterminate length";
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_string (what);
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if (ffebad_start (FFEBAD_CONCAT_ARG_KIND))
+ {
+ char *what;
+
+ if (rrk != 0)
+ what = "an array";
+ else
+ what = "of indeterminate length";
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_string (what);
+ ffebad_finish ();
+ }
+ }
+
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ return reduced;
+}
+
+/* ffeexpr_reduced_eqop2_ -- Wrap up reduction of EQ and NE operators
+
+ reduced = ffeexpr_reduced_eqop2_(reduced,l,op,r);
+
+ Makes sure the left and right arguments for reduced have basictype of
+ INTEGER, REAL, COMPLEX, or CHARACTER. Determine common basictype and
+ size for reduction. If both left
+ and right arguments have where of CONSTANT, assign where CONSTANT to
+ reduced, else assign where FLEETING. Create CONVERT ops for args where
+ needed. Convert typeless
+ constants to the desired type/size explicitly.
+
+ If these requirements cannot be met, generate error message. */
+
+static ffebld
+ffeexpr_reduced_eqop2_ (ffebld reduced, ffeexprExpr_ l, ffeexprExpr_ op,
+ ffeexprExpr_ r)
+{
+ ffeinfo linfo, rinfo, ninfo;
+ ffeinfoBasictype lbt, rbt, nbt;
+ ffeinfoKindtype lkt, rkt, nkt;
+ ffeinfoRank lrk, rrk;
+ ffeinfoKind lkd, rkd;
+ ffeinfoWhere lwh, rwh, nwh;
+ ffetargetCharacterSize lsz, rsz;
+
+ linfo = ffebld_info (ffebld_left (reduced));
+ lbt = ffeinfo_basictype (linfo);
+ lkt = ffeinfo_kindtype (linfo);
+ lrk = ffeinfo_rank (linfo);
+ lkd = ffeinfo_kind (linfo);
+ lwh = ffeinfo_where (linfo);
+ lsz = ffebld_size_known (ffebld_left (reduced));
+
+ rinfo = ffebld_info (ffebld_right (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+ rsz = ffebld_size_known (ffebld_right (reduced));
+
+ ffeexpr_type_combine (&nbt, &nkt, lbt, lkt, rbt, rkt, op->token);
+
+ if (((nbt == FFEINFO_basictypeINTEGER) || (nbt == FFEINFO_basictypeREAL)
+ || (nbt == FFEINFO_basictypeCOMPLEX) || (nbt == FFEINFO_basictypeCHARACTER))
+ && (lrk == 0) && (rrk == 0))
+ {
+ switch (lwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ nwh = FFEINFO_whereCONSTANT;
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+
+ if ((lsz != FFETARGET_charactersizeNONE)
+ && (rsz != FFETARGET_charactersizeNONE))
+ lsz = rsz = (lsz > rsz) ? lsz : rsz;
+
+ ninfo = ffeinfo_new (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICALDEFAULT,
+ 0, FFEINFO_kindENTITY, nwh, FFETARGET_charactersizeNONE);
+ ffebld_set_info (reduced, ninfo);
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ l->token, op->token, nbt, nkt, 0, lsz,
+ FFEEXPR_contextLET));
+ ffebld_set_right (reduced, ffeexpr_convert (ffebld_right (reduced),
+ r->token, op->token, nbt, nkt, 0, rsz,
+ FFEEXPR_contextLET));
+ return reduced;
+ }
+
+ if ((lbt == FFEINFO_basictypeLOGICAL)
+ && (rbt == FFEINFO_basictypeLOGICAL))
+ {
+ if (ffebad_start_msg ("Use .EQV./.NEQV. instead of .EQ./.NE. at %0 for LOGICAL operands at %1 and %2",
+ FFEBAD_severityFATAL))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_here (2, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else if ((lbt != FFEINFO_basictypeINTEGER) && (lbt != FFEINFO_basictypeREAL)
+ && (lbt != FFEINFO_basictypeCOMPLEX) && (lbt != FFEINFO_basictypeCHARACTER))
+ {
+ if ((rbt != FFEINFO_basictypeINTEGER) && (rbt != FFEINFO_basictypeREAL)
+ && (rbt != FFEINFO_basictypeCOMPLEX) && (rbt != FFEINFO_basictypeCHARACTER))
+ {
+ if ((lbt != FFEINFO_basictypeANY) && (rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_EQOP_ARGS_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_here (2, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((lbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_EQOP_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_finish ();
+ }
+ }
+ }
+ else if ((rbt != FFEINFO_basictypeINTEGER) && (rbt != FFEINFO_basictypeREAL)
+ && (rbt != FFEINFO_basictypeCOMPLEX) && (rbt != FFEINFO_basictypeCHARACTER))
+ {
+ if ((rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_EQOP_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else if (lrk != 0)
+ {
+ if ((lkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_EQOP_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((rkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_EQOP_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ return reduced;
+}
+
+/* ffeexpr_reduced_math1_ -- Wrap up reduction of + - unary operators
+
+ reduced = ffeexpr_reduced_math1_(reduced,op,r);
+
+ Makes sure the argument for reduced has basictype of
+ INTEGER, REAL, or COMPLEX. If the argument has where of CONSTANT,
+ assign where CONSTANT to
+ reduced, else assign where FLEETING.
+
+ If these requirements cannot be met, generate error message. */
+
+static ffebld
+ffeexpr_reduced_math1_ (ffebld reduced, ffeexprExpr_ op, ffeexprExpr_ r)
+{
+ ffeinfo rinfo, ninfo;
+ ffeinfoBasictype rbt;
+ ffeinfoKindtype rkt;
+ ffeinfoRank rrk;
+ ffeinfoKind rkd;
+ ffeinfoWhere rwh, nwh;
+
+ rinfo = ffebld_info (ffebld_left (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+
+ if (((rbt == FFEINFO_basictypeINTEGER) || (rbt == FFEINFO_basictypeREAL)
+ || (rbt == FFEINFO_basictypeCOMPLEX)) && (rrk == 0))
+ {
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ nwh = FFEINFO_whereCONSTANT;
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+
+ ninfo = ffeinfo_new (rbt, rkt, 0, FFEINFO_kindENTITY, nwh,
+ FFETARGET_charactersizeNONE);
+ ffebld_set_info (reduced, ninfo);
+ return reduced;
+ }
+
+ if ((rbt != FFEINFO_basictypeINTEGER) && (rbt != FFEINFO_basictypeREAL)
+ && (rbt != FFEINFO_basictypeCOMPLEX))
+ {
+ if ((rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_MATH_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((rkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_MATH_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ return reduced;
+}
+
+/* ffeexpr_reduced_math2_ -- Wrap up reduction of + - * / operators
+
+ reduced = ffeexpr_reduced_math2_(reduced,l,op,r);
+
+ Makes sure the left and right arguments for reduced have basictype of
+ INTEGER, REAL, or COMPLEX. Determine common basictype and
+ size for reduction (flag expression for combined hollerith/typeless
+ situations for later determination of effective basictype). If both left
+ and right arguments have where of CONSTANT, assign where CONSTANT to
+ reduced, else assign where FLEETING. Create CONVERT ops for args where
+ needed. Convert typeless
+ constants to the desired type/size explicitly.
+
+ If these requirements cannot be met, generate error message. */
+
+static ffebld
+ffeexpr_reduced_math2_ (ffebld reduced, ffeexprExpr_ l, ffeexprExpr_ op,
+ ffeexprExpr_ r)
+{
+ ffeinfo linfo, rinfo, ninfo;
+ ffeinfoBasictype lbt, rbt, nbt;
+ ffeinfoKindtype lkt, rkt, nkt;
+ ffeinfoRank lrk, rrk;
+ ffeinfoKind lkd, rkd;
+ ffeinfoWhere lwh, rwh, nwh;
+
+ linfo = ffebld_info (ffebld_left (reduced));
+ lbt = ffeinfo_basictype (linfo);
+ lkt = ffeinfo_kindtype (linfo);
+ lrk = ffeinfo_rank (linfo);
+ lkd = ffeinfo_kind (linfo);
+ lwh = ffeinfo_where (linfo);
+
+ rinfo = ffebld_info (ffebld_right (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+
+ ffeexpr_type_combine (&nbt, &nkt, lbt, lkt, rbt, rkt, op->token);
+
+ if (((nbt == FFEINFO_basictypeINTEGER) || (nbt == FFEINFO_basictypeREAL)
+ || (nbt == FFEINFO_basictypeCOMPLEX)) && (lrk == 0) && (rrk == 0))
+ {
+ switch (lwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ nwh = FFEINFO_whereCONSTANT;
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+
+ ninfo = ffeinfo_new (nbt, nkt, 0, FFEINFO_kindENTITY, nwh,
+ FFETARGET_charactersizeNONE);
+ ffebld_set_info (reduced, ninfo);
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ l->token, op->token, nbt, nkt, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ ffebld_set_right (reduced, ffeexpr_convert (ffebld_right (reduced),
+ r->token, op->token, nbt, nkt, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ return reduced;
+ }
+
+ if ((lbt != FFEINFO_basictypeINTEGER) && (lbt != FFEINFO_basictypeREAL)
+ && (lbt != FFEINFO_basictypeCOMPLEX))
+ {
+ if ((rbt != FFEINFO_basictypeINTEGER)
+ && (rbt != FFEINFO_basictypeREAL) && (rbt != FFEINFO_basictypeCOMPLEX))
+ {
+ if ((lbt != FFEINFO_basictypeANY) && (rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_MATH_ARGS_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_here (2, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((lbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_MATH_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_finish ();
+ }
+ }
+ }
+ else if ((rbt != FFEINFO_basictypeINTEGER) && (rbt != FFEINFO_basictypeREAL)
+ && (rbt != FFEINFO_basictypeCOMPLEX))
+ {
+ if ((rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_MATH_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else if (lrk != 0)
+ {
+ if ((lkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_MATH_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((rkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_MATH_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ return reduced;
+}
+
+/* ffeexpr_reduced_power_ -- Wrap up reduction of ** operator
+
+ reduced = ffeexpr_reduced_power_(reduced,l,op,r);
+
+ Makes sure the left and right arguments for reduced have basictype of
+ INTEGER, REAL, or COMPLEX. Determine common basictype and
+ size for reduction (flag expression for combined hollerith/typeless
+ situations for later determination of effective basictype). If both left
+ and right arguments have where of CONSTANT, assign where CONSTANT to
+ reduced, else assign where FLEETING. Create CONVERT ops for args where
+ needed. Note that real**int or complex**int
+ comes out as int = real**int etc with no conversions.
+
+ If these requirements cannot be met, generate error message using the
+ info in l, op, and r arguments and assign basictype, size, kind, and where
+ of ANY. */
+
+static ffebld
+ffeexpr_reduced_power_ (ffebld reduced, ffeexprExpr_ l, ffeexprExpr_ op,
+ ffeexprExpr_ r)
+{
+ ffeinfo linfo, rinfo, ninfo;
+ ffeinfoBasictype lbt, rbt, nbt;
+ ffeinfoKindtype lkt, rkt, nkt;
+ ffeinfoRank lrk, rrk;
+ ffeinfoKind lkd, rkd;
+ ffeinfoWhere lwh, rwh, nwh;
+
+ linfo = ffebld_info (ffebld_left (reduced));
+ lbt = ffeinfo_basictype (linfo);
+ lkt = ffeinfo_kindtype (linfo);
+ lrk = ffeinfo_rank (linfo);
+ lkd = ffeinfo_kind (linfo);
+ lwh = ffeinfo_where (linfo);
+
+ rinfo = ffebld_info (ffebld_right (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+
+ if ((rbt == FFEINFO_basictypeINTEGER)
+ && ((lbt == FFEINFO_basictypeREAL)
+ || (lbt == FFEINFO_basictypeCOMPLEX)))
+ {
+ nbt = lbt;
+ nkt = ffeinfo_kindtype_max (nbt, lkt, FFEINFO_kindtypeREALDEFAULT);
+ if (nkt != FFEINFO_kindtypeREALDEFAULT)
+ {
+ nkt = ffeinfo_kindtype_max (nbt, lkt, FFEINFO_kindtypeREALDOUBLE);
+ if (nkt != FFEINFO_kindtypeREALDOUBLE)
+ nkt = FFEINFO_kindtypeREALDOUBLE; /* Highest kt we can power! */
+ }
+ if (rkt == FFEINFO_kindtypeINTEGER4)
+ {
+ ffebad_start_msg ("Unsupported operand for ** at %1 -- converting to default INTEGER",
+ FFEBAD_severityWARNING);
+ ffebad_here (0, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ if (rkt != FFEINFO_kindtypeINTEGERDEFAULT)
+ {
+ ffebld_set_right (reduced, ffeexpr_convert (ffebld_right (reduced),
+ r->token, op->token,
+ FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGERDEFAULT, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ rkt = FFEINFO_kindtypeINTEGERDEFAULT;
+ }
+ }
+ else
+ {
+ ffeexpr_type_combine (&nbt, &nkt, lbt, lkt, rbt, rkt, op->token);
+
+#if 0 /* INTEGER4**INTEGER4 works now. */
+ if ((nbt == FFEINFO_basictypeINTEGER)
+ && (nkt != FFEINFO_kindtypeINTEGERDEFAULT))
+ nkt = FFEINFO_kindtypeINTEGERDEFAULT; /* Highest kt we can power! */
+#endif
+ if (((nbt == FFEINFO_basictypeREAL)
+ || (nbt == FFEINFO_basictypeCOMPLEX))
+ && (nkt != FFEINFO_kindtypeREALDEFAULT))
+ {
+ nkt = ffeinfo_kindtype_max (nbt, nkt, FFEINFO_kindtypeREALDOUBLE);
+ if (nkt != FFEINFO_kindtypeREALDOUBLE)
+ nkt = FFEINFO_kindtypeREALDOUBLE; /* Highest kt we can power! */
+ }
+ /* else Gonna turn into an error below. */
+ }
+
+ if (((nbt == FFEINFO_basictypeINTEGER) || (nbt == FFEINFO_basictypeREAL)
+ || (nbt == FFEINFO_basictypeCOMPLEX)) && (lrk == 0) && (rrk == 0))
+ {
+ switch (lwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ nwh = FFEINFO_whereCONSTANT;
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+
+ ninfo = ffeinfo_new (nbt, nkt, 0, FFEINFO_kindENTITY, nwh,
+ FFETARGET_charactersizeNONE);
+ ffebld_set_info (reduced, ninfo);
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ l->token, op->token, nbt, nkt, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ if (rbt != FFEINFO_basictypeINTEGER)
+ ffebld_set_right (reduced, ffeexpr_convert (ffebld_right (reduced),
+ r->token, op->token, nbt, nkt, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ return reduced;
+ }
+
+ if ((lbt != FFEINFO_basictypeINTEGER) && (lbt != FFEINFO_basictypeREAL)
+ && (lbt != FFEINFO_basictypeCOMPLEX))
+ {
+ if ((rbt != FFEINFO_basictypeINTEGER)
+ && (rbt != FFEINFO_basictypeREAL) && (rbt != FFEINFO_basictypeCOMPLEX))
+ {
+ if ((lbt != FFEINFO_basictypeANY) && (rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_MATH_ARGS_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_here (2, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((lbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_MATH_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_finish ();
+ }
+ }
+ }
+ else if ((rbt != FFEINFO_basictypeINTEGER) && (rbt != FFEINFO_basictypeREAL)
+ && (rbt != FFEINFO_basictypeCOMPLEX))
+ {
+ if ((rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_MATH_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else if (lrk != 0)
+ {
+ if ((lkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_MATH_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((rkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_MATH_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ return reduced;
+}
+
+/* ffeexpr_reduced_relop2_ -- Wrap up reduction of LT, LE, GE, and GT operators
+
+ reduced = ffeexpr_reduced_relop2_(reduced,l,op,r);
+
+ Makes sure the left and right arguments for reduced have basictype of
+ INTEGER, REAL, or CHARACTER. Determine common basictype and
+ size for reduction. If both left
+ and right arguments have where of CONSTANT, assign where CONSTANT to
+ reduced, else assign where FLEETING. Create CONVERT ops for args where
+ needed. Convert typeless
+ constants to the desired type/size explicitly.
+
+ If these requirements cannot be met, generate error message. */
+
+static ffebld
+ffeexpr_reduced_relop2_ (ffebld reduced, ffeexprExpr_ l, ffeexprExpr_ op,
+ ffeexprExpr_ r)
+{
+ ffeinfo linfo, rinfo, ninfo;
+ ffeinfoBasictype lbt, rbt, nbt;
+ ffeinfoKindtype lkt, rkt, nkt;
+ ffeinfoRank lrk, rrk;
+ ffeinfoKind lkd, rkd;
+ ffeinfoWhere lwh, rwh, nwh;
+ ffetargetCharacterSize lsz, rsz;
+
+ linfo = ffebld_info (ffebld_left (reduced));
+ lbt = ffeinfo_basictype (linfo);
+ lkt = ffeinfo_kindtype (linfo);
+ lrk = ffeinfo_rank (linfo);
+ lkd = ffeinfo_kind (linfo);
+ lwh = ffeinfo_where (linfo);
+ lsz = ffebld_size_known (ffebld_left (reduced));
+
+ rinfo = ffebld_info (ffebld_right (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+ rsz = ffebld_size_known (ffebld_right (reduced));
+
+ ffeexpr_type_combine (&nbt, &nkt, lbt, lkt, rbt, rkt, op->token);
+
+ if (((nbt == FFEINFO_basictypeINTEGER) || (nbt == FFEINFO_basictypeREAL)
+ || (nbt == FFEINFO_basictypeCHARACTER))
+ && (lrk == 0) && (rrk == 0))
+ {
+ switch (lwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ nwh = FFEINFO_whereCONSTANT;
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereIMMEDIATE:
+ nwh = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ default:
+ nwh = FFEINFO_whereFLEETING;
+ break;
+ }
+
+ if ((lsz != FFETARGET_charactersizeNONE)
+ && (rsz != FFETARGET_charactersizeNONE))
+ lsz = rsz = (lsz > rsz) ? lsz : rsz;
+
+ ninfo = ffeinfo_new (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICALDEFAULT,
+ 0, FFEINFO_kindENTITY, nwh, FFETARGET_charactersizeNONE);
+ ffebld_set_info (reduced, ninfo);
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ l->token, op->token, nbt, nkt, 0, lsz,
+ FFEEXPR_contextLET));
+ ffebld_set_right (reduced, ffeexpr_convert (ffebld_right (reduced),
+ r->token, op->token, nbt, nkt, 0, rsz,
+ FFEEXPR_contextLET));
+ return reduced;
+ }
+
+ if ((lbt != FFEINFO_basictypeINTEGER) && (lbt != FFEINFO_basictypeREAL)
+ && (lbt != FFEINFO_basictypeCHARACTER))
+ {
+ if ((rbt != FFEINFO_basictypeINTEGER) && (rbt != FFEINFO_basictypeREAL)
+ && (rbt != FFEINFO_basictypeCHARACTER))
+ {
+ if ((lbt != FFEINFO_basictypeANY) && (rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_RELOP_ARGS_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_here (2, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((lbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_RELOP_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_finish ();
+ }
+ }
+ }
+ else if ((rbt != FFEINFO_basictypeINTEGER) && (rbt != FFEINFO_basictypeREAL)
+ && (rbt != FFEINFO_basictypeCHARACTER))
+ {
+ if ((rbt != FFEINFO_basictypeANY)
+ && ffebad_start (FFEBAD_RELOP_ARG_TYPE))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_finish ();
+ }
+ }
+ else if (lrk != 0)
+ {
+ if ((lkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_RELOP_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (l->token), ffelex_token_where_column (l->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if ((rkd != FFEINFO_kindANY)
+ && ffebad_start (FFEBAD_RELOP_ARG_KIND))
+ {
+ ffebad_here (0, ffelex_token_where_line (op->token), ffelex_token_where_column (op->token));
+ ffebad_here (1, ffelex_token_where_line (r->token), ffelex_token_where_column (r->token));
+ ffebad_string ("an array");
+ ffebad_finish ();
+ }
+ }
+
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ return reduced;
+}
+
+/* ffeexpr_reduced_ugly1_ -- Deal with TYPELESS, HOLLERITH, and LOGICAL
+
+ reduced = ffeexpr_reduced_ugly1_(reduced,op,r);
+
+ Sigh. */
+
+static ffebld
+ffeexpr_reduced_ugly1_ (ffebld reduced, ffeexprExpr_ op, ffeexprExpr_ r)
+{
+ ffeinfo rinfo;
+ ffeinfoBasictype rbt;
+ ffeinfoKindtype rkt;
+ ffeinfoRank rrk;
+ ffeinfoKind rkd;
+ ffeinfoWhere rwh;
+
+ rinfo = ffebld_info (ffebld_left (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+
+ if ((rbt == FFEINFO_basictypeTYPELESS)
+ || (rbt == FFEINFO_basictypeHOLLERITH))
+ {
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ r->token, op->token, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ rinfo = ffebld_info (ffebld_left (reduced));
+ rbt = FFEINFO_basictypeINTEGER;
+ rkt = FFEINFO_kindtypeINTEGERDEFAULT;
+ rrk = 0;
+ rkd = FFEINFO_kindENTITY;
+ rwh = ffeinfo_where (rinfo);
+ }
+
+ if (rbt == FFEINFO_basictypeLOGICAL)
+ {
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ r->token, op->token, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ }
+
+ return reduced;
+}
+
+/* ffeexpr_reduced_ugly1log_ -- Deal with TYPELESS and HOLLERITH
+
+ reduced = ffeexpr_reduced_ugly1log_(reduced,op,r);
+
+ Sigh. */
+
+static ffebld
+ffeexpr_reduced_ugly1log_ (ffebld reduced, ffeexprExpr_ op, ffeexprExpr_ r)
+{
+ ffeinfo rinfo;
+ ffeinfoBasictype rbt;
+ ffeinfoKindtype rkt;
+ ffeinfoRank rrk;
+ ffeinfoKind rkd;
+ ffeinfoWhere rwh;
+
+ rinfo = ffebld_info (ffebld_left (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+
+ if ((rbt == FFEINFO_basictypeTYPELESS)
+ || (rbt == FFEINFO_basictypeHOLLERITH))
+ {
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ r->token, op->token, FFEINFO_basictypeLOGICAL, 0,
+ FFEINFO_kindtypeLOGICALDEFAULT,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ rinfo = ffebld_info (ffebld_left (reduced));
+ rbt = FFEINFO_basictypeLOGICAL;
+ rkt = FFEINFO_kindtypeLOGICALDEFAULT;
+ rrk = 0;
+ rkd = FFEINFO_kindENTITY;
+ rwh = ffeinfo_where (rinfo);
+ }
+
+ return reduced;
+}
+
+/* ffeexpr_reduced_ugly2_ -- Deal with TYPELESS, HOLLERITH, and LOGICAL
+
+ reduced = ffeexpr_reduced_ugly2_(reduced,l,op,r);
+
+ Sigh. */
+
+static ffebld
+ffeexpr_reduced_ugly2_ (ffebld reduced, ffeexprExpr_ l, ffeexprExpr_ op,
+ ffeexprExpr_ r)
+{
+ ffeinfo linfo, rinfo;
+ ffeinfoBasictype lbt, rbt;
+ ffeinfoKindtype lkt, rkt;
+ ffeinfoRank lrk, rrk;
+ ffeinfoKind lkd, rkd;
+ ffeinfoWhere lwh, rwh;
+
+ linfo = ffebld_info (ffebld_left (reduced));
+ lbt = ffeinfo_basictype (linfo);
+ lkt = ffeinfo_kindtype (linfo);
+ lrk = ffeinfo_rank (linfo);
+ lkd = ffeinfo_kind (linfo);
+ lwh = ffeinfo_where (linfo);
+
+ rinfo = ffebld_info (ffebld_right (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+
+ if ((lbt == FFEINFO_basictypeTYPELESS)
+ || (lbt == FFEINFO_basictypeHOLLERITH))
+ {
+ if ((rbt == FFEINFO_basictypeTYPELESS)
+ || (rbt == FFEINFO_basictypeHOLLERITH))
+ {
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ l->token, op->token, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ ffebld_set_right (reduced, ffeexpr_convert (ffebld_right (reduced),
+ r->token, op->token, FFEINFO_basictypeINTEGER, 0,
+ FFEINFO_kindtypeINTEGERDEFAULT,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ linfo = ffebld_info (ffebld_left (reduced));
+ rinfo = ffebld_info (ffebld_right (reduced));
+ lbt = rbt = FFEINFO_basictypeINTEGER;
+ lkt = rkt = FFEINFO_kindtypeINTEGERDEFAULT;
+ lrk = rrk = 0;
+ lkd = rkd = FFEINFO_kindENTITY;
+ lwh = ffeinfo_where (linfo);
+ rwh = ffeinfo_where (rinfo);
+ }
+ else
+ {
+ ffebld_set_left (reduced, ffeexpr_convert_expr (ffebld_left (reduced),
+ l->token, ffebld_right (reduced), r->token,
+ FFEEXPR_contextLET));
+ linfo = ffebld_info (ffebld_left (reduced));
+ lbt = ffeinfo_basictype (linfo);
+ lkt = ffeinfo_kindtype (linfo);
+ lrk = ffeinfo_rank (linfo);
+ lkd = ffeinfo_kind (linfo);
+ lwh = ffeinfo_where (linfo);
+ }
+ }
+ else
+ {
+ if ((rbt == FFEINFO_basictypeTYPELESS)
+ || (rbt == FFEINFO_basictypeHOLLERITH))
+ {
+ ffebld_set_right (reduced, ffeexpr_convert_expr (ffebld_right (reduced),
+ r->token, ffebld_left (reduced), l->token,
+ FFEEXPR_contextLET));
+ rinfo = ffebld_info (ffebld_right (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+ }
+ /* else Leave it alone. */
+ }
+
+ if (lbt == FFEINFO_basictypeLOGICAL)
+ {
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ l->token, op->token, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ }
+
+ if (rbt == FFEINFO_basictypeLOGICAL)
+ {
+ ffebld_set_right (reduced, ffeexpr_convert (ffebld_right (reduced),
+ r->token, op->token, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ }
+
+ return reduced;
+}
+
+/* ffeexpr_reduced_ugly2log_ -- Deal with TYPELESS and HOLLERITH
+
+ reduced = ffeexpr_reduced_ugly2log_(reduced,l,op,r);
+
+ Sigh. */
+
+static ffebld
+ffeexpr_reduced_ugly2log_ (ffebld reduced, ffeexprExpr_ l, ffeexprExpr_ op,
+ ffeexprExpr_ r)
+{
+ ffeinfo linfo, rinfo;
+ ffeinfoBasictype lbt, rbt;
+ ffeinfoKindtype lkt, rkt;
+ ffeinfoRank lrk, rrk;
+ ffeinfoKind lkd, rkd;
+ ffeinfoWhere lwh, rwh;
+
+ linfo = ffebld_info (ffebld_left (reduced));
+ lbt = ffeinfo_basictype (linfo);
+ lkt = ffeinfo_kindtype (linfo);
+ lrk = ffeinfo_rank (linfo);
+ lkd = ffeinfo_kind (linfo);
+ lwh = ffeinfo_where (linfo);
+
+ rinfo = ffebld_info (ffebld_right (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+
+ if ((lbt == FFEINFO_basictypeTYPELESS)
+ || (lbt == FFEINFO_basictypeHOLLERITH))
+ {
+ if ((rbt == FFEINFO_basictypeTYPELESS)
+ || (rbt == FFEINFO_basictypeHOLLERITH))
+ {
+ ffebld_set_left (reduced, ffeexpr_convert (ffebld_left (reduced),
+ l->token, op->token, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ ffebld_set_right (reduced, ffeexpr_convert (ffebld_right (reduced),
+ r->token, op->token, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET));
+ linfo = ffebld_info (ffebld_left (reduced));
+ rinfo = ffebld_info (ffebld_right (reduced));
+ lbt = rbt = FFEINFO_basictypeLOGICAL;
+ lkt = rkt = FFEINFO_kindtypeLOGICALDEFAULT;
+ lrk = rrk = 0;
+ lkd = rkd = FFEINFO_kindENTITY;
+ lwh = ffeinfo_where (linfo);
+ rwh = ffeinfo_where (rinfo);
+ }
+ else
+ {
+ ffebld_set_left (reduced, ffeexpr_convert_expr (ffebld_left (reduced),
+ l->token, ffebld_right (reduced), r->token,
+ FFEEXPR_contextLET));
+ linfo = ffebld_info (ffebld_left (reduced));
+ lbt = ffeinfo_basictype (linfo);
+ lkt = ffeinfo_kindtype (linfo);
+ lrk = ffeinfo_rank (linfo);
+ lkd = ffeinfo_kind (linfo);
+ lwh = ffeinfo_where (linfo);
+ }
+ }
+ else
+ {
+ if ((rbt == FFEINFO_basictypeTYPELESS)
+ || (rbt == FFEINFO_basictypeHOLLERITH))
+ {
+ ffebld_set_right (reduced, ffeexpr_convert_expr (ffebld_right (reduced),
+ r->token, ffebld_left (reduced), l->token,
+ FFEEXPR_contextLET));
+ rinfo = ffebld_info (ffebld_right (reduced));
+ rbt = ffeinfo_basictype (rinfo);
+ rkt = ffeinfo_kindtype (rinfo);
+ rrk = ffeinfo_rank (rinfo);
+ rkd = ffeinfo_kind (rinfo);
+ rwh = ffeinfo_where (rinfo);
+ }
+ /* else Leave it alone. */
+ }
+
+ return reduced;
+}
+
+/* Fumble through tokens until a nonmatching CLOSE_PAREN, EOS, or SEMICOLON
+ is found.
+
+ The idea is to process the tokens as they would be done by normal
+ expression processing, with the key things being telling the lexer
+ when hollerith/character constants are about to happen, until the
+ true closing token is found. */
+
+static ffelexHandler
+ffeexpr_find_close_paren_ (ffelexToken t,
+ ffelexHandler after)
+{
+ ffeexpr_find_.after = after;
+ ffeexpr_find_.level = 1;
+ return (ffelexHandler) ffeexpr_nil_rhs_ (t);
+}
+
+static ffelexHandler
+ffeexpr_nil_finished_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (--ffeexpr_find_.level == 0)
+ return (ffelexHandler) ffeexpr_find_.after;
+ return (ffelexHandler) ffeexpr_nil_binary_;
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLON:
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+
+ default:
+ if (--ffeexpr_find_.level == 0)
+ return (ffelexHandler) ffeexpr_find_.after (t);
+ return (ffelexHandler) ffeexpr_nil_rhs_ (t);
+ }
+}
+
+static ffelexHandler
+ffeexpr_nil_rhs_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeQUOTE:
+ if (ffe_is_vxt ())
+ return (ffelexHandler) ffeexpr_nil_quote_;
+ ffelex_set_expecting_hollerith (-1, '\"',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ return (ffelexHandler) ffeexpr_nil_apostrophe_;
+
+ case FFELEX_typeAPOSTROPHE:
+ ffelex_set_expecting_hollerith (-1, '\'',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ return (ffelexHandler) ffeexpr_nil_apostrophe_;
+
+ case FFELEX_typePERCENT:
+ return (ffelexHandler) ffeexpr_nil_percent_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ++ffeexpr_find_.level;
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+
+ case FFELEX_typePLUS:
+ case FFELEX_typeMINUS:
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+
+ case FFELEX_typePERIOD:
+ return (ffelexHandler) ffeexpr_nil_period_;
+
+ case FFELEX_typeNUMBER:
+ ffeexpr_hollerith_count_ = atol (ffelex_token_text (t));
+ if (ffeexpr_hollerith_count_ > 0)
+ ffelex_set_expecting_hollerith (ffeexpr_hollerith_count_,
+ '\0',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ return (ffelexHandler) ffeexpr_nil_number_;
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ return (ffelexHandler) ffeexpr_nil_name_rhs_;
+
+ case FFELEX_typeASTERISK:
+ case FFELEX_typeSLASH:
+ case FFELEX_typePOWER:
+ case FFELEX_typeCONCAT:
+ case FFELEX_typeREL_EQ:
+ case FFELEX_typeREL_NE:
+ case FFELEX_typeREL_LE:
+ case FFELEX_typeREL_GE:
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+
+ default:
+ return (ffelexHandler) ffeexpr_nil_finished_ (t);
+ }
+}
+
+static ffelexHandler
+ffeexpr_nil_period_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffeexpr_current_dotdot_ = ffestr_other (t);
+ switch (ffeexpr_current_dotdot_)
+ {
+ case FFESTR_otherNone:
+ return (ffelexHandler) ffeexpr_nil_rhs_ (t);
+
+ case FFESTR_otherTRUE:
+ case FFESTR_otherFALSE:
+ case FFESTR_otherNOT:
+ return (ffelexHandler) ffeexpr_nil_end_period_;
+
+ default:
+ return (ffelexHandler) ffeexpr_nil_swallow_period_;
+ }
+ break; /* Nothing really reaches here. */
+
+ case FFELEX_typeNUMBER:
+ return (ffelexHandler) ffeexpr_nil_real_;
+
+ default:
+ return (ffelexHandler) ffeexpr_nil_rhs_ (t);
+ }
+}
+
+static ffelexHandler
+ffeexpr_nil_end_period_ (ffelexToken t)
+{
+ switch (ffeexpr_current_dotdot_)
+ {
+ case FFESTR_otherNOT:
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ return (ffelexHandler) ffeexpr_nil_rhs_ (t);
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+
+ case FFESTR_otherTRUE:
+ case FFESTR_otherFALSE:
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+ return (ffelexHandler) ffeexpr_nil_binary_;
+
+ default:
+ assert ("Bad [nil] unary dotdot in ffeexpr_current_dotdot_" == NULL);
+ exit (0);
+ return NULL;
+ }
+}
+
+static ffelexHandler
+ffeexpr_nil_swallow_period_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ return (ffelexHandler) ffeexpr_nil_rhs_ (t);
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+}
+
+static ffelexHandler
+ffeexpr_nil_real_ (ffelexToken t)
+{
+ char d;
+ char *p;
+
+ if (((ffelex_token_type (t) != FFELEX_typeNAME)
+ && (ffelex_token_type (t) != FFELEX_typeNAMES))
+ || !(((ffesrc_char_match_init ((d = *(p = ffelex_token_text (t))),
+ 'D', 'd')
+ || ffesrc_char_match_init (d, 'E', 'e')
+ || ffesrc_char_match_init (d, 'Q', 'q')))
+ && ffeexpr_isdigits_ (++p)))
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+
+ if (*p == '\0')
+ return (ffelexHandler) ffeexpr_nil_real_exponent_;
+ return (ffelexHandler) ffeexpr_nil_binary_;
+}
+
+static ffelexHandler
+ffeexpr_nil_real_exponent_ (ffelexToken t)
+{
+ if ((ffelex_token_type (t) != FFELEX_typePLUS)
+ && (ffelex_token_type (t) != FFELEX_typeMINUS))
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+
+ return (ffelexHandler) ffeexpr_nil_real_exp_sign_;
+}
+
+static ffelexHandler
+ffeexpr_nil_real_exp_sign_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+ return (ffelexHandler) ffeexpr_nil_binary_;
+}
+
+static ffelexHandler
+ffeexpr_nil_number_ (ffelexToken t)
+{
+ char d;
+ char *p;
+
+ if (ffeexpr_hollerith_count_ > 0)
+ ffelex_set_expecting_hollerith (0, '\0',
+ ffewhere_line_unknown (),
+ ffewhere_column_unknown ());
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ if ((ffesrc_char_match_init ((d = *(p = ffelex_token_text (t))),
+ 'D', 'd')
+ || ffesrc_char_match_init (d, 'E', 'e')
+ || ffesrc_char_match_init (d, 'Q', 'q'))
+ && ffeexpr_isdigits_ (++p))
+ {
+ if (*p == '\0')
+ {
+ ffeexpr_find_.t = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_nil_number_exponent_;
+ }
+ return (ffelexHandler) ffeexpr_nil_binary_;
+ }
+ break;
+
+ case FFELEX_typePERIOD:
+ ffeexpr_find_.t = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_nil_number_period_;
+
+ case FFELEX_typeHOLLERITH:
+ return (ffelexHandler) ffeexpr_nil_binary_;
+
+ default:
+ break;
+ }
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+}
+
+/* Expects ffeexpr_find_.t. */
+
+static ffelexHandler
+ffeexpr_nil_number_exponent_ (ffelexToken t)
+{
+ ffelexHandler nexthandler;
+
+ if ((ffelex_token_type (t) != FFELEX_typePLUS)
+ && (ffelex_token_type (t) != FFELEX_typeMINUS))
+ {
+ nexthandler
+ = (ffelexHandler) ffeexpr_nil_binary_ (ffeexpr_find_.t);
+ ffelex_token_kill (ffeexpr_find_.t);
+ return (ffelexHandler) (*nexthandler) (t);
+ }
+
+ ffelex_token_kill (ffeexpr_find_.t);
+ return (ffelexHandler) ffeexpr_nil_number_exp_sign_;
+}
+
+static ffelexHandler
+ffeexpr_nil_number_exp_sign_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+
+ return (ffelexHandler) ffeexpr_nil_binary_;
+}
+
+/* Expects ffeexpr_find_.t. */
+
+static ffelexHandler
+ffeexpr_nil_number_period_ (ffelexToken t)
+{
+ ffelexHandler nexthandler;
+ char d;
+ char *p;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ if ((ffesrc_char_match_init ((d = *(p = ffelex_token_text (t))),
+ 'D', 'd')
+ || ffesrc_char_match_init (d, 'E', 'e')
+ || ffesrc_char_match_init (d, 'Q', 'q'))
+ && ffeexpr_isdigits_ (++p))
+ {
+ if (*p == '\0')
+ return (ffelexHandler) ffeexpr_nil_number_per_exp_;
+ ffelex_token_kill (ffeexpr_find_.t);
+ return (ffelexHandler) ffeexpr_nil_binary_;
+ }
+ nexthandler
+ = (ffelexHandler) ffeexpr_nil_binary_ (ffeexpr_find_.t);
+ ffelex_token_kill (ffeexpr_find_.t);
+ return (ffelexHandler) (*nexthandler) (t);
+
+ case FFELEX_typeNUMBER:
+ ffelex_token_kill (ffeexpr_find_.t);
+ return (ffelexHandler) ffeexpr_nil_number_real_;
+
+ default:
+ break;
+ }
+ ffelex_token_kill (ffeexpr_find_.t);
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+}
+
+/* Expects ffeexpr_find_.t. */
+
+static ffelexHandler
+ffeexpr_nil_number_per_exp_ (ffelexToken t)
+{
+ if ((ffelex_token_type (t) != FFELEX_typePLUS)
+ && (ffelex_token_type (t) != FFELEX_typeMINUS))
+ {
+ ffelexHandler nexthandler;
+
+ nexthandler
+ = (ffelexHandler) ffeexpr_nil_binary_ (ffeexpr_find_.t);
+ ffelex_token_kill (ffeexpr_find_.t);
+ return (ffelexHandler) (*nexthandler) (t);
+ }
+
+ ffelex_token_kill (ffeexpr_find_.t);
+ return (ffelexHandler) ffeexpr_nil_num_per_exp_sign_;
+}
+
+static ffelexHandler
+ffeexpr_nil_number_real_ (ffelexToken t)
+{
+ char d;
+ char *p;
+
+ if (((ffelex_token_type (t) != FFELEX_typeNAME)
+ && (ffelex_token_type (t) != FFELEX_typeNAMES))
+ || !(((ffesrc_char_match_init ((d = *(p = ffelex_token_text (t))),
+ 'D', 'd')
+ || ffesrc_char_match_init (d, 'E', 'e')
+ || ffesrc_char_match_init (d, 'Q', 'q')))
+ && ffeexpr_isdigits_ (++p)))
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+
+ if (*p == '\0')
+ return (ffelexHandler) ffeexpr_nil_number_real_exp_;
+
+ return (ffelexHandler) ffeexpr_nil_binary_;
+}
+
+static ffelexHandler
+ffeexpr_nil_num_per_exp_sign_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+ return (ffelexHandler) ffeexpr_nil_binary_;
+}
+
+static ffelexHandler
+ffeexpr_nil_number_real_exp_ (ffelexToken t)
+{
+ if ((ffelex_token_type (t) != FFELEX_typePLUS)
+ && (ffelex_token_type (t) != FFELEX_typeMINUS))
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+ return (ffelexHandler) ffeexpr_nil_num_real_exp_sn_;
+}
+
+static ffelexHandler
+ffeexpr_nil_num_real_exp_sn_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+ return (ffelexHandler) ffeexpr_nil_binary_;
+}
+
+static ffelexHandler
+ffeexpr_nil_binary_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typePLUS:
+ case FFELEX_typeMINUS:
+ case FFELEX_typeASTERISK:
+ case FFELEX_typeSLASH:
+ case FFELEX_typePOWER:
+ case FFELEX_typeCONCAT:
+ case FFELEX_typeOPEN_ANGLE:
+ case FFELEX_typeCLOSE_ANGLE:
+ case FFELEX_typeREL_EQ:
+ case FFELEX_typeREL_NE:
+ case FFELEX_typeREL_GE:
+ case FFELEX_typeREL_LE:
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+
+ case FFELEX_typePERIOD:
+ return (ffelexHandler) ffeexpr_nil_binary_period_;
+
+ default:
+ return (ffelexHandler) ffeexpr_nil_finished_ (t);
+ }
+}
+
+static ffelexHandler
+ffeexpr_nil_binary_period_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffeexpr_current_dotdot_ = ffestr_other (t);
+ switch (ffeexpr_current_dotdot_)
+ {
+ case FFESTR_otherTRUE:
+ case FFESTR_otherFALSE:
+ case FFESTR_otherNOT:
+ return (ffelexHandler) ffeexpr_nil_binary_sw_per_;
+
+ default:
+ return (ffelexHandler) ffeexpr_nil_binary_end_per_;
+ }
+ break; /* Nothing really reaches here. */
+
+ default:
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+ }
+}
+
+static ffelexHandler
+ffeexpr_nil_binary_end_per_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ return (ffelexHandler) ffeexpr_nil_rhs_ (t);
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+}
+
+static ffelexHandler
+ffeexpr_nil_binary_sw_per_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+ return (ffelexHandler) ffeexpr_nil_binary_;
+}
+
+static ffelexHandler
+ffeexpr_nil_quote_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ return (ffelexHandler) ffeexpr_nil_rhs_ (t);
+ return (ffelexHandler) ffeexpr_nil_binary_;
+}
+
+static ffelexHandler
+ffeexpr_nil_apostrophe_ (ffelexToken t)
+{
+ assert (ffelex_token_type (t) == FFELEX_typeCHARACTER);
+ return (ffelexHandler) ffeexpr_nil_apos_char_;
+}
+
+static ffelexHandler
+ffeexpr_nil_apos_char_ (ffelexToken t)
+{
+ char c;
+
+ if ((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNAMES))
+ {
+ if ((ffelex_token_length (t) == 1)
+ && (ffesrc_char_match_init ((c = ffelex_token_text (t)[0]),
+ 'B', 'b')
+ || ffesrc_char_match_init (c, 'O', 'o')
+ || ffesrc_char_match_init (c, 'X', 'x')
+ || ffesrc_char_match_init (c, 'Z', 'z')))
+ return (ffelexHandler) ffeexpr_nil_binary_;
+ }
+ if ((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNAMES))
+ return (ffelexHandler) ffeexpr_nil_rhs_ (t);
+ return (ffelexHandler) ffeexpr_nil_substrp_ (t);
+}
+
+static ffelexHandler
+ffeexpr_nil_name_rhs_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeQUOTE:
+ case FFELEX_typeAPOSTROPHE:
+ ffelex_set_hexnum (TRUE);
+ return (ffelexHandler) ffeexpr_nil_name_apos_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ++ffeexpr_find_.level;
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+
+ default:
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+ }
+}
+
+static ffelexHandler
+ffeexpr_nil_name_apos_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) == FFELEX_typeNAME)
+ return (ffelexHandler) ffeexpr_nil_name_apos_name_;
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+}
+
+static ffelexHandler
+ffeexpr_nil_name_apos_name_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeAPOSTROPHE:
+ case FFELEX_typeQUOTE:
+ return (ffelexHandler) ffeexpr_nil_finished_;
+
+ default:
+ return (ffelexHandler) ffeexpr_nil_finished_ (t);
+ }
+}
+
+static ffelexHandler
+ffeexpr_nil_percent_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffeexpr_stack_->percent = ffeexpr_percent_ (t);
+ ffeexpr_find_.t = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_nil_percent_name_;
+
+ default:
+ return (ffelexHandler) ffeexpr_nil_rhs_ (t);
+ }
+}
+
+/* Expects ffeexpr_find_.t. */
+
+static ffelexHandler
+ffeexpr_nil_percent_name_ (ffelexToken t)
+{
+ ffelexHandler nexthandler;
+
+ if (ffelex_token_type (t) != FFELEX_typeOPEN_PAREN)
+ {
+ nexthandler
+ = (ffelexHandler) ffeexpr_nil_rhs_ (ffeexpr_find_.t);
+ ffelex_token_kill (ffeexpr_find_.t);
+ return (ffelexHandler) (*nexthandler) (t);
+ }
+
+ ffelex_token_kill (ffeexpr_find_.t);
+ ++ffeexpr_find_.level;
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+}
+
+static ffelexHandler
+ffeexpr_nil_substrp_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeOPEN_PAREN)
+ return (ffelexHandler) ffeexpr_nil_binary_ (t);
+
+ ++ffeexpr_find_.level;
+ return (ffelexHandler) ffeexpr_nil_rhs_;
+}
+
+/* ffeexpr_finished_ -- Reduce expression stack to one expr, finish
+
+ ffelexToken t;
+ return ffeexpr_finished_(t);
+
+ Reduces expression stack to one (or zero) elements by repeatedly reducing
+ the top operator on the stack (or, if the top element on the stack is
+ itself an operator, issuing an error message and discarding it). Calls
+ finishing routine with the expression, returning the ffelexHandler it
+ returns to the caller. */
+
+static ffelexHandler
+ffeexpr_finished_ (ffelexToken t)
+{
+ ffeexprExpr_ operand; /* This is B in -B or A+B. */
+ ffebld expr;
+ ffeexprCallback callback;
+ ffeexprStack_ s;
+ ffebldConstant constnode; /* For detecting magical number. */
+ ffelexToken ft; /* Temporary copy of first token in
+ expression. */
+ ffelexHandler next;
+ ffeinfo info;
+ bool error = FALSE;
+
+ while (((operand = ffeexpr_stack_->exprstack) != NULL)
+ && ((operand->previous != NULL) || (operand->type != FFEEXPR_exprtypeOPERAND_)))
+ {
+ if (operand->type == FFEEXPR_exprtypeOPERAND_)
+ ffeexpr_reduce_ ();
+ else
+ {
+ if (ffest_ffebad_start (FFEBAD_MISSING_OPERAND_FOR_OPERATOR))
+ {
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->exprstack->token),
+ ffelex_token_where_column (ffeexpr_stack_->exprstack->token));
+ ffebad_finish ();
+ }
+ ffeexpr_stack_->exprstack = operand->previous; /* Pop the useless
+ operator. */
+ ffeexpr_expr_kill_ (operand);
+ }
+ }
+
+ assert ((operand == NULL) || (operand->previous == NULL));
+
+ ffebld_pool_pop ();
+ if (operand == NULL)
+ expr = NULL;
+ else
+ {
+ expr = operand->u.operand;
+ info = ffebld_info (expr);
+ if ((ffebld_op (expr) == FFEBLD_opCONTER)
+ && (ffebld_conter_orig (expr) == NULL)
+ && ffebld_constant_is_magical (constnode = ffebld_conter (expr)))
+ {
+ ffetarget_integer_bad_magical (operand->token);
+ }
+ ffeexpr_expr_kill_ (operand);
+ ffeexpr_stack_->exprstack = NULL;
+ }
+
+ ft = ffeexpr_stack_->first_token;
+
+again: /* :::::::::::::::::::: */
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextLET:
+ case FFEEXPR_contextSFUNCDEF:
+ error = (expr == NULL)
+ || (ffeinfo_rank (info) != 0);
+ break;
+
+ case FFEEXPR_contextPAREN_:
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextPARENFILENUM_:
+ if (ffelex_token_type (t) != FFELEX_typeCOMMA)
+ ffeexpr_stack_->context = FFEEXPR_contextPAREN_;
+ else
+ ffeexpr_stack_->context = FFEEXPR_contextFILENUM;
+ goto again; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextPARENFILEUNIT_:
+ if (ffelex_token_type (t) != FFELEX_typeCOMMA)
+ ffeexpr_stack_->context = FFEEXPR_contextPAREN_;
+ else
+ ffeexpr_stack_->context = FFEEXPR_contextFILEUNIT;
+ goto again; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEFACTUALARGEXPR_:
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ if (!ffe_is_ugly_args ()
+ && ffebad_start (FFEBAD_ACTUALARG))
+ {
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_finish ();
+ }
+ break;
+
+ default:
+ break;
+ }
+ error = (expr != NULL) && (ffeinfo_rank (info) != 0);
+ break;
+
+ case FFEEXPR_contextACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+#if 0 /* Should never get here. */
+ expr = ffeexpr_convert (expr, ft, ft,
+ FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT,
+ 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+#else
+ assert ("why hollerith/typeless in actualarg_?" == NULL);
+#endif
+ break;
+
+ default:
+ break;
+ }
+ switch ((expr == NULL) ? FFEBLD_opANY : ffebld_op (expr))
+ {
+ case FFEBLD_opSYMTER:
+ case FFEBLD_opPERCENT_LOC:
+ case FFEBLD_opPERCENT_VAL:
+ case FFEBLD_opPERCENT_REF:
+ case FFEBLD_opPERCENT_DESCR:
+ error = FALSE;
+ break;
+
+ default:
+ error = (expr != NULL) && (ffeinfo_rank (info) != 0);
+ break;
+ }
+ {
+ ffesymbol s;
+ ffeinfoWhere where;
+ ffeinfoKind kind;
+
+ if (!error
+ && (expr != NULL)
+ && (ffebld_op (expr) == FFEBLD_opSYMTER)
+ && ((s = ffebld_symter (expr)), (where = ffesymbol_where (s)),
+ (where == FFEINFO_whereINTRINSIC)
+ || (where == FFEINFO_whereGLOBAL)
+ || ((where == FFEINFO_whereDUMMY)
+ && ((kind = ffesymbol_kind (s)),
+ (kind == FFEINFO_kindFUNCTION)
+ || (kind == FFEINFO_kindSUBROUTINE))))
+ && !ffesymbol_explicitwhere (s))
+ {
+ ffebad_start (where == FFEINFO_whereINTRINSIC
+ ? FFEBAD_NEED_INTRINSIC : FFEBAD_NEED_EXTERNAL);
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ ffesymbol_signal_change (s);
+ ffesymbol_set_explicitwhere (s, TRUE);
+ ffesymbol_signal_unreported (s);
+ }
+ }
+ break;
+
+ case FFEEXPR_contextINDEX_:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ case FFEEXPR_contextRETURN:
+ if ((error = (expr != NULL) && (ffeinfo_rank (info) != 0)))
+ break;
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeNONE:
+ error = FALSE;
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ if (ffe_is_pedantic ())
+ {
+ error = TRUE;
+ break;
+ }
+ /* Fall through. */
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break; /* expr==NULL ok for substring; element case
+ caught by callback. */
+
+ case FFEEXPR_contextDO:
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ error = !ffe_is_ugly_logint ();
+ if (!ffeexpr_stack_->is_rhs)
+ break; /* Don't convert lhs variable. */
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ ffeinfo_kindtype (ffebld_info (expr)), 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ if (!ffeexpr_stack_->is_rhs)
+ {
+ error = TRUE;
+ break; /* Don't convert lhs variable. */
+ }
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeREAL:
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if (!ffeexpr_stack_->is_rhs
+ && (ffebld_op (expr) != FFEBLD_opSYMTER))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextDOWHILE:
+ case FFEEXPR_contextIF:
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeINTEGER:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeLOGICAL:
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextASSIGN:
+ case FFEEXPR_contextAGOTO:
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeINTEGER:
+ error = (ffeinfo_kindtype (info) != ffecom_label_kind ());
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ error = !ffe_is_ugly_logint ()
+ || (ffeinfo_kindtype (info) != ffecom_label_kind ());
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((expr == NULL) || (ffeinfo_rank (info) != 0)
+ || (ffebld_op (expr) != FFEBLD_opSYMTER))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextCGOTO:
+ case FFEEXPR_contextFORMAT:
+ case FFEEXPR_contextDIMLIST:
+ case FFEEXPR_contextFILENUM: /* See equiv code in _ambig_. */
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ if (ffe_is_pedantic ())
+ {
+ error = TRUE;
+ break;
+ }
+ /* Fall through. */
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextARITHIF:
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ if (ffe_is_pedantic ())
+ {
+ error = TRUE;
+ break;
+ }
+ /* Fall through. */
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeREAL:
+ error = FALSE;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextSTOP:
+ if ((error = (expr != NULL) && (ffeinfo_rank (info) != 0)))
+ break;
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeINTEGER:
+ error = (ffeinfo_kindtype (info) != FFEINFO_kindtypeINTEGERDEFAULT);
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ error = (ffeinfo_kindtype (info) != FFEINFO_kindtypeCHARACTERDEFAULT);
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ case FFEINFO_basictypeNONE:
+ error = FALSE;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((expr != NULL) && ((ffebld_op (expr) != FFEBLD_opCONTER)
+ || (ffebld_conter_orig (expr) != NULL)))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextINCLUDE:
+ error = (expr == NULL) || (ffeinfo_rank (info) != 0)
+ || (ffeinfo_basictype (info) != FFEINFO_basictypeCHARACTER)
+ || (ffebld_op (expr) != FFEBLD_opCONTER)
+ || (ffebld_conter_orig (expr) != NULL);
+ break;
+
+ case FFEEXPR_contextSELECTCASE:
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeCHARACTER:
+ case FFEINFO_basictypeLOGICAL:
+ error = FALSE;
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextCASE:
+ if ((error = (expr != NULL) && (ffeinfo_rank (info) != 0)))
+ break;
+ switch ((expr == NULL) ? FFEINFO_basictypeINTEGER
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeCHARACTER:
+ case FFEINFO_basictypeLOGICAL:
+ error = FALSE;
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((expr != NULL) && (ffebld_op (expr) != FFEBLD_opCONTER))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextCHARACTERSIZE:
+ case FFEEXPR_contextKINDTYPE:
+ case FFEEXPR_contextDIMLISTCOMMON:
+ if ((error = (expr != NULL) && (ffeinfo_rank (info) != 0)))
+ break;
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ if (ffe_is_pedantic ())
+ {
+ error = TRUE;
+ break;
+ }
+ /* Fall through. */
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((expr != NULL) && (ffebld_op (expr) != FFEBLD_opCONTER))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextEQVINDEX_:
+ if ((error = (expr != NULL) && (ffeinfo_rank (info) != 0)))
+ break;
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeNONE:
+ error = FALSE;
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ if (ffe_is_pedantic ())
+ {
+ error = TRUE;
+ break;
+ }
+ /* Fall through. */
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((expr != NULL) && (ffebld_op (expr) != FFEBLD_opCONTER))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextPARAMETER:
+ if (ffeexpr_stack_->is_rhs)
+ error = (expr == NULL) || (ffeinfo_rank (info) != 0)
+ || (ffebld_op (expr) != FFEBLD_opCONTER);
+ else
+ error = (expr == NULL) || (ffeinfo_rank (info) != 0)
+ || (ffebld_op (expr) != FFEBLD_opSYMTER);
+ break;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ if (ffelex_token_type (t) == FFELEX_typeCOLON)
+ ffeexpr_stack_->context = FFEEXPR_contextINDEX_;
+ else
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARG_;
+ goto again; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextINDEXORACTUALARGEXPR_:
+ if (ffelex_token_type (t) == FFELEX_typeCOLON)
+ ffeexpr_stack_->context = FFEEXPR_contextINDEX_;
+ else
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARGEXPR_;
+ goto again; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ if (ffelex_token_type (t) == FFELEX_typeCOLON)
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFINDEX_;
+ else
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARG_;
+ goto again; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_:
+ if (ffelex_token_type (t) == FFELEX_typeCOLON)
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFINDEX_;
+ else
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARGEXPR_;
+ goto again; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextIMPDOCTRL_:
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ if (!ffeexpr_stack_->is_rhs
+ && (ffebld_op (expr) != FFEBLD_opSYMTER))
+ error = TRUE;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ error = error && !ffe_is_ugly_logint ();
+ if (!ffeexpr_stack_->is_rhs)
+ break; /* Don't convert lhs variable. */
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ ffeinfo_kindtype (ffebld_info (expr)), 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ break;
+
+ case FFEINFO_basictypeREAL:
+ if (!ffeexpr_stack_->is_rhs
+ && ffe_is_warn_surprising ()
+ && !error)
+ {
+ ffebad_start (FFEBAD_DO_REAL); /* See error message!!! */
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_string (ffelex_token_text (ft));
+ ffebad_finish ();
+ }
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextDATAIMPDOCTRL_:
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ if (ffeexpr_stack_->is_rhs)
+ {
+ if ((ffebld_op (expr) != FFEBLD_opCONTER)
+ && (ffeinfo_where (info) != FFEINFO_whereIMMEDIATE))
+ error = TRUE;
+ }
+ else if ((ffebld_op (expr) != FFEBLD_opSYMTER)
+ || (ffeinfo_where (info) != FFEINFO_whereIMMEDIATE))
+ error = TRUE;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ error = error
+ && (ffeinfo_kindtype (info) != FFEINFO_kindtypeLOGICALDEFAULT);
+ if (!ffeexpr_stack_->is_rhs)
+ break; /* Don't convert lhs variable. */
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ error = error &&
+ (ffeinfo_kindtype (info) != FFEINFO_kindtypeINTEGERDEFAULT);
+ break;
+
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ case FFEINFO_basictypeREAL:
+ if (!ffeexpr_stack_->is_rhs
+ && ffe_is_warn_surprising ()
+ && !error)
+ {
+ ffebad_start (FFEBAD_DO_REAL); /* See error message!!! */
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_string (ffelex_token_text (ft));
+ ffebad_finish ();
+ }
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextIMPDOITEM_:
+ if (ffelex_token_type (t) == FFELEX_typeEQUALS)
+ {
+ ffeexpr_stack_->is_rhs = FALSE;
+ ffeexpr_stack_->context = FFEEXPR_contextIMPDOCTRL_;
+ goto again; /* :::::::::::::::::::: */
+ }
+ /* Fall through. */
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextFILEVXTCODE:
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ break;
+ }
+ error = (expr == NULL)
+ || ((ffeinfo_rank (info) != 0)
+ && ((ffebld_op (expr) != FFEBLD_opSYMTER)
+ || (ffesymbol_arraysize (ffebld_symter (expr)) == NULL)
+ || (ffebld_op (ffesymbol_arraysize (ffebld_symter (expr)))
+ == FFEBLD_opSTAR))); /* Bad if null expr, or if
+ array that is not a SYMTER
+ (can't happen yet, I
+ think) or has a NULL or
+ STAR (assumed) array
+ size. */
+ break;
+
+ case FFEEXPR_contextIMPDOITEMDF_:
+ if (ffelex_token_type (t) == FFELEX_typeEQUALS)
+ {
+ ffeexpr_stack_->is_rhs = FALSE;
+ ffeexpr_stack_->context = FFEEXPR_contextIMPDOCTRL_;
+ goto again; /* :::::::::::::::::::: */
+ }
+ /* Fall through. */
+ case FFEEXPR_contextIOLISTDF:
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ break;
+ }
+ error
+ = (expr == NULL)
+ || ((ffeinfo_basictype (info) == FFEINFO_basictypeCHARACTER)
+ && (ffeinfo_kindtype (info) != FFEINFO_kindtypeCHARACTERDEFAULT))
+ || ((ffeinfo_rank (info) != 0)
+ && ((ffebld_op (expr) != FFEBLD_opSYMTER)
+ || (ffesymbol_arraysize (ffebld_symter (expr)) == NULL)
+ || (ffebld_op (ffesymbol_arraysize (ffebld_symter (expr)))
+ == FFEBLD_opSTAR))); /* Bad if null expr,
+ non-default-kindtype
+ character expr, or if
+ array that is not a SYMTER
+ (can't happen yet, I
+ think) or has a NULL or
+ STAR (assumed) array
+ size. */
+ break;
+
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ error = (expr == NULL)
+ || (ffebld_op (expr) != FFEBLD_opARRAYREF)
+ || ((ffeinfo_where (info) != FFEINFO_whereFLEETING_CADDR)
+ && (ffeinfo_where (info) != FFEINFO_whereFLEETING_IADDR));
+ break;
+
+ case FFEEXPR_contextDATAIMPDOINDEX_:
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ if (ffe_is_pedantic ())
+ {
+ error = TRUE;
+ break;
+ }
+ /* Fall through. */
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((ffeinfo_where (info) != FFEINFO_whereCONSTANT)
+ && (ffeinfo_where (info) != FFEINFO_whereIMMEDIATE))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextDATA:
+ if (expr == NULL)
+ error = TRUE;
+ else if (ffeexpr_stack_->is_rhs)
+ error = (ffebld_op (expr) != FFEBLD_opCONTER);
+ else if (ffebld_op (expr) == FFEBLD_opSYMTER)
+ error = FALSE;
+ else
+ error = (ffeinfo_where (info) != FFEINFO_whereFLEETING_CADDR);
+ break;
+
+ case FFEEXPR_contextINITVAL:
+ error = (expr == NULL) || (ffebld_op (expr) != FFEBLD_opCONTER);
+ break;
+
+ case FFEEXPR_contextEQUIVALENCE:
+ if (expr == NULL)
+ error = TRUE;
+ else if (ffebld_op (expr) == FFEBLD_opSYMTER)
+ error = FALSE;
+ else
+ error = (ffeinfo_where (info) != FFEINFO_whereFLEETING_CADDR);
+ break;
+
+ case FFEEXPR_contextFILEASSOC:
+ case FFEEXPR_contextFILEINT:
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeINTEGER:
+ error = FALSE;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((expr == NULL) || (ffeinfo_rank (info) != 0))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextFILEDFINT:
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeINTEGER:
+ error = (ffeinfo_kindtype (info) != FFEINFO_kindtypeINTEGERDEFAULT);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((expr == NULL) || (ffeinfo_rank (info) != 0))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextFILELOG:
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ error = FALSE;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((expr == NULL) || (ffeinfo_rank (info) != 0))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextFILECHAR:
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeCHARACTER:
+ error = FALSE;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((expr == NULL) || (ffeinfo_rank (info) != 0))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextFILENUMCHAR:
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ if (ffe_is_pedantic ())
+ {
+ error = TRUE;
+ break;
+ }
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeCHARACTER:
+ error = FALSE;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextFILEDFCHAR:
+ if ((error = (expr == NULL) || (ffeinfo_rank (info) != 0)))
+ break;
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeCHARACTER:
+ error
+ = (ffeinfo_kindtype (info)
+ != FFEINFO_kindtypeCHARACTERDEFAULT);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if (!ffeexpr_stack_->is_rhs
+ && (ffebld_op (expr) == FFEBLD_opSUBSTR))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextFILEUNIT: /* See equiv code in _ambig_. */
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ if ((error = (ffeinfo_rank (info) != 0)))
+ break;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ if ((error = (ffeinfo_rank (info) != 0)))
+ break;
+ if (ffe_is_pedantic ())
+ {
+ error = TRUE;
+ break;
+ }
+ /* Fall through. */
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ if ((error = (ffeinfo_rank (info) != 0)))
+ break;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (ffebld_op (expr))
+ { /* As if _lhs had been called instead of
+ _rhs. */
+ case FFEBLD_opSYMTER:
+ error
+ = (ffeinfo_where (ffebld_info (expr)) == FFEINFO_whereCONSTANT);
+ break;
+
+ case FFEBLD_opSUBSTR:
+ error = (ffeinfo_where (ffebld_info (expr))
+ == FFEINFO_whereCONSTANT_SUBOBJECT);
+ break;
+
+ case FFEBLD_opARRAYREF:
+ error = FALSE;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if (!error
+ && ((ffeinfo_kindtype (info) != FFEINFO_kindtypeCHARACTERDEFAULT)
+ || ((ffeinfo_rank (info) != 0)
+ && ((ffebld_op (expr) != FFEBLD_opSYMTER)
+ || (ffesymbol_arraysize (ffebld_symter (expr)) == NULL)
+ || (ffebld_op (ffesymbol_arraysize (ffebld_symter (expr)))
+ == FFEBLD_opSTAR))))) /* Bad if
+ non-default-kindtype
+ character expr, or if
+ array that is not a SYMTER
+ (can't happen yet, I
+ think), or has a NULL or
+ STAR (assumed) array
+ size. */
+ error = TRUE;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextFILEFORMAT:
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeINTEGER:
+ error = (expr == NULL)
+ || ((ffeinfo_rank (info) != 0) ?
+ ffe_is_pedantic () /* F77 C5. */
+ : (ffeinfo_kindtype (info) != ffecom_label_kind ()))
+ || (ffebld_op (expr) != FFEBLD_opSYMTER);
+ break;
+
+ case FFEINFO_basictypeLOGICAL:
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ /* F77 C5 -- must be an array of hollerith. */
+ error
+ = ffe_is_pedantic ()
+ || (ffeinfo_rank (info) == 0);
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ if ((ffeinfo_kindtype (info) != FFEINFO_kindtypeCHARACTERDEFAULT)
+ || ((ffeinfo_rank (info) != 0)
+ && ((ffebld_op (expr) != FFEBLD_opSYMTER)
+ || (ffesymbol_arraysize (ffebld_symter (expr)) == NULL)
+ || (ffebld_op (ffesymbol_arraysize (ffebld_symter (expr)))
+ == FFEBLD_opSTAR)))) /* Bad if
+ non-default-kindtype
+ character expr, or if
+ array that is not a SYMTER
+ (can't happen yet, I
+ think), or has a NULL or
+ STAR (assumed) array
+ size. */
+ error = TRUE;
+ else
+ error = FALSE;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextLOC_:
+ /* See also ffeintrin_check_loc_. */
+ if ((expr == NULL)
+ || (ffeinfo_kind (info) != FFEINFO_kindENTITY)
+ || ((ffebld_op (expr) != FFEBLD_opSYMTER)
+ && (ffebld_op (expr) != FFEBLD_opSUBSTR)
+ && (ffebld_op (expr) != FFEBLD_opARRAYREF)))
+ error = TRUE;
+ break;
+
+ default:
+ error = FALSE;
+ break;
+ }
+
+ if (error && ((expr == NULL) || (ffebld_op (expr) != FFEBLD_opANY)))
+ {
+ ffebad_start (FFEBAD_EXPR_WRONG);
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_finish ();
+ expr = ffebld_new_any ();
+ ffebld_set_info (expr, ffeinfo_new_any ());
+ }
+
+ callback = ffeexpr_stack_->callback;
+ s = ffeexpr_stack_->previous;
+ malloc_kill_ks (ffe_pool_program_unit (), ffeexpr_stack_,
+ sizeof (*ffeexpr_stack_));
+ ffeexpr_stack_ = s;
+ next = (ffelexHandler) (*callback) (ft, expr, t);
+ ffelex_token_kill (ft);
+ return (ffelexHandler) next;
+}
+
+/* ffeexpr_finished_ambig_ -- Check validity of ambiguous unit/form spec
+
+ ffebld expr;
+ expr = ffeexpr_finished_ambig_(expr);
+
+ Replicates a bit of ffeexpr_finished_'s task when in a context
+ of UNIT or FORMAT. */
+
+static ffebld
+ffeexpr_finished_ambig_ (ffelexToken ft, ffebld expr)
+{
+ ffeinfo info = ffebld_info (expr);
+ bool error;
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFILENUMAMBIG: /* Same as FILENUM in _finished_. */
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ if (ffe_is_pedantic ())
+ {
+ error = TRUE;
+ break;
+ }
+ /* Fall through. */
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = FALSE;
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ if ((expr == NULL) || (ffeinfo_rank (info) != 0))
+ error = TRUE;
+ break;
+
+ case FFEEXPR_contextFILEUNITAMBIG: /* Same as FILEUNIT in _finished_. */
+ if ((expr != NULL) && (ffebld_op (expr) == FFEBLD_opSTAR))
+ {
+ error = FALSE;
+ break;
+ }
+ switch ((expr == NULL) ? FFEINFO_basictypeNONE
+ : ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeLOGICAL:
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeLOGICAL,
+ FFEINFO_kindtypeLOGICALDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ /* Fall through. */
+ case FFEINFO_basictypeREAL:
+ case FFEINFO_basictypeCOMPLEX:
+ if (ffe_is_pedantic ())
+ {
+ error = TRUE;
+ break;
+ }
+ /* Fall through. */
+ case FFEINFO_basictypeINTEGER:
+ case FFEINFO_basictypeHOLLERITH:
+ case FFEINFO_basictypeTYPELESS:
+ error = (ffeinfo_rank (info) != 0);
+ expr = ffeexpr_convert (expr, ft, ft, FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ break;
+
+ case FFEINFO_basictypeCHARACTER:
+ switch (ffebld_op (expr))
+ { /* As if _lhs had been called instead of
+ _rhs. */
+ case FFEBLD_opSYMTER:
+ error
+ = (ffeinfo_where (ffebld_info (expr)) == FFEINFO_whereCONSTANT);
+ break;
+
+ case FFEBLD_opSUBSTR:
+ error = (ffeinfo_where (ffebld_info (expr))
+ == FFEINFO_whereCONSTANT_SUBOBJECT);
+ break;
+
+ case FFEBLD_opARRAYREF:
+ error = FALSE;
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ default:
+ error = TRUE;
+ break;
+ }
+ break;
+
+ default:
+ assert ("bad context" == NULL);
+ error = TRUE;
+ break;
+ }
+
+ if (error && ((expr == NULL) || (ffebld_op (expr) != FFEBLD_opANY)))
+ {
+ ffebad_start (FFEBAD_EXPR_WRONG);
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_finish ();
+ expr = ffebld_new_any ();
+ ffebld_set_info (expr, ffeinfo_new_any ());
+ }
+
+ return expr;
+}
+
+/* ffeexpr_token_lhs_ -- Initial state for lhs expression
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Basically a smaller version of _rhs_; keep them both in sync, of course. */
+
+static ffelexHandler
+ffeexpr_token_lhs_ (ffelexToken t)
+{
+
+ /* When changing the list of valid initial lhs tokens, check whether to
+ update a corresponding list in ffeexpr_cb_close_paren_ambig_1_ for the
+ READ (expr) <token> case -- it assumes it knows which tokens <token> can
+ be to indicate an lhs (or implied DO), which right now is the set
+ {NAME,OPEN_PAREN}.
+
+ This comment also appears in ffeexpr_token_first_lhs_. */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffeexpr_tokens_[0] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_name_lhs_;
+
+ default:
+ return (ffelexHandler) ffeexpr_finished_ (t);
+ }
+}
+
+/* ffeexpr_token_rhs_ -- Initial state for rhs expression
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ The initial state and the post-binary-operator state are the same and
+ both handled here, with the expression stack used to distinguish
+ between them. Binary operators are invalid here; unary operators,
+ constants, subexpressions, and name references are valid. */
+
+static ffelexHandler
+ffeexpr_token_rhs_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeQUOTE:
+ if (ffe_is_vxt ())
+ {
+ ffeexpr_tokens_[0] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_quote_;
+ }
+ ffeexpr_tokens_[0] = ffelex_token_use (t);
+ ffelex_set_expecting_hollerith (-1, '\"',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ /* Don't have to unset this one. */
+ return (ffelexHandler) ffeexpr_token_apostrophe_;
+
+ case FFELEX_typeAPOSTROPHE:
+ ffeexpr_tokens_[0] = ffelex_token_use (t);
+ ffelex_set_expecting_hollerith (-1, '\'',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ /* Don't have to unset this one. */
+ return (ffelexHandler) ffeexpr_token_apostrophe_;
+
+ case FFELEX_typePERCENT:
+ ffeexpr_tokens_[0] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_percent_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffeexpr_stack_->tokens[0] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextPAREN_,
+ ffeexpr_cb_close_paren_c_);
+
+ case FFELEX_typePLUS:
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeUNARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorADD_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceADD_;
+ e->u.operator.as = FFEEXPR_operatorassociativityADD_;
+ ffeexpr_exprstack_push_unary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeMINUS:
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeUNARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorSUBTRACT_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceSUBTRACT_;
+ e->u.operator.as = FFEEXPR_operatorassociativitySUBTRACT_;
+ ffeexpr_exprstack_push_unary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typePERIOD:
+ ffeexpr_tokens_[0] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_period_;
+
+ case FFELEX_typeNUMBER:
+ ffeexpr_tokens_[0] = ffelex_token_use (t);
+ ffeexpr_hollerith_count_ = atol (ffelex_token_text (t));
+ if (ffeexpr_hollerith_count_ > 0)
+ ffelex_set_expecting_hollerith (ffeexpr_hollerith_count_,
+ '\0',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ return (ffelexHandler) ffeexpr_token_number_;
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffeexpr_tokens_[0] = ffelex_token_use (t);
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextACTUALARG_:
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ return (ffelexHandler) ffeexpr_token_name_arg_;
+
+ default:
+ return (ffelexHandler) ffeexpr_token_name_rhs_;
+ }
+
+ case FFELEX_typeASTERISK:
+ case FFELEX_typeSLASH:
+ case FFELEX_typePOWER:
+ case FFELEX_typeCONCAT:
+ case FFELEX_typeREL_EQ:
+ case FFELEX_typeREL_NE:
+ case FFELEX_typeREL_LE:
+ case FFELEX_typeREL_GE:
+ if (ffest_ffebad_start (FFEBAD_MISSING_FIRST_BINARY_OPERAND))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+#if 0
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCLOSE_ANGLE:
+ case FFELEX_typeCLOSE_PAREN:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+#endif
+ default:
+ return (ffelexHandler) ffeexpr_finished_ (t);
+ }
+}
+
+/* ffeexpr_token_period_ -- Rhs PERIOD
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle a period detected at rhs (expecting unary op or operand) state.
+ Must begin a floating-point value (as in .12) or a dot-dot name, of
+ which only .NOT., .TRUE., and .FALSE. are truly valid. Other sort-of-
+ valid names represent binary operators, which are invalid here because
+ there isn't an operand at the top of the stack. */
+
+static ffelexHandler
+ffeexpr_token_period_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffeexpr_current_dotdot_ = ffestr_other (t);
+ switch (ffeexpr_current_dotdot_)
+ {
+ case FFESTR_otherNone:
+ if (ffest_ffebad_start (FFEBAD_IGNORING_PERIOD))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ return (ffelexHandler) ffeexpr_token_rhs_ (t);
+
+ case FFESTR_otherTRUE:
+ case FFESTR_otherFALSE:
+ case FFESTR_otherNOT:
+ ffeexpr_tokens_[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_end_period_;
+
+ default:
+ if (ffest_ffebad_start (FFEBAD_MISSING_FIRST_BINARY_OPERAND))
+ {
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ return (ffelexHandler) ffeexpr_token_swallow_period_;
+ }
+ break; /* Nothing really reaches here. */
+
+ case FFELEX_typeNUMBER:
+ ffeexpr_tokens_[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_real_;
+
+ default:
+ if (ffest_ffebad_start (FFEBAD_IGNORING_PERIOD))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ return (ffelexHandler) ffeexpr_token_rhs_ (t);
+ }
+}
+
+/* ffeexpr_token_end_period_ -- Rhs PERIOD NAME(NOT, TRUE, or FALSE)
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Expecting a period to close a .NOT, .TRUE, or .FALSE at rhs (unary op
+ or operator) state. If period isn't found, issue a diagnostic but
+ pretend we saw one. ffeexpr_current_dotdot_ must already contained the
+ dotdot representation of the name in between the two PERIOD tokens. */
+
+static ffelexHandler
+ffeexpr_token_end_period_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ {
+ if (ffest_ffebad_start (FFEBAD_INSERTING_PERIOD))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_string (ffelex_token_text (ffeexpr_tokens_[1]));
+ ffebad_finish ();
+ }
+ }
+
+ ffelex_token_kill (ffeexpr_tokens_[1]); /* Kill "NOT"/"TRUE"/"FALSE"
+ token. */
+
+ e = ffeexpr_expr_new_ ();
+ e->token = ffeexpr_tokens_[0];
+
+ switch (ffeexpr_current_dotdot_)
+ {
+ case FFESTR_otherNOT:
+ e->type = FFEEXPR_exprtypeUNARY_;
+ e->u.operator.op = FFEEXPR_operatorNOT_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceNOT_;
+ e->u.operator.as = FFEEXPR_operatorassociativityNOT_;
+ ffeexpr_exprstack_push_unary_ (e);
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ return (ffelexHandler) ffeexpr_token_rhs_ (t);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFESTR_otherTRUE:
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->u.operand
+ = ffebld_new_conter (ffebld_constant_new_logicaldefault (TRUE));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICALDEFAULT,
+ 0, FFEINFO_kindENTITY, FFEINFO_whereCONSTANT, FFETARGET_charactersizeNONE));
+ ffeexpr_exprstack_push_operand_ (e);
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ return (ffelexHandler) ffeexpr_token_binary_;
+
+ case FFESTR_otherFALSE:
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->u.operand
+ = ffebld_new_conter (ffebld_constant_new_logicaldefault (FALSE));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeLOGICAL, FFEINFO_kindtypeLOGICALDEFAULT,
+ 0, FFEINFO_kindENTITY, FFEINFO_whereCONSTANT, FFETARGET_charactersizeNONE));
+ ffeexpr_exprstack_push_operand_ (e);
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ return (ffelexHandler) ffeexpr_token_binary_;
+
+ default:
+ assert ("Bad unary dotdot in ffeexpr_current_dotdot_" == NULL);
+ exit (0);
+ return NULL;
+ }
+}
+
+/* ffeexpr_token_swallow_period_ -- Rhs PERIOD NAME(not NOT, TRUE, or FALSE)
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ A diagnostic has already been issued; just swallow a period if there is
+ one, then continue with ffeexpr_token_rhs_. */
+
+static ffelexHandler
+ffeexpr_token_swallow_period_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ return (ffelexHandler) ffeexpr_token_rhs_ (t);
+
+ return (ffelexHandler) ffeexpr_token_rhs_;
+}
+
+/* ffeexpr_token_real_ -- Rhs PERIOD NUMBER
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ After a period and a string of digits, check next token for possible
+ exponent designation (D, E, or Q as first/only character) and continue
+ real-number handling accordingly. Else form basic real constant, push
+ onto expression stack, and enter binary state using current token (which,
+ if it is a name not beginning with D, E, or Q, will certainly result
+ in an error, but that's not for this routine to deal with). */
+
+static ffelexHandler
+ffeexpr_token_real_ (ffelexToken t)
+{
+ char d;
+ char *p;
+
+ if (((ffelex_token_type (t) != FFELEX_typeNAME)
+ && (ffelex_token_type (t) != FFELEX_typeNAMES))
+ || !(((ffesrc_char_match_init ((d = *(p = ffelex_token_text (t))),
+ 'D', 'd')
+ || ffesrc_char_match_init (d, 'E', 'e')
+ || ffesrc_char_match_init (d, 'Q', 'q')))
+ && ffeexpr_isdigits_ (++p)))
+ {
+#if 0
+ /* This code has been removed because it seems inconsistent to
+ produce a diagnostic in this case, but not all of the other
+ ones that look for an exponent and cannot recognize one. */
+ if (((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNAMES))
+ && ffest_ffebad_start (FFEBAD_INVALID_EXPONENT))
+ {
+ char bad[2];
+
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ bad[0] = *(p - 1);
+ bad[1] = '\0';
+ ffebad_string (bad);
+ ffebad_finish ();
+ }
+#endif
+ ffeexpr_make_float_const_ (ffesrc_char_internal_init ('E', 'e'), NULL,
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ NULL, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ }
+
+ /* Just exponent character by itself? In which case, PLUS or MINUS must
+ surely be next, followed by a NUMBER token. */
+
+ if (*p == '\0')
+ {
+ ffeexpr_tokens_[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_real_exponent_;
+ }
+
+ ffeexpr_make_float_const_ (d, NULL, ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ t, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+}
+
+/* ffeexpr_token_real_exponent_ -- Rhs PERIOD NUMBER NAME(D, E, or Q)
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Ensures this token is PLUS or MINUS, preserves it, goes to final state
+ for real number (exponent digits). Else issues diagnostic, assumes a
+ zero exponent field for number, passes token on to binary state as if
+ previous token had been "E0" instead of "E", for example. */
+
+static ffelexHandler
+ffeexpr_token_real_exponent_ (ffelexToken t)
+{
+ if ((ffelex_token_type (t) != FFELEX_typePLUS)
+ && (ffelex_token_type (t) != FFELEX_typeMINUS))
+ {
+ if (ffest_ffebad_start (FFEBAD_MISSING_EXPONENT_VALUE))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[2]),
+ ffelex_token_where_column (ffeexpr_tokens_[2]));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ ffeexpr_make_float_const_ (ffesrc_char_internal_init ('E', 'e'), NULL,
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ NULL, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ }
+
+ ffeexpr_tokens_[3] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_real_exp_sign_;
+}
+
+/* ffeexpr_token_real_exp_sign_ -- Rhs PERIOD NUMBER NAME(D,E,Q) PLUS/MINUS
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Make sure token is a NUMBER, make a real constant out of all we have and
+ push it onto the expression stack. Else issue diagnostic and pretend
+ exponent field was a zero. */
+
+static ffelexHandler
+ffeexpr_token_real_exp_sign_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ {
+ if (ffest_ffebad_start (FFEBAD_MISSING_EXPONENT_VALUE))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[2]),
+ ffelex_token_where_column (ffeexpr_tokens_[2]));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ ffeexpr_make_float_const_ (ffesrc_char_internal_init ('E', 'e'), NULL,
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ NULL, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ ffelex_token_kill (ffeexpr_tokens_[3]);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ }
+
+ ffeexpr_make_float_const_ (ffelex_token_text (ffeexpr_tokens_[2])[0], NULL,
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1], ffeexpr_tokens_[2],
+ ffeexpr_tokens_[3], t);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ ffelex_token_kill (ffeexpr_tokens_[3]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+}
+
+/* ffeexpr_token_number_ -- Rhs NUMBER
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ If the token is a period, we may have a floating-point number, or an
+ integer followed by a dotdot binary operator. If the token is a name
+ beginning with D, E, or Q, we definitely have a floating-point number.
+ If the token is a hollerith constant, that's what we've got, so push
+ it onto the expression stack and continue with the binary state.
+
+ Otherwise, we have an integer followed by something the binary state
+ should be able to swallow. */
+
+static ffelexHandler
+ffeexpr_token_number_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+ ffeinfo ni;
+ char d;
+ char *p;
+
+ if (ffeexpr_hollerith_count_ > 0)
+ ffelex_set_expecting_hollerith (0, '\0',
+ ffewhere_line_unknown (),
+ ffewhere_column_unknown ());
+
+ /* See if we've got a floating-point number here. */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ if ((ffesrc_char_match_init ((d = *(p = ffelex_token_text (t))),
+ 'D', 'd')
+ || ffesrc_char_match_init (d, 'E', 'e')
+ || ffesrc_char_match_init (d, 'Q', 'q'))
+ && ffeexpr_isdigits_ (++p))
+ {
+
+ /* Just exponent character by itself? In which case, PLUS or MINUS
+ must surely be next, followed by a NUMBER token. */
+
+ if (*p == '\0')
+ {
+ ffeexpr_tokens_[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_number_exponent_;
+ }
+ ffeexpr_make_float_const_ (d, ffeexpr_tokens_[0], NULL, NULL, t,
+ NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+ }
+ break;
+
+ case FFELEX_typePERIOD:
+ ffeexpr_tokens_[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_number_period_;
+
+ case FFELEX_typeHOLLERITH:
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_tokens_[0];
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_hollerith (t));
+ ni = ffeinfo_new (FFEINFO_basictypeHOLLERITH, FFEINFO_kindtypeNONE,
+ 0, FFEINFO_kindENTITY, FFEINFO_whereCONSTANT,
+ ffelex_token_length (t));
+ ffebld_set_info (e->u.operand, ni);
+ ffeexpr_exprstack_push_operand_ (e);
+ return (ffelexHandler) ffeexpr_token_binary_;
+
+ default:
+ break;
+ }
+
+ /* Nothing specific we were looking for, so make an integer and pass the
+ current token to the binary state. */
+
+ ffeexpr_make_float_const_ ('I', ffeexpr_tokens_[0], NULL, NULL,
+ NULL, NULL, NULL);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+}
+
+/* ffeexpr_token_number_exponent_ -- Rhs NUMBER NAME(D, E, or Q)
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Ensures this token is PLUS or MINUS, preserves it, goes to final state
+ for real number (exponent digits). Else treats number as integer, passes
+ name to binary, passes current token to subsequent handler. */
+
+static ffelexHandler
+ffeexpr_token_number_exponent_ (ffelexToken t)
+{
+ if ((ffelex_token_type (t) != FFELEX_typePLUS)
+ && (ffelex_token_type (t) != FFELEX_typeMINUS))
+ {
+ ffeexprExpr_ e;
+ ffelexHandler nexthandler;
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_tokens_[0];
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_integerdefault
+ (ffeexpr_tokens_[0]));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeINTEGER, FFEINFO_kindtypeINTEGERDEFAULT,
+ 0, FFEINFO_kindENTITY, FFEINFO_whereCONSTANT, FFETARGET_charactersizeNONE));
+ ffeexpr_exprstack_push_operand_ (e);
+ nexthandler = (ffelexHandler) ffeexpr_token_binary_ (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ return (ffelexHandler) (*nexthandler) (t);
+ }
+
+ ffeexpr_tokens_[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_number_exp_sign_;
+}
+
+/* ffeexpr_token_number_exp_sign_ -- Rhs NUMBER NAME(D,E,Q) PLUS/MINUS
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Make sure token is a NUMBER, make a real constant out of all we have and
+ push it onto the expression stack. Else issue diagnostic and pretend
+ exponent field was a zero. */
+
+static ffelexHandler
+ffeexpr_token_number_exp_sign_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ {
+ if (ffest_ffebad_start (FFEBAD_MISSING_EXPONENT_VALUE))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[1]),
+ ffelex_token_where_column (ffeexpr_tokens_[1]));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ ffeexpr_make_float_const_ (ffelex_token_text (ffeexpr_tokens_[1])[0],
+ ffeexpr_tokens_[0], NULL, NULL,
+ ffeexpr_tokens_[1], ffeexpr_tokens_[2],
+ NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ }
+
+ ffeexpr_make_float_const_ (ffelex_token_text (ffeexpr_tokens_[1])[0],
+ ffeexpr_tokens_[0], NULL, NULL,
+ ffeexpr_tokens_[1], ffeexpr_tokens_[2], t);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+}
+
+/* ffeexpr_token_number_period_ -- Rhs NUMBER PERIOD
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle a period detected following a number at rhs state. Must begin a
+ floating-point value (as in 1., 1.2, 1.E3, or 1.E+3) or a dot-dot name. */
+
+static ffelexHandler
+ffeexpr_token_number_period_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+ ffelexHandler nexthandler;
+ char *p;
+ char d;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ if ((ffesrc_char_match_init ((d = *(p = ffelex_token_text (t))),
+ 'D', 'd')
+ || ffesrc_char_match_init (d, 'E', 'e')
+ || ffesrc_char_match_init (d, 'Q', 'q'))
+ && ffeexpr_isdigits_ (++p))
+ {
+
+ /* Just exponent character by itself? In which case, PLUS or MINUS
+ must surely be next, followed by a NUMBER token. */
+
+ if (*p == '\0')
+ {
+ ffeexpr_tokens_[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_number_per_exp_;
+ }
+ ffeexpr_make_float_const_ (d, ffeexpr_tokens_[0],
+ ffeexpr_tokens_[1], NULL, t, NULL,
+ NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+ }
+ /* A name not representing an exponent, so assume it will be something
+ like EQ, make an integer from the number, pass the period to binary
+ state and the current token to the resulting state. */
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_tokens_[0];
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_integerdefault
+ (ffeexpr_tokens_[0]));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0,
+ FFEINFO_kindENTITY, FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ ffeexpr_exprstack_push_operand_ (e);
+ nexthandler = (ffelexHandler) ffeexpr_token_binary_
+ (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ return (ffelexHandler) (*nexthandler) (t);
+
+ case FFELEX_typeNUMBER:
+ ffeexpr_tokens_[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_number_real_;
+
+ default:
+ break;
+ }
+
+ /* Nothing specific we were looking for, so make a real number and pass the
+ period and then the current token to the binary state. */
+
+ ffeexpr_make_float_const_ (ffesrc_char_internal_init ('E', 'e'),
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ NULL, NULL, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+}
+
+/* ffeexpr_token_number_per_exp_ -- Rhs NUMBER PERIOD NAME(D, E, or Q)
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Ensures this token is PLUS or MINUS, preserves it, goes to final state
+ for real number (exponent digits). Else treats number as real, passes
+ name to binary, passes current token to subsequent handler. */
+
+static ffelexHandler
+ffeexpr_token_number_per_exp_ (ffelexToken t)
+{
+ if ((ffelex_token_type (t) != FFELEX_typePLUS)
+ && (ffelex_token_type (t) != FFELEX_typeMINUS))
+ {
+ ffelexHandler nexthandler;
+
+ ffeexpr_make_float_const_ (ffesrc_char_internal_init ('E', 'e'),
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ NULL, NULL, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ nexthandler = (ffelexHandler) ffeexpr_token_binary_ (ffeexpr_tokens_[2]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ return (ffelexHandler) (*nexthandler) (t);
+ }
+
+ ffeexpr_tokens_[3] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_num_per_exp_sign_;
+}
+
+/* ffeexpr_token_number_real_ -- Rhs NUMBER PERIOD NUMBER
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ After a number, period, and number, check next token for possible
+ exponent designation (D, E, or Q as first/only character) and continue
+ real-number handling accordingly. Else form basic real constant, push
+ onto expression stack, and enter binary state using current token (which,
+ if it is a name not beginning with D, E, or Q, will certainly result
+ in an error, but that's not for this routine to deal with). */
+
+static ffelexHandler
+ffeexpr_token_number_real_ (ffelexToken t)
+{
+ char d;
+ char *p;
+
+ if (((ffelex_token_type (t) != FFELEX_typeNAME)
+ && (ffelex_token_type (t) != FFELEX_typeNAMES))
+ || !(((ffesrc_char_match_init ((d = *(p = ffelex_token_text (t))),
+ 'D', 'd')
+ || ffesrc_char_match_init (d, 'E', 'e')
+ || ffesrc_char_match_init (d, 'Q', 'q')))
+ && ffeexpr_isdigits_ (++p)))
+ {
+#if 0
+ /* This code has been removed because it seems inconsistent to
+ produce a diagnostic in this case, but not all of the other
+ ones that look for an exponent and cannot recognize one. */
+ if (((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNAMES))
+ && ffest_ffebad_start (FFEBAD_INVALID_EXPONENT))
+ {
+ char bad[2];
+
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ bad[0] = *(p - 1);
+ bad[1] = '\0';
+ ffebad_string (bad);
+ ffebad_finish ();
+ }
+#endif
+ ffeexpr_make_float_const_ (ffesrc_char_internal_init ('E', 'e'),
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ ffeexpr_tokens_[2], NULL, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ }
+
+ /* Just exponent character by itself? In which case, PLUS or MINUS must
+ surely be next, followed by a NUMBER token. */
+
+ if (*p == '\0')
+ {
+ ffeexpr_tokens_[3] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_number_real_exp_;
+ }
+
+ ffeexpr_make_float_const_ (d, ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ ffeexpr_tokens_[2], t, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+}
+
+/* ffeexpr_token_num_per_exp_sign_ -- Rhs NUMBER PERIOD NAME(D,E,Q) PLUS/MINUS
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Make sure token is a NUMBER, make a real constant out of all we have and
+ push it onto the expression stack. Else issue diagnostic and pretend
+ exponent field was a zero. */
+
+static ffelexHandler
+ffeexpr_token_num_per_exp_sign_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ {
+ if (ffest_ffebad_start (FFEBAD_MISSING_EXPONENT_VALUE))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[2]),
+ ffelex_token_where_column (ffeexpr_tokens_[2]));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ ffeexpr_make_float_const_ (ffesrc_char_internal_init ('E', 'e'),
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ NULL, NULL, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ ffelex_token_kill (ffeexpr_tokens_[3]);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ }
+
+ ffeexpr_make_float_const_ (ffelex_token_text (ffeexpr_tokens_[2])[0],
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1], NULL,
+ ffeexpr_tokens_[2], ffeexpr_tokens_[3], t);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ ffelex_token_kill (ffeexpr_tokens_[3]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+}
+
+/* ffeexpr_token_number_real_exp_ -- Rhs NUMBER PERIOD NUMBER NAME(D, E, or Q)
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Ensures this token is PLUS or MINUS, preserves it, goes to final state
+ for real number (exponent digits). Else issues diagnostic, assumes a
+ zero exponent field for number, passes token on to binary state as if
+ previous token had been "E0" instead of "E", for example. */
+
+static ffelexHandler
+ffeexpr_token_number_real_exp_ (ffelexToken t)
+{
+ if ((ffelex_token_type (t) != FFELEX_typePLUS)
+ && (ffelex_token_type (t) != FFELEX_typeMINUS))
+ {
+ if (ffest_ffebad_start (FFEBAD_MISSING_EXPONENT_VALUE))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[3]),
+ ffelex_token_where_column (ffeexpr_tokens_[3]));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ ffeexpr_make_float_const_ (ffesrc_char_internal_init ('E', 'e'),
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ ffeexpr_tokens_[2], NULL, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ ffelex_token_kill (ffeexpr_tokens_[3]);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ }
+
+ ffeexpr_tokens_[4] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_num_real_exp_sn_;
+}
+
+/* ffeexpr_token_num_real_exp_sn_ -- Rhs NUMBER PERIOD NUMBER NAME(D,E,Q)
+ PLUS/MINUS
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Make sure token is a NUMBER, make a real constant out of all we have and
+ push it onto the expression stack. Else issue diagnostic and pretend
+ exponent field was a zero. */
+
+static ffelexHandler
+ffeexpr_token_num_real_exp_sn_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ {
+ if (ffest_ffebad_start (FFEBAD_MISSING_EXPONENT_VALUE))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[3]),
+ ffelex_token_where_column (ffeexpr_tokens_[3]));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ ffeexpr_make_float_const_ (ffesrc_char_internal_init ('E', 'e'),
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ ffeexpr_tokens_[2], NULL, NULL, NULL);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ ffelex_token_kill (ffeexpr_tokens_[3]);
+ ffelex_token_kill (ffeexpr_tokens_[4]);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ }
+
+ ffeexpr_make_float_const_ (ffelex_token_text (ffeexpr_tokens_[3])[0],
+ ffeexpr_tokens_[0], ffeexpr_tokens_[1],
+ ffeexpr_tokens_[2], ffeexpr_tokens_[3],
+ ffeexpr_tokens_[4], t);
+
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ ffelex_token_kill (ffeexpr_tokens_[3]);
+ ffelex_token_kill (ffeexpr_tokens_[4]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+}
+
+/* ffeexpr_token_binary_ -- Handle binary operator possibility
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ The possibility of a binary operator is handled here, meaning the previous
+ token was an operand. */
+
+static ffelexHandler
+ffeexpr_token_binary_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+
+ if (!ffeexpr_stack_->is_rhs)
+ return (ffelexHandler) ffeexpr_finished_ (t); /* For now. */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typePLUS:
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorADD_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceADD_;
+ e->u.operator.as = FFEEXPR_operatorassociativityADD_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeMINUS:
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorSUBTRACT_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceSUBTRACT_;
+ e->u.operator.as = FFEEXPR_operatorassociativitySUBTRACT_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeASTERISK:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextDATA:
+ return (ffelexHandler) ffeexpr_finished_ (t);
+
+ default:
+ break;
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorMULTIPLY_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceMULTIPLY_;
+ e->u.operator.as = FFEEXPR_operatorassociativityMULTIPLY_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeSLASH:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextDATA:
+ return (ffelexHandler) ffeexpr_finished_ (t);
+
+ default:
+ break;
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorDIVIDE_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceDIVIDE_;
+ e->u.operator.as = FFEEXPR_operatorassociativityDIVIDE_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typePOWER:
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorPOWER_;
+ e->u.operator.prec = FFEEXPR_operatorprecedencePOWER_;
+ e->u.operator.as = FFEEXPR_operatorassociativityPOWER_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeCONCAT:
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorCONCATENATE_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceCONCATENATE_;
+ e->u.operator.as = FFEEXPR_operatorassociativityCONCATENATE_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeOPEN_ANGLE:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFORMAT:
+ ffebad_start (FFEBAD_FORMAT_EXPR_TOKEN);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ break;
+
+ default:
+ break;
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorLT_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceLT_;
+ e->u.operator.as = FFEEXPR_operatorassociativityLT_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeCLOSE_ANGLE:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFORMAT:
+ return ffeexpr_finished_ (t);
+
+ default:
+ break;
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorGT_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceGT_;
+ e->u.operator.as = FFEEXPR_operatorassociativityGT_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeREL_EQ:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFORMAT:
+ ffebad_start (FFEBAD_FORMAT_EXPR_TOKEN);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ break;
+
+ default:
+ break;
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorEQ_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceEQ_;
+ e->u.operator.as = FFEEXPR_operatorassociativityEQ_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeREL_NE:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFORMAT:
+ ffebad_start (FFEBAD_FORMAT_EXPR_TOKEN);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ break;
+
+ default:
+ break;
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorNE_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceNE_;
+ e->u.operator.as = FFEEXPR_operatorassociativityNE_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeREL_LE:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFORMAT:
+ ffebad_start (FFEBAD_FORMAT_EXPR_TOKEN);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ break;
+
+ default:
+ break;
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorLE_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceLE_;
+ e->u.operator.as = FFEEXPR_operatorassociativityLE_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typeREL_GE:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextFORMAT:
+ ffebad_start (FFEBAD_FORMAT_EXPR_TOKEN);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ break;
+
+ default:
+ break;
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorGE_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceGE_;
+ e->u.operator.as = FFEEXPR_operatorassociativityGE_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_;
+
+ case FFELEX_typePERIOD:
+ ffeexpr_tokens_[0] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_binary_period_;
+
+#if 0
+ case FFELEX_typeOPEN_PAREN:
+ case FFELEX_typeCLOSE_PAREN:
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+#endif
+ default:
+ return (ffelexHandler) ffeexpr_finished_ (t);
+ }
+}
+
+/* ffeexpr_token_binary_period_ -- Binary PERIOD
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle a period detected at binary (expecting binary op or end) state.
+ Must begin a dot-dot name, of which .NOT., .TRUE., and .FALSE. are not
+ valid. */
+
+static ffelexHandler
+ffeexpr_token_binary_period_ (ffelexToken t)
+{
+ ffeexprExpr_ operand;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffeexpr_current_dotdot_ = ffestr_other (t);
+ switch (ffeexpr_current_dotdot_)
+ {
+ case FFESTR_otherTRUE:
+ case FFESTR_otherFALSE:
+ case FFESTR_otherNOT:
+ if (ffest_ffebad_start (FFEBAD_MISSING_BINARY_OPERATOR))
+ {
+ operand = ffeexpr_stack_->exprstack;
+ assert (operand != NULL);
+ assert (operand->type == FFEEXPR_exprtypeOPERAND_);
+ ffebad_here (0, ffelex_token_where_line (operand->token), ffelex_token_where_column (operand->token));
+ ffebad_here (1, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ return (ffelexHandler) ffeexpr_token_binary_sw_per_;
+
+ default:
+ ffeexpr_tokens_[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_binary_end_per_;
+ }
+ break; /* Nothing really reaches here. */
+
+ default:
+ if (ffest_ffebad_start (FFEBAD_IGNORING_PERIOD))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ }
+}
+
+/* ffeexpr_token_binary_end_per_ -- Binary PERIOD NAME(not NOT, TRUE, or FALSE)
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Expecting a period to close a dot-dot at binary (binary op
+ or operator) state. If period isn't found, issue a diagnostic but
+ pretend we saw one. ffeexpr_current_dotdot_ must already contained the
+ dotdot representation of the name in between the two PERIOD tokens. */
+
+static ffelexHandler
+ffeexpr_token_binary_end_per_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffeexpr_tokens_[0];
+
+ switch (ffeexpr_current_dotdot_)
+ {
+ case FFESTR_otherAND:
+ e->u.operator.op = FFEEXPR_operatorAND_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceAND_;
+ e->u.operator.as = FFEEXPR_operatorassociativityAND_;
+ break;
+
+ case FFESTR_otherOR:
+ e->u.operator.op = FFEEXPR_operatorOR_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceOR_;
+ e->u.operator.as = FFEEXPR_operatorassociativityOR_;
+ break;
+
+ case FFESTR_otherXOR:
+ e->u.operator.op = FFEEXPR_operatorXOR_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceXOR_;
+ e->u.operator.as = FFEEXPR_operatorassociativityXOR_;
+ break;
+
+ case FFESTR_otherEQV:
+ e->u.operator.op = FFEEXPR_operatorEQV_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceEQV_;
+ e->u.operator.as = FFEEXPR_operatorassociativityEQV_;
+ break;
+
+ case FFESTR_otherNEQV:
+ e->u.operator.op = FFEEXPR_operatorNEQV_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceNEQV_;
+ e->u.operator.as = FFEEXPR_operatorassociativityNEQV_;
+ break;
+
+ case FFESTR_otherLT:
+ e->u.operator.op = FFEEXPR_operatorLT_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceLT_;
+ e->u.operator.as = FFEEXPR_operatorassociativityLT_;
+ break;
+
+ case FFESTR_otherLE:
+ e->u.operator.op = FFEEXPR_operatorLE_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceLE_;
+ e->u.operator.as = FFEEXPR_operatorassociativityLE_;
+ break;
+
+ case FFESTR_otherEQ:
+ e->u.operator.op = FFEEXPR_operatorEQ_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceEQ_;
+ e->u.operator.as = FFEEXPR_operatorassociativityEQ_;
+ break;
+
+ case FFESTR_otherNE:
+ e->u.operator.op = FFEEXPR_operatorNE_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceNE_;
+ e->u.operator.as = FFEEXPR_operatorassociativityNE_;
+ break;
+
+ case FFESTR_otherGT:
+ e->u.operator.op = FFEEXPR_operatorGT_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceGT_;
+ e->u.operator.as = FFEEXPR_operatorassociativityGT_;
+ break;
+
+ case FFESTR_otherGE:
+ e->u.operator.op = FFEEXPR_operatorGE_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceGE_;
+ e->u.operator.as = FFEEXPR_operatorassociativityGE_;
+ break;
+
+ default:
+ if (ffest_ffebad_start (FFEBAD_INVALID_DOTDOT))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_string (ffelex_token_text (ffeexpr_tokens_[1]));
+ ffebad_finish ();
+ }
+ e->u.operator.op = FFEEXPR_operatorEQ_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceEQ_;
+ e->u.operator.as = FFEEXPR_operatorassociativityEQ_;
+ break;
+ }
+
+ ffeexpr_exprstack_push_binary_ (e);
+
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ {
+ if (ffest_ffebad_start (FFEBAD_INSERTING_PERIOD))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_string (ffelex_token_text (ffeexpr_tokens_[1]));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_tokens_[1]); /* Kill dot-dot token. */
+ return (ffelexHandler) ffeexpr_token_rhs_ (t);
+ }
+
+ ffelex_token_kill (ffeexpr_tokens_[1]); /* Kill dot-dot token. */
+ return (ffelexHandler) ffeexpr_token_rhs_;
+}
+
+/* ffeexpr_token_binary_sw_per_ -- Rhs PERIOD NAME(NOT, TRUE, or FALSE)
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ A diagnostic has already been issued; just swallow a period if there is
+ one, then continue with ffeexpr_token_binary_. */
+
+static ffelexHandler
+ffeexpr_token_binary_sw_per_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) != FFELEX_typePERIOD)
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+
+ return (ffelexHandler) ffeexpr_token_binary_;
+}
+
+/* ffeexpr_token_quote_ -- Rhs QUOTE
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Expecting a NUMBER that we'll treat as an octal integer. */
+
+static ffelexHandler
+ffeexpr_token_quote_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+ ffebld anyexpr;
+
+ if (ffelex_token_type (t) != FFELEX_typeNUMBER)
+ {
+ if (ffest_ffebad_start (FFEBAD_QUOTE_MISSES_DIGITS))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ return (ffelexHandler) ffeexpr_token_rhs_ (t);
+ }
+
+ /* This is kind of a kludge to prevent any whining about magical numbers
+ that start out as these octal integers, so "20000000000 (on a 32-bit
+ 2's-complement machine) by itself won't produce an error. */
+
+ anyexpr = ffebld_new_any ();
+ ffebld_set_info (anyexpr, ffeinfo_new_any ());
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_tokens_[0];
+ e->u.operand = ffebld_new_conter_with_orig
+ (ffebld_constant_new_integeroctal (t), anyexpr);
+ ffebld_set_info (e->u.operand, ffeinfo_new (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT, FFETARGET_charactersizeNONE));
+ ffeexpr_exprstack_push_operand_ (e);
+ return (ffelexHandler) ffeexpr_token_binary_;
+}
+
+/* ffeexpr_token_apostrophe_ -- Rhs APOSTROPHE
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle an open-apostrophe, which begins either a character ('char-const'),
+ typeless octal ('octal-const'O), or typeless hexadecimal ('hex-const'Z or
+ 'hex-const'X) constant. */
+
+static ffelexHandler
+ffeexpr_token_apostrophe_ (ffelexToken t)
+{
+ assert (ffelex_token_type (t) == FFELEX_typeCHARACTER);
+ if (ffe_is_pedantic_not_90 () && (ffelex_token_length (t) == 0))
+ {
+ ffebad_start (FFEBAD_NULL_CHAR_CONST);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ ffeexpr_tokens_[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_apos_char_;
+}
+
+/* ffeexpr_token_apos_char_ -- Rhs APOSTROPHE CHARACTER
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Close-apostrophe is implicit; if this token is NAME, it is a possible
+ typeless-constant radix specifier. */
+
+static ffelexHandler
+ffeexpr_token_apos_char_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+ ffeinfo ni;
+ char c;
+ ffetargetCharacterSize size;
+
+ if ((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNAMES))
+ {
+ if ((ffelex_token_length (t) == 1)
+ && (ffesrc_char_match_init ((c = ffelex_token_text (t)[0]), 'B',
+ 'b')
+ || ffesrc_char_match_init (c, 'O', 'o')
+ || ffesrc_char_match_init (c, 'X', 'x')
+ || ffesrc_char_match_init (c, 'Z', 'z')))
+ {
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_tokens_[0];
+ switch (c)
+ {
+ case FFESRC_CASE_MATCH_INIT ('B', 'b', match_b, no_match):
+ e->u.operand = ffebld_new_conter
+ (ffebld_constant_new_typeless_bv (ffeexpr_tokens_[1]));
+ size = ffetarget_size_typeless_binary (ffeexpr_tokens_[1]);
+ break;
+
+ case FFESRC_CASE_MATCH_INIT ('O', 'o', match_o, no_match):
+ e->u.operand = ffebld_new_conter
+ (ffebld_constant_new_typeless_ov (ffeexpr_tokens_[1]));
+ size = ffetarget_size_typeless_octal (ffeexpr_tokens_[1]);
+ break;
+
+ case FFESRC_CASE_MATCH_INIT ('X', 'x', match_x, no_match):
+ e->u.operand = ffebld_new_conter
+ (ffebld_constant_new_typeless_hxv (ffeexpr_tokens_[1]));
+ size = ffetarget_size_typeless_hex (ffeexpr_tokens_[1]);
+ break;
+
+ case FFESRC_CASE_MATCH_INIT ('Z', 'z', match_z, no_match):
+ e->u.operand = ffebld_new_conter
+ (ffebld_constant_new_typeless_hzv (ffeexpr_tokens_[1]));
+ size = ffetarget_size_typeless_hex (ffeexpr_tokens_[1]);
+ break;
+
+ default:
+ no_match: /* :::::::::::::::::::: */
+ assert ("not BOXZ!" == NULL);
+ size = 0;
+ break;
+ }
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeTYPELESS, FFEINFO_kindtypeNONE,
+ 0, FFEINFO_kindENTITY, FFEINFO_whereCONSTANT, size));
+ ffeexpr_exprstack_push_operand_ (e);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+ }
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_tokens_[0];
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_characterdefault
+ (ffeexpr_tokens_[1]));
+ ni = ffeinfo_new (FFEINFO_basictypeCHARACTER, FFEINFO_kindtypeCHARACTERDEFAULT,
+ 0, FFEINFO_kindENTITY, FFEINFO_whereCONSTANT,
+ ffelex_token_length (ffeexpr_tokens_[1]));
+ ffebld_set_info (e->u.operand, ni);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffeexpr_exprstack_push_operand_ (e);
+ if ((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNAMES))
+ {
+ if (ffest_ffebad_start (FFEBAD_INVALID_RADIX_SPECIFIER))
+ {
+ ffebad_string (ffelex_token_text (t));
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_finish ();
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeBINARY_;
+ e->token = ffelex_token_use (t);
+ e->u.operator.op = FFEEXPR_operatorCONCATENATE_;
+ e->u.operator.prec = FFEEXPR_operatorprecedenceCONCATENATE_;
+ e->u.operator.as = FFEEXPR_operatorassociativityCONCATENATE_;
+ ffeexpr_exprstack_push_binary_ (e);
+ return (ffelexHandler) ffeexpr_token_rhs_ (t);
+ }
+ ffeexpr_is_substr_ok_ = !ffe_is_pedantic_not_90 (); /* Allow "'hello'(3:5)". */
+ return (ffelexHandler) ffeexpr_token_substrp_ (t);
+}
+
+/* ffeexpr_token_name_lhs_ -- Lhs NAME
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle a name followed by open-paren, period (RECORD.MEMBER), percent
+ (RECORD%MEMBER), or nothing at all. */
+
+static ffelexHandler
+ffeexpr_token_name_lhs_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+ ffeexprParenType_ paren_type;
+ ffesymbol s;
+ ffebld expr;
+ ffeinfo info;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextASSIGN:
+ case FFEEXPR_contextAGOTO:
+ case FFEEXPR_contextFILEUNIT_DF:
+ goto just_name; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffelex_token_use (ffeexpr_tokens_[0]);
+ s = ffeexpr_declare_parenthesized_ (ffeexpr_tokens_[0], FALSE,
+ &paren_type);
+
+ switch (ffesymbol_where (s))
+ {
+ case FFEINFO_whereLOCAL:
+ if (ffeexpr_stack_->context == FFEEXPR_contextSUBROUTINEREF)
+ ffesymbol_error (s, ffeexpr_tokens_[0]); /* Recursion. */
+ break;
+
+ case FFEINFO_whereINTRINSIC:
+ case FFEINFO_whereGLOBAL:
+ if (ffeexpr_stack_->context != FFEEXPR_contextSUBROUTINEREF)
+ ffesymbol_error (s, ffeexpr_tokens_[0]); /* Can call intrin. */
+ break;
+
+ case FFEINFO_whereCOMMON:
+ case FFEINFO_whereDUMMY:
+ case FFEINFO_whereRESULT:
+ break;
+
+ case FFEINFO_whereNONE:
+ case FFEINFO_whereANY:
+ break;
+
+ default:
+ ffesymbol_error (s, ffeexpr_tokens_[0]);
+ break;
+ }
+
+ if (ffesymbol_attrs (s) & FFESYMBOL_attrsANY)
+ {
+ e->u.operand = ffebld_new_any ();
+ ffebld_set_info (e->u.operand, ffeinfo_new_any ());
+ }
+ else
+ {
+ e->u.operand = ffebld_new_symter (s,
+ ffesymbol_generic (s),
+ ffesymbol_specific (s),
+ ffesymbol_implementation (s));
+ ffebld_set_info (e->u.operand, ffesymbol_info (s));
+ }
+ ffeexpr_exprstack_push_ (e); /* Not a complete operand yet. */
+ ffeexpr_stack_->tokens[0] = ffeexpr_tokens_[0];
+ switch (paren_type)
+ {
+ case FFEEXPR_parentypeSUBROUTINE_:
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextACTUALARG_,
+ ffeexpr_token_arguments_);
+
+ case FFEEXPR_parentypeARRAY_:
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ ffeexpr_stack_->bound_list = ffesymbol_dims (s);
+ ffeexpr_stack_->rank = 0;
+ ffeexpr_stack_->constant = TRUE;
+ ffeexpr_stack_->immediate = TRUE;
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextDATAIMPDOINDEX_,
+ ffeexpr_token_elements_);
+
+ case FFEEXPR_contextEQUIVALENCE:
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextEQVINDEX_,
+ ffeexpr_token_elements_);
+
+ default:
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextINDEX_,
+ ffeexpr_token_elements_);
+ }
+
+ case FFEEXPR_parentypeSUBSTRING_:
+ e->u.operand = ffeexpr_collapse_symter (e->u.operand,
+ ffeexpr_tokens_[0]);
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextINDEX_,
+ ffeexpr_token_substring_);
+
+ case FFEEXPR_parentypeEQUIVALENCE_:
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ ffeexpr_stack_->bound_list = ffesymbol_dims (s);
+ ffeexpr_stack_->rank = 0;
+ ffeexpr_stack_->constant = TRUE;
+ ffeexpr_stack_->immediate = TRUE;
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextEQVINDEX_,
+ ffeexpr_token_equivalence_);
+
+ case FFEEXPR_parentypeFUNCTION_: /* Invalid case. */
+ case FFEEXPR_parentypeFUNSUBSTR_: /* Invalid case. */
+ ffesymbol_error (s, ffeexpr_tokens_[0]);
+ /* Fall through. */
+ case FFEEXPR_parentypeANY_:
+ e->u.operand = ffebld_new_any ();
+ ffebld_set_info (e->u.operand, ffeinfo_new_any ());
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextACTUALARG_,
+ ffeexpr_token_anything_);
+
+ default:
+ assert ("bad paren type" == NULL);
+ break;
+ }
+
+ case FFELEX_typeEQUALS: /* As in "VAR=". */
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextIMPDOITEM_: /* within
+ "(,VAR=start,end[,incr])". */
+ case FFEEXPR_contextIMPDOITEMDF_:
+ ffeexpr_stack_->context = FFEEXPR_contextIMPDOCTRL_;
+ break;
+
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ ffeexpr_stack_->context = FFEEXPR_contextDATAIMPDOCTRL_;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+#if 0
+ case FFELEX_typePERIOD:
+ case FFELEX_typePERCENT:
+ assert ("FOO%, FOO. not yet supported!~~" == NULL);
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+just_name: /* :::::::::::::::::::: */
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_tokens_[0];
+ s = ffeexpr_declare_unadorned_ (ffeexpr_tokens_[0],
+ (ffeexpr_stack_->context
+ == FFEEXPR_contextSUBROUTINEREF));
+
+ switch (ffesymbol_where (s))
+ {
+ case FFEINFO_whereCONSTANT:
+ if ((ffeexpr_stack_->context != FFEEXPR_contextPARAMETER)
+ || (ffesymbol_kind (s) != FFEINFO_kindENTITY))
+ ffesymbol_error (s, ffeexpr_tokens_[0]);
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ if ((ffeexpr_stack_->context != FFEEXPR_contextDATAIMPDOCTRL_)
+ && (ffeexpr_stack_->context != FFEEXPR_contextDATAIMPDOINDEX_))
+ ffesymbol_error (s, ffeexpr_tokens_[0]);
+ break;
+
+ case FFEINFO_whereLOCAL:
+ if (ffeexpr_stack_->context == FFEEXPR_contextSUBROUTINEREF)
+ ffesymbol_error (s, ffeexpr_tokens_[0]); /* Recurse!. */
+ break;
+
+ case FFEINFO_whereINTRINSIC:
+ if (ffeexpr_stack_->context != FFEEXPR_contextSUBROUTINEREF)
+ ffesymbol_error (s, ffeexpr_tokens_[0]); /* Can call intrin. */
+ break;
+
+ default:
+ break;
+ }
+
+ if (ffesymbol_attrs (s) & FFESYMBOL_attrsANY)
+ {
+ expr = ffebld_new_any ();
+ info = ffeinfo_new_any ();
+ ffebld_set_info (expr, info);
+ }
+ else
+ {
+ expr = ffebld_new_symter (s,
+ ffesymbol_generic (s),
+ ffesymbol_specific (s),
+ ffesymbol_implementation (s));
+ info = ffesymbol_info (s);
+ ffebld_set_info (expr, info);
+ if (ffesymbol_is_doiter (s))
+ {
+ ffebad_start (FFEBAD_DOITER);
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffest_ffebad_here_doiter (1, s);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ }
+ expr = ffeexpr_collapse_symter (expr, ffeexpr_tokens_[0]);
+ }
+
+ if (ffeexpr_stack_->context == FFEEXPR_contextSUBROUTINEREF)
+ {
+ if (ffebld_op (expr) == FFEBLD_opANY)
+ {
+ expr = ffebld_new_any ();
+ ffebld_set_info (expr, ffeinfo_new_any ());
+ }
+ else
+ {
+ expr = ffebld_new_subrref (expr, NULL); /* No argument list. */
+ if (ffesymbol_generic (s) != FFEINTRIN_genNONE)
+ ffeintrin_fulfill_generic (&expr, &info, e->token);
+ else if (ffesymbol_specific (s) != FFEINTRIN_specNONE)
+ ffeintrin_fulfill_specific (&expr, &info, NULL, e->token);
+ else
+ ffeexpr_fulfill_call_ (&expr, e->token);
+
+ if (ffebld_op (expr) != FFEBLD_opANY)
+ ffebld_set_info (expr,
+ ffeinfo_new (ffeinfo_basictype (info),
+ ffeinfo_kindtype (info),
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereFLEETING,
+ ffeinfo_size (info)));
+ else
+ ffebld_set_info (expr, ffeinfo_new_any ());
+ }
+ }
+
+ e->u.operand = expr;
+ ffeexpr_exprstack_push_operand_ (e);
+ return (ffelexHandler) ffeexpr_finished_ (t);
+}
+
+/* ffeexpr_token_name_arg_ -- Rhs NAME
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle first token in an actual-arg (or possible actual-arg) context
+ being a NAME, and use second token to refine the context. */
+
+static ffelexHandler
+ffeexpr_token_name_arg_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ case FFELEX_typeCOMMA:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARG_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARG_;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextINDEXORACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ ffeexpr_stack_->context = FFEEXPR_contextSFUNCDEFACTUALARGEXPR_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ ffeexpr_stack_->context
+ = FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_;
+ break;
+
+ default:
+ assert ("bad context in _name_arg_" == NULL);
+ break;
+ }
+ break;
+ }
+
+ return (ffelexHandler) ffeexpr_token_name_rhs_ (t);
+}
+
+/* ffeexpr_token_name_rhs_ -- Rhs NAME
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle a name followed by open-paren, apostrophe (O'octal-const',
+ Z'hex-const', or X'hex-const'), period (RECORD.MEMBER).
+
+ 26-Nov-91 JCB 1.2
+ When followed by apostrophe or quote, set lex hexnum flag on so
+ [0-9] as first char of next token seen as starting a potentially
+ hex number (NAME).
+ 04-Oct-91 JCB 1.1
+ In case of intrinsic, decorate its SYMTER with the type info for
+ the specific intrinsic. */
+
+static ffelexHandler
+ffeexpr_token_name_rhs_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+ ffeexprParenType_ paren_type;
+ ffesymbol s;
+ bool sfdef;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeQUOTE:
+ case FFELEX_typeAPOSTROPHE:
+ ffeexpr_tokens_[1] = ffelex_token_use (t);
+ ffelex_set_hexnum (TRUE);
+ return (ffelexHandler) ffeexpr_token_name_apos_;
+
+ case FFELEX_typeOPEN_PAREN:
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffelex_token_use (ffeexpr_tokens_[0]);
+ s = ffeexpr_declare_parenthesized_ (ffeexpr_tokens_[0], TRUE,
+ &paren_type);
+ if (ffesymbol_attrs (s) & FFESYMBOL_attrsANY)
+ e->u.operand = ffebld_new_any ();
+ else
+ e->u.operand = ffebld_new_symter (s, ffesymbol_generic (s),
+ ffesymbol_specific (s),
+ ffesymbol_implementation (s));
+ ffeexpr_exprstack_push_ (e); /* Not a complete operand yet. */
+ ffeexpr_stack_->tokens[0] = ffeexpr_tokens_[0];
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ {
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ case FFEEXPR_contextSFUNCDEFACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_:
+ sfdef = TRUE;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ assert ("weird context!" == NULL);
+ sfdef = FALSE;
+ break;
+
+ default:
+ sfdef = FALSE;
+ break;
+ }
+ switch (paren_type)
+ {
+ case FFEEXPR_parentypeFUNCTION_:
+ ffebld_set_info (e->u.operand, ffesymbol_info (s));
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ if (ffesymbol_where (s) == FFEINFO_whereCONSTANT)
+ { /* A statement function. */
+ ffeexpr_stack_->num_args
+ = ffebld_list_length
+ (ffeexpr_stack_->next_dummy
+ = ffesymbol_dummyargs (s));
+ ffeexpr_stack_->tokens[1] = NULL; /* !=NULL when > num_args. */
+ }
+ else if ((ffesymbol_where (s) == FFEINFO_whereINTRINSIC)
+ && !ffe_is_pedantic_not_90 ()
+ && ((ffesymbol_implementation (s)
+ == FFEINTRIN_impICHAR)
+ || (ffesymbol_implementation (s)
+ == FFEINTRIN_impIACHAR)
+ || (ffesymbol_implementation (s)
+ == FFEINTRIN_impLEN)))
+ { /* Allow arbitrary concatenations. */
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ sfdef
+ ? FFEEXPR_contextSFUNCDEF
+ : FFEEXPR_contextLET,
+ ffeexpr_token_arguments_);
+ }
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ sfdef
+ ? FFEEXPR_contextSFUNCDEFACTUALARG_
+ : FFEEXPR_contextACTUALARG_,
+ ffeexpr_token_arguments_);
+
+ case FFEEXPR_parentypeARRAY_:
+ ffebld_set_info (e->u.operand,
+ ffesymbol_info (ffebld_symter (e->u.operand)));
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ ffeexpr_stack_->bound_list = ffesymbol_dims (s);
+ ffeexpr_stack_->rank = 0;
+ ffeexpr_stack_->constant = TRUE;
+ ffeexpr_stack_->immediate = TRUE;
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ sfdef
+ ? FFEEXPR_contextSFUNCDEFINDEX_
+ : FFEEXPR_contextINDEX_,
+ ffeexpr_token_elements_);
+
+ case FFEEXPR_parentypeSUBSTRING_:
+ ffebld_set_info (e->u.operand,
+ ffesymbol_info (ffebld_symter (e->u.operand)));
+ e->u.operand = ffeexpr_collapse_symter (e->u.operand,
+ ffeexpr_tokens_[0]);
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ sfdef
+ ? FFEEXPR_contextSFUNCDEFINDEX_
+ : FFEEXPR_contextINDEX_,
+ ffeexpr_token_substring_);
+
+ case FFEEXPR_parentypeFUNSUBSTR_:
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ sfdef
+ ? FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_
+ : FFEEXPR_contextINDEXORACTUALARG_,
+ ffeexpr_token_funsubstr_);
+
+ case FFEEXPR_parentypeANY_:
+ ffebld_set_info (e->u.operand, ffesymbol_info (s));
+ return
+ (ffelexHandler)
+ ffeexpr_rhs (ffeexpr_stack_->pool,
+ sfdef
+ ? FFEEXPR_contextSFUNCDEFACTUALARG_
+ : FFEEXPR_contextACTUALARG_,
+ ffeexpr_token_anything_);
+
+ default:
+ assert ("bad paren type" == NULL);
+ break;
+ }
+
+ case FFELEX_typeEQUALS: /* As in "VAR=". */
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextIMPDOITEM_: /* "(,VAR=start,end[,incr])". */
+ case FFEEXPR_contextIMPDOITEMDF_:
+ ffeexpr_stack_->is_rhs = FALSE; /* Really an lhs construct. */
+ ffeexpr_stack_->context = FFEEXPR_contextIMPDOCTRL_;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+#if 0
+ case FFELEX_typePERIOD:
+ case FFELEX_typePERCENT:
+ ~~Support these two someday, though not required
+ assert ("FOO%, FOO. not yet supported!~~" == NULL);
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ assert ("strange context" == NULL);
+ break;
+
+ default:
+ break;
+ }
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_tokens_[0];
+ s = ffeexpr_declare_unadorned_ (ffeexpr_tokens_[0], FALSE);
+ if (ffesymbol_attrs (s) & FFESYMBOL_attrsANY)
+ {
+ e->u.operand = ffebld_new_any ();
+ ffebld_set_info (e->u.operand, ffeinfo_new_any ());
+ }
+ else
+ {
+ e->u.operand = ffebld_new_symter (s, FFEINTRIN_genNONE,
+ ffesymbol_specific (s),
+ ffesymbol_implementation (s));
+ if (ffesymbol_specific (s) == FFEINTRIN_specNONE)
+ ffebld_set_info (e->u.operand, ffeinfo_use (ffesymbol_info (s)));
+ else
+ { /* Decorate the SYMTER with the actual type
+ of the intrinsic. */
+ ffebld_set_info (e->u.operand, ffeinfo_new
+ (ffeintrin_basictype (ffesymbol_specific (s)),
+ ffeintrin_kindtype (ffesymbol_specific (s)),
+ 0,
+ ffesymbol_kind (s),
+ ffesymbol_where (s),
+ FFETARGET_charactersizeNONE));
+ }
+ if (ffesymbol_is_doiter (s))
+ ffebld_symter_set_is_doiter (e->u.operand, TRUE);
+ e->u.operand = ffeexpr_collapse_symter (e->u.operand,
+ ffeexpr_tokens_[0]);
+ }
+ ffeexpr_exprstack_push_operand_ (e);
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+}
+
+/* ffeexpr_token_name_apos_ -- Rhs NAME APOSTROPHE
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Expecting a NAME token, analyze the previous NAME token to see what kind,
+ if any, typeless constant we've got.
+
+ 01-Sep-90 JCB 1.1
+ Expect a NAME instead of CHARACTER in this situation. */
+
+static ffelexHandler
+ffeexpr_token_name_apos_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+
+ ffelex_set_hexnum (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffeexpr_tokens_[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_name_apos_name_;
+
+ default:
+ break;
+ }
+
+ if (ffest_ffebad_start (FFEBAD_INVALID_RADIX_SPECIFIER))
+ {
+ ffebad_string (ffelex_token_text (ffeexpr_tokens_[0]));
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_here (1, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->u.operand = ffebld_new_any ();
+ ffebld_set_info (e->u.operand, ffeinfo_new_any ());
+ e->token = ffeexpr_tokens_[0];
+ ffeexpr_exprstack_push_operand_ (e);
+
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+}
+
+/* ffeexpr_token_name_apos_name_ -- Rhs NAME APOSTROPHE NAME
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Expecting an APOSTROPHE token, analyze the previous NAME token to see
+ what kind, if any, typeless constant we've got. */
+
+static ffelexHandler
+ffeexpr_token_name_apos_name_ (ffelexToken t)
+{
+ ffeexprExpr_ e;
+ char c;
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->token = ffeexpr_tokens_[0];
+
+ if ((ffelex_token_type (t) == ffelex_token_type (ffeexpr_tokens_[1]))
+ && (ffelex_token_length (ffeexpr_tokens_[0]) == 1)
+ && (ffesrc_char_match_init ((c = ffelex_token_text (ffeexpr_tokens_[0])[0]),
+ 'B', 'b')
+ || ffesrc_char_match_init (c, 'O', 'o')
+ || ffesrc_char_match_init (c, 'X', 'x')
+ || ffesrc_char_match_init (c, 'Z', 'z')))
+ {
+ ffetargetCharacterSize size;
+
+ if (!ffe_is_typeless_boz ()) {
+
+ switch (c)
+ {
+ case FFESRC_CASE_MATCH_INIT ('B', 'b', imatch_b, no_imatch):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_integerbinary
+ (ffeexpr_tokens_[2]));
+ break;
+
+ case FFESRC_CASE_MATCH_INIT ('O', 'o', imatch_o, no_imatch):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_integeroctal
+ (ffeexpr_tokens_[2]));
+ break;
+
+ case FFESRC_CASE_MATCH_INIT ('X', 'x', imatch_x, no_imatch):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_integerhex
+ (ffeexpr_tokens_[2]));
+ break;
+
+ case FFESRC_CASE_MATCH_INIT ('Z', 'z', imatch_z, no_imatch):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_integerhex
+ (ffeexpr_tokens_[2]));
+ break;
+
+ default:
+ no_imatch: /* :::::::::::::::::::: */
+ assert ("not BOXZ!" == NULL);
+ abort ();
+ }
+
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0,
+ FFEINFO_kindENTITY, FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ ffeexpr_exprstack_push_operand_ (e);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+ }
+
+ switch (c)
+ {
+ case FFESRC_CASE_MATCH_INIT ('B', 'b', match_b, no_match):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_typeless_bm
+ (ffeexpr_tokens_[2]));
+ size = ffetarget_size_typeless_binary (ffeexpr_tokens_[2]);
+ break;
+
+ case FFESRC_CASE_MATCH_INIT ('O', 'o', match_o, no_match):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_typeless_om
+ (ffeexpr_tokens_[2]));
+ size = ffetarget_size_typeless_octal (ffeexpr_tokens_[2]);
+ break;
+
+ case FFESRC_CASE_MATCH_INIT ('X', 'x', match_x, no_match):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_typeless_hxm
+ (ffeexpr_tokens_[2]));
+ size = ffetarget_size_typeless_hex (ffeexpr_tokens_[2]);
+ break;
+
+ case FFESRC_CASE_MATCH_INIT ('Z', 'z', match_z, no_match):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_typeless_hzm
+ (ffeexpr_tokens_[2]));
+ size = ffetarget_size_typeless_hex (ffeexpr_tokens_[2]);
+ break;
+
+ default:
+ no_match: /* :::::::::::::::::::: */
+ assert ("not BOXZ!" == NULL);
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_typeless_hzm
+ (ffeexpr_tokens_[2]));
+ size = ffetarget_size_typeless_hex (ffeexpr_tokens_[2]);
+ break;
+ }
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeTYPELESS, FFEINFO_kindtypeNONE,
+ 0, FFEINFO_kindENTITY, FFEINFO_whereCONSTANT, size));
+ ffeexpr_exprstack_push_operand_ (e);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+ return (ffelexHandler) ffeexpr_token_binary_;
+ }
+
+ if (ffest_ffebad_start (FFEBAD_INVALID_RADIX_SPECIFIER))
+ {
+ ffebad_string (ffelex_token_text (ffeexpr_tokens_[0]));
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[2]);
+
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ e->u.operand = ffebld_new_any ();
+ ffebld_set_info (e->u.operand, ffeinfo_new_any ());
+ e->token = ffeexpr_tokens_[0];
+ ffeexpr_exprstack_push_operand_ (e);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeAPOSTROPHE:
+ case FFELEX_typeQUOTE:
+ return (ffelexHandler) ffeexpr_token_binary_;
+
+ default:
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+ }
+}
+
+/* ffeexpr_token_percent_ -- Rhs PERCENT
+
+ Handle a percent sign possibly followed by "LOC". If followed instead
+ by "VAL", "REF", or "DESCR", issue an error message and substitute
+ "LOC". If followed by something else, treat the percent sign as a
+ spurious incorrect token and reprocess the token via _rhs_. */
+
+static ffelexHandler
+ffeexpr_token_percent_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffeexpr_stack_->percent = ffeexpr_percent_ (t);
+ ffeexpr_tokens_[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_token_percent_name_;
+
+ default:
+ if (ffest_ffebad_start (FFEBAD_INVALID_TOKEN_IN_EXPRESSION))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->first_token),
+ ffelex_token_where_column (ffeexpr_stack_->first_token));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ return (ffelexHandler) ffeexpr_token_rhs_ (t);
+ }
+}
+
+/* ffeexpr_token_percent_name_ -- Rhs PERCENT NAME
+
+ Make sure the token is OPEN_PAREN and prepare for the one-item list of
+ LHS expressions. Else display an error message. */
+
+static ffelexHandler
+ffeexpr_token_percent_name_ (ffelexToken t)
+{
+ ffelexHandler nexthandler;
+
+ if (ffelex_token_type (t) != FFELEX_typeOPEN_PAREN)
+ {
+ if (ffest_ffebad_start (FFEBAD_INVALID_TOKEN_IN_EXPRESSION))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->first_token),
+ ffelex_token_where_column (ffeexpr_stack_->first_token));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_tokens_[0]);
+ nexthandler = (ffelexHandler) ffeexpr_token_rhs_ (ffeexpr_tokens_[1]);
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ return (ffelexHandler) (*nexthandler) (t);
+ }
+
+ switch (ffeexpr_stack_->percent)
+ {
+ default:
+ if (ffest_ffebad_start (FFEBAD_INVALID_PERCENT))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_tokens_[0]),
+ ffelex_token_where_column (ffeexpr_tokens_[0]));
+ ffebad_string (ffelex_token_text (ffeexpr_tokens_[1]));
+ ffebad_finish ();
+ }
+ ffeexpr_stack_->percent = FFEEXPR_percentLOC_;
+ /* Fall through. */
+ case FFEEXPR_percentLOC_:
+ ffeexpr_stack_->tokens[0] = ffeexpr_tokens_[0];
+ ffelex_token_kill (ffeexpr_tokens_[1]);
+ ffeexpr_stack_->tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextLOC_,
+ ffeexpr_cb_end_loc_);
+ }
+}
+
+/* ffeexpr_make_float_const_ -- Make a floating-point constant
+
+ See prototype.
+
+ Pass 'E', 'D', or 'Q' for exponent letter. */
+
+static void
+ffeexpr_make_float_const_ (char exp_letter, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits)
+{
+ ffeexprExpr_ e;
+
+ e = ffeexpr_expr_new_ ();
+ e->type = FFEEXPR_exprtypeOPERAND_;
+ if (integer != NULL)
+ e->token = ffelex_token_use (integer);
+ else
+ {
+ assert (decimal != NULL);
+ e->token = ffelex_token_use (decimal);
+ }
+
+ switch (exp_letter)
+ {
+#if !FFETARGET_okREALQUAD
+ case FFESRC_CASE_MATCH_INIT ('Q', 'q', match_q, no_match):
+ if (ffebad_start (FFEBAD_QUAD_UNSUPPORTED))
+ {
+ ffebad_here (0, ffelex_token_where_line (e->token),
+ ffelex_token_where_column (e->token));
+ ffebad_finish ();
+ }
+ goto match_d; /* The FFESRC_CASE_* macros don't
+ allow fall-through! */
+#endif
+
+ case FFESRC_CASE_MATCH_INIT ('D', 'd', match_d, no_match):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_realdouble
+ (integer, decimal, fraction, exponent, exponent_sign, exponent_digits));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeREAL, FFEINFO_kindtypeREALDOUBLE,
+ 0, FFEINFO_kindENTITY, FFEINFO_whereCONSTANT, FFETARGET_charactersizeNONE));
+ break;
+
+ case FFESRC_CASE_MATCH_INIT ('E', 'e', match_e, no_match):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_realdefault
+ (integer, decimal, fraction, exponent, exponent_sign, exponent_digits));
+ ffebld_set_info (e->u.operand, ffeinfo_new (FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREALDEFAULT, 0, FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT, FFETARGET_charactersizeNONE));
+ break;
+
+#if FFETARGET_okREALQUAD
+ case FFESRC_CASE_MATCH_INIT ('Q', 'q', match_q, no_match):
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_realquad
+ (integer, decimal, fraction, exponent, exponent_sign, exponent_digits));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeREAL, FFEINFO_kindtypeREALQUAD,
+ 0, FFEINFO_kindENTITY, FFEINFO_whereCONSTANT, FFETARGET_charactersizeNONE));
+ break;
+#endif
+
+ case 'I': /* Make an integer. */
+ e->u.operand = ffebld_new_conter (ffebld_constant_new_integerdefault
+ (ffeexpr_tokens_[0]));
+ ffebld_set_info (e->u.operand,
+ ffeinfo_new (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0,
+ FFEINFO_kindENTITY, FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ break;
+
+ default:
+ no_match: /* :::::::::::::::::::: */
+ assert ("Lost the exponent letter!" == NULL);
+ }
+
+ ffeexpr_exprstack_push_operand_ (e);
+}
+
+/* Just like ffesymbol_declare_local, except performs any implicit info
+ assignment necessary. */
+
+static ffesymbol
+ffeexpr_declare_unadorned_ (ffelexToken t, bool maybe_intrin)
+{
+ ffesymbol s;
+ ffeinfoKind k;
+ bool bad;
+
+ s = ffesymbol_declare_local (t, maybe_intrin);
+
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ /* Special-case these since they can involve a different concept
+ of "state" (in the stmtfunc name space). */
+ {
+ case FFEEXPR_contextDATAIMPDOINDEX_:
+ case FFEEXPR_contextDATAIMPDOCTRL_:
+ if (ffeexpr_context_outer_ (ffeexpr_stack_)
+ == FFEEXPR_contextDATAIMPDOINDEX_)
+ s = ffeexpr_sym_impdoitem_ (s, t);
+ else
+ if (ffeexpr_stack_->is_rhs)
+ s = ffeexpr_sym_impdoitem_ (s, t);
+ else
+ s = ffeexpr_sym_lhs_impdoctrl_ (s, t);
+ bad = (ffesymbol_kind (s) != FFEINFO_kindENTITY)
+ || ((ffesymbol_where (s) != FFEINFO_whereCONSTANT)
+ && (ffesymbol_where (s) != FFEINFO_whereIMMEDIATE));
+ if (bad && (ffesymbol_kind (s) != FFEINFO_kindANY))
+ ffesymbol_error (s, t);
+ return s;
+
+ default:
+ break;
+ }
+
+ switch ((ffesymbol_sfdummyparent (s) == NULL)
+ ? ffesymbol_state (s)
+ : FFESYMBOL_stateUNDERSTOOD)
+ {
+ case FFESYMBOL_stateNONE: /* Before first exec, not seen in expr
+ context. */
+ if (!ffest_seen_first_exec ())
+ goto seen; /* :::::::::::::::::::: */
+ /* Fall through. */
+ case FFESYMBOL_stateUNCERTAIN: /* Unseen since first exec. */
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ {
+ case FFEEXPR_contextSUBROUTINEREF:
+ s = ffeexpr_sym_lhs_call_ (s, t);
+ break;
+
+ case FFEEXPR_contextFILEEXTFUNC:
+ s = ffeexpr_sym_lhs_extfunc_ (s, t);
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ s = ffecom_sym_exec_transition (s);
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ goto understood; /* :::::::::::::::::::: */
+ /* Fall through. */
+ case FFEEXPR_contextACTUALARG_:
+ s = ffeexpr_sym_rhs_actualarg_ (s, t);
+ break;
+
+ case FFEEXPR_contextDATA:
+ if (ffeexpr_stack_->is_rhs)
+ s = ffeexpr_sym_rhs_let_ (s, t);
+ else
+ s = ffeexpr_sym_lhs_data_ (s, t);
+ break;
+
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ s = ffeexpr_sym_lhs_data_ (s, t);
+ break;
+
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ case FFEEXPR_contextSFUNCDEFACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_:
+ s = ffecom_sym_exec_transition (s);
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ goto understood; /* :::::::::::::::::::: */
+ /* Fall through. */
+ case FFEEXPR_contextLET:
+ case FFEEXPR_contextPAREN_:
+ case FFEEXPR_contextACTUALARGEXPR_:
+ case FFEEXPR_contextINDEXORACTUALARGEXPR_:
+ case FFEEXPR_contextASSIGN:
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextDO:
+ case FFEEXPR_contextDOWHILE:
+ case FFEEXPR_contextAGOTO:
+ case FFEEXPR_contextCGOTO:
+ case FFEEXPR_contextIF:
+ case FFEEXPR_contextARITHIF:
+ case FFEEXPR_contextFORMAT:
+ case FFEEXPR_contextSTOP:
+ case FFEEXPR_contextRETURN:
+ case FFEEXPR_contextSELECTCASE:
+ case FFEEXPR_contextCASE:
+ case FFEEXPR_contextFILEASSOC:
+ case FFEEXPR_contextFILEINT:
+ case FFEEXPR_contextFILEDFINT:
+ case FFEEXPR_contextFILELOG:
+ case FFEEXPR_contextFILENUM:
+ case FFEEXPR_contextFILENUMAMBIG:
+ case FFEEXPR_contextFILECHAR:
+ case FFEEXPR_contextFILENUMCHAR:
+ case FFEEXPR_contextFILEDFCHAR:
+ case FFEEXPR_contextFILEKEY:
+ case FFEEXPR_contextFILEUNIT:
+ case FFEEXPR_contextFILEUNIT_DF:
+ case FFEEXPR_contextFILEUNITAMBIG:
+ case FFEEXPR_contextFILEFORMAT:
+ case FFEEXPR_contextFILENAMELIST:
+ case FFEEXPR_contextFILEVXTCODE:
+ case FFEEXPR_contextINDEX_:
+ case FFEEXPR_contextIMPDOITEM_:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ case FFEEXPR_contextIMPDOCTRL_:
+ case FFEEXPR_contextLOC_:
+ if (ffeexpr_stack_->is_rhs)
+ s = ffeexpr_sym_rhs_let_ (s, t);
+ else
+ s = ffeexpr_sym_lhs_let_ (s, t);
+ break;
+
+ case FFEEXPR_contextCHARACTERSIZE:
+ case FFEEXPR_contextEQUIVALENCE:
+ case FFEEXPR_contextINCLUDE:
+ case FFEEXPR_contextPARAMETER:
+ case FFEEXPR_contextDIMLIST:
+ case FFEEXPR_contextDIMLISTCOMMON:
+ case FFEEXPR_contextKINDTYPE:
+ case FFEEXPR_contextINITVAL:
+ case FFEEXPR_contextEQVINDEX_:
+ break; /* Will turn into errors below. */
+
+ default:
+ ffesymbol_error (s, t);
+ break;
+ }
+ /* Fall through. */
+ case FFESYMBOL_stateUNDERSTOOD: /* Nothing much more to learn. */
+ understood: /* :::::::::::::::::::: */
+ k = ffesymbol_kind (s);
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ {
+ case FFEEXPR_contextSUBROUTINEREF:
+ bad = ((k != FFEINFO_kindSUBROUTINE)
+ && ((ffesymbol_where (s) != FFEINFO_whereINTRINSIC)
+ || (k != FFEINFO_kindNONE)));
+ break;
+
+ case FFEEXPR_contextFILEEXTFUNC:
+ bad = (k != FFEINFO_kindFUNCTION)
+ || (ffesymbol_where (s) != FFEINFO_whereGLOBAL);
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ case FFEEXPR_contextACTUALARG_:
+ switch (k)
+ {
+ case FFEINFO_kindENTITY:
+ bad = FALSE;
+ break;
+
+ case FFEINFO_kindFUNCTION:
+ case FFEINFO_kindSUBROUTINE:
+ bad
+ = ((ffesymbol_where (s) != FFEINFO_whereGLOBAL)
+ && (ffesymbol_where (s) != FFEINFO_whereDUMMY)
+ && ((ffesymbol_where (s) != FFEINFO_whereINTRINSIC)
+ || !ffeintrin_is_actualarg (ffesymbol_specific (s))));
+ break;
+
+ case FFEINFO_kindNONE:
+ if (ffesymbol_where (s) == FFEINFO_whereINTRINSIC)
+ {
+ bad = !(ffeintrin_is_actualarg (ffesymbol_specific (s)));
+ break;
+ }
+
+ /* If state is UNDERSTOOD here, it's CHAR*(*) or attrsANY,
+ and in the former case, attrsTYPE is set, so we
+ see this as an error as we should, since CHAR*(*)
+ cannot be actually referenced in a main/block data
+ program unit. */
+
+ if ((ffesymbol_attrs (s) & (FFESYMBOL_attrsANY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE))
+ == FFESYMBOL_attrsEXTERNAL)
+ bad = FALSE;
+ else
+ bad = TRUE;
+ break;
+
+ default:
+ bad = TRUE;
+ break;
+ }
+ break;
+
+ case FFEEXPR_contextDATA:
+ if (ffeexpr_stack_->is_rhs)
+ bad = (k != FFEINFO_kindENTITY)
+ || (ffesymbol_where (s) != FFEINFO_whereCONSTANT);
+ else
+ bad = (k != FFEINFO_kindENTITY)
+ || ((ffesymbol_where (s) != FFEINFO_whereNONE)
+ && (ffesymbol_where (s) != FFEINFO_whereLOCAL)
+ && (ffesymbol_where (s) != FFEINFO_whereCOMMON));
+ break;
+
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ bad = TRUE; /* Unadorned item never valid. */
+ break;
+
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ case FFEEXPR_contextSFUNCDEFACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_:
+ case FFEEXPR_contextLET:
+ case FFEEXPR_contextPAREN_:
+ case FFEEXPR_contextACTUALARGEXPR_:
+ case FFEEXPR_contextINDEXORACTUALARGEXPR_:
+ case FFEEXPR_contextASSIGN:
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextDO:
+ case FFEEXPR_contextDOWHILE:
+ case FFEEXPR_contextAGOTO:
+ case FFEEXPR_contextCGOTO:
+ case FFEEXPR_contextIF:
+ case FFEEXPR_contextARITHIF:
+ case FFEEXPR_contextFORMAT:
+ case FFEEXPR_contextSTOP:
+ case FFEEXPR_contextRETURN:
+ case FFEEXPR_contextSELECTCASE:
+ case FFEEXPR_contextCASE:
+ case FFEEXPR_contextFILEASSOC:
+ case FFEEXPR_contextFILEINT:
+ case FFEEXPR_contextFILEDFINT:
+ case FFEEXPR_contextFILELOG:
+ case FFEEXPR_contextFILENUM:
+ case FFEEXPR_contextFILENUMAMBIG:
+ case FFEEXPR_contextFILECHAR:
+ case FFEEXPR_contextFILENUMCHAR:
+ case FFEEXPR_contextFILEDFCHAR:
+ case FFEEXPR_contextFILEKEY:
+ case FFEEXPR_contextFILEUNIT:
+ case FFEEXPR_contextFILEUNIT_DF:
+ case FFEEXPR_contextFILEUNITAMBIG:
+ case FFEEXPR_contextFILEFORMAT:
+ case FFEEXPR_contextFILENAMELIST:
+ case FFEEXPR_contextFILEVXTCODE:
+ case FFEEXPR_contextINDEX_:
+ case FFEEXPR_contextIMPDOITEM_:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ case FFEEXPR_contextIMPDOCTRL_:
+ case FFEEXPR_contextLOC_:
+ bad = (k != FFEINFO_kindENTITY); /* This catches "SUBROUTINE
+ X(A);EXTERNAL A;CALL
+ Y(A);B=A", for example. */
+ break;
+
+ case FFEEXPR_contextCHARACTERSIZE:
+ case FFEEXPR_contextEQUIVALENCE:
+ case FFEEXPR_contextPARAMETER:
+ case FFEEXPR_contextDIMLIST:
+ case FFEEXPR_contextDIMLISTCOMMON:
+ case FFEEXPR_contextKINDTYPE:
+ case FFEEXPR_contextINITVAL:
+ case FFEEXPR_contextEQVINDEX_:
+ bad = (k != FFEINFO_kindENTITY)
+ || (ffesymbol_where (s) != FFEINFO_whereCONSTANT);
+ break;
+
+ case FFEEXPR_contextINCLUDE:
+ bad = TRUE;
+ break;
+
+ default:
+ bad = TRUE;
+ break;
+ }
+ if (bad && (k != FFEINFO_kindANY))
+ ffesymbol_error (s, t);
+ return s;
+
+ case FFESYMBOL_stateSEEN: /* Seen but not yet in exec portion. */
+ seen: /* :::::::::::::::::::: */
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ {
+ case FFEEXPR_contextPARAMETER:
+ if (ffeexpr_stack_->is_rhs)
+ ffesymbol_error (s, t);
+ else
+ s = ffeexpr_sym_lhs_parameter_ (s, t);
+ break;
+
+ case FFEEXPR_contextDATA:
+ s = ffecom_sym_exec_transition (s);
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ goto understood; /* :::::::::::::::::::: */
+ if (ffeexpr_stack_->is_rhs)
+ ffesymbol_error (s, t);
+ else
+ s = ffeexpr_sym_lhs_data_ (s, t);
+ goto understood; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ s = ffecom_sym_exec_transition (s);
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ goto understood; /* :::::::::::::::::::: */
+ s = ffeexpr_sym_lhs_data_ (s, t);
+ goto understood; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextEQUIVALENCE:
+ s = ffeexpr_sym_lhs_equivalence_ (s, t);
+ break;
+
+ case FFEEXPR_contextDIMLIST:
+ s = ffeexpr_sym_rhs_dimlist_ (s, t);
+ break;
+
+ case FFEEXPR_contextCHARACTERSIZE:
+ case FFEEXPR_contextKINDTYPE:
+ case FFEEXPR_contextDIMLISTCOMMON:
+ case FFEEXPR_contextINITVAL:
+ case FFEEXPR_contextEQVINDEX_:
+ ffesymbol_error (s, t);
+ break;
+
+ case FFEEXPR_contextINCLUDE:
+ ffesymbol_error (s, t);
+ break;
+
+ case FFEEXPR_contextACTUALARG_: /* E.g. I in REAL A(Y(I)). */
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ s = ffecom_sym_exec_transition (s);
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ goto understood; /* :::::::::::::::::::: */
+ s = ffeexpr_sym_rhs_actualarg_ (s, t);
+ goto understood; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextINDEX_:
+ case FFEEXPR_contextACTUALARGEXPR_:
+ case FFEEXPR_contextINDEXORACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ case FFEEXPR_contextSFUNCDEFACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_:
+ assert (ffeexpr_stack_->is_rhs);
+ s = ffecom_sym_exec_transition (s);
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ goto understood; /* :::::::::::::::::::: */
+ s = ffeexpr_sym_rhs_let_ (s, t);
+ goto understood; /* :::::::::::::::::::: */
+
+ default:
+ ffesymbol_error (s, t);
+ break;
+ }
+ return s;
+
+ default:
+ assert ("bad symbol state" == NULL);
+ return NULL;
+ break;
+ }
+}
+
+/* Have FOO in DATA (XYZ(FOO),...)/.../ or DATA (...,XYZ=FOO,BAR,BLETCH).
+ Could be found via the "statement-function" name space (in which case
+ it should become an iterator) or the local name space (in which case
+ it should be either a named constant, or a variable that will have an
+ sfunc name space sibling that should become an iterator). */
+
+static ffesymbol
+ffeexpr_sym_impdoitem_ (ffesymbol sp, ffelexToken t)
+{
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffesymbolState ss;
+ ffesymbolState ns;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+
+ ss = ffesymbol_state (sp);
+
+ if (ffesymbol_sfdummyparent (sp) != NULL)
+ { /* Have symbol in sfunc name space. */
+ switch (ss)
+ {
+ case FFESYMBOL_stateNONE: /* Used as iterator already. */
+ if (ffeexpr_level_ < ffesymbol_maxentrynum (sp))
+ ffesymbol_error (sp, t); /* Can't use dead iterator. */
+ else
+ { /* Can use dead iterator because we're at at
+ least an innermore (higher-numbered) level
+ than the iterator's outermost
+ (lowest-numbered) level. */
+ ffesymbol_signal_change (sp);
+ ffesymbol_set_state (sp, FFESYMBOL_stateSEEN);
+ ffesymbol_set_maxentrynum (sp, ffeexpr_level_);
+ ffesymbol_signal_unreported (sp);
+ }
+ break;
+
+ case FFESYMBOL_stateSEEN: /* Seen already in this or other
+ implied-DO. Set symbol level
+ number to outermost value, as that
+ tells us we can see it as iterator
+ at that level at the innermost. */
+ if (ffeexpr_level_ < ffesymbol_maxentrynum (sp))
+ {
+ ffesymbol_signal_change (sp);
+ ffesymbol_set_maxentrynum (sp, ffeexpr_level_);
+ ffesymbol_signal_unreported (sp);
+ }
+ break;
+
+ case FFESYMBOL_stateUNCERTAIN: /* Iterator. */
+ assert (ffeexpr_level_ == ffesymbol_maxentrynum (sp));
+ ffesymbol_error (sp, t); /* (,,,I=I,10). */
+ break;
+
+ case FFESYMBOL_stateUNDERSTOOD:
+ break; /* ANY. */
+
+ default:
+ assert ("Foo Bar!!" == NULL);
+ break;
+ }
+
+ return sp;
+ }
+
+ /* Got symbol in local name space, so we haven't seen it in impdo yet.
+ First, if it is brand-new and we're in executable statements, set the
+ attributes and exec-transition it to set state UNCERTAIN or UNDERSTOOD.
+ Second, if it is now a constant (PARAMETER), then just return it, it
+ can't be an implied-do iterator. If it is understood, complain if it is
+ not a valid variable, but make the inner name space iterator anyway and
+ return that. If it is not understood, improve understanding of the
+ symbol accordingly, complain accordingly, in either case make the inner
+ name space iterator and return that. */
+
+ sa = ffesymbol_attrs (sp);
+
+ if (ffesymbol_state_is_specable (ss)
+ && ffest_seen_first_exec ())
+ {
+ assert (sa == FFESYMBOL_attrsetNONE);
+ ffesymbol_signal_change (sp);
+ ffesymbol_set_state (sp, FFESYMBOL_stateSEEN);
+ ffesymbol_resolve_intrin (sp);
+ if (ffeimplic_establish_symbol (sp))
+ ffesymbol_set_attr (sp, FFESYMBOL_attrSFARG);
+ else
+ ffesymbol_error (sp, t);
+
+ /* After the exec transition, the state will either be UNCERTAIN (could
+ be a dummy or local var) or UNDERSTOOD (local var, because this is a
+ PROGRAM/BLOCKDATA program unit). */
+
+ sp = ffecom_sym_exec_transition (sp);
+ sa = ffesymbol_attrs (sp);
+ ss = ffesymbol_state (sp);
+ }
+
+ ns = ss;
+ kind = ffesymbol_kind (sp);
+ where = ffesymbol_where (sp);
+
+ if (ss == FFESYMBOL_stateUNDERSTOOD)
+ {
+ if (kind != FFEINFO_kindENTITY)
+ ffesymbol_error (sp, t);
+ if (where == FFEINFO_whereCONSTANT)
+ return sp;
+ }
+ else
+ {
+ /* Enhance understanding of local symbol. This used to imply exec
+ transition, but that doesn't seem necessary, since the local symbol
+ doesn't actually get put into an ffebld tree here -- we just learn
+ more about it, just like when we see a local symbol's name in the
+ dummy-arg list of a statement function. */
+
+ if (ss != FFESYMBOL_stateUNCERTAIN)
+ {
+ /* Figure out what kind of object we've got based on previous
+ declarations of or references to the object. */
+
+ ns = FFESYMBOL_stateSEEN;
+
+ if (sa & FFESYMBOL_attrsANY)
+ na = sa;
+ else if (!(sa & ~(FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsANY
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsRESULT
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)))
+ na = sa | FFESYMBOL_attrsSFARG;
+ else
+ na = FFESYMBOL_attrsetNONE;
+ }
+ else
+ { /* stateUNCERTAIN. */
+ na = sa | FFESYMBOL_attrsSFARG;
+ ns = FFESYMBOL_stateUNDERSTOOD;
+
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ if (sa & FFESYMBOL_attrsEXTERNAL)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ na = FFESYMBOL_attrsetNONE;
+ }
+ else if (sa & FFESYMBOL_attrsDUMMY)
+ {
+ assert (!(sa & FFESYMBOL_attrsEXTERNAL)); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = FFEINFO_kindENTITY;
+ }
+ else if (sa & FFESYMBOL_attrsARRAY)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsTYPE)));
+
+ na = FFESYMBOL_attrsetNONE;
+ }
+ else if (sa & FFESYMBOL_attrsSFARG)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ ns = FFESYMBOL_stateUNCERTAIN;
+ }
+ else if (sa & FFESYMBOL_attrsTYPE)
+ {
+ assert (!(sa & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsTYPE
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG)));
+
+ kind = FFEINFO_kindENTITY;
+
+ if (sa & (FFESYMBOL_attrsADJUSTABLE | FFESYMBOL_attrsANYLEN))
+ na = FFESYMBOL_attrsetNONE;
+ else if (ffest_is_entry_valid ())
+ ns = FFESYMBOL_stateUNCERTAIN; /* Could be DUMMY or LOCAL. */
+ else
+ where = FFEINFO_whereLOCAL;
+ }
+ else
+ na = FFESYMBOL_attrsetNONE; /* Error. */
+ }
+
+ /* Now see what we've got for a new object: NONE means a new error
+ cropped up; ANY means an old error to be ignored; otherwise,
+ everything's ok, update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (sp, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_signal_change (sp); /* May need to back up to previous
+ version. */
+ if (!ffeimplic_establish_symbol (sp))
+ ffesymbol_error (sp, t);
+ else
+ {
+ ffesymbol_set_info (sp,
+ ffeinfo_new (ffesymbol_basictype (sp),
+ ffesymbol_kindtype (sp),
+ ffesymbol_rank (sp),
+ kind,
+ where,
+ ffesymbol_size (sp)));
+ ffesymbol_set_attrs (sp, na);
+ ffesymbol_set_state (sp, ns);
+ ffesymbol_resolve_intrin (sp);
+ if (!ffesymbol_state_is_specable (ns))
+ sp = ffecom_sym_learned (sp);
+ ffesymbol_signal_unreported (sp); /* For debugging purposes. */
+ }
+ }
+ }
+
+ /* Here we create the sfunc-name-space symbol representing what should
+ become an iterator in this name space at this or an outermore (lower-
+ numbered) expression level, else the implied-DO construct is in error. */
+
+ s = ffesymbol_declare_sfdummy (t); /* Sets maxentrynum to 0 for new obj;
+ also sets sfa_dummy_parent to
+ parent symbol. */
+ assert (sp == ffesymbol_sfdummyparent (s));
+
+ ffesymbol_signal_change (s);
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_set_maxentrynum (s, ffeexpr_level_);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereIMMEDIATE,
+ FFETARGET_charactersizeNONE));
+ ffesymbol_signal_unreported (s);
+
+ if (((ffesymbol_basictype (sp) != FFEINFO_basictypeINTEGER)
+ && (ffesymbol_basictype (sp) != FFEINFO_basictypeANY))
+ || ((ffesymbol_kindtype (sp) != FFEINFO_kindtypeINTEGERDEFAULT)
+ && (ffesymbol_kindtype (sp) != FFEINFO_kindtypeANY)))
+ ffesymbol_error (s, t);
+
+ return s;
+}
+
+/* Have FOO in CALL FOO. Local name space, executable context only. */
+
+static ffesymbol
+ffeexpr_sym_lhs_call_ (ffesymbol s, ffelexToken t)
+{
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+ ffeintrinGen gen;
+ ffeintrinSpec spec;
+ ffeintrinImp imp;
+ bool error = FALSE;
+
+ assert ((ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ || (ffesymbol_state (s) == FFESYMBOL_stateUNCERTAIN));
+
+ na = sa = ffesymbol_attrs (s);
+
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = ffesymbol_kind (s);
+ where = ffesymbol_where (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (sa & FFESYMBOL_attrsEXTERNAL)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ if (sa & FFESYMBOL_attrsTYPE)
+ error = TRUE;
+ else
+ /* Not TYPE. */
+ {
+ kind = FFEINFO_kindSUBROUTINE;
+
+ if (sa & FFESYMBOL_attrsDUMMY)
+ ; /* Not TYPE. */
+ else if (sa & FFESYMBOL_attrsACTUALARG)
+ ; /* Not DUMMY or TYPE. */
+ else /* Not ACTUALARG, DUMMY, or TYPE. */
+ where = FFEINFO_whereGLOBAL;
+ }
+ }
+ else if (sa & FFESYMBOL_attrsDUMMY)
+ {
+ assert (!(sa & FFESYMBOL_attrsEXTERNAL)); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ if (sa & FFESYMBOL_attrsTYPE)
+ error = TRUE;
+ else
+ kind = FFEINFO_kindSUBROUTINE;
+ }
+ else if (sa & FFESYMBOL_attrsARRAY)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsTYPE)));
+
+ error = TRUE;
+ }
+ else if (sa & FFESYMBOL_attrsSFARG)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ error = TRUE;
+ }
+ else if (sa & FFESYMBOL_attrsTYPE)
+ {
+ assert (!(sa & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsTYPE
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG)));
+
+ error = TRUE;
+ }
+ else if (sa == FFESYMBOL_attrsetNONE)
+ {
+ assert (ffesymbol_state (s) == FFESYMBOL_stateNONE);
+
+ if (ffeintrin_is_intrinsic (ffesymbol_text (s), t, FALSE,
+ &gen, &spec, &imp))
+ {
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ ffesymbol_set_generic (s, gen);
+ ffesymbol_set_specific (s, spec);
+ ffesymbol_set_implementation (s, imp);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindSUBROUTINE,
+ FFEINFO_whereINTRINSIC,
+ FFETARGET_charactersizeNONE));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ ffesymbol_reference (s, t, FALSE);
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+
+ return s;
+ }
+
+ kind = FFEINFO_kindSUBROUTINE;
+ where = FFEINFO_whereGLOBAL;
+ }
+ else
+ error = TRUE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (error)
+ ffesymbol_error (s, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ kind, /* SUBROUTINE. */
+ where, /* GLOBAL or DUMMY. */
+ ffesymbol_size (s)));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ ffesymbol_reference (s, t, FALSE);
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* Have FOO in DATA FOO/.../. Local name space and executable context
+ only. (This will change in the future when DATA FOO may be followed
+ by COMMON FOO or even INTEGER FOO(10), etc.) */
+
+static ffesymbol
+ffeexpr_sym_lhs_data_ (ffesymbol s, ffelexToken t)
+{
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+ bool error = FALSE;
+
+ assert ((ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ || (ffesymbol_state (s) == FFESYMBOL_stateUNCERTAIN));
+
+ na = sa = ffesymbol_attrs (s);
+
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = ffesymbol_kind (s);
+ where = ffesymbol_where (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (sa & FFESYMBOL_attrsEXTERNAL)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ error = TRUE;
+ }
+ else if (sa & FFESYMBOL_attrsDUMMY)
+ {
+ assert (!(sa & FFESYMBOL_attrsEXTERNAL)); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ error = TRUE;
+ }
+ else if (sa & FFESYMBOL_attrsARRAY)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsTYPE)));
+
+ if (sa & FFESYMBOL_attrsADJUSTABLE)
+ error = TRUE;
+ where = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsSFARG)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ where = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsTYPE)
+ {
+ assert (!(sa & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsTYPE
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG)));
+
+ if (sa & (FFESYMBOL_attrsADJUSTABLE | FFESYMBOL_attrsANYLEN))
+ error = TRUE;
+ else
+ {
+ kind = FFEINFO_kindENTITY;
+ where = FFEINFO_whereLOCAL;
+ }
+ }
+ else if (sa == FFESYMBOL_attrsetNONE)
+ {
+ assert (ffesymbol_state (s) == FFESYMBOL_stateNONE);
+ kind = FFEINFO_kindENTITY;
+ where = FFEINFO_whereLOCAL;
+ }
+ else
+ error = TRUE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (error)
+ ffesymbol_error (s, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ if (!ffeimplic_establish_symbol (s))
+ {
+ ffesymbol_error (s, t);
+ return s;
+ }
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ kind, /* ENTITY. */
+ where, /* LOCAL. */
+ ffesymbol_size (s)));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* Have FOO in EQUIVALENCE (...,FOO,...). Does not include
+ EQUIVALENCE (...,BAR(FOO),...). */
+
+static ffesymbol
+ffeexpr_sym_lhs_equivalence_ (ffesymbol s, ffelexToken t)
+{
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+
+ na = sa = ffesymbol_attrs (s);
+ kind = FFEINFO_kindENTITY;
+ where = ffesymbol_where (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (!(sa & ~(FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)))
+ na = sa | FFESYMBOL_attrsEQUIV;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Don't know why we're bothering to set kind and where in this code, but
+ added the following to make it complete, in case it's really important.
+ Generally this is left up to symbol exec transition. */
+
+ if (where == FFEINFO_whereNONE)
+ {
+ if (na & (FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsCOMMON))
+ where = FFEINFO_whereCOMMON;
+ else if (na & FFESYMBOL_attrsSAVE)
+ where = FFEINFO_whereLOCAL;
+ }
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ kind, /* Always ENTITY. */
+ where, /* NONE, COMMON, or LOCAL. */
+ ffesymbol_size (s)));
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_resolve_intrin (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* Have FOO in OPEN(...,USEROPEN=FOO,...). Executable context only.
+
+ Note that I think this should be considered semantically similar to
+ doing CALL XYZ(FOO), in that it should be considered like an
+ ACTUALARG context. In particular, without EXTERNAL being specified,
+ it should not be allowed. */
+
+static ffesymbol
+ffeexpr_sym_lhs_extfunc_ (ffesymbol s, ffelexToken t)
+{
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+ bool needs_type = FALSE;
+ bool error = FALSE;
+
+ assert ((ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ || (ffesymbol_state (s) == FFESYMBOL_stateUNCERTAIN));
+
+ na = sa = ffesymbol_attrs (s);
+
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = ffesymbol_kind (s);
+ where = ffesymbol_where (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (sa & FFESYMBOL_attrsEXTERNAL)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ if (sa & FFESYMBOL_attrsTYPE)
+ where = FFEINFO_whereGLOBAL;
+ else
+ /* Not TYPE. */
+ {
+ kind = FFEINFO_kindFUNCTION;
+ needs_type = TRUE;
+
+ if (sa & FFESYMBOL_attrsDUMMY)
+ ; /* Not TYPE. */
+ else if (sa & FFESYMBOL_attrsACTUALARG)
+ ; /* Not DUMMY or TYPE. */
+ else /* Not ACTUALARG, DUMMY, or TYPE. */
+ where = FFEINFO_whereGLOBAL;
+ }
+ }
+ else if (sa & FFESYMBOL_attrsDUMMY)
+ {
+ assert (!(sa & FFESYMBOL_attrsEXTERNAL)); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = FFEINFO_kindFUNCTION;
+ if (!(sa & FFESYMBOL_attrsTYPE))
+ needs_type = TRUE;
+ }
+ else if (sa & FFESYMBOL_attrsARRAY)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsTYPE)));
+
+ error = TRUE;
+ }
+ else if (sa & FFESYMBOL_attrsSFARG)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ error = TRUE;
+ }
+ else if (sa & FFESYMBOL_attrsTYPE)
+ {
+ assert (!(sa & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsTYPE
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG)));
+
+ if (sa & (FFESYMBOL_attrsADJUSTABLE | FFESYMBOL_attrsANYLEN))
+ error = TRUE;
+ else
+ {
+ kind = FFEINFO_kindFUNCTION;
+ where = FFEINFO_whereGLOBAL;
+ }
+ }
+ else if (sa == FFESYMBOL_attrsetNONE)
+ {
+ assert (ffesymbol_state (s) == FFESYMBOL_stateNONE);
+ kind = FFEINFO_kindFUNCTION;
+ where = FFEINFO_whereGLOBAL;
+ needs_type = TRUE;
+ }
+ else
+ error = TRUE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (error)
+ ffesymbol_error (s, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ if (needs_type && !ffeimplic_establish_symbol (s))
+ {
+ ffesymbol_error (s, t);
+ return s;
+ }
+ if (!ffesymbol_explicitwhere (s))
+ {
+ ffebad_start (FFEBAD_NEED_EXTERNAL);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ ffesymbol_set_explicitwhere (s, TRUE);
+ }
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ kind, /* FUNCTION. */
+ where, /* GLOBAL or DUMMY. */
+ ffesymbol_size (s)));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ ffesymbol_reference (s, t, FALSE);
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* Have FOO in DATA (stuff,FOO=1,10)/.../. */
+
+static ffesymbol
+ffeexpr_sym_lhs_impdoctrl_ (ffesymbol s, ffelexToken t)
+{
+ ffesymbolState ss;
+
+ /* If the symbol isn't in the sfunc name space, pretend as though we saw a
+ reference to it already within the imp-DO construct at this level, so as
+ to get a symbol that is in the sfunc name space. But this is an
+ erroneous construct, and should be caught elsewhere. */
+
+ if (ffesymbol_sfdummyparent (s) == NULL)
+ {
+ s = ffeexpr_sym_impdoitem_ (s, t);
+ if (ffesymbol_sfdummyparent (s) == NULL)
+ { /* PARAMETER FOO...DATA (A(I),FOO=...). */
+ ffesymbol_error (s, t);
+ return s;
+ }
+ }
+
+ ss = ffesymbol_state (s);
+
+ switch (ss)
+ {
+ case FFESYMBOL_stateNONE: /* Used as iterator already. */
+ if (ffeexpr_level_ < ffesymbol_maxentrynum (s))
+ ffesymbol_error (s, t); /* Can't reuse dead iterator. F90 disallows
+ this; F77 allows it but it is a stupid
+ feature. */
+ else
+ { /* Can use dead iterator because we're at at
+ least a innermore (higher-numbered) level
+ than the iterator's outermost
+ (lowest-numbered) level. This should be
+ diagnosed later, because it means an item
+ in this list didn't reference this
+ iterator. */
+#if 1
+ ffesymbol_error (s, t); /* For now, complain. */
+#else /* Someday will detect all cases where initializer doesn't reference
+ all applicable iterators, in which case reenable this code. */
+ ffesymbol_signal_change (s);
+ ffesymbol_set_state (s, FFESYMBOL_stateUNCERTAIN);
+ ffesymbol_set_maxentrynum (s, ffeexpr_level_);
+ ffesymbol_signal_unreported (s);
+#endif
+ }
+ break;
+
+ case FFESYMBOL_stateSEEN: /* Seen already in this or other implied-DO.
+ If seen in outermore level, can't be an
+ iterator here, so complain. If not seen
+ at current level, complain for now,
+ because that indicates something F90
+ rejects (though we currently don't detect
+ all such cases for now). */
+ if (ffeexpr_level_ <= ffesymbol_maxentrynum (s))
+ {
+ ffesymbol_signal_change (s);
+ ffesymbol_set_state (s, FFESYMBOL_stateUNCERTAIN);
+ ffesymbol_signal_unreported (s);
+ }
+ else
+ ffesymbol_error (s, t);
+ break;
+
+ case FFESYMBOL_stateUNCERTAIN: /* Already iterator! */
+ assert ("DATA implied-DO control var seen twice!!" == NULL);
+ ffesymbol_error (s, t);
+ break;
+
+ case FFESYMBOL_stateUNDERSTOOD:
+ break; /* ANY. */
+
+ default:
+ assert ("Foo Bletch!!" == NULL);
+ break;
+ }
+
+ return s;
+}
+
+/* Have FOO in PARAMETER (FOO=...). */
+
+static ffesymbol
+ffeexpr_sym_lhs_parameter_ (ffesymbol s, ffelexToken t)
+{
+ ffesymbolAttrs sa;
+
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (sa & ~(FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsTYPE))
+ {
+ if (!(sa & FFESYMBOL_attrsANY))
+ ffesymbol_error (s, t);
+ }
+ else
+ {
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ if (!ffeimplic_establish_symbol (s))
+ {
+ ffesymbol_error (s, t);
+ return s;
+ }
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ ffesymbol_size (s)));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* Have FOO in CALL XYZ(...,FOO,...). Does not include any other
+ embedding of FOO, such as CALL XYZ((FOO)) or CALL XYZ(FOO+1). */
+
+static ffesymbol
+ffeexpr_sym_rhs_actualarg_ (ffesymbol s, ffelexToken t)
+{
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+ ffesymbolState ns;
+ bool needs_type = FALSE;
+
+ assert ((ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ || (ffesymbol_state (s) == FFESYMBOL_stateUNCERTAIN));
+
+ na = sa = ffesymbol_attrs (s);
+
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = ffesymbol_kind (s);
+ where = ffesymbol_where (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ ns = FFESYMBOL_stateUNDERSTOOD;
+
+ if (sa & FFESYMBOL_attrsEXTERNAL)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ if (sa & FFESYMBOL_attrsTYPE)
+ where = FFEINFO_whereGLOBAL;
+ else
+ /* Not TYPE. */
+ {
+ ns = FFESYMBOL_stateUNCERTAIN;
+
+ if (sa & FFESYMBOL_attrsDUMMY)
+ assert (kind == FFEINFO_kindNONE); /* FUNCTION, SUBROUTINE. */
+ else if (sa & FFESYMBOL_attrsACTUALARG)
+ ; /* Not DUMMY or TYPE. */
+ else
+ /* Not ACTUALARG, DUMMY, or TYPE. */
+ {
+ assert (kind == FFEINFO_kindNONE); /* FUNCTION, SUBROUTINE. */
+ na |= FFESYMBOL_attrsACTUALARG;
+ where = FFEINFO_whereGLOBAL;
+ }
+ }
+ }
+ else if (sa & FFESYMBOL_attrsDUMMY)
+ {
+ assert (!(sa & FFESYMBOL_attrsEXTERNAL)); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = FFEINFO_kindENTITY;
+ if (!(sa & FFESYMBOL_attrsTYPE))
+ needs_type = TRUE;
+ }
+ else if (sa & FFESYMBOL_attrsARRAY)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsTYPE)));
+
+ where = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsSFARG)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ where = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsTYPE)
+ {
+ assert (!(sa & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsTYPE
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG)));
+
+ if (sa & FFESYMBOL_attrsANYLEN)
+ ns = FFESYMBOL_stateNONE;
+ else
+ {
+ kind = FFEINFO_kindENTITY;
+ where = FFEINFO_whereLOCAL;
+ }
+ }
+ else if (sa == FFESYMBOL_attrsetNONE)
+ {
+ /* New state is left empty because there isn't any state flag to
+ set for this case, and it's UNDERSTOOD after all. */
+ assert (ffesymbol_state (s) == FFESYMBOL_stateNONE);
+ kind = FFEINFO_kindENTITY;
+ where = FFEINFO_whereLOCAL;
+ needs_type = TRUE;
+ }
+ else
+ ns = FFESYMBOL_stateNONE; /* Error. */
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (ns == FFESYMBOL_stateNONE)
+ ffesymbol_error (s, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ if (needs_type && !ffeimplic_establish_symbol (s))
+ {
+ ffesymbol_error (s, t);
+ return s;
+ }
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ kind,
+ where,
+ ffesymbol_size (s)));
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, ns);
+ s = ffecom_sym_learned (s);
+ ffesymbol_reference (s, t, FALSE);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* Have FOO in DIMENSION XYZ(FOO) or any array declarator containing
+ a reference to FOO. */
+
+static ffesymbol
+ffeexpr_sym_rhs_dimlist_ (ffesymbol s, ffelexToken t)
+{
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+
+ na = sa = ffesymbol_attrs (s);
+ kind = FFEINFO_kindENTITY;
+ where = ffesymbol_where (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (!(sa & ~(FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)))
+ na = sa | FFESYMBOL_attrsADJUSTS;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Since this symbol definitely is going into an expression (the
+ dimension-list for some dummy array, presumably), figure out WHERE if
+ possible. */
+
+ if (where == FFEINFO_whereNONE)
+ {
+ if (na & (FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST))
+ where = FFEINFO_whereCOMMON;
+ else if (na & FFESYMBOL_attrsDUMMY)
+ where = FFEINFO_whereDUMMY;
+ }
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ if (!ffeimplic_establish_symbol (s))
+ {
+ ffesymbol_error (s, t);
+ return s;
+ }
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ kind, /* Always ENTITY. */
+ where, /* NONE, COMMON, or DUMMY. */
+ ffesymbol_size (s)));
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_resolve_intrin (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* Have FOO in XYZ = ...FOO.... Does not include cases like FOO in
+ XYZ = BAR(FOO), as such cases are handled elsewhere. */
+
+static ffesymbol
+ffeexpr_sym_rhs_let_ (ffesymbol s, ffelexToken t)
+{
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+ bool error = FALSE;
+
+ assert ((ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ || (ffesymbol_state (s) == FFESYMBOL_stateUNCERTAIN));
+
+ na = sa = ffesymbol_attrs (s);
+
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = ffesymbol_kind (s);
+ where = ffesymbol_where (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (sa & FFESYMBOL_attrsEXTERNAL)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ error = TRUE;
+ }
+ else if (sa & FFESYMBOL_attrsDUMMY)
+ {
+ assert (!(sa & FFESYMBOL_attrsEXTERNAL)); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = FFEINFO_kindENTITY;
+ }
+ else if (sa & FFESYMBOL_attrsARRAY)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsTYPE)));
+
+ where = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsSFARG)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ where = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsTYPE)
+ {
+ assert (!(sa & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsTYPE
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG)));
+
+ if (sa & FFESYMBOL_attrsANYLEN)
+ error = TRUE;
+ else
+ {
+ kind = FFEINFO_kindENTITY;
+ where = FFEINFO_whereLOCAL;
+ }
+ }
+ else if (sa == FFESYMBOL_attrsetNONE)
+ {
+ assert (ffesymbol_state (s) == FFESYMBOL_stateNONE);
+ kind = FFEINFO_kindENTITY;
+ where = FFEINFO_whereLOCAL;
+ }
+ else
+ error = TRUE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (error)
+ ffesymbol_error (s, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ if (!ffeimplic_establish_symbol (s))
+ {
+ ffesymbol_error (s, t);
+ return s;
+ }
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ kind, /* ENTITY. */
+ where, /* LOCAL. */
+ ffesymbol_size (s)));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* ffeexpr_declare_parenthesized_ -- ffesymbol wrapper for NAME(...) operand
+
+ ffelexToken t;
+ bool maybe_intrin;
+ ffeexprParenType_ paren_type;
+ ffesymbol s;
+ s = ffeexpr_declare_parenthesized_ (t, maybe_intrin, &paren_type);
+
+ Just like ffesymbol_declare_local, except performs any implicit info
+ assignment necessary, and it returns the type of the parenthesized list
+ (list of function args, list of array args, or substring spec). */
+
+static ffesymbol
+ffeexpr_declare_parenthesized_ (ffelexToken t, bool maybe_intrin,
+ ffeexprParenType_ *paren_type)
+{
+ ffesymbol s;
+ ffesymbolState st; /* Effective state. */
+ ffeinfoKind k;
+ bool bad;
+
+ if (maybe_intrin && ffesrc_check_symbol ())
+ { /* Knock off some easy cases. */
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextSUBROUTINEREF:
+ case FFEEXPR_contextDATA:
+ case FFEEXPR_contextDATAIMPDOINDEX_:
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ case FFEEXPR_contextSFUNCDEFACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_:
+ case FFEEXPR_contextLET:
+ case FFEEXPR_contextPAREN_:
+ case FFEEXPR_contextACTUALARGEXPR_:
+ case FFEEXPR_contextINDEXORACTUALARGEXPR_:
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextDO:
+ case FFEEXPR_contextDOWHILE:
+ case FFEEXPR_contextACTUALARG_:
+ case FFEEXPR_contextCGOTO:
+ case FFEEXPR_contextIF:
+ case FFEEXPR_contextARITHIF:
+ case FFEEXPR_contextFORMAT:
+ case FFEEXPR_contextSTOP:
+ case FFEEXPR_contextRETURN:
+ case FFEEXPR_contextSELECTCASE:
+ case FFEEXPR_contextCASE:
+ case FFEEXPR_contextFILEASSOC:
+ case FFEEXPR_contextFILEINT:
+ case FFEEXPR_contextFILEDFINT:
+ case FFEEXPR_contextFILELOG:
+ case FFEEXPR_contextFILENUM:
+ case FFEEXPR_contextFILENUMAMBIG:
+ case FFEEXPR_contextFILECHAR:
+ case FFEEXPR_contextFILENUMCHAR:
+ case FFEEXPR_contextFILEDFCHAR:
+ case FFEEXPR_contextFILEKEY:
+ case FFEEXPR_contextFILEUNIT:
+ case FFEEXPR_contextFILEUNIT_DF:
+ case FFEEXPR_contextFILEUNITAMBIG:
+ case FFEEXPR_contextFILEFORMAT:
+ case FFEEXPR_contextFILENAMELIST:
+ case FFEEXPR_contextFILEVXTCODE:
+ case FFEEXPR_contextINDEX_:
+ case FFEEXPR_contextIMPDOITEM_:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ case FFEEXPR_contextIMPDOCTRL_:
+ case FFEEXPR_contextDATAIMPDOCTRL_:
+ case FFEEXPR_contextCHARACTERSIZE:
+ case FFEEXPR_contextPARAMETER:
+ case FFEEXPR_contextDIMLIST:
+ case FFEEXPR_contextDIMLISTCOMMON:
+ case FFEEXPR_contextKINDTYPE:
+ case FFEEXPR_contextINITVAL:
+ case FFEEXPR_contextEQVINDEX_:
+ break; /* These could be intrinsic invocations. */
+
+ case FFEEXPR_contextAGOTO:
+ case FFEEXPR_contextFILEFORMATNML:
+ case FFEEXPR_contextALLOCATE:
+ case FFEEXPR_contextDEALLOCATE:
+ case FFEEXPR_contextHEAPSTAT:
+ case FFEEXPR_contextNULLIFY:
+ case FFEEXPR_contextINCLUDE:
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ case FFEEXPR_contextLOC_:
+ case FFEEXPR_contextINDEXORACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ case FFEEXPR_contextPARENFILENUM_:
+ case FFEEXPR_contextPARENFILEUNIT_:
+ maybe_intrin = FALSE;
+ break; /* Can't be intrinsic invocation. */
+
+ default:
+ assert ("blah! blah! waaauuggh!" == NULL);
+ break;
+ }
+ }
+
+ s = ffesymbol_declare_local (t, maybe_intrin);
+
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ /* Special-case these since they can involve a different concept
+ of "state" (in the stmtfunc name space). */
+ {
+ case FFEEXPR_contextDATAIMPDOINDEX_:
+ case FFEEXPR_contextDATAIMPDOCTRL_:
+ if (ffeexpr_context_outer_ (ffeexpr_stack_)
+ == FFEEXPR_contextDATAIMPDOINDEX_)
+ s = ffeexpr_sym_impdoitem_ (s, t);
+ else
+ if (ffeexpr_stack_->is_rhs)
+ s = ffeexpr_sym_impdoitem_ (s, t);
+ else
+ s = ffeexpr_sym_lhs_impdoctrl_ (s, t);
+ if (ffesymbol_kind (s) != FFEINFO_kindANY)
+ ffesymbol_error (s, t);
+ return s;
+
+ default:
+ break;
+ }
+
+ switch ((ffesymbol_sfdummyparent (s) == NULL)
+ ? ffesymbol_state (s)
+ : FFESYMBOL_stateUNDERSTOOD)
+ {
+ case FFESYMBOL_stateNONE: /* Before first exec, not seen in expr
+ context. */
+ if (!ffest_seen_first_exec ())
+ goto seen; /* :::::::::::::::::::: */
+ /* Fall through. */
+ case FFESYMBOL_stateUNCERTAIN: /* Unseen since first exec. */
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ {
+ case FFEEXPR_contextSUBROUTINEREF:
+ s = ffeexpr_sym_lhs_call_ (s, t); /* "CALL FOO"=="CALL
+ FOO(...)". */
+ break;
+
+ case FFEEXPR_contextDATA:
+ if (ffeexpr_stack_->is_rhs)
+ s = ffeexpr_sym_rhs_let_ (s, t);
+ else
+ s = ffeexpr_sym_lhs_data_ (s, t);
+ break;
+
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ s = ffeexpr_sym_lhs_data_ (s, t);
+ break;
+
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ case FFEEXPR_contextSFUNCDEFACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_:
+ s = ffecom_sym_exec_transition (s);
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ goto understood; /* :::::::::::::::::::: */
+ /* Fall through. */
+ case FFEEXPR_contextLET:
+ case FFEEXPR_contextPAREN_:
+ case FFEEXPR_contextACTUALARGEXPR_:
+ case FFEEXPR_contextINDEXORACTUALARGEXPR_:
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextDO:
+ case FFEEXPR_contextDOWHILE:
+ case FFEEXPR_contextACTUALARG_:
+ case FFEEXPR_contextCGOTO:
+ case FFEEXPR_contextIF:
+ case FFEEXPR_contextARITHIF:
+ case FFEEXPR_contextFORMAT:
+ case FFEEXPR_contextSTOP:
+ case FFEEXPR_contextRETURN:
+ case FFEEXPR_contextSELECTCASE:
+ case FFEEXPR_contextCASE:
+ case FFEEXPR_contextFILEASSOC:
+ case FFEEXPR_contextFILEINT:
+ case FFEEXPR_contextFILEDFINT:
+ case FFEEXPR_contextFILELOG:
+ case FFEEXPR_contextFILENUM:
+ case FFEEXPR_contextFILENUMAMBIG:
+ case FFEEXPR_contextFILECHAR:
+ case FFEEXPR_contextFILENUMCHAR:
+ case FFEEXPR_contextFILEDFCHAR:
+ case FFEEXPR_contextFILEKEY:
+ case FFEEXPR_contextFILEUNIT:
+ case FFEEXPR_contextFILEUNIT_DF:
+ case FFEEXPR_contextFILEUNITAMBIG:
+ case FFEEXPR_contextFILEFORMAT:
+ case FFEEXPR_contextFILENAMELIST:
+ case FFEEXPR_contextFILEVXTCODE:
+ case FFEEXPR_contextINDEX_:
+ case FFEEXPR_contextIMPDOITEM_:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ case FFEEXPR_contextIMPDOCTRL_:
+ case FFEEXPR_contextLOC_:
+ if (ffeexpr_stack_->is_rhs)
+ s = ffeexpr_paren_rhs_let_ (s, t);
+ else
+ s = ffeexpr_paren_lhs_let_ (s, t);
+ break;
+
+ case FFEEXPR_contextASSIGN:
+ case FFEEXPR_contextAGOTO:
+ case FFEEXPR_contextCHARACTERSIZE:
+ case FFEEXPR_contextEQUIVALENCE:
+ case FFEEXPR_contextINCLUDE:
+ case FFEEXPR_contextPARAMETER:
+ case FFEEXPR_contextDIMLIST:
+ case FFEEXPR_contextDIMLISTCOMMON:
+ case FFEEXPR_contextKINDTYPE:
+ case FFEEXPR_contextINITVAL:
+ case FFEEXPR_contextEQVINDEX_:
+ break; /* Will turn into errors below. */
+
+ default:
+ ffesymbol_error (s, t);
+ break;
+ }
+ /* Fall through. */
+ case FFESYMBOL_stateUNDERSTOOD: /* Nothing much more to learn. */
+ understood: /* :::::::::::::::::::: */
+
+ /* State might have changed, update it. */
+ st = ((ffesymbol_sfdummyparent (s) == NULL)
+ ? ffesymbol_state (s)
+ : FFESYMBOL_stateUNDERSTOOD);
+
+ k = ffesymbol_kind (s);
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ {
+ case FFEEXPR_contextSUBROUTINEREF:
+ bad = ((k != FFEINFO_kindSUBROUTINE)
+ && ((ffesymbol_where (s) != FFEINFO_whereINTRINSIC)
+ || (k != FFEINFO_kindNONE)));
+ break;
+
+ case FFEEXPR_contextDATA:
+ if (ffeexpr_stack_->is_rhs)
+ bad = (k != FFEINFO_kindENTITY)
+ || (ffesymbol_where (s) != FFEINFO_whereCONSTANT);
+ else
+ bad = (k != FFEINFO_kindENTITY)
+ || ((ffesymbol_where (s) != FFEINFO_whereNONE)
+ && (ffesymbol_where (s) != FFEINFO_whereLOCAL)
+ && (ffesymbol_where (s) != FFEINFO_whereCOMMON));
+ break;
+
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ bad = (k != FFEINFO_kindENTITY) || (ffesymbol_rank (s) == 0)
+ || ((ffesymbol_where (s) != FFEINFO_whereNONE)
+ && (ffesymbol_where (s) != FFEINFO_whereLOCAL)
+ && (ffesymbol_where (s) != FFEINFO_whereCOMMON));
+ break;
+
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ case FFEEXPR_contextSFUNCDEFACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_:
+ case FFEEXPR_contextLET:
+ case FFEEXPR_contextPAREN_:
+ case FFEEXPR_contextACTUALARGEXPR_:
+ case FFEEXPR_contextINDEXORACTUALARGEXPR_:
+ case FFEEXPR_contextIOLIST:
+ case FFEEXPR_contextIOLISTDF:
+ case FFEEXPR_contextDO:
+ case FFEEXPR_contextDOWHILE:
+ case FFEEXPR_contextACTUALARG_:
+ case FFEEXPR_contextCGOTO:
+ case FFEEXPR_contextIF:
+ case FFEEXPR_contextARITHIF:
+ case FFEEXPR_contextFORMAT:
+ case FFEEXPR_contextSTOP:
+ case FFEEXPR_contextRETURN:
+ case FFEEXPR_contextSELECTCASE:
+ case FFEEXPR_contextCASE:
+ case FFEEXPR_contextFILEASSOC:
+ case FFEEXPR_contextFILEINT:
+ case FFEEXPR_contextFILEDFINT:
+ case FFEEXPR_contextFILELOG:
+ case FFEEXPR_contextFILENUM:
+ case FFEEXPR_contextFILENUMAMBIG:
+ case FFEEXPR_contextFILECHAR:
+ case FFEEXPR_contextFILENUMCHAR:
+ case FFEEXPR_contextFILEDFCHAR:
+ case FFEEXPR_contextFILEKEY:
+ case FFEEXPR_contextFILEUNIT:
+ case FFEEXPR_contextFILEUNIT_DF:
+ case FFEEXPR_contextFILEUNITAMBIG:
+ case FFEEXPR_contextFILEFORMAT:
+ case FFEEXPR_contextFILENAMELIST:
+ case FFEEXPR_contextFILEVXTCODE:
+ case FFEEXPR_contextINDEX_:
+ case FFEEXPR_contextIMPDOITEM_:
+ case FFEEXPR_contextIMPDOITEMDF_:
+ case FFEEXPR_contextIMPDOCTRL_:
+ case FFEEXPR_contextLOC_:
+ bad = FALSE; /* Let paren-switch handle the cases. */
+ break;
+
+ case FFEEXPR_contextASSIGN:
+ case FFEEXPR_contextAGOTO:
+ case FFEEXPR_contextCHARACTERSIZE:
+ case FFEEXPR_contextEQUIVALENCE:
+ case FFEEXPR_contextPARAMETER:
+ case FFEEXPR_contextDIMLIST:
+ case FFEEXPR_contextDIMLISTCOMMON:
+ case FFEEXPR_contextKINDTYPE:
+ case FFEEXPR_contextINITVAL:
+ case FFEEXPR_contextEQVINDEX_:
+ bad = (k != FFEINFO_kindENTITY)
+ || (ffesymbol_where (s) != FFEINFO_whereCONSTANT);
+ break;
+
+ case FFEEXPR_contextINCLUDE:
+ bad = TRUE;
+ break;
+
+ default:
+ bad = TRUE;
+ break;
+ }
+
+ switch (bad ? FFEINFO_kindANY : k)
+ {
+ case FFEINFO_kindNONE: /* Case "CHARACTER X,Y; Y=X(?". */
+ if (ffesymbol_where (s) == FFEINFO_whereINTRINSIC)
+ {
+ if (ffeexpr_context_outer_ (ffeexpr_stack_)
+ == FFEEXPR_contextSUBROUTINEREF)
+ *paren_type = FFEEXPR_parentypeSUBROUTINE_;
+ else
+ *paren_type = FFEEXPR_parentypeFUNCTION_;
+ break;
+ }
+ if (st == FFESYMBOL_stateUNDERSTOOD)
+ {
+ bad = TRUE;
+ *paren_type = FFEEXPR_parentypeANY_;
+ }
+ else
+ *paren_type = FFEEXPR_parentypeFUNSUBSTR_;
+ break;
+
+ case FFEINFO_kindFUNCTION:
+ *paren_type = FFEEXPR_parentypeFUNCTION_;
+ switch (ffesymbol_where (s))
+ {
+ case FFEINFO_whereLOCAL:
+ bad = TRUE; /* Attempt to recurse! */
+ break;
+
+ case FFEINFO_whereCONSTANT:
+ bad = ((ffesymbol_sfexpr (s) == NULL)
+ || (ffebld_op (ffesymbol_sfexpr (s))
+ == FFEBLD_opANY)); /* Attempt to recurse! */
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFEINFO_kindSUBROUTINE:
+ if ((ffeexpr_stack_->context != FFEEXPR_contextSUBROUTINEREF)
+ || (ffeexpr_stack_->previous != NULL))
+ {
+ bad = TRUE;
+ *paren_type = FFEEXPR_parentypeANY_;
+ break;
+ }
+
+ *paren_type = FFEEXPR_parentypeSUBROUTINE_;
+ switch (ffesymbol_where (s))
+ {
+ case FFEINFO_whereLOCAL:
+ case FFEINFO_whereCONSTANT:
+ bad = TRUE; /* Attempt to recurse! */
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFEINFO_kindENTITY:
+ if (ffesymbol_rank (s) == 0)
+ {
+ if (ffesymbol_basictype (s) == FFEINFO_basictypeCHARACTER)
+ *paren_type = FFEEXPR_parentypeSUBSTRING_;
+ else
+ {
+ bad = TRUE;
+ *paren_type = FFEEXPR_parentypeANY_;
+ }
+ }
+ else
+ *paren_type = FFEEXPR_parentypeARRAY_;
+ break;
+
+ default:
+ case FFEINFO_kindANY:
+ bad = TRUE;
+ *paren_type = FFEEXPR_parentypeANY_;
+ break;
+ }
+
+ if (bad)
+ {
+ if (k == FFEINFO_kindANY)
+ ffest_shutdown ();
+ else
+ ffesymbol_error (s, t);
+ }
+
+ return s;
+
+ case FFESYMBOL_stateSEEN: /* Seen but not yet in exec portion. */
+ seen: /* :::::::::::::::::::: */
+ bad = TRUE;
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ {
+ case FFEEXPR_contextPARAMETER:
+ if (ffeexpr_stack_->is_rhs)
+ ffesymbol_error (s, t);
+ else
+ s = ffeexpr_sym_lhs_parameter_ (s, t);
+ break;
+
+ case FFEEXPR_contextDATA:
+ s = ffecom_sym_exec_transition (s);
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ goto understood; /* :::::::::::::::::::: */
+ if (ffeexpr_stack_->is_rhs)
+ ffesymbol_error (s, t);
+ else
+ s = ffeexpr_sym_lhs_data_ (s, t);
+ goto understood; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ s = ffecom_sym_exec_transition (s);
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ goto understood; /* :::::::::::::::::::: */
+ s = ffeexpr_sym_lhs_data_ (s, t);
+ goto understood; /* :::::::::::::::::::: */
+
+ case FFEEXPR_contextEQUIVALENCE:
+ s = ffeexpr_sym_lhs_equivalence_ (s, t);
+ bad = FALSE;
+ break;
+
+ case FFEEXPR_contextDIMLIST:
+ s = ffeexpr_sym_rhs_dimlist_ (s, t);
+ break;
+
+ case FFEEXPR_contextCHARACTERSIZE:
+ case FFEEXPR_contextKINDTYPE:
+ case FFEEXPR_contextDIMLISTCOMMON:
+ case FFEEXPR_contextINITVAL:
+ case FFEEXPR_contextEQVINDEX_:
+ break;
+
+ case FFEEXPR_contextINCLUDE:
+ break;
+
+ case FFEEXPR_contextINDEX_:
+ case FFEEXPR_contextACTUALARGEXPR_:
+ case FFEEXPR_contextINDEXORACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ case FFEEXPR_contextSFUNCDEFACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_:
+ assert (ffeexpr_stack_->is_rhs);
+ s = ffecom_sym_exec_transition (s);
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ goto understood; /* :::::::::::::::::::: */
+ s = ffeexpr_paren_rhs_let_ (s, t);
+ goto understood; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+ k = ffesymbol_kind (s);
+ switch (bad ? FFEINFO_kindANY : k)
+ {
+ case FFEINFO_kindNONE: /* Case "CHARACTER X,Y; Y=X(?". */
+ *paren_type = FFEEXPR_parentypeFUNSUBSTR_;
+ break;
+
+ case FFEINFO_kindFUNCTION:
+ *paren_type = FFEEXPR_parentypeFUNCTION_;
+ switch (ffesymbol_where (s))
+ {
+ case FFEINFO_whereLOCAL:
+ bad = TRUE; /* Attempt to recurse! */
+ break;
+
+ case FFEINFO_whereCONSTANT:
+ bad = ((ffesymbol_sfexpr (s) == NULL)
+ || (ffebld_op (ffesymbol_sfexpr (s))
+ == FFEBLD_opANY)); /* Attempt to recurse! */
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFEINFO_kindSUBROUTINE:
+ *paren_type = FFEEXPR_parentypeANY_;
+ bad = TRUE; /* Cannot possibly be in
+ contextSUBROUTINEREF. */
+ break;
+
+ case FFEINFO_kindENTITY:
+ if (ffesymbol_rank (s) == 0)
+ {
+ if (ffeexpr_stack_->context == FFEEXPR_contextEQUIVALENCE)
+ *paren_type = FFEEXPR_parentypeEQUIVALENCE_;
+ else if (ffesymbol_basictype (s) == FFEINFO_basictypeCHARACTER)
+ *paren_type = FFEEXPR_parentypeSUBSTRING_;
+ else
+ {
+ bad = TRUE;
+ *paren_type = FFEEXPR_parentypeANY_;
+ }
+ }
+ else
+ *paren_type = FFEEXPR_parentypeARRAY_;
+ break;
+
+ default:
+ case FFEINFO_kindANY:
+ bad = TRUE;
+ *paren_type = FFEEXPR_parentypeANY_;
+ break;
+ }
+
+ if (bad)
+ {
+ if (k == FFEINFO_kindANY)
+ ffest_shutdown ();
+ else
+ ffesymbol_error (s, t);
+ }
+
+ return s;
+
+ default:
+ assert ("bad symbol state" == NULL);
+ return NULL;
+ }
+}
+
+/* Have FOO in XYZ = ...FOO(...).... Executable context only. */
+
+static ffesymbol
+ffeexpr_paren_rhs_let_ (ffesymbol s, ffelexToken t)
+{
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+ ffeintrinGen gen;
+ ffeintrinSpec spec;
+ ffeintrinImp imp;
+ bool maybe_ambig = FALSE;
+ bool error = FALSE;
+
+ assert ((ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ || (ffesymbol_state (s) == FFESYMBOL_stateUNCERTAIN));
+
+ na = sa = ffesymbol_attrs (s);
+
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = ffesymbol_kind (s);
+ where = ffesymbol_where (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (sa & FFESYMBOL_attrsEXTERNAL)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ if (sa & FFESYMBOL_attrsTYPE)
+ where = FFEINFO_whereGLOBAL;
+ else
+ /* Not TYPE. */
+ {
+ kind = FFEINFO_kindFUNCTION;
+
+ if (sa & FFESYMBOL_attrsDUMMY)
+ ; /* Not TYPE. */
+ else if (sa & FFESYMBOL_attrsACTUALARG)
+ ; /* Not DUMMY or TYPE. */
+ else /* Not ACTUALARG, DUMMY, or TYPE. */
+ where = FFEINFO_whereGLOBAL;
+ }
+ }
+ else if (sa & FFESYMBOL_attrsDUMMY)
+ {
+ assert (!(sa & FFESYMBOL_attrsEXTERNAL)); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ kind = FFEINFO_kindFUNCTION;
+ maybe_ambig = TRUE; /* If basictypeCHARACTER, can't be sure; kind
+ could be ENTITY w/substring ref. */
+ }
+ else if (sa & FFESYMBOL_attrsARRAY)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsTYPE)));
+
+ where = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsSFARG)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ where = FFEINFO_whereLOCAL; /* Actually an error, but at least we
+ know it's a local var. */
+ }
+ else if (sa & FFESYMBOL_attrsTYPE)
+ {
+ assert (!(sa & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsTYPE
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG)));
+
+ if (ffeintrin_is_intrinsic (ffesymbol_text (s), t, FALSE,
+ &gen, &spec, &imp))
+ {
+ if (!(sa & FFESYMBOL_attrsANYLEN)
+ && (ffeimplic_peek_symbol_type (s, NULL)
+ == FFEINFO_basictypeCHARACTER))
+ return s; /* Haven't learned anything yet. */
+
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ ffesymbol_set_generic (s, gen);
+ ffesymbol_set_specific (s, spec);
+ ffesymbol_set_implementation (s, imp);
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ 0,
+ FFEINFO_kindFUNCTION,
+ FFEINFO_whereINTRINSIC,
+ ffesymbol_size (s)));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ ffesymbol_reference (s, t, FALSE);
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+
+ return s;
+ }
+ if (sa & FFESYMBOL_attrsANYLEN)
+ error = TRUE; /* Error, since the only way we can,
+ given CHARACTER*(*) FOO, accept
+ FOO(...) is for FOO to be a dummy
+ arg or constant, but it can't
+ become either now. */
+ else if (sa & FFESYMBOL_attrsADJUSTABLE)
+ {
+ kind = FFEINFO_kindENTITY;
+ where = FFEINFO_whereLOCAL;
+ }
+ else
+ {
+ kind = FFEINFO_kindFUNCTION;
+ where = FFEINFO_whereGLOBAL;
+ maybe_ambig = TRUE; /* If basictypeCHARACTER, can't be sure;
+ could be ENTITY/LOCAL w/substring ref. */
+ }
+ }
+ else if (sa == FFESYMBOL_attrsetNONE)
+ {
+ assert (ffesymbol_state (s) == FFESYMBOL_stateNONE);
+
+ if (ffeintrin_is_intrinsic (ffesymbol_text (s), t, FALSE,
+ &gen, &spec, &imp))
+ {
+ if (ffeimplic_peek_symbol_type (s, NULL)
+ == FFEINFO_basictypeCHARACTER)
+ return s; /* Haven't learned anything yet. */
+
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ ffesymbol_set_generic (s, gen);
+ ffesymbol_set_specific (s, spec);
+ ffesymbol_set_implementation (s, imp);
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ 0,
+ FFEINFO_kindFUNCTION,
+ FFEINFO_whereINTRINSIC,
+ ffesymbol_size (s)));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ s = ffecom_sym_learned (s);
+ ffesymbol_reference (s, t, FALSE);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ return s;
+ }
+
+ kind = FFEINFO_kindFUNCTION;
+ where = FFEINFO_whereGLOBAL;
+ maybe_ambig = TRUE; /* If basictypeCHARACTER, can't be sure;
+ could be ENTITY/LOCAL w/substring ref. */
+ }
+ else
+ error = TRUE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (error)
+ ffesymbol_error (s, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_signal_change (s); /* May need to back up to previous
+ version. */
+ if (!ffeimplic_establish_symbol (s))
+ {
+ ffesymbol_error (s, t);
+ return s;
+ }
+ if (maybe_ambig
+ && (ffesymbol_basictype (s) == FFEINFO_basictypeCHARACTER))
+ return s; /* Still not sure, let caller deal with it
+ based on (...). */
+
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ kind,
+ where,
+ ffesymbol_size (s)));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ s = ffecom_sym_learned (s);
+ ffesymbol_reference (s, t, FALSE);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* ffeexpr_token_arguments_ -- OPEN_PAREN [expr COMMA]...expr
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle expression (which might be null) and COMMA or CLOSE_PAREN. */
+
+static ffelexHandler
+ffeexpr_token_arguments_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffeexprExpr_ procedure;
+ ffebld reduced;
+ ffeinfo info;
+ ffeexprContext ctx;
+ bool check_intrin = FALSE; /* Set TRUE if intrinsic is REAL(Z) or AIMAG(Z). */
+
+ procedure = ffeexpr_stack_->exprstack;
+ info = ffebld_info (procedure->u.operand);
+
+ /* Is there an expression to add? If the expression is nil,
+ it might still be an argument. It is if:
+
+ - The current token is comma, or
+
+ - The -fugly-comma flag was specified *and* the procedure
+ being invoked is external.
+
+ Otherwise, if neither of the above is the case, just
+ ignore this (nil) expression. */
+
+ if ((expr != NULL)
+ || (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ || (ffe_is_ugly_comma ()
+ && (ffeinfo_where (info) == FFEINFO_whereGLOBAL)))
+ {
+ /* This expression, even if nil, is apparently intended as an argument. */
+
+ /* Internal procedure (CONTAINS, or statement function)? */
+
+ if (ffeinfo_where (info) == FFEINFO_whereCONSTANT)
+ {
+ if ((expr == NULL)
+ && ffebad_start (FFEBAD_NULL_ARGUMENT))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_here (1, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ if (expr == NULL)
+ ;
+ else
+ {
+ if (ffeexpr_stack_->next_dummy == NULL)
+ { /* Report later which was the first extra argument. */
+ if (ffeexpr_stack_->tokens[1] == NULL)
+ {
+ ffeexpr_stack_->tokens[1] = ffelex_token_use (ft);
+ ffeexpr_stack_->num_args = 0;
+ }
+ ++ffeexpr_stack_->num_args; /* Count # of extra arguments. */
+ }
+ else
+ {
+ if ((ffeinfo_rank (ffebld_info (expr)) != 0)
+ && ffebad_start (FFEBAD_ARRAY_AS_SFARG))
+ {
+ ffebad_here (0,
+ ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_here (1, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_string (ffesymbol_text (ffesymbol_sfdummyparent
+ (ffebld_symter (ffebld_head
+ (ffeexpr_stack_->next_dummy)))));
+ ffebad_finish ();
+ }
+ else
+ {
+ expr = ffeexpr_convert_expr (expr, ft,
+ ffebld_head (ffeexpr_stack_->next_dummy),
+ ffeexpr_stack_->tokens[0],
+ FFEEXPR_contextLET);
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ }
+ --ffeexpr_stack_->num_args; /* Count down # of args. */
+ ffeexpr_stack_->next_dummy
+ = ffebld_trail (ffeexpr_stack_->next_dummy);
+ }
+ }
+ }
+ else
+ {
+ if ((expr == NULL)
+ && ffe_is_pedantic ()
+ && ffebad_start (FFEBAD_NULL_ARGUMENT_W))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_here (1, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ }
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ {
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFACTUALARGEXPR_:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_:
+ ctx = FFEEXPR_contextSFUNCDEFACTUALARG_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ assert ("bad context" == NULL);
+ ctx = FFEEXPR_context;
+ break;
+
+ default:
+ ctx = FFEEXPR_contextACTUALARG_;
+ break;
+ }
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool, ctx,
+ ffeexpr_token_arguments_);
+
+ default:
+ break;
+ }
+
+ if ((ffeinfo_where (info) == FFEINFO_whereCONSTANT)
+ && (ffeexpr_stack_->next_dummy != NULL))
+ { /* Too few arguments. */
+ if (ffebad_start (FFEBAD_TOO_FEW_ARGUMENTS))
+ {
+ char num[10];
+
+ sprintf (num, "%" ffebldListLength_f "u", ffeexpr_stack_->num_args);
+
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_string (num);
+ ffebad_string (ffesymbol_text (ffesymbol_sfdummyparent (ffebld_symter
+ (ffebld_head (ffeexpr_stack_->next_dummy)))));
+ ffebad_finish ();
+ }
+ for (;
+ ffeexpr_stack_->next_dummy != NULL;
+ ffeexpr_stack_->next_dummy
+ = ffebld_trail (ffeexpr_stack_->next_dummy))
+ {
+ expr = ffebld_new_conter (ffebld_constant_new_integerdefault_val (0));
+ ffebld_set_info (expr, ffeinfo_new_any ());
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ }
+ }
+
+ if ((ffeinfo_where (info) == FFEINFO_whereCONSTANT)
+ && (ffeexpr_stack_->tokens[1] != NULL))
+ { /* Too many arguments to statement function. */
+ if (ffebad_start (FFEBAD_TOO_MANY_ARGUMENTS))
+ {
+ char num[10];
+
+ sprintf (num, "%" ffebldListLength_f "u", ffeexpr_stack_->num_args);
+
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_stack_->tokens[1]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[1]));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_string (num);
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_stack_->tokens[1]);
+ }
+ ffebld_end_list (&ffeexpr_stack_->bottom);
+
+ if (ffebld_op (procedure->u.operand) == FFEBLD_opANY)
+ {
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ }
+ else
+ {
+ if (ffeexpr_stack_->context != FFEEXPR_contextSUBROUTINEREF)
+ reduced = ffebld_new_funcref (procedure->u.operand,
+ ffeexpr_stack_->expr);
+ else
+ reduced = ffebld_new_subrref (procedure->u.operand,
+ ffeexpr_stack_->expr);
+ if (ffebld_symter_generic (procedure->u.operand) != FFEINTRIN_genNONE)
+ ffeintrin_fulfill_generic (&reduced, &info, ffeexpr_stack_->tokens[0]);
+ else if (ffebld_symter_specific (procedure->u.operand)
+ != FFEINTRIN_specNONE)
+ ffeintrin_fulfill_specific (&reduced, &info, &check_intrin,
+ ffeexpr_stack_->tokens[0]);
+ else
+ ffeexpr_fulfill_call_ (&reduced, ffeexpr_stack_->tokens[0]);
+
+ if (ffebld_op (reduced) != FFEBLD_opANY)
+ ffebld_set_info (reduced,
+ ffeinfo_new (ffeinfo_basictype (info),
+ ffeinfo_kindtype (info),
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereFLEETING,
+ ffeinfo_size (info)));
+ else
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ }
+ if (ffebld_op (reduced) == FFEBLD_opFUNCREF)
+ reduced = ffeexpr_collapse_funcref (reduced, ffeexpr_stack_->tokens[0]);
+ ffeexpr_stack_->exprstack = procedure->previous; /* Pops
+ not-quite-operand off
+ stack. */
+ procedure->u.operand = reduced; /* Save the line/column ffewhere
+ info. */
+ ffeexpr_exprstack_push_operand_ (procedure); /* Push it back on stack. */
+ if (ffelex_token_type (t) == FFELEX_typeCLOSE_PAREN)
+ {
+ ffelex_token_kill (ffeexpr_stack_->tokens[0]);
+ ffeexpr_is_substr_ok_ = FALSE; /* Nobody likes "FUNC(3)(1:1)".... */
+
+ /* If the intrinsic needs checking (is REAL(Z) or AIMAG(Z), where
+ Z is DOUBLE COMPLEX), and a command-line option doesn't already
+ establish interpretation, probably complain. */
+
+ if (check_intrin
+ && !ffe_is_90 ()
+ && !ffe_is_ugly_complex ())
+ {
+ /* If the outer expression is REAL(me...), issue diagnostic
+ only if next token isn't the close-paren for REAL(me). */
+
+ if ((ffeexpr_stack_->previous != NULL)
+ && (ffeexpr_stack_->previous->exprstack != NULL)
+ && (ffeexpr_stack_->previous->exprstack->type == FFEEXPR_exprtypeOPERAND_)
+ && ((reduced = ffeexpr_stack_->previous->exprstack->u.operand) != NULL)
+ && (ffebld_op (reduced) == FFEBLD_opSYMTER)
+ && (ffebld_symter_implementation (reduced) == FFEINTRIN_impREAL))
+ return (ffelexHandler) ffeexpr_token_intrincheck_;
+
+ /* Diagnose the ambiguity now. */
+
+ if (ffebad_start (FFEBAD_INTRINSIC_CMPAMBIG))
+ {
+ ffebad_string (ffeintrin_name_implementation
+ (ffebld_symter_implementation
+ (ffebld_left
+ (ffeexpr_stack_->exprstack->u.operand))));
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_stack_->exprstack->token),
+ ffelex_token_where_column (ffeexpr_stack_->exprstack->token));
+ ffebad_finish ();
+ }
+ }
+ return (ffelexHandler) ffeexpr_token_substrp_;
+ }
+
+ if (ffest_ffebad_start (FFEBAD_INVALID_TOKEN_IN_EXPRESSION))
+ {
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_stack_->tokens[0]);
+ ffeexpr_is_substr_ok_ = FALSE;/* Nobody likes "FUNC(3)(1:1)".... */
+ return
+ (ffelexHandler) ffeexpr_find_close_paren_ (t,
+ (ffelexHandler)
+ ffeexpr_token_substrp_);
+}
+
+/* ffeexpr_token_elements_ -- OPEN_PAREN [expr COMMA]...expr
+
+ Return a pointer to this array to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle expression and COMMA or CLOSE_PAREN. */
+
+static ffelexHandler
+ffeexpr_token_elements_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffeexprExpr_ array;
+ ffebld reduced;
+ ffeinfo info;
+ ffeinfoWhere where;
+ ffetargetIntegerDefault val;
+ ffetargetIntegerDefault lval = 0;
+ ffetargetIntegerDefault uval = 0;
+ ffebld lbound;
+ ffebld ubound;
+ bool lcheck;
+ bool ucheck;
+
+ array = ffeexpr_stack_->exprstack;
+ info = ffebld_info (array->u.operand);
+
+ if ((expr == NULL) /* && ((ffeexpr_stack_->rank != 0) ||
+ (ffelex_token_type(t) ==
+ FFELEX_typeCOMMA)) */ )
+ {
+ if (ffebad_start (FFEBAD_NULL_ELEMENT))
+ {
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_here (1, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ if (ffeexpr_stack_->rank < ffeinfo_rank (info))
+ { /* Don't bother if we're going to complain
+ later! */
+ expr = ffebld_new_conter (ffebld_constant_new_integerdefault_val (1));
+ ffebld_set_info (expr, ffeinfo_new_any ());
+ }
+ }
+
+ if (expr == NULL)
+ ;
+ else if (ffeinfo_rank (info) == 0)
+ { /* In EQUIVALENCE context, ffeinfo_rank(info)
+ may == 0. */
+ ++ffeexpr_stack_->rank; /* Track anyway, may need for new VXT
+ feature. */
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ }
+ else
+ {
+ ++ffeexpr_stack_->rank;
+ if (ffeexpr_stack_->rank > ffeinfo_rank (info))
+ { /* Report later which was the first extra
+ element. */
+ if (ffeexpr_stack_->rank == ffeinfo_rank (info) + 1)
+ ffeexpr_stack_->tokens[1] = ffelex_token_use (ft);
+ }
+ else
+ {
+ switch (ffeinfo_where (ffebld_info (expr)))
+ {
+ case FFEINFO_whereCONSTANT:
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ ffeexpr_stack_->constant = FALSE;
+ break;
+
+ default:
+ ffeexpr_stack_->constant = FALSE;
+ ffeexpr_stack_->immediate = FALSE;
+ break;
+ }
+ if (ffebld_op (expr) == FFEBLD_opCONTER)
+ {
+ val = ffebld_constant_integerdefault (ffebld_conter (expr));
+
+ lbound = ffebld_left (ffebld_head (ffeexpr_stack_->bound_list));
+ if (lbound == NULL)
+ {
+ lcheck = TRUE;
+ lval = 1;
+ }
+ else if (ffebld_op (lbound) == FFEBLD_opCONTER)
+ {
+ lcheck = TRUE;
+ lval = ffebld_constant_integerdefault (ffebld_conter (lbound));
+ }
+ else
+ lcheck = FALSE;
+
+ ubound = ffebld_right (ffebld_head (ffeexpr_stack_->bound_list));
+ assert (ubound != NULL);
+ if (ffebld_op (ubound) == FFEBLD_opCONTER)
+ {
+ ucheck = TRUE;
+ uval = ffebld_constant_integerdefault (ffebld_conter (ubound));
+ }
+ else
+ ucheck = FALSE;
+
+ if ((lcheck && (val < lval)) || (ucheck && (val > uval)))
+ {
+ ffebad_start (FFEBAD_RANGE_ARRAY);
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_finish ();
+ }
+ }
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ ffeexpr_stack_->bound_list = ffebld_trail (ffeexpr_stack_->bound_list);
+ }
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ switch (ffeexpr_context_outer_ (ffeexpr_stack_))
+ {
+ case FFEEXPR_contextDATAIMPDOITEM_:
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextDATAIMPDOINDEX_,
+ ffeexpr_token_elements_);
+
+ case FFEEXPR_contextEQUIVALENCE:
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextEQVINDEX_,
+ ffeexpr_token_elements_);
+
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextSFUNCDEFINDEX_,
+ ffeexpr_token_elements_);
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ assert ("bad context" == NULL);
+ break;
+
+ default:
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextINDEX_,
+ ffeexpr_token_elements_);
+ }
+
+ default:
+ break;
+ }
+
+ if ((ffeexpr_stack_->rank != ffeinfo_rank (info))
+ && (ffeinfo_rank (info) != 0))
+ {
+ char num[10];
+
+ if (ffeexpr_stack_->rank < ffeinfo_rank (info))
+ {
+ if (ffebad_start (FFEBAD_TOO_FEW_ELEMENTS))
+ {
+ sprintf (num, "%d",
+ (int) (ffeinfo_rank (info) - ffeexpr_stack_->rank));
+
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1,
+ ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_string (num);
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if (ffebad_start (FFEBAD_TOO_MANY_ELEMENTS))
+ {
+ sprintf (num, "%d",
+ (int) (ffeexpr_stack_->rank - ffeinfo_rank (info)));
+
+ ffebad_here (0,
+ ffelex_token_where_line (ffeexpr_stack_->tokens[1]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[1]));
+ ffebad_here (1,
+ ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_string (num);
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_stack_->tokens[1]);
+ }
+ while (ffeexpr_stack_->rank++ < ffeinfo_rank (info))
+ {
+ expr = ffebld_new_conter (ffebld_constant_new_integerdefault_val (1));
+ ffebld_set_info (expr, ffeinfo_new (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT,
+ 0, FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ ffebld_append_item (&ffeexpr_stack_->bottom, expr);
+ }
+ }
+ ffebld_end_list (&ffeexpr_stack_->bottom);
+
+ if (ffebld_op (array->u.operand) == FFEBLD_opANY)
+ {
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ }
+ else
+ {
+ reduced = ffebld_new_arrayref (array->u.operand, ffeexpr_stack_->expr);
+ if (ffeexpr_stack_->constant)
+ where = FFEINFO_whereFLEETING_CADDR;
+ else if (ffeexpr_stack_->immediate)
+ where = FFEINFO_whereFLEETING_IADDR;
+ else
+ where = FFEINFO_whereFLEETING;
+ ffebld_set_info (reduced,
+ ffeinfo_new (ffeinfo_basictype (info),
+ ffeinfo_kindtype (info),
+ 0,
+ FFEINFO_kindENTITY,
+ where,
+ ffeinfo_size (info)));
+ reduced = ffeexpr_collapse_arrayref (reduced, ffeexpr_stack_->tokens[0]);
+ }
+
+ ffeexpr_stack_->exprstack = array->previous; /* Pops not-quite-operand off
+ stack. */
+ array->u.operand = reduced; /* Save the line/column ffewhere info. */
+ ffeexpr_exprstack_push_operand_ (array); /* Push it back on stack. */
+
+ switch (ffeinfo_basictype (info))
+ {
+ case FFEINFO_basictypeCHARACTER:
+ ffeexpr_is_substr_ok_ = TRUE; /* Everyone likes "FOO(3)(1:1)".... */
+ break;
+
+ case FFEINFO_basictypeNONE:
+ ffeexpr_is_substr_ok_ = TRUE;
+ assert (ffeexpr_stack_->context == FFEEXPR_contextEQUIVALENCE);
+ break;
+
+ default:
+ ffeexpr_is_substr_ok_ = FALSE;
+ break;
+ }
+
+ if (ffelex_token_type (t) == FFELEX_typeCLOSE_PAREN)
+ {
+ ffelex_token_kill (ffeexpr_stack_->tokens[0]);
+ return (ffelexHandler) ffeexpr_token_substrp_;
+ }
+
+ if (ffest_ffebad_start (FFEBAD_INVALID_TOKEN_IN_EXPRESSION))
+ {
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_finish ();
+ }
+ ffelex_token_kill (ffeexpr_stack_->tokens[0]);
+ return
+ (ffelexHandler) ffeexpr_find_close_paren_ (t,
+ (ffelexHandler)
+ ffeexpr_token_substrp_);
+}
+
+/* ffeexpr_token_equivalence_ -- OPEN_PAREN expr
+
+ Return a pointer to this array to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ If token is COLON, pass off to _substr_, else init list and pass off
+ to _elements_. This handles the case "EQUIVALENCE (FOO(expr?", where
+ ? marks the token, and where FOO's rank/type has not yet been established,
+ meaning we could be in a list of indices or in a substring
+ specification. */
+
+static ffelexHandler
+ffeexpr_token_equivalence_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ if (ffelex_token_type (t) == FFELEX_typeCOLON)
+ return ffeexpr_token_substring_ (ft, expr, t);
+
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ return ffeexpr_token_elements_ (ft, expr, t);
+}
+
+/* ffeexpr_token_substring_ -- NAME(of kindENTITY) OPEN_PAREN expr
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle expression (which may be null) and COLON. */
+
+static ffelexHandler
+ffeexpr_token_substring_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffeexprExpr_ string;
+ ffeinfo info;
+ ffetargetIntegerDefault i;
+ ffeexprContext ctx;
+ ffetargetCharacterSize size;
+
+ string = ffeexpr_stack_->exprstack;
+ info = ffebld_info (string->u.operand);
+ size = ffebld_size_max (string->u.operand);
+
+ if (ffelex_token_type (t) == FFELEX_typeCOLON)
+ {
+ if ((expr != NULL)
+ && (ffebld_op (expr) == FFEBLD_opCONTER)
+ && (((i = ffebld_constant_integerdefault (ffebld_conter (expr)))
+ < 1)
+ || ((size != FFETARGET_charactersizeNONE) && (i > size))))
+ {
+ ffebad_start (FFEBAD_RANGE_SUBSTR);
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_finish ();
+ }
+ ffeexpr_stack_->expr = expr;
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ ctx = FFEEXPR_contextSFUNCDEFINDEX_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ assert ("bad context" == NULL);
+ ctx = FFEEXPR_context;
+ break;
+
+ default:
+ ctx = FFEEXPR_contextINDEX_;
+ break;
+ }
+
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool, ctx,
+ ffeexpr_token_substring_1_);
+ }
+
+ if (ffest_ffebad_start (FFEBAD_MISSING_COLON_IN_SUBSTR))
+ {
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_finish ();
+ }
+
+ ffeexpr_stack_->expr = NULL;
+ return (ffelexHandler) ffeexpr_token_substring_1_ (ft, expr, t);
+}
+
+/* ffeexpr_token_substring_1_ -- NAME OPEN_PAREN [expr COMMA]...expr
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ Handle expression (which might be null) and CLOSE_PAREN. */
+
+static ffelexHandler
+ffeexpr_token_substring_1_ (ffelexToken ft, ffebld last, ffelexToken t)
+{
+ ffeexprExpr_ string;
+ ffebld reduced;
+ ffebld substrlist;
+ ffebld first = ffeexpr_stack_->expr;
+ ffebld strop;
+ ffeinfo info;
+ ffeinfoWhere lwh;
+ ffeinfoWhere rwh;
+ ffeinfoWhere where;
+ ffeinfoKindtype first_kt;
+ ffeinfoKindtype last_kt;
+ ffetargetIntegerDefault first_val;
+ ffetargetIntegerDefault last_val;
+ ffetargetCharacterSize size;
+ ffetargetCharacterSize strop_size_max;
+
+ string = ffeexpr_stack_->exprstack;
+ strop = string->u.operand;
+ info = ffebld_info (strop);
+
+ if ((first == NULL) || (ffebld_op (first) == FFEBLD_opCONTER))
+ { /* The starting point is known. */
+ first_val = (first == NULL) ? 1
+ : ffebld_constant_integerdefault (ffebld_conter (first));
+ }
+ else
+ { /* Assume start of the entity. */
+ first_val = 1;
+ }
+
+ if ((last != NULL) && (ffebld_op (last) == FFEBLD_opCONTER))
+ { /* The ending point is known. */
+ last_val = ffebld_constant_integerdefault (ffebld_conter (last));
+
+ if ((first == NULL) || (ffebld_op (first) == FFEBLD_opCONTER))
+ { /* The beginning point is a constant. */
+ if (first_val <= last_val)
+ size = last_val - first_val + 1;
+ else
+ {
+ if (0 && ffe_is_90 ())
+ size = 0;
+ else
+ {
+ size = 1;
+ ffebad_start (FFEBAD_ZERO_SIZE);
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_finish ();
+ }
+ }
+ }
+ else
+ size = FFETARGET_charactersizeNONE;
+
+ strop_size_max = ffebld_size_max (strop);
+
+ if ((strop_size_max != FFETARGET_charactersizeNONE)
+ && (last_val > strop_size_max))
+ { /* Beyond maximum possible end of string. */
+ ffebad_start (FFEBAD_RANGE_SUBSTR);
+ ffebad_here (0, ffelex_token_where_line (ft),
+ ffelex_token_where_column (ft));
+ ffebad_finish ();
+ }
+ }
+ else
+ size = FFETARGET_charactersizeNONE; /* The size is not known. */
+
+#if 0 /* Don't do this, or "is size of target
+ known?" would no longer be easily
+ answerable. To see if there is a max
+ size, use ffebld_size_max; to get only the
+ known size, else NONE, use
+ ffebld_size_known; use ffebld_size if
+ values are sure to be the same (not
+ opSUBSTR or opCONCATENATE or known to have
+ known length). By getting rid of this
+ "useful info" stuff, we don't end up
+ blank-padding the constant in the
+ assignment "A(I:J)='XYZ'" to the known
+ length of A. */
+ if (size == FFETARGET_charactersizeNONE)
+ size = strop_size_max; /* Assume we use the entire string. */
+#endif
+
+ substrlist
+ = ffebld_new_item
+ (first,
+ ffebld_new_item
+ (last,
+ NULL
+ )
+ )
+ ;
+
+ if (first == NULL)
+ lwh = FFEINFO_whereCONSTANT;
+ else
+ lwh = ffeinfo_where (ffebld_info (first));
+ if (last == NULL)
+ rwh = FFEINFO_whereCONSTANT;
+ else
+ rwh = ffeinfo_where (ffebld_info (last));
+
+ switch (lwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ where = FFEINFO_whereCONSTANT;
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ where = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ where = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ switch (rwh)
+ {
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereIMMEDIATE:
+ where = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ where = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+
+ default:
+ where = FFEINFO_whereFLEETING;
+ break;
+ }
+
+ if (first == NULL)
+ first_kt = FFEINFO_kindtypeINTEGERDEFAULT;
+ else
+ first_kt = ffeinfo_kindtype (ffebld_info (first));
+ if (last == NULL)
+ last_kt = FFEINFO_kindtypeINTEGERDEFAULT;
+ else
+ last_kt = ffeinfo_kindtype (ffebld_info (last));
+
+ switch (where)
+ {
+ case FFEINFO_whereCONSTANT:
+ switch (ffeinfo_where (info))
+ {
+ case FFEINFO_whereCONSTANT:
+ break;
+
+ case FFEINFO_whereIMMEDIATE: /* Not possible, actually. */
+ where = FFEINFO_whereIMMEDIATE;
+ break;
+
+ default:
+ where = FFEINFO_whereFLEETING_CADDR;
+ break;
+ }
+ break;
+
+ case FFEINFO_whereIMMEDIATE:
+ switch (ffeinfo_where (info))
+ {
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereIMMEDIATE: /* Not possible, actually. */
+ break;
+
+ default:
+ where = FFEINFO_whereFLEETING_IADDR;
+ break;
+ }
+ break;
+
+ default:
+ switch (ffeinfo_where (info))
+ {
+ case FFEINFO_whereCONSTANT:
+ where = FFEINFO_whereCONSTANT_SUBOBJECT; /* An F90 concept. */
+ break;
+
+ case FFEINFO_whereIMMEDIATE: /* Not possible, actually. */
+ default:
+ where = FFEINFO_whereFLEETING;
+ break;
+ }
+ break;
+ }
+
+ if (ffebld_op (strop) == FFEBLD_opANY)
+ {
+ reduced = ffebld_new_any ();
+ ffebld_set_info (reduced, ffeinfo_new_any ());
+ }
+ else
+ {
+ reduced = ffebld_new_substr (strop, substrlist);
+ ffebld_set_info (reduced, ffeinfo_new
+ (FFEINFO_basictypeCHARACTER,
+ ffeinfo_kindtype (info),
+ 0,
+ FFEINFO_kindENTITY,
+ where,
+ size));
+ reduced = ffeexpr_collapse_substr (reduced, ffeexpr_stack_->tokens[0]);
+ }
+
+ ffeexpr_stack_->exprstack = string->previous; /* Pops not-quite-operand off
+ stack. */
+ string->u.operand = reduced; /* Save the line/column ffewhere info. */
+ ffeexpr_exprstack_push_operand_ (string); /* Push it back on stack. */
+
+ if (ffelex_token_type (t) == FFELEX_typeCLOSE_PAREN)
+ {
+ ffelex_token_kill (ffeexpr_stack_->tokens[0]);
+ ffeexpr_is_substr_ok_ = FALSE; /* Nobody likes "FOO(3:5)(1:1)".... */
+ return (ffelexHandler) ffeexpr_token_substrp_;
+ }
+
+ if (ffest_ffebad_start (FFEBAD_INVALID_TOKEN_IN_EXPRESSION))
+ {
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->tokens[0]),
+ ffelex_token_where_column (ffeexpr_stack_->tokens[0]));
+ ffebad_finish ();
+ }
+
+ ffelex_token_kill (ffeexpr_stack_->tokens[0]);
+ ffeexpr_is_substr_ok_ = FALSE;/* Nobody likes "FOO(3:5)(1:1)".... */
+ return
+ (ffelexHandler) ffeexpr_find_close_paren_ (t,
+ (ffelexHandler)
+ ffeexpr_token_substrp_);
+}
+
+/* ffeexpr_token_substrp_ -- Rhs <character entity>
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ If OPEN_PAREN, treat as start of a substring ("(3:4)") construct, and
+ issue error message if flag (serves as argument) is set. Else, just
+ forward token to binary_. */
+
+static ffelexHandler
+ffeexpr_token_substrp_ (ffelexToken t)
+{
+ ffeexprContext ctx;
+
+ if (ffelex_token_type (t) != FFELEX_typeOPEN_PAREN)
+ return (ffelexHandler) ffeexpr_token_binary_ (t);
+
+ ffeexpr_stack_->tokens[0] = ffelex_token_use (t);
+
+ switch (ffeexpr_stack_->context)
+ {
+ case FFEEXPR_contextSFUNCDEF:
+ case FFEEXPR_contextSFUNCDEFINDEX_:
+ ctx = FFEEXPR_contextSFUNCDEFINDEX_;
+ break;
+
+ case FFEEXPR_contextSFUNCDEFACTUALARG_:
+ case FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_:
+ assert ("bad context" == NULL);
+ ctx = FFEEXPR_context;
+ break;
+
+ default:
+ ctx = FFEEXPR_contextINDEX_;
+ break;
+ }
+
+ if (!ffeexpr_is_substr_ok_)
+ {
+ if (ffebad_start (FFEBAD_BAD_SUBSTR))
+ {
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ffeexpr_stack_->exprstack->token),
+ ffelex_token_where_column (ffeexpr_stack_->exprstack->token));
+ ffebad_finish ();
+ }
+
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool, ctx,
+ ffeexpr_token_anything_);
+ }
+
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool, ctx,
+ ffeexpr_token_substring_);
+}
+
+static ffelexHandler
+ffeexpr_token_intrincheck_ (ffelexToken t)
+{
+ if ((ffelex_token_type (t) != FFELEX_typeCLOSE_PAREN)
+ && ffebad_start (FFEBAD_INTRINSIC_CMPAMBIG))
+ {
+ ffebad_string (ffeintrin_name_implementation
+ (ffebld_symter_implementation
+ (ffebld_left
+ (ffeexpr_stack_->exprstack->u.operand))));
+ ffebad_here (0, ffelex_token_where_line (ffeexpr_stack_->exprstack->token),
+ ffelex_token_where_column (ffeexpr_stack_->exprstack->token));
+ ffebad_finish ();
+ }
+
+ return (ffelexHandler) ffeexpr_token_substrp_ (t);
+}
+
+/* ffeexpr_token_funsubstr_ -- NAME OPEN_PAREN expr
+
+ Return a pointer to this function to the lexer (ffelex), which will
+ invoke it for the next token.
+
+ If COLON, do everything we would have done since _parenthesized_ if
+ we had known NAME represented a kindENTITY instead of a kindFUNCTION.
+ If not COLON, do likewise for kindFUNCTION instead. */
+
+static ffelexHandler
+ffeexpr_token_funsubstr_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffeinfoWhere where;
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffebld symter = ffeexpr_stack_->exprstack->u.operand;
+ bool needs_type;
+ ffeintrinGen gen;
+ ffeintrinSpec spec;
+ ffeintrinImp imp;
+
+ s = ffebld_symter (symter);
+ sa = ffesymbol_attrs (s);
+ where = ffesymbol_where (s);
+
+ /* We get here only if we don't already know enough about FOO when seeing a
+ FOO(stuff) reference, and FOO might turn out to be a CHARACTER type. If
+ "stuff" is a substring reference, then FOO is a CHARACTER scalar type.
+ Else FOO is a function, either intrinsic or external. If intrinsic, it
+ wouldn't necessarily be CHARACTER type, so unless it has already been
+ declared DUMMY, it hasn't had its type established yet. It can't be
+ CHAR*(*) in any case, though it can have an explicit CHAR*n type. */
+
+ assert (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsTYPE)));
+
+ needs_type = !(ffesymbol_attrs (s) & FFESYMBOL_attrsDUMMY);
+
+ ffesymbol_signal_change (s); /* Probably already done, but in case.... */
+
+ if (ffelex_token_type (t) == FFELEX_typeCOLON)
+ { /* Definitely an ENTITY (char substring). */
+ if (needs_type && !ffeimplic_establish_symbol (s))
+ {
+ ffesymbol_error (s, ffeexpr_stack_->tokens[0]);
+ return (ffelexHandler) ffeexpr_token_arguments_ (ft, expr, t);
+ }
+
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ FFEINFO_kindENTITY,
+ (where == FFEINFO_whereNONE)
+ ? FFEINFO_whereLOCAL
+ : where,
+ ffesymbol_size (s)));
+ ffebld_set_info (symter, ffeinfo_use (ffesymbol_info (s)));
+
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+
+ ffeexpr_stack_->exprstack->u.operand
+ = ffeexpr_collapse_symter (symter, ffeexpr_tokens_[0]);
+
+ return (ffelexHandler) ffeexpr_token_substring_ (ft, expr, t);
+ }
+
+ /* The "stuff" isn't a substring notation, so we now know the overall
+ reference is to a function. */
+
+ if (ffeintrin_is_intrinsic (ffesymbol_text (s), ffeexpr_stack_->tokens[0],
+ FALSE, &gen, &spec, &imp))
+ {
+ ffebld_symter_set_generic (symter, gen);
+ ffebld_symter_set_specific (symter, spec);
+ ffebld_symter_set_implementation (symter, imp);
+ ffesymbol_set_generic (s, gen);
+ ffesymbol_set_specific (s, spec);
+ ffesymbol_set_implementation (s, imp);
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ 0,
+ FFEINFO_kindFUNCTION,
+ FFEINFO_whereINTRINSIC,
+ ffesymbol_size (s)));
+ }
+ else
+ { /* Not intrinsic, now needs CHAR type. */
+ if (!ffeimplic_establish_symbol (s))
+ {
+ ffesymbol_error (s, ffeexpr_stack_->tokens[0]);
+ return (ffelexHandler) ffeexpr_token_arguments_ (ft, expr, t);
+ }
+
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ FFEINFO_kindFUNCTION,
+ (where == FFEINFO_whereNONE)
+ ? FFEINFO_whereGLOBAL
+ : where,
+ ffesymbol_size (s)));
+ }
+
+ ffebld_set_info (symter, ffeinfo_use (ffesymbol_info (s)));
+
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ s = ffecom_sym_learned (s);
+ ffesymbol_reference (s, ffeexpr_stack_->tokens[0], FALSE);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ ffebld_init_list (&ffeexpr_stack_->expr, &ffeexpr_stack_->bottom);
+ return (ffelexHandler) ffeexpr_token_arguments_ (ft, expr, t);
+}
+
+/* ffeexpr_token_anything_ -- NAME OPEN_PAREN any-expr
+
+ Handle basically any expression, looking for CLOSE_PAREN. */
+
+static ffelexHandler
+ffeexpr_token_anything_ (ffelexToken ft UNUSED, ffebld expr UNUSED,
+ ffelexToken t)
+{
+ ffeexprExpr_ e = ffeexpr_stack_->exprstack;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLON:
+ return (ffelexHandler) ffeexpr_rhs (ffeexpr_stack_->pool,
+ FFEEXPR_contextACTUALARG_,
+ ffeexpr_token_anything_);
+
+ default:
+ e->u.operand = ffebld_new_any ();
+ ffebld_set_info (e->u.operand, ffeinfo_new_any ());
+ ffelex_token_kill (ffeexpr_stack_->tokens[0]);
+ ffeexpr_is_substr_ok_ = FALSE;
+ if (ffelex_token_type (t) == FFELEX_typeCLOSE_PAREN)
+ return (ffelexHandler) ffeexpr_token_substrp_;
+ return (ffelexHandler) ffeexpr_token_substrp_ (t);
+ }
+}
+
+/* Terminate module. */
+
+void
+ffeexpr_terminate_2 ()
+{
+ assert (ffeexpr_stack_ == NULL);
+ assert (ffeexpr_level_ == 0);
+}
diff --git a/contrib/gcc/f/expr.h b/contrib/gcc/f/expr.h
new file mode 100644
index 0000000..04143e6
--- /dev/null
+++ b/contrib/gcc/f/expr.h
@@ -0,0 +1,194 @@
+/* expr.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ expr.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_expr
+#define _H_f_expr
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFEEXPR_contextLET,
+ FFEEXPR_contextASSIGN,
+ FFEEXPR_contextIOLIST,
+ FFEEXPR_contextPARAMETER,
+ FFEEXPR_contextSUBROUTINEREF,
+ FFEEXPR_contextDATA,
+ FFEEXPR_contextIF,
+ FFEEXPR_contextARITHIF,
+ FFEEXPR_contextDO,
+ FFEEXPR_contextDOWHILE,
+ FFEEXPR_contextFORMAT,
+ FFEEXPR_contextAGOTO,
+ FFEEXPR_contextCGOTO,
+ FFEEXPR_contextCHARACTERSIZE,
+ FFEEXPR_contextEQUIVALENCE,
+ FFEEXPR_contextSTOP,
+ FFEEXPR_contextRETURN,
+ FFEEXPR_contextSFUNCDEF,
+ FFEEXPR_contextINCLUDE,
+ FFEEXPR_contextWHERE,
+ FFEEXPR_contextSELECTCASE,
+ FFEEXPR_contextCASE,
+ FFEEXPR_contextDIMLIST,
+ FFEEXPR_contextDIMLISTCOMMON, /* Dim list in COMMON stmt. */
+ FFEEXPR_contextFILEASSOC, /* ASSOCIATEVARIABLE=. */
+ FFEEXPR_contextFILEINT, /* IOSTAT=. */
+ FFEEXPR_contextFILEDFINT, /* NEXTREC=. */
+ FFEEXPR_contextFILELOG, /* NAMED=. */
+ FFEEXPR_contextFILENUM, /* Numerical expression. */
+ FFEEXPR_contextFILECHAR, /* Character expression. */
+ FFEEXPR_contextFILENUMCHAR, /* READ KEYxyz=. */
+ FFEEXPR_contextFILEDFCHAR, /* Default kind character expression. */
+ FFEEXPR_contextFILEKEY, /* OPEN KEY=. */
+ FFEEXPR_contextFILEEXTFUNC, /* USEROPEN=. */
+ FFEEXPR_contextFILEUNIT, /* READ/WRITE UNIT=. */
+ FFEEXPR_contextFILEUNIT_DF, /* DEFINE FILE unit (no "(" after it). */
+ FFEEXPR_contextFILEFORMATNML, /* [FMT=] or [NML=]. */
+ FFEEXPR_contextFILEFORMAT, /* FMT=. */
+ FFEEXPR_contextFILENAMELIST,/* NML=. */
+ FFEEXPR_contextFILENUMAMBIG,/* BACKSPACE, ENDFILE, REWIND, UNLOCK...
+ where at e.g. BACKSPACE(, if COMMA seen
+ before ), it is ok. */
+ FFEEXPR_contextFILEUNITAMBIG, /* READ(, if COMMA seen before ), ok. */
+ FFEEXPR_contextFILEVXTCODE, /* ENCODE/DECODE third arg (scalar/array). */
+ FFEEXPR_contextALLOCATE, /* ALLOCATE objects (weird). */
+ FFEEXPR_contextDEALLOCATE, /* DEALLOCATE objects (weird). */
+ FFEEXPR_contextHEAPSTAT, /* ALLOCATE/DEALLOCATE STAT= variable. */
+ FFEEXPR_contextKINDTYPE, /* KIND=. */
+ FFEEXPR_contextINITVAL, /* R426 =initialization-expr. */
+ FFEEXPR_contextNULLIFY, /* Pointer names only (F90) or pointers. */
+ FFEEXPR_contextIOLISTDF, /* IOLIST w/internal file (V112 9-14 30,31). */
+ FFEEXPR_contextINDEX_, /* Element dimension or substring value. */
+ FFEEXPR_contextEQVINDEX_, /* EQUIVALENCE element dimension. */
+ FFEEXPR_contextDATAIMPDOINDEX_, /* INDEX in DATAIMPDO context. */
+ FFEEXPR_contextIMPDOITEM_,
+ FFEEXPR_contextIMPDOITEMDF_,/* to ...ITEM_ as IOLISTDF is to IOLIST. */
+ FFEEXPR_contextIMPDOCTRL_,
+ FFEEXPR_contextDATAIMPDOITEM_,
+ FFEEXPR_contextDATAIMPDOCTRL_,
+ FFEEXPR_contextLOC_,
+ FFEEXPR_contextACTUALARG_, /* Actual arg to function or subroutine;
+ turns into ACTUALARGEXPR_ if tokens not
+ NAME (CLOSE_PAREN/COMMA) or PERCENT.... */
+ FFEEXPR_contextACTUALARGEXPR_, /* Like LET but disallow CHAR*(*)
+ concats. */
+ FFEEXPR_contextINDEXORACTUALARG_, /* "CHARACTER FOO; PRINT *,FOO(?". */
+ FFEEXPR_contextINDEXORACTUALARGEXPR_, /* ? not NAME
+ (CLOSE_PAREN/COMMA). */
+ FFEEXPR_contextSFUNCDEFINDEX_, /* INDEX_ within stmt-func def. */
+ FFEEXPR_contextSFUNCDEFACTUALARG_,
+ FFEEXPR_contextSFUNCDEFACTUALARGEXPR_,
+ FFEEXPR_contextSFUNCDEFINDEXORACTUALARG_,
+ FFEEXPR_contextSFUNCDEFINDEXORACTUALARGEXPR_,
+ FFEEXPR_contextPAREN_, /* Rhs paren except in LET context. */
+ FFEEXPR_contextPARENFILENUM_, /* Either PAREN or FILENUM context. */
+ FFEEXPR_contextPARENFILEUNIT_, /* Either PAREN or FILEUNIT context. */
+ FFEEXPR_context
+ } ffeexprContext;
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "bld.h"
+#include "lex.h"
+#include "malloc.h"
+
+/* Structure definitions. */
+
+typedef ffelexHandler (*ffeexprCallback) (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+ffebld ffeexpr_collapse_convert (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_paren (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_uplus (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_uminus (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_not (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_add (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_subtract (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_multiply (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_divide (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_power (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_concatenate (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_lt (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_le (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_eq (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_ne (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_gt (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_ge (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_and (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_or (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_xor (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_eqv (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_neqv (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_symter (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_funcref (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_arrayref (ffebld expr, ffelexToken t);
+ffebld ffeexpr_collapse_substr (ffebld expr, ffelexToken t);
+ffebld ffeexpr_convert (ffebld source, ffelexToken source_token,
+ ffelexToken dest_token, ffeinfoBasictype bt, ffeinfoKindtype kt,
+ ffeinfoRank rk, ffetargetCharacterSize sz,
+ ffeexprContext context);
+ffebld ffeexpr_convert_expr (ffebld source, ffelexToken source_token,
+ ffebld dest, ffelexToken dest_token,
+ ffeexprContext context);
+ffebld ffeexpr_convert_to_sym (ffebld source, ffelexToken source_token,
+ ffesymbol dest, ffelexToken dest_token);
+void ffeexpr_init_2 (void);
+ffelexHandler ffeexpr_rhs (mallocPool pool, ffeexprContext context,
+ ffeexprCallback callback);
+ffelexHandler ffeexpr_lhs (mallocPool pool, ffeexprContext context,
+ ffeexprCallback callback);
+void ffeexpr_terminate_2 (void);
+void ffeexpr_type_combine (ffeinfoBasictype *nbt, ffeinfoKindtype *nkt,
+ ffeinfoBasictype lbt, ffeinfoKindtype lkt,
+ ffeinfoBasictype rbt, ffeinfoKindtype rkt,
+ ffelexToken t);
+
+/* Define macros. */
+
+#define ffeexpr_init_0()
+#define ffeexpr_init_1()
+#define ffeexpr_init_3()
+#define ffeexpr_init_4()
+#define ffeexpr_terminate_0()
+#define ffeexpr_terminate_1()
+#define ffeexpr_terminate_3()
+#define ffeexpr_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/fini.c b/contrib/gcc/f/fini.c
new file mode 100644
index 0000000..439ecca
--- /dev/null
+++ b/contrib/gcc/f/fini.c
@@ -0,0 +1,773 @@
+/* fini.c
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "proj.h"
+#include "malloc.h"
+
+#define MAXNAMELEN 100
+
+typedef struct _name_ *name;
+
+struct _name_
+ {
+ name next;
+ name previous;
+ name next_alpha;
+ name previous_alpha;
+ int namelen;
+ int kwlen;
+ char kwname[MAXNAMELEN];
+ char name_uc[MAXNAMELEN];
+ char name_lc[MAXNAMELEN];
+ char name_ic[MAXNAMELEN];
+ };
+
+struct _name_root_
+ {
+ name first;
+ name last;
+ };
+
+struct _name_alpha_
+ {
+ name ign1;
+ name ign2;
+ name first;
+ name last;
+ };
+
+static FILE *in;
+static FILE *out;
+static char prefix[32];
+static char postfix[32];
+static char storage[32];
+static char *spaces[]
+=
+{
+ "", /* 0 */
+ " ", /* 1 */
+ " ", /* 2 */
+ " ", /* 3 */
+ " ", /* 4 */
+ " ", /* 5 */
+ " ", /* 6 */
+ " ", /* 7 */
+ "\t", /* 8 */
+ "\t ", /* 9 */
+ "\t ", /* 10 */
+ "\t ", /* 11 */
+ "\t ", /* 12 */
+ "\t ", /* 13 */
+ "\t ", /* 14 */
+ "\t ", /* 15 */
+ "\t\t", /* 16 */
+ "\t\t ", /* 17 */
+ "\t\t ", /* 18 */
+ "\t\t ", /* 19 */
+ "\t\t ", /* 20 */
+ "\t\t ", /* 21 */
+ "\t\t ", /* 22 */
+ "\t\t ", /* 23 */
+ "\t\t\t", /* 24 */
+ "\t\t\t ", /* 25 */
+ "\t\t\t ", /* 26 */
+ "\t\t\t ", /* 27 */
+ "\t\t\t ", /* 28 */
+ "\t\t\t ", /* 29 */
+ "\t\t\t ", /* 30 */
+ "\t\t\t ", /* 31 */
+ "\t\t\t\t", /* 32 */
+ "\t\t\t\t ", /* 33 */
+ "\t\t\t\t ", /* 34 */
+ "\t\t\t\t ", /* 35 */
+ "\t\t\t\t ", /* 36 */
+ "\t\t\t\t ", /* 37 */
+ "\t\t\t\t ", /* 38 */
+ "\t\t\t\t ", /* 39 */
+ "\t\t\t\t\t", /* 40 */
+ "\t\t\t\t\t ", /* 41 */
+ "\t\t\t\t\t ", /* 42 */
+ "\t\t\t\t\t ", /* 43 */
+ "\t\t\t\t\t ", /* 44 */
+ "\t\t\t\t\t ", /* 45 */
+ "\t\t\t\t\t ", /* 46 */
+ "\t\t\t\t\t ", /* 47 */
+ "\t\t\t\t\t\t", /* 48 */
+ "\t\t\t\t\t\t ", /* 49 */
+ "\t\t\t\t\t\t ", /* 50 */
+ "\t\t\t\t\t\t ", /* 51 */
+ "\t\t\t\t\t\t ", /* 52 */
+ "\t\t\t\t\t\t ", /* 53 */
+ "\t\t\t\t\t\t ", /* 54 */
+ "\t\t\t\t\t\t ", /* 55 */
+ "\t\t\t\t\t\t\t", /* 56 */
+ "\t\t\t\t\t\t\t ", /* 57 */
+ "\t\t\t\t\t\t\t ", /* 58 */
+ "\t\t\t\t\t\t\t ", /* 59 */
+ "\t\t\t\t\t\t\t ", /* 60 */
+ "\t\t\t\t\t\t\t ", /* 61 */
+ "\t\t\t\t\t\t\t ", /* 62 */
+ "\t\t\t\t\t\t\t ", /* 63 */
+ "\t\t\t\t\t\t\t\t", /* 64 */
+ "\t\t\t\t\t\t\t\t ", /* 65 */
+ "\t\t\t\t\t\t\t\t ", /* 66 */
+ "\t\t\t\t\t\t\t\t ", /* 67 */
+ "\t\t\t\t\t\t\t\t ", /* 68 */
+ "\t\t\t\t\t\t\t\t ", /* 69 */
+ "\t\t\t\t\t\t\t\t ", /* 70 */
+ "\t\t\t\t\t\t\t\t ", /* 71 */
+ "\t\t\t\t\t\t\t\t\t", /* 72 */
+ "\t\t\t\t\t\t\t\t\t ", /* 73 */
+ "\t\t\t\t\t\t\t\t\t ", /* 74 */
+ "\t\t\t\t\t\t\t\t\t ", /* 75 */
+ "\t\t\t\t\t\t\t\t\t ", /* 76 */
+ "\t\t\t\t\t\t\t\t\t ", /* 77 */
+ "\t\t\t\t\t\t\t\t\t ", /* 78 */
+ "\t\t\t\t\t\t\t\t\t ", /* 79 */
+ "\t\t\t\t\t\t\t\t\t\t", /* 80 */
+ "\t\t\t\t\t\t\t\t\t\t ", /* 81 */
+ "\t\t\t\t\t\t\t\t\t\t ", /* 82 */
+ "\t\t\t\t\t\t\t\t\t\t ", /* 83 */
+ "\t\t\t\t\t\t\t\t\t\t ", /* 84 */
+ "\t\t\t\t\t\t\t\t\t\t ", /* 85 */
+ "\t\t\t\t\t\t\t\t\t\t ", /* 86 */
+ "\t\t\t\t\t\t\t\t\t\t ",/* 87 */
+ "\t\t\t\t\t\t\t\t\t\t\t", /* 88 */
+ "\t\t\t\t\t\t\t\t\t\t\t ", /* 89 */
+ "\t\t\t\t\t\t\t\t\t\t\t ", /* 90 */
+ "\t\t\t\t\t\t\t\t\t\t\t ", /* 91 */
+ "\t\t\t\t\t\t\t\t\t\t\t ", /* 92 */
+ "\t\t\t\t\t\t\t\t\t\t\t ",/* 93 */
+ "\t\t\t\t\t\t\t\t\t\t\t ", /* 94 */
+ "\t\t\t\t\t\t\t\t\t\t\t ", /* 95 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t", /* 96 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t ", /* 97 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t ", /* 98 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t ",/* 99 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t ", /* 100 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t ", /* 101 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t ", /* 102 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t ", /* 103 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t", /* 104 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t ",/* 105 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 106 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 107 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 108 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 109 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 110 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 111 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t", /* 112 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 113 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 114 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 115 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 116 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 117 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 118 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 119 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t", /* 120 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 121 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 122 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 123 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 124 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 125 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 126 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 127 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t", /* 128 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 129 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 130 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 131 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 132 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 133 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 134 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 135 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t", /* 136 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 137 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 138 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 139 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 140 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 141 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 142 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 143 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t", /* 144 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 145 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 146 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 147 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 148 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 149 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 150 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 151 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t", /* 152 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 153 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 154 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 155 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 156 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 157 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 158 */
+ "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t ", /* 159 */
+};
+
+void testname (bool nested, int indent, name first, name last);
+void testnames (bool nested, int indent, int len, name first, name last);
+
+int
+main (int argc, char **argv)
+{
+ char buf[MAXNAMELEN];
+ char last_buf[MAXNAMELEN] = "";
+ char kwname[MAXNAMELEN];
+ char routine[32];
+ char type[32];
+ int i;
+ int count;
+ int len;
+ struct _name_root_ names[200];
+ struct _name_alpha_ names_alpha;
+ name n;
+ name newname;
+ char *input_name;
+ char *output_name;
+ char *include_name;
+ FILE *incl;
+ int fixlengths;
+ int total_length;
+ int do_name; /* TRUE if token may be NAME. */
+ int do_names; /* TRUE if token may be NAMES. */
+ int cc;
+ bool do_exit = FALSE;
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (names); ++i)
+ { /* Initialize length/name ordered list roots. */
+ names[i].first = (name) &names[i];
+ names[i].last = (name) &names[i];
+ }
+ names_alpha.first = (name) &names_alpha; /* Initialize name order. */
+ names_alpha.last = (name) &names_alpha;
+
+ if (argc != 4)
+ {
+ fprintf (stderr, "Command form: fini input output-code output-include\n");
+ exit (1);
+ }
+
+ input_name = argv[1];
+ output_name = argv[2];
+ include_name = argv[3];
+
+ in = fopen (input_name, "r");
+ if (in == NULL)
+ {
+ fprintf (stderr, "Cannot open \"%s\"\n", input_name);
+ exit (1);
+ }
+ out = fopen (output_name, "w");
+ if (out == NULL)
+ {
+ fclose (in);
+ fprintf (stderr, "Cannot open \"%s\"\n", output_name);
+ exit (1);
+ }
+ incl = fopen (include_name, "w");
+ if (incl == NULL)
+ {
+ fclose (in);
+ fprintf (stderr, "Cannot open \"%s\"\n", include_name);
+ exit (1);
+ }
+
+ /* Get past the initial block-style comment (man, this parsing code is just
+ _so_ lame, but I'm too lazy to improve it). */
+
+ for (;;)
+ {
+ cc = getc (in);
+ if (cc == '{')
+ {
+ while (((cc = getc (in)) != '}') && (cc != EOF))
+ ;
+ }
+ else if (cc != EOF)
+ {
+ while (((cc = getc (in)) != EOF) && (! ISALNUM (cc)))
+ ;
+ ungetc (cc, in);
+ break;
+ }
+ else
+ {
+ assert ("EOF too soon!" == NULL);
+ exit (1);
+ }
+ }
+
+ fscanf (in, "%s %s %s %s %s %d %d", prefix, postfix, storage, type, routine,
+ &do_name, &do_names);
+
+ if (storage[0] == '\0')
+ storage[1] = '\0';
+ else
+ /* Assume string is quoted somehow, replace ending quote with space. */
+ {
+ if (storage[2] == '\0')
+ storage[1] = '\0';
+ else
+ storage[strlen (storage) - 1] = ' ';
+ }
+
+ if (postfix[0] == '\0')
+ postfix[1] = '\0';
+ else /* Assume string is quoted somehow, strip off
+ ending quote. */
+ postfix[strlen (postfix) - 1] = '\0';
+
+ for (i = 1; storage[i] != '\0'; ++i)
+ storage[i - 1] = storage[i];
+ storage[i - 1] = '\0';
+
+ for (i = 1; postfix[i] != '\0'; ++i)
+ postfix[i - 1] = postfix[i];
+ postfix[i - 1] = '\0';
+
+ fixlengths = strlen (prefix) + strlen (postfix);
+
+ while (TRUE)
+ {
+ count = fscanf (in, "%s %s", buf, kwname);
+ if (count == EOF)
+ break;
+ len = strlen (buf);
+ if (len == 0)
+ continue; /* Skip empty lines. */
+ if (buf[0] == ';')
+ continue; /* Skip commented-out lines. */
+ for (i = strlen (buf) - 1; i > 0; --i)
+ cc = buf[i];
+
+ /* Make new name object to store name and its keyword. */
+
+ newname = (name) malloc (sizeof (*newname));
+ newname->namelen = strlen (buf);
+ newname->kwlen = strlen (kwname);
+ total_length = newname->kwlen + fixlengths;
+ if (total_length >= 32) /* Else resulting keyword name too long. */
+ {
+ fprintf (stderr, "%s: %s%s%s is 31+%d chars long\n", input_name,
+ prefix, kwname, postfix, total_length - 31);
+ do_exit = TRUE;
+ }
+ strcpy (newname->kwname, kwname);
+ for (i = 0; i < newname->namelen; ++i)
+ {
+ cc = buf[i];
+ if (ISALPHA (cc))
+ {
+ newname->name_uc[i] = toupper (cc);
+ newname->name_lc[i] = tolower (cc);
+ newname->name_ic[i] = cc;
+ }
+ else
+ newname->name_uc[i] = newname->name_lc[i] = newname->name_ic[i]
+ = cc;
+ }
+ newname->name_uc[i] = newname->name_lc[i] = newname->name_ic[i] = '\0';
+
+ /* Warn user if names aren't alphabetically ordered. */
+
+ if ((last_buf[0] != '\0')
+ && (strcmp (last_buf, newname->name_uc) >= 0))
+ {
+ fprintf (stderr, "%s: \"%s\" precedes \"%s\"\n", input_name,
+ last_buf, newname->name_uc);
+ do_exit = TRUE;
+ }
+ strcpy (last_buf, newname->name_uc);
+
+ /* Append name to end of alpha-sorted list (assumes names entered in
+ alpha order wrt name, not kwname, even though kwname is output from
+ this list). */
+
+ n = names_alpha.last;
+ newname->next_alpha = n->next_alpha;
+ newname->previous_alpha = n;
+ n->next_alpha->previous_alpha = newname;
+ n->next_alpha = newname;
+
+ /* Insert name in appropriate length/name ordered list. */
+
+ n = (name) &names[len];
+ while ((n->next != (name) &names[len])
+ && (strcmp (buf, n->next->name_uc) > 0))
+ n = n->next;
+ if (strcmp (buf, n->next->name_uc) == 0)
+ {
+ fprintf (stderr, "%s: extraneous \"%s\"\n", input_name, buf);
+ do_exit = TRUE;
+ }
+ newname->next = n->next;
+ newname->previous = n;
+ n->next->previous = newname;
+ n->next = newname;
+ }
+
+#if 0
+ for (len = 0; len < ARRAY_SIZE (name); ++len)
+ {
+ if (names[len].first == (name) &names[len])
+ continue;
+ printf ("Length %d:\n", len);
+ for (n = names[len].first; n != (name) &names[len]; n = n->next)
+ printf (" %s %s %s\n", n->name_uc, n->name_lc, n->name_ic);
+ }
+#endif
+
+ if (do_exit)
+ exit (1);
+
+ /* First output the #include file. */
+
+ for (n = names_alpha.first; n != (name) &names_alpha; n = n->next_alpha)
+ {
+ fprintf (incl, "#define %sl%s%s %d\n", prefix, n->kwname, postfix,
+ n->namelen);
+ }
+
+ fprintf (incl,
+ "\
+\n\
+enum %s_\n\
+{\n\
+%sNone%s,\n\
+",
+ type, prefix, postfix);
+
+ for (n = names_alpha.first; n != (name) &names_alpha; n = n->next_alpha)
+ {
+ fprintf (incl,
+ "\
+%s%s%s,\n\
+",
+ prefix, n->kwname, postfix);
+ }
+
+ fprintf (incl,
+ "\
+%s%s\n\
+};\n\
+typedef enum %s_ %s;\n\
+",
+ prefix, postfix, type, type);
+
+ /* Now output the C program. */
+
+ fprintf (out,
+ "\
+%s%s\n\
+%s (ffelexToken t)\n\
+%c\n\
+ char *p;\n\
+ int c;\n\
+\n\
+ p = ffelex_token_text (t);\n\
+\n\
+",
+ storage, type, routine, '{');
+
+ if (do_name)
+ {
+ if (do_names)
+ fprintf (out,
+ "\
+ if (ffelex_token_type (t) == FFELEX_typeNAME)\n\
+ {\n\
+ switch (ffelex_token_length (t))\n\
+\t{\n\
+"
+ );
+ else
+ fprintf (out,
+ "\
+ assert (ffelex_token_type (t) == FFELEX_typeNAME);\n\
+\n\
+ switch (ffelex_token_length (t))\n\
+ {\n\
+"
+ );
+
+/* Now output the length as a case, followed by the binary search within that length. */
+
+ for (len = 0; ((size_t) len) < ARRAY_SIZE (names); ++len)
+ {
+ if (names[len].first != (name) &names[len])
+ {
+ if (do_names)
+ fprintf (out,
+ "\
+\tcase %d:\n\
+",
+ len);
+ else
+ fprintf (out,
+ "\
+ case %d:\n\
+",
+ len);
+ testname (FALSE, do_names ? 10 : 6, names[len].first, names[len].last);
+ if (do_names)
+ fprintf (out,
+ "\
+\t break;\n\
+"
+ );
+ else
+ fprintf (out,
+ "\
+ break;\n\
+"
+ );
+ }
+ }
+
+ if (do_names)
+ fprintf (out,
+ "\
+\t}\n\
+ return %sNone%s;\n\
+ }\n\
+\n\
+",
+ prefix, postfix);
+ else
+ fprintf (out,
+ "\
+ }\n\
+\n\
+ return %sNone%s;\n\
+}\n\
+",
+ prefix, postfix);
+ }
+
+ if (do_names)
+ {
+ fputs ("\
+ assert (ffelex_token_type (t) == FFELEX_typeNAMES);\n\
+\n\
+ switch (ffelex_token_length (t))\n\
+ {\n\
+ default:\n\
+",
+ out);
+
+ /* Find greatest non-empty length list. */
+
+ for (len = ARRAY_SIZE (names) - 1;
+ names[len].first == (name) &names[len];
+ --len)
+ ;
+
+/* Now output the length as a case, followed by the binary search within that length. */
+
+ if (len > 0)
+ {
+ for (; len != 0; --len)
+ {
+ fprintf (out,
+ "\
+ case %d:\n\
+",
+ len);
+ if (names[len].first != (name) &names[len])
+ testnames (FALSE, 6, len, names[len].first, names[len].last);
+ }
+ if (names[1].first == (name) &names[1])
+ fprintf (out,
+ "\
+ ;\n\
+"
+ ); /* Need empty statement after an empty case
+ 1: */
+ }
+
+ fprintf (out,
+ "\
+ }\n\
+\n\
+ return %sNone%s;\n\
+}\n\
+",
+ prefix, postfix);
+ }
+
+ if (out != stdout)
+ fclose (out);
+ if (incl != stdout)
+ fclose (incl);
+ if (in != stdin)
+ fclose (in);
+ exit (0);
+}
+
+void
+testname (bool nested, int indent, name first, name last)
+{
+ name n;
+ name nhalf;
+ int num;
+ int numhalf;
+
+ assert (!nested || indent >= 2);
+ assert (((size_t) indent) + 4 < ARRAY_SIZE (spaces));
+
+ num = 0;
+ numhalf = 0;
+ for (n = first, nhalf = first; n != last->next; n = n->next)
+ {
+ if ((++num & 1) == 0)
+ {
+ nhalf = nhalf->next;
+ ++numhalf;
+ }
+ }
+
+ if (nested)
+ fprintf (out,
+ "\
+%s{\n\
+",
+ spaces[indent - 2]);
+
+ fprintf (out,
+ "\
+%sif ((c = ffesrc_strcmp_2c (ffe_case_match (), p, \"%s\", \"%s\", \"%s\")) == 0)\n\
+%sreturn %s%s%s;\n\
+",
+ spaces[indent], nhalf->name_uc, nhalf->name_lc, nhalf->name_ic,
+ spaces[indent + 2], prefix, nhalf->kwname, postfix);
+
+ if (num != 1)
+ {
+ fprintf (out,
+ "\
+%selse if (c < 0)\n\
+",
+ spaces[indent]);
+
+ if (numhalf == 0)
+ fprintf (out,
+ "\
+%s;\n\
+",
+ spaces[indent + 2]);
+ else
+ testname (TRUE, indent + 4, first, nhalf->previous);
+
+ if (num - numhalf > 1)
+ {
+ fprintf (out,
+ "\
+%selse\n\
+",
+ spaces[indent]);
+
+ testname (TRUE, indent + 4, nhalf->next, last);
+ }
+ }
+
+ if (nested)
+ fprintf (out,
+ "\
+%s}\n\
+",
+ spaces[indent - 2]);
+}
+
+void
+testnames (bool nested, int indent, int len, name first, name last)
+{
+ name n;
+ name nhalf;
+ int num;
+ int numhalf;
+
+ assert (!nested || indent >= 2);
+ assert (((size_t) indent) + 4 < ARRAY_SIZE (spaces));
+
+ num = 0;
+ numhalf = 0;
+ for (n = first, nhalf = first; n != last->next; n = n->next)
+ {
+ if ((++num & 1) == 0)
+ {
+ nhalf = nhalf->next;
+ ++numhalf;
+ }
+ }
+
+ if (nested)
+ fprintf (out,
+ "\
+%s{\n\
+",
+ spaces[indent - 2]);
+
+ fprintf (out,
+ "\
+%sif ((c = ffesrc_strncmp_2c (ffe_case_match (), p, \"%s\", \"%s\", \"%s\", %d)) == 0)\n\
+%sreturn %s%s%s;\n\
+",
+ spaces[indent], nhalf->name_uc, nhalf->name_lc, nhalf->name_ic,
+ len, spaces[indent + 2], prefix, nhalf->kwname, postfix);
+
+ if (num != 1)
+ {
+ fprintf (out,
+ "\
+%selse if (c < 0)\n\
+",
+ spaces[indent]);
+
+ if (numhalf == 0)
+ fprintf (out,
+ "\
+%s;\n\
+",
+ spaces[indent + 2]);
+ else
+ testnames (TRUE, indent + 4, len, first, nhalf->previous);
+
+ if (num - numhalf > 1)
+ {
+ fprintf (out,
+ "\
+%selse\n\
+",
+ spaces[indent]);
+
+ testnames (TRUE, indent + 4, len, nhalf->next, last);
+ }
+ }
+
+ if (nested)
+ fprintf (out,
+ "\
+%s}\n\
+",
+ spaces[indent - 2]);
+}
diff --git a/contrib/gcc/f/flags.j b/contrib/gcc/f/flags.j
new file mode 100644
index 0000000..02742d8
--- /dev/null
+++ b/contrib/gcc/f/flags.j
@@ -0,0 +1,27 @@
+/* flags.j -- Wrapper for GCC's flags.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_flags
+#define _J_f_flags
+#include "flags.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/g77.1 b/contrib/gcc/f/g77.1
new file mode 100644
index 0000000..d6a465b
--- /dev/null
+++ b/contrib/gcc/f/g77.1
@@ -0,0 +1,357 @@
+.\" Copyright (c) 1995-1997 Free Software Foundation -*-Text-*-
+.\" See section COPYING for conditions for redistribution
+.\" FIXME: no info here on predefines. Should there be? extra for F77...
+.TH G77 1 "1998-09-01" "GNU Tools" "GNU Tools"
+.de BP
+.sp
+.ti \-.2i
+\(**
+..
+.SH NAME
+g77 \- GNU project Fortran Compiler (v0.5.24)
+.SH SYNOPSIS
+.RB g77 " [" \c
+.IR option " | " "filename " ].\|.\|.
+.SH WARNING
+The information in this man page is an extract from the full
+documentation of the GNU Fortran compiler (version 0.5.24),
+and is limited to the meaning of some of the options.
+.PP
+This man page is not up to date, since no volunteers want to
+maintain it. If you find a discrepancy between the man page and the
+software, please check the Info file, which is the authoritative
+documentation.
+.\" .PP
+.\" The version of GNU Fortran documented by the Info file is 0.5.24,
+.\" which includes substantial improvements and changes since 0.5.24,
+.\" the version documented in this man page.
+.PP
+If we find that the things in this man page that are out of date cause
+significant confusion or complaints, we will stop distributing the man
+page. The alternative, updating the man page when we update the Info
+file, is impractical because the rest of the work of maintaining GNU Fortran
+leaves us no time for that. The GNU project regards man pages as
+obsolete and should not let them take time away from other things.
+.PP
+For complete and current documentation, refer to the Info file `\|\c
+.B g77\c
+\&\|' or the manual
+.I
+Using and Porting GNU Fortran (for version 0.5.24)\c
+\&. Both are made from the Texinfo source file
+.BR g77.texi .
+.PP
+If your system has the `\|\c
+.B info\c
+\&\|' command installed, the command `\|\c
+.B info g77\c
+\&\|' should work, unless
+.B g77
+has not been properly installed.
+If your system lacks `\|\c
+.B info\c
+\&\|', or you wish to avoid using it for now,
+the command `\|\c
+.B more /usr/info/g77.info*\c
+\&\|' should work, unless
+.B g77
+has not been properly installed.
+.PP
+If
+.B g77
+has not been properly installed, so that you
+cannot easily access the Info file for it,
+ask your system administrator, or the installer
+of
+.B g77
+(if you know who that is) to fix the problem.
+.SH DESCRIPTION
+The C and F77 compilers are integrated;
+.B g77
+is a program to call
+.B gcc
+with options to recognize programs written in Fortran (ANSI FORTRAN 77,
+also called F77).
+.B gcc
+processes input files
+through one or more of four stages: preprocessing, compilation,
+assembly, and linking. This man page contains full descriptions for
+.I only
+F77-specific aspects of the compiler, though it also contains
+summaries of some general-purpose options. For a fuller explanation
+of the compiler, see
+.BR gcc ( 1 ).
+
+For complete documentation on GNU Fortran, type `\|\c
+.B info g77\c
+\&\|'.
+
+F77 source files use the suffix `\|\c
+.B .f\c
+\&\|' or `\|\c
+.B .for\c
+\&\|'; F77 files to be preprocessed by
+.BR cpp ( 1 )
+use the suffix `\|\c
+.B .F\c
+\&\|' or `\|\c
+.B .fpp\c
+\&\|'; Ratfor source files use the suffix `\|\c
+.B .r\c
+\&\|' (though
+.B ratfor
+itself is not supplied as part of
+.B g77\c
+\&).
+.SH OPTIONS
+There are many command-line options, including options to control
+details of optimization, warnings, and code generation, which are
+common to both
+.B gcc
+and
+.B g77\c
+\&. For full information on all options, see
+.BR gcc ( 1 ).
+
+Options must be separate: `\|\c
+.B \-dr\c
+\&\|' is quite different from `\|\c
+.B \-d \-r
+\&\|'.
+
+Most `\|\c
+.B \-f\c
+\&\|' and `\|\c
+.B \-W\c
+\&\|' options have two contrary forms:
+.BI \-f name
+and
+.BI \-fno\- name\c
+\& (or
+.BI \-W name
+and
+.BI \-Wno\- name\c
+\&). Only the non-default forms are shown here.
+
+.TP
+.B \-c
+Compile or assemble the source files, but do not link. The compiler
+output is an object file corresponding to each source file.
+.TP
+.BI \-D macro
+Define macro \c
+.I macro\c
+\& with the string `\|\c
+.B 1\c
+\&\|' as its definition.
+.TP
+.BI \-D macro = defn
+Define macro \c
+.I macro\c
+\& as \c
+.I defn\c
+\&.
+.TP
+.B \-E
+Stop after the preprocessing stage; do not run the compiler proper. The
+output is preprocessed source code, which is sent to the
+standard output.
+.TP
+.B \-g
+Produce debugging information in the operating system's native format
+(for DBX or SDB or DWARF). GDB also can work with this debugging
+information. On most systems that use DBX format, `\|\c
+.B \-g\c
+\&\|' enables use
+of extra debugging information that only GDB can use.
+
+Unlike most other Fortran compilers, GNU Fortran allows you to use `\|\c
+.B \-g\c
+\&\|' with
+`\|\c
+.B \-O\c
+\&\|'. The shortcuts taken by optimized code may occasionally
+produce surprising results: some variables you declared may not exist
+at all; flow of control may briefly move where you did not expect it;
+some statements may not be executed because they compute constant
+results or their values were already at hand; some statements may
+execute in different places because they were moved out of loops.
+
+Nevertheless it proves possible to debug optimized output. This makes
+it reasonable to use the optimizer for programs that might have bugs.
+.TP
+.BI "\-I" "dir"\c
+\&
+Append directory \c
+.I dir\c
+\& to the list of directories searched for include files.
+.TP
+.BI "\-L" "dir"\c
+\&
+Add directory \c
+.I dir\c
+\& to the list of directories to be searched
+for `\|\c
+.B \-l\c
+\&\|'.
+.TP
+.BI \-l library\c
+\&
+Use the library named \c
+.I library\c
+\& when linking.
+.TP
+.B \-nostdinc
+Do not search the standard system directories for header files. Only
+the directories you have specified with
+.B \-I
+options (and the current directory, if appropriate) are searched.
+.TP
+.B \-O
+Optimize. Optimizing compilation takes somewhat more time, and a lot
+more memory for a large function. See the GCC documentation for
+further optimisation options. Loop unrolling, in particular, may be
+worth investigating for typical numerical Fortran programs.
+.TP
+.BI "\-o " file\c
+\&
+Place output in file \c
+.I file\c
+\&.
+.TP
+.B \-S
+Stop after the stage of compilation proper; do not assemble. The output
+is an assembler code file for each non-assembler input
+file specified.
+.TP
+.BI \-U macro
+Undefine macro \c
+.I macro\c
+\&.
+.TP
+.B \-v
+Print (on standard error output) the commands executed to run the
+stages of compilation. Also print the version number of the compiler
+driver program and of the preprocessor and the compiler proper. The
+version numbers of g77 itself and the GCC distribution on which it is
+based are distinct.
+.TP
+.B \-Wall
+Issue warnings for conditions which pertain to usage that we recommend
+avoiding and that we believe is easy to avoid, even in conjunction
+with macros.
+.PP
+
+.SH FILES
+.ta \w'LIBDIR/g77\-include 'u
+file.h C header (preprocessor) file
+.br
+file.f Fortran source file
+.br
+file.for Fortran source file
+.br
+file.F preprocessed Fortran source file
+.br
+file.fpp preprocessed Fortran source file
+.br
+file.r Ratfor source file (ratfor not included)
+.br
+file.s assembly language file
+.br
+file.o object file
+.br
+a.out link edited output
+.br
+\fITMPDIR\fR/cc\(** temporary files
+.br
+\fILIBDIR\fR/cpp preprocessor
+.br
+\fILIBDIR\fR/f771 compiler
+.br
+\fILIBDIR\fR/libg2c.a Fortran run-time library
+.br
+\fILIBDIR\fR/libgcc.a GCC subroutine library
+.br
+/lib/crt[01n].o start-up routine
+.br
+/lib/libc.a standard C library, see
+.IR intro (3)
+.br
+/usr/include standard directory for
+.B #include
+files
+.br
+\fILIBDIR\fR/include standard gcc directory for
+.B #include
+.br
+ files.
+.sp
+.I LIBDIR
+is usually
+.B /usr/local/lib/\c
+.IR machine / version .
+.sp
+.I TMPDIR
+comes from the environment variable
+.B TMPDIR
+(default
+.B /usr/tmp
+if available, else
+.B /tmp\c
+\&).
+.SH "SEE ALSO"
+gcc(1), cpp(1), as(1), ld(1), gdb(1), adb(1), dbx(1), sdb(1).
+.br
+.RB "`\|" g77 "\|', `\|" gcc "\|', `\|" cpp "\|',"
+.RB "`\|" as "\|', `\|" ld "\|',"
+and
+.RB "`\|" gdb "\|'"
+entries in
+.B info\c
+\&.
+.br
+.I
+Using and Porting GNU Fortran (for version 0.5.24)\c
+, James Craig Burley;
+.I
+Using and Porting GNU CC (for version 2.0)\c
+, Richard M. Stallman;
+.I
+The C Preprocessor\c
+, Richard M. Stallman;
+.I
+Debugging with GDB: the GNU Source-Level Debugger\c
+, Richard M. Stallman and Roland H. Pesch;
+.I
+Using as: the GNU Assembler\c
+, Dean Elsner, Jay Fenlason & friends;
+.I
+gld: the GNU linker\c
+, Steve Chamberlain and Roland Pesch.
+
+.SH BUGS
+For instructions on how to report bugs, type `\|\c
+.B info g77 -n Bugs\c
+\&\|'.
+
+.SH COPYING
+Copyright (c) 1991-1998 Free Software Foundation, Inc.
+.PP
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+.PP
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the
+entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
+.PP
+Permission is granted to copy and distribute translations of this
+manual into another language, under the above conditions for modified
+versions, except that this permission notice may be included in
+translations approved by the Free Software Foundation instead of in
+the original English.
+.SH AUTHORS
+See the GNU CC Manual for the contributors to GNU CC.
+See the GNU Fortran Manual for the contributors to
+GNU Fortran.
diff --git a/contrib/gcc/f/g77.texi b/contrib/gcc/f/g77.texi
new file mode 100644
index 0000000..48c36e9
--- /dev/null
+++ b/contrib/gcc/f/g77.texi
@@ -0,0 +1,14999 @@
+\input texinfo @c -*-texinfo-*-
+@c fix @set inside @example:
+@tex
+\gdef\set{\begingroup\catcode` =10 \parsearg\setxxx}
+\gdef\setyyy#1 #2\endsetyyy{%
+ \def\temp{#2}%
+ \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty
+ \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted.
+ \fi
+ \endgroup
+}
+@end tex
+
+@c %**start of header
+@setfilename g77.info
+
+@set last-up-date 1999-03-11
+@set version-g77 0.5.24
+@set version-egcs 1.1.2
+@set email-general egcs@@egcs.cygnus.com
+@set email-bugs egcs-bugs@@egcs.cygnus.com
+@set email-burley craig@@jcb-sc.com
+@set path-g77 egcs/gcc/f
+@set path-libf2c egcs/libf2c
+@set which-g77 @code{egcs}-@value{version-egcs}
+
+@c @setfilename useg77.info
+@c @setfilename portg77.info
+@c To produce the full manual, use the "g77.info" setfilename, and
+@c make sure the following do NOT begin with '@c' (and the @clear lines DO)
+@set INTERNALS
+@set USING
+@c To produce a user-only manual, use the "useg77.info" setfilename, and
+@c make sure the following does NOT begin with '@c':
+@c @clear INTERNALS
+@c To produce a porter-only manual, use the "portg77.info" setfilename,
+@c and make sure the following does NOT begin with '@c':
+@c @clear USING
+
+@c (For FSF printing, turn on smallbook; that is all that is needed.)
+
+@c smallbook
+
+@ifset INTERNALS
+@ifset USING
+@settitle Using and Porting GNU Fortran
+@end ifset
+@end ifset
+@c seems reasonable to assume at least one of INTERNALS or USING is set...
+@ifclear INTERNALS
+@settitle Using GNU Fortran
+@end ifclear
+@ifclear USING
+@settitle Porting GNU Fortran
+@end ifclear
+@c then again, have some fun
+@ifclear INTERNALS
+@ifclear USING
+@settitle Doing Squat with GNU Fortran
+@end ifclear
+@end ifclear
+
+@syncodeindex fn cp
+@syncodeindex vr cp
+@c %**end of header
+@setchapternewpage odd
+
+@ifinfo
+This file explains how to use the GNU Fortran system.
+
+Published by the Free Software Foundation
+59 Temple Place - Suite 330
+Boston, MA 02111-1307 USA
+
+Copyright (C) 1995-1997 Free Software Foundation, Inc.
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through Tex and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``GNU General Public License,'' ``Funding for Free
+Software,'' and ``Protect Your Freedom---Fight `Look And Feel'@w{}'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the sections entitled ``GNU General Public License,''
+``Funding for Free Software,'' and ``Protect Your Freedom---Fight `Look
+And Feel'@w{}'', and this permission notice, may be included in
+translations approved by the Free Software Foundation instead of in the
+original English.
+@end ifinfo
+
+Contributed by James Craig Burley (@email{@value{email-burley}}).
+Inspired by a first pass at translating @file{g77-0.5.16/f/DOC} that
+was contributed to Craig by David Ronis (@email{ronis@@onsager.chem.mcgill.ca}).
+
+@finalout
+@titlepage
+@comment The title is printed in a large font.
+@center @titlefont{Using GNU Fortran}
+@sp 2
+@center James Craig Burley
+@sp 3
+@center Last updated @value{last-up-date}
+@sp 1
+@c The version number appears some more times in this file.
+
+@center for version @value{version-g77}
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1995-1997 Free Software Foundation, Inc.
+@sp 2
+For GNU Fortran Version @value{version-g77}*
+@sp 1
+Published by the Free Software Foundation @*
+59 Temple Place - Suite 330@*
+Boston, MA 02111-1307, USA@*
+@c Last printed ??ber, 19??.@*
+@c Printed copies are available for $? each.@*
+@c ISBN ???
+@sp 1
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided also that the
+sections entitled ``GNU General Public License,'' ``Funding for Free
+Software,'' and ``Protect Your Freedom---Fight `Look And Feel'@w{}'' are
+included exactly as in the original, and provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that the sections entitled ``GNU General Public License,''
+``Funding for Free Software,'' and ``Protect Your Freedom---Fight `Look
+And Feel'@w{}'', and this permission notice, may be included in
+translations approved by the Free Software Foundation instead of in the
+original English.
+@end titlepage
+@page
+
+@ifinfo
+
+@dircategory Programming
+@direntry
+* g77: (g77). The GNU Fortran compiler.
+@end direntry
+@node Top, Copying,, (DIR)
+@top Introduction
+@cindex Introduction
+
+@ifset INTERNALS
+@ifset USING
+This manual documents how to run, install and port the GNU Fortran
+compiler, as well as its new features and incompatibilities, and how to
+report bugs. It corresponds to GNU Fortran version @value{version-g77}.
+@end ifset
+@end ifset
+
+@ifclear INTERNALS
+This manual documents how to run and install the GNU Fortran compiler,
+as well as its new features and incompatibilities, and how to report
+bugs. It corresponds to GNU Fortran version @value{version-g77}.
+@end ifclear
+@ifclear USING
+This manual documents how to port the GNU Fortran compiler,
+as well as its new features and incompatibilities, and how to report
+bugs. It corresponds to GNU Fortran version @value{version-g77}.
+@end ifclear
+
+An online, ``live'' version of this document
+(derived directly from the up-to-date mainline version
+of @code{g77} within @code{egcs})
+is available at
+@uref{http://egcs.cygnus.com/onlinedocs/g77_toc.html}.
+
+@end ifinfo
+@menu
+* Copying:: GNU General Public License says
+ how you can copy and share GNU Fortran.
+* Contributors:: People who have contributed to GNU Fortran.
+* Funding:: How to help assure continued work for free software.
+* Funding GNU Fortran:: How to help assure continued work on GNU Fortran.
+* Look and Feel:: Protect your freedom---fight ``look and feel''.
+@ifset USING
+* Getting Started:: Finding your way around this manual.
+* What is GNU Fortran?:: How @code{g77} fits into the universe.
+* G77 and GCC:: You can compile Fortran, C, or other programs.
+* Invoking G77:: Command options supported by @code{g77}.
+* News:: News about recent releases of @code{g77}.
+* Changes:: User-visible changes to recent releases of @code{g77}.
+* Language:: The GNU Fortran language.
+* Compiler:: The GNU Fortran compiler.
+* Other Dialects:: Dialects of Fortran supported by @code{g77}.
+* Other Compilers:: Fortran compilers other than @code{g77}.
+* Other Languages:: Languages other than Fortran.
+* Installation:: How to configure, compile and install GNU Fortran.
+* Debugging and Interfacing:: How @code{g77} generates code.
+* Collected Fortran Wisdom:: How to avoid Trouble.
+* Trouble:: If you have trouble with GNU Fortran.
+* Open Questions:: Things we'd like to know.
+* Bugs:: How, why, and where to report bugs.
+* Service:: How to find suppliers of support for GNU Fortran.
+@end ifset
+@ifset INTERNALS
+* Adding Options:: Guidance on teaching @code{g77} about new options.
+* Projects:: Projects for @code{g77} internals hackers.
+@end ifset
+
+* M: Diagnostics. Diagnostics produced by @code{g77}.
+
+* Index:: Index of concepts and symbol names.
+@end menu
+@c yes, the "M: " @emph{is} intentional -- bad.def references it (CMPAMBIG)!
+
+@node Copying
+@unnumbered GNU GENERAL PUBLIC LICENSE
+@center Version 2, June 1991
+
+@display
+Copyright @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.
+@end display
+
+@unnumberedsec 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.
+
+@iftex
+@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifinfo
+
+@enumerate 0
+@item
+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.
+
+@item
+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.
+
+@item
+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:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+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.
+
+@item
+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.)
+@end enumerate
+
+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.
+
+@item
+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:
+
+@enumerate a
+@item
+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,
+
+@item
+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,
+
+@item
+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.)
+@end enumerate
+
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@iftex
+@heading NO WARRANTY
+@end iftex
+@ifinfo
+@center NO WARRANTY
+@end ifinfo
+
+@item
+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.
+
+@item
+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.
+@end enumerate
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+
+@page
+@unnumberedsec 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.
+
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) 19@var{yy} @var{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.
+@end smallexample
+
+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:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{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.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{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:
+
+@smallexample
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end smallexample
+
+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
+@unnumbered Contributors to GNU Fortran
+@cindex contributors
+@cindex credits
+
+In addition to James Craig Burley, who wrote the front end,
+many people have helped create and improve GNU Fortran.
+
+@itemize @bullet
+@item
+The packaging and compiler portions of GNU Fortran are based largely
+on the GNU CC compiler.
+@xref{Contributors,,Contributors to GNU CC,gcc,Using and Porting GNU CC},
+for more information.
+
+@item
+The run-time library used by GNU Fortran is a repackaged version
+of the @code{libf2c} library (combined from the @code{libF77} and
+@code{libI77} libraries) provided as part of @code{f2c}, available for
+free from @code{netlib} sites on the Internet.
+
+@item
+Cygnus Support and The Free Software Foundation contributed
+significant money and/or equipment to Craig's efforts.
+
+@item
+The following individuals served as alpha testers prior to @code{g77}'s
+public release. This work consisted of testing, researching, sometimes
+debugging, and occasionally providing small amounts of code and fixes
+for @code{g77}, plus offering plenty of helpful advice to Craig:
+
+@itemize @w{}
+@item
+Jonathan Corbet
+@item
+Dr.@: Mark Fernyhough
+@item
+Takafumi Hayashi (The University of Aizu)---@email{takafumi@@u-aizu.ac.jp}
+@item
+Kate Hedstrom
+@item
+Michel Kern (INRIA and Rice University)---@email{Michel.Kern@@inria.fr}
+@item
+Dr.@: A. O. V. Le Blanc
+@item
+Dave Love
+@item
+Rick Lutowski
+@item
+Toon Moene
+@item
+Rick Niles
+@item
+Derk Reefman
+@item
+Wayne K. Schroll
+@item
+Bill Thorson
+@item
+Pedro A. M. Vazquez
+@item
+Ian Watson
+@end itemize
+
+@item
+Scott Snyder (@email{snyder@@d0sgif.fnal.gov})
+provided the patch to add rudimentary support
+for @code{INTEGER*1}, @code{INTEGER*2}, and
+@code{LOGICAL*1}.
+This inspired Craig to add further support,
+even though the resulting support
+would still be incomplete, because version 0.6 is still
+a ways off.
+
+@item
+David Ronis (@email{ronis@@onsager.chem.mcgill.ca}) inspired
+and encouraged Craig to rewrite the documentation in texinfo
+format by contributing a first pass at a translation of the
+old @file{g77-0.5.16/f/DOC} file.
+
+@item
+Toon Moene (@email{toon@@moene.indiv.nluug.nl}) performed
+some analysis of generated code as part of an overall project
+to improve @code{g77} code generation to at least be as good
+as @code{f2c} used in conjunction with @code{gcc}.
+So far, this has resulted in the three, somewhat
+experimental, options added by @code{g77} to the @code{gcc}
+compiler and its back end.
+
+(These, in turn, have made their way into the @code{egcs}
+version of the compiler, and do not exist in @code{gcc}
+version 2.8 or versions of @code{g77} based on that version
+of @code{gcc}.)
+
+@item
+John Carr (@email{jfc@@mit.edu}) wrote the alias analysis improvements.
+
+@item
+Thanks to Mary Cortani and the staff at Craftwork Solutions
+(@email{support@@craftwork.com}) for all of their support.
+
+@item
+Many other individuals have helped debug, test, and improve @code{g77}
+over the past several years, and undoubtedly more people
+will be doing so in the future.
+If you have done so, and would like
+to see your name listed in the above list, please ask!
+The default is that people wish to remain anonymous.
+@end itemize
+
+@node Funding
+@chapter Funding Free Software
+
+If you want to have more free software a few years from now, it makes
+sense for you to help encourage people to contribute funds for its
+development. The most effective approach known is to encourage
+commercial redistributors to donate.
+
+Users of free software systems can boost the pace of development by
+encouraging for-a-fee distributors to donate part of their selling price
+to free software developers---the Free Software Foundation, and others.
+
+The way to convince distributors to do this is to demand it and expect
+it from them. So when you compare distributors, judge them partly by
+how much they give to free software development. Show distributors
+they must compete to be the one who gives the most.
+
+To make this approach work, you must insist on numbers that you can
+compare, such as, ``We will donate ten dollars to the Frobnitz project
+for each disk sold.'' Don't be satisfied with a vague promise, such as
+``A portion of the profits are donated,'' since it doesn't give a basis
+for comparison.
+
+Even a precise fraction ``of the profits from this disk'' is not very
+meaningful, since creative accounting and unrelated business decisions
+can greatly alter what fraction of the sales price counts as profit.
+If the price you pay is $50, ten percent of the profit is probably
+less than a dollar; it might be a few cents, or nothing at all.
+
+Some redistributors do development work themselves. This is useful too;
+but to keep everyone honest, you need to inquire how much they do, and
+what kind. Some kinds of development make much more long-term
+difference than others. For example, maintaining a separate version of
+a program contributes very little; maintaining the standard version of a
+program for the whole community contributes much. Easy new ports
+contribute little, since someone else would surely do them; difficult
+ports such as adding a new CPU to the GNU C compiler contribute more;
+major new features or packages contribute the most.
+
+By establishing the idea that supporting further development is ``the
+proper thing to do'' when distributing free software for a fee, we can
+assure a steady flow of resources into making more free software.
+
+@display
+Copyright (C) 1994 Free Software Foundation, Inc.
+Verbatim copying and redistribution of this section is permitted
+without royalty; alteration is not permitted.
+@end display
+
+@node Funding GNU Fortran
+@chapter Funding GNU Fortran
+@cindex funding improvements
+@cindex improvements, funding
+
+Work on GNU Fortran is still being done mostly by its author,
+James Craig Burley (@email{@value{email-burley}}), who is a volunteer
+for, not an employee of, the Free Software Foundation (FSF).
+As with other GNU software, funding is important because it can pay for
+needed equipment, personnel, and so on.
+
+@cindex FSF, funding the
+@cindex funding the FSF
+The FSF provides information on the best way to fund ongoing
+development of GNU software (such as GNU Fortran) in documents
+such as the ``GNUS Bulletin''.
+Email @email{gnu@@gnu.org} for information on funding the FSF.
+
+To fund specific GNU Fortran work in particular, the FSF might
+provide a means for that, but the FSF does not provide direct funding
+to the author of GNU Fortran to continue his work. The FSF has
+employee salary restrictions that can be incompatible with the
+financial needs of some volunteers, who therefore choose to
+remain volunteers and thus be able to be free to do contract work
+and otherwise make their own schedules for doing GNU work.
+
+Still, funding the FSF at least indirectly benefits work
+on specific projects like GNU Fortran because it ensures the
+continuing operation of the FSF offices, their workstations, their
+network connections, and so on, which are invaluable to volunteers.
+(Similarly, hiring Cygnus Support can help a project like GNU
+Fortran---Cygnus has been a long-time donor of equipment usage to the author
+of GNU Fortran, and this too has been invaluable---@xref{Contributors}.)
+
+Currently, the only way to directly fund the author of GNU Fortran
+in his work on that project is to hire him for the work you want
+him to do, or donate money to him.
+Several people have done this
+already, with the result that he has not needed to immediately find
+contract work on a few occasions.
+If more people did this, he
+would be able to plan on not doing contract work for many months and
+could thus devote that time to work on projects (such as the planned
+changes for 0.6) that require longer timeframes to complete.
+For the latest information on the status of the author, do
+@kbd{finger -l burley@@gnu.org} on a UNIX system
+(or any system with a command like UNIX @code{finger}).
+
+Another important way to support work on GNU Fortran is to volunteer
+to help out.
+Work is needed on documentation, testing, porting
+to various machines, and in some cases, coding (although major
+changes planned for version 0.6 make it difficult to add manpower to this
+area).
+Email @email{@value{email-general}} to volunteer for this work.
+
+@xref{Funding,,Funding Free Software}, for more information.
+
+@node Look and Feel
+@chapter Protect Your Freedom---Fight ``Look And Feel''
+@c the above chapter heading overflows onto the next line. --mew 1/26/93
+
+To preserve the ability to write free software, including replacements
+for proprietary software, authors must be free to replicate the
+user interface to which users of existing software have become
+accustomed.
+
+@xref{Look and Feel,,Protect Your Freedom---Fight ``Look And Feel'',
+gcc,Using and Porting GNU CC}, for more information.
+
+@node Getting Started
+@chapter Getting Started
+@cindex getting started
+@cindex new users
+@cindex newbies
+@cindex beginners
+
+If you don't need help getting started reading the portions
+of this manual that are most important to you, you should skip
+this portion of the manual.
+
+If you are new to compilers, especially Fortran compilers, or
+new to how compilers are structured under UNIX and UNIX-like
+systems, you'll want to see @ref{What is GNU Fortran?}.
+
+If you are new to GNU compilers, or have used only one GNU
+compiler in the past and not had to delve into how it lets
+you manage various versions and configurations of @code{gcc},
+you should see @ref{G77 and GCC}.
+
+Everyone except experienced @code{g77} users should
+see @ref{Invoking G77}.
+
+If you're acquainted with previous versions of @code{g77},
+you should see @ref{News}.
+Further, if you've actually used previous versions of @code{g77},
+especially if you've written or modified Fortran code to
+be compiled by previous versions of @code{g77}, you
+should see @ref{Changes}.
+
+If you intend to write or otherwise compile code that is
+not already strictly conforming ANSI FORTRAN 77---and this
+is probably everyone---you should see @ref{Language}.
+
+If you don't already have @code{g77} installed on your
+system, you must see @ref{Installation}.
+
+If you run into trouble getting Fortran code to compile,
+link, run, or work properly, you might find answers
+if you see @ref{Debugging and Interfacing},
+see @ref{Collected Fortran Wisdom},
+and see @ref{Trouble}.
+You might also find that the problems you are encountering
+are bugs in @code{g77}---see @ref{Bugs}, for information on
+reporting them, after reading the other material.
+
+If you need further help with @code{g77}, or with
+freely redistributable software in general,
+see @ref{Service}.
+
+If you would like to help the @code{g77} project,
+see @ref{Funding GNU Fortran}, for information on
+helping financially, and see @ref{Projects}, for information
+on helping in other ways.
+
+If you're generally curious about the future of
+@code{g77}, see @ref{Projects}.
+If you're curious about its past,
+see @ref{Contributors},
+and see @ref{Funding GNU Fortran}.
+
+To see a few of the questions maintainers of @code{g77} have,
+and that you might be able to answer,
+see @ref{Open Questions}.
+
+@ifset USING
+@node What is GNU Fortran?
+@chapter What is GNU Fortran?
+@cindex concepts, basic
+@cindex basic concepts
+
+GNU Fortran, or @code{g77}, is designed initially as a free replacement
+for, or alternative to, the UNIX @code{f77} command.
+(Similarly, @code{gcc} is designed as a replacement
+for the UNIX @code{cc} command.)
+
+@code{g77} also is designed to fit in well with the other
+fine GNU compilers and tools.
+
+Sometimes these design goals conflict---in such cases, resolution
+often is made in favor of fitting in well with Project GNU.
+These cases are usually identified in the appropriate
+sections of this manual.
+
+@cindex compilers
+As compilers, @code{g77}, @code{gcc}, and @code{f77}
+share the following characteristics:
+
+@itemize @bullet
+@cindex source code
+@cindex file, source
+@cindex code, source
+@cindex source file
+@item
+They read a user's program, stored in a file and
+containing instructions written in the appropriate
+language (Fortran, C, and so on).
+This file contains @dfn{source code}.
+
+@cindex translation of user programs
+@cindex machine code
+@cindex code, machine
+@cindex mistakes
+@item
+They translate the user's program into instructions
+a computer can carry out more quickly than it takes
+to translate the instructions in the first place.
+These instructions are called @dfn{machine code}---code
+designed to be efficiently translated and processed
+by a machine such as a computer.
+Humans usually aren't as good writing machine code
+as they are at writing Fortran or C, because
+it is easy to make tiny mistakes writing machine code.
+When writing Fortran or C, it is easy
+to make big mistakes.
+
+@cindex debugger
+@cindex bugs, finding
+@cindex gdb command
+@cindex commands, gdb
+@item
+They provide information in the generated machine code
+that can make it easier to find bugs in the program
+(using a debugging tool, called a @dfn{debugger},
+such as @code{gdb}).
+
+@cindex libraries
+@cindex linking
+@cindex ld command
+@cindex commands, ld
+@item
+They locate and gather machine code already generated
+to perform actions requested by statements in
+the user's program.
+This machine code is organized
+into @dfn{libraries} and is located and gathered
+during the @dfn{link} phase of the compilation
+process.
+(Linking often is thought of as a separate
+step, because it can be directly invoked via the
+@code{ld} command.
+However, the @code{g77} and @code{gcc}
+commands, as with most compiler commands, automatically
+perform the linking step by calling on @code{ld}
+directly, unless asked to not do so by the user.)
+
+@cindex language, incorrect use of
+@cindex incorrect use of language
+@item
+They attempt to diagnose cases where the user's
+program contains incorrect usages of the language.
+The @dfn{diagnostics} produced by the compiler
+indicate the problem and the location in the user's
+source file where the problem was first noticed.
+The user can use this information to locate and
+fix the problem.
+@cindex diagnostics, incorrect
+@cindex incorrect diagnostics
+@cindex error messages, incorrect
+@cindex incorrect error messages
+(Sometimes an incorrect usage
+of the language leads to a situation where the
+compiler can no longer make any sense of what
+follows---while a human might be able to---and
+thus ends up complaining about many ``problems''
+it encounters that, in fact, stem from just one
+problem, usually the first one reported.)
+
+@cindex warnings
+@cindex questionable instructions
+@item
+They attempt to diagnose cases where the user's
+program contains a correct usage of the language,
+but instructs the computer to do something questionable.
+These diagnostics often are in the form of @dfn{warnings},
+instead of the @dfn{errors} that indicate incorrect
+usage of the language.
+@end itemize
+
+How these actions are performed is generally under the
+control of the user.
+Using command-line options, the user can specify
+how persnickety the compiler is to be regarding
+the program (whether to diagnose questionable usage
+of the language), how much time to spend making
+the generated machine code run faster, and so on.
+
+@cindex components of g77
+@cindex g77, components of
+@code{g77} consists of several components:
+
+@cindex gcc command
+@cindex commands, gcc
+@itemize @bullet
+@item
+A modified version of the @code{gcc} command, which also might be
+installed as the system's @code{cc} command.
+(In many cases, @code{cc} refers to the
+system's ``native'' C compiler, which
+might be a non-GNU compiler, or an older version
+of @code{gcc} considered more stable or that is
+used to build the operating system kernel.)
+
+@cindex g77 command
+@cindex commands, g77
+@item
+The @code{g77} command itself, which also might be installed as the
+system's @code{f77} command.
+
+@cindex libg2c library
+@cindex libf2c library
+@cindex libraries, libf2c
+@cindex libraries, libg2c
+@cindex run-time library
+@item
+The @code{libg2c} run-time library.
+This library contains the machine code needed to support
+capabilities of the Fortran language that are not directly
+provided by the machine code generated by the @code{g77}
+compilation phase.
+
+@code{libg2c} is just the unique name @code{g77} gives
+to its version of @code{libf2c} to distinguish it from
+any copy of @code{libf2c} installed from @code{f2c}
+(or versions of @code{g77} that built @code{libf2c} under
+that same name)
+on the system.
+
+The maintainer of @code{libf2c} currently is
+@email{dmg@@bell-labs.com}.
+
+@cindex f771 program
+@cindex programs, f771
+@cindex assembler
+@cindex as command
+@cindex commands, as
+@cindex assembly code
+@cindex code, assembly
+@item
+The compiler itself, internally named @code{f771}.
+
+Note that @code{f771} does not generate machine code directly---it
+generates @dfn{assembly code} that is a more readable form
+of machine code, leaving the conversion to actual machine code
+to an @dfn{assembler}, usually named @code{as}.
+@end itemize
+
+@code{gcc} is often thought of as ``the C compiler'' only,
+but it does more than that.
+Based on command-line options and the names given for files
+on the command line, @code{gcc} determines which actions to perform, including
+preprocessing, compiling (in a variety of possible languages), assembling,
+and linking.
+
+@cindex driver, gcc command as
+@cindex gcc command as driver
+@cindex executable file
+@cindex files, executable
+@cindex cc1 program
+@cindex programs, cc1
+@cindex preprocessor
+@cindex cpp program
+@cindex programs, cpp
+For example, the command @samp{gcc foo.c} @dfn{drives} the file
+@file{foo.c} through the preprocessor @code{cpp}, then
+the C compiler (internally named
+@code{cc1}), then the assembler (usually @code{as}), then the linker
+(@code{ld}), producing an executable program named @file{a.out} (on
+UNIX systems).
+
+@cindex cc1plus program
+@cindex programs, cc1plus
+As another example, the command @samp{gcc foo.cc} would do much the same as
+@samp{gcc foo.c}, but instead of using the C compiler named @code{cc1},
+@code{gcc} would use the C++ compiler (named @code{cc1plus}).
+
+@cindex f771 program
+@cindex programs, f771
+In a GNU Fortran installation, @code{gcc} recognizes Fortran source
+files by name just like it does C and C++ source files.
+It knows to use the Fortran compiler named @code{f771}, instead of
+@code{cc1} or @code{cc1plus}, to compile Fortran files.
+
+@cindex gcc not recognizing Fortran source
+@cindex unrecognized file format
+@cindex file format not recognized
+Non-Fortran-related operation of @code{gcc} is generally
+unaffected by installing the GNU Fortran version of @code{gcc}.
+However, without the installed version of @code{gcc} being the
+GNU Fortran version, @code{gcc} will not be able to compile
+and link Fortran programs---and since @code{g77} uses @code{gcc}
+to do most of the actual work, neither will @code{g77}!
+
+@cindex g77 command
+@cindex commands, g77
+The @code{g77} command is essentially just a front-end for
+the @code{gcc} command.
+Fortran users will normally use @code{g77} instead of @code{gcc},
+because @code{g77}
+knows how to specify the libraries needed to link with Fortran programs
+(@code{libg2c} and @code{lm}).
+@code{g77} can still compile and link programs and
+source files written in other languages, just like @code{gcc}.
+
+@cindex printing version information
+@cindex version information, printing
+The command @samp{g77 -v} is a quick
+way to display lots of version information for the various programs
+used to compile a typical preprocessed Fortran source file---this
+produces much more output than @samp{gcc -v} currently does.
+(If it produces an error message near the end of the output---diagnostics
+from the linker, usually @code{ld}---you might
+have an out-of-date @code{libf2c} that improperly handles
+complex arithmetic.)
+In the output of this command, the line beginning @samp{GNU Fortran Front
+End} identifies the version number of GNU Fortran; immediately
+preceding that line is a line identifying the version of @code{gcc}
+with which that version of @code{g77} was built.
+
+@cindex libf2c library
+@cindex libraries, libf2c
+The @code{libf2c} library is distributed with GNU Fortran for
+the convenience of its users, but is not part of GNU Fortran.
+It contains the procedures
+needed by Fortran programs while they are running.
+
+@cindex in-line code
+@cindex code, in-line
+For example, while code generated by @code{g77} is likely
+to do additions, subtractions, and multiplications @dfn{in line}---in
+the actual compiled code---it is not likely to do trigonometric
+functions this way.
+
+Instead, operations like trigonometric
+functions are compiled by the @code{f771} compiler
+(invoked by @code{g77} when compiling Fortran code) into machine
+code that, when run, calls on functions in @code{libg2c}, so
+@code{libg2c} must be linked with almost every useful program
+having any component compiled by GNU Fortran.
+(As mentioned above, the @code{g77} command takes
+care of all this for you.)
+
+The @code{f771} program represents most of what is unique to GNU Fortran.
+While much of the @code{libg2c} component comes from
+the @code{libf2c} component of @code{f2c},
+a free Fortran-to-C converter distributed by Bellcore (AT&T),
+plus @code{libU77}, provided by Dave Love,
+and the @code{g77} command is just a small front-end to @code{gcc},
+@code{f771} is a combination of two rather
+large chunks of code.
+
+@cindex GNU Back End (GBE)
+@cindex GBE
+@cindex gcc back end
+@cindex back end, gcc
+@cindex code generator
+One chunk is the so-called @dfn{GNU Back End}, or GBE,
+which knows how to generate fast code for a wide variety of processors.
+The same GBE is used by the C, C++, and Fortran compiler programs @code{cc1},
+@code{cc1plus}, and @code{f771}, plus others.
+Often the GBE is referred to as the ``gcc back end'' or
+even just ``gcc''---in this manual, the term GBE is used
+whenever the distinction is important.
+
+@cindex GNU Fortran Front End (FFE)
+@cindex FFE
+@cindex g77 front end
+@cindex front end, g77
+The other chunk of @code{f771} is the
+majority of what is unique about GNU Fortran---the code that knows how
+to interpret Fortran programs to determine what they are intending to
+do, and then communicate that knowledge to the GBE for actual compilation
+of those programs.
+This chunk is called the @dfn{Fortran Front End} (FFE).
+The @code{cc1} and @code{cc1plus} programs have their own front ends,
+for the C and C++ languages, respectively.
+These fronts ends are responsible for diagnosing
+incorrect usage of their respective languages by the
+programs the process, and are responsible for most of
+the warnings about questionable constructs as well.
+(The GBE handles producing some warnings, like those
+concerning possible references to undefined variables.)
+
+Because so much is shared among the compilers for various languages,
+much of the behavior and many of the user-selectable options for these
+compilers are similar.
+For example, diagnostics (error messages and
+warnings) are similar in appearance; command-line
+options like @samp{-Wall} have generally similar effects; and the quality
+of generated code (in terms of speed and size) is roughly similar
+(since that work is done by the shared GBE).
+
+@node G77 and GCC
+@chapter Compile Fortran, C, or Other Programs
+@cindex compiling programs
+@cindex programs, compiling
+
+@cindex gcc command
+@cindex commands, gcc
+A GNU Fortran installation includes a modified version of the @code{gcc}
+command.
+
+In a non-Fortran installation, @code{gcc} recognizes C, C++,
+and Objective-C source files.
+
+In a GNU Fortran installation, @code{gcc} also recognizes Fortran source
+files and accepts Fortran-specific command-line options, plus some
+command-line options that are designed to cater to Fortran users
+but apply to other languages as well.
+
+@xref{G++ and GCC,,Compile C; C++; or Objective-C,gcc,Using and Porting GNU CC},
+for information on the way different languages are handled
+by the GNU CC compiler (@code{gcc}).
+
+@cindex g77 command
+@cindex commands, g77
+Also provided as part of GNU Fortran is the @code{g77} command.
+The @code{g77} command is designed to make compiling and linking Fortran
+programs somewhat easier than when using the @code{gcc} command for
+these tasks.
+It does this by analyzing the command line somewhat and changing it
+appropriately before submitting it to the @code{gcc} command.
+
+@cindex -v option
+@cindex g77 options, -v
+@cindex options, -v
+Use the @samp{-v} option with @code{g77}
+to see what is going on---the first line of output is the invocation
+of the @code{gcc} command.
+
+@node Invoking G77
+@chapter GNU Fortran Command Options
+@cindex GNU Fortran command options
+@cindex command options
+@cindex options, GNU Fortran command
+
+The @code{g77} command supports all the options supported by the
+@code{gcc} command.
+@xref{Invoking GCC,,GNU CC Command Options,gcc,Using and Porting GNU CC},
+for information
+on the non-Fortran-specific aspects of the @code{gcc} command (and,
+therefore, the @code{g77} command).
+
+@cindex options, negative forms
+@cindex negative forms of options
+All @code{gcc} and @code{g77} options
+are accepted both by @code{g77} and by @code{gcc}
+(as well as any other drivers built at the same time,
+such as @code{g++}),
+since adding @code{g77} to the @code{gcc} distribution
+enables acceptance of @code{g77}-specific options
+by all of the relevant drivers.
+
+In some cases, options have positive and negative forms;
+the negative form of @samp{-ffoo} would be @samp{-fno-foo}.
+This manual documents only one of these two forms, whichever
+one is not the default.
+
+@menu
+* Option Summary:: Brief list of all @code{g77} options,
+ without explanations.
+* Overall Options:: Controlling the kind of output:
+ an executable, object files, assembler files,
+ or preprocessed source.
+* Shorthand Options:: Options that are shorthand for other options.
+* Fortran Dialect Options:: Controlling the variant of Fortran language
+ compiled.
+* Warning Options:: How picky should the compiler be?
+* Debugging Options:: Symbol tables, measurements, and debugging dumps.
+* Optimize Options:: How much optimization?
+* Preprocessor Options:: Controlling header files and macro definitions.
+ Also, getting dependency information for Make.
+* Directory Options:: Where to find header files and libraries.
+ Where to find the compiler executable files.
+* Code Gen Options:: Specifying conventions for function calls, data layout
+ and register usage.
+* Environment Variables:: Env vars that affect GNU Fortran.
+@end menu
+
+@node Option Summary
+@section Option Summary
+
+Here is a summary of all the options specific to GNU Fortran, grouped
+by type. Explanations are in the following sections.
+
+@table @emph
+@item Overall Options
+@xref{Overall Options,,Options Controlling the Kind of Output}.
+@smallexample
+-fversion -fset-g77-defaults -fno-silent
+@end smallexample
+
+@item Shorthand Options
+@xref{Shorthand Options}.
+@smallexample
+-ff66 -fno-f66 -ff77 -fno-f77 -fugly -fno-ugly
+@end smallexample
+
+@item Fortran Language Options
+@xref{Fortran Dialect Options,,Options Controlling Fortran Dialect}.
+@smallexample
+-ffree-form -fno-fixed-form -ff90
+-fvxt -fdollar-ok -fno-backslash
+-fno-ugly-args -fno-ugly-assign -fno-ugly-assumed
+-fugly-comma -fugly-complex -fugly-init -fugly-logint
+-fonetrip -ftypeless-boz
+-fintrin-case-initcap -fintrin-case-upper
+-fintrin-case-lower -fintrin-case-any
+-fmatch-case-initcap -fmatch-case-upper
+-fmatch-case-lower -fmatch-case-any
+-fsource-case-upper -fsource-case-lower -fsource-case-preserve
+-fsymbol-case-initcap -fsymbol-case-upper
+-fsymbol-case-lower -fsymbol-case-any
+-fcase-strict-upper -fcase-strict-lower
+-fcase-initcap -fcase-upper -fcase-lower -fcase-preserve
+-ff2c-intrinsics-delete -ff2c-intrinsics-hide
+-ff2c-intrinsics-disable -ff2c-intrinsics-enable
+-fbadu77-intrinsics-delete -fbadu77-intrinsics-hide
+-fbadu77-intrinsics-disable -fbadu77-intrinsics-enable
+-ff90-intrinsics-delete -ff90-intrinsics-hide
+-ff90-intrinsics-disable -ff90-intrinsics-enable
+-fgnu-intrinsics-delete -fgnu-intrinsics-hide
+-fgnu-intrinsics-disable -fgnu-intrinsics-enable
+-fmil-intrinsics-delete -fmil-intrinsics-hide
+-fmil-intrinsics-disable -fmil-intrinsics-enable
+-funix-intrinsics-delete -funix-intrinsics-hide
+-funix-intrinsics-disable -funix-intrinsics-enable
+-fvxt-intrinsics-delete -fvxt-intrinsics-hide
+-fvxt-intrinsics-disable -fvxt-intrinsics-enable
+-ffixed-line-length-@var{n} -ffixed-line-length-none
+@end smallexample
+
+@item Warning Options
+@xref{Warning Options,,Options to Request or Suppress Warnings}.
+@smallexample
+-fsyntax-only -pedantic -pedantic-errors -fpedantic
+-w -Wno-globals -Wimplicit -Wunused -Wuninitialized
+-Wall -Wsurprising
+-Werror -W
+@end smallexample
+
+@item Debugging Options
+@xref{Debugging Options,,Options for Debugging Your Program or GCC}.
+@smallexample
+-g
+@end smallexample
+
+@item Optimization Options
+@xref{Optimize Options,,Options that Control Optimization}.
+@smallexample
+-malign-double
+-ffloat-store -fforce-mem -fforce-addr -fno-inline
+-ffast-math -fstrength-reduce -frerun-cse-after-loop
+-fexpensive-optimizations -fdelayed-branch
+-fschedule-insns -fschedule-insn2 -fcaller-saves
+-funroll-loops -funroll-all-loops
+-fno-move-all-movables -fno-reduce-all-givs
+-fno-rerun-loop-opt
+@end smallexample
+
+@item Directory Options
+@xref{Directory Options,,Options for Directory Search}.
+@smallexample
+-I@var{dir} -I-
+@end smallexample
+
+@item Code Generation Options
+@xref{Code Gen Options,,Options for Code Generation Conventions}.
+@smallexample
+-fno-automatic -finit-local-zero -fno-f2c
+-ff2c-library -fno-underscoring -fno-ident
+-fpcc-struct-return -freg-struct-return
+-fshort-double -fno-common -fpack-struct
+-fzeros -fno-second-underscore
+-fdebug-kludge -fno-emulate-complex
+-falias-check -fargument-alias
+-fargument-noalias -fno-argument-noalias-global
+-fno-globals
+@end smallexample
+@end table
+
+@menu
+* Overall Options:: Controlling the kind of output:
+ an executable, object files, assembler files,
+ or preprocessed source.
+* Shorthand Options:: Options that are shorthand for other options.
+* Fortran Dialect Options:: Controlling the variant of Fortran language
+ compiled.
+* Warning Options:: How picky should the compiler be?
+* Debugging Options:: Symbol tables, measurements, and debugging dumps.
+* Optimize Options:: How much optimization?
+* Preprocessor Options:: Controlling header files and macro definitions.
+ Also, getting dependency information for Make.
+* Directory Options:: Where to find header files and libraries.
+ Where to find the compiler executable files.
+* Code Gen Options:: Specifying conventions for function calls, data layout
+ and register usage.
+@end menu
+
+@node Overall Options
+@section Options Controlling the Kind of Output
+@cindex overall options
+@cindex options, overall
+
+Compilation can involve as many as four stages: preprocessing, code
+generation (often what is really meant by the term ``compilation''),
+assembly, and linking, always in that order. The first three
+stages apply to an individual source file, and end by producing an
+object file; linking combines all the object files (those newly
+compiled, and those specified as input) into an executable file.
+
+@cindex file name suffix
+@cindex suffixes, file name
+@cindex file name extension
+@cindex extensions, file name
+@cindex file type
+@cindex types, file
+For any given input file, the file name suffix determines what kind of
+program is contained in the file---that is, the language in which the
+program is written is generally indicated by the suffix.
+Suffixes specific to GNU Fortran are listed below.
+@xref{Overall Options,,gcc,Using and Porting GNU CC}, for
+information on suffixes recognized by GNU CC.
+
+@table @code
+@item @var{file}.f
+@item @var{file}.for
+Fortran source code that should not be preprocessed.
+
+Such source code cannot contain any preprocessor directives, such
+as @code{#include}, @code{#define}, @code{#if}, and so on.
+
+You can force @samp{.f} files to be preprocessed by @samp{cpp} by using
+@samp{-x f77-cpp-input}, @ref{LEX}.
+
+@cindex preprocessor
+@cindex C preprocessor
+@cindex cpp preprocessor
+@cindex Fortran preprocessor
+@cindex cpp program
+@cindex programs, cpp
+@cindex .F filename suffix
+@cindex .fpp filename suffix
+@item @var{file}.F
+@item @var{file}.fpp
+Fortran source code that must be preprocessed (by the C preprocessor
+@code{cpp}, which is part of GNU CC).
+
+Note that preprocessing is not extended to the contents of
+files included by the @code{INCLUDE} directive---the @code{#include}
+preprocessor directive must be used instead.
+
+@cindex Ratfor preprocessor
+@cindex programs, ratfor
+@cindex .r filename suffix
+@pindex ratfor
+@item @var{file}.r
+Ratfor source code, which must be preprocessed by the @code{ratfor}
+command, which is available separately (as it is not yet part of the GNU
+Fortran distribution).
+One version in Fortran, adapted for use with @code{g77}, is at
+@uref{ftp://members.aol.com/n8tm/rat7.uue} (of uncertain copyright
+status). Another, public domain version in C is at
+@uref{http://sepwww.stanford.edu/sep/prof/ratfor.shar.2}.
+@end table
+
+UNIX users typically use the @file{@var{file}.f} and @file{@var{file}.F}
+nomenclature.
+Users of other operating systems, especially those that cannot
+distinguish upper-case
+letters from lower-case letters in their file names, typically use
+the @file{@var{file}.for} and @file{@var{file}.fpp} nomenclature.
+
+@cindex #define
+@cindex #include
+@cindex #if
+Use of the preprocessor @code{cpp} allows use of C-like
+constructs such as @code{#define} and @code{#include}, but can
+lead to unexpected, even mistaken, results due to Fortran's source file
+format.
+It is recommended that use of the C preprocessor
+be limited to @code{#include} and, in
+conjunction with @code{#define}, only @code{#if} and related directives,
+thus avoiding in-line macro expansion entirely.
+This recommendation applies especially
+when using the traditional fixed source form.
+With free source form,
+fewer unexpected transformations are likely to happen, but use of
+constructs such as Hollerith and character constants can nevertheless
+present problems, especially when these are continued across multiple
+source lines.
+These problems result, primarily, from differences between the way
+such constants are interpreted by the C preprocessor and by a Fortran
+compiler.
+
+Another example of a problem that results from using the C preprocessor
+is that a Fortran comment line that happens to contain any
+characters ``interesting'' to the C preprocessor,
+such as a backslash at the end of the line,
+is not recognized by the preprocessor as a comment line,
+so instead of being passed through ``raw'',
+the line is edited according to the rules for the preprocessor.
+For example, the backslash at the end of the line is removed,
+along with the subsequent newline, resulting in the next
+line being effectively commented out---unfortunate if that
+line is a non-comment line of important code!
+
+@emph{Note:} The @samp{-traditional} and @samp{-undef} flags are supplied
+to @code{cpp} by default, to help avoid unpleasant surprises.
+@xref{Preprocessor Options,,Options Controlling the Preprocessor,
+gcc,Using and Porting GNU CC}.
+This means that ANSI C preprocessor features (such as the @samp{#}
+operator) aren't available, and only variables in the C reserved
+namespace (generally, names with a leading underscore) are liable to
+substitution by C predefines.
+Thus, if you want to do system-specific
+tests, use, for example, @samp{#ifdef __linux__} rather than @samp{#ifdef linux}.
+Use the @samp{-v} option to see exactly how the preprocessor is invoked.
+
+@cindex /*
+Unfortunately, the @samp{-traditional} flag will not avoid an error from
+anything that @code{cpp} sees as an unterminated C comment, such as:
+@smallexample
+C Some Fortran compilers accept /* as starting
+C an inline comment.
+@end smallexample
+@xref{Trailing Comment}.
+
+The following options that affect overall processing are recognized
+by the @code{g77} and @code{gcc} commands in a GNU Fortran installation:
+
+@table @code
+@cindex -fversion option
+@cindex options, -fversion
+@cindex printing version information
+@cindex version information, printing
+@item -fversion
+Ensure that the @code{g77}-specific version of the compiler phase is reported,
+if run.
+(This is supplied automatically when @samp{-v} or @samp{--verbose}
+is specified as a command-line option for @code{g77} or @code{gcc}
+and when the resulting commands compile Fortran source files.)
+
+@cindex -fset-g77-defaults option
+@cindex options, -fset-g77-defaults
+@item -fset-g77-defaults
+@emph{Version info:}
+This option is obsolete in @code{egcs}
+as of version 1.1.
+
+Set up whatever @code{gcc} options are to apply to Fortran
+compilations, and avoid running internal consistency checks
+that might take some time.
+
+This option is supplied automatically when compiling Fortran code
+via the @code{g77} or @code{gcc} command.
+The description of this option is provided so that users seeing
+it in the output of, say, @samp{g77 -v} understand why it is
+there.
+
+@cindex modifying g77
+@cindex code, modifying
+Also, developers who run @code{f771} directly might want to specify it
+by hand to get the same defaults as they would running @code{f771}
+via @code{g77} or @code{gcc}.
+However, such developers should, after linking a new @code{f771}
+executable, invoke it without this option once,
+e.g. via @kbd{./f771 -quiet < /dev/null},
+to ensure that they have not introduced any
+internal inconsistencies (such as in the table of
+intrinsics) before proceeding---@code{g77} will crash
+with a diagnostic if it detects an inconsistency.
+
+@cindex -fno-silent option
+@cindex options, -fno-silent
+@cindex @code{f2c} compatibility
+@cindex compatibility, @code{f2c}
+@cindex status, compilation
+@cindex compilation status
+@cindex reporting compilation status
+@cindex printing compilation status
+@item -fno-silent
+Print (to @code{stderr}) the names of the program units as
+they are compiled, in a form similar to that used by popular
+UNIX @code{f77} implementations and @code{f2c}.
+@end table
+
+@xref{Overall Options,,Options Controlling the Kind of Output,
+gcc,Using and Porting GNU CC}, for information
+on more options that control the overall operation of the @code{gcc} command
+(and, by extension, the @code{g77} command).
+
+@node Shorthand Options
+@section Shorthand Options
+@cindex shorthand options
+@cindex options, shorthand
+@cindex macro options
+@cindex options, macro
+
+The following options serve as ``shorthand''
+for other options accepted by the compiler:
+
+@table @code
+@cindex -fugly option
+@cindex options, -fugly
+@item -fugly
+@cindex ugly features
+@cindex features, ugly
+Specify that certain ``ugly'' constructs are to be quietly accepted.
+Same as:
+
+@smallexample
+-fugly-args -fugly-assign -fugly-assumed
+-fugly-comma -fugly-complex -fugly-init
+-fugly-logint
+@end smallexample
+
+These constructs are considered inappropriate to use in new
+or well-maintained portable Fortran code, but widely used
+in old code.
+@xref{Distensions}, for more information.
+
+@emph{Note:} The @samp{-fugly} option is likely to
+be removed in a future version.
+Implicitly enabling all the @samp{-fugly-*} options
+is unlikely to be feasible, or sensible, in the future,
+so users should learn to specify only those
+@samp{-fugly-*} options they really need for a
+particular source file.
+
+@cindex -fno-ugly option
+@cindex options, -fno-ugly
+@item -fno-ugly
+@cindex ugly features
+@cindex features, ugly
+Specify that all ``ugly'' constructs are to be noisily rejected.
+Same as:
+
+@smallexample
+-fno-ugly-args -fno-ugly-assign -fno-ugly-assumed
+-fno-ugly-comma -fno-ugly-complex -fno-ugly-init
+-fno-ugly-logint
+@end smallexample
+
+@xref{Distensions}, for more information.
+
+@cindex -ff66 option
+@cindex options, -ff66
+@item -ff66
+@cindex FORTRAN 66
+@cindex compatibility, FORTRAN 66
+Specify that the program is written in idiomatic FORTRAN 66.
+Same as @samp{-fonetrip -fugly-assumed}.
+
+The @samp{-fno-f66} option is the inverse of @samp{-ff66}.
+As such, it is the same as @samp{-fno-onetrip -fno-ugly-assumed}.
+
+The meaning of this option is likely to be refined as future
+versions of @code{g77} provide more compatibility with other
+existing and obsolete Fortran implementations.
+
+@cindex -ff77 option
+@cindex options, -ff77
+@item -ff77
+@cindex UNIX f77
+@cindex @code{f2c} compatibility
+@cindex compatibility, @code{f2c}
+@cindex @code{f77} compatibility
+@cindex compatibility, @code{f77}
+Specify that the program is written in idiomatic UNIX FORTRAN 77
+and/or the dialect accepted by the @code{f2c} product.
+Same as @samp{-fbackslash -fno-typeless-boz}.
+
+The meaning of this option is likely to be refined as future
+versions of @code{g77} provide more compatibility with other
+existing and obsolete Fortran implementations.
+
+@cindex -fno-f77 option
+@cindex options, -fno-f77
+@item -fno-f77
+@cindex UNIX f77
+The @samp{-fno-f77} option is @emph{not} the inverse
+of @samp{-ff77}.
+It specifies that the program is not written in idiomatic UNIX
+FORTRAN 77 or @code{f2c}, but in a more widely portable dialect.
+@samp{-fno-f77} is the same as @samp{-fno-backslash}.
+
+The meaning of this option is likely to be refined as future
+versions of @code{g77} provide more compatibility with other
+existing and obsolete Fortran implementations.
+@end table
+
+@node Fortran Dialect Options
+@section Options Controlling Fortran Dialect
+@cindex dialect options
+@cindex language dialect options
+@cindex options, dialect
+
+The following options control the dialect of Fortran
+that the compiler accepts:
+
+@table @code
+@cindex -ffree-form option
+@cindex options, -ffree-form
+@cindex -fno-fixed-form option
+@cindex options, -fno-fixed-form
+@cindex source file form
+@cindex free form
+@cindex fixed form
+@cindex Fortran 90 features
+@item -ffree-form
+@item -fno-fixed-form
+Specify that the source file is written in free form
+(introduced in Fortran 90) instead of the more-traditional fixed form.
+
+@cindex -ff90 option
+@cindex options, -ff90
+@cindex Fortran 90 features
+@item -ff90
+Allow certain Fortran-90 constructs.
+
+This option controls whether certain
+Fortran 90 constructs are recognized.
+(Other Fortran 90 constructs
+might or might not be recognized depending on other options such as
+@samp{-fvxt}, @samp{-ff90-intrinsics-enable}, and the
+current level of support for Fortran 90.)
+
+@xref{Fortran 90}, for more information.
+
+@cindex -fvxt option
+@cindex options, -fvxt
+@item -fvxt
+@cindex Fortran 90 features
+@cindex VXT features
+Specify the treatment of certain constructs that have different
+meanings depending on whether the code is written in
+GNU Fortran (based on FORTRAN 77 and akin to Fortran 90)
+or VXT Fortran (more like VAX FORTRAN).
+
+The default is @samp{-fno-vxt}.
+@samp{-fvxt} specifies that the VXT Fortran interpretations
+for those constructs are to be chosen.
+
+@xref{VXT Fortran}, for more information.
+
+@cindex -fdollar-ok option
+@cindex options, -fdollar-ok
+@item -fdollar-ok
+@cindex dollar sign
+@cindex symbol names
+@cindex character set
+Allow @samp{$} as a valid character in a symbol name.
+
+@cindex -fno-backslash option
+@cindex options, -fno-backslash
+@item -fno-backslash
+@cindex backslash
+@cindex character constants
+@cindex Hollerith constants
+Specify that @samp{\} is not to be specially interpreted in character
+and Hollerith constants a la C and many UNIX Fortran compilers.
+
+For example, with @samp{-fbackslash} in effect, @samp{A\nB} specifies
+three characters, with the second one being newline.
+With @samp{-fno-backslash}, it specifies four characters,
+@samp{A}, @samp{\}, @samp{n}, and @samp{B}.
+
+Note that @code{g77} implements a fairly general form of backslash
+processing that is incompatible with the narrower forms supported
+by some other compilers.
+For example, @samp{'A\003B'} is a three-character string in @code{g77},
+whereas other compilers that support backslash might not support
+the three-octal-digit form, and thus treat that string as longer
+than three characters.
+
+@xref{Backslash in Constants}, for
+information on why @samp{-fbackslash} is the default
+instead of @samp{-fno-backslash}.
+
+@cindex -fno-ugly-args option
+@cindex options, -fno-ugly-args
+@item -fno-ugly-args
+Disallow passing Hollerith and typeless constants as actual
+arguments (for example, @samp{CALL FOO(4HABCD)}).
+
+@xref{Ugly Implicit Argument Conversion}, for more information.
+
+@cindex -fugly-assign option
+@cindex options, -fugly-assign
+@item -fugly-assign
+Use the same storage for a given variable regardless of
+whether it is used to hold an assigned-statement label
+(as in @samp{ASSIGN 10 TO I}) or used to hold numeric data
+(as in @samp{I = 3}).
+
+@xref{Ugly Assigned Labels}, for more information.
+
+@cindex -fugly-assumed option
+@cindex options, -fugly-assumed
+@item -fugly-assumed
+Assume any dummy array with a final dimension specified as @samp{1}
+is really an assumed-size array, as if @samp{*} had been specified
+for the final dimension instead of @samp{1}.
+
+For example, @samp{DIMENSION X(1)} is treated as if it
+had read @samp{DIMENSION X(*)}.
+
+@xref{Ugly Assumed-Size Arrays}, for more information.
+
+@cindex -fugly-comma option
+@cindex options, -fugly-comma
+@item -fugly-comma
+In an external-procedure invocation,
+treat a trailing comma in the argument list
+as specification of a trailing null argument,
+and treat an empty argument list
+as specification of a single null argument.
+
+For example, @samp{CALL FOO(,)} is treated as
+@samp{CALL FOO(%VAL(0), %VAL(0))}.
+That is, @emph{two} null arguments are specified
+by the procedure call when @samp{-fugly-comma} is in force.
+And @samp{F = FUNC()} is treated as @samp{F = FUNC(%VAL(0))}.
+
+The default behavior, @samp{-fno-ugly-comma}, is to ignore
+a single trailing comma in an argument list.
+So, by default, @samp{CALL FOO(X,)} is treated
+exactly the same as @samp{CALL FOO(X)}.
+
+@xref{Ugly Null Arguments}, for more information.
+
+@cindex -fugly-complex option
+@cindex options, -fugly-complex
+@item -fugly-complex
+Do not complain about @samp{REAL(@var{expr})} or
+@samp{AIMAG(@var{expr})} when @var{expr} is a @code{COMPLEX}
+type other than @code{COMPLEX(KIND=1)}---usually
+this is used to permit @code{COMPLEX(KIND=2)}
+(@code{DOUBLE COMPLEX}) operands.
+
+The @samp{-ff90} option controls the interpretation
+of this construct.
+
+@xref{Ugly Complex Part Extraction}, for more information.
+
+@cindex -fno-ugly-init option
+@cindex options, -fno-ugly-init
+@item -fno-ugly-init
+Disallow use of Hollerith and typeless constants as initial
+values (in @code{PARAMETER} and @code{DATA} statements), and
+use of character constants to
+initialize numeric types and vice versa.
+
+For example, @samp{DATA I/'F'/, CHRVAR/65/, J/4HABCD/} is disallowed by
+@samp{-fno-ugly-init}.
+
+@xref{Ugly Conversion of Initializers}, for more information.
+
+@cindex -fugly-logint option
+@cindex options, -fugly-logint
+@item -fugly-logint
+Treat @code{INTEGER} and @code{LOGICAL} variables and
+expressions as potential stand-ins for each other.
+
+For example, automatic conversion between @code{INTEGER} and
+@code{LOGICAL} is enabled, for many contexts, via this option.
+
+@xref{Ugly Integer Conversions}, for more information.
+
+@cindex -fonetrip option
+@cindex options, -fonetrip
+@item -fonetrip
+@cindex FORTRAN 66
+@cindex DO loops, one-trip
+@cindex one-trip DO loops
+@cindex compatibility, FORTRAN 66
+Imperative executable @code{DO} loops are to be executed at
+least once each time they are reached.
+
+ANSI FORTRAN 77 and more recent versions of the Fortran standard
+specify that the body of an imperative @code{DO} loop is not executed
+if the number of iterations calculated from the parameters of the
+loop is less than 1.
+(For example, @samp{DO 10 I = 1, 0}.)
+Such a loop is called a @dfn{zero-trip loop}.
+
+Prior to ANSI FORTRAN 77, many compilers implemented @code{DO} loops
+such that the body of a loop would be executed at least once, even
+if the iteration count was zero.
+Fortran code written assuming this behavior is said to require
+@dfn{one-trip loops}.
+For example, some code written to the FORTRAN 66 standard
+expects this behavior from its @code{DO} loops, although that
+standard did not specify this behavior.
+
+The @samp{-fonetrip} option specifies that the source file(s) being
+compiled require one-trip loops.
+
+This option affects only those loops specified by the (imperative) @code{DO}
+statement and by implied-@code{DO} lists in I/O statements.
+Loops specified by implied-@code{DO} lists in @code{DATA} and
+specification (non-executable) statements are not affected.
+
+@cindex -ftypeless-boz option
+@cindex options, -ftypeless-boz
+@cindex prefix-radix constants
+@cindex constants, prefix-radix
+@cindex constants, types
+@cindex types, constants
+@item -ftypeless-boz
+Specifies that prefix-radix non-decimal constants, such as
+@samp{Z'ABCD'}, are typeless instead of @code{INTEGER(KIND=1)}.
+
+You can test for yourself whether a particular compiler treats
+the prefix form as @code{INTEGER(KIND=1)} or typeless by running the
+following program:
+
+@smallexample
+EQUIVALENCE (I, R)
+R = Z'ABCD1234'
+J = Z'ABCD1234'
+IF (J .EQ. I) PRINT *, 'Prefix form is TYPELESS'
+IF (J .NE. I) PRINT *, 'Prefix form is INTEGER'
+END
+@end smallexample
+
+Reports indicate that many compilers process this form as
+@code{INTEGER(KIND=1)}, though a few as typeless, and at least one
+based on a command-line option specifying some kind of
+compatibility.
+
+@cindex -fintrin-case-initcap option
+@cindex options, -fintrin-case-initcap
+@item -fintrin-case-initcap
+@cindex -fintrin-case-upper option
+@cindex options, -fintrin-case-upper
+@item -fintrin-case-upper
+@cindex -fintrin-case-lower option
+@cindex options, -fintrin-case-lower
+@item -fintrin-case-lower
+@cindex -fintrin-case-any option
+@cindex options, -fintrin-case-any
+@item -fintrin-case-any
+Specify expected case for intrinsic names.
+@samp{-fintrin-case-lower} is the default.
+
+@cindex -fmatch-case-initcap option
+@cindex options, -fmatch-case-initcap
+@item -fmatch-case-initcap
+@cindex -fmatch-case-upper option
+@cindex options, -fmatch-case-upper
+@item -fmatch-case-upper
+@cindex -fmatch-case-lower option
+@cindex options, -fmatch-case-lower
+@item -fmatch-case-lower
+@cindex -fmatch-case-any option
+@cindex options, -fmatch-case-any
+@item -fmatch-case-any
+Specify expected case for keywords.
+@samp{-fmatch-case-lower} is the default.
+
+@cindex -fsource-case-upper option
+@cindex options, -fsource-case-upper
+@item -fsource-case-upper
+@cindex -fsource-case-lower option
+@cindex options, -fsource-case-lower
+@item -fsource-case-lower
+@cindex -fsource-case-preserve option
+@cindex options, -fsource-case-preserve
+@item -fsource-case-preserve
+Specify whether source text other than character and Hollerith constants
+is to be translated to uppercase, to lowercase, or preserved as is.
+@samp{-fsource-case-lower} is the default.
+
+@cindex -fsymbol-case-initcap option
+@cindex options, -fsymbol-case-initcap
+@item -fsymbol-case-initcap
+@cindex -fsymbol-case-upper option
+@cindex options, -fsymbol-case-upper
+@item -fsymbol-case-upper
+@cindex -fsymbol-case-lower option
+@cindex options, -fsymbol-case-lower
+@item -fsymbol-case-lower
+@cindex -fsymbol-case-any option
+@cindex options, -fsymbol-case-any
+@item -fsymbol-case-any
+Specify valid cases for user-defined symbol names.
+@samp{-fsymbol-case-any} is the default.
+
+@cindex -fcase-strict-upper option
+@cindex options, -fcase-strict-upper
+@item -fcase-strict-upper
+Same as @samp{-fintrin-case-upper -fmatch-case-upper -fsource-case-preserve
+-fsymbol-case-upper}.
+(Requires all pertinent source to be in uppercase.)
+
+@cindex -fcase-strict-lower option
+@cindex options, -fcase-strict-lower
+@item -fcase-strict-lower
+Same as @samp{-fintrin-case-lower -fmatch-case-lower -fsource-case-preserve
+-fsymbol-case-lower}.
+(Requires all pertinent source to be in lowercase.)
+
+@cindex -fcase-initcap option
+@cindex options, -fcase-initcap
+@item -fcase-initcap
+Same as @samp{-fintrin-case-initcap -fmatch-case-initcap -fsource-case-preserve
+-fsymbol-case-initcap}.
+(Requires all pertinent source to be in initial capitals,
+as in @samp{Print *,SqRt(Value)}.)
+
+@cindex -fcase-upper option
+@cindex options, -fcase-upper
+@item -fcase-upper
+Same as @samp{-fintrin-case-any -fmatch-case-any -fsource-case-upper
+-fsymbol-case-any}.
+(Maps all pertinent source to uppercase.)
+
+@cindex -fcase-lower option
+@cindex options, -fcase-lower
+@item -fcase-lower
+Same as @samp{-fintrin-case-any -fmatch-case-any -fsource-case-lower
+-fsymbol-case-any}.
+(Maps all pertinent source to lowercase.)
+
+@cindex -fcase-preserve option
+@cindex options, -fcase-preserve
+@item -fcase-preserve
+Same as @samp{-fintrin-case-any -fmatch-case-any -fsource-case-preserve
+-fsymbol-case-any}.
+(Preserves all case in user-defined symbols,
+while allowing any-case matching of intrinsics and keywords.
+For example, @samp{call Foo(i,I)} would pass two @emph{different}
+variables named @samp{i} and @samp{I} to a procedure named @samp{Foo}.)
+
+@cindex -fbadu77-intrinsics-delete option
+@cindex options, -fbadu77-intrinsics-delete
+@item -fbadu77-intrinsics-delete
+@cindex -fbadu77-intrinsics-hide option
+@cindex options, -fbadu77-intrinsics-hide
+@item -fbadu77-intrinsics-hide
+@cindex -fbadu77-intrinsics-disable option
+@cindex options, -fbadu77-intrinsics-disable
+@item -fbadu77-intrinsics-disable
+@cindex -fbadu77-intrinsics-enable option
+@cindex options, -fbadu77-intrinsics-enable
+@item -fbadu77-intrinsics-enable
+@cindex badu77 intrinsics
+@cindex intrinsics, badu77
+Specify status of UNIX intrinsics having inappropriate forms.
+@samp{-fbadu77-intrinsics-enable} is the default.
+@xref{Intrinsic Groups}.
+
+@cindex -ff2c-intrinsics-delete option
+@cindex options, -ff2c-intrinsics-delete
+@item -ff2c-intrinsics-delete
+@cindex -ff2c-intrinsics-hide option
+@cindex options, -ff2c-intrinsics-hide
+@item -ff2c-intrinsics-hide
+@cindex -ff2c-intrinsics-disable option
+@cindex options, -ff2c-intrinsics-disable
+@item -ff2c-intrinsics-disable
+@cindex -ff2c-intrinsics-enable option
+@cindex options, -ff2c-intrinsics-enable
+@item -ff2c-intrinsics-enable
+@cindex f2c intrinsics
+@cindex intrinsics, f2c
+Specify status of f2c-specific intrinsics.
+@samp{-ff2c-intrinsics-enable} is the default.
+@xref{Intrinsic Groups}.
+
+@cindex -ff90-intrinsics-delete option
+@cindex options, -ff90-intrinsics-delete
+@item -ff90-intrinsics-delete
+@cindex -ff90-intrinsics-hide option
+@cindex options, -ff90-intrinsics-hide
+@item -ff90-intrinsics-hide
+@cindex -ff90-intrinsics-disable option
+@cindex options, -ff90-intrinsics-disable
+@item -ff90-intrinsics-disable
+@cindex -ff90-intrinsics-enable option
+@cindex options, -ff90-intrinsics-enable
+@item -ff90-intrinsics-enable
+@cindex Fortran 90 intrinsics
+@cindex intrinsics, Fortran 90
+Specify status of F90-specific intrinsics.
+@samp{-ff90-intrinsics-enable} is the default.
+@xref{Intrinsic Groups}.
+
+@cindex -fgnu-intrinsics-delete option
+@cindex options, -fgnu-intrinsics-delete
+@item -fgnu-intrinsics-delete
+@cindex -fgnu-intrinsics-hide option
+@cindex options, -fgnu-intrinsics-hide
+@item -fgnu-intrinsics-hide
+@cindex -fgnu-intrinsics-disable option
+@cindex options, -fgnu-intrinsics-disable
+@item -fgnu-intrinsics-disable
+@cindex -fgnu-intrinsics-enable option
+@cindex options, -fgnu-intrinsics-enable
+@item -fgnu-intrinsics-enable
+@cindex Digital Fortran features
+@cindex COMPLEX intrinsics
+@cindex intrinsics, COMPLEX
+Specify status of Digital's COMPLEX-related intrinsics.
+@samp{-fgnu-intrinsics-enable} is the default.
+@xref{Intrinsic Groups}.
+
+@cindex -fmil-intrinsics-delete option
+@cindex options, -fmil-intrinsics-delete
+@item -fmil-intrinsics-delete
+@cindex -fmil-intrinsics-hide option
+@cindex options, -fmil-intrinsics-hide
+@item -fmil-intrinsics-hide
+@cindex -fmil-intrinsics-disable option
+@cindex options, -fmil-intrinsics-disable
+@item -fmil-intrinsics-disable
+@cindex -fmil-intrinsics-enable option
+@cindex options, -fmil-intrinsics-enable
+@item -fmil-intrinsics-enable
+@cindex MIL-STD 1753
+@cindex intrinsics, MIL-STD 1753
+Specify status of MIL-STD-1753-specific intrinsics.
+@samp{-fmil-intrinsics-enable} is the default.
+@xref{Intrinsic Groups}.
+
+@cindex -funix-intrinsics-delete option
+@cindex options, -funix-intrinsics-delete
+@item -funix-intrinsics-delete
+@cindex -funix-intrinsics-hide option
+@cindex options, -funix-intrinsics-hide
+@item -funix-intrinsics-hide
+@cindex -funix-intrinsics-disable option
+@cindex options, -funix-intrinsics-disable
+@item -funix-intrinsics-disable
+@cindex -funix-intrinsics-enable option
+@cindex options, -funix-intrinsics-enable
+@item -funix-intrinsics-enable
+@cindex UNIX intrinsics
+@cindex intrinsics, UNIX
+Specify status of UNIX intrinsics.
+@samp{-funix-intrinsics-enable} is the default.
+@xref{Intrinsic Groups}.
+
+@cindex -fvxt-intrinsics-delete option
+@cindex options, -fvxt-intrinsics-delete
+@item -fvxt-intrinsics-delete
+@cindex -fvxt-intrinsics-hide option
+@cindex options, -fvxt-intrinsics-hide
+@item -fvxt-intrinsics-hide
+@cindex -fvxt-intrinsics-disable option
+@cindex options, -fvxt-intrinsics-disable
+@item -fvxt-intrinsics-disable
+@cindex -fvxt-intrinsics-enable option
+@cindex options, -fvxt-intrinsics-enable
+@item -fvxt-intrinsics-enable
+@cindex VXT intrinsics
+@cindex intrinsics, VXT
+Specify status of VXT intrinsics.
+@samp{-fvxt-intrinsics-enable} is the default.
+@xref{Intrinsic Groups}.
+
+@cindex -ffixed-line-length-@var{n} option
+@cindex options, -ffixed-line-length-@var{n}
+@item -ffixed-line-length-@var{n}
+@cindex source file format
+@cindex line length
+@cindex length of source lines
+@cindex fixed-form line length
+Set column after which characters are ignored in typical fixed-form
+lines in the source file, and through which spaces are assumed (as
+if padded to that length) after the ends of short fixed-form lines.
+
+@cindex card image
+@cindex extended-source option
+Popular values for @var{n} include 72 (the
+standard and the default), 80 (card image), and 132 (corresponds
+to ``extended-source'' options in some popular compilers).
+@var{n} may be @samp{none}, meaning that the entire line is meaningful
+and that continued character constants never have implicit spaces appended
+to them to fill out the line.
+@samp{-ffixed-line-length-0} means the same thing as
+@samp{-ffixed-line-length-none}.
+
+@xref{Source Form}, for more information.
+@end table
+
+@node Warning Options
+@section Options to Request or Suppress Warnings
+@cindex options to control warnings
+@cindex warning messages
+@cindex messages, warning
+@cindex suppressing warnings
+
+Warnings are diagnostic messages that report constructions which
+are not inherently erroneous but which are risky or suggest there
+might have been an error.
+
+You can request many specific warnings with options beginning @samp{-W},
+for example @samp{-Wimplicit} to request warnings on implicit
+declarations. Each of these specific warning options also has a
+negative form beginning @samp{-Wno-} to turn off warnings;
+for example, @samp{-Wno-implicit}. This manual lists only one of the
+two forms, whichever is not the default.
+
+These options control the amount and kinds of warnings produced by GNU
+Fortran:
+
+@table @code
+@cindex syntax checking
+@cindex -fsyntax-only option
+@cindex options, -fsyntax-only
+@item -fsyntax-only
+Check the code for syntax errors, but don't do anything beyond that.
+
+@cindex -pedantic option
+@cindex options, -pedantic
+@item -pedantic
+Issue warnings for uses of extensions to ANSI FORTRAN 77.
+@samp{-pedantic} also applies to C-language constructs where they
+occur in GNU Fortran source files, such as use of @samp{\e} in a
+character constant within a directive like @samp{#include}.
+
+Valid ANSI FORTRAN 77 programs should compile properly with or without
+this option.
+However, without this option, certain GNU extensions and traditional
+Fortran features are supported as well.
+With this option, many of them are rejected.
+
+Some users try to use @samp{-pedantic} to check programs for strict ANSI
+conformance.
+They soon find that it does not do quite what they want---it finds some
+non-ANSI practices, but not all.
+However, improvements to @code{g77} in this area are welcome.
+
+@cindex -pedantic-errors option
+@cindex options, -pedantic-errors
+@item -pedantic-errors
+Like @samp{-pedantic}, except that errors are produced rather than
+warnings.
+
+@cindex -fpedantic option
+@cindex options, -fpedantic
+@item -fpedantic
+Like @samp{-pedantic}, but applies only to Fortran constructs.
+
+@cindex -w option
+@cindex options, -w
+@item -w
+Inhibit all warning messages.
+
+@cindex -Wno-globals option
+@cindex options, -Wno-globals
+@item -Wno-globals
+@cindex global names, warning
+@cindex warnings, global names
+Inhibit warnings about use of a name as both a global name
+(a subroutine, function, or block data program unit, or a
+common block) and implicitly as the name of an intrinsic
+in a source file.
+
+Also inhibit warnings about inconsistent invocations and/or
+definitions of global procedures (function and subroutines).
+Such inconsistencies include different numbers of arguments
+and different types of arguments.
+
+@cindex -Wimplicit option
+@cindex options, -Wimplicit
+@item -Wimplicit
+@cindex implicit declaration, warning
+@cindex warnings, implicit declaration
+@cindex -u option
+@cindex /WARNINGS=DECLARATIONS switch
+@cindex IMPLICIT NONE, similar effect
+@cindex effecting IMPLICIT NONE
+Warn whenever a variable, array, or function is implicitly
+declared.
+Has an effect similar to using the @code{IMPLICIT NONE} statement
+in every program unit.
+(Some Fortran compilers provide this feature by an option
+named @samp{-u} or @samp{/WARNINGS=DECLARATIONS}.)
+
+@cindex -Wunused option
+@cindex options, -Wunused
+@item -Wunused
+@cindex unused variables
+@cindex variables, unused
+Warn whenever a variable is unused aside from its declaration.
+
+@cindex -Wuninitialized option
+@cindex options, -Wuninitialized
+@item -Wuninitialized
+@cindex uninitialized variables
+@cindex variables, uninitialized
+Warn whenever an automatic variable is used without first being initialized.
+
+These warnings are possible only in optimizing compilation,
+because they require data-flow information that is computed only
+when optimizing. If you don't specify @samp{-O}, you simply won't
+get these warnings.
+
+These warnings occur only for variables that are candidates for
+register allocation. Therefore, they do not occur for a variable
+@c that is declared @code{VOLATILE}, or
+whose address is taken, or whose size
+is other than 1, 2, 4 or 8 bytes. Also, they do not occur for
+arrays, even when they are in registers.
+
+Note that there might be no warning about a variable that is used only
+to compute a value that itself is never used, because such
+computations may be deleted by data-flow analysis before the warnings
+are printed.
+
+These warnings are made optional because GNU Fortran is not smart
+enough to see all the reasons why the code might be correct
+despite appearing to have an error. Here is one example of how
+this can happen:
+
+@example
+SUBROUTINE DISPAT(J)
+IF (J.EQ.1) I=1
+IF (J.EQ.2) I=4
+IF (J.EQ.3) I=5
+CALL FOO(I)
+END
+@end example
+
+@noindent
+If the value of @code{J} is always 1, 2 or 3, then @code{I} is
+always initialized, but GNU Fortran doesn't know this. Here is
+another common case:
+
+@example
+SUBROUTINE MAYBE(FLAG)
+LOGICAL FLAG
+IF (FLAG) VALUE = 9.4
+@dots{}
+IF (FLAG) PRINT *, VALUE
+END
+@end example
+
+@noindent
+This has no bug because @code{VALUE} is used only if it is set.
+
+@cindex -Wall option
+@cindex options, -Wall
+@item -Wall
+@cindex all warnings
+@cindex warnings, all
+The @samp{-Wunused} and @samp{-Wuninitialized} options combined.
+These are all the
+options which pertain to usage that we recommend avoiding and that we
+believe is easy to avoid.
+(As more warnings are added to @code{g77}, some might
+be added to the list enabled by @samp{-Wall}.)
+@end table
+
+The remaining @samp{-W@dots{}} options are not implied by @samp{-Wall}
+because they warn about constructions that we consider reasonable to
+use, on occasion, in clean programs.
+
+@table @code
+@c @item -W
+@c Print extra warning messages for these events:
+@c
+@c @itemize @bullet
+@c @item
+@c If @samp{-Wall} or @samp{-Wunused} is also specified, warn about unused
+@c arguments.
+@c
+@c @end itemize
+@c
+@cindex -Wsurprising option
+@cindex options, -Wsurprising
+@item -Wsurprising
+Warn about ``suspicious'' constructs that are interpreted
+by the compiler in a way that might well be surprising to
+someone reading the code.
+These differences can result in subtle, compiler-dependent
+(even machine-dependent) behavioral differences.
+The constructs warned about include:
+
+@itemize @bullet
+@item
+Expressions having two arithmetic operators in a row, such
+as @samp{X*-Y}.
+Such a construct is nonstandard, and can produce
+unexpected results in more complicated situations such
+as @samp{X**-Y*Z}.
+@code{g77}, along with many other compilers, interprets
+this example differently than many programmers, and a few
+other compilers.
+Specifically, @code{g77} interprets @samp{X**-Y*Z} as
+@samp{(X**(-Y))*Z}, while others might think it should
+be interpreted as @samp{X**(-(Y*Z))}.
+
+A revealing example is the constant expression @samp{2**-2*1.},
+which @code{g77} evaluates to .25, while others might evaluate
+it to 0., the difference resulting from the way precedence affects
+type promotion.
+
+(The @samp{-fpedantic} option also warns about expressions
+having two arithmetic operators in a row.)
+
+@item
+Expressions with a unary minus followed by an operand and then
+a binary operator other than plus or minus.
+For example, @samp{-2**2} produces a warning, because
+the precedence is @samp{-(2**2)}, yielding -4, not
+@samp{(-2)**2}, which yields 4, and which might represent
+what a programmer expects.
+
+An example of an expression producing different results
+in a surprising way is @samp{-I*S}, where @var{I} holds
+the value @samp{-2147483648} and @var{S} holds @samp{0.5}.
+On many systems, negating @var{I} results in the same
+value, not a positive number, because it is already the
+lower bound of what an @code{INTEGER(KIND=1)} variable can hold.
+So, the expression evaluates to a positive number, while
+the ``expected'' interpretation, @samp{(-I)*S}, would
+evaluate to a negative number.
+
+Even cases such as @samp{-I*J} produce warnings,
+even though, in most configurations and situations,
+there is no computational difference between the
+results of the two interpretations---the purpose
+of this warning is to warn about differing interpretations
+and encourage a better style of coding, not to identify
+only those places where bugs might exist in the user's
+code.
+
+@cindex DO statement
+@cindex statements, DO
+@item
+@code{DO} loops with @code{DO} variables that are not
+of integral type---that is, using @code{REAL}
+variables as loop control variables.
+Although such loops can be written to work in the
+``obvious'' way, the way @code{g77} is required by the
+Fortran standard to interpret such code is likely to
+be quite different from the way many programmers expect.
+(This is true of all @code{DO} loops, but the differences
+are pronounced for non-integral loop control variables.)
+
+@xref{Loops}, for more information.
+@end itemize
+
+@cindex -Werror option
+@cindex options, -Werror
+@item -Werror
+Make all warnings into errors.
+
+@cindex -W option
+@cindex options, -W
+@item -W
+@cindex extra warnings
+@cindex warnings, extra
+Turns on ``extra warnings'' and, if optimization is specified
+via @samp{-O}, the @samp{-Wuninitialized} option.
+(This might change in future versions of @code{g77}.)
+
+``Extra warnings'' are issued for:
+
+@itemize @bullet
+@item
+@cindex unused parameters
+@cindex parameters, unused
+@cindex unused arguments
+@cindex arguments, unused
+@cindex unused dummies
+@cindex dummies, unused
+Unused parameters to a procedure (when @samp{-Wunused} also is
+specified).
+
+@item
+@cindex overflow
+Overflows involving floating-point constants (not available
+for certain configurations).
+@end itemize
+@end table
+
+@xref{Warning Options,,Options to Request or Suppress Warnings,
+gcc,Using and Porting GNU CC}, for information on more options offered
+by the GBE shared by @code{g77}, @code{gcc}, and other GNU compilers.
+
+Some of these have no effect when compiling programs written in Fortran:
+
+@table @code
+@cindex -Wcomment option
+@cindex options, -Wcomment
+@item -Wcomment
+@cindex -Wformat option
+@cindex options, -Wformat
+@item -Wformat
+@cindex -Wparentheses option
+@cindex options, -Wparentheses
+@item -Wparentheses
+@cindex -Wswitch option
+@cindex options, -Wswitch
+@item -Wswitch
+@cindex -Wtraditional option
+@cindex options, -Wtraditional
+@item -Wtraditional
+@cindex -Wshadow option
+@cindex options, -Wshadow
+@item -Wshadow
+@cindex -Wid-clash-@var{len} option
+@cindex options, -Wid-clash-@var{len}
+@item -Wid-clash-@var{len}
+@cindex -Wlarger-than-@var{len} option
+@cindex options, -Wlarger-than-@var{len}
+@item -Wlarger-than-@var{len}
+@cindex -Wconversion option
+@cindex options, -Wconversion
+@item -Wconversion
+@cindex -Waggregate-return option
+@cindex options, -Waggregate-return
+@item -Waggregate-return
+@cindex -Wredundant-decls option
+@cindex options, -Wredundant-decls
+@item -Wredundant-decls
+@cindex unsupported warnings
+@cindex warnings, unsupported
+These options all could have some relevant meaning for
+GNU Fortran programs, but are not yet supported.
+@end table
+
+@node Debugging Options
+@section Options for Debugging Your Program or GNU Fortran
+@cindex options, debugging
+@cindex debugging information options
+
+GNU Fortran has various special options that are used for debugging
+either your program or @code{g77}.
+
+@table @code
+@cindex -g option
+@cindex options, -g
+@item -g
+Produce debugging information in the operating system's native format
+(stabs, COFF, XCOFF, or DWARF). GDB can work with this debugging
+information.
+
+@cindex common blocks
+@cindex equivalence areas
+@cindex missing debug features
+Support for this option in Fortran programs is incomplete.
+In particular, names of variables and arrays in common blocks
+or that are storage-associated via @code{EQUIVALENCE} are
+unavailable to the debugger.
+
+However, version 0.5.19 of @code{g77} does provide this information
+in a rudimentary way, as controlled by the
+@samp{-fdebug-kludge} option.
+
+@xref{Code Gen Options,,Options for Code Generation Conventions},
+for more information.
+@end table
+
+@xref{Debugging Options,,Options for Debugging Your Program or GNU CC,
+gcc,Using and Porting GNU CC}, for more information on debugging options.
+
+@node Optimize Options
+@section Options That Control Optimization
+@cindex optimize options
+@cindex options, optimization
+
+Most Fortran users will want to use no optimization when
+developing and testing programs, and use @samp{-O} or @samp{-O2} when
+compiling programs for late-cycle testing and for production use.
+However, note that certain diagnostics---such as for uninitialized
+variables---depend on the flow analysis done by @samp{-O}, i.e.@: you
+must use @samp{-O} or @samp{-O2} to get such diagnostics.
+
+The following flags have particular applicability when
+compiling Fortran programs:
+
+@table @code
+@cindex -malign-double option
+@cindex options, -malign-double
+@item -malign-double
+(Intel x86 architecture only.)
+
+Noticeably improves performance of @code{g77} programs making
+heavy use of @code{REAL(KIND=2)} (@code{DOUBLE PRECISION}) data
+on some systems.
+In particular, systems using Pentium, Pentium Pro, 586, and
+686 implementations
+of the i386 architecture execute programs faster when
+@code{REAL(KIND=2)} (@code{DOUBLE PRECISION}) data are
+aligned on 64-bit boundaries
+in memory.
+
+This option can, at least, make benchmark results more consistent
+across various system configurations, versions of the program,
+and data sets.
+
+@emph{Note:} The warning in the @code{gcc} documentation about
+this option does not apply, generally speaking, to Fortran
+code compiled by @code{g77}.
+
+@emph{Also note:} @samp{-malign-double} applies only to
+statically-allocated data.
+Double-precision data on the stack can still
+cause problems due to misalignment.
+@xref{Aligned Data}.
+
+@emph{Also also note:} The negative form of @samp{-malign-double}
+is @samp{-mno-align-double}, not @samp{-benign-double}.
+
+@cindex -ffloat-store option
+@cindex options, -ffloat-store
+@item -ffloat-store
+@cindex IEEE conformance
+@cindex conformance, IEEE
+@cindex floating point precision
+Might help a Fortran program that depends on exact IEEE conformance on
+some machines, but might slow down a program that doesn't.
+
+This option is effective when the floating point unit is set to work in
+IEEE 854 `extended precision'---as it typically is on x86 and m68k GNU
+systems---rather than IEEE 754 double precision. @code{-ffloat-store}
+tries to remove the extra precision by spilling data from floating point
+registers into memory and this typically involves a big performance
+hit. However, it doesn't affect intermediate results, so that it is
+only partially effective. `Excess precision' is avoided in code like:
+@smallexample
+a = b + c
+d = a * e
+@end smallexample
+but not in code like:
+@smallexample
+ d = (b + c) * e
+@end smallexample
+
+For another, potentially better, way of controlling the precision
+@ref{Floating point precision}.
+
+@cindex -fforce-mem option
+@cindex options, -fforce-mem
+@item -fforce-mem
+@cindex -fforce-addr option
+@cindex options, -fforce-addr
+@item -fforce-addr
+@cindex loops, speeding up
+@cindex speeding up loops
+Might improve optimization of loops.
+
+@cindex -fno-inline option
+@cindex options, -fno-inline
+@item -fno-inline
+@cindex in-line compilation
+@cindex compilation, in-line
+@c DL: Only relevant for -O3?
+Don't compile statement functions inline.
+Might reduce the size of a program unit---which might be at
+expense of some speed (though it should compile faster).
+Note that if you are not optimizing, no functions can be expanded inline.
+
+@cindex -ffast-math option
+@cindex options, -ffast-math
+@item -ffast-math
+@cindex IEEE conformance
+@cindex conformance, IEEE
+Might allow some programs designed to not be too dependent
+on IEEE behavior for floating-point to run faster, or die trying.
+
+@cindex -fstrength-reduce option
+@cindex options, -fstrength-reduce
+@item -fstrength-reduce
+@cindex loops, speeding up
+@cindex speeding up loops
+@c DL: normally defaulted?
+Might make some loops run faster.
+
+@cindex -frerun-cse-after-loop option
+@cindex options, -frerun-cse-after-loop
+@item -frerun-cse-after-loop
+@cindex -fexpensive-optimizations option
+@cindex options, -fexpensive-optimizations
+@c DL: This is -O2?
+@item -fexpensive-optimizations
+@cindex -fdelayed-branch option
+@cindex options, -fdelayed-branch
+@item -fdelayed-branch
+@cindex -fschedule-insns option
+@cindex options, -fschedule-insns
+@item -fschedule-insns
+@cindex -fschedule-insns2 option
+@cindex options, -fschedule-insns2
+@item -fschedule-insns2
+@cindex -fcaller-saves option
+@cindex options, -fcaller-saves
+@item -fcaller-saves
+Might improve performance on some code.
+
+@cindex -funroll-loops option
+@cindex options, -funroll-loops
+@item -funroll-loops
+@cindex loops, unrolling
+@cindex unrolling loops
+@cindex loop optimization
+@c DL: fixme: Craig doesn't like `indexed' but f95 doesn't seem to
+@c provide a suitable term
+Typically improves performance on code using indexed @code{DO} loops by
+unrolling them and is probably generally appropriate for Fortran, though
+it is not turned on at any optimization level.
+Note that outer loop unrolling isn't done specifically; decisions about
+whether to unroll a loop are made on the basis of its instruction count.
+
+@c DL: Fixme: This should obviously go somewhere else...
+Also, no `loop discovery'@footnote{@dfn{loop discovery} refers to the
+process by which a compiler, or indeed any reader of a program,
+determines which portions of the program are more likely to be executed
+repeatedly as it is being run. Such discovery typically is done early
+when compiling using optimization techniques, so the ``discovered''
+loops get more attention---and more run-time resources, such as
+registers---from the compiler. It is easy to ``discover'' loops that are
+constructed out of looping constructs in the language
+(such as Fortran's @code{DO}). For some programs, ``discovering'' loops
+constructed out of lower-level constructs (such as @code{IF} and
+@code{GOTO}) can lead to generation of more optimal code
+than otherwise.} is done, so only loops written with @code{DO}
+benefit from loop optimizations, including---but not limited
+to---unrolling. Loops written with @code{IF} and @code{GOTO} will not
+be recognized as such. This option only unrolls indexed @code{DO}
+loops, not @code{DO WHILE} loops.
+
+@cindex -funroll-all-loops option
+@cindex options, -funroll-all-loops
+@cindex @code{DO WHILE}
+@item -funroll-all-loops
+@c DL: Check my understanding of -funroll-all-loops v. -funroll-loops is correct.
+Probably improves performance on code using @code{DO WHILE} loops by
+unrolling them in addition to indexed @code{DO} loops. In the absence
+of @code{DO WHILE}, this option is equivalent to @code{-funroll-loops}
+but possibly slower.
+
+@item -fno-move-all-movables
+@cindex -fno-move-all-movables option
+@cindex options, -fno-move-all-movables
+@item -fno-reduce-all-givs
+@cindex -fno-reduce-all-givs option
+@cindex options, -fno-reduce-all-givs
+@item -fno-rerun-loop-opt
+@cindex -fno-rerun-loop-opt option
+@cindex options, -fno-rerun-loop-opt
+@emph{Version info:}
+These options are not supported by
+versions of @code{g77} based on @code{gcc} version 2.8.
+
+Each of these might improve performance on some code.
+
+Analysis of Fortran code optimization and the resulting
+optimizations triggered by the above options were
+contributed by Toon Moene (@email{toon@@moene.indiv.nluug.nl}).
+
+These three options are intended to be removed someday, once
+they have helped determine the efficacy of various
+approaches to improving the performance of Fortran code.
+
+Please let us know how use of these options affects
+the performance of your production code.
+We're particularly interested in code that runs faster
+when these options are @emph{disabled}, and in
+non-Fortran code that benefits when they are
+@emph{enabled} via the above @code{gcc} command-line options.
+@end table
+
+@xref{Optimize Options,,Options That Control Optimization,
+gcc,Using and Porting GNU CC}, for more information on options
+to optimize the generated machine code.
+
+@node Preprocessor Options
+@section Options Controlling the Preprocessor
+@cindex preprocessor options
+@cindex options, preprocessor
+@cindex cpp program
+@cindex programs, cpp
+
+These options control the C preprocessor, which is run on each C source
+file before actual compilation.
+
+@xref{Preprocessor Options,,Options Controlling the Preprocessor,
+gcc,Using and Porting GNU CC}, for information on C preprocessor options.
+
+@cindex INCLUDE directive
+@cindex directive, INCLUDE
+Some of these options also affect how @code{g77} processes the
+@code{INCLUDE} directive.
+Since this directive is processed even when preprocessing
+is not requested, it is not described in this section.
+@xref{Directory Options,,Options for Directory Search}, for
+information on how @code{g77} processes the @code{INCLUDE} directive.
+
+However, the @code{INCLUDE} directive does not apply
+preprocessing to the contents of the included file itself.
+
+Therefore, any file that contains preprocessor directives
+(such as @code{#include}, @code{#define}, and @code{#if})
+must be included via the @code{#include} directive, not
+via the @code{INCLUDE} directive.
+Therefore, any file containing preprocessor directives,
+if included, is necessarily included by a file that itself
+contains preprocessor directives.
+
+@node Directory Options
+@section Options for Directory Search
+@cindex directory options
+@cindex options, directory search
+@cindex search path
+
+These options affect how the @code{cpp} preprocessor searches
+for files specified via the @code{#include} directive.
+Therefore, when compiling Fortran programs, they are meaningful
+when the preprocessor is used.
+
+@cindex INCLUDE directive
+@cindex directive, INCLUDE
+Some of these options also affect how @code{g77} searches
+for files specified via the @code{INCLUDE} directive,
+although files included by that directive are not,
+themselves, preprocessed.
+These options are:
+
+@table @code
+@cindex -I- option
+@cindex options, -I-
+@item -I-
+@cindex -Idir option
+@cindex options, -Idir
+@item -I@var{dir}
+@cindex directory search paths for inclusion
+@cindex inclusion, directory search paths for
+@cindex searching for included files
+These affect interpretation of the @code{INCLUDE} directive
+(as well as of the @code{#include} directive of the @code{cpp}
+preprocessor).
+
+Note that @samp{-I@var{dir}} must be specified @emph{without} any
+spaces between @samp{-I} and the directory name---that is,
+@samp{-Ifoo/bar} is valid, but @samp{-I foo/bar}
+is rejected by the @code{g77} compiler (though the preprocessor supports
+the latter form).
+@c this is due to toplev.c's inflexible option processing
+Also note that the general behavior of @samp{-I} and
+@code{INCLUDE} is pretty much the same as of @samp{-I} with
+@code{#include} in the @code{cpp} preprocessor, with regard to
+looking for @file{header.gcc} files and other such things.
+
+@xref{Directory Options,,Options for Directory Search,
+gcc,Using and Porting GNU CC}, for information on the @samp{-I} option.
+@end table
+
+@node Code Gen Options
+@section Options for Code Generation Conventions
+@cindex code generation conventions
+@cindex options, code generation
+@cindex run-time options
+
+These machine-independent options control the interface conventions
+used in code generation.
+
+Most of them have both positive and negative forms; the negative form
+of @samp{-ffoo} would be @samp{-fno-foo}. In the table below, only
+one of the forms is listed---the one which is not the default. You
+can figure out the other form by either removing @samp{no-} or adding
+it.
+
+@table @code
+@cindex -fno-automatic option
+@cindex options, -fno-automatic
+@item -fno-automatic
+@cindex SAVE statement
+@cindex statements, SAVE
+Treat each program unit as if the @code{SAVE} statement was specified
+for every local variable and array referenced in it.
+Does not affect common blocks.
+(Some Fortran compilers provide this option under
+the name @samp{-static}.)
+
+@cindex -finit-local-zero option
+@cindex options, -finit-local-zero
+@item -finit-local-zero
+@cindex DATA statement
+@cindex statements, DATA
+@cindex initialization of local variables
+@cindex variables, initialization of
+@cindex uninitialized variables
+@cindex variables, uninitialized
+Specify that variables and arrays that are local to a program unit
+(not in a common block and not passed as an argument) are to be initialized
+to binary zeros.
+
+Since there is a run-time penalty for initialization of variables
+that are not given the @code{SAVE} attribute, it might be a
+good idea to also use @samp{-fno-automatic} with @samp{-finit-local-zero}.
+
+@cindex -fno-f2c option
+@cindex options, -fno-f2c
+@item -fno-f2c
+@cindex @code{f2c} compatibility
+@cindex compatibility, @code{f2c}
+Do not generate code designed to be compatible with code generated
+by @code{f2c}; use the GNU calling conventions instead.
+
+The @code{f2c} calling conventions require functions that return
+type @code{REAL(KIND=1)} to actually return the C type @code{double},
+and functions that return type @code{COMPLEX} to return the
+values via an extra argument in the calling sequence that points
+to where to store the return value.
+Under the GNU calling conventions, such functions simply return
+their results as they would in GNU C---@code{REAL(KIND=1)} functions
+return the C type @code{float}, and @code{COMPLEX} functions
+return the GNU C type @code{complex} (or its @code{struct}
+equivalent).
+
+This does not affect the generation of code that interfaces with the
+@code{libg2c} library.
+
+However, because the @code{libg2c} library uses @code{f2c}
+calling conventions, @code{g77} rejects attempts to pass
+intrinsics implemented by routines in this library as actual
+arguments when @samp{-fno-f2c} is used, to avoid bugs when
+they are actually called by code expecting the GNU calling
+conventions to work.
+
+For example, @samp{INTRINSIC ABS;CALL FOO(ABS)} is
+rejected when @samp{-fno-f2c} is in force.
+(Future versions of the @code{g77} run-time library might
+offer routines that provide GNU-callable versions of the
+routines that implement the @code{f2c}-callable intrinsics
+that may be passed as actual arguments, so that
+valid programs need not be rejected when @samp{-fno-f2c}
+is used.)
+
+@strong{Caution:} If @samp{-fno-f2c} is used when compiling any
+source file used in a program, it must be used when compiling
+@emph{all} Fortran source files used in that program.
+
+@c seems kinda dumb to tell people about an option they can't use -- jcb
+@c then again, we want users building future-compatible libraries with it.
+@cindex -ff2c-library option
+@cindex options, -ff2c-library
+@item -ff2c-library
+Specify that use of @code{libg2c} (or the original @code{libf2c})
+is required.
+This is the default for the current version of @code{g77}.
+
+Currently it is not
+valid to specify @samp{-fno-f2c-library}.
+This option is provided so users can specify it in shell
+scripts that build programs and libraries that require the
+@code{libf2c} library, even when being compiled by future
+versions of @code{g77} that might otherwise default to
+generating code for an incompatible library.
+
+@cindex -fno-underscoring option
+@cindex options, -fno-underscoring
+@item -fno-underscoring
+@cindex underscores
+@cindex symbol names, underscores
+@cindex transforming symbol names
+@cindex symbol names, transforming
+Do not transform names of entities specified in the Fortran
+source file by appending underscores to them.
+
+With @samp{-funderscoring} in effect, @code{g77} appends two underscores
+to names with underscores and one underscore to external names with
+no underscores. (@code{g77} also appends two underscores to internal
+names with underscores to avoid naming collisions with external names.
+The @samp{-fno-second-underscore} option disables appending of the
+second underscore in all cases.)
+
+This is done to ensure compatibility with code produced by many
+UNIX Fortran compilers, including @code{f2c}, which perform the
+same transformations.
+
+Use of @samp{-fno-underscoring} is not recommended unless you are
+experimenting with issues such as integration of (GNU) Fortran into
+existing system environments (vis-a-vis existing libraries, tools, and
+so on).
+
+For example, with @samp{-funderscoring}, and assuming other defaults like
+@samp{-fcase-lower} and that @samp{j()} and @samp{max_count()} are
+external functions while @samp{my_var} and @samp{lvar} are local variables,
+a statement like
+
+@smallexample
+I = J() + MAX_COUNT (MY_VAR, LVAR)
+@end smallexample
+
+@noindent
+is implemented as something akin to:
+
+@smallexample
+i = j_() + max_count__(&my_var__, &lvar);
+@end smallexample
+
+With @samp{-fno-underscoring}, the same statement is implemented as:
+
+@smallexample
+i = j() + max_count(&my_var, &lvar);
+@end smallexample
+
+Use of @samp{-fno-underscoring} allows direct specification of
+user-defined names while debugging and when interfacing @code{g77}-compiled
+code with other languages.
+
+Note that just because the names match does @emph{not} mean that the
+interface implemented by @code{g77} for an external name matches the
+interface implemented by some other language for that same name.
+That is, getting code produced by @code{g77} to link to code produced
+by some other compiler using this or any other method can be only a
+small part of the overall solution---getting the code generated by
+both compilers to agree on issues other than naming can require
+significant effort, and, unlike naming disagreements, linkers normally
+cannot detect disagreements in these other areas.
+
+Also, note that with @samp{-fno-underscoring}, the lack of appended
+underscores introduces the very real possibility that a user-defined
+external name will conflict with a name in a system library, which
+could make finding unresolved-reference bugs quite difficult in some
+cases---they might occur at program run time, and show up only as
+buggy behavior at run time.
+
+In future versions of @code{g77}, we hope to improve naming and linking
+issues so that debugging always involves using the names as they appear
+in the source, even if the names as seen by the linker are mangled to
+prevent accidental linking between procedures with incompatible
+interfaces.
+
+@cindex -fno-second-underscore option
+@cindex options, -fno-second-underscore
+@item -fno-second-underscore
+@cindex underscores
+@cindex symbol names, underscores
+@cindex transforming symbol names
+@cindex symbol names, transforming
+Do not append a second underscore to names of entities specified
+in the Fortran source file.
+
+This option has no effect if @samp{-fno-underscoring} is
+in effect.
+
+Otherwise, with this option, an external name such as @samp{MAX_COUNT}
+is implemented as a reference to the link-time external symbol
+@samp{max_count_}, instead of @samp{max_count__}.
+
+@cindex -fno-ident option
+@cindex options, -fno-ident
+@item -fno-ident
+Ignore the @samp{#ident} directive.
+
+@cindex -fzeros option
+@cindex options, -fzeros
+@item -fzeros
+Treat initial values of zero as if they were any other value.
+
+As of version 0.5.18, @code{g77} normally treats @code{DATA} and
+other statements that are used to specify initial values of zero
+for variables and arrays as if no values were actually specified,
+in the sense that no diagnostics regarding multiple initializations
+are produced.
+
+This is done to speed up compiling of programs that initialize
+large arrays to zeros.
+
+Use @samp{-fzeros} to revert to the simpler, slower behavior
+that can catch multiple initializations by keeping track of
+all initializations, zero or otherwise.
+
+@emph{Caution:} Future versions of @code{g77} might disregard this option
+(and its negative form, the default) or interpret it somewhat
+differently.
+The interpretation changes will affect only non-standard
+programs; standard-conforming programs should not be affected.
+
+@cindex -fdebug-kludge option
+@cindex options, -fdebug-kludge
+@item -fdebug-kludge
+Emit information on @code{COMMON} and @code{EQUIVALENCE} members
+that might help users of debuggers work around lack of proper debugging
+information on such members.
+
+As of version 0.5.19, @code{g77} offers this option to emit
+information on members of aggregate areas to help users while debugging.
+This information consists of establishing the type and contents of each
+such member so that, when a debugger is asked to print the contents,
+the printed information provides rudimentary debugging information.
+This information identifies the name of the aggregate area (either the
+@code{COMMON} block name, or the @code{g77}-assigned name for the
+@code{EQUIVALENCE} name) and the offset, in bytes, of the member from
+the beginning of the area.
+
+Using @code{gdb}, this information is not coherently displayed in the Fortran
+language mode, so temporarily switching to the C language mode to display the
+information is suggested.
+Use @samp{set language c} and @samp{set language fortran} to accomplish this.
+
+For example:
+
+@smallexample
+ COMMON /X/A,B
+ EQUIVALENCE (C,D)
+ CHARACTER XX*50
+ EQUIVALENCE (I,XX(20:20))
+ END
+
+GDB is free software and you are welcome to distribute copies of it
+ under certain conditions; type "show copying" to see the conditions.
+There is absolutely no warranty for GDB; type "show warranty" for details.
+GDB 4.16 (lm-gnits-dwim), Copyright 1996 Free Software Foundation, Inc...
+(gdb) b MAIN__
+Breakpoint 1 at 0t1200000201120112: file cd.f, line 5.
+(gdb) r
+Starting program: /home/user/a.out
+
+Breakpoint 1, MAIN__ () at cd.f:5
+Current language: auto; currently fortran
+(gdb) set language c
+Warning: the current language does not match this frame.
+(gdb) p a
+$2 = "At (COMMON) `x_' plus 0 bytes"
+(gdb) p b
+$3 = "At (COMMON) `x_' plus 4 bytes"
+(gdb) p c
+$4 = "At (EQUIVALENCE) `__g77_equiv_c' plus 0 bytes"
+(gdb) p d
+$5 = "At (EQUIVALENCE) `__g77_equiv_c' plus 0 bytes"
+(gdb) p i
+$6 = "At (EQUIVALENCE) `__g77_equiv_xx' plus 20 bytes"
+(gdb) p xx
+$7 = "At (EQUIVALENCE) `__g77_equiv_xx' plus 1 bytes"
+(gdb) set language fortran
+(gdb)
+@end smallexample
+
+@noindent
+Use @samp{-fdebug-kludge} to generate this information,
+which might make some programs noticeably larger.
+
+@emph{Caution:} Future versions of @code{g77} might disregard this option
+(and its negative form).
+Current plans call for this to happen when published versions of @code{g77}
+and @code{gdb} exist that provide proper access to debugging information on
+@code{COMMON} and @code{EQUIVALENCE} members.
+
+@cindex -fno-emulate-complex option
+@cindex options, -fno-emulate-complex
+@item -fno-emulate-complex
+Implement @code{COMPLEX} arithmetic using the facilities in
+the @code{gcc} back end that provide direct support of
+@code{complex} arithmetic, instead of emulating the arithmetic.
+
+@code{gcc} has some known problems in its back-end support
+for @code{complex} arithmetic, due primarily to the support not being
+completed as of version 2.7.2.2.
+Other front ends for the @code{gcc} back end avoid this problem
+by emulating @code{complex} arithmetic at a higher level, so the
+back end sees arithmetic on the real and imaginary components.
+To make @code{g77} more portable to systems where @code{complex}
+support in the @code{gcc} back end is particularly troublesome,
+@code{g77} now defaults to performing the same kinds of emulations
+done by these other front ends.
+
+Use @samp{-fno-emulate-complex} to try the @code{complex} support
+in the @code{gcc} back end, in case it works and produces faster
+programs.
+So far, all the known bugs seem to involve compile-time crashes,
+rather than the generation of incorrect code.
+
+Use of this option should not affect how Fortran code compiled
+by @code{g77} works in terms of its interfaces to other code,
+e.g. that compiled by @code{f2c}.
+
+@emph{Caution:} Future versions of @code{g77} are likely to change
+the default for this option to
+@samp{-fno-emulate-complex}, and perhaps someday ignore both forms
+of this option.
+
+Also, it is possible that use of the @samp{-fno-emulate-complex} option
+could result in incorrect code being silently produced by @code{g77}.
+But, this is generally true of compilers anyway, so, as usual, test
+the programs you compile before assuming they are working.
+
+@cindex -falias-check option
+@cindex options, -falias-check
+@cindex -fargument-alias option
+@cindex options, -fargument-alias
+@cindex -fargument-noalias option
+@cindex options, -fargument-noalias
+@cindex -fno-argument-noalias-global option
+@cindex options, -fno-argument-noalias-global
+@item -falias-check
+@item -fargument-alias
+@item -fargument-noalias
+@item -fno-argument-noalias-global
+@emph{Version info:}
+These options are not supported by
+versions of @code{g77} based on @code{gcc} version 2.8.
+
+These options specify to what degree aliasing
+(overlap)
+is permitted between
+arguments (passed as pointers) and @code{COMMON} (external, or
+public) storage.
+
+The default for Fortran code, as mandated by the FORTRAN 77 and
+Fortran 90 standards, is @samp{-fargument-noalias-global}.
+The default for code written in the C language family is
+@samp{-fargument-alias}.
+
+Note that, on some systems, compiling with @samp{-fforce-addr} in
+effect can produce more optimal code when the default aliasing
+options are in effect (and when optimization is enabled).
+
+@xref{Aliasing Assumed To Work}, for detailed information on the implications
+of compiling Fortran code that depends on the ability to alias dummy
+arguments.
+
+@cindex -fno-globals option
+@cindex options, -fno-globals
+@item -fno-globals
+@cindex global names, warning
+@cindex warnings, global names
+Disable diagnostics about inter-procedural
+analysis problems, such as disagreements about the
+type of a function or a procedure's argument,
+that might cause a compiler crash when attempting
+to inline a reference to a procedure within a
+program unit.
+(The diagnostics themselves are still produced, but
+as warnings, unless @samp{-Wno-globals} is specified,
+in which case no relevant diagnostics are produced.)
+
+Further, this option disables such inlining, to
+avoid compiler crashes resulting from incorrect
+code that would otherwise be diagnosed.
+
+As such, this option might be quite useful when
+compiling existing, ``working'' code that happens
+to have a few bugs that do not generally show
+themselves, but @code{g77} exposes via a
+diagnostic.
+
+Use of this option therefore has the effect of
+instructing @code{g77} to behave more like it did
+up through version 0.5.19.1, when it paid little or
+no attention to disagreements between program units
+about a procedure's type and argument information,
+and when it performed no inlining of procedures
+(except statement functions).
+
+Without this option, @code{g77} defaults to performing
+the potentially inlining procedures as it started doing
+in version 0.5.20, but as of version 0.5.21, it also
+diagnoses disagreements that might cause such inlining
+to crash the compiler.
+@end table
+
+@xref{Code Gen Options,,Options for Code Generation Conventions,
+gcc,Using and Porting GNU CC}, for information on more options
+offered by the GBE
+shared by @code{g77}, @code{gcc}, and other GNU compilers.
+
+Some of these do @emph{not} work when compiling programs written in Fortran:
+
+@table @code
+@cindex -fpcc-struct-return option
+@cindex options, -fpcc-struct-return
+@item -fpcc-struct-return
+@cindex -freg-struct-return option
+@cindex options, -freg-struct-return
+@item -freg-struct-return
+You should not use these except strictly the same way as you
+used them to build the version of @code{libg2c} with which
+you will be linking all code compiled by @code{g77} with the
+same option.
+
+@cindex -fshort-double option
+@cindex options, -fshort-double
+@item -fshort-double
+This probably either has no effect on Fortran programs, or
+makes them act loopy.
+
+@cindex -fno-common option
+@cindex options, -fno-common
+@item -fno-common
+Do not use this when compiling Fortran programs,
+or there will be Trouble.
+
+@cindex -fpack-struct option
+@cindex options, -fpack-struct
+@item -fpack-struct
+This probably will break any calls to the @code{libg2c} library,
+at the very least, even if it is built with the same option.
+@end table
+
+@node Environment Variables
+@section Environment Variables Affecting GNU Fortran
+@cindex environment variables
+
+GNU Fortran currently does not make use of any environment
+variables to control its operation above and beyond those
+that affect the operation of @code{gcc}.
+
+@xref{Environment Variables,,Environment Variables Affecting GNU CC,
+gcc,Using and Porting GNU CC}, for information on environment
+variables.
+
+@include news.texi
+
+@node Changes
+@chapter User-visible Changes
+@cindex versions, recent
+@cindex recent versions
+@cindex changes, user-visible
+@cindex user-visible changes
+
+This section describes changes to @code{g77} that are visible
+to the programmers who actually write and maintain Fortran
+code they compile with @code{g77}.
+Information on changes to installation procedures,
+changes to the documentation, and bug fixes is
+not provided here, unless it is likely to affect how
+users use @code{g77}.
+@xref{News,,News About GNU Fortran}, for information on
+such changes to @code{g77}.
+
+To find out about existing bugs and ongoing plans for GNU
+Fortran, retrieve @uref{ftp://alpha.gnu.org/g77.plan}
+or, if you cannot do that, email
+@email{fortran@@gnu.org} asking for a recent copy of the
+GNU Fortran @file{.plan} file.
+
+@heading In @code{egcs} 1.1 (versus 0.5.24):
+@itemize @bullet
+@cindex alignment
+@cindex double-precision performance
+@cindex -malign-double
+@item
+Align static double-precision variables and arrays
+on Intel x86 targets
+regardless of whether @samp{-malign-double} is specified.
+
+Generally, this affects only local variables and arrays
+having the @code{SAVE} attribute
+or given initial values via @code{DATA}.
+@end itemize
+
+@heading In @code{egcs} 1.1 (versus @code{egcs} 1.0.3):
+@itemize @bullet
+@item
+Support @samp{FORMAT(I<@var{expr}>)} when @var{expr} is a
+compile-time constant @code{INTEGER} expression.
+
+@item
+Fix @code{g77} @samp{-g} option so procedures that
+use @samp{ENTRY} can be stepped through, line by line,
+in @code{gdb}.
+
+@item
+Allow any @code{REAL} argument to intrinsics
+@code{Second} and @code{CPU_Time}.
+
+@item
+Use @code{tempnam}, if available, to open scratch files
+(as in @samp{OPEN(STATUS='SCRATCH')})
+so that the @code{TMPDIR} environment variable,
+if present, is used.
+
+@item
+@code{g77}'s version of @code{libf2c} separates out
+the setting of global state
+(such as command-line arguments and signal handling)
+from @file{main.o} into distinct, new library
+archive members.
+
+This should make it easier to write portable applications
+that have their own (non-Fortran) @code{main()} routine
+properly set up the @code{libf2c} environment, even
+when @code{libf2c} (now @code{libg2c}) is a shared library.
+
+@item
+The @code{g77} command now expects the run-time library
+to be named @code{libg2c.a} instead of @code{libf2c.a},
+to ensure that a version other than the one built and
+installed as part of the same @code{g77} version is picked up.
+
+@item
+Some diagnostics have been changed from warnings to errors,
+to prevent inadvertent use of the resulting, probably buggy,
+programs.
+These mostly include diagnostics about use of unsupported features
+in the @code{OPEN}, @code{INQUIRE}, @code{READ}, and
+@code{WRITE} statements,
+and about truncations of various sorts of constants.
+@end itemize
+
+@heading In 0.5.24 and @code{egcs} 1.1 (versus 0.5.23):
+@itemize @bullet
+@item
+@code{g77} now treats @samp{%LOC(@var{expr})} and
+@samp{LOC(@var{expr})} as ``ordinary'' expressions
+when they are used as arguments in procedure calls.
+This change applies only to global (filewide) analysis,
+making it consistent with
+how @code{g77} actually generates code
+for these cases.
+
+Previously, @code{g77} treated these expressions
+as denoting special ``pointer'' arguments
+for the purposes of filewide analysis.
+
+@item
+The @code{g77} driver now ensures that @samp{-lg2c}
+is specified in the link phase prior to any
+occurrence of @samp{-lm}.
+This prevents accidentally linking to a routine
+in the SunOS4 @samp{-lm} library
+when the generated code wants to link to the one
+in @code{libf2c} (@code{libg2c}).
+
+@item
+@code{g77} emits more debugging information when
+@samp{-g} is used.
+
+This new information allows, for example,
+@kbd{which __g77_length_a} to be used in @code{gdb}
+to determine the type of the phantom length argument
+supplied with @samp{CHARACTER} variables.
+
+This information pertains to internally-generated
+type, variable, and other information,
+not to the longstanding deficiencies vis-a-vis
+@samp{COMMON} and @samp{EQUIVALENCE}.
+
+@item
+The F90 @samp{Date_and_Time} intrinsic now is
+supported.
+
+@item
+The F90 @samp{System_Clock} intrinsic allows
+the optional arguments (except for the @samp{Count}
+argument) to be omitted.
+@end itemize
+
+@heading In 0.5.23:
+@itemize @bullet
+@item
+This release contains several regressions against
+version 0.5.22 of @code{g77}, due to using the
+``vanilla'' @code{gcc} back end instead of patching
+it to fix a few bugs and improve performance in a
+few cases.
+
+@xref{Actual Bugs,,Actual Bugs We Haven't Fixed Yet},
+available in plain-text format in @code{gcc/f/BUGS},
+for information on the known bugs in this version,
+including the regressions.
+
+Features that have been dropped from this version
+of @code{g77} due to their being implemented
+via @code{g77}-specific patches to the @code{gcc}
+back end in previous releases include:
+
+@itemize --
+@item
+Support for @code{__restrict__} keyword,
+the options @samp{-fargument-alias}, @samp{-fargument-noalias},
+and @samp{-fargument-noalias-global},
+and the corresponding alias-analysis code.
+
+(@code{egcs} has the alias-analysis
+code, but not the @code{__restrict__} keyword.
+@code{egcs} @code{g77} users benefit from the alias-analysis
+code despite the lack of the @code{__restrict__} keyword,
+which is a C-language construct.)
+
+@item
+Support for the GNU compiler options
+@samp{-fmove-all-movables},
+@samp{-freduce-all-givs},
+and @samp{-frerun-loop-opt}.
+
+(@code{egcs} supports these options.
+@code{g77} users of @code{egcs} benefit from them even if
+they are not explicitly specified,
+because the defaults are optimized for @code{g77} users.)
+
+@item
+Support for the @samp{-W} option warning about
+integer division by zero.
+
+@item
+The Intel x86-specific option @samp{-malign-double}
+applying to stack-allocated data
+as well as statically-allocate data.
+@end itemize
+
+@item
+Support @code{gcc} version 2.8,
+and remove support for prior versions of @code{gcc}.
+
+@cindex -@w{}-driver option
+@cindex g77 options, -@w{}-driver
+@cindex options, -@w{}-driver
+@item
+Remove support for the @samp{--driver} option,
+as @code{g77} now does all the driving,
+just like @code{gcc}.
+
+@item
+The @code{g77} command now expects the run-time library
+to be named @code{libg2c.a} instead of @code{libf2c.a},
+to ensure that a version other than the one built and
+installed as part of the same @code{g77} version is picked up.
+
+@item
+@code{g77}'s version of @code{libf2c} separates out
+the setting of global state
+(such as command-line arguments and signal handling)
+from @file{main.o} into distinct, new library
+archive members.
+
+This should make it easier to write portable applications
+that have their own (non-Fortran) @code{main()} routine
+properly set up the @code{libf2c} environment, even
+when @code{libf2c} (now @code{libg2c}) is a shared library.
+
+@item
+Some diagnostics have been changed from warnings to errors,
+to prevent inadvertent use of the resulting, probably buggy,
+programs.
+These mostly include diagnostics about use of unsupported features
+in the @code{OPEN}, @code{INQUIRE}, @code{READ}, and
+@code{WRITE} statements,
+and about truncations of various sorts of constants.
+@end itemize
+
+@heading In 0.5.22:
+@itemize @bullet
+@item
+Fix @code{Signal} intrinsic so it offers portable
+support for 64-bit systems (such as Digital Alphas
+running GNU/Linux).
+
+@item
+Support @samp{FORMAT(I<@var{expr}>)} when @var{expr} is a
+compile-time constant @code{INTEGER} expression.
+
+@item
+Fix @code{g77} @samp{-g} option so procedures that
+use @samp{ENTRY} can be stepped through, line by line,
+in @code{gdb}.
+
+@item
+Allow any @code{REAL} argument to intrinsics
+@code{Second} and @code{CPU_Time}.
+
+@item
+Allow any numeric argument to intrinsics
+@code{Int2} and @code{Int8}.
+
+@item
+Use @code{tempnam}, if available, to open scratch files
+(as in @samp{OPEN(STATUS='SCRATCH')})
+so that the @code{TMPDIR} environment variable,
+if present, is used.
+
+@item
+Rename the @code{gcc} keyword @code{restrict} to
+@code{__restrict__}, to avoid rejecting valid, existing,
+C programs.
+Support for @code{restrict} is now more like support
+for @code{complex}.
+
+@item
+Fix @samp{-fugly-comma} to affect invocations of
+only external procedures.
+Restore rejection of gratuitous trailing omitted
+arguments to intrinsics, as in @samp{I=MAX(3,4,,)}.
+
+@item
+Fix compiler so it accepts @samp{-fgnu-intrinsics-*} and
+@samp{-fbadu77-intrinsics-*} options.
+@end itemize
+
+@heading In @code{egcs} 1.0.2 (versus @code{egcs} 1.0.1):
+@itemize @bullet
+@item
+Fix compiler so it accepts @samp{-fgnu-intrinsics-*} and
+@samp{-fbadu77-intrinsics-*} options.
+@end itemize
+
+@heading In @code{egcs} 1.0 (versus 0.5.21):
+@itemize @bullet
+@item
+Version 1.0 of @code{egcs}
+contains several regressions against
+version 0.5.21 of @code{g77},
+due to using the
+``vanilla'' @code{gcc} back end instead of patching
+it to fix a few bugs and improve performance in a
+few cases.
+
+@xref{Actual Bugs,,Actual Bugs We Haven't Fixed Yet},
+available in plain-text format in @code{gcc/f/BUGS},
+for information on the known bugs in this version,
+including the regressions.
+
+Features that have been dropped from this version
+of @code{g77} due to their being implemented
+via @code{g77}-specific patches to the @code{gcc}
+back end in previous releases include:
+
+@itemize --
+@item
+Support for the C-language @code{restrict} keyword.
+
+@item
+Support for the @samp{-W} option warning about
+integer division by zero.
+
+@item
+The Intel x86-specific option @samp{-malign-double}
+applying to stack-allocated data
+as well as statically-allocate data.
+@end itemize
+
+@cindex -@w{}-driver option
+@cindex g77 options, -@w{}-driver
+@cindex options, -@w{}-driver
+@item
+Remove support for the @samp{--driver} option,
+as @code{g77} now does all the driving,
+just like @code{gcc}.
+
+@item
+Allow any numeric argument to intrinsics
+@code{Int2} and @code{Int8}.
+@end itemize
+
+@heading In 0.5.21:
+@itemize @bullet
+@item
+When the @samp{-W} option is specified, @code{gcc}, @code{g77},
+and other GNU compilers that incorporate the @code{gcc}
+back end as modified by @code{g77}, issue
+a warning about integer division by constant zero.
+
+@item
+New option @samp{-Wno-globals} disables warnings
+about ``suspicious'' use of a name both as a global
+name and as the implicit name of an intrinsic, and
+warnings about disagreements over the number or natures of
+arguments passed to global procedures, or the
+natures of the procedures themselves.
+
+The default is to issue such warnings, which are
+new as of this version of @code{g77}.
+
+@item
+New option @samp{-fno-globals} disables diagnostics
+about potentially fatal disagreements
+analysis problems, such as disagreements over the
+number or natures of arguments passed to global
+procedures, or the natures of those procedures themselves.
+
+The default is to issue such diagnostics and flag
+the compilation as unsuccessful.
+With this option, the diagnostics are issued as
+warnings, or, if @samp{-Wno-globals} is specified,
+are not issued at all.
+
+This option also disables inlining of global procedures,
+to avoid compiler crashes resulting from coding errors
+that these diagnostics normally would identify.
+
+@item
+Fix @code{libU77} routines that accept file and other names
+to strip trailing blanks from them, for consistency
+with other implementations.
+Blanks may be forcibly appended to such names by
+appending a single null character (@samp{CHAR(0)})
+to the significant trailing blanks.
+
+@item
+Fix @code{CHMOD} intrinsic to work with file names
+that have embedded blanks, commas, and so on.
+
+@item
+Fix @code{SIGNAL} intrinsic so it accepts an
+optional third @samp{Status} argument.
+
+@item
+Make many changes to @code{libU77} intrinsics to
+support existing code more directly.
+
+Such changes include allowing both subroutine and
+function forms of many routines, changing @code{MCLOCK()}
+and @code{TIME()} to return @code{INTEGER(KIND=1)} values,
+introducing @code{MCLOCK8()} and @code{TIME8()} to
+return @code{INTEGER(KIND=2)} values,
+and placing functions that are intended to perform
+side effects in a new intrinsic group, @code{badu77}.
+
+@item
+Add options @samp{-fbadu77-intrinsics-delete},
+@samp{-fbadu77-intrinsics-hide}, and so on.
+
+@item
+Add @code{INT2} and @code{INT8} intrinsics.
+
+@item
+Add @code{CPU_TIME} intrinsic.
+
+@item
+Add @code{ALARM} intrinsic.
+
+@item
+@code{CTIME} intrinsic now accepts any @code{INTEGER}
+argument, not just @code{INTEGER(KIND=2)}.
+
+@item
+@code{g77} driver now prints version information (such as produced
+by @kbd{g77 -v}) to @code{stderr} instead of @code{stdout}.
+
+@item
+The @samp{.r} suffix now designates a Ratfor source file,
+to be preprocessed via the @code{ratfor} command, available
+separately.
+@end itemize
+
+@heading In 0.5.20:
+@itemize @bullet
+@item
+The @samp{-fno-typeless-boz} option is now the default.
+
+This option specifies that non-decimal-radix
+constants using the prefixed-radix form (such as @samp{Z'1234'})
+are to be interpreted as @code{INTEGER(KIND=1)} constants.
+Specify @samp{-ftypeless-boz} to cause such
+constants to be interpreted as typeless.
+
+(Version 0.5.19 introduced @samp{-fno-typeless-boz} and
+its inverse.)
+
+@xref{Fortran Dialect Options,,Options Controlling Fortran Dialect},
+for information on the @samp{-ftypeless-boz} option.
+
+@item
+Options @samp{-ff90-intrinsics-enable} and
+@samp{-fvxt-intrinsics-enable} now are the
+defaults.
+
+Some programs might use names that clash with
+intrinsic names defined (and now enabled) by these
+options or by the new @code{libU77} intrinsics.
+Users of such programs might need to compile them
+differently (using, for example, @samp{-ff90-intrinsics-disable})
+or, better yet, insert appropriate @code{EXTERNAL}
+statements specifying that these names are not intended
+to be names of intrinsics.
+
+@item
+The @samp{ALWAYS_FLUSH} macro is no longer defined when
+building @code{libf2c}, which should result in improved
+I/O performance, especially over NFS.
+
+@emph{Note:} If you have code that depends on the behavior
+of @code{libf2c} when built with @samp{ALWAYS_FLUSH} defined,
+you will have to modify @code{libf2c} accordingly before
+building it from this and future versions of @code{g77}.
+
+@xref{Output Assumed To Flush}, for more information.
+
+@item
+Dave Love's implementation of @code{libU77} has been
+added to the version of @code{libf2c} distributed with
+and built as part of @code{g77}.
+@code{g77} now knows about the routines in this library
+as intrinsics.
+
+@item
+New option @samp{-fvxt} specifies that the
+source file is written in VXT Fortran, instead of GNU Fortran.
+
+@xref{VXT Fortran}, for more information on the constructs
+recognized when the @samp{-fvxt} option is specified.
+
+@item
+The @samp{-fvxt-not-f90} option has been deleted,
+along with its inverse, @samp{-ff90-not-vxt}.
+
+If you used one of these deleted options, you should
+re-read the pertinent documentation to determine which
+options, if any, are appropriate for compiling your
+code with this version of @code{g77}.
+
+@xref{Other Dialects}, for more information.
+
+@item
+The @samp{-fugly} option now issues a warning, as it
+likely will be removed in a future version.
+
+(Enabling all the @samp{-fugly-*} options is unlikely
+to be feasible, or sensible, in the future,
+so users should learn to specify only those
+@samp{-fugly-*} options they really need for a
+particular source file.)
+
+@item
+The @samp{-fugly-assumed} option, introduced in
+version 0.5.19, has been changed to
+better accommodate old and new code.
+@xref{Ugly Assumed-Size Arrays}, for more information.
+
+@item
+Related to supporting Alpha (AXP) machines, the @code{LOC()}
+intrinsic and @code{%LOC()} construct now return
+values of @code{INTEGER(KIND=0)} type,
+as defined by the GNU Fortran language.
+
+This type is wide enough
+(holds the same number of bits)
+as the character-pointer type on the machine.
+
+On most machines, this won't make a difference,
+whereas, on Alphas and other systems with 64-bit pointers,
+the @code{INTEGER(KIND=0)} type is equivalent to @code{INTEGER(KIND=2)}
+(often referred to as @code{INTEGER*8})
+instead of the more common @code{INTEGER(KIND=1)}
+(often referred to as @code{INTEGER*4}).
+
+@item
+Emulate @code{COMPLEX} arithmetic in the @code{g77} front
+end, to avoid bugs in @code{complex} support in the
+@code{gcc} back end.
+New option @samp{-fno-emulate-complex}
+causes @code{g77} to revert the 0.5.19 behavior.
+
+@item
+Dummy arguments are no longer assumed to potentially alias
+(overlap)
+other dummy arguments or @code{COMMON} areas when any of
+these are defined (assigned to) by Fortran code.
+
+This can result in faster and/or smaller programs when
+compiling with optimization enabled, though on some
+systems this effect is observed only when @samp{-fforce-addr}
+also is specified.
+
+New options @samp{-falias-check}, @samp{-fargument-alias},
+@samp{-fargument-noalias},
+and @samp{-fno-argument-noalias-global} control the
+way @code{g77} handles potential aliasing.
+
+@xref{Aliasing Assumed To Work}, for detailed information on why the
+new defaults might result in some programs no longer working the way they
+did when compiled by previous versions of @code{g77}.
+
+@item
+New option @samp{-fugly-assign} specifies that the
+same memory locations are to be used to hold the
+values assigned by both statements @samp{I = 3} and
+@samp{ASSIGN 10 TO I}, for example.
+(Normally, @code{g77} uses a separate memory location
+to hold assigned statement labels.)
+
+@xref{Ugly Assigned Labels}, for more information.
+
+@item
+@code{FORMAT} and @code{ENTRY} statements now are allowed to
+precede @code{IMPLICIT NONE} statements.
+
+@item
+Enable full support of @code{INTEGER(KIND=2)}
+(often referred to as @code{INTEGER*8})
+available in
+@code{libf2c} and @file{f2c.h} so that @code{f2c} users
+may make full use of its features via the @code{g77}
+version of @file{f2c.h} and the @code{INTEGER(KIND=2)}
+support routines in the @code{g77} version of @code{libf2c}.
+
+@item
+Improve @code{g77} driver and @code{libf2c} so that @samp{g77 -v}
+yields version information on the library.
+
+@item
+The @code{SNGL} and @code{FLOAT} intrinsics now are
+specific intrinsics, instead of synonyms for the
+generic intrinsic @code{REAL}.
+
+@item
+New intrinsics have been added.
+These are @code{REALPART}, @code{IMAGPART},
+@code{COMPLEX},
+@code{LONG}, and @code{SHORT}.
+
+@item
+A new group of intrinsics, @samp{gnu}, has been added
+to contain the new @code{REALPART}, @code{IMAGPART},
+and @code{COMPLEX} intrinsics.
+An old group, @samp{dcp}, has been removed.
+
+@item
+Complain about industry-wide ambiguous references
+@samp{REAL(@var{expr})} and @samp{AIMAG(@var{expr})},
+where @var{expr} is @code{DOUBLE COMPLEX} (or any
+complex type other than @code{COMPLEX}), unless
+@samp{-ff90} option specifies Fortran 90 interpretation
+or new @samp{-fugly-complex} option, in conjunction with
+@samp{-fnot-f90}, specifies @code{f2c} interpretation.
+@end itemize
+
+@heading In 0.5.19:
+
+@itemize @bullet
+@item
+A temporary kludge option provides bare-bones information on
+@code{COMMON} and @code{EQUIVALENCE} members at debug time.
+@xref{Code Gen Options,,Options for Code Generation Conventions},
+for information on the @samp{-fdebug-kludge} option.
+
+@item
+New @samp{-fonetrip} option specifies FORTRAN-66-style
+one-trip @code{DO} loops.
+
+@item
+New @samp{-fno-silent} option causes names of program units
+to be printed as they are compiled, in a fashion similar to
+UNIX @code{f77} and @code{f2c}.
+
+@item
+New @samp{-fugly-assumed} option specifies that arrays
+dimensioned via @samp{DIMENSION X(1)}, for example, are to be
+treated as assumed-size.
+
+@item
+New @samp{-fno-typeless-boz} option specifies that non-decimal-radix
+constants using the prefixed-radix form (such as @samp{Z'1234'})
+are to be interpreted as @code{INTEGER(KIND=1)} constants.
+
+@item
+New @samp{-ff66} option is a ``shorthand'' option that specifies
+behaviors considered appropriate for FORTRAN 66 programs.
+
+@item
+New @samp{-ff77} option is a ``shorthand'' option that specifies
+behaviors considered appropriate for UNIX @code{f77} programs.
+
+@item
+New @samp{-fugly-comma} and @samp{-fugly-logint} options provided
+to perform some of what @samp{-fugly} used to do.
+@samp{-fugly} and @samp{-fno-ugly} are now ``shorthand'' options,
+in that they do nothing more than enable (or disable) other
+@samp{-fugly-*} options.
+
+@item
+Change code generation for list-directed I/O so it allows
+for new versions of @code{libf2c} that might return non-zero
+status codes for some operations previously assumed to always
+return zero.
+
+This change not only affects how @code{IOSTAT=} variables
+are set by list-directed I/O, it also affects whether
+@code{END=} and @code{ERR=} labels are reached by these
+operations.
+
+@item
+Add intrinsic support for new @code{FTELL} and @code{FSEEK}
+procedures in @code{libf2c}.
+
+@item
+Add options @samp{--help} and @samp{--version} to the
+@code{g77} command, to conform to GNU coding guidelines.
+Also add printing of @code{g77} version number when
+the @samp{--verbose} (@samp{-v}) option is used.
+@end itemize
+
+@heading In 0.5.18:
+
+@itemize @bullet
+@item
+The @code{BYTE} and @code{WORD} statements now are supported,
+to a limited extent.
+
+@item
+@code{INTEGER*1}, @code{INTEGER*2}, @code{INTEGER*8},
+and their @code{LOGICAL}
+equivalents, now are supported to a limited extent.
+Among the missing elements are complete intrinsic and constant
+support.
+
+@item
+Support automatic arrays in procedures.
+For example, @samp{REAL A(N)}, where @samp{A} is
+not a dummy argument, specifies that @samp{A} is
+an automatic array.
+The size of @samp{A} is calculated from the value
+of @samp{N} each time the procedure is called,
+that amount of space is allocated, and that space
+is freed when the procedure returns to its caller.
+
+@item
+Add @samp{-fno-zeros} option, enabled by default,
+to reduce compile-time CPU and memory usage for
+code that provides initial zero values for variables
+and arrays.
+
+@item
+Introduce three new options that apply to all compilations
+by @code{g77}-aware GNU compilers---@samp{-fmove-all-movables},
+@samp{-freduce-all-givs}, and @samp{-frerun-loop-opt}---which
+can improve the run-time performance of some programs.
+
+@item
+Replace much of the existing documentation with a single
+Info document.
+
+@item
+New option @samp{-fno-second-underscore}.
+@end itemize
+
+@heading In 0.5.17:
+
+@itemize @bullet
+@item
+The @code{ERF()} and @code{ERFC()} intrinsics now are generic
+intrinsics, mapping to @code{ERF}/@code{DERF} and
+@code{ERFC}/@code{DERFC}, respectively.
+@emph{Note:} Use @samp{INTRINSIC ERF,ERFC} in any code that
+might reference these as generic intrinsics, to
+improve the likelihood of diagnostics (instead of subtle run-time
+bugs) when using compilers that don't support these as intrinsics.
+
+@item
+New option @samp{-Wsurprising}.
+
+@item
+DO loops with non-@code{INTEGER} variables now diagnosed only when
+@samp{-Wsurprising} specified.
+Previously, this was diagnosed @emph{unless} @samp{-fpedantic} or
+@samp{-fugly} was specified.
+@end itemize
+
+@heading In 0.5.16:
+
+@itemize @bullet
+@item
+@code{libf2c} changed to output a leading zero (0) digit for floating-point
+values output via list-directed and formatted output (to bring @code{g77}
+more into line with many existing Fortran implementations---the
+ANSI FORTRAN 77 standard leaves this choice to the implementation).
+
+@item
+@code{libf2c} no longer built with debugging information
+intact, making it much smaller.
+
+@item
+Automatic installation of the @code{g77} command now works.
+
+@item
+Diagnostic messages now more informative, a la @code{gcc},
+including messages like @samp{In function `foo':} and @samp{In file
+included from...:}.
+
+@item
+New group of intrinsics called @samp{unix}, including @code{ABORT},
+@code{DERF}, @code{DERFC}, @code{ERF}, @code{ERFC}, @code{EXIT},
+@code{FLUSH}, @code{GETARG}, @code{GETENV}, @code{SIGNAL}, and
+@code{SYSTEM}.
+
+@item
+@samp{-funix-intrinsics-@{delete,hide,disable,enable@}}
+options added.
+
+@item
+@samp{-fno-underscoring} option added.
+
+@item
+@samp{--driver} option added to the @code{g77} command.
+
+@item
+Support for the @code{gcc} options @samp{-fident} and @samp{-fno-ident}
+added.
+
+@item
+@samp{g77 -v} returns much more version info, making the submission
+of better bug reports easily.
+
+@item
+Many improvements to the @code{g77} command to better fulfill its role as
+a front-end to the @code{gcc} driver.
+For example, @code{g77} now
+recognizes @samp{--verbose} as a verbose way of specifying @samp{-v}.
+
+@item
+Compiling preprocessed (@file{*.F} and @file{*.fpp}) files now
+results in better diagnostics and debugging information, as the
+source-location info now is passed all the
+way through the compilation process instead of being lost.
+@end itemize
+
+@node Language
+@chapter The GNU Fortran Language
+
+@cindex standard, ANSI FORTRAN 77
+@cindex ANSI FORTRAN 77 standard
+@cindex reference works
+GNU Fortran supports a variety of extensions to, and dialects
+of, the Fortran language.
+Its primary base is the ANSI FORTRAN 77 standard, currently available on
+the network at
+@uref{http://www.fortran.com/fortran/F77_std/rjcnf0001.html}
+or as monolithic text at
+@uref{http://www.fortran.com/fortran/F77_std/f77_std.html}.
+It offers some extensions that are popular among users
+of UNIX @code{f77} and @code{f2c} compilers, some that
+are popular among users of other compilers (such as Digital
+products), some that are popular among users of the
+newer Fortran 90 standard, and some that are introduced
+by GNU Fortran.
+
+@cindex textbooks
+(If you need a text on Fortran,
+a few freely available electronic references have pointers from
+@uref{http://www.fortran.com/fortran/Books/}. There is a `cooperative
+net project', @cite{User Notes on Fortran Programming} at
+@uref{ftp://vms.huji.ac.il/fortran/} and mirrors elsewhere; some of this
+material might not apply specifically to @code{g77}.)
+
+Part of what defines a particular implementation of a Fortran
+system, such as @code{g77}, is the particular characteristics
+of how it supports types, constants, and so on.
+Much of this is left up to the implementation by the various
+Fortran standards and accepted practice in the industry.
+
+The GNU Fortran @emph{language} is described below.
+Much of the material is organized along the same lines
+as the ANSI FORTRAN 77 standard itself.
+
+@xref{Other Dialects}, for information on features @code{g77} supports
+that are not part of the GNU Fortran language.
+
+@emph{Note}: This portion of the documentation definitely needs a lot
+of work!
+
+@menu
+Relationship to the ANSI FORTRAN 77 standard:
+* Direction of Language Development:: Where GNU Fortran is headed.
+* Standard Support:: Degree of support for the standard.
+
+Extensions to the ANSI FORTRAN 77 standard:
+* Conformance::
+* Notation Used::
+* Terms and Concepts::
+* Characters Lines Sequence::
+* Data Types and Constants::
+* Expressions::
+* Specification Statements::
+* Control Statements::
+* Functions and Subroutines::
+* Scope and Classes of Names::
+* I/O::
+* Fortran 90 Features::
+@end menu
+
+@node Direction of Language Development
+@section Direction of Language Development
+@cindex direction of language development
+@cindex features, language
+@cindex language features
+
+The purpose of the following description of the GNU Fortran
+language is to promote wide portability of GNU Fortran programs.
+
+GNU Fortran is an evolving language, due to the
+fact that @code{g77} itself is in beta test.
+Some current features of the language might later
+be redefined as dialects of Fortran supported by @code{g77}
+when better ways to express these features are added to @code{g77},
+for example.
+Such features would still be supported by
+@code{g77}, but would be available only when
+one or more command-line options were used.
+
+The GNU Fortran @emph{language} is distinct from the
+GNU Fortran @emph{compilation system} (@code{g77}).
+
+For example, @code{g77} supports various dialects of
+Fortran---in a sense, these are languages other than
+GNU Fortran---though its primary
+purpose is to support the GNU Fortran language, which also is
+described in its documentation and by its implementation.
+
+On the other hand, non-GNU compilers might offer
+support for the GNU Fortran language, and are encouraged
+to do so.
+
+Currently, the GNU Fortran language is a fairly fuzzy object.
+It represents something of a cross between what @code{g77} accepts
+when compiling using the prevailing defaults and what this
+document describes as being part of the language.
+
+Future versions of @code{g77} are expected to clarify the
+definition of the language in the documentation.
+Often, this will mean adding new features to the language, in the form
+of both new documentation and new support in @code{g77}.
+However, it might occasionally mean removing a feature
+from the language itself to ``dialect'' status.
+In such a case, the documentation would be adjusted
+to reflect the change, and @code{g77} itself would likely be changed
+to require one or more command-line options to continue supporting
+the feature.
+
+The development of the GNU Fortran language is intended to strike
+a balance between:
+
+@itemize @bullet
+@item
+Serving as a mostly-upwards-compatible language from the
+de facto UNIX Fortran dialect as supported by @code{f77}.
+
+@item
+Offering new, well-designed language features.
+Attributes of such features include
+not making existing code any harder to read
+(for those who might be unaware that the new
+features are not in use) and
+not making state-of-the-art
+compilers take longer to issue diagnostics,
+among others.
+
+@item
+Supporting existing, well-written code without gratuitously
+rejecting non-standard constructs, regardless of the origin
+of the code (its dialect).
+
+@item
+Offering default behavior and command-line options to reduce
+and, where reasonable, eliminate the need for programmers to make
+any modifications to code that already works in existing
+production environments.
+
+@item
+Diagnosing constructs that have different meanings in different
+systems, languages, and dialects, while offering clear,
+less ambiguous ways to express each of the different meanings
+so programmers can change their code appropriately.
+@end itemize
+
+One of the biggest practical challenges for the developers of the
+GNU Fortran language is meeting the sometimes contradictory demands
+of the above items.
+
+For example, a feature might be widely used in one popular environment,
+but the exact same code that utilizes that feature might not work
+as expected---perhaps it might mean something entirely different---in
+another popular environment.
+
+Traditionally, Fortran compilers---even portable ones---have solved this
+problem by simply offering the appropriate feature to users of
+the respective systems.
+This approach treats users of various Fortran systems and dialects
+as remote ``islands'', or camps, of programmers, and assume that these
+camps rarely come into contact with each other (or,
+especially, with each other's code).
+
+Project GNU takes a radically different approach to software and language
+design, in that it assumes that users of GNU software do not necessarily
+care what kind of underlying system they are using, regardless
+of whether they are using software (at the user-interface
+level) or writing it (for example, writing Fortran or C code).
+
+As such, GNU users rarely need consider just what kind of underlying
+hardware (or, in many cases, operating system) they are using at any
+particular time.
+They can use and write software designed for a general-purpose,
+widely portable, heterogenous environment---the GNU environment.
+
+In line with this philosophy, GNU Fortran must evolve into a product
+that is widely ported and portable not only in the sense that it can
+be successfully built, installed, and run by users, but in the larger
+sense that its users can use it in the same way, and expect largely the
+same behaviors from it, regardless of the kind of system they are using
+at any particular time.
+
+This approach constrains the solutions @code{g77} can use to resolve
+conflicts between various camps of Fortran users.
+If these two camps disagree about what a particular construct should
+mean, @code{g77} cannot simply be changed to treat that particular construct as
+having one meaning without comment (such as a warning), lest the users
+expecting it to have the other meaning are unpleasantly surprised that
+their code misbehaves when executed.
+
+The use of the ASCII backslash character in character constants is
+an excellent (and still somewhat unresolved) example of this kind of
+controversy.
+@xref{Backslash in Constants}.
+Other examples are likely to arise in the future, as @code{g77} developers
+strive to improve its ability to accept an ever-wider variety of existing
+Fortran code without requiring significant modifications to said code.
+
+Development of GNU Fortran is further constrained by the desire
+to avoid requiring programmers to change their code.
+This is important because it allows programmers, administrators,
+and others to more faithfully evaluate and validate @code{g77}
+(as an overall product and as new versions are distributed)
+without having to support multiple versions of their programs
+so that they continue to work the same way on their existing
+systems (non-GNU perhaps, but possibly also earlier versions
+of @code{g77}).
+
+@node Standard Support
+@section ANSI FORTRAN 77 Standard Support
+@cindex ANSI FORTRAN 77 support
+@cindex standard support
+@cindex support for ANSI FORTRAN 77
+@cindex compatibility, FORTRAN 77
+@cindex FORTRAN 77 compatibility
+
+GNU Fortran supports ANSI FORTRAN 77 with the following caveats.
+In summary, the only ANSI FORTRAN 77 features @code{g77} doesn't
+support are those that are probably rarely used in actual code,
+some of which are explicitly disallowed by the Fortran 90 standard.
+
+@menu
+* No Passing External Assumed-length:: CHAR*(*) CFUNC restriction.
+* No Passing Dummy Assumed-length:: CHAR*(*) CFUNC restriction.
+* No Pathological Implied-DO:: No @samp{((@dots{}, I=@dots{}), I=@dots{})}.
+* No Useless Implied-DO:: No @samp{(A, I=1, 1)}.
+@end menu
+
+@node No Passing External Assumed-length
+@subsection No Passing External Assumed-length
+
+@code{g77} disallows passing of an external procedure
+as an actual argument if the procedure's
+type is declared @code{CHARACTER*(*)}. For example:
+
+@example
+CHARACTER*(*) CFUNC
+EXTERNAL CFUNC
+CALL FOO(CFUNC)
+END
+@end example
+
+@noindent
+It isn't clear whether the standard considers this conforming.
+
+@node No Passing Dummy Assumed-length
+@subsection No Passing Dummy Assumed-length
+
+@code{g77} disallows passing of a dummy procedure
+as an actual argument if the procedure's
+type is declared @code{CHARACTER*(*)}.
+
+@example
+SUBROUTINE BAR(CFUNC)
+CHARACTER*(*) CFUNC
+EXTERNAL CFUNC
+CALL FOO(CFUNC)
+END
+@end example
+
+@noindent
+It isn't clear whether the standard considers this conforming.
+
+@node No Pathological Implied-DO
+@subsection No Pathological Implied-DO
+
+The @code{DO} variable for an implied-@code{DO} construct in a
+@code{DATA} statement may not be used as the @code{DO} variable
+for an outer implied-@code{DO} construct. For example, this
+fragment is disallowed by @code{g77}:
+
+@smallexample
+DATA ((A(I, I), I= 1, 10), I= 1, 10) /@dots{}/
+@end smallexample
+
+@noindent
+This also is disallowed by Fortran 90, as it offers no additional
+capabilities and would have a variety of possible meanings.
+
+Note that it is @emph{very} unlikely that any production Fortran code
+tries to use this unsupported construct.
+
+@node No Useless Implied-DO
+@subsection No Useless Implied-DO
+
+An array element initializer in an implied-@code{DO} construct in a
+@code{DATA} statement must contain at least one reference to the @code{DO}
+variables of each outer implied-@code{DO} construct. For example,
+this fragment is disallowed by @code{g77}:
+
+@smallexample
+DATA (A, I= 1, 1) /1./
+@end smallexample
+
+@noindent
+This also is disallowed by Fortran 90, as FORTRAN 77's more permissive
+requirements offer no additional capabilities.
+However, @code{g77} doesn't necessarily diagnose all cases
+where this requirement is not met.
+
+Note that it is @emph{very} unlikely that any production Fortran code
+tries to use this unsupported construct.
+
+@node Conformance
+@section Conformance
+
+(The following information augments or overrides the information in
+Section 1.4 of ANSI X3.9-1978 FORTRAN 77 in specifying the GNU Fortran
+language.
+Chapter 1 of that document otherwise serves as the basis
+for the relevant aspects of GNU Fortran.)
+
+The definition of the GNU Fortran language is akin to that of
+the ANSI FORTRAN 77 language in that it does not generally require
+conforming implementations to diagnose cases where programs do
+not conform to the language.
+
+However, @code{g77} as a compiler is being developed in a way that
+is intended to enable it to diagnose such cases in an easy-to-understand
+manner.
+
+A program that conforms to the GNU Fortran language should, when
+compiled, linked, and executed using a properly installed @code{g77}
+system, perform as described by the GNU Fortran language definition.
+Reasons for different behavior include, among others:
+
+@itemize @bullet
+@item
+Use of resources (memory---heap, stack, and so on; disk space; CPU
+time; etc.) exceeds those of the system.
+
+@item
+Range and/or precision of calculations required by the program
+exceeds that of the system.
+
+@item
+Excessive reliance on behaviors that are system-dependent
+(non-portable Fortran code).
+
+@item
+Bugs in the program.
+
+@item
+Bug in @code{g77}.
+
+@item
+Bugs in the system.
+@end itemize
+
+Despite these ``loopholes'', the availability of a clear specification
+of the language of programs submitted to @code{g77}, as this document
+is intended to provide, is considered an important aspect of providing
+a robust, clean, predictable Fortran implementation.
+
+The definition of the GNU Fortran language, while having no special
+legal status, can therefore be viewed as a sort of contract, or agreement.
+This agreement says, in essence, ``if you write a program in this language,
+and run it in an environment (such as a @code{g77} system) that supports
+this language, the program should behave in a largely predictable way''.
+
+@node Notation Used
+@section Notation Used in This Chapter
+
+(The following information augments or overrides the information in
+Section 1.5 of ANSI X3.9-1978 FORTRAN 77 in specifying the GNU Fortran
+language.
+Chapter 1 of that document otherwise serves as the basis
+for the relevant aspects of GNU Fortran.)
+
+In this chapter, ``must'' denotes a requirement, ``may'' denotes permission,
+and ``must not'' and ``may not'' denote prohibition.
+Terms such as ``might'', ``should'', and ``can'' generally add little or
+nothing in the way of weight to the GNU Fortran language itself,
+but are used to explain or illustrate the language.
+
+For example:
+
+@display
+``The @code{FROBNITZ} statement must precede all executable
+statements in a program unit, and may not specify any dummy
+arguments. It may specify local or common variables and arrays.
+Its use should be limited to portions of the program designed to
+be non-portable and system-specific, because it might cause the
+containing program unit to behave quite differently on different
+systems.''
+@end display
+
+Insofar as the GNU Fortran language is specified,
+the requirements and permissions denoted by the above sample statement
+are limited to the placement of the statement and the kinds of
+things it may specify.
+The rest of the statement---the content regarding non-portable portions
+of the program and the differing behavior of program units containing
+the @code{FROBNITZ} statement---does not pertain the GNU Fortran
+language itself.
+That content offers advice and warnings about the @code{FROBNITZ}
+statement.
+
+@emph{Remember:} The GNU Fortran language definition specifies
+both what constitutes a valid GNU Fortran program and how,
+given such a program, a valid GNU Fortran implementation is
+to interpret that program.
+
+It is @emph{not} incumbent upon a valid GNU Fortran implementation
+to behave in any particular way, any consistent way, or any
+predictable way when it is asked to interpret input that is
+@emph{not} a valid GNU Fortran program.
+
+Such input is said to have @dfn{undefined} behavior when
+interpreted by a valid GNU Fortran implementation, though
+an implementation may choose to specify behaviors for some
+cases of inputs that are not valid GNU Fortran programs.
+
+Other notation used herein is that of the GNU texinfo format,
+which is used to generate printed hardcopy, on-line hypertext
+(Info), and on-line HTML versions, all from a single source
+document.
+This notation is used as follows:
+
+@itemize @bullet
+@item
+Keywords defined by the GNU Fortran language are shown
+in uppercase, as in: @code{COMMON}, @code{INTEGER}, and
+@code{BLOCK DATA}.
+
+Note that, in practice, many Fortran programs are written
+in lowercase---uppercase is used in this manual as a
+means to readily distinguish keywords and sample Fortran-related
+text from the prose in this document.
+
+@item
+Portions of actual sample program, input, or output text
+look like this: @samp{Actual program text}.
+
+Generally, uppercase is used for all Fortran-specific and
+Fortran-related text, though this does not always include
+literal text within Fortran code.
+
+For example: @samp{PRINT *, 'My name is Bob'}.
+
+@item
+A metasyntactic variable---that is, a name used in this document
+to serve as a placeholder for whatever text is used by the
+user or programmer--appears as shown in the following example:
+
+``The @code{INTEGER @var{ivar}} statement specifies that
+@var{ivar} is a variable or array of type @code{INTEGER}.''
+
+In the above example, any valid text may be substituted for
+the metasyntactic variable @var{ivar} to make the statement
+apply to a specific instance, as long as the same text is
+substituted for @emph{both} occurrences of @var{ivar}.
+
+@item
+Ellipses (``@dots{}'') are used to indicate further text that
+is either unimportant or expanded upon further, elsewhere.
+
+@item
+Names of data types are in the style of Fortran 90, in most
+cases.
+
+@xref{Kind Notation}, for information on the relationship
+between Fortran 90 nomenclature (such as @code{INTEGER(KIND=1)})
+and the more traditional, less portably concise nomenclature
+(such as @code{INTEGER*4}).
+@end itemize
+
+@node Terms and Concepts
+@section Fortran Terms and Concepts
+
+(The following information augments or overrides the information in
+Chapter 2 of ANSI X3.9-1978 FORTRAN 77 in specifying the GNU Fortran
+language.
+Chapter 2 of that document otherwise serves as the basis
+for the relevant aspects of GNU Fortran.)
+
+@menu
+* Syntactic Items::
+* Statements Comments Lines::
+* Scope of Names and Labels::
+@end menu
+
+@node Syntactic Items
+@subsection Syntactic Items
+
+(Corresponds to Section 2.2 of ANSI X3.9-1978 FORTRAN 77.)
+
+In GNU Fortran, a symbolic name is at least one character long,
+and has no arbitrary upper limit on length.
+However, names of entities requiring external linkage (such as
+external functions, external subroutines, and @code{COMMON} areas)
+might be restricted to some arbitrary length by the system.
+Such a restriction is no more constrained than that of one
+through six characters.
+
+Underscores (@samp{_}) are accepted in symbol names after the first
+character (which must be a letter).
+
+@node Statements Comments Lines
+@subsection Statements, Comments, and Lines
+
+(Corresponds to Section 2.3 of ANSI X3.9-1978 FORTRAN 77.)
+
+@cindex comments, trailing
+@cindex trailing comments
+Use of an exclamation point (@samp{!}) to begin a
+trailing comment (a comment that extends to the end of the same
+source line) is permitted under the following conditions:
+
+@itemize @bullet
+@item
+The exclamation point does not appear in column 6.
+Otherwise, it is treated as an indicator of a continuation
+line.
+
+@item
+The exclamation point appears outside a character or Hollerith
+constant.
+Otherwise, the exclamation point is considered part of the
+constant.
+
+@item
+The exclamation point appears to the left of any other possible
+trailing comment.
+That is, a trailing comment may contain exclamation points
+in their commentary text.
+@end itemize
+
+@cindex semicolons
+@cindex statements, separated by semicolon
+Use of a semicolon (@samp{;}) as a statement separator
+is permitted under the following conditions:
+
+@itemize @bullet
+@item
+The semicolon appears outside a character or Hollerith
+constant.
+Otherwise, the semicolon is considered part of the
+constant.
+
+@item
+The semicolon appears to the left of a trailing comment.
+Otherwise, the semicolon is considered part of that
+comment.
+
+@item
+Neither a logical @code{IF} statement nor a non-construct
+@code{WHERE} statement (a Fortran 90 feature) may be
+followed (in the same, possibly continued, line) by
+a semicolon used as a statement separator.
+
+This restriction avoids the confusion
+that can result when reading a line such as:
+
+@smallexample
+IF (VALIDP) CALL FOO; CALL BAR
+@end smallexample
+
+@noindent
+Some readers might think the @samp{CALL BAR} is executed
+only if @samp{VALIDP} is @code{.TRUE.}, while others might
+assume its execution is unconditional.
+
+(At present, @code{g77} does not diagnose code that
+violates this restriction.)
+@end itemize
+
+@node Scope of Names and Labels
+@subsection Scope of Symbolic Names and Statement Labels
+@cindex scope
+
+(Corresponds to Section 2.9 of ANSI X3.9-1978 FORTRAN 77.)
+
+Included in the list of entities that have a scope of a
+program unit are construct names (a Fortran 90 feature).
+@xref{Construct Names}, for more information.
+
+@node Characters Lines Sequence
+@section Characters, Lines, and Execution Sequence
+
+(The following information augments or overrides the information in
+Chapter 3 of ANSI X3.9-1978 FORTRAN 77 in specifying the GNU Fortran
+language.
+Chapter 3 of that document otherwise serves as the basis
+for the relevant aspects of GNU Fortran.)
+
+@menu
+* Character Set::
+* Lines::
+* Continuation Line::
+* Statements::
+* Statement Labels::
+* Order::
+* INCLUDE::
+* Cpp-style directives::
+@end menu
+
+@node Character Set
+@subsection GNU Fortran Character Set
+@cindex characters
+
+(Corresponds to Section 3.1 of ANSI X3.9-1978 FORTRAN 77.)
+
+Letters include uppercase letters (the twenty-six characters
+of the English alphabet) and lowercase letters (their lowercase
+equivalent).
+Generally, lowercase letters may be used in place of uppercase
+letters, though in character and Hollerith constants, they
+are distinct.
+
+Special characters include:
+
+@itemize @bullet
+@item
+Semicolon (@samp{;})
+
+@item
+Exclamation point (@samp{!})
+
+@item
+Double quote (@samp{"})
+
+@item
+Backslash (@samp{\})
+
+@item
+Question mark (@samp{?})
+
+@item
+Hash mark (@samp{#})
+
+@item
+Ampersand (@samp{&})
+
+@item
+Percent sign (@samp{%})
+
+@item
+Underscore (@samp{_})
+
+@item
+Open angle (@samp{<})
+
+@item
+Close angle (@samp{>})
+
+@item
+The FORTRAN 77 special characters (@key{SPC}, @samp{=},
+@samp{+}, @samp{-}, @samp{*}, @samp{/}, @samp{(},
+@samp{)}, @samp{,}, @samp{.}, @samp{$}, @samp{'},
+and @samp{:})
+@end itemize
+
+@cindex blanks (spaces)
+Note that this document refers to @key{SPC} as @dfn{space},
+while X3.9-1978 FORTRAN 77 refers to it as @dfn{blank}.
+
+@node Lines
+@subsection Lines
+@cindex lines
+@cindex source file format
+@cindex source form
+@cindex files, source
+@cindex source code
+@cindex code, source
+@cindex fixed form
+@cindex free form
+
+(Corresponds to Section 3.2 of ANSI X3.9-1978 FORTRAN 77.)
+
+The way a Fortran compiler views source files depends entirely on the
+implementation choices made for the compiler, since those choices
+are explicitly left to the implementation by the published Fortran
+standards.
+
+The GNU Fortran language mandates a view applicable to UNIX-like
+text files---files that are made up of an arbitrary number of lines,
+each with an arbitrary number of characters (sometimes called stream-based
+files).
+
+This view does not apply to types of files that are specified as
+having a particular number of characters on every single line (sometimes
+referred to as record-based files).
+
+Because a ``line in a program unit is a sequence of 72 characters'',
+to quote X3.9-1978, the GNU Fortran language specifies that a
+stream-based text file is translated to GNU Fortran lines as follows:
+
+@itemize @bullet
+@item
+A newline in the file is the character that represents the end of
+a line of text to the underlying system.
+For example, on ASCII-based systems, a newline is the @key{NL}
+character, which has ASCII value 12 (decimal).
+
+@item
+Each newline in the file serves to end the line of text that precedes
+it (and that does not contain a newline).
+
+@item
+The end-of-file marker (@code{EOF}) also serves to end the line
+of text that precedes it (and that does not contain a newline).
+
+@item
+@cindex blanks (spaces)
+Any line of text that is shorter than 72 characters is padded to that length
+with spaces (called ``blanks'' in the standard).
+
+@item
+Any line of text that is longer than 72 characters is truncated to that
+length, but the truncated remainder must consist entirely of spaces.
+
+@item
+Characters other than newline and the GNU Fortran character set
+are invalid.
+@end itemize
+
+For the purposes of the remainder of this description of the GNU
+Fortran language, the translation described above has already
+taken place, unless otherwise specified.
+
+The result of the above translation is that the source file appears,
+in terms of the remainder of this description of the GNU Fortran language,
+as if it had an arbitrary
+number of 72-character lines, each character being among the GNU Fortran
+character set.
+
+For example, if the source file itself has two newlines in a row,
+the second newline becomes, after the above translation, a single
+line containing 72 spaces.
+
+@node Continuation Line
+@subsection Continuation Line
+@cindex continuation lines, number of
+@cindex lines, continuation
+@cindex number of continuation lines
+@cindex limits on continuation lines
+
+(Corresponds to Section 3.2.3 of ANSI X3.9-1978 FORTRAN 77.)
+
+A continuation line is any line that both
+
+@itemize @bullet
+@item
+Contains a continuation character, and
+
+@item
+Contains only spaces in columns 1 through 5
+@end itemize
+
+A continuation character is any character of the GNU Fortran character set
+other than space (@key{SPC}) or zero (@samp{0})
+in column 6, or a digit (@samp{0} through @samp{9}) in column
+7 through 72 of a line that has only spaces to the left of that
+digit.
+
+The continuation character is ignored as far as the content of
+the statement is concerned.
+
+The GNU Fortran language places no limit on the number of
+continuation lines in a statement.
+In practice, the limit depends on a variety of factors, such as
+available memory, statement content, and so on, but no
+GNU Fortran system may impose an arbitrary limit.
+
+@node Statements
+@subsection Statements
+
+(Corresponds to Section 3.3 of ANSI X3.9-1978 FORTRAN 77.)
+
+Statements may be written using an arbitrary number of continuation
+lines.
+
+Statements may be separated using the semicolon (@samp{;}), except
+that the logical @code{IF} and non-construct @code{WHERE} statements
+may not be separated from subsequent statements using only a semicolon
+as statement separator.
+
+The @code{END PROGRAM}, @code{END SUBROUTINE}, @code{END FUNCTION},
+and @code{END BLOCK DATA} statements are alternatives to the @code{END}
+statement.
+These alternatives may be written as normal statements---they are not
+subject to the restrictions of the @code{END} statement.
+
+However, no statement other than @code{END} may have an initial line
+that appears to be an @code{END} statement---even @code{END PROGRAM},
+for example, must not be written as:
+
+@example
+ END
+ &PROGRAM
+@end example
+
+@node Statement Labels
+@subsection Statement Labels
+
+(Corresponds to Section 3.4 of ANSI X3.9-1978 FORTRAN 77.)
+
+A statement separated from its predecessor via a semicolon may be
+labeled as follows:
+
+@itemize @bullet
+@item
+The semicolon is followed by the label for the statement,
+which in turn follows the label.
+
+@item
+The label must be no more than five digits in length.
+
+@item
+The first digit of the label for the statement is not
+the first non-space character on a line.
+Otherwise, that character is treated as a continuation
+character.
+@end itemize
+
+A statement may have only one label defined for it.
+
+@node Order
+@subsection Order of Statements and Lines
+
+(Corresponds to Section 3.5 of ANSI X3.9-1978 FORTRAN 77.)
+
+Generally, @code{DATA} statements may precede executable statements.
+However, specification statements pertaining to any entities
+initialized by a @code{DATA} statement must precede that @code{DATA}
+statement.
+For example,
+after @samp{DATA I/1/}, @samp{INTEGER I} is not permitted, but
+@samp{INTEGER J} is permitted.
+
+The last line of a program unit may be an @code{END} statement,
+or may be:
+
+@itemize @bullet
+@item
+An @code{END PROGRAM} statement, if the program unit is a main program.
+
+@item
+An @code{END SUBROUTINE} statement, if the program unit is a subroutine.
+
+@item
+An @code{END FUNCTION} statement, if the program unit is a function.
+
+@item
+An @code{END BLOCK DATA} statement, if the program unit is a block data.
+@end itemize
+
+@node INCLUDE
+@subsection Including Source Text
+@cindex INCLUDE
+
+Additional source text may be included in the processing of
+the source file via the @code{INCLUDE} directive:
+
+@example
+INCLUDE @var{filename}
+@end example
+
+@noindent
+The source text to be included is identified by @var{filename},
+which is a literal GNU Fortran character constant.
+The meaning and interpretation of @var{filename} depends on the
+implementation, but typically is a filename.
+
+(@code{g77} treats it as a filename that it searches for
+in the current directory and/or directories specified
+via the @samp{-I} command-line option.)
+
+The effect of the @code{INCLUDE} directive is as if the
+included text directly replaced the directive in the source
+file prior to interpretation of the program.
+Included text may itself use @code{INCLUDE}.
+The depth of nested @code{INCLUDE} references depends on
+the implementation, but typically is a positive integer.
+
+This virtual replacement treats the statements and @code{INCLUDE}
+directives in the included text as syntactically distinct from
+those in the including text.
+
+Therefore, the first non-comment line of the included text
+must not be a continuation line.
+The included text must therefore have, after the non-comment
+lines, either an initial line (statement), an @code{INCLUDE}
+directive, or nothing (the end of the included text).
+
+Similarly, the including text may end the @code{INCLUDE}
+directive with a semicolon or the end of the line, but it
+cannot follow an @code{INCLUDE} directive at the end of its
+line with a continuation line.
+Thus, the last statement in an included text may not be
+continued.
+
+Any statements between two @code{INCLUDE} directives on the
+same line are treated as if they appeared in between the
+respective included texts.
+For example:
+
+@smallexample
+INCLUDE 'A'; PRINT *, 'B'; INCLUDE 'C'; END PROGRAM
+@end smallexample
+
+@noindent
+If the text included by @samp{INCLUDE 'A'} constitutes
+a @samp{PRINT *, 'A'} statement and the text included by
+@samp{INCLUDE 'C'} constitutes a @samp{PRINT *, 'C'} statement,
+then the output of the above sample program would be
+
+@example
+A
+B
+C
+@end example
+
+@noindent
+(with suitable allowances for how an implementation defines
+its handling of output).
+
+Included text must not include itself directly or indirectly,
+regardless of whether the @var{filename} used to reference
+the text is the same.
+
+Note that @code{INCLUDE} is @emph{not} a statement.
+As such, it is neither a non-executable or executable
+statement.
+However, if the text it includes constitutes one or more
+executable statements, then the placement of @code{INCLUDE}
+is subject to effectively the same restrictions as those
+on executable statements.
+
+An @code{INCLUDE} directive may be continued across multiple
+lines as if it were a statement.
+This permits long names to be used for @var{filename}.
+
+@node Cpp-style directives
+@subsection Cpp-style directives
+@cindex #
+@cindex preprocessor
+
+@code{cpp} output-style @code{#} directives @xref{C Preprocessor
+Output,,, cpp, The C Preprocessor}, are recognized by the compiler even
+when the preprocessor isn't run on the input (as it is when compiling
+@samp{.F} files). (Note the distinction between these @code{cpp}
+@code{#} @emph{output} directives and @code{#line} @emph{input}
+directives.)
+
+@node Data Types and Constants
+@section Data Types and Constants
+
+(The following information augments or overrides the information in
+Chapter 4 of ANSI X3.9-1978 FORTRAN 77 in specifying the GNU Fortran
+language.
+Chapter 4 of that document otherwise serves as the basis
+for the relevant aspects of GNU Fortran.)
+
+To more concisely express the appropriate types for
+entities, this document uses the more concise
+Fortran 90 nomenclature such as @code{INTEGER(KIND=1)}
+instead of the more traditional, but less portably concise,
+byte-size-based nomenclature such as @code{INTEGER*4},
+wherever reasonable.
+
+When referring to generic types---in contexts where the
+specific precision and range of a type are not important---this
+document uses the generic type names @code{INTEGER}, @code{LOGICAL},
+@code{REAL}, @code{COMPLEX}, and @code{CHARACTER}.
+
+In some cases, the context requires specification of a
+particular type.
+This document uses the @samp{KIND=} notation to accomplish
+this throughout, sometimes supplying the more traditional
+notation for clarification, though the traditional notation
+might not work the same way on all GNU Fortran implementations.
+
+Use of @samp{KIND=} makes this document more concise because
+@code{g77} is able to define values for @samp{KIND=} that
+have the same meanings on all systems, due to the way the
+Fortran 90 standard specifies these values are to be used.
+
+(In particular, that standard permits an implementation to
+arbitrarily assign nonnegative values.
+There are four distinct sets of assignments: one to the @code{CHARACTER}
+type; one to the @code{INTEGER} type; one to the @code{LOGICAL} type;
+and the fourth to both the @code{REAL} and @code{COMPLEX} types.
+Implementations are free to assign these values in any order,
+leave gaps in the ordering of assignments, and assign more than
+one value to a representation.)
+
+This makes @samp{KIND=} values superior to the values used
+in non-standard statements such as @samp{INTEGER*4}, because
+the meanings of the values in those statements vary from machine
+to machine, compiler to compiler, even operating system to
+operating system.
+
+However, use of @samp{KIND=} is @emph{not} generally recommended
+when writing portable code (unless, for example, the code is
+going to be compiled only via @code{g77}, which is a widely
+ported compiler).
+GNU Fortran does not yet have adequate language constructs to
+permit use of @samp{KIND=} in a fashion that would make the
+code portable to Fortran 90 implementations; and, this construct
+is known to @emph{not} be accepted by many popular FORTRAN 77
+implementations, so it cannot be used in code that is to be ported
+to those.
+
+The distinction here is that this document is able to use
+specific values for @samp{KIND=} to concisely document the
+types of various operations and operands.
+
+A Fortran program should use the FORTRAN 77 designations for the
+appropriate GNU Fortran types---such as @code{INTEGER} for
+@code{INTEGER(KIND=1)}, @code{REAL} for @code{REAL(KIND=1)},
+and @code{DOUBLE COMPLEX} for @code{COMPLEX(KIND=2)}---and,
+where no such designations exist, make use of appropriate
+techniques (preprocessor macros, parameters, and so on)
+to specify the types in a fashion that may be easily adjusted
+to suit each particular implementation to which the program
+is ported.
+(These types generally won't need to be adjusted for ports of
+@code{g77}.)
+
+Further details regarding GNU Fortran data types and constants
+are provided below.
+
+@menu
+* Types::
+* Constants::
+* Integer Type::
+* Character Type::
+@end menu
+
+@node Types
+@subsection Data Types
+
+(Corresponds to Section 4.1 of ANSI X3.9-1978 FORTRAN 77.)
+
+GNU Fortran supports these types:
+
+@enumerate
+@item
+Integer (generic type @code{INTEGER})
+
+@item
+Real (generic type @code{REAL})
+
+@item
+Double precision
+
+@item
+Complex (generic type @code{COMPLEX})
+
+@item
+Logical (generic type @code{LOGICAL})
+
+@item
+Character (generic type @code{CHARACTER})
+
+@item
+Double Complex
+@end enumerate
+
+(The types numbered 1 through 6 above are standard FORTRAN 77 types.)
+
+The generic types shown above are referred to in this document
+using only their generic type names.
+Such references usually indicate that any specific type (kind)
+of that generic type is valid.
+
+For example, a context described in this document as accepting
+the @code{COMPLEX} type also is likely to accept the
+@code{DOUBLE COMPLEX} type.
+
+The GNU Fortran language supports three ways to specify
+a specific kind of a generic type.
+
+@menu
+* Double Notation:: As in @code{DOUBLE COMPLEX}.
+* Star Notation:: As in @code{INTEGER*4}.
+* Kind Notation:: As in @code{INTEGER(KIND=1)}.
+@end menu
+
+@node Double Notation
+@subsubsection Double Notation
+
+The GNU Fortran language supports two uses of the keyword
+@code{DOUBLE} to specify a specific kind of type:
+
+@itemize @bullet
+@item
+@code{DOUBLE PRECISION}, equivalent to @code{REAL(KIND=2)}
+
+@item
+@code{DOUBLE COMPLEX}, equivalent to @code{COMPLEX(KIND=2)}
+@end itemize
+
+Use one of the above forms where a type name is valid.
+
+While use of this notation is popular, it doesn't scale
+well in a language or dialect rich in intrinsic types,
+as is the case for the GNU Fortran language (especially
+planned future versions of it).
+
+After all, one rarely sees type names such as @samp{DOUBLE INTEGER},
+@samp{QUADRUPLE REAL}, or @samp{QUARTER INTEGER}.
+Instead, @code{INTEGER*8}, @code{REAL*16}, and @code{INTEGER*1}
+often are substituted for these, respectively, even though they
+do not always have the same meanings on all systems.
+(And, the fact that @samp{DOUBLE REAL} does not exist as such
+is an inconsistency.)
+
+Therefore, this document uses ``double notation'' only on occasion
+for the benefit of those readers who are accustomed to it.
+
+@node Star Notation
+@subsubsection Star Notation
+@cindex *@var{n} notation
+
+The following notation specifies the storage size for a type:
+
+@smallexample
+@var{generic-type}*@var{n}
+@end smallexample
+
+@noindent
+@var{generic-type} must be a generic type---one of
+@code{INTEGER}, @code{REAL}, @code{COMPLEX}, @code{LOGICAL},
+or @code{CHARACTER}.
+@var{n} must be one or more digits comprising a decimal
+integer number greater than zero.
+
+Use the above form where a type name is valid.
+
+The @samp{*@var{n}} notation specifies that the amount of storage
+occupied by variables and array elements of that type is @var{n}
+times the storage occupied by a @code{CHARACTER*1} variable.
+
+This notation might indicate a different degree of precision and/or
+range for such variables and array elements, and the functions that
+return values of types using this notation.
+It does not limit the precision or range of values of that type
+in any particular way---use explicit code to do that.
+
+Further, the GNU Fortran language requires no particular values
+for @var{n} to be supported by an implementation via the @samp{*@var{n}}
+notation.
+@code{g77} supports @code{INTEGER*1} (as @code{INTEGER(KIND=3)})
+on all systems, for example,
+but not all implementations are required to do so, and @code{g77}
+is known to not support @code{REAL*1} on most (or all) systems.
+
+As a result, except for @var{generic-type} of @code{CHARACTER},
+uses of this notation should be limited to isolated
+portions of a program that are intended to handle system-specific
+tasks and are expected to be non-portable.
+
+(Standard FORTRAN 77 supports the @samp{*@var{n}} notation for
+only @code{CHARACTER}, where it signifies not only the amount
+of storage occupied, but the number of characters in entities
+of that type.
+However, almost all Fortran compilers have supported this
+notation for generic types, though with a variety of meanings
+for @var{n}.)
+
+Specifications of types using the @samp{*@var{n}} notation
+always are interpreted as specifications of the appropriate
+types described in this document using the @samp{KIND=@var{n}}
+notation, described below.
+
+While use of this notation is popular, it doesn't serve well
+in the context of a widely portable dialect of Fortran, such as
+the GNU Fortran language.
+
+For example, even on one particular machine, two or more popular
+Fortran compilers might well disagree on the size of a type
+declared @code{INTEGER*2} or @code{REAL*16}.
+Certainly there
+is known to be disagreement over such things among Fortran
+compilers on @emph{different} systems.
+
+Further, this notation offers no elegant way to specify sizes
+that are not even multiples of the ``byte size'' typically
+designated by @code{INTEGER*1}.
+Use of ``absurd'' values (such as @code{INTEGER*1000}) would
+certainly be possible, but would perhaps be stretching the original
+intent of this notation beyond the breaking point in terms
+of widespread readability of documentation and code making use
+of it.
+
+Therefore, this document uses ``star notation'' only on occasion
+for the benefit of those readers who are accustomed to it.
+
+@node Kind Notation
+@subsubsection Kind Notation
+@cindex KIND= notation
+
+The following notation specifies the kind-type selector of a type:
+
+@smallexample
+@var{generic-type}(KIND=@var{n})
+@end smallexample
+
+@noindent
+Use the above form where a type name is valid.
+
+@var{generic-type} must be a generic type---one of
+@code{INTEGER}, @code{REAL}, @code{COMPLEX}, @code{LOGICAL},
+or @code{CHARACTER}.
+@var{n} must be an integer initialization expression that
+is a positive, nonzero value.
+
+Programmers are discouraged from writing these values directly
+into their code.
+Future versions of the GNU Fortran language will offer
+facilities that will make the writing of code portable
+to @code{g77} @emph{and} Fortran 90 implementations simpler.
+
+However, writing code that ports to existing FORTRAN 77
+implementations depends on avoiding the @samp{KIND=} construct.
+
+The @samp{KIND=} construct is thus useful in the context
+of GNU Fortran for two reasons:
+
+@itemize @bullet
+@item
+It provides a means to specify a type in a fashion that
+is portable across all GNU Fortran implementations (though
+not other FORTRAN 77 and Fortran 90 implementations).
+
+@item
+It provides a sort of Rosetta stone for this document to use
+to concisely describe the types of various operations and
+operands.
+@end itemize
+
+The values of @var{n} in the GNU Fortran language are
+assigned using a scheme that:
+
+@itemize @bullet
+@item
+Attempts to maximize the ability of readers
+of this document to quickly familiarize themselves
+with assignments for popular types
+
+@item
+Provides a unique value for each specific desired
+meaning
+
+@item
+Provides a means to automatically assign new values so
+they have a ``natural'' relationship to existing values,
+if appropriate, or, if no such relationship exists, will
+not interfere with future values assigned on the basis
+of such relationships
+
+@item
+Avoids using values that are similar to values used
+in the existing, popular @samp{*@var{n}} notation,
+to prevent readers from expecting that these implied
+correspondences work on all GNU Fortran implementations
+@end itemize
+
+The assignment system accomplishes this by assigning
+to each ``fundamental meaning'' of a specific type a
+unique prime number.
+Combinations of fundamental meanings---for example, a type
+that is two times the size of some other type---are assigned
+values of @var{n} that are the products of the values for
+those fundamental meanings.
+
+A prime value of @var{n} is never given more than one fundamental
+meaning, to avoid situations where some code or system
+cannot reasonably provide those meanings in the form of a
+single type.
+
+The values of @var{n} assigned so far are:
+
+@table @code
+@item KIND=0
+This value is reserved for future use.
+
+The planned future use is for this value to designate,
+explicitly, context-sensitive kind-type selection.
+For example, the expression @samp{1D0 * 0.1_0} would
+be equivalent to @samp{1D0 * 0.1D0}.
+
+@item KIND=1
+This corresponds to the default types for
+@code{REAL}, @code{INTEGER}, @code{LOGICAL}, @code{COMPLEX},
+and @code{CHARACTER}, as appropriate.
+
+These are the ``default'' types described in the Fortran 90 standard,
+though that standard does not assign any particular @samp{KIND=}
+value to these types.
+
+(Typically, these are @code{REAL*4}, @code{INTEGER*4},
+@code{LOGICAL*4}, and @code{COMPLEX*8}.)
+
+@item KIND=2
+This corresponds to types that occupy twice as much
+storage as the default types.
+@code{REAL(KIND=2)} is @code{DOUBLE PRECISION} (typically @code{REAL*8}),
+@code{COMPLEX(KIND=2)} is @code{DOUBLE COMPLEX} (typically @code{COMPLEX*16}),
+
+These are the ``double precision'' types described in the Fortran 90
+standard,
+though that standard does not assign any particular @samp{KIND=}
+value to these types.
+
+@var{n} of 4 thus corresponds to types that occupy four times
+as much storage as the default types, @var{n} of 8 to types that
+occupy eight times as much storage, and so on.
+
+The @code{INTEGER(KIND=2)} and @code{LOGICAL(KIND=2)} types
+are not necessarily supported by every GNU Fortran implementation.
+
+@item KIND=3
+This corresponds to types that occupy as much
+storage as the default @code{CHARACTER} type,
+which is the same effective type as @code{CHARACTER(KIND=1)}
+(making that type effectively the same as @code{CHARACTER(KIND=3)}).
+
+(Typically, these are @code{INTEGER*1} and @code{LOGICAL*1}.)
+
+@var{n} of 6 thus corresponds to types that occupy twice as
+much storage as the @var{n}=3 types, @var{n} of 12 to types
+that occupy four times as much storage, and so on.
+
+These are not necessarily supported by every GNU Fortran
+implementation.
+
+@item KIND=5
+This corresponds to types that occupy half the
+storage as the default (@var{n}=1) types.
+
+(Typically, these are @code{INTEGER*2} and @code{LOGICAL*2}.)
+
+@var{n} of 25 thus corresponds to types that occupy one-quarter
+as much storage as the default types.
+
+These are not necessarily supported by every GNU Fortran
+implementation.
+
+@item KIND=7
+@cindex pointers
+This is valid only as @code{INTEGER(KIND=7)} and
+denotes the @code{INTEGER} type that has the smallest
+storage size that holds a pointer on the system.
+
+A pointer representable by this type is capable of uniquely
+addressing a @code{CHARACTER*1} variable, array, array element,
+or substring.
+
+(Typically this is equivalent to @code{INTEGER*4} or,
+on 64-bit systems, @code{INTEGER*8}.
+In a compatible C implementation, it typically would
+be the same size and semantics of the C type @code{void *}.)
+@end table
+
+Note that these are @emph{proposed} correspondences and might change
+in future versions of @code{g77}---avoid writing code depending
+on them while @code{g77}, and therefore the GNU Fortran language
+it defines, is in beta testing.
+
+Values not specified in the above list are reserved to
+future versions of the GNU Fortran language.
+
+Implementation-dependent meanings will be assigned new,
+unique prime numbers so as to not interfere with other
+implementation-dependent meanings, and offer the possibility
+of increasing the portability of code depending on such
+types by offering support for them in other GNU Fortran
+implementations.
+
+Other meanings that might be given unique values are:
+
+@itemize @bullet
+@item
+Types that make use of only half their storage size for
+representing precision and range.
+
+For example, some compilers offer options that cause
+@code{INTEGER} types to occupy the amount of storage
+that would be needed for @code{INTEGER(KIND=2)} types, but the
+range remains that of @code{INTEGER(KIND=1)}.
+
+@item
+The IEEE single floating-point type.
+
+@item
+Types with a specific bit pattern (endianness), such as the
+little-endian form of @code{INTEGER(KIND=1)}.
+These could permit, conceptually, use of portable code and
+implementations on data files written by existing systems.
+@end itemize
+
+Future @emph{prime} numbers should be given meanings in as incremental
+a fashion as possible, to allow for flexibility and
+expressiveness in combining types.
+
+For example, instead of defining a prime number for little-endian
+IEEE doubles, one prime number might be assigned the meaning
+``little-endian'', another the meaning ``IEEE double'', and the
+value of @var{n} for a little-endian IEEE double would thus
+naturally be the product of those two respective assigned values.
+(It could even be reasonable to have IEEE values result from the
+products of prime values denoting exponent and fraction sizes
+and meanings, hidden bit usage, availability and representations
+of special values such as subnormals, infinities, and Not-A-Numbers
+(NaNs), and so on.)
+
+This assignment mechanism, while not inherently required for
+future versions of the GNU Fortran language, is worth using
+because it could ease management of the ``space'' of supported
+types much easier in the long run.
+
+The above approach suggests a mechanism for specifying inheritance
+of intrinsic (built-in) types for an entire, widely portable
+product line.
+It is certainly reasonable that, unlike programmers of other languages
+offering inheritance mechanisms that employ verbose names for classes
+and subclasses, along with graphical browsers to elucidate the
+relationships, Fortran programmers would employ
+a mechanism that works by multiplying prime numbers together
+and finding the prime factors of such products.
+
+Most of the advantages for the above scheme have been explained
+above.
+One disadvantage is that it could lead to the defining,
+by the GNU Fortran language, of some fairly large prime numbers.
+This could lead to the GNU Fortran language being declared
+``munitions'' by the United States Department of Defense.
+
+@node Constants
+@subsection Constants
+@cindex constants
+@cindex types, constants
+
+(Corresponds to Section 4.2 of ANSI X3.9-1978 FORTRAN 77.)
+
+A @dfn{typeless constant} has one of the following forms:
+
+@smallexample
+'@var{binary-digits}'B
+'@var{octal-digits}'O
+'@var{hexadecimal-digits}'Z
+'@var{hexadecimal-digits}'X
+@end smallexample
+
+@noindent
+@var{binary-digits}, @var{octal-digits}, and @var{hexadecimal-digits}
+are nonempty strings of characters in the set @samp{01}, @samp{01234567},
+and @samp{0123456789ABCDEFabcdef}, respectively.
+(The value for @samp{A} (and @samp{a}) is 10, for @samp{B} and @samp{b}
+is 11, and so on.)
+
+A prefix-radix constant, such as @samp{Z'ABCD'}, can optionally be
+treated as typeless. @xref{Fortran Dialect Options,, Options
+Controlling Fortran Dialect}, for information on the
+@samp{-ftypeless-boz} option.
+
+Typeless constants have values that depend on the context in which
+they are used.
+
+All other constants, called @dfn{typed constants}, are interpreted---converted
+to internal form---according to their inherent type.
+Thus, context is @emph{never} a determining factor for the type, and hence
+the interpretation, of a typed constant.
+(All constants in the ANSI FORTRAN 77 language are typed constants.)
+
+For example, @samp{1} is always type @code{INTEGER(KIND=1)} in GNU
+Fortran (called default INTEGER in Fortran 90),
+@samp{9.435784839284958} is always type @code{REAL(KIND=1)} (even if the
+additional precision specified is lost, and even when used in a
+@code{REAL(KIND=2)} context), @samp{1E0} is always type @code{REAL(KIND=2)},
+and @samp{1D0} is always type @code{REAL(KIND=2)}.
+
+@node Integer Type
+@subsection Integer Type
+
+(Corresponds to Section 4.3 of ANSI X3.9-1978 FORTRAN 77.)
+
+An integer constant also may have one of the following forms:
+
+@smallexample
+B'@var{binary-digits}'
+O'@var{octal-digits}'
+Z'@var{hexadecimal-digits}'
+X'@var{hexadecimal-digits}'
+@end smallexample
+
+@noindent
+@var{binary-digits}, @var{octal-digits}, and @var{hexadecimal-digits}
+are nonempty strings of characters in the set @samp{01}, @samp{01234567},
+and @samp{0123456789ABCDEFabcdef}, respectively.
+(The value for @samp{A} (and @samp{a}) is 10, for @samp{B} and @samp{b}
+is 11, and so on.)
+
+@node Character Type
+@subsection Character Type
+
+(Corresponds to Section 4.8 of ANSI X3.9-1978 FORTRAN 77.)
+
+@cindex double quoted character constants
+A character constant may be delimited by a pair of double quotes
+(@samp{"}) instead of apostrophes.
+In this case, an apostrophe within the constant represents
+a single apostrophe, while a double quote is represented in
+the source text of the constant by two consecutive double
+quotes with no intervening spaces.
+
+@cindex zero-length CHARACTER
+@cindex null CHARACTER strings
+@cindex empty CHARACTER strings
+@cindex strings, empty
+@cindex CHARACTER, null
+A character constant may be empty (have a length of zero).
+
+A character constant may include a substring specification,
+The value of such a constant is the value of the substring---for
+example, the value of @samp{'hello'(3:5)} is the same
+as the value of @samp{'llo'}.
+
+@node Expressions
+@section Expressions
+
+(The following information augments or overrides the information in
+Chapter 6 of ANSI X3.9-1978 FORTRAN 77 in specifying the GNU Fortran
+language.
+Chapter 6 of that document otherwise serves as the basis
+for the relevant aspects of GNU Fortran.)
+
+@menu
+* %LOC()::
+@end menu
+
+@node %LOC()
+@subsection The @code{%LOC()} Construct
+@cindex %LOC() construct
+
+@example
+%LOC(@var{arg})
+@end example
+
+The @code{%LOC()} construct is an expression
+that yields the value of the location of its argument,
+@var{arg}, in memory.
+The size of the type of the expression depends on the system---typically,
+it is equivalent to either @code{INTEGER(KIND=1)} or @code{INTEGER(KIND=2)},
+though it is actually type @code{INTEGER(KIND=7)}.
+
+The argument to @code{%LOC()} must be suitable as the
+left-hand side of an assignment statement.
+That is, it may not be a general expression involving
+operators such as addition, subtraction, and so on,
+nor may it be a constant.
+
+Use of @code{%LOC()} is recommended only for code that
+is accessing facilities outside of GNU Fortran, such as
+operating system or windowing facilities.
+It is best to constrain such uses to isolated portions of
+a program---portions that deal specifically and exclusively
+with low-level, system-dependent facilities.
+Such portions might well provide a portable interface for
+use by the program as a whole, but are themselves not
+portable, and should be thoroughly tested each time they
+are rebuilt using a new compiler or version of a compiler.
+
+Do not depend on @code{%LOC()} returning a pointer that
+can be safely used to @emph{define} (change) the argument.
+While this might work in some circumstances, it is hard
+to predict whether it will continue to work when a program
+(that works using this unsafe behavior)
+is recompiled using different command-line options or
+a different version of @code{g77}.
+
+Generally, @code{%LOC()} is safe when used as an argument
+to a procedure that makes use of the value of the corresponding
+dummy argument only during its activation, and only when
+such use is restricted to referencing (reading) the value
+of the argument to @code{%LOC()}.
+
+@emph{Implementation Note:} Currently, @code{g77} passes
+arguments (those not passed using a construct such as @code{%VAL()})
+by reference or descriptor, depending on the type of
+the actual argument.
+Thus, given @samp{INTEGER I}, @samp{CALL FOO(I)} would
+seem to mean the same thing as @samp{CALL FOO(%VAL(%LOC(I)))}, and
+in fact might compile to identical code.
+
+However, @samp{CALL FOO(%VAL(%LOC(I)))} emphatically means
+``pass, by value, the address of @samp{I} in memory''.
+While @samp{CALL FOO(I)} might use that same approach in a
+particular version of @code{g77}, another version or compiler
+might choose a different implementation, such as copy-in/copy-out,
+to effect the desired behavior---and which will therefore not
+necessarily compile to the same code as would
+@samp{CALL FOO(%VAL(%LOC(I)))}
+using the same version or compiler.
+
+@xref{Debugging and Interfacing}, for detailed information on
+how this particular version of @code{g77} implements various
+constructs.
+
+@node Specification Statements
+@section Specification Statements
+
+(The following information augments or overrides the information in
+Chapter 8 of ANSI X3.9-1978 FORTRAN 77 in specifying the GNU Fortran
+language.
+Chapter 8 of that document otherwise serves as the basis
+for the relevant aspects of GNU Fortran.)
+
+@menu
+* NAMELIST::
+* DOUBLE COMPLEX::
+@end menu
+
+@node NAMELIST
+@subsection @code{NAMELIST} Statement
+@cindex NAMELIST statement
+@cindex statements, NAMELIST
+
+The @code{NAMELIST} statement, and related I/O constructs, are
+supported by the GNU Fortran language in essentially the same
+way as they are by @code{f2c}.
+
+This follows Fortran 90 with the restriction that on @code{NAMELIST}
+input, subscripts must have the form
+@smallexample
+@var{subscript} [ @code{:} @var{subscript} [ @code{:} @var{stride}]]
+@end smallexample
+i.e.@:
+@smallexample
+&xx x(1:3,8:10:2)=1,2,3,4,5,6/
+@end smallexample
+is allowed, but not, say,
+@smallexample
+&xx x(:3,8::2)=1,2,3,4,5,6/
+@end smallexample
+
+As an extension of the Fortran 90 form, @code{$} and @code{$END} may be
+used in place of @code{&} and @code{/} in @code{NAMELIST} input, so that
+@smallexample
+$&xx x(1:3,8:10:2)=1,2,3,4,5,6 $end
+@end smallexample
+could be used instead of the example above.
+
+@node DOUBLE COMPLEX
+@subsection @code{DOUBLE COMPLEX} Statement
+@cindex DOUBLE COMPLEX
+
+@code{DOUBLE COMPLEX} is a type-statement (and type) that
+specifies the type @code{COMPLEX(KIND=2)} in GNU Fortran.
+
+@node Control Statements
+@section Control Statements
+
+(The following information augments or overrides the information in
+Chapter 11 of ANSI X3.9-1978 FORTRAN 77 in specifying the GNU Fortran
+language.
+Chapter 11 of that document otherwise serves as the basis
+for the relevant aspects of GNU Fortran.)
+
+@menu
+* DO WHILE::
+* END DO::
+* Construct Names::
+* CYCLE and EXIT::
+@end menu
+
+@node DO WHILE
+@subsection DO WHILE
+@cindex DO WHILE
+@cindex DO
+@cindex MIL-STD 1753
+
+The @code{DO WHILE} statement, a feature of both the MIL-STD 1753 and
+Fortran 90 standards, is provided by the GNU Fortran language.
+The Fortran 90 ``do forever'' statement comprising just @code{DO} is
+also supported.
+
+@node END DO
+@subsection END DO
+@cindex END DO
+@cindex MIL-STD 1753
+
+The @code{END DO} statement is provided by the GNU Fortran language.
+
+This statement is used in one of two ways:
+
+@itemize @bullet
+@item
+The Fortran 90 meaning, in which it specifies the termination
+point of a single @code{DO} loop started with a @code{DO} statement
+that specifies no termination label.
+
+@item
+The MIL-STD 1753 meaning, in which it specifies the termination
+point of one or more @code{DO} loops, all of which start with a
+@code{DO} statement that specify the label defined for the
+@code{END DO} statement.
+
+This kind of @code{END DO} statement is merely a synonym for
+@code{CONTINUE}, except it is permitted only when the statement
+is labeled and a target of one or more labeled @code{DO} loops.
+
+It is expected that this use of @code{END DO} will be removed from
+the GNU Fortran language in the future, though it is likely that
+it will long be supported by @code{g77} as a dialect form.
+@end itemize
+
+@node Construct Names
+@subsection Construct Names
+@cindex construct names
+
+The GNU Fortran language supports construct names as defined
+by the Fortran 90 standard.
+These names are local to the program unit and are defined
+as follows:
+
+@smallexample
+@var{construct-name}: @var{block-statement}
+@end smallexample
+
+@noindent
+Here, @var{construct-name} is the construct name itself;
+its definition is connoted by the single colon (@samp{:}); and
+@var{block-statement} is an @code{IF}, @code{DO},
+or @code{SELECT CASE} statement that begins a block.
+
+A block that is given a construct name must also specify the
+same construct name in its termination statement:
+
+@example
+END @var{block} @var{construct-name}
+@end example
+
+@noindent
+Here, @var{block} must be @code{IF}, @code{DO}, or @code{SELECT},
+as appropriate.
+
+@node CYCLE and EXIT
+@subsection The @code{CYCLE} and @code{EXIT} Statements
+
+The @code{CYCLE} and @code{EXIT} statements specify that
+the remaining statements in the current iteration of a
+particular active (enclosing) @code{DO} loop are to be skipped.
+
+@code{CYCLE} specifies that these statements are skipped,
+but the @code{END DO} statement that marks the end of the
+@code{DO} loop be executed---that is, the next iteration,
+if any, is to be started.
+If the statement marking the end of the @code{DO} loop is
+not @code{END DO}---in other words, if the loop is not
+a block @code{DO}---the @code{CYCLE} statement does not
+execute that statement, but does start the next iteration (if any).
+
+@code{EXIT} specifies that the loop specified by the
+@code{DO} construct is terminated.
+
+The @code{DO} loop affected by @code{CYCLE} and @code{EXIT}
+is the innermost enclosing @code{DO} loop when the following
+forms are used:
+
+@example
+CYCLE
+EXIT
+@end example
+
+Otherwise, the following forms specify the construct name
+of the pertinent @code{DO} loop:
+
+@example
+CYCLE @var{construct-name}
+EXIT @var{construct-name}
+@end example
+
+@code{CYCLE} and @code{EXIT} can be viewed as glorified @code{GO TO}
+statements.
+However, they cannot be easily thought of as @code{GO TO} statements
+in obscure cases involving FORTRAN 77 loops.
+For example:
+
+@smallexample
+ DO 10 I = 1, 5
+ DO 10 J = 1, 5
+ IF (J .EQ. 5) EXIT
+ DO 10 K = 1, 5
+ IF (K .EQ. 3) CYCLE
+10 PRINT *, 'I=', I, ' J=', J, ' K=', K
+20 CONTINUE
+@end smallexample
+
+@noindent
+In particular, neither the @code{EXIT} nor @code{CYCLE} statements
+above are equivalent to a @code{GO TO} statement to either label
+@samp{10} or @samp{20}.
+
+To understand the effect of @code{CYCLE} and @code{EXIT} in the
+above fragment, it is helpful to first translate it to its equivalent
+using only block @code{DO} loops:
+
+@smallexample
+ DO I = 1, 5
+ DO J = 1, 5
+ IF (J .EQ. 5) EXIT
+ DO K = 1, 5
+ IF (K .EQ. 3) CYCLE
+10 PRINT *, 'I=', I, ' J=', J, ' K=', K
+ END DO
+ END DO
+ END DO
+20 CONTINUE
+@end smallexample
+
+Adding new labels allows translation of @code{CYCLE} and @code{EXIT}
+to @code{GO TO} so they may be more easily understood by programmers
+accustomed to FORTRAN coding:
+
+@smallexample
+ DO I = 1, 5
+ DO J = 1, 5
+ IF (J .EQ. 5) GOTO 18
+ DO K = 1, 5
+ IF (K .EQ. 3) GO TO 12
+10 PRINT *, 'I=', I, ' J=', J, ' K=', K
+12 END DO
+ END DO
+18 END DO
+20 CONTINUE
+@end smallexample
+
+@noindent
+Thus, the @code{CYCLE} statement in the innermost loop skips over
+the @code{PRINT} statement as it begins the next iteration of the
+loop, while the @code{EXIT} statement in the middle loop ends that
+loop but @emph{not} the outermost loop.
+
+@node Functions and Subroutines
+@section Functions and Subroutines
+
+(The following information augments or overrides the information in
+Chapter 15 of ANSI X3.9-1978 FORTRAN 77 in specifying the GNU Fortran
+language.
+Chapter 15 of that document otherwise serves as the basis
+for the relevant aspects of GNU Fortran.)
+
+@menu
+* %VAL()::
+* %REF()::
+* %DESCR()::
+* Generics and Specifics::
+* REAL() and AIMAG() of Complex::
+* CMPLX() of DOUBLE PRECISION::
+* MIL-STD 1753::
+* f77/f2c Intrinsics::
+* Table of Intrinsic Functions::
+@end menu
+
+@node %VAL()
+@subsection The @code{%VAL()} Construct
+@cindex %VAL() construct
+
+@example
+%VAL(@var{arg})
+@end example
+
+The @code{%VAL()} construct specifies that an argument,
+@var{arg}, is to be passed by value, instead of by reference
+or descriptor.
+
+@code{%VAL()} is restricted to actual arguments in
+invocations of external procedures.
+
+Use of @code{%VAL()} is recommended only for code that
+is accessing facilities outside of GNU Fortran, such as
+operating system or windowing facilities.
+It is best to constrain such uses to isolated portions of
+a program---portions the deal specifically and exclusively
+with low-level, system-dependent facilities.
+Such portions might well provide a portable interface for
+use by the program as a whole, but are themselves not
+portable, and should be thoroughly tested each time they
+are rebuilt using a new compiler or version of a compiler.
+
+@emph{Implementation Note:} Currently, @code{g77} passes
+all arguments either by reference or by descriptor.
+
+Thus, use of @code{%VAL()} tends to be restricted to cases
+where the called procedure is written in a language other
+than Fortran that supports call-by-value semantics.
+(C is an example of such a language.)
+
+@xref{Procedures,,Procedures (SUBROUTINE and FUNCTION)},
+for detailed information on
+how this particular version of @code{g77} passes arguments
+to procedures.
+
+@node %REF()
+@subsection The @code{%REF()} Construct
+@cindex %REF() construct
+
+@example
+%REF(@var{arg})
+@end example
+
+The @code{%REF()} construct specifies that an argument,
+@var{arg}, is to be passed by reference, instead of by
+value or descriptor.
+
+@code{%REF()} is restricted to actual arguments in
+invocations of external procedures.
+
+Use of @code{%REF()} is recommended only for code that
+is accessing facilities outside of GNU Fortran, such as
+operating system or windowing facilities.
+It is best to constrain such uses to isolated portions of
+a program---portions the deal specifically and exclusively
+with low-level, system-dependent facilities.
+Such portions might well provide a portable interface for
+use by the program as a whole, but are themselves not
+portable, and should be thoroughly tested each time they
+are rebuilt using a new compiler or version of a compiler.
+
+Do not depend on @code{%REF()} supplying a pointer to the
+procedure being invoked.
+While that is a likely implementation choice, other
+implementation choices are available that preserve Fortran
+pass-by-reference semantics without passing a pointer to
+the argument, @var{arg}.
+(For example, a copy-in/copy-out implementation.)
+
+@emph{Implementation Note:} Currently, @code{g77} passes
+all arguments
+(other than variables and arrays of type @code{CHARACTER})
+by reference.
+Future versions of, or dialects supported by, @code{g77} might
+not pass @code{CHARACTER} functions by reference.
+
+Thus, use of @code{%REF()} tends to be restricted to cases
+where @var{arg} is type @code{CHARACTER} but the called
+procedure accesses it via a means other than the method
+used for Fortran @code{CHARACTER} arguments.
+
+@xref{Procedures,,Procedures (SUBROUTINE and FUNCTION)}, for detailed information on
+how this particular version of @code{g77} passes arguments
+to procedures.
+
+@node %DESCR()
+@subsection The @code{%DESCR()} Construct
+@cindex %DESCR() construct
+
+@example
+%DESCR(@var{arg})
+@end example
+
+The @code{%DESCR()} construct specifies that an argument,
+@var{arg}, is to be passed by descriptor, instead of by
+value or reference.
+
+@code{%DESCR()} is restricted to actual arguments in
+invocations of external procedures.
+
+Use of @code{%DESCR()} is recommended only for code that
+is accessing facilities outside of GNU Fortran, such as
+operating system or windowing facilities.
+It is best to constrain such uses to isolated portions of
+a program---portions the deal specifically and exclusively
+with low-level, system-dependent facilities.
+Such portions might well provide a portable interface for
+use by the program as a whole, but are themselves not
+portable, and should be thoroughly tested each time they
+are rebuilt using a new compiler or version of a compiler.
+
+Do not depend on @code{%DESCR()} supplying a pointer
+and/or a length passed by value
+to the procedure being invoked.
+While that is a likely implementation choice, other
+implementation choices are available that preserve the
+pass-by-reference semantics without passing a pointer to
+the argument, @var{arg}.
+(For example, a copy-in/copy-out implementation.)
+And, future versions of @code{g77} might change the
+way descriptors are implemented, such as passing a
+single argument pointing to a record containing the
+pointer/length information instead of passing that same
+information via two arguments as it currently does.
+
+@emph{Implementation Note:} Currently, @code{g77} passes
+all variables and arrays of type @code{CHARACTER}
+by descriptor.
+Future versions of, or dialects supported by, @code{g77} might
+pass @code{CHARACTER} functions by descriptor as well.
+
+Thus, use of @code{%DESCR()} tends to be restricted to cases
+where @var{arg} is not type @code{CHARACTER} but the called
+procedure accesses it via a means similar to the method
+used for Fortran @code{CHARACTER} arguments.
+
+@xref{Procedures,,Procedures (SUBROUTINE and FUNCTION)}, for detailed information on
+how this particular version of @code{g77} passes arguments
+to procedures.
+
+@node Generics and Specifics
+@subsection Generics and Specifics
+@cindex generic intrinsics
+@cindex intrinsics, generic
+
+The ANSI FORTRAN 77 language defines generic and specific
+intrinsics.
+In short, the distinctions are:
+
+@itemize @bullet
+@item
+@emph{Specific} intrinsics have
+specific types for their arguments and a specific return
+type.
+
+@item
+@emph{Generic} intrinsics are treated,
+on a case-by-case basis in the program's source code,
+as one of several possible specific intrinsics.
+
+Typically, a generic intrinsic has a return type that
+is determined by the type of one or more of its arguments.
+@end itemize
+
+The GNU Fortran language generalizes these concepts somewhat,
+especially by providing intrinsic subroutines and generic
+intrinsics that are treated as either a specific intrinsic subroutine
+or a specific intrinsic function (e.g. @code{SECOND}).
+
+However, GNU Fortran avoids generalizing this concept to
+the point where existing code would be accepted as meaning
+something possibly different than what was intended.
+
+For example, @code{ABS} is a generic intrinsic, so all working
+code written using @code{ABS} of an @code{INTEGER} argument
+expects an @code{INTEGER} return value.
+Similarly, all such code expects that @code{ABS} of an @code{INTEGER*2}
+argument returns an @code{INTEGER*2} return value.
+
+Yet, @code{IABS} is a @emph{specific} intrinsic that accepts only
+an @code{INTEGER(KIND=1)} argument.
+Code that passes something other than an @code{INTEGER(KIND=1)}
+argument to @code{IABS} is not valid GNU Fortran code, because
+it is not clear what the author intended.
+
+For example, if @samp{J} is @code{INTEGER(KIND=6)}, @samp{IABS(J)}
+is not defined by the GNU Fortran language, because the programmer
+might have used that construct to mean any of the following, subtly
+different, things:
+
+@itemize @bullet
+@item
+Convert @samp{J} to @code{INTEGER(KIND=1)} first
+(as if @samp{IABS(INT(J))} had been written).
+
+@item
+Convert the result of the intrinsic to @code{INTEGER(KIND=1)}
+(as if @samp{INT(ABS(J))} had been written).
+
+@item
+No conversion (as if @samp{ABS(J)} had been written).
+@end itemize
+
+The distinctions matter especially when types and values wider than
+@code{INTEGER(KIND=1)} (such as @code{INTEGER(KIND=2)}), or when
+operations performing more ``arithmetic'' than absolute-value, are involved.
+
+The following sample program is not a valid GNU Fortran program, but
+might be accepted by other compilers.
+If so, the output is likely to be revealing in terms of how a given
+compiler treats intrinsics (that normally are specific) when they
+are given arguments that do not conform to their stated requirements:
+
+@cindex JCB002 program
+@smallexample
+ PROGRAM JCB002
+C Version 1:
+C Modified 1997-05-21 (Burley) to accommodate compilers that implement
+C INT(I1-I2) as INT(I1)-INT(I2) given INTEGER*2 I1,I2.
+C
+C Version 0:
+C Written by James Craig Burley 1997-02-20.
+C Contact via Internet email: burley@@gnu.org
+C
+C Purpose:
+C Determine how compilers handle non-standard IDIM
+C on INTEGER*2 operands, which presumably can be
+C extrapolated into understanding how the compiler
+C generally treats specific intrinsics that are passed
+C arguments not of the correct types.
+C
+C If your compiler implements INTEGER*2 and INTEGER
+C as the same type, change all INTEGER*2 below to
+C INTEGER*1.
+C
+ INTEGER*2 I0, I4
+ INTEGER I1, I2, I3
+ INTEGER*2 ISMALL, ILARGE
+ INTEGER*2 ITOOLG, ITWO
+ INTEGER*2 ITMP
+ LOGICAL L2, L3, L4
+C
+C Find smallest INTEGER*2 number.
+C
+ ISMALL=0
+ 10 I0 = ISMALL-1
+ IF ((I0 .GE. ISMALL) .OR. (I0+1 .NE. ISMALL)) GOTO 20
+ ISMALL = I0
+ GOTO 10
+ 20 CONTINUE
+C
+C Find largest INTEGER*2 number.
+C
+ ILARGE=0
+ 30 I0 = ILARGE+1
+ IF ((I0 .LE. ILARGE) .OR. (I0-1 .NE. ILARGE)) GOTO 40
+ ILARGE = I0
+ GOTO 30
+ 40 CONTINUE
+C
+C Multiplying by two adds stress to the situation.
+C
+ ITWO = 2
+C
+C Need a number that, added to -2, is too wide to fit in I*2.
+C
+ ITOOLG = ISMALL
+C
+C Use IDIM the straightforward way.
+C
+ I1 = IDIM (ILARGE, ISMALL) * ITWO + ITOOLG
+C
+C Calculate result for first interpretation.
+C
+ I2 = (INT (ILARGE) - INT (ISMALL)) * ITWO + ITOOLG
+C
+C Calculate result for second interpretation.
+C
+ ITMP = ILARGE - ISMALL
+ I3 = (INT (ITMP)) * ITWO + ITOOLG
+C
+C Calculate result for third interpretation.
+C
+ I4 = (ILARGE - ISMALL) * ITWO + ITOOLG
+C
+C Print results.
+C
+ PRINT *, 'ILARGE=', ILARGE
+ PRINT *, 'ITWO=', ITWO
+ PRINT *, 'ITOOLG=', ITOOLG
+ PRINT *, 'ISMALL=', ISMALL
+ PRINT *, 'I1=', I1
+ PRINT *, 'I2=', I2
+ PRINT *, 'I3=', I3
+ PRINT *, 'I4=', I4
+ PRINT *
+ L2 = (I1 .EQ. I2)
+ L3 = (I1 .EQ. I3)
+ L4 = (I1 .EQ. I4)
+ IF (L2 .AND. .NOT.L3 .AND. .NOT.L4) THEN
+ PRINT *, 'Interp 1: IDIM(I*2,I*2) => IDIM(INT(I*2),INT(I*2))'
+ STOP
+ END IF
+ IF (L3 .AND. .NOT.L2 .AND. .NOT.L4) THEN
+ PRINT *, 'Interp 2: IDIM(I*2,I*2) => INT(DIM(I*2,I*2))'
+ STOP
+ END IF
+ IF (L4 .AND. .NOT.L2 .AND. .NOT.L3) THEN
+ PRINT *, 'Interp 3: IDIM(I*2,I*2) => DIM(I*2,I*2)'
+ STOP
+ END IF
+ PRINT *, 'Results need careful analysis.'
+ END
+@end smallexample
+
+No future version of the GNU Fortran language
+will likely permit specific intrinsic invocations with wrong-typed
+arguments (such as @code{IDIM} in the above example), since
+it has been determined that disagreements exist among
+many production compilers on the interpretation of
+such invocations.
+These disagreements strongly suggest that Fortran programmers,
+and certainly existing Fortran programs, disagree about the
+meaning of such invocations.
+
+The first version of @samp{JCB002} didn't accommodate some compilers'
+treatment of @samp{INT(I1-I2)} where @samp{I1} and @samp{I2} are
+@code{INTEGER*2}.
+In such a case, these compilers apparently convert both
+operands to @code{INTEGER*4} and then do an @code{INTEGER*4} subtraction,
+instead of doing an @code{INTEGER*2} subtraction on the
+original values in @samp{I1} and @samp{I2}.
+
+However, the results of the careful analyses done on the outputs
+of programs compiled by these various compilers show that they
+all implement either @samp{Interp 1} or @samp{Interp 2} above.
+
+Specifically, it is believed that the new version of @samp{JCB002}
+above will confirm that:
+
+@itemize @bullet
+@item
+Digital Semiconductor (``DEC'') Alpha OSF/1, HP-UX 10.0.1, AIX 3.2.5
+@code{f77} compilers all implement @samp{Interp 1}.
+
+@item
+IRIX 5.3 @code{f77} compiler implements @samp{Interp 2}.
+
+@item
+Solaris 2.5, SunOS 4.1.3, DECstation ULTRIX 4.3,
+and IRIX 6.1 @code{f77} compilers all implement @samp{Interp 3}.
+@end itemize
+
+If you get different results than the above for the stated
+compilers, or have results for other compilers that might be
+worth adding to the above list, please let us know the details
+(compiler product, version, machine, results, and so on).
+
+@node REAL() and AIMAG() of Complex
+@subsection @code{REAL()} and @code{AIMAG()} of Complex
+@cindex REAL intrinsic
+@cindex intrinsics, REAL
+@cindex AIMAG intrinsic
+@cindex intrinsics, AIMAG
+
+The GNU Fortran language disallows @code{REAL(@var{expr})}
+and @code{AIMAG(@var{expr})},
+where @var{expr} is any @code{COMPLEX} type other than @code{COMPLEX(KIND=1)},
+except when they are used in the following way:
+
+@example
+REAL(REAL(@var{expr}))
+REAL(AIMAG(@var{expr}))
+@end example
+
+@noindent
+The above forms explicitly specify that the desired effect
+is to convert the real or imaginary part of @var{expr}, which might
+be some @code{REAL} type other than @code{REAL(KIND=1)},
+to type @code{REAL(KIND=1)},
+and have that serve as the value of the expression.
+
+The GNU Fortran language offers clearly named intrinsics to extract the
+real and imaginary parts of a complex entity without any
+conversion:
+
+@example
+REALPART(@var{expr})
+IMAGPART(@var{expr})
+@end example
+
+To express the above using typical extended FORTRAN 77,
+use the following constructs
+(when @var{expr} is @code{COMPLEX(KIND=2)}):
+
+@example
+DBLE(@var{expr})
+DIMAG(@var{expr})
+@end example
+
+The FORTRAN 77 language offers no way
+to explicitly specify the real and imaginary parts of a complex expression of
+arbitrary type, apparently as a result of requiring support for
+only one @code{COMPLEX} type (@code{COMPLEX(KIND=1)}).
+The concepts of converting an expression to type @code{REAL(KIND=1)} and
+of extracting the real part of a complex expression were
+thus ``smooshed'' by FORTRAN 77 into a single intrinsic, since
+they happened to have the exact same effect in that language
+(due to having only one @code{COMPLEX} type).
+
+@emph{Note:} When @samp{-ff90} is in effect,
+@code{g77} treats @samp{REAL(@var{expr})}, where @var{expr} is of
+type @code{COMPLEX}, as @samp{REALPART(@var{expr})},
+whereas with @samp{-fugly-complex -fno-f90} in effect, it is
+treated as @samp{REAL(REALPART(@var{expr}))}.
+
+@xref{Ugly Complex Part Extraction}, for more information.
+
+@node CMPLX() of DOUBLE PRECISION
+@subsection @code{CMPLX()} of @code{DOUBLE PRECISION}
+@cindex CMPLX intrinsic
+@cindex intrinsics, CMPLX
+
+In accordance with Fortran 90 and at least some (perhaps all)
+other compilers, the GNU Fortran language defines @code{CMPLX()}
+as always returning a result that is type @code{COMPLEX(KIND=1)}.
+
+This means @samp{CMPLX(D1,D2)}, where @samp{D1} and @samp{D2}
+are @code{REAL(KIND=2)} (@code{DOUBLE PRECISION}), is treated as:
+
+@example
+CMPLX(SNGL(D1), SNGL(D2))
+@end example
+
+(It was necessary for Fortran 90 to specify this behavior
+for @code{DOUBLE PRECISION} arguments, since that is
+the behavior mandated by FORTRAN 77.)
+
+The GNU Fortran language also provides the @code{DCMPLX()} intrinsic,
+which is provided by some FORTRAN 77 compilers to construct
+a @code{DOUBLE COMPLEX} entity from of @code{DOUBLE PRECISION}
+operands.
+However, this solution does not scale well when more @code{COMPLEX} types
+(having various precisions and ranges) are offered by Fortran implementations.
+
+Fortran 90 extends the @code{CMPLX()} intrinsic by adding
+an extra argument used to specify the desired kind of complex
+result.
+However, this solution is somewhat awkward to use, and
+@code{g77} currently does not support it.
+
+The GNU Fortran language provides a simple way to build a complex
+value out of two numbers, with the precise type of the value
+determined by the types of the two numbers (via the usual
+type-promotion mechanism):
+
+@example
+COMPLEX(@var{real}, @var{imag})
+@end example
+
+When @var{real} and @var{imag} are the same @code{REAL} types, @code{COMPLEX()}
+performs no conversion other than to put them together to form a
+complex result of the same (complex version of real) type.
+
+@xref{Complex Intrinsic}, for more information.
+
+@node MIL-STD 1753
+@subsection MIL-STD 1753 Support
+@cindex MIL-STD 1753
+
+The GNU Fortran language includes the MIL-STD 1753 intrinsics
+@code{BTEST}, @code{IAND}, @code{IBCLR}, @code{IBITS},
+@code{IBSET}, @code{IEOR}, @code{IOR}, @code{ISHFT},
+@code{ISHFTC}, @code{MVBITS}, and @code{NOT}.
+
+@node f77/f2c Intrinsics
+@subsection @code{f77}/@code{f2c} Intrinsics
+
+The bit-manipulation intrinsics supported by traditional
+@code{f77} and by @code{f2c} are available in the GNU Fortran language.
+These include @code{AND}, @code{LSHIFT}, @code{OR}, @code{RSHIFT},
+and @code{XOR}.
+
+Also supported are the intrinsics @code{CDABS},
+@code{CDCOS}, @code{CDEXP}, @code{CDLOG}, @code{CDSIN},
+@code{CDSQRT}, @code{DCMPLX}, @code{DCONJG}, @code{DFLOAT},
+@code{DIMAG}, @code{DREAL}, and @code{IMAG},
+@code{ZABS}, @code{ZCOS}, @code{ZEXP}, @code{ZLOG}, @code{ZSIN},
+and @code{ZSQRT}.
+
+@node Table of Intrinsic Functions
+@subsection Table of Intrinsic Functions
+@cindex intrinsics, table of
+@cindex table of intrinsics
+
+(Corresponds to Section 15.10 of ANSI X3.9-1978 FORTRAN 77.)
+
+The GNU Fortran language adds various functions, subroutines, types,
+and arguments to the set of intrinsic functions in ANSI FORTRAN 77.
+The complete set of intrinsics supported by the GNU Fortran language
+is described below.
+
+Note that a name is not treated as that of an intrinsic if it is
+specified in an @code{EXTERNAL} statement in the same program unit;
+if a command-line option is used to disable the groups to which
+the intrinsic belongs; or if the intrinsic is not named in an
+@code{INTRINSIC} statement and a command-line option is used to
+hide the groups to which the intrinsic belongs.
+
+So, it is recommended that any reference in a program unit to
+an intrinsic procedure that is not a standard FORTRAN 77
+intrinsic be accompanied by an appropriate @code{INTRINSIC}
+statement in that program unit.
+This sort of defensive programming makes it more
+likely that an implementation will issue a diagnostic rather
+than generate incorrect code for such a reference.
+
+The terminology used below is based on that of the Fortran 90
+standard, so that the text may be more concise and accurate:
+
+@itemize @bullet
+@item
+@code{OPTIONAL} means the argument may be omitted.
+
+@item
+@samp{A-1, A-2, @dots{}, A-n} means more than one argument
+(generally named @samp{A}) may be specified.
+
+@item
+@samp{scalar} means the argument must not be an array (must
+be a variable or array element, or perhaps a constant if expressions
+are permitted).
+
+@item
+@samp{DIMENSION(4)} means the argument must be an array having 4 elements.
+
+@item
+@code{INTENT(IN)} means the argument must be an expression
+(such as a constant or a variable that is defined upon invocation
+of the intrinsic).
+
+@item
+@code{INTENT(OUT)} means the argument must be definable by the
+invocation of the intrinsic (that is, must not be a constant nor
+an expression involving operators other than array reference and
+substring reference).
+
+@item
+@code{INTENT(INOUT)} means the argument must be defined prior to,
+and definable by, invocation of the intrinsic (a combination of
+the requirements of @code{INTENT(IN)} and @code{INTENT(OUT)}.
+
+@item
+@xref{Kind Notation}, for an explanation of @code{KIND}.
+@end itemize
+
+@ifinfo
+(Note that the empty lines appearing in the menu below
+are not intentional---they result from a bug in the
+GNU @code{makeinfo} program@dots{}a program that, if it
+did not exist, would leave this document in far worse shape!)
+@end ifinfo
+
+@c The actual documentation for intrinsics comes from
+@c intdoc.texi, which in turn is automatically generated
+@c from the internal g77 tables in intrin.def _and_ the
+@c largely hand-written text in intdoc.h. So, if you want
+@c to change or add to existing documentation on intrinsics,
+@c you probably want to edit intdoc.h.
+@c
+@set familyF77
+@set familyGNU
+@set familyASC
+@set familyMIL
+@set familyF90
+@clear familyVXT
+@clear familyFVZ
+@set familyF2C
+@set familyF2U
+@clear familyBADU77
+@include intdoc.texi
+
+@node Scope and Classes of Names
+@section Scope and Classes of Symbolic Names
+@cindex symbolic names
+@cindex scope
+
+(The following information augments or overrides the information in
+Chapter 18 of ANSI X3.9-1978 FORTRAN 77 in specifying the GNU Fortran
+language.
+Chapter 18 of that document otherwise serves as the basis
+for the relevant aspects of GNU Fortran.)
+
+@menu
+* Underscores in Symbol Names::
+@end menu
+
+@node Underscores in Symbol Names
+@subsection Underscores in Symbol Names
+@cindex underscores
+
+Underscores (@samp{_}) are accepted in symbol names after the first
+character (which must be a letter).
+
+@node I/O
+@section I/O
+
+@cindex dollar sign
+A dollar sign at the end of an output format specification suppresses
+the newline at the end of the output.
+
+@cindex <> edit descriptor
+@cindex edit descriptor, <>
+Edit descriptors in @code{FORMAT} statements may contain compile-time
+@code{INTEGER} constant expressions in angle brackets, such as
+@smallexample
+10 FORMAT (I<WIDTH>)
+@end smallexample
+
+The @code{OPEN} specifier @code{NAME=} is equivalent to @code{FILE=}.
+
+These Fortran 90 features are supported:
+@itemize @bullet
+@item
+@cindex Z edit descriptor
+@cindex edit descriptor, Z
+The @code{Z} edit descriptor is supported.
+@item
+The @code{FILE=} specifier may be omitted in an @code{OPEN} statement if
+@code{STATUS='SCRATCH'} is supplied. The @code{STATUS='REPLACE'}
+specifier is supported.
+@end itemize
+
+@node Fortran 90 Features
+@section Fortran 90 Features
+@cindex Fortran 90
+
+For convenience this section collects a list (probably incomplete) of
+the Fortran 90 features supported by the GNU Fortran language, even if
+they are documented elsewhere.
+@c makeinfo 1.68 objects to the nested parens
+@ifnotinfo
+@xref{Characters Lines Sequence,,{Characters, Lines, and Execution Sequence}},
+@end ifnotinfo
+@ifinfo
+@xref{Characters Lines Sequence},
+@end ifinfo
+for information on additional fixed source form lexical issues. In
+addition, the free source form is supported through the
+@cindex @samp{-ffree-form}
+@samp{-ffree-form} option. Other Fortran 90 features can be turned on
+by the
+@cindex @samp{-ff90}
+@samp{-ff90} option, @ref{Fortran 90}. For information on the Fortran
+90 intrinsics available @ref{Table of Intrinsic Functions}.
+
+@table @asis
+@item Automatic arrays in procedures
+@item Character assignments
+@cindex character assignments
+In character assignments, the variable being assigned may occur on the
+right hand side of the assignment.
+@item Character strings
+@cindex double quoted character constants
+Strings may have zero length and substrings of character constants are
+permitted. Character constants may be enclosed in double quotes
+(@code{"}) as well as single quotes. @xref{Character Type}.
+@item Construct names
+(Symbolic tags on blocks.) @xref{Construct Names }.
+@item @code{CYCLE} and @code{EXIT}
+@xref{CYCLE and EXIT,,The @code{CYCLE} and @code{EXIT} Statements}.
+@item @code{DOUBLE COMPLEX}
+@xref{DOUBLE COMPLEX,,@code{DOUBLE COMPLEX} Statement
+}.
+@item @code{DO WHILE}
+@xref{DO WHILE}.
+@item @code{END} decoration
+@xref{Statements}.
+@item @code{END DO}
+@xref{END DO}.
+@item @code{KIND}
+@item @code{IMPLICIT NONE}
+@item @code{INCLUDE} statements
+@xref{INCLUDE}.
+@item List directed and namelist i/o on internal files
+@item Binary, octal and hexadecimal constants
+These are supported more generally than required by Fortran 90.
+@xref{Integer Type}.
+@item @code{NAMELIST}
+@xref{NAMELIST}.
+@item @code{OPEN} specifiers
+@code{STATUS='REPLACE'} is supported.
+@item Relational operators
+The operators @code{<}, @code{<=}, @code{==}, @code{/=}, @code{>} and
+@code{>=} may be used instead of @code{.LT.}, @code{.LE.}, @code{.EQ.},
+@code{.NE.}, @code{.GT.} and @code{.GE.} respectively.
+@item @code{SELECT CASE}
+Not fully implemented. @xref{SELECT CASE on CHARACTER Type,,
+@code{SELECT CASE} on @code{CHARACTER} Type}.
+@item Specification statements
+A limited subset of the Fortran 90 syntax and semantics for variable
+declarations is supported, including @code{KIND}. @xref{Kind Notation}.
+(@code{KIND} is of limited usefulness in the absence of the
+@code{KIND}-related intrinsics, since these intrinsics permit writing
+more widely portable code.) An example of supported @code{KIND} usage
+is:
+@smallexample
+INTEGER (KIND=1) :: FOO=1, BAR=2
+CHARACTER (LEN=3) FOO
+@end smallexample
+@code{PARAMETER} and @code{DIMENSION} attributes aren't supported.
+@end table
+
+@node Other Dialects
+@chapter Other Dialects
+
+GNU Fortran supports a variety of features that are not
+considered part of the GNU Fortran language itself, but
+are representative of various dialects of Fortran that
+@code{g77} supports in whole or in part.
+
+Any of the features listed below might be disallowed by
+@code{g77} unless some command-line option is specified.
+Currently, some of the features are accepted using the
+default invocation of @code{g77}, but that might change
+in the future.
+
+@emph{Note: This portion of the documentation definitely needs a lot
+of work!}
+
+@menu
+* Source Form:: Details of fixed-form and free-form source.
+* Trailing Comment:: Use of @samp{/*} to start a comment.
+* Debug Line:: Use of @samp{D} in column 1.
+* Dollar Signs:: Use of @samp{$} in symbolic names.
+* Case Sensitivity:: Uppercase and lowercase in source files.
+* VXT Fortran:: @dots{}versus the GNU Fortran language.
+* Fortran 90:: @dots{}versus the GNU Fortran language.
+* Pedantic Compilation:: Enforcing the standard.
+* Distensions:: Misfeatures supported by GNU Fortran.
+@end menu
+
+@node Source Form
+@section Source Form
+@cindex source file format
+@cindex source form
+@cindex files, source
+@cindex source code
+@cindex code, source
+@cindex fixed form
+@cindex free form
+
+GNU Fortran accepts programs written in either fixed form or
+free form.
+
+Fixed form
+corresponds to ANSI FORTRAN 77 (plus popular extensions, such as
+allowing tabs) and Fortran 90's fixed form.
+
+Free form corresponds to
+Fortran 90's free form (though possibly not entirely up-to-date, and
+without complaining about some things that for which Fortran 90 requires
+diagnostics, such as the spaces in the constant in @samp{R = 3 . 1}).
+
+The way a Fortran compiler views source files depends entirely on the
+implementation choices made for the compiler, since those choices
+are explicitly left to the implementation by the published Fortran
+standards.
+GNU Fortran currently tries to be somewhat like a few popular compilers
+(@code{f2c}, Digital (``DEC'') Fortran, and so on), though a cleaner default
+definition along with more
+flexibility offered by command-line options is likely to be offered
+in version 0.6.
+
+This section describes how @code{g77} interprets source lines.
+
+@menu
+* Carriage Returns:: Carriage returns ignored.
+* Tabs:: Tabs converted to spaces.
+* Short Lines:: Short lines padded with spaces (fixed-form only).
+* Long Lines:: Long lines truncated.
+* Ampersands:: Special Continuation Lines.
+@end menu
+
+@node Carriage Returns
+@subsection Carriage Returns
+@cindex carriage returns
+
+Carriage returns (@samp{\r}) in source lines are ignored.
+This is somewhat different from @code{f2c}, which seems to treat them as
+spaces outside character/Hollerith constants, and encodes them as @samp{\r}
+inside such constants.
+
+@node Tabs
+@subsection Tabs
+@cindex tab characters
+
+A source line with a @key{TAB} character anywhere in it is treated as
+entirely significant---however long it is---instead of ending in
+column 72 (for fixed-form source) or 132 (for free-form source).
+This also is different from @code{f2c}, which encodes tabs as
+@samp{\t} (the ASCII @key{TAB} character) inside character
+and Hollerith constants, but nevertheless seems to treat the column
+position as if it had been affected by the canonical tab positioning.
+
+@code{g77} effectively
+translates tabs to the appropriate number of spaces (a la the default
+for the UNIX @code{expand} command) before doing any other processing, other
+than (currently) noting whether a tab was found on a line and using this
+information to decide how to interpret the length of the line and continued
+constants.
+
+Note that this default behavior probably will change for version 0.6,
+when it will presumably be available via a command-line option.
+The default as of version 0.6 is planned to be a ``pure visual''
+model, where tabs are immediately
+converted to spaces and otherwise have no effect, so the way a typical
+user sees source lines produces a consistent result no matter how the
+spacing in those source lines is actually implemented via tabs, spaces,
+and trailing tabs/spaces before newline.
+Command-line options are likely to be added to specify whether all or
+just-tabbed lines are to be extended to 132 or full input-line length,
+and perhaps even an option will be added to specify the truncated-line
+behavior to which some Digital compilers default (and which affects
+the way continued character/Hollerith constants are interpreted).
+
+@node Short Lines
+@subsection Short Lines
+@cindex short source lines
+@cindex space-padding
+@cindex spaces
+@cindex source lines, short
+@cindex lines, short
+
+Source lines shorter than the applicable fixed-form length are treated as
+if they were padded with spaces to that length.
+(None of this is relevant to source files written in free form.)
+
+This affects only
+continued character and Hollerith constants, and is a different
+interpretation than provided by some other popular compilers
+(although a bit more consistent with the traditional punched-card
+basis of Fortran and the way the Fortran standard expressed fixed
+source form).
+
+@code{g77} might someday offer an option to warn about cases where differences
+might be seen as a result of this treatment, and perhaps an option to
+specify the alternate behavior as well.
+
+Note that this padding cannot apply to lines that are effectively of
+infinite length---such lines are specified using command-line options
+like @samp{-ffixed-line-length-none}, for example.
+
+@node Long Lines
+@subsection Long Lines
+@cindex long source lines
+@cindex truncation
+@cindex lines, long
+@cindex source lines, long
+
+Source lines longer than the applicable length are truncated to that
+length.
+Currently, @code{g77} does not warn if the truncated characters are
+not spaces, to accommodate existing code written for systems that
+treated truncated text as commentary (especially in columns 73 through 80).
+
+@xref{Fortran Dialect Options,,Options Controlling Fortran Dialect},
+for information on the @samp{-ffixed-line-length-@var{n}} option,
+which can be used to set the line length applicable to fixed-form
+source files.
+
+@node Ampersands
+@subsection Ampersand Continuation Line
+@cindex ampersand continuation line
+@cindex continuation line, ampersand
+
+A @samp{&} in column 1 of fixed-form source denotes an arbitrary-length
+continuation line, imitating the behavior of @code{f2c}.
+
+@node Trailing Comment
+@section Trailing Comment
+
+@cindex trailing comment
+@cindex comment, trailing
+@cindex /*
+@code{g77} supports use of @samp{/*} to start a trailing
+comment.
+In the GNU Fortran language, @samp{!} is used for this purpose.
+
+@samp{/*} is not in the GNU Fortran language
+because the use of @samp{/*} in a program might
+suggest to some readers that a block, not trailing, comment is
+started (and thus ended by @samp{*/}, not end of line),
+since that is the meaning of @samp{/*} in C.
+
+Also, such readers might think they can use @samp{//} to start
+a trailing comment as an alternative to @samp{/*}, but
+@samp{//} already denotes concatenation, and such a ``comment''
+might actually result in a program that compiles without
+error (though it would likely behave incorrectly).
+
+@node Debug Line
+@section Debug Line
+@cindex debug line
+@cindex comment line, debug
+
+Use of @samp{D} or @samp{d} as the first character (column 1) of
+a source line denotes a debug line.
+
+In turn, a debug line is treated as either a comment line
+or a normal line, depending on whether debug lines are enabled.
+
+When treated as a comment line, a line beginning with @samp{D} or
+@samp{d} is treated as if it the first character was @samp{C} or @samp{c}, respectively.
+When treated as a normal line, such a line is treated as if
+the first character was @key{SPC} (space).
+
+(Currently, @code{g77} provides no means for treating debug
+lines as normal lines.)
+
+@node Dollar Signs
+@section Dollar Signs in Symbol Names
+@cindex dollar sign
+@cindex $
+
+Dollar signs (@samp{$}) are allowed in symbol names (after the first character)
+when the @samp{-fdollar-ok} option is specified.
+
+@node Case Sensitivity
+@section Case Sensitivity
+@cindex case sensitivity
+@cindex source file format
+@cindex code, source
+@cindex source code
+@cindex uppercase letters
+@cindex lowercase letters
+@cindex letters, uppercase
+@cindex letters, lowercase
+
+GNU Fortran offers the programmer way too much flexibility in deciding
+how source files are to be treated vis-a-vis uppercase and lowercase
+characters.
+There are 66 useful settings that affect case sensitivity, plus 10
+settings that are nearly useless, with the remaining 116 settings
+being either redundant or useless.
+
+None of these settings have any effect on the contents of comments
+(the text after a @samp{c} or @samp{C} in Column 1, for example)
+or of character or Hollerith constants.
+Note that things like the @samp{E} in the statement
+@samp{CALL FOO(3.2E10)} and the @samp{TO} in @samp{ASSIGN 10 TO LAB}
+are considered built-in keywords, and so are affected by
+these settings.
+
+Low-level switches are identified in this section as follows:
+
+@itemize @w{}
+@item A
+Source Case Conversion:
+
+@itemize @w{}
+@item 0
+Preserve (see Note 1)
+@item 1
+Convert to Upper Case
+@item 2
+Convert to Lower Case
+@end itemize
+
+@item B
+Built-in Keyword Matching:
+
+@itemize @w{}
+@item 0
+Match Any Case (per-character basis)
+@item 1
+Match Upper Case Only
+@item 2
+Match Lower Case Only
+@item 3
+Match InitialCaps Only (see tables for spellings)
+@end itemize
+
+@item C
+Built-in Intrinsic Matching:
+
+@itemize @w{}
+@item 0
+Match Any Case (per-character basis)
+@item 1
+Match Upper Case Only
+@item 2
+Match Lower Case Only
+@item 3
+Match InitialCaps Only (see tables for spellings)
+@end itemize
+
+@item D
+User-defined Symbol Possibilities (warnings only):
+
+@itemize @w{}
+@item 0
+Allow Any Case (per-character basis)
+@item 1
+Allow Upper Case Only
+@item 2
+Allow Lower Case Only
+@item 3
+Allow InitialCaps Only (see Note 2)
+@end itemize
+@end itemize
+
+Note 1: @code{g77} eventually will support @code{NAMELIST} in a manner that is
+consistent with these source switches---in the sense that input will be
+expected to meet the same requirements as source code in terms
+of matching symbol names and keywords (for the exponent letters).
+
+Currently, however, @code{NAMELIST} is supported by @code{libg2c},
+which uppercases @code{NAMELIST} input and symbol names for matching.
+This means not only that @code{NAMELIST} output currently shows symbol
+(and keyword) names in uppercase even if lower-case source
+conversion (option A2) is selected, but that @code{NAMELIST} cannot be
+adequately supported when source case preservation (option A0)
+is selected.
+
+If A0 is selected, a warning message will be
+output for each @code{NAMELIST} statement to this effect.
+The behavior
+of the program is undefined at run time if two or more symbol names
+appear in a given @code{NAMELIST} such that the names are identical
+when converted to upper case (e.g. @samp{NAMELIST /X/ VAR, Var, var}).
+For complete and total elegance, perhaps there should be a warning
+when option A2 is selected, since the output of NAMELIST is currently
+in uppercase but will someday be lowercase (when a @code{libg77} is written),
+but that seems to be overkill for a product in beta test.
+
+Note 2: Rules for InitialCaps names are:
+
+@itemize --
+@item
+Must be a single uppercase letter, @strong{or}
+@item
+Must start with an uppercase letter and contain at least one
+lowercase letter.
+@end itemize
+
+So @samp{A}, @samp{Ab}, @samp{ABc}, @samp{AbC}, and @samp{Abc} are
+valid InitialCaps names, but @samp{AB}, @samp{A2}, and @samp{ABC} are
+not.
+Note that most, but not all, built-in names meet these
+requirements---the exceptions are some of the two-letter format
+specifiers, such as @samp{BN} and @samp{BZ}.
+
+Here are the names of the corresponding command-line options:
+
+@smallexample
+A0: -fsource-case-preserve
+A1: -fsource-case-upper
+A2: -fsource-case-lower
+
+B0: -fmatch-case-any
+B1: -fmatch-case-upper
+B2: -fmatch-case-lower
+B3: -fmatch-case-initcap
+
+C0: -fintrin-case-any
+C1: -fintrin-case-upper
+C2: -fintrin-case-lower
+C3: -fintrin-case-initcap
+
+D0: -fsymbol-case-any
+D1: -fsymbol-case-upper
+D2: -fsymbol-case-lower
+D3: -fsymbol-case-initcap
+@end smallexample
+
+Useful combinations of the above settings, along with abbreviated
+option names that set some of these combinations all at once:
+
+@smallexample
+ 1: A0-- B0--- C0--- D0--- -fcase-preserve
+ 2: A0-- B0--- C0--- D-1--
+ 3: A0-- B0--- C0--- D--2-
+ 4: A0-- B0--- C0--- D---3
+ 5: A0-- B0--- C-1-- D0---
+ 6: A0-- B0--- C-1-- D-1--
+ 7: A0-- B0--- C-1-- D--2-
+ 8: A0-- B0--- C-1-- D---3
+ 9: A0-- B0--- C--2- D0---
+10: A0-- B0--- C--2- D-1--
+11: A0-- B0--- C--2- D--2-
+12: A0-- B0--- C--2- D---3
+13: A0-- B0--- C---3 D0---
+14: A0-- B0--- C---3 D-1--
+15: A0-- B0--- C---3 D--2-
+16: A0-- B0--- C---3 D---3
+17: A0-- B-1-- C0--- D0---
+18: A0-- B-1-- C0--- D-1--
+19: A0-- B-1-- C0--- D--2-
+20: A0-- B-1-- C0--- D---3
+21: A0-- B-1-- C-1-- D0---
+22: A0-- B-1-- C-1-- D-1-- -fcase-strict-upper
+23: A0-- B-1-- C-1-- D--2-
+24: A0-- B-1-- C-1-- D---3
+25: A0-- B-1-- C--2- D0---
+26: A0-- B-1-- C--2- D-1--
+27: A0-- B-1-- C--2- D--2-
+28: A0-- B-1-- C--2- D---3
+29: A0-- B-1-- C---3 D0---
+30: A0-- B-1-- C---3 D-1--
+31: A0-- B-1-- C---3 D--2-
+32: A0-- B-1-- C---3 D---3
+33: A0-- B--2- C0--- D0---
+34: A0-- B--2- C0--- D-1--
+35: A0-- B--2- C0--- D--2-
+36: A0-- B--2- C0--- D---3
+37: A0-- B--2- C-1-- D0---
+38: A0-- B--2- C-1-- D-1--
+39: A0-- B--2- C-1-- D--2-
+40: A0-- B--2- C-1-- D---3
+41: A0-- B--2- C--2- D0---
+42: A0-- B--2- C--2- D-1--
+43: A0-- B--2- C--2- D--2- -fcase-strict-lower
+44: A0-- B--2- C--2- D---3
+45: A0-- B--2- C---3 D0---
+46: A0-- B--2- C---3 D-1--
+47: A0-- B--2- C---3 D--2-
+48: A0-- B--2- C---3 D---3
+49: A0-- B---3 C0--- D0---
+50: A0-- B---3 C0--- D-1--
+51: A0-- B---3 C0--- D--2-
+52: A0-- B---3 C0--- D---3
+53: A0-- B---3 C-1-- D0---
+54: A0-- B---3 C-1-- D-1--
+55: A0-- B---3 C-1-- D--2-
+56: A0-- B---3 C-1-- D---3
+57: A0-- B---3 C--2- D0---
+58: A0-- B---3 C--2- D-1--
+59: A0-- B---3 C--2- D--2-
+60: A0-- B---3 C--2- D---3
+61: A0-- B---3 C---3 D0---
+62: A0-- B---3 C---3 D-1--
+63: A0-- B---3 C---3 D--2-
+64: A0-- B---3 C---3 D---3 -fcase-initcap
+65: A-1- B01-- C01-- D01-- -fcase-upper
+66: A--2 B0-2- C0-2- D0-2- -fcase-lower
+@end smallexample
+
+Number 22 is the ``strict'' ANSI FORTRAN 77 model wherein all input
+(except comments, character constants, and Hollerith strings) must
+be entered in uppercase.
+Use @samp{-fcase-strict-upper} to specify this
+combination.
+
+Number 43 is like Number 22 except all input must be lowercase. Use
+@samp{-fcase-strict-lower} to specify this combination.
+
+Number 65 is the ``classic'' ANSI FORTRAN 77 model as implemented on many
+non-UNIX machines whereby all the source is translated to uppercase.
+Use @samp{-fcase-upper} to specify this combination.
+
+Number 66 is the ``canonical'' UNIX model whereby all the source is
+translated to lowercase.
+Use @samp{-fcase-lower} to specify this combination.
+
+There are a few nearly useless combinations:
+
+@smallexample
+67: A-1- B01-- C01-- D--2-
+68: A-1- B01-- C01-- D---3
+69: A-1- B01-- C--23 D01--
+70: A-1- B01-- C--23 D--2-
+71: A-1- B01-- C--23 D---3
+72: A--2 B01-- C0-2- D-1--
+73: A--2 B01-- C0-2- D---3
+74: A--2 B01-- C-1-3 D0-2-
+75: A--2 B01-- C-1-3 D-1--
+76: A--2 B01-- C-1-3 D---3
+@end smallexample
+
+The above allow some programs to be compiled but with restrictions that
+make most useful programs impossible: Numbers 67 and 72 warn about
+@emph{any} user-defined symbol names (such as @samp{SUBROUTINE FOO});
+Numbers
+68 and 73 warn about any user-defined symbol names longer than one
+character that don't have at least one non-alphabetic character after
+the first;
+Numbers 69 and 74 disallow any references to intrinsics;
+and Numbers 70, 71, 75, and 76 are combinations of the restrictions in
+67+69, 68+69, 72+74, and 73+74, respectively.
+
+All redundant combinations are shown in the above tables anyplace
+where more than one setting is shown for a low-level switch.
+For example, @samp{B0-2-} means either setting 0 or 2 is valid for switch B.
+The ``proper'' setting in such a case is the one that copies the setting
+of switch A---any other setting might slightly reduce the speed of
+the compiler, though possibly to an unmeasurable extent.
+
+All remaining combinations are useless in that they prevent successful
+compilation of non-null source files (source files with something other
+than comments).
+
+@node VXT Fortran
+@section VXT Fortran
+
+@cindex VXT extensions
+@cindex extensions, VXT
+@code{g77} supports certain constructs that
+have different meanings in VXT Fortran than they
+do in the GNU Fortran language.
+
+Generally, this manual uses the invented term VXT Fortran to refer
+VAX FORTRAN (circa v4).
+That compiler offered many popular features, though not necessarily
+those that are specific to the VAX processor architecture,
+the VMS operating system,
+or Digital Equipment Corporation's Fortran product line.
+(VAX and VMS probably are trademarks of Digital Equipment
+Corporation.)
+
+An extension offered by a Digital Fortran product that also is
+offered by several other Fortran products for different kinds of
+systems is probably going to be considered for inclusion in @code{g77}
+someday, and is considered a VXT Fortran feature.
+
+The @samp{-fvxt} option generally specifies that, where
+the meaning of a construct is ambiguous (means one thing
+in GNU Fortran and another in VXT Fortran), the VXT Fortran
+meaning is to be assumed.
+
+@menu
+* Double Quote Meaning:: @samp{"2000} as octal constant.
+* Exclamation Point:: @samp{!} in column 6.
+@end menu
+
+@node Double Quote Meaning
+@subsection Meaning of Double Quote
+@cindex double quotes
+@cindex character constants
+@cindex constants, character
+@cindex octal constants
+@cindex constants, octal
+
+@code{g77} treats double-quote (@samp{"})
+as beginning an octal constant of @code{INTEGER(KIND=1)} type
+when the @code{-fvxt} option is specified.
+The form of this octal constant is
+
+@example
+"@var{octal-digits}
+@end example
+
+@noindent
+where @var{octal-digits} is a nonempty string of characters in
+the set @samp{01234567}.
+
+For example, the @code{-fvxt} option permits this:
+
+@example
+PRINT *, "20
+END
+@end example
+
+@noindent
+The above program would print the value @samp{16}.
+
+@xref{Integer Type}, for information on the preferred construct
+for integer constants specified using GNU Fortran's octal notation.
+
+(In the GNU Fortran language, the double-quote character (@samp{"})
+delimits a character constant just as does apostrophe (@samp{'}).
+There is no way to allow
+both constructs in the general case, since statements like
+@samp{PRINT *,"2000 !comment?"} would be ambiguous.)
+
+@node Exclamation Point
+@subsection Meaning of Exclamation Point in Column 6
+@cindex exclamation points
+@cindex continuation character
+@cindex characters, continuation
+@cindex comment character
+@cindex characters, comment
+
+@code{g77} treats an exclamation point (@samp{!}) in column 6 of
+a fixed-form source file
+as a continuation character rather than
+as the beginning of a comment
+(as it does in any other column)
+when the @code{-fvxt} option is specified.
+
+The following program, when run, prints a message indicating
+whether it is interpreted according to GNU Fortran (and Fortran 90)
+rules or VXT Fortran rules:
+
+@smallexample
+C234567 (This line begins in column 1.)
+ I = 0
+ !1
+ IF (I.EQ.0) PRINT *, ' I am a VXT Fortran program'
+ IF (I.EQ.1) PRINT *, ' I am a Fortran 90 program'
+ IF (I.LT.0 .OR. I.GT.1) PRINT *, ' I am a HAL 9000 computer'
+ END
+@end smallexample
+
+(In the GNU Fortran and Fortran 90 languages, exclamation point is
+a valid character and, unlike space (@key{SPC}) or zero (@samp{0}),
+marks a line as a continuation line when it appears in column 6.)
+
+@node Fortran 90
+@section Fortran 90
+@cindex compatibility, Fortran 90
+@cindex Fortran 90 compatibility
+
+The GNU Fortran language includes a number of features that are
+part of Fortran 90, even when the @samp{-ff90} option is not specified.
+The features enabled by @samp{-ff90} are intended to be those that,
+when @samp{-ff90} is not specified, would have another
+meaning to @code{g77}---usually meaning something invalid in the
+GNU Fortran language.
+
+So, the purpose of @samp{-ff90} is not to specify whether @code{g77} is
+to gratuitously reject Fortran 90 constructs.
+The @samp{-pedantic} option specified with @samp{-fno-f90} is intended
+to do that, although its implementation is certainly incomplete at
+this point.
+
+When @samp{-ff90} is specified:
+
+@itemize @bullet
+@item
+The type of @samp{REAL(@var{expr})} and @samp{AIMAG(@var{expr})},
+where @var{expr} is @code{COMPLEX} type,
+is the same type as the real part of @var{expr}.
+
+For example, assuming @samp{Z} is type @code{COMPLEX(KIND=2)},
+@samp{REAL(Z)} would return a value of type @code{REAL(KIND=2)},
+not of type @code{REAL(KIND=1)}, since @samp{-ff90} is specified.
+@end itemize
+
+@node Pedantic Compilation
+@section Pedantic Compilation
+@cindex pedantic compilation
+@cindex compilation, pedantic
+
+The @samp{-fpedantic} command-line option specifies that @code{g77}
+is to warn about code that is not standard-conforming.
+This is useful for finding
+some extensions @code{g77} accepts that other compilers might not accept.
+(Note that the @samp{-pedantic} and @samp{-pedantic-errors} options
+always imply @samp{-fpedantic}.)
+
+With @samp{-fno-f90} in force, ANSI FORTRAN 77 is used as the standard
+for conforming code.
+With @samp{-ff90} in force, Fortran 90 is used.
+
+The constructs for which @code{g77} issues diagnostics when @samp{-fpedantic}
+and @samp{-fno-f90} are in force are:
+
+@itemize @bullet
+@item
+Automatic arrays, as in
+
+@example
+SUBROUTINE X(N)
+REAL A(N)
+@dots{}
+@end example
+
+@noindent
+where @samp{A} is not listed in any @code{ENTRY} statement,
+and thus is not a dummy argument.
+
+@item
+The commas in @samp{READ (5), I} and @samp{WRITE (10), J}.
+
+These commas are disallowed by FORTRAN 77, but, while strictly
+superfluous, are syntactically elegant,
+especially given that commas are required in statements such
+as @samp{READ 99, I} and @samp{PRINT *, J}.
+Many compilers permit the superfluous commas for this reason.
+
+@item
+@code{DOUBLE COMPLEX}, either explicitly or implicitly.
+
+An explicit use of this type is via a @code{DOUBLE COMPLEX} or
+@code{IMPLICIT DOUBLE COMPLEX} statement, for examples.
+
+An example of an implicit use is the expression @samp{C*D},
+where @samp{C} is @code{COMPLEX(KIND=1)}
+and @samp{D} is @code{DOUBLE PRECISION}.
+This expression is prohibited by ANSI FORTRAN 77
+because the rules of promotion would suggest that it
+produce a @code{DOUBLE COMPLEX} result---a type not
+provided for by that standard.
+
+@item
+Automatic conversion of numeric
+expressions to @code{INTEGER(KIND=1)} in contexts such as:
+
+@itemize --
+@item
+Array-reference indexes.
+@item
+Alternate-return values.
+@item
+Computed @code{GOTO}.
+@item
+@code{FORMAT} run-time expressions (not yet supported).
+@item
+Dimension lists in specification statements.
+@item
+Numbers for I/O statements (such as @samp{READ (UNIT=3.2), I})
+@item
+Sizes of @code{CHARACTER} entities in specification statements.
+@item
+Kind types in specification entities (a Fortran 90 feature).
+@item
+Initial, terminal, and incrementation parameters for implied-@code{DO}
+constructs in @code{DATA} statements.
+@end itemize
+
+@item
+Automatic conversion of @code{LOGICAL} expressions to @code{INTEGER}
+in contexts such as arithmetic @code{IF} (where @code{COMPLEX}
+expressions are disallowed anyway).
+
+@item
+Zero-size array dimensions, as in:
+
+@example
+INTEGER I(10,20,4:2)
+@end example
+
+@item
+Zero-length @code{CHARACTER} entities, as in:
+
+@example
+PRINT *, ''
+@end example
+
+@item
+Substring operators applied to character constants and named
+constants, as in:
+
+@example
+PRINT *, 'hello'(3:5)
+@end example
+
+@item
+Null arguments passed to statement function, as in:
+
+@example
+PRINT *, FOO(,3)
+@end example
+
+@item
+Disagreement among program units regarding whether a given @code{COMMON}
+area is @code{SAVE}d (for targets where program units in a single source
+file are ``glued'' together as they typically are for UNIX development
+environments).
+
+@item
+Disagreement among program units regarding the size of a
+named @code{COMMON} block.
+
+@item
+Specification statements following first @code{DATA} statement.
+
+(In the GNU Fortran language, @samp{DATA I/1/} may be followed by @samp{INTEGER J},
+but not @samp{INTEGER I}.
+The @samp{-fpedantic} option disallows both of these.)
+
+@item
+Semicolon as statement separator, as in:
+
+@example
+CALL FOO; CALL BAR
+@end example
+@c
+@c @item
+@c Comma before list of I/O items in @code{WRITE}
+@c @c, @code{ENCODE}, @code{DECODE}, and @code{REWRITE}
+@c statements, as with @code{READ} (as explained above).
+
+@item
+Use of @samp{&} in column 1 of fixed-form source (to indicate continuation).
+
+@item
+Use of @code{CHARACTER} constants to initialize numeric entities, and vice
+versa.
+
+@item
+Expressions having two arithmetic operators in a row, such
+as @samp{X*-Y}.
+@end itemize
+
+If @samp{-fpedantic} is specified along with @samp{-ff90}, the
+following constructs result in diagnostics:
+
+@itemize @bullet
+@item
+Use of semicolon as a statement separator on a line
+that has an @code{INCLUDE} directive.
+@end itemize
+
+@node Distensions
+@section Distensions
+@cindex distensions
+@cindex ugly features
+@cindex features, ugly
+
+The @samp{-fugly-*} command-line options determine whether certain
+features supported by VAX FORTRAN and other such compilers, but considered
+too ugly to be in code that can be changed to use safer and/or more
+portable constructs, are accepted.
+These are humorously referred to as ``distensions'',
+extensions that just plain look ugly in the harsh light of day.
+
+@emph{Note:} The @samp{-fugly} option, which currently serves
+as shorthand to enable all of the distensions below, is likely to
+be removed in a future version of @code{g77}.
+That's because it's likely new distensions will be added that
+conflict with existing ones in terms of assigning meaning to
+a given chunk of code.
+(Also, it's pretty clear that users should not use @samp{-fugly}
+as shorthand when the next release of @code{g77} might add a
+distension to that that causes their existing code, when recompiled,
+to behave differently---perhaps even fail to compile or run
+correctly.)
+
+@menu
+* Ugly Implicit Argument Conversion:: Disabled via @samp{-fno-ugly-args}.
+* Ugly Assumed-Size Arrays:: Enabled via @samp{-fugly-assumed}.
+* Ugly Null Arguments:: Enabled via @samp{-fugly-comma}.
+* Ugly Complex Part Extraction:: Enabled via @samp{-fugly-complex}.
+* Ugly Conversion of Initializers:: Disabled via @samp{-fno-ugly-init}.
+* Ugly Integer Conversions:: Enabled via @samp{-fugly-logint}.
+* Ugly Assigned Labels:: Enabled via @samp{-fugly-assign}.
+@end menu
+
+@node Ugly Implicit Argument Conversion
+@subsection Implicit Argument Conversion
+@cindex Hollerith constants
+@cindex constants, Hollerith
+
+The @samp{-fno-ugly-args} option disables
+passing typeless and Hollerith constants as actual arguments
+in procedure invocations.
+For example:
+
+@example
+CALL FOO(4HABCD)
+CALL BAR('123'O)
+@end example
+
+@noindent
+These constructs can be too easily used to create non-portable
+code, but are not considered as ``ugly'' as others.
+Further, they are widely used in existing Fortran source code
+in ways that often are quite portable.
+Therefore, they are enabled by default.
+
+@node Ugly Assumed-Size Arrays
+@subsection Ugly Assumed-Size Arrays
+@cindex arrays, assumed-size
+@cindex assumed-size arrays
+@cindex DIMENSION X(1)
+
+The @samp{-fugly-assumed} option enables
+the treatment of any array with a final dimension specified as @samp{1}
+as an assumed-size array, as if @samp{*} had been specified
+instead.
+
+For example, @samp{DIMENSION X(1)} is treated as if it
+had read @samp{DIMENSION X(*)} if @samp{X} is listed as
+a dummy argument in a preceding @code{SUBROUTINE}, @code{FUNCTION},
+or @code{ENTRY} statement in the same program unit.
+
+Use an explicit lower bound to avoid this interpretation.
+For example, @samp{DIMENSION X(1:1)} is never treated as if
+it had read @samp{DIMENSION X(*)} or @samp{DIMENSION X(1:*)}.
+Nor is @samp{DIMENSION X(2-1)} affected by this option,
+since that kind of expression is unlikely to have been
+intended to designate an assumed-size array.
+
+This option is used to prevent warnings being issued about apparent
+out-of-bounds reference such as @samp{X(2) = 99}.
+
+It also prevents the array from being used in contexts that
+disallow assumed-size arrays, such as @samp{PRINT *,X}.
+In such cases, a diagnostic is generated and the source file is
+not compiled.
+
+The construct affected by this option is used only in old code
+that pre-exists the widespread acceptance of adjustable and assumed-size
+arrays in the Fortran community.
+
+@emph{Note:} This option does not affect how @samp{DIMENSION X(1)} is
+treated if @samp{X} is listed as a dummy argument only
+@emph{after} the @code{DIMENSION} statement (presumably in
+an @code{ENTRY} statement).
+For example, @samp{-fugly-assumed} has no effect on the
+following program unit:
+
+@example
+SUBROUTINE X
+REAL A(1)
+RETURN
+ENTRY Y(A)
+PRINT *, A
+END
+@end example
+
+@node Ugly Complex Part Extraction
+@subsection Ugly Complex Part Extraction
+@cindex complex values
+@cindex real part
+@cindex imaginary part
+
+The @samp{-fugly-complex} option enables
+use of the @code{REAL()} and @code{AIMAG()}
+intrinsics with arguments that are
+@code{COMPLEX} types other than @code{COMPLEX(KIND=1)}.
+
+With @samp{-ff90} in effect, these intrinsics return
+the unconverted real and imaginary parts (respectively)
+of their argument.
+
+With @samp{-fno-f90} in effect, these intrinsics convert
+the real and imaginary parts to @code{REAL(KIND=1)}, and return
+the result of that conversion.
+
+Due to this ambiguity, the GNU Fortran language defines
+these constructs as invalid, except in the specific
+case where they are entirely and solely passed as an
+argument to an invocation of the @code{REAL()} intrinsic.
+For example,
+
+@example
+REAL(REAL(Z))
+@end example
+
+@noindent
+is permitted even when @samp{Z} is @code{COMPLEX(KIND=2)}
+and @samp{-fno-ugly-complex} is in effect, because the
+meaning is clear.
+
+@code{g77} enforces this restriction, unless @samp{-fugly-complex}
+is specified, in which case the appropriate interpretation is
+chosen and no diagnostic is issued.
+
+@xref{CMPAMBIG}, for information on how to cope with existing
+code with unclear expectations of @code{REAL()} and @code{AIMAG()}
+with @code{COMPLEX(KIND=2)} arguments.
+
+@xref{RealPart Intrinsic}, for information on the @code{REALPART()}
+intrinsic, used to extract the real part of a complex expression
+without conversion.
+@xref{ImagPart Intrinsic}, for information on the @code{IMAGPART()}
+intrinsic, used to extract the imaginary part of a complex expression
+without conversion.
+
+@node Ugly Null Arguments
+@subsection Ugly Null Arguments
+@cindex trailing commas
+@cindex commas, trailing
+@cindex null arguments
+@cindex arguments, null
+
+The @samp{-fugly-comma} option enables use of a single trailing comma
+to mean ``pass an extra trailing null argument''
+in a list of actual arguments to an external procedure,
+and use of an empty list of arguments to such a procedure
+to mean ``pass a single null argument''.
+
+@cindex omitting arguments
+@cindex arguments, omitting
+(Null arguments often are used in some procedure-calling
+schemes to indicate omitted arguments.)
+
+For example, @samp{CALL FOO(,)} means ``pass
+two null arguments'', rather than ``pass one null argument''.
+Also, @samp{CALL BAR()} means ``pass one null argument''.
+
+This construct is considered ``ugly'' because it does not
+provide an elegant way to pass a single null argument
+that is syntactically distinct from passing no arguments.
+That is, this construct changes the meaning of code that
+makes no use of the construct.
+
+So, with @samp{-fugly-comma} in force, @samp{CALL FOO()}
+and @samp{I = JFUNC()} pass a single null argument, instead
+of passing no arguments as required by the Fortran 77 and
+90 standards.
+
+@emph{Note:} Many systems gracefully allow the case
+where a procedure call passes one extra argument that the
+called procedure does not expect.
+
+So, in practice, there might be no difference in
+the behavior of a program that does @samp{CALL FOO()}
+or @samp{I = JFUNC()} and is compiled with @samp{-fugly-comma}
+in force as compared to its behavior when compiled
+with the default, @samp{-fno-ugly-comma}, in force,
+assuming @samp{FOO} and @samp{JFUNC} do not expect any
+arguments to be passed.
+
+@node Ugly Conversion of Initializers
+@subsection Ugly Conversion of Initializers
+
+The constructs disabled by @samp{-fno-ugly-init} are:
+
+@itemize @bullet
+@cindex Hollerith constants
+@cindex constants, Hollerith
+@item
+Use of Hollerith and typeless constants in contexts where they set
+initial (compile-time) values for variables, arrays, and named
+constants---that is, @code{DATA} and @code{PARAMETER} statements, plus
+type-declaration statements specifying initial values.
+
+Here are some sample initializations that are disabled by the
+@samp{-fno-ugly-init} option:
+
+@example
+PARAMETER (VAL='9A304FFE'X)
+REAL*8 STRING/8HOUTPUT00/
+DATA VAR/4HABCD/
+@end example
+
+@cindex character constants
+@cindex constants, character
+@item
+In the same contexts as above, use of character constants to initialize
+numeric items and vice versa (one constant per item).
+
+Here are more sample initializations that are disabled by the
+@samp{-fno-ugly-init} option:
+
+@example
+INTEGER IA
+CHARACTER BELL
+PARAMETER (IA = 'A')
+PARAMETER (BELL = 7)
+@end example
+
+@item
+Use of Hollerith and typeless constants on the right-hand side
+of assignment statements to numeric types, and in other
+contexts (such as passing arguments in invocations of
+intrinsic procedures and statement functions) that
+are treated as assignments to known types (the dummy
+arguments, in these cases).
+
+Here are sample statements that are disabled by the
+@samp{-fno-ugly-init} option:
+
+@example
+IVAR = 4HABCD
+PRINT *, IMAX0(2HAB, 2HBA)
+@end example
+@end itemize
+
+The above constructs, when used,
+can tend to result in non-portable code.
+But, they are widely used in existing Fortran code in ways
+that often are quite portable.
+Therefore, they are enabled by default.
+
+@node Ugly Integer Conversions
+@subsection Ugly Integer Conversions
+
+The constructs enabled via @samp{-fugly-logint} are:
+
+@itemize @bullet
+@item
+Automatic conversion between @code{INTEGER} and @code{LOGICAL} as
+dictated by
+context (typically implies nonportable dependencies on how a
+particular implementation encodes @code{.TRUE.} and @code{.FALSE.}).
+
+@item
+Use of a @code{LOGICAL} variable in @code{ASSIGN} and assigned-@code{GOTO}
+statements.
+@end itemize
+
+The above constructs are disabled by default because use
+of them tends to lead to non-portable code.
+Even existing Fortran code that uses that often turns out
+to be non-portable, if not outright buggy.
+
+Some of this is due to differences among implementations as
+far as how @code{.TRUE.} and @code{.FALSE.} are encoded as
+@code{INTEGER} values---Fortran code that assumes a particular
+coding is likely to use one of the above constructs, and is
+also likely to not work correctly on implementations using
+different encodings.
+
+@xref{Equivalence Versus Equality}, for more information.
+
+@node Ugly Assigned Labels
+@subsection Ugly Assigned Labels
+@cindex ASSIGN statement
+@cindex statements, ASSIGN
+@cindex assigned labels
+@cindex pointers
+
+The @samp{-fugly-assign} option forces @code{g77} to use the
+same storage for assigned labels as it would for a normal
+assignment to the same variable.
+
+For example, consider the following code fragment:
+
+@example
+I = 3
+ASSIGN 10 TO I
+@end example
+
+@noindent
+Normally, for portability and improved diagnostics, @code{g77}
+reserves distinct storage for a ``sibling'' of @samp{I}, used
+only for @code{ASSIGN} statements to that variable (along with
+the corresponding assigned-@code{GOTO} and assigned-@samp{FORMAT}-I/O
+statements that reference the variable).
+
+However, some code (that violates the ANSI FORTRAN 77 standard)
+attempts to copy assigned labels among variables involved with
+@code{ASSIGN} statements, as in:
+
+@example
+ASSIGN 10 TO I
+ISTATE(5) = I
+@dots{}
+J = ISTATE(ICUR)
+GOTO J
+@end example
+
+@noindent
+Such code doesn't work under @code{g77} unless @samp{-fugly-assign}
+is specified on the command-line, ensuring that the value of @code{I}
+referenced in the second line is whatever value @code{g77} uses
+to designate statement label @samp{10}, so the value may be
+copied into the @samp{ISTATE} array, later retrieved into a
+variable of the appropriate type (@samp{J}), and used as the target of
+an assigned-@code{GOTO} statement.
+
+@emph{Note:} To avoid subtle program bugs,
+when @samp{-fugly-assign} is specified,
+@code{g77} requires the type of variables
+specified in assigned-label contexts
+@emph{must} be the same type returned by @code{%LOC()}.
+On many systems, this type is effectively the same
+as @code{INTEGER(KIND=1)}, while, on others, it is
+effectively the same as @code{INTEGER(KIND=2)}.
+
+Do @emph{not} depend on @code{g77} actually writing valid pointers
+to these variables, however.
+While @code{g77} currently chooses that implementation, it might
+be changed in the future.
+
+@xref{Assigned Statement Labels,,Assigned Statement Labels (ASSIGN and GOTO)},
+for implementation details on assigned-statement labels.
+
+@node Compiler
+@chapter The GNU Fortran Compiler
+
+The GNU Fortran compiler, @code{g77}, supports programs written
+in the GNU Fortran language and in some other dialects of Fortran.
+
+Some aspects of how @code{g77} works are universal regardless
+of dialect, and yet are not properly part of the GNU Fortran
+language itself.
+These are described below.
+
+@emph{Note: This portion of the documentation definitely needs a lot
+of work!}
+
+@menu
+* Compiler Limits::
+* Compiler Types::
+* Compiler Constants::
+* Compiler Intrinsics::
+@end menu
+
+@node Compiler Limits
+@section Compiler Limits
+@cindex limits, compiler
+@cindex compiler limits
+
+@code{g77}, as with GNU tools in general, imposes few arbitrary restrictions
+on lengths of identifiers, number of continuation lines, number of external
+symbols in a program, and so on.
+
+@cindex options, -Nl
+@cindex -Nl option
+@cindex options, -Nx
+@cindex -Nx option
+For example, some other Fortran compiler have an option
+(such as @samp{-Nl@var{x}}) to increase the limit on the
+number of continuation lines.
+Also, some Fortran compilation systems have an option
+(such as @samp{-Nx@var{x}}) to increase the limit on the
+number of external symbols.
+
+@code{g77}, @code{gcc}, and GNU @code{ld} (the GNU linker) have
+no equivalent options, since they do not impose arbitrary
+limits in these areas.
+
+@cindex rank, maximum
+@cindex maximum rank
+@cindex number of dimensions, maximum
+@cindex maximum number of dimensions
+@code{g77} does currently limit the number of dimensions in an array
+to the same degree as do the Fortran standards---seven (7).
+This restriction might well be lifted in a future version.
+
+@node Compiler Types
+@section Compiler Types
+@cindex types, of data
+@cindex data types
+
+Fortran implementations have a fair amount of freedom given them by the
+standard as far as how much storage space is used and how much precision
+and range is offered by the various types such as @code{LOGICAL(KIND=1)},
+@code{INTEGER(KIND=1)}, @code{REAL(KIND=1)}, @code{REAL(KIND=2)},
+@code{COMPLEX(KIND=1)}, and @code{CHARACTER}.
+Further, many compilers offer so-called @samp{*@var{n}} notation, but
+the interpretation of @var{n} varies across compilers and target architectures.
+
+The standard requires that @code{LOGICAL(KIND=1)}, @code{INTEGER(KIND=1)},
+and @code{REAL(KIND=1)}
+occupy the same amount of storage space, and that @code{COMPLEX(KIND=1)}
+and @code{REAL(KIND=2)} take twice as much storage space as @code{REAL(KIND=1)}.
+Further, it requires that @code{COMPLEX(KIND=1)}
+entities be ordered such that when a @code{COMPLEX(KIND=1)} variable is
+storage-associated (such as via @code{EQUIVALENCE})
+with a two-element @code{REAL(KIND=1)} array named @samp{R}, @samp{R(1)}
+corresponds to the real element and @samp{R(2)} to the imaginary
+element of the @code{COMPLEX(KIND=1)} variable.
+
+(Few requirements as to precision or ranges of any of these are
+placed on the implementation, nor is the relationship of storage sizes of
+these types to the @code{CHARACTER} type specified, by the standard.)
+
+@code{g77} follows the above requirements, warning when compiling
+a program requires placement of items in memory that contradict the
+requirements of the target architecture.
+(For example, a program can require placement of a @code{REAL(KIND=2)}
+on a boundary that is not an even multiple of its size, but still an
+even multiple of the size of a @code{REAL(KIND=1)} variable.
+On some target architectures, using the canonical
+mapping of Fortran types to underlying architectural types, such
+placement is prohibited by the machine definition or
+the Application Binary Interface (ABI) in force for
+the configuration defined for building @code{gcc} and @code{g77}.
+@code{g77} warns about such
+situations when it encounters them.)
+
+@code{g77} follows consistent rules for configuring the mapping between Fortran
+types, including the @samp{*@var{n}} notation, and the underlying architectural
+types as accessed by a similarly-configured applicable version of the
+@code{gcc} compiler.
+These rules offer a widely portable, consistent Fortran/C
+environment, although they might well conflict with the expectations of
+users of Fortran compilers designed and written for particular
+architectures.
+
+These rules are based on the configuration that is in force for the
+version of @code{gcc} built in the same release as @code{g77} (and
+which was therefore used to build both the @code{g77} compiler
+components and the @code{libg2c} run-time library):
+
+@table @code
+@cindex REAL(KIND=1) type
+@cindex types, REAL(KIND=1)
+@item REAL(KIND=1)
+Same as @code{float} type.
+
+@cindex REAL(KIND=2) type
+@cindex types, REAL(KIND=2)
+@item REAL(KIND=2)
+Same as whatever floating-point type that is twice the size
+of a @code{float}---usually, this is a @code{double}.
+
+@cindex INTEGER(KIND=1) type
+@cindex types, INTEGER(KIND=1)
+@item INTEGER(KIND=1)
+Same as an integral type that is occupies the same amount
+of memory storage as @code{float}---usually, this is either
+an @code{int} or a @code{long int}.
+
+@cindex LOGICAL(KIND=1) type
+@cindex types, LOGICAL(KIND=1)
+@item LOGICAL(KIND=1)
+Same @code{gcc} type as @code{INTEGER(KIND=1)}.
+
+@cindex INTEGER(KIND=2) type
+@cindex types, INTEGER(KIND=2)
+@item INTEGER(KIND=2)
+Twice the size, and usually nearly twice the range,
+as @code{INTEGER(KIND=1)}---usually, this is either
+a @code{long int} or a @code{long long int}.
+
+@cindex LOGICAL(KIND=2) type
+@cindex types, LOGICAL(KIND=2)
+@item LOGICAL(KIND=2)
+Same @code{gcc} type as @code{INTEGER(KIND=2)}.
+
+@cindex INTEGER(KIND=3) type
+@cindex types, INTEGER(KIND=3)
+@item INTEGER(KIND=3)
+Same @code{gcc} type as signed @code{char}.
+
+@cindex LOGICAL(KIND=3) type
+@cindex types, LOGICAL(KIND=3)
+@item LOGICAL(KIND=3)
+Same @code{gcc} type as @code{INTEGER(KIND=3)}.
+
+@cindex INTEGER(KIND=6) type
+@cindex types, INTEGER(KIND=6)
+@item INTEGER(KIND=6)
+Twice the size, and usually nearly twice the range,
+as @code{INTEGER(KIND=3)}---usually, this is
+a @code{short}.
+
+@cindex LOGICAL(KIND=6) type
+@cindex types, LOGICAL(KIND=6)
+@item LOGICAL(KIND=6)
+Same @code{gcc} type as @code{INTEGER(KIND=6)}.
+
+@cindex COMPLEX(KIND=1) type
+@cindex types, COMPLEX(KIND=1)
+@item COMPLEX(KIND=1)
+Two @code{REAL(KIND=1)} scalars (one for the real part followed by
+one for the imaginary part).
+
+@cindex COMPLEX(KIND=2) type
+@cindex types, COMPLEX(KIND=2)
+@item COMPLEX(KIND=2)
+Two @code{REAL(KIND=2)} scalars.
+
+@cindex *@var{n} notation
+@item @var{numeric-type}*@var{n}
+(Where @var{numeric-type} is any type other than @code{CHARACTER}.)
+Same as whatever @code{gcc} type occupies @var{n} times the storage
+space of a @code{gcc} @code{char} item.
+
+@cindex DOUBLE PRECISION type
+@cindex types, DOUBLE PRECISION
+@item DOUBLE PRECISION
+Same as @code{REAL(KIND=2)}.
+
+@cindex DOUBLE COMPLEX type
+@cindex types, DOUBLE COMPLEX
+@item DOUBLE COMPLEX
+Same as @code{COMPLEX(KIND=2)}.
+@end table
+
+Note that the above are proposed correspondences and might change
+in future versions of @code{g77}---avoid writing code depending
+on them.
+
+Other types supported by @code{g77}
+are derived from gcc types such as @code{char}, @code{short},
+@code{int}, @code{long int}, @code{long long int}, @code{long double},
+and so on.
+That is, whatever types @code{gcc} already supports, @code{g77} supports
+now or probably will support in a future version.
+The rules for the @samp{@var{numeric-type}*@var{n}} notation
+apply to these types,
+and new values for @samp{@var{numeric-type}(KIND=@var{n})} will be
+assigned in a way that encourages clarity, consistency, and portability.
+
+@node Compiler Constants
+@section Compiler Constants
+@cindex constants
+@cindex types, constants
+
+@code{g77} strictly assigns types to @emph{all} constants not
+documented as ``typeless'' (typeless constants including @samp{'1'Z},
+for example).
+Many other Fortran compilers attempt to assign types to typed constants
+based on their context.
+This results in hard-to-find bugs, nonportable
+code, and is not in the spirit (though it strictly follows the letter)
+of the 77 and 90 standards.
+
+@code{g77} might offer, in a future release, explicit constructs by
+which a wider variety of typeless constants may be specified, and/or
+user-requested warnings indicating places where @code{g77} might differ
+from how other compilers assign types to constants.
+
+@xref{Context-Sensitive Constants}, for more information on this issue.
+
+@node Compiler Intrinsics
+@section Compiler Intrinsics
+
+@code{g77} offers an ever-widening set of intrinsics.
+Currently these all are procedures (functions and subroutines).
+
+Some of these intrinsics are unimplemented, but their names reserved
+to reduce future problems with existing code as they are implemented.
+Others are implemented as part of the GNU Fortran language, while
+yet others are provided for compatibility with other dialects of
+Fortran but are not part of the GNU Fortran language.
+
+To manage these distinctions, @code{g77} provides intrinsic @emph{groups},
+a facility that is simply an extension of the intrinsic groups provided
+by the GNU Fortran language.
+
+@menu
+* Intrinsic Groups:: How intrinsics are grouped for easy management.
+* Other Intrinsics:: Intrinsics other than those in the GNU
+ Fortran language.
+@end menu
+
+@node Intrinsic Groups
+@subsection Intrinsic Groups
+@cindex groups of intrinsics
+@cindex intrinsics, groups
+
+A given specific intrinsic belongs in one or more groups.
+Each group is deleted, disabled, hidden, or enabled
+by default or a command-line option.
+The meaning of each term follows.
+
+@table @b
+@cindex deleted intrinsics
+@cindex intrinsics, deleted
+@item Deleted
+No intrinsics are recognized as belonging to that group.
+
+@cindex disabled intrinsics
+@cindex intrinsics, disabled
+@item Disabled
+Intrinsics are recognized as belonging to the group, but
+references to them (other than via the @code{INTRINSIC} statement)
+are disallowed through that group.
+
+@cindex hidden intrinsics
+@cindex intrinsics, hidden
+@item Hidden
+Intrinsics in that group are recognized and enabled (if implemented)
+@emph{only} if the first mention of the actual name of an intrinsic
+in a program unit is in an @code{INTRINSIC} statement.
+
+@cindex enabled intrinsics
+@cindex intrinsics, enabled
+@item Enabled
+Intrinsics in that group are recognized and enabled (if implemented).
+@end table
+
+The distinction between deleting and disabling a group is illustrated
+by the following example.
+Assume intrinsic @samp{FOO} belongs only to group @samp{FGR}.
+If group @samp{FGR} is deleted, the following program unit will
+successfully compile, because @samp{FOO()} will be seen as a
+reference to an external function named @samp{FOO}:
+
+@example
+PRINT *, FOO()
+END
+@end example
+
+@noindent
+If group @samp{FGR} is disabled, compiling the above program will produce
+diagnostics, either because the @samp{FOO} intrinsic is improperly invoked
+or, if properly invoked, it is not enabled.
+To change the above program so it references an external function @samp{FOO}
+instead of the disabled @samp{FOO} intrinsic,
+add the following line to the top:
+
+@example
+EXTERNAL FOO
+@end example
+
+@noindent
+So, deleting a group tells @code{g77} to pretend as though the intrinsics in
+that group do not exist at all, whereas disabling it tells @code{g77} to
+recognize them as (disabled) intrinsics in intrinsic-like contexts.
+
+Hiding a group is like enabling it, but the intrinsic must be first
+named in an @code{INTRINSIC} statement to be considered a reference to the
+intrinsic rather than to an external procedure.
+This might be the ``safest'' way to treat a new group of intrinsics
+when compiling old
+code, because it allows the old code to be generally written as if
+those new intrinsics never existed, but to be changed to use them
+by inserting @code{INTRINSIC} statements in the appropriate places.
+However, it should be the goal of development to use @code{EXTERNAL}
+for all names of external procedures that might be intrinsic names.
+
+If an intrinsic is in more than one group, it is enabled if any of its
+containing groups are enabled; if not so enabled, it is hidden if
+any of its containing groups are hidden; if not so hidden, it is disabled
+if any of its containing groups are disabled; if not so disabled, it is
+deleted.
+This extra complication is necessary because some intrinsics,
+such as @code{IBITS}, belong to more than one group, and hence should be
+enabled if any of the groups to which they belong are enabled, and so
+on.
+
+The groups are:
+
+@cindex intrinsics, groups of
+@cindex groups of intrinsics
+@table @code
+@cindex @code{badu77} intrinsics group
+@item badu77
+UNIX intrinsics having inappropriate forms (usually functions that
+have intended side effects).
+
+@cindex @code{gnu} intrinsics group
+@item gnu
+Intrinsics the GNU Fortran language supports that are extensions to
+the Fortran standards (77 and 90).
+
+@cindex @code{f2c} intrinsics group
+@item f2c
+Intrinsics supported by AT&T's @code{f2c} converter and/or @code{libf2c}.
+
+@cindex @code{f90} intrinsics group
+@item f90
+Fortran 90 intrinsics.
+
+@cindex @code{mil} intrinsics group
+@item mil
+MIL-STD 1753 intrinsics (@code{MVBITS}, @code{IAND}, @code{BTEST}, and so on).
+
+@cindex @code{mil} intrinsics group
+@item unix
+UNIX intrinsics (@code{IARGC}, @code{EXIT}, @code{ERF}, and so on).
+
+@cindex @code{mil} intrinsics group
+@item vxt
+VAX/VMS FORTRAN (current as of v4) intrinsics.
+@end table
+
+@node Other Intrinsics
+@subsection Other Intrinsics
+@cindex intrinsics, others
+@cindex other intrinsics
+
+@code{g77} supports intrinsics other than those in the GNU Fortran
+language proper.
+This set of intrinsics is described below.
+
+@ifinfo
+(Note that the empty lines appearing in the menu below
+are not intentional---they result from a bug in the
+@code{makeinfo} program.)
+@end ifinfo
+
+@c The actual documentation for intrinsics comes from
+@c intdoc.texi, which in turn is automatically generated
+@c from the internal g77 tables in intrin.def _and_ the
+@c largely hand-written text in intdoc.h. So, if you want
+@c to change or add to existing documentation on intrinsics,
+@c you probably want to edit intdoc.h.
+@c
+@clear familyF77
+@clear familyGNU
+@clear familyASC
+@clear familyMIL
+@clear familyF90
+@set familyVXT
+@set familyFVZ
+@clear familyF2C
+@clear familyF2U
+@set familyBADU77
+@include intdoc.texi
+
+@node Other Compilers
+@chapter Other Compilers
+
+An individual Fortran source file can be compiled to
+an object (@file{*.o}) file instead of to the final
+program executable.
+This allows several portions of a program to be compiled
+at different times and linked together whenever a new
+version of the program is needed.
+However, it introduces the issue of @dfn{object compatibility}
+across the various object files (and libraries, or @file{*.a}
+files) that are linked together to produce any particular
+executable file.
+
+Object compatibility is an issue when combining, in one
+program, Fortran code compiled by more than one compiler
+(or more than one configuration of a compiler).
+If the compilers
+disagree on how to transform the names of procedures, there
+will normally be errors when linking such programs.
+Worse, if the compilers agree on naming, but disagree on issues
+like how to pass parameters, return arguments, and lay out
+@code{COMMON} areas, the earliest detected errors might be the
+incorrect results produced by the program (and that assumes
+these errors are detected, which is not always the case).
+
+Normally, @code{g77} generates code that is
+object-compatible with code generated by a version of
+@code{f2c} configured (with, for example, @file{f2c.h} definitions)
+to be generally compatible with @code{g77} as built by @code{gcc}.
+(Normally, @code{f2c} will, by default, conform to the appropriate
+configuration, but it is possible that older or perhaps even newer
+versions of @code{f2c}, or versions having certain configuration changes
+to @code{f2c} internals, will produce object files that are
+incompatible with @code{g77}.)
+
+For example, a Fortran string subroutine
+argument will become two arguments on the C side: a @code{char *}
+and an @code{int} length.
+
+Much of this compatibility results from the fact that
+@code{g77} uses the same run-time library,
+@code{libf2c}, used by @code{f2c},
+though @code{g77} gives its version the name @code{libg2c}
+so as to avoid conflicts when linking,
+installing them in the same directories,
+and so on.
+
+Other compilers might or might not generate code that
+is object-compatible with @code{libg2c} and current @code{g77},
+and some might offer such compatibility only when explicitly
+selected via a command-line option to the compiler.
+
+@emph{Note: This portion of the documentation definitely needs a lot
+of work!}
+
+@menu
+* Dropping f2c Compatibility:: When speed is more important.
+* Compilers Other Than f2c:: Interoperation with code from other compilers.
+@end menu
+
+@node Dropping f2c Compatibility
+@section Dropping @code{f2c} Compatibility
+
+Specifying @samp{-fno-f2c} allows @code{g77} to generate, in
+some cases, faster code, by not needing to allow to the possibility
+of linking with code compiled by @code{f2c}.
+
+For example, this affects how @code{REAL(KIND=1)},
+@code{COMPLEX(KIND=1)}, and @code{COMPLEX(KIND=2)} functions are called.
+With @samp{-fno-f2c}, they are
+compiled as returning the appropriate @code{gcc} type
+(@code{float}, @code{__complex__ float}, @code{__complex__ double},
+in many configurations).
+
+With @samp{-ff2c} in force, they
+are compiled differently (with perhaps slower run-time performance)
+to accommodate the restrictions inherent in @code{f2c}'s use of K&R
+C as an intermediate language---@code{REAL(KIND=1)} functions
+return C's @code{double} type, while @code{COMPLEX} functions return
+@code{void} and use an extra argument pointing to a place for the functions to
+return their values.
+
+It is possible that, in some cases, leaving @samp{-ff2c} in force
+might produce faster code than using @samp{-fno-f2c}.
+Feel free to experiment, but remember to experiment with changing the way
+@emph{entire programs and their Fortran libraries are compiled} at
+a time, since this sort of experimentation affects the interface
+of code generated for a Fortran source file---that is, it affects
+object compatibility.
+
+Note that @code{f2c} compatibility is a fairly static target to achieve,
+though not necessarily perfectly so, since, like @code{g77}, it is
+still being improved.
+However, specifying @samp{-fno-f2c} causes @code{g77}
+to generate code that will probably be incompatible with code
+generated by future versions of @code{g77} when the same option
+is in force.
+You should make sure you are always able to recompile complete
+programs from source code when upgrading to new versions of @code{g77}
+or @code{f2c}, especially when using options such as @samp{-fno-f2c}.
+
+Therefore, if you are using @code{g77} to compile libraries and other
+object files for possible future use and you don't want to require
+recompilation for future use with subsequent versions of @code{g77},
+you might want to stick with @code{f2c} compatibility for now, and
+carefully watch for any announcements about changes to the
+@code{f2c}/@code{libf2c} interface that might affect existing programs
+(thus requiring recompilation).
+
+It is probable that a future version of @code{g77} will not,
+by default, generate object files compatible with @code{f2c},
+and that version probably would no longer use @code{libf2c}.
+If you expect to depend on this compatibility in the
+long term, use the options @samp{-ff2c -ff2c-library} when compiling
+all of the applicable code.
+This should cause future versions of @code{g77} either to produce
+compatible code (at the expense of the availability of some features and
+performance), or at the very least, to produce diagnostics.
+
+(The library @code{g77} produces will no longer be named @file{libg2c}
+when it is no longer generally compatible with @file{libf2c}.
+It will likely be referred to, and, if installed as a distinct
+library, named @code{libg77}, or some other as-yet-unused name.)
+
+@node Compilers Other Than f2c
+@section Compilers Other Than @code{f2c}
+
+On systems with Fortran compilers other than @code{f2c} and @code{g77},
+code compiled by @code{g77} is not expected to work
+well with code compiled by the native compiler.
+(This is true for @code{f2c}-compiled objects as well.)
+Libraries compiled with the native compiler probably will have
+to be recompiled with @code{g77} to be used with @code{g77}-compiled code.
+
+Reasons for such incompatibilities include:
+
+@itemize @bullet
+@item
+There might be differences in the way names of Fortran procedures
+are translated for use in the system's object-file format.
+For example, the statement @samp{CALL FOO} might be compiled
+by @code{g77} to call a procedure the linker @code{ld} sees
+given the name @samp{_foo_}, while the apparently corresponding
+statement @samp{SUBROUTINE FOO} might be compiled by the
+native compiler to define the linker-visible name @samp{_foo},
+or @samp{_FOO_}, and so on.
+
+@item
+There might be subtle type mismatches which cause subroutine arguments
+and function return values to get corrupted.
+
+This is why simply getting @code{g77} to
+transform procedure names the same way a native
+compiler does is not usually a good idea---unless
+some effort has been made to ensure that, aside
+from the way the two compilers transform procedure
+names, everything else about the way they generate
+code for procedure interfaces is identical.
+
+@item
+Native compilers
+use libraries of private I/O routines which will not be available
+at link time unless you have the native compiler---and you would
+have to explicitly ask for them.
+
+For example, on the Sun you
+would have to add @samp{-L/usr/lang/SCx.x -lF77 -lV77} to the link
+command.
+@end itemize
+
+@node Other Languages
+@chapter Other Languages
+
+@emph{Note: This portion of the documentation definitely needs a lot
+of work!}
+
+@menu
+* Interoperating with C and C++::
+@end menu
+
+@node Interoperating with C and C++
+@section Tools and advice for interoperating with C and C++
+
+@cindex C, linking with
+@cindex C++, linking with
+@cindex linking with C
+The following discussion assumes that you are running @code{g77} in @code{f2c}
+compatibility mode, i.e.@: not using @samp{-fno-f2c}.
+It provides some
+advice about quick and simple techniques for linking Fortran and C (or
+C++), the most common requirement.
+For the full story consult the
+description of code generation.
+@xref{Debugging and Interfacing}.
+
+When linking Fortran and C, it's usually best to use @code{g77} to do
+the linking so that the correct libraries are included (including the
+maths one).
+If you're linking with C++ you will want to add
+@samp{-lstdc++}, @samp{-lg++} or whatever.
+If you need to use another
+driver program (or @code{ld} directly),
+you can find out what linkage
+options @code{g77} passes by running @samp{g77 -v}.
+
+@menu
+* C Interfacing Tools::
+* C Access to Type Information::
+* f2c Skeletons and Prototypes::
+* C++ Considerations::
+* Startup Code::
+@end menu
+
+@node C Interfacing Tools
+@subsection C Interfacing Tools
+@pindex f2c
+@cindex cfortran.h
+@cindex Netlib
+Even if you don't actually use it as a compiler, @samp{f2c} from
+@uref{ftp://ftp.netlib.org/f2c/src}, can be a useful tool when you're
+interfacing (linking) Fortran and C@.
+@xref{f2c Skeletons and Prototypes,,Generating Skeletons and Prototypes with @code{f2c}}.
+
+To use @code{f2c} for this purpose you only need retrieve and
+build the @file{src} directory from the distribution, consult the
+@file{README} instructions there for machine-specifics, and install the
+@code{f2c} program on your path.
+
+Something else that might be useful is @samp{cfortran.h} from
+@uref{ftp://zebra/desy.de/cfortran}.
+This is a fairly general tool which
+can be used to generate interfaces for calling in both directions
+between Fortran and C@.
+It can be used in @code{f2c} mode with
+@code{g77}---consult its documentation for details.
+
+@node C Access to Type Information
+@subsection Accessing Type Information in C
+
+@cindex types, Fortran/C
+Generally, C code written to link with
+@code{g77} code---calling and/or being
+called from Fortran---should @samp{#include <g2c.h>} to define the C
+versions of the Fortran types.
+Don't assume Fortran @code{INTEGER} types
+correspond to C @samp{int}s, for instance; instead, declare them as
+@code{integer}, a type defined by @file{g2c.h}.
+@file{g2c.h} is installed where @code{gcc} will find it by
+default, assuming you use a copy of @code{gcc} compatible with
+@code{g77}, probably built at the same time as @code{g77}.
+
+@node f2c Skeletons and Prototypes
+@subsection Generating Skeletons and Prototypes with @code{f2c}
+
+@pindex f2c
+@cindex -fno-second-underscore
+A simple and foolproof way to write @code{g77}-callable C routines---e.g.@: to
+interface with an existing library---is to write a file (named, for
+example, @file{fred.f}) of dummy Fortran
+skeletons comprising just the declaration of the routine(s) and dummy
+arguments plus @samp{END} statements.
+Then run @code{f2c} on file @file{fred.f} to produce @file{fred.c}
+into which you can edit
+useful code, confident the calling sequence is correct, at least.
+(There are some errors otherwise commonly made in generating C
+interfaces with @code{f2c} conventions,
+such as not using @code{doublereal}
+as the return type of a @code{REAL} @code{FUNCTION}.)
+
+@pindex ftnchek
+@code{f2c} also can help with calling Fortran from C, using its
+@samp{-P} option to generate C prototypes appropriate for calling the
+Fortran.@footnote{The files generated like this can also be used for
+inter-unit consistency checking of dummy and actual arguments, although
+the @samp{ftnchek} tool from @uref{ftp://ftp.netlib.org/fortran}
+or @uref{ftp://ftp.dsm.fordham.edu} is
+probably better for this purpose.}
+If the Fortran code containing any
+routines to be called from C is in file @file{joe.f}, use the command
+@kbd{f2c -P joe.f} to generate the file @file{joe.P} containing
+prototype information.
+@code{#include} this in the C which has to call
+the Fortran routines to make sure you get it right.
+
+@xref{Arrays,,Arrays (DIMENSION)}, for information on the differences
+between the way Fortran (including compilers like @code{g77}) and
+C handle arrays.
+
+@node C++ Considerations
+@subsection C++ Considerations
+
+@cindex C++
+@code{f2c} can be used to generate suitable code for compilation with a
+C++ system using the @samp{-C++} option.
+The important thing about linking @code{g77}-compiled
+code with C++ is that the prototypes for the @code{g77}
+routines must specify C linkage to avoid name mangling.
+So, use an @samp{extern "C"} declaration.
+@code{f2c}'s @samp{-C++} option will take care
+of this when generating skeletons or prototype files as above, and also
+avoid clashes with C++ reserved words in addition to those in C@.
+
+@node Startup Code
+@subsection Startup Code
+
+@cindex startup code
+@cindex runtime initialization
+@cindex initialization, runtime
+Unlike with some runtime systems,
+it shouldn't be necessary
+(unless there are bugs)
+to use a Fortran main program unit to ensure the
+runtime---specifically the I/O system---is initialized.
+
+However, to use the @code{g77} intrinsics @code{GETARG} and @code{IARGC},
+either the @code{main} routine from the @file{libg2c} library must be used,
+or the @code{f_setarg} routine
+(new as of @code{egcs} version 1.1 and @code{g77} version 0.5.23)
+must be called with the appropriate @code{argc} and @code{argv} arguments
+prior to the program calling @code{GETARG} or @code{IARGC}.
+
+To provide more flexibility for mixed-language programming
+involving @code{g77} while allowing for shared libraries,
+as of @code{egcs} version 1.1 and @code{g77} version 0.5.23,
+@code{g77}'s @code{main} routine in @code{libg2c}
+does the following, in order:
+
+@enumerate
+@item
+Calls @code{f_setarg}
+with the incoming @code{argc} and @code{argv} arguments,
+in the same order as for @code{main} itself.
+
+This sets up the command-line environment
+for @code{GETARG} and @code{IARGC}.
+
+@item
+Calls @code{f_setsig} (with no arguments).
+
+This sets up the signaling and exception environment.
+
+@item
+Calls @code{f_init} (with no arguments).
+
+This initializes the I/O environment,
+though that should not be necessary,
+as all I/O functions in @code{libf2c}
+are believed to call @code{f_init} automatically,
+if necessary.
+
+(A future version of @code{g77} might skip this explicit step,
+to speed up normal exit of a program.)
+
+@item
+Arranges for @code{f_exit} to be called (with no arguments)
+when the program exits.
+
+This ensures that the I/O environment is properly shut down
+before the program exits normally.
+Otherwise, output buffers might not be fully flushed,
+scratch files might not be deleted, and so on.
+
+The simple way @code{main} does this is
+to call @code{f_exit} itself after calling
+@code{MAIN__} (in the next step).
+
+However, this does not catch the cases where the program
+might call @code{exit} directly,
+instead of using the @code{EXIT} intrinsic
+(implemented as @code{exit_} in @code{libf2c}).
+
+So, @code{main} attempts to use
+the operating environment's @code{onexit} or @code{atexit}
+facility, if available,
+to cause @code{f_exit} to be called automatically
+upon any invocation of @code{exit}.
+
+@item
+Calls @code{MAIN__} (with no arguments).
+
+This starts executing the Fortran main program unit for
+the application.
+(Both @code{g77} and @code{f2c} currently compile a main
+program unit so that its global name is @code{MAIN__}.)
+
+@item
+If no @code{onexit} or @code{atexit} is provided by the system,
+calls @code{f_exit}.
+
+@item
+Calls @code{exit} with a zero argument,
+to signal a successful program termination.
+
+@item
+Returns a zero value to the caller,
+to signal a successful program termination,
+in case @code{exit} doesn't exit on the system.
+@end enumerate
+
+All of the above names are C @code{extern} names,
+i.e.@: not mangled.
+
+When using the @code{main} procedure provided by @code{g77}
+without a Fortran main program unit,
+you need to provide @code{MAIN__}
+as the entry point for your C code.
+(Make sure you link the object file that defines that
+entry point with the rest of your program.)
+
+To provide your own @code{main} procedure
+in place of @code{g77}'s,
+make sure you specify the object file defining that procedure
+@emph{before} @samp{-lg2c} on the @code{g77} command line.
+Since the @samp{-lg2c} option is implicitly provided,
+this is usually straightforward.
+(Use the @samp{--verbose} option to see how and where
+@code{g77} implicitly adds @samp{-lg2c} in a command line
+that will link the program.
+Feel free to specify @samp{-lg2c} explicitly,
+as appropriate.)
+
+However, when providing your own @code{main},
+make sure you perform the appropriate tasks in the
+appropriate order.
+For example, if your @code{main} does not call @code{f_setarg},
+make sure the rest of your application does not call
+@code{GETARG} or @code{IARGC}.
+
+And, if your @code{main} fails to ensure that @code{f_exit}
+is called upon program exit,
+some files might end up incompletely written,
+some scratch files might be left lying around,
+and some existing files being written might be left
+with old data not properly truncated at the end.
+
+Note that, generally, the @code{g77} operating environment
+does not depend on a procedure named @code{MAIN__} actually
+being called prior to any other @code{g77}-compiled code.
+That is, @code{MAIN__} does not, itself,
+set up any important operating-environment characteristics
+upon which other code might depend.
+This might change in future versions of @code{g77},
+with appropriate notification in the release notes.
+
+For more information, consult the source code for the above routines.
+These are in @file{@value{path-libf2c}/libF77/}, named @file{main.c},
+@file{setarg.c}, @file{setsig.c}, @file{getarg_.c}, and @file{iargc_.c}.
+
+Also, the file @file{@value{path-g77}/com.c} contains the code @code{g77}
+uses to open-code (inline) references to @code{IARGC}.
+
+@include g77install.texi
+
+@node Debugging and Interfacing
+@chapter Debugging and Interfacing
+@cindex debugging
+@cindex interfacing
+@cindex calling C routines
+@cindex C routines calling Fortran
+@cindex f2c compatibility
+
+GNU Fortran currently generates code that is object-compatible with
+the @code{f2c} converter.
+Also, it avoids limitations in the current GBE, such as the
+inability to generate a procedure with
+multiple entry points, by generating code that is structured
+differently (in terms of procedure names, scopes, arguments, and
+so on) than might be expected.
+
+As a result, writing code in other languages that calls on, is
+called by, or shares in-memory data with @code{g77}-compiled code generally
+requires some understanding of the way @code{g77} compiles code for
+various constructs.
+
+Similarly, using a debugger to debug @code{g77}-compiled
+code, even if that debugger supports native Fortran debugging, generally
+requires this sort of information.
+
+This section describes some of the basic information on how
+@code{g77} compiles code for constructs involving interfaces to other
+languages and to debuggers.
+
+@emph{Caution:} Much or all of this information pertains to only the current
+release of @code{g77}, sometimes even to using certain compiler options
+with @code{g77} (such as @samp{-fno-f2c}).
+Do not write code that depends on this
+information without clearly marking said code as nonportable and
+subject to review for every new release of @code{g77}.
+This information
+is provided primarily to make debugging of code generated by this
+particular release of @code{g77} easier for the user, and partly to make
+writing (generally nonportable) interface code easier.
+Both of these
+activities require tracking changes in new version of @code{g77} as they
+are installed, because new versions can change the behaviors
+described in this section.
+
+@menu
+* Main Program Unit:: How @code{g77} compiles a main program unit.
+* Procedures:: How @code{g77} constructs parameter lists
+ for procedures.
+* Functions:: Functions returning floating-point or character data.
+* Names:: Naming of user-defined variables, procedures, etc.
+* Common Blocks:: Accessing common variables while debugging.
+* Local Equivalence Areas:: Accessing @code{EQUIVALENCE} while debugging.
+* Complex Variables:: How @code{g77} performs complex arithmetic.
+* Arrays:: Dealing with (possibly multi-dimensional) arrays.
+* Adjustable Arrays:: Special consideration for adjustable arrays.
+* Alternate Entry Points:: How @code{g77} implements alternate @code{ENTRY}.
+* Alternate Returns:: How @code{g77} handles alternate returns.
+* Assigned Statement Labels:: How @code{g77} handles @code{ASSIGN}.
+* Run-time Library Errors:: Meanings of some @code{IOSTAT=} values.
+@end menu
+
+@node Main Program Unit
+@section Main Program Unit (PROGRAM)
+@cindex PROGRAM statement
+@cindex statements, PROGRAM
+
+When @code{g77} compiles a main program unit, it gives it the public
+procedure name @samp{MAIN__}.
+The @code{libg2c} library has the actual @code{main()} procedure
+as is typical of C-based environments, and
+it is this procedure that performs some initial start-up
+activity and then calls @samp{MAIN__}.
+
+Generally, @code{g77} and @code{libg2c} are designed so that you need not
+include a main program unit written in Fortran in your program---it
+can be written in C or some other language.
+Especially for I/O handling, this is the case, although @code{g77} version 0.5.16
+includes a bug fix for @code{libg2c} that solved a problem with using the
+@code{OPEN} statement as the first Fortran I/O activity in a program
+without a Fortran main program unit.
+
+However, if you don't intend to use @code{g77} (or @code{f2c}) to compile
+your main program unit---that is, if you intend to compile a @code{main()}
+procedure using some other language---you should carefully
+examine the code for @code{main()} in @code{libg2c}, found in the source
+file @file{@value{path-libf2c}/libF77/main.c}, to see what kinds of things
+might need to be done by your @code{main()} in order to provide the
+Fortran environment your Fortran code is expecting.
+
+@cindex IARGC() intrinsic
+@cindex intrinsics, IARGC()
+@cindex GETARG() intrinsic
+@cindex intrinsics, GETARG()
+For example, @code{libg2c}'s @code{main()} sets up the information used by
+the @code{IARGC} and @code{GETARG} intrinsics.
+Bypassing @code{libg2c}'s @code{main()}
+without providing a substitute for this activity would mean
+that invoking @code{IARGC} and @code{GETARG} would produce undefined
+results.
+
+@cindex debugging
+@cindex main program unit, debugging
+@cindex main()
+@cindex MAIN__()
+@cindex .gdbinit
+When debugging, one implication of the fact that @code{main()}, which
+is the place where the debugged program ``starts'' from the
+debugger's point of view, is in @code{libg2c} is that you won't be
+starting your Fortran program at a point you recognize as your
+Fortran code.
+
+The standard way to get around this problem is to set a break
+point (a one-time, or temporary, break point will do) at
+the entrance to @samp{MAIN__}, and then run the program.
+A convenient way to do so is to add the @code{gdb} command
+
+@example
+tbreak MAIN__
+@end example
+
+@noindent
+to the file @file{.gdbinit} in the directory in which you're debugging
+(using @code{gdb}).
+
+After doing this, the debugger will see the current execution
+point of the program as at the beginning of the main program
+unit of your program.
+
+Of course, if you really want to set a break point at some
+other place in your program and just start the program
+running, without first breaking at @samp{MAIN__},
+that should work fine.
+
+@node Procedures
+@section Procedures (SUBROUTINE and FUNCTION)
+@cindex procedures
+@cindex SUBROUTINE statement
+@cindex statements, SUBROUTINE
+@cindex FUNCTION statement
+@cindex statements, FUNCTION
+@cindex signature of procedures
+
+Currently, @code{g77} passes arguments via reference---specifically,
+by passing a pointer to the location in memory of a variable, array,
+array element, a temporary location that holds the result of evaluating an
+expression, or a temporary or permanent location that holds the value
+of a constant.
+
+Procedures that accept @code{CHARACTER} arguments are implemented by
+@code{g77} so that each @code{CHARACTER} argument has two actual arguments.
+
+The first argument occupies the expected position in the
+argument list and has the user-specified name.
+This argument
+is a pointer to an array of characters, passed by the caller.
+
+The second argument is appended to the end of the user-specified
+calling sequence and is named @samp{__g77_length_@var{x}}, where @var{x}
+is the user-specified name.
+This argument is of the C type @code{ftnlen}
+(see @file{@value{path-libf2c}/g2c.h.in} for information on that type) and
+is the number of characters the caller has allocated in the
+array pointed to by the first argument.
+
+A procedure will ignore the length argument if @samp{X} is not declared
+@code{CHARACTER*(*)}, because for other declarations, it knows the
+length.
+Not all callers necessarily ``know'' this, however, which
+is why they all pass the extra argument.
+
+The contents of the @code{CHARACTER} argument are specified by the
+address passed in the first argument (named after it).
+The procedure can read or write these contents as appropriate.
+
+When more than one @code{CHARACTER} argument is present in the argument
+list, the length arguments are appended in the order
+the original arguments appear.
+So @samp{CALL FOO('HI','THERE')} is implemented in
+C as @samp{foo("hi","there",2,5);}, ignoring the fact that @code{g77}
+does not provide the trailing null bytes on the constant
+strings (@code{f2c} does provide them, but they are unnecessary in
+a Fortran environment, and you should not expect them to be
+there).
+
+Note that the above information applies to @code{CHARACTER} variables and
+arrays @strong{only}.
+It does @strong{not} apply to external @code{CHARACTER}
+functions or to intrinsic @code{CHARACTER} functions.
+That is, no second length argument is passed to @samp{FOO} in this case:
+
+@example
+CHARACTER X
+EXTERNAL X
+CALL FOO(X)
+@end example
+
+@noindent
+Nor does @samp{FOO} expect such an argument in this case:
+
+@example
+SUBROUTINE FOO(X)
+CHARACTER X
+EXTERNAL X
+@end example
+
+Because of this implementation detail, if a program has a bug
+such that there is disagreement as to whether an argument is
+a procedure, and the type of the argument is @code{CHARACTER}, subtle
+symptoms might appear.
+
+@node Functions
+@section Functions (FUNCTION and RETURN)
+@cindex functions
+@cindex FUNCTION statement
+@cindex statements, FUNCTION
+@cindex RETURN statement
+@cindex statements, RETURN
+@cindex return type of functions
+
+@code{g77} handles in a special way functions that return the following
+types:
+
+@itemize @bullet
+@item
+@code{CHARACTER}
+@item
+@code{COMPLEX}
+@item
+@code{REAL(KIND=1)}
+@end itemize
+
+For @code{CHARACTER}, @code{g77} implements a subroutine (a C function
+returning @code{void})
+with two arguments prepended: @samp{__g77_result}, which the caller passes
+as a pointer to a @code{char} array expected to hold the return value,
+and @samp{__g77_length}, which the caller passes as an @code{ftnlen} value
+specifying the length of the return value as declared in the calling
+program.
+For @code{CHARACTER*(*)}, the called function uses @samp{__g77_length}
+to determine the size of the array that @samp{__g77_result} points to;
+otherwise, it ignores that argument.
+
+For @code{COMPLEX}, when @samp{-ff2c} is in
+force, @code{g77} implements
+a subroutine with one argument prepended: @samp{__g77_result}, which the
+caller passes as a pointer to a variable of the type of the function.
+The called function writes the return value into this variable instead
+of returning it as a function value.
+When @samp{-fno-f2c} is in force,
+@code{g77} implements a @code{COMPLEX} function as @code{gcc}'s
+@samp{__complex__ float} or @samp{__complex__ double} function
+(or an emulation thereof, when @samp{-femulate-complex} is in effect),
+returning the result of the function in the same way as @code{gcc} would.
+
+For @code{REAL(KIND=1)}, when @samp{-ff2c} is in force, @code{g77} implements
+a function that actually returns @code{REAL(KIND=2)} (typically
+C's @code{double} type).
+When @samp{-fno-f2c} is in force, @code{REAL(KIND=1)}
+functions return @code{float}.
+
+@node Names
+@section Names
+@cindex symbol names
+@cindex transformation of symbol names
+
+Fortran permits each implementation to decide how to represent
+names as far as how they're seen in other contexts, such as debuggers
+and when interfacing to other languages, and especially as far
+as how casing is handled.
+
+External names---names of entities that are public, or ``accessible'',
+to all modules in a program---normally have an underscore (@samp{_})
+appended by @code{g77},
+to generate code that is compatible with @code{f2c}.
+External names include names of Fortran things like common blocks,
+external procedures (subroutines and functions, but not including
+statement functions, which are internal procedures), and entry point
+names.
+
+However, use of the @samp{-fno-underscoring} option
+disables this kind of transformation of external names (though inhibiting
+the transformation certainly improves the chances of colliding with
+incompatible externals written in other languages---but that
+might be intentional.
+
+@cindex -fno-underscoring option
+@cindex options, -fno-underscoring
+@cindex -fno-second-underscore option
+@cindex options, -fno-underscoring
+When @samp{-funderscoring} is in force, any name (external or local)
+that already has at least one underscore in it is
+implemented by @code{g77} by appending two underscores.
+(This second underscore can be disabled via the
+@samp{-fno-second-underscore} option.)
+External names are changed this way for @code{f2c} compatibility.
+Local names are changed this way to avoid collisions with external names
+that are different in the source code---@code{f2c} does the same thing, but
+there's no compatibility issue there except for user expectations while
+debugging.
+
+For example:
+
+@example
+Max_Cost = 0
+@end example
+
+@cindex debugging
+@noindent
+Here, a user would, in the debugger, refer to this variable using the
+name @samp{max_cost__} (or @samp{MAX_COST__} or @samp{Max_Cost__},
+as described below).
+(We hope to improve @code{g77} in this regard in the future---don't
+write scripts depending on this behavior!
+Also, consider experimenting with the @samp{-fno-underscoring}
+option to try out debugging without having to massage names by
+hand like this.)
+
+@code{g77} provides a number of command-line options that allow the user
+to control how case mapping is handled for source files.
+The default is the traditional UNIX model for Fortran compilers---names
+are mapped to lower case.
+Other command-line options can be specified to map names to upper
+case, or to leave them exactly as written in the source file.
+
+For example:
+
+@example
+Foo = 9.436
+@end example
+
+@noindent
+Here, it is normally the case that the variable assigned will be named
+@samp{foo}.
+This would be the name to enter when using a debugger to
+access the variable.
+
+However, depending on the command-line options specified, the
+name implemented by @code{g77} might instead be @samp{FOO} or even
+@samp{Foo}, thus affecting how debugging is done.
+
+Also:
+
+@example
+Call Foo
+@end example
+
+@noindent
+This would normally call a procedure that, if it were in a separate C program,
+be defined starting with the line:
+
+@example
+void foo_()
+@end example
+
+@noindent
+However, @code{g77} command-line options could be used to change the casing
+of names, resulting in the name @samp{FOO_} or @samp{Foo_} being given to the
+procedure instead of @samp{foo_}, and the @samp{-fno-underscoring} option
+could be used to inhibit the appending of the underscore to the name.
+
+@node Common Blocks
+@section Common Blocks (COMMON)
+@cindex common blocks
+@cindex COMMON statement
+@cindex statements, COMMON
+
+@code{g77} names and lays out @code{COMMON} areas
+the same way @code{f2c} does,
+for compatibility with @code{f2c}.
+
+Currently, @code{g77} does not emit ``true'' debugging information for
+members of a @code{COMMON} area, due to an apparent bug in the GBE.
+
+(As of Version 0.5.19, @code{g77} emits debugging information for such
+members in the form of a constant string specifying the base name of
+the aggregate area and the offset of the member in bytes from the start
+of the area.
+Use the @samp{-fdebug-kludge} option to enable this behavior.
+In @code{gdb}, use @samp{set language c} before printing the value
+of the member, then @samp{set language fortran} to restore the default
+language, since @code{gdb} doesn't provide a way to print a readable
+version of a character string in Fortran language mode.
+
+This kludge will be removed in a future version of @code{g77} that,
+in conjunction with a contemporary version of @code{gdb},
+properly supports Fortran-language debugging, including access
+to members of @code{COMMON} areas.)
+
+@xref{Code Gen Options,,Options for Code Generation Conventions},
+for information on the @samp{-fdebug-kludge} option.
+
+Moreover, @code{g77} currently implements a @code{COMMON} area such that its
+type is an array of the C @code{char} data type.
+
+So, when debugging, you must know the offset into a @code{COMMON} area
+for a particular item in that area, and you have to take into
+account the appropriate multiplier for the respective sizes
+of the types (as declared in your code) for the items preceding
+the item in question as compared to the size of the @code{char} type.
+
+For example, using default implicit typing, the statement
+
+@example
+COMMON I(15), R(20), T
+@end example
+
+@noindent
+results in a public 144-byte @code{char} array named @samp{_BLNK__}
+with @samp{I} placed at @samp{_BLNK__[0]}, @samp{R} at @samp{_BLNK__[60]},
+and @samp{T} at @samp{_BLNK__[140]}.
+(This is assuming that the target machine for
+the compilation has 4-byte @code{INTEGER(KIND=1)} and @code{REAL(KIND=1)}
+types.)
+
+@node Local Equivalence Areas
+@section Local Equivalence Areas (EQUIVALENCE)
+@cindex equivalence areas
+@cindex local equivalence areas
+@cindex EQUIVALENCE statement
+@cindex statements, EQUIVALENCE
+
+@code{g77} treats storage-associated areas involving a @code{COMMON}
+block as explained in the section on common blocks.
+
+A local @code{EQUIVALENCE} area is a collection of variables and arrays
+connected to each other in any way via @code{EQUIVALENCE}, none of which are
+listed in a @code{COMMON} statement.
+
+Currently, @code{g77} does not emit ``true'' debugging information for
+members in a local @code{EQUIVALENCE} area, due to an apparent bug in the GBE.
+
+(As of Version 0.5.19, @code{g77} does emit debugging information for such
+members in the form of a constant string specifying the base name of
+the aggregate area and the offset of the member in bytes from the start
+of the area.
+Use the @samp{-fdebug-kludge} option to enable this behavior.
+In @code{gdb}, use @samp{set language c} before printing the value
+of the member, then @samp{set language fortran} to restore the default
+language, since @code{gdb} doesn't provide a way to print a readable
+version of a character string in Fortran language mode.
+
+This kludge will be removed in a future version of @code{g77} that,
+in conjunction with a contemporary version of @code{gdb},
+properly supports Fortran-language debugging, including access
+to members of @code{EQUIVALENCE} areas.)
+
+@xref{Code Gen Options,,Options for Code Generation Conventions},
+for information on the @samp{-fdebug-kludge} option.
+
+Moreover, @code{g77} implements a local @code{EQUIVALENCE} area such that its
+type is an array of the C @code{char} data type.
+
+The name @code{g77} gives this array of @code{char} type is @samp{__g77_equiv_@var{x}},
+where @var{x} is the name of the item that is placed at the beginning (offset 0)
+of this array.
+If more than one such item is placed at the beginning, @var{x} is
+the name that sorts to the top in an alphabetical sort of the list of
+such items.
+
+When debugging, you must therefore access members of @code{EQUIVALENCE}
+areas by specifying the appropriate @samp{__g77_equiv_@var{x}}
+array section with the appropriate offset.
+See the explanation of debugging @code{COMMON} blocks
+for info applicable to debugging local @code{EQUIVALENCE} areas.
+
+(@emph{Note:} @code{g77} version 0.5.18 and earlier chose the name
+for @var{x} using a different method when more than one name was
+in the list of names of entities placed at the beginning of the
+array.
+Though the documentation specified that the first name listed in
+the @code{EQUIVALENCE} statements was chosen for @var{x}, @code{g77}
+in fact chose the name using a method that was so complicated,
+it seemed easier to change it to an alphabetical sort than to describe the
+previous method in the documentation.)
+
+@node Complex Variables
+@section Complex Variables (COMPLEX)
+@cindex complex variables
+@cindex imaginary part of complex
+@cindex COMPLEX statement
+@cindex statements, COMPLEX
+
+As of 0.5.20, @code{g77} defaults to handling @code{COMPLEX} types
+(and related intrinsics, constants, functions, and so on)
+in a manner that
+makes direct debugging involving these types in Fortran
+language mode difficult.
+
+Essentially, @code{g77} implements these types using an
+internal construct similar to C's @code{struct}, at least
+as seen by the @code{gcc} back end.
+
+Currently, the back end, when outputting debugging info with
+the compiled code for the assembler to digest, does not detect
+these @code{struct} types as being substitutes for Fortran
+complex.
+As a result, the Fortran language modes of debuggers such as
+@code{gdb} see these types as C @code{struct} types, which
+they might or might not support.
+
+Until this is fixed, switch to C language mode to work with
+entities of @code{COMPLEX} type and then switch back to Fortran language
+mode afterward.
+(In @code{gdb}, this is accomplished via @samp{set lang c} and
+either @samp{set lang fortran} or @samp{set lang auto}.)
+
+@emph{Note:} Compiling with the @samp{-fno-emulate-complex} option
+avoids the debugging problem, but is known to cause other problems
+like compiler crashes and generation of incorrect code, so it is
+not recommended.
+
+@node Arrays
+@section Arrays (DIMENSION)
+@cindex DIMENSION statement
+@cindex statements, DIMENSION
+@cindex array ordering
+@cindex ordering, array
+@cindex column-major ordering
+@cindex row-major ordering
+@cindex arrays
+
+Fortran uses ``column-major ordering'' in its arrays.
+This differs from other languages, such as C, which use ``row-major ordering''.
+The difference is that, with Fortran, array elements adjacent to
+each other in memory differ in the @emph{first} subscript instead of
+the last; @samp{A(5,10,20)} immediately follows @samp{A(4,10,20)},
+whereas with row-major ordering it would follow @samp{A(5,10,19)}.
+
+This consideration
+affects not only interfacing with and debugging Fortran code,
+it can greatly affect how code is designed and written, especially
+when code speed and size is a concern.
+
+Fortran also differs from C, a popular language for interfacing and
+to support directly in debuggers, in the way arrays are treated.
+In C, arrays are single-dimensional and have interesting relationships
+to pointers, neither of which is true for Fortran.
+As a result, dealing with Fortran arrays from within
+an environment limited to C concepts can be challenging.
+
+For example, accessing the array element @samp{A(5,10,20)} is easy enough
+in Fortran (use @samp{A(5,10,20)}), but in C some difficult machinations
+are needed.
+First, C would treat the A array as a single-dimension array.
+Second, C does not understand low bounds for arrays as does Fortran.
+Third, C assumes a low bound of zero (0), while Fortran defaults to a
+low bound of one (1) and can supports an arbitrary low bound.
+Therefore, calculations must be done
+to determine what the C equivalent of @samp{A(5,10,20)} would be, and these
+calculations require knowing the dimensions of @samp{A}.
+
+For @samp{DIMENSION A(2:11,21,0:29)}, the calculation of the offset of
+@samp{A(5,10,20)} would be:
+
+@example
+ (5-2)
++ (10-1)*(11-2+1)
++ (20-0)*(11-2+1)*(21-1+1)
+= 4293
+@end example
+
+@noindent
+So the C equivalent in this case would be @samp{a[4293]}.
+
+When using a debugger directly on Fortran code, the C equivalent
+might not work, because some debuggers cannot understand the notion
+of low bounds other than zero. However, unlike @code{f2c}, @code{g77}
+does inform the GBE that a multi-dimensional array (like @samp{A}
+in the above example) is really multi-dimensional, rather than a
+single-dimensional array, so at least the dimensionality of the array
+is preserved.
+
+Debuggers that understand Fortran should have no trouble with
+non-zero low bounds, but for non-Fortran debuggers, especially
+C debuggers, the above example might have a C equivalent of
+@samp{a[4305]}.
+This calculation is arrived at by eliminating the subtraction
+of the lower bound in the first parenthesized expression on each
+line---that is, for @samp{(5-2)} substitute @samp{(5)}, for @samp{(10-1)}
+substitute @samp{(10)}, and for @samp{(20-0)} substitute @samp{(20)}.
+Actually, the implication of
+this can be that the expression @samp{*(&a[2][1][0] + 4293)} works fine,
+but that @samp{a[20][10][5]} produces the equivalent of
+@samp{*(&a[0][0][0] + 4305)} because of the missing lower bounds.
+
+Come to think of it, perhaps
+the behavior is due to the debugger internally compensating for
+the lower bounds by offsetting the base address of @samp{a}, leaving
+@samp{&a} set lower, in this case, than @samp{&a[2][1][0]} (the address of
+its first element as identified by subscripts equal to the
+corresponding lower bounds).
+
+You know, maybe nobody really needs to use arrays.
+
+@node Adjustable Arrays
+@section Adjustable Arrays (DIMENSION)
+@cindex arrays, adjustable
+@cindex adjustable arrays
+@cindex arrays, automatic
+@cindex automatic arrays
+@cindex DIMENSION statement
+@cindex statements, DIMENSION
+@cindex dimensioning arrays
+@cindex arrays, dimensioning
+
+Adjustable and automatic arrays in Fortran require the implementation
+(in this
+case, the @code{g77} compiler) to ``memorize'' the expressions that
+dimension the arrays each time the procedure is invoked.
+This is so that subsequent changes to variables used in those
+expressions, made during execution of the procedure, do not
+have any effect on the dimensions of those arrays.
+
+For example:
+
+@example
+REAL ARRAY(5)
+DATA ARRAY/5*2/
+CALL X(ARRAY, 5)
+END
+SUBROUTINE X(A, N)
+DIMENSION A(N)
+N = 20
+PRINT *, N, A
+END
+@end example
+
+@noindent
+Here, the implementation should, when running the program, print something
+like:
+
+@example
+20 2. 2. 2. 2. 2.
+@end example
+
+@noindent
+Note that this shows that while the value of @samp{N} was successfully
+changed, the size of the @samp{A} array remained at 5 elements.
+
+To support this, @code{g77} generates code that executes before any user
+code (and before the internally generated computed @code{GOTO} to handle
+alternate entry points, as described below) that evaluates each
+(nonconstant) expression in the list of subscripts for an
+array, and saves the result of each such evaluation to be used when
+determining the size of the array (instead of re-evaluating the
+expressions).
+
+So, in the above example, when @samp{X} is first invoked, code is
+executed that copies the value of @samp{N} to a temporary.
+And that same temporary serves as the actual high bound for the single
+dimension of the @samp{A} array (the low bound being the constant 1).
+Since the user program cannot (legitimately) change the value
+of the temporary during execution of the procedure, the size
+of the array remains constant during each invocation.
+
+For alternate entry points, the code @code{g77} generates takes into
+account the possibility that a dummy adjustable array is not actually
+passed to the actual entry point being invoked at that time.
+In that case, the public procedure implementing the entry point
+passes to the master private procedure implementing all the
+code for the entry points a @code{NULL} pointer where a pointer to that
+adjustable array would be expected.
+The @code{g77}-generated code
+doesn't attempt to evaluate any of the expressions in the subscripts
+for an array if the pointer to that array is @code{NULL} at run time in
+such cases.
+(Don't depend on this particular implementation
+by writing code that purposely passes @code{NULL} pointers where the
+callee expects adjustable arrays, even if you know the callee
+won't reference the arrays---nor should you pass @code{NULL} pointers
+for any dummy arguments used in calculating the bounds of such
+arrays or leave undefined any values used for that purpose in
+COMMON---because the way @code{g77} implements these things might
+change in the future!)
+
+@node Alternate Entry Points
+@section Alternate Entry Points (ENTRY)
+@cindex alternate entry points
+@cindex entry points
+@cindex ENTRY statement
+@cindex statements, ENTRY
+
+The GBE does not understand the general concept of
+alternate entry points as Fortran provides via the ENTRY statement.
+@code{g77} gets around this by using an approach to compiling procedures
+having at least one @code{ENTRY} statement that is almost identical to the
+approach used by @code{f2c}.
+(An alternate approach could be used that
+would probably generate faster, but larger, code that would also
+be a bit easier to debug.)
+
+Information on how @code{g77} implements @code{ENTRY} is provided for those
+trying to debug such code.
+The choice of implementation seems
+unlikely to affect code (compiled in other languages) that interfaces
+to such code.
+
+@code{g77} compiles exactly one public procedure for the primary entry
+point of a procedure plus each @code{ENTRY} point it specifies, as usual.
+That is, in terms of the public interface, there is no difference
+between
+
+@example
+SUBROUTINE X
+END
+SUBROUTINE Y
+END
+@end example
+
+@noindent
+and:
+
+@example
+SUBROUTINE X
+ENTRY Y
+END
+@end example
+
+The difference between the above two cases lies in the code compiled
+for the @samp{X} and @samp{Y} procedures themselves, plus the fact that,
+for the second case, an extra internal procedure is compiled.
+
+For every Fortran procedure with at least one @code{ENTRY}
+statement, @code{g77} compiles an extra procedure
+named @samp{__g77_masterfun_@var{x}}, where @var{x} is
+the name of the primary entry point (which, in the above case,
+using the standard compiler options, would be @samp{x_} in C).
+
+This extra procedure is compiled as a private procedure---that is,
+a procedure not accessible by name to separately compiled modules.
+It contains all the code in the program unit, including the code
+for the primary entry point plus for every entry point.
+(The code for each public procedure is quite short, and explained later.)
+
+The extra procedure has some other interesting characteristics.
+
+The argument list for this procedure is invented by @code{g77}.
+It contains
+a single integer argument named @samp{__g77_which_entrypoint},
+passed by value (as in Fortran's @samp{%VAL()} intrinsic), specifying the
+entry point index---0 for the primary entry point, 1 for the
+first entry point (the first @code{ENTRY} statement encountered), 2 for
+the second entry point, and so on.
+
+It also contains, for functions returning @code{CHARACTER} and
+(when @samp{-ff2c} is in effect) @code{COMPLEX} functions,
+and for functions returning different types among the
+@code{ENTRY} statements (e.g. @samp{REAL FUNCTION R()}
+containing @samp{ENTRY I()}), an argument named @samp{__g77_result} that
+is expected at run time to contain a pointer to where to store
+the result of the entry point.
+For @code{CHARACTER} functions, this
+storage area is an array of the appropriate number of characters;
+for @code{COMPLEX} functions, it is the appropriate area for the return
+type; for multiple-return-type functions, it is a union of all the supported return
+types (which cannot include @code{CHARACTER}, since combining @code{CHARACTER}
+and non-@code{CHARACTER} return types via @code{ENTRY} in a single function
+is not supported by @code{g77}).
+
+For @code{CHARACTER} functions, the @samp{__g77_result} argument is followed
+by yet another argument named @samp{__g77_length} that, at run time,
+specifies the caller's expected length of the returned value.
+Note that only @code{CHARACTER*(*)} functions and entry points actually
+make use of this argument, even though it is always passed by
+all callers of public @code{CHARACTER} functions (since the caller does not
+generally know whether such a function is @code{CHARACTER*(*)} or whether
+there are any other callers that don't have that information).
+
+The rest of the argument list is the union of all the arguments
+specified for all the entry points (in their usual forms, e.g.
+@code{CHARACTER} arguments have extra length arguments, all appended at
+the end of this list).
+This is considered the ``master list'' of
+arguments.
+
+The code for this procedure has, before the code for the first
+executable statement, code much like that for the following Fortran
+statement:
+
+@smallexample
+ GOTO (100000,100001,100002), __g77_which_entrypoint
+100000 @dots{}code for primary entry point@dots{}
+100001 @dots{}code immediately following first ENTRY statement@dots{}
+100002 @dots{}code immediately following second ENTRY statement@dots{}
+@end smallexample
+
+@noindent
+(Note that invalid Fortran statement labels and variable names
+are used in the above example to highlight the fact that it
+represents code generated by the @code{g77} internals, not code to be
+written by the user.)
+
+It is this code that, when the procedure is called, picks which
+entry point to start executing.
+
+Getting back to the public procedures (@samp{x} and @samp{Y} in the original
+example), those procedures are fairly simple.
+Their interfaces
+are just like they would be if they were self-contained procedures
+(without @code{ENTRY}), of course, since that is what the callers
+expect.
+Their code consists of simply calling the private
+procedure, described above, with the appropriate extra arguments
+(the entry point index, and perhaps a pointer to a multiple-type-
+return variable, local to the public procedure, that contains
+all the supported returnable non-character types).
+For arguments
+that are not listed for a given entry point that are listed for
+other entry points, and therefore that are in the ``master list''
+for the private procedure, null pointers (in C, the @code{NULL} macro)
+are passed.
+Also, for entry points that are part of a multiple-type-
+returning function, code is compiled after the call of the private
+procedure to extract from the multi-type union the appropriate result,
+depending on the type of the entry point in question, returning
+that result to the original caller.
+
+When debugging a procedure containing alternate entry points, you
+can either set a break point on the public procedure itself (e.g.
+a break point on @samp{X} or @samp{Y}) or on the private procedure that
+contains most of the pertinent code (e.g. @samp{__g77_masterfun_@var{x}}).
+If you do the former, you should use the debugger's command to
+``step into'' the called procedure to get to the actual code; with
+the latter approach, the break point leaves you right at the
+actual code, skipping over the public entry point and its call
+to the private procedure (unless you have set a break point there
+as well, of course).
+
+Further, the list of dummy arguments that is visible when the
+private procedure is active is going to be the expanded version
+of the list for whichever particular entry point is active,
+as explained above, and the way in which return values are
+handled might well be different from how they would be handled
+for an equivalent single-entry function.
+
+@node Alternate Returns
+@section Alternate Returns (SUBROUTINE and RETURN)
+@cindex subroutines
+@cindex alternate returns
+@cindex SUBROUTINE statement
+@cindex statements, SUBROUTINE
+@cindex RETURN statement
+@cindex statements, RETURN
+
+Subroutines with alternate returns (e.g. @samp{SUBROUTINE X(*)} and
+@samp{CALL X(*50)}) are implemented by @code{g77} as functions returning
+the C @code{int} type.
+The actual alternate-return arguments are omitted from the calling sequence.
+Instead, the caller uses
+the return value to do a rough equivalent of the Fortran
+computed-@code{GOTO} statement, as in @samp{GOTO (50), X()} in the
+example above (where @samp{X} is quietly declared as an @code{INTEGER(KIND=1)}
+function), and the callee just returns whatever integer
+is specified in the @code{RETURN} statement for the subroutine
+For example, @samp{RETURN 1} is implemented as @samp{X = 1} followed
+by @samp{RETURN}
+in C, and @samp{RETURN} by itself is @samp{X = 0} and @samp{RETURN}).
+
+@node Assigned Statement Labels
+@section Assigned Statement Labels (ASSIGN and GOTO)
+@cindex assigned statement labels
+@cindex statement labels, assigned
+@cindex ASSIGN statement
+@cindex statements, ASSIGN
+@cindex GOTO statement
+@cindex statements, GOTO
+
+For portability to machines where a pointer (such as to a label,
+which is how @code{g77} implements @code{ASSIGN} and its relatives,
+the assigned-@code{GOTO} and assigned-@code{FORMAT}-I/O statements)
+is wider (bitwise) than an @code{INTEGER(KIND=1)}, @code{g77}
+uses a different memory location to hold the @code{ASSIGN}ed value of a variable
+than it does the numerical value in that variable, unless the
+variable is wide enough (can hold enough bits).
+
+In particular, while @code{g77} implements
+
+@example
+I = 10
+@end example
+
+@noindent
+as, in C notation, @samp{i = 10;}, it implements
+
+@example
+ASSIGN 10 TO I
+@end example
+
+@noindent
+as, in GNU's extended C notation (for the label syntax),
+@samp{__g77_ASSIGN_I = &&L10;} (where @samp{L10} is just a massaging
+of the Fortran label @samp{10} to make the syntax C-like; @code{g77} doesn't
+actually generate the name @samp{L10} or any other name like that,
+since debuggers cannot access labels anyway).
+
+While this currently means that an @code{ASSIGN} statement does not
+overwrite the numeric contents of its target variable, @emph{do not}
+write any code depending on this feature.
+@code{g77} has already changed this implementation across
+versions and might do so in the future.
+This information is provided only to make debugging Fortran programs
+compiled with the current version of @code{g77} somewhat easier.
+If there's no debugger-visible variable named @samp{__g77_ASSIGN_I}
+in a program unit that does @samp{ASSIGN 10 TO I}, that probably
+means @code{g77} has decided it can store the pointer to the label directly
+into @samp{I} itself.
+
+@xref{Ugly Assigned Labels}, for information on a command-line option
+to force @code{g77} to use the same storage for both normal and
+assigned-label uses of a variable.
+
+@node Run-time Library Errors
+@section Run-time Library Errors
+@cindex IOSTAT=
+@cindex error values
+@cindex error messages
+@cindex messages, run-time
+@cindex I/O, errors
+
+The @code{libg2c} library currently has the following table to relate
+error code numbers, returned in @code{IOSTAT=} variables, to messages.
+This information should, in future versions of this document, be
+expanded upon to include detailed descriptions of each message.
+
+In line with good coding practices, any of the numbers in the
+list below should @emph{not} be directly written into Fortran
+code you write.
+Instead, make a separate @code{INCLUDE} file that defines
+@code{PARAMETER} names for them, and use those in your code,
+so you can more easily change the actual numbers in the future.
+
+The information below is culled from the definition
+of @samp{F_err} in @file{f/runtime/libI77/err.c} in the
+@code{g77} source tree.
+
+@smallexample
+100: "error in format"
+101: "illegal unit number"
+102: "formatted io not allowed"
+103: "unformatted io not allowed"
+104: "direct io not allowed"
+105: "sequential io not allowed"
+106: "can't backspace file"
+107: "null file name"
+108: "can't stat file"
+109: "unit not connected"
+110: "off end of record"
+111: "truncation failed in endfile"
+112: "incomprehensible list input"
+113: "out of free space"
+114: "unit not connected"
+115: "read unexpected character"
+116: "bad logical input field"
+117: "bad variable type"
+118: "bad namelist name"
+119: "variable not in namelist"
+120: "no end record"
+121: "variable count incorrect"
+122: "subscript for scalar variable"
+123: "invalid array section"
+124: "substring out of bounds"
+125: "subscript out of bounds"
+126: "can't read file"
+127: "can't write file"
+128: "'new' file exists"
+129: "can't append to file"
+130: "non-positive record number"
+131: "I/O started while already doing I/O"
+@end smallexample
+
+@node Collected Fortran Wisdom
+@chapter Collected Fortran Wisdom
+@cindex wisdom
+@cindex legacy code
+@cindex code, legacy
+@cindex writing code
+@cindex code, writing
+
+Most users of @code{g77} can be divided into two camps:
+
+@itemize @bullet
+@item
+Those writing new Fortran code to be compiled by @code{g77}.
+
+@item
+Those using @code{g77} to compile existing, ``legacy'' code.
+@end itemize
+
+Users writing new code generally understand most of the necessary
+aspects of Fortran to write ``mainstream'' code, but often need
+help deciding how to handle problems, such as the construction
+of libraries containing @code{BLOCK DATA}.
+
+Users dealing with ``legacy'' code sometimes don't have much
+experience with Fortran, but believe that the code they're compiling
+already works when compiled by other compilers (and might
+not understand why, as is sometimes the case, it doesn't work
+when compiled by @code{g77}).
+
+The following information is designed to help users do a better job
+coping with existing, ``legacy'' Fortran code, and with writing
+new code as well.
+
+@menu
+* Advantages Over f2c:: If @code{f2c} is so great, why @code{g77}?
+* Block Data and Libraries:: How @code{g77} solves a common problem.
+* Loops:: Fortran @code{DO} loops surprise many people.
+* Working Programs:: Getting programs to work should be done first.
+* Overly Convenient Options:: Temptations to avoid, habits to not form.
+* Faster Programs:: Everybody wants these, but at what cost?
+@end menu
+
+@node Advantages Over f2c
+@section Advantages Over f2c
+
+Without @code{f2c}, @code{g77} would have taken much longer to
+do and probably not been as good for quite a while.
+Sometimes people who notice how much @code{g77} depends on, and
+documents encouragement to use, @code{f2c} ask why @code{g77}
+was created if @code{f2c} already existed.
+
+This section gives some basic answers to these questions, though it
+is not intended to be comprehensive.
+
+@menu
+* Language Extensions:: Features used by Fortran code.
+* Compiler Options:: Features helpful during development.
+* Compiler Speed:: Speed of the compilation process.
+* Program Speed:: Speed of the generated, optimized code.
+* Ease of Debugging:: Debugging ease-of-use at the source level.
+* Character and Hollerith Constants:: A byte saved is a byte earned.
+@end menu
+
+@node Language Extensions
+@subsection Language Extensions
+
+@code{g77} offers several extensions to the Fortran language that @code{f2c}
+doesn't.
+
+However, @code{f2c} offers a few that @code{g77} doesn't, like
+fairly complete support for @code{INTEGER*2}.
+It is expected that @code{g77} will offer some or all of these missing
+features at some time in the future.
+(Version 0.5.18 of @code{g77} offers some rudimentary support for some
+of these features.)
+
+@node Compiler Options
+@subsection Compiler Options
+
+@code{g77} offers a whole bunch of compiler options that @code{f2c} doesn't.
+
+However, @code{f2c} offers a few that @code{g77} doesn't, like an
+option to generate code to check array subscripts at run time.
+It is expected that @code{g77} will offer some or all of these
+missing options at some time in the future.
+
+@node Compiler Speed
+@subsection Compiler Speed
+
+Saving the steps of writing and then rereading C code is a big reason
+why @code{g77} should be able to compile code much faster than using
+@code{f2c} in conjunction with the equivalent invocation of @code{gcc}.
+
+However, due to @code{g77}'s youth, lots of self-checking is still being
+performed.
+As a result, this improvement is as yet unrealized
+(though the potential seems to be there for quite a big speedup
+in the future).
+It is possible that, as of version 0.5.18, @code{g77}
+is noticeably faster compiling many Fortran source files than using
+@code{f2c} in conjunction with @code{gcc}.
+
+@node Program Speed
+@subsection Program Speed
+
+@code{g77} has the potential to better optimize code than @code{f2c},
+even when @code{gcc} is used to compile the output of @code{f2c},
+because @code{f2c} must necessarily
+translate Fortran into a somewhat lower-level language (C) that cannot
+preserve all the information that is potentially useful for optimization,
+while @code{g77} can gather, preserve, and transmit that information directly
+to the GBE.
+
+For example, @code{g77} implements @code{ASSIGN} and assigned
+@code{GOTO} using direct assignment of pointers to labels and direct
+jumps to labels, whereas @code{f2c} maps the assigned labels to
+integer values and then uses a C @code{switch} statement to encode
+the assigned @code{GOTO} statements.
+
+However, as is typical, theory and reality don't quite match, at least
+not in all cases, so it is still the case that @code{f2c} plus @code{gcc}
+can generate code that is faster than @code{g77}.
+
+Version 0.5.18 of @code{g77} offered default
+settings and options, via patches to the @code{gcc}
+back end, that allow for better program speed, though
+some of these improvements also affected the performance
+of programs translated by @code{f2c} and then compiled
+by @code{g77}'s version of @code{gcc}.
+
+Version 0.5.20 of @code{g77} offers further performance
+improvements, at least one of which (alias analysis) is
+not generally applicable to @code{f2c} (though @code{f2c}
+could presumably be changed to also take advantage of
+this new capability of the @code{gcc} back end, assuming
+this is made available in an upcoming release of @code{gcc}).
+
+@node Ease of Debugging
+@subsection Ease of Debugging
+
+Because @code{g77} compiles directly to assembler code like @code{gcc},
+instead of translating to an intermediate language (C) as does @code{f2c},
+support for debugging can be better for @code{g77} than @code{f2c}.
+
+However, although @code{g77} might be somewhat more ``native'' in terms of
+debugging support than @code{f2c} plus @code{gcc}, there still are a lot
+of things ``not quite right''.
+Many of the important ones should be resolved in the near future.
+
+For example, @code{g77} doesn't have to worry about reserved names
+like @code{f2c} does.
+Given @samp{FOR = WHILE}, @code{f2c} must necessarily
+translate this to something @emph{other} than
+@samp{for = while;}, because C reserves those words.
+
+However, @code{g77} does still uses things like an extra level of indirection
+for @code{ENTRY}-laden procedures---in this case, because the back end doesn't
+yet support multiple entry points.
+
+Another example is that, given
+
+@smallexample
+COMMON A, B
+EQUIVALENCE (B, C)
+@end smallexample
+
+@noindent
+the @code{g77} user should be able to access the variables directly, by name,
+without having to traverse C-like structures and unions, while @code{f2c}
+is unlikely to ever offer this ability (due to limitations in the
+C language).
+
+However, due to apparent bugs in the back end, @code{g77} currently doesn't
+take advantage of this facility at all---it doesn't emit any debugging
+information for @code{COMMON} and @code{EQUIVALENCE} areas,
+other than information
+on the array of @code{char} it creates (and, in the case
+of local @code{EQUIVALENCE}, names) for each such area.
+
+Yet another example is arrays.
+@code{g77} represents them to the debugger
+using the same ``dimensionality'' as in the source code, while @code{f2c}
+must necessarily convert them all to one-dimensional arrays to fit
+into the confines of the C language.
+However, the level of support
+offered by debuggers for interactive Fortran-style access to arrays
+as compiled by @code{g77} can vary widely.
+In some cases, it can actually
+be an advantage that @code{f2c} converts everything to widely supported
+C semantics.
+
+In fairness, @code{g77} could do many of the things @code{f2c} does
+to get things working at least as well as @code{f2c}---for now,
+the developers prefer making @code{g77} work the
+way they think it is supposed to, and finding help improving the
+other products (the back end of @code{gcc}; @code{gdb}; and so on)
+to get things working properly.
+
+@node Character and Hollerith Constants
+@subsection Character and Hollerith Constants
+@cindex character constants
+@cindex constants, character
+@cindex Hollerith constants
+@cindex constants, Hollerith
+@cindex trailing null byte
+@cindex null byte, trailing
+@cindex zero byte, trailing
+
+To avoid the extensive hassle that would be needed to avoid this,
+@code{f2c} uses C character constants to encode character and Hollerith
+constants.
+That means a constant like @samp{'HELLO'} is translated to
+@samp{"hello"} in C, which further means that an extra null byte is
+present at the end of the constant.
+This null byte is superfluous.
+
+@code{g77} does not generate such null bytes.
+This represents significant
+savings of resources, such as on systems where @file{/dev/null} or
+@file{/dev/zero} represent bottlenecks in the systems' performance,
+because @code{g77} simply asks for fewer zeros from the operating
+system than @code{f2c}.
+(Avoiding spurious use of zero bytes, each byte typically have
+eight zero bits, also reduces the liabilities in case
+Microsoft's rumored patent on the digits 0 and 1 is upheld.)
+
+@node Block Data and Libraries
+@section Block Data and Libraries
+@cindex block data and libraries
+@cindex BLOCK DATA statement
+@cindex statements, BLOCK DATA
+@cindex libraries, containing BLOCK DATA
+@cindex @code{f2c} compatibility
+@cindex compatibility, @code{f2c}
+
+To ensure that block data program units are linked, especially a concern
+when they are put into libraries, give each one a name (as in
+@samp{BLOCK DATA FOO}) and make sure there is an @samp{EXTERNAL FOO}
+statement in every program unit that uses any common block
+initialized by the corresponding @code{BLOCK DATA}.
+@code{g77} currently compiles a @code{BLOCK DATA} as if it were a
+@code{SUBROUTINE},
+that is, it generates an actual procedure having the appropriate name.
+The procedure does nothing but return immediately if it happens to be
+called.
+For @samp{EXTERNAL FOO}, where @samp{FOO} is not otherwise referenced in the
+same program unit, @code{g77} assumes there exists a @samp{BLOCK DATA FOO}
+in the program and ensures that by generating a
+reference to it so the linker will make sure it is present.
+(Specifically, @code{g77} outputs in the data section a static pointer to the
+external name @samp{FOO}.)
+
+The implementation @code{g77} currently uses to make this work is
+one of the few things not compatible with @code{f2c} as currently
+shipped.
+@code{f2c} currently does nothing with @samp{EXTERNAL FOO} except
+issue a warning that @samp{FOO} is not otherwise referenced,
+and, for @samp{BLOCK DATA FOO},
+@code{f2c} doesn't generate a dummy procedure with the name @samp{FOO}.
+The upshot is that you shouldn't mix @code{f2c} and @code{g77} in
+this particular case.
+If you use @code{f2c} to compile @samp{BLOCK DATA FOO},
+then any @code{g77}-compiled program unit that says @samp{EXTERNAL FOO}
+will result in an unresolved reference when linked.
+If you do the
+opposite, then @samp{FOO} might not be linked in under various
+circumstances (such as when @samp{FOO} is in a library, or you're
+using a ``clever'' linker---so clever, it produces a broken program
+with little or no warning by omitting initializations of global data
+because they are contained in unreferenced procedures).
+
+The changes you make to your code to make @code{g77} handle this situation,
+however, appear to be a widely portable way to handle it.
+That is, many systems permit it (as they should, since the
+FORTRAN 77 standard permits @samp{EXTERNAL FOO} when @samp{FOO}
+is a block data program unit), and of the ones
+that might not link @samp{BLOCK DATA FOO} under some circumstances, most of
+them appear to do so once @samp{EXTERNAL FOO} is present in the appropriate
+program units.
+
+Here is the recommended approach to modifying a program containing
+a program unit such as the following:
+
+@smallexample
+BLOCK DATA FOO
+COMMON /VARS/ X, Y, Z
+DATA X, Y, Z / 3., 4., 5. /
+END
+@end smallexample
+
+@noindent
+If the above program unit might be placed in a library module, then
+ensure that every program unit in every program that references that
+particular @code{COMMON} area uses the @code{EXTERNAL} statement
+to force the area to be initialized.
+
+For example, change a program unit that starts with
+
+@smallexample
+INTEGER FUNCTION CURX()
+COMMON /VARS/ X, Y, Z
+CURX = X
+END
+@end smallexample
+
+@noindent
+so that it uses the @code{EXTERNAL} statement, as in:
+
+@smallexample
+INTEGER FUNCTION CURX()
+COMMON /VARS/ X, Y, Z
+EXTERNAL FOO
+CURX = X
+END
+@end smallexample
+
+@noindent
+That way, @samp{CURX} is compiled by @code{g77} (and many other
+compilers) so that the linker knows it must include @samp{FOO},
+the @code{BLOCK DATA} program unit that sets the initial values
+for the variables in @samp{VAR}, in the executable program.
+
+@node Loops
+@section Loops
+@cindex DO statement
+@cindex statements, DO
+@cindex trips, number of
+@cindex number of trips
+
+The meaning of a @code{DO} loop in Fortran is precisely specified
+in the Fortran standard@dots{}and is quite different from what
+many programmers might expect.
+
+In particular, Fortran indexed @code{DO} loops are implemented as if
+the number of trips through the loop is calculated @emph{before}
+the loop is entered.
+
+The number of trips for a loop is calculated from the @var{start},
+@var{end}, and @var{increment} values specified in a statement such as:
+
+@smallexample
+DO @var{iter} = @var{start}, @var{end}, @var{increment}
+@end smallexample
+
+@noindent
+The trip count is evaluated using a fairly simple formula
+based on the three values following the @samp{=} in the
+statement, and it is that trip count that is effectively
+decremented during each iteration of the loop.
+If, at the beginning of an iteration of the loop, the
+trip count is zero or negative, the loop terminates.
+The per-loop-iteration modifications to @var{iter} are not
+related to determining whether to terminate the loop.
+
+There are two important things to remember about the trip
+count:
+
+@itemize @bullet
+@item
+It can be @emph{negative}, in which case it is
+treated as if it was zero---meaning the loop is
+not executed at all.
+
+@item
+The type used to @emph{calculate} the trip count
+is the same type as @var{iter}, but the final
+calculation, and thus the type of the trip
+count itself, always is @code{INTEGER(KIND=1)}.
+@end itemize
+
+These two items mean that there are loops that cannot
+be written in straightforward fashion using the Fortran @code{DO}.
+
+For example, on a system with the canonical 32-bit two's-complement
+implementation of @code{INTEGER(KIND=1)}, the following loop will not work:
+
+@smallexample
+DO I = -2000000000, 2000000000
+@end smallexample
+
+@noindent
+Although the @var{start} and @var{end} values are well within
+the range of @code{INTEGER(KIND=1)}, the @emph{trip count} is not.
+The expected trip count is 40000000001, which is outside
+the range of @code{INTEGER(KIND=1)} on many systems.
+
+Instead, the above loop should be constructed this way:
+
+@smallexample
+I = -2000000000
+DO
+ IF (I .GT. 2000000000) EXIT
+ @dots{}
+ I = I + 1
+END DO
+@end smallexample
+
+@noindent
+The simple @code{DO} construct and the @code{EXIT} statement
+(used to leave the innermost loop)
+are F90 features that @code{g77} supports.
+
+Some Fortran compilers have buggy implementations of @code{DO},
+in that they don't follow the standard.
+They implement @code{DO} as a straightforward translation
+to what, in C, would be a @code{for} statement.
+Instead of creating a temporary variable to hold the trip count
+as calculated at run time, these compilers
+use the iteration variable @var{iter} to control
+whether the loop continues at each iteration.
+
+The bug in such an implementation shows up when the
+trip count is within the range of the type of @var{iter},
+but the magnitude of @samp{ABS(@var{end}) + ABS(@var{incr})}
+exceeds that range. For example:
+
+@smallexample
+DO I = 2147483600, 2147483647
+@end smallexample
+
+@noindent
+A loop started by the above statement will work as implemented
+by @code{g77}, but the use, by some compilers, of a
+more C-like implementation akin to
+
+@smallexample
+for (i = 2147483600; i <= 2147483647; ++i)
+@end smallexample
+
+@noindent
+produces a loop that does not terminate, because @samp{i}
+can never be greater than 2147483647, since incrementing it
+beyond that value overflows @samp{i}, setting it to -2147483648.
+This is a large, negative number that still is less than 2147483647.
+
+Another example of unexpected behavior of @code{DO} involves
+using a nonintegral iteration variable @var{iter}, that is,
+a @code{REAL} variable.
+Consider the following program:
+
+@smallexample
+ DATA BEGIN, END, STEP /.1, .31, .007/
+ DO 10 R = BEGIN, END, STEP
+ IF (R .GT. END) PRINT *, R, ' .GT. ', END, '!!'
+ PRINT *,R
+10 CONTINUE
+ PRINT *,'LAST = ',R
+ IF (R .LE. END) PRINT *, R, ' .LE. ', END, '!!'
+ END
+@end smallexample
+
+@noindent
+A C-like view of @code{DO} would hold that the two ``exclamatory''
+@code{PRINT} statements are never executed.
+However, this is the output of running the above program
+as compiled by @code{g77} on a GNU/Linux ix86 system:
+
+@smallexample
+ .100000001
+ .107000001
+ .114
+ .120999999
+ @dots{}
+ .289000005
+ .296000004
+ .303000003
+LAST = .310000002
+ .310000002 .LE. .310000002!!
+@end smallexample
+
+Note that one of the two checks in the program turned up
+an apparent violation of the programmer's expectation---yet,
+the loop is correctly implemented by @code{g77}, in that
+it has 30 iterations.
+This trip count of 30 is correct when evaluated using
+the floating-point representations for the @var{begin},
+@var{end}, and @var{incr} values (.1, .31, .007) on GNU/Linux
+ix86 are used.
+On other systems, an apparently more accurate trip count
+of 31 might result, but, nevertheless, @code{g77} is
+faithfully following the Fortran standard, and the result
+is not what the author of the sample program above
+apparently expected.
+(Such other systems might, for different values in the @code{DATA}
+statement, violate the other programmer's expectation,
+for example.)
+
+Due to this combination of imprecise representation
+of floating-point values and the often-misunderstood
+interpretation of @code{DO} by standard-conforming
+compilers such as @code{g77}, use of @code{DO} loops
+with @code{REAL} iteration
+variables is not recommended.
+Such use can be caught by specifying @samp{-Wsurprising}.
+@xref{Warning Options}, for more information on this
+option.
+
+@node Working Programs
+@section Working Programs
+
+Getting Fortran programs to work in the first place can be
+quite a challenge---even when the programs already work on
+other systems, or when using other compilers.
+
+@code{g77} offers some facilities that might be useful for
+tracking down bugs in such programs.
+
+@menu
+* Not My Type::
+* Variables Assumed To Be Zero::
+* Variables Assumed To Be Saved::
+* Unwanted Variables::
+* Unused Arguments::
+* Surprising Interpretations of Code::
+* Aliasing Assumed To Work::
+* Output Assumed To Flush::
+* Large File Unit Numbers::
+* Floating point precision::
+* Inconsistent Calling Sequences::
+@end menu
+
+@node Not My Type
+@subsection Not My Type
+@cindex mistyped variables
+@cindex variables, mistyped
+@cindex mistyped functions
+@cindex functions, mistyped
+@cindex implicit typing
+
+A fruitful source of bugs in Fortran source code is use, or
+mis-use, of Fortran's implicit-typing feature, whereby the
+type of a variable, array, or function is determined by the
+first character of its name.
+
+Simple cases of this include statements like @samp{LOGX=9.227},
+without a statement such as @samp{REAL LOGX}.
+In this case, @samp{LOGX} is implicitly given @code{INTEGER(KIND=1)}
+type, with the result of the assignment being that it is given
+the value @samp{9}.
+
+More involved cases include a function that is defined starting
+with a statement like @samp{DOUBLE PRECISION FUNCTION IPS(@dots{})}.
+Any caller of this function that does not also declare @samp{IPS}
+as type @code{DOUBLE PRECISION} (or, in GNU Fortran, @code{REAL(KIND=2)})
+is likely to assume it returns
+@code{INTEGER}, or some other type, leading to invalid results
+or even program crashes.
+
+The @samp{-Wimplicit} option might catch failures to
+properly specify the types of
+variables, arrays, and functions in the code.
+
+However, in code that makes heavy use of Fortran's
+implicit-typing facility, this option might produce so
+many warnings about cases that are working, it would be
+hard to find the one or two that represent bugs.
+This is why so many experienced Fortran programmers strongly
+recommend widespread use of the @code{IMPLICIT NONE} statement,
+despite it not being standard FORTRAN 77, to completely turn
+off implicit typing.
+(@code{g77} supports @code{IMPLICIT NONE}, as do almost all
+FORTRAN 77 compilers.)
+
+Note that @samp{-Wimplicit} catches only implicit typing of
+@emph{names}.
+It does not catch implicit typing of expressions such
+as @samp{X**(2/3)}.
+Such expressions can be buggy as well---in fact, @samp{X**(2/3)}
+is equivalent to @samp{X**0}, due to the way Fortran expressions
+are given types and then evaluated.
+(In this particular case, the programmer probably wanted
+@samp{X**(2./3.)}.)
+
+@node Variables Assumed To Be Zero
+@subsection Variables Assumed To Be Zero
+@cindex zero-initialized variables
+@cindex variables assumed to be zero
+@cindex uninitialized variables
+
+Many Fortran programs were developed on systems that provided
+automatic initialization of all, or some, variables and arrays
+to zero.
+As a result, many of these programs depend, sometimes
+inadvertently, on this behavior, though to do so violates
+the Fortran standards.
+
+You can ask @code{g77} for this behavior by specifying the
+@samp{-finit-local-zero} option when compiling Fortran code.
+(You might want to specify @samp{-fno-automatic} as well,
+to avoid code-size inflation for non-optimized compilations.)
+
+Note that a program that works better when compiled with the
+@samp{-finit-local-zero} option
+is almost certainly depending on a particular system's,
+or compiler's, tendency to initialize some variables to zero.
+It might be worthwhile finding such cases and fixing them,
+using techniques such as compiling with the @samp{-O -Wuninitialized}
+options using @code{g77}.
+
+@node Variables Assumed To Be Saved
+@subsection Variables Assumed To Be Saved
+@cindex variables retaining values across calls
+@cindex saved variables
+@cindex static variables
+
+Many Fortran programs were developed on systems that
+saved the values of all, or some, variables and arrays
+across procedure calls.
+As a result, many of these programs depend, sometimes
+inadvertently, on being able to assign a value to a
+variable, perform a @code{RETURN} to a calling procedure,
+and, upon subsequent invocation, reference the previously
+assigned variable to obtain the value.
+
+They expect this despite not using the @code{SAVE} statement
+to specify that the value in a variable is expected to survive
+procedure returns and calls.
+Depending on variables and arrays to retain values across
+procedure calls without using @code{SAVE} to require it violates
+the Fortran standards.
+
+You can ask @code{g77} to assume @code{SAVE} is specified for all
+relevant (local) variables and arrays by using the
+@samp{-fno-automatic} option.
+
+Note that a program that works better when compiled with the
+@samp{-fno-automatic} option
+is almost certainly depending on not having to use
+the @code{SAVE} statement as required by the Fortran standard.
+It might be worthwhile finding such cases and fixing them,
+using techniques such as compiling with the @samp{-O -Wuninitialized}
+options using @code{g77}.
+
+@node Unwanted Variables
+@subsection Unwanted Variables
+
+The @samp{-Wunused} option can find bugs involving
+implicit typing, sometimes
+more easily than using @samp{-Wimplicit} in code that makes
+heavy use of implicit typing.
+An unused variable or array might indicate that the
+spelling for its declaration is different from that of
+its intended uses.
+
+Other than cases involving typos, unused variables rarely
+indicate actual bugs in a program.
+However, investigating such cases thoroughly has, on occasion,
+led to the discovery of code that had not been completely
+written---where the programmer wrote declarations as needed
+for the whole algorithm, wrote some or even most of the code
+for that algorithm, then got distracted and forgot that the
+job was not complete.
+
+@node Unused Arguments
+@subsection Unused Arguments
+@cindex unused arguments
+@cindex arguments, unused
+
+As with unused variables, It is possible that unused arguments
+to a procedure might indicate a bug.
+Compile with @samp{-W -Wunused} option to catch cases of
+unused arguments.
+
+Note that @samp{-W} also enables warnings regarding overflow
+of floating-point constants under certain circumstances.
+
+@node Surprising Interpretations of Code
+@subsection Surprising Interpretations of Code
+
+The @samp{-Wsurprising} option can help find bugs involving
+expression evaluation or in
+the way @code{DO} loops with non-integral iteration variables
+are handled.
+Cases found by this option might indicate a difference of
+interpretation between the author of the code involved, and
+a standard-conforming compiler such as @code{g77}.
+Such a difference might produce actual bugs.
+
+In any case, changing the code to explicitly do what the
+programmer might have expected it to do, so @code{g77} and
+other compilers are more likely to follow the programmer's
+expectations, might be worthwhile, especially if such changes
+make the program work better.
+
+@node Aliasing Assumed To Work
+@subsection Aliasing Assumed To Work
+@cindex -falias-check option
+@cindex options, -falias-check
+@cindex -fargument-alias option
+@cindex options, -fargument-alias
+@cindex -fargument-noalias option
+@cindex options, -fargument-noalias
+@cindex -fno-argument-noalias-global option
+@cindex options, -fno-argument-noalias-global
+@cindex aliasing
+@cindex anti-aliasing
+@cindex overlapping arguments
+@cindex overlays
+@cindex association, storage
+@cindex storage association
+@cindex scheduling of reads and writes
+@cindex reads and writes, scheduling
+
+The @samp{-falias-check}, @samp{-fargument-alias},
+@samp{-fargument-noalias},
+and @samp{-fno-argument-noalias-global} options,
+introduced in version 0.5.20 and
+@code{g77}'s version 2.7.2.2.f.2 of @code{gcc},
+were withdrawn as of @code{g77} version 0.5.23
+due to their not being supported by @code{gcc} version 2.8.
+
+These options, which control the assumptions regarding aliasing
+(overlapping) of writes and reads to main memory (core) made
+by the @code{gcc} back end,
+might well be added back (in some form) in a future version
+of @code{gcc}.
+
+However, these options @emph{are} supported by @code{egcs}.
+
+The information below still is useful, but applies to
+only those versions of @code{g77} that support the
+alias analysis implied by support for these options.
+
+These options are effective only when compiling with @samp{-O}
+(specifying any level other than @samp{-O0})
+or with @samp{-falias-check}.
+
+The default for Fortran code is @samp{-fargument-noalias-global}.
+(The default for C code and code written in other C-based languages
+is @samp{-fargument-alias}.
+These defaults apply regardless of whether you use @code{g77} or
+@code{gcc} to compile your code.)
+
+Note that, on some systems, compiling with @samp{-fforce-addr} in
+effect can produce more optimal code when the default aliasing
+options are in effect (and when optimization is enabled).
+
+If your program is not working when compiled with optimization,
+it is possible it is violating the Fortran standards (77 and 90)
+by relying on the ability to ``safely'' modify variables and
+arrays that are aliased, via procedure calls, to other variables
+and arrays, without using @code{EQUIVALENCE} to explicitly
+set up this kind of aliasing.
+
+(The FORTRAN 77 standard's prohibition of this sort of
+overlap, generally referred to therein as ``storage
+assocation'', appears in Sections 15.9.3.6.
+This prohibition allows implementations, such as @code{g77},
+to, for example, implement the passing of procedures and
+even values in @code{COMMON} via copy operations into local,
+perhaps more efficiently accessed temporaries at entry to a
+procedure, and, where appropriate, via copy operations back
+out to their original locations in memory at exit from that
+procedure, without having to take into consideration the
+order in which the local copies are updated by the code,
+among other things.)
+
+To test this hypothesis, try compiling your program with
+the @samp{-fargument-alias} option, which causes the
+compiler to revert to assumptions essentially the same as
+made by versions of @code{g77} prior to 0.5.20.
+
+If the program works using this option, that strongly suggests
+that the bug is in your program.
+Finding and fixing the bug(s) should result in a program that
+is more standard-conforming and that can be compiled by @code{g77}
+in a way that results in a faster executable.
+
+(You might want to try compiling with @samp{-fargument-noalias},
+a kind of half-way point, to see if the problem is limited to
+aliasing between dummy arguments and @code{COMMON} variables---this
+option assumes that such aliasing is not done, while still allowing
+aliasing among dummy arguments.)
+
+An example of aliasing that is invalid according to the standards
+is shown in the following program, which might @emph{not} produce
+the expected results when executed:
+
+@smallexample
+I = 1
+CALL FOO(I, I)
+PRINT *, I
+END
+
+SUBROUTINE FOO(J, K)
+J = J + K
+K = J * K
+PRINT *, J, K
+END
+@end smallexample
+
+The above program attempts to use the temporary aliasing of the
+@samp{J} and @samp{K} arguments in @samp{FOO} to effect a
+pathological behavior---the simultaneous changing of the values
+of @emph{both} @samp{J} and @samp{K} when either one of them
+is written.
+
+The programmer likely expects the program to print these values:
+
+@example
+2 4
+4
+@end example
+
+However, since the program is not standard-conforming, an
+implementation's behavior when running it is undefined, because
+subroutine @samp{FOO} modifies at least one of the arguments,
+and they are aliased with each other.
+(Even if one of the assignment statements was deleted, the
+program would still violate these rules.
+This kind of on-the-fly aliasing is permitted by the standard
+only when none of the aliased items are defined, or written,
+while the aliasing is in effect.)
+
+As a practical example, an optimizing compiler might schedule
+the @samp{J =} part of the second line of @samp{FOO} @emph{after}
+the reading of @samp{J} and @samp{K} for the @samp{J * K} expression,
+resulting in the following output:
+
+@example
+2 2
+2
+@end example
+
+Essentially, compilers are promised (by the standard and, therefore,
+by programmers who write code they claim to be standard-conforming)
+that if they cannot detect aliasing via static analysis of a single
+program unit's @code{EQUIVALENCE} and @code{COMMON} statements, no
+such aliasing exists.
+In such cases, compilers are free to assume that an assignment to
+one variable will not change the value of another variable, allowing
+it to avoid generating code to re-read the value of the other
+variable, to re-schedule reads and writes, and so on, to produce
+a faster executable.
+
+The same promise holds true for arrays (as seen by the called
+procedure)---an element of one dummy array cannot be aliased
+with, or overlap, any element of another dummy array or be
+in a @code{COMMON} area known to the procedure.
+
+(These restrictions apply only when the procedure defines, or
+writes to, one of the aliased variables or arrays.)
+
+Unfortunately, there is no way to find @emph{all} possible cases of
+violations of the prohibitions against aliasing in Fortran code.
+Static analysis is certainly imperfect, as is run-time analysis,
+since neither can catch all violations.
+(Static analysis can catch all likely violations, and some that
+might never actually happen, while run-time analysis can catch
+only those violations that actually happen during a particular run.
+Neither approach can cope with programs mixing Fortran code with
+routines written in other languages, however.)
+
+Currently, @code{g77} provides neither static nor run-time facilities
+to detect any cases of this problem, although other products might.
+Run-time facilities are more likely to be offered by future
+versions of @code{g77}, though patches improving @code{g77} so that
+it provides either form of detection are welcome.
+
+@node Output Assumed To Flush
+@subsection Output Assumed To Flush
+@cindex ALWAYS_FLUSH
+@cindex synchronous write errors
+@cindex disk full
+@cindex flushing output
+@cindex fflush()
+@cindex I/O, flushing
+@cindex output, flushing
+@cindex writes, flushing
+@cindex NFS
+@cindex network file system
+
+For several versions prior to 0.5.20, @code{g77} configured its
+version of the @code{libf2c} run-time library so that one of
+its configuration macros, @samp{ALWAYS_FLUSH}, was defined.
+
+This was done as a result of a belief that many programs expected
+output to be flushed to the operating system (under UNIX, via
+the @code{fflush()} library call) with the result that errors,
+such as disk full, would be immediately flagged via the
+relevant @code{ERR=} and @code{IOSTAT=} mechanism.
+
+Because of the adverse effects this approach had on the performance
+of many programs, @code{g77} no longer configures @code{libf2c}
+(now named @code{libg2c} in its @code{g77} incarnation)
+to always flush output.
+
+If your program depends on this behavior, either insert the
+appropriate @samp{CALL FLUSH} statements, or modify the sources
+to the @code{libg2c}, rebuild and reinstall @code{g77}, and
+relink your programs with the modified library.
+
+(Ideally, @code{libg2c} would offer the choice at run-time, so
+that a compile-time option to @code{g77} or @code{f2c} could
+result in generating the appropriate calls to flushing or
+non-flushing library routines.)
+
+@xref{Always Flush Output}, for information on how to modify
+the @code{g77} source tree so that a version of @code{libg2c}
+can be built and installed with the @samp{ALWAYS_FLUSH} macro defined.
+
+@node Large File Unit Numbers
+@subsection Large File Unit Numbers
+@cindex MXUNIT
+@cindex unit numbers
+@cindex maximum unit number
+@cindex illegal unit number
+@cindex increasing maximum unit number
+
+If your program crashes at run time with a message including
+the text @samp{illegal unit number}, that probably is
+a message from the run-time library, @code{libg2c}.
+
+The message means that your program has attempted to use a
+file unit number that is out of the range accepted by
+@code{libg2c}.
+Normally, this range is 0 through 99, and the high end
+of the range is controlled by a @code{libg2c} source-file
+macro named @samp{MXUNIT}.
+
+If you can easily change your program to use unit numbers
+in the range 0 through 99, you should do so.
+
+Otherwise, see @ref{Larger File Unit Numbers}, for information on how
+to change @samp{MXUNIT} in @code{libg2c} so you can build and
+install a new version of @code{libg2c} that supports the larger
+unit numbers you need.
+
+@emph{Note:} While @code{libg2c} places a limit on the range
+of Fortran file-unit numbers, the underlying library and operating
+system might impose different kinds of limits.
+For example, some systems limit the number of files simultaneously
+open by a running program.
+Information on how to increase these limits should be found
+in your system's documentation.
+
+@node Floating point precision
+@subsection Floating point precision
+
+@cindex IEEE 754
+@cindex IEEE conformance
+@cindex conformance, IEEE
+@cindex floating point precision
+If your program depends on exact IEEE 754 floating point handling it may
+help on some systems---specifically x86 or m68k hardware---to use
+the @code{-ffloat-store} option or to reset the precision flag on the
+floating point unit @xref{Optimize Options}.
+
+However, it might be better simply to put the FPU into double precision
+mode and not take the performance hit of @code{-ffloat-store}. On x86
+and m68k GNU systems you can do this with a technique similar to that
+for turning on floating point exceptions @xref{Floating-point Exception
+Handling}. The control word could be set to double precision by
+replacing the @code{__setfpucw} call with one like this:
+@smallexample
+ __setfpucw ((_FPU_DEFAULT & ~_FPU_EXTENDED) | _FPU_DOUBLE);
+@end smallexample
+(It is not clear whether this has any effect on the operation of the GNU
+maths library, but we have no evidence of it causing trouble.)
+
+Some targets (such as the Alpha) may need special options for full IEEE
+conformance @xref{Submodel Options,,Hardware Models and
+Configurations,gcc,Using and Porting GNU CC}.
+
+@node Inconsistent Calling Sequences
+@subsection Inconsistent Calling Sequences
+
+@pindex ftnchek
+@cindex floating point errors
+@cindex x86 FPU stack
+Code containing inconsistent calling sequences in the same file is
+normally rejected @xref{GLOBALS}. (Use, say, @code{ftnchek} to ensure
+consistency across source files
+@c makeinfo 1.68 objects to the nested parens
+@ifinfo
+@xref{f2c Skeletons and Prototypes}.)
+@end ifinfo
+@ifnotinfo
+@xref{f2c Skeletons and Prototypes,,
+{Generating Skeletons and Prototypes with @code{f2c}}}.)
+@end ifnotinfo
+
+Mysterious errors, which may appear to be code generation problems, can
+appear specifically on the x86 architecture with some such
+inconsistencies. On x86 hardware, floating point return values of
+functions are placed on the floating point unit's register stack, not
+the normal stack. Thus calling a @code{REAL} or @code{DOUBLE PRECISION}
+@code{FUNCTION} as some other sort of procedure, or vice versa,
+scrambles the floating point stack. This may break unrelated code
+executed later. Similarly if, say, external C routines are written
+incorrectly.
+
+@node Overly Convenient Options
+@section Overly Convenient Command-line Options
+@cindex overly convenient options
+@cindex options, overly convenient
+
+These options should be used only as a quick-and-dirty way to determine
+how well your program will run under different compilation models
+without having to change the source.
+Some are more problematic
+than others, depending on how portable and maintainable you want the
+program to be (and, of course, whether you are allowed to change it
+at all is crucial).
+
+You should not continue to use these command-line options to compile
+a given program, but rather should make changes to the source code:
+
+@table @code
+@cindex -finit-local-zero option
+@cindex options, -finit-local-zero
+@item -finit-local-zero
+(This option specifies that any uninitialized local variables
+and arrays have default initialization to binary zeros.)
+
+Many other compilers do this automatically, which means lots of
+Fortran code developed with those compilers depends on it.
+
+It is safer (and probably
+would produce a faster program) to find the variables and arrays that
+need such initialization and provide it explicitly via @code{DATA}, so that
+@samp{-finit-local-zero} is not needed.
+
+Consider using @samp{-Wuninitialized} (which requires @samp{-O}) to
+find likely candidates, but
+do not specify @samp{-finit-local-zero} or @samp{-fno-automatic},
+or this technique won't work.
+
+@cindex -fno-automatic option
+@cindex options, -fno-automatic
+@item -fno-automatic
+(This option specifies that all local variables and arrays
+are to be treated as if they were named in @code{SAVE} statements.)
+
+Many other compilers do this automatically, which means lots of
+Fortran code developed with those compilers depends on it.
+
+The effect of this is that all non-automatic variables and arrays
+are made static, that is, not placed on the stack or in heap storage.
+This might cause a buggy program to appear to work better.
+If so, rather than relying on this command-line option (and hoping all
+compilers provide the equivalent one), add @code{SAVE}
+statements to some or all program unit sources, as appropriate.
+Consider using @samp{-Wuninitialized} (which requires @samp{-O})
+to find likely candidates, but
+do not specify @samp{-finit-local-zero} or @samp{-fno-automatic},
+or this technique won't work.
+
+The default is @samp{-fautomatic}, which tells @code{g77} to try
+and put variables and arrays on the stack (or in fast registers)
+where possible and reasonable.
+This tends to make programs faster.
+
+@cindex automatic arrays
+@cindex arrays, automatic
+@emph{Note:} Automatic variables and arrays are not affected
+by this option.
+These are variables and arrays that are @emph{necessarily} automatic,
+either due to explicit statements, or due to the way they are
+declared.
+Examples include local variables and arrays not given the
+@code{SAVE} attribute in procedures declared @code{RECURSIVE},
+and local arrays declared with non-constant bounds (automatic
+arrays).
+Currently, @code{g77} supports only automatic arrays, not
+@code{RECURSIVE} procedures or other means of explicitly
+specifying that variables or arrays are automatic.
+
+@cindex -fugly option
+@cindex options, -fugly
+@item -fugly
+Fix the source code so that @samp{-fno-ugly} will work.
+Note that, for many programs, it is difficult to practically
+avoid using the features enabled via @samp{-fugly-init}, and these
+features pose the lowest risk of writing nonportable code, among the
+various ``ugly'' features.
+
+@cindex -f@var{group}-intrinsics-hide option
+@cindex options, -f@var{group}-intrinsics-hide
+@item -f@var{group}-intrinsics-hide
+Change the source code to use @code{EXTERNAL} for any external procedure
+that might be the name of an intrinsic.
+It is easy to find these using @samp{-f@var{group}-intrinsics-disable}.
+@end table
+
+@node Faster Programs
+@section Faster Programs
+@cindex speeding up programs
+@cindex programs, speeding up
+
+Aside from the usual @code{gcc} options, such as @samp{-O},
+@samp{-ffast-math}, and so on, consider trying some of the
+following approaches to speed up your program (once you get
+it working).
+
+@menu
+* Aligned Data::
+* Prefer Automatic Uninitialized Variables::
+* Avoid f2c Compatibility::
+* Use Submodel Options::
+@end menu
+
+@node Aligned Data
+@subsection Aligned Data
+@cindex data, aligned
+@cindex stack, aligned
+@cindex aligned data
+@cindex aligned stack
+@cindex Pentium optimizations
+@cindex optimizations, Pentium
+
+On some systems, such as those with Pentium Pro CPUs, programs
+that make heavy use of @code{REAL(KIND=2)} (@code{DOUBLE PRECISION})
+might run much slower
+than possible due to the compiler not aligning these 64-bit
+values to 64-bit boundaries in memory.
+(The effect also is present, though
+to a lesser extent, on the 586 (Pentium) architecture.)
+
+The Intel x86 architecture generally ensures that these programs will
+work on all its implementations,
+but particular implementations (such as Pentium Pro)
+perform better with more strict alignment.
+(Such behavior isn't unique to the Intel x86 architecture.)
+Other architectures might @emph{demand} 64-bit alignment
+of 64-bit data.
+
+There are a variety of approaches to use to address this problem:
+
+@itemize @bullet
+@item
+@cindex COMMON, layout
+@cindex layout of common blocks
+Order your @code{COMMON} and @code{EQUIVALENCE} areas such
+that the variables and arrays with the widest alignment
+guidelines come first.
+
+For example, on most systems, this would mean placing
+@code{COMPLEX(KIND=2)}, @code{REAL(KIND=2)}, and
+@code{INTEGER(KIND=2)} entities first, followed by @code{REAL(KIND=1)},
+@code{INTEGER(KIND=1)}, and @code{LOGICAL(KIND=1)} entities, then
+@code{INTEGER(KIND=6)} entities, and finally @code{CHARACTER}
+and @code{INTEGER(KIND=3)} entities.
+
+The reason to use such placement is it makes it more likely
+that your data will be aligned properly, without requiring
+you to do detailed analysis of each aggregate (@code{COMMON}
+and @code{EQUIVALENCE}) area.
+
+Specifically, on systems where the above guidelines are
+appropriate, placing @code{CHARACTER} entities before
+@code{REAL(KIND=2)} entities can work just as well,
+but only if the number of bytes occupied by the @code{CHARACTER}
+entities is divisible by the recommended alignment for
+@code{REAL(KIND=2)}.
+
+By ordering the placement of entities in aggregate
+areas according to the simple guidelines above, you
+avoid having to carefully count the number of bytes
+occupied by each entity to determine whether the
+actual alignment of each subsequent entity meets the
+alignment guidelines for the type of that entity.
+
+If you don't ensure correct alignment of @code{COMMON} elements, the
+compiler may be forced by some systems to violate the Fortran semantics by
+adding padding to get @code{DOUBLE PRECISION} data properly aligned.
+If the unfortunate practice is employed of overlaying different types of
+data in the @code{COMMON} block, the different variants
+of this block may become misaligned with respect to each other.
+Even if your platform doesn't require strict alignment,
+@code{COMMON} should be laid out as above for portability.
+(Unfortunately the FORTRAN 77 standard didn't anticipate this
+possible requirement, which is compiler-independent on a given platform.)
+
+@item
+@cindex -malign-double option
+@cindex options, -malign-double
+Use the (x86-specific) @samp{-malign-double} option when compiling
+programs for the Pentium and Pentium Pro architectures (called 586
+and 686 in the @code{gcc} configuration subsystem).
+The warning about this in the @code{gcc} manual isn't
+generally relevant to Fortran,
+but using it will force @code{COMMON} to be padded if necessary to align
+@code{DOUBLE PRECISION} data.
+
+When @code{DOUBLE PRECISION} data is forcibly aligned
+in @code{COMMON} by @code{g77} due to specifying @samp{-malign-double},
+@code{g77} issues a warning about the need to
+insert padding.
+
+In this case, each and every program unit that uses
+the same @code{COMMON} area
+must specify the same layout of variables and their types
+for that area
+and be compiled with @samp{-malign-double} as well.
+@code{g77} will issue warnings in each case,
+but as long as every program unit using that area
+is compiled with the same warnings,
+the resulting object files should work when linked together
+unless the program makes additional assumptions about
+@code{COMMON} area layouts that are outside the scope
+of the FORTRAN 77 standard,
+or uses @code{EQUIVALENCE} or different layouts
+in ways that assume no padding is ever inserted by the compiler.
+
+@emph{Note:} @samp{-malign-double} applies only to
+statically-allocated data.
+Double-precision data on the stack can still
+cause problems due to misalignment.
+@xref{Aligned Data}.
+
+@item
+Ensure that @file{crt0.o} or @file{crt1.o}
+on your system guarantees a 64-bit
+aligned stack for @code{main()}.
+The recent one from GNU (@code{glibc2}) will do this on x86 systems,
+but we don't know of any other x86 setups where it will be right.
+Read your system's documentation to determine if
+it is appropriate to upgrade to a more recent version
+to obtain the optimal alignment.
+@end itemize
+
+Progress is being made on making this work
+``out of the box'' on future versions of @code{g77},
+@code{gcc}, and some of the relevant operating systems
+(such as GNU/Linux).
+
+@node Prefer Automatic Uninitialized Variables
+@subsection Prefer Automatic Uninitialized Variables
+
+If you're using @samp{-fno-automatic} already, you probably
+should change your code to allow compilation with @samp{-fautomatic}
+(the default), to allow the program to run faster.
+
+Similarly, you should be able to use @samp{-fno-init-local-zero}
+(the default) instead of @samp{-finit-local-zero}.
+This is because it is rare that every variable affected by these
+options in a given program actually needs to
+be so affected.
+
+For example, @samp{-fno-automatic}, which effectively @code{SAVE}s
+every local non-automatic variable and array, affects even things like
+@code{DO} iteration
+variables, which rarely need to be @code{SAVE}d, and this often reduces
+run-time performances.
+Similarly, @samp{-fno-init-local-zero} forces such
+variables to be initialized to zero---when @code{SAVE}d (such as when
+@samp{-fno-automatic}), this by itself generally affects only
+startup time for a program, but when not @code{SAVE}d,
+it can slow down the procedure every time it is called.
+
+@xref{Overly Convenient Options,,Overly Convenient Command-Line Options},
+for information on the @samp{-fno-automatic} and
+@samp{-finit-local-zero} options and how to convert
+their use into selective changes in your own code.
+
+@node Avoid f2c Compatibility
+@subsection Avoid f2c Compatibility
+@cindex -fno-f2c option
+@cindex options, -fno-f2c
+@cindex @code{f2c} compatibility
+@cindex compatibility, @code{f2c}
+
+If you aren't linking with any code compiled using
+@code{f2c}, try using the @samp{-fno-f2c} option when
+compiling @emph{all} the code in your program.
+(Note that @code{libf2c} is @emph{not} an example of code
+that is compiled using @code{f2c}---it is compiled by a C
+compiler, typically @code{gcc}.)
+
+@node Use Submodel Options
+@subsection Use Submodel Options
+@cindex Pentium optimizations
+@cindex optimizations, Pentium
+@cindex 586/686 CPUs
+@cindex submodels
+
+Using an appropriate @samp{-m} option to generate specific code for your
+CPU may be worthwhile, though it may mean the executable won't run on
+other versions of the CPU that don't support the same instruction set.
+@xref{Submodel Options,,Hardware Models and Configurations,gcc,Using and
+Porting GNU CC}.
+
+For recent CPUs that don't have explicit support in
+the released version of @code{gcc}, it may still be possible to get
+improvements.
+For instance, the flags recommended for 586/686
+(Pentium(Pro)) chips for building the Linux kernel are:
+
+@smallexample
+-m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2
+-fomit-frame-pointer
+@end smallexample
+
+@noindent @samp{-fomit-frame-pointer} will, however, inhibit debugging
+on x86 systems.
+
+@node Trouble
+@chapter Known Causes of Trouble with GNU Fortran
+@cindex bugs, known
+@cindex installation trouble
+@cindex known causes of trouble
+
+This section describes known problems that affect users of GNU Fortran.
+Most of these are not GNU Fortran bugs per se---if they were, we would
+fix them.
+But the result for a user might be like the result of a bug.
+
+Some of these problems are due to bugs in other software, some are
+missing features that are too much work to add, and some are places
+where people's opinions differ as to what is best.
+
+Information on bugs that show up when configuring, porting, building,
+or installing @code{g77} is not provided here.
+@xref{Problems Installing}.
+
+To find out about major bugs discovered in the current release and
+possible workarounds for them, retrieve
+@uref{ftp://alpha.gnu.org/g77.plan}.
+
+(Note that some of this portion of the manual is lifted
+directly from the @code{gcc} manual, with minor modifications
+to tailor it to users of @code{g77}.
+Anytime a bug seems to have more to do with the @code{gcc}
+portion of @code{g77},
+@xref{Trouble,,Known Causes of Trouble with GNU CC,
+gcc,Using and Porting GNU CC}.)
+
+@menu
+* But-bugs:: Bugs really in other programs or elsewhere.
+* Actual Bugs:: Bugs and misfeatures we will fix later.
+* Missing Features:: Features we already know we want to add later.
+* Disappointments:: Regrettable things we can't change.
+* Non-bugs:: Things we think are right, but some others disagree.
+* Warnings and Errors:: Which problems in your code get warnings,
+ and which get errors.
+@end menu
+
+@node But-bugs
+@section Bugs Not In GNU Fortran
+@cindex but-bugs
+
+These are bugs to which the maintainers often have to reply,
+``but that isn't a bug in @code{g77}@dots{}''.
+Some of these already are fixed in new versions of other
+software; some still need to be fixed; some are problems
+with how @code{g77} is installed or is being used;
+some are the result of bad hardware that causes software
+to misbehave in sometimes bizarre ways;
+some just cannot be addressed at this time until more
+is known about the problem.
+
+Please don't re-report these bugs to the @code{g77} maintainers---if
+you must remind someone how important it is to you that the problem
+be fixed, talk to the people responsible for the other products
+identified below, but preferably only after you've tried the
+latest versions of those products.
+The @code{g77} maintainers have their hands full working on
+just fixing and improving @code{g77}, without serving as a
+clearinghouse for all bugs that happen to affect @code{g77}
+users.
+
+@xref{Collected Fortran Wisdom}, for information on behavior
+of Fortran programs, and the programs that compile them, that
+might be @emph{thought} to indicate bugs.
+
+@menu
+* Signal 11 and Friends:: Strange behavior by any software.
+* Cannot Link Fortran Programs:: Unresolved references.
+* Large Common Blocks:: Problems on older GNU/Linux systems.
+* Debugger Problems:: When the debugger crashes.
+* NeXTStep Problems:: Misbehaving executables.
+* Stack Overflow:: More misbehaving executables.
+* Nothing Happens:: Less behaving executables.
+* Strange Behavior at Run Time:: Executables misbehaving due to
+ bugs in your program.
+* Floating-point Errors:: The results look wrong, but@dots{}.
+@end menu
+
+@node Signal 11 and Friends
+@subsection Signal 11 and Friends
+@cindex signal 11
+@cindex hardware errors
+
+A whole variety of strange behaviors can occur when the
+software, or the way you are using the software,
+stresses the hardware in a way that triggers hardware bugs.
+This might seem hard to believe, but it happens frequently
+enough that there exist documents explaining in detail
+what the various causes of the problems are, what
+typical symptoms look like, and so on.
+
+Generally these problems are referred to in this document
+as ``signal 11'' crashes, because the Linux kernel, running
+on the most popular hardware (the Intel x86 line), often
+stresses the hardware more than other popular operating
+systems.
+When hardware problems do occur under GNU/Linux on x86
+systems, these often manifest themselves as ``signal 11''
+problems, as illustrated by the following diagnostic:
+
+@smallexample
+sh# @kbd{g77 myprog.f}
+gcc: Internal compiler error: program f771 got fatal signal 11
+sh#
+@end smallexample
+
+It is @emph{very} important to remember that the above
+message is @emph{not} the only one that indicates a
+hardware problem, nor does it always indicate a hardware
+problem.
+
+In particular, on systems other than those running the Linux
+kernel, the message might appear somewhat or very different,
+as it will if the error manifests itself while running a
+program other than the @code{g77} compiler.
+For example,
+it will appear somewhat different when running your program,
+when running Emacs, and so on.
+
+How to cope with such problems is well beyond the scope
+of this manual.
+
+However, users of Linux-based systems (such as GNU/Linux)
+should review @uref{http://www.bitwizard.nl/sig11}, a source
+of detailed information on diagnosing hardware problems,
+by recognizing their common symptoms.
+
+Users of other operating systems and hardware might
+find this reference useful as well.
+If you know of similar material for another hardware/software
+combination, please let us know so we can consider including
+a reference to it in future versions of this manual.
+
+@node Cannot Link Fortran Programs
+@subsection Cannot Link Fortran Programs
+@cindex unresolved reference (various)
+@cindex linking error for user code
+@cindex code, user
+@cindex ld error for user code
+@cindex ld can't find strange names
+On some systems, perhaps just those with out-of-date (shared?)
+libraries, unresolved-reference errors happen when linking @code{g77}-compiled
+programs (which should be done using @code{g77}).
+
+If this happens to you, try appending @samp{-lc} to the command you
+use to link the program, e.g. @samp{g77 foo.f -lc}.
+@code{g77} already specifies @samp{-lg2c -lm} when it calls the linker,
+but it cannot also specify @samp{-lc} because not all systems have a
+file named @file{libc.a}.
+
+It is unclear at this point whether there are legitimately installed
+systems where @samp{-lg2c -lm} is insufficient to resolve code produced
+by @code{g77}.
+
+@cindex undefined reference (_main)
+@cindex linking error for user code
+@cindex ld error for user code
+@cindex code, user
+@cindex ld can't find _main
+If your program doesn't link due to unresolved references to names
+like @samp{_main}, make sure you're using the @code{g77} command to do the
+link, since this command ensures that the necessary libraries are
+loaded by specifying @samp{-lg2c -lm} when it invokes the @code{gcc}
+command to do the actual link.
+(Use the @samp{-v} option to discover
+more about what actually happens when you use the @code{g77} and @code{gcc}
+commands.)
+
+Also, try specifying @samp{-lc} as the last item on the @code{g77}
+command line, in case that helps.
+
+@node Large Common Blocks
+@subsection Large Common Blocks
+@cindex common blocks, large
+@cindex large common blocks
+@cindex linker errors
+@cindex ld errors
+@cindex errors, linker
+On some older GNU/Linux systems, programs with common blocks larger
+than 16MB cannot be linked without some kind of error
+message being produced.
+
+This is a bug in older versions of @code{ld}, fixed in
+more recent versions of @code{binutils}, such as version 2.6.
+
+@node Debugger Problems
+@subsection Debugger Problems
+@cindex @code{gdb} support
+@cindex support, @code{gdb}
+There are some known problems when using @code{gdb} on code
+compiled by @code{g77}.
+Inadequate investigation as of the release of 0.5.16 results in not
+knowing which products are the culprit, but @file{gdb-4.14} definitely
+crashes when, for example, an attempt is made to print the contents
+of a @code{COMPLEX(KIND=2)} dummy array, on at least some GNU/Linux
+machines, plus some others.
+Attempts to access assumed-size arrays are
+also known to crash recent versions of @code{gdb}.
+(@code{gdb}'s Fortran support was done for a different compiler
+and isn't properly compatible with @code{g77}.)
+
+@node NeXTStep Problems
+@subsection NeXTStep Problems
+@cindex NeXTStep problems
+@cindex bus error
+@cindex segmentation violation
+Developers of Fortran code on NeXTStep (all architectures) have to
+watch out for the following problem when writing programs with
+large, statically allocated (i.e. non-stack based) data structures
+(common blocks, saved arrays).
+
+Due to the way the native loader (@file{/bin/ld}) lays out
+data structures in virtual memory, it is very easy to create an
+executable wherein the @samp{__DATA} segment overlaps (has addresses in
+common) with the @samp{UNIX STACK} segment.
+
+This leads to all sorts of trouble, from the executable simply not
+executing, to bus errors.
+The NeXTStep command line tool @code{ebadexec} points to
+the problem as follows:
+
+@smallexample
+% @kbd{/bin/ebadexec a.out}
+/bin/ebadexec: __LINKEDIT segment (truncated address = 0x3de000
+rounded size = 0x2a000) of executable file: a.out overlaps with UNIX
+STACK segment (truncated address = 0x400000 rounded size =
+0x3c00000) of executable file: a.out
+@end smallexample
+
+(In the above case, it is the @samp{__LINKEDIT} segment that overlaps the
+stack segment.)
+
+This can be cured by assigning the @samp{__DATA} segment
+(virtual) addresses beyond the stack segment.
+A conservative
+estimate for this is from address 6000000 (hexadecimal) onwards---this
+has always worked for me [Toon Moene]:
+
+@smallexample
+% @kbd{g77 -segaddr __DATA 6000000 test.f}
+% @kbd{ebadexec a.out}
+ebadexec: file: a.out appears to be executable
+%
+@end smallexample
+
+Browsing through @file{@value{path-g77}/Makefile.in},
+you will find that the @code{f771} program itself also has to be
+linked with these flags---it has large statically allocated
+data structures.
+(Version 0.5.18 reduces this somewhat, but probably
+not enough.)
+
+(The above item was contributed by Toon Moene
+(@email{toon@@moene.indiv.nluug.nl}).)
+
+@node Stack Overflow
+@subsection Stack Overflow
+@cindex stack overflow
+@cindex segmentation violation
+@code{g77} code might fail at runtime (probably with a ``segmentation
+violation'') due to overflowing the stack.
+This happens most often on systems with an environment
+that provides substantially more heap space (for use
+when arbitrarily allocating and freeing memory) than stack
+space.
+
+Often this can be cured by
+increasing or removing your shell's limit on stack usage, typically
+using @kbd{limit stacksize} (in @code{csh} and derivatives) or
+@kbd{ulimit -s} (in @code{sh} and derivatives).
+
+Increasing the allowed stack size might, however, require
+changing some operating system or system configuration parameters.
+
+You might be able to work around the problem by compiling with the
+@samp{-fno-automatic} option to reduce stack usage, probably at the
+expense of speed.
+
+@xref{Maximum Stackable Size}, for information on patching
+@code{g77} to use different criteria for placing local
+non-automatic variables and arrays on the stack.
+
+@cindex automatic arrays
+@cindex arrays, automatic
+However, if your program uses large automatic arrays
+(for example, has declarations like @samp{REAL A(N)} where
+@samp{A} is a local array and @samp{N} is a dummy or
+@code{COMMON} variable that can have a large value),
+neither use of @samp{-fno-automatic},
+nor changing the cut-off point for @code{g77} for using the stack,
+will solve the problem by changing the placement of these
+large arrays, as they are @emph{necessarily} automatic.
+
+@code{g77} currently provides no means to specify that
+automatic arrays are to be allocated on the heap instead
+of the stack.
+So, other than increasing the stack size, your best bet is to
+change your source code to avoid large automatic arrays.
+Methods for doing this currently are outside the scope of
+this document.
+
+(@emph{Note:} If your system puts stack and heap space in the
+same memory area, such that they are effectively combined, then
+a stack overflow probably indicates a program that is either
+simply too large for the system, or buggy.)
+
+@node Nothing Happens
+@subsection Nothing Happens
+@cindex nothing happens
+@cindex naming programs @samp{test}
+@cindex @samp{test} programs
+@cindex programs named @samp{test}
+It is occasionally reported that a ``simple'' program,
+such as a ``Hello, World!'' program, does nothing when
+it is run, even though the compiler reported no errors,
+despite the program containing nothing other than a
+simple @code{PRINT} statement.
+
+This most often happens because the program has been
+compiled and linked on a UNIX system and named @samp{test},
+though other names can lead to similarly unexpected
+run-time behavior on various systems.
+
+Essentially this problem boils down to giving
+your program a name that is already known to
+the shell you are using to identify some other program,
+which the shell continues to execute instead of your
+program when you invoke it via, for example:
+
+@smallexample
+sh# @kbd{test}
+sh#
+@end smallexample
+
+Under UNIX and many other system, a simple command name
+invokes a searching mechanism that might well not choose
+the program located in the current working directory if
+there is another alternative (such as the @code{test}
+command commonly installed on UNIX systems).
+
+The reliable way to invoke a program you just linked in
+the current directory under UNIX is to specify it using
+an explicit pathname, as in:
+
+@smallexample
+sh# @kbd{./test}
+ Hello, World!
+sh#
+@end smallexample
+
+Users who encounter this problem should take the time to
+read up on how their shell searches for commands, how to
+set their search path, and so on.
+The relevant UNIX commands to learn about include
+@code{man}, @code{info} (on GNU systems), @code{setenv} (or
+@code{set} and @code{env}), @code{which}, and @code{find}.
+
+@node Strange Behavior at Run Time
+@subsection Strange Behavior at Run Time
+@cindex segmentation violation
+@cindex bus error
+@cindex overwritten data
+@cindex data, overwritten
+@code{g77} code might fail at runtime with ``segmentation violation'',
+``bus error'', or even something as subtle as a procedure call
+overwriting a variable or array element that it is not supposed
+to touch.
+
+These can be symptoms of a wide variety of actual bugs that
+occurred earlier during the program's run, but manifested
+themselves as @emph{visible} problems some time later.
+
+Overflowing the bounds of an array---usually by writing beyond
+the end of it---is one of two kinds of bug that often occurs
+in Fortran code.
+
+The other kind of bug is a mismatch between the actual arguments
+passed to a procedure and the dummy arguments as declared by that
+procedure.
+
+Both of these kinds of bugs, and some others as well, can be
+difficult to track down, because the bug can change its behavior,
+or even appear to not occur, when using a debugger.
+
+That is, these bugs can be quite sensitive to data, including
+data representing the placement of other data in memory (that is,
+pointers, such as the placement of stack frames in memory).
+
+Plans call for improving @code{g77} so that it can offer the
+ability to catch and report some of these problems at compile, link, or
+run time, such as by generating code to detect references to
+beyond the bounds of an array, or checking for agreement between
+calling and called procedures.
+
+In the meantime, finding and fixing the programming
+bugs that lead to these behaviors is, ultimately, the user's
+responsibility, as difficult as that task can sometimes be.
+
+@cindex ``infinite spaces'' printed
+@cindex spaces, endless printing of
+@cindex libc, non-ANSI or non-default
+@cindex C library
+@cindex linking against non-standard library
+@cindex Solaris
+One runtime problem that has been observed might have a simple solution.
+If a formatted @code{WRITE} produces an endless stream of spaces, check
+that your program is linked against the correct version of the C library.
+The configuration process takes care to account for your
+system's normal @file{libc} not being ANSI-standard, which will
+otherwise cause this behaviour.
+If your system's default library is
+ANSI-standard and you subsequently link against a non-ANSI one, there
+might be problems such as this one.
+
+Specifically, on Solaris2 systems,
+avoid picking up the @code{BSD} library from @file{/usr/ucblib}.
+
+@node Floating-point Errors
+@subsection Floating-point Errors
+@cindex floating-point errors
+@cindex rounding errors
+@cindex inconsistent floating-point results
+@cindex results, inconsistent
+Some programs appear to produce inconsistent floating-point
+results compiled by @code{g77} versus by other compilers.
+
+Often the reason for this behavior is the fact that floating-point
+values are represented on almost all Fortran systems by
+@emph{approximations}, and these approximations are inexact
+even for apparently simple values like 0.1, 0.2, 0.3, 0.4, 0.6,
+0.7, 0.8, 0.9, 1.1, and so on.
+Most Fortran systems, including all current ports of @code{g77},
+use binary arithmetic to represent these approximations.
+
+Therefore, the exact value of any floating-point approximation
+as manipulated by @code{g77}-compiled code is representable by
+adding some combination of the values 1.0, 0.5, 0.25, 0.125, and
+so on (just keep dividing by two) through the precision of the
+fraction (typically around 23 bits for @code{REAL(KIND=1)}, 52 for
+@code{REAL(KIND=2)}), then multiplying the sum by a integral
+power of two (in Fortran, by @samp{2**N}) that typically is between
+-127 and +128 for @code{REAL(KIND=1)} and -1023 and +1024 for
+@code{REAL(KIND=2)}, then multiplying by -1 if the number
+is negative.
+
+So, a value like 0.2 is exactly represented in decimal---since
+it is a fraction, @samp{2/10}, with a denominator that is compatible
+with the base of the number system (base 10).
+However, @samp{2/10} cannot be represented by any finite number
+of sums of any of 1.0, 0.5, 0.25, and so on, so 0.2 cannot
+be exactly represented in binary notation.
+
+(On the other hand, decimal notation can represent any binary
+number in a finite number of digits.
+Decimal notation cannot do so with ternary, or base-3,
+notation, which would represent floating-point numbers as
+sums of any of @samp{1/1}, @samp{1/3}, @samp{1/9}, and so on.
+After all, no finite number of decimal digits can exactly
+represent @samp{1/3}.
+Fortunately, few systems use ternary notation.)
+
+Moreover, differences in the way run-time I/O libraries convert
+between these approximations and the decimal representation often
+used by programmers and the programs they write can result in
+apparent differences between results that do not actually exist,
+or exist to such a small degree that they usually are not worth
+worrying about.
+
+For example, consider the following program:
+
+@smallexample
+PRINT *, 0.2
+END
+@end smallexample
+
+When compiled by @code{g77}, the above program might output
+@samp{0.20000003}, while another compiler might produce a
+executable that outputs @samp{0.2}.
+
+This particular difference is due to the fact that, currently,
+conversion of floating-point values by the @code{libg2c} library,
+used by @code{g77}, handles only double-precision values.
+
+Since @samp{0.2} in the program is a single-precision value, it
+is converted to double precision (still in binary notation)
+before being converted back to decimal.
+The conversion to binary appends _binary_ zero digits to the
+original value---which, again, is an inexact approximation of
+0.2---resulting in an approximation that is much less exact
+than is connoted by the use of double precision.
+
+(The appending of binary zero digits has essentially the same
+effect as taking a particular decimal approximation of
+@samp{1/3}, such as @samp{0.3333333}, and appending decimal
+zeros to it, producing @samp{0.33333330000000000}.
+Treating the resulting decimal approximation as if it really
+had 18 or so digits of valid precision would make it seem
+a very poor approximation of @samp{1/3}.)
+
+As a result of converting the single-precision approximation
+to double precision by appending binary zeros, the conversion
+of the resulting double-precision
+value to decimal produces what looks like an incorrect
+result, when in fact the result is @emph{inexact}, and
+is probably no less inaccurate or imprecise an approximation
+of 0.2 than is produced by other compilers that happen to output
+the converted value as ``exactly'' @samp{0.2}.
+(Some compilers behave in a way that can make them appear
+to retain more accuracy across a conversion of a single-precision
+constant to double precision.
+@xref{Context-Sensitive Constants}, to see why
+this practice is illusory and even dangerous.)
+
+Note that a more exact approximation of the constant is
+computed when the program is changed to specify a
+double-precision constant:
+
+@smallexample
+PRINT *, 0.2D0
+END
+@end smallexample
+
+Future versions of @code{g77} and/or @code{libg2c} might convert
+single-precision values directly to decimal,
+instead of converting them to double precision first.
+This would tend to result in output that is more consistent
+with that produced by some other Fortran implementations.
+
+A useful source of information on floating-point computation is David
+Goldberg, `What Every Computer Scientist Should Know About
+Floating-Point Arithmetic', Computing Surveys, 23, March 1991, pp.@:
+5--48.
+An online version is available at
+@uref{http://docs.sun.com},
+and there is a supplemented version, in PostScript form, at
+@uref{http://www.validgh.com/goldberg/paper.ps}.
+
+Information related to the IEEE 754
+floating-point standard by a leading light can be found at
+@uref{http://http.cs.berkeley.edu/%7Ewkahan/ieee754status};
+see also slides from the short course referenced from
+@uref{http://http.cs.berkeley.edu/%7Efateman/}.
+@uref{http://www.linuxsupportline.com/%7Ebillm/} has a brief
+guide to IEEE 754, a somewhat x86-GNU/Linux-specific FAQ,
+and library code for GNU/Linux x86 systems.
+
+The supplement to the PostScript-formatted Goldberg document,
+referenced above, is available in HTML format.
+See `Differences Among IEEE 754 Implementations' by Doug Priest,
+available online at
+@uref{http://www.validgh.com/goldberg/addendum.html}.
+This document explores some of the issues surrounding computing
+of extended (80-bit) results on processors such as the x86,
+especially when those results are arbitrarily truncated
+to 32-bit or 64-bit values by the compiler
+as ``spills''.
+
+@cindex spills of floating-point results
+@cindex 80-bit spills
+@cindex truncation, of floating-point values
+(@emph{Note:} @code{g77} specifically, and @code{gcc} generally,
+does arbitrarily truncate 80-bit results during spills
+as of this writing.
+It is not yet clear whether a future version of
+the GNU compiler suite will offer 80-bit spills
+as an option, or perhaps even as the default behavior.)
+
+@c xref would be different between editions:
+The GNU C library provides routines for controlling the FPU, and other
+documentation about this.
+
+@xref{Floating point precision}, regarding IEEE 754 conformance.
+
+@include bugs.texi
+
+@node Missing Features
+@section Missing Features
+
+This section lists features we know are missing from @code{g77},
+and which we want to add someday.
+(There is no priority implied in the ordering below.)
+
+@menu
+GNU Fortran language:
+* Better Source Model::
+* Fortran 90 Support::
+* Intrinsics in PARAMETER Statements::
+* SELECT CASE on CHARACTER Type::
+* RECURSIVE Keyword::
+* Popular Non-standard Types::
+* Full Support for Compiler Types::
+* Array Bounds Expressions::
+* POINTER Statements::
+* Sensible Non-standard Constructs::
+* FLUSH Statement::
+* Expressions in FORMAT Statements::
+* Explicit Assembler Code::
+* Q Edit Descriptor::
+
+GNU Fortran dialects:
+* Old-style PARAMETER Statements::
+* TYPE and ACCEPT I/O Statements::
+* STRUCTURE UNION RECORD MAP::
+* OPEN CLOSE and INQUIRE Keywords::
+* ENCODE and DECODE::
+* Suppressing Space Padding::
+* Fortran Preprocessor::
+* Bit Operations on Floating-point Data::
+
+New facilities:
+* POSIX Standard::
+* Floating-point Exception Handling::
+* Nonportable Conversions::
+* Large Automatic Arrays::
+* Support for Threads::
+* Increasing Precision/Range::
+
+Better diagnostics:
+* Gracefully Handle Sensible Bad Code::
+* Non-standard Conversions::
+* Non-standard Intrinsics::
+* Modifying DO Variable::
+* Better Pedantic Compilation::
+* Warn About Implicit Conversions::
+* Invalid Use of Hollerith Constant::
+* Dummy Array Without Dimensioning Dummy::
+* Invalid FORMAT Specifiers::
+* Ambiguous Dialects::
+* Unused Labels::
+* Informational Messages::
+
+Run-time facilities:
+* Uninitialized Variables at Run Time::
+* Bounds Checking at Run Time::
+* Portable Unformatted Files::
+
+Debugging:
+* Labels Visible to Debugger::
+@end menu
+
+@node Better Source Model
+@subsection Better Source Model
+
+@code{g77} needs to provide, as the default source-line model,
+a ``pure visual'' mode, where
+the interpretation of a source program in this mode can be accurately
+determined by a user looking at a traditionally displayed rendition
+of the program (assuming the user knows whether the program is fixed
+or free form).
+
+The design should assume the user cannot tell tabs from spaces
+and cannot see trailing spaces on lines, but has canonical tab stops
+and, for fixed-form source, has the ability to always know exactly
+where column 72 is (since the Fortran standard itself requires
+this for fixed-form source).
+
+This would change the default treatment of fixed-form source
+to not treat lines with tabs as if they were infinitely long---instead,
+they would end at column 72 just as if the tabs were replaced
+by spaces in the canonical way.
+
+As part of this, provide common alternate models (Digital, @code{f2c},
+and so on) via command-line options.
+This includes allowing arbitrarily long
+lines for free-form source as well as fixed-form source and providing
+various limits and diagnostics as appropriate.
+
+@cindex sequence numbers
+@cindex columns 73 through 80
+Also, @code{g77} should offer, perhaps even default to, warnings
+when characters beyond the last valid column are anything other
+than spaces.
+This would mean code with ``sequence numbers'' in columns 73 through 80
+would be rejected, and there's a lot of that kind of code around,
+but one of the most frequent bugs encountered by new users is
+accidentally writing fixed-form source code into and beyond
+column 73.
+So, maybe the users of old code would be able to more easily handle
+having to specify, say, a @code{-Wno-col73to80} option.
+
+@node Fortran 90 Support
+@subsection Fortran 90 Support
+@cindex Fortran 90 support
+@cindex support, Fortran 90
+
+@code{g77} does not support many of the features that
+distinguish Fortran 90 (and, now, Fortran 95) from
+ANSI FORTRAN 77.
+
+Some Fortran 90 features are supported, because they
+make sense to offer even to die-hard users of F77.
+For example, many of them codify various ways F77 has
+been extended to meet users' needs during its tenure,
+so @code{g77} might as well offer them as the primary
+way to meet those same needs, even if it offers compatibility
+with one or more of the ways those needs were met
+by other F77 compilers in the industry.
+
+Still, many important F90 features are not supported,
+because no attempt has been made to research each and
+every feature and assess its viability in @code{g77}.
+In the meantime, users who need those features must
+use Fortran 90 compilers anyway, and the best approach
+to adding some F90 features to GNU Fortran might well be
+to fund a comprehensive project to create GNU Fortran 95.
+
+@node Intrinsics in PARAMETER Statements
+@subsection Intrinsics in @code{PARAMETER} Statements
+@cindex PARAMETER statement
+@cindex statements, PARAMETER
+
+@code{g77} doesn't allow intrinsics in @code{PARAMETER} statements.
+This feature is considered to be absolutely vital, even though it
+is not standard-conforming, and is scheduled for version 0.6.
+
+Related to this, @code{g77} doesn't allow non-integral
+exponentiation in @code{PARAMETER} statements, such as
+@samp{PARAMETER (R=2**.25)}.
+It is unlikely @code{g77} will ever support this feature,
+as doing it properly requires complete emulation of
+a target computer's floating-point facilities when
+building @code{g77} as a cross-compiler.
+But, if the @code{gcc} back end is enhanced to provide
+such a facility, @code{g77} will likely use that facility
+in implementing this feature soon afterwards.
+
+@node SELECT CASE on CHARACTER Type
+@subsection @code{SELECT CASE} on @code{CHARACTER} Type
+
+Character-type selector/cases for @code{SELECT CASE} currently
+are not supported.
+
+@node RECURSIVE Keyword
+@subsection @code{RECURSIVE} Keyword
+@cindex RECURSIVE keyword
+@cindex keywords, RECURSIVE
+@cindex recursion, lack of
+@cindex lack of recursion
+
+@code{g77} doesn't support the @code{RECURSIVE} keyword that
+F90 compilers do.
+Nor does it provide any means for compiling procedures
+designed to do recursion.
+
+All recursive code can be rewritten to not use recursion,
+but the result is not pretty.
+
+@node Increasing Precision/Range
+@subsection Increasing Precision/Range
+@cindex -r8
+@cindex -i8
+@cindex f2c
+@cindex increasing precision
+@cindex precision, increasing
+@cindex increasing range
+@cindex range, increasing
+@cindex Toolpack
+@cindex Netlib
+
+Some compilers, such as @code{f2c}, have an option (@samp{-r8} or
+similar) that provides automatic treatment of @code{REAL}
+entities such that they have twice the storage size, and
+a corresponding increase in the range and precision, of what
+would normally be the @code{REAL(KIND=1)} (default @code{REAL}) type.
+(This affects @code{COMPLEX} the same way.)
+
+They also typically offer another option (@samp{-i8}) to increase
+@code{INTEGER} entities so they are twice as large
+(with roughly twice as much range).
+
+(There are potential pitfalls in using these options.)
+
+@code{g77} does not yet offer any option that performs these
+kinds of transformations.
+Part of the problem is the lack of detailed specifications regarding
+exactly how these options affect the interpretation of constants,
+intrinsics, and so on.
+
+Until @code{g77} addresses this need, programmers could improve
+the portability of their code by modifying it to not require
+compile-time options to produce correct results.
+Some free tools are available which may help, specifically
+in Toolpack (which one would expect to be sound) and the @file{fortran}
+section of the Netlib repository.
+
+Use of preprocessors can provide a fairly portable means
+to work around the lack of widely portable methods in the Fortran
+language itself (though increasing acceptance of Fortran 90 would
+alleviate this problem).
+
+@node Popular Non-standard Types
+@subsection Popular Non-standard Types
+@cindex INTEGER*2 support
+@cindex LOGICAL*1 support
+
+@code{g77} doesn't fully support @code{INTEGER*2}, @code{LOGICAL*1},
+and similar.
+Version 0.6 will provide full support for this very
+popular set of features.
+In the meantime, version 0.5.18 provides rudimentary support
+for them.
+
+@node Full Support for Compiler Types
+@subsection Full Support for Compiler Types
+
+@cindex REAL*16 support
+@code{g77} doesn't support @code{INTEGER}, @code{REAL}, and @code{COMPLEX} equivalents
+for @emph{all} applicable back-end-supported types (@code{char}, @code{short int},
+@code{int}, @code{long int}, @code{long long int}, and @code{long double}).
+This means providing intrinsic support, and maybe constant
+support (using F90 syntax) as well, and, for most
+machines will result in automatic support of @code{INTEGER*1},
+@code{INTEGER*2}, @code{INTEGER*8}, maybe even @code{REAL*16},
+and so on.
+This is scheduled for version 0.6.
+
+@node Array Bounds Expressions
+@subsection Array Bounds Expressions
+@cindex array elements, in adjustable array bounds
+@cindex function references, in adjustable array bounds
+@cindex array bounds, adjustable
+@cindex DIMENSION statement
+@cindex statements, DIMENSION
+
+@code{g77} doesn't support more general expressions to dimension
+arrays, such as array element references, function
+references, etc.
+
+For example, @code{g77} currently does not accept the following:
+
+@smallexample
+SUBROUTINE X(M, N)
+INTEGER N(10), M(N(2), N(1))
+@end smallexample
+
+@node POINTER Statements
+@subsection POINTER Statements
+@cindex POINTER statement
+@cindex statements, POINTER
+@cindex Cray pointers
+
+@code{g77} doesn't support pointers or allocatable objects
+(other than automatic arrays).
+This set of features is
+probably considered just behind intrinsics
+in @code{PARAMETER} statements on the list of large,
+important things to add to @code{g77}.
+
+In the meantime, consider using the @code{INTEGER(KIND=7)}
+declaration to specify that a variable must be
+able to hold a pointer.
+This construct is not portable to other non-GNU compilers,
+but it is portable to all machines GNU Fortran supports
+when @code{g77} is used.
+
+@xref{Functions and Subroutines}, for information on
+@code{%VAL()}, @code{%REF()}, and @code{%DESCR()}
+constructs, which are useful for passing pointers to
+procedures written in languages other than Fortran.
+
+@node Sensible Non-standard Constructs
+@subsection Sensible Non-standard Constructs
+
+@code{g77} rejects things other compilers accept,
+like @samp{INTRINSIC SQRT,SQRT}.
+As time permits in the future, some of these things that are easy for
+humans to read and write and unlikely to be intended to mean something
+else will be accepted by @code{g77} (though @samp{-fpedantic} should
+trigger warnings about such non-standard constructs).
+
+Until @code{g77} no longer gratuitously rejects sensible code,
+you might as well fix your code
+to be more standard-conforming and portable.
+
+The kind of case that is important to except from the
+recommendation to change your code is one where following
+good coding rules would force you to write non-standard
+code that nevertheless has a clear meaning.
+
+For example, when writing an @code{INCLUDE} file that
+defines a common block, it might be appropriate to
+include a @code{SAVE} statement for the common block
+(such as @samp{SAVE /CBLOCK/}), so that variables
+defined in the common block retain their values even
+when all procedures declaring the common block become
+inactive (return to their callers).
+
+However, putting @code{SAVE} statements in an @code{INCLUDE}
+file would prevent otherwise standard-conforming code
+from also specifying the @code{SAVE} statement, by itself,
+to indicate that all local variables and arrays are to
+have the @code{SAVE} attribute.
+
+For this reason, @code{g77} already has been changed to
+allow this combination, because although the general
+problem of gratuitously rejecting unambiguous and
+``safe'' constructs still exists in @code{g77}, this
+particular construct was deemed useful enough that
+it was worth fixing @code{g77} for just this case.
+
+So, while there is no need to change your code
+to avoid using this particular construct, there
+might be other, equally appropriate but non-standard
+constructs, that you shouldn't have to stop using
+just because @code{g77} (or any other compiler)
+gratuitously rejects it.
+
+Until the general problem is solved, if you have
+any such construct you believe is worthwhile
+using (e.g. not just an arbitrary, redundant
+specification of an attribute), please submit a
+bug report with an explanation, so we can consider
+fixing @code{g77} just for cases like yours.
+
+@node FLUSH Statement
+@subsection @code{FLUSH} Statement
+
+@code{g77} could perhaps use a @code{FLUSH} statement that
+does what @samp{CALL FLUSH} does,
+but that supports @samp{*} as the unit designator (same unit as for
+@code{PRINT}) and accepts @code{ERR=} and/or @code{IOSTAT=}
+specifiers.
+
+@node Expressions in FORMAT Statements
+@subsection Expressions in @code{FORMAT} Statements
+@cindex FORMAT statement
+@cindex statements, FORMAT
+
+@code{g77} doesn't support @samp{FORMAT(I<J>)} and the like.
+Supporting this requires a significant redesign or replacement
+of @code{libg2c}.
+
+However, @code{g77} does support
+this construct when the expression is constant
+(as of version 0.5.22).
+For example:
+
+@smallexample
+ PARAMETER (IWIDTH = 12)
+10 FORMAT (I<IWIDTH>)
+@end smallexample
+
+Otherwise, at least for output (@code{PRINT} and
+@code{WRITE}), Fortran code making use of this feature can
+be rewritten to avoid it by constructing the @code{FORMAT}
+string in a @code{CHARACTER} variable or array, then
+using that variable or array in place of the @code{FORMAT}
+statement label to do the original @code{PRINT} or @code{WRITE}.
+
+Many uses of this feature on input can be rewritten this way
+as well, but not all can.
+For example, this can be rewritten:
+
+@smallexample
+ READ 20, I
+20 FORMAT (I<J>)
+@end smallexample
+
+However, this cannot, in general, be rewritten, especially
+when @code{ERR=} and @code{END=} constructs are employed:
+
+@smallexample
+ READ 30, J, I
+30 FORMAT (I<J>)
+@end smallexample
+
+@node Explicit Assembler Code
+@subsection Explicit Assembler Code
+
+@code{g77} needs to provide some way, a la @code{gcc}, for @code{g77}
+code to specify explicit assembler code.
+
+@node Q Edit Descriptor
+@subsection Q Edit Descriptor
+@cindex FORMAT statement
+@cindex Q edit descriptor
+@cindex edit descriptor, Q
+
+The @code{Q} edit descriptor in @code{FORMAT}s isn't supported.
+(This is meant to get the number of characters remaining in an input record.)
+Supporting this requires a significant redesign or replacement
+of @code{libg2c}.
+
+A workaround might be using internal I/O or the stream-based intrinsics.
+@xref{FGetC Intrinsic (subroutine)}.
+
+@node Old-style PARAMETER Statements
+@subsection Old-style PARAMETER Statements
+@cindex PARAMETER statement
+@cindex statements, PARAMETER
+
+@code{g77} doesn't accept @samp{PARAMETER I=1}.
+Supporting this obsolete form of
+the @code{PARAMETER} statement would not be particularly hard, as most of the
+parsing code is already in place and working.
+
+Until time/money is
+spent implementing it, you might as well fix your code to use the
+standard form, @samp{PARAMETER (I=1)} (possibly needing
+@samp{INTEGER I} preceding the @code{PARAMETER} statement as well,
+otherwise, in the obsolete form of @code{PARAMETER}, the
+type of the variable is set from the type of the constant being
+assigned to it).
+
+@node TYPE and ACCEPT I/O Statements
+@subsection @code{TYPE} and @code{ACCEPT} I/O Statements
+@cindex TYPE statement
+@cindex statements, TYPE
+@cindex ACCEPT statement
+@cindex statements, ACCEPT
+
+@code{g77} doesn't support the I/O statements @code{TYPE} and
+@code{ACCEPT}.
+These are common extensions that should be easy to support,
+but also are fairly easy to work around in user code.
+
+Generally, any @samp{TYPE fmt,list} I/O statement can be replaced
+by @samp{PRINT fmt,list}.
+And, any @samp{ACCEPT fmt,list} statement can be
+replaced by @samp{READ fmt,list}.
+
+@node STRUCTURE UNION RECORD MAP
+@subsection @code{STRUCTURE}, @code{UNION}, @code{RECORD}, @code{MAP}
+@cindex STRUCTURE statement
+@cindex statements, STRUCTURE
+@cindex UNION statement
+@cindex statements, UNION
+@cindex RECORD statement
+@cindex statements, RECORD
+@cindex MAP statement
+@cindex statements, MAP
+
+@code{g77} doesn't support @code{STRUCTURE}, @code{UNION}, @code{RECORD},
+@code{MAP}.
+This set of extensions is quite a bit
+lower on the list of large, important things to add to @code{g77}, partly
+because it requires a great deal of work either upgrading or
+replacing @code{libg2c}.
+
+@node OPEN CLOSE and INQUIRE Keywords
+@subsection @code{OPEN}, @code{CLOSE}, and @code{INQUIRE} Keywords
+@cindex disposition of files
+@cindex OPEN statement
+@cindex statements, OPEN
+@cindex CLOSE statement
+@cindex statements, CLOSE
+@cindex INQUIRE statement
+@cindex statements, INQUIRE
+
+@code{g77} doesn't have support for keywords such as @code{DISP='DELETE'} in
+the @code{OPEN}, @code{CLOSE}, and @code{INQUIRE} statements.
+These extensions are easy to add to @code{g77} itself, but
+require much more work on @code{libg2c}.
+
+@cindex FORM='PRINT'
+@cindex ANS carriage control
+@cindex carraige control
+@pindex asa
+@pindex fpr
+@code{g77} doesn't support @code{FORM='PRINT'} or an equivalent to
+translate the traditional `carriage control' characters in column 1 of
+output to use backspaces, carriage returns and the like. However
+programs exist to translate them in output files (or standard output).
+These are typically called either @code{fpr} or @code{asa}. You can get
+a version of @code{asa} from
+@uref{ftp://sunsite.unc.edu/pub/Linux/devel/lang/fortran} for GNU
+systems which will probably build easily on other systems.
+Alternatively, @code{fpr} is in BSD distributions in various archive
+sites.
+
+@c (Can both programs can be used in a pipeline,
+@c with a named input file,
+@c and/or with a named output file???)
+
+@node ENCODE and DECODE
+@subsection @code{ENCODE} and @code{DECODE}
+@cindex ENCODE statement
+@cindex statements, ENCODE
+@cindex DECODE statement
+@cindex statements, DECODE
+
+@code{g77} doesn't support @code{ENCODE} or @code{DECODE}.
+
+These statements are best replaced by READ and WRITE statements
+involving internal files (CHARACTER variables and arrays).
+
+For example, replace a code fragment like
+
+@smallexample
+ INTEGER*1 LINE(80)
+@dots{}
+ DECODE (80, 9000, LINE) A, B, C
+@dots{}
+9000 FORMAT (1X, 3(F10.5))
+@end smallexample
+
+@noindent
+with:
+
+@smallexample
+ CHARACTER*80 LINE
+@dots{}
+ READ (UNIT=LINE, FMT=9000) A, B, C
+@dots{}
+9000 FORMAT (1X, 3(F10.5))
+@end smallexample
+
+Similarly, replace a code fragment like
+
+@smallexample
+ INTEGER*1 LINE(80)
+@dots{}
+ ENCODE (80, 9000, LINE) A, B, C
+@dots{}
+9000 FORMAT (1X, 'OUTPUT IS ', 3(F10.5))
+@end smallexample
+
+@noindent
+with:
+
+@smallexample
+ CHARACTER*80 LINE
+@dots{}
+ WRITE (UNIT=LINE, FMT=9000) A, B, C
+@dots{}
+9000 FORMAT (1X, 'OUTPUT IS ', 3(F10.5))
+@end smallexample
+
+It is entirely possible that @code{ENCODE} and @code{DECODE} will
+be supported by a future version of @code{g77}.
+
+@node Suppressing Space Padding
+@subsection Suppressing Space Padding of Source Lines
+
+@code{g77} should offer VXT-Fortran-style suppression of virtual
+spaces at the end of a source line
+if an appropriate command-line option is specified.
+
+This affects cases where
+a character constant is continued onto the next line in a fixed-form
+source file, as in the following example:
+
+@smallexample
+10 PRINT *,'HOW MANY
+ 1 SPACES?'
+@end smallexample
+
+@noindent
+@code{g77}, and many other compilers, virtually extend
+the continued line through column 72 with spaces that become part
+of the character constant, but Digital Fortran normally didn't,
+leaving only one space between @samp{MANY} and @samp{SPACES?}
+in the output of the above statement.
+
+Fairly recently, at least one version of Digital Fortran
+was enhanced to provide the other behavior when a
+command-line option is specified, apparently due to demand
+from readers of the USENET group @file{comp.lang.fortran}
+to offer conformance to this widespread practice in the
+industry.
+@code{g77} should return the favor by offering conformance
+to Digital's approach to handling the above example.
+
+@node Fortran Preprocessor
+@subsection Fortran Preprocessor
+
+@code{g77} should offer a preprocessor designed specifically
+for Fortran to replace @samp{cpp -traditional}.
+There are several out there worth evaluating, at least.
+
+Such a preprocessor would recognize Hollerith constants,
+properly parse comments and character constants, and so on.
+It might also recognize, process, and thus preprocess
+files included via the @code{INCLUDE} directive.
+
+@node Bit Operations on Floating-point Data
+@subsection Bit Operations on Floating-point Data
+@cindex AND intrinsic
+@cindex intrinsics, AND
+@cindex OR intrinsic
+@cindex intrinsics, OR
+@cindex SHIFT intrinsic
+@cindex intrinsics, SHIFT
+
+@code{g77} does not allow @code{REAL} and other non-integral types for
+arguments to intrinsics like @code{AND}, @code{OR}, and @code{SHIFT}.
+
+For example, this program is rejected by @code{g77}, because
+the intrinsic @code{IAND} does not accept @code{REAL} arguments:
+
+@smallexample
+DATA A/7.54/, B/9.112/
+PRINT *, IAND(A, B)
+END
+@end smallexample
+
+@node POSIX Standard
+@subsection @code{POSIX} Standard
+
+@code{g77} should support the POSIX standard for Fortran.
+
+@node Floating-point Exception Handling
+@subsection Floating-point Exception Handling
+@cindex floating point exceptions
+@cindex exceptions, floating point
+@cindex FPE handling
+@cindex NaN values
+
+The @code{gcc} backend and, consequently, @code{g77}, currently provides no
+general control over whether or not floating-point exceptions are trapped or
+ignored.
+(Ignoring them typically results in NaN values being
+propagated in systems that conform to IEEE 754.)
+The behaviour is normally inherited from the system-dependent startup
+code, though some targets, such as the Alpha, have code generation
+options which change the behaviour.
+
+Most systems provide some C-callable mechanism to change this; this can
+be invoked at startup using @code{gcc}'s @code{constructor} attribute.
+For example, just compiling and linking the following C code with your
+program will turn on exception trapping for the ``common'' exceptions
+on an x86-based GNU system:
+
+@smallexample
+#include <fpu_control.h>
+static void __attribute__ ((constructor))
+trapfpe ()
+@{
+ __setfpucw (_FPU_DEFAULT &
+ ~(_FPU_MASK_IM | _FPU_MASK_ZM | _FPU_MASK_OM));
+@}
+@end smallexample
+
+A convenient trick is to compile this something like:
+@smallexample
+gcc -o libtrapfpe.a trapfpe.c
+@end smallexample
+and then use it by adding @code{-trapfpe} to the @code{g77} command line
+when linking.
+
+@node Nonportable Conversions
+@subsection Nonportable Conversions
+@cindex nonportable conversions
+@cindex conversions, nonportable
+
+@code{g77} doesn't accept some particularly nonportable,
+silent data-type conversions such as @code{LOGICAL}
+to @code{REAL} (as in @samp{A=.FALSE.}, where @samp{A}
+is type @code{REAL}), that other compilers might
+quietly accept.
+
+Some of these conversions are accepted by @code{g77}
+when the @samp{-fugly} option is specified.
+Perhaps it should accept more or all of them.
+
+@node Large Automatic Arrays
+@subsection Large Automatic Arrays
+@cindex automatic arrays
+@cindex arrays, automatic
+
+Currently, automatic arrays always are allocated on the stack.
+For situations where the stack cannot be made large enough,
+@code{g77} should offer a compiler option that specifies
+allocation of automatic arrays in heap storage.
+
+@node Support for Threads
+@subsection Support for Threads
+@cindex threads
+@cindex parallel processing
+
+Neither the code produced by @code{g77} nor the @code{libg2c} library
+are thread-safe, nor does @code{g77} have support for parallel processing
+(other than the instruction-level parallelism available on some
+processors).
+A package such as PVM might help here.
+
+@node Gracefully Handle Sensible Bad Code
+@subsection Gracefully Handle Sensible Bad Code
+
+@code{g77} generally should continue processing for
+warnings and recoverable (user) errors whenever possible---that
+is, it shouldn't gratuitously make bad or useless code.
+
+For example:
+
+@smallexample
+INTRINSIC ZABS
+CALL FOO(ZABS)
+END
+@end smallexample
+
+@noindent
+When compiling the above with @samp{-ff2c-intrinsics-disable},
+@code{g77} should indeed complain about passing @code{ZABS},
+but it still should compile, instead of rejecting
+the entire @code{CALL} statement.
+(Some of this is related to improving
+the compiler internals to improve how statements are analyzed.)
+
+@node Non-standard Conversions
+@subsection Non-standard Conversions
+
+@samp{-Wconversion} and related should flag places where non-standard
+conversions are found.
+Perhaps much of this would be part of @samp{-Wugly*}.
+
+@node Non-standard Intrinsics
+@subsection Non-standard Intrinsics
+
+@code{g77} needs a new option, like @samp{-Wintrinsics}, to warn about use of
+non-standard intrinsics without explicit @code{INTRINSIC} statements for them.
+This would help find code that might fail silently when ported to another
+compiler.
+
+@node Modifying DO Variable
+@subsection Modifying @code{DO} Variable
+
+@code{g77} should warn about modifying @code{DO} variables
+via @code{EQUIVALENCE}.
+(The internal information gathered to produce this warning
+might also be useful in setting the
+internal ``doiter'' flag for a variable or even array
+reference within a loop, since that might produce faster code someday.)
+
+For example, this code is invalid, so @code{g77} should warn about
+the invalid assignment to @samp{NOTHER}:
+
+@smallexample
+EQUIVALENCE (I, NOTHER)
+DO I = 1, 100
+ IF (I.EQ. 10) NOTHER = 20
+END DO
+@end smallexample
+
+@node Better Pedantic Compilation
+@subsection Better Pedantic Compilation
+
+@code{g77} needs to support @samp{-fpedantic} more thoroughly,
+and use it only to generate
+warnings instead of rejecting constructs outright.
+Have it warn:
+if a variable that dimensions an array is not a dummy or placed
+explicitly in @code{COMMON} (F77 does not allow it to be
+placed in @code{COMMON} via @code{EQUIVALENCE}); if specification statements
+follow statement-function-definition statements; about all sorts of
+syntactic extensions.
+
+@node Warn About Implicit Conversions
+@subsection Warn About Implicit Conversions
+
+@code{g77} needs a @samp{-Wpromotions} option to warn if source code appears
+to expect automatic, silent, and
+somewhat dangerous compiler-assisted conversion of @code{REAL(KIND=1)}
+constants to @code{REAL(KIND=2)} based on context.
+
+For example, it would warn about cases like this:
+
+@smallexample
+DOUBLE PRECISION FOO
+PARAMETER (TZPHI = 9.435784839284958)
+FOO = TZPHI * 3D0
+@end smallexample
+
+@node Invalid Use of Hollerith Constant
+@subsection Invalid Use of Hollerith Constant
+
+@code{g77} should disallow statements like @samp{RETURN 2HAB},
+which are invalid in both source forms
+(unlike @samp{RETURN (2HAB)},
+which probably still makes no sense but at least can
+be reliably parsed).
+Fixed-form processing rejects it, but not free-form, except
+in a way that is a bit difficult to understand.
+
+@node Dummy Array Without Dimensioning Dummy
+@subsection Dummy Array Without Dimensioning Dummy
+
+@code{g77} should complain when a list of dummy arguments containing an
+adjustable dummy array does
+not also contain every variable listed in the dimension list of the
+adjustable array.
+
+Currently, @code{g77} does complain about a variable that
+dimensions an array but doesn't appear in any dummy list or @code{COMMON}
+area, but this needs to be extended to catch cases where it doesn't appear in
+every dummy list that also lists any arrays it dimensions.
+
+For example, @code{g77} should warn about the entry point @samp{ALT}
+below, since it includes @samp{ARRAY} but not @samp{ISIZE} in its
+list of arguments:
+
+@smallexample
+SUBROUTINE PRIMARY(ARRAY, ISIZE)
+REAL ARRAY(ISIZE)
+ENTRY ALT(ARRAY)
+@end smallexample
+
+@node Invalid FORMAT Specifiers
+@subsection Invalid FORMAT Specifiers
+
+@code{g77} should check @code{FORMAT} specifiers for validity
+as it does @code{FORMAT} statements.
+
+For example, a diagnostic would be produced for:
+
+@smallexample
+PRINT 'HI THERE!' !User meant PRINT *, 'HI THERE!'
+@end smallexample
+
+@node Ambiguous Dialects
+@subsection Ambiguous Dialects
+
+@code{g77} needs a set of options such as @samp{-Wugly*}, @samp{-Wautomatic},
+@samp{-Wvxt}, @samp{-Wf90}, and so on.
+These would warn about places in the user's source where ambiguities
+are found, helpful in resolving ambiguities in the program's
+dialect or dialects.
+
+@node Unused Labels
+@subsection Unused Labels
+
+@code{g77} should warn about unused labels when @samp{-Wunused} is in effect.
+
+@node Informational Messages
+@subsection Informational Messages
+
+@code{g77} needs an option to suppress information messages (notes).
+@samp{-w} does this but also suppresses warnings.
+The default should be to suppress info messages.
+
+Perhaps info messages should simply be eliminated.
+
+@node Uninitialized Variables at Run Time
+@subsection Uninitialized Variables at Run Time
+
+@code{g77} needs an option to initialize everything (not otherwise
+explicitly initialized) to ``weird''
+(machine-dependent) values, e.g. NaNs, bad (non-@code{NULL}) pointers, and
+largest-magnitude integers, would help track down references to
+some kinds of uninitialized variables at run time.
+
+Note that use of the options @samp{-O -Wuninitialized} can catch
+many such bugs at compile time.
+
+@node Bounds Checking at Run Time
+@subsection Bounds Checking at Run Time
+
+@code{g77} should offer run-time bounds-checking of array/subscript references
+in a fashion similar to @code{f2c}.
+
+Note that @code{g77} already warns about references to out-of-bounds
+elements of arrays when it detects these at compile time.
+
+@node Portable Unformatted Files
+@subsection Portable Unformatted Files
+
+@cindex unformatted files
+@cindex file formats
+@cindex binary data
+@cindex byte ordering
+@code{g77} has no facility for exchanging unformatted files with systems
+using different number formats---even differing only in endianness (byte
+order)---or written by other compilers. Some compilers provide
+facilities at least for doing byte-swapping during unformatted I/O.
+
+It is unrealistic to expect to cope with exchanging unformatted files
+with arbitrary other compiler runtimes, but the @code{g77} runtime
+should at least be able to read files written by @code{g77} on systems
+with different number formats, particularly if they differ only in byte
+order.
+
+In case you do need to write a program to translate to or from
+@code{g77} (@code{libf2c}) unformatted files, they are written as
+follows:
+@table @asis
+@item Sequential
+Unformatted sequential records consist of
+@enumerate
+@item
+A number giving the length of the record contents;
+@item
+the length of record contents again (for backspace).
+@end enumerate
+The record length is of C type
+@code{long}; this means that it is 8 bytes on 64-bit systems such as
+Alpha GNU/Linux and 4 bytes on other systems, such as x86 GNU/Linux.
+Consequently such files cannot be exchanged between 64-bit and 32-bit
+systems, even with the same basic number format.
+@item Direct access
+Unformatted direct access files form a byte stream of length
+@var{records}*@var{recl} bytes, where @var{records} is the maximum
+record number (@code{REC=@var{records}}) written and @var{recl} is the
+record length in bytes specified in the @code{OPEN} statement
+(@code{RECL=@var{recl}}). Data appear in the records as determined by
+the relevant @code{WRITE} statement. Dummy records with arbitrary
+contents appear in the file in place of records which haven't been
+written.
+@end table
+
+Thus for exchanging a sequential or direct access unformatted file
+between big- and little-endian 32-bit systems using IEEE 754 floating
+point it would be sufficient to reverse the bytes in consecutive words
+in the file @emph{iff} only @code{REAL*4}, @code{COMPLEX},
+@code{INTEGER*4} and/or @code{LOGICAL*4} data have been written to it by
+@code{g77}.
+
+If necessary, it is possible to do byte-oriented i/o with @code{g77}'s
+@code{FGETC} and @code{FPUTC} intrinsics. Byte-swapping can be done in
+Fortran by equivalencing larger sized variables to an @code{INTEGER*1}
+array or a set of scalars.
+
+@cindex HDF
+@cindex PDB
+If you need to exchange binary data between arbitrary system and
+compiler variations, we recommend using a portable binary format with
+Fortran bindings, such as NCSA's HDF (@uref{http://hdf.ncsa.uiuc.edu/})
+or PACT's PDB@footnote{No, not @emph{that} one.}
+(@uref{http://www.llnl.gov/def_sci/pact/pact_homepage.html}). (Unlike,
+say, CDF or XDR, HDF-like systems write in the native number formats and
+only incur overhead when they are read on a system with a different
+format.) A future @code{g77} runtime library should use such
+techniques.
+
+@node Labels Visible to Debugger
+@subsection Labels Visible to Debugger
+
+@code{g77} should output debugging information for statements labels,
+for use by debuggers that know how to support them.
+Same with weirder things like construct names.
+It is not yet known if any debug formats or debuggers support these.
+
+@node Disappointments
+@section Disappointments and Misunderstandings
+
+These problems are perhaps regrettable, but we don't know any practical
+way around them for now.
+
+@menu
+* Mangling of Names:: @samp{SUBROUTINE FOO} is given
+ external name @samp{foo_}.
+* Multiple Definitions of External Names:: No doing both @samp{COMMON /FOO/}
+ and @samp{SUBROUTINE FOO}.
+* Limitation on Implicit Declarations:: No @samp{IMPLICIT CHARACTER*(*)}.
+@end menu
+
+@node Mangling of Names
+@subsection Mangling of Names in Source Code
+@cindex naming issues
+@cindex external names
+@cindex common blocks
+@cindex name space
+@cindex underscores
+
+The current external-interface design, which includes naming of
+external procedures, COMMON blocks, and the library interface,
+has various usability problems, including things like adding
+underscores where not really necessary (and preventing easier
+inter-language operability) and yet not providing complete
+namespace freedom for user C code linked with Fortran apps (due
+to the naming of functions in the library, among other things).
+
+Project GNU should at least get all this ``right'' for systems
+it fully controls, such as the Hurd, and provide defaults and
+options for compatibility with existing systems and interoperability
+with popular existing compilers.
+
+@node Multiple Definitions of External Names
+@subsection Multiple Definitions of External Names
+@cindex block data
+@cindex BLOCK DATA statement
+@cindex statements, BLOCK DATA
+@cindex COMMON statement
+@cindex statements, COMMON
+@cindex naming conflicts
+
+@code{g77} doesn't allow a common block and an external procedure or
+@code{BLOCK DATA} to have the same name.
+Some systems allow this, but @code{g77} does not,
+to be compatible with @code{f2c}.
+
+@code{g77} could special-case the way it handles
+@code{BLOCK DATA}, since it is not compatible with @code{f2c} in this
+particular area (necessarily, since @code{g77} offers an
+important feature here), but
+it is likely that such special-casing would be very annoying to people
+with programs that use @samp{EXTERNAL FOO}, with no other mention of
+@samp{FOO} in the same program unit, to refer to external procedures, since
+the result would be that @code{g77} would treat these references as requests to
+force-load BLOCK DATA program units.
+
+In that case, if @code{g77} modified
+names of @code{BLOCK DATA} so they could have the same names as
+@code{COMMON}, users
+would find that their programs wouldn't link because the @samp{FOO} procedure
+didn't have its name translated the same way.
+
+(Strictly speaking,
+@code{g77} could emit a null-but-externally-satisfying definition of
+@samp{FOO} with its name transformed as if it had been a
+@code{BLOCK DATA}, but that probably invites more trouble than it's
+worth.)
+
+@node Limitation on Implicit Declarations
+@subsection Limitation on Implicit Declarations
+@cindex IMPLICIT CHARACTER*(*) statement
+@cindex statements, IMPLICIT CHARACTER*(*)
+
+@code{g77} disallows @code{IMPLICIT CHARACTER*(*)}.
+This is not standard-conforming.
+
+@node Non-bugs
+@section Certain Changes We Don't Want to Make
+
+This section lists changes that people frequently request, but which
+we do not make because we think GNU Fortran is better without them.
+
+@menu
+* Backslash in Constants:: Why @samp{'\\'} is a constant that
+ is one, not two, characters long.
+* Initializing Before Specifying:: Why @samp{DATA VAR/1/} can't precede
+ @samp{COMMON VAR}.
+* Context-Sensitive Intrinsicness:: Why @samp{CALL SQRT} won't work.
+* Context-Sensitive Constants:: Why @samp{9.435784839284958} is a
+ single-precision constant,
+ and might be interpreted as
+ @samp{9.435785} or similar.
+* Equivalence Versus Equality:: Why @samp{.TRUE. .EQ. .TRUE.} won't work.
+* Order of Side Effects:: Why @samp{J = IFUNC() - IFUNC()} might
+ not behave as expected.
+@end menu
+
+@node Backslash in Constants
+@subsection Backslash in Constants
+@cindex backslash
+@cindex f77 support
+@cindex support, f77
+
+In the opinion of many experienced Fortran users,
+@samp{-fno-backslash} should be the default, not @samp{-fbackslash},
+as currently set by @code{g77}.
+
+First of all, you can always specify
+@samp{-fno-backslash} to turn off this processing.
+
+Despite not being within the spirit (though apparently within the
+letter) of the ANSI FORTRAN 77 standard, @code{g77} defaults to
+@samp{-fbackslash} because that is what most UNIX @code{f77} commands
+default to, and apparently lots of code depends on this feature.
+
+This is a particularly troubling issue.
+The use of a C construct in the midst of Fortran code
+is bad enough, worse when it makes existing Fortran
+programs stop working (as happens when programs written
+for non-UNIX systems are ported to UNIX systems with
+compilers that provide the @samp{-fbackslash} feature
+as the default---sometimes with no option to turn it off).
+
+The author of GNU Fortran wished, for reasons of linguistic
+purity, to make @samp{-fno-backslash} the default for GNU
+Fortran and thus require users of UNIX @code{f77} and @code{f2c}
+to specify @samp{-fbackslash} to get the UNIX behavior.
+
+However, the realization that @code{g77} is intended as
+a replacement for @emph{UNIX} @code{f77}, caused the author
+to choose to make @code{g77} as compatible with
+@code{f77} as feasible, which meant making @samp{-fbackslash}
+the default.
+
+The primary focus on compatibility is at the source-code
+level, and the question became ``What will users expect
+a replacement for @code{f77} to do, by default?''
+Although at least one UNIX @code{f77} does not provide
+@samp{-fbackslash} as a default, it appears that
+the majority of them do, which suggests that
+the majority of code that is compiled by UNIX @code{f77}
+compilers expects @samp{-fbackslash} to be the default.
+
+It is probably the case that more code exists
+that would @emph{not} work with @samp{-fbackslash}
+in force than code that requires it be in force.
+
+However, most of @emph{that} code is not being compiled
+with @code{f77},
+and when it is, new build procedures (shell scripts,
+makefiles, and so on) must be set up anyway so that
+they work under UNIX.
+That makes a much more natural and safe opportunity for
+non-UNIX users to adapt their build procedures for
+@code{g77}'s default of @samp{-fbackslash} than would
+exist for the majority of UNIX @code{f77} users who
+would have to modify existing, working build procedures
+to explicitly specify @samp{-fbackslash} if that was
+not the default.
+
+One suggestion has been to configure the default for
+@samp{-fbackslash} (and perhaps other options as well)
+based on the configuration of @code{g77}.
+
+This is technically quite straightforward, but will be avoided
+even in cases where not configuring defaults to be
+dependent on a particular configuration greatly inconveniences
+some users of legacy code.
+
+Many users appreciate the GNU compilers because they provide an
+environment that is uniform across machines.
+These users would be
+inconvenienced if the compiler treated things like the
+format of the source code differently on certain machines.
+
+Occasionally users write programs intended only for a particular machine
+type.
+On these occasions, the users would benefit if the GNU Fortran compiler
+were to support by default the same dialect as the other compilers on
+that machine.
+But such applications are rare.
+And users writing a
+program to run on more than one type of machine cannot possibly benefit
+from this kind of compatibility.
+(This is consistent with the design goals for @code{gcc}.
+To change them for @code{g77}, you must first change them
+for @code{gcc}.
+Do not ask the maintainers of @code{g77} to do this for you,
+or to disassociate @code{g77} from the widely understood, if
+not widely agreed-upon, goals for GNU compilers in general.)
+
+This is why GNU Fortran does and will treat backslashes in the same
+fashion on all types of machines (by default).
+@xref{Direction of Language Development}, for more information on
+this overall philosophy guiding the development of the GNU Fortran
+language.
+
+Of course, users strongly concerned about portability should indicate
+explicitly in their build procedures which options are expected
+by their source code, or write source code that has as few such
+expectations as possible.
+
+For example, avoid writing code that depends on backslash (@samp{\})
+being interpreted either way in particular, such as by
+starting a program unit with:
+
+@smallexample
+CHARACTER BACKSL
+PARAMETER (BACKSL = '\\')
+@end smallexample
+
+@noindent
+Then, use concatenation of @samp{BACKSL} anyplace a backslash
+is desired.
+In this way, users can write programs which have the same meaning
+in many Fortran dialects.
+
+(However, this technique does not work for Hollerith constants---which
+is just as well, since the only generally portable uses for Hollerith
+constants are in places where character constants can and should
+be used instead, for readability.)
+
+@node Initializing Before Specifying
+@subsection Initializing Before Specifying
+@cindex initialization, statement placement
+@cindex placing initialization statements
+
+@code{g77} does not allow @samp{DATA VAR/1/} to appear in the
+source code before @samp{COMMON VAR},
+@samp{DIMENSION VAR(10)}, @samp{INTEGER VAR}, and so on.
+In general, @code{g77} requires initialization of a variable
+or array to be specified @emph{after} all other specifications
+of attributes (type, size, placement, and so on) of that variable
+or array are specified (though @emph{confirmation} of data type is
+permitted).
+
+It is @emph{possible} @code{g77} will someday allow all of this,
+even though it is not allowed by the FORTRAN 77 standard.
+
+Then again, maybe it is better to have
+@code{g77} always require placement of @code{DATA}
+so that it can possibly immediately write constants
+to the output file, thus saving time and space.
+
+That is, @samp{DATA A/1000000*1/} should perhaps always
+be immediately writable to canonical assembler, unless it's already known
+to be in a @code{COMMON} area following as-yet-uninitialized stuff,
+and to do this it cannot be followed by @samp{COMMON A}.
+
+@node Context-Sensitive Intrinsicness
+@subsection Context-Sensitive Intrinsicness
+@cindex intrinsics, context-sensitive
+@cindex context-sensitive intrinsics
+
+@code{g77} treats procedure references to @emph{possible} intrinsic
+names as always enabling their intrinsic nature, regardless of
+whether the @emph{form} of the reference is valid for that
+intrinsic.
+
+For example, @samp{CALL SQRT} is interpreted by @code{g77} as
+an invalid reference to the @code{SQRT} intrinsic function,
+because the reference is a subroutine invocation.
+
+First, @code{g77} recognizes the statement @samp{CALL SQRT}
+as a reference to a @emph{procedure} named @samp{SQRT}, not
+to a @emph{variable} with that name (as it would for a statement
+such as @samp{V = SQRT}).
+
+Next, @code{g77} establishes that, in the program unit being compiled,
+@code{SQRT} is an intrinsic---not a subroutine that
+happens to have the same name as an intrinsic (as would be
+the case if, for example, @samp{EXTERNAL SQRT} was present).
+
+Finally, @code{g77} recognizes that the @emph{form} of the
+reference is invalid for that particular intrinsic.
+That is, it recognizes that it is invalid for an intrinsic
+@emph{function}, such as @code{SQRT}, to be invoked as
+a @emph{subroutine}.
+
+At that point, @code{g77} issues a diagnostic.
+
+Some users claim that it is ``obvious'' that @samp{CALL SQRT}
+references an external subroutine of their own, not an
+intrinsic function.
+
+However, @code{g77} knows about intrinsic
+subroutines, not just functions, and is able to support both having
+the same names, for example.
+
+As a result of this, @code{g77} rejects calls
+to intrinsics that are not subroutines, and function invocations
+of intrinsics that are not functions, just as it (and most compilers)
+rejects invocations of intrinsics with the wrong number (or types)
+of arguments.
+
+So, use the @samp{EXTERNAL SQRT} statement in a program unit that calls
+a user-written subroutine named @samp{SQRT}.
+
+@node Context-Sensitive Constants
+@subsection Context-Sensitive Constants
+@cindex constants, context-sensitive
+@cindex context-sensitive constants
+
+@code{g77} does not use context to determine the types of
+constants or named constants (@code{PARAMETER}), except
+for (non-standard) typeless constants such as @samp{'123'O}.
+
+For example, consider the following statement:
+
+@smallexample
+PRINT *, 9.435784839284958 * 2D0
+@end smallexample
+
+@noindent
+@code{g77} will interpret the (truncated) constant
+@samp{9.435784839284958} as a @code{REAL(KIND=1)}, not @code{REAL(KIND=2)},
+constant, because the suffix @code{D0} is not specified.
+
+As a result, the output of the above statement when
+compiled by @code{g77} will appear to have ``less precision''
+than when compiled by other compilers.
+
+In these and other cases, some compilers detect the
+fact that a single-precision constant is used in
+a double-precision context and therefore interpret the
+single-precision constant as if it was @emph{explicitly}
+specified as a double-precision constant.
+(This has the effect of appending @emph{decimal}, not
+@emph{binary}, zeros to the fractional part of the
+number---producing different computational results.)
+
+The reason this misfeature is dangerous is that a slight,
+apparently innocuous change to the source code can change
+the computational results.
+Consider:
+
+@smallexample
+REAL ALMOST, CLOSE
+DOUBLE PRECISION FIVE
+PARAMETER (ALMOST = 5.000000000001)
+FIVE = 5
+CLOSE = 5.000000000001
+PRINT *, 5.000000000001 - FIVE
+PRINT *, ALMOST - FIVE
+PRINT *, CLOSE - FIVE
+END
+@end smallexample
+
+@noindent
+Running the above program should
+result in the same value being
+printed three times.
+With @code{g77} as the compiler,
+it does.
+
+However, compiled by many other compilers,
+running the above program would print
+two or three distinct values, because
+in two or three of the statements, the
+constant @samp{5.000000000001}, which
+on most systems is exactly equal to @samp{5.}
+when interpreted as a single-precision constant,
+is instead interpreted as a double-precision
+constant, preserving the represented
+precision.
+However, this ``clever'' promotion of
+type does not extend to variables or,
+in some compilers, to named constants.
+
+Since programmers often are encouraged to replace manifest
+constants or permanently-assigned variables with named
+constants (@code{PARAMETER} in Fortran), and might need
+to replace some constants with variables having the same
+values for pertinent portions of code,
+it is important that compilers treat code so modified in the
+same way so that the results of such programs are the same.
+@code{g77} helps in this regard by treating constants just
+the same as variables in terms of determining their types
+in a context-independent way.
+
+Still, there is a lot of existing Fortran code that has
+been written to depend on the way other compilers freely
+interpret constants' types based on context, so anything
+@code{g77} can do to help flag cases of this in such code
+could be very helpful.
+
+@node Equivalence Versus Equality
+@subsection Equivalence Versus Equality
+@cindex .EQV., with integer operands
+@cindex comparing logical expressions
+@cindex logical expressions, comparing
+
+Use of @code{.EQ.} and @code{.NE.} on @code{LOGICAL} operands
+is not supported, except via @samp{-fugly}, which is not
+recommended except for legacy code (where the behavior expected
+by the @emph{code} is assumed).
+
+Legacy code should be changed, as resources permit, to use @code{.EQV.}
+and @code{.NEQV.} instead, as these are permitted by the various
+Fortran standards.
+
+New code should never be written expecting @code{.EQ.} or @code{.NE.}
+to work if either of its operands is @code{LOGICAL}.
+
+The problem with supporting this ``feature'' is that there is
+unlikely to be consensus on how it works, as illustrated by the
+following sample program:
+
+@smallexample
+LOGICAL L,M,N
+DATA L,M,N /3*.FALSE./
+IF (L.AND.M.EQ.N) PRINT *,'L.AND.M.EQ.N'
+END
+@end smallexample
+
+The issue raised by the above sample program is: what is the
+precedence of @code{.EQ.} (and @code{.NE.}) when applied to
+@code{LOGICAL} operands?
+
+Some programmers will argue that it is the same as the precedence
+for @code{.EQ.} when applied to numeric (such as @code{INTEGER})
+operands.
+By this interpretation, the subexpression @samp{M.EQ.N} must be
+evaluated first in the above program, resulting in a program that,
+when run, does not execute the @code{PRINT} statement.
+
+Other programmers will argue that the precedence is the same as
+the precedence for @code{.EQV.}, which is restricted by the standards
+to @code{LOGICAL} operands.
+By this interpretation, the subexpression @samp{L.AND.M} must be
+evaluated first, resulting in a program that @emph{does} execute
+the @code{PRINT} statement.
+
+Assigning arbitrary semantic interpretations to syntactic expressions
+that might legitimately have more than one ``obvious'' interpretation
+is generally unwise.
+
+The creators of the various Fortran standards have done a good job
+in this case, requiring a distinct set of operators (which have their
+own distinct precedence) to compare @code{LOGICAL} operands.
+This requirement results in expression syntax with more certain
+precedence (without requiring substantial context), making it easier
+for programmers to read existing code.
+@code{g77} will avoid muddying up elements of the Fortran language
+that were well-designed in the first place.
+
+(Ask C programmers about the precedence of expressions such as
+@samp{(a) & (b)} and @samp{(a) - (b)}---they cannot even tell
+you, without knowing more context, whether the @samp{&} and @samp{-}
+operators are infix (binary) or unary!)
+
+@node Order of Side Effects
+@subsection Order of Side Effects
+@cindex side effects, order of evaluation
+@cindex order of evaluation, side effects
+
+@code{g77} does not necessarily produce code that, when run, performs
+side effects (such as those performed by function invocations)
+in the same order as in some other compiler---or even in the same
+order as another version, port, or invocation (using different
+command-line options) of @code{g77}.
+
+It is never safe to depend on the order of evaluation of side effects.
+For example, an expression like this may very well behave differently
+from one compiler to another:
+
+@smallexample
+J = IFUNC() - IFUNC()
+@end smallexample
+
+@noindent
+There is no guarantee that @samp{IFUNC} will be evaluated in any particular
+order.
+Either invocation might happen first.
+If @samp{IFUNC} returns 5 the first time it is invoked, and
+returns 12 the second time, @samp{J} might end up with the
+value @samp{7}, or it might end up with @samp{-7}.
+
+Generally, in Fortran, procedures with side-effects intended to
+be visible to the caller are best designed as @emph{subroutines},
+not functions.
+Examples of such side-effects include:
+
+@itemize @bullet
+@item
+The generation of random numbers
+that are intended to influence return values.
+
+@item
+Performing I/O
+(other than internal I/O to local variables).
+
+@item
+Updating information in common blocks.
+@end itemize
+
+An example of a side-effect that is not intended to be visible
+to the caller is a function that maintains a cache of recently
+calculated results, intended solely to speed repeated invocations
+of the function with identical arguments.
+Such a function can be safely used in expressions, because
+if the compiler optimizes away one or more calls to the
+function, operation of the program is unaffected (aside
+from being speeded up).
+
+@node Warnings and Errors
+@section Warning Messages and Error Messages
+
+@cindex error messages
+@cindex warnings vs errors
+@cindex messages, warning and error
+The GNU compiler can produce two kinds of diagnostics: errors and
+warnings.
+Each kind has a different purpose:
+
+@itemize @w{}
+@item
+@emph{Errors} report problems that make it impossible to compile your
+program.
+GNU Fortran reports errors with the source file name, line
+number, and column within the line where the problem is apparent.
+
+@item
+@emph{Warnings} report other unusual conditions in your code that
+@emph{might} indicate a problem, although compilation can (and does)
+proceed.
+Warning messages also report the source file name, line number,
+and column information,
+but include the text @samp{warning:} to distinguish them
+from error messages.
+@end itemize
+
+Warnings might indicate danger points where you should check to make sure
+that your program really does what you intend; or the use of obsolete
+features; or the use of nonstandard features of GNU Fortran.
+Many warnings are issued only if you ask for them, with one of the
+@samp{-W} options (for instance, @samp{-Wall} requests a variety of
+useful warnings).
+
+@emph{Note:} Currently, the text of the line and a pointer to the column
+is printed in most @code{g77} diagnostics.
+Probably, as of version 0.6, @code{g77} will
+no longer print the text of the source line, instead printing
+the column number following the file name and line number in
+a form that GNU Emacs recognizes.
+This change is expected to speed up and reduce the memory usage
+of the @code{g77} compiler.
+@c
+@c Say this when it is true -- hopefully 0.6, maybe 0.7 or later. --burley
+@c
+@c GNU Fortran always tries to compile your program if possible; it never
+@c gratuitously rejects a program whose meaning is clear merely because
+@c (for instance) it fails to conform to a standard. In some cases,
+@c however, the Fortran standard specifies that certain extensions are
+@c forbidden, and a diagnostic @emph{must} be issued by a conforming
+@c compiler. The @samp{-pedantic} option tells GNU Fortran to issue warnings
+@c in such cases; @samp{-pedantic-errors} says to make them errors instead.
+@c This does not mean that @emph{all} non-ANSI constructs get warnings
+@c or errors.
+
+@xref{Warning Options,,Options to Request or Suppress Warnings}, for
+more detail on these and related command-line options.
+
+@node Open Questions
+@chapter Open Questions
+
+Please consider offering useful answers to these questions!
+
+@itemize @bullet
+@item
+@code{LOC()} and other intrinsics are probably somewhat misclassified.
+Is the a need for more precise classification of intrinsics, and if so,
+what are the appropriate groupings?
+Is there a need to individually
+enable/disable/delete/hide intrinsics from the command line?
+@end itemize
+
+@node Bugs
+@chapter Reporting Bugs
+@cindex bugs
+@cindex reporting bugs
+
+Your bug reports play an essential role in making GNU Fortran reliable.
+
+When you encounter a problem, the first thing to do is to see if it is
+already known.
+@xref{Trouble}.
+If it isn't known, then you should report the problem.
+
+Reporting a bug might help you by bringing a solution to your problem, or
+it might not.
+(If it does not, look in the service directory; see
+@ref{Service}.)
+In any case, the principal function of a bug report is
+to help the entire community by making the next version of GNU Fortran work
+better.
+Bug reports are your contribution to the maintenance of GNU Fortran.
+
+Since the maintainers are very overloaded, we cannot respond to every
+bug report.
+However, if the bug has not been fixed, we are likely to
+send you a patch and ask you to tell us whether it works.
+
+In order for a bug report to serve its purpose, you must include the
+information that makes for fixing the bug.
+
+@menu
+* Criteria: Bug Criteria. Have you really found a bug?
+* Where: Bug Lists. Where to send your bug report.
+* Reporting: Bug Reporting. How to report a bug effectively.
+* Patches: Sending Patches. How to send a patch for GNU Fortran.
+@end menu
+
+@xref{Trouble,,Known Causes of Trouble with GNU Fortran},
+for information on problems we already know about.
+
+@xref{Service,,How To Get Help with GNU Fortran},
+for information on where to ask for help.
+
+@node Bug Criteria
+@section Have You Found a Bug?
+@cindex bug criteria
+
+If you are not sure whether you have found a bug, here are some guidelines:
+
+@itemize @bullet
+@cindex fatal signal
+@cindex core dump
+@item
+If the compiler gets a fatal signal, for any input whatever, that is a
+compiler bug.
+Reliable compilers never crash---they just remain obsolete.
+
+@cindex invalid assembly code
+@cindex assembly code, invalid
+@item
+If the compiler produces invalid assembly code, for any input whatever,
+@c (except an @code{asm} statement),
+that is a compiler bug, unless the
+compiler reports errors (not just warnings) which would ordinarily
+prevent the assembler from being run.
+
+@cindex undefined behavior
+@cindex undefined function value
+@item
+If the compiler produces valid assembly code that does not correctly
+execute the input source code, that is a compiler bug.
+
+However, you must double-check to make sure, because you might have run
+into an incompatibility between GNU Fortran and traditional Fortran.
+@c (@pxref{Incompatibilities}).
+These incompatibilities might be considered
+bugs, but they are inescapable consequences of valuable features.
+
+Or you might have a program whose behavior is undefined, which happened
+by chance to give the desired results with another Fortran compiler.
+It is best to check the relevant Fortran standard thoroughly if
+it is possible that the program indeed does something undefined.
+
+After you have localized the error to a single source line, it should
+be easy to check for these things.
+If your program is correct and well defined, you have found
+a compiler bug.
+
+It might help if, in your submission, you identified the specific
+language in the relevant Fortran standard that specifies the
+desired behavior, if it isn't likely to be obvious and agreed-upon
+by all Fortran users.
+
+@item
+If the compiler produces an error message for valid input, that is a
+compiler bug.
+
+@cindex invalid input
+@item
+If the compiler does not produce an error message for invalid input,
+that is a compiler bug.
+However, you should note that your idea of
+``invalid input'' might be someone else's idea
+of ``an extension'' or ``support for traditional practice''.
+
+@item
+If you are an experienced user of Fortran compilers, your suggestions
+for improvement of GNU Fortran are welcome in any case.
+@end itemize
+
+Many, perhaps most, bug reports against @code{g77} turn out to
+be bugs in the user's code.
+While we find such bug reports educational, they sometimes take
+a considerable amount of time to track down or at least respond
+to---time we could be spending making @code{g77}, not some user's
+code, better.
+
+Some steps you can take to verify that the bug is not certainly
+in the code you're compiling with @code{g77}:
+
+@itemize @bullet
+@item
+Compile your code using the @code{g77} options @samp{-W -Wall -O}.
+These options enable many useful warning; the @samp{-O} option
+enables flow analysis that enables the uninitialized-variable
+warning.
+
+If you investigate the warnings and find evidence of possible bugs
+in your code, fix them first and retry @code{g77}.
+
+@item
+Compile your code using the @code{g77} options @samp{-finit-local-zero},
+@samp{-fno-automatic}, @samp{-ffloat-store}, and various
+combinations thereof.
+
+If your code works with any of these combinations, that is not
+proof that the bug isn't in @code{g77}---a @code{g77} bug exposed
+by your code might simply be avoided, or have a different, more subtle
+effect, when different options are used---but it can be a
+strong indicator that your code is making unwarranted assumptions
+about the Fortran dialect and/or underlying machine it is
+being compiled and run on.
+
+@xref{Overly Convenient Options,,Overly Convenient Command-Line Options},
+for information on the @samp{-fno-automatic} and
+@samp{-finit-local-zero} options and how to convert
+their use into selective changes in your own code.
+
+@item
+@pindex ftnchek
+Validate your code with @code{ftnchek} or a similar code-checking
+tool.
+@code{ftnchek} can be found at @uref{ftp://ftp.netlib.org/fortran}
+or @uref{ftp://ftp.dsm.fordham.edu}.
+
+@pindex make
+@cindex Makefile example
+Here are some sample @file{Makefile} rules using @code{ftnchek}
+``project'' files to do cross-file checking and @code{sfmakedepend}
+(from @uref{ftp://ahab.rutgers.edu/pub/perl/sfmakedepend})
+to maintain dependencies automatically.
+These assume the use of GNU @code{make}.
+
+@smallexample
+# Dummy suffix for ftnchek targets:
+.SUFFIXES: .chek
+.PHONY: chekall
+
+# How to compile .f files (for implicit rule):
+FC = g77
+# Assume `include' directory:
+FFLAGS = -Iinclude -g -O -Wall
+
+# Flags for ftnchek:
+CHEK1 = -array=0 -include=includes -noarray
+CHEK2 = -nonovice -usage=1 -notruncation
+CHEKFLAGS = $(CHEK1) $(CHEK2)
+
+# Run ftnchek with all the .prj files except the one corresponding
+# to the target's root:
+%.chek : %.f ; \
+ ftnchek $(filter-out $*.prj,$(PRJS)) $(CHEKFLAGS) \
+ -noextern -library $<
+
+# Derive a project file from a source file:
+%.prj : %.f ; \
+ ftnchek $(CHEKFLAGS) -noextern -project -library $<
+
+# The list of objects is assumed to be in variable OBJS.
+# Sources corresponding to the objects:
+SRCS = $(OBJS:%.o=%.f)
+# ftnchek project files:
+PRJS = $(OBJS:%.o=%.prj)
+
+# Build the program
+prog: $(OBJS) ; \
+ $(FC) -o $@ $(OBJS)
+
+chekall: $(PRJS) ; \
+ ftnchek $(CHEKFLAGS) $(PRJS)
+
+prjs: $(PRJS)
+
+# For Emacs M-x find-tag:
+TAGS: $(SRCS) ; \
+ etags $(SRCS)
+
+# Rebuild dependencies:
+depend: ; \
+ sfmakedepend -I $(PLTLIBDIR) -I includes -a prj $(SRCS1)
+@end smallexample
+
+@item
+Try your code out using other Fortran compilers, such as @code{f2c}.
+If it does not work on at least one other compiler (assuming the
+compiler supports the features the code needs), that is a strong
+indicator of a bug in the code.
+
+However, even if your code works on many compilers @emph{except}
+@code{g77}, that does @emph{not} mean the bug is in @code{g77}.
+It might mean the bug is in your code, and that @code{g77} simply
+exposes it more readily than other compilers.
+@end itemize
+
+@node Bug Lists
+@section Where to Report Bugs
+@cindex bug report mailing lists
+@kindex @value{email-bugs}
+Send bug reports for GNU Fortran to @email{@value{email-bugs}}.
+
+Often people think of posting bug reports to a newsgroup instead of
+mailing them.
+This sometimes appears to work, but it has one problem which can be
+crucial: a newsgroup posting does not contain a mail path back to the
+sender.
+Thus, if maintainers need more information, they might be unable
+to reach you. For this reason, you should always send bug reports by
+mail to the proper mailing list.
+
+As a last resort, send bug reports on paper to:
+
+@example
+GNU Compiler Bugs
+Free Software Foundation
+59 Temple Place - Suite 330
+Boston, MA 02111-1307, USA
+@end example
+
+@node Bug Reporting
+@section How to Report Bugs
+@cindex compiler bugs, reporting
+
+The fundamental principle of reporting bugs usefully is this:
+@strong{report all the facts}.
+If you are not sure whether to state a
+fact or leave it out, state it!
+
+Often people omit facts because they think they know what causes the
+problem and they conclude that some details don't matter.
+Thus, you might
+assume that the name of the variable you use in an example does not matter.
+Well, probably it doesn't, but one cannot be sure.
+Perhaps the bug is a
+stray memory reference which happens to fetch from the location where that
+name is stored in memory; perhaps, if the name were different, the contents
+of that location would fool the compiler into doing the right thing despite
+the bug.
+Play it safe and give a specific, complete example.
+That is the
+easiest thing for you to do, and the most helpful.
+
+Keep in mind that the purpose of a bug report is to enable someone to
+fix the bug if it is not known.
+It isn't very important what happens if
+the bug is already known.
+Therefore, always write your bug reports on
+the assumption that the bug is not known.
+
+Sometimes people give a few sketchy facts and ask, ``Does this ring a
+bell?''
+This cannot help us fix a bug, so it is rarely helpful.
+We respond by asking for enough details to enable us to investigate.
+You might as well expedite matters by sending them to begin with.
+(Besides, there are enough bells ringing around here as it is.)
+
+Try to make your bug report self-contained.
+If we have to ask you for
+more information, it is best if you include all the previous information
+in your response, as well as the information that was missing.
+
+Please report each bug in a separate message.
+This makes it easier for
+us to track which bugs have been fixed and to forward your bugs reports
+to the appropriate maintainer.
+
+Do not compress and encode any part of your bug report using programs
+such as @file{uuencode}.
+If you do so it will slow down the processing
+of your bug.
+If you must submit multiple large files, use @file{shar},
+which allows us to read your message without having to run any
+decompression programs.
+
+(As a special exception for GNU Fortran bug-reporting, at least
+for now, if you are sending more than a few lines of code, if
+your program's source file format contains ``interesting'' things
+like trailing spaces or strange characters, or if you need to
+include binary data files, it is acceptable to put all the
+files together in a @code{tar} archive, and, whether you need to
+do that, it is acceptable to then compress the single file (@code{tar}
+archive or source file)
+using @code{gzip} and encode it via @code{uuencode}.
+Do not use any MIME stuff---the current maintainer can't decode this.
+Using @code{compress} instead of @code{gzip} is acceptable, assuming
+you have licensed the use of the patented algorithm in
+@code{compress} from Unisys.)
+
+To enable someone to investigate the bug, you should include all these
+things:
+
+@itemize @bullet
+@item
+The version of GNU Fortran.
+You can get this by running @code{g77} with the @samp{-v} option.
+(Ignore any error messages that might be displayed
+when the linker is run.)
+
+Without this, we won't know whether there is any point in looking for
+the bug in the current version of GNU Fortran.
+
+@item
+@cindex preprocessor
+@cindex cpp program
+@cindex programs, cpp
+@pindex cpp
+A complete input file that will reproduce the bug.
+If the bug is in the compiler proper (@file{f771}) and
+you are using the C preprocessor, run your
+source file through the C preprocessor by doing @samp{g77 -E
+@var{sourcefile} > @var{outfile}}, then include the contents of
+@var{outfile} in the bug report. (When you do this, use the same
+@samp{-I}, @samp{-D} or @samp{-U} options that you used in actual
+compilation.)
+
+A single statement is not enough of an example.
+In order to compile it,
+it must be embedded in a complete file of compiler input; and the bug
+might depend on the details of how this is done.
+
+Without a real example one can compile, all anyone can do about your bug
+report is wish you luck. It would be futile to try to guess how to
+provoke the bug. For example, bugs in register allocation and reloading
+frequently depend on every little detail of the function they happen in.
+
+@item
+@cindex included files
+@cindex INCLUDE directive
+@cindex directive, INCLUDE
+@cindex #include directive
+@cindex directive, #include
+Note that you should include with your bug report any files
+included by the source file
+(via the @code{#include} or @code{INCLUDE} directive)
+that you send, and any files they include, and so on.
+
+It is not necessary to replace
+the @code{#include} and @code{INCLUDE} directives
+with the actual files in the version of the source file that
+you send, but it might make submitting the bug report easier
+in the end.
+However, be sure to @emph{reproduce} the bug using the @emph{exact}
+version of the source material you submit, to avoid wild-goose
+chases.
+
+@item
+The command arguments you gave GNU Fortran to compile that example
+and observe the bug. For example, did you use @samp{-O}? To guarantee
+you won't omit something important, list all the options.
+
+If we were to try to guess the arguments, we would probably guess wrong
+and then we would not encounter the bug.
+
+@item
+The type of machine you are using, and the operating system name and
+version number.
+(Much of this information is printed by @samp{g77 -v}---if you
+include that, send along any additional info you have that you
+don't see clearly represented in that output.)
+
+@item
+The operands you gave to the @code{configure} command when you installed
+the compiler.
+
+@item
+A complete list of any modifications you have made to the compiler
+source. (We don't promise to investigate the bug unless it happens in
+an unmodified compiler. But if you've made modifications and don't tell
+us, then you are sending us on a wild-goose chase.)
+
+Be precise about these changes. A description in English is not
+enough---send a context diff for them.
+
+Adding files of your own (such as a machine description for a machine we
+don't support) is a modification of the compiler source.
+
+@item
+Details of any other deviations from the standard procedure for installing
+GNU Fortran.
+
+@item
+A description of what behavior you observe that you believe is
+incorrect. For example, ``The compiler gets a fatal signal,'' or,
+``The assembler instruction at line 208 in the output is incorrect.''
+
+Of course, if the bug is that the compiler gets a fatal signal, then one
+can't miss it. But if the bug is incorrect output, the maintainer might
+not notice unless it is glaringly wrong. None of us has time to study
+all the assembler code from a 50-line Fortran program just on the chance that
+one instruction might be wrong. We need @emph{you} to do this part!
+
+Even if the problem you experience is a fatal signal, you should still
+say so explicitly. Suppose something strange is going on, such as, your
+copy of the compiler is out of synch, or you have encountered a bug in
+the C library on your system. (This has happened!) Your copy might
+crash and the copy here would not. If you @i{said} to expect a crash,
+then when the compiler here fails to crash, we would know that the bug
+was not happening. If you don't say to expect a crash, then we would
+not know whether the bug was happening. We would not be able to draw
+any conclusion from our observations.
+
+If the problem is a diagnostic when building GNU Fortran with some other
+compiler, say whether it is a warning or an error.
+
+Often the observed symptom is incorrect output when your program is run.
+Sad to say, this is not enough information unless the program is short
+and simple. None of us has time to study a large program to figure out
+how it would work if compiled correctly, much less which line of it was
+compiled wrong. So you will have to do that. Tell us which source line
+it is, and what incorrect result happens when that line is executed. A
+person who understands the program can find this as easily as finding a
+bug in the program itself.
+
+@item
+If you send examples of assembler code output from GNU Fortran,
+please use @samp{-g} when you make them. The debugging information
+includes source line numbers which are essential for correlating the
+output with the input.
+
+@item
+If you wish to mention something in the GNU Fortran source, refer to it by
+context, not by line number.
+
+The line numbers in the development sources don't match those in your
+sources. Your line numbers would convey no convenient information to the
+maintainers.
+
+@item
+Additional information from a debugger might enable someone to find a
+problem on a machine which he does not have available. However, you
+need to think when you collect this information if you want it to have
+any chance of being useful.
+
+@cindex backtrace for bug reports
+For example, many people send just a backtrace, but that is never
+useful by itself. A simple backtrace with arguments conveys little
+about GNU Fortran because the compiler is largely data-driven; the same
+functions are called over and over for different RTL insns, doing
+different things depending on the details of the insn.
+
+Most of the arguments listed in the backtrace are useless because they
+are pointers to RTL list structure. The numeric values of the
+pointers, which the debugger prints in the backtrace, have no
+significance whatever; all that matters is the contents of the objects
+they point to (and most of the contents are other such pointers).
+
+In addition, most compiler passes consist of one or more loops that
+scan the RTL insn sequence. The most vital piece of information about
+such a loop---which insn it has reached---is usually in a local variable,
+not in an argument.
+
+@findex debug_rtx
+What you need to provide in addition to a backtrace are the values of
+the local variables for several stack frames up. When a local
+variable or an argument is an RTX, first print its value and then use
+the GDB command @code{pr} to print the RTL expression that it points
+to. (If GDB doesn't run on your machine, use your debugger to call
+the function @code{debug_rtx} with the RTX as an argument.) In
+general, whenever a variable is a pointer, its value is no use
+without the data it points to.
+@end itemize
+
+Here are some things that are not necessary:
+
+@itemize @bullet
+@item
+A description of the envelope of the bug.
+
+Often people who encounter a bug spend a lot of time investigating
+which changes to the input file will make the bug go away and which
+changes will not affect it.
+
+This is often time consuming and not very useful, because the way we
+will find the bug is by running a single example under the debugger with
+breakpoints, not by pure deduction from a series of examples. You might
+as well save your time for something else.
+
+Of course, if you can find a simpler example to report @emph{instead} of
+the original one, that is a convenience. Errors in the output will be
+easier to spot, running under the debugger will take less time, etc.
+Most GNU Fortran bugs involve just one function, so the most straightforward
+way to simplify an example is to delete all the function definitions
+except the one where the bug occurs. Those earlier in the file may be
+replaced by external declarations if the crucial function depends on
+them. (Exception: inline functions might affect compilation of functions
+defined later in the file.)
+
+However, simplification is not vital; if you don't want to do this,
+report the bug anyway and send the entire test case you used.
+
+@item
+In particular, some people insert conditionals @samp{#ifdef BUG} around
+a statement which, if removed, makes the bug not happen. These are just
+clutter; we won't pay any attention to them anyway. Besides, you should
+send us preprocessor output, and that can't have conditionals.
+
+@item
+A patch for the bug.
+
+A patch for the bug is useful if it is a good one. But don't omit the
+necessary information, such as the test case, on the assumption that a
+patch is all we need. We might see problems with your patch and decide
+to fix the problem another way, or we might not understand it at all.
+
+Sometimes with a program as complicated as GNU Fortran it is very hard to
+construct an example that will make the program follow a certain path
+through the code. If you don't send the example, we won't be able to
+construct one, so we won't be able to verify that the bug is fixed.
+
+And if we can't understand what bug you are trying to fix, or why your
+patch should be an improvement, we won't install it. A test case will
+help us to understand.
+
+@xref{Sending Patches}, for guidelines on how to make it easy for us to
+understand and install your patches.
+
+@item
+A guess about what the bug is or what it depends on.
+
+Such guesses are usually wrong. Even the maintainer can't guess right
+about such things without first using the debugger to find the facts.
+
+@item
+A core dump file.
+
+We have no way of examining a core dump for your type of machine
+unless we have an identical system---and if we do have one,
+we should be able to reproduce the crash ourselves.
+@end itemize
+
+@node Sending Patches
+@section Sending Patches for GNU Fortran
+
+If you would like to write bug fixes or improvements for the GNU Fortran
+compiler, that is very helpful.
+Send suggested fixes to the bug report
+mailing list, @email{@value{email-bugs}}.
+
+Please follow these guidelines so we can study your patches efficiently.
+If you don't follow these guidelines, your information might still be
+useful, but using it will take extra work. Maintaining GNU Fortran is a lot
+of work in the best of circumstances, and we can't keep up unless you do
+your best to help.
+
+@itemize @bullet
+@item
+Send an explanation with your changes of what problem they fix or what
+improvement they bring about. For a bug fix, just include a copy of the
+bug report, and explain why the change fixes the bug.
+
+(Referring to a bug report is not as good as including it, because then
+we will have to look it up, and we have probably already deleted it if
+we've already fixed the bug.)
+
+@item
+Always include a proper bug report for the problem you think you have
+fixed. We need to convince ourselves that the change is right before
+installing it. Even if it is right, we might have trouble judging it if
+we don't have a way to reproduce the problem.
+
+@item
+Include all the comments that are appropriate to help people reading the
+source in the future understand why this change was needed.
+
+@item
+Don't mix together changes made for different reasons.
+Send them @emph{individually}.
+
+If you make two changes for separate reasons, then we might not want to
+install them both. We might want to install just one. If you send them
+all jumbled together in a single set of diffs, we have to do extra work
+to disentangle them---to figure out which parts of the change serve
+which purpose. If we don't have time for this, we might have to ignore
+your changes entirely.
+
+If you send each change as soon as you have written it, with its own
+explanation, then the two changes never get tangled up, and we can
+consider each one properly without any extra work to disentangle them.
+
+Ideally, each change you send should be impossible to subdivide into
+parts that we might want to consider separately, because each of its
+parts gets its motivation from the other parts.
+
+@item
+Send each change as soon as that change is finished. Sometimes people
+think they are helping us by accumulating many changes to send them all
+together. As explained above, this is absolutely the worst thing you
+could do.
+
+Since you should send each change separately, you might as well send it
+right away. That gives us the option of installing it immediately if it
+is important.
+
+@item
+Use @samp{diff -c} to make your diffs. Diffs without context are hard
+for us to install reliably. More than that, they make it hard for us to
+study the diffs to decide whether we want to install them. Unidiff
+format is better than contextless diffs, but not as easy to read as
+@samp{-c} format.
+
+If you have GNU @code{diff}, use @samp{diff -cp}, which shows the name of the
+function that each change occurs in.
+(The maintainer of GNU Fortran currently uses @samp{diff -rcp2N}.)
+
+@item
+Write the change log entries for your changes. We get lots of changes,
+and we don't have time to do all the change log writing ourselves.
+
+Read the @file{ChangeLog} file to see what sorts of information to put
+in, and to learn the style that we use. The purpose of the change log
+is to show people where to find what was changed. So you need to be
+specific about what functions you changed; in large functions, it's
+often helpful to indicate where within the function the change was.
+
+On the other hand, once you have shown people where to find the change,
+you need not explain its purpose. Thus, if you add a new function, all
+you need to say about it is that it is new. If you feel that the
+purpose needs explaining, it probably does---but the explanation will be
+much more useful if you put it in comments in the code.
+
+If you would like your name to appear in the header line for who made
+the change, send us the header line.
+
+@item
+When you write the fix, keep in mind that we can't install a change that
+would break other systems.
+
+People often suggest fixing a problem by changing machine-independent
+files such as @file{toplev.c} to do something special that a particular
+system needs. Sometimes it is totally obvious that such changes would
+break GNU Fortran for almost all users. We can't possibly make a change like
+that. At best it might tell us how to write another patch that would
+solve the problem acceptably.
+
+Sometimes people send fixes that @emph{might} be an improvement in
+general---but it is hard to be sure of this. It's hard to install
+such changes because we have to study them very carefully. Of course,
+a good explanation of the reasoning by which you concluded the change
+was correct can help convince us.
+
+The safest changes are changes to the configuration files for a
+particular machine. These are safe because they can't create new bugs
+on other machines.
+
+Please help us keep up with the workload by designing the patch in a
+form that is good to install.
+@end itemize
+
+@node Service
+@chapter How To Get Help with GNU Fortran
+
+If you need help installing, using or changing GNU Fortran, there are two
+ways to find it:
+
+@itemize @bullet
+@item
+Look in the service directory for someone who might help you for a fee.
+The service directory is found in the file named @file{SERVICE} in the
+GNU CC distribution.
+
+@item
+Send a message to @email{@value{email-general}}.
+@end itemize
+
+@end ifset
+@ifset INTERNALS
+@node Adding Options
+@chapter Adding Options
+@cindex options, adding
+@cindex adding options
+
+To add a new command-line option to @code{g77}, first decide
+what kind of option you wish to add.
+Search the @code{g77} and @code{gcc} documentation for one
+or more options that is most closely like the one you want to add
+(in terms of what kind of effect it has, and so on) to
+help clarify its nature.
+
+@itemize @bullet
+@item
+@emph{Fortran options} are options that apply only
+when compiling Fortran programs.
+They are accepted by @code{g77} and @code{gcc}, but
+they apply only when compiling Fortran programs.
+
+@item
+@emph{Compiler options} are options that apply
+when compiling most any kind of program.
+@end itemize
+
+@emph{Fortran options} are listed in the file
+@file{@value{path-g77}/lang-options.h},
+which is used during the build of @code{gcc} to
+build a list of all options that are accepted by
+at least one language's compiler.
+This list goes into the @samp{lang_options} array
+in @file{gcc/toplev.c}, which uses this array to
+determine whether a particular option should be
+offered to the linked-in front end for processing
+by calling @samp{lang_option_decode}, which, for
+@code{g77}, is in @file{@value{path-g77}/com.c} and just
+calls @samp{ffe_decode_option}.
+
+If the linked-in front end ``rejects'' a
+particular option passed to it, @file{toplev.c}
+just ignores the option, because @emph{some}
+language's compiler is willing to accept it.
+
+This allows commands like @samp{gcc -fno-asm foo.c bar.f}
+to work, even though Fortran compilation does
+not currently support the @samp{-fno-asm} option;
+even though the @code{f771} version of @samp{lang_decode_option}
+rejects @samp{-fno-asm}, @file{toplev.c} doesn't
+produce a diagnostic because some other language (C)
+does accept it.
+
+This also means that commands like
+@samp{g77 -fno-asm foo.f} yield no diagnostics,
+despite the fact that no phase of the command was
+able to recognize and process @samp{-fno-asm}---perhaps
+a warning about this would be helpful if it were
+possible.
+
+Code that processes Fortran options is found in
+@file{@value{path-g77}/top.c}, function @samp{ffe_decode_option}.
+This code needs to check positive and negative forms
+of each option.
+
+The defaults for Fortran options are set in their
+global definitions, also found in @file{@value{path-g77}/top.c}.
+Many of these defaults are actually macros defined
+in @file{@value{path-g77}/target.h}, since they might be
+machine-specific.
+However, since, in practice, GNU compilers
+should behave the same way on all configurations
+(especially when it comes to language constructs),
+the practice of setting defaults in @file{target.h}
+is likely to be deprecated and, ultimately, stopped
+in future versions of @code{g77}.
+
+Accessor macros for Fortran options, used by code
+in the @code{g77} FFE, are defined in @file{@value{path-g77}/top.h}.
+
+@emph{Compiler options} are listed in @file{gcc/toplev.c}
+in the array @samp{f_options}.
+An option not listed in @samp{lang_options} is
+looked up in @samp{f_options} and handled from there.
+
+The defaults for compiler options are set in the
+global definitions for the corresponding variables,
+some of which are in @file{gcc/toplev.c}.
+
+You can set different defaults for @emph{Fortran-oriented}
+or @emph{Fortran-reticent} compiler options by changing
+the way @code{f771} handles the @samp{-fset-g77-defaults}
+option, which is always provided as the first option when
+called by @code{g77} or @code{gcc}.
+
+This code is in @samp{ffe_decode_options} in @file{@value{path-g77}/top.c}.
+Have it change just the variables that you want to default
+to a different setting for Fortran compiles compared to
+compiles of other languages.
+
+The @samp{-fset-g77-defaults} option is passed to @code{f771}
+automatically because of the specification information
+kept in @file{@value{path-g77}/lang-specs.h}.
+This file tells the @code{gcc} command how to recognize,
+in this case, Fortran source files (those to be preprocessed,
+and those that are not), and further, how to invoke the
+appropriate programs (including @code{f771}) to process
+those source files.
+
+It is in @file{@value{path-g77}/lang-specs.h} that @samp{-fset-g77-defaults},
+@samp{-fversion}, and other options are passed, as appropriate,
+even when the user has not explicitly specified them.
+Other ``internal'' options such as @samp{-quiet} also
+are passed via this mechanism.
+
+@node Projects
+@chapter Projects
+@cindex projects
+
+If you want to contribute to @code{g77} by doing research,
+design, specification, documentation, coding, or testing,
+the following information should give you some ideas.
+More relevant information might be available from
+@uref{ftp://alpha.gnu.org/gnu/g77/projects/}.
+
+@menu
+* Efficiency:: Make @code{g77} itself compile code faster.
+* Better Optimization:: Teach @code{g77} to generate faster code.
+* Simplify Porting:: Make @code{g77} easier to configure, build,
+ and install.
+* More Extensions:: Features many users won't know to ask for.
+* Machine Model:: @code{g77} should better leverage @code{gcc}.
+* Internals Documentation:: Make maintenance easier.
+* Internals Improvements:: Make internals more robust.
+* Better Diagnostics:: Make using @code{g77} on new code easier.
+@end menu
+
+@node Efficiency
+@section Improve Efficiency
+@cindex efficiency
+
+Don't bother doing any performance analysis until most of the
+following items are taken care of, because there's no question
+they represent serious space/time problems, although some of
+them show up only given certain kinds of (popular) input.
+
+@itemize @bullet
+@item
+Improve @samp{malloc} package and its uses to specify more info about
+memory pools and, where feasible, use obstacks to implement them.
+
+@item
+Skip over uninitialized portions of aggregate areas (arrays,
+@code{COMMON} areas, @code{EQUIVALENCE} areas) so zeros need not be output.
+This would reduce memory usage for large initialized aggregate
+areas, even ones with only one initialized element.
+
+As of version 0.5.18, a portion of this item has already been
+accomplished.
+
+@item
+Prescan the statement (in @file{sta.c}) so that the nature of the statement
+is determined as much as possible by looking entirely at its form,
+and not looking at any context (previous statements, including types
+of symbols).
+This would allow ripping out of the statement-confirmation,
+symbol retraction/confirmation, and diagnostic inhibition
+mechanisms.
+Plus, it would result in much-improved diagnostics.
+For example, @samp{CALL some-intrinsic(@dots{})}, where the intrinsic
+is not a subroutine intrinsic, would result actual error instead of the
+unimplemented-statement catch-all.
+
+@item
+Throughout @code{g77}, don't pass line/column pairs where
+a simple @samp{ffewhere} type, which points to the error as much as is
+desired by the configuration, will do, and don't pass @samp{ffelexToken} types
+where a simple @samp{ffewhere} type will do.
+Then, allow new default
+configuration of @samp{ffewhere} such that the source line text is not
+preserved, and leave it to things like Emacs' next-error function
+to point to them (now that @samp{next-error} supports column,
+or, perhaps, character-offset, numbers).
+The change in calling sequences should improve performance somewhat,
+as should not having to save source lines.
+(Whether this whole
+item will improve performance is questionable, but it should
+improve maintainability.)
+
+@item
+Handle @samp{DATA (A(I),I=1,1000000)/1000000*2/} more efficiently, especially
+as regards the assembly output.
+Some of this might require improving
+the back end, but lots of improvement in space/time required in @code{g77}
+itself can be fairly easily obtained without touching the back end.
+Maybe type-conversion, where necessary, can be speeded up as well in
+cases like the one shown (converting the @samp{2} into @samp{2.}).
+
+@item
+If analysis shows it to be worthwhile, optimize @file{lex.c}.
+
+@item
+Consider redesigning @file{lex.c} to not need any feedback
+during tokenization, by keeping track of enough parse state on its
+own.
+@end itemize
+
+@node Better Optimization
+@section Better Optimization
+@cindex optimization, better
+@cindex code generation, improving
+
+Much of this work should be put off until after @code{g77} has
+all the features necessary for its widespread acceptance as a
+useful F77 compiler.
+However, perhaps this work can be done in parallel during
+the feature-adding work.
+
+@itemize @bullet
+@item
+Do the equivalent of the trick of putting @samp{extern inline} in front
+of every function definition in @code{libg2c} and #include'ing the resulting
+file in @code{f2c}+@code{gcc}---that is, inline all run-time-library functions
+that are at all worth inlining.
+(Some of this has already been done, such as for integral exponentiation.)
+
+@item
+When doing @samp{CHAR_VAR = CHAR_FUNC(@dots{})},
+and it's clear that types line up
+and @samp{CHAR_VAR} is addressable or not a @samp{VAR_DECL},
+make @samp{CHAR_VAR}, not a
+temporary, be the receiver for @samp{CHAR_FUNC}.
+(This is now done for @code{COMPLEX} variables.)
+
+@item
+Design and implement Fortran-specific optimizations that don't
+really belong in the back end, or where the front end needs to
+give the back end more info than it currently does.
+
+@item
+Design and implement a new run-time library interface, with the
+code going into @code{libgcc} so no special linking is required to
+link Fortran programs using standard language features.
+This library
+would speed up lots of things, from I/O (using precompiled formats,
+doing just one, or, at most, very few, calls for arrays or array sections,
+and so on) to general computing (array/section implementations of
+various intrinsics, implementation of commonly performed loops that
+aren't likely to be optimally compiled otherwise, etc.).
+
+Among the important things the library would do are:
+
+@itemize @bullet
+@item
+Be a one-stop-shop-type
+library, hence shareable and usable by all, in that what are now
+library-build-time options in @code{libg2c} would be moved at least to the
+@code{g77} compile phase, if not to finer grains (such as choosing how
+list-directed I/O formatting is done by default at @code{OPEN} time, for
+preconnected units via options or even statements in the main program
+unit, maybe even on a per-I/O basis with appropriate pragma-like
+devices).
+@end itemize
+
+@item
+Probably requiring the new library design, change interface to
+normally have @code{COMPLEX} functions return their values in the way
+@code{gcc} would if they were declared @code{__complex__ float},
+rather than using
+the mechanism currently used by @code{CHARACTER} functions (whereby the
+functions are compiled as returning void and their first arg is
+a pointer to where to store the result).
+(Don't append underscores to
+external names for @code{COMPLEX} functions in some cases once @code{g77} uses
+@code{gcc} rather than @code{f2c} calling conventions.)
+
+@item
+Do something useful with @samp{doiter} references where possible.
+For example, @samp{CALL FOO(I)} cannot modify @samp{I} if within
+a @code{DO} loop that uses @samp{I} as the
+iteration variable, and the back end might find that info useful
+in determining whether it needs to read @samp{I} back into a register after
+the call.
+(It normally has to do that, unless it knows @samp{FOO} never
+modifies its passed-by-reference argument, which is rarely the case
+for Fortran-77 code.)
+@end itemize
+
+@node Simplify Porting
+@section Simplify Porting
+@cindex porting, simplify
+@cindex simplify porting
+
+Making @code{g77} easier to configure, port, build, and install, either
+as a single-system compiler or as a cross-compiler, would be
+very useful.
+
+@itemize @bullet
+@item
+A new library (replacing @code{libg2c}) should improve portability as well as
+produce more optimal code.
+Further, @code{g77} and the new library should
+conspire to simplify naming of externals, such as by removing unnecessarily
+added underscores, and to reduce/eliminate the possibility of naming
+conflicts, while making debugger more straightforward.
+
+Also, it should
+make multi-language applications more feasible, such as by providing
+Fortran intrinsics that get Fortran unit numbers given C @code{FILE *}
+descriptors.
+
+@item
+Possibly related to a new library, @code{g77} should produce the equivalent
+of a @code{gcc} @samp{main(argc, argv)} function when it compiles a
+main program unit, instead of compiling something that must be
+called by a library
+implementation of @code{main()}.
+
+This would do many useful things such as
+provide more flexibility in terms of setting up exception handling,
+not requiring programmers to start their debugging sessions with
+@kbd{breakpoint MAIN__} followed by @kbd{run}, and so on.
+
+@item
+The GBE needs to understand the difference between alignment
+requirements and desires.
+For example, on Intel x86 machines, @code{g77} currently imposes
+overly strict alignment requirements, due to the back end, but it
+would be useful for Fortran and C programmers to be able to override
+these @emph{recommendations} as long as they don't violate the actual
+processor @emph{requirements}.
+@end itemize
+
+@node More Extensions
+@section More Extensions
+@cindex extensions, more
+
+These extensions are not the sort of things users ask for ``by name'',
+but they might improve the usability of @code{g77}, and Fortran in
+general, in the long run.
+Some of these items really pertain to improving @code{g77} internals
+so that some popular extensions can be more easily supported.
+
+@itemize @bullet
+@item
+Look through all the documentation on the GNU Fortran language,
+dialects, compiler, missing features, bugs, and so on.
+Many mentions of incomplete or missing features are
+sprinkled throughout.
+It is not worth repeating them here.
+
+@item
+@cindex concatenation
+@cindex CHARACTER*(*)
+Support arbitrary operands for concatenation, even in contexts where
+run-time allocation is required.
+
+@item
+Consider adding a @code{NUMERIC} type to designate typeless numeric constants,
+named and unnamed.
+The idea is to provide a forward-looking, effective
+replacement for things like the old-style @code{PARAMETER} statement
+when people
+really need typelessness in a maintainable, portable, clearly documented
+way.
+Maybe @code{TYPELESS} would include @code{CHARACTER}, @code{POINTER},
+and whatever else might come along.
+(This is not really a call for polymorphism per se, just
+an ability to express limited, syntactic polymorphism.)
+
+@item
+Support @samp{OPEN(@dots{},KEY=(@dots{}),@dots{})}.
+
+@item
+Support arbitrary file unit numbers, instead of limiting them
+to 0 through @samp{MXUNIT-1}.
+(This is a @code{libg2c} issue.)
+
+@item
+@samp{OPEN(NOSPANBLOCKS,@dots{})} is treated as
+@samp{OPEN(UNIT=NOSPANBLOCKS,@dots{})}, so a
+later @code{UNIT=} in the first example is invalid.
+Make sure this is what users of this feature would expect.
+
+@item
+Currently @code{g77} disallows @samp{READ(1'10)} since
+it is an obnoxious syntax, but
+supporting it might be pretty easy if needed.
+More details are needed, such
+as whether general expressions separated by an apostrophe are supported,
+or maybe the record number can be a general expression, and so on.
+
+@item
+Support @code{STRUCTURE}, @code{UNION}, @code{MAP}, and @code{RECORD}
+fully.
+Currently there is no support at all
+for @code{%FILL} in @code{STRUCTURE} and related syntax,
+whereas the rest of the
+stuff has at least some parsing support.
+This requires either major
+changes to @code{libg2c} or its replacement.
+
+@item
+F90 and @code{g77} probably disagree about label scoping relative to
+@code{INTERFACE} and @code{END INTERFACE}, and their contained
+procedure interface bodies (blocks?).
+
+@item
+@code{ENTRY} doesn't support F90 @code{RESULT()} yet,
+since that was added after S8.112.
+
+@item
+Empty-statement handling (10 ;;CONTINUE;;) probably isn't consistent
+with the final form of the standard (it was vague at S8.112).
+
+@item
+It seems to be an ``open'' question whether a file, immediately after being
+@code{OPEN}ed,is positioned at the beginning, the end, or wherever---it
+might be nice to offer an option of opening to ``undefined'' status, requiring
+an explicit absolute-positioning operation to be performed before any
+other (besides @code{CLOSE}) to assist in making applications port to systems
+(some IBM?) that @code{OPEN} to the end of a file or some such thing.
+@end itemize
+
+@node Machine Model
+@section Machine Model
+
+This items pertain to generalizing @code{g77}'s view of
+the machine model to more fully accept whatever the GBE
+provides it via its configuration.
+
+@itemize @bullet
+@item
+Switch to using @samp{REAL_VALUE_TYPE} to represent floating-point constants
+exclusively so the target float format need not be required.
+This
+means changing the way @code{g77} handles initialization of aggregate areas
+having more than one type, such as @code{REAL} and @code{INTEGER},
+because currently
+it initializes them as if they were arrays of @code{char} and uses the
+bit patterns of the constants of the various types in them to determine
+what to stuff in elements of the arrays.
+
+@item
+Rely more and more on back-end info and capabilities, especially in the
+area of constants (where having the @code{g77} front-end's IL just store
+the appropriate tree nodes containing constants might be best).
+
+@item
+Suite of C and Fortran programs that a user/administrator can run on a
+machine to help determine the configuration for @code{g77} before building
+and help determine if the compiler works (especially with whatever
+libraries are installed) after building.
+@end itemize
+
+@node Internals Documentation
+@section Internals Documentation
+
+Better info on how @code{g77} works and how to port it is needed.
+Much of this should be done only after the redesign planned for
+0.6 is complete.
+
+@node Internals Improvements
+@section Internals Improvements
+
+Some more items that would make @code{g77} more reliable
+and easier to maintain:
+
+@itemize @bullet
+@item
+Generally make expression handling focus
+more on critical syntax stuff, leaving semantics to callers.
+For example,
+anything a caller can check, semantically, let it do so, rather
+than having @file{expr.c} do it.
+(Exceptions might include things like
+diagnosing @samp{FOO(I--K:)=BAR} where @samp{FOO} is a @code{PARAMETER}---if
+it seems
+important to preserve the left-to-right-in-source order of production
+of diagnostics.)
+
+@item
+Come up with better naming conventions for @samp{-D} to establish requirements
+to achieve desired implementation dialect via @file{proj.h}.
+
+@item
+Clean up used tokens and @samp{ffewhere}s in @samp{ffeglobal_terminate_1}.
+
+@item
+Replace @file{sta.c} @samp{outpooldisp} mechanism with @samp{malloc_pool_use}.
+
+@item
+Check for @samp{opANY} in more places in @file{com.c}, @file{std.c},
+and @file{ste.c}, and get rid of the @samp{opCONVERT(opANY)} kludge
+(after determining if there is indeed no real need for it).
+
+@item
+Utility to read and check @file{bad.def} messages and their references in the
+code, to make sure calls are consistent with message templates.
+
+@item
+Search and fix @samp{&ffe@dots{}} and similar so that
+@samp{ffe@dots{}ptr@dots{}} macros are
+available instead (a good argument for wishing this could have written all
+this stuff in C++, perhaps).
+On the other hand, it's questionable whether this sort of
+improvement is really necessary, given the availability of
+tools such as Emacs and Perl, which make finding any
+address-taking of structure members easy enough?
+
+@item
+Some modules truly export the member names of their structures (and the
+structures themselves), maybe fix this, and fix other modules that just
+appear to as well (by appending @samp{_}, though it'd be ugly and probably
+not worth the time).
+
+@item
+Implement C macros @samp{RETURNS(value)} and @samp{SETS(something,value)}
+in @file{proj.h}
+and use them throughout @code{g77} source code (especially in the definitions
+of access macros in @samp{.h} files) so they can be tailored
+to catch code writing into a @samp{RETURNS()} or reading from a @samp{SETS()}.
+
+@item
+Decorate throughout with @code{const} and other such stuff.
+
+@item
+All F90 notational derivations in the source code are still based
+on the S8.112 version of the draft standard.
+Probably should update
+to the official standard, or put documentation of the rules as used
+in the code@dots{}uh@dots{}in the code.
+
+@item
+Some @samp{ffebld_new} calls (those outside of @file{ffeexpr.c} or
+inside but invoked via paths not involving @samp{ffeexpr_lhs} or
+@samp{ffeexpr_rhs}) might be creating things
+in improper pools, leading to such things staying around too long or
+(doubtful, but possible and dangerous) not long enough.
+
+@item
+Some @samp{ffebld_list_new} (or whatever) calls might not be matched by
+@samp{ffebld_list_bottom} (or whatever) calls, which might someday matter.
+(It definitely is not a problem just yet.)
+
+@item
+Probably not doing clean things when we fail to @code{EQUIVALENCE} something
+due to alignment/mismatch or other problems---they end up without
+@samp{ffestorag} objects, so maybe the backend (and other parts of the front
+end) can notice that and handle like an @samp{opANY} (do what it wants, just
+don't complain or crash).
+Most of this seems to have been addressed
+by now, but a code review wouldn't hurt.
+@end itemize
+
+@node Better Diagnostics
+@section Better Diagnostics
+
+These are things users might not ask about, or that need to
+be looked into, before worrying about.
+Also here are items that involve reducing unnecessary diagnostic
+clutter.
+
+@itemize @bullet
+@item
+When @code{FUNCTION} and @code{ENTRY} point types disagree (@code{CHARACTER}
+lengths, type classes, and so on),
+@samp{ANY}-ize the offending @code{ENTRY} point and any @emph{new} dummies
+it specifies.
+
+@item
+Speed up and improve error handling for data when repeat-count is
+specified.
+For example, don't output 20 unnecessary messages after the
+first necessary one for:
+
+@smallexample
+INTEGER X(20)
+CONTINUE
+DATA (X(I), J= 1, 20) /20*5/
+END
+@end smallexample
+
+@noindent
+(The @code{CONTINUE} statement ensures the @code{DATA} statement
+is processed in the context of executable, not specification,
+statements.)
+@end itemize
+@end ifset
+
+@ifset USING
+@node Diagnostics
+@chapter Diagnostics
+@cindex diagnostics
+
+Some diagnostics produced by @code{g77} require sufficient explanation
+that the explanations are given below, and the diagnostics themselves
+identify the appropriate explanation.
+
+Identification uses the GNU Info format---specifically, the @code{info}
+command that displays the explanation is given within square
+brackets in the diagnostic.
+For example:
+
+@smallexample
+foo.f:5: Invalid statement [info -f g77 M FOOEY]
+@end smallexample
+
+More details about the above diagnostic is found in the @code{g77} Info
+documentation, menu item @samp{M}, submenu item @samp{FOOEY},
+which is displayed by typing the UNIX command
+@samp{info -f g77 M FOOEY}.
+
+Other Info readers, such as EMACS, may be just as easily used to display
+the pertinent node.
+In the above example, @samp{g77} is the Info document name,
+@samp{M} is the top-level menu item to select,
+and, in that node (named @samp{Diagnostics}, the name of
+this chapter, which is the very text you're reading now),
+@samp{FOOEY} is the menu item to select.
+
+@iftex
+In this printed version of the @code{g77} manual, the above example
+points to a section, below, entitled @samp{FOOEY}---though, of course,
+as the above is just a sample, no such section exists.
+@end iftex
+
+@menu
+* CMPAMBIG:: Ambiguous use of intrinsic.
+* EXPIMP:: Intrinsic used explicitly and implicitly.
+* INTGLOB:: Intrinsic also used as name of global.
+* LEX:: Various lexer messages
+* GLOBALS:: Disagreements about globals.
+* LINKFAIL:: When linking @samp{f771} fails.
+@end menu
+
+@node CMPAMBIG
+@section @code{CMPAMBIG}
+
+@noindent
+@smallexample
+Ambiguous use of intrinsic @var{intrinsic} @dots{}
+@end smallexample
+
+The type of the argument to the invocation of the @var{intrinsic}
+intrinsic is a @code{COMPLEX} type other than @code{COMPLEX(KIND=1)}.
+Typically, it is @code{COMPLEX(KIND=2)}, also known as
+@code{DOUBLE COMPLEX}.
+
+The interpretation of this invocation depends on the particular
+dialect of Fortran for which the code was written.
+Some dialects convert the real part of the argument to
+@code{REAL(KIND=1)}, thus losing precision; other dialects,
+and Fortran 90, do no such conversion.
+
+So, GNU Fortran rejects such invocations except under certain
+circumstances, to avoid making an incorrect assumption that results
+in generating the wrong code.
+
+To determine the dialect of the program unit, perhaps even whether
+that particular invocation is properly coded, determine how the
+result of the intrinsic is used.
+
+The result of @var{intrinsic} is expected (by the original programmer)
+to be @code{REAL(KIND=1)} (the non-Fortran-90 interpretation) if:
+
+@itemize @bullet
+@item
+It is passed as an argument to a procedure that explicitly or
+implicitly declares that argument @code{REAL(KIND=1)}.
+
+For example,
+a procedure with no @code{DOUBLE PRECISION} or @code{IMPLICIT DOUBLE PRECISION}
+statement specifying the dummy argument corresponding to an
+actual argument of @samp{REAL(Z)}, where @samp{Z} is declared
+@code{DOUBLE COMPLEX}, strongly suggests that the programmer
+expected @samp{REAL(Z)} to return @code{REAL(KIND=1)} instead
+of @code{REAL(KIND=2)}.
+
+@item
+It is used in a context that would otherwise not include
+any @code{REAL(KIND=2)} but where treating the @var{intrinsic}
+invocation as @code{REAL(KIND=2)} would result in unnecessary
+promotions and (typically) more expensive operations on the
+wider type.
+
+For example:
+
+@smallexample
+DOUBLE COMPLEX Z
+@dots{}
+R(1) = T * REAL(Z)
+@end smallexample
+
+The above example suggests the programmer expected the real part
+of @samp{Z} to be converted to @code{REAL(KIND=1)} before being
+multiplied by @samp{T} (presumed, along with @samp{R} above, to
+be type @code{REAL(KIND=1)}).
+
+Otherwise, the conversion would have to be delayed until after
+the multiplication, requiring not only an extra conversion
+(of @samp{T} to @code{REAL(KIND=2)}), but a (typically) more
+expensive multiplication (a double-precision multiplication instead
+of a single-precision one).
+@end itemize
+
+The result of @var{intrinsic} is expected (by the original programmer)
+to be @code{REAL(KIND=2)} (the Fortran 90 interpretation) if:
+
+@itemize @bullet
+@item
+It is passed as an argument to a procedure that explicitly or
+implicitly declares that argument @code{REAL(KIND=2)}.
+
+For example, a procedure specifying a @code{DOUBLE PRECISION}
+dummy argument corresponding to an
+actual argument of @samp{REAL(Z)}, where @samp{Z} is declared
+@code{DOUBLE COMPLEX}, strongly suggests that the programmer
+expected @samp{REAL(Z)} to return @code{REAL(KIND=2)} instead
+of @code{REAL(KIND=1)}.
+
+@item
+It is used in an expression context that includes
+other @code{REAL(KIND=2)} operands,
+or is assigned to a @code{REAL(KIND=2)} variable or array element.
+
+For example:
+
+@smallexample
+DOUBLE COMPLEX Z
+DOUBLE PRECISION R, T
+@dots{}
+R(1) = T * REAL(Z)
+@end smallexample
+
+The above example suggests the programmer expected the real part
+of @samp{Z} to @emph{not} be converted to @code{REAL(KIND=1)}
+by the @code{REAL()} intrinsic.
+
+Otherwise, the conversion would have to be immediately followed
+by a conversion back to @code{REAL(KIND=2)}, losing
+the original, full precision of the real part of @code{Z},
+before being multiplied by @samp{T}.
+@end itemize
+
+Once you have determined whether a particular invocation of @var{intrinsic}
+expects the Fortran 90 interpretation, you can:
+
+@itemize @bullet
+@item
+Change it to @samp{DBLE(@var{expr})} (if @var{intrinsic} is
+@samp{REAL}) or @samp{DIMAG(@var{expr})} (if @var{intrinsic}
+is @samp{AIMAG})
+if it expected the Fortran 90 interpretation.
+
+This assumes @var{expr} is @code{COMPLEX(KIND=2)}---if it is
+some other type, such as @code{COMPLEX*32}, you should use the
+appropriate intrinsic, such as the one to convert to @code{REAL*16}
+(perhaps @code{DBLEQ()} in place of @code{DBLE()}, and
+@code{QIMAG()} in place of @code{DIMAG()}).
+
+@item
+Change it to @samp{REAL(@var{intrinsic}(@var{expr}))},
+otherwise.
+This converts to @code{REAL(KIND=1)} in all working
+Fortran compilers.
+@end itemize
+
+If you don't want to change the code, and you are certain that all
+ambiguous invocations of @var{intrinsic} in the source file have
+the same expectation regarding interpretation, you can:
+
+@itemize @bullet
+@item
+Compile with the @code{g77} option @samp{-ff90}, to enable the
+Fortran 90 interpretation.
+
+@item
+Compile with the @code{g77} options @samp{-fno-f90 -fugly-complex},
+to enable the non-Fortran-90 interpretations.
+@end itemize
+
+@xref{REAL() and AIMAG() of Complex}, for more information on this
+issue.
+
+Note: If the above suggestions don't produce enough evidence
+as to whether a particular program expects the Fortran 90
+interpretation of this ambiguous invocation of @var{intrinsic},
+there is one more thing you can try.
+
+If you have access to most or all the compilers used on the
+program to create successfully tested and deployed executables,
+read the documentation for, and @emph{also} test out, each compiler
+to determine how it treats the @var{intrinsic} intrinsic in
+this case.
+(If all the compilers don't agree on an interpretation, there
+might be lurking bugs in the deployed versions of the program.)
+
+The following sample program might help:
+
+@cindex JCB003 program
+@smallexample
+ PROGRAM JCB003
+C
+C Written by James Craig Burley 1997-02-23.
+C Contact via Internet email: burley@@gnu.org
+C
+C Determine how compilers handle non-standard REAL
+C and AIMAG on DOUBLE COMPLEX operands.
+C
+ DOUBLE COMPLEX Z
+ REAL R
+ Z = (3.3D0, 4.4D0)
+ R = Z
+ CALL DUMDUM(Z, R)
+ R = REAL(Z) - R
+ IF (R .NE. 0.) PRINT *, 'REAL() is Fortran 90'
+ IF (R .EQ. 0.) PRINT *, 'REAL() is not Fortran 90'
+ R = 4.4D0
+ CALL DUMDUM(Z, R)
+ R = AIMAG(Z) - R
+ IF (R .NE. 0.) PRINT *, 'AIMAG() is Fortran 90'
+ IF (R .EQ. 0.) PRINT *, 'AIMAG() is not Fortran 90'
+ END
+C
+C Just to make sure compiler doesn't use naive flow
+C analysis to optimize away careful work above,
+C which might invalidate results....
+C
+ SUBROUTINE DUMDUM(Z, R)
+ DOUBLE COMPLEX Z
+ REAL R
+ END
+@end smallexample
+
+If the above program prints contradictory results on a
+particular compiler, run away!
+
+@node EXPIMP
+@section @code{EXPIMP}
+
+@noindent
+@smallexample
+Intrinsic @var{intrinsic} referenced @dots{}
+@end smallexample
+
+The @var{intrinsic} is explicitly declared in one program
+unit in the source file and implicitly used as an intrinsic
+in another program unit in the same source file.
+
+This diagnostic is designed to catch cases where a program
+might depend on using the name @var{intrinsic} as an intrinsic
+in one program unit and as a global name (such as the name
+of a subroutine or function) in another, but @code{g77} recognizes
+the name as an intrinsic in both cases.
+
+After verifying that the program unit making implicit use
+of the intrinsic is indeed written expecting the intrinsic,
+add an @samp{INTRINSIC @var{intrinsic}} statement to that
+program unit to prevent this warning.
+
+This and related warnings are disabled by using
+the @samp{-Wno-globals} option when compiling.
+
+Note that this warning is not issued for standard intrinsics.
+Standard intrinsics include those described in the FORTRAN 77
+standard and, if @samp{-ff90} is specified, those described
+in the Fortran 90 standard.
+Such intrinsics are not as likely to be confused with user
+procedures as intrinsics provided as extensions to the
+standard by @code{g77}.
+
+@node INTGLOB
+@section @code{INTGLOB}
+
+@noindent
+@smallexample
+Same name `@var{intrinsic}' given @dots{}
+@end smallexample
+
+The name @var{intrinsic} is used for a global entity (a common
+block or a program unit) in one program unit and implicitly
+used as an intrinsic in another program unit.
+
+This diagnostic is designed to catch cases where a program
+intends to use a name entirely as a global name, but @code{g77}
+recognizes the name as an intrinsic in the program unit that
+references the name, a situation that would likely produce
+incorrect code.
+
+For example:
+
+@smallexample
+INTEGER FUNCTION TIME()
+@dots{}
+END
+@dots{}
+PROGRAM SAMP
+INTEGER TIME
+PRINT *, 'Time is ', TIME()
+END
+@end smallexample
+
+The above example defines a program unit named @samp{TIME}, but
+the reference to @samp{TIME} in the main program unit @samp{SAMP}
+is normally treated by @code{g77} as a reference to the intrinsic
+@code{TIME()} (unless a command-line option that prevents such
+treatment has been specified).
+
+As a result, the program @samp{SAMP} will @emph{not}
+invoke the @samp{TIME} function in the same source file.
+
+Since @code{g77} recognizes @code{libU77} procedures as
+intrinsics, and since some existing code uses the same names
+for its own procedures as used by some @code{libU77}
+procedures, this situation is expected to arise often enough
+to make this sort of warning worth issuing.
+
+After verifying that the program unit making implicit use
+of the intrinsic is indeed written expecting the intrinsic,
+add an @samp{INTRINSIC @var{intrinsic}} statement to that
+program unit to prevent this warning.
+
+Or, if you believe the program unit is designed to invoke the
+program-defined procedure instead of the intrinsic (as
+recognized by @code{g77}), add an @samp{EXTERNAL @var{intrinsic}}
+statement to the program unit that references the name to
+prevent this warning.
+
+This and related warnings are disabled by using
+the @samp{-Wno-globals} option when compiling.
+
+Note that this warning is not issued for standard intrinsics.
+Standard intrinsics include those described in the FORTRAN 77
+standard and, if @samp{-ff90} is specified, those described
+in the Fortran 90 standard.
+Such intrinsics are not as likely to be confused with user
+procedures as intrinsics provided as extensions to the
+standard by @code{g77}.
+
+@node LEX
+@section @code{LEX}
+
+@noindent
+@smallexample
+Unrecognized character @dots{}
+Invalid first character @dots{}
+Line too long @dots{}
+Non-numeric character @dots{}
+Continuation indicator @dots{}
+Label at @dots{} invalid with continuation line indicator @dots{}
+Character constant @dots{}
+Continuation line @dots{}
+Statement at @dots{} begins with invalid token
+@end smallexample
+
+Although the diagnostics identify specific problems, they can
+be produced when general problems such as the following occur:
+
+@itemize @bullet
+@item
+The source file contains something other than Fortran code.
+
+If the code in the file does not look like many of the examples
+elsewhere in this document, it might not be Fortran code.
+(Note that Fortran code often is written in lower case letters,
+while the examples in this document use upper case letters,
+for stylistic reasons.)
+
+For example, if the file contains lots of strange-looking
+characters, it might be APL source code; if it contains lots
+of parentheses, it might be Lisp source code; if it
+contains lots of bugs, it might be C++ source code.
+
+@item
+The source file contains free-form Fortran code, but @samp{-ffree-form}
+was not specified on the command line to compile it.
+
+Free form is a newer form for Fortran code.
+The older, classic form is called fixed form.
+
+Fixed-form code is visually fairly distinctive, because
+numerical labels and comments are all that appear in
+the first five columns of a line, the sixth column is
+reserved to denote continuation lines,
+and actual statements start at or beyond column 7.
+Spaces generally are not significant, so if you
+see statements such as @samp{REALX,Y} and @samp{DO10I=1,100},
+you are looking at fixed-form code.
+Comment lines are indicated by the letter @samp{C} or the symbol
+@samp{*} in column 1.
+(Some code uses @samp{!} or @samp{/*} to begin in-line comments,
+which many compilers support.)
+
+Free-form code is distinguished from fixed-form source
+primarily by the fact that statements may start anywhere.
+(If lots of statements start in columns 1 through 6,
+that's a strong indicator of free-form source.)
+Consecutive keywords must be separated by spaces, so
+@samp{REALX,Y} is not valid, while @samp{REAL X,Y} is.
+There are no comment lines per se, but @samp{!} starts a
+comment anywhere in a line (other than within a character or
+Hollerith constant).
+
+@xref{Source Form}, for more information.
+
+@item
+The source file is in fixed form and has been edited without
+sensitivity to the column requirements.
+
+Statements in fixed-form code must be entirely contained within
+columns 7 through 72 on a given line.
+Starting them ``early'' is more likely to result in diagnostics
+than finishing them ``late'', though both kinds of errors are
+often caught at compile time.
+
+For example, if the following code fragment is edited by following
+the commented instructions literally, the result, shown afterward,
+would produce a diagnostic when compiled:
+
+@smallexample
+C On XYZZY systems, remove "C" on next line:
+C CALL XYZZY_RESET
+@end smallexample
+
+The result of editing the above line might be:
+
+@smallexample
+C On XYZZY systems, remove "C" on next line:
+ CALL XYZZY_RESET
+@end smallexample
+
+However, that leaves the first @samp{C} in the @samp{CALL}
+statement in column 6, making it a comment line, which is
+not really what the author intended, and which is likely
+to result in one of the above-listed diagnostics.
+
+@emph{Replacing} the @samp{C} in column 1 with a space
+is the proper change to make, to ensure the @samp{CALL}
+keyword starts in or after column 7.
+
+Another common mistake like this is to forget that fixed-form
+source lines are significant through only column 72, and that,
+normally, any text beyond column 72 is ignored or is diagnosed
+at compile time.
+
+@xref{Source Form}, for more information.
+
+@item
+The source file requires preprocessing, and the preprocessing
+is not being specified at compile time.
+
+A source file containing lines beginning with @code{#define},
+@code{#include}, @code{#if}, and so on is likely one that
+requires preprocessing.
+
+If the file's suffix is @samp{.f} or @samp{.for}, the file
+will normally be compiled @emph{without} preprocessing by @code{g77}.
+
+Change the file's suffix from @samp{.f} to @samp{.F} (or, on
+systems with case-insensitive file names, to @samp{.fpp}) or
+from @samp{.for} to @samp{.fpp}.
+@code{g77} compiles files with such names @emph{with}
+preprocessing.
+
+@pindex cpp
+@cindex preprocessor
+@cindex cpp program
+@cindex programs, cpp
+@cindex @samp{-x f77-cpp-input} option
+@cindex options, @samp{-x f77-cpp-input}
+Or, learn how to use @code{gcc}'s @samp{-x} option to specify
+the language @samp{f77-cpp-input} for Fortran files that
+require preprocessing.
+@xref{Overall Options,,gcc,Using and Porting GNU CC}.
+
+@item
+The source file is preprocessed, and the results of preprocessing
+result in syntactic errors that are not necessarily obvious to
+someone examining the source file itself.
+
+Examples of errors resulting from preprocessor macro expansion
+include exceeding the line-length limit, improperly starting,
+terminating, or incorporating the apostrophe or double-quote in
+a character constant, improperly forming a Hollerith constant,
+and so on.
+
+@xref{Overall Options,,Options Controlling the Kind of Output},
+for suggestions about how to use, and not use, preprocessing
+for Fortran code.
+@end itemize
+
+@node GLOBALS
+@section @code{GLOBALS}
+
+@noindent
+@smallexample
+Global name @var{name} defined at @dots{} already defined@dots{}
+Global name @var{name} at @dots{} has different type@dots{}
+Too many arguments passed to @var{name} at @dots{}
+Too few arguments passed to @var{name} at @dots{}
+Argument #@var{n} of @var{name} is @dots{}
+@end smallexample
+
+These messages all identify disagreements about the
+global procedure named @var{name} among different program
+units (usually including @var{name} itself).
+
+These disagreements, if not diagnosed, could result in a
+compiler crash if the compiler attempted to inline a reference
+to @var{name} within a calling program unit that disagreed
+with the @var{name} program unit regarding whether the
+procedure is a subroutine or function, the type of the
+return value of the procedure (if it is a function), the
+number of arguments the procedure accepts, or the type
+of each argument.
+
+Such disagreements @emph{should} be fixed in the Fortran
+code itself.
+However, if that is not immediately practical, and the code
+has been working for some time, it is possible it will work
+when compiled by @code{g77} with the @samp{-fno-globals} option.
+
+The @samp{-fno-globals} option disables these diagnostics, and
+also disables all inlining of references to global procedures
+to avoid compiler crashes.
+The diagnostics are actually produced, but as warnings, unless
+the @samp{-Wno-globals} option also is specified.
+
+After using @samp{-fno-globals} to work around these problems,
+it is wise to stop using that option and address them by fixing
+the Fortran code, because such problems, while they might not
+actually result in bugs on some systems, indicate that the code
+is not as portable as it could be.
+In particular, the code might appear to work on a particular
+system, but have bugs that affect the reliability of the data
+without exhibiting any other outward manifestations of the bugs.
+
+@node LINKFAIL
+@section @code{LINKFAIL}
+
+@noindent
+@smallexample
+If the above command failed due to an unresolved reference
+to strtoul, _strtoul, bsearch, _bsearch, or similar, see
+[info -f g77 M LINKFAIL] (a node in the g77 documentation)
+for information on what causes this, how to work around
+the problem by editing $@{srcdir@}/proj.c, and what else to do.
+@end smallexample
+
+@xref{Missing strtoul or bsearch}, for more information on
+this problem,
+which occurs only in releases of @code{g77}
+based on @code{gcc}.
+(It does not occur in @code{egcs}.)
+
+On AIX 4.1, @code{g77} might not build with the native (non-GNU) tools
+due to a linker bug in coping with the @samp{-bbigtoc} option which
+leads to a @samp{Relocation overflow} error. The GNU linker is not
+recommended on current AIX versions, though; it was developed under a
+now-unsupported version. This bug is said to be fixed by `update PTF
+U455193 for APAR IX75823'.
+
+Compiling with @samp{-mminimal-toc}
+might solve this problem, e.g.@: by adding
+@smallexample
+BOOT_CFLAGS='-mminimal-toc -O2 -g'
+@end smallexample
+to the @code{make bootstrap} command line.
+@end ifset
+
+@node Index
+@unnumbered Index
+
+@printindex cp
+@summarycontents
+@contents
+@bye
diff --git a/contrib/gcc/f/g77spec.c b/contrib/gcc/f/g77spec.c
new file mode 100644
index 0000000..79d3637
--- /dev/null
+++ b/contrib/gcc/f/g77spec.c
@@ -0,0 +1,580 @@
+/* Specific flags and argument handling of the Fortran front-end.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file contains a filter for the main `gcc' driver, which is
+ replicated for the `g77' driver by adding this filter. The purpose
+ of this filter is to be basically identical to gcc (in that
+ it faithfully passes all of the original arguments to gcc) but,
+ unless explicitly overridden by the user in certain ways, ensure
+ that the needs of the language supported by this wrapper are met.
+
+ For GNU Fortran (g77), we do the following to the argument list
+ before passing it to `gcc':
+
+ 1. Make sure `-lg2c -lm' is at the end of the list.
+
+ 2. Make sure each time `-lg2c' or `-lm' is seen, it forms
+ part of the series `-lg2c -lm'.
+
+ #1 and #2 are not done if `-nostdlib' or any option that disables
+ the linking phase is present, or if `-xfoo' is in effect. Note that
+ a lack of source files or -l options disables linking.
+
+ This program was originally made out of gcc/cp/g++spec.c, but the
+ way it builds the new argument list was rewritten so it is much
+ easier to maintain, improve the way it decides to add or not add
+ extra arguments, etc. And several improvements were made in the
+ handling of arguments, primarily to make it more consistent with
+ `gcc' itself. */
+
+#include "config.h"
+#include "system.h"
+#include "gansidecl.h"
+#include <f/version.h>
+
+#ifndef MATH_LIBRARY
+#define MATH_LIBRARY "-lm"
+#endif
+
+#ifndef FORTRAN_LIBRARY
+#define FORTRAN_LIBRARY "-lg2c"
+#endif
+
+/* Options this driver needs to recognize, not just know how to
+ skip over. */
+typedef enum
+{
+ OPTION_b, /* Aka --prefix. */
+ OPTION_B, /* Aka --target. */
+ OPTION_c, /* Aka --compile. */
+ OPTION_driver, /* Wrapper-specific option. */
+ OPTION_E, /* Aka --preprocess. */
+ OPTION_help, /* --help. */
+ OPTION_i, /* -imacros, -include, -include-*. */
+ OPTION_l,
+ OPTION_L, /* Aka --library-directory. */
+ OPTION_M, /* Aka --dependencies. */
+ OPTION_MM, /* Aka --user-dependencies. */
+ OPTION_nostdlib, /* Aka --no-standard-libraries, or
+ -nodefaultlibs. */
+ OPTION_o, /* Aka --output. */
+ OPTION_S, /* Aka --assemble. */
+ OPTION_syntax_only, /* -fsyntax-only. */
+ OPTION_v, /* Aka --verbose. */
+ OPTION_version, /* --version. */
+ OPTION_V, /* Aka --use-version. */
+ OPTION_x, /* Aka --language. */
+ OPTION_ /* Unrecognized or unimportant. */
+} Option;
+
+/* The original argument list and related info is copied here. */
+static int g77_xargc;
+static char **g77_xargv;
+static void (*g77_fn)();
+
+/* The new argument list will be built here. */
+static int g77_newargc;
+static char **g77_newargv;
+
+extern char *xmalloc PROTO((size_t));
+
+extern char *version_string;
+
+/* --- This comes from gcc.c (2.8.1) verbatim: */
+
+/* This defines which switch letters take arguments. */
+
+#define DEFAULT_SWITCH_TAKES_ARG(CHAR) \
+ ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
+ || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
+ || (CHAR) == 'I' || (CHAR) == 'm' || (CHAR) == 'x' \
+ || (CHAR) == 'L' || (CHAR) == 'A')
+
+#ifndef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
+#endif
+
+/* This defines which multi-letter switches take arguments. */
+
+#define DEFAULT_WORD_SWITCH_TAKES_ARG(STR) \
+ (!strcmp (STR, "Tdata") || !strcmp (STR, "Ttext") \
+ || !strcmp (STR, "Tbss") || !strcmp (STR, "include") \
+ || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
+ || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
+ || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
+ || !strcmp (STR, "isystem") || !strcmp (STR, "specs"))
+
+#ifndef WORD_SWITCH_TAKES_ARG
+#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
+#endif
+
+/* --- End of verbatim. */
+
+/* Assumes text[0] == '-'. Returns number of argv items that belong to
+ (and follow) this one, an option id for options important to the
+ caller, and a pointer to the first char of the arg, if embedded (else
+ returns NULL, meaning no arg or it's the next argv).
+
+ Note that this also assumes gcc.c's pass converting long options
+ to short ones, where available, has already been run. */
+
+static void
+lookup_option (xopt, xskip, xarg, text)
+ Option *xopt;
+ int *xskip;
+ char **xarg;
+ char *text;
+{
+ Option opt = OPTION_;
+ int skip;
+ char *arg = NULL;
+
+ if ((skip = SWITCH_TAKES_ARG (text[1])))
+ skip -= (text[2] != '\0'); /* See gcc.c. */
+
+ if (text[1] == 'B')
+ opt = OPTION_B, skip = (text[2] == '\0'), arg = text + 2;
+ else if (text[1] == 'b')
+ opt = OPTION_b, skip = (text[2] == '\0'), arg = text + 2;
+ else if ((text[1] == 'c') && (text[2] == '\0'))
+ opt = OPTION_c, skip = 0;
+ else if ((text[1] == 'E') && (text[2] == '\0'))
+ opt = OPTION_E, skip = 0;
+ else if (text[1] == 'i')
+ opt = OPTION_i, skip = 0;
+ else if (text[1] == 'l')
+ opt = OPTION_l;
+ else if (text[1] == 'L')
+ opt = OPTION_L, arg = text + 2;
+ else if (text[1] == 'o')
+ opt = OPTION_o;
+ else if ((text[1] == 'S') && (text[2] == '\0'))
+ opt = OPTION_S, skip = 0;
+ else if (text[1] == 'V')
+ opt = OPTION_V, skip = (text[2] == '\0');
+ else if ((text[1] == 'v') && (text[2] == '\0'))
+ opt = OPTION_v, skip = 0;
+ else if (text[1] == 'x')
+ opt = OPTION_x, arg = text + 2;
+ else
+ {
+ if ((skip = WORD_SWITCH_TAKES_ARG (text + 1)) != 0) /* See gcc.c. */
+ ;
+ else if (! strncmp (text, "-fdriver", 8)) /* Really --driver!! */
+ opt = OPTION_driver; /* Never mind arg, this is unsupported. */
+ else if (! strcmp (text, "-fhelp")) /* Really --help!! */
+ opt = OPTION_help;
+ else if (! strcmp (text, "-M"))
+ opt = OPTION_M;
+ else if (! strcmp (text, "-MM"))
+ opt = OPTION_MM;
+ else if (! strcmp (text, "-nostdlib")
+ || ! strcmp (text, "-nodefaultlibs"))
+ opt = OPTION_nostdlib;
+ else if (! strcmp (text, "-fsyntax-only"))
+ opt = OPTION_syntax_only;
+ else if (! strcmp (text, "-dumpversion"))
+ opt = OPTION_version;
+ else if (! strcmp (text, "-Xlinker")
+ || ! strcmp (text, "-specs"))
+ skip = 1;
+ else
+ skip = 0;
+ }
+
+ if (xopt != NULL)
+ *xopt = opt;
+ if (xskip != NULL)
+ *xskip = skip;
+ if (xarg != NULL)
+ {
+ if ((arg != NULL)
+ && (arg[0] == '\0'))
+ *xarg = NULL;
+ else
+ *xarg = arg;
+ }
+}
+
+/* Append another argument to the list being built. As long as it is
+ identical to the corresponding arg in the original list, just increment
+ the new arg count. Otherwise allocate a new list, etc. */
+
+static void
+append_arg (arg)
+ char *arg;
+{
+ static int newargsize;
+
+#if 0
+ fprintf (stderr, "`%s'\n", arg);
+#endif
+
+ if (g77_newargv == g77_xargv
+ && g77_newargc < g77_xargc
+ && (arg == g77_xargv[g77_newargc]
+ || ! strcmp (arg, g77_xargv[g77_newargc])))
+ {
+ ++g77_newargc;
+ return; /* Nothing new here. */
+ }
+
+ if (g77_newargv == g77_xargv)
+ { /* Make new arglist. */
+ int i;
+
+ newargsize = (g77_xargc << 2) + 20; /* This should handle all. */
+ g77_newargv = (char **) xmalloc (newargsize * sizeof (char *));
+
+ /* Copy what has been done so far. */
+ for (i = 0; i < g77_newargc; ++i)
+ g77_newargv[i] = g77_xargv[i];
+ }
+
+ if (g77_newargc == newargsize)
+ (*g77_fn) ("overflowed output arg list for `%s'", arg);
+
+ g77_newargv[g77_newargc++] = arg;
+}
+
+void
+lang_specific_driver (fn, in_argc, in_argv, in_added_libraries)
+ void (*fn)();
+ int *in_argc;
+ char ***in_argv;
+ int *in_added_libraries;
+{
+ int argc = *in_argc;
+ char **argv = *in_argv;
+ int i;
+ int verbose = 0;
+ Option opt;
+ int skip;
+ char *arg;
+
+ /* This will be NULL if we encounter a situation where we should not
+ link in libf2c. */
+ char *library = FORTRAN_LIBRARY;
+
+ /* This will become 0 if anything other than -v and kin (like -V)
+ is seen, meaning the user is trying to accomplish something.
+ If it remains nonzero, and the user wants version info, add stuff to
+ the command line to make gcc invoke all the appropriate phases
+ to get all the version info. */
+ int add_version_magic = 1;
+
+ /* 0 => -xnone in effect.
+ 1 => -xfoo in effect. */
+ int saw_speclang = 0;
+
+ /* 0 => initial/reset state
+ 1 => last arg was -l<library>
+ 2 => last two args were -l<library> -lm. */
+ int saw_library = 0;
+
+ /* The number of input and output files in the incoming arg list. */
+ int n_infiles = 0;
+ int n_outfiles = 0;
+
+#if 0
+ fprintf (stderr, "Incoming:");
+ for (i = 0; i < argc; i++)
+ fprintf (stderr, " %s", argv[i]);
+ fprintf (stderr, "\n");
+#endif
+
+ g77_xargc = argc;
+ g77_xargv = argv;
+ g77_newargc = 0;
+ g77_newargv = argv;
+ g77_fn = fn;
+
+ /* First pass through arglist.
+
+ If -nostdlib or a "turn-off-linking" option is anywhere in the
+ command line, don't do any library-option processing (except
+ relating to -x). Also, if -v is specified, but no other options
+ that do anything special (allowing -V version, etc.), remember
+ to add special stuff to make gcc command actually invoke all
+ the different phases of the compilation process so all the version
+ numbers can be seen.
+
+ Also, here is where all problems with missing arguments to options
+ are caught. If this loop is exited normally, it means all options
+ have the appropriate number of arguments as far as the rest of this
+ program is concerned. */
+
+ for (i = 1; i < argc; ++i)
+ {
+ if ((argv[i][0] == '+') && (argv[i][1] == 'e'))
+ {
+ add_version_magic = 0;
+ continue;
+ }
+
+ if ((argv[i][0] != '-') || (argv[i][1] == '\0'))
+ {
+ ++n_infiles;
+ add_version_magic = 0;
+ continue;
+ }
+
+ lookup_option (&opt, &skip, NULL, argv[i]);
+
+ switch (opt)
+ {
+ case OPTION_nostdlib:
+ case OPTION_c:
+ case OPTION_S:
+ case OPTION_syntax_only:
+ case OPTION_E:
+ case OPTION_M:
+ case OPTION_MM:
+ /* These options disable linking entirely or linking of the
+ standard libraries. */
+ library = 0;
+ add_version_magic = 0;
+ break;
+
+ case OPTION_l:
+ ++n_infiles;
+ add_version_magic = 0;
+ break;
+
+ case OPTION_o:
+ ++n_outfiles;
+ add_version_magic = 0;
+ break;
+
+ case OPTION_v:
+ if (! verbose)
+ fprintf (stderr, "g77 version %s (from FSF-g77 version %s)\n",
+ version_string, ffe_version_string);
+ verbose = 1;
+ break;
+
+ case OPTION_b:
+ case OPTION_B:
+ case OPTION_L:
+ case OPTION_i:
+ case OPTION_V:
+ /* These options are useful in conjunction with -v to get
+ appropriate version info. */
+ break;
+
+ case OPTION_version:
+ printf ("\
+GNU Fortran %s\n\
+Copyright (C) 1997 Free Software Foundation, Inc.\n\
+For more version information on components of the GNU Fortran\n\
+compilation system, especially useful when reporting bugs,\n\
+type the command `g77 --verbose'.\n\
+\n\
+GNU Fortran comes with NO WARRANTY, to the extent permitted by law.\n\
+You may redistribute copies of GNU Fortran\n\
+under the terms of the GNU General Public License.\n\
+For more information about these matters, see the file named COPYING\n\
+or type the command `info -f g77 Copying'.\n\
+", ffe_version_string);
+ exit (0);
+ break;
+
+ case OPTION_help:
+ /* Let gcc.c handle this, as the egcs version has a really
+ cool facility for handling --help and --verbose --help. */
+ return;
+
+#if 0
+ printf ("\
+Usage: g77 [OPTION]... FORTRAN-SOURCE...\n\
+\n\
+Compile and link Fortran source code to produce an executable program,\n\
+which by default is named `a.out', and can be invoked with the UNIX\n\
+command `./a.out'.\n\
+\n\
+Options:\n\
+--debug include debugging information in executable.\n\
+--help display this help and exit.\n\
+--optimize[=LEVEL] take extra time and memory to make generated\n\
+ executable run faster. LEVEL is 0 for no\n\
+ optimization, 1 for normal optimization, and\n\
+ increases through 3 for more optimization.\n\
+--output=PROGRAM name the executable PROGRAM instead of a.out;\n\
+ invoke with the command `./PROGRAM'.\n\
+--version display version information and exit.\n\
+\n\
+Many other options exist to tailor the compilation process, specify\n\
+the dialect of the Fortran source code, specify details of the\n\
+code-generation methodology, and so on.\n\
+\n\
+For more information on g77 and gcc, type the commands `info -f g77'\n\
+and `info -f gcc' to read the Info documentation.\n\
+\n\
+Report bugs to <egcs-bugs@cygnus.org>.\n");
+ exit (0);
+ break;
+#endif
+
+ case OPTION_driver:
+ (*fn) ("--driver no longer supported", argv[i]);
+ break;
+
+ default:
+ add_version_magic = 0;
+ break;
+ }
+
+ /* This is the one place we check for missing arguments in the
+ program. */
+
+ if (i + skip < argc)
+ i += skip;
+ else
+ (*fn) ("argument to `%s' missing", argv[i]);
+ }
+
+ if ((n_outfiles != 0) && (n_infiles == 0))
+ (*fn) ("No input files; unwilling to write output files");
+
+ /* Second pass through arglist, transforming arguments as appropriate. */
+
+ append_arg (argv[0]); /* Start with command name, of course. */
+
+ for (i = 1; i < argc; ++i)
+ {
+ if (argv[i][0] == '\0')
+ {
+ append_arg (argv[i]); /* Interesting. Just append as is. */
+ continue;
+ }
+
+ if ((argv[i][0] == '-') && (argv[i][1] != 'l'))
+ {
+ /* Not a filename or library. */
+
+ if (saw_library == 1) /* -l<library>. */
+ append_arg (MATH_LIBRARY);
+
+ saw_library = 0;
+
+ lookup_option (&opt, &skip, &arg, argv[i]);
+
+ if (argv[i][1] == '\0')
+ {
+ append_arg (argv[i]); /* "-" == Standard input. */
+ continue;
+ }
+
+ if (opt == OPTION_x)
+ {
+ /* Track input language. */
+ char *lang;
+
+ if (arg == NULL)
+ lang = argv[i+1];
+ else
+ lang = arg;
+
+ saw_speclang = (strcmp (lang, "none") != 0);
+ }
+
+ append_arg (argv[i]);
+
+ for (; skip != 0; --skip)
+ append_arg (argv[++i]);
+
+ continue;
+ }
+
+ /* A filename/library, not an option. */
+
+ if (saw_speclang)
+ saw_library = 0; /* -xfoo currently active. */
+ else
+ { /* -lfoo or filename. */
+ if (strcmp (argv[i], MATH_LIBRARY) == 0
+#ifdef ALT_LIBM
+ || strcmp (argv[i], ALT_LIBM) == 0
+#endif
+ )
+ {
+ if (saw_library == 1)
+ saw_library = 2; /* -l<library> -lm. */
+ else
+ append_arg (FORTRAN_LIBRARY);
+ }
+ else if (strcmp (argv[i], FORTRAN_LIBRARY) == 0)
+ saw_library = 1; /* -l<library>. */
+ else
+ { /* Other library, or filename. */
+ if (saw_library == 1)
+ append_arg (MATH_LIBRARY);
+ saw_library = 0;
+ }
+ }
+ append_arg (argv[i]);
+ }
+
+ /* Append `-lg2c -lm' as necessary. */
+
+ if (! add_version_magic && library)
+ { /* Doing a link and no -nostdlib. */
+ if (saw_speclang)
+ append_arg ("-xnone");
+
+ switch (saw_library)
+ {
+ case 0:
+ append_arg (library);
+ case 1:
+ append_arg (MATH_LIBRARY);
+ default:
+ break;
+ }
+ }
+ else if (add_version_magic && verbose)
+ {
+ append_arg ("-c");
+ append_arg ("-xf77-version");
+ append_arg ("/dev/null");
+ append_arg ("-xnone");
+ }
+
+ if (verbose
+ && g77_newargv != g77_xargv)
+ {
+ fprintf (stderr, "Driving:");
+ for (i = 0; i < g77_newargc; i++)
+ fprintf (stderr, " %s", g77_newargv[i]);
+ fprintf (stderr, "\n");
+ }
+
+ *in_argc = g77_newargc;
+ *in_argv = g77_newargv;
+}
+
+/* Called before linking. Returns 0 on success and -1 on failure. */
+int lang_specific_pre_link () /* Not used for F77. */
+{
+ return 0;
+}
+
+/* Number of extra output files that lang_specific_pre_link may generate. */
+int lang_specific_extra_outfiles = 0; /* Not used for F77. */
diff --git a/contrib/gcc/f/glimits.j b/contrib/gcc/f/glimits.j
new file mode 100644
index 0000000..5d5406c
--- /dev/null
+++ b/contrib/gcc/f/glimits.j
@@ -0,0 +1,28 @@
+/* glimits.j -- Wrapper for GCC's glimits.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#if !USE_HOST_LIMITS
+#include "glimits.h"
+#else
+#include <limits.h>
+#endif
+#endif
diff --git a/contrib/gcc/f/global.c b/contrib/gcc/f/global.c
new file mode 100644
index 0000000..8be7d0c4
--- /dev/null
+++ b/contrib/gcc/f/global.c
@@ -0,0 +1,1536 @@
+/* global.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995, 1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+
+ Description:
+ Manages information kept across individual program units within a single
+ source file. This includes reporting errors when a name is defined
+ multiple times (for example, two program units named FOO) and when a
+ COMMON block is given initial data in more than one program unit.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "global.h"
+#include "info.h"
+#include "lex.h"
+#include "malloc.h"
+#include "name.h"
+#include "symbol.h"
+#include "top.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+#if FFEGLOBAL_ENABLED
+static ffenameSpace ffeglobal_filewide_ = NULL;
+static char *ffeglobal_type_string_[] =
+{
+ [FFEGLOBAL_typeNONE] "??",
+ [FFEGLOBAL_typeMAIN] "main program",
+ [FFEGLOBAL_typeEXT] "external",
+ [FFEGLOBAL_typeSUBR] "subroutine",
+ [FFEGLOBAL_typeFUNC] "function",
+ [FFEGLOBAL_typeBDATA] "block data",
+ [FFEGLOBAL_typeCOMMON] "common block",
+ [FFEGLOBAL_typeANY] "?any?"
+};
+#endif
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+
+/* Call given fn with all globals
+
+ ffeglobal (*fn)(ffeglobal g);
+ ffeglobal_drive(fn); */
+
+#if FFEGLOBAL_ENABLED
+void
+ffeglobal_drive (ffeglobal (*fn) ())
+{
+ if (ffeglobal_filewide_ != NULL)
+ ffename_space_drive_global (ffeglobal_filewide_, fn);
+}
+
+#endif
+/* ffeglobal_new_ -- Make new global
+
+ ffename n;
+ ffeglobal g;
+ g = ffeglobal_new_(n); */
+
+#if FFEGLOBAL_ENABLED
+static ffeglobal
+ffeglobal_new_ (ffename n)
+{
+ ffeglobal g;
+
+ assert (n != NULL);
+
+ g = (ffeglobal) malloc_new_ks (malloc_pool_image (), "FFEGLOBAL",
+ sizeof (*g));
+ g->n = n;
+#ifdef FFECOM_globalHOOK
+ g->hook = FFECOM_globalNULL;
+#endif
+ g->tick = 0;
+
+ ffename_set_global (n, g);
+
+ return g;
+}
+
+#endif
+/* ffeglobal_init_1 -- Initialize per file
+
+ ffeglobal_init_1(); */
+
+void
+ffeglobal_init_1 ()
+{
+#if FFEGLOBAL_ENABLED
+ if (ffeglobal_filewide_ != NULL)
+ ffename_space_kill (ffeglobal_filewide_);
+ ffeglobal_filewide_ = ffename_space_new (malloc_pool_image ());
+#endif
+}
+
+/* ffeglobal_init_common -- Initial value specified for common block
+
+ ffesymbol s; // the ffesymbol for the common block
+ ffelexToken t; // the token with the point of initialization
+ ffeglobal_init_common(s,t);
+
+ For back ends where file-wide global symbols are not maintained, does
+ nothing. Otherwise, makes sure this common block hasn't already been
+ initialized in a previous program unit, and flag that it's been
+ initialized in this one. */
+
+void
+ffeglobal_init_common (ffesymbol s, ffelexToken t)
+{
+#if FFEGLOBAL_ENABLED
+ ffeglobal g;
+
+ g = ffesymbol_global (s);
+
+ if ((g == NULL) || (g->type != FFEGLOBAL_typeCOMMON))
+ return;
+ if (g->type == FFEGLOBAL_typeANY)
+ return;
+
+ if (g->tick == ffe_count_2)
+ return;
+
+ if (g->tick != 0)
+ {
+ if (g->u.common.initt != NULL)
+ {
+ ffebad_start (FFEBAD_COMMON_ALREADY_INIT);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->u.common.initt),
+ ffelex_token_where_column (g->u.common.initt));
+ ffebad_finish ();
+ }
+
+ /* Complain about just one attempt to reinit per program unit, but
+ continue referring back to the first such successful attempt. */
+ }
+ else
+ {
+ if (g->u.common.blank)
+ {
+ ffebad_start (FFEBAD_COMMON_BLANK_INIT);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ g->u.common.initt = ffelex_token_use (t);
+ }
+
+ g->tick = ffe_count_2;
+#endif
+}
+
+/* ffeglobal_new_common -- New common block
+
+ ffesymbol s; // the ffesymbol for the new common block
+ ffelexToken t; // the token with the name of the common block
+ bool blank; // TRUE if blank common
+ ffeglobal_new_common(s,t,blank);
+
+ For back ends where file-wide global symbols are not maintained, does
+ nothing. Otherwise, makes sure this symbol hasn't been seen before or
+ is known as a common block. */
+
+void
+ffeglobal_new_common (ffesymbol s, ffelexToken t, bool blank)
+{
+#if FFEGLOBAL_ENABLED
+ ffename n;
+ ffeglobal g;
+
+ if (ffesymbol_global (s) == NULL)
+ {
+ n = ffename_find (ffeglobal_filewide_, t);
+ g = ffename_global (n);
+ }
+ else
+ {
+ g = ffesymbol_global (s);
+ n = NULL;
+ }
+
+ if ((g != NULL) && (g->type == FFEGLOBAL_typeANY))
+ return;
+
+ if ((g != NULL) && (g->type != FFEGLOBAL_typeNONE))
+ {
+ if (g->type == FFEGLOBAL_typeCOMMON)
+ {
+ assert (g->u.common.blank == blank);
+ }
+ else
+ {
+ if (ffe_is_globals () || ffe_is_warn_globals ())
+ {
+ ffebad_start (ffe_is_globals ()
+ ? FFEBAD_FILEWIDE_ALREADY_SEEN
+ : FFEBAD_FILEWIDE_ALREADY_SEEN_W);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+ g->type = FFEGLOBAL_typeANY;
+ }
+ }
+ else
+ {
+ if (g == NULL)
+ {
+ g = ffeglobal_new_ (n);
+ g->intrinsic = FALSE;
+ }
+ else if (g->intrinsic
+ && !g->explicit_intrinsic
+ && ffe_is_warn_globals ())
+ {
+ ffebad_start (FFEBAD_INTRINSIC_GLOBAL);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_string ("common block");
+ ffebad_string ("intrinsic");
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+ g->t = ffelex_token_use (t);
+ g->type = FFEGLOBAL_typeCOMMON;
+ g->u.common.have_pad = FALSE;
+ g->u.common.have_save = FALSE;
+ g->u.common.have_size = FALSE;
+ g->u.common.blank = blank;
+ }
+
+ ffesymbol_set_global (s, g);
+#endif
+}
+
+/* ffeglobal_new_progunit_ -- New program unit
+
+ ffesymbol s; // the ffesymbol for the new unit
+ ffelexToken t; // the token with the name of the unit
+ ffeglobalType type; // the type of the new unit
+ ffeglobal_new_progunit_(s,t,type);
+
+ For back ends where file-wide global symbols are not maintained, does
+ nothing. Otherwise, makes sure this symbol hasn't been seen before. */
+
+void
+ffeglobal_new_progunit_ (ffesymbol s, ffelexToken t, ffeglobalType type)
+{
+#if FFEGLOBAL_ENABLED
+ ffename n;
+ ffeglobal g;
+
+ n = ffename_find (ffeglobal_filewide_, t);
+ g = ffename_global (n);
+ if ((g != NULL) && (g->type == FFEGLOBAL_typeANY))
+ return;
+
+ if ((g != NULL)
+ && ((g->type == FFEGLOBAL_typeMAIN)
+ || (g->type == FFEGLOBAL_typeSUBR)
+ || (g->type == FFEGLOBAL_typeFUNC)
+ || (g->type == FFEGLOBAL_typeBDATA))
+ && g->u.proc.defined)
+ {
+ if (ffe_is_globals () || ffe_is_warn_globals ())
+ {
+ ffebad_start (ffe_is_globals ()
+ ? FFEBAD_FILEWIDE_ALREADY_SEEN
+ : FFEBAD_FILEWIDE_ALREADY_SEEN_W);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+ g->type = FFEGLOBAL_typeANY;
+ }
+ else if ((g != NULL)
+ && (g->type != FFEGLOBAL_typeNONE)
+ && (g->type != FFEGLOBAL_typeEXT)
+ && (g->type != type))
+ {
+ if (ffe_is_globals () || ffe_is_warn_globals ())
+ {
+ ffebad_start (ffe_is_globals ()
+ ? FFEBAD_FILEWIDE_DISAGREEMENT
+ : FFEBAD_FILEWIDE_DISAGREEMENT_W);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_string (ffeglobal_type_string_[type]);
+ ffebad_string (ffeglobal_type_string_[g->type]);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+ g->type = FFEGLOBAL_typeANY;
+ }
+ else
+ {
+ if (g == NULL)
+ {
+ g = ffeglobal_new_ (n);
+ g->intrinsic = FALSE;
+ g->u.proc.n_args = -1;
+ g->u.proc.other_t = NULL;
+ }
+ else if ((ffesymbol_basictype (s) != FFEINFO_basictypeNONE)
+ && ((ffesymbol_basictype (s) != g->u.proc.bt)
+ || (ffesymbol_kindtype (s) != g->u.proc.kt)
+ || ((ffesymbol_size (s) != FFETARGET_charactersizeNONE)
+ && (ffesymbol_size (s) != g->u.proc.sz))))
+ {
+ if (ffe_is_globals () || ffe_is_warn_globals ())
+ {
+ ffebad_start (ffe_is_globals ()
+ ? FFEBAD_FILEWIDE_TYPE_MISMATCH
+ : FFEBAD_FILEWIDE_TYPE_MISMATCH_W);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+ g->type = FFEGLOBAL_typeANY;
+ return;
+ }
+ if (g->intrinsic
+ && !g->explicit_intrinsic
+ && ffe_is_warn_globals ())
+ {
+ ffebad_start (FFEBAD_INTRINSIC_GLOBAL);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_string ("global");
+ ffebad_string ("intrinsic");
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+ g->t = ffelex_token_use (t);
+ if ((g->tick == 0)
+ || (g->u.proc.bt == FFEINFO_basictypeNONE)
+ || (g->u.proc.kt == FFEINFO_kindtypeNONE))
+ {
+ g->u.proc.bt = ffesymbol_basictype (s);
+ g->u.proc.kt = ffesymbol_kindtype (s);
+ g->u.proc.sz = ffesymbol_size (s);
+ }
+ g->tick = ffe_count_2;
+ if ((g->tick != 0)
+ && (g->type != type))
+ g->u.proc.n_args = -1;
+ g->type = type;
+ g->u.proc.defined = TRUE;
+ }
+
+ ffesymbol_set_global (s, g);
+#endif
+}
+
+/* ffeglobal_pad_common -- Check initial padding of common area
+
+ ffesymbol s; // the common area
+ ffetargetAlign pad; // the initial padding
+ ffeglobal_pad_common(s,pad,ffesymbol_where_line(s),
+ ffesymbol_where_column(s));
+
+ In global-enabled mode, make sure the padding agrees with any existing
+ padding established for the common area, otherwise complain.
+ In global-disabled mode, warn about nonzero padding. */
+
+void
+ffeglobal_pad_common (ffesymbol s, ffetargetAlign pad, ffewhereLine wl,
+ ffewhereColumn wc)
+{
+#if FFEGLOBAL_ENABLED
+ ffeglobal g;
+
+ g = ffesymbol_global (s);
+ if ((g == NULL) || (g->type != FFEGLOBAL_typeCOMMON))
+ return; /* Let someone else catch this! */
+ if (g->type == FFEGLOBAL_typeANY)
+ return;
+
+ if (!g->u.common.have_pad)
+ {
+ g->u.common.have_pad = TRUE;
+ g->u.common.pad = pad;
+ g->u.common.pad_where_line = ffewhere_line_use (wl);
+ g->u.common.pad_where_col = ffewhere_column_use (wc);
+
+ if (pad != 0)
+ {
+ char padding[20];
+
+ sprintf (&padding[0], "%" ffetargetAlign_f "u", pad);
+ ffebad_start (FFEBAD_COMMON_INIT_PAD);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_string (padding);
+ ffebad_string ((pad == 1)
+ ? FFECOM_SIZE_UNIT : FFECOM_SIZE_UNITS);
+ ffebad_here (0, wl, wc);
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if (g->u.common.pad != pad)
+ {
+ char padding_1[20];
+ char padding_2[20];
+
+ sprintf (&padding_1[0], "%" ffetargetAlign_f "u", pad);
+ sprintf (&padding_2[0], "%" ffetargetAlign_f "u", g->u.common.pad);
+ ffebad_start (FFEBAD_COMMON_DIFF_PAD);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_string (padding_1);
+ ffebad_here (0, wl, wc);
+ ffebad_string (padding_2);
+ ffebad_string ((pad == 1)
+ ? FFECOM_SIZE_UNIT : FFECOM_SIZE_UNITS);
+ ffebad_string ((g->u.common.pad == 1)
+ ? FFECOM_SIZE_UNIT : FFECOM_SIZE_UNITS);
+ ffebad_here (1, g->u.common.pad_where_line, g->u.common.pad_where_col);
+ ffebad_finish ();
+ }
+
+ if (g->u.common.pad < pad)
+ {
+ g->u.common.pad = pad;
+ g->u.common.pad_where_line = ffewhere_line_use (wl);
+ g->u.common.pad_where_col = ffewhere_column_use (wc);
+ }
+ }
+#endif
+}
+
+/* Collect info for a global's argument. */
+
+void
+ffeglobal_proc_def_arg (ffesymbol s, int argno, char *name, ffeglobalArgSummary as,
+ ffeinfoBasictype bt, ffeinfoKindtype kt,
+ bool array)
+{
+ ffeglobal g = ffesymbol_global (s);
+ ffeglobalArgInfo_ ai;
+
+ assert (g != NULL);
+
+ if (g->type == FFEGLOBAL_typeANY)
+ return;
+
+ assert (g->u.proc.n_args >= 0);
+
+ if (argno >= g->u.proc.n_args)
+ return; /* Already complained about this discrepancy. */
+
+ ai = &g->u.proc.arg_info[argno];
+
+ /* Maybe warn about previous references. */
+
+ if ((ai->t != NULL)
+ && ffe_is_warn_globals ())
+ {
+ char *refwhy = NULL;
+ char *defwhy = NULL;
+ bool warn = FALSE;
+
+ switch (as)
+ {
+ case FFEGLOBAL_argsummaryREF:
+ if ((ai->as != FFEGLOBAL_argsummaryREF)
+ && (ai->as != FFEGLOBAL_argsummaryNONE)
+ && ((ai->as != FFEGLOBAL_argsummaryDESCR) /* Choose better message. */
+ || (ai->bt != FFEINFO_basictypeCHARACTER)
+ || (ai->bt == bt)))
+ {
+ warn = TRUE;
+ refwhy = "passed by reference";
+ }
+ break;
+
+ case FFEGLOBAL_argsummaryDESCR:
+ if ((ai->as != FFEGLOBAL_argsummaryDESCR)
+ && (ai->as != FFEGLOBAL_argsummaryNONE)
+ && ((ai->as != FFEGLOBAL_argsummaryREF) /* Choose better message. */
+ || (bt != FFEINFO_basictypeCHARACTER)
+ || (ai->bt == bt)))
+ {
+ warn = TRUE;
+ refwhy = "passed by descriptor";
+ }
+ break;
+
+ case FFEGLOBAL_argsummaryPROC:
+ if ((ai->as != FFEGLOBAL_argsummaryPROC)
+ && (ai->as != FFEGLOBAL_argsummarySUBR)
+ && (ai->as != FFEGLOBAL_argsummaryFUNC)
+ && (ai->as != FFEGLOBAL_argsummaryNONE))
+ {
+ warn = TRUE;
+ refwhy = "a procedure";
+ }
+ break;
+
+ case FFEGLOBAL_argsummarySUBR:
+ if ((ai->as != FFEGLOBAL_argsummaryPROC)
+ && (ai->as != FFEGLOBAL_argsummarySUBR)
+ && (ai->as != FFEGLOBAL_argsummaryNONE))
+ {
+ warn = TRUE;
+ refwhy = "a subroutine";
+ }
+ break;
+
+ case FFEGLOBAL_argsummaryFUNC:
+ if ((ai->as != FFEGLOBAL_argsummaryPROC)
+ && (ai->as != FFEGLOBAL_argsummaryFUNC)
+ && (ai->as != FFEGLOBAL_argsummaryNONE))
+ {
+ warn = TRUE;
+ refwhy = "a function";
+ }
+ break;
+
+ case FFEGLOBAL_argsummaryALTRTN:
+ if ((ai->as != FFEGLOBAL_argsummaryALTRTN)
+ && (ai->as != FFEGLOBAL_argsummaryNONE))
+ {
+ warn = TRUE;
+ refwhy = "an alternate-return label";
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ((refwhy != NULL) && (defwhy == NULL))
+ {
+ /* Fill in the def info. */
+
+ switch (ai->as)
+ {
+ case FFEGLOBAL_argsummaryNONE:
+ defwhy = "omitted";
+ break;
+
+ case FFEGLOBAL_argsummaryVAL:
+ defwhy = "passed by value";
+ break;
+
+ case FFEGLOBAL_argsummaryREF:
+ defwhy = "passed by reference";
+ break;
+
+ case FFEGLOBAL_argsummaryDESCR:
+ defwhy = "passed by descriptor";
+ break;
+
+ case FFEGLOBAL_argsummaryPROC:
+ defwhy = "a procedure";
+ break;
+
+ case FFEGLOBAL_argsummarySUBR:
+ defwhy = "a subroutine";
+ break;
+
+ case FFEGLOBAL_argsummaryFUNC:
+ defwhy = "a function";
+ break;
+
+ case FFEGLOBAL_argsummaryALTRTN:
+ defwhy = "an alternate-return label";
+ break;
+
+#if 0
+ case FFEGLOBAL_argsummaryPTR:
+ defwhy = "a pointer";
+ break;
+#endif
+
+ default:
+ defwhy = "???";
+ break;
+ }
+ }
+
+ if (!warn
+ && (bt != FFEINFO_basictypeHOLLERITH)
+ && (bt != FFEINFO_basictypeTYPELESS)
+ && (bt != FFEINFO_basictypeNONE)
+ && (ai->bt != FFEINFO_basictypeHOLLERITH)
+ && (ai->bt != FFEINFO_basictypeTYPELESS)
+ && (ai->bt != FFEINFO_basictypeNONE))
+ {
+ /* Check types. */
+
+ if ((bt != ai->bt)
+ && ((bt != FFEINFO_basictypeREAL)
+ || (ai->bt != FFEINFO_basictypeCOMPLEX))
+ && ((bt != FFEINFO_basictypeCOMPLEX)
+ || (ai->bt != FFEINFO_basictypeREAL)))
+ {
+ warn = TRUE; /* We can cope with these differences. */
+ refwhy = "one type";
+ defwhy = "some other type";
+ }
+
+ if (!warn && (kt != ai->kt))
+ {
+ warn = TRUE;
+ refwhy = "one precision";
+ defwhy = "some other precision";
+ }
+ }
+
+ if (warn)
+ {
+ char num[60];
+
+ if (name == NULL)
+ sprintf (&num[0], "%d", argno + 1);
+ else
+ {
+ if (strlen (name) < 30)
+ sprintf (&num[0], "%d (named `%s')", argno + 1, name);
+ else
+ sprintf (&num[0], "%d (named `%.*s...')", argno + 1, 30, name);
+ }
+ ffebad_start (FFEBAD_FILEWIDE_ARG_W);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_string (num);
+ ffebad_string (refwhy);
+ ffebad_string (defwhy);
+ ffebad_here (0, ffelex_token_where_line (g->t), ffelex_token_where_column (g->t));
+ ffebad_here (1, ffelex_token_where_line (ai->t), ffelex_token_where_column (ai->t));
+ ffebad_finish ();
+ }
+ }
+
+ /* Define this argument. */
+
+ if (ai->t != NULL)
+ ffelex_token_kill (ai->t);
+ if ((as != FFEGLOBAL_argsummaryPROC)
+ || (ai->t == NULL))
+ ai->as = as; /* Otherwise leave SUBR/FUNC info intact. */
+ ai->t = ffelex_token_use (g->t);
+ if (name == NULL)
+ ai->name = NULL;
+ else
+ {
+ ai->name = malloc_new_ks (malloc_pool_image (),
+ "ffeglobalArgInfo_ name",
+ strlen (name) + 1);
+ strcpy (ai->name, name);
+ }
+ ai->bt = bt;
+ ai->kt = kt;
+ ai->array = array;
+}
+
+/* Collect info on #args a global accepts. */
+
+void
+ffeglobal_proc_def_nargs (ffesymbol s, int n_args)
+{
+ ffeglobal g = ffesymbol_global (s);
+
+ assert (g != NULL);
+
+ if (g->type == FFEGLOBAL_typeANY)
+ return;
+
+ if (g->u.proc.n_args >= 0)
+ {
+ if (g->u.proc.n_args == n_args)
+ return;
+
+ if (ffe_is_warn_globals ())
+ {
+ ffebad_start (FFEBAD_FILEWIDE_NARGS_W);
+ ffebad_string (ffesymbol_text (s));
+ if (g->u.proc.n_args > n_args)
+ ffebad_string ("few");
+ else
+ ffebad_string ("many");
+ ffebad_here (0, ffelex_token_where_line (g->u.proc.other_t),
+ ffelex_token_where_column (g->u.proc.other_t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+ }
+
+ /* This is new info we can use in cross-checking future references
+ and a possible future definition. */
+
+ g->u.proc.n_args = n_args;
+ g->u.proc.other_t = NULL; /* No other reference yet. */
+
+ if (n_args == 0)
+ {
+ g->u.proc.arg_info = NULL;
+ return;
+ }
+
+ g->u.proc.arg_info
+ = (ffeglobalArgInfo_) malloc_new_ks (malloc_pool_image (),
+ "ffeglobalArgInfo_",
+ n_args * sizeof (g->u.proc.arg_info[0]));
+ while (n_args-- > 0)
+ g->u.proc.arg_info[n_args].t = NULL;
+}
+
+/* Verify that the info for a global's argument is valid. */
+
+bool
+ffeglobal_proc_ref_arg (ffesymbol s, int argno, ffeglobalArgSummary as,
+ ffeinfoBasictype bt, ffeinfoKindtype kt,
+ bool array, ffelexToken t)
+{
+ ffeglobal g = ffesymbol_global (s);
+ ffeglobalArgInfo_ ai;
+
+ assert (g != NULL);
+
+ if (g->type == FFEGLOBAL_typeANY)
+ return FALSE;
+
+ assert (g->u.proc.n_args >= 0);
+
+ if (argno >= g->u.proc.n_args)
+ return TRUE; /* Already complained about this discrepancy. */
+
+ ai = &g->u.proc.arg_info[argno];
+
+ /* Warn about previous references. */
+
+ if (ai->t != NULL)
+ {
+ char *refwhy = NULL;
+ char *defwhy = NULL;
+ bool fail = FALSE;
+ bool warn = FALSE;
+
+ switch (as)
+ {
+ case FFEGLOBAL_argsummaryNONE:
+ if (g->u.proc.defined)
+ {
+ fail = TRUE;
+ refwhy = "omitted";
+ defwhy = "not optional";
+ }
+ break;
+
+ case FFEGLOBAL_argsummaryVAL:
+ if (ai->as != FFEGLOBAL_argsummaryVAL)
+ {
+ fail = TRUE;
+ refwhy = "passed by value";
+ }
+ break;
+
+ case FFEGLOBAL_argsummaryREF:
+ if ((ai->as != FFEGLOBAL_argsummaryREF)
+ && (ai->as != FFEGLOBAL_argsummaryNONE)
+ && ((ai->as != FFEGLOBAL_argsummaryDESCR) /* Choose better message. */
+ || (ai->bt != FFEINFO_basictypeCHARACTER)
+ || (ai->bt == bt)))
+ {
+ fail = TRUE;
+ refwhy = "passed by reference";
+ }
+ break;
+
+ case FFEGLOBAL_argsummaryDESCR:
+ if ((ai->as != FFEGLOBAL_argsummaryDESCR)
+ && (ai->as != FFEGLOBAL_argsummaryNONE)
+ && ((ai->as != FFEGLOBAL_argsummaryREF) /* Choose better message. */
+ || (bt != FFEINFO_basictypeCHARACTER)
+ || (ai->bt == bt)))
+ {
+ fail = TRUE;
+ refwhy = "passed by descriptor";
+ }
+ break;
+
+ case FFEGLOBAL_argsummaryPROC:
+ if ((ai->as != FFEGLOBAL_argsummaryPROC)
+ && (ai->as != FFEGLOBAL_argsummarySUBR)
+ && (ai->as != FFEGLOBAL_argsummaryFUNC)
+ && (ai->as != FFEGLOBAL_argsummaryNONE))
+ {
+ fail = TRUE;
+ refwhy = "a procedure";
+ }
+ break;
+
+ case FFEGLOBAL_argsummarySUBR:
+ if ((ai->as != FFEGLOBAL_argsummaryPROC)
+ && (ai->as != FFEGLOBAL_argsummarySUBR)
+ && (ai->as != FFEGLOBAL_argsummaryNONE))
+ {
+ fail = TRUE;
+ refwhy = "a subroutine";
+ }
+ break;
+
+ case FFEGLOBAL_argsummaryFUNC:
+ if ((ai->as != FFEGLOBAL_argsummaryPROC)
+ && (ai->as != FFEGLOBAL_argsummaryFUNC)
+ && (ai->as != FFEGLOBAL_argsummaryNONE))
+ {
+ fail = TRUE;
+ refwhy = "a function";
+ }
+ break;
+
+ case FFEGLOBAL_argsummaryALTRTN:
+ if ((ai->as != FFEGLOBAL_argsummaryALTRTN)
+ && (ai->as != FFEGLOBAL_argsummaryNONE))
+ {
+ fail = TRUE;
+ refwhy = "an alternate-return label";
+ }
+ break;
+
+#if 0
+ case FFEGLOBAL_argsummaryPTR:
+ if ((ai->as != FFEGLOBAL_argsummaryPTR)
+ && (ai->as != FFEGLOBAL_argsummaryNONE))
+ {
+ fail = TRUE;
+ refwhy = "a pointer";
+ }
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ if ((refwhy != NULL) && (defwhy == NULL))
+ {
+ /* Fill in the def info. */
+
+ switch (ai->as)
+ {
+ case FFEGLOBAL_argsummaryNONE:
+ defwhy = "omitted";
+ break;
+
+ case FFEGLOBAL_argsummaryVAL:
+ defwhy = "passed by value";
+ break;
+
+ case FFEGLOBAL_argsummaryREF:
+ defwhy = "passed by reference";
+ break;
+
+ case FFEGLOBAL_argsummaryDESCR:
+ defwhy = "passed by descriptor";
+ break;
+
+ case FFEGLOBAL_argsummaryPROC:
+ defwhy = "a procedure";
+ break;
+
+ case FFEGLOBAL_argsummarySUBR:
+ defwhy = "a subroutine";
+ break;
+
+ case FFEGLOBAL_argsummaryFUNC:
+ defwhy = "a function";
+ break;
+
+ case FFEGLOBAL_argsummaryALTRTN:
+ defwhy = "an alternate-return label";
+ break;
+
+#if 0
+ case FFEGLOBAL_argsummaryPTR:
+ defwhy = "a pointer";
+ break;
+#endif
+
+ default:
+ defwhy = "???";
+ break;
+ }
+ }
+
+ if (!fail && !warn
+ && (bt != FFEINFO_basictypeHOLLERITH)
+ && (bt != FFEINFO_basictypeTYPELESS)
+ && (bt != FFEINFO_basictypeNONE)
+ && (ai->bt != FFEINFO_basictypeHOLLERITH)
+ && (ai->bt != FFEINFO_basictypeNONE)
+ && (ai->bt != FFEINFO_basictypeTYPELESS))
+ {
+ /* Check types. */
+
+ if ((bt != ai->bt)
+ && ((bt != FFEINFO_basictypeREAL)
+ || (ai->bt != FFEINFO_basictypeCOMPLEX))
+ && ((bt != FFEINFO_basictypeCOMPLEX)
+ || (ai->bt != FFEINFO_basictypeREAL)))
+ {
+ if (((bt == FFEINFO_basictypeINTEGER)
+ && (ai->bt == FFEINFO_basictypeLOGICAL))
+ || ((bt == FFEINFO_basictypeLOGICAL)
+ && (ai->bt == FFEINFO_basictypeINTEGER)))
+ warn = TRUE; /* We can cope with these differences. */
+ else
+ fail = TRUE;
+ refwhy = "one type";
+ defwhy = "some other type";
+ }
+
+ if (!fail && !warn && (kt != ai->kt))
+ {
+ fail = TRUE;
+ refwhy = "one precision";
+ defwhy = "some other precision";
+ }
+ }
+
+ if (fail && ! g->u.proc.defined)
+ {
+ /* No point failing if we're worried only about invocations. */
+ fail = FALSE;
+ warn = TRUE;
+ }
+
+ if (fail && ! ffe_is_globals ())
+ {
+ warn = TRUE;
+ fail = FALSE;
+ }
+
+ if (fail || (warn && ffe_is_warn_globals ()))
+ {
+ char num[60];
+
+ if (ai->name == NULL)
+ sprintf (&num[0], "%d", argno + 1);
+ else
+ {
+ if (strlen (ai->name) < 30)
+ sprintf (&num[0], "%d (named `%s')", argno + 1, ai->name);
+ else
+ sprintf (&num[0], "%d (named `%.*s...')", argno + 1, 30, ai->name);
+ }
+ ffebad_start (fail ? FFEBAD_FILEWIDE_ARG : FFEBAD_FILEWIDE_ARG_W);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_string (num);
+ ffebad_string (refwhy);
+ ffebad_string (defwhy);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (ai->t), ffelex_token_where_column (ai->t));
+ ffebad_finish ();
+ return (fail ? FALSE : TRUE);
+ }
+
+ if (warn)
+ return TRUE;
+ }
+
+ /* Define this argument. */
+
+ if (ai->t != NULL)
+ ffelex_token_kill (ai->t);
+ if ((as != FFEGLOBAL_argsummaryPROC)
+ || (ai->t == NULL))
+ ai->as = as;
+ ai->t = ffelex_token_use (g->t);
+ ai->name = NULL;
+ ai->bt = bt;
+ ai->kt = kt;
+ ai->array = array;
+ return TRUE;
+}
+
+bool
+ffeglobal_proc_ref_nargs (ffesymbol s, int n_args, ffelexToken t)
+{
+ ffeglobal g = ffesymbol_global (s);
+
+ assert (g != NULL);
+
+ if (g->type == FFEGLOBAL_typeANY)
+ return FALSE;
+
+ if (g->u.proc.n_args >= 0)
+ {
+ if (g->u.proc.n_args == n_args)
+ return TRUE;
+
+ if (g->u.proc.defined && ffe_is_globals ())
+ {
+ ffebad_start (FFEBAD_FILEWIDE_NARGS);
+ ffebad_string (ffesymbol_text (s));
+ if (g->u.proc.n_args > n_args)
+ ffebad_string ("few");
+ else
+ ffebad_string ("many");
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ return FALSE;
+ }
+
+ if (ffe_is_warn_globals ())
+ {
+ ffebad_start (FFEBAD_FILEWIDE_NARGS_W);
+ ffebad_string (ffesymbol_text (s));
+ if (g->u.proc.n_args > n_args)
+ ffebad_string ("few");
+ else
+ ffebad_string ("many");
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+
+ return TRUE; /* Don't replace the info we already have. */
+ }
+
+ /* This is new info we can use in cross-checking future references
+ and a possible future definition. */
+
+ g->u.proc.n_args = n_args;
+ g->u.proc.other_t = ffelex_token_use (t);
+
+ /* Make this "the" place we found the global, since it has the most info. */
+
+ if (g->t != NULL)
+ ffelex_token_kill (g->t);
+ g->t = ffelex_token_use (t);
+
+ if (n_args == 0)
+ {
+ g->u.proc.arg_info = NULL;
+ return TRUE;
+ }
+
+ g->u.proc.arg_info
+ = (ffeglobalArgInfo_) malloc_new_ks (malloc_pool_image (),
+ "ffeglobalArgInfo_",
+ n_args * sizeof (g->u.proc.arg_info[0]));
+ while (n_args-- > 0)
+ g->u.proc.arg_info[n_args].t = NULL;
+
+ return TRUE;
+}
+
+/* Return a global for a promoted symbol (one that has heretofore
+ been assumed to be local, but since discovered to be global). */
+
+ffeglobal
+ffeglobal_promoted (ffesymbol s)
+{
+#if FFEGLOBAL_ENABLED
+ ffename n;
+ ffeglobal g;
+
+ assert (ffesymbol_global (s) == NULL);
+
+ n = ffename_find (ffeglobal_filewide_, ffename_token (ffesymbol_name (s)));
+ g = ffename_global (n);
+
+ return g;
+#else
+ return NULL;
+#endif
+}
+
+/* Register a reference to an intrinsic. Such a reference is always
+ valid, though a warning might be in order if the same name has
+ already been used for a global. */
+
+void
+ffeglobal_ref_intrinsic (ffesymbol s, ffelexToken t, bool explicit)
+{
+#if FFEGLOBAL_ENABLED
+ ffename n;
+ ffeglobal g;
+
+ if (ffesymbol_global (s) == NULL)
+ {
+ n = ffename_find (ffeglobal_filewide_, t);
+ g = ffename_global (n);
+ }
+ else
+ {
+ g = ffesymbol_global (s);
+ n = NULL;
+ }
+
+ if ((g != NULL) && (g->type == FFEGLOBAL_typeANY))
+ return;
+
+ if ((g != NULL) && (g->type != FFEGLOBAL_typeNONE))
+ {
+ if (! explicit
+ && ! g->intrinsic
+ && ffe_is_warn_globals ())
+ {
+ ffebad_start (FFEBAD_INTRINSIC_GLOBAL);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_string ("intrinsic");
+ ffebad_string ("global");
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if (g == NULL)
+ {
+ g = ffeglobal_new_ (n);
+ g->tick = ffe_count_2;
+ g->type = FFEGLOBAL_typeNONE;
+ g->intrinsic = TRUE;
+ g->explicit_intrinsic = explicit;
+ g->t = ffelex_token_use (t);
+ }
+ else if (g->intrinsic
+ && (explicit != g->explicit_intrinsic)
+ && (g->tick != ffe_count_2)
+ && ffe_is_warn_globals ())
+ {
+ ffebad_start (FFEBAD_INTRINSIC_EXPIMP);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_string (explicit ? "explicit" : "implicit");
+ ffebad_string (explicit ? "implicit" : "explicit");
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+ }
+
+ g->intrinsic = TRUE;
+ if (explicit)
+ g->explicit_intrinsic = TRUE;
+
+ ffesymbol_set_global (s, g);
+#endif
+}
+
+/* Register a reference to a global. Returns TRUE if the reference
+ is valid. */
+
+bool
+ffeglobal_ref_progunit_ (ffesymbol s, ffelexToken t, ffeglobalType type)
+{
+#if FFEGLOBAL_ENABLED
+ ffename n = NULL;
+ ffeglobal g;
+
+ /* It is never really _known_ that an EXTERNAL statement
+ names a BLOCK DATA by just looking at the program unit,
+ so override a different notion here. */
+ if (type == FFEGLOBAL_typeBDATA)
+ type = FFEGLOBAL_typeEXT;
+
+ g = ffesymbol_global (s);
+ if (g == NULL)
+ {
+ n = ffename_find (ffeglobal_filewide_, t);
+ g = ffename_global (n);
+ if (g != NULL)
+ ffesymbol_set_global (s, g);
+ }
+
+ if ((g != NULL) && (g->type == FFEGLOBAL_typeANY))
+ return TRUE;
+
+ if ((g != NULL)
+ && (g->type != FFEGLOBAL_typeNONE)
+ && (g->type != type)
+ && (g->type != FFEGLOBAL_typeEXT)
+ && (type != FFEGLOBAL_typeEXT))
+ {
+ if ((((type == FFEGLOBAL_typeBDATA)
+ && (g->type != FFEGLOBAL_typeCOMMON))
+ || ((g->type == FFEGLOBAL_typeBDATA)
+ && (type != FFEGLOBAL_typeCOMMON)
+ && ! g->u.proc.defined)))
+ {
+#if 0 /* This is likely to just annoy people. */
+ if (ffe_is_warn_globals ())
+ {
+ ffebad_start (FFEBAD_FILEWIDE_TIFF);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_string (ffeglobal_type_string_[type]);
+ ffebad_string (ffeglobal_type_string_[g->type]);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+#endif
+ }
+ else if (ffe_is_globals ())
+ {
+ ffebad_start (FFEBAD_FILEWIDE_DISAGREEMENT);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_string (ffeglobal_type_string_[type]);
+ ffebad_string (ffeglobal_type_string_[g->type]);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ g->type = FFEGLOBAL_typeANY;
+ return FALSE;
+ }
+ else if (ffe_is_warn_globals ())
+ {
+ ffebad_start (FFEBAD_FILEWIDE_DISAGREEMENT_W);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_string (ffeglobal_type_string_[type]);
+ ffebad_string (ffeglobal_type_string_[g->type]);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ g->type = FFEGLOBAL_typeANY;
+ return TRUE;
+ }
+ }
+
+ if ((g != NULL)
+ && (type == FFEGLOBAL_typeFUNC))
+ {
+ /* If just filling in this function's type, do so. */
+ if ((g->tick == ffe_count_2)
+ && (ffesymbol_basictype (s) != FFEINFO_basictypeNONE)
+ && (ffesymbol_kindtype (s) != FFEINFO_kindtypeNONE))
+ {
+ g->u.proc.bt = ffesymbol_basictype (s);
+ g->u.proc.kt = ffesymbol_kindtype (s);
+ g->u.proc.sz = ffesymbol_size (s);
+ }
+ /* Else, make sure there is type agreement. */
+ else if ((g->u.proc.bt != FFEINFO_basictypeNONE)
+ && (ffesymbol_basictype (s) != FFEINFO_basictypeNONE)
+ && ((ffesymbol_basictype (s) != g->u.proc.bt)
+ || (ffesymbol_kindtype (s) != g->u.proc.kt)
+ || ((ffesymbol_size (s) != g->u.proc.sz)
+ && g->u.proc.defined
+ && (g->u.proc.sz != FFETARGET_charactersizeNONE))))
+ {
+ if (ffe_is_globals ())
+ {
+ ffebad_start (FFEBAD_FILEWIDE_TYPE_MISMATCH);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ g->type = FFEGLOBAL_typeANY;
+ return FALSE;
+ }
+ if (ffe_is_warn_globals ())
+ {
+ ffebad_start (FFEBAD_FILEWIDE_TYPE_MISMATCH_W);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+ g->type = FFEGLOBAL_typeANY;
+ return TRUE;
+ }
+ }
+
+ if (g == NULL)
+ {
+ g = ffeglobal_new_ (n);
+ g->t = ffelex_token_use (t);
+ g->tick = ffe_count_2;
+ g->intrinsic = FALSE;
+ g->type = type;
+ g->u.proc.defined = FALSE;
+ g->u.proc.bt = ffesymbol_basictype (s);
+ g->u.proc.kt = ffesymbol_kindtype (s);
+ g->u.proc.sz = ffesymbol_size (s);
+ g->u.proc.n_args = -1;
+ ffesymbol_set_global (s, g);
+ }
+ else if (g->intrinsic
+ && !g->explicit_intrinsic
+ && (g->tick != ffe_count_2)
+ && ffe_is_warn_globals ())
+ {
+ ffebad_start (FFEBAD_INTRINSIC_GLOBAL);
+ ffebad_string (ffelex_token_text (t));
+ ffebad_string ("global");
+ ffebad_string ("intrinsic");
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_here (1, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_finish ();
+ }
+
+ if ((g->type != type)
+ && (type != FFEGLOBAL_typeEXT))
+ {
+ /* We've learned more, so point to where we learned it. */
+ g->t = ffelex_token_use (t);
+ g->type = type;
+#ifdef FFECOM_globalHOOK
+ g->hook = FFECOM_globalNULL; /* Discard previous _DECL. */
+#endif
+ g->u.proc.n_args = -1;
+ }
+
+ return TRUE;
+#endif
+}
+
+/* ffeglobal_save_common -- Check SAVE status of common area
+
+ ffesymbol s; // the common area
+ bool save; // TRUE if SAVEd, FALSE otherwise
+ ffeglobal_save_common(s,save,ffesymbol_where_line(s),
+ ffesymbol_where_column(s));
+
+ In global-enabled mode, make sure the save info agrees with any existing
+ info established for the common area, otherwise complain.
+ In global-disabled mode, do nothing. */
+
+void
+ffeglobal_save_common (ffesymbol s, bool save, ffewhereLine wl,
+ ffewhereColumn wc)
+{
+#if FFEGLOBAL_ENABLED
+ ffeglobal g;
+
+ g = ffesymbol_global (s);
+ if ((g == NULL) || (g->type != FFEGLOBAL_typeCOMMON))
+ return; /* Let someone else catch this! */
+ if (g->type == FFEGLOBAL_typeANY)
+ return;
+
+ if (!g->u.common.have_save)
+ {
+ g->u.common.have_save = TRUE;
+ g->u.common.save = save;
+ g->u.common.save_where_line = ffewhere_line_use (wl);
+ g->u.common.save_where_col = ffewhere_column_use (wc);
+ }
+ else
+ {
+ if ((g->u.common.save != save) && ffe_is_pedantic ())
+ {
+ ffebad_start (FFEBAD_COMMON_DIFF_SAVE);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_here (save ? 0 : 1, wl, wc);
+ ffebad_here (save ? 1 : 0, g->u.common.pad_where_line, g->u.common.pad_where_col);
+ ffebad_finish ();
+ }
+ }
+#endif
+}
+
+/* ffeglobal_size_common -- Establish size of COMMON area
+
+ ffesymbol s; // the common area
+ ffetargetOffset size; // size in units
+ if (ffeglobal_size_common(s,size)) // new size is largest seen
+
+ In global-enabled mode, set the size if it current size isn't known or is
+ smaller than new size, and for non-blank common, complain if old size
+ is different from new. Return TRUE if the new size is the largest seen
+ for this COMMON area (or if no size was known for it previously).
+ In global-disabled mode, do nothing. */
+
+#if FFEGLOBAL_ENABLED
+bool
+ffeglobal_size_common (ffesymbol s, ffetargetOffset size)
+{
+ ffeglobal g;
+
+ g = ffesymbol_global (s);
+ if ((g == NULL) || (g->type != FFEGLOBAL_typeCOMMON))
+ return FALSE;
+ if (g->type == FFEGLOBAL_typeANY)
+ return FALSE;
+
+ if (!g->u.common.have_size)
+ {
+ g->u.common.have_size = TRUE;
+ g->u.common.size = size;
+ return TRUE;
+ }
+
+ if ((g->tick > 0) && (g->tick < ffe_count_2)
+ && (g->u.common.size < size))
+ {
+ char oldsize[40];
+ char newsize[40];
+
+ /* Common block initialized in a previous program unit, which
+ effectively freezes its size, but now the program is trying
+ to enlarge it. */
+
+ sprintf (&oldsize[0], "%" ffetargetOffset_f "d", g->u.common.size);
+ sprintf (&newsize[0], "%" ffetargetOffset_f "d", size);
+
+ ffebad_start (FFEBAD_COMMON_ENLARGED);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_string (oldsize);
+ ffebad_string (newsize);
+ ffebad_string ((g->u.common.size == 1)
+ ? FFECOM_SIZE_UNIT : FFECOM_SIZE_UNITS);
+ ffebad_string ((size == 1)
+ ? FFECOM_SIZE_UNIT : FFECOM_SIZE_UNITS);
+ ffebad_here (0, ffelex_token_where_line (g->u.common.initt),
+ ffelex_token_where_column (g->u.common.initt));
+ ffebad_here (1, ffesymbol_where_line (s),
+ ffesymbol_where_column (s));
+ ffebad_finish ();
+ }
+ else if ((g->u.common.size != size) && !g->u.common.blank)
+ {
+ char oldsize[40];
+ char newsize[40];
+
+ /* Warn about this even if not -pedantic, because putting all
+ program units in a single source file is the only way to
+ detect this. Apparently UNIX-model linkers neither handle
+ nor report when they make a common unit smaller than
+ requested, such as when the smaller-declared version is
+ initialized and the larger-declared version is not. So
+ if people complain about strange overwriting, we can tell
+ them to put all their code in a single file and compile
+ that way. Warnings about differing sizes must therefore
+ always be issued. */
+
+ sprintf (&oldsize[0], "%" ffetargetOffset_f "d", g->u.common.size);
+ sprintf (&newsize[0], "%" ffetargetOffset_f "d", size);
+
+ ffebad_start (FFEBAD_COMMON_DIFF_SIZE);
+ ffebad_string (ffesymbol_text (s));
+ ffebad_string (oldsize);
+ ffebad_string (newsize);
+ ffebad_string ((g->u.common.size == 1)
+ ? FFECOM_SIZE_UNIT : FFECOM_SIZE_UNITS);
+ ffebad_string ((size == 1)
+ ? FFECOM_SIZE_UNIT : FFECOM_SIZE_UNITS);
+ ffebad_here (0, ffelex_token_where_line (g->t),
+ ffelex_token_where_column (g->t));
+ ffebad_here (1, ffesymbol_where_line (s),
+ ffesymbol_where_column (s));
+ ffebad_finish ();
+ }
+
+ if (size > g->u.common.size)
+ {
+ g->u.common.size = size;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+#endif
+void
+ffeglobal_terminate_1 ()
+{
+}
diff --git a/contrib/gcc/f/global.h b/contrib/gcc/f/global.h
new file mode 100644
index 0000000..38cf8d5
--- /dev/null
+++ b/contrib/gcc/f/global.h
@@ -0,0 +1,200 @@
+/* global.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995, 1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ global.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_global
+#define _H_f_global
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFEGLOBAL_typeNONE,
+ FFEGLOBAL_typeMAIN,
+ FFEGLOBAL_typeEXT, /* EXTERNAL is all we know. */
+ FFEGLOBAL_typeSUBR,
+ FFEGLOBAL_typeFUNC,
+ FFEGLOBAL_typeBDATA,
+ FFEGLOBAL_typeCOMMON,
+ FFEGLOBAL_typeANY, /* Confusion reigns, so just ignore. */
+ FFEGLOBAL_type
+ } ffeglobalType;
+
+typedef enum
+ {
+ FFEGLOBAL_argsummaryNONE, /* No arg present. */
+ FFEGLOBAL_argsummaryVAL, /* Pass-by-value. */
+ FFEGLOBAL_argsummaryREF, /* Pass-by-reference. */
+ FFEGLOBAL_argsummaryDESCR, /* Pass-by-descriptor. */
+ FFEGLOBAL_argsummaryPROC, /* Procedure (intrinsic, external). */
+ FFEGLOBAL_argsummarySUBR, /* Subroutine (intrinsic, external). */
+ FFEGLOBAL_argsummaryFUNC, /* Function (intrinsic, external). */
+ FFEGLOBAL_argsummaryALTRTN, /* Alternate-return (label). */
+ FFEGLOBAL_argsummaryANY,
+ FFEGLOBAL_argsummary
+ } ffeglobalArgSummary;
+
+/* Typedefs. */
+
+typedef struct _ffeglobal_arginfo_ *ffeglobalArgInfo_;
+typedef struct _ffeglobal_ *ffeglobal;
+
+/* Include files needed by this one. */
+
+#include "info.h"
+#include "lex.h"
+#include "name.h"
+#include "symbol.h"
+#include "target.h"
+#include "top.h"
+
+/* Structure definitions. */
+
+struct _ffeglobal_arginfo_
+{
+ ffelexToken t; /* Different from master token when difference is important. */
+ char *name; /* Name of dummy arg, or NULL if not yet known. */
+ ffeglobalArgSummary as;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ bool array;
+};
+
+struct _ffeglobal_
+{
+ ffelexToken t;
+ ffename n;
+#ifdef FFECOM_globalHOOK
+ ffecomGlobal hook;
+#endif
+ ffeCounter tick; /* Recent transition in this progunit. */
+ ffeglobalType type;
+ bool intrinsic; /* Known as intrinsic? */
+ bool explicit_intrinsic; /* Explicit intrinsic? */
+ union {
+ struct {
+ ffelexToken initt; /* First initial value. */
+ bool have_pad; /* Padding info avail for COMMON? */
+ ffetargetAlign pad; /* Initial padding for COMMON. */
+ ffewhereLine pad_where_line;
+ ffewhereColumn pad_where_col;
+ bool have_save; /* Save info avail for COMMON? */
+ bool save; /* Save info for COMMON. */
+ ffewhereLine save_where_line;
+ ffewhereColumn save_where_col;
+ bool have_size; /* Size info avail for COMMON? */
+ ffetargetOffset size; /* Size info for COMMON. */
+ bool blank; /* TRUE if blank COMMON. */
+ } common;
+ struct {
+ bool defined; /* Seen actual code yet? */
+ ffeinfoBasictype bt; /* NONE for non-function. */
+ ffeinfoKindtype kt; /* NONE for non-function. */
+ ffetargetCharacterSize sz;
+ int n_args; /* 0 for main/blockdata. */
+ ffelexToken other_t; /* Location of reference. */
+ ffeglobalArgInfo_ arg_info; /* Info on each argument. */
+ } proc;
+ } u;
+};
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+void ffeglobal_drive (ffeglobal (*fn) ());
+void ffeglobal_init_1 (void);
+void ffeglobal_init_common (ffesymbol s, ffelexToken t);
+void ffeglobal_new_progunit_ (ffesymbol s, ffelexToken t, ffeglobalType type);
+void ffeglobal_new_common (ffesymbol s, ffelexToken t, bool blank);
+void ffeglobal_pad_common (ffesymbol s, ffetargetAlign pad, ffewhereLine wl,
+ ffewhereColumn wc);
+void ffeglobal_proc_def_arg (ffesymbol s, int argno, char *name, ffeglobalArgSummary as,
+ ffeinfoBasictype bt, ffeinfoKindtype kt,
+ bool array);
+void ffeglobal_proc_def_nargs (ffesymbol s, int n_args);
+bool ffeglobal_proc_ref_arg (ffesymbol s, int argno, ffeglobalArgSummary as,
+ ffeinfoBasictype bt, ffeinfoKindtype kt,
+ bool array, ffelexToken t);
+bool ffeglobal_proc_ref_nargs (ffesymbol s, int n_args, ffelexToken t);
+ffeglobal ffeglobal_promoted (ffesymbol s);
+void ffeglobal_ref_intrinsic (ffesymbol s, ffelexToken t, bool explicit);
+bool ffeglobal_ref_progunit_ (ffesymbol s, ffelexToken t, ffeglobalType type);
+void ffeglobal_save_common (ffesymbol s, bool save, ffewhereLine wl,
+ ffewhereColumn wc);
+bool ffeglobal_size_common (ffesymbol s, ffetargetOffset size);
+void ffeglobal_terminate_1 (void);
+
+/* Define macros. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+#define FFEGLOBAL_ENABLED 0
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#define FFEGLOBAL_ENABLED 1
+#else
+#error
+#endif
+
+#define ffeglobal_common_init(g) ((g)->tick != 0)
+#define ffeglobal_common_have_pad(g) ((g)->u.common.have_pad)
+#define ffeglobal_common_have_size(g) ((g)->u.common.have_size)
+#define ffeglobal_common_pad(g) ((g)->u.common.pad)
+#define ffeglobal_common_size(g) ((g)->u.common.size)
+#define ffeglobal_hook(g) ((g)->hook)
+#define ffeglobal_init_0()
+#define ffeglobal_init_2()
+#define ffeglobal_init_3()
+#define ffeglobal_init_4()
+#define ffeglobal_new_blockdata(s,t) \
+ ffeglobal_new_progunit_(s,t,FFEGLOBAL_typeBDATA)
+#define ffeglobal_new_function(s,t) \
+ ffeglobal_new_progunit_(s,t,FFEGLOBAL_typeFUNC)
+#define ffeglobal_new_program(s,t) \
+ ffeglobal_new_progunit_(s,t,FFEGLOBAL_typeMAIN)
+#define ffeglobal_new_subroutine(s,t) \
+ ffeglobal_new_progunit_(s,t,FFEGLOBAL_typeSUBR)
+#define ffeglobal_ref_blockdata(s,t) \
+ ffeglobal_ref_progunit_(s,t,FFEGLOBAL_typeBDATA)
+#define ffeglobal_ref_external(s,t) \
+ ffeglobal_ref_progunit_(s,t,FFEGLOBAL_typeEXT)
+#define ffeglobal_ref_function(s,t) \
+ ffeglobal_ref_progunit_(s,t,FFEGLOBAL_typeFUNC)
+#define ffeglobal_ref_subroutine(s,t) \
+ ffeglobal_ref_progunit_(s,t,FFEGLOBAL_typeSUBR)
+#define ffeglobal_set_hook(g,h) ((g)->hook = (h))
+#define ffeglobal_terminate_0()
+#define ffeglobal_terminate_2()
+#define ffeglobal_terminate_3()
+#define ffeglobal_terminate_4()
+#define ffeglobal_text(g) ffename_text((g)->n)
+#define ffeglobal_type(g) ((g)->type)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/hconfig.j b/contrib/gcc/f/hconfig.j
new file mode 100644
index 0000000..a2fc0d1
--- /dev/null
+++ b/contrib/gcc/f/hconfig.j
@@ -0,0 +1,27 @@
+/* hconfig.j -- Wrapper for GCC's hconfig.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_hconfig
+#define _J_f_hconfig
+#include "hconfig.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/implic.c b/contrib/gcc/f/implic.c
new file mode 100644
index 0000000..bee8edf
--- /dev/null
+++ b/contrib/gcc/f/implic.c
@@ -0,0 +1,382 @@
+/* implic.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None.
+
+ Description:
+ The GNU Fortran Front End.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "implic.h"
+#include "info.h"
+#include "src.h"
+#include "symbol.h"
+#include "target.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFEIMPLIC_stateINITIAL_,
+ FFEIMPLIC_stateASSUMED_,
+ FFEIMPLIC_stateESTABLISHED_,
+ FFEIMPLIC_state
+ } ffeimplicState_;
+
+/* Internal typedefs. */
+
+typedef struct _ffeimplic_ *ffeimplic_;
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+struct _ffeimplic_
+ {
+ ffeimplicState_ state;
+ ffeinfo info;
+ };
+
+/* Static objects accessed by functions in this module. */
+
+/* NOTE: This is definitely ASCII-specific!! */
+
+static struct _ffeimplic_ ffeimplic_table_['z' - 'A' + 1];
+
+/* Static functions (internal). */
+
+static ffeimplic_ ffeimplic_lookup_ (char c);
+
+/* Internal macros. */
+
+
+/* ffeimplic_lookup_ -- Look up implicit descriptor for initial character
+
+ ffeimplic_ imp;
+ if ((imp = ffeimplic_lookup_('A')) == NULL)
+ // error
+
+ Returns a pointer to an implicit descriptor block based on the character
+ passed, or NULL if it is not a valid initial character for an implicit
+ data type. */
+
+static ffeimplic_
+ffeimplic_lookup_ (char c)
+{
+ /* NOTE: This is definitely ASCII-specific!! */
+ if (ISALPHA (c) || (c == '_'))
+ return &ffeimplic_table_[c - 'A'];
+ return NULL;
+}
+
+/* ffeimplic_establish_initial -- Establish type of implicit initial letter
+
+ ffesymbol s;
+ if (!ffeimplic_establish_initial(s))
+ // error
+
+ Assigns implicit type information to the symbol based on the first
+ character of the symbol's name. */
+
+bool
+ffeimplic_establish_initial (char c, ffeinfoBasictype basic_type,
+ ffeinfoKindtype kind_type, ffetargetCharacterSize size)
+{
+ ffeimplic_ imp;
+
+ imp = ffeimplic_lookup_ (c);
+ if (imp == NULL)
+ return FALSE; /* Character not A-Z or some such thing. */
+ if (ffeinfo_basictype (imp->info) == FFEINFO_basictypeNONE)
+ return FALSE; /* IMPLICIT NONE in effect here. */
+
+ switch (imp->state)
+ {
+ case FFEIMPLIC_stateINITIAL_:
+ imp->info = ffeinfo_new (basic_type,
+ kind_type,
+ 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereNONE,
+ size);
+ imp->state = FFEIMPLIC_stateESTABLISHED_;
+ return TRUE;
+
+ case FFEIMPLIC_stateASSUMED_:
+ if ((ffeinfo_basictype (imp->info) != basic_type)
+ || (ffeinfo_kindtype (imp->info) != kind_type)
+ || (ffeinfo_size (imp->info) != size))
+ return FALSE;
+ imp->state = FFEIMPLIC_stateESTABLISHED_;
+ return TRUE;
+
+ case FFEIMPLIC_stateESTABLISHED_:
+ return FALSE;
+
+ default:
+ assert ("Weird state for implicit object" == NULL);
+ return FALSE;
+ }
+}
+
+/* ffeimplic_establish_symbol -- Establish implicit type of a symbol
+
+ ffesymbol s;
+ if (!ffeimplic_establish_symbol(s))
+ // error
+
+ Assigns implicit type information to the symbol based on the first
+ character of the symbol's name.
+
+ If symbol already has a type, return TRUE.
+ Get first character of symbol's name.
+ Get ffeimplic_ object for it (return FALSE if NULL returned).
+ Return FALSE if object has no assigned type (IMPLICIT NONE).
+ Copy the type information from the object to the symbol.
+ If the object is state "INITIAL", set to state "ASSUMED" so no
+ subsequent IMPLICIT statement may change the state.
+ Return TRUE. */
+
+bool
+ffeimplic_establish_symbol (ffesymbol s)
+{
+ char c;
+ ffeimplic_ imp;
+
+ if (ffesymbol_basictype (s) != FFEINFO_basictypeNONE)
+ return TRUE;
+
+ c = *(ffesymbol_text (s));
+ imp = ffeimplic_lookup_ (c);
+ if (imp == NULL)
+ return FALSE; /* First character not A-Z or some such
+ thing. */
+ if (ffeinfo_basictype (imp->info) == FFEINFO_basictypeNONE)
+ return FALSE; /* IMPLICIT NONE in effect here. */
+
+ ffesymbol_signal_change (s); /* Gonna change, save existing? */
+
+ /* Establish basictype, kindtype, size; preserve rank, kind, where. */
+
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffeinfo_basictype (imp->info),
+ ffeinfo_kindtype (imp->info),
+ ffesymbol_rank (s),
+ ffesymbol_kind (s),
+ ffesymbol_where (s),
+ ffeinfo_size (imp->info)));
+
+ if (imp->state == FFEIMPLIC_stateINITIAL_)
+ imp->state = FFEIMPLIC_stateASSUMED_;
+
+ if (ffe_is_warn_implicit ())
+ {
+ ffebad_start_msg ("Implicit declaration of `%A' at %0",
+ FFEBAD_severityWARNING);
+ ffebad_here (0, ffesymbol_where_line (s),
+ ffesymbol_where_column (s));
+ ffebad_string (ffesymbol_text (s));
+ ffebad_finish ();
+ }
+
+ return TRUE;
+}
+
+/* ffeimplic_init_2 -- Initialize table
+
+ ffeimplic_init_2();
+
+ Assigns initial type information to all initial letters.
+
+ Allows for holes in the sequence of letters (i.e. EBCDIC). */
+
+void
+ffeimplic_init_2 ()
+{
+ ffeimplic_ imp;
+ char c;
+
+ for (c = 'A'; c <= 'z'; ++c)
+ {
+ imp = &ffeimplic_table_[c - 'A'];
+ imp->state = FFEIMPLIC_stateINITIAL_;
+ switch (c)
+ {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case '_':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ imp->info = ffeinfo_new (FFEINFO_basictypeREAL,
+ FFEINFO_kindtypeREALDEFAULT,
+ 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereNONE,
+ FFETARGET_charactersizeNONE);
+ break;
+
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ imp->info = ffeinfo_new (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0, FFEINFO_kindNONE, FFEINFO_whereNONE,
+ FFETARGET_charactersizeNONE);
+ break;
+
+ default:
+ imp->info = ffeinfo_new (FFEINFO_basictypeNONE, FFEINFO_kindtypeNONE, 0,
+ FFEINFO_kindNONE, FFEINFO_whereNONE, FFETARGET_charactersizeNONE);
+ break;
+ }
+ }
+}
+
+/* ffeimplic_none -- Implement IMPLICIT NONE statement
+
+ ffeimplic_none();
+
+ Assigns null type information to all initial letters. */
+
+void
+ffeimplic_none ()
+{
+ ffeimplic_ imp;
+
+ for (imp = &ffeimplic_table_[0];
+ imp != &ffeimplic_table_[ARRAY_SIZE (ffeimplic_table_)];
+ imp++)
+ {
+ imp->info = ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereNONE,
+ FFETARGET_charactersizeNONE);
+ }
+}
+
+/* ffeimplic_peek_symbol_type -- Determine implicit type of a symbol
+
+ ffesymbol s;
+ char *name; // name for s in case it is NULL, or NULL if s never NULL
+ if (ffeimplic_peek_symbol_type(s,name) == FFEINFO_basictypeCHARACTER)
+ // is or will be a CHARACTER-typed name
+
+ Like establish_symbol, but doesn't change anything.
+
+ If symbol is non-NULL and already has a type, return it.
+ Get first character of symbol's name or from name arg if symbol is NULL.
+ Get ffeimplic_ object for it (return FALSE if NULL returned).
+ Return NONE if object has no assigned type (IMPLICIT NONE).
+ Return the data type indicated in the object.
+
+ 24-Oct-91 JCB 2.0
+ Take a char * instead of ffelexToken, since the latter isn't always
+ needed anyway (as when ffecom calls it). */
+
+ffeinfoBasictype
+ffeimplic_peek_symbol_type (ffesymbol s, char *name)
+{
+ char c;
+ ffeimplic_ imp;
+
+ if (s == NULL)
+ c = *name;
+ else
+ {
+ if (ffesymbol_basictype (s) != FFEINFO_basictypeNONE)
+ return ffesymbol_basictype (s);
+
+ c = *(ffesymbol_text (s));
+ }
+
+ imp = ffeimplic_lookup_ (c);
+ if (imp == NULL)
+ return FFEINFO_basictypeNONE; /* First character not A-Z or
+ something. */
+ return ffeinfo_basictype (imp->info);
+}
+
+/* ffeimplic_terminate_2 -- Terminate table
+
+ ffeimplic_terminate_2();
+
+ Kills info object for each entry in table. */
+
+void
+ffeimplic_terminate_2 ()
+{
+}
diff --git a/contrib/gcc/f/implic.h b/contrib/gcc/f/implic.h
new file mode 100644
index 0000000..7550e0d
--- /dev/null
+++ b/contrib/gcc/f/implic.h
@@ -0,0 +1,74 @@
+/* implic.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ implic.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_implic
+#define _H_f_implic
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "info.h"
+#include "symbol.h"
+#include "target.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+bool ffeimplic_establish_initial (char c, ffeinfoBasictype basic_type,
+ ffeinfoKindtype kind_type, ffetargetCharacterSize size);
+bool ffeimplic_establish_symbol (ffesymbol s);
+void ffeimplic_init_2 (void);
+void ffeimplic_none (void);
+ffeinfoBasictype ffeimplic_peek_symbol_type (ffesymbol s, char *name);
+void ffeimplic_terminate_2 (void);
+
+/* Define macros. */
+
+#define ffeimplic_init_0()
+#define ffeimplic_init_1()
+#define ffeimplic_init_3()
+#define ffeimplic_init_4()
+#define ffeimplic_terminate_0()
+#define ffeimplic_terminate_1()
+#define ffeimplic_terminate_3()
+#define ffeimplic_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/info-b.def b/contrib/gcc/f/info-b.def
new file mode 100644
index 0000000..30df25e
--- /dev/null
+++ b/contrib/gcc/f/info-b.def
@@ -0,0 +1,36 @@
+/* info-b.def -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ info.c
+
+ Modifications:
+*/
+
+FFEINFO_BASICTYPE (FFEINFO_basictypeNONE, "None", "")
+FFEINFO_BASICTYPE (FFEINFO_basictypeINTEGER, "INTEGER", "i")
+FFEINFO_BASICTYPE (FFEINFO_basictypeLOGICAL, "LOGICAL", "l")
+FFEINFO_BASICTYPE (FFEINFO_basictypeREAL, "REAL", "r")
+FFEINFO_BASICTYPE (FFEINFO_basictypeCOMPLEX, "COMPLEX", "c")
+FFEINFO_BASICTYPE (FFEINFO_basictypeCHARACTER, "CHARACTER", "a")
+FFEINFO_BASICTYPE (FFEINFO_basictypeHOLLERITH, "Hollerith", "h")
+FFEINFO_BASICTYPE (FFEINFO_basictypeTYPELESS, "Typeless", "t")
+FFEINFO_BASICTYPE (FFEINFO_basictypeANY, "Any", "~")
diff --git a/contrib/gcc/f/info-k.def b/contrib/gcc/f/info-k.def
new file mode 100644
index 0000000..a1441c9
--- /dev/null
+++ b/contrib/gcc/f/info-k.def
@@ -0,0 +1,37 @@
+/* info-k.def -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ info.c
+
+ Modifications:
+*/
+
+FFEINFO_KIND (FFEINFO_kindNONE, "an unknown kind", "")
+FFEINFO_KIND (FFEINFO_kindENTITY, "an entity", "e")
+FFEINFO_KIND (FFEINFO_kindFUNCTION, "a function", "f")
+FFEINFO_KIND (FFEINFO_kindSUBROUTINE, "a subroutine", "u")
+FFEINFO_KIND (FFEINFO_kindPROGRAM, "a program", "p")
+FFEINFO_KIND (FFEINFO_kindBLOCKDATA, "a block-data unit", "b")
+FFEINFO_KIND (FFEINFO_kindCOMMON, "a common block", "c")
+FFEINFO_KIND (FFEINFO_kindCONSTRUCT, "a construct", ":")
+FFEINFO_KIND (FFEINFO_kindNAMELIST, "a namelist", "n")
+FFEINFO_KIND (FFEINFO_kindANY, "anything", "~")
diff --git a/contrib/gcc/f/info-w.def b/contrib/gcc/f/info-w.def
new file mode 100644
index 0000000..54a1b364
--- /dev/null
+++ b/contrib/gcc/f/info-w.def
@@ -0,0 +1,41 @@
+/* info-w.def -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ info.c
+
+ Modifications:
+*/
+
+FFEINFO_WHERE (FFEINFO_whereNONE, "None", "")
+FFEINFO_WHERE (FFEINFO_whereLOCAL, "Local", "l") /* Defined locally. */
+FFEINFO_WHERE (FFEINFO_whereCOMMON, "Common", "c") /* In a common area. */
+FFEINFO_WHERE (FFEINFO_whereDUMMY, "Dummy", "d") /* A dummy argument. */
+FFEINFO_WHERE (FFEINFO_whereGLOBAL, "Global", "g") /* Reference to external global like FUNCTION, SUBR. */
+FFEINFO_WHERE (FFEINFO_whereRESULT, "Result", "r") /* Result of this function. */
+FFEINFO_WHERE (FFEINFO_whereFLEETING, "Fleeting", "f") /* Result of "X*Y", "FUNCREF(5,1.3)", "ARRAY(X)", etc. */
+FFEINFO_WHERE (FFEINFO_whereFLEETING_CADDR, "Fleet-Const", "fp") /* "A(3)", "CHARS(4:5)". */
+FFEINFO_WHERE (FFEINFO_whereFLEETING_IADDR, "Fleet-Immed", "fi") /* A(IX) in "DATA (A(IX),IX=1,100)/.../". */
+FFEINFO_WHERE (FFEINFO_whereIMMEDIATE, "Immediate", "i") /* IX in "DATA (A(IX),IX=1,100)/.../". */
+FFEINFO_WHERE (FFEINFO_whereINTRINSIC, "Intrinsic", "b")
+FFEINFO_WHERE (FFEINFO_whereCONSTANT, "Constant", "p") /* For kindFUNCTION, means statement function! */
+FFEINFO_WHERE (FFEINFO_whereCONSTANT_SUBOBJECT, "Const-subobj", "q") /* As in "'FOO'(I:J)". */
+FFEINFO_WHERE (FFEINFO_whereANY, "Any", "~")
diff --git a/contrib/gcc/f/info.c b/contrib/gcc/f/info.c
new file mode 100644
index 0000000..05a6e26
--- /dev/null
+++ b/contrib/gcc/f/info.c
@@ -0,0 +1,304 @@
+/* info.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ An abstraction for information maintained on a per-operator and per-
+ operand basis in expression trees.
+
+ Modifications:
+ 30-Aug-90 JCB 2.0
+ Extensive rewrite for new cleaner approach.
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "info.h"
+#include "target.h"
+#include "type.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+static char *ffeinfo_basictype_string_[]
+=
+{
+#define FFEINFO_BASICTYPE(KWD,LNAM,SNAM) SNAM,
+#include "info-b.def"
+#undef FFEINFO_BASICTYPE
+};
+static char *ffeinfo_kind_message_[]
+=
+{
+#define FFEINFO_KIND(KWD,LNAM,SNAM) LNAM,
+#include "info-k.def"
+#undef FFEINFO_KIND
+};
+static char *ffeinfo_kind_string_[]
+=
+{
+#define FFEINFO_KIND(KWD,LNAM,SNAM) SNAM,
+#include "info-k.def"
+#undef FFEINFO_KIND
+};
+static ffeinfoBasictype ffeinfo_combine_[FFEINFO_basictype][FFEINFO_basictype];
+static char *ffeinfo_kindtype_string_[]
+=
+{
+ "",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "*",
+};
+static char *ffeinfo_where_string_[]
+=
+{
+#define FFEINFO_WHERE(KWD,LNAM,SNAM) SNAM,
+#include "info-w.def"
+#undef FFEINFO_WHERE
+};
+static ffetype ffeinfo_types_[FFEINFO_basictype][FFEINFO_kindtype]
+ = { { NULL } };
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+
+/* ffeinfo_basictype_combine -- Combine two basictypes into highest rank type
+
+ ffeinfoBasictype i, j, k;
+ k = ffeinfo_basictype_combine(i,j);
+
+ Returns a type based on "standard" operation between two given types. */
+
+ffeinfoBasictype
+ffeinfo_basictype_combine (ffeinfoBasictype l, ffeinfoBasictype r)
+{
+ assert (l < FFEINFO_basictype);
+ assert (r < FFEINFO_basictype);
+ return ffeinfo_combine_[l][r];
+}
+
+/* ffeinfo_basictype_string -- Return tiny string showing the basictype
+
+ ffeinfoBasictype i;
+ printf("%s",ffeinfo_basictype_string(dt));
+
+ Returns the string based on the basic type. */
+
+char *
+ffeinfo_basictype_string (ffeinfoBasictype basictype)
+{
+ if (basictype >= ARRAY_SIZE (ffeinfo_basictype_string_))
+ return "?\?\?";
+ return ffeinfo_basictype_string_[basictype];
+}
+
+/* ffeinfo_init_0 -- Initialize
+
+ ffeinfo_init_0(); */
+
+void
+ffeinfo_init_0 ()
+{
+ ffeinfoBasictype i;
+ ffeinfoBasictype j;
+
+ assert (FFEINFO_basictype == ARRAY_SIZE (ffeinfo_basictype_string_));
+ assert (FFEINFO_kind == ARRAY_SIZE (ffeinfo_kind_message_));
+ assert (FFEINFO_kind == ARRAY_SIZE (ffeinfo_kind_string_));
+ assert (FFEINFO_kindtype == ARRAY_SIZE (ffeinfo_kindtype_string_));
+ assert (FFEINFO_where == ARRAY_SIZE (ffeinfo_where_string_));
+
+ /* Make array that, given two basic types, produces resulting basic type. */
+
+ for (i = 0; i < FFEINFO_basictype; ++i)
+ for (j = 0; j < FFEINFO_basictype; ++j)
+ if ((i == FFEINFO_basictypeANY) || (j == FFEINFO_basictypeANY))
+ ffeinfo_combine_[i][j] = FFEINFO_basictypeANY;
+ else
+ ffeinfo_combine_[i][j] = FFEINFO_basictypeNONE;
+
+#define same(bt) ffeinfo_combine_[bt][bt] = bt
+#define use2(bt1,bt2) ffeinfo_combine_[bt1][bt2] \
+ = ffeinfo_combine_[bt2][bt1] = bt2
+
+ same (FFEINFO_basictypeINTEGER);
+ same (FFEINFO_basictypeLOGICAL);
+ same (FFEINFO_basictypeREAL);
+ same (FFEINFO_basictypeCOMPLEX);
+ same (FFEINFO_basictypeCHARACTER);
+ use2 (FFEINFO_basictypeINTEGER, FFEINFO_basictypeREAL);
+ use2 (FFEINFO_basictypeINTEGER, FFEINFO_basictypeCOMPLEX);
+ use2 (FFEINFO_basictypeREAL, FFEINFO_basictypeCOMPLEX);
+
+#undef same
+#undef use2
+}
+
+/* ffeinfo_kind_message -- Return helpful string showing the kind
+
+ ffeinfoKind kind;
+ printf("%s",ffeinfo_kind_message(kind));
+
+ Returns the string based on the kind. */
+
+char *
+ffeinfo_kind_message (ffeinfoKind kind)
+{
+ if (kind >= ARRAY_SIZE (ffeinfo_kind_message_))
+ return "?\?\?";
+ return ffeinfo_kind_message_[kind];
+}
+
+/* ffeinfo_kind_string -- Return tiny string showing the kind
+
+ ffeinfoKind kind;
+ printf("%s",ffeinfo_kind_string(kind));
+
+ Returns the string based on the kind. */
+
+char *
+ffeinfo_kind_string (ffeinfoKind kind)
+{
+ if (kind >= ARRAY_SIZE (ffeinfo_kind_string_))
+ return "?\?\?";
+ return ffeinfo_kind_string_[kind];
+}
+
+ffeinfoKindtype
+ffeinfo_kindtype_max(ffeinfoBasictype bt,
+ ffeinfoKindtype k1,
+ ffeinfoKindtype k2)
+{
+ if ((bt == FFEINFO_basictypeANY)
+ || (k1 == FFEINFO_kindtypeANY)
+ || (k2 == FFEINFO_kindtypeANY))
+ return FFEINFO_kindtypeANY;
+
+ if (ffetype_size (ffeinfo_types_[bt][k1])
+ > ffetype_size (ffeinfo_types_[bt][k2]))
+ return k1;
+ return k2;
+}
+
+/* ffeinfo_kindtype_string -- Return tiny string showing the kind type
+
+ ffeinfoKindtype kind_type;
+ printf("%s",ffeinfo_kindtype_string(kind));
+
+ Returns the string based on the kind type. */
+
+char *
+ffeinfo_kindtype_string (ffeinfoKindtype kind_type)
+{
+ if (kind_type >= ARRAY_SIZE (ffeinfo_kindtype_string_))
+ return "?\?\?";
+ return ffeinfo_kindtype_string_[kind_type];
+}
+
+void
+ffeinfo_set_type (ffeinfoBasictype basictype, ffeinfoKindtype kindtype,
+ ffetype type)
+{
+ assert (basictype < FFEINFO_basictype);
+ assert (kindtype < FFEINFO_kindtype);
+ assert (ffeinfo_types_[basictype][kindtype] == NULL);
+
+ ffeinfo_types_[basictype][kindtype] = type;
+}
+
+ffetype
+ffeinfo_type (ffeinfoBasictype basictype, ffeinfoKindtype kindtype)
+{
+ assert (basictype < FFEINFO_basictype);
+ assert (kindtype < FFEINFO_kindtype);
+
+ return ffeinfo_types_[basictype][kindtype];
+}
+
+/* ffeinfo_where_string -- Return tiny string showing the where
+
+ ffeinfoWhere where;
+ printf("%s",ffeinfo_where_string(where));
+
+ Returns the string based on the where. */
+
+char *
+ffeinfo_where_string (ffeinfoWhere where)
+{
+ if (where >= ARRAY_SIZE (ffeinfo_where_string_))
+ return "?\?\?";
+ return ffeinfo_where_string_[where];
+}
+
+/* ffeinfo_new -- Return object representing datatype, kind, and where info
+
+ ffeinfo i;
+ i = ffeinfo_new(FFEINFO_datatypeINTEGER,FFEINFO_kindSCALAR,
+ FFEINFO_whereLOCAL);
+
+ Returns the string based on the data type. */
+
+#ifndef __GNUC__
+ffeinfo
+ffeinfo_new (ffeinfoBasictype basictype, ffeinfoKindtype kindtype,
+ ffeinfoRank rank, ffeinfoKind kind, ffeinfoWhere where,
+ ffetargetCharacterSize size)
+{
+ ffeinfo i;
+
+ i.basictype = basictype;
+ i.kindtype = kindtype;
+ i.rank = rank;
+ i.size = size;
+ i.kind = kind;
+ i.where = where;
+ i.size = size;
+
+ return i;
+}
+#endif
diff --git a/contrib/gcc/f/info.h b/contrib/gcc/f/info.h
new file mode 100644
index 0000000..8eaaa5d
--- /dev/null
+++ b/contrib/gcc/f/info.h
@@ -0,0 +1,186 @@
+/* info.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ info.c
+
+ Modifications:
+ 30-Aug-90 JCB 2.0
+ Extensive rewrite for new cleaner approach.
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_info
+#define _H_f_info
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+#define FFEINFO_BASICTYPE(KWD,LNAM,SNAM) KWD,
+#include "info-b.def"
+#undef FFEINFO_BASICTYPE
+ FFEINFO_basictype
+ } ffeinfoBasictype;
+
+typedef enum
+ { /* If these kindtypes aren't in size order,
+ change _kindtype_max. */
+ FFEINFO_kindtypeNONE,
+ FFEINFO_kindtypeINTEGER1,
+ FFEINFO_kindtypeINTEGER2,
+ FFEINFO_kindtypeINTEGER3,
+ FFEINFO_kindtypeINTEGER4,
+ FFEINFO_kindtypeINTEGER5,
+ FFEINFO_kindtypeINTEGER6,
+ FFEINFO_kindtypeINTEGER7,
+ FFEINFO_kindtypeINTEGER8,
+ FFEINFO_kindtypeLOGICAL1 = 1, /* Ok to omit, but ok to overlap. */
+ FFEINFO_kindtypeLOGICAL2,
+ FFEINFO_kindtypeLOGICAL3,
+ FFEINFO_kindtypeLOGICAL4,
+ FFEINFO_kindtypeLOGICAL5,
+ FFEINFO_kindtypeLOGICAL6,
+ FFEINFO_kindtypeLOGICAL7,
+ FFEINFO_kindtypeLOGICAL8,
+ FFEINFO_kindtypeREAL1 = 1, /* Ok to omit, but ok to overlap. */
+ FFEINFO_kindtypeREAL2,
+ FFEINFO_kindtypeREAL3,
+ FFEINFO_kindtypeREAL4,
+ FFEINFO_kindtypeREAL5,
+ FFEINFO_kindtypeREAL6,
+ FFEINFO_kindtypeREAL7,
+ FFEINFO_kindtypeREAL8,
+ FFEINFO_kindtypeCHARACTER1 = 1, /* Ok to omit, but ok to overlap. */
+ FFEINFO_kindtypeCHARACTER2,
+ FFEINFO_kindtypeCHARACTER3,
+ FFEINFO_kindtypeCHARACTER4,
+ FFEINFO_kindtypeCHARACTER5,
+ FFEINFO_kindtypeCHARACTER6,
+ FFEINFO_kindtypeCHARACTER7,
+ FFEINFO_kindtypeCHARACTER8,
+ FFEINFO_kindtypeANY,
+ FFEINFO_kindtype
+ } ffeinfoKindtype;
+
+typedef enum
+ {
+#define FFEINFO_KIND(KWD,LNAM,SNAM) KWD,
+#include "info-k.def"
+#undef FFEINFO_KIND
+ FFEINFO_kind
+ } ffeinfoKind;
+
+typedef enum
+ {
+#define FFEINFO_WHERE(KWD,LNAM,SNAM) KWD,
+#include "info-w.def"
+#undef FFEINFO_WHERE
+ FFEINFO_where
+ } ffeinfoWhere;
+
+/* Typedefs. */
+
+typedef struct _ffeinfo_ ffeinfo;
+typedef char ffeinfoRank;
+
+/* Include files needed by this one. */
+
+#include "target.h"
+#include "type.h"
+
+/* Structure definitions. */
+
+struct _ffeinfo_
+ {
+ ffeinfoBasictype basictype;
+ ffeinfoKindtype kindtype;
+ ffeinfoRank rank;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+ ffetargetCharacterSize size;
+ };
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+ffeinfoBasictype ffeinfo_basictype_combine (ffeinfoBasictype l,
+ ffeinfoBasictype r);
+char *ffeinfo_basictype_string (ffeinfoBasictype basictype);
+void ffeinfo_init_0 (void);
+char *ffeinfo_kind_message (ffeinfoKind kind);
+char *ffeinfo_kind_string (ffeinfoKind kind);
+ffeinfoKindtype ffeinfo_kindtype_max(ffeinfoBasictype bt,
+ ffeinfoKindtype k1,
+ ffeinfoKindtype k2);
+char *ffeinfo_kindtype_string (ffeinfoKindtype kind_type);
+char *ffeinfo_where_string (ffeinfoWhere where);
+ffeinfo ffeinfo_new (ffeinfoBasictype basictype, ffeinfoKindtype kindtype,
+ ffeinfoRank rank, ffeinfoKind kind, ffeinfoWhere where,
+ ffetargetCharacterSize size);
+void ffeinfo_set_type (ffeinfoBasictype basictype, ffeinfoKindtype kindtype,
+ ffetype type);
+ffetype ffeinfo_type (ffeinfoBasictype basictype, ffeinfoKindtype kindtype);
+
+/* Define macros. */
+
+#define ffeinfo_basictype(i) (i.basictype)
+#define ffeinfo_init_1()
+#define ffeinfo_init_2()
+#define ffeinfo_init_3()
+#define ffeinfo_init_4()
+#define ffeinfo_kind(i) (i.kind)
+#define ffeinfo_kindtype(i) (i.kindtype)
+#ifdef __GNUC__
+#define ffeinfo_new(bt,kt,r,k,w,sz) \
+ ((ffeinfo) {(bt), (kt), (r), (k), (w), (sz)})
+#endif
+#define ffeinfo_new_any() \
+ ffeinfo_new (FFEINFO_basictypeANY, FFEINFO_kindtypeANY, 0, \
+ FFEINFO_kindANY, FFEINFO_whereANY, \
+ FFETARGET_charactersizeNONE)
+#define ffeinfo_new_null() \
+ ffeinfo_new (FFEINFO_basictypeNONE, FFEINFO_kindtypeNONE, 0, \
+ FFEINFO_kindNONE, FFEINFO_whereNONE, \
+ FFETARGET_charactersizeNONE)
+#define ffeinfo_rank(i) (i.rank)
+#define ffeinfo_size(i) (i.size)
+#define ffeinfo_terminate_0()
+#define ffeinfo_terminate_1()
+#define ffeinfo_terminate_2()
+#define ffeinfo_terminate_3()
+#define ffeinfo_terminate_4()
+#define ffeinfo_use(i) i
+#define ffeinfo_where(i) (i.where)
+
+#define FFEINFO_kindtypeINTEGERDEFAULT FFEINFO_kindtypeINTEGER1
+#define FFEINFO_kindtypeLOGICALDEFAULT FFEINFO_kindtypeLOGICAL1
+#define FFEINFO_kindtypeREALDEFAULT FFEINFO_kindtypeREAL1
+#define FFEINFO_kindtypeREALDOUBLE FFEINFO_kindtypeREAL2
+#define FFEINFO_kindtypeREALQUAD FFEINFO_kindtypeREAL3
+#define FFEINFO_kindtypeCHARACTERDEFAULT FFEINFO_kindtypeCHARACTER1
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/input.j b/contrib/gcc/f/input.j
new file mode 100644
index 0000000..1444de2
--- /dev/null
+++ b/contrib/gcc/f/input.j
@@ -0,0 +1,27 @@
+/* input.j -- Wrapper for GCC's input.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_input
+#define _J_f_input
+#include "input.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/intdoc.c b/contrib/gcc/f/intdoc.c
new file mode 100644
index 0000000..0ac39ff
--- /dev/null
+++ b/contrib/gcc/f/intdoc.c
@@ -0,0 +1,1336 @@
+/* intdoc.c
+ Copyright (C) 1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+/* From f/proj.h, which uses #error -- not all C compilers
+ support that, and we want *this* program to be compilable
+ by pretty much any C compiler. */
+#include "hconfig.j"
+#include "system.j"
+#include "assert.j"
+#if HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+typedef enum
+ {
+#if !defined(false) || !defined(true)
+ false = 0, true = 1,
+#endif
+#if !defined(FALSE) || !defined(TRUE)
+ FALSE = 0, TRUE = 1,
+#endif
+ Doggone_Trailing_Comma_Dont_Work = 1
+ } bool;
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+/* Pull in the intrinsics info, but only the doc parts. */
+#define FFEINTRIN_DOC 1
+#include "intrin.h"
+
+char *family_name (ffeintrinFamily family);
+static void dumpif (ffeintrinFamily fam);
+static void dumpendif (void);
+static void dumpclearif (void);
+static void dumpem (void);
+static void dumpgen (int menu, char *name, char *name_uc,
+ ffeintrinGen gen);
+static void dumpspec (int menu, char *name, char *name_uc,
+ ffeintrinSpec spec);
+static void dumpimp (int menu, char *name, char *name_uc, size_t genno, ffeintrinFamily family,
+ ffeintrinImp imp, ffeintrinSpec spec);
+static char *argument_info_ptr (ffeintrinImp imp, int argno);
+static char *argument_info_string (ffeintrinImp imp, int argno);
+static char *argument_name_ptr (ffeintrinImp imp, int argno);
+static char *argument_name_string (ffeintrinImp imp, int argno);
+#if 0
+static char *elaborate_if_complex (ffeintrinImp imp, int argno);
+static char *elaborate_if_maybe_complex (ffeintrinImp imp, int argno);
+static char *elaborate_if_real (ffeintrinImp imp, int argno);
+#endif
+static void print_type_string (char *c);
+
+int
+main (int argc, char **argv)
+{
+ if (argc != 1)
+ {
+ fprintf (stderr, "\
+Usage: intdoc > intdoc.texi\n\
+ Collects and dumps documentation on g77 intrinsics\n\
+ to the file named intdoc.texi.\n");
+ exit (1);
+ }
+
+ dumpem ();
+ return 0;
+}
+
+struct _ffeintrin_name_
+ {
+ char *name_uc;
+ char *name_lc;
+ char *name_ic;
+ ffeintrinGen generic;
+ ffeintrinSpec specific;
+ };
+
+struct _ffeintrin_gen_
+ {
+ char *name; /* Name as seen in program. */
+ ffeintrinSpec specs[2];
+ };
+
+struct _ffeintrin_spec_
+ {
+ char *name; /* Uppercase name as seen in source code,
+ lowercase if no source name, "none" if no
+ name at all (NONE case). */
+ bool is_actualarg; /* Ok to pass as actual arg if -pedantic. */
+ ffeintrinFamily family;
+ ffeintrinImp implementation;
+ };
+
+struct _ffeintrin_imp_
+ {
+ char *name; /* Name of implementation. */
+#if 0 /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+ ffecomGfrt gfrt; /* gfrt index in library. */
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+ char *control;
+ };
+
+static struct _ffeintrin_name_ names[] = {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC) \
+ { UPPER, LOWER, MIXED, FFEINTRIN_ ## GEN, FFEINTRIN_ ## SPEC },
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+static struct _ffeintrin_gen_ gens[] = {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2) \
+ { NAME, { SPEC1, SPEC2, }, },
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+static struct _ffeintrin_imp_ imps[] = {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#if 0 /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL) \
+ { NAME, FFECOM_gfrt ## GFRT, CONTROL },
+#elif 1 /* FFECOM_targetCURRENT == FFECOM_targetFFE */
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL) \
+ { NAME, CONTROL },
+#else
+#error
+#endif
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+static struct _ffeintrin_spec_ specs[] = {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP) \
+ { NAME, CALLABLE, FAMILY, IMP, },
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+struct cc_pair { ffeintrinImp imp; char *text; };
+
+static char *descriptions[FFEINTRIN_imp] = { 0 };
+static struct cc_pair cc_descriptions[] = {
+#define DEFDOC(IMP,SUMMARY,DESCRIPTION) { FFEINTRIN_imp ## IMP, DESCRIPTION },
+#include "intdoc.h0"
+#undef DEFDOC
+};
+
+static char *summaries[FFEINTRIN_imp] = { 0 };
+static struct cc_pair cc_summaries[] = {
+#define DEFDOC(IMP,SUMMARY,DESCRIPTION) { FFEINTRIN_imp ## IMP, SUMMARY },
+#include "intdoc.h0"
+#undef DEFDOC
+};
+
+char *
+family_name (ffeintrinFamily family)
+{
+ switch (family)
+ {
+ case FFEINTRIN_familyF77:
+ return "familyF77";
+
+ case FFEINTRIN_familyASC:
+ return "familyASC";
+
+ case FFEINTRIN_familyMIL:
+ return "familyMIL";
+
+ case FFEINTRIN_familyGNU:
+ return "familyGNU";
+
+ case FFEINTRIN_familyF90:
+ return "familyF90";
+
+ case FFEINTRIN_familyVXT:
+ return "familyVXT";
+
+ case FFEINTRIN_familyFVZ:
+ return "familyFVZ";
+
+ case FFEINTRIN_familyF2C:
+ return "familyF2C";
+
+ case FFEINTRIN_familyF2U:
+ return "familyF2U";
+
+ case FFEINTRIN_familyBADU77:
+ return "familyBADU77";
+
+ default:
+ assert ("bad family" == NULL);
+ return "??";
+ }
+}
+
+static int in_ifset = 0;
+static ffeintrinFamily latest_family = FFEINTRIN_familyNONE;
+
+static void
+dumpif (ffeintrinFamily fam)
+{
+ assert (fam != FFEINTRIN_familyNONE);
+ if ((in_ifset != 2)
+ || (fam != latest_family))
+ {
+ if (in_ifset == 2)
+ printf ("@end ifset\n");
+ latest_family = fam;
+ printf ("@ifset %s\n", family_name (fam));
+ }
+ in_ifset = 1;
+}
+
+static void
+dumpendif ()
+{
+ in_ifset = 2;
+}
+
+static void
+dumpclearif ()
+{
+ if ((in_ifset == 2)
+ || (latest_family != FFEINTRIN_familyNONE))
+ printf ("@end ifset\n");
+ latest_family = FFEINTRIN_familyNONE;
+ in_ifset = 0;
+}
+
+static void
+dumpem ()
+{
+ int i;
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (cc_descriptions); ++i)
+ {
+ assert (descriptions[cc_descriptions[i].imp] == NULL);
+ descriptions[cc_descriptions[i].imp] = cc_descriptions[i].text;
+ }
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (cc_summaries); ++i)
+ {
+ assert (summaries[cc_summaries[i].imp] == NULL);
+ summaries[cc_summaries[i].imp] = cc_summaries[i].text;
+ }
+
+ printf ("@c This file is automatically derived from intdoc.c, intdoc.in,\n");
+ printf ("@c ansify.c, intrin.def, and intrin.h. Edit those files instead.\n");
+ printf ("@menu\n");
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (names); ++i)
+ {
+ if (names[i].generic != FFEINTRIN_genNONE)
+ dumpgen (1, names[i].name_ic, names[i].name_uc,
+ names[i].generic);
+ if (names[i].specific != FFEINTRIN_specNONE)
+ dumpspec (1, names[i].name_ic, names[i].name_uc,
+ names[i].specific);
+ }
+ dumpclearif ();
+
+ printf ("@end menu\n\n");
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (names); ++i)
+ {
+ if (names[i].generic != FFEINTRIN_genNONE)
+ dumpgen (0, names[i].name_ic, names[i].name_uc,
+ names[i].generic);
+ if (names[i].specific != FFEINTRIN_specNONE)
+ dumpspec (0, names[i].name_ic, names[i].name_uc,
+ names[i].specific);
+ }
+ dumpclearif ();
+}
+
+static void
+dumpgen (int menu, char *name, char *name_uc, ffeintrinGen gen)
+{
+ size_t i;
+ int total = 0;
+
+ if (!menu)
+ {
+ for (i = 0; i < ARRAY_SIZE (gens[gen].specs); ++i)
+ {
+ if (gens[gen].specs[i] != FFEINTRIN_specNONE)
+ ++total;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE (gens[gen].specs); ++i)
+ {
+ ffeintrinSpec spec;
+ size_t j;
+
+ if ((spec = gens[gen].specs[i]) == FFEINTRIN_specNONE)
+ continue;
+
+ dumpif (specs[spec].family);
+ dumpimp (menu, name, name_uc, i, specs[spec].family, specs[spec].implementation,
+ spec);
+ if (!menu && (total > 0))
+ {
+ if (total == 1)
+ {
+ printf ("\
+For information on another intrinsic with the same name:\n");
+ }
+ else
+ {
+ printf ("\
+For information on other intrinsics with the same name:\n");
+ }
+ for (j = 0; j < ARRAY_SIZE (gens[gen].specs); ++j)
+ {
+ if (j == i)
+ continue;
+ if ((spec = gens[gen].specs[j]) == FFEINTRIN_specNONE)
+ continue;
+ printf ("@xref{%s Intrinsic (%s)}.\n",
+ name, specs[spec].name);
+ }
+ printf ("\n");
+ }
+ dumpendif ();
+ }
+}
+
+static void
+dumpspec (int menu, char *name, char *name_uc, ffeintrinSpec spec)
+{
+ dumpif (specs[spec].family);
+ dumpimp (menu, name, name_uc, 0, specs[spec].family, specs[spec].implementation,
+ FFEINTRIN_specNONE);
+ dumpendif ();
+}
+
+static void
+dumpimp (int menu, char *name, char *name_uc, size_t genno, ffeintrinFamily family, ffeintrinImp imp,
+ ffeintrinSpec spec)
+{
+ char *c;
+ bool subr;
+ char *argc;
+ char *argi;
+ int colon;
+ int argno;
+
+ assert ((imp != FFEINTRIN_impNONE) || !genno);
+
+ if (menu)
+ {
+ printf ("* %s Intrinsic",
+ name);
+ if (spec != FFEINTRIN_specNONE)
+ printf (" (%s)", specs[spec].name); /* See XYZZY1 below */
+ printf ("::");
+#define INDENT_SUMMARY 24
+ if ((imp == FFEINTRIN_impNONE)
+ || (summaries[imp] != NULL))
+ {
+ int spaces = INDENT_SUMMARY - 14 - strlen (name);
+ char *c;
+
+ if (spec != FFEINTRIN_specNONE)
+ spaces -= (3 + strlen (specs[spec].name)); /* See XYZZY1 above */
+ if (spaces < 1)
+ spaces = 1;
+ while (spaces--)
+ fputc (' ', stdout);
+
+ if (imp == FFEINTRIN_impNONE)
+ {
+ printf ("(Reserved for future use.)\n");
+ return;
+ }
+
+ for (c = summaries[imp]; c[0] != '\0'; ++c)
+ {
+ if ((c[0] == '@')
+ && (c[1] >= '0')
+ && (c[1] <= '9'))
+ {
+ int argno = c[1] - '0';
+
+ c += 2;
+ while ((c[0] >= '0')
+ && (c[0] <= '9'))
+ {
+ argno = 10 * argno + (c[0] - '0');
+ ++c;
+ }
+ assert (c[0] == '@');
+ if (argno == 0)
+ printf ("%s", name);
+ else if (argno == 99)
+ { /* Yeah, this is a major kludge. */
+ printf ("\n");
+ spaces = INDENT_SUMMARY + 1;
+ while (spaces--)
+ fputc (' ', stdout);
+ }
+ else
+ printf ("%s", argument_name_string (imp, argno - 1));
+ }
+ else
+ fputc (c[0], stdout);
+ }
+ }
+ printf ("\n");
+ return;
+ }
+
+ printf ("@node %s Intrinsic", name);
+ if (spec != FFEINTRIN_specNONE)
+ printf (" (%s)", specs[spec].name);
+ printf ("\n@subsubsection %s Intrinsic", name);
+ if (spec != FFEINTRIN_specNONE)
+ printf (" (%s)", specs[spec].name);
+ printf ("\n@cindex %s intrinsic\n@cindex intrinsics, %s\n",
+ name, name);
+
+ if (imp == FFEINTRIN_impNONE)
+ {
+ printf ("\n\
+This intrinsic is not yet implemented.\n\
+The name is, however, reserved as an intrinsic.\n\
+Use @samp{EXTERNAL %s} to use this name for an\n\
+external procedure.\n\
+\n\
+",
+ name);
+ return;
+ }
+
+ c = imps[imp].control;
+ subr = (c[0] == '-');
+ colon = (c[2] == ':') ? 2 : 3;
+
+ printf ("\n\
+@noindent\n\
+@example\n\
+%s%s(",
+ (subr ? "CALL " : ""), name);
+
+ fflush (stdout);
+
+ for (argno = 0; ; ++argno)
+ {
+ argc = argument_name_ptr (imp, argno);
+ if (argc == NULL)
+ break;
+ if (argno > 0)
+ printf (", ");
+ printf ("@var{%s}", argc);
+ argi = argument_info_string (imp, argno);
+ if ((argi[0] == '*')
+ || (argi[0] == 'n')
+ || (argi[0] == '+')
+ || (argi[0] == 'p'))
+ printf ("-1, @var{%s}-2, @dots{}, @var{%s}-n",
+ argc, argc);
+ }
+
+ printf (")\n\
+@end example\n\
+\n\
+");
+
+ if (!subr)
+ {
+ int other_arg;
+ char *arg_string;
+ char *arg_info;
+
+ if ((c[colon + 1] >= '0')
+ && (c[colon + 1] <= '9'))
+ {
+ other_arg = c[colon + 1] - '0';
+ arg_string = argument_name_string (imp, other_arg);
+ arg_info = argument_info_string (imp, other_arg);
+ }
+ else
+ {
+ other_arg = -1;
+ arg_string = NULL;
+ arg_info = NULL;
+ }
+
+ printf ("\
+@noindent\n\
+%s: ", name);
+ print_type_string (c);
+ printf (" function");
+
+ if ((c[0] == 'R')
+ && (c[1] == 'C'))
+ {
+ assert (other_arg >= 0);
+
+ if ((arg_info[0] == '?') || (arg_info[0] == '!') || (arg_info[0] == '+')
+ || (arg_info[0] == '*') || (arg_info[0] == 'n') || (arg_info[0] == 'p'))
+ ++arg_info;
+ if ((arg_info[0] == 'F') || (arg_info[0] == 'N'))
+ printf (".\n\
+The exact type is @samp{REAL(KIND=1)} when argument @var{%s} is\n\
+any type other than @code{COMPLEX}, or when it is @code{COMPLEX(KIND=1)}.\n\
+When @var{%s} is any @code{COMPLEX} type other than @code{COMPLEX(KIND=1)},\n\
+this intrinsic is valid only when used as the argument to\n\
+@code{REAL()}, as explained below.\n\n",
+ arg_string,
+ arg_string);
+ else
+ printf (".\n\
+This intrinsic is valid when argument @var{%s} is\n\
+@code{COMPLEX(KIND=1)}.\n\
+When @var{%s} is any other @code{COMPLEX} type,\n\
+this intrinsic is valid only when used as the argument to\n\
+@code{REAL()}, as explained below.\n\n",
+ arg_string,
+ arg_string);
+ }
+#if 0
+ else if ((c[0] == 'I')
+ && (c[1] == '7'))
+ printf (", the exact type being wide enough to hold a pointer\n\
+on the target system (typically @code{INTEGER(KIND=1)} or @code{INTEGER(KIND=4)}).\n\n");
+#endif
+ else if ((c[1] == '=')
+ && (c[colon + 1] >= '0')
+ && (c[colon + 1] <= '9'))
+ {
+ assert (other_arg >= 0);
+
+ if ((arg_info[0] == '?') || (arg_info[0] == '!') || (arg_info[0] == '+')
+ || (arg_info[0] == '*') || (arg_info[0] == 'n') || (arg_info[0] == 'p'))
+ ++arg_info;
+
+ if (((c[0] == arg_info[0])
+ && ((c[0] == 'A') || (c[0] == 'C') || (c[0] == 'I')
+ || (c[0] == 'L') || (c[0] == 'R')))
+ || ((c[0] == 'R')
+ && (arg_info[0] == 'C'))
+ || ((c[0] == 'C')
+ && (arg_info[0] == 'R')))
+ printf (", the @samp{KIND=} value of the type being that of argument @var{%s}.\n\n",
+ arg_string);
+ else if ((c[0] == 'S')
+ && ((arg_info[0] == 'C')
+ || (arg_info[0] == 'F')
+ || (arg_info[0] == 'N')))
+ printf (".\n\
+The exact type depends on that of argument @var{%s}---if @var{%s} is\n\
+@code{COMPLEX}, this function's type is @code{REAL}\n\
+with the same @samp{KIND=} value as the type of @var{%s}.\n\
+Otherwise, this function's type is the same as that of @var{%s}.\n\n",
+ arg_string, arg_string, arg_string, arg_string);
+ else
+ printf (", the exact type being that of argument @var{%s}.\n\n",
+ arg_string);
+ }
+ else if ((c[1] == '=')
+ && (c[colon + 1] == '*'))
+ printf (", the exact type being the result of cross-promoting the\n\
+types of all the arguments.\n\n");
+ else if (c[1] == '=')
+ assert ("?0:?:" == NULL);
+ else
+ printf (".\n\n");
+ }
+
+ for (argno = 0, argc = &c[colon + 3]; *argc != '\0'; ++argno)
+ {
+ char optionality = '\0';
+ char extra = '\0';
+ char basic;
+ char kind;
+ int length;
+ int elements;
+
+ printf ("\
+@noindent\n\
+@var{");
+ for (; ; ++argc)
+ {
+ if (argc[0] == '=')
+ break;
+ printf ("%c", *argc);
+ }
+ printf ("}: ");
+
+ ++argc;
+ if ((*argc == '?')
+ || (*argc == '!')
+ || (*argc == '*')
+ || (*argc == '+')
+ || (*argc == 'n')
+ || (*argc == 'p'))
+ optionality = *(argc++);
+ basic = *(argc++);
+ kind = *(argc++);
+ if (*argc == '[')
+ {
+ length = *++argc - '0';
+ if (*++argc != ']')
+ length = 10 * length + (*(argc++) - '0');
+ ++argc;
+ }
+ else
+ length = -1;
+ if (*argc == '(')
+ {
+ elements = *++argc - '0';
+ if (*++argc != ')')
+ elements = 10 * elements + (*(argc++) - '0');
+ ++argc;
+ }
+ else if (*argc == '&')
+ {
+ elements = -1;
+ ++argc;
+ }
+ else
+ elements = 0;
+ if ((*argc == '&')
+ || (*argc == 'i')
+ || (*argc == 'w')
+ || (*argc == 'x'))
+ extra = *(argc++);
+ if (*argc == ',')
+ ++argc;
+
+ switch (basic)
+ {
+ case '-':
+ switch (kind)
+ {
+ case '*':
+ printf ("Any type");
+ break;
+
+ default:
+ assert ("kind arg" == NULL);
+ break;
+ }
+ break;
+
+ case 'A':
+ assert ((kind == '1') || (kind == '*'));
+ printf ("@code{CHARACTER");
+ if (length != -1)
+ printf ("*%d", length);
+ printf ("}");
+ break;
+
+ case 'C':
+ switch (kind)
+ {
+ case '*':
+ printf ("@code{COMPLEX}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{COMPLEX(KIND=%d)}", (kind - '0'));
+ break;
+
+ case 'A':
+ printf ("Same @samp{KIND=} value as for @var{%s}",
+ argument_name_string (imp, 0));
+ break;
+
+ default:
+ assert ("Ca" == NULL);
+ break;
+ }
+ break;
+
+ case 'I':
+ switch (kind)
+ {
+ case '*':
+ printf ("@code{INTEGER}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{INTEGER(KIND=%d)}", (kind - '0'));
+ break;
+
+ case 'A':
+ printf ("@code{INTEGER} with same @samp{KIND=} value as for @var{%s}",
+ argument_name_string (imp, 0));
+ break;
+
+ default:
+ assert ("Ia" == NULL);
+ break;
+ }
+ break;
+
+ case 'L':
+ switch (kind)
+ {
+ case '*':
+ printf ("@code{LOGICAL}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{LOGICAL(KIND=%d)}", (kind - '0'));
+ break;
+
+ case 'A':
+ printf ("@code{LOGICAL} with same @samp{KIND=} value as for @var{%s}",
+ argument_name_string (imp, 0));
+ break;
+
+ default:
+ assert ("La" == NULL);
+ break;
+ }
+ break;
+
+ case 'R':
+ switch (kind)
+ {
+ case '*':
+ printf ("@code{REAL}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{REAL(KIND=%d)}", (kind - '0'));
+ break;
+
+ case 'A':
+ printf ("@code{REAL} with same @samp{KIND=} value as for @var{%s}",
+ argument_name_string (imp, 0));
+ break;
+
+ default:
+ assert ("Ra" == NULL);
+ break;
+ }
+ break;
+
+ case 'B':
+ switch (kind)
+ {
+ case '*':
+ printf ("@code{INTEGER} or @code{LOGICAL}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{INTEGER(KIND=%d)} or @code{LOGICAL(KIND=%d)}",
+ (kind - '0'), (kind - '0'));
+ break;
+
+ case 'A':
+ printf ("Same type and @samp{KIND=} value as for @var{%s}",
+ argument_name_string (imp, 0));
+ break;
+
+ default:
+ assert ("Ba" == NULL);
+ break;
+ }
+ break;
+
+ case 'F':
+ switch (kind)
+ {
+ case '*':
+ printf ("@code{REAL} or @code{COMPLEX}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{REAL(KIND=%d)} or @code{COMPLEX(KIND=%d)}",
+ (kind - '0'), (kind - '0'));
+ break;
+
+ case 'A':
+ printf ("Same type as @var{%s}",
+ argument_name_string (imp, 0));
+ break;
+
+ default:
+ assert ("Fa" == NULL);
+ break;
+ }
+ break;
+
+ case 'N':
+ switch (kind)
+ {
+ case '*':
+ printf ("@code{INTEGER}, @code{REAL}, or @code{COMPLEX}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{INTEGER(KIND=%d)}, @code{REAL(KIND=%d)}, or @code{COMPLEX(KIND=%d)}",
+ (kind - '0'), (kind - '0'), (kind - '0'));
+ break;
+
+ default:
+ assert ("N1" == NULL);
+ break;
+ }
+ break;
+
+ case 'S':
+ switch (kind)
+ {
+ case '*':
+ printf ("@code{INTEGER} or @code{REAL}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{INTEGER(KIND=%d)} or @code{REAL(KIND=%d)}",
+ (kind - '0'), (kind - '0'));
+ break;
+
+ case 'A':
+ printf ("@code{INTEGER} or @code{REAL} with same @samp{KIND=} value as for @var{%s}",
+ argument_name_string (imp, 0));
+ break;
+
+ default:
+ assert ("Sa" == NULL);
+ break;
+ }
+ break;
+
+ case 'g':
+ printf ("@samp{*@var{label}}, where @var{label} is the label\n\
+of an executable statement");
+ break;
+
+ case 's':
+ printf ("Signal handler (@code{INTEGER FUNCTION} or @code{SUBROUTINE})\n\
+or dummy/global @code{INTEGER(KIND=1)} scalar");
+ break;
+
+ default:
+ assert ("arg type?" == NULL);
+ break;
+ }
+
+ switch (optionality)
+ {
+ case '\0':
+ break;
+
+ case '!':
+ printf ("; OPTIONAL (must be omitted if @var{%s} is @code{COMPLEX})",
+ argument_name_string (imp, argno-1));
+ break;
+
+ case '?':
+ printf ("; OPTIONAL");
+ break;
+
+ case '*':
+ printf ("; OPTIONAL");
+ break;
+
+ case 'n':
+ case '+':
+ break;
+
+ case 'p':
+ printf ("; at least two such arguments must be provided");
+ break;
+
+ default:
+ assert ("optionality!" == NULL);
+ break;
+ }
+
+ switch (elements)
+ {
+ case -1:
+ break;
+
+ case 0:
+ if ((basic != 'g')
+ && (basic != 's'))
+ printf ("; scalar");
+ break;
+
+ default:
+ assert (extra != '\0');
+ printf ("; DIMENSION(%d)", elements);
+ break;
+ }
+
+ switch (extra)
+ {
+ case '\0':
+ if ((basic != 'g')
+ && (basic != 's'))
+ printf ("; INTENT(IN)");
+ break;
+
+ case 'i':
+ break;
+
+ case '&':
+ printf ("; cannot be a constant or expression");
+ break;
+
+ case 'w':
+ printf ("; INTENT(OUT)");
+ break;
+
+ case 'x':
+ printf ("; INTENT(INOUT)");
+ break;
+ }
+
+ printf (".\n\n");
+ }
+
+ printf ("\
+@noindent\n\
+Intrinsic groups: ");
+ switch (family)
+ {
+ case FFEINTRIN_familyF77:
+ printf ("(standard FORTRAN 77).");
+ break;
+
+ case FFEINTRIN_familyGNU:
+ printf ("@code{gnu}.");
+ break;
+
+ case FFEINTRIN_familyASC:
+ printf ("@code{f2c}, @code{f90}.");
+ break;
+
+ case FFEINTRIN_familyMIL:
+ printf ("@code{mil}, @code{f90}, @code{vxt}.");
+ break;
+
+ case FFEINTRIN_familyF90:
+ printf ("@code{f90}.");
+ break;
+
+ case FFEINTRIN_familyVXT:
+ printf ("@code{vxt}.");
+ break;
+
+ case FFEINTRIN_familyFVZ:
+ printf ("@code{f2c}, @code{vxt}.");
+ break;
+
+ case FFEINTRIN_familyF2C:
+ printf ("@code{f2c}.");
+ break;
+
+ case FFEINTRIN_familyF2U:
+ printf ("@code{unix}.");
+ break;
+
+ case FFEINTRIN_familyBADU77:
+ printf ("@code{badu77}.");
+ break;
+
+ default:
+ assert ("bad family" == NULL);
+ printf ("@code{???}.");
+ break;
+ }
+ printf ("\n\n");
+
+ if (descriptions[imp] != NULL)
+ {
+ char *c = descriptions[imp];
+
+ printf ("\
+@noindent\n\
+Description:\n\
+\n");
+
+ while (c[0] != '\0')
+ {
+ if ((c[0] == '@')
+ && (c[1] >= '0')
+ && (c[1] <= '9'))
+ {
+ int argno = c[1] - '0';
+
+ c += 2;
+ while ((c[0] >= '0')
+ && (c[0] <= '9'))
+ {
+ argno = 10 * argno + (c[0] - '0');
+ ++c;
+ }
+ assert (c[0] == '@');
+ if (argno == 0)
+ printf ("%s", name_uc);
+ else
+ printf ("%s", argument_name_string (imp, argno - 1));
+ }
+ else
+ fputc (c[0], stdout);
+ ++c;
+ }
+
+ printf ("\n");
+ }
+}
+
+static char *
+argument_info_ptr (ffeintrinImp imp, int argno)
+{
+ char *c = imps[imp].control;
+ static char arginfos[8][32];
+ static int argx = 0;
+ int i;
+
+ if (c[2] == ':')
+ c += 5;
+ else
+ c += 6;
+
+ while (argno--)
+ {
+ while ((c[0] != ',') && (c[0] != '\0'))
+ ++c;
+ if (c[0] != ',')
+ break;
+ ++c;
+ }
+
+ if (c[0] == '\0')
+ return NULL;
+
+ for (; (c[0] != '=') && (c[0] != '\0'); ++c)
+ ;
+
+ assert (c[0] == '=');
+
+ for (i = 0, ++c; (c[0] != ',') && (c[0] != '\0'); ++c, ++i)
+ arginfos[argx][i] = c[0];
+
+ arginfos[argx][i] = '\0';
+
+ c = &arginfos[argx][0];
+ ++argx;
+ if (((size_t) argx) >= ARRAY_SIZE (arginfos))
+ argx = 0;
+
+ return c;
+}
+
+static char *
+argument_info_string (ffeintrinImp imp, int argno)
+{
+ char *p;
+
+ p = argument_info_ptr (imp, argno);
+ assert (p != NULL);
+ return p;
+}
+
+static char *
+argument_name_ptr (ffeintrinImp imp, int argno)
+{
+ char *c = imps[imp].control;
+ static char argnames[8][32];
+ static int argx = 0;
+ int i;
+
+ if (c[2] == ':')
+ c += 5;
+ else
+ c += 6;
+
+ while (argno--)
+ {
+ while ((c[0] != ',') && (c[0] != '\0'))
+ ++c;
+ if (c[0] != ',')
+ break;
+ ++c;
+ }
+
+ if (c[0] == '\0')
+ return NULL;
+
+ for (i = 0; (c[0] != '=') && (c[0] != '\0'); ++c, ++i)
+ argnames[argx][i] = c[0];
+
+ assert (c[0] == '=');
+ argnames[argx][i] = '\0';
+
+ c = &argnames[argx][0];
+ ++argx;
+ if (((size_t) argx) >= ARRAY_SIZE (argnames))
+ argx = 0;
+
+ return c;
+}
+
+static char *
+argument_name_string (ffeintrinImp imp, int argno)
+{
+ char *p;
+
+ p = argument_name_ptr (imp, argno);
+ assert (p != NULL);
+ return p;
+}
+
+static void
+print_type_string (char *c)
+{
+ char basic = c[0];
+ char kind = c[1];
+
+ switch (basic)
+ {
+ case 'A':
+ assert ((kind == '1') || (kind == '='));
+ if (c[2] == ':')
+ printf ("@code{CHARACTER*1}");
+ else
+ {
+ assert (c[2] == '*');
+ printf ("@code{CHARACTER*(*)}");
+ }
+ break;
+
+ case 'C':
+ switch (kind)
+ {
+ case '=':
+ printf ("@code{COMPLEX}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{COMPLEX(KIND=%d)}", (kind - '0'));
+ break;
+
+ default:
+ assert ("Ca" == NULL);
+ break;
+ }
+ break;
+
+ case 'I':
+ switch (kind)
+ {
+ case '=':
+ printf ("@code{INTEGER}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{INTEGER(KIND=%d)}", (kind - '0'));
+ break;
+
+ default:
+ assert ("Ia" == NULL);
+ break;
+ }
+ break;
+
+ case 'L':
+ switch (kind)
+ {
+ case '=':
+ printf ("@code{LOGICAL}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{LOGICAL(KIND=%d)}", (kind - '0'));
+ break;
+
+ default:
+ assert ("La" == NULL);
+ break;
+ }
+ break;
+
+ case 'R':
+ switch (kind)
+ {
+ case '=':
+ printf ("@code{REAL}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{REAL(KIND=%d)}", (kind - '0'));
+ break;
+
+ case 'C':
+ printf ("@code{REAL}");
+ break;
+
+ default:
+ assert ("Ra" == NULL);
+ break;
+ }
+ break;
+
+ case 'B':
+ switch (kind)
+ {
+ case '=':
+ printf ("@code{INTEGER} or @code{LOGICAL}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{INTEGER(KIND=%d)} or @code{LOGICAL(KIND=%d)}",
+ (kind - '0'), (kind - '0'));
+ break;
+
+ default:
+ assert ("Ba" == NULL);
+ break;
+ }
+ break;
+
+ case 'F':
+ switch (kind)
+ {
+ case '=':
+ printf ("@code{REAL} or @code{COMPLEX}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{REAL(KIND=%d)} or @code{COMPLEX(KIND=%d)}",
+ (kind - '0'), (kind - '0'));
+ break;
+
+ default:
+ assert ("Fa" == NULL);
+ break;
+ }
+ break;
+
+ case 'N':
+ switch (kind)
+ {
+ case '=':
+ printf ("@code{INTEGER}, @code{REAL}, or @code{COMPLEX}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{INTEGER(KIND=%d)}, @code{REAL(KIND=%d)}, or @code{COMPLEX(KIND=%d)}",
+ (kind - '0'), (kind - '0'), (kind - '0'));
+ break;
+
+ default:
+ assert ("N1" == NULL);
+ break;
+ }
+ break;
+
+ case 'S':
+ switch (kind)
+ {
+ case '=':
+ printf ("@code{INTEGER} or @code{REAL}");
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ printf ("@code{INTEGER(KIND=%d)} or @code{REAL(KIND=%d)}",
+ (kind - '0'), (kind - '0'));
+ break;
+
+ default:
+ assert ("Sa" == NULL);
+ break;
+ }
+ break;
+
+ default:
+ assert ("type?" == NULL);
+ break;
+ }
+}
diff --git a/contrib/gcc/f/intdoc.in b/contrib/gcc/f/intdoc.in
new file mode 100644
index 0000000..203dd61
--- /dev/null
+++ b/contrib/gcc/f/intdoc.in
@@ -0,0 +1,2519 @@
+/* Copyright (C) 1997, 1999 Free Software Foundation, Inc.
+ * This is part of the G77 manual.
+ * For copying conditions, see the file g77.texi. */
+
+/* This is the file containing the verbage for the
+ intrinsics. It consists of a data base built up
+ via DEFDOC macros of the form:
+
+ DEFDOC (IMP, SUMMARY, DESCRIPTION)
+
+ IMP is the implementation keyword used in the intrin module.
+ SUMMARY is the short summary to go in the "* Menu:" section
+ of the Info document. DESCRIPTION is the longer description
+ to go in the documentation itself.
+
+ Note that IMP is leveraged across multiple intrinsic names.
+
+ To make for more accurate and consistent documentation,
+ the translation made by intdoc.c of the text in SUMMARY
+ and DESCRIPTION includes the special sequence
+
+ @ARGNO@
+
+ where ARGNO is a series of digits forming a number that
+ is substituted by intdoc.c as follows:
+
+ 0 The initial-caps form of the intrinsic name (e.g. Float).
+ 1-98 The initial-caps form of the ARGNO'th argument.
+ 99 (SUMMARY only) a newline plus the appropriate # of spaces.
+
+ Hope this info is enough to encourage people to feel free to
+ add documentation to this file!
+
+*/
+
+#define ARCHAIC(upper,mixed) \
+ "Archaic form of @code{" #upper "()} that is specific\n\
+to one type for @var{@1@}.\n\
+@xref{" #mixed " Intrinsic}.\n"
+
+#define ARCHAIC_2nd(upper,mixed) \
+ "Archaic form of @code{" #upper "()} that is specific\n\
+to one type for @var{@2@}.\n\
+@xref{" #mixed " Intrinsic}.\n"
+
+#define ARCHAIC_2(upper,mixed) \
+ "Archaic form of @code{" #upper "()} that is specific\n\
+to one type for @var{@1@} and @var{@2@}.\n\
+@xref{" #mixed " Intrinsic}.\n"
+
+DEFDOC (ABS, "Absolute value.", "\
+Returns the absolute value of @var{@1@}.
+
+If @var{@1@} is type @code{COMPLEX}, the absolute
+value is computed as:
+
+@example
+SQRT(REALPART(@var{@1@})**2, IMAGPART(@var{@1@})**2)
+@end example
+
+@noindent
+Otherwise, it is computed by negating the @var{@1@} if
+it is negative, or returning @var{@1@}.
+
+@xref{Sign Intrinsic}, for how to explicitly
+compute the positive or negative form of the absolute
+value of an expression.
+")
+
+DEFDOC (CABS, "Absolute value (archaic).", ARCHAIC (ABS, Abs))
+
+DEFDOC (DABS, "Absolute value (archaic).", ARCHAIC (ABS, Abs))
+
+DEFDOC (IABS, "Absolute value (archaic).", ARCHAIC (ABS, Abs))
+
+DEFDOC (CDABS, "Absolute value (archaic).", ARCHAIC (ABS, Abs))
+
+DEFDOC (ACHAR, "ASCII character from code.", "\
+Returns the ASCII character corresponding to the
+code specified by @var{@1@}.
+
+@xref{IAChar Intrinsic}, for the inverse of this function.
+
+@xref{Char Intrinsic}, for the function corresponding
+to the system's native character set.
+")
+
+DEFDOC (IACHAR, "ASCII code for character.", "\
+Returns the code for the ASCII character in the
+first character position of @var{@1@}.
+
+@xref{AChar Intrinsic}, for the inverse of this function.
+
+@xref{IChar Intrinsic}, for the function corresponding
+to the system's native character set.
+")
+
+DEFDOC (CHAR, "Character from code.", "\
+Returns the character corresponding to the
+code specified by @var{@1@}, using the system's
+native character set.
+
+Because the system's native character set is used,
+the correspondence between character and their codes
+is not necessarily the same between GNU Fortran
+implementations.
+
+Note that no intrinsic exists to convert a numerical
+value to a printable character string.
+For example, there is no intrinsic that, given
+an @code{INTEGER} or @code{REAL} argument with the
+value @samp{154}, returns the @code{CHARACTER}
+result @samp{'154'}.
+
+Instead, you can use internal-file I/O to do this kind
+of conversion.
+For example:
+
+@smallexample
+INTEGER VALUE
+CHARACTER*10 STRING
+VALUE = 154
+WRITE (STRING, '(I10)'), VALUE
+PRINT *, STRING
+END
+@end smallexample
+
+The above program, when run, prints:
+
+@smallexample
+ 154
+@end smallexample
+
+@xref{IChar Intrinsic}, for the inverse of the @code{@0@} function.
+
+@xref{AChar Intrinsic}, for the function corresponding
+to the ASCII character set.
+")
+
+DEFDOC (ICHAR, "Code for character.", "\
+Returns the code for the character in the
+first character position of @var{@1@}.
+
+Because the system's native character set is used,
+the correspondence between character and their codes
+is not necessarily the same between GNU Fortran
+implementations.
+
+Note that no intrinsic exists to convert a printable
+character string to a numerical value.
+For example, there is no intrinsic that, given
+the @code{CHARACTER} value @samp{'154'}, returns an
+@code{INTEGER} or @code{REAL} value with the value @samp{154}.
+
+Instead, you can use internal-file I/O to do this kind
+of conversion.
+For example:
+
+@smallexample
+INTEGER VALUE
+CHARACTER*10 STRING
+STRING = '154'
+READ (STRING, '(I10)'), VALUE
+PRINT *, VALUE
+END
+@end smallexample
+
+The above program, when run, prints:
+
+@smallexample
+ 154
+@end smallexample
+
+@xref{Char Intrinsic}, for the inverse of the @code{@0@} function.
+
+@xref{IAChar Intrinsic}, for the function corresponding
+to the ASCII character set.
+")
+
+DEFDOC (ACOS, "Arc cosine.", "\
+Returns the arc-cosine (inverse cosine) of @var{@1@}
+in radians.
+
+@xref{Cos Intrinsic}, for the inverse of this function.
+")
+
+DEFDOC (DACOS, "Arc cosine (archaic).", ARCHAIC (ACOS, ACos))
+
+DEFDOC (AIMAG, "Convert/extract imaginary part of complex.", "\
+Returns the (possibly converted) imaginary part of @var{@1@}.
+
+Use of @code{@0@()} with an argument of a type
+other than @code{COMPLEX(KIND=1)} is restricted to the following case:
+
+@example
+REAL(AIMAG(@1@))
+@end example
+
+@noindent
+This expression converts the imaginary part of @1@ to
+@code{REAL(KIND=1)}.
+
+@xref{REAL() and AIMAG() of Complex}, for more information.
+")
+
+DEFDOC (DIMAG, "Convert/extract imaginary part of complex (archaic).", ARCHAIC (AIMAG, AImag))
+
+DEFDOC (AINT, "Truncate to whole number.", "\
+Returns @var{@1@} with the fractional portion of its
+magnitude truncated and its sign preserved.
+(Also called ``truncation towards zero''.)
+
+@xref{ANInt Intrinsic}, for how to round to nearest
+whole number.
+
+@xref{Int Intrinsic}, for how to truncate and then convert
+number to @code{INTEGER}.
+")
+
+DEFDOC (DINT, "Truncate to whole number (archaic).", ARCHAIC (AINT, AInt))
+
+DEFDOC (INT, "Convert to @code{INTEGER} value truncated@99@to whole number.", "\
+Returns @var{@1@} with the fractional portion of its
+magnitude truncated and its sign preserved, converted
+to type @code{INTEGER(KIND=1)}.
+
+If @var{@1@} is type @code{COMPLEX}, its real part is
+truncated and converted, and its imaginary part is disregarded.
+
+@xref{NInt Intrinsic}, for how to convert, rounded to nearest
+whole number.
+
+@xref{AInt Intrinsic}, for how to truncate to whole number
+without converting.
+")
+
+DEFDOC (IDINT, "Convert to @code{INTEGER} value truncated@99@to whole number (archaic).", ARCHAIC (INT, Int))
+
+DEFDOC (ANINT, "Round to nearest whole number.", "\
+Returns @var{@1@} with the fractional portion of its
+magnitude eliminated by rounding to the nearest whole
+number and with its sign preserved.
+
+A fractional portion exactly equal to
+@samp{.5} is rounded to the whole number that
+is larger in magnitude.
+(Also called ``Fortran round''.)
+
+@xref{AInt Intrinsic}, for how to truncate to
+whole number.
+
+@xref{NInt Intrinsic}, for how to round and then convert
+number to @code{INTEGER}.
+")
+
+DEFDOC (DNINT, "Round to nearest whole number (archaic).", ARCHAIC (ANINT, ANInt))
+
+DEFDOC (NINT, "Convert to @code{INTEGER} value rounded@99@to nearest whole number.", "\
+Returns @var{@1@} with the fractional portion of its
+magnitude eliminated by rounding to the nearest whole
+number and with its sign preserved, converted
+to type @code{INTEGER(KIND=1)}.
+
+If @var{@1@} is type @code{COMPLEX}, its real part is
+rounded and converted.
+
+A fractional portion exactly equal to
+@samp{.5} is rounded to the whole number that
+is larger in magnitude.
+(Also called ``Fortran round''.)
+
+@xref{Int Intrinsic}, for how to convert, truncate to
+whole number.
+
+@xref{ANInt Intrinsic}, for how to round to nearest whole number
+without converting.
+")
+
+DEFDOC (IDNINT, "Convert to @code{INTEGER} value rounded@99@to nearest whole number (archaic).", ARCHAIC (NINT, NInt))
+
+DEFDOC (LOG, "Natural logarithm.", "\
+Returns the natural logarithm of @var{@1@}, which must
+be greater than zero or, if type @code{COMPLEX}, must not
+be zero.
+
+@xref{Exp Intrinsic}, for the inverse of this function.
+
+@xref{Log10 Intrinsic}, for the `common' (base-10) logarithm function.
+")
+
+DEFDOC (ALOG, "Natural logarithm (archaic).", ARCHAIC (LOG, Log))
+
+DEFDOC (CLOG, "Natural logarithm (archaic).", ARCHAIC (LOG, Log))
+
+DEFDOC (DLOG, "Natural logarithm (archaic).", ARCHAIC (LOG, Log))
+
+DEFDOC (CDLOG, "Natural logarithm (archaic).", ARCHAIC (LOG, Log))
+
+DEFDOC (LOG10, "Common logarithm.", "\
+Returns the common logarithm (base 10) of @var{@1@}, which must
+be greater than zero.
+
+The inverse of this function is @samp{10. ** LOG10(@var{@1@})}.
+
+@xref{Log Intrinsic}, for the natural logarithm function.
+")
+
+DEFDOC (ALOG10, "Common logarithm (archaic).", ARCHAIC (LOG10, Log10))
+
+DEFDOC (DLOG10, "Common logarithm (archaic).", ARCHAIC (LOG10, Log10))
+
+DEFDOC (MAX, "Maximum value.", "\
+Returns the argument with the largest value.
+
+@xref{Min Intrinsic}, for the opposite function.
+")
+
+DEFDOC (AMAX0, "Maximum value (archaic).", "\
+Archaic form of @code{MAX()} that is specific
+to one type for @var{@1@} and a different return type.
+@xref{Max Intrinsic}.
+")
+
+DEFDOC (AMAX1, "Maximum value (archaic).", ARCHAIC (MAX, Max))
+
+DEFDOC (DMAX1, "Maximum value (archaic).", ARCHAIC (MAX, Max))
+
+DEFDOC (MAX0, "Maximum value (archaic).", ARCHAIC (MAX, Max))
+
+DEFDOC (MAX1, "Maximum value (archaic).", "\
+Archaic form of @code{MAX()} that is specific
+to one type for @var{@1@} and a different return type.
+@xref{Max Intrinsic}.
+")
+
+DEFDOC (MIN, "Minimum value.", "\
+Returns the argument with the smallest value.
+
+@xref{Max Intrinsic}, for the opposite function.
+")
+
+DEFDOC (AMIN0, "Minimum value (archaic).", "\
+Archaic form of @code{MIN()} that is specific
+to one type for @var{@1@} and a different return type.
+@xref{Min Intrinsic}.
+")
+
+DEFDOC (AMIN1, "Minimum value (archaic).", ARCHAIC (MIN, Min))
+
+DEFDOC (DMIN1, "Minimum value (archaic).", ARCHAIC (MIN, Min))
+
+DEFDOC (MIN0, "Minimum value (archaic).", ARCHAIC (MIN, Min))
+
+DEFDOC (MIN1, "Minimum value (archaic).", "\
+Archaic form of @code{MIN()} that is specific
+to one type for @var{@1@} and a different return type.
+@xref{Min Intrinsic}.
+")
+
+DEFDOC (MOD, "Remainder.", "\
+Returns remainder calculated as:
+
+@smallexample
+@var{@1@} - (INT(@var{@1@} / @var{@2@}) * @var{@2@})
+@end smallexample
+
+@var{@2@} must not be zero.
+")
+
+DEFDOC (AMOD, "Remainder (archaic).", ARCHAIC (MOD, Mod))
+
+DEFDOC (DMOD, "Remainder (archaic).", ARCHAIC (MOD, Mod))
+
+DEFDOC (AND, "Boolean AND.", "\
+Returns value resulting from boolean AND of
+pair of bits in each of @var{@1@} and @var{@2@}.
+")
+
+DEFDOC (IAND, "Boolean AND.", "\
+Returns value resulting from boolean AND of
+pair of bits in each of @var{@1@} and @var{@2@}.
+")
+
+DEFDOC (OR, "Boolean OR.", "\
+Returns value resulting from boolean OR of
+pair of bits in each of @var{@1@} and @var{@2@}.
+")
+
+DEFDOC (IOR, "Boolean OR.", "\
+Returns value resulting from boolean OR of
+pair of bits in each of @var{@1@} and @var{@2@}.
+")
+
+DEFDOC (XOR, "Boolean XOR.", "\
+Returns value resulting from boolean exclusive-OR of
+pair of bits in each of @var{@1@} and @var{@2@}.
+")
+
+DEFDOC (IEOR, "Boolean XOR.", "\
+Returns value resulting from boolean exclusive-OR of
+pair of bits in each of @var{@1@} and @var{@2@}.
+")
+
+DEFDOC (NOT, "Boolean NOT.", "\
+Returns value resulting from boolean NOT of each bit
+in @var{@1@}.
+")
+
+DEFDOC (ASIN, "Arc sine.", "\
+Returns the arc-sine (inverse sine) of @var{@1@}
+in radians.
+
+@xref{Sin Intrinsic}, for the inverse of this function.
+")
+
+DEFDOC (DASIN, "Arc sine (archaic).", ARCHAIC (ASIN, ASin))
+
+DEFDOC (ATAN, "Arc tangent.", "\
+Returns the arc-tangent (inverse tangent) of @var{@1@}
+in radians.
+
+@xref{Tan Intrinsic}, for the inverse of this function.
+")
+
+DEFDOC (DATAN, "Arc tangent (archaic).", ARCHAIC (ATAN, ATan))
+
+DEFDOC (ATAN2, "Arc tangent.", "\
+Returns the arc-tangent (inverse tangent) of the complex
+number (@var{@1@}, @var{@2@}) in radians.
+
+@xref{Tan Intrinsic}, for the inverse of this function.
+")
+
+DEFDOC (DATAN2, "Arc tangent (archaic).", ARCHAIC_2 (ATAN2, ATan2))
+
+DEFDOC (BIT_SIZE, "Number of bits in argument's type.", "\
+Returns the number of bits (integer precision plus sign bit)
+represented by the type for @var{@1@}.
+
+@xref{BTest Intrinsic}, for how to test the value of a
+bit in a variable or array.
+
+@xref{IBSet Intrinsic}, for how to set a bit in a variable to 1.
+
+@xref{IBClr Intrinsic}, for how to set a bit in a variable to 0.
+
+")
+
+DEFDOC (BTEST, "Test bit.", "\
+Returns @code{.TRUE.} if bit @var{@2@} in @var{@1@} is
+1, @code{.FALSE.} otherwise.
+
+(Bit 0 is the low-order (rightmost) bit, adding the value
+@ifinfo
+2**0,
+@end ifinfo
+@iftex
+@tex
+$2^0$,
+@end tex
+@end iftex
+or 1,
+to the number if set to 1;
+bit 1 is the next-higher-order bit, adding
+@ifinfo
+2**1,
+@end ifinfo
+@iftex
+@tex
+$2^1$,
+@end tex
+@end iftex
+or 2;
+bit 2 adds
+@ifinfo
+2**2,
+@end ifinfo
+@iftex
+@tex
+$2^2$,
+@end tex
+@end iftex
+or 4; and so on.)
+
+@xref{Bit_Size Intrinsic}, for how to obtain the number of bits
+in a type.
+The leftmost bit of @var{@1@} is @samp{BIT_SIZE(@var{@1@}-1)}.
+")
+
+DEFDOC (CMPLX, "Construct @code{COMPLEX(KIND=1)} value.", "\
+If @var{@1@} is not type @code{COMPLEX},
+constructs a value of type @code{COMPLEX(KIND=1)} from the
+real and imaginary values specified by @var{@1@} and
+@var{@2@}, respectively.
+If @var{@2@} is omitted, @samp{0.} is assumed.
+
+If @var{@1@} is type @code{COMPLEX},
+converts it to type @code{COMPLEX(KIND=1)}.
+
+@xref{Complex Intrinsic}, for information on easily constructing
+a @code{COMPLEX} value of arbitrary precision from @code{REAL}
+arguments.
+")
+
+DEFDOC (DCMPLX, "Construct @code{COMPLEX(KIND=2)} value.", "\
+If @var{@1@} is not type @code{COMPLEX},
+constructs a value of type @code{COMPLEX(KIND=2)} from the
+real and imaginary values specified by @var{@1@} and
+@var{@2@}, respectively.
+If @var{@2@} is omitted, @samp{0D0} is assumed.
+
+If @var{@1@} is type @code{COMPLEX},
+converts it to type @code{COMPLEX(KIND=2)}.
+
+Although this intrinsic is not standard Fortran,
+it is a popular extension offered by many compilers
+that support @code{DOUBLE COMPLEX}, since it offers
+the easiest way to convert to @code{DOUBLE COMPLEX}
+without using Fortran 90 features (such as the @samp{KIND=}
+argument to the @code{CMPLX()} intrinsic).
+
+(@samp{CMPLX(0D0, 0D0)} returns a single-precision
+@code{COMPLEX} result, as required by standard FORTRAN 77.
+That's why so many compilers provide @code{DCMPLX()}, since
+@samp{DCMPLX(0D0, 0D0)} returns a @code{DOUBLE COMPLEX}
+result.
+Still, @code{DCMPLX()} converts even @code{REAL*16} arguments
+to their @code{REAL*8} equivalents in most dialects of
+Fortran, so neither it nor @code{CMPLX()} allow easy
+construction of arbitrary-precision values without
+potentially forcing a conversion involving extending or
+reducing precision.
+GNU Fortran provides such an intrinsic, called @code{COMPLEX()}.)
+
+@xref{Complex Intrinsic}, for information on easily constructing
+a @code{COMPLEX} value of arbitrary precision from @code{REAL}
+arguments.
+")
+
+DEFDOC (CONJG, "Complex conjugate.", "\
+Returns the complex conjugate:
+
+@example
+COMPLEX(REALPART(@var{@1@}), -IMAGPART(@var{@1@}))
+@end example
+")
+
+DEFDOC (DCONJG, "Complex conjugate (archaic).", ARCHAIC (CONJG, Conjg))
+
+DEFDOC (COS, "Cosine.", "\
+Returns the cosine of @var{@1@}, an angle measured
+in radians.
+
+@xref{ACos Intrinsic}, for the inverse of this function.
+")
+
+DEFDOC (CCOS, "Cosine (archaic).", ARCHAIC (COS, Cos))
+
+DEFDOC (DCOS, "Cosine (archaic).", ARCHAIC (COS, Cos))
+
+DEFDOC (CDCOS, "Cosine (archaic).", ARCHAIC (COS, Cos))
+
+DEFDOC (COSH, "Hyperbolic cosine.", "\
+Returns the hyperbolic cosine of @var{@1@}.
+")
+
+DEFDOC (DCOSH, "Hyperbolic cosine (archaic).", ARCHAIC (COSH, CosH))
+
+DEFDOC (SQRT, "Square root.", "\
+Returns the square root of @var{@1@}, which must
+not be negative.
+
+To calculate and represent the square root of a negative
+number, complex arithmetic must be used.
+For example, @samp{SQRT(COMPLEX(@var{@1@}))}.
+
+The inverse of this function is @samp{SQRT(@var{@1@}) * SQRT(@var{@1@})}.
+")
+
+DEFDOC (CSQRT, "Square root (archaic).", ARCHAIC (SQRT, SqRt))
+
+DEFDOC (DSQRT, "Square root (archaic).", ARCHAIC (SQRT, SqRt))
+
+DEFDOC (CDSQRT, "Square root (archaic).", ARCHAIC (SQRT, SqRt))
+
+DEFDOC (DBLE, "Convert to double precision.", "\
+Returns @var{@1@} converted to double precision
+(@code{REAL(KIND=2)}).
+If @var{@1@} is @code{COMPLEX}, the real part of
+@var{@1@} is used for the conversion
+and the imaginary part disregarded.
+
+@xref{Sngl Intrinsic}, for the function that converts
+to single precision.
+
+@xref{Int Intrinsic}, for the function that converts
+to @code{INTEGER}.
+
+@xref{Complex Intrinsic}, for the function that converts
+to @code{COMPLEX}.
+")
+
+DEFDOC (DIM, "Difference magnitude (non-negative subtract).", "\
+Returns @samp{@var{@1@}-@var{@2@}} if @var{@1@} is greater than
+@var{@2@}; otherwise returns zero.
+")
+
+DEFDOC (DDIM, "Difference magnitude (archaic).", ARCHAIC_2 (DIM, DiM))
+DEFDOC (IDIM, "Difference magnitude (archaic).", ARCHAIC_2 (DIM, DiM))
+
+DEFDOC (DPROD, "Double-precision product.", "\
+Returns @samp{DBLE(@var{@1@})*DBLE(@var{@2@})}.
+")
+
+DEFDOC (EXP, "Exponential.", "\
+Returns @samp{@var{e}**@var{@1@}}, where
+@var{e} is approximately 2.7182818.
+
+@xref{Log Intrinsic}, for the inverse of this function.
+")
+
+DEFDOC (CEXP, "Exponential (archaic).", ARCHAIC (EXP, Exp))
+
+DEFDOC (DEXP, "Exponential (archaic).", ARCHAIC (EXP, Exp))
+
+DEFDOC (CDEXP, "Exponential (archaic).", ARCHAIC (EXP, Exp))
+
+DEFDOC (FLOAT, "Conversion (archaic).", ARCHAIC (REAL, Real))
+DEFDOC (DFLOAT, "Conversion (archaic).", ARCHAIC (REAL, Real))
+
+DEFDOC (IFIX, "Conversion (archaic).", ARCHAIC (INT, Int))
+
+DEFDOC (LONG, "Conversion to @code{INTEGER(KIND=1)} (archaic).", "\
+Archaic form of @code{INT()} that is specific
+to one type for @var{@1@}.
+@xref{Int Intrinsic}.
+
+The precise meaning of this intrinsic might change
+in a future version of the GNU Fortran language,
+as more is learned about how it is used.
+")
+
+DEFDOC (SHORT, "Convert to @code{INTEGER(KIND=6)} value@99@truncated to whole number.", "\
+Returns @var{@1@} with the fractional portion of its
+magnitude truncated and its sign preserved, converted
+to type @code{INTEGER(KIND=6)}.
+
+If @var{@1@} is type @code{COMPLEX}, its real part
+is truncated and converted, and its imaginary part is disgregarded.
+
+@xref{Int Intrinsic}.
+
+The precise meaning of this intrinsic might change
+in a future version of the GNU Fortran language,
+as more is learned about how it is used.
+")
+
+DEFDOC (INT2, "Convert to @code{INTEGER(KIND=6)} value@99@truncated to whole number.", "\
+Returns @var{@1@} with the fractional portion of its
+magnitude truncated and its sign preserved, converted
+to type @code{INTEGER(KIND=6)}.
+
+If @var{@1@} is type @code{COMPLEX}, its real part
+is truncated and converted, and its imaginary part is disgregarded.
+
+@xref{Int Intrinsic}.
+
+The precise meaning of this intrinsic might change
+in a future version of the GNU Fortran language,
+as more is learned about how it is used.
+")
+
+DEFDOC (INT8, "Convert to @code{INTEGER(KIND=2)} value@99@truncated to whole number.", "\
+Returns @var{@1@} with the fractional portion of its
+magnitude truncated and its sign preserved, converted
+to type @code{INTEGER(KIND=2)}.
+
+If @var{@1@} is type @code{COMPLEX}, its real part
+is truncated and converted, and its imaginary part is disgregarded.
+
+@xref{Int Intrinsic}.
+
+The precise meaning of this intrinsic might change
+in a future version of the GNU Fortran language,
+as more is learned about how it is used.
+")
+
+DEFDOC (LEN, "Length of character entity.", "\
+Returns the length of @var{@1@}.
+
+If @var{@1@} is an array, the length of an element
+of @var{@1@} is returned.
+
+Note that @var{@1@} need not be defined when this
+intrinsic is invoked, since only the length, not
+the content, of @var{@1@} is needed.
+
+@xref{Bit_Size Intrinsic}, for the function that determines
+the size of its argument in bits.
+")
+
+DEFDOC (TAN, "Tangent.", "\
+Returns the tangent of @var{@1@}, an angle measured
+in radians.
+
+@xref{ATan Intrinsic}, for the inverse of this function.
+")
+
+DEFDOC (DTAN, "Tangent (archaic).", ARCHAIC (TAN, Tan))
+
+DEFDOC (TANH, "Hyperbolic tangent.", "\
+Returns the hyperbolic tangent of @var{@1@}.
+")
+
+DEFDOC (DTANH, "Hyperbolic tangent (archaic).", ARCHAIC (TANH, TanH))
+
+DEFDOC (SNGL, "Convert (archaic).", ARCHAIC (REAL, Real))
+
+DEFDOC (SIN, "Sine.", "\
+Returns the sine of @var{@1@}, an angle measured
+in radians.
+
+@xref{ASin Intrinsic}, for the inverse of this function.
+")
+
+DEFDOC (CSIN, "Sine (archaic).", ARCHAIC (SIN, Sin))
+
+DEFDOC (DSIN, "Sine (archaic).", ARCHAIC (SIN, Sin))
+
+DEFDOC (CDSIN, "Sine (archaic).", ARCHAIC (SIN, Sin))
+
+DEFDOC (SINH, "Hyperbolic sine.", "\
+Returns the hyperbolic sine of @var{@1@}.
+")
+
+DEFDOC (DSINH, "Hyperbolic sine (archaic).", ARCHAIC (SINH, SinH))
+
+DEFDOC (LSHIFT, "Left-shift bits.", "\
+Returns @var{@1@} shifted to the left
+@var{@2@} bits.
+
+Although similar to the expression
+@samp{@var{@1@}*(2**@var{@2@})}, there
+are important differences.
+For example, the sign of the result is
+not necessarily the same as the sign of
+@var{@1@}.
+
+Currently this intrinsic is defined assuming
+the underlying representation of @var{@1@}
+is as a two's-complement integer.
+It is unclear at this point whether that
+definition will apply when a different
+representation is involved.
+
+@xref{LShift Intrinsic}, for the inverse of this function.
+
+@xref{IShft Intrinsic}, for information
+on a more widely available left-shifting
+intrinsic that is also more precisely defined.
+")
+
+DEFDOC (RSHIFT, "Right-shift bits.", "\
+Returns @var{@1@} shifted to the right
+@var{@2@} bits.
+
+Although similar to the expression
+@samp{@var{@1@}/(2**@var{@2@})}, there
+are important differences.
+For example, the sign of the result is
+undefined.
+
+Currently this intrinsic is defined assuming
+the underlying representation of @var{@1@}
+is as a two's-complement integer.
+It is unclear at this point whether that
+definition will apply when a different
+representation is involved.
+
+@xref{RShift Intrinsic}, for the inverse of this function.
+
+@xref{IShft Intrinsic}, for information
+on a more widely available right-shifting
+intrinsic that is also more precisely defined.
+")
+
+DEFDOC (LGE, "Lexically greater than or equal.", "\
+Returns @samp{.TRUE.} if @samp{@var{@1@}.GE.@var{@2@}},
+@samp{.FALSE.} otherwise.
+@var{@1@} and @var{@2@} are interpreted as containing
+ASCII character codes.
+If either value contains a character not in the ASCII
+character set, the result is processor dependent.
+
+If the @var{@1@} and @var{@2@} are not the same length,
+the shorter is compared as if spaces were appended to
+it to form a value that has the same length as the longer.
+
+The lexical comparison intrinsics @code{LGe}, @code{LGt},
+@code{LLe}, and @code{LLt} differ from the corresponding
+intrinsic operators @code{.GE.}, @code{.GT.},
+@code{.LE.}, @code{.LT.}.
+Because the ASCII collating sequence is assumed,
+the following expressions always return @samp{.TRUE.}:
+
+@smallexample
+LGE ('0', ' ')
+LGE ('A', '0')
+LGE ('a', 'A')
+@end smallexample
+
+The following related expressions do @emph{not} always
+return @samp{.TRUE.}, as they are not necessarily evaluated
+assuming the arguments use ASCII encoding:
+
+@smallexample
+'0' .GE. ' '
+'A' .GE. '0'
+'a' .GE. 'A'
+@end smallexample
+
+The same difference exists
+between @code{LGt} and @code{.GT.};
+between @code{LLe} and @code{.LE.}; and
+between @code{LLt} and @code{.LT.}.
+")
+
+DEFDOC (LGT, "Lexically greater than.", "\
+Returns @samp{.TRUE.} if @samp{@var{@1@}.GT.@var{@2@}},
+@samp{.FALSE.} otherwise.
+@var{@1@} and @var{@2@} are interpreted as containing
+ASCII character codes.
+If either value contains a character not in the ASCII
+character set, the result is processor dependent.
+
+If the @var{@1@} and @var{@2@} are not the same length,
+the shorter is compared as if spaces were appended to
+it to form a value that has the same length as the longer.
+
+@xref{LGe Intrinsic}, for information on the distinction
+between the @code{@0@} intrinsic and the @code{.GT.}
+operator.
+")
+
+DEFDOC (LLE, "Lexically less than or equal.", "\
+Returns @samp{.TRUE.} if @samp{@var{@1@}.LE.@var{@2@}},
+@samp{.FALSE.} otherwise.
+@var{@1@} and @var{@2@} are interpreted as containing
+ASCII character codes.
+If either value contains a character not in the ASCII
+character set, the result is processor dependent.
+
+If the @var{@1@} and @var{@2@} are not the same length,
+the shorter is compared as if spaces were appended to
+it to form a value that has the same length as the longer.
+
+@xref{LGe Intrinsic}, for information on the distinction
+between the @code{@0@} intrinsic and the @code{.LE.}
+operator.
+")
+
+DEFDOC (LLT, "Lexically less than.", "\
+Returns @samp{.TRUE.} if @samp{@var{@1@}.LT.@var{@2@}},
+@samp{.FALSE.} otherwise.
+@var{@1@} and @var{@2@} are interpreted as containing
+ASCII character codes.
+If either value contains a character not in the ASCII
+character set, the result is processor dependent.
+
+If the @var{@1@} and @var{@2@} are not the same length,
+the shorter is compared as if spaces were appended to
+it to form a value that has the same length as the longer.
+
+@xref{LGe Intrinsic}, for information on the distinction
+between the @code{@0@} intrinsic and the @code{.LT.}
+operator.
+")
+
+DEFDOC (SIGN, "Apply sign to magnitude.", "\
+Returns @samp{ABS(@var{@1@})*@var{s}}, where
+@var{s} is +1 if @samp{@var{@2@}.GE.0},
+-1 otherwise.
+
+@xref{Abs Intrinsic}, for the function that returns
+the magnitude of a value.
+")
+
+DEFDOC (DSIGN, "Apply sign to magnitude (archaic).", ARCHAIC_2 (SIGN, Sign))
+DEFDOC (ISIGN, "Apply sign to magnitude (archaic).", ARCHAIC_2 (SIGN, Sign))
+
+DEFDOC (REAL, "Convert value to type @code{REAL(KIND=1)}.", "\
+Converts @var{@1@} to @code{REAL(KIND=1)}.
+
+Use of @code{@0@()} with a @code{COMPLEX} argument
+(other than @code{COMPLEX(KIND=1)}) is restricted to the following case:
+
+@example
+REAL(REAL(@1@))
+@end example
+
+@noindent
+This expression converts the real part of @1@ to
+@code{REAL(KIND=1)}.
+
+@xref{RealPart Intrinsic}, for information on a GNU Fortran
+intrinsic that extracts the real part of an arbitrary
+@code{COMPLEX} value.
+
+@xref{REAL() and AIMAG() of Complex}, for more information.
+")
+
+DEFDOC (DREAL, "Convert value to type @code{REAL(KIND=2)}.", "\
+Converts @var{@1@} to @code{REAL(KIND=2)}.
+
+If @var{@1@} is type @code{COMPLEX}, its real part
+is converted (if necessary) to @code{REAL(KIND=2)},
+and its imaginary part is disregarded.
+
+Although this intrinsic is not standard Fortran,
+it is a popular extension offered by many compilers
+that support @code{DOUBLE COMPLEX}, since it offers
+the easiest way to extract the real part of a @code{DOUBLE COMPLEX}
+value without using the Fortran 90 @code{REAL()} intrinsic
+in a way that produces a return value inconsistent with
+the way many FORTRAN 77 compilers handle @code{REAL()} of
+a @code{DOUBLE COMPLEX} value.
+
+@xref{RealPart Intrinsic}, for information on a GNU Fortran
+intrinsic that avoids these areas of confusion.
+
+@xref{Dble Intrinsic}, for information on the standard FORTRAN 77
+replacement for @code{DREAL()}.
+
+@xref{REAL() and AIMAG() of Complex}, for more information on
+this issue.
+")
+
+DEFDOC (IMAGPART, "Extract imaginary part of complex.", "\
+The imaginary part of @var{@1@} is returned, without conversion.
+
+@emph{Note:} The way to do this in standard Fortran 90
+is @samp{AIMAG(@var{@1@})}.
+However, when, for example, @var{@1@} is @code{DOUBLE COMPLEX},
+@samp{AIMAG(@var{@1@})} means something different for some compilers
+that are not true Fortran 90 compilers but offer some
+extensions standardized by Fortran 90 (such as the
+@code{DOUBLE COMPLEX} type, also known as @code{COMPLEX(KIND=2)}).
+
+The advantage of @code{@0@()} is that, while not necessarily
+more or less portable than @code{AIMAG()}, it is more likely to
+cause a compiler that doesn't support it to produce a diagnostic
+than generate incorrect code.
+
+@xref{REAL() and AIMAG() of Complex}, for more information.
+")
+
+DEFDOC (COMPLEX, "Build complex value from real and@99@imaginary parts.", "\
+Returns a @code{COMPLEX} value that has @samp{@1@} and @samp{@2@} as its
+real and imaginary parts, respectively.
+
+If @var{@1@} and @var{@2@} are the same type, and that type is not
+@code{INTEGER}, no data conversion is performed, and the type of
+the resulting value has the same kind value as the types
+of @var{@1@} and @var{@2@}.
+
+If @var{@1@} and @var{@2@} are not the same type, the usual type-promotion
+rules are applied to both, converting either or both to the
+appropriate @code{REAL} type.
+The type of the resulting value has the same kind value as the
+type to which both @var{@1@} and @var{@2@} were converted, in this case.
+
+If @var{@1@} and @var{@2@} are both @code{INTEGER}, they are both converted
+to @code{REAL(KIND=1)}, and the result of the @code{@0@()}
+invocation is type @code{COMPLEX(KIND=1)}.
+
+@emph{Note:} The way to do this in standard Fortran 90
+is too hairy to describe here, but it is important to
+note that @samp{CMPLX(D1,D2)} returns a @code{COMPLEX(KIND=1)}
+result even if @samp{D1} and @samp{D2} are type @code{REAL(KIND=2)}.
+Hence the availability of @code{COMPLEX()} in GNU Fortran.
+")
+
+DEFDOC (LOC, "Address of entity in core.", "\
+The @code{LOC()} intrinsic works the
+same way as the @code{%LOC()} construct.
+@xref{%LOC(),,The @code{%LOC()} Construct}, for
+more information.
+")
+
+DEFDOC (REALPART, "Extract real part of complex.", "\
+The real part of @var{@1@} is returned, without conversion.
+
+@emph{Note:} The way to do this in standard Fortran 90
+is @samp{REAL(@var{@1@})}.
+However, when, for example, @var{@1@} is @code{COMPLEX(KIND=2)},
+@samp{REAL(@var{@1@})} means something different for some compilers
+that are not true Fortran 90 compilers but offer some
+extensions standardized by Fortran 90 (such as the
+@code{DOUBLE COMPLEX} type, also known as @code{COMPLEX(KIND=2)}).
+
+The advantage of @code{@0@()} is that, while not necessarily
+more or less portable than @code{REAL()}, it is more likely to
+cause a compiler that doesn't support it to produce a diagnostic
+than generate incorrect code.
+
+@xref{REAL() and AIMAG() of Complex}, for more information.
+")
+
+DEFDOC (GETARG, "Obtain command-line argument.", "\
+Sets @var{@2@} to the @var{@1@}-th command-line argument (or to all
+blanks if there are fewer than @var{@2@} command-line arguments);
+@code{CALL @0@(0, @var{value})} sets @var{value} to the name of the
+program (on systems that support this feature).
+
+@xref{IArgC Intrinsic}, for information on how to get the number
+of arguments.
+")
+
+DEFDOC (ABORT, "Abort the program.", "\
+Prints a message and potentially causes a core dump via @code{abort(3)}.
+")
+
+DEFDOC (EXIT, "Terminate the program.", "\
+Exit the program with status @var{@1@} after closing open Fortran
+I/O units and otherwise behaving as @code{exit(2)}.
+If @var{@1@} is omitted the canonical `success' value
+will be returned to the system.
+")
+
+DEFDOC (IARGC, "Obtain count of command-line arguments.", "\
+Returns the number of command-line arguments.
+
+This count does not include the specification of the program
+name itself.
+")
+
+DEFDOC (CTIME_func, "Convert time to Day Mon dd hh:mm:ss yyyy.", "\
+Converts @var{@1@}, a system time value, such as returned by
+@code{TIME8()}, to a string of the form @samp{Sat Aug 19 18:13:14 1995},
+and returns that string as the function value.
+
+@xref{Time8 Intrinsic}.
+")
+
+DEFDOC (CTIME_subr, "Convert time to Day Mon dd hh:mm:ss yyyy.", "\
+Converts @var{@2@}, a system time value, such as returned by
+@code{TIME8()}, to a string of the form @samp{Sat Aug 19 18:13:14 1995},
+and returns that string in @var{@1@}.
+
+@xref{Time8 Intrinsic}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+")
+
+DEFDOC (DATE, "Get current date as dd-Mon-yy.", "\
+Returns @var{@1@} in the form @samp{@var{dd}-@var{mmm}-@var{yy}},
+representing the numeric day of the month @var{dd}, a three-character
+abbreviation of the month name @var{mmm} and the last two digits of
+the year @var{yy}, e.g.@: @samp{25-Nov-96}.
+
+This intrinsic is not recommended, due to the year 2000 approaching.
+@xref{CTime Intrinsic (subroutine)}, for information on obtaining more digits
+for the current (or any) date.
+")
+
+DEFDOC (DTIME_func, "Get elapsed time since last time.", "\
+Initially, return the number of seconds of runtime
+since the start of the process's execution
+as the function value,
+and the user and system components of this in @samp{@var{@1@}(1)}
+and @samp{@var{@1@}(2)} respectively.
+The functions' value is equal to @samp{@var{@1@}(1) + @var{@1@}(2)}.
+
+Subsequent invocations of @samp{@0@()} return values accumulated since the
+previous invocation.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+")
+
+DEFDOC (DTIME_subr, "Get elapsed time since last time.", "\
+Initially, return the number of seconds of runtime
+since the start of the process's execution
+in @var{@1@},
+and the user and system components of this in @samp{@var{@2@}(1)}
+and @samp{@var{@2@}(2)} respectively.
+The value of @var{@1@} is equal to @samp{@var{@2@}(1) + @var{@2@}(2)}.
+
+Subsequent invocations of @samp{@0@()} set values based on accumulations
+since the previous invocation.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+")
+
+DEFDOC (ETIME_func, "Get elapsed time for process.", "\
+Return the number of seconds of runtime
+since the start of the process's execution
+as the function value,
+and the user and system components of this in @samp{@var{@1@}(1)}
+and @samp{@var{@1@}(2)} respectively.
+The functions' value is equal to @samp{@var{@1@}(1) + @var{@1@}(2)}.
+")
+
+DEFDOC (ETIME_subr, "Get elapsed time for process.", "\
+Return the number of seconds of runtime
+since the start of the process's execution
+in @var{@1@},
+and the user and system components of this in @samp{@var{@2@}(1)}
+and @samp{@var{@2@}(2)} respectively.
+The value of @var{@1@} is equal to @samp{@var{@2@}(1) + @var{@2@}(2)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+")
+
+DEFDOC (FDATE_func, "Get current time as Day Mon dd hh:mm:ss yyyy.", "\
+Returns the current date (using the same format as @code{CTIME()}).
+
+Equivalent to:
+
+@example
+CTIME(TIME8())
+@end example
+
+@xref{CTime Intrinsic (function)}.
+")
+
+DEFDOC (FDATE_subr, "Get current time as Day Mon dd hh:mm:ss yyyy.", "\
+Returns the current date (using the same format as @code{CTIME()})
+in @var{@1@}.
+
+Equivalent to:
+
+@example
+CALL CTIME(@var{@1@}, TIME8())
+@end example
+
+@xref{CTime Intrinsic (subroutine)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+")
+
+DEFDOC (GMTIME, "Convert time to GMT time info.", "\
+Given a system time value @var{@1@}, fills @var{@2@} with values
+extracted from it appropriate to the GMT time zone using
+@code{gmtime(3)}.
+
+The array elements are as follows:
+
+@enumerate
+@item
+Seconds after the minute, range 0--59 or 0--61 to allow for leap
+seconds
+
+@item
+Minutes after the hour, range 0--59
+
+@item
+Hours past midnight, range 0--23
+
+@item
+Day of month, range 0--31
+
+@item
+Number of months since January, range 0--12
+
+@item
+Years since 1900
+
+@item
+Number of days since Sunday, range 0--6
+
+@item
+Days since January 1
+
+@item
+Daylight savings indicator: positive if daylight savings is in effect,
+zero if not, and negative if the information isn't available.
+@end enumerate
+")
+
+DEFDOC (LTIME, "Convert time to local time info.", "\
+Given a system time value @var{@1@}, fills @var{@2@} with values
+extracted from it appropriate to the GMT time zone using
+@code{localtime(3)}.
+
+The array elements are as follows:
+
+@enumerate
+@item
+Seconds after the minute, range 0--59 or 0--61 to allow for leap
+seconds
+
+@item
+Minutes after the hour, range 0--59
+
+@item
+Hours past midnight, range 0--23
+
+@item
+Day of month, range 0--31
+
+@item
+Number of months since January, range 0--12
+
+@item
+Years since 1900
+
+@item
+Number of days since Sunday, range 0--6
+
+@item
+Days since January 1
+
+@item
+Daylight savings indicator: positive if daylight savings is in effect,
+zero if not, and negative if the information isn't available.
+@end enumerate
+")
+
+DEFDOC (IDATE_unix, "Get local time info.", "\
+Fills @var{@1@} with the numerical values at the current local time
+of day, month (in the range 1--12), and year in elements 1, 2, and 3,
+respectively.
+The year has four significant digits.
+")
+
+DEFDOC (IDATE_vxt, "Get local time info (VAX/VMS).", "\
+Returns the numerical values of the current local time.
+The month (in the range 1--12) is returned in @var{@1@},
+the day (in the range 1--7) in @var{@2@},
+and the year in @var{@3@} (in the range 0--99).
+
+This intrinsic is not recommended, due to the year 2000 approaching.
+")
+
+DEFDOC (ITIME, "Get local time of day.", "\
+Returns the current local time hour, minutes, and seconds in elements
+1, 2, and 3 of @var{@1@}, respectively.
+")
+
+DEFDOC (MCLOCK, "Get number of clock ticks for process.", "\
+Returns the number of clock ticks since the start of the process.
+Supported on systems with @code{clock(3)} (q.v.).
+
+This intrinsic is not fully portable, such as to systems
+with 32-bit @code{INTEGER} types but supporting times
+wider than 32 bits.
+@xref{MClock8 Intrinsic}, for information on a
+similar intrinsic that might be portable to more
+GNU Fortran implementations, though to fewer
+Fortran compilers.
+
+If the system does not support @code{clock(3)},
+-1 is returned.
+")
+
+DEFDOC (MCLOCK8, "Get number of clock ticks for process.", "\
+Returns the number of clock ticks since the start of the process.
+Supported on systems with @code{clock(3)} (q.v.).
+
+@emph{Warning:} this intrinsic does not increase the range
+of the timing values over that returned by @code{clock(3)}.
+On a system with a 32-bit @code{clock(3)},
+@code{@0@} will return a 32-bit value,
+even though converted to an @samp{INTEGER(KIND=2)} value.
+That means overflows of the 32-bit value can still occur.
+
+No Fortran implementations other than GNU Fortran are
+known to support this intrinsic at the time of this
+writing.
+@xref{MClock Intrinsic}, for information on a
+similar intrinsic that might be portable to more Fortran
+compilers, though to fewer GNU Fortran implementations.
+
+If the system does not support @code{clock(3)},
+-1 is returned.
+")
+
+DEFDOC (SECNDS, "Get local time offset since midnight.", "\
+Returns the local time in seconds since midnight minus the value
+@var{@1@}.
+")
+
+DEFDOC (SECOND_func, "Get CPU time for process in seconds.", "\
+Returns the process's runtime in seconds---the same value as the
+UNIX function @code{etime} returns.
+")
+
+DEFDOC (SECOND_subr, "Get CPU time for process@99@in seconds.", "\
+Returns the process's runtime in seconds in @var{@1@}---the same value
+as the UNIX function @code{etime} returns.
+
+This routine is known from Cray Fortran. @xref{CPU_Time Intrinsic},
+for a standard equivalent.
+")
+
+DEFDOC (SYSTEM_CLOCK, "Get current system clock value.", "\
+Returns in @var{@1@} the current value of the system clock; this is
+the value returned by the UNIX function @code{times(2)}
+in this implementation, but
+isn't in general.
+@var{@2@} is the number of clock ticks per second and
+@var{@3@} is the maximum value this can take, which isn't very useful
+in this implementation since it's just the maximum C @code{unsigned
+int} value.
+")
+
+DEFDOC (CPU_TIME, "Get current CPU time.", "\
+Returns in @var{@1@} the current value of the system time.
+This implementation of the Fortran 95 intrinsic is just an alias for
+@code{second} @xref{Second Intrinsic (subroutine)}.
+")
+
+DEFDOC (TIME8, "Get current time as time value.", "\
+Returns the current time encoded as a long integer
+(in the manner of the UNIX function @code{time(3)}).
+This value is suitable for passing to @code{CTIME},
+@code{GMTIME}, and @code{LTIME}.
+
+@emph{Warning:} this intrinsic does not increase the range
+of the timing values over that returned by @code{time(3)}.
+On a system with a 32-bit @code{time(3)},
+@code{@0@} will return a 32-bit value,
+even though converted to an @samp{INTEGER(KIND=2)} value.
+That means overflows of the 32-bit value can still occur.
+
+No Fortran implementations other than GNU Fortran are
+known to support this intrinsic at the time of this
+writing.
+@xref{Time Intrinsic (UNIX)}, for information on a
+similar intrinsic that might be portable to more Fortran
+compilers, though to fewer GNU Fortran implementations.
+")
+
+DEFDOC (TIME_unix, "Get current time as time value.", "\
+Returns the current time encoded as an integer
+(in the manner of the UNIX function @code{time(3)}).
+This value is suitable for passing to @code{CTIME},
+@code{GMTIME}, and @code{LTIME}.
+
+This intrinsic is not fully portable, such as to systems
+with 32-bit @code{INTEGER} types but supporting times
+wider than 32 bits.
+@xref{Time8 Intrinsic}, for information on a
+similar intrinsic that might be portable to more
+GNU Fortran implementations, though to fewer
+Fortran compilers.
+")
+
+#define BES(num,n,val) "\
+Calculates the Bessel function of the " #num " kind of \
+order " #n " of @var{@" #val "@}.\n\
+See @code{bessel(3m)}, on whose implementation the \
+function depends.\
+"
+
+DEFDOC (BESJ0, "Bessel function.", BES (first, 0, 1))
+DEFDOC (BESJ1, "Bessel function.", BES (first, 1, 1))
+DEFDOC (BESJN, "Bessel function.", BES (first, @var{N}, 2))
+DEFDOC (BESY0, "Bessel function.", BES (second, 0, 1))
+DEFDOC (BESY1, "Bessel function.", BES (second, 1, 1))
+DEFDOC (BESYN, "Bessel function.", BES (second, @var{N}, 2))
+DEFDOC (DBESJ0, "Bessel function (archaic).", ARCHAIC (BESJ0, BesJ0))
+DEFDOC (DBESJ1, "Bessel function (archaic).", ARCHAIC (BESJ1, BesJ1))
+DEFDOC (DBESJN, "Bessel function (archaic).", ARCHAIC_2nd (BESJN, BesJN))
+DEFDOC (DBESY0, "Bessel function (archaic).", ARCHAIC (BESY0, BesY0))
+DEFDOC (DBESY1, "Bessel function (archaic).", ARCHAIC (BESY1, BesY1))
+DEFDOC (DBESYN, "Bessel function (archaic).", ARCHAIC_2nd (BESYN, BesYN))
+
+DEFDOC (ERF, "Error function.", "\
+Returns the error function of @var{@1@}.
+See @code{erf(3m)}, which provides the implementation.
+")
+
+DEFDOC (ERFC, "Complementary error function.", "\
+Returns the complementary error function of @var{@1@}:
+@samp{ERFC(R) = 1 - ERF(R)} (except that the result may be more
+accurate than explicitly evaluating that formulae would give).
+See @code{erfc(3m)}, which provides the implementation.
+")
+
+DEFDOC (DERF, "Error function (archaic).", ARCHAIC (ERF, ErF))
+DEFDOC (DERFC, "Complementary error function (archaic).", ARCHAIC (ERFC, ErFC))
+
+DEFDOC (IRAND, "Random number.", "\
+Returns a uniform quasi-random number up to a system-dependent limit.
+If @var{@1@} is 0, the next number in sequence is returned; if
+@var{@1@} is 1, the generator is restarted by calling the UNIX function
+@samp{srand(0)}; if @var{@1@} has any other value,
+it is used as a new seed with @code{srand()}.
+
+@xref{SRand Intrinsic}.
+
+@emph{Note:} As typically implemented (by the routine of the same
+name in the C library), this random number generator is a very poor
+one, though the BSD and GNU libraries provide a much better
+implementation than the `traditional' one.
+On a different system you almost certainly want to use something better.
+")
+
+DEFDOC (RAND, "Random number.", "\
+Returns a uniform quasi-random number between 0 and 1.
+If @var{@1@} is 0, the next number in sequence is returned; if
+@var{@1@} is 1, the generator is restarted by calling @samp{srand(0)};
+if @var{@1@} has any other value, it is used as a new seed with
+@code{srand}.
+
+@xref{SRand Intrinsic}.
+
+@emph{Note:} As typically implemented (by the routine of the same
+name in the C library), this random number generator is a very poor
+one, though the BSD and GNU libraries provide a much better
+implementation than the `traditional' one.
+On a different system you
+almost certainly want to use something better.
+")
+
+DEFDOC (SRAND, "Random seed.", "\
+Reinitialises the generator with the seed in @var{@1@}.
+@xref{IRand Intrinsic}.
+@xref{Rand Intrinsic}.
+")
+
+DEFDOC (ACCESS, "Check file accessibility.", "\
+Checks file @var{@1@} for accessibility in the mode specified by @var{@2@} and
+returns 0 if the file is accessible in that mode, otherwise an error
+code if the file is inaccessible or @var{@2@} is invalid.
+See @code{access(2)}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{@1@}---otherwise,
+trailing blanks in @var{@1@} are ignored.
+@var{@2@} may be a concatenation of any of the following characters:
+
+@table @samp
+@item r
+Read permission
+
+@item w
+Write permission
+
+@item x
+Execute permission
+
+@item @kbd{SPC}
+Existence
+@end table
+")
+
+DEFDOC (CHDIR_subr, "Change directory.", "\
+Sets the current working directory to be @var{@1@}.
+If the @var{@2@} argument is supplied, it contains 0
+on success or a non-zero error code otherwise upon return.
+See @code{chdir(3)}.
+
+@emph{Caution:} Using this routine during I/O to a unit connected with a
+non-absolute file name can cause subsequent I/O on such a unit to fail
+because the I/O library may reopen files by name.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@2@} argument.
+")
+
+DEFDOC (CHDIR_func, "Change directory.", "\
+Sets the current working directory to be @var{@1@}.
+Returns 0 on success or a non-zero error code.
+See @code{chdir(3)}.
+
+@emph{Caution:} Using this routine during I/O to a unit connected with a
+non-absolute file name can cause subsequent I/O on such a unit to fail
+because the I/O library may reopen files by name.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+")
+
+DEFDOC (CHMOD_func, "Change file modes.", "\
+Changes the access mode of file @var{@1@} according to the
+specification @var{@2@}, which is given in the format of
+@code{chmod(1)}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{@1@}---otherwise,
+trailing blanks in @var{@1@} are ignored.
+Currently, @var{@1@} must not contain the single quote
+character.
+
+Returns 0 on success or a non-zero error code otherwise.
+
+Note that this currently works
+by actually invoking @code{/bin/chmod} (or the @code{chmod} found when
+the library was configured) and so may fail in some circumstances and
+will, anyway, be slow.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+")
+
+DEFDOC (CHMOD_subr, "Change file modes.", "\
+Changes the access mode of file @var{@1@} according to the
+specification @var{@2@}, which is given in the format of
+@code{chmod(1)}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{@1@}---otherwise,
+trailing blanks in @var{@1@} are ignored.
+Currently, @var{@1@} must not contain the single quote
+character.
+
+If the @var{@3@} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+
+Note that this currently works
+by actually invoking @code{/bin/chmod} (or the @code{chmod} found when
+the library was configured) and so may fail in some circumstances and
+will, anyway, be slow.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@3@} argument.
+")
+
+DEFDOC (GETCWD_func, "Get current working directory.", "\
+Places the current working directory in @var{@1@}.
+Returns 0 on
+success, otherwise a non-zero error code
+(@code{ENOSYS} if the system does not provide @code{getcwd(3)}
+or @code{getwd(3)}).
+")
+
+DEFDOC (GETCWD_subr, "Get current working directory.", "\
+Places the current working directory in @var{@1@}.
+If the @var{@2@} argument is supplied, it contains 0
+success or a non-zero error code upon return
+(@code{ENOSYS} if the system does not provide @code{getcwd(3)}
+or @code{getwd(3)}).
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@2@} argument.
+")
+
+DEFDOC (FSTAT_func, "Get file information.", "\
+Obtains data about the file open on Fortran I/O unit @var{@1@} and
+places them in the array @var{@2@}.
+The values in this array are
+extracted from the @code{stat} structure as returned by
+@code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+Returns 0 on success or a non-zero error code.
+")
+
+DEFDOC (FSTAT_subr, "Get file information.", "\
+Obtains data about the file open on Fortran I/O unit @var{@1@} and
+places them in the array @var{@2@}.
+The values in this array are
+extracted from the @code{stat} structure as returned by
+@code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+If the @var{@3@} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@3@} argument.
+")
+
+DEFDOC (LSTAT_func, "Get file information.", "\
+Obtains data about the given file @var{@1@} and places them in the array
+@var{@2@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{@1@}---otherwise,
+trailing blanks in @var{@1@} are ignored.
+If @var{@1@} is a symbolic link it returns data on the
+link itself, so the routine is available only on systems that support
+symbolic links.
+The values in this array are extracted from the
+@code{stat} structure as returned by @code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+Returns 0 on success or a non-zero error code
+(@code{ENOSYS} if the system does not provide @code{lstat(2)}).
+")
+
+DEFDOC (LSTAT_subr, "Get file information.", "\
+Obtains data about the given file @var{@1@} and places them in the array
+@var{@2@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{@1@}---otherwise,
+trailing blanks in @var{@1@} are ignored.
+If @var{@1@} is a symbolic link it returns data on the
+link itself, so the routine is available only on systems that support
+symbolic links.
+The values in this array are extracted from the
+@code{stat} structure as returned by @code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+If the @var{@3@} argument is supplied, it contains
+0 on success or a non-zero error code upon return
+(@code{ENOSYS} if the system does not provide @code{lstat(2)}).
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@3@} argument.
+")
+
+DEFDOC (STAT_func, "Get file information.", "\
+Obtains data about the given file @var{@1@} and places them in the array
+@var{@2@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{@1@}---otherwise,
+trailing blanks in @var{@1@} are ignored.
+The values in this array are extracted from the
+@code{stat} structure as returned by @code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+Returns 0 on success or a non-zero error code.
+")
+
+DEFDOC (STAT_subr, "Get file information.", "\
+Obtains data about the given file @var{@1@} and places them in the array
+@var{@2@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{@1@}---otherwise,
+trailing blanks in @var{@1@} are ignored.
+The values in this array are extracted from the
+@code{stat} structure as returned by @code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+If the @var{@3@} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@3@} argument.
+")
+
+DEFDOC (LINK_subr, "Make hard link in file system.", "\
+Makes a (hard) link from file @var{@1@} to @var{@2@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{@1@} and @var{@2@}---otherwise,
+trailing blanks in @var{@1@} and @var{@2@} are ignored.
+If the @var{@3@} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+See @code{link(2)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@3@} argument.
+")
+
+DEFDOC (LINK_func, "Make hard link in file system.", "\
+Makes a (hard) link from file @var{@1@} to @var{@2@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{@1@} and @var{@2@}---otherwise,
+trailing blanks in @var{@1@} and @var{@2@} are ignored.
+Returns 0 on success or a non-zero error code.
+See @code{link(2)}.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+")
+
+DEFDOC (SYMLNK_subr, "Make symbolic link in file system.", "\
+Makes a symbolic link from file @var{@1@} to @var{@2@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{@1@} and @var{@2@}---otherwise,
+trailing blanks in @var{@1@} and @var{@2@} are ignored.
+If the @var{@3@} argument is supplied, it contains
+0 on success or a non-zero error code upon return
+(@code{ENOSYS} if the system does not provide @code{symlink(2)}).
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@3@} argument.
+")
+
+DEFDOC (SYMLNK_func, "Make symbolic link in file system.", "\
+Makes a symbolic link from file @var{@1@} to @var{@2@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{@1@} and @var{@2@}---otherwise,
+trailing blanks in @var{@1@} and @var{@2@} are ignored.
+Returns 0 on success or a non-zero error code
+(@code{ENOSYS} if the system does not provide @code{symlink(2)}).
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+")
+
+DEFDOC (RENAME_subr, "Rename file.", "\
+Renames the file @var{@1@} to @var{@2@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{@1@} and @var{@2@}---otherwise,
+trailing blanks in @var{@1@} and @var{@2@} are ignored.
+See @code{rename(2)}.
+If the @var{@3@} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@3@} argument.
+")
+
+DEFDOC (RENAME_func, "Rename file.", "\
+Renames the file @var{@1@} to @var{@2@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{@1@} and @var{@2@}---otherwise,
+trailing blanks in @var{@1@} and @var{@2@} are ignored.
+See @code{rename(2)}.
+Returns 0 on success or a non-zero error code.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+")
+
+DEFDOC (UMASK_subr, "Set file creation permissions mask.", "\
+Sets the file creation mask to @var{@1@} and returns the old value in
+argument @var{@2@} if it is supplied.
+See @code{umask(2)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+")
+
+DEFDOC (UMASK_func, "Set file creation permissions mask.", "\
+Sets the file creation mask to @var{@1@} and returns the old value.
+See @code{umask(2)}.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+")
+
+DEFDOC (UNLINK_subr, "Unlink file.", "\
+Unlink the file @var{@1@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{@1@}---otherwise,
+trailing blanks in @var{@1@} are ignored.
+If the @var{@2@} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+See @code{unlink(2)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@2@} argument.
+")
+
+DEFDOC (UNLINK_func, "Unlink file.", "\
+Unlink the file @var{@1@}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{@1@}---otherwise,
+trailing blanks in @var{@1@} are ignored.
+Returns 0 on success or a non-zero error code.
+See @code{unlink(2)}.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+")
+
+DEFDOC (GERROR, "Get error message for last error.", "\
+Returns the system error message corresponding to the last system
+error (C @code{errno}).
+")
+
+DEFDOC (IERRNO, "Get error number for last error.", "\
+Returns the last system error number (corresponding to the C
+@code{errno}).
+")
+
+DEFDOC (PERROR, "Print error message for last error.", "\
+Prints (on the C @code{stderr} stream) a newline-terminated error
+message corresponding to the last system error.
+This is prefixed by @var{@1@}, a colon and a space.
+See @code{perror(3)}.
+")
+
+DEFDOC (GETGID, "Get process group id.", "\
+Returns the group id for the current process.
+")
+
+DEFDOC (GETUID, "Get process user id.", "\
+Returns the user id for the current process.
+")
+
+DEFDOC (GETPID, "Get process id.", "\
+Returns the process id for the current process.
+")
+
+DEFDOC (GETENV, "Get environment variable.", "\
+Sets @var{@2@} to the value of environment variable given by the
+value of @var{@1@} (@code{$name} in shell terms) or to blanks if
+@code{$name} has not been set.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{@1@}---otherwise,
+trailing blanks in @var{@1@} are ignored.
+")
+
+DEFDOC (GETLOG, "Get login name.", "\
+Returns the login name for the process in @var{@1@}.
+
+@emph{Caution:} On some systems, the @code{getlogin(3)}
+function, which this intrinsic calls at run time,
+is either not implemented or returns a null pointer.
+In the latter case, this intrinsic returns blanks
+in @var{@1@}.
+")
+
+DEFDOC (HOSTNM_func, "Get host name.", "\
+Fills @var{@1@} with the system's host name returned by
+@code{gethostname(2)}, returning 0 on success or a non-zero error code
+(@code{ENOSYS} if the system does not provide @code{gethostname(2)}).
+
+On some systems (specifically SCO) it may be necessary to link the
+``socket'' library if you call this routine.
+Typically this means adding @samp{-lg2c -lsocket -lm}
+to the @code{g77} command line when linking the program.
+")
+
+DEFDOC (HOSTNM_subr, "Get host name.", "\
+Fills @var{@1@} with the system's host name returned by
+@code{gethostname(2)}.
+If the @var{@2@} argument is supplied, it contains
+0 on success or a non-zero error code upon return
+(@code{ENOSYS} if the system does not provide @code{gethostname(2)}).
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@2@} argument.
+
+On some systems (specifically SCO) it may be necessary to link the
+``socket'' library if you call this routine.
+Typically this means adding @samp{-lg2c -lsocket -lm}
+to the @code{g77} command line when linking the program.
+")
+
+DEFDOC (FLUSH, "Flush buffered output.", "\
+Flushes Fortran unit(s) currently open for output.
+Without the optional argument, all such units are flushed,
+otherwise just the unit specified by @var{@1@}.
+
+Some non-GNU implementations of Fortran provide this intrinsic
+as a library procedure that might or might not support the
+(optional) @var{@1@} argument.
+")
+
+DEFDOC (FNUM, "Get file descriptor from Fortran unit number.", "\
+Returns the Unix file descriptor number corresponding to the open
+Fortran I/O unit @var{@1@}.
+This could be passed to an interface to C I/O routines.
+")
+
+#define IOWARN "
+Stream I/O should not be mixed with normal record-oriented (formatted or
+unformatted) I/O on the same unit; the results are unpredictable.
+"
+
+DEFDOC (FGET_func, "Read a character from unit 5 stream-wise.", "\
+Reads a single character into @var{@1@} in stream mode from unit 5
+(by-passing normal formatted input) using @code{getc(3)}.
+Returns 0 on
+success, @minus{}1 on end-of-file, and the error code from
+@code{ferror(3)} otherwise.
+" IOWARN)
+
+DEFDOC (FGET_subr, "Read a character from unit 5 stream-wise.", "\
+Reads a single character into @var{@1@} in stream mode from unit 5
+(by-passing normal formatted output) using @code{getc(3)}.
+Returns in
+@var{@2@} 0 on success, @minus{}1 on end-of-file, and the error code
+from @code{ferror(3)} otherwise.
+" IOWARN)
+
+DEFDOC (FGETC_func, "Read a character stream-wise.", "\
+Reads a single character into @var{@2@} in stream mode from unit @var{@1@}
+(by-passing normal formatted output) using @code{getc(3)}.
+Returns 0 on
+success, @minus{}1 on end-of-file, and the error code from
+@code{ferror(3)} otherwise.
+" IOWARN)
+
+DEFDOC (FGETC_subr, "Read a character stream-wise.", "\
+Reads a single character into @var{@2@} in stream mode from unit @var{@1@}
+(by-passing normal formatted output) using @code{getc(3)}.
+Returns in
+@var{@3@} 0 on success, @minus{}1 on end-of-file, and the error code from
+@code{ferror(3)} otherwise.
+" IOWARN)
+
+DEFDOC (FPUT_func, "Write a character to unit 6 stream-wise.", "\
+Writes the single character @var{@1@} in stream mode to unit 6
+(by-passing normal formatted output) using @code{getc(3)}.
+Returns 0 on
+success, the error code from @code{ferror(3)} otherwise.
+" IOWARN)
+
+DEFDOC (FPUT_subr, "Write a character to unit 6 stream-wise.", "\
+Writes the single character @var{@1@} in stream mode to unit 6
+(by-passing normal formatted output) using @code{putc(3)}.
+Returns in
+@var{@2@} 0 on success, the error code from @code{ferror(3)} otherwise.
+" IOWARN)
+
+DEFDOC (FPUTC_func, "Write a character stream-wise.", "\
+Writes the single character @var{@2@} in stream mode to unit @var{@1@}
+(by-passing normal formatted output) using @code{putc(3)}.
+Returns 0 on
+success, the error code from @code{ferror(3)} otherwise.
+" IOWARN)
+
+DEFDOC (FPUTC_subr, "Write a character stream-wise.", "\
+Writes the single character @var{@1@} in stream mode to unit 6
+(by-passing normal formatted output) using @code{putc(3)}.
+Returns in
+@var{@2@} 0 on success, the error code from @code{ferror(3)} otherwise.
+" IOWARN)
+
+DEFDOC (FSEEK, "Position file (low-level).", "\
+Attempts to move Fortran unit @var{@1@} to the specified
+@var{@2@}: absolute offset if @var{@3@}=0; relative to the
+current offset if @var{@3@}=1; relative to the end of the file if
+@var{@3@}=2.
+It branches to label @var{@4@} if @var{@1@} is
+not open or if the call otherwise fails.
+")
+
+DEFDOC (FTELL_func, "Get file position (low-level).", "\
+Returns the current offset of Fortran unit @var{@1@}
+(or @minus{}1 if @var{@1@} is not open).
+")
+
+DEFDOC (FTELL_subr, "Get file position (low-level).", "\
+Sets @var{@2@} to the current offset of Fortran unit @var{@1@}
+(or to @minus{}1 if @var{@1@} is not open).
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+")
+
+DEFDOC (ISATTY, "Is unit connected to a terminal?", "\
+Returns @code{.TRUE.} if and only if the Fortran I/O unit
+specified by @var{@1@} is connected
+to a terminal device.
+See @code{isatty(3)}.
+")
+
+DEFDOC (TTYNAM_func, "Get name of terminal device for unit.", "\
+Returns the name of the terminal device open on logical unit
+@var{@1@} or a blank string if @var{@1@} is not connected to a
+terminal.
+")
+
+DEFDOC (TTYNAM_subr, "Get name of terminal device for unit.", "\
+Sets @var{@1@} to the name of the terminal device open on logical unit
+@var{@2@} or a blank string if @var{@2@} is not connected to a
+terminal.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+")
+
+DEFDOC (SIGNAL_subr, "Muck with signal handling.", "\
+If @var{@2@} is a an @code{EXTERNAL} routine, arranges for it to be
+invoked with a single integer argument (of system-dependent length)
+when signal @var{@1@} occurs.
+If @var{@2@} is an integer, it can be
+used to turn off handling of signal @var{@1@} or revert to its default
+action.
+See @code{signal(2)}.
+
+Note that @var{@2@} will be called using C conventions,
+so the value of its argument in Fortran terms
+Fortran terms is obtained by applying @code{%LOC()} (or @var{LOC()}) to it.
+
+The value returned by @code{signal(2)} is written to @var{@3@}, if
+that argument is supplied.
+Otherwise the return value is ignored.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@3@} argument.
+
+@emph{Warning:} Use of the @code{libf2c} run-time library function
+@samp{signal_} directly
+(such as via @samp{EXTERNAL SIGNAL})
+requires use of the @code{%VAL()} construct
+to pass an @code{INTEGER} value
+(such as @samp{SIG_IGN} or @samp{SIG_DFL})
+for the @var{@2@} argument.
+
+However, while @samp{CALL SIGNAL(@var{signum}, %VAL(SIG_IGN))}
+works when @samp{SIGNAL} is treated as an external procedure
+(and resolves, at link time, to @code{libf2c}'s @samp{signal_} routine),
+this construct is not valid when @samp{SIGNAL} is recognized
+as the intrinsic of that name.
+
+Therefore, for maximum portability and reliability,
+code such references to the @samp{SIGNAL} facility as follows:
+
+@smallexample
+INTRINSIC SIGNAL
+@dots{}
+CALL SIGNAL(@var{signum}, SIG_IGN)
+@end smallexample
+
+@code{g77} will compile such a call correctly,
+while other compilers will generally either do so as well
+or reject the @samp{INTRINSIC SIGNAL} statement via a diagnostic,
+allowing you to take appropriate action.
+")
+
+DEFDOC (SIGNAL_func, "Muck with signal handling.", "\
+If @var{@2@} is a an @code{EXTERNAL} routine, arranges for it to be
+invoked with a single integer argument (of system-dependent length)
+when signal @var{@1@} occurs.
+If @var{@2@} is an integer, it can be
+used to turn off handling of signal @var{@1@} or revert to its default
+action.
+See @code{signal(2)}.
+
+Note that @var{@2@} will be called using C conventions,
+so the value of its argument in Fortran terms
+is obtained by applying @code{%LOC()} (or @var{LOC()}) to it.
+
+The value returned by @code{signal(2)} is returned.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+@emph{Warning:} If the returned value is stored in
+an @code{INTEGER(KIND=1)} (default @code{INTEGER}) argument,
+truncation of the original return value occurs on some systems
+(such as Alphas, which have 64-bit pointers but 32-bit default integers),
+with no warning issued by @code{g77} under normal circumstances.
+
+Therefore, the following code fragment might silently fail on
+some systems:
+
+@smallexample
+INTEGER RTN
+EXTERNAL MYHNDL
+RTN = SIGNAL(@var{signum}, MYHNDL)
+@dots{}
+! Restore original handler:
+RTN = SIGNAL(@var{signum}, RTN)
+@end smallexample
+
+The reason for the failure is that @samp{RTN} might not hold
+all the information on the original handler for the signal,
+thus restoring an invalid handler.
+This bug could manifest itself as a spurious run-time failure
+at an arbitrary point later during the program's execution,
+for example.
+
+@emph{Warning:} Use of the @code{libf2c} run-time library function
+@samp{signal_} directly
+(such as via @samp{EXTERNAL SIGNAL})
+requires use of the @code{%VAL()} construct
+to pass an @code{INTEGER} value
+(such as @samp{SIG_IGN} or @samp{SIG_DFL})
+for the @var{@2@} argument.
+
+However, while @samp{RTN = SIGNAL(@var{signum}, %VAL(SIG_IGN))}
+works when @samp{SIGNAL} is treated as an external procedure
+(and resolves, at link time, to @code{libf2c}'s @samp{signal_} routine),
+this construct is not valid when @samp{SIGNAL} is recognized
+as the intrinsic of that name.
+
+Therefore, for maximum portability and reliability,
+code such references to the @samp{SIGNAL} facility as follows:
+
+@smallexample
+INTRINSIC SIGNAL
+@dots{}
+RTN = SIGNAL(@var{signum}, SIG_IGN)
+@end smallexample
+
+@code{g77} will compile such a call correctly,
+while other compilers will generally either do so as well
+or reject the @samp{INTRINSIC SIGNAL} statement via a diagnostic,
+allowing you to take appropriate action.
+")
+
+DEFDOC (KILL_func, "Signal a process.", "\
+Sends the signal specified by @var{@2@} to the process @var{@1@}.
+Returns 0 on success or a non-zero error code.
+See @code{kill(2)}.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+")
+
+DEFDOC (KILL_subr, "Signal a process.", "\
+Sends the signal specified by @var{@2@} to the process @var{@1@}.
+If the @var{@3@} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+See @code{kill(2)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@3@} argument.
+")
+
+DEFDOC (LNBLNK, "Get last non-blank character in string.", "\
+Returns the index of the last non-blank character in @var{@1@}.
+@code{LNBLNK} and @code{LEN_TRIM} are equivalent.
+")
+
+DEFDOC (SLEEP, "Sleep for a specified time.", "\
+Causes the process to pause for @var{@1@} seconds.
+See @code{sleep(2)}.
+")
+
+DEFDOC (SYSTEM_subr, "Invoke shell (system) command.", "\
+Passes the command @var{@1@} to a shell (see @code{system(3)}).
+If argument @var{@2@} is present, it contains the value returned by
+@code{system(3)}, presumably 0 if the shell command succeeded.
+Note that which shell is used to invoke the command is system-dependent
+and environment-dependent.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{@2@} argument.
+")
+
+DEFDOC (SYSTEM_func, "Invoke shell (system) command.", "\
+Passes the command @var{@1@} to a shell (see @code{system(3)}).
+Returns the value returned by
+@code{system(3)}, presumably 0 if the shell command succeeded.
+Note that which shell is used to invoke the command is system-dependent
+and environment-dependent.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+However, the function form can be valid in cases where the
+actual side effects performed by the call are unimportant to
+the application.
+
+For example, on a UNIX system, @samp{SAME = SYSTEM('cmp a b')}
+does not perform any side effects likely to be important to the
+program, so the programmer would not care if the actual system
+call (and invocation of @code{cmp}) was optimized away in a situation
+where the return value could be determined otherwise, or was not
+actually needed (@samp{SAME} not actually referenced after the
+sample assignment statement).
+")
+
+DEFDOC (TIME_vxt, "Get the time as a character value.", "\
+Returns in @var{@1@} a character representation of the current time as
+obtained from @code{ctime(3)}.
+
+@xref{Fdate Intrinsic (subroutine)}, for an equivalent routine.
+")
+
+DEFDOC (IBCLR, "Clear a bit.", "\
+Returns the value of @var{@1@} with bit @var{@2@} cleared (set to
+zero).
+@xref{BTest Intrinsic}, for information on bit positions.
+")
+
+DEFDOC (IBSET, "Set a bit.", "\
+Returns the value of @var{@1@} with bit @var{@2@} set (to one).
+@xref{BTest Intrinsic}, for information on bit positions.
+")
+
+DEFDOC (IBITS, "Extract a bit subfield of a variable.", "\
+Extracts a subfield of length @var{@3@} from @var{@1@}, starting from
+bit position @var{@2@} and extending left for @var{@3@} bits.
+The result is right-justified and the remaining bits are zeroed.
+The value
+of @samp{@var{@2@}+@var{@3@}} must be less than or equal to the value
+@samp{BIT_SIZE(@var{@1@})}.
+@xref{Bit_Size Intrinsic}.
+")
+
+DEFDOC (ISHFT, "Logical bit shift.", "\
+All bits representing @var{@1@} are shifted @var{@2@} places.
+@samp{@var{@2@}.GT.0} indicates a left shift, @samp{@var{@2@}.EQ.0}
+indicates no shift and @samp{@var{@2@}.LT.0} indicates a right shift.
+If the absolute value of the shift count is greater than
+@samp{BIT_SIZE(@var{@1@})}, the result is undefined.
+Bits shifted out from the left end or the right end, as the case may be,
+are lost.
+Zeros are shifted in from the opposite end.
+
+@xref{IShftC Intrinsic}, for the circular-shift equivalent.
+")
+
+DEFDOC (ISHFTC, "Circular bit shift.", "\
+The rightmost @var{@3@} bits of the argument @var{@1@}
+are shifted circularly @var{@2@}
+places, i.e.@: the bits shifted out of one end are shifted into
+the opposite end.
+No bits are lost.
+The unshifted bits of the result are the same as
+the unshifted bits of @var{@1@}.
+The absolute value of the argument @var{@2@}
+must be less than or equal to @var{@3@}.
+The value of @var{@3@} must be greater than or equal to one and less than
+or equal to @samp{BIT_SIZE(@var{@1@})}.
+
+@xref{IShft Intrinsic}, for the logical shift equivalent.
+")
+
+DEFDOC (MVBITS, "Moving a bit field.", "\
+Moves @var{@3@} bits from positions @var{@2@} through
+@samp{@var{@2@}+@var{@3@}-1} of @var{@1@} to positions @var{@5@} through
+@samp{@var{@2@}+@var{@3@}-1} of @var{@4@}. The portion of argument
+@var{@4@} not affected by the movement of bits is unchanged. Arguments
+@var{@1@} and @var{@4@} are permitted to be the same numeric storage
+unit. The values of @samp{@var{@2@}+@var{@3@}} and
+@samp{@var{@5@}+@var{@3@}} must be less than or equal to
+@samp{BIT_SIZE(@var{@1@})}.
+")
+
+DEFDOC (INDEX, "Locate a CHARACTER substring.", "\
+Returns the position of the start of the first occurrence of string
+@var{@2@} as a substring in @var{@1@}, counting from one.
+If @var{@2@} doesn't occur in @var{@1@}, zero is returned.
+")
+
+DEFDOC (ALARM, "Execute a routine after a given delay.", "\
+Causes external subroutine @var{@2@} to be executed after a delay of
+@var{@1@} seconds by using @code{alarm(1)} to set up a signal and
+@code{signal(2)} to catch it.
+If @var{@3@} is supplied, it will be
+returned with the number of seconds remaining until any previously
+scheduled alarm was due to be delivered, or zero if there was no
+previously scheduled alarm.
+@xref{Signal Intrinsic (subroutine)}.
+")
+
+DEFDOC (DATE_AND_TIME, "Get the current date and time.", "\
+Returns:
+@table @var
+@item @1@
+The date in the form @var{ccyymmdd}: century, year, month and day;
+@item @2@
+The time in the form @samp{@var{hhmmss.ss}}: hours, minutes, seconds
+and milliseconds;
+@item @3@
+The difference between local time and UTC (GMT) in the form @var{Shhmm}:
+sign, hours and minutes, e.g.@: @samp{-0500} (winter in New York);
+@item @4@
+The year, month of the year, day of the month, time difference in
+minutes from UTC, hour of the day, minutes of the hour, seconds
+of the minute, and milliseconds
+of the second in successive values of the array.
+@end table
+
+On systems where a millisecond timer isn't available, the millisecond
+value is returned as zero.
+")
diff --git a/contrib/gcc/f/intdoc.texi b/contrib/gcc/f/intdoc.texi
new file mode 100644
index 0000000..a507d41
--- /dev/null
+++ b/contrib/gcc/f/intdoc.texi
@@ -0,0 +1,10745 @@
+@c This file is automatically derived from intdoc.c, intdoc.in,
+@c ansify.c, intrin.def, and intrin.h. Edit those files instead.
+@menu
+@ifset familyF2U
+* Abort Intrinsic:: Abort the program.
+@end ifset
+@ifset familyF77
+* Abs Intrinsic:: Absolute value.
+@end ifset
+@ifset familyF2U
+* Access Intrinsic:: Check file accessibility.
+@end ifset
+@ifset familyASC
+* AChar Intrinsic:: ASCII character from code.
+@end ifset
+@ifset familyF77
+* ACos Intrinsic:: Arc cosine.
+@end ifset
+@ifset familyVXT
+* ACosD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF90
+* AdjustL Intrinsic:: (Reserved for future use.)
+* AdjustR Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* AImag Intrinsic:: Convert/extract imaginary part of complex.
+@end ifset
+@ifset familyVXT
+* AIMax0 Intrinsic:: (Reserved for future use.)
+* AIMin0 Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* AInt Intrinsic:: Truncate to whole number.
+@end ifset
+@ifset familyVXT
+* AJMax0 Intrinsic:: (Reserved for future use.)
+* AJMin0 Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* Alarm Intrinsic:: Execute a routine after a given delay.
+@end ifset
+@ifset familyF90
+* All Intrinsic:: (Reserved for future use.)
+* Allocated Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* ALog Intrinsic:: Natural logarithm (archaic).
+* ALog10 Intrinsic:: Common logarithm (archaic).
+* AMax0 Intrinsic:: Maximum value (archaic).
+* AMax1 Intrinsic:: Maximum value (archaic).
+* AMin0 Intrinsic:: Minimum value (archaic).
+* AMin1 Intrinsic:: Minimum value (archaic).
+* AMod Intrinsic:: Remainder (archaic).
+@end ifset
+@ifset familyF2C
+* And Intrinsic:: Boolean AND.
+@end ifset
+@ifset familyF77
+* ANInt Intrinsic:: Round to nearest whole number.
+@end ifset
+@ifset familyF90
+* Any Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* ASin Intrinsic:: Arc sine.
+@end ifset
+@ifset familyVXT
+* ASinD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF90
+* Associated Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* ATan Intrinsic:: Arc tangent.
+* ATan2 Intrinsic:: Arc tangent.
+@end ifset
+@ifset familyVXT
+* ATan2D Intrinsic:: (Reserved for future use.)
+* ATanD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* BesJ0 Intrinsic:: Bessel function.
+* BesJ1 Intrinsic:: Bessel function.
+* BesJN Intrinsic:: Bessel function.
+* BesY0 Intrinsic:: Bessel function.
+* BesY1 Intrinsic:: Bessel function.
+* BesYN Intrinsic:: Bessel function.
+@end ifset
+@ifset familyVXT
+* BITest Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF90
+* Bit_Size Intrinsic:: Number of bits in argument's type.
+@end ifset
+@ifset familyVXT
+* BJTest Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyMIL
+* BTest Intrinsic:: Test bit.
+@end ifset
+@ifset familyF77
+* CAbs Intrinsic:: Absolute value (archaic).
+* CCos Intrinsic:: Cosine (archaic).
+@end ifset
+@ifset familyFVZ
+* CDAbs Intrinsic:: Absolute value (archaic).
+* CDCos Intrinsic:: Cosine (archaic).
+* CDExp Intrinsic:: Exponential (archaic).
+* CDLog Intrinsic:: Natural logarithm (archaic).
+* CDSin Intrinsic:: Sine (archaic).
+* CDSqRt Intrinsic:: Square root (archaic).
+@end ifset
+@ifset familyF90
+* Ceiling Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* CExp Intrinsic:: Exponential (archaic).
+* Char Intrinsic:: Character from code.
+@end ifset
+@ifset familyF2U
+* ChDir Intrinsic (subroutine):: Change directory.
+@end ifset
+@ifset familyBADU77
+* ChDir Intrinsic (function):: Change directory.
+@end ifset
+@ifset familyF2U
+* ChMod Intrinsic (subroutine):: Change file modes.
+@end ifset
+@ifset familyBADU77
+* ChMod Intrinsic (function):: Change file modes.
+@end ifset
+@ifset familyF77
+* CLog Intrinsic:: Natural logarithm (archaic).
+* Cmplx Intrinsic:: Construct @code{COMPLEX(KIND=1)} value.
+@end ifset
+@ifset familyGNU
+* Complex Intrinsic:: Build complex value from real and
+ imaginary parts.
+@end ifset
+@ifset familyF77
+* Conjg Intrinsic:: Complex conjugate.
+* Cos Intrinsic:: Cosine.
+@end ifset
+@ifset familyVXT
+* CosD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* CosH Intrinsic:: Hyperbolic cosine.
+@end ifset
+@ifset familyF90
+* Count Intrinsic:: (Reserved for future use.)
+* CPU_Time Intrinsic:: Get current CPU time.
+* CShift Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* CSin Intrinsic:: Sine (archaic).
+* CSqRt Intrinsic:: Square root (archaic).
+@end ifset
+@ifset familyF2U
+* CTime Intrinsic (subroutine):: Convert time to Day Mon dd hh:mm:ss yyyy.
+* CTime Intrinsic (function):: Convert time to Day Mon dd hh:mm:ss yyyy.
+@end ifset
+@ifset familyF77
+* DAbs Intrinsic:: Absolute value (archaic).
+* DACos Intrinsic:: Arc cosine (archaic).
+@end ifset
+@ifset familyVXT
+* DACosD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* DASin Intrinsic:: Arc sine (archaic).
+@end ifset
+@ifset familyVXT
+* DASinD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* DATan Intrinsic:: Arc tangent (archaic).
+* DATan2 Intrinsic:: Arc tangent (archaic).
+@end ifset
+@ifset familyVXT
+* DATan2D Intrinsic:: (Reserved for future use.)
+* DATanD Intrinsic:: (Reserved for future use.)
+* Date Intrinsic:: Get current date as dd-Mon-yy.
+@end ifset
+@ifset familyF90
+* Date_and_Time Intrinsic:: Get the current date and time.
+@end ifset
+@ifset familyF2U
+* DbesJ0 Intrinsic:: Bessel function (archaic).
+* DbesJ1 Intrinsic:: Bessel function (archaic).
+* DbesJN Intrinsic:: Bessel function (archaic).
+* DbesY0 Intrinsic:: Bessel function (archaic).
+* DbesY1 Intrinsic:: Bessel function (archaic).
+* DbesYN Intrinsic:: Bessel function (archaic).
+@end ifset
+@ifset familyF77
+* Dble Intrinsic:: Convert to double precision.
+@end ifset
+@ifset familyVXT
+* DbleQ Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyFVZ
+* DCmplx Intrinsic:: Construct @code{COMPLEX(KIND=2)} value.
+* DConjg Intrinsic:: Complex conjugate (archaic).
+@end ifset
+@ifset familyF77
+* DCos Intrinsic:: Cosine (archaic).
+@end ifset
+@ifset familyVXT
+* DCosD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* DCosH Intrinsic:: Hyperbolic cosine (archaic).
+* DDiM Intrinsic:: Difference magnitude (archaic).
+@end ifset
+@ifset familyF2U
+* DErF Intrinsic:: Error function (archaic).
+* DErFC Intrinsic:: Complementary error function (archaic).
+@end ifset
+@ifset familyF77
+* DExp Intrinsic:: Exponential (archaic).
+@end ifset
+@ifset familyFVZ
+* DFloat Intrinsic:: Conversion (archaic).
+@end ifset
+@ifset familyVXT
+* DFlotI Intrinsic:: (Reserved for future use.)
+* DFlotJ Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF90
+* Digits Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* DiM Intrinsic:: Difference magnitude (non-negative subtract).
+@end ifset
+@ifset familyFVZ
+* DImag Intrinsic:: Convert/extract imaginary part of complex (archaic).
+@end ifset
+@ifset familyF77
+* DInt Intrinsic:: Truncate to whole number (archaic).
+* DLog Intrinsic:: Natural logarithm (archaic).
+* DLog10 Intrinsic:: Common logarithm (archaic).
+* DMax1 Intrinsic:: Maximum value (archaic).
+* DMin1 Intrinsic:: Minimum value (archaic).
+* DMod Intrinsic:: Remainder (archaic).
+* DNInt Intrinsic:: Round to nearest whole number (archaic).
+@end ifset
+@ifset familyF90
+* Dot_Product Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* DProd Intrinsic:: Double-precision product.
+@end ifset
+@ifset familyVXT
+* DReal Intrinsic:: Convert value to type @code{REAL(KIND=2)}.
+@end ifset
+@ifset familyF77
+* DSign Intrinsic:: Apply sign to magnitude (archaic).
+* DSin Intrinsic:: Sine (archaic).
+@end ifset
+@ifset familyVXT
+* DSinD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* DSinH Intrinsic:: Hyperbolic sine (archaic).
+* DSqRt Intrinsic:: Square root (archaic).
+* DTan Intrinsic:: Tangent (archaic).
+@end ifset
+@ifset familyVXT
+* DTanD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* DTanH Intrinsic:: Hyperbolic tangent (archaic).
+@end ifset
+@ifset familyF2U
+* Dtime Intrinsic (subroutine):: Get elapsed time since last time.
+@end ifset
+@ifset familyBADU77
+* Dtime Intrinsic (function):: Get elapsed time since last time.
+@end ifset
+@ifset familyF90
+* EOShift Intrinsic:: (Reserved for future use.)
+* Epsilon Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* ErF Intrinsic:: Error function.
+* ErFC Intrinsic:: Complementary error function.
+* ETime Intrinsic (subroutine):: Get elapsed time for process.
+* ETime Intrinsic (function):: Get elapsed time for process.
+* Exit Intrinsic:: Terminate the program.
+@end ifset
+@ifset familyF77
+* Exp Intrinsic:: Exponential.
+@end ifset
+@ifset familyF90
+* Exponent Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* Fdate Intrinsic (subroutine):: Get current time as Day Mon dd hh:mm:ss yyyy.
+* Fdate Intrinsic (function):: Get current time as Day Mon dd hh:mm:ss yyyy.
+* FGet Intrinsic (subroutine):: Read a character from unit 5 stream-wise.
+@end ifset
+@ifset familyBADU77
+* FGet Intrinsic (function):: Read a character from unit 5 stream-wise.
+@end ifset
+@ifset familyF2U
+* FGetC Intrinsic (subroutine):: Read a character stream-wise.
+@end ifset
+@ifset familyBADU77
+* FGetC Intrinsic (function):: Read a character stream-wise.
+@end ifset
+@ifset familyF77
+* Float Intrinsic:: Conversion (archaic).
+@end ifset
+@ifset familyVXT
+* FloatI Intrinsic:: (Reserved for future use.)
+* FloatJ Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF90
+* Floor Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* Flush Intrinsic:: Flush buffered output.
+* FNum Intrinsic:: Get file descriptor from Fortran unit number.
+* FPut Intrinsic (subroutine):: Write a character to unit 6 stream-wise.
+@end ifset
+@ifset familyBADU77
+* FPut Intrinsic (function):: Write a character to unit 6 stream-wise.
+@end ifset
+@ifset familyF2U
+* FPutC Intrinsic (subroutine):: Write a character stream-wise.
+@end ifset
+@ifset familyBADU77
+* FPutC Intrinsic (function):: Write a character stream-wise.
+@end ifset
+@ifset familyF90
+* Fraction Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* FSeek Intrinsic:: Position file (low-level).
+* FStat Intrinsic (subroutine):: Get file information.
+* FStat Intrinsic (function):: Get file information.
+* FTell Intrinsic (subroutine):: Get file position (low-level).
+* FTell Intrinsic (function):: Get file position (low-level).
+* GError Intrinsic:: Get error message for last error.
+* GetArg Intrinsic:: Obtain command-line argument.
+* GetCWD Intrinsic (subroutine):: Get current working directory.
+* GetCWD Intrinsic (function):: Get current working directory.
+* GetEnv Intrinsic:: Get environment variable.
+* GetGId Intrinsic:: Get process group id.
+* GetLog Intrinsic:: Get login name.
+* GetPId Intrinsic:: Get process id.
+* GetUId Intrinsic:: Get process user id.
+* GMTime Intrinsic:: Convert time to GMT time info.
+* HostNm Intrinsic (subroutine):: Get host name.
+* HostNm Intrinsic (function):: Get host name.
+@end ifset
+@ifset familyF90
+* Huge Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* IAbs Intrinsic:: Absolute value (archaic).
+@end ifset
+@ifset familyASC
+* IAChar Intrinsic:: ASCII code for character.
+@end ifset
+@ifset familyMIL
+* IAnd Intrinsic:: Boolean AND.
+@end ifset
+@ifset familyF2U
+* IArgC Intrinsic:: Obtain count of command-line arguments.
+@end ifset
+@ifset familyMIL
+* IBClr Intrinsic:: Clear a bit.
+* IBits Intrinsic:: Extract a bit subfield of a variable.
+* IBSet Intrinsic:: Set a bit.
+@end ifset
+@ifset familyF77
+* IChar Intrinsic:: Code for character.
+@end ifset
+@ifset familyF2U
+* IDate Intrinsic (UNIX):: Get local time info.
+@end ifset
+@ifset familyVXT
+* IDate Intrinsic (VXT):: Get local time info (VAX/VMS).
+@end ifset
+@ifset familyF77
+* IDiM Intrinsic:: Difference magnitude (archaic).
+* IDInt Intrinsic:: Convert to @code{INTEGER} value truncated
+ to whole number (archaic).
+* IDNInt Intrinsic:: Convert to @code{INTEGER} value rounded
+ to nearest whole number (archaic).
+@end ifset
+@ifset familyMIL
+* IEOr Intrinsic:: Boolean XOR.
+@end ifset
+@ifset familyF2U
+* IErrNo Intrinsic:: Get error number for last error.
+@end ifset
+@ifset familyF77
+* IFix Intrinsic:: Conversion (archaic).
+@end ifset
+@ifset familyVXT
+* IIAbs Intrinsic:: (Reserved for future use.)
+* IIAnd Intrinsic:: (Reserved for future use.)
+* IIBClr Intrinsic:: (Reserved for future use.)
+* IIBits Intrinsic:: (Reserved for future use.)
+* IIBSet Intrinsic:: (Reserved for future use.)
+* IIDiM Intrinsic:: (Reserved for future use.)
+* IIDInt Intrinsic:: (Reserved for future use.)
+* IIDNnt Intrinsic:: (Reserved for future use.)
+* IIEOr Intrinsic:: (Reserved for future use.)
+* IIFix Intrinsic:: (Reserved for future use.)
+* IInt Intrinsic:: (Reserved for future use.)
+* IIOr Intrinsic:: (Reserved for future use.)
+* IIQint Intrinsic:: (Reserved for future use.)
+* IIQNnt Intrinsic:: (Reserved for future use.)
+* IIShftC Intrinsic:: (Reserved for future use.)
+* IISign Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2C
+* Imag Intrinsic:: Extract imaginary part of complex.
+@end ifset
+@ifset familyGNU
+* ImagPart Intrinsic:: Extract imaginary part of complex.
+@end ifset
+@ifset familyVXT
+* IMax0 Intrinsic:: (Reserved for future use.)
+* IMax1 Intrinsic:: (Reserved for future use.)
+* IMin0 Intrinsic:: (Reserved for future use.)
+* IMin1 Intrinsic:: (Reserved for future use.)
+* IMod Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* Index Intrinsic:: Locate a CHARACTER substring.
+@end ifset
+@ifset familyVXT
+* INInt Intrinsic:: (Reserved for future use.)
+* INot Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* Int Intrinsic:: Convert to @code{INTEGER} value truncated
+ to whole number.
+@end ifset
+@ifset familyGNU
+* Int2 Intrinsic:: Convert to @code{INTEGER(KIND=6)} value
+ truncated to whole number.
+* Int8 Intrinsic:: Convert to @code{INTEGER(KIND=2)} value
+ truncated to whole number.
+@end ifset
+@ifset familyMIL
+* IOr Intrinsic:: Boolean OR.
+@end ifset
+@ifset familyF2U
+* IRand Intrinsic:: Random number.
+* IsaTty Intrinsic:: Is unit connected to a terminal?
+@end ifset
+@ifset familyMIL
+* IShft Intrinsic:: Logical bit shift.
+* IShftC Intrinsic:: Circular bit shift.
+@end ifset
+@ifset familyF77
+* ISign Intrinsic:: Apply sign to magnitude (archaic).
+@end ifset
+@ifset familyF2U
+* ITime Intrinsic:: Get local time of day.
+@end ifset
+@ifset familyVXT
+* IZExt Intrinsic:: (Reserved for future use.)
+* JIAbs Intrinsic:: (Reserved for future use.)
+* JIAnd Intrinsic:: (Reserved for future use.)
+* JIBClr Intrinsic:: (Reserved for future use.)
+* JIBits Intrinsic:: (Reserved for future use.)
+* JIBSet Intrinsic:: (Reserved for future use.)
+* JIDiM Intrinsic:: (Reserved for future use.)
+* JIDInt Intrinsic:: (Reserved for future use.)
+* JIDNnt Intrinsic:: (Reserved for future use.)
+* JIEOr Intrinsic:: (Reserved for future use.)
+* JIFix Intrinsic:: (Reserved for future use.)
+* JInt Intrinsic:: (Reserved for future use.)
+* JIOr Intrinsic:: (Reserved for future use.)
+* JIQint Intrinsic:: (Reserved for future use.)
+* JIQNnt Intrinsic:: (Reserved for future use.)
+* JIShft Intrinsic:: (Reserved for future use.)
+* JIShftC Intrinsic:: (Reserved for future use.)
+* JISign Intrinsic:: (Reserved for future use.)
+* JMax0 Intrinsic:: (Reserved for future use.)
+* JMax1 Intrinsic:: (Reserved for future use.)
+* JMin0 Intrinsic:: (Reserved for future use.)
+* JMin1 Intrinsic:: (Reserved for future use.)
+* JMod Intrinsic:: (Reserved for future use.)
+* JNInt Intrinsic:: (Reserved for future use.)
+* JNot Intrinsic:: (Reserved for future use.)
+* JZExt Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* Kill Intrinsic (subroutine):: Signal a process.
+@end ifset
+@ifset familyBADU77
+* Kill Intrinsic (function):: Signal a process.
+@end ifset
+@ifset familyF90
+* Kind Intrinsic:: (Reserved for future use.)
+* LBound Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* Len Intrinsic:: Length of character entity.
+@end ifset
+@ifset familyF90
+* Len_Trim Intrinsic:: Get last non-blank character in string.
+@end ifset
+@ifset familyF77
+* LGe Intrinsic:: Lexically greater than or equal.
+* LGt Intrinsic:: Lexically greater than.
+@end ifset
+@ifset familyF2U
+* Link Intrinsic (subroutine):: Make hard link in file system.
+@end ifset
+@ifset familyBADU77
+* Link Intrinsic (function):: Make hard link in file system.
+@end ifset
+@ifset familyF77
+* LLe Intrinsic:: Lexically less than or equal.
+* LLt Intrinsic:: Lexically less than.
+@end ifset
+@ifset familyF2U
+* LnBlnk Intrinsic:: Get last non-blank character in string.
+* Loc Intrinsic:: Address of entity in core.
+@end ifset
+@ifset familyF77
+* Log Intrinsic:: Natural logarithm.
+* Log10 Intrinsic:: Common logarithm.
+@end ifset
+@ifset familyF90
+* Logical Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* Long Intrinsic:: Conversion to @code{INTEGER(KIND=1)} (archaic).
+@end ifset
+@ifset familyF2C
+* LShift Intrinsic:: Left-shift bits.
+@end ifset
+@ifset familyF2U
+* LStat Intrinsic (subroutine):: Get file information.
+* LStat Intrinsic (function):: Get file information.
+* LTime Intrinsic:: Convert time to local time info.
+@end ifset
+@ifset familyF90
+* MatMul Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* Max Intrinsic:: Maximum value.
+* Max0 Intrinsic:: Maximum value (archaic).
+* Max1 Intrinsic:: Maximum value (archaic).
+@end ifset
+@ifset familyF90
+* MaxExponent Intrinsic:: (Reserved for future use.)
+* MaxLoc Intrinsic:: (Reserved for future use.)
+* MaxVal Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* MClock Intrinsic:: Get number of clock ticks for process.
+* MClock8 Intrinsic:: Get number of clock ticks for process.
+@end ifset
+@ifset familyF90
+* Merge Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* Min Intrinsic:: Minimum value.
+* Min0 Intrinsic:: Minimum value (archaic).
+* Min1 Intrinsic:: Minimum value (archaic).
+@end ifset
+@ifset familyF90
+* MinExponent Intrinsic:: (Reserved for future use.)
+* MinLoc Intrinsic:: (Reserved for future use.)
+* MinVal Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* Mod Intrinsic:: Remainder.
+@end ifset
+@ifset familyF90
+* Modulo Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyMIL
+* MvBits Intrinsic:: Moving a bit field.
+@end ifset
+@ifset familyF90
+* Nearest Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* NInt Intrinsic:: Convert to @code{INTEGER} value rounded
+ to nearest whole number.
+@end ifset
+@ifset familyMIL
+* Not Intrinsic:: Boolean NOT.
+@end ifset
+@ifset familyF2C
+* Or Intrinsic:: Boolean OR.
+@end ifset
+@ifset familyF90
+* Pack Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* PError Intrinsic:: Print error message for last error.
+@end ifset
+@ifset familyF90
+* Precision Intrinsic:: (Reserved for future use.)
+* Present Intrinsic:: (Reserved for future use.)
+* Product Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyVXT
+* QAbs Intrinsic:: (Reserved for future use.)
+* QACos Intrinsic:: (Reserved for future use.)
+* QACosD Intrinsic:: (Reserved for future use.)
+* QASin Intrinsic:: (Reserved for future use.)
+* QASinD Intrinsic:: (Reserved for future use.)
+* QATan Intrinsic:: (Reserved for future use.)
+* QATan2 Intrinsic:: (Reserved for future use.)
+* QATan2D Intrinsic:: (Reserved for future use.)
+* QATanD Intrinsic:: (Reserved for future use.)
+* QCos Intrinsic:: (Reserved for future use.)
+* QCosD Intrinsic:: (Reserved for future use.)
+* QCosH Intrinsic:: (Reserved for future use.)
+* QDiM Intrinsic:: (Reserved for future use.)
+* QExp Intrinsic:: (Reserved for future use.)
+* QExt Intrinsic:: (Reserved for future use.)
+* QExtD Intrinsic:: (Reserved for future use.)
+* QFloat Intrinsic:: (Reserved for future use.)
+* QInt Intrinsic:: (Reserved for future use.)
+* QLog Intrinsic:: (Reserved for future use.)
+* QLog10 Intrinsic:: (Reserved for future use.)
+* QMax1 Intrinsic:: (Reserved for future use.)
+* QMin1 Intrinsic:: (Reserved for future use.)
+* QMod Intrinsic:: (Reserved for future use.)
+* QNInt Intrinsic:: (Reserved for future use.)
+* QSin Intrinsic:: (Reserved for future use.)
+* QSinD Intrinsic:: (Reserved for future use.)
+* QSinH Intrinsic:: (Reserved for future use.)
+* QSqRt Intrinsic:: (Reserved for future use.)
+* QTan Intrinsic:: (Reserved for future use.)
+* QTanD Intrinsic:: (Reserved for future use.)
+* QTanH Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF90
+* Radix Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* Rand Intrinsic:: Random number.
+@end ifset
+@ifset familyF90
+* Random_Number Intrinsic:: (Reserved for future use.)
+* Random_Seed Intrinsic:: (Reserved for future use.)
+* Range Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* Real Intrinsic:: Convert value to type @code{REAL(KIND=1)}.
+@end ifset
+@ifset familyGNU
+* RealPart Intrinsic:: Extract real part of complex.
+@end ifset
+@ifset familyF2U
+* Rename Intrinsic (subroutine):: Rename file.
+@end ifset
+@ifset familyBADU77
+* Rename Intrinsic (function):: Rename file.
+@end ifset
+@ifset familyF90
+* Repeat Intrinsic:: (Reserved for future use.)
+* Reshape Intrinsic:: (Reserved for future use.)
+* RRSpacing Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2C
+* RShift Intrinsic:: Right-shift bits.
+@end ifset
+@ifset familyF90
+* Scale Intrinsic:: (Reserved for future use.)
+* Scan Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyVXT
+* Secnds Intrinsic:: Get local time offset since midnight.
+@end ifset
+@ifset familyF2U
+* Second Intrinsic (function):: Get CPU time for process in seconds.
+* Second Intrinsic (subroutine):: Get CPU time for process
+ in seconds.
+@end ifset
+@ifset familyF90
+* Selected_Int_Kind Intrinsic:: (Reserved for future use.)
+* Selected_Real_Kind Intrinsic:: (Reserved for future use.)
+* Set_Exponent Intrinsic:: (Reserved for future use.)
+* Shape Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* Short Intrinsic:: Convert to @code{INTEGER(KIND=6)} value
+ truncated to whole number.
+@end ifset
+@ifset familyF77
+* Sign Intrinsic:: Apply sign to magnitude.
+@end ifset
+@ifset familyF2U
+* Signal Intrinsic (subroutine):: Muck with signal handling.
+@end ifset
+@ifset familyBADU77
+* Signal Intrinsic (function):: Muck with signal handling.
+@end ifset
+@ifset familyF77
+* Sin Intrinsic:: Sine.
+@end ifset
+@ifset familyVXT
+* SinD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* SinH Intrinsic:: Hyperbolic sine.
+@end ifset
+@ifset familyF2U
+* Sleep Intrinsic:: Sleep for a specified time.
+@end ifset
+@ifset familyF77
+* Sngl Intrinsic:: Convert (archaic).
+@end ifset
+@ifset familyVXT
+* SnglQ Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF90
+* Spacing Intrinsic:: (Reserved for future use.)
+* Spread Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* SqRt Intrinsic:: Square root.
+@end ifset
+@ifset familyF2U
+* SRand Intrinsic:: Random seed.
+* Stat Intrinsic (subroutine):: Get file information.
+* Stat Intrinsic (function):: Get file information.
+@end ifset
+@ifset familyF90
+* Sum Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* SymLnk Intrinsic (subroutine):: Make symbolic link in file system.
+@end ifset
+@ifset familyBADU77
+* SymLnk Intrinsic (function):: Make symbolic link in file system.
+@end ifset
+@ifset familyF2U
+* System Intrinsic (subroutine):: Invoke shell (system) command.
+@end ifset
+@ifset familyBADU77
+* System Intrinsic (function):: Invoke shell (system) command.
+@end ifset
+@ifset familyF90
+* System_Clock Intrinsic:: Get current system clock value.
+@end ifset
+@ifset familyF77
+* Tan Intrinsic:: Tangent.
+@end ifset
+@ifset familyVXT
+* TanD Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF77
+* TanH Intrinsic:: Hyperbolic tangent.
+@end ifset
+@ifset familyF2U
+* Time Intrinsic (UNIX):: Get current time as time value.
+@end ifset
+@ifset familyVXT
+* Time Intrinsic (VXT):: Get the time as a character value.
+@end ifset
+@ifset familyF2U
+* Time8 Intrinsic:: Get current time as time value.
+@end ifset
+@ifset familyF90
+* Tiny Intrinsic:: (Reserved for future use.)
+* Transfer Intrinsic:: (Reserved for future use.)
+* Transpose Intrinsic:: (Reserved for future use.)
+* Trim Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* TtyNam Intrinsic (subroutine):: Get name of terminal device for unit.
+* TtyNam Intrinsic (function):: Get name of terminal device for unit.
+@end ifset
+@ifset familyF90
+* UBound Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2U
+* UMask Intrinsic (subroutine):: Set file creation permissions mask.
+@end ifset
+@ifset familyBADU77
+* UMask Intrinsic (function):: Set file creation permissions mask.
+@end ifset
+@ifset familyF2U
+* Unlink Intrinsic (subroutine):: Unlink file.
+@end ifset
+@ifset familyBADU77
+* Unlink Intrinsic (function):: Unlink file.
+@end ifset
+@ifset familyF90
+* Unpack Intrinsic:: (Reserved for future use.)
+* Verify Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2C
+* XOr Intrinsic:: Boolean XOR.
+* ZAbs Intrinsic:: Absolute value (archaic).
+* ZCos Intrinsic:: Cosine (archaic).
+* ZExp Intrinsic:: Exponential (archaic).
+@end ifset
+@ifset familyVXT
+* ZExt Intrinsic:: (Reserved for future use.)
+@end ifset
+@ifset familyF2C
+* ZLog Intrinsic:: Natural logarithm (archaic).
+* ZSin Intrinsic:: Sine (archaic).
+* ZSqRt Intrinsic:: Square root (archaic).
+@end ifset
+@end menu
+
+@ifset familyF2U
+@node Abort Intrinsic
+@subsubsection Abort Intrinsic
+@cindex Abort intrinsic
+@cindex intrinsics, Abort
+
+@noindent
+@example
+CALL Abort()
+@end example
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Prints a message and potentially causes a core dump via @code{abort(3)}.
+
+@end ifset
+@ifset familyF77
+@node Abs Intrinsic
+@subsubsection Abs Intrinsic
+@cindex Abs intrinsic
+@cindex intrinsics, Abs
+
+@noindent
+@example
+Abs(@var{A})
+@end example
+
+@noindent
+Abs: @code{INTEGER} or @code{REAL} function.
+The exact type depends on that of argument @var{A}---if @var{A} is
+@code{COMPLEX}, this function's type is @code{REAL}
+with the same @samp{KIND=} value as the type of @var{A}.
+Otherwise, this function's type is the same as that of @var{A}.
+
+@noindent
+@var{A}: @code{INTEGER}, @code{REAL}, or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the absolute value of @var{A}.
+
+If @var{A} is type @code{COMPLEX}, the absolute
+value is computed as:
+
+@example
+SQRT(REALPART(@var{A})**2, IMAGPART(@var{A})**2)
+@end example
+
+@noindent
+Otherwise, it is computed by negating the @var{A} if
+it is negative, or returning @var{A}.
+
+@xref{Sign Intrinsic}, for how to explicitly
+compute the positive or negative form of the absolute
+value of an expression.
+
+@end ifset
+@ifset familyF2U
+@node Access Intrinsic
+@subsubsection Access Intrinsic
+@cindex Access intrinsic
+@cindex intrinsics, Access
+
+@noindent
+@example
+Access(@var{Name}, @var{Mode})
+@end example
+
+@noindent
+Access: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Name}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Mode}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Checks file @var{Name} for accessibility in the mode specified by @var{Mode} and
+returns 0 if the file is accessible in that mode, otherwise an error
+code if the file is inaccessible or @var{Mode} is invalid.
+See @code{access(2)}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{Name}---otherwise,
+trailing blanks in @var{Name} are ignored.
+@var{Mode} may be a concatenation of any of the following characters:
+
+@table @samp
+@item r
+Read permission
+
+@item w
+Write permission
+
+@item x
+Execute permission
+
+@item @kbd{SPC}
+Existence
+@end table
+
+@end ifset
+@ifset familyASC
+@node AChar Intrinsic
+@subsubsection AChar Intrinsic
+@cindex AChar intrinsic
+@cindex intrinsics, AChar
+
+@noindent
+@example
+AChar(@var{I})
+@end example
+
+@noindent
+AChar: @code{CHARACTER*1} function.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{f90}.
+
+@noindent
+Description:
+
+Returns the ASCII character corresponding to the
+code specified by @var{I}.
+
+@xref{IAChar Intrinsic}, for the inverse of this function.
+
+@xref{Char Intrinsic}, for the function corresponding
+to the system's native character set.
+
+@end ifset
+@ifset familyF77
+@node ACos Intrinsic
+@subsubsection ACos Intrinsic
+@cindex ACos intrinsic
+@cindex intrinsics, ACos
+
+@noindent
+@example
+ACos(@var{X})
+@end example
+
+@noindent
+ACos: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the arc-cosine (inverse cosine) of @var{X}
+in radians.
+
+@xref{Cos Intrinsic}, for the inverse of this function.
+
+@end ifset
+@ifset familyVXT
+@node ACosD Intrinsic
+@subsubsection ACosD Intrinsic
+@cindex ACosD intrinsic
+@cindex intrinsics, ACosD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL ACosD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF90
+@node AdjustL Intrinsic
+@subsubsection AdjustL Intrinsic
+@cindex AdjustL intrinsic
+@cindex intrinsics, AdjustL
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL AdjustL} to use this name for an
+external procedure.
+
+@node AdjustR Intrinsic
+@subsubsection AdjustR Intrinsic
+@cindex AdjustR intrinsic
+@cindex intrinsics, AdjustR
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL AdjustR} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node AImag Intrinsic
+@subsubsection AImag Intrinsic
+@cindex AImag intrinsic
+@cindex intrinsics, AImag
+
+@noindent
+@example
+AImag(@var{Z})
+@end example
+
+@noindent
+AImag: @code{REAL} function.
+This intrinsic is valid when argument @var{Z} is
+@code{COMPLEX(KIND=1)}.
+When @var{Z} is any other @code{COMPLEX} type,
+this intrinsic is valid only when used as the argument to
+@code{REAL()}, as explained below.
+
+@noindent
+@var{Z}: @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the (possibly converted) imaginary part of @var{Z}.
+
+Use of @code{AIMAG()} with an argument of a type
+other than @code{COMPLEX(KIND=1)} is restricted to the following case:
+
+@example
+REAL(AIMAG(Z))
+@end example
+
+@noindent
+This expression converts the imaginary part of Z to
+@code{REAL(KIND=1)}.
+
+@xref{REAL() and AIMAG() of Complex}, for more information.
+
+@end ifset
+@ifset familyVXT
+@node AIMax0 Intrinsic
+@subsubsection AIMax0 Intrinsic
+@cindex AIMax0 intrinsic
+@cindex intrinsics, AIMax0
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL AIMax0} to use this name for an
+external procedure.
+
+@node AIMin0 Intrinsic
+@subsubsection AIMin0 Intrinsic
+@cindex AIMin0 intrinsic
+@cindex intrinsics, AIMin0
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL AIMin0} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node AInt Intrinsic
+@subsubsection AInt Intrinsic
+@cindex AInt intrinsic
+@cindex intrinsics, AInt
+
+@noindent
+@example
+AInt(@var{A})
+@end example
+
+@noindent
+AInt: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{A}.
+
+@noindent
+@var{A}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @var{A} with the fractional portion of its
+magnitude truncated and its sign preserved.
+(Also called ``truncation towards zero''.)
+
+@xref{ANInt Intrinsic}, for how to round to nearest
+whole number.
+
+@xref{Int Intrinsic}, for how to truncate and then convert
+number to @code{INTEGER}.
+
+@end ifset
+@ifset familyVXT
+@node AJMax0 Intrinsic
+@subsubsection AJMax0 Intrinsic
+@cindex AJMax0 intrinsic
+@cindex intrinsics, AJMax0
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL AJMax0} to use this name for an
+external procedure.
+
+@node AJMin0 Intrinsic
+@subsubsection AJMin0 Intrinsic
+@cindex AJMin0 intrinsic
+@cindex intrinsics, AJMin0
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL AJMin0} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node Alarm Intrinsic
+@subsubsection Alarm Intrinsic
+@cindex Alarm intrinsic
+@cindex intrinsics, Alarm
+
+@noindent
+@example
+CALL Alarm(@var{Seconds}, @var{Handler}, @var{Status})
+@end example
+
+@noindent
+@var{Seconds}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Handler}: Signal handler (@code{INTEGER FUNCTION} or @code{SUBROUTINE})
+or dummy/global @code{INTEGER(KIND=1)} scalar.
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Causes external subroutine @var{Handler} to be executed after a delay of
+@var{Seconds} seconds by using @code{alarm(1)} to set up a signal and
+@code{signal(2)} to catch it.
+If @var{Status} is supplied, it will be
+returned with the number of seconds remaining until any previously
+scheduled alarm was due to be delivered, or zero if there was no
+previously scheduled alarm.
+@xref{Signal Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF90
+@node All Intrinsic
+@subsubsection All Intrinsic
+@cindex All intrinsic
+@cindex intrinsics, All
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL All} to use this name for an
+external procedure.
+
+@node Allocated Intrinsic
+@subsubsection Allocated Intrinsic
+@cindex Allocated intrinsic
+@cindex intrinsics, Allocated
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Allocated} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node ALog Intrinsic
+@subsubsection ALog Intrinsic
+@cindex ALog intrinsic
+@cindex intrinsics, ALog
+
+@noindent
+@example
+ALog(@var{X})
+@end example
+
+@noindent
+ALog: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{LOG()} that is specific
+to one type for @var{X}.
+@xref{Log Intrinsic}.
+
+@node ALog10 Intrinsic
+@subsubsection ALog10 Intrinsic
+@cindex ALog10 intrinsic
+@cindex intrinsics, ALog10
+
+@noindent
+@example
+ALog10(@var{X})
+@end example
+
+@noindent
+ALog10: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{LOG10()} that is specific
+to one type for @var{X}.
+@xref{Log10 Intrinsic}.
+
+@node AMax0 Intrinsic
+@subsubsection AMax0 Intrinsic
+@cindex AMax0 intrinsic
+@cindex intrinsics, AMax0
+
+@noindent
+@example
+AMax0(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+AMax0: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{A}: @code{INTEGER(KIND=1)}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MAX()} that is specific
+to one type for @var{A} and a different return type.
+@xref{Max Intrinsic}.
+
+@node AMax1 Intrinsic
+@subsubsection AMax1 Intrinsic
+@cindex AMax1 intrinsic
+@cindex intrinsics, AMax1
+
+@noindent
+@example
+AMax1(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+AMax1: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=1)}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MAX()} that is specific
+to one type for @var{A}.
+@xref{Max Intrinsic}.
+
+@node AMin0 Intrinsic
+@subsubsection AMin0 Intrinsic
+@cindex AMin0 intrinsic
+@cindex intrinsics, AMin0
+
+@noindent
+@example
+AMin0(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+AMin0: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{A}: @code{INTEGER(KIND=1)}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MIN()} that is specific
+to one type for @var{A} and a different return type.
+@xref{Min Intrinsic}.
+
+@node AMin1 Intrinsic
+@subsubsection AMin1 Intrinsic
+@cindex AMin1 intrinsic
+@cindex intrinsics, AMin1
+
+@noindent
+@example
+AMin1(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+AMin1: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=1)}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MIN()} that is specific
+to one type for @var{A}.
+@xref{Min Intrinsic}.
+
+@node AMod Intrinsic
+@subsubsection AMod Intrinsic
+@cindex AMod intrinsic
+@cindex intrinsics, AMod
+
+@noindent
+@example
+AMod(@var{A}, @var{P})
+@end example
+
+@noindent
+AMod: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+@var{P}: @code{REAL(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MOD()} that is specific
+to one type for @var{A}.
+@xref{Mod Intrinsic}.
+
+@end ifset
+@ifset familyF2C
+@node And Intrinsic
+@subsubsection And Intrinsic
+@cindex And intrinsic
+@cindex intrinsics, And
+
+@noindent
+@example
+And(@var{I}, @var{J})
+@end example
+
+@noindent
+And: @code{INTEGER} or @code{LOGICAL} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{I}: @code{INTEGER} or @code{LOGICAL}; scalar; INTENT(IN).
+
+@noindent
+@var{J}: @code{INTEGER} or @code{LOGICAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Returns value resulting from boolean AND of
+pair of bits in each of @var{I} and @var{J}.
+
+@end ifset
+@ifset familyF77
+@node ANInt Intrinsic
+@subsubsection ANInt Intrinsic
+@cindex ANInt intrinsic
+@cindex intrinsics, ANInt
+
+@noindent
+@example
+ANInt(@var{A})
+@end example
+
+@noindent
+ANInt: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{A}.
+
+@noindent
+@var{A}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @var{A} with the fractional portion of its
+magnitude eliminated by rounding to the nearest whole
+number and with its sign preserved.
+
+A fractional portion exactly equal to
+@samp{.5} is rounded to the whole number that
+is larger in magnitude.
+(Also called ``Fortran round''.)
+
+@xref{AInt Intrinsic}, for how to truncate to
+whole number.
+
+@xref{NInt Intrinsic}, for how to round and then convert
+number to @code{INTEGER}.
+
+@end ifset
+@ifset familyF90
+@node Any Intrinsic
+@subsubsection Any Intrinsic
+@cindex Any intrinsic
+@cindex intrinsics, Any
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Any} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node ASin Intrinsic
+@subsubsection ASin Intrinsic
+@cindex ASin intrinsic
+@cindex intrinsics, ASin
+
+@noindent
+@example
+ASin(@var{X})
+@end example
+
+@noindent
+ASin: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the arc-sine (inverse sine) of @var{X}
+in radians.
+
+@xref{Sin Intrinsic}, for the inverse of this function.
+
+@end ifset
+@ifset familyVXT
+@node ASinD Intrinsic
+@subsubsection ASinD Intrinsic
+@cindex ASinD intrinsic
+@cindex intrinsics, ASinD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL ASinD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF90
+@node Associated Intrinsic
+@subsubsection Associated Intrinsic
+@cindex Associated intrinsic
+@cindex intrinsics, Associated
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Associated} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node ATan Intrinsic
+@subsubsection ATan Intrinsic
+@cindex ATan intrinsic
+@cindex intrinsics, ATan
+
+@noindent
+@example
+ATan(@var{X})
+@end example
+
+@noindent
+ATan: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the arc-tangent (inverse tangent) of @var{X}
+in radians.
+
+@xref{Tan Intrinsic}, for the inverse of this function.
+
+@node ATan2 Intrinsic
+@subsubsection ATan2 Intrinsic
+@cindex ATan2 intrinsic
+@cindex intrinsics, ATan2
+
+@noindent
+@example
+ATan2(@var{Y}, @var{X})
+@end example
+
+@noindent
+ATan2: @code{REAL} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{Y}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the arc-tangent (inverse tangent) of the complex
+number (@var{Y}, @var{X}) in radians.
+
+@xref{Tan Intrinsic}, for the inverse of this function.
+
+@end ifset
+@ifset familyVXT
+@node ATan2D Intrinsic
+@subsubsection ATan2D Intrinsic
+@cindex ATan2D intrinsic
+@cindex intrinsics, ATan2D
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL ATan2D} to use this name for an
+external procedure.
+
+@node ATanD Intrinsic
+@subsubsection ATanD Intrinsic
+@cindex ATanD intrinsic
+@cindex intrinsics, ATanD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL ATanD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node BesJ0 Intrinsic
+@subsubsection BesJ0 Intrinsic
+@cindex BesJ0 intrinsic
+@cindex intrinsics, BesJ0
+
+@noindent
+@example
+BesJ0(@var{X})
+@end example
+
+@noindent
+BesJ0: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Calculates the Bessel function of the first kind of order 0 of @var{X}.
+See @code{bessel(3m)}, on whose implementation the function depends.
+@node BesJ1 Intrinsic
+@subsubsection BesJ1 Intrinsic
+@cindex BesJ1 intrinsic
+@cindex intrinsics, BesJ1
+
+@noindent
+@example
+BesJ1(@var{X})
+@end example
+
+@noindent
+BesJ1: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Calculates the Bessel function of the first kind of order 1 of @var{X}.
+See @code{bessel(3m)}, on whose implementation the function depends.
+@node BesJN Intrinsic
+@subsubsection BesJN Intrinsic
+@cindex BesJN intrinsic
+@cindex intrinsics, BesJN
+
+@noindent
+@example
+BesJN(@var{N}, @var{X})
+@end example
+
+@noindent
+BesJN: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{N}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Calculates the Bessel function of the first kind of order @var{N} of @var{X}.
+See @code{bessel(3m)}, on whose implementation the function depends.
+@node BesY0 Intrinsic
+@subsubsection BesY0 Intrinsic
+@cindex BesY0 intrinsic
+@cindex intrinsics, BesY0
+
+@noindent
+@example
+BesY0(@var{X})
+@end example
+
+@noindent
+BesY0: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Calculates the Bessel function of the second kind of order 0 of @var{X}.
+See @code{bessel(3m)}, on whose implementation the function depends.
+@node BesY1 Intrinsic
+@subsubsection BesY1 Intrinsic
+@cindex BesY1 intrinsic
+@cindex intrinsics, BesY1
+
+@noindent
+@example
+BesY1(@var{X})
+@end example
+
+@noindent
+BesY1: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Calculates the Bessel function of the second kind of order 1 of @var{X}.
+See @code{bessel(3m)}, on whose implementation the function depends.
+@node BesYN Intrinsic
+@subsubsection BesYN Intrinsic
+@cindex BesYN intrinsic
+@cindex intrinsics, BesYN
+
+@noindent
+@example
+BesYN(@var{N}, @var{X})
+@end example
+
+@noindent
+BesYN: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{N}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Calculates the Bessel function of the second kind of order @var{N} of @var{X}.
+See @code{bessel(3m)}, on whose implementation the function depends.
+@end ifset
+@ifset familyVXT
+@node BITest Intrinsic
+@subsubsection BITest Intrinsic
+@cindex BITest intrinsic
+@cindex intrinsics, BITest
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL BITest} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF90
+@node Bit_Size Intrinsic
+@subsubsection Bit_Size Intrinsic
+@cindex Bit_Size intrinsic
+@cindex intrinsics, Bit_Size
+
+@noindent
+@example
+Bit_Size(@var{I})
+@end example
+
+@noindent
+Bit_Size: @code{INTEGER} function, the @samp{KIND=} value of the type being that of argument @var{I}.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar.
+
+@noindent
+Intrinsic groups: @code{f90}.
+
+@noindent
+Description:
+
+Returns the number of bits (integer precision plus sign bit)
+represented by the type for @var{I}.
+
+@xref{BTest Intrinsic}, for how to test the value of a
+bit in a variable or array.
+
+@xref{IBSet Intrinsic}, for how to set a bit in a variable to 1.
+
+@xref{IBClr Intrinsic}, for how to set a bit in a variable to 0.
+
+
+@end ifset
+@ifset familyVXT
+@node BJTest Intrinsic
+@subsubsection BJTest Intrinsic
+@cindex BJTest intrinsic
+@cindex intrinsics, BJTest
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL BJTest} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyMIL
+@node BTest Intrinsic
+@subsubsection BTest Intrinsic
+@cindex BTest intrinsic
+@cindex intrinsics, BTest
+
+@noindent
+@example
+BTest(@var{I}, @var{Pos})
+@end example
+
+@noindent
+BTest: @code{LOGICAL(KIND=1)} function.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Pos}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+Returns @code{.TRUE.} if bit @var{Pos} in @var{I} is
+1, @code{.FALSE.} otherwise.
+
+(Bit 0 is the low-order (rightmost) bit, adding the value
+@ifinfo
+2**0,
+@end ifinfo
+@iftex
+@tex
+$2^0$,
+@end tex
+@end iftex
+or 1,
+to the number if set to 1;
+bit 1 is the next-higher-order bit, adding
+@ifinfo
+2**1,
+@end ifinfo
+@iftex
+@tex
+$2^1$,
+@end tex
+@end iftex
+or 2;
+bit 2 adds
+@ifinfo
+2**2,
+@end ifinfo
+@iftex
+@tex
+$2^2$,
+@end tex
+@end iftex
+or 4; and so on.)
+
+@xref{Bit_Size Intrinsic}, for how to obtain the number of bits
+in a type.
+The leftmost bit of @var{I} is @samp{BIT_SIZE(@var{I}-1)}.
+
+@end ifset
+@ifset familyF77
+@node CAbs Intrinsic
+@subsubsection CAbs Intrinsic
+@cindex CAbs intrinsic
+@cindex intrinsics, CAbs
+
+@noindent
+@example
+CAbs(@var{A})
+@end example
+
+@noindent
+CAbs: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{A}: @code{COMPLEX(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{ABS()} that is specific
+to one type for @var{A}.
+@xref{Abs Intrinsic}.
+
+@node CCos Intrinsic
+@subsubsection CCos Intrinsic
+@cindex CCos intrinsic
+@cindex intrinsics, CCos
+
+@noindent
+@example
+CCos(@var{X})
+@end example
+
+@noindent
+CCos: @code{COMPLEX(KIND=1)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{COS()} that is specific
+to one type for @var{X}.
+@xref{Cos Intrinsic}.
+
+@end ifset
+@ifset familyFVZ
+@node CDAbs Intrinsic
+@subsubsection CDAbs Intrinsic
+@cindex CDAbs intrinsic
+@cindex intrinsics, CDAbs
+
+@noindent
+@example
+CDAbs(@var{A})
+@end example
+
+@noindent
+CDAbs: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{vxt}.
+
+@noindent
+Description:
+
+Archaic form of @code{ABS()} that is specific
+to one type for @var{A}.
+@xref{Abs Intrinsic}.
+
+@node CDCos Intrinsic
+@subsubsection CDCos Intrinsic
+@cindex CDCos intrinsic
+@cindex intrinsics, CDCos
+
+@noindent
+@example
+CDCos(@var{X})
+@end example
+
+@noindent
+CDCos: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{vxt}.
+
+@noindent
+Description:
+
+Archaic form of @code{COS()} that is specific
+to one type for @var{X}.
+@xref{Cos Intrinsic}.
+
+@node CDExp Intrinsic
+@subsubsection CDExp Intrinsic
+@cindex CDExp intrinsic
+@cindex intrinsics, CDExp
+
+@noindent
+@example
+CDExp(@var{X})
+@end example
+
+@noindent
+CDExp: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{vxt}.
+
+@noindent
+Description:
+
+Archaic form of @code{EXP()} that is specific
+to one type for @var{X}.
+@xref{Exp Intrinsic}.
+
+@node CDLog Intrinsic
+@subsubsection CDLog Intrinsic
+@cindex CDLog intrinsic
+@cindex intrinsics, CDLog
+
+@noindent
+@example
+CDLog(@var{X})
+@end example
+
+@noindent
+CDLog: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{vxt}.
+
+@noindent
+Description:
+
+Archaic form of @code{LOG()} that is specific
+to one type for @var{X}.
+@xref{Log Intrinsic}.
+
+@node CDSin Intrinsic
+@subsubsection CDSin Intrinsic
+@cindex CDSin intrinsic
+@cindex intrinsics, CDSin
+
+@noindent
+@example
+CDSin(@var{X})
+@end example
+
+@noindent
+CDSin: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{vxt}.
+
+@noindent
+Description:
+
+Archaic form of @code{SIN()} that is specific
+to one type for @var{X}.
+@xref{Sin Intrinsic}.
+
+@node CDSqRt Intrinsic
+@subsubsection CDSqRt Intrinsic
+@cindex CDSqRt intrinsic
+@cindex intrinsics, CDSqRt
+
+@noindent
+@example
+CDSqRt(@var{X})
+@end example
+
+@noindent
+CDSqRt: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{vxt}.
+
+@noindent
+Description:
+
+Archaic form of @code{SQRT()} that is specific
+to one type for @var{X}.
+@xref{SqRt Intrinsic}.
+
+@end ifset
+@ifset familyF90
+@node Ceiling Intrinsic
+@subsubsection Ceiling Intrinsic
+@cindex Ceiling intrinsic
+@cindex intrinsics, Ceiling
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Ceiling} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node CExp Intrinsic
+@subsubsection CExp Intrinsic
+@cindex CExp intrinsic
+@cindex intrinsics, CExp
+
+@noindent
+@example
+CExp(@var{X})
+@end example
+
+@noindent
+CExp: @code{COMPLEX(KIND=1)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{EXP()} that is specific
+to one type for @var{X}.
+@xref{Exp Intrinsic}.
+
+@node Char Intrinsic
+@subsubsection Char Intrinsic
+@cindex Char intrinsic
+@cindex intrinsics, Char
+
+@noindent
+@example
+Char(@var{I})
+@end example
+
+@noindent
+Char: @code{CHARACTER*1} function.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the character corresponding to the
+code specified by @var{I}, using the system's
+native character set.
+
+Because the system's native character set is used,
+the correspondence between character and their codes
+is not necessarily the same between GNU Fortran
+implementations.
+
+Note that no intrinsic exists to convert a numerical
+value to a printable character string.
+For example, there is no intrinsic that, given
+an @code{INTEGER} or @code{REAL} argument with the
+value @samp{154}, returns the @code{CHARACTER}
+result @samp{'154'}.
+
+Instead, you can use internal-file I/O to do this kind
+of conversion.
+For example:
+
+@smallexample
+INTEGER VALUE
+CHARACTER*10 STRING
+VALUE = 154
+WRITE (STRING, '(I10)'), VALUE
+PRINT *, STRING
+END
+@end smallexample
+
+The above program, when run, prints:
+
+@smallexample
+ 154
+@end smallexample
+
+@xref{IChar Intrinsic}, for the inverse of the @code{CHAR} function.
+
+@xref{AChar Intrinsic}, for the function corresponding
+to the ASCII character set.
+
+@end ifset
+@ifset familyF2U
+@node ChDir Intrinsic (subroutine)
+@subsubsection ChDir Intrinsic (subroutine)
+@cindex ChDir intrinsic
+@cindex intrinsics, ChDir
+
+@noindent
+@example
+CALL ChDir(@var{Dir}, @var{Status})
+@end example
+
+@noindent
+@var{Dir}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Sets the current working directory to be @var{Dir}.
+If the @var{Status} argument is supplied, it contains 0
+on success or a non-zero error code otherwise upon return.
+See @code{chdir(3)}.
+
+@emph{Caution:} Using this routine during I/O to a unit connected with a
+non-absolute file name can cause subsequent I/O on such a unit to fail
+because the I/O library may reopen files by name.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{ChDir Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node ChDir Intrinsic (function)
+@subsubsection ChDir Intrinsic (function)
+@cindex ChDir intrinsic
+@cindex intrinsics, ChDir
+
+@noindent
+@example
+ChDir(@var{Dir})
+@end example
+
+@noindent
+ChDir: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Dir}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Sets the current working directory to be @var{Dir}.
+Returns 0 on success or a non-zero error code.
+See @code{chdir(3)}.
+
+@emph{Caution:} Using this routine during I/O to a unit connected with a
+non-absolute file name can cause subsequent I/O on such a unit to fail
+because the I/O library may reopen files by name.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+For information on other intrinsics with the same name:
+@xref{ChDir Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF2U
+@node ChMod Intrinsic (subroutine)
+@subsubsection ChMod Intrinsic (subroutine)
+@cindex ChMod intrinsic
+@cindex intrinsics, ChMod
+
+@noindent
+@example
+CALL ChMod(@var{Name}, @var{Mode}, @var{Status})
+@end example
+
+@noindent
+@var{Name}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Mode}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Changes the access mode of file @var{Name} according to the
+specification @var{Mode}, which is given in the format of
+@code{chmod(1)}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{Name}---otherwise,
+trailing blanks in @var{Name} are ignored.
+Currently, @var{Name} must not contain the single quote
+character.
+
+If the @var{Status} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+
+Note that this currently works
+by actually invoking @code{/bin/chmod} (or the @code{chmod} found when
+the library was configured) and so may fail in some circumstances and
+will, anyway, be slow.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{ChMod Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node ChMod Intrinsic (function)
+@subsubsection ChMod Intrinsic (function)
+@cindex ChMod intrinsic
+@cindex intrinsics, ChMod
+
+@noindent
+@example
+ChMod(@var{Name}, @var{Mode})
+@end example
+
+@noindent
+ChMod: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Name}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Mode}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Changes the access mode of file @var{Name} according to the
+specification @var{Mode}, which is given in the format of
+@code{chmod(1)}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{Name}---otherwise,
+trailing blanks in @var{Name} are ignored.
+Currently, @var{Name} must not contain the single quote
+character.
+
+Returns 0 on success or a non-zero error code otherwise.
+
+Note that this currently works
+by actually invoking @code{/bin/chmod} (or the @code{chmod} found when
+the library was configured) and so may fail in some circumstances and
+will, anyway, be slow.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+For information on other intrinsics with the same name:
+@xref{ChMod Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF77
+@node CLog Intrinsic
+@subsubsection CLog Intrinsic
+@cindex CLog intrinsic
+@cindex intrinsics, CLog
+
+@noindent
+@example
+CLog(@var{X})
+@end example
+
+@noindent
+CLog: @code{COMPLEX(KIND=1)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{LOG()} that is specific
+to one type for @var{X}.
+@xref{Log Intrinsic}.
+
+@node Cmplx Intrinsic
+@subsubsection Cmplx Intrinsic
+@cindex Cmplx intrinsic
+@cindex intrinsics, Cmplx
+
+@noindent
+@example
+Cmplx(@var{X}, @var{Y})
+@end example
+
+@noindent
+Cmplx: @code{COMPLEX(KIND=1)} function.
+
+@noindent
+@var{X}: @code{INTEGER}, @code{REAL}, or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+@var{Y}: @code{INTEGER} or @code{REAL}; OPTIONAL (must be omitted if @var{X} is @code{COMPLEX}); scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+If @var{X} is not type @code{COMPLEX},
+constructs a value of type @code{COMPLEX(KIND=1)} from the
+real and imaginary values specified by @var{X} and
+@var{Y}, respectively.
+If @var{Y} is omitted, @samp{0.} is assumed.
+
+If @var{X} is type @code{COMPLEX},
+converts it to type @code{COMPLEX(KIND=1)}.
+
+@xref{Complex Intrinsic}, for information on easily constructing
+a @code{COMPLEX} value of arbitrary precision from @code{REAL}
+arguments.
+
+@end ifset
+@ifset familyGNU
+@node Complex Intrinsic
+@subsubsection Complex Intrinsic
+@cindex Complex intrinsic
+@cindex intrinsics, Complex
+
+@noindent
+@example
+Complex(@var{Real}, @var{Imag})
+@end example
+
+@noindent
+Complex: @code{COMPLEX} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{Real}: @code{INTEGER} or @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+@var{Imag}: @code{INTEGER} or @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{gnu}.
+
+@noindent
+Description:
+
+Returns a @code{COMPLEX} value that has @samp{Real} and @samp{Imag} as its
+real and imaginary parts, respectively.
+
+If @var{Real} and @var{Imag} are the same type, and that type is not
+@code{INTEGER}, no data conversion is performed, and the type of
+the resulting value has the same kind value as the types
+of @var{Real} and @var{Imag}.
+
+If @var{Real} and @var{Imag} are not the same type, the usual type-promotion
+rules are applied to both, converting either or both to the
+appropriate @code{REAL} type.
+The type of the resulting value has the same kind value as the
+type to which both @var{Real} and @var{Imag} were converted, in this case.
+
+If @var{Real} and @var{Imag} are both @code{INTEGER}, they are both converted
+to @code{REAL(KIND=1)}, and the result of the @code{COMPLEX()}
+invocation is type @code{COMPLEX(KIND=1)}.
+
+@emph{Note:} The way to do this in standard Fortran 90
+is too hairy to describe here, but it is important to
+note that @samp{CMPLX(D1,D2)} returns a @code{COMPLEX(KIND=1)}
+result even if @samp{D1} and @samp{D2} are type @code{REAL(KIND=2)}.
+Hence the availability of @code{COMPLEX()} in GNU Fortran.
+
+@end ifset
+@ifset familyF77
+@node Conjg Intrinsic
+@subsubsection Conjg Intrinsic
+@cindex Conjg intrinsic
+@cindex intrinsics, Conjg
+
+@noindent
+@example
+Conjg(@var{Z})
+@end example
+
+@noindent
+Conjg: @code{COMPLEX} function, the @samp{KIND=} value of the type being that of argument @var{Z}.
+
+@noindent
+@var{Z}: @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the complex conjugate:
+
+@example
+COMPLEX(REALPART(@var{Z}), -IMAGPART(@var{Z}))
+@end example
+
+@node Cos Intrinsic
+@subsubsection Cos Intrinsic
+@cindex Cos intrinsic
+@cindex intrinsics, Cos
+
+@noindent
+@example
+Cos(@var{X})
+@end example
+
+@noindent
+Cos: @code{REAL} or @code{COMPLEX} function, the exact type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL} or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the cosine of @var{X}, an angle measured
+in radians.
+
+@xref{ACos Intrinsic}, for the inverse of this function.
+
+@end ifset
+@ifset familyVXT
+@node CosD Intrinsic
+@subsubsection CosD Intrinsic
+@cindex CosD intrinsic
+@cindex intrinsics, CosD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL CosD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node CosH Intrinsic
+@subsubsection CosH Intrinsic
+@cindex CosH intrinsic
+@cindex intrinsics, CosH
+
+@noindent
+@example
+CosH(@var{X})
+@end example
+
+@noindent
+CosH: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the hyperbolic cosine of @var{X}.
+
+@end ifset
+@ifset familyF90
+@node Count Intrinsic
+@subsubsection Count Intrinsic
+@cindex Count intrinsic
+@cindex intrinsics, Count
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Count} to use this name for an
+external procedure.
+
+@node CPU_Time Intrinsic
+@subsubsection CPU_Time Intrinsic
+@cindex CPU_Time intrinsic
+@cindex intrinsics, CPU_Time
+
+@noindent
+@example
+CALL CPU_Time(@var{Seconds})
+@end example
+
+@noindent
+@var{Seconds}: @code{REAL}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{f90}.
+
+@noindent
+Description:
+
+Returns in @var{Seconds} the current value of the system time.
+This implementation of the Fortran 95 intrinsic is just an alias for
+@code{second} @xref{Second Intrinsic (subroutine)}.
+
+@node CShift Intrinsic
+@subsubsection CShift Intrinsic
+@cindex CShift intrinsic
+@cindex intrinsics, CShift
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL CShift} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node CSin Intrinsic
+@subsubsection CSin Intrinsic
+@cindex CSin intrinsic
+@cindex intrinsics, CSin
+
+@noindent
+@example
+CSin(@var{X})
+@end example
+
+@noindent
+CSin: @code{COMPLEX(KIND=1)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{SIN()} that is specific
+to one type for @var{X}.
+@xref{Sin Intrinsic}.
+
+@node CSqRt Intrinsic
+@subsubsection CSqRt Intrinsic
+@cindex CSqRt intrinsic
+@cindex intrinsics, CSqRt
+
+@noindent
+@example
+CSqRt(@var{X})
+@end example
+
+@noindent
+CSqRt: @code{COMPLEX(KIND=1)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{SQRT()} that is specific
+to one type for @var{X}.
+@xref{SqRt Intrinsic}.
+
+@end ifset
+@ifset familyF2U
+@node CTime Intrinsic (subroutine)
+@subsubsection CTime Intrinsic (subroutine)
+@cindex CTime intrinsic
+@cindex intrinsics, CTime
+
+@noindent
+@example
+CALL CTime(@var{Result}, @var{STime})
+@end example
+
+@noindent
+@var{Result}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+@var{STime}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Converts @var{STime}, a system time value, such as returned by
+@code{TIME8()}, to a string of the form @samp{Sat Aug 19 18:13:14 1995},
+and returns that string in @var{Result}.
+
+@xref{Time8 Intrinsic}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+
+For information on other intrinsics with the same name:
+@xref{CTime Intrinsic (function)}.
+
+@node CTime Intrinsic (function)
+@subsubsection CTime Intrinsic (function)
+@cindex CTime intrinsic
+@cindex intrinsics, CTime
+
+@noindent
+@example
+CTime(@var{STime})
+@end example
+
+@noindent
+CTime: @code{CHARACTER*(*)} function.
+
+@noindent
+@var{STime}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Converts @var{STime}, a system time value, such as returned by
+@code{TIME8()}, to a string of the form @samp{Sat Aug 19 18:13:14 1995},
+and returns that string as the function value.
+
+@xref{Time8 Intrinsic}.
+
+For information on other intrinsics with the same name:
+@xref{CTime Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF77
+@node DAbs Intrinsic
+@subsubsection DAbs Intrinsic
+@cindex DAbs intrinsic
+@cindex intrinsics, DAbs
+
+@noindent
+@example
+DAbs(@var{A})
+@end example
+
+@noindent
+DAbs: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{ABS()} that is specific
+to one type for @var{A}.
+@xref{Abs Intrinsic}.
+
+@node DACos Intrinsic
+@subsubsection DACos Intrinsic
+@cindex DACos intrinsic
+@cindex intrinsics, DACos
+
+@noindent
+@example
+DACos(@var{X})
+@end example
+
+@noindent
+DACos: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{ACOS()} that is specific
+to one type for @var{X}.
+@xref{ACos Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node DACosD Intrinsic
+@subsubsection DACosD Intrinsic
+@cindex DACosD intrinsic
+@cindex intrinsics, DACosD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL DACosD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node DASin Intrinsic
+@subsubsection DASin Intrinsic
+@cindex DASin intrinsic
+@cindex intrinsics, DASin
+
+@noindent
+@example
+DASin(@var{X})
+@end example
+
+@noindent
+DASin: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{ASIN()} that is specific
+to one type for @var{X}.
+@xref{ASin Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node DASinD Intrinsic
+@subsubsection DASinD Intrinsic
+@cindex DASinD intrinsic
+@cindex intrinsics, DASinD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL DASinD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node DATan Intrinsic
+@subsubsection DATan Intrinsic
+@cindex DATan intrinsic
+@cindex intrinsics, DATan
+
+@noindent
+@example
+DATan(@var{X})
+@end example
+
+@noindent
+DATan: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{ATAN()} that is specific
+to one type for @var{X}.
+@xref{ATan Intrinsic}.
+
+@node DATan2 Intrinsic
+@subsubsection DATan2 Intrinsic
+@cindex DATan2 intrinsic
+@cindex intrinsics, DATan2
+
+@noindent
+@example
+DATan2(@var{Y}, @var{X})
+@end example
+
+@noindent
+DATan2: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{Y}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{ATAN2()} that is specific
+to one type for @var{Y} and @var{X}.
+@xref{ATan2 Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node DATan2D Intrinsic
+@subsubsection DATan2D Intrinsic
+@cindex DATan2D intrinsic
+@cindex intrinsics, DATan2D
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL DATan2D} to use this name for an
+external procedure.
+
+@node DATanD Intrinsic
+@subsubsection DATanD Intrinsic
+@cindex DATanD intrinsic
+@cindex intrinsics, DATanD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL DATanD} to use this name for an
+external procedure.
+
+@node Date Intrinsic
+@subsubsection Date Intrinsic
+@cindex Date intrinsic
+@cindex intrinsics, Date
+
+@noindent
+@example
+CALL Date(@var{Date})
+@end example
+
+@noindent
+@var{Date}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{vxt}.
+
+@noindent
+Description:
+
+Returns @var{Date} in the form @samp{@var{dd}-@var{mmm}-@var{yy}},
+representing the numeric day of the month @var{dd}, a three-character
+abbreviation of the month name @var{mmm} and the last two digits of
+the year @var{yy}, e.g.@: @samp{25-Nov-96}.
+
+This intrinsic is not recommended, due to the year 2000 approaching.
+@xref{CTime Intrinsic (subroutine)}, for information on obtaining more digits
+for the current (or any) date.
+
+@end ifset
+@ifset familyF90
+@node Date_and_Time Intrinsic
+@subsubsection Date_and_Time Intrinsic
+@cindex Date_and_Time intrinsic
+@cindex intrinsics, Date_and_Time
+
+@noindent
+@example
+CALL Date_and_Time(@var{Date}, @var{Time}, @var{Zone}, @var{Values})
+@end example
+
+@noindent
+@var{Date}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+@var{Time}: @code{CHARACTER}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+@var{Zone}: @code{CHARACTER}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+@var{Values}: @code{INTEGER(KIND=1)}; OPTIONAL; DIMENSION(8); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{f90}.
+
+@noindent
+Description:
+
+Returns:
+@table @var
+@item Date
+The date in the form @var{ccyymmdd}: century, year, month and day;
+@item Time
+The time in the form @samp{@var{hhmmss.ss}}: hours, minutes, seconds
+and milliseconds;
+@item Zone
+The difference between local time and UTC (GMT) in the form @var{Shhmm}:
+sign, hours and minutes, e.g.@: @samp{-0500} (winter in New York);
+@item Values
+The year, month of the year, day of the month, time difference in
+minutes from UTC, hour of the day, minutes of the hour, seconds
+of the minute, and milliseconds
+of the second in successive values of the array.
+@end table
+
+On systems where a millisecond timer isn't available, the millisecond
+value is returned as zero.
+
+@end ifset
+@ifset familyF2U
+@node DbesJ0 Intrinsic
+@subsubsection DbesJ0 Intrinsic
+@cindex DbesJ0 intrinsic
+@cindex intrinsics, DbesJ0
+
+@noindent
+@example
+DbesJ0(@var{X})
+@end example
+
+@noindent
+DbesJ0: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Archaic form of @code{BESJ0()} that is specific
+to one type for @var{X}.
+@xref{BesJ0 Intrinsic}.
+
+@node DbesJ1 Intrinsic
+@subsubsection DbesJ1 Intrinsic
+@cindex DbesJ1 intrinsic
+@cindex intrinsics, DbesJ1
+
+@noindent
+@example
+DbesJ1(@var{X})
+@end example
+
+@noindent
+DbesJ1: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Archaic form of @code{BESJ1()} that is specific
+to one type for @var{X}.
+@xref{BesJ1 Intrinsic}.
+
+@node DbesJN Intrinsic
+@subsubsection DbesJN Intrinsic
+@cindex DbesJN intrinsic
+@cindex intrinsics, DbesJN
+
+@noindent
+@example
+DbesJN(@var{N}, @var{X})
+@end example
+
+@noindent
+DbesJN: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{N}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Archaic form of @code{BESJN()} that is specific
+to one type for @var{X}.
+@xref{BesJN Intrinsic}.
+
+@node DbesY0 Intrinsic
+@subsubsection DbesY0 Intrinsic
+@cindex DbesY0 intrinsic
+@cindex intrinsics, DbesY0
+
+@noindent
+@example
+DbesY0(@var{X})
+@end example
+
+@noindent
+DbesY0: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Archaic form of @code{BESY0()} that is specific
+to one type for @var{X}.
+@xref{BesY0 Intrinsic}.
+
+@node DbesY1 Intrinsic
+@subsubsection DbesY1 Intrinsic
+@cindex DbesY1 intrinsic
+@cindex intrinsics, DbesY1
+
+@noindent
+@example
+DbesY1(@var{X})
+@end example
+
+@noindent
+DbesY1: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Archaic form of @code{BESY1()} that is specific
+to one type for @var{X}.
+@xref{BesY1 Intrinsic}.
+
+@node DbesYN Intrinsic
+@subsubsection DbesYN Intrinsic
+@cindex DbesYN intrinsic
+@cindex intrinsics, DbesYN
+
+@noindent
+@example
+DbesYN(@var{N}, @var{X})
+@end example
+
+@noindent
+DbesYN: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{N}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Archaic form of @code{BESYN()} that is specific
+to one type for @var{X}.
+@xref{BesYN Intrinsic}.
+
+@end ifset
+@ifset familyF77
+@node Dble Intrinsic
+@subsubsection Dble Intrinsic
+@cindex Dble intrinsic
+@cindex intrinsics, Dble
+
+@noindent
+@example
+Dble(@var{A})
+@end example
+
+@noindent
+Dble: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{INTEGER}, @code{REAL}, or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @var{A} converted to double precision
+(@code{REAL(KIND=2)}).
+If @var{A} is @code{COMPLEX}, the real part of
+@var{A} is used for the conversion
+and the imaginary part disregarded.
+
+@xref{Sngl Intrinsic}, for the function that converts
+to single precision.
+
+@xref{Int Intrinsic}, for the function that converts
+to @code{INTEGER}.
+
+@xref{Complex Intrinsic}, for the function that converts
+to @code{COMPLEX}.
+
+@end ifset
+@ifset familyVXT
+@node DbleQ Intrinsic
+@subsubsection DbleQ Intrinsic
+@cindex DbleQ intrinsic
+@cindex intrinsics, DbleQ
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL DbleQ} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyFVZ
+@node DCmplx Intrinsic
+@subsubsection DCmplx Intrinsic
+@cindex DCmplx intrinsic
+@cindex intrinsics, DCmplx
+
+@noindent
+@example
+DCmplx(@var{X}, @var{Y})
+@end example
+
+@noindent
+DCmplx: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{INTEGER}, @code{REAL}, or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+@var{Y}: @code{INTEGER} or @code{REAL}; OPTIONAL (must be omitted if @var{X} is @code{COMPLEX}); scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{vxt}.
+
+@noindent
+Description:
+
+If @var{X} is not type @code{COMPLEX},
+constructs a value of type @code{COMPLEX(KIND=2)} from the
+real and imaginary values specified by @var{X} and
+@var{Y}, respectively.
+If @var{Y} is omitted, @samp{0D0} is assumed.
+
+If @var{X} is type @code{COMPLEX},
+converts it to type @code{COMPLEX(KIND=2)}.
+
+Although this intrinsic is not standard Fortran,
+it is a popular extension offered by many compilers
+that support @code{DOUBLE COMPLEX}, since it offers
+the easiest way to convert to @code{DOUBLE COMPLEX}
+without using Fortran 90 features (such as the @samp{KIND=}
+argument to the @code{CMPLX()} intrinsic).
+
+(@samp{CMPLX(0D0, 0D0)} returns a single-precision
+@code{COMPLEX} result, as required by standard FORTRAN 77.
+That's why so many compilers provide @code{DCMPLX()}, since
+@samp{DCMPLX(0D0, 0D0)} returns a @code{DOUBLE COMPLEX}
+result.
+Still, @code{DCMPLX()} converts even @code{REAL*16} arguments
+to their @code{REAL*8} equivalents in most dialects of
+Fortran, so neither it nor @code{CMPLX()} allow easy
+construction of arbitrary-precision values without
+potentially forcing a conversion involving extending or
+reducing precision.
+GNU Fortran provides such an intrinsic, called @code{COMPLEX()}.)
+
+@xref{Complex Intrinsic}, for information on easily constructing
+a @code{COMPLEX} value of arbitrary precision from @code{REAL}
+arguments.
+
+@node DConjg Intrinsic
+@subsubsection DConjg Intrinsic
+@cindex DConjg intrinsic
+@cindex intrinsics, DConjg
+
+@noindent
+@example
+DConjg(@var{Z})
+@end example
+
+@noindent
+DConjg: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{Z}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{vxt}.
+
+@noindent
+Description:
+
+Archaic form of @code{CONJG()} that is specific
+to one type for @var{Z}.
+@xref{Conjg Intrinsic}.
+
+@end ifset
+@ifset familyF77
+@node DCos Intrinsic
+@subsubsection DCos Intrinsic
+@cindex DCos intrinsic
+@cindex intrinsics, DCos
+
+@noindent
+@example
+DCos(@var{X})
+@end example
+
+@noindent
+DCos: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{COS()} that is specific
+to one type for @var{X}.
+@xref{Cos Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node DCosD Intrinsic
+@subsubsection DCosD Intrinsic
+@cindex DCosD intrinsic
+@cindex intrinsics, DCosD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL DCosD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node DCosH Intrinsic
+@subsubsection DCosH Intrinsic
+@cindex DCosH intrinsic
+@cindex intrinsics, DCosH
+
+@noindent
+@example
+DCosH(@var{X})
+@end example
+
+@noindent
+DCosH: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{COSH()} that is specific
+to one type for @var{X}.
+@xref{CosH Intrinsic}.
+
+@node DDiM Intrinsic
+@subsubsection DDiM Intrinsic
+@cindex DDiM intrinsic
+@cindex intrinsics, DDiM
+
+@noindent
+@example
+DDiM(@var{X}, @var{Y})
+@end example
+
+@noindent
+DDiM: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+@var{Y}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{DIM()} that is specific
+to one type for @var{X} and @var{Y}.
+@xref{DiM Intrinsic}.
+
+@end ifset
+@ifset familyF2U
+@node DErF Intrinsic
+@subsubsection DErF Intrinsic
+@cindex DErF intrinsic
+@cindex intrinsics, DErF
+
+@noindent
+@example
+DErF(@var{X})
+@end example
+
+@noindent
+DErF: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Archaic form of @code{ERF()} that is specific
+to one type for @var{X}.
+@xref{ErF Intrinsic}.
+
+@node DErFC Intrinsic
+@subsubsection DErFC Intrinsic
+@cindex DErFC intrinsic
+@cindex intrinsics, DErFC
+
+@noindent
+@example
+DErFC(@var{X})
+@end example
+
+@noindent
+DErFC: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Archaic form of @code{ERFC()} that is specific
+to one type for @var{X}.
+@xref{ErFC Intrinsic}.
+
+@end ifset
+@ifset familyF77
+@node DExp Intrinsic
+@subsubsection DExp Intrinsic
+@cindex DExp intrinsic
+@cindex intrinsics, DExp
+
+@noindent
+@example
+DExp(@var{X})
+@end example
+
+@noindent
+DExp: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{EXP()} that is specific
+to one type for @var{X}.
+@xref{Exp Intrinsic}.
+
+@end ifset
+@ifset familyFVZ
+@node DFloat Intrinsic
+@subsubsection DFloat Intrinsic
+@cindex DFloat intrinsic
+@cindex intrinsics, DFloat
+
+@noindent
+@example
+DFloat(@var{A})
+@end example
+
+@noindent
+DFloat: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{vxt}.
+
+@noindent
+Description:
+
+Archaic form of @code{REAL()} that is specific
+to one type for @var{A}.
+@xref{Real Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node DFlotI Intrinsic
+@subsubsection DFlotI Intrinsic
+@cindex DFlotI intrinsic
+@cindex intrinsics, DFlotI
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL DFlotI} to use this name for an
+external procedure.
+
+@node DFlotJ Intrinsic
+@subsubsection DFlotJ Intrinsic
+@cindex DFlotJ intrinsic
+@cindex intrinsics, DFlotJ
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL DFlotJ} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF90
+@node Digits Intrinsic
+@subsubsection Digits Intrinsic
+@cindex Digits intrinsic
+@cindex intrinsics, Digits
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Digits} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node DiM Intrinsic
+@subsubsection DiM Intrinsic
+@cindex DiM intrinsic
+@cindex intrinsics, DiM
+
+@noindent
+@example
+DiM(@var{X}, @var{Y})
+@end example
+
+@noindent
+DiM: @code{INTEGER} or @code{REAL} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{X}: @code{INTEGER} or @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+@var{Y}: @code{INTEGER} or @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @samp{@var{X}-@var{Y}} if @var{X} is greater than
+@var{Y}; otherwise returns zero.
+
+@end ifset
+@ifset familyFVZ
+@node DImag Intrinsic
+@subsubsection DImag Intrinsic
+@cindex DImag intrinsic
+@cindex intrinsics, DImag
+
+@noindent
+@example
+DImag(@var{Z})
+@end example
+
+@noindent
+DImag: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{Z}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{vxt}.
+
+@noindent
+Description:
+
+Archaic form of @code{AIMAG()} that is specific
+to one type for @var{Z}.
+@xref{AImag Intrinsic}.
+
+@end ifset
+@ifset familyF77
+@node DInt Intrinsic
+@subsubsection DInt Intrinsic
+@cindex DInt intrinsic
+@cindex intrinsics, DInt
+
+@noindent
+@example
+DInt(@var{A})
+@end example
+
+@noindent
+DInt: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{AINT()} that is specific
+to one type for @var{A}.
+@xref{AInt Intrinsic}.
+
+@node DLog Intrinsic
+@subsubsection DLog Intrinsic
+@cindex DLog intrinsic
+@cindex intrinsics, DLog
+
+@noindent
+@example
+DLog(@var{X})
+@end example
+
+@noindent
+DLog: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{LOG()} that is specific
+to one type for @var{X}.
+@xref{Log Intrinsic}.
+
+@node DLog10 Intrinsic
+@subsubsection DLog10 Intrinsic
+@cindex DLog10 intrinsic
+@cindex intrinsics, DLog10
+
+@noindent
+@example
+DLog10(@var{X})
+@end example
+
+@noindent
+DLog10: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{LOG10()} that is specific
+to one type for @var{X}.
+@xref{Log10 Intrinsic}.
+
+@node DMax1 Intrinsic
+@subsubsection DMax1 Intrinsic
+@cindex DMax1 intrinsic
+@cindex intrinsics, DMax1
+
+@noindent
+@example
+DMax1(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+DMax1: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=2)}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MAX()} that is specific
+to one type for @var{A}.
+@xref{Max Intrinsic}.
+
+@node DMin1 Intrinsic
+@subsubsection DMin1 Intrinsic
+@cindex DMin1 intrinsic
+@cindex intrinsics, DMin1
+
+@noindent
+@example
+DMin1(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+DMin1: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=2)}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MIN()} that is specific
+to one type for @var{A}.
+@xref{Min Intrinsic}.
+
+@node DMod Intrinsic
+@subsubsection DMod Intrinsic
+@cindex DMod intrinsic
+@cindex intrinsics, DMod
+
+@noindent
+@example
+DMod(@var{A}, @var{P})
+@end example
+
+@noindent
+DMod: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+@var{P}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MOD()} that is specific
+to one type for @var{A}.
+@xref{Mod Intrinsic}.
+
+@node DNInt Intrinsic
+@subsubsection DNInt Intrinsic
+@cindex DNInt intrinsic
+@cindex intrinsics, DNInt
+
+@noindent
+@example
+DNInt(@var{A})
+@end example
+
+@noindent
+DNInt: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{ANINT()} that is specific
+to one type for @var{A}.
+@xref{ANInt Intrinsic}.
+
+@end ifset
+@ifset familyF90
+@node Dot_Product Intrinsic
+@subsubsection Dot_Product Intrinsic
+@cindex Dot_Product intrinsic
+@cindex intrinsics, Dot_Product
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Dot_Product} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node DProd Intrinsic
+@subsubsection DProd Intrinsic
+@cindex DProd intrinsic
+@cindex intrinsics, DProd
+
+@noindent
+@example
+DProd(@var{X}, @var{Y})
+@end example
+
+@noindent
+DProd: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+@var{Y}: @code{REAL(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @samp{DBLE(@var{X})*DBLE(@var{Y})}.
+
+@end ifset
+@ifset familyVXT
+@node DReal Intrinsic
+@subsubsection DReal Intrinsic
+@cindex DReal intrinsic
+@cindex intrinsics, DReal
+
+@noindent
+@example
+DReal(@var{A})
+@end example
+
+@noindent
+DReal: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{INTEGER}, @code{REAL}, or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{vxt}.
+
+@noindent
+Description:
+
+Converts @var{A} to @code{REAL(KIND=2)}.
+
+If @var{A} is type @code{COMPLEX}, its real part
+is converted (if necessary) to @code{REAL(KIND=2)},
+and its imaginary part is disregarded.
+
+Although this intrinsic is not standard Fortran,
+it is a popular extension offered by many compilers
+that support @code{DOUBLE COMPLEX}, since it offers
+the easiest way to extract the real part of a @code{DOUBLE COMPLEX}
+value without using the Fortran 90 @code{REAL()} intrinsic
+in a way that produces a return value inconsistent with
+the way many FORTRAN 77 compilers handle @code{REAL()} of
+a @code{DOUBLE COMPLEX} value.
+
+@xref{RealPart Intrinsic}, for information on a GNU Fortran
+intrinsic that avoids these areas of confusion.
+
+@xref{Dble Intrinsic}, for information on the standard FORTRAN 77
+replacement for @code{DREAL()}.
+
+@xref{REAL() and AIMAG() of Complex}, for more information on
+this issue.
+
+@end ifset
+@ifset familyF77
+@node DSign Intrinsic
+@subsubsection DSign Intrinsic
+@cindex DSign intrinsic
+@cindex intrinsics, DSign
+
+@noindent
+@example
+DSign(@var{A}, @var{B})
+@end example
+
+@noindent
+DSign: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+@var{B}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{SIGN()} that is specific
+to one type for @var{A} and @var{B}.
+@xref{Sign Intrinsic}.
+
+@node DSin Intrinsic
+@subsubsection DSin Intrinsic
+@cindex DSin intrinsic
+@cindex intrinsics, DSin
+
+@noindent
+@example
+DSin(@var{X})
+@end example
+
+@noindent
+DSin: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{SIN()} that is specific
+to one type for @var{X}.
+@xref{Sin Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node DSinD Intrinsic
+@subsubsection DSinD Intrinsic
+@cindex DSinD intrinsic
+@cindex intrinsics, DSinD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL DSinD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node DSinH Intrinsic
+@subsubsection DSinH Intrinsic
+@cindex DSinH intrinsic
+@cindex intrinsics, DSinH
+
+@noindent
+@example
+DSinH(@var{X})
+@end example
+
+@noindent
+DSinH: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{SINH()} that is specific
+to one type for @var{X}.
+@xref{SinH Intrinsic}.
+
+@node DSqRt Intrinsic
+@subsubsection DSqRt Intrinsic
+@cindex DSqRt intrinsic
+@cindex intrinsics, DSqRt
+
+@noindent
+@example
+DSqRt(@var{X})
+@end example
+
+@noindent
+DSqRt: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{SQRT()} that is specific
+to one type for @var{X}.
+@xref{SqRt Intrinsic}.
+
+@node DTan Intrinsic
+@subsubsection DTan Intrinsic
+@cindex DTan intrinsic
+@cindex intrinsics, DTan
+
+@noindent
+@example
+DTan(@var{X})
+@end example
+
+@noindent
+DTan: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{TAN()} that is specific
+to one type for @var{X}.
+@xref{Tan Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node DTanD Intrinsic
+@subsubsection DTanD Intrinsic
+@cindex DTanD intrinsic
+@cindex intrinsics, DTanD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL DTanD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node DTanH Intrinsic
+@subsubsection DTanH Intrinsic
+@cindex DTanH intrinsic
+@cindex intrinsics, DTanH
+
+@noindent
+@example
+DTanH(@var{X})
+@end example
+
+@noindent
+DTanH: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{X}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{TANH()} that is specific
+to one type for @var{X}.
+@xref{TanH Intrinsic}.
+
+@end ifset
+@ifset familyF2U
+@node Dtime Intrinsic (subroutine)
+@subsubsection Dtime Intrinsic (subroutine)
+@cindex Dtime intrinsic
+@cindex intrinsics, Dtime
+
+@noindent
+@example
+CALL Dtime(@var{Result}, @var{TArray})
+@end example
+
+@noindent
+@var{Result}: @code{REAL(KIND=1)}; scalar; INTENT(OUT).
+
+@noindent
+@var{TArray}: @code{REAL(KIND=1)}; DIMENSION(2); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Initially, return the number of seconds of runtime
+since the start of the process's execution
+in @var{Result},
+and the user and system components of this in @samp{@var{TArray}(1)}
+and @samp{@var{TArray}(2)} respectively.
+The value of @var{Result} is equal to @samp{@var{TArray}(1) + @var{TArray}(2)}.
+
+Subsequent invocations of @samp{DTIME()} set values based on accumulations
+since the previous invocation.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+
+For information on other intrinsics with the same name:
+@xref{Dtime Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node Dtime Intrinsic (function)
+@subsubsection Dtime Intrinsic (function)
+@cindex Dtime intrinsic
+@cindex intrinsics, Dtime
+
+@noindent
+@example
+Dtime(@var{TArray})
+@end example
+
+@noindent
+Dtime: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{TArray}: @code{REAL(KIND=1)}; DIMENSION(2); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Initially, return the number of seconds of runtime
+since the start of the process's execution
+as the function value,
+and the user and system components of this in @samp{@var{TArray}(1)}
+and @samp{@var{TArray}(2)} respectively.
+The functions' value is equal to @samp{@var{TArray}(1) + @var{TArray}(2)}.
+
+Subsequent invocations of @samp{DTIME()} return values accumulated since the
+previous invocation.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+For information on other intrinsics with the same name:
+@xref{Dtime Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF90
+@node EOShift Intrinsic
+@subsubsection EOShift Intrinsic
+@cindex EOShift intrinsic
+@cindex intrinsics, EOShift
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL EOShift} to use this name for an
+external procedure.
+
+@node Epsilon Intrinsic
+@subsubsection Epsilon Intrinsic
+@cindex Epsilon intrinsic
+@cindex intrinsics, Epsilon
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Epsilon} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node ErF Intrinsic
+@subsubsection ErF Intrinsic
+@cindex ErF intrinsic
+@cindex intrinsics, ErF
+
+@noindent
+@example
+ErF(@var{X})
+@end example
+
+@noindent
+ErF: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the error function of @var{X}.
+See @code{erf(3m)}, which provides the implementation.
+
+@node ErFC Intrinsic
+@subsubsection ErFC Intrinsic
+@cindex ErFC intrinsic
+@cindex intrinsics, ErFC
+
+@noindent
+@example
+ErFC(@var{X})
+@end example
+
+@noindent
+ErFC: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the complementary error function of @var{X}:
+@samp{ERFC(R) = 1 - ERF(R)} (except that the result may be more
+accurate than explicitly evaluating that formulae would give).
+See @code{erfc(3m)}, which provides the implementation.
+
+@node ETime Intrinsic (subroutine)
+@subsubsection ETime Intrinsic (subroutine)
+@cindex ETime intrinsic
+@cindex intrinsics, ETime
+
+@noindent
+@example
+CALL ETime(@var{Result}, @var{TArray})
+@end example
+
+@noindent
+@var{Result}: @code{REAL(KIND=1)}; scalar; INTENT(OUT).
+
+@noindent
+@var{TArray}: @code{REAL(KIND=1)}; DIMENSION(2); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Return the number of seconds of runtime
+since the start of the process's execution
+in @var{Result},
+and the user and system components of this in @samp{@var{TArray}(1)}
+and @samp{@var{TArray}(2)} respectively.
+The value of @var{Result} is equal to @samp{@var{TArray}(1) + @var{TArray}(2)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+
+For information on other intrinsics with the same name:
+@xref{ETime Intrinsic (function)}.
+
+@node ETime Intrinsic (function)
+@subsubsection ETime Intrinsic (function)
+@cindex ETime intrinsic
+@cindex intrinsics, ETime
+
+@noindent
+@example
+ETime(@var{TArray})
+@end example
+
+@noindent
+ETime: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{TArray}: @code{REAL(KIND=1)}; DIMENSION(2); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Return the number of seconds of runtime
+since the start of the process's execution
+as the function value,
+and the user and system components of this in @samp{@var{TArray}(1)}
+and @samp{@var{TArray}(2)} respectively.
+The functions' value is equal to @samp{@var{TArray}(1) + @var{TArray}(2)}.
+
+For information on other intrinsics with the same name:
+@xref{ETime Intrinsic (subroutine)}.
+
+@node Exit Intrinsic
+@subsubsection Exit Intrinsic
+@cindex Exit intrinsic
+@cindex intrinsics, Exit
+
+@noindent
+@example
+CALL Exit(@var{Status})
+@end example
+
+@noindent
+@var{Status}: @code{INTEGER}; OPTIONAL; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Exit the program with status @var{Status} after closing open Fortran
+I/O units and otherwise behaving as @code{exit(2)}.
+If @var{Status} is omitted the canonical `success' value
+will be returned to the system.
+
+@end ifset
+@ifset familyF77
+@node Exp Intrinsic
+@subsubsection Exp Intrinsic
+@cindex Exp intrinsic
+@cindex intrinsics, Exp
+
+@noindent
+@example
+Exp(@var{X})
+@end example
+
+@noindent
+Exp: @code{REAL} or @code{COMPLEX} function, the exact type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL} or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @samp{@var{e}**@var{X}}, where
+@var{e} is approximately 2.7182818.
+
+@xref{Log Intrinsic}, for the inverse of this function.
+
+@end ifset
+@ifset familyF90
+@node Exponent Intrinsic
+@subsubsection Exponent Intrinsic
+@cindex Exponent intrinsic
+@cindex intrinsics, Exponent
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Exponent} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node Fdate Intrinsic (subroutine)
+@subsubsection Fdate Intrinsic (subroutine)
+@cindex Fdate intrinsic
+@cindex intrinsics, Fdate
+
+@noindent
+@example
+CALL Fdate(@var{Date})
+@end example
+
+@noindent
+@var{Date}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the current date (using the same format as @code{CTIME()})
+in @var{Date}.
+
+Equivalent to:
+
+@example
+CALL CTIME(@var{Date}, TIME8())
+@end example
+
+@xref{CTime Intrinsic (subroutine)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+
+For information on other intrinsics with the same name:
+@xref{Fdate Intrinsic (function)}.
+
+@node Fdate Intrinsic (function)
+@subsubsection Fdate Intrinsic (function)
+@cindex Fdate intrinsic
+@cindex intrinsics, Fdate
+
+@noindent
+@example
+Fdate()
+@end example
+
+@noindent
+Fdate: @code{CHARACTER*(*)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the current date (using the same format as @code{CTIME()}).
+
+Equivalent to:
+
+@example
+CTIME(TIME8())
+@end example
+
+@xref{CTime Intrinsic (function)}.
+
+For information on other intrinsics with the same name:
+@xref{Fdate Intrinsic (subroutine)}.
+
+@node FGet Intrinsic (subroutine)
+@subsubsection FGet Intrinsic (subroutine)
+@cindex FGet intrinsic
+@cindex intrinsics, FGet
+
+@noindent
+@example
+CALL FGet(@var{C}, @var{Status})
+@end example
+
+@noindent
+@var{C}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Reads a single character into @var{C} in stream mode from unit 5
+(by-passing normal formatted output) using @code{getc(3)}.
+Returns in
+@var{Status} 0 on success, @minus{}1 on end-of-file, and the error code
+from @code{ferror(3)} otherwise.
+
+Stream I/O should not be mixed with normal record-oriented (formatted or
+unformatted) I/O on the same unit; the results are unpredictable.
+
+For information on other intrinsics with the same name:
+@xref{FGet Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node FGet Intrinsic (function)
+@subsubsection FGet Intrinsic (function)
+@cindex FGet intrinsic
+@cindex intrinsics, FGet
+
+@noindent
+@example
+FGet(@var{C})
+@end example
+
+@noindent
+FGet: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{C}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Reads a single character into @var{C} in stream mode from unit 5
+(by-passing normal formatted input) using @code{getc(3)}.
+Returns 0 on
+success, @minus{}1 on end-of-file, and the error code from
+@code{ferror(3)} otherwise.
+
+Stream I/O should not be mixed with normal record-oriented (formatted or
+unformatted) I/O on the same unit; the results are unpredictable.
+
+For information on other intrinsics with the same name:
+@xref{FGet Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF2U
+@node FGetC Intrinsic (subroutine)
+@subsubsection FGetC Intrinsic (subroutine)
+@cindex FGetC intrinsic
+@cindex intrinsics, FGetC
+
+@noindent
+@example
+CALL FGetC(@var{Unit}, @var{C}, @var{Status})
+@end example
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{C}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Reads a single character into @var{C} in stream mode from unit @var{Unit}
+(by-passing normal formatted output) using @code{getc(3)}.
+Returns in
+@var{Status} 0 on success, @minus{}1 on end-of-file, and the error code from
+@code{ferror(3)} otherwise.
+
+Stream I/O should not be mixed with normal record-oriented (formatted or
+unformatted) I/O on the same unit; the results are unpredictable.
+
+For information on other intrinsics with the same name:
+@xref{FGetC Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node FGetC Intrinsic (function)
+@subsubsection FGetC Intrinsic (function)
+@cindex FGetC intrinsic
+@cindex intrinsics, FGetC
+
+@noindent
+@example
+FGetC(@var{Unit}, @var{C})
+@end example
+
+@noindent
+FGetC: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{C}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Reads a single character into @var{C} in stream mode from unit @var{Unit}
+(by-passing normal formatted output) using @code{getc(3)}.
+Returns 0 on
+success, @minus{}1 on end-of-file, and the error code from
+@code{ferror(3)} otherwise.
+
+Stream I/O should not be mixed with normal record-oriented (formatted or
+unformatted) I/O on the same unit; the results are unpredictable.
+
+For information on other intrinsics with the same name:
+@xref{FGetC Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF77
+@node Float Intrinsic
+@subsubsection Float Intrinsic
+@cindex Float intrinsic
+@cindex intrinsics, Float
+
+@noindent
+@example
+Float(@var{A})
+@end example
+
+@noindent
+Float: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{A}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{REAL()} that is specific
+to one type for @var{A}.
+@xref{Real Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node FloatI Intrinsic
+@subsubsection FloatI Intrinsic
+@cindex FloatI intrinsic
+@cindex intrinsics, FloatI
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL FloatI} to use this name for an
+external procedure.
+
+@node FloatJ Intrinsic
+@subsubsection FloatJ Intrinsic
+@cindex FloatJ intrinsic
+@cindex intrinsics, FloatJ
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL FloatJ} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF90
+@node Floor Intrinsic
+@subsubsection Floor Intrinsic
+@cindex Floor intrinsic
+@cindex intrinsics, Floor
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Floor} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node Flush Intrinsic
+@subsubsection Flush Intrinsic
+@cindex Flush intrinsic
+@cindex intrinsics, Flush
+
+@noindent
+@example
+CALL Flush(@var{Unit})
+@end example
+
+@noindent
+@var{Unit}: @code{INTEGER}; OPTIONAL; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Flushes Fortran unit(s) currently open for output.
+Without the optional argument, all such units are flushed,
+otherwise just the unit specified by @var{Unit}.
+
+Some non-GNU implementations of Fortran provide this intrinsic
+as a library procedure that might or might not support the
+(optional) @var{Unit} argument.
+
+@node FNum Intrinsic
+@subsubsection FNum Intrinsic
+@cindex FNum intrinsic
+@cindex intrinsics, FNum
+
+@noindent
+@example
+FNum(@var{Unit})
+@end example
+
+@noindent
+FNum: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the Unix file descriptor number corresponding to the open
+Fortran I/O unit @var{Unit}.
+This could be passed to an interface to C I/O routines.
+
+@node FPut Intrinsic (subroutine)
+@subsubsection FPut Intrinsic (subroutine)
+@cindex FPut intrinsic
+@cindex intrinsics, FPut
+
+@noindent
+@example
+CALL FPut(@var{C}, @var{Status})
+@end example
+
+@noindent
+@var{C}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Writes the single character @var{C} in stream mode to unit 6
+(by-passing normal formatted output) using @code{putc(3)}.
+Returns in
+@var{Status} 0 on success, the error code from @code{ferror(3)} otherwise.
+
+Stream I/O should not be mixed with normal record-oriented (formatted or
+unformatted) I/O on the same unit; the results are unpredictable.
+
+For information on other intrinsics with the same name:
+@xref{FPut Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node FPut Intrinsic (function)
+@subsubsection FPut Intrinsic (function)
+@cindex FPut intrinsic
+@cindex intrinsics, FPut
+
+@noindent
+@example
+FPut(@var{C})
+@end example
+
+@noindent
+FPut: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{C}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Writes the single character @var{C} in stream mode to unit 6
+(by-passing normal formatted output) using @code{getc(3)}.
+Returns 0 on
+success, the error code from @code{ferror(3)} otherwise.
+
+Stream I/O should not be mixed with normal record-oriented (formatted or
+unformatted) I/O on the same unit; the results are unpredictable.
+
+For information on other intrinsics with the same name:
+@xref{FPut Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF2U
+@node FPutC Intrinsic (subroutine)
+@subsubsection FPutC Intrinsic (subroutine)
+@cindex FPutC intrinsic
+@cindex intrinsics, FPutC
+
+@noindent
+@example
+CALL FPutC(@var{Unit}, @var{C}, @var{Status})
+@end example
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{C}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Writes the single character @var{Unit} in stream mode to unit 6
+(by-passing normal formatted output) using @code{putc(3)}.
+Returns in
+@var{C} 0 on success, the error code from @code{ferror(3)} otherwise.
+
+Stream I/O should not be mixed with normal record-oriented (formatted or
+unformatted) I/O on the same unit; the results are unpredictable.
+
+For information on other intrinsics with the same name:
+@xref{FPutC Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node FPutC Intrinsic (function)
+@subsubsection FPutC Intrinsic (function)
+@cindex FPutC intrinsic
+@cindex intrinsics, FPutC
+
+@noindent
+@example
+FPutC(@var{Unit}, @var{C})
+@end example
+
+@noindent
+FPutC: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{C}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Writes the single character @var{C} in stream mode to unit @var{Unit}
+(by-passing normal formatted output) using @code{putc(3)}.
+Returns 0 on
+success, the error code from @code{ferror(3)} otherwise.
+
+Stream I/O should not be mixed with normal record-oriented (formatted or
+unformatted) I/O on the same unit; the results are unpredictable.
+
+For information on other intrinsics with the same name:
+@xref{FPutC Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF90
+@node Fraction Intrinsic
+@subsubsection Fraction Intrinsic
+@cindex Fraction intrinsic
+@cindex intrinsics, Fraction
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Fraction} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node FSeek Intrinsic
+@subsubsection FSeek Intrinsic
+@cindex FSeek intrinsic
+@cindex intrinsics, FSeek
+
+@noindent
+@example
+CALL FSeek(@var{Unit}, @var{Offset}, @var{Whence}, @var{ErrLab})
+@end example
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Offset}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Whence}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{ErrLab}: @samp{*@var{label}}, where @var{label} is the label
+of an executable statement; OPTIONAL.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Attempts to move Fortran unit @var{Unit} to the specified
+@var{Offset}: absolute offset if @var{Whence}=0; relative to the
+current offset if @var{Whence}=1; relative to the end of the file if
+@var{Whence}=2.
+It branches to label @var{ErrLab} if @var{Unit} is
+not open or if the call otherwise fails.
+
+@node FStat Intrinsic (subroutine)
+@subsubsection FStat Intrinsic (subroutine)
+@cindex FStat intrinsic
+@cindex intrinsics, FStat
+
+@noindent
+@example
+CALL FStat(@var{Unit}, @var{SArray}, @var{Status})
+@end example
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{SArray}: @code{INTEGER(KIND=1)}; DIMENSION(13); INTENT(OUT).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Obtains data about the file open on Fortran I/O unit @var{Unit} and
+places them in the array @var{SArray}.
+The values in this array are
+extracted from the @code{stat} structure as returned by
+@code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+If the @var{Status} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{FStat Intrinsic (function)}.
+
+@node FStat Intrinsic (function)
+@subsubsection FStat Intrinsic (function)
+@cindex FStat intrinsic
+@cindex intrinsics, FStat
+
+@noindent
+@example
+FStat(@var{Unit}, @var{SArray})
+@end example
+
+@noindent
+FStat: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{SArray}: @code{INTEGER(KIND=1)}; DIMENSION(13); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Obtains data about the file open on Fortran I/O unit @var{Unit} and
+places them in the array @var{SArray}.
+The values in this array are
+extracted from the @code{stat} structure as returned by
+@code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+Returns 0 on success or a non-zero error code.
+
+For information on other intrinsics with the same name:
+@xref{FStat Intrinsic (subroutine)}.
+
+@node FTell Intrinsic (subroutine)
+@subsubsection FTell Intrinsic (subroutine)
+@cindex FTell intrinsic
+@cindex intrinsics, FTell
+
+@noindent
+@example
+CALL FTell(@var{Unit}, @var{Offset})
+@end example
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Offset}: @code{INTEGER(KIND=1)}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Sets @var{Offset} to the current offset of Fortran unit @var{Unit}
+(or to @minus{}1 if @var{Unit} is not open).
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+
+For information on other intrinsics with the same name:
+@xref{FTell Intrinsic (function)}.
+
+@node FTell Intrinsic (function)
+@subsubsection FTell Intrinsic (function)
+@cindex FTell intrinsic
+@cindex intrinsics, FTell
+
+@noindent
+@example
+FTell(@var{Unit})
+@end example
+
+@noindent
+FTell: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the current offset of Fortran unit @var{Unit}
+(or @minus{}1 if @var{Unit} is not open).
+
+For information on other intrinsics with the same name:
+@xref{FTell Intrinsic (subroutine)}.
+
+@node GError Intrinsic
+@subsubsection GError Intrinsic
+@cindex GError intrinsic
+@cindex intrinsics, GError
+
+@noindent
+@example
+CALL GError(@var{Message})
+@end example
+
+@noindent
+@var{Message}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the system error message corresponding to the last system
+error (C @code{errno}).
+
+@node GetArg Intrinsic
+@subsubsection GetArg Intrinsic
+@cindex GetArg intrinsic
+@cindex intrinsics, GetArg
+
+@noindent
+@example
+CALL GetArg(@var{Pos}, @var{Value})
+@end example
+
+@noindent
+@var{Pos}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Value}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Sets @var{Value} to the @var{Pos}-th command-line argument (or to all
+blanks if there are fewer than @var{Value} command-line arguments);
+@code{CALL GETARG(0, @var{value})} sets @var{value} to the name of the
+program (on systems that support this feature).
+
+@xref{IArgC Intrinsic}, for information on how to get the number
+of arguments.
+
+@node GetCWD Intrinsic (subroutine)
+@subsubsection GetCWD Intrinsic (subroutine)
+@cindex GetCWD intrinsic
+@cindex intrinsics, GetCWD
+
+@noindent
+@example
+CALL GetCWD(@var{Name}, @var{Status})
+@end example
+
+@noindent
+@var{Name}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Places the current working directory in @var{Name}.
+If the @var{Status} argument is supplied, it contains 0
+success or a non-zero error code upon return
+(@code{ENOSYS} if the system does not provide @code{getcwd(3)}
+or @code{getwd(3)}).
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{GetCWD Intrinsic (function)}.
+
+@node GetCWD Intrinsic (function)
+@subsubsection GetCWD Intrinsic (function)
+@cindex GetCWD intrinsic
+@cindex intrinsics, GetCWD
+
+@noindent
+@example
+GetCWD(@var{Name})
+@end example
+
+@noindent
+GetCWD: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Name}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Places the current working directory in @var{Name}.
+Returns 0 on
+success, otherwise a non-zero error code
+(@code{ENOSYS} if the system does not provide @code{getcwd(3)}
+or @code{getwd(3)}).
+
+For information on other intrinsics with the same name:
+@xref{GetCWD Intrinsic (subroutine)}.
+
+@node GetEnv Intrinsic
+@subsubsection GetEnv Intrinsic
+@cindex GetEnv intrinsic
+@cindex intrinsics, GetEnv
+
+@noindent
+@example
+CALL GetEnv(@var{Name}, @var{Value})
+@end example
+
+@noindent
+@var{Name}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Value}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Sets @var{Value} to the value of environment variable given by the
+value of @var{Name} (@code{$name} in shell terms) or to blanks if
+@code{$name} has not been set.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{Name}---otherwise,
+trailing blanks in @var{Name} are ignored.
+
+@node GetGId Intrinsic
+@subsubsection GetGId Intrinsic
+@cindex GetGId intrinsic
+@cindex intrinsics, GetGId
+
+@noindent
+@example
+GetGId()
+@end example
+
+@noindent
+GetGId: @code{INTEGER(KIND=1)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the group id for the current process.
+
+@node GetLog Intrinsic
+@subsubsection GetLog Intrinsic
+@cindex GetLog intrinsic
+@cindex intrinsics, GetLog
+
+@noindent
+@example
+CALL GetLog(@var{Login})
+@end example
+
+@noindent
+@var{Login}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the login name for the process in @var{Login}.
+
+@emph{Caution:} On some systems, the @code{getlogin(3)}
+function, which this intrinsic calls at run time,
+is either not implemented or returns a null pointer.
+In the latter case, this intrinsic returns blanks
+in @var{Login}.
+
+@node GetPId Intrinsic
+@subsubsection GetPId Intrinsic
+@cindex GetPId intrinsic
+@cindex intrinsics, GetPId
+
+@noindent
+@example
+GetPId()
+@end example
+
+@noindent
+GetPId: @code{INTEGER(KIND=1)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the process id for the current process.
+
+@node GetUId Intrinsic
+@subsubsection GetUId Intrinsic
+@cindex GetUId intrinsic
+@cindex intrinsics, GetUId
+
+@noindent
+@example
+GetUId()
+@end example
+
+@noindent
+GetUId: @code{INTEGER(KIND=1)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the user id for the current process.
+
+@node GMTime Intrinsic
+@subsubsection GMTime Intrinsic
+@cindex GMTime intrinsic
+@cindex intrinsics, GMTime
+
+@noindent
+@example
+CALL GMTime(@var{STime}, @var{TArray})
+@end example
+
+@noindent
+@var{STime}: @code{INTEGER(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+@var{TArray}: @code{INTEGER(KIND=1)}; DIMENSION(9); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Given a system time value @var{STime}, fills @var{TArray} with values
+extracted from it appropriate to the GMT time zone using
+@code{gmtime(3)}.
+
+The array elements are as follows:
+
+@enumerate
+@item
+Seconds after the minute, range 0--59 or 0--61 to allow for leap
+seconds
+
+@item
+Minutes after the hour, range 0--59
+
+@item
+Hours past midnight, range 0--23
+
+@item
+Day of month, range 0--31
+
+@item
+Number of months since January, range 0--12
+
+@item
+Years since 1900
+
+@item
+Number of days since Sunday, range 0--6
+
+@item
+Days since January 1
+
+@item
+Daylight savings indicator: positive if daylight savings is in effect,
+zero if not, and negative if the information isn't available.
+@end enumerate
+
+@node HostNm Intrinsic (subroutine)
+@subsubsection HostNm Intrinsic (subroutine)
+@cindex HostNm intrinsic
+@cindex intrinsics, HostNm
+
+@noindent
+@example
+CALL HostNm(@var{Name}, @var{Status})
+@end example
+
+@noindent
+@var{Name}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Fills @var{Name} with the system's host name returned by
+@code{gethostname(2)}.
+If the @var{Status} argument is supplied, it contains
+0 on success or a non-zero error code upon return
+(@code{ENOSYS} if the system does not provide @code{gethostname(2)}).
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+On some systems (specifically SCO) it may be necessary to link the
+``socket'' library if you call this routine.
+Typically this means adding @samp{-lg2c -lsocket -lm}
+to the @code{g77} command line when linking the program.
+
+For information on other intrinsics with the same name:
+@xref{HostNm Intrinsic (function)}.
+
+@node HostNm Intrinsic (function)
+@subsubsection HostNm Intrinsic (function)
+@cindex HostNm intrinsic
+@cindex intrinsics, HostNm
+
+@noindent
+@example
+HostNm(@var{Name})
+@end example
+
+@noindent
+HostNm: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Name}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Fills @var{Name} with the system's host name returned by
+@code{gethostname(2)}, returning 0 on success or a non-zero error code
+(@code{ENOSYS} if the system does not provide @code{gethostname(2)}).
+
+On some systems (specifically SCO) it may be necessary to link the
+``socket'' library if you call this routine.
+Typically this means adding @samp{-lg2c -lsocket -lm}
+to the @code{g77} command line when linking the program.
+
+For information on other intrinsics with the same name:
+@xref{HostNm Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF90
+@node Huge Intrinsic
+@subsubsection Huge Intrinsic
+@cindex Huge intrinsic
+@cindex intrinsics, Huge
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Huge} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node IAbs Intrinsic
+@subsubsection IAbs Intrinsic
+@cindex IAbs intrinsic
+@cindex intrinsics, IAbs
+
+@noindent
+@example
+IAbs(@var{A})
+@end example
+
+@noindent
+IAbs: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{INTEGER(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{ABS()} that is specific
+to one type for @var{A}.
+@xref{Abs Intrinsic}.
+
+@end ifset
+@ifset familyASC
+@node IAChar Intrinsic
+@subsubsection IAChar Intrinsic
+@cindex IAChar intrinsic
+@cindex intrinsics, IAChar
+
+@noindent
+@example
+IAChar(@var{C})
+@end example
+
+@noindent
+IAChar: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{C}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}, @code{f90}.
+
+@noindent
+Description:
+
+Returns the code for the ASCII character in the
+first character position of @var{C}.
+
+@xref{AChar Intrinsic}, for the inverse of this function.
+
+@xref{IChar Intrinsic}, for the function corresponding
+to the system's native character set.
+
+@end ifset
+@ifset familyMIL
+@node IAnd Intrinsic
+@subsubsection IAnd Intrinsic
+@cindex IAnd intrinsic
+@cindex intrinsics, IAnd
+
+@noindent
+@example
+IAnd(@var{I}, @var{J})
+@end example
+
+@noindent
+IAnd: @code{INTEGER} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{J}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+Returns value resulting from boolean AND of
+pair of bits in each of @var{I} and @var{J}.
+
+@end ifset
+@ifset familyF2U
+@node IArgC Intrinsic
+@subsubsection IArgC Intrinsic
+@cindex IArgC intrinsic
+@cindex intrinsics, IArgC
+
+@noindent
+@example
+IArgC()
+@end example
+
+@noindent
+IArgC: @code{INTEGER(KIND=1)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the number of command-line arguments.
+
+This count does not include the specification of the program
+name itself.
+
+@end ifset
+@ifset familyMIL
+@node IBClr Intrinsic
+@subsubsection IBClr Intrinsic
+@cindex IBClr intrinsic
+@cindex intrinsics, IBClr
+
+@noindent
+@example
+IBClr(@var{I}, @var{Pos})
+@end example
+
+@noindent
+IBClr: @code{INTEGER} function, the @samp{KIND=} value of the type being that of argument @var{I}.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Pos}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+Returns the value of @var{I} with bit @var{Pos} cleared (set to
+zero).
+@xref{BTest Intrinsic}, for information on bit positions.
+
+@node IBits Intrinsic
+@subsubsection IBits Intrinsic
+@cindex IBits intrinsic
+@cindex intrinsics, IBits
+
+@noindent
+@example
+IBits(@var{I}, @var{Pos}, @var{Len})
+@end example
+
+@noindent
+IBits: @code{INTEGER} function, the @samp{KIND=} value of the type being that of argument @var{I}.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Pos}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Len}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+Extracts a subfield of length @var{Len} from @var{I}, starting from
+bit position @var{Pos} and extending left for @var{Len} bits.
+The result is right-justified and the remaining bits are zeroed.
+The value
+of @samp{@var{Pos}+@var{Len}} must be less than or equal to the value
+@samp{BIT_SIZE(@var{I})}.
+@xref{Bit_Size Intrinsic}.
+
+@node IBSet Intrinsic
+@subsubsection IBSet Intrinsic
+@cindex IBSet intrinsic
+@cindex intrinsics, IBSet
+
+@noindent
+@example
+IBSet(@var{I}, @var{Pos})
+@end example
+
+@noindent
+IBSet: @code{INTEGER} function, the @samp{KIND=} value of the type being that of argument @var{I}.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Pos}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+Returns the value of @var{I} with bit @var{Pos} set (to one).
+@xref{BTest Intrinsic}, for information on bit positions.
+
+@end ifset
+@ifset familyF77
+@node IChar Intrinsic
+@subsubsection IChar Intrinsic
+@cindex IChar intrinsic
+@cindex intrinsics, IChar
+
+@noindent
+@example
+IChar(@var{C})
+@end example
+
+@noindent
+IChar: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{C}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the code for the character in the
+first character position of @var{C}.
+
+Because the system's native character set is used,
+the correspondence between character and their codes
+is not necessarily the same between GNU Fortran
+implementations.
+
+Note that no intrinsic exists to convert a printable
+character string to a numerical value.
+For example, there is no intrinsic that, given
+the @code{CHARACTER} value @samp{'154'}, returns an
+@code{INTEGER} or @code{REAL} value with the value @samp{154}.
+
+Instead, you can use internal-file I/O to do this kind
+of conversion.
+For example:
+
+@smallexample
+INTEGER VALUE
+CHARACTER*10 STRING
+STRING = '154'
+READ (STRING, '(I10)'), VALUE
+PRINT *, VALUE
+END
+@end smallexample
+
+The above program, when run, prints:
+
+@smallexample
+ 154
+@end smallexample
+
+@xref{Char Intrinsic}, for the inverse of the @code{ICHAR} function.
+
+@xref{IAChar Intrinsic}, for the function corresponding
+to the ASCII character set.
+
+@end ifset
+@ifset familyF2U
+@node IDate Intrinsic (UNIX)
+@subsubsection IDate Intrinsic (UNIX)
+@cindex IDate intrinsic
+@cindex intrinsics, IDate
+
+@noindent
+@example
+CALL IDate(@var{TArray})
+@end example
+
+@noindent
+@var{TArray}: @code{INTEGER(KIND=1)}; DIMENSION(3); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Fills @var{TArray} with the numerical values at the current local time
+of day, month (in the range 1--12), and year in elements 1, 2, and 3,
+respectively.
+The year has four significant digits.
+
+For information on other intrinsics with the same name:
+@xref{IDate Intrinsic (VXT)}.
+
+@end ifset
+@ifset familyVXT
+@node IDate Intrinsic (VXT)
+@subsubsection IDate Intrinsic (VXT)
+@cindex IDate intrinsic
+@cindex intrinsics, IDate
+
+@noindent
+@example
+CALL IDate(@var{M}, @var{D}, @var{Y})
+@end example
+
+@noindent
+@var{M}: @code{INTEGER(KIND=1)}; scalar; INTENT(OUT).
+
+@noindent
+@var{D}: @code{INTEGER(KIND=1)}; scalar; INTENT(OUT).
+
+@noindent
+@var{Y}: @code{INTEGER(KIND=1)}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{vxt}.
+
+@noindent
+Description:
+
+Returns the numerical values of the current local time.
+The month (in the range 1--12) is returned in @var{M},
+the day (in the range 1--7) in @var{D},
+and the year in @var{Y} (in the range 0--99).
+
+This intrinsic is not recommended, due to the year 2000 approaching.
+
+For information on other intrinsics with the same name:
+@xref{IDate Intrinsic (UNIX)}.
+
+@end ifset
+@ifset familyF77
+@node IDiM Intrinsic
+@subsubsection IDiM Intrinsic
+@cindex IDiM intrinsic
+@cindex intrinsics, IDiM
+
+@noindent
+@example
+IDiM(@var{X}, @var{Y})
+@end example
+
+@noindent
+IDiM: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{X}: @code{INTEGER(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+@var{Y}: @code{INTEGER(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{DIM()} that is specific
+to one type for @var{X} and @var{Y}.
+@xref{DiM Intrinsic}.
+
+@node IDInt Intrinsic
+@subsubsection IDInt Intrinsic
+@cindex IDInt intrinsic
+@cindex intrinsics, IDInt
+
+@noindent
+@example
+IDInt(@var{A})
+@end example
+
+@noindent
+IDInt: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{INT()} that is specific
+to one type for @var{A}.
+@xref{Int Intrinsic}.
+
+@node IDNInt Intrinsic
+@subsubsection IDNInt Intrinsic
+@cindex IDNInt intrinsic
+@cindex intrinsics, IDNInt
+
+@noindent
+@example
+IDNInt(@var{A})
+@end example
+
+@noindent
+IDNInt: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{NINT()} that is specific
+to one type for @var{A}.
+@xref{NInt Intrinsic}.
+
+@end ifset
+@ifset familyMIL
+@node IEOr Intrinsic
+@subsubsection IEOr Intrinsic
+@cindex IEOr intrinsic
+@cindex intrinsics, IEOr
+
+@noindent
+@example
+IEOr(@var{I}, @var{J})
+@end example
+
+@noindent
+IEOr: @code{INTEGER} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{J}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+Returns value resulting from boolean exclusive-OR of
+pair of bits in each of @var{I} and @var{J}.
+
+@end ifset
+@ifset familyF2U
+@node IErrNo Intrinsic
+@subsubsection IErrNo Intrinsic
+@cindex IErrNo intrinsic
+@cindex intrinsics, IErrNo
+
+@noindent
+@example
+IErrNo()
+@end example
+
+@noindent
+IErrNo: @code{INTEGER(KIND=1)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the last system error number (corresponding to the C
+@code{errno}).
+
+@end ifset
+@ifset familyF77
+@node IFix Intrinsic
+@subsubsection IFix Intrinsic
+@cindex IFix intrinsic
+@cindex intrinsics, IFix
+
+@noindent
+@example
+IFix(@var{A})
+@end example
+
+@noindent
+IFix: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{INT()} that is specific
+to one type for @var{A}.
+@xref{Int Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node IIAbs Intrinsic
+@subsubsection IIAbs Intrinsic
+@cindex IIAbs intrinsic
+@cindex intrinsics, IIAbs
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIAbs} to use this name for an
+external procedure.
+
+@node IIAnd Intrinsic
+@subsubsection IIAnd Intrinsic
+@cindex IIAnd intrinsic
+@cindex intrinsics, IIAnd
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIAnd} to use this name for an
+external procedure.
+
+@node IIBClr Intrinsic
+@subsubsection IIBClr Intrinsic
+@cindex IIBClr intrinsic
+@cindex intrinsics, IIBClr
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIBClr} to use this name for an
+external procedure.
+
+@node IIBits Intrinsic
+@subsubsection IIBits Intrinsic
+@cindex IIBits intrinsic
+@cindex intrinsics, IIBits
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIBits} to use this name for an
+external procedure.
+
+@node IIBSet Intrinsic
+@subsubsection IIBSet Intrinsic
+@cindex IIBSet intrinsic
+@cindex intrinsics, IIBSet
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIBSet} to use this name for an
+external procedure.
+
+@node IIDiM Intrinsic
+@subsubsection IIDiM Intrinsic
+@cindex IIDiM intrinsic
+@cindex intrinsics, IIDiM
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIDiM} to use this name for an
+external procedure.
+
+@node IIDInt Intrinsic
+@subsubsection IIDInt Intrinsic
+@cindex IIDInt intrinsic
+@cindex intrinsics, IIDInt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIDInt} to use this name for an
+external procedure.
+
+@node IIDNnt Intrinsic
+@subsubsection IIDNnt Intrinsic
+@cindex IIDNnt intrinsic
+@cindex intrinsics, IIDNnt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIDNnt} to use this name for an
+external procedure.
+
+@node IIEOr Intrinsic
+@subsubsection IIEOr Intrinsic
+@cindex IIEOr intrinsic
+@cindex intrinsics, IIEOr
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIEOr} to use this name for an
+external procedure.
+
+@node IIFix Intrinsic
+@subsubsection IIFix Intrinsic
+@cindex IIFix intrinsic
+@cindex intrinsics, IIFix
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIFix} to use this name for an
+external procedure.
+
+@node IInt Intrinsic
+@subsubsection IInt Intrinsic
+@cindex IInt intrinsic
+@cindex intrinsics, IInt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IInt} to use this name for an
+external procedure.
+
+@node IIOr Intrinsic
+@subsubsection IIOr Intrinsic
+@cindex IIOr intrinsic
+@cindex intrinsics, IIOr
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIOr} to use this name for an
+external procedure.
+
+@node IIQint Intrinsic
+@subsubsection IIQint Intrinsic
+@cindex IIQint intrinsic
+@cindex intrinsics, IIQint
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIQint} to use this name for an
+external procedure.
+
+@node IIQNnt Intrinsic
+@subsubsection IIQNnt Intrinsic
+@cindex IIQNnt intrinsic
+@cindex intrinsics, IIQNnt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIQNnt} to use this name for an
+external procedure.
+
+@node IIShftC Intrinsic
+@subsubsection IIShftC Intrinsic
+@cindex IIShftC intrinsic
+@cindex intrinsics, IIShftC
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IIShftC} to use this name for an
+external procedure.
+
+@node IISign Intrinsic
+@subsubsection IISign Intrinsic
+@cindex IISign intrinsic
+@cindex intrinsics, IISign
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IISign} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2C
+@node Imag Intrinsic
+@subsubsection Imag Intrinsic
+@cindex Imag intrinsic
+@cindex intrinsics, Imag
+
+@noindent
+@example
+Imag(@var{Z})
+@end example
+
+@noindent
+Imag: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{Z}.
+
+@noindent
+@var{Z}: @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+The imaginary part of @var{Z} is returned, without conversion.
+
+@emph{Note:} The way to do this in standard Fortran 90
+is @samp{AIMAG(@var{Z})}.
+However, when, for example, @var{Z} is @code{DOUBLE COMPLEX},
+@samp{AIMAG(@var{Z})} means something different for some compilers
+that are not true Fortran 90 compilers but offer some
+extensions standardized by Fortran 90 (such as the
+@code{DOUBLE COMPLEX} type, also known as @code{COMPLEX(KIND=2)}).
+
+The advantage of @code{IMAG()} is that, while not necessarily
+more or less portable than @code{AIMAG()}, it is more likely to
+cause a compiler that doesn't support it to produce a diagnostic
+than generate incorrect code.
+
+@xref{REAL() and AIMAG() of Complex}, for more information.
+
+@end ifset
+@ifset familyGNU
+@node ImagPart Intrinsic
+@subsubsection ImagPart Intrinsic
+@cindex ImagPart intrinsic
+@cindex intrinsics, ImagPart
+
+@noindent
+@example
+ImagPart(@var{Z})
+@end example
+
+@noindent
+ImagPart: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{Z}.
+
+@noindent
+@var{Z}: @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{gnu}.
+
+@noindent
+Description:
+
+The imaginary part of @var{Z} is returned, without conversion.
+
+@emph{Note:} The way to do this in standard Fortran 90
+is @samp{AIMAG(@var{Z})}.
+However, when, for example, @var{Z} is @code{DOUBLE COMPLEX},
+@samp{AIMAG(@var{Z})} means something different for some compilers
+that are not true Fortran 90 compilers but offer some
+extensions standardized by Fortran 90 (such as the
+@code{DOUBLE COMPLEX} type, also known as @code{COMPLEX(KIND=2)}).
+
+The advantage of @code{IMAGPART()} is that, while not necessarily
+more or less portable than @code{AIMAG()}, it is more likely to
+cause a compiler that doesn't support it to produce a diagnostic
+than generate incorrect code.
+
+@xref{REAL() and AIMAG() of Complex}, for more information.
+
+@end ifset
+@ifset familyVXT
+@node IMax0 Intrinsic
+@subsubsection IMax0 Intrinsic
+@cindex IMax0 intrinsic
+@cindex intrinsics, IMax0
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IMax0} to use this name for an
+external procedure.
+
+@node IMax1 Intrinsic
+@subsubsection IMax1 Intrinsic
+@cindex IMax1 intrinsic
+@cindex intrinsics, IMax1
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IMax1} to use this name for an
+external procedure.
+
+@node IMin0 Intrinsic
+@subsubsection IMin0 Intrinsic
+@cindex IMin0 intrinsic
+@cindex intrinsics, IMin0
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IMin0} to use this name for an
+external procedure.
+
+@node IMin1 Intrinsic
+@subsubsection IMin1 Intrinsic
+@cindex IMin1 intrinsic
+@cindex intrinsics, IMin1
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IMin1} to use this name for an
+external procedure.
+
+@node IMod Intrinsic
+@subsubsection IMod Intrinsic
+@cindex IMod intrinsic
+@cindex intrinsics, IMod
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IMod} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node Index Intrinsic
+@subsubsection Index Intrinsic
+@cindex Index intrinsic
+@cindex intrinsics, Index
+
+@noindent
+@example
+Index(@var{String}, @var{Substring})
+@end example
+
+@noindent
+Index: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{String}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Substring}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the position of the start of the first occurrence of string
+@var{Substring} as a substring in @var{String}, counting from one.
+If @var{Substring} doesn't occur in @var{String}, zero is returned.
+
+@end ifset
+@ifset familyVXT
+@node INInt Intrinsic
+@subsubsection INInt Intrinsic
+@cindex INInt intrinsic
+@cindex intrinsics, INInt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL INInt} to use this name for an
+external procedure.
+
+@node INot Intrinsic
+@subsubsection INot Intrinsic
+@cindex INot intrinsic
+@cindex intrinsics, INot
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL INot} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node Int Intrinsic
+@subsubsection Int Intrinsic
+@cindex Int intrinsic
+@cindex intrinsics, Int
+
+@noindent
+@example
+Int(@var{A})
+@end example
+
+@noindent
+Int: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{INTEGER}, @code{REAL}, or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @var{A} with the fractional portion of its
+magnitude truncated and its sign preserved, converted
+to type @code{INTEGER(KIND=1)}.
+
+If @var{A} is type @code{COMPLEX}, its real part is
+truncated and converted, and its imaginary part is disregarded.
+
+@xref{NInt Intrinsic}, for how to convert, rounded to nearest
+whole number.
+
+@xref{AInt Intrinsic}, for how to truncate to whole number
+without converting.
+
+@end ifset
+@ifset familyGNU
+@node Int2 Intrinsic
+@subsubsection Int2 Intrinsic
+@cindex Int2 intrinsic
+@cindex intrinsics, Int2
+
+@noindent
+@example
+Int2(@var{A})
+@end example
+
+@noindent
+Int2: @code{INTEGER(KIND=6)} function.
+
+@noindent
+@var{A}: @code{INTEGER}, @code{REAL}, or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{gnu}.
+
+@noindent
+Description:
+
+Returns @var{A} with the fractional portion of its
+magnitude truncated and its sign preserved, converted
+to type @code{INTEGER(KIND=6)}.
+
+If @var{A} is type @code{COMPLEX}, its real part
+is truncated and converted, and its imaginary part is disgregarded.
+
+@xref{Int Intrinsic}.
+
+The precise meaning of this intrinsic might change
+in a future version of the GNU Fortran language,
+as more is learned about how it is used.
+
+@node Int8 Intrinsic
+@subsubsection Int8 Intrinsic
+@cindex Int8 intrinsic
+@cindex intrinsics, Int8
+
+@noindent
+@example
+Int8(@var{A})
+@end example
+
+@noindent
+Int8: @code{INTEGER(KIND=2)} function.
+
+@noindent
+@var{A}: @code{INTEGER}, @code{REAL}, or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{gnu}.
+
+@noindent
+Description:
+
+Returns @var{A} with the fractional portion of its
+magnitude truncated and its sign preserved, converted
+to type @code{INTEGER(KIND=2)}.
+
+If @var{A} is type @code{COMPLEX}, its real part
+is truncated and converted, and its imaginary part is disgregarded.
+
+@xref{Int Intrinsic}.
+
+The precise meaning of this intrinsic might change
+in a future version of the GNU Fortran language,
+as more is learned about how it is used.
+
+@end ifset
+@ifset familyMIL
+@node IOr Intrinsic
+@subsubsection IOr Intrinsic
+@cindex IOr intrinsic
+@cindex intrinsics, IOr
+
+@noindent
+@example
+IOr(@var{I}, @var{J})
+@end example
+
+@noindent
+IOr: @code{INTEGER} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{J}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+Returns value resulting from boolean OR of
+pair of bits in each of @var{I} and @var{J}.
+
+@end ifset
+@ifset familyF2U
+@node IRand Intrinsic
+@subsubsection IRand Intrinsic
+@cindex IRand intrinsic
+@cindex intrinsics, IRand
+
+@noindent
+@example
+IRand(@var{Flag})
+@end example
+
+@noindent
+IRand: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Flag}: @code{INTEGER}; OPTIONAL; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns a uniform quasi-random number up to a system-dependent limit.
+If @var{Flag} is 0, the next number in sequence is returned; if
+@var{Flag} is 1, the generator is restarted by calling the UNIX function
+@samp{srand(0)}; if @var{Flag} has any other value,
+it is used as a new seed with @code{srand()}.
+
+@xref{SRand Intrinsic}.
+
+@emph{Note:} As typically implemented (by the routine of the same
+name in the C library), this random number generator is a very poor
+one, though the BSD and GNU libraries provide a much better
+implementation than the `traditional' one.
+On a different system you almost certainly want to use something better.
+
+@node IsaTty Intrinsic
+@subsubsection IsaTty Intrinsic
+@cindex IsaTty intrinsic
+@cindex intrinsics, IsaTty
+
+@noindent
+@example
+IsaTty(@var{Unit})
+@end example
+
+@noindent
+IsaTty: @code{LOGICAL(KIND=1)} function.
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns @code{.TRUE.} if and only if the Fortran I/O unit
+specified by @var{Unit} is connected
+to a terminal device.
+See @code{isatty(3)}.
+
+@end ifset
+@ifset familyMIL
+@node IShft Intrinsic
+@subsubsection IShft Intrinsic
+@cindex IShft intrinsic
+@cindex intrinsics, IShft
+
+@noindent
+@example
+IShft(@var{I}, @var{Shift})
+@end example
+
+@noindent
+IShft: @code{INTEGER} function, the @samp{KIND=} value of the type being that of argument @var{I}.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Shift}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+All bits representing @var{I} are shifted @var{Shift} places.
+@samp{@var{Shift}.GT.0} indicates a left shift, @samp{@var{Shift}.EQ.0}
+indicates no shift and @samp{@var{Shift}.LT.0} indicates a right shift.
+If the absolute value of the shift count is greater than
+@samp{BIT_SIZE(@var{I})}, the result is undefined.
+Bits shifted out from the left end or the right end, as the case may be,
+are lost.
+Zeros are shifted in from the opposite end.
+
+@xref{IShftC Intrinsic}, for the circular-shift equivalent.
+
+@node IShftC Intrinsic
+@subsubsection IShftC Intrinsic
+@cindex IShftC intrinsic
+@cindex intrinsics, IShftC
+
+@noindent
+@example
+IShftC(@var{I}, @var{Shift}, @var{Size})
+@end example
+
+@noindent
+IShftC: @code{INTEGER} function, the @samp{KIND=} value of the type being that of argument @var{I}.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Shift}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Size}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+The rightmost @var{Size} bits of the argument @var{I}
+are shifted circularly @var{Shift}
+places, i.e.@: the bits shifted out of one end are shifted into
+the opposite end.
+No bits are lost.
+The unshifted bits of the result are the same as
+the unshifted bits of @var{I}.
+The absolute value of the argument @var{Shift}
+must be less than or equal to @var{Size}.
+The value of @var{Size} must be greater than or equal to one and less than
+or equal to @samp{BIT_SIZE(@var{I})}.
+
+@xref{IShft Intrinsic}, for the logical shift equivalent.
+
+@end ifset
+@ifset familyF77
+@node ISign Intrinsic
+@subsubsection ISign Intrinsic
+@cindex ISign intrinsic
+@cindex intrinsics, ISign
+
+@noindent
+@example
+ISign(@var{A}, @var{B})
+@end example
+
+@noindent
+ISign: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{INTEGER(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+@var{B}: @code{INTEGER(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{SIGN()} that is specific
+to one type for @var{A} and @var{B}.
+@xref{Sign Intrinsic}.
+
+@end ifset
+@ifset familyF2U
+@node ITime Intrinsic
+@subsubsection ITime Intrinsic
+@cindex ITime intrinsic
+@cindex intrinsics, ITime
+
+@noindent
+@example
+CALL ITime(@var{TArray})
+@end example
+
+@noindent
+@var{TArray}: @code{INTEGER(KIND=1)}; DIMENSION(3); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the current local time hour, minutes, and seconds in elements
+1, 2, and 3 of @var{TArray}, respectively.
+
+@end ifset
+@ifset familyVXT
+@node IZExt Intrinsic
+@subsubsection IZExt Intrinsic
+@cindex IZExt intrinsic
+@cindex intrinsics, IZExt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL IZExt} to use this name for an
+external procedure.
+
+@node JIAbs Intrinsic
+@subsubsection JIAbs Intrinsic
+@cindex JIAbs intrinsic
+@cindex intrinsics, JIAbs
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIAbs} to use this name for an
+external procedure.
+
+@node JIAnd Intrinsic
+@subsubsection JIAnd Intrinsic
+@cindex JIAnd intrinsic
+@cindex intrinsics, JIAnd
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIAnd} to use this name for an
+external procedure.
+
+@node JIBClr Intrinsic
+@subsubsection JIBClr Intrinsic
+@cindex JIBClr intrinsic
+@cindex intrinsics, JIBClr
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIBClr} to use this name for an
+external procedure.
+
+@node JIBits Intrinsic
+@subsubsection JIBits Intrinsic
+@cindex JIBits intrinsic
+@cindex intrinsics, JIBits
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIBits} to use this name for an
+external procedure.
+
+@node JIBSet Intrinsic
+@subsubsection JIBSet Intrinsic
+@cindex JIBSet intrinsic
+@cindex intrinsics, JIBSet
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIBSet} to use this name for an
+external procedure.
+
+@node JIDiM Intrinsic
+@subsubsection JIDiM Intrinsic
+@cindex JIDiM intrinsic
+@cindex intrinsics, JIDiM
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIDiM} to use this name for an
+external procedure.
+
+@node JIDInt Intrinsic
+@subsubsection JIDInt Intrinsic
+@cindex JIDInt intrinsic
+@cindex intrinsics, JIDInt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIDInt} to use this name for an
+external procedure.
+
+@node JIDNnt Intrinsic
+@subsubsection JIDNnt Intrinsic
+@cindex JIDNnt intrinsic
+@cindex intrinsics, JIDNnt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIDNnt} to use this name for an
+external procedure.
+
+@node JIEOr Intrinsic
+@subsubsection JIEOr Intrinsic
+@cindex JIEOr intrinsic
+@cindex intrinsics, JIEOr
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIEOr} to use this name for an
+external procedure.
+
+@node JIFix Intrinsic
+@subsubsection JIFix Intrinsic
+@cindex JIFix intrinsic
+@cindex intrinsics, JIFix
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIFix} to use this name for an
+external procedure.
+
+@node JInt Intrinsic
+@subsubsection JInt Intrinsic
+@cindex JInt intrinsic
+@cindex intrinsics, JInt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JInt} to use this name for an
+external procedure.
+
+@node JIOr Intrinsic
+@subsubsection JIOr Intrinsic
+@cindex JIOr intrinsic
+@cindex intrinsics, JIOr
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIOr} to use this name for an
+external procedure.
+
+@node JIQint Intrinsic
+@subsubsection JIQint Intrinsic
+@cindex JIQint intrinsic
+@cindex intrinsics, JIQint
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIQint} to use this name for an
+external procedure.
+
+@node JIQNnt Intrinsic
+@subsubsection JIQNnt Intrinsic
+@cindex JIQNnt intrinsic
+@cindex intrinsics, JIQNnt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIQNnt} to use this name for an
+external procedure.
+
+@node JIShft Intrinsic
+@subsubsection JIShft Intrinsic
+@cindex JIShft intrinsic
+@cindex intrinsics, JIShft
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIShft} to use this name for an
+external procedure.
+
+@node JIShftC Intrinsic
+@subsubsection JIShftC Intrinsic
+@cindex JIShftC intrinsic
+@cindex intrinsics, JIShftC
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JIShftC} to use this name for an
+external procedure.
+
+@node JISign Intrinsic
+@subsubsection JISign Intrinsic
+@cindex JISign intrinsic
+@cindex intrinsics, JISign
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JISign} to use this name for an
+external procedure.
+
+@node JMax0 Intrinsic
+@subsubsection JMax0 Intrinsic
+@cindex JMax0 intrinsic
+@cindex intrinsics, JMax0
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JMax0} to use this name for an
+external procedure.
+
+@node JMax1 Intrinsic
+@subsubsection JMax1 Intrinsic
+@cindex JMax1 intrinsic
+@cindex intrinsics, JMax1
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JMax1} to use this name for an
+external procedure.
+
+@node JMin0 Intrinsic
+@subsubsection JMin0 Intrinsic
+@cindex JMin0 intrinsic
+@cindex intrinsics, JMin0
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JMin0} to use this name for an
+external procedure.
+
+@node JMin1 Intrinsic
+@subsubsection JMin1 Intrinsic
+@cindex JMin1 intrinsic
+@cindex intrinsics, JMin1
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JMin1} to use this name for an
+external procedure.
+
+@node JMod Intrinsic
+@subsubsection JMod Intrinsic
+@cindex JMod intrinsic
+@cindex intrinsics, JMod
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JMod} to use this name for an
+external procedure.
+
+@node JNInt Intrinsic
+@subsubsection JNInt Intrinsic
+@cindex JNInt intrinsic
+@cindex intrinsics, JNInt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JNInt} to use this name for an
+external procedure.
+
+@node JNot Intrinsic
+@subsubsection JNot Intrinsic
+@cindex JNot intrinsic
+@cindex intrinsics, JNot
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JNot} to use this name for an
+external procedure.
+
+@node JZExt Intrinsic
+@subsubsection JZExt Intrinsic
+@cindex JZExt intrinsic
+@cindex intrinsics, JZExt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL JZExt} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node Kill Intrinsic (subroutine)
+@subsubsection Kill Intrinsic (subroutine)
+@cindex Kill intrinsic
+@cindex intrinsics, Kill
+
+@noindent
+@example
+CALL Kill(@var{Pid}, @var{Signal}, @var{Status})
+@end example
+
+@noindent
+@var{Pid}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Signal}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Sends the signal specified by @var{Signal} to the process @var{Pid}.
+If the @var{Status} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+See @code{kill(2)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{Kill Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node Kill Intrinsic (function)
+@subsubsection Kill Intrinsic (function)
+@cindex Kill intrinsic
+@cindex intrinsics, Kill
+
+@noindent
+@example
+Kill(@var{Pid}, @var{Signal})
+@end example
+
+@noindent
+Kill: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Pid}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Signal}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Sends the signal specified by @var{Signal} to the process @var{Pid}.
+Returns 0 on success or a non-zero error code.
+See @code{kill(2)}.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+For information on other intrinsics with the same name:
+@xref{Kill Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF90
+@node Kind Intrinsic
+@subsubsection Kind Intrinsic
+@cindex Kind intrinsic
+@cindex intrinsics, Kind
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Kind} to use this name for an
+external procedure.
+
+@node LBound Intrinsic
+@subsubsection LBound Intrinsic
+@cindex LBound intrinsic
+@cindex intrinsics, LBound
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL LBound} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node Len Intrinsic
+@subsubsection Len Intrinsic
+@cindex Len intrinsic
+@cindex intrinsics, Len
+
+@noindent
+@example
+Len(@var{String})
+@end example
+
+@noindent
+Len: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{String}: @code{CHARACTER}; scalar.
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the length of @var{String}.
+
+If @var{String} is an array, the length of an element
+of @var{String} is returned.
+
+Note that @var{String} need not be defined when this
+intrinsic is invoked, since only the length, not
+the content, of @var{String} is needed.
+
+@xref{Bit_Size Intrinsic}, for the function that determines
+the size of its argument in bits.
+
+@end ifset
+@ifset familyF90
+@node Len_Trim Intrinsic
+@subsubsection Len_Trim Intrinsic
+@cindex Len_Trim intrinsic
+@cindex intrinsics, Len_Trim
+
+@noindent
+@example
+Len_Trim(@var{String})
+@end example
+
+@noindent
+Len_Trim: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{String}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f90}.
+
+@noindent
+Description:
+
+Returns the index of the last non-blank character in @var{String}.
+@code{LNBLNK} and @code{LEN_TRIM} are equivalent.
+
+@end ifset
+@ifset familyF77
+@node LGe Intrinsic
+@subsubsection LGe Intrinsic
+@cindex LGe intrinsic
+@cindex intrinsics, LGe
+
+@noindent
+@example
+LGe(@var{String_A}, @var{String_B})
+@end example
+
+@noindent
+LGe: @code{LOGICAL(KIND=1)} function.
+
+@noindent
+@var{String_A}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{String_B}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @samp{.TRUE.} if @samp{@var{String_A}.GE.@var{String_B}},
+@samp{.FALSE.} otherwise.
+@var{String_A} and @var{String_B} are interpreted as containing
+ASCII character codes.
+If either value contains a character not in the ASCII
+character set, the result is processor dependent.
+
+If the @var{String_A} and @var{String_B} are not the same length,
+the shorter is compared as if spaces were appended to
+it to form a value that has the same length as the longer.
+
+The lexical comparison intrinsics @code{LGe}, @code{LGt},
+@code{LLe}, and @code{LLt} differ from the corresponding
+intrinsic operators @code{.GE.}, @code{.GT.},
+@code{.LE.}, @code{.LT.}.
+Because the ASCII collating sequence is assumed,
+the following expressions always return @samp{.TRUE.}:
+
+@smallexample
+LGE ('0', ' ')
+LGE ('A', '0')
+LGE ('a', 'A')
+@end smallexample
+
+The following related expressions do @emph{not} always
+return @samp{.TRUE.}, as they are not necessarily evaluated
+assuming the arguments use ASCII encoding:
+
+@smallexample
+'0' .GE. ' '
+'A' .GE. '0'
+'a' .GE. 'A'
+@end smallexample
+
+The same difference exists
+between @code{LGt} and @code{.GT.};
+between @code{LLe} and @code{.LE.}; and
+between @code{LLt} and @code{.LT.}.
+
+@node LGt Intrinsic
+@subsubsection LGt Intrinsic
+@cindex LGt intrinsic
+@cindex intrinsics, LGt
+
+@noindent
+@example
+LGt(@var{String_A}, @var{String_B})
+@end example
+
+@noindent
+LGt: @code{LOGICAL(KIND=1)} function.
+
+@noindent
+@var{String_A}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{String_B}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @samp{.TRUE.} if @samp{@var{String_A}.GT.@var{String_B}},
+@samp{.FALSE.} otherwise.
+@var{String_A} and @var{String_B} are interpreted as containing
+ASCII character codes.
+If either value contains a character not in the ASCII
+character set, the result is processor dependent.
+
+If the @var{String_A} and @var{String_B} are not the same length,
+the shorter is compared as if spaces were appended to
+it to form a value that has the same length as the longer.
+
+@xref{LGe Intrinsic}, for information on the distinction
+between the @code{LGT} intrinsic and the @code{.GT.}
+operator.
+
+@end ifset
+@ifset familyF2U
+@node Link Intrinsic (subroutine)
+@subsubsection Link Intrinsic (subroutine)
+@cindex Link intrinsic
+@cindex intrinsics, Link
+
+@noindent
+@example
+CALL Link(@var{Path1}, @var{Path2}, @var{Status})
+@end example
+
+@noindent
+@var{Path1}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Path2}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Makes a (hard) link from file @var{Path1} to @var{Path2}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{Path1} and @var{Path2}---otherwise,
+trailing blanks in @var{Path1} and @var{Path2} are ignored.
+If the @var{Status} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+See @code{link(2)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{Link Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node Link Intrinsic (function)
+@subsubsection Link Intrinsic (function)
+@cindex Link intrinsic
+@cindex intrinsics, Link
+
+@noindent
+@example
+Link(@var{Path1}, @var{Path2})
+@end example
+
+@noindent
+Link: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Path1}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Path2}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Makes a (hard) link from file @var{Path1} to @var{Path2}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{Path1} and @var{Path2}---otherwise,
+trailing blanks in @var{Path1} and @var{Path2} are ignored.
+Returns 0 on success or a non-zero error code.
+See @code{link(2)}.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+For information on other intrinsics with the same name:
+@xref{Link Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF77
+@node LLe Intrinsic
+@subsubsection LLe Intrinsic
+@cindex LLe intrinsic
+@cindex intrinsics, LLe
+
+@noindent
+@example
+LLe(@var{String_A}, @var{String_B})
+@end example
+
+@noindent
+LLe: @code{LOGICAL(KIND=1)} function.
+
+@noindent
+@var{String_A}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{String_B}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @samp{.TRUE.} if @samp{@var{String_A}.LE.@var{String_B}},
+@samp{.FALSE.} otherwise.
+@var{String_A} and @var{String_B} are interpreted as containing
+ASCII character codes.
+If either value contains a character not in the ASCII
+character set, the result is processor dependent.
+
+If the @var{String_A} and @var{String_B} are not the same length,
+the shorter is compared as if spaces were appended to
+it to form a value that has the same length as the longer.
+
+@xref{LGe Intrinsic}, for information on the distinction
+between the @code{LLE} intrinsic and the @code{.LE.}
+operator.
+
+@node LLt Intrinsic
+@subsubsection LLt Intrinsic
+@cindex LLt intrinsic
+@cindex intrinsics, LLt
+
+@noindent
+@example
+LLt(@var{String_A}, @var{String_B})
+@end example
+
+@noindent
+LLt: @code{LOGICAL(KIND=1)} function.
+
+@noindent
+@var{String_A}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{String_B}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @samp{.TRUE.} if @samp{@var{String_A}.LT.@var{String_B}},
+@samp{.FALSE.} otherwise.
+@var{String_A} and @var{String_B} are interpreted as containing
+ASCII character codes.
+If either value contains a character not in the ASCII
+character set, the result is processor dependent.
+
+If the @var{String_A} and @var{String_B} are not the same length,
+the shorter is compared as if spaces were appended to
+it to form a value that has the same length as the longer.
+
+@xref{LGe Intrinsic}, for information on the distinction
+between the @code{LLT} intrinsic and the @code{.LT.}
+operator.
+
+@end ifset
+@ifset familyF2U
+@node LnBlnk Intrinsic
+@subsubsection LnBlnk Intrinsic
+@cindex LnBlnk intrinsic
+@cindex intrinsics, LnBlnk
+
+@noindent
+@example
+LnBlnk(@var{String})
+@end example
+
+@noindent
+LnBlnk: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{String}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the index of the last non-blank character in @var{String}.
+@code{LNBLNK} and @code{LEN_TRIM} are equivalent.
+
+@node Loc Intrinsic
+@subsubsection Loc Intrinsic
+@cindex Loc intrinsic
+@cindex intrinsics, Loc
+
+@noindent
+@example
+Loc(@var{Entity})
+@end example
+
+@noindent
+Loc: @code{INTEGER(KIND=7)} function.
+
+@noindent
+@var{Entity}: Any type; cannot be a constant or expression.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+The @code{LOC()} intrinsic works the
+same way as the @code{%LOC()} construct.
+@xref{%LOC(),,The @code{%LOC()} Construct}, for
+more information.
+
+@end ifset
+@ifset familyF77
+@node Log Intrinsic
+@subsubsection Log Intrinsic
+@cindex Log intrinsic
+@cindex intrinsics, Log
+
+@noindent
+@example
+Log(@var{X})
+@end example
+
+@noindent
+Log: @code{REAL} or @code{COMPLEX} function, the exact type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL} or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the natural logarithm of @var{X}, which must
+be greater than zero or, if type @code{COMPLEX}, must not
+be zero.
+
+@xref{Exp Intrinsic}, for the inverse of this function.
+
+@xref{Log10 Intrinsic}, for the `common' (base-10) logarithm function.
+
+@node Log10 Intrinsic
+@subsubsection Log10 Intrinsic
+@cindex Log10 intrinsic
+@cindex intrinsics, Log10
+
+@noindent
+@example
+Log10(@var{X})
+@end example
+
+@noindent
+Log10: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the common logarithm (base 10) of @var{X}, which must
+be greater than zero.
+
+The inverse of this function is @samp{10. ** LOG10(@var{X})}.
+
+@xref{Log Intrinsic}, for the natural logarithm function.
+
+@end ifset
+@ifset familyF90
+@node Logical Intrinsic
+@subsubsection Logical Intrinsic
+@cindex Logical intrinsic
+@cindex intrinsics, Logical
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Logical} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node Long Intrinsic
+@subsubsection Long Intrinsic
+@cindex Long intrinsic
+@cindex intrinsics, Long
+
+@noindent
+@example
+Long(@var{A})
+@end example
+
+@noindent
+Long: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{INTEGER(KIND=6)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Archaic form of @code{INT()} that is specific
+to one type for @var{A}.
+@xref{Int Intrinsic}.
+
+The precise meaning of this intrinsic might change
+in a future version of the GNU Fortran language,
+as more is learned about how it is used.
+
+@end ifset
+@ifset familyF2C
+@node LShift Intrinsic
+@subsubsection LShift Intrinsic
+@cindex LShift intrinsic
+@cindex intrinsics, LShift
+
+@noindent
+@example
+LShift(@var{I}, @var{Shift})
+@end example
+
+@noindent
+LShift: @code{INTEGER} function, the @samp{KIND=} value of the type being that of argument @var{I}.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Shift}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Returns @var{I} shifted to the left
+@var{Shift} bits.
+
+Although similar to the expression
+@samp{@var{I}*(2**@var{Shift})}, there
+are important differences.
+For example, the sign of the result is
+not necessarily the same as the sign of
+@var{I}.
+
+Currently this intrinsic is defined assuming
+the underlying representation of @var{I}
+is as a two's-complement integer.
+It is unclear at this point whether that
+definition will apply when a different
+representation is involved.
+
+@xref{LShift Intrinsic}, for the inverse of this function.
+
+@xref{IShft Intrinsic}, for information
+on a more widely available left-shifting
+intrinsic that is also more precisely defined.
+
+@end ifset
+@ifset familyF2U
+@node LStat Intrinsic (subroutine)
+@subsubsection LStat Intrinsic (subroutine)
+@cindex LStat intrinsic
+@cindex intrinsics, LStat
+
+@noindent
+@example
+CALL LStat(@var{File}, @var{SArray}, @var{Status})
+@end example
+
+@noindent
+@var{File}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{SArray}: @code{INTEGER(KIND=1)}; DIMENSION(13); INTENT(OUT).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Obtains data about the given file @var{File} and places them in the array
+@var{SArray}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{File}---otherwise,
+trailing blanks in @var{File} are ignored.
+If @var{File} is a symbolic link it returns data on the
+link itself, so the routine is available only on systems that support
+symbolic links.
+The values in this array are extracted from the
+@code{stat} structure as returned by @code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+If the @var{Status} argument is supplied, it contains
+0 on success or a non-zero error code upon return
+(@code{ENOSYS} if the system does not provide @code{lstat(2)}).
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{LStat Intrinsic (function)}.
+
+@node LStat Intrinsic (function)
+@subsubsection LStat Intrinsic (function)
+@cindex LStat intrinsic
+@cindex intrinsics, LStat
+
+@noindent
+@example
+LStat(@var{File}, @var{SArray})
+@end example
+
+@noindent
+LStat: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{File}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{SArray}: @code{INTEGER(KIND=1)}; DIMENSION(13); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Obtains data about the given file @var{File} and places them in the array
+@var{SArray}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{File}---otherwise,
+trailing blanks in @var{File} are ignored.
+If @var{File} is a symbolic link it returns data on the
+link itself, so the routine is available only on systems that support
+symbolic links.
+The values in this array are extracted from the
+@code{stat} structure as returned by @code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+Returns 0 on success or a non-zero error code
+(@code{ENOSYS} if the system does not provide @code{lstat(2)}).
+
+For information on other intrinsics with the same name:
+@xref{LStat Intrinsic (subroutine)}.
+
+@node LTime Intrinsic
+@subsubsection LTime Intrinsic
+@cindex LTime intrinsic
+@cindex intrinsics, LTime
+
+@noindent
+@example
+CALL LTime(@var{STime}, @var{TArray})
+@end example
+
+@noindent
+@var{STime}: @code{INTEGER(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+@var{TArray}: @code{INTEGER(KIND=1)}; DIMENSION(9); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Given a system time value @var{STime}, fills @var{TArray} with values
+extracted from it appropriate to the GMT time zone using
+@code{localtime(3)}.
+
+The array elements are as follows:
+
+@enumerate
+@item
+Seconds after the minute, range 0--59 or 0--61 to allow for leap
+seconds
+
+@item
+Minutes after the hour, range 0--59
+
+@item
+Hours past midnight, range 0--23
+
+@item
+Day of month, range 0--31
+
+@item
+Number of months since January, range 0--12
+
+@item
+Years since 1900
+
+@item
+Number of days since Sunday, range 0--6
+
+@item
+Days since January 1
+
+@item
+Daylight savings indicator: positive if daylight savings is in effect,
+zero if not, and negative if the information isn't available.
+@end enumerate
+
+@end ifset
+@ifset familyF90
+@node MatMul Intrinsic
+@subsubsection MatMul Intrinsic
+@cindex MatMul intrinsic
+@cindex intrinsics, MatMul
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL MatMul} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node Max Intrinsic
+@subsubsection Max Intrinsic
+@cindex Max intrinsic
+@cindex intrinsics, Max
+
+@noindent
+@example
+Max(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+Max: @code{INTEGER} or @code{REAL} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{A}: @code{INTEGER} or @code{REAL}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the argument with the largest value.
+
+@xref{Min Intrinsic}, for the opposite function.
+
+@node Max0 Intrinsic
+@subsubsection Max0 Intrinsic
+@cindex Max0 intrinsic
+@cindex intrinsics, Max0
+
+@noindent
+@example
+Max0(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+Max0: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{INTEGER(KIND=1)}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MAX()} that is specific
+to one type for @var{A}.
+@xref{Max Intrinsic}.
+
+@node Max1 Intrinsic
+@subsubsection Max1 Intrinsic
+@cindex Max1 intrinsic
+@cindex intrinsics, Max1
+
+@noindent
+@example
+Max1(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+Max1: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=1)}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MAX()} that is specific
+to one type for @var{A} and a different return type.
+@xref{Max Intrinsic}.
+
+@end ifset
+@ifset familyF90
+@node MaxExponent Intrinsic
+@subsubsection MaxExponent Intrinsic
+@cindex MaxExponent intrinsic
+@cindex intrinsics, MaxExponent
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL MaxExponent} to use this name for an
+external procedure.
+
+@node MaxLoc Intrinsic
+@subsubsection MaxLoc Intrinsic
+@cindex MaxLoc intrinsic
+@cindex intrinsics, MaxLoc
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL MaxLoc} to use this name for an
+external procedure.
+
+@node MaxVal Intrinsic
+@subsubsection MaxVal Intrinsic
+@cindex MaxVal intrinsic
+@cindex intrinsics, MaxVal
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL MaxVal} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node MClock Intrinsic
+@subsubsection MClock Intrinsic
+@cindex MClock intrinsic
+@cindex intrinsics, MClock
+
+@noindent
+@example
+MClock()
+@end example
+
+@noindent
+MClock: @code{INTEGER(KIND=1)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the number of clock ticks since the start of the process.
+Supported on systems with @code{clock(3)} (q.v.).
+
+This intrinsic is not fully portable, such as to systems
+with 32-bit @code{INTEGER} types but supporting times
+wider than 32 bits.
+@xref{MClock8 Intrinsic}, for information on a
+similar intrinsic that might be portable to more
+GNU Fortran implementations, though to fewer
+Fortran compilers.
+
+If the system does not support @code{clock(3)},
+-1 is returned.
+
+@node MClock8 Intrinsic
+@subsubsection MClock8 Intrinsic
+@cindex MClock8 intrinsic
+@cindex intrinsics, MClock8
+
+@noindent
+@example
+MClock8()
+@end example
+
+@noindent
+MClock8: @code{INTEGER(KIND=2)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the number of clock ticks since the start of the process.
+Supported on systems with @code{clock(3)} (q.v.).
+
+@emph{Warning:} this intrinsic does not increase the range
+of the timing values over that returned by @code{clock(3)}.
+On a system with a 32-bit @code{clock(3)},
+@code{MCLOCK8} will return a 32-bit value,
+even though converted to an @samp{INTEGER(KIND=2)} value.
+That means overflows of the 32-bit value can still occur.
+
+No Fortran implementations other than GNU Fortran are
+known to support this intrinsic at the time of this
+writing.
+@xref{MClock Intrinsic}, for information on a
+similar intrinsic that might be portable to more Fortran
+compilers, though to fewer GNU Fortran implementations.
+
+If the system does not support @code{clock(3)},
+-1 is returned.
+
+@end ifset
+@ifset familyF90
+@node Merge Intrinsic
+@subsubsection Merge Intrinsic
+@cindex Merge intrinsic
+@cindex intrinsics, Merge
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Merge} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node Min Intrinsic
+@subsubsection Min Intrinsic
+@cindex Min intrinsic
+@cindex intrinsics, Min
+
+@noindent
+@example
+Min(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+Min: @code{INTEGER} or @code{REAL} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{A}: @code{INTEGER} or @code{REAL}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the argument with the smallest value.
+
+@xref{Max Intrinsic}, for the opposite function.
+
+@node Min0 Intrinsic
+@subsubsection Min0 Intrinsic
+@cindex Min0 intrinsic
+@cindex intrinsics, Min0
+
+@noindent
+@example
+Min0(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+Min0: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{INTEGER(KIND=1)}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MIN()} that is specific
+to one type for @var{A}.
+@xref{Min Intrinsic}.
+
+@node Min1 Intrinsic
+@subsubsection Min1 Intrinsic
+@cindex Min1 intrinsic
+@cindex intrinsics, Min1
+
+@noindent
+@example
+Min1(@var{A}-1, @var{A}-2, @dots{}, @var{A}-n)
+@end example
+
+@noindent
+Min1: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=1)}; at least two such arguments must be provided; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{MIN()} that is specific
+to one type for @var{A} and a different return type.
+@xref{Min Intrinsic}.
+
+@end ifset
+@ifset familyF90
+@node MinExponent Intrinsic
+@subsubsection MinExponent Intrinsic
+@cindex MinExponent intrinsic
+@cindex intrinsics, MinExponent
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL MinExponent} to use this name for an
+external procedure.
+
+@node MinLoc Intrinsic
+@subsubsection MinLoc Intrinsic
+@cindex MinLoc intrinsic
+@cindex intrinsics, MinLoc
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL MinLoc} to use this name for an
+external procedure.
+
+@node MinVal Intrinsic
+@subsubsection MinVal Intrinsic
+@cindex MinVal intrinsic
+@cindex intrinsics, MinVal
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL MinVal} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node Mod Intrinsic
+@subsubsection Mod Intrinsic
+@cindex Mod intrinsic
+@cindex intrinsics, Mod
+
+@noindent
+@example
+Mod(@var{A}, @var{P})
+@end example
+
+@noindent
+Mod: @code{INTEGER} or @code{REAL} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{A}: @code{INTEGER} or @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+@var{P}: @code{INTEGER} or @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns remainder calculated as:
+
+@smallexample
+@var{A} - (INT(@var{A} / @var{P}) * @var{P})
+@end smallexample
+
+@var{P} must not be zero.
+
+@end ifset
+@ifset familyF90
+@node Modulo Intrinsic
+@subsubsection Modulo Intrinsic
+@cindex Modulo intrinsic
+@cindex intrinsics, Modulo
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Modulo} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyMIL
+@node MvBits Intrinsic
+@subsubsection MvBits Intrinsic
+@cindex MvBits intrinsic
+@cindex intrinsics, MvBits
+
+@noindent
+@example
+CALL MvBits(@var{From}, @var{FromPos}, @var{Len}, @var{TO}, @var{ToPos})
+@end example
+
+@noindent
+@var{From}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{FromPos}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Len}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{TO}: @code{INTEGER} with same @samp{KIND=} value as for @var{From}; scalar; INTENT(INOUT).
+
+@noindent
+@var{ToPos}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+Moves @var{Len} bits from positions @var{FromPos} through
+@samp{@var{FromPos}+@var{Len}-1} of @var{From} to positions @var{ToPos} through
+@samp{@var{FromPos}+@var{Len}-1} of @var{TO}. The portion of argument
+@var{TO} not affected by the movement of bits is unchanged. Arguments
+@var{From} and @var{TO} are permitted to be the same numeric storage
+unit. The values of @samp{@var{FromPos}+@var{Len}} and
+@samp{@var{ToPos}+@var{Len}} must be less than or equal to
+@samp{BIT_SIZE(@var{From})}.
+
+@end ifset
+@ifset familyF90
+@node Nearest Intrinsic
+@subsubsection Nearest Intrinsic
+@cindex Nearest intrinsic
+@cindex intrinsics, Nearest
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Nearest} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node NInt Intrinsic
+@subsubsection NInt Intrinsic
+@cindex NInt intrinsic
+@cindex intrinsics, NInt
+
+@noindent
+@example
+NInt(@var{A})
+@end example
+
+@noindent
+NInt: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{A}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @var{A} with the fractional portion of its
+magnitude eliminated by rounding to the nearest whole
+number and with its sign preserved, converted
+to type @code{INTEGER(KIND=1)}.
+
+If @var{A} is type @code{COMPLEX}, its real part is
+rounded and converted.
+
+A fractional portion exactly equal to
+@samp{.5} is rounded to the whole number that
+is larger in magnitude.
+(Also called ``Fortran round''.)
+
+@xref{Int Intrinsic}, for how to convert, truncate to
+whole number.
+
+@xref{ANInt Intrinsic}, for how to round to nearest whole number
+without converting.
+
+@end ifset
+@ifset familyMIL
+@node Not Intrinsic
+@subsubsection Not Intrinsic
+@cindex Not intrinsic
+@cindex intrinsics, Not
+
+@noindent
+@example
+Not(@var{I})
+@end example
+
+@noindent
+Not: @code{INTEGER} function, the @samp{KIND=} value of the type being that of argument @var{I}.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{mil}, @code{f90}, @code{vxt}.
+
+@noindent
+Description:
+
+Returns value resulting from boolean NOT of each bit
+in @var{I}.
+
+@end ifset
+@ifset familyF2C
+@node Or Intrinsic
+@subsubsection Or Intrinsic
+@cindex Or intrinsic
+@cindex intrinsics, Or
+
+@noindent
+@example
+Or(@var{I}, @var{J})
+@end example
+
+@noindent
+Or: @code{INTEGER} or @code{LOGICAL} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{I}: @code{INTEGER} or @code{LOGICAL}; scalar; INTENT(IN).
+
+@noindent
+@var{J}: @code{INTEGER} or @code{LOGICAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Returns value resulting from boolean OR of
+pair of bits in each of @var{I} and @var{J}.
+
+@end ifset
+@ifset familyF90
+@node Pack Intrinsic
+@subsubsection Pack Intrinsic
+@cindex Pack intrinsic
+@cindex intrinsics, Pack
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Pack} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node PError Intrinsic
+@subsubsection PError Intrinsic
+@cindex PError intrinsic
+@cindex intrinsics, PError
+
+@noindent
+@example
+CALL PError(@var{String})
+@end example
+
+@noindent
+@var{String}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Prints (on the C @code{stderr} stream) a newline-terminated error
+message corresponding to the last system error.
+This is prefixed by @var{String}, a colon and a space.
+See @code{perror(3)}.
+
+@end ifset
+@ifset familyF90
+@node Precision Intrinsic
+@subsubsection Precision Intrinsic
+@cindex Precision intrinsic
+@cindex intrinsics, Precision
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Precision} to use this name for an
+external procedure.
+
+@node Present Intrinsic
+@subsubsection Present Intrinsic
+@cindex Present intrinsic
+@cindex intrinsics, Present
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Present} to use this name for an
+external procedure.
+
+@node Product Intrinsic
+@subsubsection Product Intrinsic
+@cindex Product intrinsic
+@cindex intrinsics, Product
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Product} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyVXT
+@node QAbs Intrinsic
+@subsubsection QAbs Intrinsic
+@cindex QAbs intrinsic
+@cindex intrinsics, QAbs
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QAbs} to use this name for an
+external procedure.
+
+@node QACos Intrinsic
+@subsubsection QACos Intrinsic
+@cindex QACos intrinsic
+@cindex intrinsics, QACos
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QACos} to use this name for an
+external procedure.
+
+@node QACosD Intrinsic
+@subsubsection QACosD Intrinsic
+@cindex QACosD intrinsic
+@cindex intrinsics, QACosD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QACosD} to use this name for an
+external procedure.
+
+@node QASin Intrinsic
+@subsubsection QASin Intrinsic
+@cindex QASin intrinsic
+@cindex intrinsics, QASin
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QASin} to use this name for an
+external procedure.
+
+@node QASinD Intrinsic
+@subsubsection QASinD Intrinsic
+@cindex QASinD intrinsic
+@cindex intrinsics, QASinD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QASinD} to use this name for an
+external procedure.
+
+@node QATan Intrinsic
+@subsubsection QATan Intrinsic
+@cindex QATan intrinsic
+@cindex intrinsics, QATan
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QATan} to use this name for an
+external procedure.
+
+@node QATan2 Intrinsic
+@subsubsection QATan2 Intrinsic
+@cindex QATan2 intrinsic
+@cindex intrinsics, QATan2
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QATan2} to use this name for an
+external procedure.
+
+@node QATan2D Intrinsic
+@subsubsection QATan2D Intrinsic
+@cindex QATan2D intrinsic
+@cindex intrinsics, QATan2D
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QATan2D} to use this name for an
+external procedure.
+
+@node QATanD Intrinsic
+@subsubsection QATanD Intrinsic
+@cindex QATanD intrinsic
+@cindex intrinsics, QATanD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QATanD} to use this name for an
+external procedure.
+
+@node QCos Intrinsic
+@subsubsection QCos Intrinsic
+@cindex QCos intrinsic
+@cindex intrinsics, QCos
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QCos} to use this name for an
+external procedure.
+
+@node QCosD Intrinsic
+@subsubsection QCosD Intrinsic
+@cindex QCosD intrinsic
+@cindex intrinsics, QCosD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QCosD} to use this name for an
+external procedure.
+
+@node QCosH Intrinsic
+@subsubsection QCosH Intrinsic
+@cindex QCosH intrinsic
+@cindex intrinsics, QCosH
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QCosH} to use this name for an
+external procedure.
+
+@node QDiM Intrinsic
+@subsubsection QDiM Intrinsic
+@cindex QDiM intrinsic
+@cindex intrinsics, QDiM
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QDiM} to use this name for an
+external procedure.
+
+@node QExp Intrinsic
+@subsubsection QExp Intrinsic
+@cindex QExp intrinsic
+@cindex intrinsics, QExp
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QExp} to use this name for an
+external procedure.
+
+@node QExt Intrinsic
+@subsubsection QExt Intrinsic
+@cindex QExt intrinsic
+@cindex intrinsics, QExt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QExt} to use this name for an
+external procedure.
+
+@node QExtD Intrinsic
+@subsubsection QExtD Intrinsic
+@cindex QExtD intrinsic
+@cindex intrinsics, QExtD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QExtD} to use this name for an
+external procedure.
+
+@node QFloat Intrinsic
+@subsubsection QFloat Intrinsic
+@cindex QFloat intrinsic
+@cindex intrinsics, QFloat
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QFloat} to use this name for an
+external procedure.
+
+@node QInt Intrinsic
+@subsubsection QInt Intrinsic
+@cindex QInt intrinsic
+@cindex intrinsics, QInt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QInt} to use this name for an
+external procedure.
+
+@node QLog Intrinsic
+@subsubsection QLog Intrinsic
+@cindex QLog intrinsic
+@cindex intrinsics, QLog
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QLog} to use this name for an
+external procedure.
+
+@node QLog10 Intrinsic
+@subsubsection QLog10 Intrinsic
+@cindex QLog10 intrinsic
+@cindex intrinsics, QLog10
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QLog10} to use this name for an
+external procedure.
+
+@node QMax1 Intrinsic
+@subsubsection QMax1 Intrinsic
+@cindex QMax1 intrinsic
+@cindex intrinsics, QMax1
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QMax1} to use this name for an
+external procedure.
+
+@node QMin1 Intrinsic
+@subsubsection QMin1 Intrinsic
+@cindex QMin1 intrinsic
+@cindex intrinsics, QMin1
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QMin1} to use this name for an
+external procedure.
+
+@node QMod Intrinsic
+@subsubsection QMod Intrinsic
+@cindex QMod intrinsic
+@cindex intrinsics, QMod
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QMod} to use this name for an
+external procedure.
+
+@node QNInt Intrinsic
+@subsubsection QNInt Intrinsic
+@cindex QNInt intrinsic
+@cindex intrinsics, QNInt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QNInt} to use this name for an
+external procedure.
+
+@node QSin Intrinsic
+@subsubsection QSin Intrinsic
+@cindex QSin intrinsic
+@cindex intrinsics, QSin
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QSin} to use this name for an
+external procedure.
+
+@node QSinD Intrinsic
+@subsubsection QSinD Intrinsic
+@cindex QSinD intrinsic
+@cindex intrinsics, QSinD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QSinD} to use this name for an
+external procedure.
+
+@node QSinH Intrinsic
+@subsubsection QSinH Intrinsic
+@cindex QSinH intrinsic
+@cindex intrinsics, QSinH
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QSinH} to use this name for an
+external procedure.
+
+@node QSqRt Intrinsic
+@subsubsection QSqRt Intrinsic
+@cindex QSqRt intrinsic
+@cindex intrinsics, QSqRt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QSqRt} to use this name for an
+external procedure.
+
+@node QTan Intrinsic
+@subsubsection QTan Intrinsic
+@cindex QTan intrinsic
+@cindex intrinsics, QTan
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QTan} to use this name for an
+external procedure.
+
+@node QTanD Intrinsic
+@subsubsection QTanD Intrinsic
+@cindex QTanD intrinsic
+@cindex intrinsics, QTanD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QTanD} to use this name for an
+external procedure.
+
+@node QTanH Intrinsic
+@subsubsection QTanH Intrinsic
+@cindex QTanH intrinsic
+@cindex intrinsics, QTanH
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL QTanH} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF90
+@node Radix Intrinsic
+@subsubsection Radix Intrinsic
+@cindex Radix intrinsic
+@cindex intrinsics, Radix
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Radix} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node Rand Intrinsic
+@subsubsection Rand Intrinsic
+@cindex Rand intrinsic
+@cindex intrinsics, Rand
+
+@noindent
+@example
+Rand(@var{Flag})
+@end example
+
+@noindent
+Rand: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{Flag}: @code{INTEGER}; OPTIONAL; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns a uniform quasi-random number between 0 and 1.
+If @var{Flag} is 0, the next number in sequence is returned; if
+@var{Flag} is 1, the generator is restarted by calling @samp{srand(0)};
+if @var{Flag} has any other value, it is used as a new seed with
+@code{srand}.
+
+@xref{SRand Intrinsic}.
+
+@emph{Note:} As typically implemented (by the routine of the same
+name in the C library), this random number generator is a very poor
+one, though the BSD and GNU libraries provide a much better
+implementation than the `traditional' one.
+On a different system you
+almost certainly want to use something better.
+
+@end ifset
+@ifset familyF90
+@node Random_Number Intrinsic
+@subsubsection Random_Number Intrinsic
+@cindex Random_Number intrinsic
+@cindex intrinsics, Random_Number
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Random_Number} to use this name for an
+external procedure.
+
+@node Random_Seed Intrinsic
+@subsubsection Random_Seed Intrinsic
+@cindex Random_Seed intrinsic
+@cindex intrinsics, Random_Seed
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Random_Seed} to use this name for an
+external procedure.
+
+@node Range Intrinsic
+@subsubsection Range Intrinsic
+@cindex Range intrinsic
+@cindex intrinsics, Range
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Range} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node Real Intrinsic
+@subsubsection Real Intrinsic
+@cindex Real intrinsic
+@cindex intrinsics, Real
+
+@noindent
+@example
+Real(@var{A})
+@end example
+
+@noindent
+Real: @code{REAL} function.
+The exact type is @samp{REAL(KIND=1)} when argument @var{A} is
+any type other than @code{COMPLEX}, or when it is @code{COMPLEX(KIND=1)}.
+When @var{A} is any @code{COMPLEX} type other than @code{COMPLEX(KIND=1)},
+this intrinsic is valid only when used as the argument to
+@code{REAL()}, as explained below.
+
+@noindent
+@var{A}: @code{INTEGER}, @code{REAL}, or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Converts @var{A} to @code{REAL(KIND=1)}.
+
+Use of @code{REAL()} with a @code{COMPLEX} argument
+(other than @code{COMPLEX(KIND=1)}) is restricted to the following case:
+
+@example
+REAL(REAL(A))
+@end example
+
+@noindent
+This expression converts the real part of A to
+@code{REAL(KIND=1)}.
+
+@xref{RealPart Intrinsic}, for information on a GNU Fortran
+intrinsic that extracts the real part of an arbitrary
+@code{COMPLEX} value.
+
+@xref{REAL() and AIMAG() of Complex}, for more information.
+
+@end ifset
+@ifset familyGNU
+@node RealPart Intrinsic
+@subsubsection RealPart Intrinsic
+@cindex RealPart intrinsic
+@cindex intrinsics, RealPart
+
+@noindent
+@example
+RealPart(@var{Z})
+@end example
+
+@noindent
+RealPart: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{Z}.
+
+@noindent
+@var{Z}: @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{gnu}.
+
+@noindent
+Description:
+
+The real part of @var{Z} is returned, without conversion.
+
+@emph{Note:} The way to do this in standard Fortran 90
+is @samp{REAL(@var{Z})}.
+However, when, for example, @var{Z} is @code{COMPLEX(KIND=2)},
+@samp{REAL(@var{Z})} means something different for some compilers
+that are not true Fortran 90 compilers but offer some
+extensions standardized by Fortran 90 (such as the
+@code{DOUBLE COMPLEX} type, also known as @code{COMPLEX(KIND=2)}).
+
+The advantage of @code{REALPART()} is that, while not necessarily
+more or less portable than @code{REAL()}, it is more likely to
+cause a compiler that doesn't support it to produce a diagnostic
+than generate incorrect code.
+
+@xref{REAL() and AIMAG() of Complex}, for more information.
+
+@end ifset
+@ifset familyF2U
+@node Rename Intrinsic (subroutine)
+@subsubsection Rename Intrinsic (subroutine)
+@cindex Rename intrinsic
+@cindex intrinsics, Rename
+
+@noindent
+@example
+CALL Rename(@var{Path1}, @var{Path2}, @var{Status})
+@end example
+
+@noindent
+@var{Path1}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Path2}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Renames the file @var{Path1} to @var{Path2}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{Path1} and @var{Path2}---otherwise,
+trailing blanks in @var{Path1} and @var{Path2} are ignored.
+See @code{rename(2)}.
+If the @var{Status} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{Rename Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node Rename Intrinsic (function)
+@subsubsection Rename Intrinsic (function)
+@cindex Rename intrinsic
+@cindex intrinsics, Rename
+
+@noindent
+@example
+Rename(@var{Path1}, @var{Path2})
+@end example
+
+@noindent
+Rename: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Path1}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Path2}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Renames the file @var{Path1} to @var{Path2}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{Path1} and @var{Path2}---otherwise,
+trailing blanks in @var{Path1} and @var{Path2} are ignored.
+See @code{rename(2)}.
+Returns 0 on success or a non-zero error code.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+For information on other intrinsics with the same name:
+@xref{Rename Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF90
+@node Repeat Intrinsic
+@subsubsection Repeat Intrinsic
+@cindex Repeat intrinsic
+@cindex intrinsics, Repeat
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Repeat} to use this name for an
+external procedure.
+
+@node Reshape Intrinsic
+@subsubsection Reshape Intrinsic
+@cindex Reshape intrinsic
+@cindex intrinsics, Reshape
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Reshape} to use this name for an
+external procedure.
+
+@node RRSpacing Intrinsic
+@subsubsection RRSpacing Intrinsic
+@cindex RRSpacing intrinsic
+@cindex intrinsics, RRSpacing
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL RRSpacing} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2C
+@node RShift Intrinsic
+@subsubsection RShift Intrinsic
+@cindex RShift intrinsic
+@cindex intrinsics, RShift
+
+@noindent
+@example
+RShift(@var{I}, @var{Shift})
+@end example
+
+@noindent
+RShift: @code{INTEGER} function, the @samp{KIND=} value of the type being that of argument @var{I}.
+
+@noindent
+@var{I}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Shift}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Returns @var{I} shifted to the right
+@var{Shift} bits.
+
+Although similar to the expression
+@samp{@var{I}/(2**@var{Shift})}, there
+are important differences.
+For example, the sign of the result is
+undefined.
+
+Currently this intrinsic is defined assuming
+the underlying representation of @var{I}
+is as a two's-complement integer.
+It is unclear at this point whether that
+definition will apply when a different
+representation is involved.
+
+@xref{RShift Intrinsic}, for the inverse of this function.
+
+@xref{IShft Intrinsic}, for information
+on a more widely available right-shifting
+intrinsic that is also more precisely defined.
+
+@end ifset
+@ifset familyF90
+@node Scale Intrinsic
+@subsubsection Scale Intrinsic
+@cindex Scale intrinsic
+@cindex intrinsics, Scale
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Scale} to use this name for an
+external procedure.
+
+@node Scan Intrinsic
+@subsubsection Scan Intrinsic
+@cindex Scan intrinsic
+@cindex intrinsics, Scan
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Scan} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyVXT
+@node Secnds Intrinsic
+@subsubsection Secnds Intrinsic
+@cindex Secnds intrinsic
+@cindex intrinsics, Secnds
+
+@noindent
+@example
+Secnds(@var{T})
+@end example
+
+@noindent
+Secnds: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{T}: @code{REAL(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{vxt}.
+
+@noindent
+Description:
+
+Returns the local time in seconds since midnight minus the value
+@var{T}.
+
+@end ifset
+@ifset familyF2U
+@node Second Intrinsic (function)
+@subsubsection Second Intrinsic (function)
+@cindex Second intrinsic
+@cindex intrinsics, Second
+
+@noindent
+@example
+Second()
+@end example
+
+@noindent
+Second: @code{REAL(KIND=1)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the process's runtime in seconds---the same value as the
+UNIX function @code{etime} returns.
+
+For information on other intrinsics with the same name:
+@xref{Second Intrinsic (subroutine)}.
+
+@node Second Intrinsic (subroutine)
+@subsubsection Second Intrinsic (subroutine)
+@cindex Second intrinsic
+@cindex intrinsics, Second
+
+@noindent
+@example
+CALL Second(@var{Seconds})
+@end example
+
+@noindent
+@var{Seconds}: @code{REAL}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the process's runtime in seconds in @var{Seconds}---the same value
+as the UNIX function @code{etime} returns.
+
+This routine is known from Cray Fortran. @xref{CPU_Time Intrinsic},
+for a standard equivalent.
+
+For information on other intrinsics with the same name:
+@xref{Second Intrinsic (function)}.
+
+@end ifset
+@ifset familyF90
+@node Selected_Int_Kind Intrinsic
+@subsubsection Selected_Int_Kind Intrinsic
+@cindex Selected_Int_Kind intrinsic
+@cindex intrinsics, Selected_Int_Kind
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Selected_Int_Kind} to use this name for an
+external procedure.
+
+@node Selected_Real_Kind Intrinsic
+@subsubsection Selected_Real_Kind Intrinsic
+@cindex Selected_Real_Kind intrinsic
+@cindex intrinsics, Selected_Real_Kind
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Selected_Real_Kind} to use this name for an
+external procedure.
+
+@node Set_Exponent Intrinsic
+@subsubsection Set_Exponent Intrinsic
+@cindex Set_Exponent intrinsic
+@cindex intrinsics, Set_Exponent
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Set_Exponent} to use this name for an
+external procedure.
+
+@node Shape Intrinsic
+@subsubsection Shape Intrinsic
+@cindex Shape intrinsic
+@cindex intrinsics, Shape
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Shape} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node Short Intrinsic
+@subsubsection Short Intrinsic
+@cindex Short intrinsic
+@cindex intrinsics, Short
+
+@noindent
+@example
+Short(@var{A})
+@end example
+
+@noindent
+Short: @code{INTEGER(KIND=6)} function.
+
+@noindent
+@var{A}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns @var{A} with the fractional portion of its
+magnitude truncated and its sign preserved, converted
+to type @code{INTEGER(KIND=6)}.
+
+If @var{A} is type @code{COMPLEX}, its real part
+is truncated and converted, and its imaginary part is disgregarded.
+
+@xref{Int Intrinsic}.
+
+The precise meaning of this intrinsic might change
+in a future version of the GNU Fortran language,
+as more is learned about how it is used.
+
+@end ifset
+@ifset familyF77
+@node Sign Intrinsic
+@subsubsection Sign Intrinsic
+@cindex Sign intrinsic
+@cindex intrinsics, Sign
+
+@noindent
+@example
+Sign(@var{A}, @var{B})
+@end example
+
+@noindent
+Sign: @code{INTEGER} or @code{REAL} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{A}: @code{INTEGER} or @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+@var{B}: @code{INTEGER} or @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns @samp{ABS(@var{A})*@var{s}}, where
+@var{s} is +1 if @samp{@var{B}.GE.0},
+-1 otherwise.
+
+@xref{Abs Intrinsic}, for the function that returns
+the magnitude of a value.
+
+@end ifset
+@ifset familyF2U
+@node Signal Intrinsic (subroutine)
+@subsubsection Signal Intrinsic (subroutine)
+@cindex Signal intrinsic
+@cindex intrinsics, Signal
+
+@noindent
+@example
+CALL Signal(@var{Number}, @var{Handler}, @var{Status})
+@end example
+
+@noindent
+@var{Number}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Handler}: Signal handler (@code{INTEGER FUNCTION} or @code{SUBROUTINE})
+or dummy/global @code{INTEGER(KIND=1)} scalar.
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=7)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+If @var{Handler} is a an @code{EXTERNAL} routine, arranges for it to be
+invoked with a single integer argument (of system-dependent length)
+when signal @var{Number} occurs.
+If @var{Handler} is an integer, it can be
+used to turn off handling of signal @var{Number} or revert to its default
+action.
+See @code{signal(2)}.
+
+Note that @var{Handler} will be called using C conventions,
+so the value of its argument in Fortran terms
+Fortran terms is obtained by applying @code{%LOC()} (or @var{LOC()}) to it.
+
+The value returned by @code{signal(2)} is written to @var{Status}, if
+that argument is supplied.
+Otherwise the return value is ignored.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+@emph{Warning:} Use of the @code{libf2c} run-time library function
+@samp{signal_} directly
+(such as via @samp{EXTERNAL SIGNAL})
+requires use of the @code{%VAL()} construct
+to pass an @code{INTEGER} value
+(such as @samp{SIG_IGN} or @samp{SIG_DFL})
+for the @var{Handler} argument.
+
+However, while @samp{CALL SIGNAL(@var{signum}, %VAL(SIG_IGN))}
+works when @samp{SIGNAL} is treated as an external procedure
+(and resolves, at link time, to @code{libf2c}'s @samp{signal_} routine),
+this construct is not valid when @samp{SIGNAL} is recognized
+as the intrinsic of that name.
+
+Therefore, for maximum portability and reliability,
+code such references to the @samp{SIGNAL} facility as follows:
+
+@smallexample
+INTRINSIC SIGNAL
+@dots{}
+CALL SIGNAL(@var{signum}, SIG_IGN)
+@end smallexample
+
+@code{g77} will compile such a call correctly,
+while other compilers will generally either do so as well
+or reject the @samp{INTRINSIC SIGNAL} statement via a diagnostic,
+allowing you to take appropriate action.
+
+For information on other intrinsics with the same name:
+@xref{Signal Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node Signal Intrinsic (function)
+@subsubsection Signal Intrinsic (function)
+@cindex Signal intrinsic
+@cindex intrinsics, Signal
+
+@noindent
+@example
+Signal(@var{Number}, @var{Handler})
+@end example
+
+@noindent
+Signal: @code{INTEGER(KIND=7)} function.
+
+@noindent
+@var{Number}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Handler}: Signal handler (@code{INTEGER FUNCTION} or @code{SUBROUTINE})
+or dummy/global @code{INTEGER(KIND=1)} scalar.
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+If @var{Handler} is a an @code{EXTERNAL} routine, arranges for it to be
+invoked with a single integer argument (of system-dependent length)
+when signal @var{Number} occurs.
+If @var{Handler} is an integer, it can be
+used to turn off handling of signal @var{Number} or revert to its default
+action.
+See @code{signal(2)}.
+
+Note that @var{Handler} will be called using C conventions,
+so the value of its argument in Fortran terms
+is obtained by applying @code{%LOC()} (or @var{LOC()}) to it.
+
+The value returned by @code{signal(2)} is returned.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+@emph{Warning:} If the returned value is stored in
+an @code{INTEGER(KIND=1)} (default @code{INTEGER}) argument,
+truncation of the original return value occurs on some systems
+(such as Alphas, which have 64-bit pointers but 32-bit default integers),
+with no warning issued by @code{g77} under normal circumstances.
+
+Therefore, the following code fragment might silently fail on
+some systems:
+
+@smallexample
+INTEGER RTN
+EXTERNAL MYHNDL
+RTN = SIGNAL(@var{signum}, MYHNDL)
+@dots{}
+! Restore original handler:
+RTN = SIGNAL(@var{signum}, RTN)
+@end smallexample
+
+The reason for the failure is that @samp{RTN} might not hold
+all the information on the original handler for the signal,
+thus restoring an invalid handler.
+This bug could manifest itself as a spurious run-time failure
+at an arbitrary point later during the program's execution,
+for example.
+
+@emph{Warning:} Use of the @code{libf2c} run-time library function
+@samp{signal_} directly
+(such as via @samp{EXTERNAL SIGNAL})
+requires use of the @code{%VAL()} construct
+to pass an @code{INTEGER} value
+(such as @samp{SIG_IGN} or @samp{SIG_DFL})
+for the @var{Handler} argument.
+
+However, while @samp{RTN = SIGNAL(@var{signum}, %VAL(SIG_IGN))}
+works when @samp{SIGNAL} is treated as an external procedure
+(and resolves, at link time, to @code{libf2c}'s @samp{signal_} routine),
+this construct is not valid when @samp{SIGNAL} is recognized
+as the intrinsic of that name.
+
+Therefore, for maximum portability and reliability,
+code such references to the @samp{SIGNAL} facility as follows:
+
+@smallexample
+INTRINSIC SIGNAL
+@dots{}
+RTN = SIGNAL(@var{signum}, SIG_IGN)
+@end smallexample
+
+@code{g77} will compile such a call correctly,
+while other compilers will generally either do so as well
+or reject the @samp{INTRINSIC SIGNAL} statement via a diagnostic,
+allowing you to take appropriate action.
+
+For information on other intrinsics with the same name:
+@xref{Signal Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF77
+@node Sin Intrinsic
+@subsubsection Sin Intrinsic
+@cindex Sin intrinsic
+@cindex intrinsics, Sin
+
+@noindent
+@example
+Sin(@var{X})
+@end example
+
+@noindent
+Sin: @code{REAL} or @code{COMPLEX} function, the exact type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL} or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the sine of @var{X}, an angle measured
+in radians.
+
+@xref{ASin Intrinsic}, for the inverse of this function.
+
+@end ifset
+@ifset familyVXT
+@node SinD Intrinsic
+@subsubsection SinD Intrinsic
+@cindex SinD intrinsic
+@cindex intrinsics, SinD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL SinD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node SinH Intrinsic
+@subsubsection SinH Intrinsic
+@cindex SinH intrinsic
+@cindex intrinsics, SinH
+
+@noindent
+@example
+SinH(@var{X})
+@end example
+
+@noindent
+SinH: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the hyperbolic sine of @var{X}.
+
+@end ifset
+@ifset familyF2U
+@node Sleep Intrinsic
+@subsubsection Sleep Intrinsic
+@cindex Sleep intrinsic
+@cindex intrinsics, Sleep
+
+@noindent
+@example
+CALL Sleep(@var{Seconds})
+@end example
+
+@noindent
+@var{Seconds}: @code{INTEGER(KIND=1)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Causes the process to pause for @var{Seconds} seconds.
+See @code{sleep(2)}.
+
+@end ifset
+@ifset familyF77
+@node Sngl Intrinsic
+@subsubsection Sngl Intrinsic
+@cindex Sngl intrinsic
+@cindex intrinsics, Sngl
+
+@noindent
+@example
+Sngl(@var{A})
+@end example
+
+@noindent
+Sngl: @code{REAL(KIND=1)} function.
+
+@noindent
+@var{A}: @code{REAL(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Archaic form of @code{REAL()} that is specific
+to one type for @var{A}.
+@xref{Real Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node SnglQ Intrinsic
+@subsubsection SnglQ Intrinsic
+@cindex SnglQ intrinsic
+@cindex intrinsics, SnglQ
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL SnglQ} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF90
+@node Spacing Intrinsic
+@subsubsection Spacing Intrinsic
+@cindex Spacing intrinsic
+@cindex intrinsics, Spacing
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Spacing} to use this name for an
+external procedure.
+
+@node Spread Intrinsic
+@subsubsection Spread Intrinsic
+@cindex Spread intrinsic
+@cindex intrinsics, Spread
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Spread} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node SqRt Intrinsic
+@subsubsection SqRt Intrinsic
+@cindex SqRt intrinsic
+@cindex intrinsics, SqRt
+
+@noindent
+@example
+SqRt(@var{X})
+@end example
+
+@noindent
+SqRt: @code{REAL} or @code{COMPLEX} function, the exact type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL} or @code{COMPLEX}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the square root of @var{X}, which must
+not be negative.
+
+To calculate and represent the square root of a negative
+number, complex arithmetic must be used.
+For example, @samp{SQRT(COMPLEX(@var{X}))}.
+
+The inverse of this function is @samp{SQRT(@var{X}) * SQRT(@var{X})}.
+
+@end ifset
+@ifset familyF2U
+@node SRand Intrinsic
+@subsubsection SRand Intrinsic
+@cindex SRand intrinsic
+@cindex intrinsics, SRand
+
+@noindent
+@example
+CALL SRand(@var{Seed})
+@end example
+
+@noindent
+@var{Seed}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Reinitialises the generator with the seed in @var{Seed}.
+@xref{IRand Intrinsic}.
+@xref{Rand Intrinsic}.
+
+@node Stat Intrinsic (subroutine)
+@subsubsection Stat Intrinsic (subroutine)
+@cindex Stat intrinsic
+@cindex intrinsics, Stat
+
+@noindent
+@example
+CALL Stat(@var{File}, @var{SArray}, @var{Status})
+@end example
+
+@noindent
+@var{File}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{SArray}: @code{INTEGER(KIND=1)}; DIMENSION(13); INTENT(OUT).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Obtains data about the given file @var{File} and places them in the array
+@var{SArray}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{File}---otherwise,
+trailing blanks in @var{File} are ignored.
+The values in this array are extracted from the
+@code{stat} structure as returned by @code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+If the @var{Status} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{Stat Intrinsic (function)}.
+
+@node Stat Intrinsic (function)
+@subsubsection Stat Intrinsic (function)
+@cindex Stat intrinsic
+@cindex intrinsics, Stat
+
+@noindent
+@example
+Stat(@var{File}, @var{SArray})
+@end example
+
+@noindent
+Stat: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{File}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{SArray}: @code{INTEGER(KIND=1)}; DIMENSION(13); INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Obtains data about the given file @var{File} and places them in the array
+@var{SArray}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{File}---otherwise,
+trailing blanks in @var{File} are ignored.
+The values in this array are extracted from the
+@code{stat} structure as returned by @code{fstat(2)} q.v., as follows:
+
+@enumerate
+@item
+Device ID
+
+@item
+Inode number
+
+@item
+File mode
+
+@item
+Number of links
+
+@item
+Owner's uid
+
+@item
+Owner's gid
+
+@item
+ID of device containing directory entry for file
+(0 if not available)
+
+@item
+File size (bytes)
+
+@item
+Last access time
+
+@item
+Last modification time
+
+@item
+Last file status change time
+
+@item
+Preferred I/O block size (-1 if not available)
+
+@item
+Number of blocks allocated (-1 if not available)
+@end enumerate
+
+Not all these elements are relevant on all systems.
+If an element is not relevant, it is returned as 0.
+
+Returns 0 on success or a non-zero error code.
+
+For information on other intrinsics with the same name:
+@xref{Stat Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF90
+@node Sum Intrinsic
+@subsubsection Sum Intrinsic
+@cindex Sum intrinsic
+@cindex intrinsics, Sum
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Sum} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node SymLnk Intrinsic (subroutine)
+@subsubsection SymLnk Intrinsic (subroutine)
+@cindex SymLnk intrinsic
+@cindex intrinsics, SymLnk
+
+@noindent
+@example
+CALL SymLnk(@var{Path1}, @var{Path2}, @var{Status})
+@end example
+
+@noindent
+@var{Path1}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Path2}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Makes a symbolic link from file @var{Path1} to @var{Path2}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{Path1} and @var{Path2}---otherwise,
+trailing blanks in @var{Path1} and @var{Path2} are ignored.
+If the @var{Status} argument is supplied, it contains
+0 on success or a non-zero error code upon return
+(@code{ENOSYS} if the system does not provide @code{symlink(2)}).
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{SymLnk Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node SymLnk Intrinsic (function)
+@subsubsection SymLnk Intrinsic (function)
+@cindex SymLnk intrinsic
+@cindex intrinsics, SymLnk
+
+@noindent
+@example
+SymLnk(@var{Path1}, @var{Path2})
+@end example
+
+@noindent
+SymLnk: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Path1}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Path2}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Makes a symbolic link from file @var{Path1} to @var{Path2}.
+A null character (@samp{CHAR(0)}) marks the end of
+the names in @var{Path1} and @var{Path2}---otherwise,
+trailing blanks in @var{Path1} and @var{Path2} are ignored.
+Returns 0 on success or a non-zero error code
+(@code{ENOSYS} if the system does not provide @code{symlink(2)}).
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+For information on other intrinsics with the same name:
+@xref{SymLnk Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF2U
+@node System Intrinsic (subroutine)
+@subsubsection System Intrinsic (subroutine)
+@cindex System intrinsic
+@cindex intrinsics, System
+
+@noindent
+@example
+CALL System(@var{Command}, @var{Status})
+@end example
+
+@noindent
+@var{Command}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Passes the command @var{Command} to a shell (see @code{system(3)}).
+If argument @var{Status} is present, it contains the value returned by
+@code{system(3)}, presumably 0 if the shell command succeeded.
+Note that which shell is used to invoke the command is system-dependent
+and environment-dependent.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{System Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node System Intrinsic (function)
+@subsubsection System Intrinsic (function)
+@cindex System intrinsic
+@cindex intrinsics, System
+
+@noindent
+@example
+System(@var{Command})
+@end example
+
+@noindent
+System: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Command}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Passes the command @var{Command} to a shell (see @code{system(3)}).
+Returns the value returned by
+@code{system(3)}, presumably 0 if the shell command succeeded.
+Note that which shell is used to invoke the command is system-dependent
+and environment-dependent.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+However, the function form can be valid in cases where the
+actual side effects performed by the call are unimportant to
+the application.
+
+For example, on a UNIX system, @samp{SAME = SYSTEM('cmp a b')}
+does not perform any side effects likely to be important to the
+program, so the programmer would not care if the actual system
+call (and invocation of @code{cmp}) was optimized away in a situation
+where the return value could be determined otherwise, or was not
+actually needed (@samp{SAME} not actually referenced after the
+sample assignment statement).
+
+For information on other intrinsics with the same name:
+@xref{System Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF90
+@node System_Clock Intrinsic
+@subsubsection System_Clock Intrinsic
+@cindex System_Clock intrinsic
+@cindex intrinsics, System_Clock
+
+@noindent
+@example
+CALL System_Clock(@var{Count}, @var{Rate}, @var{Max})
+@end example
+
+@noindent
+@var{Count}: @code{INTEGER(KIND=1)}; scalar; INTENT(OUT).
+
+@noindent
+@var{Rate}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+@var{Max}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{f90}.
+
+@noindent
+Description:
+
+Returns in @var{Count} the current value of the system clock; this is
+the value returned by the UNIX function @code{times(2)}
+in this implementation, but
+isn't in general.
+@var{Rate} is the number of clock ticks per second and
+@var{Max} is the maximum value this can take, which isn't very useful
+in this implementation since it's just the maximum C @code{unsigned
+int} value.
+
+@end ifset
+@ifset familyF77
+@node Tan Intrinsic
+@subsubsection Tan Intrinsic
+@cindex Tan intrinsic
+@cindex intrinsics, Tan
+
+@noindent
+@example
+Tan(@var{X})
+@end example
+
+@noindent
+Tan: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the tangent of @var{X}, an angle measured
+in radians.
+
+@xref{ATan Intrinsic}, for the inverse of this function.
+
+@end ifset
+@ifset familyVXT
+@node TanD Intrinsic
+@subsubsection TanD Intrinsic
+@cindex TanD intrinsic
+@cindex intrinsics, TanD
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL TanD} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF77
+@node TanH Intrinsic
+@subsubsection TanH Intrinsic
+@cindex TanH intrinsic
+@cindex intrinsics, TanH
+
+@noindent
+@example
+TanH(@var{X})
+@end example
+
+@noindent
+TanH: @code{REAL} function, the @samp{KIND=} value of the type being that of argument @var{X}.
+
+@noindent
+@var{X}: @code{REAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: (standard FORTRAN 77).
+
+@noindent
+Description:
+
+Returns the hyperbolic tangent of @var{X}.
+
+@end ifset
+@ifset familyF2U
+@node Time Intrinsic (UNIX)
+@subsubsection Time Intrinsic (UNIX)
+@cindex Time intrinsic
+@cindex intrinsics, Time
+
+@noindent
+@example
+Time()
+@end example
+
+@noindent
+Time: @code{INTEGER(KIND=1)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the current time encoded as an integer
+(in the manner of the UNIX function @code{time(3)}).
+This value is suitable for passing to @code{CTIME},
+@code{GMTIME}, and @code{LTIME}.
+
+This intrinsic is not fully portable, such as to systems
+with 32-bit @code{INTEGER} types but supporting times
+wider than 32 bits.
+@xref{Time8 Intrinsic}, for information on a
+similar intrinsic that might be portable to more
+GNU Fortran implementations, though to fewer
+Fortran compilers.
+
+For information on other intrinsics with the same name:
+@xref{Time Intrinsic (VXT)}.
+
+@end ifset
+@ifset familyVXT
+@node Time Intrinsic (VXT)
+@subsubsection Time Intrinsic (VXT)
+@cindex Time intrinsic
+@cindex intrinsics, Time
+
+@noindent
+@example
+CALL Time(@var{Time})
+@end example
+
+@noindent
+@var{Time}: @code{CHARACTER*8}; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{vxt}.
+
+@noindent
+Description:
+
+Returns in @var{Time} a character representation of the current time as
+obtained from @code{ctime(3)}.
+
+@xref{Fdate Intrinsic (subroutine)}, for an equivalent routine.
+
+For information on other intrinsics with the same name:
+@xref{Time Intrinsic (UNIX)}.
+
+@end ifset
+@ifset familyF2U
+@node Time8 Intrinsic
+@subsubsection Time8 Intrinsic
+@cindex Time8 intrinsic
+@cindex intrinsics, Time8
+
+@noindent
+@example
+Time8()
+@end example
+
+@noindent
+Time8: @code{INTEGER(KIND=2)} function.
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the current time encoded as a long integer
+(in the manner of the UNIX function @code{time(3)}).
+This value is suitable for passing to @code{CTIME},
+@code{GMTIME}, and @code{LTIME}.
+
+@emph{Warning:} this intrinsic does not increase the range
+of the timing values over that returned by @code{time(3)}.
+On a system with a 32-bit @code{time(3)},
+@code{TIME8} will return a 32-bit value,
+even though converted to an @samp{INTEGER(KIND=2)} value.
+That means overflows of the 32-bit value can still occur.
+
+No Fortran implementations other than GNU Fortran are
+known to support this intrinsic at the time of this
+writing.
+@xref{Time Intrinsic (UNIX)}, for information on a
+similar intrinsic that might be portable to more Fortran
+compilers, though to fewer GNU Fortran implementations.
+
+@end ifset
+@ifset familyF90
+@node Tiny Intrinsic
+@subsubsection Tiny Intrinsic
+@cindex Tiny intrinsic
+@cindex intrinsics, Tiny
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Tiny} to use this name for an
+external procedure.
+
+@node Transfer Intrinsic
+@subsubsection Transfer Intrinsic
+@cindex Transfer intrinsic
+@cindex intrinsics, Transfer
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Transfer} to use this name for an
+external procedure.
+
+@node Transpose Intrinsic
+@subsubsection Transpose Intrinsic
+@cindex Transpose intrinsic
+@cindex intrinsics, Transpose
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Transpose} to use this name for an
+external procedure.
+
+@node Trim Intrinsic
+@subsubsection Trim Intrinsic
+@cindex Trim intrinsic
+@cindex intrinsics, Trim
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Trim} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node TtyNam Intrinsic (subroutine)
+@subsubsection TtyNam Intrinsic (subroutine)
+@cindex TtyNam intrinsic
+@cindex intrinsics, TtyNam
+
+@noindent
+@example
+CALL TtyNam(@var{Name}, @var{Unit})
+@end example
+
+@noindent
+@var{Name}: @code{CHARACTER}; scalar; INTENT(OUT).
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Sets @var{Name} to the name of the terminal device open on logical unit
+@var{Unit} or a blank string if @var{Unit} is not connected to a
+terminal.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+
+For information on other intrinsics with the same name:
+@xref{TtyNam Intrinsic (function)}.
+
+@node TtyNam Intrinsic (function)
+@subsubsection TtyNam Intrinsic (function)
+@cindex TtyNam intrinsic
+@cindex intrinsics, TtyNam
+
+@noindent
+@example
+TtyNam(@var{Unit})
+@end example
+
+@noindent
+TtyNam: @code{CHARACTER*(*)} function.
+
+@noindent
+@var{Unit}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Returns the name of the terminal device open on logical unit
+@var{Unit} or a blank string if @var{Unit} is not connected to a
+terminal.
+
+For information on other intrinsics with the same name:
+@xref{TtyNam Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF90
+@node UBound Intrinsic
+@subsubsection UBound Intrinsic
+@cindex UBound intrinsic
+@cindex intrinsics, UBound
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL UBound} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2U
+@node UMask Intrinsic (subroutine)
+@subsubsection UMask Intrinsic (subroutine)
+@cindex UMask intrinsic
+@cindex intrinsics, UMask
+
+@noindent
+@example
+CALL UMask(@var{Mask}, @var{Old})
+@end example
+
+@noindent
+@var{Mask}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+@var{Old}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Sets the file creation mask to @var{Mask} and returns the old value in
+argument @var{Old} if it is supplied.
+See @code{umask(2)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine.
+
+For information on other intrinsics with the same name:
+@xref{UMask Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node UMask Intrinsic (function)
+@subsubsection UMask Intrinsic (function)
+@cindex UMask intrinsic
+@cindex intrinsics, UMask
+
+@noindent
+@example
+UMask(@var{Mask})
+@end example
+
+@noindent
+UMask: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{Mask}: @code{INTEGER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Sets the file creation mask to @var{Mask} and returns the old value.
+See @code{umask(2)}.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+For information on other intrinsics with the same name:
+@xref{UMask Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF2U
+@node Unlink Intrinsic (subroutine)
+@subsubsection Unlink Intrinsic (subroutine)
+@cindex Unlink intrinsic
+@cindex intrinsics, Unlink
+
+@noindent
+@example
+CALL Unlink(@var{File}, @var{Status})
+@end example
+
+@noindent
+@var{File}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+@var{Status}: @code{INTEGER(KIND=1)}; OPTIONAL; scalar; INTENT(OUT).
+
+@noindent
+Intrinsic groups: @code{unix}.
+
+@noindent
+Description:
+
+Unlink the file @var{File}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{File}---otherwise,
+trailing blanks in @var{File} are ignored.
+If the @var{Status} argument is supplied, it contains
+0 on success or a non-zero error code upon return.
+See @code{unlink(2)}.
+
+Some non-GNU implementations of Fortran provide this intrinsic as
+only a function, not as a subroutine, or do not support the
+(optional) @var{Status} argument.
+
+For information on other intrinsics with the same name:
+@xref{Unlink Intrinsic (function)}.
+
+@end ifset
+@ifset familyBADU77
+@node Unlink Intrinsic (function)
+@subsubsection Unlink Intrinsic (function)
+@cindex Unlink intrinsic
+@cindex intrinsics, Unlink
+
+@noindent
+@example
+Unlink(@var{File})
+@end example
+
+@noindent
+Unlink: @code{INTEGER(KIND=1)} function.
+
+@noindent
+@var{File}: @code{CHARACTER}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{badu77}.
+
+@noindent
+Description:
+
+Unlink the file @var{File}.
+A null character (@samp{CHAR(0)}) marks the end of
+the name in @var{File}---otherwise,
+trailing blanks in @var{File} are ignored.
+Returns 0 on success or a non-zero error code.
+See @code{unlink(2)}.
+
+Due to the side effects performed by this intrinsic, the function
+form is not recommended.
+
+For information on other intrinsics with the same name:
+@xref{Unlink Intrinsic (subroutine)}.
+
+@end ifset
+@ifset familyF90
+@node Unpack Intrinsic
+@subsubsection Unpack Intrinsic
+@cindex Unpack intrinsic
+@cindex intrinsics, Unpack
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Unpack} to use this name for an
+external procedure.
+
+@node Verify Intrinsic
+@subsubsection Verify Intrinsic
+@cindex Verify intrinsic
+@cindex intrinsics, Verify
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL Verify} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2C
+@node XOr Intrinsic
+@subsubsection XOr Intrinsic
+@cindex XOr intrinsic
+@cindex intrinsics, XOr
+
+@noindent
+@example
+XOr(@var{I}, @var{J})
+@end example
+
+@noindent
+XOr: @code{INTEGER} or @code{LOGICAL} function, the exact type being the result of cross-promoting the
+types of all the arguments.
+
+@noindent
+@var{I}: @code{INTEGER} or @code{LOGICAL}; scalar; INTENT(IN).
+
+@noindent
+@var{J}: @code{INTEGER} or @code{LOGICAL}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Returns value resulting from boolean exclusive-OR of
+pair of bits in each of @var{I} and @var{J}.
+
+@node ZAbs Intrinsic
+@subsubsection ZAbs Intrinsic
+@cindex ZAbs intrinsic
+@cindex intrinsics, ZAbs
+
+@noindent
+@example
+ZAbs(@var{A})
+@end example
+
+@noindent
+ZAbs: @code{REAL(KIND=2)} function.
+
+@noindent
+@var{A}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Archaic form of @code{ABS()} that is specific
+to one type for @var{A}.
+@xref{Abs Intrinsic}.
+
+@node ZCos Intrinsic
+@subsubsection ZCos Intrinsic
+@cindex ZCos intrinsic
+@cindex intrinsics, ZCos
+
+@noindent
+@example
+ZCos(@var{X})
+@end example
+
+@noindent
+ZCos: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Archaic form of @code{COS()} that is specific
+to one type for @var{X}.
+@xref{Cos Intrinsic}.
+
+@node ZExp Intrinsic
+@subsubsection ZExp Intrinsic
+@cindex ZExp intrinsic
+@cindex intrinsics, ZExp
+
+@noindent
+@example
+ZExp(@var{X})
+@end example
+
+@noindent
+ZExp: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Archaic form of @code{EXP()} that is specific
+to one type for @var{X}.
+@xref{Exp Intrinsic}.
+
+@end ifset
+@ifset familyVXT
+@node ZExt Intrinsic
+@subsubsection ZExt Intrinsic
+@cindex ZExt intrinsic
+@cindex intrinsics, ZExt
+
+This intrinsic is not yet implemented.
+The name is, however, reserved as an intrinsic.
+Use @samp{EXTERNAL ZExt} to use this name for an
+external procedure.
+
+@end ifset
+@ifset familyF2C
+@node ZLog Intrinsic
+@subsubsection ZLog Intrinsic
+@cindex ZLog intrinsic
+@cindex intrinsics, ZLog
+
+@noindent
+@example
+ZLog(@var{X})
+@end example
+
+@noindent
+ZLog: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Archaic form of @code{LOG()} that is specific
+to one type for @var{X}.
+@xref{Log Intrinsic}.
+
+@node ZSin Intrinsic
+@subsubsection ZSin Intrinsic
+@cindex ZSin intrinsic
+@cindex intrinsics, ZSin
+
+@noindent
+@example
+ZSin(@var{X})
+@end example
+
+@noindent
+ZSin: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Archaic form of @code{SIN()} that is specific
+to one type for @var{X}.
+@xref{Sin Intrinsic}.
+
+@node ZSqRt Intrinsic
+@subsubsection ZSqRt Intrinsic
+@cindex ZSqRt intrinsic
+@cindex intrinsics, ZSqRt
+
+@noindent
+@example
+ZSqRt(@var{X})
+@end example
+
+@noindent
+ZSqRt: @code{COMPLEX(KIND=2)} function.
+
+@noindent
+@var{X}: @code{COMPLEX(KIND=2)}; scalar; INTENT(IN).
+
+@noindent
+Intrinsic groups: @code{f2c}.
+
+@noindent
+Description:
+
+Archaic form of @code{SQRT()} that is specific
+to one type for @var{X}.
+@xref{SqRt Intrinsic}.
+
+@end ifset
diff --git a/contrib/gcc/f/intrin.c b/contrib/gcc/f/intrin.c
new file mode 100644
index 0000000..6e27d21
--- /dev/null
+++ b/contrib/gcc/f/intrin.c
@@ -0,0 +1,2055 @@
+/* intrin.c -- Recognize references to intrinsics
+ Copyright (C) 1995-1998 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+*/
+
+#include "proj.h"
+#include "intrin.h"
+#include "expr.h"
+#include "info.h"
+#include "src.h"
+#include "symbol.h"
+#include "target.h"
+#include "top.h"
+
+struct _ffeintrin_name_
+ {
+ char *name_uc;
+ char *name_lc;
+ char *name_ic;
+ ffeintrinGen generic;
+ ffeintrinSpec specific;
+ };
+
+struct _ffeintrin_gen_
+ {
+ char *name; /* Name as seen in program. */
+ ffeintrinSpec specs[2];
+ };
+
+struct _ffeintrin_spec_
+ {
+ char *name; /* Uppercase name as seen in source code,
+ lowercase if no source name, "none" if no
+ name at all (NONE case). */
+ bool is_actualarg; /* Ok to pass as actual arg if -pedantic. */
+ ffeintrinFamily family;
+ ffeintrinImp implementation;
+ };
+
+struct _ffeintrin_imp_
+ {
+ char *name; /* Name of implementation. */
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffecomGfrt gfrt_direct; /* library routine, direct-callable form. */
+ ffecomGfrt gfrt_f2c; /* library routine, f2c-callable form. */
+ ffecomGfrt gfrt_gnu; /* library routine, gnu-callable form. */
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+ char *control;
+ };
+
+static ffebad ffeintrin_check_ (ffeintrinImp imp, ffebldOp op,
+ ffebld args, ffeinfoBasictype *xbt,
+ ffeinfoKindtype *xkt,
+ ffetargetCharacterSize *xsz,
+ bool *check_intrin,
+ ffelexToken t,
+ bool commit);
+static bool ffeintrin_check_any_ (ffebld arglist);
+static int ffeintrin_cmp_name_ (const void *name, const void *intrinsic);
+
+static struct _ffeintrin_name_ ffeintrin_names_[]
+=
+{ /* Alpha order. */
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC) \
+ { UPPER, LOWER, MIXED, FFEINTRIN_ ## GEN, FFEINTRIN_ ## SPEC },
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+static struct _ffeintrin_gen_ ffeintrin_gens_[]
+=
+{
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2) \
+ { NAME, { SPEC1, SPEC2, }, },
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+static struct _ffeintrin_imp_ ffeintrin_imps_[]
+=
+{
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL) \
+ { NAME, FFECOM_gfrt ## GFRTDIRECT, FFECOM_gfrt ## GFRTF2C, \
+ FFECOM_gfrt ## GFRTGNU, CONTROL },
+#elif FFECOM_targetCURRENT == FFECOM_targetFFE
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL) \
+ { NAME, CONTROL },
+#else
+#error
+#endif
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+static struct _ffeintrin_spec_ ffeintrin_specs_[]
+=
+{
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP) \
+ { NAME, CALLABLE, FAMILY, IMP, },
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+};
+
+
+static ffebad
+ffeintrin_check_ (ffeintrinImp imp, ffebldOp op,
+ ffebld args, ffeinfoBasictype *xbt,
+ ffeinfoKindtype *xkt,
+ ffetargetCharacterSize *xsz,
+ bool *check_intrin,
+ ffelexToken t,
+ bool commit)
+{
+ char *c = ffeintrin_imps_[imp].control;
+ bool subr = (c[0] == '-');
+ char *argc;
+ ffebld arg;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ ffetargetCharacterSize sz = FFETARGET_charactersizeNONE;
+ ffeinfoKindtype firstarg_kt;
+ bool need_col;
+ ffeinfoBasictype col_bt = FFEINFO_basictypeNONE;
+ ffeinfoKindtype col_kt = FFEINFO_kindtypeNONE;
+ int colon = (c[2] == ':') ? 2 : 3;
+ int argno;
+
+ /* Check procedure type (function vs. subroutine) against
+ invocation. */
+
+ if (op == FFEBLD_opSUBRREF)
+ {
+ if (!subr)
+ return FFEBAD_INTRINSIC_IS_FUNC;
+ }
+ else if (op == FFEBLD_opFUNCREF)
+ {
+ if (subr)
+ return FFEBAD_INTRINSIC_IS_SUBR;
+ }
+ else
+ return FFEBAD_INTRINSIC_REF;
+
+ /* Check the arglist for validity. */
+
+ if ((args != NULL)
+ && (ffebld_head (args) != NULL))
+ firstarg_kt = ffeinfo_kindtype (ffebld_info (ffebld_head (args)));
+ else
+ firstarg_kt = FFEINFO_kindtype;
+
+ for (argc = &c[colon + 3],
+ arg = args;
+ *argc != '\0';
+ )
+ {
+ char optional = '\0';
+ char required = '\0';
+ char extra = '\0';
+ char basic;
+ char kind;
+ int length;
+ int elements;
+ bool lastarg_complex = FALSE;
+
+ /* We don't do anything with keywords yet. */
+ do
+ {
+ } while (*(++argc) != '=');
+
+ ++argc;
+ if ((*argc == '?')
+ || (*argc == '!')
+ || (*argc == '*'))
+ optional = *(argc++);
+ if ((*argc == '+')
+ || (*argc == 'n')
+ || (*argc == 'p'))
+ required = *(argc++);
+ basic = *(argc++);
+ kind = *(argc++);
+ if (*argc == '[')
+ {
+ length = *++argc - '0';
+ if (*++argc != ']')
+ length = 10 * length + (*(argc++) - '0');
+ ++argc;
+ }
+ else
+ length = -1;
+ if (*argc == '(')
+ {
+ elements = *++argc - '0';
+ if (*++argc != ')')
+ elements = 10 * elements + (*(argc++) - '0');
+ ++argc;
+ }
+ else if (*argc == '&')
+ {
+ elements = -1;
+ ++argc;
+ }
+ else
+ elements = 0;
+ if ((*argc == '&')
+ || (*argc == 'i')
+ || (*argc == 'w')
+ || (*argc == 'x'))
+ extra = *(argc++);
+ if (*argc == ',')
+ ++argc;
+
+ /* Break out of this loop only when current arg spec completely
+ processed. */
+
+ do
+ {
+ bool okay;
+ ffebld a;
+ ffeinfo i;
+ bool anynum;
+ ffeinfoBasictype abt = FFEINFO_basictypeNONE;
+ ffeinfoKindtype akt = FFEINFO_kindtypeNONE;
+
+ if ((arg == NULL)
+ || (ffebld_head (arg) == NULL))
+ {
+ if (required != '\0')
+ return FFEBAD_INTRINSIC_TOOFEW;
+ if (optional == '\0')
+ return FFEBAD_INTRINSIC_TOOFEW;
+ if (arg != NULL)
+ arg = ffebld_trail (arg);
+ break; /* Try next argspec. */
+ }
+
+ a = ffebld_head (arg);
+ i = ffebld_info (a);
+ anynum = (ffeinfo_basictype (i) == FFEINFO_basictypeHOLLERITH)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeTYPELESS);
+
+ /* See how well the arg matches up to the spec. */
+
+ switch (basic)
+ {
+ case 'A':
+ okay = (ffeinfo_basictype (i) == FFEINFO_basictypeCHARACTER)
+ && ((length == -1)
+ || (ffeinfo_size (i) == (ffetargetCharacterSize) length));
+ break;
+
+ case 'C':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX);
+ abt = FFEINFO_basictypeCOMPLEX;
+ break;
+
+ case 'I':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER);
+ abt = FFEINFO_basictypeINTEGER;
+ break;
+
+ case 'L':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeLOGICAL);
+ abt = FFEINFO_basictypeLOGICAL;
+ break;
+
+ case 'R':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ abt = FFEINFO_basictypeREAL;
+ break;
+
+ case 'B':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeLOGICAL);
+ break;
+
+ case 'F':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case 'N':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case 'S':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case 'g':
+ okay = ((ffebld_op (a) == FFEBLD_opLABTER)
+ || (ffebld_op (a) == FFEBLD_opLABTOK));
+ elements = -1;
+ extra = '-';
+ break;
+
+ case 's':
+ okay = (((((ffeinfo_basictype (i) == FFEINFO_basictypeNONE)
+ && (ffeinfo_kindtype (i) == FFEINFO_kindtypeNONE)
+ && (ffeinfo_kind (i) == FFEINFO_kindSUBROUTINE))
+ || ((ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ && (ffeinfo_kindtype (i) == FFEINFO_kindtypeINTEGERDEFAULT)
+ && (ffeinfo_kind (i) == FFEINFO_kindFUNCTION))
+ || (ffeinfo_kind (i) == FFEINFO_kindNONE))
+ && ((ffeinfo_where (i) == FFEINFO_whereDUMMY)
+ || (ffeinfo_where (i) == FFEINFO_whereGLOBAL)))
+ || ((ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ && (ffeinfo_kind (i) == FFEINFO_kindENTITY)));
+ elements = -1;
+ extra = '-';
+ break;
+
+ case '-':
+ default:
+ okay = TRUE;
+ break;
+ }
+
+ switch (kind)
+ {
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ akt = (kind - '0');
+ if ((ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeLOGICAL))
+ {
+ switch (akt)
+ { /* Translate to internal kinds for now! */
+ default:
+ break;
+
+ case 2:
+ akt = 4;
+ break;
+
+ case 3:
+ akt = 2;
+ break;
+
+ case 4:
+ akt = 5;
+ break;
+
+ case 6:
+ akt = 3;
+ break;
+
+ case 7:
+ akt = ffecom_pointer_kind ();
+ break;
+ }
+ }
+ okay &= anynum || (ffeinfo_kindtype (i) == akt);
+ break;
+
+ case 'A':
+ okay &= anynum || (ffeinfo_kindtype (i) == firstarg_kt);
+ akt = (firstarg_kt == FFEINFO_kindtype) ? FFEINFO_kindtypeNONE
+ : firstarg_kt;
+ break;
+
+ case '*':
+ default:
+ break;
+ }
+
+ switch (elements)
+ {
+ ffebld b;
+
+ case -1:
+ break;
+
+ case 0:
+ if (ffeinfo_rank (i) != 0)
+ okay = FALSE;
+ break;
+
+ default:
+ if ((ffeinfo_rank (i) != 1)
+ || (ffebld_op (a) != FFEBLD_opSYMTER)
+ || ((b = ffesymbol_arraysize (ffebld_symter (a))) == NULL)
+ || (ffebld_op (b) != FFEBLD_opCONTER)
+ || (ffeinfo_basictype (ffebld_info (b)) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kindtype (ffebld_info (b)) != FFEINFO_kindtypeINTEGERDEFAULT)
+ || (ffebld_constant_integer1 (ffebld_conter (b)) != elements))
+ okay = FALSE;
+ break;
+ }
+
+ switch (extra)
+ {
+ case '&':
+ if ((ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ || ((ffebld_op (a) != FFEBLD_opSYMTER)
+ && (ffebld_op (a) != FFEBLD_opSUBSTR)
+ && (ffebld_op (a) != FFEBLD_opARRAYREF)))
+ okay = FALSE;
+ break;
+
+ case 'w':
+ case 'x':
+ if ((ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ || ((ffebld_op (a) != FFEBLD_opSYMTER)
+ && (ffebld_op (a) != FFEBLD_opARRAYREF)
+ && (ffebld_op (a) != FFEBLD_opSUBSTR)))
+ okay = FALSE;
+ break;
+
+ case '-':
+ case 'i':
+ break;
+
+ default:
+ if (ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ okay = FALSE;
+ break;
+ }
+
+ if ((optional == '!')
+ && lastarg_complex)
+ okay = FALSE;
+
+ if (!okay)
+ {
+ /* If it wasn't optional, it's an error,
+ else maybe it could match a later argspec. */
+ if (optional == '\0')
+ return FFEBAD_INTRINSIC_REF;
+ break; /* Try next argspec. */
+ }
+
+ lastarg_complex
+ = (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX);
+
+ if (anynum)
+ {
+ /* If we know dummy arg type, convert to that now. */
+
+ if ((abt != FFEINFO_basictypeNONE)
+ && (akt != FFEINFO_kindtypeNONE)
+ && commit)
+ {
+ /* We have a known type, convert hollerith/typeless
+ to it. */
+
+ a = ffeexpr_convert (a, t, NULL,
+ abt, akt, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ ffebld_set_head (arg, a);
+ }
+ }
+
+ arg = ffebld_trail (arg); /* Arg accepted, now move on. */
+
+ if (optional == '*')
+ continue; /* Go ahead and try another arg. */
+ if (required == '\0')
+ break;
+ if ((required == 'n')
+ || (required == '+'))
+ {
+ optional = '*';
+ required = '\0';
+ }
+ else if (required == 'p')
+ required = 'n';
+ } while (TRUE);
+ }
+
+ if (arg != NULL)
+ return FFEBAD_INTRINSIC_TOOMANY;
+
+ /* Set up the initial type for the return value of the function. */
+
+ need_col = FALSE;
+ switch (c[0])
+ {
+ case 'A':
+ bt = FFEINFO_basictypeCHARACTER;
+ sz = (c[2] == '*') ? FFETARGET_charactersizeNONE : 1;
+ break;
+
+ case 'C':
+ bt = FFEINFO_basictypeCOMPLEX;
+ break;
+
+ case 'I':
+ bt = FFEINFO_basictypeINTEGER;
+ break;
+
+ case 'L':
+ bt = FFEINFO_basictypeLOGICAL;
+ break;
+
+ case 'R':
+ bt = FFEINFO_basictypeREAL;
+ break;
+
+ case 'B':
+ case 'F':
+ case 'N':
+ case 'S':
+ need_col = TRUE;
+ /* Fall through. */
+ case '-':
+ default:
+ bt = FFEINFO_basictypeNONE;
+ break;
+ }
+
+ switch (c[1])
+ {
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ kt = (c[1] - '0');
+ if ((bt == FFEINFO_basictypeINTEGER)
+ || (bt == FFEINFO_basictypeLOGICAL))
+ {
+ switch (kt)
+ { /* Translate to internal kinds for now! */
+ default:
+ break;
+
+ case 2:
+ kt = 4;
+ break;
+
+ case 3:
+ kt = 2;
+ break;
+
+ case 4:
+ kt = 5;
+ break;
+
+ case 6:
+ kt = 3;
+ break;
+
+ case 7:
+ kt = ffecom_pointer_kind ();
+ break;
+ }
+ }
+ break;
+
+ case 'C':
+ if (ffe_is_90 ())
+ need_col = TRUE;
+ kt = 1;
+ break;
+
+ case '=':
+ need_col = TRUE;
+ /* Fall through. */
+ case '-':
+ default:
+ kt = FFEINFO_kindtypeNONE;
+ break;
+ }
+
+ /* Determine collective type of COL, if there is one. */
+
+ if (need_col || c[colon + 1] != '-')
+ {
+ bool okay = TRUE;
+ bool have_anynum = FALSE;
+
+ for (arg = args;
+ arg != NULL;
+ arg = (c[colon + 1] == '*') ? ffebld_trail (arg) : NULL)
+ {
+ ffebld a = ffebld_head (arg);
+ ffeinfo i;
+ bool anynum;
+
+ if (a == NULL)
+ continue;
+ i = ffebld_info (a);
+
+ anynum = (ffeinfo_basictype (i) == FFEINFO_basictypeHOLLERITH)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeTYPELESS);
+ if (anynum)
+ {
+ have_anynum = TRUE;
+ continue;
+ }
+
+ if ((col_bt == FFEINFO_basictypeNONE)
+ && (col_kt == FFEINFO_kindtypeNONE))
+ {
+ col_bt = ffeinfo_basictype (i);
+ col_kt = ffeinfo_kindtype (i);
+ }
+ else
+ {
+ ffeexpr_type_combine (&col_bt, &col_kt,
+ col_bt, col_kt,
+ ffeinfo_basictype (i),
+ ffeinfo_kindtype (i),
+ NULL);
+ if ((col_bt == FFEINFO_basictypeNONE)
+ || (col_kt == FFEINFO_kindtypeNONE))
+ return FFEBAD_INTRINSIC_REF;
+ }
+ }
+
+ if (have_anynum
+ && ((col_bt == FFEINFO_basictypeNONE)
+ || (col_kt == FFEINFO_kindtypeNONE)))
+ {
+ /* No type, but have hollerith/typeless. Use type of return
+ value to determine type of COL. */
+
+ switch (c[0])
+ {
+ case 'A':
+ return FFEBAD_INTRINSIC_REF;
+
+ case 'B':
+ case 'I':
+ case 'L':
+ if ((col_bt != FFEINFO_basictypeNONE)
+ && (col_bt != FFEINFO_basictypeINTEGER))
+ return FFEBAD_INTRINSIC_REF;
+ /* Fall through. */
+ case 'N':
+ case 'S':
+ case '-':
+ default:
+ col_bt = FFEINFO_basictypeINTEGER;
+ col_kt = FFEINFO_kindtypeINTEGER1;
+ break;
+
+ case 'C':
+ if ((col_bt != FFEINFO_basictypeNONE)
+ && (col_bt != FFEINFO_basictypeCOMPLEX))
+ return FFEBAD_INTRINSIC_REF;
+ col_bt = FFEINFO_basictypeCOMPLEX;
+ col_kt = FFEINFO_kindtypeREAL1;
+ break;
+
+ case 'R':
+ if ((col_bt != FFEINFO_basictypeNONE)
+ && (col_bt != FFEINFO_basictypeREAL))
+ return FFEBAD_INTRINSIC_REF;
+ /* Fall through. */
+ case 'F':
+ col_bt = FFEINFO_basictypeREAL;
+ col_kt = FFEINFO_kindtypeREAL1;
+ break;
+ }
+ }
+
+ switch (c[0])
+ {
+ case 'B':
+ okay = (col_bt == FFEINFO_basictypeINTEGER)
+ || (col_bt == FFEINFO_basictypeLOGICAL);
+ if (need_col)
+ bt = col_bt;
+ break;
+
+ case 'F':
+ okay = (col_bt == FFEINFO_basictypeCOMPLEX)
+ || (col_bt == FFEINFO_basictypeREAL);
+ if (need_col)
+ bt = col_bt;
+ break;
+
+ case 'N':
+ okay = (col_bt == FFEINFO_basictypeCOMPLEX)
+ || (col_bt == FFEINFO_basictypeINTEGER)
+ || (col_bt == FFEINFO_basictypeREAL);
+ if (need_col)
+ bt = col_bt;
+ break;
+
+ case 'S':
+ okay = (col_bt == FFEINFO_basictypeINTEGER)
+ || (col_bt == FFEINFO_basictypeREAL)
+ || (col_bt == FFEINFO_basictypeCOMPLEX);
+ if (need_col)
+ bt = ((col_bt != FFEINFO_basictypeCOMPLEX) ? col_bt
+ : FFEINFO_basictypeREAL);
+ break;
+ }
+
+ switch (c[1])
+ {
+ case '=':
+ if (need_col)
+ kt = col_kt;
+ break;
+
+ case 'C':
+ if (col_bt == FFEINFO_basictypeCOMPLEX)
+ {
+ if (col_kt != FFEINFO_kindtypeREALDEFAULT)
+ *check_intrin = TRUE;
+ if (need_col)
+ kt = col_kt;
+ }
+ break;
+ }
+
+ if (!okay)
+ return FFEBAD_INTRINSIC_REF;
+ }
+
+ /* Now, convert args in the arglist to the final type of the COL. */
+
+ for (argno = 0, argc = &c[colon + 3],
+ arg = args;
+ *argc != '\0';
+ ++argno)
+ {
+ char optional = '\0';
+ char required = '\0';
+ char extra = '\0';
+ char basic;
+ char kind;
+ int length;
+ int elements;
+ bool lastarg_complex = FALSE;
+
+ /* We don't do anything with keywords yet. */
+ do
+ {
+ } while (*(++argc) != '=');
+
+ ++argc;
+ if ((*argc == '?')
+ || (*argc == '!')
+ || (*argc == '*'))
+ optional = *(argc++);
+ if ((*argc == '+')
+ || (*argc == 'n')
+ || (*argc == 'p'))
+ required = *(argc++);
+ basic = *(argc++);
+ kind = *(argc++);
+ if (*argc == '[')
+ {
+ length = *++argc - '0';
+ if (*++argc != ']')
+ length = 10 * length + (*(argc++) - '0');
+ ++argc;
+ }
+ else
+ length = -1;
+ if (*argc == '(')
+ {
+ elements = *++argc - '0';
+ if (*++argc != ')')
+ elements = 10 * elements + (*(argc++) - '0');
+ ++argc;
+ }
+ else if (*argc == '&')
+ {
+ elements = -1;
+ ++argc;
+ }
+ else
+ elements = 0;
+ if ((*argc == '&')
+ || (*argc == 'i')
+ || (*argc == 'w')
+ || (*argc == 'x'))
+ extra = *(argc++);
+ if (*argc == ',')
+ ++argc;
+
+ /* Break out of this loop only when current arg spec completely
+ processed. */
+
+ do
+ {
+ bool okay;
+ ffebld a;
+ ffeinfo i;
+ bool anynum;
+ ffeinfoBasictype abt = FFEINFO_basictypeNONE;
+ ffeinfoKindtype akt = FFEINFO_kindtypeNONE;
+
+ if ((arg == NULL)
+ || (ffebld_head (arg) == NULL))
+ {
+ if (arg != NULL)
+ arg = ffebld_trail (arg);
+ break; /* Try next argspec. */
+ }
+
+ a = ffebld_head (arg);
+ i = ffebld_info (a);
+ anynum = (ffeinfo_basictype (i) == FFEINFO_basictypeHOLLERITH)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeTYPELESS);
+
+ /* Determine what the default type for anynum would be. */
+
+ if (anynum)
+ {
+ switch (c[colon + 1])
+ {
+ case '-':
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (argno != (c[colon + 1] - '0'))
+ break;
+ case '*':
+ abt = col_bt;
+ akt = col_kt;
+ break;
+ }
+ }
+
+ /* Again, match arg up to the spec. We go through all of
+ this again to properly follow the contour of optional
+ arguments. Probably this level of flexibility is not
+ needed, perhaps it's even downright naughty. */
+
+ switch (basic)
+ {
+ case 'A':
+ okay = (ffeinfo_basictype (i) == FFEINFO_basictypeCHARACTER)
+ && ((length == -1)
+ || (ffeinfo_size (i) == (ffetargetCharacterSize) length));
+ break;
+
+ case 'C':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX);
+ abt = FFEINFO_basictypeCOMPLEX;
+ break;
+
+ case 'I':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER);
+ abt = FFEINFO_basictypeINTEGER;
+ break;
+
+ case 'L':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeLOGICAL);
+ abt = FFEINFO_basictypeLOGICAL;
+ break;
+
+ case 'R':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ abt = FFEINFO_basictypeREAL;
+ break;
+
+ case 'B':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeLOGICAL);
+ break;
+
+ case 'F':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case 'N':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case 'S':
+ okay = anynum
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeREAL);
+ break;
+
+ case 'g':
+ okay = ((ffebld_op (a) == FFEBLD_opLABTER)
+ || (ffebld_op (a) == FFEBLD_opLABTOK));
+ elements = -1;
+ extra = '-';
+ break;
+
+ case 's':
+ okay = (((((ffeinfo_basictype (i) == FFEINFO_basictypeNONE)
+ && (ffeinfo_kindtype (i) == FFEINFO_kindtypeNONE)
+ && (ffeinfo_kind (i) == FFEINFO_kindSUBROUTINE))
+ || ((ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ && (ffeinfo_kindtype (i) == FFEINFO_kindtypeINTEGERDEFAULT)
+ && (ffeinfo_kind (i) == FFEINFO_kindFUNCTION))
+ || (ffeinfo_kind (i) == FFEINFO_kindNONE))
+ && ((ffeinfo_where (i) == FFEINFO_whereDUMMY)
+ || (ffeinfo_where (i) == FFEINFO_whereGLOBAL)))
+ || ((ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ && (ffeinfo_kind (i) == FFEINFO_kindENTITY)));
+ elements = -1;
+ extra = '-';
+ break;
+
+ case '-':
+ default:
+ okay = TRUE;
+ break;
+ }
+
+ switch (kind)
+ {
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ akt = (kind - '0');
+ if ((ffeinfo_basictype (i) == FFEINFO_basictypeINTEGER)
+ || (ffeinfo_basictype (i) == FFEINFO_basictypeLOGICAL))
+ {
+ switch (akt)
+ { /* Translate to internal kinds for now! */
+ default:
+ break;
+
+ case 2:
+ akt = 4;
+ break;
+
+ case 3:
+ akt = 2;
+ break;
+
+ case 4:
+ akt = 5;
+ break;
+
+ case 6:
+ akt = 3;
+ break;
+
+ case 7:
+ akt = ffecom_pointer_kind ();
+ break;
+ }
+ }
+ okay &= anynum || (ffeinfo_kindtype (i) == akt);
+ break;
+
+ case 'A':
+ okay &= anynum || (ffeinfo_kindtype (i) == firstarg_kt);
+ akt = (firstarg_kt == FFEINFO_kindtype) ? FFEINFO_kindtypeNONE
+ : firstarg_kt;
+ break;
+
+ case '*':
+ default:
+ break;
+ }
+
+ switch (elements)
+ {
+ ffebld b;
+
+ case -1:
+ break;
+
+ case 0:
+ if (ffeinfo_rank (i) != 0)
+ okay = FALSE;
+ break;
+
+ default:
+ if ((ffeinfo_rank (i) != 1)
+ || (ffebld_op (a) != FFEBLD_opSYMTER)
+ || ((b = ffesymbol_arraysize (ffebld_symter (a))) == NULL)
+ || (ffebld_op (b) != FFEBLD_opCONTER)
+ || (ffeinfo_basictype (ffebld_info (b)) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kindtype (ffebld_info (b)) != FFEINFO_kindtypeINTEGERDEFAULT)
+ || (ffebld_constant_integer1 (ffebld_conter (b)) != elements))
+ okay = FALSE;
+ break;
+ }
+
+ switch (extra)
+ {
+ case '&':
+ if ((ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ || ((ffebld_op (a) != FFEBLD_opSYMTER)
+ && (ffebld_op (a) != FFEBLD_opSUBSTR)
+ && (ffebld_op (a) != FFEBLD_opARRAYREF)))
+ okay = FALSE;
+ break;
+
+ case 'w':
+ case 'x':
+ if ((ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ || ((ffebld_op (a) != FFEBLD_opSYMTER)
+ && (ffebld_op (a) != FFEBLD_opARRAYREF)
+ && (ffebld_op (a) != FFEBLD_opSUBSTR)))
+ okay = FALSE;
+ break;
+
+ case '-':
+ case 'i':
+ break;
+
+ default:
+ if (ffeinfo_kind (i) != FFEINFO_kindENTITY)
+ okay = FALSE;
+ break;
+ }
+
+ if ((optional == '!')
+ && lastarg_complex)
+ okay = FALSE;
+
+ if (!okay)
+ {
+ /* If it wasn't optional, it's an error,
+ else maybe it could match a later argspec. */
+ if (optional == '\0')
+ return FFEBAD_INTRINSIC_REF;
+ break; /* Try next argspec. */
+ }
+
+ lastarg_complex
+ = (ffeinfo_basictype (i) == FFEINFO_basictypeCOMPLEX);
+
+ if (anynum && commit)
+ {
+ /* If we know dummy arg type, convert to that now. */
+
+ if (abt == FFEINFO_basictypeNONE)
+ abt = FFEINFO_basictypeINTEGER;
+ if (akt == FFEINFO_kindtypeNONE)
+ akt = FFEINFO_kindtypeINTEGER1;
+
+ /* We have a known type, convert hollerith/typeless to it. */
+
+ a = ffeexpr_convert (a, t, NULL,
+ abt, akt, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ ffebld_set_head (arg, a);
+ }
+ else if ((c[colon + 1] == '*') && commit)
+ {
+ /* This is where we promote types to the consensus
+ type for the COL. Maybe this is where -fpedantic
+ should issue a warning as well. */
+
+ a = ffeexpr_convert (a, t, NULL,
+ col_bt, col_kt, 0,
+ ffeinfo_size (i),
+ FFEEXPR_contextLET);
+ ffebld_set_head (arg, a);
+ }
+
+ arg = ffebld_trail (arg); /* Arg accepted, now move on. */
+
+ if (optional == '*')
+ continue; /* Go ahead and try another arg. */
+ if (required == '\0')
+ break;
+ if ((required == 'n')
+ || (required == '+'))
+ {
+ optional = '*';
+ required = '\0';
+ }
+ else if (required == 'p')
+ required = 'n';
+ } while (TRUE);
+ }
+
+ *xbt = bt;
+ *xkt = kt;
+ *xsz = sz;
+ return FFEBAD;
+}
+
+static bool
+ffeintrin_check_any_ (ffebld arglist)
+{
+ ffebld item;
+
+ for (; arglist != NULL; arglist = ffebld_trail (arglist))
+ {
+ item = ffebld_head (arglist);
+ if ((item != NULL)
+ && (ffebld_op (item) == FFEBLD_opANY))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Compare name to intrinsic's name. Uses strcmp on arguments' names. */
+
+static int
+ffeintrin_cmp_name_ (const void *name, const void *intrinsic)
+{
+ char *uc = (char *) ((struct _ffeintrin_name_ *) intrinsic)->name_uc;
+ char *lc = (char *) ((struct _ffeintrin_name_ *) intrinsic)->name_lc;
+ char *ic = (char *) ((struct _ffeintrin_name_ *) intrinsic)->name_ic;
+
+ return ffesrc_strcmp_2c (ffe_case_intrin (), name, uc, lc, ic);
+}
+
+/* Return basic type of intrinsic implementation, based on its
+ run-time implementation *only*. (This is used only when
+ the type of an intrinsic name is needed without having a
+ list of arguments, i.e. an interface signature, such as when
+ passing the intrinsic itself, or really the run-time-library
+ function, as an argument.)
+
+ If there's no eligible intrinsic implementation, there must be
+ a bug somewhere else; no such reference should have been permitted
+ to go this far. (Well, this might be wrong.) */
+
+ffeinfoBasictype
+ffeintrin_basictype (ffeintrinSpec spec)
+{
+ ffeintrinImp imp;
+ ffecomGfrt gfrt;
+
+ assert (spec < FFEINTRIN_spec);
+ imp = ffeintrin_specs_[spec].implementation;
+ assert (imp < FFEINTRIN_imp);
+
+ if (ffe_is_f2c ())
+ gfrt = ffeintrin_imps_[imp].gfrt_f2c;
+ else
+ gfrt = ffeintrin_imps_[imp].gfrt_gnu;
+
+ assert (gfrt != FFECOM_gfrt);
+
+ return ffecom_gfrt_basictype (gfrt);
+}
+
+/* Return family to which specific intrinsic belongs. */
+
+ffeintrinFamily
+ffeintrin_family (ffeintrinSpec spec)
+{
+ if (spec >= FFEINTRIN_spec)
+ return FALSE;
+ return ffeintrin_specs_[spec].family;
+}
+
+/* Check and fill in info on func/subr ref node.
+
+ ffebld expr; // FUNCREF or SUBRREF with no info (caller
+ // gets it from the modified info structure).
+ ffeinfo info; // Already filled in, will be overwritten.
+ ffelexToken token; // Used for error message.
+ ffeintrin_fulfill_generic (&expr, &info, token);
+
+ Based on the generic id, figure out which specific procedure is meant and
+ pick that one. Else return an error, a la _specific. */
+
+void
+ffeintrin_fulfill_generic (ffebld *expr, ffeinfo *info, ffelexToken t)
+{
+ ffebld symter;
+ ffebldOp op;
+ ffeintrinGen gen;
+ ffeintrinSpec spec = FFEINTRIN_specNONE;
+ ffeinfoBasictype bt = FFEINFO_basictypeNONE;
+ ffeinfoKindtype kt = FFEINFO_kindtypeNONE;
+ ffetargetCharacterSize sz = FFETARGET_charactersizeNONE;
+ ffeintrinImp imp;
+ ffeintrinSpec tspec;
+ ffeintrinImp nimp = FFEINTRIN_impNONE;
+ ffebad error;
+ bool any = FALSE;
+ bool highly_specific = FALSE;
+ int i;
+
+ op = ffebld_op (*expr);
+ assert ((op == FFEBLD_opFUNCREF) || (op == FFEBLD_opSUBRREF));
+ assert (ffebld_op (ffebld_left (*expr)) == FFEBLD_opSYMTER);
+
+ gen = ffebld_symter_generic (ffebld_left (*expr));
+ assert (gen != FFEINTRIN_genNONE);
+
+ imp = FFEINTRIN_impNONE;
+ error = FFEBAD;
+
+ any = ffeintrin_check_any_ (ffebld_right (*expr));
+
+ for (i = 0;
+ (((size_t) i) < ARRAY_SIZE (ffeintrin_gens_[gen].specs))
+ && ((tspec = ffeintrin_gens_[gen].specs[i]) != FFEINTRIN_specNONE)
+ && !any;
+ ++i)
+ {
+ ffeintrinImp timp = ffeintrin_specs_[tspec].implementation;
+ ffeinfoBasictype tbt;
+ ffeinfoKindtype tkt;
+ ffetargetCharacterSize tsz;
+ ffeIntrinsicState state
+ = ffeintrin_state_family (ffeintrin_specs_[tspec].family);
+ ffebad terror;
+
+ if (state == FFE_intrinsicstateDELETED)
+ continue;
+
+ if (timp != FFEINTRIN_impNONE)
+ {
+ if (!(ffeintrin_imps_[timp].control[0] == '-')
+ != !(ffebld_op (*expr) == FFEBLD_opSUBRREF))
+ continue; /* Form of reference must match form of specific. */
+ }
+
+ if (state == FFE_intrinsicstateDISABLED)
+ terror = FFEBAD_INTRINSIC_DISABLED;
+ else if (timp == FFEINTRIN_impNONE)
+ terror = FFEBAD_INTRINSIC_UNIMPL;
+ else
+ {
+ terror = ffeintrin_check_ (timp, ffebld_op (*expr),
+ ffebld_right (*expr),
+ &tbt, &tkt, &tsz, NULL, t, FALSE);
+ if (terror == FFEBAD)
+ {
+ if (imp != FFEINTRIN_impNONE)
+ {
+ ffebad_start (FFEBAD_INTRINSIC_AMBIG);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_string (ffeintrin_gens_[gen].name);
+ ffebad_string (ffeintrin_specs_[spec].name);
+ ffebad_string (ffeintrin_specs_[tspec].name);
+ ffebad_finish ();
+ }
+ else
+ {
+ if (ffebld_symter_specific (ffebld_left (*expr))
+ == tspec)
+ highly_specific = TRUE;
+ imp = timp;
+ spec = tspec;
+ bt = tbt;
+ kt = tkt;
+ sz = tkt;
+ error = terror;
+ }
+ }
+ else if (terror != FFEBAD)
+ { /* This error has precedence over others. */
+ if ((error == FFEBAD_INTRINSIC_DISABLED)
+ || (error == FFEBAD_INTRINSIC_UNIMPL))
+ error = FFEBAD;
+ }
+ }
+
+ if (error == FFEBAD)
+ error = terror;
+ }
+
+ if (any || (imp == FFEINTRIN_impNONE))
+ {
+ if (!any)
+ {
+ if (error == FFEBAD)
+ error = FFEBAD_INTRINSIC_REF;
+ ffebad_start (error);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_string (ffeintrin_gens_[gen].name);
+ ffebad_finish ();
+ }
+
+ *expr = ffebld_new_any ();
+ *info = ffeinfo_new_any ();
+ }
+ else
+ {
+ if (!highly_specific && (nimp != FFEINTRIN_impNONE))
+ {
+ fprintf (stderr, "lineno=%ld, gen=%s, imp=%s, timp=%s\n",
+ (long) lineno,
+ ffeintrin_gens_[gen].name,
+ ffeintrin_imps_[imp].name,
+ ffeintrin_imps_[nimp].name);
+ assert ("Ambiguous generic reference" == NULL);
+ abort ();
+ }
+ error = ffeintrin_check_ (imp, ffebld_op (*expr),
+ ffebld_right (*expr),
+ &bt, &kt, &sz, NULL, t, TRUE);
+ assert (error == FFEBAD);
+ *info = ffeinfo_new (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereFLEETING,
+ sz);
+ symter = ffebld_left (*expr);
+ ffebld_symter_set_specific (symter, spec);
+ ffebld_symter_set_implementation (symter, imp);
+ ffebld_set_info (symter,
+ ffeinfo_new (bt,
+ kt,
+ 0,
+ (bt == FFEINFO_basictypeNONE)
+ ? FFEINFO_kindSUBROUTINE
+ : FFEINFO_kindFUNCTION,
+ FFEINFO_whereINTRINSIC,
+ sz));
+
+ if ((ffesymbol_attrs (ffebld_symter (symter)) & FFESYMBOL_attrsTYPE)
+ && (((bt != ffesymbol_basictype (ffebld_symter (symter)))
+ || (kt != ffesymbol_kindtype (ffebld_symter (symter)))
+ || ((sz != FFETARGET_charactersizeNONE)
+ && (sz != ffesymbol_size (ffebld_symter (symter)))))))
+ {
+ ffebad_start (FFEBAD_INTRINSIC_TYPE);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_string (ffeintrin_gens_[gen].name);
+ ffebad_finish ();
+ }
+ }
+}
+
+/* Check and fill in info on func/subr ref node.
+
+ ffebld expr; // FUNCREF or SUBRREF with no info (caller
+ // gets it from the modified info structure).
+ ffeinfo info; // Already filled in, will be overwritten.
+ bool check_intrin; // May be omitted, else set TRUE if intrinsic needs checking.
+ ffelexToken token; // Used for error message.
+ ffeintrin_fulfill_specific (&expr, &info, &check_intrin, token);
+
+ Based on the specific id, determine whether the arg list is valid
+ (number, type, rank, and kind of args) and fill in the info structure
+ accordingly. Currently don't rewrite the expression, but perhaps
+ someday do so for constant collapsing, except when an error occurs,
+ in which case it is overwritten with ANY and info is also overwritten
+ accordingly. */
+
+void
+ffeintrin_fulfill_specific (ffebld *expr, ffeinfo *info,
+ bool *check_intrin, ffelexToken t)
+{
+ ffebld symter;
+ ffebldOp op;
+ ffeintrinGen gen;
+ ffeintrinSpec spec;
+ ffeintrinImp imp;
+ ffeinfoBasictype bt = FFEINFO_basictypeNONE;
+ ffeinfoKindtype kt = FFEINFO_kindtypeNONE;
+ ffetargetCharacterSize sz = FFETARGET_charactersizeNONE;
+ ffeIntrinsicState state;
+ ffebad error;
+ bool any = FALSE;
+ char *name;
+
+ op = ffebld_op (*expr);
+ assert ((op == FFEBLD_opFUNCREF) || (op == FFEBLD_opSUBRREF));
+ assert (ffebld_op (ffebld_left (*expr)) == FFEBLD_opSYMTER);
+
+ gen = ffebld_symter_generic (ffebld_left (*expr));
+ spec = ffebld_symter_specific (ffebld_left (*expr));
+ assert (spec != FFEINTRIN_specNONE);
+
+ if (gen != FFEINTRIN_genNONE)
+ name = ffeintrin_gens_[gen].name;
+ else
+ name = ffeintrin_specs_[spec].name;
+
+ state = ffeintrin_state_family (ffeintrin_specs_[spec].family);
+
+ imp = ffeintrin_specs_[spec].implementation;
+ if (check_intrin != NULL)
+ *check_intrin = FALSE;
+
+ any = ffeintrin_check_any_ (ffebld_right (*expr));
+
+ if (state == FFE_intrinsicstateDISABLED)
+ error = FFEBAD_INTRINSIC_DISABLED;
+ else if (imp == FFEINTRIN_impNONE)
+ error = FFEBAD_INTRINSIC_UNIMPL;
+ else if (!any)
+ {
+ error = ffeintrin_check_ (imp, ffebld_op (*expr),
+ ffebld_right (*expr),
+ &bt, &kt, &sz, check_intrin, t, TRUE);
+ }
+ else
+ error = FFEBAD; /* Not really needed, but quiet -Wuninitialized. */
+
+ if (any || (error != FFEBAD))
+ {
+ if (!any)
+ {
+
+ ffebad_start (error);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_string (name);
+ ffebad_finish ();
+ }
+
+ *expr = ffebld_new_any ();
+ *info = ffeinfo_new_any ();
+ }
+ else
+ {
+ *info = ffeinfo_new (bt,
+ kt,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereFLEETING,
+ sz);
+ symter = ffebld_left (*expr);
+ ffebld_set_info (symter,
+ ffeinfo_new (bt,
+ kt,
+ 0,
+ (bt == FFEINFO_basictypeNONE)
+ ? FFEINFO_kindSUBROUTINE
+ : FFEINFO_kindFUNCTION,
+ FFEINFO_whereINTRINSIC,
+ sz));
+
+ if ((ffesymbol_attrs (ffebld_symter (symter)) & FFESYMBOL_attrsTYPE)
+ && (((bt != ffesymbol_basictype (ffebld_symter (symter)))
+ || (kt != ffesymbol_kindtype (ffebld_symter (symter)))
+ || (sz != ffesymbol_size (ffebld_symter (symter))))))
+ {
+ ffebad_start (FFEBAD_INTRINSIC_TYPE);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_string (name);
+ ffebad_finish ();
+ }
+ }
+}
+
+/* Return run-time index of intrinsic implementation as direct call. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ffecomGfrt
+ffeintrin_gfrt_direct (ffeintrinImp imp)
+{
+ assert (imp < FFEINTRIN_imp);
+
+ return ffeintrin_imps_[imp].gfrt_direct;
+}
+#endif
+
+/* Return run-time index of intrinsic implementation as actual argument. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ffecomGfrt
+ffeintrin_gfrt_indirect (ffeintrinImp imp)
+{
+ assert (imp < FFEINTRIN_imp);
+
+ if (! ffe_is_f2c ())
+ return ffeintrin_imps_[imp].gfrt_gnu;
+ return ffeintrin_imps_[imp].gfrt_f2c;
+}
+#endif
+
+void
+ffeintrin_init_0 ()
+{
+ int i;
+ char *p1;
+ char *p2;
+ char *p3;
+ int colon;
+
+ if (!ffe_is_do_internal_checks ())
+ return;
+
+ assert (FFEINTRIN_gen == ARRAY_SIZE (ffeintrin_gens_));
+ assert (FFEINTRIN_imp == ARRAY_SIZE (ffeintrin_imps_));
+ assert (FFEINTRIN_spec == ARRAY_SIZE (ffeintrin_specs_));
+
+ for (i = 1; ((size_t) i) < ARRAY_SIZE (ffeintrin_names_); ++i)
+ { /* Make sure binary-searched list is in alpha
+ order. */
+ if (strcmp (ffeintrin_names_[i - 1].name_uc,
+ ffeintrin_names_[i].name_uc) >= 0)
+ assert ("name list out of order" == NULL);
+ }
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (ffeintrin_names_); ++i)
+ {
+ assert ((ffeintrin_names_[i].generic == FFEINTRIN_genNONE)
+ || (ffeintrin_names_[i].specific == FFEINTRIN_specNONE));
+
+ p1 = ffeintrin_names_[i].name_uc;
+ p2 = ffeintrin_names_[i].name_lc;
+ p3 = ffeintrin_names_[i].name_ic;
+ for (; *p1 != '\0' && *p2 != '\0' && *p3 != '\0'; ++p1, ++p2, ++p3)
+ {
+ if (! IN_CTYPE_DOMAIN (*p1)
+ || ! IN_CTYPE_DOMAIN (*p2)
+ || ! IN_CTYPE_DOMAIN (*p3))
+ break;
+ if ((ISDIGIT (*p1) || (*p1 == '_')) && (*p1 == *p2) && (*p1 == *p3))
+ continue;
+ if (! ISUPPER (*p1) || ! ISLOWER (*p2)
+ || (*p1 != toupper (*p2)) || ((*p3 != *p1) && (*p3 != *p2)))
+ break;
+ }
+ assert ((*p1 == *p2) && (*p1 == *p3) && (*p1 == '\0'));
+ }
+
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (ffeintrin_imps_); ++i)
+ {
+ char *c = ffeintrin_imps_[i].control;
+
+ if (c[0] == '\0')
+ continue;
+
+ if ((c[0] != '-')
+ && (c[0] != 'A')
+ && (c[0] != 'C')
+ && (c[0] != 'I')
+ && (c[0] != 'L')
+ && (c[0] != 'R')
+ && (c[0] != 'B')
+ && (c[0] != 'F')
+ && (c[0] != 'N')
+ && (c[0] != 'S'))
+ {
+ fprintf (stderr, "%s: bad return-base-type\n",
+ ffeintrin_imps_[i].name);
+ continue;
+ }
+ if ((c[1] != '-')
+ && (c[1] != '=')
+ && ((c[1] < '1')
+ || (c[1] > '9'))
+ && (c[1] != 'C'))
+ {
+ fprintf (stderr, "%s: bad return-kind-type\n",
+ ffeintrin_imps_[i].name);
+ continue;
+ }
+ if (c[2] == ':')
+ colon = 2;
+ else
+ {
+ if (c[2] != '*')
+ {
+ fprintf (stderr, "%s: bad return-modifier\n",
+ ffeintrin_imps_[i].name);
+ continue;
+ }
+ colon = 3;
+ }
+ if ((c[colon] != ':') || (c[colon + 2] != ':'))
+ {
+ fprintf (stderr, "%s: bad control\n",
+ ffeintrin_imps_[i].name);
+ continue;
+ }
+ if ((c[colon + 1] != '-')
+ && (c[colon + 1] != '*')
+ && ((c[colon + 1] < '0')
+ || (c[colon + 1] > '9')))
+ {
+ fprintf (stderr, "%s: bad COL-spec\n",
+ ffeintrin_imps_[i].name);
+ continue;
+ }
+ c += (colon + 3);
+ while (c[0] != '\0')
+ {
+ while ((c[0] != '=')
+ && (c[0] != ',')
+ && (c[0] != '\0'))
+ ++c;
+ if (c[0] != '=')
+ {
+ fprintf (stderr, "%s: bad keyword\n",
+ ffeintrin_imps_[i].name);
+ break;
+ }
+ if ((c[1] == '?')
+ || (c[1] == '!')
+ || (c[1] == '+')
+ || (c[1] == '*')
+ || (c[1] == 'n')
+ || (c[1] == 'p'))
+ ++c;
+ if ((c[1] != '-')
+ && (c[1] != 'A')
+ && (c[1] != 'C')
+ && (c[1] != 'I')
+ && (c[1] != 'L')
+ && (c[1] != 'R')
+ && (c[1] != 'B')
+ && (c[1] != 'F')
+ && (c[1] != 'N')
+ && (c[1] != 'S')
+ && (c[1] != 'g')
+ && (c[1] != 's'))
+ {
+ fprintf (stderr, "%s: bad arg-base-type\n",
+ ffeintrin_imps_[i].name);
+ break;
+ }
+ if ((c[2] != '*')
+ && ((c[2] < '1')
+ || (c[2] > '9'))
+ && (c[2] != 'A'))
+ {
+ fprintf (stderr, "%s: bad arg-kind-type\n",
+ ffeintrin_imps_[i].name);
+ break;
+ }
+ if (c[3] == '[')
+ {
+ if (((c[4] < '0') || (c[4] > '9'))
+ || ((c[5] != ']')
+ && (++c, (c[4] < '0') || (c[4] > '9')
+ || (c[5] != ']'))))
+ {
+ fprintf (stderr, "%s: bad arg-len\n",
+ ffeintrin_imps_[i].name);
+ break;
+ }
+ c += 3;
+ }
+ if (c[3] == '(')
+ {
+ if (((c[4] < '0') || (c[4] > '9'))
+ || ((c[5] != ')')
+ && (++c, (c[4] < '0') || (c[4] > '9')
+ || (c[5] != ')'))))
+ {
+ fprintf (stderr, "%s: bad arg-rank\n",
+ ffeintrin_imps_[i].name);
+ break;
+ }
+ c += 3;
+ }
+ else if ((c[3] == '&')
+ && (c[4] == '&'))
+ ++c;
+ if ((c[3] == '&')
+ || (c[3] == 'i')
+ || (c[3] == 'w')
+ || (c[3] == 'x'))
+ ++c;
+ if (c[3] == ',')
+ {
+ c += 4;
+ continue;
+ }
+ if (c[3] != '\0')
+ {
+ fprintf (stderr, "%s: bad arg-list\n",
+ ffeintrin_imps_[i].name);
+ }
+ break;
+ }
+ }
+}
+
+/* Determine whether intrinsic is okay as an actual argument. */
+
+bool
+ffeintrin_is_actualarg (ffeintrinSpec spec)
+{
+ ffeIntrinsicState state;
+
+ if (spec >= FFEINTRIN_spec)
+ return FALSE;
+
+ state = ffeintrin_state_family (ffeintrin_specs_[spec].family);
+
+ return (!ffe_is_pedantic () || ffeintrin_specs_[spec].is_actualarg)
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ && (ffe_is_f2c ()
+ ? (ffeintrin_imps_[ffeintrin_specs_[spec].implementation].gfrt_f2c
+ != FFECOM_gfrt)
+ : (ffeintrin_imps_[ffeintrin_specs_[spec].implementation].gfrt_gnu
+ != FFECOM_gfrt))
+#endif
+ && ((state == FFE_intrinsicstateENABLED)
+ || (state == FFE_intrinsicstateHIDDEN));
+}
+
+/* Determine if name is intrinsic, return info.
+
+ char *name; // C-string name of possible intrinsic.
+ ffelexToken t; // NULL if no diagnostic to be given.
+ bool explicit; // TRUE if INTRINSIC name.
+ ffeintrinGen gen; // (TRUE only) Generic id of intrinsic.
+ ffeintrinSpec spec; // (TRUE only) Specific id of intrinsic.
+ ffeintrinImp imp; // (TRUE only) Implementation id of intrinsic.
+ if (ffeintrin_is_intrinsic (name, t, explicit,
+ &gen, &spec, &imp))
+ // is an intrinsic, use gen, spec, imp, and
+ // kind accordingly. */
+
+bool
+ffeintrin_is_intrinsic (char *name, ffelexToken t, bool explicit,
+ ffeintrinGen *xgen, ffeintrinSpec *xspec,
+ ffeintrinImp *ximp)
+{
+ struct _ffeintrin_name_ *intrinsic;
+ ffeintrinGen gen;
+ ffeintrinSpec spec;
+ ffeintrinImp imp;
+ ffeIntrinsicState state;
+ bool disabled = FALSE;
+ bool unimpl = FALSE;
+
+ intrinsic = bsearch (name, &ffeintrin_names_[0],
+ ARRAY_SIZE (ffeintrin_names_),
+ sizeof (struct _ffeintrin_name_),
+ (void *) ffeintrin_cmp_name_);
+
+ if (intrinsic == NULL)
+ return FALSE;
+
+ gen = intrinsic->generic;
+ spec = intrinsic->specific;
+ imp = ffeintrin_specs_[spec].implementation;
+
+ /* Generic is okay only if at least one of its specifics is okay. */
+
+ if (gen != FFEINTRIN_genNONE)
+ {
+ int i;
+ ffeintrinSpec tspec;
+ bool ok = FALSE;
+
+ name = ffeintrin_gens_[gen].name;
+
+ for (i = 0;
+ (((size_t) i) < ARRAY_SIZE (ffeintrin_gens_[gen].specs))
+ && ((tspec
+ = ffeintrin_gens_[gen].specs[i]) != FFEINTRIN_specNONE);
+ ++i)
+ {
+ state = ffeintrin_state_family (ffeintrin_specs_[tspec].family);
+
+ if (state == FFE_intrinsicstateDELETED)
+ continue;
+
+ if (state == FFE_intrinsicstateDISABLED)
+ {
+ disabled = TRUE;
+ continue;
+ }
+
+ if (ffeintrin_specs_[tspec].implementation == FFEINTRIN_impNONE)
+ {
+ unimpl = TRUE;
+ continue;
+ }
+
+ if ((state == FFE_intrinsicstateENABLED)
+ || (explicit
+ && (state == FFE_intrinsicstateHIDDEN)))
+ {
+ ok = TRUE;
+ break;
+ }
+ }
+ if (!ok)
+ gen = FFEINTRIN_genNONE;
+ }
+
+ /* Specific is okay only if not: unimplemented, disabled, deleted, or
+ hidden and not explicit. */
+
+ if (spec != FFEINTRIN_specNONE)
+ {
+ if (gen != FFEINTRIN_genNONE)
+ name = ffeintrin_gens_[gen].name;
+ else
+ name = ffeintrin_specs_[spec].name;
+
+ if (((state = ffeintrin_state_family (ffeintrin_specs_[spec].family))
+ == FFE_intrinsicstateDELETED)
+ || (!explicit
+ && (state == FFE_intrinsicstateHIDDEN)))
+ spec = FFEINTRIN_specNONE;
+ else if (state == FFE_intrinsicstateDISABLED)
+ {
+ disabled = TRUE;
+ spec = FFEINTRIN_specNONE;
+ }
+ else if (imp == FFEINTRIN_impNONE)
+ {
+ unimpl = TRUE;
+ spec = FFEINTRIN_specNONE;
+ }
+ }
+
+ /* If neither is okay, not an intrinsic. */
+
+ if ((gen == FFEINTRIN_genNONE) && (spec == FFEINTRIN_specNONE))
+ {
+ /* Here is where we produce a diagnostic about a reference to a
+ disabled or unimplemented intrinsic, if the diagnostic is desired. */
+
+ if ((disabled || unimpl)
+ && (t != NULL))
+ {
+ ffebad_start (disabled
+ ? FFEBAD_INTRINSIC_DISABLED
+ : FFEBAD_INTRINSIC_UNIMPLW);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_string (name);
+ ffebad_finish ();
+ }
+
+ return FALSE;
+ }
+
+ /* Determine whether intrinsic is function or subroutine. If no specific
+ id, scan list of possible specifics for generic to get consensus. If
+ not unanimous, or clear from the context, return NONE. */
+
+ if (spec == FFEINTRIN_specNONE)
+ {
+ int i;
+ ffeintrinSpec tspec;
+ ffeintrinImp timp;
+ bool at_least_one_ok = FALSE;
+
+ for (i = 0;
+ (((size_t) i) < ARRAY_SIZE (ffeintrin_gens_[gen].specs))
+ && ((tspec
+ = ffeintrin_gens_[gen].specs[i]) != FFEINTRIN_specNONE);
+ ++i)
+ {
+ if (((state = ffeintrin_state_family (ffeintrin_specs_[tspec].family))
+ == FFE_intrinsicstateDELETED)
+ || (state == FFE_intrinsicstateDISABLED))
+ continue;
+
+ if ((timp = ffeintrin_specs_[tspec].implementation)
+ == FFEINTRIN_impNONE)
+ continue;
+
+ at_least_one_ok = TRUE;
+ break;
+ }
+
+ if (!at_least_one_ok)
+ {
+ *xgen = FFEINTRIN_genNONE;
+ *xspec = FFEINTRIN_specNONE;
+ *ximp = FFEINTRIN_impNONE;
+ return FALSE;
+ }
+ }
+
+ *xgen = gen;
+ *xspec = spec;
+ *ximp = imp;
+ return TRUE;
+}
+
+/* Return TRUE if intrinsic is standard F77 (or, if -ff90, F90). */
+
+bool
+ffeintrin_is_standard (ffeintrinGen gen, ffeintrinSpec spec)
+{
+ if (spec == FFEINTRIN_specNONE)
+ {
+ if (gen == FFEINTRIN_genNONE)
+ return FALSE;
+
+ spec = ffeintrin_gens_[gen].specs[0];
+ if (spec == FFEINTRIN_specNONE)
+ return FALSE;
+ }
+
+ if ((ffeintrin_specs_[spec].family == FFEINTRIN_familyF77)
+ || (ffe_is_90 ()
+ && ((ffeintrin_specs_[spec].family == FFEINTRIN_familyF90)
+ || (ffeintrin_specs_[spec].family == FFEINTRIN_familyMIL)
+ || (ffeintrin_specs_[spec].family == FFEINTRIN_familyASC))))
+ return TRUE;
+ return FALSE;
+}
+
+/* Return kind type of intrinsic implementation. See ffeintrin_basictype,
+ its sibling. */
+
+ffeinfoKindtype
+ffeintrin_kindtype (ffeintrinSpec spec)
+{
+ ffeintrinImp imp;
+ ffecomGfrt gfrt;
+
+ assert (spec < FFEINTRIN_spec);
+ imp = ffeintrin_specs_[spec].implementation;
+ assert (imp < FFEINTRIN_imp);
+
+ if (ffe_is_f2c ())
+ gfrt = ffeintrin_imps_[imp].gfrt_f2c;
+ else
+ gfrt = ffeintrin_imps_[imp].gfrt_gnu;
+
+ assert (gfrt != FFECOM_gfrt);
+
+ return ffecom_gfrt_kindtype (gfrt);
+}
+
+/* Return name of generic intrinsic. */
+
+char *
+ffeintrin_name_generic (ffeintrinGen gen)
+{
+ assert (gen < FFEINTRIN_gen);
+ return ffeintrin_gens_[gen].name;
+}
+
+/* Return name of intrinsic implementation. */
+
+char *
+ffeintrin_name_implementation (ffeintrinImp imp)
+{
+ assert (imp < FFEINTRIN_imp);
+ return ffeintrin_imps_[imp].name;
+}
+
+/* Return external/internal name of specific intrinsic. */
+
+char *
+ffeintrin_name_specific (ffeintrinSpec spec)
+{
+ assert (spec < FFEINTRIN_spec);
+ return ffeintrin_specs_[spec].name;
+}
+
+/* Return state of family. */
+
+ffeIntrinsicState
+ffeintrin_state_family (ffeintrinFamily family)
+{
+ ffeIntrinsicState state;
+
+ switch (family)
+ {
+ case FFEINTRIN_familyNONE:
+ return FFE_intrinsicstateDELETED;
+
+ case FFEINTRIN_familyF77:
+ return FFE_intrinsicstateENABLED;
+
+ case FFEINTRIN_familyASC:
+ state = ffe_intrinsic_state_f2c ();
+ state = ffe_state_max (state, ffe_intrinsic_state_f90 ());
+ return state;
+
+ case FFEINTRIN_familyMIL:
+ state = ffe_intrinsic_state_vxt ();
+ state = ffe_state_max (state, ffe_intrinsic_state_f90 ());
+ state = ffe_state_max (state, ffe_intrinsic_state_mil ());
+ return state;
+
+ case FFEINTRIN_familyGNU:
+ state = ffe_intrinsic_state_gnu ();
+ return state;
+
+ case FFEINTRIN_familyF90:
+ state = ffe_intrinsic_state_f90 ();
+ return state;
+
+ case FFEINTRIN_familyVXT:
+ state = ffe_intrinsic_state_vxt ();
+ return state;
+
+ case FFEINTRIN_familyFVZ:
+ state = ffe_intrinsic_state_f2c ();
+ state = ffe_state_max (state, ffe_intrinsic_state_vxt ());
+ return state;
+
+ case FFEINTRIN_familyF2C:
+ state = ffe_intrinsic_state_f2c ();
+ return state;
+
+ case FFEINTRIN_familyF2U:
+ state = ffe_intrinsic_state_unix ();
+ return state;
+
+ case FFEINTRIN_familyBADU77:
+ state = ffe_intrinsic_state_badu77 ();
+ return state;
+
+ default:
+ assert ("bad family" == NULL);
+ return FFE_intrinsicstateDELETED;
+ }
+}
diff --git a/contrib/gcc/f/intrin.def b/contrib/gcc/f/intrin.def
new file mode 100644
index 0000000..0c00dcc
--- /dev/null
+++ b/contrib/gcc/f/intrin.def
@@ -0,0 +1,3351 @@
+/* intrin.def -- Public #include File (module.h template V1.0)
+ The Free Software Foundation has released this file into the
+ public domain.
+
+ Owning Modules:
+ intrin.c
+
+ Modifications:
+*/
+
+/* Intrinsic names listed in alphabetical order, sorted by uppercase name.
+ This list is keyed to the names of intrinsics as seen in source code. */
+
+DEFNAME ("ABORT", "abort", "Abort", genNONE, specABORT) /* UNIX */
+DEFNAME ("ABS", "abs", "Abs", genNONE, specABS)
+DEFNAME ("ACCESS", "access", "Access", genNONE, specACCESS) /* UNIX */
+DEFNAME ("ACHAR", "achar", "AChar", genNONE, specACHAR) /* F90, F2C */
+DEFNAME ("ACOS", "acos", "ACos", genNONE, specACOS)
+DEFNAME ("ACOSD", "acosd", "ACosD", genNONE, specACOSD) /* VXT */
+DEFNAME ("ADJUSTL", "adjustl", "AdjustL", genNONE, specADJUSTL) /* F90 */
+DEFNAME ("ADJUSTR", "adjustr", "AdjustR", genNONE, specADJUSTR) /* F90 */
+DEFNAME ("AIMAG", "aimag", "AImag", genNONE, specAIMAG)
+DEFNAME ("AIMAX0", "aimax0", "AIMax0", genNONE, specAIMAX0) /* VXT */
+DEFNAME ("AIMIN0", "aimin0", "AIMin0", genNONE, specAIMIN0) /* VXT */
+DEFNAME ("AINT", "aint", "AInt", genNONE, specAINT)
+DEFNAME ("AJMAX0", "ajmax0", "AJMax0", genNONE, specAJMAX0) /* VXT */
+DEFNAME ("AJMIN0", "ajmin0", "AJMin0", genNONE, specAJMIN0) /* VXT */
+DEFNAME ("ALARM", "alarm", "Alarm", genNONE, specALARM) /* UNIX */
+DEFNAME ("ALL", "all", "All", genNONE, specALL) /* F90 */
+DEFNAME ("ALLOCATED", "allocated", "Allocated", genNONE, specALLOCATED) /* F90 */
+DEFNAME ("ALOG", "alog", "ALog", genNONE, specALOG)
+DEFNAME ("ALOG10", "alog10", "ALog10", genNONE, specALOG10)
+DEFNAME ("AMAX0", "amax0", "AMax0", genNONE, specAMAX0)
+DEFNAME ("AMAX1", "amax1", "AMax1", genNONE, specAMAX1)
+DEFNAME ("AMIN0", "amin0", "AMin0", genNONE, specAMIN0)
+DEFNAME ("AMIN1", "amin1", "AMin1", genNONE, specAMIN1)
+DEFNAME ("AMOD", "amod", "AMod", genNONE, specAMOD)
+DEFNAME ("AND", "and", "And", genNONE, specAND) /* F2C */
+DEFNAME ("ANINT", "anint", "ANInt", genNONE, specANINT)
+DEFNAME ("ANY", "any", "Any", genNONE, specANY) /* F90 */
+DEFNAME ("ASIN", "asin", "ASin", genNONE, specASIN)
+DEFNAME ("ASIND", "asind", "ASinD", genNONE, specASIND) /* VXT */
+DEFNAME ("ASSOCIATED", "associated", "Associated", genNONE, specASSOCIATED) /* F90 */
+DEFNAME ("ATAN", "atan", "ATan", genNONE, specATAN)
+DEFNAME ("ATAN2", "atan2", "ATan2", genNONE, specATAN2)
+DEFNAME ("ATAN2D", "atan2d", "ATan2D", genNONE, specATAN2D) /* VXT */
+DEFNAME ("ATAND", "atand", "ATanD", genNONE, specATAND) /* VXT */
+DEFNAME ("BESJ0", "besj0", "BesJ0", genNONE, specBESJ0) /* UNIX */
+DEFNAME ("BESJ1", "besj1", "BesJ1", genNONE, specBESJ1) /* UNIX */
+DEFNAME ("BESJN", "besjn", "BesJN", genNONE, specBESJN) /* UNIX */
+DEFNAME ("BESY0", "besy0", "BesY0", genNONE, specBESY0) /* UNIX */
+DEFNAME ("BESY1", "besy1", "BesY1", genNONE, specBESY1) /* UNIX */
+DEFNAME ("BESYN", "besyn", "BesYN", genNONE, specBESYN) /* UNIX */
+DEFNAME ("BITEST", "bitest", "BITest", genNONE, specBITEST) /* VXT */
+DEFNAME ("BIT_SIZE", "bit_size", "Bit_Size", genNONE, specBIT_SIZE) /* F90 */
+DEFNAME ("BJTEST", "bjtest", "BJTest", genNONE, specBJTEST) /* VXT */
+DEFNAME ("BTEST", "btest", "BTest", genNONE, specBTEST) /* F90, VXT */
+DEFNAME ("CABS", "cabs", "CAbs", genNONE, specCABS)
+DEFNAME ("CCOS", "ccos", "CCos", genNONE, specCCOS)
+DEFNAME ("CDABS", "cdabs", "CDAbs", genNONE, specCDABS) /* VXT */
+DEFNAME ("CDCOS", "cdcos", "CDCos", genNONE, specCDCOS) /* VXT */
+DEFNAME ("CDEXP", "cdexp", "CDExp", genNONE, specCDEXP) /* VXT */
+DEFNAME ("CDLOG", "cdlog", "CDLog", genNONE, specCDLOG) /* VXT */
+DEFNAME ("CDSIN", "cdsin", "CDSin", genNONE, specCDSIN) /* VXT */
+DEFNAME ("CDSQRT", "cdsqrt", "CDSqRt", genNONE, specCDSQRT) /* VXT */
+DEFNAME ("CEILING", "ceiling", "Ceiling", genNONE, specCEILING) /* F90 */
+DEFNAME ("CEXP", "cexp", "CExp", genNONE, specCEXP)
+DEFNAME ("CHAR", "char", "Char", genNONE, specCHAR)
+DEFNAME ("CHDIR", "chdir", "ChDir", genCHDIR, specNONE) /* UNIX */
+DEFNAME ("CHMOD", "chmod", "ChMod", genCHMOD, specNONE) /* UNIX */
+DEFNAME ("CLOG", "clog", "CLog", genNONE, specCLOG)
+DEFNAME ("CMPLX", "cmplx", "Cmplx", genNONE, specCMPLX)
+DEFNAME ("COMPLEX", "complex", "Complex", genNONE, specCOMPLEX)
+DEFNAME ("CONJG", "conjg", "Conjg", genNONE, specCONJG)
+DEFNAME ("COS", "cos", "Cos", genNONE, specCOS)
+DEFNAME ("COSD", "cosd", "CosD", genNONE, specCOSD) /* VXT */
+DEFNAME ("COSH", "cosh", "CosH", genNONE, specCOSH)
+DEFNAME ("COUNT", "count", "Count", genNONE, specCOUNT) /* F90 */
+DEFNAME ("CPU_TIME", "cpu_time", "CPU_Time", genNONE, specCPU_TIME) /* F95 */
+DEFNAME ("CSHIFT", "cshift", "CShift", genNONE, specCSHIFT) /* F90 */
+DEFNAME ("CSIN", "csin", "CSin", genNONE, specCSIN)
+DEFNAME ("CSQRT", "csqrt", "CSqRt", genNONE, specCSQRT)
+DEFNAME ("CTIME", "ctime", "CTime", genCTIME, specNONE) /* UNIX */
+DEFNAME ("DABS", "dabs", "DAbs", genNONE, specDABS)
+DEFNAME ("DACOS", "dacos", "DACos", genNONE, specDACOS)
+DEFNAME ("DACOSD", "dacosd", "DACosD", genNONE, specDACOSD) /* VXT */
+DEFNAME ("DASIN", "dasin", "DASin", genNONE, specDASIN)
+DEFNAME ("DASIND", "dasind", "DASinD", genNONE, specDASIND) /* VXT */
+DEFNAME ("DATAN", "datan", "DATan", genNONE, specDATAN)
+DEFNAME ("DATAN2", "datan2", "DATan2", genNONE, specDATAN2)
+DEFNAME ("DATAN2D", "datan2d", "DATan2D", genNONE, specDATAN2D) /* VXT */
+DEFNAME ("DATAND", "datand", "DATanD", genNONE, specDATAND) /* VXT */
+DEFNAME ("DATE", "date", "Date", genNONE, specDATE) /* VXT */
+DEFNAME ("DATE_AND_TIME", "date_and_time", "Date_and_Time", genNONE, specDATE_AND_TIME) /* F90 */
+DEFNAME ("DBESJ0", "dbesj0", "DbesJ0", genNONE, specDBESJ0) /* UNIX */
+DEFNAME ("DBESJ1", "dbesj1", "DbesJ1", genNONE, specDBESJ1) /* UNIX */
+DEFNAME ("DBESJN", "dbesjn", "DbesJN", genNONE, specDBESJN) /* UNIX */
+DEFNAME ("DBESY0", "dbesy0", "DbesY0", genNONE, specDBESY0) /* UNIX */
+DEFNAME ("DBESY1", "dbesy1", "DbesY1", genNONE, specDBESY1) /* UNIX */
+DEFNAME ("DBESYN", "dbesyn", "DbesYN", genNONE, specDBESYN) /* UNIX */
+DEFNAME ("DBLE", "dble", "Dble", genNONE, specDBLE)
+DEFNAME ("DBLEQ", "dbleq", "DbleQ", genNONE, specDBLEQ) /* VXT */
+DEFNAME ("DCMPLX", "dcmplx", "DCmplx", genNONE, specDCMPLX) /* F2C, VXT */
+DEFNAME ("DCONJG", "dconjg", "DConjg", genNONE, specDCONJG) /* F2C, VXT */
+DEFNAME ("DCOS", "dcos", "DCos", genNONE, specDCOS)
+DEFNAME ("DCOSD", "dcosd", "DCosD", genNONE, specDCOSD) /* VXT */
+DEFNAME ("DCOSH", "dcosh", "DCosH", genNONE, specDCOSH)
+DEFNAME ("DDIM", "ddim", "DDiM", genNONE, specDDIM)
+DEFNAME ("DERF", "derf", "DErF", genNONE, specDERF) /* UNIX */
+DEFNAME ("DERFC", "derfc", "DErFC", genNONE, specDERFC) /* UNIX */
+DEFNAME ("DEXP", "dexp", "DExp", genNONE, specDEXP)
+DEFNAME ("DFLOAT", "dfloat", "DFloat", genNONE, specDFLOAT) /* F2C, VXT */
+DEFNAME ("DFLOTI", "dfloti", "DFlotI", genNONE, specDFLOTI) /* VXT */
+DEFNAME ("DFLOTJ", "dflotj", "DFlotJ", genNONE, specDFLOTJ) /* VXT */
+DEFNAME ("DIGITS", "digits", "Digits", genNONE, specDIGITS) /* F90 */
+DEFNAME ("DIM", "dim", "DiM", genNONE, specDIM)
+DEFNAME ("DIMAG", "dimag", "DImag", genNONE, specDIMAG) /* F2C, VXT */
+DEFNAME ("DINT", "dint", "DInt", genNONE, specDINT)
+DEFNAME ("DLOG", "dlog", "DLog", genNONE, specDLOG)
+DEFNAME ("DLOG10", "dlog10", "DLog10", genNONE, specDLOG10)
+DEFNAME ("DMAX1", "dmax1", "DMax1", genNONE, specDMAX1)
+DEFNAME ("DMIN1", "dmin1", "DMin1", genNONE, specDMIN1)
+DEFNAME ("DMOD", "dmod", "DMod", genNONE, specDMOD)
+DEFNAME ("DNINT", "dnint", "DNInt", genNONE, specDNINT)
+DEFNAME ("DOT_PRODUCT", "dot_product", "Dot_Product", genNONE, specDOT_PRODUCT) /* F90 */
+DEFNAME ("DPROD", "dprod", "DProd", genNONE, specDPROD)
+DEFNAME ("DREAL", "dreal", "DReal", genNONE, specDREAL) /* VXT */
+DEFNAME ("DSIGN", "dsign", "DSign", genNONE, specDSIGN)
+DEFNAME ("DSIN", "dsin", "DSin", genNONE, specDSIN)
+DEFNAME ("DSIND", "dsind", "DSinD", genNONE, specDSIND) /* VXT */
+DEFNAME ("DSINH", "dsinh", "DSinH", genNONE, specDSINH)
+DEFNAME ("DSQRT", "dsqrt", "DSqRt", genNONE, specDSQRT)
+DEFNAME ("DTAN", "dtan", "DTan", genNONE, specDTAN)
+DEFNAME ("DTAND", "dtand", "DTanD", genNONE, specDTAND) /* VXT */
+DEFNAME ("DTANH", "dtanh", "DTanH", genNONE, specDTANH)
+DEFNAME ("DTIME", "dtime", "Dtime", genDTIME, specNONE) /* UNIX */
+DEFNAME ("EOSHIFT", "eoshift", "EOShift", genNONE, specEOSHIFT) /* F90 */
+DEFNAME ("EPSILON", "epsilon", "Epsilon", genNONE, specEPSILON) /* F90 */
+DEFNAME ("ERF", "erf", "ErF", genNONE, specERF) /* UNIX */
+DEFNAME ("ERFC", "erfc", "ErFC", genNONE, specERFC) /* UNIX */
+DEFNAME ("ETIME", "etime", "ETime", genETIME, specNONE) /* UNIX */
+DEFNAME ("EXIT", "exit", "Exit", genNONE, specEXIT) /* UNIX */
+DEFNAME ("EXP", "exp", "Exp", genNONE, specEXP)
+DEFNAME ("EXPONENT", "exponent", "Exponent", genNONE, specEXPONENT) /* F90 */
+DEFNAME ("FDATE", "fdate", "Fdate", genFDATE, specNONE) /* UNIX */
+DEFNAME ("FGET", "fget", "FGet", genFGET, specNONE) /* UNIX */
+DEFNAME ("FGETC", "fgetc", "FGetC", genFGETC, specNONE) /* UNIX */
+DEFNAME ("FLOAT", "float", "Float", genNONE, specFLOAT)
+DEFNAME ("FLOATI", "floati", "FloatI", genNONE, specFLOATI) /* VXT */
+DEFNAME ("FLOATJ", "floatj", "FloatJ", genNONE, specFLOATJ) /* VXT */
+DEFNAME ("FLOOR", "floor", "Floor", genNONE, specFLOOR) /* F90 */
+DEFNAME ("FLUSH", "flush", "Flush", genNONE, specFLUSH) /* UNIX */
+DEFNAME ("FNUM", "fnum", "FNum", genNONE, specFNUM) /* UNIX */
+DEFNAME ("FPABSP", "fpabsp", "FPAbsP", genFPABSP, specNONE) /* F2C */
+DEFNAME ("FPEXPN", "fpexpn", "FPExpn", genFPEXPN, specNONE) /* F2C */
+DEFNAME ("FPFRAC", "fpfrac", "FPFrac", genFPFRAC, specNONE) /* F2C */
+DEFNAME ("FPMAKE", "fpmake", "FPMake", genFPMAKE, specNONE) /* F2C */
+DEFNAME ("FPRRSP", "fprrsp", "FPRRSp", genFPRRSP, specNONE) /* F2C */
+DEFNAME ("FPSCAL", "fpscal", "FPScal", genFPSCAL, specNONE) /* F2C */
+DEFNAME ("FPUT", "fput", "FPut", genFPUT, specNONE) /* UNIX */
+DEFNAME ("FPUTC", "fputc", "FPutC", genFPUTC, specNONE) /* UNIX */
+DEFNAME ("FRACTION", "fraction", "Fraction", genNONE, specFRACTION) /* F90 */
+DEFNAME ("FSEEK", "fseek", "FSeek", genNONE, specFSEEK) /* UNIX */
+DEFNAME ("FSTAT", "fstat", "FStat", genFSTAT, specNONE) /* UNIX */
+DEFNAME ("FTELL", "ftell", "FTell", genFTELL, specNONE) /* UNIX */
+DEFNAME ("GERROR", "gerror", "GError", genNONE, specGERROR) /* UNIX */
+DEFNAME ("GETARG", "getarg", "GetArg", genNONE, specGETARG) /* UNIX */
+DEFNAME ("GETCWD", "getcwd", "GetCWD", genGETCWD, specNONE) /* UNIX */
+DEFNAME ("GETENV", "getenv", "GetEnv", genNONE, specGETENV) /* UNIX */
+DEFNAME ("GETGID", "getgid", "GetGId", genNONE, specGETGID) /* UNIX */
+DEFNAME ("GETLOG", "getlog", "GetLog", genNONE, specGETLOG) /* UNIX */
+DEFNAME ("GETPID", "getpid", "GetPId", genNONE, specGETPID) /* UNIX */
+DEFNAME ("GETUID", "getuid", "GetUId", genNONE, specGETUID) /* UNIX */
+DEFNAME ("GMTIME", "gmtime", "GMTime", genNONE, specGMTIME) /* UNIX */
+DEFNAME ("HOSTNM", "hostnm", "HostNm", genHOSTNM, specNONE) /* UNIX */
+DEFNAME ("HUGE", "huge", "Huge", genNONE, specHUGE) /* F90 */
+DEFNAME ("IABS", "iabs", "IAbs", genNONE, specIABS)
+DEFNAME ("IACHAR", "iachar", "IAChar", genNONE, specIACHAR) /* F90, F2C */
+DEFNAME ("IAND", "iand", "IAnd", genNONE, specIAND) /* F90, VXT */
+DEFNAME ("IARGC", "iargc", "IArgC", genNONE, specIARGC) /* UNIX */
+DEFNAME ("IBCLR", "ibclr", "IBClr", genNONE, specIBCLR) /* F90, VXT */
+DEFNAME ("IBITS", "ibits", "IBits", genNONE, specIBITS) /* F90, VXT */
+DEFNAME ("IBSET", "ibset", "IBSet", genNONE, specIBSET) /* F90, VXT */
+DEFNAME ("ICHAR", "ichar", "IChar", genNONE, specICHAR)
+DEFNAME ("IDATE", "idate", "IDate", genIDATE, specNONE) /* UNIX, VXT */
+DEFNAME ("IDIM", "idim", "IDiM", genNONE, specIDIM)
+DEFNAME ("IDINT", "idint", "IDInt", genNONE, specIDINT)
+DEFNAME ("IDNINT", "idnint", "IDNInt", genNONE, specIDNINT)
+DEFNAME ("IEOR", "ieor", "IEOr", genNONE, specIEOR) /* F90, VXT */
+DEFNAME ("IERRNO", "ierrno", "IErrNo", genNONE, specIERRNO) /* UNIX */
+DEFNAME ("IFIX", "ifix", "IFix", genNONE, specIFIX)
+DEFNAME ("IIABS", "iiabs", "IIAbs", genNONE, specIIABS) /* VXT */
+DEFNAME ("IIAND", "iiand", "IIAnd", genNONE, specIIAND) /* VXT */
+DEFNAME ("IIBCLR", "iibclr", "IIBClr", genNONE, specIIBCLR) /* VXT */
+DEFNAME ("IIBITS", "iibits", "IIBits", genNONE, specIIBITS) /* VXT */
+DEFNAME ("IIBSET", "iibset", "IIBSet", genNONE, specIIBSET) /* VXT */
+DEFNAME ("IIDIM", "iidim", "IIDiM", genNONE, specIIDIM) /* VXT */
+DEFNAME ("IIDINT", "iidint", "IIDInt", genNONE, specIIDINT) /* VXT */
+DEFNAME ("IIDNNT", "iidnnt", "IIDNnt", genNONE, specIIDNNT) /* VXT */
+DEFNAME ("IIEOR", "iieor", "IIEOr", genNONE, specIIEOR) /* VXT */
+DEFNAME ("IIFIX", "iifix", "IIFix", genNONE, specIIFIX) /* VXT */
+DEFNAME ("IINT", "iint", "IInt", genNONE, specIINT) /* VXT */
+DEFNAME ("IIOR", "iior", "IIOr", genNONE, specIIOR) /* VXT */
+DEFNAME ("IIQINT", "iiqint", "IIQint", genNONE, specIIQINT) /* VXT */
+DEFNAME ("IIQNNT", "iiqnnt", "IIQNnt", genNONE, specIIQNNT) /* VXT */
+DEFNAME ("IISHFT", "iishft", "IIShft", genNONE, specNONE) /* VXT */
+DEFNAME ("IISHFTC", "iishftc", "IIShftC", genNONE, specIISHFTC) /* VXT */
+DEFNAME ("IISIGN", "iisign", "IISign", genNONE, specIISIGN) /* VXT */
+DEFNAME ("IMAG", "imag", "Imag", genNONE, specIMAG) /* F2C */
+DEFNAME ("IMAGPART", "imagpart", "ImagPart", genNONE, specIMAGPART) /* GNU */
+DEFNAME ("IMAX0", "imax0", "IMax0", genNONE, specIMAX0) /* VXT */
+DEFNAME ("IMAX1", "imax1", "IMax1", genNONE, specIMAX1) /* VXT */
+DEFNAME ("IMIN0", "imin0", "IMin0", genNONE, specIMIN0) /* VXT */
+DEFNAME ("IMIN1", "imin1", "IMin1", genNONE, specIMIN1) /* VXT */
+DEFNAME ("IMOD", "imod", "IMod", genNONE, specIMOD) /* VXT */
+DEFNAME ("INDEX", "index", "Index", genNONE, specINDEX)
+DEFNAME ("ININT", "inint", "INInt", genNONE, specININT) /* VXT */
+DEFNAME ("INOT", "inot", "INot", genNONE, specINOT) /* VXT */
+DEFNAME ("INT", "int", "Int", genNONE, specINT)
+DEFNAME ("INT2", "int2", "Int2", genNONE, specINT2) /* MS */
+DEFNAME ("INT8", "int8", "Int8", genNONE, specINT8) /* GNU */
+DEFNAME ("IOR", "ior", "IOr", genNONE, specIOR) /* F90, VXT */
+DEFNAME ("IRAND", "irand", "IRand", genNONE, specIRAND) /* UNIX */
+DEFNAME ("ISATTY", "isatty", "IsaTty", genNONE, specISATTY) /* UNIX */
+DEFNAME ("ISHFT", "ishft", "IShft", genNONE, specISHFT) /* F90 */
+DEFNAME ("ISHFTC", "ishftc", "IShftC", genNONE, specISHFTC) /* F90, VXT */
+DEFNAME ("ISIGN", "isign", "ISign", genNONE, specISIGN)
+DEFNAME ("ITIME", "itime", "ITime", genNONE, specITIME) /* UNIX */
+DEFNAME ("IZEXT", "izext", "IZExt", genNONE, specIZEXT) /* VXT */
+DEFNAME ("JIABS", "jiabs", "JIAbs", genNONE, specJIABS) /* VXT */
+DEFNAME ("JIAND", "jiand", "JIAnd", genNONE, specJIAND) /* VXT */
+DEFNAME ("JIBCLR", "jibclr", "JIBClr", genNONE, specJIBCLR) /* VXT */
+DEFNAME ("JIBITS", "jibits", "JIBits", genNONE, specJIBITS) /* VXT */
+DEFNAME ("JIBSET", "jibset", "JIBSet", genNONE, specJIBSET) /* VXT */
+DEFNAME ("JIDIM", "jidim", "JIDiM", genNONE, specJIDIM) /* VXT */
+DEFNAME ("JIDINT", "jidint", "JIDInt", genNONE, specJIDINT) /* VXT */
+DEFNAME ("JIDNNT", "jidnnt", "JIDNnt", genNONE, specJIDNNT) /* VXT */
+DEFNAME ("JIEOR", "jieor", "JIEOr", genNONE, specJIEOR) /* VXT */
+DEFNAME ("JIFIX", "jifix", "JIFix", genNONE, specJIFIX) /* VXT */
+DEFNAME ("JINT", "jint", "JInt", genNONE, specJINT) /* VXT */
+DEFNAME ("JIOR", "jior", "JIOr", genNONE, specJIOR) /* VXT */
+DEFNAME ("JIQINT", "jiqint", "JIQint", genNONE, specJIQINT) /* VXT */
+DEFNAME ("JIQNNT", "jiqnnt", "JIQNnt", genNONE, specJIQNNT) /* VXT */
+DEFNAME ("JISHFT", "jishft", "JIShft", genNONE, specJISHFT) /* VXT */
+DEFNAME ("JISHFTC", "jishftc", "JIShftC", genNONE, specJISHFTC) /* VXT */
+DEFNAME ("JISIGN", "jisign", "JISign", genNONE, specJISIGN) /* VXT */
+DEFNAME ("JMAX0", "jmax0", "JMax0", genNONE, specJMAX0) /* VXT */
+DEFNAME ("JMAX1", "jmax1", "JMax1", genNONE, specJMAX1) /* VXT */
+DEFNAME ("JMIN0", "jmin0", "JMin0", genNONE, specJMIN0) /* VXT */
+DEFNAME ("JMIN1", "jmin1", "JMin1", genNONE, specJMIN1) /* VXT */
+DEFNAME ("JMOD", "jmod", "JMod", genNONE, specJMOD) /* VXT */
+DEFNAME ("JNINT", "jnint", "JNInt", genNONE, specJNINT) /* VXT */
+DEFNAME ("JNOT", "jnot", "JNot", genNONE, specJNOT) /* VXT */
+DEFNAME ("JZEXT", "jzext", "JZExt", genNONE, specJZEXT) /* VXT */
+DEFNAME ("KILL", "kill", "Kill", genKILL, specNONE) /* UNIX */
+DEFNAME ("KIND", "kind", "Kind", genNONE, specKIND) /* F90 */
+DEFNAME ("LBOUND", "lbound", "LBound", genNONE, specLBOUND) /* F90 */
+DEFNAME ("LEN", "len", "Len", genNONE, specLEN)
+DEFNAME ("LEN_TRIM", "len_trim", "Len_Trim", genNONE, specLEN_TRIM) /* F90 */
+DEFNAME ("LGE", "lge", "LGe", genNONE, specLGE)
+DEFNAME ("LGT", "lgt", "LGt", genNONE, specLGT)
+DEFNAME ("LINK", "link", "Link", genLINK, specNONE) /* UNIX */
+DEFNAME ("LLE", "lle", "LLe", genNONE, specLLE)
+DEFNAME ("LLT", "llt", "LLt", genNONE, specLLT)
+DEFNAME ("LNBLNK", "lnblnk", "LnBlnk", genNONE, specLNBLNK) /* UNIX */
+DEFNAME ("LOC", "loc", "Loc", genNONE, specLOC) /* VXT */
+DEFNAME ("LOG", "log", "Log", genNONE, specLOG)
+DEFNAME ("LOG10", "log10", "Log10", genNONE, specLOG10)
+DEFNAME ("LOGICAL", "logical", "Logical", genNONE, specLOGICAL) /* F90 */
+DEFNAME ("LONG", "long", "Long", genNONE, specLONG) /* UNIX */
+DEFNAME ("LSHIFT", "lshift", "LShift", genNONE, specLSHIFT) /* F2C */
+DEFNAME ("LSTAT", "lstat", "LStat", genLSTAT, specNONE) /* UNIX */
+DEFNAME ("LTIME", "ltime", "LTime", genNONE, specLTIME) /* UNIX */
+DEFNAME ("MATMUL", "matmul", "MatMul", genNONE, specMATMUL) /* F90 */
+DEFNAME ("MAX", "max", "Max", genNONE, specMAX)
+DEFNAME ("MAX0", "max0", "Max0", genNONE, specMAX0)
+DEFNAME ("MAX1", "max1", "Max1", genNONE, specMAX1)
+DEFNAME ("MAXEXPONENT", "maxexponent", "MaxExponent", genNONE, specMAXEXPONENT) /* F90 */
+DEFNAME ("MAXLOC", "maxloc", "MaxLoc", genNONE, specMAXLOC) /* F90 */
+DEFNAME ("MAXVAL", "maxval", "MaxVal", genNONE, specMAXVAL) /* F90 */
+DEFNAME ("MCLOCK", "mclock", "MClock", genNONE, specMCLOCK) /* UNIX */
+DEFNAME ("MCLOCK8", "mclock8", "MClock8", genNONE, specMCLOCK8) /* UNIX */
+DEFNAME ("MERGE", "merge", "Merge", genNONE, specMERGE) /* F90 */
+DEFNAME ("MIN", "min", "Min", genNONE, specMIN)
+DEFNAME ("MIN0", "min0", "Min0", genNONE, specMIN0)
+DEFNAME ("MIN1", "min1", "Min1", genNONE, specMIN1)
+DEFNAME ("MINEXPONENT", "minexponent", "MinExponent", genNONE, specMINEXPONENT) /* F90 */
+DEFNAME ("MINLOC", "minloc", "MinLoc", genNONE, specMINLOC) /* F90 */
+DEFNAME ("MINVAL", "minval", "MinVal", genNONE, specMINVAL) /* F90 */
+DEFNAME ("MOD", "mod", "Mod", genNONE, specMOD)
+DEFNAME ("MODULO", "modulo", "Modulo", genNONE, specMODULO) /* F90 */
+DEFNAME ("MVBITS", "mvbits", "MvBits", genNONE, specMVBITS) /* F90 */
+DEFNAME ("NEAREST", "nearest", "Nearest", genNONE, specNEAREST) /* F90 */
+DEFNAME ("NINT", "nint", "NInt", genNONE, specNINT)
+DEFNAME ("NOT", "not", "Not", genNONE, specNOT) /* F2C, F90, VXT */
+DEFNAME ("OR", "or", "Or", genNONE, specOR) /* F2C */
+DEFNAME ("PACK", "pack", "Pack", genNONE, specPACK) /* F90 */
+DEFNAME ("PERROR", "perror", "PError", genNONE, specPERROR) /* UNIX */
+DEFNAME ("PRECISION", "precision", "Precision", genNONE, specPRECISION) /* F90 */
+DEFNAME ("PRESENT", "present", "Present", genNONE, specPRESENT) /* F90 */
+DEFNAME ("PRODUCT", "product", "Product", genNONE, specPRODUCT) /* F90 */
+DEFNAME ("QABS", "qabs", "QAbs", genNONE, specQABS) /* VXT */
+DEFNAME ("QACOS", "qacos", "QACos", genNONE, specQACOS) /* VXT */
+DEFNAME ("QACOSD", "qacosd", "QACosD", genNONE, specQACOSD) /* VXT */
+DEFNAME ("QASIN", "qasin", "QASin", genNONE, specQASIN) /* VXT */
+DEFNAME ("QASIND", "qasind", "QASinD", genNONE, specQASIND) /* VXT */
+DEFNAME ("QATAN", "qatan", "QATan", genNONE, specQATAN) /* VXT */
+DEFNAME ("QATAN2", "qatan2", "QATan2", genNONE, specQATAN2) /* VXT */
+DEFNAME ("QATAN2D", "qatan2d", "QATan2D", genNONE, specQATAN2D) /* VXT */
+DEFNAME ("QATAND", "qatand", "QATanD", genNONE, specQATAND) /* VXT */
+DEFNAME ("QCOS", "qcos", "QCos", genNONE, specQCOS) /* VXT */
+DEFNAME ("QCOSD", "qcosd", "QCosD", genNONE, specQCOSD) /* VXT */
+DEFNAME ("QCOSH", "qcosh", "QCosH", genNONE, specQCOSH) /* VXT */
+DEFNAME ("QDIM", "qdim", "QDiM", genNONE, specQDIM) /* VXT */
+DEFNAME ("QEXP", "qexp", "QExp", genNONE, specQEXP) /* VXT */
+DEFNAME ("QEXT", "qext", "QExt", genNONE, specQEXT) /* VXT */
+DEFNAME ("QEXTD", "qextd", "QExtD", genNONE, specQEXTD) /* VXT */
+DEFNAME ("QFLOAT", "qfloat", "QFloat", genNONE, specQFLOAT) /* VXT */
+DEFNAME ("QINT", "qint", "QInt", genNONE, specQINT) /* VXT */
+DEFNAME ("QLOG", "qlog", "QLog", genNONE, specQLOG) /* VXT */
+DEFNAME ("QLOG10", "qlog10", "QLog10", genNONE, specQLOG10) /* VXT */
+DEFNAME ("QMAX1", "qmax1", "QMax1", genNONE, specQMAX1) /* VXT */
+DEFNAME ("QMIN1", "qmin1", "QMin1", genNONE, specQMIN1) /* VXT */
+DEFNAME ("QMOD", "qmod", "QMod", genNONE, specQMOD) /* VXT */
+DEFNAME ("QNINT", "qnint", "QNInt", genNONE, specQNINT) /* VXT */
+DEFNAME ("QSIN", "qsin", "QSin", genNONE, specQSIN) /* VXT */
+DEFNAME ("QSIND", "qsind", "QSinD", genNONE, specQSIND) /* VXT */
+DEFNAME ("QSINH", "qsinh", "QSinH", genNONE, specQSINH) /* VXT */
+DEFNAME ("QSQRT", "qsqrt", "QSqRt", genNONE, specQSQRT) /* VXT */
+DEFNAME ("QTAN", "qtan", "QTan", genNONE, specQTAN) /* VXT */
+DEFNAME ("QTAND", "qtand", "QTanD", genNONE, specQTAND) /* VXT */
+DEFNAME ("QTANH", "qtanh", "QTanH", genNONE, specQTANH) /* VXT */
+DEFNAME ("RADIX", "radix", "Radix", genNONE, specRADIX) /* F90 */
+DEFNAME ("RAND", "rand", "Rand", genNONE, specRAND) /* UNIX */
+DEFNAME ("RANDOM_NUMBER", "random_number", "Random_Number", genNONE, specRANDOM_NUMBER) /* F90 */
+DEFNAME ("RANDOM_SEED", "random_seed", "Random_Seed", genNONE, specRANDOM_SEED) /* F90 */
+DEFNAME ("RANGE", "range", "Range", genNONE, specRANGE) /* F90 */
+DEFNAME ("REAL", "real", "Real", genNONE, specREAL)
+DEFNAME ("REALPART", "realpart", "RealPart", genNONE, specREALPART) /* GNU */
+DEFNAME ("RENAME", "rename", "Rename", genRENAME, specNONE) /* UNIX */
+DEFNAME ("REPEAT", "repeat", "Repeat", genNONE, specREPEAT) /* F90 */
+DEFNAME ("RESHAPE", "reshape", "Reshape", genNONE, specRESHAPE) /* F90 */
+DEFNAME ("RRSPACING", "rrspacing", "RRSpacing", genNONE, specRRSPACING) /* F90 */
+DEFNAME ("RSHIFT", "rshift", "RShift", genNONE, specRSHIFT) /* F2C */
+DEFNAME ("SCALE", "scale", "Scale", genNONE, specSCALE) /* F90 */
+DEFNAME ("SCAN", "scan", "Scan", genNONE, specSCAN) /* F90 */
+DEFNAME ("SECNDS", "secnds", "Secnds", genNONE, specSECNDS) /* VXT */
+DEFNAME ("SECOND", "second", "Second", genSECOND, specNONE) /* UNIX */
+DEFNAME ("SELECTED_INT_KIND", "selected_int_kind", "Selected_Int_Kind", genNONE, specSEL_INT_KIND) /* F90 */
+DEFNAME ("SELECTED_REAL_KIND", "selected_real_kind", "Selected_Real_Kind", genNONE, specSEL_REAL_KIND) /* F90 */
+DEFNAME ("SET_EXPONENT", "set_exponent", "Set_Exponent", genNONE, specSET_EXPONENT) /* F90 */
+DEFNAME ("SHAPE", "shape", "Shape", genNONE, specSHAPE) /* F90 */
+DEFNAME ("SHORT", "short", "Short", genNONE, specSHORT) /* UNIX */
+DEFNAME ("SIGN", "sign", "Sign", genNONE, specSIGN)
+DEFNAME ("SIGNAL", "signal", "Signal", genSIGNAL, specNONE) /* UNIX */
+DEFNAME ("SIN", "sin", "Sin", genNONE, specSIN)
+DEFNAME ("SIND", "sind", "SinD", genNONE, specSIND) /* VXT */
+DEFNAME ("SINH", "sinh", "SinH", genNONE, specSINH)
+DEFNAME ("SLEEP", "sleep", "Sleep", genNONE, specSLEEP) /* UNIX */
+DEFNAME ("SNGL", "sngl", "Sngl", genNONE, specSNGL)
+DEFNAME ("SNGLQ", "snglq", "SnglQ", genNONE, specSNGLQ) /* VXT */
+DEFNAME ("SPACING", "spacing", "Spacing", genNONE, specSPACING) /* F90 */
+DEFNAME ("SPREAD", "spread", "Spread", genNONE, specSPREAD) /* F90 */
+DEFNAME ("SQRT", "sqrt", "SqRt", genNONE, specSQRT)
+DEFNAME ("SRAND", "srand", "SRand", genNONE, specSRAND) /* UNIX */
+DEFNAME ("STAT", "stat", "Stat", genSTAT, specNONE) /* UNIX */
+DEFNAME ("SUM", "sum", "Sum", genNONE, specSUM) /* F90 */
+DEFNAME ("SYMLNK", "symlnk", "SymLnk", genSYMLNK, specNONE) /* UNIX */
+DEFNAME ("SYSTEM", "system", "System", genSYSTEM, specNONE) /* UNIX */
+DEFNAME ("SYSTEM_CLOCK", "system_clock", "System_Clock", genNONE, specSYSTEM_CLOCK) /* F90 */
+DEFNAME ("TAN", "tan", "Tan", genNONE, specTAN)
+DEFNAME ("TAND", "tand", "TanD", genNONE, specTAND) /* VXT */
+DEFNAME ("TANH", "tanh", "TanH", genNONE, specTANH)
+DEFNAME ("TIME", "time", "Time", genTIME, specNONE) /* UNIX, VXT */
+DEFNAME ("TIME8", "time8", "Time8", genNONE, specTIME8) /* UNIX */
+DEFNAME ("TINY", "tiny", "Tiny", genNONE, specTINY) /* F90 */
+DEFNAME ("TRANSFER", "transfer", "Transfer", genNONE, specTRANSFER) /* F90 */
+DEFNAME ("TRANSPOSE", "transpose", "Transpose", genNONE, specTRANSPOSE) /* F90 */
+DEFNAME ("TRIM", "trim", "Trim", genNONE, specTRIM) /* F90 */
+DEFNAME ("TTYNAM", "ttynam", "TtyNam", genTTYNAM, specNONE) /* UNIX */
+DEFNAME ("UBOUND", "ubound", "UBound", genNONE, specUBOUND) /* F90 */
+DEFNAME ("UMASK", "umask", "UMask", genUMASK, specNONE) /* UNIX */
+DEFNAME ("UNLINK", "unlink", "Unlink", genUNLINK, specNONE) /* UNIX */
+DEFNAME ("UNPACK", "unpack", "Unpack", genNONE, specUNPACK) /* F90 */
+DEFNAME ("VERIFY", "verify", "Verify", genNONE, specVERIFY) /* F90 */
+DEFNAME ("XOR", "xor", "XOr", genNONE, specXOR) /* F2C */
+DEFNAME ("ZABS", "zabs", "ZAbs", genNONE, specZABS) /* F2C */
+DEFNAME ("ZCOS", "zcos", "ZCos", genNONE, specZCOS) /* F2C */
+DEFNAME ("ZEXP", "zexp", "ZExp", genNONE, specZEXP) /* F2C */
+DEFNAME ("ZEXT", "zext", "ZExt", genNONE, specZEXT) /* VXT */
+DEFNAME ("ZLOG", "zlog", "ZLog", genNONE, specZLOG) /* F2C */
+DEFNAME ("ZSIN", "zsin", "ZSin", genNONE, specZSIN) /* F2C */
+DEFNAME ("ZSQRT", "zsqrt", "ZSqRt", genNONE, specZSQRT) /* F2C */
+
+/* Internally generic intrinsics.
+
+ Should properly be called "mapped" intrinsics. These are intrinsics
+ that map to one or more generally different implementations -- e.g.
+ that have differing interpretations depending on the Fortran dialect
+ being used. Also, this includes the placeholder intrinsics that
+ have no specific versions, but we want to reserve the names for now. */
+
+DEFGEN (CTIME, "CTIME", /* UNIX */
+ FFEINTRIN_specCTIME_subr,
+ FFEINTRIN_specCTIME_func
+ )
+DEFGEN (CHDIR, "CHDIR", /* UNIX */
+ FFEINTRIN_specCHDIR_subr,
+ FFEINTRIN_specCHDIR_func
+ )
+DEFGEN (CHMOD, "CHMOD", /* UNIX */
+ FFEINTRIN_specCHMOD_subr,
+ FFEINTRIN_specCHMOD_func
+ )
+DEFGEN (DTIME, "DTIME", /* UNIX */
+ FFEINTRIN_specDTIME_subr,
+ FFEINTRIN_specDTIME_func
+ )
+DEFGEN (ETIME, "ETIME", /* UNIX */
+ FFEINTRIN_specETIME_subr,
+ FFEINTRIN_specETIME_func
+ )
+DEFGEN (FDATE, "FDATE", /* UNIX */
+ FFEINTRIN_specFDATE_subr,
+ FFEINTRIN_specFDATE_func
+ )
+DEFGEN (FGET, "FGET", /* UNIX */
+ FFEINTRIN_specFGET_subr,
+ FFEINTRIN_specFGET_func
+ )
+DEFGEN (FGETC, "FGETC", /* UNIX */
+ FFEINTRIN_specFGETC_subr,
+ FFEINTRIN_specFGETC_func
+ )
+DEFGEN (FPABSP, "FPABSP", /* F2C */
+ FFEINTRIN_specNONE,
+ FFEINTRIN_specNONE
+ )
+DEFGEN (FPEXPN, "FPEXPN", /* F2C */
+ FFEINTRIN_specNONE,
+ FFEINTRIN_specNONE
+ )
+DEFGEN (FPFRAC, "FPFRAC", /* F2C */
+ FFEINTRIN_specNONE,
+ FFEINTRIN_specNONE
+ )
+DEFGEN (FPMAKE, "FPMAKE", /* F2C */
+ FFEINTRIN_specNONE,
+ FFEINTRIN_specNONE
+ )
+DEFGEN (FPRRSP, "FPRRSP", /* F2C */
+ FFEINTRIN_specNONE,
+ FFEINTRIN_specNONE
+ )
+DEFGEN (FPSCAL, "FPSCAL", /* F2C */
+ FFEINTRIN_specNONE,
+ FFEINTRIN_specNONE
+ )
+DEFGEN (FPUT, "FPUT", /* UNIX */
+ FFEINTRIN_specFPUT_subr,
+ FFEINTRIN_specFPUT_func
+ )
+DEFGEN (FPUTC, "FPUTC", /* UNIX */
+ FFEINTRIN_specFPUTC_subr,
+ FFEINTRIN_specFPUTC_func
+ )
+DEFGEN (FSTAT, "FSTAT", /* UNIX */
+ FFEINTRIN_specFSTAT_subr,
+ FFEINTRIN_specFSTAT_func
+ )
+DEFGEN (FTELL, "FTELL", /* UNIX */
+ FFEINTRIN_specFTELL_subr,
+ FFEINTRIN_specFTELL_func
+ )
+DEFGEN (GETCWD, "GETCWD", /* UNIX */
+ FFEINTRIN_specGETCWD_subr,
+ FFEINTRIN_specGETCWD_func
+ )
+DEFGEN (HOSTNM, "HOSTNM", /* UNIX */
+ FFEINTRIN_specHOSTNM_subr,
+ FFEINTRIN_specHOSTNM_func
+ )
+DEFGEN (IDATE, "IDATE", /* UNIX/VXT */
+ FFEINTRIN_specIDATE_unix,
+ FFEINTRIN_specIDATE_vxt
+ )
+DEFGEN (KILL, "KILL", /* UNIX */
+ FFEINTRIN_specKILL_subr,
+ FFEINTRIN_specKILL_func
+ )
+DEFGEN (LINK, "LINK", /* UNIX */
+ FFEINTRIN_specLINK_subr,
+ FFEINTRIN_specLINK_func
+ )
+DEFGEN (LSTAT, "LSTAT", /* UNIX */
+ FFEINTRIN_specLSTAT_subr,
+ FFEINTRIN_specLSTAT_func
+ )
+DEFGEN (RENAME, "RENAME", /* UNIX */
+ FFEINTRIN_specRENAME_subr,
+ FFEINTRIN_specRENAME_func
+ )
+DEFGEN (SECOND, "SECOND", /* UNIX/CRAY */
+ FFEINTRIN_specSECOND_func,
+ FFEINTRIN_specSECOND_subr
+ )
+DEFGEN (SIGNAL, "SIGNAL", /* UNIX */
+ FFEINTRIN_specSIGNAL_subr,
+ FFEINTRIN_specSIGNAL_func
+ )
+DEFGEN (STAT, "STAT", /* UNIX */
+ FFEINTRIN_specSTAT_subr,
+ FFEINTRIN_specSTAT_func
+ )
+DEFGEN (SYMLNK, "SYMLNK", /* UNIX */
+ FFEINTRIN_specSYMLNK_subr,
+ FFEINTRIN_specSYMLNK_func
+ )
+DEFGEN (SYSTEM, "SYSTEM", /* UNIX */
+ FFEINTRIN_specSYSTEM_subr,
+ FFEINTRIN_specSYSTEM_func
+ )
+DEFGEN (TIME, "TIME", /* UNIX/VXT */
+ FFEINTRIN_specTIME_unix,
+ FFEINTRIN_specTIME_vxt
+ )
+DEFGEN (TTYNAM, "TTYNAM", /* UNIX/VXT */
+ FFEINTRIN_specTTYNAM_subr,
+ FFEINTRIN_specTTYNAM_func
+ )
+DEFGEN (UMASK, "UMASK", /* UNIX */
+ FFEINTRIN_specUMASK_subr,
+ FFEINTRIN_specUMASK_func
+ )
+DEFGEN (UNLINK, "UNLINK", /* UNIX */
+ FFEINTRIN_specUNLINK_subr,
+ FFEINTRIN_specUNLINK_func
+ )
+DEFGEN (NONE, "none",
+ FFEINTRIN_specNONE,
+ FFEINTRIN_specNONE
+ )
+
+/* Specific intrinsic information.
+
+ Currently this list starts with the list of F77-standard intrinsics
+ in alphabetical order, then continues with the list of all other
+ intrinsics.
+
+ The second boolean argument specifies whether the intrinsic is
+ allowed by the standard to be passed as an actual argument. */
+
+DEFSPEC (ABS,
+ "ABS",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impABS
+ )
+DEFSPEC (ACOS,
+ "ACOS",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impACOS
+ )
+DEFSPEC (AIMAG,
+ "AIMAG",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impAIMAG
+ )
+DEFSPEC (AINT,
+ "AINT",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impAINT
+ )
+DEFSPEC (ALOG,
+ "ALOG",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impALOG
+ )
+DEFSPEC (ALOG10,
+ "ALOG10",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impALOG10
+ )
+DEFSPEC (AMAX0,
+ "AMAX0",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impAMAX0
+ )
+DEFSPEC (AMAX1,
+ "AMAX1",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impAMAX1
+ )
+DEFSPEC (AMIN0,
+ "AMIN0",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impAMIN0
+ )
+DEFSPEC (AMIN1,
+ "AMIN1",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impAMIN1
+ )
+DEFSPEC (AMOD,
+ "AMOD",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impAMOD
+ )
+DEFSPEC (ANINT,
+ "ANINT",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impANINT
+ )
+DEFSPEC (ASIN,
+ "ASIN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impASIN
+ )
+DEFSPEC (ATAN,
+ "ATAN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impATAN
+ )
+DEFSPEC (ATAN2,
+ "ATAN2",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impATAN2
+ )
+DEFSPEC (CABS,
+ "CABS",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCABS
+ )
+DEFSPEC (CCOS,
+ "CCOS",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCCOS
+ )
+DEFSPEC (CEXP,
+ "CEXP",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCEXP
+ )
+DEFSPEC (CHAR,
+ "CHAR",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCHAR
+ )
+DEFSPEC (CLOG,
+ "CLOG",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCLOG
+ )
+DEFSPEC (CMPLX,
+ "CMPLX",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCMPLX
+ )
+DEFSPEC (CONJG,
+ "CONJG",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCONJG
+ )
+DEFSPEC (COS,
+ "COS",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCOS
+ )
+DEFSPEC (COSH,
+ "COSH",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCOSH
+ )
+DEFSPEC (CSIN,
+ "CSIN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCSIN
+ )
+DEFSPEC (CSQRT,
+ "CSQRT",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impCSQRT
+ )
+DEFSPEC (DABS,
+ "DABS",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDABS
+ )
+DEFSPEC (DACOS,
+ "DACOS",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDACOS
+ )
+DEFSPEC (DASIN,
+ "DASIN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDASIN
+ )
+DEFSPEC (DATAN,
+ "DATAN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDATAN
+ )
+DEFSPEC (DATAN2,
+ "DATAN2",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDATAN2
+ )
+DEFSPEC (DBLE,
+ "DBLE",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDBLE
+ )
+DEFSPEC (DCOS,
+ "DCOS",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDCOS
+ )
+DEFSPEC (DCOSH,
+ "DCOSH",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDCOSH
+ )
+DEFSPEC (DDIM,
+ "DDIM",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDDIM
+ )
+DEFSPEC (DEXP,
+ "DEXP",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDEXP
+ )
+DEFSPEC (DIM,
+ "DIM",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDIM
+ )
+DEFSPEC (DINT,
+ "DINT",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDINT
+ )
+DEFSPEC (DLOG,
+ "DLOG",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDLOG
+ )
+DEFSPEC (DLOG10,
+ "DLOG10",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDLOG10
+ )
+DEFSPEC (DMAX1,
+ "DMAX1",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDMAX1
+ )
+DEFSPEC (DMIN1,
+ "DMIN1",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDMIN1
+ )
+DEFSPEC (DMOD,
+ "DMOD",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDMOD
+ )
+DEFSPEC (DNINT,
+ "DNINT",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDNINT
+ )
+DEFSPEC (DPROD,
+ "DPROD",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDPROD
+ )
+DEFSPEC (DSIGN,
+ "DSIGN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDSIGN
+ )
+DEFSPEC (DSIN,
+ "DSIN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDSIN
+ )
+DEFSPEC (DSINH,
+ "DSINH",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDSINH
+ )
+DEFSPEC (DSQRT,
+ "DSQRT",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDSQRT
+ )
+DEFSPEC (DTAN,
+ "DTAN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDTAN
+ )
+DEFSPEC (DTANH,
+ "DTANH",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impDTANH
+ )
+DEFSPEC (EXP,
+ "EXP",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impEXP
+ )
+DEFSPEC (FLOAT,
+ "FLOAT",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impFLOAT
+ )
+DEFSPEC (IABS,
+ "IABS",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impIABS
+ )
+DEFSPEC (ICHAR,
+ "ICHAR",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impICHAR
+ )
+DEFSPEC (IDIM,
+ "IDIM",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impIDIM
+ )
+DEFSPEC (IDINT,
+ "IDINT",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impIDINT
+ )
+DEFSPEC (IDNINT,
+ "IDNINT",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impIDNINT
+ )
+DEFSPEC (IFIX,
+ "IFIX",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impIFIX
+ )
+DEFSPEC (INDEX,
+ "INDEX",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impINDEX
+ )
+DEFSPEC (INT,
+ "INT",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impINT
+ )
+DEFSPEC (ISIGN,
+ "ISIGN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impISIGN
+ )
+DEFSPEC (LEN,
+ "LEN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impLEN
+ )
+DEFSPEC (LGE,
+ "LGE",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impLGE
+ )
+DEFSPEC (LGT,
+ "LGT",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impLGT
+ )
+DEFSPEC (LLE,
+ "LLE",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impLLE
+ )
+DEFSPEC (LLT,
+ "LLT",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impLLT
+ )
+DEFSPEC (LOG,
+ "LOG",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impLOG
+ )
+DEFSPEC (LOG10,
+ "LOG10",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impLOG10
+ )
+DEFSPEC (MAX,
+ "MAX",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impMAX
+ )
+DEFSPEC (MAX0,
+ "MAX0",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impMAX0
+ )
+DEFSPEC (MAX1,
+ "MAX1",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impMAX1
+ )
+DEFSPEC (MIN,
+ "MIN",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impMIN
+ )
+DEFSPEC (MIN0,
+ "MIN0",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impMIN0
+ )
+DEFSPEC (MIN1,
+ "MIN1",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impMIN1
+ )
+DEFSPEC (MOD,
+ "MOD",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impMOD
+ )
+DEFSPEC (NINT,
+ "NINT",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impNINT
+ )
+DEFSPEC (REAL,
+ "REAL",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impREAL
+ )
+DEFSPEC (SIGN,
+ "SIGN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impSIGN
+ )
+DEFSPEC (SIN,
+ "SIN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impSIN
+ )
+DEFSPEC (SINH,
+ "SINH",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impSINH
+ )
+DEFSPEC (SNGL,
+ "SNGL",
+ FALSE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impSNGL
+ )
+DEFSPEC (SQRT,
+ "SQRT",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impSQRT
+ )
+DEFSPEC (TAN,
+ "TAN",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impTAN
+ )
+DEFSPEC (TANH,
+ "TANH",
+ TRUE,
+ FFEINTRIN_familyF77,
+ FFEINTRIN_impTANH
+ )
+
+DEFSPEC (ABORT,
+ "ABORT",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impABORT
+ )
+DEFSPEC (ACCESS,
+ "ACCESS",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impACCESS
+)
+DEFSPEC (ACHAR,
+ "ACHAR",
+ FALSE,
+ FFEINTRIN_familyASC,
+ FFEINTRIN_impACHAR
+ )
+DEFSPEC (ACOSD,
+ "ACOSD",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ADJUSTL,
+ "ADJUSTL",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ADJUSTR,
+ "ADJUSTR",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (AIMAX0,
+ "AIMAX0",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (AIMIN0,
+ "AIMIN0",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (AJMAX0,
+ "AJMAX0",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (AJMIN0,
+ "AJMIN0",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ALARM,
+ "ALARM",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impALARM
+ )
+DEFSPEC (ALL,
+ "ALL",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ALLOCATED,
+ "ALLOCATED",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (AND,
+ "AND",
+ FALSE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impAND
+ )
+DEFSPEC (ANY,
+ "ANY",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ASIND,
+ "ASIND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ASSOCIATED,
+ "ASSOCIATED",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ATAN2D,
+ "ATAN2D",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ATAND,
+ "ATAND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (BESJ0,
+ "BESJ0",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impBESJ0
+)
+DEFSPEC (BESJ1,
+ "BESJ1",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impBESJ1
+)
+DEFSPEC (BESJN,
+ "BESJN",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impBESJN
+)
+DEFSPEC (BESY0,
+ "BESY0",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impBESY0
+)
+DEFSPEC (BESY1,
+ "BESY1",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impBESY1
+)
+DEFSPEC (BESYN,
+ "BESYN",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impBESYN
+)
+DEFSPEC (BIT_SIZE,
+ "BIT_SIZE",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impBIT_SIZE
+ )
+DEFSPEC (BITEST,
+ "BITEST",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (BJTEST,
+ "BJTEST",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (BTEST,
+ "BTEST",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impBTEST
+ )
+DEFSPEC (CDABS,
+ "CDABS",
+ TRUE,
+ FFEINTRIN_familyFVZ,
+ FFEINTRIN_impCDABS
+ )
+DEFSPEC (CDCOS,
+ "CDCOS",
+ TRUE,
+ FFEINTRIN_familyFVZ,
+ FFEINTRIN_impCDCOS
+ )
+DEFSPEC (CDEXP,
+ "CDEXP",
+ TRUE,
+ FFEINTRIN_familyFVZ,
+ FFEINTRIN_impCDEXP
+ )
+DEFSPEC (CDLOG,
+ "CDLOG",
+ TRUE,
+ FFEINTRIN_familyFVZ,
+ FFEINTRIN_impCDLOG
+ )
+DEFSPEC (CDSIN,
+ "CDSIN",
+ TRUE,
+ FFEINTRIN_familyFVZ,
+ FFEINTRIN_impCDSIN
+ )
+DEFSPEC (CDSQRT,
+ "CDSQRT",
+ TRUE,
+ FFEINTRIN_familyFVZ,
+ FFEINTRIN_impCDSQRT
+ )
+DEFSPEC (CEILING,
+ "CEILING",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (CHDIR_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impCHDIR_func
+)
+DEFSPEC (CHDIR_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impCHDIR_subr
+)
+DEFSPEC (CHMOD_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impCHMOD_func
+)
+DEFSPEC (CHMOD_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impCHMOD_subr
+)
+DEFSPEC (COMPLEX,
+ "COMPLEX",
+ FALSE,
+ FFEINTRIN_familyGNU,
+ FFEINTRIN_impCOMPLEX
+ )
+DEFSPEC (COSD,
+ "COSD",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (COUNT,
+ "COUNT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (CSHIFT,
+ "CSHIFT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (CPU_TIME,
+ "CPU_TIME",
+ FALSE,
+ FFEINTRIN_familyF95,
+ FFEINTRIN_impCPU_TIME
+)
+DEFSPEC (CTIME_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impCTIME_func
+)
+DEFSPEC (CTIME_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impCTIME_subr
+)
+DEFSPEC (DACOSD,
+ "DACOSD",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DASIND,
+ "DASIND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DATAN2D,
+ "DATAN2D",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DATAND,
+ "DATAND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DATE,
+ "DATE",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impDATE
+)
+DEFSPEC (DATE_AND_TIME,
+ "DATE_AND_TIME",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impDATE_AND_TIME
+ )
+DEFSPEC (DBESJ0,
+ "DBESJ0",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impDBESJ0
+)
+DEFSPEC (DBESJ1,
+ "DBESJ1",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impDBESJ1
+)
+DEFSPEC (DBESJN,
+ "DBESJN",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impDBESJN
+)
+DEFSPEC (DBESY0,
+ "DBESY0",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impDBESY0
+)
+DEFSPEC (DBESY1,
+ "DBESY1",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impDBESY1
+)
+DEFSPEC (DBESYN,
+ "DBESYN",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impDBESYN
+)
+DEFSPEC (DBLEQ,
+ "DBLEQ",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DCMPLX,
+ "DCMPLX",
+ FALSE,
+ FFEINTRIN_familyFVZ,
+ FFEINTRIN_impDCMPLX
+ )
+DEFSPEC (DCONJG,
+ "DCONJG",
+ TRUE,
+ FFEINTRIN_familyFVZ,
+ FFEINTRIN_impDCONJG
+ )
+DEFSPEC (DCOSD,
+ "DCOSD",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DERF,
+ "DERF",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impDERF
+ )
+DEFSPEC (DERFC,
+ "DERFC",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impDERFC
+ )
+DEFSPEC (DFLOAT,
+ "DFLOAT",
+ FALSE,
+ FFEINTRIN_familyFVZ,
+ FFEINTRIN_impDFLOAT
+ )
+DEFSPEC (DFLOTI,
+ "DFLOTI",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DFLOTJ,
+ "DFLOTJ",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DIGITS,
+ "DIGITS",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DIMAG,
+ "DIMAG",
+ TRUE,
+ FFEINTRIN_familyFVZ,
+ FFEINTRIN_impDIMAG
+ )
+DEFSPEC (DOT_PRODUCT,
+ "DOT_PRODUCT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DREAL,
+ "DREAL",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impDREAL
+ )
+DEFSPEC (DSIND,
+ "DSIND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DTAND,
+ "DTAND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (DTIME_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impDTIME_func
+)
+DEFSPEC (DTIME_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impDTIME_subr
+)
+DEFSPEC (EOSHIFT,
+ "EOSHIFT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (EPSILON,
+ "EPSILON",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ERF,
+ "ERF",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impERF
+ )
+DEFSPEC (ERFC,
+ "ERFC",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impERFC
+ )
+DEFSPEC (ETIME_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impETIME_func
+)
+DEFSPEC (ETIME_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impETIME_subr
+)
+DEFSPEC (EXIT,
+ "EXIT",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impEXIT
+ )
+DEFSPEC (EXPONENT,
+ "EXPONENT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (FDATE_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFDATE_func
+)
+DEFSPEC (FDATE_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFDATE_subr
+)
+DEFSPEC (FGET_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impFGET_func
+)
+DEFSPEC (FGET_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFGET_subr
+)
+DEFSPEC (FGETC_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impFGETC_func
+)
+DEFSPEC (FGETC_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFGETC_subr
+)
+DEFSPEC (FLOATI,
+ "FLOATI",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (FLOATJ,
+ "FLOATJ",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (FLOOR,
+ "FLOOR",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (FLUSH,
+ "FLUSH",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFLUSH
+ )
+DEFSPEC (FNUM,
+ "FNUM",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFNUM
+)
+DEFSPEC (FPUT_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impFPUT_func
+)
+DEFSPEC (FPUT_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFPUT_subr
+)
+DEFSPEC (FPUTC_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impFPUTC_func
+)
+DEFSPEC (FPUTC_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFPUTC_subr
+)
+DEFSPEC (FRACTION,
+ "FRACTION",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (FSEEK,
+ "FSEEK",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFSEEK
+ )
+DEFSPEC (FSTAT_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFSTAT_func
+)
+DEFSPEC (FSTAT_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFSTAT_subr
+)
+DEFSPEC (FTELL_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFTELL_func
+ )
+DEFSPEC (FTELL_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impFTELL_subr
+ )
+DEFSPEC (GERROR,
+ "GERROR",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impGERROR
+)
+DEFSPEC (GETARG,
+ "GETARG",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impGETARG
+ )
+DEFSPEC (GETCWD_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impGETCWD_func
+)
+DEFSPEC (GETCWD_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impGETCWD_subr
+)
+DEFSPEC (GETENV,
+ "GETENV",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impGETENV
+ )
+DEFSPEC (GETGID,
+ "GETGID",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impGETGID
+)
+DEFSPEC (GETLOG,
+ "GETLOG",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impGETLOG
+)
+DEFSPEC (GETPID,
+ "GETPID",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impGETPID
+)
+DEFSPEC (GETUID,
+ "GETUID",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impGETUID
+)
+DEFSPEC (GMTIME,
+ "GMTIME",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impGMTIME
+)
+DEFSPEC (HOSTNM_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impHOSTNM_func
+)
+DEFSPEC (HOSTNM_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impHOSTNM_subr
+)
+DEFSPEC (HUGE,
+ "HUGE",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IACHAR,
+ "IACHAR",
+ FALSE,
+ FFEINTRIN_familyASC,
+ FFEINTRIN_impIACHAR
+ )
+DEFSPEC (IAND,
+ "IAND",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impIAND
+ )
+DEFSPEC (IARGC,
+ "IARGC",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impIARGC
+ )
+DEFSPEC (IBCLR,
+ "IBCLR",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impIBCLR
+ )
+DEFSPEC (IBITS,
+ "IBITS",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impIBITS
+ )
+DEFSPEC (IBSET,
+ "IBSET",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impIBSET
+ )
+DEFSPEC (IDATE_unix,
+ "UNIX",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impIDATE_unix
+)
+DEFSPEC (IDATE_vxt,
+ "VXT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impIDATE_vxt
+)
+DEFSPEC (IEOR,
+ "IEOR",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impIEOR
+ )
+DEFSPEC (IERRNO,
+ "IERRNO",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impIERRNO
+)
+DEFSPEC (IIABS,
+ "IIABS",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIAND,
+ "IIAND",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIBCLR,
+ "IIBCLR",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIBITS,
+ "IIBITS",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIBSET,
+ "IIBSET",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIDIM,
+ "IIDIM",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIDINT,
+ "IIDINT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIDNNT,
+ "IIDNNT",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIEOR,
+ "IIEOR",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIFIX,
+ "IIFIX",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IINT,
+ "IINT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIOR,
+ "IIOR",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIQINT,
+ "IIQINT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IIQNNT,
+ "IIQNNT",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IISHFT,
+ "IISHFT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IISHFTC,
+ "IISHFTC",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IISIGN,
+ "IISIGN",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IMAG,
+ "IMAG",
+ FALSE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impIMAGPART
+ )
+DEFSPEC (IMAGPART,
+ "IMAGPART",
+ FALSE,
+ FFEINTRIN_familyGNU,
+ FFEINTRIN_impIMAGPART
+ )
+DEFSPEC (IMAX0,
+ "IMAX0",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IMAX1,
+ "IMAX1",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IMIN0,
+ "IMIN0",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IMIN1,
+ "IMIN1",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (IMOD,
+ "IMOD",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ININT,
+ "ININT",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (INOT,
+ "INOT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (INT2,
+ "INT2",
+ FALSE,
+ FFEINTRIN_familyGNU,
+ FFEINTRIN_impINT2
+ )
+DEFSPEC (INT8,
+ "INT8",
+ FALSE,
+ FFEINTRIN_familyGNU,
+ FFEINTRIN_impINT8
+ )
+DEFSPEC (IOR,
+ "IOR",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impIOR
+ )
+DEFSPEC (IRAND,
+ "IRAND",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impIRAND
+)
+DEFSPEC (ISATTY,
+ "ISATTY",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impISATTY
+)
+DEFSPEC (ISHFT,
+ "ISHFT",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impISHFT
+ )
+DEFSPEC (ISHFTC,
+ "ISHFTC",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impISHFTC
+ )
+DEFSPEC (ITIME,
+ "ITIME",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impITIME
+)
+DEFSPEC (IZEXT,
+ "IZEXT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIABS,
+ "JIABS",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIAND,
+ "JIAND",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIBCLR,
+ "JIBCLR",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIBITS,
+ "JIBITS",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIBSET,
+ "JIBSET",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIDIM,
+ "JIDIM",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIDINT,
+ "JIDINT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIDNNT,
+ "JIDNNT",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIEOR,
+ "JIEOR",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIFIX,
+ "JIFIX",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JINT,
+ "JINT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIOR,
+ "JIOR",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIQINT,
+ "JIQINT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JIQNNT,
+ "JIQNNT",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JISHFT,
+ "JISHFT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JISHFTC,
+ "JISHFTC",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JISIGN,
+ "JISIGN",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JMAX0,
+ "JMAX0",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JMAX1,
+ "JMAX1",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JMIN0,
+ "JMIN0",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JMIN1,
+ "JMIN1",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JMOD,
+ "JMOD",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JNINT,
+ "JNINT",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JNOT,
+ "JNOT",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (JZEXT,
+ "JZEXT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (KILL_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impKILL_func
+)
+DEFSPEC (KILL_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impKILL_subr
+)
+DEFSPEC (KIND,
+ "KIND",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (LBOUND,
+ "LBOUND",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (LINK_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impLINK_func
+)
+DEFSPEC (LINK_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impLINK_subr
+)
+DEFSPEC (LEN_TRIM,
+ "LEN_TRIM",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impLNBLNK
+ )
+DEFSPEC (LNBLNK,
+ "LNBLNK",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impLNBLNK
+)
+DEFSPEC (LOC,
+ "LOC",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impLOC
+ )
+DEFSPEC (LOGICAL,
+ "LOGICAL",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (LONG,
+ "LONG",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impLONG
+ )
+DEFSPEC (LSHIFT,
+ "LSHIFT",
+ FALSE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impLSHIFT
+ )
+DEFSPEC (LSTAT_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impLSTAT_func
+)
+DEFSPEC (LSTAT_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impLSTAT_subr
+)
+DEFSPEC (LTIME,
+ "LTIME",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impLTIME
+)
+DEFSPEC (MATMUL,
+ "MATMUL",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (MAXEXPONENT,
+ "MAXEXPONENT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (MAXLOC,
+ "MAXLOC",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (MAXVAL,
+ "MAXVAL",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (MCLOCK,
+ "MCLOCK",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impMCLOCK
+)
+DEFSPEC (MCLOCK8,
+ "MCLOCK8",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impMCLOCK8
+)
+DEFSPEC (MERGE,
+ "MERGE",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (MINEXPONENT,
+ "MINEXPONENT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (MINLOC,
+ "MINLOC",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (MINVAL,
+ "MINVAL",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (MODULO,
+ "MODULO",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (MVBITS,
+ "MVBITS",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impMVBITS
+ )
+DEFSPEC (NEAREST,
+ "NEAREST",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (NOT,
+ "NOT",
+ FALSE,
+ FFEINTRIN_familyMIL,
+ FFEINTRIN_impNOT
+ )
+DEFSPEC (OR,
+ "OR",
+ FALSE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impOR
+ )
+DEFSPEC (PACK,
+ "PACK",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (PERROR,
+ "PERROR",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impPERROR
+)
+DEFSPEC (PRECISION,
+ "PRECISION",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (PRESENT,
+ "PRESENT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (PRODUCT,
+ "PRODUCT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QABS,
+ "QABS",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QACOS,
+ "QACOS",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QACOSD,
+ "QACOSD",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QASIN,
+ "QASIN",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QASIND,
+ "QASIND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QATAN,
+ "QATAN",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QATAN2,
+ "QATAN2",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QATAN2D,
+ "QATAN2D",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QATAND,
+ "QATAND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QCOS,
+ "QCOS",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QCOSD,
+ "QCOSD",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QCOSH,
+ "QCOSH",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QDIM,
+ "QDIM",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QEXP,
+ "QEXP",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QEXT,
+ "QEXT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QEXTD,
+ "QEXTD",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QFLOAT,
+ "QFLOAT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QINT,
+ "QINT",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QLOG,
+ "QLOG",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QLOG10,
+ "QLOG10",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QMAX1,
+ "QMAX1",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QMIN1,
+ "QMIN1",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QMOD,
+ "QMOD",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QNINT,
+ "QNINT",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QSIGN,
+ "QSIGN",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QSIN,
+ "QSIN",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QSIND,
+ "QSIND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QSINH,
+ "QSINH",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QSQRT,
+ "QSQRT",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QTAN,
+ "QTAN",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QTAND,
+ "QTAND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (QTANH,
+ "QTANH",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (RADIX,
+ "RADIX",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (RAND,
+ "RAND",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impRAND
+)
+DEFSPEC (RANDOM_NUMBER,
+ "RANDOM_NUMBER",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (RANDOM_SEED,
+ "RANDOM_SEED",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (RANGE,
+ "RANGE",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (REALPART,
+ "REALPART",
+ FALSE,
+ FFEINTRIN_familyGNU,
+ FFEINTRIN_impREALPART
+ )
+DEFSPEC (RENAME_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impRENAME_func
+)
+DEFSPEC (RENAME_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impRENAME_subr
+)
+DEFSPEC (REPEAT,
+ "REPEAT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (RESHAPE,
+ "RESHAPE",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (RRSPACING,
+ "RRSPACING",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (RSHIFT,
+ "RSHIFT",
+ FALSE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impRSHIFT
+ )
+DEFSPEC (SCALE,
+ "SCALE",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SCAN,
+ "SCAN",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SECNDS,
+ "SECNDS",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impSECNDS
+)
+DEFSPEC (SECOND_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impSECOND_func
+)
+DEFSPEC (SECOND_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impSECOND_subr
+)
+DEFSPEC (SEL_INT_KIND,
+ "SEL_INT_KIND",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SEL_REAL_KIND,
+ "SEL_REAL_KIND",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SET_EXPONENT,
+ "SET_EXPONENT",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SHAPE,
+ "SHAPE",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SHORT,
+ "SHORT",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impSHORT
+ )
+DEFSPEC (SIGNAL_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impSIGNAL_func
+ )
+DEFSPEC (SIGNAL_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impSIGNAL_subr
+ )
+DEFSPEC (SIND,
+ "SIND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SLEEP,
+ "SLEEP",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impSLEEP
+)
+DEFSPEC (SNGLQ,
+ "SNGLQ",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SPACING,
+ "SPACING",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SPREAD,
+ "SPREAD",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SRAND,
+ "SRAND",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impSRAND
+)
+DEFSPEC (STAT_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impSTAT_func
+)
+DEFSPEC (STAT_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impSTAT_subr
+)
+DEFSPEC (SUM,
+ "SUM",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (SYMLNK_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impSYMLNK_func
+)
+DEFSPEC (SYMLNK_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impSYMLNK_subr
+)
+DEFSPEC (SYSTEM_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impSYSTEM_func
+ )
+DEFSPEC (SYSTEM_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impSYSTEM_subr
+ )
+DEFSPEC (SYSTEM_CLOCK,
+ "SYSTEM_CLOCK",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impSYSTEM_CLOCK
+ )
+DEFSPEC (TAND,
+ "TAND",
+ TRUE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (TIME8,
+ "UNIX",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impTIME8
+)
+DEFSPEC (TIME_unix,
+ "UNIX",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impTIME_unix
+)
+DEFSPEC (TIME_vxt,
+ "VXT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impTIME_vxt
+)
+DEFSPEC (TINY,
+ "TINY",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (TRANSFER,
+ "TRANSFER",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (TRANSPOSE,
+ "TRANSPOSE",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (TRIM,
+ "TRIM",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (TTYNAM_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impTTYNAM_func
+)
+DEFSPEC (TTYNAM_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impTTYNAM_subr
+)
+DEFSPEC (UBOUND,
+ "UBOUND",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (UMASK_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impUMASK_func
+)
+DEFSPEC (UMASK_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impUMASK_subr
+)
+DEFSPEC (UNLINK_func,
+ "function",
+ FALSE,
+ FFEINTRIN_familyBADU77,
+ FFEINTRIN_impUNLINK_func
+)
+DEFSPEC (UNLINK_subr,
+ "subroutine",
+ FALSE,
+ FFEINTRIN_familyF2U,
+ FFEINTRIN_impUNLINK_subr
+)
+DEFSPEC (UNPACK,
+ "UNPACK",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (VERIFY,
+ "VERIFY",
+ FALSE,
+ FFEINTRIN_familyF90,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (XOR,
+ "XOR",
+ FALSE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impXOR
+ )
+DEFSPEC (ZABS,
+ "ZABS",
+ TRUE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impCDABS
+ )
+DEFSPEC (ZCOS,
+ "ZCOS",
+ TRUE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impCDCOS
+ )
+DEFSPEC (ZEXP,
+ "ZEXP",
+ TRUE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impCDEXP
+ )
+DEFSPEC (ZEXT,
+ "ZEXT",
+ FALSE,
+ FFEINTRIN_familyVXT,
+ FFEINTRIN_impNONE
+ )
+DEFSPEC (ZLOG,
+ "ZLOG",
+ TRUE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impCDLOG
+ )
+DEFSPEC (ZSIN,
+ "ZSIN",
+ TRUE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impCDSIN
+ )
+DEFSPEC (ZSQRT,
+ "ZSQRT",
+ TRUE,
+ FFEINTRIN_familyF2C,
+ FFEINTRIN_impCDSQRT
+ )
+DEFSPEC (NONE,
+ "none",
+ FALSE,
+ FFEINTRIN_familyNONE,
+ FFEINTRIN_impNONE
+ )
+
+/* Intrinsic implementations ordered in two sections:
+ F77, then extensions; secondarily, alphabetical
+ ordering. */
+
+/* The DEFIMP macro specifies the following fields for an intrinsic:
+
+ CODE -- The internal name for this intrinsic; `FFEINTRIN_imp'
+ prepends this to form the `enum' name.
+
+ NAME -- The textual name to use when printing information on
+ this intrinsic.
+
+ GFRTDIRECT -- The run-time library routine that is suitable for
+ a call to implement a *direct* invocation of the
+ intrinsic (e.g. `ABS(10)').
+
+ GFRTF2C -- The run-time library routine that is suitable for
+ passing as an argument to a procedure that will
+ invoke the argument as an EXTERNAL procedure, when
+ f2c calling conventions will be used (e.g.
+ `CALL FOO(ABS)', when FOO compiled with -ff2c).
+
+ GFRTGNU -- The run-time library routine that is suitable for
+ passing as an argument to a procedure that will
+ invoke the argument as an EXTERNAL procedure, when
+ GNU calling conventions will be used (e.g.
+ `CALL FOO(ABS)', when FOO compiled with -fno-f2c).
+
+ CONTROL -- A control string, described below.
+
+*/
+
+/* The control string has the following format:
+
+ <return-type>:<arglist-info>:[<argitem-info>,...]
+
+ <return-type> is:
+
+ <return-base-type><return-kind-type>[<return-modifier>]
+
+ <return-base-type> is:
+
+ - Subroutine
+ A Character
+ C Complex
+ I Integer
+ L Logical
+ R Real
+ B Boolean (I or L), decided by co-operand list (COL)
+ F Floating-point (C or R), decided by COL
+ N Numeric (C, I, or R), decided by co-operand list (COL)
+ S Scalar numeric (I or R), decided by COL, which may be COMPLEX
+
+ <return-kind-type> is:
+
+ - Subroutine
+ = Decided by COL
+ 1 (Default)
+ 2 (Twice the size of 1)
+ 3 (Same size as CHARACTER*1)
+ 4 (Twice the size of 2)
+ 6 (Twice the size as 3)
+ 7 (Same size as `char *')
+ C Like 1 (F77), except (F90), if COL is COMPLEX, uses kind type of COL
+
+ <return-modifier> is:
+
+ * Valid for <return-base-type> of `A' only, means program may
+ declare any length for return value, default being (*)
+
+ <arglist-info> is:
+
+ <COL-spec>
+
+ <COL-spec> is:
+
+ - No COL (return-base-type and return-kind-type must be definitive)
+ * All arguments form COL (must have more than one argument)
+ n Argument n (0 for first arg, 1 for second, etc.) forms COL
+
+ <argitem-info> is:
+
+ <name>=[<optionality>]<arg-base-type><arg-kind-type>[<arg-len>][<arg-rank>][<arg-extra>]
+
+ <name> is the standard keyword name for the argument.
+
+ <optionality> is:
+
+ ? Argument is optional
+ ! Like ?, but argument must be omitted if previous arg was COMPLEX
+ + One or more of these arguments must be specified
+ * Zero or more of these arguments must be specified
+ n Numbered names for arguments, one or more must be specified
+ p Like n, but two or more must be specified
+
+ <arg-base-type> is:
+
+ - Any is valid (arg-kind-type is 0)
+ A Character*(*)
+ C Complex
+ I Integer
+ L Logical
+ R Real
+ B Boolean (I or L)
+ F Floating-point (C or R)
+ N Numeric (C, I, or R)
+ S Scalar numeric (I or R)
+ g GOTO label (alternate-return form of CALL) (arg-kind-type is 0)
+ s Signal handler (INTEGER FUNCTION, SUBROUTINE or dummy/global
+ default INTEGER variable) (arg-kind-type is 0)
+
+ <arg-kind-type> is:
+
+ * Any is valid
+ 1 (Default)
+ 2 (Twice the size of 1)
+ 3 (Same size as CHARACTER*1)
+ 4 (Twice the size of 2)
+ 6 (Twice the size as 3)
+ A Same as first argument
+
+ <arg-len> is:
+
+ (Default) CHARACTER*(*)
+ [n] CHARACTER*n
+
+ <arg-rank> is:
+
+ (default) Rank-0 (variable or array element)
+ (n) Rank-1 array n elements long
+ & Any (arg-extra is &)
+
+ <arg-extra> is:
+
+ (default) Arg is INTENT(IN)
+ i Arg's attributes are all that matter (inquiry function)
+ w Arg is INTENT(OUT)
+ x Arg is INTENT(INOUT)
+ & Arg can have its address taken (LOC(), for example)
+
+*/
+
+DEFIMP (ABS, "ABS", ,ABS,, "S=:0:A=N*")
+DEFIMP (ACOS, "ACOS", L_ACOS,ACOS,, "R=:0:X=R*")
+DEFIMP (AIMAG, "AIMAG", ,AIMAG,, "RC:0:Z=C*")
+DEFIMP (AINT, "AINT", ,AINT,, "R=:0:A=R*")
+DEFIMP (ALOG, "ALOG", L_LOG,ALOG,, "R1:-:X=R1")
+DEFIMP (ALOG10, "ALOG10", ,ALOG10,, "R1:-:X=R1")
+DEFIMP (AMAX0, "AMAX0", ,,, "R1:*:A=pI1")
+DEFIMP (AMAX1, "AMAX1", ,,, "R1:*:A=pR1")
+DEFIMP (AMIN0, "AMIN0", ,,, "R1:*:A=pI1")
+DEFIMP (AMIN1, "AMIN1", ,,, "R1:*:A=pR1")
+DEFIMP (AMOD, "AMOD", ,AMOD,, "R1:*:A=R1,P=R1")
+DEFIMP (ANINT, "ANINT", ,ANINT,, "R=:0:A=R*")
+DEFIMP (ASIN, "ASIN", L_ASIN,ASIN,, "R=:0:X=R*")
+DEFIMP (ATAN, "ATAN", L_ATAN,ATAN,, "R=:0:X=R*")
+DEFIMP (ATAN2, "ATAN2", L_ATAN2,ATAN2,, "R=:*:Y=R*,X=R*")
+DEFIMP (CABS, "CABS", ,CABS,, "R1:-:A=C1")
+DEFIMP (CCOS, "CCOS", ,CCOS,, "C1:-:X=C1")
+DEFIMP (CEXP, "CEXP", ,CEXP,, "C1:-:X=C1")
+DEFIMP (CHAR, "CHAR", ,,, "A1:-:I=I*")
+DEFIMP (CLOG, "CLOG", ,CLOG,, "C1:-:X=C1")
+DEFIMP (CMPLX, "CMPLX", ,,, "C1:*:X=N*,Y=!S*")
+DEFIMP (CONJG, "CONJG", ,CONJG,, "C=:0:Z=C*")
+DEFIMP (COS, "COS", L_COS,COS,, "F=:0:X=F*")
+DEFIMP (COSH, "COSH", L_COSH,COSH,, "R=:0:X=R*")
+DEFIMP (CSIN, "CSIN", ,CSIN,, "C1:-:X=C1")
+DEFIMP (CSQRT, "CSQRT", ,CSQRT,, "C1:-:X=C1")
+DEFIMP (DABS, "DABS", ,DABS,, "R2:-:A=R2")
+DEFIMP (DACOS, "DACOS", L_ACOS,DACOS,, "R2:-:X=R2")
+DEFIMP (DASIN, "DASIN", L_ASIN,DASIN,, "R2:-:X=R2")
+DEFIMP (DATAN, "DATAN", L_ATAN,DATAN,, "R2:-:X=R2")
+DEFIMP (DATAN2, "DATAN2", L_ATAN2,DATAN2,,"R2:*:Y=R2,X=R2")
+DEFIMP (DBLE, "DBLE", ,,, "R2:-:A=N*")
+DEFIMP (DCMPLX, "DCMPLX", ,,, "C2:*:X=N*,Y=!S*")
+DEFIMP (DCOS, "DCOS", L_COS,DCOS,, "R2:-:X=R2")
+DEFIMP (DCOSH, "DCOSH", L_COSH,DCOSH,, "R2:-:X=R2")
+DEFIMP (DDIM, "DDIM", ,DDIM,, "R2:*:X=R2,Y=R2")
+DEFIMP (DEXP, "DEXP", L_EXP,DEXP,, "R2:-:X=R2")
+DEFIMP (DIM, "DIM", ,DIM,, "S=:*:X=S*,Y=S*")
+DEFIMP (DINT, "DINT", ,DINT,, "R2:-:A=R2")
+DEFIMP (DLOG, "DLOG", L_LOG,DLOG,, "R2:-:X=R2")
+DEFIMP (DLOG10, "DLOG10", ,DLOG10,, "R2:-:X=R2")
+DEFIMP (DMAX1, "DMAX1", ,,, "R2:*:A=pR2")
+DEFIMP (DMIN1, "DMIN1", ,,, "R2:*:A=pR2")
+DEFIMP (DMOD, "DMOD", ,DMOD,, "R2:*:A=R2,P=R2")
+DEFIMP (DNINT, "DNINT", ,DNINT,, "R2:-:A=R2")
+DEFIMP (DPROD, "DPROD", ,DPROD,, "R2:*:X=R1,Y=R1")
+DEFIMP (DSIGN, "DSIGN", ,DSIGN,, "R2:*:A=R2,B=R2")
+DEFIMP (DSIN, "DSIN", L_SIN,DSIN,, "R2:-:X=R2")
+DEFIMP (DSINH, "DSINH", L_SINH,DSINH,, "R2:-:X=R2")
+DEFIMP (DSQRT, "DSQRT", L_SQRT,DSQRT,, "R2:-:X=R2")
+DEFIMP (DTAN, "DTAN", L_TAN,DTAN,, "R2:-:X=R2")
+DEFIMP (DTANH, "DTANH", L_TANH,DTANH,, "R2:-:X=R2")
+DEFIMP (EXP, "EXP", L_EXP,EXP,, "F=:0:X=F*")
+DEFIMP (FLOAT, "FLOAT", ,,, "R1:-:A=I*")
+DEFIMP (IABS, "IABS", ,IABS,IABS, "I1:-:A=I1")
+DEFIMP (ICHAR, "ICHAR", ,,, "I1:-:C=A*")
+DEFIMP (IDIM, "IDIM", ,IDIM,IDIM, "I1:*:X=I1,Y=I1")
+DEFIMP (IDINT, "IDINT", ,,, "I1:-:A=R2")
+DEFIMP (IDNINT, "IDNINT", ,IDNINT,IDNINT, "I1:-:A=R2")
+DEFIMP (IFIX, "IFIX", ,,, "I1:-:A=R1")
+DEFIMP (INDEX, "INDEX", ,INDEX,INDEX, "I1:*:String=A*,Substring=A*")
+DEFIMP (INT, "INT", ,,, "I1:-:A=N*")
+DEFIMP (ISIGN, "ISIGN", ,ISIGN,ISIGN, "I1:*:A=I1,B=I1")
+DEFIMP (LEN, "LEN", ,LEN,LEN, "I1:-:String=A*i")
+DEFIMP (LGE, "LGE", ,LGE,LGE, "L1:*:String_A=A1,String_B=A1")
+DEFIMP (LGT, "LGT", ,LGT,LGT, "L1:*:String_A=A1,String_B=A1")
+DEFIMP (LLE, "LLE", ,LLE,LLE, "L1:*:String_A=A1,String_B=A1")
+DEFIMP (LLT, "LLT", ,LLT,LLT, "L1:*:String_A=A1,String_B=A1")
+DEFIMP (LOG, "LOG", L_LOG,ALOG,, "F=:0:X=F*")
+DEFIMP (LOG10, "LOG10", ,,, "R=:0:X=R*")
+DEFIMP (MAX, "MAX", ,,, "S=:*:A=pS*")
+DEFIMP (MIN, "MIN", ,,, "S=:*:A=pS*")
+DEFIMP (MAX0, "MAX0", ,,, "I1:*:A=pI1")
+DEFIMP (MAX1, "MAX1", ,,, "I1:*:A=pR1")
+DEFIMP (MIN0, "MIN0", ,,, "I1:*:A=pI1")
+DEFIMP (MIN1, "MIN1", ,,, "I1:*:A=pR1")
+DEFIMP (MOD, "MOD", ,MOD,MOD, "S=:*:A=S*,P=S*")
+DEFIMP (NINT, "NINT", ,NINT,NINT, "I1:-:A=R*")
+DEFIMP (REAL, "REAL", ,,, "RC:0:A=N*")
+DEFIMP (SIGN, "SIGN", ,SIGN,, "S=:*:A=S*,B=S*")
+DEFIMP (SIN, "SIN", L_SIN,SIN,, "F=:0:X=F*")
+DEFIMP (SINH, "SINH", L_SINH,SINH,, "R=:0:X=R*")
+DEFIMP (SNGL, "SNGL", ,,, "R1:-:A=R2")
+DEFIMP (SQRT, "SQRT", L_SQRT,SQRT,, "F=:0:X=F*")
+DEFIMP (TAN, "TAN", L_TAN,TAN,, "R=:0:X=R*")
+DEFIMP (TANH, "TANH", L_TANH,TANH,, "R=:0:X=R*")
+
+DEFIMP (ABORT, "ABORT", ABORT,,, "--:-:")
+DEFIMP (ACCESS, "ACCESS", ACCESS,,, "I1:-:Name=A1,Mode=A1")
+DEFIMP (ACHAR, "ACHAR", ,,, "A1:-:I=I*")
+DEFIMP (ALARM, "ALARM", ALARM,,, "--:-:Seconds=I*,Handler=s*,Status=?I1w")
+DEFIMP (AND, "AND", ,,, "B=:*:I=B*,J=B*")
+DEFIMP (BESJ0, "BESJ0", L_BESJ0,,, "R=:0:X=R*")
+DEFIMP (BESJ1, "BESJ1", L_BESJ1,,, "R=:0:X=R*")
+DEFIMP (BESJN, "BESJN", L_BESJN,,, "R=:1:N=I*,X=R*")
+DEFIMP (BESY0, "BESY0", L_BESY0,,, "R=:0:X=R*")
+DEFIMP (BESY1, "BESY1", L_BESY1,,, "R=:0:X=R*")
+DEFIMP (BESYN, "BESYN", L_BESYN,,, "R=:1:N=I*,X=R*")
+DEFIMP (BIT_SIZE, "BIT_SIZE", ,,, "I=:0:I=I*i")
+DEFIMP (BTEST, "BTEST", ,,, "L1:*:I=I*,Pos=I*")
+DEFIMP (CDABS, "CDABS", ,CDABS,, "R2:-:A=C2")
+DEFIMP (CDCOS, "CDCOS", ,CDCOS,, "C2:-:X=C2")
+DEFIMP (CDEXP, "CDEXP", ,CDEXP,, "C2:-:X=C2")
+DEFIMP (CDLOG, "CDLOG", ,CDLOG,, "C2:-:X=C2")
+DEFIMP (CDSIN, "CDSIN", ,CDSIN,, "C2:-:X=C2")
+DEFIMP (CDSQRT, "CDSQRT", ,CDSQRT,, "C2:-:X=C2")
+DEFIMP (CHDIR_func, "CHDIR_func", CHDIR,,, "I1:-:Dir=A1")
+DEFIMP (CHDIR_subr, "CHDIR_subr", CHDIR,,, "--:-:Dir=A1,Status=?I1w")
+DEFIMP (CHMOD_func, "CHMOD_func", CHMOD,,, "I1:-:Name=A1,Mode=A1")
+DEFIMP (CHMOD_subr, "CHMOD_subr", CHMOD,,, "--:-:Name=A1,Mode=A1,Status=?I1w")
+DEFIMP (COMPLEX, "COMPLEX", ,,, "C=:*:Real=S*,Imag=S*")
+DEFIMP (CPU_TIME, "CPU_TIME", SECOND,,, "--:-:Seconds=R*w")
+DEFIMP (CTIME_func, "CTIME_func", CTIME,,, "A1*:-:STime=I*")
+DEFIMP (CTIME_subr, "CTIME_subr", CTIME,,, "--:-:Result=A1w,STime=I*")
+DEFIMP (DATE, "DATE", DATE,,, "--:-:Date=A1w")
+DEFIMP (DATE_AND_TIME, "DATE_AND_TIME", DATE_AND_TIME,,, "--:-:Date=A1w,Time=?A1w,Zone=?A1w,Values=?I1(8)w")
+DEFIMP (DBESJ0, "DBESJ0", L_BESJ0,,, "R2:-:X=R2")
+DEFIMP (DBESJ1, "DBESJ1", L_BESJ1,,, "R2:-:X=R2")
+DEFIMP (DBESJN, "DBESJN", L_BESJN,,, "R2:-:N=I*,X=R2")
+DEFIMP (DBESY0, "DBESY0", L_BESY0,,, "R2:-:X=R2")
+DEFIMP (DBESY1, "DBESY1", L_BESY1,,, "R2:-:X=R2")
+DEFIMP (DBESYN, "DBESYN", L_BESYN,,, "R2:-:N=I*,X=R2")
+DEFIMP (DCONJG, "DCONJG", ,DCONJG,, "C2:-:Z=C2")
+DEFIMP (DERF, "DERF", L_ERF,DERF,, "R2:-:X=R2")
+DEFIMP (DERFC, "DERFC", L_ERFC,DERFC,, "R2:-:X=R2")
+DEFIMP (DFLOAT, "DFLOAT", ,,, "R2:-:A=I*")
+DEFIMP (DIMAG, "DIMAG", ,DIMAG,, "R2:-:Z=C2")
+DEFIMP (DREAL, "DREAL", ,,, "R2:-:A=N*")
+DEFIMP (DTIME_func, "DTIME_func", DTIME,,, "R1:-:TArray=R1(2)w")
+DEFIMP (DTIME_subr, "DTIME_subr", DTIME,,, "--:-:Result=R1w,TArray=R1(2)w")
+DEFIMP (ERF, "ERF", L_ERF,ERF,, "R=:0:X=R*")
+DEFIMP (ERFC, "ERFC", L_ERFC,ERFC,, "R=:0:X=R*")
+DEFIMP (ETIME_func, "ETIME_func", ETIME,,, "R1:-:TArray=R1(2)w")
+DEFIMP (ETIME_subr, "ETIME_subr", ETIME,,, "--:-:Result=R1w,TArray=R1(2)w")
+DEFIMP (EXIT, "EXIT", EXIT,,, "--:-:Status=?I*")
+DEFIMP (FDATE_func, "FDATE_func", FDATE,,, "A1*:-:")
+DEFIMP (FDATE_subr, "FDATE_subr", FDATE,,, "--:-:Date=A1w")
+DEFIMP (FGET_func, "FGET_func", FGET,,, "I1:-:C=A1w")
+DEFIMP (FGET_subr, "FGET_subr", FGET,,, "--:-:C=A1w,Status=?I1w")
+DEFIMP (FGETC_func, "FGETC_func", FGETC,,, "I1:-:Unit=I*,C=A1w")
+DEFIMP (FGETC_subr, "FGETC_subr", FGETC,,, "--:-:Unit=I*,C=A1w,Status=?I1w")
+DEFIMP (FLUSH, "FLUSH", ,,, "--:-:Unit=?I*")
+DEFIMP (FNUM, "FNUM", FNUM,,, "I1:-:Unit=I*")
+DEFIMP (FPUT_func, "FPUT_func", FPUT,,, "I1:-:C=A1")
+DEFIMP (FPUT_subr, "FPUT_subr", FPUT,,, "--:-:C=A1,Status=?I1w")
+DEFIMP (FPUTC_func, "FPUTC_func", FPUTC,,, "I1:-:Unit=I*,C=A1")
+DEFIMP (FPUTC_subr, "FPUTC_subr", FPUTC,,, "--:-:Unit=I*,C=A1,Status=?I1w")
+DEFIMP (FSEEK, "FSEEK", FSEEK,,, "--:-:Unit=I*,Offset=I*,Whence=I*,ErrLab=?g*")
+DEFIMP (FSTAT_func, "FSTAT_func", FSTAT,,, "I1:-:Unit=I*,SArray=I1(13)w")
+DEFIMP (FSTAT_subr, "FSTAT_subr", FSTAT,,, "--:-:Unit=I*,SArray=I1(13)w,Status=?I1w")
+DEFIMP (FTELL_func, "FTELL_func", FTELL,,, "I1:-:Unit=I*")
+DEFIMP (FTELL_subr, "FTELL_subr", FTELL,,, "--:-:Unit=I*,Offset=I1w")
+DEFIMP (GERROR, "GERROR", GERROR,,, "--:-:Message=A1w")
+DEFIMP (GETARG, "GETARG", GETARG,,, "--:-:Pos=I*,Value=A1w")
+DEFIMP (GETCWD_func, "GETCWD_func", GETCWD,,, "I1:-:Name=A1w")
+DEFIMP (GETCWD_subr, "GETCWD_subr", GETCWD,,, "--:-:Name=A1w,Status=?I1w")
+DEFIMP (GETGID, "GETGID", GETGID,,, "I1:-:")
+DEFIMP (GETLOG, "GETLOG", GETLOG,,, "--:-:Login=A1w")
+DEFIMP (GETPID, "GETPID", GETPID,,, "I1:-:")
+DEFIMP (GETUID, "GETUID", GETUID,,, "I1:-:")
+DEFIMP (GETENV, "GETENV", GETENV,,, "--:-:Name=A1,Value=A1w")
+DEFIMP (GMTIME, "GMTIME", GMTIME,,, "--:-:STime=I1,TArray=I1(9)w")
+DEFIMP (HOSTNM_func, "HOSTNM_func", HOSTNM,,, "I1:-:Name=A1w")
+DEFIMP (HOSTNM_subr, "HOSTNM_subr", HOSTNM,,, "--:-:Name=A1w,Status=?I1w")
+DEFIMP (IACHAR, "IACHAR", ,,, "I1:-:C=A*")
+DEFIMP (IAND, "IAND", ,,, "I=:*:I=I*,J=I*")
+DEFIMP (IARGC, "IARGC", IARGC,,, "I1:-:")
+DEFIMP (IBCLR, "IBCLR", ,,, "I=:0:I=I*,Pos=I*")
+DEFIMP (IBITS, "IBITS", ,,, "I=:0:I=I*,Pos=I*,Len=I*")
+DEFIMP (IBSET, "IBSET", ,,, "I=:0:I=I*,Pos=I*")
+DEFIMP (IDATE_unix, "IDATE_unix", IDATE,,, "--:-:TArray=I1(3)w")
+DEFIMP (IDATE_vxt, "IDATE_vxt", VXTIDATE,,, "--:-:M=I1w,D=I1w,Y=I1w")
+DEFIMP (IEOR, "IEOR", ,,, "I=:*:I=I*,J=I*")
+DEFIMP (IOR, "IOR", ,,, "I=:*:I=I*,J=I*")
+DEFIMP (IERRNO, "IERRNO", IERRNO,,, "I1:-:")
+DEFIMP (IMAGPART, "IMAGPART", ,,, "R=:0:Z=C*")
+DEFIMP (INT2, "INT2", ,,, "I6:-:A=N*")
+DEFIMP (INT8, "INT8", ,,, "I2:-:A=N*")
+DEFIMP (IRAND, "IRAND", IRAND,,, "I1:-:Flag=?I*")
+DEFIMP (ISATTY, "ISATTY", ISATTY,,, "L1:-:Unit=I*")
+DEFIMP (ISHFT, "ISHFT", ,,, "I=:0:I=I*,Shift=I*")
+DEFIMP (ISHFTC, "ISHFTC", ,,, "I=:0:I=I*,Shift=I*,Size=I*")
+DEFIMP (ITIME, "ITIME", ITIME,,, "--:-:TArray=I1(3)w")
+DEFIMP (KILL_func, "KILL_func", KILL,,, "I1:-:Pid=I*,Signal=I*")
+DEFIMP (KILL_subr, "KILL_subr", KILL,,, "--:-:Pid=I*,Signal=I*,Status=?I1w")
+DEFIMP (LINK_func, "LINK_func", LINK,,, "I1:-:Path1=A1,Path2=A1")
+DEFIMP (LINK_subr, "LINK_subr", LINK,,, "--:-:Path1=A1,Path2=A1,Status=?I1w")
+DEFIMP (LNBLNK, "LNBLNK", LNBLNK,,, "I1:-:String=A1")
+DEFIMP (LONG, "LONG", ,,, "I1:-:A=I6")
+DEFIMP (LSTAT_func, "LSTAT_func", LSTAT,,, "I1:-:File=A1,SArray=I1(13)w")
+DEFIMP (LSTAT_subr, "LSTAT_subr", LSTAT,,, "--:-:File=A1,SArray=I1(13)w,Status=?I1w")
+DEFIMP (LTIME, "LTIME", LTIME,,, "--:-:STime=I1,TArray=I1(9)w")
+DEFIMP (LOC, "LOC", ,,, "I7:-:Entity=-*&&")
+DEFIMP (LSHIFT, "LSHIFT", ,,, "I=:0:I=I*,Shift=I*")
+DEFIMP (MCLOCK, "MCLOCK", MCLOCK,,, "I1:-:")
+DEFIMP (MCLOCK8, "MCLOCK8", MCLOCK,,, "I2:-:")
+DEFIMP (MVBITS, "MVBITS", ,,, "--:-:From=I*,FromPos=I*,Len=I*,TO=IAx,ToPos=I*")
+DEFIMP (NOT, "NOT", ,,, "I=:0:I=I*")
+DEFIMP (OR, "OR", ,,, "B=:*:I=B*,J=B*")
+DEFIMP (PERROR, "PERROR", PERROR,,, "--:-:String=A1")
+DEFIMP (RAND, "RAND", RAND,,, "R1:-:Flag=?I*")
+DEFIMP (REALPART, "REALPART", ,,, "R=:0:Z=C*")
+DEFIMP (RENAME_func, "RENAME_func", RENAME,,, "I1:-:Path1=A1,Path2=A1")
+DEFIMP (RENAME_subr, "RENAME_subr", RENAME,,, "--:-:Path1=A1,Path2=A1,Status=?I1w")
+DEFIMP (RSHIFT, "RSHIFT", ,,, "I=:0:I=I*,Shift=I*")
+DEFIMP (SECNDS, "SECNDS", SECNDS,,, "R1:-:T=R1")
+DEFIMP (SECOND_func, "SECOND_func", SECOND,SECOND,, "R1:-:")
+DEFIMP (SECOND_subr, "SECOND_subr", SECOND,,, "--:-:Seconds=R*w")
+DEFIMP (SHORT, "SHORT", ,,, "I6:-:A=I*")
+DEFIMP (SIGNAL_func, "SIGNAL_func", L_SIGNAL,,, "I7:-:Number=I*,Handler=s*")
+DEFIMP (SIGNAL_subr, "SIGNAL_subr", L_SIGNAL,,, "--:-:Number=I*,Handler=s*,Status=?I7w")
+DEFIMP (SLEEP, "SLEEP", SLEEP,,, "--:-:Seconds=I1")
+DEFIMP (SRAND, "SRAND", SRAND,,, "--:-:Seed=I*")
+DEFIMP (STAT_func, "STAT_func", STAT,,, "I1:-:File=A1,SArray=I1(13)w")
+DEFIMP (STAT_subr, "STAT_subr", STAT,,, "--:-:File=A1,SArray=I1(13)w,Status=?I1w")
+DEFIMP (SYMLNK_func, "SYMLNK_func", SYMLNK,,, "I1:-:Path1=A1,Path2=A1")
+DEFIMP (SYMLNK_subr, "SYMLNK_subr", SYMLNK,,, "--:-:Path1=A1,Path2=A1,Status=?I1w")
+DEFIMP (SYSTEM_func, "SYSTEM_func", SYSTEM,SYSTEM,SYSTEM,"I1:-:Command=A1")
+DEFIMP (SYSTEM_subr, "SYSTEM_subr", SYSTEM,,, "--:-:Command=A1,Status=?I1w")
+DEFIMP (SYSTEM_CLOCK, "SYSTEM_CLOCK", SYSTEM_CLOCK,,, "--:-:Count=I1w,Rate=?I1w,Max=?I1w")
+DEFIMP (TIME8, "TIME8", TIME,,, "I2:-:")
+DEFIMP (TIME_unix, "TIME_unix", TIME,,, "I1:-:")
+DEFIMP (TIME_vxt, "TIME_vxt", VXTTIME,,, "--:-:Time=A1[8]w")
+DEFIMP (TTYNAM_func, "TTYNAM_func", TTYNAM,,, "A1*:-:Unit=I*")
+DEFIMP (TTYNAM_subr, "TTYNAM_subr", TTYNAM,,, "--:-:Name=A1w,Unit=I*")
+DEFIMP (UMASK_func, "UMASK_func", UMASK,,, "I1:-:Mask=I*")
+DEFIMP (UMASK_subr, "UMASK_subr", UMASK,,, "--:-:Mask=I*,Old=?I1w")
+DEFIMP (UNLINK_func, "UNLINK_func", UNLINK,,, "I1:-:File=A1")
+DEFIMP (UNLINK_subr, "UNLINK_subr", UNLINK,,, "--:-:File=A1,Status=?I1w")
+DEFIMP (XOR, "XOR", ,,, "B=:*:I=B*,J=B*")
+DEFIMP (NONE, "none", ,,, "")
diff --git a/contrib/gcc/f/intrin.h b/contrib/gcc/f/intrin.h
new file mode 100644
index 0000000..0006c8a
--- /dev/null
+++ b/contrib/gcc/f/intrin.h
@@ -0,0 +1,130 @@
+/* intrin.h -- Public interface for intrin.c
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+*/
+
+#ifndef _H_f_intrin
+#define _H_f_intrin
+
+#ifndef FFEINTRIN_DOC
+#define FFEINTRIN_DOC 0 /* 1 means intrinsic documentation only (intdoc.c). */
+#endif
+
+typedef enum
+ {
+ FFEINTRIN_familyNONE, /* Not in any family. */
+ FFEINTRIN_familyF77, /* ANSI FORTRAN 77. */
+ FFEINTRIN_familyGNU, /* GNU Fortran intrinsics. */
+ FFEINTRIN_familyF2C, /* f2c intrinsics. */
+ FFEINTRIN_familyF90, /* Fortran 90. */
+ FFEINTRIN_familyF95 = FFEINTRIN_familyF90,
+ FFEINTRIN_familyVXT, /* VAX/VMS FORTRAN. */
+ FFEINTRIN_familyMIL, /* MIL STD 1753 (MVBITS, etc), in mil, vxt, and f90. */
+ FFEINTRIN_familyASC, /* ASCII-related (ACHAR, IACHAR), both f2c and f90. */
+ FFEINTRIN_familyFVZ, /* in both f2c and VAX/VMS FORTRAN. */
+ FFEINTRIN_familyF2U, /* libf2c/libU77 UNIX system intrinsics. */
+ FFEINTRIN_familyBADU77, /* libU77 UNIX system intrinsics with bad form. */
+ FFEINTRIN_family
+ } ffeintrinFamily;
+
+typedef enum
+ {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2) FFEINTRIN_gen ## CODE,
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+ FFEINTRIN_gen
+ } ffeintrinGen;
+
+typedef enum
+ {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP) FFEINTRIN_spec ## CODE,
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL)
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+ FFEINTRIN_spec
+ } ffeintrinSpec;
+
+typedef enum
+ {
+#define DEFNAME(UPPER,LOWER,MIXED,GEN,SPEC)
+#define DEFGEN(CODE,NAME,SPEC1,SPEC2)
+#define DEFSPEC(CODE,NAME,CALLABLE,FAMILY,IMP)
+#define DEFIMP(CODE,NAME,GFRTDIRECT,GFRTF2C,GFRTGNU,CONTROL) \
+ FFEINTRIN_imp ## CODE,
+#include "intrin.def"
+#undef DEFNAME
+#undef DEFGEN
+#undef DEFSPEC
+#undef DEFIMP
+ FFEINTRIN_imp
+ } ffeintrinImp;
+
+#if !FFEINTRIN_DOC
+
+#include "bld.h"
+#include "info.h"
+
+ffeinfoBasictype ffeintrin_basictype (ffeintrinSpec spec);
+ffeintrinFamily ffeintrin_family (ffeintrinSpec spec);
+void ffeintrin_fulfill_generic (ffebld *expr, ffeinfo *info, ffelexToken t);
+void ffeintrin_fulfill_specific (ffebld *expr, ffeinfo *info,
+ bool *check_intrin, ffelexToken t);
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ffecomGfrt ffeintrin_gfrt_direct (ffeintrinImp imp);
+ffecomGfrt ffeintrin_gfrt_indirect (ffeintrinImp imp);
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+void ffeintrin_init_0 (void);
+#define ffeintrin_init_1()
+#define ffeintrin_init_2()
+#define ffeintrin_init_3()
+#define ffeintrin_init_4()
+bool ffeintrin_is_actualarg (ffeintrinSpec spec);
+bool ffeintrin_is_intrinsic (char *name, ffelexToken t, bool explicit,
+ ffeintrinGen *gen, ffeintrinSpec *spec,
+ ffeintrinImp *imp);
+bool ffeintrin_is_standard (ffeintrinGen gen, ffeintrinSpec spec);
+ffeinfoKindtype ffeintrin_kindtype (ffeintrinSpec spec);
+char *ffeintrin_name_generic (ffeintrinGen gen);
+char *ffeintrin_name_implementation (ffeintrinImp imp);
+char *ffeintrin_name_specific (ffeintrinSpec spec);
+ffeIntrinsicState ffeintrin_state_family (ffeintrinFamily family);
+#define ffeintrin_terminate_0()
+#define ffeintrin_terminate_1()
+#define ffeintrin_terminate_2()
+#define ffeintrin_terminate_3()
+#define ffeintrin_terminate_4()
+
+#endif /* !FFEINTRIN_DOC */
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/lab.c b/contrib/gcc/f/lab.c
new file mode 100644
index 0000000..e161097
--- /dev/null
+++ b/contrib/gcc/f/lab.c
@@ -0,0 +1,159 @@
+/* lab.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+
+ Description:
+ Complex data abstraction for Fortran labels. Maintains a single master
+ list for all labels; it is expected initialization and termination of
+ this list will occur on program-unit boundaries.
+
+ Modifications:
+ 22-Aug-89 JCB 1.1
+ Change ffelab_new for new ffewhere interface.
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "lab.h"
+#include "malloc.h"
+
+/* Externals defined here. */
+
+ffelab ffelab_list_;
+ffelabNumber ffelab_num_news_;
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+
+/* ffelab_find -- Find the ffelab object having the desired label value
+
+ ffelab l;
+ ffelabValue v;
+ l = ffelab_find(v);
+
+ If the desired ffelab object doesn't exist, returns NULL.
+
+ Straightforward search of list of ffelabs. */
+
+ffelab
+ffelab_find (ffelabValue v)
+{
+ ffelab l;
+
+ for (l = ffelab_list_; (l != NULL) && (ffelab_value (l) != v); l = l->next)
+ ;
+
+ return l;
+}
+
+/* ffelab_finish -- Shut down label management
+
+ ffelab_finish();
+
+ At the end of processing a program unit, call this routine to shut down
+ label management.
+
+ Kill all the labels on the list. */
+
+void
+ffelab_finish ()
+{
+ ffelab l;
+ ffelab pl;
+
+ for (pl = NULL, l = ffelab_list_; l != NULL; pl = l, l = l->next)
+ if (pl != NULL)
+ malloc_kill_ks (ffe_pool_any_unit (), pl, sizeof (*pl));
+
+ if (pl != NULL)
+ malloc_kill_ks (ffe_pool_any_unit (), pl, sizeof (*pl));
+}
+
+/* ffelab_init_3 -- Initialize label management system
+
+ ffelab_init_3();
+
+ Initialize the label management system. Do this before a new program
+ unit is going to be processed. */
+
+void
+ffelab_init_3 ()
+{
+ ffelab_list_ = NULL;
+ ffelab_num_news_ = 0;
+}
+
+/* ffelab_new -- Create an ffelab object.
+
+ ffelab l;
+ ffelabValue v;
+ l = ffelab_new(v);
+
+ Create a label having a given value. If the value isn't known, pass
+ FFELAB_valueNONE, and set it later with ffelab_set_value.
+
+ Allocate, initialize, and stick at top of label list.
+
+ 22-Aug-89 JCB 1.1
+ Change for new ffewhere interface. */
+
+ffelab
+ffelab_new (ffelabValue v)
+{
+ ffelab l;
+
+ ++ffelab_num_news_;
+ l = (ffelab) malloc_new_ks (ffe_pool_any_unit (), "FFELAB label", sizeof (*l));
+ l->next = ffelab_list_;
+#ifdef FFECOM_labelHOOK
+ l->hook = FFECOM_labelNULL;
+#endif
+ l->value = v;
+ l->firstref_line = ffewhere_line_unknown ();
+ l->firstref_col = ffewhere_column_unknown ();
+ l->doref_line = ffewhere_line_unknown ();
+ l->doref_col = ffewhere_column_unknown ();
+ l->definition_line = ffewhere_line_unknown ();
+ l->definition_col = ffewhere_column_unknown ();
+ l->type = FFELAB_typeUNKNOWN;
+ ffelab_list_ = l;
+ return l;
+}
diff --git a/contrib/gcc/f/lab.h b/contrib/gcc/f/lab.h
new file mode 100644
index 0000000..d559860
--- /dev/null
+++ b/contrib/gcc/f/lab.h
@@ -0,0 +1,154 @@
+/* lab.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ lab.c
+
+ Modifications:
+ 22-Aug-89 JCB 1.1
+ Change for new ffewhere interface.
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_lab
+#define _H_f_lab
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFELAB_typeUNKNOWN, /* No info yet on label. */
+ FFELAB_typeANY, /* Label valid for anything, no msgs. */
+ FFELAB_typeUSELESS, /* No valid way to reference this label. */
+ FFELAB_typeASSIGNABLE, /* Target of ASSIGN: so FORMAT or BRANCH. */
+ FFELAB_typeFORMAT, /* FORMAT label. */
+ FFELAB_typeLOOPEND, /* Target of a labeled DO statement. */
+ FFELAB_typeNOTLOOP, /* Branch target statement not valid DO
+ target. */
+ FFELAB_typeENDIF, /* END IF label. */
+ FFELAB_type
+ } ffelabType;
+
+#define FFELAB_valueNONE 0
+#define FFELAB_valueMAX 99999
+
+/* Typedefs. */
+
+typedef struct _ffelab_ *ffelab;
+typedef ffelab ffelabHandle;
+typedef unsigned long ffelabNumber; /* Count of new labels. */
+#define ffelabNumber_f "l"
+typedef unsigned long ffelabValue;
+#define ffelabValue_f "l"
+
+/* Include files needed by this one. */
+
+#include "com.h"
+#include "where.h"
+
+/* Structure definitions. */
+
+struct _ffelab_
+ {
+ ffelab next;
+#ifdef FFECOM_labelHOOK
+ ffecomLabel hook;
+#endif
+ ffelabValue value; /* 1 through 99999, or 100000+ for temp
+ labels. */
+ unsigned long blocknum; /* Managed entirely by user of module. */
+ ffewhereLine firstref_line;
+ ffewhereColumn firstref_col;
+ ffewhereLine doref_line;
+ ffewhereColumn doref_col;
+ ffewhereLine definition_line; /* ffewhere_line_unknown() if not
+ defined. */
+ ffewhereColumn definition_col;
+ ffelabType type;
+ };
+
+/* Global objects accessed by users of this module. */
+
+extern ffelab ffelab_list_;
+extern ffelabNumber ffelab_num_news_;
+
+/* Declare functions with prototypes. */
+
+ffelab ffelab_find (ffelabValue v);
+void ffelab_finish (void);
+void ffelab_init_3 (void);
+ffelab ffelab_new (ffelabValue v);
+
+/* Define macros. */
+
+#define ffelab_blocknum(l) ((l)->blocknum)
+#define ffelab_definition_column(l) ((l)->definition_col)
+#define ffelab_definition_filename(l) \
+ ffewhere_line_filename((l)->definition_line)
+#define ffelab_definition_filelinenum(l) \
+ ffewhere_line_filelinenum((l)->definition_line)
+#define ffelab_definition_line(l) ((l)->definition_line)
+#define ffelab_definition_line_number(l) \
+ ffewhere_line_number((l)->definition_line)
+#define ffelab_doref_column(l) ((l)->doref_col)
+#define ffelab_doref_filename(l) ffewhere_line_filename((l)->doref_line)
+#define ffelab_doref_filelinenum(l) ffewhere_line_filelinenum((l)->doref_line)
+#define ffelab_doref_line(l) ((l)->doref_line)
+#define ffelab_doref_line_number(l) ffewhere_line_number((l)->doref_line)
+#define ffelab_firstref_column(l) ((l)->firstref_col)
+#define ffelab_firstref_filename(l) ffewhere_line_filename((l)->firstref_line)
+#define ffelab_firstref_filelinenum(l) \
+ ffewhere_line_filelinenum((l)->firstref_line)
+#define ffelab_firstref_line(l) ((l)->firstref_line)
+#define ffelab_firstref_line_number(l) ffewhere_line_number((l)->firstref_line)
+#define ffelab_handle_done(h)
+#define ffelab_handle_first() ((ffelabHandle) ffelab_list_)
+#define ffelab_handle_next(h) ((ffelabHandle) (((ffelab) h)->next))
+#define ffelab_handle_target(h) ((ffelab) h)
+#define ffelab_hook(l) ((l)->hook)
+#define ffelab_init_0()
+#define ffelab_init_1()
+#define ffelab_init_2()
+#define ffelab_init_4()
+#define ffelab_kill(l) ffelab_set_value(l,FFELAB_valueNONE);
+#define ffelab_new_generated() (ffelab_new(ffelab_generated_++))
+#define ffelab_number() (ffelab_num_news_)
+#define ffelab_set_blocknum(l,b) ((l)->blocknum = (b))
+#define ffelab_set_definition_column(l,cn) ((l)->definition_col = (cn))
+#define ffelab_set_definition_line(l,ln) ((l)->definition_line = (ln))
+#define ffelab_set_doref_column(l,cn) ((l)->doref_col = (cn))
+#define ffelab_set_doref_line(l,ln) ((l)->doref_line = (ln))
+#define ffelab_set_firstref_column(l,cn) ((l)->firstref_col = (cn))
+#define ffelab_set_firstref_line(l,ln) ((l)->firstref_line = (ln))
+#define ffelab_set_hook(l,h) ((l)->hook = (h))
+#define ffelab_set_type(l,t) ((l)->type = (t))
+#define ffelab_terminate_0()
+#define ffelab_terminate_1()
+#define ffelab_terminate_2()
+#define ffelab_terminate_3()
+#define ffelab_terminate_4()
+#define ffelab_type(l) ((l)->type)
+#define ffelab_value(l) ((l)->value)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/lang-options.h b/contrib/gcc/f/lang-options.h
new file mode 100644
index 0000000..4b7c6b8
--- /dev/null
+++ b/contrib/gcc/f/lang-options.h
@@ -0,0 +1,158 @@
+/* lang-options.h file for Fortran
+ Copyright (C) 1995-1998 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+*/
+
+/* This is the contribution to the `lang_options' array in gcc.c for
+ g77. */
+
+#ifdef __STDC__ /* To be consistent with lang-specs.h. Maybe avoid
+ overflowing some old compiler's tables, etc. */
+
+DEFINE_LANG_NAME ("Fortran")
+
+ { "-fversion", "Print g77-specific compiler version info, run internal tests" },
+ { "-fnull-version", "" },
+/*"-fident",*/
+/*"-fno-ident",*/
+ { "-ff66", "Program is written in typical FORTRAN 66 dialect" },
+ { "-fno-f66", "" },
+ { "-ff77", "Program is written in typical Unix f77 dialect" },
+ { "-fno-f77", "Program does not use Unix-f77 dialectal features" },
+ { "-ff90", "Program is written in Fortran-90-ish dialect" },
+ { "-fno-f90", "" },
+ { "-fautomatic", "" },
+ { "-fno-automatic", "Treat local vars and COMMON blocks as if they were named in SAVE statements" },
+ { "-fdollar-ok", "Allow $ in symbol names" },
+ { "-fno-dollar-ok", "" },
+ { "-ff2c", "" },
+ { "-fno-f2c", "f2c-compatible code need not be generated" },
+ { "-ff2c-library", "" },
+ { "-fno-f2c-library", "Unsupported; do not generate libf2c-calling code" },
+ { "-ffree-form", "Program is written in Fortran-90-ish free form" },
+ { "-fno-free-form", "" },
+ { "-ffixed-form", "" },
+ { "-fno-fixed-form", "" },
+ { "-fpedantic", "Warn about use of (only a few for now) Fortran extensions" },
+ { "-fno-pedantic", "" },
+ { "-fvxt", "Program is written in VXT (Digital-like) FORTRAN" },
+ { "-fno-vxt", "" },
+ { "-fugly", "Obsolete; allow certain ugly features" },
+ { "-fno-ugly", "" },
+ { "-fugly-args", "" },
+ { "-fno-ugly-args", "Hollerith and typeless constants not passed as arguments" },
+ { "-fugly-assign", "Allow ordinary copying of ASSIGN'ed vars" },
+ { "-fno-ugly-assign", "" },
+ { "-fugly-assumed", "Dummy array dimensioned to (1) is assumed-size" },
+ { "-fno-ugly-assumed", "" },
+ { "-fugly-comma", "Trailing comma in procedure call denotes null argument" },
+ { "-fno-ugly-comma", "" },
+ { "-fugly-complex", "Allow REAL(Z) and AIMAG(Z) given DOUBLE COMPLEX Z" },
+ { "-fno-ugly-complex", "" },
+ { "-fugly-init", "" },
+ { "-fno-ugly-init", "Initialization via DATA and PARAMETER is type-compatible" },
+ { "-fugly-logint", "Allow INTEGER and LOGICAL interchangeability" },
+ { "-fno-ugly-logint", "" },
+ { "-fxyzzy", "Print internal debugging-related info" },
+ { "-fno-xyzzy", "" },
+ { "-finit-local-zero", "Initialize local vars and arrays to zero" },
+ { "-fno-init-local-zero", "" },
+ { "-fbackslash", "" },
+ { "-fno-backslash", "Backslashes in character/hollerith constants not special (C-style)" },
+ { "-femulate-complex", "" },
+ { "-fno-emulate-complex", "Have compiler back end cope with COMPLEX arithmetic" },
+ { "-funderscoring", "" },
+ { "-fno-underscoring", "Disable the appending of underscores to externals" },
+ { "-fsecond-underscore", "" },
+ { "-fno-second-underscore", "Never append a second underscore to externals" },
+ { "-fintrin-case-initcap", "Intrinsics spelled as e.g. SqRt" },
+ { "-fintrin-case-upper", "Intrinsics in uppercase" },
+ { "-fintrin-case-lower", "" },
+ { "-fintrin-case-any", "Intrinsics letters in arbitrary cases" },
+ { "-fmatch-case-initcap", "Language keywords spelled as e.g. IOStat" },
+ { "-fmatch-case-upper", "Language keywords in uppercase" },
+ { "-fmatch-case-lower", "" },
+ { "-fmatch-case-any", "Language keyword letters in arbitrary cases" },
+ { "-fsource-case-upper", "Internally convert most source to uppercase" },
+ { "-fsource-case-lower", "" },
+ { "-fsource-case-preserve", "Internally preserve source case" },
+ { "-fsymbol-case-initcap", "Symbol names spelled in mixed case" },
+ { "-fsymbol-case-upper", "Symbol names in uppercase" },
+ { "-fsymbol-case-lower", "Symbol names in lowercase" },
+ { "-fsymbol-case-any", "" },
+ { "-fcase-strict-upper", "Program written in uppercase" },
+ { "-fcase-strict-lower", "Program written in lowercase" },
+ { "-fcase-initcap", "Program written in strict mixed-case" },
+ { "-fcase-upper", "Compile as if program written in uppercase" },
+ { "-fcase-lower", "Compile as if program written in lowercase" },
+ { "-fcase-preserve", "Preserve all spelling (case) used in program" },
+ { "-fbadu77-intrinsics-delete", "Delete libU77 intrinsics with bad interfaces" },
+ { "-fbadu77-intrinsics-disable", "Disable libU77 intrinsics with bad interfaces" },
+ { "-fbadu77-intrinsics-enable", "" },
+ { "-fbadu77-intrinsics-hide", "Hide libU77 intrinsics with bad interfaces" },
+ { "-ff2c-intrinsics-delete", "Delete non-FORTRAN-77 intrinsics f2c supports" },
+ { "-ff2c-intrinsics-disable", "Disable non-FORTRAN-77 intrinsics f2c supports" },
+ { "-ff2c-intrinsics-enable", "" },
+ { "-ff2c-intrinsics-hide", "Hide non-FORTRAN-77 intrinsics f2c supports" },
+ { "-ff90-intrinsics-delete", "Delete non-FORTRAN-77 intrinsics F90 supports" },
+ { "-ff90-intrinsics-disable", "Disable non-FORTRAN-77 intrinsics F90 supports" },
+ { "-ff90-intrinsics-enable", "" },
+ { "-ff90-intrinsics-hide", "Hide non-FORTRAN-77 intrinsics F90 supports" },
+ { "-fgnu-intrinsics-delete", "Delete non-FORTRAN-77 intrinsics g77 supports" },
+ { "-fgnu-intrinsics-disable", "Disable non-FORTRAN 77 intrinsics F90 supports" },
+ { "-fgnu-intrinsics-enable", "" },
+ { "-fgnu-intrinsics-hide", "Hide non-FORTRAN 77 intrinsics F90 supports" },
+ { "-fmil-intrinsics-delete", "Delete MIL-STD 1753 intrinsics" },
+ { "-fmil-intrinsics-disable", "Disable MIL-STD 1753 intrinsics" },
+ { "-fmil-intrinsics-enable", "" },
+ { "-fmil-intrinsics-hide", "Hide MIL-STD 1753 intrinsics" },
+ { "-funix-intrinsics-delete", "Delete libU77 intrinsics" },
+ { "-funix-intrinsics-disable", "Disable libU77 intrinsics" },
+ { "-funix-intrinsics-enable", "" },
+ { "-funix-intrinsics-hide", "Hide libU77 intrinsics" },
+ { "-fvxt-intrinsics-delete", "Delete non-FORTRAN-77 intrinsics VXT FORTRAN supports" },
+ { "-fvxt-intrinsics-disable", "Disable non-FORTRAN-77 intrinsics VXT FORTRAN supports" },
+ { "-fvxt-intrinsics-enable", "" },
+ { "-fvxt-intrinsics-hide", "Hide non-FORTRAN-77 intrinsics VXT FORTRAN supports" },
+ { "-fzeros", "Treat initial values of 0 like non-zero values" },
+ { "-fno-zeros", "" },
+ { "-fdebug-kludge", "Emit special debugging information for COMMON and EQUIVALENCE" },
+ { "-fno-debug-kludge", "" },
+ { "-fonetrip", "Take at least one trip through each iterative DO loop" },
+ { "-fno-onetrip", "" },
+ { "-fsilent", "" },
+ { "-fno-silent", "Print names of program units as they are compiled" },
+ { "-fglobals", "" },
+ { "-fno-globals", "Disable fatal diagnostics about inter-procedural problems" },
+ { "-ftypeless-boz", "Make prefix-radix non-decimal constants be typeless" },
+ { "-fno-typeless-boz", "" },
+ { "-Wglobals", "" },
+ { "-Wno-globals", "Disable warnings about inter-procedural problems" },
+/*"-Wimplicit",*/
+/*"-Wno-implicit",*/
+ { "-Wsurprising", "Warn about constructs with surprising meanings" },
+ { "-Wno-surprising", "" },
+/*"-Wall",*/
+/* Prefix options. */
+ { "-I", "Add a directory for INCLUDE searching" },
+ { "-ffixed-line-length-", "Set the maximum line length" },
+
+#endif
diff --git a/contrib/gcc/f/lang-specs.h b/contrib/gcc/f/lang-specs.h
new file mode 100644
index 0000000..bf8786f
--- /dev/null
+++ b/contrib/gcc/f/lang-specs.h
@@ -0,0 +1,106 @@
+/* lang-specs.h file for Fortran
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+*/
+
+/* This is the contribution to the `default_compilers' array in gcc.c for
+ g77. */
+
+ {".F", {"@f77-cpp-input"}},
+ {".fpp", {"@f77-cpp-input"}},
+ {"@f77-cpp-input",
+ /* For f77 we want -traditional to avoid errors with, for
+ instance, mismatched '. Also, we avoid unpleasant surprises
+ with substitution of names not prefixed by `_' by using %P
+ rather than %p (although this isn't consistent with SGI and
+ Sun f77, at least) so you test `__unix' rather than `unix'.
+ -D_LANGUAGE_FORTRAN is used by some compilers like SGI and
+ might as well be in there. */
+ {"cpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ %{C:%{!E:%eGNU C does not support -C without using -E}}\
+ %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
+ -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
+ %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+ %{!undef:%P} -D_LANGUAGE_FORTRAN %{trigraphs} \
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}} -traditional\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
+ %i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
+ "%{!M:%{!MM:%{!E:f771 %{!pipe:%g.i} %(f771) \
+ %{!Q:-quiet} -dumpbase %b.F %{d*} %{m*} %{a}\
+ %{g*} %{O*} %{W*} %{w} %{pedantic*} \
+ %{v:-version -fversion} %{pg:-p} %{p} %{f*} %{I*}\
+ %{aux-info*}\
+ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
+ %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
+ %{!S:as %a %Y\
+ %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
+ %{!pipe:%g.s} %A\n }}}}"}},
+ {".r", {"@ratfor"}},
+ {"@ratfor",
+ {"ratfor %{C} %{v}\
+ %{C:%{!E:%eGNU C does not support -C without using -E}}\
+ %{!E:%{!pipe:-o %g.f}}%{E:%W{o*}} %i |\n",
+ "%{!E:f771 %{!pipe:%g.f} %(f771) \
+ %{!Q:-quiet} -dumpbase %b.r %{d*} %{m*} %{a}\
+ %{g*} %{O*} %{W*} %{w} %{pedantic*} \
+ %{v:-version -fversion} %{pg:-p} %{p} %{f*} %{I*}\
+ %{aux-info*}\
+ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
+ %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
+ %{!S:as %a %Y\
+ %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
+ %{!pipe:%g.s} %A\n }}"}},
+ {".f", {"@f77"}},
+ {".for", {"@f77"}},
+ {"@f77",
+ {"%{!M:%{!MM:%{!E:f771 %i %(f771) \
+ %{!Q:-quiet} -dumpbase %b.f %{d*} %{m*} %{a}\
+ %{g*} %{O*} %{W*} %{w} %{pedantic*}\
+ %{v:-version -fversion} %{pg:-p} %{p} %{f*} %{I*}\
+ %{aux-info*}\
+ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
+ %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
+ %{!S:as %a %Y\
+ %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
+ %{!pipe:%g.s} %A\n }}}}"}},
+ {"@f77-version",
+ {"cpp -lang-c %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I \
+ %{C:%{!E:%eGNU C does not support -C without using -E}} \
+ %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG} \
+ -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 \
+ %{ansi:-trigraphs -$ -D__STRICT_ANSI__} \
+ %{!undef:%P} -D_LANGUAGE_FORTRAN %{trigraphs} \
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}} -traditional \
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z \
+ /dev/null /dev/null \n\
+ f771 -fnull-version %(f771) \
+ %{!Q:-quiet} -dumpbase g77-version.f %{d*} %{m*} %{a} \
+ %{g*} %{O*} %{W*} %{w} %{pedantic*} \
+ -version -fversion %{f*} %{I*} -o %g.s /dev/null \n\
+ as %a %Y -o %g%O %g.s %A \n\
+ ld %l %X -o %g %g%O %{A} %{d} %{e*} %{m} %{N} %{n} \
+ %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} \
+ %{!A:%{!nostdlib:%{!nostartfiles:%S}}} \
+ %{static:} %{L*} %D -lg2c -lm \
+ %{!nostdlib:%{!nodefaultlibs:%G %L %G}} \
+ %{!A:%{!nostdlib:%{!nostartfiles:%E}}} \
+ %{T*} \n\
+ %g \n"}},
diff --git a/contrib/gcc/f/lex.c b/contrib/gcc/f/lex.c
new file mode 100644
index 0000000..c62e5b2
--- /dev/null
+++ b/contrib/gcc/f/lex.c
@@ -0,0 +1,4717 @@
+/* Implementation of Fortran lexer
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "proj.h"
+#include "top.h"
+#include "bad.h"
+#include "com.h"
+#include "lex.h"
+#include "malloc.h"
+#include "src.h"
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#include "flags.j"
+#include "input.j"
+#include "toplev.j"
+#include "tree.j"
+#include "output.j" /* Must follow tree.j so TREE_CODE is defined! */
+#endif
+
+#ifdef DWARF_DEBUGGING_INFO
+void dwarfout_resume_previous_source_file (register unsigned);
+void dwarfout_start_new_source_file (register char *);
+void dwarfout_define (register unsigned, register char *);
+void dwarfout_undef (register unsigned, register char *);
+#endif DWARF_DEBUGGING_INFO
+
+static void ffelex_append_to_token_ (char c);
+static int ffelex_backslash_ (int c, ffewhereColumnNumber col);
+static void ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0,
+ ffewhereColumnNumber cn0);
+static void ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0,
+ ffewhereColumnNumber cn0, ffewhereLineNumber ln1,
+ ffewhereColumnNumber cn1);
+static void ffelex_bad_here_ (int num, ffewhereLineNumber ln0,
+ ffewhereColumnNumber cn0);
+static void ffelex_finish_statement_ (void);
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static int ffelex_get_directive_line_ (char **text, FILE *finput);
+static int ffelex_hash_ (FILE *f);
+#endif
+static ffewhereColumnNumber ffelex_image_char_ (int c,
+ ffewhereColumnNumber col);
+static void ffelex_include_ (void);
+static bool ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col);
+static bool ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col);
+static void ffelex_next_line_ (void);
+static void ffelex_prepare_eos_ (void);
+static void ffelex_send_token_ (void);
+static ffelexHandler ffelex_swallow_tokens_ (ffelexToken t);
+static ffelexToken ffelex_token_new_ (void);
+
+/* Pertaining to the geometry of the input file. */
+
+/* Initial size for card image to be allocated. */
+#define FFELEX_columnINITIAL_SIZE_ 255
+
+/* The card image itself, which grows as source lines get longer. It
+ has room for ffelex_card_size_ + 8 characters, and the length of the
+ current image is ffelex_card_length_. (The + 8 characters are made
+ available for easy handling of tabs and such.) */
+static char *ffelex_card_image_;
+static ffewhereColumnNumber ffelex_card_size_;
+static ffewhereColumnNumber ffelex_card_length_;
+
+/* Max width for free-form lines (ISO F90). */
+#define FFELEX_FREE_MAX_COLUMNS_ 132
+
+/* True if we saw a tab on the current line, as this (currently) means
+ the line is therefore treated as though final_nontab_column_ were
+ infinite. */
+static bool ffelex_saw_tab_;
+
+/* TRUE if current line is known to be erroneous, so don't bother
+ expanding room for it just to display it. */
+static bool ffelex_bad_line_ = FALSE;
+
+/* Last column for vanilla, i.e. non-tabbed, line. Usually 72 or 132. */
+static ffewhereColumnNumber ffelex_final_nontab_column_;
+
+/* Array for quickly deciding what kind of line the current card has,
+ based on its first character. */
+static ffelexType ffelex_first_char_[256];
+
+/* Pertaining to file management. */
+
+/* The wf argument of the most recent active ffelex_file_(fixed,free)
+ function. */
+static ffewhereFile ffelex_current_wf_;
+
+/* TRUE if an INCLUDE statement can be processed (ffelex_set_include
+ can be called). */
+static bool ffelex_permit_include_;
+
+/* TRUE if an INCLUDE statement is pending (ffelex_set_include has been
+ called). */
+static bool ffelex_set_include_;
+
+/* Information on the pending INCLUDE file. */
+static FILE *ffelex_include_file_;
+static bool ffelex_include_free_form_;
+static ffewhereFile ffelex_include_wherefile_;
+
+/* Current master line count. */
+static ffewhereLineNumber ffelex_linecount_current_;
+/* Next master line count. */
+static ffewhereLineNumber ffelex_linecount_next_;
+
+/* ffewhere info on the latest (currently active) line read from the
+ active source file. */
+static ffewhereLine ffelex_current_wl_;
+static ffewhereColumn ffelex_current_wc_;
+
+/* Pertaining to tokens in general. */
+
+/* Initial capacity for text in a CHARACTER/HOLLERITH/NAME/NAMES/NUMBER
+ token. */
+#define FFELEX_columnTOKEN_SIZE_ 63
+#if FFELEX_columnTOKEN_SIZE_ < FFEWHERE_indexMAX
+#error "token size too small!"
+#endif
+
+/* Current token being lexed. */
+static ffelexToken ffelex_token_;
+
+/* Handler for current token. */
+static ffelexHandler ffelex_handler_;
+
+/* TRUE if fixed-form lexer is to generate NAMES instead of NAME tokens. */
+static bool ffelex_names_;
+
+/* TRUE if both lexers are to generate NAMES instead of NAME tokens. */
+static bool ffelex_names_pure_;
+
+/* TRUE if 0-9 starts a NAME token instead of NUMBER, for parsing hex
+ numbers. */
+static bool ffelex_hexnum_;
+
+/* For ffelex_swallow_tokens(). */
+static ffelexHandler ffelex_eos_handler_;
+
+/* Number of tokens sent since last EOS or beginning of input file
+ (include INCLUDEd files). */
+static unsigned long int ffelex_number_of_tokens_;
+
+/* Number of labels sent (as NUMBER tokens) since last reset of
+ ffelex_number_of_tokens_ to 0, should be 0 or 1 in most cases.
+ (Fixed-form source only.) */
+static unsigned long int ffelex_label_tokens_;
+
+/* Metering for token management, to catch token-memory leaks. */
+static long int ffelex_total_tokens_ = 0;
+static long int ffelex_old_total_tokens_ = 1;
+static long int ffelex_token_nextid_ = 0;
+
+/* Pertaining to lexing CHARACTER and HOLLERITH tokens. */
+
+/* >0 if a Hollerith constant of that length might be in mid-lex, used
+ when the next character seen is 'H' or 'h' to enter HOLLERITH lexing
+ mode (see ffelex_raw_mode_). */
+static long int ffelex_expecting_hollerith_;
+
+/* -3: Backslash (escape) sequence being lexed in CHARACTER.
+ -2: Possible closing apostrophe/quote seen in CHARACTER.
+ -1: Lexing CHARACTER.
+ 0: Not lexing CHARACTER or HOLLERITH.
+ >0: Lexing HOLLERITH, value is # chars remaining to expect. */
+static long int ffelex_raw_mode_;
+
+/* When lexing CHARACTER, open quote/apostrophe (either ' or "). */
+static char ffelex_raw_char_;
+
+/* TRUE when backslash processing had to use most recent character
+ to finish its state engine, but that character is not part of
+ the backslash sequence, so must be reconsidered as a "normal"
+ character in CHARACTER/HOLLERITH lexing. */
+static bool ffelex_backslash_reconsider_ = FALSE;
+
+/* Characters preread before lexing happened (might include EOF). */
+static int *ffelex_kludge_chars_ = NULL;
+
+/* Doing the kludge processing, so not initialized yet. */
+static bool ffelex_kludge_flag_ = FALSE;
+
+/* The beginning of a (possible) CHARACTER/HOLLERITH token. */
+static ffewhereLine ffelex_raw_where_line_;
+static ffewhereColumn ffelex_raw_where_col_;
+
+
+/* Call this to append another character to the current token. If it isn't
+ currently big enough for it, it will be enlarged. The current token
+ must be a CHARACTER, HOLLERITH, NAME, NAMES, or NUMBER. */
+
+static void
+ffelex_append_to_token_ (char c)
+{
+ if (ffelex_token_->text == NULL)
+ {
+ ffelex_token_->text
+ = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
+ FFELEX_columnTOKEN_SIZE_ + 1);
+ ffelex_token_->size = FFELEX_columnTOKEN_SIZE_;
+ ffelex_token_->length = 0;
+ }
+ else if (ffelex_token_->length >= ffelex_token_->size)
+ {
+ ffelex_token_->text
+ = malloc_resize_ksr (malloc_pool_image (),
+ ffelex_token_->text,
+ (ffelex_token_->size << 1) + 1,
+ ffelex_token_->size + 1);
+ ffelex_token_->size <<= 1;
+ assert (ffelex_token_->length < ffelex_token_->size);
+ }
+#ifdef MAP_CHARACTER
+Sorry, MAP_CHARACTER is not going to work as expected in GNU Fortran,
+please contact fortran@gnu.org if you wish to fund work to
+port g77 to non-ASCII machines.
+#endif
+ ffelex_token_->text[ffelex_token_->length++] = c;
+}
+
+/* Do backslash (escape) processing for a CHARACTER/HOLLERITH token
+ being lexed. */
+
+static int
+ffelex_backslash_ (int c, ffewhereColumnNumber col)
+{
+ static int state = 0;
+ static unsigned int count;
+ static int code;
+ static unsigned int firstdig = 0;
+ static int nonnull;
+ static ffewhereLineNumber line;
+ static ffewhereColumnNumber column;
+
+ /* See gcc/c-lex.c readescape() for a straightforward version
+ of this state engine for handling backslashes in character/
+ hollerith constants. */
+
+#define wide_flag 0
+#define warn_traditional 0
+#define flag_traditional 0
+
+ switch (state)
+ {
+ case 0:
+ if ((c == '\\')
+ && (ffelex_raw_mode_ != 0)
+ && ffe_is_backslash ())
+ {
+ state = 1;
+ column = col + 1;
+ line = ffelex_linecount_current_;
+ return EOF;
+ }
+ return c;
+
+ case 1:
+ state = 0; /* Assume simple case. */
+ switch (c)
+ {
+ case 'x':
+ if (warn_traditional)
+ {
+ ffebad_start_msg_lex ("The meaning of `\\x' (at %0) varies with -traditional",
+ FFEBAD_severityWARNING);
+ ffelex_bad_here_ (0, line, column);
+ ffebad_finish ();
+ }
+
+ if (flag_traditional)
+ return c;
+
+ code = 0;
+ count = 0;
+ nonnull = 0;
+ state = 2;
+ return EOF;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ code = c - '0';
+ count = 1;
+ state = 3;
+ return EOF;
+
+ case '\\': case '\'': case '"':
+ return c;
+
+#if 0 /* Inappropriate for Fortran. */
+ case '\n':
+ ffelex_next_line_ ();
+ *ignore_ptr = 1;
+ return 0;
+#endif
+
+ case 'n':
+ return TARGET_NEWLINE;
+
+ case 't':
+ return TARGET_TAB;
+
+ case 'r':
+ return TARGET_CR;
+
+ case 'f':
+ return TARGET_FF;
+
+ case 'b':
+ return TARGET_BS;
+
+ case 'a':
+ if (warn_traditional)
+ {
+ ffebad_start_msg_lex ("The meaning of `\\a' (at %0) varies with -traditional",
+ FFEBAD_severityWARNING);
+ ffelex_bad_here_ (0, line, column);
+ ffebad_finish ();
+ }
+
+ if (flag_traditional)
+ return c;
+ return TARGET_BELL;
+
+ case 'v':
+#if 0 /* Vertical tab is present in common usage compilers. */
+ if (flag_traditional)
+ return c;
+#endif
+ return TARGET_VT;
+
+ case 'e':
+ case 'E':
+ case '(':
+ case '{':
+ case '[':
+ case '%':
+ if (pedantic)
+ {
+ char m[2];
+
+ m[0] = c;
+ m[1] = '\0';
+ ffebad_start_msg_lex ("Non-ANSI-C-standard escape sequence `\\%A' at %0",
+ FFEBAD_severityPEDANTIC);
+ ffelex_bad_here_ (0, line, column);
+ ffebad_string (m);
+ ffebad_finish ();
+ }
+ return (c == 'E' || c == 'e') ? 033 : c;
+
+ case '?':
+ return c;
+
+ default:
+ if (c >= 040 && c < 0177)
+ {
+ char m[2];
+
+ m[0] = c;
+ m[1] = '\0';
+ ffebad_start_msg_lex ("Unknown escape sequence `\\%A' at %0",
+ FFEBAD_severityPEDANTIC);
+ ffelex_bad_here_ (0, line, column);
+ ffebad_string (m);
+ ffebad_finish ();
+ }
+ else if (c == EOF)
+ {
+ ffebad_start_msg_lex ("Unterminated escape sequence `\\' at %0",
+ FFEBAD_severityPEDANTIC);
+ ffelex_bad_here_ (0, line, column);
+ ffebad_finish ();
+ }
+ else
+ {
+ char m[20];
+
+ sprintf (&m[0], "%x", c);
+ ffebad_start_msg_lex ("Unknown escape sequence `\\' followed by char code 0x%A at %0",
+ FFEBAD_severityPEDANTIC);
+ ffelex_bad_here_ (0, line, column);
+ ffebad_string (m);
+ ffebad_finish ();
+ }
+ }
+ return c;
+
+ case 2:
+ if ((c >= 'a' && c <= 'f')
+ || (c >= 'A' && c <= 'F')
+ || (c >= '0' && c <= '9'))
+ {
+ code *= 16;
+ if (c >= 'a' && c <= 'f')
+ code += c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ code += c - 'A' + 10;
+ if (c >= '0' && c <= '9')
+ code += c - '0';
+ if (code != 0 || count != 0)
+ {
+ if (count == 0)
+ firstdig = code;
+ count++;
+ }
+ nonnull = 1;
+ return EOF;
+ }
+
+ state = 0;
+
+ if (! nonnull)
+ {
+ ffebad_start_msg_lex ("\\x used at %0 with no following hex digits",
+ FFEBAD_severityFATAL);
+ ffelex_bad_here_ (0, line, column);
+ ffebad_finish ();
+ }
+ else if (count == 0)
+ /* Digits are all 0's. Ok. */
+ ;
+ else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
+ || (count > 1
+ && ((1 << (TYPE_PRECISION (integer_type_node) - (count - 1) * 4))
+ <= (int) firstdig)))
+ {
+ ffebad_start_msg_lex ("Hex escape at %0 out of range",
+ FFEBAD_severityPEDANTIC);
+ ffelex_bad_here_ (0, line, column);
+ ffebad_finish ();
+ }
+ break;
+
+ case 3:
+ if ((c <= '7') && (c >= '0') && (count++ < 3))
+ {
+ code = (code * 8) + (c - '0');
+ return EOF;
+ }
+ state = 0;
+ break;
+
+ default:
+ assert ("bad backslash state" == NULL);
+ abort ();
+ }
+
+ /* Come here when code has a built character, and c is the next
+ character that might (or might not) be the next one in the constant. */
+
+ /* Don't bother doing this check for each character going into
+ CHARACTER or HOLLERITH constants, just the escaped-value ones.
+ gcc apparently checks every single character, which seems
+ like it'd be kinda slow and not worth doing anyway. */
+
+ if (!wide_flag
+ && TYPE_PRECISION (char_type_node) < HOST_BITS_PER_INT
+ && code >= (1 << TYPE_PRECISION (char_type_node)))
+ {
+ ffebad_start_msg_lex ("Escape sequence at %0 out of range for character",
+ FFEBAD_severityFATAL);
+ ffelex_bad_here_ (0, line, column);
+ ffebad_finish ();
+ }
+
+ if (c == EOF)
+ {
+ /* Known end of constant, just append this character. */
+ ffelex_append_to_token_ (code);
+ if (ffelex_raw_mode_ > 0)
+ --ffelex_raw_mode_;
+ return EOF;
+ }
+
+ /* Have two characters to handle. Do the first, then leave it to the
+ caller to detect anything special about the second. */
+
+ ffelex_append_to_token_ (code);
+ if (ffelex_raw_mode_ > 0)
+ --ffelex_raw_mode_;
+ ffelex_backslash_reconsider_ = TRUE;
+ return c;
+}
+
+/* ffelex_bad_1_ -- Issue diagnostic with one source point
+
+ ffelex_bad_1_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1);
+
+ Creates ffewhere line and column objects for the source point, sends them
+ along with the error code to ffebad, then kills the line and column
+ objects before returning. */
+
+static void
+ffelex_bad_1_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0)
+{
+ ffewhereLine wl0;
+ ffewhereColumn wc0;
+
+ wl0 = ffewhere_line_new (ln0);
+ wc0 = ffewhere_column_new (cn0);
+ ffebad_start_lex (errnum);
+ ffebad_here (0, wl0, wc0);
+ ffebad_finish ();
+ ffewhere_line_kill (wl0);
+ ffewhere_column_kill (wc0);
+}
+
+/* ffelex_bad_2_ -- Issue diagnostic with two source points
+
+ ffelex_bad_2_(FFEBAD_SOME_ERROR,ffelex_linecount_current_,column + 1,
+ otherline,othercolumn);
+
+ Creates ffewhere line and column objects for the source points, sends them
+ along with the error code to ffebad, then kills the line and column
+ objects before returning. */
+
+static void
+ffelex_bad_2_ (ffebad errnum, ffewhereLineNumber ln0, ffewhereColumnNumber cn0,
+ ffewhereLineNumber ln1, ffewhereColumnNumber cn1)
+{
+ ffewhereLine wl0, wl1;
+ ffewhereColumn wc0, wc1;
+
+ wl0 = ffewhere_line_new (ln0);
+ wc0 = ffewhere_column_new (cn0);
+ wl1 = ffewhere_line_new (ln1);
+ wc1 = ffewhere_column_new (cn1);
+ ffebad_start_lex (errnum);
+ ffebad_here (0, wl0, wc0);
+ ffebad_here (1, wl1, wc1);
+ ffebad_finish ();
+ ffewhere_line_kill (wl0);
+ ffewhere_column_kill (wc0);
+ ffewhere_line_kill (wl1);
+ ffewhere_column_kill (wc1);
+}
+
+static void
+ffelex_bad_here_ (int n, ffewhereLineNumber ln0,
+ ffewhereColumnNumber cn0)
+{
+ ffewhereLine wl0;
+ ffewhereColumn wc0;
+
+ wl0 = ffewhere_line_new (ln0);
+ wc0 = ffewhere_column_new (cn0);
+ ffebad_here (n, wl0, wc0);
+ ffewhere_line_kill (wl0);
+ ffewhere_column_kill (wc0);
+}
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static int
+ffelex_getc_ (FILE *finput)
+{
+ int c;
+
+ if (ffelex_kludge_chars_ == NULL)
+ return getc (finput);
+
+ c = *ffelex_kludge_chars_++;
+ if (c != 0)
+ return c;
+
+ ffelex_kludge_chars_ = NULL;
+ return getc (finput);
+}
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static int
+ffelex_cfebackslash_ (int *use_d, int *d, FILE *finput)
+{
+ register int c = getc (finput);
+ register int code;
+ register unsigned count;
+ unsigned firstdig = 0;
+ int nonnull;
+
+ *use_d = 0;
+
+ switch (c)
+ {
+ case 'x':
+ if (warn_traditional)
+ warning ("the meaning of `\\x' varies with -traditional");
+
+ if (flag_traditional)
+ return c;
+
+ code = 0;
+ count = 0;
+ nonnull = 0;
+ while (1)
+ {
+ c = getc (finput);
+ if (!(c >= 'a' && c <= 'f')
+ && !(c >= 'A' && c <= 'F')
+ && !(c >= '0' && c <= '9'))
+ {
+ *use_d = 1;
+ *d = c;
+ break;
+ }
+ code *= 16;
+ if (c >= 'a' && c <= 'f')
+ code += c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ code += c - 'A' + 10;
+ if (c >= '0' && c <= '9')
+ code += c - '0';
+ if (code != 0 || count != 0)
+ {
+ if (count == 0)
+ firstdig = code;
+ count++;
+ }
+ nonnull = 1;
+ }
+ if (! nonnull)
+ error ("\\x used with no following hex digits");
+ else if (count == 0)
+ /* Digits are all 0's. Ok. */
+ ;
+ else if ((count - 1) * 4 >= TYPE_PRECISION (integer_type_node)
+ || (count > 1
+ && (((unsigned) 1
+ << (TYPE_PRECISION (integer_type_node) - (count - 1)
+ * 4))
+ <= firstdig)))
+ pedwarn ("hex escape out of range");
+ return code;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7':
+ code = 0;
+ count = 0;
+ while ((c <= '7') && (c >= '0') && (count++ < 3))
+ {
+ code = (code * 8) + (c - '0');
+ c = getc (finput);
+ }
+ *use_d = 1;
+ *d = c;
+ return code;
+
+ case '\\': case '\'': case '"':
+ return c;
+
+ case '\n':
+ ffelex_next_line_ ();
+ *use_d = 2;
+ return 0;
+
+ case EOF:
+ *use_d = 1;
+ *d = EOF;
+ return EOF;
+
+ case 'n':
+ return TARGET_NEWLINE;
+
+ case 't':
+ return TARGET_TAB;
+
+ case 'r':
+ return TARGET_CR;
+
+ case 'f':
+ return TARGET_FF;
+
+ case 'b':
+ return TARGET_BS;
+
+ case 'a':
+ if (warn_traditional)
+ warning ("the meaning of `\\a' varies with -traditional");
+
+ if (flag_traditional)
+ return c;
+ return TARGET_BELL;
+
+ case 'v':
+#if 0 /* Vertical tab is present in common usage compilers. */
+ if (flag_traditional)
+ return c;
+#endif
+ return TARGET_VT;
+
+ case 'e':
+ case 'E':
+ if (pedantic)
+ pedwarn ("non-ANSI-standard escape sequence, `\\%c'", c);
+ return 033;
+
+ case '?':
+ return c;
+
+ /* `\(', etc, are used at beginning of line to avoid confusing Emacs. */
+ case '(':
+ case '{':
+ case '[':
+ /* `\%' is used to prevent SCCS from getting confused. */
+ case '%':
+ if (pedantic)
+ pedwarn ("non-ANSI escape sequence `\\%c'", c);
+ return c;
+ }
+ if (c >= 040 && c < 0177)
+ pedwarn ("unknown escape sequence `\\%c'", c);
+ else
+ pedwarn ("unknown escape sequence: `\\' followed by char code 0x%x", c);
+ return c;
+}
+
+#endif
+/* A miniature version of the C front-end lexer. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static int
+ffelex_cfelex_ (ffelexToken *xtoken, FILE *finput, int c)
+{
+ ffelexToken token;
+ char buff[129];
+ char *p;
+ char *q;
+ char *r;
+ register unsigned buffer_length;
+
+ if ((*xtoken != NULL) && !ffelex_kludge_flag_)
+ ffelex_token_kill (*xtoken);
+
+ switch (c)
+ {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ buffer_length = ARRAY_SIZE (buff);
+ p = &buff[0];
+ q = p;
+ r = &buff[buffer_length];
+ for (;;)
+ {
+ *p++ = c;
+ if (p >= r)
+ {
+ register unsigned bytes_used = (p - q);
+
+ buffer_length *= 2;
+ q = (char *)xrealloc (q, buffer_length);
+ p = &q[bytes_used];
+ r = &q[buffer_length];
+ }
+ c = ffelex_getc_ (finput);
+ if (! ISDIGIT (c))
+ break;
+ }
+ *p = '\0';
+ token = ffelex_token_new_number (q, ffewhere_line_unknown (),
+ ffewhere_column_unknown ());
+
+ if (q != &buff[0])
+ free (q);
+
+ break;
+
+ case '\"':
+ buffer_length = ARRAY_SIZE (buff);
+ p = &buff[0];
+ q = p;
+ r = &buff[buffer_length];
+ c = ffelex_getc_ (finput);
+ for (;;)
+ {
+ bool done = FALSE;
+ int use_d = 0;
+ int d;
+
+ switch (c)
+ {
+ case '\"':
+ c = getc (finput);
+ done = TRUE;
+ break;
+
+ case '\\': /* ~~~~~ */
+ c = ffelex_cfebackslash_ (&use_d, &d, finput);
+ break;
+
+ case EOF:
+ case '\n':
+ fatal ("Badly formed directive -- no closing quote");
+ done = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ if (done)
+ break;
+
+ if (use_d != 2) /* 0=>c, 1=>cd, 2=>nil. */
+ {
+ *p++ = c;
+ if (p >= r)
+ {
+ register unsigned bytes_used = (p - q);
+
+ buffer_length = bytes_used * 2;
+ q = (char *)xrealloc (q, buffer_length);
+ p = &q[bytes_used];
+ r = &q[buffer_length];
+ }
+ }
+ if (use_d == 1)
+ c = d;
+ else
+ c = getc (finput);
+ }
+ *p = '\0';
+ token = ffelex_token_new_character (q, ffewhere_line_unknown (),
+ ffewhere_column_unknown ());
+
+ if (q != &buff[0])
+ free (q);
+
+ break;
+
+ default:
+ token = NULL;
+ break;
+ }
+
+ *xtoken = token;
+ return c;
+}
+#endif
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffelex_file_pop_ (char *input_filename)
+{
+ if (input_file_stack->next)
+ {
+ struct file_stack *p = input_file_stack;
+ input_file_stack = p->next;
+ free (p);
+ input_file_stack_tick++;
+#ifdef DWARF_DEBUGGING_INFO
+ if (debug_info_level == DINFO_LEVEL_VERBOSE
+ && write_symbols == DWARF_DEBUG)
+ dwarfout_resume_previous_source_file (input_file_stack->line);
+#endif /* DWARF_DEBUGGING_INFO */
+ }
+ else
+ error ("#-lines for entering and leaving files don't match");
+
+ /* Now that we've pushed or popped the input stack,
+ update the name in the top element. */
+ if (input_file_stack)
+ input_file_stack->name = input_filename;
+}
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffelex_file_push_ (int old_lineno, char *input_filename)
+{
+ struct file_stack *p
+ = (struct file_stack *) xmalloc (sizeof (struct file_stack));
+
+ input_file_stack->line = old_lineno;
+ p->next = input_file_stack;
+ p->name = input_filename;
+ input_file_stack = p;
+ input_file_stack_tick++;
+#ifdef DWARF_DEBUGGING_INFO
+ if (debug_info_level == DINFO_LEVEL_VERBOSE
+ && write_symbols == DWARF_DEBUG)
+ dwarfout_start_new_source_file (input_filename);
+#endif /* DWARF_DEBUGGING_INFO */
+
+ /* Now that we've pushed or popped the input stack,
+ update the name in the top element. */
+ if (input_file_stack)
+ input_file_stack->name = input_filename;
+}
+#endif
+
+/* Prepare to finish a statement-in-progress by sending the current
+ token, if any, then setting up EOS as the current token with the
+ appropriate current pointer. The caller can then move the current
+ pointer before actually sending EOS, if desired, as it is in
+ typical fixed-form cases. */
+
+static void
+ffelex_prepare_eos_ ()
+{
+ if (ffelex_token_->type != FFELEX_typeNONE)
+ {
+ ffelex_backslash_ (EOF, 0);
+
+ switch (ffelex_raw_mode_)
+ {
+ case -2:
+ break;
+
+ case -1:
+ ffebad_start_lex ((ffelex_raw_char_ == '\'') ? FFEBAD_NO_CLOSING_APOSTROPHE
+ : FFEBAD_NO_CLOSING_QUOTE);
+ ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
+ ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
+ ffebad_finish ();
+ break;
+
+ case 0:
+ break;
+
+ default:
+ {
+ char num[20];
+
+ ffebad_start_lex (FFEBAD_NOT_ENOUGH_HOLLERITH_CHARS);
+ ffebad_here (0, ffelex_token_->where_line, ffelex_token_->where_col);
+ ffebad_here (1, ffelex_current_wl_, ffelex_current_wc_);
+ sprintf (num, "%lu", (unsigned long) ffelex_raw_mode_);
+ ffebad_string (num);
+ ffebad_finish ();
+ /* Make sure the token has some text, might as well fill up with spaces. */
+ do
+ {
+ ffelex_append_to_token_ (' ');
+ } while (--ffelex_raw_mode_ > 0);
+ break;
+ }
+ }
+ ffelex_raw_mode_ = 0;
+ ffelex_send_token_ ();
+ }
+ ffelex_token_->type = FFELEX_typeEOS;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_use (ffelex_current_wc_);
+}
+
+static void
+ffelex_finish_statement_ ()
+{
+ if ((ffelex_number_of_tokens_ == 0)
+ && (ffelex_token_->type == FFELEX_typeNONE))
+ return; /* Don't have a statement pending. */
+
+ if (ffelex_token_->type != FFELEX_typeEOS)
+ ffelex_prepare_eos_ ();
+
+ ffelex_permit_include_ = TRUE;
+ ffelex_send_token_ ();
+ ffelex_permit_include_ = FALSE;
+ ffelex_number_of_tokens_ = 0;
+ ffelex_label_tokens_ = 0;
+ ffelex_names_ = TRUE;
+ ffelex_names_pure_ = FALSE; /* Probably not necessary. */
+ ffelex_hexnum_ = FALSE;
+
+ if (!ffe_is_ffedebug ())
+ return;
+
+ /* For debugging purposes only. */
+
+ if (ffelex_total_tokens_ != ffelex_old_total_tokens_)
+ {
+ fprintf (dmpout, "; token_track had %ld tokens, now have %ld.\n",
+ ffelex_old_total_tokens_, ffelex_total_tokens_);
+ ffelex_old_total_tokens_ = ffelex_total_tokens_;
+ }
+}
+
+/* Copied from gcc/c-common.c get_directive_line. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static int
+ffelex_get_directive_line_ (char **text, FILE *finput)
+{
+ static char *directive_buffer = NULL;
+ static unsigned buffer_length = 0;
+ register char *p;
+ register char *buffer_limit;
+ register int looking_for = 0;
+ register int char_escaped = 0;
+
+ if (buffer_length == 0)
+ {
+ directive_buffer = (char *)xmalloc (128);
+ buffer_length = 128;
+ }
+
+ buffer_limit = &directive_buffer[buffer_length];
+
+ for (p = directive_buffer; ; )
+ {
+ int c;
+
+ /* Make buffer bigger if it is full. */
+ if (p >= buffer_limit)
+ {
+ register unsigned bytes_used = (p - directive_buffer);
+
+ buffer_length *= 2;
+ directive_buffer
+ = (char *)xrealloc (directive_buffer, buffer_length);
+ p = &directive_buffer[bytes_used];
+ buffer_limit = &directive_buffer[buffer_length];
+ }
+
+ c = getc (finput);
+
+ /* Discard initial whitespace. */
+ if ((c == ' ' || c == '\t') && p == directive_buffer)
+ continue;
+
+ /* Detect the end of the directive. */
+ if ((c == '\n' && looking_for == 0)
+ || c == EOF)
+ {
+ if (looking_for != 0)
+ fatal ("Bad directive -- missing close-quote");
+
+ *p++ = '\0';
+ *text = directive_buffer;
+ return c;
+ }
+
+ *p++ = c;
+ if (c == '\n')
+ ffelex_next_line_ ();
+
+ /* Handle string and character constant syntax. */
+ if (looking_for)
+ {
+ if (looking_for == c && !char_escaped)
+ looking_for = 0; /* Found terminator... stop looking. */
+ }
+ else
+ if (c == '\'' || c == '"')
+ looking_for = c; /* Don't stop buffering until we see another
+ one of these (or an EOF). */
+
+ /* Handle backslash. */
+ char_escaped = (c == '\\' && ! char_escaped);
+ }
+}
+#endif
+
+/* Handle # directives that make it through (or are generated by) the
+ preprocessor. As much as reasonably possible, emulate the behavior
+ of the gcc compiler phase cc1, though interactions between #include
+ and INCLUDE might possibly produce bizarre results in terms of
+ error reporting and the generation of debugging info vis-a-vis the
+ locations of some things.
+
+ Returns the next character unhandled, which is always newline or EOF. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static int
+ffelex_hash_ (FILE *finput)
+{
+ register int c;
+ ffelexToken token = NULL;
+
+ /* Read first nonwhite char after the `#'. */
+
+ c = ffelex_getc_ (finput);
+ while (c == ' ' || c == '\t')
+ c = ffelex_getc_ (finput);
+
+ /* If a letter follows, then if the word here is `line', skip
+ it and ignore it; otherwise, ignore the line, with an error
+ if the word isn't `pragma', `ident', `define', or `undef'. */
+
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
+ {
+ if (c == 'p')
+ {
+ if (getc (finput) == 'r'
+ && getc (finput) == 'a'
+ && getc (finput) == 'g'
+ && getc (finput) == 'm'
+ && getc (finput) == 'a'
+ && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
+ || c == EOF))
+ {
+ goto skipline;
+#if 0 /* g77 doesn't handle pragmas, so ignores them FOR NOW. */
+#ifdef HANDLE_SYSV_PRAGMA
+ return handle_sysv_pragma (finput, c);
+#else /* !HANDLE_SYSV_PRAGMA */
+#ifdef HANDLE_PRAGMA
+ HANDLE_PRAGMA (finput);
+#endif /* HANDLE_PRAGMA */
+ goto skipline;
+#endif /* !HANDLE_SYSV_PRAGMA */
+#endif /* 0 */
+ }
+ }
+
+ else if (c == 'd')
+ {
+ if (getc (finput) == 'e'
+ && getc (finput) == 'f'
+ && getc (finput) == 'i'
+ && getc (finput) == 'n'
+ && getc (finput) == 'e'
+ && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
+ || c == EOF))
+ {
+ char *text;
+
+ c = ffelex_get_directive_line_ (&text, finput);
+
+#ifdef DWARF_DEBUGGING_INFO
+ if ((debug_info_level == DINFO_LEVEL_VERBOSE)
+ && (write_symbols == DWARF_DEBUG))
+ dwarfout_define (lineno, text);
+#endif /* DWARF_DEBUGGING_INFO */
+
+ goto skipline;
+ }
+ }
+ else if (c == 'u')
+ {
+ if (getc (finput) == 'n'
+ && getc (finput) == 'd'
+ && getc (finput) == 'e'
+ && getc (finput) == 'f'
+ && ((c = getc (finput)) == ' ' || c == '\t' || c == '\n'
+ || c == EOF))
+ {
+ char *text;
+
+ c = ffelex_get_directive_line_ (&text, finput);
+
+#ifdef DWARF_DEBUGGING_INFO
+ if ((debug_info_level == DINFO_LEVEL_VERBOSE)
+ && (write_symbols == DWARF_DEBUG))
+ dwarfout_undef (lineno, text);
+#endif /* DWARF_DEBUGGING_INFO */
+
+ goto skipline;
+ }
+ }
+ else if (c == 'l')
+ {
+ if (getc (finput) == 'i'
+ && getc (finput) == 'n'
+ && getc (finput) == 'e'
+ && ((c = getc (finput)) == ' ' || c == '\t'))
+ goto linenum;
+ }
+ else if (c == 'i')
+ {
+ if (getc (finput) == 'd'
+ && getc (finput) == 'e'
+ && getc (finput) == 'n'
+ && getc (finput) == 't'
+ && ((c = getc (finput)) == ' ' || c == '\t'))
+ {
+ /* #ident. The pedantic warning is now in cccp.c. */
+
+ /* Here we have just seen `#ident '.
+ A string constant should follow. */
+
+ while (c == ' ' || c == '\t')
+ c = getc (finput);
+
+ /* If no argument, ignore the line. */
+ if (c == '\n' || c == EOF)
+ return c;
+
+ c = ffelex_cfelex_ (&token, finput, c);
+
+ if ((token == NULL)
+ || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
+ {
+ error ("invalid #ident");
+ goto skipline;
+ }
+
+ if (ffe_is_ident ())
+ {
+#ifdef ASM_OUTPUT_IDENT
+ ASM_OUTPUT_IDENT (asm_out_file,
+ ffelex_token_text (token));
+#endif
+ }
+
+ /* Skip the rest of this line. */
+ goto skipline;
+ }
+ }
+
+ error ("undefined or invalid # directive");
+ goto skipline;
+ }
+
+ linenum:
+ /* Here we have either `#line' or `# <nonletter>'.
+ In either case, it should be a line number; a digit should follow. */
+
+ while (c == ' ' || c == '\t')
+ c = ffelex_getc_ (finput);
+
+ /* If the # is the only nonwhite char on the line,
+ just ignore it. Check the new newline. */
+ if (c == '\n' || c == EOF)
+ return c;
+
+ /* Something follows the #; read a token. */
+
+ c = ffelex_cfelex_ (&token, finput, c);
+
+ if ((token != NULL)
+ && (ffelex_token_type (token) == FFELEX_typeNUMBER))
+ {
+ int old_lineno = lineno;
+ char *old_input_filename = input_filename;
+ ffewhereFile wf;
+
+ /* subtract one, because it is the following line that
+ gets the specified number */
+ int l = atoi (ffelex_token_text (token)) - 1;
+
+ /* Is this the last nonwhite stuff on the line? */
+ while (c == ' ' || c == '\t')
+ c = ffelex_getc_ (finput);
+ if (c == '\n' || c == EOF)
+ {
+ /* No more: store the line number and check following line. */
+ lineno = l;
+ if (!ffelex_kludge_flag_)
+ {
+ ffewhere_file_set (NULL, TRUE, (ffewhereLineNumber) l);
+
+ if (token != NULL)
+ ffelex_token_kill (token);
+ }
+ return c;
+ }
+
+ /* More follows: it must be a string constant (filename). */
+
+ /* Read the string constant. */
+ c = ffelex_cfelex_ (&token, finput, c);
+
+ if ((token == NULL)
+ || (ffelex_token_type (token) != FFELEX_typeCHARACTER))
+ {
+ error ("invalid #line");
+ goto skipline;
+ }
+
+ lineno = l;
+
+ if (ffelex_kludge_flag_)
+ input_filename = ffelex_token_text (token);
+ else
+ {
+ wf = ffewhere_file_new (ffelex_token_text (token),
+ ffelex_token_length (token));
+ input_filename = ffewhere_file_name (wf);
+ ffewhere_file_set (wf, TRUE, (ffewhereLineNumber) l);
+ }
+
+#if 0 /* Not sure what g77 should do with this yet. */
+ /* Each change of file name
+ reinitializes whether we are now in a system header. */
+ in_system_header = 0;
+#endif
+
+ if (main_input_filename == 0)
+ main_input_filename = input_filename;
+
+ /* Is this the last nonwhite stuff on the line? */
+ while (c == ' ' || c == '\t')
+ c = getc (finput);
+ if (c == '\n' || c == EOF)
+ {
+ if (!ffelex_kludge_flag_)
+ {
+ /* Update the name in the top element of input_file_stack. */
+ if (input_file_stack)
+ input_file_stack->name = input_filename;
+
+ if (token != NULL)
+ ffelex_token_kill (token);
+ }
+ return c;
+ }
+
+ c = ffelex_cfelex_ (&token, finput, c);
+
+ /* `1' after file name means entering new file.
+ `2' after file name means just left a file. */
+
+ if ((token != NULL)
+ && (ffelex_token_type (token) == FFELEX_typeNUMBER))
+ {
+ int num = atoi (ffelex_token_text (token));
+
+ if (ffelex_kludge_flag_)
+ {
+ lineno = 1;
+ input_filename = old_input_filename;
+ fatal ("Use `#line ...' instead of `# ...' in first line");
+ }
+
+ if (num == 1)
+ {
+ /* Pushing to a new file. */
+ ffelex_file_push_ (old_lineno, input_filename);
+ }
+ else if (num == 2)
+ {
+ /* Popping out of a file. */
+ ffelex_file_pop_ (input_filename);
+ }
+
+ /* Is this the last nonwhite stuff on the line? */
+ while (c == ' ' || c == '\t')
+ c = getc (finput);
+ if (c == '\n' || c == EOF)
+ {
+ if (token != NULL)
+ ffelex_token_kill (token);
+ return c;
+ }
+
+ c = ffelex_cfelex_ (&token, finput, c);
+ }
+
+ /* `3' after file name means this is a system header file. */
+
+#if 0 /* Not sure what g77 should do with this yet. */
+ if ((token != NULL)
+ && (ffelex_token_type (token) == FFELEX_typeNUMBER)
+ && (atoi (ffelex_token_text (token)) == 3))
+ in_system_header = 1;
+#endif
+
+ while (c == ' ' || c == '\t')
+ c = getc (finput);
+ if (((token != NULL)
+ || (c != '\n' && c != EOF))
+ && ffelex_kludge_flag_)
+ {
+ lineno = 1;
+ input_filename = old_input_filename;
+ fatal ("Use `#line ...' instead of `# ...' in first line");
+ }
+ }
+ else
+ error ("invalid #-line");
+
+ /* skip the rest of this line. */
+ skipline:
+ if ((token != NULL) && !ffelex_kludge_flag_)
+ ffelex_token_kill (token);
+ while ((c = getc (finput)) != EOF && c != '\n')
+ ;
+ return c;
+}
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+/* "Image" a character onto the card image, return incremented column number.
+
+ Normally invoking this function as in
+ column = ffelex_image_char_ (c, column);
+ is the same as doing:
+ ffelex_card_image_[column++] = c;
+
+ However, tabs and carriage returns are handled specially, to preserve
+ the visual "image" of the input line (in most editors) in the card
+ image.
+
+ Carriage returns are ignored, as they are assumed to be followed
+ by newlines.
+
+ A tab is handled by first doing:
+ ffelex_card_image_[column++] = ' ';
+ That is, it translates to at least one space. Then, as many spaces
+ are imaged as necessary to bring the column number to the next tab
+ position, where tab positions start in the ninth column and each
+ eighth column afterwards. ALSO, a static var named ffelex_saw_tab_
+ is set to TRUE to notify the lexer that a tab was seen.
+
+ Columns are numbered and tab stops set as illustrated below:
+
+ 012345670123456701234567...
+ x y z
+ xx yy zz
+ ...
+ xxxxxxx yyyyyyy zzzzzzz
+ xxxxxxxx yyyyyyyy... */
+
+static ffewhereColumnNumber
+ffelex_image_char_ (int c, ffewhereColumnNumber column)
+{
+ ffewhereColumnNumber old_column = column;
+
+ if (column >= ffelex_card_size_)
+ {
+ ffewhereColumnNumber newmax = ffelex_card_size_ << 1;
+
+ if (ffelex_bad_line_)
+ return column;
+
+ if ((newmax >> 1) != ffelex_card_size_)
+ { /* Overflowed column number. */
+ overflow: /* :::::::::::::::::::: */
+
+ ffelex_bad_line_ = TRUE;
+ strcpy (&ffelex_card_image_[column - 3], "...");
+ ffelex_card_length_ = column;
+ ffelex_bad_1_ (FFEBAD_LINE_TOO_LONG,
+ ffelex_linecount_current_, column + 1);
+ return column;
+ }
+
+ ffelex_card_image_
+ = malloc_resize_ksr (malloc_pool_image (),
+ ffelex_card_image_,
+ newmax + 9,
+ ffelex_card_size_ + 9);
+ ffelex_card_size_ = newmax;
+ }
+
+ switch (c)
+ {
+ case '\r':
+ break;
+
+ case '\t':
+ ffelex_saw_tab_ = TRUE;
+ ffelex_card_image_[column++] = ' ';
+ while ((column & 7) != 0)
+ ffelex_card_image_[column++] = ' ';
+ break;
+
+ case '\0':
+ if (!ffelex_bad_line_)
+ {
+ ffelex_bad_line_ = TRUE;
+ strcpy (&ffelex_card_image_[column], "[\\0]");
+ ffelex_card_length_ = column + 4;
+ ffebad_start_msg_lex ("Null character at %0 -- line ignored",
+ FFEBAD_severityFATAL);
+ ffelex_bad_here_ (0, ffelex_linecount_current_, column + 1);
+ ffebad_finish ();
+ column += 4;
+ }
+ break;
+
+ default:
+ ffelex_card_image_[column++] = c;
+ break;
+ }
+
+ if (column < old_column)
+ {
+ column = old_column;
+ goto overflow; /* :::::::::::::::::::: */
+ }
+
+ return column;
+}
+
+static void
+ffelex_include_ ()
+{
+ ffewhereFile include_wherefile = ffelex_include_wherefile_;
+ FILE *include_file = ffelex_include_file_;
+ /* The rest of this is to push, and after the INCLUDE file is processed,
+ pop, the static lexer state info that pertains to each particular
+ input file. */
+ char *card_image;
+ ffewhereColumnNumber card_size = ffelex_card_size_;
+ ffewhereColumnNumber card_length = ffelex_card_length_;
+ ffewhereLine current_wl = ffelex_current_wl_;
+ ffewhereColumn current_wc = ffelex_current_wc_;
+ bool saw_tab = ffelex_saw_tab_;
+ ffewhereColumnNumber final_nontab_column = ffelex_final_nontab_column_;
+ ffewhereFile current_wf = ffelex_current_wf_;
+ ffewhereLineNumber linecount_current = ffelex_linecount_current_;
+ ffewhereLineNumber linecount_offset
+ = ffewhere_line_filelinenum (current_wl);
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ int old_lineno = lineno;
+ char *old_input_filename = input_filename;
+#endif
+
+ if (card_length != 0)
+ {
+ card_image = malloc_new_ks (malloc_pool_image (),
+ "FFELEX saved card image",
+ card_length);
+ memcpy (card_image, ffelex_card_image_, card_length);
+ }
+ else
+ card_image = NULL;
+
+ ffelex_set_include_ = FALSE;
+
+ ffelex_next_line_ ();
+
+ ffewhere_file_set (include_wherefile, TRUE, 0);
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffelex_file_push_ (old_lineno, ffewhere_file_name (include_wherefile));
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+ if (ffelex_include_free_form_)
+ ffelex_file_free (include_wherefile, include_file);
+ else
+ ffelex_file_fixed (include_wherefile, include_file);
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffelex_file_pop_ (ffewhere_file_name (current_wf));
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC */
+
+ ffewhere_file_set (current_wf, TRUE, linecount_offset);
+
+ ffecom_close_include (include_file);
+
+ if (card_length != 0)
+ {
+#ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
+#error "need to handle possible reduction of card size here!!"
+#endif
+ assert (ffelex_card_size_ >= card_length); /* It shrunk?? */
+ memcpy (ffelex_card_image_, card_image, card_length);
+ }
+ ffelex_card_image_[card_length] = '\0';
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ input_filename = old_input_filename;
+ lineno = old_lineno;
+#endif
+ ffelex_linecount_current_ = linecount_current;
+ ffelex_current_wf_ = current_wf;
+ ffelex_final_nontab_column_ = final_nontab_column;
+ ffelex_saw_tab_ = saw_tab;
+ ffelex_current_wc_ = current_wc;
+ ffelex_current_wl_ = current_wl;
+ ffelex_card_length_ = card_length;
+ ffelex_card_size_ = card_size;
+}
+
+/* ffelex_is_free_char_ctx_contin_ -- Character Context Continuation?
+
+ ffewhereColumnNumber col;
+ int c; // Char at col.
+ if ((c == '&') && ffelex_is_free_char_ctx_contin_(col + 1))
+ // We have a continuation indicator.
+
+ If there are <n> spaces starting at ffelex_card_image_[col] up through
+ the null character, where <n> is 0 or greater, returns TRUE. */
+
+static bool
+ffelex_is_free_char_ctx_contin_ (ffewhereColumnNumber col)
+{
+ while (ffelex_card_image_[col] != '\0')
+ {
+ if (ffelex_card_image_[col++] != ' ')
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* ffelex_is_free_nonc_ctx_contin_ -- Noncharacter Context Continuation?
+
+ ffewhereColumnNumber col;
+ int c; // Char at col.
+ if ((c == '&') && ffelex_is_free_nonc_ctx_contin_(col + 1))
+ // We have a continuation indicator.
+
+ If there are <n> spaces starting at ffelex_card_image_[col] up through
+ the null character or '!', where <n> is 0 or greater, returns TRUE. */
+
+static bool
+ffelex_is_free_nonc_ctx_contin_ (ffewhereColumnNumber col)
+{
+ while ((ffelex_card_image_[col] != '\0') && (ffelex_card_image_[col] != '!'))
+ {
+ if (ffelex_card_image_[col++] != ' ')
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+ffelex_next_line_ ()
+{
+ ffelex_linecount_current_ = ffelex_linecount_next_;
+ ++ffelex_linecount_next_;
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ++lineno;
+#endif
+}
+
+static void
+ffelex_send_token_ ()
+{
+ ++ffelex_number_of_tokens_;
+
+ ffelex_backslash_ (EOF, 0);
+
+ if (ffelex_token_->text == NULL)
+ {
+ if (ffelex_token_->type == FFELEX_typeCHARACTER)
+ {
+ ffelex_append_to_token_ ('\0');
+ ffelex_token_->length = 0;
+ }
+ }
+ else
+ ffelex_token_->text[ffelex_token_->length] = '\0';
+
+ assert (ffelex_raw_mode_ == 0);
+
+ if (ffelex_token_->type == FFELEX_typeNAMES)
+ {
+ ffewhere_line_kill (ffelex_token_->currentnames_line);
+ ffewhere_column_kill (ffelex_token_->currentnames_col);
+ }
+
+ assert (ffelex_handler_ != NULL);
+ ffelex_handler_ = (ffelexHandler) (*ffelex_handler_) (ffelex_token_);
+ assert (ffelex_handler_ != NULL);
+
+ ffelex_token_kill (ffelex_token_);
+
+ ffelex_token_ = ffelex_token_new_ ();
+ ffelex_token_->uses = 1;
+ ffelex_token_->text = NULL;
+ if (ffelex_raw_mode_ < 0)
+ {
+ ffelex_token_->type = FFELEX_typeCHARACTER;
+ ffelex_token_->where_line = ffelex_raw_where_line_;
+ ffelex_token_->where_col = ffelex_raw_where_col_;
+ ffelex_raw_where_line_ = ffewhere_line_unknown ();
+ ffelex_raw_where_col_ = ffewhere_column_unknown ();
+ }
+ else
+ {
+ ffelex_token_->type = FFELEX_typeNONE;
+ ffelex_token_->where_line = ffewhere_line_unknown ();
+ ffelex_token_->where_col = ffewhere_column_unknown ();
+ }
+
+ if (ffelex_set_include_)
+ ffelex_include_ ();
+}
+
+/* ffelex_swallow_tokens_ -- Eat all tokens delivered to me
+
+ return ffelex_swallow_tokens_;
+
+ Return this handler when you don't want to look at any more tokens in the
+ statement because you've encountered an unrecoverable error in the
+ statement. */
+
+static ffelexHandler
+ffelex_swallow_tokens_ (ffelexToken t)
+{
+ assert (ffelex_eos_handler_ != NULL);
+
+ if ((ffelex_token_type (t) == FFELEX_typeEOS)
+ || (ffelex_token_type (t) == FFELEX_typeSEMICOLON))
+ return (ffelexHandler) (*ffelex_eos_handler_) (t);
+
+ return (ffelexHandler) ffelex_swallow_tokens_;
+}
+
+static ffelexToken
+ffelex_token_new_ ()
+{
+ ffelexToken t;
+
+ ++ffelex_total_tokens_;
+
+ t = (ffelexToken) malloc_new_ks (malloc_pool_image (),
+ "FFELEX token", sizeof (*t));
+ t->id_ = ffelex_token_nextid_++;
+ return t;
+}
+
+static char *
+ffelex_type_string_ (ffelexType type)
+{
+ static char *types[] = {
+ "FFELEX_typeNONE",
+ "FFELEX_typeCOMMENT",
+ "FFELEX_typeEOS",
+ "FFELEX_typeEOF",
+ "FFELEX_typeERROR",
+ "FFELEX_typeRAW",
+ "FFELEX_typeQUOTE",
+ "FFELEX_typeDOLLAR",
+ "FFELEX_typeHASH",
+ "FFELEX_typePERCENT",
+ "FFELEX_typeAMPERSAND",
+ "FFELEX_typeAPOSTROPHE",
+ "FFELEX_typeOPEN_PAREN",
+ "FFELEX_typeCLOSE_PAREN",
+ "FFELEX_typeASTERISK",
+ "FFELEX_typePLUS",
+ "FFELEX_typeMINUS",
+ "FFELEX_typePERIOD",
+ "FFELEX_typeSLASH",
+ "FFELEX_typeNUMBER",
+ "FFELEX_typeOPEN_ANGLE",
+ "FFELEX_typeEQUALS",
+ "FFELEX_typeCLOSE_ANGLE",
+ "FFELEX_typeNAME",
+ "FFELEX_typeCOMMA",
+ "FFELEX_typePOWER",
+ "FFELEX_typeCONCAT",
+ "FFELEX_typeDEBUG",
+ "FFELEX_typeNAMES",
+ "FFELEX_typeHOLLERITH",
+ "FFELEX_typeCHARACTER",
+ "FFELEX_typeCOLON",
+ "FFELEX_typeSEMICOLON",
+ "FFELEX_typeUNDERSCORE",
+ "FFELEX_typeQUESTION",
+ "FFELEX_typeOPEN_ARRAY",
+ "FFELEX_typeCLOSE_ARRAY",
+ "FFELEX_typeCOLONCOLON",
+ "FFELEX_typeREL_LE",
+ "FFELEX_typeREL_NE",
+ "FFELEX_typeREL_EQ",
+ "FFELEX_typePOINTS",
+ "FFELEX_typeREL_GE"
+ };
+
+ if (type >= ARRAY_SIZE (types))
+ return "???";
+ return types[type];
+}
+
+void
+ffelex_display_token (ffelexToken t)
+{
+ if (t == NULL)
+ t = ffelex_token_;
+
+ fprintf (dmpout, "; Token #%lu is %s (line %" ffewhereLineNumber_f "u, col %"
+ ffewhereColumnNumber_f "u)",
+ t->id_,
+ ffelex_type_string_ (t->type),
+ ffewhere_line_number (t->where_line),
+ ffewhere_column_number (t->where_col));
+
+ if (t->text != NULL)
+ fprintf (dmpout, ": \"%.*s\"\n",
+ (int) t->length,
+ t->text);
+ else
+ fprintf (dmpout, ".\n");
+}
+
+/* ffelex_expecting_character -- Tells if next token expected to be CHARACTER
+
+ if (ffelex_expecting_character())
+ // next token delivered by lexer will be CHARACTER.
+
+ If the most recent call to ffelex_set_expecting_hollerith since the last
+ token was delivered by the lexer passed a length of -1, then we return
+ TRUE, because the next token we deliver will be typeCHARACTER, else we
+ return FALSE. */
+
+bool
+ffelex_expecting_character ()
+{
+ return (ffelex_raw_mode_ != 0);
+}
+
+/* ffelex_file_fixed -- Lex a given file in fixed source form
+
+ ffewhere wf;
+ FILE *f;
+ ffelex_file_fixed(wf,f);
+
+ Lexes the file according to Fortran 90 ANSI + VXT specifications. */
+
+ffelexHandler
+ffelex_file_fixed (ffewhereFile wf, FILE *f)
+{
+ register int c = 0; /* Character currently under consideration. */
+ register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
+ bool disallow_continuation_line;
+ bool ignore_disallowed_continuation = FALSE;
+ int latest_char_in_file = 0; /* For getting back into comment-skipping
+ code. */
+ ffelexType lextype;
+ ffewhereColumnNumber first_label_char; /* First char of label --
+ column number. */
+ char label_string[6]; /* Text of label. */
+ int labi; /* Length of label text. */
+ bool finish_statement; /* Previous statement finished? */
+ bool have_content; /* This line have content? */
+ bool just_do_label; /* Nothing but label (and continuation?) on
+ line. */
+
+ /* Lex is called for a particular file, not for a particular program unit.
+ Yet the two events do share common characteristics. The first line in a
+ file or in a program unit cannot be a continuation line. No token can
+ be in mid-formation. No current label for the statement exists, since
+ there is no current statement. */
+
+ assert (ffelex_handler_ != NULL);
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ lineno = 0;
+ input_filename = ffewhere_file_name (wf);
+#endif
+ ffelex_current_wf_ = wf;
+ disallow_continuation_line = TRUE;
+ ignore_disallowed_continuation = FALSE;
+ ffelex_token_->type = FFELEX_typeNONE;
+ ffelex_number_of_tokens_ = 0;
+ ffelex_label_tokens_ = 0;
+ ffelex_current_wl_ = ffewhere_line_unknown ();
+ ffelex_current_wc_ = ffewhere_column_unknown ();
+ latest_char_in_file = '\n';
+
+ if (ffe_is_null_version ())
+ {
+ /* Just substitute a "program" directly here. */
+
+ char line[] = " call g77__fvers;call g77__ivers;call g77__uvers;end";
+ char *p;
+
+ column = 0;
+ for (p = &line[0]; *p != '\0'; ++p)
+ column = ffelex_image_char_ (*p, column);
+
+ c = EOF;
+
+ goto have_line; /* :::::::::::::::::::: */
+ }
+
+ goto first_line; /* :::::::::::::::::::: */
+
+ /* Come here to get a new line. */
+
+ beginning_of_line: /* :::::::::::::::::::: */
+
+ disallow_continuation_line = FALSE;
+
+ /* Come here directly when last line didn't clarify the continuation issue. */
+
+ beginning_of_line_again: /* :::::::::::::::::::: */
+
+#ifdef REDUCE_CARD_SIZE_AFTER_BIGGY /* Define if occasional large lines. */
+ if (ffelex_card_size_ != FFELEX_columnINITIAL_SIZE_)
+ {
+ ffelex_card_image_
+ = malloc_resize_ks (malloc_pool_image (),
+ ffelex_card_image_,
+ FFELEX_columnINITIAL_SIZE_ + 9,
+ ffelex_card_size_ + 9);
+ ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
+ }
+#endif
+
+ first_line: /* :::::::::::::::::::: */
+
+ c = latest_char_in_file;
+ if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
+ {
+
+ end_of_file: /* :::::::::::::::::::: */
+
+ /* Line ending in EOF instead of \n still counts as a whole line. */
+
+ ffelex_finish_statement_ ();
+ ffewhere_line_kill (ffelex_current_wl_);
+ ffewhere_column_kill (ffelex_current_wc_);
+ return (ffelexHandler) ffelex_handler_;
+ }
+
+ ffelex_next_line_ ();
+
+ ffelex_bad_line_ = FALSE;
+
+ /* Skip over comment (and otherwise ignored) lines as quickly as possible! */
+
+ while (((lextype = ffelex_first_char_[c]) == FFELEX_typeCOMMENT)
+ || (lextype == FFELEX_typeERROR)
+ || (lextype == FFELEX_typeSLASH)
+ || (lextype == FFELEX_typeHASH))
+ {
+ /* Test most frequent type of line first, etc. */
+ if ((lextype == FFELEX_typeCOMMENT)
+ || ((lextype == FFELEX_typeSLASH)
+ && ((c = getc (f)) == '*'))) /* NOTE SIDE-EFFECT. */
+ {
+ /* Typical case (straight comment), just ignore rest of line. */
+ comment_line: /* :::::::::::::::::::: */
+
+ while ((c != '\n') && (c != EOF))
+ c = getc (f);
+ }
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ else if (lextype == FFELEX_typeHASH)
+ c = ffelex_hash_ (f);
+#endif
+ else if (lextype == FFELEX_typeSLASH)
+ {
+ /* SIDE-EFFECT ABOVE HAS HAPPENED. */
+ ffelex_card_image_[0] = '/';
+ ffelex_card_image_[1] = c;
+ column = 2;
+ goto bad_first_character; /* :::::::::::::::::::: */
+ }
+ else
+ /* typeERROR or unsupported typeHASH. */
+ { /* Bad first character, get line and display
+ it with message. */
+ column = ffelex_image_char_ (c, 0);
+
+ bad_first_character: /* :::::::::::::::::::: */
+
+ ffelex_bad_line_ = TRUE;
+ while (((c = getc (f)) != '\n') && (c != EOF))
+ column = ffelex_image_char_ (c, column);
+ ffelex_card_image_[column] = '\0';
+ ffelex_card_length_ = column;
+ ffelex_bad_1_ (FFEBAD_FIRST_CHAR_INVALID,
+ ffelex_linecount_current_, 1);
+ }
+
+ /* Read past last char in line. */
+
+ if (c == EOF)
+ {
+ ffelex_next_line_ ();
+ goto end_of_file; /* :::::::::::::::::::: */
+ }
+
+ c = getc (f);
+
+ ffelex_next_line_ ();
+
+ if (c == EOF)
+ goto end_of_file; /* :::::::::::::::::::: */
+
+ ffelex_bad_line_ = FALSE;
+ } /* while [c, first char, means comment] */
+
+ ffelex_saw_tab_
+ = (c == '&')
+ || (ffelex_final_nontab_column_ == 0);
+
+ if (lextype == FFELEX_typeDEBUG)
+ c = ' '; /* A 'D' or 'd' in column 1 with the
+ debug-lines option on. */
+
+ column = ffelex_image_char_ (c, 0);
+
+ /* Read the entire line in as is (with whitespace processing). */
+
+ while (((c = getc (f)) != '\n') && (c != EOF))
+ column = ffelex_image_char_ (c, column);
+
+ if (ffelex_bad_line_)
+ {
+ ffelex_card_image_[column] = '\0';
+ ffelex_card_length_ = column;
+ goto comment_line; /* :::::::::::::::::::: */
+ }
+
+ /* If no tab, cut off line after column 72/132. */
+
+ if (!ffelex_saw_tab_ && (column > ffelex_final_nontab_column_))
+ {
+ /* Technically, we should now fill ffelex_card_image_ up thru column
+ 72/132 with spaces, since character/hollerith constants must count
+ them in that manner. To save CPU time in several ways (avoid a loop
+ here that would be used only when we actually end a line in
+ character-constant mode; avoid writing memory unnecessarily; avoid a
+ loop later checking spaces when not scanning for character-constant
+ characters), we don't do this, and we do the appropriate thing when
+ we encounter end-of-line while actually processing a character
+ constant. */
+
+ column = ffelex_final_nontab_column_;
+ }
+
+ have_line: /* :::::::::::::::::::: */
+
+ ffelex_card_image_[column] = '\0';
+ ffelex_card_length_ = column;
+
+ /* Save next char in file so we can use register-based c while analyzing
+ line we just read. */
+
+ latest_char_in_file = c; /* Should be either '\n' or EOF. */
+
+ have_content = FALSE;
+
+ /* Handle label, if any. */
+
+ labi = 0;
+ first_label_char = FFEWHERE_columnUNKNOWN;
+ for (column = 0; column < 5; ++column)
+ {
+ switch (c = ffelex_card_image_[column])
+ {
+ case '\0':
+ case '!':
+ goto stop_looking; /* :::::::::::::::::::: */
+
+ case ' ':
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ label_string[labi++] = c;
+ if (first_label_char == FFEWHERE_columnUNKNOWN)
+ first_label_char = column + 1;
+ break;
+
+ case '&':
+ if (column != 0)
+ {
+ ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
+ ffelex_linecount_current_,
+ column + 1);
+ goto beginning_of_line_again; /* :::::::::::::::::::: */
+ }
+ if (ffe_is_pedantic ())
+ ffelex_bad_1_ (FFEBAD_AMPERSAND,
+ ffelex_linecount_current_, 1);
+ finish_statement = FALSE;
+ just_do_label = FALSE;
+ goto got_a_continuation; /* :::::::::::::::::::: */
+
+ case '/':
+ if (ffelex_card_image_[column + 1] == '*')
+ goto stop_looking; /* :::::::::::::::::::: */
+ /* Fall through. */
+ default:
+ ffelex_bad_1_ (FFEBAD_LABEL_FIELD_NOT_NUMERIC,
+ ffelex_linecount_current_, column + 1);
+ goto beginning_of_line_again; /* :::::::::::::::::::: */
+ }
+ }
+
+ stop_looking: /* :::::::::::::::::::: */
+
+ label_string[labi] = '\0';
+
+ /* Find first nonblank char starting with continuation column. */
+
+ if (column == 5) /* In which case we didn't see end of line in
+ label field. */
+ while ((c = ffelex_card_image_[column]) == ' ')
+ ++column;
+
+ /* Now we're trying to figure out whether this is a continuation line and
+ whether there's anything else of substance on the line. The cases are
+ as follows:
+
+ 1. If a line has an explicit continuation character (other than the digit
+ zero), then if it also has a label, the label is ignored and an error
+ message is printed. Any remaining text on the line is passed to the
+ parser tasks, thus even an all-blank line (possibly with an ignored
+ label) aside from a positive continuation character might have meaning
+ in the midst of a character or hollerith constant.
+
+ 2. If a line has no explicit continuation character (that is, it has a
+ space in column 6 and the first non-space character past column 6 is
+ not a digit 0-9), then there are two possibilities:
+
+ A. A label is present and/or a non-space (and non-comment) character
+ appears somewhere after column 6. Terminate processing of the previous
+ statement, if any, send the new label for the next statement, if any,
+ and start processing a new statement with this non-blank character, if
+ any.
+
+ B. The line is essentially blank, except for a possible comment character.
+ Don't terminate processing of the previous statement and don't pass any
+ characters to the parser tasks, since the line is not flagged as a
+ continuation line. We treat it just like a completely blank line.
+
+ 3. If a line has a continuation character of zero (0), then we terminate
+ processing of the previous statement, if any, send the new label for the
+ next statement, if any, and start processing a new statement, if any
+ non-blank characters are present.
+
+ If, when checking to see if we should terminate the previous statement, it
+ is found that there is no previous statement but that there is an
+ outstanding label, substitute CONTINUE as the statement for the label
+ and display an error message. */
+
+ finish_statement = FALSE;
+ just_do_label = FALSE;
+
+ switch (c)
+ {
+ case '!': /* ANSI Fortran 90 says ! in column 6 is
+ continuation. */
+ /* VXT Fortran says ! anywhere is comment, even column 6. */
+ if (ffe_is_vxt () || (column != 5))
+ goto no_tokens_on_line; /* :::::::::::::::::::: */
+ goto got_a_continuation; /* :::::::::::::::::::: */
+
+ case '/':
+ if (ffelex_card_image_[column + 1] != '*')
+ goto some_other_character; /* :::::::::::::::::::: */
+ /* Fall through. */
+ if (column == 5)
+ {
+ /* This seems right to do. But it is close to call, since / * starting
+ in column 6 will thus be interpreted as a continuation line
+ beginning with '*'. */
+
+ goto got_a_continuation;/* :::::::::::::::::::: */
+ }
+ /* Fall through. */
+ case '\0':
+ /* End of line. Therefore may be continued-through line, so handle
+ pending label as possible to-be-continued and drive end-of-statement
+ for any previous statement, else treat as blank line. */
+
+ no_tokens_on_line: /* :::::::::::::::::::: */
+
+ if (ffe_is_pedantic () && (c == '/'))
+ ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
+ ffelex_linecount_current_, column + 1);
+ if (first_label_char != FFEWHERE_columnUNKNOWN)
+ { /* Can't be a continued-through line if it
+ has a label. */
+ finish_statement = TRUE;
+ have_content = TRUE;
+ just_do_label = TRUE;
+ break;
+ }
+ goto beginning_of_line_again; /* :::::::::::::::::::: */
+
+ case '0':
+ if (ffe_is_pedantic () && (column != 5))
+ ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
+ ffelex_linecount_current_, column + 1);
+ finish_statement = TRUE;
+ goto check_for_content; /* :::::::::::::::::::: */
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+
+ /* NOTE: This label can be reached directly from the code
+ that lexes the label field in columns 1-5. */
+ got_a_continuation: /* :::::::::::::::::::: */
+
+ if (first_label_char != FFEWHERE_columnUNKNOWN)
+ {
+ ffelex_bad_2_ (FFEBAD_LABEL_ON_CONTINUATION,
+ ffelex_linecount_current_,
+ first_label_char,
+ ffelex_linecount_current_,
+ column + 1);
+ first_label_char = FFEWHERE_columnUNKNOWN;
+ }
+ if (disallow_continuation_line)
+ {
+ if (!ignore_disallowed_continuation)
+ ffelex_bad_1_ (FFEBAD_INVALID_CONTINUATION,
+ ffelex_linecount_current_, column + 1);
+ goto beginning_of_line_again; /* :::::::::::::::::::: */
+ }
+ if (ffe_is_pedantic () && (column != 5))
+ ffelex_bad_1_ (FFEBAD_NON_ANSI_CONTINUATION_COLUMN,
+ ffelex_linecount_current_, column + 1);
+ if ((ffelex_raw_mode_ != 0)
+ && (((c = ffelex_card_image_[column + 1]) != '\0')
+ || !ffelex_saw_tab_))
+ {
+ ++column;
+ have_content = TRUE;
+ break;
+ }
+
+ check_for_content: /* :::::::::::::::::::: */
+
+ while ((c = ffelex_card_image_[++column]) == ' ')
+ ;
+ if ((c == '\0')
+ || (c == '!')
+ || ((c == '/')
+ && (ffelex_card_image_[column + 1] == '*')))
+ {
+ if (ffe_is_pedantic () && (c == '/'))
+ ffelex_bad_1_ (FFEBAD_NON_ANSI_COMMENT,
+ ffelex_linecount_current_, column + 1);
+ just_do_label = TRUE;
+ }
+ else
+ have_content = TRUE;
+ break;
+
+ default:
+
+ some_other_character: /* :::::::::::::::::::: */
+
+ if (column == 5)
+ goto got_a_continuation;/* :::::::::::::::::::: */
+
+ /* Here is the very normal case of a regular character starting in
+ column 7 or beyond with a blank in column 6. */
+
+ finish_statement = TRUE;
+ have_content = TRUE;
+ break;
+ }
+
+ if (have_content
+ || (first_label_char != FFEWHERE_columnUNKNOWN))
+ {
+ /* The line has content of some kind, install new end-statement
+ point for error messages. Note that "content" includes cases
+ where there's little apparent content but enough to finish
+ a statement. That's because finishing a statement can trigger
+ an impending INCLUDE, and that requires accurate line info being
+ maintained by the lexer. */
+
+ if (finish_statement)
+ ffelex_prepare_eos_ (); /* Prepare EOS before we move current pointer. */
+
+ ffewhere_line_kill (ffelex_current_wl_);
+ ffewhere_column_kill (ffelex_current_wc_);
+ ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
+ ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
+ }
+
+ /* We delay this for a combination of reasons. Mainly, it can start
+ INCLUDE processing, and we want to delay that until the lexer's
+ info on the line is coherent. And we want to delay that until we're
+ sure there's a reason to make that info coherent, to avoid saving
+ lots of useless lines. */
+
+ if (finish_statement)
+ ffelex_finish_statement_ ();
+
+ /* If label is present, enclose it in a NUMBER token and send it along. */
+
+ if (first_label_char != FFEWHERE_columnUNKNOWN)
+ {
+ assert (ffelex_token_->type == FFELEX_typeNONE);
+ ffelex_token_->type = FFELEX_typeNUMBER;
+ ffelex_append_to_token_ ('\0'); /* Make room for label text. */
+ strcpy (ffelex_token_->text, label_string);
+ ffelex_token_->where_line
+ = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (first_label_char);
+ ffelex_token_->length = labi;
+ ffelex_send_token_ ();
+ ++ffelex_label_tokens_;
+ }
+
+ if (just_do_label)
+ goto beginning_of_line; /* :::::::::::::::::::: */
+
+ /* Here is the main engine for parsing. c holds the character at column.
+ It is already known that c is not a blank, end of line, or shriek,
+ unless ffelex_raw_mode_ is not 0 (indicating we are in a
+ character/hollerith constant). A partially filled token may already
+ exist in ffelex_token_. One special case: if, when the end of the line
+ is reached, continuation_line is FALSE and the only token on the line is
+ END, then it is indeed the last statement. We don't look for
+ continuation lines during this program unit in that case. This is
+ according to ANSI. */
+
+ if (ffelex_raw_mode_ != 0)
+ {
+
+ parse_raw_character: /* :::::::::::::::::::: */
+
+ if (c == '\0')
+ {
+ ffewhereColumnNumber i;
+
+ if (ffelex_saw_tab_ || (column >= ffelex_final_nontab_column_))
+ goto beginning_of_line; /* :::::::::::::::::::: */
+
+ /* Pad out line with "virtual" spaces. */
+
+ for (i = column; i < ffelex_final_nontab_column_; ++i)
+ ffelex_card_image_[i] = ' ';
+ ffelex_card_image_[i] = '\0';
+ ffelex_card_length_ = i;
+ c = ' ';
+ }
+
+ switch (ffelex_raw_mode_)
+ {
+ case -3:
+ c = ffelex_backslash_ (c, column);
+ if (c == EOF)
+ break;
+
+ if (!ffelex_backslash_reconsider_)
+ ffelex_append_to_token_ (c);
+ ffelex_raw_mode_ = -1;
+ break;
+
+ case -2:
+ if (c == ffelex_raw_char_)
+ {
+ ffelex_raw_mode_ = -1;
+ ffelex_append_to_token_ (c);
+ }
+ else
+ {
+ ffelex_raw_mode_ = 0;
+ ffelex_backslash_reconsider_ = TRUE;
+ }
+ break;
+
+ case -1:
+ if (c == ffelex_raw_char_)
+ ffelex_raw_mode_ = -2;
+ else
+ {
+ c = ffelex_backslash_ (c, column);
+ if (c == EOF)
+ {
+ ffelex_raw_mode_ = -3;
+ break;
+ }
+
+ ffelex_append_to_token_ (c);
+ }
+ break;
+
+ default:
+ c = ffelex_backslash_ (c, column);
+ if (c == EOF)
+ break;
+
+ if (!ffelex_backslash_reconsider_)
+ {
+ ffelex_append_to_token_ (c);
+ --ffelex_raw_mode_;
+ }
+ break;
+ }
+
+ if (ffelex_backslash_reconsider_)
+ ffelex_backslash_reconsider_ = FALSE;
+ else
+ c = ffelex_card_image_[++column];
+
+ if (ffelex_raw_mode_ == 0)
+ {
+ ffelex_send_token_ ();
+ assert (ffelex_raw_mode_ == 0);
+ while (c == ' ')
+ c = ffelex_card_image_[++column];
+ if ((c == '\0')
+ || (c == '!')
+ || ((c == '/')
+ && (ffelex_card_image_[column + 1] == '*')))
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ goto parse_nonraw_character; /* :::::::::::::::::::: */
+ }
+ goto parse_raw_character; /* :::::::::::::::::::: */
+ }
+
+ parse_nonraw_character: /* :::::::::::::::::::: */
+
+ switch (ffelex_token_->type)
+ {
+ case FFELEX_typeNONE:
+ switch (c)
+ {
+ case '\"':
+ ffelex_token_->type = FFELEX_typeQUOTE;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '$':
+ ffelex_token_->type = FFELEX_typeDOLLAR;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '%':
+ ffelex_token_->type = FFELEX_typePERCENT;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '&':
+ ffelex_token_->type = FFELEX_typeAMPERSAND;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '\'':
+ ffelex_token_->type = FFELEX_typeAPOSTROPHE;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '(':
+ ffelex_token_->type = FFELEX_typeOPEN_PAREN;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case ')':
+ ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '*':
+ ffelex_token_->type = FFELEX_typeASTERISK;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case '+':
+ ffelex_token_->type = FFELEX_typePLUS;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case ',':
+ ffelex_token_->type = FFELEX_typeCOMMA;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '-':
+ ffelex_token_->type = FFELEX_typeMINUS;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '.':
+ ffelex_token_->type = FFELEX_typePERIOD;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '/':
+ ffelex_token_->type = FFELEX_typeSLASH;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ ffelex_token_->type
+ = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_append_to_token_ (c);
+ break;
+
+ case ':':
+ ffelex_token_->type = FFELEX_typeCOLON;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case ';':
+ ffelex_token_->type = FFELEX_typeSEMICOLON;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_permit_include_ = TRUE;
+ ffelex_send_token_ ();
+ ffelex_permit_include_ = FALSE;
+ break;
+
+ case '<':
+ ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case '=':
+ ffelex_token_->type = FFELEX_typeEQUALS;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case '>':
+ ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case '?':
+ ffelex_token_->type = FFELEX_typeQUESTION;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '_':
+ if (1 || ffe_is_90 ())
+ {
+ ffelex_token_->type = FFELEX_typeUNDERSCORE;
+ ffelex_token_->where_line
+ = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col
+ = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+ }
+ /* Fall through. */
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ c = ffesrc_char_source (c);
+
+ if (ffesrc_char_match_init (c, 'H', 'h')
+ && ffelex_expecting_hollerith_ != 0)
+ {
+ ffelex_raw_mode_ = ffelex_expecting_hollerith_;
+ ffelex_token_->type = FFELEX_typeHOLLERITH;
+ ffelex_token_->where_line = ffelex_raw_where_line_;
+ ffelex_token_->where_col = ffelex_raw_where_col_;
+ ffelex_raw_where_line_ = ffewhere_line_unknown ();
+ ffelex_raw_where_col_ = ffewhere_column_unknown ();
+ c = ffelex_card_image_[++column];
+ goto parse_raw_character; /* :::::::::::::::::::: */
+ }
+
+ if (ffelex_names_)
+ {
+ ffelex_token_->where_line
+ = ffewhere_line_use (ffelex_token_->currentnames_line
+ = ffewhere_line_use (ffelex_current_wl_));
+ ffelex_token_->where_col
+ = ffewhere_column_use (ffelex_token_->currentnames_col
+ = ffewhere_column_new (column + 1));
+ ffelex_token_->type = FFELEX_typeNAMES;
+ }
+ else
+ {
+ ffelex_token_->where_line
+ = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_token_->type = FFELEX_typeNAME;
+ }
+ ffelex_append_to_token_ (c);
+ break;
+
+ default:
+ ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
+ ffelex_linecount_current_, column + 1);
+ ffelex_finish_statement_ ();
+ disallow_continuation_line = TRUE;
+ ignore_disallowed_continuation = TRUE;
+ goto beginning_of_line_again; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeNAME:
+ switch (c)
+ {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ c = ffesrc_char_source (c);
+ /* Fall through. */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '_':
+ case '$':
+ if ((c == '$')
+ && !ffe_is_dollar_ok ())
+ {
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ ffelex_append_to_token_ (c);
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeNAMES:
+ switch (c)
+ {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ c = ffesrc_char_source (c);
+ /* Fall through. */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '_':
+ case '$':
+ if ((c == '$')
+ && !ffe_is_dollar_ok ())
+ {
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ if (ffelex_token_->length < FFEWHERE_indexMAX)
+ {
+ ffewhere_track (&ffelex_token_->currentnames_line,
+ &ffelex_token_->currentnames_col,
+ ffelex_token_->wheretrack,
+ ffelex_token_->length,
+ ffelex_linecount_current_,
+ column + 1);
+ }
+ ffelex_append_to_token_ (c);
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeNUMBER:
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ ffelex_append_to_token_ (c);
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeASTERISK:
+ switch (c)
+ {
+ case '*': /* ** */
+ ffelex_token_->type = FFELEX_typePOWER;
+ ffelex_send_token_ ();
+ break;
+
+ default: /* * not followed by another *. */
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeCOLON:
+ switch (c)
+ {
+ case ':': /* :: */
+ ffelex_token_->type = FFELEX_typeCOLONCOLON;
+ ffelex_send_token_ ();
+ break;
+
+ default: /* : not followed by another :. */
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeSLASH:
+ switch (c)
+ {
+ case '/': /* // */
+ ffelex_token_->type = FFELEX_typeCONCAT;
+ ffelex_send_token_ ();
+ break;
+
+ case ')': /* /) */
+ ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
+ ffelex_send_token_ ();
+ break;
+
+ case '=': /* /= */
+ ffelex_token_->type = FFELEX_typeREL_NE;
+ ffelex_send_token_ ();
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeOPEN_PAREN:
+ switch (c)
+ {
+ case '/': /* (/ */
+ ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
+ ffelex_send_token_ ();
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeOPEN_ANGLE:
+ switch (c)
+ {
+ case '=': /* <= */
+ ffelex_token_->type = FFELEX_typeREL_LE;
+ ffelex_send_token_ ();
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeEQUALS:
+ switch (c)
+ {
+ case '=': /* == */
+ ffelex_token_->type = FFELEX_typeREL_EQ;
+ ffelex_send_token_ ();
+ break;
+
+ case '>': /* => */
+ ffelex_token_->type = FFELEX_typePOINTS;
+ ffelex_send_token_ ();
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeCLOSE_ANGLE:
+ switch (c)
+ {
+ case '=': /* >= */
+ ffelex_token_->type = FFELEX_typeREL_GE;
+ ffelex_send_token_ ();
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ default:
+ assert ("Serious error!!" == NULL);
+ abort ();
+ break;
+ }
+
+ c = ffelex_card_image_[++column];
+
+ parse_next_character: /* :::::::::::::::::::: */
+
+ if (ffelex_raw_mode_ != 0)
+ goto parse_raw_character; /* :::::::::::::::::::: */
+
+ while (c == ' ')
+ c = ffelex_card_image_[++column];
+
+ if ((c == '\0')
+ || (c == '!')
+ || ((c == '/')
+ && (ffelex_card_image_[column + 1] == '*')))
+ {
+ if ((ffelex_number_of_tokens_ == ffelex_label_tokens_)
+ && (ffelex_token_->type == FFELEX_typeNAMES)
+ && (ffelex_token_->length == 3)
+ && (ffesrc_strncmp_2c (ffe_case_match (),
+ ffelex_token_->text,
+ "END", "end", "End",
+ 3)
+ == 0))
+ {
+ ffelex_finish_statement_ ();
+ disallow_continuation_line = TRUE;
+ ignore_disallowed_continuation = FALSE;
+ goto beginning_of_line_again; /* :::::::::::::::::::: */
+ }
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ }
+ goto parse_nonraw_character; /* :::::::::::::::::::: */
+}
+
+/* ffelex_file_free -- Lex a given file in free source form
+
+ ffewhere wf;
+ FILE *f;
+ ffelex_file_free(wf,f);
+
+ Lexes the file according to Fortran 90 ANSI + VXT specifications. */
+
+ffelexHandler
+ffelex_file_free (ffewhereFile wf, FILE *f)
+{
+ register int c = 0; /* Character currently under consideration. */
+ register ffewhereColumnNumber column = 0; /* Not really; 0 means column 1... */
+ bool continuation_line = FALSE;
+ ffewhereColumnNumber continuation_column;
+ int latest_char_in_file = 0; /* For getting back into comment-skipping
+ code. */
+
+ /* Lex is called for a particular file, not for a particular program unit.
+ Yet the two events do share common characteristics. The first line in a
+ file or in a program unit cannot be a continuation line. No token can
+ be in mid-formation. No current label for the statement exists, since
+ there is no current statement. */
+
+ assert (ffelex_handler_ != NULL);
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ lineno = 0;
+ input_filename = ffewhere_file_name (wf);
+#endif
+ ffelex_current_wf_ = wf;
+ continuation_line = FALSE;
+ ffelex_token_->type = FFELEX_typeNONE;
+ ffelex_number_of_tokens_ = 0;
+ ffelex_current_wl_ = ffewhere_line_unknown ();
+ ffelex_current_wc_ = ffewhere_column_unknown ();
+ latest_char_in_file = '\n';
+
+ /* Come here to get a new line. */
+
+ beginning_of_line: /* :::::::::::::::::::: */
+
+ c = latest_char_in_file;
+ if ((c == EOF) || ((c = ffelex_getc_ (f)) == EOF))
+ {
+
+ end_of_file: /* :::::::::::::::::::: */
+
+ /* Line ending in EOF instead of \n still counts as a whole line. */
+
+ ffelex_finish_statement_ ();
+ ffewhere_line_kill (ffelex_current_wl_);
+ ffewhere_column_kill (ffelex_current_wc_);
+ return (ffelexHandler) ffelex_handler_;
+ }
+
+ ffelex_next_line_ ();
+
+ ffelex_bad_line_ = FALSE;
+
+ /* Skip over initial-comment and empty lines as quickly as possible! */
+
+ while ((c == '\n')
+ || (c == '!')
+ || (c == '#'))
+ {
+ if (c == '#')
+ {
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ c = ffelex_hash_ (f);
+#else
+ /* Don't skip over # line after all. */
+ break;
+#endif
+ }
+
+ comment_line: /* :::::::::::::::::::: */
+
+ while ((c != '\n') && (c != EOF))
+ c = getc (f);
+
+ if (c == EOF)
+ {
+ ffelex_next_line_ ();
+ goto end_of_file; /* :::::::::::::::::::: */
+ }
+
+ c = getc (f);
+
+ ffelex_next_line_ ();
+
+ if (c == EOF)
+ goto end_of_file; /* :::::::::::::::::::: */
+ }
+
+ ffelex_saw_tab_ = FALSE;
+
+ column = ffelex_image_char_ (c, 0);
+
+ /* Read the entire line in as is (with whitespace processing). */
+
+ while (((c = getc (f)) != '\n') && (c != EOF))
+ column = ffelex_image_char_ (c, column);
+
+ if (ffelex_bad_line_)
+ {
+ ffelex_card_image_[column] = '\0';
+ ffelex_card_length_ = column;
+ goto comment_line; /* :::::::::::::::::::: */
+ }
+
+ /* If no tab, cut off line after column 132. */
+
+ if (!ffelex_saw_tab_ && (column > FFELEX_FREE_MAX_COLUMNS_))
+ column = FFELEX_FREE_MAX_COLUMNS_;
+
+ ffelex_card_image_[column] = '\0';
+ ffelex_card_length_ = column;
+
+ /* Save next char in file so we can use register-based c while analyzing
+ line we just read. */
+
+ latest_char_in_file = c; /* Should be either '\n' or EOF. */
+
+ column = 0;
+ continuation_column = 0;
+
+ /* Skip over initial spaces to see if the first nonblank character
+ is exclamation point, newline, or EOF (line is therefore a comment) or
+ ampersand (line is therefore a continuation line). */
+
+ while ((c = ffelex_card_image_[column]) == ' ')
+ ++column;
+
+ switch (c)
+ {
+ case '!':
+ case '\0':
+ goto beginning_of_line; /* :::::::::::::::::::: */
+
+ case '&':
+ continuation_column = column + 1;
+ break;
+
+ default:
+ break;
+ }
+
+ /* The line definitely has content of some kind, install new end-statement
+ point for error messages. */
+
+ ffewhere_line_kill (ffelex_current_wl_);
+ ffewhere_column_kill (ffelex_current_wc_);
+ ffelex_current_wl_ = ffewhere_line_new (ffelex_linecount_current_);
+ ffelex_current_wc_ = ffewhere_column_new (ffelex_card_length_ + 1);
+
+ /* Figure out which column to start parsing at. */
+
+ if (continuation_line)
+ {
+ if (continuation_column == 0)
+ {
+ if (ffelex_raw_mode_ != 0)
+ {
+ ffelex_bad_1_ (FFEBAD_BAD_CHAR_CONTINUE,
+ ffelex_linecount_current_, column + 1);
+ }
+ else if (ffelex_token_->type != FFELEX_typeNONE)
+ {
+ ffelex_bad_1_ (FFEBAD_BAD_LEXTOK_CONTINUE,
+ ffelex_linecount_current_, column + 1);
+ }
+ }
+ else if (ffelex_is_free_char_ctx_contin_ (continuation_column))
+ { /* Line contains only a single "&" as only
+ nonblank character. */
+ ffelex_bad_1_ (FFEBAD_BAD_FREE_CONTINUE,
+ ffelex_linecount_current_, continuation_column);
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ }
+ column = continuation_column;
+ }
+ else
+ column = 0;
+
+ c = ffelex_card_image_[column];
+ continuation_line = FALSE;
+
+ /* Here is the main engine for parsing. c holds the character at column.
+ It is already known that c is not a blank, end of line, or shriek,
+ unless ffelex_raw_mode_ is not 0 (indicating we are in a
+ character/hollerith constant). A partially filled token may already
+ exist in ffelex_token_. */
+
+ if (ffelex_raw_mode_ != 0)
+ {
+
+ parse_raw_character: /* :::::::::::::::::::: */
+
+ switch (c)
+ {
+ case '&':
+ if (ffelex_is_free_char_ctx_contin_ (column + 1))
+ {
+ continuation_line = TRUE;
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case '\0':
+ ffelex_finish_statement_ ();
+ goto beginning_of_line; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+
+ switch (ffelex_raw_mode_)
+ {
+ case -3:
+ c = ffelex_backslash_ (c, column);
+ if (c == EOF)
+ break;
+
+ if (!ffelex_backslash_reconsider_)
+ ffelex_append_to_token_ (c);
+ ffelex_raw_mode_ = -1;
+ break;
+
+ case -2:
+ if (c == ffelex_raw_char_)
+ {
+ ffelex_raw_mode_ = -1;
+ ffelex_append_to_token_ (c);
+ }
+ else
+ {
+ ffelex_raw_mode_ = 0;
+ ffelex_backslash_reconsider_ = TRUE;
+ }
+ break;
+
+ case -1:
+ if (c == ffelex_raw_char_)
+ ffelex_raw_mode_ = -2;
+ else
+ {
+ c = ffelex_backslash_ (c, column);
+ if (c == EOF)
+ {
+ ffelex_raw_mode_ = -3;
+ break;
+ }
+
+ ffelex_append_to_token_ (c);
+ }
+ break;
+
+ default:
+ c = ffelex_backslash_ (c, column);
+ if (c == EOF)
+ break;
+
+ if (!ffelex_backslash_reconsider_)
+ {
+ ffelex_append_to_token_ (c);
+ --ffelex_raw_mode_;
+ }
+ break;
+ }
+
+ if (ffelex_backslash_reconsider_)
+ ffelex_backslash_reconsider_ = FALSE;
+ else
+ c = ffelex_card_image_[++column];
+
+ if (ffelex_raw_mode_ == 0)
+ {
+ ffelex_send_token_ ();
+ assert (ffelex_raw_mode_ == 0);
+ while (c == ' ')
+ c = ffelex_card_image_[++column];
+ if ((c == '\0') || (c == '!'))
+ {
+ ffelex_finish_statement_ ();
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ }
+ if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
+ {
+ continuation_line = TRUE;
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ }
+ goto parse_nonraw_character_noncontin; /* :::::::::::::::::::: */
+ }
+ goto parse_raw_character; /* :::::::::::::::::::: */
+ }
+
+ parse_nonraw_character: /* :::::::::::::::::::: */
+
+ if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
+ {
+ continuation_line = TRUE;
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ }
+
+ parse_nonraw_character_noncontin: /* :::::::::::::::::::: */
+
+ switch (ffelex_token_->type)
+ {
+ case FFELEX_typeNONE:
+ if (c == ' ')
+ { /* Otherwise
+ finish-statement/continue-statement
+ already checked. */
+ while (c == ' ')
+ c = ffelex_card_image_[++column];
+ if ((c == '\0') || (c == '!'))
+ {
+ ffelex_finish_statement_ ();
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ }
+ if ((c == '&') && ffelex_is_free_nonc_ctx_contin_ (column + 1))
+ {
+ continuation_line = TRUE;
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ }
+ }
+
+ switch (c)
+ {
+ case '\"':
+ ffelex_token_->type = FFELEX_typeQUOTE;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '$':
+ ffelex_token_->type = FFELEX_typeDOLLAR;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '%':
+ ffelex_token_->type = FFELEX_typePERCENT;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '&':
+ ffelex_token_->type = FFELEX_typeAMPERSAND;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '\'':
+ ffelex_token_->type = FFELEX_typeAPOSTROPHE;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '(':
+ ffelex_token_->type = FFELEX_typeOPEN_PAREN;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case ')':
+ ffelex_token_->type = FFELEX_typeCLOSE_PAREN;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '*':
+ ffelex_token_->type = FFELEX_typeASTERISK;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case '+':
+ ffelex_token_->type = FFELEX_typePLUS;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case ',':
+ ffelex_token_->type = FFELEX_typeCOMMA;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '-':
+ ffelex_token_->type = FFELEX_typeMINUS;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '.':
+ ffelex_token_->type = FFELEX_typePERIOD;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '/':
+ ffelex_token_->type = FFELEX_typeSLASH;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ ffelex_token_->type
+ = ffelex_hexnum_ ? FFELEX_typeNAME : FFELEX_typeNUMBER;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_append_to_token_ (c);
+ break;
+
+ case ':':
+ ffelex_token_->type = FFELEX_typeCOLON;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case ';':
+ ffelex_token_->type = FFELEX_typeSEMICOLON;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_permit_include_ = TRUE;
+ ffelex_send_token_ ();
+ ffelex_permit_include_ = FALSE;
+ break;
+
+ case '<':
+ ffelex_token_->type = FFELEX_typeOPEN_ANGLE;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case '=':
+ ffelex_token_->type = FFELEX_typeEQUALS;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case '>':
+ ffelex_token_->type = FFELEX_typeCLOSE_ANGLE;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ break;
+
+ case '?':
+ ffelex_token_->type = FFELEX_typeQUESTION;
+ ffelex_token_->where_line = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+
+ case '_':
+ if (1 || ffe_is_90 ())
+ {
+ ffelex_token_->type = FFELEX_typeUNDERSCORE;
+ ffelex_token_->where_line
+ = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col
+ = ffewhere_column_new (column + 1);
+ ffelex_send_token_ ();
+ break;
+ }
+ /* Fall through. */
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ c = ffesrc_char_source (c);
+
+ if (ffesrc_char_match_init (c, 'H', 'h')
+ && ffelex_expecting_hollerith_ != 0)
+ {
+ ffelex_raw_mode_ = ffelex_expecting_hollerith_;
+ ffelex_token_->type = FFELEX_typeHOLLERITH;
+ ffelex_token_->where_line = ffelex_raw_where_line_;
+ ffelex_token_->where_col = ffelex_raw_where_col_;
+ ffelex_raw_where_line_ = ffewhere_line_unknown ();
+ ffelex_raw_where_col_ = ffewhere_column_unknown ();
+ c = ffelex_card_image_[++column];
+ goto parse_raw_character; /* :::::::::::::::::::: */
+ }
+
+ if (ffelex_names_pure_)
+ {
+ ffelex_token_->where_line
+ = ffewhere_line_use (ffelex_token_->currentnames_line
+ = ffewhere_line_use (ffelex_current_wl_));
+ ffelex_token_->where_col
+ = ffewhere_column_use (ffelex_token_->currentnames_col
+ = ffewhere_column_new (column + 1));
+ ffelex_token_->type = FFELEX_typeNAMES;
+ }
+ else
+ {
+ ffelex_token_->where_line
+ = ffewhere_line_use (ffelex_current_wl_);
+ ffelex_token_->where_col = ffewhere_column_new (column + 1);
+ ffelex_token_->type = FFELEX_typeNAME;
+ }
+ ffelex_append_to_token_ (c);
+ break;
+
+ default:
+ ffelex_bad_1_ (FFEBAD_UNRECOGNIZED_CHARACTER,
+ ffelex_linecount_current_, column + 1);
+ ffelex_finish_statement_ ();
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeNAME:
+ switch (c)
+ {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ c = ffesrc_char_source (c);
+ /* Fall through. */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '_':
+ case '$':
+ if ((c == '$')
+ && !ffe_is_dollar_ok ())
+ {
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ ffelex_append_to_token_ (c);
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeNAMES:
+ switch (c)
+ {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ c = ffesrc_char_source (c);
+ /* Fall through. */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '_':
+ case '$':
+ if ((c == '$')
+ && !ffe_is_dollar_ok ())
+ {
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ if (ffelex_token_->length < FFEWHERE_indexMAX)
+ {
+ ffewhere_track (&ffelex_token_->currentnames_line,
+ &ffelex_token_->currentnames_col,
+ ffelex_token_->wheretrack,
+ ffelex_token_->length,
+ ffelex_linecount_current_,
+ column + 1);
+ }
+ ffelex_append_to_token_ (c);
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeNUMBER:
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ ffelex_append_to_token_ (c);
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeASTERISK:
+ switch (c)
+ {
+ case '*': /* ** */
+ ffelex_token_->type = FFELEX_typePOWER;
+ ffelex_send_token_ ();
+ break;
+
+ default: /* * not followed by another *. */
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeCOLON:
+ switch (c)
+ {
+ case ':': /* :: */
+ ffelex_token_->type = FFELEX_typeCOLONCOLON;
+ ffelex_send_token_ ();
+ break;
+
+ default: /* : not followed by another :. */
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeSLASH:
+ switch (c)
+ {
+ case '/': /* // */
+ ffelex_token_->type = FFELEX_typeCONCAT;
+ ffelex_send_token_ ();
+ break;
+
+ case ')': /* /) */
+ ffelex_token_->type = FFELEX_typeCLOSE_ARRAY;
+ ffelex_send_token_ ();
+ break;
+
+ case '=': /* /= */
+ ffelex_token_->type = FFELEX_typeREL_NE;
+ ffelex_send_token_ ();
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeOPEN_PAREN:
+ switch (c)
+ {
+ case '/': /* (/ */
+ ffelex_token_->type = FFELEX_typeOPEN_ARRAY;
+ ffelex_send_token_ ();
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeOPEN_ANGLE:
+ switch (c)
+ {
+ case '=': /* <= */
+ ffelex_token_->type = FFELEX_typeREL_LE;
+ ffelex_send_token_ ();
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeEQUALS:
+ switch (c)
+ {
+ case '=': /* == */
+ ffelex_token_->type = FFELEX_typeREL_EQ;
+ ffelex_send_token_ ();
+ break;
+
+ case '>': /* => */
+ ffelex_token_->type = FFELEX_typePOINTS;
+ ffelex_send_token_ ();
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ case FFELEX_typeCLOSE_ANGLE:
+ switch (c)
+ {
+ case '=': /* >= */
+ ffelex_token_->type = FFELEX_typeREL_GE;
+ ffelex_send_token_ ();
+ break;
+
+ default:
+ ffelex_send_token_ ();
+ goto parse_next_character; /* :::::::::::::::::::: */
+ }
+ break;
+
+ default:
+ assert ("Serious error!" == NULL);
+ abort ();
+ break;
+ }
+
+ c = ffelex_card_image_[++column];
+
+ parse_next_character: /* :::::::::::::::::::: */
+
+ if (ffelex_raw_mode_ != 0)
+ goto parse_raw_character; /* :::::::::::::::::::: */
+
+ if ((c == '\0') || (c == '!'))
+ {
+ ffelex_finish_statement_ ();
+ goto beginning_of_line; /* :::::::::::::::::::: */
+ }
+ goto parse_nonraw_character; /* :::::::::::::::::::: */
+}
+
+/* See the code in com.c that calls this to understand why. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+void
+ffelex_hash_kludge (FILE *finput)
+{
+ /* If you change this constant string, you have to change whatever
+ code might thus be affected by it in terms of having to use
+ ffelex_getc_() instead of getc() in the lexers and _hash_. */
+ static char match[] = "# 1 \"";
+ static int kludge[ARRAY_SIZE (match) + 1];
+ int c;
+ char *p;
+ int *q;
+
+ /* Read chars as long as they match the target string.
+ Copy them into an array that will serve as a record
+ of what we read (essentially a multi-char ungetc(),
+ for code that uses ffelex_getc_ instead of getc() elsewhere
+ in the lexer. */
+ for (p = &match[0], q = &kludge[0], c = getc (finput);
+ (c == *p) && (*p != '\0') && (c != EOF);
+ ++p, ++q, c = getc (finput))
+ *q = c;
+
+ *q = c; /* Might be EOF, which requires int. */
+ *++q = 0;
+
+ ffelex_kludge_chars_ = &kludge[0];
+
+ if (*p == 0)
+ {
+ ffelex_kludge_flag_ = TRUE;
+ ++ffelex_kludge_chars_;
+ ffelex_hash_ (finput); /* Handle it NOW rather than later. */
+ ffelex_kludge_flag_ = FALSE;
+ }
+}
+
+#endif
+void
+ffelex_init_1 ()
+{
+ unsigned int i;
+
+ ffelex_final_nontab_column_ = ffe_fixed_line_length ();
+ ffelex_card_size_ = FFELEX_columnINITIAL_SIZE_;
+ ffelex_card_image_ = malloc_new_ksr (malloc_pool_image (),
+ "FFELEX card image",
+ FFELEX_columnINITIAL_SIZE_ + 9);
+ ffelex_card_image_[0] = '\0';
+
+ for (i = 0; i < 256; ++i)
+ ffelex_first_char_[i] = FFELEX_typeERROR;
+
+ ffelex_first_char_['\t'] = FFELEX_typeRAW;
+ ffelex_first_char_['\n'] = FFELEX_typeCOMMENT;
+ ffelex_first_char_['\v'] = FFELEX_typeCOMMENT;
+ ffelex_first_char_['\f'] = FFELEX_typeCOMMENT;
+ ffelex_first_char_['\r'] = FFELEX_typeRAW;
+ ffelex_first_char_[' '] = FFELEX_typeRAW;
+ ffelex_first_char_['!'] = FFELEX_typeCOMMENT;
+ ffelex_first_char_['*'] = FFELEX_typeCOMMENT;
+ ffelex_first_char_['/'] = FFELEX_typeSLASH;
+ ffelex_first_char_['&'] = FFELEX_typeRAW;
+ ffelex_first_char_['#'] = FFELEX_typeHASH;
+
+ for (i = '0'; i <= '9'; ++i)
+ ffelex_first_char_[i] = FFELEX_typeRAW;
+
+ if ((ffe_case_match () == FFE_caseNONE)
+ || ((ffe_case_match () == FFE_caseUPPER)
+ && (ffe_case_source () != FFE_caseLOWER)) /* Idiot! :-) */
+ || ((ffe_case_match () == FFE_caseLOWER)
+ && (ffe_case_source () == FFE_caseLOWER)))
+ {
+ ffelex_first_char_['C'] = FFELEX_typeCOMMENT;
+ ffelex_first_char_['D'] = FFELEX_typeCOMMENT;
+ }
+ if ((ffe_case_match () == FFE_caseNONE)
+ || ((ffe_case_match () == FFE_caseLOWER)
+ && (ffe_case_source () != FFE_caseUPPER)) /* Idiot! :-) */
+ || ((ffe_case_match () == FFE_caseUPPER)
+ && (ffe_case_source () == FFE_caseUPPER)))
+ {
+ ffelex_first_char_['c'] = FFELEX_typeCOMMENT;
+ ffelex_first_char_['d'] = FFELEX_typeCOMMENT;
+ }
+
+ ffelex_linecount_current_ = 0;
+ ffelex_linecount_next_ = 1;
+ ffelex_raw_mode_ = 0;
+ ffelex_set_include_ = FALSE;
+ ffelex_permit_include_ = FALSE;
+ ffelex_names_ = TRUE; /* First token in program is a names. */
+ ffelex_names_pure_ = FALSE; /* Free-form lexer does NAMES only for
+ FORMAT. */
+ ffelex_hexnum_ = FALSE;
+ ffelex_expecting_hollerith_ = 0;
+ ffelex_raw_where_line_ = ffewhere_line_unknown ();
+ ffelex_raw_where_col_ = ffewhere_column_unknown ();
+
+ ffelex_token_ = ffelex_token_new_ ();
+ ffelex_token_->type = FFELEX_typeNONE;
+ ffelex_token_->uses = 1;
+ ffelex_token_->where_line = ffewhere_line_unknown ();
+ ffelex_token_->where_col = ffewhere_column_unknown ();
+ ffelex_token_->text = NULL;
+
+ ffelex_handler_ = NULL;
+}
+
+/* ffelex_is_names_expected -- Is the current parser expecting NAMES vs. NAME?
+
+ if (ffelex_is_names_expected())
+ // Deliver NAMES token
+ else
+ // Deliver NAME token
+
+ Must be called while lexer is active, obviously. */
+
+bool
+ffelex_is_names_expected ()
+{
+ return ffelex_names_;
+}
+
+/* Current card image, which has the master linecount number
+ ffelex_linecount_current_. */
+
+char *
+ffelex_line ()
+{
+ return ffelex_card_image_;
+}
+
+/* ffelex_line_length -- Return length of current lexer line
+
+ printf("Length is %lu\n",ffelex_line_length());
+
+ Must be called while lexer is active, obviously. */
+
+ffewhereColumnNumber
+ffelex_line_length ()
+{
+ return ffelex_card_length_;
+}
+
+/* Master line count of current card image, or 0 if no card image
+ is current. */
+
+ffewhereLineNumber
+ffelex_line_number ()
+{
+ return ffelex_linecount_current_;
+}
+
+/* ffelex_set_expecting_hollerith -- Set hollerith expectation status
+
+ ffelex_set_expecting_hollerith(0);
+
+ Lex initially assumes no hollerith constant is about to show up. If
+ syntactic analysis expects one, it should call this function with the
+ number of characters expected in the constant immediately after recognizing
+ the decimal number preceding the "H" and the constant itself. Then, if
+ the next character is indeed H, the lexer will interpret it as beginning
+ a hollerith constant and ship the token formed by reading the specified
+ number of characters (interpreting blanks and otherwise-comments too)
+ from the input file. It is up to syntactic analysis to call this routine
+ again with 0 to turn hollerith detection off immediately upon receiving
+ the token that might or might not be HOLLERITH.
+
+ Also call this after seeing an APOSTROPHE or QUOTE token that begins a
+ character constant. Pass the expected termination character (apostrophe
+ or quote).
+
+ Pass for length either the length of the hollerith (must be > 0), -1
+ meaning expecting a character constant, or 0 to cancel expectation of
+ a hollerith only after calling it with a length of > 0 and receiving the
+ next token (which may or may not have been a HOLLERITH token).
+
+ Pass for which either an apostrophe or quote when passing length of -1.
+ Else which is a don't-care.
+
+ Pass for line and column the line/column info for the token beginning the
+ character or hollerith constant, for use in error messages, when passing
+ a length of -1 -- this function will invoke ffewhere_line/column_use to
+ make its own copies. Else line and column are don't-cares (when length
+ is 0) and the outstanding copies of the previous line/column info, if
+ still around, are killed.
+
+ 21-Feb-90 JCB 3.1
+ When called with length of 0, also zero ffelex_raw_mode_. This is
+ so ffest_save_ can undo the effects of replaying tokens like
+ APOSTROPHE and QUOTE.
+ 25-Jan-90 JCB 3.0
+ New line, column arguments allow error messages to point to the true
+ beginning of a character/hollerith constant, rather than the beginning
+ of the content part, which makes them more consistent and helpful.
+ 05-Nov-89 JCB 2.0
+ New "which" argument allows caller to specify termination character,
+ which should be apostrophe or double-quote, to support Fortran 90. */
+
+void
+ffelex_set_expecting_hollerith (long length, char which,
+ ffewhereLine line, ffewhereColumn column)
+{
+
+ /* First kill the pending line/col info, if any (should only be pending
+ when this call has length==0, the previous call had length>0, and a
+ non-HOLLERITH token was sent in between the calls, but play it safe). */
+
+ ffewhere_line_kill (ffelex_raw_where_line_);
+ ffewhere_column_kill (ffelex_raw_where_col_);
+
+ /* Now handle the length function. */
+ switch (length)
+ {
+ case 0:
+ ffelex_expecting_hollerith_ = 0;
+ ffelex_raw_mode_ = 0;
+ ffelex_raw_where_line_ = ffewhere_line_unknown ();
+ ffelex_raw_where_col_ = ffewhere_column_unknown ();
+ return; /* Don't set new line/column info from args. */
+
+ case -1:
+ ffelex_raw_mode_ = -1;
+ ffelex_raw_char_ = which;
+ break;
+
+ default: /* length > 0 */
+ ffelex_expecting_hollerith_ = length;
+ break;
+ }
+
+ /* Now set new line/column information from passed args. */
+
+ ffelex_raw_where_line_ = ffewhere_line_use (line);
+ ffelex_raw_where_col_ = ffewhere_column_use (column);
+}
+
+/* ffelex_set_handler -- Set handler for tokens before calling _fixed or _free
+
+ ffelex_set_handler((ffelexHandler) my_first_handler);
+
+ Must be called before calling ffelex_file_fixed or ffelex_file_free or
+ after they return, but not while they are active. */
+
+void
+ffelex_set_handler (ffelexHandler first)
+{
+ ffelex_handler_ = first;
+}
+
+/* ffelex_set_hexnum -- Set hexnum flag
+
+ ffelex_set_hexnum(TRUE);
+
+ Lex normally interprets a token starting with [0-9] as a NUMBER token,
+ so if it sees a [A-Za-z] in it, it stops parsing the NUMBER and leaves
+ the character as the first of the next token. But when parsing a
+ hexadecimal number, by calling this function with TRUE before starting
+ the parse of the token itself, lex will interpret [0-9] as the start
+ of a NAME token. */
+
+void
+ffelex_set_hexnum (bool f)
+{
+ ffelex_hexnum_ = f;
+}
+
+/* ffelex_set_include -- Set INCLUDE file to be processed next
+
+ ffewhereFile wf; // The ffewhereFile object for the file.
+ bool free_form; // TRUE means read free-form file, FALSE fixed-form.
+ FILE *fi; // The file to INCLUDE.
+ ffelex_set_include(wf,free_form,fi);
+
+ Must be called only after receiving the EOS token following a valid
+ INCLUDE statement specifying a file that has already been successfully
+ opened. */
+
+void
+ffelex_set_include (ffewhereFile wf, bool free_form, FILE *fi)
+{
+ assert (ffelex_permit_include_);
+ assert (!ffelex_set_include_);
+ ffelex_set_include_ = TRUE;
+ ffelex_include_free_form_ = free_form;
+ ffelex_include_file_ = fi;
+ ffelex_include_wherefile_ = wf;
+}
+
+/* ffelex_set_names -- Set names/name flag, names = TRUE
+
+ ffelex_set_names(FALSE);
+
+ Lex initially assumes multiple names should be formed. If this function is
+ called with FALSE, then single names are formed instead. The differences
+ are a difference in the token type (FFELEX_typeNAMES vs. FFELEX_typeNAME)
+ and in whether full source-location tracking is performed (it is for
+ multiple names, not for single names), which is more expensive in terms of
+ CPU time. */
+
+void
+ffelex_set_names (bool f)
+{
+ ffelex_names_ = f;
+ if (!f)
+ ffelex_names_pure_ = FALSE;
+}
+
+/* ffelex_set_names_pure -- Set names/name (pure) flag, names = TRUE
+
+ ffelex_set_names_pure(FALSE);
+
+ Like ffelex_set_names, except affects both lexers. Normally, the
+ free-form lexer need not generate NAMES tokens because adjacent NAME
+ tokens must be separated by spaces which causes the lexer to generate
+ separate tokens for analysis (whereas in fixed-form the spaces are
+ ignored resulting in one long token). But in FORMAT statements, for
+ some reason, the Fortran 90 standard specifies that spaces can occur
+ anywhere within a format-item-list with no effect on the format spec
+ (except of course within character string edit descriptors), which means
+ that "1PE14.2" and "1 P E 1 4 . 2" are equivalent. For the FORMAT
+ statement handling, the existence of spaces makes it hard to deal with,
+ because each token is seen distinctly (i.e. seven tokens in the latter
+ example). But when no spaces are provided, as in the former example,
+ then only four tokens are generated, NUMBER("1"), NAME("PE14"), PERIOD,
+ NUMBER ("2"). By generating a NAMES instead of NAME, three things happen:
+ One, ffest_kw_format_ does a substring rather than full-string match,
+ and thus matches "PE14" to "PE"; two, ffelex_token_xyz_from_names functions
+ may be used to pull NAME/NAMES and NUMBER tokens out of the NAMES token;
+ and three, error reporting can point to the actual character rather than
+ at or prior to it. The first two things could be resolved by providing
+ alternate functions fairly easy, thus allowing FORMAT handling to expect
+ both lexers to generate NAME tokens instead of NAMES (with otherwise minor
+ changes to FORMAT parsing), but the third, error reporting, would suffer,
+ and when one makes mistakes in a FORMAT, believe me, one wants a pointer
+ to exactly where the compilers thinks the problem is, to even begin to get
+ a handle on it. So there. */
+
+void
+ffelex_set_names_pure (bool f)
+{
+ ffelex_names_pure_ = f;
+ ffelex_names_ = f;
+}
+
+/* ffelex_splice_tokens -- Splice off and send tokens from a NAMES
+
+ return (ffelexHandler) ffelex_splice_tokens(first_handler,master_token,
+ start_char_index);
+
+ Returns first_handler if start_char_index chars into master_token (which
+ must be a NAMES token) is '\0'. Else, creates a subtoken from that
+ char, either NUMBER (if it is a digit), a NAME (if a valid firstnamechar),
+ an UNDERSCORE (if an underscore), or DOLLAR (if a dollar sign)
+ and sends it to first_handler. If anything other than NAME is sent, the
+ character at the end of it in the master token is examined to see if it
+ begins a NAME, NUMBER, UNDERSCORE, or DOLLAR, and, if so,
+ the handler returned by first_handler is invoked with that token, and
+ this process is repeated until the end of the master token or a NAME
+ token is reached. */
+
+ffelexHandler
+ffelex_splice_tokens (ffelexHandler first, ffelexToken master,
+ ffeTokenLength start)
+{
+ char *p;
+ ffeTokenLength i;
+ ffelexToken t;
+
+ p = ffelex_token_text (master) + (i = start);
+
+ while (*p != '\0')
+ {
+ if (ISDIGIT (*p))
+ {
+ t = ffelex_token_number_from_names (master, i);
+ p += ffelex_token_length (t);
+ i += ffelex_token_length (t);
+ }
+ else if (ffesrc_is_name_init (*p))
+ {
+ t = ffelex_token_name_from_names (master, i, 0);
+ p += ffelex_token_length (t);
+ i += ffelex_token_length (t);
+ }
+ else if (*p == '$')
+ {
+ t = ffelex_token_dollar_from_names (master, i);
+ ++p;
+ ++i;
+ }
+ else if (*p == '_')
+ {
+ t = ffelex_token_uscore_from_names (master, i);
+ ++p;
+ ++i;
+ }
+ else
+ {
+ assert ("not a valid NAMES character" == NULL);
+ t = NULL;
+ }
+ assert (first != NULL);
+ first = (ffelexHandler) (*first) (t);
+ ffelex_token_kill (t);
+ }
+
+ return first;
+}
+
+/* ffelex_swallow_tokens -- Eat all tokens delivered to me
+
+ return ffelex_swallow_tokens;
+
+ Return this handler when you don't want to look at any more tokens in the
+ statement because you've encountered an unrecoverable error in the
+ statement. */
+
+ffelexHandler
+ffelex_swallow_tokens (ffelexToken t, ffelexHandler handler)
+{
+ assert (handler != NULL);
+
+ if ((t != NULL) && ((ffelex_token_type (t) == FFELEX_typeEOS)
+ || (ffelex_token_type (t) == FFELEX_typeSEMICOLON)))
+ return (ffelexHandler) (*handler) (t);
+
+ ffelex_eos_handler_ = handler;
+ return (ffelexHandler) ffelex_swallow_tokens_;
+}
+
+/* ffelex_token_dollar_from_names -- Return a dollar from within a names token
+
+ ffelexToken t;
+ t = ffelex_token_dollar_from_names(t,6);
+
+ It's as if you made a new token of dollar type having the dollar
+ at, in the example above, the sixth character of the NAMES token. */
+
+ffelexToken
+ffelex_token_dollar_from_names (ffelexToken t, ffeTokenLength start)
+{
+ ffelexToken nt;
+
+ assert (t != NULL);
+ assert (ffelex_token_type (t) == FFELEX_typeNAMES);
+ assert (start < t->length);
+ assert (t->text[start] == '$');
+
+ /* Now make the token. */
+
+ nt = ffelex_token_new_ ();
+ nt->type = FFELEX_typeDOLLAR;
+ nt->length = 0;
+ nt->uses = 1;
+ ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
+ t->where_col, t->wheretrack, start);
+ nt->text = NULL;
+ return nt;
+}
+
+/* ffelex_token_kill -- Decrement use count for token, kill if no uses left
+
+ ffelexToken t;
+ ffelex_token_kill(t);
+
+ Complements a call to ffelex_token_use or ffelex_token_new_.... */
+
+void
+ffelex_token_kill (ffelexToken t)
+{
+ assert (t != NULL);
+
+ assert (t->uses > 0);
+
+ if (--t->uses != 0)
+ return;
+
+ --ffelex_total_tokens_;
+
+ if (t->type == FFELEX_typeNAMES)
+ ffewhere_track_kill (t->where_line, t->where_col,
+ t->wheretrack, t->length);
+ ffewhere_line_kill (t->where_line);
+ ffewhere_column_kill (t->where_col);
+ if (t->text != NULL)
+ malloc_kill_ksr (malloc_pool_image (), t->text, t->size + 1);
+ malloc_kill_ks (malloc_pool_image (), t, sizeof (*t));
+}
+
+/* Make a new NAME token that is a substring of a NAMES token. */
+
+ffelexToken
+ffelex_token_name_from_names (ffelexToken t, ffeTokenLength start,
+ ffeTokenLength len)
+{
+ ffelexToken nt;
+
+ assert (t != NULL);
+ assert (ffelex_token_type (t) == FFELEX_typeNAMES);
+ assert (start < t->length);
+ if (len == 0)
+ len = t->length - start;
+ else
+ {
+ assert (len > 0);
+ assert ((start + len) <= t->length);
+ }
+ assert (ffelex_is_firstnamechar (t->text[start]));
+
+ nt = ffelex_token_new_ ();
+ nt->type = FFELEX_typeNAME;
+ nt->size = len; /* Assume nobody's gonna fiddle with token
+ text. */
+ nt->length = len;
+ nt->uses = 1;
+ ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
+ t->where_col, t->wheretrack, start);
+ nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
+ len + 1);
+ strncpy (nt->text, t->text + start, len);
+ nt->text[len] = '\0';
+ return nt;
+}
+
+/* Make a new NAMES token that is a substring of another NAMES token. */
+
+ffelexToken
+ffelex_token_names_from_names (ffelexToken t, ffeTokenLength start,
+ ffeTokenLength len)
+{
+ ffelexToken nt;
+
+ assert (t != NULL);
+ assert (ffelex_token_type (t) == FFELEX_typeNAMES);
+ assert (start < t->length);
+ if (len == 0)
+ len = t->length - start;
+ else
+ {
+ assert (len > 0);
+ assert ((start + len) <= t->length);
+ }
+ assert (ffelex_is_firstnamechar (t->text[start]));
+
+ nt = ffelex_token_new_ ();
+ nt->type = FFELEX_typeNAMES;
+ nt->size = len; /* Assume nobody's gonna fiddle with token
+ text. */
+ nt->length = len;
+ nt->uses = 1;
+ ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
+ t->where_col, t->wheretrack, start);
+ ffewhere_track_copy (nt->wheretrack, t->wheretrack, start, len);
+ nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
+ len + 1);
+ strncpy (nt->text, t->text + start, len);
+ nt->text[len] = '\0';
+ return nt;
+}
+
+/* Make a new CHARACTER token. */
+
+ffelexToken
+ffelex_token_new_character (char *s, ffewhereLine l, ffewhereColumn c)
+{
+ ffelexToken t;
+
+ t = ffelex_token_new_ ();
+ t->type = FFELEX_typeCHARACTER;
+ t->length = t->size = strlen (s); /* Assume it won't get bigger. */
+ t->uses = 1;
+ t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
+ t->size + 1);
+ strcpy (t->text, s);
+ t->where_line = ffewhere_line_use (l);
+ t->where_col = ffewhere_column_new (c);
+ return t;
+}
+
+/* Make a new EOF token right after end of file. */
+
+ffelexToken
+ffelex_token_new_eof ()
+{
+ ffelexToken t;
+
+ t = ffelex_token_new_ ();
+ t->type = FFELEX_typeEOF;
+ t->uses = 1;
+ t->text = NULL;
+ t->where_line = ffewhere_line_new (ffelex_linecount_current_);
+ t->where_col = ffewhere_column_new (1);
+ return t;
+}
+
+/* Make a new NAME token. */
+
+ffelexToken
+ffelex_token_new_name (char *s, ffewhereLine l, ffewhereColumn c)
+{
+ ffelexToken t;
+
+ assert (ffelex_is_firstnamechar (*s));
+
+ t = ffelex_token_new_ ();
+ t->type = FFELEX_typeNAME;
+ t->length = t->size = strlen (s); /* Assume it won't get bigger. */
+ t->uses = 1;
+ t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
+ t->size + 1);
+ strcpy (t->text, s);
+ t->where_line = ffewhere_line_use (l);
+ t->where_col = ffewhere_column_new (c);
+ return t;
+}
+
+/* Make a new NAMES token. */
+
+ffelexToken
+ffelex_token_new_names (char *s, ffewhereLine l, ffewhereColumn c)
+{
+ ffelexToken t;
+
+ assert (ffelex_is_firstnamechar (*s));
+
+ t = ffelex_token_new_ ();
+ t->type = FFELEX_typeNAMES;
+ t->length = t->size = strlen (s); /* Assume it won't get bigger. */
+ t->uses = 1;
+ t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
+ t->size + 1);
+ strcpy (t->text, s);
+ t->where_line = ffewhere_line_use (l);
+ t->where_col = ffewhere_column_new (c);
+ ffewhere_track_clear (t->wheretrack, t->length); /* Assume contiguous
+ names. */
+ return t;
+}
+
+/* Make a new NUMBER token.
+
+ The first character of the string must be a digit, and only the digits
+ are copied into the new number. So this may be used to easily extract
+ a NUMBER token from within any text string. Then the length of the
+ resulting token may be used to calculate where the digits stopped
+ in the original string. */
+
+ffelexToken
+ffelex_token_new_number (char *s, ffewhereLine l, ffewhereColumn c)
+{
+ ffelexToken t;
+ ffeTokenLength len;
+
+ /* How long is the string of decimal digits at s? */
+
+ len = strspn (s, "0123456789");
+
+ /* Make sure there is at least one digit. */
+
+ assert (len != 0);
+
+ /* Now make the token. */
+
+ t = ffelex_token_new_ ();
+ t->type = FFELEX_typeNUMBER;
+ t->length = t->size = len; /* Assume it won't get bigger. */
+ t->uses = 1;
+ t->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
+ len + 1);
+ strncpy (t->text, s, len);
+ t->text[len] = '\0';
+ t->where_line = ffewhere_line_use (l);
+ t->where_col = ffewhere_column_new (c);
+ return t;
+}
+
+/* Make a new token of any type that doesn't contain text. A private
+ function that is used by public macros in the interface file. */
+
+ffelexToken
+ffelex_token_new_simple_ (ffelexType type, ffewhereLine l, ffewhereColumn c)
+{
+ ffelexToken t;
+
+ t = ffelex_token_new_ ();
+ t->type = type;
+ t->uses = 1;
+ t->text = NULL;
+ t->where_line = ffewhere_line_use (l);
+ t->where_col = ffewhere_column_new (c);
+ return t;
+}
+
+/* Make a new NUMBER token from an existing NAMES token.
+
+ Like ffelex_token_new_number, this function calculates the length
+ of the digit string itself. */
+
+ffelexToken
+ffelex_token_number_from_names (ffelexToken t, ffeTokenLength start)
+{
+ ffelexToken nt;
+ ffeTokenLength len;
+
+ assert (t != NULL);
+ assert (ffelex_token_type (t) == FFELEX_typeNAMES);
+ assert (start < t->length);
+
+ /* How long is the string of decimal digits at s? */
+
+ len = strspn (t->text + start, "0123456789");
+
+ /* Make sure there is at least one digit. */
+
+ assert (len != 0);
+
+ /* Now make the token. */
+
+ nt = ffelex_token_new_ ();
+ nt->type = FFELEX_typeNUMBER;
+ nt->size = len; /* Assume nobody's gonna fiddle with token
+ text. */
+ nt->length = len;
+ nt->uses = 1;
+ ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
+ t->where_col, t->wheretrack, start);
+ nt->text = malloc_new_ksr (malloc_pool_image (), "FFELEX token text",
+ len + 1);
+ strncpy (nt->text, t->text + start, len);
+ nt->text[len] = '\0';
+ return nt;
+}
+
+/* Make a new UNDERSCORE token from a NAMES token. */
+
+ffelexToken
+ffelex_token_uscore_from_names (ffelexToken t, ffeTokenLength start)
+{
+ ffelexToken nt;
+
+ assert (t != NULL);
+ assert (ffelex_token_type (t) == FFELEX_typeNAMES);
+ assert (start < t->length);
+ assert (t->text[start] == '_');
+
+ /* Now make the token. */
+
+ nt = ffelex_token_new_ ();
+ nt->type = FFELEX_typeUNDERSCORE;
+ nt->uses = 1;
+ ffewhere_set_from_track (&nt->where_line, &nt->where_col, t->where_line,
+ t->where_col, t->wheretrack, start);
+ nt->text = NULL;
+ return nt;
+}
+
+/* ffelex_token_use -- Return another instance of a token
+
+ ffelexToken t;
+ t = ffelex_token_use(t);
+
+ In a sense, the new token is a copy of the old, though it might be the
+ same with just a new use count.
+
+ We use the use count method (easy). */
+
+ffelexToken
+ffelex_token_use (ffelexToken t)
+{
+ if (t == NULL)
+ assert ("_token_use: null token" == NULL);
+ t->uses++;
+ return t;
+}
diff --git a/contrib/gcc/f/lex.h b/contrib/gcc/f/lex.h
new file mode 100644
index 0000000..c9a9dd5
--- /dev/null
+++ b/contrib/gcc/f/lex.h
@@ -0,0 +1,201 @@
+/* lex.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ lex.c
+
+ Modifications:
+ 22-Aug-89 JCB 1.1
+ Change for new ffewhere interface.
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_lex
+#define _H_f_lex
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFELEX_typeNONE,
+ FFELEX_typeCOMMENT,
+ FFELEX_typeEOS,
+ FFELEX_typeEOF,
+ FFELEX_typeERROR,
+ FFELEX_typeRAW,
+ FFELEX_typeQUOTE,
+ FFELEX_typeDOLLAR,
+ FFELEX_typeHASH,
+ FFELEX_typePERCENT,
+ FFELEX_typeAMPERSAND,
+ FFELEX_typeAPOSTROPHE,
+ FFELEX_typeOPEN_PAREN,
+ FFELEX_typeCLOSE_PAREN,
+ FFELEX_typeASTERISK,
+ FFELEX_typePLUS,
+ FFELEX_typeMINUS,
+ FFELEX_typePERIOD,
+ FFELEX_typeSLASH,
+ FFELEX_typeNUMBER, /* Grep: [0-9][0-9]*. */
+ FFELEX_typeOPEN_ANGLE,
+ FFELEX_typeEQUALS,
+ FFELEX_typeCLOSE_ANGLE,
+ FFELEX_typeNAME, /* Grep: [A-Za-z][A-Za-z0-9_]*. */
+ FFELEX_typeCOMMA,
+ FFELEX_typePOWER, /* "**". */
+ FFELEX_typeCONCAT, /* "//". */
+ FFELEX_typeDEBUG,
+ FFELEX_typeNAMES, /* Same as FFELEX_typeNAME in initial
+ context. */
+ FFELEX_typeHOLLERITH, /* <text> part of <nn>H<text>. */
+ FFELEX_typeCHARACTER, /* <text> part of '<text>' or "<text>". */
+ FFELEX_typeCOLON,
+ FFELEX_typeSEMICOLON,
+ FFELEX_typeUNDERSCORE,
+ FFELEX_typeQUESTION,
+ FFELEX_typeOPEN_ARRAY, /* "(/". */
+ FFELEX_typeCLOSE_ARRAY, /* "/)". */
+ FFELEX_typeCOLONCOLON, /* "::". */
+ FFELEX_typeREL_LE, /* "<=". */
+ FFELEX_typeREL_NE, /* "<>". */
+ FFELEX_typeREL_EQ, /* "==". */
+ FFELEX_typePOINTS, /* "=>". */
+ FFELEX_typeREL_GE, /* ">=". */
+ FFELEX_type
+ } ffelexType;
+
+/* Typedefs. */
+
+typedef struct _lextoken_ *ffelexToken;
+typedef void *lex_sigh_;
+typedef lex_sigh_ (*lex_sigh__) (ffelexToken);
+typedef lex_sigh__ (*ffelexHandler) (ffelexToken);
+
+/* Include files needed by this one. */
+
+#include "top.h"
+#include "where.h"
+
+/* Structure definitions. */
+
+struct _lextoken_
+ {
+ long int id_; /* DEBUG ONLY. */
+ ffeTokenLength size;
+ ffeTokenLength length;
+ unsigned short uses;
+ char *text;
+ ffelexType type;
+ ffewhereLine where_line;
+ ffewhereColumn where_col;
+ ffewhereLine currentnames_line; /* For tracking NAMES tokens. */
+ ffewhereColumn currentnames_col; /* For tracking NAMES tokens. */
+ ffewhereTrack wheretrack; /* For tracking NAMES tokens. */
+ };
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+void ffelex_display_token (ffelexToken t);
+bool ffelex_expecting_character (void);
+ffelexHandler ffelex_file_fixed (ffewhereFile wf, FILE *f);
+ffelexHandler ffelex_file_free (ffewhereFile wf, FILE *f);
+void ffelex_hash_kludge (FILE *f);
+void ffelex_init_1 (void);
+bool ffelex_is_names_expected (void);
+char *ffelex_line (void);
+ffewhereColumnNumber ffelex_line_length (void);
+ffewhereLineNumber ffelex_line_number (void);
+void ffelex_set_expecting_hollerith (long length, char which,
+ ffewhereLine line,
+ ffewhereColumn column);
+void ffelex_set_handler (ffelexHandler first);
+void ffelex_set_hexnum (bool on);
+void ffelex_set_include (ffewhereFile wf, bool free_form, FILE *fi);
+void ffelex_set_names (bool on);
+void ffelex_set_names_pure (bool on);
+ffelexHandler ffelex_splice_tokens (ffelexHandler first, ffelexToken master,
+ ffeTokenLength start);
+ffelexHandler ffelex_swallow_tokens (ffelexToken t, ffelexHandler handler);
+ffelexToken ffelex_token_dollar_from_names (ffelexToken t,
+ ffeTokenLength start);
+void ffelex_token_kill (ffelexToken t);
+ffelexToken ffelex_token_name_from_names (ffelexToken t,
+ ffeTokenLength start,
+ ffeTokenLength len);
+ffelexToken ffelex_token_names_from_names (ffelexToken t,
+ ffeTokenLength start,
+ ffeTokenLength len);
+ffelexToken ffelex_token_new (void);
+ffelexToken ffelex_token_new_character (char *s, ffewhereLine l,
+ ffewhereColumn c);
+ffelexToken ffelex_token_new_eof (void);
+ffelexToken ffelex_token_new_name (char *s, ffewhereLine l,
+ ffewhereColumn c);
+ffelexToken ffelex_token_new_names (char *s, ffewhereLine l,
+ ffewhereColumn c);
+ffelexToken ffelex_token_new_number (char *s, ffewhereLine l,
+ ffewhereColumn c);
+ffelexToken ffelex_token_new_simple_ (ffelexType type, ffewhereLine l,
+ ffewhereColumn c);
+ffelexToken ffelex_token_number_from_names (ffelexToken t,
+ ffeTokenLength start);
+ffelexToken ffelex_token_uscore_from_names (ffelexToken t,
+ ffeTokenLength start);
+ffelexToken ffelex_token_use (ffelexToken t);
+
+/* Define macros. */
+
+#define ffelex_init_0()
+#define ffelex_init_2()
+#define ffelex_init_3()
+#define ffelex_init_4()
+#define ffelex_is_firstnamechar(c) \
+ (ISALPHA ((c)) || ((c) == '_'))
+#define ffelex_terminate_0()
+#define ffelex_terminate_1()
+#define ffelex_terminate_2()
+#define ffelex_terminate_3()
+#define ffelex_terminate_4()
+#define ffelex_token_length(t) ((t)->length)
+#define ffelex_token_new_eos(l,c) \
+ ffelex_token_new_simple_ (FFELEX_typeEOS, (l), (c))
+#define ffelex_token_new_period(l,c) \
+ ffelex_token_new_simple_ (FFELEX_typePERIOD, (l), (c))
+#define ffelex_token_strcmp(t1,t2) strcmp ((t1)->text, (t2)->text)
+#define ffelex_token_text(t) ((t)->text)
+#define ffelex_token_type(t) ((t)->type)
+#define ffelex_token_where_column(t) ((t)->where_col)
+#define ffelex_token_where_filename(t) \
+ ffewhere_line_filename ((t)->where_line)
+#define ffelex_token_where_filelinenum(t) \
+ ffewhere_line_filelinenum((t)->where_line)
+#define ffelex_token_where_line(t) ((t)->where_line)
+#define ffelex_token_where_line_number(t) \
+ ffewhere_line_number ((t)->where_line)
+#define ffelex_token_wheretrack(t) ((t)->wheretrack)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/malloc.c b/contrib/gcc/f/malloc.c
new file mode 100644
index 0000000..4560211
--- /dev/null
+++ b/contrib/gcc/f/malloc.c
@@ -0,0 +1,554 @@
+/* malloc.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Fast pool-based memory allocation.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "malloc.h"
+
+/* Assume gcc/toplev.o is linked in. */
+void *xmalloc (unsigned size);
+void *xrealloc (void *ptr, int size);
+
+/* Externals defined here. */
+
+struct _malloc_root_ malloc_root_
+=
+{
+ {
+ &malloc_root_.malloc_pool_image_,
+ &malloc_root_.malloc_pool_image_,
+ (mallocPool) &malloc_root_.malloc_pool_image_.eldest,
+ (mallocPool) &malloc_root_.malloc_pool_image_.eldest,
+ (mallocArea_) &malloc_root_.malloc_pool_image_.first,
+ (mallocArea_) &malloc_root_.malloc_pool_image_.first,
+ 0,
+#if MALLOC_DEBUG
+ 0, 0, 0, 0, 0, 0, 0, { '/' }
+#endif
+ },
+};
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+static void *malloc_reserve_ = NULL; /* For crashes. */
+#if MALLOC_DEBUG
+static char *malloc_types_[] =
+{"KS", "KSR", "NF", "NFR", "US", "USR"};
+#endif
+
+/* Static functions (internal). */
+
+static void malloc_kill_area_ (mallocPool pool, mallocArea_ a);
+#if MALLOC_DEBUG
+static void malloc_verify_area_ (mallocPool pool, mallocArea_ a);
+#endif
+
+/* Internal macros. */
+
+#if MALLOC_DEBUG
+#define malloc_kill_(ptr,s) do {memset((ptr),127,(s));free((ptr));} while(0)
+#else
+#define malloc_kill_(ptr,s) free((ptr))
+#endif
+
+/* malloc_kill_area_ -- Kill storage area and its object
+
+ malloc_kill_area_(mallocPool pool,mallocArea_ area);
+
+ Does the actual killing of a storage area. */
+
+static void
+malloc_kill_area_ (mallocPool pool UNUSED, mallocArea_ a)
+{
+#if MALLOC_DEBUG
+ assert (strcmp (a->name, ((char *) (a->where)) + a->size) == 0);
+#endif
+ malloc_kill_ (a->where, a->size);
+ a->next->previous = a->previous;
+ a->previous->next = a->next;
+#if MALLOC_DEBUG
+ pool->freed += a->size;
+ pool->frees++;
+#endif
+ malloc_kill_ (a,
+ offsetof (struct _malloc_area_, name)
+ + strlen (a->name) + 1);
+}
+
+/* malloc_verify_area_ -- Verify storage area and its object
+
+ malloc_verify_area_(mallocPool pool,mallocArea_ area);
+
+ Does the actual verifying of a storage area. */
+
+#if MALLOC_DEBUG
+static void
+malloc_verify_area_ (mallocPool pool UNUSED, mallocArea_ a UNUSED)
+{
+ mallocSize s = a->size;
+
+ assert (strcmp (a->name, ((char *) (a->where)) + s) == 0);
+}
+#endif
+
+/* malloc_init -- Initialize malloc cluster
+
+ malloc_init();
+
+ Call malloc_init before you do anything else. */
+
+void
+malloc_init ()
+{
+ if (malloc_reserve_ != NULL)
+ return;
+ malloc_reserve_ = malloc (20 * 1024); /* In case of crash, free this first. */
+ assert (malloc_reserve_ != NULL);
+}
+
+/* malloc_pool_display -- Display a pool
+
+ mallocPool p;
+ malloc_pool_display(p);
+
+ Displays information associated with the pool and its subpools. */
+
+void
+malloc_pool_display (mallocPool p UNUSED)
+{
+#if MALLOC_DEBUG
+ mallocPool q;
+ mallocArea_ a;
+
+ fprintf (dmpout, "Pool \"%s\": bytes allocated=%lu, freed=%lu, old sizes=%lu, new sizes\
+=%lu,\n allocations=%lu, frees=%lu, resizes=%lu, uses=%lu\n Subpools:\n",
+ p->name, p->allocated, p->freed, p->old_sizes, p->new_sizes, p->allocations,
+ p->frees, p->resizes, p->uses);
+
+ for (q = p->eldest; q != (mallocPool) & p->eldest; q = q->next)
+ fprintf (dmpout, " \"%s\"\n", q->name);
+
+ fprintf (dmpout, " Storage areas:\n");
+
+ for (a = p->first; a != (mallocArea_) & p->first; a = a->next)
+ {
+ fprintf (dmpout, " ");
+ malloc_display_ (a);
+ }
+#endif
+}
+
+/* malloc_pool_kill -- Destroy a pool
+
+ mallocPool p;
+ malloc_pool_kill(p);
+
+ Releases all storage associated with the pool and its subpools. */
+
+void
+malloc_pool_kill (mallocPool p)
+{
+ mallocPool q;
+ mallocArea_ a;
+
+ if (--p->uses != 0)
+ return;
+
+#if 0
+ malloc_pool_display (p);
+#endif
+
+ assert (p->next->previous == p);
+ assert (p->previous->next == p);
+
+ /* Kill off all the subpools. */
+
+ while ((q = p->eldest) != (mallocPool) &p->eldest)
+ {
+ q->uses = 1; /* Force the kill. */
+ malloc_pool_kill (q);
+ }
+
+ /* Now free all the storage areas. */
+
+ while ((a = p->first) != (mallocArea_) & p->first)
+ {
+ malloc_kill_area_ (p, a);
+ }
+
+ /* Now remove from list of sibling pools. */
+
+ p->next->previous = p->previous;
+ p->previous->next = p->next;
+
+ /* Finally, free the pool itself. */
+
+ malloc_kill_ (p,
+ offsetof (struct _malloc_pool_, name)
+ + strlen (p->name) + 1);
+}
+
+/* malloc_pool_new -- Make a new pool
+
+ mallocPool p;
+ p = malloc_pool_new("My new pool",malloc_pool_image(),1024);
+
+ Makes a new pool with the given name and default new-chunk allocation. */
+
+mallocPool
+malloc_pool_new (char *name, mallocPool parent,
+ unsigned long chunks UNUSED)
+{
+ mallocPool p;
+
+ if (parent == NULL)
+ parent = malloc_pool_image ();
+
+ p = malloc_new_ (offsetof (struct _malloc_pool_, name)
+ + (MALLOC_DEBUG ? strlen (name) + 1 : 0));
+ p->next = (mallocPool) &(parent->eldest);
+ p->previous = parent->youngest;
+ parent->youngest->next = p;
+ parent->youngest = p;
+ p->eldest = (mallocPool) &(p->eldest);
+ p->youngest = (mallocPool) &(p->eldest);
+ p->first = (mallocArea_) &(p->first);
+ p->last = (mallocArea_) &(p->first);
+ p->uses = 1;
+#if MALLOC_DEBUG
+ p->allocated = p->freed = p->old_sizes = p->new_sizes = p->allocations
+ = p->frees = p->resizes = 0;
+ strcpy (p->name, name);
+#endif
+ return p;
+}
+
+/* malloc_pool_use -- Use an existing pool
+
+ mallocPool p;
+ p = malloc_pool_new(pool);
+
+ Increments use count for pool; means a matching malloc_pool_kill must
+ be performed before a subsequent one will actually kill the pool. */
+
+mallocPool
+malloc_pool_use (mallocPool pool)
+{
+ ++pool->uses;
+ return pool;
+}
+
+/* malloc_display_ -- Display info on a mallocArea_
+
+ mallocArea_ a;
+ malloc_display_(a);
+
+ Simple. */
+
+void
+malloc_display_ (mallocArea_ a UNUSED)
+{
+#if MALLOC_DEBUG
+ fprintf (dmpout, "At %08lX, size=%" mallocSize_f "u, type=%s, \"%s\"\n",
+ (unsigned long) a->where, a->size, malloc_types_[a->type], a->name);
+#endif
+}
+
+/* malloc_find_inpool_ -- Find mallocArea_ for object in pool
+
+ mallocPool pool;
+ void *ptr;
+ mallocArea_ a;
+ a = malloc_find_inpool_(pool,ptr);
+
+ Search for object in list of mallocArea_s, die if not found. */
+
+mallocArea_
+malloc_find_inpool_ (mallocPool pool, void *ptr)
+{
+ mallocArea_ a;
+ mallocArea_ b = (mallocArea_) &pool->first;
+ int n = 0;
+
+ for (a = pool->first; a != (mallocArea_) &pool->first; a = a->next)
+ {
+ assert (("Infinite loop detected" != NULL) && (a != b));
+ if (a->where == ptr)
+ return a;
+ ++n;
+ if (n & 1)
+ b = b->next;
+ }
+ assert ("Couldn't find object in pool!" == NULL);
+ return NULL;
+}
+
+/* malloc_kill_inpool_ -- Kill object
+
+ malloc_kill_inpool_(NULL,MALLOC_typeUS_,ptr,size_in_bytes);
+
+ Find the mallocArea_ for the pointer, make sure the type is proper, and
+ kill both of them. */
+
+void
+malloc_kill_inpool_ (mallocPool pool, mallocType_ type UNUSED,
+ void *ptr, mallocSize s UNUSED)
+{
+ mallocArea_ a;
+
+ if (pool == NULL)
+ pool = malloc_pool_image ();
+
+#if MALLOC_DEBUG
+ assert ((pool == malloc_pool_image ())
+ || malloc_pool_find_ (pool, malloc_pool_image ()));
+#endif
+
+ a = malloc_find_inpool_ (pool, ptr);
+#if MALLOC_DEBUG
+ assert (a->type == type);
+ if ((type != MALLOC_typeUS_) && (type != MALLOC_typeUSR_))
+ assert (a->size == s);
+#endif
+ malloc_kill_area_ (pool, a);
+}
+
+/* malloc_new_ -- Allocate new object, die if unable
+
+ ptr = malloc_new_(size_in_bytes);
+
+ Call malloc, bomb if it returns NULL. */
+
+void *
+malloc_new_ (mallocSize s)
+{
+ void *ptr;
+ unsigned ss = s;
+
+#if MALLOC_DEBUG && 0
+ assert (s == (mallocSize) ss);/* Else alloc is too big for this
+ library/sys. */
+#endif
+
+ ptr = xmalloc (ss);
+#if MALLOC_DEBUG
+ memset (ptr, 126, ss); /* Catch some kinds of errors more
+ quickly/reliably. */
+#endif
+ return ptr;
+}
+
+/* malloc_new_inpool_ -- Allocate new object, die if unable
+
+ ptr = malloc_new_inpool_(NULL,MALLOC_typeUS_,"object",size_in_bytes);
+
+ Allocate the structure and allocate a mallocArea_ to describe it, then
+ add it to the list of mallocArea_s for the pool. */
+
+void *
+malloc_new_inpool_ (mallocPool pool, mallocType_ type, char *name, mallocSize s)
+{
+ void *ptr;
+ mallocArea_ a;
+ unsigned short i;
+
+ if (pool == NULL)
+ pool = malloc_pool_image ();
+
+#if MALLOC_DEBUG
+ assert ((pool == malloc_pool_image ())
+ || malloc_pool_find_ (pool, malloc_pool_image ()));
+#endif
+
+ ptr = malloc_new_ (s + (i = (MALLOC_DEBUG ? strlen (name) + 1 : 0)));
+#if MALLOC_DEBUG
+ strcpy (((char *) (ptr)) + s, name);
+#endif
+ a = malloc_new_ (offsetof (struct _malloc_area_, name) + i);
+ switch (type)
+ { /* A little optimization to speed up killing
+ of non-permanent stuff. */
+ case MALLOC_typeKP_:
+ case MALLOC_typeKPR_:
+ a->next = (mallocArea_) &pool->first;
+ break;
+
+ default:
+ a->next = pool->first;
+ break;
+ }
+ a->previous = a->next->previous;
+ a->next->previous = a;
+ a->previous->next = a;
+ a->where = ptr;
+#if MALLOC_DEBUG
+ a->size = s;
+ a->type = type;
+ strcpy (a->name, name);
+ pool->allocated += s;
+ pool->allocations++;
+#endif
+ return ptr;
+}
+
+/* malloc_new_zinpool_ -- Allocate new zeroed object, die if unable
+
+ ptr = malloc_new_zinpool_(NULL,MALLOC_typeUS_,"object",size_in_bytes,0);
+
+ Like malloc_new_inpool_, but zeros out all the bytes in the area (assuming
+ you pass it a 0). */
+
+void *
+malloc_new_zinpool_ (mallocPool pool, mallocType_ type, char *name, mallocSize s,
+ int z)
+{
+ void *ptr;
+
+ ptr = malloc_new_inpool_ (pool, type, name, s);
+ memset (ptr, z, s);
+ return ptr;
+}
+
+/* malloc_pool_find_ -- See if pool is a descendant of another pool
+
+ if (malloc_pool_find_(target_pool,parent_pool)) ...;
+
+ Recursive descent on each of the children of the parent pool, after
+ first checking the children themselves. */
+
+char
+malloc_pool_find_ (mallocPool pool, mallocPool parent)
+{
+ mallocPool p;
+
+ for (p = parent->eldest; p != (mallocPool) & parent->eldest; p = p->next)
+ {
+ if ((p == pool) || malloc_pool_find_ (pool, p))
+ return 1;
+ }
+ return 0;
+}
+
+/* malloc_resize_inpool_ -- Resize existing object in pool
+
+ ptr = malloc_resize_inpool_(NULL,MALLOC_typeUSR_,ptr,new_size,old_size);
+
+ Find the object's mallocArea_, check it out, then do the resizing. */
+
+void *
+malloc_resize_inpool_ (mallocPool pool, mallocType_ type UNUSED,
+ void *ptr, mallocSize ns, mallocSize os UNUSED)
+{
+ mallocArea_ a;
+
+ if (pool == NULL)
+ pool = malloc_pool_image ();
+
+#if MALLOC_DEBUG
+ assert ((pool == malloc_pool_image ())
+ || malloc_pool_find_ (pool, malloc_pool_image ()));
+#endif
+
+ a = malloc_find_inpool_ (pool, ptr);
+#if MALLOC_DEBUG
+ assert (a->type == type);
+ if ((type == MALLOC_typeKSR_) || (type == MALLOC_typeKPR_))
+ assert (a->size == os);
+ assert (strcmp (a->name, ((char *) (ptr)) + os) == 0);
+#endif
+ ptr = malloc_resize_ (ptr, ns + (MALLOC_DEBUG ? strlen (a->name) + 1: 0));
+ a->where = ptr;
+#if MALLOC_DEBUG
+ a->size = ns;
+ strcpy (((char *) (ptr)) + ns, a->name);
+ pool->old_sizes += os;
+ pool->new_sizes += ns;
+ pool->resizes++;
+#endif
+ return ptr;
+}
+
+/* malloc_resize_ -- Reallocate object, die if unable
+
+ ptr = malloc_resize_(ptr,size_in_bytes);
+
+ Call realloc, bomb if it returns NULL. */
+
+void *
+malloc_resize_ (void *ptr, mallocSize s)
+{
+ int ss = s;
+
+#if MALLOC_DEBUG && 0
+ assert (s == (mallocSize) ss);/* Too big if failure here. */
+#endif
+
+ ptr = xrealloc (ptr, ss);
+ return ptr;
+}
+
+/* malloc_verify_inpool_ -- Verify object
+
+ Find the mallocArea_ for the pointer, make sure the type is proper, and
+ verify both of them. */
+
+void
+malloc_verify_inpool_ (mallocPool pool UNUSED, mallocType_ type UNUSED,
+ void *ptr UNUSED, mallocSize s UNUSED)
+{
+#if MALLOC_DEBUG
+ mallocArea_ a;
+
+ if (pool == NULL)
+ pool = malloc_pool_image ();
+
+ assert ((pool == malloc_pool_image ())
+ || malloc_pool_find_ (pool, malloc_pool_image ()));
+
+ a = malloc_find_inpool_ (pool, ptr);
+ assert (a->type == type);
+ if ((type != MALLOC_typeUS_) && (type != MALLOC_typeUSR_))
+ assert (a->size == s);
+ malloc_verify_area_ (pool, a);
+#endif
+}
diff --git a/contrib/gcc/f/malloc.h b/contrib/gcc/f/malloc.h
new file mode 100644
index 0000000..ea43276
--- /dev/null
+++ b/contrib/gcc/f/malloc.h
@@ -0,0 +1,183 @@
+/* malloc.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ malloc.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_malloc
+#define _H_f_malloc
+
+#ifndef MALLOC_DEBUG
+#define MALLOC_DEBUG 0 /* 1 means check caller's use of this module. */
+#endif
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ MALLOC_typeKS_,
+ MALLOC_typeKSR_,
+ MALLOC_typeKP_,
+ MALLOC_typeKPR_,
+ MALLOC_typeUS_,
+ MALLOC_typeUSR_,
+ MALLOC_type_
+ } mallocType_;
+
+/* Typedefs. */
+
+typedef struct _malloc_area_ *mallocArea_;
+typedef struct _malloc_pool_ *mallocPool;
+typedef unsigned long int mallocSize;
+#define mallocSize_f "l"
+
+/* Include files needed by this one. */
+
+
+/* Structure definitions. */
+
+struct _malloc_area_
+ {
+ mallocArea_ next;
+ mallocArea_ previous;
+ void *where;
+#if MALLOC_DEBUG
+ mallocSize size;
+ mallocType_ type;
+#endif
+ char name[1];
+ };
+
+struct _malloc_pool_
+ {
+ mallocPool next;
+ mallocPool previous;
+ mallocPool eldest;
+ mallocPool youngest;
+ mallocArea_ first;
+ mallocArea_ last;
+ unsigned long uses;
+#if MALLOC_DEBUG
+ mallocSize allocated;
+ mallocSize freed;
+ mallocSize old_sizes;
+ mallocSize new_sizes;
+ unsigned long allocations;
+ unsigned long frees;
+ unsigned long resizes;
+#endif
+ char name[1];
+ };
+
+struct _malloc_root_
+ {
+ struct _malloc_pool_ malloc_pool_image_;
+ };
+
+/* Global objects accessed by users of this module. */
+
+extern struct _malloc_root_ malloc_root_;
+
+/* Declare functions with prototypes. */
+
+void malloc_display_ (mallocArea_ a);
+mallocArea_ malloc_find_inpool_ (mallocPool pool, void *ptr);
+void malloc_init (void);
+void malloc_kill_inpool_ (mallocPool pool, mallocType_ type, void *ptr,
+ mallocSize size);
+void *malloc_new_ (mallocSize size);
+void *malloc_new_inpool_ (mallocPool pool, mallocType_ type, char *name,
+ mallocSize size);
+void *malloc_new_zinpool_ (mallocPool pool, mallocType_ type, char *name,
+ mallocSize size, int z);
+void malloc_pool_display (mallocPool p);
+char malloc_pool_find_ (mallocPool p, mallocPool parent);
+void malloc_pool_kill (mallocPool p);
+mallocPool malloc_pool_new (char *name, mallocPool parent, unsigned long chunks);
+mallocPool malloc_pool_use (mallocPool p);
+void *malloc_resize_ (void *ptr, mallocSize new_size);
+void *malloc_resize_inpool_ (mallocPool pool, mallocType_ type, void *ptr,
+ mallocSize new_size, mallocSize old_size);
+void malloc_verify_inpool_ (mallocPool pool, mallocType_ type, void *ptr,
+ mallocSize size);
+
+/* Define macros. */
+
+#define malloc_new_ks(pool,name,size) \
+ malloc_new_inpool_ (pool,MALLOC_typeKS_,name,size)
+#define malloc_new_ksr(pool,name,size) \
+ malloc_new_inpool_ (pool,MALLOC_typeKSR_,name,size)
+#define malloc_new_kp(pool,name,size) \
+ malloc_new_inpool_ (pool,MALLOC_typeKP_,name,size)
+#define malloc_new_kpr(pool,name,size) \
+ malloc_new_inpool_ (pool,MALLOC_typeKPR_,name,size)
+#define malloc_new_us(pool,name,size) \
+ malloc_new_inpool_ (pool,MALLOC_typeUS_,name,size)
+#define malloc_new_usr(pool,name,size) \
+ malloc_new_inpool_ (pool,MALLOC_typeUSR_,name,size)
+#define malloc_new_zks(pool,name,size,z) \
+ malloc_new_zinpool_ (pool,MALLOC_typeKS_,name,size,z)
+#define malloc_new_zksr(pool,name,size,z) \
+ malloc_new_zinpool_ (pool,MALLOC_typeKSR_,name,size,z)
+#define malloc_new_zkp(pool,name,size,z) \
+ malloc_new_zinpool_ (pool,MALLOC_typeKP_,name,size,z)
+#define malloc_new_zkpr(pool,name,size,z) \
+ malloc_new_zinpool_ (pool,MALLOC_typeKPR_,name,size,z)
+#define malloc_new_zus(pool,name,size,z) \
+ malloc_new_zinpool_ (pool,MALLOC_typeUS_,name,size,z)
+#define malloc_new_zusr(pool,name,size,z) \
+ malloc_new_zinpool_ (pool,MALLOC_typeUSR_,name,size,z)
+#define malloc_kill_ks(pool,ptr,size) \
+ malloc_kill_inpool_ (pool,MALLOC_typeKS_,ptr,size)
+#define malloc_kill_ksr(pool,ptr,size) \
+ malloc_kill_inpool_ (pool,MALLOC_typeKSR_,ptr,size)
+#define malloc_kill_us(pool,ptr) \
+ malloc_kill_inpool_ (pool,MALLOC_typeUS_,ptr,0)
+#define malloc_kill_usr(pool,ptr) \
+ malloc_kill_inpool_ (pool,MALLOC_typeUSR_,ptr,0)
+#define malloc_pool_image() (&malloc_root_.malloc_pool_image_)
+#define malloc_resize_ksr(pool,ptr,new_size,old_size) \
+ malloc_resize_inpool_ (pool,MALLOC_typeKSR_,ptr,new_size,old_size)
+#define malloc_resize_kpr(pool,ptr,new_size,old_size) \
+ malloc_resize_inpool_ (pool,MALLOC_typeKPR_,ptr,new_size,old_size)
+#define malloc_resize_usr(pool,ptr,new_size) \
+ malloc_resize_inpool_ (pool,MALLOC_typeUSR_,ptr,new_size,0)
+#define malloc_verify_kp(pool,name,size) \
+ malloc_verify_inpool_ (pool,MALLOC_typeKP_,name,size)
+#define malloc_verify_kpr(pool,name,size) \
+ malloc_verify_inpool_ (pool,MALLOC_typeKPR_,name,size)
+#define malloc_verify_ks(pool,ptr,size) \
+ malloc_verify_inpool_ (pool,MALLOC_typeKS_,ptr,size)
+#define malloc_verify_ksr(pool,ptr,size) \
+ malloc_verify_inpool_ (pool,MALLOC_typeKSR_,ptr,size)
+#define malloc_verify_us(pool,ptr) \
+ malloc_verify_inpool_ (pool,MALLOC_typeUS_,ptr,0)
+#define malloc_verify_usr(pool,ptr) \
+ malloc_verify_inpool_ (pool,MALLOC_typeUSR_,ptr,0)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/name.c b/contrib/gcc/f/name.c
new file mode 100644
index 0000000..560f642
--- /dev/null
+++ b/contrib/gcc/f/name.c
@@ -0,0 +1,242 @@
+/* name.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None.
+
+ Description:
+ Name and name space abstraction.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "bad.h"
+#include "name.h"
+#include "lex.h"
+#include "malloc.h"
+#include "src.h"
+#include "where.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+static ffename ffename_lookup_ (ffenameSpace ns, ffelexToken t, bool *found);
+
+/* Internal macros. */
+
+
+/* Searches for and returns the matching ffename object, or returns a
+ pointer to the name before which the new name should go. */
+
+static ffename
+ffename_lookup_ (ffenameSpace ns, ffelexToken t, bool *found)
+{
+ ffename n;
+
+ for (n = ns->first; n != (ffename) &ns->first; n = n->next)
+ {
+ if (ffelex_token_strcmp (t, n->t) == 0)
+ {
+ *found = TRUE;
+ return n;
+ }
+ }
+
+ *found = FALSE;
+ return n; /* (n == (ffename) &ns->first) */
+}
+
+/* Searches for and returns the matching ffename object, or creates a new
+ one (with a NULL ffesymbol) and returns that. If last arg is TRUE,
+ check whether token meets character-content requirements (such as
+ "all characters must be uppercase", as determined by
+ ffesrc_bad_char_symbol (), issue diagnostic if it doesn't. */
+
+ffename
+ffename_find (ffenameSpace ns, ffelexToken t)
+{
+ ffename n;
+ ffename newn;
+ bool found;
+
+ assert (ns != NULL);
+ assert ((t != NULL) && ((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNAMES)));
+
+ n = ffename_lookup_ (ns, t, &found);
+ if (found)
+ return n;
+
+ newn = (ffename) malloc_new_ks (ns->pool, "FFENAME name", sizeof (*n));
+ newn->next = n;
+ newn->previous = n->previous;
+ n->previous = newn;
+ newn->previous->next = newn;
+ newn->t = ffelex_token_use (t);
+ newn->u.s = NULL;
+
+ return newn;
+}
+
+/* ffename_kill -- Kill name from name space
+
+ ffenameSpace ns;
+ ffename s;
+ ffename_kill(ns,s);
+
+ Removes the name from the name space. */
+
+void
+ffename_kill (ffenameSpace ns, ffename n)
+{
+ assert (ns != NULL);
+ assert (n != NULL);
+
+ ffelex_token_kill (n->t);
+ n->next->previous = n->previous;
+ n->previous->next = n->next;
+ malloc_kill_ks (ns->pool, n, sizeof (*n));
+}
+
+/* ffename_lookup -- Look up name in name space
+
+ ffenameSpace ns;
+ ffelexToken t;
+ ffename s;
+ n = ffename_lookup(ns,t);
+
+ Searches for and returns the matching ffename object, or returns NULL. */
+
+ffename
+ffename_lookup (ffenameSpace ns, ffelexToken t)
+{
+ ffename n;
+ bool found;
+
+ assert (ns != NULL);
+ assert ((t != NULL) && ((ffelex_token_type (t) == FFELEX_typeNAME)
+ || (ffelex_token_type (t) == FFELEX_typeNAMES)));
+
+ n = ffename_lookup_ (ns, t, &found);
+
+ return found ? n : NULL;
+}
+
+/* ffename_space_drive_global -- Call given fn for each global in name space
+
+ ffenameSpace ns;
+ ffeglobal (*fn)();
+ ffename_space_drive_global(ns,fn); */
+
+void
+ffename_space_drive_global (ffenameSpace ns, ffeglobal (*fn) ())
+{
+ ffename n;
+
+ if (ns == NULL)
+ return;
+
+ for (n = ns->first; n != (ffename) &ns->first; n = n->next)
+ {
+ if (n->u.g != NULL)
+ n->u.g = (*fn) (n->u.g);
+ }
+}
+
+/* ffename_space_drive_symbol -- Call given fn for each symbol in name space
+
+ ffenameSpace ns;
+ ffesymbol (*fn)();
+ ffename_space_drive_symbol(ns,fn); */
+
+void
+ffename_space_drive_symbol (ffenameSpace ns, ffesymbol (*fn) ())
+{
+ ffename n;
+
+ if (ns == NULL)
+ return;
+
+ for (n = ns->first; n != (ffename) &ns->first; n = n->next)
+ {
+ if (n->u.s != NULL)
+ n->u.s = (*fn) (n->u.s);
+ }
+}
+
+/* ffename_space_kill -- Kill name space
+
+ ffenameSpace ns;
+ ffename_space_kill(ns);
+
+ Removes the names from the name space; kills the name space. */
+
+void
+ffename_space_kill (ffenameSpace ns)
+{
+ assert (ns != NULL);
+
+ while (ns->first != (ffename) &ns->first)
+ ffename_kill (ns, ns->first);
+
+ malloc_kill_ks (ns->pool, ns, sizeof (*ns));
+}
+
+/* ffename_space_new -- Create name space
+
+ ffenameSpace ns;
+ ns = ffename_space_new(malloc_pool_image());
+
+ Create new name space. */
+
+ffenameSpace
+ffename_space_new (mallocPool pool)
+{
+ ffenameSpace ns;
+
+ ns = (ffenameSpace) malloc_new_ks (pool, "FFENAME space",
+ sizeof (*ns));
+ ns->first = (ffename) &ns->first;
+ ns->last = (ffename) &ns->first;
+ ns->pool = pool;
+
+ return ns;
+}
diff --git a/contrib/gcc/f/name.h b/contrib/gcc/f/name.h
new file mode 100644
index 0000000..8359ed6
--- /dev/null
+++ b/contrib/gcc/f/name.h
@@ -0,0 +1,109 @@
+/* name.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ name.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_name
+#define _H_f_name
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+typedef struct _ffename_ *ffename;
+typedef struct _ffename_space_ *ffenameSpace;
+
+/* Include files needed by this one. */
+
+#include "global.h"
+#include "lex.h"
+#include "malloc.h"
+#include "symbol.h"
+
+/* Structure definitions. */
+
+struct _ffename_
+ {
+ ffename next;
+ ffename previous;
+ ffelexToken t;
+ union
+ {
+ ffesymbol s;
+ ffeglobal g;
+ }
+ u;
+ };
+
+struct _ffename_space_
+ {
+ ffename first;
+ ffename last;
+ mallocPool pool;
+ };
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+ffename ffename_find (ffenameSpace ns, ffelexToken t);
+void ffename_kill (ffenameSpace ns, ffename n);
+ffename ffename_lookup (ffenameSpace ns, ffelexToken t);
+void ffename_space_drive_global (ffenameSpace ns, ffeglobal (*fn) ());
+void ffename_space_drive_symbol (ffenameSpace ns, ffesymbol (*fn) ());
+void ffename_space_kill (ffenameSpace ns);
+ffenameSpace ffename_space_new (mallocPool pool);
+
+/* Define macros. */
+
+#define ffename_first_token(n) ((n)->t)
+#define ffename_global(n) ((n)->u.g)
+#define ffename_init_0()
+#define ffename_init_1()
+#define ffename_init_2()
+#define ffename_init_3()
+#define ffename_init_4()
+#define ffename_set_global(n,glob) ((n)->u.g = (glob))
+#define ffename_set_symbol(n,sym) ((n)->u.s = (sym))
+#define ffename_symbol(n) ((n)->u.s)
+#define ffename_terminate_0()
+#define ffename_terminate_1()
+#define ffename_terminate_2()
+#define ffename_terminate_3()
+#define ffename_terminate_4()
+#define ffename_text(n) ffelex_token_text((n)->t)
+#define ffename_token(n) ((n)->t)
+#define ffename_where_filename(n) ffelex_token_where_filename((n)->t)
+#define ffename_where_filelinenum(n) ffelex_token_where_filelinenum((n)->t)
+#define ffename_where_line(n) ffelex_token_where_line((n)->t)
+#define ffename_where_column(n) ffelex_token_where_column((n)->t)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/news.texi b/contrib/gcc/f/news.texi
new file mode 100644
index 0000000..3885137
--- /dev/null
+++ b/contrib/gcc/f/news.texi
@@ -0,0 +1,2330 @@
+@c Copyright (C) 1995-1999 Free Software Foundation, Inc.
+@c This is part of the G77 manual.
+@c For copying conditions, see the file g77.texi.
+
+@c The text of this file appears in the file BUGS
+@c in the G77 distribution, as well as in the G77 manual.
+
+@c 1999-03-11
+
+@ifclear NEWSONLY
+@node News
+@chapter News About GNU Fortran
+@end ifclear
+@cindex versions, recent
+@cindex recent versions
+
+Changes made to recent versions of GNU Fortran are listed
+below, with the most recent version first.
+
+The changes are generally listed in order:
+
+@enumerate
+@item
+Code-generation and run-time-library bug-fixes
+
+@item
+Compiler and run-time-library crashes involving valid code
+that have been fixed
+
+@item
+New features
+
+@item
+Fixes and enhancements to existing features
+
+@item
+New diagnostics
+
+@item
+Internal improvements
+
+@item
+Miscellany
+@end enumerate
+
+This order is not strict---for example, some items
+involve a combination of these elements.
+
+Note that two variants of @code{g77} are tracked below.
+The @code{egcs} variant is described vis-a-vis
+previous versions of @code{egcs} and/or
+an official FSF version,
+as appropriate.
+
+Therefore, @code{egcs} versions sometimes have multiple listings
+to help clarify how they differ from other versions,
+though this can make getting a complete picture
+of what a particular @code{egcs} version contains
+somewhat more difficult.
+
+An online, ``live'' version of this document
+(derived directly from the up-to-date mainline version
+of @code{g77} within @code{egcs})
+is available at
+@uref{http://egcs.cygnus.com/onlinedocs/g77_news.html}.
+
+@heading In 0.5.24 and @code{egcs} 1.1.2 (versus 0.5.23 and 1.1.1):
+@itemize @bullet
+@item
+Fix the @code{IDate} Intrinsic (VXT)
+so the returned year is in the documented, non-Y2K-compliant range
+of 0--99,
+instead of being returned as 100 in the year 2000.
+
+@item
+Fix the @samp{Date_and_Time} intrinsic (in @code{libg2c})
+to return the milliseconds value properly
+in @var{Values}(8).
+
+@item
+Fix the @samp{LStat} intrinsic (in @code{libg2c})
+to return device-ID information properly
+in @var{SArray}(7).
+
+@item
+Improve documentation.
+@end itemize
+
+@heading In 0.5.24 and @code{egcs} 1.1.1 (versus 0.5.23 and 1.1):
+@itemize @bullet
+@item
+Fix @code{libg2c} so it performs an implicit @code{ENDFILE} operation
+(as appropriate)
+whenever a @code{REWIND} is done.
+
+(This bug was introduced in 0.5.23 and @code{egcs} 1.1 in
+@code{g77}'s version of @code{libf2c}.)
+
+@item
+Fix @code{libg2c} so it no longer crashes with a spurious diagnostic
+upon doing any I/O following a direct formatted write.
+
+(This bug was introduced in 0.5.23 and @code{egcs} 1.1 in
+@code{g77}'s version of @code{libf2c}.)
+
+@item
+Fix @code{g77} so it no longer crashes compiling references
+to the @samp{Rand} intrinsic on some systems.
+
+@item
+Fix @code{g77} portion of installation process so it works
+better on some systems
+(those with shells requiring @samp{else true} clauses
+on @samp{if} constructs
+for the completion code to be set properly).
+@end itemize
+
+@heading In @code{egcs} 1.1 (versus 0.5.24):
+@itemize @bullet
+@item
+Fix @code{g77} crash compiling code
+containing the construct @samp{CMPLX(0.)} or similar.
+
+@item
+Fix @code{g77} crash
+(or apparently infinite run-time)
+when compiling certain complicated expressions
+involving @code{COMPLEX} arithmetic
+(especially multiplication).
+
+@cindex DNRM2
+@cindex stack, 387 coprocessor
+@cindex Intel x86
+@cindex -O2
+@item
+Fix a code-generation bug that afflicted
+Intel x86 targets when @samp{-O2} was specified
+compiling, for example, an old version of
+the @samp{DNRM2} routine.
+
+The x87 coprocessor stack was being
+mismanaged in cases involving assigned @code{GOTO}
+and @code{ASSIGN}.
+
+@cindex alignment
+@cindex double-precision performance
+@cindex -malign-double
+@item
+Align static double-precision variables and arrays
+on Intel x86 targets
+regardless of whether @samp{-malign-double} is specified.
+
+Generally, this affects only local variables and arrays
+having the @code{SAVE} attribute
+or given initial values via @code{DATA}.
+@end itemize
+
+@c 1998-09-01: egcs-1.1 released.
+@heading In @code{egcs} 1.1 (versus @code{egcs} 1.0.3):
+@itemize @bullet
+@item
+Fix bugs in the @code{libU77} intrinsic @samp{HostNm}
+that wrote one byte beyond the end of its @samp{CHARACTER}
+argument,
+and in the @code{libU77} intrinsics
+@samp{GMTime} and @samp{LTime}
+that overwrote their arguments.
+
+@item
+Assumed arrays with negative bounds
+(such as @samp{REAL A(-1:*)})
+no longer elicit spurious diagnostics from @code{g77},
+even on systems with pointers having
+different sizes than integers.
+
+This bug is not known to have existed in any
+recent version of @code{gcc}.
+It was introduced in an early release of @code{egcs}.
+
+@item
+Valid combinations of @code{EXTERNAL},
+passing that external as a dummy argument
+without explicitly giving it a type,
+and, in a subsequent program unit,
+referencing that external as
+an external function with a different type
+no longer crash @code{g77}.
+
+@item
+@code{CASE DEFAULT} no longer crashes @code{g77}.
+
+@item
+The @samp{-Wunused} option no longer issues a spurious
+warning about the ``master'' procedure generated by
+@code{g77} for procedures containing @code{ENTRY} statements.
+
+@item
+Support @samp{FORMAT(I<@var{expr}>)} when @var{expr} is a
+compile-time constant @code{INTEGER} expression.
+
+@item
+Fix @code{g77} @samp{-g} option so procedures that
+use @samp{ENTRY} can be stepped through, line by line,
+in @code{gdb}.
+
+@item
+Allow any @code{REAL} argument to intrinsics
+@code{Second} and @code{CPU_Time}.
+
+@item
+Use @code{tempnam}, if available, to open scratch files
+(as in @samp{OPEN(STATUS='SCRATCH')})
+so that the @code{TMPDIR} environment variable,
+if present, is used.
+
+@item
+@code{g77}'s version of @code{libf2c} separates out
+the setting of global state
+(such as command-line arguments and signal handling)
+from @file{main.o} into distinct, new library
+archive members.
+
+This should make it easier to write portable applications
+that have their own (non-Fortran) @code{main()} routine
+properly set up the @code{libf2c} environment, even
+when @code{libf2c} (now @code{libg2c}) is a shared library.
+
+@item
+@code{g77} no longer installs the @file{f77} command
+and @file{f77.1} man page
+in the @file{/usr} or @file{/usr/local} heirarchy,
+even if the @file{f77-install-ok} file exists
+in the source or build directory.
+See the installation documentation for more information.
+
+@item
+@code{g77} no longer installs the @file{libf2c.a} library
+and @file{f2c.h} include file
+in the @file{/usr} or @file{/usr/local} heirarchy,
+even if the @file{f2c-install-ok} or @file{f2c-exists-ok} files exist
+in the source or build directory.
+See the installation documentation for more information.
+
+@item
+The @file{libf2c.a} library produced by @code{g77} has been
+renamed to @file{libg2c.a}.
+It is installed only in the @code{gcc} ``private''
+directory heirarchy, @file{gcc-lib}.
+This allows system administrators and users to choose which
+version of the @code{libf2c} library from @code{netlib} they
+wish to use on a case-by-case basis.
+See the installation documentation for more information.
+
+@item
+The @file{f2c.h} include (header) file produced by @code{g77}
+has been renamed to @file{g2c.h}.
+It is installed only in the @code{gcc} ``private''
+directory heirarchy, @file{gcc-lib}.
+This allows system administrators and users to choose which
+version of the include file from @code{netlib} they
+wish to use on a case-by-case basis.
+See the installation documentation for more information.
+
+@item
+The @code{g77} command now expects the run-time library
+to be named @code{libg2c.a} instead of @code{libf2c.a},
+to ensure that a version other than the one built and
+installed as part of the same @code{g77} version is picked up.
+
+@item
+During the configuration and build process,
+@code{g77} creates subdirectories it needs only as it
+needs them.
+Other cleaning up of the configuration and build process
+has been performed as well.
+
+@item
+@code{install-info} now used to update the directory of
+Info documentation to contain an entry for @code{g77}
+(during installation).
+
+@item
+Some diagnostics have been changed from warnings to errors,
+to prevent inadvertent use of the resulting, probably buggy,
+programs.
+These mostly include diagnostics about use of unsupported features
+in the @code{OPEN}, @code{INQUIRE}, @code{READ}, and
+@code{WRITE} statements,
+and about truncations of various sorts of constants.
+
+@item
+Improve compilation of @code{FORMAT} expressions so that
+a null byte is appended to the last operand if it
+is a constant.
+This provides a cleaner run-time diagnostic as provided
+by @code{libf2c} for statements like @samp{PRINT '(I1', 42}.
+
+@item
+Improve documentation and indexing.
+
+@item
+The upgrade to @code{libf2c} as of 1998-06-18
+should fix a variety of problems, including
+those involving some uses of the @samp{T} format
+specifier, and perhaps some build (porting) problems
+as well.
+@end itemize
+
+@heading In 0.5.24 and @code{egcs} 1.1 (versus 0.5.23):
+@itemize @bullet
+@item
+@code{g77} no longer produces incorrect code
+and initial values
+for @samp{EQUIVALENCE} and @samp{COMMON}
+aggregates that, due to ``unnatural'' ordering of members
+vis-a-vis their types, require initial padding.
+
+@item
+@code{g77} no longer crashes when compiling code
+containing specification statements such as
+@samp{INTEGER(KIND=7) PTR}.
+
+@item
+@code{g77} no longer crashes when compiling code
+such as @samp{J = SIGNAL(1, 2)}.
+
+@item
+@code{g77} now treats @samp{%LOC(@var{expr})} and
+@samp{LOC(@var{expr})} as ``ordinary'' expressions
+when they are used as arguments in procedure calls.
+This change applies only to global (filewide) analysis,
+making it consistent with
+how @code{g77} actually generates code
+for these cases.
+
+Previously, @code{g77} treated these expressions
+as denoting special ``pointer'' arguments
+for the purposes of filewide analysis.
+
+@item
+The @code{g77} driver now ensures that @samp{-lg2c}
+is specified in the link phase prior to any
+occurrence of @samp{-lm}.
+This prevents accidentally linking to a routine
+in the SunOS4 @samp{-lm} library
+when the generated code wants to link to the one
+in @code{libf2c} (@code{libg2c}).
+
+@item
+@code{g77} emits more debugging information when
+@samp{-g} is used.
+
+This new information allows, for example,
+@kbd{which __g77_length_a} to be used in @code{gdb}
+to determine the type of the phantom length argument
+supplied with @samp{CHARACTER} variables.
+
+This information pertains to internally-generated
+type, variable, and other information,
+not to the longstanding deficiencies vis-a-vis
+@samp{COMMON} and @samp{EQUIVALENCE}.
+
+@item
+The F90 @samp{Date_and_Time} intrinsic now is
+supported.
+
+@item
+The F90 @samp{System_Clock} intrinsic allows
+the optional arguments (except for the @samp{Count}
+argument) to be omitted.
+
+@item
+Upgrade to @code{libf2c} as of 1998-06-18.
+
+@item
+Improve documentation and indexing.
+@end itemize
+
+@c 1998-05-20: 0.5.23 released.
+@heading In 0.5.23 (versus 0.5.22):
+@itemize @bullet
+@item
+This release contains several regressions against
+version 0.5.22 of @code{g77}, due to using the
+``vanilla'' @code{gcc} back end instead of patching
+it to fix a few bugs and improve performance in a
+few cases.
+
+@ifset last-up-date
+@xref{Actual Bugs,,Actual Bugs We Haven't Fixed Yet},
+for information on the known bugs in this version,
+including the regressions.
+@end ifset
+
+@ifset NEWSONLY
+See @file{egcs/gcc/f/BUGS},
+for information on the known bugs in this version,
+including the regressions.
+@end ifset
+
+Features that have been dropped from this version
+of @code{g77} due to their being implemented
+via @code{g77}-specific patches to the @code{gcc}
+back end in previous releases include:
+
+@itemize --
+@item
+Support for @code{__restrict__} keyword,
+the options @samp{-fargument-alias}, @samp{-fargument-noalias},
+and @samp{-fargument-noalias-global},
+and the corresponding alias-analysis code.
+
+(@code{egcs} has the alias-analysis
+code, but not the @code{__restrict__} keyword.
+@code{egcs} @code{g77} users benefit from the alias-analysis
+code despite the lack of the @code{__restrict__} keyword,
+which is a C-language construct.)
+
+@item
+Support for the GNU compiler options
+@samp{-fmove-all-movables},
+@samp{-freduce-all-givs},
+and @samp{-frerun-loop-opt}.
+
+(@code{egcs} supports these options.
+@code{g77} users of @code{egcs} benefit from them even if
+they are not explicitly specified,
+because the defaults are optimized for @code{g77} users.)
+
+@item
+Support for the @samp{-W} option warning about
+integer division by zero.
+
+@item
+The Intel x86-specific option @samp{-malign-double}
+applying to stack-allocated data
+as well as statically-allocate data.
+@end itemize
+
+Note that the @file{gcc/f/gbe/} subdirectory has been removed
+from this distribution as a result of @code{g77} no longer
+including patches for the @code{gcc} back end.
+
+@item
+Fix bugs in the @code{libU77} intrinsic @samp{HostNm}
+that wrote one byte beyond the end of its @samp{CHARACTER}
+argument,
+and in the @code{libU77} intrinsics
+@samp{GMTime} and @samp{LTime}
+that overwrote their arguments.
+
+@item
+Support @code{gcc} version 2.8,
+and remove support for prior versions of @code{gcc}.
+
+@cindex -@w{}-driver option
+@cindex g77 options, -@w{}-driver
+@cindex options, -@w{}-driver
+@item
+Remove support for the @samp{--driver} option,
+as @code{g77} now does all the driving,
+just like @code{gcc}.
+
+@item
+@code{CASE DEFAULT} no longer crashes @code{g77}.
+
+@item
+Valid combinations of @code{EXTERNAL},
+passing that external as a dummy argument
+without explicitly giving it a type,
+and, in a subsequent program unit,
+referencing that external as
+an external function with a different type
+no longer crash @code{g77}.
+
+@item
+@code{g77} no longer installs the @file{f77} command
+and @file{f77.1} man page
+in the @file{/usr} or @file{/usr/local} heirarchy,
+even if the @file{f77-install-ok} file exists
+in the source or build directory.
+See the installation documentation for more information.
+
+@item
+@code{g77} no longer installs the @file{libf2c.a} library
+and @file{f2c.h} include file
+in the @file{/usr} or @file{/usr/local} heirarchy,
+even if the @file{f2c-install-ok} or @file{f2c-exists-ok} files exist
+in the source or build directory.
+See the installation documentation for more information.
+
+@item
+The @file{libf2c.a} library produced by @code{g77} has been
+renamed to @file{libg2c.a}.
+It is installed only in the @code{gcc} ``private''
+directory heirarchy, @file{gcc-lib}.
+This allows system administrators and users to choose which
+version of the @code{libf2c} library from @code{netlib} they
+wish to use on a case-by-case basis.
+See the installation documentation for more information.
+
+@item
+The @file{f2c.h} include (header) file produced by @code{g77}
+has been renamed to @file{g2c.h}.
+It is installed only in the @code{gcc} ``private''
+directory heirarchy, @file{gcc-lib}.
+This allows system administrators and users to choose which
+version of the include file from @code{netlib} they
+wish to use on a case-by-case basis.
+See the installation documentation for more information.
+
+@item
+The @code{g77} command now expects the run-time library
+to be named @code{libg2c.a} instead of @code{libf2c.a},
+to ensure that a version other than the one built and
+installed as part of the same @code{g77} version is picked up.
+
+@item
+The @samp{-Wunused} option no longer issues a spurious
+warning about the ``master'' procedure generated by
+@code{g77} for procedures containing @code{ENTRY} statements.
+
+@item
+@code{g77}'s version of @code{libf2c} separates out
+the setting of global state
+(such as command-line arguments and signal handling)
+from @file{main.o} into distinct, new library
+archive members.
+
+This should make it easier to write portable applications
+that have their own (non-Fortran) @code{main()} routine
+properly set up the @code{libf2c} environment, even
+when @code{libf2c} (now @code{libg2c}) is a shared library.
+
+@item
+During the configuration and build process,
+@code{g77} creates subdirectories it needs only as it
+needs them, thus avoiding unnecessary creation of, for example,
+@file{stage1/f/runtime} when doing a non-bootstrap build.
+Other cleaning up of the configuration and build process
+has been performed as well.
+
+@item
+@code{install-info} now used to update the directory of
+Info documentation to contain an entry for @code{g77}
+(during installation).
+
+@item
+Some diagnostics have been changed from warnings to errors,
+to prevent inadvertent use of the resulting, probably buggy,
+programs.
+These mostly include diagnostics about use of unsupported features
+in the @code{OPEN}, @code{INQUIRE}, @code{READ}, and
+@code{WRITE} statements,
+and about truncations of various sorts of constants.
+
+@item
+Improve documentation and indexing.
+
+@item
+Upgrade to @code{libf2c} as of 1998-04-20.
+
+This should fix a variety of problems, including
+those involving some uses of the @samp{T} format
+specifier, and perhaps some build (porting) problems
+as well.
+@end itemize
+
+@c 1998-03-16: 0.5.22 released.
+@heading In 0.5.22 (versus 0.5.21):
+@itemize @bullet
+@item
+Fix code generation for iterative @code{DO} loops that
+have one or more references to the iteration variable,
+or to aliases of it, in their control expressions.
+For example, @samp{DO 10 J=2,J} now is compiled correctly.
+
+@cindex DNRM2
+@cindex stack, 387 coprocessor
+@cindex Intel x86
+@cindex -O2
+@item
+Fix a code-generation bug that afflicted
+Intel x86 targets when @samp{-O2} was specified
+compiling, for example, an old version of
+the @samp{DNRM2} routine.
+
+The x87 coprocessor stack was being
+mismanaged in cases involving assigned @code{GOTO}
+and @code{ASSIGN}.
+
+@item
+Fix @code{DTime} intrinsic so as not to truncate
+results to integer values (on some systems).
+
+@item
+Fix @code{Signal} intrinsic so it offers portable
+support for 64-bit systems (such as Digital Alphas
+running GNU/Linux).
+
+@item
+Fix run-time crash involving @code{NAMELIST} on 64-bit
+machines such as Alphas.
+
+@item
+Fix @code{g77} version of @code{libf2c} so it no longer
+produces a spurious @samp{I/O recursion} diagnostic at run time
+when an I/O operation (such as @samp{READ *,I}) is interrupted
+in a manner that causes the program to be terminated
+via the @samp{f_exit} routine (such as via @kbd{C-c}).
+
+@item
+Fix @code{g77} crash triggered by @code{CASE} statement with
+an omitted lower or upper bound.
+
+@item
+Fix @code{g77} crash compiling references to @code{CPU_Time}
+intrinsic.
+
+@item
+Fix @code{g77} crash
+(or apparently infinite run-time)
+when compiling certain complicated expressions
+involving @code{COMPLEX} arithmetic
+(especially multiplication).
+
+@item
+Fix @code{g77} crash on statements such as
+@samp{PRINT *, (REAL(Z(I)),I=1,2)}, where
+@samp{Z} is @code{DOUBLE COMPLEX}.
+
+@item
+Fix a @code{g++} crash.
+
+@item
+Support @samp{FORMAT(I<@var{expr}>)} when @var{expr} is a
+compile-time constant @code{INTEGER} expression.
+
+@item
+Fix @code{g77} @samp{-g} option so procedures that
+use @samp{ENTRY} can be stepped through, line by line,
+in @code{gdb}.
+
+@item
+Fix a profiling-related bug in @code{gcc} back end for
+Intel x86 architecture.
+
+@item
+Allow any @code{REAL} argument to intrinsics
+@code{Second} and @code{CPU_Time}.
+
+@item
+Allow any numeric argument to intrinsics
+@code{Int2} and @code{Int8}.
+
+@item
+Use @code{tempnam}, if available, to open scratch files
+(as in @samp{OPEN(STATUS='SCRATCH')})
+so that the @code{TMPDIR} environment variable,
+if present, is used.
+
+@item
+Rename the @code{gcc} keyword @code{restrict} to
+@code{__restrict__}, to avoid rejecting valid, existing,
+C programs.
+Support for @code{restrict} is now more like support
+for @code{complex}.
+
+@item
+Fix @samp{-fpedantic} to not reject procedure invocations
+such as @samp{I=J()} and @samp{CALL FOO()}.
+
+@item
+Fix @samp{-fugly-comma} to affect invocations of
+only external procedures.
+Restore rejection of gratuitous trailing omitted
+arguments to intrinsics, as in @samp{I=MAX(3,4,,)}.
+
+@item
+Fix compiler so it accepts @samp{-fgnu-intrinsics-*} and
+@samp{-fbadu77-intrinsics-*} options.
+
+@item
+Improve diagnostic messages from @code{libf2c}
+so it is more likely that the printing of the
+active format string is limited to the string,
+with no trailing garbage being printed.
+
+(Unlike @code{f2c}, @code{g77} did not append
+a null byte to its compiled form of every
+format string specified via a @code{FORMAT} statement.
+However, @code{f2c} would exhibit the problem
+anyway for a statement like @samp{PRINT '(I)garbage', 1}
+by printing @samp{(I)garbage} as the format string.)
+
+@item
+Improve compilation of @code{FORMAT} expressions so that
+a null byte is appended to the last operand if it
+is a constant.
+This provides a cleaner run-time diagnostic as provided
+by @code{libf2c} for statements like @samp{PRINT '(I1', 42}.
+
+@item
+Fix various crashes involving code with diagnosed errors.
+
+@item
+Fix cross-compilation bug when configuring @code{libf2c}.
+
+@item
+Improve diagnostics.
+
+@item
+Improve documentation and indexing.
+
+@item
+Upgrade to @code{libf2c} as of 1997-09-23.
+This fixes a formatted-I/O bug that afflicted
+64-bit systems with 32-bit integers
+(such as Digital Alpha running GNU/Linux).
+@end itemize
+
+@c 1998-03-15: egcs-1.0.2 released.
+@heading In @code{egcs} 1.0.2 (versus @code{egcs} 1.0.1):
+@itemize @bullet
+@item
+Fix @code{g77} crash triggered by @code{CASE} statement with
+an omitted lower or upper bound.
+
+@item
+Fix @code{g77} crash on statements such as
+@samp{PRINT *, (REAL(Z(I)),I=1,2)}, where
+@samp{Z} is @code{DOUBLE COMPLEX}.
+
+@cindex ELF support
+@cindex support, ELF
+@cindex -fPIC option
+@cindex options, -fPIC
+@item
+Fix @samp{-fPIC} (such as compiling for ELF targets)
+on the Intel x86 architecture target
+so invalid assembler code is no longer produced.
+
+@item
+Fix @samp{-fpedantic} to not reject procedure invocations
+such as @samp{I=J()} and @samp{CALL FOO()}.
+
+@item
+Fix @samp{-fugly-comma} to affect invocations of
+only external procedures.
+Restore rejection of gratuitous trailing omitted
+arguments to intrinsics, as in @samp{I=MAX(3,4,,)}.
+
+@item
+Fix compiler so it accepts @samp{-fgnu-intrinsics-*} and
+@samp{-fbadu77-intrinsics-*} options.
+@end itemize
+
+@c 1998-01-02: egcs-1.0.1 released.
+@heading In @code{egcs} 1.0.1 (versus @code{egcs} 1.0):
+@itemize @bullet
+@item
+Fix run-time crash involving @code{NAMELIST} on 64-bit
+machines such as Alphas.
+@end itemize
+
+@c 1997-12-03: egcs-1.0 released.
+@heading In @code{egcs} 1.0 (versus 0.5.21):
+@itemize @bullet
+@item
+Version 1.0 of @code{egcs}
+contains several regressions against
+version 0.5.21 of @code{g77},
+due to using the
+``vanilla'' @code{gcc} back end instead of patching
+it to fix a few bugs and improve performance in a
+few cases.
+
+@ifset last-up-date
+@xref{Actual Bugs,,Actual Bugs We Haven't Fixed Yet},
+for information on the known bugs in this version,
+including the regressions.
+@end ifset
+
+@ifset NEWSONLY
+See @file{egcs/gcc/f/BUGS},
+for information on the known bugs in this version,
+including the regressions.
+@end ifset
+
+Features that have been dropped from this version
+of @code{g77} due to their being implemented
+via @code{g77}-specific patches to the @code{gcc}
+back end in previous releases include:
+
+@itemize --
+@item
+Support for the C-language @code{restrict} keyword.
+
+@item
+Support for the @samp{-W} option warning about
+integer division by zero.
+
+@item
+The Intel x86-specific option @samp{-malign-double}
+applying to stack-allocated data
+as well as statically-allocate data.
+@end itemize
+
+Note that the @file{gcc/f/gbe/} subdirectory has been removed
+from this distribution as a result of @code{g77}
+being fully integrated with
+the @code{egcs} variant of the @code{gcc} back end.
+
+@item
+Fix code generation for iterative @code{DO} loops that
+have one or more references to the iteration variable,
+or to aliases of it, in their control expressions.
+For example, @samp{DO 10 J=2,J} now is compiled correctly.
+
+@item
+Fix @code{DTime} intrinsic so as not to truncate
+results to integer values (on some systems).
+
+@item
+Remove support for non-@code{egcs} versions of @code{gcc}.
+
+@cindex -@w{}-driver option
+@cindex g77 options, -@w{}-driver
+@cindex options, -@w{}-driver
+@item
+Remove support for the @samp{--driver} option,
+as @code{g77} now does all the driving,
+just like @code{gcc}.
+
+@item
+Allow any numeric argument to intrinsics
+@code{Int2} and @code{Int8}.
+
+@item
+Improve diagnostic messages from @code{libf2c}
+so it is more likely that the printing of the
+active format string is limited to the string,
+with no trailing garbage being printed.
+
+(Unlike @code{f2c}, @code{g77} did not append
+a null byte to its compiled form of every
+format string specified via a @code{FORMAT} statement.
+However, @code{f2c} would exhibit the problem
+anyway for a statement like @samp{PRINT '(I)garbage', 1}
+by printing @samp{(I)garbage} as the format string.)
+
+@item
+Upgrade to @code{libf2c} as of 1997-09-23.
+This fixes a formatted-I/O bug that afflicted
+64-bit systems with 32-bit integers
+(such as Digital Alpha running GNU/Linux).
+@end itemize
+
+@c 1997-09-09: 0.5.21 released.
+@heading In 0.5.21:
+@itemize @bullet
+@item
+Fix a code-generation bug introduced by 0.5.20
+caused by loop unrolling (by specifying
+@samp{-funroll-loops} or similar).
+This bug afflicted all code compiled by
+version 2.7.2.2.f.2 of @code{gcc} (C, C++,
+Fortran, and so on).
+
+@item
+Fix a code-generation bug manifested when
+combining local @code{EQUIVALENCE} with a
+@code{DATA} statement that follows
+the first executable statement (or is
+treated as an executable-context statement
+as a result of using the @samp{-fpedantic}
+option).
+
+@item
+Fix a compiler crash that occured when an
+integer division by a constant zero is detected.
+Instead, when the @samp{-W} option is specified,
+the @code{gcc} back end issues a warning about such a case.
+This bug afflicted all code compiled by
+version 2.7.2.2.f.2 of @code{gcc} (C, C++,
+Fortran, and so on).
+
+@item
+Fix a compiler crash that occurred in some cases
+of procedure inlining.
+(Such cases became more frequent in 0.5.20.)
+
+@item
+Fix a compiler crash resulting from using @code{DATA}
+or similar to initialize a @code{COMPLEX} variable or
+array to zero.
+
+@item
+Fix compiler crashes involving use of @code{AND}, @code{OR},
+or @code{XOR} intrinsics.
+
+@item
+Fix compiler bug triggered when using a @code{COMMON}
+or @code{EQUIVALENCE} variable
+as the target of an @code{ASSIGN}
+or assigned-@code{GOTO} statement.
+
+@item
+Fix compiler crashes due to using the name of a some
+non-standard intrinsics (such as @samp{FTELL} or
+@samp{FPUTC}) as such and as the name of a procedure
+or common block.
+Such dual use of a name in a program is allowed by
+the standard.
+
+@c @code{g77}'s version of @code{libf2c} has been modified
+@c so that the external names of library's procedures do not
+@c conflict with names used for Fortran procedures compiled
+@c by @code{g77}.
+@c An additional layer of jacket procedures has been added
+@c to @code{libf2c} to map the old names to the new names,
+@c for automatic use by programs that interface to the
+@c library procedures via the external-procedure mechanism.
+@c
+@c For example, the intrinsic @code{FPUTC} previously was
+@c implemented by @code{g77} as a call to the @code{libf2c}
+@c routine @samp{fputc_}.
+@c This would conflict with a Fortran procedure named @code{FPUTC}
+@c (using default compiler options), and this conflict
+@c would cause a crash under certain circumstances.
+@c
+@c Now, the intrinsic @code{FPUTC} calls @samp{G77_fputc_0},
+@c which does not conflict with the @samp{fputc_} external
+@c that implements a Fortran procedure named @code{FPUTC}.
+@c
+@c Programs that refer to @code{FPUTC} as an external procedure
+@c without supplying their own implementation will link to
+@c the new @code{libf2c} routine @samp{fputc_}, which is
+@c simply a jacket routine that calls @samp{G77_fputc_0}.
+
+@item
+Place automatic arrays on the stack, even if
+@code{SAVE} or the @samp{-fno-automatic} option
+is in effect.
+This avoids a compiler crash in some cases.
+
+@item
+The @samp{-malign-double} option now reliably aligns
+@code{DOUBLE PRECISION} optimally on Pentium and
+Pentium Pro architectures (586 and 686 in @code{gcc}).
+
+@item
+New option @samp{-Wno-globals} disables warnings
+about ``suspicious'' use of a name both as a global
+name and as the implicit name of an intrinsic, and
+warnings about disagreements over the number or natures of
+arguments passed to global procedures, or the
+natures of the procedures themselves.
+
+The default is to issue such warnings, which are
+new as of this version of @code{g77}.
+
+@item
+New option @samp{-fno-globals} disables diagnostics
+about potentially fatal disagreements
+analysis problems, such as disagreements over the
+number or natures of arguments passed to global
+procedures, or the natures of those procedures themselves.
+
+The default is to issue such diagnostics and flag
+the compilation as unsuccessful.
+With this option, the diagnostics are issued as
+warnings, or, if @samp{-Wno-globals} is specified,
+are not issued at all.
+
+This option also disables inlining of global procedures,
+to avoid compiler crashes resulting from coding errors
+that these diagnostics normally would identify.
+
+@item
+Diagnose cases where a reference to a procedure
+disagrees with the type of that procedure, or
+where disagreements about the number or nature
+of arguments exist.
+This avoids a compiler crash.
+
+@item
+Fix parsing bug whereby @code{g77} rejected a
+second initialization specification immediately
+following the first's closing @samp{/} without
+an intervening comma in a @code{DATA} statement,
+and the second specification was an implied-DO list.
+
+@item
+Improve performance of the @code{gcc} back end so
+certain complicated expressions involving @code{COMPLEX}
+arithmetic (especially multiplication) don't appear to
+take forever to compile.
+
+@item
+Fix a couple of profiling-related bugs in @code{gcc}
+back end.
+
+@item
+Integrate GNU Ada's (GNAT's) changes to the back end,
+which consist almost entirely of bug fixes.
+These fixes are circa version 3.10p of GNAT.
+
+@item
+Include some other @code{gcc} fixes that seem useful in
+@code{g77}'s version of @code{gcc}.
+(See @file{gcc/ChangeLog} for details---compare it
+to that file in the vanilla @code{gcc-2.7.2.3.tar.gz}
+distribution.)
+
+@item
+Fix @code{libU77} routines that accept file and other names
+to strip trailing blanks from them, for consistency
+with other implementations.
+Blanks may be forcibly appended to such names by
+appending a single null character (@samp{CHAR(0)})
+to the significant trailing blanks.
+
+@item
+Fix @code{CHMOD} intrinsic to work with file names
+that have embedded blanks, commas, and so on.
+
+@item
+Fix @code{SIGNAL} intrinsic so it accepts an
+optional third @samp{Status} argument.
+
+@item
+Fix @code{IDATE()} intrinsic subroutine (VXT form)
+so it accepts arguments in the correct order.
+Documentation fixed accordingly, and for
+@code{GMTIME()} and @code{LTIME()} as well.
+
+@item
+Make many changes to @code{libU77} intrinsics to
+support existing code more directly.
+
+Such changes include allowing both subroutine and
+function forms of many routines, changing @code{MCLOCK()}
+and @code{TIME()} to return @code{INTEGER(KIND=1)} values,
+introducing @code{MCLOCK8()} and @code{TIME8()} to
+return @code{INTEGER(KIND=2)} values,
+and placing functions that are intended to perform
+side effects in a new intrinsic group, @code{badu77}.
+
+@item
+Improve @code{libU77} so it is more portable.
+
+@item
+Add options @samp{-fbadu77-intrinsics-delete},
+@samp{-fbadu77-intrinsics-hide}, and so on.
+
+@item
+Fix crashes involving diagnosed or invalid code.
+
+@item
+@code{g77} and @code{gcc} now do a somewhat better
+job detecting and diagnosing arrays that are too
+large to handle before these cause diagnostics
+during the assembler or linker phase, a compiler
+crash, or generation of incorrect code.
+
+@item
+Make some fixes to alias analysis code.
+
+@item
+Add support for @code{restrict} keyword in @code{gcc}
+front end.
+
+@item
+Support @code{gcc} version 2.7.2.3
+(modified by @code{g77} into version 2.7.2.3.f.1),
+and remove
+support for prior versions of @code{gcc}.
+
+@item
+Incorporate GNAT's patches to the @code{gcc} back
+end into @code{g77}'s, so GNAT users do not need
+to apply GNAT's patches to build both GNAT and @code{g77}
+from the same source tree.
+
+@item
+Modify @code{make} rules and related code so that
+generation of Info documentation doesn't require
+compilation using @code{gcc}.
+Now, any ANSI C compiler should be adequate to
+produce the @code{g77} documentation (in particular,
+the tables of intrinsics) from scratch.
+
+@item
+Add @code{INT2} and @code{INT8} intrinsics.
+
+@item
+Add @code{CPU_TIME} intrinsic.
+
+@item
+Add @code{ALARM} intrinsic.
+
+@item
+@code{CTIME} intrinsic now accepts any @code{INTEGER}
+argument, not just @code{INTEGER(KIND=2)}.
+
+@item
+Warn when explicit type declaration disagrees with
+the type of an intrinsic invocation.
+
+@item
+Support @samp{*f771} entry in @code{gcc} @file{specs} file.
+
+@item
+Fix typo in @code{make} rule @samp{g77-cross}, used only for
+cross-compiling.
+
+@item
+Fix @code{libf2c} build procedure to re-archive library
+if previous attempt to archive was interrupted.
+
+@item
+Change @code{gcc} to unroll loops only during the last
+invocation (of as many as two invocations) of loop
+optimization.
+
+@item
+Improve handling of @samp{-fno-f2c} so that code that
+attempts to pass an intrinsic as an actual argument,
+such as @samp{CALL FOO(ABS)}, is rejected due to the fact
+that the run-time-library routine is, effectively,
+compiled with @samp{-ff2c} in effect.
+
+@item
+Fix @code{g77} driver to recognize @samp{-fsyntax-only}
+as an option that inhibits linking, just like @samp{-c} or
+@samp{-S}, and to recognize and properly handle the
+@samp{-nostdlib}, @samp{-M}, @samp{-MM}, @samp{-nodefaultlibs},
+and @samp{-Xlinker} options.
+
+@item
+Upgrade to @code{libf2c} as of 1997-08-16.
+
+@item
+Modify @code{libf2c} to consistently and clearly diagnose
+recursive I/O (at run time).
+
+@item
+@code{g77} driver now prints version information (such as produced
+by @kbd{g77 -v}) to @code{stderr} instead of @code{stdout}.
+
+@item
+The @samp{.r} suffix now designates a Ratfor source file,
+to be preprocessed via the @code{ratfor} command, available
+separately.
+
+@item
+Fix some aspects of how @code{gcc} determines what kind of
+system is being configured and what kinds are supported.
+For example, GNU Linux/Alpha ELF systems now are directly
+supported.
+
+@item
+Improve diagnostics.
+
+@item
+Improve documentation and indexing.
+
+@item
+Include all pertinent files for @code{libf2c} that come
+from @code{netlib.bell-labs.com}; give any such files
+that aren't quite accurate in @code{g77}'s version of
+@code{libf2c} the suffix @samp{.netlib}.
+
+@item
+Reserve @code{INTEGER(KIND=0)} for future use.
+@end itemize
+
+@c 1997-02-28: 0.5.20 released.
+@heading In 0.5.20:
+@itemize @bullet
+@item
+The @samp{-fno-typeless-boz} option is now the default.
+
+This option specifies that non-decimal-radix
+constants using the prefixed-radix form (such as @samp{Z'1234'})
+are to be interpreted as @code{INTEGER} constants.
+Specify @samp{-ftypeless-boz} to cause such
+constants to be interpreted as typeless.
+
+(Version 0.5.19 introduced @samp{-fno-typeless-boz} and
+its inverse.)
+
+@item
+Options @samp{-ff90-intrinsics-enable} and
+@samp{-fvxt-intrinsics-enable} now are the
+defaults.
+
+Some programs might use names that clash with
+intrinsic names defined (and now enabled) by these
+options or by the new @code{libU77} intrinsics.
+Users of such programs might need to compile them
+differently (using, for example, @samp{-ff90-intrinsics-disable})
+or, better yet, insert appropriate @code{EXTERNAL}
+statements specifying that these names are not intended
+to be names of intrinsics.
+
+@item
+The @samp{ALWAYS_FLUSH} macro is no longer defined when
+building @code{libf2c}, which should result in improved
+I/O performance, especially over NFS.
+
+@emph{Note:} If you have code that depends on the behavior
+of @code{libf2c} when built with @samp{ALWAYS_FLUSH} defined,
+you will have to modify @code{libf2c} accordingly before
+building it from this and future versions of @code{g77}.
+
+@item
+Dave Love's implementation of @code{libU77} has been
+added to the version of @code{libf2c} distributed with
+and built as part of @code{g77}.
+@code{g77} now knows about the routines in this library
+as intrinsics.
+
+@item
+New option @samp{-fvxt} specifies that the
+source file is written in VXT Fortran, instead of GNU Fortran.
+
+@item
+The @samp{-fvxt-not-f90} option has been deleted,
+along with its inverse, @samp{-ff90-not-vxt}.
+
+If you used one of these deleted options, you should
+re-read the pertinent documentation to determine which
+options, if any, are appropriate for compiling your
+code with this version of @code{g77}.
+
+@item
+The @samp{-fugly} option now issues a warning, as it
+likely will be removed in a future version.
+
+(Enabling all the @samp{-fugly-*} options is unlikely
+to be feasible, or sensible, in the future,
+so users should learn to specify only those
+@samp{-fugly-*} options they really need for a
+particular source file.)
+
+@item
+The @samp{-fugly-assumed} option, introduced in
+version 0.5.19, has been changed to
+better accommodate old and new code.
+
+@item
+Make a number of fixes to the @code{g77} front end and
+the @code{gcc} back end to better support Alpha (AXP)
+machines.
+This includes providing at least one bug-fix to the
+@code{gcc} back end for Alphas.
+
+@item
+Related to supporting Alpha (AXP) machines, the @code{LOC()}
+intrinsic and @code{%LOC()} construct now return
+values of integer type that is the same width (holds
+the same number of bits) as the pointer type on the
+machine.
+
+On most machines, this won't make a difference, whereas
+on Alphas, the type these constructs return is
+@code{INTEGER*8} instead of the more common @code{INTEGER*4}.
+
+@item
+Emulate @code{COMPLEX} arithmetic in the @code{g77} front
+end, to avoid bugs in @code{complex} support in the
+@code{gcc} back end.
+New option @samp{-fno-emulate-complex}
+causes @code{g77} to revert the 0.5.19 behavior.
+
+@item
+Fix bug whereby @samp{REAL A(1)}, for example, caused
+a compiler crash if @samp{-fugly-assumed} was in effect
+and @var{A} was a local (automatic) array.
+That case is no longer affected by the new
+handling of @samp{-fugly-assumed}.
+
+@item
+Fix @code{g77} command driver so that @samp{g77 -o foo.f}
+no longer deletes @file{foo.f} before issuing other
+diagnostics, and so the @samp{-x} option is properly
+handled.
+
+@item
+Enable inlining of subroutines and functions by the @code{gcc}
+back end.
+This works as it does for @code{gcc} itself---program units
+may be inlined for invocations that follow them in the same
+program unit, as long as the appropriate compile-time
+options are specified.
+
+@item
+Dummy arguments are no longer assumed to potentially alias
+(overlap)
+other dummy arguments or @code{COMMON} areas when any of
+these are defined (assigned to) by Fortran code.
+
+This can result in faster and/or smaller programs when
+compiling with optimization enabled, though on some
+systems this effect is observed only when @samp{-fforce-addr}
+also is specified.
+
+New options @samp{-falias-check}, @samp{-fargument-alias},
+@samp{-fargument-noalias},
+and @samp{-fno-argument-noalias-global} control the
+way @code{g77} handles potential aliasing.
+
+@item
+The @code{CONJG()} and @code{DCONJG()} intrinsics now
+are compiled in-line.
+
+@item
+The bug-fix for 0.5.19.1 has been re-done.
+The @code{g77} compiler has been changed back to
+assume @code{libf2c} has no aliasing problems in
+its implementations of the @code{COMPLEX} (and
+@code{DOUBLE COMPLEX}) intrinsics.
+The @code{libf2c} has been changed to have no such
+problems.
+
+As a result, 0.5.20 is expected to offer improved performance
+over 0.5.19.1, perhaps as good as 0.5.19 in most
+or all cases, due to this change alone.
+
+@emph{Note:} This change requires version 0.5.20 of
+@code{libf2c}, at least, when linking code produced
+by any versions of @code{g77} other than 0.5.19.1.
+Use @samp{g77 -v} to determine the version numbers
+of the @code{libF77}, @code{libI77}, and @code{libU77}
+components of the @code{libf2c} library.
+(If these version numbers are not printed---in
+particular, if the linker complains about unresolved
+references to names like @samp{g77__fvers__}---that
+strongly suggests your installation has an obsolete
+version of @code{libf2c}.)
+
+@item
+New option @samp{-fugly-assign} specifies that the
+same memory locations are to be used to hold the
+values assigned by both statements @samp{I = 3} and
+@samp{ASSIGN 10 TO I}, for example.
+(Normally, @code{g77} uses a separate memory location
+to hold assigned statement labels.)
+
+@item
+@code{FORMAT} and @code{ENTRY} statements now are allowed to
+precede @code{IMPLICIT NONE} statements.
+
+@item
+Produce diagnostic for unsupported @code{SELECT CASE} on
+@code{CHARACTER} type, instead of crashing, at compile time.
+
+@item
+Fix crashes involving diagnosed or invalid code.
+
+@item
+Change approach to building @code{libf2c} archive
+(@file{libf2c.a}) so that members are added to it
+only when truly necessary, so the user that installs
+an already-built @code{g77} doesn't need to have write
+access to the build tree (whereas the user doing the
+build might not have access to install new software
+on the system).
+
+@item
+Support @code{gcc} version 2.7.2.2
+(modified by @code{g77} into version 2.7.2.2.f.2),
+and remove
+support for prior versions of @code{gcc}.
+
+@item
+Upgrade to @code{libf2c} as of 1997-02-08, and
+fix up some of the build procedures.
+
+@item
+Improve general build procedures for @code{g77},
+fixing minor bugs (such as deletion of any file
+named @file{f771} in the parent directory of @code{gcc/}).
+
+@item
+Enable full support of @code{INTEGER*8} available in
+@code{libf2c} and @file{f2c.h} so that @code{f2c} users
+may make full use of its features via the @code{g77}
+version of @file{f2c.h} and the @code{INTEGER*8}
+support routines in the @code{g77} version of @code{libf2c}.
+
+@item
+Improve @code{g77} driver and @code{libf2c} so that @samp{g77 -v}
+yields version information on the library.
+
+@item
+The @code{SNGL} and @code{FLOAT} intrinsics now are
+specific intrinsics, instead of synonyms for the
+generic intrinsic @code{REAL}.
+
+@item
+New intrinsics have been added.
+These are @code{REALPART}, @code{IMAGPART},
+@code{COMPLEX},
+@code{LONG}, and @code{SHORT}.
+
+@item
+A new group of intrinsics, @samp{gnu}, has been added
+to contain the new @code{REALPART}, @code{IMAGPART},
+and @code{COMPLEX} intrinsics.
+An old group, @samp{dcp}, has been removed.
+
+@item
+Complain about industry-wide ambiguous references
+@samp{REAL(@var{expr})} and @samp{AIMAG(@var{expr})},
+where @var{expr} is @code{DOUBLE COMPLEX} (or any
+complex type other than @code{COMPLEX}), unless
+@samp{-ff90} option specifies Fortran 90 interpretation
+or new @samp{-fugly-complex} option, in conjunction with
+@samp{-fnot-f90}, specifies @code{f2c} interpretation.
+
+@item
+Make improvements to diagnostics.
+
+@item
+Speed up compiler a bit.
+
+@item
+Improvements to documentation and indexing, including
+a new chapter containing information on one, later
+more, diagnostics that users are directed to pull
+up automatically via a message in the diagnostic itself.
+
+(Hence the menu item @samp{M} for the node
+@samp{Diagnostics} in the top-level menu of
+the Info documentation.)
+@end itemize
+
+@c 1997-02-01: 0.5.19.1 released.
+@heading In 0.5.19.1:
+@itemize @bullet
+@item
+Code-generation bugs afflicting operations on complex
+data have been fixed.
+
+These bugs occurred when assigning the result of an
+operation to a complex variable (or array element)
+that also served as an input to that operation.
+
+The operations affected by this bug were: @samp{CONJG()},
+@samp{DCONJG()}, @samp{CCOS()}, @samp{CDCOS()},
+@samp{CLOG()}, @samp{CDLOG()}, @samp{CSIN()}, @samp{CDSIN()},
+@samp{CSQRT()}, @samp{CDSQRT()}, complex division, and
+raising a @code{DOUBLE COMPLEX} operand to an @code{INTEGER}
+power.
+(The related generic and @samp{Z}-prefixed intrinsics,
+such as @samp{ZSIN()}, also were affected.)
+
+For example, @samp{C = CSQRT(C)}, @samp{Z = Z/C}, and @samp{Z = Z**I}
+(where @samp{C} is @code{COMPLEX} and @samp{Z} is
+@code{DOUBLE COMPLEX}) have been fixed.
+@end itemize
+
+@c 1996-12-07: 0.5.19 released.
+@heading In 0.5.19:
+@itemize @bullet
+@item
+Fix @code{FORMAT} statement parsing so negative values for
+specifiers such as @samp{P} (e.g. @samp{FORMAT(-1PF8.1)})
+are correctly processed as negative.
+
+@item
+Fix @code{SIGNAL} intrinsic so it once again accepts a
+procedure as its second argument.
+
+@item
+A temporary kludge option provides bare-bones information on
+@code{COMMON} and @code{EQUIVALENCE} members at debug time.
+
+@item
+New @samp{-fonetrip} option specifies FORTRAN-66-style
+one-trip @code{DO} loops.
+
+@item
+New @samp{-fno-silent} option causes names of program units
+to be printed as they are compiled, in a fashion similar to
+UNIX @code{f77} and @code{f2c}.
+
+@item
+New @samp{-fugly-assumed} option specifies that arrays
+dimensioned via @samp{DIMENSION X(1)}, for example, are to be
+treated as assumed-size.
+
+@item
+New @samp{-fno-typeless-boz} option specifies that non-decimal-radix
+constants using the prefixed-radix form (such as @samp{Z'1234'})
+are to be interpreted as @code{INTEGER} constants.
+
+@item
+New @samp{-ff66} option is a ``shorthand'' option that specifies
+behaviors considered appropriate for FORTRAN 66 programs.
+
+@item
+New @samp{-ff77} option is a ``shorthand'' option that specifies
+behaviors considered appropriate for UNIX @code{f77} programs.
+
+@item
+New @samp{-fugly-comma} and @samp{-fugly-logint} options provided
+to perform some of what @samp{-fugly} used to do.
+@samp{-fugly} and @samp{-fno-ugly} are now ``shorthand'' options,
+in that they do nothing more than enable (or disable) other
+@samp{-fugly-*} options.
+
+@item
+Fix parsing of assignment statements involving targets that
+are substrings of elements of @code{CHARACTER} arrays having
+names such as @samp{READ}, @samp{WRITE}, @samp{GOTO}, and
+@samp{REALFUNCTIONFOO}.
+
+@item
+Fix crashes involving diagnosed code.
+
+@item
+Fix handling of local @code{EQUIVALENCE} areas so certain cases
+of valid Fortran programs are not misdiagnosed as improperly
+extending the area backwards.
+
+@item
+Support @code{gcc} version 2.7.2.1.
+
+@item
+Upgrade to @code{libf2c} as of 1996-09-26, and
+fix up some of the build procedures.
+
+@item
+Change code generation for list-directed I/O so it allows
+for new versions of @code{libf2c} that might return non-zero
+status codes for some operations previously assumed to always
+return zero.
+
+This change not only affects how @code{IOSTAT=} variables
+are set by list-directed I/O, it also affects whether
+@code{END=} and @code{ERR=} labels are reached by these
+operations.
+
+@item
+Add intrinsic support for new @code{FTELL} and @code{FSEEK}
+procedures in @code{libf2c}.
+
+@item
+Modify @code{fseek_()} in @code{libf2c} to be more portable
+(though, in practice, there might be no systems where this
+matters) and to catch invalid @samp{whence} arguments.
+
+@item
+Some useless warnings from the @samp{-Wunused} option have
+been eliminated.
+
+@item
+Fix a problem building the @file{f771} executable
+on AIX systems by linking with the @samp{-bbigtoc} option.
+
+@item
+Abort configuration if @code{gcc} has not been patched
+using the patch file provided in the @samp{gcc/f/gbe/}
+subdirectory.
+
+@item
+Add options @samp{--help} and @samp{--version} to the
+@code{g77} command, to conform to GNU coding guidelines.
+Also add printing of @code{g77} version number when
+the @samp{--verbose} (@samp{-v}) option is used.
+
+@item
+Change internally generated name for local @code{EQUIVALENCE}
+areas to one based on the alphabetically sorted first name
+in the list of names for entities placed at the beginning
+of the areas.
+
+@item
+Improvements to documentation and indexing.
+@end itemize
+
+@c 1996-04-01: 0.5.18 released.
+@heading In 0.5.18:
+@itemize @bullet
+@item
+Add some rudimentary support for @code{INTEGER*1},
+@code{INTEGER*2}, @code{INTEGER*8},
+and their @code{LOGICAL} equivalents.
+(This support works on most, maybe all, @code{gcc} targets.)
+
+Thanks to Scott Snyder (@email{snyder@@d0sgif.fnal.gov})
+for providing the patch for this!
+
+Among the missing elements from the support for these
+features are full intrinsic support and constants.
+
+@item
+Add some rudimentary support for the @code{BYTE} and
+@code{WORD} type-declaration statements.
+@code{BYTE} corresponds to @code{INTEGER*1},
+while @code{WORD} corresponds to @code{INTEGER*2}.
+
+Thanks to Scott Snyder (@email{snyder@@d0sgif.fnal.gov})
+for providing the patch for this!
+
+@item
+The compiler code handling intrinsics has been largely
+rewritten to accommodate the new types.
+No new intrinsics or arguments for existing
+intrinsics have been added, so there is, at this
+point, no intrinsic to convert to @code{INTEGER*8},
+for example.
+
+@item
+Support automatic arrays in procedures.
+
+@item
+Reduce space/time requirements for handling large
+@emph{sparsely} initialized aggregate arrays.
+This improvement applies to only a subset of
+the general problem to be addressed in 0.6.
+
+@item
+Treat initial values of zero as if they weren't
+specified (in DATA and type-declaration statements).
+The initial values will be set to zero anyway, but the amount
+of compile time processing them will be reduced,
+in some cases significantly (though, again, this
+is only a subset of the general problem to be
+addressed in 0.6).
+
+A new option, @samp{-fzeros}, is introduced to
+enable the traditional treatment of zeros as any
+other value.
+
+@item
+With @samp{-ff90} in force, @code{g77} incorrectly
+interpreted @samp{REAL(Z)} as returning a @code{REAL}
+result, instead of as a @code{DOUBLE PRECISION}
+result.
+(Here, @samp{Z} is @code{DOUBLE COMPLEX}.)
+
+With @samp{-fno-f90} in force, the interpretation remains
+unchanged, since this appears to be how at least some
+F77 code using the @code{DOUBLE COMPLEX} extension expected
+it to work.
+
+Essentially, @samp{REAL(Z)} in F90 is the same as
+@samp{DBLE(Z)}, while in extended F77, it appears to
+be the same as @samp{REAL(REAL(Z))}.
+
+@item
+An expression involving exponentiation, where both operands
+were type @code{INTEGER} and the right-hand operand
+was negative, was erroneously evaluated.
+
+@item
+Fix bugs involving @code{DATA} implied-@code{DO} constructs
+(these involved an errant diagnostic and a crash, both on good
+code, one involving subsequent statement-function definition).
+
+@item
+Close @code{INCLUDE} files after processing them, so compiling source
+files with lots of @code{INCLUDE} statements does not result in
+being unable to open @code{INCLUDE} files after all the available
+file descriptors are used up.
+
+@item
+Speed up compiling, especially of larger programs, and perhaps
+slightly reduce memory utilization while compiling (this is
+@emph{not} the improvement planned for 0.6 involving large aggregate
+areas)---these improvements result from simply turning
+off some low-level code to do self-checking that hasn't been
+triggered in a long time.
+
+@item
+Introduce three new options that
+implement optimizations in the @code{gcc} back end (GBE).
+These options are @samp{-fmove-all-movables}, @samp{-freduce-all-givs},
+and @samp{-frerun-loop-opt}, which are enabled, by default,
+for Fortran compilations.
+These optimizations are intended to help toon Fortran programs.
+
+@item
+Patch the GBE to do a better job optimizing certain
+kinds of references to array elements.
+
+@item
+Due to patches to the GBE, the version number of @code{gcc}
+also is patched to make it easier to manage installations,
+especially useful if it turns out a @code{g77} change to the
+GBE has a bug.
+
+The @code{g77}-modified version number is the @code{gcc}
+version number with the string @samp{.f.@var{n}} appended,
+where @samp{f} identifies the version as enhanced for
+Fortran, and @var{n} is @samp{1} for the first Fortran
+patch for that version of @code{gcc}, @samp{2} for the
+second, and so on.
+
+So, this introduces version 2.7.2.f.1 of @code{gcc}.
+
+@item
+Make several improvements and fixes to diagnostics, including
+the removal of two that were inappropriate or inadequate.
+
+@item
+Warning about two successive arithmetic operators, produced
+by @samp{-Wsurprising}, now produced @emph{only} when both
+operators are, indeed, arithmetic (not relational/boolean).
+
+@item
+@samp{-Wsurprising} now warns about the remaining cases
+of using non-integral variables for implied-@code{DO}
+loops, instead of these being rejected unless @samp{-fpedantic}
+or @samp{-fugly} specified.
+
+@item
+Allow @code{SAVE} of a local variable or array, even after
+it has been given an initial value via @code{DATA}, for example.
+
+@item
+Introduce an Info version of @code{g77} documentation, which
+supercedes @file{gcc/f/CREDITS}, @file{gcc/f/DOC}, and
+@file{gcc/f/PROJECTS}.
+These files will be removed in a future release.
+The files @file{gcc/f/BUGS}, @file{gcc/f/INSTALL}, and
+@file{gcc/f/NEWS} now are automatically built from
+the texinfo source when distributions are made.
+
+This effort was inspired by a first pass at translating
+@file{g77-0.5.16/f/DOC} that was contributed to Craig by
+David Ronis (@email{ronis@@onsager.chem.mcgill.ca}).
+
+@item
+New @samp{-fno-second-underscore} option to specify
+that, when @samp{-funderscoring} is in effect, a second
+underscore is not to be appended to Fortran names already
+containing an underscore.
+
+@item
+Change the way iterative @code{DO} loops work to follow
+the F90 standard.
+In particular, calculation of the iteration count is
+still done by converting the start, end, and increment
+parameters to the type of the @code{DO} variable, but
+the result of the calculation is always converted to
+the default @code{INTEGER} type.
+
+(This should have no effect on existing code compiled
+by @code{g77}, but code written to assume that use
+of a @emph{wider} type for the @code{DO} variable
+will result in an iteration count being fully calculated
+using that wider type (wider
+than default @code{INTEGER}) must be rewritten.)
+
+@item
+Support @code{gcc} version 2.7.2.
+
+@item
+Upgrade to @code{libf2c} as of 1996-03-23, and
+fix up some of the build procedures.
+
+Note that the email addresses related to @code{f2c}
+have changed---the distribution site now is
+named @code{netlib.bell-labs.com}, and the
+maintainer's new address is @email{dmg@@bell-labs.com}.
+@end itemize
+
+@c 1995-11-18: 0.5.17 released.
+@heading In 0.5.17:
+@itemize @bullet
+@item
+@strong{Fix serious bug} in @samp{g77 -v} command that can cause removal of a
+system's @file{/dev/null} special file if run by user @samp{root}.
+
+@strong{All users} of version 0.5.16 should ensure that
+they have not removed @file{/dev/null} or replaced it with an ordinary
+file (e.g. by comparing the output of @samp{ls -l /dev/null} with
+@samp{ls -l /dev/zero}.
+If the output isn't basically the
+same, contact your system
+administrator about restoring @file{/dev/null} to its proper status).
+
+This bug is particularly insidious because removing @file{/dev/null} as
+a special file can go undetected for quite a while, aside from
+various applications and programs exhibiting sudden, strange
+behaviors.
+
+I sincerely apologize for not realizing the
+implications of the fact that when @samp{g77 -v} runs the @code{ld} command
+with @samp{-o /dev/null} that @code{ld} tries to @emph{remove} the executable
+it is supposed to build (especially if it reports unresolved
+references, which it should in this case)!
+
+@item
+Fix crash on @samp{CHARACTER*(*) FOO} in a main or block data program unit.
+
+@item
+Fix crash that can occur when diagnostics given outside of any
+program unit (such as when input file contains @samp{@@foo}).
+
+@item
+Fix crashes, infinite loops (hangs), and such involving diagnosed code.
+
+@item
+Fix @code{ASSIGN}'ed variables so they can be @code{SAVE}'d or dummy arguments,
+and issue clearer error message in cases where target of @code{ASSIGN}
+or @code{ASSIGN}ed @code{GOTO}/@code{FORMAT} is too small (which should
+never happen).
+
+@item
+Make @code{libf2c} build procedures work on more systems again by
+eliminating unnecessary invocations of @samp{ld -r -x} and @samp{mv}.
+
+@item
+Fix omission of @samp{-funix-intrinsics-@dots{}} options in list of permitted
+options to compiler.
+
+@item
+Fix failure to always diagnose missing type declaration for
+@code{IMPLICIT NONE}.
+
+@item
+Fix compile-time performance problem (which could sometimes
+crash the compiler, cause a hang, or whatever, due to a bug
+in the back end) involving exponentiation with a large @code{INTEGER}
+constant for the right-hand operator (e.g. @samp{I**32767}).
+
+@item
+Fix build procedures so cross-compiling @code{g77} (the @code{fini}
+utility in particular) is properly built using the host compiler.
+
+@item
+Add new @samp{-Wsurprising} option to warn about constructs that are
+interpreted by the Fortran standard (and @code{g77}) in ways that
+are surprising to many programmers.
+
+@item
+Add @code{ERF()} and @code{ERFC()} as generic intrinsics mapping to existing
+@code{ERF}/@code{DERF} and @code{ERFC}/@code{DERFC} specific intrinsics.
+
+@emph{Note:} You should
+specify @samp{INTRINSIC ERF,ERFC} in any code where you might use
+these as generic intrinsics, to improve likelihood of diagnostics
+(instead of subtle run-time bugs) when using a compiler that
+doesn't support these as intrinsics (e.g. @code{f2c}).
+
+@item
+Remove from @samp{-fno-pedantic} the diagnostic about @code{DO}
+with non-@code{INTEGER} index variable; issue that under
+@samp{-Wsurprising} instead.
+
+@item
+Clarify some diagnostics that say things like ``ignored'' when that's
+misleading.
+
+@item
+Clarify diagnostic on use of @code{.EQ.}/@code{.NE.} on @code{LOGICAL}
+operands.
+
+@item
+Minor improvements to code generation for various operations on
+@code{LOGICAL} operands.
+
+@item
+Minor improvement to code generation for some @code{DO} loops on some
+machines.
+
+@item
+Support @code{gcc} version 2.7.1.
+
+@item
+Upgrade to @code{libf2c} as of 1995-11-15.
+@end itemize
+
+@c 1995-08-30: 0.5.16 released.
+@heading In 0.5.16:
+@itemize @bullet
+@item
+Fix a code-generation bug involving complicated @code{EQUIVALENCE} statements
+not involving @code{COMMON}.
+
+@item
+Fix code-generation bugs involving invoking ``gratis'' library procedures
+in @code{libf2c} from code compiled with @samp{-fno-f2c} by making these
+procedures known to @code{g77} as intrinsics (not affected by -fno-f2c).
+This is known to fix code invoking @code{ERF()}, @code{ERFC()},
+@code{DERF()}, and @code{DERFC()}.
+
+@item
+Update @code{libf2c} to include netlib patches through 1995-08-16, and
+@code{#define} @samp{WANT_LEAD_0} to 1 to make @code{g77}-compiled code more
+consistent with other Fortran implementations by outputting
+leading zeros in formatted and list-directed output.
+
+@item
+Fix a code-generation bug involving adjustable dummy arrays with high
+bounds whose primaries are changed during procedure execution, and
+which might well improve code-generation performance for such arrays
+compared to @code{f2c} plus @code{gcc} (but apparently only when using
+@file{gcc-2.7.0} or later).
+
+@item
+Fix a code-generation bug involving invocation of @code{COMPLEX} and
+@code{DOUBLE COMPLEX} @code{FUNCTION}s and doing @code{COMPLEX} and
+@code{DOUBLE COMPLEX} divides, when the result
+of the invocation or divide is assigned directly to a variable
+that overlaps one or more of the arguments to the invocation or divide.
+
+@item
+Fix crash by not generating new optimal code for @samp{X**I} if @samp{I} is
+nonconstant and the expression is used to dimension a dummy
+array, since the @code{gcc} back end does not support the necessary
+mechanics (and the @code{gcc} front end rejects the equivalent
+construct, as it turns out).
+
+@item
+Fix crash on expressions like @samp{COMPLEX**INTEGER}.
+
+@item
+Fix crash on expressions like @samp{(1D0,2D0)**2}, i.e. raising a
+@code{DOUBLE COMPLEX} constant to an @code{INTEGER} constant power.
+
+@item
+Fix crashes and such involving diagnosed code.
+
+@item
+Diagnose, instead of crashing on, statement function definitions
+having duplicate dummy argument names.
+
+@item
+Fix bug causing rejection of good code involving statement function
+definitions.
+
+@item
+Fix bug resulting in debugger not knowing size of local equivalence
+area when any member of area has initial value (via @code{DATA},
+for example).
+
+@item
+Fix installation bug that prevented installation of @code{g77} driver.
+Provide for easy selection of whether to install copy of @code{g77}
+as @code{f77} to replace the broken code.
+
+@item
+Fix @code{gcc} driver (affects @code{g77} thereby) to not
+gratuitously invoke the
+@code{f771} program (e.g. when @samp{-E} is specified).
+
+@item
+Fix diagnostic to point to correct source line when it immediately
+follows an @code{INCLUDE} statement.
+
+@item
+Support more compiler options in @code{gcc}/@code{g77} when
+compiling Fortran files.
+These options include @samp{-p}, @samp{-pg}, @samp{-aux-info}, @samp{-P},
+correct setting of version-number macros for preprocessing, full
+recognition of @samp{-O0}, and
+automatic insertion of configuration-specific linker specs.
+
+@item
+Add new intrinsics that interface to existing routines in @code{libf2c}:
+@code{ABORT}, @code{DERF}, @code{DERFC}, @code{ERF}, @code{ERFC}, @code{EXIT},
+@code{FLUSH}, @code{GETARG}, @code{GETENV}, @code{IARGC},
+@code{SIGNAL}, and @code{SYSTEM}.
+Note that @code{ABORT}, @code{EXIT}, @code{FLUSH}, @code{SIGNAL}, and
+@code{SYSTEM} are intrinsic subroutines, not functions (since they
+have side effects), so to get the return values from @code{SIGNAL}
+and @code{SYSTEM}, append a final argument specifying an @code{INTEGER}
+variable or array element (e.g. @samp{CALL SYSTEM('rm foo',ISTAT)}).
+
+@item
+Add new intrinsic group named @samp{unix} to contain the new intrinsics,
+and by default enable this new group.
+
+@item
+Move @code{LOC()} intrinsic out of the @samp{vxt} group to the new
+@samp{unix} group.
+
+@item
+Improve @code{g77} so that @samp{g77 -v} by itself (or with
+certain other options, including @samp{-B}, @samp{-b}, @samp{-i},
+@samp{-nostdlib}, and @samp{-V}) reports lots more useful
+version info, and so that long-form options @code{gcc} accepts are
+understood by @code{g77} as well (even in truncated, unambiguous forms).
+
+@item
+Add new @code{g77} option @samp{--driver=name} to specify driver when
+default, @code{gcc}, isn't appropriate.
+
+@item
+Add support for @samp{#} directives (as output by the preprocessor) in the
+compiler, and enable generation of those directives by the
+preprocessor (when compiling @samp{.F} files) so diagnostics and debugging
+info are more useful to users of the preprocessor.
+
+@item
+Produce better diagnostics, more like @code{gcc}, with info such as
+@samp{In function `foo':} and @samp{In file included from...:}.
+
+@item
+Support @code{gcc}'s @samp{-fident} and @samp{-fno-ident} options.
+
+@item
+When @samp{-Wunused} in effect, don't warn about local variables used as
+statement-function dummy arguments or @code{DATA} implied-@code{DO} iteration
+variables, even though, strictly speaking, these are not uses
+of the variables themselves.
+
+@item
+When @samp{-W -Wunused} in effect, don't warn about unused dummy arguments
+at all, since there's no way to turn this off for individual
+cases (@code{g77} might someday start warning about these)---applies
+to @code{gcc} versions 2.7.0 and later, since earlier versions didn't
+warn about unused dummy arguments.
+
+@item
+New option @samp{-fno-underscoring} that inhibits transformation of names
+(by appending one or two underscores) so users may experiment
+with implications of such an environment.
+
+@item
+Minor improvement to @file{gcc/f/info} module to make it easier to build
+@code{g77} using the native (non-@code{gcc}) compiler on certain machines
+(but definitely not all machines nor all non-@code{gcc} compilers).
+Please
+do not report bugs showing problems compilers have with
+macros defined in @file{gcc/f/target.h} and used in places like
+@file{gcc/f/expr.c}.
+
+@item
+Add warning to be printed for each invocation of the compiler
+if the target machine @code{INTEGER}, @code{REAL}, or @code{LOGICAL} size
+is not 32 bits,
+since @code{g77} is known to not work well for such cases (to be
+fixed in Version 0.6---@pxref{Actual Bugs,,Actual Bugs We Haven't Fixed Yet}).
+
+@item
+Lots of new documentation (though work is still needed to put it into
+canonical GNU format).
+
+@item
+Build @code{libf2c} with @samp{-g0}, not @samp{-g2}, in effect
+(by default), to produce
+smaller library without lots of debugging clutter.
+@end itemize
+
+@c 1995-05-19: 0.5.15 released.
+@heading In 0.5.15:
+@itemize @bullet
+@item
+Fix bad code generation involving @samp{X**I} and temporary, internal variables
+generated by @code{g77} and the back end (such as for @code{DO} loops).
+
+@item
+Fix crash given @samp{CHARACTER A;DATA A/.TRUE./}.
+
+@item
+Replace crash with diagnostic given @samp{CHARACTER A;DATA A/1.0/}.
+
+@item
+Fix crash or other erratic behavior when null character constant
+(@samp{''}) is encountered.
+
+@item
+Fix crash or other erratic behavior involving diagnosed code.
+
+@item
+Fix code generation for external functions returning type @code{REAL} when
+the @samp{-ff2c} option is in force (which it is by default) so that
+@code{f2c} compatibility is indeed provided.
+
+@item
+Disallow @samp{COMMON I(10)} if @samp{I} has previously been specified
+with an array declarator.
+
+@item
+New @samp{-ffixed-line-length-@var{n}} option, where @var{n} is the
+maximum length
+of a typical fixed-form line, defaulting to 72 columns, such
+that characters beyond column @var{n} are ignored, or @var{n} is @samp{none},
+meaning no characters are ignored.
+does not affect lines
+with @samp{&} in column 1, which are always processed as if
+@samp{-ffixed-line-length-none} was in effect.
+
+@item
+No longer generate better code for some kinds of array references,
+as @code{gcc} back end is to be fixed to do this even better, and it
+turned out to slow down some code in some cases after all.
+
+@item
+In @code{COMMON} and @code{EQUIVALENCE} areas with any members given initial
+values (e.g. via @code{DATA}), uninitialized members now always
+initialized to binary zeros (though this is not required by
+the standard, and might not be done in future versions
+of @code{g77}).
+Previously, in some @code{COMMON}/@code{EQUIVALENCE} areas
+(essentially those with members of more than one type), the
+uninitialized members were initialized to spaces, to
+cater to @code{CHARACTER} types, but it seems no existing code expects
+that, while much existing code expects binary zeros.
+@end itemize
+
+@heading In 0.5.14:
+@itemize @bullet
+@item
+Don't emit bad code when low bound of adjustable array is nonconstant
+and thus might vary as an expression at run time.
+
+@item
+Emit correct code for calculation of number of trips in @code{DO} loops
+for cases
+where the loop should not execute at all.
+(This bug affected cases
+where the difference between the begin and end values was less
+than the step count, though probably not for floating-point cases.)
+
+@item
+Fix crash when extra parentheses surround item in
+@code{DATA} implied-@code{DO} list.
+
+@item
+Fix crash over minor internal inconsistencies in handling diagnostics,
+just substitute dummy strings where necessary.
+
+@item
+Fix crash on some systems when compiling call to @code{MVBITS()} intrinsic.
+
+@item
+Fix crash on array assignment @samp{TYPE@var{ddd}(@dots{})=@dots{}}, where @var{ddd}
+is a string of one or more digits.
+
+@item
+Fix crash on @code{DCMPLX()} with a single @code{INTEGER} argument.
+
+@item
+Fix various crashes involving code with diagnosed errors.
+
+@item
+Support @samp{-I} option for @code{INCLUDE} statement, plus @code{gcc}'s
+@file{header.gcc} facility for handling systems like MS-DOS.
+
+@item
+Allow @code{INCLUDE} statement to be continued across multiple lines,
+even allow it to coexist with other statements on the same line.
+
+@item
+Incorporate Bellcore fixes to @code{libf2c} through 1995-03-15---this
+fixes a bug involving infinite loops reading EOF with empty list-directed
+I/O list.
+
+@item
+Remove all the @code{g77}-specific auto-configuration scripts, code,
+and so on,
+except for temporary substitutes for bsearch() and strtoul(), as
+too many configure/build problems were reported in these areas.
+People will have to fix their systems' problems themselves, or at
+least somewhere other than @code{g77}, which expects a working ANSI C
+environment (and, for now, a GNU C compiler to compile @code{g77} itself).
+
+@item
+Complain if initialized common redeclared as larger in subsequent program
+unit.
+
+@item
+Warn if blank common initialized, since its size can vary and hence
+related warnings that might be helpful won't be seen.
+
+@item
+New @samp{-fbackslash} option, on by default, that causes @samp{\}
+within @code{CHARACTER}
+and Hollerith constants to be interpreted a la GNU C.
+Note that
+this behavior is somewhat different from @code{f2c}'s, which supports only
+a limited subset of backslash (escape) sequences.
+
+@item
+Make @samp{-fugly-args} the default.
+
+@item
+New @samp{-fugly-init} option, on by default, that allows typeless/Hollerith
+to be specified as initial values for variables or named constants
+(@code{PARAMETER}), and also allows character<->numeric conversion in
+those contexts---turn off via @samp{-fno-ugly-init}.
+
+@item
+New @samp{-finit-local-zero} option to initialize
+local variables to binary zeros.
+This does not affect whether they are @code{SAVE}d, i.e. made
+automatic or static.
+
+@item
+New @samp{-Wimplicit} option to warn about implicitly typed variables, arrays,
+and functions.
+(Basically causes all program units to default to @code{IMPLICIT NONE}.)
+
+@item
+@samp{-Wall} now implies @samp{-Wuninitialized} as with @code{gcc}
+(i.e. unless @samp{-O} not specified, since @samp{-Wuninitialized}
+requires @samp{-O}), and implies @samp{-Wunused} as well.
+
+@item
+@samp{-Wunused} no longer gives spurious messages for unused
+@code{EXTERNAL} names (since they are assumed to refer to block data
+program units, to make use of libraries more reliable).
+
+@item
+Support @code{%LOC()} and @code{LOC()} of character arguments.
+
+@item
+Support null (zero-length) character constants and expressions.
+
+@item
+Support @code{f2c}'s @code{IMAG()} generic intrinsic.
+
+@item
+Support @code{ICHAR()}, @code{IACHAR()}, and @code{LEN()} of
+character expressions that are valid in assignments but
+not normally as actual arguments.
+
+@item
+Support @code{f2c}-style @samp{&} in column 1 to mean continuation line.
+
+@item
+Allow @code{NAMELIST}, @code{EXTERNAL}, @code{INTRINSIC}, and @code{VOLATILE}
+in @code{BLOCK DATA}, even though these are not allowed by the standard.
+
+@item
+Allow @code{RETURN} in main program unit.
+
+@item
+Changes to Hollerith-constant support to obey Appendix C of the
+standard:
+
+@itemize --
+@item
+Now padded on the right with zeros, not spaces.
+
+@item
+Hollerith ``format specifications'' in the form of arrays of
+non-character allowed.
+
+@item
+Warnings issued when non-space truncation occurs when converting
+to another type.
+
+@item
+When specified as actual argument, now passed
+by reference to @code{INTEGER} (padded on right with spaces if constant
+too small, otherwise fully intact if constant wider the @code{INTEGER}
+type) instead of by value.
+@end itemize
+
+@strong{Warning:} @code{f2c} differs on the
+interpretation of @samp{CALL FOO(1HX)}, which it treats exactly the
+same as @samp{CALL FOO('X')}, but which the standard and @code{g77} treat
+as @samp{CALL FOO(%REF('X '))} (padded with as many spaces as necessary
+to widen to @code{INTEGER}), essentially.
+
+@item
+Changes and fixes to typeless-constant support:
+
+@itemize --
+@item
+Now treated as a typeless double-length @code{INTEGER} value.
+
+@item
+Warnings issued when overflow occurs.
+
+@item
+Padded on the left with zeros when converting
+to a larger type.
+
+@item
+Should be properly aligned and ordered on
+the target machine for whatever type it is turned into.
+
+@item
+When specified as actual argument, now passed as reference to
+a default @code{INTEGER} constant.
+@end itemize
+
+@item
+@code{%DESCR()} of a non-@code{CHARACTER} expression now passes a pointer to
+the expression plus a length for the expression just as if
+it were a @code{CHARACTER} expression.
+For example, @samp{CALL FOO(%DESCR(D))}, where
+@samp{D} is @code{REAL*8}, is the same as @samp{CALL FOO(D,%VAL(8)))}.
+
+@item
+Name of multi-entrypoint master function changed to incorporate
+the name of the primary entry point instead of a decimal
+value, so the name of the master function for @samp{SUBROUTINE X}
+with alternate entry points is now @samp{__g77_masterfun_x}.
+
+@item
+Remove redundant message about zero-step-count @code{DO} loops.
+
+@item
+Clean up diagnostic messages, shortening many of them.
+
+@item
+Fix typo in @code{g77} man page.
+
+@item
+Clarify implications of constant-handling bugs in @file{f/BUGS}.
+
+@item
+Generate better code for @samp{**} operator with a right-hand operand of
+type @code{INTEGER}.
+
+@item
+Generate better code for @code{SQRT()} and @code{DSQRT()},
+also when @samp{-ffast-math}
+specified, enable better code generation for @code{SIN()} and @code{COS()}.
+
+@item
+Generate better code for some kinds of array references.
+
+@item
+Speed up lexing somewhat (this makes the compilation phase noticeably
+faster).
+@end itemize
diff --git a/contrib/gcc/f/news0.texi b/contrib/gcc/f/news0.texi
new file mode 100644
index 0000000..8fb85f4
--- /dev/null
+++ b/contrib/gcc/f/news0.texi
@@ -0,0 +1,14 @@
+@setfilename NEW
+@set NEWSONLY
+
+@c The immediately following lines apply to the NEWS file
+@c which is generated using this file.
+This file lists recent changes to the GNU Fortran compiler.
+Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+You may copy, distribute, and modify it freely as long as you preserve
+this copyright notice and permission notice.
+
+@node Top,,, (dir)
+@chapter News About GNU Fortran
+@include news.texi
+@bye
diff --git a/contrib/gcc/f/output.j b/contrib/gcc/f/output.j
new file mode 100644
index 0000000..f995fcb
--- /dev/null
+++ b/contrib/gcc/f/output.j
@@ -0,0 +1,28 @@
+/* output.j -- Wrapper for GCC's output.h
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_output
+#define _J_f_output
+#include "gansidecl.h"
+#include "output.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/parse.c b/contrib/gcc/f/parse.c
new file mode 100644
index 0000000..6c92de9
--- /dev/null
+++ b/contrib/gcc/f/parse.c
@@ -0,0 +1,95 @@
+/* GNU Fortran
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "proj.h"
+#include "top.h"
+#include "com.h"
+#include "where.h"
+#include "version.h"
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#include "flags.j"
+#endif
+
+#define NAME_OF_STDIN "<stdin>"
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+main (int argc, char *argv[])
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+FILE *finput;
+
+int
+yyparse ()
+#else
+#error
+#endif
+{
+ ffewhereFile wf;
+
+ if (ffe_is_version ())
+ fprintf (stderr, "GNU Fortran Front End version %s\n", ffe_version_string);
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffe_init_0 ();
+
+ {
+ int strings_processed;
+ for (--argc, ++argv; argc > 0; argc -= strings_processed, argv += strings_processed)
+ {
+ strings_processed = ffe_decode_option (argc, argv);
+ if (strings_processed == 0)
+ {
+ fprintf (stderr, "Unrecognized option: %s\n", argv[0]);
+ strings_processed = 1;
+ }
+ }
+ }
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ if (!ffe_is_pedantic ())
+ ffe_set_is_pedantic (pedantic);
+#else
+#error
+#endif
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ wf = ffewhere_file_new (NAME_OF_STDIN, strlen (NAME_OF_STDIN));
+ ffecom_file (NAME_OF_STDIN);
+ ffe_file (wf, stdin);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ wf = ffewhere_file_new (main_input_filename, strlen (main_input_filename));
+ ffecom_file (main_input_filename);
+ ffe_file (wf, finput);
+#else
+#error
+#endif
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffecom_finish_compile ();
+
+ return 0;
+#elif FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffe_terminate_0 ();
+
+ exit (0);
+#else
+#error
+#endif
+}
diff --git a/contrib/gcc/f/proj.c b/contrib/gcc/f/proj.c
new file mode 100644
index 0000000..6af2df5
--- /dev/null
+++ b/contrib/gcc/f/proj.c
@@ -0,0 +1,68 @@
+/* proj.c file for GNU Fortran
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "proj.h"
+#include "glimits.j"
+
+#ifndef HAVE_STRTOUL
+unsigned long int
+strtoul (const char *nptr, char **endptr, int base)
+{
+ unsigned long int number = 0;
+ unsigned long int old_number = 0;
+
+ assert (base == 10);
+ assert (endptr == NULL);
+
+ while (ISDIGIT (*nptr))
+ {
+ number = old_number * 10 + (*(nptr++) - '0');
+ if ((number <= old_number) && (old_number != 0))
+ return ULONG_MAX;
+ old_number = number;
+ }
+
+ return number;
+}
+#endif
+
+#ifndef HAVE_BSEARCH
+void *
+bsearch (const void *key, const void *base, size_t nmemb, size_t size,
+ int (*compar) (const void *, const void *))
+{
+ size_t i;
+ int cmp;
+
+ /* We do a dumb incremental search, not a binary search, for now. */
+
+ for (i = 0; i < nmemb; ++i)
+ {
+ if ((cmp = (*compar) (key, base)) == 0)
+ return base;
+ if (cmp < 0)
+ break;
+ base += size;
+ }
+
+ return NULL;
+}
+#endif
diff --git a/contrib/gcc/f/proj.h b/contrib/gcc/f/proj.h
new file mode 100644
index 0000000..93b12b3
--- /dev/null
+++ b/contrib/gcc/f/proj.h
@@ -0,0 +1,83 @@
+/* proj.h file for Gnu Fortran
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+*/
+
+#ifndef _H_f_proj
+#define _H_f_proj
+
+#ifdef USE_HCONFIG
+#include "hconfig.j"
+#else
+#include "config.j"
+#endif
+#include "system.j"
+
+#if !defined (__GNUC__) || (__GNUC__ < 2)
+#error "You have to use gcc 2.x to build g77 (might be fixed in g77-0.6)."
+#endif
+
+#ifndef BUILT_WITH_270
+#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
+#define BUILT_WITH_270 1
+#else
+#define BUILT_WITH_270 0
+#endif
+#endif /* !defined (BUILT_WITH_270) */
+
+/* Include files everyone gets. <assert.h> is needed for assert().
+ <stddef.h> is needed for offsetof, but technically also NULL,
+ size_t, ptrdiff_t, and so on. */
+
+#include "assert.j"
+
+#if HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+
+/* Generally useful definitions. */
+
+typedef enum
+ {
+#if !defined(false) || !defined(true)
+ false = 0, true = 1,
+#endif
+#if !defined(FALSE) || !defined(TRUE)
+ FALSE = 0, TRUE = 1,
+#endif
+ Doggone_Trailing_Comma_Dont_Work = 1
+ } bool;
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+
+#ifndef UNUSED /* Compile with -DUNUSED= if cc doesn't support this. */
+#if BUILT_WITH_270
+#define UNUSED __attribute__ ((unused))
+#else /* !BUILT_WITH_270 */
+#define UNUSED
+#endif /* !BUILT_WITH_270 */
+#endif /* !defined (UNUSED) */
+
+#ifndef dmpout
+#define dmpout stderr
+#endif
+
+#endif
diff --git a/contrib/gcc/f/rtl.j b/contrib/gcc/f/rtl.j
new file mode 100644
index 0000000..99923f4
--- /dev/null
+++ b/contrib/gcc/f/rtl.j
@@ -0,0 +1,28 @@
+/* rtl.j -- Wrapper for GCC's rtl.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_rtl
+#define _J_f_rtl
+#include "config.j"
+#include "rtl.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/src.c b/contrib/gcc/f/src.c
new file mode 100644
index 0000000..3fd1755
--- /dev/null
+++ b/contrib/gcc/f/src.c
@@ -0,0 +1,445 @@
+/* src.c -- Implementation File
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+
+ Description:
+ Source-file functions to handle various combinations of case sensitivity
+ and insensitivity at run time.
+
+ Modifications:
+*/
+
+#include "proj.h"
+#include "src.h"
+#include "top.h"
+
+/* This array does a toupper (), but any valid char type is valid as an
+ index and returns identity if not a lower-case character. */
+
+char ffesrc_toupper_[256];
+
+/* This array does a tolower (), but any valid char type is valid as an
+ index and returns identity if not an upper-case character. */
+
+char ffesrc_tolower_[256];
+
+/* This array is set up so that, given a source-mapped character, the result
+ of indexing into this array will match an upper-cased character depending
+ on the source-mapped character's case and the established ffe_case_match()
+ setting. So the uppercase cells contain identies (e.g. ['A'] == 'A')
+ as long as uppercase matching is permitted (!FFE_caseLOWER) and the
+ lowercase cells contain uppercased identities (e.g. ['a'] == 'A') as long
+ as lowercase matching is permitted (!FFE_caseUPPER). Else the case
+ cells contain -1. _init_ is for the first character of a keyword,
+ and _noninit_ is for other characters. */
+
+char ffesrc_char_match_init_[256];
+char ffesrc_char_match_noninit_[256];
+
+/* This array is used to map input source according to the established
+ ffe_case_source() setting: for FFE_caseNONE, the array is all
+ identities; for FFE_caseUPPER, the lowercase cells contain
+ uppercased identities; and vice versa for FFE_caseLOWER. */
+
+char ffesrc_char_source_[256];
+
+/* This array is used to map an internally generated character so that it
+ will be accepted as an initial character in a keyword. The assumption
+ is that the incoming character is uppercase. */
+
+char ffesrc_char_internal_init_[256];
+
+/* This array is used to determine if a particular character is valid in
+ a symbol name according to the established ffe_case_symbol() setting:
+ for FFE_caseNONE, the array is all FFEBAD; for FFE_caseUPPER, the
+ lowercase cells contain a non-FFEBAD error code (FFEBAD_SYMBOL_UPPER_CASE);
+ and vice versa for FFE_caseLOWER. _init_ and _noninit_ distinguish
+ between initial and subsequent characters for the caseINITCAP case,
+ and their error codes are different for appropriate messages --
+ specifically, _noninit_ contains a non-FFEBAD error code for all
+ except lowercase characters for the caseINITCAP case.
+
+ See ffesrc_check_symbol_, it must be TRUE if this array is not all
+ FFEBAD. */
+
+ffebad ffesrc_bad_symbol_init_[256];
+ffebad ffesrc_bad_symbol_noninit_[256];
+
+/* Set TRUE if any element in ffesrc_bad_symbol (with an index representing
+ a character that can also be in the text of a token passed to
+ ffename_find, strictly speaking) is not FFEBAD. I.e., TRUE if it is
+ necessary to check token characters against the ffesrc_bad_symbol_
+ array. */
+
+bool ffesrc_check_symbol_;
+
+/* These are set TRUE if the kind of character (upper/lower) is ok as a match
+ in the context (initial/noninitial character of keyword). */
+
+bool ffesrc_ok_match_init_upper_;
+bool ffesrc_ok_match_init_lower_;
+bool ffesrc_ok_match_noninit_upper_;
+bool ffesrc_ok_match_noninit_lower_;
+
+/* Initialize table of alphabetic matches. */
+
+void
+ffesrc_init_1 ()
+{
+ int i;
+
+ for (i = 0; i < 256; ++i)
+ {
+ ffesrc_char_match_init_[i] = i;
+ ffesrc_char_match_noninit_[i] = i;
+ ffesrc_char_source_[i] = i;
+ ffesrc_char_internal_init_[i] = i;
+ ffesrc_toupper_[i] = i;
+ ffesrc_tolower_[i] = i;
+ ffesrc_bad_symbol_init_[i] = FFEBAD;
+ ffesrc_bad_symbol_noninit_[i] = FFEBAD;
+ }
+
+ for (i = 'A'; i <= 'Z'; ++i)
+ ffesrc_tolower_[i] = tolower (i);
+
+ for (i = 'a'; i <= 'z'; ++i)
+ ffesrc_toupper_[i] = toupper (i);
+
+ ffesrc_check_symbol_ = (ffe_case_symbol () != FFE_caseNONE);
+
+ ffesrc_ok_match_init_upper_ = (ffe_case_match () != FFE_caseLOWER);
+ ffesrc_ok_match_init_lower_ = (ffe_case_match () != FFE_caseUPPER)
+ && (ffe_case_match () != FFE_caseINITCAP);
+ ffesrc_ok_match_noninit_upper_ = (ffe_case_match () != FFE_caseLOWER)
+ && (ffe_case_match () != FFE_caseINITCAP);
+ ffesrc_ok_match_noninit_lower_ = (ffe_case_match () != FFE_caseUPPER);
+
+ /* Note that '-' is used to flag an invalid match character. '-' is
+ somewhat arbitrary, actually. -1 was used, but that's not wise on a
+ system with unsigned chars as default -- it'd turn into 255 or some such
+ large positive number, which would sort higher than the alphabetics and
+ thus possibly cause problems. So '-' is picked just because it's never
+ likely to be a symbol character in Fortran and because it's "less than"
+ any alphabetic character. EBCDIC might see things differently, I don't
+ remember it well enough, but that's just tough -- lots of other things
+ might have to change to support EBCDIC -- anyway, some other character
+ could easily be picked. */
+
+#define FFESRC_INVALID_SYMBOL_CHAR_ '-'
+
+ if (!ffesrc_ok_match_init_upper_)
+ for (i = 'A'; i <= 'Z'; ++i)
+ ffesrc_char_match_init_[i] = FFESRC_INVALID_SYMBOL_CHAR_;
+
+ if (ffesrc_ok_match_init_lower_)
+ for (i = 'a'; i <= 'z'; ++i)
+ ffesrc_char_match_init_[i] = toupper (i);
+ else
+ for (i = 'a'; i <= 'z'; ++i)
+ ffesrc_char_match_init_[i] = FFESRC_INVALID_SYMBOL_CHAR_;
+
+ if (!ffesrc_ok_match_noninit_upper_)
+ for (i = 'A'; i <= 'Z'; ++i)
+ ffesrc_char_match_noninit_[i] = FFESRC_INVALID_SYMBOL_CHAR_;
+
+ if (ffesrc_ok_match_noninit_lower_)
+ for (i = 'a'; i <= 'z'; ++i)
+ ffesrc_char_match_noninit_[i] = toupper (i);
+ else
+ for (i = 'a'; i <= 'z'; ++i)
+ ffesrc_char_match_noninit_[i] = FFESRC_INVALID_SYMBOL_CHAR_;
+
+ if (ffe_case_source () == FFE_caseLOWER)
+ for (i = 'A'; i <= 'Z'; ++i)
+ ffesrc_char_source_[i] = tolower (i);
+ else if (ffe_case_source () == FFE_caseUPPER)
+ for (i = 'a'; i <= 'z'; ++i)
+ ffesrc_char_source_[i] = toupper (i);
+
+ if (ffe_case_match () == FFE_caseLOWER)
+ for (i = 'A'; i <= 'Z'; ++i)
+ ffesrc_char_internal_init_[i] = tolower (i);
+
+ switch (ffe_case_symbol ())
+ {
+ case FFE_caseLOWER:
+ for (i = 'A'; i <= 'Z'; ++i)
+ {
+ ffesrc_bad_symbol_init_[i] = FFEBAD_SYMBOL_UPPER_CASE;
+ ffesrc_bad_symbol_noninit_[i] = FFEBAD_SYMBOL_UPPER_CASE;
+ }
+ break;
+
+ case FFE_caseUPPER:
+ for (i = 'a'; i <= 'z'; ++i)
+ {
+ ffesrc_bad_symbol_init_[i] = FFEBAD_SYMBOL_LOWER_CASE;
+ ffesrc_bad_symbol_noninit_[i] = FFEBAD_SYMBOL_LOWER_CASE;
+ }
+ break;
+
+ case FFE_caseINITCAP:
+ for (i = 0; i < 256; ++i)
+ ffesrc_bad_symbol_noninit_[i] = FFEBAD_SYMBOL_NOLOWER_INITCAP;
+ for (i = 'a'; i <= 'z'; ++i)
+ {
+ ffesrc_bad_symbol_init_[i] = FFEBAD_SYMBOL_LOWER_INITCAP;
+ ffesrc_bad_symbol_noninit_[i] = FFEBAD;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Compare two strings a la strcmp, the first being a source string with its
+ length passed, and the second being a constant string passed
+ in InitialCaps form. Also, the return value is always -1, 0, or 1. */
+
+int
+ffesrc_strcmp_1ns2i (ffeCase mcase, const char *var, int len,
+ const char *str_ic)
+{
+ char c;
+ char d;
+
+ switch (mcase)
+ {
+ case FFE_caseNONE:
+ for (; len > 0; --len, ++var, ++str_ic)
+ {
+ c = ffesrc_char_source (*var); /* Transform source. */
+ c = ffesrc_toupper (c); /* Upcase source. */
+ d = ffesrc_toupper (*str_ic); /* Upcase InitialCaps char. */
+ if (c != d)
+ {
+ if ((d != '\0') && (c < d))
+ return -1;
+ else
+ return 1;
+ }
+ }
+ break;
+
+ case FFE_caseUPPER:
+ for (; len > 0; --len, ++var, ++str_ic)
+ {
+ c = ffesrc_char_source (*var); /* Transform source. */
+ d = ffesrc_toupper (*str_ic); /* Transform InitialCaps char. */
+ if (c != d)
+ {
+ if ((d != '\0') && (c < d))
+ return -1;
+ else
+ return 1;
+ }
+ }
+ break;
+
+ case FFE_caseLOWER:
+ for (; len > 0; --len, ++var, ++str_ic)
+ {
+ c = ffesrc_char_source (*var); /* Transform source. */
+ d = ffesrc_tolower (*str_ic); /* Transform InitialCaps char. */
+ if (c != d)
+ {
+ if ((d != '\0') && (c < d))
+ return -1;
+ else
+ return 1;
+ }
+ }
+ break;
+
+ case FFE_caseINITCAP:
+ for (; len > 0; --len, ++var, ++str_ic)
+ {
+ c = ffesrc_char_source (*var); /* Transform source. */
+ d = *str_ic; /* No transform of InitialCaps char. */
+ if (c != d)
+ {
+ c = ffesrc_toupper (c);
+ d = ffesrc_toupper (d);
+ while ((len > 0) && (c == d))
+ { /* Skip past equivalent (case-ins) chars. */
+ --len, ++var, ++str_ic;
+ if (len > 0)
+ c = ffesrc_toupper (*var);
+ d = ffesrc_toupper (*str_ic);
+ }
+ if ((d != '\0') && (c < d))
+ return -1;
+ else
+ return 1;
+ }
+ }
+ break;
+
+ default:
+ assert ("bad case value" == NULL);
+ return -1;
+ }
+
+ if (*str_ic == '\0')
+ return 0;
+ return -1;
+}
+
+/* Compare two strings a la strcmp, the second being a constant string passed
+ in both uppercase and lowercase form. If not equal, the uppercase string
+ is used to determine the sign of the return value. Also, the return
+ value is always -1, 0, or 1. */
+
+int
+ffesrc_strcmp_2c (ffeCase mcase, const char *var, const char *str_uc,
+ const char *str_lc, const char *str_ic)
+{
+ int i;
+ char c;
+
+ switch (mcase)
+ {
+ case FFE_caseNONE:
+ for (; *var != '\0'; ++var, ++str_uc)
+ {
+ c = ffesrc_toupper (*var); /* Upcase source. */
+ if (c != *str_uc)
+ {
+ if ((*str_uc != '\0') && (c < *str_uc))
+ return -1;
+ else
+ return 1;
+ }
+ }
+ if (*str_uc == '\0')
+ return 0;
+ return -1;
+
+ case FFE_caseUPPER:
+ i = strcmp (var, str_uc);
+ break;
+
+ case FFE_caseLOWER:
+ i = strcmp (var, str_lc);
+ break;
+
+ case FFE_caseINITCAP:
+ for (; *var != '\0'; ++var, ++str_ic, ++str_uc)
+ {
+ if (*var != *str_ic)
+ {
+ c = ffesrc_toupper (*var);
+ while ((c != '\0') && (c == *str_uc))
+ { /* Skip past equivalent (case-ins) chars. */
+ ++var, ++str_uc;
+ c = ffesrc_toupper (*var);
+ }
+ if ((*str_uc != '\0') && (c < *str_uc))
+ return -1;
+ else
+ return 1;
+ }
+ }
+ if (*str_ic == '\0')
+ return 0;
+ return -1;
+
+ default:
+ assert ("bad case value" == NULL);
+ return -1;
+ }
+
+ if (i == 0)
+ return 0;
+ else if (i < 0)
+ return -1;
+ return 1;
+}
+
+/* Compare two strings a la strncmp, the second being a constant string passed
+ in uppercase, lowercase, and InitialCaps form. If not equal, the
+ uppercase string is used to determine the sign of the return value. */
+
+int
+ffesrc_strncmp_2c (ffeCase mcase, const char *var, const char *str_uc,
+ const char *str_lc, const char *str_ic, int len)
+{
+ int i;
+ char c;
+
+ switch (mcase)
+ {
+ case FFE_caseNONE:
+ for (; len > 0; ++var, ++str_uc, --len)
+ {
+ c = ffesrc_toupper (*var); /* Upcase source. */
+ if (c != *str_uc)
+ {
+ if (c < *str_uc)
+ return -1;
+ else
+ return 1;
+ }
+ }
+ return 0;
+
+ case FFE_caseUPPER:
+ i = strncmp (var, str_uc, len);
+ break;
+
+ case FFE_caseLOWER:
+ i = strncmp (var, str_lc, len);
+ break;
+
+ case FFE_caseINITCAP:
+ for (; len > 0; ++var, ++str_ic, ++str_uc, --len)
+ {
+ if (*var != *str_ic)
+ {
+ c = ffesrc_toupper (*var);
+ while ((len > 0) && (c == *str_uc))
+ { /* Skip past equivalent (case-ins) chars. */
+ --len, ++var, ++str_uc;
+ if (len > 0)
+ c = ffesrc_toupper (*var);
+ }
+ if ((len > 0) && (c < *str_uc))
+ return -1;
+ else
+ return 1;
+ }
+ }
+ return 0;
+
+ default:
+ assert ("bad case value" == NULL);
+ return -1;
+ }
+
+ if (i == 0)
+ return 0;
+ else if (i < 0)
+ return -1;
+ return 1;
+}
diff --git a/contrib/gcc/f/src.h b/contrib/gcc/f/src.h
new file mode 100644
index 0000000..0216a7c
--- /dev/null
+++ b/contrib/gcc/f/src.h
@@ -0,0 +1,144 @@
+/* src.h -- Public #include File
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ src.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_src
+#define _H_f_src
+
+#include "bad.h"
+#include "top.h"
+
+extern char ffesrc_toupper_[256];
+extern char ffesrc_tolower_[256];
+extern char ffesrc_char_match_init_[256];
+extern char ffesrc_char_match_noninit_[256];
+extern char ffesrc_char_source_[256];
+extern char ffesrc_char_internal_init_[256];
+extern ffebad ffesrc_bad_symbol_init_[256];
+extern ffebad ffesrc_bad_symbol_noninit_[256];
+extern bool ffesrc_check_symbol_;
+extern bool ffesrc_ok_match_init_upper_;
+extern bool ffesrc_ok_match_init_lower_;
+extern bool ffesrc_ok_match_noninit_upper_;
+extern bool ffesrc_ok_match_noninit_lower_;
+
+/* These C-language-syntax modifiers could avoid the match arg if gcc's
+ extension allowing macros to generate dynamic labels was used. They
+ could use the no_match arg (and the "caller's" label defs) if there
+ was a way to say "goto default" in a switch statement. Oh well.
+
+ NOTE: These macro assume "case FFESRC_CASE_MATCH_[NON]INIT(...):" is used
+ to invoke them, and thus assume the "above" case does not fall through to
+ this one. This syntax was chosen to keep indenting tools working. */
+
+#define FFESRC_CASE_MATCH_INIT(upper, lower, match, no_match) \
+ upper: if (!ffesrc_ok_match_init_upper_) goto no_match; \
+ else goto match; \
+ case lower: if (!ffesrc_ok_match_init_lower_) goto no_match; \
+ match
+
+#define FFESRC_CASE_MATCH_NONINIT(upper, lower, match, no_match) \
+ upper: if (!ffesrc_ok_match_noninit_upper_) goto no_match; \
+ else goto match; \
+ case lower: if (!ffesrc_ok_match_noninit_lower_) goto no_match; \
+ match
+
+/* If character is ok in a symbol name (not including intrinsic names),
+ returns FFEBAD, else returns something else, type ffebad. */
+
+#define ffesrc_bad_char_symbol_init(c) \
+ (ffesrc_bad_symbol_init_[(unsigned int) (c)])
+#define ffesrc_bad_char_symbol_noninit(c) \
+ (ffesrc_bad_symbol_noninit_[(unsigned int) (c)])
+
+/* Returns TRUE if character is ok in a symbol name (including
+ intrinsic names). Doesn't care about case settings, this is
+ used just for parsing (before semantic complaints about symbol-
+ name casing and such). One specific usage is to decide whether
+ an underscore is valid as the first or subsequent character in
+ some symbol name -- if not, an underscore is a separate token
+ (while lexing, for example). Note that ffesrc_is_name_init
+ must return TRUE for a (not necessarily proper) subset of
+ characters for which ffelex_is_firstnamechar returns TRUE. */
+
+#define ffesrc_is_name_init(c) \
+ ((ISALPHA ((c))) || (! (1 || ffe_is_90 ()) && ((c) == '_')))
+#define ffesrc_is_name_noninit(c) \
+ ((ISALNUM ((c))) || (! (1 || ffe_is_90 ()) && ((c) == '_')))
+
+/* Test if source-translated character matches given alphabetic character
+ (passed in both uppercase and lowercase, to allow for custom speedup
+ of compilation in environments where compile-time options aren't needed
+ for casing). */
+
+#define ffesrc_char_match_init(c, up, low) \
+ (ffesrc_char_match_init_[(unsigned int) (c)] == up)
+
+#define ffesrc_char_match_noninit(c, up, low) \
+ (ffesrc_char_match_noninit_[(unsigned int) (c)] == up)
+
+/* Translate character from input-file form to source form. */
+
+#define ffesrc_char_source(c) (ffesrc_char_source_[(unsigned int) (c)])
+
+/* Translate internal character (upper/lower) to source form in an
+ initial-character context (i.e. ffesrc_char_match_init of the result
+ will always succeed). */
+
+#define ffesrc_char_internal_init(up, low) \
+ (ffesrc_char_internal_init_[(unsigned int) (up)])
+
+/* Returns TRUE if a name representing a symbol should be checked for
+ validity according to compile-time options. That is, if it is possible
+ that ffesrc_bad_char_symbol(c) can return something other than FFEBAD
+ for any valid character in an ffelex NAME(S) token. */
+
+#define ffesrc_check_symbol() ffesrc_check_symbol_
+
+#define ffesrc_init_0()
+void ffesrc_init_1 (void);
+#define ffesrc_init_2()
+#define ffesrc_init_3()
+#define ffesrc_init_4()
+int ffesrc_strcmp_1ns2i (ffeCase mcase, const char *var, int len,
+ const char *str_ic);
+int ffesrc_strcmp_2c (ffeCase mcase, const char *var, const char *str_uc,
+ const char *str_lc, const char *str_ic);
+int ffesrc_strncmp_2c (ffeCase mcase, const char *var, const char *str_uc,
+ const char *str_lc, const char *str_ic, int len);
+#define ffesrc_terminate_0()
+#define ffesrc_terminate_1()
+#define ffesrc_terminate_2()
+#define ffesrc_terminate_3()
+#define ffesrc_terminate_4()
+#define ffesrc_toupper(c) (ffesrc_toupper_[(unsigned int) (c)])
+#define ffesrc_tolower(c) (ffesrc_tolower_[(unsigned int) (c)])
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/st.c b/contrib/gcc/f/st.c
new file mode 100644
index 0000000..2abd099
--- /dev/null
+++ b/contrib/gcc/f/st.c
@@ -0,0 +1,554 @@
+/* st.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ The high-level input level to statement handling for the rest of the
+ FFE. ffest_first is the first state for the lexer to invoke to start
+ a statement. A statement normally starts with a NUMBER token (to indicate
+ a label def) followed by a NAME token (to indicate what kind of statement
+ it is), though of course the NUMBER token may be omitted. ffest_first
+ gathers the first NAME token and returns a state of ffest_second_,
+ where the trailing underscore means "internal to ffest" and thus outside
+ users should not depend on this. ffest_second_ then looks at the second
+ token in conjunction with the first, decides what possible statements are
+ meant, and tries each possible statement in turn, from most likely to
+ least likely. A successful attempt currently is recorded, and further
+ successful attempts by other possibilities raise an assertion error in
+ ffest_confirmed (this is to detect ambiguities). A failure in an
+ attempt is signaled by calling ffest_ffebad_start; this results in the
+ next token sent by ffest_save_ (the intermediary when more than one
+ possible statement exists) being EOS to shut down processing and the next
+ possibility tried.
+
+ When all possibilities have been tried, the successful one is retried with
+ inhibition turned off (FALSE) as reported by ffest_is_inhibited(). If
+ there is no successful one, the first one is retried so the user gets to
+ see the error messages.
+
+ In the future, after syntactic bugs have been reasonably shaken out and
+ ambiguities thus detected, the first successful possibility will be
+ enabled (inhibited goes FALSE) as soon as it confirms success by calling
+ ffest_confirmed, thus retrying the possibility will not be necessary.
+
+ The only complication in all this is that expression handling is
+ happening while possibilities are inhibited. It is up to the expression
+ handler, conceptually, to not make any changes to its knowledge base for
+ variable names and so on when inhibited that cannot be undone if
+ the current possibility fails (shuts down via ffest_ffebad_start). In
+ fact, this business is handled not be ffeexpr, but by lower levels.
+
+ ffesta functions serve only to provide information used in syntactic
+ processing of possible statements, and thus may not make changes to the
+ knowledge base for variables and such.
+
+ ffestb functions perform the syntactic analysis for possible statements,
+ and thus again may not make changes to the knowledge base except under the
+ auspices of ffeexpr and its subordinates, changes which can be undone when
+ necessary.
+
+ ffestc functions perform the semantic analysis for the chosen statement,
+ and thus may change the knowledge base as necessary since they are invoked
+ by ffestb functions only after a given statement is confirmed and
+ enabled. Note, however, that a few ffestc functions (identified by
+ their statement names rather than grammar numbers) indicate valid forms
+ that are, outside of any context, ambiguous, such as ELSE WHERE and
+ PRIVATE; these functions should make a quick decision as to what is
+ intended and dispatch to the appropriate specific ffestc function.
+
+ ffestd functions actually implement statements. When called, the
+ statement is considered valid and is either an executable statement or
+ a nonexecutable statement with direct-output results. For example, CALL,
+ GOTO, and assignment statements pass through ffestd because they are
+ executable; DATA statements pass through because they map directly to the
+ output file (or at least might so map); ENTRY statements also pass through
+ because they essentially affect code generation in an immediate way;
+ whereas INTEGER, SAVE, and SUBROUTINE statements do not go through
+ ffestd functions because they merely update the knowledge base.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "st.h"
+#include "bad.h"
+#include "lex.h"
+#include "sta.h"
+#include "stb.h"
+#include "stc.h"
+#include "std.h"
+#include "ste.h"
+#include "stp.h"
+#include "str.h"
+#include "sts.h"
+#include "stt.h"
+#include "stu.h"
+#include "stv.h"
+#include "stw.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+
+/* ffest_confirmed -- Confirm current possibility as only one
+
+ ffest_confirmed();
+
+ Sets the confirmation flag. During debugging for ambiguous constructs,
+ asserts that the confirmation flag for a previous possibility has not
+ yet been set. */
+
+void
+ffest_confirmed ()
+{
+ ffesta_confirmed ();
+}
+
+/* ffest_eof -- End of (non-INCLUDEd) source file
+
+ ffest_eof();
+
+ Call after piping tokens through ffest_first, where the most recent
+ token sent through must be EOS.
+
+ 20-Feb-91 JCB 1.1
+ Put new EOF token in ffesta_tokens[0], not NULL, because too much
+ code expects something there for error reporting and the like. Also,
+ do basically the same things ffest_second and ffesta_zero do for
+ processing a statement (make and destroy pools, et cetera). */
+
+void
+ffest_eof ()
+{
+ ffesta_eof ();
+}
+
+/* ffest_ffebad_here_current_stmt -- ffebad_here with ptr to current stmt
+
+ ffest_ffebad_here_current_stmt(0);
+
+ Outsiders can call this fn if they have no more convenient place to
+ point to (via a token or pair of ffewhere objects) and they know a
+ current, useful statement is being evaluted by ffest (i.e. they are
+ being called from ffestb, ffestc, ffestd, ... functions). */
+
+void
+ffest_ffebad_here_current_stmt (ffebadIndex i)
+{
+ ffesta_ffebad_here_current_stmt (i);
+}
+
+/* ffest_ffebad_here_doiter -- Calls ffebad_here with ptr to DO iter var
+
+ ffesymbol s;
+ // call ffebad_start first, of course.
+ ffest_ffebad_here_doiter(0,s);
+ // call ffebad_finish afterwards, naturally.
+
+ Searches the stack of blocks backwards for a DO loop that has s
+ as its iteration variable, then calls ffebad_here with pointers to
+ that particular reference to the variable. Crashes if the DO loop
+ can't be found. */
+
+void
+ffest_ffebad_here_doiter (ffebadIndex i, ffesymbol s)
+{
+ ffestc_ffebad_here_doiter (i, s);
+}
+
+/* ffest_ffebad_start -- Start a possibly inhibited error report
+
+ if (ffest_ffebad_start(FFEBAD_SOME_ERROR))
+ {
+ ffebad_here, ffebad_string ...;
+ ffebad_finish();
+ }
+
+ Call if the error might indicate that ffest is evaluating the wrong
+ statement form, instead of calling ffebad_start directly. If ffest
+ is choosing between forms, it will return FALSE, send an EOS/SEMICOLON
+ token through as the next token (if the current one isn't already one
+ of those), and try another possible form. Otherwise, ffebad_start is
+ called with the argument and TRUE returned. */
+
+bool
+ffest_ffebad_start (ffebad errnum)
+{
+ return ffesta_ffebad_start (errnum);
+}
+
+/* ffest_first -- Parse the first token in a statement
+
+ return ffest_first; // to lexer. */
+
+ffelexHandler
+ffest_first (ffelexToken t)
+{
+ return ffesta_first (t);
+}
+
+/* ffest_init_0 -- Initialize for entire image invocation
+
+ ffest_init_0();
+
+ Call just once per invocation of the compiler (not once per invocation
+ of the front end).
+
+ Gets memory for the list of possibles once and for all, since this
+ list never gets larger than a certain size (FFEST_maxPOSSIBLES_)
+ and is not particularly large. Initializes the array of pointers to
+ this list. Initializes the executable and nonexecutable lists. */
+
+void
+ffest_init_0 ()
+{
+ ffesta_init_0 ();
+ ffestb_init_0 ();
+ ffestc_init_0 ();
+ ffestd_init_0 ();
+ ffeste_init_0 ();
+ ffestp_init_0 ();
+ ffestr_init_0 ();
+ ffests_init_0 ();
+ ffestt_init_0 ();
+ ffestu_init_0 ();
+ ffestv_init_0 ();
+ ffestw_init_0 ();
+}
+
+/* ffest_init_1 -- Initialize for entire image invocation
+
+ ffest_init_1();
+
+ Call just once per invocation of the compiler (not once per invocation
+ of the front end).
+
+ Gets memory for the list of possibles once and for all, since this
+ list never gets larger than a certain size (FFEST_maxPOSSIBLES_)
+ and is not particularly large. Initializes the array of pointers to
+ this list. Initializes the executable and nonexecutable lists. */
+
+void
+ffest_init_1 ()
+{
+ ffesta_init_1 ();
+ ffestb_init_1 ();
+ ffestc_init_1 ();
+ ffestd_init_1 ();
+ ffeste_init_1 ();
+ ffestp_init_1 ();
+ ffestr_init_1 ();
+ ffests_init_1 ();
+ ffestt_init_1 ();
+ ffestu_init_1 ();
+ ffestv_init_1 ();
+ ffestw_init_1 ();
+}
+
+/* ffest_init_2 -- Initialize for entire image invocation
+
+ ffest_init_2();
+
+ Call just once per invocation of the compiler (not once per invocation
+ of the front end).
+
+ Gets memory for the list of possibles once and for all, since this
+ list never gets larger than a certain size (FFEST_maxPOSSIBLES_)
+ and is not particularly large. Initializes the array of pointers to
+ this list. Initializes the executable and nonexecutable lists. */
+
+void
+ffest_init_2 ()
+{
+ ffesta_init_2 ();
+ ffestb_init_2 ();
+ ffestc_init_2 ();
+ ffestd_init_2 ();
+ ffeste_init_2 ();
+ ffestp_init_2 ();
+ ffestr_init_2 ();
+ ffests_init_2 ();
+ ffestt_init_2 ();
+ ffestu_init_2 ();
+ ffestv_init_2 ();
+ ffestw_init_2 ();
+}
+
+/* ffest_init_3 -- Initialize for any program unit
+
+ ffest_init_3(); */
+
+void
+ffest_init_3 ()
+{
+ ffesta_init_3 ();
+ ffestb_init_3 ();
+ ffestc_init_3 ();
+ ffestd_init_3 ();
+ ffeste_init_3 ();
+ ffestp_init_3 ();
+ ffestr_init_3 ();
+ ffests_init_3 ();
+ ffestt_init_3 ();
+ ffestu_init_3 ();
+ ffestv_init_3 ();
+ ffestw_init_3 ();
+
+ ffestw_display_state ();
+}
+
+/* ffest_init_4 -- Initialize for statement functions
+
+ ffest_init_4(); */
+
+void
+ffest_init_4 ()
+{
+ ffesta_init_4 ();
+ ffestb_init_4 ();
+ ffestc_init_4 ();
+ ffestd_init_4 ();
+ ffeste_init_4 ();
+ ffestp_init_4 ();
+ ffestr_init_4 ();
+ ffests_init_4 ();
+ ffestt_init_4 ();
+ ffestu_init_4 ();
+ ffestv_init_4 ();
+ ffestw_init_4 ();
+}
+
+/* Test whether ENTRY statement is valid.
+
+ Returns TRUE if current program unit is known to be FUNCTION or SUBROUTINE.
+ Else returns FALSE. */
+
+bool
+ffest_is_entry_valid ()
+{
+ return ffesta_is_entry_valid;
+}
+
+/* ffest_is_inhibited -- Test whether the current possibility is inhibited
+
+ if (!ffest_is_inhibited())
+ // implement the statement.
+
+ Just make sure the current possibility has been confirmed. If anyone
+ really needs to test whether the current possibility is inhibited prior
+ to confirming it, that indicates a need to begin statement processing
+ before it is certain that the given possibility is indeed the statement
+ to be processed. As of this writing, there does not appear to be such
+ a need. If there is, then when confirming a statement would normally
+ immediately disable the inhibition (whereas currently we leave the
+ confirmed statement disabled until we've tried the other possibilities,
+ to check for ambiguities), we must check to see if the possibility has
+ already tested for inhibition prior to confirmation and, if so, maintain
+ inhibition until the end of the statement (which may be forced right
+ away) and then rerun the entire statement from the beginning. Otherwise,
+ initial calls to ffestb functions won't have been made, but subsequent
+ calls (after confirmation) will, which is wrong. Of course, this all
+ applies only to those statements implemented via multiple calls to
+ ffestb, although if a statement requiring only a single ffestb call
+ tested for inhibition prior to confirmation, it would likely mean that
+ the ffestb call would be completely dropped without this mechanism. */
+
+bool
+ffest_is_inhibited ()
+{
+ return ffesta_is_inhibited ();
+}
+
+/* ffest_seen_first_exec -- Test whether first executable stmt has been seen
+
+ if (ffest_seen_first_exec())
+ // No more spec stmts can be seen.
+
+ In a case where, say, the first statement is PARAMETER(A)=B, FALSE
+ will be returned while the PARAMETER statement is being run, and TRUE
+ will be returned if it doesn't confirm and the assignment statement
+ is being run. */
+
+bool
+ffest_seen_first_exec ()
+{
+ return ffesta_seen_first_exec;
+}
+
+/* Shut down current parsing possibility, but without bothering the
+ user with a diagnostic if we're not inhibited. */
+
+void
+ffest_shutdown ()
+{
+ ffesta_shutdown ();
+}
+
+/* ffest_sym_end_transition -- Update symbol info just before end of unit
+
+ ffesymbol s;
+ ffest_sym_end_transition(s); */
+
+ffesymbol
+ffest_sym_end_transition (ffesymbol s)
+{
+ return ffestu_sym_end_transition (s);
+}
+
+/* ffest_sym_exec_transition -- Update symbol just before first exec stmt
+
+ ffesymbol s;
+ ffest_sym_exec_transition(s); */
+
+ffesymbol
+ffest_sym_exec_transition (ffesymbol s)
+{
+ return ffestu_sym_exec_transition (s);
+}
+
+/* ffest_terminate_0 -- Terminate for entire image invocation
+
+ ffest_terminate_0(); */
+
+void
+ffest_terminate_0 ()
+{
+ ffesta_terminate_0 ();
+ ffestb_terminate_0 ();
+ ffestc_terminate_0 ();
+ ffestd_terminate_0 ();
+ ffeste_terminate_0 ();
+ ffestp_terminate_0 ();
+ ffestr_terminate_0 ();
+ ffests_terminate_0 ();
+ ffestt_terminate_0 ();
+ ffestu_terminate_0 ();
+ ffestv_terminate_0 ();
+ ffestw_terminate_0 ();
+}
+
+/* ffest_terminate_1 -- Terminate for source file
+
+ ffest_terminate_1(); */
+
+void
+ffest_terminate_1 ()
+{
+ ffesta_terminate_1 ();
+ ffestb_terminate_1 ();
+ ffestc_terminate_1 ();
+ ffestd_terminate_1 ();
+ ffeste_terminate_1 ();
+ ffestp_terminate_1 ();
+ ffestr_terminate_1 ();
+ ffests_terminate_1 ();
+ ffestt_terminate_1 ();
+ ffestu_terminate_1 ();
+ ffestv_terminate_1 ();
+ ffestw_terminate_1 ();
+}
+
+/* ffest_terminate_2 -- Terminate for outer program unit
+
+ ffest_terminate_2(); */
+
+void
+ffest_terminate_2 ()
+{
+ ffesta_terminate_2 ();
+ ffestb_terminate_2 ();
+ ffestc_terminate_2 ();
+ ffestd_terminate_2 ();
+ ffeste_terminate_2 ();
+ ffestp_terminate_2 ();
+ ffestr_terminate_2 ();
+ ffests_terminate_2 ();
+ ffestt_terminate_2 ();
+ ffestu_terminate_2 ();
+ ffestv_terminate_2 ();
+ ffestw_terminate_2 ();
+}
+
+/* ffest_terminate_3 -- Terminate for any program unit
+
+ ffest_terminate_3(); */
+
+void
+ffest_terminate_3 ()
+{
+ ffesta_terminate_3 ();
+ ffestb_terminate_3 ();
+ ffestc_terminate_3 ();
+ ffestd_terminate_3 ();
+ ffeste_terminate_3 ();
+ ffestp_terminate_3 ();
+ ffestr_terminate_3 ();
+ ffests_terminate_3 ();
+ ffestt_terminate_3 ();
+ ffestu_terminate_3 ();
+ ffestv_terminate_3 ();
+ ffestw_terminate_3 ();
+}
+
+/* ffest_terminate_4 -- Terminate for statement functions
+
+ ffest_terminate_4(); */
+
+void
+ffest_terminate_4 ()
+{
+ ffesta_terminate_4 ();
+ ffestb_terminate_4 ();
+ ffestc_terminate_4 ();
+ ffestd_terminate_4 ();
+ ffeste_terminate_4 ();
+ ffestp_terminate_4 ();
+ ffestr_terminate_4 ();
+ ffests_terminate_4 ();
+ ffestt_terminate_4 ();
+ ffestu_terminate_4 ();
+ ffestv_terminate_4 ();
+ ffestw_terminate_4 ();
+}
diff --git a/contrib/gcc/f/st.h b/contrib/gcc/f/st.h
new file mode 100644
index 0000000..5036b27
--- /dev/null
+++ b/contrib/gcc/f/st.h
@@ -0,0 +1,81 @@
+/* st.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ st.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_st
+#define _H_f_st
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "bad.h"
+#include "lex.h"
+#include "symbol.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+void ffest_confirmed (void);
+void ffest_eof (void);
+bool ffest_ffebad_start (ffebad errnum);
+void ffest_ffebad_here_current_stmt (ffebadIndex i);
+void ffest_ffebad_here_doiter (ffebadIndex i, ffesymbol s);
+ffelexHandler ffest_first (ffelexToken t);
+void ffest_init_0 (void);
+void ffest_init_1 (void);
+void ffest_init_2 (void);
+void ffest_init_3 (void);
+void ffest_init_4 (void);
+bool ffest_is_entry_valid (void);
+bool ffest_is_inhibited (void);
+bool ffest_seen_first_exec (void);
+void ffest_shutdown (void);
+ffesymbol ffest_sym_end_transition (ffesymbol s);
+ffesymbol ffest_sym_exec_transition (ffesymbol s);
+void ffest_terminate_0 (void);
+void ffest_terminate_1 (void);
+void ffest_terminate_2 (void);
+void ffest_terminate_3 (void);
+void ffest_terminate_4 (void);
+
+/* Define macros. */
+
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/sta.c b/contrib/gcc/f/sta.c
new file mode 100644
index 0000000..58156f5
--- /dev/null
+++ b/contrib/gcc/f/sta.c
@@ -0,0 +1,2000 @@
+/* sta.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Analyzes the first two tokens, figures out what statements are
+ possible, tries parsing the possible statements by calling on
+ the ffestb functions.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "sta.h"
+#include "bad.h"
+#include "implic.h"
+#include "lex.h"
+#include "malloc.h"
+#include "stb.h"
+#include "stc.h"
+#include "std.h"
+#include "str.h"
+#include "storag.h"
+#include "symbol.h"
+
+/* Externals defined here. */
+
+ffelexToken ffesta_tokens[FFESTA_tokensMAX]; /* For use by a possible. */
+ffestrFirst ffesta_first_kw; /* First NAME(S) looked up. */
+ffestrSecond ffesta_second_kw; /* Second NAME(S) looked up. */
+mallocPool ffesta_output_pool; /* Pool for results of stmt handling. */
+mallocPool ffesta_scratch_pool; /* Pool for stmt scratch handling. */
+ffelexToken ffesta_construct_name;
+ffelexToken ffesta_label_token; /* Pending label stuff. */
+bool ffesta_seen_first_exec;
+bool ffesta_is_entry_valid = FALSE; /* TRUE only in SUBROUTINE/FUNCTION. */
+bool ffesta_line_has_semicolons = FALSE;
+
+/* Simple definitions and enumerations. */
+
+#define FFESTA_ABORT_ON_CONFIRM_ 1 /* 0=slow, tested way; 1=faster way
+ that might not always work. Here's
+ the old description of what used
+ to not work with ==1: (try
+ "CONTINUE\10
+ FORMAT('hi',I11)\END"). Problem
+ is that the "topology" of the
+ confirmed stmt's tokens with
+ regard to CHARACTER, HOLLERITH,
+ NAME/NAMES/NUMBER tokens (like hex
+ numbers), isn't traced if we abort
+ early, then other stmts might get
+ their grubby hands on those
+ unprocessed tokens and commit them
+ improperly. Ideal fix is to rerun
+ the confirmed stmt and forget the
+ rest. */
+
+#define FFESTA_maxPOSSIBLES_ 8/* Never more than this # of possibles. */
+
+/* Internal typedefs. */
+
+typedef struct _ffesta_possible_ *ffestaPossible_;
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+struct _ffesta_possible_
+ {
+ ffestaPossible_ next;
+ ffestaPossible_ previous;
+ ffelexHandler handler;
+ bool named;
+ };
+
+struct _ffesta_possible_root_
+ {
+ ffestaPossible_ first;
+ ffestaPossible_ last;
+ ffelexHandler nil;
+ };
+
+/* Static objects accessed by functions in this module. */
+
+static bool ffesta_is_inhibited_ = FALSE;
+static ffelexToken ffesta_token_0_; /* For use by ffest possibility
+ handling. */
+static ffestaPossible_ ffesta_possibles_[FFESTA_maxPOSSIBLES_];
+static int ffesta_num_possibles_ = 0; /* Number of possibilities. */
+static struct _ffesta_possible_root_ ffesta_possible_nonexecs_;
+static struct _ffesta_possible_root_ ffesta_possible_execs_;
+static ffestaPossible_ ffesta_current_possible_;
+static ffelexHandler ffesta_current_handler_;
+static bool ffesta_confirmed_current_ = FALSE;
+static bool ffesta_confirmed_other_ = FALSE;
+static ffestaPossible_ ffesta_confirmed_possible_;
+static bool ffesta_current_shutdown_ = FALSE;
+#if !FFESTA_ABORT_ON_CONFIRM_
+static bool ffesta_is_two_into_statement_ = FALSE; /* For IF, WHERE stmts. */
+static ffelexToken ffesta_twotokens_1_; /* For IF, WHERE stmts. */
+static ffelexToken ffesta_twotokens_2_; /* For IF, WHERE stmts. */
+#endif
+static ffestaPooldisp ffesta_outpooldisp_; /* After statement dealt
+ with. */
+static bool ffesta_inhibit_confirmation_ = FALSE;
+
+/* Static functions (internal). */
+
+static void ffesta_add_possible_ (ffelexHandler fn, bool exec, bool named);
+static bool ffesta_inhibited_exec_transition_ (void);
+static void ffesta_reset_possibles_ (void);
+static ffelexHandler ffesta_save_ (ffelexToken t);
+static ffelexHandler ffesta_second_ (ffelexToken t);
+#if !FFESTA_ABORT_ON_CONFIRM_
+static ffelexHandler ffesta_send_two_ (ffelexToken t);
+#endif
+
+/* Internal macros. */
+
+#define ffesta_add_possible_exec_(fn) (ffesta_add_possible_ (fn, TRUE, TRUE))
+#define ffesta_add_possible_nonexec_(fn) (ffesta_add_possible_ (fn, FALSE, TRUE))
+#define ffesta_add_possible_unnamed_exec_(fn) (ffesta_add_possible_ (fn, TRUE, FALSE))
+#define ffesta_add_possible_unnamed_nonexec_(fn) (ffesta_add_possible_ (fn, FALSE, FALSE))
+
+/* Add possible statement to appropriate list. */
+
+static void
+ffesta_add_possible_ (ffelexHandler fn, bool exec, bool named)
+{
+ ffestaPossible_ p;
+
+ assert (ffesta_num_possibles_ < FFESTA_maxPOSSIBLES_);
+
+ p = ffesta_possibles_[ffesta_num_possibles_++];
+
+ if (exec)
+ {
+ p->next = (ffestaPossible_) &ffesta_possible_execs_.first;
+ p->previous = ffesta_possible_execs_.last;
+ }
+ else
+ {
+ p->next = (ffestaPossible_) &ffesta_possible_nonexecs_.first;
+ p->previous = ffesta_possible_nonexecs_.last;
+ }
+ p->next->previous = p;
+ p->previous->next = p;
+
+ p->handler = fn;
+ p->named = named;
+}
+
+/* ffesta_inhibited_exec_transition_ -- Do exec transition while inhibited
+
+ if (!ffesta_inhibited_exec_transition_()) // couldn't transition...
+
+ Invokes ffestc_exec_transition, but first enables ffebad and ffesta and
+ afterwards disables them again. Then returns the result of the
+ invocation of ffestc_exec_transition. */
+
+static bool
+ffesta_inhibited_exec_transition_ ()
+{
+ bool result;
+
+ assert (ffebad_inhibit ());
+ assert (ffesta_is_inhibited_);
+
+ ffebad_set_inhibit (FALSE);
+ ffesta_is_inhibited_ = FALSE;
+
+ result = ffestc_exec_transition ();
+
+ ffebad_set_inhibit (TRUE);
+ ffesta_is_inhibited_ = TRUE;
+
+ return result;
+}
+
+/* ffesta_reset_possibles_ -- Reset (clear) lists of possible statements
+
+ ffesta_reset_possibles_();
+
+ Clears the lists of executable and nonexecutable statements. */
+
+static void
+ffesta_reset_possibles_ ()
+{
+ ffesta_num_possibles_ = 0;
+
+ ffesta_possible_execs_.first = ffesta_possible_execs_.last
+ = (ffestaPossible_) &ffesta_possible_execs_.first;
+ ffesta_possible_nonexecs_.first = ffesta_possible_nonexecs_.last
+ = (ffestaPossible_) &ffesta_possible_nonexecs_.first;
+}
+
+/* ffesta_save_ -- Save token on list, pass thru to current handler
+
+ return ffesta_save_; // to lexer.
+
+ Receives a token from the lexer. Saves it in the list of tokens. Calls
+ the current handler with the token.
+
+ If no shutdown error occurred (via
+ ffest_ffebad_start), then if the token was EOS or SEMICOLON, mark the
+ current possible as successful and confirmed but try the next possible
+ anyway until ambiguities in the form handling are ironed out. */
+
+static ffelexHandler
+ffesta_save_ (ffelexToken t)
+{
+ static ffelexToken *saved_tokens = NULL; /* A variable-sized array. */
+ static unsigned int num_saved_tokens = 0; /* Number currently saved. */
+ static unsigned int max_saved_tokens = 0; /* Maximum to be saved. */
+ unsigned int toknum; /* Index into saved_tokens array. */
+ ffelexToken eos; /* EOS created on-the-fly for shutdown
+ purposes. */
+ ffelexToken t2; /* Another temporary token (no intersect with
+ eos, btw). */
+
+ /* Save the current token. */
+
+ if (saved_tokens == NULL)
+ {
+ saved_tokens
+ = (ffelexToken *) malloc_new_ksr (malloc_pool_image (),
+ "FFEST Saved Tokens",
+ (max_saved_tokens = 8) * sizeof (ffelexToken));
+ /* Start off with 8. */
+ }
+ else if (num_saved_tokens >= max_saved_tokens)
+ {
+ toknum = max_saved_tokens;
+ max_saved_tokens <<= 1; /* Multiply by two. */
+ assert (max_saved_tokens > toknum);
+ saved_tokens
+ = (ffelexToken *) malloc_resize_ksr (malloc_pool_image (),
+ saved_tokens,
+ max_saved_tokens * sizeof (ffelexToken),
+ toknum * sizeof (ffelexToken));
+ }
+
+ *(saved_tokens + num_saved_tokens++) = ffelex_token_use (t);
+
+ /* Transmit the current token to the current handler. */
+
+ ffesta_current_handler_ = (ffelexHandler) (*ffesta_current_handler_) (t);
+
+ /* See if this possible has been shut down, or confirmed in which case we
+ might as well shut it down anyway to save time. */
+
+ if ((ffesta_current_shutdown_ || (FFESTA_ABORT_ON_CONFIRM_
+ && ffesta_confirmed_current_))
+ && !ffelex_expecting_character ())
+ {
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+
+ default:
+ eos = ffelex_token_new_eos (ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffesta_inhibit_confirmation_ = ffesta_current_shutdown_;
+ (*ffesta_current_handler_) (eos);
+ ffesta_inhibit_confirmation_ = FALSE;
+ ffelex_token_kill (eos);
+ break;
+ }
+ }
+ else
+ {
+
+ /* If this is an EOS or SEMICOLON token, switch to next handler, else
+ return self as next handler for lexer. */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+
+ default:
+ return (ffelexHandler) ffesta_save_;
+ }
+ }
+
+ next_handler: /* :::::::::::::::::::: */
+
+ /* Note that a shutdown also happens after seeing the first two tokens
+ after "IF (expr)" or "WHERE (expr)" where a statement follows, even
+ though there is no error. This causes the IF or WHERE form to be
+ implemented first before ffest_first is called for the first token in
+ the following statement. */
+
+ if (ffesta_current_shutdown_)
+ ffesta_current_shutdown_ = FALSE; /* Only after sending EOS! */
+ else
+ assert (ffesta_confirmed_current_);
+
+ if (ffesta_confirmed_current_)
+ {
+ ffesta_confirmed_current_ = FALSE;
+ ffesta_confirmed_other_ = TRUE;
+ }
+
+ /* Pick next handler. */
+
+ ffesta_current_possible_ = ffesta_current_possible_->next;
+ ffesta_current_handler_ = ffesta_current_possible_->handler;
+ if (ffesta_current_handler_ == NULL)
+ { /* No handler in this list, try exec list if
+ not tried yet. */
+ if (ffesta_current_possible_
+ == (ffestaPossible_) &ffesta_possible_nonexecs_)
+ {
+ ffesta_current_possible_ = ffesta_possible_execs_.first;
+ ffesta_current_handler_ = ffesta_current_possible_->handler;
+ }
+ if ((ffesta_current_handler_ == NULL)
+ || (!ffesta_seen_first_exec
+ && ((ffesta_confirmed_possible_ != NULL)
+ || !ffesta_inhibited_exec_transition_ ())))
+ /* Don't run execs if: (decoding the "if" ^^^ up here ^^^) - we
+ have no exec handler available, or - we haven't seen the first
+ executable statement yet, and - we've confirmed a nonexec
+ (otherwise even a nonexec would cause a transition), or - a
+ nonexec-to-exec transition can't be made at the statement context
+ level (as in an executable statement in the middle of a STRUCTURE
+ definition); if it can be made, ffestc_exec_transition makes the
+ corresponding transition at the statement state level so
+ specification statements are no longer accepted following an
+ unrecognized statement. (Note: it is valid for f_e_t_ to decide
+ to always return TRUE by "shrieking" away the statement state
+ stack until a transitionable state is reached. Or it can leave
+ the stack as is and return FALSE.)
+
+ If we decide not to run execs, enter this block to rerun the
+ confirmed statement, if any. */
+ { /* At end of both lists! Pick confirmed or
+ first possible. */
+ ffebad_set_inhibit (FALSE);
+ ffesta_is_inhibited_ = FALSE;
+ ffesta_confirmed_other_ = FALSE;
+ ffesta_tokens[0] = ffesta_token_0_;
+ if (ffesta_confirmed_possible_ == NULL)
+ { /* No confirmed success, just use first
+ named possible, or first possible if
+ no named possibles. */
+ ffestaPossible_ possible = ffesta_possible_nonexecs_.first;
+ ffestaPossible_ first = NULL;
+ ffestaPossible_ first_named = NULL;
+ ffestaPossible_ first_exec = NULL;
+
+ for (;;)
+ {
+ if (possible->handler == NULL)
+ {
+ if (possible == (ffestaPossible_) &ffesta_possible_nonexecs_)
+ {
+ possible = first_exec = ffesta_possible_execs_.first;
+ continue;
+ }
+ else
+ break;
+ }
+ if (first == NULL)
+ first = possible;
+ if (possible->named
+ && (first_named == NULL))
+ first_named = possible;
+
+ possible = possible->next;
+ }
+
+ if (first_named != NULL)
+ ffesta_current_possible_ = first_named;
+ else if (ffesta_seen_first_exec
+ && (first_exec != NULL))
+ ffesta_current_possible_ = first_exec;
+ else
+ ffesta_current_possible_ = first;
+
+ ffesta_current_handler_ = ffesta_current_possible_->handler;
+ assert (ffesta_current_handler_ != NULL);
+ }
+ else
+ { /* Confirmed success, use it. */
+ ffesta_current_possible_ = ffesta_confirmed_possible_;
+ ffesta_current_handler_ = ffesta_confirmed_possible_->handler;
+ }
+ ffesta_reset_possibles_ ();
+ }
+ else
+ { /* Switching from [empty?] list of nonexecs
+ to nonempty list of execs at this point. */
+ ffesta_tokens[0] = ffelex_token_use (ffesta_token_0_);
+ ffesymbol_set_retractable (ffesta_scratch_pool);
+ }
+ }
+ else
+ {
+ ffesta_tokens[0] = ffelex_token_use (ffesta_token_0_);
+ ffesymbol_set_retractable (ffesta_scratch_pool);
+ }
+
+ /* Send saved tokens to current handler until either shut down or all
+ tokens sent. */
+
+ for (toknum = 0; toknum < num_saved_tokens; ++toknum)
+ {
+ t = *(saved_tokens + toknum);
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCHARACTER:
+ ffelex_set_expecting_hollerith (0, '\0',
+ ffewhere_line_unknown (),
+ ffewhere_column_unknown ());
+ ffesta_current_handler_
+ = (ffelexHandler) (*ffesta_current_handler_) (t);
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffelex_is_names_expected ())
+ ffesta_current_handler_
+ = (ffelexHandler) (*ffesta_current_handler_) (t);
+ else
+ {
+ t2 = ffelex_token_name_from_names (t, 0, 0);
+ ffesta_current_handler_
+ = (ffelexHandler) (*ffesta_current_handler_) (t2);
+ ffelex_token_kill (t2);
+ }
+ break;
+
+ default:
+ ffesta_current_handler_
+ = (ffelexHandler) (*ffesta_current_handler_) (t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited_)
+ ffelex_token_kill (t); /* Won't need this any more. */
+
+ /* See if this possible has been shut down. */
+
+ else if ((ffesta_current_shutdown_ || (FFESTA_ABORT_ON_CONFIRM_
+ && ffesta_confirmed_current_))
+ && !ffelex_expecting_character ())
+ {
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+
+ default:
+ eos = ffelex_token_new_eos (ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffesta_inhibit_confirmation_ = ffesta_current_shutdown_;
+ (*ffesta_current_handler_) (eos);
+ ffesta_inhibit_confirmation_ = FALSE;
+ ffelex_token_kill (eos);
+ break;
+ }
+ goto next_handler; /* :::::::::::::::::::: */
+ }
+ }
+
+ /* Finished sending all the tokens so far. If still trying possibilities,
+ then if we've just sent an EOS or SEMICOLON token through, go to the
+ next handler. Otherwise, return self so we can gather and process more
+ tokens. */
+
+ if (ffesta_is_inhibited_)
+ {
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ goto next_handler; /* :::::::::::::::::::: */
+
+ default:
+#if FFESTA_ABORT_ON_CONFIRM_
+ assert (!ffesta_confirmed_other_); /* Catch ambiguities. */
+#endif
+ return (ffelexHandler) ffesta_save_;
+ }
+ }
+
+ /* This was the one final possibility, uninhibited, so send the final
+ handler it sent. */
+
+ num_saved_tokens = 0;
+#if !FFESTA_ABORT_ON_CONFIRM_
+ if (ffesta_is_two_into_statement_)
+ { /* End of the line for the previous two
+ tokens, resurrect them. */
+ ffelexHandler next;
+
+ ffesta_is_two_into_statement_ = FALSE;
+ next = (ffelexHandler) ffesta_first (ffesta_twotokens_1_);
+ ffelex_token_kill (ffesta_twotokens_1_);
+ next = (ffelexHandler) (*next) (ffesta_twotokens_2_);
+ ffelex_token_kill (ffesta_twotokens_2_);
+ return (ffelexHandler) next;
+ }
+#endif
+
+ assert (ffesta_current_handler_ != NULL);
+ return (ffelexHandler) ffesta_current_handler_;
+}
+
+/* ffesta_second_ -- Parse the token after a NAME/NAMES in a statement
+
+ return ffesta_second_; // to lexer.
+
+ The second token cannot be a NAMES, since the first token is a NAME or
+ NAMES. If the second token is a NAME, look up its name in the list of
+ second names for use by whoever needs it.
+
+ Then make a list of all the possible statements this could be, based on
+ looking at the first two tokens. Two lists of possible statements are
+ created, one consisting of nonexecutable statements, the other consisting
+ of executable statements.
+
+ If the total number of possibilities is one, just fire up that
+ possibility by calling its handler function, passing the first two
+ tokens through it and so on.
+
+ Otherwise, start up a process whereby tokens are passed to the first
+ possibility on the list until EOS or SEMICOLON is reached or an error
+ is detected. But inhibit any actual reporting of errors; just record
+ their existence in the list. If EOS or SEMICOLON is reached with no
+ errors (other than non-form errors happening downstream, such as an
+ overflowing value for an integer or a GOTO statement identifying a label
+ on a FORMAT statement), then that is the only possible statement. Rerun
+ the statement with error-reporting turned on if any non-form errors were
+ generated, otherwise just use its results, then erase the list of tokens
+ memorized during the search process. If a form error occurs, immediately
+ cancel that possibility by sending EOS as the next token, remember the
+ error code for that possibility, and try the next possibility on the list,
+ first sending it the list of tokens memorized while handling the first
+ possibility, then continuing on as before.
+
+ Ultimately, either the end of the list of possibilities will be reached
+ without any successful forms being detected, in which case we pick one
+ based on hueristics (usually the first possibility) and rerun it with
+ error reporting turned on using the list of memorized tokens so the user
+ sees the error, or one of the possibilities will effectively succeed. */
+
+static ffelexHandler
+ffesta_second_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffesymbol s;
+
+ assert (ffelex_token_type (t) != FFELEX_typeNAMES);
+
+ if (ffelex_token_type (t) == FFELEX_typeNAME)
+ ffesta_second_kw = ffestr_second (t);
+
+ /* Here we use switch on the first keyword name and handle each possible
+ recognizable name by looking at the second token, and building the list
+ of possible names accordingly. For now, just put every possible
+ statement on the list for ambiguity checking. */
+
+ switch (ffesta_first_kw)
+ {
+#if FFESTR_VXT
+ case FFESTR_firstACCEPT:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_V019);
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstALLOCATABLE:
+ ffestb_args.dimlist.len = FFESTR_firstlALLOCATABLE;
+ ffestb_args.dimlist.badname = "ALLOCATABLE";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_dimlist);
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstALLOCATE:
+ ffestb_args.heap.len = FFESTR_firstlALLOCATE;
+ ffestb_args.heap.badname = "ALLOCATE";
+ ffestb_args.heap.ctx = FFEEXPR_contextALLOCATE;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_heap);
+ break;
+#endif
+
+ case FFESTR_firstASSIGN:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R838);
+ break;
+
+ case FFESTR_firstBACKSPACE:
+ ffestb_args.beru.len = FFESTR_firstlBACKSPACE;
+ ffestb_args.beru.badname = "BACKSPACE";
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_beru);
+ break;
+
+ case FFESTR_firstBLOCK:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_block);
+ break;
+
+ case FFESTR_firstBLOCKDATA:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_blockdata);
+ break;
+
+ case FFESTR_firstBYTE:
+ ffestb_args.decl.len = FFESTR_firstlBYTE;
+ ffestb_args.decl.type = FFESTP_typeBYTE;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
+ break;
+
+ case FFESTR_firstCALL:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R1212);
+ break;
+
+ case FFESTR_firstCASE:
+ case FFESTR_firstCASEDEFAULT:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R810);
+ break;
+
+ case FFESTR_firstCHRCTR:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_chartype);
+ break;
+
+ case FFESTR_firstCLOSE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R907);
+ break;
+
+ case FFESTR_firstCOMMON:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R547);
+ break;
+
+ case FFESTR_firstCMPLX:
+ ffestb_args.decl.len = FFESTR_firstlCMPLX;
+ ffestb_args.decl.type = FFESTP_typeCOMPLEX;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstCONTAINS:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R1228);
+ break;
+#endif
+
+ case FFESTR_firstCONTINUE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R841);
+ break;
+
+ case FFESTR_firstCYCLE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R834);
+ break;
+
+ case FFESTR_firstDATA:
+ if (ffe_is_pedantic_not_90 ())
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R528);
+ else
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R528);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstDEALLOCATE:
+ ffestb_args.heap.len = FFESTR_firstlDEALLOCATE;
+ ffestb_args.heap.badname = "DEALLOCATE";
+ ffestb_args.heap.ctx = FFEEXPR_contextDEALLOCATE;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_heap);
+ break;
+#endif
+
+#if FFESTR_VXT
+ case FFESTR_firstDECODE:
+ ffestb_args.vxtcode.len = FFESTR_firstlDECODE;
+ ffestb_args.vxtcode.badname = "DECODE";
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_vxtcode);
+ break;
+#endif
+
+#if FFESTR_VXT
+ case FFESTR_firstDEFINEFILE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_V025);
+ break;
+
+ case FFESTR_firstDELETE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_V021);
+ break;
+#endif
+ case FFESTR_firstDIMENSION:
+ ffestb_args.R524.len = FFESTR_firstlDIMENSION;
+ ffestb_args.R524.badname = "DIMENSION";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R524);
+ break;
+
+ case FFESTR_firstDO:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_do);
+ break;
+
+ case FFESTR_firstDBL:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_double);
+ break;
+
+ case FFESTR_firstDBLCMPLX:
+ ffestb_args.decl.len = FFESTR_firstlDBLCMPLX;
+ ffestb_args.decl.type = FFESTP_typeDBLCMPLX;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_dbltype);
+ break;
+
+ case FFESTR_firstDBLPRCSN:
+ ffestb_args.decl.len = FFESTR_firstlDBLPRCSN;
+ ffestb_args.decl.type = FFESTP_typeDBLPRCSN;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_dbltype);
+ break;
+
+ case FFESTR_firstDOWHILE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_dowhile);
+ break;
+
+ case FFESTR_firstELSE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_else);
+ break;
+
+ case FFESTR_firstELSEIF:
+ ffestb_args.elsexyz.second = FFESTR_secondIF;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_elsexyz);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstELSEWHERE:
+ ffestb_args.elsexyz.second = FFESTR_secondWHERE;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_elsexyz);
+ break;
+#endif
+
+#if FFESTR_VXT
+ case FFESTR_firstENCODE:
+ ffestb_args.vxtcode.len = FFESTR_firstlENCODE;
+ ffestb_args.vxtcode.badname = "ENCODE";
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_vxtcode);
+ break;
+#endif
+
+ case FFESTR_firstEND:
+ if ((ffelex_token_type (ffesta_token_0_) == FFELEX_typeNAMES)
+ || (ffelex_token_type (t) != FFELEX_typeNAME))
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_end);
+ else
+ {
+ switch (ffesta_second_kw)
+ {
+ case FFESTR_secondBLOCK:
+ case FFESTR_secondBLOCKDATA:
+ case FFESTR_secondDO:
+ case FFESTR_secondFILE:
+ case FFESTR_secondFUNCTION:
+ case FFESTR_secondIF:
+#if FFESTR_F90
+ case FFESTR_secondMODULE:
+#endif
+ case FFESTR_secondPROGRAM:
+ case FFESTR_secondSELECT:
+ case FFESTR_secondSUBROUTINE:
+#if FFESTR_F90
+ case FFESTR_secondWHERE:
+#endif
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_end);
+ break;
+
+ default:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_end);
+ break;
+ }
+ }
+ break;
+
+ case FFESTR_firstENDBLOCK:
+ ffestb_args.endxyz.len = FFESTR_firstlENDBLOCK;
+ ffestb_args.endxyz.second = FFESTR_secondBLOCK;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+
+ case FFESTR_firstENDBLOCKDATA:
+ ffestb_args.endxyz.len = FFESTR_firstlENDBLOCKDATA;
+ ffestb_args.endxyz.second = FFESTR_secondBLOCKDATA;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+
+ case FFESTR_firstENDDO:
+ ffestb_args.endxyz.len = FFESTR_firstlENDDO;
+ ffestb_args.endxyz.second = FFESTR_secondDO;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+
+ case FFESTR_firstENDFILE:
+ ffestb_args.beru.len = FFESTR_firstlENDFILE;
+ ffestb_args.beru.badname = "ENDFILE";
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_beru);
+ break;
+
+ case FFESTR_firstENDFUNCTION:
+ ffestb_args.endxyz.len = FFESTR_firstlENDFUNCTION;
+ ffestb_args.endxyz.second = FFESTR_secondFUNCTION;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+
+ case FFESTR_firstENDIF:
+ ffestb_args.endxyz.len = FFESTR_firstlENDIF;
+ ffestb_args.endxyz.second = FFESTR_secondIF;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstENDINTERFACE:
+ ffestb_args.endxyz.len = FFESTR_firstlENDINTERFACE;
+ ffestb_args.endxyz.second = FFESTR_secondINTERFACE;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+#endif
+
+#if FFESTR_VXT
+ case FFESTR_firstENDMAP:
+ ffestb_args.endxyz.len = FFESTR_firstlENDMAP;
+ ffestb_args.endxyz.second = FFESTR_secondMAP;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstENDMODULE:
+ ffestb_args.endxyz.len = FFESTR_firstlENDMODULE;
+ ffestb_args.endxyz.second = FFESTR_secondMODULE;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+#endif
+
+ case FFESTR_firstENDPROGRAM:
+ ffestb_args.endxyz.len = FFESTR_firstlENDPROGRAM;
+ ffestb_args.endxyz.second = FFESTR_secondPROGRAM;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+
+ case FFESTR_firstENDSELECT:
+ ffestb_args.endxyz.len = FFESTR_firstlENDSELECT;
+ ffestb_args.endxyz.second = FFESTR_secondSELECT;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+
+#if FFESTR_VXT
+ case FFESTR_firstENDSTRUCTURE:
+ ffestb_args.endxyz.len = FFESTR_firstlENDSTRUCTURE;
+ ffestb_args.endxyz.second = FFESTR_secondSTRUCTURE;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+#endif
+
+ case FFESTR_firstENDSUBROUTINE:
+ ffestb_args.endxyz.len = FFESTR_firstlENDSUBROUTINE;
+ ffestb_args.endxyz.second = FFESTR_secondSUBROUTINE;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstENDTYPE:
+ ffestb_args.endxyz.len = FFESTR_firstlENDTYPE;
+ ffestb_args.endxyz.second = FFESTR_secondTYPE;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+#endif
+
+#if FFESTR_VXT
+ case FFESTR_firstENDUNION:
+ ffestb_args.endxyz.len = FFESTR_firstlENDUNION;
+ ffestb_args.endxyz.second = FFESTR_secondUNION;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstENDWHERE:
+ ffestb_args.endxyz.len = FFESTR_firstlENDWHERE;
+ ffestb_args.endxyz.second = FFESTR_secondWHERE;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_endxyz);
+ break;
+#endif
+
+ case FFESTR_firstENTRY:
+ ffestb_args.dummy.len = FFESTR_firstlENTRY;
+ ffestb_args.dummy.badname = "ENTRY";
+ ffestb_args.dummy.is_subr = ffestc_is_entry_in_subr ();
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_dummy);
+ break;
+
+ case FFESTR_firstEQUIVALENCE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R544);
+ break;
+
+ case FFESTR_firstEXIT:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R835);
+ break;
+
+ case FFESTR_firstEXTERNAL:
+ ffestb_args.varlist.len = FFESTR_firstlEXTERNAL;
+ ffestb_args.varlist.badname = "EXTERNAL";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_varlist);
+ break;
+
+#if FFESTR_VXT
+ case FFESTR_firstFIND:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_V026);
+ break;
+#endif
+
+ /* WARNING: don't put anything that might cause an item to precede
+ FORMAT in the list of possible statements (it's added below) without
+ making sure FORMAT still is first. It has to run with
+ ffelex_set_names_pure(TRUE), to make sure the lexer delivers NAMES
+ tokens. */
+
+ case FFESTR_firstFORMAT:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R1001);
+ break;
+
+ case FFESTR_firstFUNCTION:
+ ffestb_args.dummy.len = FFESTR_firstlFUNCTION;
+ ffestb_args.dummy.badname = "FUNCTION";
+ ffestb_args.dummy.is_subr = FALSE;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_dummy);
+ break;
+
+ case FFESTR_firstGOTO:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_goto);
+ break;
+
+ case FFESTR_firstIF:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_if);
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R840);
+ break;
+
+ case FFESTR_firstIMPLICIT:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_R539);
+ break;
+
+ case FFESTR_firstINCLUDE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_S3P4);
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ case FFELEX_typeNAME:
+ case FFELEX_typeAPOSTROPHE:
+ case FFELEX_typeQUOTE:
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFESTR_firstINQUIRE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R923);
+ break;
+
+ case FFESTR_firstINTGR:
+ ffestb_args.decl.len = FFESTR_firstlINTGR;
+ ffestb_args.decl.type = FFESTP_typeINTEGER;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ ffestb_args.varlist.len = FFESTR_firstlINTENT;
+ ffestb_args.varlist.badname = "INTENT";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_varlist);
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstINTERFACE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R1202);
+ break;
+#endif
+
+ case FFESTR_firstINTRINSIC:
+ ffestb_args.varlist.len = FFESTR_firstlINTRINSIC;
+ ffestb_args.varlist.badname = "INTRINSIC";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_varlist);
+ break;
+
+ case FFESTR_firstLGCL:
+ ffestb_args.decl.len = FFESTR_firstlLGCL;
+ ffestb_args.decl.type = FFESTP_typeLOGICAL;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
+ break;
+
+#if FFESTR_VXT
+ case FFESTR_firstMAP:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_V012);
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstMODULE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_module);
+ break;
+#endif
+
+ case FFESTR_firstNAMELIST:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R542);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstNULLIFY:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R624);
+ break;
+#endif
+
+ case FFESTR_firstOPEN:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R904);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ ffestb_args.varlist.len = FFESTR_firstlOPTIONAL;
+ ffestb_args.varlist.badname = "OPTIONAL";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_varlist);
+ break;
+#endif
+
+ case FFESTR_firstPARAMETER:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R537);
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_V027);
+ break;
+
+ case FFESTR_firstPAUSE:
+ ffestb_args.halt.len = FFESTR_firstlPAUSE;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_halt);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstPOINTER:
+ ffestb_args.dimlist.len = FFESTR_firstlPOINTER;
+ ffestb_args.dimlist.badname = "POINTER";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_dimlist);
+ break;
+#endif
+
+ case FFESTR_firstPRINT:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R911);
+ break;
+
+#if HARD_F90
+ case FFESTR_firstPRIVATE:
+ ffestb_args.varlist.len = FFESTR_firstlPRIVATE;
+ ffestb_args.varlist.badname = "ACCESS";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_varlist);
+ break;
+#endif
+
+ case FFESTR_firstPROGRAM:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R1102);
+ break;
+
+#if HARD_F90
+ case FFESTR_firstPUBLIC:
+ ffestb_args.varlist.len = FFESTR_firstlPUBLIC;
+ ffestb_args.varlist.badname = "ACCESS";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_varlist);
+ break;
+#endif
+
+ case FFESTR_firstREAD:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R909);
+ break;
+
+ case FFESTR_firstREAL:
+ ffestb_args.decl.len = FFESTR_firstlREAL;
+ ffestb_args.decl.type = FFESTP_typeREAL;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
+ break;
+
+#if FFESTR_VXT
+ case FFESTR_firstRECORD:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_V016);
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstRECURSIVE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_recursive);
+ break;
+#endif
+
+ case FFESTR_firstRETURN:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R1227);
+ break;
+
+ case FFESTR_firstREWIND:
+ ffestb_args.beru.len = FFESTR_firstlREWIND;
+ ffestb_args.beru.badname = "REWIND";
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_beru);
+ break;
+
+#if FFESTR_VXT
+ case FFESTR_firstREWRITE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_V018);
+ break;
+#endif
+
+ case FFESTR_firstSAVE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R522);
+ break;
+
+ case FFESTR_firstSELECT:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R809);
+ break;
+
+ case FFESTR_firstSELECTCASE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R809);
+ break;
+
+#if HARD_F90
+ case FFESTR_firstSEQUENCE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R423B);
+ break;
+#endif
+
+ case FFESTR_firstSTOP:
+ ffestb_args.halt.len = FFESTR_firstlSTOP;
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_halt);
+ break;
+
+#if FFESTR_VXT
+ case FFESTR_firstSTRUCTURE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_V003);
+ break;
+#endif
+
+ case FFESTR_firstSUBROUTINE:
+ ffestb_args.dummy.len = FFESTR_firstlSUBROUTINE;
+ ffestb_args.dummy.badname = "SUBROUTINE";
+ ffestb_args.dummy.is_subr = TRUE;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_dummy);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstTARGET:
+ ffestb_args.dimlist.len = FFESTR_firstlTARGET;
+ ffestb_args.dimlist.badname = "TARGET";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_dimlist);
+ break;
+#endif
+
+ case FFESTR_firstTYPE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_V020);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstTYPE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_type);
+ break;
+#endif
+
+#if HARD_F90
+ case FFESTR_firstTYPE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_typetype);
+ break;
+#endif
+
+#if FFESTR_VXT
+ case FFESTR_firstUNLOCK:
+ ffestb_args.beru.len = FFESTR_firstlUNLOCK;
+ ffestb_args.beru.badname = "UNLOCK";
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_beru);
+ break;
+#endif
+
+#if FFESTR_VXT
+ case FFESTR_firstUNION:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_V009);
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstUSE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R1107);
+ break;
+#endif
+
+ case FFESTR_firstVIRTUAL:
+ ffestb_args.R524.len = FFESTR_firstlVIRTUAL;
+ ffestb_args.R524.badname = "VIRTUAL";
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_R524);
+ break;
+
+ case FFESTR_firstVOLATILE:
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_V014);
+ break;
+
+#if HARD_F90
+ case FFESTR_firstWHERE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_where);
+ break;
+#endif
+
+ case FFESTR_firstWORD:
+ ffestb_args.decl.len = FFESTR_firstlWORD;
+ ffestb_args.decl.type = FFESTP_typeWORD;
+ ffesta_add_possible_nonexec_ ((ffelexHandler) ffestb_decl_gentype);
+ break;
+
+ case FFESTR_firstWRITE:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_R910);
+ break;
+
+ default:
+ break;
+ }
+
+ /* Now check the default cases, which are always "live" (meaning that no
+ other possibility can override them). These are where the second token
+ is OPEN_PAREN, PERCENT, EQUALS, POINTS, or COLON. */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ s = ffesymbol_lookup_local (ffesta_token_0_);
+ if (((s == NULL) || (ffesymbol_dims (s) == NULL))
+ && !ffesta_seen_first_exec)
+ { /* Not known as array; may be stmt function. */
+ ffesta_add_possible_unnamed_nonexec_ ((ffelexHandler) ffestb_R1229);
+
+ /* If the symbol is (or will be due to implicit typing) of
+ CHARACTER type, then the statement might be an assignment
+ statement. If so, since it can't be a function invocation nor
+ an array element reference, the open paren following the symbol
+ name must be followed by an expression and a colon. Without the
+ colon (which cannot appear in a stmt function definition), the
+ let stmt rejects. So CHARACTER_NAME(...)=expr, unlike any other
+ type, is not ambiguous alone. */
+
+ if (ffeimplic_peek_symbol_type (s,
+ ffelex_token_text (ffesta_token_0_))
+ == FFEINFO_basictypeCHARACTER)
+ ffesta_add_possible_unnamed_exec_ ((ffelexHandler) ffestb_let);
+ }
+ else /* Not statement function if known as an
+ array. */
+ ffesta_add_possible_unnamed_exec_ ((ffelexHandler) ffestb_let);
+ break;
+
+#if FFESTR_F90
+ case FFELEX_typePERCENT:
+#endif
+ case FFELEX_typeEQUALS:
+#if FFESTR_F90
+ case FFELEX_typePOINTS:
+#endif
+ ffesta_add_possible_unnamed_exec_ ((ffelexHandler) ffestb_let);
+ break;
+
+ case FFELEX_typeCOLON:
+ ffesta_add_possible_exec_ ((ffelexHandler) ffestb_construct);
+ break;
+
+ default:
+ ;
+ }
+
+ /* Now see how many possibilities are on the list. */
+
+ switch (ffesta_num_possibles_)
+ {
+ case 0: /* None, so invalid statement. */
+ no_stmts: /* :::::::::::::::::::: */
+ ffesta_tokens[0] = ffesta_token_0_;
+ ffesta_ffebad_2t (FFEBAD_UNREC_STMT, ffesta_token_0_, t);
+ next = (ffelexHandler) ffelex_swallow_tokens (NULL,
+ (ffelexHandler) ffesta_zero);
+ break;
+
+ case 1: /* One, so just do it! */
+ ffesta_tokens[0] = ffesta_token_0_;
+ next = ffesta_possible_execs_.first->handler;
+ if (next == NULL)
+ { /* Have a nonexec stmt. */
+ next = ffesta_possible_nonexecs_.first->handler;
+ assert (next != NULL);
+ }
+ else if (ffesta_seen_first_exec)
+ ; /* Have an exec stmt after exec transition. */
+ else if (!ffestc_exec_transition ())
+ /* 1 exec stmt only, but not valid in context, so pretend as though
+ statement is unrecognized. */
+ goto no_stmts; /* :::::::::::::::::::: */
+ break;
+
+ default: /* More than one, so try them in order. */
+ ffesta_confirmed_possible_ = NULL;
+ ffesta_current_possible_ = ffesta_possible_nonexecs_.first;
+ ffesta_current_handler_ = ffesta_current_possible_->handler;
+ if (ffesta_current_handler_ == NULL)
+ {
+ ffesta_current_possible_ = ffesta_possible_execs_.first;
+ ffesta_current_handler_ = ffesta_current_possible_->handler;
+ assert (ffesta_current_handler_ != NULL);
+ if (!ffesta_seen_first_exec)
+ { /* Need to do exec transition now. */
+ ffesta_tokens[0] = ffesta_token_0_;
+ if (!ffestc_exec_transition ())
+ goto no_stmts; /* :::::::::::::::::::: */
+ }
+ }
+ ffesta_tokens[0] = ffelex_token_use (ffesta_token_0_);
+ next = (ffelexHandler) ffesta_save_;
+ ffebad_set_inhibit (TRUE);
+ ffesta_is_inhibited_ = TRUE;
+ break;
+ }
+
+ ffesta_output_pool
+ = malloc_pool_new ("Statement Output", ffe_pool_program_unit (), 1024);
+ ffesta_scratch_pool
+ = malloc_pool_new ("Statement Scratch", ffe_pool_program_unit (), 1024);
+ ffesta_outpooldisp_ = FFESTA_pooldispDISCARD;
+
+ if (ffesta_is_inhibited_)
+ ffesymbol_set_retractable (ffesta_scratch_pool);
+
+ ffelex_set_names (FALSE); /* Most handlers will want this. If not,
+ they have to set it TRUE again (its value
+ at the beginning of a statement). */
+
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffesta_send_two_ -- Send the two tokens saved by ffesta_two after all
+
+ return ffesta_send_two_; // to lexer.
+
+ Currently, if this function gets called, it means that the two tokens
+ saved by ffesta_two did not have their handlers derailed by
+ ffesta_save_, which probably means they weren't sent by ffesta_save_
+ but directly by the lexer, which probably means the original statement
+ (which should be IF (expr) or WHERE (expr)) somehow evaluated to only
+ one possibility in ffesta_second_ or somebody optimized FFEST to
+ immediately revert to one possibility upon confirmation but forgot to
+ change this function (and thus perhaps the entire resubmission
+ mechanism). */
+
+#if !FFESTA_ABORT_ON_CONFIRM_
+static ffelexHandler
+ffesta_send_two_ (ffelexToken t)
+{
+ assert ("what am I doing here?" == NULL);
+ return NULL;
+}
+
+#endif
+/* ffesta_confirmed -- Confirm current possibility as only one
+
+ ffesta_confirmed();
+
+ Sets the confirmation flag. During debugging for ambiguous constructs,
+ asserts that the confirmation flag for a previous possibility has not
+ yet been set. */
+
+void
+ffesta_confirmed ()
+{
+ if (ffesta_inhibit_confirmation_)
+ return;
+ ffesta_confirmed_current_ = TRUE;
+ assert (!ffesta_confirmed_other_
+ || (ffesta_confirmed_possible_ == ffesta_current_possible_));
+ ffesta_confirmed_possible_ = ffesta_current_possible_;
+}
+
+/* ffesta_eof -- End of (non-INCLUDEd) source file
+
+ ffesta_eof();
+
+ Call after piping tokens through ffest_first, where the most recent
+ token sent through must be EOS.
+
+ 20-Feb-91 JCB 1.1
+ Put new EOF token in ffesta_tokens[0], not NULL, because too much
+ code expects something there for error reporting and the like. Also,
+ do basically the same things ffest_second and ffesta_zero do for
+ processing a statement (make and destroy pools, et cetera). */
+
+void
+ffesta_eof ()
+{
+ ffesta_tokens[0] = ffelex_token_new_eof ();
+
+ ffesta_output_pool
+ = malloc_pool_new ("Statement Output", ffe_pool_program_unit (), 1024);
+ ffesta_scratch_pool
+ = malloc_pool_new ("Statement Scratch", ffe_pool_program_unit (), 1024);
+ ffesta_outpooldisp_ = FFESTA_pooldispDISCARD;
+
+ ffestc_eof ();
+
+ if (ffesta_tokens[0] != NULL)
+ ffelex_token_kill (ffesta_tokens[0]);
+
+ if (ffesta_output_pool != NULL)
+ {
+ if (ffesta_outpooldisp_ == FFESTA_pooldispDISCARD)
+ malloc_pool_kill (ffesta_output_pool);
+ ffesta_output_pool = NULL;
+ }
+
+ if (ffesta_scratch_pool != NULL)
+ {
+ malloc_pool_kill (ffesta_scratch_pool);
+ ffesta_scratch_pool = NULL;
+ }
+
+ if (ffesta_label_token != NULL)
+ {
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+ }
+
+ if (ffe_is_ffedebug ())
+ {
+ ffestorag_report ();
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffesymbol_report_all ();
+#endif
+ }
+}
+
+/* ffesta_ffebad_here_current_stmt -- ffebad_here with ptr to current stmt
+
+ ffesta_ffebad_here_current_stmt(0);
+
+ Outsiders can call this fn if they have no more convenient place to
+ point to (via a token or pair of ffewhere objects) and they know a
+ current, useful statement is being evaluted by ffest (i.e. they are
+ being called from ffestb, ffestc, ffestd, ... functions). */
+
+void
+ffesta_ffebad_here_current_stmt (ffebadIndex i)
+{
+ assert (ffesta_tokens[0] != NULL);
+ ffebad_here (i, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+}
+
+/* ffesta_ffebad_start -- Start a possibly inhibited error report
+
+ if (ffesta_ffebad_start(FFEBAD_SOME_ERROR))
+ {
+ ffebad_here, ffebad_string ...;
+ ffebad_finish();
+ }
+
+ Call if the error might indicate that ffest is evaluating the wrong
+ statement form, instead of calling ffebad_start directly. If ffest
+ is choosing between forms, it will return FALSE, send an EOS/SEMICOLON
+ token through as the next token (if the current one isn't already one
+ of those), and try another possible form. Otherwise, ffebad_start is
+ called with the argument and TRUE returned. */
+
+bool
+ffesta_ffebad_start (ffebad errnum)
+{
+ if (!ffesta_is_inhibited_)
+ {
+ ffebad_start (errnum);
+ return TRUE;
+ }
+
+ if (!ffesta_confirmed_current_)
+ ffesta_current_shutdown_ = TRUE;
+
+ return FALSE;
+}
+
+/* ffesta_first -- Parse the first token in a statement
+
+ return ffesta_first; // to lexer. */
+
+ffelexHandler
+ffesta_first (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeEOS:
+ ffesta_tokens[0] = ffelex_token_use (t);
+ if (ffesta_label_token != NULL)
+ {
+ ffebad_start (FFEBAD_LABEL_WITHOUT_STMT);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_string (ffelex_token_text (ffesta_label_token));
+ ffebad_here (1, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffesta_token_0_ = ffelex_token_use (t);
+ ffesta_first_kw = ffestr_first (t);
+ return (ffelexHandler) ffesta_second_;
+
+ case FFELEX_typeNUMBER:
+ if (ffesta_line_has_semicolons
+ && !ffe_is_free_form ()
+ && ffe_is_pedantic ())
+ {
+ ffebad_start (FFEBAD_LABEL_WRONG_PLACE);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_string (ffelex_token_text (t));
+ ffebad_finish ();
+ }
+ if (ffesta_label_token == NULL)
+ {
+ ffesta_label_token = ffelex_token_use (t);
+ return (ffelexHandler) ffesta_first;
+ }
+ else
+ {
+ ffebad_start (FFEBAD_EXTRA_LABEL_DEF);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_string (ffelex_token_text (t));
+ ffebad_here (1, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_string (ffelex_token_text (ffesta_label_token));
+ ffebad_finish ();
+
+ return (ffelexHandler) ffesta_first;
+ }
+
+ default: /* Invalid first token. */
+ ffesta_tokens[0] = ffelex_token_use (t);
+ ffebad_start (FFEBAD_STMT_BEGINS_BAD);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffesta_init_0 -- Initialize for entire image invocation
+
+ ffesta_init_0();
+
+ Call just once per invocation of the compiler (not once per invocation
+ of the front end).
+
+ Gets memory for the list of possibles once and for all, since this
+ list never gets larger than a certain size (FFESTA_maxPOSSIBLES_)
+ and is not particularly large. Initializes the array of pointers to
+ this list. Initializes the executable and nonexecutable lists. */
+
+void
+ffesta_init_0 ()
+{
+ ffestaPossible_ ptr;
+ int i;
+
+ ptr = (ffestaPossible_) malloc_new_kp (malloc_pool_image (),
+ "FFEST possibles",
+ FFESTA_maxPOSSIBLES_
+ * sizeof (*ptr));
+
+ for (i = 0; i < FFESTA_maxPOSSIBLES_; ++i)
+ ffesta_possibles_[i] = ptr++;
+
+ ffesta_possible_execs_.first = ffesta_possible_execs_.last
+ = (ffestaPossible_) &ffesta_possible_execs_.first;
+ ffesta_possible_nonexecs_.first = ffesta_possible_nonexecs_.last
+ = (ffestaPossible_) &ffesta_possible_nonexecs_.first;
+ ffesta_possible_execs_.nil = ffesta_possible_nonexecs_.nil = NULL;
+}
+
+/* ffesta_init_3 -- Initialize for any program unit
+
+ ffesta_init_3(); */
+
+void
+ffesta_init_3 ()
+{
+ ffesta_output_pool = NULL; /* May be doing this just before reaching */
+ ffesta_scratch_pool = NULL; /* ffesta_zero or ffesta_two. */
+ /* NOTE: we let the ffe_terminate_2 action of killing the program_unit pool
+ handle the killing of the output and scratch pools for us, which is why
+ we don't have a terminate_3 action to do so. */
+ ffesta_construct_name = NULL;
+ ffesta_label_token = NULL;
+ ffesta_seen_first_exec = FALSE;
+}
+
+/* ffesta_is_inhibited -- Test whether the current possibility is inhibited
+
+ if (!ffesta_is_inhibited())
+ // implement the statement.
+
+ Just make sure the current possibility has been confirmed. If anyone
+ really needs to test whether the current possibility is inhibited prior
+ to confirming it, that indicates a need to begin statement processing
+ before it is certain that the given possibility is indeed the statement
+ to be processed. As of this writing, there does not appear to be such
+ a need. If there is, then when confirming a statement would normally
+ immediately disable the inhibition (whereas currently we leave the
+ confirmed statement disabled until we've tried the other possibilities,
+ to check for ambiguities), we must check to see if the possibility has
+ already tested for inhibition prior to confirmation and, if so, maintain
+ inhibition until the end of the statement (which may be forced right
+ away) and then rerun the entire statement from the beginning. Otherwise,
+ initial calls to ffestb functions won't have been made, but subsequent
+ calls (after confirmation) will, which is wrong. Of course, this all
+ applies only to those statements implemented via multiple calls to
+ ffestb, although if a statement requiring only a single ffestb call
+ tested for inhibition prior to confirmation, it would likely mean that
+ the ffestb call would be completely dropped without this mechanism. */
+
+bool
+ffesta_is_inhibited ()
+{
+ assert (ffesta_confirmed_current_ || ffesta_inhibit_confirmation_);
+ return ffesta_is_inhibited_;
+}
+
+/* ffesta_ffebad_1p -- Issue diagnostic with one source character
+
+ ffelexToken names_token;
+ ffeTokenLength index;
+ ffelexToken next_token;
+ ffesta_ffebad_1p(FFEBAD_SOME_ERROR,names_token,index,next_token);
+
+ Equivalent to "if (ffest_ffebad_start(FFEBAD_SOME_ERROR))" followed by
+ sending one argument, the location of index with names_token, if TRUE is
+ returned. If index is equal to the length of names_token, meaning it
+ points to the end of the token, then uses the location in next_token
+ (which should be the token sent by the lexer after it sent names_token)
+ instead. */
+
+void
+ffesta_ffebad_1p (ffebad errnum, ffelexToken names_token, ffeTokenLength index,
+ ffelexToken next_token)
+{
+ ffewhereLine line;
+ ffewhereColumn col;
+
+ assert (index <= ffelex_token_length (names_token));
+
+ if (ffesta_ffebad_start (errnum))
+ {
+ if (index == ffelex_token_length (names_token))
+ {
+ assert (next_token != NULL);
+ line = ffelex_token_where_line (next_token);
+ col = ffelex_token_where_column (next_token);
+ ffebad_here (0, line, col);
+ }
+ else
+ {
+ ffewhere_set_from_track (&line, &col,
+ ffelex_token_where_line (names_token),
+ ffelex_token_where_column (names_token),
+ ffelex_token_wheretrack (names_token),
+ index);
+ ffebad_here (0, line, col);
+ ffewhere_line_kill (line);
+ ffewhere_column_kill (col);
+ }
+ ffebad_finish ();
+ }
+}
+
+void
+ffesta_ffebad_1sp (ffebad errnum, char *s, ffelexToken names_token,
+ ffeTokenLength index, ffelexToken next_token)
+{
+ ffewhereLine line;
+ ffewhereColumn col;
+
+ assert (index <= ffelex_token_length (names_token));
+
+ if (ffesta_ffebad_start (errnum))
+ {
+ ffebad_string (s);
+ if (index == ffelex_token_length (names_token))
+ {
+ assert (next_token != NULL);
+ line = ffelex_token_where_line (next_token);
+ col = ffelex_token_where_column (next_token);
+ ffebad_here (0, line, col);
+ }
+ else
+ {
+ ffewhere_set_from_track (&line, &col,
+ ffelex_token_where_line (names_token),
+ ffelex_token_where_column (names_token),
+ ffelex_token_wheretrack (names_token),
+ index);
+ ffebad_here (0, line, col);
+ ffewhere_line_kill (line);
+ ffewhere_column_kill (col);
+ }
+ ffebad_finish ();
+ }
+}
+
+void
+ffesta_ffebad_1st (ffebad errnum, char *s, ffelexToken t)
+{
+ if (ffesta_ffebad_start (errnum))
+ {
+ ffebad_string (s);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+}
+
+/* ffesta_ffebad_1t -- Issue diagnostic with one source token
+
+ ffelexToken t;
+ ffesta_ffebad_1t(FFEBAD_SOME_ERROR,t);
+
+ Equivalent to "if (ffesta_ffebad_start(FFEBAD_SOME_ERROR))" followed by
+ sending one argument, the location of the token t, if TRUE is returned. */
+
+void
+ffesta_ffebad_1t (ffebad errnum, ffelexToken t)
+{
+ if (ffesta_ffebad_start (errnum))
+ {
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+}
+
+void
+ffesta_ffebad_2st (ffebad errnum, char *s, ffelexToken t1, ffelexToken t2)
+{
+ if (ffesta_ffebad_start (errnum))
+ {
+ ffebad_string (s);
+ ffebad_here (0, ffelex_token_where_line (t1), ffelex_token_where_column (t1));
+ ffebad_here (1, ffelex_token_where_line (t2), ffelex_token_where_column (t2));
+ ffebad_finish ();
+ }
+}
+
+/* ffesta_ffebad_2t -- Issue diagnostic with two source tokens
+
+ ffelexToken t1, t2;
+ ffesta_ffebad_2t(FFEBAD_SOME_ERROR,t1,t2);
+
+ Equivalent to "if (ffesta_ffebad_start(FFEBAD_SOME_ERROR))" followed by
+ sending two argument, the locations of the tokens t1 and t2, if TRUE is
+ returned. */
+
+void
+ffesta_ffebad_2t (ffebad errnum, ffelexToken t1, ffelexToken t2)
+{
+ if (ffesta_ffebad_start (errnum))
+ {
+ ffebad_here (0, ffelex_token_where_line (t1), ffelex_token_where_column (t1));
+ ffebad_here (1, ffelex_token_where_line (t2), ffelex_token_where_column (t2));
+ ffebad_finish ();
+ }
+}
+
+ffestaPooldisp
+ffesta_outpooldisp ()
+{
+ return ffesta_outpooldisp_;
+}
+
+void
+ffesta_set_outpooldisp (ffestaPooldisp d)
+{
+ ffesta_outpooldisp_ = d;
+}
+
+/* Shut down current parsing possibility, but without bothering the
+ user with a diagnostic if we're not inhibited. */
+
+void
+ffesta_shutdown ()
+{
+ if (ffesta_is_inhibited_)
+ ffesta_current_shutdown_ = TRUE;
+}
+
+/* ffesta_two -- Deal with the first two tokens after a swallowed statement
+
+ return ffesta_two(first_token,second_token); // to lexer.
+
+ Like ffesta_zero, except instead of expecting an EOS or SEMICOLON, it
+ expects the first two tokens of a statement that is part of another
+ statement: the first two tokens of statement in "IF (expr) statement" or
+ "WHERE (expr) statement", in particular. The first token must be a NAME
+ or NAMES, the second can be basically anything. The statement type MUST
+ be confirmed by now.
+
+ If we're not inhibited, just handle things as if we were ffesta_zero
+ and saw an EOS just before the two tokens.
+
+ If we're inhibited, set ffesta_current_shutdown_ to shut down the current
+ statement and continue with other possibilities, then (presumably) come
+ back to this one for real when not inhibited. */
+
+ffelexHandler
+ffesta_two (ffelexToken first, ffelexToken second)
+{
+#if FFESTA_ABORT_ON_CONFIRM_
+ ffelexHandler next;
+#endif
+
+ assert ((ffelex_token_type (first) == FFELEX_typeNAME)
+ || (ffelex_token_type (first) == FFELEX_typeNAMES));
+ assert (ffesta_tokens[0] != NULL);
+
+ if (ffesta_is_inhibited_) /* Oh, not really done with statement. */
+ {
+ ffesta_current_shutdown_ = TRUE;
+ /* To catch the EOS on shutdown. */
+ return (ffelexHandler) ffelex_swallow_tokens (second,
+ (ffelexHandler) ffesta_zero);
+ }
+
+ ffestw_display_state ();
+
+ ffelex_token_kill (ffesta_tokens[0]);
+
+ if (ffesta_output_pool != NULL)
+ {
+ if (ffesta_outpooldisp_ == FFESTA_pooldispDISCARD)
+ malloc_pool_kill (ffesta_output_pool);
+ ffesta_output_pool = NULL;
+ }
+
+ if (ffesta_scratch_pool != NULL)
+ {
+ malloc_pool_kill (ffesta_scratch_pool);
+ ffesta_scratch_pool = NULL;
+ }
+
+ ffesta_reset_possibles_ ();
+ ffesta_confirmed_current_ = FALSE;
+
+ /* What happens here is somewhat interesting. We effectively derail the
+ line of handlers for these two tokens, the first two in a statement, by
+ setting a flag to TRUE. This flag tells ffesta_save_ (or, conceivably,
+ the lexer via ffesta_second_'s case 1:, where it has only one possible
+ kind of statement -- someday this will be more likely, i.e. after
+ confirmation causes an immediate switch to only the one context rather
+ than just setting a flag and running through the remaining possibles to
+ look for ambiguities) that the last two tokens it sent did not reach the
+ truly desired targets (ffest_first and ffesta_second_) since that would
+ otherwise attempt to recursively invoke ffesta_save_ in most cases,
+ while the existing ffesta_save_ was still alive and making use of static
+ (nonrecursive) variables. Instead, ffesta_save_, upon seeing this flag
+ set TRUE, sets it to FALSE and resubmits the two tokens copied here to
+ ffest_first and, presumably, ffesta_second_, kills them, and returns the
+ handler returned by the handler for the second token. Thus, even though
+ ffesta_save_ is still (likely to be) recursively invoked, the former
+ invocation is past the use of any static variables possibly changed
+ during the first-two-token invocation of the latter invocation. */
+
+#if FFESTA_ABORT_ON_CONFIRM_
+ /* Shouldn't be in ffesta_save_ at all here. */
+
+ next = (ffelexHandler) ffesta_first (first);
+ return (ffelexHandler) (*next) (second);
+#else
+ ffesta_twotokens_1_ = ffelex_token_use (first);
+ ffesta_twotokens_2_ = ffelex_token_use (second);
+
+ ffesta_is_two_into_statement_ = TRUE;
+ return (ffelexHandler) ffesta_send_two_; /* Shouldn't get called. */
+#endif
+}
+
+/* ffesta_zero -- Deal with the end of a swallowed statement
+
+ return ffesta_zero; // to lexer.
+
+ NOTICE that this code is COPIED, largely, into a
+ similar function named ffesta_two that gets invoked in place of
+ _zero_ when the end of the statement happens before EOS or SEMICOLON and
+ to tokens into the next statement have been read (as is the case with the
+ logical-IF and WHERE-stmt statements). So any changes made here should
+ probably be made in _two_ at the same time. */
+
+ffelexHandler
+ffesta_zero (ffelexToken t)
+{
+ assert ((ffelex_token_type (t) == FFELEX_typeEOS)
+ || (ffelex_token_type (t) == FFELEX_typeSEMICOLON));
+ assert (ffesta_tokens[0] != NULL);
+
+ if (ffesta_is_inhibited_)
+ ffesymbol_retract (TRUE);
+ else
+ ffestw_display_state ();
+
+ /* Do CONTINUE if nothing else. This is done specifically so that "IF
+ (...) BLAH" causes the same things to happen as if "IF (...) CONTINUE"
+ was done, so that tracking of labels and such works. (Try a small
+ program like "DO 10 ...", "IF (...) BLAH", "10 CONTINUE", "END".)
+
+ But it turns out that just testing "!ffesta_confirmed_current_"
+ isn't enough, because then typing "GOTO" instead of "BLAH" above
+ doesn't work -- the statement is confirmed (we know the user
+ attempted a GOTO) but ffestc hasn't seen it. So, instead, just
+ always tell ffestc to do "any" statement it needs to reset. */
+
+ if (!ffesta_is_inhibited_
+ && ffesta_seen_first_exec)
+ {
+ ffestc_any ();
+ }
+
+ ffelex_token_kill (ffesta_tokens[0]);
+
+ if (ffesta_is_inhibited_) /* Oh, not really done with statement. */
+ return (ffelexHandler) ffesta_zero; /* Call me again when done! */
+
+ if (ffesta_output_pool != NULL)
+ {
+ if (ffesta_outpooldisp_ == FFESTA_pooldispDISCARD)
+ malloc_pool_kill (ffesta_output_pool);
+ ffesta_output_pool = NULL;
+ }
+
+ if (ffesta_scratch_pool != NULL)
+ {
+ malloc_pool_kill (ffesta_scratch_pool);
+ ffesta_scratch_pool = NULL;
+ }
+
+ ffesta_reset_possibles_ ();
+ ffesta_confirmed_current_ = FALSE;
+
+ if (ffelex_token_type (t) == FFELEX_typeSEMICOLON)
+ {
+ ffesta_line_has_semicolons = TRUE;
+ if (ffe_is_pedantic_not_90 ())
+ {
+ ffebad_start (FFEBAD_SEMICOLON);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ }
+ else
+ ffesta_line_has_semicolons = FALSE;
+
+ if (ffesta_label_token != NULL)
+ {
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+ }
+
+ if (ffe_is_ffedebug ())
+ {
+ ffestorag_report ();
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffesymbol_report_all ();
+#endif
+ }
+
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffesta_first;
+}
diff --git a/contrib/gcc/f/sta.h b/contrib/gcc/f/sta.h
new file mode 100644
index 0000000..6bb9913
--- /dev/null
+++ b/contrib/gcc/f/sta.h
@@ -0,0 +1,117 @@
+/* sta.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ sta.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_sta
+#define _H_f_sta
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFESTA_pooldispDISCARD, /* Default state. */
+ FFESTA_pooldispPRESERVE, /* Preserve through end of program unit. */
+ FFESTA_pooldisp
+ } ffestaPooldisp;
+
+#define FFESTA_tokensMAX 10 /* Max # tokens in fixed positions. */
+
+/* Typedefs. */
+
+/* Include files needed by this one. */
+
+#include "bad.h"
+#include "lex.h"
+#include "malloc.h"
+#include "str.h"
+#include "symbol.h"
+
+typedef mallocPool ffestaPool; /* No need for use count yet. */
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+extern ffelexToken ffesta_tokens[FFESTA_tokensMAX];
+extern ffestrFirst ffesta_first_kw;
+extern ffestrSecond ffesta_second_kw;
+extern mallocPool ffesta_output_pool;
+extern mallocPool ffesta_scratch_pool;
+extern ffelexToken ffesta_construct_name;
+extern ffelexToken ffesta_label_token;
+extern bool ffesta_seen_first_exec;
+extern bool ffesta_is_entry_valid;
+extern bool ffesta_line_has_semicolons;
+
+/* Declare functions with prototypes. */
+
+void ffesta_confirmed (void);
+void ffesta_eof (void);
+bool ffesta_ffebad_start (ffebad errnum);
+void ffesta_ffebad_here_current_stmt (ffebadIndex i);
+ffelexHandler ffesta_first (ffelexToken t);
+void ffesta_init_0 (void);
+void ffesta_init_3 (void);
+bool ffesta_is_inhibited (void);
+void ffesta_terminate_0 (void);
+void ffesta_terminate_1 (void);
+void ffesta_terminate_2 (void);
+void ffesta_terminate_3 (void);
+void ffesta_terminate_4 (void);
+void ffesta_ffebad_here_doiter (ffebadIndex i, ffesymbol s);
+void ffesta_shutdown (void);
+ffesymbol ffesta_sym_end_transition (ffesymbol s);
+ffesymbol ffesta_sym_exec_transition (ffesymbol s);
+void ffesta_ffebad_1p (ffebad msg, ffelexToken names_token,
+ ffeTokenLength index, ffelexToken next_token);
+void ffesta_ffebad_1sp (ffebad msg, char *s, ffelexToken names_token,
+ ffeTokenLength index, ffelexToken next_token);
+void ffesta_ffebad_1st (ffebad msg, char *s, ffelexToken t);
+void ffesta_ffebad_1t (ffebad msg, ffelexToken t);
+void ffesta_ffebad_2st (ffebad msg, char *s, ffelexToken t1, ffelexToken t2);
+void ffesta_ffebad_2t (ffebad msg, ffelexToken t1, ffelexToken t2);
+ffelexHandler ffesta_zero (ffelexToken t);
+ffelexHandler ffesta_two (ffelexToken first, ffelexToken second);
+ffestaPooldisp ffesta_outpooldisp (void);
+void ffesta_set_outpooldisp (ffestaPooldisp d);
+
+/* Define macros. */
+
+#define ffesta_init_1()
+#define ffesta_init_2()
+#define ffesta_init_4()
+#define ffesta_terminate_0()
+#define ffesta_terminate_1()
+#define ffesta_terminate_2()
+#define ffesta_terminate_3()
+#define ffesta_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/stb.c b/contrib/gcc/f/stb.c
new file mode 100644
index 0000000..dc4bda4
--- /dev/null
+++ b/contrib/gcc/f/stb.c
@@ -0,0 +1,25198 @@
+/* stb.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ st.c
+
+ Description:
+ Parses the proper form for statements, builds up expression trees for
+ them, but does not actually implement them. Uses ffebad (primarily via
+ ffesta_ffebad_start) to indicate errors in form. In many cases, an invalid
+ statement form indicates another possible statement needs to be looked at
+ by ffest. In a few cases, a valid statement form might not completely
+ determine the nature of the statement, as in REALFUNCTIONA(B), which is
+ a valid form for either the first statement of a function named A taking
+ an argument named B or for the declaration of a real array named FUNCTIONA
+ with an adjustable size of B. A similar (though somewhat easier) choice
+ must be made for the statement-function-def vs. assignment forms, as in
+ the case of FOO(A) = A+2.0.
+
+ A given parser consists of one or more state handlers, the first of which
+ is the initial state, and the last of which (for any given input) returns
+ control to a final state handler (ffesta_zero or ffesta_two, explained
+ below). The functions handling the states for a given parser usually have
+ the same names, differing only in the final number, as in ffestb_foo_
+ (handles the initial state), ffestb_foo_1_, ffestb_foo_2_ (handle
+ subsequent states), although liberties sometimes are taken with the "foo"
+ part either when keywords are clarified into given statements or are
+ transferred into other possible areas. (For example, the type-name
+ states can hop over to _dummy_ functions when the FUNCTION or RECURSIVE
+ keywords are seen, though this kind of thing is kept to a minimum.) Only
+ the names without numbers are exported to the rest of ffest; the others
+ are local (static).
+
+ Each initial state is provided with the first token in ffesta_tokens[0],
+ which will be killed upon return to the final state (ffesta_zero or
+ ffelex_swallow_tokens passed through to ffesta_zero), so while it may
+ be changed to another token, a valid token must be left there to be
+ killed. Also, a "convenient" array of tokens are left in
+ ffesta_tokens[1..FFESTA_tokensMAX]. The initial state of this set of
+ elements is undefined, thus, if tokens are stored here, they must be
+ killed before returning to the final state. Any parser may also use
+ cross-state local variables by sticking a structure containing storage
+ for those variables in the local union ffestb_local_ (unless the union
+ goes on strike). Furthermore, parsers that handle more than one first or
+ second tokens (like _varlist_, which handles EXTERNAL, INTENT, INTRINSIC,
+ OPTIONAL,
+ PUBLIC, or PRIVATE, and _endxyz_, which handles ENDBLOCK, ENDBLOCKDATA,
+ ENDDO, ENDIF, and so on) may expect arguments from ffest in the
+ ffest-wide union ffest_args_, the substructure specific to the parser.
+
+ A parser's responsibility is: to call either ffesta_confirmed or
+ ffest_ffebad_start before returning to the final state; to be the only
+ parser that can possibly call ffesta_confirmed for a given statement;
+ to call ffest_ffebad_start immediately upon recognizing a bad token
+ (specifically one that another statement parser might confirm upon);
+ to call ffestc functions only after calling ffesta_confirmed and only
+ when ffesta_is_inhibited returns FALSE; and to call ffesta_is_inhibited
+ only after calling ffesta_confirmed. Confirm as early as reasonably
+ possible, even when only one ffestc function is called for the statement
+ later on, because early confirmation can enhance the error-reporting
+ capabilities if a subsequent error is detected and this parser isn't
+ the first possibility for the statement.
+
+ To assist the parser, functions like ffesta_ffebad_1t and _1p_ have
+ been provided to make use of ffest_ffebad_start fairly easy.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "stb.h"
+#include "bad.h"
+#include "expr.h"
+#include "lex.h"
+#include "malloc.h"
+#include "src.h"
+#include "sta.h"
+#include "stc.h"
+#include "stp.h"
+#include "str.h"
+
+/* Externals defined here. */
+
+struct _ffestb_args_ ffestb_args;
+
+/* Simple definitions and enumerations. */
+
+#define FFESTB_KILL_EASY_ 1 /* 1 for only one _subr_kill_xyz_ fn. */
+
+/* Internal typedefs. */
+
+union ffestb_subrargs_u_
+ {
+ struct
+ {
+ ffesttTokenList labels; /* Input arg, must not be NULL. */
+ ffelexHandler handler; /* Input arg, call me when done. */
+ bool ok; /* Output arg, TRUE if list ended in
+ CLOSE_PAREN. */
+ }
+ label_list;
+ struct
+ {
+ ffesttDimList dims; /* Input arg, must not be NULL. */
+ ffelexHandler handler; /* Input arg, call me when done. */
+ mallocPool pool; /* Pool to allocate into. */
+ bool ok; /* Output arg, TRUE if list ended in
+ CLOSE_PAREN. */
+ ffeexprContext ctx; /* DIMLIST or DIMLISTCOMMON. */
+#ifdef FFECOM_dimensionsMAX
+ int ndims; /* For backends that really can't have
+ infinite dims. */
+#endif
+ }
+ dim_list;
+ struct
+ {
+ ffesttTokenList args; /* Input arg, must not be NULL. */
+ ffelexHandler handler; /* Input arg, call me when done. */
+ ffelexToken close_paren;/* Output arg if ok, CLOSE_PAREN token. */
+ bool is_subr; /* Input arg, TRUE if list in subr-def
+ context. */
+ bool ok; /* Output arg, TRUE if list ended in
+ CLOSE_PAREN. */
+ bool names; /* Do ffelex_set_names(TRUE) before return. */
+ }
+ name_list;
+ };
+
+union ffestb_local_u_
+ {
+ struct
+ {
+ ffebld expr;
+ }
+ call_stmt;
+ struct
+ {
+ ffebld expr;
+ }
+ go_to;
+ struct
+ {
+ ffebld dest;
+ bool vxtparam; /* If assignment might really be VXT
+ PARAMETER stmt. */
+ }
+ let;
+ struct
+ {
+ ffebld expr;
+ }
+ if_stmt;
+ struct
+ {
+ ffebld expr;
+ }
+ else_stmt;
+ struct
+ {
+ ffebld expr;
+ }
+ dowhile;
+ struct
+ {
+ ffebld var;
+ ffebld start;
+ ffebld end;
+ }
+ do_stmt;
+ struct
+ {
+ bool is_cblock;
+ }
+ R522;
+ struct
+ {
+ ffebld expr;
+ bool started;
+ }
+ parameter;
+ struct
+ {
+ ffesttExprList exprs;
+ bool started;
+ }
+ equivalence;
+ struct
+ {
+ ffebld expr;
+ bool started;
+ }
+ data;
+ struct
+ {
+ ffestrOther kw;
+ }
+ varlist;
+#if FFESTR_F90
+ struct
+ {
+ ffestrOther kw;
+ }
+ type;
+#endif
+ struct
+ {
+ ffelexHandler next;
+ }
+ construct;
+ struct
+ {
+ ffesttFormatList f;
+ ffestpFormatType current; /* What we're currently working on. */
+ ffelexToken t; /* Token of what we're currently working on. */
+ ffesttFormatValue pre;
+ ffesttFormatValue post;
+ ffesttFormatValue dot;
+ ffesttFormatValue exp;
+ bool sign; /* _3_, pos/neg; elsewhere, signed/unsigned. */
+ bool complained; /* If run-time expr seen in nonexec context. */
+ }
+ format;
+#if FFESTR_F90
+ struct
+ {
+ bool started;
+ }
+ moduleprocedure;
+#endif
+ struct
+ {
+ ffebld expr;
+ }
+ selectcase;
+ struct
+ {
+ ffesttCaseList cases;
+ }
+ case_stmt;
+#if FFESTR_F90
+ struct
+ {
+ ffesttExprList exprs;
+ ffebld expr;
+ }
+ heap;
+#endif
+#if FFESTR_F90
+ struct
+ {
+ ffesttExprList exprs;
+ }
+ R624;
+#endif
+#if FFESTR_F90
+ struct
+ {
+ ffestpDefinedOperator operator;
+ bool assignment; /* TRUE for INTERFACE ASSIGNMENT, FALSE for
+ ...OPERATOR. */
+ bool slash; /* TRUE if OPEN_ARRAY, FALSE if OPEN_PAREN. */
+ }
+ interface;
+#endif
+ struct
+ {
+ bool is_cblock;
+ }
+ V014;
+#if FFESTR_VXT
+ struct
+ {
+ bool started;
+ ffebld u;
+ ffebld m;
+ ffebld n;
+ ffebld asv;
+ }
+ V025;
+#endif
+ struct
+ {
+ ffestpBeruIx ix;
+ bool label;
+ bool left;
+ ffeexprContext context;
+ }
+ beru;
+ struct
+ {
+ ffestpCloseIx ix;
+ bool label;
+ bool left;
+ ffeexprContext context;
+ }
+ close;
+ struct
+ {
+ ffestpDeleteIx ix;
+ bool label;
+ bool left;
+ ffeexprContext context;
+ }
+ delete;
+ struct
+ {
+ ffestpDeleteIx ix;
+ bool label;
+ bool left;
+ ffeexprContext context;
+ }
+ find;
+ struct
+ {
+ ffestpInquireIx ix;
+ bool label;
+ bool left;
+ ffeexprContext context;
+ bool may_be_iolength;
+ }
+ inquire;
+ struct
+ {
+ ffestpOpenIx ix;
+ bool label;
+ bool left;
+ ffeexprContext context;
+ }
+ open;
+ struct
+ {
+ ffestpReadIx ix;
+ bool label;
+ bool left;
+ ffeexprContext context;
+ }
+ read;
+ struct
+ {
+ ffestpRewriteIx ix;
+ bool label;
+ bool left;
+ ffeexprContext context;
+ }
+ rewrite;
+ struct
+ {
+ ffestpWriteIx ix;
+ bool label;
+ bool left;
+ ffeexprContext context;
+ }
+ vxtcode;
+ struct
+ {
+ ffestpWriteIx ix;
+ bool label;
+ bool left;
+ ffeexprContext context;
+ }
+ write;
+#if FFESTR_F90
+ struct
+ {
+ bool started;
+ }
+ structure;
+#endif
+ struct
+ {
+ bool started;
+ }
+ common;
+ struct
+ {
+ bool started;
+ }
+ dimension;
+ struct
+ {
+ bool started;
+ }
+ dimlist;
+ struct
+ {
+ char *badname;
+ ffestrFirst first_kw;
+ bool is_subr;
+ }
+ dummy;
+ struct
+ {
+ ffebld kind; /* Kind type parameter, if any. */
+ ffelexToken kindt; /* Kind type first token, if any. */
+ ffebld len; /* Length type parameter, if any. */
+ ffelexToken lent; /* Length type parameter, if any. */
+ ffelexHandler handler;
+ ffelexToken recursive;
+ ffebld expr;
+ ffesttTokenList toklist;/* For ambiguity resolution. */
+ ffesttImpList imps; /* List of IMPLICIT letters. */
+ ffelexHandler imp_handler; /* Call if paren list wasn't letters. */
+ char *badname;
+ ffestrOther kw; /* INTENT(IN/OUT/INOUT). */
+ ffestpType type;
+ bool parameter; /* If PARAMETER attribute seen (governs =expr
+ context). */
+ bool coloncolon; /* If COLONCOLON seen (allows =expr). */
+ bool aster_after; /* "*" seen after, not before,
+ [RECURSIVE]FUNCTIONxyz. */
+ bool empty; /* Ambig function dummy arg list empty so
+ far? */
+ bool imp_started; /* Started IMPLICIT statement already. */
+ bool imp_seen_comma; /* TRUE if next COMMA within parens means not
+ R541. */
+ }
+ decl;
+ struct
+ {
+ bool started;
+ }
+ vxtparam;
+ }; /* Merge with the one in ffestb later. */
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+static union ffestb_subrargs_u_ ffestb_subrargs_;
+static union ffestb_local_u_ ffestb_local_;
+
+/* Static functions (internal). */
+
+static void ffestb_subr_ambig_to_ents_ (void);
+static ffelexHandler ffestb_subr_ambig_nope_ (ffelexToken t);
+static ffelexHandler ffestb_subr_dimlist_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_subr_dimlist_1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_subr_dimlist_2_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_subr_name_list_ (ffelexToken t);
+static ffelexHandler ffestb_subr_name_list_1_ (ffelexToken t);
+static void ffestb_subr_R1001_append_p_ (void);
+static ffelexHandler ffestb_decl_kindparam_ (ffelexToken t);
+static ffelexHandler ffestb_decl_kindparam_1_ (ffelexToken t);
+static ffelexHandler ffestb_decl_kindparam_2_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_decl_starkind_ (ffelexToken t);
+static ffelexHandler ffestb_decl_starlen_ (ffelexToken t);
+static ffelexHandler ffestb_decl_starlen_1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_decl_typeparams_ (ffelexToken t);
+static ffelexHandler ffestb_decl_typeparams_1_ (ffelexToken t);
+static ffelexHandler ffestb_decl_typeparams_2_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_decl_typeparams_3_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+#if FFESTR_F90
+static ffelexHandler ffestb_decl_typetype1_ (ffelexToken t);
+static ffelexHandler ffestb_decl_typetype2_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_subr_label_list_ (ffelexToken t);
+static ffelexHandler ffestb_subr_label_list_1_ (ffelexToken t);
+static ffelexHandler ffestb_do1_ (ffelexToken t);
+static ffelexHandler ffestb_do2_ (ffelexToken t);
+static ffelexHandler ffestb_do3_ (ffelexToken t);
+static ffelexHandler ffestb_do4_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_do5_ (ffelexToken t);
+static ffelexHandler ffestb_do6_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_do7_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_do8_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_do9_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_else1_ (ffelexToken t);
+static ffelexHandler ffestb_else2_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_else3_ (ffelexToken t);
+static ffelexHandler ffestb_else4_ (ffelexToken t);
+static ffelexHandler ffestb_else5_ (ffelexToken t);
+static ffelexHandler ffestb_end1_ (ffelexToken t);
+static ffelexHandler ffestb_end2_ (ffelexToken t);
+static ffelexHandler ffestb_end3_ (ffelexToken t);
+static ffelexHandler ffestb_goto1_ (ffelexToken t);
+static ffelexHandler ffestb_goto2_ (ffelexToken t);
+static ffelexHandler ffestb_goto3_ (ffelexToken t);
+static ffelexHandler ffestb_goto4_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_goto5_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_goto6_ (ffelexToken t);
+static ffelexHandler ffestb_goto7_ (ffelexToken t);
+static ffelexHandler ffestb_halt1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_if1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_if2_ (ffelexToken t);
+static ffelexHandler ffestb_if3_ (ffelexToken t);
+static ffelexHandler ffestb_let1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_let2_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+#if FFESTR_F90
+static ffelexHandler ffestb_type1_ (ffelexToken t);
+static ffelexHandler ffestb_type2_ (ffelexToken t);
+static ffelexHandler ffestb_type3_ (ffelexToken t);
+static ffelexHandler ffestb_type4_ (ffelexToken t);
+#endif
+#if FFESTR_F90
+static ffelexHandler ffestb_varlist1_ (ffelexToken t);
+static ffelexHandler ffestb_varlist2_ (ffelexToken t);
+static ffelexHandler ffestb_varlist3_ (ffelexToken t);
+static ffelexHandler ffestb_varlist4_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_varlist5_ (ffelexToken t);
+static ffelexHandler ffestb_varlist6_ (ffelexToken t);
+#if FFESTR_F90
+static ffelexHandler ffestb_where1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_where2_ (ffelexToken t);
+static ffelexHandler ffestb_where3_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_R5221_ (ffelexToken t);
+static ffelexHandler ffestb_R5222_ (ffelexToken t);
+static ffelexHandler ffestb_R5223_ (ffelexToken t);
+static ffelexHandler ffestb_R5224_ (ffelexToken t);
+static ffelexHandler ffestb_R5281_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R5282_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R5283_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R5284_ (ffelexToken t);
+static ffelexHandler ffestb_R5371_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R5372_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R5373_ (ffelexToken t);
+static ffelexHandler ffestb_R5421_ (ffelexToken t);
+static ffelexHandler ffestb_R5422_ (ffelexToken t);
+static ffelexHandler ffestb_R5423_ (ffelexToken t);
+static ffelexHandler ffestb_R5424_ (ffelexToken t);
+static ffelexHandler ffestb_R5425_ (ffelexToken t);
+static ffelexHandler ffestb_R5441_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R5442_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R5443_ (ffelexToken t);
+static ffelexHandler ffestb_R5444_ (ffelexToken t);
+static ffelexHandler ffestb_R8341_ (ffelexToken t);
+static ffelexHandler ffestb_R8351_ (ffelexToken t);
+static ffelexHandler ffestb_R8381_ (ffelexToken t);
+static ffelexHandler ffestb_R8382_ (ffelexToken t);
+static ffelexHandler ffestb_R8383_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R8401_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R8402_ (ffelexToken t);
+static ffelexHandler ffestb_R8403_ (ffelexToken t);
+static ffelexHandler ffestb_R8404_ (ffelexToken t);
+static ffelexHandler ffestb_R8405_ (ffelexToken t);
+static ffelexHandler ffestb_R8406_ (ffelexToken t);
+static ffelexHandler ffestb_R8407_ (ffelexToken t);
+static ffelexHandler ffestb_R11021_ (ffelexToken t);
+static ffelexHandler ffestb_R1111_1_ (ffelexToken t);
+static ffelexHandler ffestb_R1111_2_ (ffelexToken t);
+static ffelexHandler ffestb_R12121_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R12271_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_construct1_ (ffelexToken t);
+static ffelexHandler ffestb_construct2_ (ffelexToken t);
+#if FFESTR_F90
+static ffelexHandler ffestb_heap1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_heap2_ (ffelexToken t);
+static ffelexHandler ffestb_heap3_ (ffelexToken t);
+static ffelexHandler ffestb_heap4_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_heap5_ (ffelexToken t);
+#endif
+#if FFESTR_F90
+static ffelexHandler ffestb_module1_ (ffelexToken t);
+static ffelexHandler ffestb_module2_ (ffelexToken t);
+static ffelexHandler ffestb_module3_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_R8091_ (ffelexToken t);
+static ffelexHandler ffestb_R8092_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R8093_ (ffelexToken t);
+static ffelexHandler ffestb_R8101_ (ffelexToken t);
+static ffelexHandler ffestb_R8102_ (ffelexToken t);
+static ffelexHandler ffestb_R8103_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R8104_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R10011_ (ffelexToken t);
+static ffelexHandler ffestb_R10012_ (ffelexToken t);
+static ffelexHandler ffestb_R10013_ (ffelexToken t);
+static ffelexHandler ffestb_R10014_ (ffelexToken t);
+static ffelexHandler ffestb_R10015_ (ffelexToken t);
+static ffelexHandler ffestb_R10016_ (ffelexToken t);
+static ffelexHandler ffestb_R10017_ (ffelexToken t);
+static ffelexHandler ffestb_R10018_ (ffelexToken t);
+static ffelexHandler ffestb_R10019_ (ffelexToken t);
+static ffelexHandler ffestb_R100110_ (ffelexToken t);
+static ffelexHandler ffestb_R100111_ (ffelexToken t);
+static ffelexHandler ffestb_R100112_ (ffelexToken t);
+static ffelexHandler ffestb_R100113_ (ffelexToken t);
+static ffelexHandler ffestb_R100114_ (ffelexToken t);
+static ffelexHandler ffestb_R100115_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R100116_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R100117_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R100118_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+#if FFESTR_F90
+static ffelexHandler ffestb_R11071_ (ffelexToken t);
+static ffelexHandler ffestb_R11072_ (ffelexToken t);
+static ffelexHandler ffestb_R11073_ (ffelexToken t);
+static ffelexHandler ffestb_R11074_ (ffelexToken t);
+static ffelexHandler ffestb_R11075_ (ffelexToken t);
+static ffelexHandler ffestb_R11076_ (ffelexToken t);
+static ffelexHandler ffestb_R11077_ (ffelexToken t);
+static ffelexHandler ffestb_R11078_ (ffelexToken t);
+static ffelexHandler ffestb_R11079_ (ffelexToken t);
+static ffelexHandler ffestb_R110710_ (ffelexToken t);
+static ffelexHandler ffestb_R110711_ (ffelexToken t);
+static ffelexHandler ffestb_R110712_ (ffelexToken t);
+#endif
+#if FFESTR_F90
+static ffelexHandler ffestb_R12021_ (ffelexToken t);
+static ffelexHandler ffestb_R12022_ (ffelexToken t);
+static ffelexHandler ffestb_R12023_ (ffelexToken t);
+static ffelexHandler ffestb_R12024_ (ffelexToken t);
+static ffelexHandler ffestb_R12025_ (ffelexToken t);
+static ffelexHandler ffestb_R12026_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_S3P41_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0141_ (ffelexToken t);
+static ffelexHandler ffestb_V0142_ (ffelexToken t);
+static ffelexHandler ffestb_V0143_ (ffelexToken t);
+static ffelexHandler ffestb_V0144_ (ffelexToken t);
+#if FFESTR_VXT
+static ffelexHandler ffestb_V0251_ (ffelexToken t);
+static ffelexHandler ffestb_V0252_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0253_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0254_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0255_ (ffelexToken t);
+static ffelexHandler ffestb_V0256_ (ffelexToken t);
+static ffelexHandler ffestb_V0257_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0258_ (ffelexToken t);
+#endif
+#if FFESTB_KILL_EASY_
+static void ffestb_subr_kill_easy_ (ffestpInquireIx max);
+#else
+static void ffestb_subr_kill_accept_ (void);
+static void ffestb_subr_kill_beru_ (void);
+static void ffestb_subr_kill_close_ (void);
+static void ffestb_subr_kill_delete_ (void);
+static void ffestb_subr_kill_find_ (void); /* Not written yet. */
+static void ffestb_subr_kill_inquire_ (void);
+static void ffestb_subr_kill_open_ (void);
+static void ffestb_subr_kill_print_ (void);
+static void ffestb_subr_kill_read_ (void);
+static void ffestb_subr_kill_rewrite_ (void);
+static void ffestb_subr_kill_type_ (void);
+static void ffestb_subr_kill_vxtcode_ (void); /* Not written yet. */
+static void ffestb_subr_kill_write_ (void);
+#endif
+static ffelexHandler ffestb_beru1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_beru2_ (ffelexToken t);
+static ffelexHandler ffestb_beru3_ (ffelexToken t);
+static ffelexHandler ffestb_beru4_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_beru5_ (ffelexToken t);
+static ffelexHandler ffestb_beru6_ (ffelexToken t);
+static ffelexHandler ffestb_beru7_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_beru8_ (ffelexToken t);
+static ffelexHandler ffestb_beru9_ (ffelexToken t);
+static ffelexHandler ffestb_beru10_ (ffelexToken t);
+#if FFESTR_VXT
+static ffelexHandler ffestb_vxtcode1_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_vxtcode2_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_vxtcode3_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_vxtcode4_ (ffelexToken t);
+static ffelexHandler ffestb_vxtcode5_ (ffelexToken t);
+static ffelexHandler ffestb_vxtcode6_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_vxtcode7_ (ffelexToken t);
+static ffelexHandler ffestb_vxtcode8_ (ffelexToken t);
+static ffelexHandler ffestb_vxtcode9_ (ffelexToken t);
+static ffelexHandler ffestb_vxtcode10_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+#endif
+static ffelexHandler ffestb_R9041_ (ffelexToken t);
+static ffelexHandler ffestb_R9042_ (ffelexToken t);
+static ffelexHandler ffestb_R9043_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9044_ (ffelexToken t);
+static ffelexHandler ffestb_R9045_ (ffelexToken t);
+static ffelexHandler ffestb_R9046_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9047_ (ffelexToken t);
+static ffelexHandler ffestb_R9048_ (ffelexToken t);
+static ffelexHandler ffestb_R9049_ (ffelexToken t);
+static ffelexHandler ffestb_R9071_ (ffelexToken t);
+static ffelexHandler ffestb_R9072_ (ffelexToken t);
+static ffelexHandler ffestb_R9073_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9074_ (ffelexToken t);
+static ffelexHandler ffestb_R9075_ (ffelexToken t);
+static ffelexHandler ffestb_R9076_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9077_ (ffelexToken t);
+static ffelexHandler ffestb_R9078_ (ffelexToken t);
+static ffelexHandler ffestb_R9079_ (ffelexToken t);
+static ffelexHandler ffestb_R9091_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9092_ (ffelexToken t);
+static ffelexHandler ffestb_R9093_ (ffelexToken t);
+static ffelexHandler ffestb_R9094_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9095_ (ffelexToken t);
+static ffelexHandler ffestb_R9096_ (ffelexToken t);
+static ffelexHandler ffestb_R9097_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9098_ (ffelexToken t);
+static ffelexHandler ffestb_R9099_ (ffelexToken t);
+static ffelexHandler ffestb_R90910_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R90911_ (ffelexToken t);
+static ffelexHandler ffestb_R90912_ (ffelexToken t);
+static ffelexHandler ffestb_R90913_ (ffelexToken t);
+static ffelexHandler ffestb_R90914_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R90915_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9101_ (ffelexToken t);
+static ffelexHandler ffestb_R9102_ (ffelexToken t);
+static ffelexHandler ffestb_R9103_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9104_ (ffelexToken t);
+static ffelexHandler ffestb_R9105_ (ffelexToken t);
+static ffelexHandler ffestb_R9106_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9107_ (ffelexToken t);
+static ffelexHandler ffestb_R9108_ (ffelexToken t);
+static ffelexHandler ffestb_R9109_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R91010_ (ffelexToken t);
+static ffelexHandler ffestb_R91011_ (ffelexToken t);
+static ffelexHandler ffestb_R91012_ (ffelexToken t);
+static ffelexHandler ffestb_R91013_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R91014_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9111_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9112_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9231_ (ffelexToken t);
+static ffelexHandler ffestb_R9232_ (ffelexToken t);
+static ffelexHandler ffestb_R9233_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9234_ (ffelexToken t);
+static ffelexHandler ffestb_R9235_ (ffelexToken t);
+static ffelexHandler ffestb_R9236_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R9237_ (ffelexToken t);
+static ffelexHandler ffestb_R9238_ (ffelexToken t);
+static ffelexHandler ffestb_R9239_ (ffelexToken t);
+static ffelexHandler ffestb_R92310_ (ffelexToken t);
+static ffelexHandler ffestb_R92311_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+#if FFESTR_VXT
+static ffelexHandler ffestb_V0181_ (ffelexToken t);
+static ffelexHandler ffestb_V0182_ (ffelexToken t);
+static ffelexHandler ffestb_V0183_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0184_ (ffelexToken t);
+static ffelexHandler ffestb_V0185_ (ffelexToken t);
+static ffelexHandler ffestb_V0186_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0187_ (ffelexToken t);
+static ffelexHandler ffestb_V0188_ (ffelexToken t);
+static ffelexHandler ffestb_V0189_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V01810_ (ffelexToken t);
+static ffelexHandler ffestb_V01811_ (ffelexToken t);
+static ffelexHandler ffestb_V01812_ (ffelexToken t);
+static ffelexHandler ffestb_V01813_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0191_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0192_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+#endif
+static ffelexHandler ffestb_V0201_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0202_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+#if FFESTR_VXT
+static ffelexHandler ffestb_V0211_ (ffelexToken t);
+static ffelexHandler ffestb_V0212_ (ffelexToken t);
+static ffelexHandler ffestb_V0213_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0214_ (ffelexToken t);
+static ffelexHandler ffestb_V0215_ (ffelexToken t);
+static ffelexHandler ffestb_V0216_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0217_ (ffelexToken t);
+static ffelexHandler ffestb_V0218_ (ffelexToken t);
+static ffelexHandler ffestb_V0219_ (ffelexToken t);
+static ffelexHandler ffestb_V0261_ (ffelexToken t);
+static ffelexHandler ffestb_V0262_ (ffelexToken t);
+static ffelexHandler ffestb_V0263_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0264_ (ffelexToken t);
+static ffelexHandler ffestb_V0265_ (ffelexToken t);
+static ffelexHandler ffestb_V0266_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0267_ (ffelexToken t);
+static ffelexHandler ffestb_V0268_ (ffelexToken t);
+static ffelexHandler ffestb_V0269_ (ffelexToken t);
+#endif
+#if FFESTR_F90
+static ffelexHandler ffestb_dimlist1_ (ffelexToken t);
+static ffelexHandler ffestb_dimlist2_ (ffelexToken t);
+static ffelexHandler ffestb_dimlist3_ (ffelexToken t);
+static ffelexHandler ffestb_dimlist4_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_dummy1_ (ffelexToken t);
+static ffelexHandler ffestb_dummy2_ (ffelexToken t);
+static ffelexHandler ffestb_R5241_ (ffelexToken t);
+static ffelexHandler ffestb_R5242_ (ffelexToken t);
+static ffelexHandler ffestb_R5243_ (ffelexToken t);
+static ffelexHandler ffestb_R5244_ (ffelexToken t);
+static ffelexHandler ffestb_R5471_ (ffelexToken t);
+static ffelexHandler ffestb_R5472_ (ffelexToken t);
+static ffelexHandler ffestb_R5473_ (ffelexToken t);
+static ffelexHandler ffestb_R5474_ (ffelexToken t);
+static ffelexHandler ffestb_R5475_ (ffelexToken t);
+static ffelexHandler ffestb_R5476_ (ffelexToken t);
+static ffelexHandler ffestb_R5477_ (ffelexToken t);
+#if FFESTR_F90
+static ffelexHandler ffestb_R6241_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_R6242_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_R12291_ (ffelexToken t);
+static ffelexHandler ffestb_R12292_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_decl_chartype1_ (ffelexToken t);
+#if FFESTR_F90
+static ffelexHandler ffestb_decl_recursive1_ (ffelexToken t);
+static ffelexHandler ffestb_decl_recursive2_ (ffelexToken t);
+static ffelexHandler ffestb_decl_recursive3_ (ffelexToken t);
+static ffelexHandler ffestb_decl_recursive4_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_decl_attrs_ (ffelexToken t);
+static ffelexHandler ffestb_decl_attrs_1_ (ffelexToken t);
+static ffelexHandler ffestb_decl_attrs_2_ (ffelexToken t);
+#if FFESTR_F90
+static ffelexHandler ffestb_decl_attrs_3_ (ffelexToken t);
+static ffelexHandler ffestb_decl_attrs_4_ (ffelexToken t);
+static ffelexHandler ffestb_decl_attrs_5_ (ffelexToken t);
+static ffelexHandler ffestb_decl_attrs_6_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_decl_attrs_7_ (ffelexToken t);
+static ffelexHandler ffestb_decl_attrsp_ (ffelexToken t);
+static ffelexHandler ffestb_decl_ents_ (ffelexToken t);
+static ffelexHandler ffestb_decl_ents_1_ (ffelexToken t);
+static ffelexHandler ffestb_decl_ents_2_ (ffelexToken t);
+static ffelexHandler ffestb_decl_ents_3_ (ffelexToken t);
+static ffelexHandler ffestb_decl_ents_4_ (ffelexToken t);
+static ffelexHandler ffestb_decl_ents_5_ (ffelexToken t);
+static ffelexHandler ffestb_decl_ents_6_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_decl_ents_7_ (ffelexToken t);
+static ffelexHandler ffestb_decl_ents_8_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_decl_ents_9_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_decl_ents_10_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_decl_ents_11_ (ffelexToken t);
+static ffelexHandler ffestb_decl_entsp_ (ffelexToken t);
+static ffelexHandler ffestb_decl_entsp_1_ (ffelexToken t);
+static ffelexHandler ffestb_decl_entsp_2_ (ffelexToken t);
+static ffelexHandler ffestb_decl_entsp_3_ (ffelexToken t);
+static ffelexHandler ffestb_decl_entsp_4_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_decl_entsp_5_ (ffelexToken t);
+static ffelexHandler ffestb_decl_entsp_6_ (ffelexToken t);
+static ffelexHandler ffestb_decl_entsp_7_ (ffelexToken t);
+static ffelexHandler ffestb_decl_entsp_8_ (ffelexToken t);
+#if FFESTR_F90
+static ffelexHandler ffestb_decl_func_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_decl_funcname_ (ffelexToken t);
+static ffelexHandler ffestb_decl_funcname_1_ (ffelexToken t);
+static ffelexHandler ffestb_decl_funcname_2_ (ffelexToken t);
+static ffelexHandler ffestb_decl_funcname_3_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_decl_funcname_4_ (ffelexToken t);
+static ffelexHandler ffestb_decl_funcname_5_ (ffelexToken t);
+static ffelexHandler ffestb_decl_funcname_6_ (ffelexToken t);
+static ffelexHandler ffestb_decl_funcname_7_ (ffelexToken t);
+static ffelexHandler ffestb_decl_funcname_8_ (ffelexToken t);
+static ffelexHandler ffestb_decl_funcname_9_ (ffelexToken t);
+#if FFESTR_VXT
+static ffelexHandler ffestb_V0031_ (ffelexToken t);
+static ffelexHandler ffestb_V0032_ (ffelexToken t);
+static ffelexHandler ffestb_V0033_ (ffelexToken t);
+static ffelexHandler ffestb_V0034_ (ffelexToken t);
+static ffelexHandler ffestb_V0035_ (ffelexToken t);
+static ffelexHandler ffestb_V0036_ (ffelexToken t);
+static ffelexHandler ffestb_V0161_ (ffelexToken t);
+static ffelexHandler ffestb_V0162_ (ffelexToken t);
+static ffelexHandler ffestb_V0163_ (ffelexToken t);
+static ffelexHandler ffestb_V0164_ (ffelexToken t);
+static ffelexHandler ffestb_V0165_ (ffelexToken t);
+static ffelexHandler ffestb_V0166_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_V0271_ (ffelexToken t);
+static ffelexHandler ffestb_V0272_ (ffelexToken ft, ffebld expr,
+ ffelexToken t);
+static ffelexHandler ffestb_V0273_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R5391_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R5392_ (ffelexToken t);
+#if FFESTR_F90
+static ffelexHandler ffestb_decl_R5393_ (ffelexToken t);
+#endif
+static ffelexHandler ffestb_decl_R5394_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R5395_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539letters_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539letters_1_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539letters_2_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539letters_3_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539letters_4_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539letters_5_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539maybe_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539maybe_1_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539maybe_2_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539maybe_3_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539maybe_4_ (ffelexToken t);
+static ffelexHandler ffestb_decl_R539maybe_5_ (ffelexToken t);
+
+/* Internal macros. */
+
+#if FFESTB_KILL_EASY_
+#define ffestb_subr_kill_accept_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_acceptix)
+#define ffestb_subr_kill_beru_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_beruix)
+#define ffestb_subr_kill_close_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_closeix)
+#define ffestb_subr_kill_delete_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_deleteix)
+#define ffestb_subr_kill_find_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_findix)
+#define ffestb_subr_kill_inquire_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_inquireix)
+#define ffestb_subr_kill_open_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_openix)
+#define ffestb_subr_kill_print_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_printix)
+#define ffestb_subr_kill_read_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_readix)
+#define ffestb_subr_kill_rewrite_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_rewriteix)
+#define ffestb_subr_kill_type_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_typeix)
+#define ffestb_subr_kill_vxtcode_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_vxtcodeix)
+#define ffestb_subr_kill_write_() \
+ ffestb_subr_kill_easy_((ffestpInquireIx) FFESTP_writeix)
+#endif
+
+/* ffestb_subr_ambig_nope_ -- Cleans up and aborts ambig w/o confirming
+
+ ffestb_subr_ambig_nope_();
+
+ Switch from ambiguity handling in _entsp_ functions to handling entities
+ in _ents_ (perform housekeeping tasks). */
+
+static ffelexHandler
+ffestb_subr_ambig_nope_ (ffelexToken t)
+{
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_subr_ambig_to_ents_ -- Switches from ambiguity to entity decl
+
+ ffestb_subr_ambig_to_ents_();
+
+ Switch from ambiguity handling in _entsp_ functions to handling entities
+ in _ents_ (perform housekeeping tasks). */
+
+static void
+ffestb_subr_ambig_to_ents_ ()
+{
+ ffelexToken nt;
+
+ nt = ffelex_token_name_from_names (ffesta_tokens[1], 0, 0);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_tokens[1] = nt;
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (!ffestb_local_.decl.aster_after)
+ {
+ if (ffestb_local_.decl.type == FFESTP_typeCHARACTER)
+ {
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ ffestb_local_.decl.kind, ffestb_local_.decl.kindt,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.kindt != NULL)
+ {
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ }
+ if (ffestb_local_.decl.lent != NULL)
+ {
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ }
+ }
+ else
+ {
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ ffestb_local_.decl.kind, ffestb_local_.decl.kindt, NULL,
+ NULL);
+ if (ffestb_local_.decl.kindt != NULL)
+ {
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ }
+ }
+ return;
+ }
+ if (ffestb_local_.decl.type == FFESTP_typeCHARACTER)
+ {
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ ffestb_local_.decl.kind, ffestb_local_.decl.kindt, NULL, NULL);
+ if (ffestb_local_.decl.kindt != NULL)
+ {
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ }
+ }
+ else if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ /* NAME/NAMES token already in ffesta_tokens[1]. */
+}
+
+/* ffestb_subr_dimlist_ -- OPEN_PAREN expr
+
+ (ffestb_subr_dimlist_) // to expression handler
+
+ Deal with a dimension list.
+
+ 19-Dec-90 JCB 1.1
+ Detect too many dimensions if backend wants it. */
+
+static ffelexHandler
+ffestb_subr_dimlist_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+#ifdef FFECOM_dimensionsMAX
+ if (ffestb_subrargs_.dim_list.ndims++ == FFECOM_dimensionsMAX)
+ {
+ ffesta_ffebad_1t (FFEBAD_TOO_MANY_DIMS, ft);
+ ffestb_subrargs_.dim_list.ok = TRUE; /* Not a parse error, really. */
+ return (ffelexHandler) ffestb_subrargs_.dim_list.handler;
+ }
+#endif
+ ffestt_dimlist_append (ffestb_subrargs_.dim_list.dims, NULL, expr,
+ ffelex_token_use (t));
+ ffestb_subrargs_.dim_list.ok = TRUE;
+ return (ffelexHandler) ffestb_subrargs_.dim_list.handler;
+
+ case FFELEX_typeCOMMA:
+ if ((expr != NULL) && (ffebld_op (expr) == FFEBLD_opSTAR))
+ break;
+#ifdef FFECOM_dimensionsMAX
+ if (ffestb_subrargs_.dim_list.ndims++ == FFECOM_dimensionsMAX)
+ {
+ ffesta_ffebad_1t (FFEBAD_TOO_MANY_DIMS, ft);
+ return (ffelexHandler) ffeexpr_rhs (ffestb_subrargs_.dim_list.pool,
+ ffestb_subrargs_.dim_list.ctx,
+ (ffeexprCallback) ffestb_subr_dimlist_2_);
+ }
+#endif
+ ffestt_dimlist_append (ffestb_subrargs_.dim_list.dims, NULL, expr,
+ ffelex_token_use (t));
+ return (ffelexHandler) ffeexpr_rhs (ffestb_subrargs_.dim_list.pool,
+ ffestb_subrargs_.dim_list.ctx,
+ (ffeexprCallback) ffestb_subr_dimlist_);
+
+ case FFELEX_typeCOLON:
+ if ((expr != NULL) && (ffebld_op (expr) == FFEBLD_opSTAR))
+ break;
+#ifdef FFECOM_dimensionsMAX
+ if (ffestb_subrargs_.dim_list.ndims++ == FFECOM_dimensionsMAX)
+ {
+ ffesta_ffebad_1t (FFEBAD_TOO_MANY_DIMS, ft);
+ return (ffelexHandler) ffeexpr_rhs (ffestb_subrargs_.dim_list.pool,
+ ffestb_subrargs_.dim_list.ctx,
+ (ffeexprCallback) ffestb_subr_dimlist_2_);
+ }
+#endif
+ ffestt_dimlist_append (ffestb_subrargs_.dim_list.dims, expr, NULL,
+ ffelex_token_use (t)); /* NULL second expr for
+ now, just plug in. */
+ return (ffelexHandler) ffeexpr_rhs (ffestb_subrargs_.dim_list.pool,
+ ffestb_subrargs_.dim_list.ctx,
+ (ffeexprCallback) ffestb_subr_dimlist_1_);
+
+ default:
+ break;
+ }
+
+ ffestb_subrargs_.dim_list.ok = FALSE;
+ return (ffelexHandler) ffestb_subrargs_.dim_list.handler (t);
+}
+
+/* ffestb_subr_dimlist_1_ -- OPEN_PAREN expr COLON expr
+
+ (ffestb_subr_dimlist_1_) // to expression handler
+
+ Get the upper bound. */
+
+static ffelexHandler
+ffestb_subr_dimlist_1_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffestb_subrargs_.dim_list.dims->previous->upper = expr;
+ ffestb_subrargs_.dim_list.ok = TRUE;
+ return (ffelexHandler) ffestb_subrargs_.dim_list.handler;
+
+ case FFELEX_typeCOMMA:
+ if ((expr != NULL) && (ffebld_op (expr) == FFEBLD_opSTAR))
+ break;
+ ffestb_subrargs_.dim_list.dims->previous->upper = expr;
+ return (ffelexHandler) ffeexpr_rhs (ffestb_subrargs_.dim_list.pool,
+ ffestb_subrargs_.dim_list.ctx, (ffeexprCallback) ffestb_subr_dimlist_);
+
+ default:
+ break;
+ }
+
+ ffestb_subrargs_.dim_list.ok = FALSE;
+ return (ffelexHandler) ffestb_subrargs_.dim_list.handler (t);
+}
+
+/* ffestb_subr_dimlist_2_ -- OPEN_PAREN too-many-dim-exprs
+
+ (ffestb_subr_dimlist_2_) // to expression handler
+
+ Get the upper bound. */
+
+static ffelexHandler
+ffestb_subr_dimlist_2_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffestb_subrargs_.dim_list.ok = TRUE; /* Not a parse error, really. */
+ return (ffelexHandler) ffestb_subrargs_.dim_list.handler;
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLON:
+ if ((expr != NULL) && (ffebld_op (expr) == FFEBLD_opSTAR))
+ break;
+ return (ffelexHandler) ffeexpr_rhs (ffestb_subrargs_.dim_list.pool,
+ ffestb_subrargs_.dim_list.ctx,
+ (ffeexprCallback) ffestb_subr_dimlist_2_);
+
+ default:
+ break;
+ }
+
+ ffestb_subrargs_.dim_list.ok = FALSE;
+ return (ffelexHandler) ffestb_subrargs_.dim_list.handler (t);
+}
+
+/* ffestb_subr_name_list_ -- Collect a list of name args and close-paren
+
+ return ffestb_subr_name_list_; // to lexer after seeing OPEN_PAREN
+
+ This implements R1224 in the Fortran 90 spec. The arg list may be
+ empty, or be a comma-separated list (an optional trailing comma currently
+ results in a warning but no other effect) of arguments. For functions,
+ however, "*" is invalid (we implement dummy-arg-name, rather than R1224
+ dummy-arg, which itself is either dummy-arg-name or "*"). */
+
+static ffelexHandler
+ffestb_subr_name_list_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (ffestt_tokenlist_count (ffestb_subrargs_.name_list.args) != 0)
+ { /* Trailing comma, warn. */
+ ffebad_start (FFEBAD_TRAILING_COMMA);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ ffestb_subrargs_.name_list.ok = TRUE;
+ ffestb_subrargs_.name_list.close_paren = ffelex_token_use (t);
+ if (ffestb_subrargs_.name_list.names)
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_subrargs_.name_list.handler;
+
+ case FFELEX_typeASTERISK:
+ if (!ffestb_subrargs_.name_list.is_subr)
+ break;
+
+ case FFELEX_typeNAME:
+ ffestt_tokenlist_append (ffestb_subrargs_.name_list.args,
+ ffelex_token_use (t));
+ return (ffelexHandler) ffestb_subr_name_list_1_;
+
+ default:
+ break;
+ }
+
+ ffestb_subrargs_.name_list.ok = FALSE;
+ ffestb_subrargs_.name_list.close_paren = ffelex_token_use (t);
+ if (ffestb_subrargs_.name_list.names)
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) (*ffestb_subrargs_.name_list.handler) (t);
+}
+
+/* ffestb_subr_name_list_1_ -- NAME or ASTERISK
+
+ return ffestb_subr_name_list_1_; // to lexer
+
+ The next token must be COMMA or CLOSE_PAREN, either way go to original
+ state, but only after adding the appropriate name list item. */
+
+static ffelexHandler
+ffestb_subr_name_list_1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_subr_name_list_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ ffestb_subrargs_.name_list.ok = TRUE;
+ ffestb_subrargs_.name_list.close_paren = ffelex_token_use (t);
+ if (ffestb_subrargs_.name_list.names)
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_subrargs_.name_list.handler;
+
+ default:
+ ffestb_subrargs_.name_list.ok = FALSE;
+ ffestb_subrargs_.name_list.close_paren = ffelex_token_use (t);
+ if (ffestb_subrargs_.name_list.names)
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) (*ffestb_subrargs_.name_list.handler) (t);
+ }
+}
+
+static void
+ffestb_subr_R1001_append_p_ (void)
+{
+ ffesttFormatList f;
+
+ if (!ffestb_local_.format.pre.present)
+ {
+ ffesta_ffebad_1t (FFEBAD_FORMAT_BAD_P_SPEC, ffestb_local_.format.t);
+ ffelex_token_kill (ffestb_local_.format.t);
+ return;
+ }
+
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeP;
+ f->t = ffestb_local_.format.t;
+ f->u.R1010.val = ffestb_local_.format.pre;
+}
+
+/* ffestb_decl_kindparam_ -- "type" OPEN_PAREN
+
+ return ffestb_decl_kindparam_; // to lexer
+
+ Handle "[KIND=]expr)". */
+
+static ffelexHandler
+ffestb_decl_kindparam_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_kindparam_1_;
+
+ default:
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextKINDTYPE,
+ (ffeexprCallback) ffestb_decl_kindparam_2_)))
+ (t);
+ }
+}
+
+/* ffestb_decl_kindparam_1_ -- "type" OPEN_PAREN NAME
+
+ return ffestb_decl_kindparam_1_; // to lexer
+
+ Handle "[KIND=]expr)". */
+
+static ffelexHandler
+ffestb_decl_kindparam_1_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestr_other (ffesta_tokens[1]) != FFESTR_otherKIND)
+ break;
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextKINDTYPE, (ffeexprCallback) ffestb_decl_kindparam_2_);
+
+ default:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextKINDTYPE, (ffeexprCallback) ffestb_decl_kindparam_2_)))
+ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_kindparam_2_ -- "type" OPEN_PAREN ["KIND="] expr
+
+ (ffestb_decl_kindparam_2_) // to expression handler
+
+ Handle "[KIND=]expr)". */
+
+static ffelexHandler
+ffestb_decl_kindparam_2_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffestb_local_.decl.kind = expr;
+ ffestb_local_.decl.kindt = ffelex_token_use (ft);
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_local_.decl.handler;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_starkind_ -- "type" ASTERISK
+
+ return ffestb_decl_starkind_; // to lexer
+
+ Handle NUMBER. */
+
+static ffelexHandler
+ffestb_decl_starkind_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestb_local_.decl.kindt = ffelex_token_use (t);
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_local_.decl.handler;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_starlen_ -- "CHARACTER" ASTERISK
+
+ return ffestb_decl_starlen_; // to lexer
+
+ Handle NUMBER. */
+
+static ffelexHandler
+ffestb_decl_starlen_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = ffelex_token_use (t);
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_local_.decl.handler;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCHARACTERSIZE,
+ (ffeexprCallback) ffestb_decl_starlen_1_);
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_starlen_1_ -- "CHARACTER" ASTERISK OPEN_PAREN expr
+
+ (ffestb_decl_starlen_1_) // to expression handler
+
+ Handle CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_decl_starlen_1_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestb_local_.decl.len = expr;
+ ffestb_local_.decl.lent = ffelex_token_use (ft);
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_local_.decl.handler;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_typeparams_ -- "CHARACTER" OPEN_PAREN
+
+ return ffestb_decl_typeparams_; // to lexer
+
+ Handle "[KIND=]expr)". */
+
+static ffelexHandler
+ffestb_decl_typeparams_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_typeparams_1_;
+
+ default:
+ if (ffestb_local_.decl.lent == NULL)
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCHARACTERSIZE,
+ (ffeexprCallback) ffestb_decl_typeparams_2_)))
+ (t);
+ if (ffestb_local_.decl.kindt != NULL)
+ break;
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextKINDTYPE,
+ (ffeexprCallback) ffestb_decl_typeparams_3_)))
+ (t);
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_typeparams_1_ -- "CHARACTER" OPEN_PAREN NAME
+
+ return ffestb_decl_typeparams_1_; // to lexer
+
+ Handle "[KIND=]expr)". */
+
+static ffelexHandler
+ffestb_decl_typeparams_1_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ switch (ffestr_other (ffesta_tokens[1]))
+ {
+ case FFESTR_otherLEN:
+ if (ffestb_local_.decl.lent != NULL)
+ break;
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCHARACTERSIZE,
+ (ffeexprCallback) ffestb_decl_typeparams_2_);
+
+ case FFESTR_otherKIND:
+ if (ffestb_local_.decl.kindt != NULL)
+ break;
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextKINDTYPE,
+ (ffeexprCallback) ffestb_decl_typeparams_3_);
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ nt = ffesta_tokens[1];
+ if (ffestb_local_.decl.lent == NULL)
+ next = (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCHARACTERSIZE,
+ (ffeexprCallback) ffestb_decl_typeparams_2_)))
+ (nt);
+ else if (ffestb_local_.decl.kindt == NULL)
+ next = (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextKINDTYPE,
+ (ffeexprCallback) ffestb_decl_typeparams_3_)))
+ (nt);
+ else
+ {
+ ffesta_tokens[1] = nt;
+ break;
+ }
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_typeparams_2_ -- "CHARACTER" OPEN_PAREN ["LEN="] expr
+
+ (ffestb_decl_typeparams_2_) // to expression handler
+
+ Handle "[LEN=]expr)". */
+
+static ffelexHandler
+ffestb_decl_typeparams_2_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffestb_local_.decl.len = expr;
+ ffestb_local_.decl.lent = ffelex_token_use (ft);
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_local_.decl.handler;
+
+ case FFELEX_typeCOMMA:
+ ffestb_local_.decl.len = expr;
+ ffestb_local_.decl.lent = ffelex_token_use (ft);
+ return (ffelexHandler) ffestb_decl_typeparams_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_typeparams_3_ -- "CHARACTER" OPEN_PAREN ["KIND="] expr
+
+ (ffestb_decl_typeparams_3_) // to expression handler
+
+ Handle "[KIND=]expr)". */
+
+static ffelexHandler
+ffestb_decl_typeparams_3_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffestb_local_.decl.kind = expr;
+ ffestb_local_.decl.kindt = ffelex_token_use (ft);
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_local_.decl.handler;
+
+ case FFELEX_typeCOMMA:
+ ffestb_local_.decl.kind = expr;
+ ffestb_local_.decl.kindt = ffelex_token_use (ft);
+ return (ffelexHandler) ffestb_decl_typeparams_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_typetype1_ -- "TYPE" OPEN_PAREN
+
+ return ffestb_decl_typetype1_; // to lexer
+
+ Handle NAME. */
+
+#if FFESTR_F90
+static ffelexHandler
+ffestb_decl_typetype1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffestb_local_.decl.kindt = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_typetype2_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_typetype2_ -- "TYPE" OPEN_PAREN NAME
+
+ return ffestb_decl_typetype2_; // to lexer
+
+ Handle CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_decl_typetype2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffestb_local_.decl.type = FFESTP_typeTYPE;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_local_.decl.handler;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ ffestb_local_.decl.badname,
+ t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_subr_label_list_ -- Collect a tokenlist of labels and close-paren
+
+ return ffestb_subr_label_list_; // to lexer after seeing OPEN_PAREN
+
+ First token must be a NUMBER. Must be followed by zero or more COMMA
+ NUMBER pairs. Must then be followed by a CLOSE_PAREN. If all ok, put
+ the NUMBER tokens in a token list and return via the handler for the
+ token after CLOSE_PAREN. Else return via
+ same handler, but with the ok return value set FALSE. */
+
+static ffelexHandler
+ffestb_subr_label_list_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) == FFELEX_typeNUMBER)
+ {
+ ffestt_tokenlist_append (ffestb_subrargs_.label_list.labels,
+ ffelex_token_use (t));
+ return (ffelexHandler) ffestb_subr_label_list_1_;
+ }
+
+ ffestb_subrargs_.label_list.ok = FALSE;
+ return (ffelexHandler) (*ffestb_subrargs_.label_list.handler) (t);
+}
+
+/* ffestb_subr_label_list_1_ -- NUMBER
+
+ return ffestb_subr_label_list_1_; // to lexer after seeing NUMBER
+
+ The next token must be COMMA, in which case go back to
+ ffestb_subr_label_list_, or CLOSE_PAREN, in which case set ok to TRUE
+ and go to the handler. */
+
+static ffelexHandler
+ffestb_subr_label_list_1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_subr_label_list_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ ffestb_subrargs_.label_list.ok = TRUE;
+ return (ffelexHandler) ffestb_subrargs_.label_list.handler;
+
+ default:
+ ffestb_subrargs_.label_list.ok = FALSE;
+ return (ffelexHandler) (*ffestb_subrargs_.label_list.handler) (t);
+ }
+}
+
+/* ffestb_do -- Parse the DO statement
+
+ return ffestb_do; // to lexer
+
+ Make sure the statement has a valid form for the DO statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_do (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexHandler next;
+ ffelexToken nt;
+ ffestrSecond kw;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstDO)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_do1_;
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_do2_;
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = NULL;
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_do3_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_do1_ (t);
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstDO)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlDO);
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN: /* Must be "DO" label "WHILE". */
+ if (! ISDIGIT (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1] = ffelex_token_number_from_names (ffesta_tokens[0],
+ i);
+ p += ffelex_token_length (ffesta_tokens[1]);
+ i += ffelex_token_length (ffesta_tokens[1]);
+ if (((*p) != 'W') && ((*p) != 'w'))
+ goto bad_i1; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ kw = ffestr_second (nt);
+ ffelex_token_kill (nt);
+ if (kw != FFESTR_secondWHILE)
+ goto bad_i1; /* :::::::::::::::::::: */
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextDOWHILE, (ffeexprCallback) ffestb_do4_);
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (*p == '\0')
+ {
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_do2_;
+ }
+ if (! ISDIGIT (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1] = ffelex_token_number_from_names (ffesta_tokens[0],
+ i);
+ p += ffelex_token_length (ffesta_tokens[1]);
+ i += ffelex_token_length (ffesta_tokens[1]);
+ if (*p != '\0')
+ goto bad_i1; /* :::::::::::::::::::: */
+ return (ffelexHandler) ffestb_do2_;
+
+ case FFELEX_typeEQUALS:
+ if (ISDIGIT (*p))
+ {
+ ffesta_tokens[1]
+ = ffelex_token_number_from_names (ffesta_tokens[0], i);
+ p += ffelex_token_length (ffesta_tokens[1]);
+ i += ffelex_token_length (ffesta_tokens[1]);
+ }
+ else
+ ffesta_tokens[1] = NULL;
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i1; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_lhs
+ (ffesta_output_pool, FFEEXPR_contextDO,
+ (ffeexprCallback) ffestb_do6_)))
+ (nt);
+ ffelex_token_kill (nt); /* Will get it back in _6_... */
+ return (ffelexHandler) (*next) (t);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (ISDIGIT (*p))
+ {
+ ffesta_tokens[1]
+ = ffelex_token_number_from_names (ffesta_tokens[0], i);
+ p += ffelex_token_length (ffesta_tokens[1]);
+ i += ffelex_token_length (ffesta_tokens[1]);
+ }
+ else
+ ffesta_tokens[1] = NULL;
+ if (*p != '\0')
+ goto bad_i1; /* :::::::::::::::::::: */
+ return (ffelexHandler) ffestb_do1_ (t);
+ }
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i1: /* :::::::::::::::::::: */
+ if (ffesta_tokens[1])
+ ffelex_token_kill (ffesta_tokens[1]);
+
+bad_i: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "DO", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_dowhile -- Parse the DOWHILE statement
+
+ return ffestb_dowhile; // to lexer
+
+ Make sure the statement has a valid form for the DOWHILE statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_dowhile (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstDOWHILE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlDOWHILE);
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextDOWHILE, (ffeexprCallback) ffestb_do4_);
+
+ case FFELEX_typeEQUALS:/* Not really DOWHILE, but DOWHILExyz=.... */
+ ffesta_tokens[1] = NULL;
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], FFESTR_firstlDO,
+ 0);
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_lhs
+ (ffesta_output_pool, FFEEXPR_contextDO,
+ (ffeexprCallback) ffestb_do6_)))
+ (nt);
+ ffelex_token_kill (nt); /* Will get it back in _6_... */
+ return (ffelexHandler) (*next) (t);
+ }
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "DO", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_do1_ -- "DO" [label]
+
+ return ffestb_do1_; // to lexer
+
+ Make sure the statement has a valid form for the DO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_do1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ return (ffelexHandler) ffestb_do2_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffesta_tokens[1] != NULL)
+ ffestc_R819B (ffesta_construct_name, ffesta_tokens[1], NULL,
+ NULL);
+ else
+ ffestc_R820B (ffesta_construct_name, NULL, NULL);
+ }
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeNAME:
+ return (ffelexHandler) ffestb_do2_ (t);
+
+ default:
+ break;
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_do2_ -- "DO" [label] [,]
+
+ return ffestb_do2_; // to lexer
+
+ Make sure the statement has a valid form for the DO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_do2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_do3_;
+
+ default:
+ break;
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_do3_ -- "DO" [label] [,] NAME
+
+ return ffestb_do3_; // to lexer
+
+ Make sure the statement has a valid form for the DO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_do3_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextDO, (ffeexprCallback) ffestb_do6_)))
+ (ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[2]); /* Will get it back in _6_... */
+ return (ffelexHandler) (*next) (t);
+
+ case FFELEX_typeOPEN_PAREN:
+ if (ffestr_second (ffesta_tokens[2]) != FFESTR_secondWHILE)
+ {
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid token. */
+ }
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextDOWHILE, (ffeexprCallback) ffestb_do4_);
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[2]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_do4_ -- "DO" [label] [,] "WHILE" OPEN_PAREN expr
+
+ (ffestb_do4_) // to expression handler
+
+ Make sure the statement has a valid form for the DO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_do4_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[2] = ffelex_token_use (ft);
+ ffestb_local_.dowhile.expr = expr;
+ return (ffelexHandler) ffestb_do5_;
+
+ default:
+ break;
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_do5_ -- "DO" [label] [,] "WHILE" OPEN_PAREN expr CLOSE_PAREN
+
+ return ffestb_do5_; // to lexer
+
+ Make sure the statement has a valid form for the DO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_do5_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffesta_tokens[1] != NULL)
+ ffestc_R819B (ffesta_construct_name, ffesta_tokens[1],
+ ffestb_local_.dowhile.expr, ffesta_tokens[2]);
+ else
+ ffestc_R820B (ffesta_construct_name, ffestb_local_.dowhile.expr,
+ ffesta_tokens[2]);
+ }
+ ffelex_token_kill (ffesta_tokens[2]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[2]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_do6_ -- "DO" [label] [,] var-expr
+
+ (ffestb_do6_) // to expression handler
+
+ Make sure the statement has a valid form for the DO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_do6_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ /* _3_ already ensured that this would be an EQUALS token. If not, it is a
+ bug in the FFE. */
+
+ assert (ffelex_token_type (t) == FFELEX_typeEQUALS);
+
+ ffesta_tokens[2] = ffelex_token_use (ft);
+ ffestb_local_.do_stmt.var = expr;
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextDO, (ffeexprCallback) ffestb_do7_);
+}
+
+/* ffestb_do7_ -- "DO" [label] [,] var-expr EQUALS expr
+
+ (ffestb_do7_) // to expression handler
+
+ Make sure the statement has a valid form for the DO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_do7_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (expr == NULL)
+ break;
+ ffesta_tokens[3] = ffelex_token_use (ft);
+ ffestb_local_.do_stmt.start = expr;
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextDO, (ffeexprCallback) ffestb_do8_);
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[2]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_do8_ -- "DO" [label] [,] var-expr EQUALS expr COMMA expr
+
+ (ffestb_do8_) // to expression handler
+
+ Make sure the statement has a valid form for the DO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_do8_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[4] = ffelex_token_use (ft);
+ ffestb_local_.do_stmt.end = expr;
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextDO, (ffeexprCallback) ffestb_do9_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[4] = ffelex_token_use (ft);
+ ffestb_local_.do_stmt.end = expr;
+ return (ffelexHandler) ffestb_do9_ (NULL, NULL, t);
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[3]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_do9_ -- "DO" [label] [,] var-expr EQUALS expr COMMA expr
+ [COMMA expr]
+
+ (ffestb_do9_) // to expression handler
+
+ Make sure the statement has a valid form for the DO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_do9_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if ((expr == NULL) && (ft != NULL))
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffesta_tokens[1] != NULL)
+ ffestc_R819A (ffesta_construct_name, ffesta_tokens[1],
+ ffestb_local_.do_stmt.var, ffesta_tokens[2],
+ ffestb_local_.do_stmt.start, ffesta_tokens[3],
+ ffestb_local_.do_stmt.end, ffesta_tokens[4], expr, ft);
+ else
+ ffestc_R820A (ffesta_construct_name, ffestb_local_.do_stmt.var,
+ ffesta_tokens[2], ffestb_local_.do_stmt.start,
+ ffesta_tokens[3], ffestb_local_.do_stmt.end,
+ ffesta_tokens[4], expr, ft);
+ }
+ ffelex_token_kill (ffesta_tokens[4]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[4]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_else -- Parse the ELSE statement
+
+ return ffestb_else; // to lexer
+
+ Make sure the statement has a valid form for the ELSE statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_else (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstELSE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = NULL;
+ ffestb_args.elsexyz.second = FFESTR_secondNone;
+ return (ffelexHandler) ffestb_else1_ (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ break;
+ }
+
+ ffesta_confirmed ();
+ ffestb_args.elsexyz.second = ffesta_second_kw;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_else1_;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstELSE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+ }
+ ffesta_confirmed ();
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlELSE)
+ {
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlELSE);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ }
+ else
+ ffesta_tokens[1] = NULL;
+ ffestb_args.elsexyz.second = FFESTR_secondNone;
+ return (ffelexHandler) ffestb_else1_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ELSE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ELSE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "ELSE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_elsexyz -- Parse an ELSEIF/ELSEWHERE statement
+
+ return ffestb_elsexyz; // to lexer
+
+ Expects len and second to be set in ffestb_args.elsexyz to the length
+ of the ELSExyz keyword involved and the corresponding ffestrSecond value. */
+
+ffelexHandler
+ffestb_elsexyz (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (ffesta_first_kw == FFESTR_firstELSEIF)
+ goto bad_0; /* :::::::::::::::::::: */
+ ffesta_confirmed ();
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_else1_ (t);
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ if (ffesta_first_kw != FFESTR_firstELSEIF)
+ goto bad_0; /* :::::::::::::::::::: */
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_else1_ (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeNAMES:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ if (ffesta_first_kw != FFESTR_firstELSEIF)
+ goto bad_1; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlELSEIF)
+ {
+ i = FFESTR_firstlELSEIF;
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_else1_ (t);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+ }
+ ffesta_confirmed ();
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlELSE);
+ ffesta_tokens[1]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+#if FFESTR_F90
+ if ((ffestb_args.elsexyz.second == FFESTR_secondWHERE)
+ && (ffelex_token_length (ffesta_tokens[1]) != FFESTR_secondlWHERE))
+ ffestb_args.elsexyz.second = FFESTR_secondNone;
+#endif
+ return (ffelexHandler) ffestb_else1_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ELSE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ELSE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "ELSE IF", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_else1_ -- "ELSE" (NAME)
+
+ return ffestb_else1_; // to lexer
+
+ If EOS/SEMICOLON, implement the appropriate statement (keep in mind that
+ "ELSE WHERE" is ambiguous at the syntactic level). If OPEN_PAREN, start
+ expression analysis with callback at _2_. */
+
+static ffelexHandler
+ffestb_else1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ if (ffestb_args.elsexyz.second == FFESTR_secondIF)
+ {
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIF, (ffeexprCallback) ffestb_else2_);
+ }
+ /* Fall through. */
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ELSE", t);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+
+ }
+
+ switch (ffestb_args.elsexyz.second)
+ {
+#if FFESTR_F90
+ case FFESTR_secondWHERE:
+ if (!ffesta_is_inhibited ())
+ if ((ffesta_first_kw == FFESTR_firstELSEWHERE)
+ && (ffelex_token_type (ffesta_tokens[0]) == FFELEX_typeNAME))
+ ffestc_R744 ();
+ else
+ ffestc_elsewhere (ffesta_tokens[1]); /* R744 or R805. */
+ break;
+#endif
+
+ default:
+ if (!ffesta_is_inhibited ())
+ ffestc_R805 (ffesta_tokens[1]);
+ break;
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+}
+
+/* ffestb_else2_ -- "ELSE" "IF" OPEN_PAREN expr
+
+ (ffestb_else2_) // to expression handler
+
+ Make sure the next token is CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_else2_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffestb_local_.else_stmt.expr = expr;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_else3_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ELSE IF", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_else3_ -- "ELSE" "IF" OPEN_PAREN expr CLOSE_PAREN
+
+ return ffestb_else3_; // to lexer
+
+ Make sure the next token is "THEN". */
+
+static ffelexHandler
+ffestb_else3_ (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ if (ffestr_first (t) == FFESTR_firstTHEN)
+ return (ffelexHandler) ffestb_else4_;
+ break;
+
+ case FFELEX_typeNAMES:
+ ffesta_confirmed ();
+ if (ffestr_first (t) != FFESTR_firstTHEN)
+ break;
+ if (ffelex_token_length (t) == FFESTR_firstlTHEN)
+ return (ffelexHandler) ffestb_else4_;
+ p = ffelex_token_text (t) + (i = FFESTR_firstlTHEN);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[2] = ffelex_token_name_from_names (t, i, 0);
+ return (ffelexHandler) ffestb_else5_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ELSE IF", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "ELSE IF", t, i, NULL);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_else4_ -- "ELSE" "IF" OPEN_PAREN expr CLOSE_PAREN "THEN"
+
+ return ffestb_else4_; // to lexer
+
+ Handle a NAME or EOS/SEMICOLON, then go to state _5_. */
+
+static ffelexHandler
+ffestb_else4_ (ffelexToken t)
+{
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_tokens[2] = NULL;
+ return (ffelexHandler) ffestb_else5_ (t);
+
+ case FFELEX_typeNAME:
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_else5_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ELSE IF", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_else5_ -- "ELSE" "IF" OPEN_PAREN expr CLOSE_PAREN "THEN"
+
+ return ffestb_else5_; // to lexer
+
+ Make sure the next token is EOS or SEMICOLON; implement R804. */
+
+static ffelexHandler
+ffestb_else5_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R804 (ffestb_local_.else_stmt.expr, ffesta_tokens[1],
+ ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_tokens[2] != NULL)
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ELSE IF", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_tokens[2] != NULL)
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_end -- Parse the END statement
+
+ return ffestb_end; // to lexer
+
+ Make sure the statement has a valid form for the END statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_end (ffelexToken t)
+{
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstEND)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_tokens[1] = NULL;
+ ffestb_args.endxyz.second = FFESTR_secondNone;
+ return (ffelexHandler) ffestb_end3_ (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ break;
+ }
+
+ ffesta_confirmed ();
+ ffestb_args.endxyz.second = ffesta_second_kw;
+ switch (ffesta_second_kw)
+ {
+ case FFESTR_secondFILE:
+ ffestb_args.beru.badname = "ENDFILE";
+ return (ffelexHandler) ffestb_beru;
+
+ case FFESTR_secondBLOCK:
+ return (ffelexHandler) ffestb_end1_;
+
+#if FFESTR_F90
+ case FFESTR_secondINTERFACE:
+#endif
+#if FFESTR_VXT
+ case FFESTR_secondMAP:
+ case FFESTR_secondSTRUCTURE:
+ case FFESTR_secondUNION:
+#endif
+#if FFESTR_F90
+ case FFESTR_secondWHERE:
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_end3_;
+#endif
+
+ case FFESTR_secondNone:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ return (ffelexHandler) ffestb_end2_;
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstEND)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+ }
+ ffesta_confirmed ();
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlEND)
+ {
+ i = FFESTR_firstlEND;
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ ffesta_tokens[1] = NULL;
+ ffestb_args.endxyz.second = FFESTR_secondNone;
+ return (ffelexHandler) ffestb_end3_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "END", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "END", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "END", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_endxyz -- Parse an ENDxyz statement
+
+ return ffestb_endxyz; // to lexer
+
+ Expects len and second to be set in ffestb_args.endxyz to the length
+ of the ENDxyz keyword involved and the corresponding ffestrSecond value. */
+
+ffelexHandler
+ffestb_endxyz (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_end3_ (t);
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ switch (ffestb_args.endxyz.second)
+ {
+#if FFESTR_F90
+ case FFESTR_secondINTERFACE:
+#endif
+#if FFESTR_VXT
+ case FFESTR_secondMAP:
+ case FFESTR_secondSTRUCTURE:
+ case FFESTR_secondUNION:
+#endif
+#if FFESTR_F90
+ case FFESTR_secondWHERE:
+ goto bad_1; /* :::::::::::::::::::: */
+#endif
+
+ case FFESTR_secondBLOCK:
+ if (ffesta_second_kw != FFESTR_secondDATA)
+ goto bad_1; /* :::::::::::::::::::: */
+ return (ffelexHandler) ffestb_end2_;
+
+ default:
+ return (ffelexHandler) ffestb_end2_ (t);
+ }
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeNAMES:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+ }
+ ffesta_confirmed ();
+ if (ffestb_args.endxyz.second == FFESTR_secondBLOCK)
+ {
+ i = FFESTR_firstlEND;
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ if (ffelex_token_length (ffesta_tokens[0]) != ffestb_args.endxyz.len)
+ {
+ p = ffelex_token_text (ffesta_tokens[0])
+ + (i = ffestb_args.endxyz.len);
+ switch (ffestb_args.endxyz.second)
+ {
+#if FFESTR_F90
+ case FFESTR_secondINTERFACE:
+#endif
+#if FFESTR_VXT
+ case FFESTR_secondMAP:
+ case FFESTR_secondSTRUCTURE:
+ case FFESTR_secondUNION:
+#endif
+#if FFESTR_F90
+ case FFESTR_secondWHERE:
+ goto bad_i; /* :::::::::::::::::::: */
+#endif
+
+ default:
+ break;
+ }
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ return (ffelexHandler) ffestb_end3_ (t);
+ }
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_end3_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "END", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "END", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "END", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_end1_ -- "END" "BLOCK"
+
+ return ffestb_end1_; // to lexer
+
+ Make sure the next token is "DATA". */
+
+static ffelexHandler
+ffestb_end1_ (ffelexToken t)
+{
+ if ((ffelex_token_type (t) == FFELEX_typeNAME)
+ && (ffesrc_strcmp_2c (ffe_case_match (), ffelex_token_text (t), "DATA",
+ "data", "Data")
+ == 0))
+ {
+ return (ffelexHandler) ffestb_end2_;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "END", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_end2_ -- "END" <unit-kind>
+
+ return ffestb_end2_; // to lexer
+
+ Make sure the next token is a NAME or EOS. */
+
+static ffelexHandler
+ffestb_end2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_end3_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_end3_ (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "END", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffestb_end3_ -- "END" <unit-kind> (NAME)
+
+ return ffestb_end3_; // to lexer
+
+ Make sure the next token is an EOS, then implement the statement. */
+
+static ffelexHandler
+ffestb_end3_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "END", t);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (ffestb_args.endxyz.second == FFESTR_secondNone)
+ {
+ if (!ffesta_is_inhibited ())
+ ffestc_end ();
+ return (ffelexHandler) ffesta_zero (t);
+ }
+ break;
+ }
+
+ switch (ffestb_args.endxyz.second)
+ {
+#if FFESTR_F90
+ case FFESTR_secondTYPE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R425 (ffesta_tokens[1]);
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_secondWHERE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R745 ();
+ break;
+#endif
+
+ case FFESTR_secondIF:
+ if (!ffesta_is_inhibited ())
+ ffestc_R806 (ffesta_tokens[1]);
+ break;
+
+ case FFESTR_secondSELECT:
+ if (!ffesta_is_inhibited ())
+ ffestc_R811 (ffesta_tokens[1]);
+ break;
+
+ case FFESTR_secondDO:
+ if (!ffesta_is_inhibited ())
+ ffestc_R825 (ffesta_tokens[1]);
+ break;
+
+ case FFESTR_secondPROGRAM:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1103 (ffesta_tokens[1]);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_secondMODULE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1106 (ffesta_tokens[1]);
+ break;
+#endif
+ case FFESTR_secondBLOCK:
+ case FFESTR_secondBLOCKDATA:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1112 (ffesta_tokens[1]);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_secondINTERFACE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1203 ();
+ break;
+#endif
+
+ case FFESTR_secondFUNCTION:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1221 (ffesta_tokens[1]);
+ break;
+
+ case FFESTR_secondSUBROUTINE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1225 (ffesta_tokens[1]);
+ break;
+
+#if FFESTR_VXT
+ case FFESTR_secondSTRUCTURE:
+ if (!ffesta_is_inhibited ())
+ ffestc_V004 ();
+ break;
+#endif
+
+#if FFESTR_VXT
+ case FFESTR_secondUNION:
+ if (!ffesta_is_inhibited ())
+ ffestc_V010 ();
+ break;
+#endif
+
+#if FFESTR_VXT
+ case FFESTR_secondMAP:
+ if (!ffesta_is_inhibited ())
+ ffestc_V013 ();
+ break;
+#endif
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "END", ffesta_tokens[0]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+}
+
+/* ffestb_goto -- Parse the GOTO statement
+
+ return ffestb_goto; // to lexer
+
+ Make sure the statement has a valid form for the GOTO statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_goto (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstGO:
+ if ((ffelex_token_type (t) != FFELEX_typeNAME)
+ || (ffesta_second_kw != FFESTR_secondTO))
+ goto bad_1; /* :::::::::::::::::::: */
+ ffesta_confirmed ();
+ return (ffelexHandler) ffestb_goto1_;
+
+ case FFESTR_firstGOTO:
+ return (ffelexHandler) ffestb_goto1_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstGOTO)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ case FFELEX_typePERCENT: /* Since GOTO I%J is apparently valid
+ in '90. */
+ case FFELEX_typeCOMMA:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+ }
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlGOTO)
+ {
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlGOTO);
+ if (ISDIGIT (*p))
+ {
+ nt = ffelex_token_number_from_names (ffesta_tokens[0], i);
+ p += ffelex_token_length (nt);
+ i += ffelex_token_length (nt);
+ if (*p != '\0')
+ {
+ ffelex_token_kill (nt);
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ }
+ else if (ffesrc_is_name_init (*p))
+ {
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ }
+ else
+ goto bad_i; /* :::::::::::::::::::: */
+ next = (ffelexHandler) ffestb_goto1_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+ return (ffelexHandler) ffestb_goto1_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "GO TO", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "GO TO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "GO TO", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_goto1_ -- "GOTO" or "GO" "TO"
+
+ return ffestb_goto1_; // to lexer
+
+ Make sure the statement has a valid form for the GOTO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_goto1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ if (ffelex_token_type (ffesta_tokens[0]) == FFELEX_typeNAME)
+ ffesta_confirmed ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_goto2_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ ffestb_subrargs_.label_list.labels = ffestt_tokenlist_create ();
+ ffestb_subrargs_.label_list.handler = (ffelexHandler) ffestb_goto3_;
+ return (ffelexHandler) ffestb_subr_label_list_;
+
+ case FFELEX_typeNAME:
+ if (ffelex_token_type (ffesta_tokens[0]) == FFELEX_typeNAME)
+ ffesta_confirmed ();
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextAGOTO,
+ (ffeexprCallback) ffestb_goto4_)))
+ (t);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ break;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "GO TO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_goto2_ -- "GO/TO" NUMBER
+
+ return ffestb_goto2_; // to lexer
+
+ Make sure the statement has a valid form for the GOTO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_goto2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R836 (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "GO TO", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_goto3_ -- "GO/TO" OPEN_PAREN label-list CLOSE_PAREN
+
+ return ffestb_goto3_; // to lexer
+
+ Make sure the statement has a valid form for the GOTO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_goto3_ (ffelexToken t)
+{
+ if (!ffestb_subrargs_.label_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool, FFEEXPR_contextCGOTO,
+ (ffeexprCallback) ffestb_goto5_);
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+
+ default:
+ ffesta_confirmed ();
+ /* Fall through. */
+ case FFELEX_typeOPEN_PAREN: /* Could still be assignment!! */
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool, FFEEXPR_contextCGOTO,
+ (ffeexprCallback) ffestb_goto5_)))
+ (t);
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "computed-GOTO", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_tokenlist_kill (ffestb_subrargs_.label_list.labels);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_goto4_ -- "GO/TO" expr
+
+ (ffestb_goto4_) // to expression handler
+
+ Make sure the statement has a valid form for the GOTO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_goto4_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (expr == NULL)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ ffestb_local_.go_to.expr = expr;
+ return (ffelexHandler) ffestb_goto6_;
+
+ case FFELEX_typeOPEN_PAREN:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ ffestb_local_.go_to.expr = expr;
+ return (ffelexHandler) ffestb_goto6_ (t);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R839 (expr, ft, NULL);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "assigned-GOTO", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_goto5_ -- "GO/TO" OPEN_PAREN label-list CLOSE_PAREN (COMMA) expr
+
+ (ffestb_goto5_) // to expression handler
+
+ Make sure the statement has a valid form for the GOTO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_goto5_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R837 (ffestb_subrargs_.label_list.labels, expr, ft);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_tokenlist_kill (ffestb_subrargs_.label_list.labels);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "computed-GOTO", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_tokenlist_kill (ffestb_subrargs_.label_list.labels);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_goto6_ -- "GO/TO" expr (COMMA)
+
+ return ffestb_goto6_; // to lexer
+
+ Make sure the statement has a valid form for the GOTO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_goto6_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffesta_tokens[2] = ffelex_token_use (t);
+ ffestb_subrargs_.label_list.labels = ffestt_tokenlist_create ();
+ ffestb_subrargs_.label_list.handler = (ffelexHandler) ffestb_goto7_;
+ return (ffelexHandler) ffestb_subr_label_list_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "assigned-GOTO", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_goto7_ -- "GO/TO" expr (COMMA) OPEN_PAREN label-list CLOSE_PAREN
+
+ return ffestb_goto7_; // to lexer
+
+ Make sure the statement has a valid form for the GOTO statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_goto7_ (ffelexToken t)
+{
+ if (!ffestb_subrargs_.label_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R839 (ffestb_local_.go_to.expr, ffesta_tokens[1],
+ ffestb_subrargs_.label_list.labels);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffestt_tokenlist_kill (ffestb_subrargs_.label_list.labels);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "assigned-GOTO", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffestt_tokenlist_kill (ffestb_subrargs_.label_list.labels);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_halt -- Parse the STOP/PAUSE statement
+
+ return ffestb_halt; // to lexer
+
+ Make sure the statement has a valid form for the STOP/PAUSE statement. If
+ it does, implement the statement. */
+
+ffelexHandler
+ffestb_halt (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ case FFELEX_typeAPOSTROPHE:
+ case FFELEX_typeQUOTE:
+ ffesta_confirmed ();
+ break;
+ }
+
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextSTOP,
+ (ffeexprCallback) ffestb_halt1_)))
+ (t);
+
+ case FFELEX_typeNAMES:
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ case FFELEX_typeAPOSTROPHE:
+ case FFELEX_typeQUOTE:
+ ffesta_confirmed ();
+ break;
+ }
+ next = (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextSTOP,
+ (ffeexprCallback) ffestb_halt1_);
+ next = (ffelexHandler) ffelex_splice_tokens (next, ffesta_tokens[0],
+ ffestb_args.halt.len);
+ if (next == NULL)
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ (ffesta_first_kw == FFESTR_firstSTOP)
+ ? "STOP" : "PAUSE",
+ ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ (ffesta_first_kw == FFESTR_firstSTOP)
+ ? "STOP" : "PAUSE",
+ t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_halt1_ -- "STOP/PAUSE" expr
+
+ (ffestb_halt1_) // to expression handler
+
+ Make sure the next token is an EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_halt1_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffesta_first_kw == FFESTR_firstSTOP)
+ ffestc_R842 (expr, ft);
+ else
+ ffestc_R843 (expr, ft);
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ (ffesta_first_kw == FFESTR_firstSTOP)
+ ? "STOP" : "PAUSE",
+ t);
+ break;
+ }
+
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_if -- Parse an IF statement
+
+ return ffestb_if; // to lexer
+
+ Make sure the statement has a valid form for an IF statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_if (ffelexToken t)
+{
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstIF)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstIF)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlIF)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool, FFEEXPR_contextIF,
+ (ffeexprCallback) ffestb_if1_);
+
+bad_0: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IF", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IF", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_if1_ -- "IF" OPEN_PAREN expr
+
+ (ffestb_if1_) // to expression handler
+
+ Make sure the next token is CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_if1_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffestb_local_.if_stmt.expr = expr;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_if2_;
+
+ default:
+ break;
+ }
+
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IF", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_if2_ -- "IF" OPEN_PAREN expr CLOSE_PAREN
+
+ return ffestb_if2_; // to lexer
+
+ Make sure the next token is NAME. */
+
+static ffelexHandler
+ffestb_if2_ (ffelexToken t)
+{
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffesta_confirmed ();
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_if3_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ if ((ffesta_construct_name == NULL)
+ || (ffelex_token_type (t) != FFELEX_typeNUMBER))
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IF", t);
+ else
+ ffesta_ffebad_2st (FFEBAD_INVALID_STMT_FORM, "CONSTRUCT",
+ ffesta_construct_name, t);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_if3_ -- "IF" OPEN_PAREN expr CLOSE_PAREN NAME
+
+ return ffestb_if3_; // to lexer
+
+ If the next token is EOS or SEMICOLON and the preceding NAME was "THEN",
+ implement R803. Else, implement R807 and send the preceding NAME followed
+ by the current token. */
+
+static ffelexHandler
+ffestb_if3_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (ffestr_first (ffesta_tokens[2]) == FFESTR_firstTHEN)
+ {
+ if (!ffesta_is_inhibited ())
+ ffestc_R803 (ffesta_construct_name, ffestb_local_.if_stmt.expr,
+ ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ return (ffelexHandler) ffesta_zero (t);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (ffesta_construct_name != NULL)
+ {
+ if (!ffesta_is_inhibited ())
+ ffesta_ffebad_2st (FFEBAD_INVALID_STMT_FORM, "CONSTRUCT",
+ ffesta_construct_name, ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R807 (ffestb_local_.if_stmt.expr, ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ {
+ ffelexToken my_2 = ffesta_tokens[2];
+
+ next = (ffelexHandler) ffesta_two (my_2, t);
+ ffelex_token_kill (my_2);
+ }
+ return (ffelexHandler) next;
+}
+
+/* ffestb_where -- Parse a WHERE statement
+
+ return ffestb_where; // to lexer
+
+ Make sure the statement has a valid form for a WHERE statement.
+ If it does, implement the statement. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_where (ffelexToken t)
+{
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstWHERE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstWHERE)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlWHERE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool, FFEEXPR_contextWHERE,
+ (ffeexprCallback) ffestb_where1_);
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WHERE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WHERE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+#endif
+/* ffestb_where1_ -- "WHERE" OPEN_PAREN expr
+
+ (ffestb_where1_) // to expression handler
+
+ Make sure the next token is CLOSE_PAREN. */
+
+#if FFESTR_F90
+static ffelexHandler
+ffestb_where1_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffestb_local_.if_stmt.expr = expr;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_where2_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WHERE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_where2_ -- "WHERE" OPEN_PAREN expr CLOSE_PAREN
+
+ return ffestb_where2_; // to lexer
+
+ Make sure the next token is NAME. */
+
+#if FFESTR_F90
+static ffelexHandler
+ffestb_where2_ (ffelexToken t)
+{
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ ffesta_confirmed ();
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_where3_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R742 (ffestb_local_.if_stmt.expr, ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WHERE", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_where3_ -- "WHERE" OPEN_PAREN expr CLOSE_PAREN NAME
+
+ return ffestb_where3_; // to lexer
+
+ Implement R742. */
+
+#if FFESTR_F90
+static ffelexHandler
+ffestb_where3_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken my_2 = ffesta_tokens[2];
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R740 (ffestb_local_.if_stmt.expr, ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ next = (ffelexHandler) ffesta_two (my_2, t);
+ ffelex_token_kill (my_2);
+ return (ffelexHandler) next;
+}
+
+#endif
+/* ffestb_let -- Parse an assignment statement
+
+ return ffestb_let; // to lexer
+
+ Make sure the statement has a valid form for an assignment statement. If
+ it does, implement the statement. */
+
+ffelexHandler
+ffestb_let (ffelexToken t)
+{
+ ffelexHandler next;
+ bool vxtparam; /* TRUE if it might really be a VXT PARAMETER
+ stmt. */
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ vxtparam = FALSE;
+ break;
+
+ case FFELEX_typeNAMES:
+ vxtparam = TRUE;
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ case FFELEX_typePERCENT:
+ case FFELEX_typePOINTS:
+ ffestb_local_.let.vxtparam = FALSE;
+ break;
+
+ case FFELEX_typeEQUALS:
+ if (!vxtparam || (ffesta_first_kw != FFESTR_firstPARAMETER))
+ {
+ ffestb_local_.let.vxtparam = FALSE;
+ break;
+ }
+ p = ffelex_token_text (ffesta_tokens[0]) + FFESTR_firstlPARAMETER;
+ ffestb_local_.let.vxtparam = ffesrc_is_name_init (*p);
+ break;
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ next = (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextLET,
+ (ffeexprCallback) ffestb_let1_)))
+ (ffesta_tokens[0]);
+ return (ffelexHandler) (*next) (t);
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "assignment", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "assignment", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_let1_ -- expr
+
+ (ffestb_let1_) // to expression handler
+
+ Make sure the next token is EQUALS or POINTS. */
+
+static ffelexHandler
+ffestb_let1_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ ffestb_local_.let.dest = expr;
+
+ switch (ffelex_token_type (t))
+ {
+#if FFESTR_F90
+ case FFELEX_typePOINTS:
+#endif
+ case FFELEX_typeEQUALS:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextLET, (ffeexprCallback) ffestb_let2_);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "assignment", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_let2_ -- expr EQUALS/POINTS expr
+
+ (ffestb_end2_) // to expression handler
+
+ Make sure the next token is EOS or SEMICOLON; implement the statement. */
+
+static ffelexHandler
+ffestb_let2_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ if (ffestb_local_.let.vxtparam && !ffestc_is_let_not_V027 ())
+ break;
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+#if FFESTR_F90
+ if (ffelex_token_type (ffesta_tokens[1]) == FFELEX_typeEQUALS)
+#endif
+ ffestc_let (ffestb_local_.let.dest, expr, ft);
+#if FFESTR_F90
+ else
+ ffestc_R738 (ffestb_local_.let.dest, expr, ft);
+#endif
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM,
+ (ffelex_token_type (ffesta_tokens[1]) == FFELEX_typeEQUALS)
+ ? "assignment" : "pointer-assignment",
+ t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_type -- Parse the TYPE statement
+
+ return ffestb_type; // to lexer
+
+ Make sure the statement has a valid form for the TYPE statement. If
+ it does, implement the statement. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_type (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstTYPE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ return (ffelexHandler) ffestb_type1_;
+
+ case FFELEX_typeNAME: /* No confirm here, because ambig w/V020 VXT
+ TYPE. */
+ ffesta_tokens[1] = NULL;
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_type4_;
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstTYPE)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlTYPE);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOMMA:
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_confirmed ();
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_type1_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+ }
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1] = NULL;
+ ffesta_tokens[2]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ return (ffelexHandler) ffestb_type4_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "TYPE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "TYPE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "TYPE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_type1_ -- "TYPE" COMMA
+
+ return ffestb_type1_; // to lexer
+
+ Make sure the next token is a NAME. */
+
+static ffelexHandler
+ffestb_type1_ (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ ffestb_local_.type.kw = ffestr_other (t);
+ switch (ffestb_local_.varlist.kw)
+ {
+ case FFESTR_otherPUBLIC:
+ case FFESTR_otherPRIVATE:
+ return (ffelexHandler) ffestb_type2_;
+
+ default:
+ ffelex_token_kill (ffesta_tokens[1]);
+ break;
+ }
+ break;
+
+ case FFELEX_typeNAMES:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ ffestb_local_.type.kw = ffestr_other (t);
+ switch (ffestb_local_.varlist.kw)
+ {
+ case FFESTR_otherPUBLIC:
+ p = ffelex_token_text (t) + (i = FFESTR_otherlPUBLIC);
+ if (*p == '\0')
+ return (ffelexHandler) ffestb_type2_;
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i1; /* :::::::::::::::::::: */
+ ffesta_tokens[2] = ffelex_token_name_from_names (t, i, 0);
+ return (ffelexHandler) ffestb_type4_;
+
+ case FFESTR_otherPRIVATE:
+ p = ffelex_token_text (t) + (i = FFESTR_otherlPRIVATE);
+ if (*p == '\0')
+ return (ffelexHandler) ffestb_type2_;
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i1; /* :::::::::::::::::::: */
+ ffesta_tokens[2] = ffelex_token_name_from_names (t, i, 0);
+ return (ffelexHandler) ffestb_type4_;
+
+ default:
+ ffelex_token_kill (ffesta_tokens[1]);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "TYPE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_i1: /* :::::::::::::::::::: */
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "TYPE", t, i, NULL);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_type2_ -- "TYPE" COMMA NAME
+
+ return ffestb_type2_; // to lexer
+
+ Handle COLONCOLON or NAME. */
+
+static ffelexHandler
+ffestb_type2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOLONCOLON:
+ return (ffelexHandler) ffestb_type3_;
+
+ case FFELEX_typeNAME:
+ return (ffelexHandler) ffestb_type3_ (t);
+
+ default:
+ break;
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "TYPE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_type3_ -- "TYPE" [COMMA NAME [COLONCOLON]]
+
+ return ffestb_type3_; // to lexer
+
+ Make sure the next token is a NAME. */
+
+static ffelexHandler
+ffestb_type3_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_type4_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "TYPE", t);
+ break;
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_type4_ -- "TYPE" [COMMA NAME [COLONCOLON]] NAME
+
+ return ffestb_type4_; // to lexer
+
+ Make sure the next token is an EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_type4_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R424 (ffesta_tokens[1], ffestb_local_.type.kw,
+ ffesta_tokens[2]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "TYPE", t);
+ break;
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_varlist -- Parse EXTERNAL/INTENT/INTRINSIC/OPTIONAL/PUBLIC/PRIVATE
+ statement
+
+ return ffestb_varlist; // to lexer
+
+ Make sure the statement has a valid form. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_varlist (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffelexHandler next;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ switch (ffesta_first_kw)
+ {
+#if FFESTR_F90
+ case FFESTR_firstPUBLIC:
+ if (!ffesta_is_inhibited ())
+ ffestc_R521A ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFESTR_firstPRIVATE:
+ if (!ffesta_is_inhibited ())
+ ffestc_private (); /* Either R523A or R521B. */
+ return (ffelexHandler) ffesta_zero (t);
+#endif
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ switch (ffesta_first_kw)
+ {
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ if (!ffesta_is_inhibited ())
+ ffestc_R520_start ();
+ break;
+
+ case FFESTR_firstPUBLIC:
+ if (!ffesta_is_inhibited ())
+ ffestc_R521Astart ();
+ break;
+
+ case FFESTR_firstPRIVATE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R521Bstart ();
+ break;
+#endif
+
+ default:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+ return (ffelexHandler) ffestb_varlist5_;
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ switch (ffesta_first_kw)
+ {
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ return (ffelexHandler) ffestb_varlist1_;
+#endif
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstEXTERNAL:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1207_start ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ goto bad_1; /* :::::::::::::::::::: */
+#endif
+
+ case FFESTR_firstINTRINSIC:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1208_start ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ if (!ffesta_is_inhibited ())
+ ffestc_R520_start ();
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstPUBLIC:
+ if (!ffesta_is_inhibited ())
+ ffestc_R521Astart ();
+ break;
+
+ case FFESTR_firstPRIVATE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R521Bstart ();
+ break;
+#endif
+
+ default:
+ break;
+ }
+ return (ffelexHandler) ffestb_varlist5_ (t);
+ }
+
+ case FFELEX_typeNAMES:
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = ffestb_args.varlist.len);
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ switch (ffesta_first_kw)
+ {
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ goto bad_1; /* :::::::::::::::::::: */
+#endif
+
+ default:
+ break;
+ }
+ if (*p != '\0')
+ break;
+ switch (ffesta_first_kw)
+ {
+#if FFESTR_F90
+ case FFESTR_firstPUBLIC:
+ if (!ffesta_is_inhibited ())
+ ffestc_R521A ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFESTR_firstPRIVATE:
+ if (!ffesta_is_inhibited ())
+ ffestc_private (); /* Either R423A or R521B. */
+ return (ffelexHandler) ffesta_zero (t);
+#endif
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ switch (ffesta_first_kw)
+ {
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ goto bad_1; /* :::::::::::::::::::: */
+#endif
+
+ default:
+ break;
+ }
+ if (*p != '\0')
+ break;
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ switch (ffesta_first_kw)
+ {
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ if (!ffesta_is_inhibited ())
+ ffestc_R520_start ();
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstPUBLIC:
+ if (!ffesta_is_inhibited ())
+ ffestc_R521Astart ();
+ break;
+
+ case FFESTR_firstPRIVATE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R521Bstart ();
+ break;
+#endif
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+ return (ffelexHandler) ffestb_varlist5_;
+
+ case FFELEX_typeOPEN_PAREN:
+ switch (ffesta_first_kw)
+ {
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ if (*p != '\0')
+ goto bad_1; /* :::::::::::::::::::: */
+ return (ffelexHandler) ffestb_varlist1_;
+#endif
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstEXTERNAL:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1207_start ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ goto bad_1; /* :::::::::::::::::::: */
+#endif
+
+ case FFESTR_firstINTRINSIC:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1208_start ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ if (!ffesta_is_inhibited ())
+ ffestc_R520_start ();
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstPUBLIC:
+ if (!ffesta_is_inhibited ())
+ ffestc_R521Astart ();
+ break;
+
+ case FFESTR_firstPRIVATE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R521Bstart ();
+ break;
+#endif
+
+ default:
+ break;
+ }
+ return (ffelexHandler) ffestb_varlist5_ (t);
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ /* Here, we have at least one char after the first keyword and t is
+ COMMA or EOS/SEMICOLON. Also we know that this form is valid for
+ only the statements reaching here (specifically, INTENT won't reach
+ here). */
+
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstEXTERNAL:
+ ffestc_R1207_start ();
+ break;
+
+ case FFESTR_firstINTRINSIC:
+ ffestc_R1208_start ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ ffestc_R520_start ();
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstPUBLIC:
+ ffestc_R521Astart ();
+ break;
+
+ case FFESTR_firstPRIVATE:
+ ffestc_R521Bstart ();
+ break;
+#endif
+
+ default:
+ assert (FALSE);
+ }
+ }
+ next = (ffelexHandler) ffestb_varlist5_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.varlist.badname, ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.varlist.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, ffestb_args.varlist.badname, ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_varlist1_ -- "INTENT" OPEN_PAREN
+
+ return ffestb_varlist1_; // to lexer
+
+ Handle NAME. */
+
+#if FFESTR_F90
+static ffelexHandler
+ffestb_varlist1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ ffestb_local_.varlist.kw = ffestr_other (t);
+ switch (ffestb_local_.varlist.kw)
+ {
+ case FFESTR_otherIN:
+ return (ffelexHandler) ffestb_varlist2_;
+
+ case FFESTR_otherINOUT:
+ return (ffelexHandler) ffestb_varlist3_;
+
+ case FFESTR_otherOUT:
+ return (ffelexHandler) ffestb_varlist3_;
+
+ default:
+ ffelex_token_kill (ffesta_tokens[1]);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.varlist.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_varlist2_ -- "INTENT" OPEN_PAREN "IN"
+
+ return ffestb_varlist2_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_varlist2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ switch (ffestr_other (t))
+ {
+ case FFESTR_otherOUT:
+ ffestb_local_.varlist.kw = FFESTR_otherINOUT;
+ return (ffelexHandler) ffestb_varlist3_;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_varlist4_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.varlist.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_varlist3_ -- "INTENT" OPEN_PAREN NAME ["OUT"]
+
+ return ffestb_varlist3_; // to lexer
+
+ Handle CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_varlist3_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_varlist4_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.varlist.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_varlist4_ -- "INTENT" OPEN_PAREN NAME ["OUT"] CLOSE_PAREN
+
+ return ffestb_varlist4_; // to lexer
+
+ Handle COLONCOLON or NAME. */
+
+static ffelexHandler
+ffestb_varlist4_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R519_start (ffesta_tokens[1], ffestb_local_.varlist.kw);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_varlist5_;
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R519_start (ffesta_tokens[1], ffestb_local_.varlist.kw);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_varlist5_ (t);
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.varlist.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_varlist5_ -- Handles the list of variable names
+
+ return ffestb_varlist5_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_varlist5_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_varlist6_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.varlist.badname, t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstEXTERNAL:
+ ffestc_R1207_finish ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ ffestc_R519_finish ();
+ break;
+#endif
+
+ case FFESTR_firstINTRINSIC:
+ ffestc_R1208_finish ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ ffestc_R520_finish ();
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstPUBLIC:
+ ffestc_R521Afinish ();
+ break;
+
+ case FFESTR_firstPRIVATE:
+ ffestc_R521Bfinish ();
+ break;
+#endif
+
+ default:
+ assert (FALSE);
+ }
+ }
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_varlist6_ -- (whatever) NAME
+
+ return ffestb_varlist6_; // to lexer
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_varlist6_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstEXTERNAL:
+ ffestc_R1207_item (ffesta_tokens[1]);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ ffestc_R519_item (ffesta_tokens[1]);
+ break;
+#endif
+
+ case FFESTR_firstINTRINSIC:
+ ffestc_R1208_item (ffesta_tokens[1]);
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ ffestc_R520_item (ffesta_tokens[1]);
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstPUBLIC:
+ ffestc_R521Aitem (ffesta_tokens[1]);
+ break;
+
+ case FFESTR_firstPRIVATE:
+ ffestc_R521Bitem (ffesta_tokens[1]);
+ break;
+#endif
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_varlist5_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstEXTERNAL:
+ ffestc_R1207_item (ffesta_tokens[1]);
+ ffestc_R1207_finish ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ ffestc_R519_item (ffesta_tokens[1]);
+ ffestc_R519_finish ();
+ break;
+#endif
+
+ case FFESTR_firstINTRINSIC:
+ ffestc_R1208_item (ffesta_tokens[1]);
+ ffestc_R1208_finish ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ ffestc_R520_item (ffesta_tokens[1]);
+ ffestc_R520_finish ();
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstPUBLIC:
+ ffestc_R521Aitem (ffesta_tokens[1]);
+ ffestc_R521Afinish ();
+ break;
+
+ case FFESTR_firstPRIVATE:
+ ffestc_R521Bitem (ffesta_tokens[1]);
+ ffestc_R521Bfinish ();
+ break;
+#endif
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.varlist.badname, t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstEXTERNAL:
+ ffestc_R1207_finish ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ ffestc_R519_finish ();
+ break;
+#endif
+
+ case FFESTR_firstINTRINSIC:
+ ffestc_R1208_finish ();
+ break;
+
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ ffestc_R520_finish ();
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstPUBLIC:
+ ffestc_R521Afinish ();
+ break;
+
+ case FFESTR_firstPRIVATE:
+ ffestc_R521Bfinish ();
+ break;
+#endif
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R423B -- Parse the SEQUENCE statement
+
+ return ffestb_R423B; // to lexer
+
+ Make sure the statement has a valid form for the SEQUENCE statement. If
+ it does, implement the statement. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_R423B (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstSEQUENCE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstSEQUENCE)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlSEQUENCE)
+ {
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlSEQUENCE);
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R423B ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SEQUENCE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid first token. */
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SEQUENCE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "SEQUENCE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_R522 -- Parse the SAVE statement
+
+ return ffestb_R522; // to lexer
+
+ Make sure the statement has a valid form for the SAVE statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_R522 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffelexHandler next;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstSAVE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R522 ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R522start ();
+ return (ffelexHandler) ffestb_R5221_ (t);
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R522start ();
+ return (ffelexHandler) ffestb_R5221_;
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstSAVE)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlSAVE);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R522 ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ if (!ffesta_is_inhibited ())
+ ffestc_R522start ();
+ return (ffelexHandler) ffestb_R5221_ (t);
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ if (!ffesta_is_inhibited ())
+ ffestc_R522start ();
+ return (ffelexHandler) ffestb_R5221_;
+ }
+
+ /* Here, we have at least one char after "SAVE" and t is COMMA or
+ EOS/SEMICOLON. */
+
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ if (!ffesta_is_inhibited ())
+ ffestc_R522start ();
+ next = (ffelexHandler) ffestb_R5221_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SAVE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SAVE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "SAVE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5221_ -- "SAVE" [COLONCOLON]
+
+ return ffestb_R5221_; // to lexer
+
+ Handle NAME or SLASH. */
+
+static ffelexHandler
+ffestb_R5221_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffestb_local_.R522.is_cblock = FALSE;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R5224_;
+
+ case FFELEX_typeSLASH:
+ ffestb_local_.R522.is_cblock = TRUE;
+ return (ffelexHandler) ffestb_R5222_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SAVE", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R522finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5222_ -- "SAVE" [COLONCOLON] SLASH
+
+ return ffestb_R5222_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_R5222_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R5223_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SAVE", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R522finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5223_ -- "SAVE" [COLONCOLON] SLASH NAME
+
+ return ffestb_R5223_; // to lexer
+
+ Handle SLASH. */
+
+static ffelexHandler
+ffestb_R5223_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeSLASH:
+ return (ffelexHandler) ffestb_R5224_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SAVE", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R522finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5224_ -- "SAVE" [COLONCOLON] R523
+
+ return ffestb_R5224_; // to lexer
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_R5224_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffestb_local_.R522.is_cblock)
+ ffestc_R522item_cblock (ffesta_tokens[1]);
+ else
+ ffestc_R522item_object (ffesta_tokens[1]);
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_R5221_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffestb_local_.R522.is_cblock)
+ ffestc_R522item_cblock (ffesta_tokens[1]);
+ else
+ ffestc_R522item_object (ffesta_tokens[1]);
+ ffestc_R522finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SAVE", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R522finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R528 -- Parse the DATA statement
+
+ return ffestb_R528; // to lexer
+
+ Make sure the statement has a valid form for the DATA statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_R528 (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+ ffelexToken nt;
+ ffelexHandler next;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstDATA)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeSLASH:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeOPEN_PAREN:
+ break;
+ }
+ ffestb_local_.data.started = FALSE;
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_R5281_)))
+ (t);
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstDATA)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlDATA);
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ if (*p == '\0')
+ {
+ ffestb_local_.data.started = FALSE;
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextDATA,
+ (ffeexprCallback)
+ ffestb_R5281_)))
+ (t);
+ }
+ break;
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ break;
+ }
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffestb_local_.data.started = FALSE;
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ next = (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_R5281_)))
+ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DATA", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DATA", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "DATA", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5281_ -- "DATA" expr-list
+
+ (ffestb_R5281_) // to expression handler
+
+ Handle COMMA or SLASH. */
+
+static ffelexHandler
+ffestb_R5281_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.data.started)
+ {
+ ffestc_R528_start ();
+ ffestb_local_.data.started = TRUE;
+ }
+ ffestc_R528_item_object (expr, ft);
+ }
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_R5281_);
+
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.data.started)
+ {
+ ffestc_R528_start ();
+ ffestb_local_.data.started = TRUE;
+ }
+ ffestc_R528_item_object (expr, ft);
+ ffestc_R528_item_startvals ();
+ }
+ return (ffelexHandler) ffeexpr_rhs
+ (ffesta_output_pool, FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_R5282_);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DATA", t);
+ break;
+ }
+
+ if (ffestb_local_.data.started && !ffesta_is_inhibited ())
+ ffestc_R528_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5282_ -- "DATA" expr-list SLASH expr-list
+
+ (ffestb_R5282_) // to expression handler
+
+ Handle ASTERISK, COMMA, or SLASH. */
+
+static ffelexHandler
+ffestb_R5282_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R528_item_value (NULL, NULL, expr, ft);
+ return (ffelexHandler) ffeexpr_rhs
+ (ffesta_output_pool, FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_R5282_);
+
+ case FFELEX_typeASTERISK:
+ if (expr == NULL)
+ break;
+ ffestb_local_.data.expr = expr;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ return (ffelexHandler) ffeexpr_rhs
+ (ffesta_output_pool, FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_R5283_);
+
+ case FFELEX_typeSLASH:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R528_item_value (NULL, NULL, expr, ft);
+ ffestc_R528_item_endvals (t);
+ }
+ return (ffelexHandler) ffestb_R5284_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DATA", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R528_item_endvals (t);
+ ffestc_R528_finish ();
+ }
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5283_ -- "DATA" expr-list SLASH expr ASTERISK expr
+
+ (ffestb_R5283_) // to expression handler
+
+ Handle COMMA or SLASH. */
+
+static ffelexHandler
+ffestb_R5283_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R528_item_value (ffestb_local_.data.expr, ffesta_tokens[1],
+ expr, ft);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffeexpr_rhs
+ (ffesta_output_pool, FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_R5282_);
+
+ case FFELEX_typeSLASH:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R528_item_value (ffestb_local_.data.expr, ffesta_tokens[1],
+ expr, ft);
+ ffestc_R528_item_endvals (t);
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_R5284_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DATA", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R528_item_endvals (t);
+ ffestc_R528_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5284_ -- "DATA" expr-list SLASH expr-list SLASH
+
+ return ffestb_R5284_; // to lexer
+
+ Handle [COMMA] NAME or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_R5284_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_R5281_);
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeOPEN_PAREN:
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_R5281_)))
+ (t);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R528_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DATA", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R528_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R537 -- Parse a PARAMETER statement
+
+ return ffestb_R537; // to lexer
+
+ Make sure the statement has a valid form for an PARAMETER statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R537 (ffelexToken t)
+{
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstPARAMETER)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstPARAMETER)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlPARAMETER)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ ffestb_local_.parameter.started = FALSE;
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextPARAMETER,
+ (ffeexprCallback) ffestb_R5371_);
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PARAMETER", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PARAMETER", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R5371_ -- "PARAMETER" OPEN_PAREN expr
+
+ (ffestb_R5371_) // to expression handler
+
+ Make sure the next token is EQUALS. */
+
+static ffelexHandler
+ffestb_R5371_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffestb_local_.parameter.expr = expr;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (expr == NULL)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextPARAMETER, (ffeexprCallback) ffestb_R5372_);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PARAMETER", t);
+ if (ffestb_local_.parameter.started)
+ ffestc_R537_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5372_ -- "PARAMETER" OPEN_PAREN expr EQUALS expr
+
+ (ffestb_R5372_) // to expression handler
+
+ Make sure the next token is COMMA or CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_R5372_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.parameter.started)
+ {
+ ffestc_R537_start ();
+ ffestb_local_.parameter.started = TRUE;
+ }
+ ffestc_R537_item (ffestb_local_.parameter.expr, ffesta_tokens[1],
+ expr, ft);
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextPARAMETER,
+ (ffeexprCallback) ffestb_R5371_);
+
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.parameter.started)
+ {
+ ffestc_R537_start ();
+ ffestb_local_.parameter.started = TRUE;
+ }
+ ffestc_R537_item (ffestb_local_.parameter.expr, ffesta_tokens[1],
+ expr, ft);
+ ffestc_R537_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_R5373_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PARAMETER", t);
+ if (ffestb_local_.parameter.started)
+ ffestc_R537_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5373_ -- "PARAMETER" OPEN_PAREN expr EQUALS expr CLOSE_PAREN
+
+ return ffestb_R5373_; // to lexer
+
+ Make sure the next token is EOS or SEMICOLON, or generate an error. All
+ cleanup has already been done, by the way. */
+
+static ffelexHandler
+ffestb_R5373_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PARAMETER", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R542 -- Parse the NAMELIST statement
+
+ return ffestb_R542; // to lexer
+
+ Make sure the statement has a valid form for the NAMELIST statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_R542 (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstNAMELIST)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstNAMELIST)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlNAMELIST);
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeSLASH:
+ break;
+ }
+
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R542_start ();
+ return (ffelexHandler) ffestb_R5421_;
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NAMELIST", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NAMELIST", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "NAMELIST", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5421_ -- "NAMELIST" SLASH
+
+ return ffestb_R5421_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_R5421_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (!ffesta_is_inhibited ())
+ ffestc_R542_item_nlist (t);
+ return (ffelexHandler) ffestb_R5422_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NAMELIST", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R542_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5422_ -- "NAMELIST" SLASH NAME
+
+ return ffestb_R5422_; // to lexer
+
+ Handle SLASH. */
+
+static ffelexHandler
+ffestb_R5422_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeSLASH:
+ return (ffelexHandler) ffestb_R5423_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NAMELIST", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R542_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5423_ -- "NAMELIST" SLASH NAME SLASH
+
+ return ffestb_R5423_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_R5423_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (!ffesta_is_inhibited ())
+ ffestc_R542_item_nitem (t);
+ return (ffelexHandler) ffestb_R5424_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NAMELIST", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R542_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5424_ -- "NAMELIST" SLASH NAME SLASH NAME
+
+ return ffestb_R5424_; // to lexer
+
+ Handle COMMA, EOS/SEMICOLON, or SLASH. */
+
+static ffelexHandler
+ffestb_R5424_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R5425_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R542_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeSLASH:
+ return (ffelexHandler) ffestb_R5421_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NAMELIST", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R542_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5425_ -- "NAMELIST" SLASH NAME SLASH NAME COMMA
+
+ return ffestb_R5425_; // to lexer
+
+ Handle NAME or SLASH. */
+
+static ffelexHandler
+ffestb_R5425_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (!ffesta_is_inhibited ())
+ ffestc_R542_item_nitem (t);
+ return (ffelexHandler) ffestb_R5424_;
+
+ case FFELEX_typeSLASH:
+ return (ffelexHandler) ffestb_R5421_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NAMELIST", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R542_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R544 -- Parse an EQUIVALENCE statement
+
+ return ffestb_R544; // to lexer
+
+ Make sure the statement has a valid form for an EQUIVALENCE statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R544 (ffelexToken t)
+{
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstEQUIVALENCE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstEQUIVALENCE)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlEQUIVALENCE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ ffestb_local_.equivalence.started = FALSE;
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextEQUIVALENCE,
+ (ffeexprCallback) ffestb_R5441_);
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "EQUIVALENCE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "EQUIVALENCE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R5441_ -- "EQUIVALENCE" OPEN_PAREN expr
+
+ (ffestb_R5441_) // to expression handler
+
+ Make sure the next token is COMMA. */
+
+static ffelexHandler
+ffestb_R5441_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ ffestb_local_.equivalence.exprs = ffestt_exprlist_create ();
+ ffestt_exprlist_append (ffestb_local_.equivalence.exprs, expr,
+ ffelex_token_use (ft));
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextEQUIVALENCE,
+ (ffeexprCallback) ffestb_R5442_);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "EQUIVALENCE", t);
+ if (ffestb_local_.equivalence.started)
+ ffestc_R544_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5442_ -- "EQUIVALENCE" OPEN_PAREN expr COMMA expr
+
+ (ffestb_R5442_) // to expression handler
+
+ Make sure the next token is COMMA or CLOSE_PAREN. For COMMA, we just
+ append the expression to our list and continue; for CLOSE_PAREN, we
+ append the expression and move to _3_. */
+
+static ffelexHandler
+ffestb_R5442_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ ffestt_exprlist_append (ffestb_local_.equivalence.exprs, expr,
+ ffelex_token_use (ft));
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextEQUIVALENCE,
+ (ffeexprCallback) ffestb_R5442_);
+
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestt_exprlist_append (ffestb_local_.equivalence.exprs, expr,
+ ffelex_token_use (ft));
+ return (ffelexHandler) ffestb_R5443_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "EQUIVALENCE", t);
+ if (ffestb_local_.equivalence.started)
+ ffestc_R544_finish ();
+ ffestt_exprlist_kill (ffestb_local_.equivalence.exprs);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5443_ -- "EQUIVALENCE" OPEN_PAREN expr COMMA expr CLOSE_PAREN
+
+ return ffestb_R5443_; // to lexer
+
+ Make sure the next token is COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_R5443_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.equivalence.started)
+ {
+ ffestc_R544_start ();
+ ffestb_local_.equivalence.started = TRUE;
+ }
+ ffestc_R544_item (ffestb_local_.equivalence.exprs);
+ }
+ ffestt_exprlist_kill (ffestb_local_.equivalence.exprs);
+ return (ffelexHandler) ffestb_R5444_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.equivalence.started)
+ {
+ ffestc_R544_start ();
+ ffestb_local_.equivalence.started = TRUE;
+ }
+ ffestc_R544_item (ffestb_local_.equivalence.exprs);
+ ffestc_R544_finish ();
+ }
+ ffestt_exprlist_kill (ffestb_local_.equivalence.exprs);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "EQUIVALENCE", t);
+ if (ffestb_local_.equivalence.started)
+ ffestc_R544_finish ();
+ ffestt_exprlist_kill (ffestb_local_.equivalence.exprs);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5444_ -- "EQUIVALENCE" OPEN_PAREN expr COMMA expr CLOSE_PAREN COMMA
+
+ return ffestb_R5444_; // to lexer
+
+ Make sure the next token is OPEN_PAREN, or generate an error. */
+
+static ffelexHandler
+ffestb_R5444_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextEQUIVALENCE,
+ (ffeexprCallback) ffestb_R5441_);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "EQUIVALENCE", t);
+ if (ffestb_local_.equivalence.started)
+ ffestc_R544_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R834 -- Parse the CYCLE statement
+
+ return ffestb_R834; // to lexer
+
+ Make sure the statement has a valid form for the CYCLE statement. If
+ it does, implement the statement. */
+
+ffelexHandler
+ffestb_R834 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstCYCLE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R8341_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_R8341_ (t);
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstCYCLE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+ }
+ ffesta_confirmed ();
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlCYCLE);
+ if (*p == '\0')
+ {
+ ffesta_tokens[1] = NULL;
+ }
+ else
+ {
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ }
+ return (ffelexHandler) ffestb_R8341_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CYCLE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CYCLE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "CYCLE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8341_ -- "CYCLE" [NAME]
+
+ return ffestb_R8341_; // to lexer
+
+ Make sure the next token is an EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_R8341_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R834 (ffesta_tokens[1]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CYCLE", t);
+ break;
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R835 -- Parse the EXIT statement
+
+ return ffestb_R835; // to lexer
+
+ Make sure the statement has a valid form for the EXIT statement. If
+ it does, implement the statement. */
+
+ffelexHandler
+ffestb_R835 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstEXIT)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R8351_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_R8351_ (t);
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstEXIT)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+ }
+ ffesta_confirmed ();
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlEXIT);
+ if (*p == '\0')
+ {
+ ffesta_tokens[1] = NULL;
+ }
+ else
+ {
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ }
+ return (ffelexHandler) ffestb_R8351_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "EXIT", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "EXIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "EXIT", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8351_ -- "EXIT" [NAME]
+
+ return ffestb_R8351_; // to lexer
+
+ Make sure the next token is an EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_R8351_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R835 (ffesta_tokens[1]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "EXIT", t);
+ break;
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R838 -- Parse the ASSIGN statement
+
+ return ffestb_R838; // to lexer
+
+ Make sure the statement has a valid form for the ASSIGN statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_R838 (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+ ffelexHandler next;
+ ffelexToken et; /* First token in target. */
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstASSIGN)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNUMBER:
+ break;
+ }
+ ffesta_tokens[1] = ffelex_token_use (t);
+ ffesta_confirmed ();
+ return (ffelexHandler) ffestb_R8381_;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstASSIGN)
+ goto bad_0; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ /* Fall through. */
+ case FFELEX_typePERCENT:
+ case FFELEX_typeOPEN_PAREN:
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlASSIGN);
+ if (! ISDIGIT (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1]
+ = ffelex_token_number_from_names (ffesta_tokens[0], i);
+ p += ffelex_token_length (ffesta_tokens[1]); /* Skip to "TO". */
+ i += ffelex_token_length (ffesta_tokens[1]);
+ if (!ffesrc_char_match_init (*p, 'T', 't') /* "TO". */
+ || (++i, !ffesrc_char_match_noninit (*++p, 'O', 'o')))
+ {
+ bad_i_1: /* :::::::::::::::::::: */
+ ffelex_token_kill (ffesta_tokens[1]);
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ ++p, ++i;
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i_1; /* :::::::::::::::::::: */
+ et = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ next = (ffelexHandler)
+ (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextASSIGN,
+ (ffeexprCallback)
+ ffestb_R8383_)))
+ (et);
+ ffelex_token_kill (et);
+ return (ffelexHandler) (*next) (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ASSIGN", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid first token. */
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ASSIGN", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "ASSIGN", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8381_ -- "ASSIGN" NUMBER
+
+ return ffestb_R8381_; // to lexer
+
+ Make sure the next token is "TO". */
+
+static ffelexHandler
+ffestb_R8381_ (ffelexToken t)
+{
+ if ((ffelex_token_type (t) == FFELEX_typeNAME)
+ && (ffesrc_strcmp_2c (ffe_case_match (), ffelex_token_text (t), "TO", "to",
+ "To") == 0))
+ {
+ return (ffelexHandler) ffestb_R8382_;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ASSIGN", t);
+ if (ffelex_token_type (t) == FFELEX_typeNAME)
+ return (ffelexHandler) ffestb_R8382_ (t); /* Maybe user forgot "TO". */
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8382_ -- "ASSIGN" NUMBER ("TO")
+
+ return ffestb_R8382_; // to lexer
+
+ Make sure the next token is a name, then pass it along to the expression
+ evaluator as an LHS expression. The callback function is _3_. */
+
+static ffelexHandler
+ffestb_R8382_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) == FFELEX_typeNAME)
+ {
+ return (ffelexHandler)
+ (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool, FFEEXPR_contextASSIGN,
+ (ffeexprCallback) ffestb_R8383_)))
+ (t);
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ASSIGN", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8383_ -- "ASSIGN" NUMBER ("TO") expression
+
+ (ffestb_R8383_) // to expression handler
+
+ Make sure the next token is an EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_R8383_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R838 (ffesta_tokens[1], expr, ft);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ASSIGN", t);
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R840 -- Parse an arithmetic-IF statement
+
+ return ffestb_R840; // to lexer
+
+ Make sure the statement has a valid form for an arithmetic-IF statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R840 (ffelexToken t)
+{
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlIF)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffesta_first_kw != FFESTR_firstIF)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstIF)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool, FFEEXPR_contextARITHIF,
+ (ffeexprCallback) ffestb_R8401_);
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "arithmetic-IF", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "arithmetic-IF", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R8401_ -- "IF" OPEN_PAREN expr
+
+ (ffestb_R8401_) // to expression handler
+
+ Make sure the next token is CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_R8401_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ ffestb_local_.if_stmt.expr = expr;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ ffelex_set_names (TRUE); /* In case it's a logical IF instead. */
+ return (ffelexHandler) ffestb_R8402_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "arithmetic-IF", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8402_ -- "IF" OPEN_PAREN expr CLOSE_PAREN
+
+ return ffestb_R8402_; // to lexer
+
+ Make sure the next token is NUMBER. */
+
+static ffelexHandler
+ffestb_R8402_ (ffelexToken t)
+{
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed ();
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R8403_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "arithmetic-IF", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8403_ -- "IF" OPEN_PAREN expr CLOSE_PAREN NUMBER
+
+ return ffestb_R8403_; // to lexer
+
+ Make sure the next token is COMMA. */
+
+static ffelexHandler
+ffestb_R8403_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R8404_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "arithmetic-IF", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8404_ -- "IF" OPEN_PAREN expr CLOSE_PAREN NUMBER COMMA
+
+ return ffestb_R8404_; // to lexer
+
+ Make sure the next token is NUMBER. */
+
+static ffelexHandler
+ffestb_R8404_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffesta_tokens[3] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R8405_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "arithmetic-IF", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8405_ -- "IF" OPEN_PAREN expr CLOSE_PAREN NUMBER COMMA NUMBER
+
+ return ffestb_R8405_; // to lexer
+
+ Make sure the next token is COMMA. */
+
+static ffelexHandler
+ffestb_R8405_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R8406_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "arithmetic-IF", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8406_ -- "IF" OPEN_PAREN expr CLOSE_PAREN NUMBER COMMA NUMBER COMMA
+
+ return ffestb_R8406_; // to lexer
+
+ Make sure the next token is NUMBER. */
+
+static ffelexHandler
+ffestb_R8406_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffesta_tokens[4] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R8407_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "arithmetic-IF", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8407_ -- "IF" OPEN_PAREN expr CLOSE_PAREN NUMBER COMMA NUMBER COMMA
+ NUMBER
+
+ return ffestb_R8407_; // to lexer
+
+ Make sure the next token is EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_R8407_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R840 (ffestb_local_.if_stmt.expr, ffesta_tokens[1],
+ ffesta_tokens[2], ffesta_tokens[3], ffesta_tokens[4]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ ffelex_token_kill (ffesta_tokens[4]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "arithmetic-IF", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ ffelex_token_kill (ffesta_tokens[4]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R841 -- Parse the CONTINUE statement
+
+ return ffestb_R841; // to lexer
+
+ Make sure the statement has a valid form for the CONTINUE statement. If
+ it does, implement the statement. */
+
+ffelexHandler
+ffestb_R841 (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstCONTINUE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstCONTINUE)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlCONTINUE)
+ {
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlCONTINUE);
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R841 ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CONTINUE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid first token. */
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CONTINUE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "CONTINUE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R1102 -- Parse the PROGRAM statement
+
+ return ffestb_R1102; // to lexer
+
+ Make sure the statement has a valid form for the PROGRAM statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_R1102 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstPROGRAM)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ break;
+ }
+
+ ffesta_confirmed ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R11021_;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstPROGRAM)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+ }
+ ffesta_confirmed ();
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlPROGRAM);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ return (ffelexHandler) ffestb_R11021_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PROGRAM", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PROGRAM", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "PROGRAM", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R11021_ -- "PROGRAM" NAME
+
+ return ffestb_R11021_; // to lexer
+
+ Make sure the next token is an EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_R11021_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R1102 (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PROGRAM", t);
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_block -- Parse the BLOCK DATA statement
+
+ return ffestb_block; // to lexer
+
+ Make sure the statement has a valid form for the BLOCK DATA statement. If
+ it does, implement the statement. */
+
+ffelexHandler
+ffestb_block (ffelexToken t)
+{
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstBLOCK)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ if (ffesta_second_kw != FFESTR_secondDATA)
+ goto bad_1; /* :::::::::::::::::::: */
+ break;
+ }
+
+ ffesta_confirmed ();
+ return (ffelexHandler) ffestb_R1111_1_;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "BLOCK DATA", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "BLOCK DATA", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_blockdata -- Parse the BLOCKDATA statement
+
+ return ffestb_blockdata; // to lexer
+
+ Make sure the statement has a valid form for the BLOCKDATA statement. If
+ it does, implement the statement. */
+
+ffelexHandler
+ffestb_blockdata (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstBLOCKDATA)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R1111_2_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_R1111_2_ (t);
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstBLOCKDATA)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+ }
+ ffesta_confirmed ();
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlBLOCKDATA);
+ if (*p == '\0')
+ {
+ ffesta_tokens[1] = NULL;
+ }
+ else
+ {
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ }
+ return (ffelexHandler) ffestb_R1111_2_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "BLOCK DATA", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "BLOCK DATA", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "BLOCK DATA", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R1111_1_ -- "BLOCK" "DATA"
+
+ return ffestb_R1111_1_; // to lexer
+
+ Make sure the next token is a NAME, EOS, or SEMICOLON token. */
+
+static ffelexHandler
+ffestb_R1111_1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R1111_2_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_R1111_2_ (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "BLOCK DATA", t);
+ break;
+ }
+
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R1111_2_ -- "BLOCK/DATA" NAME
+
+ return ffestb_R1111_2_; // to lexer
+
+ Make sure the next token is an EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_R1111_2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R1111 (ffesta_tokens[1]);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "BLOCK DATA", t);
+ break;
+ }
+
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R1212 -- Parse the CALL statement
+
+ return ffestb_R1212; // to lexer
+
+ Make sure the statement has a valid form for the CALL statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_R1212 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstCALL)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ break;
+ }
+ ffesta_confirmed ();
+ return (ffelexHandler)
+ (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool, FFEEXPR_contextSUBROUTINEREF,
+ (ffeexprCallback) ffestb_R12121_)))
+ (t);
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstCALL)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+ }
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlCALL);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ next = (ffelexHandler)
+ (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool, FFEEXPR_contextSUBROUTINEREF,
+ (ffeexprCallback) ffestb_R12121_)))
+ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CALL", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CALL", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "CALL", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R12121_ -- "CALL" expr
+
+ (ffestb_R12121_) // to expression handler
+
+ Make sure the statement has a valid form for the CALL statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R12121_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R1212 (expr, ft);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CALL", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R1227 -- Parse the RETURN statement
+
+ return ffestb_R1227; // to lexer
+
+ Make sure the statement has a valid form for the RETURN statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_R1227 (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstRETURN)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed ();
+ break;
+
+ default:
+ break;
+ }
+
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool, FFEEXPR_contextRETURN,
+ (ffeexprCallback) ffestb_R12271_)))
+ (t);
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstRETURN)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+
+ default:
+ break;
+ }
+ next = (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextRETURN, (ffeexprCallback) ffestb_R12271_);
+ next = (ffelexHandler) ffelex_splice_tokens (next, ffesta_tokens[0],
+ FFESTR_firstlRETURN);
+ if (next == NULL)
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RETURN", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RETURN", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R12271_ -- "RETURN" expr
+
+ (ffestb_R12271_) // to expression handler
+
+ Make sure the next token is an EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_R12271_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R1227 (expr, ft);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RETURN", t);
+ break;
+ }
+
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R1228 -- Parse the CONTAINS statement
+
+ return ffestb_R1228; // to lexer
+
+ Make sure the statement has a valid form for the CONTAINS statement. If
+ it does, implement the statement. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_R1228 (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstCONTAINS)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstCONTAINS)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlCONTAINS)
+ {
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlCONTAINS);
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R1228 ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CONTAINS", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid first token. */
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CONTAINS", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "CONTAINS", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_V009 -- Parse the UNION statement
+
+ return ffestb_V009; // to lexer
+
+ Make sure the statement has a valid form for the UNION statement. If
+ it does, implement the statement. */
+
+#if FFESTR_VXT
+ffelexHandler
+ffestb_V009 (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstUNION)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstUNION)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlUNION)
+ {
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlUNION);
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V009 ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "UNION", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid first token. */
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "UNION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "UNION", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_construct -- Parse a construct name
+
+ return ffestb_construct; // to lexer
+
+ Make sure the statement can have a construct name (if-then-stmt, do-stmt,
+ select-case-stmt). */
+
+ffelexHandler
+ffestb_construct (ffelexToken t UNUSED)
+{
+ /* This handler gets invoked only when token 0 is NAME/NAMES and token 1 is
+ COLON. */
+
+ ffesta_confirmed ();
+ ffelex_set_names (TRUE);
+ return (ffelexHandler) ffestb_construct1_;
+}
+
+/* ffestb_construct1_ -- NAME COLON
+
+ return ffestb_construct1_; // to lexer
+
+ Make sure we've got a NAME that is DO, DOWHILE, IF, SELECT, or SELECTCASE. */
+
+static ffelexHandler
+ffestb_construct1_ (ffelexToken t)
+{
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_first_kw = ffestr_first (t);
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstIF:
+ ffestb_local_.construct.next = (ffelexHandler) ffestb_if;
+ break;
+
+ case FFESTR_firstDO:
+ ffestb_local_.construct.next = (ffelexHandler) ffestb_do;
+ break;
+
+ case FFESTR_firstDOWHILE:
+ ffestb_local_.construct.next = (ffelexHandler) ffestb_dowhile;
+ break;
+
+ case FFESTR_firstSELECT:
+ case FFESTR_firstSELECTCASE:
+ ffestb_local_.construct.next = (ffelexHandler) ffestb_R809;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ ffesta_construct_name = ffesta_tokens[0];
+ ffesta_tokens[0] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_construct2_;
+
+ case FFELEX_typeNAMES:
+ ffesta_first_kw = ffestr_first (t);
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstIF:
+ if (ffelex_token_length (t) != FFESTR_firstlIF)
+ goto bad; /* :::::::::::::::::::: */
+ ffestb_local_.construct.next = (ffelexHandler) ffestb_if;
+ break;
+
+ case FFESTR_firstDO:
+ ffestb_local_.construct.next = (ffelexHandler) ffestb_do;
+ break;
+
+ case FFESTR_firstDOWHILE:
+ if (ffelex_token_length (t) != FFESTR_firstlDOWHILE)
+ goto bad; /* :::::::::::::::::::: */
+ ffestb_local_.construct.next = (ffelexHandler) ffestb_dowhile;
+ break;
+
+ case FFESTR_firstSELECTCASE:
+ if (ffelex_token_length (t) != FFESTR_firstlSELECTCASE)
+ goto bad; /* :::::::::::::::::::: */
+ ffestb_local_.construct.next = (ffelexHandler) ffestb_R809;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ ffesta_construct_name = ffesta_tokens[0];
+ ffesta_tokens[0] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_construct2_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_2st (FFEBAD_INVALID_STMT_FORM, "CONSTRUCT",
+ ffesta_tokens[0], t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_construct2_ -- NAME COLON "DO/DOWHILE/IF/SELECT/SELECTCASE"
+
+ return ffestb_construct2_; // to lexer
+
+ This extra step is needed to set ffesta_second_kw if the second token
+ (here) is a NAME, so DO and SELECT can continue to expect it. */
+
+static ffelexHandler
+ffestb_construct2_ (ffelexToken t)
+{
+ if (ffelex_token_type (t) == FFELEX_typeNAME)
+ ffesta_second_kw = ffestr_second (t);
+ return (ffelexHandler) (*ffestb_local_.construct.next) (t);
+}
+
+/* ffestb_heap -- Parse an ALLOCATE/DEALLOCATE statement
+
+ return ffestb_heap; // to lexer
+
+ Make sure the statement has a valid form for an ALLOCATE/DEALLOCATE
+ statement. If it does, implement the statement. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_heap (ffelexToken t)
+{
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffelex_token_length (ffesta_tokens[0]) != ffestb_args.heap.len)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ ffestb_local_.heap.exprs = ffestt_exprlist_create ();
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_args.heap.ctx,
+ (ffeexprCallback) ffestb_heap1_);
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.heap.badname, ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.heap.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_heap1_ -- "ALLOCATE/DEALLOCATE" OPEN_PAREN expr
+
+ (ffestb_heap1_) // to expression handler
+
+ Make sure the next token is COMMA. */
+
+static ffelexHandler
+ffestb_heap1_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ ffestt_exprlist_append (ffestb_local_.heap.exprs, expr,
+ ffelex_token_use (t));
+ return (ffelexHandler) ffestb_heap2_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestt_exprlist_append (ffestb_local_.heap.exprs, expr,
+ ffelex_token_use (t));
+ ffesta_tokens[1] = NULL;
+ ffestb_local_.heap.expr = NULL;
+ return (ffelexHandler) ffestb_heap5_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.heap.badname, t);
+ ffestt_exprlist_kill (ffestb_local_.heap.exprs);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_heap2_ -- "ALLOCATE/DEALLOCATE" OPEN_PAREN expr COMMA
+
+ return ffestb_heap2_; // to lexer
+
+ Make sure the next token is NAME. */
+
+static ffelexHandler
+ffestb_heap2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_heap3_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.heap.badname, t);
+ ffestt_exprlist_kill (ffestb_local_.heap.exprs);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_heap3_ -- "ALLOCATE/DEALLOCATE" OPEN_PAREN expr COMMA NAME
+
+ return ffestb_heap3_; // to lexer
+
+ If token is EQUALS, make sure NAME was "STAT" and handle STAT variable;
+ else pass NAME and token to expression handler. */
+
+static ffelexHandler
+ffestb_heap3_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestr_other (ffesta_tokens[1]) != FFESTR_otherSTAT)
+ break;
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextHEAPSTAT,
+ (ffeexprCallback) ffestb_heap4_);
+
+ default:
+ next = (ffelexHandler)
+ (*((ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_args.heap.ctx,
+ (ffeexprCallback) ffestb_heap1_)))
+ (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) (*next) (t);
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.heap.badname, t);
+ ffestt_exprlist_kill (ffestb_local_.heap.exprs);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_heap4_ -- "ALLOCATE/DEALLOCATE" OPEN_PAREN ... COMMA "STAT" EQUALS
+ expr
+
+ (ffestb_heap4_) // to expression handler
+
+ Make sure the next token is CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_heap4_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ ffestb_local_.heap.expr = expr;
+ return (ffelexHandler) ffestb_heap5_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.heap.badname, t);
+ ffestt_exprlist_kill (ffestb_local_.heap.exprs);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_heap5_ -- "ALLOCATE/DEALLOCATE" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_heap5_; // to lexer
+
+ Make sure the next token is EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_heap5_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ if (ffesta_first_kw == FFESTR_firstALLOCATE)
+ ffestc_R620 (ffestb_local_.heap.exprs, ffestb_local_.heap.expr,
+ ffesta_tokens[1]);
+ else
+ ffestc_R625 (ffestb_local_.heap.exprs, ffestb_local_.heap.expr,
+ ffesta_tokens[1]);
+ ffestt_exprlist_kill (ffestb_local_.heap.exprs);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.heap.badname, t);
+ ffestt_exprlist_kill (ffestb_local_.heap.exprs);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_module -- Parse the MODULEPROCEDURE statement
+
+ return ffestb_module; // to lexer
+
+ Make sure the statement has a valid form for the MODULEPROCEDURE statement.
+ If it does, implement the statement.
+
+ 31-May-90 JCB 1.1
+ Confirm NAME==MODULE followed by standard four invalid tokens, so we
+ get decent message if somebody forgets that MODULE requires a name. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_module (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffelexToken mt; /* Name in MODULE PROCEDUREname, i.e.
+ includes "PROCEDURE". */
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstMODULE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ break;
+
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ goto bad_1m; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1m; /* :::::::::::::::::::: */
+ }
+
+ ffesta_confirmed ();
+ if (ffesta_second_kw != FFESTR_secondPROCEDURE)
+ {
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_module3_;
+ }
+ ffestb_local_.moduleprocedure.started = FALSE;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_module1_;
+
+ case FFELEX_typeNAMES:
+ p = ffelex_token_text (ffesta_tokens[0])
+ + (i = FFESTR_firstlMODULEPROCEDURE);
+ if ((ffesta_first_kw == FFESTR_firstMODULE)
+ || ((ffesta_first_kw == FFESTR_firstMODULEPROCEDURE)
+ && !ffesrc_is_name_init (*p)))
+ { /* Definitely not "MODULE PROCEDURE name". */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1m; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1m; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+ }
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlMODULE);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_im; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ if (!ffesta_is_inhibited ())
+ ffestc_R1105 (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) ffesta_zero (t);
+ }
+
+ /* Here we know that we're indeed looking at a MODULEPROCEDURE
+ statement rather than MODULE and that the character following
+ MODULEPROCEDURE in the NAMES token is a valid first character for a
+ NAME. This means that unless the second token is COMMA, we have an
+ ambiguous statement that can be read either as MODULE PROCEDURE name
+ or MODULE PROCEDUREname, the former being an R1205, the latter an
+ R1105. */
+
+ if (ffesta_first_kw != FFESTR_firstMODULEPROCEDURE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOMMA: /* Aha, clearly not MODULE PROCEDUREname. */
+ ffesta_confirmed ();
+ ffestb_local_.moduleprocedure.started = FALSE;
+ ffesta_tokens[1]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ return (ffelexHandler) ffestb_module2_ (t);
+
+ case FFELEX_typeEOS: /* MODULE PROCEDURE name or MODULE
+ PROCEDUREname. */
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+ }
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ mt = ffelex_token_name_from_names (ffesta_tokens[0], FFESTR_firstlMODULE,
+ 0);
+ if (!ffesta_is_inhibited ())
+ ffestc_module (mt, nt); /* Implement ambiguous statement. */
+ ffelex_token_kill (nt);
+ ffelex_token_kill (mt);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "MODULE PROCEDURE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "MODULE PROCEDURE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_1m: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "MODULE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_im: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "MODULE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_module1_ -- "MODULEPROCEDURE" or "MODULE" "PROCEDURE"
+
+ return ffestb_module1_; // to lexer
+
+ Make sure the statement has a valid form for the MODULEPROCEDURE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_module1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (!ffestb_local_.moduleprocedure.started
+ && (ffelex_token_type (ffesta_tokens[0]) == FFELEX_typeNAME))
+ {
+ ffesta_confirmed ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ }
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_module2_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (ffestb_local_.moduleprocedure.started)
+ break; /* Error if we've already seen NAME COMMA. */
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R1105 (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ break;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.moduleprocedure.started && !ffesta_is_inhibited ())
+ ffestc_R1205_finish ();
+ else if (!ffestb_local_.moduleprocedure.started)
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "MODULE PROCEDURE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_module2_ -- "MODULE/PROCEDURE" NAME
+
+ return ffestb_module2_; // to lexer
+
+ Make sure the statement has a valid form for the MODULEPROCEDURE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_module2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffestb_local_.moduleprocedure.started)
+ {
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R1205_start ();
+ }
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R1205_item (ffesta_tokens[1]);
+ ffestc_R1205_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ if (!ffestb_local_.moduleprocedure.started)
+ {
+ ffestb_local_.moduleprocedure.started = TRUE;
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R1205_start ();
+ }
+ if (!ffesta_is_inhibited ())
+ ffestc_R1205_item (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_module1_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.moduleprocedure.started && !ffesta_is_inhibited ())
+ ffestc_R1205_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "MODULE PROCEDURE", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_module3_ -- "MODULE" NAME
+
+ return ffestb_module3_; // to lexer
+
+ Make sure the statement has a valid form for the MODULE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_module3_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1105 (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "MODULE", t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_R809 -- Parse the SELECTCASE statement
+
+ return ffestb_R809; // to lexer
+
+ Make sure the statement has a valid form for the SELECTCASE statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R809 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstSELECT:
+ if ((ffelex_token_type (t) != FFELEX_typeNAME)
+ || (ffesta_second_kw != FFESTR_secondCASE))
+ goto bad_1; /* :::::::::::::::::::: */
+ ffesta_confirmed ();
+ return (ffelexHandler) ffestb_R8091_;
+
+ case FFESTR_firstSELECTCASE:
+ return (ffelexHandler) ffestb_R8091_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstSELECTCASE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ break;
+ }
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlSELECTCASE);
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ return (ffelexHandler) ffestb_R8091_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SELECT CASE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SELECT CASE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "SELECT CASE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8091_ -- "SELECTCASE" or "SELECT" "CASE"
+
+ return ffestb_R8091_; // to lexer
+
+ Make sure the statement has a valid form for the SELECTCASE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R8091_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextSELECTCASE, (ffeexprCallback) ffestb_R8092_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ break;
+
+ default:
+ break;
+ }
+
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SELECT CASE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8092_ -- "SELECT/CASE" OPEN_PAREN expr
+
+ (ffestb_R8092_) // to expression handler
+
+ Make sure the statement has a valid form for the SELECTCASE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R8092_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ ffestb_local_.selectcase.expr = expr;
+ return (ffelexHandler) ffestb_R8093_;
+
+ default:
+ break;
+ }
+
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SELECT CASE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8093_ -- "SELECT/CASE" OPEN_PAREN expr CLOSE_PAREN
+
+ return ffestb_R8093_; // to lexer
+
+ Make sure the statement has a valid form for the SELECTCASE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R8093_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R809 (ffesta_construct_name, ffestb_local_.selectcase.expr,
+ ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ return ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ break;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffesta_construct_name != NULL)
+ {
+ ffelex_token_kill (ffesta_construct_name);
+ ffesta_construct_name = NULL;
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "SELECT CASE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R810 -- Parse the CASE statement
+
+ return ffestb_R810; // to lexer
+
+ Make sure the statement has a valid form for the CASE statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R810 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstCASE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ if (ffesta_second_kw != FFESTR_secondDEFAULT)
+ goto bad_1; /* :::::::::::::::::::: */
+ ffestb_local_.case_stmt.cases = NULL;
+ return (ffelexHandler) ffestb_R8101_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.case_stmt.cases = ffestt_caselist_create ();
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCASE, (ffeexprCallback) ffestb_R8103_);
+ }
+
+ case FFELEX_typeNAMES:
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstCASEDEFAULT:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+ }
+ ffestb_local_.case_stmt.cases = NULL;
+ p = ffelex_token_text (ffesta_tokens[0])
+ + (i = FFESTR_firstlCASEDEFAULT);
+ if (*p == '\0')
+ return (ffelexHandler) ffestb_R8101_ (t);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1] = ffelex_token_name_from_names (ffesta_tokens[0], i,
+ 0);
+ return (ffelexHandler) ffestb_R8102_ (t);
+
+ case FFESTR_firstCASE:
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ break;
+ }
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlCASE);
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ ffestb_local_.case_stmt.cases = ffestt_caselist_create ();
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCASE, (ffeexprCallback) ffestb_R8103_);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CASE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CASE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "CASE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8101_ -- "CASE" case-selector
+
+ return ffestb_R8101_; // to lexer
+
+ Make sure the statement has a valid form for the CASE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R8101_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R8102_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_tokens[1] = NULL;
+ return (ffelexHandler) ffestb_R8102_ (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ break;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.case_stmt.cases != NULL)
+ ffestt_caselist_kill (ffestb_local_.case_stmt.cases);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CASE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8102_ -- "CASE" case-selector [NAME]
+
+ return ffestb_R8102_; // to lexer
+
+ Make sure the statement has a valid form for the CASE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R8102_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R810 (ffestb_local_.case_stmt.cases, ffesta_tokens[1]);
+ if (ffestb_local_.case_stmt.cases != NULL)
+ ffestt_caselist_kill (ffestb_local_.case_stmt.cases);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ break;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.case_stmt.cases != NULL)
+ ffestt_caselist_kill (ffestb_local_.case_stmt.cases);
+ if (ffesta_tokens[1] != NULL)
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CASE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8103_ -- "CASE" OPEN_PAREN expr
+
+ (ffestb_R8103_) // to expression handler
+
+ Make sure the statement has a valid form for the CASE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R8103_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffestt_caselist_append (ffestb_local_.case_stmt.cases, FALSE, expr, NULL,
+ ffelex_token_use (ft));
+ return (ffelexHandler) ffestb_R8101_;
+
+ case FFELEX_typeCOMMA:
+ ffestt_caselist_append (ffestb_local_.case_stmt.cases, FALSE, expr, NULL,
+ ffelex_token_use (ft));
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCASE, (ffeexprCallback) ffestb_R8103_);
+
+ case FFELEX_typeCOLON:
+ ffestt_caselist_append (ffestb_local_.case_stmt.cases, TRUE, expr, NULL,
+ ffelex_token_use (ft)); /* NULL second expr for
+ now, just plug in. */
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCASE, (ffeexprCallback) ffestb_R8104_);
+
+ default:
+ break;
+ }
+
+ ffestt_caselist_kill (ffestb_local_.case_stmt.cases);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CASE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R8104_ -- "CASE" OPEN_PAREN expr COLON expr
+
+ (ffestb_R8104_) // to expression handler
+
+ Make sure the statement has a valid form for the CASE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R8104_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffestb_local_.case_stmt.cases->previous->expr2 = expr;
+ return (ffelexHandler) ffestb_R8101_;
+
+ case FFELEX_typeCOMMA:
+ ffestb_local_.case_stmt.cases->previous->expr2 = expr;
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCASE, (ffeexprCallback) ffestb_R8103_);
+
+ default:
+ break;
+ }
+
+ ffestt_caselist_kill (ffestb_local_.case_stmt.cases);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CASE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R1001 -- Parse a FORMAT statement
+
+ return ffestb_R1001; // to lexer
+
+ Make sure the statement has a valid form for an FORMAT statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R1001 (ffelexToken t)
+{
+ ffesttFormatList f;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstFORMAT)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstFORMAT)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlFORMAT)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.format.complained = FALSE;
+ ffestb_local_.format.f = NULL; /* No parent yet. */
+ ffestb_local_.format.f = ffestt_formatlist_create (NULL,
+ ffelex_token_use (t));
+ ffelex_set_names_pure (TRUE); /* Have even free-form lexer give us
+ NAMES. */
+ return (ffelexHandler) ffestb_R10011_;
+
+ case FFELEX_typeOPEN_ARRAY:/* "(/". */
+ ffesta_confirmed ();
+ ffestb_local_.format.complained = FALSE;
+ ffestb_local_.format.f = ffestt_formatlist_create (NULL,
+ ffelex_token_use (t));
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeSLASH;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val.present = FALSE;
+ f->u.R1010.val.rtexpr = FALSE;
+ f->u.R1010.val.t = NULL;
+ f->u.R1010.val.u.unsigned_val = 1;
+ ffelex_set_names_pure (TRUE); /* Have even free-form lexer give us
+ NAMES. */
+ return (ffelexHandler) ffestb_R100112_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R10011_ -- "FORMAT" OPEN_PAREN expr
+
+ return ffestb_R10011_; // to lexer
+
+ For CLOSE_PAREN, wrap up the format list and if it is the top-level one,
+ exit. For anything else, pass it to _2_. */
+
+static ffelexHandler
+ffestb_R10011_ (ffelexToken t)
+{
+ ffesttFormatList f;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ break;
+
+ default:
+ return (ffelexHandler) ffestb_R10012_ (t);
+ }
+
+ /* If we have a format we're working on, continue working on it. */
+
+ f = ffestb_local_.format.f->u.root.parent;
+
+ if (f != NULL)
+ {
+ ffestb_local_.format.f = f->next;
+ return (ffelexHandler) ffestb_R100111_;
+ }
+
+ return (ffelexHandler) ffestb_R100114_;
+}
+
+/* ffestb_R10012_ -- "FORMAT" OPEN_PAREN [format-item-list]
+
+ return ffestb_R10012_; // to lexer
+
+ The initial state for a format-item. Here, just handle the initial
+ number, sign for number, or run-time expression. Also handle spurious
+ comma, close-paren (indicating spurious comma), close-array (like
+ close-paren but preceded by slash), and quoted strings. */
+
+static ffelexHandler
+ffestb_R10012_ (ffelexToken t)
+{
+ unsigned long unsigned_val;
+ ffesttFormatList f;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_ANGLE:
+ ffesta_confirmed ();
+ ffestb_local_.format.pre.t = ffelex_token_use (t);
+ ffelex_set_names_pure (FALSE);
+ if (!ffesta_seen_first_exec && !ffestb_local_.format.complained)
+ {
+ ffestb_local_.format.complained = TRUE;
+ ffebad_start (FFEBAD_FORMAT_EXPR_SPEC);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFORMAT, (ffeexprCallback) ffestb_R100115_);
+
+ case FFELEX_typeNUMBER:
+ ffestb_local_.format.sign = FALSE; /* No sign present. */
+ ffestb_local_.format.pre.present = TRUE;
+ ffestb_local_.format.pre.rtexpr = FALSE;
+ ffestb_local_.format.pre.t = ffelex_token_use (t);
+ ffestb_local_.format.pre.u.unsigned_val = unsigned_val
+ = strtoul (ffelex_token_text (t), NULL, 10);
+ ffelex_set_expecting_hollerith (unsigned_val, '\0',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ return (ffelexHandler) ffestb_R10014_;
+
+ case FFELEX_typePLUS:
+ ffestb_local_.format.sign = TRUE; /* Positive. */
+ ffestb_local_.format.pre.t = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R10013_;
+
+ case FFELEX_typeMINUS:
+ ffestb_local_.format.sign = FALSE; /* Negative. */
+ ffestb_local_.format.pre.t = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R10013_;
+
+ case FFELEX_typeCOLON:
+ case FFELEX_typeCOLONCOLON:/* "::". */
+ case FFELEX_typeSLASH:
+ case FFELEX_typeCONCAT: /* "//". */
+ case FFELEX_typeNAMES:
+ case FFELEX_typeDOLLAR:
+ case FFELEX_typeOPEN_PAREN:
+ case FFELEX_typeOPEN_ARRAY:/* "(/". */
+ ffestb_local_.format.sign = FALSE; /* No sign present. */
+ ffestb_local_.format.pre.present = FALSE;
+ ffestb_local_.format.pre.rtexpr = FALSE;
+ ffestb_local_.format.pre.t = NULL;
+ ffestb_local_.format.pre.u.unsigned_val = 1;
+ return (ffelexHandler) ffestb_R10014_ (t);
+
+ case FFELEX_typeCOMMA:
+ ffebad_start (FFEBAD_FORMAT_EXTRA_COMMA);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ return (ffelexHandler) ffestb_R10012_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ ffebad_start (FFEBAD_FORMAT_EXTRA_COMMA);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ f = ffestb_local_.format.f->u.root.parent;
+ if (f == NULL)
+ return (ffelexHandler) ffestb_R100114_;
+ ffestb_local_.format.f = f->next;
+ return (ffelexHandler) ffestb_R100111_;
+
+ case FFELEX_typeCLOSE_ARRAY: /* "/)". */
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeSLASH;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val.present = FALSE;
+ f->u.R1010.val.rtexpr = FALSE;
+ f->u.R1010.val.t = NULL;
+ f->u.R1010.val.u.unsigned_val = 1;
+ f = ffestb_local_.format.f->u.root.parent;
+ if (f == NULL)
+ return (ffelexHandler) ffestb_R100114_;
+ ffestb_local_.format.f = f->next;
+ return (ffelexHandler) ffestb_R100111_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffesta_ffebad_1t (FFEBAD_FORMAT_MISSING_PAREN, t);
+ for (f = ffestb_local_.format.f;
+ f->u.root.parent != NULL;
+ f = f->u.root.parent->next)
+ ;
+ ffestb_local_.format.f = f;
+ return (ffelexHandler) ffestb_R100114_ (t);
+
+ case FFELEX_typeQUOTE:
+ if (ffe_is_vxt ())
+ break; /* Error, probably something like FORMAT("17)
+ = X. */
+ ffelex_set_expecting_hollerith (-1, '\"',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t)); /* Don't have to unset
+ this one. */
+ return (ffelexHandler) ffestb_R100113_;
+
+ case FFELEX_typeAPOSTROPHE:
+#if 0 /* No apparent need for this, and not killed
+ anywhere. */
+ ffesta_tokens[1] = ffelex_token_use (t);
+#endif
+ ffelex_set_expecting_hollerith (-1, '\'',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t)); /* Don't have to unset
+ this one. */
+ return (ffelexHandler) ffestb_R100113_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R10013_ -- "FORMAT" OPEN_PAREN [format-item-list] PLUS/MINUS
+
+ return ffestb_R10013_; // to lexer
+
+ Expect a NUMBER or complain about and then ignore the PLUS/MINUS. */
+
+static ffelexHandler
+ffestb_R10013_ (ffelexToken t)
+{
+ unsigned long unsigned_val;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestb_local_.format.pre.present = TRUE;
+ ffestb_local_.format.pre.rtexpr = FALSE;
+ unsigned_val = strtoul (ffelex_token_text (t), NULL, 10);
+ ffestb_local_.format.pre.u.signed_val = ffestb_local_.format.sign
+ ? unsigned_val : -unsigned_val;
+ ffestb_local_.format.sign = TRUE; /* Sign present. */
+ return (ffelexHandler) ffestb_R10014_;
+
+ default:
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_SIGN);
+ ffebad_here (0, ffelex_token_where_line (ffestb_local_.format.pre.t),
+ ffelex_token_where_column (ffestb_local_.format.pre.t));
+ ffebad_finish ();
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ return (ffelexHandler) ffestb_R10012_ (t);
+ }
+}
+
+/* ffestb_R10014_ -- "FORMAT" OPEN_PAREN [format-item-list] [[+/-] NUMBER]
+
+ return ffestb_R10014_; // to lexer
+
+ Here is where we expect to see the actual NAMES, COLON, SLASH, OPEN_PAREN,
+ OPEN_ARRAY, COLONCOLON, CONCAT, DOLLAR, or HOLLERITH that identifies what
+ kind of format-item we're dealing with. But if we see a NUMBER instead, it
+ means free-form spaces number like "5 6 X", so scale the current number
+ accordingly and reenter this state. (I really wouldn't be surprised if
+ they change this spacing rule in the F90 spec so that you can't embed
+ spaces within numbers or within keywords like BN in a free-source-form
+ program.) */
+
+static ffelexHandler
+ffestb_R10014_ (ffelexToken t)
+{
+ ffesttFormatList f;
+ ffeTokenLength i;
+ char *p;
+ ffestrFormat kw;
+
+ ffelex_set_expecting_hollerith (0, '\0',
+ ffewhere_line_unknown (),
+ ffewhere_column_unknown ());
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeHOLLERITH:
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeR1016;
+ f->t = ffelex_token_use (t);
+ ffelex_token_kill (ffestb_local_.format.pre.t); /* It WAS present! */
+ return (ffelexHandler) ffestb_R100111_;
+
+ case FFELEX_typeNUMBER:
+ assert (ffestb_local_.format.pre.present);
+ ffesta_confirmed ();
+ if (ffestb_local_.format.pre.rtexpr)
+ {
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_NUMBER);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ return (ffelexHandler) ffestb_R10014_;
+ }
+ if (ffestb_local_.format.sign)
+ {
+ for (i = ffelex_token_length (t) + 1; i > 0; --i)
+ ffestb_local_.format.pre.u.signed_val *= 10;
+ ffestb_local_.format.pre.u.signed_val += strtoul (ffelex_token_text (t),
+ NULL, 10);
+ }
+ else
+ {
+ for (i = ffelex_token_length (t) + 1; i > 0; --i)
+ ffestb_local_.format.pre.u.unsigned_val *= 10;
+ ffestb_local_.format.pre.u.unsigned_val += strtoul (ffelex_token_text (t),
+ NULL, 10);
+ ffelex_set_expecting_hollerith (ffestb_local_.format.pre.u.unsigned_val,
+ '\0',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ }
+ return (ffelexHandler) ffestb_R10014_;
+
+ case FFELEX_typeCOLONCOLON: /* "::". */
+ if (ffestb_local_.format.pre.present)
+ {
+ ffesta_ffebad_1t (FFEBAD_FORMAT_BAD_COLON_SPEC,
+ ffestb_local_.format.pre.t);
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ ffestb_local_.format.pre.present = FALSE;
+ }
+ else
+ {
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeCOLON;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val.present = FALSE;
+ f->u.R1010.val.rtexpr = FALSE;
+ f->u.R1010.val.t = NULL;
+ f->u.R1010.val.u.unsigned_val = 1;
+ }
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeCOLON;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val.present = FALSE;
+ f->u.R1010.val.rtexpr = FALSE;
+ f->u.R1010.val.t = NULL;
+ f->u.R1010.val.u.unsigned_val = 1;
+ return (ffelexHandler) ffestb_R100112_;
+
+ case FFELEX_typeCOLON:
+ if (ffestb_local_.format.pre.present)
+ {
+ ffesta_ffebad_1t (FFEBAD_FORMAT_BAD_COLON_SPEC,
+ ffestb_local_.format.pre.t);
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ return (ffelexHandler) ffestb_R100112_;
+ }
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeCOLON;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val.present = FALSE;
+ f->u.R1010.val.rtexpr = FALSE;
+ f->u.R1010.val.t = NULL;
+ f->u.R1010.val.u.unsigned_val = 1;
+ return (ffelexHandler) ffestb_R100112_;
+
+ case FFELEX_typeCONCAT: /* "//". */
+ if (ffestb_local_.format.sign)
+ {
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_SIGN);
+ ffebad_here (0, ffelex_token_where_line (ffestb_local_.format.pre.t),
+ ffelex_token_where_column (ffestb_local_.format.pre.t));
+ ffebad_finish ();
+ ffestb_local_.format.pre.u.unsigned_val
+ = (ffestb_local_.format.pre.u.signed_val < 0)
+ ? -ffestb_local_.format.pre.u.signed_val
+ : ffestb_local_.format.pre.u.signed_val;
+ }
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeSLASH;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val = ffestb_local_.format.pre;
+ ffestb_local_.format.pre.present = FALSE;
+ ffestb_local_.format.pre.rtexpr = FALSE;
+ ffestb_local_.format.pre.t = NULL;
+ ffestb_local_.format.pre.u.unsigned_val = 1;
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeSLASH;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val = ffestb_local_.format.pre;
+ return (ffelexHandler) ffestb_R100112_;
+
+ case FFELEX_typeSLASH:
+ if (ffestb_local_.format.sign)
+ {
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_SIGN);
+ ffebad_here (0, ffelex_token_where_line (ffestb_local_.format.pre.t),
+ ffelex_token_where_column (ffestb_local_.format.pre.t));
+ ffebad_finish ();
+ ffestb_local_.format.pre.u.unsigned_val
+ = (ffestb_local_.format.pre.u.signed_val < 0)
+ ? -ffestb_local_.format.pre.u.signed_val
+ : ffestb_local_.format.pre.u.signed_val;
+ }
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeSLASH;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val = ffestb_local_.format.pre;
+ return (ffelexHandler) ffestb_R100112_;
+
+ case FFELEX_typeOPEN_PAREN:
+ if (ffestb_local_.format.sign)
+ {
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_SIGN);
+ ffebad_here (0, ffelex_token_where_line (ffestb_local_.format.pre.t),
+ ffelex_token_where_column (ffestb_local_.format.pre.t));
+ ffebad_finish ();
+ ffestb_local_.format.pre.u.unsigned_val
+ = (ffestb_local_.format.pre.u.signed_val < 0)
+ ? -ffestb_local_.format.pre.u.signed_val
+ : ffestb_local_.format.pre.u.signed_val;
+ }
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeFORMAT;
+ f->t = ffelex_token_use (t);
+ f->u.R1003D.R1004 = ffestb_local_.format.pre;
+ f->u.R1003D.format = ffestb_local_.format.f
+ = ffestt_formatlist_create (f, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_R10011_;
+
+ case FFELEX_typeOPEN_ARRAY:/* "(/". */
+ if (ffestb_local_.format.sign)
+ {
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_SIGN);
+ ffebad_here (0, ffelex_token_where_line (ffestb_local_.format.pre.t),
+ ffelex_token_where_column (ffestb_local_.format.pre.t));
+ ffebad_finish ();
+ ffestb_local_.format.pre.u.unsigned_val
+ = (ffestb_local_.format.pre.u.signed_val < 0)
+ ? -ffestb_local_.format.pre.u.signed_val
+ : ffestb_local_.format.pre.u.signed_val;
+ }
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeFORMAT;
+ f->t = ffelex_token_use (t);
+ f->u.R1003D.R1004 = ffestb_local_.format.pre;
+ f->u.R1003D.format = ffestb_local_.format.f
+ = ffestt_formatlist_create (f, ffelex_token_use (t));
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeSLASH;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val.present = FALSE;
+ f->u.R1010.val.rtexpr = FALSE;
+ f->u.R1010.val.t = NULL;
+ f->u.R1010.val.u.unsigned_val = 1;
+ return (ffelexHandler) ffestb_R100112_;
+
+ case FFELEX_typeCLOSE_ARRAY: /* "/)". */
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeSLASH;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val = ffestb_local_.format.pre;
+ f = ffestb_local_.format.f->u.root.parent;
+ if (f == NULL)
+ return (ffelexHandler) ffestb_R100114_;
+ ffestb_local_.format.f = f->next;
+ return (ffelexHandler) ffestb_R100111_;
+
+ case FFELEX_typeQUOTE:
+ if (ffe_is_vxt ())
+ break; /* A totally bad character in a VXT FORMAT. */
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_NUMBER);
+ ffebad_here (0, ffelex_token_where_line (ffestb_local_.format.pre.t),
+ ffelex_token_where_column (ffestb_local_.format.pre.t));
+ ffebad_finish ();
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ ffesta_confirmed ();
+#if 0 /* No apparent need for this, and not killed
+ anywhere. */
+ ffesta_tokens[1] = ffelex_token_use (t);
+#endif
+ ffelex_set_expecting_hollerith (-1, '\"',
+ ffelex_token_where_line (t),
+ ffelex_token_where_column (t)); /* Don't have to unset
+ this one. */
+ return (ffelexHandler) ffestb_R100113_;
+
+ case FFELEX_typeAPOSTROPHE:
+ ffesta_confirmed ();
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_NUMBER);
+ ffebad_here (0, ffelex_token_where_line (ffestb_local_.format.pre.t),
+ ffelex_token_where_column (ffestb_local_.format.pre.t));
+ ffebad_finish ();
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+#if 0 /* No apparent need for this, and not killed
+ anywhere. */
+ ffesta_tokens[1] = ffelex_token_use (t);
+#endif
+ ffelex_set_expecting_hollerith (-1, '\'', ffelex_token_where_line (t),
+ ffelex_token_where_column (t)); /* Don't have to unset
+ this one. */
+ return (ffelexHandler) ffestb_R100113_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffesta_ffebad_1t (FFEBAD_FORMAT_MISSING_PAREN, t);
+ for (f = ffestb_local_.format.f;
+ f->u.root.parent != NULL;
+ f = f->u.root.parent->next)
+ ;
+ ffestb_local_.format.f = f;
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ return (ffelexHandler) ffestb_R100114_ (t);
+
+ case FFELEX_typeDOLLAR:
+ ffestb_local_.format.t = ffelex_token_use (t);
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed (); /* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeDOLLAR;
+ return (ffelexHandler) ffestb_R10015_;
+
+ case FFELEX_typeNAMES:
+ kw = ffestr_format (t);
+ ffestb_local_.format.t = ffelex_token_use (t);
+ switch (kw)
+ {
+ case FFESTR_formatI:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeI;
+ i = FFESTR_formatlI;
+ break;
+
+ case FFESTR_formatB:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeB;
+ i = FFESTR_formatlB;
+ break;
+
+ case FFESTR_formatO:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeO;
+ i = FFESTR_formatlO;
+ break;
+
+ case FFESTR_formatZ:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeZ;
+ i = FFESTR_formatlZ;
+ break;
+
+ case FFESTR_formatF:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeF;
+ i = FFESTR_formatlF;
+ break;
+
+ case FFESTR_formatE:
+ ffestb_local_.format.current = FFESTP_formattypeE;
+ i = FFESTR_formatlE;
+ break;
+
+ case FFESTR_formatEN:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeEN;
+ i = FFESTR_formatlEN;
+ break;
+
+ case FFESTR_formatG:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeG;
+ i = FFESTR_formatlG;
+ break;
+
+ case FFESTR_formatL:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeL;
+ i = FFESTR_formatlL;
+ break;
+
+ case FFESTR_formatA:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeA;
+ i = FFESTR_formatlA;
+ break;
+
+ case FFESTR_formatD:
+ ffestb_local_.format.current = FFESTP_formattypeD;
+ i = FFESTR_formatlD;
+ break;
+
+ case FFESTR_formatQ:
+ ffestb_local_.format.current = FFESTP_formattypeQ;
+ i = FFESTR_formatlQ;
+ break;
+
+ case FFESTR_formatDOLLAR:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeDOLLAR;
+ i = FFESTR_formatlDOLLAR;
+ break;
+
+ case FFESTR_formatP:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeP;
+ i = FFESTR_formatlP;
+ break;
+
+ case FFESTR_formatT:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeT;
+ i = FFESTR_formatlT;
+ break;
+
+ case FFESTR_formatTL:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeTL;
+ i = FFESTR_formatlTL;
+ break;
+
+ case FFESTR_formatTR:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeTR;
+ i = FFESTR_formatlTR;
+ break;
+
+ case FFESTR_formatX:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeX;
+ i = FFESTR_formatlX;
+ break;
+
+ case FFESTR_formatS:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeS;
+ i = FFESTR_formatlS;
+ break;
+
+ case FFESTR_formatSP:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeSP;
+ i = FFESTR_formatlSP;
+ break;
+
+ case FFESTR_formatSS:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeSS;
+ i = FFESTR_formatlSS;
+ break;
+
+ case FFESTR_formatBN:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeBN;
+ i = FFESTR_formatlBN;
+ break;
+
+ case FFESTR_formatBZ:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeBZ;
+ i = FFESTR_formatlBZ;
+ break;
+
+ case FFESTR_formatH: /* Error, either "H" or "<expr>H". */
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeH;
+ i = FFESTR_formatlH;
+ break;
+
+ case FFESTR_formatPD:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_subr_R1001_append_p_ ();
+ ffestb_local_.format.t = ffelex_token_name_from_names (t,
+ FFESTR_formatlP, 1);
+ ffestb_local_.format.sign = FALSE;
+ ffestb_local_.format.pre.present = FALSE;
+ ffestb_local_.format.pre.rtexpr = FALSE;
+ ffestb_local_.format.pre.t = NULL;
+ ffestb_local_.format.pre.u.unsigned_val = 1;
+ ffestb_local_.format.current = FFESTP_formattypeD;
+ i = FFESTR_formatlPD;
+ break;
+
+ case FFESTR_formatPE:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_subr_R1001_append_p_ ();
+ ffestb_local_.format.t = ffelex_token_name_from_names (t,
+ FFESTR_formatlP, 1);
+ ffestb_local_.format.sign = FALSE;
+ ffestb_local_.format.pre.present = FALSE;
+ ffestb_local_.format.pre.rtexpr = FALSE;
+ ffestb_local_.format.pre.t = NULL;
+ ffestb_local_.format.pre.u.unsigned_val = 1;
+ ffestb_local_.format.current = FFESTP_formattypeE;
+ i = FFESTR_formatlPE;
+ break;
+
+ case FFESTR_formatPEN:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_subr_R1001_append_p_ ();
+ ffestb_local_.format.t = ffelex_token_name_from_names (t,
+ FFESTR_formatlP, 1);
+ ffestb_local_.format.sign = FALSE;
+ ffestb_local_.format.pre.present = FALSE;
+ ffestb_local_.format.pre.rtexpr = FALSE;
+ ffestb_local_.format.pre.t = NULL;
+ ffestb_local_.format.pre.u.unsigned_val = 1;
+ ffestb_local_.format.current = FFESTP_formattypeEN;
+ i = FFESTR_formatlPEN;
+ break;
+
+ case FFESTR_formatPF:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_subr_R1001_append_p_ ();
+ ffestb_local_.format.t = ffelex_token_name_from_names (t,
+ FFESTR_formatlP, 1);
+ ffestb_local_.format.sign = FALSE;
+ ffestb_local_.format.pre.present = FALSE;
+ ffestb_local_.format.pre.rtexpr = FALSE;
+ ffestb_local_.format.pre.t = NULL;
+ ffestb_local_.format.pre.u.unsigned_val = 1;
+ ffestb_local_.format.current = FFESTP_formattypeF;
+ i = FFESTR_formatlPF;
+ break;
+
+ case FFESTR_formatPG:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_subr_R1001_append_p_ ();
+ ffestb_local_.format.t = ffelex_token_name_from_names (t,
+ FFESTR_formatlP, 1);
+ ffestb_local_.format.sign = FALSE;
+ ffestb_local_.format.pre.present = FALSE;
+ ffestb_local_.format.pre.rtexpr = FALSE;
+ ffestb_local_.format.pre.t = NULL;
+ ffestb_local_.format.pre.u.unsigned_val = 1;
+ ffestb_local_.format.current = FFESTP_formattypeG;
+ i = FFESTR_formatlPG;
+ break;
+
+ default:
+ if (ffestb_local_.format.pre.present)
+ ffesta_confirmed ();/* Number preceding this invalid elsewhere. */
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ p = strpbrk (ffelex_token_text (t), "0123456789");
+ if (p == NULL)
+ i = ffelex_token_length (t);
+ else
+ i = p - ffelex_token_text (t);
+ break;
+ }
+ p = ffelex_token_text (t) + i;
+ if (*p == '\0')
+ return (ffelexHandler) ffestb_R10015_;
+ if (! ISDIGIT (*p))
+ {
+ if (ffestb_local_.format.current == FFESTP_formattypeH)
+ p = strpbrk (p, "0123456789");
+ else
+ {
+ p = NULL;
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ }
+ if (p == NULL)
+ return (ffelexHandler) ffestb_R10015_;
+ i = p - ffelex_token_text (t); /* Collect digits. */
+ }
+ ffestb_local_.format.post.present = TRUE;
+ ffestb_local_.format.post.rtexpr = FALSE;
+ ffestb_local_.format.post.t = ffelex_token_number_from_names (t, i);
+ ffestb_local_.format.post.u.unsigned_val
+ = strtoul (ffelex_token_text (ffestb_local_.format.post.t), NULL, 10);
+ p += ffelex_token_length (ffestb_local_.format.post.t);
+ i += ffelex_token_length (ffestb_local_.format.post.t);
+ if (*p == '\0')
+ return (ffelexHandler) ffestb_R10016_;
+ if ((kw != FFESTR_formatP) || !ffelex_is_firstnamechar (*p))
+ {
+ if (ffestb_local_.format.current != FFESTP_formattypeH)
+ ffesta_ffebad_1p (FFEBAD_FORMAT_TEXT_IN_NUMBER, t, i, NULL);
+ return (ffelexHandler) ffestb_R10016_;
+ }
+
+ /* Here we have [number]P[number][text]. Treat as
+ [number]P,[number][text]. */
+
+ ffestb_subr_R1001_append_p_ ();
+ t = ffestb_local_.format.t = ffelex_token_names_from_names (t, i, 0);
+ ffestb_local_.format.sign = FALSE;
+ ffestb_local_.format.pre = ffestb_local_.format.post;
+ kw = ffestr_format (t);
+ switch (kw)
+ { /* Only a few possibilities here. */
+ case FFESTR_formatD:
+ ffestb_local_.format.current = FFESTP_formattypeD;
+ i = FFESTR_formatlD;
+ break;
+
+ case FFESTR_formatE:
+ ffestb_local_.format.current = FFESTP_formattypeE;
+ i = FFESTR_formatlE;
+ break;
+
+ case FFESTR_formatEN:
+ ffestb_local_.format.current = FFESTP_formattypeEN;
+ i = FFESTR_formatlEN;
+ break;
+
+ case FFESTR_formatF:
+ ffestb_local_.format.current = FFESTP_formattypeF;
+ i = FFESTR_formatlF;
+ break;
+
+ case FFESTR_formatG:
+ ffestb_local_.format.current = FFESTP_formattypeG;
+ i = FFESTR_formatlG;
+ break;
+
+ default:
+ ffebad_start (FFEBAD_FORMAT_P_NOCOMMA);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ p = strpbrk (ffelex_token_text (t), "0123456789");
+ if (p == NULL)
+ i = ffelex_token_length (t);
+ else
+ i = p - ffelex_token_text (t);
+ }
+ p = ffelex_token_text (t) + i;
+ if (*p == '\0')
+ return (ffelexHandler) ffestb_R10015_;
+ if (! ISDIGIT (*p))
+ {
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ p = strpbrk (p, "0123456789");
+ if (p == NULL)
+ return (ffelexHandler) ffestb_R10015_;
+ i = p - ffelex_token_text (t); /* Collect digits anyway. */
+ }
+ ffestb_local_.format.post.present = TRUE;
+ ffestb_local_.format.post.rtexpr = FALSE;
+ ffestb_local_.format.post.t = ffelex_token_number_from_names (t, i);
+ ffestb_local_.format.post.u.unsigned_val
+ = strtoul (ffelex_token_text (ffestb_local_.format.post.t), NULL, 10);
+ p += ffelex_token_length (ffestb_local_.format.post.t);
+ i += ffelex_token_length (ffestb_local_.format.post.t);
+ if (*p == '\0')
+ return (ffelexHandler) ffestb_R10016_;
+ ffesta_ffebad_1p (FFEBAD_FORMAT_TEXT_IN_NUMBER, t, i, NULL);
+ return (ffelexHandler) ffestb_R10016_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", t);
+ if (ffestb_local_.format.pre.present)
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R10015_ -- [[+/-] NUMBER] NAMES
+
+ return ffestb_R10015_; // to lexer
+
+ Here we've gotten at least the initial mnemonic for the edit descriptor.
+ We expect either a NUMBER, for the post-mnemonic value, a NAMES, for
+ further clarification (in free-form only, sigh) of the mnemonic, or
+ anything else. In all cases we go to _6_, with the difference that for
+ NUMBER and NAMES we send the next token rather than the current token. */
+
+static ffelexHandler
+ffestb_R10015_ (ffelexToken t)
+{
+ bool split_pea; /* New NAMES requires splitting kP from new
+ edit desc. */
+ ffestrFormat kw;
+ char *p;
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_ANGLE:
+ ffesta_confirmed ();
+ ffestb_local_.format.post.t = ffelex_token_use (t);
+ ffelex_set_names_pure (FALSE);
+ if (!ffesta_seen_first_exec && !ffestb_local_.format.complained)
+ {
+ ffestb_local_.format.complained = TRUE;
+ ffebad_start (FFEBAD_FORMAT_EXPR_SPEC);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFORMAT, (ffeexprCallback) ffestb_R100116_);
+
+ case FFELEX_typeNUMBER:
+ ffestb_local_.format.post.present = TRUE;
+ ffestb_local_.format.post.rtexpr = FALSE;
+ ffestb_local_.format.post.t = ffelex_token_use (t);
+ ffestb_local_.format.post.u.unsigned_val
+ = strtoul (ffelex_token_text (t), NULL, 10);
+ return (ffelexHandler) ffestb_R10016_;
+
+ case FFELEX_typeNAMES:
+ ffesta_confirmed (); /* NAMES " " NAMES invalid elsewhere in
+ free-form. */
+ kw = ffestr_format (t);
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeP:
+ split_pea = TRUE;
+ break;
+
+ case FFESTP_formattypeH: /* An error, maintain this indicator. */
+ kw = FFESTR_formatNone;
+ split_pea = FALSE;
+ break;
+
+ default:
+ split_pea = FALSE;
+ break;
+ }
+
+ switch (kw)
+ {
+ case FFESTR_formatF:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeP:
+ ffestb_local_.format.current = FFESTP_formattypeF;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlF;
+ break;
+
+ case FFESTR_formatE:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeP:
+ ffestb_local_.format.current = FFESTP_formattypeE;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlE;
+ break;
+
+ case FFESTR_formatEN:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeP:
+ ffestb_local_.format.current = FFESTP_formattypeEN;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlEN;
+ break;
+
+ case FFESTR_formatG:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeP:
+ ffestb_local_.format.current = FFESTP_formattypeG;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlG;
+ break;
+
+ case FFESTR_formatL:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeT:
+ ffestb_local_.format.current = FFESTP_formattypeTL;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlL;
+ break;
+
+ case FFESTR_formatD:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeP:
+ ffestb_local_.format.current = FFESTP_formattypeD;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlD;
+ break;
+
+ case FFESTR_formatS:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeS:
+ ffestb_local_.format.current = FFESTP_formattypeSS;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlS;
+ break;
+
+ case FFESTR_formatP:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeS:
+ ffestb_local_.format.current = FFESTP_formattypeSP;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlP;
+ break;
+
+ case FFESTR_formatR:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeT:
+ ffestb_local_.format.current = FFESTP_formattypeTR;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlR;
+ break;
+
+ case FFESTR_formatZ:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeB:
+ ffestb_local_.format.current = FFESTP_formattypeBZ;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlZ;
+ break;
+
+ case FFESTR_formatN:
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeE:
+ ffestb_local_.format.current = FFESTP_formattypeEN;
+ break;
+
+ case FFESTP_formattypeB:
+ ffestb_local_.format.current = FFESTP_formattypeBN;
+ break;
+
+ default:
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ break;
+ }
+ i = FFESTR_formatlN;
+ break;
+
+ default:
+ if (ffestb_local_.format.current != FFESTP_formattypeH)
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ split_pea = FALSE; /* Go ahead and let the P be in the party. */
+ p = strpbrk (ffelex_token_text (t), "0123456789");
+ if (p == NULL)
+ i = ffelex_token_length (t);
+ else
+ i = p - ffelex_token_text (t);
+ }
+
+ if (split_pea)
+ {
+ ffestb_subr_R1001_append_p_ ();
+ ffestb_local_.format.t = ffelex_token_use (t);
+ ffestb_local_.format.sign = FALSE;
+ ffestb_local_.format.pre.present = FALSE;
+ ffestb_local_.format.pre.rtexpr = FALSE;
+ ffestb_local_.format.pre.t = NULL;
+ ffestb_local_.format.pre.u.unsigned_val = 1;
+ }
+
+ p = ffelex_token_text (t) + i;
+ if (*p == '\0')
+ return (ffelexHandler) ffestb_R10015_;
+ if (! ISDIGIT (*p))
+ {
+ ffestb_local_.format.current = FFESTP_formattypeNone;
+ p = strpbrk (p, "0123456789");
+ if (p == NULL)
+ return (ffelexHandler) ffestb_R10015_;
+ i = p - ffelex_token_text (t); /* Collect digits anyway. */
+ }
+ ffestb_local_.format.post.present = TRUE;
+ ffestb_local_.format.post.rtexpr = FALSE;
+ ffestb_local_.format.post.t = ffelex_token_number_from_names (t, i);
+ ffestb_local_.format.post.u.unsigned_val
+ = strtoul (ffelex_token_text (ffestb_local_.format.post.t), NULL, 10);
+ p += ffelex_token_length (ffestb_local_.format.post.t);
+ i += ffelex_token_length (ffestb_local_.format.post.t);
+ if (*p == '\0')
+ return (ffelexHandler) ffestb_R10016_;
+ ffesta_ffebad_1p (FFEBAD_FORMAT_TEXT_IN_NUMBER, t, i, NULL);
+ return (ffelexHandler) ffestb_R10016_;
+
+ default:
+ ffestb_local_.format.post.present = FALSE;
+ ffestb_local_.format.post.rtexpr = FALSE;
+ ffestb_local_.format.post.t = NULL;
+ ffestb_local_.format.post.u.unsigned_val = 1;
+ return (ffelexHandler) ffestb_R10016_ (t);
+ }
+}
+
+/* ffestb_R10016_ -- [[+/-] NUMBER] NAMES NUMBER
+
+ return ffestb_R10016_; // to lexer
+
+ Expect a PERIOD here. Maybe find a NUMBER to append to the current
+ number, in which case return to this state. Maybe find a NAMES to switch
+ from a kP descriptor to a new descriptor (else the NAMES is spurious),
+ in which case generator the P item and go to state _4_. Anything
+ else, pass token on to state _8_. */
+
+static ffelexHandler
+ffestb_R10016_ (ffelexToken t)
+{
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typePERIOD:
+ return (ffelexHandler) ffestb_R10017_;
+
+ case FFELEX_typeNUMBER:
+ assert (ffestb_local_.format.post.present);
+ ffesta_confirmed ();
+ if (ffestb_local_.format.post.rtexpr)
+ {
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_NUMBER);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ return (ffelexHandler) ffestb_R10016_;
+ }
+ for (i = ffelex_token_length (t) + 1; i > 0; --i)
+ ffestb_local_.format.post.u.unsigned_val *= 10;
+ ffestb_local_.format.post.u.unsigned_val += strtoul (ffelex_token_text (t),
+ NULL, 10);
+ return (ffelexHandler) ffestb_R10016_;
+
+ case FFELEX_typeNAMES:
+ ffesta_confirmed (); /* NUMBER " " NAMES invalid elsewhere. */
+ if (ffestb_local_.format.current != FFESTP_formattypeP)
+ {
+ ffesta_ffebad_1t (FFEBAD_FORMAT_TEXT_IN_NUMBER, t);
+ return (ffelexHandler) ffestb_R10016_;
+ }
+ ffestb_subr_R1001_append_p_ ();
+ ffestb_local_.format.sign = FALSE;
+ ffestb_local_.format.pre = ffestb_local_.format.post;
+ return (ffelexHandler) ffestb_R10014_ (t);
+
+ default:
+ ffestb_local_.format.dot.present = FALSE;
+ ffestb_local_.format.dot.rtexpr = FALSE;
+ ffestb_local_.format.dot.t = NULL;
+ ffestb_local_.format.dot.u.unsigned_val = 1;
+ return (ffelexHandler) ffestb_R10018_ (t);
+ }
+}
+
+/* ffestb_R10017_ -- [[+/-] NUMBER] NAMES NUMBER PERIOD
+
+ return ffestb_R10017_; // to lexer
+
+ Here we've gotten the period following the edit descriptor.
+ We expect either a NUMBER, for the dot value, or something else, which
+ probably means we're not even close to being in a real FORMAT statement. */
+
+static ffelexHandler
+ffestb_R10017_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_ANGLE:
+ ffestb_local_.format.dot.t = ffelex_token_use (t);
+ ffelex_set_names_pure (FALSE);
+ if (!ffesta_seen_first_exec && !ffestb_local_.format.complained)
+ {
+ ffestb_local_.format.complained = TRUE;
+ ffebad_start (FFEBAD_FORMAT_EXPR_SPEC);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFORMAT, (ffeexprCallback) ffestb_R100117_);
+
+ case FFELEX_typeNUMBER:
+ ffestb_local_.format.dot.present = TRUE;
+ ffestb_local_.format.dot.rtexpr = FALSE;
+ ffestb_local_.format.dot.t = ffelex_token_use (t);
+ ffestb_local_.format.dot.u.unsigned_val
+ = strtoul (ffelex_token_text (t), NULL, 10);
+ return (ffelexHandler) ffestb_R10018_;
+
+ default:
+ ffelex_token_kill (ffestb_local_.format.t);
+ if (ffestb_local_.format.pre.present)
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ if (ffestb_local_.format.post.present)
+ ffelex_token_kill (ffestb_local_.format.post.t);
+ ffesta_ffebad_1t (FFEBAD_FORMAT_MISSING_DOT, t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffestb_R10018_ -- [[+/-] NUMBER] NAMES NUMBER PERIOD NUMBER
+
+ return ffestb_R10018_; // to lexer
+
+ Expect a NAMES here, which must begin with "E" to be valid. Maybe find a
+ NUMBER to append to the current number, in which case return to this state.
+ Anything else, pass token on to state _10_. */
+
+static ffelexHandler
+ffestb_R10018_ (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ assert (ffestb_local_.format.dot.present);
+ ffesta_confirmed ();
+ if (ffestb_local_.format.dot.rtexpr)
+ {
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_NUMBER);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ return (ffelexHandler) ffestb_R10018_;
+ }
+ for (i = ffelex_token_length (t) + 1; i > 0; --i)
+ ffestb_local_.format.dot.u.unsigned_val *= 10;
+ ffestb_local_.format.dot.u.unsigned_val += strtoul (ffelex_token_text (t),
+ NULL, 10);
+ return (ffelexHandler) ffestb_R10018_;
+
+ case FFELEX_typeNAMES:
+ if (!ffesrc_char_match_init (*(p = ffelex_token_text (t)), 'E', 'e'))
+ {
+ ffesta_ffebad_1t (FFEBAD_FORMAT_TEXT_IN_NUMBER, t);
+ return (ffelexHandler) ffestb_R10018_;
+ }
+ if (*++p == '\0')
+ return (ffelexHandler) ffestb_R10019_; /* Go get NUMBER. */
+ i = 1;
+ if (! ISDIGIT (*p))
+ {
+ ffesta_ffebad_1p (FFEBAD_FORMAT_TEXT_IN_NUMBER, t, 1, NULL);
+ return (ffelexHandler) ffestb_R10018_;
+ }
+ ffestb_local_.format.exp.present = TRUE;
+ ffestb_local_.format.exp.rtexpr = FALSE;
+ ffestb_local_.format.exp.t = ffelex_token_number_from_names (t, i);
+ ffestb_local_.format.exp.u.unsigned_val
+ = strtoul (ffelex_token_text (ffestb_local_.format.exp.t), NULL, 10);
+ p += ffelex_token_length (ffestb_local_.format.exp.t);
+ i += ffelex_token_length (ffestb_local_.format.exp.t);
+ if (*p == '\0')
+ return (ffelexHandler) ffestb_R100110_;
+ ffesta_ffebad_1p (FFEBAD_FORMAT_TEXT_IN_NUMBER, t, i, NULL);
+ return (ffelexHandler) ffestb_R100110_;
+
+ default:
+ ffestb_local_.format.exp.present = FALSE;
+ ffestb_local_.format.exp.rtexpr = FALSE;
+ ffestb_local_.format.exp.t = NULL;
+ ffestb_local_.format.exp.u.unsigned_val = 1;
+ return (ffelexHandler) ffestb_R100110_ (t);
+ }
+}
+
+/* ffestb_R10019_ -- [[+/-] NUMBER] NAMES NUMBER PERIOD NUMBER "E"
+
+ return ffestb_R10019_; // to lexer
+
+ Here we've gotten the "E" following the edit descriptor.
+ We expect either a NUMBER, for the exponent value, or something else. */
+
+static ffelexHandler
+ffestb_R10019_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_ANGLE:
+ ffestb_local_.format.exp.t = ffelex_token_use (t);
+ ffelex_set_names_pure (FALSE);
+ if (!ffesta_seen_first_exec && !ffestb_local_.format.complained)
+ {
+ ffestb_local_.format.complained = TRUE;
+ ffebad_start (FFEBAD_FORMAT_EXPR_SPEC);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFORMAT, (ffeexprCallback) ffestb_R100118_);
+
+ case FFELEX_typeNUMBER:
+ ffestb_local_.format.exp.present = TRUE;
+ ffestb_local_.format.exp.rtexpr = FALSE;
+ ffestb_local_.format.exp.t = ffelex_token_use (t);
+ ffestb_local_.format.exp.u.unsigned_val
+ = strtoul (ffelex_token_text (t), NULL, 10);
+ return (ffelexHandler) ffestb_R100110_;
+
+ default:
+ ffelex_token_kill (ffestb_local_.format.t);
+ if (ffestb_local_.format.pre.present)
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ if (ffestb_local_.format.post.present)
+ ffelex_token_kill (ffestb_local_.format.post.t);
+ if (ffestb_local_.format.dot.present)
+ ffelex_token_kill (ffestb_local_.format.dot.t);
+ ffesta_ffebad_1t (FFEBAD_FORMAT_MISSING_EXP, t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffestb_R100110_ -- [[+/-] NUMBER] NAMES NUMBER [PERIOD NUMBER ["E" NUMBER]]
+
+ return ffestb_R100110_; // to lexer
+
+ Maybe find a NUMBER to append to the current number, in which case return
+ to this state. Anything else, handle current descriptor, then pass token
+ on to state _10_. */
+
+static ffelexHandler
+ffestb_R100110_ (ffelexToken t)
+{
+ ffeTokenLength i;
+ enum expect
+ {
+ required,
+ optional,
+ disallowed
+ };
+ ffebad err;
+ enum expect pre;
+ enum expect post;
+ enum expect dot;
+ enum expect exp;
+ bool R1005;
+ ffesttFormatList f;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ assert (ffestb_local_.format.exp.present);
+ ffesta_confirmed ();
+ if (ffestb_local_.format.exp.rtexpr)
+ {
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_NUMBER);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+ return (ffelexHandler) ffestb_R100110_;
+ }
+ for (i = ffelex_token_length (t) + 1; i > 0; --i)
+ ffestb_local_.format.exp.u.unsigned_val *= 10;
+ ffestb_local_.format.exp.u.unsigned_val += strtoul (ffelex_token_text (t),
+ NULL, 10);
+ return (ffelexHandler) ffestb_R100110_;
+
+ default:
+ if (ffestb_local_.format.sign
+ && (ffestb_local_.format.current != FFESTP_formattypeP)
+ && (ffestb_local_.format.current != FFESTP_formattypeH))
+ {
+ ffebad_start (FFEBAD_FORMAT_SPURIOUS_SIGN);
+ ffebad_here (0, ffelex_token_where_line (ffestb_local_.format.pre.t),
+ ffelex_token_where_column (ffestb_local_.format.pre.t));
+ ffebad_finish ();
+ ffestb_local_.format.pre.u.unsigned_val
+ = (ffestb_local_.format.pre.u.signed_val < 0)
+ ? -ffestb_local_.format.pre.u.signed_val
+ : ffestb_local_.format.pre.u.signed_val;
+ }
+ switch (ffestb_local_.format.current)
+ {
+ case FFESTP_formattypeI:
+ err = FFEBAD_FORMAT_BAD_I_SPEC;
+ pre = optional;
+ post = required;
+ dot = optional;
+ exp = disallowed;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeB:
+ err = FFEBAD_FORMAT_BAD_B_SPEC;
+ pre = optional;
+ post = required;
+ dot = optional;
+ exp = disallowed;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeO:
+ err = FFEBAD_FORMAT_BAD_O_SPEC;
+ pre = optional;
+ post = required;
+ dot = optional;
+ exp = disallowed;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeZ:
+ err = FFEBAD_FORMAT_BAD_Z_SPEC;
+ pre = optional;
+ post = required;
+ dot = optional;
+ exp = disallowed;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeF:
+ err = FFEBAD_FORMAT_BAD_F_SPEC;
+ pre = optional;
+ post = required;
+ dot = required;
+ exp = disallowed;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeE:
+ err = FFEBAD_FORMAT_BAD_E_SPEC;
+ pre = optional;
+ post = required;
+ dot = required;
+ exp = optional;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeEN:
+ err = FFEBAD_FORMAT_BAD_EN_SPEC;
+ pre = optional;
+ post = required;
+ dot = required;
+ exp = optional;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeG:
+ err = FFEBAD_FORMAT_BAD_G_SPEC;
+ pre = optional;
+ post = required;
+ dot = required;
+ exp = optional;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeL:
+ err = FFEBAD_FORMAT_BAD_L_SPEC;
+ pre = optional;
+ post = required;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeA:
+ err = FFEBAD_FORMAT_BAD_A_SPEC;
+ pre = optional;
+ post = optional;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeD:
+ err = FFEBAD_FORMAT_BAD_D_SPEC;
+ pre = optional;
+ post = required;
+ dot = required;
+ exp = disallowed;
+ R1005 = TRUE;
+ break;
+
+ case FFESTP_formattypeQ:
+ err = FFEBAD_FORMAT_BAD_Q_SPEC;
+ pre = disallowed;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeDOLLAR:
+ err = FFEBAD_FORMAT_BAD_DOLLAR_SPEC;
+ pre = disallowed;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeP:
+ err = FFEBAD_FORMAT_BAD_P_SPEC;
+ pre = required;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeT:
+ err = FFEBAD_FORMAT_BAD_T_SPEC;
+ pre = disallowed;
+ post = required;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeTL:
+ err = FFEBAD_FORMAT_BAD_TL_SPEC;
+ pre = disallowed;
+ post = required;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeTR:
+ err = FFEBAD_FORMAT_BAD_TR_SPEC;
+ pre = disallowed;
+ post = required;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeX:
+ err = FFEBAD_FORMAT_BAD_X_SPEC;
+ pre = required;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeS:
+ err = FFEBAD_FORMAT_BAD_S_SPEC;
+ pre = disallowed;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeSP:
+ err = FFEBAD_FORMAT_BAD_SP_SPEC;
+ pre = disallowed;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeSS:
+ err = FFEBAD_FORMAT_BAD_SS_SPEC;
+ pre = disallowed;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeBN:
+ err = FFEBAD_FORMAT_BAD_BN_SPEC;
+ pre = disallowed;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeBZ:
+ err = FFEBAD_FORMAT_BAD_BZ_SPEC;
+ pre = disallowed;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeH: /* Definitely an error, make sure of
+ it. */
+ err = FFEBAD_FORMAT_BAD_H_SPEC;
+ pre = ffestb_local_.format.pre.present ? disallowed : required;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+
+ case FFESTP_formattypeNone:
+ ffesta_ffebad_1t (FFEBAD_FORMAT_BAD_SPEC,
+ ffestb_local_.format.t);
+
+ clean_up_to_11_: /* :::::::::::::::::::: */
+
+ ffelex_token_kill (ffestb_local_.format.t);
+ if (ffestb_local_.format.pre.present)
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ if (ffestb_local_.format.post.present)
+ ffelex_token_kill (ffestb_local_.format.post.t);
+ if (ffestb_local_.format.dot.present)
+ ffelex_token_kill (ffestb_local_.format.dot.t);
+ if (ffestb_local_.format.exp.present)
+ ffelex_token_kill (ffestb_local_.format.exp.t);
+ return (ffelexHandler) ffestb_R100111_ (t);
+
+ default:
+ assert ("bad format item" == NULL);
+ err = FFEBAD_FORMAT_BAD_H_SPEC;
+ pre = disallowed;
+ post = disallowed;
+ dot = disallowed;
+ exp = disallowed;
+ R1005 = FALSE;
+ break;
+ }
+ if (((pre == disallowed) && ffestb_local_.format.pre.present)
+ || ((pre == required) && !ffestb_local_.format.pre.present))
+ {
+ ffesta_ffebad_1t (err, (pre == required)
+ ? ffestb_local_.format.t : ffestb_local_.format.pre.t);
+ goto clean_up_to_11_; /* :::::::::::::::::::: */
+ }
+ if (((post == disallowed) && ffestb_local_.format.post.present)
+ || ((post == required) && !ffestb_local_.format.post.present))
+ {
+ ffesta_ffebad_1t (err, (post == required)
+ ? ffestb_local_.format.t : ffestb_local_.format.post.t);
+ goto clean_up_to_11_; /* :::::::::::::::::::: */
+ }
+ if (((dot == disallowed) && ffestb_local_.format.dot.present)
+ || ((dot == required) && !ffestb_local_.format.dot.present))
+ {
+ ffesta_ffebad_1t (err, (dot == required)
+ ? ffestb_local_.format.t : ffestb_local_.format.dot.t);
+ goto clean_up_to_11_; /* :::::::::::::::::::: */
+ }
+ if (((exp == disallowed) && ffestb_local_.format.exp.present)
+ || ((exp == required) && !ffestb_local_.format.exp.present))
+ {
+ ffesta_ffebad_1t (err, (exp == required)
+ ? ffestb_local_.format.t : ffestb_local_.format.exp.t);
+ goto clean_up_to_11_; /* :::::::::::::::::::: */
+ }
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = ffestb_local_.format.current;
+ f->t = ffestb_local_.format.t;
+ if (R1005)
+ {
+ f->u.R1005.R1004 = ffestb_local_.format.pre;
+ f->u.R1005.R1006 = ffestb_local_.format.post;
+ f->u.R1005.R1007_or_R1008 = ffestb_local_.format.dot;
+ f->u.R1005.R1009 = ffestb_local_.format.exp;
+ }
+ else
+ /* Must be R1010. */
+ {
+ if (pre == disallowed)
+ f->u.R1010.val = ffestb_local_.format.post;
+ else
+ f->u.R1010.val = ffestb_local_.format.pre;
+ }
+ return (ffelexHandler) ffestb_R100111_ (t);
+ }
+}
+
+/* ffestb_R100111_ -- edit-descriptor
+
+ return ffestb_R100111_; // to lexer
+
+ Expect a COMMA, CLOSE_PAREN, CLOSE_ARRAY, COLON, COLONCOLON, SLASH, or
+ CONCAT, or complain about missing comma. */
+
+static ffelexHandler
+ffestb_R100111_ (ffelexToken t)
+{
+ ffesttFormatList f;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R10012_;
+
+ case FFELEX_typeCOLON:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeSLASH:
+ case FFELEX_typeCONCAT:
+ return (ffelexHandler) ffestb_R10012_ (t);
+
+ case FFELEX_typeCLOSE_PAREN:
+ f = ffestb_local_.format.f->u.root.parent;
+ if (f == NULL)
+ return (ffelexHandler) ffestb_R100114_;
+ ffestb_local_.format.f = f->next;
+ return (ffelexHandler) ffestb_R100111_;
+
+ case FFELEX_typeCLOSE_ARRAY: /* "/)". */
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeSLASH;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val.present = FALSE;
+ f->u.R1010.val.rtexpr = FALSE;
+ f->u.R1010.val.t = NULL;
+ f->u.R1010.val.u.unsigned_val = 1;
+ f = ffestb_local_.format.f->u.root.parent;
+ if (f == NULL)
+ return (ffelexHandler) ffestb_R100114_;
+ ffestb_local_.format.f = f->next;
+ return (ffelexHandler) ffestb_R100111_;
+
+ case FFELEX_typeOPEN_ANGLE:
+ case FFELEX_typeDOLLAR:
+ case FFELEX_typeNUMBER:
+ case FFELEX_typeOPEN_PAREN:
+ case FFELEX_typeOPEN_ARRAY:
+ case FFELEX_typeQUOTE:
+ case FFELEX_typeAPOSTROPHE:
+ case FFELEX_typeNAMES:
+ ffesta_ffebad_1t (FFEBAD_FORMAT_MISSING_COMMA, t);
+ return (ffelexHandler) ffestb_R10012_ (t);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffesta_ffebad_1t (FFEBAD_FORMAT_MISSING_PAREN, t);
+ for (f = ffestb_local_.format.f;
+ f->u.root.parent != NULL;
+ f = f->u.root.parent->next)
+ ;
+ ffestb_local_.format.f = f;
+ return (ffelexHandler) ffestb_R100114_ (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffestb_R100112_ -- COLON, COLONCOLON, SLASH, OPEN_ARRAY, or CONCAT
+
+ return ffestb_R100112_; // to lexer
+
+ Like _11_ except the COMMA is optional. */
+
+static ffelexHandler
+ffestb_R100112_ (ffelexToken t)
+{
+ ffesttFormatList f;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R10012_;
+
+ case FFELEX_typeCOLON:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeSLASH:
+ case FFELEX_typeCONCAT:
+ case FFELEX_typeOPEN_ANGLE:
+ case FFELEX_typeNAMES:
+ case FFELEX_typeDOLLAR:
+ case FFELEX_typeNUMBER:
+ case FFELEX_typeOPEN_PAREN:
+ case FFELEX_typeOPEN_ARRAY:
+ case FFELEX_typeQUOTE:
+ case FFELEX_typeAPOSTROPHE:
+ case FFELEX_typePLUS:
+ case FFELEX_typeMINUS:
+ return (ffelexHandler) ffestb_R10012_ (t);
+
+ case FFELEX_typeCLOSE_PAREN:
+ f = ffestb_local_.format.f->u.root.parent;
+ if (f == NULL)
+ return (ffelexHandler) ffestb_R100114_;
+ ffestb_local_.format.f = f->next;
+ return (ffelexHandler) ffestb_R100111_;
+
+ case FFELEX_typeCLOSE_ARRAY: /* "/)". */
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeSLASH;
+ f->t = ffelex_token_use (t);
+ f->u.R1010.val.present = FALSE;
+ f->u.R1010.val.rtexpr = FALSE;
+ f->u.R1010.val.t = NULL;
+ f->u.R1010.val.u.unsigned_val = 1;
+ f = ffestb_local_.format.f->u.root.parent;
+ if (f == NULL)
+ return (ffelexHandler) ffestb_R100114_;
+ ffestb_local_.format.f = f->next;
+ return (ffelexHandler) ffestb_R100111_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffesta_ffebad_1t (FFEBAD_FORMAT_MISSING_PAREN, t);
+ for (f = ffestb_local_.format.f;
+ f->u.root.parent != NULL;
+ f = f->u.root.parent->next)
+ ;
+ ffestb_local_.format.f = f;
+ return (ffelexHandler) ffestb_R100114_ (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffestb_R100113_ -- Handle CHARACTER token.
+
+ return ffestb_R100113_; // to lexer
+
+ Append the format item to the list, go to _11_. */
+
+static ffelexHandler
+ffestb_R100113_ (ffelexToken t)
+{
+ ffesttFormatList f;
+
+ assert (ffelex_token_type (t) == FFELEX_typeCHARACTER);
+
+ if (ffe_is_pedantic_not_90 () && (ffelex_token_length (t) == 0))
+ {
+ ffebad_start (FFEBAD_NULL_CHAR_CONST);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_finish ();
+ }
+
+ f = ffestt_formatlist_append (ffestb_local_.format.f);
+ f->type = FFESTP_formattypeR1016;
+ f->t = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R100111_;
+}
+
+/* ffestb_R100114_ -- "FORMAT" OPEN_PAREN format-item-list CLOSE_PAREN
+
+ return ffestb_R100114_; // to lexer
+
+ Handle EOS/SEMICOLON or something else. */
+
+static ffelexHandler
+ffestb_R100114_ (ffelexToken t)
+{
+ ffelex_set_names_pure (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited () && !ffestb_local_.format.complained)
+ ffestc_R1001 (ffestb_local_.format.f);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffestb_R100115_ -- OPEN_ANGLE expr
+
+ (ffestb_R100115_) // to expression handler
+
+ Handle expression prior to the edit descriptor. */
+
+static ffelexHandler
+ffestb_R100115_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_ANGLE:
+ ffestb_local_.format.pre.present = TRUE;
+ ffestb_local_.format.pre.rtexpr = TRUE;
+ ffestb_local_.format.pre.u.expr = expr;
+ ffelex_set_names_pure (TRUE);
+ return (ffelexHandler) ffestb_R10014_;
+
+ default:
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffestb_R100116_ -- "[n]X" OPEN_ANGLE expr
+
+ (ffestb_R100116_) // to expression handler
+
+ Handle expression after the edit descriptor. */
+
+static ffelexHandler
+ffestb_R100116_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_ANGLE:
+ ffestb_local_.format.post.present = TRUE;
+ ffestb_local_.format.post.rtexpr = TRUE;
+ ffestb_local_.format.post.u.expr = expr;
+ ffelex_set_names_pure (TRUE);
+ return (ffelexHandler) ffestb_R10016_;
+
+ default:
+ ffelex_token_kill (ffestb_local_.format.t);
+ ffelex_token_kill (ffestb_local_.format.post.t);
+ if (ffestb_local_.format.pre.present)
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffestb_R100117_ -- "[n]X[n]." OPEN_ANGLE expr
+
+ (ffestb_R100117_) // to expression handler
+
+ Handle expression after the PERIOD. */
+
+static ffelexHandler
+ffestb_R100117_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_ANGLE:
+ ffestb_local_.format.dot.present = TRUE;
+ ffestb_local_.format.dot.rtexpr = TRUE;
+ ffestb_local_.format.dot.u.expr = expr;
+ ffelex_set_names_pure (TRUE);
+ return (ffelexHandler) ffestb_R10018_;
+
+ default:
+ ffelex_token_kill (ffestb_local_.format.t);
+ ffelex_token_kill (ffestb_local_.format.dot.t);
+ if (ffestb_local_.format.pre.present)
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ if (ffestb_local_.format.post.present)
+ ffelex_token_kill (ffestb_local_.format.post.t);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffestb_R100118_ -- "[n]X[n].[n]E" OPEN_ANGLE expr
+
+ (ffestb_R100118_) // to expression handler
+
+ Handle expression after the "E". */
+
+static ffelexHandler
+ffestb_R100118_ (ffelexToken ft UNUSED, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_ANGLE:
+ ffestb_local_.format.exp.present = TRUE;
+ ffestb_local_.format.exp.rtexpr = TRUE;
+ ffestb_local_.format.exp.u.expr = expr;
+ ffelex_set_names_pure (TRUE);
+ return (ffelexHandler) ffestb_R100110_;
+
+ default:
+ ffelex_token_kill (ffestb_local_.format.t);
+ ffelex_token_kill (ffestb_local_.format.exp.t);
+ if (ffestb_local_.format.pre.present)
+ ffelex_token_kill (ffestb_local_.format.pre.t);
+ if (ffestb_local_.format.post.present)
+ ffelex_token_kill (ffestb_local_.format.post.t);
+ if (ffestb_local_.format.dot.present)
+ ffelex_token_kill (ffestb_local_.format.dot.t);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FORMAT", t);
+ ffestt_formatlist_kill (ffestb_local_.format.f);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+}
+
+/* ffestb_R1107 -- Parse the USE statement
+
+ return ffestb_R1107; // to lexer
+
+ Make sure the statement has a valid form for the USE statement.
+ If it does, implement the statement. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_R1107 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstUSE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+ ffesta_confirmed ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R11071_;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstUSE)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlUSE);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+ }
+ ffesta_confirmed ();
+ ffesta_tokens[1]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ return (ffelexHandler) ffestb_R11071_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "USE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R11071_ -- "USE" NAME
+
+ return ffestb_R11071_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R11071_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R1107_start (ffesta_tokens[1], FALSE);
+ ffestc_R1107_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R11072_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R11072_ -- "USE" NAME COMMA
+
+ return ffestb_R11072_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R11072_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R11073_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R11073_ -- "USE" NAME COMMA NAME
+
+ return ffestb_R11073_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R11073_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOLON:
+ if (ffestr_other (ffesta_tokens[2]) != FFESTR_otherONLY)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R1107_start (ffesta_tokens[1], TRUE);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffestb_R11074_;
+
+ case FFELEX_typePOINTS:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1107_start (ffesta_tokens[1], FALSE);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_tokens[1] = ffesta_tokens[2];
+ return (ffelexHandler) ffestb_R110711_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R11074_ -- "USE" NAME COMMA "ONLY" COLON
+
+ return ffestb_R11074_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R11074_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R11075_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R11075_ -- "USE" NAME COMMA "ONLY" COLON NAME
+
+ return ffestb_R11075_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R11075_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R1107_item (NULL, ffesta_tokens[1]);
+ ffestc_R1107_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1107_item (NULL, ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_R11078_;
+
+ case FFELEX_typePOINTS:
+ return (ffelexHandler) ffestb_R11076_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R11076_ -- "USE" NAME COMMA "ONLY" COLON NAME POINTS
+
+ return ffestb_R11076_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R11076_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1107_item (ffesta_tokens[1], t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_R11077_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R11077_ -- "USE" NAME COMMA "ONLY" COLON NAME POINTS NAME
+
+ return ffestb_R11077_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R11077_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R11078_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R11078_ -- "USE" NAME COMMA "ONLY" COLON NAME POINTS NAME COMMA
+
+ return ffestb_R11078_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R11078_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R11075_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R11079_ -- "USE" NAME COMMA
+
+ return ffestb_R11079_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R11079_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R110710_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R110710_ -- "USE" NAME COMMA NAME
+
+ return ffestb_R110710_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R110710_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typePOINTS:
+ return (ffelexHandler) ffestb_R110711_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R110711_ -- "USE" NAME COMMA NAME POINTS
+
+ return ffestb_R110711_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R110711_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1107_item (ffesta_tokens[1], t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_R110712_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R110712_ -- "USE" NAME COMMA NAME POINTS NAME
+
+ return ffestb_R110712_; // to lexer
+
+ Make sure the statement has a valid form for the USE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R110712_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R11079_;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "USE", t);
+ ffestc_R1107_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_R1202 -- Parse the INTERFACE statement
+
+ return ffestb_R1202; // to lexer
+
+ Make sure the statement has a valid form for the INTERFACE statement.
+ If it does, implement the statement.
+
+ 15-May-90 JCB 1.1
+ Allow INTERFACE by itself; missed this
+ valid form when originally doing syntactic analysis code. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_R1202 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstINTERFACE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorNone, NULL);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ ffesta_confirmed ();
+ switch (ffesta_second_kw)
+ {
+ case FFESTR_secondOPERATOR:
+ ffestb_local_.interface.operator = FFESTP_definedoperatorOPERATOR;
+ break;
+
+ case FFESTR_secondASSIGNMENT:
+ ffestb_local_.interface.operator = FFESTP_definedoperatorASSIGNMENT;
+ break;
+
+ default:
+ ffestb_local_.interface.operator = FFESTP_definedoperatorNone;
+ break;
+ }
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R12021_;
+
+ case FFELEX_typeNAMES:
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlINTERFACE);
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstINTERFACEOPERATOR:
+ if (*(ffelex_token_text (ffesta_tokens[0])
+ + FFESTR_firstlINTERFACEOPERATOR) == '\0')
+ ffestb_local_.interface.operator
+ = FFESTP_definedoperatorOPERATOR;
+ break;
+
+ case FFESTR_firstINTERFACEASSGNMNT:
+ if (*(ffelex_token_text (ffesta_tokens[0])
+ + FFESTR_firstlINTERFACEASSGNMNT) == '\0')
+ ffestb_local_.interface.operator
+ = FFESTP_definedoperatorASSIGNMENT;
+ break;
+
+ case FFESTR_firstINTERFACE:
+ ffestb_local_.interface.operator = FFESTP_definedoperatorNone;
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ case FFELEX_typeOPEN_ARRAY: /* Sigh. */
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (*p == '\0')
+ {
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorNone, NULL);
+ return (ffelexHandler) ffesta_zero (t);
+ }
+ break;
+ }
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1] = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ return (ffelexHandler) ffestb_R12021_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INTERFACE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INTERFACE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "INTERFACE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R12021_ -- "INTERFACE" NAME
+
+ return ffestb_R12021_; // to lexer
+
+ Make sure the statement has a valid form for the INTERFACE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_R12021_ (ffelexToken t)
+{
+ ffestb_local_.interface.slash = TRUE; /* Slash follows open paren. */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorNone, ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.interface.slash = FALSE; /* Slash doesn't follow. */
+ /* Fall through. */
+ case FFELEX_typeOPEN_ARRAY:
+ switch (ffestb_local_.interface.operator)
+ {
+ case FFESTP_definedoperatorNone:
+ break;
+
+ case FFESTP_definedoperatorOPERATOR:
+ ffestb_local_.interface.assignment = FALSE;
+ return (ffelexHandler) ffestb_R12022_;
+
+ case FFESTP_definedoperatorASSIGNMENT:
+ ffestb_local_.interface.assignment = TRUE;
+ return (ffelexHandler) ffestb_R12022_;
+
+ default:
+ assert (FALSE);
+ }
+ break;
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ break;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INTERFACE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R12022_ -- "INTERFACE" "OPERATOR/ASSIGNMENT" OPEN_PAREN
+
+ return ffestb_R12022_; // to lexer
+
+ Make sure the statement has a valid form for the INTERFACE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_R12022_ (ffelexToken t)
+{
+ ffesta_tokens[2] = ffelex_token_use (t);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typePERIOD:
+ if (ffestb_local_.interface.slash)
+ break;
+ return (ffelexHandler) ffestb_R12023_;
+
+ case FFELEX_typePOWER:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorPOWER;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeASTERISK:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorMULT;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typePLUS:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorADD;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeCONCAT:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorCONCAT;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeSLASH:
+ if (ffestb_local_.interface.slash)
+ {
+ ffestb_local_.interface.operator = FFESTP_definedoperatorCONCAT;
+ return (ffelexHandler) ffestb_R12025_;
+ }
+ ffestb_local_.interface.operator = FFESTP_definedoperatorDIVIDE;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeMINUS:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorSUBTRACT;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeREL_EQ:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorEQ;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeREL_NE:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorNE;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeOPEN_ANGLE:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorLT;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeREL_LE:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorLE;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeCLOSE_ANGLE:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorGT;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeREL_GE:
+ if (ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorGE;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeEQUALS:
+ if (ffestb_local_.interface.slash)
+ {
+ ffestb_local_.interface.operator = FFESTP_definedoperatorNE;
+ return (ffelexHandler) ffestb_R12025_;
+ }
+ ffestb_local_.interface.operator = FFESTP_definedoperatorASSIGNMENT;
+ return (ffelexHandler) ffestb_R12025_;
+
+ case FFELEX_typeCLOSE_ARRAY:
+ if (!ffestb_local_.interface.slash)
+ {
+ ffestb_local_.interface.operator = FFESTP_definedoperatorDIVIDE;
+ return (ffelexHandler) ffestb_R12026_;
+ }
+ ffestb_local_.interface.operator = FFESTP_definedoperatorCONCAT;
+ return (ffelexHandler) ffestb_R12026_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ if (!ffestb_local_.interface.slash)
+ break;
+ ffestb_local_.interface.operator = FFESTP_definedoperatorDIVIDE;
+ return (ffelexHandler) ffestb_R12026_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INTERFACE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R12023_ -- "INTERFACE" NAME OPEN_PAREN PERIOD
+
+ return ffestb_R12023_; // to lexer
+
+ Make sure the statement has a valid form for the INTERFACE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_R12023_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R12024_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INTERFACE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R12024_ -- "INTERFACE" NAME OPEN_PAREN PERIOD NAME
+
+ return ffestb_R12024_; // to lexer
+
+ Make sure the statement has a valid form for the INTERFACE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_R12024_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typePERIOD:
+ return (ffelexHandler) ffestb_R12025_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INTERFACE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R12025_ -- "INTERFACE" NAME OPEN_PAREN operator
+
+ return ffestb_R12025_; // to lexer
+
+ Make sure the statement has a valid form for the INTERFACE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_R12025_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_R12026_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INTERFACE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R12026_ -- "INTERFACE" NAME OPEN_PAREN operator CLOSE_PAREN
+
+ return ffestb_R12026_; // to lexer
+
+ Make sure the statement has a valid form for the INTERFACE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_R12026_ (ffelexToken t)
+{
+ char *p;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (ffestb_local_.interface.assignment
+ && (ffestb_local_.interface.operator
+ != FFESTP_definedoperatorASSIGNMENT))
+ {
+ ffebad_start (FFEBAD_INTERFACE_ASSIGNMENT);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[1]),
+ ffelex_token_where_column (ffesta_tokens[1]));
+ ffebad_here (1, ffelex_token_where_line (ffesta_tokens[2]),
+ ffelex_token_where_column (ffesta_tokens[2]));
+ ffebad_finish ();
+ }
+ switch (ffelex_token_type (ffesta_tokens[2]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffestr_other (ffesta_tokens[2]))
+ {
+ case FFESTR_otherNOT:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorNOT, NULL);
+ break;
+
+ case FFESTR_otherAND:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorAND, NULL);
+ break;
+
+ case FFESTR_otherOR:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorOR, NULL);
+ break;
+
+ case FFESTR_otherEQV:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorEQV, NULL);
+ break;
+
+ case FFESTR_otherNEQV:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorNEQV, NULL);
+ break;
+
+ case FFESTR_otherEQ:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorEQ, NULL);
+ break;
+
+ case FFESTR_otherNE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorNE, NULL);
+ break;
+
+ case FFESTR_otherLT:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorLT, NULL);
+ break;
+
+ case FFESTR_otherLE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorLE, NULL);
+ break;
+
+ case FFESTR_otherGT:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorGT, NULL);
+ break;
+
+ case FFESTR_otherGE:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorGE, NULL);
+ break;
+
+ default:
+ for (p = ffelex_token_text (ffesta_tokens[2]); *p != '\0'; ++p)
+ {
+ if (! ISALPHA (*p))
+ {
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_ffebad_1t (FFEBAD_INTERFACE_NONLETTER,
+ ffesta_tokens[2]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ }
+ }
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (FFESTP_definedoperatorOPERATOR,
+ ffesta_tokens[2]);
+ }
+ break;
+
+ case FFELEX_typeEQUALS:
+ if (!ffestb_local_.interface.assignment
+ && (ffestb_local_.interface.operator
+ == FFESTP_definedoperatorASSIGNMENT))
+ {
+ ffebad_start (FFEBAD_INTERFACE_OPERATOR);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[1]),
+ ffelex_token_where_column (ffesta_tokens[1]));
+ ffebad_here (1, ffelex_token_where_line (ffesta_tokens[2]),
+ ffelex_token_where_column (ffesta_tokens[2]));
+ ffebad_finish ();
+ }
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (ffestb_local_.interface.operator, NULL);
+ break;
+
+ default:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1202 (ffestb_local_.interface.operator, NULL);
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INTERFACE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_S3P4 -- Parse the INCLUDE line
+
+ return ffestb_S3P4; // to lexer
+
+ Make sure the statement has a valid form for the INCLUDE line. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_S3P4 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexHandler next;
+ ffelexToken nt;
+ ffelexToken ut;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstINCLUDE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ case FFELEX_typeAPOSTROPHE:
+ case FFELEX_typeQUOTE:
+ break;
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+ ffesta_confirmed ();
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool, FFEEXPR_contextINCLUDE,
+ (ffeexprCallback) ffestb_S3P41_)))
+ (t);
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstINCLUDE)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlINCLUDE);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeAPOSTROPHE:
+ case FFELEX_typeQUOTE:
+ break;
+ }
+ ffesta_confirmed ();
+ if (*p == '\0')
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool, FFEEXPR_contextINCLUDE,
+ (ffeexprCallback) ffestb_S3P41_)))
+ (t);
+ if (! ISDIGIT (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ nt = ffelex_token_number_from_names (ffesta_tokens[0], i);
+ p += ffelex_token_length (nt);
+ i += ffelex_token_length (nt);
+ if ((*p != '_') || (++i, *++p != '\0'))
+ {
+ ffelex_token_kill (nt);
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ ut = ffelex_token_uscore_from_names (ffesta_tokens[0], i - 1);
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs
+ (ffesta_output_pool, FFEEXPR_contextINCLUDE,
+ (ffeexprCallback) ffestb_S3P41_)))
+ (nt);
+ ffelex_token_kill (nt);
+ next = (ffelexHandler) (*next) (ut);
+ ffelex_token_kill (ut);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INCLUDE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INCLUDE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "INCLUDE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_S3P41_ -- "INCLUDE" [NUMBER "_"] expr
+
+ (ffestb_S3P41_) // to expression handler
+
+ Make sure the next token is an EOS, but not a SEMICOLON. */
+
+static ffelexHandler
+ffestb_S3P41_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffe_is_pedantic ()
+ && ((ffelex_token_type (t) == FFELEX_typeSEMICOLON)
+ || ffesta_line_has_semicolons))
+ {
+ ffebad_start_msg ("INCLUDE at %0 not the only statement on the source line", FFEBAD_severityWARNING);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ }
+ ffestc_S3P4 (expr, ft);
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INCLUDE", t);
+ break;
+ }
+
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V012 -- Parse the MAP statement
+
+ return ffestb_V012; // to lexer
+
+ Make sure the statement has a valid form for the MAP statement. If
+ it does, implement the statement. */
+
+#if FFESTR_VXT
+ffelexHandler
+ffestb_V012 (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstMAP)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstMAP)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlMAP)
+ {
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlMAP);
+ goto bad_i; /* :::::::::::::::::::: */
+ }
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V012 ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "MAP", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid first token. */
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "MAP", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "MAP", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_V014 -- Parse the VOLATILE statement
+
+ return ffestb_V014; // to lexer
+
+ Make sure the statement has a valid form for the VOLATILE statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_V014 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffelexHandler next;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstVOLATILE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V014_start ();
+ return (ffelexHandler) ffestb_V0141_ (t);
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V014_start ();
+ return (ffelexHandler) ffestb_V0141_;
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstVOLATILE)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlVOLATILE);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ if (!ffesta_is_inhibited ())
+ ffestc_V014_start ();
+ return (ffelexHandler) ffestb_V0141_ (t);
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ if (!ffesta_is_inhibited ())
+ ffestc_V014_start ();
+ return (ffelexHandler) ffestb_V0141_;
+ }
+
+ /* Here, we have at least one char after "VOLATILE" and t is COMMA or
+ EOS/SEMICOLON. */
+
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ if (!ffesta_is_inhibited ())
+ ffestc_V014_start ();
+ next = (ffelexHandler) ffestb_V0141_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "VOLATILE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "VOLATILE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "VOLATILE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0141_ -- "VOLATILE" [COLONCOLON]
+
+ return ffestb_V0141_; // to lexer
+
+ Handle NAME or SLASH. */
+
+static ffelexHandler
+ffestb_V0141_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffestb_local_.V014.is_cblock = FALSE;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0144_;
+
+ case FFELEX_typeSLASH:
+ ffestb_local_.V014.is_cblock = TRUE;
+ return (ffelexHandler) ffestb_V0142_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "VOLATILE", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V014_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0142_ -- "VOLATILE" [COLONCOLON] SLASH
+
+ return ffestb_V0142_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_V0142_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0143_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "VOLATILE", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V014_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0143_ -- "VOLATILE" [COLONCOLON] SLASH NAME
+
+ return ffestb_V0143_; // to lexer
+
+ Handle SLASH. */
+
+static ffelexHandler
+ffestb_V0143_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeSLASH:
+ return (ffelexHandler) ffestb_V0144_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "VOLATILE", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V014_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0144_ -- "VOLATILE" [COLONCOLON] R523
+
+ return ffestb_V0144_; // to lexer
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_V0144_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffestb_local_.V014.is_cblock)
+ ffestc_V014_item_cblock (ffesta_tokens[1]);
+ else
+ ffestc_V014_item_object (ffesta_tokens[1]);
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_V0141_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffestb_local_.V014.is_cblock)
+ ffestc_V014_item_cblock (ffesta_tokens[1]);
+ else
+ ffestc_V014_item_object (ffesta_tokens[1]);
+ ffestc_V014_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "VOLATILE", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V014_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V025 -- Parse the DEFINEFILE statement
+
+ return ffestb_V025; // to lexer
+
+ Make sure the statement has a valid form for the DEFINEFILE statement.
+ If it does, implement the statement. */
+
+#if FFESTR_VXT
+ffelexHandler
+ffestb_V025 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffelexHandler next;
+
+ ffestb_local_.V025.started = FALSE;
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstDEFINE:
+ if ((ffelex_token_type (t) != FFELEX_typeNAME)
+ || (ffesta_second_kw != FFESTR_secondFILE))
+ goto bad_1; /* :::::::::::::::::::: */
+ ffesta_confirmed ();
+ return (ffelexHandler) ffestb_V0251_;
+
+ case FFESTR_firstDEFINEFILE:
+ return (ffelexHandler) ffestb_V0251_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstDEFINEFILE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ break;
+ }
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlDEFINEFILE);
+ if (ISDIGIT (*p))
+ nt = ffelex_token_number_from_names (ffesta_tokens[0], i);
+ else if (ffesrc_is_name_init (*p))
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ else
+ goto bad_i; /* :::::::::::::::::::: */
+ next = (ffelexHandler) ffestb_V0251_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0251_ -- "DEFINEFILE" or "DEFINE" "FILE"
+
+ return ffestb_V0251_; // to lexer
+
+ Make sure the statement has a valid form for the DEFINEFILE statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_V0251_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ if (ffelex_token_type (ffesta_tokens[0]) == FFELEX_typeNAME)
+ ffesta_confirmed ();
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEUNIT_DF, (ffeexprCallback) ffestb_V0252_)))
+ (t);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ break;
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0252_ -- "DEFINEFILE" expr
+
+ (ffestb_V0252_) // to expression handler
+
+ Make sure the statement has a valid form for the DEFINEFILE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_V0252_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.V025.u = expr;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_V0253_);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0253_ -- "DEFINEFILE" expr OPEN_PAREN expr
+
+ (ffestb_V0253_) // to expression handler
+
+ Make sure the statement has a valid form for the DEFINEFILE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_V0253_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffestb_local_.V025.m = expr;
+ ffesta_tokens[2] = ffelex_token_use (ft);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_V0254_);
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0254_ -- "DEFINEFILE" expr OPEN_PAREN expr COMMA expr
+
+ (ffestb_V0254_) // to expression handler
+
+ Make sure the statement has a valid form for the DEFINEFILE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_V0254_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffestb_local_.V025.n = expr;
+ ffesta_tokens[3] = ffelex_token_use (ft);
+ return (ffelexHandler) ffestb_V0255_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0255_ -- "DEFINEFILE" expr OPEN_PAREN expr COMMA expr COMMA
+
+ return ffestb_V0255_; // to lexer
+
+ Make sure the statement has a valid form for the DEFINEFILE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_V0255_ (ffelexToken t)
+{
+ char *p;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ p = ffelex_token_text (t);
+ if (!ffesrc_char_match_init (*p, 'U', 'u') || (*++p != '\0'))
+ break;
+ return (ffelexHandler) ffestb_V0256_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0256_ -- "DEFINEFILE" expr OPEN_PAREN expr COMMA expr COMMA "U"
+
+ return ffestb_V0256_; // to lexer
+
+ Make sure the statement has a valid form for the DEFINEFILE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_V0256_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextFILEASSOC,
+ (ffeexprCallback) ffestb_V0257_);
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0257_ -- "DEFINEFILE" expr OPEN_PAREN expr COMMA expr COMMA "U"
+ COMMA expr
+
+ (ffestb_V0257_) // to expression handler
+
+ Make sure the statement has a valid form for the DEFINEFILE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_V0257_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffestb_local_.V025.asv = expr;
+ ffesta_tokens[4] = ffelex_token_use (ft);
+ return (ffelexHandler) ffestb_V0258_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0258_ -- "DEFINEFILE" expr OPEN_PAREN expr COMMA expr COMMA "U"
+ COMMA expr CLOSE_PAREN
+
+ return ffestb_V0258_; // to lexer
+
+ Make sure the statement has a valid form for the DEFINEFILE statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_V0258_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffestb_local_.V025.started)
+ {
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V025_start ();
+ ffestb_local_.V025.started = TRUE;
+ }
+ if (!ffesta_is_inhibited ())
+ ffestc_V025_item (ffestb_local_.V025.u, ffesta_tokens[1],
+ ffestb_local_.V025.m, ffesta_tokens[2],
+ ffestb_local_.V025.n, ffesta_tokens[3],
+ ffestb_local_.V025.asv, ffesta_tokens[4]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ ffelex_token_kill (ffesta_tokens[4]);
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEUNIT_DF, (ffeexprCallback) ffestb_V0252_);
+ if (!ffesta_is_inhibited ())
+ ffestc_V025_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffesta_tokens[3]);
+ ffelex_token_kill (ffesta_tokens[4]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DEFINE FILE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_subr_kill_easy_ -- Kill I/O statement data structure
+
+ ffestb_subr_kill_easy_();
+
+ Kills all tokens in the I/O data structure. Assumes that they are
+ overlaid with each other (union) in ffest_private.h and the typing
+ and structure references assume (though not necessarily dangerous if
+ FALSE) that INQUIRE has the most file elements. */
+
+#if FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_easy_ (ffestpInquireIx max)
+{
+ ffestpInquireIx ix;
+
+ for (ix = 0; ix < max; ++ix)
+ {
+ if (ffestp_file.inquire.inquire_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.inquire.inquire_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.inquire.inquire_spec[ix].kw);
+ if (ffestp_file.inquire.inquire_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.inquire.inquire_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_accept_ -- Kill ACCEPT statement data structure
+
+ ffestb_subr_kill_accept_();
+
+ Kills all tokens in the ACCEPT data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_accept_ ()
+{
+ ffestpAcceptIx ix;
+
+ for (ix = 0; ix < FFESTP_acceptix; ++ix)
+ {
+ if (ffestp_file.accept.accept_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.accept.accept_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.accept.accept_spec[ix].kw);
+ if (ffestp_file.accept.accept_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.accept.accept_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_beru_ -- Kill BACKSPACE/ENDFILE/REWIND/UNLOCK statement
+ data structure
+
+ ffestb_subr_kill_beru_();
+
+ Kills all tokens in the BACKSPACE/ENDFILE/REWIND/UNLOCK data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_beru_ ()
+{
+ ffestpBeruIx ix;
+
+ for (ix = 0; ix < FFESTP_beruix; ++ix)
+ {
+ if (ffestp_file.beru.beru_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.beru.beru_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.beru.beru_spec[ix].kw);
+ if (ffestp_file.beru.beru_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.beru.beru_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_close_ -- Kill CLOSE statement data structure
+
+ ffestb_subr_kill_close_();
+
+ Kills all tokens in the CLOSE data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_close_ ()
+{
+ ffestpCloseIx ix;
+
+ for (ix = 0; ix < FFESTP_closeix; ++ix)
+ {
+ if (ffestp_file.close.close_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.close.close_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.close.close_spec[ix].kw);
+ if (ffestp_file.close.close_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.close.close_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_delete_ -- Kill DELETE statement data structure
+
+ ffestb_subr_kill_delete_();
+
+ Kills all tokens in the DELETE data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_delete_ ()
+{
+ ffestpDeleteIx ix;
+
+ for (ix = 0; ix < FFESTP_deleteix; ++ix)
+ {
+ if (ffestp_file.delete.delete_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.delete.delete_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.delete.delete_spec[ix].kw);
+ if (ffestp_file.delete.delete_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.delete.delete_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_inquire_ -- Kill INQUIRE statement data structure
+
+ ffestb_subr_kill_inquire_();
+
+ Kills all tokens in the INQUIRE data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_inquire_ ()
+{
+ ffestpInquireIx ix;
+
+ for (ix = 0; ix < FFESTP_inquireix; ++ix)
+ {
+ if (ffestp_file.inquire.inquire_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.inquire.inquire_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.inquire.inquire_spec[ix].kw);
+ if (ffestp_file.inquire.inquire_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.inquire.inquire_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_open_ -- Kill OPEN statement data structure
+
+ ffestb_subr_kill_open_();
+
+ Kills all tokens in the OPEN data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_open_ ()
+{
+ ffestpOpenIx ix;
+
+ for (ix = 0; ix < FFESTP_openix; ++ix)
+ {
+ if (ffestp_file.open.open_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.open.open_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.open.open_spec[ix].kw);
+ if (ffestp_file.open.open_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.open.open_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_print_ -- Kill PRINT statement data structure
+
+ ffestb_subr_kill_print_();
+
+ Kills all tokens in the PRINT data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_print_ ()
+{
+ ffestpPrintIx ix;
+
+ for (ix = 0; ix < FFESTP_printix; ++ix)
+ {
+ if (ffestp_file.print.print_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.print.print_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.print.print_spec[ix].kw);
+ if (ffestp_file.print.print_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.print.print_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_read_ -- Kill READ statement data structure
+
+ ffestb_subr_kill_read_();
+
+ Kills all tokens in the READ data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_read_ ()
+{
+ ffestpReadIx ix;
+
+ for (ix = 0; ix < FFESTP_readix; ++ix)
+ {
+ if (ffestp_file.read.read_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.read.read_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.read.read_spec[ix].kw);
+ if (ffestp_file.read.read_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.read.read_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_rewrite_ -- Kill REWRITE statement data structure
+
+ ffestb_subr_kill_rewrite_();
+
+ Kills all tokens in the REWRITE data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_rewrite_ ()
+{
+ ffestpRewriteIx ix;
+
+ for (ix = 0; ix < FFESTP_rewriteix; ++ix)
+ {
+ if (ffestp_file.rewrite.rewrite_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.rewrite.rewrite_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.rewrite.rewrite_spec[ix].kw);
+ if (ffestp_file.rewrite.rewrite_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.rewrite.rewrite_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_type_ -- Kill TYPE statement data structure
+
+ ffestb_subr_kill_type_();
+
+ Kills all tokens in the TYPE data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_type_ ()
+{
+ ffestpTypeIx ix;
+
+ for (ix = 0; ix < FFESTP_typeix; ++ix)
+ {
+ if (ffestp_file.type.type_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.type.type_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.type.type_spec[ix].kw);
+ if (ffestp_file.type.type_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.type.type_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_subr_kill_write_ -- Kill WRITE statement data structure
+
+ ffestb_subr_kill_write_();
+
+ Kills all tokens in the WRITE data structure. */
+
+#if !FFESTB_KILL_EASY_
+static void
+ffestb_subr_kill_write_ ()
+{
+ ffestpWriteIx ix;
+
+ for (ix = 0; ix < FFESTP_writeix; ++ix)
+ {
+ if (ffestp_file.write.write_spec[ix].kw_or_val_present)
+ {
+ if (ffestp_file.write.write_spec[ix].kw_present)
+ ffelex_token_kill (ffestp_file.write.write_spec[ix].kw);
+ if (ffestp_file.write.write_spec[ix].value_present)
+ ffelex_token_kill (ffestp_file.write.write_spec[ix].value);
+ }
+ }
+}
+
+#endif
+/* ffestb_beru -- Parse the BACKSPACE/ENDFILE/REWIND/UNLOCK statement
+
+ return ffestb_beru; // to lexer
+
+ Make sure the statement has a valid form for the BACKSPACE/ENDFILE/REWIND/
+ UNLOCK statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_beru (ffelexToken t)
+{
+ ffelexHandler next;
+ ffestpBeruIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeOPEN_PAREN:
+ for (ix = 0; ix < FFESTP_beruix; ++ix)
+ ffestp_file.beru.beru_spec[ix].kw_or_val_present = FALSE;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_beru2_;
+
+ default:
+ break;
+ }
+
+ for (ix = 0; ix < FFESTP_beruix; ++ix)
+ ffestp_file.beru.beru_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM,
+ (ffeexprCallback) ffestb_beru1_)))
+ (t);
+
+ case FFELEX_typeNAMES:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeOPEN_PAREN:
+ if (ffelex_token_length (ffesta_tokens[0])
+ != ffestb_args.beru.len)
+ break;
+
+ for (ix = 0; ix < FFESTP_beruix; ++ix)
+ ffestp_file.beru.beru_spec[ix].kw_or_val_present = FALSE;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_beru2_;
+
+ default:
+ break;
+ }
+ for (ix = 0; ix < FFESTP_beruix; ++ix)
+ ffestp_file.beru.beru_spec[ix].kw_or_val_present = FALSE;
+ next = (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_beru1_);
+ next = (ffelexHandler) ffelex_splice_tokens (next, ffesta_tokens[0],
+ ffestb_args.beru.len);
+ if (next == NULL)
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.beru.badname, ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.beru.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_beru1_ -- "BACKSPACE/ENDFILE/REWIND/UNLOCK" expr
+
+ (ffestb_beru1_) // to expression handler
+
+ Make sure the next token is an EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_beru1_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ ffesta_confirmed ();
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].kw_or_val_present
+ = TRUE;
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].kw_present = FALSE;
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].value_present = TRUE;
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].value_is_label
+ = FALSE;
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].value
+ = ffelex_token_use (ft);
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].u.expr = expr;
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstBACKSPACE:
+ ffestc_R919 ();
+ break;
+
+ case FFESTR_firstENDFILE:
+ case FFESTR_firstEND:
+ ffestc_R920 ();
+ break;
+
+ case FFESTR_firstREWIND:
+ ffestc_R921 ();
+ break;
+
+#if FFESTR_VXT
+ case FFESTR_firstUNLOCK:
+ ffestc_V022 ();
+ break;
+#endif
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffestb_subr_kill_beru_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_beru_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.beru.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_beru2_ -- "BACKSPACE/ENDFILE/REWIND/UNLOCK" OPEN_PAREN
+
+ return ffestb_beru2_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_beru2_ (ffelexToken t)
+{
+ ffelexToken nt;
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_beru3_;
+
+ default:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUMAMBIG, (ffeexprCallback) ffestb_beru4_)))
+ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_beru3_ -- "BACKSPACE/ENDFILE/REWIND/UNLOCK" OPEN_PAREN NAME
+
+ return ffestb_beru3_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_beru3_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+ ffelexToken ot;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffelex_token_kill (ffesta_tokens[1]);
+ nt = ffesta_tokens[2];
+ next = (ffelexHandler) ffestb_beru5_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ nt = ffesta_tokens[1];
+ ot = ffesta_tokens[2];
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUMAMBIG, (ffeexprCallback) ffestb_beru4_)))
+ (nt);
+ ffelex_token_kill (nt);
+ next = (ffelexHandler) (*next) (ot);
+ ffelex_token_kill (ot);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_beru4_ -- "BACKSPACE/ENDFILE/REWIND/UNLOCK" OPEN_PAREN expr [CLOSE_PAREN]
+
+ (ffestb_beru4_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here.
+
+ 15-Feb-91 JCB 1.2
+ Now using new mechanism whereby expr comes back as opITEM if the
+ expr is considered part (or all) of an I/O control list (and should
+ be stripped of its outer opITEM node) or not if it is considered
+ a plain unit number that happens to have been enclosed in parens.
+ 26-Mar-90 JCB 1.1
+ No longer expecting close-paren here because of constructs like
+ BACKSPACE (5)+2, so now expecting either COMMA because it was a
+ construct like BACKSPACE (5+2,... or EOS/SEMICOLON because it is like
+ the former construct. Ah, the vagaries of Fortran. */
+
+static ffelexHandler
+ffestb_beru4_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ bool inlist;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ if (ffebld_op (expr) == FFEBLD_opITEM)
+ {
+ inlist = TRUE;
+ expr = ffebld_head (expr);
+ }
+ else
+ inlist = FALSE;
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].kw_or_val_present
+ = TRUE;
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].kw_present = FALSE;
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].value_present = TRUE;
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].value_is_label
+ = FALSE;
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].value
+ = ffelex_token_use (ft);
+ ffestp_file.beru.beru_spec[FFESTP_beruixUNIT].u.expr = expr;
+ if (inlist)
+ return (ffelexHandler) ffestb_beru9_ (t);
+ return (ffelexHandler) ffestb_beru10_ (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_beru_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.beru.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_beru5_ -- "BACKSPACE/ENDFILE/REWIND/UNLOCK" OPEN_PAREN [external-file-unit
+ COMMA]
+
+ return ffestb_beru5_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_beru5_ (ffelexToken t)
+{
+ ffestrGenio kw;
+
+ ffestb_local_.beru.label = FALSE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ kw = ffestr_genio (t);
+ switch (kw)
+ {
+ case FFESTR_genioERR:
+ ffestb_local_.beru.ix = FFESTP_beruixERR;
+ ffestb_local_.beru.label = TRUE;
+ break;
+
+ case FFESTR_genioIOSTAT:
+ ffestb_local_.beru.ix = FFESTP_beruixIOSTAT;
+ ffestb_local_.beru.left = TRUE;
+ ffestb_local_.beru.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_genioUNIT:
+ ffestb_local_.beru.ix = FFESTP_beruixUNIT;
+ ffestb_local_.beru.left = FALSE;
+ ffestb_local_.beru.context = FFEEXPR_contextFILENUM;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.beru.beru_spec[ffestb_local_.beru.ix]
+ .kw_or_val_present)
+ break; /* Can't specify a keyword twice! */
+ ffestp_file.beru.beru_spec[ffestb_local_.beru.ix]
+ .kw_or_val_present = TRUE;
+ ffestp_file.beru.beru_spec[ffestb_local_.beru.ix]
+ .kw_present = TRUE;
+ ffestp_file.beru.beru_spec[ffestb_local_.beru.ix]
+ .value_present = FALSE;
+ ffestp_file.beru.beru_spec[ffestb_local_.beru.ix].value_is_label
+ = ffestb_local_.beru.label;
+ ffestp_file.beru.beru_spec[ffestb_local_.beru.ix].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_beru6_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_beru_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.beru.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_beru6_ -- "BACKSPACE/ENDFILE/REWIND/UNLOCK" OPEN_PAREN [external-file-unit
+ COMMA] NAME
+
+ return ffestb_beru6_; // to lexer
+
+ Make sure EQUALS here, send next token to expression handler. */
+
+static ffelexHandler
+ffestb_beru6_ (ffelexToken t)
+{
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestb_local_.beru.label)
+ return (ffelexHandler) ffestb_beru8_;
+ if (ffestb_local_.beru.left)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_local_.beru.context,
+ (ffeexprCallback) ffestb_beru7_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.beru.context,
+ (ffeexprCallback) ffestb_beru7_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_beru_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.beru.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_beru7_ -- "BACKSPACE/ENDFILE/REWIND/UNLOCK" OPEN_PAREN ... NAME EQUALS expr
+
+ (ffestb_beru7_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_beru7_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.beru.beru_spec[ffestb_local_.beru.ix].value_present
+ = TRUE;
+ ffestp_file.beru.beru_spec[ffestb_local_.beru.ix].value
+ = ffelex_token_use (ft);
+ ffestp_file.beru.beru_spec[ffestb_local_.beru.ix].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_beru5_;
+ return (ffelexHandler) ffestb_beru10_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_beru_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.beru.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_beru8_ -- "BACKSPACE/ENDFILE/REWIND/UNLOCK" OPEN_PAREN ... NAME EQUALS
+
+ return ffestb_beru8_; // to lexer
+
+ Handle NUMBER for label here. */
+
+static ffelexHandler
+ffestb_beru8_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestp_file.beru.beru_spec[ffestb_local_.beru.ix].value_present
+ = TRUE;
+ ffestp_file.beru.beru_spec[ffestb_local_.beru.ix].value
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_beru9_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_beru_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.beru.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_beru9_ -- "BACKSPACE/ENDFILE/REWIND/UNLOCK" OPEN_PAREN ... NAME EQUALS
+ NUMBER
+
+ return ffestb_beru9_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_beru9_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_beru5_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_beru10_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_beru_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.beru.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_beru10_ -- "BACKSPACE/ENDFILE/REWIND/UNLOCK" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_beru10_; // to lexer
+
+ Handle EOS or SEMICOLON here. */
+
+static ffelexHandler
+ffestb_beru10_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstBACKSPACE:
+ ffestc_R919 ();
+ break;
+
+ case FFESTR_firstENDFILE:
+ case FFESTR_firstEND:
+ ffestc_R920 ();
+ break;
+
+ case FFESTR_firstREWIND:
+ ffestc_R921 ();
+ break;
+
+#if FFESTR_VXT
+ case FFESTR_firstUNLOCK:
+ ffestc_V022 ();
+ break;
+#endif
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffestb_subr_kill_beru_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_beru_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.beru.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_vxtcode -- Parse the VXT DECODE/ENCODE statement
+
+ return ffestb_vxtcode; // to lexer
+
+ Make sure the statement has a valid form for the VXT DECODE/ENCODE
+ statement. If it does, implement the statement. */
+
+#if FFESTR_VXT
+ffelexHandler
+ffestb_vxtcode (ffelexToken t)
+{
+ ffestpVxtcodeIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ for (ix = 0; ix < FFESTP_vxtcodeix; ++ix)
+ ffestp_file.vxtcode.vxtcode_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_vxtcode1_);
+ }
+
+ case FFELEX_typeNAMES:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ if (ffelex_token_length (ffesta_tokens[0])
+ != ffestb_args.vxtcode.len)
+ goto bad_0; /* :::::::::::::::::::: */
+
+ for (ix = 0; ix < FFESTP_vxtcodeix; ++ix)
+ ffestp_file.vxtcode.vxtcode_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_vxtcode1_);
+ }
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_vxtcode1_ -- "VXTCODE" OPEN_PAREN expr
+
+ (ffestb_vxtcode1_) // to expression handler
+
+ Handle COMMA here. */
+
+static ffelexHandler
+ffestb_vxtcode1_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixC].kw_or_val_present
+ = TRUE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixC].kw_present = FALSE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixC].value_present = TRUE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixC].value_is_label
+ = FALSE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixC].value
+ = ffelex_token_use (ft);
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixC].u.expr = expr;
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMAT, (ffeexprCallback) ffestb_vxtcode2_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_vxtcode_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_vxtcode2_ -- "VXTCODE" OPEN_PAREN expr COMMA expr
+
+ (ffestb_vxtcode2_) // to expression handler
+
+ Handle COMMA here. */
+
+static ffelexHandler
+ffestb_vxtcode2_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixF].kw_or_val_present
+ = TRUE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixF].kw_present = FALSE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixF].value_present = TRUE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixF].value_is_label
+ = (expr == NULL);
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixF].value
+ = ffelex_token_use (ft);
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixF].u.expr = expr;
+ if (ffesta_first_kw == FFESTR_firstENCODE)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextFILEVXTCODE,
+ (ffeexprCallback) ffestb_vxtcode3_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEVXTCODE,
+ (ffeexprCallback) ffestb_vxtcode3_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_vxtcode_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_vxtcode3_ -- "VXTCODE" OPEN_PAREN expr COMMA expr COMMA expr
+
+ (ffestb_vxtcode3_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_vxtcode3_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixB].kw_or_val_present
+ = TRUE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixB].kw_present = FALSE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixB].value_present = TRUE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixB].value_is_label
+ = FALSE;
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixB].value
+ = ffelex_token_use (ft);
+ ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixB].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_vxtcode4_;
+ return (ffelexHandler) ffestb_vxtcode9_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_vxtcode_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_vxtcode4_ -- "VXTCODE" OPEN_PAREN ...
+
+ return ffestb_vxtcode4_; // to lexer
+
+ Handle NAME=expr construct here. */
+
+static ffelexHandler
+ffestb_vxtcode4_ (ffelexToken t)
+{
+ ffestrGenio kw;
+
+ ffestb_local_.vxtcode.label = FALSE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ kw = ffestr_genio (t);
+ switch (kw)
+ {
+ case FFESTR_genioERR:
+ ffestb_local_.vxtcode.ix = FFESTP_vxtcodeixERR;
+ ffestb_local_.vxtcode.label = TRUE;
+ break;
+
+ case FFESTR_genioIOSTAT:
+ ffestb_local_.vxtcode.ix = FFESTP_vxtcodeixIOSTAT;
+ ffestb_local_.vxtcode.left = TRUE;
+ ffestb_local_.vxtcode.context = FFEEXPR_contextFILEINT;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix]
+ .kw_or_val_present)
+ break; /* Can't specify a keyword twice! */
+ ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix]
+ .kw_or_val_present = TRUE;
+ ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix]
+ .kw_present = TRUE;
+ ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix]
+ .value_present = FALSE;
+ ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix].value_is_label
+ = ffestb_local_.vxtcode.label;
+ ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_vxtcode5_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_vxtcode_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_vxtcode5_ -- "VXTCODE" OPEN_PAREN [external-file-unit COMMA [format
+ COMMA]] NAME
+
+ return ffestb_vxtcode5_; // to lexer
+
+ Make sure EQUALS here, send next token to expression handler. */
+
+static ffelexHandler
+ffestb_vxtcode5_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestb_local_.vxtcode.label)
+ return (ffelexHandler) ffestb_vxtcode7_;
+ if (ffestb_local_.vxtcode.left)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_local_.vxtcode.context,
+ (ffeexprCallback) ffestb_vxtcode6_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.vxtcode.context,
+ (ffeexprCallback) ffestb_vxtcode6_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_vxtcode_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_vxtcode6_ -- "VXTCODE" OPEN_PAREN ... NAME EQUALS expr
+
+ (ffestb_vxtcode6_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_vxtcode6_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix].value_present
+ = TRUE;
+ ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix].value
+ = ffelex_token_use (ft);
+ ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_vxtcode4_;
+ return (ffelexHandler) ffestb_vxtcode9_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_vxtcode_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_vxtcode7_ -- "VXTCODE" OPEN_PAREN ... NAME EQUALS
+
+ return ffestb_vxtcode7_; // to lexer
+
+ Handle NUMBER for label here. */
+
+static ffelexHandler
+ffestb_vxtcode7_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix].value_present
+ = TRUE;
+ ffestp_file.vxtcode.vxtcode_spec[ffestb_local_.vxtcode.ix].value
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_vxtcode8_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_vxtcode_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_vxtcode8_ -- "VXTCODE" OPEN_PAREN ... NAME EQUALS NUMBER
+
+ return ffestb_vxtcode8_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_vxtcode8_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_vxtcode4_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_vxtcode9_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_vxtcode_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_vxtcode9_ -- "VXTCODE" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_vxtcode9_; // to lexer
+
+ Handle EOS or SEMICOLON here.
+
+ 07-Jun-90 JCB 1.1
+ Context for ENCODE/DECODE expressions is now IOLISTDF instead of IOLIST
+ since they apply to internal files. */
+
+static ffelexHandler
+ffestb_vxtcode9_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffesta_first_kw == FFESTR_firstENCODE)
+ {
+ ffestc_V023_start ();
+ ffestc_V023_finish ();
+ }
+ else
+ {
+ ffestc_V024_start ();
+ ffestc_V024_finish ();
+ }
+ }
+ ffestb_subr_kill_vxtcode_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeOPEN_PAREN:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ if (ffesta_first_kw == FFESTR_firstENCODE)
+ ffestc_V023_start ();
+ else
+ ffestc_V024_start ();
+ ffestb_subr_kill_vxtcode_ ();
+ if (ffesta_first_kw == FFESTR_firstDECODE)
+ next = (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextIOLISTDF,
+ (ffeexprCallback) ffestb_vxtcode10_);
+ else
+ next = (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLISTDF,
+ (ffeexprCallback) ffestb_vxtcode10_);
+
+ /* EXTENSION: Allow an optional preceding COMMA here if not pedantic.
+ (f2c provides this extension, as do other compilers, supposedly.) */
+
+ if (!ffe_is_pedantic () && (ffelex_token_type (t) == FFELEX_typeCOMMA))
+ return next;
+
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_vxtcode_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_vxtcode10_ -- "VXTCODE(...)" expr
+
+ (ffestb_vxtcode10_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here.
+
+ 07-Jun-90 JCB 1.1
+ Context for ENCODE/DECODE expressions is now IOLISTDF instead of IOLIST
+ since they apply to internal files. */
+
+static ffelexHandler
+ffestb_vxtcode10_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ if (ffesta_first_kw == FFESTR_firstENCODE)
+ ffestc_V023_item (expr, ft);
+ else
+ ffestc_V024_item (expr, ft);
+ if (ffesta_first_kw == FFESTR_firstDECODE)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextIOLISTDF,
+ (ffeexprCallback) ffestb_vxtcode10_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLISTDF,
+ (ffeexprCallback) ffestb_vxtcode10_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ if (ffesta_first_kw == FFESTR_firstENCODE)
+ {
+ ffestc_V023_item (expr, ft);
+ ffestc_V023_finish ();
+ }
+ else
+ {
+ ffestc_V024_item (expr, ft);
+ ffestc_V024_finish ();
+ }
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ if (ffesta_first_kw == FFESTR_firstENCODE)
+ ffestc_V023_finish ();
+ else
+ ffestc_V024_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.vxtcode.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_R904 -- Parse an OPEN statement
+
+ return ffestb_R904; // to lexer
+
+ Make sure the statement has a valid form for an OPEN statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R904 (ffelexToken t)
+{
+ ffestpOpenIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstOPEN)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstOPEN)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlOPEN)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ for (ix = 0; ix < FFESTP_openix; ++ix)
+ ffestp_file.open.open_spec[ix].kw_or_val_present = FALSE;
+
+ return (ffelexHandler) ffestb_R9041_;
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "OPEN", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "OPEN", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R9041_ -- "OPEN" OPEN_PAREN
+
+ return ffestb_R9041_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9041_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9042_;
+
+ default:
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_R9043_)))
+ (t);
+ }
+}
+
+/* ffestb_R9042_ -- "OPEN" OPEN_PAREN NAME
+
+ return ffestb_R9042_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_R9042_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) ffestb_R9044_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_R9043_)))
+ (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_R9043_ -- "OPEN" OPEN_PAREN expr
+
+ (ffestb_R9043_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9043_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.open.open_spec[FFESTP_openixUNIT].kw_or_val_present
+ = TRUE;
+ ffestp_file.open.open_spec[FFESTP_openixUNIT].kw_present = FALSE;
+ ffestp_file.open.open_spec[FFESTP_openixUNIT].value_present = TRUE;
+ ffestp_file.open.open_spec[FFESTP_openixUNIT].value_is_label
+ = FALSE;
+ ffestp_file.open.open_spec[FFESTP_openixUNIT].value
+ = ffelex_token_use (ft);
+ ffestp_file.open.open_spec[FFESTP_openixUNIT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9044_;
+ return (ffelexHandler) ffestb_R9049_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_open_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "OPEN", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9044_ -- "OPEN" OPEN_PAREN [external-file-unit COMMA]
+
+ return ffestb_R9044_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9044_ (ffelexToken t)
+{
+ ffestrOpen kw;
+
+ ffestb_local_.open.label = FALSE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ kw = ffestr_open (t);
+ switch (kw)
+ {
+ case FFESTR_openACCESS:
+ ffestb_local_.open.ix = FFESTP_openixACCESS;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_openACTION:
+ ffestb_local_.open.ix = FFESTP_openixACTION;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_openASSOCIATEVARIABLE:
+ ffestb_local_.open.ix = FFESTP_openixASSOCIATEVARIABLE;
+ ffestb_local_.open.left = TRUE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEASSOC;
+ break;
+
+ case FFESTR_openBLANK:
+ ffestb_local_.open.ix = FFESTP_openixBLANK;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_openBLOCKSIZE:
+ ffestb_local_.open.ix = FFESTP_openixBLOCKSIZE;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_openBUFFERCOUNT:
+ ffestb_local_.open.ix = FFESTP_openixBUFFERCOUNT;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_openCARRIAGECONTROL:
+ ffestb_local_.open.ix = FFESTP_openixCARRIAGECONTROL;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_openDEFAULTFILE:
+ ffestb_local_.open.ix = FFESTP_openixDEFAULTFILE;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_openDELIM:
+ ffestb_local_.open.ix = FFESTP_openixDELIM;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_openDISP:
+ case FFESTR_openDISPOSE:
+ ffestb_local_.open.ix = FFESTP_openixDISPOSE;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_openERR:
+ ffestb_local_.open.ix = FFESTP_openixERR;
+ ffestb_local_.open.label = TRUE;
+ break;
+
+ case FFESTR_openEXTENDSIZE:
+ ffestb_local_.open.ix = FFESTP_openixEXTENDSIZE;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_openFILE:
+ case FFESTR_openNAME:
+ ffestb_local_.open.ix = FFESTP_openixFILE;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_openFORM:
+ ffestb_local_.open.ix = FFESTP_openixFORM;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_openINITIALSIZE:
+ ffestb_local_.open.ix = FFESTP_openixINITIALSIZE;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_openIOSTAT:
+ ffestb_local_.open.ix = FFESTP_openixIOSTAT;
+ ffestb_local_.open.left = TRUE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEINT;
+ break;
+
+#if 0 /* Haven't added support for expression
+ context yet (though easy). */
+ case FFESTR_openKEY:
+ ffestb_local_.open.ix = FFESTP_openixKEY;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEKEY;
+ break;
+#endif
+
+ case FFESTR_openMAXREC:
+ ffestb_local_.open.ix = FFESTP_openixMAXREC;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_openNOSPANBLOCKS:
+ if (ffestp_file.open.open_spec[FFESTP_openixNOSPANBLOCKS]
+ .kw_or_val_present)
+ goto bad; /* :::::::::::::::::::: */
+ ffestp_file.open.open_spec[FFESTP_openixNOSPANBLOCKS]
+ .kw_or_val_present = TRUE;
+ ffestp_file.open.open_spec[FFESTP_openixNOSPANBLOCKS]
+ .kw_present = TRUE;
+ ffestp_file.open.open_spec[FFESTP_openixNOSPANBLOCKS]
+ .value_present = FALSE;
+ ffestp_file.open.open_spec[FFESTP_openixNOSPANBLOCKS].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9048_;
+
+ case FFESTR_openORGANIZATION:
+ ffestb_local_.open.ix = FFESTP_openixORGANIZATION;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_openPAD:
+ ffestb_local_.open.ix = FFESTP_openixPAD;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_openPOSITION:
+ ffestb_local_.open.ix = FFESTP_openixPOSITION;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_openREADONLY:
+ if (ffestp_file.open.open_spec[FFESTP_openixREADONLY]
+ .kw_or_val_present)
+ goto bad; /* :::::::::::::::::::: */
+ ffestp_file.open.open_spec[FFESTP_openixREADONLY]
+ .kw_or_val_present = TRUE;
+ ffestp_file.open.open_spec[FFESTP_openixREADONLY]
+ .kw_present = TRUE;
+ ffestp_file.open.open_spec[FFESTP_openixREADONLY]
+ .value_present = FALSE;
+ ffestp_file.open.open_spec[FFESTP_openixREADONLY].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9048_;
+
+ case FFESTR_openRECL:
+ case FFESTR_openRECORDSIZE:
+ ffestb_local_.open.ix = FFESTP_openixRECL;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_openRECORDTYPE:
+ ffestb_local_.open.ix = FFESTP_openixRECORDTYPE;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_openSHARED:
+ if (ffestp_file.open.open_spec[FFESTP_openixSHARED]
+ .kw_or_val_present)
+ goto bad; /* :::::::::::::::::::: */
+ ffestp_file.open.open_spec[FFESTP_openixSHARED]
+ .kw_or_val_present = TRUE;
+ ffestp_file.open.open_spec[FFESTP_openixSHARED]
+ .kw_present = TRUE;
+ ffestp_file.open.open_spec[FFESTP_openixSHARED]
+ .value_present = FALSE;
+ ffestp_file.open.open_spec[FFESTP_openixSHARED].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9048_;
+
+ case FFESTR_openSTATUS:
+ case FFESTR_openTYPE:
+ ffestb_local_.open.ix = FFESTP_openixSTATUS;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_openUNIT:
+ ffestb_local_.open.ix = FFESTP_openixUNIT;
+ ffestb_local_.open.left = FALSE;
+ ffestb_local_.open.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_openUSEROPEN:
+ ffestb_local_.open.ix = FFESTP_openixUSEROPEN;
+ ffestb_local_.open.left = TRUE;
+ ffestb_local_.open.context = FFEEXPR_contextFILEEXTFUNC;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.open.open_spec[ffestb_local_.open.ix]
+ .kw_or_val_present)
+ break; /* Can't specify a keyword twice! */
+ ffestp_file.open.open_spec[ffestb_local_.open.ix]
+ .kw_or_val_present = TRUE;
+ ffestp_file.open.open_spec[ffestb_local_.open.ix]
+ .kw_present = TRUE;
+ ffestp_file.open.open_spec[ffestb_local_.open.ix]
+ .value_present = FALSE;
+ ffestp_file.open.open_spec[ffestb_local_.open.ix].value_is_label
+ = ffestb_local_.open.label;
+ ffestp_file.open.open_spec[ffestb_local_.open.ix].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9045_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_open_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "OPEN", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9045_ -- "OPEN" OPEN_PAREN [external-file-unit COMMA] NAME
+
+ return ffestb_R9045_; // to lexer
+
+ Make sure EQUALS here, send next token to expression handler. */
+
+static ffelexHandler
+ffestb_R9045_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestb_local_.open.label)
+ return (ffelexHandler) ffestb_R9047_;
+ if (ffestb_local_.open.left)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_local_.open.context,
+ (ffeexprCallback) ffestb_R9046_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.open.context,
+ (ffeexprCallback) ffestb_R9046_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_open_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "OPEN", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9046_ -- "OPEN" OPEN_PAREN ... NAME EQUALS expr
+
+ (ffestb_R9046_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9046_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.open.open_spec[ffestb_local_.open.ix].value_present
+ = TRUE;
+ ffestp_file.open.open_spec[ffestb_local_.open.ix].value
+ = ffelex_token_use (ft);
+ ffestp_file.open.open_spec[ffestb_local_.open.ix].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9044_;
+ return (ffelexHandler) ffestb_R9049_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_open_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "OPEN", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9047_ -- "OPEN" OPEN_PAREN ... NAME EQUALS
+
+ return ffestb_R9047_; // to lexer
+
+ Handle NUMBER for label here. */
+
+static ffelexHandler
+ffestb_R9047_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestp_file.open.open_spec[ffestb_local_.open.ix].value_present
+ = TRUE;
+ ffestp_file.open.open_spec[ffestb_local_.open.ix].value
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9048_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_open_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "OPEN", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9048_ -- "OPEN" OPEN_PAREN ... NAME EQUALS NUMBER
+
+ return ffestb_R9048_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9048_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R9044_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_R9049_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_open_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "OPEN", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9049_ -- "OPEN" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_R9049_; // to lexer
+
+ Handle EOS or SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R9049_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R904 ();
+ ffestb_subr_kill_open_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_open_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "OPEN", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R907 -- Parse a CLOSE statement
+
+ return ffestb_R907; // to lexer
+
+ Make sure the statement has a valid form for a CLOSE statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R907 (ffelexToken t)
+{
+ ffestpCloseIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstCLOSE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstCLOSE)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlCLOSE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ for (ix = 0; ix < FFESTP_closeix; ++ix)
+ ffestp_file.close.close_spec[ix].kw_or_val_present = FALSE;
+
+ return (ffelexHandler) ffestb_R9071_;
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CLOSE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CLOSE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R9071_ -- "CLOSE" OPEN_PAREN
+
+ return ffestb_R9071_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9071_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9072_;
+
+ default:
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_R9073_)))
+ (t);
+ }
+}
+
+/* ffestb_R9072_ -- "CLOSE" OPEN_PAREN NAME
+
+ return ffestb_R9072_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_R9072_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) ffestb_R9074_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_R9073_)))
+ (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_R9073_ -- "CLOSE" OPEN_PAREN expr
+
+ (ffestb_R9073_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9073_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.close.close_spec[FFESTP_closeixUNIT].kw_or_val_present
+ = TRUE;
+ ffestp_file.close.close_spec[FFESTP_closeixUNIT].kw_present = FALSE;
+ ffestp_file.close.close_spec[FFESTP_closeixUNIT].value_present = TRUE;
+ ffestp_file.close.close_spec[FFESTP_closeixUNIT].value_is_label
+ = FALSE;
+ ffestp_file.close.close_spec[FFESTP_closeixUNIT].value
+ = ffelex_token_use (ft);
+ ffestp_file.close.close_spec[FFESTP_closeixUNIT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9074_;
+ return (ffelexHandler) ffestb_R9079_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_close_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CLOSE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9074_ -- "CLOSE" OPEN_PAREN [external-file-unit COMMA]
+
+ return ffestb_R9074_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9074_ (ffelexToken t)
+{
+ ffestrGenio kw;
+
+ ffestb_local_.close.label = FALSE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ kw = ffestr_genio (t);
+ switch (kw)
+ {
+ case FFESTR_genioERR:
+ ffestb_local_.close.ix = FFESTP_closeixERR;
+ ffestb_local_.close.label = TRUE;
+ break;
+
+ case FFESTR_genioIOSTAT:
+ ffestb_local_.close.ix = FFESTP_closeixIOSTAT;
+ ffestb_local_.close.left = TRUE;
+ ffestb_local_.close.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_genioSTATUS:
+ case FFESTR_genioDISP:
+ case FFESTR_genioDISPOSE:
+ ffestb_local_.close.ix = FFESTP_closeixSTATUS;
+ ffestb_local_.close.left = FALSE;
+ ffestb_local_.close.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_genioUNIT:
+ ffestb_local_.close.ix = FFESTP_closeixUNIT;
+ ffestb_local_.close.left = FALSE;
+ ffestb_local_.close.context = FFEEXPR_contextFILENUM;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.close.close_spec[ffestb_local_.close.ix]
+ .kw_or_val_present)
+ break; /* Can't specify a keyword twice! */
+ ffestp_file.close.close_spec[ffestb_local_.close.ix]
+ .kw_or_val_present = TRUE;
+ ffestp_file.close.close_spec[ffestb_local_.close.ix]
+ .kw_present = TRUE;
+ ffestp_file.close.close_spec[ffestb_local_.close.ix]
+ .value_present = FALSE;
+ ffestp_file.close.close_spec[ffestb_local_.close.ix].value_is_label
+ = ffestb_local_.close.label;
+ ffestp_file.close.close_spec[ffestb_local_.close.ix].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9075_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_close_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CLOSE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9075_ -- "CLOSE" OPEN_PAREN [external-file-unit COMMA] NAME
+
+ return ffestb_R9075_; // to lexer
+
+ Make sure EQUALS here, send next token to expression handler. */
+
+static ffelexHandler
+ffestb_R9075_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestb_local_.close.label)
+ return (ffelexHandler) ffestb_R9077_;
+ if (ffestb_local_.close.left)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_local_.close.context,
+ (ffeexprCallback) ffestb_R9076_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.close.context,
+ (ffeexprCallback) ffestb_R9076_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_close_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CLOSE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9076_ -- "CLOSE" OPEN_PAREN ... NAME EQUALS expr
+
+ (ffestb_R9076_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9076_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.close.close_spec[ffestb_local_.close.ix].value_present
+ = TRUE;
+ ffestp_file.close.close_spec[ffestb_local_.close.ix].value
+ = ffelex_token_use (ft);
+ ffestp_file.close.close_spec[ffestb_local_.close.ix].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9074_;
+ return (ffelexHandler) ffestb_R9079_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_close_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CLOSE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9077_ -- "CLOSE" OPEN_PAREN ... NAME EQUALS
+
+ return ffestb_R9077_; // to lexer
+
+ Handle NUMBER for label here. */
+
+static ffelexHandler
+ffestb_R9077_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestp_file.close.close_spec[ffestb_local_.close.ix].value_present
+ = TRUE;
+ ffestp_file.close.close_spec[ffestb_local_.close.ix].value
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9078_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_close_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CLOSE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9078_ -- "CLOSE" OPEN_PAREN ... NAME EQUALS NUMBER
+
+ return ffestb_R9078_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9078_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R9074_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_R9079_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_close_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CLOSE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9079_ -- "CLOSE" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_R9079_; // to lexer
+
+ Handle EOS or SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R9079_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R907 ();
+ ffestb_subr_kill_close_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_close_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "CLOSE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R909 -- Parse the READ statement
+
+ return ffestb_R909; // to lexer
+
+ Make sure the statement has a valid form for the READ
+ statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R909 (ffelexToken t)
+{
+ ffelexHandler next;
+ ffestpReadIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstREAD)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeOPEN_PAREN:
+ for (ix = 0; ix < FFESTP_readix; ++ix)
+ ffestp_file.read.read_spec[ix].kw_or_val_present = FALSE;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9092_;
+
+ default:
+ break;
+ }
+
+ for (ix = 0; ix < FFESTP_readix; ++ix)
+ ffestp_file.read.read_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_R9091_)))
+ (t);
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstREAD)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlREAD)
+ break;
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlREAD)
+ break;
+
+ for (ix = 0; ix < FFESTP_readix; ++ix)
+ ffestp_file.read.read_spec[ix].kw_or_val_present = FALSE;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9092_;
+
+ default:
+ break;
+ }
+ for (ix = 0; ix < FFESTP_readix; ++ix)
+ ffestp_file.read.read_spec[ix].kw_or_val_present = FALSE;
+ next = (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_R9091_);
+ next = (ffelexHandler) ffelex_splice_tokens (next, ffesta_tokens[0],
+ FFESTR_firstlREAD);
+ if (next == NULL)
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R9091_ -- "READ" expr
+
+ (ffestb_R9091_) // to expression handler
+
+ Make sure the next token is a COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_R9091_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].kw_or_val_present
+ = TRUE;
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].kw_present = FALSE;
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].value_present = TRUE;
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].value_is_label
+ = (expr == NULL);
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].value
+ = ffelex_token_use (ft);
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].u.expr = expr;
+ if (!ffesta_is_inhibited ())
+ ffestc_R909_start (TRUE);
+ ffestb_subr_kill_read_ ();
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestc_context_iolist (),
+ (ffeexprCallback) ffestb_R90915_);
+ if (!ffesta_is_inhibited ())
+ ffestc_R909_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_read_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9092_ -- "READ" OPEN_PAREN
+
+ return ffestb_R9092_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9092_ (ffelexToken t)
+{
+ ffelexToken nt;
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9093_;
+
+ default:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEUNITAMBIG, (ffeexprCallback) ffestb_R9094_)))
+ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_R9093_ -- "READ" OPEN_PAREN NAME
+
+ return ffestb_R9093_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_R9093_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+ ffelexToken ot;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffelex_token_kill (ffesta_tokens[1]);
+ nt = ffesta_tokens[2];
+ next = (ffelexHandler) ffestb_R9098_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ nt = ffesta_tokens[1];
+ ot = ffesta_tokens[2];
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEUNITAMBIG, (ffeexprCallback) ffestb_R9094_)))
+ (nt);
+ ffelex_token_kill (nt);
+ next = (ffelexHandler) (*next) (ot);
+ ffelex_token_kill (ot);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_R9094_ -- "READ" OPEN_PAREN expr [CLOSE_PAREN]
+
+ (ffestb_R9094_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here.
+
+ 15-Feb-91 JCB 1.1
+ Use new ffeexpr mechanism whereby the expr is encased in an opITEM if
+ ffeexpr decided it was an item in a control list (hence a unit
+ specifier), or a format specifier otherwise. */
+
+static ffelexHandler
+ffestb_R9094_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ if (expr == NULL)
+ goto bad; /* :::::::::::::::::::: */
+
+ if (ffebld_op (expr) != FFEBLD_opITEM)
+ {
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].kw_or_val_present
+ = TRUE;
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].kw_present = FALSE;
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].value_present = TRUE;
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].value_is_label
+ = FALSE;
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].value
+ = ffelex_token_use (ft);
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].u.expr = expr;
+ if (!ffesta_is_inhibited ())
+ ffestc_R909_start (TRUE);
+ ffestb_subr_kill_read_ ();
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ ffestc_context_iolist (),
+ (ffeexprCallback) ffestb_R90915_);
+ if (!ffesta_is_inhibited ())
+ ffestc_R909_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ }
+
+ expr = ffebld_head (expr);
+
+ if (expr == NULL)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ ffestp_file.read.read_spec[FFESTP_readixUNIT].kw_or_val_present
+ = TRUE;
+ ffestp_file.read.read_spec[FFESTP_readixUNIT].kw_present = FALSE;
+ ffestp_file.read.read_spec[FFESTP_readixUNIT].value_present = TRUE;
+ ffestp_file.read.read_spec[FFESTP_readixUNIT].value_is_label
+ = FALSE;
+ ffestp_file.read.read_spec[FFESTP_readixUNIT].value
+ = ffelex_token_use (ft);
+ ffestp_file.read.read_spec[FFESTP_readixUNIT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9095_;
+ return (ffelexHandler) ffestb_R90913_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_read_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9095_ -- "READ" OPEN_PAREN expr COMMA
+
+ return ffestb_R9095_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9095_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9096_;
+
+ default:
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_R9097_)))
+ (t);
+ }
+}
+
+/* ffestb_R9096_ -- "READ" OPEN_PAREN expr COMMA NAME
+
+ return ffestb_R9096_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_R9096_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) ffestb_R9098_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_R9097_)))
+ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_R9097_ -- "READ" OPEN_PAREN expr COMMA expr
+
+ (ffestb_R9097_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9097_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].kw_or_val_present
+ = TRUE;
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].kw_present = FALSE;
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].value_present = TRUE;
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].value_is_label
+ = (expr == NULL);
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].value
+ = ffelex_token_use (ft);
+ ffestp_file.read.read_spec[FFESTP_readixFORMAT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9098_;
+ return (ffelexHandler) ffestb_R90913_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_read_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9098_ -- "READ" OPEN_PAREN [external-file-unit COMMA [format
+ COMMA]]
+
+ return ffestb_R9098_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9098_ (ffelexToken t)
+{
+ ffestrGenio kw;
+
+ ffestb_local_.read.label = FALSE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ kw = ffestr_genio (t);
+ switch (kw)
+ {
+ case FFESTR_genioADVANCE:
+ ffestb_local_.read.ix = FFESTP_readixADVANCE;
+ ffestb_local_.read.left = FALSE;
+ ffestb_local_.read.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_genioEOR:
+ ffestb_local_.read.ix = FFESTP_readixEOR;
+ ffestb_local_.read.label = TRUE;
+ break;
+
+ case FFESTR_genioERR:
+ ffestb_local_.read.ix = FFESTP_readixERR;
+ ffestb_local_.read.label = TRUE;
+ break;
+
+ case FFESTR_genioEND:
+ ffestb_local_.read.ix = FFESTP_readixEND;
+ ffestb_local_.read.label = TRUE;
+ break;
+
+ case FFESTR_genioFMT:
+ ffestb_local_.read.ix = FFESTP_readixFORMAT;
+ ffestb_local_.read.left = FALSE;
+ ffestb_local_.read.context = FFEEXPR_contextFILEFORMAT;
+ break;
+
+ case FFESTR_genioIOSTAT:
+ ffestb_local_.read.ix = FFESTP_readixIOSTAT;
+ ffestb_local_.read.left = TRUE;
+ ffestb_local_.read.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_genioKEY:
+ case FFESTR_genioKEYEQ:
+ ffestb_local_.read.ix = FFESTP_readixKEYEQ;
+ ffestb_local_.read.left = FALSE;
+ ffestb_local_.read.context = FFEEXPR_contextFILENUMCHAR;
+ break;
+
+ case FFESTR_genioKEYGE:
+ ffestb_local_.read.ix = FFESTP_readixKEYGE;
+ ffestb_local_.read.left = FALSE;
+ ffestb_local_.read.context = FFEEXPR_contextFILENUMCHAR;
+ break;
+
+ case FFESTR_genioKEYGT:
+ ffestb_local_.read.ix = FFESTP_readixKEYGT;
+ ffestb_local_.read.left = FALSE;
+ ffestb_local_.read.context = FFEEXPR_contextFILENUMCHAR;
+ break;
+
+ case FFESTR_genioKEYID:
+ ffestb_local_.read.ix = FFESTP_readixKEYID;
+ ffestb_local_.read.left = FALSE;
+ ffestb_local_.read.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_genioNML:
+ ffestb_local_.read.ix = FFESTP_readixFORMAT;
+ ffestb_local_.read.left = TRUE;
+ ffestb_local_.read.context = FFEEXPR_contextFILENAMELIST;
+ break;
+
+ case FFESTR_genioNULLS:
+ ffestb_local_.read.ix = FFESTP_readixNULLS;
+ ffestb_local_.read.left = TRUE;
+ ffestb_local_.read.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_genioREC:
+ ffestb_local_.read.ix = FFESTP_readixREC;
+ ffestb_local_.read.left = FALSE;
+ ffestb_local_.read.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_genioSIZE:
+ ffestb_local_.read.ix = FFESTP_readixSIZE;
+ ffestb_local_.read.left = TRUE;
+ ffestb_local_.read.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_genioUNIT:
+ ffestb_local_.read.ix = FFESTP_readixUNIT;
+ ffestb_local_.read.left = FALSE;
+ ffestb_local_.read.context = FFEEXPR_contextFILEUNIT;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[ffestb_local_.read.ix]
+ .kw_or_val_present)
+ break; /* Can't specify a keyword twice! */
+ ffestp_file.read.read_spec[ffestb_local_.read.ix]
+ .kw_or_val_present = TRUE;
+ ffestp_file.read.read_spec[ffestb_local_.read.ix]
+ .kw_present = TRUE;
+ ffestp_file.read.read_spec[ffestb_local_.read.ix]
+ .value_present = FALSE;
+ ffestp_file.read.read_spec[ffestb_local_.read.ix].value_is_label
+ = ffestb_local_.read.label;
+ ffestp_file.read.read_spec[ffestb_local_.read.ix].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9099_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_read_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9099_ -- "READ" OPEN_PAREN [external-file-unit COMMA [format
+ COMMA]] NAME
+
+ return ffestb_R9099_; // to lexer
+
+ Make sure EQUALS here, send next token to expression handler. */
+
+static ffelexHandler
+ffestb_R9099_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestb_local_.read.label)
+ return (ffelexHandler) ffestb_R90911_;
+ if (ffestb_local_.read.left)
+ return (ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ ffestb_local_.read.context,
+ (ffeexprCallback) ffestb_R90910_);
+ return (ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.read.context,
+ (ffeexprCallback) ffestb_R90910_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_read_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R90910_ -- "READ" OPEN_PAREN ... NAME EQUALS expr
+
+ (ffestb_R90910_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R90910_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ {
+ if (ffestb_local_.read.context == FFEEXPR_contextFILEFORMAT)
+ ffestp_file.read.read_spec[ffestb_local_.read.ix]
+ .value_is_label = TRUE;
+ else
+ break;
+ }
+ ffestp_file.read.read_spec[ffestb_local_.read.ix].value_present
+ = TRUE;
+ ffestp_file.read.read_spec[ffestb_local_.read.ix].value
+ = ffelex_token_use (ft);
+ ffestp_file.read.read_spec[ffestb_local_.read.ix].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9098_;
+ return (ffelexHandler) ffestb_R90913_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_read_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R90911_ -- "READ" OPEN_PAREN ... NAME EQUALS
+
+ return ffestb_R90911_; // to lexer
+
+ Handle NUMBER for label here. */
+
+static ffelexHandler
+ffestb_R90911_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestp_file.read.read_spec[ffestb_local_.read.ix].value_present
+ = TRUE;
+ ffestp_file.read.read_spec[ffestb_local_.read.ix].value
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R90912_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_read_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R90912_ -- "READ" OPEN_PAREN ... NAME EQUALS NUMBER
+
+ return ffestb_R90912_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R90912_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R9098_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_R90913_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_read_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R90913_ -- "READ" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_R90913_; // to lexer
+
+ Handle EOS or SEMICOLON here.
+
+ 15-Feb-91 JCB 1.1
+ Fix to allow implied-DO construct here (OPEN_PAREN) -- actually,
+ don't presume knowledge of what an initial token in an lhs context
+ is going to be, let ffeexpr_lhs handle that as much as possible. */
+
+static ffelexHandler
+ffestb_R90913_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R909_start (FALSE);
+ ffestc_R909_finish ();
+ }
+ ffestb_subr_kill_read_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_confirmed ();
+ /* Fall through. */
+ case FFELEX_typeOPEN_PAREN: /* Could still be assignment!! */
+ break;
+ }
+
+ /* If token isn't NAME or OPEN_PAREN, ffeexpr_lhs will ultimately whine
+ about it, so leave it up to that code. */
+
+ /* EXTENSION: Allow an optional preceding COMMA here if not pedantic. (f2c
+ provides this extension, as do other compilers, supposedly.) */
+
+ if (!ffe_is_pedantic () && (ffelex_token_type (t) == FFELEX_typeCOMMA))
+ return (ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ ffestc_context_iolist (),
+ (ffeexprCallback) ffestb_R90914_);
+
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_lhs (ffesta_output_pool,
+ ffestc_context_iolist (),
+ (ffeexprCallback) ffestb_R90914_)))
+ (t);
+}
+
+/* ffestb_R90914_ -- "READ(...)" expr
+
+ (ffestb_R90914_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R90914_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R909_start (FALSE);
+ ffestb_subr_kill_read_ ();
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R909_item (expr, ft);
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestc_context_iolist (),
+ (ffeexprCallback) ffestb_R90915_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R909_start (FALSE);
+ ffestb_subr_kill_read_ ();
+
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R909_item (expr, ft);
+ ffestc_R909_finish ();
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_read_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R90915_ -- "READ(...)" expr COMMA expr
+
+ (ffestb_R90915_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R90915_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R909_item (expr, ft);
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestc_context_iolist (),
+ (ffeexprCallback) ffestb_R90915_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R909_item (expr, ft);
+ ffestc_R909_finish ();
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R909_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "READ", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R910 -- Parse the WRITE statement
+
+ return ffestb_R910; // to lexer
+
+ Make sure the statement has a valid form for the WRITE
+ statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R910 (ffelexToken t)
+{
+ ffestpWriteIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstWRITE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ for (ix = 0; ix < FFESTP_writeix; ++ix)
+ ffestp_file.write.write_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) ffestb_R9101_;
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstWRITE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlWRITE)
+ goto bad_0; /* :::::::::::::::::::: */
+
+ for (ix = 0; ix < FFESTP_writeix; ++ix)
+ ffestp_file.write.write_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) ffestb_R9101_;
+ }
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R9101_ -- "WRITE" OPEN_PAREN
+
+ return ffestb_R9101_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9101_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9102_;
+
+ default:
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEUNIT, (ffeexprCallback) ffestb_R9103_)))
+ (t);
+ }
+}
+
+/* ffestb_R9102_ -- "WRITE" OPEN_PAREN NAME
+
+ return ffestb_R9102_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_R9102_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) ffestb_R9107_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEUNIT, (ffeexprCallback) ffestb_R9103_)))
+ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_R9103_ -- "WRITE" OPEN_PAREN expr [CLOSE_PAREN]
+
+ (ffestb_R9103_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R9103_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.write.write_spec[FFESTP_writeixUNIT].kw_or_val_present
+ = TRUE;
+ ffestp_file.write.write_spec[FFESTP_writeixUNIT].kw_present = FALSE;
+ ffestp_file.write.write_spec[FFESTP_writeixUNIT].value_present = TRUE;
+ ffestp_file.write.write_spec[FFESTP_writeixUNIT].value_is_label
+ = FALSE;
+ ffestp_file.write.write_spec[FFESTP_writeixUNIT].value
+ = ffelex_token_use (ft);
+ ffestp_file.write.write_spec[FFESTP_writeixUNIT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9104_;
+ return (ffelexHandler) ffestb_R91012_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_write_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9104_ -- "WRITE" OPEN_PAREN expr COMMA
+
+ return ffestb_R9104_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9104_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9105_;
+
+ default:
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_R9106_)))
+ (t);
+ }
+}
+
+/* ffestb_R9105_ -- "WRITE" OPEN_PAREN expr COMMA NAME
+
+ return ffestb_R9105_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_R9105_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) ffestb_R9107_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_R9106_)))
+ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_R9106_ -- "WRITE" OPEN_PAREN expr COMMA expr
+
+ (ffestb_R9106_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9106_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ ffestp_file.write.write_spec[FFESTP_writeixFORMAT].kw_or_val_present
+ = TRUE;
+ ffestp_file.write.write_spec[FFESTP_writeixFORMAT].kw_present = FALSE;
+ ffestp_file.write.write_spec[FFESTP_writeixFORMAT].value_present = TRUE;
+ ffestp_file.write.write_spec[FFESTP_writeixFORMAT].value_is_label
+ = (expr == NULL);
+ ffestp_file.write.write_spec[FFESTP_writeixFORMAT].value
+ = ffelex_token_use (ft);
+ ffestp_file.write.write_spec[FFESTP_writeixFORMAT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9107_;
+ return (ffelexHandler) ffestb_R91012_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_write_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9107_ -- "WRITE" OPEN_PAREN [external-file-unit COMMA [format
+ COMMA]]
+
+ return ffestb_R9107_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9107_ (ffelexToken t)
+{
+ ffestrGenio kw;
+
+ ffestb_local_.write.label = FALSE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ kw = ffestr_genio (t);
+ switch (kw)
+ {
+ case FFESTR_genioADVANCE:
+ ffestb_local_.write.ix = FFESTP_writeixADVANCE;
+ ffestb_local_.write.left = FALSE;
+ ffestb_local_.write.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_genioEOR:
+ ffestb_local_.write.ix = FFESTP_writeixEOR;
+ ffestb_local_.write.label = TRUE;
+ break;
+
+ case FFESTR_genioERR:
+ ffestb_local_.write.ix = FFESTP_writeixERR;
+ ffestb_local_.write.label = TRUE;
+ break;
+
+ case FFESTR_genioFMT:
+ ffestb_local_.write.ix = FFESTP_writeixFORMAT;
+ ffestb_local_.write.left = FALSE;
+ ffestb_local_.write.context = FFEEXPR_contextFILEFORMAT;
+ break;
+
+ case FFESTR_genioIOSTAT:
+ ffestb_local_.write.ix = FFESTP_writeixIOSTAT;
+ ffestb_local_.write.left = TRUE;
+ ffestb_local_.write.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_genioNML:
+ ffestb_local_.write.ix = FFESTP_writeixFORMAT;
+ ffestb_local_.write.left = TRUE;
+ ffestb_local_.write.context = FFEEXPR_contextFILENAMELIST;
+ break;
+
+ case FFESTR_genioREC:
+ ffestb_local_.write.ix = FFESTP_writeixREC;
+ ffestb_local_.write.left = FALSE;
+ ffestb_local_.write.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_genioUNIT:
+ ffestb_local_.write.ix = FFESTP_writeixUNIT;
+ ffestb_local_.write.left = FALSE;
+ ffestb_local_.write.context = FFEEXPR_contextFILEUNIT;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.write.write_spec[ffestb_local_.write.ix]
+ .kw_or_val_present)
+ break; /* Can't specify a keyword twice! */
+ ffestp_file.write.write_spec[ffestb_local_.write.ix]
+ .kw_or_val_present = TRUE;
+ ffestp_file.write.write_spec[ffestb_local_.write.ix]
+ .kw_present = TRUE;
+ ffestp_file.write.write_spec[ffestb_local_.write.ix]
+ .value_present = FALSE;
+ ffestp_file.write.write_spec[ffestb_local_.write.ix].value_is_label
+ = ffestb_local_.write.label;
+ ffestp_file.write.write_spec[ffestb_local_.write.ix].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9108_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_write_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9108_ -- "WRITE" OPEN_PAREN [external-file-unit COMMA [format
+ COMMA]] NAME
+
+ return ffestb_R9108_; // to lexer
+
+ Make sure EQUALS here, send next token to expression handler. */
+
+static ffelexHandler
+ffestb_R9108_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestb_local_.write.label)
+ return (ffelexHandler) ffestb_R91010_;
+ if (ffestb_local_.write.left)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_local_.write.context,
+ (ffeexprCallback) ffestb_R9109_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.write.context,
+ (ffeexprCallback) ffestb_R9109_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_write_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9109_ -- "WRITE" OPEN_PAREN ... NAME EQUALS expr
+
+ (ffestb_R9109_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9109_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ {
+ if (ffestb_local_.write.context == FFEEXPR_contextFILEFORMAT)
+ ffestp_file.write.write_spec[ffestb_local_.write.ix]
+ .value_is_label = TRUE;
+ else
+ break;
+ }
+ ffestp_file.write.write_spec[ffestb_local_.write.ix].value_present
+ = TRUE;
+ ffestp_file.write.write_spec[ffestb_local_.write.ix].value
+ = ffelex_token_use (ft);
+ ffestp_file.write.write_spec[ffestb_local_.write.ix].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9107_;
+ return (ffelexHandler) ffestb_R91012_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_write_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R91010_ -- "WRITE" OPEN_PAREN ... NAME EQUALS
+
+ return ffestb_R91010_; // to lexer
+
+ Handle NUMBER for label here. */
+
+static ffelexHandler
+ffestb_R91010_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestp_file.write.write_spec[ffestb_local_.write.ix].value_present
+ = TRUE;
+ ffestp_file.write.write_spec[ffestb_local_.write.ix].value
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R91011_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_write_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R91011_ -- "WRITE" OPEN_PAREN ... NAME EQUALS NUMBER
+
+ return ffestb_R91011_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R91011_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R9107_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_R91012_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_write_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R91012_ -- "WRITE" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_R91012_; // to lexer
+
+ Handle EOS or SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R91012_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R910_start ();
+ ffestc_R910_finish ();
+ }
+ ffestb_subr_kill_write_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_confirmed ();
+ /* Fall through. */
+ case FFELEX_typeOPEN_PAREN: /* Could still be assignment!! */
+
+ /* EXTENSION: Allow an optional preceding COMMA here if not pedantic.
+ (f2c provides this extension, as do other compilers, supposedly.) */
+
+ if (!ffe_is_pedantic () && (ffelex_token_type (t) == FFELEX_typeCOMMA))
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestc_context_iolist (), (ffeexprCallback) ffestb_R91013_);
+
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestc_context_iolist (), (ffeexprCallback) ffestb_R91013_)))
+ (t);
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ break;
+ }
+
+ ffestb_subr_kill_write_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R91013_ -- "WRITE(...)" expr
+
+ (ffestb_R91013_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R91013_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R910_start ();
+ ffestb_subr_kill_write_ ();
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R910_item (expr, ft);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestc_context_iolist (), (ffeexprCallback) ffestb_R91014_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R910_start ();
+ ffestb_subr_kill_write_ ();
+
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R910_item (expr, ft);
+ ffestc_R910_finish ();
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_write_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R91014_ -- "WRITE(...)" expr COMMA expr
+
+ (ffestb_R91014_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R91014_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R910_item (expr, ft);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestc_context_iolist (), (ffeexprCallback) ffestb_R91014_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R910_item (expr, ft);
+ ffestc_R910_finish ();
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R910_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "WRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R911 -- Parse the PRINT statement
+
+ return ffestb_R911; // to lexer
+
+ Make sure the statement has a valid form for the PRINT
+ statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R911 (ffelexToken t)
+{
+ ffelexHandler next;
+ ffestpPrintIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstPRINT)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed ();
+ break;
+
+ default:
+ break;
+ }
+
+ for (ix = 0; ix < FFESTP_printix; ++ix)
+ ffestp_file.print.print_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_R9111_)))
+ (t);
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstPRINT)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlPRINT)
+ break;
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+ for (ix = 0; ix < FFESTP_printix; ++ix)
+ ffestp_file.print.print_spec[ix].kw_or_val_present = FALSE;
+ next = (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_R9111_);
+ next = (ffelexHandler) ffelex_splice_tokens (next, ffesta_tokens[0],
+ FFESTR_firstlPRINT);
+ if (next == NULL)
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PRINT", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PRINT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R9111_ -- "PRINT" expr
+
+ (ffestb_R9111_) // to expression handler
+
+ Make sure the next token is a COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_R9111_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ ffestp_file.print.print_spec[FFESTP_printixFORMAT].kw_or_val_present
+ = TRUE;
+ ffestp_file.print.print_spec[FFESTP_printixFORMAT].kw_present = FALSE;
+ ffestp_file.print.print_spec[FFESTP_printixFORMAT].value_present = TRUE;
+ ffestp_file.print.print_spec[FFESTP_printixFORMAT].value_is_label
+ = (expr == NULL);
+ ffestp_file.print.print_spec[FFESTP_printixFORMAT].value
+ = ffelex_token_use (ft);
+ ffestp_file.print.print_spec[FFESTP_printixFORMAT].u.expr = expr;
+ if (!ffesta_is_inhibited ())
+ ffestc_R911_start ();
+ ffestb_subr_kill_print_ ();
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST, (ffeexprCallback) ffestb_R9112_);
+ if (!ffesta_is_inhibited ())
+ ffestc_R911_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_print_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PRINT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9112_ -- "PRINT" expr COMMA expr
+
+ (ffestb_R9112_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R9112_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R911_item (expr, ft);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST, (ffeexprCallback) ffestb_R9112_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R911_item (expr, ft);
+ ffestc_R911_finish ();
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R911_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PRINT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R923 -- Parse an INQUIRE statement
+
+ return ffestb_R923; // to lexer
+
+ Make sure the statement has a valid form for an INQUIRE statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R923 (ffelexToken t)
+{
+ ffestpInquireIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstINQUIRE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstINQUIRE)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlINQUIRE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ for (ix = 0; ix < FFESTP_inquireix; ++ix)
+ ffestp_file.inquire.inquire_spec[ix].kw_or_val_present = FALSE;
+
+ ffestb_local_.inquire.may_be_iolength = TRUE;
+ return (ffelexHandler) ffestb_R9231_;
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R9231_ -- "INQUIRE" OPEN_PAREN
+
+ return ffestb_R9231_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9231_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9232_;
+
+ default:
+ ffestb_local_.inquire.may_be_iolength = FALSE;
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_R9233_)))
+ (t);
+ }
+}
+
+/* ffestb_R9232_ -- "INQUIRE" OPEN_PAREN NAME
+
+ return ffestb_R9232_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_R9232_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) ffestb_R9234_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ ffestb_local_.inquire.may_be_iolength = FALSE;
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_R9233_)))
+ (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_R9233_ -- "INQUIRE" OPEN_PAREN expr
+
+ (ffestb_R9233_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9233_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].kw_or_val_present
+ = TRUE;
+ ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].kw_present = FALSE;
+ ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].value_present = TRUE;
+ ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].value_is_label
+ = FALSE;
+ ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].value
+ = ffelex_token_use (ft);
+ ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9234_;
+ return (ffelexHandler) ffestb_R9239_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_inquire_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9234_ -- "INQUIRE" OPEN_PAREN [external-file-unit COMMA]
+
+ return ffestb_R9234_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_R9234_ (ffelexToken t)
+{
+ ffestrInquire kw;
+
+ ffestb_local_.inquire.label = FALSE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ kw = ffestr_inquire (t);
+ if (kw != FFESTR_inquireIOLENGTH)
+ ffestb_local_.inquire.may_be_iolength = FALSE;
+ switch (kw)
+ {
+ case FFESTR_inquireACCESS:
+ ffestb_local_.inquire.ix = FFESTP_inquireixACCESS;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireACTION:
+ ffestb_local_.inquire.ix = FFESTP_inquireixACTION;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireBLANK:
+ ffestb_local_.inquire.ix = FFESTP_inquireixBLANK;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireCARRIAGECONTROL:
+ ffestb_local_.inquire.ix = FFESTP_inquireixCARRIAGECONTROL;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_inquireDEFAULTFILE:
+ ffestb_local_.inquire.ix = FFESTP_inquireixDEFAULTFILE;
+ ffestb_local_.inquire.left = FALSE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_inquireDELIM:
+ ffestb_local_.inquire.ix = FFESTP_inquireixDELIM;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireDIRECT:
+ ffestb_local_.inquire.ix = FFESTP_inquireixDIRECT;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireERR:
+ ffestb_local_.inquire.ix = FFESTP_inquireixERR;
+ ffestb_local_.inquire.label = TRUE;
+ break;
+
+ case FFESTR_inquireEXIST:
+ ffestb_local_.inquire.ix = FFESTP_inquireixEXIST;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILELOG;
+ break;
+
+ case FFESTR_inquireFILE:
+ ffestb_local_.inquire.ix = FFESTP_inquireixFILE;
+ ffestb_local_.inquire.left = FALSE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_inquireFORM:
+ ffestb_local_.inquire.ix = FFESTP_inquireixFORM;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireFORMATTED:
+ ffestb_local_.inquire.ix = FFESTP_inquireixFORMATTED;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireIOLENGTH:
+ if (!ffestb_local_.inquire.may_be_iolength)
+ goto bad; /* :::::::::::::::::::: */
+ ffestb_local_.inquire.ix = FFESTP_inquireixIOLENGTH;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_inquireIOSTAT:
+ ffestb_local_.inquire.ix = FFESTP_inquireixIOSTAT;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_inquireKEYED:
+ ffestb_local_.inquire.ix = FFESTP_inquireixKEYED;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_inquireNAME:
+ ffestb_local_.inquire.ix = FFESTP_inquireixNAME;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_inquireNAMED:
+ ffestb_local_.inquire.ix = FFESTP_inquireixNAMED;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILELOG;
+ break;
+
+ case FFESTR_inquireNEXTREC:
+ ffestb_local_.inquire.ix = FFESTP_inquireixNEXTREC;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFINT;
+ break;
+
+ case FFESTR_inquireNUMBER:
+ ffestb_local_.inquire.ix = FFESTP_inquireixNUMBER;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_inquireOPENED:
+ ffestb_local_.inquire.ix = FFESTP_inquireixOPENED;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILELOG;
+ break;
+
+ case FFESTR_inquireORGANIZATION:
+ ffestb_local_.inquire.ix = FFESTP_inquireixORGANIZATION;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_inquirePAD:
+ ffestb_local_.inquire.ix = FFESTP_inquireixPAD;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquirePOSITION:
+ ffestb_local_.inquire.ix = FFESTP_inquireixPOSITION;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireREAD:
+ ffestb_local_.inquire.ix = FFESTP_inquireixREAD;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireREADWRITE:
+ ffestb_local_.inquire.ix = FFESTP_inquireixREADWRITE;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireRECL:
+ ffestb_local_.inquire.ix = FFESTP_inquireixRECL;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_inquireRECORDTYPE:
+ ffestb_local_.inquire.ix = FFESTP_inquireixRECORDTYPE;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILECHAR;
+ break;
+
+ case FFESTR_inquireSEQUENTIAL:
+ ffestb_local_.inquire.ix = FFESTP_inquireixSEQUENTIAL;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireUNFORMATTED:
+ ffestb_local_.inquire.ix = FFESTP_inquireixUNFORMATTED;
+ ffestb_local_.inquire.left = TRUE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILEDFCHAR;
+ break;
+
+ case FFESTR_inquireUNIT:
+ ffestb_local_.inquire.ix = FFESTP_inquireixUNIT;
+ ffestb_local_.inquire.left = FALSE;
+ ffestb_local_.inquire.context = FFEEXPR_contextFILENUM;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix]
+ .kw_or_val_present)
+ break; /* Can't specify a keyword twice! */
+ ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix]
+ .kw_or_val_present = TRUE;
+ ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix]
+ .kw_present = TRUE;
+ ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix]
+ .value_present = FALSE;
+ ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix].value_is_label
+ = ffestb_local_.inquire.label;
+ ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9235_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_inquire_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9235_ -- "INQUIRE" OPEN_PAREN [external-file-unit COMMA] NAME
+
+ return ffestb_R9235_; // to lexer
+
+ Make sure EQUALS here, send next token to expression handler. */
+
+static ffelexHandler
+ffestb_R9235_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestb_local_.inquire.label)
+ return (ffelexHandler) ffestb_R9237_;
+ if (ffestb_local_.inquire.left)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_local_.inquire.context,
+ (ffeexprCallback) ffestb_R9236_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.inquire.context,
+ (ffeexprCallback) ffestb_R9236_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_inquire_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9236_ -- "INQUIRE" OPEN_PAREN ... NAME EQUALS expr
+
+ (ffestb_R9236_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9236_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (ffestb_local_.inquire.ix == FFESTP_inquireixIOLENGTH)
+ break; /* IOLENGTH=expr must be followed by
+ CLOSE_PAREN. */
+ /* Fall through. */
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix].value_present
+ = TRUE;
+ ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix].value
+ = ffelex_token_use (ft);
+ ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_R9234_;
+ if (ffestb_local_.inquire.ix == FFESTP_inquireixIOLENGTH)
+ return (ffelexHandler) ffestb_R92310_;
+ return (ffelexHandler) ffestb_R9239_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_inquire_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9237_ -- "INQUIRE" OPEN_PAREN ... NAME EQUALS
+
+ return ffestb_R9237_; // to lexer
+
+ Handle NUMBER for label here. */
+
+static ffelexHandler
+ffestb_R9237_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix].value_present
+ = TRUE;
+ ffestp_file.inquire.inquire_spec[ffestb_local_.inquire.ix].value
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R9238_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_inquire_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9238_ -- "INQUIRE" OPEN_PAREN ... NAME EQUALS NUMBER
+
+ return ffestb_R9238_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_R9238_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_R9234_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_R9239_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_inquire_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R9239_ -- "INQUIRE" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_R9239_; // to lexer
+
+ Handle EOS or SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R9239_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R923A ();
+ ffestb_subr_kill_inquire_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_inquire_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R92310_ -- "INQUIRE(IOLENGTH=expr)"
+
+ return ffestb_R92310_; // to lexer
+
+ Make sure EOS or SEMICOLON not here; begin R923B processing and expect
+ output IO list. */
+
+static ffelexHandler
+ffestb_R92310_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ break;
+
+ default:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R923B_start ();
+ ffestb_subr_kill_inquire_ ();
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST, (ffeexprCallback) ffestb_R92311_)))
+ (t);
+ }
+
+ ffestb_subr_kill_inquire_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R92311_ -- "INQUIRE(IOLENGTH=expr)" expr
+
+ (ffestb_R92311_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_R92311_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R923B_item (expr, ft);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST, (ffeexprCallback) ffestb_R92311_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R923B_item (expr, ft);
+ ffestc_R923B_finish ();
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R923B_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "INQUIRE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V018 -- Parse the REWRITE statement
+
+ return ffestb_V018; // to lexer
+
+ Make sure the statement has a valid form for the REWRITE
+ statement. If it does, implement the statement. */
+
+#if FFESTR_VXT
+ffelexHandler
+ffestb_V018 (ffelexToken t)
+{
+ ffestpRewriteIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstREWRITE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ for (ix = 0; ix < FFESTP_rewriteix; ++ix)
+ ffestp_file.rewrite.rewrite_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) ffestb_V0181_;
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstREWRITE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlREWRITE)
+ goto bad_0; /* :::::::::::::::::::: */
+
+ for (ix = 0; ix < FFESTP_rewriteix; ++ix)
+ ffestp_file.rewrite.rewrite_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) ffestb_V0181_;
+ }
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_V0181_ -- "REWRITE" OPEN_PAREN
+
+ return ffestb_V0181_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_V0181_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0182_;
+
+ default:
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_V0183_)))
+ (t);
+ }
+}
+
+/* ffestb_V0182_ -- "REWRITE" OPEN_PAREN NAME
+
+ return ffestb_V0182_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_V0182_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) ffestb_V0187_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_V0183_)))
+ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_V0183_ -- "REWRITE" OPEN_PAREN expr [CLOSE_PAREN]
+
+ (ffestb_V0183_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_V0183_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixUNIT].kw_or_val_present
+ = TRUE;
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixUNIT].kw_present = FALSE;
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixUNIT].value_present = TRUE;
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixUNIT].value_is_label
+ = FALSE;
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixUNIT].value
+ = ffelex_token_use (ft);
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixUNIT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_V0184_;
+ return (ffelexHandler) ffestb_V01812_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_rewrite_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0184_ -- "REWRITE" OPEN_PAREN expr COMMA
+
+ return ffestb_V0184_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_V0184_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0185_;
+
+ default:
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMAT, (ffeexprCallback) ffestb_V0186_)))
+ (t);
+ }
+}
+
+/* ffestb_V0185_ -- "REWRITE" OPEN_PAREN expr COMMA NAME
+
+ return ffestb_V0185_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_V0185_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) ffestb_V0187_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMAT, (ffeexprCallback) ffestb_V0186_)))
+ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_V0186_ -- "REWRITE" OPEN_PAREN expr COMMA expr
+
+ (ffestb_V0186_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_V0186_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].kw_or_val_present
+ = TRUE;
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].kw_present = FALSE;
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].value_present = TRUE;
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].value_is_label
+ = (expr == NULL);
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].value
+ = ffelex_token_use (ft);
+ ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_V0187_;
+ return (ffelexHandler) ffestb_V01812_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_rewrite_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0187_ -- "REWRITE" OPEN_PAREN [external-file-unit COMMA [format
+ COMMA]]
+
+ return ffestb_V0187_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_V0187_ (ffelexToken t)
+{
+ ffestrGenio kw;
+
+ ffestb_local_.rewrite.label = FALSE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ kw = ffestr_genio (t);
+ switch (kw)
+ {
+ case FFESTR_genioERR:
+ ffestb_local_.rewrite.ix = FFESTP_rewriteixERR;
+ ffestb_local_.rewrite.label = TRUE;
+ break;
+
+ case FFESTR_genioFMT:
+ ffestb_local_.rewrite.ix = FFESTP_rewriteixFMT;
+ ffestb_local_.rewrite.left = FALSE;
+ ffestb_local_.rewrite.context = FFEEXPR_contextFILEFORMAT;
+ break;
+
+ case FFESTR_genioIOSTAT:
+ ffestb_local_.rewrite.ix = FFESTP_rewriteixIOSTAT;
+ ffestb_local_.rewrite.left = TRUE;
+ ffestb_local_.rewrite.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_genioUNIT:
+ ffestb_local_.rewrite.ix = FFESTP_rewriteixUNIT;
+ ffestb_local_.rewrite.left = FALSE;
+ ffestb_local_.rewrite.context = FFEEXPR_contextFILENUM;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix]
+ .kw_or_val_present)
+ break; /* Can't specify a keyword twice! */
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix]
+ .kw_or_val_present = TRUE;
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix]
+ .kw_present = TRUE;
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix]
+ .value_present = FALSE;
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix].value_is_label
+ = ffestb_local_.rewrite.label;
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0188_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_rewrite_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0188_ -- "REWRITE" OPEN_PAREN [external-file-unit COMMA [format
+ COMMA]] NAME
+
+ return ffestb_V0188_; // to lexer
+
+ Make sure EQUALS here, send next token to expression handler. */
+
+static ffelexHandler
+ffestb_V0188_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestb_local_.rewrite.label)
+ return (ffelexHandler) ffestb_V01810_;
+ if (ffestb_local_.rewrite.left)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_local_.rewrite.context,
+ (ffeexprCallback) ffestb_V0189_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.rewrite.context,
+ (ffeexprCallback) ffestb_V0189_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_rewrite_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0189_ -- "REWRITE" OPEN_PAREN ... NAME EQUALS expr
+
+ (ffestb_V0189_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_V0189_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ if (ffestb_local_.rewrite.context == FFEEXPR_contextFILEFORMAT)
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix]
+ .value_is_label = TRUE;
+ else
+ break;
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix].value_present
+ = TRUE;
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix].value
+ = ffelex_token_use (ft);
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_V0187_;
+ return (ffelexHandler) ffestb_V01812_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_rewrite_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V01810_ -- "REWRITE" OPEN_PAREN ... NAME EQUALS
+
+ return ffestb_V01810_; // to lexer
+
+ Handle NUMBER for label here. */
+
+static ffelexHandler
+ffestb_V01810_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix].value_present
+ = TRUE;
+ ffestp_file.rewrite.rewrite_spec[ffestb_local_.rewrite.ix].value
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V01811_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_rewrite_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V01811_ -- "REWRITE" OPEN_PAREN ... NAME EQUALS NUMBER
+
+ return ffestb_V01811_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_V01811_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_V0187_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_V01812_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_rewrite_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V01812_ -- "REWRITE" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_V01812_; // to lexer
+
+ Handle EOS or SEMICOLON here. */
+
+static ffelexHandler
+ffestb_V01812_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_V018_start ();
+ ffestc_V018_finish ();
+ }
+ ffestb_subr_kill_rewrite_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeOPEN_PAREN:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V018_start ();
+ ffestb_subr_kill_rewrite_ ();
+
+ /* EXTENSION: Allow an optional preceding COMMA here if not pedantic.
+ (f2c provides this extension, as do other compilers, supposedly.) */
+
+ if (!ffe_is_pedantic () && (ffelex_token_type (t) == FFELEX_typeCOMMA))
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST, (ffeexprCallback) ffestb_V01813_);
+
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST, (ffeexprCallback) ffestb_V01813_)))
+ (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_rewrite_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V01813_ -- "REWRITE(...)" expr
+
+ (ffestb_V01813_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_V01813_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_V018_item (expr, ft);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST, (ffeexprCallback) ffestb_V01813_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_V018_item (expr, ft);
+ ffestc_V018_finish ();
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V018_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "REWRITE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V019 -- Parse the ACCEPT statement
+
+ return ffestb_V019; // to lexer
+
+ Make sure the statement has a valid form for the ACCEPT
+ statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_V019 (ffelexToken t)
+{
+ ffelexHandler next;
+ ffestpAcceptIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstACCEPT)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed ();
+ break;
+
+ default:
+ break;
+ }
+
+ for (ix = 0; ix < FFESTP_acceptix; ++ix)
+ ffestp_file.accept.accept_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_V0191_)))
+ (t);
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstACCEPT)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlACCEPT)
+ break;
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+ for (ix = 0; ix < FFESTP_acceptix; ++ix)
+ ffestp_file.accept.accept_spec[ix].kw_or_val_present = FALSE;
+ next = (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_V0191_);
+ next = (ffelexHandler) ffelex_splice_tokens (next, ffesta_tokens[0],
+ FFESTR_firstlACCEPT);
+ if (next == NULL)
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ACCEPT", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ACCEPT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_V0191_ -- "ACCEPT" expr
+
+ (ffestb_V0191_) // to expression handler
+
+ Make sure the next token is a COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_V0191_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ ffestp_file.accept.accept_spec[FFESTP_acceptixFORMAT].kw_or_val_present
+ = TRUE;
+ ffestp_file.accept.accept_spec[FFESTP_acceptixFORMAT].kw_present = FALSE;
+ ffestp_file.accept.accept_spec[FFESTP_acceptixFORMAT].value_present = TRUE;
+ ffestp_file.accept.accept_spec[FFESTP_acceptixFORMAT].value_is_label
+ = (expr == NULL);
+ ffestp_file.accept.accept_spec[FFESTP_acceptixFORMAT].value
+ = ffelex_token_use (ft);
+ ffestp_file.accept.accept_spec[FFESTP_acceptixFORMAT].u.expr = expr;
+ if (!ffesta_is_inhibited ())
+ ffestc_V019_start ();
+ ffestb_subr_kill_accept_ ();
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST,
+ (ffeexprCallback) ffestb_V0192_);
+ if (!ffesta_is_inhibited ())
+ ffestc_V019_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_accept_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ACCEPT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0192_ -- "ACCEPT" expr COMMA expr
+
+ (ffestb_V0192_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_V0192_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_V019_item (expr, ft);
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST,
+ (ffeexprCallback) ffestb_V0192_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_V019_item (expr, ft);
+ ffestc_V019_finish ();
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V019_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "ACCEPT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_V020 -- Parse the TYPE statement
+
+ return ffestb_V020; // to lexer
+
+ Make sure the statement has a valid form for the TYPE
+ statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_V020 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexHandler next;
+ ffestpTypeIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstTYPE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ case FFELEX_typeCOMMA: /* Because "TYPE,PUBLIC::A" is ambiguous with
+ '90. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNUMBER:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeNAME: /* Because TYPE A is ambiguous with '90. */
+ default:
+ break;
+ }
+
+ for (ix = 0; ix < FFESTP_typeix; ++ix)
+ ffestp_file.type.type_spec[ix].kw_or_val_present = FALSE;
+ return (ffelexHandler) (*((ffelexHandler)
+ ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_V0201_)))
+ (t);
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstTYPE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlTYPE)
+ break;
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ if (ffelex_token_length (ffesta_tokens[0]) == FFESTR_firstlTYPE)
+ break; /* Else might be assignment/stmtfuncdef. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typeCOLON:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlTYPE);
+ if (ISDIGIT (*p))
+ ffesta_confirmed (); /* Else might be '90 TYPE statement. */
+ for (ix = 0; ix < FFESTP_typeix; ++ix)
+ ffestp_file.type.type_spec[ix].kw_or_val_present = FALSE;
+ next = (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILEFORMATNML, (ffeexprCallback) ffestb_V0201_);
+ next = (ffelexHandler) ffelex_splice_tokens (next, ffesta_tokens[0],
+ FFESTR_firstlTYPE);
+ if (next == NULL)
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "TYPE I/O", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "TYPE I/O", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_V0201_ -- "TYPE" expr
+
+ (ffestb_V0201_) // to expression handler
+
+ Make sure the next token is a COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_V0201_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ bool comma = TRUE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffe_is_vxt () && (expr != NULL)
+ && (ffebld_op (expr) == FFEBLD_opSYMTER))
+ break;
+ comma = FALSE;
+ /* Fall through. */
+ case FFELEX_typeCOMMA:
+ if (!ffe_is_vxt () && comma && (expr != NULL)
+ && (ffebld_op (expr) == FFEBLD_opPAREN)
+ && (ffebld_op (ffebld_left (expr)) == FFEBLD_opSYMTER))
+ break;
+ ffesta_confirmed ();
+ ffestp_file.type.type_spec[FFESTP_typeixFORMAT].kw_or_val_present
+ = TRUE;
+ ffestp_file.type.type_spec[FFESTP_typeixFORMAT].kw_present = FALSE;
+ ffestp_file.type.type_spec[FFESTP_typeixFORMAT].value_present = TRUE;
+ ffestp_file.type.type_spec[FFESTP_typeixFORMAT].value_is_label
+ = (expr == NULL);
+ ffestp_file.type.type_spec[FFESTP_typeixFORMAT].value
+ = ffelex_token_use (ft);
+ ffestp_file.type.type_spec[FFESTP_typeixFORMAT].u.expr = expr;
+ if (!ffesta_is_inhibited ())
+ ffestc_V020_start ();
+ ffestb_subr_kill_type_ ();
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST, (ffeexprCallback) ffestb_V0202_);
+ if (!ffesta_is_inhibited ())
+ ffestc_V020_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_type_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "TYPE I/O", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0202_ -- "TYPE" expr COMMA expr
+
+ (ffestb_V0202_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_V0202_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_V020_item (expr, ft);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextIOLIST, (ffeexprCallback) ffestb_V0202_);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_V020_item (expr, ft);
+ ffestc_V020_finish ();
+ }
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V020_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "TYPE I/O", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V021 -- Parse a DELETE statement
+
+ return ffestb_V021; // to lexer
+
+ Make sure the statement has a valid form for a DELETE statement.
+ If it does, implement the statement. */
+
+#if FFESTR_VXT
+ffelexHandler
+ffestb_V021 (ffelexToken t)
+{
+ ffestpDeleteIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstDELETE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstDELETE)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlDELETE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ for (ix = 0; ix < FFESTP_deleteix; ++ix)
+ ffestp_file.delete.delete_spec[ix].kw_or_val_present = FALSE;
+
+ return (ffelexHandler) ffestb_V0211_;
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DELETE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DELETE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_V0211_ -- "DELETE" OPEN_PAREN
+
+ return ffestb_V0211_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_V0211_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0212_;
+
+ default:
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_V0213_)))
+ (t);
+ }
+}
+
+/* ffestb_V0212_ -- "DELETE" OPEN_PAREN NAME
+
+ return ffestb_V0212_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_V0212_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) ffestb_V0214_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_V0213_)))
+ (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_V0213_ -- "DELETE" OPEN_PAREN expr
+
+ (ffestb_V0213_) // to expression handler
+
+ Handle COMMA or DELETE_PAREN here. */
+
+static ffelexHandler
+ffestb_V0213_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.delete.delete_spec[FFESTP_deleteixUNIT].kw_or_val_present
+ = TRUE;
+ ffestp_file.delete.delete_spec[FFESTP_deleteixUNIT].kw_present = FALSE;
+ ffestp_file.delete.delete_spec[FFESTP_deleteixUNIT].value_present = TRUE;
+ ffestp_file.delete.delete_spec[FFESTP_deleteixUNIT].value_is_label
+ = FALSE;
+ ffestp_file.delete.delete_spec[FFESTP_deleteixUNIT].value
+ = ffelex_token_use (ft);
+ ffestp_file.delete.delete_spec[FFESTP_deleteixUNIT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_V0214_;
+ return (ffelexHandler) ffestb_V0219_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_delete_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DELETE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0214_ -- "DELETE" OPEN_PAREN [external-file-unit COMMA]
+
+ return ffestb_V0214_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_V0214_ (ffelexToken t)
+{
+ ffestrGenio kw;
+
+ ffestb_local_.delete.label = FALSE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ kw = ffestr_genio (t);
+ switch (kw)
+ {
+ case FFESTR_genioERR:
+ ffestb_local_.delete.ix = FFESTP_deleteixERR;
+ ffestb_local_.delete.label = TRUE;
+ break;
+
+ case FFESTR_genioIOSTAT:
+ ffestb_local_.delete.ix = FFESTP_deleteixIOSTAT;
+ ffestb_local_.delete.left = TRUE;
+ ffestb_local_.delete.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_genioREC:
+ ffestb_local_.delete.ix = FFESTP_deleteixREC;
+ ffestb_local_.delete.left = FALSE;
+ ffestb_local_.delete.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_genioUNIT:
+ ffestb_local_.delete.ix = FFESTP_deleteixUNIT;
+ ffestb_local_.delete.left = FALSE;
+ ffestb_local_.delete.context = FFEEXPR_contextFILENUM;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.delete.delete_spec[ffestb_local_.delete.ix]
+ .kw_or_val_present)
+ break; /* Can't specify a keyword twice! */
+ ffestp_file.delete.delete_spec[ffestb_local_.delete.ix]
+ .kw_or_val_present = TRUE;
+ ffestp_file.delete.delete_spec[ffestb_local_.delete.ix]
+ .kw_present = TRUE;
+ ffestp_file.delete.delete_spec[ffestb_local_.delete.ix]
+ .value_present = FALSE;
+ ffestp_file.delete.delete_spec[ffestb_local_.delete.ix].value_is_label
+ = ffestb_local_.delete.label;
+ ffestp_file.delete.delete_spec[ffestb_local_.delete.ix].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0215_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_delete_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DELETE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0215_ -- "DELETE" OPEN_PAREN [external-file-unit COMMA] NAME
+
+ return ffestb_V0215_; // to lexer
+
+ Make sure EQUALS here, send next token to expression handler. */
+
+static ffelexHandler
+ffestb_V0215_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestb_local_.delete.label)
+ return (ffelexHandler) ffestb_V0217_;
+ if (ffestb_local_.delete.left)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_local_.delete.context,
+ (ffeexprCallback) ffestb_V0216_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.delete.context, (ffeexprCallback) ffestb_V0216_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_delete_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DELETE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0216_ -- "DELETE" OPEN_PAREN ... NAME EQUALS expr
+
+ (ffestb_V0216_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_V0216_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.delete.delete_spec[ffestb_local_.delete.ix].value_present
+ = TRUE;
+ ffestp_file.delete.delete_spec[ffestb_local_.delete.ix].value
+ = ffelex_token_use (ft);
+ ffestp_file.delete.delete_spec[ffestb_local_.delete.ix].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_V0214_;
+ return (ffelexHandler) ffestb_V0219_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_delete_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DELETE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0217_ -- "DELETE" OPEN_PAREN ... NAME EQUALS
+
+ return ffestb_V0217_; // to lexer
+
+ Handle NUMBER for label here. */
+
+static ffelexHandler
+ffestb_V0217_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestp_file.delete.delete_spec[ffestb_local_.delete.ix].value_present
+ = TRUE;
+ ffestp_file.delete.delete_spec[ffestb_local_.delete.ix].value
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0218_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_delete_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DELETE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0218_ -- "DELETE" OPEN_PAREN ... NAME EQUALS NUMBER
+
+ return ffestb_V0218_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_V0218_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_V0214_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_V0219_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_delete_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DELETE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0219_ -- "DELETE" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_V0219_; // to lexer
+
+ Handle EOS or SEMICOLON here. */
+
+static ffelexHandler
+ffestb_V0219_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V021 ();
+ ffestb_subr_kill_delete_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_delete_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "DELETE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V026 -- Parse a FIND statement
+
+ return ffestb_V026; // to lexer
+
+ Make sure the statement has a valid form for a FIND statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_V026 (ffelexToken t)
+{
+ ffestpFindIx ix;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstFIND)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstFIND)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlFIND)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ for (ix = 0; ix < FFESTP_findix; ++ix)
+ ffestp_file.find.find_spec[ix].kw_or_val_present = FALSE;
+
+ return (ffelexHandler) ffestb_V0261_;
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FIND", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FIND", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_V0261_ -- "FIND" OPEN_PAREN
+
+ return ffestb_V0261_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_V0261_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0262_;
+
+ default:
+ return (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_V0263_)))
+ (t);
+ }
+}
+
+/* ffestb_V0262_ -- "FIND" OPEN_PAREN NAME
+
+ return ffestb_V0262_; // to lexer
+
+ If EQUALS here, go to states that handle it. Else, send NAME and this
+ token thru expression handler. */
+
+static ffelexHandler
+ffestb_V0262_ (ffelexToken t)
+{
+ ffelexHandler next;
+ ffelexToken nt;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ nt = ffesta_tokens[1];
+ next = (ffelexHandler) ffestb_V0264_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ next = (ffelexHandler) (*((ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextFILENUM, (ffeexprCallback) ffestb_V0263_)))
+ (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) (*next) (t);
+ }
+}
+
+/* ffestb_V0263_ -- "FIND" OPEN_PAREN expr
+
+ (ffestb_V0263_) // to expression handler
+
+ Handle COMMA or FIND_PAREN here. */
+
+static ffelexHandler
+ffestb_V0263_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.find.find_spec[FFESTP_findixUNIT].kw_or_val_present
+ = TRUE;
+ ffestp_file.find.find_spec[FFESTP_findixUNIT].kw_present = FALSE;
+ ffestp_file.find.find_spec[FFESTP_findixUNIT].value_present = TRUE;
+ ffestp_file.find.find_spec[FFESTP_findixUNIT].value_is_label
+ = FALSE;
+ ffestp_file.find.find_spec[FFESTP_findixUNIT].value
+ = ffelex_token_use (ft);
+ ffestp_file.find.find_spec[FFESTP_findixUNIT].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_V0264_;
+ return (ffelexHandler) ffestb_V0269_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_find_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FIND", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0264_ -- "FIND" OPEN_PAREN [external-file-unit COMMA]
+
+ return ffestb_V0264_; // to lexer
+
+ Handle expr construct (not NAME=expr construct) here. */
+
+static ffelexHandler
+ffestb_V0264_ (ffelexToken t)
+{
+ ffestrGenio kw;
+
+ ffestb_local_.find.label = FALSE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ kw = ffestr_genio (t);
+ switch (kw)
+ {
+ case FFESTR_genioERR:
+ ffestb_local_.find.ix = FFESTP_findixERR;
+ ffestb_local_.find.label = TRUE;
+ break;
+
+ case FFESTR_genioIOSTAT:
+ ffestb_local_.find.ix = FFESTP_findixIOSTAT;
+ ffestb_local_.find.left = TRUE;
+ ffestb_local_.find.context = FFEEXPR_contextFILEINT;
+ break;
+
+ case FFESTR_genioREC:
+ ffestb_local_.find.ix = FFESTP_findixREC;
+ ffestb_local_.find.left = FALSE;
+ ffestb_local_.find.context = FFEEXPR_contextFILENUM;
+ break;
+
+ case FFESTR_genioUNIT:
+ ffestb_local_.find.ix = FFESTP_findixUNIT;
+ ffestb_local_.find.left = FALSE;
+ ffestb_local_.find.context = FFEEXPR_contextFILENUM;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.find.find_spec[ffestb_local_.find.ix]
+ .kw_or_val_present)
+ break; /* Can't specify a keyword twice! */
+ ffestp_file.find.find_spec[ffestb_local_.find.ix]
+ .kw_or_val_present = TRUE;
+ ffestp_file.find.find_spec[ffestb_local_.find.ix]
+ .kw_present = TRUE;
+ ffestp_file.find.find_spec[ffestb_local_.find.ix]
+ .value_present = FALSE;
+ ffestp_file.find.find_spec[ffestb_local_.find.ix].value_is_label
+ = ffestb_local_.find.label;
+ ffestp_file.find.find_spec[ffestb_local_.find.ix].kw
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0265_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestb_subr_kill_find_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FIND", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0265_ -- "FIND" OPEN_PAREN [external-file-unit COMMA] NAME
+
+ return ffestb_V0265_; // to lexer
+
+ Make sure EQUALS here, send next token to expression handler. */
+
+static ffelexHandler
+ffestb_V0265_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (ffestb_local_.find.label)
+ return (ffelexHandler) ffestb_V0267_;
+ if (ffestb_local_.find.left)
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ ffestb_local_.find.context,
+ (ffeexprCallback) ffestb_V0266_);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.find.context,
+ (ffeexprCallback) ffestb_V0266_);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_find_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FIND", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0266_ -- "FIND" OPEN_PAREN ... NAME EQUALS expr
+
+ (ffestb_V0266_) // to expression handler
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_V0266_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestp_file.find.find_spec[ffestb_local_.find.ix].value_present
+ = TRUE;
+ ffestp_file.find.find_spec[ffestb_local_.find.ix].value
+ = ffelex_token_use (ft);
+ ffestp_file.find.find_spec[ffestb_local_.find.ix].u.expr = expr;
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_V0264_;
+ return (ffelexHandler) ffestb_V0269_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_find_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FIND", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0267_ -- "FIND" OPEN_PAREN ... NAME EQUALS
+
+ return ffestb_V0267_; // to lexer
+
+ Handle NUMBER for label here. */
+
+static ffelexHandler
+ffestb_V0267_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestp_file.find.find_spec[ffestb_local_.find.ix].value_present
+ = TRUE;
+ ffestp_file.find.find_spec[ffestb_local_.find.ix].value
+ = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0268_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_find_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FIND", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0268_ -- "FIND" OPEN_PAREN ... NAME EQUALS NUMBER
+
+ return ffestb_V0268_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN here. */
+
+static ffelexHandler
+ffestb_V0268_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_V0264_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_V0269_;
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_find_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FIND", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0269_ -- "FIND" OPEN_PAREN ... CLOSE_PAREN
+
+ return ffestb_V0269_; // to lexer
+
+ Handle EOS or SEMICOLON here. */
+
+static ffelexHandler
+ffestb_V0269_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V026 ();
+ ffestb_subr_kill_find_ ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestb_subr_kill_find_ ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FIND", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_dimlist -- Parse the ALLOCATABLE/POINTER/TARGET statement
+
+ return ffestb_dimlist; // to lexer
+
+ Make sure the statement has a valid form for the ALLOCATABLE/POINTER/
+ TARGET statement. If it does, implement the statement. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_dimlist (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffelexHandler next;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_start ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_start ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_start ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffestb_local_.dimlist.started = TRUE;
+ return (ffelexHandler) ffestb_dimlist1_;
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_start ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_start ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_start ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffestb_local_.dimlist.started = TRUE;
+ return (ffelexHandler) ffestb_dimlist1_ (t);
+ }
+
+ case FFELEX_typeNAMES:
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = ffestb_args.dimlist.len);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_start ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_start ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_start ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffestb_local_.dimlist.started = TRUE;
+ next = (ffelexHandler) ffestb_dimlist1_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_start ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_start ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_start ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffestb_local_.dimlist.started = TRUE;
+ return (ffelexHandler) ffestb_dimlist1_;
+
+ case FFELEX_typeOPEN_PAREN:
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ ffestb_local_.dimlist.started = FALSE;
+ next = (ffelexHandler) ffestb_dimlist1_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.dimlist.badname, ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.dimlist.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, ffestb_args.dimlist.badname, ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_dimlist1_ -- "ALLOCATABLE/POINTER/TARGET" [COLONCOLON]
+
+ return ffestb_dimlist1_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_dimlist1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_dimlist2_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.dimlist.badname, t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_finish ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_finish ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_finish ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_dimlist2_ -- "ALLOCATABLE/POINTER/TARGET" ... NAME
+
+ return ffestb_dimlist2_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_dimlist2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_subrargs_.dim_list.dims = ffestt_dimlist_create ();
+ ffestb_subrargs_.dim_list.handler = (ffelexHandler) ffestb_dimlist3_;
+ ffestb_subrargs_.dim_list.pool = ffesta_output_pool;
+ ffestb_subrargs_.dim_list.ctx = FFEEXPR_contextDIMLIST;
+#ifdef FFECOM_dimensionsMAX
+ ffestb_subrargs_.dim_list.ndims = 0;
+#endif
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextDIMLIST, (ffeexprCallback) ffestb_subr_dimlist_);
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.dimlist.started)
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_start ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_start ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_start ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ ffestb_local_.dimlist.started = TRUE;
+ }
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_item (ffesta_tokens[1], NULL);
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_item (ffesta_tokens[1], NULL);
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_item (ffesta_tokens[1], NULL);
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_dimlist4_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.dimlist.started)
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_start ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_start ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_start ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_item (ffesta_tokens[1], NULL);
+ ffestc_R525_finish ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_item (ffesta_tokens[1], NULL);
+ ffestc_R526_finish ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_item (ffesta_tokens[1], NULL);
+ ffestc_R527_finish ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.dimlist.badname, t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_finish ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_finish ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_finish ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_dimlist3_ -- "ALLOCATABLE/POINTER/TARGET" ... NAME OPEN_PAREN
+ dimlist CLOSE_PAREN
+
+ return ffestb_dimlist3_; // to lexer
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_dimlist3_ (ffelexToken t)
+{
+ if (!ffestb_subrargs_.dim_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.dimlist.started)
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_start ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_start ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_start ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ ffestb_local_.dimlist.started = TRUE;
+ }
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_item (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_item (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_item (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffestb_dimlist4_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.dimlist.started)
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_start ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_start ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_start ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_item (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ ffestc_R525_finish ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_item (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ ffestc_R526_finish ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_item (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ ffestc_R527_finish ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.dimlist.badname, t);
+ if (ffestb_local_.dimlist.started && !ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_finish ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_finish ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_finish ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_dimlist4_ -- "ALLOCATABLE/POINTER/TARGET" ... COMMA
+
+ return ffestb_dimlist4_; // to lexer
+
+ Make sure we don't have EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_dimlist4_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffesta_first_kw)
+ {
+ case FFESTR_firstALLOCATABLE:
+ ffestc_R525_finish ();
+ break;
+
+ case FFESTR_firstPOINTER:
+ ffestc_R526_finish ();
+ break;
+
+ case FFESTR_firstTARGET:
+ ffestc_R527_finish ();
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.dimlist.badname, t);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ return (ffelexHandler) ffestb_dimlist1_ (t);
+ }
+}
+
+#endif
+/* ffestb_dummy -- Parse an ENTRY/FUNCTION/SUBROUTINE statement
+
+ return ffestb_dummy; // to lexer
+
+ Make sure the statement has a valid form for an ENTRY/FUNCTION/SUBROUTINE
+ statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_dummy (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ break;
+ }
+
+ ffesta_confirmed ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ ffestb_local_.decl.recursive = NULL;
+ ffestb_local_.dummy.badname = ffestb_args.dummy.badname;
+ ffestb_local_.dummy.is_subr = ffestb_args.dummy.is_subr;
+ ffestb_local_.dummy.first_kw = ffesta_first_kw;
+ return (ffelexHandler) ffestb_dummy1_;
+
+ case FFELEX_typeNAMES:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeOPEN_PAREN:
+ break;
+ }
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = ffestb_args.dummy.len);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1]
+ = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ ffestb_local_.decl.recursive = NULL;
+ ffestb_local_.dummy.badname = ffestb_args.dummy.badname;
+ ffestb_local_.dummy.is_subr = ffestb_args.dummy.is_subr;
+ ffestb_local_.dummy.first_kw = ffesta_first_kw;
+ return (ffelexHandler) ffestb_dummy1_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.dummy.badname, ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.dummy.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, ffestb_args.dummy.badname, ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_dummy1_ -- "ENTRY/FUNCTION/SUBROUTINE" NAME
+
+ return ffestb_dummy1_; // to lexer
+
+ Make sure the next token is an EOS, SEMICOLON, or OPEN_PAREN. In the
+ former case, just implement a null arg list, else get the arg list and
+ then implement. */
+
+static ffelexHandler
+ffestb_dummy1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (ffestb_local_.dummy.first_kw == FFESTR_firstFUNCTION)
+ {
+ ffesta_confirmed (); /* Later, not if typename w/o RECURSIVE. */
+ break; /* Produce an error message, need that open
+ paren. */
+ }
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ { /* Pretend as though we got a truly NULL
+ list. */
+ ffestb_subrargs_.name_list.args = NULL;
+ ffestb_subrargs_.name_list.ok = TRUE;
+ ffestb_subrargs_.name_list.close_paren = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_dummy2_ (t);
+ }
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_subrargs_.name_list.args = ffestt_tokenlist_create ();
+ ffestb_subrargs_.name_list.handler = (ffelexHandler) ffestb_dummy2_;
+ ffestb_subrargs_.name_list.is_subr = ffestb_local_.dummy.is_subr;
+ ffestb_subrargs_.name_list.names = FALSE;
+ return (ffelexHandler) ffestb_subr_name_list_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_local_.dummy.badname, t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_dummy2_ -- <dummy-keyword> NAME OPEN_PAREN arg-list CLOSE_PAREN
+
+ return ffestb_dummy2_; // to lexer
+
+ Make sure the statement has a valid form for a dummy-def statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_dummy2_ (ffelexToken t)
+{
+ if (!ffestb_subrargs_.name_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ switch (ffestb_local_.dummy.first_kw)
+ {
+ case FFESTR_firstFUNCTION:
+ ffestc_R1219 (ffesta_tokens[1], ffestb_subrargs_.name_list.args,
+ ffestb_subrargs_.name_list.close_paren, FFESTP_typeNone,
+ NULL, NULL, NULL, NULL, ffestb_local_.decl.recursive, NULL);
+ break;
+
+ case FFESTR_firstSUBROUTINE:
+ ffestc_R1223 (ffesta_tokens[1], ffestb_subrargs_.name_list.args,
+ ffestb_subrargs_.name_list.close_paren,
+ ffestb_local_.decl.recursive);
+ break;
+
+ case FFESTR_firstENTRY:
+ ffestc_R1226 (ffesta_tokens[1], ffestb_subrargs_.name_list.args,
+ ffestb_subrargs_.name_list.close_paren);
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ if (ffestb_subrargs_.name_list.args != NULL)
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ if ((ffestb_local_.dummy.first_kw != FFESTR_firstFUNCTION)
+ || (ffestr_other (t) != FFESTR_otherRESULT))
+ break;
+ ffestb_local_.decl.type = FFESTP_typeNone;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_funcname_6_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_local_.dummy.badname, t);
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ if (ffestb_subrargs_.name_list.args != NULL)
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R524 -- Parse the DIMENSION statement
+
+ return ffestb_R524; // to lexer
+
+ Make sure the statement has a valid form for the DIMENSION statement. If
+ it does, implement the statement. */
+
+ffelexHandler
+ffestb_R524 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffelexHandler next;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R524_start (ffesta_first_kw == FFESTR_firstVIRTUAL);
+ ffestb_local_.dimension.started = TRUE;
+ return (ffelexHandler) ffestb_R5241_ (t);
+ }
+
+ case FFELEX_typeNAMES:
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = ffestb_args.R524.len);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ break;
+ }
+
+ /* Here, we have at least one char after "DIMENSION" and t is
+ OPEN_PAREN. */
+
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ ffestb_local_.dimension.started = FALSE;
+ next = (ffelexHandler) ffestb_R5241_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.R524.badname, ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.R524.badname, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, ffestb_args.R524.badname, ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5241_ -- "DIMENSION"
+
+ return ffestb_R5241_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_R5241_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R5242_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.R524.badname, t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R524_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5242_ -- "DIMENSION" ... NAME
+
+ return ffestb_R5242_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_R5242_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_subrargs_.dim_list.dims = ffestt_dimlist_create ();
+ ffestb_subrargs_.dim_list.handler = (ffelexHandler) ffestb_R5243_;
+ ffestb_subrargs_.dim_list.pool = ffesta_output_pool;
+ ffestb_subrargs_.dim_list.ctx = ffesta_is_entry_valid
+ ? FFEEXPR_contextDIMLIST : FFEEXPR_contextDIMLISTCOMMON;
+#ifdef FFECOM_dimensionsMAX
+ ffestb_subrargs_.dim_list.ndims = 0;
+#endif
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_subrargs_.dim_list.ctx,
+ (ffeexprCallback) ffestb_subr_dimlist_);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.R524.badname, t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R524_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5243_ -- "DIMENSION" ... NAME OPEN_PAREN dimlist CLOSE_PAREN
+
+ return ffestb_R5243_; // to lexer
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_R5243_ (ffelexToken t)
+{
+ if (!ffestb_subrargs_.dim_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.dimension.started)
+ {
+ ffestc_R524_start (ffesta_first_kw == FFESTR_firstVIRTUAL);
+ ffestb_local_.dimension.started = TRUE;
+ }
+ ffestc_R524_item (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffestb_R5244_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.dimension.started)
+ {
+ ffestc_R524_start (ffesta_first_kw == FFESTR_firstVIRTUAL);
+ ffestb_local_.dimension.started = TRUE;
+ }
+ ffestc_R524_item (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ ffestc_R524_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.R524.badname, t);
+ if (ffestb_local_.dimension.started && !ffesta_is_inhibited ())
+ ffestc_R524_finish ();
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5244_ -- "DIMENSION" ... COMMA
+
+ return ffestb_R5244_; // to lexer
+
+ Make sure we don't have EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_R5244_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R524_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, ffestb_args.R524.badname, t);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ return (ffelexHandler) ffestb_R5241_ (t);
+ }
+}
+
+/* ffestb_R547 -- Parse the COMMON statement
+
+ return ffestb_R547; // to lexer
+
+ Make sure the statement has a valid form for the COMMON statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_R547 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffelexHandler next;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstCOMMON)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ case FFELEX_typeSLASH:
+ case FFELEX_typeCONCAT:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_start ();
+ ffestb_local_.common.started = TRUE;
+ return (ffelexHandler) ffestb_R5471_ (t);
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstCOMMON)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlCOMMON);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeSLASH:
+ case FFELEX_typeCONCAT:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_start ();
+ ffestb_local_.common.started = TRUE;
+ return (ffelexHandler) ffestb_R5471_ (t);
+
+ case FFELEX_typeOPEN_PAREN:
+ break;
+ }
+
+ /* Here, we have at least one char after "COMMON" and t is COMMA,
+ EOS/SEMICOLON, OPEN_PAREN, SLASH, or CONCAT. */
+
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ if (ffelex_token_type (t) == FFELEX_typeOPEN_PAREN)
+ ffestb_local_.common.started = FALSE;
+ else
+ {
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_start ();
+ ffestb_local_.common.started = TRUE;
+ }
+ next = (ffelexHandler) ffestb_R5471_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "COMMON", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "COMMON", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "COMMON", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5471_ -- "COMMON"
+
+ return ffestb_R5471_; // to lexer
+
+ Handle NAME, SLASH, or CONCAT. */
+
+static ffelexHandler
+ffestb_R5471_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ return (ffelexHandler) ffestb_R5474_ (t);
+
+ case FFELEX_typeSLASH:
+ return (ffelexHandler) ffestb_R5472_;
+
+ case FFELEX_typeCONCAT:
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_item_cblock (NULL);
+ return (ffelexHandler) ffestb_R5474_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "COMMON", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5472_ -- "COMMON" SLASH
+
+ return ffestb_R5472_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_R5472_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R5473_;
+
+ case FFELEX_typeSLASH:
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_item_cblock (NULL);
+ return (ffelexHandler) ffestb_R5474_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "COMMON", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5473_ -- "COMMON" SLASH NAME
+
+ return ffestb_R5473_; // to lexer
+
+ Handle SLASH. */
+
+static ffelexHandler
+ffestb_R5473_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeSLASH:
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_item_cblock (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_R5474_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "COMMON", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5474_ -- "COMMON" [SLASH NAME SLASH] or "COMMON" CONCAT
+
+ return ffestb_R5474_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_R5474_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_R5475_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "COMMON", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5475_ -- "COMMON" ... NAME
+
+ return ffestb_R5475_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_R5475_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_subrargs_.dim_list.dims = ffestt_dimlist_create ();
+ ffestb_subrargs_.dim_list.handler = (ffelexHandler) ffestb_R5476_;
+ ffestb_subrargs_.dim_list.pool = ffesta_output_pool;
+ ffestb_subrargs_.dim_list.ctx = FFEEXPR_contextDIMLISTCOMMON;
+#ifdef FFECOM_dimensionsMAX
+ ffestb_subrargs_.dim_list.ndims = 0;
+#endif
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextDIMLISTCOMMON, (ffeexprCallback) ffestb_subr_dimlist_);
+
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_item_object (ffesta_tokens[1], NULL);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_R5477_;
+
+ case FFELEX_typeSLASH:
+ case FFELEX_typeCONCAT:
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_item_object (ffesta_tokens[1], NULL);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_R5471_ (t);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_R547_item_object (ffesta_tokens[1], NULL);
+ ffestc_R547_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "COMMON", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5476_ -- "COMMON" ... NAME OPEN_PAREN dimlist CLOSE_PAREN
+
+ return ffestb_R5476_; // to lexer
+
+ Handle COMMA, SLASH, CONCAT, EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_R5476_ (ffelexToken t)
+{
+ if (!ffestb_subrargs_.dim_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.common.started)
+ {
+ ffestc_R547_start ();
+ ffestb_local_.common.started = TRUE;
+ }
+ ffestc_R547_item_object (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffestb_R5477_;
+
+ case FFELEX_typeSLASH:
+ case FFELEX_typeCONCAT:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.common.started)
+ {
+ ffestc_R547_start ();
+ ffestb_local_.common.started = TRUE;
+ }
+ ffestc_R547_item_object (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffestb_R5471_ (t);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.common.started)
+ ffestc_R547_start ();
+ ffestc_R547_item_object (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ ffestc_R547_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "COMMON", t);
+ if (ffestb_local_.common.started && !ffesta_is_inhibited ())
+ ffestc_R547_finish ();
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R5477_ -- "COMMON" ... COMMA
+
+ return ffestb_R5477_; // to lexer
+
+ Make sure we don't have EOS or SEMICOLON. */
+
+static ffelexHandler
+ffestb_R5477_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R547_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "COMMON", t);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ return (ffelexHandler) ffestb_R5471_ (t);
+ }
+}
+
+/* ffestb_R624 -- Parse a NULLIFY statement
+
+ return ffestb_R624; // to lexer
+
+ Make sure the statement has a valid form for a NULLIFY
+ statement. If it does, implement the statement.
+
+ 31-May-90 JCB 2.0
+ Rewrite to produce a list of expressions rather than just names; this
+ eases semantic checking, putting it in expression handling where that
+ kind of thing gets done anyway, and makes it easier to support more
+ flexible extensions to Fortran 90 like NULLIFY(FOO%BAR). */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_R624 (ffelexToken t)
+{
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstNULLIFY)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstNULLIFY)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlNULLIFY)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeNAME:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ ffestb_local_.R624.exprs = ffestt_exprlist_create ();
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextNULLIFY,
+ (ffeexprCallback) ffestb_R6241_);
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NULLIFY", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NULLIFY", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_R6241_ -- "NULLIFY" OPEN_PAREN expr
+
+ return ffestb_R6241_; // to lexer
+
+ Make sure the statement has a valid form for a NULLIFY statement. If it
+ does, implement the statement.
+
+ 31-May-90 JCB 2.0
+ Rewrite to produce a list of expressions rather than just names; this
+ eases semantic checking, putting it in expression handling where that
+ kind of thing gets done anyway, and makes it easier to support more
+ flexible extensions to Fortran 90 like NULLIFY(FOO%BAR). */
+
+static ffelexHandler
+ffestb_R6241_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestt_exprlist_append (ffestb_local_.R624.exprs, expr,
+ ffelex_token_use (t));
+ return (ffelexHandler) ffestb_R6242_;
+
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ ffestt_exprlist_append (ffestb_local_.R624.exprs, expr,
+ ffelex_token_use (t));
+ return (ffelexHandler) ffeexpr_lhs (ffesta_output_pool,
+ FFEEXPR_contextNULLIFY,
+ (ffeexprCallback) ffestb_R6241_);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NULLIFY", t);
+ ffestt_exprlist_kill (ffestb_local_.R624.exprs);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R6242_ -- "NULLIFY" OPEN_PAREN expr-list CLOSE_PAREN
+
+ return ffestb_R6242_; // to lexer
+
+ Make sure the statement has a valid form for a NULLIFY statement. If it
+ does, implement the statement. */
+
+static ffelexHandler
+ffestb_R6242_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R624 (ffestb_local_.R624.exprs);
+ ffestt_exprlist_kill (ffestb_local_.R624.exprs);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "NULLIFY", t);
+ ffestt_exprlist_kill (ffestb_local_.R624.exprs);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_R1229 -- Parse a STMTFUNCTION statement
+
+ return ffestb_R1229; // to lexer
+
+ Make sure the statement has a valid form for a STMTFUNCTION
+ statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_R1229 (ffelexToken t)
+{
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeNAME:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ ffestb_subrargs_.name_list.args = ffestt_tokenlist_create ();
+ ffestb_subrargs_.name_list.handler = (ffelexHandler) ffestb_R12291_;
+ ffestb_subrargs_.name_list.is_subr = FALSE; /* No "*" items in list! */
+ ffestb_subrargs_.name_list.names = TRUE; /* In case "IF(FOO)CALL
+ FOO...". */
+ return (ffelexHandler) ffestb_subr_name_list_;
+
+bad_0: /* :::::::::::::::::::: */
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_2t (FFEBAD_UNREC_STMT, ffesta_tokens[0], t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R12291_ -- "STMTFUNCTION" OPEN_PAREN dummy-name-list CLOSE_PAREN
+
+ return ffestb_R12291_; // to lexer
+
+ Make sure the statement has a valid form for a STMTFUNCTION statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_R12291_ (ffelexToken t)
+{
+ ffelex_set_names (FALSE);
+
+ if (!ffestb_subrargs_.name_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R1229_start (ffesta_tokens[0],
+ ffestb_subrargs_.name_list.args,
+ ffestb_subrargs_.name_list.close_paren);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextSFUNCDEF, (ffeexprCallback) ffestb_R12292_);
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_2t (FFEBAD_UNREC_STMT, ffesta_tokens[0], t);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_R12292_ -- "STMTFUNCTION" OPEN_PAREN dummy-name-list CLOSE_PAREN
+ EQUALS expr
+
+ (ffestb_R12292_) // to expression handler
+
+ Make sure the statement has a valid form for a STMTFUNCTION statement. If
+ it does, implement the statement. */
+
+static ffelexHandler
+ffestb_R12292_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ if (expr == NULL)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1229_finish (expr, ft);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffestc_R1229_finish (NULL, NULL);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "statement-function-definition", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_chartype -- Parse the CHARACTER statement
+
+ return ffestb_decl_chartype; // to lexer
+
+ Make sure the statement has a valid form for the CHARACTER statement. If
+ it does, implement the statement. */
+
+ffelexHandler
+ffestb_decl_chartype (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ ffestb_local_.decl.type = FFESTP_typeCHARACTER;
+ ffestb_local_.decl.recursive = NULL;
+ ffestb_local_.decl.parameter = FALSE; /* No PARAMETER attribute seen. */
+ ffestb_local_.decl.coloncolon = FALSE; /* No COLONCOLON seen. */
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstCHRCTR)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_;
+
+ case FFELEX_typeCOLONCOLON:
+ ffestb_local_.decl.coloncolon = TRUE;
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeASTERISK:
+ ffesta_confirmed ();
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_chartype1_;
+ ffestb_local_.decl.badname = "TYPEDECL";
+ return (ffelexHandler) ffestb_decl_starlen_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_attrsp_;
+ ffestb_local_.decl.badname = "_TYPEDECL";
+ return (ffelexHandler) ffestb_decl_typeparams_;
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_entsp_ (t);
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstCHRCTR)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlCHRCTR);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_;
+
+ case FFELEX_typeCOLONCOLON:
+ ffestb_local_.decl.coloncolon = TRUE;
+ ffesta_confirmed ();
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeASTERISK:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ break;
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_chartype1_;
+ ffestb_local_.decl.badname = "TYPEDECL";
+ return (ffelexHandler) ffestb_decl_starlen_;
+
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ break;
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ if (*p != '\0')
+ break;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_attrsp_;
+ ffestb_local_.decl.badname = "TYPEDECL";
+ return (ffelexHandler) ffestb_decl_typeparams_;
+ }
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ ffesta_tokens[1] = ffelex_token_names_from_names (ffesta_tokens[0], i, 0);
+ return (ffelexHandler) ffestb_decl_entsp_2_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "type-declaration", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_chartype1_ -- "CHARACTER" ASTERISK char-length
+
+ return ffestb_decl_chartype1_; // to lexer
+
+ Handle COMMA, COLONCOLON, or anything else. */
+
+static ffelexHandler
+ffestb_decl_chartype1_ (ffelexToken t)
+{
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOLONCOLON:
+ ffestb_local_.decl.coloncolon = TRUE;
+ /* Fall through. */
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, ffestb_local_.decl.len, ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ default:
+ return (ffelexHandler) ffestb_decl_entsp_ (t);
+ }
+}
+
+/* ffestb_decl_dbltype -- Parse the DOUBLEPRECISION/DOUBLECOMPLEX statement
+
+ return ffestb_decl_dbltype; // to lexer
+
+ Make sure the statement has a valid form for the DOUBLEPRECISION/
+ DOUBLECOMPLEX statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_decl_dbltype (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ ffestb_local_.decl.type = ffestb_args.decl.type;
+ ffestb_local_.decl.recursive = NULL;
+ ffestb_local_.decl.parameter = FALSE; /* No PARAMETER attribute seen. */
+ ffestb_local_.decl.coloncolon = FALSE; /* No COLONCOLON seen. */
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_;
+
+ case FFELEX_typeCOLONCOLON:
+ ffestb_local_.decl.coloncolon = TRUE;
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_entsp_ (t);
+ }
+
+ case FFELEX_typeNAMES:
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = ffestb_args.decl.len);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_;
+
+ case FFELEX_typeCOLONCOLON:
+ ffestb_local_.decl.coloncolon = TRUE;
+ ffesta_confirmed ();
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ break;
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeOPEN_PAREN:
+ if (*p != '\0')
+ break;
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ ffesta_tokens[1] = ffelex_token_names_from_names (ffesta_tokens[0], i, 0);
+ return (ffelexHandler) ffestb_decl_entsp_2_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "type-declaration", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_double -- Parse the DOUBLE PRECISION/DOUBLE COMPLEX statement
+
+ return ffestb_decl_double; // to lexer
+
+ Make sure the statement has a valid form for the DOUBLE PRECISION/
+ DOUBLE COMPLEX statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_decl_double (ffelexToken t)
+{
+ ffestb_local_.decl.recursive = NULL;
+ ffestb_local_.decl.parameter = FALSE; /* No PARAMETER attribute seen. */
+ ffestb_local_.decl.coloncolon = FALSE; /* No COLONCOLON seen. */
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstDBL)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ switch (ffestr_second (t))
+ {
+ case FFESTR_secondCOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeDBLCMPLX;
+ break;
+
+ case FFESTR_secondPRECISION:
+ ffestb_local_.decl.type = FFESTP_typeDBLPRCSN;
+ break;
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_attrsp_;
+ }
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_decl_gentype -- Parse the INTEGER/REAL/COMPLEX/LOGICAL statement
+
+ return ffestb_decl_gentype; // to lexer
+
+ Make sure the statement has a valid form for the INTEGER/REAL/COMPLEX/
+ LOGICAL statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_decl_gentype (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+
+ ffestb_local_.decl.type = ffestb_args.decl.type;
+ ffestb_local_.decl.recursive = NULL;
+ ffestb_local_.decl.parameter = FALSE; /* No PARAMETER attribute seen. */
+ ffestb_local_.decl.coloncolon = FALSE; /* No COLONCOLON seen. */
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_;
+
+ case FFELEX_typeCOLONCOLON:
+ ffestb_local_.decl.coloncolon = TRUE;
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeASTERISK:
+ ffesta_confirmed ();
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_attrsp_;
+ ffestb_local_.decl.badname = "TYPEDECL";
+ return (ffelexHandler) ffestb_decl_starkind_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_attrsp_;
+ ffestb_local_.decl.badname = "TYPEDECL";
+ return (ffelexHandler) ffestb_decl_kindparam_;
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_entsp_ (t);
+ }
+
+ case FFELEX_typeNAMES:
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = ffestb_args.decl.len);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_;
+
+ case FFELEX_typeCOLONCOLON:
+ ffestb_local_.decl.coloncolon = TRUE;
+ ffesta_confirmed ();
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ break;
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeASTERISK:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ break;
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_attrsp_;
+ ffestb_local_.decl.badname = "TYPEDECL";
+ return (ffelexHandler) ffestb_decl_starkind_;
+
+ case FFELEX_typeOPEN_PAREN:
+ if (*p != '\0')
+ break;
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_attrsp_;
+ ffestb_local_.decl.badname = "TYPEDECL";
+ return (ffelexHandler) ffestb_decl_kindparam_;
+ }
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ ffesta_tokens[1] = ffelex_token_names_from_names (ffesta_tokens[0], i, 0);
+ return (ffelexHandler) ffestb_decl_entsp_2_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "type-declaration", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_recursive -- Parse the RECURSIVE FUNCTION statement
+
+ return ffestb_decl_recursive; // to lexer
+
+ Make sure the statement has a valid form for the RECURSIVE FUNCTION
+ statement. If it does, implement the statement. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_decl_recursive (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffelexToken ot;
+ ffelexHandler next;
+ bool needfunc;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstRECURSIVE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ break;
+ }
+ ffesta_confirmed ();
+ ffestb_local_.decl.recursive = ffelex_token_use (ffesta_tokens[0]);
+ switch (ffesta_second_kw)
+ {
+ case FFESTR_secondINTEGER:
+ ffestb_local_.decl.type = FFESTP_typeINTEGER;
+ return (ffelexHandler) ffestb_decl_recursive1_;
+
+ case FFESTR_secondBYTE:
+ ffestb_local_.decl.type = FFESTP_typeBYTE;
+ return (ffelexHandler) ffestb_decl_recursive1_;
+
+ case FFESTR_secondWORD:
+ ffestb_local_.decl.type = FFESTP_typeWORD;
+ return (ffelexHandler) ffestb_decl_recursive1_;
+
+ case FFESTR_secondREAL:
+ ffestb_local_.decl.type = FFESTP_typeREAL;
+ return (ffelexHandler) ffestb_decl_recursive1_;
+
+ case FFESTR_secondCOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeCOMPLEX;
+ return (ffelexHandler) ffestb_decl_recursive1_;
+
+ case FFESTR_secondLOGICAL:
+ ffestb_local_.decl.type = FFESTP_typeLOGICAL;
+ return (ffelexHandler) ffestb_decl_recursive1_;
+
+ case FFESTR_secondCHARACTER:
+ ffestb_local_.decl.type = FFESTP_typeCHARACTER;
+ return (ffelexHandler) ffestb_decl_recursive1_;
+
+ case FFESTR_secondDOUBLE:
+ return (ffelexHandler) ffestb_decl_recursive2_;
+
+ case FFESTR_secondDOUBLEPRECISION:
+ ffestb_local_.decl.type = FFESTP_typeDBLPRCSN;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_func_;
+
+ case FFESTR_secondDOUBLECOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeDBLCMPLX;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_func_;
+
+ case FFESTR_secondTYPE:
+ ffestb_local_.decl.type = FFESTP_typeTYPE;
+ return (ffelexHandler) ffestb_decl_recursive3_;
+
+ case FFESTR_secondFUNCTION:
+ ffestb_local_.dummy.first_kw = FFESTR_firstFUNCTION;
+ ffestb_local_.dummy.badname = "FUNCTION";
+ ffestb_local_.dummy.is_subr = FALSE;
+ return (ffelexHandler) ffestb_decl_recursive4_;
+
+ case FFESTR_secondSUBROUTINE:
+ ffestb_local_.dummy.first_kw = FFESTR_firstSUBROUTINE;
+ ffestb_local_.dummy.badname = "SUBROUTINE";
+ ffestb_local_.dummy.is_subr = TRUE;
+ return (ffelexHandler) ffestb_decl_recursive4_;
+
+ default:
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstRECURSIVE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeASTERISK:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeEOS:
+ ffesta_confirmed ();
+ break;
+
+ default:
+ break;
+ }
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlRECURSIVE);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_0; /* :::::::::::::::::::: */
+ ffestb_local_.decl.recursive
+ = ffelex_token_name_from_names (ffesta_tokens[0], 0,
+ FFESTR_firstlRECURSIVE);
+ nt = ffelex_token_names_from_names (ffesta_tokens[0],
+ FFESTR_firstlRECURSIVE, 0);
+ switch (ffestr_first (nt))
+ {
+ case FFESTR_firstINTGR:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlINTGR);
+ ffestb_local_.decl.type = FFESTP_typeINTEGER;
+ needfunc = FALSE;
+ goto typefunc; /* :::::::::::::::::::: */
+
+ case FFESTR_firstBYTE:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlBYTE);
+ ffestb_local_.decl.type = FFESTP_typeBYTE;
+ needfunc = FALSE;
+ goto typefunc; /* :::::::::::::::::::: */
+
+ case FFESTR_firstWORD:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlWORD);
+ ffestb_local_.decl.type = FFESTP_typeWORD;
+ needfunc = FALSE;
+ goto typefunc; /* :::::::::::::::::::: */
+
+ case FFESTR_firstREAL:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlREAL);
+ ffestb_local_.decl.type = FFESTP_typeREAL;
+ needfunc = FALSE;
+ goto typefunc; /* :::::::::::::::::::: */
+
+ case FFESTR_firstCMPLX:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlCMPLX);
+ ffestb_local_.decl.type = FFESTP_typeCOMPLEX;
+ needfunc = FALSE;
+ goto typefunc; /* :::::::::::::::::::: */
+
+ case FFESTR_firstLGCL:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlLGCL);
+ ffestb_local_.decl.type = FFESTP_typeLOGICAL;
+ needfunc = FALSE;
+ goto typefunc; /* :::::::::::::::::::: */
+
+ case FFESTR_firstCHRCTR:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlCHRCTR);
+ ffestb_local_.decl.type = FFESTP_typeCHARACTER;
+ needfunc = FALSE;
+ goto typefunc; /* :::::::::::::::::::: */
+
+ case FFESTR_firstDBLPRCSN:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlDBLPRCSN);
+ ffestb_local_.decl.type = FFESTP_typeDBLPRCSN;
+ needfunc = TRUE;
+ goto typefunc; /* :::::::::::::::::::: */
+
+ case FFESTR_firstDBLCMPLX:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlDBLCMPLX);
+ ffestb_local_.decl.type = FFESTP_typeDBLCMPLX;
+ needfunc = TRUE;
+ goto typefunc; /* :::::::::::::::::::: */
+
+ case FFESTR_firstTYPE:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlTYPE);
+ ffestb_local_.decl.type = FFESTP_typeTYPE;
+ next = (ffelexHandler) ffestb_decl_recursive3_;
+ break;
+
+ case FFESTR_firstFUNCTION:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlFUNCTION);
+ ffestb_local_.dummy.first_kw = FFESTR_firstFUNCTION;
+ ffestb_local_.dummy.badname = "FUNCTION";
+ ffestb_local_.dummy.is_subr = FALSE;
+ next = (ffelexHandler) ffestb_decl_recursive4_;
+ break;
+
+ case FFESTR_firstSUBROUTINE:
+ p = ffelex_token_text (nt) + (i = FFESTR_firstlSUBROUTINE);
+ ffestb_local_.dummy.first_kw = FFESTR_firstSUBROUTINE;
+ ffestb_local_.dummy.badname = "SUBROUTINE";
+ ffestb_local_.dummy.is_subr = TRUE;
+ next = (ffelexHandler) ffestb_decl_recursive4_;
+ break;
+
+ default:
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffelex_token_kill (nt);
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+ if (*p == '\0')
+ {
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+ }
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ot = ffelex_token_name_from_names (nt, i, 0);
+ ffelex_token_kill (nt);
+ next = (ffelexHandler) (*next) (ot);
+ ffelex_token_kill (ot);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+typefunc: /* :::::::::::::::::::: */
+ if (*p == '\0')
+ {
+ ffelex_token_kill (nt);
+ if (needfunc) /* DOUBLE PRECISION or DOUBLE COMPLEX? */
+ {
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+ return (ffelexHandler) ffestb_decl_recursive1_ (t);
+ }
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ot = ffelex_token_names_from_names (nt, i, 0);
+ ffelex_token_kill (nt);
+ if (ffestr_first (ot) != FFESTR_firstFUNCTION)
+ goto bad_o; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ot) + (i = FFESTR_firstlFUNCTION);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1] = ffelex_token_name_from_names (ot, i, 0);
+ ffelex_token_kill (ot);
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_funcname_1_ (t);
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "type-declaration", nt, i, t);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_o: /* :::::::::::::::::::: */
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", ot);
+ ffelex_token_kill (ot);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_recursive1_ -- "RECURSIVE" generic-type
+
+ return ffestb_decl_recursive1_; // to lexer
+
+ Handle ASTERISK, OPEN_PAREN, or NAME. */
+
+static ffelexHandler
+ffestb_decl_recursive1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeASTERISK:
+ ffesta_confirmed ();
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_func_;
+ ffestb_local_.decl.badname = "TYPEFUNC";
+ if (ffestb_local_.decl.type == FFESTP_typeCHARACTER)
+ return (ffelexHandler) ffestb_decl_starlen_;
+ return (ffelexHandler) ffestb_decl_starkind_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_func_;
+ ffestb_local_.decl.badname = "TYPEFUNC";
+ if (ffestb_local_.decl.type == FFESTP_typeCHARACTER)
+ {
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_typeparams_;
+ }
+ return (ffelexHandler) ffestb_decl_kindparam_;
+
+ case FFELEX_typeNAME:
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_func_ (t);
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_recursive2_ -- "RECURSIVE" "DOUBLE"
+
+ return ffestb_decl_recursive2_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_decl_recursive2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ switch (ffestr_second (t))
+ {
+ case FFESTR_secondPRECISION:
+ ffestb_local_.decl.type = FFESTP_typeDBLPRCSN;
+ break;
+
+ case FFESTR_secondCOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeDBLCMPLX;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_func_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_recursive3_ -- "RECURSIVE" "TYPE"
+
+ return ffestb_decl_recursive3_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_recursive3_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_func_;
+ ffestb_local_.decl.badname = "TYPEFUNC";
+ return (ffelexHandler) ffestb_decl_typetype1_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_recursive4_ -- "RECURSIVE" "FUNCTION/SUBROUTINE"
+
+ return ffestb_decl_recursive4_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_recursive4_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_dummy1_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_decl_typetype -- Parse the R426/R501/R1219 TYPE statement
+
+ return ffestb_decl_typetype; // to lexer
+
+ Make sure the statement has a valid form for the TYPE statement. If it
+ does, implement the statement. */
+
+#if FFESTR_F90
+ffelexHandler
+ffestb_decl_typetype (ffelexToken t)
+{
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstTYPE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstTYPE)
+ goto bad_0; /* :::::::::::::::::::: */
+ if (ffelex_token_length (ffesta_tokens[0]) != FFESTR_firstlTYPE)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOLONCOLON:/* Not COMMA: R424 "TYPE,PUBLIC::A". */
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ ffestb_local_.decl.recursive = NULL;
+ ffestb_local_.decl.parameter = FALSE; /* No PARAMETER attribute seen. */
+ ffestb_local_.decl.coloncolon = FALSE; /* No COLONCOLON seen. */
+
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_attrsp_;
+ ffestb_local_.decl.badname = "type-declaration";
+ return (ffelexHandler) ffestb_decl_typetype1_;
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+#endif
+/* ffestb_decl_attrs_ -- "type" [type parameters] COMMA
+
+ return ffestb_decl_attrs_; // to lexer
+
+ Handle NAME of an attribute. */
+
+static ffelexHandler
+ffestb_decl_attrs_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ switch (ffestr_first (t))
+ {
+#if FFESTR_F90
+ case FFESTR_firstALLOCATABLE:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribALLOCATABLE, t,
+ FFESTR_otherNone, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+#endif
+
+ case FFESTR_firstDIMENSION:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_attrs_1_;
+
+ case FFESTR_firstEXTERNAL:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribEXTERNAL, t,
+ FFESTR_otherNone, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+
+#if FFESTR_F90
+ case FFESTR_firstINTENT:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_attrs_3_;
+#endif
+
+ case FFESTR_firstINTRINSIC:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribINTRINSIC, t,
+ FFESTR_otherNone, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+
+#if FFESTR_F90
+ case FFESTR_firstOPTIONAL:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribOPTIONAL, t,
+ FFESTR_otherNone, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+#endif
+
+ case FFESTR_firstPARAMETER:
+ ffestb_local_.decl.parameter = TRUE;
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribPARAMETER, t,
+ FFESTR_otherNone, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+
+#if FFESTR_F90
+ case FFESTR_firstPOINTER:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribPOINTER, t,
+ FFESTR_otherNone, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+#endif
+
+#if FFESTR_F90
+ case FFESTR_firstPRIVATE:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribPRIVATE, t,
+ FFESTR_otherNone, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+
+ case FFESTR_firstPUBLIC:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribPUBLIC, t,
+ FFESTR_otherNone, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+#endif
+
+ case FFESTR_firstSAVE:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribSAVE, t,
+ FFESTR_otherNone, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+
+#if FFESTR_F90
+ case FFESTR_firstTARGET:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribTARGET, t,
+ FFESTR_otherNone, NULL);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+#endif
+
+ default:
+ ffesta_ffebad_1t (FFEBAD_INVALID_TYPEDECL_ATTR, t);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_attrs_1_ -- "type" [type parameters] ",DIMENSION"
+
+ return ffestb_decl_attrs_1_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_attrs_1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_subrargs_.dim_list.dims = ffestt_dimlist_create ();
+ ffestb_subrargs_.dim_list.handler = (ffelexHandler) ffestb_decl_attrs_2_;
+ ffestb_subrargs_.dim_list.pool = ffesta_scratch_pool;
+ ffestb_subrargs_.dim_list.ctx = ffesta_is_entry_valid
+ ? FFEEXPR_contextDIMLIST : FFEEXPR_contextDIMLISTCOMMON;
+#ifdef FFECOM_dimensionsMAX
+ ffestb_subrargs_.dim_list.ndims = 0;
+#endif
+ return (ffelexHandler) ffeexpr_rhs (ffesta_scratch_pool,
+ ffestb_subrargs_.dim_list.ctx,
+ (ffeexprCallback) ffestb_subr_dimlist_);
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_ffebad_1t (FFEBAD_INVALID_TYPEDECL_ATTR, ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_decl_attrs_7_ (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1t (FFEBAD_INVALID_TYPEDECL_ATTR, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_attrs_2_ -- "type" [type parameters] ",DIMENSION" OPEN_PAREN
+ dimlist CLOSE_PAREN
+
+ return ffestb_decl_attrs_2_; // to lexer
+
+ Handle COMMA or COLONCOLON. */
+
+static ffelexHandler
+ffestb_decl_attrs_2_ (ffelexToken t)
+{
+ if (!ffestb_subrargs_.dim_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribDIMENSION, ffesta_tokens[1],
+ FFESTR_otherNone, ffestb_subrargs_.dim_list.dims);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffestb_decl_attrs_7_ (t);
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_attrs_3_ -- "type" [type parameters] ",INTENT"
+
+ return ffestb_decl_attrs_3_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+#if FFESTR_F90
+static ffelexHandler
+ffestb_decl_attrs_3_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ return (ffelexHandler) ffestb_decl_attrs_4_;
+
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_ffebad_1t (FFEBAD_INVALID_TYPEDECL_ATTR, ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_decl_attrs_7_ (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1t (FFEBAD_INVALID_TYPEDECL_ATTR, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_attrs_4_ -- "type" [type parameters] ",INTENT" OPEN_PAREN
+
+ return ffestb_decl_attrs_4_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_decl_attrs_4_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffestb_local_.decl.kw = ffestr_other (t);
+ switch (ffestb_local_.decl.kw)
+ {
+ case FFESTR_otherIN:
+ return (ffelexHandler) ffestb_decl_attrs_5_;
+
+ case FFESTR_otherINOUT:
+ return (ffelexHandler) ffestb_decl_attrs_6_;
+
+ case FFESTR_otherOUT:
+ return (ffelexHandler) ffestb_decl_attrs_6_;
+
+ default:
+ ffestb_local_.decl.kw = FFESTR_otherNone;
+ ffesta_ffebad_1t (FFEBAD_INVALID_TYPEDECL_ATTR, t);
+ return (ffelexHandler) ffestb_decl_attrs_5_;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_attrs_5_ -- "type" [type parameters] ",INTENT" OPEN_PAREN "IN"
+
+ return ffestb_decl_attrs_5_; // to lexer
+
+ Handle NAME or CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_decl_attrs_5_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ switch (ffestr_other (t))
+ {
+ case FFESTR_otherOUT:
+ if (ffestb_local_.decl.kw != FFESTR_otherNone)
+ ffestb_local_.decl.kw = FFESTR_otherINOUT;
+ return (ffelexHandler) ffestb_decl_attrs_6_;
+
+ default:
+ if (ffestb_local_.decl.kw != FFESTR_otherNone)
+ {
+ ffestb_local_.decl.kw = FFESTR_otherNone;
+ ffesta_ffebad_1t (FFEBAD_INVALID_TYPEDECL_ATTR, t);
+ }
+ return (ffelexHandler) ffestb_decl_attrs_5_;
+ }
+ break;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_decl_attrs_6_ (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_attrs_6_ -- "type" [type parameters] ",INTENT" OPEN_PAREN "IN"
+ ["OUT"]
+
+ return ffestb_decl_attrs_6_; // to lexer
+
+ Handle CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_decl_attrs_6_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if ((ffestb_local_.decl.kw != FFESTR_otherNone)
+ && !ffesta_is_inhibited ())
+ ffestc_decl_attrib (FFESTP_attribINTENT, ffesta_tokens[1],
+ ffestb_local_.decl.kw, NULL);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_decl_attrs_7_;
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_decl_attrs_7_ -- "type" [type parameters] attribute
+
+ return ffestb_decl_attrs_7_; // to lexer
+
+ Handle COMMA (another attribute) or COLONCOLON (entities). */
+
+static ffelexHandler
+ffestb_decl_attrs_7_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_decl_attrs_;
+
+ case FFELEX_typeCOLONCOLON:
+ ffestb_local_.decl.coloncolon = TRUE;
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_attrsp_ -- "type" [type parameters]
+
+ return ffestb_decl_attrsp_; // to lexer
+
+ Handle COMMA (meaning we have attributes), COLONCOLON (meaning we have
+ no attributes but entities), or go to entsp to see about functions or
+ entities. */
+
+static ffelexHandler
+ffestb_decl_attrsp_ (ffelexToken t)
+{
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ ffestb_local_.decl.kind, ffestb_local_.decl.kindt,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ return (ffelexHandler) ffestb_decl_attrs_;
+
+ case FFELEX_typeCOLONCOLON:
+ ffestb_local_.decl.coloncolon = TRUE;
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ ffestb_local_.decl.kind, ffestb_local_.decl.kindt,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ default:
+ return (ffelexHandler) ffestb_decl_entsp_ (t);
+ }
+}
+
+/* ffestb_decl_ents_ -- "type" [type parameters] [attributes "::"]
+
+ return ffestb_decl_ents_; // to lexer
+
+ Handle NAME of an entity. */
+
+static ffelexHandler
+ffestb_decl_ents_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_ents_1_;
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_1_ -- "type" [type parameters] [attributes "::"] NAME
+
+ return ffestb_decl_ents_1_; // to lexer
+
+ Handle ASTERISK, OPEN_PAREN, EQUALS, SLASH, COMMA, or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_decl_ents_1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_item (ffesta_tokens[1], NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, FALSE);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_decl_item (ffesta_tokens[1], NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, FALSE);
+ ffestc_decl_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeASTERISK:
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_ents_2_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_ents_3_ (t);
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typeSLASH:
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_subrargs_.dim_list.dims = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_ents_7_ (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_2_ -- "type" [type parameters] [attributes "::"] NAME
+ ASTERISK
+
+ return ffestb_decl_ents_2_; // to lexer
+
+ Handle NUMBER or OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_ents_2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ if (ffestb_local_.decl.type != FFESTP_typeCHARACTER)
+ {
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_ents_3_;
+ }
+ /* Fall through. *//* (CHARACTER's *n is always a len spec. */
+ case FFELEX_typeOPEN_PAREN:/* "*(" is after the (omitted)
+ "(array-spec)". */
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_subrargs_.dim_list.dims = NULL;
+ return (ffelexHandler) ffestb_decl_ents_5_ (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_3_ -- "type" [type parameters] [attributes "::"] NAME
+ [ASTERISK NUMBER]
+
+ return ffestb_decl_ents_3_; // to lexer
+
+ Handle ASTERISK, OPEN_PAREN, EQUALS, SLASH, COMMA, or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_decl_ents_3_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_item (ffesta_tokens[1], ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, NULL, NULL, NULL, NULL, NULL, FALSE);
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_decl_item (ffesta_tokens[1], ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, NULL, NULL, NULL, NULL, NULL, FALSE);
+ ffestc_decl_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeASTERISK:
+ ffestb_subrargs_.dim_list.dims = NULL;
+ return (ffelexHandler) ffestb_decl_ents_5_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_subrargs_.dim_list.dims = ffestt_dimlist_create ();
+ ffestb_subrargs_.dim_list.handler = (ffelexHandler) ffestb_decl_ents_4_;
+ ffestb_subrargs_.dim_list.pool = ffesta_output_pool;
+ ffestb_subrargs_.dim_list.ctx = ffesta_is_entry_valid
+ ? FFEEXPR_contextDIMLIST : FFEEXPR_contextDIMLISTCOMMON;
+#ifdef FFECOM_dimensionsMAX
+ ffestb_subrargs_.dim_list.ndims = 0;
+#endif
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_subrargs_.dim_list.ctx,
+ (ffeexprCallback) ffestb_subr_dimlist_);
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typeSLASH:
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_subrargs_.dim_list.dims = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_ents_7_ (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_4_ -- "type" [type parameters] [attributes "::"] NAME
+ [ASTERISK NUMBER] [OPEN_PAREN dimlist CLOSE_PAREN]
+
+ return ffestb_decl_ents_4_; // to lexer
+
+ Handle ASTERISK, EQUALS, SLASH, COMMA, or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_decl_ents_4_ (ffelexToken t)
+{
+ ffelexToken nt;
+
+ if (!ffestb_subrargs_.dim_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ if (ffelex_token_type (ffesta_tokens[1]) == FFELEX_typeNAMES)
+ {
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeASTERISK:
+ case FFELEX_typeSLASH: /* But NOT FFELEX_typeEQUALS. */
+ case FFELEX_typeCOLONCOLON: /* Actually an error. */
+ break; /* Confirm and handle. */
+
+ default: /* Perhaps EQUALS, as in
+ INTEGERFUNCTIONX(A)=B. */
+ goto bad; /* :::::::::::::::::::: */
+ }
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ nt = ffelex_token_name_from_names (ffesta_tokens[1], 0, 0);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_tokens[1] = nt;
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ NULL, NULL, NULL, NULL);
+ }
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_item (ffesta_tokens[1], ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, ffestb_subrargs_.dim_list.dims,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent, NULL, NULL,
+ FALSE);
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_decl_item (ffesta_tokens[1], ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, ffestb_subrargs_.dim_list.dims,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent, NULL, NULL,
+ FALSE);
+ ffestc_decl_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeASTERISK:
+ if (ffestb_local_.decl.lent != NULL)
+ break; /* Can't specify "*length" twice. */
+ return (ffelexHandler) ffestb_decl_ents_5_;
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typeSLASH:
+ return (ffelexHandler) ffestb_decl_ents_7_ (t);
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ if ((ffelex_token_type (ffesta_tokens[1]) != FFELEX_typeNAMES)
+ && !ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_5_ -- "type" [type parameters] [attributes "::"] NAME
+ [ASTERISK NUMBER] [OPEN_PAREN dimlist CLOSE_PAREN]
+ ASTERISK
+
+ return ffestb_decl_ents_5_; // to lexer
+
+ Handle NUMBER or OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_ents_5_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_ents_7_;
+
+ case FFELEX_typeOPEN_PAREN:
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCHARACTERSIZE, (ffeexprCallback) ffestb_decl_ents_6_);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_subrargs_.dim_list.dims != NULL)
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_6_ -- "type" [type parameters] [attributes "::"] NAME
+ [ASTERISK NUMBER] [OPEN_PAREN dimlist CLOSE_PAREN]
+ ASTERISK OPEN_PAREN expr
+
+ (ffestb_decl_ents_6_) // to expression handler
+
+ Handle CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_decl_ents_6_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ ffestb_local_.decl.len = expr;
+ ffestb_local_.decl.lent = ffelex_token_use (ft);
+ return (ffelexHandler) ffestb_decl_ents_7_;
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_subrargs_.dim_list.dims != NULL)
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_7_ -- "type" [type parameters] [attributes "::"] NAME
+ [ASTERISK NUMBER] [OPEN_PAREN dimlist CLOSE_PAREN]
+ [ASTERISK charlength]
+
+ return ffestb_decl_ents_7_; // to lexer
+
+ Handle EQUALS, SLASH, COMMA, or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_decl_ents_7_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_item (ffesta_tokens[1], ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, ffestb_subrargs_.dim_list.dims,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent, NULL, NULL,
+ FALSE);
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_subrargs_.dim_list.dims != NULL)
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_decl_item (ffesta_tokens[1], ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, ffestb_subrargs_.dim_list.dims,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent, NULL, NULL,
+ FALSE);
+ ffestc_decl_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_subrargs_.dim_list.dims != NULL)
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeEQUALS:
+ if (!ffestb_local_.decl.coloncolon)
+ ffesta_ffebad_1t (FFEBAD_INVALID_TYPEDECL_INIT, t);
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ ffestb_local_.decl.parameter ? FFEEXPR_contextPARAMETER
+ : FFEEXPR_contextINITVAL, (ffeexprCallback) ffestb_decl_ents_8_);
+
+ case FFELEX_typeSLASH:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_decl_item (ffesta_tokens[1], ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, ffestb_subrargs_.dim_list.dims,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent, NULL, NULL,
+ TRUE);
+ ffestc_decl_itemstartvals ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_subrargs_.dim_list.dims != NULL)
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ return (ffelexHandler) ffeexpr_rhs
+ (ffesta_output_pool, FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_decl_ents_9_);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_subrargs_.dim_list.dims != NULL)
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_8_ -- "type" [type parameters] [attributes "::"] NAME
+ [ASTERISK NUMBER] [OPEN_PAREN dimlist CLOSE_PAREN]
+ [ASTERISK charlength] EQUALS expr
+
+ (ffestb_decl_ents_8_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_decl_ents_8_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_item (ffesta_tokens[1], ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, ffestb_subrargs_.dim_list.dims,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent, expr, ft,
+ FALSE);
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_subrargs_.dim_list.dims != NULL)
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_decl_item (ffesta_tokens[1], ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, ffestb_subrargs_.dim_list.dims,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent, expr, ft,
+ FALSE);
+ ffestc_decl_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_subrargs_.dim_list.dims != NULL)
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_subrargs_.dim_list.dims != NULL)
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_9_ -- "type" ... SLASH expr
+
+ (ffestb_decl_ents_9_) // to expression handler
+
+ Handle ASTERISK, COMMA, or SLASH. */
+
+static ffelexHandler
+ffestb_decl_ents_9_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_itemvalue (NULL, NULL, expr, ft);
+ return (ffelexHandler) ffeexpr_rhs
+ (ffesta_output_pool, FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_decl_ents_9_);
+
+ case FFELEX_typeASTERISK:
+ if (expr == NULL)
+ break;
+ ffestb_local_.decl.expr = expr;
+ ffesta_tokens[1] = ffelex_token_use (ft);
+ return (ffelexHandler) ffeexpr_rhs
+ (ffesta_output_pool, FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_decl_ents_10_);
+
+ case FFELEX_typeSLASH:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_decl_itemvalue (NULL, NULL, expr, ft);
+ ffestc_decl_itemendvals (t);
+ }
+ return (ffelexHandler) ffestb_decl_ents_11_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_decl_itemendvals (t);
+ ffestc_decl_finish ();
+ }
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_10_ -- "type" ... SLASH expr ASTERISK expr
+
+ (ffestb_decl_ents_10_) // to expression handler
+
+ Handle COMMA or SLASH. */
+
+static ffelexHandler
+ffestb_decl_ents_10_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_itemvalue (ffestb_local_.decl.expr, ffesta_tokens[1],
+ expr, ft);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffeexpr_rhs
+ (ffesta_output_pool, FFEEXPR_contextDATA,
+ (ffeexprCallback) ffestb_decl_ents_9_);
+
+ case FFELEX_typeSLASH:
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_decl_itemvalue (ffestb_local_.decl.expr, ffesta_tokens[1],
+ expr, ft);
+ ffestc_decl_itemendvals (t);
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_decl_ents_11_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_decl_itemendvals (t);
+ ffestc_decl_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_ents_11_ -- "type" [type parameters] [attributes "::"] NAME
+ [ASTERISK NUMBER] [OPEN_PAREN dimlist CLOSE_PAREN]
+ [ASTERISK charlength] SLASH initvals SLASH
+
+ return ffestb_decl_ents_11_; // to lexer
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_decl_ents_11_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_decl_ents_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_decl_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_entsp_ -- "type" [type parameters]
+
+ return ffestb_decl_entsp_; // to lexer
+
+ Handle NAME or NAMES beginning either an entity (object) declaration or
+ a function definition.. */
+
+static ffelexHandler
+ffestb_decl_entsp_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_entsp_1_;
+
+ case FFELEX_typeNAMES:
+ ffesta_confirmed ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_entsp_2_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "type-declaration", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_entsp_1_ -- "type" [type parameters] NAME
+
+ return ffestb_decl_entsp_1_; // to lexer
+
+ If we get another NAME token here, then the previous one must be
+ "RECURSIVE" or "FUNCTION" and we handle it accordingly. Otherwise,
+ we send the previous and current token through to _ents_. */
+
+static ffelexHandler
+ffestb_decl_entsp_1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ switch (ffestr_first (ffesta_tokens[1]))
+ {
+#if FFESTR_F90
+ case FFESTR_firstRECURSIVE:
+ if (ffestr_first (t) != FFESTR_firstFUNCTION)
+ {
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ break;
+ }
+ ffestb_local_.decl.recursive = ffesta_tokens[1];
+ return (ffelexHandler) ffestb_decl_funcname_;
+#endif
+
+ case FFESTR_firstFUNCTION:
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_decl_funcname_ (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", ffesta_tokens[1]);
+ break;
+ }
+ break;
+
+ default:
+ if ((ffelex_token_type (ffesta_tokens[1]) != FFELEX_typeNAMES)
+ && !ffesta_is_inhibited ())
+ ffestc_decl_start (ffestb_local_.decl.type, ffesta_tokens[0],
+ ffestb_local_.decl.kind, ffestb_local_.decl.kindt,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ /* NAME/NAMES token already in ffesta_tokens[1]. */
+ return (ffelexHandler) ffestb_decl_ents_1_ (t);
+ }
+
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_entsp_2_ -- "type" [type parameters] NAMES
+
+ return ffestb_decl_entsp_2_; // to lexer
+
+ If we get an ASTERISK or OPEN_PAREN here, then if the previous NAMES
+ begins with "FUNCTION" or "RECURSIVEFUNCTION" and is followed by a
+ first-name-char, we have a possible syntactically ambiguous situation.
+ Otherwise, we have a straightforward situation just as if we went
+ through _entsp_1_ instead of here. */
+
+static ffelexHandler
+ffestb_decl_entsp_2_ (ffelexToken t)
+{
+ ffelexToken nt;
+ bool asterisk_ok;
+ char *p;
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeASTERISK:
+ ffesta_confirmed ();
+ switch (ffestb_local_.decl.type)
+ {
+ case FFESTP_typeINTEGER:
+ case FFESTP_typeREAL:
+ case FFESTP_typeCOMPLEX:
+ case FFESTP_typeLOGICAL:
+ asterisk_ok = (ffestb_local_.decl.kindt == NULL);
+ break;
+
+ case FFESTP_typeCHARACTER:
+ asterisk_ok = (ffestb_local_.decl.lent == NULL);
+ break;
+
+ case FFESTP_typeBYTE:
+ case FFESTP_typeWORD:
+ default:
+ asterisk_ok = FALSE;
+ break;
+ }
+ switch (ffestr_first (ffesta_tokens[1]))
+ {
+#if FFESTR_F90
+ case FFESTR_firstRECURSIVEFNCTN:
+ if (!asterisk_ok)
+ break; /* For our own convenience, treat as non-FN
+ stmt. */
+ p = ffelex_token_text (ffesta_tokens[1])
+ + (i = FFESTR_firstlRECURSIVEFNCTN);
+ if (!ffesrc_is_name_init (*p))
+ break;
+ ffestb_local_.decl.recursive
+ = ffelex_token_name_from_names (ffesta_tokens[1], 0,
+ FFESTR_firstlRECURSIVEFNCTN);
+ ffesta_tokens[2] = ffelex_token_name_from_names (ffesta_tokens[1],
+ FFESTR_firstlRECURSIVEFNCTN, 0);
+ return (ffelexHandler) ffestb_decl_entsp_3_;
+#endif
+
+ case FFESTR_firstFUNCTION:
+ if (!asterisk_ok)
+ break; /* For our own convenience, treat as non-FN
+ stmt. */
+ p = ffelex_token_text (ffesta_tokens[1])
+ + (i = FFESTR_firstlFUNCTION);
+ if (!ffesrc_is_name_init (*p))
+ break;
+ ffestb_local_.decl.recursive = NULL;
+ ffesta_tokens[2] = ffelex_token_name_from_names (ffesta_tokens[1],
+ FFESTR_firstlFUNCTION, 0);
+ return (ffelexHandler) ffestb_decl_entsp_3_;
+
+ default:
+ break;
+ }
+ break;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.decl.aster_after = FALSE;
+ switch (ffestr_first (ffesta_tokens[1]))
+ {
+#if FFESTR_F90
+ case FFESTR_firstRECURSIVEFNCTN:
+ p = ffelex_token_text (ffesta_tokens[1])
+ + (i = FFESTR_firstlRECURSIVEFNCTN);
+ if (!ffesrc_is_name_init (*p))
+ break;
+ ffestb_local_.decl.recursive
+ = ffelex_token_name_from_names (ffesta_tokens[1], 0,
+ FFESTR_firstlRECURSIVEFNCTN);
+ ffesta_tokens[2] = ffelex_token_name_from_names (ffesta_tokens[1],
+ FFESTR_firstlRECURSIVEFNCTN, 0);
+ return (ffelexHandler) ffestb_decl_entsp_5_ (t);
+#endif
+
+ case FFESTR_firstFUNCTION:
+ p = ffelex_token_text (ffesta_tokens[1])
+ + (i = FFESTR_firstlFUNCTION);
+ if (!ffesrc_is_name_init (*p))
+ break;
+ ffestb_local_.decl.recursive = NULL;
+ ffesta_tokens[2] = ffelex_token_name_from_names (ffesta_tokens[1],
+ FFESTR_firstlFUNCTION, 0);
+ return (ffelexHandler) ffestb_decl_entsp_5_ (t);
+
+ default:
+ break;
+ }
+ if ((ffestb_local_.decl.kindt != NULL)
+ || (ffestb_local_.decl.lent != NULL))
+ break; /* Have kind/len type param, definitely not
+ assignment stmt. */
+ return (ffelexHandler) ffestb_decl_entsp_1_ (t);
+
+ default:
+ break;
+ }
+
+ nt = ffelex_token_name_from_names (ffesta_tokens[1], 0, 0);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_tokens[1] = nt; /* Change NAMES to NAME. */
+ return (ffelexHandler) ffestb_decl_entsp_1_ (t);
+}
+
+/* ffestb_decl_entsp_3_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME ASTERISK
+
+ return ffestb_decl_entsp_3_; // to lexer
+
+ Handle NUMBER or OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_entsp_3_ (ffelexToken t)
+{
+ ffestb_local_.decl.aster_after = TRUE;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ switch (ffestb_local_.decl.type)
+ {
+ case FFESTP_typeINTEGER:
+ case FFESTP_typeREAL:
+ case FFESTP_typeCOMPLEX:
+ case FFESTP_typeLOGICAL:
+ ffestb_local_.decl.kindt = ffelex_token_use (t);
+ break;
+
+ case FFESTP_typeCHARACTER:
+ ffestb_local_.decl.lent = ffelex_token_use (t);
+ break;
+
+ case FFESTP_typeBYTE:
+ case FFESTP_typeWORD:
+ default:
+ assert (FALSE);
+ }
+ return (ffelexHandler) ffestb_decl_entsp_5_;
+
+ case FFELEX_typeOPEN_PAREN:
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCHARACTERSIZE,
+ (ffeexprCallback) ffestb_decl_entsp_4_);
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_entsp_4_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME ASTERISK OPEN_PAREN expr
+
+ (ffestb_decl_entsp_4_) // to expression handler
+
+ Allow only CLOSE_PAREN; and deal with character-length expression. */
+
+static ffelexHandler
+ffestb_decl_entsp_4_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ switch (ffestb_local_.decl.type)
+ {
+ case FFESTP_typeCHARACTER:
+ ffestb_local_.decl.len = expr;
+ ffestb_local_.decl.lent = ffelex_token_use (ft);
+ break;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ break;
+ }
+ return (ffelexHandler) ffestb_decl_entsp_5_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_entsp_5_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME [type parameter]
+
+ return ffestb_decl_entsp_5_; // to lexer
+
+ Make sure the next token is an OPEN_PAREN. Get the arg list or dimension
+ list. If it can't be an arg list, or if the CLOSE_PAREN is followed by
+ something other than EOS/SEMICOLON or NAME, then treat as dimension list
+ and handle statement as an R426/R501. If it can't be a dimension list, or
+ if the CLOSE_PAREN is followed by NAME, treat as an arg list and handle
+ statement as an R1219. If it can be either an arg list or a dimension
+ list and if the CLOSE_PAREN is followed by EOS/SEMICOLON, ask FFESTC
+ whether to treat the statement as an R426/R501 or an R1219 and act
+ accordingly. */
+
+static ffelexHandler
+ffestb_decl_entsp_5_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ if (ffestb_local_.decl.aster_after && (ffestb_local_.decl.len != NULL))
+ { /* "CHARACTER[RECURSIVE]FUNCTIONxyz*(len-expr)
+ (..." must be a function-stmt, since the
+ (len-expr) cannot precede (array-spec) in
+ an object declaration but can precede
+ (name-list) in a function stmt. */
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_tokens[1] = ffesta_tokens[2];
+ return (ffelexHandler) ffestb_decl_funcname_4_ (t);
+ }
+ ffestb_local_.decl.toklist = ffestt_tokenlist_create ();
+ ffestb_local_.decl.empty = TRUE;
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_entsp_6_;
+
+ default:
+ break;
+ }
+
+ assert (ffestb_local_.decl.aster_after);
+ ffesta_confirmed (); /* We've seen an ASTERISK, so even EQUALS
+ confirmed. */
+ ffestb_subr_ambig_to_ents_ ();
+ ffestb_subrargs_.dim_list.dims = NULL;
+ return (ffelexHandler) ffestb_decl_ents_7_ (t);
+}
+
+/* ffestb_decl_entsp_6_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME [type parameter] OPEN_PAREN
+
+ return ffestb_decl_entsp_6_; // to lexer
+
+ If CLOSE_PAREN, we definitely have an R1219 function-stmt, since
+ the notation "name()" is invalid for a declaration. */
+
+static ffelexHandler
+ffestb_decl_entsp_6_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (!ffestb_local_.decl.empty)
+ { /* Trailing comma, just a warning for
+ stmt func def, so allow ambiguity. */
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist,
+ ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_entsp_8_;
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_tokens[1] = ffesta_tokens[2];
+ next = (ffelexHandler) ffestt_tokenlist_handle
+ (ffestb_local_.decl.toklist, (ffelexHandler) ffestb_decl_funcname_4_);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) (*next) (t);
+
+ case FFELEX_typeNAME:
+ ffestb_local_.decl.empty = FALSE;
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_entsp_7_;
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typePERCENT:
+ case FFELEX_typePERIOD:
+ case FFELEX_typeOPEN_PAREN:
+ if ((ffestb_local_.decl.kindt != NULL)
+ || (ffestb_local_.decl.lent != NULL))
+ break; /* type(params)name or type*val name, either
+ way confirmed. */
+ return (ffelexHandler) ffestb_subr_ambig_nope_ (t);
+
+ default:
+ break;
+ }
+
+ ffesta_confirmed ();
+ ffestb_subr_ambig_to_ents_ ();
+ next = (ffelexHandler) ffestt_tokenlist_handle (ffestb_local_.decl.toklist,
+ (ffelexHandler) ffestb_decl_ents_3_);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffestb_decl_entsp_7_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME [type parameter] OPEN_PAREN NAME
+
+ return ffestb_decl_entsp_7_; // to lexer
+
+ Expect COMMA or CLOSE_PAREN to remain ambiguous, else not an R1219
+ function-stmt. */
+
+static ffelexHandler
+ffestb_decl_entsp_7_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_entsp_8_;
+
+ case FFELEX_typeCOMMA:
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_entsp_6_;
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typePERCENT:
+ case FFELEX_typePERIOD:
+ case FFELEX_typeOPEN_PAREN:
+ if ((ffestb_local_.decl.kindt != NULL)
+ || (ffestb_local_.decl.lent != NULL))
+ break; /* type(params)name or type*val name, either
+ way confirmed. */
+ return (ffelexHandler) ffestb_subr_ambig_nope_ (t);
+
+ default:
+ break;
+ }
+
+ ffesta_confirmed ();
+ ffestb_subr_ambig_to_ents_ ();
+ next = (ffelexHandler) ffestt_tokenlist_handle (ffestb_local_.decl.toklist,
+ (ffelexHandler) ffestb_decl_ents_3_);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffestb_decl_entsp_8_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME [type parameter] OPEN_PAREN name-list
+ CLOSE_PAREN
+
+ return ffestb_decl_entsp_8_; // to lexer
+
+ If EOS/SEMICOLON, situation remains ambiguous, ask FFESTC to resolve
+ it. If NAME (must be "RESULT", but that is checked later on),
+ definitely an R1219 function-stmt. Anything else, handle as entity decl. */
+
+static ffelexHandler
+ffestb_decl_entsp_8_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (ffestc_is_decl_not_R1219 ())
+ break;
+ /* Fall through. */
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_tokens[1] = ffesta_tokens[2];
+ next = (ffelexHandler) ffestt_tokenlist_handle
+ (ffestb_local_.decl.toklist, (ffelexHandler) ffestb_decl_funcname_4_);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) (*next) (t);
+
+ case FFELEX_typeEQUALS:
+ case FFELEX_typePOINTS:
+ case FFELEX_typePERCENT:
+ case FFELEX_typePERIOD:
+ case FFELEX_typeOPEN_PAREN:
+ if ((ffestb_local_.decl.kindt != NULL)
+ || (ffestb_local_.decl.lent != NULL))
+ break; /* type(params)name or type*val name, either
+ way confirmed. */
+ return (ffelexHandler) ffestb_subr_ambig_nope_ (t);
+
+ default:
+ break;
+ }
+
+ ffesta_confirmed ();
+ ffestb_subr_ambig_to_ents_ ();
+ next = (ffelexHandler) ffestt_tokenlist_handle (ffestb_local_.decl.toklist,
+ (ffelexHandler) ffestb_decl_ents_3_);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffestb_decl_func_ -- ["type" [type parameters]] RECURSIVE
+
+ return ffestb_decl_func_; // to lexer
+
+ Handle "FUNCTION". */
+
+#if FFESTR_F90
+static ffelexHandler
+ffestb_decl_func_ (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (ffestr_first (t) != FFESTR_firstFUNCTION)
+ break;
+ return (ffelexHandler) ffestb_decl_funcname_;
+
+ case FFELEX_typeNAMES:
+ ffesta_confirmed ();
+ if (ffestr_first (t) != FFESTR_firstFUNCTION)
+ break;
+ p = ffelex_token_text (t) + (i = FFESTR_firstlFUNCTION);
+ if (*p == '\0')
+ break;
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffesta_tokens[1] = ffelex_token_name_from_names (t, i, 0);
+ return (ffelexHandler) ffestb_decl_funcname_1_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_i: /* :::::::::::::::::::: */
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t, i, NULL);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_decl_funcname_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+
+ return ffestb_decl_funcname_; // to lexer
+
+ Handle NAME of a function. */
+
+static ffelexHandler
+ffestb_decl_funcname_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_funcname_1_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_funcname_1_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME
+
+ return ffestb_decl_funcname_1_; // to lexer
+
+ Handle ASTERISK or OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_funcname_1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeASTERISK:
+ return (ffelexHandler) ffestb_decl_funcname_2_;
+
+ case FFELEX_typeOPEN_PAREN:
+ return (ffelexHandler) ffestb_decl_funcname_4_ (t);
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_funcname_2_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME ASTERISK
+
+ return ffestb_decl_funcname_2_; // to lexer
+
+ Handle NUMBER or OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_funcname_2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNUMBER:
+ switch (ffestb_local_.decl.type)
+ {
+ case FFESTP_typeINTEGER:
+ case FFESTP_typeREAL:
+ case FFESTP_typeCOMPLEX:
+ case FFESTP_typeLOGICAL:
+ if (ffestb_local_.decl.kindt == NULL)
+ ffestb_local_.decl.kindt = ffelex_token_use (t);
+ else
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ break;
+
+ case FFESTP_typeCHARACTER:
+ if (ffestb_local_.decl.lent == NULL)
+ ffestb_local_.decl.lent = ffelex_token_use (t);
+ else
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ break;
+
+ case FFESTP_typeBYTE:
+ case FFESTP_typeWORD:
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ break;
+ }
+ return (ffelexHandler) ffestb_decl_funcname_4_;
+
+ case FFELEX_typeOPEN_PAREN:
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextCHARACTERSIZE,
+ (ffeexprCallback) ffestb_decl_funcname_3_);
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_funcname_3_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME ASTERISK OPEN_PAREN expr
+
+ (ffestb_decl_funcname_3_) // to expression handler
+
+ Allow only CLOSE_PAREN; and deal with character-length expression. */
+
+static ffelexHandler
+ffestb_decl_funcname_3_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ if (expr == NULL)
+ break;
+ switch (ffestb_local_.decl.type)
+ {
+ case FFESTP_typeCHARACTER:
+ if (ffestb_local_.decl.lent == NULL)
+ {
+ ffestb_local_.decl.len = expr;
+ ffestb_local_.decl.lent = ffelex_token_use (ft);
+ }
+ else
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ break;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ break;
+ }
+ return (ffelexHandler) ffestb_decl_funcname_4_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_funcname_4_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME [type parameter]
+
+ return ffestb_decl_funcname_4_; // to lexer
+
+ Make sure the next token is an OPEN_PAREN. Get the arg list and
+ then implement. */
+
+static ffelexHandler
+ffestb_decl_funcname_4_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_subrargs_.name_list.args = ffestt_tokenlist_create ();
+ ffestb_subrargs_.name_list.handler
+ = (ffelexHandler) ffestb_decl_funcname_5_;
+ ffestb_subrargs_.name_list.is_subr = FALSE;
+ ffestb_subrargs_.name_list.names = FALSE;
+ return (ffelexHandler) ffestb_subr_name_list_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_funcname_5_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME [type parameter] OPEN_PAREN arg-list
+ CLOSE_PAREN
+
+ return ffestb_decl_funcname_5_; // to lexer
+
+ Must have EOS/SEMICOLON or "RESULT" here. */
+
+static ffelexHandler
+ffestb_decl_funcname_5_ (ffelexToken t)
+{
+ if (!ffestb_subrargs_.name_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R1219 (ffesta_tokens[1], ffestb_subrargs_.name_list.args,
+ ffestb_subrargs_.name_list.close_paren, ffestb_local_.decl.type,
+ ffestb_local_.decl.kind, ffestb_local_.decl.kindt,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent,
+ ffestb_local_.decl.recursive, NULL);
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeNAME:
+ if (ffestr_other (t) != FFESTR_otherRESULT)
+ break;
+ return (ffelexHandler) ffestb_decl_funcname_6_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_funcname_6_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME [type parameter] OPEN_PAREN arglist
+ CLOSE_PAREN "RESULT"
+
+ return ffestb_decl_funcname_6_; // to lexer
+
+ Make sure the next token is an OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_funcname_6_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ return (ffelexHandler) ffestb_decl_funcname_7_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_funcname_7_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME [type parameter] OPEN_PAREN arglist
+ CLOSE_PAREN "RESULT" OPEN_PAREN
+
+ return ffestb_decl_funcname_7_; // to lexer
+
+ Make sure the next token is a NAME. */
+
+static ffelexHandler
+ffestb_decl_funcname_7_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[2] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_funcname_8_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_funcname_8_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME [type parameter] OPEN_PAREN arglist
+ CLOSE_PAREN "RESULT" OPEN_PAREN NAME
+
+ return ffestb_decl_funcname_8_; // to lexer
+
+ Make sure the next token is a CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_decl_funcname_8_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_decl_funcname_9_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_funcname_9_ -- "type" [type parameters] [RECURSIVE] FUNCTION
+ NAME [type parameter] OPEN_PAREN arg-list
+ CLOSE_PAREN "RESULT" OPEN_PAREN NAME CLOSE_PAREN
+
+ return ffestb_decl_funcname_9_; // to lexer
+
+ Must have EOS/SEMICOLON here. */
+
+static ffelexHandler
+ffestb_decl_funcname_9_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_R1219 (ffesta_tokens[1], ffestb_subrargs_.name_list.args,
+ ffestb_subrargs_.name_list.close_paren, ffestb_local_.decl.type,
+ ffestb_local_.decl.kind, ffestb_local_.decl.kindt,
+ ffestb_local_.decl.len, ffestb_local_.decl.lent,
+ ffestb_local_.decl.recursive, ffesta_tokens[2]);
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.recursive != NULL)
+ ffelex_token_kill (ffestb_local_.decl.recursive);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffelex_token_kill (ffesta_tokens[2]);
+ ffelex_token_kill (ffestb_subrargs_.name_list.close_paren);
+ ffestt_tokenlist_kill (ffestb_subrargs_.name_list.args);
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "FUNCTION", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V003 -- Parse the STRUCTURE statement
+
+ return ffestb_V003; // to lexer
+
+ Make sure the statement has a valid form for the STRUCTURE statement.
+ If it does, implement the statement. */
+
+#if FFESTR_VXT
+ffelexHandler
+ffestb_V003 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffelexHandler next;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstSTRUCTURE)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V003_start (NULL);
+ ffestb_local_.structure.started = TRUE;
+ return (ffelexHandler) ffestb_V0034_ (t);
+
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ return (ffelexHandler) ffestb_V0031_;
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstSTRUCTURE)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlSTRUCTURE);
+ switch (ffelex_token_type (t))
+ {
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeSLASH:
+ ffesta_confirmed ();
+ if (*p != '\0')
+ goto bad_1; /* :::::::::::::::::::: */
+ return (ffelexHandler) ffestb_V0031_;
+
+ case FFELEX_typeOPEN_PAREN:
+ break;
+ }
+
+ /* Here, we have at least one char after "STRUCTURE" and t is COMMA,
+ EOS/SEMICOLON, or OPEN_PAREN. */
+
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ nt = ffelex_token_name_from_names (ffesta_tokens[0], i, 0);
+ if (ffelex_token_type (t) == FFELEX_typeOPEN_PAREN)
+ ffestb_local_.structure.started = FALSE;
+ else
+ {
+ if (!ffesta_is_inhibited ())
+ ffestc_V003_start (NULL);
+ ffestb_local_.structure.started = TRUE;
+ }
+ next = (ffelexHandler) ffestb_V0034_ (nt);
+ ffelex_token_kill (nt);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "STRUCTURE", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "STRUCTURE", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "STRUCTURE", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0031_ -- "STRUCTURE" SLASH
+
+ return ffestb_V0031_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_V0031_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0032_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "STRUCTURE", t);
+ break;
+ }
+
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0032_ -- "STRUCTURE" SLASH NAME
+
+ return ffestb_V0032_; // to lexer
+
+ Handle SLASH. */
+
+static ffelexHandler
+ffestb_V0032_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeSLASH:
+ if (!ffesta_is_inhibited ())
+ ffestc_V003_start (ffesta_tokens[1]);
+ ffestb_local_.structure.started = TRUE;
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_V0033_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "STRUCTURE", t);
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0033_ -- "STRUCTURE" SLASH NAME SLASH
+
+ return ffestb_V0033_; // to lexer
+
+ Handle NAME or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_V0033_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ return (ffelexHandler) ffestb_V0034_ (t);
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ ffestc_V003_finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "STRUCTURE", t);
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0034_ -- "STRUCTURE" [SLASH NAME SLASH]
+
+ return ffestb_V0034_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_V0034_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0035_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "STRUCTURE", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V003_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0035_ -- "STRUCTURE" ... NAME
+
+ return ffestb_V0035_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_V0035_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_subrargs_.dim_list.dims = ffestt_dimlist_create ();
+ ffestb_subrargs_.dim_list.handler = (ffelexHandler) ffestb_V0036_;
+ ffestb_subrargs_.dim_list.pool = ffesta_output_pool;
+ ffestb_subrargs_.dim_list.ctx = FFEEXPR_contextDIMLISTCOMMON;
+#ifdef FFECOM_dimensionsMAX
+ ffestb_subrargs_.dim_list.ndims = 0;
+#endif
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextDIMLISTCOMMON, (ffeexprCallback) ffestb_subr_dimlist_);
+
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ ffestc_V003_item (ffesta_tokens[1], NULL);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_V0034_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_V003_item (ffesta_tokens[1], NULL);
+ ffestc_V003_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "STRUCTURE", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V003_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0036_ -- "STRUCTURE" ... NAME OPEN_PAREN dimlist CLOSE_PAREN
+
+ return ffestb_V0036_; // to lexer
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_V0036_ (ffelexToken t)
+{
+ if (!ffestb_subrargs_.dim_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.structure.started)
+ {
+ ffestc_V003_start (NULL);
+ ffestb_local_.structure.started = TRUE;
+ }
+ ffestc_V003_item (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffestb_V0034_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ {
+ if (!ffestb_local_.structure.started)
+ ffestc_V003_start (NULL);
+ ffestc_V003_item (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ ffestc_V003_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "STRUCTURE", t);
+ if (ffestb_local_.structure.started && !ffesta_is_inhibited ())
+ ffestc_V003_finish ();
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V016 -- Parse the RECORD statement
+
+ return ffestb_V016; // to lexer
+
+ Make sure the statement has a valid form for the RECORD statement. If it
+ does, implement the statement. */
+
+ffelexHandler
+ffestb_V016 (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstRECORD)
+ goto bad_0; /* :::::::::::::::::::: */
+ break;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstRECORD)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlRECORD);
+ if (*p != '\0')
+ goto bad_i; /* :::::::::::::::::::: */
+ break;
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeSLASH:
+ break;
+ }
+
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V016_start ();
+ return (ffelexHandler) ffestb_V0161_;
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RECORD", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RECORD", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "RECORD", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0161_ -- "RECORD" SLASH
+
+ return ffestb_V0161_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_V0161_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (!ffesta_is_inhibited ())
+ ffestc_V016_item_structure (t);
+ return (ffelexHandler) ffestb_V0162_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RECORD", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V016_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0162_ -- "RECORD" SLASH NAME
+
+ return ffestb_V0162_; // to lexer
+
+ Handle SLASH. */
+
+static ffelexHandler
+ffestb_V0162_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeSLASH:
+ return (ffelexHandler) ffestb_V0163_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RECORD", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V016_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0163_ -- "RECORD" SLASH NAME SLASH
+
+ return ffestb_V0163_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_V0163_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0164_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RECORD", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V016_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0164_ -- "RECORD" ... NAME
+
+ return ffestb_V0164_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_V0164_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_subrargs_.dim_list.dims = ffestt_dimlist_create ();
+ ffestb_subrargs_.dim_list.handler = (ffelexHandler) ffestb_V0165_;
+ ffestb_subrargs_.dim_list.pool = ffesta_output_pool;
+ ffestb_subrargs_.dim_list.ctx = FFEEXPR_contextDIMLISTCOMMON;
+#ifdef FFECOM_dimensionsMAX
+ ffestb_subrargs_.dim_list.ndims = 0;
+#endif
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextDIMLISTCOMMON, (ffeexprCallback) ffestb_subr_dimlist_);
+
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ ffestc_V016_item_object (ffesta_tokens[1], NULL);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_V0166_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_V016_item_object (ffesta_tokens[1], NULL);
+ ffestc_V016_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RECORD", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V016_finish ();
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0165_ -- "RECORD" ... NAME OPEN_PAREN dimlist CLOSE_PAREN
+
+ return ffestb_V0165_; // to lexer
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_V0165_ (ffelexToken t)
+{
+ if (!ffestb_subrargs_.dim_list.ok)
+ goto bad; /* :::::::::::::::::::: */
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (!ffesta_is_inhibited ())
+ ffestc_V016_item_object (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffestb_V0166_;
+
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_V016_item_object (ffesta_tokens[1],
+ ffestb_subrargs_.dim_list.dims);
+ ffestc_V016_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RECORD", t);
+ if (ffestb_local_.structure.started && !ffesta_is_inhibited ())
+ ffestc_V016_finish ();
+ ffestt_dimlist_kill (ffestb_subrargs_.dim_list.dims);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0166_ -- "RECORD" SLASH NAME SLASH NAME [OPEN_PAREN dimlist
+ CLOSE_PAREN] COMMA
+
+ return ffestb_V0166_; // to lexer
+
+ Handle NAME or SLASH. */
+
+static ffelexHandler
+ffestb_V0166_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0164_;
+
+ case FFELEX_typeSLASH:
+ return (ffelexHandler) ffestb_V0161_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "RECORD", t);
+ break;
+ }
+
+ if (!ffesta_is_inhibited ())
+ ffestc_V016_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_V027 -- Parse the VXT PARAMETER statement
+
+ return ffestb_V027; // to lexer
+
+ Make sure the statement has a valid form for the VXT PARAMETER statement.
+ If it does, implement the statement. */
+
+ffelexHandler
+ffestb_V027 (ffelexToken t)
+{
+ char *p;
+ ffeTokenLength i;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstPARAMETER)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ break;
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+ ffesta_confirmed ();
+ ffestb_local_.vxtparam.started = TRUE;
+ if (!ffesta_is_inhibited ())
+ ffestc_V027_start ();
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0271_;
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstPARAMETER)
+ goto bad_0; /* :::::::::::::::::::: */
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlPARAMETER);
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ break;
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+ if (!ffesrc_is_name_init (*p))
+ goto bad_i; /* :::::::::::::::::::: */
+ ffestb_local_.vxtparam.started = FALSE;
+ ffesta_tokens[1] = ffelex_token_name_from_names (ffesta_tokens[0], i,
+ 0);
+ return (ffelexHandler) ffestb_V0271_ (t);
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PARAMETER", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PARAMETER", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+
+bad_i: /* :::::::::::::::::::: */
+ ffesta_ffebad_1sp (FFEBAD_INVALID_STMT_FORM, "PARAMETER", ffesta_tokens[0], i, t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0271_ -- "PARAMETER" NAME
+
+ return ffestb_V0271_; // to lexer
+
+ Handle EQUALS. */
+
+static ffelexHandler
+ffestb_V0271_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEQUALS:
+ return (ffelexHandler) ffeexpr_rhs (ffesta_output_pool,
+ FFEEXPR_contextPARAMETER, (ffeexprCallback) ffestb_V0272_);
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PARAMETER", t);
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.vxtparam.started && !ffesta_is_inhibited ())
+ ffestc_V027_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0272_ -- "PARAMETER" NAME EQUALS expr
+
+ (ffestb_V0272_) // to expression handler
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_V0272_ (ffelexToken ft, ffebld expr, ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffestb_local_.vxtparam.started)
+ {
+ if (ffestc_is_let_not_V027 ())
+ break; /* Not a valid VXTPARAMETER stmt. */
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_V027_start ();
+ ffestb_local_.vxtparam.started = TRUE;
+ }
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ {
+ ffestc_V027_item (ffesta_tokens[1], expr, ft);
+ ffestc_V027_finish ();
+ }
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeCOMMA:
+ ffesta_confirmed ();
+ if (!ffestb_local_.vxtparam.started)
+ {
+ if (!ffesta_is_inhibited ())
+ ffestc_V027_start ();
+ ffestb_local_.vxtparam.started = TRUE;
+ }
+ if (expr == NULL)
+ break;
+ if (!ffesta_is_inhibited ())
+ ffestc_V027_item (ffesta_tokens[1], expr, ft);
+ ffelex_token_kill (ffesta_tokens[1]);
+ return (ffelexHandler) ffestb_V0273_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ if (ffestb_local_.vxtparam.started && !ffesta_is_inhibited ())
+ ffestc_V027_finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PARAMETER", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_V0273_ -- "PARAMETER" NAME EQUALS expr COMMA
+
+ return ffestb_V0273_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_V0273_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_V0271_;
+
+ default:
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "PARAMETER", t);
+ break;
+ }
+
+ if (ffestb_local_.vxtparam.started && !ffesta_is_inhibited ())
+ ffestc_V027_finish ();
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R539 -- Parse the IMPLICIT FUNCTION statement
+
+ return ffestb_decl_R539; // to lexer
+
+ Make sure the statement has a valid form for the IMPLICIT
+ statement. If it does, implement the statement. */
+
+ffelexHandler
+ffestb_decl_R539 (ffelexToken t)
+{
+ ffeTokenLength i;
+ char *p;
+ ffelexToken nt;
+ ffestrSecond kw;
+
+ ffestb_local_.decl.recursive = NULL;
+
+ switch (ffelex_token_type (ffesta_tokens[0]))
+ {
+ case FFELEX_typeNAME:
+ if (ffesta_first_kw != FFESTR_firstIMPLICIT)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ ffesta_confirmed (); /* Error, but clearly intended. */
+ goto bad_1; /* :::::::::::::::::::: */
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+
+ case FFELEX_typeNAME:
+ break;
+ }
+ ffesta_confirmed ();
+ ffestb_local_.decl.imp_started = FALSE;
+ switch (ffesta_second_kw)
+ {
+ case FFESTR_secondINTEGER:
+ ffestb_local_.decl.type = FFESTP_typeINTEGER;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondBYTE:
+ ffestb_local_.decl.type = FFESTP_typeBYTE;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondWORD:
+ ffestb_local_.decl.type = FFESTP_typeWORD;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondREAL:
+ ffestb_local_.decl.type = FFESTP_typeREAL;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondCOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeCOMPLEX;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondLOGICAL:
+ ffestb_local_.decl.type = FFESTP_typeLOGICAL;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondCHARACTER:
+ ffestb_local_.decl.type = FFESTP_typeCHARACTER;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondDOUBLE:
+ return (ffelexHandler) ffestb_decl_R5392_;
+
+ case FFESTR_secondDOUBLEPRECISION:
+ ffestb_local_.decl.type = FFESTP_typeDBLPRCSN;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_R539letters_;
+
+ case FFESTR_secondDOUBLECOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeDBLCMPLX;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_R539letters_;
+
+ case FFESTR_secondNONE:
+ return (ffelexHandler) ffestb_decl_R5394_;
+
+#if FFESTR_F90
+ case FFESTR_secondTYPE:
+ ffestb_local_.decl.type = FFESTP_typeTYPE;
+ return (ffelexHandler) ffestb_decl_R5393_;
+#endif
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ case FFELEX_typeNAMES:
+ if (ffesta_first_kw != FFESTR_firstIMPLICIT)
+ goto bad_0; /* :::::::::::::::::::: */
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeCOLONCOLON:
+ case FFELEX_typeASTERISK:
+ case FFELEX_typeSEMICOLON:
+ case FFELEX_typeEOS:
+ ffesta_confirmed ();
+ break;
+
+ case FFELEX_typeOPEN_PAREN:
+ break;
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+ p = ffelex_token_text (ffesta_tokens[0]) + (i = FFESTR_firstlIMPLICIT);
+ if (!ffesrc_is_name_init (*p))
+ goto bad_0; /* :::::::::::::::::::: */
+ ffestb_local_.decl.imp_started = FALSE;
+ nt = ffelex_token_name_from_names (ffesta_tokens[0],
+ FFESTR_firstlIMPLICIT, 0);
+ kw = ffestr_second (nt);
+ ffelex_token_kill (nt);
+ switch (kw)
+ {
+ case FFESTR_secondINTEGER:
+ ffestb_local_.decl.type = FFESTP_typeINTEGER;
+ return (ffelexHandler) ffestb_decl_R5391_ (t);
+
+ case FFESTR_secondBYTE:
+ ffestb_local_.decl.type = FFESTP_typeBYTE;
+ return (ffelexHandler) ffestb_decl_R5391_ (t);
+
+ case FFESTR_secondWORD:
+ ffestb_local_.decl.type = FFESTP_typeWORD;
+ return (ffelexHandler) ffestb_decl_R5391_ (t);
+
+ case FFESTR_secondREAL:
+ ffestb_local_.decl.type = FFESTP_typeREAL;
+ return (ffelexHandler) ffestb_decl_R5391_ (t);
+
+ case FFESTR_secondCOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeCOMPLEX;
+ return (ffelexHandler) ffestb_decl_R5391_ (t);
+
+ case FFESTR_secondLOGICAL:
+ ffestb_local_.decl.type = FFESTP_typeLOGICAL;
+ return (ffelexHandler) ffestb_decl_R5391_ (t);
+
+ case FFESTR_secondCHARACTER:
+ ffestb_local_.decl.type = FFESTP_typeCHARACTER;
+ return (ffelexHandler) ffestb_decl_R5391_ (t);
+
+ case FFESTR_secondDOUBLEPRECISION:
+ ffestb_local_.decl.type = FFESTP_typeDBLPRCSN;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_R539letters_ (t);
+
+ case FFESTR_secondDOUBLECOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeDBLCMPLX;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_R539letters_ (t);
+
+ case FFESTR_secondNONE:
+ return (ffelexHandler) ffestb_decl_R5394_ (t);
+
+#if FFESTR_F90
+ case FFESTR_secondTYPE:
+ ffestb_local_.decl.type = FFESTP_typeTYPE;
+ return (ffelexHandler) ffestb_decl_R5393_ (t);
+#endif
+
+ default:
+ goto bad_1; /* :::::::::::::::::::: */
+ }
+
+ default:
+ goto bad_0; /* :::::::::::::::::::: */
+ }
+
+bad_0: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", ffesta_tokens[0]);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+
+bad_1: /* :::::::::::::::::::: */
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t,
+ (ffelexHandler) ffesta_zero); /* Invalid second token. */
+}
+
+/* ffestb_decl_R5391_ -- "IMPLICIT" generic-type
+
+ return ffestb_decl_R5391_; // to lexer
+
+ Handle ASTERISK or OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_R5391_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeASTERISK:
+ ffesta_confirmed ();
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_R539letters_;
+ ffestb_local_.decl.badname = "IMPLICIT";
+ if (ffestb_local_.decl.type == FFESTP_typeCHARACTER)
+ return (ffelexHandler) ffestb_decl_starlen_;
+ return (ffelexHandler) ffestb_decl_starkind_;
+
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_R539letters_;
+ ffestb_local_.decl.badname = "IMPLICIT";
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ if (ffestb_local_.decl.type == FFESTP_typeCHARACTER)
+ ffestb_local_.decl.imp_handler
+ = (ffelexHandler) ffestb_decl_typeparams_;
+ else
+ ffestb_local_.decl.imp_handler
+ = (ffelexHandler) ffestb_decl_kindparam_;
+ return (ffelexHandler) ffestb_decl_R539maybe_ (t);
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R5392_ -- "IMPLICIT" "DOUBLE"
+
+ return ffestb_decl_R5392_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_decl_R5392_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ switch (ffestr_second (t))
+ {
+ case FFESTR_secondPRECISION:
+ ffestb_local_.decl.type = FFESTP_typeDBLPRCSN;
+ break;
+
+ case FFESTR_secondCOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeDBLCMPLX;
+ break;
+
+ default:
+ goto bad; /* :::::::::::::::::::: */
+ }
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_R539letters_;
+
+ default:
+ break;
+ }
+
+bad: /* :::::::::::::::::::: */
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R5393_ -- "IMPLICIT" "TYPE"
+
+ return ffestb_decl_R5393_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+#if FFESTR_F90
+static ffelexHandler
+ffestb_decl_R5393_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.decl.handler = (ffelexHandler) ffestb_decl_R539letters_;
+ ffestb_local_.decl.badname = "IMPLICIT";
+ return (ffelexHandler) ffestb_decl_typetype1_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+#endif
+/* ffestb_decl_R5394_ -- "IMPLICIT" "NONE"
+
+ return ffestb_decl_R5394_; // to lexer
+
+ Handle EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_decl_R5394_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R539 (); /* IMPLICIT NONE. */
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R5395_ -- "IMPLICIT" implicit-spec-list COMMA
+
+ return ffestb_decl_R5395_; // to lexer
+
+ Handle NAME for next type-spec. */
+
+static ffelexHandler
+ffestb_decl_R5395_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ switch (ffestr_second (t))
+ {
+ case FFESTR_secondINTEGER:
+ ffestb_local_.decl.type = FFESTP_typeINTEGER;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondBYTE:
+ ffestb_local_.decl.type = FFESTP_typeBYTE;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondWORD:
+ ffestb_local_.decl.type = FFESTP_typeWORD;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondREAL:
+ ffestb_local_.decl.type = FFESTP_typeREAL;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondCOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeCOMPLEX;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondLOGICAL:
+ ffestb_local_.decl.type = FFESTP_typeLOGICAL;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondCHARACTER:
+ ffestb_local_.decl.type = FFESTP_typeCHARACTER;
+ return (ffelexHandler) ffestb_decl_R5391_;
+
+ case FFESTR_secondDOUBLE:
+ return (ffelexHandler) ffestb_decl_R5392_;
+
+ case FFESTR_secondDOUBLEPRECISION:
+ ffestb_local_.decl.type = FFESTP_typeDBLPRCSN;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_R539letters_;
+
+ case FFESTR_secondDOUBLECOMPLEX:
+ ffestb_local_.decl.type = FFESTP_typeDBLCMPLX;
+ ffestb_local_.decl.kind = NULL;
+ ffestb_local_.decl.kindt = NULL;
+ ffestb_local_.decl.len = NULL;
+ ffestb_local_.decl.lent = NULL;
+ return (ffelexHandler) ffestb_decl_R539letters_;
+
+#if FFESTR_F90
+ case FFESTR_secondTYPE:
+ ffestb_local_.decl.type = FFESTP_typeTYPE;
+ return (ffelexHandler) ffestb_decl_R5393_;
+#endif
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R539letters_ -- "IMPLICIT" type-spec
+
+ return ffestb_decl_R539letters_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_R539letters_ (ffelexToken t)
+{
+ ffelex_set_names (FALSE);
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeOPEN_PAREN:
+ ffestb_local_.decl.imps = ffestt_implist_create ();
+ return (ffelexHandler) ffestb_decl_R539letters_1_;
+
+ default:
+ break;
+ }
+
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R539letters_1_ -- "IMPLICIT" type-spec OPEN_PAREN
+
+ return ffestb_decl_R539letters_1_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_decl_R539letters_1_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (ffelex_token_length (t) != 1)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ return (ffelexHandler) ffestb_decl_R539letters_2_;
+
+ default:
+ break;
+ }
+
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R539letters_2_ -- "IMPLICIT" type-spec OPEN_PAREN NAME
+
+ return ffestb_decl_R539letters_2_; // to lexer
+
+ Handle COMMA or MINUS. */
+
+static ffelexHandler
+ffestb_decl_R539letters_2_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffestt_implist_append (ffestb_local_.decl.imps, ffesta_tokens[1], NULL);
+ return (ffelexHandler) ffestb_decl_R539letters_1_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ ffestt_implist_append (ffestb_local_.decl.imps, ffesta_tokens[1], NULL);
+ return (ffelexHandler) ffestb_decl_R539letters_5_;
+
+ case FFELEX_typeMINUS:
+ return (ffelexHandler) ffestb_decl_R539letters_3_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R539letters_3_ -- "IMPLICIT" type-spec OPEN_PAREN NAME MINUS
+
+ return ffestb_decl_R539letters_3_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_decl_R539letters_3_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (ffelex_token_length (t) != 1)
+ break;
+ ffestt_implist_append (ffestb_local_.decl.imps, ffesta_tokens[1],
+ ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_R539letters_4_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R539letters_4_ -- "IMPLICIT" type-spec OPEN_PAREN NAME MINUS
+ NAME
+
+ return ffestb_decl_R539letters_4_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_decl_R539letters_4_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ return (ffelexHandler) ffestb_decl_R539letters_1_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ return (ffelexHandler) ffestb_decl_R539letters_5_;
+
+ default:
+ break;
+ }
+
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R539letters_5_ -- "IMPLICIT" type-spec OPEN_PAREN
+ letter-spec-list CLOSE_PAREN
+
+ return ffestb_decl_R539letters_5_; // to lexer
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_decl_R539letters_5_ (ffelexToken t)
+{
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ if (!ffestb_local_.decl.imp_started)
+ {
+ ffestb_local_.decl.imp_started = TRUE;
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R539start ();
+ }
+ if (!ffesta_is_inhibited ())
+ ffestc_R539item (ffestb_local_.decl.type, ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, ffestb_local_.decl.len,
+ ffestb_local_.decl.lent, ffestb_local_.decl.imps);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_decl_R5395_;
+ if (!ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ default:
+ break;
+ }
+
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
+
+/* ffestb_decl_R539maybe_ -- "IMPLICIT" generic-type-spec
+
+ return ffestb_decl_R539maybe_; // to lexer
+
+ Handle OPEN_PAREN. */
+
+static ffelexHandler
+ffestb_decl_R539maybe_ (ffelexToken t)
+{
+ assert (ffelex_token_type (t) == FFELEX_typeOPEN_PAREN);
+ ffestb_local_.decl.imps = ffestt_implist_create ();
+ ffestb_local_.decl.toklist = ffestt_tokenlist_create ();
+ ffestb_local_.decl.imp_seen_comma
+ = (ffestb_local_.decl.type != FFESTP_typeCHARACTER);
+ return (ffelexHandler) ffestb_decl_R539maybe_1_;
+}
+
+/* ffestb_decl_R539maybe_1_ -- "IMPLICIT" generic-type-spec OPEN_PAREN
+
+ return ffestb_decl_R539maybe_1_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_decl_R539maybe_1_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (ffelex_token_length (t) != 1)
+ break;
+ ffesta_tokens[1] = ffelex_token_use (t);
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_R539maybe_2_;
+
+ default:
+ break;
+ }
+
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ next = (ffelexHandler) ffestt_tokenlist_handle (ffestb_local_.decl.toklist,
+ (ffelexHandler) ffestb_local_.decl.imp_handler);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffestb_decl_R539maybe_2_ -- "IMPLICIT" generic-type-spec OPEN_PAREN NAME
+
+ return ffestb_decl_R539maybe_2_; // to lexer
+
+ Handle COMMA or MINUS. */
+
+static ffelexHandler
+ffestb_decl_R539maybe_2_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ ffestt_implist_append (ffestb_local_.decl.imps, ffesta_tokens[1], NULL);
+ if (ffestb_local_.decl.imp_seen_comma)
+ {
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) ffestb_decl_R539letters_1_;
+ }
+ ffestb_local_.decl.imp_seen_comma = TRUE;
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_R539maybe_1_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ ffestt_implist_append (ffestb_local_.decl.imps, ffesta_tokens[1], NULL);
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_R539maybe_5_;
+
+ case FFELEX_typeMINUS:
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_R539maybe_3_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ next = (ffelexHandler) ffestt_tokenlist_handle (ffestb_local_.decl.toklist,
+ (ffelexHandler) ffestb_local_.decl.imp_handler);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffestb_decl_R539maybe_3_ -- "IMPLICIT" type-spec OPEN_PAREN NAME MINUS
+
+ return ffestb_decl_R539maybe_3_; // to lexer
+
+ Handle NAME. */
+
+static ffelexHandler
+ffestb_decl_R539maybe_3_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeNAME:
+ if (ffelex_token_length (t) != 1)
+ break;
+ ffestt_implist_append (ffestb_local_.decl.imps, ffesta_tokens[1],
+ ffelex_token_use (t));
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_R539maybe_4_;
+
+ default:
+ break;
+ }
+
+ ffelex_token_kill (ffesta_tokens[1]);
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ next = (ffelexHandler) ffestt_tokenlist_handle (ffestb_local_.decl.toklist,
+ (ffelexHandler) ffestb_local_.decl.imp_handler);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffestb_decl_R539maybe_4_ -- "IMPLICIT" type-spec OPEN_PAREN NAME MINUS
+ NAME
+
+ return ffestb_decl_R539maybe_4_; // to lexer
+
+ Handle COMMA or CLOSE_PAREN. */
+
+static ffelexHandler
+ffestb_decl_R539maybe_4_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ if (ffestb_local_.decl.imp_seen_comma)
+ {
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) ffestb_decl_R539letters_1_;
+ }
+ ffestb_local_.decl.imp_seen_comma = TRUE;
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_R539maybe_1_;
+
+ case FFELEX_typeCLOSE_PAREN:
+ ffestt_tokenlist_append (ffestb_local_.decl.toklist, ffelex_token_use (t));
+ return (ffelexHandler) ffestb_decl_R539maybe_5_;
+
+ default:
+ break;
+ }
+
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ next = (ffelexHandler) ffestt_tokenlist_handle (ffestb_local_.decl.toklist,
+ (ffelexHandler) ffestb_local_.decl.imp_handler);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) (*next) (t);
+}
+
+/* ffestb_decl_R539maybe_5_ -- "IMPLICIT" type-spec OPEN_PAREN
+ letter-spec-list CLOSE_PAREN
+
+ return ffestb_decl_R539maybe_5_; // to lexer
+
+ Handle COMMA or EOS/SEMICOLON. */
+
+static ffelexHandler
+ffestb_decl_R539maybe_5_ (ffelexToken t)
+{
+ ffelexHandler next;
+
+ switch (ffelex_token_type (t))
+ {
+ case FFELEX_typeCOMMA:
+ case FFELEX_typeEOS:
+ case FFELEX_typeSEMICOLON:
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ if (!ffestb_local_.decl.imp_started)
+ {
+ ffestb_local_.decl.imp_started = TRUE;
+ ffesta_confirmed ();
+ if (!ffesta_is_inhibited ())
+ ffestc_R539start ();
+ }
+ if (!ffesta_is_inhibited ())
+ ffestc_R539item (ffestb_local_.decl.type, ffestb_local_.decl.kind,
+ ffestb_local_.decl.kindt, ffestb_local_.decl.len,
+ ffestb_local_.decl.lent, ffestb_local_.decl.imps);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ if (ffelex_token_type (t) == FFELEX_typeCOMMA)
+ return (ffelexHandler) ffestb_decl_R5395_;
+ if (!ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ return (ffelexHandler) ffesta_zero (t);
+
+ case FFELEX_typeOPEN_PAREN:
+ ffesta_confirmed ();
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ next = (ffelexHandler) ffestt_tokenlist_handle (ffestb_local_.decl.toklist,
+ (ffelexHandler) ffestb_local_.decl.imp_handler);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ return (ffelexHandler) (*next) (t);
+
+ default:
+ break;
+ }
+
+ ffestt_implist_kill (ffestb_local_.decl.imps);
+ ffestt_tokenlist_kill (ffestb_local_.decl.toklist);
+ if (ffestb_local_.decl.kindt != NULL)
+ ffelex_token_kill (ffestb_local_.decl.kindt);
+ if (ffestb_local_.decl.lent != NULL)
+ ffelex_token_kill (ffestb_local_.decl.lent);
+ if (ffestb_local_.decl.imp_started && !ffesta_is_inhibited ())
+ ffestc_R539finish ();
+ ffesta_ffebad_1st (FFEBAD_INVALID_STMT_FORM, "IMPLICIT", t);
+ return (ffelexHandler) ffelex_swallow_tokens (t, (ffelexHandler) ffesta_zero);
+}
diff --git a/contrib/gcc/f/stb.h b/contrib/gcc/f/stb.h
new file mode 100644
index 0000000..7338bcf
--- /dev/null
+++ b/contrib/gcc/f/stb.h
@@ -0,0 +1,253 @@
+/* stb.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ stb.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_stb
+#define _H_f_stb
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "bad.h"
+#include "expr.h"
+#include "lex.h"
+#include "stp.h"
+#include "str.h"
+
+/* Structure definitions. */
+
+struct _ffestb_args_
+ {
+ struct
+ {
+ char *badname;
+ ffeTokenLength len; /* Length of "ENTRY/FUNCTION/SUBROUTINE". */
+ bool is_subr; /* TRUE if SUBROUTINE or if ENTRY within
+ SUBROUTINE. */
+ }
+ dummy;
+ struct
+ {
+ char *badname;
+ ffeTokenLength len; /* Length of
+ "BACKSPACE/ENDFILE/REWIND/UNLOCK". */
+ }
+ beru;
+ struct
+ {
+ ffeTokenLength len; /* Length of keyword including "END". */
+ ffestrSecond second; /* Second keyword. */
+ }
+ endxyz;
+ struct
+ {
+ ffestrSecond second; /* Second keyword. */
+ }
+ elsexyz;
+ struct
+ {
+ ffeTokenLength len; /* Length of "STOP/PAUSE". */
+ }
+ halt;
+#if FFESTR_F90
+ struct
+ {
+ char *badname;
+ ffeTokenLength len; /* Length of "ALLOCATE/DEALLOCATE". */
+ ffeexprContext ctx; /* Either ALLOCATE or DEALLOCATE. */
+ }
+ heap;
+#endif
+ struct
+ {
+ char *badname;
+ ffeTokenLength len; /* Length of
+ "EXTERNAL/INTENT/INTRINSIC/OPTIONAL/PUBLIC/
+ PRIVATE". */
+ }
+ varlist;
+#if FFESTR_VXT
+ struct
+ {
+ char *badname;
+ ffeTokenLength len; /* Length of "ENCODE/DECODE". */
+ }
+ vxtcode;
+#endif
+#if FFESTR_F90
+ struct
+ {
+ char *badname;
+ ffeTokenLength len; /* Length of "ALLOCATABLE/POINTER/TARGET". */
+ }
+ dimlist;
+#endif
+ struct
+ {
+ char *badname;
+ ffeTokenLength len; /* Length of "DIMENSION/VIRTUAL". */
+ }
+ R524;
+ struct
+ {
+ ffeTokenLength len; /* Length of first keyword. */
+ ffestpType type; /* Type of declaration. */
+ }
+ decl;
+ };
+
+/* Global objects accessed by users of this module. */
+
+extern struct _ffestb_args_ ffestb_args;
+
+/* Declare functions with prototypes. */
+
+ffelexHandler ffestb_beru (ffelexToken t);
+ffelexHandler ffestb_block (ffelexToken t);
+ffelexHandler ffestb_blockdata (ffelexToken t);
+ffelexHandler ffestb_decl_chartype (ffelexToken t);
+ffelexHandler ffestb_construct (ffelexToken t);
+ffelexHandler ffestb_decl_dbltype (ffelexToken t);
+ffelexHandler ffestb_decl_double (ffelexToken t);
+ffelexHandler ffestb_dimlist (ffelexToken t);
+ffelexHandler ffestb_do (ffelexToken t);
+ffelexHandler ffestb_dowhile (ffelexToken t);
+ffelexHandler ffestb_dummy (ffelexToken t);
+ffelexHandler ffestb_else (ffelexToken t);
+ffelexHandler ffestb_elsexyz (ffelexToken t);
+ffelexHandler ffestb_end (ffelexToken t);
+ffelexHandler ffestb_endxyz (ffelexToken t);
+ffelexHandler ffestb_decl_gentype (ffelexToken t);
+ffelexHandler ffestb_goto (ffelexToken t);
+ffelexHandler ffestb_halt (ffelexToken t);
+#if FFESTR_F90
+ffelexHandler ffestb_heap (ffelexToken t);
+#endif
+ffelexHandler ffestb_if (ffelexToken t);
+ffelexHandler ffestb_let (ffelexToken t);
+#if FFESTR_F90
+ffelexHandler ffestb_module (ffelexToken t);
+#endif
+#if FFESTR_F90
+ffelexHandler ffestb_decl_recursive (ffelexToken t);
+#endif
+#if FFESTR_F90
+ffelexHandler ffestb_type (ffelexToken t);
+#endif
+#if FFESTR_F90
+ffelexHandler ffestb_decl_typetype (ffelexToken t);
+#endif
+ffelexHandler ffestb_varlist (ffelexToken t);
+#if FFESTR_VXT
+ffelexHandler ffestb_vxtcode (ffelexToken t);
+#endif
+#if FFESTR_F90
+ffelexHandler ffestb_where (ffelexToken t);
+#endif
+#if HARD_F90
+ffelexHandler ffestb_R423B (ffelexToken t);
+#endif
+ffelexHandler ffestb_R522 (ffelexToken t);
+ffelexHandler ffestb_R524 (ffelexToken t);
+ffelexHandler ffestb_R528 (ffelexToken t);
+ffelexHandler ffestb_R537 (ffelexToken t);
+ffelexHandler ffestb_decl_R539 (ffelexToken t);
+ffelexHandler ffestb_R542 (ffelexToken t);
+ffelexHandler ffestb_R544 (ffelexToken t);
+ffelexHandler ffestb_R547 (ffelexToken t);
+#if FFESTR_F90
+ffelexHandler ffestb_R624 (ffelexToken t);
+#endif
+ffelexHandler ffestb_R809 (ffelexToken t);
+ffelexHandler ffestb_R810 (ffelexToken t);
+ffelexHandler ffestb_R834 (ffelexToken t);
+ffelexHandler ffestb_R835 (ffelexToken t);
+ffelexHandler ffestb_R838 (ffelexToken t);
+ffelexHandler ffestb_R840 (ffelexToken t);
+ffelexHandler ffestb_R841 (ffelexToken t);
+ffelexHandler ffestb_R904 (ffelexToken t);
+ffelexHandler ffestb_R907 (ffelexToken t);
+ffelexHandler ffestb_R909 (ffelexToken t);
+ffelexHandler ffestb_R910 (ffelexToken t);
+ffelexHandler ffestb_R911 (ffelexToken t);
+ffelexHandler ffestb_R923 (ffelexToken t);
+ffelexHandler ffestb_R1001 (ffelexToken t);
+ffelexHandler ffestb_R1102 (ffelexToken t);
+#if FFESTR_F90
+ffelexHandler ffestb_R1107 (ffelexToken t);
+#endif
+#if FFESTR_F90
+ffelexHandler ffestb_R1202 (ffelexToken t);
+#endif
+ffelexHandler ffestb_R1212 (ffelexToken t);
+ffelexHandler ffestb_R1227 (ffelexToken t);
+#if FFESTR_F90
+ffelexHandler ffestb_R1228 (ffelexToken t);
+#endif
+ffelexHandler ffestb_R1229 (ffelexToken t);
+ffelexHandler ffestb_S3P4 (ffelexToken t);
+#if FFESTR_VXT
+ffelexHandler ffestb_V003 (ffelexToken t);
+ffelexHandler ffestb_V009 (ffelexToken t);
+ffelexHandler ffestb_V012 (ffelexToken t);
+#endif
+ffelexHandler ffestb_V014 (ffelexToken t);
+#if FFESTR_VXT
+ffelexHandler ffestb_V016 (ffelexToken t);
+ffelexHandler ffestb_V018 (ffelexToken t);
+ffelexHandler ffestb_V019 (ffelexToken t);
+#endif
+ffelexHandler ffestb_V020 (ffelexToken t);
+#if FFESTR_VXT
+ffelexHandler ffestb_V021 (ffelexToken t);
+ffelexHandler ffestb_V025 (ffelexToken t);
+ffelexHandler ffestb_V026 (ffelexToken t);
+#endif
+ffelexHandler ffestb_V027 (ffelexToken t);
+
+/* Define macros. */
+
+#define ffestb_init_0()
+#define ffestb_init_1()
+#define ffestb_init_2()
+#define ffestb_init_3()
+#define ffestb_init_4()
+#define ffestb_terminate_0()
+#define ffestb_terminate_1()
+#define ffestb_terminate_2()
+#define ffestb_terminate_3()
+#define ffestb_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/stc.c b/contrib/gcc/f/stc.c
new file mode 100644
index 0000000..e720f9d
--- /dev/null
+++ b/contrib/gcc/f/stc.c
@@ -0,0 +1,13898 @@
+/* stc.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ st.c
+
+ Description:
+ Verifies the proper semantics for statements, checking expressions already
+ semantically analyzed individually, collectively, checking label defs and
+ refs, and so on. Uses ffebad to indicate errors in semantics.
+
+ In many cases, both a token and a keyword (ffestrFirst, ffestrSecond,
+ or ffestrOther) is provided. ONLY USE THE TOKEN as a pointer to the
+ source-code location for an error message or similar; use the keyword
+ as the semantic matching for the token, since the token's text might
+ not match the keyword's code. For example, INTENT(IN OUT) A in free
+ source form passes to ffestc_R519_start the token "IN" but the keyword
+ FFESTR_otherINOUT, and the latter is correct.
+
+ Generally, either a single ffestc function handles an entire statement,
+ in which case its name is ffestc_xyz_, or more than one function is
+ needed, in which case its names are ffestc_xyz_start_,
+ ffestc_xyz_item_ or ffestc_xyz_item_abc_, and ffestc_xyz_finish_.
+ The caller must call _start_ before calling any _item_ functions, and
+ must call _finish_ afterwards. If it is clearly a syntactic matter as
+ to restrictions on the number and variety of _item_ calls, then the caller
+ should report any errors and ffestc_ should presume it has been taken
+ care of and handle any semantic problems with grace and no error messages.
+ If the permitted number and variety of _item_ calls has some basis in
+ semantics, then the caller should not generate any messages and ffestc
+ should do all the checking.
+
+ A few ffestc functions have names rather than grammar numbers, like
+ ffestc_elsewhere and ffestc_end. These are cases where the actual
+ statement depends on its context rather than just its form; ELSE WHERE
+ may be the obvious (WHERE...ELSE WHERE...END WHERE) or something a little
+ more subtle (WHERE: IF THEN...ELSE WHERE...END IF WHERE). The actual
+ ffestc functions do exist and do work, but may or may not be invoked
+ by ffestb depending on whether some form of resolution is possible.
+ For example, ffestc_R1103 end-program-stmt is reachable directly when
+ END PROGRAM [name] is specified, or via ffestc_end when END is specified
+ and the context is a main program. So ffestc_xyz_ should make a quick
+ determination of the context and pick the appropriate ffestc_Nxyz_
+ function to invoke, without a lot of ceremony.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "stc.h"
+#include "bad.h"
+#include "bld.h"
+#include "data.h"
+#include "expr.h"
+#include "global.h"
+#include "implic.h"
+#include "lex.h"
+#include "malloc.h"
+#include "src.h"
+#include "sta.h"
+#include "std.h"
+#include "stp.h"
+#include "str.h"
+#include "stt.h"
+#include "stw.h"
+
+/* Externals defined here. */
+
+ffeexprContext ffestc_iolist_context_ = FFEEXPR_contextIOLIST;
+/* Valid only from READ/WRITE start to finish. */
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFESTC_orderOK_, /* Statement ok in this context, process. */
+ FFESTC_orderBAD_, /* Statement not ok in this context, don't
+ process. */
+ FFESTC_orderBADOK_, /* Don't process but push block if
+ applicable. */
+ FFESTC
+ } ffestcOrder_;
+
+typedef enum
+ {
+ FFESTC_stateletSIMPLE_, /* Expecting simple/start. */
+ FFESTC_stateletATTRIB_, /* Expecting attrib/item/itemstart. */
+ FFESTC_stateletITEM_, /* Expecting item/itemstart/finish. */
+ FFESTC_stateletITEMVALS_, /* Expecting itemvalue/itemendvals. */
+ FFESTC_
+ } ffestcStatelet_;
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+union ffestc_local_u_
+ {
+ struct
+ {
+ ffebld initlist; /* For list of one sym in INTEGER I/3/ case. */
+ ffetargetCharacterSize stmt_size;
+ ffetargetCharacterSize size;
+ ffeinfoBasictype basic_type;
+ ffeinfoKindtype stmt_kind_type;
+ ffeinfoKindtype kind_type;
+ bool per_var_kind_ok;
+ char is_R426; /* 1=R426, 2=R501. */
+ }
+ decl;
+ struct
+ {
+ ffebld objlist; /* For list of target objects. */
+ ffebldListBottom list_bottom; /* For building lists. */
+ }
+ data;
+ struct
+ {
+ ffebldListBottom list_bottom; /* For building lists. */
+ int entry_num;
+ }
+ dummy;
+ struct
+ {
+ ffesymbol symbol; /* NML symbol. */
+ }
+ namelist;
+ struct
+ {
+ ffelexToken t; /* First token in list. */
+ ffeequiv eq; /* Current equivalence being built up. */
+ ffebld list; /* List of expressions in equivalence. */
+ ffebldListBottom bottom;
+ bool ok; /* TRUE while current list still being
+ processed. */
+ bool save; /* TRUE if any var in list is SAVEd. */
+ }
+ equiv;
+ struct
+ {
+ ffesymbol symbol; /* BCB/NCB symbol. */
+ }
+ common;
+ struct
+ {
+ ffesymbol symbol; /* SFN symbol. */
+ }
+ sfunc;
+#if FFESTR_VXT
+ struct
+ {
+ char list_state; /* 0=>no field names allowed, 1=>error
+ reported already, 2=>field names req'd,
+ 3=>have a field name. */
+ }
+ V003;
+#endif
+ }; /* Merge with the one in ffestc later. */
+
+/* Static objects accessed by functions in this module. */
+
+static bool ffestc_ok_; /* _start_ fn's send this to _xyz_ fn's. */
+static bool ffestc_parent_ok_; /* Parent sym for baby sym fn's ok. */
+static char ffestc_namelist_; /* 0=>not namelist, 1=>namelist, 2=>error. */
+static union ffestc_local_u_ ffestc_local_;
+static ffestcStatelet_ ffestc_statelet_ = FFESTC_stateletSIMPLE_;
+static ffestwShriek ffestc_shriek_after1_ = NULL;
+static unsigned long ffestc_blocknum_ = 0; /* Next block# to assign. */
+static int ffestc_entry_num_;
+static int ffestc_sfdummy_argno_;
+static int ffestc_saved_entry_num_;
+static ffelab ffestc_label_;
+
+/* Static functions (internal). */
+
+static void ffestc_R544_equiv_ (ffebld expr, ffelexToken t);
+static void ffestc_establish_declinfo_ (ffebld kind, ffelexToken kindt,
+ ffebld len, ffelexToken lent);
+static void ffestc_establish_declstmt_ (ffestpType type, ffelexToken typet,
+ ffebld kind, ffelexToken kindt,
+ ffebld len, ffelexToken lent);
+static void ffestc_establish_impletter_ (ffelexToken first, ffelexToken last);
+static ffeinfoKindtype ffestc_kindtype_kind_ (ffeinfoBasictype bt,
+ ffetargetCharacterSize val);
+static ffeinfoKindtype ffestc_kindtype_star_ (ffeinfoBasictype bt,
+ ffetargetCharacterSize val);
+static void ffestc_labeldef_any_ (void);
+static bool ffestc_labeldef_begin_ (void);
+static void ffestc_labeldef_branch_begin_ (void);
+static void ffestc_labeldef_branch_end_ (void);
+static void ffestc_labeldef_endif_ (void);
+static void ffestc_labeldef_format_ (void);
+static void ffestc_labeldef_invalid_ (void);
+static void ffestc_labeldef_notloop_ (void);
+static void ffestc_labeldef_notloop_begin_ (void);
+static void ffestc_labeldef_useless_ (void);
+static bool ffestc_labelref_is_assignable_ (ffelexToken label_token,
+ ffelab *label);
+static bool ffestc_labelref_is_branch_ (ffelexToken label_token,
+ ffelab *label);
+static bool ffestc_labelref_is_format_ (ffelexToken label_token,
+ ffelab *label);
+static bool ffestc_labelref_is_loopend_ (ffelexToken label_token,
+ ffelab *label);
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_access_ (void);
+#endif
+static ffestcOrder_ ffestc_order_actiondo_ (void);
+static ffestcOrder_ ffestc_order_actionif_ (void);
+static ffestcOrder_ ffestc_order_actionwhere_ (void);
+static void ffestc_order_any_ (void);
+static void ffestc_order_bad_ (void);
+static ffestcOrder_ ffestc_order_blockdata_ (void);
+static ffestcOrder_ ffestc_order_blockspec_ (void);
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_component_ (void);
+#endif
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_contains_ (void);
+#endif
+static ffestcOrder_ ffestc_order_data_ (void);
+static ffestcOrder_ ffestc_order_data77_ (void);
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_derivedtype_ (void);
+#endif
+static ffestcOrder_ ffestc_order_do_ (void);
+static ffestcOrder_ ffestc_order_entry_ (void);
+static ffestcOrder_ ffestc_order_exec_ (void);
+static ffestcOrder_ ffestc_order_format_ (void);
+static ffestcOrder_ ffestc_order_function_ (void);
+static ffestcOrder_ ffestc_order_iface_ (void);
+static ffestcOrder_ ffestc_order_ifthen_ (void);
+static ffestcOrder_ ffestc_order_implicit_ (void);
+static ffestcOrder_ ffestc_order_implicitnone_ (void);
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_interface_ (void);
+#endif
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_map_ (void);
+#endif
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_module_ (void);
+#endif
+static ffestcOrder_ ffestc_order_parameter_ (void);
+static ffestcOrder_ ffestc_order_program_ (void);
+static ffestcOrder_ ffestc_order_progspec_ (void);
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_record_ (void);
+#endif
+static ffestcOrder_ ffestc_order_selectcase_ (void);
+static ffestcOrder_ ffestc_order_sfunc_ (void);
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_spec_ (void);
+#endif
+#if FFESTR_VXT
+static ffestcOrder_ ffestc_order_structure_ (void);
+#endif
+static ffestcOrder_ ffestc_order_subroutine_ (void);
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_type_ (void);
+#endif
+static ffestcOrder_ ffestc_order_typedecl_ (void);
+#if FFESTR_VXT
+static ffestcOrder_ ffestc_order_union_ (void);
+#endif
+static ffestcOrder_ ffestc_order_unit_ (void);
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_use_ (void);
+#endif
+#if FFESTR_VXT
+static ffestcOrder_ ffestc_order_vxtstructure_ (void);
+#endif
+#if FFESTR_F90
+static ffestcOrder_ ffestc_order_where_ (void);
+#endif
+static void ffestc_promote_dummy_ (ffelexToken t);
+static void ffestc_promote_execdummy_ (ffelexToken t);
+static void ffestc_promote_sfdummy_ (ffelexToken t);
+static void ffestc_shriek_begin_program_ (void);
+#if FFESTR_F90
+static void ffestc_shriek_begin_uses_ (void);
+#endif
+static void ffestc_shriek_blockdata_ (bool ok);
+static void ffestc_shriek_do_ (bool ok);
+static void ffestc_shriek_end_program_ (bool ok);
+#if FFESTR_F90
+static void ffestc_shriek_end_uses_ (bool ok);
+#endif
+static void ffestc_shriek_function_ (bool ok);
+static void ffestc_shriek_if_ (bool ok);
+static void ffestc_shriek_ifthen_ (bool ok);
+#if FFESTR_F90
+static void ffestc_shriek_interface_ (bool ok);
+#endif
+#if FFESTR_F90
+static void ffestc_shriek_map_ (bool ok);
+#endif
+#if FFESTR_F90
+static void ffestc_shriek_module_ (bool ok);
+#endif
+static void ffestc_shriek_select_ (bool ok);
+#if FFESTR_VXT
+static void ffestc_shriek_structure_ (bool ok);
+#endif
+static void ffestc_shriek_subroutine_ (bool ok);
+#if FFESTR_F90
+static void ffestc_shriek_type_ (bool ok);
+#endif
+#if FFESTR_VXT
+static void ffestc_shriek_union_ (bool ok);
+#endif
+#if FFESTR_F90
+static void ffestc_shriek_where_ (bool ok);
+#endif
+#if FFESTR_F90
+static void ffestc_shriek_wherethen_ (bool ok);
+#endif
+static int ffestc_subr_binsrch_ (char **list, int size, ffestpFile *spec,
+ char *whine);
+static ffestvFormat ffestc_subr_format_ (ffestpFile *spec);
+static bool ffestc_subr_is_branch_ (ffestpFile *spec);
+static bool ffestc_subr_is_format_ (ffestpFile *spec);
+static bool ffestc_subr_is_present_ (char *name, ffestpFile *spec);
+static int ffestc_subr_speccmp_ (char *string, ffestpFile *spec,
+ char **target, int *length);
+static ffestvUnit ffestc_subr_unit_ (ffestpFile *spec);
+static void ffestc_try_shriek_do_ (void);
+
+/* Internal macros. */
+
+#define ffestc_check_simple_() \
+ assert(ffestc_statelet_ == FFESTC_stateletSIMPLE_)
+#define ffestc_check_start_() \
+ assert(ffestc_statelet_ == FFESTC_stateletSIMPLE_); \
+ ffestc_statelet_ = FFESTC_stateletATTRIB_
+#define ffestc_check_attrib_() \
+ assert(ffestc_statelet_ == FFESTC_stateletATTRIB_)
+#define ffestc_check_item_() \
+ assert(ffestc_statelet_ == FFESTC_stateletATTRIB_ \
+ || ffestc_statelet_ == FFESTC_stateletITEM_); \
+ ffestc_statelet_ = FFESTC_stateletITEM_
+#define ffestc_check_item_startvals_() \
+ assert(ffestc_statelet_ == FFESTC_stateletATTRIB_ \
+ || ffestc_statelet_ == FFESTC_stateletITEM_); \
+ ffestc_statelet_ = FFESTC_stateletITEMVALS_
+#define ffestc_check_item_value_() \
+ assert(ffestc_statelet_ == FFESTC_stateletITEMVALS_)
+#define ffestc_check_item_endvals_() \
+ assert(ffestc_statelet_ == FFESTC_stateletITEMVALS_); \
+ ffestc_statelet_ = FFESTC_stateletITEM_
+#define ffestc_check_finish_() \
+ assert(ffestc_statelet_ == FFESTC_stateletATTRIB_ \
+ || ffestc_statelet_ == FFESTC_stateletITEM_); \
+ ffestc_statelet_ = FFESTC_stateletSIMPLE_
+#define ffestc_order_action_() ffestc_order_exec_()
+#if FFESTR_F90
+#define ffestc_order_interfacespec_() ffestc_order_derivedtype_()
+#endif
+#define ffestc_shriek_if_lost_ ffestc_shriek_if_
+#if FFESTR_F90
+#define ffestc_shriek_where_lost_ ffestc_shriek_where_
+#endif
+
+/* ffestc_establish_declinfo_ -- Determine specific type/params info for entity
+
+ ffestc_establish_declinfo_(kind,kind_token,len,len_token);
+
+ Must be called after _declstmt_ called to establish base type. */
+
+static void
+ffestc_establish_declinfo_ (ffebld kind, ffelexToken kindt, ffebld len,
+ ffelexToken lent)
+{
+ ffeinfoBasictype bt = ffestc_local_.decl.basic_type;
+ ffeinfoKindtype kt;
+ ffetargetCharacterSize val;
+
+ if (kindt == NULL)
+ kt = ffestc_local_.decl.stmt_kind_type;
+ else if (!ffestc_local_.decl.per_var_kind_ok)
+ {
+ ffebad_start (FFEBAD_KINDTYPE);
+ ffebad_here (0, ffelex_token_where_line (kindt),
+ ffelex_token_where_column (kindt));
+ ffebad_here (1, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ kt = ffestc_local_.decl.stmt_kind_type;
+ }
+ else
+ {
+ if (kind == NULL)
+ {
+ assert (ffelex_token_type (kindt) == FFELEX_typeNUMBER);
+ val = atol (ffelex_token_text (kindt));
+ kt = ffestc_kindtype_star_ (bt, val);
+ }
+ else if (ffebld_op (kind) == FFEBLD_opANY)
+ kt = ffestc_local_.decl.stmt_kind_type;
+ else
+ {
+ assert (ffebld_op (kind) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (kind))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (kind))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ val = ffebld_constant_integerdefault (ffebld_conter (kind));
+ kt = ffestc_kindtype_kind_ (bt, val);
+ }
+
+ if (kt == FFEINFO_kindtypeNONE)
+ { /* Not valid kind type. */
+ ffebad_start (FFEBAD_KINDTYPE);
+ ffebad_here (0, ffelex_token_where_line (kindt),
+ ffelex_token_where_column (kindt));
+ ffebad_here (1, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ kt = ffestc_local_.decl.stmt_kind_type;
+ }
+ }
+
+ ffestc_local_.decl.kind_type = kt;
+
+ /* Now check length specification for CHARACTER data type. */
+
+ if (((len == NULL) && (lent == NULL))
+ || (bt != FFEINFO_basictypeCHARACTER))
+ val = ffestc_local_.decl.stmt_size;
+ else
+ {
+ if (len == NULL)
+ {
+ assert (ffelex_token_type (lent) == FFELEX_typeNUMBER);
+ val = atol (ffelex_token_text (lent));
+ }
+ else if (ffebld_op (len) == FFEBLD_opSTAR)
+ val = FFETARGET_charactersizeNONE;
+ else if (ffebld_op (len) == FFEBLD_opANY)
+ val = FFETARGET_charactersizeNONE;
+ else
+ {
+ assert (ffebld_op (len) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (len))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (len))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ val = ffebld_constant_integerdefault (ffebld_conter (len));
+ }
+ }
+
+ if ((val == 0) && !(0 && ffe_is_90 ()))
+ {
+ val = 1;
+ ffebad_start (FFEBAD_ZERO_SIZE);
+ ffebad_here (0, ffelex_token_where_line (lent), ffelex_token_where_column (lent));
+ ffebad_finish ();
+ }
+ ffestc_local_.decl.size = val;
+}
+
+/* ffestc_establish_declstmt_ -- Establish host-specific type/params info
+
+ ffestc_establish_declstmt_(type,type_token,kind,kind_token,len,
+ len_token); */
+
+static void
+ffestc_establish_declstmt_ (ffestpType type, ffelexToken typet, ffebld kind,
+ ffelexToken kindt, ffebld len, ffelexToken lent)
+{
+ ffeinfoBasictype bt;
+ ffeinfoKindtype ktd; /* Default kindtype. */
+ ffeinfoKindtype kt;
+ ffetargetCharacterSize val;
+ bool per_var_kind_ok = TRUE;
+
+ /* Determine basictype and default kindtype. */
+
+ switch (type)
+ {
+ case FFESTP_typeINTEGER:
+ bt = FFEINFO_basictypeINTEGER;
+ ktd = FFEINFO_kindtypeINTEGERDEFAULT;
+ break;
+
+ case FFESTP_typeBYTE:
+ bt = FFEINFO_basictypeINTEGER;
+ ktd = FFEINFO_kindtypeINTEGER2;
+ break;
+
+ case FFESTP_typeWORD:
+ bt = FFEINFO_basictypeINTEGER;
+ ktd = FFEINFO_kindtypeINTEGER3;
+ break;
+
+ case FFESTP_typeREAL:
+ bt = FFEINFO_basictypeREAL;
+ ktd = FFEINFO_kindtypeREALDEFAULT;
+ break;
+
+ case FFESTP_typeCOMPLEX:
+ bt = FFEINFO_basictypeCOMPLEX;
+ ktd = FFEINFO_kindtypeREALDEFAULT;
+ break;
+
+ case FFESTP_typeLOGICAL:
+ bt = FFEINFO_basictypeLOGICAL;
+ ktd = FFEINFO_kindtypeLOGICALDEFAULT;
+ break;
+
+ case FFESTP_typeCHARACTER:
+ bt = FFEINFO_basictypeCHARACTER;
+ ktd = FFEINFO_kindtypeCHARACTERDEFAULT;
+ break;
+
+ case FFESTP_typeDBLPRCSN:
+ bt = FFEINFO_basictypeREAL;
+ ktd = FFEINFO_kindtypeREALDOUBLE;
+ per_var_kind_ok = FALSE;
+ break;
+
+ case FFESTP_typeDBLCMPLX:
+ bt = FFEINFO_basictypeCOMPLEX;
+#if FFETARGET_okCOMPLEX2
+ ktd = FFEINFO_kindtypeREALDOUBLE;
+#else
+ ktd = FFEINFO_kindtypeREALDEFAULT;
+ ffebad_start (FFEBAD_BAD_DBLCMPLX);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+#endif
+ per_var_kind_ok = FALSE;
+ break;
+
+ default:
+ assert ("Unexpected type (F90 TYPE?)!" == NULL);
+ bt = FFEINFO_basictypeNONE;
+ ktd = FFEINFO_kindtypeNONE;
+ break;
+ }
+
+ if (kindt == NULL)
+ kt = ktd;
+ else
+ { /* Not necessarily default kind type. */
+ if (kind == NULL)
+ { /* Shouldn't happen for CHARACTER. */
+ assert (ffelex_token_type (kindt) == FFELEX_typeNUMBER);
+ val = atol (ffelex_token_text (kindt));
+ kt = ffestc_kindtype_star_ (bt, val);
+ }
+ else if (ffebld_op (kind) == FFEBLD_opANY)
+ kt = ktd;
+ else
+ {
+ assert (ffebld_op (kind) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (kind))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (kind))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ val = ffebld_constant_integerdefault (ffebld_conter (kind));
+ kt = ffestc_kindtype_kind_ (bt, val);
+ }
+
+ if (kt == FFEINFO_kindtypeNONE)
+ { /* Not valid kind type. */
+ ffebad_start (FFEBAD_KINDTYPE);
+ ffebad_here (0, ffelex_token_where_line (kindt),
+ ffelex_token_where_column (kindt));
+ ffebad_here (1, ffelex_token_where_line (typet),
+ ffelex_token_where_column (typet));
+ ffebad_finish ();
+ kt = ktd;
+ }
+ }
+
+ ffestc_local_.decl.basic_type = bt;
+ ffestc_local_.decl.stmt_kind_type = kt;
+ ffestc_local_.decl.per_var_kind_ok = per_var_kind_ok;
+
+ /* Now check length specification for CHARACTER data type. */
+
+ if (((len == NULL) && (lent == NULL))
+ || (type != FFESTP_typeCHARACTER))
+ val = (type == FFESTP_typeCHARACTER) ? 1 : FFETARGET_charactersizeNONE;
+ else
+ {
+ if (len == NULL)
+ {
+ assert (ffelex_token_type (lent) == FFELEX_typeNUMBER);
+ val = atol (ffelex_token_text (lent));
+ }
+ else if (ffebld_op (len) == FFEBLD_opSTAR)
+ val = FFETARGET_charactersizeNONE;
+ else if (ffebld_op (len) == FFEBLD_opANY)
+ val = FFETARGET_charactersizeNONE;
+ else
+ {
+ assert (ffebld_op (len) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (len))
+ == FFEINFO_basictypeINTEGER);
+ assert (ffeinfo_kindtype (ffebld_info (len))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ val = ffebld_constant_integerdefault (ffebld_conter (len));
+ }
+ }
+
+ if ((val == 0) && !(0 && ffe_is_90 ()))
+ {
+ val = 1;
+ ffebad_start (FFEBAD_ZERO_SIZE);
+ ffebad_here (0, ffelex_token_where_line (lent), ffelex_token_where_column (lent));
+ ffebad_finish ();
+ }
+ ffestc_local_.decl.stmt_size = val;
+}
+
+/* ffestc_establish_impletter_ -- Establish type/params for IMPLICIT letter(s)
+
+ ffestc_establish_impletter_(first_letter_token,last_letter_token); */
+
+static void
+ffestc_establish_impletter_ (ffelexToken first, ffelexToken last)
+{
+ bool ok = FALSE; /* Stays FALSE if first letter > last. */
+ char c;
+
+ if (last == NULL)
+ ok = ffeimplic_establish_initial (c = *(ffelex_token_text (first)),
+ ffestc_local_.decl.basic_type,
+ ffestc_local_.decl.kind_type,
+ ffestc_local_.decl.size);
+ else
+ {
+ for (c = *(ffelex_token_text (first));
+ c <= *(ffelex_token_text (last));
+ c++)
+ {
+ ok = ffeimplic_establish_initial (c,
+ ffestc_local_.decl.basic_type,
+ ffestc_local_.decl.kind_type,
+ ffestc_local_.decl.size);
+ if (!ok)
+ break;
+ }
+ }
+
+ if (!ok)
+ {
+ char cs[2];
+
+ cs[0] = c;
+ cs[1] = '\0';
+
+ ffebad_start (FFEBAD_BAD_IMPLICIT);
+ ffebad_here (0, ffelex_token_where_line (first), ffelex_token_where_column (first));
+ ffebad_string (cs);
+ ffebad_finish ();
+ }
+}
+
+/* ffestc_init_3 -- Initialize ffestc for new program unit
+
+ ffestc_init_3(); */
+
+void
+ffestc_init_3 ()
+{
+ ffestv_save_state_ = FFESTV_savestateNONE;
+ ffestc_entry_num_ = 0;
+ ffestv_num_label_defines_ = 0;
+}
+
+/* ffestc_init_4 -- Initialize ffestc for new scoping unit
+
+ ffestc_init_4();
+
+ For SUBROUTINEs/FUNCTIONs within INTERFACE/END INTERFACE, derived-TYPE-
+ defs, and statement function defs. */
+
+void
+ffestc_init_4 ()
+{
+ ffestc_saved_entry_num_ = ffestc_entry_num_;
+ ffestc_entry_num_ = 0;
+}
+
+/* ffestc_kindtype_kind_ -- Determine kindtype from basictype and KIND= value
+
+ ffeinfoKindtype kt;
+ ffeinfoBasictype bt;
+ ffetargetCharacterSize val;
+ kt = ffestc_kindtype_kind_(bt,val);
+ if (kt == FFEINFO_kindtypeNONE)
+ // unsupported/invalid KIND= value for type */
+
+static ffeinfoKindtype
+ffestc_kindtype_kind_ (ffeinfoBasictype bt, ffetargetCharacterSize val)
+{
+ ffetype type;
+ ffetype base_type;
+ ffeinfoKindtype kt;
+
+ base_type = ffeinfo_type (bt, 1); /* ~~ */
+ assert (base_type != NULL);
+
+ type = ffetype_lookup_kind (base_type, (int) val);
+ if (type == NULL)
+ return FFEINFO_kindtypeNONE;
+
+ for (kt = 1; kt < FFEINFO_kindtype; ++kt)
+ if (ffeinfo_type (bt, kt) == type)
+ return kt;
+
+ return FFEINFO_kindtypeNONE;
+}
+
+/* ffestc_kindtype_star_ -- Determine kindtype from basictype and * value
+
+ ffeinfoKindtype kt;
+ ffeinfoBasictype bt;
+ ffetargetCharacterSize val;
+ kt = ffestc_kindtype_star_(bt,val);
+ if (kt == FFEINFO_kindtypeNONE)
+ // unsupported/invalid * value for type */
+
+static ffeinfoKindtype
+ffestc_kindtype_star_ (ffeinfoBasictype bt, ffetargetCharacterSize val)
+{
+ ffetype type;
+ ffetype base_type;
+ ffeinfoKindtype kt;
+
+ base_type = ffeinfo_type (bt, 1); /* ~~ */
+ assert (base_type != NULL);
+
+ type = ffetype_lookup_star (base_type, (int) val);
+ if (type == NULL)
+ return FFEINFO_kindtypeNONE;
+
+ for (kt = 1; kt < FFEINFO_kindtype; ++kt)
+ if (ffeinfo_type (bt, kt) == type)
+ return kt;
+
+ return FFEINFO_kindtypeNONE;
+}
+
+/* Define label as usable for anything without complaint. */
+
+static void
+ffestc_labeldef_any_ ()
+{
+ if ((ffesta_label_token == NULL)
+ || !ffestc_labeldef_begin_ ())
+ return;
+
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_labeldef_begin_ -- Define label as unknown, initially
+
+ ffestc_labeldef_begin_(); */
+
+static bool
+ffestc_labeldef_begin_ ()
+{
+ ffelabValue label_value;
+ ffelab label;
+
+ label_value = (ffelabValue) atol (ffelex_token_text (ffesta_label_token));
+ if ((label_value == 0) || (label_value > FFELAB_valueMAX))
+ {
+ ffebad_start (FFEBAD_LABEL_NUMBER_INVALID);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_finish ();
+ }
+
+ label = ffelab_find (label_value);
+ if (label == NULL)
+ {
+ label = ffestc_label_ = ffelab_new (label_value);
+ ffestv_num_label_defines_++;
+ ffelab_set_definition_line (label,
+ ffewhere_line_use (ffelex_token_where_line (ffesta_label_token)));
+ ffelab_set_definition_column (label,
+ ffewhere_column_use (ffelex_token_where_column (ffesta_label_token)));
+
+ return TRUE;
+ }
+
+ if (ffewhere_line_is_unknown (ffelab_definition_line (label)))
+ {
+ ffestv_num_label_defines_++;
+ ffestc_label_ = label;
+ ffelab_set_definition_line (label,
+ ffewhere_line_use (ffelex_token_where_line (ffesta_label_token)));
+ ffelab_set_definition_column (label,
+ ffewhere_column_use (ffelex_token_where_column (ffesta_label_token)));
+
+ return TRUE;
+ }
+
+ ffebad_start (FFEBAD_LABEL_ALREADY_DEFINED);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_definition_line (label),
+ ffelab_definition_column (label));
+ ffebad_string (ffelex_token_text (ffesta_label_token));
+ ffebad_finish ();
+
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+ return FALSE;
+}
+
+/* ffestc_labeldef_branch_begin_ -- Define label as a branch target one
+
+ ffestc_labeldef_branch_begin_(); */
+
+static void
+ffestc_labeldef_branch_begin_ ()
+{
+ if ((ffesta_label_token == NULL)
+ || (ffestc_shriek_after1_ != NULL)
+ || !ffestc_labeldef_begin_ ())
+ return;
+
+ switch (ffelab_type (ffestc_label_))
+ {
+ case FFELAB_typeUNKNOWN:
+ case FFELAB_typeASSIGNABLE:
+ ffelab_set_type (ffestc_label_, FFELAB_typeNOTLOOP);
+ ffelab_set_blocknum (ffestc_label_,
+ ffestw_blocknum (ffestw_stack_top ()));
+ ffestd_labeldef_branch (ffestc_label_);
+ break;
+
+ case FFELAB_typeNOTLOOP:
+ if (ffelab_blocknum (ffestc_label_)
+ < ffestw_blocknum (ffestw_stack_top ()))
+ {
+ ffebad_start (FFEBAD_LABEL_BLOCK);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_firstref_line (ffestc_label_),
+ ffelab_firstref_column (ffestc_label_));
+ ffebad_finish ();
+ }
+ ffelab_set_blocknum (ffestc_label_,
+ ffestw_blocknum (ffestw_stack_top ()));
+ ffestd_labeldef_branch (ffestc_label_);
+ break;
+
+ case FFELAB_typeLOOPEND:
+ if ((ffestw_state (ffestw_stack_top ()) != FFESTV_stateDO)
+ || (ffestw_label (ffestw_stack_top ()) != ffestc_label_))
+ { /* Unterminated block. */
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_DO_BLOCK_END);
+ ffebad_here (0, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_here (2, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_finish ();
+ break;
+ }
+ ffestd_labeldef_branch (ffestc_label_);
+ /* Leave something around for _branch_end_() to handle. */
+ return;
+
+ case FFELAB_typeFORMAT:
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_firstref_line (ffestc_label_),
+ ffelab_firstref_column (ffestc_label_));
+ ffebad_finish ();
+ break;
+
+ default:
+ assert ("bad label" == NULL);
+ /* Fall through. */
+ case FFELAB_typeANY:
+ break;
+ }
+
+ ffestc_try_shriek_do_ ();
+
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+}
+
+/* Define possible end of labeled-DO-loop. Call only after calling
+ ffestc_labeldef_branch_begin_, or when other branch_* functions
+ recognize that a label might also be serving as a branch end (in
+ which case they must issue a diagnostic). */
+
+static void
+ffestc_labeldef_branch_end_ ()
+{
+ if (ffesta_label_token == NULL)
+ return;
+
+ assert (ffestc_label_ != NULL);
+ assert ((ffelab_type (ffestc_label_) == FFELAB_typeLOOPEND)
+ || (ffelab_type (ffestc_label_) == FFELAB_typeANY));
+
+ while ((ffestw_state (ffestw_stack_top ()) == FFESTV_stateDO)
+ && (ffestw_label (ffestw_stack_top ()) == ffestc_label_))
+ ffestc_shriek_do_ (TRUE);
+
+ ffestc_try_shriek_do_ ();
+
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+}
+
+/* ffestc_labeldef_endif_ -- Define label as an END IF one
+
+ ffestc_labeldef_endif_(); */
+
+static void
+ffestc_labeldef_endif_ ()
+{
+ if ((ffesta_label_token == NULL)
+ || (ffestc_shriek_after1_ != NULL)
+ || !ffestc_labeldef_begin_ ())
+ return;
+
+ switch (ffelab_type (ffestc_label_))
+ {
+ case FFELAB_typeUNKNOWN:
+ case FFELAB_typeASSIGNABLE:
+ ffelab_set_type (ffestc_label_, FFELAB_typeENDIF);
+ ffelab_set_blocknum (ffestc_label_,
+ ffestw_blocknum (ffestw_previous (ffestw_stack_top ())));
+ ffestd_labeldef_endif (ffestc_label_);
+ break;
+
+ case FFELAB_typeNOTLOOP:
+ if (ffelab_blocknum (ffestc_label_)
+ < ffestw_blocknum (ffestw_previous (ffestw_stack_top ())))
+ {
+ ffebad_start (FFEBAD_LABEL_BLOCK);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_firstref_line (ffestc_label_),
+ ffelab_firstref_column (ffestc_label_));
+ ffebad_finish ();
+ }
+ ffelab_set_blocknum (ffestc_label_,
+ ffestw_blocknum (ffestw_previous (ffestw_stack_top ())));
+ ffestd_labeldef_endif (ffestc_label_);
+ break;
+
+ case FFELAB_typeLOOPEND:
+ if ((ffestw_state (ffestw_stack_top ()) != FFESTV_stateDO)
+ || (ffestw_label (ffestw_stack_top ()) != ffestc_label_))
+ { /* Unterminated block. */
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_DO_BLOCK_END);
+ ffebad_here (0, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_here (2, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_finish ();
+ break;
+ }
+ ffestd_labeldef_endif (ffestc_label_);
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_finish ();
+ ffestc_labeldef_branch_end_ ();
+ return;
+
+ case FFELAB_typeFORMAT:
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_firstref_line (ffestc_label_),
+ ffelab_firstref_column (ffestc_label_));
+ ffebad_finish ();
+ break;
+
+ default:
+ assert ("bad label" == NULL);
+ /* Fall through. */
+ case FFELAB_typeANY:
+ break;
+ }
+
+ ffestc_try_shriek_do_ ();
+
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+}
+
+/* ffestc_labeldef_format_ -- Define label as a FORMAT one
+
+ ffestc_labeldef_format_(); */
+
+static void
+ffestc_labeldef_format_ ()
+{
+ if ((ffesta_label_token == NULL)
+ || (ffestc_shriek_after1_ != NULL))
+ {
+ ffebad_start (FFEBAD_FORMAT_NO_LABEL_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ return;
+ }
+
+ if (!ffestc_labeldef_begin_ ())
+ return;
+
+ switch (ffelab_type (ffestc_label_))
+ {
+ case FFELAB_typeUNKNOWN:
+ case FFELAB_typeASSIGNABLE:
+ ffelab_set_type (ffestc_label_, FFELAB_typeFORMAT);
+ ffestd_labeldef_format (ffestc_label_);
+ break;
+
+ case FFELAB_typeFORMAT:
+ ffestd_labeldef_format (ffestc_label_);
+ break;
+
+ case FFELAB_typeLOOPEND:
+ if ((ffestw_state (ffestw_stack_top ()) != FFESTV_stateDO)
+ || (ffestw_label (ffestw_stack_top ()) != ffestc_label_))
+ { /* Unterminated block. */
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_DO_BLOCK_END);
+ ffebad_here (0, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_here (2, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_finish ();
+ break;
+ }
+ ffestd_labeldef_format (ffestc_label_);
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_finish ();
+ ffestc_labeldef_branch_end_ ();
+ return;
+
+ case FFELAB_typeNOTLOOP:
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_firstref_line (ffestc_label_),
+ ffelab_firstref_column (ffestc_label_));
+ ffebad_finish ();
+ break;
+
+ default:
+ assert ("bad label" == NULL);
+ /* Fall through. */
+ case FFELAB_typeANY:
+ break;
+ }
+
+ ffestc_try_shriek_do_ ();
+
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+}
+
+/* ffestc_labeldef_invalid_ -- Label definition invalid, complain if present
+
+ ffestc_labeldef_invalid_(); */
+
+static void
+ffestc_labeldef_invalid_ ()
+{
+ if ((ffesta_label_token == NULL)
+ || (ffestc_shriek_after1_ != NULL)
+ || !ffestc_labeldef_begin_ ())
+ return;
+
+ ffebad_start (FFEBAD_INVALID_LABEL_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_finish ();
+
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffestc_try_shriek_do_ ();
+
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+}
+
+/* Define label as a non-loop-ending one on a statement that can't
+ be in the "then" part of a logical IF, such as a block-IF statement. */
+
+static void
+ffestc_labeldef_notloop_ ()
+{
+ if (ffesta_label_token == NULL)
+ return;
+
+ assert (ffestc_shriek_after1_ == NULL);
+
+ if (!ffestc_labeldef_begin_ ())
+ return;
+
+ switch (ffelab_type (ffestc_label_))
+ {
+ case FFELAB_typeUNKNOWN:
+ case FFELAB_typeASSIGNABLE:
+ ffelab_set_type (ffestc_label_, FFELAB_typeNOTLOOP);
+ ffelab_set_blocknum (ffestc_label_,
+ ffestw_blocknum (ffestw_stack_top ()));
+ ffestd_labeldef_notloop (ffestc_label_);
+ break;
+
+ case FFELAB_typeNOTLOOP:
+ if (ffelab_blocknum (ffestc_label_)
+ < ffestw_blocknum (ffestw_stack_top ()))
+ {
+ ffebad_start (FFEBAD_LABEL_BLOCK);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_firstref_line (ffestc_label_),
+ ffelab_firstref_column (ffestc_label_));
+ ffebad_finish ();
+ }
+ ffelab_set_blocknum (ffestc_label_,
+ ffestw_blocknum (ffestw_stack_top ()));
+ ffestd_labeldef_notloop (ffestc_label_);
+ break;
+
+ case FFELAB_typeLOOPEND:
+ if ((ffestw_state (ffestw_stack_top ()) != FFESTV_stateDO)
+ || (ffestw_label (ffestw_stack_top ()) != ffestc_label_))
+ { /* Unterminated block. */
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_DO_BLOCK_END);
+ ffebad_here (0, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_here (2, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_finish ();
+ break;
+ }
+ ffestd_labeldef_notloop (ffestc_label_);
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_finish ();
+ ffestc_labeldef_branch_end_ ();
+ return;
+
+ case FFELAB_typeFORMAT:
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_firstref_line (ffestc_label_),
+ ffelab_firstref_column (ffestc_label_));
+ ffebad_finish ();
+ break;
+
+ default:
+ assert ("bad label" == NULL);
+ /* Fall through. */
+ case FFELAB_typeANY:
+ break;
+ }
+
+ ffestc_try_shriek_do_ ();
+
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+}
+
+/* Define label as a non-loop-ending one. Use this when it is
+ possible that the pending label is inhibited because we're in
+ the midst of a logical-IF, and thus _branch_end_ is going to
+ be called after the current statement to resolve a potential
+ loop-ending label. */
+
+static void
+ffestc_labeldef_notloop_begin_ ()
+{
+ if ((ffesta_label_token == NULL)
+ || (ffestc_shriek_after1_ != NULL)
+ || !ffestc_labeldef_begin_ ())
+ return;
+
+ switch (ffelab_type (ffestc_label_))
+ {
+ case FFELAB_typeUNKNOWN:
+ case FFELAB_typeASSIGNABLE:
+ ffelab_set_type (ffestc_label_, FFELAB_typeNOTLOOP);
+ ffelab_set_blocknum (ffestc_label_,
+ ffestw_blocknum (ffestw_stack_top ()));
+ ffestd_labeldef_notloop (ffestc_label_);
+ break;
+
+ case FFELAB_typeNOTLOOP:
+ if (ffelab_blocknum (ffestc_label_)
+ < ffestw_blocknum (ffestw_stack_top ()))
+ {
+ ffebad_start (FFEBAD_LABEL_BLOCK);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_firstref_line (ffestc_label_),
+ ffelab_firstref_column (ffestc_label_));
+ ffebad_finish ();
+ }
+ ffelab_set_blocknum (ffestc_label_,
+ ffestw_blocknum (ffestw_stack_top ()));
+ ffestd_labeldef_notloop (ffestc_label_);
+ break;
+
+ case FFELAB_typeLOOPEND:
+ if ((ffestw_state (ffestw_stack_top ()) != FFESTV_stateDO)
+ || (ffestw_label (ffestw_stack_top ()) != ffestc_label_))
+ { /* Unterminated block. */
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_DO_BLOCK_END);
+ ffebad_here (0, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_here (2, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_finish ();
+ break;
+ }
+ ffestd_labeldef_branch (ffestc_label_);
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_finish ();
+ return;
+
+ case FFELAB_typeFORMAT:
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_firstref_line (ffestc_label_),
+ ffelab_firstref_column (ffestc_label_));
+ ffebad_finish ();
+ break;
+
+ default:
+ assert ("bad label" == NULL);
+ /* Fall through. */
+ case FFELAB_typeANY:
+ break;
+ }
+
+ ffestc_try_shriek_do_ ();
+
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+}
+
+/* ffestc_labeldef_useless_ -- Define label as a useless one
+
+ ffestc_labeldef_useless_(); */
+
+static void
+ffestc_labeldef_useless_ ()
+{
+ if ((ffesta_label_token == NULL)
+ || (ffestc_shriek_after1_ != NULL)
+ || !ffestc_labeldef_begin_ ())
+ return;
+
+ switch (ffelab_type (ffestc_label_))
+ {
+ case FFELAB_typeUNKNOWN:
+ ffelab_set_type (ffestc_label_, FFELAB_typeUSELESS);
+ ffestd_labeldef_useless (ffestc_label_);
+ break;
+
+ case FFELAB_typeLOOPEND:
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ if ((ffestw_state (ffestw_stack_top ()) != FFESTV_stateDO)
+ || (ffestw_label (ffestw_stack_top ()) != ffestc_label_))
+ { /* Unterminated block. */
+ ffebad_start (FFEBAD_LABEL_DO_BLOCK_END);
+ ffebad_here (0, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_here (2, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_finish ();
+ break;
+ }
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_doref_line (ffestc_label_),
+ ffelab_doref_column (ffestc_label_));
+ ffebad_finish ();
+ ffestc_labeldef_branch_end_ ();
+ return;
+
+ case FFELAB_typeASSIGNABLE:
+ case FFELAB_typeFORMAT:
+ case FFELAB_typeNOTLOOP:
+ ffelab_set_type (ffestc_label_, FFELAB_typeANY);
+ ffestd_labeldef_any (ffestc_label_);
+
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelex_token_where_line (ffesta_label_token),
+ ffelex_token_where_column (ffesta_label_token));
+ ffebad_here (1, ffelab_firstref_line (ffestc_label_),
+ ffelab_firstref_column (ffestc_label_));
+ ffebad_finish ();
+ break;
+
+ default:
+ assert ("bad label" == NULL);
+ /* Fall through. */
+ case FFELAB_typeANY:
+ break;
+ }
+
+ ffestc_try_shriek_do_ ();
+
+ ffelex_token_kill (ffesta_label_token);
+ ffesta_label_token = NULL;
+}
+
+/* ffestc_labelref_is_assignable_ -- Reference to label in ASSIGN stmt
+
+ if (ffestc_labelref_is_assignable_(label_token,&label))
+ // label ref is ok, label is filled in with ffelab object */
+
+static bool
+ffestc_labelref_is_assignable_ (ffelexToken label_token, ffelab *x_label)
+{
+ ffelab label;
+ ffelabValue label_value;
+
+ label_value = (ffelabValue) atol (ffelex_token_text (label_token));
+ if ((label_value == 0) || (label_value > FFELAB_valueMAX))
+ {
+ ffebad_start (FFEBAD_LABEL_NUMBER_INVALID);
+ ffebad_here (0, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+ return FALSE;
+ }
+
+ label = ffelab_find (label_value);
+ if (label == NULL)
+ {
+ label = ffelab_new (label_value);
+ ffelab_set_firstref_line (label,
+ ffewhere_line_use (ffelex_token_where_line (label_token)));
+ ffelab_set_firstref_column (label,
+ ffewhere_column_use (ffelex_token_where_column (label_token)));
+ }
+
+ switch (ffelab_type (label))
+ {
+ case FFELAB_typeUNKNOWN:
+ ffelab_set_type (label, FFELAB_typeASSIGNABLE);
+ break;
+
+ case FFELAB_typeASSIGNABLE:
+ case FFELAB_typeLOOPEND:
+ case FFELAB_typeFORMAT:
+ case FFELAB_typeNOTLOOP:
+ case FFELAB_typeENDIF:
+ break;
+
+ case FFELAB_typeUSELESS:
+ ffelab_set_type (label, FFELAB_typeANY);
+ ffestd_labeldef_any (label);
+
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelab_firstref_line (label), ffelab_firstref_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+
+ ffestc_try_shriek_do_ ();
+
+ return FALSE;
+
+ default:
+ assert ("bad label" == NULL);
+ /* Fall through. */
+ case FFELAB_typeANY:
+ break;
+ }
+
+ *x_label = label;
+ return TRUE;
+}
+
+/* ffestc_labelref_is_branch_ -- Reference to label in branch stmt
+
+ if (ffestc_labelref_is_branch_(label_token,&label))
+ // label ref is ok, label is filled in with ffelab object */
+
+static bool
+ffestc_labelref_is_branch_ (ffelexToken label_token, ffelab *x_label)
+{
+ ffelab label;
+ ffelabValue label_value;
+ ffestw block;
+ unsigned long blocknum;
+
+ label_value = (ffelabValue) atol (ffelex_token_text (label_token));
+ if ((label_value == 0) || (label_value > FFELAB_valueMAX))
+ {
+ ffebad_start (FFEBAD_LABEL_NUMBER_INVALID);
+ ffebad_here (0, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+ return FALSE;
+ }
+
+ label = ffelab_find (label_value);
+ if (label == NULL)
+ {
+ label = ffelab_new (label_value);
+ ffelab_set_firstref_line (label,
+ ffewhere_line_use (ffelex_token_where_line (label_token)));
+ ffelab_set_firstref_column (label,
+ ffewhere_column_use (ffelex_token_where_column (label_token)));
+ }
+
+ switch (ffelab_type (label))
+ {
+ case FFELAB_typeUNKNOWN:
+ case FFELAB_typeASSIGNABLE:
+ ffelab_set_type (label, FFELAB_typeNOTLOOP);
+ ffelab_set_blocknum (label, ffestw_blocknum (ffestw_stack_top ()));
+ break;
+
+ case FFELAB_typeLOOPEND:
+ if (ffelab_blocknum (label) != 0)
+ break; /* Already taken care of. */
+ for (block = ffestw_top_do (ffestw_stack_top ());
+ (block != NULL) && (ffestw_label (block) != label);
+ block = ffestw_top_do (ffestw_previous (block)))
+ ; /* Find most recent DO <label> ancestor. */
+ if (block == NULL)
+ { /* Reference to within a (dead) block. */
+ ffebad_start (FFEBAD_LABEL_BLOCK);
+ ffebad_here (0, ffelab_definition_line (label),
+ ffelab_definition_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+ break;
+ }
+ ffelab_set_blocknum (label, ffestw_blocknum (block));
+ ffelab_set_firstref_line (label,
+ ffewhere_line_use (ffelex_token_where_line (label_token)));
+ ffelab_set_firstref_column (label,
+ ffewhere_column_use (ffelex_token_where_column (label_token)));
+ break;
+
+ case FFELAB_typeNOTLOOP:
+ case FFELAB_typeENDIF:
+ if (ffelab_blocknum (label) == ffestw_blocknum (ffestw_stack_top ()))
+ break;
+ blocknum = ffelab_blocknum (label);
+ for (block = ffestw_stack_top ();
+ ffestw_blocknum (block) > blocknum;
+ block = ffestw_previous (block))
+ ; /* Find most recent common ancestor. */
+ if (ffelab_blocknum (label) == ffestw_blocknum (block))
+ break; /* Check again. */
+ if (!ffewhere_line_is_unknown (ffelab_definition_line (label)))
+ { /* Reference to within a (dead) block. */
+ ffebad_start (FFEBAD_LABEL_BLOCK);
+ ffebad_here (0, ffelab_definition_line (label),
+ ffelab_definition_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+ break;
+ }
+ ffelab_set_blocknum (label, ffestw_blocknum (block));
+ break;
+
+ case FFELAB_typeFORMAT:
+ if (ffewhere_line_is_unknown (ffelab_definition_line (label)))
+ {
+ ffelab_set_type (label, FFELAB_typeANY);
+ ffestd_labeldef_any (label);
+
+ ffebad_start (FFEBAD_LABEL_USE_USE);
+ ffebad_here (0, ffelab_firstref_line (label), ffelab_firstref_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+
+ ffestc_try_shriek_do_ ();
+
+ return FALSE;
+ }
+ /* Fall through. */
+ case FFELAB_typeUSELESS:
+ ffelab_set_type (label, FFELAB_typeANY);
+ ffestd_labeldef_any (label);
+
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelab_definition_line (label), ffelab_definition_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+
+ ffestc_try_shriek_do_ ();
+
+ return FALSE;
+
+ default:
+ assert ("bad label" == NULL);
+ /* Fall through. */
+ case FFELAB_typeANY:
+ break;
+ }
+
+ *x_label = label;
+ return TRUE;
+}
+
+/* ffestc_labelref_is_format_ -- Reference to label in [FMT=] specification
+
+ if (ffestc_labelref_is_format_(label_token,&label))
+ // label ref is ok, label is filled in with ffelab object */
+
+static bool
+ffestc_labelref_is_format_ (ffelexToken label_token, ffelab *x_label)
+{
+ ffelab label;
+ ffelabValue label_value;
+
+ label_value = (ffelabValue) atol (ffelex_token_text (label_token));
+ if ((label_value == 0) || (label_value > FFELAB_valueMAX))
+ {
+ ffebad_start (FFEBAD_LABEL_NUMBER_INVALID);
+ ffebad_here (0, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+ return FALSE;
+ }
+
+ label = ffelab_find (label_value);
+ if (label == NULL)
+ {
+ label = ffelab_new (label_value);
+ ffelab_set_firstref_line (label,
+ ffewhere_line_use (ffelex_token_where_line (label_token)));
+ ffelab_set_firstref_column (label,
+ ffewhere_column_use (ffelex_token_where_column (label_token)));
+ }
+
+ switch (ffelab_type (label))
+ {
+ case FFELAB_typeUNKNOWN:
+ case FFELAB_typeASSIGNABLE:
+ ffelab_set_type (label, FFELAB_typeFORMAT);
+ break;
+
+ case FFELAB_typeFORMAT:
+ break;
+
+ case FFELAB_typeLOOPEND:
+ case FFELAB_typeNOTLOOP:
+ if (ffewhere_line_is_unknown (ffelab_definition_line (label)))
+ {
+ ffelab_set_type (label, FFELAB_typeANY);
+ ffestd_labeldef_any (label);
+
+ ffebad_start (FFEBAD_LABEL_USE_USE);
+ ffebad_here (0, ffelab_firstref_line (label), ffelab_firstref_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+
+ ffestc_try_shriek_do_ ();
+
+ return FALSE;
+ }
+ /* Fall through. */
+ case FFELAB_typeUSELESS:
+ case FFELAB_typeENDIF:
+ ffelab_set_type (label, FFELAB_typeANY);
+ ffestd_labeldef_any (label);
+
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelab_definition_line (label), ffelab_definition_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+
+ ffestc_try_shriek_do_ ();
+
+ return FALSE;
+
+ default:
+ assert ("bad label" == NULL);
+ /* Fall through. */
+ case FFELAB_typeANY:
+ break;
+ }
+
+ ffestc_try_shriek_do_ ();
+
+ *x_label = label;
+ return TRUE;
+}
+
+/* ffestc_labelref_is_loopend_ -- Reference to label in DO stmt
+
+ if (ffestc_labelref_is_loopend_(label_token,&label))
+ // label ref is ok, label is filled in with ffelab object */
+
+static bool
+ffestc_labelref_is_loopend_ (ffelexToken label_token, ffelab *x_label)
+{
+ ffelab label;
+ ffelabValue label_value;
+
+ label_value = (ffelabValue) atol (ffelex_token_text (label_token));
+ if ((label_value == 0) || (label_value > FFELAB_valueMAX))
+ {
+ ffebad_start (FFEBAD_LABEL_NUMBER_INVALID);
+ ffebad_here (0, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+ return FALSE;
+ }
+
+ label = ffelab_find (label_value);
+ if (label == NULL)
+ {
+ label = ffelab_new (label_value);
+ ffelab_set_doref_line (label,
+ ffewhere_line_use (ffelex_token_where_line (label_token)));
+ ffelab_set_doref_column (label,
+ ffewhere_column_use (ffelex_token_where_column (label_token)));
+ }
+
+ switch (ffelab_type (label))
+ {
+ case FFELAB_typeASSIGNABLE:
+ ffelab_set_doref_line (label,
+ ffewhere_line_use (ffelex_token_where_line (label_token)));
+ ffelab_set_doref_column (label,
+ ffewhere_column_use (ffelex_token_where_column (label_token)));
+ ffewhere_line_kill (ffelab_firstref_line (label));
+ ffelab_set_firstref_line (label, ffewhere_line_unknown ());
+ ffewhere_column_kill (ffelab_firstref_column (label));
+ ffelab_set_firstref_column (label, ffewhere_column_unknown ());
+ /* Fall through. */
+ case FFELAB_typeUNKNOWN:
+ ffelab_set_type (label, FFELAB_typeLOOPEND);
+ ffelab_set_blocknum (label, 0);
+ break;
+
+ case FFELAB_typeLOOPEND:
+ if (!ffewhere_line_is_unknown (ffelab_definition_line (label)))
+ { /* Def must follow all refs. */
+ ffelab_set_type (label, FFELAB_typeANY);
+ ffestd_labeldef_any (label);
+
+ ffebad_start (FFEBAD_LABEL_DEF_DO);
+ ffebad_here (0, ffelab_definition_line (label),
+ ffelab_definition_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+
+ ffestc_try_shriek_do_ ();
+
+ return FALSE;
+ }
+ if (ffelab_blocknum (label) != 0)
+ { /* Had a branch ref earlier, can't go inside
+ this new block! */
+ ffelab_set_type (label, FFELAB_typeANY);
+ ffestd_labeldef_any (label);
+
+ ffebad_start (FFEBAD_LABEL_USE_USE);
+ ffebad_here (0, ffelab_firstref_line (label),
+ ffelab_firstref_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+
+ ffestc_try_shriek_do_ ();
+
+ return FALSE;
+ }
+ if ((ffestw_state (ffestw_stack_top ()) != FFESTV_stateDO)
+ || (ffestw_label (ffestw_stack_top ()) != label))
+ { /* Top of stack interrupts flow between two
+ DOs specifying label. */
+ ffelab_set_type (label, FFELAB_typeANY);
+ ffestd_labeldef_any (label);
+
+ ffebad_start (FFEBAD_LABEL_DO_BLOCK_DO);
+ ffebad_here (0, ffelab_doref_line (label),
+ ffelab_doref_column (label));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_here (2, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+
+ ffestc_try_shriek_do_ ();
+
+ return FALSE;
+ }
+ break;
+
+ case FFELAB_typeNOTLOOP:
+ case FFELAB_typeFORMAT:
+ if (ffewhere_line_is_unknown (ffelab_definition_line (label)))
+ {
+ ffelab_set_type (label, FFELAB_typeANY);
+ ffestd_labeldef_any (label);
+
+ ffebad_start (FFEBAD_LABEL_USE_USE);
+ ffebad_here (0, ffelab_firstref_line (label), ffelab_firstref_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+
+ ffestc_try_shriek_do_ ();
+
+ return FALSE;
+ }
+ /* Fall through. */
+ case FFELAB_typeUSELESS:
+ case FFELAB_typeENDIF:
+ ffelab_set_type (label, FFELAB_typeANY);
+ ffestd_labeldef_any (label);
+
+ ffebad_start (FFEBAD_LABEL_USE_DEF);
+ ffebad_here (0, ffelab_definition_line (label), ffelab_definition_column (label));
+ ffebad_here (1, ffelex_token_where_line (label_token),
+ ffelex_token_where_column (label_token));
+ ffebad_finish ();
+
+ ffestc_try_shriek_do_ ();
+
+ return FALSE;
+
+ default:
+ assert ("bad label" == NULL);
+ /* Fall through. */
+ case FFELAB_typeANY:
+ break;
+ }
+
+ *x_label = label;
+ return TRUE;
+}
+
+/* ffestc_order_access_ -- Check ordering on <access> statement
+
+ if (ffestc_order_access_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_F90
+static ffestcOrder_
+ffestc_order_access_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE3:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_actiondo_ -- Check ordering on <actiondo> statement
+
+ if (ffestc_order_actiondo_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_actiondo_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateDO:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateIFTHEN:
+ case FFESTV_stateSELECT1:
+ if (ffestw_top_do (ffestw_stack_top ()) == NULL)
+ break;
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateIF:
+ if (ffestw_top_do (ffestw_stack_top ()) == NULL)
+ break;
+ ffestc_shriek_after1_ = ffestc_shriek_if_;
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ default:
+ break;
+ }
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+}
+
+/* ffestc_order_actionif_ -- Check ordering on <actionif> statement
+
+ if (ffestc_order_actionif_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_actionif_ ()
+{
+ bool update;
+
+recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ case FFESTV_statePROGRAM3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM4);
+ update = TRUE;
+ break;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateSUBROUTINE3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE4);
+ update = TRUE;
+ break;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateFUNCTION3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION4);
+ update = TRUE;
+ break;
+
+ case FFESTV_statePROGRAM4:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateFUNCTION4:
+ update = FALSE;
+ break;
+
+ case FFESTV_stateIFTHEN:
+ case FFESTV_stateDO:
+ case FFESTV_stateSELECT1:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateIF:
+ ffestc_shriek_after1_ = ffestc_shriek_if_;
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+
+ switch (ffestw_state (ffestw_previous (ffestw_stack_top ())))
+ {
+ case FFESTV_stateINTERFACE0:
+ ffestc_order_bad_ ();
+ if (update)
+ ffestw_update (NULL);
+ return FFESTC_orderBAD_;
+
+ default:
+ if (update)
+ ffestw_update (NULL);
+ return FFESTC_orderOK_;
+ }
+}
+
+/* ffestc_order_actionwhere_ -- Check ordering on <actionwhere> statement
+
+ if (ffestc_order_actionwhere_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_actionwhere_ ()
+{
+ bool update;
+
+recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ case FFESTV_statePROGRAM3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM4);
+ update = TRUE;
+ break;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateSUBROUTINE3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE4);
+ update = TRUE;
+ break;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateFUNCTION3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION4);
+ update = TRUE;
+ break;
+
+ case FFESTV_statePROGRAM4:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateFUNCTION4:
+ update = FALSE;
+ break;
+
+ case FFESTV_stateWHERETHEN:
+ case FFESTV_stateIFTHEN:
+ case FFESTV_stateDO:
+ case FFESTV_stateSELECT1:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+#if FFESTR_F90
+ ffestc_shriek_after1_ = ffestc_shriek_where_;
+#endif
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateIF:
+ ffestc_shriek_after1_ = ffestc_shriek_if_;
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+
+ switch (ffestw_state (ffestw_previous (ffestw_stack_top ())))
+ {
+ case FFESTV_stateINTERFACE0:
+ ffestc_order_bad_ ();
+ if (update)
+ ffestw_update (NULL);
+ return FFESTC_orderBAD_;
+
+ default:
+ if (update)
+ ffestw_update (NULL);
+ return FFESTC_orderOK_;
+ }
+}
+
+/* Check ordering on "any" statement. Like _actionwhere_, but
+ doesn't produce any diagnostics. */
+
+static void
+ffestc_order_any_ ()
+{
+ bool update;
+
+recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ case FFESTV_statePROGRAM3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM4);
+ update = TRUE;
+ break;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateSUBROUTINE3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE4);
+ update = TRUE;
+ break;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateFUNCTION3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION4);
+ update = TRUE;
+ break;
+
+ case FFESTV_statePROGRAM4:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateFUNCTION4:
+ update = FALSE;
+ break;
+
+ case FFESTV_stateWHERETHEN:
+ case FFESTV_stateIFTHEN:
+ case FFESTV_stateDO:
+ case FFESTV_stateSELECT1:
+ return;
+
+ case FFESTV_stateWHERE:
+#if FFESTR_F90
+ ffestc_shriek_after1_ = ffestc_shriek_where_;
+#endif
+ return;
+
+ case FFESTV_stateIF:
+ ffestc_shriek_after1_ = ffestc_shriek_if_;
+ return;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ default:
+ return;
+ }
+
+ switch (ffestw_state (ffestw_previous (ffestw_stack_top ())))
+ {
+ case FFESTV_stateINTERFACE0:
+ if (update)
+ ffestw_update (NULL);
+ return;
+
+ default:
+ if (update)
+ ffestw_update (NULL);
+ return;
+ }
+}
+
+/* ffestc_order_bad_ -- Whine about statement ordering violation
+
+ ffestc_order_bad_();
+
+ Uses current ffesta_tokens[0] and, if available, info on where current
+ state started to produce generic message. Someday we should do
+ fancier things than this, but this just gets things creaking along for
+ now. */
+
+static void
+ffestc_order_bad_ ()
+{
+ if (ffewhere_line_is_unknown (ffestw_line (ffestw_stack_top ())))
+ {
+ ffebad_start (FFEBAD_ORDER_1);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ }
+ else
+ {
+ ffebad_start (FFEBAD_ORDER_2);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ ffestc_labeldef_useless_ (); /* Any label definition is useless. */
+}
+
+/* ffestc_order_blockdata_ -- Check ordering on <blockdata> statement
+
+ if (ffestc_order_blockdata_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_blockdata_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ case FFESTV_stateBLOCKDATA2:
+ case FFESTV_stateBLOCKDATA3:
+ case FFESTV_stateBLOCKDATA4:
+ case FFESTV_stateBLOCKDATA5:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_blockspec_ -- Check ordering on <blockspec> statement
+
+ if (ffestc_order_blockspec_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_blockspec_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ case FFESTV_stateBLOCKDATA2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateBLOCKDATA3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateMODULE3:
+ case FFESTV_stateBLOCKDATA3:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_component_ -- Check ordering on <component-decl> statement
+
+ if (ffestc_order_component_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_F90
+static ffestcOrder_
+ffestc_order_component_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateTYPE:
+ case FFESTV_stateSTRUCTURE:
+ case FFESTV_stateMAP:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+ ffestc_shriek_where_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_contains_ -- Check ordering on CONTAINS statement
+
+ if (ffestc_order_contains_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_F90
+static ffestcOrder_
+ffestc_order_contains_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ case FFESTV_statePROGRAM3:
+ case FFESTV_statePROGRAM4:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM5);
+ break;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateSUBROUTINE4:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE5);
+ break;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateFUNCTION4:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION5);
+ break;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ case FFESTV_stateMODULE3:
+ case FFESTV_stateMODULE4:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE5);
+ break;
+
+ case FFESTV_stateUSE:
+ ffestc_shriek_end_uses_ (TRUE);
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+ ffestc_shriek_where_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+
+ switch (ffestw_state (ffestw_previous (ffestw_stack_top ())))
+ {
+ case FFESTV_stateNIL:
+ ffestw_update (NULL);
+ return FFESTC_orderOK_;
+
+ default:
+ ffestc_order_bad_ ();
+ ffestw_update (NULL);
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_data_ -- Check ordering on DATA statement
+
+ if (ffestc_order_data_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_data_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateBLOCKDATA2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM2:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateBLOCKDATA2:
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateBLOCKDATA3:
+ case FFESTV_statePROGRAM4:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateFUNCTION4:
+ case FFESTV_stateBLOCKDATA4:
+ case FFESTV_stateWHERETHEN:
+ case FFESTV_stateIFTHEN:
+ case FFESTV_stateDO:
+ case FFESTV_stateSELECT0:
+ case FFESTV_stateSELECT1:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_data77_ -- Check ordering on pedantic-F77 DATA statement
+
+ if (ffestc_order_data77_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_data77_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ case FFESTV_statePROGRAM3:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM4);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateSUBROUTINE3:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE4);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateFUNCTION3:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION4);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ case FFESTV_stateBLOCKDATA2:
+ case FFESTV_stateBLOCKDATA3:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateBLOCKDATA4);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM4:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateFUNCTION4:
+ case FFESTV_stateBLOCKDATA4:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERETHEN:
+ case FFESTV_stateIFTHEN:
+ case FFESTV_stateDO:
+ case FFESTV_stateSELECT0:
+ case FFESTV_stateSELECT1:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_derivedtype_ -- Check ordering on derived TYPE statement
+
+ if (ffestc_order_derivedtype_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_F90
+static ffestcOrder_
+ffestc_order_derivedtype_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateMODULE3:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+ ffestc_shriek_end_uses_ (TRUE);
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+ ffestc_shriek_where_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_do_ -- Check ordering on <do> statement
+
+ if (ffestc_order_do_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_do_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateDO:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_entry_ -- Check ordering on ENTRY statement
+
+ if (ffestc_order_entry_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_entry_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateSUBROUTINE0:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE1);
+ break;
+
+ case FFESTV_stateFUNCTION0:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION1);
+ break;
+
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateFUNCTION4:
+ break;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+
+ switch (ffestw_state (ffestw_previous (ffestw_stack_top ())))
+ {
+ case FFESTV_stateNIL:
+ case FFESTV_stateMODULE5:
+ ffestw_update (NULL);
+ return FFESTC_orderOK_;
+
+ default:
+ ffestc_order_bad_ ();
+ ffestw_update (NULL);
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_exec_ -- Check ordering on <exec> statement
+
+ if (ffestc_order_exec_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_exec_ ()
+{
+ bool update;
+
+recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ case FFESTV_statePROGRAM3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM4);
+ update = TRUE;
+ break;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateSUBROUTINE3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE4);
+ update = TRUE;
+ break;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateFUNCTION3:
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION4);
+ update = TRUE;
+ break;
+
+ case FFESTV_statePROGRAM4:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateFUNCTION4:
+ update = FALSE;
+ break;
+
+ case FFESTV_stateIFTHEN:
+ case FFESTV_stateDO:
+ case FFESTV_stateSELECT1:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+
+ switch (ffestw_state (ffestw_previous (ffestw_stack_top ())))
+ {
+ case FFESTV_stateINTERFACE0:
+ ffestc_order_bad_ ();
+ if (update)
+ ffestw_update (NULL);
+ return FFESTC_orderBAD_;
+
+ default:
+ if (update)
+ ffestw_update (NULL);
+ return FFESTC_orderOK_;
+ }
+}
+
+/* ffestc_order_format_ -- Check ordering on FORMAT statement
+
+ if (ffestc_order_format_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_format_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM1);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE1);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION1);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_statePROGRAM4:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateFUNCTION4:
+ case FFESTV_stateWHERETHEN:
+ case FFESTV_stateIFTHEN:
+ case FFESTV_stateDO:
+ case FFESTV_stateSELECT0:
+ case FFESTV_stateSELECT1:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_function_ -- Check ordering on <function> statement
+
+ if (ffestc_order_function_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_function_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateFUNCTION4:
+ case FFESTV_stateFUNCTION5:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_iface_ -- Check ordering on <iface> statement
+
+ if (ffestc_order_iface_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_iface_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ case FFESTV_statePROGRAM5:
+ case FFESTV_stateSUBROUTINE5:
+ case FFESTV_stateFUNCTION5:
+ case FFESTV_stateMODULE5:
+ case FFESTV_stateINTERFACE0:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_ifthen_ -- Check ordering on <ifthen> statement
+
+ if (ffestc_order_ifthen_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_ifthen_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateIFTHEN:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_implicit_ -- Check ordering on IMPLICIT statement
+
+ if (ffestc_order_implicit_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_implicit_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateBLOCKDATA2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM2:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateMODULE2:
+ case FFESTV_stateBLOCKDATA2:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_implicitnone_ -- Check ordering on IMPLICIT NONE statement
+
+ if (ffestc_order_implicitnone_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_implicitnone_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateBLOCKDATA3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_interface_ -- Check ordering on <interface> statement
+
+ if (ffestc_order_interface_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_F90
+static ffestcOrder_
+ffestc_order_interface_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateINTERFACE0:
+ case FFESTV_stateINTERFACE1:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+ ffestc_shriek_where_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_map_ -- Check ordering on <map> statement
+
+ if (ffestc_order_map_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_VXT
+static ffestcOrder_
+ffestc_order_map_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateMAP:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+ ffestc_shriek_where_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_module_ -- Check ordering on <module> statement
+
+ if (ffestc_order_module_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_F90
+static ffestcOrder_
+ffestc_order_module_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ case FFESTV_stateMODULE3:
+ case FFESTV_stateMODULE4:
+ case FFESTV_stateMODULE5:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+ ffestc_shriek_end_uses_ (TRUE);
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+ ffestc_shriek_where_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_parameter_ -- Check ordering on <parameter> statement
+
+ if (ffestc_order_parameter_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_parameter_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateBLOCKDATA2);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM2:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateMODULE2:
+ case FFESTV_stateBLOCKDATA2:
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateMODULE3:
+ case FFESTV_stateBLOCKDATA3:
+ case FFESTV_stateTYPE: /* GNU extension here! */
+ case FFESTV_stateSTRUCTURE:
+ case FFESTV_stateUNION:
+ case FFESTV_stateMAP:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_program_ -- Check ordering on <program> statement
+
+ if (ffestc_order_program_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_program_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ case FFESTV_statePROGRAM3:
+ case FFESTV_statePROGRAM4:
+ case FFESTV_statePROGRAM5:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_progspec_ -- Check ordering on <progspec> statement
+
+ if (ffestc_order_progspec_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_progspec_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateMODULE3:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ case FFESTV_stateBLOCKDATA2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateBLOCKDATA2);
+ if (ffe_is_pedantic ())
+ {
+ ffebad_start (FFEBAD_BLOCKDATA_STMT);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_record_ -- Check ordering on RECORD statement
+
+ if (ffestc_order_record_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_VXT
+static ffestcOrder_
+ffestc_order_record_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ case FFESTV_stateBLOCKDATA2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateBLOCKDATA3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateMODULE3:
+ case FFESTV_stateBLOCKDATA3:
+ case FFESTV_stateSTRUCTURE:
+ case FFESTV_stateMAP:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_selectcase_ -- Check ordering on <selectcase> statement
+
+ if (ffestc_order_selectcase_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_selectcase_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateSELECT0:
+ case FFESTV_stateSELECT1:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_sfunc_ -- Check ordering on statement-function definition
+
+ if (ffestc_order_sfunc_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_sfunc_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_spec_ -- Check ordering on <spec> statement
+
+ if (ffestc_order_spec_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_F90
+static ffestcOrder_
+ffestc_order_spec_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateMODULE3:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_structure_ -- Check ordering on <structure> statement
+
+ if (ffestc_order_structure_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_VXT
+static ffestcOrder_
+ffestc_order_structure_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateSTRUCTURE:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_subroutine_ -- Check ordering on <subroutine> statement
+
+ if (ffestc_order_subroutine_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_subroutine_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateSUBROUTINE5:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_type_ -- Check ordering on <type> statement
+
+ if (ffestc_order_type_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_F90
+static ffestcOrder_
+ffestc_order_type_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateTYPE:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+ ffestc_shriek_where_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_typedecl_ -- Check ordering on <typedecl> statement
+
+ if (ffestc_order_typedecl_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_typedecl_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ case FFESTV_stateBLOCKDATA2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateBLOCKDATA3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateMODULE3:
+ case FFESTV_stateBLOCKDATA3:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_union_ -- Check ordering on <union> statement
+
+ if (ffestc_order_union_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_VXT
+static ffestcOrder_
+ffestc_order_union_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateUNION:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_unit_ -- Check ordering on <unit> statement
+
+ if (ffestc_order_unit_() != FFESTC_orderOK_)
+ return; */
+
+static ffestcOrder_
+ffestc_order_unit_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+/* ffestc_order_use_ -- Check ordering on USE statement
+
+ if (ffestc_order_use_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_F90
+static ffestcOrder_
+ffestc_order_use_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM1);
+ ffestc_shriek_begin_uses_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateSUBROUTINE0:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE1);
+ ffestc_shriek_begin_uses_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateFUNCTION0:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION1);
+ ffestc_shriek_begin_uses_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateMODULE0:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE1);
+ ffestc_shriek_begin_uses_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateUSE:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+ ffestc_shriek_where_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_vxtstructure_ -- Check ordering on STRUCTURE statement
+
+ if (ffestc_order_vxtstructure_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_VXT
+static ffestcOrder_
+ffestc_order_vxtstructure_ ()
+{
+ recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_statePROGRAM2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_statePROGRAM3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSUBROUTINE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateFUNCTION3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateMODULE3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ case FFESTV_stateBLOCKDATA2:
+ ffestw_update (NULL);
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateBLOCKDATA3);
+ return FFESTC_orderOK_;
+
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateMODULE3:
+ case FFESTV_stateBLOCKDATA3:
+ case FFESTV_stateSTRUCTURE:
+ case FFESTV_stateMAP:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+#if FFESTR_F90
+ ffestc_shriek_where_ (FALSE);
+#endif
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* ffestc_order_where_ -- Check ordering on <where> statement
+
+ if (ffestc_order_where_() != FFESTC_orderOK_)
+ return; */
+
+#if FFESTR_F90
+static ffestcOrder_
+ffestc_order_where_ ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateWHERETHEN:
+ return FFESTC_orderOK_;
+
+ case FFESTV_stateWHERE:
+ ffestc_order_bad_ ();
+ ffestc_shriek_where_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ case FFESTV_stateIF:
+ ffestc_order_bad_ ();
+ ffestc_shriek_if_ (FALSE);
+ return FFESTC_orderBAD_;
+
+ default:
+ ffestc_order_bad_ ();
+ return FFESTC_orderBAD_;
+ }
+}
+
+#endif
+/* Invoked for each token in dummy arg list of FUNCTION, SUBROUTINE, and
+ ENTRY (prior to the first executable statement). */
+
+static void
+ffestc_promote_dummy_ (ffelexToken t)
+{
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffebld e;
+ bool sfref_ok;
+
+ assert (t != NULL);
+
+ if (ffelex_token_type (t) == FFELEX_typeASTERISK)
+ {
+ ffebld_append_item (&ffestc_local_.dummy.list_bottom,
+ ffebld_new_star ());
+ return; /* Don't bother with alternate returns! */
+ }
+
+ s = ffesymbol_declare_local (t, FALSE);
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ sfref_ok = FALSE;
+
+ if (sa & FFESYMBOL_attrsANY)
+ na = sa;
+ else if (sa & FFESYMBOL_attrsDUMMY)
+ {
+ if (ffestc_entry_num_ == ffesymbol_maxentrynum (s))
+ { /* Seen this one twice in this list! */
+ na = FFESYMBOL_attrsetNONE;
+ }
+ else
+ na = sa;
+ sfref_ok = TRUE; /* Ok for sym to be ref'd in sfuncdef
+ previously, since already declared as a
+ dummy arg. */
+ }
+ else if (!(sa & ~(FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsANY
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsANYSIZE
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)))
+ na = sa | FFESYMBOL_attrsDUMMY;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ if (!ffesymbol_is_specable (s)
+ && (!sfref_ok
+ || (ffesymbol_where (s) != FFEINFO_whereDUMMY)))
+ na = FFESYMBOL_attrsetNONE; /* Can't dcl sym ref'd in sfuncdef. */
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_set_attrs (s, na);
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_set_maxentrynum (s, ffestc_entry_num_);
+ ffesymbol_set_numentries (s, ffesymbol_numentries (s) + 1);
+ e = ffebld_new_symter (s, FFEINTRIN_genNONE, FFEINTRIN_specNONE,
+ FFEINTRIN_impNONE);
+ ffebld_set_info (e,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereNONE,
+ FFETARGET_charactersizeNONE));
+ ffebld_append_item (&ffestc_local_.dummy.list_bottom, e);
+ ffesymbol_signal_unreported (s);
+ }
+}
+
+/* ffestc_promote_execdummy_ -- Declare token as dummy variable in exec context
+
+ ffestc_promote_execdummy_(t);
+
+ Invoked for each token in dummy arg list of ENTRY when the statement
+ follows the first executable statement. */
+
+static void
+ffestc_promote_execdummy_ (ffelexToken t)
+{
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffesymbolState ss;
+ ffesymbolState ns;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+ ffebld e;
+
+ assert (t != NULL);
+
+ if (ffelex_token_type (t) == FFELEX_typeASTERISK)
+ {
+ ffebld_append_item (&ffestc_local_.dummy.list_bottom,
+ ffebld_new_star ());
+ return; /* Don't bother with alternate returns! */
+ }
+
+ s = ffesymbol_declare_local (t, FALSE);
+ na = sa = ffesymbol_attrs (s);
+ ss = ffesymbol_state (s);
+ kind = ffesymbol_kind (s);
+ where = ffesymbol_where (s);
+
+ if (ffestc_entry_num_ == ffesymbol_maxentrynum (s))
+ { /* Seen this one twice in this list! */
+ na = FFESYMBOL_attrsetNONE;
+ }
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ ns = FFESYMBOL_stateUNDERSTOOD; /* Assume we know it all know. */
+
+ switch (kind)
+ {
+ case FFEINFO_kindENTITY:
+ case FFEINFO_kindFUNCTION:
+ case FFEINFO_kindSUBROUTINE:
+ break; /* These are fine, as far as we know. */
+
+ case FFEINFO_kindNONE:
+ if (sa & FFESYMBOL_attrsDUMMY)
+ ns = FFESYMBOL_stateUNCERTAIN; /* Learned nothing new. */
+ else if (sa & FFESYMBOL_attrsANYLEN)
+ {
+ kind = FFEINFO_kindENTITY;
+ where = FFEINFO_whereDUMMY;
+ }
+ else if (sa & FFESYMBOL_attrsACTUALARG)
+ na = FFESYMBOL_attrsetNONE;
+ else
+ {
+ na = sa | FFESYMBOL_attrsDUMMY;
+ ns = FFESYMBOL_stateUNCERTAIN;
+ }
+ break;
+
+ default:
+ na = FFESYMBOL_attrsetNONE; /* Error. */
+ break;
+ }
+
+ switch (where)
+ {
+ case FFEINFO_whereDUMMY:
+ break; /* This is fine. */
+
+ case FFEINFO_whereNONE:
+ where = FFEINFO_whereDUMMY;
+ break;
+
+ default:
+ na = FFESYMBOL_attrsetNONE; /* Error. */
+ break;
+ }
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, t);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, ns);
+ ffesymbol_set_maxentrynum (s, ffestc_entry_num_);
+ ffesymbol_set_numentries (s, ffesymbol_numentries (s) + 1);
+ if ((ns == FFESYMBOL_stateUNDERSTOOD)
+ && (kind != FFEINFO_kindSUBROUTINE)
+ && !ffeimplic_establish_symbol (s))
+ {
+ ffesymbol_error (s, t);
+ return;
+ }
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ kind,
+ where,
+ ffesymbol_size (s)));
+ e = ffebld_new_symter (s, FFEINTRIN_genNONE, FFEINTRIN_specNONE,
+ FFEINTRIN_impNONE);
+ ffebld_set_info (e, ffeinfo_use (ffesymbol_info (s)));
+ ffebld_append_item (&ffestc_local_.dummy.list_bottom, e);
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s);
+ }
+}
+
+/* ffestc_promote_sfdummy_ -- Declare token as stmt-func dummy variable
+
+ ffestc_promote_sfdummy_(t);
+
+ Invoked for each token in dummy arg list of statement function.
+
+ 22-Oct-91 JCB 1.1
+ Reject arg if CHARACTER*(*). */
+
+static void
+ffestc_promote_sfdummy_ (ffelexToken t)
+{
+ ffesymbol s;
+ ffesymbol sp; /* Parent symbol. */
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffebld e;
+
+ assert (t != NULL);
+
+ s = ffesymbol_declare_sfdummy (t); /* Sets maxentrynum to 0 for new obj;
+ also sets sfa_dummy_parent to
+ parent symbol. */
+ if (ffesymbol_state (s) != FFESYMBOL_stateNONE)
+ {
+ ffesymbol_error (s, t); /* Dummy already in list. */
+ return;
+ }
+
+ sp = ffesymbol_sfdummyparent (s); /* Now flag dummy's parent as used
+ for dummy. */
+ sa = ffesymbol_attrs (sp);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (!ffesymbol_is_specable (sp)
+ && ((ffesymbol_kind (sp) != FFEINFO_kindENTITY)
+ || ((ffesymbol_where (sp) != FFEINFO_whereLOCAL)
+ && (ffesymbol_where (sp) != FFEINFO_whereCOMMON)
+ && (ffesymbol_where (sp) != FFEINFO_whereDUMMY)
+ && (ffesymbol_where (sp) != FFEINFO_whereNONE))))
+ na = FFESYMBOL_attrsetNONE; /* Can't be PARAMETER etc., must be a var. */
+ else if (sa & FFESYMBOL_attrsANY)
+ na = sa;
+ else if (!(sa & ~(FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsRESULT
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)))
+ na = sa | FFESYMBOL_attrsSFARG;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ {
+ ffesymbol_error (sp, t);
+ ffesymbol_set_info (s, ffeinfo_new_any ());
+ }
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_set_state (sp, FFESYMBOL_stateSEEN);
+ ffesymbol_set_attrs (sp, na);
+ if (!ffeimplic_establish_symbol (sp)
+ || ((ffesymbol_basictype (sp) == FFEINFO_basictypeCHARACTER)
+ && (ffesymbol_size (sp) == FFETARGET_charactersizeNONE)))
+ ffesymbol_error (sp, t);
+ else
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (sp),
+ ffesymbol_kindtype (sp),
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereDUMMY,
+ ffesymbol_size (sp)));
+
+ ffesymbol_signal_unreported (sp);
+ }
+
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_maxentrynum (s, ffestc_sfdummy_argno_++);
+ ffesymbol_signal_unreported (s);
+ e = ffebld_new_symter (s, FFEINTRIN_genNONE, FFEINTRIN_specNONE,
+ FFEINTRIN_impNONE);
+ ffebld_set_info (e, ffeinfo_use (ffesymbol_info (s)));
+ ffebld_append_item (&ffestc_local_.dummy.list_bottom, e);
+}
+
+/* ffestc_shriek_begin_program_ -- Implicit PROGRAM statement
+
+ ffestc_shriek_begin_program_();
+
+ Invoked only when a PROGRAM statement is NOT present at the beginning
+ of a main program unit. */
+
+static void
+ffestc_shriek_begin_program_ ()
+{
+ ffestw b;
+ ffesymbol s;
+
+ ffestc_blocknum_ = 0;
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_statePROGRAM0);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_end_program_);
+ ffestw_set_name (b, NULL);
+
+ s = ffesymbol_declare_programunit (NULL,
+ ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+
+ /* Special case: this is one symbol that won't go through
+ ffestu_exec_transition_ when the first statement in a main program is
+ executable, because the transition happens in ffest before ffestc is
+ reached and triggers the implicit generation of a main program. So we
+ do the exec transition for the implicit main program right here, just
+ for cleanliness' sake (at the very least). */
+
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindPROGRAM,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+
+ ffesymbol_signal_unreported (s);
+
+ ffestd_R1102 (s, NULL);
+}
+
+/* ffestc_shriek_begin_uses_ -- Start a bunch of USE statements
+
+ ffestc_shriek_begin_uses_();
+
+ Invoked before handling the first USE statement in a block of one or
+ more USE statements. _end_uses_(bool ok) is invoked before handling
+ the first statement after the block (there are no BEGIN USE and END USE
+ statements, but the semantics of USE statements effectively requires
+ handling them as a single block rather than one statement at a time). */
+
+#if FFESTR_F90
+static void
+ffestc_shriek_begin_uses_ ()
+{
+ ffestw b;
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_stateUSE);
+ ffestw_set_blocknum (b, 0);
+ ffestw_set_shriek (b, ffestc_shriek_end_uses_);
+
+ ffestd_begin_uses ();
+}
+
+#endif
+/* ffestc_shriek_blockdata_ -- End a BLOCK DATA
+
+ ffestc_shriek_blockdata_(TRUE); */
+
+static void
+ffestc_shriek_blockdata_ (bool ok)
+{
+ if (!ffesta_seen_first_exec)
+ {
+ ffesta_seen_first_exec = TRUE;
+ ffestd_exec_begin ();
+ }
+
+ ffestd_R1112 (ok);
+
+ ffestd_exec_end ();
+
+ if (ffestw_name (ffestw_stack_top ()) != NULL)
+ ffelex_token_kill (ffestw_name (ffestw_stack_top ()));
+ ffestw_kill (ffestw_pop ());
+
+ ffe_terminate_2 ();
+ ffe_init_2 ();
+}
+
+/* ffestc_shriek_do_ -- End of statement following DO-term-stmt etc
+
+ ffestc_shriek_do_(TRUE);
+
+ Also invoked by _labeldef_branch_end_ (or, in cases
+ of errors, other _labeldef_ functions) when the label definition is
+ for a DO-target (LOOPEND) label, once per matching/outstanding DO
+ block on the stack. These cases invoke this function with ok==TRUE, so
+ only forced stack popping (via ffestc_eof()) invokes it with ok==FALSE. */
+
+static void
+ffestc_shriek_do_ (bool ok)
+{
+ ffelab l;
+
+ if (((l = ffestw_label (ffestw_stack_top ())) != NULL)
+ && (ffewhere_line_is_unknown (ffelab_definition_line (l))))
+ { /* DO target is label that is still
+ undefined. */
+ assert ((ffelab_type (l) == FFELAB_typeLOOPEND)
+ || (ffelab_type (l) == FFELAB_typeANY));
+ if (ffelab_type (l) != FFELAB_typeANY)
+ {
+ ffelab_set_definition_line (l,
+ ffewhere_line_use (ffelab_doref_line (l)));
+ ffelab_set_definition_column (l,
+ ffewhere_column_use (ffelab_doref_column (l)));
+ ffestv_num_label_defines_++;
+ }
+ ffestd_labeldef_branch (l);
+ }
+
+ ffestd_do (ok);
+
+ if (ffestw_name (ffestw_stack_top ()) != NULL)
+ ffelex_token_kill (ffestw_name (ffestw_stack_top ()));
+ if (ffestw_do_iter_var_t (ffestw_stack_top ()) != NULL)
+ ffelex_token_kill (ffestw_do_iter_var_t (ffestw_stack_top ()));
+ if (ffestw_do_iter_var (ffestw_stack_top ()) != NULL)
+ ffesymbol_set_is_doiter (ffestw_do_iter_var (ffestw_stack_top ()), FALSE);
+ ffestw_kill (ffestw_pop ());
+}
+
+/* ffestc_shriek_end_program_ -- End a PROGRAM
+
+ ffestc_shriek_end_program_(); */
+
+static void
+ffestc_shriek_end_program_ (bool ok)
+{
+ if (!ffesta_seen_first_exec)
+ {
+ ffesta_seen_first_exec = TRUE;
+ ffestd_exec_begin ();
+ }
+
+ ffestd_R1103 (ok);
+
+ ffestd_exec_end ();
+
+ if (ffestw_name (ffestw_stack_top ()) != NULL)
+ ffelex_token_kill (ffestw_name (ffestw_stack_top ()));
+ ffestw_kill (ffestw_pop ());
+
+ ffe_terminate_2 ();
+ ffe_init_2 ();
+}
+
+/* ffestc_shriek_end_uses_ -- End a bunch of USE statements
+
+ ffestc_shriek_end_uses_(TRUE);
+
+ ok==TRUE means simply not popping due to ffestc_eof()
+ being called, because there is no formal END USES statement in Fortran. */
+
+#if FFESTR_F90
+static void
+ffestc_shriek_end_uses_ (bool ok)
+{
+ ffestd_end_uses (ok);
+
+ ffestw_kill (ffestw_pop ());
+}
+
+#endif
+/* ffestc_shriek_function_ -- End a FUNCTION
+
+ ffestc_shriek_function_(TRUE); */
+
+static void
+ffestc_shriek_function_ (bool ok)
+{
+ if (!ffesta_seen_first_exec)
+ {
+ ffesta_seen_first_exec = TRUE;
+ ffestd_exec_begin ();
+ }
+
+ ffestd_R1221 (ok);
+
+ ffestd_exec_end ();
+
+ ffelex_token_kill (ffestw_name (ffestw_stack_top ()));
+ ffestw_kill (ffestw_pop ());
+ ffesta_is_entry_valid = FALSE;
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffe_terminate_2 ();
+ ffe_init_2 ();
+ break;
+
+ default:
+ ffe_terminate_3 ();
+ ffe_init_3 ();
+ break;
+
+ case FFESTV_stateINTERFACE0:
+ ffe_terminate_4 ();
+ ffe_init_4 ();
+ break;
+ }
+}
+
+/* ffestc_shriek_if_ -- End of statement following logical IF
+
+ ffestc_shriek_if_(TRUE);
+
+ Applies ONLY to logical IF, not to IF-THEN. For example, does not
+ ffelex_token_kill the construct name for an IF-THEN block (the name
+ field is invalid for logical IF). ok==TRUE iff statement following
+ logical IF (substatement) is valid; else, statement is invalid or
+ stack forcibly popped due to ffestc_eof(). */
+
+static void
+ffestc_shriek_if_ (bool ok)
+{
+ ffestd_end_R807 (ok);
+
+ ffestw_kill (ffestw_pop ());
+ ffestc_shriek_after1_ = NULL;
+
+ ffestc_try_shriek_do_ ();
+}
+
+/* ffestc_shriek_ifthen_ -- End an IF-THEN
+
+ ffestc_shriek_ifthen_(TRUE); */
+
+static void
+ffestc_shriek_ifthen_ (bool ok)
+{
+ ffestd_R806 (ok);
+
+ if (ffestw_name (ffestw_stack_top ()) != NULL)
+ ffelex_token_kill (ffestw_name (ffestw_stack_top ()));
+ ffestw_kill (ffestw_pop ());
+
+ ffestc_try_shriek_do_ ();
+}
+
+/* ffestc_shriek_interface_ -- End an INTERFACE
+
+ ffestc_shriek_interface_(TRUE); */
+
+#if FFESTR_F90
+static void
+ffestc_shriek_interface_ (bool ok)
+{
+ ffestd_R1203 (ok);
+
+ ffestw_kill (ffestw_pop ());
+
+ ffestc_try_shriek_do_ ();
+}
+
+#endif
+/* ffestc_shriek_map_ -- End a MAP
+
+ ffestc_shriek_map_(TRUE); */
+
+#if FFESTR_VXT
+static void
+ffestc_shriek_map_ (bool ok)
+{
+ ffestd_V013 (ok);
+
+ ffestw_kill (ffestw_pop ());
+
+ ffestc_try_shriek_do_ ();
+}
+
+#endif
+/* ffestc_shriek_module_ -- End a MODULE
+
+ ffestc_shriek_module_(TRUE); */
+
+#if FFESTR_F90
+static void
+ffestc_shriek_module_ (bool ok)
+{
+ if (!ffesta_seen_first_exec)
+ {
+ ffesta_seen_first_exec = TRUE;
+ ffestd_exec_begin ();
+ }
+
+ ffestd_R1106 (ok);
+
+ ffestd_exec_end ();
+
+ ffelex_token_kill (ffestw_name (ffestw_stack_top ()));
+ ffestw_kill (ffestw_pop ());
+
+ ffe_terminate_2 ();
+ ffe_init_2 ();
+}
+
+#endif
+/* ffestc_shriek_select_ -- End a SELECT
+
+ ffestc_shriek_select_(TRUE); */
+
+static void
+ffestc_shriek_select_ (bool ok)
+{
+ ffestwSelect s;
+ ffestwCase c;
+
+ ffestd_R811 (ok);
+
+ if (ffestw_name (ffestw_stack_top ()) != NULL)
+ ffelex_token_kill (ffestw_name (ffestw_stack_top ()));
+ s = ffestw_select (ffestw_stack_top ());
+ ffelex_token_kill (s->t);
+ for (c = s->first_rel; c != (ffestwCase) &s->first_rel; c = c->next_rel)
+ ffelex_token_kill (c->t);
+ malloc_pool_kill (s->pool);
+
+ ffestw_kill (ffestw_pop ());
+
+ ffestc_try_shriek_do_ ();
+}
+
+/* ffestc_shriek_structure_ -- End a STRUCTURE
+
+ ffestc_shriek_structure_(TRUE); */
+
+#if FFESTR_VXT
+static void
+ffestc_shriek_structure_ (bool ok)
+{
+ ffestd_V004 (ok);
+
+ ffestw_kill (ffestw_pop ());
+
+ ffestc_try_shriek_do_ ();
+}
+
+#endif
+/* ffestc_shriek_subroutine_ -- End a SUBROUTINE
+
+ ffestc_shriek_subroutine_(TRUE); */
+
+static void
+ffestc_shriek_subroutine_ (bool ok)
+{
+ if (!ffesta_seen_first_exec)
+ {
+ ffesta_seen_first_exec = TRUE;
+ ffestd_exec_begin ();
+ }
+
+ ffestd_R1225 (ok);
+
+ ffestd_exec_end ();
+
+ ffelex_token_kill (ffestw_name (ffestw_stack_top ()));
+ ffestw_kill (ffestw_pop ());
+ ffesta_is_entry_valid = FALSE;
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffe_terminate_2 ();
+ ffe_init_2 ();
+ break;
+
+ default:
+ ffe_terminate_3 ();
+ ffe_init_3 ();
+ break;
+
+ case FFESTV_stateINTERFACE0:
+ ffe_terminate_4 ();
+ ffe_init_4 ();
+ break;
+ }
+}
+
+/* ffestc_shriek_type_ -- End a TYPE
+
+ ffestc_shriek_type_(TRUE); */
+
+#if FFESTR_F90
+static void
+ffestc_shriek_type_ (bool ok)
+{
+ ffestd_R425 (ok);
+
+ ffe_terminate_4 ();
+
+ ffelex_token_kill (ffestw_name (ffestw_stack_top ()));
+ ffestw_kill (ffestw_pop ());
+
+ ffestc_try_shriek_do_ ();
+}
+
+#endif
+/* ffestc_shriek_union_ -- End a UNION
+
+ ffestc_shriek_union_(TRUE); */
+
+#if FFESTR_VXT
+static void
+ffestc_shriek_union_ (bool ok)
+{
+ ffestd_V010 (ok);
+
+ ffestw_kill (ffestw_pop ());
+
+ ffestc_try_shriek_do_ ();
+}
+
+#endif
+/* ffestc_shriek_where_ -- Implicit END WHERE statement
+
+ ffestc_shriek_where_(TRUE);
+
+ Implement the end of the current WHERE "block". ok==TRUE iff statement
+ following WHERE (substatement) is valid; else, statement is invalid
+ or stack forcibly popped due to ffestc_eof(). */
+
+#if FFESTR_F90
+static void
+ffestc_shriek_where_ (bool ok)
+{
+ ffestd_R745 (ok);
+
+ ffestw_kill (ffestw_pop ());
+ ffestc_shriek_after1_ = NULL;
+ if (ffestw_state (ffestw_stack_top ()) == FFESTV_stateIF)
+ ffestc_shriek_if_ (TRUE); /* "IF (x) WHERE (y) stmt" is only valid
+ case. */
+
+ ffestc_try_shriek_do_ ();
+}
+
+#endif
+/* ffestc_shriek_wherethen_ -- End a WHERE(-THEN)
+
+ ffestc_shriek_wherethen_(TRUE); */
+
+#if FFESTR_F90
+static void
+ffestc_shriek_wherethen_ (bool ok)
+{
+ ffestd_end_R740 (ok);
+
+ ffestw_kill (ffestw_pop ());
+
+ ffestc_try_shriek_do_ ();
+}
+
+#endif
+/* ffestc_subr_binsrch_ -- Binary search of char const in list of strings
+
+ i = ffestc_subr_binsrch_(search_list,search_list_size,&spec,"etc");
+
+ search_list contains search_list_size char *'s, spec is checked to see
+ if it is a char constant and, if so, is binary-searched against the list.
+ 0 is returned if not found, else the "classic" index (beginning with 1)
+ is returned. Before returning 0 where the search was performed but
+ fruitless, if "etc" is a non-NULL char *, an error message is displayed
+ using "etc" as the pick-one-of-these string. */
+
+static int
+ffestc_subr_binsrch_ (char **list, int size, ffestpFile *spec, char *whine)
+{
+ int lowest_tested;
+ int highest_tested;
+ int halfway;
+ int offset;
+ int c;
+ char *str;
+ int len;
+
+ if (size == 0)
+ return 0; /* Nobody should pass size == 0, but for
+ elegance.... */
+
+ lowest_tested = -1;
+ highest_tested = size;
+ halfway = size >> 1;
+
+ list += halfway;
+
+ c = ffestc_subr_speccmp_ (*list, spec, &str, &len);
+ if (c == 2)
+ return 0;
+ c = -c; /* Sigh. */
+
+next: /* :::::::::::::::::::: */
+ switch (c)
+ {
+ case -1:
+ offset = (halfway - lowest_tested) >> 1;
+ if (offset == 0)
+ goto nope; /* :::::::::::::::::::: */
+ highest_tested = halfway;
+ list -= offset;
+ halfway -= offset;
+ c = ffesrc_strcmp_1ns2i (ffe_case_match (), str, len, *list);
+ goto next; /* :::::::::::::::::::: */
+
+ case 0:
+ return halfway + 1;
+
+ case 1:
+ offset = (highest_tested - halfway) >> 1;
+ if (offset == 0)
+ goto nope; /* :::::::::::::::::::: */
+ lowest_tested = halfway;
+ list += offset;
+ halfway += offset;
+ c = ffesrc_strcmp_1ns2i (ffe_case_match (), str, len, *list);
+ goto next; /* :::::::::::::::::::: */
+
+ default:
+ assert ("unexpected return from ffesrc_strcmp_1ns2i" == NULL);
+ break;
+ }
+
+nope: /* :::::::::::::::::::: */
+ ffebad_start (FFEBAD_SPEC_VALUE);
+ ffebad_here (0, ffelex_token_where_line (spec->value),
+ ffelex_token_where_column (spec->value));
+ ffebad_string (whine);
+ ffebad_finish ();
+ return 0;
+}
+
+/* ffestc_subr_format_ -- Return summary of format specifier
+
+ ffestc_subr_format_(&specifier); */
+
+static ffestvFormat
+ffestc_subr_format_ (ffestpFile *spec)
+{
+ if (!spec->kw_or_val_present)
+ return FFESTV_formatNONE;
+ assert (spec->value_present);
+ if (spec->value_is_label)
+ return FFESTV_formatLABEL; /* Ok if not a label. */
+
+ assert (spec->value != NULL);
+ if (ffebld_op (spec->u.expr) == FFEBLD_opSTAR)
+ return FFESTV_formatASTERISK;
+
+ if (ffeinfo_kind (ffebld_info (spec->u.expr)) == FFEINFO_kindNAMELIST)
+ return FFESTV_formatNAMELIST;
+
+ if (ffeinfo_rank (ffebld_info (spec->u.expr)) != 0)
+ return FFESTV_formatCHAREXPR; /* F77 C5. */
+
+ switch (ffeinfo_basictype (ffebld_info (spec->u.expr)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ return FFESTV_formatINTEXPR;
+
+ case FFEINFO_basictypeCHARACTER:
+ return FFESTV_formatCHAREXPR;
+
+ case FFEINFO_basictypeANY:
+ return FFESTV_formatASTERISK;
+
+ default:
+ assert ("bad basictype" == NULL);
+ return FFESTV_formatINTEXPR;
+ }
+}
+
+/* ffestc_subr_is_branch_ -- Handle specifier as branch target label
+
+ ffestc_subr_is_branch_(&specifier); */
+
+static bool
+ffestc_subr_is_branch_ (ffestpFile *spec)
+{
+ if (!spec->kw_or_val_present)
+ return TRUE;
+ assert (spec->value_present);
+ assert (spec->value_is_label);
+ spec->value_is_label++; /* For checking purposes only; 1=>2. */
+ return ffestc_labelref_is_branch_ (spec->value, &spec->u.label);
+}
+
+/* ffestc_subr_is_format_ -- Handle specifier as format target label
+
+ ffestc_subr_is_format_(&specifier); */
+
+static bool
+ffestc_subr_is_format_ (ffestpFile *spec)
+{
+ if (!spec->kw_or_val_present)
+ return TRUE;
+ assert (spec->value_present);
+ if (!spec->value_is_label)
+ return TRUE; /* Ok if not a label. */
+
+ spec->value_is_label++; /* For checking purposes only; 1=>2. */
+ return ffestc_labelref_is_format_ (spec->value, &spec->u.label);
+}
+
+/* ffestc_subr_is_present_ -- Ensure specifier is present, else error
+
+ ffestc_subr_is_present_("SPECIFIER",&specifier); */
+
+static bool
+ffestc_subr_is_present_ (char *name, ffestpFile *spec)
+{
+ if (spec->kw_or_val_present)
+ {
+ assert (spec->value_present);
+ return TRUE;
+ }
+
+ ffebad_start (FFEBAD_MISSING_SPECIFIER);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_string (name);
+ ffebad_finish ();
+ return FALSE;
+}
+
+/* ffestc_subr_speccmp_ -- Compare string to constant expression, if present
+
+ if (ffestc_subr_speccmp_("Constant",&specifier,NULL,NULL) == 0)
+ // specifier value is present and is a char constant "CONSTANT"
+
+ Like strcmp, except the return values are defined as: -1 returned in place
+ of strcmp's generic negative value, 1 in place of it's generic positive
+ value, and 2 when there is no character constant string to compare. Also,
+ a case-insensitive comparison is performed, where string is assumed to
+ already be in InitialCaps form.
+
+ If a non-NULL pointer is provided as the char **target, then *target is
+ written with NULL if 2 is returned, a pointer to the constant string
+ value of the specifier otherwise. Similarly, length is written with
+ 0 if 2 is returned, the length of the constant string value otherwise. */
+
+static int
+ffestc_subr_speccmp_ (char *string, ffestpFile *spec, char **target,
+ int *length)
+{
+ ffebldConstant c;
+ int i;
+
+ if (!spec->kw_or_val_present || !spec->value_present
+ || (spec->u.expr == NULL)
+ || (ffebld_op (spec->u.expr) != FFEBLD_opCONTER))
+ {
+ if (target != NULL)
+ *target = NULL;
+ if (length != NULL)
+ *length = 0;
+ return 2;
+ }
+
+ if (ffebld_constant_type (c = ffebld_conter (spec->u.expr))
+ != FFEBLD_constCHARACTERDEFAULT)
+ {
+ if (target != NULL)
+ *target = NULL;
+ if (length != NULL)
+ *length = 0;
+ return 2;
+ }
+
+ if (target != NULL)
+ *target = ffebld_constant_characterdefault (c).text;
+ if (length != NULL)
+ *length = ffebld_constant_characterdefault (c).length;
+
+ i = ffesrc_strcmp_1ns2i (ffe_case_match (),
+ ffebld_constant_characterdefault (c).text,
+ ffebld_constant_characterdefault (c).length,
+ string);
+ if (i == 0)
+ return 0;
+ if (i > 0)
+ return -1; /* Yes indeed, we reverse the strings to
+ _strcmpin_. */
+ return 1;
+}
+
+/* ffestc_subr_unit_ -- Return summary of unit specifier
+
+ ffestc_subr_unit_(&specifier); */
+
+static ffestvUnit
+ffestc_subr_unit_ (ffestpFile *spec)
+{
+ if (!spec->kw_or_val_present)
+ return FFESTV_unitNONE;
+ assert (spec->value_present);
+ assert (spec->value != NULL);
+
+ if (ffebld_op (spec->u.expr) == FFEBLD_opSTAR)
+ return FFESTV_unitASTERISK;
+
+ switch (ffeinfo_basictype (ffebld_info (spec->u.expr)))
+ {
+ case FFEINFO_basictypeINTEGER:
+ return FFESTV_unitINTEXPR;
+
+ case FFEINFO_basictypeCHARACTER:
+ return FFESTV_unitCHAREXPR;
+
+ case FFEINFO_basictypeANY:
+ return FFESTV_unitASTERISK;
+
+ default:
+ assert ("bad basictype" == NULL);
+ return FFESTV_unitINTEXPR;
+ }
+}
+
+/* Call this function whenever it's possible that one or more top
+ stack items are label-targeting DO blocks that have had their
+ labels defined, but at a time when they weren't at the top of the
+ stack. This prevents uninformative diagnostics for programs
+ like "DO 10", "IF (...) THEN", "10 ELSE", "END IF", "END". */
+
+static void
+ffestc_try_shriek_do_ ()
+{
+ ffelab lab;
+ ffelabType ty;
+
+ while ((ffestw_state (ffestw_stack_top ()) == FFESTV_stateDO)
+ && ((lab = (ffestw_label (ffestw_stack_top ()))) != NULL)
+ && (((ty = (ffelab_type (lab)))
+ == FFELAB_typeANY)
+ || (ty == FFELAB_typeUSELESS)
+ || (ty == FFELAB_typeFORMAT)
+ || (ty == FFELAB_typeNOTLOOP)
+ || (ty == FFELAB_typeENDIF)))
+ ffestc_shriek_do_ (FALSE);
+}
+
+/* ffestc_decl_start -- R426 or R501
+
+ ffestc_decl_start(...);
+
+ Verify that R426 component-def-stmt or R501 type-declaration-stmt are
+ valid here, figure out which one, and implement. */
+
+void
+ffestc_decl_start (ffestpType type, ffelexToken typet, ffebld kind,
+ ffelexToken kindt, ffebld len, ffelexToken lent)
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ case FFESTV_statePROGRAM0:
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_statePROGRAM1:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateBLOCKDATA1:
+ case FFESTV_statePROGRAM2:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateMODULE2:
+ case FFESTV_stateBLOCKDATA2:
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateMODULE3:
+ case FFESTV_stateBLOCKDATA3:
+ case FFESTV_stateUSE:
+ ffestc_local_.decl.is_R426 = 2;
+ break;
+
+ case FFESTV_stateTYPE:
+ case FFESTV_stateSTRUCTURE:
+ case FFESTV_stateMAP:
+ ffestc_local_.decl.is_R426 = 1;
+ break;
+
+ default:
+ ffestc_order_bad_ ();
+ ffestc_labeldef_useless_ ();
+ ffestc_local_.decl.is_R426 = 0;
+ return;
+ }
+
+ switch (ffestc_local_.decl.is_R426)
+ {
+#if FFESTR_F90
+ case 1:
+ ffestc_R426_start (type, typet, kind, kindt, len, lent);
+ break;
+#endif
+
+ case 2:
+ ffestc_R501_start (type, typet, kind, kindt, len, lent);
+ break;
+
+ default:
+ ffestc_labeldef_useless_ ();
+ break;
+ }
+}
+
+/* ffestc_decl_attrib -- R426 or R501 type attribute
+
+ ffestc_decl_attrib(...);
+
+ Verify that R426 component-def-stmt or R501 type-declaration-stmt attribute
+ is valid here and implement. */
+
+void
+ffestc_decl_attrib (ffestpAttrib attrib UNUSED,
+ ffelexToken attribt UNUSED,
+ ffestrOther intent_kw UNUSED,
+ ffesttDimList dims UNUSED)
+{
+#if FFESTR_F90
+ switch (ffestc_local_.decl.is_R426)
+ {
+ case 1:
+ ffestc_R426_attrib (attrib, attribt, intent_kw, dims);
+ break;
+
+ case 2:
+ ffestc_R501_attrib (attrib, attribt, intent_kw, dims);
+ break;
+
+ default:
+ break;
+ }
+#else
+ ffebad_start (FFEBAD_F90);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ return;
+#endif
+}
+
+/* ffestc_decl_item -- R426 or R501
+
+ ffestc_decl_item(...);
+
+ Establish type for a particular object. */
+
+void
+ffestc_decl_item (ffelexToken name, ffebld kind, ffelexToken kindt,
+ ffesttDimList dims, ffebld len, ffelexToken lent, ffebld init,
+ ffelexToken initt, bool clist)
+{
+ switch (ffestc_local_.decl.is_R426)
+ {
+#if FFESTR_F90
+ case 1:
+ ffestc_R426_item (name, kind, kindt, dims, len, lent, init, initt,
+ clist);
+ break;
+#endif
+
+ case 2:
+ ffestc_R501_item (name, kind, kindt, dims, len, lent, init, initt,
+ clist);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* ffestc_decl_itemstartvals -- R426 or R501 start list of values
+
+ ffestc_decl_itemstartvals();
+
+ Gonna specify values for the object now. */
+
+void
+ffestc_decl_itemstartvals ()
+{
+ switch (ffestc_local_.decl.is_R426)
+ {
+#if FFESTR_F90
+ case 1:
+ ffestc_R426_itemstartvals ();
+ break;
+#endif
+
+ case 2:
+ ffestc_R501_itemstartvals ();
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* ffestc_decl_itemvalue -- R426 or R501 source value
+
+ ffestc_decl_itemvalue(repeat,repeat_token,value,value_token);
+
+ Make sure repeat and value are valid for the object being initialized. */
+
+void
+ffestc_decl_itemvalue (ffebld repeat, ffelexToken repeat_token,
+ ffebld value, ffelexToken value_token)
+{
+ switch (ffestc_local_.decl.is_R426)
+ {
+#if FFESTR_F90
+ case 1:
+ ffestc_R426_itemvalue (repeat, repeat_token, value, value_token);
+ break;
+#endif
+
+ case 2:
+ ffestc_R501_itemvalue (repeat, repeat_token, value, value_token);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* ffestc_decl_itemendvals -- R426 or R501 end list of values
+
+ ffelexToken t; // the SLASH token that ends the list.
+ ffestc_decl_itemendvals(t);
+
+ No more values, might specify more objects now. */
+
+void
+ffestc_decl_itemendvals (ffelexToken t)
+{
+ switch (ffestc_local_.decl.is_R426)
+ {
+#if FFESTR_F90
+ case 1:
+ ffestc_R426_itemendvals (t);
+ break;
+#endif
+
+ case 2:
+ ffestc_R501_itemendvals (t);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* ffestc_decl_finish -- R426 or R501
+
+ ffestc_decl_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_decl_finish ()
+{
+ switch (ffestc_local_.decl.is_R426)
+ {
+#if FFESTR_F90
+ case 1:
+ ffestc_R426_finish ();
+ break;
+#endif
+
+ case 2:
+ ffestc_R501_finish ();
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* ffestc_elsewhere -- Generic ELSE WHERE statement
+
+ ffestc_end();
+
+ Decide whether ELSEWHERE or ELSE w/if-construct-name=="WHERE" is meant. */
+
+void
+ffestc_elsewhere (ffelexToken where)
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateIFTHEN:
+ ffestc_R805 (where);
+ break;
+
+ default:
+#if FFESTR_F90
+ ffestc_R744 ();
+#endif
+ break;
+ }
+}
+
+/* ffestc_end -- Generic END statement
+
+ ffestc_end();
+
+ Make sure a generic END is valid in the current context, and implement
+ it. */
+
+void
+ffestc_end ()
+{
+ ffestw b;
+
+ b = ffestw_stack_top ();
+
+recurse:
+
+ switch (ffestw_state (b))
+ {
+ case FFESTV_stateBLOCKDATA0:
+ case FFESTV_stateBLOCKDATA1:
+ case FFESTV_stateBLOCKDATA2:
+ case FFESTV_stateBLOCKDATA3:
+ case FFESTV_stateBLOCKDATA4:
+ case FFESTV_stateBLOCKDATA5:
+ ffestc_R1112 (NULL);
+ break;
+
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateFUNCTION4:
+ case FFESTV_stateFUNCTION5:
+ if ((ffestw_state (ffestw_previous (b)) != FFESTV_stateNIL)
+ && (ffestw_state (ffestw_previous (b)) != FFESTV_stateINTERFACE0))
+ {
+ ffebad_start (FFEBAD_END_WO);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_previous (b)), ffestw_col (ffestw_previous (b)));
+ ffebad_string ("FUNCTION");
+ ffebad_finish ();
+ }
+ ffestc_R1221 (NULL);
+ break;
+
+ case FFESTV_stateMODULE0:
+ case FFESTV_stateMODULE1:
+ case FFESTV_stateMODULE2:
+ case FFESTV_stateMODULE3:
+ case FFESTV_stateMODULE4:
+ case FFESTV_stateMODULE5:
+#if FFESTR_F90
+ ffestc_R1106 (NULL);
+#endif
+ break;
+
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateSUBROUTINE5:
+ if ((ffestw_state (ffestw_previous (b)) != FFESTV_stateNIL)
+ && (ffestw_state (ffestw_previous (b)) != FFESTV_stateINTERFACE0))
+ {
+ ffebad_start (FFEBAD_END_WO);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_previous (b)), ffestw_col (ffestw_previous (b)));
+ ffebad_string ("SUBROUTINE");
+ ffebad_finish ();
+ }
+ ffestc_R1225 (NULL);
+ break;
+
+ case FFESTV_stateUSE:
+ b = ffestw_previous (ffestw_stack_top ());
+ goto recurse; /* :::::::::::::::::::: */
+
+ default:
+ ffestc_R1103 (NULL);
+ break;
+ }
+}
+
+/* ffestc_eof -- Generic EOF
+
+ ffestc_eof();
+
+ Make sure we're at state NIL, or issue an error message and use each
+ block's shriek function to clean up to state NIL. */
+
+void
+ffestc_eof ()
+{
+ if (ffestw_state (ffestw_stack_top ()) != FFESTV_stateNIL)
+ {
+ ffebad_start (FFEBAD_EOF_BEFORE_BLOCK_END);
+ ffebad_here (0, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ do
+ (*ffestw_shriek (ffestw_stack_top ()))(FALSE);
+ while (ffestw_state (ffestw_stack_top ()) != FFESTV_stateNIL);
+ }
+}
+
+/* ffestc_exec_transition -- Check if ok and move stmt state to executable
+
+ if (ffestc_exec_transition())
+ // Transition successful (kind of like a CONTINUE stmt was seen).
+
+ If the current statement state is a non-nested specification state in
+ which, say, a CONTINUE statement would be valid, then enter the state
+ we'd be in after seeing CONTINUE (without, of course, generating any
+ CONTINUE code), call ffestd_exec_begin, and return TRUE. Otherwise
+ return FALSE.
+
+ This function cannot be invoked once the first executable statement
+ is seen. This function may choose to always return TRUE by shrieking
+ away any interceding state stack entries to reach the base level of
+ specification state, but right now it doesn't, and it is (or should
+ be) purely an issue of how one wishes errors to be handled (for example,
+ an unrecognized statement in the middle of a STRUCTURE construct: after
+ the error message, should subsequent statements still be interpreted as
+ being within the construct, or should the construct be terminated upon
+ seeing the unrecognized statement? we do the former at the moment). */
+
+bool
+ffestc_exec_transition ()
+{
+ bool update;
+
+recurse:
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ ffestc_shriek_begin_program_ ();
+ goto recurse; /* :::::::::::::::::::: */
+
+ case FFESTV_statePROGRAM0:
+ case FFESTV_stateSUBROUTINE0:
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateBLOCKDATA0:
+ ffestw_state (ffestw_stack_top ()) += 4; /* To state UNIT4. */
+ update = TRUE;
+ break;
+
+ case FFESTV_statePROGRAM1:
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateBLOCKDATA1:
+ ffestw_state (ffestw_stack_top ()) += 3; /* To state UNIT4. */
+ update = TRUE;
+ break;
+
+ case FFESTV_statePROGRAM2:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateBLOCKDATA2:
+ ffestw_state (ffestw_stack_top ()) += 2; /* To state UNIT4. */
+ update = TRUE;
+ break;
+
+ case FFESTV_statePROGRAM3:
+ case FFESTV_stateSUBROUTINE3:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateBLOCKDATA3:
+ ffestw_state (ffestw_stack_top ()) += 1; /* To state UNIT4. */
+ update = TRUE;
+ break;
+
+ case FFESTV_stateUSE:
+#if FFESTR_F90
+ ffestc_shriek_end_uses_ (TRUE);
+#endif
+ goto recurse; /* :::::::::::::::::::: */
+
+ default:
+ return FALSE;
+ }
+
+ if (update)
+ ffestw_update (NULL); /* Update state line/col info. */
+
+ ffesta_seen_first_exec = TRUE;
+ ffestd_exec_begin ();
+
+ return TRUE;
+}
+
+/* ffestc_ffebad_here_doiter -- Calls ffebad_here with ptr to DO iter var
+
+ ffesymbol s;
+ // call ffebad_start first, of course.
+ ffestc_ffebad_here_doiter(0,s);
+ // call ffebad_finish afterwards, naturally.
+
+ Searches the stack of blocks backwards for a DO loop that has s
+ as its iteration variable, then calls ffebad_here with pointers to
+ that particular reference to the variable. Crashes if the DO loop
+ can't be found. */
+
+void
+ffestc_ffebad_here_doiter (ffebadIndex i, ffesymbol s)
+{
+ ffestw block;
+
+ for (block = ffestw_top_do (ffestw_stack_top ());
+ (block != NULL) && (ffestw_blocknum (block) != 0);
+ block = ffestw_top_do (ffestw_previous (block)))
+ {
+ if (ffestw_do_iter_var (block) == s)
+ {
+ ffebad_here (i, ffelex_token_where_line (ffestw_do_iter_var_t (block)),
+ ffelex_token_where_column (ffestw_do_iter_var_t (block)));
+ return;
+ }
+ }
+ assert ("no do block found" == NULL);
+}
+
+/* ffestc_is_decl_not_R1219 -- Context information for FFESTB
+
+ if (ffestc_is_decl_not_R1219()) ...
+
+ When a statement with the form "type[RECURSIVE]FUNCTIONname(name-list)"
+ is seen, call this function. It returns TRUE if the statement's context
+ is such that it is a declaration of an object named
+ "[RECURSIVE]FUNCTIONname" with an array-decl spec of "name-list", FALSE
+ if the statement's context is such that it begins the definition of a
+ function named "name" havin the dummy argument list "name-list" (this
+ is the R1219 function-stmt case). */
+
+bool
+ffestc_is_decl_not_R1219 ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateNIL:
+ case FFESTV_statePROGRAM5:
+ case FFESTV_stateSUBROUTINE5:
+ case FFESTV_stateFUNCTION5:
+ case FFESTV_stateMODULE5:
+ case FFESTV_stateINTERFACE0:
+ return FALSE;
+
+ default:
+ return TRUE;
+ }
+}
+
+/* ffestc_is_entry_in_subr -- Context information for FFESTB
+
+ if (ffestc_is_entry_in_subr()) ...
+
+ When a statement with the form "ENTRY name(name-list)"
+ is seen, call this function. It returns TRUE if the statement's context
+ is such that it may have "*", meaning alternate return, in place of
+ names in the name list (i.e. if the ENTRY is in a subroutine context).
+ It also returns TRUE if the ENTRY is not in a function context (invalid
+ but prevents extra complaints about "*", if present). It returns FALSE
+ if the ENTRY is in a function context. */
+
+bool
+ffestc_is_entry_in_subr ()
+{
+ ffestvState s;
+
+ s = ffestw_state (ffestw_stack_top ());
+
+recurse:
+
+ switch (s)
+ {
+ case FFESTV_stateFUNCTION0:
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateFUNCTION3:
+ case FFESTV_stateFUNCTION4:
+ return FALSE;
+
+ case FFESTV_stateUSE:
+ s = ffestw_state (ffestw_previous (ffestw_stack_top ()));
+ goto recurse; /* :::::::::::::::::::: */
+
+ default:
+ return TRUE;
+ }
+}
+
+/* ffestc_is_let_not_V027 -- Context information for FFESTB
+
+ if (ffestc_is_let_not_V027()) ...
+
+ When a statement with the form "PARAMETERname=expr"
+ is seen, call this function. It returns TRUE if the statement's context
+ is such that it is an assignment to an object named "PARAMETERname", FALSE
+ if the statement's context is such that it is a V-extension PARAMETER
+ statement that is like a PARAMETER(name=expr) statement except that the
+ type of name is determined by the type of expr, not the implicit or
+ explicit typing of name. */
+
+bool
+ffestc_is_let_not_V027 ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_statePROGRAM4:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateFUNCTION4:
+ case FFESTV_stateWHERETHEN:
+ case FFESTV_stateIFTHEN:
+ case FFESTV_stateDO:
+ case FFESTV_stateSELECT0:
+ case FFESTV_stateSELECT1:
+ case FFESTV_stateWHERE:
+ case FFESTV_stateIF:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+/* ffestc_module -- MODULE or MODULE PROCEDURE statement
+
+ ffestc_module(module_name_token,procedure_name_token);
+
+ Decide which is intended, and implement it by calling _R1105_ or
+ _R1205_. */
+
+#if FFESTR_F90
+void
+ffestc_module (ffelexToken module, ffelexToken procedure)
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateINTERFACE0:
+ case FFESTV_stateINTERFACE1:
+ ffestc_R1205_start ();
+ ffestc_R1205_item (procedure);
+ ffestc_R1205_finish ();
+ break;
+
+ default:
+ ffestc_R1105 (module);
+ break;
+ }
+}
+
+#endif
+/* ffestc_private -- Generic PRIVATE statement
+
+ ffestc_end();
+
+ This is either a PRIVATE within R422 derived-type statement or an
+ R521 PRIVATE statement. Figure it out based on context and implement
+ it, or produce an error. */
+
+#if FFESTR_F90
+void
+ffestc_private ()
+{
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateTYPE:
+ ffestc_R423A ();
+ break;
+
+ default:
+ ffestc_R521B ();
+ break;
+ }
+}
+
+#endif
+/* ffestc_terminate_4 -- Terminate ffestc after scoping unit
+
+ ffestc_terminate_4();
+
+ For SUBROUTINEs/FUNCTIONs within INTERFACE/END INTERFACE, derived-TYPE-
+ defs, and statement function defs. */
+
+void
+ffestc_terminate_4 ()
+{
+ ffestc_entry_num_ = ffestc_saved_entry_num_;
+}
+
+/* ffestc_R423A -- PRIVATE statement (in R422 derived-type statement)
+
+ ffestc_R423A(); */
+
+#if FFESTR_F90
+void
+ffestc_R423A ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_type_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (ffestw_substate (ffestw_stack_top ()) != 0)
+ {
+ ffebad_start (FFEBAD_DERIVTYP_ACCESS_FIRST);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ return;
+ }
+
+ if (ffestw_state (ffestw_previous (ffestw_stack_top ())) != FFESTV_stateMODULE3)
+ {
+ ffebad_start (FFEBAD_DERIVTYP_ACCESS);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ return;
+ }
+
+ ffestw_set_substate (ffestw_stack_top (), 1); /* Seen
+ private-sequence-stmt. */
+
+ ffestd_R423A ();
+}
+
+/* ffestc_R423B -- SEQUENCE statement (in R422 derived-type-stmt)
+
+ ffestc_R423B(); */
+
+void
+ffestc_R423B ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_type_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (ffestw_substate (ffestw_stack_top ()) != 0)
+ {
+ ffebad_start (FFEBAD_DERIVTYP_ACCESS_FIRST);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ return;
+ }
+
+ ffestw_set_substate (ffestw_stack_top (), 1); /* Seen
+ private-sequence-stmt. */
+
+ ffestd_R423B ();
+}
+
+/* ffestc_R424 -- derived-TYPE-def statement
+
+ ffestc_R424(access_token,access_kw,name_token);
+
+ Handle a derived-type definition. */
+
+void
+ffestc_R424 (ffelexToken access, ffestrOther access_kw, ffelexToken name)
+{
+ ffestw b;
+
+ assert (name != NULL);
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_derivedtype_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if ((access != NULL)
+ && (ffestw_state (ffestw_stack_top ()) != FFESTV_stateMODULE3))
+ {
+ ffebad_start (FFEBAD_DERIVTYP_ACCESS);
+ ffebad_here (0, ffelex_token_where_line (access),
+ ffelex_token_where_column (access));
+ ffebad_finish ();
+ access = NULL;
+ }
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_stateTYPE);
+ ffestw_set_blocknum (b, 0);
+ ffestw_set_shriek (b, ffestc_shriek_type_);
+ ffestw_set_name (b, ffelex_token_use (name));
+ ffestw_set_substate (b, 0); /* Awaiting private-sequence-stmt and one
+ component-def-stmt. */
+
+ ffestd_R424 (access, access_kw, name);
+
+ ffe_init_4 ();
+}
+
+/* ffestc_R425 -- END TYPE statement
+
+ ffestc_R425(name_token);
+
+ Make sure ffestc_kind_ identifies a TYPE definition. If not
+ NULL, make sure name_token gives the correct name. Implement the end
+ of the type definition. */
+
+void
+ffestc_R425 (ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_type_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (ffestw_substate (ffestw_stack_top ()) != 2)
+ {
+ ffebad_start (FFEBAD_DERIVTYP_NO_COMPONENTS);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+
+ if ((name != NULL)
+ && (ffelex_token_strcmp (name, ffestw_name (ffestw_stack_top ())) != 0))
+ {
+ ffebad_start (FFEBAD_TYPE_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+
+ ffestc_shriek_type_ (TRUE);
+}
+
+/* ffestc_R426_start -- component-declaration-stmt
+
+ ffestc_R426_start(...);
+
+ Verify that R426 component-declaration-stmt is
+ valid here and implement. */
+
+void
+ffestc_R426_start (ffestpType type, ffelexToken typet, ffebld kind,
+ ffelexToken kindt, ffebld len, ffelexToken lent)
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_component_ () != FFESTC_orderOK_)
+ {
+ ffestc_local_.decl.is_R426 = 0;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateSTRUCTURE:
+ case FFESTV_stateMAP:
+ ffestw_set_substate (ffestw_stack_top (), 1); /* Seen at least one
+ member. */
+ break;
+
+ case FFESTV_stateTYPE:
+ ffestw_set_substate (ffestw_stack_top (), 2);
+ break;
+
+ default:
+ assert ("Component parent state invalid" == NULL);
+ break;
+ }
+}
+
+/* ffestc_R426_attrib -- type attribute
+
+ ffestc_R426_attrib(...);
+
+ Verify that R426 component-declaration-stmt attribute
+ is valid here and implement. */
+
+void
+ffestc_R426_attrib (ffestpAttrib attrib, ffelexToken attribt,
+ ffestrOther intent_kw, ffesttDimList dims)
+{
+ ffestc_check_attrib_ ();
+}
+
+/* ffestc_R426_item -- declared object
+
+ ffestc_R426_item(...);
+
+ Establish type for a particular object. */
+
+void
+ffestc_R426_item (ffelexToken name, ffebld kind, ffelexToken kindt,
+ ffesttDimList dims, ffebld len, ffelexToken lent, ffebld init,
+ ffelexToken initt, bool clist)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ assert (ffelex_token_type (name) == FFELEX_typeNAME); /* Not NAMES. */
+ assert (kind == NULL); /* No way an expression should get here. */
+
+ if ((dims != NULL) || (init != NULL) || clist)
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+}
+
+/* ffestc_R426_itemstartvals -- Start list of values
+
+ ffestc_R426_itemstartvals();
+
+ Gonna specify values for the object now. */
+
+void
+ffestc_R426_itemstartvals ()
+{
+ ffestc_check_item_startvals_ ();
+}
+
+/* ffestc_R426_itemvalue -- Source value
+
+ ffestc_R426_itemvalue(repeat,repeat_token,value,value_token);
+
+ Make sure repeat and value are valid for the object being initialized. */
+
+void
+ffestc_R426_itemvalue (ffebld repeat, ffelexToken repeat_token,
+ ffebld value, ffelexToken value_token)
+{
+ ffestc_check_item_value_ ();
+}
+
+/* ffestc_R426_itemendvals -- End list of values
+
+ ffelexToken t; // the SLASH token that ends the list.
+ ffestc_R426_itemendvals(t);
+
+ No more values, might specify more objects now. */
+
+void
+ffestc_R426_itemendvals (ffelexToken t)
+{
+ ffestc_check_item_endvals_ ();
+}
+
+/* ffestc_R426_finish -- Done
+
+ ffestc_R426_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R426_finish ()
+{
+ ffestc_check_finish_ ();
+}
+
+#endif
+/* ffestc_R501_start -- type-declaration-stmt
+
+ ffestc_R501_start(...);
+
+ Verify that R501 type-declaration-stmt is
+ valid here and implement. */
+
+void
+ffestc_R501_start (ffestpType type, ffelexToken typet, ffebld kind,
+ ffelexToken kindt, ffebld len, ffelexToken lent)
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_typedecl_ () != FFESTC_orderOK_)
+ {
+ ffestc_local_.decl.is_R426 = 0;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestc_establish_declstmt_ (type, typet, kind, kindt, len, lent);
+}
+
+/* ffestc_R501_attrib -- type attribute
+
+ ffestc_R501_attrib(...);
+
+ Verify that R501 type-declaration-stmt attribute
+ is valid here and implement. */
+
+void
+ffestc_R501_attrib (ffestpAttrib attrib, ffelexToken attribt,
+ ffestrOther intent_kw UNUSED,
+ ffesttDimList dims UNUSED)
+{
+ ffestc_check_attrib_ ();
+
+ switch (attrib)
+ {
+#if FFESTR_F90
+ case FFESTP_attribALLOCATABLE:
+ break;
+#endif
+
+ case FFESTP_attribDIMENSION:
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ break;
+
+ case FFESTP_attribEXTERNAL:
+ break;
+
+#if FFESTR_F90
+ case FFESTP_attribINTENT:
+ break;
+#endif
+
+ case FFESTP_attribINTRINSIC:
+ break;
+
+#if FFESTR_F90
+ case FFESTP_attribOPTIONAL:
+ break;
+#endif
+
+ case FFESTP_attribPARAMETER:
+ break;
+
+#if FFESTR_F90
+ case FFESTP_attribPOINTER:
+ break;
+#endif
+
+#if FFESTR_F90
+ case FFESTP_attribPRIVATE:
+ break;
+
+ case FFESTP_attribPUBLIC:
+ break;
+#endif
+
+ case FFESTP_attribSAVE:
+ switch (ffestv_save_state_)
+ {
+ case FFESTV_savestateNONE:
+ ffestv_save_state_ = FFESTV_savestateSPECIFIC;
+ ffestv_save_line_
+ = ffewhere_line_use (ffelex_token_where_line (attribt));
+ ffestv_save_col_
+ = ffewhere_column_use (ffelex_token_where_column (attribt));
+ break;
+
+ case FFESTV_savestateSPECIFIC:
+ case FFESTV_savestateANY:
+ break;
+
+ case FFESTV_savestateALL:
+ if (ffe_is_pedantic ())
+ {
+ ffebad_start (FFEBAD_CONFLICTING_SAVES);
+ ffebad_here (0, ffestv_save_line_, ffestv_save_col_);
+ ffebad_here (1, ffelex_token_where_line (attribt),
+ ffelex_token_where_column (attribt));
+ ffebad_finish ();
+ }
+ ffestv_save_state_ = FFESTV_savestateANY;
+ break;
+
+ default:
+ assert ("unexpected save state" == NULL);
+ break;
+ }
+ break;
+
+#if FFESTR_F90
+ case FFESTP_attribTARGET:
+ break;
+#endif
+
+ default:
+ assert ("unexpected attribute" == NULL);
+ break;
+ }
+}
+
+/* ffestc_R501_item -- declared object
+
+ ffestc_R501_item(...);
+
+ Establish type for a particular object. */
+
+void
+ffestc_R501_item (ffelexToken name, ffebld kind, ffelexToken kindt,
+ ffesttDimList dims, ffebld len, ffelexToken lent,
+ ffebld init, ffelexToken initt, bool clist)
+{
+ ffesymbol s;
+ ffesymbol sfn; /* FUNCTION symbol. */
+ ffebld array_size;
+ ffebld extents;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffestpDimtype nd;
+ bool is_init = (init != NULL) || clist;
+ bool is_assumed;
+ bool is_ugly_assumed;
+ ffeinfoRank rank;
+
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ assert (ffelex_token_type (name) == FFELEX_typeNAME); /* Not NAMES. */
+ assert (kind == NULL); /* No way an expression should get here. */
+
+ ffestc_establish_declinfo_ (kind, kindt, len, lent);
+
+ is_assumed = (ffestc_local_.decl.basic_type == FFEINFO_basictypeCHARACTER)
+ && (ffestc_local_.decl.size == FFETARGET_charactersizeNONE);
+
+ if ((dims != NULL) || is_init)
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+ s = ffesymbol_declare_local (name, TRUE);
+ sa = ffesymbol_attrs (s);
+
+ /* First figure out what kind of object this is based solely on the current
+ object situation (type params, dimension list, and initialization). */
+
+ na = FFESYMBOL_attrsTYPE;
+
+ if (is_assumed)
+ na |= FFESYMBOL_attrsANYLEN;
+
+ is_ugly_assumed = (ffe_is_ugly_assumed ()
+ && ((sa & FFESYMBOL_attrsDUMMY)
+ || (ffesymbol_where (s) == FFEINFO_whereDUMMY)));
+
+ nd = ffestt_dimlist_type (dims, is_ugly_assumed);
+ switch (nd)
+ {
+ case FFESTP_dimtypeNONE:
+ break;
+
+ case FFESTP_dimtypeKNOWN:
+ na |= FFESYMBOL_attrsARRAY;
+ break;
+
+ case FFESTP_dimtypeADJUSTABLE:
+ na |= FFESYMBOL_attrsARRAY | FFESYMBOL_attrsADJUSTABLE;
+ break;
+
+ case FFESTP_dimtypeASSUMED:
+ na |= FFESYMBOL_attrsARRAY | FFESYMBOL_attrsANYSIZE;
+ break;
+
+ case FFESTP_dimtypeADJUSTABLEASSUMED:
+ na |= FFESYMBOL_attrsARRAY | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYSIZE;
+ break;
+
+ default:
+ assert ("unexpected dimtype" == NULL);
+ na = FFESYMBOL_attrsetNONE;
+ break;
+ }
+
+ if (!ffesta_is_entry_valid
+ && (((na & (FFESYMBOL_attrsANYLEN | FFESYMBOL_attrsARRAY))
+ == (FFESYMBOL_attrsANYLEN | FFESYMBOL_attrsARRAY))))
+ na = FFESYMBOL_attrsetNONE;
+
+ if (is_init)
+ {
+ if (na == FFESYMBOL_attrsetNONE)
+ ;
+ else if (na & (FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYSIZE))
+ na = FFESYMBOL_attrsetNONE;
+ else
+ na |= FFESYMBOL_attrsINIT;
+ }
+
+ /* Now figure out what kind of object we've got based on previous
+ declarations of or references to the object. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ;
+ else if (!ffesymbol_is_specable (s)
+ && (((ffesymbol_where (s) != FFEINFO_whereCONSTANT)
+ && (ffesymbol_where (s) != FFEINFO_whereINTRINSIC))
+ || (na & (FFESYMBOL_attrsARRAY | FFESYMBOL_attrsINIT))))
+ na = FFESYMBOL_attrsetNONE; /* Can't dcl sym ref'd in sfuncdef, and can't
+ dimension/init UNDERSTOODs. */
+ else if (sa & FFESYMBOL_attrsANY)
+ na = sa;
+ else if ((sa & na)
+ || ((sa & (FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsADJUSTS))
+ && (na & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsANYLEN)))
+ || ((sa & FFESYMBOL_attrsRESULT)
+ && (na & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsINIT)))
+ || ((sa & (FFESYMBOL_attrsSFUNC
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsINTRINSIC
+ | FFESYMBOL_attrsINIT))
+ && (na & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsINIT)))
+ || ((sa & FFESYMBOL_attrsARRAY)
+ && !ffesta_is_entry_valid
+ && (na & FFESYMBOL_attrsANYLEN))
+ || ((sa & (FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsANYSIZE
+ | FFESYMBOL_attrsDUMMY))
+ && (na & FFESYMBOL_attrsINIT))
+ || ((sa & (FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV))
+ && (na & (FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsANYSIZE))))
+ na = FFESYMBOL_attrsetNONE;
+ else if ((ffesymbol_kind (s) == FFEINFO_kindENTITY)
+ && (ffesymbol_where (s) == FFEINFO_whereCONSTANT)
+ && (na & FFESYMBOL_attrsANYLEN))
+ { /* If CHARACTER*(*) FOO after PARAMETER FOO. */
+ na |= FFESYMBOL_attrsTYPE;
+ ffestc_local_.decl.size = ffebld_size (ffesymbol_init (s));
+ }
+ else
+ na |= sa;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ {
+ ffesymbol_error (s, name);
+ ffestc_parent_ok_ = FALSE;
+ }
+ else if (na & FFESYMBOL_attrsANY)
+ ffestc_parent_ok_ = FALSE;
+ else
+ {
+ ffesymbol_set_attrs (s, na);
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ rank = ffesymbol_rank (s);
+ if (dims != NULL)
+ {
+ ffesymbol_set_dims (s, ffestt_dimlist_as_expr (dims, &rank,
+ &array_size,
+ &extents,
+ is_ugly_assumed));
+ ffesymbol_set_arraysize (s, array_size);
+ ffesymbol_set_extents (s, extents);
+ if (!(0 && ffe_is_90 ())
+ && (ffebld_op (array_size) == FFEBLD_opCONTER)
+ && (ffebld_constant_integerdefault (ffebld_conter (array_size))
+ == 0))
+ {
+ ffebad_start (FFEBAD_ZERO_ARRAY);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_finish ();
+ }
+ }
+ if (init != NULL)
+ {
+ ffesymbol_set_init (s,
+ ffeexpr_convert (init, initt, name,
+ ffestc_local_.decl.basic_type,
+ ffestc_local_.decl.kind_type,
+ rank,
+ ffestc_local_.decl.size,
+ FFEEXPR_contextDATA));
+ ffecom_notify_init_symbol (s);
+ ffesymbol_update_init (s);
+#if FFEGLOBAL_ENABLED
+ if (ffesymbol_common (s) != NULL)
+ ffeglobal_init_common (ffesymbol_common (s), initt);
+#endif
+ }
+ else if (clist)
+ {
+ ffebld symter;
+
+ symter = ffebld_new_symter (s, FFEINTRIN_genNONE,
+ FFEINTRIN_specNONE,
+ FFEINTRIN_impNONE);
+
+ ffebld_set_info (symter,
+ ffeinfo_new (ffestc_local_.decl.basic_type,
+ ffestc_local_.decl.kind_type,
+ rank,
+ FFEINFO_kindNONE,
+ FFEINFO_whereNONE,
+ ffestc_local_.decl.size));
+ ffestc_local_.decl.initlist = ffebld_new_item (symter, NULL);
+ }
+ if (ffesymbol_basictype (s) == FFEINFO_basictypeNONE)
+ {
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffestc_local_.decl.basic_type,
+ ffestc_local_.decl.kind_type,
+ rank,
+ ffesymbol_kind (s),
+ ffesymbol_where (s),
+ ffestc_local_.decl.size));
+ if ((na & FFESYMBOL_attrsRESULT)
+ && ((sfn = ffesymbol_funcresult (s)) != NULL))
+ {
+ ffesymbol_set_info (sfn,
+ ffeinfo_new (ffestc_local_.decl.basic_type,
+ ffestc_local_.decl.kind_type,
+ rank,
+ ffesymbol_kind (sfn),
+ ffesymbol_where (sfn),
+ ffestc_local_.decl.size));
+ ffesymbol_signal_unreported (sfn);
+ }
+ }
+ else if ((ffestc_local_.decl.basic_type != ffesymbol_basictype (s))
+ || (ffestc_local_.decl.kind_type != ffesymbol_kindtype (s))
+ || ((ffestc_local_.decl.basic_type
+ == FFEINFO_basictypeCHARACTER)
+ && (ffestc_local_.decl.size != ffesymbol_size (s))))
+ { /* Explicit type disagrees with established
+ implicit type. */
+ ffesymbol_error (s, name);
+ }
+
+ if ((na & FFESYMBOL_attrsADJUSTS)
+ && ((ffestc_local_.decl.basic_type != FFEINFO_basictypeINTEGER)
+ || (ffestc_local_.decl.kind_type != FFEINFO_kindtypeINTEGER1)))
+ ffesymbol_error (s, name);
+
+ ffesymbol_signal_unreported (s);
+ ffestc_parent_ok_ = TRUE;
+ }
+}
+
+/* ffestc_R501_itemstartvals -- Start list of values
+
+ ffestc_R501_itemstartvals();
+
+ Gonna specify values for the object now. */
+
+void
+ffestc_R501_itemstartvals ()
+{
+ ffestc_check_item_startvals_ ();
+
+ if (ffestc_parent_ok_)
+ ffedata_begin (ffestc_local_.decl.initlist);
+}
+
+/* ffestc_R501_itemvalue -- Source value
+
+ ffestc_R501_itemvalue(repeat,repeat_token,value,value_token);
+
+ Make sure repeat and value are valid for the object being initialized. */
+
+void
+ffestc_R501_itemvalue (ffebld repeat, ffelexToken repeat_token,
+ ffebld value, ffelexToken value_token)
+{
+ ffetargetIntegerDefault rpt;
+
+ ffestc_check_item_value_ ();
+
+ if (!ffestc_parent_ok_)
+ return;
+
+ if (repeat == NULL)
+ rpt = 1;
+ else if (ffebld_op (repeat) == FFEBLD_opCONTER)
+ rpt = ffebld_constant_integerdefault (ffebld_conter (repeat));
+ else
+ {
+ ffestc_parent_ok_ = FALSE;
+ ffedata_end (TRUE, NULL);
+ return;
+ }
+
+ if (!(ffestc_parent_ok_ = ffedata_value (rpt, value,
+ (repeat_token == NULL) ? value_token : repeat_token)))
+ ffedata_end (TRUE, NULL);
+}
+
+/* ffestc_R501_itemendvals -- End list of values
+
+ ffelexToken t; // the SLASH token that ends the list.
+ ffestc_R501_itemendvals(t);
+
+ No more values, might specify more objects now. */
+
+void
+ffestc_R501_itemendvals (ffelexToken t)
+{
+ ffestc_check_item_endvals_ ();
+
+ if (ffestc_parent_ok_)
+ ffestc_parent_ok_ = ffedata_end (FALSE, t);
+
+ if (ffestc_parent_ok_)
+ ffesymbol_signal_unreported (ffebld_symter (ffebld_head
+ (ffestc_local_.decl.initlist)));
+}
+
+/* ffestc_R501_finish -- Done
+
+ ffestc_R501_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R501_finish ()
+{
+ ffestc_check_finish_ ();
+}
+
+/* ffestc_R519_start -- INTENT statement list begin
+
+ ffestc_R519_start();
+
+ Verify that INTENT is valid here, and begin accepting items in the list. */
+
+#if FFESTR_F90
+void
+ffestc_R519_start (ffelexToken intent, ffestrOther intent_kw)
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_spec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R519_start (intent_kw);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R519_item -- INTENT statement for name
+
+ ffestc_R519_item(name_token);
+
+ Make sure name_token identifies a valid object to be INTENTed. */
+
+void
+ffestc_R519_item (ffelexToken name)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R519_item (name);
+}
+
+/* ffestc_R519_finish -- INTENT statement list complete
+
+ ffestc_R519_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R519_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R519_finish ();
+}
+
+/* ffestc_R520_start -- OPTIONAL statement list begin
+
+ ffestc_R520_start();
+
+ Verify that OPTIONAL is valid here, and begin accepting items in the list. */
+
+void
+ffestc_R520_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_spec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R520_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R520_item -- OPTIONAL statement for name
+
+ ffestc_R520_item(name_token);
+
+ Make sure name_token identifies a valid object to be OPTIONALed. */
+
+void
+ffestc_R520_item (ffelexToken name)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R520_item (name);
+}
+
+/* ffestc_R520_finish -- OPTIONAL statement list complete
+
+ ffestc_R520_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R520_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R520_finish ();
+}
+
+/* ffestc_R521A -- PUBLIC statement
+
+ ffestc_R521A();
+
+ Verify that PUBLIC is valid here. */
+
+void
+ffestc_R521A ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_access_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ switch (ffestv_access_state_)
+ {
+ case FFESTV_accessstateNONE:
+ ffestv_access_state_ = FFESTV_accessstatePUBLIC;
+ ffestv_access_line_
+ = ffewhere_line_use (ffelex_token_where_line (ffesta_tokens[0]));
+ ffestv_access_col_
+ = ffewhere_column_use (ffelex_token_where_column (ffesta_tokens[0]));
+ break;
+
+ case FFESTV_accessstateANY:
+ break;
+
+ case FFESTV_accessstatePUBLIC:
+ case FFESTV_accessstatePRIVATE:
+ ffebad_start (FFEBAD_CONFLICTING_ACCESSES);
+ ffebad_here (0, ffestv_access_line_, ffestv_access_col_);
+ ffebad_here (1, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ ffestv_access_state_ = FFESTV_accessstateANY;
+ break;
+
+ default:
+ assert ("unexpected access state" == NULL);
+ break;
+ }
+
+ ffestd_R521A ();
+}
+
+/* ffestc_R521Astart -- PUBLIC statement list begin
+
+ ffestc_R521Astart();
+
+ Verify that PUBLIC is valid here, and begin accepting items in the list. */
+
+void
+ffestc_R521Astart ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_access_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R521Astart ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R521Aitem -- PUBLIC statement for name
+
+ ffestc_R521Aitem(name_token);
+
+ Make sure name_token identifies a valid object to be PUBLICed. */
+
+void
+ffestc_R521Aitem (ffelexToken name)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R521Aitem (name);
+}
+
+/* ffestc_R521Afinish -- PUBLIC statement list complete
+
+ ffestc_R521Afinish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R521Afinish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R521Afinish ();
+}
+
+/* ffestc_R521B -- PRIVATE statement
+
+ ffestc_R521B();
+
+ Verify that PRIVATE is valid here (outside a derived-type statement). */
+
+void
+ffestc_R521B ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_access_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ switch (ffestv_access_state_)
+ {
+ case FFESTV_accessstateNONE:
+ ffestv_access_state_ = FFESTV_accessstatePRIVATE;
+ ffestv_access_line_
+ = ffewhere_line_use (ffelex_token_where_line (ffesta_tokens[0]));
+ ffestv_access_col_
+ = ffewhere_column_use (ffelex_token_where_column (ffesta_tokens[0]));
+ break;
+
+ case FFESTV_accessstateANY:
+ break;
+
+ case FFESTV_accessstatePUBLIC:
+ case FFESTV_accessstatePRIVATE:
+ ffebad_start (FFEBAD_CONFLICTING_ACCESSES);
+ ffebad_here (0, ffestv_access_line_, ffestv_access_col_);
+ ffebad_here (1, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ ffestv_access_state_ = FFESTV_accessstateANY;
+ break;
+
+ default:
+ assert ("unexpected access state" == NULL);
+ break;
+ }
+
+ ffestd_R521B ();
+}
+
+/* ffestc_R521Bstart -- PRIVATE statement list begin
+
+ ffestc_R521Bstart();
+
+ Verify that PRIVATE is valid here, and begin accepting items in the list. */
+
+void
+ffestc_R521Bstart ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_access_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R521Bstart ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R521Bitem -- PRIVATE statement for name
+
+ ffestc_R521Bitem(name_token);
+
+ Make sure name_token identifies a valid object to be PRIVATEed. */
+
+void
+ffestc_R521Bitem (ffelexToken name)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R521Bitem (name);
+}
+
+/* ffestc_R521Bfinish -- PRIVATE statement list complete
+
+ ffestc_R521Bfinish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R521Bfinish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R521Bfinish ();
+}
+
+#endif
+/* ffestc_R522 -- SAVE statement with no list
+
+ ffestc_R522();
+
+ Verify that SAVE is valid here, and flag everything as SAVEd. */
+
+void
+ffestc_R522 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_blockspec_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ switch (ffestv_save_state_)
+ {
+ case FFESTV_savestateNONE:
+ ffestv_save_state_ = FFESTV_savestateALL;
+ ffestv_save_line_
+ = ffewhere_line_use (ffelex_token_where_line (ffesta_tokens[0]));
+ ffestv_save_col_
+ = ffewhere_column_use (ffelex_token_where_column (ffesta_tokens[0]));
+ break;
+
+ case FFESTV_savestateANY:
+ break;
+
+ case FFESTV_savestateSPECIFIC:
+ case FFESTV_savestateALL:
+ if (ffe_is_pedantic ())
+ {
+ ffebad_start (FFEBAD_CONFLICTING_SAVES);
+ ffebad_here (0, ffestv_save_line_, ffestv_save_col_);
+ ffebad_here (1, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ }
+ ffestv_save_state_ = FFESTV_savestateALL;
+ break;
+
+ default:
+ assert ("unexpected save state" == NULL);
+ break;
+ }
+
+ ffe_set_is_saveall (TRUE);
+
+ ffestd_R522 ();
+}
+
+/* ffestc_R522start -- SAVE statement list begin
+
+ ffestc_R522start();
+
+ Verify that SAVE is valid here, and begin accepting items in the list. */
+
+void
+ffestc_R522start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_blockspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ switch (ffestv_save_state_)
+ {
+ case FFESTV_savestateNONE:
+ ffestv_save_state_ = FFESTV_savestateSPECIFIC;
+ ffestv_save_line_
+ = ffewhere_line_use (ffelex_token_where_line (ffesta_tokens[0]));
+ ffestv_save_col_
+ = ffewhere_column_use (ffelex_token_where_column (ffesta_tokens[0]));
+ break;
+
+ case FFESTV_savestateSPECIFIC:
+ case FFESTV_savestateANY:
+ break;
+
+ case FFESTV_savestateALL:
+ if (ffe_is_pedantic ())
+ {
+ ffebad_start (FFEBAD_CONFLICTING_SAVES);
+ ffebad_here (0, ffestv_save_line_, ffestv_save_col_);
+ ffebad_here (1, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ }
+ ffestv_save_state_ = FFESTV_savestateANY;
+ break;
+
+ default:
+ assert ("unexpected save state" == NULL);
+ break;
+ }
+
+ ffestd_R522start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R522item_object -- SAVE statement for object-name
+
+ ffestc_R522item_object(name_token);
+
+ Make sure name_token identifies a valid object to be SAVEd. */
+
+void
+ffestc_R522item_object (ffelexToken name)
+{
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ s = ffesymbol_declare_local (name, FALSE);
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (!ffesymbol_is_specable (s)
+ && ((ffesymbol_kind (s) != FFEINFO_kindENTITY)
+ || (ffesymbol_where (s) != FFEINFO_whereLOCAL)))
+ na = FFESYMBOL_attrsetNONE; /* Can't dcl sym ref'd in sfuncdef. */
+ else if (sa & FFESYMBOL_attrsANY)
+ na = sa;
+ else if (!(sa & ~(FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)))
+ na = sa | FFESYMBOL_attrsSAVE;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, name);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_set_attrs (s, na);
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_update_save (s);
+ ffesymbol_signal_unreported (s);
+ }
+
+ ffestd_R522item_object (name);
+}
+
+/* ffestc_R522item_cblock -- SAVE statement for common-block-name
+
+ ffestc_R522item_cblock(name_token);
+
+ Make sure name_token identifies a valid common block to be SAVEd. */
+
+void
+ffestc_R522item_cblock (ffelexToken name)
+{
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ s = ffesymbol_declare_cblock (name, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (!ffesymbol_is_specable (s))
+ na = FFESYMBOL_attrsetNONE;
+ else if (sa & FFESYMBOL_attrsANY)
+ na = sa; /* Already have an error here, say nothing. */
+ else if (!(sa & ~(FFESYMBOL_attrsCBLOCK)))
+ na = sa | FFESYMBOL_attrsSAVECBLOCK;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, (name == NULL) ? ffesta_tokens[0] : name);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_update_save (s);
+ ffesymbol_signal_unreported (s);
+ }
+
+ ffestd_R522item_cblock (name);
+}
+
+/* ffestc_R522finish -- SAVE statement list complete
+
+ ffestc_R522finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R522finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R522finish ();
+}
+
+/* ffestc_R524_start -- DIMENSION statement list begin
+
+ ffestc_R524_start(bool virtual);
+
+ Verify that DIMENSION is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_R524_start (bool virtual)
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_blockspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R524_start (virtual);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R524_item -- DIMENSION statement for object-name
+
+ ffestc_R524_item(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be DIMENSIONd. */
+
+void
+ffestc_R524_item (ffelexToken name, ffesttDimList dims)
+{
+ ffesymbol s;
+ ffebld array_size;
+ ffebld extents;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffestpDimtype nd;
+ ffeinfoRank rank;
+ bool is_ugly_assumed;
+
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ assert (dims != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+ s = ffesymbol_declare_local (name, FALSE);
+ sa = ffesymbol_attrs (s);
+
+ /* First figure out what kind of object this is based solely on the current
+ object situation (dimension list). */
+
+ is_ugly_assumed = (ffe_is_ugly_assumed ()
+ && ((sa & FFESYMBOL_attrsDUMMY)
+ || (ffesymbol_where (s) == FFEINFO_whereDUMMY)));
+
+ nd = ffestt_dimlist_type (dims, is_ugly_assumed);
+ switch (nd)
+ {
+ case FFESTP_dimtypeKNOWN:
+ na = FFESYMBOL_attrsARRAY;
+ break;
+
+ case FFESTP_dimtypeADJUSTABLE:
+ na = FFESYMBOL_attrsARRAY | FFESYMBOL_attrsADJUSTABLE;
+ break;
+
+ case FFESTP_dimtypeASSUMED:
+ na = FFESYMBOL_attrsARRAY | FFESYMBOL_attrsANYSIZE;
+ break;
+
+ case FFESTP_dimtypeADJUSTABLEASSUMED:
+ na = FFESYMBOL_attrsARRAY | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYSIZE;
+ break;
+
+ default:
+ assert ("Unexpected dims type" == NULL);
+ na = FFESYMBOL_attrsetNONE;
+ break;
+ }
+
+ /* Now figure out what kind of object we've got based on previous
+ declarations of or references to the object. */
+
+ if (!ffesymbol_is_specable (s))
+ na = FFESYMBOL_attrsetNONE; /* Can't dcl sym ref'd in sfuncdef. */
+ else if (sa & FFESYMBOL_attrsANY)
+ na = FFESYMBOL_attrsANY;
+ else if (!ffesta_is_entry_valid
+ && (sa & FFESYMBOL_attrsANYLEN))
+ na = FFESYMBOL_attrsetNONE;
+ else if ((sa & FFESYMBOL_attrsARRAY)
+ || ((sa & (FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSAVE))
+ && (na & (FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYSIZE))))
+ na = FFESYMBOL_attrsetNONE;
+ else if (!(sa & ~(FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsANYSIZE
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsTYPE)))
+ na |= sa;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, name);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_set_dims (s, ffestt_dimlist_as_expr (dims, &rank,
+ &array_size,
+ &extents,
+ is_ugly_assumed));
+ ffesymbol_set_arraysize (s, array_size);
+ ffesymbol_set_extents (s, extents);
+ if (!(0 && ffe_is_90 ())
+ && (ffebld_op (array_size) == FFEBLD_opCONTER)
+ && (ffebld_constant_integerdefault (ffebld_conter (array_size))
+ == 0))
+ {
+ ffebad_start (FFEBAD_ZERO_ARRAY);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_finish ();
+ }
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ rank,
+ ffesymbol_kind (s),
+ ffesymbol_where (s),
+ ffesymbol_size (s)));
+ }
+
+ ffesymbol_signal_unreported (s);
+
+ ffestd_R524_item (name, dims);
+}
+
+/* ffestc_R524_finish -- DIMENSION statement list complete
+
+ ffestc_R524_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R524_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R524_finish ();
+}
+
+/* ffestc_R525_start -- ALLOCATABLE statement list begin
+
+ ffestc_R525_start();
+
+ Verify that ALLOCATABLE is valid here, and begin accepting items in the
+ list. */
+
+#if FFESTR_F90
+void
+ffestc_R525_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_progspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R525_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R525_item -- ALLOCATABLE statement for object-name
+
+ ffestc_R525_item(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be ALLOCATABLEd. */
+
+void
+ffestc_R525_item (ffelexToken name, ffesttDimList dims)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+ ffestd_R525_item (name, dims);
+}
+
+/* ffestc_R525_finish -- ALLOCATABLE statement list complete
+
+ ffestc_R525_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R525_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R525_finish ();
+}
+
+/* ffestc_R526_start -- POINTER statement list begin
+
+ ffestc_R526_start();
+
+ Verify that POINTER is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_R526_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_progspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R526_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R526_item -- POINTER statement for object-name
+
+ ffestc_R526_item(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be POINTERd. */
+
+void
+ffestc_R526_item (ffelexToken name, ffesttDimList dims)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+ ffestd_R526_item (name, dims);
+}
+
+/* ffestc_R526_finish -- POINTER statement list complete
+
+ ffestc_R526_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R526_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R526_finish ();
+}
+
+/* ffestc_R527_start -- TARGET statement list begin
+
+ ffestc_R527_start();
+
+ Verify that TARGET is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_R527_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_progspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R527_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R527_item -- TARGET statement for object-name
+
+ ffestc_R527_item(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be TARGETd. */
+
+void
+ffestc_R527_item (ffelexToken name, ffesttDimList dims)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+ ffestd_R527_item (name, dims);
+}
+
+/* ffestc_R527_finish -- TARGET statement list complete
+
+ ffestc_R527_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R527_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R527_finish ();
+}
+
+#endif
+/* ffestc_R528_start -- DATA statement list begin
+
+ ffestc_R528_start();
+
+ Verify that DATA is valid here, and begin accepting items in the list. */
+
+void
+ffestc_R528_start ()
+{
+ ffestcOrder_ order;
+
+ ffestc_check_start_ ();
+ if (ffe_is_pedantic_not_90 ())
+ order = ffestc_order_data77_ ();
+ else
+ order = ffestc_order_data_ ();
+ if (order != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+#if 1
+ ffestc_local_.data.objlist = NULL;
+#else
+ ffestd_R528_start_ ();
+#endif
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R528_item_object -- DATA statement target object
+
+ ffestc_R528_item_object(object,object_token);
+
+ Make sure object is valid to be DATAd. */
+
+void
+ffestc_R528_item_object (ffebld expr, ffelexToken expr_token UNUSED)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+#if 1
+ if (ffestc_local_.data.objlist == NULL)
+ ffebld_init_list (&ffestc_local_.data.objlist,
+ &ffestc_local_.data.list_bottom);
+
+ ffebld_append_item (&ffestc_local_.data.list_bottom, expr);
+#else
+ ffestd_R528_item_object_ (expr, expr_token);
+#endif
+}
+
+/* ffestc_R528_item_startvals -- DATA statement start list of values
+
+ ffestc_R528_item_startvals();
+
+ No more objects, gonna specify values for the list of objects now. */
+
+void
+ffestc_R528_item_startvals ()
+{
+ ffestc_check_item_startvals_ ();
+ if (!ffestc_ok_)
+ return;
+
+#if 1
+ assert (ffestc_local_.data.objlist != NULL);
+ ffebld_end_list (&ffestc_local_.data.list_bottom);
+ ffedata_begin (ffestc_local_.data.objlist);
+#else
+ ffestd_R528_item_startvals_ ();
+#endif
+}
+
+/* ffestc_R528_item_value -- DATA statement source value
+
+ ffestc_R528_item_value(repeat,repeat_token,value,value_token);
+
+ Make sure repeat and value are valid for the objects being initialized. */
+
+void
+ffestc_R528_item_value (ffebld repeat, ffelexToken repeat_token,
+ ffebld value, ffelexToken value_token)
+{
+ ffetargetIntegerDefault rpt;
+
+ ffestc_check_item_value_ ();
+ if (!ffestc_ok_)
+ return;
+
+#if 1
+ if (repeat == NULL)
+ rpt = 1;
+ else if (ffebld_op (repeat) == FFEBLD_opCONTER)
+ rpt = ffebld_constant_integerdefault (ffebld_conter (repeat));
+ else
+ {
+ ffestc_ok_ = FALSE;
+ ffedata_end (TRUE, NULL);
+ return;
+ }
+
+ if (!(ffestc_ok_ = ffedata_value (rpt, value,
+ (repeat_token == NULL)
+ ? value_token
+ : repeat_token)))
+ ffedata_end (TRUE, NULL);
+
+#else
+ ffestd_R528_item_value_ (repeat, value);
+#endif
+}
+
+/* ffestc_R528_item_endvals -- DATA statement start list of values
+
+ ffelexToken t; // the SLASH token that ends the list.
+ ffestc_R528_item_endvals(t);
+
+ No more values, might specify more objects now. */
+
+void
+ffestc_R528_item_endvals (ffelexToken t)
+{
+ ffestc_check_item_endvals_ ();
+ if (!ffestc_ok_)
+ return;
+
+#if 1
+ ffedata_end (!ffestc_ok_, t);
+ ffestc_local_.data.objlist = NULL;
+#else
+ ffestd_R528_item_endvals_ (t);
+#endif
+}
+
+/* ffestc_R528_finish -- DATA statement list complete
+
+ ffestc_R528_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R528_finish ()
+{
+ ffestc_check_finish_ ();
+
+#if 1
+#else
+ ffestd_R528_finish_ ();
+#endif
+}
+
+/* ffestc_R537_start -- PARAMETER statement list begin
+
+ ffestc_R537_start();
+
+ Verify that PARAMETER is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_R537_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_parameter_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+ ffestd_R537_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R537_item -- PARAMETER statement assignment
+
+ ffestc_R537_item(dest,dest_token,source,source_token);
+
+ Make sure the source is a valid source for the destination; make the
+ assignment. */
+
+void
+ffestc_R537_item (ffebld dest, ffelexToken dest_token, ffebld source,
+ ffelexToken source_token)
+{
+ ffesymbol s;
+
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if ((ffebld_op (dest) == FFEBLD_opANY)
+ || (ffebld_op (source) == FFEBLD_opANY))
+ {
+ if (ffebld_op (dest) == FFEBLD_opSYMTER)
+ {
+ s = ffebld_symter (dest);
+ ffesymbol_set_init (s, ffebld_new_any ());
+ ffebld_set_info (ffesymbol_init (s), ffeinfo_new_any ());
+ ffesymbol_signal_unreported (s);
+ }
+ ffestd_R537_item (dest, source);
+ return;
+ }
+
+ assert (ffebld_op (dest) == FFEBLD_opSYMTER);
+ assert (ffebld_op (source) == FFEBLD_opCONTER);
+
+ s = ffebld_symter (dest);
+ if ((ffesymbol_basictype (s) == FFEINFO_basictypeCHARACTER)
+ && (ffesymbol_size (s) == FFETARGET_charactersizeNONE))
+ { /* Destination has explicit/implicit
+ CHARACTER*(*) type; set length. */
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ 0,
+ ffesymbol_kind (s),
+ ffesymbol_where (s),
+ ffebld_size (source)));
+ ffebld_set_info (dest, ffeinfo_use (ffesymbol_info (s)));
+ }
+
+ source = ffeexpr_convert_expr (source, source_token, dest, dest_token,
+ FFEEXPR_contextDATA);
+
+ ffesymbol_set_init (s, source);
+
+ ffesymbol_signal_unreported (s);
+
+ ffestd_R537_item (dest, source);
+}
+
+/* ffestc_R537_finish -- PARAMETER statement list complete
+
+ ffestc_R537_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R537_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R537_finish ();
+}
+
+/* ffestc_R539 -- IMPLICIT NONE statement
+
+ ffestc_R539();
+
+ Verify that the IMPLICIT NONE statement is ok here and implement. */
+
+void
+ffestc_R539 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_implicitnone_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffeimplic_none ();
+
+ ffestd_R539 ();
+}
+
+/* ffestc_R539start -- IMPLICIT statement
+
+ ffestc_R539start();
+
+ Verify that the IMPLICIT statement is ok here and implement. */
+
+void
+ffestc_R539start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_implicit_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R539start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R539item -- IMPLICIT statement specification (R540)
+
+ ffestc_R539item(...);
+
+ Verify that the type and letter list are all ok and implement. */
+
+void
+ffestc_R539item (ffestpType type, ffebld kind, ffelexToken kindt,
+ ffebld len, ffelexToken lent, ffesttImpList letters)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if ((type == FFESTP_typeCHARACTER) && (len != NULL)
+ && (ffebld_op (len) == FFEBLD_opSTAR))
+ { /* Complain and pretend they're CHARACTER
+ [*1]. */
+ ffebad_start (FFEBAD_IMPLICIT_ADJLEN);
+ ffebad_here (0, ffelex_token_where_line (lent),
+ ffelex_token_where_column (lent));
+ ffebad_finish ();
+ len = NULL;
+ lent = NULL;
+ }
+ ffestc_establish_declstmt_ (type, ffesta_tokens[0], kind, kindt, len, lent);
+ ffestc_establish_declinfo_ (NULL, NULL, NULL, NULL);
+
+ ffestt_implist_drive (letters, ffestc_establish_impletter_);
+
+ ffestd_R539item (type, kind, kindt, len, lent, letters);
+}
+
+/* ffestc_R539finish -- IMPLICIT statement
+
+ ffestc_R539finish();
+
+ Finish up any local activities. */
+
+void
+ffestc_R539finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R539finish ();
+}
+
+/* ffestc_R542_start -- NAMELIST statement list begin
+
+ ffestc_R542_start();
+
+ Verify that NAMELIST is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_R542_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_progspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ if (ffe_is_f2c_library ()
+ && (ffe_case_source () == FFE_caseNONE))
+ {
+ ffebad_start (FFEBAD_NAMELIST_CASE);
+ ffesta_ffebad_here_current_stmt (0);
+ ffebad_finish ();
+ }
+
+ ffestd_R542_start ();
+
+ ffestc_local_.namelist.symbol = NULL;
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R542_item_nlist -- NAMELIST statement for group-name
+
+ ffestc_R542_item_nlist(groupname_token);
+
+ Make sure name_token identifies a valid object to be NAMELISTd. */
+
+void
+ffestc_R542_item_nlist (ffelexToken name)
+{
+ ffesymbol s;
+
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_local_.namelist.symbol != NULL)
+ ffesymbol_signal_unreported (ffestc_local_.namelist.symbol);
+
+ s = ffesymbol_declare_local (name, FALSE);
+
+ if ((ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ || ((ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ && (ffesymbol_kind (s) == FFEINFO_kindNAMELIST)))
+ {
+ ffestc_parent_ok_ = TRUE;
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ {
+ ffebld_init_list (ffesymbol_ptr_to_namelist (s),
+ ffesymbol_ptr_to_listbottom (s));
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindNAMELIST,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ }
+ }
+ else
+ {
+ if (ffesymbol_kind (s) != FFEINFO_kindANY)
+ ffesymbol_error (s, name);
+ ffestc_parent_ok_ = FALSE;
+ }
+
+ ffestc_local_.namelist.symbol = s;
+
+ ffestd_R542_item_nlist (name);
+}
+
+/* ffestc_R542_item_nitem -- NAMELIST statement for variable-name
+
+ ffestc_R542_item_nitem(name_token);
+
+ Make sure name_token identifies a valid object to be NAMELISTd. */
+
+void
+ffestc_R542_item_nitem (ffelexToken name)
+{
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffebld e;
+
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ s = ffesymbol_declare_local (name, FALSE);
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (!ffesymbol_is_specable (s)
+ && ((ffesymbol_kind (s) != FFEINFO_kindENTITY)
+ || ((ffesymbol_where (s) != FFEINFO_whereLOCAL)
+ && (ffesymbol_where (s) != FFEINFO_whereCOMMON))))
+ na = FFESYMBOL_attrsetNONE;
+ else if (sa & FFESYMBOL_attrsANY)
+ na = FFESYMBOL_attrsANY;
+ else if (!(sa & ~(FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)))
+ na = sa | FFESYMBOL_attrsNAMELIST;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, name);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_set_attrs (s, na);
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_set_namelisted (s, TRUE);
+ ffesymbol_signal_unreported (s);
+#if 0 /* No need to establish type yet! */
+ if (!ffeimplic_establish_symbol (s))
+ ffesymbol_error (s, name);
+#endif
+ }
+
+ if (ffestc_parent_ok_)
+ {
+ e = ffebld_new_symter (s, FFEINTRIN_genNONE, FFEINTRIN_specNONE,
+ FFEINTRIN_impNONE);
+ ffebld_set_info (e,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE, 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereNONE,
+ FFETARGET_charactersizeNONE));
+ ffebld_append_item
+ (ffesymbol_ptr_to_listbottom (ffestc_local_.namelist.symbol), e);
+ }
+
+ ffestd_R542_item_nitem (name);
+}
+
+/* ffestc_R542_finish -- NAMELIST statement list complete
+
+ ffestc_R542_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R542_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffesymbol_signal_unreported (ffestc_local_.namelist.symbol);
+
+ ffestd_R542_finish ();
+}
+
+/* ffestc_R544_start -- EQUIVALENCE statement list begin
+
+ ffestc_R544_start();
+
+ Verify that EQUIVALENCE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_R544_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_blockspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R544_item -- EQUIVALENCE statement assignment
+
+ ffestc_R544_item(exprlist);
+
+ Make sure the equivalence is valid, then implement it. */
+
+void
+ffestc_R544_item (ffesttExprList exprlist)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ /* First we go through the list and come up with one ffeequiv object that
+ will describe all items in the list. When an ffeequiv object is first
+ found, it is used (else we create one as a "local equiv" for the time
+ being). If subsequent ffeequiv objects are found, they are merged with
+ the first so we end up with one. However, if more than one COMMON
+ variable is involved, then an error condition occurs. */
+
+ ffestc_local_.equiv.ok = TRUE;
+ ffestc_local_.equiv.t = NULL; /* No token yet. */
+ ffestc_local_.equiv.eq = NULL;/* No equiv yet. */
+ ffestc_local_.equiv.save = FALSE; /* No SAVEd variables yet. */
+
+ ffebld_init_list (&ffestc_local_.equiv.list, &ffestc_local_.equiv.bottom);
+ ffestt_exprlist_drive (exprlist, ffestc_R544_equiv_); /* Get one equiv. */
+ ffebld_end_list (&ffestc_local_.equiv.bottom);
+
+ if (!ffestc_local_.equiv.ok)
+ return; /* Something went wrong, stop bothering with
+ this stuff. */
+
+ if (ffestc_local_.equiv.eq == NULL)
+ ffestc_local_.equiv.eq = ffeequiv_new (); /* Make local equivalence. */
+
+ /* Append this list of equivalences to list of such lists for this
+ equivalence. */
+
+ ffeequiv_add (ffestc_local_.equiv.eq, ffestc_local_.equiv.list,
+ ffestc_local_.equiv.t);
+ if (ffestc_local_.equiv.save)
+ ffeequiv_update_save (ffestc_local_.equiv.eq);
+}
+
+/* ffestc_R544_equiv_ -- EQUIVALENCE statement handler for item in list
+
+ ffebld expr;
+ ffelexToken t;
+ ffestc_R544_equiv_(expr,t);
+
+ Record information, if any, on symbol in expr; if symbol has equivalence
+ object already, merge with outstanding object if present or make it
+ the outstanding object. */
+
+static void
+ffestc_R544_equiv_ (ffebld expr, ffelexToken t)
+{
+ ffesymbol s;
+
+ if (!ffestc_local_.equiv.ok)
+ return;
+
+ if (ffestc_local_.equiv.t == NULL)
+ ffestc_local_.equiv.t = t;
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opANY:
+ return; /* Don't put this on the list. */
+
+ case FFEBLD_opSYMTER:
+ case FFEBLD_opARRAYREF:
+ case FFEBLD_opSUBSTR:
+ break; /* All of these are ok. */
+
+ default:
+ assert ("ffestc_R544_equiv_ bad op" == NULL);
+ return;
+ }
+
+ ffebld_append_item (&ffestc_local_.equiv.bottom, expr);
+
+ s = ffeequiv_symbol (expr);
+
+ /* See if symbol has an equivalence object already. */
+
+ if (ffesymbol_equiv (s) != NULL)
+ {
+ if (ffestc_local_.equiv.eq == NULL)
+ ffestc_local_.equiv.eq = ffesymbol_equiv (s); /* New equiv obj. */
+ else if (ffestc_local_.equiv.eq != ffesymbol_equiv (s))
+ {
+ ffestc_local_.equiv.eq = ffeequiv_merge (ffesymbol_equiv (s),
+ ffestc_local_.equiv.eq,
+ t);
+ if (ffestc_local_.equiv.eq == NULL)
+ ffestc_local_.equiv.ok = FALSE; /* Couldn't merge. */
+ }
+ }
+
+ if (ffesymbol_is_save (s))
+ ffestc_local_.equiv.save = TRUE;
+}
+
+/* ffestc_R544_finish -- EQUIVALENCE statement list complete
+
+ ffestc_R544_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R544_finish ()
+{
+ ffestc_check_finish_ ();
+}
+
+/* ffestc_R547_start -- COMMON statement list begin
+
+ ffestc_R547_start();
+
+ Verify that COMMON is valid here, and begin accepting items in the list. */
+
+void
+ffestc_R547_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_blockspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestc_local_.common.symbol = NULL; /* Blank common is the default. */
+ ffestc_parent_ok_ = TRUE;
+
+ ffestd_R547_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R547_item_object -- COMMON statement for object-name
+
+ ffestc_R547_item_object(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be COMMONd. */
+
+void
+ffestc_R547_item_object (ffelexToken name, ffesttDimList dims)
+{
+ ffesymbol s;
+ ffebld array_size;
+ ffebld extents;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffestpDimtype nd;
+ ffebld e;
+ ffeinfoRank rank;
+ bool is_ugly_assumed;
+
+ if (ffestc_parent_ok_ && (ffestc_local_.common.symbol == NULL))
+ ffestc_R547_item_cblock (NULL); /* As if "COMMON [//] ...". */
+
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ if (dims != NULL)
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+ s = ffesymbol_declare_local (name, FALSE);
+ sa = ffesymbol_attrs (s);
+
+ /* First figure out what kind of object this is based solely on the current
+ object situation (dimension list). */
+
+ is_ugly_assumed = (ffe_is_ugly_assumed ()
+ && ((sa & FFESYMBOL_attrsDUMMY)
+ || (ffesymbol_where (s) == FFEINFO_whereDUMMY)));
+
+ nd = ffestt_dimlist_type (dims, is_ugly_assumed);
+ switch (nd)
+ {
+ case FFESTP_dimtypeNONE:
+ na = FFESYMBOL_attrsCOMMON;
+ break;
+
+ case FFESTP_dimtypeKNOWN:
+ na = FFESYMBOL_attrsCOMMON | FFESYMBOL_attrsARRAY;
+ break;
+
+ default:
+ na = FFESYMBOL_attrsetNONE;
+ break;
+ }
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ;
+ else if (!ffesymbol_is_specable (s))
+ na = FFESYMBOL_attrsetNONE; /* Can't dcl sym ref'd in sfuncdef. */
+ else if (sa & FFESYMBOL_attrsANY)
+ na = FFESYMBOL_attrsANY;
+ else if ((sa & (FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsSFARG))
+ && (na & FFESYMBOL_attrsARRAY))
+ na = FFESYMBOL_attrsetNONE;
+ else if (!(sa & ~(FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)))
+ na |= sa;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, name);
+ else if ((ffesymbol_equiv (s) != NULL)
+ && (ffeequiv_common (ffesymbol_equiv (s)) != NULL)
+ && (ffeequiv_common (ffesymbol_equiv (s))
+ != ffestc_local_.common.symbol))
+ {
+ /* Oops, just COMMONed a symbol to a different area (via equiv). */
+ ffebad_start (FFEBAD_EQUIV_COMMON);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_string (ffesymbol_text (ffestc_local_.common.symbol));
+ ffebad_string (ffesymbol_text (ffeequiv_common (ffesymbol_equiv (s))));
+ ffebad_finish ();
+ ffesymbol_set_attr (s, na | FFESYMBOL_attrANY);
+ ffesymbol_set_info (s, ffeinfo_new_any ());
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_signal_unreported (s);
+ }
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_set_common (s, ffestc_local_.common.symbol);
+#if FFEGLOBAL_ENABLED
+ if (ffesymbol_is_init (s))
+ ffeglobal_init_common (ffestc_local_.common.symbol, name);
+#endif
+ if (ffesymbol_is_save (ffestc_local_.common.symbol))
+ ffesymbol_update_save (s);
+ if (ffesymbol_equiv (s) != NULL)
+ { /* Is this newly COMMONed symbol involved in
+ an equivalence? */
+ if (ffeequiv_common (ffesymbol_equiv (s)) == NULL)
+ ffeequiv_set_common (ffesymbol_equiv (s), /* Yes, tell equiv obj. */
+ ffestc_local_.common.symbol);
+#if FFEGLOBAL_ENABLED
+ if (ffeequiv_is_init (ffesymbol_equiv (s)))
+ ffeglobal_init_common (ffestc_local_.common.symbol, name);
+#endif
+ if (ffesymbol_is_save (ffestc_local_.common.symbol))
+ ffeequiv_update_save (ffesymbol_equiv (s));
+ }
+ if (dims != NULL)
+ {
+ ffesymbol_set_dims (s, ffestt_dimlist_as_expr (dims, &rank,
+ &array_size,
+ &extents,
+ is_ugly_assumed));
+ ffesymbol_set_arraysize (s, array_size);
+ ffesymbol_set_extents (s, extents);
+ if (!(0 && ffe_is_90 ())
+ && (ffebld_op (array_size) == FFEBLD_opCONTER)
+ && (ffebld_constant_integerdefault (ffebld_conter (array_size))
+ == 0))
+ {
+ ffebad_start (FFEBAD_ZERO_ARRAY);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_finish ();
+ }
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ rank,
+ ffesymbol_kind (s),
+ ffesymbol_where (s),
+ ffesymbol_size (s)));
+ }
+ ffesymbol_signal_unreported (s);
+ }
+
+ if (ffestc_parent_ok_)
+ {
+ e = ffebld_new_symter (s, FFEINTRIN_genNONE, FFEINTRIN_specNONE,
+ FFEINTRIN_impNONE);
+ ffebld_set_info (e,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereNONE,
+ FFETARGET_charactersizeNONE));
+ ffebld_append_item
+ (ffesymbol_ptr_to_listbottom (ffestc_local_.common.symbol), e);
+ }
+
+ ffestd_R547_item_object (name, dims);
+}
+
+/* ffestc_R547_item_cblock -- COMMON statement for common-block-name
+
+ ffestc_R547_item_cblock(name_token);
+
+ Make sure name_token identifies a valid common block to be COMMONd. */
+
+void
+ffestc_R547_item_cblock (ffelexToken name)
+{
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_local_.common.symbol != NULL)
+ ffesymbol_signal_unreported (ffestc_local_.common.symbol);
+
+ s = ffesymbol_declare_cblock (name,
+ ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (!ffesymbol_is_specable (s))
+ na = FFESYMBOL_attrsetNONE;
+ else if (sa & FFESYMBOL_attrsANY)
+ na = FFESYMBOL_attrsANY; /* Already have an error here, say nothing. */
+ else if (!(sa & ~(FFESYMBOL_attrsCBLOCK
+ | FFESYMBOL_attrsSAVECBLOCK)))
+ {
+ if (!(sa & FFESYMBOL_attrsCBLOCK))
+ ffebld_init_list (ffesymbol_ptr_to_commonlist (s),
+ ffesymbol_ptr_to_listbottom (s));
+ na = sa | FFESYMBOL_attrsCBLOCK;
+ }
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ {
+ ffesymbol_error (s, name == NULL ? ffesta_tokens[0] : name);
+ ffestc_parent_ok_ = FALSE;
+ }
+ else if (na & FFESYMBOL_attrsANY)
+ ffestc_parent_ok_ = FALSE;
+ else
+ {
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ if (name == NULL)
+ ffesymbol_update_save (s);
+ ffestc_parent_ok_ = TRUE;
+ }
+
+ ffestc_local_.common.symbol = s;
+
+ ffestd_R547_item_cblock (name);
+}
+
+/* ffestc_R547_finish -- COMMON statement list complete
+
+ ffestc_R547_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R547_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_local_.common.symbol != NULL)
+ ffesymbol_signal_unreported (ffestc_local_.common.symbol);
+
+ ffestd_R547_finish ();
+}
+
+/* ffestc_R620 -- ALLOCATE statement
+
+ ffestc_R620(exprlist,stat,stat_token);
+
+ Make sure the expression list is valid, then implement it. */
+
+#if FFESTR_F90
+void
+ffestc_R620 (ffesttExprList exprlist, ffebld stat, ffelexToken stat_token)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ ffestd_R620 (exprlist, stat);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R624 -- NULLIFY statement
+
+ ffestc_R624(pointer_name_list);
+
+ Make sure pointer_name_list identifies valid pointers for a NULLIFY. */
+
+void
+ffestc_R624 (ffesttExprList pointers)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ ffestd_R624 (pointers);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R625 -- DEALLOCATE statement
+
+ ffestc_R625(exprlist,stat,stat_token);
+
+ Make sure the equivalence is valid, then implement it. */
+
+void
+ffestc_R625 (ffesttExprList exprlist, ffebld stat, ffelexToken stat_token)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ ffestd_R625 (exprlist, stat);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+#endif
+/* ffestc_let -- R1213 or R737
+
+ ffestc_let(...);
+
+ Verify that R1213 defined-assignment or R737 assignment-stmt are
+ valid here, figure out which one, and implement. */
+
+#if FFESTR_F90
+void
+ffestc_let (ffebld dest, ffebld source, ffelexToken source_token)
+{
+ ffestc_R737 (dest, source, source_token);
+}
+
+#endif
+/* ffestc_R737 -- Assignment statement
+
+ ffestc_R737(dest_expr,source_expr,source_token);
+
+ Make sure the assignment is valid. */
+
+void
+ffestc_R737 (ffebld dest, ffebld source, ffelexToken source_token)
+{
+ ffestc_check_simple_ ();
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+#if FFESTR_F90
+ case FFESTV_stateWHERE:
+ case FFESTV_stateWHERETHEN:
+ if (ffestc_order_actionwhere_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R737B (dest, source);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ return;
+#endif
+
+ default:
+ break;
+ }
+
+ if (ffestc_order_actionwhere_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ source = ffeexpr_convert_expr (source, source_token, dest, ffesta_tokens[0],
+ FFEEXPR_contextLET);
+
+ ffestd_R737A (dest, source);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R738 -- Pointer assignment statement
+
+ ffestc_R738(dest_expr,source_expr,source_token);
+
+ Make sure the assignment is valid. */
+
+#if FFESTR_F90
+void
+ffestc_R738 (ffebld dest, ffebld source, ffelexToken source_token)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ ffestd_R738 (dest, source);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R740 -- WHERE statement
+
+ ffestc_R740(expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestc_R740 (ffebld expr, ffelexToken expr_token)
+{
+ ffestw b;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, ffestw_top_do (ffestw_previous (b)));
+ ffestw_set_state (b, FFESTV_stateWHERE);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_where_lost_);
+
+ ffestd_R740 (expr);
+
+ /* Leave label finishing to next statement. */
+
+}
+
+/* ffestc_R742 -- WHERE-construct statement
+
+ ffestc_R742(expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestc_R742 (ffebld expr, ffelexToken expr_token)
+{
+ ffestw b;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_exec_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_probably_this_wont_work_ ();
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, ffestw_top_do (ffestw_previous (b)));
+ ffestw_set_state (b, FFESTV_stateWHERETHEN);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_wherethen_);
+ ffestw_set_substate (b, 0); /* Haven't seen ELSEWHERE yet. */
+
+ ffestd_R742 (expr);
+}
+
+/* ffestc_R744 -- ELSE WHERE statement
+
+ ffestc_R744();
+
+ Make sure ffestc_kind_ identifies a WHERE block.
+ Implement the ELSE of the current WHERE block. */
+
+void
+ffestc_R744 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_where_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (ffestw_substate (ffestw_stack_top ()) != 0)
+ {
+ ffebad_start (FFEBAD_SECOND_ELSE_WHERE);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+
+ ffestw_set_substate (ffestw_stack_top (), 1); /* Saw ELSEWHERE. */
+
+ ffestd_R744 ();
+}
+
+/* ffestc_R745 -- END WHERE statement
+
+ ffestc_R745();
+
+ Make sure ffestc_kind_ identifies a WHERE block.
+ Implement the end of the current WHERE block. */
+
+void
+ffestc_R745 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_where_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffestc_shriek_wherethen_ (TRUE);
+}
+
+#endif
+/* ffestc_R803 -- Block IF (IF-THEN) statement
+
+ ffestc_R803(construct_name,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestc_R803 (ffelexToken construct_name, ffebld expr,
+ ffelexToken expr_token UNUSED)
+{
+ ffestw b;
+ ffesymbol s;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_exec_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_ ();
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, ffestw_top_do (ffestw_previous (b)));
+ ffestw_set_state (b, FFESTV_stateIFTHEN);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_ifthen_);
+ ffestw_set_substate (b, 0); /* Haven't seen ELSE yet. */
+
+ if (construct_name == NULL)
+ ffestw_set_name (b, NULL);
+ else
+ {
+ ffestw_set_name (b, ffelex_token_use (construct_name));
+
+ s = ffesymbol_declare_local (construct_name, FALSE);
+
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ {
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindCONSTRUCT,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s);
+ }
+ else
+ ffesymbol_error (s, construct_name);
+ }
+
+ ffestd_R803 (construct_name, expr);
+}
+
+/* ffestc_R804 -- ELSE IF statement
+
+ ffestc_R804(expr,expr_token,name_token);
+
+ Make sure ffestc_kind_ identifies an IF block. If not
+ NULL, make sure name_token gives the correct name. Implement the else
+ of the IF block. */
+
+void
+ffestc_R804 (ffebld expr, ffelexToken expr_token UNUSED,
+ ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_ifthen_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (name != NULL)
+ {
+ if (ffestw_name (ffestw_stack_top ()) == NULL)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_NOT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ else if (ffelex_token_strcmp (name,
+ ffestw_name (ffestw_stack_top ()))
+ != 0)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+ }
+
+ if (ffestw_substate (ffestw_stack_top ()) != 0)
+ {
+ ffebad_start (FFEBAD_AFTER_ELSE);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ return; /* Don't upset back end with ELSEIF
+ after ELSE. */
+ }
+
+ ffestd_R804 (expr, name);
+}
+
+/* ffestc_R805 -- ELSE statement
+
+ ffestc_R805(name_token);
+
+ Make sure ffestc_kind_ identifies an IF block. If not
+ NULL, make sure name_token gives the correct name. Implement the ELSE
+ of the IF block. */
+
+void
+ffestc_R805 (ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_ifthen_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (name != NULL)
+ {
+ if (ffestw_name (ffestw_stack_top ()) == NULL)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_NOT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ else if (ffelex_token_strcmp (name, ffestw_name (ffestw_stack_top ())) != 0)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+ }
+
+ if (ffestw_substate (ffestw_stack_top ()) != 0)
+ {
+ ffebad_start (FFEBAD_AFTER_ELSE);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ return; /* Tell back end about only one ELSE. */
+ }
+
+ ffestw_set_substate (ffestw_stack_top (), 1); /* Saw ELSE. */
+
+ ffestd_R805 (name);
+}
+
+/* ffestc_R806 -- END IF statement
+
+ ffestc_R806(name_token);
+
+ Make sure ffestc_kind_ identifies an IF block. If not
+ NULL, make sure name_token gives the correct name. Implement the end
+ of the IF block. */
+
+void
+ffestc_R806 (ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_ifthen_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_endif_ ();
+
+ if (name == NULL)
+ {
+ if (ffestw_name (ffestw_stack_top ()) != NULL)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if (ffestw_name (ffestw_stack_top ()) == NULL)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_NOT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ else if (ffelex_token_strcmp (name, ffestw_name (ffestw_stack_top ())) != 0)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+ }
+
+ ffestc_shriek_ifthen_ (TRUE);
+}
+
+/* ffestc_R807 -- Logical IF statement
+
+ ffestc_R807(expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestc_R807 (ffebld expr, ffelexToken expr_token UNUSED)
+{
+ ffestw b;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_action_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, ffestw_top_do (ffestw_previous (b)));
+ ffestw_set_state (b, FFESTV_stateIF);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_if_lost_);
+
+ ffestd_R807 (expr);
+
+ /* Do the label finishing in the next statement. */
+
+}
+
+/* ffestc_R809 -- SELECT CASE statement
+
+ ffestc_R809(construct_name,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestc_R809 (ffelexToken construct_name, ffebld expr, ffelexToken expr_token)
+{
+ ffestw b;
+ mallocPool pool;
+ ffestwSelect s;
+ ffesymbol sym;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_exec_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_ ();
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, ffestw_top_do (ffestw_previous (b)));
+ ffestw_set_state (b, FFESTV_stateSELECT0);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_select_);
+ ffestw_set_substate (b, 0); /* Haven't seen CASE DEFAULT yet. */
+
+ /* Init block to manage CASE list. */
+
+ pool = malloc_pool_new ("Select", ffe_pool_any_unit (), 1024);
+ s = (ffestwSelect) malloc_new_kp (pool, "Select", sizeof (*s));
+ s->first_rel = (ffestwCase) &s->first_rel;
+ s->last_rel = (ffestwCase) &s->first_rel;
+ s->first_stmt = (ffestwCase) &s->first_rel;
+ s->last_stmt = (ffestwCase) &s->first_rel;
+ s->pool = pool;
+ s->cases = 1;
+ s->t = ffelex_token_use (expr_token);
+ s->type = ffeinfo_basictype (ffebld_info (expr));
+ s->kindtype = ffeinfo_kindtype (ffebld_info (expr));
+ ffestw_set_select (b, s);
+
+ if (construct_name == NULL)
+ ffestw_set_name (b, NULL);
+ else
+ {
+ ffestw_set_name (b, ffelex_token_use (construct_name));
+
+ sym = ffesymbol_declare_local (construct_name, FALSE);
+
+ if (ffesymbol_state (sym) == FFESYMBOL_stateNONE)
+ {
+ ffesymbol_set_state (sym, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (sym,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE, 0,
+ FFEINFO_kindCONSTRUCT,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ sym = ffecom_sym_learned (sym);
+ ffesymbol_signal_unreported (sym);
+ }
+ else
+ ffesymbol_error (sym, construct_name);
+ }
+
+ ffestd_R809 (construct_name, expr);
+}
+
+/* ffestc_R810 -- CASE statement
+
+ ffestc_R810(case_value_range_list,name);
+
+ If case_value_range_list is NULL, it's CASE DEFAULT. name is the case-
+ construct-name. Make sure no more than one CASE DEFAULT is present for
+ a given case-construct and that there aren't any overlapping ranges or
+ duplicate case values. */
+
+void
+ffestc_R810 (ffesttCaseList cases, ffelexToken name)
+{
+ ffesttCaseList caseobj;
+ ffestwSelect s;
+ ffestwCase c, nc;
+ ffebldConstant expr1c, expr2c;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_selectcase_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ s = ffestw_select (ffestw_stack_top ());
+
+ if (ffestw_state (ffestw_stack_top ()) == FFESTV_stateSELECT0)
+ {
+#if 0 /* Not sure we want to have msgs point here
+ instead of SELECT CASE. */
+ ffestw_update (NULL); /* Update state line/col info. */
+#endif
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateSELECT1);
+ }
+
+ if (name != NULL)
+ {
+ if (ffestw_name (ffestw_stack_top ()) == NULL)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_NOT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ else if (ffelex_token_strcmp (name,
+ ffestw_name (ffestw_stack_top ()))
+ != 0)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+ }
+
+ if (cases == NULL)
+ {
+ if (ffestw_substate (ffestw_stack_top ()) != 0)
+ {
+ ffebad_start (FFEBAD_CASE_SECOND_DEFAULT);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+
+ ffestw_set_substate (ffestw_stack_top (), 1); /* Saw ELSE. */
+ }
+ else
+ { /* For each case, try to fit into sorted list
+ of ranges. */
+ for (caseobj = cases->next; caseobj != cases; caseobj = caseobj->next)
+ {
+ if ((caseobj->expr1 == NULL)
+ && (!caseobj->range
+ || (caseobj->expr2 == NULL)))
+ { /* "CASE (:)". */
+ ffebad_start (FFEBAD_CASE_BAD_RANGE);
+ ffebad_here (0, ffelex_token_where_line (caseobj->t),
+ ffelex_token_where_column (caseobj->t));
+ ffebad_finish ();
+ continue;
+ }
+
+ if (((caseobj->expr1 != NULL)
+ && ((ffeinfo_basictype (ffebld_info (caseobj->expr1))
+ != s->type)
+ || (ffeinfo_kindtype (ffebld_info (caseobj->expr1))
+ != s->kindtype)))
+ || ((caseobj->range)
+ && (caseobj->expr2 != NULL)
+ && ((ffeinfo_basictype (ffebld_info (caseobj->expr2))
+ != s->type)
+ || (ffeinfo_kindtype (ffebld_info (caseobj->expr2))
+ != s->kindtype))))
+ {
+ ffebad_start (FFEBAD_CASE_TYPE_DISAGREE);
+ ffebad_here (0, ffelex_token_where_line (caseobj->t),
+ ffelex_token_where_column (caseobj->t));
+ ffebad_here (1, ffelex_token_where_line (s->t),
+ ffelex_token_where_column (s->t));
+ ffebad_finish ();
+ continue;
+ }
+
+ if ((s->type == FFEINFO_basictypeLOGICAL) && (caseobj->range))
+ {
+ ffebad_start (FFEBAD_CASE_LOGICAL_RANGE);
+ ffebad_here (0, ffelex_token_where_line (caseobj->t),
+ ffelex_token_where_column (caseobj->t));
+ ffebad_finish ();
+ continue;
+ }
+
+ if (caseobj->expr1 == NULL)
+ expr1c = NULL;
+ else if (ffebld_op (caseobj->expr1) != FFEBLD_opCONTER)
+ continue; /* opANY. */
+ else
+ expr1c = ffebld_conter (caseobj->expr1);
+
+ if (!caseobj->range)
+ expr2c = expr1c; /* expr1c and expr2c are NOT NULL in this
+ case. */
+ else if (caseobj->expr2 == NULL)
+ expr2c = NULL;
+ else if (ffebld_op (caseobj->expr2) != FFEBLD_opCONTER)
+ continue; /* opANY. */
+ else
+ expr2c = ffebld_conter (caseobj->expr2);
+
+ if (expr1c == NULL)
+ { /* "CASE (:high)", must be first in list. */
+ c = s->first_rel;
+ if ((c != (ffestwCase) &s->first_rel)
+ && ((c->low == NULL)
+ || (ffebld_constant_cmp (expr2c, c->low) >= 0)))
+ { /* Other "CASE (:high)" or lowest "CASE
+ (low[:high])" low. */
+ ffebad_start (FFEBAD_CASE_DUPLICATE);
+ ffebad_here (0, ffelex_token_where_line (caseobj->t),
+ ffelex_token_where_column (caseobj->t));
+ ffebad_here (1, ffelex_token_where_line (c->t),
+ ffelex_token_where_column (c->t));
+ ffebad_finish ();
+ continue;
+ }
+ }
+ else if (expr2c == NULL)
+ { /* "CASE (low:)", must be last in list. */
+ c = s->last_rel;
+ if ((c != (ffestwCase) &s->first_rel)
+ && ((c->high == NULL)
+ || (ffebld_constant_cmp (expr1c, c->high) <= 0)))
+ { /* Other "CASE (low:)" or lowest "CASE
+ ([low:]high)" high. */
+ ffebad_start (FFEBAD_CASE_DUPLICATE);
+ ffebad_here (0, ffelex_token_where_line (caseobj->t),
+ ffelex_token_where_column (caseobj->t));
+ ffebad_here (1, ffelex_token_where_line (c->t),
+ ffelex_token_where_column (c->t));
+ ffebad_finish ();
+ continue;
+ }
+ c = c->next_rel; /* Same as c = (ffestwCase) &s->first;. */
+ }
+ else
+ { /* (expr1c != NULL) && (expr2c != NULL). */
+ if (ffebld_constant_cmp (expr1c, expr2c) > 0)
+ { /* Such as "CASE (3:1)" or "CASE ('B':'A')". */
+ ffebad_start (FFEBAD_CASE_RANGE_USELESS); /* Warn/inform only. */
+ ffebad_here (0, ffelex_token_where_line (caseobj->t),
+ ffelex_token_where_column (caseobj->t));
+ ffebad_finish ();
+ continue;
+ }
+ for (c = s->first_rel;
+ (c != (ffestwCase) &s->first_rel)
+ && ((c->low == NULL)
+ || (ffebld_constant_cmp (expr1c, c->low) > 0));
+ c = c->next_rel)
+ ;
+ nc = c; /* Which one to report? */
+ if (((c != (ffestwCase) &s->first_rel)
+ && (ffebld_constant_cmp (expr2c, c->low) >= 0))
+ || (((nc = c->previous_rel) != (ffestwCase) &s->first_rel)
+ && (ffebld_constant_cmp (expr1c, nc->high) <= 0)))
+ { /* Interference with range in case nc. */
+ ffebad_start (FFEBAD_CASE_DUPLICATE);
+ ffebad_here (0, ffelex_token_where_line (caseobj->t),
+ ffelex_token_where_column (caseobj->t));
+ ffebad_here (1, ffelex_token_where_line (nc->t),
+ ffelex_token_where_column (nc->t));
+ ffebad_finish ();
+ continue;
+ }
+ }
+
+ /* If we reach here for this case range/value, it's ok (sorts into
+ the list of ranges/values) so we give it its own case object
+ sorted into the list of case statements. */
+
+ nc = malloc_new_kp (s->pool, "Case range", sizeof (*nc));
+ nc->next_rel = c;
+ nc->previous_rel = c->previous_rel;
+ nc->next_stmt = (ffestwCase) &s->first_rel;
+ nc->previous_stmt = s->last_stmt;
+ nc->low = expr1c;
+ nc->high = expr2c;
+ nc->casenum = s->cases;
+ nc->t = ffelex_token_use (caseobj->t);
+ nc->next_rel->previous_rel = nc;
+ nc->previous_rel->next_rel = nc;
+ nc->next_stmt->previous_stmt = nc;
+ nc->previous_stmt->next_stmt = nc;
+ }
+ }
+
+ ffestd_R810 ((cases == NULL) ? 0 : s->cases);
+
+ s->cases++; /* Increment # of cases. */
+}
+
+/* ffestc_R811 -- END SELECT statement
+
+ ffestc_R811(name_token);
+
+ Make sure ffestc_kind_ identifies a SELECT block. If not
+ NULL, make sure name_token gives the correct name. Implement the end
+ of the SELECT block. */
+
+void
+ffestc_R811 (ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_selectcase_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_ ();
+
+ if (name == NULL)
+ {
+ if (ffestw_name (ffestw_stack_top ()) != NULL)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if (ffestw_name (ffestw_stack_top ()) == NULL)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_NOT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ else if (ffelex_token_strcmp (name,
+ ffestw_name (ffestw_stack_top ()))
+ != 0)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+ }
+
+ ffestc_shriek_select_ (TRUE);
+}
+
+/* ffestc_R819A -- Iterative labeled DO statement
+
+ ffestc_R819A(construct_name,label_token,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestc_R819A (ffelexToken construct_name, ffelexToken label_token, ffebld var,
+ ffelexToken var_token, ffebld start, ffelexToken start_token, ffebld end,
+ ffelexToken end_token, ffebld incr, ffelexToken incr_token)
+{
+ ffestw b;
+ ffelab label;
+ ffesymbol s;
+ ffesymbol varsym;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_exec_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_ ();
+
+ if (!ffestc_labelref_is_loopend_ (label_token, &label))
+ return;
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, b);
+ ffestw_set_state (b, FFESTV_stateDO);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_do_);
+ ffestw_set_label (b, label);
+ switch (ffebld_op (var))
+ {
+ case FFEBLD_opSYMTER:
+ if ((ffeinfo_basictype (ffebld_info (var)) == FFEINFO_basictypeREAL)
+ && ffe_is_warn_surprising ())
+ {
+ ffebad_start (FFEBAD_DO_REAL); /* See error message!!! */
+ ffebad_here (0, ffelex_token_where_line (var_token),
+ ffelex_token_where_column (var_token));
+ ffebad_string (ffesymbol_text (ffebld_symter (var)));
+ ffebad_finish ();
+ }
+ if (!ffesymbol_is_doiter (varsym = ffebld_symter (var)))
+ { /* Presumably already complained about by
+ ffeexpr_lhs_. */
+ ffesymbol_set_is_doiter (varsym, TRUE);
+ ffestw_set_do_iter_var (b, varsym);
+ ffestw_set_do_iter_var_t (b, ffelex_token_use (var_token));
+ break;
+ }
+ /* Fall through. */
+ case FFEBLD_opANY:
+ ffestw_set_do_iter_var (b, NULL);
+ ffestw_set_do_iter_var_t (b, NULL);
+ break;
+
+ default:
+ assert ("bad iter var" == NULL);
+ break;
+ }
+
+ if (construct_name == NULL)
+ ffestw_set_name (b, NULL);
+ else
+ {
+ ffestw_set_name (b, ffelex_token_use (construct_name));
+
+ s = ffesymbol_declare_local (construct_name, FALSE);
+
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ {
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindCONSTRUCT,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s);
+ }
+ else
+ ffesymbol_error (s, construct_name);
+ }
+
+ if (incr == NULL)
+ {
+ incr = ffebld_new_conter (ffebld_constant_new_integerdefault_val (1));
+ ffebld_set_info (incr, ffeinfo_new
+ (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ }
+
+ start = ffeexpr_convert_expr (start, start_token, var, var_token,
+ FFEEXPR_contextLET);
+ end = ffeexpr_convert_expr (end, end_token, var, var_token,
+ FFEEXPR_contextLET);
+ incr = ffeexpr_convert_expr (incr, incr_token, var, var_token,
+ FFEEXPR_contextLET);
+
+ ffestd_R819A (construct_name, label, var,
+ start, start_token,
+ end, end_token,
+ incr, incr_token);
+}
+
+/* ffestc_R819B -- Labeled DO WHILE statement
+
+ ffestc_R819B(construct_name,label_token,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestc_R819B (ffelexToken construct_name, ffelexToken label_token,
+ ffebld expr, ffelexToken expr_token UNUSED)
+{
+ ffestw b;
+ ffelab label;
+ ffesymbol s;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_exec_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_ ();
+
+ if (!ffestc_labelref_is_loopend_ (label_token, &label))
+ return;
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, b);
+ ffestw_set_state (b, FFESTV_stateDO);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_do_);
+ ffestw_set_label (b, label);
+ ffestw_set_do_iter_var (b, NULL);
+ ffestw_set_do_iter_var_t (b, NULL);
+
+ if (construct_name == NULL)
+ ffestw_set_name (b, NULL);
+ else
+ {
+ ffestw_set_name (b, ffelex_token_use (construct_name));
+
+ s = ffesymbol_declare_local (construct_name, FALSE);
+
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ {
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindCONSTRUCT,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s);
+ }
+ else
+ ffesymbol_error (s, construct_name);
+ }
+
+ ffestd_R819B (construct_name, label, expr);
+}
+
+/* ffestc_R820A -- Iterative nonlabeled DO statement
+
+ ffestc_R820A(construct_name,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestc_R820A (ffelexToken construct_name, ffebld var, ffelexToken var_token,
+ ffebld start, ffelexToken start_token, ffebld end, ffelexToken end_token,
+ ffebld incr, ffelexToken incr_token)
+{
+ ffestw b;
+ ffesymbol s;
+ ffesymbol varsym;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_exec_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_ ();
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, b);
+ ffestw_set_state (b, FFESTV_stateDO);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_do_);
+ ffestw_set_label (b, NULL);
+ switch (ffebld_op (var))
+ {
+ case FFEBLD_opSYMTER:
+ if ((ffeinfo_basictype (ffebld_info (var)) == FFEINFO_basictypeREAL)
+ && ffe_is_warn_surprising ())
+ {
+ ffebad_start (FFEBAD_DO_REAL); /* See error message!!! */
+ ffebad_here (0, ffelex_token_where_line (var_token),
+ ffelex_token_where_column (var_token));
+ ffebad_string (ffesymbol_text (ffebld_symter (var)));
+ ffebad_finish ();
+ }
+ if (!ffesymbol_is_doiter (varsym = ffebld_symter (var)))
+ { /* Presumably already complained about by
+ ffeexpr_lhs_. */
+ ffesymbol_set_is_doiter (varsym, TRUE);
+ ffestw_set_do_iter_var (b, varsym);
+ ffestw_set_do_iter_var_t (b, ffelex_token_use (var_token));
+ break;
+ }
+ /* Fall through. */
+ case FFEBLD_opANY:
+ ffestw_set_do_iter_var (b, NULL);
+ ffestw_set_do_iter_var_t (b, NULL);
+ break;
+
+ default:
+ assert ("bad iter var" == NULL);
+ break;
+ }
+
+ if (construct_name == NULL)
+ ffestw_set_name (b, NULL);
+ else
+ {
+ ffestw_set_name (b, ffelex_token_use (construct_name));
+
+ s = ffesymbol_declare_local (construct_name, FALSE);
+
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ {
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindCONSTRUCT,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s);
+ }
+ else
+ ffesymbol_error (s, construct_name);
+ }
+
+ if (incr == NULL)
+ {
+ incr = ffebld_new_conter (ffebld_constant_new_integerdefault_val (1));
+ ffebld_set_info (incr, ffeinfo_new
+ (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ }
+
+ start = ffeexpr_convert_expr (start, start_token, var, var_token,
+ FFEEXPR_contextLET);
+ end = ffeexpr_convert_expr (end, end_token, var, var_token,
+ FFEEXPR_contextLET);
+ incr = ffeexpr_convert_expr (incr, incr_token, var, var_token,
+ FFEEXPR_contextLET);
+
+#if 0
+ if ((ffebld_op (incr) == FFEBLD_opCONTER)
+ && (ffebld_constant_is_zero (ffebld_conter (incr))))
+ {
+ ffebad_start (FFEBAD_DO_STEP_ZERO);
+ ffebad_here (0, ffelex_token_where_line (incr_token),
+ ffelex_token_where_column (incr_token));
+ ffebad_string ("Iterative DO loop");
+ ffebad_finish ();
+ }
+#endif
+
+ ffestd_R819A (construct_name, NULL, var,
+ start, start_token,
+ end, end_token,
+ incr, incr_token);
+}
+
+/* ffestc_R820B -- Nonlabeled DO WHILE statement
+
+ ffestc_R820B(construct_name,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestc_R820B (ffelexToken construct_name, ffebld expr,
+ ffelexToken expr_token UNUSED)
+{
+ ffestw b;
+ ffesymbol s;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_exec_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_ ();
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, b);
+ ffestw_set_state (b, FFESTV_stateDO);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_do_);
+ ffestw_set_label (b, NULL);
+ ffestw_set_do_iter_var (b, NULL);
+ ffestw_set_do_iter_var_t (b, NULL);
+
+ if (construct_name == NULL)
+ ffestw_set_name (b, NULL);
+ else
+ {
+ ffestw_set_name (b, ffelex_token_use (construct_name));
+
+ s = ffesymbol_declare_local (construct_name, FALSE);
+
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ {
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindCONSTRUCT,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s);
+ }
+ else
+ ffesymbol_error (s, construct_name);
+ }
+
+ ffestd_R819B (construct_name, NULL, expr);
+}
+
+/* ffestc_R825 -- END DO statement
+
+ ffestc_R825(name_token);
+
+ Make sure ffestc_kind_ identifies a DO block. If not
+ NULL, make sure name_token gives the correct name. Implement the end
+ of the DO block. */
+
+void
+ffestc_R825 (ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_do_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (name == NULL)
+ {
+ if (ffestw_name (ffestw_stack_top ()) != NULL)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ }
+ else
+ {
+ if (ffestw_name (ffestw_stack_top ()) == NULL)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_NOT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ else if (ffelex_token_strcmp (name,
+ ffestw_name (ffestw_stack_top ()))
+ != 0)
+ {
+ ffebad_start (FFEBAD_CONSTRUCT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+ }
+
+ if (ffesta_label_token == NULL)
+ { /* If top of stack has label, its an error! */
+ if (ffestw_label (ffestw_stack_top ()) != NULL)
+ {
+ ffebad_start (FFEBAD_DO_HAD_LABEL);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+
+ ffestc_shriek_do_ (TRUE);
+
+ ffestc_try_shriek_do_ ();
+
+ return;
+ }
+
+ ffestd_R825 (name);
+
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R834 -- CYCLE statement
+
+ ffestc_R834(name_token);
+
+ Handle a CYCLE within a loop. */
+
+void
+ffestc_R834 (ffelexToken name)
+{
+ ffestw block;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actiondo_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_begin_ ();
+
+ if (name == NULL)
+ block = ffestw_top_do (ffestw_stack_top ());
+ else
+ { /* Search for name. */
+ for (block = ffestw_top_do (ffestw_stack_top ());
+ (block != NULL) && (ffestw_blocknum (block) != 0);
+ block = ffestw_top_do (ffestw_previous (block)))
+ {
+ if ((ffestw_name (block) != NULL)
+ && (ffelex_token_strcmp (name, ffestw_name (block)) == 0))
+ break;
+ }
+ if ((block == NULL) || (ffestw_blocknum (block) == 0))
+ {
+ block = ffestw_top_do (ffestw_stack_top ());
+ ffebad_start (FFEBAD_CONSTRUCT_NO_DO_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_finish ();
+ }
+ }
+
+ ffestd_R834 (block);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+
+ /* notloop's that are actionif's can be the target of a loop-end
+ statement if they're in the "then" part of a logical IF, as
+ in "DO 10", "10 IF (...) CYCLE". */
+
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R835 -- EXIT statement
+
+ ffestc_R835(name_token);
+
+ Handle a EXIT within a loop. */
+
+void
+ffestc_R835 (ffelexToken name)
+{
+ ffestw block;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actiondo_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_begin_ ();
+
+ if (name == NULL)
+ block = ffestw_top_do (ffestw_stack_top ());
+ else
+ { /* Search for name. */
+ for (block = ffestw_top_do (ffestw_stack_top ());
+ (block != NULL) && (ffestw_blocknum (block) != 0);
+ block = ffestw_top_do (ffestw_previous (block)))
+ {
+ if ((ffestw_name (block) != NULL)
+ && (ffelex_token_strcmp (name, ffestw_name (block)) == 0))
+ break;
+ }
+ if ((block == NULL) || (ffestw_blocknum (block) == 0))
+ {
+ block = ffestw_top_do (ffestw_stack_top ());
+ ffebad_start (FFEBAD_CONSTRUCT_NO_DO_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_finish ();
+ }
+ }
+
+ ffestd_R835 (block);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+
+ /* notloop's that are actionif's can be the target of a loop-end
+ statement if they're in the "then" part of a logical IF, as
+ in "DO 10", "10 IF (...) EXIT". */
+
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R836 -- GOTO statement
+
+ ffestc_R836(label_token);
+
+ Make sure label_token identifies a valid label for a GOTO. Update
+ that label's info to indicate it is the target of a GOTO. */
+
+void
+ffestc_R836 (ffelexToken label_token)
+{
+ ffelab label;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_begin_ ();
+
+ if (ffestc_labelref_is_branch_ (label_token, &label))
+ ffestd_R836 (label);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+
+ /* notloop's that are actionif's can be the target of a loop-end
+ statement if they're in the "then" part of a logical IF, as
+ in "DO 10", "10 IF (...) GOTO 100". */
+
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R837 -- Computed GOTO statement
+
+ ffestc_R837(label_list,expr,expr_token);
+
+ Make sure label_list identifies valid labels for a GOTO. Update
+ each label's info to indicate it is the target of a GOTO. */
+
+void
+ffestc_R837 (ffesttTokenList label_toks, ffebld expr,
+ ffelexToken expr_token UNUSED)
+{
+ ffesttTokenItem ti;
+ bool ok = TRUE;
+ int i;
+ ffelab *labels;
+
+ assert (label_toks != NULL);
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ labels = malloc_new_kp (ffesta_output_pool, "FFESTC labels",
+ sizeof (*labels)
+ * ffestt_tokenlist_count (label_toks));
+
+ for (ti = label_toks->first, i = 0;
+ ti != (ffesttTokenItem) &label_toks->first;
+ ti = ti->next, ++i)
+ {
+ if (!ffestc_labelref_is_branch_ (ti->t, &labels[i]))
+ {
+ ok = FALSE;
+ break;
+ }
+ }
+
+ if (ok)
+ ffestd_R837 (labels, ffestt_tokenlist_count (label_toks), expr);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R838 -- ASSIGN statement
+
+ ffestc_R838(label_token,target_variable,target_token);
+
+ Make sure label_token identifies a valid label for an assignment. Update
+ that label's info to indicate it is the source of an assignment. Update
+ target_variable's info to indicate it is the target the assignment of that
+ label. */
+
+void
+ffestc_R838 (ffelexToken label_token, ffebld target,
+ ffelexToken target_token UNUSED)
+{
+ ffelab label;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffestc_labelref_is_assignable_ (label_token, &label))
+ ffestd_R838 (label, target);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R839 -- Assigned GOTO statement
+
+ ffestc_R839(target,target_token,label_list);
+
+ Make sure label_list identifies valid labels for a GOTO. Update
+ each label's info to indicate it is the target of a GOTO. */
+
+void
+ffestc_R839 (ffebld target, ffelexToken target_token UNUSED,
+ ffesttTokenList label_toks)
+{
+ ffesttTokenItem ti;
+ bool ok = TRUE;
+ int i;
+ ffelab *labels;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_begin_ ();
+
+ if (label_toks == NULL)
+ {
+ labels = NULL;
+ i = 0;
+ }
+ else
+ {
+ labels = malloc_new_kp (ffesta_output_pool, "FFESTC labels",
+ sizeof (*labels) * ffestt_tokenlist_count (label_toks));
+
+ for (ti = label_toks->first, i = 0;
+ ti != (ffesttTokenItem) &label_toks->first;
+ ti = ti->next, ++i)
+ {
+ if (!ffestc_labelref_is_branch_ (ti->t, &labels[i]))
+ {
+ ok = FALSE;
+ break;
+ }
+ }
+ }
+
+ if (ok)
+ ffestd_R839 (target, labels, i);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+
+ /* notloop's that are actionif's can be the target of a loop-end
+ statement if they're in the "then" part of a logical IF, as
+ in "DO 10", "10 IF (...) GOTO I". */
+
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R840 -- Arithmetic IF statement
+
+ ffestc_R840(expr,expr_token,neg,zero,pos);
+
+ Make sure the labels are valid; implement. */
+
+void
+ffestc_R840 (ffebld expr, ffelexToken expr_token UNUSED,
+ ffelexToken neg_token, ffelexToken zero_token,
+ ffelexToken pos_token)
+{
+ ffelab neg;
+ ffelab zero;
+ ffelab pos;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_begin_ ();
+
+ if (ffestc_labelref_is_branch_ (neg_token, &neg)
+ && ffestc_labelref_is_branch_ (zero_token, &zero)
+ && ffestc_labelref_is_branch_ (pos_token, &pos))
+ ffestd_R840 (expr, neg, zero, pos);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+
+ /* notloop's that are actionif's can be the target of a loop-end
+ statement if they're in the "then" part of a logical IF, as
+ in "DO 10", "10 IF (...) GOTO (100,200,300), I". */
+
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R841 -- CONTINUE statement
+
+ ffestc_R841(); */
+
+void
+ffestc_R841 ()
+{
+ ffestc_check_simple_ ();
+
+ if (ffestc_order_actionwhere_ () != FFESTC_orderOK_)
+ return;
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+#if FFESTR_F90
+ case FFESTV_stateWHERE:
+ case FFESTV_stateWHERETHEN:
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R841 (TRUE);
+
+ /* It's okay that we call ffestc_labeldef_branch_end_ () below,
+ since that will be a no-op after calling _useless_ () above. */
+ break;
+#endif
+
+ default:
+ ffestc_labeldef_branch_begin_ ();
+
+ ffestd_R841 (FALSE);
+
+ break;
+ }
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R842 -- STOP statement
+
+ ffestc_R842(expr,expr_token);
+
+ Make sure statement is valid here; implement. expr and expr_token are
+ both NULL if there was no expression. */
+
+void
+ffestc_R842 (ffebld expr, ffelexToken expr_token UNUSED)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_begin_ ();
+
+ ffestd_R842 (expr);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+
+ /* notloop's that are actionif's can be the target of a loop-end
+ statement if they're in the "then" part of a logical IF, as
+ in "DO 10", "10 IF (...) STOP". */
+
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R843 -- PAUSE statement
+
+ ffestc_R843(expr,expr_token);
+
+ Make sure statement is valid here; implement. expr and expr_token are
+ both NULL if there was no expression. */
+
+void
+ffestc_R843 (ffebld expr, ffelexToken expr_token UNUSED)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ ffestd_R843 (expr);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R904 -- OPEN statement
+
+ ffestc_R904();
+
+ Make sure an OPEN is valid in the current context, and implement it. */
+
+void
+ffestc_R904 ()
+{
+ int i;
+ int expect_file;
+ char *status_strs[]
+ =
+ {
+ "New",
+ "Old",
+ "Replace",
+ "Scratch",
+ "Unknown"
+ };
+ char *access_strs[]
+ =
+ {
+ "Append",
+ "Direct",
+ "Keyed",
+ "Sequential"
+ };
+ char *blank_strs[]
+ =
+ {
+ "Null",
+ "Zero"
+ };
+ char *carriagecontrol_strs[]
+ =
+ {
+ "Fortran",
+ "List",
+ "None"
+ };
+ char *dispose_strs[]
+ =
+ {
+ "Delete",
+ "Keep",
+ "Print",
+ "Print/Delete",
+ "Save",
+ "Submit",
+ "Submit/Delete"
+ };
+ char *form_strs[]
+ =
+ {
+ "Formatted",
+ "Unformatted"
+ };
+ char *organization_strs[]
+ =
+ {
+ "Indexed",
+ "Relative",
+ "Sequential"
+ };
+ char *position_strs[]
+ =
+ {
+ "Append",
+ "AsIs",
+ "Rewind"
+ };
+ char *action_strs[]
+ =
+ {
+ "Read",
+ "ReadWrite",
+ "Write"
+ };
+ char *delim_strs[]
+ =
+ {
+ "Apostrophe",
+ "None",
+ "Quote"
+ };
+ char *recordtype_strs[]
+ =
+ {
+ "Fixed",
+ "Segmented",
+ "Stream",
+ "Stream_CR",
+ "Stream_LF",
+ "Variable"
+ };
+ char *pad_strs[]
+ =
+ {
+ "No",
+ "Yes"
+ };
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffestc_subr_is_branch_
+ (&ffestp_file.open.open_spec[FFESTP_openixERR])
+ && ffestc_subr_is_present_ ("UNIT",
+ &ffestp_file.open.open_spec[FFESTP_openixUNIT]))
+ {
+ i = ffestc_subr_binsrch_ (status_strs,
+ ARRAY_SIZE (status_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixSTATUS],
+ "NEW, OLD, REPLACE, SCRATCH, or UNKNOWN");
+ switch (i)
+ {
+ case 0: /* Unknown. */
+ case 5: /* UNKNOWN. */
+ expect_file = 2; /* Unknown, don't care about FILE=. */
+ break;
+
+ case 1: /* NEW. */
+ case 2: /* OLD. */
+ if (ffe_is_pedantic ())
+ expect_file = 1; /* Yes, need FILE=. */
+ else
+ expect_file = 2; /* f2clib doesn't care about FILE=. */
+ break;
+
+ case 3: /* REPLACE. */
+ expect_file = 1; /* Yes, need FILE=. */
+ break;
+
+ case 4: /* SCRATCH. */
+ expect_file = 0; /* No, disallow FILE=. */
+ break;
+
+ default:
+ assert ("invalid _binsrch_ result" == NULL);
+ expect_file = 0;
+ break;
+ }
+ if ((expect_file == 0)
+ && ffestp_file.open.open_spec[FFESTP_openixFILE].kw_or_val_present)
+ {
+ ffebad_start (FFEBAD_CONFLICTING_SPECS);
+ assert (ffestp_file.open.open_spec[FFESTP_openixFILE].kw_or_val_present);
+ if (ffestp_file.open.open_spec[FFESTP_openixFILE].kw_present)
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.open.open_spec[FFESTP_openixFILE].kw),
+ ffelex_token_where_column
+ (ffestp_file.open.open_spec[FFESTP_openixFILE].kw));
+ }
+ else
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.open.open_spec[FFESTP_openixFILE].value),
+ ffelex_token_where_column
+ (ffestp_file.open.open_spec[FFESTP_openixFILE].value));
+ }
+ assert (ffestp_file.open.open_spec[FFESTP_openixSTATUS].kw_or_val_present);
+ if (ffestp_file.open.open_spec[FFESTP_openixSTATUS].kw_present)
+ {
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.open.open_spec[FFESTP_openixSTATUS].kw),
+ ffelex_token_where_column
+ (ffestp_file.open.open_spec[FFESTP_openixSTATUS].kw));
+ }
+ else
+ {
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.open.open_spec[FFESTP_openixSTATUS].value),
+ ffelex_token_where_column
+ (ffestp_file.open.open_spec[FFESTP_openixSTATUS].value));
+ }
+ ffebad_finish ();
+ }
+ else if ((expect_file == 1)
+ && !ffestp_file.open.open_spec[FFESTP_openixFILE].kw_or_val_present)
+ {
+ ffebad_start (FFEBAD_MISSING_SPECIFIER);
+ assert (ffestp_file.open.open_spec[FFESTP_openixSTATUS].kw_or_val_present);
+ if (ffestp_file.open.open_spec[FFESTP_openixSTATUS].kw_present)
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.open.open_spec[FFESTP_openixSTATUS].kw),
+ ffelex_token_where_column
+ (ffestp_file.open.open_spec[FFESTP_openixSTATUS].kw));
+ }
+ else
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.open.open_spec[FFESTP_openixSTATUS].value),
+ ffelex_token_where_column
+ (ffestp_file.open.open_spec[FFESTP_openixSTATUS].value));
+ }
+ ffebad_string ("FILE=");
+ ffebad_finish ();
+ }
+
+ ffestc_subr_binsrch_ (access_strs, ARRAY_SIZE (access_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixACCESS],
+ "APPEND, DIRECT, KEYED, or SEQUENTIAL");
+
+ ffestc_subr_binsrch_ (blank_strs, ARRAY_SIZE (blank_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixBLANK],
+ "NULL or ZERO");
+
+ ffestc_subr_binsrch_ (carriagecontrol_strs,
+ ARRAY_SIZE (carriagecontrol_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixCARRIAGECONTROL],
+ "FORTRAN, LIST, or NONE");
+
+ ffestc_subr_binsrch_ (dispose_strs, ARRAY_SIZE (dispose_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixDISPOSE],
+ "DELETE, KEEP, PRINT, PRINT/DELETE, SAVE, SUBMIT, or SUBMIT/DELETE");
+
+ ffestc_subr_binsrch_ (form_strs, ARRAY_SIZE (form_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixFORM],
+ "FORMATTED or UNFORMATTED");
+
+ ffestc_subr_binsrch_ (organization_strs, ARRAY_SIZE (organization_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixORGANIZATION],
+ "INDEXED, RELATIVE, or SEQUENTIAL");
+
+ ffestc_subr_binsrch_ (position_strs, ARRAY_SIZE (position_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixPOSITION],
+ "APPEND, ASIS, or REWIND");
+
+ ffestc_subr_binsrch_ (action_strs, ARRAY_SIZE (action_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixACTION],
+ "READ, READWRITE, or WRITE");
+
+ ffestc_subr_binsrch_ (delim_strs, ARRAY_SIZE (delim_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixDELIM],
+ "APOSTROPHE, NONE, or QUOTE");
+
+ ffestc_subr_binsrch_ (recordtype_strs, ARRAY_SIZE (recordtype_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixRECORDTYPE],
+ "FIXED, SEGMENTED, STREAM, STREAM_CR, STREAM_LF, or VARIABLE");
+
+ ffestc_subr_binsrch_ (pad_strs, ARRAY_SIZE (pad_strs),
+ &ffestp_file.open.open_spec[FFESTP_openixPAD],
+ "NO or YES");
+
+ ffestd_R904 ();
+ }
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R907 -- CLOSE statement
+
+ ffestc_R907();
+
+ Make sure a CLOSE is valid in the current context, and implement it. */
+
+void
+ffestc_R907 ()
+{
+ char *status_strs[]
+ =
+ {
+ "Delete",
+ "Keep",
+ "Print",
+ "Print/Delete",
+ "Save",
+ "Submit",
+ "Submit/Delete"
+ };
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffestc_subr_is_branch_
+ (&ffestp_file.close.close_spec[FFESTP_closeixERR])
+ && ffestc_subr_is_present_ ("UNIT",
+ &ffestp_file.close.close_spec[FFESTP_closeixUNIT]))
+ {
+ ffestc_subr_binsrch_ (status_strs, ARRAY_SIZE (status_strs),
+ &ffestp_file.close.close_spec[FFESTP_closeixSTATUS],
+ "DELETE, KEEP, PRINT, PRINT/DELETE, SAVE, SUBMIT, or SUBMIT/DELETE");
+
+ ffestd_R907 ();
+ }
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R909_start -- READ(...) statement list begin
+
+ ffestc_R909_start(FALSE);
+
+ Verify that READ is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_R909_start (bool only_format)
+{
+ ffestvUnit unit;
+ ffestvFormat format;
+ bool rec;
+ bool key;
+ ffestpReadIx keyn;
+ ffestpReadIx spec1;
+ ffestpReadIx spec2;
+
+ ffestc_check_start_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_branch_begin_ ();
+
+ if (!ffestc_subr_is_format_
+ (&ffestp_file.read.read_spec[FFESTP_readixFORMAT]))
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ format = ffestc_subr_format_
+ (&ffestp_file.read.read_spec[FFESTP_readixFORMAT]);
+ ffestc_namelist_ = (format == FFESTV_formatNAMELIST);
+
+ if (only_format)
+ {
+ ffestd_R909_start (TRUE, FFESTV_unitNONE, format, FALSE, FALSE);
+
+ ffestc_ok_ = TRUE;
+ return;
+ }
+
+ if (!ffestc_subr_is_branch_
+ (&ffestp_file.read.read_spec[FFESTP_readixEOR])
+ || !ffestc_subr_is_branch_
+ (&ffestp_file.read.read_spec[FFESTP_readixERR])
+ || !ffestc_subr_is_branch_
+ (&ffestp_file.read.read_spec[FFESTP_readixEND]))
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ unit = ffestc_subr_unit_
+ (&ffestp_file.read.read_spec[FFESTP_readixUNIT]);
+ if (unit == FFESTV_unitNONE)
+ {
+ ffebad_start (FFEBAD_NO_UNIT_SPEC);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ rec = ffestp_file.read.read_spec[FFESTP_readixREC].kw_or_val_present;
+
+ if (ffestp_file.read.read_spec[FFESTP_readixKEYEQ].kw_or_val_present)
+ {
+ key = TRUE;
+ keyn = spec1 = FFESTP_readixKEYEQ;
+ }
+ else
+ {
+ key = FALSE;
+ keyn = spec1 = FFESTP_readix;
+ }
+
+ if (ffestp_file.read.read_spec[FFESTP_readixKEYGT].kw_or_val_present)
+ {
+ if (key)
+ {
+ spec2 = FFESTP_readixKEYGT;
+ whine: /* :::::::::::::::::::: */
+ ffebad_start (FFEBAD_CONFLICTING_SPECS);
+ assert (ffestp_file.read.read_spec[spec1].kw_or_val_present);
+ if (ffestp_file.read.read_spec[spec1].kw_present)
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.read.read_spec[spec1].kw),
+ ffelex_token_where_column
+ (ffestp_file.read.read_spec[spec1].kw));
+ }
+ else
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.read.read_spec[spec1].value),
+ ffelex_token_where_column
+ (ffestp_file.read.read_spec[spec1].value));
+ }
+ assert (ffestp_file.read.read_spec[spec2].kw_or_val_present);
+ if (ffestp_file.read.read_spec[spec2].kw_present)
+ {
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.read.read_spec[spec2].kw),
+ ffelex_token_where_column
+ (ffestp_file.read.read_spec[spec2].kw));
+ }
+ else
+ {
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.read.read_spec[spec2].value),
+ ffelex_token_where_column
+ (ffestp_file.read.read_spec[spec2].value));
+ }
+ ffebad_finish ();
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ key = TRUE;
+ keyn = spec1 = FFESTP_readixKEYGT;
+ }
+
+ if (ffestp_file.read.read_spec[FFESTP_readixKEYGE].kw_or_val_present)
+ {
+ if (key)
+ {
+ spec2 = FFESTP_readixKEYGT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ key = TRUE;
+ keyn = FFESTP_readixKEYGT;
+ }
+
+ if (rec)
+ {
+ spec1 = FFESTP_readixREC;
+ if (key)
+ {
+ spec2 = keyn;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (unit == FFESTV_unitCHAREXPR)
+ {
+ spec2 = FFESTP_readixUNIT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if ((format == FFESTV_formatASTERISK)
+ || (format == FFESTV_formatNAMELIST))
+ {
+ spec2 = FFESTP_readixFORMAT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixADVANCE].kw_or_val_present)
+ {
+ spec2 = FFESTP_readixADVANCE;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixEND].kw_or_val_present)
+ {
+ spec2 = FFESTP_readixEND;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixNULLS].kw_or_val_present)
+ {
+ spec2 = FFESTP_readixNULLS;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ }
+ else if (key)
+ {
+ spec1 = keyn;
+ if (unit == FFESTV_unitCHAREXPR)
+ {
+ spec2 = FFESTP_readixUNIT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if ((format == FFESTV_formatASTERISK)
+ || (format == FFESTV_formatNAMELIST))
+ {
+ spec2 = FFESTP_readixFORMAT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixADVANCE].kw_or_val_present)
+ {
+ spec2 = FFESTP_readixADVANCE;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixEND].kw_or_val_present)
+ {
+ spec2 = FFESTP_readixEND;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixEOR].kw_or_val_present)
+ {
+ spec2 = FFESTP_readixEOR;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixNULLS].kw_or_val_present)
+ {
+ spec2 = FFESTP_readixNULLS;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixREC].kw_or_val_present)
+ {
+ spec2 = FFESTP_readixREC;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixSIZE].kw_or_val_present)
+ {
+ spec2 = FFESTP_readixSIZE;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ }
+ else
+ { /* Sequential/Internal. */
+ if (unit == FFESTV_unitCHAREXPR)
+ { /* Internal file. */
+ spec1 = FFESTP_readixUNIT;
+ if (format == FFESTV_formatNAMELIST)
+ {
+ spec2 = FFESTP_readixFORMAT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixADVANCE].kw_or_val_present)
+ {
+ spec2 = FFESTP_readixADVANCE;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixADVANCE].kw_or_val_present)
+ { /* ADVANCE= specified. */
+ spec1 = FFESTP_readixADVANCE;
+ if (format == FFESTV_formatNONE)
+ {
+ ffebad_start (FFEBAD_MISSING_FORMAT_SPEC);
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.read.read_spec[spec1].kw),
+ ffelex_token_where_column
+ (ffestp_file.read.read_spec[spec1].kw));
+ ffebad_finish ();
+
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ if (format == FFESTV_formatNAMELIST)
+ {
+ spec2 = FFESTP_readixFORMAT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixEOR].kw_or_val_present)
+ { /* EOR= specified. */
+ spec1 = FFESTP_readixEOR;
+ if (ffestc_subr_speccmp_ ("No",
+ &ffestp_file.read.read_spec[FFESTP_readixADVANCE],
+ NULL, NULL) != 0)
+ {
+ goto whine_advance; /* :::::::::::::::::::: */
+ }
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixNULLS].kw_or_val_present)
+ { /* NULLS= specified. */
+ spec1 = FFESTP_readixNULLS;
+ if (format != FFESTV_formatASTERISK)
+ {
+ spec2 = FFESTP_readixFORMAT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ }
+ if (ffestp_file.read.read_spec[FFESTP_readixSIZE].kw_or_val_present)
+ { /* SIZE= specified. */
+ spec1 = FFESTP_readixSIZE;
+ if (ffestc_subr_speccmp_ ("No",
+ &ffestp_file.read.read_spec[FFESTP_readixADVANCE],
+ NULL, NULL) != 0)
+ {
+ whine_advance: /* :::::::::::::::::::: */
+ if (ffestp_file.read.read_spec[FFESTP_readixADVANCE]
+ .kw_or_val_present)
+ {
+ ffebad_start (FFEBAD_CONFLICTING_SPECS);
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.read.read_spec[spec1].kw),
+ ffelex_token_where_column
+ (ffestp_file.read.read_spec[spec1].kw));
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.read.read_spec[FFESTP_readixADVANCE].kw),
+ ffelex_token_where_column
+ (ffestp_file.read.read_spec[FFESTP_readixADVANCE].kw));
+ ffebad_finish ();
+ }
+ else
+ {
+ ffebad_start (FFEBAD_MISSING_ADVANCE_SPEC);
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.read.read_spec[spec1].kw),
+ ffelex_token_where_column
+ (ffestp_file.read.read_spec[spec1].kw));
+ ffebad_finish ();
+ }
+
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ }
+ }
+
+ if (unit == FFESTV_unitCHAREXPR)
+ ffestc_iolist_context_ = FFEEXPR_contextIOLISTDF;
+ else
+ ffestc_iolist_context_ = FFEEXPR_contextIOLIST;
+
+ ffestd_R909_start (FALSE, unit, format, rec, key);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R909_item -- READ statement i/o item
+
+ ffestc_R909_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestc_R909_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_namelist_ != 0)
+ {
+ if (ffestc_namelist_ == 1)
+ {
+ ffestc_namelist_ = 2;
+ ffebad_start (FFEBAD_NAMELIST_ITEMS);
+ ffebad_here (0, ffelex_token_where_line (expr_token),
+ ffelex_token_where_column (expr_token));
+ ffebad_finish ();
+ }
+ return;
+ }
+
+ ffestd_R909_item (expr, expr_token);
+}
+
+/* ffestc_R909_finish -- READ statement list complete
+
+ ffestc_R909_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R909_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R909_finish ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R910_start -- WRITE(...) statement list begin
+
+ ffestc_R910_start();
+
+ Verify that WRITE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_R910_start ()
+{
+ ffestvUnit unit;
+ ffestvFormat format;
+ bool rec;
+ ffestpWriteIx spec1;
+ ffestpWriteIx spec2;
+
+ ffestc_check_start_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_branch_begin_ ();
+
+ if (!ffestc_subr_is_branch_
+ (&ffestp_file.write.write_spec[FFESTP_writeixEOR])
+ || !ffestc_subr_is_branch_
+ (&ffestp_file.write.write_spec[FFESTP_writeixERR])
+ || !ffestc_subr_is_format_
+ (&ffestp_file.write.write_spec[FFESTP_writeixFORMAT]))
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ format = ffestc_subr_format_
+ (&ffestp_file.write.write_spec[FFESTP_writeixFORMAT]);
+ ffestc_namelist_ = (format == FFESTV_formatNAMELIST);
+
+ unit = ffestc_subr_unit_
+ (&ffestp_file.write.write_spec[FFESTP_writeixUNIT]);
+ if (unit == FFESTV_unitNONE)
+ {
+ ffebad_start (FFEBAD_NO_UNIT_SPEC);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ rec = ffestp_file.write.write_spec[FFESTP_writeixREC].kw_or_val_present;
+
+ if (rec)
+ {
+ spec1 = FFESTP_writeixREC;
+ if (unit == FFESTV_unitCHAREXPR)
+ {
+ spec2 = FFESTP_writeixUNIT;
+ whine: /* :::::::::::::::::::: */
+ ffebad_start (FFEBAD_CONFLICTING_SPECS);
+ assert (ffestp_file.write.write_spec[spec1].kw_or_val_present);
+ if (ffestp_file.write.write_spec[spec1].kw_present)
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.write.write_spec[spec1].kw),
+ ffelex_token_where_column
+ (ffestp_file.write.write_spec[spec1].kw));
+ }
+ else
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.write.write_spec[spec1].value),
+ ffelex_token_where_column
+ (ffestp_file.write.write_spec[spec1].value));
+ }
+ assert (ffestp_file.write.write_spec[spec2].kw_or_val_present);
+ if (ffestp_file.write.write_spec[spec2].kw_present)
+ {
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.write.write_spec[spec2].kw),
+ ffelex_token_where_column
+ (ffestp_file.write.write_spec[spec2].kw));
+ }
+ else
+ {
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.write.write_spec[spec2].value),
+ ffelex_token_where_column
+ (ffestp_file.write.write_spec[spec2].value));
+ }
+ ffebad_finish ();
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ if ((format == FFESTV_formatASTERISK)
+ || (format == FFESTV_formatNAMELIST))
+ {
+ spec2 = FFESTP_writeixFORMAT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.write.write_spec[FFESTP_writeixADVANCE].kw_or_val_present)
+ {
+ spec2 = FFESTP_writeixADVANCE;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ }
+ else
+ { /* Sequential/Indexed/Internal. */
+ if (unit == FFESTV_unitCHAREXPR)
+ { /* Internal file. */
+ spec1 = FFESTP_writeixUNIT;
+ if (format == FFESTV_formatNAMELIST)
+ {
+ spec2 = FFESTP_writeixFORMAT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ if (ffestp_file.write.write_spec[FFESTP_writeixADVANCE].kw_or_val_present)
+ {
+ spec2 = FFESTP_writeixADVANCE;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ }
+ if (ffestp_file.write.write_spec[FFESTP_writeixADVANCE].kw_or_val_present)
+ { /* ADVANCE= specified. */
+ spec1 = FFESTP_writeixADVANCE;
+ if (format == FFESTV_formatNONE)
+ {
+ ffebad_start (FFEBAD_MISSING_FORMAT_SPEC);
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.write.write_spec[spec1].kw),
+ ffelex_token_where_column
+ (ffestp_file.write.write_spec[spec1].kw));
+ ffebad_finish ();
+
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ if (format == FFESTV_formatNAMELIST)
+ {
+ spec2 = FFESTP_writeixFORMAT;
+ goto whine; /* :::::::::::::::::::: */
+ }
+ }
+ if (ffestp_file.write.write_spec[FFESTP_writeixEOR].kw_or_val_present)
+ { /* EOR= specified. */
+ spec1 = FFESTP_writeixEOR;
+ if (ffestc_subr_speccmp_ ("No",
+ &ffestp_file.write.write_spec[FFESTP_writeixADVANCE],
+ NULL, NULL) != 0)
+ {
+ if (ffestp_file.write.write_spec[FFESTP_writeixADVANCE]
+ .kw_or_val_present)
+ {
+ ffebad_start (FFEBAD_CONFLICTING_SPECS);
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.write.write_spec[spec1].kw),
+ ffelex_token_where_column
+ (ffestp_file.write.write_spec[spec1].kw));
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.write.write_spec[FFESTP_writeixADVANCE].kw),
+ ffelex_token_where_column
+ (ffestp_file.write.write_spec[FFESTP_writeixADVANCE].kw));
+ ffebad_finish ();
+ }
+ else
+ {
+ ffebad_start (FFEBAD_MISSING_ADVANCE_SPEC);
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.write.write_spec[spec1].kw),
+ ffelex_token_where_column
+ (ffestp_file.write.write_spec[spec1].kw));
+ ffebad_finish ();
+ }
+
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ }
+ }
+
+ if (unit == FFESTV_unitCHAREXPR)
+ ffestc_iolist_context_ = FFEEXPR_contextIOLISTDF;
+ else
+ ffestc_iolist_context_ = FFEEXPR_contextIOLIST;
+
+ ffestd_R910_start (unit, format, rec);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R910_item -- WRITE statement i/o item
+
+ ffestc_R910_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestc_R910_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_namelist_ != 0)
+ {
+ if (ffestc_namelist_ == 1)
+ {
+ ffestc_namelist_ = 2;
+ ffebad_start (FFEBAD_NAMELIST_ITEMS);
+ ffebad_here (0, ffelex_token_where_line (expr_token),
+ ffelex_token_where_column (expr_token));
+ ffebad_finish ();
+ }
+ return;
+ }
+
+ ffestd_R910_item (expr, expr_token);
+}
+
+/* ffestc_R910_finish -- WRITE statement list complete
+
+ ffestc_R910_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R910_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R910_finish ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R911_start -- PRINT(...) statement list begin
+
+ ffestc_R911_start();
+
+ Verify that PRINT is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_R911_start ()
+{
+ ffestvFormat format;
+
+ ffestc_check_start_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_branch_begin_ ();
+
+ if (!ffestc_subr_is_format_
+ (&ffestp_file.print.print_spec[FFESTP_printixFORMAT]))
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ format = ffestc_subr_format_
+ (&ffestp_file.print.print_spec[FFESTP_printixFORMAT]);
+ ffestc_namelist_ = (format == FFESTV_formatNAMELIST);
+
+ ffestd_R911_start (format);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R911_item -- PRINT statement i/o item
+
+ ffestc_R911_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestc_R911_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_namelist_ != 0)
+ {
+ if (ffestc_namelist_ == 1)
+ {
+ ffestc_namelist_ = 2;
+ ffebad_start (FFEBAD_NAMELIST_ITEMS);
+ ffebad_here (0, ffelex_token_where_line (expr_token),
+ ffelex_token_where_column (expr_token));
+ ffebad_finish ();
+ }
+ return;
+ }
+
+ ffestd_R911_item (expr, expr_token);
+}
+
+/* ffestc_R911_finish -- PRINT statement list complete
+
+ ffestc_R911_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R911_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R911_finish ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R919 -- BACKSPACE statement
+
+ ffestc_R919();
+
+ Make sure a BACKSPACE is valid in the current context, and implement it. */
+
+void
+ffestc_R919 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffestc_subr_is_branch_
+ (&ffestp_file.beru.beru_spec[FFESTP_beruixERR])
+ && ffestc_subr_is_present_ ("UNIT",
+ &ffestp_file.beru.beru_spec[FFESTP_beruixUNIT]))
+ ffestd_R919 ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R920 -- ENDFILE statement
+
+ ffestc_R920();
+
+ Make sure a ENDFILE is valid in the current context, and implement it. */
+
+void
+ffestc_R920 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffestc_subr_is_branch_
+ (&ffestp_file.beru.beru_spec[FFESTP_beruixERR])
+ && ffestc_subr_is_present_ ("UNIT",
+ &ffestp_file.beru.beru_spec[FFESTP_beruixUNIT]))
+ ffestd_R920 ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R921 -- REWIND statement
+
+ ffestc_R921();
+
+ Make sure a REWIND is valid in the current context, and implement it. */
+
+void
+ffestc_R921 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffestc_subr_is_branch_
+ (&ffestp_file.beru.beru_spec[FFESTP_beruixERR])
+ && ffestc_subr_is_present_ ("UNIT",
+ &ffestp_file.beru.beru_spec[FFESTP_beruixUNIT]))
+ ffestd_R921 ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R923A -- INQUIRE statement (non-IOLENGTH version)
+
+ ffestc_R923A();
+
+ Make sure an INQUIRE is valid in the current context, and implement it. */
+
+void
+ffestc_R923A ()
+{
+ bool by_file;
+ bool by_unit;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffestc_subr_is_branch_
+ (&ffestp_file.inquire.inquire_spec[FFESTP_inquireixERR]))
+ {
+ by_file = ffestp_file.inquire.inquire_spec[FFESTP_inquireixFILE]
+ .kw_or_val_present;
+ by_unit = ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT]
+ .kw_or_val_present;
+ if (by_file && by_unit)
+ {
+ ffebad_start (FFEBAD_CONFLICTING_SPECS);
+ assert (ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].kw_or_val_present);
+ if (ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].kw_present)
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].kw),
+ ffelex_token_where_column
+ (ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].kw));
+ }
+ else
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].value),
+ ffelex_token_where_column
+ (ffestp_file.inquire.inquire_spec[FFESTP_inquireixUNIT].value));
+ }
+ assert (ffestp_file.inquire.inquire_spec[FFESTP_inquireixFILE].kw_or_val_present);
+ if (ffestp_file.inquire.inquire_spec[FFESTP_inquireixFILE].kw_present)
+ {
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.inquire.inquire_spec[FFESTP_inquireixFILE].kw),
+ ffelex_token_where_column
+ (ffestp_file.inquire.inquire_spec[FFESTP_inquireixFILE].kw));
+ }
+ else
+ {
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.inquire.inquire_spec[FFESTP_inquireixFILE].value),
+ ffelex_token_where_column
+ (ffestp_file.inquire.inquire_spec[FFESTP_inquireixFILE].value));
+ }
+ ffebad_finish ();
+ }
+ else if (!by_file && !by_unit)
+ {
+ ffebad_start (FFEBAD_MISSING_SPECIFIER);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_string ("UNIT= or FILE=");
+ ffebad_finish ();
+ }
+ else
+ ffestd_R923A (by_file);
+ }
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R923B_start -- INQUIRE(IOLENGTH=expr) statement list begin
+
+ ffestc_R923B_start();
+
+ Verify that INQUIRE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_R923B_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_branch_begin_ ();
+
+ ffestd_R923B_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R923B_item -- INQUIRE statement i/o item
+
+ ffestc_R923B_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestc_R923B_item (ffebld expr, ffelexToken expr_token UNUSED)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R923B_item (expr);
+}
+
+/* ffestc_R923B_finish -- INQUIRE statement list complete
+
+ ffestc_R923B_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R923B_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R923B_finish ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R1001 -- FORMAT statement
+
+ ffestc_R1001(format_list);
+
+ Make sure format_list is valid. Update label's info to indicate it is a
+ FORMAT label, and (perhaps) warn if there is no label! */
+
+void
+ffestc_R1001 (ffesttFormatList f)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_format_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_format_ ();
+
+ ffestd_R1001 (f);
+}
+
+/* ffestc_R1102 -- PROGRAM statement
+
+ ffestc_R1102(name_token);
+
+ Make sure ffestc_kind_ identifies an empty block. Make sure name_token
+ gives a valid name. Implement the beginning of a main program. */
+
+void
+ffestc_R1102 (ffelexToken name)
+{
+ ffestw b;
+ ffesymbol s;
+
+ assert (name != NULL);
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_unit_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffestc_blocknum_ = 0;
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_statePROGRAM0);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_end_program_);
+
+ ffestw_set_name (b, ffelex_token_use (name));
+
+ s = ffesymbol_declare_programunit (name,
+ ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ {
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindPROGRAM,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ ffesymbol_signal_unreported (s);
+ }
+ else
+ ffesymbol_error (s, name);
+
+ ffestd_R1102 (s, name);
+}
+
+/* ffestc_R1103 -- END PROGRAM statement
+
+ ffestc_R1103(name_token);
+
+ Make sure ffestc_kind_ identifies the current kind of program unit. If not
+ NULL, make sure name_token gives the correct name. Implement the end
+ of the current program unit. */
+
+void
+ffestc_R1103 (ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_program_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_ ();
+
+ if (name != NULL)
+ {
+ if (ffestw_name (ffestw_stack_top ()) == NULL)
+ {
+ ffebad_start (FFEBAD_PROGRAM_NOT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ else if (ffelex_token_strcmp (name, ffestw_name (ffestw_stack_top ())) != 0)
+ {
+ ffebad_start (FFEBAD_UNIT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+ }
+
+ ffestc_shriek_end_program_ (TRUE);
+}
+
+/* ffestc_R1105 -- MODULE statement
+
+ ffestc_R1105(name_token);
+
+ Make sure ffestc_kind_ identifies an empty block. Make sure name_token
+ gives a valid name. Implement the beginning of a module. */
+
+#if FFESTR_F90
+void
+ffestc_R1105 (ffelexToken name)
+{
+ ffestw b;
+
+ assert (name != NULL);
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_unit_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffestc_blocknum_ = 0;
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_stateMODULE0);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_module_);
+ ffestw_set_name (b, ffelex_token_use (name));
+
+ ffestd_R1105 (name);
+}
+
+/* ffestc_R1106 -- END MODULE statement
+
+ ffestc_R1106(name_token);
+
+ Make sure ffestc_kind_ identifies the current kind of program unit. If not
+ NULL, make sure name_token gives the correct name. Implement the end
+ of the current program unit. */
+
+void
+ffestc_R1106 (ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_module_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if ((name != NULL)
+ && (ffelex_token_strcmp (name, ffestw_name (ffestw_stack_top ())) != 0))
+ {
+ ffebad_start (FFEBAD_UNIT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+
+ ffestc_shriek_module_ (TRUE);
+}
+
+/* ffestc_R1107_start -- USE statement list begin
+
+ ffestc_R1107_start();
+
+ Verify that USE is valid here, and begin accepting items in the list. */
+
+void
+ffestc_R1107_start (ffelexToken name, bool only)
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_use_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R1107_start (name, only);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R1107_item -- USE statement for name
+
+ ffestc_R1107_item(local_token,use_token);
+
+ Make sure name_token identifies a valid object to be USEed. local_token
+ may be NULL if _start_ was called with only==TRUE. */
+
+void
+ffestc_R1107_item (ffelexToken local, ffelexToken use)
+{
+ ffestc_check_item_ ();
+ assert (use != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R1107_item (local, use);
+}
+
+/* ffestc_R1107_finish -- USE statement list complete
+
+ ffestc_R1107_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R1107_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R1107_finish ();
+}
+
+#endif
+/* ffestc_R1111 -- BLOCK DATA statement
+
+ ffestc_R1111(name_token);
+
+ Make sure ffestc_kind_ identifies no current program unit. If not
+ NULL, make sure name_token gives a valid name. Implement the beginning
+ of a block data program unit. */
+
+void
+ffestc_R1111 (ffelexToken name)
+{
+ ffestw b;
+ ffesymbol s;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_unit_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffestc_blocknum_ = 0;
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_stateBLOCKDATA0);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_blockdata_);
+
+ if (name == NULL)
+ ffestw_set_name (b, NULL);
+ else
+ ffestw_set_name (b, ffelex_token_use (name));
+
+ s = ffesymbol_declare_blockdataunit (name,
+ ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ {
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindBLOCKDATA,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ ffesymbol_signal_unreported (s);
+ }
+ else
+ ffesymbol_error (s, name);
+
+ ffestd_R1111 (s, name);
+}
+
+/* ffestc_R1112 -- END BLOCK DATA statement
+
+ ffestc_R1112(name_token);
+
+ Make sure ffestc_kind_ identifies the current kind of program unit. If not
+ NULL, make sure name_token gives the correct name. Implement the end
+ of the current program unit. */
+
+void
+ffestc_R1112 (ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_blockdata_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (name != NULL)
+ {
+ if (ffestw_name (ffestw_stack_top ()) == NULL)
+ {
+ ffebad_start (FFEBAD_BLOCKDATA_NOT_NAMED);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+ else if (ffelex_token_strcmp (name, ffestw_name (ffestw_stack_top ())) != 0)
+ {
+ ffebad_start (FFEBAD_UNIT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+ }
+
+ ffestc_shriek_blockdata_ (TRUE);
+}
+
+/* ffestc_R1202 -- INTERFACE statement
+
+ ffestc_R1202(operator,defined_name);
+
+ Make sure ffestc_kind_ identifies an INTERFACE block.
+ Implement the end of the current interface.
+
+ 15-May-90 JCB 1.1
+ Allow no operator or name to mean INTERFACE by itself; missed this
+ valid form when originally doing syntactic analysis code. */
+
+#if FFESTR_F90
+void
+ffestc_R1202 (ffestpDefinedOperator operator, ffelexToken name)
+{
+ ffestw b;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_interfacespec_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_stateINTERFACE0);
+ ffestw_set_blocknum (b, 0);
+ ffestw_set_shriek (b, ffestc_shriek_interface_);
+
+ if ((operator == FFESTP_definedoperatorNone) && (name == NULL))
+ ffestw_set_substate (b, 0); /* No generic-spec, so disallow MODULE
+ PROCEDURE. */
+ else
+ ffestw_set_substate (b, 1); /* MODULE PROCEDURE ok. */
+
+ ffestd_R1202 (operator, name);
+
+ ffe_init_4 ();
+}
+
+/* ffestc_R1203 -- END INTERFACE statement
+
+ ffestc_R1203();
+
+ Make sure ffestc_kind_ identifies an INTERFACE block.
+ Implement the end of the current interface. */
+
+void
+ffestc_R1203 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_interface_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffestc_shriek_interface_ (TRUE);
+
+ ffe_terminate_4 ();
+}
+
+/* ffestc_R1205_start -- MODULE PROCEDURE statement list begin
+
+ ffestc_R1205_start();
+
+ Verify that MODULE PROCEDURE is valid here, and begin accepting items in
+ the list. */
+
+void
+ffestc_R1205_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_interface_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ if (ffestw_substate (ffestw_stack_top ()) == 0)
+ {
+ ffebad_start (FFEBAD_INVALID_MODULE_PROCEDURE);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ if (ffestw_state (ffestw_stack_top ()) == FFESTV_stateINTERFACE0)
+ {
+ ffestw_update (NULL); /* Update state line/col info. */
+ ffestw_set_state (ffestw_stack_top (), FFESTV_stateINTERFACE1);
+ }
+
+ ffestd_R1205_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R1205_item -- MODULE PROCEDURE statement for name
+
+ ffestc_R1205_item(name_token);
+
+ Make sure name_token identifies a valid object to be MODULE PROCEDUREed. */
+
+void
+ffestc_R1205_item (ffelexToken name)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R1205_item (name);
+}
+
+/* ffestc_R1205_finish -- MODULE PROCEDURE statement list complete
+
+ ffestc_R1205_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R1205_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R1205_finish ();
+}
+
+#endif
+/* ffestc_R1207_start -- EXTERNAL statement list begin
+
+ ffestc_R1207_start();
+
+ Verify that EXTERNAL is valid here, and begin accepting items in the list. */
+
+void
+ffestc_R1207_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_progspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R1207_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R1207_item -- EXTERNAL statement for name
+
+ ffestc_R1207_item(name_token);
+
+ Make sure name_token identifies a valid object to be EXTERNALd. */
+
+void
+ffestc_R1207_item (ffelexToken name)
+{
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ s = ffesymbol_declare_local (name, FALSE);
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (!ffesymbol_is_specable (s))
+ na = FFESYMBOL_attrsetNONE; /* Can't dcl sym ref'd in sfuncdef. */
+ else if (sa & FFESYMBOL_attrsANY)
+ na = FFESYMBOL_attrsANY;
+ else if (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsTYPE)))
+ na = sa | FFESYMBOL_attrsEXTERNAL;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, name);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_set_explicitwhere (s, TRUE);
+ ffesymbol_reference (s, name, FALSE);
+ ffesymbol_signal_unreported (s);
+ }
+
+ ffestd_R1207_item (name);
+}
+
+/* ffestc_R1207_finish -- EXTERNAL statement list complete
+
+ ffestc_R1207_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R1207_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R1207_finish ();
+}
+
+/* ffestc_R1208_start -- INTRINSIC statement list begin
+
+ ffestc_R1208_start();
+
+ Verify that INTRINSIC is valid here, and begin accepting items in the list. */
+
+void
+ffestc_R1208_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_progspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R1208_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R1208_item -- INTRINSIC statement for name
+
+ ffestc_R1208_item(name_token);
+
+ Make sure name_token identifies a valid object to be INTRINSICd. */
+
+void
+ffestc_R1208_item (ffelexToken name)
+{
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffeintrinGen gen;
+ ffeintrinSpec spec;
+ ffeintrinImp imp;
+
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ s = ffesymbol_declare_local (name, TRUE);
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (!ffesymbol_is_specable (s))
+ na = FFESYMBOL_attrsetNONE; /* Can't dcl sym ref'd in sfuncdef. */
+ else if (sa & FFESYMBOL_attrsANY)
+ na = sa;
+ else if (!(sa & ~FFESYMBOL_attrsTYPE))
+ {
+ if (ffeintrin_is_intrinsic (ffelex_token_text (name), name, TRUE,
+ &gen, &spec, &imp)
+ && ((imp == FFEINTRIN_impNONE)
+#if 0 /* Don't bother with this for now. */
+ || ((ffeintrin_basictype (spec)
+ == ffesymbol_basictype (s))
+ && (ffeintrin_kindtype (spec)
+ == ffesymbol_kindtype (s)))
+#else
+ || 1
+#endif
+ || !(sa & FFESYMBOL_attrsTYPE)))
+ na = sa | FFESYMBOL_attrsINTRINSIC;
+ else
+ na = FFESYMBOL_attrsetNONE;
+ }
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, name);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_generic (s, gen);
+ ffesymbol_set_specific (s, spec);
+ ffesymbol_set_implementation (s, imp);
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereINTRINSIC,
+ ffesymbol_size (s)));
+ ffesymbol_set_explicitwhere (s, TRUE);
+ ffesymbol_reference (s, name, TRUE);
+ }
+
+ ffesymbol_signal_unreported (s);
+
+ ffestd_R1208_item (name);
+}
+
+/* ffestc_R1208_finish -- INTRINSIC statement list complete
+
+ ffestc_R1208_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_R1208_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_R1208_finish ();
+}
+
+/* ffestc_R1212 -- CALL statement
+
+ ffestc_R1212(expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestc_R1212 (ffebld expr, ffelexToken expr_token UNUSED)
+{
+ ffebld item; /* ITEM. */
+ ffebld labexpr; /* LABTOK=>LABTER. */
+ ffelab label;
+ bool ok; /* TRUE if all LABTOKs were ok. */
+ bool ok1; /* TRUE if a particular LABTOK is ok. */
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffebld_op (expr) != FFEBLD_opSUBRREF)
+ ffestd_R841 (FALSE); /* CONTINUE. */
+ else
+ {
+ ok = TRUE;
+
+ for (item = ffebld_right (expr);
+ item != NULL;
+ item = ffebld_trail (item))
+ {
+ if (((labexpr = ffebld_head (item)) != NULL)
+ && (ffebld_op (labexpr) == FFEBLD_opLABTOK))
+ {
+ ok1 = ffestc_labelref_is_branch_ (ffebld_labtok (labexpr),
+ &label);
+ ffelex_token_kill (ffebld_labtok (labexpr));
+ if (!ok1)
+ {
+ label = NULL;
+ ok = FALSE;
+ }
+ ffebld_set_op (labexpr, FFEBLD_opLABTER);
+ ffebld_set_labter (labexpr, label);
+ }
+ }
+
+ if (ok)
+ ffestd_R1212 (expr);
+ }
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R1213 -- Defined assignment statement
+
+ ffestc_R1213(dest_expr,source_expr,source_token);
+
+ Make sure the assignment is valid. */
+
+#if FFESTR_F90
+void
+ffestc_R1213 (ffebld dest, ffebld source, ffelexToken source_token)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ ffestd_R1213 (dest, source);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+#endif
+/* ffestc_R1219 -- FUNCTION statement
+
+ ffestc_R1219(funcname,arglist,ending_token,kind,kindt,len,lent,
+ recursive);
+
+ Make sure statement is valid here, register arguments for the
+ function name, and so on.
+
+ 06-Apr-90 JCB 2.0
+ Added the kind, len, and recursive arguments. */
+
+void
+ffestc_R1219 (ffelexToken funcname, ffesttTokenList args,
+ ffelexToken final UNUSED, ffestpType type, ffebld kind,
+ ffelexToken kindt, ffebld len, ffelexToken lent,
+ ffelexToken recursive, ffelexToken result)
+{
+ ffestw b;
+ ffesymbol s;
+ ffesymbol fs; /* FUNCTION symbol when dealing with RESULT
+ symbol. */
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffelexToken res;
+ bool separate_result;
+
+ assert ((funcname != NULL)
+ && (ffelex_token_type (funcname) == FFELEX_typeNAME));
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_iface_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffestc_blocknum_ = 0;
+ ffesta_is_entry_valid =
+ (ffestw_state (ffestw_stack_top ()) == FFESTV_stateNIL);
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_stateFUNCTION0);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_function_);
+ ffestw_set_name (b, ffelex_token_use (funcname));
+
+ if (type == FFESTP_typeNone)
+ {
+ ffestc_local_.decl.basic_type = FFEINFO_basictypeNONE;
+ ffestc_local_.decl.kind_type = FFEINFO_kindtypeNONE;
+ ffestc_local_.decl.size = FFETARGET_charactersizeNONE;
+ }
+ else
+ {
+ ffestc_establish_declstmt_ (type, ffesta_tokens[0],
+ kind, kindt, len, lent);
+ ffestc_establish_declinfo_ (NULL, NULL, NULL, NULL);
+ }
+
+ separate_result = (result != NULL)
+ && (ffelex_token_strcmp (funcname, result) != 0);
+
+ if (separate_result)
+ fs = ffesymbol_declare_funcnotresunit (funcname); /* Global/local. */
+ else
+ fs = ffesymbol_declare_funcunit (funcname); /* Global only. */
+
+ if (ffesymbol_state (fs) == FFESYMBOL_stateNONE)
+ {
+ ffesymbol_set_state (fs, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_signal_unreported (fs);
+
+ /* Note that .basic_type and .kind_type might be NONE here. */
+
+ ffesymbol_set_info (fs,
+ ffeinfo_new (ffestc_local_.decl.basic_type,
+ ffestc_local_.decl.kind_type,
+ 0,
+ FFEINFO_kindFUNCTION,
+ FFEINFO_whereLOCAL,
+ ffestc_local_.decl.size));
+
+ /* Check whether the type info fits the filewide expectations;
+ set ok flag accordingly. */
+
+ ffesymbol_reference (fs, funcname, FALSE);
+ if (ffesymbol_attrs (fs) & FFESYMBOL_attrsANY)
+ ffestc_parent_ok_ = FALSE;
+ else
+ ffestc_parent_ok_ = TRUE;
+ }
+ else
+ {
+ if (ffesymbol_kind (fs) != FFEINFO_kindANY)
+ ffesymbol_error (fs, funcname);
+ ffestc_parent_ok_ = FALSE;
+ }
+
+ if (ffestc_parent_ok_)
+ {
+ ffebld_init_list (&fs->dummy_args, &ffestc_local_.dummy.list_bottom);
+ ffestt_tokenlist_drive (args, ffestc_promote_dummy_);
+ ffebld_end_list (&ffestc_local_.dummy.list_bottom);
+ }
+
+ if (result == NULL)
+ res = funcname;
+ else
+ res = result;
+
+ s = ffesymbol_declare_funcresult (res);
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (sa & FFESYMBOL_attrsANY)
+ na = FFESYMBOL_attrsANY;
+ else if (ffesymbol_state (s) != FFESYMBOL_stateNONE)
+ na = FFESYMBOL_attrsetNONE;
+ else
+ {
+ na = FFESYMBOL_attrsRESULT;
+ if (ffestc_local_.decl.basic_type != FFEINFO_basictypeNONE)
+ {
+ na |= FFESYMBOL_attrsTYPE;
+ if ((ffestc_local_.decl.basic_type == FFEINFO_basictypeCHARACTER)
+ && (ffestc_local_.decl.size == FFETARGET_charactersizeNONE))
+ na |= FFESYMBOL_attrsANYLEN;
+ }
+ }
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if ((na & ~FFESYMBOL_attrsANY) == FFESYMBOL_attrsetNONE)
+ {
+ if (!(na & FFESYMBOL_attrsANY))
+ ffesymbol_error (s, res);
+ ffesymbol_set_funcresult (fs, NULL);
+ ffesymbol_set_funcresult (s, NULL);
+ ffestc_parent_ok_ = FALSE;
+ }
+ else
+ {
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ ffesymbol_set_funcresult (fs, s);
+ ffesymbol_set_funcresult (s, fs);
+ if (ffestc_local_.decl.basic_type != FFEINFO_basictypeNONE)
+ {
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffestc_local_.decl.basic_type,
+ ffestc_local_.decl.kind_type,
+ 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereNONE,
+ ffestc_local_.decl.size));
+ }
+ }
+
+ ffesymbol_signal_unreported (fs);
+
+ ffestd_R1219 (fs, funcname, args, type, kind, kindt, len, lent,
+ (recursive != NULL), result, separate_result);
+}
+
+/* ffestc_R1221 -- END FUNCTION statement
+
+ ffestc_R1221(name_token);
+
+ Make sure ffestc_kind_ identifies the current kind of program unit. If
+ not NULL, make sure name_token gives the correct name. Implement the end
+ of the current program unit. */
+
+void
+ffestc_R1221 (ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_function_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_ ();
+
+ if ((name != NULL)
+ && (ffelex_token_strcmp (name, ffestw_name (ffestw_stack_top ())) != 0))
+ {
+ ffebad_start (FFEBAD_UNIT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+
+ ffestc_shriek_function_ (TRUE);
+}
+
+/* ffestc_R1223 -- SUBROUTINE statement
+
+ ffestc_R1223(subrname,arglist,ending_token,recursive_token);
+
+ Make sure statement is valid here, register arguments for the
+ subroutine name, and so on.
+
+ 06-Apr-90 JCB 2.0
+ Added the recursive argument. */
+
+void
+ffestc_R1223 (ffelexToken subrname, ffesttTokenList args,
+ ffelexToken final, ffelexToken recursive)
+{
+ ffestw b;
+ ffesymbol s;
+
+ assert ((subrname != NULL)
+ && (ffelex_token_type (subrname) == FFELEX_typeNAME));
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_iface_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffestc_blocknum_ = 0;
+ ffesta_is_entry_valid
+ = (ffestw_state (ffestw_stack_top ()) == FFESTV_stateNIL);
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_stateSUBROUTINE0);
+ ffestw_set_blocknum (b, ffestc_blocknum_++);
+ ffestw_set_shriek (b, ffestc_shriek_subroutine_);
+ ffestw_set_name (b, ffelex_token_use (subrname));
+
+ s = ffesymbol_declare_subrunit (subrname);
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ {
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindSUBROUTINE,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ ffestc_parent_ok_ = TRUE;
+ }
+ else
+ {
+ if (ffesymbol_kind (s) != FFEINFO_kindANY)
+ ffesymbol_error (s, subrname);
+ ffestc_parent_ok_ = FALSE;
+ }
+
+ if (ffestc_parent_ok_)
+ {
+ ffebld_init_list (&s->dummy_args, &ffestc_local_.dummy.list_bottom);
+ ffestt_tokenlist_drive (args, ffestc_promote_dummy_);
+ ffebld_end_list (&ffestc_local_.dummy.list_bottom);
+ }
+
+ ffesymbol_signal_unreported (s);
+
+ ffestd_R1223 (s, subrname, args, final, (recursive != NULL));
+}
+
+/* ffestc_R1225 -- END SUBROUTINE statement
+
+ ffestc_R1225(name_token);
+
+ Make sure ffestc_kind_ identifies the current kind of program unit. If
+ not NULL, make sure name_token gives the correct name. Implement the end
+ of the current program unit. */
+
+void
+ffestc_R1225 (ffelexToken name)
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_subroutine_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_ ();
+
+ if ((name != NULL)
+ && (ffelex_token_strcmp (name, ffestw_name (ffestw_stack_top ())) != 0))
+ {
+ ffebad_start (FFEBAD_UNIT_WRONG_NAME);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_here (1, ffelex_token_where_line (ffestw_name (ffestw_stack_top ())),
+ ffelex_token_where_column (ffestw_name (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+
+ ffestc_shriek_subroutine_ (TRUE);
+}
+
+/* ffestc_R1226 -- ENTRY statement
+
+ ffestc_R1226(entryname,arglist,ending_token);
+
+ Make sure we're in a SUBROUTINE or FUNCTION, register arguments for the
+ entry point name, and so on. */
+
+void
+ffestc_R1226 (ffelexToken entryname, ffesttTokenList args,
+ ffelexToken final UNUSED)
+{
+ ffesymbol s;
+ ffesymbol fs;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ bool in_spec; /* TRUE if further specification statements
+ may follow, FALSE if executable stmts. */
+ bool in_func; /* TRUE if ENTRY is a FUNCTION, not
+ SUBROUTINE. */
+
+ assert ((entryname != NULL)
+ && (ffelex_token_type (entryname) == FFELEX_typeNAME));
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_entry_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateFUNCTION1:
+ case FFESTV_stateFUNCTION2:
+ case FFESTV_stateFUNCTION3:
+ in_func = TRUE;
+ in_spec = TRUE;
+ break;
+
+ case FFESTV_stateFUNCTION4:
+ in_func = TRUE;
+ in_spec = FALSE;
+ break;
+
+ case FFESTV_stateSUBROUTINE1:
+ case FFESTV_stateSUBROUTINE2:
+ case FFESTV_stateSUBROUTINE3:
+ in_func = FALSE;
+ in_spec = TRUE;
+ break;
+
+ case FFESTV_stateSUBROUTINE4:
+ in_func = FALSE;
+ in_spec = FALSE;
+ break;
+
+ default:
+ assert ("ENTRY not in FUNCTION or SUBROUTINE?" == NULL);
+ in_func = FALSE;
+ in_spec = FALSE;
+ break;
+ }
+
+ if (in_func)
+ fs = ffesymbol_declare_funcunit (entryname);
+ else
+ fs = ffesymbol_declare_subrunit (entryname);
+
+ if (ffesymbol_state (fs) == FFESYMBOL_stateNONE)
+ ffesymbol_set_state (fs, FFESYMBOL_stateUNDERSTOOD);
+ else
+ {
+ if (ffesymbol_kind (fs) != FFEINFO_kindANY)
+ ffesymbol_error (fs, entryname);
+ }
+
+ ++ffestc_entry_num_;
+
+ ffebld_init_list (&fs->dummy_args, &ffestc_local_.dummy.list_bottom);
+ if (in_spec)
+ ffestt_tokenlist_drive (args, ffestc_promote_dummy_);
+ else
+ ffestt_tokenlist_drive (args, ffestc_promote_execdummy_);
+ ffebld_end_list (&ffestc_local_.dummy.list_bottom);
+
+ if (in_func)
+ {
+ s = ffesymbol_declare_funcresult (entryname);
+ ffesymbol_set_funcresult (fs, s);
+ ffesymbol_set_funcresult (s, fs);
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous
+ declarations of or references to the object. */
+
+ if (ffesymbol_state (s) == FFESYMBOL_stateUNDERSTOOD)
+ na = FFESYMBOL_attrsetNONE;
+ else if (sa & FFESYMBOL_attrsANY)
+ na = FFESYMBOL_attrsANY;
+ else if (!(sa & ~(FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsTYPE)))
+ na = sa | FFESYMBOL_attrsRESULT;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error
+ cropped up; ANY means an old error to be ignored; otherwise,
+ everything's ok, update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ {
+ ffesymbol_error (s, entryname);
+ ffestc_parent_ok_ = FALSE;
+ }
+ else if (na & FFESYMBOL_attrsANY)
+ {
+ ffestc_parent_ok_ = FALSE;
+ }
+ else
+ {
+ ffesymbol_set_attrs (s, na);
+ if (ffesymbol_state (s) == FFESYMBOL_stateNONE)
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ else if (ffesymbol_state (s) == FFESYMBOL_stateUNCERTAIN)
+ {
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereRESULT,
+ ffesymbol_size (s)));
+ ffesymbol_resolve_intrin (s);
+ ffestorag_exec_layout (s);
+ }
+ }
+
+ /* Since ENTRY might appear after executable stmts, do what would have
+ been done if it hadn't -- give symbol implicit type and
+ exec-transition it. */
+
+ if (!in_spec && ffesymbol_is_specable (s))
+ {
+ if (!ffeimplic_establish_symbol (s)) /* Do implicit typing. */
+ ffesymbol_error (s, entryname);
+ s = ffecom_sym_exec_transition (s);
+ }
+
+ /* Use whatever type info is available for ENTRY to set up type for its
+ global-name-space function symbol relative. */
+
+ ffesymbol_set_info (fs,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ 0,
+ FFEINFO_kindFUNCTION,
+ FFEINFO_whereLOCAL,
+ ffesymbol_size (s)));
+
+
+ /* Check whether the type info fits the filewide expectations;
+ set ok flag accordingly. */
+
+ ffesymbol_reference (fs, entryname, FALSE);
+
+ /* ~~Question??:
+ When ENTRY FOO() RESULT(IBAR) is supported, what will the typing be
+ if FOO and IBAR would normally end up with different types? I think
+ the answer is that FOO is always given whatever type would be chosen
+ for IBAR, rather than the other way around, and I think it ends up
+ working that way for FUNCTION FOO() RESULT(IBAR), but this should be
+ checked out in all its different combos. Related question is, is
+ there any way that FOO in either case ends up without type info
+ filled in? Does anyone care? */
+
+ ffesymbol_signal_unreported (s);
+ }
+ else
+ {
+ ffesymbol_set_info (fs,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindSUBROUTINE,
+ FFEINFO_whereLOCAL,
+ FFETARGET_charactersizeNONE));
+ }
+
+ if (!in_spec)
+ fs = ffecom_sym_exec_transition (fs);
+
+ ffesymbol_signal_unreported (fs);
+
+ ffestd_R1226 (fs);
+}
+
+/* ffestc_R1227 -- RETURN statement
+
+ ffestc_R1227(expr,expr_token);
+
+ Make sure statement is valid here; implement. expr and expr_token are
+ both NULL if there was no expression. */
+
+void
+ffestc_R1227 (ffebld expr, ffelexToken expr_token)
+{
+ ffestw b;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_notloop_begin_ ();
+
+ for (b = ffestw_stack_top (); ; b = ffestw_previous (b))
+ {
+ switch (ffestw_state (b))
+ {
+ case FFESTV_statePROGRAM4:
+ case FFESTV_stateSUBROUTINE4:
+ case FFESTV_stateFUNCTION4:
+ goto base; /* :::::::::::::::::::: */
+
+ case FFESTV_stateNIL:
+ assert ("bad state" == NULL);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ base:
+ switch (ffestw_state (b))
+ {
+ case FFESTV_statePROGRAM4:
+ if (ffe_is_pedantic ())
+ {
+ ffebad_start (FFEBAD_RETURN_IN_MAIN);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ }
+ if (expr != NULL)
+ {
+ ffebad_start (FFEBAD_ALTRETURN_IN_PROGRAM);
+ ffebad_here (0, ffelex_token_where_line (expr_token),
+ ffelex_token_where_column (expr_token));
+ ffebad_finish ();
+ expr = NULL;
+ }
+ break;
+
+ case FFESTV_stateSUBROUTINE4:
+ break;
+
+ case FFESTV_stateFUNCTION4:
+ if (expr != NULL)
+ {
+ ffebad_start (FFEBAD_ALTRETURN_IN_FUNCTION);
+ ffebad_here (0, ffelex_token_where_line (expr_token),
+ ffelex_token_where_column (expr_token));
+ ffebad_finish ();
+ expr = NULL;
+ }
+ break;
+
+ default:
+ assert ("bad state #2" == NULL);
+ break;
+ }
+
+ ffestd_R1227 (expr);
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+
+ /* notloop's that are actionif's can be the target of a loop-end
+ statement if they're in the "then" part of a logical IF, as
+ in "DO 10", "10 IF (...) RETURN". */
+
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_R1228 -- CONTAINS statement
+
+ ffestc_R1228(); */
+
+#if FFESTR_F90
+void
+ffestc_R1228 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_contains_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffestd_R1228 ();
+
+ ffe_terminate_3 ();
+ ffe_init_3 ();
+}
+
+#endif
+/* ffestc_R1229_start -- STMTFUNCTION statement begin
+
+ ffestc_R1229_start(func_name,func_arg_list,close_paren);
+
+ Verify that STMTFUNCTION is valid here, establish func_arg_list in a new
+ "live" scope within the current scope, and expect the actual expression
+ (or NULL) in ffestc_R1229_finish. The reason there are two ffestc
+ functions to handle this is so the scope can be established, allowing
+ ffeexpr to assign proper characteristics to references to the dummy
+ arguments. */
+
+void
+ffestc_R1229_start (ffelexToken name, ffesttTokenList args,
+ ffelexToken final UNUSED)
+{
+ ffesymbol s;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+
+ ffestc_check_start_ ();
+ if (ffestc_order_sfunc_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ assert (name != NULL);
+ assert (args != NULL);
+
+ s = ffesymbol_declare_local (name, FALSE);
+ sa = ffesymbol_attrs (s);
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (!ffesymbol_is_specable (s))
+ na = FFESYMBOL_attrsetNONE; /* Can't dcl sym ref'd in sfuncdef. */
+ else if (sa & FFESYMBOL_attrsANY)
+ na = FFESYMBOL_attrsANY;
+ else if (!(sa & ~FFESYMBOL_attrsTYPE))
+ na = sa | FFESYMBOL_attrsSFUNC;
+ else
+ na = FFESYMBOL_attrsetNONE;
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ {
+ ffesymbol_error (s, name);
+ ffestc_parent_ok_ = FALSE;
+ }
+ else if (na & FFESYMBOL_attrsANY)
+ ffestc_parent_ok_ = FALSE;
+ else
+ {
+ ffesymbol_set_attrs (s, na);
+ ffesymbol_set_state (s, FFESYMBOL_stateSEEN);
+ if (!ffeimplic_establish_symbol (s)
+ || ((ffesymbol_basictype (s) == FFEINFO_basictypeCHARACTER)
+ && (ffesymbol_size (s) == FFETARGET_charactersizeNONE)))
+ {
+ ffesymbol_error (s, ffesta_tokens[0]);
+ ffestc_parent_ok_ = FALSE;
+ }
+ else
+ {
+ /* Tell ffeexpr that sfunc def is in progress. */
+ ffesymbol_set_sfexpr (s, ffebld_new_any ());
+ ffebld_set_info (ffesymbol_sfexpr (s), ffeinfo_new_any ());
+ ffestc_parent_ok_ = TRUE;
+ }
+ }
+
+ ffe_init_4 ();
+
+ if (ffestc_parent_ok_)
+ {
+ ffebld_init_list (&s->dummy_args, &ffestc_local_.dummy.list_bottom);
+ ffestc_sfdummy_argno_ = 0;
+ ffestt_tokenlist_drive (args, ffestc_promote_sfdummy_);
+ ffebld_end_list (&ffestc_local_.dummy.list_bottom);
+ }
+
+ ffestc_local_.sfunc.symbol = s;
+
+ ffestd_R1229_start (name, args);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_R1229_finish -- STMTFUNCTION statement list complete
+
+ ffestc_R1229_finish(expr,expr_token);
+
+ If expr is NULL, an error occurred parsing the expansion expression, so
+ just cancel the effects of ffestc_R1229_start and pretend nothing
+ happened. Otherwise, install the expression as the expansion for the
+ statement function named in _start_, then clean up. */
+
+void
+ffestc_R1229_finish (ffebld expr, ffelexToken expr_token)
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_parent_ok_ && (expr != NULL))
+ ffesymbol_set_sfexpr (ffestc_local_.sfunc.symbol,
+ ffeexpr_convert_to_sym (expr,
+ expr_token,
+ ffestc_local_.sfunc.symbol,
+ ffesta_tokens[0]));
+
+ ffestd_R1229_finish (ffestc_local_.sfunc.symbol);
+
+ ffesymbol_signal_unreported (ffestc_local_.sfunc.symbol);
+
+ ffe_terminate_4 ();
+}
+
+/* ffestc_S3P4 -- INCLUDE line
+
+ ffestc_S3P4(filename,filename_token);
+
+ Make sure INCLUDE not preceded by any semicolons or a label def; implement. */
+
+void
+ffestc_S3P4 (ffebld filename, ffelexToken filename_token UNUSED)
+{
+ ffestc_check_simple_ ();
+ ffestc_labeldef_invalid_ ();
+
+ ffestd_S3P4 (filename);
+}
+
+/* ffestc_V003_start -- STRUCTURE statement list begin
+
+ ffestc_V003_start(structure_name);
+
+ Verify that STRUCTURE is valid here, and begin accepting items in the list. */
+
+#if FFESTR_VXT
+void
+ffestc_V003_start (ffelexToken structure_name)
+{
+ ffestw b;
+
+ ffestc_check_start_ ();
+ if (ffestc_order_vxtstructure_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateSTRUCTURE:
+ case FFESTV_stateMAP:
+ ffestc_local_.V003.list_state = 2; /* Require at least one field
+ name. */
+ ffestw_set_substate (ffestw_stack_top (), 1); /* Seen at least one
+ member. */
+ break;
+
+ default:
+ ffestc_local_.V003.list_state = 0; /* No field names required. */
+ if (structure_name == NULL)
+ {
+ ffebad_start (FFEBAD_STRUCT_MISSING_NAME);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ }
+ break;
+ }
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_stateSTRUCTURE);
+ ffestw_set_blocknum (b, 0);
+ ffestw_set_shriek (b, ffestc_shriek_structure_);
+ ffestw_set_substate (b, 0); /* No field-declarations seen yet. */
+
+ ffestd_V003_start (structure_name);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_V003_item -- STRUCTURE statement for object-name
+
+ ffestc_V003_item(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be STRUCTUREd. */
+
+void
+ffestc_V003_item (ffelexToken name, ffesttDimList dims)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_local_.V003.list_state < 2)
+ {
+ if (ffestc_local_.V003.list_state == 0)
+ {
+ ffestc_local_.V003.list_state = 1;
+ ffebad_start (FFEBAD_STRUCT_IGNORING_FIELD);
+ ffebad_here (0, ffelex_token_where_line (name),
+ ffelex_token_where_column (name));
+ ffebad_finish ();
+ }
+ return;
+ }
+ ffestc_local_.V003.list_state = 3; /* Have at least one field name. */
+
+ if (dims != NULL)
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+ ffestd_V003_item (name, dims);
+}
+
+/* ffestc_V003_finish -- STRUCTURE statement list complete
+
+ ffestc_V003_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_V003_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_local_.V003.list_state == 2)
+ {
+ ffebad_start (FFEBAD_STRUCT_MISSING_FIELD);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_previous (ffestw_stack_top ())),
+ ffestw_col (ffestw_previous (ffestw_stack_top ())));
+ ffebad_finish ();
+ }
+
+ ffestd_V003_finish ();
+}
+
+/* ffestc_V004 -- END STRUCTURE statement
+
+ ffestc_V004();
+
+ Make sure ffestc_kind_ identifies a STRUCTURE block.
+ Implement the end of the current STRUCTURE block. */
+
+void
+ffestc_V004 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_structure_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (ffestw_substate (ffestw_stack_top ()) != 1)
+ {
+ ffebad_start (FFEBAD_STRUCT_NO_COMPONENTS);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+
+ ffestc_shriek_structure_ (TRUE);
+}
+
+/* ffestc_V009 -- UNION statement
+
+ ffestc_V009(); */
+
+void
+ffestc_V009 ()
+{
+ ffestw b;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_structure_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ ffestw_set_substate (ffestw_stack_top (), 1); /* Seen at least one member. */
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_stateUNION);
+ ffestw_set_blocknum (b, 0);
+ ffestw_set_shriek (b, ffestc_shriek_union_);
+ ffestw_set_substate (b, 0); /* No map decls seen yet. */
+
+ ffestd_V009 ();
+}
+
+/* ffestc_V010 -- END UNION statement
+
+ ffestc_V010();
+
+ Make sure ffestc_kind_ identifies a UNION block.
+ Implement the end of the current UNION block. */
+
+void
+ffestc_V010 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_union_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (ffestw_substate (ffestw_stack_top ()) != 2)
+ {
+ ffebad_start (FFEBAD_UNION_NO_TWO_MAPS);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+
+ ffestc_shriek_union_ (TRUE);
+}
+
+/* ffestc_V012 -- MAP statement
+
+ ffestc_V012(); */
+
+void
+ffestc_V012 ()
+{
+ ffestw b;
+
+ ffestc_check_simple_ ();
+ if (ffestc_order_union_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (ffestw_substate (ffestw_stack_top ()) != 2)
+ ffestw_substate (ffestw_stack_top ())++; /* 0=>1, 1=>2. */
+
+ b = ffestw_update (ffestw_push (NULL));
+ ffestw_set_top_do (b, NULL);
+ ffestw_set_state (b, FFESTV_stateMAP);
+ ffestw_set_blocknum (b, 0);
+ ffestw_set_shriek (b, ffestc_shriek_map_);
+ ffestw_set_substate (b, 0); /* No field-declarations seen yet. */
+
+ ffestd_V012 ();
+}
+
+/* ffestc_V013 -- END MAP statement
+
+ ffestc_V013();
+
+ Make sure ffestc_kind_ identifies a MAP block.
+ Implement the end of the current MAP block. */
+
+void
+ffestc_V013 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_map_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_useless_ ();
+
+ if (ffestw_substate (ffestw_stack_top ()) != 1)
+ {
+ ffebad_start (FFEBAD_MAP_NO_COMPONENTS);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_here (1, ffestw_line (ffestw_stack_top ()), ffestw_col (ffestw_stack_top ()));
+ ffebad_finish ();
+ }
+
+ ffestc_shriek_map_ (TRUE);
+}
+
+#endif
+/* ffestc_V014_start -- VOLATILE statement list begin
+
+ ffestc_V014_start();
+
+ Verify that VOLATILE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_V014_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_progspec_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_V014_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_V014_item_object -- VOLATILE statement for object-name
+
+ ffestc_V014_item_object(name_token);
+
+ Make sure name_token identifies a valid object to be VOLATILEd. */
+
+void
+ffestc_V014_item_object (ffelexToken name)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V014_item_object (name);
+}
+
+/* ffestc_V014_item_cblock -- VOLATILE statement for common-block-name
+
+ ffestc_V014_item_cblock(name_token);
+
+ Make sure name_token identifies a valid common block to be VOLATILEd. */
+
+void
+ffestc_V014_item_cblock (ffelexToken name)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V014_item_cblock (name);
+}
+
+/* ffestc_V014_finish -- VOLATILE statement list complete
+
+ ffestc_V014_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_V014_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V014_finish ();
+}
+
+/* ffestc_V016_start -- RECORD statement list begin
+
+ ffestc_V016_start();
+
+ Verify that RECORD is valid here, and begin accepting items in the list. */
+
+#if FFESTR_VXT
+void
+ffestc_V016_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_record_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ switch (ffestw_state (ffestw_stack_top ()))
+ {
+ case FFESTV_stateSTRUCTURE:
+ case FFESTV_stateMAP:
+ ffestw_set_substate (ffestw_stack_top (), 1); /* Seen at least one
+ member. */
+ break;
+
+ default:
+ break;
+ }
+
+ ffestd_V016_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_V016_item_structure -- RECORD statement for common-block-name
+
+ ffestc_V016_item_structure(name_token);
+
+ Make sure name_token identifies a valid structure to be RECORDed. */
+
+void
+ffestc_V016_item_structure (ffelexToken name)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V016_item_structure (name);
+}
+
+/* ffestc_V016_item_object -- RECORD statement for object-name
+
+ ffestc_V016_item_object(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be RECORDd. */
+
+void
+ffestc_V016_item_object (ffelexToken name, ffesttDimList dims)
+{
+ ffestc_check_item_ ();
+ assert (name != NULL);
+ if (!ffestc_ok_)
+ return;
+
+ if (dims != NULL)
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+
+ ffestd_V016_item_object (name, dims);
+}
+
+/* ffestc_V016_finish -- RECORD statement list complete
+
+ ffestc_V016_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_V016_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V016_finish ();
+}
+
+/* ffestc_V018_start -- REWRITE(...) statement list begin
+
+ ffestc_V018_start();
+
+ Verify that REWRITE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_V018_start ()
+{
+ ffestvFormat format;
+
+ ffestc_check_start_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_branch_begin_ ();
+
+ if (!ffestc_subr_is_branch_
+ (&ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixERR])
+ || !ffestc_subr_is_format_
+ (&ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT])
+ || !ffestc_subr_is_present_ ("UNIT",
+ &ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixUNIT]))
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ format = ffestc_subr_format_
+ (&ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT]);
+ switch (format)
+ {
+ case FFESTV_formatNAMELIST:
+ case FFESTV_formatASTERISK:
+ ffebad_start (FFEBAD_CONFLICTING_SPECS);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ assert (ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].kw_or_val_present);
+ if (ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].kw_present)
+ {
+ ffebad_here (0, ffelex_token_where_line
+ (ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].kw),
+ ffelex_token_where_column
+ (ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].kw));
+ }
+ else
+ {
+ ffebad_here (1, ffelex_token_where_line
+ (ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].value),
+ ffelex_token_where_column
+ (ffestp_file.rewrite.rewrite_spec[FFESTP_rewriteixFMT].value));
+ }
+ ffebad_finish ();
+ ffestc_ok_ = FALSE;
+ return;
+
+ default:
+ break;
+ }
+
+ ffestd_V018_start (format);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_V018_item -- REWRITE statement i/o item
+
+ ffestc_V018_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestc_V018_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V018_item (expr);
+}
+
+/* ffestc_V018_finish -- REWRITE statement list complete
+
+ ffestc_V018_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_V018_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V018_finish ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_V019_start -- ACCEPT statement list begin
+
+ ffestc_V019_start();
+
+ Verify that ACCEPT is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_V019_start ()
+{
+ ffestvFormat format;
+
+ ffestc_check_start_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_branch_begin_ ();
+
+ if (!ffestc_subr_is_format_
+ (&ffestp_file.accept.accept_spec[FFESTP_acceptixFORMAT]))
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ format = ffestc_subr_format_
+ (&ffestp_file.accept.accept_spec[FFESTP_acceptixFORMAT]);
+ ffestc_namelist_ = (format == FFESTV_formatNAMELIST);
+
+ ffestd_V019_start (format);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_V019_item -- ACCEPT statement i/o item
+
+ ffestc_V019_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestc_V019_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_namelist_ != 0)
+ {
+ if (ffestc_namelist_ == 1)
+ {
+ ffestc_namelist_ = 2;
+ ffebad_start (FFEBAD_NAMELIST_ITEMS);
+ ffebad_here (0, ffelex_token_where_line (expr_token),
+ ffelex_token_where_column (expr_token));
+ ffebad_finish ();
+ }
+ return;
+ }
+
+ ffestd_V019_item (expr);
+}
+
+/* ffestc_V019_finish -- ACCEPT statement list complete
+
+ ffestc_V019_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_V019_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V019_finish ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+#endif
+/* ffestc_V020_start -- TYPE statement list begin
+
+ ffestc_V020_start();
+
+ Verify that TYPE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_V020_start ()
+{
+ ffestvFormat format;
+
+ ffestc_check_start_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_branch_begin_ ();
+
+ if (!ffestc_subr_is_format_
+ (&ffestp_file.type.type_spec[FFESTP_typeixFORMAT]))
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ format = ffestc_subr_format_
+ (&ffestp_file.type.type_spec[FFESTP_typeixFORMAT]);
+ ffestc_namelist_ = (format == FFESTV_formatNAMELIST);
+
+ ffestd_V020_start (format);
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_V020_item -- TYPE statement i/o item
+
+ ffestc_V020_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestc_V020_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ if (ffestc_namelist_ != 0)
+ {
+ if (ffestc_namelist_ == 1)
+ {
+ ffestc_namelist_ = 2;
+ ffebad_start (FFEBAD_NAMELIST_ITEMS);
+ ffebad_here (0, ffelex_token_where_line (expr_token),
+ ffelex_token_where_column (expr_token));
+ ffebad_finish ();
+ }
+ return;
+ }
+
+ ffestd_V020_item (expr);
+}
+
+/* ffestc_V020_finish -- TYPE statement list complete
+
+ ffestc_V020_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_V020_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V020_finish ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_V021 -- DELETE statement
+
+ ffestc_V021();
+
+ Make sure a DELETE is valid in the current context, and implement it. */
+
+#if FFESTR_VXT
+void
+ffestc_V021 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffestc_subr_is_branch_
+ (&ffestp_file.delete.delete_spec[FFESTP_deleteixERR])
+ && ffestc_subr_is_present_ ("UNIT",
+ &ffestp_file.delete.delete_spec[FFESTP_deleteixUNIT]))
+ ffestd_V021 ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_V022 -- UNLOCK statement
+
+ ffestc_V022();
+
+ Make sure a UNLOCK is valid in the current context, and implement it. */
+
+void
+ffestc_V022 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffestc_subr_is_branch_
+ (&ffestp_file.beru.beru_spec[FFESTP_beruixERR])
+ && ffestc_subr_is_present_ ("UNIT",
+ &ffestp_file.beru.beru_spec[FFESTP_beruixUNIT]))
+ ffestd_V022 ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_V023_start -- ENCODE(...) statement list begin
+
+ ffestc_V023_start();
+
+ Verify that ENCODE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_V023_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_branch_begin_ ();
+
+ if (!ffestc_subr_is_branch_
+ (&ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixERR]))
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ ffestd_V023_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_V023_item -- ENCODE statement i/o item
+
+ ffestc_V023_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestc_V023_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V023_item (expr);
+}
+
+/* ffestc_V023_finish -- ENCODE statement list complete
+
+ ffestc_V023_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_V023_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V023_finish ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_V024_start -- DECODE(...) statement list begin
+
+ ffestc_V024_start();
+
+ Verify that DECODE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_V024_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_branch_begin_ ();
+
+ if (!ffestc_subr_is_branch_
+ (&ffestp_file.vxtcode.vxtcode_spec[FFESTP_vxtcodeixERR]))
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+
+ ffestd_V024_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_V024_item -- DECODE statement i/o item
+
+ ffestc_V024_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestc_V024_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V024_item (expr);
+}
+
+/* ffestc_V024_finish -- DECODE statement list complete
+
+ ffestc_V024_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_V024_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V024_finish ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_V025_start -- DEFINEFILE statement list begin
+
+ ffestc_V025_start();
+
+ Verify that DEFINEFILE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestc_V025_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_branch_begin_ ();
+
+ ffestd_V025_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_V025_item -- DEFINE FILE statement item
+
+ ffestc_V025_item(u,ut,m,mt,n,nt,asv,asvt);
+
+ Implement item. */
+
+void
+ffestc_V025_item (ffebld u, ffelexToken ut, ffebld m, ffelexToken mt,
+ ffebld n, ffelexToken nt, ffebld asv, ffelexToken asvt)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V025_item (u, m, n, asv);
+}
+
+/* ffestc_V025_finish -- DEFINE FILE statement list complete
+
+ ffestc_V025_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_V025_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V025_finish ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+/* ffestc_V026 -- FIND statement
+
+ ffestc_V026();
+
+ Make sure a FIND is valid in the current context, and implement it. */
+
+void
+ffestc_V026 ()
+{
+ ffestc_check_simple_ ();
+ if (ffestc_order_actionif_ () != FFESTC_orderOK_)
+ return;
+ ffestc_labeldef_branch_begin_ ();
+
+ if (ffestc_subr_is_branch_
+ (&ffestp_file.find.find_spec[FFESTP_findixERR])
+ && ffestc_subr_is_present_ ("UNIT",
+ &ffestp_file.find.find_spec[FFESTP_findixUNIT])
+ && ffestc_subr_is_present_ ("REC",
+ &ffestp_file.find.find_spec[FFESTP_findixREC]))
+ ffestd_V026 ();
+
+ if (ffestc_shriek_after1_ != NULL)
+ (*ffestc_shriek_after1_) (TRUE);
+ ffestc_labeldef_branch_end_ ();
+}
+
+#endif
+/* ffestc_V027_start -- VXT PARAMETER statement list begin
+
+ ffestc_V027_start();
+
+ Verify that PARAMETER is valid here, and begin accepting items in the list. */
+
+void
+ffestc_V027_start ()
+{
+ ffestc_check_start_ ();
+ if (ffestc_order_parameter_ () != FFESTC_orderOK_)
+ {
+ ffestc_ok_ = FALSE;
+ return;
+ }
+ ffestc_labeldef_useless_ ();
+
+ ffestd_V027_start ();
+
+ ffestc_ok_ = TRUE;
+}
+
+/* ffestc_V027_item -- VXT PARAMETER statement assignment
+
+ ffestc_V027_item(dest,dest_token,source,source_token);
+
+ Make sure the source is a valid source for the destination; make the
+ assignment. */
+
+void
+ffestc_V027_item (ffelexToken dest_token, ffebld source,
+ ffelexToken source_token UNUSED)
+{
+ ffestc_check_item_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V027_item (dest_token, source);
+}
+
+/* ffestc_V027_finish -- VXT PARAMETER statement list complete
+
+ ffestc_V027_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestc_V027_finish ()
+{
+ ffestc_check_finish_ ();
+ if (!ffestc_ok_)
+ return;
+
+ ffestd_V027_finish ();
+}
+
+/* Any executable statement. Mainly make sure that one-shot things
+ like the statement for a logical IF are reset. */
+
+void
+ffestc_any ()
+{
+ ffestc_check_simple_ ();
+
+ ffestc_order_any_ ();
+
+ ffestc_labeldef_any_ ();
+
+ if (ffestc_shriek_after1_ == NULL)
+ return;
+
+ ffestd_any ();
+
+ (*ffestc_shriek_after1_) (TRUE);
+}
diff --git a/contrib/gcc/f/stc.h b/contrib/gcc/f/stc.h
new file mode 100644
index 0000000..c26fca1
--- /dev/null
+++ b/contrib/gcc/f/stc.h
@@ -0,0 +1,360 @@
+/* stc.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ stc.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_stc
+#define _H_f_stc
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "bad.h"
+#include "bld.h"
+#include "expr.h"
+#include "lex.h"
+#include "stp.h"
+#include "str.h"
+#include "stt.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+extern ffeexprContext ffestc_iolist_context_;
+
+/* Declare functions with prototypes. */
+
+void ffestc_decl_start (ffestpType type, ffelexToken typet, ffebld kind,
+ ffelexToken kindt, ffebld len, ffelexToken lent);
+void ffestc_decl_attrib (ffestpAttrib attrib, ffelexToken attribt,
+ ffestrOther intent_kw, ffesttDimList dims);
+void ffestc_decl_item (ffelexToken name, ffebld kind, ffelexToken kindt,
+ ffesttDimList dims, ffebld len, ffelexToken lent,
+ ffebld init, ffelexToken initt, bool clist);
+void ffestc_decl_itemstartvals (void);
+void ffestc_decl_itemvalue (ffebld repeat, ffelexToken repeat_token,
+ ffebld value, ffelexToken value_token);
+void ffestc_decl_itemendvals (ffelexToken t);
+void ffestc_decl_finish (void);
+void ffestc_elsewhere (ffelexToken where_token);
+void ffestc_end (void);
+void ffestc_eof (void);
+bool ffestc_exec_transition (void);
+void ffestc_ffebad_here_doiter (ffebadIndex i, ffesymbol s);
+void ffestc_init_3 (void);
+void ffestc_init_4 (void);
+bool ffestc_is_decl_not_R1219 (void);
+bool ffestc_is_entry_in_subr (void);
+bool ffestc_is_let_not_V027 (void);
+#if FFESTR_F90
+void ffestc_let (ffebld dest, ffebld source, ffelexToken source_token);
+#else
+#define ffestc_let ffestc_R737
+#endif
+#if FFESTR_F90
+void ffestc_module (ffelexToken module_name, ffelexToken procedure_name);
+#endif
+#if FFESTR_F90
+void ffestc_private (void);
+#endif
+void ffestc_terminate_4 (void);
+#if FFESTR_F90
+void ffestc_R423A (void);
+void ffestc_R423B (void);
+void ffestc_R424 (ffelexToken access, ffestrOther access_kw, ffelexToken name);
+void ffestc_R425 (ffelexToken name);
+void ffestc_R426_start (ffestpType type, ffelexToken typet, ffebld kind,
+ ffelexToken kindt, ffebld len, ffelexToken lent);
+void ffestc_R426_attrib (ffestpAttrib attrib, ffelexToken attribt,
+ ffestrOther intent_kw, ffesttDimList dims);
+void ffestc_R426_item (ffelexToken name, ffebld kind, ffelexToken kindt,
+ ffesttDimList dims, ffebld len, ffelexToken lent, ffebld init,
+ ffelexToken initt, bool clist);
+void ffestc_R426_itemstartvals (void);
+void ffestc_R426_itemvalue (ffebld repeat, ffelexToken repeat_token,
+ ffebld value, ffelexToken value_token);
+void ffestc_R426_itemendvals (ffelexToken t);
+void ffestc_R426_finish (void);
+#endif
+void ffestc_R501_start (ffestpType type, ffelexToken typet, ffebld kind,
+ ffelexToken kindt, ffebld len, ffelexToken lent);
+void ffestc_R501_attrib (ffestpAttrib attrib, ffelexToken attribt,
+ ffestrOther intent_kw, ffesttDimList dims);
+void ffestc_R501_item (ffelexToken name, ffebld kind, ffelexToken kindt,
+ ffesttDimList dims, ffebld len, ffelexToken lent, ffebld init,
+ ffelexToken initt, bool clist);
+void ffestc_R501_itemstartvals (void);
+void ffestc_R501_itemvalue (ffebld repeat, ffelexToken repeat_token,
+ ffebld value, ffelexToken value_token);
+void ffestc_R501_itemendvals (ffelexToken t);
+void ffestc_R501_finish (void);
+#if FFESTR_F90
+void ffestc_R519_start (ffelexToken intent, ffestrOther intent_kw);
+void ffestc_R519_item (ffelexToken name);
+void ffestc_R519_finish (void);
+void ffestc_R520_start (void);
+void ffestc_R520_item (ffelexToken name);
+void ffestc_R520_finish (void);
+void ffestc_R521A (void);
+void ffestc_R521Astart (void);
+void ffestc_R521Aitem (ffelexToken name);
+void ffestc_R521Afinish (void);
+void ffestc_R521B (void);
+void ffestc_R521Bstart (void);
+void ffestc_R521Bitem (ffelexToken name);
+void ffestc_R521Bfinish (void);
+#endif
+void ffestc_R522 (void);
+void ffestc_R522start (void);
+void ffestc_R522item_object (ffelexToken name);
+void ffestc_R522item_cblock (ffelexToken name);
+void ffestc_R522finish (void);
+void ffestc_R524_start (bool virtual);
+void ffestc_R524_item (ffelexToken name, ffesttDimList dims);
+void ffestc_R524_finish (void);
+#if FFESTR_F90
+void ffestc_R525_start (void);
+void ffestc_R525_item (ffelexToken name, ffesttDimList dims);
+void ffestc_R525_finish (void);
+void ffestc_R526_start (void);
+void ffestc_R526_item (ffelexToken name, ffesttDimList dims);
+void ffestc_R526_finish (void);
+void ffestc_R527_start (void);
+void ffestc_R527_item (ffelexToken name, ffesttDimList dims);
+void ffestc_R527_finish (void);
+#endif
+void ffestc_R528_start (void);
+void ffestc_R528_item_object (ffebld expr, ffelexToken expr_token);
+void ffestc_R528_item_startvals (void);
+void ffestc_R528_item_value (ffebld repeat, ffelexToken repeat_token,
+ ffebld value, ffelexToken value_token);
+void ffestc_R528_item_endvals (ffelexToken t);
+void ffestc_R528_finish (void);
+void ffestc_R537_start (void);
+void ffestc_R537_item (ffebld dest, ffelexToken dest_token, ffebld source,
+ ffelexToken source_token);
+void ffestc_R537_finish (void);
+void ffestc_R539 (void);
+void ffestc_R539start (void);
+void ffestc_R539item (ffestpType type, ffebld kind, ffelexToken kindt,
+ ffebld len, ffelexToken lent, ffesttImpList letters);
+void ffestc_R539finish (void);
+void ffestc_R542_start (void);
+void ffestc_R542_item_nlist (ffelexToken name);
+void ffestc_R542_item_nitem (ffelexToken name);
+void ffestc_R542_finish (void);
+void ffestc_R544_start (void);
+void ffestc_R544_item (ffesttExprList exprlist);
+void ffestc_R544_finish (void);
+void ffestc_R547_start (void);
+void ffestc_R547_item_object (ffelexToken name, ffesttDimList dims);
+void ffestc_R547_item_cblock (ffelexToken name);
+void ffestc_R547_finish (void);
+#if FFESTR_F90
+void ffestc_R620 (ffesttExprList objects, ffebld stat,
+ ffelexToken stat_token);
+void ffestc_R624 (ffesttExprList pointers);
+void ffestc_R625 (ffesttExprList objects, ffebld stat,
+ ffelexToken stat_token);
+#endif
+void ffestc_R737 (ffebld dest, ffebld source, ffelexToken source_token);
+#if FFESTR_F90
+void ffestc_R738 (ffebld dest, ffebld source, ffelexToken source_token);
+void ffestc_R740 (ffebld expr, ffelexToken expr_token);
+void ffestc_R742 (ffebld expr, ffelexToken expr_token);
+void ffestc_R744 (void);
+void ffestc_R745 (void);
+#endif
+void ffestc_R803 (ffelexToken construct_name, ffebld expr,
+ ffelexToken expr_token);
+void ffestc_R804 (ffebld expr, ffelexToken expr_token, ffelexToken name);
+void ffestc_R805 (ffelexToken name);
+void ffestc_R806 (ffelexToken name);
+void ffestc_R807 (ffebld expr, ffelexToken expr_token);
+void ffestc_R809 (ffelexToken construct_name, ffebld expr,
+ ffelexToken expr_token);
+void ffestc_R810 (ffesttCaseList cases, ffelexToken name);
+void ffestc_R811 (ffelexToken name);
+void ffestc_R819A (ffelexToken construct_name, ffelexToken label, ffebld var,
+ ffelexToken var_token, ffebld start, ffelexToken start_token, ffebld end,
+ ffelexToken end_token, ffebld incr, ffelexToken incr_token);
+void ffestc_R819B (ffelexToken construct_name, ffelexToken label, ffebld expr,
+ ffelexToken expr_token);
+void ffestc_R820A (ffelexToken construct_name, ffebld var,
+ ffelexToken var_token, ffebld start, ffelexToken start_token, ffebld end,
+ ffelexToken end_token, ffebld incr, ffelexToken incr_token);
+void ffestc_R820B (ffelexToken construct_name, ffebld expr,
+ ffelexToken expr_token);
+void ffestc_R825 (ffelexToken name);
+void ffestc_R834 (ffelexToken name);
+void ffestc_R835 (ffelexToken name);
+void ffestc_R836 (ffelexToken label);
+void ffestc_R837 (ffesttTokenList label_toks, ffebld expr,
+ ffelexToken expr_token);
+void ffestc_R838 (ffelexToken label, ffebld target, ffelexToken target_token);
+void ffestc_R839 (ffebld target, ffelexToken target_token,
+ ffesttTokenList label_toks);
+void ffestc_R840 (ffebld expr, ffelexToken expr_token, ffelexToken neg,
+ ffelexToken zero, ffelexToken pos);
+void ffestc_R841 (void);
+void ffestc_R842 (ffebld expr, ffelexToken expr_token);
+void ffestc_R843 (ffebld expr, ffelexToken expr_token);
+void ffestc_R904 (void);
+void ffestc_R907 (void);
+void ffestc_R909_start (bool only_format);
+void ffestc_R909_item (ffebld expr, ffelexToken expr_token);
+void ffestc_R909_finish (void);
+void ffestc_R910_start (void);
+void ffestc_R910_item (ffebld expr, ffelexToken expr_token);
+void ffestc_R910_finish (void);
+void ffestc_R911_start (void);
+void ffestc_R911_item (ffebld expr, ffelexToken expr_token);
+void ffestc_R911_finish (void);
+void ffestc_R919 (void);
+void ffestc_R920 (void);
+void ffestc_R921 (void);
+void ffestc_R923A (void);
+void ffestc_R923B_start (void);
+void ffestc_R923B_item (ffebld expr, ffelexToken expr_token);
+void ffestc_R923B_finish (void);
+void ffestc_R1001 (ffesttFormatList f);
+void ffestc_R1102 (ffelexToken name);
+void ffestc_R1103 (ffelexToken name);
+#if FFESTR_F90
+void ffestc_R1105 (ffelexToken name);
+void ffestc_R1106 (ffelexToken name);
+void ffestc_R1107_start (ffelexToken name, bool only);
+void ffestc_R1107_item (ffelexToken local, ffelexToken use);
+void ffestc_R1107_finish (void);
+#endif
+void ffestc_R1111 (ffelexToken name);
+void ffestc_R1112 (ffelexToken name);
+#if FFESTR_F90
+void ffestc_R1202 (ffestpDefinedOperator operator, ffelexToken name);
+void ffestc_R1203 (void);
+void ffestc_R1205_start (void);
+void ffestc_R1205_item (ffelexToken name);
+void ffestc_R1205_finish (void);
+#endif
+void ffestc_R1207_start (void);
+void ffestc_R1207_item (ffelexToken name);
+void ffestc_R1207_finish (void);
+void ffestc_R1208_start (void);
+void ffestc_R1208_item (ffelexToken name);
+void ffestc_R1208_finish (void);
+void ffestc_R1212 (ffebld expr, ffelexToken expr_token);
+#if FFESTR_F90
+void ffestc_R1213 (ffebld dest, ffebld source, ffelexToken source_token);
+#endif
+void ffestc_R1219 (ffelexToken funcname, ffesttTokenList args,
+ ffelexToken final, ffestpType type, ffebld kind, ffelexToken kindt,
+ ffebld len, ffelexToken lent, ffelexToken recursive, ffelexToken result);
+void ffestc_R1221 (ffelexToken name);
+void ffestc_R1223 (ffelexToken subrname, ffesttTokenList args,
+ ffelexToken final, ffelexToken recursive);
+void ffestc_R1225 (ffelexToken name);
+void ffestc_R1226 (ffelexToken entryname, ffesttTokenList args,
+ ffelexToken final);
+void ffestc_R1227 (ffebld expr, ffelexToken expr_token);
+#if FFESTR_F90
+void ffestc_R1228 (void);
+#endif
+void ffestc_R1229_start (ffelexToken name, ffesttTokenList args,
+ ffelexToken final);
+void ffestc_R1229_finish (ffebld expr, ffelexToken expr_token);
+void ffestc_S3P4 (ffebld filename, ffelexToken filename_token);
+#if FFESTR_VXT
+void ffestc_V003_start (ffelexToken structure_name);
+void ffestc_V003_item (ffelexToken name, ffesttDimList dims);
+void ffestc_V003_finish (void);
+void ffestc_V004 (void);
+void ffestc_V009 (void);
+void ffestc_V010 (void);
+void ffestc_V012 (void);
+void ffestc_V013 (void);
+#endif
+void ffestc_V014_start (void);
+void ffestc_V014_item_object (ffelexToken name);
+void ffestc_V014_item_cblock (ffelexToken name);
+void ffestc_V014_finish (void);
+#if FFESTR_VXT
+void ffestc_V016_start (void);
+void ffestc_V016_item_structure (ffelexToken name);
+void ffestc_V016_item_object (ffelexToken name, ffesttDimList dims);
+void ffestc_V016_finish (void);
+void ffestc_V018_start (void);
+void ffestc_V018_item (ffebld expr, ffelexToken expr_token);
+void ffestc_V018_finish (void);
+void ffestc_V019_start (void);
+void ffestc_V019_item (ffebld expr, ffelexToken expr_token);
+void ffestc_V019_finish (void);
+#endif
+void ffestc_V020_start (void);
+void ffestc_V020_item (ffebld expr, ffelexToken expr_token);
+void ffestc_V020_finish (void);
+#if FFESTR_VXT
+void ffestc_V021 (void);
+void ffestc_V022 (void);
+void ffestc_V023_start (void);
+void ffestc_V023_item (ffebld expr, ffelexToken expr_token);
+void ffestc_V023_finish (void);
+void ffestc_V024_start (void);
+void ffestc_V024_item (ffebld expr, ffelexToken expr_token);
+void ffestc_V024_finish (void);
+void ffestc_V025_start (void);
+void ffestc_V025_item (ffebld u, ffelexToken ut, ffebld m, ffelexToken mt,
+ ffebld n, ffelexToken nt, ffebld asv, ffelexToken asvt);
+void ffestc_V025_finish (void);
+void ffestc_V026 (void);
+#endif
+void ffestc_V027_start (void);
+void ffestc_V027_item (ffelexToken dest_token, ffebld source,
+ ffelexToken source_token);
+void ffestc_V027_finish (void);
+void ffestc_any (void);
+
+/* Define macros. */
+
+#define ffestc_context_iolist() ffestc_iolist_context_
+#define ffestc_init_0()
+#define ffestc_init_1()
+#define ffestc_init_2()
+#define ffestc_terminate_0()
+#define ffestc_terminate_1()
+#define ffestc_terminate_2()
+#define ffestc_terminate_3()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/std.c b/contrib/gcc/f/std.c
new file mode 100644
index 0000000..540da6c
--- /dev/null
+++ b/contrib/gcc/f/std.c
@@ -0,0 +1,6905 @@
+/* std.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ st.c
+
+ Description:
+ Implements the various statements and such like.
+
+ Modifications:
+ 21-Nov-91 JCB 2.0
+ Split out actual code generation to ffeste.
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "std.h"
+#include "bld.h"
+#include "com.h"
+#include "lab.h"
+#include "lex.h"
+#include "malloc.h"
+#include "sta.h"
+#include "ste.h"
+#include "stp.h"
+#include "str.h"
+#include "sts.h"
+#include "stt.h"
+#include "stv.h"
+#include "stw.h"
+#include "symbol.h"
+#include "target.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+#define FFESTD_COPY_EASY_ 1 /* 1 for only one _subr_copy_xyz_ fn. */
+
+#define FFESTD_IS_END_OPTIMIZED_ 1 /* 0=always gen STOP/RETURN before
+ END. */
+
+typedef enum
+ {
+ FFESTD_stateletSIMPLE_, /* Expecting simple/start. */
+ FFESTD_stateletATTRIB_, /* Expecting attrib/item/itemstart. */
+ FFESTD_stateletITEM_, /* Expecting item/itemstart/finish. */
+ FFESTD_stateletITEMVALS_, /* Expecting itemvalue/itemendvals. */
+ FFESTD_
+ } ffestdStatelet_;
+
+#if FFECOM_TWOPASS
+typedef enum
+ {
+ FFESTD_stmtidENDDOLOOP_,
+ FFESTD_stmtidENDLOGIF_,
+ FFESTD_stmtidEXECLABEL_,
+ FFESTD_stmtidFORMATLABEL_,
+ FFESTD_stmtidR737A_, /* let */
+ FFESTD_stmtidR803_, /* IF-block */
+ FFESTD_stmtidR804_, /* ELSE IF */
+ FFESTD_stmtidR805_, /* ELSE */
+ FFESTD_stmtidR806_, /* END IF */
+ FFESTD_stmtidR807_, /* IF-logical */
+ FFESTD_stmtidR809_, /* SELECT CASE */
+ FFESTD_stmtidR810_, /* CASE */
+ FFESTD_stmtidR811_, /* END SELECT */
+ FFESTD_stmtidR819A_, /* DO-iterative */
+ FFESTD_stmtidR819B_, /* DO WHILE */
+ FFESTD_stmtidR825_, /* END DO */
+ FFESTD_stmtidR834_, /* CYCLE */
+ FFESTD_stmtidR835_, /* EXIT */
+ FFESTD_stmtidR836_, /* GOTO */
+ FFESTD_stmtidR837_, /* GOTO-computed */
+ FFESTD_stmtidR838_, /* ASSIGN */
+ FFESTD_stmtidR839_, /* GOTO-assigned */
+ FFESTD_stmtidR840_, /* IF-arithmetic */
+ FFESTD_stmtidR841_, /* CONTINUE */
+ FFESTD_stmtidR842_, /* STOP */
+ FFESTD_stmtidR843_, /* PAUSE */
+ FFESTD_stmtidR904_, /* OPEN */
+ FFESTD_stmtidR907_, /* CLOSE */
+ FFESTD_stmtidR909_, /* READ */
+ FFESTD_stmtidR910_, /* WRITE */
+ FFESTD_stmtidR911_, /* PRINT */
+ FFESTD_stmtidR919_, /* BACKSPACE */
+ FFESTD_stmtidR920_, /* ENDFILE */
+ FFESTD_stmtidR921_, /* REWIND */
+ FFESTD_stmtidR923A_, /* INQUIRE */
+ FFESTD_stmtidR923B_, /* INQUIRE-iolength */
+ FFESTD_stmtidR1001_, /* FORMAT */
+ FFESTD_stmtidR1103_, /* END_PROGRAM */
+ FFESTD_stmtidR1112_, /* END_BLOCK_DATA */
+ FFESTD_stmtidR1212_, /* CALL */
+ FFESTD_stmtidR1221_, /* END_FUNCTION */
+ FFESTD_stmtidR1225_, /* END_SUBROUTINE */
+ FFESTD_stmtidR1226_, /* ENTRY */
+ FFESTD_stmtidR1227_, /* RETURN */
+#if FFESTR_VXT
+ FFESTD_stmtidV018_, /* REWRITE */
+ FFESTD_stmtidV019_, /* ACCEPT */
+#endif
+ FFESTD_stmtidV020_, /* TYPE */
+#if FFESTR_VXT
+ FFESTD_stmtidV021_, /* DELETE */
+ FFESTD_stmtidV022_, /* UNLOCK */
+ FFESTD_stmtidV023_, /* ENCODE */
+ FFESTD_stmtidV024_, /* DECODE */
+ FFESTD_stmtidV025start_, /* DEFINEFILE (start) */
+ FFESTD_stmtidV025item_, /* (DEFINEFILE item) */
+ FFESTD_stmtidV025finish_, /* (DEFINEFILE finish) */
+ FFESTD_stmtidV026_, /* FIND */
+#endif
+ FFESTD_stmtid_,
+ } ffestdStmtId_;
+
+#endif
+
+/* Internal typedefs. */
+
+typedef struct _ffestd_expr_item_ *ffestdExprItem_;
+#if FFECOM_TWOPASS
+typedef struct _ffestd_stmt_ *ffestdStmt_;
+#endif
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+struct _ffestd_expr_item_
+ {
+ ffestdExprItem_ next;
+ ffebld expr;
+ ffelexToken token;
+ };
+
+#if FFECOM_TWOPASS
+struct _ffestd_stmt_
+ {
+ ffestdStmt_ next;
+ ffestdStmt_ previous;
+ ffestdStmtId_ id;
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ char *filename;
+ int filelinenum;
+#endif
+ union
+ {
+ struct
+ {
+ ffestw block;
+ }
+ enddoloop;
+ struct
+ {
+ ffelab label;
+ }
+ execlabel;
+ struct
+ {
+ ffelab label;
+ }
+ formatlabel;
+ struct
+ {
+ mallocPool pool;
+ ffebld dest;
+ ffebld source;
+ }
+ R737A;
+ struct
+ {
+ mallocPool pool;
+ ffebld expr;
+ }
+ R803;
+ struct
+ {
+ mallocPool pool;
+ ffebld expr;
+ }
+ R804;
+ struct
+ {
+ mallocPool pool;
+ ffebld expr;
+ }
+ R807;
+ struct
+ {
+ mallocPool pool;
+ ffestw block;
+ ffebld expr;
+ }
+ R809;
+ struct
+ {
+ mallocPool pool;
+ ffestw block;
+ unsigned long casenum;
+ }
+ R810;
+ struct
+ {
+ ffestw block;
+ }
+ R811;
+ struct
+ {
+ mallocPool pool;
+ ffestw block;
+ ffelab label;
+ ffebld var;
+ ffebld start;
+ ffelexToken start_token;
+ ffebld end;
+ ffelexToken end_token;
+ ffebld incr;
+ ffelexToken incr_token;
+ }
+ R819A;
+ struct
+ {
+ mallocPool pool;
+ ffestw block;
+ ffelab label;
+ ffebld expr;
+ }
+ R819B;
+ struct
+ {
+ ffestw block;
+ }
+ R834;
+ struct
+ {
+ ffestw block;
+ }
+ R835;
+ struct
+ {
+ ffelab label;
+ }
+ R836;
+ struct
+ {
+ mallocPool pool;
+ ffelab *labels;
+ int count;
+ ffebld expr;
+ }
+ R837;
+ struct
+ {
+ mallocPool pool;
+ ffelab label;
+ ffebld target;
+ }
+ R838;
+ struct
+ {
+ mallocPool pool;
+ ffebld target;
+ }
+ R839;
+ struct
+ {
+ mallocPool pool;
+ ffebld expr;
+ ffelab neg;
+ ffelab zero;
+ ffelab pos;
+ }
+ R840;
+ struct
+ {
+ mallocPool pool;
+ ffebld expr;
+ }
+ R842;
+ struct
+ {
+ mallocPool pool;
+ ffebld expr;
+ }
+ R843;
+ struct
+ {
+ mallocPool pool;
+ ffestpOpenStmt *params;
+ }
+ R904;
+ struct
+ {
+ mallocPool pool;
+ ffestpCloseStmt *params;
+ }
+ R907;
+ struct
+ {
+ mallocPool pool;
+ ffestpReadStmt *params;
+ bool only_format;
+ ffestvUnit unit;
+ ffestvFormat format;
+ bool rec;
+ bool key;
+ ffestdExprItem_ list;
+ }
+ R909;
+ struct
+ {
+ mallocPool pool;
+ ffestpWriteStmt *params;
+ ffestvUnit unit;
+ ffestvFormat format;
+ bool rec;
+ ffestdExprItem_ list;
+ }
+ R910;
+ struct
+ {
+ mallocPool pool;
+ ffestpPrintStmt *params;
+ ffestvFormat format;
+ ffestdExprItem_ list;
+ }
+ R911;
+ struct
+ {
+ mallocPool pool;
+ ffestpBeruStmt *params;
+ }
+ R919;
+ struct
+ {
+ mallocPool pool;
+ ffestpBeruStmt *params;
+ }
+ R920;
+ struct
+ {
+ mallocPool pool;
+ ffestpBeruStmt *params;
+ }
+ R921;
+ struct
+ {
+ mallocPool pool;
+ ffestpInquireStmt *params;
+ bool by_file;
+ }
+ R923A;
+ struct
+ {
+ mallocPool pool;
+ ffestpInquireStmt *params;
+ ffestdExprItem_ list;
+ }
+ R923B;
+ struct
+ {
+ ffestsHolder str;
+ }
+ R1001;
+ struct
+ {
+ mallocPool pool;
+ ffebld expr;
+ }
+ R1212;
+ struct
+ {
+ ffesymbol entry;
+ int entrynum;
+ }
+ R1226;
+ struct
+ {
+ mallocPool pool;
+ ffestw block;
+ ffebld expr;
+ }
+ R1227;
+#if FFESTR_VXT
+ struct
+ {
+ mallocPool pool;
+ ffestpRewriteStmt *params;
+ ffestvFormat format;
+ ffestdExprItem_ list;
+ }
+ V018;
+ struct
+ {
+ mallocPool pool;
+ ffestpAcceptStmt *params;
+ ffestvFormat format;
+ ffestdExprItem_ list;
+ }
+ V019;
+#endif
+ struct
+ {
+ mallocPool pool;
+ ffestpTypeStmt *params;
+ ffestvFormat format;
+ ffestdExprItem_ list;
+ }
+ V020;
+#if FFESTR_VXT
+ struct
+ {
+ mallocPool pool;
+ ffestpDeleteStmt *params;
+ }
+ V021;
+ struct
+ {
+ mallocPool pool;
+ ffestpBeruStmt *params;
+ }
+ V022;
+ struct
+ {
+ mallocPool pool;
+ ffestpVxtcodeStmt *params;
+ ffestdExprItem_ list;
+ }
+ V023;
+ struct
+ {
+ mallocPool pool;
+ ffestpVxtcodeStmt *params;
+ ffestdExprItem_ list;
+ }
+ V024;
+ struct
+ {
+ ffebld u;
+ ffebld m;
+ ffebld n;
+ ffebld asv;
+ }
+ V025item;
+ struct
+ {
+ mallocPool pool;
+ } V025finish;
+ struct
+ {
+ mallocPool pool;
+ ffestpFindStmt *params;
+ }
+ V026;
+#endif
+ }
+ u;
+ };
+
+#endif
+
+/* Static objects accessed by functions in this module. */
+
+static ffestdStatelet_ ffestd_statelet_ = FFESTD_stateletSIMPLE_;
+static int ffestd_block_level_ = 0; /* Block level for reachableness. */
+static bool ffestd_is_reachable_; /* Is the current stmt reachable? */
+static ffelab ffestd_label_formatdef_ = NULL;
+#if FFECOM_TWOPASS
+static ffestdExprItem_ *ffestd_expr_list_;
+static struct
+ {
+ ffestdStmt_ first;
+ ffestdStmt_ last;
+ }
+
+ffestd_stmt_list_
+=
+{
+ NULL, NULL
+};
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static int ffestd_2pass_entrypoints_ = 0; /* # ENTRY statements
+ pending. */
+#endif
+
+/* Static functions (internal). */
+
+#if FFECOM_TWOPASS
+static void ffestd_stmt_append_ (ffestdStmt_ stmt);
+static ffestdStmt_ ffestd_stmt_new_ (ffestdStmtId_ id);
+static void ffestd_stmt_pass_ (void);
+#endif
+#if FFESTD_COPY_EASY_ && FFECOM_TWOPASS
+static ffestpInquireStmt *ffestd_subr_copy_easy_ (ffestpInquireIx max);
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void ffestd_subr_vxt_ (void);
+#endif
+#if FFESTR_F90
+static void ffestd_subr_f90_ (void);
+#endif
+static void ffestd_subr_labels_ (bool unexpected);
+static void ffestd_R1001dump_ (ffests s, ffesttFormatList list);
+static void ffestd_R1001dump_1005_1_ (ffests s, ffesttFormatList f,
+ char *string);
+static void ffestd_R1001dump_1005_2_ (ffests s, ffesttFormatList f,
+ char *string);
+static void ffestd_R1001dump_1005_3_ (ffests s, ffesttFormatList f,
+ char *string);
+static void ffestd_R1001dump_1005_4_ (ffests s, ffesttFormatList f,
+ char *string);
+static void ffestd_R1001dump_1005_5_ (ffests s, ffesttFormatList f,
+ char *string);
+static void ffestd_R1001dump_1010_1_ (ffests s, ffesttFormatList f,
+ char *string);
+static void ffestd_R1001dump_1010_2_ (ffests s, ffesttFormatList f,
+ char *string);
+static void ffestd_R1001dump_1010_3_ (ffests s, ffesttFormatList f,
+ char *string);
+static void ffestd_R1001dump_1010_4_ (ffests s, ffesttFormatList f,
+ char *string);
+static void ffestd_R1001dump_1010_5_ (ffests s, ffesttFormatList f,
+ char *string);
+static void ffestd_R1001error_ (ffesttFormatList f);
+static void ffestd_R1001rtexpr_ (ffests s, ffesttFormatList f, ffebld expr);
+
+/* Internal macros. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define ffestd_subr_line_now_() \
+ ffeste_set_line (ffelex_token_where_filename (ffesta_tokens[0]), \
+ ffelex_token_where_filelinenum (ffesta_tokens[0]))
+#define ffestd_subr_line_restore_(s) \
+ ffeste_set_line ((s)->filename, (s)->filelinenum)
+#define ffestd_subr_line_save_(s) \
+ ((s)->filename = ffelex_token_where_filename (ffesta_tokens[0]), \
+ (s)->filelinenum = ffelex_token_where_filelinenum (ffesta_tokens[0]))
+#else
+#define ffestd_subr_line_now_()
+#if FFECOM_TWOPASS
+#define ffestd_subr_line_restore_(s)
+#define ffestd_subr_line_save_(s)
+#endif /* FFECOM_TWOPASS */
+#endif /* FFECOM_targetCURRENT != FFECOM_targetGCC */
+#define ffestd_check_simple_() \
+ assert(ffestd_statelet_ == FFESTD_stateletSIMPLE_)
+#define ffestd_check_start_() \
+ assert(ffestd_statelet_ == FFESTD_stateletSIMPLE_); \
+ ffestd_statelet_ = FFESTD_stateletATTRIB_
+#define ffestd_check_attrib_() \
+ assert(ffestd_statelet_ == FFESTD_stateletATTRIB_)
+#define ffestd_check_item_() \
+ assert(ffestd_statelet_ == FFESTD_stateletATTRIB_ \
+ || ffestd_statelet_ == FFESTD_stateletITEM_); \
+ ffestd_statelet_ = FFESTD_stateletITEM_
+#define ffestd_check_item_startvals_() \
+ assert(ffestd_statelet_ == FFESTD_stateletATTRIB_ \
+ || ffestd_statelet_ == FFESTD_stateletITEM_); \
+ ffestd_statelet_ = FFESTD_stateletITEMVALS_
+#define ffestd_check_item_value_() \
+ assert(ffestd_statelet_ == FFESTD_stateletITEMVALS_)
+#define ffestd_check_item_endvals_() \
+ assert(ffestd_statelet_ == FFESTD_stateletITEMVALS_); \
+ ffestd_statelet_ = FFESTD_stateletITEM_
+#define ffestd_check_finish_() \
+ assert(ffestd_statelet_ == FFESTD_stateletATTRIB_ \
+ || ffestd_statelet_ == FFESTD_stateletITEM_); \
+ ffestd_statelet_ = FFESTD_stateletSIMPLE_
+
+#if FFESTD_COPY_EASY_ && FFECOM_TWOPASS
+#define ffestd_subr_copy_accept_() (ffestpAcceptStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_acceptix)
+#define ffestd_subr_copy_beru_() (ffestpBeruStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_beruix)
+#define ffestd_subr_copy_close_() (ffestpCloseStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_closeix)
+#define ffestd_subr_copy_delete_() (ffestpDeleteStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_deleteix)
+#define ffestd_subr_copy_find_() (ffestpFindStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_findix)
+#define ffestd_subr_copy_inquire_() (ffestpInquireStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_inquireix)
+#define ffestd_subr_copy_open_() (ffestpOpenStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_openix)
+#define ffestd_subr_copy_print_() (ffestpPrintStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_printix)
+#define ffestd_subr_copy_read_() (ffestpReadStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_readix)
+#define ffestd_subr_copy_rewrite_() (ffestpRewriteStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_rewriteix)
+#define ffestd_subr_copy_type_() (ffestpTypeStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_typeix)
+#define ffestd_subr_copy_vxtcode_() (ffestpVxtcodeStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_vxtcodeix)
+#define ffestd_subr_copy_write_() (ffestpWriteStmt *) \
+ ffestd_subr_copy_easy_((ffestpInquireIx) FFESTP_writeix)
+#endif
+
+/* ffestd_stmt_append_ -- Append statement to end of stmt list
+
+ ffestd_stmt_append_(ffestd_stmt_new_(FFESTD_stmtidR737A_)); */
+
+#if FFECOM_TWOPASS
+static void
+ffestd_stmt_append_ (ffestdStmt_ stmt)
+{
+ stmt->next = (ffestdStmt_) &ffestd_stmt_list_.first;
+ stmt->previous = ffestd_stmt_list_.last;
+ stmt->next->previous = stmt;
+ stmt->previous->next = stmt;
+}
+
+#endif
+/* ffestd_stmt_new_ -- Make new statement with given id
+
+ ffestdStmt_ stmt;
+ stmt = ffestd_stmt_new_(FFESTD_stmtidR737A_); */
+
+#if FFECOM_TWOPASS
+static ffestdStmt_
+ffestd_stmt_new_ (ffestdStmtId_ id)
+{
+ ffestdStmt_ stmt;
+
+ stmt = malloc_new_kp (ffe_pool_any_unit (), "ffestdStmt_", sizeof (*stmt));
+ stmt->id = id;
+ return stmt;
+}
+
+#endif
+/* ffestd_stmt_pass_ -- Pass all statements on list to ffeste
+
+ ffestd_stmt_pass_(); */
+
+#if FFECOM_TWOPASS
+static void
+ffestd_stmt_pass_ ()
+{
+ ffestdStmt_ stmt;
+ ffestdExprItem_ expr; /* For traversing lists. */
+ bool okay = (TREE_CODE (current_function_decl) != ERROR_MARK);
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ if ((ffestd_2pass_entrypoints_ != 0) && okay)
+ {
+ tree which = ffecom_which_entrypoint_decl ();
+ tree value;
+ tree label;
+ int pushok;
+ int ents = ffestd_2pass_entrypoints_;
+ tree duplicate;
+
+ expand_start_case (0, which, TREE_TYPE (which), "entrypoint dispatch");
+ push_momentary ();
+
+ stmt = ffestd_stmt_list_.first;
+ do
+ {
+ while (stmt->id != FFESTD_stmtidR1226_)
+ stmt = stmt->next;
+
+ if (stmt->u.R1226.entry != NULL)
+ {
+ value = build_int_2 (stmt->u.R1226.entrynum, 0);
+ /* Yes, we really want to build a null LABEL_DECL here and not
+ put it on any list. That's what pushcase wants, so that's
+ what it gets! */
+ label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ pushok = pushcase (value, convert, label, &duplicate);
+ assert (pushok == 0);
+
+ label = ffecom_temp_label ();
+ TREE_USED (label) = 1;
+ expand_goto (label);
+ clear_momentary ();
+
+ ffesymbol_hook (stmt->u.R1226.entry).length_tree = label;
+ }
+ stmt = stmt->next;
+ }
+ while (--ents != 0);
+
+ pop_momentary ();
+ expand_end_case (which);
+ clear_momentary ();
+ }
+#endif
+
+ for (stmt = ffestd_stmt_list_.first;
+ stmt != (ffestdStmt_) &ffestd_stmt_list_.first;
+ stmt = stmt->next)
+ {
+ switch (stmt->id)
+ {
+ case FFESTD_stmtidENDDOLOOP_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_do (stmt->u.enddoloop.block);
+ ffestw_kill (stmt->u.enddoloop.block);
+ break;
+
+ case FFESTD_stmtidENDLOGIF_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_end_R807 ();
+ break;
+
+ case FFESTD_stmtidEXECLABEL_:
+ if (okay)
+ ffeste_labeldef_branch (stmt->u.execlabel.label);
+ break;
+
+ case FFESTD_stmtidFORMATLABEL_:
+ if (okay)
+ ffeste_labeldef_format (stmt->u.formatlabel.label);
+ break;
+
+ case FFESTD_stmtidR737A_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R737A (stmt->u.R737A.dest, stmt->u.R737A.source);
+ malloc_pool_kill (stmt->u.R737A.pool);
+ break;
+
+ case FFESTD_stmtidR803_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R803 (stmt->u.R803.expr);
+ malloc_pool_kill (stmt->u.R803.pool);
+ break;
+
+ case FFESTD_stmtidR804_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R804 (stmt->u.R804.expr);
+ malloc_pool_kill (stmt->u.R804.pool);
+ break;
+
+ case FFESTD_stmtidR805_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R805 ();
+ break;
+
+ case FFESTD_stmtidR806_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R806 ();
+ break;
+
+ case FFESTD_stmtidR807_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R807 (stmt->u.R807.expr);
+ malloc_pool_kill (stmt->u.R807.pool);
+ break;
+
+ case FFESTD_stmtidR809_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R809 (stmt->u.R809.block, stmt->u.R809.expr);
+ malloc_pool_kill (stmt->u.R809.pool);
+ break;
+
+ case FFESTD_stmtidR810_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R810 (stmt->u.R810.block, stmt->u.R810.casenum);
+ malloc_pool_kill (stmt->u.R810.pool);
+ break;
+
+ case FFESTD_stmtidR811_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R811 (stmt->u.R811.block);
+ malloc_pool_kill (ffestw_select (stmt->u.R811.block)->pool);
+ ffestw_kill (stmt->u.R811.block);
+ break;
+
+ case FFESTD_stmtidR819A_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R819A (stmt->u.R819A.block, stmt->u.R819A.label,
+ stmt->u.R819A.var,
+ stmt->u.R819A.start, stmt->u.R819A.start_token,
+ stmt->u.R819A.end, stmt->u.R819A.end_token,
+ stmt->u.R819A.incr, stmt->u.R819A.incr_token);
+ ffelex_token_kill (stmt->u.R819A.start_token);
+ ffelex_token_kill (stmt->u.R819A.end_token);
+ if (stmt->u.R819A.incr_token != NULL)
+ ffelex_token_kill (stmt->u.R819A.incr_token);
+ malloc_pool_kill (stmt->u.R819A.pool);
+ break;
+
+ case FFESTD_stmtidR819B_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R819B (stmt->u.R819B.block, stmt->u.R819B.label,
+ stmt->u.R819B.expr);
+ malloc_pool_kill (stmt->u.R819B.pool);
+ break;
+
+ case FFESTD_stmtidR825_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R825 ();
+ break;
+
+ case FFESTD_stmtidR834_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R834 (stmt->u.R834.block);
+ break;
+
+ case FFESTD_stmtidR835_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R835 (stmt->u.R835.block);
+ break;
+
+ case FFESTD_stmtidR836_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R836 (stmt->u.R836.label);
+ break;
+
+ case FFESTD_stmtidR837_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R837 (stmt->u.R837.labels, stmt->u.R837.count,
+ stmt->u.R837.expr);
+ malloc_pool_kill (stmt->u.R837.pool);
+ break;
+
+ case FFESTD_stmtidR838_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R838 (stmt->u.R838.label, stmt->u.R838.target);
+ malloc_pool_kill (stmt->u.R838.pool);
+ break;
+
+ case FFESTD_stmtidR839_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R839 (stmt->u.R839.target);
+ malloc_pool_kill (stmt->u.R839.pool);
+ break;
+
+ case FFESTD_stmtidR840_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R840 (stmt->u.R840.expr, stmt->u.R840.neg, stmt->u.R840.zero,
+ stmt->u.R840.pos);
+ malloc_pool_kill (stmt->u.R840.pool);
+ break;
+
+ case FFESTD_stmtidR841_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R841 ();
+ break;
+
+ case FFESTD_stmtidR842_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R842 (stmt->u.R842.expr);
+ if (stmt->u.R842.pool != NULL)
+ malloc_pool_kill (stmt->u.R842.pool);
+ break;
+
+ case FFESTD_stmtidR843_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R843 (stmt->u.R843.expr);
+ malloc_pool_kill (stmt->u.R843.pool);
+ break;
+
+ case FFESTD_stmtidR904_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R904 (stmt->u.R904.params);
+ malloc_pool_kill (stmt->u.R904.pool);
+ break;
+
+ case FFESTD_stmtidR907_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R907 (stmt->u.R907.params);
+ malloc_pool_kill (stmt->u.R907.pool);
+ break;
+
+ case FFESTD_stmtidR909_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R909_start (stmt->u.R909.params, stmt->u.R909.only_format,
+ stmt->u.R909.unit, stmt->u.R909.format,
+ stmt->u.R909.rec, stmt->u.R909.key);
+ for (expr = stmt->u.R909.list; expr != NULL; expr = expr->next)
+ {
+ if (okay)
+ ffeste_R909_item (expr->expr, expr->token);
+ ffelex_token_kill (expr->token);
+ }
+ if (okay)
+ ffeste_R909_finish ();
+ malloc_pool_kill (stmt->u.R909.pool);
+ break;
+
+ case FFESTD_stmtidR910_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R910_start (stmt->u.R910.params, stmt->u.R910.unit,
+ stmt->u.R910.format, stmt->u.R910.rec);
+ for (expr = stmt->u.R910.list; expr != NULL; expr = expr->next)
+ {
+ if (okay)
+ ffeste_R910_item (expr->expr, expr->token);
+ ffelex_token_kill (expr->token);
+ }
+ if (okay)
+ ffeste_R910_finish ();
+ malloc_pool_kill (stmt->u.R910.pool);
+ break;
+
+ case FFESTD_stmtidR911_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R911_start (stmt->u.R911.params, stmt->u.R911.format);
+ for (expr = stmt->u.R911.list; expr != NULL; expr = expr->next)
+ {
+ if (okay)
+ ffeste_R911_item (expr->expr, expr->token);
+ ffelex_token_kill (expr->token);
+ }
+ if (okay)
+ ffeste_R911_finish ();
+ malloc_pool_kill (stmt->u.R911.pool);
+ break;
+
+ case FFESTD_stmtidR919_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R919 (stmt->u.R919.params);
+ malloc_pool_kill (stmt->u.R919.pool);
+ break;
+
+ case FFESTD_stmtidR920_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R920 (stmt->u.R920.params);
+ malloc_pool_kill (stmt->u.R920.pool);
+ break;
+
+ case FFESTD_stmtidR921_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R921 (stmt->u.R921.params);
+ malloc_pool_kill (stmt->u.R921.pool);
+ break;
+
+ case FFESTD_stmtidR923A_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R923A (stmt->u.R923A.params, stmt->u.R923A.by_file);
+ malloc_pool_kill (stmt->u.R923A.pool);
+ break;
+
+ case FFESTD_stmtidR923B_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R923B_start (stmt->u.R923B.params);
+ for (expr = stmt->u.R923B.list; expr != NULL; expr = expr->next)
+ {
+ if (okay)
+ ffeste_R923B_item (expr->expr);
+ }
+ if (okay)
+ ffeste_R923B_finish ();
+ malloc_pool_kill (stmt->u.R923B.pool);
+ break;
+
+ case FFESTD_stmtidR1001_:
+ if (okay)
+ ffeste_R1001 (&stmt->u.R1001.str);
+ ffests_kill (&stmt->u.R1001.str);
+ break;
+
+ case FFESTD_stmtidR1103_:
+ if (okay)
+ ffeste_R1103 ();
+ break;
+
+ case FFESTD_stmtidR1112_:
+ if (okay)
+ ffeste_R1112 ();
+ break;
+
+ case FFESTD_stmtidR1212_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R1212 (stmt->u.R1212.expr);
+ malloc_pool_kill (stmt->u.R1212.pool);
+ break;
+
+ case FFESTD_stmtidR1221_:
+ if (okay)
+ ffeste_R1221 ();
+ break;
+
+ case FFESTD_stmtidR1225_:
+ if (okay)
+ ffeste_R1225 ();
+ break;
+
+ case FFESTD_stmtidR1226_:
+ ffestd_subr_line_restore_ (stmt);
+ if (stmt->u.R1226.entry != NULL)
+ {
+ if (okay)
+ ffeste_R1226 (stmt->u.R1226.entry);
+ }
+ break;
+
+ case FFESTD_stmtidR1227_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_R1227 (stmt->u.R1227.block, stmt->u.R1227.expr);
+ malloc_pool_kill (stmt->u.R1227.pool);
+ break;
+
+#if FFESTR_VXT
+ case FFESTD_stmtidV018_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_V018_start (stmt->u.V018.params, stmt->u.V018.format);
+ for (expr = stmt->u.V018.list; expr != NULL; expr = expr->next)
+ {
+ if (okay)
+ ffeste_V018_item (expr->expr);
+ }
+ if (okay)
+ ffeste_V018_finish ();
+ malloc_pool_kill (stmt->u.V018.pool);
+ break;
+
+ case FFESTD_stmtidV019_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_V019_start (stmt->u.V019.params, stmt->u.V019.format);
+ for (expr = stmt->u.V019.list; expr != NULL; expr = expr->next)
+ {
+ if (okay)
+ ffeste_V019_item (expr->expr);
+ }
+ if (okay)
+ ffeste_V019_finish ();
+ malloc_pool_kill (stmt->u.V019.pool);
+ break;
+#endif
+
+ case FFESTD_stmtidV020_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_V020_start (stmt->u.V020.params, stmt->u.V020.format);
+ for (expr = stmt->u.V020.list; expr != NULL; expr = expr->next)
+ {
+ if (okay)
+ ffeste_V020_item (expr->expr);
+ }
+ if (okay)
+ ffeste_V020_finish ();
+ malloc_pool_kill (stmt->u.V020.pool);
+ break;
+
+#if FFESTR_VXT
+ case FFESTD_stmtidV021_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_V021 (stmt->u.V021.params);
+ malloc_pool_kill (stmt->u.V021.pool);
+ break;
+
+ case FFESTD_stmtidV023_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_V023_start (stmt->u.V023.params);
+ for (expr = stmt->u.V023.list; expr != NULL; expr = expr->next)
+ {
+ if (okay)
+ ffeste_V023_item (expr->expr);
+ }
+ if (okay)
+ ffeste_V023_finish ();
+ malloc_pool_kill (stmt->u.V023.pool);
+ break;
+
+ case FFESTD_stmtidV024_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_V024_start (stmt->u.V024.params);
+ for (expr = stmt->u.V024.list; expr != NULL; expr = expr->next)
+ {
+ if (okay)
+ ffeste_V024_item (expr->expr);
+ }
+ if (okay)
+ ffeste_V024_finish ();
+ malloc_pool_kill (stmt->u.V024.pool);
+ break;
+
+ case FFESTD_stmtidV025start_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_V025_start ();
+ break;
+
+ case FFESTD_stmtidV025item_:
+ if (okay)
+ ffeste_V025_item (stmt->u.V025item.u, stmt->u.V025item.m,
+ stmt->u.V025item.n, stmt->u.V025item.asv);
+ break;
+
+ case FFESTD_stmtidV025finish_:
+ if (okay)
+ ffeste_V025_finish ();
+ malloc_pool_kill (stmt->u.V025finish.pool);
+ break;
+
+ case FFESTD_stmtidV026_:
+ ffestd_subr_line_restore_ (stmt);
+ if (okay)
+ ffeste_V026 (stmt->u.V026.params);
+ malloc_pool_kill (stmt->u.V026.pool);
+ break;
+#endif
+
+ default:
+ assert ("bad stmt->id" == NULL);
+ break;
+ }
+ }
+}
+
+#endif
+/* ffestd_subr_copy_easy_ -- Copy I/O statement data structure
+
+ ffestd_subr_copy_easy_();
+
+ Copies all data except tokens in the I/O data structure into a new
+ structure that lasts as long as the output pool for the current
+ statement. Assumes that they are
+ overlaid with each other (union) in stp.h and the typing
+ and structure references assume (though not necessarily dangerous if
+ FALSE) that INQUIRE has the most file elements. */
+
+#if FFESTD_COPY_EASY_ && FFECOM_TWOPASS
+static ffestpInquireStmt *
+ffestd_subr_copy_easy_ (ffestpInquireIx max)
+{
+ ffestpInquireStmt *stmt;
+ ffestpInquireIx ix;
+
+ stmt = (ffestpInquireStmt *) malloc_new_kp (ffesta_output_pool,
+ "FFESTD easy", sizeof (ffestpFile) * max);
+
+ for (ix = 0; ix < max; ++ix)
+ {
+ if ((stmt->inquire_spec[ix].kw_or_val_present
+ = ffestp_file.inquire.inquire_spec[ix].kw_or_val_present)
+ && (stmt->inquire_spec[ix].value_present
+ = ffestp_file.inquire.inquire_spec[ix].value_present))
+ {
+ if ((stmt->inquire_spec[ix].value_is_label
+ = ffestp_file.inquire.inquire_spec[ix].value_is_label))
+ stmt->inquire_spec[ix].u.label
+ = ffestp_file.inquire.inquire_spec[ix].u.label;
+ else
+ stmt->inquire_spec[ix].u.expr
+ = ffestp_file.inquire.inquire_spec[ix].u.expr;
+ }
+ }
+
+ return stmt;
+}
+
+#endif
+/* ffestd_subr_labels_ -- Handle any undefined labels
+
+ ffestd_subr_labels_(FALSE);
+
+ For every undefined label, generate an error message and either define
+ label as a FORMAT() statement (for FORMAT labels) or as a STOP statement
+ (for all other labels). */
+
+static void
+ffestd_subr_labels_ (bool unexpected)
+{
+ ffelab l;
+ ffelabHandle h;
+ ffelabNumber undef;
+ ffesttFormatList f;
+
+ undef = ffelab_number () - ffestv_num_label_defines_;
+
+ for (h = ffelab_handle_first (); h != NULL; h = ffelab_handle_next (h))
+ {
+ l = ffelab_handle_target (h);
+ if (ffewhere_line_is_unknown (ffelab_definition_line (l)))
+ { /* Undefined label. */
+ assert (!unexpected);
+ assert (undef > 0);
+ undef--;
+ ffebad_start (FFEBAD_UNDEF_LABEL);
+ if (ffelab_type (l) == FFELAB_typeLOOPEND)
+ ffebad_here (0, ffelab_doref_line (l), ffelab_doref_column (l));
+ else if (ffelab_type (l) != FFELAB_typeANY)
+ ffebad_here (0, ffelab_firstref_line (l), ffelab_firstref_column (l));
+ else if (!ffewhere_line_is_unknown (ffelab_firstref_line (l)))
+ ffebad_here (0, ffelab_firstref_line (l), ffelab_firstref_column (l));
+ else if (!ffewhere_line_is_unknown (ffelab_doref_line (l)))
+ ffebad_here (0, ffelab_doref_line (l), ffelab_doref_column (l));
+ else
+ ffebad_here (0, ffelab_definition_line (l), ffelab_definition_column (l));
+ ffebad_finish ();
+
+ switch (ffelab_type (l))
+ {
+ case FFELAB_typeFORMAT:
+ ffelab_set_definition_line (l,
+ ffewhere_line_use (ffelab_firstref_line (l)));
+ ffelab_set_definition_column (l,
+ ffewhere_column_use (ffelab_firstref_column (l)));
+ ffestv_num_label_defines_++;
+ f = ffestt_formatlist_create (NULL, NULL);
+ ffestd_labeldef_format (l);
+ ffestd_R1001 (f);
+ ffestt_formatlist_kill (f);
+ break;
+
+ case FFELAB_typeASSIGNABLE:
+ ffelab_set_definition_line (l,
+ ffewhere_line_use (ffelab_firstref_line (l)));
+ ffelab_set_definition_column (l,
+ ffewhere_column_use (ffelab_firstref_column (l)));
+ ffestv_num_label_defines_++;
+ ffelab_set_type (l, FFELAB_typeNOTLOOP);
+ ffelab_set_blocknum (l, ffestw_blocknum (ffestw_stack_top ()));
+ ffestd_labeldef_notloop (l);
+ ffestd_R842 (NULL);
+ break;
+
+ case FFELAB_typeNOTLOOP:
+ ffelab_set_definition_line (l,
+ ffewhere_line_use (ffelab_firstref_line (l)));
+ ffelab_set_definition_column (l,
+ ffewhere_column_use (ffelab_firstref_column (l)));
+ ffestv_num_label_defines_++;
+ ffelab_set_blocknum (l, ffestw_blocknum (ffestw_stack_top ()));
+ ffestd_labeldef_notloop (l);
+ ffestd_R842 (NULL);
+ break;
+
+ default:
+ assert ("bad label type" == NULL);
+ /* Fall through. */
+ case FFELAB_typeUNKNOWN:
+ case FFELAB_typeANY:
+ break;
+ }
+ }
+ }
+ ffelab_handle_done (h);
+ assert (undef == 0);
+}
+
+/* ffestd_subr_f90_ -- Report error about lack of full F90 support
+
+ ffestd_subr_f90_(); */
+
+#if FFESTR_F90
+static void
+ffestd_subr_f90_ ()
+{
+ ffebad_start (FFEBAD_F90);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+}
+
+#endif
+/* ffestd_subr_vxt_ -- Report error about lack of full VXT support
+
+ ffestd_subr_vxt_(); */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffestd_subr_vxt_ ()
+{
+ ffebad_start (FFEBAD_VXT_UNSUPPORTED);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+}
+
+#endif
+/* ffestd_begin_uses -- Start a bunch of USE statements
+
+ ffestd_begin_uses();
+
+ Invoked before handling the first USE statement in a block of one or
+ more USE statements. _end_uses_(bool ok) is invoked before handling
+ the first statement after the block (there are no BEGIN USE and END USE
+ statements, but the semantics of USE statements effectively requires
+ handling them as a single block rather than one statement at a time). */
+
+void
+ffestd_begin_uses ()
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("; begin_uses\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_do -- End of statement following DO-term-stmt etc
+
+ ffestd_do(TRUE);
+
+ Also invoked by _labeldef_branch_finish_ (or, in cases
+ of errors, other _labeldef_ functions) when the label definition is
+ for a DO-target (LOOPEND) label, once per matching/outstanding DO
+ block on the stack. These cases invoke this function with ok==TRUE, so
+ only forced stack popping (via ffestd_eof_()) invokes it with ok==FALSE. */
+
+void
+ffestd_do (bool ok UNUSED)
+{
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_do (ffestw_stack_top ());
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidENDDOLOOP_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.enddoloop.block = ffestw_stack_top ();
+ }
+#endif
+
+ --ffestd_block_level_;
+ assert (ffestd_block_level_ >= 0);
+}
+
+/* ffestd_end_uses -- End a bunch of USE statements
+
+ ffestd_end_uses(TRUE);
+
+ ok==TRUE means simply not popping due to ffestd_eof_()
+ being called, because there is no formal END USES statement in Fortran. */
+
+#if FFESTR_F90
+void
+ffestd_end_uses (bool ok)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("; end_uses\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_end_R740 -- End a WHERE(-THEN)
+
+ ffestd_end_R740(TRUE); */
+
+void
+ffestd_end_R740 (bool ok)
+{
+ return; /* F90. */
+}
+
+#endif
+/* ffestd_end_R807 -- End of statement following logical IF
+
+ ffestd_end_R807(TRUE);
+
+ Applies ONLY to logical IF, not to IF-THEN. For example, does not
+ ffelex_token_kill the construct name for an IF-THEN block (the name
+ field is invalid for logical IF). ok==TRUE iff statement following
+ logical IF (substatement) is valid; else, statement is invalid or
+ stack forcibly popped due to ffestd_eof_(). */
+
+void
+ffestd_end_R807 (bool ok UNUSED)
+{
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_end_R807 ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidENDLOGIF_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ }
+#endif
+
+ --ffestd_block_level_;
+ assert (ffestd_block_level_ >= 0);
+}
+
+/* ffestd_exec_begin -- Executable statements can start coming in now
+
+ ffestd_exec_begin(); */
+
+void
+ffestd_exec_begin ()
+{
+ ffecom_exec_transition ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("{ begin_exec\n", dmpout);
+#endif
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ if (ffestd_2pass_entrypoints_ != 0)
+ { /* Process pending ENTRY statements now that
+ info filled in. */
+ ffestdStmt_ stmt;
+ int ents = ffestd_2pass_entrypoints_;
+
+ stmt = ffestd_stmt_list_.first;
+ do
+ {
+ while (stmt->id != FFESTD_stmtidR1226_)
+ stmt = stmt->next;
+
+ if (!ffecom_2pass_advise_entrypoint (stmt->u.R1226.entry))
+ {
+ stmt->u.R1226.entry = NULL;
+ --ffestd_2pass_entrypoints_;
+ }
+ stmt = stmt->next;
+ }
+ while (--ents != 0);
+ }
+#endif
+}
+
+/* ffestd_exec_end -- Executable statements can no longer come in now
+
+ ffestd_exec_end(); */
+
+void
+ffestd_exec_end ()
+{
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ int old_lineno = lineno;
+ char *old_input_filename = input_filename;
+#endif
+
+ ffecom_end_transition ();
+
+#if FFECOM_TWOPASS
+ ffestd_stmt_pass_ ();
+#endif
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("} end_exec\n", dmpout);
+ fputs ("> end_unit\n", dmpout);
+#endif
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffecom_finish_progunit ();
+
+ if (ffestd_2pass_entrypoints_ != 0)
+ {
+ int ents = ffestd_2pass_entrypoints_;
+ ffestdStmt_ stmt = ffestd_stmt_list_.first;
+
+ do
+ {
+ while (stmt->id != FFESTD_stmtidR1226_)
+ stmt = stmt->next;
+
+ if (stmt->u.R1226.entry != NULL)
+ {
+ ffestd_subr_line_restore_ (stmt);
+ ffecom_2pass_do_entrypoint (stmt->u.R1226.entry);
+ }
+ stmt = stmt->next;
+ }
+ while (--ents != 0);
+ }
+
+ ffestd_stmt_list_.first = NULL;
+ ffestd_stmt_list_.last = NULL;
+ ffestd_2pass_entrypoints_ = 0;
+
+ lineno = old_lineno;
+ input_filename = old_input_filename;
+#endif
+}
+
+/* ffestd_init_3 -- Initialize for any program unit
+
+ ffestd_init_3(); */
+
+void
+ffestd_init_3 ()
+{
+#if FFECOM_TWOPASS
+ ffestd_stmt_list_.first = (ffestdStmt_) &ffestd_stmt_list_.first;
+ ffestd_stmt_list_.last = (ffestdStmt_) &ffestd_stmt_list_.first;
+#endif
+}
+
+/* Generate "code" for "any" label def. */
+
+void
+ffestd_labeldef_any (ffelab label UNUSED)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "; any_label_def %lu\n", ffelab_value (label));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_labeldef_branch -- Generate "code" for branch label def
+
+ ffestd_labeldef_branch(label); */
+
+void
+ffestd_labeldef_branch (ffelab label)
+{
+#if FFECOM_ONEPASS
+ ffeste_labeldef_branch (label);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidEXECLABEL_);
+ ffestd_stmt_append_ (stmt);
+ stmt->u.execlabel.label = label;
+ }
+#endif
+
+ ffestd_is_reachable_ = TRUE;
+}
+
+/* ffestd_labeldef_format -- Generate "code" for FORMAT label def
+
+ ffestd_labeldef_format(label); */
+
+void
+ffestd_labeldef_format (ffelab label)
+{
+ ffestd_label_formatdef_ = label;
+
+#if FFECOM_ONEPASS
+ ffeste_labeldef_format (label);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidFORMATLABEL_);
+ ffestd_stmt_append_ (stmt);
+ stmt->u.formatlabel.label = label;
+ }
+#endif
+}
+
+/* ffestd_labeldef_useless -- Generate "code" for useless label def
+
+ ffestd_labeldef_useless(label); */
+
+void
+ffestd_labeldef_useless (ffelab label UNUSED)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "; useless_label_def %lu\n", ffelab_value (label));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R423A -- PRIVATE statement (in R422 derived-type statement)
+
+ ffestd_R423A(); */
+
+#if FFESTR_F90
+void
+ffestd_R423A ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* PRIVATE_derived_type\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R423B -- SEQUENCE statement (in R422 derived-type-stmt)
+
+ ffestd_R423B(); */
+
+void
+ffestd_R423B ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* SEQUENCE_derived_type\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R424 -- derived-TYPE-def statement
+
+ ffestd_R424(access_token,access_kw,name_token);
+
+ Handle a derived-type definition. */
+
+void
+ffestd_R424 (ffelexToken access, ffestrOther access_kw, ffelexToken name)
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ char *a;
+
+ if (access == NULL)
+ fprintf (dmpout, "* TYPE %s\n", ffelex_token_text (name));
+ else
+ {
+ switch (access_kw)
+ {
+ case FFESTR_otherPUBLIC:
+ a = "PUBLIC";
+ break;
+
+ case FFESTR_otherPRIVATE:
+ a = "PRIVATE";
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ fprintf (dmpout, "* TYPE,%s: %s\n", a, ffelex_token_text (name));
+ }
+#endif
+}
+
+/* ffestd_R425 -- End a TYPE
+
+ ffestd_R425(TRUE); */
+
+void
+ffestd_R425 (bool ok)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "* END_TYPE %s\n", ffelex_token_text (ffestw_name (ffestw_stack_top ())));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R519_start -- INTENT statement list begin
+
+ ffestd_R519_start();
+
+ Verify that INTENT is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R519_start (ffestrOther intent_kw)
+{
+ ffestd_check_start_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ char *a;
+
+ switch (intent_kw)
+ {
+ case FFESTR_otherIN:
+ a = "IN";
+ break;
+
+ case FFESTR_otherOUT:
+ a = "OUT";
+ break;
+
+ case FFESTR_otherINOUT:
+ a = "INOUT";
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ fprintf (dmpout, "* INTENT (%s) ", a);
+#endif
+}
+
+/* ffestd_R519_item -- INTENT statement for name
+
+ ffestd_R519_item(name_token);
+
+ Make sure name_token identifies a valid object to be INTENTed. */
+
+void
+ffestd_R519_item (ffelexToken name)
+{
+ ffestd_check_item_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fprintf (dmpout, "%s,", ffelex_token_text (name));
+#endif
+}
+
+/* ffestd_R519_finish -- INTENT statement list complete
+
+ ffestd_R519_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R519_finish ()
+{
+ ffestd_check_finish_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputc ('\n', dmpout);
+#endif
+}
+
+/* ffestd_R520_start -- OPTIONAL statement list begin
+
+ ffestd_R520_start();
+
+ Verify that OPTIONAL is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R520_start ()
+{
+ ffestd_check_start_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("* OPTIONAL ", dmpout);
+#endif
+}
+
+/* ffestd_R520_item -- OPTIONAL statement for name
+
+ ffestd_R520_item(name_token);
+
+ Make sure name_token identifies a valid object to be OPTIONALed. */
+
+void
+ffestd_R520_item (ffelexToken name)
+{
+ ffestd_check_item_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fprintf (dmpout, "%s,", ffelex_token_text (name));
+#endif
+}
+
+/* ffestd_R520_finish -- OPTIONAL statement list complete
+
+ ffestd_R520_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R520_finish ()
+{
+ ffestd_check_finish_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputc ('\n', dmpout);
+#endif
+}
+
+/* ffestd_R521A -- PUBLIC statement
+
+ ffestd_R521A();
+
+ Verify that PUBLIC is valid here. */
+
+void
+ffestd_R521A ()
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("* PUBLIC\n", dmpout);
+#endif
+}
+
+/* ffestd_R521Astart -- PUBLIC statement list begin
+
+ ffestd_R521Astart();
+
+ Verify that PUBLIC is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R521Astart ()
+{
+ ffestd_check_start_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("* PUBLIC ", dmpout);
+#endif
+}
+
+/* ffestd_R521Aitem -- PUBLIC statement for name
+
+ ffestd_R521Aitem(name_token);
+
+ Make sure name_token identifies a valid object to be PUBLICed. */
+
+void
+ffestd_R521Aitem (ffelexToken name)
+{
+ ffestd_check_item_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fprintf (dmpout, "%s,", ffelex_token_text (name));
+#endif
+}
+
+/* ffestd_R521Afinish -- PUBLIC statement list complete
+
+ ffestd_R521Afinish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R521Afinish ()
+{
+ ffestd_check_finish_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputc ('\n', dmpout);
+#endif
+}
+
+/* ffestd_R521B -- PRIVATE statement
+
+ ffestd_R521B();
+
+ Verify that PRIVATE is valid here (outside a derived-type statement). */
+
+void
+ffestd_R521B ()
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("* PRIVATE_outside_of_R422_derived_type_def\n", dmpout);
+#endif
+}
+
+/* ffestd_R521Bstart -- PRIVATE statement list begin
+
+ ffestd_R521Bstart();
+
+ Verify that PRIVATE is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R521Bstart ()
+{
+ ffestd_check_start_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("* PRIVATE ", dmpout);
+#endif
+}
+
+/* ffestd_R521Bitem -- PRIVATE statement for name
+
+ ffestd_R521Bitem(name_token);
+
+ Make sure name_token identifies a valid object to be PRIVATEed. */
+
+void
+ffestd_R521Bitem (ffelexToken name)
+{
+ ffestd_check_item_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fprintf (dmpout, "%s,", ffelex_token_text (name));
+#endif
+}
+
+/* ffestd_R521Bfinish -- PRIVATE statement list complete
+
+ ffestd_R521Bfinish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R521Bfinish ()
+{
+ ffestd_check_finish_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputc ('\n', dmpout);
+#endif
+}
+
+#endif
+/* ffestd_R522 -- SAVE statement with no list
+
+ ffestd_R522();
+
+ Verify that SAVE is valid here, and flag everything as SAVEd. */
+
+void
+ffestd_R522 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* SAVE_all\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R522start -- SAVE statement list begin
+
+ ffestd_R522start();
+
+ Verify that SAVE is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R522start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* SAVE ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R522item_object -- SAVE statement for object-name
+
+ ffestd_R522item_object(name_token);
+
+ Make sure name_token identifies a valid object to be SAVEd. */
+
+void
+ffestd_R522item_object (ffelexToken name UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "%s,", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R522item_cblock -- SAVE statement for common-block-name
+
+ ffestd_R522item_cblock(name_token);
+
+ Make sure name_token identifies a valid common block to be SAVEd. */
+
+void
+ffestd_R522item_cblock (ffelexToken name UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "/%s/,", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R522finish -- SAVE statement list complete
+
+ ffestd_R522finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R522finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R524_start -- DIMENSION statement list begin
+
+ ffestd_R524_start(bool virtual);
+
+ Verify that DIMENSION is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R524_start (bool virtual UNUSED)
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if (virtual)
+ fputs ("* VIRTUAL ", dmpout); /* V028. */
+ else
+ fputs ("* DIMENSION ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R524_item -- DIMENSION statement for object-name
+
+ ffestd_R524_item(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be DIMENSIONd. */
+
+void
+ffestd_R524_item (ffelexToken name UNUSED, ffesttDimList dims UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs (ffelex_token_text (name), dmpout);
+ fputc ('(', dmpout);
+ ffestt_dimlist_dump (dims);
+ fputs ("),", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R524_finish -- DIMENSION statement list complete
+
+ ffestd_R524_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R524_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R525_start -- ALLOCATABLE statement list begin
+
+ ffestd_R525_start();
+
+ Verify that ALLOCATABLE is valid here, and begin accepting items in the
+ list. */
+
+#if FFESTR_F90
+void
+ffestd_R525_start ()
+{
+ ffestd_check_start_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("* ALLOCATABLE ", dmpout);
+#endif
+}
+
+/* ffestd_R525_item -- ALLOCATABLE statement for object-name
+
+ ffestd_R525_item(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be ALLOCATABLEd. */
+
+void
+ffestd_R525_item (ffelexToken name, ffesttDimList dims)
+{
+ ffestd_check_item_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputs (ffelex_token_text (name), dmpout);
+ if (dims != NULL)
+ {
+ fputc ('(', dmpout);
+ ffestt_dimlist_dump (dims);
+ fputc (')', dmpout);
+ }
+ fputc (',', dmpout);
+#endif
+}
+
+/* ffestd_R525_finish -- ALLOCATABLE statement list complete
+
+ ffestd_R525_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R525_finish ()
+{
+ ffestd_check_finish_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputc ('\n', dmpout);
+#endif
+}
+
+/* ffestd_R526_start -- POINTER statement list begin
+
+ ffestd_R526_start();
+
+ Verify that POINTER is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_R526_start ()
+{
+ ffestd_check_start_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("* POINTER ", dmpout);
+#endif
+}
+
+/* ffestd_R526_item -- POINTER statement for object-name
+
+ ffestd_R526_item(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be POINTERd. */
+
+void
+ffestd_R526_item (ffelexToken name, ffesttDimList dims)
+{
+ ffestd_check_item_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputs (ffelex_token_text (name), dmpout);
+ if (dims != NULL)
+ {
+ fputc ('(', dmpout);
+ ffestt_dimlist_dump (dims);
+ fputc (')', dmpout);
+ }
+ fputc (',', dmpout);
+#endif
+}
+
+/* ffestd_R526_finish -- POINTER statement list complete
+
+ ffestd_R526_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R526_finish ()
+{
+ ffestd_check_finish_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputc ('\n', dmpout);
+#endif
+}
+
+/* ffestd_R527_start -- TARGET statement list begin
+
+ ffestd_R527_start();
+
+ Verify that TARGET is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_R527_start ()
+{
+ ffestd_check_start_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("* TARGET ", dmpout);
+#endif
+}
+
+/* ffestd_R527_item -- TARGET statement for object-name
+
+ ffestd_R527_item(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be TARGETd. */
+
+void
+ffestd_R527_item (ffelexToken name, ffesttDimList dims)
+{
+ ffestd_check_item_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputs (ffelex_token_text (name), dmpout);
+ if (dims != NULL)
+ {
+ fputc ('(', dmpout);
+ ffestt_dimlist_dump (dims);
+ fputc (')', dmpout);
+ }
+ fputc (',', dmpout);
+#endif
+}
+
+/* ffestd_R527_finish -- TARGET statement list complete
+
+ ffestd_R527_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R527_finish ()
+{
+ ffestd_check_finish_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputc ('\n', dmpout);
+#endif
+}
+
+#endif
+/* ffestd_R537_start -- PARAMETER statement list begin
+
+ ffestd_R537_start();
+
+ Verify that PARAMETER is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R537_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* PARAMETER (", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R537_item -- PARAMETER statement assignment
+
+ ffestd_R537_item(dest,dest_token,source,source_token);
+
+ Make sure the source is a valid source for the destination; make the
+ assignment. */
+
+void
+ffestd_R537_item (ffebld dest UNUSED, ffebld source UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (dest);
+ fputc ('=', dmpout);
+ ffebld_dump (source);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R537_finish -- PARAMETER statement list complete
+
+ ffestd_R537_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R537_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R539 -- IMPLICIT NONE statement
+
+ ffestd_R539();
+
+ Verify that the IMPLICIT NONE statement is ok here and implement. */
+
+void
+ffestd_R539 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* IMPLICIT_NONE\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R539start -- IMPLICIT statement
+
+ ffestd_R539start();
+
+ Verify that the IMPLICIT statement is ok here and implement. */
+
+void
+ffestd_R539start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* IMPLICIT ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R539item -- IMPLICIT statement specification (R540)
+
+ ffestd_R539item(...);
+
+ Verify that the type and letter list are all ok and implement. */
+
+void
+ffestd_R539item (ffestpType type UNUSED, ffebld kind UNUSED,
+ ffelexToken kindt UNUSED, ffebld len UNUSED,
+ ffelexToken lent UNUSED, ffesttImpList letters UNUSED)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ char *a;
+#endif
+
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ switch (type)
+ {
+ case FFESTP_typeINTEGER:
+ a = "INTEGER";
+ break;
+
+ case FFESTP_typeBYTE:
+ a = "BYTE";
+ break;
+
+ case FFESTP_typeWORD:
+ a = "WORD";
+ break;
+
+ case FFESTP_typeREAL:
+ a = "REAL";
+ break;
+
+ case FFESTP_typeCOMPLEX:
+ a = "COMPLEX";
+ break;
+
+ case FFESTP_typeLOGICAL:
+ a = "LOGICAL";
+ break;
+
+ case FFESTP_typeCHARACTER:
+ a = "CHARACTER";
+ break;
+
+ case FFESTP_typeDBLPRCSN:
+ a = "DOUBLE PRECISION";
+ break;
+
+ case FFESTP_typeDBLCMPLX:
+ a = "DOUBLE COMPLEX";
+ break;
+
+#if FFESTR_F90
+ case FFESTP_typeTYPE:
+ a = "TYPE";
+ break;
+#endif
+
+ default:
+ assert (FALSE);
+ a = "?";
+ break;
+ }
+ fprintf (dmpout, "%s(", a);
+ if (kindt != NULL)
+ {
+ fputs ("kind=", dmpout);
+ if (kind == NULL)
+ fputs (ffelex_token_text (kindt), dmpout);
+ else
+ ffebld_dump (kind);
+ if (lent != NULL)
+ fputc (',', dmpout);
+ }
+ if (lent != NULL)
+ {
+ fputs ("len=", dmpout);
+ if (len == NULL)
+ fputs (ffelex_token_text (lent), dmpout);
+ else
+ ffebld_dump (len);
+ }
+ fputs (")(", dmpout);
+ ffestt_implist_dump (letters);
+ fputs ("),", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R539finish -- IMPLICIT statement
+
+ ffestd_R539finish();
+
+ Finish up any local activities. */
+
+void
+ffestd_R539finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R542_start -- NAMELIST statement list begin
+
+ ffestd_R542_start();
+
+ Verify that NAMELIST is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R542_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* NAMELIST ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R542_item_nlist -- NAMELIST statement for group-name
+
+ ffestd_R542_item_nlist(groupname_token);
+
+ Make sure name_token identifies a valid object to be NAMELISTd. */
+
+void
+ffestd_R542_item_nlist (ffelexToken name UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "/%s/", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R542_item_nitem -- NAMELIST statement for variable-name
+
+ ffestd_R542_item_nitem(name_token);
+
+ Make sure name_token identifies a valid object to be NAMELISTd. */
+
+void
+ffestd_R542_item_nitem (ffelexToken name UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "%s,", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R542_finish -- NAMELIST statement list complete
+
+ ffestd_R542_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R542_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R544_start -- EQUIVALENCE statement list begin
+
+ ffestd_R544_start();
+
+ Verify that EQUIVALENCE is valid here, and begin accepting items in the
+ list. */
+
+#if 0
+void
+ffestd_R544_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* EQUIVALENCE (", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+#endif
+/* ffestd_R544_item -- EQUIVALENCE statement assignment
+
+ ffestd_R544_item(exprlist);
+
+ Make sure the equivalence is valid, then implement it. */
+
+#if 0
+void
+ffestd_R544_item (ffesttExprList exprlist)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffestt_exprlist_dump (exprlist);
+ fputs ("),", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+#endif
+/* ffestd_R544_finish -- EQUIVALENCE statement list complete
+
+ ffestd_R544_finish();
+
+ Just wrap up any local activities. */
+
+#if 0
+void
+ffestd_R544_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+#endif
+/* ffestd_R547_start -- COMMON statement list begin
+
+ ffestd_R547_start();
+
+ Verify that COMMON is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R547_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* COMMON ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R547_item_object -- COMMON statement for object-name
+
+ ffestd_R547_item_object(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be COMMONd. */
+
+void
+ffestd_R547_item_object (ffelexToken name UNUSED,
+ ffesttDimList dims UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs (ffelex_token_text (name), dmpout);
+ if (dims != NULL)
+ {
+ fputc ('(', dmpout);
+ ffestt_dimlist_dump (dims);
+ fputc (')', dmpout);
+ }
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R547_item_cblock -- COMMON statement for common-block-name
+
+ ffestd_R547_item_cblock(name_token);
+
+ Make sure name_token identifies a valid common block to be COMMONd. */
+
+void
+ffestd_R547_item_cblock (ffelexToken name UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if (name == NULL)
+ fputs ("//,", dmpout);
+ else
+ fprintf (dmpout, "/%s/,", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R547_finish -- COMMON statement list complete
+
+ ffestd_R547_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R547_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R620 -- ALLOCATE statement
+
+ ffestd_R620(exprlist,stat,stat_token);
+
+ Make sure the expression list is valid, then implement it. */
+
+#if FFESTR_F90
+void
+ffestd_R620 (ffesttExprList exprlist, ffebld stat)
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("+ ALLOCATE (", dmpout);
+ ffestt_exprlist_dump (exprlist);
+ if (stat != NULL)
+ {
+ fputs (",stat=", dmpout);
+ ffebld_dump (stat);
+ }
+ fputs (")\n", dmpout);
+#endif
+}
+
+/* ffestd_R624 -- NULLIFY statement
+
+ ffestd_R624(pointer_name_list);
+
+ Make sure pointer_name_list identifies valid pointers for a NULLIFY. */
+
+void
+ffestd_R624 (ffesttExprList pointers)
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("+ NULLIFY (", dmpout);
+ assert (pointers != NULL);
+ ffestt_exprlist_dump (pointers);
+ fputs (")\n", dmpout);
+#endif
+}
+
+/* ffestd_R625 -- DEALLOCATE statement
+
+ ffestd_R625(exprlist,stat,stat_token);
+
+ Make sure the equivalence is valid, then implement it. */
+
+void
+ffestd_R625 (ffesttExprList exprlist, ffebld stat)
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("+ DEALLOCATE (", dmpout);
+ ffestt_exprlist_dump (exprlist);
+ if (stat != NULL)
+ {
+ fputs (",stat=", dmpout);
+ ffebld_dump (stat);
+ }
+ fputs (")\n", dmpout);
+#endif
+}
+
+#endif
+/* ffestd_R737A -- Assignment statement outside of WHERE
+
+ ffestd_R737A(dest_expr,source_expr); */
+
+void
+ffestd_R737A (ffebld dest, ffebld source)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R737A (dest, source);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR737A_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R737A.pool = ffesta_output_pool;
+ stmt->u.R737A.dest = dest;
+ stmt->u.R737A.source = source;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R737B -- Assignment statement inside of WHERE
+
+ ffestd_R737B(dest_expr,source_expr); */
+
+#if FFESTR_F90
+void
+ffestd_R737B (ffebld dest, ffebld source)
+{
+ ffestd_check_simple_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputs ("+ let_inside_where ", dmpout);
+ ffebld_dump (dest);
+ fputs ("=", dmpout);
+ ffebld_dump (source);
+ fputc ('\n', dmpout);
+#endif
+}
+
+/* ffestd_R738 -- Pointer assignment statement
+
+ ffestd_R738(dest_expr,source_expr,source_token);
+
+ Make sure the assignment is valid. */
+
+void
+ffestd_R738 (ffebld dest, ffebld source)
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("+ let_pointer ", dmpout);
+ ffebld_dump (dest);
+ fputs ("=>", dmpout);
+ ffebld_dump (source);
+ fputc ('\n', dmpout);
+#endif
+}
+
+/* ffestd_R740 -- WHERE statement
+
+ ffestd_R740(expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestd_R740 (ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("+ WHERE (", dmpout);
+ ffebld_dump (expr);
+ fputs (")\n", dmpout);
+
+ ++ffestd_block_level_;
+ assert (ffestd_block_level_ > 0);
+#endif
+}
+
+/* ffestd_R742 -- WHERE-construct statement
+
+ ffestd_R742(expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestd_R742 (ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("+ WHERE_construct (", dmpout);
+ ffebld_dump (expr);
+ fputs (")\n", dmpout);
+
+ ++ffestd_block_level_;
+ assert (ffestd_block_level_ > 0);
+#endif
+}
+
+/* ffestd_R744 -- ELSE WHERE statement
+
+ ffestd_R744();
+
+ Make sure ffestd_kind_ identifies a WHERE block.
+ Implement the ELSE of the current WHERE block. */
+
+void
+ffestd_R744 ()
+{
+ ffestd_check_simple_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputs ("+ ELSE_WHERE\n", dmpout);
+#endif
+}
+
+/* ffestd_R745 -- Implicit END WHERE statement
+
+ ffestd_R745(TRUE);
+
+ Implement the end of the current WHERE "block". ok==TRUE iff statement
+ following WHERE (substatement) is valid; else, statement is invalid
+ or stack forcibly popped due to ffestd_eof_(). */
+
+void
+ffestd_R745 (bool ok)
+{
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputs ("+ END_WHERE\n", dmpout); /* Also see ffestd_R745. */
+
+ --ffestd_block_level_;
+ assert (ffestd_block_level_ >= 0);
+#endif
+}
+
+#endif
+/* ffestd_R803 -- Block IF (IF-THEN) statement
+
+ ffestd_R803(construct_name,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestd_R803 (ffelexToken construct_name UNUSED, ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R803 (expr); /* Don't bother with name. */
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR803_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R803.pool = ffesta_output_pool;
+ stmt->u.R803.expr = expr;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+ ++ffestd_block_level_;
+ assert (ffestd_block_level_ > 0);
+}
+
+/* ffestd_R804 -- ELSE IF statement
+
+ ffestd_R804(expr,expr_token,name_token);
+
+ Make sure ffestd_kind_ identifies an IF block. If not
+ NULL, make sure name_token gives the correct name. Implement the else
+ of the IF block. */
+
+void
+ffestd_R804 (ffebld expr, ffelexToken name UNUSED)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R804 (expr); /* Don't bother with name. */
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR804_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R804.pool = ffesta_output_pool;
+ stmt->u.R804.expr = expr;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R805 -- ELSE statement
+
+ ffestd_R805(name_token);
+
+ Make sure ffestd_kind_ identifies an IF block. If not
+ NULL, make sure name_token gives the correct name. Implement the ELSE
+ of the IF block. */
+
+void
+ffestd_R805 (ffelexToken name UNUSED)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R805 (); /* Don't bother with name. */
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR805_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ }
+#endif
+}
+
+/* ffestd_R806 -- End an IF-THEN
+
+ ffestd_R806(TRUE); */
+
+void
+ffestd_R806 (bool ok UNUSED)
+{
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R806 ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR806_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ }
+#endif
+
+ --ffestd_block_level_;
+ assert (ffestd_block_level_ >= 0);
+}
+
+/* ffestd_R807 -- Logical IF statement
+
+ ffestd_R807(expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestd_R807 (ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R807 (expr);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR807_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R807.pool = ffesta_output_pool;
+ stmt->u.R807.expr = expr;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+ ++ffestd_block_level_;
+ assert (ffestd_block_level_ > 0);
+}
+
+/* ffestd_R809 -- SELECT CASE statement
+
+ ffestd_R809(construct_name,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestd_R809 (ffelexToken construct_name UNUSED, ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R809 (ffestw_stack_top (), expr);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR809_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R809.pool = ffesta_output_pool;
+ stmt->u.R809.block = ffestw_use (ffestw_stack_top ());
+ stmt->u.R809.expr = expr;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ malloc_pool_use (ffestw_select (ffestw_stack_top ())->pool);
+ }
+#endif
+
+ ++ffestd_block_level_;
+ assert (ffestd_block_level_ > 0);
+}
+
+/* ffestd_R810 -- CASE statement
+
+ ffestd_R810(case_value_range_list,name);
+
+ If casenum is 0, it's CASE DEFAULT. Else it's the case ranges at
+ the start of the first_stmt list in the select object at the top of
+ the stack that match casenum. */
+
+void
+ffestd_R810 (unsigned long casenum)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R810 (ffestw_stack_top (), casenum);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR810_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R810.pool = ffesta_output_pool;
+ stmt->u.R810.block = ffestw_stack_top ();
+ stmt->u.R810.casenum = casenum;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R811 -- End a SELECT
+
+ ffestd_R811(TRUE); */
+
+void
+ffestd_R811 (bool ok UNUSED)
+{
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R811 (ffestw_stack_top ());
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR811_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R811.block = ffestw_stack_top ();
+ }
+#endif
+
+ --ffestd_block_level_;
+ assert (ffestd_block_level_ >= 0);
+}
+
+/* ffestd_R819A -- Iterative DO statement
+
+ ffestd_R819A(construct_name,label_token,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestd_R819A (ffelexToken construct_name UNUSED, ffelab label,
+ ffebld var, ffebld start, ffelexToken start_token,
+ ffebld end, ffelexToken end_token,
+ ffebld incr, ffelexToken incr_token)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R819A (ffestw_stack_top (), label, var, start, end, incr,
+ incr_token);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR819A_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R819A.pool = ffesta_output_pool;
+ stmt->u.R819A.block = ffestw_use (ffestw_stack_top ());
+ stmt->u.R819A.label = label;
+ stmt->u.R819A.var = var;
+ stmt->u.R819A.start = start;
+ stmt->u.R819A.start_token = ffelex_token_use (start_token);
+ stmt->u.R819A.end = end;
+ stmt->u.R819A.end_token = ffelex_token_use (end_token);
+ stmt->u.R819A.incr = incr;
+ stmt->u.R819A.incr_token = (incr_token == NULL) ? NULL
+ : ffelex_token_use (incr_token);
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+ ++ffestd_block_level_;
+ assert (ffestd_block_level_ > 0);
+}
+
+/* ffestd_R819B -- DO WHILE statement
+
+ ffestd_R819B(construct_name,label_token,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestd_R819B (ffelexToken construct_name UNUSED, ffelab label,
+ ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R819B (ffestw_stack_top (), label, expr);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR819B_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R819B.pool = ffesta_output_pool;
+ stmt->u.R819B.block = ffestw_use (ffestw_stack_top ());
+ stmt->u.R819B.label = label;
+ stmt->u.R819B.expr = expr;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+ ++ffestd_block_level_;
+ assert (ffestd_block_level_ > 0);
+}
+
+/* ffestd_R825 -- END DO statement
+
+ ffestd_R825(name_token);
+
+ Make sure ffestd_kind_ identifies a DO block. If not
+ NULL, make sure name_token gives the correct name. Do whatever
+ is specific to seeing END DO with a DO-target label definition on it,
+ where the END DO is really treated as a CONTINUE (i.e. generate th
+ same code you would for CONTINUE). ffestd_do handles the actual
+ generation of end-loop code. */
+
+void
+ffestd_R825 (ffelexToken name UNUSED)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R825 ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR825_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ }
+#endif
+}
+
+/* ffestd_R834 -- CYCLE statement
+
+ ffestd_R834(name_token);
+
+ Handle a CYCLE within a loop. */
+
+void
+ffestd_R834 (ffestw block)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R834 (block);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR834_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R834.block = block;
+ }
+#endif
+}
+
+/* ffestd_R835 -- EXIT statement
+
+ ffestd_R835(name_token);
+
+ Handle a EXIT within a loop. */
+
+void
+ffestd_R835 (ffestw block)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R835 (block);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR835_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R835.block = block;
+ }
+#endif
+}
+
+/* ffestd_R836 -- GOTO statement
+
+ ffestd_R836(label);
+
+ Make sure label_token identifies a valid label for a GOTO. Update
+ that label's info to indicate it is the target of a GOTO. */
+
+void
+ffestd_R836 (ffelab label)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R836 (label);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR836_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R836.label = label;
+ }
+#endif
+
+ if (ffestd_block_level_ == 0)
+ ffestd_is_reachable_ = FALSE;
+}
+
+/* ffestd_R837 -- Computed GOTO statement
+
+ ffestd_R837(labels,expr);
+
+ Make sure label_list identifies valid labels for a GOTO. Update
+ each label's info to indicate it is the target of a GOTO. */
+
+void
+ffestd_R837 (ffelab *labels, int count, ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R837 (labels, count, expr);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR837_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R837.pool = ffesta_output_pool;
+ stmt->u.R837.labels = labels;
+ stmt->u.R837.count = count;
+ stmt->u.R837.expr = expr;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R838 -- ASSIGN statement
+
+ ffestd_R838(label_token,target_variable,target_token);
+
+ Make sure label_token identifies a valid label for an assignment. Update
+ that label's info to indicate it is the source of an assignment. Update
+ target_variable's info to indicate it is the target the assignment of that
+ label. */
+
+void
+ffestd_R838 (ffelab label, ffebld target)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R838 (label, target);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR838_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R838.pool = ffesta_output_pool;
+ stmt->u.R838.label = label;
+ stmt->u.R838.target = target;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R839 -- Assigned GOTO statement
+
+ ffestd_R839(target,labels);
+
+ Make sure label_list identifies valid labels for a GOTO. Update
+ each label's info to indicate it is the target of a GOTO. */
+
+void
+ffestd_R839 (ffebld target, ffelab *labels UNUSED, int count UNUSED)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R839 (target);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR839_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R839.pool = ffesta_output_pool;
+ stmt->u.R839.target = target;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+ if (ffestd_block_level_ == 0)
+ ffestd_is_reachable_ = FALSE;
+}
+
+/* ffestd_R840 -- Arithmetic IF statement
+
+ ffestd_R840(expr,expr_token,neg,zero,pos);
+
+ Make sure the labels are valid; implement. */
+
+void
+ffestd_R840 (ffebld expr, ffelab neg, ffelab zero, ffelab pos)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R840 (expr, neg, zero, pos);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR840_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R840.pool = ffesta_output_pool;
+ stmt->u.R840.expr = expr;
+ stmt->u.R840.neg = neg;
+ stmt->u.R840.zero = zero;
+ stmt->u.R840.pos = pos;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+ if (ffestd_block_level_ == 0)
+ ffestd_is_reachable_ = FALSE;
+}
+
+/* ffestd_R841 -- CONTINUE statement
+
+ ffestd_R841(); */
+
+void
+ffestd_R841 (bool in_where UNUSED)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R841 ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR841_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ }
+#endif
+}
+
+/* ffestd_R842 -- STOP statement
+
+ ffestd_R842(expr); */
+
+void
+ffestd_R842 (ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R842 (expr);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR842_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ if (ffesta_outpooldisp () == FFESTA_pooldispPRESERVE)
+ {
+ /* This is a "spurious" (automatically-generated) STOP
+ that follows a previous STOP or other statement.
+ Make sure we don't have an expression in the pool,
+ and then mark that the pool has already been killed. */
+ assert (expr == NULL);
+ stmt->u.R842.pool = NULL;
+ stmt->u.R842.expr = NULL;
+ }
+ else
+ {
+ stmt->u.R842.pool = ffesta_output_pool;
+ stmt->u.R842.expr = expr;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+ }
+#endif
+
+ if (ffestd_block_level_ == 0)
+ ffestd_is_reachable_ = FALSE;
+}
+
+/* ffestd_R843 -- PAUSE statement
+
+ ffestd_R843(expr,expr_token);
+
+ Make sure statement is valid here; implement. expr and expr_token are
+ both NULL if there was no expression. */
+
+void
+ffestd_R843 (ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R843 (expr);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR843_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R843.pool = ffesta_output_pool;
+ stmt->u.R843.expr = expr;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R904 -- OPEN statement
+
+ ffestd_R904();
+
+ Make sure an OPEN is valid in the current context, and implement it. */
+
+void
+ffestd_R904 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define specified(something) \
+ (ffestp_file.open.open_spec[something].kw_or_val_present)
+
+ /* Warn if there are any thing we don't handle via f2c libraries. */
+
+ if (specified (FFESTP_openixACTION)
+ || specified (FFESTP_openixASSOCIATEVARIABLE)
+ || specified (FFESTP_openixBLOCKSIZE)
+ || specified (FFESTP_openixBUFFERCOUNT)
+ || specified (FFESTP_openixCARRIAGECONTROL)
+ || specified (FFESTP_openixDEFAULTFILE)
+ || specified (FFESTP_openixDELIM)
+ || specified (FFESTP_openixDISPOSE)
+ || specified (FFESTP_openixEXTENDSIZE)
+ || specified (FFESTP_openixINITIALSIZE)
+ || specified (FFESTP_openixKEY)
+ || specified (FFESTP_openixMAXREC)
+ || specified (FFESTP_openixNOSPANBLOCKS)
+ || specified (FFESTP_openixORGANIZATION)
+ || specified (FFESTP_openixPAD)
+ || specified (FFESTP_openixPOSITION)
+ || specified (FFESTP_openixREADONLY)
+ || specified (FFESTP_openixRECORDTYPE)
+ || specified (FFESTP_openixSHARED)
+ || specified (FFESTP_openixUSEROPEN))
+ {
+ ffebad_start (FFEBAD_OPEN_UNSUPPORTED);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ }
+
+#undef specified
+#endif
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R904 (&ffestp_file.open);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR904_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R904.pool = ffesta_output_pool;
+ stmt->u.R904.params = ffestd_subr_copy_open_ ();
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R907 -- CLOSE statement
+
+ ffestd_R907();
+
+ Make sure a CLOSE is valid in the current context, and implement it. */
+
+void
+ffestd_R907 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R907 (&ffestp_file.close);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR907_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R907.pool = ffesta_output_pool;
+ stmt->u.R907.params = ffestd_subr_copy_close_ ();
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R909_start -- READ(...) statement list begin
+
+ ffestd_R909_start(FALSE);
+
+ Verify that READ is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_R909_start (bool only_format, ffestvUnit unit,
+ ffestvFormat format, bool rec, bool key)
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define specified(something) \
+ (ffestp_file.read.read_spec[something].kw_or_val_present)
+
+ /* Warn if there are any thing we don't handle via f2c libraries. */
+ if (specified (FFESTP_readixADVANCE)
+ || specified (FFESTP_readixEOR)
+ || specified (FFESTP_readixKEYEQ)
+ || specified (FFESTP_readixKEYGE)
+ || specified (FFESTP_readixKEYGT)
+ || specified (FFESTP_readixKEYID)
+ || specified (FFESTP_readixNULLS)
+ || specified (FFESTP_readixSIZE))
+ {
+ ffebad_start (FFEBAD_READ_UNSUPPORTED);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ }
+
+#undef specified
+#endif
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R909_start (&ffestp_file.read, only_format, unit, format, rec, key);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR909_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R909.pool = ffesta_output_pool;
+ stmt->u.R909.params = ffestd_subr_copy_read_ ();
+ stmt->u.R909.only_format = only_format;
+ stmt->u.R909.unit = unit;
+ stmt->u.R909.format = format;
+ stmt->u.R909.rec = rec;
+ stmt->u.R909.key = key;
+ stmt->u.R909.list = NULL;
+ ffestd_expr_list_ = &stmt->u.R909.list;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R909_item -- READ statement i/o item
+
+ ffestd_R909_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestd_R909_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_ONEPASS
+ ffeste_R909_item (expr);
+#else
+ {
+ ffestdExprItem_ item
+ = (ffestdExprItem_) malloc_new_kp (ffesta_output_pool, "ffestdExprItem_",
+ sizeof (*item));
+
+ item->next = NULL;
+ item->expr = expr;
+ item->token = ffelex_token_use (expr_token);
+ *ffestd_expr_list_ = item;
+ ffestd_expr_list_ = &item->next;
+ }
+#endif
+}
+
+/* ffestd_R909_finish -- READ statement list complete
+
+ ffestd_R909_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R909_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_ONEPASS
+ ffeste_R909_finish ();
+#else
+ /* Nothing to do, it's implicit. */
+#endif
+}
+
+/* ffestd_R910_start -- WRITE(...) statement list begin
+
+ ffestd_R910_start();
+
+ Verify that WRITE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_R910_start (ffestvUnit unit, ffestvFormat format, bool rec)
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define specified(something) \
+ (ffestp_file.write.write_spec[something].kw_or_val_present)
+
+ /* Warn if there are any thing we don't handle via f2c libraries. */
+ if (specified (FFESTP_writeixADVANCE)
+ || specified (FFESTP_writeixEOR))
+ {
+ ffebad_start (FFEBAD_WRITE_UNSUPPORTED);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ }
+
+#undef specified
+#endif
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R910_start (&ffestp_file.write, unit, format, rec);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR910_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R910.pool = ffesta_output_pool;
+ stmt->u.R910.params = ffestd_subr_copy_write_ ();
+ stmt->u.R910.unit = unit;
+ stmt->u.R910.format = format;
+ stmt->u.R910.rec = rec;
+ stmt->u.R910.list = NULL;
+ ffestd_expr_list_ = &stmt->u.R910.list;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R910_item -- WRITE statement i/o item
+
+ ffestd_R910_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestd_R910_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_ONEPASS
+ ffeste_R910_item (expr);
+#else
+ {
+ ffestdExprItem_ item
+ = (ffestdExprItem_) malloc_new_kp (ffesta_output_pool, "ffestdExprItem_",
+ sizeof (*item));
+
+ item->next = NULL;
+ item->expr = expr;
+ item->token = ffelex_token_use (expr_token);
+ *ffestd_expr_list_ = item;
+ ffestd_expr_list_ = &item->next;
+ }
+#endif
+}
+
+/* ffestd_R910_finish -- WRITE statement list complete
+
+ ffestd_R910_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R910_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_ONEPASS
+ ffeste_R910_finish ();
+#else
+ /* Nothing to do, it's implicit. */
+#endif
+}
+
+/* ffestd_R911_start -- PRINT statement list begin
+
+ ffestd_R911_start();
+
+ Verify that PRINT is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_R911_start (ffestvFormat format)
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R911_start (&ffestp_file.print, format);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR911_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R911.pool = ffesta_output_pool;
+ stmt->u.R911.params = ffestd_subr_copy_print_ ();
+ stmt->u.R911.format = format;
+ stmt->u.R911.list = NULL;
+ ffestd_expr_list_ = &stmt->u.R911.list;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R911_item -- PRINT statement i/o item
+
+ ffestd_R911_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestd_R911_item (ffebld expr, ffelexToken expr_token)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_ONEPASS
+ ffeste_R911_item (expr);
+#else
+ {
+ ffestdExprItem_ item
+ = (ffestdExprItem_) malloc_new_kp (ffesta_output_pool, "ffestdExprItem_",
+ sizeof (*item));
+
+ item->next = NULL;
+ item->expr = expr;
+ item->token = ffelex_token_use (expr_token);
+ *ffestd_expr_list_ = item;
+ ffestd_expr_list_ = &item->next;
+ }
+#endif
+}
+
+/* ffestd_R911_finish -- PRINT statement list complete
+
+ ffestd_R911_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R911_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_ONEPASS
+ ffeste_R911_finish ();
+#else
+ /* Nothing to do, it's implicit. */
+#endif
+}
+
+/* ffestd_R919 -- BACKSPACE statement
+
+ ffestd_R919();
+
+ Make sure a BACKSPACE is valid in the current context, and implement it. */
+
+void
+ffestd_R919 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R919 (&ffestp_file.beru);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR919_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R919.pool = ffesta_output_pool;
+ stmt->u.R919.params = ffestd_subr_copy_beru_ ();
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R920 -- ENDFILE statement
+
+ ffestd_R920();
+
+ Make sure a ENDFILE is valid in the current context, and implement it. */
+
+void
+ffestd_R920 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R920 (&ffestp_file.beru);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR920_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R920.pool = ffesta_output_pool;
+ stmt->u.R920.params = ffestd_subr_copy_beru_ ();
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R921 -- REWIND statement
+
+ ffestd_R921();
+
+ Make sure a REWIND is valid in the current context, and implement it. */
+
+void
+ffestd_R921 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R921 (&ffestp_file.beru);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR921_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R921.pool = ffesta_output_pool;
+ stmt->u.R921.params = ffestd_subr_copy_beru_ ();
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R923A -- INQUIRE statement (non-IOLENGTH version)
+
+ ffestd_R923A(bool by_file);
+
+ Make sure an INQUIRE is valid in the current context, and implement it. */
+
+void
+ffestd_R923A (bool by_file)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define specified(something) \
+ (ffestp_file.inquire.inquire_spec[something].kw_or_val_present)
+
+ /* Warn if there are any thing we don't handle via f2c libraries. */
+ if (specified (FFESTP_inquireixACTION)
+ || specified (FFESTP_inquireixCARRIAGECONTROL)
+ || specified (FFESTP_inquireixDEFAULTFILE)
+ || specified (FFESTP_inquireixDELIM)
+ || specified (FFESTP_inquireixKEYED)
+ || specified (FFESTP_inquireixORGANIZATION)
+ || specified (FFESTP_inquireixPAD)
+ || specified (FFESTP_inquireixPOSITION)
+ || specified (FFESTP_inquireixREAD)
+ || specified (FFESTP_inquireixREADWRITE)
+ || specified (FFESTP_inquireixRECORDTYPE)
+ || specified (FFESTP_inquireixWRITE))
+ {
+ ffebad_start (FFEBAD_INQUIRE_UNSUPPORTED);
+ ffebad_here (0, ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ ffebad_finish ();
+ }
+
+#undef specified
+#endif
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R923A (&ffestp_file.inquire, by_file);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR923A_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R923A.pool = ffesta_output_pool;
+ stmt->u.R923A.params = ffestd_subr_copy_inquire_ ();
+ stmt->u.R923A.by_file = by_file;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R923B_start -- INQUIRE(IOLENGTH=expr) statement list begin
+
+ ffestd_R923B_start();
+
+ Verify that INQUIRE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_R923B_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R923B_start (&ffestp_file.inquire);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR923B_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R923B.pool = ffesta_output_pool;
+ stmt->u.R923B.params = ffestd_subr_copy_inquire_ ();
+ stmt->u.R923B.list = NULL;
+ ffestd_expr_list_ = &stmt->u.R923B.list;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R923B_item -- INQUIRE statement i/o item
+
+ ffestd_R923B_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestd_R923B_item (ffebld expr)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_ONEPASS
+ ffeste_R923B_item (expr);
+#else
+ {
+ ffestdExprItem_ item
+ = (ffestdExprItem_) malloc_new_kp (ffesta_output_pool, "ffestdExprItem_",
+ sizeof (*item));
+
+ item->next = NULL;
+ item->expr = expr;
+ *ffestd_expr_list_ = item;
+ ffestd_expr_list_ = &item->next;
+ }
+#endif
+}
+
+/* ffestd_R923B_finish -- INQUIRE statement list complete
+
+ ffestd_R923B_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R923B_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_ONEPASS
+ ffeste_R923B_finish ();
+#else
+ /* Nothing to do, it's implicit. */
+#endif
+}
+
+/* ffestd_R1001 -- FORMAT statement
+
+ ffestd_R1001(format_list); */
+
+void
+ffestd_R1001 (ffesttFormatList f)
+{
+ ffestsHolder str;
+ ffests s = &str;
+
+ ffestd_check_simple_ ();
+
+ if (ffestd_label_formatdef_ == NULL)
+ return; /* Nothing to hook it up to (no label def). */
+
+ ffests_new (s, malloc_pool_image (), 80);
+ ffests_putc (s, '(');
+ ffestd_R1001dump_ (s, f); /* Build the string in s. */
+ ffests_putc (s, ')');
+
+#if FFECOM_ONEPASS
+ ffeste_R1001 (s);
+ ffests_kill (s); /* Kill the string in s. */
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR1001_);
+ ffestd_stmt_append_ (stmt);
+ stmt->u.R1001.str = str;
+ }
+#endif
+
+ ffestd_label_formatdef_ = NULL;
+}
+
+/* ffestd_R1001dump_ -- Dump list of formats
+
+ ffesttFormatList list;
+ ffestd_R1001dump_(list,0);
+
+ The formats in the list are dumped. */
+
+static void
+ffestd_R1001dump_ (ffests s, ffesttFormatList list)
+{
+ ffesttFormatList next;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ if (next != list->next)
+ ffests_putc (s, ',');
+ switch (next->type)
+ {
+ case FFESTP_formattypeI:
+ ffestd_R1001dump_1005_3_ (s, next, "I");
+ break;
+
+ case FFESTP_formattypeB:
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffestd_R1001dump_1005_3_ (s, next, "B");
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_R1001error_ (next);
+#else
+#error
+#endif
+ break;
+
+ case FFESTP_formattypeO:
+ ffestd_R1001dump_1005_3_ (s, next, "O");
+ break;
+
+ case FFESTP_formattypeZ:
+ ffestd_R1001dump_1005_3_ (s, next, "Z");
+ break;
+
+ case FFESTP_formattypeF:
+ ffestd_R1001dump_1005_4_ (s, next, "F");
+ break;
+
+ case FFESTP_formattypeE:
+ ffestd_R1001dump_1005_5_ (s, next, "E");
+ break;
+
+ case FFESTP_formattypeEN:
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffestd_R1001dump_1005_5_ (s, next, "EN");
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_R1001error_ (next);
+#else
+#error
+#endif
+ break;
+
+ case FFESTP_formattypeG:
+ ffestd_R1001dump_1005_5_ (s, next, "G");
+ break;
+
+ case FFESTP_formattypeL:
+ ffestd_R1001dump_1005_2_ (s, next, "L");
+ break;
+
+ case FFESTP_formattypeA:
+ ffestd_R1001dump_1005_1_ (s, next, "A");
+ break;
+
+ case FFESTP_formattypeD:
+ ffestd_R1001dump_1005_4_ (s, next, "D");
+ break;
+
+ case FFESTP_formattypeQ:
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffestd_R1001dump_1010_1_ (s, next, "Q");
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_R1001error_ (next);
+#else
+#error
+#endif
+ break;
+
+ case FFESTP_formattypeDOLLAR:
+ ffestd_R1001dump_1010_1_ (s, next, "$");
+ break;
+
+ case FFESTP_formattypeP:
+ ffestd_R1001dump_1010_4_ (s, next, "P");
+ break;
+
+ case FFESTP_formattypeT:
+ ffestd_R1001dump_1010_5_ (s, next, "T");
+ break;
+
+ case FFESTP_formattypeTL:
+ ffestd_R1001dump_1010_5_ (s, next, "TL");
+ break;
+
+ case FFESTP_formattypeTR:
+ ffestd_R1001dump_1010_5_ (s, next, "TR");
+ break;
+
+ case FFESTP_formattypeX:
+ ffestd_R1001dump_1010_3_ (s, next, "X");
+ break;
+
+ case FFESTP_formattypeS:
+ ffestd_R1001dump_1010_1_ (s, next, "S");
+ break;
+
+ case FFESTP_formattypeSP:
+ ffestd_R1001dump_1010_1_ (s, next, "SP");
+ break;
+
+ case FFESTP_formattypeSS:
+ ffestd_R1001dump_1010_1_ (s, next, "SS");
+ break;
+
+ case FFESTP_formattypeBN:
+ ffestd_R1001dump_1010_1_ (s, next, "BN");
+ break;
+
+ case FFESTP_formattypeBZ:
+ ffestd_R1001dump_1010_1_ (s, next, "BZ");
+ break;
+
+ case FFESTP_formattypeSLASH:
+ ffestd_R1001dump_1010_2_ (s, next, "/");
+ break;
+
+ case FFESTP_formattypeCOLON:
+ ffestd_R1001dump_1010_1_ (s, next, ":");
+ break;
+
+ case FFESTP_formattypeR1016:
+ switch (ffelex_token_type (next->t))
+ {
+ case FFELEX_typeCHARACTER:
+ {
+ char *p = ffelex_token_text (next->t);
+ ffeTokenLength i = ffelex_token_length (next->t);
+
+ ffests_putc (s, '\002');
+ while (i-- != 0)
+ {
+ if (*p == '\002')
+ ffests_putc (s, '\002');
+ ffests_putc (s, *p);
+ ++p;
+ }
+ ffests_putc (s, '\002');
+ }
+ break;
+
+ case FFELEX_typeHOLLERITH:
+ {
+ char *p = ffelex_token_text (next->t);
+ ffeTokenLength i = ffelex_token_length (next->t);
+
+ ffests_printf_1U (s,
+ "%" ffeTokenLength_f "uH",
+ i);
+ while (i-- != 0)
+ {
+ ffests_putc (s, *p);
+ ++p;
+ }
+ }
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ break;
+
+ case FFESTP_formattypeFORMAT:
+ if (next->u.R1003D.R1004.present)
+ {
+ if (next->u.R1003D.R1004.rtexpr)
+ ffestd_R1001rtexpr_ (s, next, next->u.R1003D.R1004.u.expr);
+ else
+ ffests_printf_1U (s, "%lu",
+ next->u.R1003D.R1004.u.unsigned_val);
+ }
+
+ ffests_putc (s, '(');
+ ffestd_R1001dump_ (s, next->u.R1003D.format);
+ ffests_putc (s, ')');
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+}
+
+/* ffestd_R1001dump_1005_1_ -- Dump a particular format
+
+ ffesttFormatList f;
+ ffestd_R1001dump_1005_1_(f,"I");
+
+ The format is dumped with form [r]X[w]. */
+
+static void
+ffestd_R1001dump_1005_1_ (ffests s, ffesttFormatList f, char *string)
+{
+ assert (!f->u.R1005.R1007_or_R1008.present);
+ assert (!f->u.R1005.R1009.present);
+
+ if (f->u.R1005.R1004.present)
+ {
+ if (f->u.R1005.R1004.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1004.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1004.u.unsigned_val);
+ }
+
+ ffests_puts (s, string);
+
+ if (f->u.R1005.R1006.present)
+ {
+ if (f->u.R1005.R1006.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1006.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1006.u.unsigned_val);
+ }
+}
+
+/* ffestd_R1001dump_1005_2_ -- Dump a particular format
+
+ ffesttFormatList f;
+ ffestd_R1001dump_1005_2_(f,"I");
+
+ The format is dumped with form [r]Xw. */
+
+static void
+ffestd_R1001dump_1005_2_ (ffests s, ffesttFormatList f, char *string)
+{
+ assert (!f->u.R1005.R1007_or_R1008.present);
+ assert (!f->u.R1005.R1009.present);
+ assert (f->u.R1005.R1006.present);
+
+ if (f->u.R1005.R1004.present)
+ {
+ if (f->u.R1005.R1004.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1004.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1004.u.unsigned_val);
+ }
+
+ ffests_puts (s, string);
+
+ if (f->u.R1005.R1006.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1006.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1006.u.unsigned_val);
+}
+
+/* ffestd_R1001dump_1005_3_ -- Dump a particular format
+
+ ffesttFormatList f;
+ ffestd_R1001dump_1005_3_(f,"I");
+
+ The format is dumped with form [r]Xw[.m]. */
+
+static void
+ffestd_R1001dump_1005_3_ (ffests s, ffesttFormatList f, char *string)
+{
+ assert (!f->u.R1005.R1009.present);
+ assert (f->u.R1005.R1006.present);
+
+ if (f->u.R1005.R1004.present)
+ {
+ if (f->u.R1005.R1004.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1004.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1004.u.unsigned_val);
+ }
+
+ ffests_puts (s, string);
+
+ if (f->u.R1005.R1006.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1006.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1006.u.unsigned_val);
+
+ if (f->u.R1005.R1007_or_R1008.present)
+ {
+ ffests_putc (s, '.');
+ if (f->u.R1005.R1007_or_R1008.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1007_or_R1008.u.expr);
+ else
+ ffests_printf_1U (s, "%lu",
+ f->u.R1005.R1007_or_R1008.u.unsigned_val);
+ }
+}
+
+/* ffestd_R1001dump_1005_4_ -- Dump a particular format
+
+ ffesttFormatList f;
+ ffestd_R1001dump_1005_4_(f,"I");
+
+ The format is dumped with form [r]Xw.d. */
+
+static void
+ffestd_R1001dump_1005_4_ (ffests s, ffesttFormatList f, char *string)
+{
+ assert (!f->u.R1005.R1009.present);
+ assert (f->u.R1005.R1007_or_R1008.present);
+ assert (f->u.R1005.R1006.present);
+
+ if (f->u.R1005.R1004.present)
+ {
+ if (f->u.R1005.R1004.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1004.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1004.u.unsigned_val);
+ }
+
+ ffests_puts (s, string);
+
+ if (f->u.R1005.R1006.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1006.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1006.u.unsigned_val);
+
+ ffests_putc (s, '.');
+ if (f->u.R1005.R1007_or_R1008.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1007_or_R1008.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1007_or_R1008.u.unsigned_val);
+}
+
+/* ffestd_R1001dump_1005_5_ -- Dump a particular format
+
+ ffesttFormatList f;
+ ffestd_R1001dump_1005_5_(f,"I");
+
+ The format is dumped with form [r]Xw.d[Ee]. */
+
+static void
+ffestd_R1001dump_1005_5_ (ffests s, ffesttFormatList f, char *string)
+{
+ assert (f->u.R1005.R1007_or_R1008.present);
+ assert (f->u.R1005.R1006.present);
+
+ if (f->u.R1005.R1004.present)
+ {
+ if (f->u.R1005.R1004.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1004.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1004.u.unsigned_val);
+ }
+
+ ffests_puts (s, string);
+
+ if (f->u.R1005.R1006.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1006.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1006.u.unsigned_val);
+
+ ffests_putc (s, '.');
+ if (f->u.R1005.R1007_or_R1008.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1007_or_R1008.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1007_or_R1008.u.unsigned_val);
+
+ if (f->u.R1005.R1009.present)
+ {
+ ffests_putc (s, 'E');
+ if (f->u.R1005.R1009.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1005.R1009.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1005.R1009.u.unsigned_val);
+ }
+}
+
+/* ffestd_R1001dump_1010_1_ -- Dump a particular format
+
+ ffesttFormatList f;
+ ffestd_R1001dump_1010_1_(f,"I");
+
+ The format is dumped with form X. */
+
+static void
+ffestd_R1001dump_1010_1_ (ffests s, ffesttFormatList f, char *string)
+{
+ assert (!f->u.R1010.val.present);
+
+ ffests_puts (s, string);
+}
+
+/* ffestd_R1001dump_1010_2_ -- Dump a particular format
+
+ ffesttFormatList f;
+ ffestd_R1001dump_1010_2_(f,"I");
+
+ The format is dumped with form [r]X. */
+
+static void
+ffestd_R1001dump_1010_2_ (ffests s, ffesttFormatList f, char *string)
+{
+ if (f->u.R1010.val.present)
+ {
+ if (f->u.R1010.val.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1010.val.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1010.val.u.unsigned_val);
+ }
+
+ ffests_puts (s, string);
+}
+
+/* ffestd_R1001dump_1010_3_ -- Dump a particular format
+
+ ffesttFormatList f;
+ ffestd_R1001dump_1010_3_(f,"I");
+
+ The format is dumped with form nX. */
+
+static void
+ffestd_R1001dump_1010_3_ (ffests s, ffesttFormatList f, char *string)
+{
+ assert (f->u.R1010.val.present);
+
+ if (f->u.R1010.val.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1010.val.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1010.val.u.unsigned_val);
+
+ ffests_puts (s, string);
+}
+
+/* ffestd_R1001dump_1010_4_ -- Dump a particular format
+
+ ffesttFormatList f;
+ ffestd_R1001dump_1010_4_(f,"I");
+
+ The format is dumped with form kX. Note that k is signed. */
+
+static void
+ffestd_R1001dump_1010_4_ (ffests s, ffesttFormatList f, char *string)
+{
+ assert (f->u.R1010.val.present);
+
+ if (f->u.R1010.val.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1010.val.u.expr);
+ else
+ ffests_printf_1D (s, "%ld", f->u.R1010.val.u.signed_val);
+
+ ffests_puts (s, string);
+}
+
+/* ffestd_R1001dump_1010_5_ -- Dump a particular format
+
+ ffesttFormatList f;
+ ffestd_R1001dump_1010_5_(f,"I");
+
+ The format is dumped with form Xn. */
+
+static void
+ffestd_R1001dump_1010_5_ (ffests s, ffesttFormatList f, char *string)
+{
+ assert (f->u.R1010.val.present);
+
+ ffests_puts (s, string);
+
+ if (f->u.R1010.val.rtexpr)
+ ffestd_R1001rtexpr_ (s, f, f->u.R1010.val.u.expr);
+ else
+ ffests_printf_1U (s, "%lu", f->u.R1010.val.u.unsigned_val);
+}
+
+/* ffestd_R1001error_ -- Complain about FORMAT specification not supported
+
+ ffesttFormatList f;
+ ffestd_R1001error_(f);
+
+ An error message is produced. */
+
+static void
+ffestd_R1001error_ (ffesttFormatList f)
+{
+ ffebad_start (FFEBAD_FORMAT_UNSUPPORTED);
+ ffebad_here (0, ffelex_token_where_line (f->t), ffelex_token_where_column (f->t));
+ ffebad_finish ();
+}
+
+static void
+ffestd_R1001rtexpr_ (ffests s, ffesttFormatList f, ffebld expr)
+{
+ if ((expr == NULL)
+ || (ffebld_op (expr) != FFEBLD_opCONTER)
+ || (ffeinfo_basictype (ffebld_info (expr)) != FFEINFO_basictypeINTEGER)
+ || (ffeinfo_kindtype (ffebld_info (expr)) == FFEINFO_kindtypeINTEGER4))
+ {
+ ffebad_start (FFEBAD_FORMAT_VARIABLE);
+ ffebad_here (0, ffelex_token_where_line (f->t), ffelex_token_where_column (f->t));
+ ffebad_finish ();
+ }
+ else
+ {
+ int val;
+
+ switch (ffeinfo_kindtype (ffebld_info (expr)))
+ {
+#if FFETARGET_okINTEGER1
+ case FFEINFO_kindtypeINTEGER1:
+ val = ffebld_constant_integer1 (ffebld_conter (expr));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER2
+ case FFEINFO_kindtypeINTEGER2:
+ val = ffebld_constant_integer2 (ffebld_conter (expr));
+ break;
+#endif
+
+#if FFETARGET_okINTEGER3
+ case FFEINFO_kindtypeINTEGER3:
+ val = ffebld_constant_integer3 (ffebld_conter (expr));
+ break;
+#endif
+
+ default:
+ assert ("bad INTEGER constant kind type" == NULL);
+ /* Fall through. */
+ case FFEINFO_kindtypeANY:
+ return;
+ }
+ ffests_printf_1D (s, "%ld", val);
+ }
+}
+
+/* ffestd_R1102 -- PROGRAM statement
+
+ ffestd_R1102(name_token);
+
+ Make sure ffestd_kind_ identifies an empty block. Make sure name_token
+ gives a valid name. Implement the beginning of a main program. */
+
+void
+ffestd_R1102 (ffesymbol s, ffelexToken name UNUSED)
+{
+ ffestd_check_simple_ ();
+
+ assert (ffestd_block_level_ == 0);
+ ffestd_is_reachable_ = TRUE;
+
+ ffecom_notify_primary_entry (s);
+ ffe_set_is_mainprog (TRUE); /* Is a main program. */
+ ffe_set_is_saveall (TRUE); /* Main program always has implicit SAVE. */
+
+ ffestw_set_sym (ffestw_stack_top (), s);
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if (name == NULL)
+ fputs ("< PROGRAM_unnamed\n", dmpout);
+ else
+ fprintf (dmpout, "< PROGRAM %s\n", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1103 -- End a PROGRAM
+
+ ffestd_R1103(); */
+
+void
+ffestd_R1103 (bool ok UNUSED)
+{
+ assert (ffestd_block_level_ == 0);
+
+ if (FFESTD_IS_END_OPTIMIZED_ && ffestd_is_reachable_)
+ ffestd_R842 (NULL); /* Generate STOP. */
+
+ if (ffestw_state (ffestw_stack_top ()) != FFESTV_statePROGRAM5)
+ ffestd_subr_labels_ (FALSE);/* Handle any undefined labels. */
+
+#if FFECOM_ONEPASS
+ ffeste_R1103 ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR1103_);
+ ffestd_stmt_append_ (stmt);
+ }
+#endif
+}
+
+/* ffestd_R1105 -- MODULE statement
+
+ ffestd_R1105(name_token);
+
+ Make sure ffestd_kind_ identifies an empty block. Make sure name_token
+ gives a valid name. Implement the beginning of a module. */
+
+#if FFESTR_F90
+void
+ffestd_R1105 (ffelexToken name)
+{
+ assert (ffestd_block_level_ == 0);
+
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fprintf (dmpout, "* MODULE %s\n", ffelex_token_text (name));
+#endif
+}
+
+/* ffestd_R1106 -- End a MODULE
+
+ ffestd_R1106(TRUE); */
+
+void
+ffestd_R1106 (bool ok)
+{
+ assert (ffestd_block_level_ == 0);
+
+ /* Generate any wrap-up code here (unlikely in MODULE!). */
+
+ if (ffestw_state (ffestw_stack_top ()) != FFESTV_stateMODULE5)
+ ffestd_subr_labels_ (TRUE); /* Handle any undefined labels (unlikely). */
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fprintf (dmpout, "< END_MODULE %s\n",
+ ffelex_token_text (ffestw_name (ffestw_stack_top ())));
+#endif
+}
+
+/* ffestd_R1107_start -- USE statement list begin
+
+ ffestd_R1107_start();
+
+ Verify that USE is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R1107_start (ffelexToken name, bool only)
+{
+ ffestd_check_start_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fprintf (dmpout, "* USE %s,", ffelex_token_text (name)); /* NB
+ _shriek_begin_uses_. */
+ if (only)
+ fputs ("only: ", dmpout);
+#endif
+}
+
+/* ffestd_R1107_item -- USE statement for name
+
+ ffestd_R1107_item(local_token,use_token);
+
+ Make sure name_token identifies a valid object to be USEed. local_token
+ may be NULL if _start_ was called with only==TRUE. */
+
+void
+ffestd_R1107_item (ffelexToken local, ffelexToken use)
+{
+ ffestd_check_item_ ();
+ assert (use != NULL);
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ if (local != NULL)
+ fprintf (dmpout, "%s=>", ffelex_token_text (local));
+ fprintf (dmpout, "%s,", ffelex_token_text (use));
+#endif
+}
+
+/* ffestd_R1107_finish -- USE statement list complete
+
+ ffestd_R1107_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R1107_finish ()
+{
+ ffestd_check_finish_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputc ('\n', dmpout);
+#endif
+}
+
+#endif
+/* ffestd_R1111 -- BLOCK DATA statement
+
+ ffestd_R1111(name_token);
+
+ Make sure ffestd_kind_ identifies no current program unit. If not
+ NULL, make sure name_token gives a valid name. Implement the beginning
+ of a block data program unit. */
+
+void
+ffestd_R1111 (ffesymbol s, ffelexToken name UNUSED)
+{
+ assert (ffestd_block_level_ == 0);
+ ffestd_is_reachable_ = TRUE;
+
+ ffestd_check_simple_ ();
+
+ ffecom_notify_primary_entry (s);
+ ffestw_set_sym (ffestw_stack_top (), s);
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if (name == NULL)
+ fputs ("< BLOCK_DATA_unnamed\n", dmpout);
+ else
+ fprintf (dmpout, "< BLOCK_DATA %s\n", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1112 -- End a BLOCK DATA
+
+ ffestd_R1112(TRUE); */
+
+void
+ffestd_R1112 (bool ok UNUSED)
+{
+ assert (ffestd_block_level_ == 0);
+
+ /* Generate any return-like code here (not likely for BLOCK DATA!). */
+
+ if (ffestw_state (ffestw_stack_top ()) != FFESTV_stateBLOCKDATA5)
+ ffestd_subr_labels_ (TRUE); /* Handle any undefined labels. */
+
+#if FFECOM_ONEPASS
+ ffeste_R1112 ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR1112_);
+ ffestd_stmt_append_ (stmt);
+ }
+#endif
+}
+
+/* ffestd_R1202 -- INTERFACE statement
+
+ ffestd_R1202(operator,defined_name);
+
+ Make sure ffestd_kind_ identifies an INTERFACE block.
+ Implement the end of the current interface.
+
+ 06-Jun-90 JCB 1.1
+ Allow no operator or name to mean INTERFACE by itself; missed this
+ valid form when originally doing syntactic analysis code. */
+
+#if FFESTR_F90
+void
+ffestd_R1202 (ffestpDefinedOperator operator, ffelexToken name)
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ switch (operator)
+ {
+ case FFESTP_definedoperatorNone:
+ if (name == NULL)
+ fputs ("* INTERFACE_unnamed\n", dmpout);
+ else
+ fprintf (dmpout, "* INTERFACE %s\n", ffelex_token_text (name));
+ break;
+
+ case FFESTP_definedoperatorOPERATOR:
+ fprintf (dmpout, "* INTERFACE_OPERATOR (.%s.)\n", ffelex_token_text (name));
+ break;
+
+ case FFESTP_definedoperatorASSIGNMENT:
+ fputs ("* INTERFACE_ASSIGNMENT (=)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorPOWER:
+ fputs ("* INTERFACE_OPERATOR (**)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorMULT:
+ fputs ("* INTERFACE_OPERATOR (*)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorADD:
+ fputs ("* INTERFACE_OPERATOR (+)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorCONCAT:
+ fputs ("* INTERFACE_OPERATOR (//)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorDIVIDE:
+ fputs ("* INTERFACE_OPERATOR (/)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorSUBTRACT:
+ fputs ("* INTERFACE_OPERATOR (-)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorNOT:
+ fputs ("* INTERFACE_OPERATOR (.not.)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorAND:
+ fputs ("* INTERFACE_OPERATOR (.and.)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorOR:
+ fputs ("* INTERFACE_OPERATOR (.or.)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorEQV:
+ fputs ("* INTERFACE_OPERATOR (.eqv.)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorNEQV:
+ fputs ("* INTERFACE_OPERATOR (.neqv.)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorEQ:
+ fputs ("* INTERFACE_OPERATOR (==)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorNE:
+ fputs ("* INTERFACE_OPERATOR (/=)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorLT:
+ fputs ("* INTERFACE_OPERATOR (<)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorLE:
+ fputs ("* INTERFACE_OPERATOR (<=)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorGT:
+ fputs ("* INTERFACE_OPERATOR (>)\n", dmpout);
+ break;
+
+ case FFESTP_definedoperatorGE:
+ fputs ("* INTERFACE_OPERATOR (>=)\n", dmpout);
+ break;
+
+ default:
+ assert (FALSE);
+ break;
+ }
+#endif
+}
+
+/* ffestd_R1203 -- End an INTERFACE
+
+ ffestd_R1203(TRUE); */
+
+void
+ffestd_R1203 (bool ok)
+{
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputs ("* END_INTERFACE\n", dmpout);
+#endif
+}
+
+/* ffestd_R1205_start -- MODULE PROCEDURE statement list begin
+
+ ffestd_R1205_start();
+
+ Verify that MODULE PROCEDURE is valid here, and begin accepting items in
+ the list. */
+
+void
+ffestd_R1205_start ()
+{
+ ffestd_check_start_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputs ("* MODULE_PROCEDURE ", dmpout);
+#endif
+}
+
+/* ffestd_R1205_item -- MODULE PROCEDURE statement for name
+
+ ffestd_R1205_item(name_token);
+
+ Make sure name_token identifies a valid object to be MODULE PROCEDUREed. */
+
+void
+ffestd_R1205_item (ffelexToken name)
+{
+ ffestd_check_item_ ();
+ assert (name != NULL);
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fprintf (dmpout, "%s,", ffelex_token_text (name));
+#endif
+}
+
+/* ffestd_R1205_finish -- MODULE PROCEDURE statement list complete
+
+ ffestd_R1205_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R1205_finish ()
+{
+ ffestd_check_finish_ ();
+
+ return; /* F90. */
+
+#ifdef FFESTD_F90
+ fputc ('\n', dmpout);
+#endif
+}
+
+#endif
+/* ffestd_R1207_start -- EXTERNAL statement list begin
+
+ ffestd_R1207_start();
+
+ Verify that EXTERNAL is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R1207_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* EXTERNAL (", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1207_item -- EXTERNAL statement for name
+
+ ffestd_R1207_item(name_token);
+
+ Make sure name_token identifies a valid object to be EXTERNALd. */
+
+void
+ffestd_R1207_item (ffelexToken name)
+{
+ ffestd_check_item_ ();
+ assert (name != NULL);
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "%s,", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1207_finish -- EXTERNAL statement list complete
+
+ ffestd_R1207_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R1207_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1208_start -- INTRINSIC statement list begin
+
+ ffestd_R1208_start();
+
+ Verify that INTRINSIC is valid here, and begin accepting items in the list. */
+
+void
+ffestd_R1208_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* INTRINSIC (", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1208_item -- INTRINSIC statement for name
+
+ ffestd_R1208_item(name_token);
+
+ Make sure name_token identifies a valid object to be INTRINSICd. */
+
+void
+ffestd_R1208_item (ffelexToken name)
+{
+ ffestd_check_item_ ();
+ assert (name != NULL);
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "%s,", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1208_finish -- INTRINSIC statement list complete
+
+ ffestd_R1208_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_R1208_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1212 -- CALL statement
+
+ ffestd_R1212(expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffestd_R1212 (ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R1212 (expr);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR1212_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R1212.pool = ffesta_output_pool;
+ stmt->u.R1212.expr = expr;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+}
+
+/* ffestd_R1213 -- Defined assignment statement
+
+ ffestd_R1213(dest_expr,source_expr,source_token);
+
+ Make sure the assignment is valid. */
+
+#if FFESTR_F90
+void
+ffestd_R1213 (ffebld dest, ffebld source)
+{
+ ffestd_check_simple_ ();
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("+ let_defined ", dmpout);
+ ffebld_dump (dest);
+ fputs ("=", dmpout);
+ ffebld_dump (source);
+ fputc ('\n', dmpout);
+#endif
+}
+
+#endif
+/* ffestd_R1219 -- FUNCTION statement
+
+ ffestd_R1219(funcname,arglist,ending_token,kind,kindt,len,lent,
+ recursive);
+
+ Make sure statement is valid here, register arguments for the
+ function name, and so on.
+
+ 06-Jun-90 JCB 2.0
+ Added the kind, len, and recursive arguments. */
+
+void
+ffestd_R1219 (ffesymbol s, ffelexToken funcname UNUSED,
+ ffesttTokenList args UNUSED, ffestpType type UNUSED,
+ ffebld kind UNUSED, ffelexToken kindt UNUSED,
+ ffebld len UNUSED, ffelexToken lent UNUSED,
+ bool recursive UNUSED, ffelexToken result UNUSED,
+ bool separate_result UNUSED)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ char *a;
+#endif
+
+ assert (ffestd_block_level_ == 0);
+ ffestd_is_reachable_ = TRUE;
+
+ ffestd_check_simple_ ();
+
+ ffecom_notify_primary_entry (s);
+ ffestw_set_sym (ffestw_stack_top (), s);
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ switch (type)
+ {
+ case FFESTP_typeINTEGER:
+ a = "INTEGER";
+ break;
+
+ case FFESTP_typeBYTE:
+ a = "BYTE";
+ break;
+
+ case FFESTP_typeWORD:
+ a = "WORD";
+ break;
+
+ case FFESTP_typeREAL:
+ a = "REAL";
+ break;
+
+ case FFESTP_typeCOMPLEX:
+ a = "COMPLEX";
+ break;
+
+ case FFESTP_typeLOGICAL:
+ a = "LOGICAL";
+ break;
+
+ case FFESTP_typeCHARACTER:
+ a = "CHARACTER";
+ break;
+
+ case FFESTP_typeDBLPRCSN:
+ a = "DOUBLE PRECISION";
+ break;
+
+ case FFESTP_typeDBLCMPLX:
+ a = "DOUBLE COMPLEX";
+ break;
+
+#if FFESTR_F90
+ case FFESTP_typeTYPE:
+ a = "TYPE";
+ break;
+#endif
+
+ case FFESTP_typeNone:
+ a = "";
+ break;
+
+ default:
+ assert (FALSE);
+ a = "?";
+ break;
+ }
+ fprintf (dmpout, "< FUNCTION %s ", ffelex_token_text (funcname));
+ if (recursive)
+ fputs ("RECURSIVE ", dmpout);
+ fprintf (dmpout, "%s(", a);
+ if (kindt != NULL)
+ {
+ fputs ("kind=", dmpout);
+ if (kind == NULL)
+ fputs (ffelex_token_text (kindt), dmpout);
+ else
+ ffebld_dump (kind);
+ if (lent != NULL)
+ fputc (',', dmpout);
+ }
+ if (lent != NULL)
+ {
+ fputs ("len=", dmpout);
+ if (len == NULL)
+ fputs (ffelex_token_text (lent), dmpout);
+ else
+ ffebld_dump (len);
+ }
+ fprintf (dmpout, ")");
+ if (args != NULL)
+ {
+ fputs (" (", dmpout);
+ ffestt_tokenlist_dump (args);
+ fputc (')', dmpout);
+ }
+ if (result != NULL)
+ fprintf (dmpout, " result(%s)", ffelex_token_text (result));
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1221 -- End a FUNCTION
+
+ ffestd_R1221(TRUE); */
+
+void
+ffestd_R1221 (bool ok UNUSED)
+{
+ assert (ffestd_block_level_ == 0);
+
+ if (FFESTD_IS_END_OPTIMIZED_ && ffestd_is_reachable_)
+ ffestd_R1227 (NULL); /* Generate RETURN. */
+
+ if (ffestw_state (ffestw_stack_top ()) != FFESTV_stateFUNCTION5)
+ ffestd_subr_labels_ (FALSE);/* Handle any undefined labels. */
+
+#if FFECOM_ONEPASS
+ ffeste_R1221 ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR1221_);
+ ffestd_stmt_append_ (stmt);
+ }
+#endif
+}
+
+/* ffestd_R1223 -- SUBROUTINE statement
+
+ ffestd_R1223(subrname,arglist,ending_token,recursive_token);
+
+ Make sure statement is valid here, register arguments for the
+ subroutine name, and so on.
+
+ 06-Jun-90 JCB 2.0
+ Added the recursive argument. */
+
+void
+ffestd_R1223 (ffesymbol s, ffelexToken subrname UNUSED,
+ ffesttTokenList args UNUSED, ffelexToken final UNUSED,
+ bool recursive UNUSED)
+{
+ assert (ffestd_block_level_ == 0);
+ ffestd_is_reachable_ = TRUE;
+
+ ffestd_check_simple_ ();
+
+ ffecom_notify_primary_entry (s);
+ ffestw_set_sym (ffestw_stack_top (), s);
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "< SUBROUTINE %s ", ffelex_token_text (subrname));
+ if (recursive)
+ fputs ("recursive ", dmpout);
+ if (args != NULL)
+ {
+ fputc ('(', dmpout);
+ ffestt_tokenlist_dump (args);
+ fputc (')', dmpout);
+ }
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1225 -- End a SUBROUTINE
+
+ ffestd_R1225(TRUE); */
+
+void
+ffestd_R1225 (bool ok UNUSED)
+{
+ assert (ffestd_block_level_ == 0);
+
+ if (FFESTD_IS_END_OPTIMIZED_ && ffestd_is_reachable_)
+ ffestd_R1227 (NULL); /* Generate RETURN. */
+
+ if (ffestw_state (ffestw_stack_top ()) != FFESTV_stateSUBROUTINE5)
+ ffestd_subr_labels_ (FALSE);/* Handle any undefined labels. */
+
+#if FFECOM_ONEPASS
+ ffeste_R1225 ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR1225_);
+ ffestd_stmt_append_ (stmt);
+ }
+#endif
+}
+
+/* ffestd_R1226 -- ENTRY statement
+
+ ffestd_R1226(entryname,arglist,ending_token);
+
+ Make sure we're in a SUBROUTINE or FUNCTION, register arguments for the
+ entry point name, and so on. */
+
+void
+ffestd_R1226 (ffesymbol entry)
+{
+ ffestd_check_simple_ ();
+
+#if (FFECOM_targetCURRENT == FFECOM_targetFFE) || FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R1226 (entry);
+#else
+ if (!ffesta_seen_first_exec || ffecom_2pass_advise_entrypoint (entry))
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR1226_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R1226.entry = entry;
+ stmt->u.R1226.entrynum = ++ffestd_2pass_entrypoints_;
+ }
+#endif
+
+ ffestd_is_reachable_ = TRUE;
+}
+
+/* ffestd_R1227 -- RETURN statement
+
+ ffestd_R1227(expr);
+
+ Make sure statement is valid here; implement. expr and expr_token are
+ both NULL if there was no expression. */
+
+void
+ffestd_R1227 (ffebld expr)
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R1227 (ffestw_stack_top (), expr);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR1227_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.R1227.pool = ffesta_output_pool;
+ stmt->u.R1227.block = ffestw_stack_top ();
+ stmt->u.R1227.expr = expr;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+ if (ffestd_block_level_ == 0)
+ ffestd_is_reachable_ = FALSE;
+}
+
+/* ffestd_R1228 -- CONTAINS statement
+
+ ffestd_R1228(); */
+
+#if FFESTR_F90
+void
+ffestd_R1228 ()
+{
+ assert (ffestd_block_level_ == 0);
+
+ ffestd_check_simple_ ();
+
+ /* Generate RETURN/STOP code here */
+
+ ffestd_subr_labels_ (ffestw_state (ffestw_stack_top ())
+ == FFESTV_stateMODULE5); /* Handle any undefined
+ labels. */
+
+ ffestd_subr_f90_ ();
+ return;
+
+#ifdef FFESTD_F90
+ fputs ("- CONTAINS\n", dmpout);
+#endif
+}
+
+#endif
+/* ffestd_R1229_start -- STMTFUNCTION statement begin
+
+ ffestd_R1229_start(func_name,func_arg_list,close_paren);
+
+ This function does not really need to do anything, since _finish_
+ gets all the info needed, and ffestc_R1229_start has already
+ done all the stuff that makes a two-phase operation (start and
+ finish) for handling statement functions necessary.
+
+ 03-Jan-91 JCB 2.0
+ Do nothing, now that _finish_ does everything. */
+
+void
+ffestd_R1229_start (ffelexToken name UNUSED, ffesttTokenList args UNUSED)
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_R1229_finish -- STMTFUNCTION statement list complete
+
+ ffestd_R1229_finish(s);
+
+ The statement function's symbol is passed. Its list of dummy args is
+ accessed via ffesymbol_dummyargs and its expansion expression (expr)
+ is accessed via ffesymbol_sfexpr.
+
+ If sfexpr is NULL, an error occurred parsing the expansion expression, so
+ just cancel the effects of ffestd_R1229_start and pretend nothing
+ happened. Otherwise, install the expression as the expansion for the
+ statement function, then clean up.
+
+ 03-Jan-91 JCB 2.0
+ Takes sfunc sym instead of just the expansion expression as an
+ argument, so this function can do all the work, and _start_ is just
+ a nicety than can do nothing in a back end. */
+
+void
+ffestd_R1229_finish (ffesymbol s)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld args = ffesymbol_dummyargs (s);
+#endif
+ ffebld expr = ffesymbol_sfexpr (s);
+
+ ffestd_check_finish_ ();
+
+ if (expr == NULL)
+ return; /* Nothing to do, definition didn't work. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "* stmtfunction %s(", ffesymbol_text (s));
+ for (; args != NULL; args = ffebld_trail (args))
+ fprintf (dmpout, "%s,", ffesymbol_text (ffebld_symter (ffebld_head (args))));
+ fputs (")=", dmpout);
+ ffebld_dump (expr);
+ fputc ('\n', dmpout);
+#if 0 /* Normally no need to preserve the
+ expression. */
+ ffesymbol_set_sfexpr (s, NULL); /* Except expr.c sees NULL
+ as recursive reference!
+ So until we can use something
+ convenient, like a "permanent"
+ expression, don't worry about
+ wasting some memory in the
+ stand-alone FFE. */
+#else
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+#endif
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ /* With gcc, cannot do anything here, because the backend hasn't even
+ (necessarily) been notified that we're compiling a program unit! */
+
+#if 0 /* Must preserve the expression for gcc. */
+ ffesymbol_set_sfexpr (s, NULL);
+#else
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+#endif
+#else
+#error
+#endif
+}
+
+/* ffestd_S3P4 -- INCLUDE line
+
+ ffestd_S3P4(filename,filename_token);
+
+ Make sure INCLUDE not preceded by any semicolons or a label def; implement. */
+
+void
+ffestd_S3P4 (ffebld filename)
+{
+ FILE *fi;
+ ffetargetCharacterDefault buildname;
+ ffewhereFile wf;
+
+ ffestd_check_simple_ ();
+
+ assert (filename != NULL);
+ if (ffebld_op (filename) != FFEBLD_opANY)
+ {
+ assert (ffebld_op (filename) == FFEBLD_opCONTER);
+ assert (ffeinfo_basictype (ffebld_info (filename))
+ == FFEINFO_basictypeCHARACTER);
+ assert (ffeinfo_kindtype (ffebld_info (filename))
+ == FFEINFO_kindtypeCHARACTERDEFAULT);
+ buildname = ffebld_constant_characterdefault (ffebld_conter (filename));
+ wf = ffewhere_file_new (ffetarget_text_characterdefault (buildname),
+ ffetarget_length_characterdefault (buildname));
+ fi = ffecom_open_include (ffewhere_file_name (wf),
+ ffelex_token_where_line (ffesta_tokens[0]),
+ ffelex_token_where_column (ffesta_tokens[0]));
+ if (fi == NULL)
+ ffewhere_file_kill (wf);
+ else
+ ffelex_set_include (wf, (ffelex_token_type (ffesta_tokens[0])
+ == FFELEX_typeNAME), fi);
+ }
+}
+
+/* ffestd_V003_start -- STRUCTURE statement list begin
+
+ ffestd_V003_start(structure_name);
+
+ Verify that STRUCTURE is valid here, and begin accepting items in the list. */
+
+#if FFESTR_VXT
+void
+ffestd_V003_start (ffelexToken structure_name)
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if (structure_name == NULL)
+ fputs ("* STRUCTURE_unnamed ", dmpout);
+ else
+ fprintf (dmpout, "* STRUCTURE %s ", ffelex_token_text (structure_name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#else
+#error
+#endif
+}
+
+/* ffestd_V003_item -- STRUCTURE statement for object-name
+
+ ffestd_V003_item(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be STRUCTUREd. */
+
+void
+ffestd_V003_item (ffelexToken name, ffesttDimList dims)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs (ffelex_token_text (name), dmpout);
+ if (dims != NULL)
+ {
+ fputc ('(', dmpout);
+ ffestt_dimlist_dump (dims);
+ fputc (')', dmpout);
+ }
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V003_finish -- STRUCTURE statement list complete
+
+ ffestd_V003_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_V003_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V004 -- End a STRUCTURE
+
+ ffestd_V004(TRUE); */
+
+void
+ffestd_V004 (bool ok)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* END_STRUCTURE\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V009 -- UNION statement
+
+ ffestd_V009(); */
+
+void
+ffestd_V009 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* UNION\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V010 -- End a UNION
+
+ ffestd_V010(TRUE); */
+
+void
+ffestd_V010 (bool ok)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* END_UNION\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V012 -- MAP statement
+
+ ffestd_V012(); */
+
+void
+ffestd_V012 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* MAP\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V013 -- End a MAP
+
+ ffestd_V013(TRUE); */
+
+void
+ffestd_V013 (bool ok)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* END_MAP\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+#endif
+/* ffestd_V014_start -- VOLATILE statement list begin
+
+ ffestd_V014_start();
+
+ Verify that VOLATILE is valid here, and begin accepting items in the list. */
+
+void
+ffestd_V014_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* VOLATILE (", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#else
+#error
+#endif
+}
+
+/* ffestd_V014_item_object -- VOLATILE statement for object-name
+
+ ffestd_V014_item_object(name_token);
+
+ Make sure name_token identifies a valid object to be VOLATILEd. */
+
+void
+ffestd_V014_item_object (ffelexToken name UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "%s,", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V014_item_cblock -- VOLATILE statement for common-block-name
+
+ ffestd_V014_item_cblock(name_token);
+
+ Make sure name_token identifies a valid common block to be VOLATILEd. */
+
+void
+ffestd_V014_item_cblock (ffelexToken name UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "/%s/,", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V014_finish -- VOLATILE statement list complete
+
+ ffestd_V014_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_V014_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V016_start -- RECORD statement list begin
+
+ ffestd_V016_start();
+
+ Verify that RECORD is valid here, and begin accepting items in the list. */
+
+#if FFESTR_VXT
+void
+ffestd_V016_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* RECORD ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#else
+#error
+#endif
+}
+
+/* ffestd_V016_item_structure -- RECORD statement for common-block-name
+
+ ffestd_V016_item_structure(name_token);
+
+ Make sure name_token identifies a valid structure to be RECORDed. */
+
+void
+ffestd_V016_item_structure (ffelexToken name)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "/%s/,", ffelex_token_text (name));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V016_item_object -- RECORD statement for object-name
+
+ ffestd_V016_item_object(name_token,dim_list);
+
+ Make sure name_token identifies a valid object to be RECORDd. */
+
+void
+ffestd_V016_item_object (ffelexToken name, ffesttDimList dims)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs (ffelex_token_text (name), dmpout);
+ if (dims != NULL)
+ {
+ fputc ('(', dmpout);
+ ffestt_dimlist_dump (dims);
+ fputc (')', dmpout);
+ }
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V016_finish -- RECORD statement list complete
+
+ ffestd_V016_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_V016_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V018_start -- REWRITE(...) statement list begin
+
+ ffestd_V018_start();
+
+ Verify that REWRITE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_V018_start (ffestvFormat format)
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_V018_start (&ffestp_file.rewrite, format);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV018_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.V018.pool = ffesta_output_pool;
+ stmt->u.V018.params = ffestd_subr_copy_rewrite_ ();
+ stmt->u.V018.format = format;
+ stmt->u.V018.list = NULL;
+ ffestd_expr_list_ = &stmt->u.V018.list;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#endif
+}
+
+/* ffestd_V018_item -- REWRITE statement i/o item
+
+ ffestd_V018_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestd_V018_item (ffebld expr)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V018_item (expr);
+#else
+ {
+ ffestdExprItem_ item
+ = (ffestdExprItem_) malloc_new_kp (ffesta_output_pool, "ffestdExprItem_",
+ sizeof (*item));
+
+ item->next = NULL;
+ item->expr = expr;
+ *ffestd_expr_list_ = item;
+ ffestd_expr_list_ = &item->next;
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V018_finish -- REWRITE statement list complete
+
+ ffestd_V018_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_V018_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V018_finish ();
+#else
+ /* Nothing to do, it's implicit. */
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V019_start -- ACCEPT statement list begin
+
+ ffestd_V019_start();
+
+ Verify that ACCEPT is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_V019_start (ffestvFormat format)
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_V019_start (&ffestp_file.accept, format);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV019_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.V019.pool = ffesta_output_pool;
+ stmt->u.V019.params = ffestd_subr_copy_accept_ ();
+ stmt->u.V019.format = format;
+ stmt->u.V019.list = NULL;
+ ffestd_expr_list_ = &stmt->u.V019.list;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#endif
+}
+
+/* ffestd_V019_item -- ACCEPT statement i/o item
+
+ ffestd_V019_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestd_V019_item (ffebld expr)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V019_item (expr);
+#else
+ {
+ ffestdExprItem_ item
+ = (ffestdExprItem_) malloc_new_kp (ffesta_output_pool, "ffestdExprItem_",
+ sizeof (*item));
+
+ item->next = NULL;
+ item->expr = expr;
+ *ffestd_expr_list_ = item;
+ ffestd_expr_list_ = &item->next;
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V019_finish -- ACCEPT statement list complete
+
+ ffestd_V019_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_V019_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V019_finish ();
+#else
+ /* Nothing to do, it's implicit. */
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+#endif
+/* ffestd_V020_start -- TYPE statement list begin
+
+ ffestd_V020_start();
+
+ Verify that TYPE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_V020_start (ffestvFormat format UNUSED)
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_V020_start (&ffestp_file.type, format);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV020_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.V020.pool = ffesta_output_pool;
+ stmt->u.V020.params = ffestd_subr_copy_type_ ();
+ stmt->u.V020.format = format;
+ stmt->u.V020.list = NULL;
+ ffestd_expr_list_ = &stmt->u.V020.list;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#endif
+}
+
+/* ffestd_V020_item -- TYPE statement i/o item
+
+ ffestd_V020_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestd_V020_item (ffebld expr UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V020_item (expr);
+#else
+ {
+ ffestdExprItem_ item
+ = (ffestdExprItem_) malloc_new_kp (ffesta_output_pool, "ffestdExprItem_",
+ sizeof (*item));
+
+ item->next = NULL;
+ item->expr = expr;
+ *ffestd_expr_list_ = item;
+ ffestd_expr_list_ = &item->next;
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V020_finish -- TYPE statement list complete
+
+ ffestd_V020_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_V020_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V020_finish ();
+#else
+ /* Nothing to do, it's implicit. */
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V021 -- DELETE statement
+
+ ffestd_V021();
+
+ Make sure a DELETE is valid in the current context, and implement it. */
+
+#if FFESTR_VXT
+void
+ffestd_V021 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_V021 (&ffestp_file.delete);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV021_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.V021.pool = ffesta_output_pool;
+ stmt->u.V021.params = ffestd_subr_copy_delete_ ();
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#endif
+}
+
+/* ffestd_V022 -- UNLOCK statement
+
+ ffestd_V022();
+
+ Make sure a UNLOCK is valid in the current context, and implement it. */
+
+void
+ffestd_V022 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_V022 (&ffestp_file.beru);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV022_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.V022.pool = ffesta_output_pool;
+ stmt->u.V022.params = ffestd_subr_copy_beru_ ();
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#endif
+}
+
+/* ffestd_V023_start -- ENCODE(...) statement list begin
+
+ ffestd_V023_start();
+
+ Verify that ENCODE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_V023_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_V023_start (&ffestp_file.vxtcode);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV023_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.V023.pool = ffesta_output_pool;
+ stmt->u.V023.params = ffestd_subr_copy_vxtcode_ ();
+ stmt->u.V023.list = NULL;
+ ffestd_expr_list_ = &stmt->u.V023.list;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#endif
+}
+
+/* ffestd_V023_item -- ENCODE statement i/o item
+
+ ffestd_V023_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestd_V023_item (ffebld expr)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V023_item (expr);
+#else
+ {
+ ffestdExprItem_ item
+ = (ffestdExprItem_) malloc_new_kp (ffesta_output_pool, "ffestdExprItem_",
+ sizeof (*item));
+
+ item->next = NULL;
+ item->expr = expr;
+ *ffestd_expr_list_ = item;
+ ffestd_expr_list_ = &item->next;
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V023_finish -- ENCODE statement list complete
+
+ ffestd_V023_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_V023_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V023_finish ();
+#else
+ /* Nothing to do, it's implicit. */
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V024_start -- DECODE(...) statement list begin
+
+ ffestd_V024_start();
+
+ Verify that DECODE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_V024_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_V024_start (&ffestp_file.vxtcode);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV024_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.V024.pool = ffesta_output_pool;
+ stmt->u.V024.params = ffestd_subr_copy_vxtcode_ ();
+ stmt->u.V024.list = NULL;
+ ffestd_expr_list_ = &stmt->u.V024.list;
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#endif
+}
+
+/* ffestd_V024_item -- DECODE statement i/o item
+
+ ffestd_V024_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffestd_V024_item (ffebld expr)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V024_item (expr);
+#else
+ {
+ ffestdExprItem_ item
+ = (ffestdExprItem_) malloc_new_kp (ffesta_output_pool, "ffestdExprItem_",
+ sizeof (*item));
+
+ item->next = NULL;
+ item->expr = expr;
+ *ffestd_expr_list_ = item;
+ ffestd_expr_list_ = &item->next;
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V024_finish -- DECODE statement list complete
+
+ ffestd_V024_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_V024_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V024_finish ();
+#else
+ /* Nothing to do, it's implicit. */
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V025_start -- DEFINEFILE statement list begin
+
+ ffestd_V025_start();
+
+ Verify that DEFINEFILE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffestd_V025_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_V025_start ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV025start_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#endif
+}
+
+/* ffestd_V025_item -- DEFINE FILE statement item
+
+ ffestd_V025_item(u,ut,m,mt,n,nt,asv,asvt);
+
+ Implement item. Treat each item kind of like a separate statement,
+ since there's really no need to treat them as an aggregate. */
+
+void
+ffestd_V025_item (ffebld u, ffebld m, ffebld n, ffebld asv)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V025_item (u, m, n, asv);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV025item_);
+ ffestd_stmt_append_ (stmt);
+ stmt->u.V025item.u = u;
+ stmt->u.V025item.m = m;
+ stmt->u.V025item.n = n;
+ stmt->u.V025item.asv = asv;
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V025_finish -- DEFINE FILE statement list complete
+
+ ffestd_V025_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_V025_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffeste_V025_finish ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV025finish_);
+ stmt->u.V025finish.pool = ffesta_output_pool;
+ ffestd_stmt_append_ (stmt);
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#endif
+}
+
+/* ffestd_V026 -- FIND statement
+
+ ffestd_V026();
+
+ Make sure a FIND is valid in the current context, and implement it. */
+
+void
+ffestd_V026 ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_V026 (&ffestp_file.find);
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidV026_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ stmt->u.V026.pool = ffesta_output_pool;
+ stmt->u.V026.params = ffestd_subr_copy_find_ ();
+ ffesta_set_outpooldisp (FFESTA_pooldispPRESERVE);
+ }
+#endif
+
+#endif
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#endif
+}
+
+#endif
+/* ffestd_V027_start -- VXT PARAMETER statement list begin
+
+ ffestd_V027_start();
+
+ Verify that PARAMETER is valid here, and begin accepting items in the list. */
+
+void
+ffestd_V027_start ()
+{
+ ffestd_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* PARAMETER_vxt ", dmpout);
+#else
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffestd_subr_vxt_ ();
+#endif
+#endif
+}
+
+/* ffestd_V027_item -- VXT PARAMETER statement assignment
+
+ ffestd_V027_item(dest,dest_token,source,source_token);
+
+ Make sure the source is a valid source for the destination; make the
+ assignment. */
+
+void
+ffestd_V027_item (ffelexToken dest_token UNUSED, ffebld source UNUSED)
+{
+ ffestd_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs (ffelex_token_text (dest_token), dmpout);
+ fputc ('=', dmpout);
+ ffebld_dump (source);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffestd_V027_finish -- VXT PARAMETER statement list complete
+
+ ffestd_V027_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffestd_V027_finish ()
+{
+ ffestd_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* Any executable statement. */
+
+void
+ffestd_any ()
+{
+ ffestd_check_simple_ ();
+
+#if FFECOM_ONEPASS
+ ffestd_subr_line_now_ ();
+ ffeste_R841 ();
+#else
+ {
+ ffestdStmt_ stmt;
+
+ stmt = ffestd_stmt_new_ (FFESTD_stmtidR841_);
+ ffestd_stmt_append_ (stmt);
+ ffestd_subr_line_save_ (stmt);
+ }
+#endif
+}
diff --git a/contrib/gcc/f/std.h b/contrib/gcc/f/std.h
new file mode 100644
index 0000000..810f427
--- /dev/null
+++ b/contrib/gcc/f/std.h
@@ -0,0 +1,298 @@
+/* std.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ std.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_std
+#define _H_f_std
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "bld.h"
+#include "lab.h"
+#include "lex.h"
+#include "stp.h"
+#include "str.h"
+#include "stt.h"
+#include "stv.h"
+#include "stw.h"
+#include "symbol.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+void ffestd_begin_uses (void);
+void ffestd_do (bool ok);
+#if FFESTR_F90
+void ffestd_end_uses (bool ok);
+void ffestd_end_R740 (bool ok);
+#endif
+void ffestd_end_R807 (bool ok);
+void ffestd_exec_begin (void);
+void ffestd_exec_end (void);
+void ffestd_init_3 (void);
+void ffestd_labeldef_any (ffelab label);
+void ffestd_labeldef_branch (ffelab label);
+void ffestd_labeldef_format (ffelab label);
+void ffestd_labeldef_useless (ffelab label);
+#if FFESTR_F90
+void ffestd_R423A (void);
+void ffestd_R423B (void);
+void ffestd_R424 (ffelexToken access, ffestrOther access_kw, ffelexToken name);
+void ffestd_R425 (bool ok);
+void ffestd_R519_start (ffestrOther intent_kw);
+void ffestd_R519_item (ffelexToken name);
+void ffestd_R519_finish (void);
+void ffestd_R520_start (void);
+void ffestd_R520_item (ffelexToken name);
+void ffestd_R520_finish (void);
+void ffestd_R521A (void);
+void ffestd_R521Astart (void);
+void ffestd_R521Aitem (ffelexToken name);
+void ffestd_R521Afinish (void);
+void ffestd_R521B (void);
+void ffestd_R521Bstart (void);
+void ffestd_R521Bitem (ffelexToken name);
+void ffestd_R521Bfinish (void);
+#endif
+void ffestd_R522 (void);
+void ffestd_R522start (void);
+void ffestd_R522item_object (ffelexToken name);
+void ffestd_R522item_cblock (ffelexToken name);
+void ffestd_R522finish (void);
+void ffestd_R524_start (bool virtual);
+void ffestd_R524_item (ffelexToken name, ffesttDimList dims);
+void ffestd_R524_finish (void);
+#if FFESTR_F90
+void ffestd_R525_start (void);
+void ffestd_R525_item (ffelexToken name, ffesttDimList dims);
+void ffestd_R525_finish (void);
+void ffestd_R526_start (void);
+void ffestd_R526_item (ffelexToken name, ffesttDimList dims);
+void ffestd_R526_finish (void);
+void ffestd_R527_start (void);
+void ffestd_R527_item (ffelexToken name, ffesttDimList dims);
+void ffestd_R527_finish (void);
+#endif
+void ffestd_R537_start (void);
+void ffestd_R537_item (ffebld dest, ffebld source);
+void ffestd_R537_finish (void);
+void ffestd_R539 (void);
+void ffestd_R539start (void);
+void ffestd_R539item (ffestpType type, ffebld kind, ffelexToken kindt,
+ ffebld len, ffelexToken lent, ffesttImpList letters);
+void ffestd_R539finish (void);
+void ffestd_R542_start (void);
+void ffestd_R542_item_nlist (ffelexToken name);
+void ffestd_R542_item_nitem (ffelexToken name);
+void ffestd_R542_finish (void);
+void ffestd_R544_start (void);
+void ffestd_R544_item (ffesttExprList exprlist);
+void ffestd_R544_finish (void);
+void ffestd_R547_start (void);
+void ffestd_R547_item_object (ffelexToken name, ffesttDimList dims);
+void ffestd_R547_item_cblock (ffelexToken name);
+void ffestd_R547_finish (void);
+#if FFESTR_F90
+void ffestd_R620 (ffesttExprList exprlist, ffebld stat);
+void ffestd_R624 (ffesttExprList pointers);
+void ffestd_R625 (ffesttExprList exprlist, ffebld stat);
+#endif
+void ffestd_R737A (ffebld dest, ffebld source);
+#if FFESTR_F90
+void ffestd_R737B (ffebld dest, ffebld source);
+void ffestd_R738 (ffebld dest, ffebld source);
+void ffestd_R740 (ffebld expr);
+void ffestd_R742 (ffebld expr);
+void ffestd_R744 (void);
+void ffestd_R745 (bool ok);
+#endif
+void ffestd_R803 (ffelexToken construct_name, ffebld expr);
+void ffestd_R804 (ffebld expr, ffelexToken name);
+void ffestd_R805 (ffelexToken name);
+void ffestd_R806 (bool ok);
+void ffestd_R807 (ffebld expr);
+void ffestd_R809 (ffelexToken construct_name, ffebld expr);
+void ffestd_R810 (unsigned long casenum);
+void ffestd_R811 (bool ok);
+void ffestd_R819A (ffelexToken construct_name, ffelab label, ffebld var,
+ ffebld start, ffelexToken start_token,
+ ffebld end, ffelexToken end_token,
+ ffebld incr, ffelexToken incr_token);
+void ffestd_R819B (ffelexToken construct_name, ffelab label, ffebld expr);
+void ffestd_R825 (ffelexToken name);
+void ffestd_R834 (ffestw block);
+void ffestd_R835 (ffestw block);
+void ffestd_R836 (ffelab label);
+void ffestd_R837 (ffelab *labels, int count, ffebld expr);
+void ffestd_R838 (ffelab label, ffebld target);
+void ffestd_R839 (ffebld target, ffelab *labels, int count);
+void ffestd_R840 (ffebld expr, ffelab neg, ffelab zero, ffelab pos);
+void ffestd_R841 (bool in_where);
+void ffestd_R842 (ffebld expr);
+void ffestd_R843 (ffebld expr);
+void ffestd_R904 (void);
+void ffestd_R907 (void);
+void ffestd_R909_start (bool only_format, ffestvUnit unit,
+ ffestvFormat format, bool rec, bool key);
+void ffestd_R909_item (ffebld expr, ffelexToken expr_token);
+void ffestd_R909_finish (void);
+void ffestd_R910_start (ffestvUnit unit, ffestvFormat format, bool rec);
+void ffestd_R910_item (ffebld expr, ffelexToken expr_token);
+void ffestd_R910_finish (void);
+void ffestd_R911_start (ffestvFormat format);
+void ffestd_R911_item (ffebld expr, ffelexToken expr_token);
+void ffestd_R911_finish (void);
+void ffestd_R919 (void);
+void ffestd_R920 (void);
+void ffestd_R921 (void);
+void ffestd_R923A (bool by_file);
+void ffestd_R923B_start (void);
+void ffestd_R923B_item (ffebld expr);
+void ffestd_R923B_finish (void);
+void ffestd_R1001 (ffesttFormatList f);
+void ffestd_R1102 (ffesymbol s, ffelexToken name);
+void ffestd_R1103 (bool ok);
+#if FFESTR_F90
+void ffestd_R1105 (ffelexToken name);
+void ffestd_R1106 (bool ok);
+void ffestd_R1107_start (ffelexToken name, bool only);
+void ffestd_R1107_item (ffelexToken local, ffelexToken use);
+void ffestd_R1107_finish (void);
+#endif
+void ffestd_R1111 (ffesymbol s, ffelexToken name);
+void ffestd_R1112 (bool ok);
+#if FFESTR_F90
+void ffestd_R1202 (ffestpDefinedOperator operator, ffelexToken name);
+void ffestd_R1203 (bool ok);
+void ffestd_R1205_start (void);
+void ffestd_R1205_item (ffelexToken name);
+void ffestd_R1205_finish (void);
+#endif
+void ffestd_R1207_start (void);
+void ffestd_R1207_item (ffelexToken name);
+void ffestd_R1207_finish (void);
+void ffestd_R1208_start (void);
+void ffestd_R1208_item (ffelexToken name);
+void ffestd_R1208_finish (void);
+void ffestd_R1212 (ffebld expr);
+#if FFESTR_F90
+void ffestd_R1213 (ffebld dest, ffebld source);
+#endif
+void ffestd_R1219 (ffesymbol s, ffelexToken funcname,
+ ffesttTokenList args, ffestpType type, ffebld kind,
+ ffelexToken kindt, ffebld len, ffelexToken lent,
+ bool recursive, ffelexToken result,
+ bool separate_result);
+void ffestd_R1221 (bool ok);
+void ffestd_R1223 (ffesymbol s, ffelexToken subrname, ffesttTokenList args,
+ ffelexToken final, bool recursive);
+void ffestd_R1225 (bool ok);
+void ffestd_R1226 (ffesymbol entry);
+void ffestd_R1227 (ffebld expr);
+#if FFESTR_F90
+void ffestd_R1228 (void);
+#endif
+void ffestd_R1229_start (ffelexToken name, ffesttTokenList args);
+void ffestd_R1229_finish (ffesymbol s);
+void ffestd_S3P4 (ffebld filename);
+#if FFESTR_VXT
+void ffestd_V003_start (ffelexToken structure_name);
+void ffestd_V003_item (ffelexToken name, ffesttDimList dims);
+void ffestd_V003_finish (void);
+void ffestd_V004 (bool ok);
+void ffestd_V009 (void);
+void ffestd_V010 (bool ok);
+void ffestd_V012 (void);
+void ffestd_V013 (bool ok);
+#endif
+void ffestd_V014_start (void);
+void ffestd_V014_item_object (ffelexToken name);
+void ffestd_V014_item_cblock (ffelexToken name);
+void ffestd_V014_finish (void);
+#if FFESTR_VXT
+void ffestd_V016_start (void);
+void ffestd_V016_item_structure (ffelexToken name);
+void ffestd_V016_item_object (ffelexToken name, ffesttDimList dims);
+void ffestd_V016_finish (void);
+void ffestd_V018_start (ffestvFormat format);
+void ffestd_V018_item (ffebld expr);
+void ffestd_V018_finish (void);
+void ffestd_V019_start (ffestvFormat format);
+void ffestd_V019_item (ffebld expr);
+void ffestd_V019_finish (void);
+#endif
+void ffestd_V020_start (ffestvFormat format);
+void ffestd_V020_item (ffebld expr);
+void ffestd_V020_finish (void);
+#if FFESTR_VXT
+void ffestd_V021 (void);
+void ffestd_V022 (void);
+void ffestd_V023_start (void);
+void ffestd_V023_item (ffebld expr);
+void ffestd_V023_finish (void);
+void ffestd_V024_start (void);
+void ffestd_V024_item (ffebld expr);
+void ffestd_V024_finish (void);
+void ffestd_V025_start (void);
+void ffestd_V025_item (ffebld u, ffebld m, ffebld n, ffebld asv);
+void ffestd_V025_finish (void);
+void ffestd_V026 (void);
+#endif
+void ffestd_V027_start (void);
+void ffestd_V027_item (ffelexToken dest_token, ffebld source);
+void ffestd_V027_finish (void);
+void ffestd_any (void);
+
+/* Define macros. */
+
+#define ffestd_init_0()
+#define ffestd_init_1()
+#define ffestd_init_2()
+#define ffestd_init_4()
+#define ffestd_labeldef_notloop(l) ffestd_labeldef_branch(l)
+#define ffestd_labeldef_endif(l) ffestd_labeldef_branch(l)
+#define ffestd_terminate_0()
+#define ffestd_terminate_1()
+#define ffestd_terminate_2()
+#define ffestd_terminate_3()
+#define ffestd_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/ste.c b/contrib/gcc/f/ste.c
new file mode 100644
index 0000000..4a2476d
--- /dev/null
+++ b/contrib/gcc/f/ste.c
@@ -0,0 +1,5419 @@
+/* ste.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ ste.c
+
+ Description:
+ Implements the various statements and such like.
+
+ Modifications:
+*/
+
+/* As of 0.5.4, any statement that calls on ffecom to transform an
+ expression might need to be wrapped in ffecom_push_calltemps ()
+ and ffecom_pop_calltemps () as are some other cases. That is
+ the case when the transformation might involve generation of
+ a temporary that must be auto-popped, the specific case being
+ when a COMPLEX operation requiring a call to libf2c being
+ generated, whereby a temp is needed to hold the result since
+ libf2c doesn't return COMPLEX results directly. Cases where it
+ is known that ffecom_expr () won't need to do this, such as
+ the CALL statement (where it's the transformation of the
+ call expr itself that does the wrapping), don't need to bother
+ with this wrapping. Forgetting to do the wrapping currently
+ means a crash at an assertion when the wrapping would be helpful
+ to keep temporaries from being wasted -- see ffecom_push_tempvar. */
+
+/* Include files. */
+
+#include "proj.h"
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#include "rtl.j"
+#include "toplev.j"
+#endif
+
+#include "ste.h"
+#include "bld.h"
+#include "com.h"
+#include "expr.h"
+#include "lab.h"
+#include "lex.h"
+#include "sta.h"
+#include "stp.h"
+#include "str.h"
+#include "sts.h"
+#include "stt.h"
+#include "stv.h"
+#include "stw.h"
+#include "symbol.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFESTE_stateletSIMPLE_, /* Expecting simple/start. */
+ FFESTE_stateletATTRIB_, /* Expecting attrib/item/itemstart. */
+ FFESTE_stateletITEM_, /* Expecting item/itemstart/finish. */
+ FFESTE_stateletITEMVALS_, /* Expecting itemvalue/itemendvals. */
+ FFESTE_
+ } ffesteStatelet_;
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+static ffesteStatelet_ ffeste_statelet_ = FFESTE_stateletSIMPLE_;
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static ffelab ffeste_label_formatdef_ = NULL;
+static tree (*ffeste_io_driver_) (ffebld expr); /* do?io. */
+static ffecomGfrt ffeste_io_endgfrt_; /* end function to call. */
+static tree ffeste_io_abort_; /* abort-io label or NULL_TREE. */
+static bool ffeste_io_abort_is_temp_; /* abort-io label is a temp. */
+static tree ffeste_io_end_; /* END= label or NULL_TREE. */
+static tree ffeste_io_err_; /* ERR= label or NULL_TREE. */
+static tree ffeste_io_iostat_; /* IOSTAT= var or NULL_TREE. */
+static bool ffeste_io_iostat_is_temp_; /* IOSTAT= var is a temp. */
+#endif
+
+/* Static functions (internal). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void ffeste_begin_iterdo_ (ffestw block, tree *tvar, tree *tincr,
+ tree *xitersvar, ffebld var,
+ ffebld start, ffelexToken start_token,
+ ffebld end, ffelexToken end_token,
+ ffebld incr, ffelexToken incr_token,
+ char *msg);
+static void ffeste_end_iterdo_ (tree tvar, tree tincr, tree itersvar);
+static void ffeste_io_call_ (tree call, bool do_check);
+static tree ffeste_io_dofio_ (ffebld expr);
+static tree ffeste_io_dolio_ (ffebld expr);
+static tree ffeste_io_douio_ (ffebld expr);
+static tree ffeste_io_ialist_ (bool have_err, ffestvUnit unit,
+ ffebld unit_expr, int unit_dflt);
+static tree ffeste_io_cilist_ (bool have_err, ffestvUnit unit,
+ ffebld unit_expr, int unit_dflt,
+ bool have_end, ffestvFormat format,
+ ffestpFile *format_spec, bool rec,
+ ffebld rec_expr);
+static tree ffeste_io_cllist_ (bool have_err, ffebld unit_expr,
+ ffestpFile *stat_spec);
+static tree ffeste_io_icilist_ (bool have_err, ffebld unit_expr,
+ bool have_end, ffestvFormat format,
+ ffestpFile *format_spec);
+static void ffeste_io_impdo_ (ffebld impdo, ffelexToken impdo_token);
+static tree ffeste_io_olist_ (bool have_err, ffebld unit_expr,
+ ffestpFile *file_spec,
+ ffestpFile *stat_spec,
+ ffestpFile *access_spec,
+ ffestpFile *form_spec,
+ ffestpFile *recl_spec,
+ ffestpFile *blank_spec);
+static void ffeste_subr_beru_ (ffestpBeruStmt *info, ffecomGfrt rt);
+#elif FFECOM_targetCURRENT == FFECOM_targetFFE
+static void ffeste_subr_file_ (char *kw, ffestpFile *spec);
+#else
+#error
+#endif
+
+/* Internal macros. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define ffeste_emit_line_note_() \
+ emit_line_note (input_filename, lineno)
+#endif
+#define ffeste_check_simple_() \
+ assert(ffeste_statelet_ == FFESTE_stateletSIMPLE_)
+#define ffeste_check_start_() \
+ assert(ffeste_statelet_ == FFESTE_stateletSIMPLE_); \
+ ffeste_statelet_ = FFESTE_stateletATTRIB_
+#define ffeste_check_attrib_() \
+ assert(ffeste_statelet_ == FFESTE_stateletATTRIB_)
+#define ffeste_check_item_() \
+ assert(ffeste_statelet_ == FFESTE_stateletATTRIB_ \
+ || ffeste_statelet_ == FFESTE_stateletITEM_); \
+ ffeste_statelet_ = FFESTE_stateletITEM_
+#define ffeste_check_item_startvals_() \
+ assert(ffeste_statelet_ == FFESTE_stateletATTRIB_ \
+ || ffeste_statelet_ == FFESTE_stateletITEM_); \
+ ffeste_statelet_ = FFESTE_stateletITEMVALS_
+#define ffeste_check_item_value_() \
+ assert(ffeste_statelet_ == FFESTE_stateletITEMVALS_)
+#define ffeste_check_item_endvals_() \
+ assert(ffeste_statelet_ == FFESTE_stateletITEMVALS_); \
+ ffeste_statelet_ = FFESTE_stateletITEM_
+#define ffeste_check_finish_() \
+ assert(ffeste_statelet_ == FFESTE_stateletATTRIB_ \
+ || ffeste_statelet_ == FFESTE_stateletITEM_); \
+ ffeste_statelet_ = FFESTE_stateletSIMPLE_
+
+#define ffeste_f2c_charnolenspec_(Spec,Exp,Init) \
+ do \
+ { \
+ if (Spec->kw_or_val_present) \
+ Exp = ffecom_arg_ptr_to_expr(Spec->u.expr,&ignore); \
+ else \
+ Exp = null_pointer_node; \
+ if (TREE_CONSTANT(Exp)) \
+ { \
+ Init = Exp; \
+ Exp = NULL_TREE; \
+ } \
+ else \
+ { \
+ Init = null_pointer_node; \
+ constantp = FALSE; \
+ } \
+ } while(0)
+
+#define ffeste_f2c_charspec_(Spec,Exp,Init,Lenexp,Leninit) \
+ do \
+ { \
+ if (Spec->kw_or_val_present) \
+ Exp = ffecom_arg_ptr_to_expr(Spec->u.expr,&Lenexp); \
+ else \
+ { \
+ Exp = null_pointer_node; \
+ Lenexp = ffecom_f2c_ftnlen_zero_node; \
+ } \
+ if (TREE_CONSTANT(Exp)) \
+ { \
+ Init = Exp; \
+ Exp = NULL_TREE; \
+ } \
+ else \
+ { \
+ Init = null_pointer_node; \
+ constantp = FALSE; \
+ } \
+ if ((Lenexp != NULL_TREE) && TREE_CONSTANT(Lenexp)) \
+ { \
+ Leninit = Lenexp; \
+ Lenexp = NULL_TREE; \
+ } \
+ else \
+ { \
+ Leninit = ffecom_f2c_ftnlen_zero_node; \
+ constantp = FALSE; \
+ } \
+ } while(0)
+
+#define ffeste_f2c_exp_(Field,Exp) \
+ do \
+ { \
+ if (Exp != NULL_TREE) \
+ { \
+ Exp = ffecom_modify(void_type_node,ffecom_2(COMPONENT_REF, \
+ TREE_TYPE(Field),t,Field),Exp); \
+ expand_expr_stmt(Exp); \
+ } \
+ } while(0)
+
+#define ffeste_f2c_init_(Init) \
+ do \
+ { \
+ TREE_CHAIN(initn) = build_tree_list((field = TREE_CHAIN(field)),Init); \
+ initn = TREE_CHAIN(initn); \
+ } while(0)
+
+#define ffeste_f2c_flagspec_(Flag,Init) \
+ do { Init = convert (ffecom_f2c_flag_type_node, \
+ Flag ? integer_one_node : integer_zero_node); } \
+ while(0)
+
+#define ffeste_f2c_intspec_(Spec,Exp,Init) \
+ do \
+ { \
+ if (Spec->kw_or_val_present) \
+ Exp = ffecom_expr(Spec->u.expr); \
+ else \
+ Exp = ffecom_integer_zero_node; \
+ if (TREE_CONSTANT(Exp)) \
+ { \
+ Init = Exp; \
+ Exp = NULL_TREE; \
+ } \
+ else \
+ { \
+ Init = ffecom_integer_zero_node; \
+ constantp = FALSE; \
+ } \
+ } while(0)
+
+#define ffeste_f2c_ptrtointspec_(Spec,Exp,Init) \
+ do \
+ { \
+ if (Spec->kw_or_val_present) \
+ Exp = ffecom_ptr_to_expr(Spec->u.expr); \
+ else \
+ Exp = null_pointer_node; \
+ if (TREE_CONSTANT(Exp)) \
+ { \
+ Init = Exp; \
+ Exp = NULL_TREE; \
+ } \
+ else \
+ { \
+ Init = null_pointer_node; \
+ constantp = FALSE; \
+ } \
+ } while(0)
+
+
+/* Begin an iterative DO loop. Pass the block to start if applicable.
+
+ NOTE: Does _two_ push_momentary () calls, which the caller must
+ undo (by calling ffeste_end_iterdo_). */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffeste_begin_iterdo_ (ffestw block, tree *xtvar, tree *xtincr,
+ tree *xitersvar, ffebld var,
+ ffebld start, ffelexToken start_token,
+ ffebld end, ffelexToken end_token,
+ ffebld incr, ffelexToken incr_token,
+ char *msg)
+{
+ tree tvar;
+ tree expr;
+ tree tstart;
+ tree tend;
+ tree tincr;
+ tree tincr_saved;
+ tree niters;
+
+ push_momentary (); /* Want to save these throughout the loop. */
+
+ tvar = ffecom_expr_rw (var);
+ tincr = ffecom_expr (incr);
+
+ /* Check whether incr is known to be zero, complain and fix. */
+
+ if (integer_zerop (tincr) || real_zerop (tincr))
+ {
+ ffebad_start (FFEBAD_DO_STEP_ZERO);
+ ffebad_here (0, ffelex_token_where_line (incr_token),
+ ffelex_token_where_column (incr_token));
+ ffebad_string (msg);
+ ffebad_finish ();
+ tincr = convert (TREE_TYPE (tvar), integer_one_node);
+ }
+
+ tincr_saved = ffecom_save_tree (tincr);
+
+ push_momentary (); /* Want to discard the rest after the loop. */
+
+ tstart = ffecom_expr (start);
+ tend = ffecom_expr (end);
+
+ { /* For warnings only, nothing else
+ happens here. */
+ tree try;
+
+ if (!ffe_is_onetrip ())
+ {
+ try = ffecom_2 (MINUS_EXPR, TREE_TYPE (tvar),
+ tend,
+ tstart);
+
+ try = ffecom_2 (PLUS_EXPR, TREE_TYPE (tvar),
+ try,
+ tincr);
+
+ if (TREE_CODE (TREE_TYPE (tvar)) != REAL_TYPE)
+ try = ffecom_2 (TRUNC_DIV_EXPR, integer_type_node, try,
+ tincr);
+ else
+ try = convert (integer_type_node,
+ ffecom_2 (RDIV_EXPR, TREE_TYPE (tvar),
+ try,
+ tincr));
+
+ /* Warn if loop never executed, since we've done the evaluation
+ of the unofficial iteration count already. */
+
+ try = ffecom_truth_value (ffecom_2 (LE_EXPR, integer_type_node,
+ try,
+ convert (TREE_TYPE (tvar),
+ integer_zero_node)));
+
+ if (integer_onep (try))
+ {
+ ffebad_start (FFEBAD_DO_NULL);
+ ffebad_here (0, ffelex_token_where_line (start_token),
+ ffelex_token_where_column (start_token));
+ ffebad_string (msg);
+ ffebad_finish ();
+ }
+ }
+
+ /* Warn if end plus incr would overflow. */
+
+ try = ffecom_2 (PLUS_EXPR, TREE_TYPE (tvar),
+ tend,
+ tincr);
+
+ if ((TREE_CODE_CLASS (TREE_CODE (try)) == 'c')
+ && TREE_CONSTANT_OVERFLOW (try))
+ {
+ ffebad_start (FFEBAD_DO_END_OVERFLOW);
+ ffebad_here (0, ffelex_token_where_line (end_token),
+ ffelex_token_where_column (end_token));
+ ffebad_string (msg);
+ ffebad_finish ();
+ }
+ }
+
+ /* Do the initial assignment into the DO var. */
+
+ tstart = ffecom_save_tree (tstart);
+
+ expr = ffecom_2 (MINUS_EXPR, TREE_TYPE (tvar),
+ tend,
+ tstart);
+
+ if (!ffe_is_onetrip ())
+ {
+ expr = ffecom_2 (PLUS_EXPR, TREE_TYPE (expr),
+ expr,
+ convert (TREE_TYPE (expr), tincr_saved));
+ }
+
+ if (TREE_CODE (TREE_TYPE (tvar)) != REAL_TYPE)
+ expr = ffecom_2 (TRUNC_DIV_EXPR, TREE_TYPE (expr),
+ expr,
+ tincr_saved);
+ else
+ expr = ffecom_2 (RDIV_EXPR, TREE_TYPE (expr),
+ expr,
+ tincr_saved);
+
+#if 1 /* New, F90-approved approach: convert to default INTEGER. */
+ if (TREE_TYPE (tvar) != error_mark_node)
+ expr = convert (ffecom_integer_type_node, expr);
+#else /* Old approach; convert to INTEGER unless that's a narrowing. */
+ if ((TREE_TYPE (tvar) != error_mark_node)
+ && ((TREE_CODE (TREE_TYPE (tvar)) != INTEGER_TYPE)
+ || ((TYPE_SIZE (TREE_TYPE (tvar)) != NULL_TREE)
+ && ((TREE_CODE (TYPE_SIZE (TREE_TYPE (tvar)))
+ != INTEGER_CST)
+ || (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tvar)))
+ <= TREE_INT_CST_LOW (TYPE_SIZE (ffecom_integer_type_node)))))))
+ /* Convert unless promoting INTEGER type of any kind downward to
+ default INTEGER; else leave as, say, INTEGER*8 (long long int). */
+ expr = convert (ffecom_integer_type_node, expr);
+#endif
+
+ niters = ffecom_push_tempvar (TREE_TYPE (expr),
+ FFETARGET_charactersizeNONE, -1, FALSE);
+ expr = ffecom_modify (void_type_node, niters, expr);
+ expand_expr_stmt (expr);
+
+ expr = ffecom_modify (void_type_node, tvar, tstart);
+ expand_expr_stmt (expr);
+
+ if (block == NULL)
+ expand_start_loop_continue_elsewhere (0);
+ else
+ ffestw_set_do_hook (block,
+ expand_start_loop_continue_elsewhere (1));
+
+ if (!ffe_is_onetrip ())
+ {
+ expr = ffecom_truth_value
+ (ffecom_2 (GE_EXPR, integer_type_node,
+ ffecom_2 (PREDECREMENT_EXPR,
+ TREE_TYPE (niters),
+ niters,
+ convert (TREE_TYPE (niters),
+ ffecom_integer_one_node)),
+ convert (TREE_TYPE (niters),
+ ffecom_integer_zero_node)));
+
+ expand_exit_loop_if_false (0, expr);
+ }
+
+ clear_momentary (); /* Discard the above now that we're done with
+ DO stmt. */
+
+ if (block == NULL)
+ {
+ *xtvar = tvar;
+ *xtincr = tincr_saved;
+ *xitersvar = niters;
+ }
+ else
+ {
+ ffestw_set_do_tvar (block, tvar);
+ ffestw_set_do_incr_saved (block, tincr_saved);
+ ffestw_set_do_count_var (block, niters);
+ }
+}
+
+#endif
+
+/* End an iterative DO loop. Pass the same iteration variable and increment
+ value trees that were generated in the paired _begin_ call. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffeste_end_iterdo_ (tree tvar, tree tincr, tree itersvar)
+{
+ tree expr;
+ tree niters = itersvar;
+
+ expand_loop_continue_here ();
+
+ if (ffe_is_onetrip ())
+ {
+ expr = ffecom_truth_value
+ (ffecom_2 (GE_EXPR, integer_type_node,
+ ffecom_2 (PREDECREMENT_EXPR,
+ TREE_TYPE (niters),
+ niters,
+ convert (TREE_TYPE (niters),
+ ffecom_integer_one_node)),
+ convert (TREE_TYPE (niters),
+ ffecom_integer_zero_node)));
+
+ expand_exit_loop_if_false (0, expr);
+ }
+
+ expr = ffecom_modify (void_type_node, tvar,
+ ffecom_2 (PLUS_EXPR, TREE_TYPE (tvar),
+ tvar,
+ tincr));
+ expand_expr_stmt (expr);
+ expand_end_loop ();
+
+ ffecom_pop_tempvar (itersvar); /* Free #iters var. */
+
+ clear_momentary ();
+ pop_momentary (); /* Lose the stuff we just built. */
+
+ clear_momentary ();
+ pop_momentary (); /* Lose the tvar and incr_saved trees. */
+}
+
+#endif
+/* ffeste_io_call_ -- Generate call to run-time I/O routine
+
+ tree callexpr = build(CALL_EXPR,...);
+ ffeste_io_call_(callexpr,TRUE);
+
+ Sets TREE_SIDE_EFFECTS(callexpr) = 1. If ffeste_io_iostat_ is not
+ NULL_TREE, replaces callexpr with "iostat = callexpr;". Expands the
+ result. If ffeste_io_abort_ is not NULL_TREE and the second argument
+ is TRUE, generates "if (iostat != 0) goto ffeste_io_abort_;". */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffeste_io_call_ (tree call, bool do_check)
+{
+ /* Generate the call and optional assignment into iostat var. */
+
+ TREE_SIDE_EFFECTS (call) = 1;
+ if (ffeste_io_iostat_ != NULL_TREE)
+ {
+ call = ffecom_modify (do_check ? NULL_TREE : void_type_node,
+ ffeste_io_iostat_, call);
+ }
+ expand_expr_stmt (call);
+
+ if (!do_check
+ || (ffeste_io_abort_ == NULL_TREE)
+ || (TREE_CODE (ffeste_io_abort_) == ERROR_MARK))
+ return;
+
+ /* Generate optional test. */
+
+ expand_start_cond (ffecom_truth_value (ffeste_io_iostat_), 0);
+ expand_goto (ffeste_io_abort_);
+ expand_end_cond ();
+}
+
+#endif
+/* ffeste_io_dofio_ -- Generate call to do_fio for formatted I/O item
+
+ ffebld expr;
+ tree call;
+ call = ffeste_io_dofio_(expr);
+
+ Returns a tree for a CALL_EXPR to the do_fio function, which handles
+ a formatted I/O list item, along with the appropriate arguments for
+ the function. It is up to the caller to set the TREE_SIDE_EFFECTS flag
+ for the CALL_EXPR, expand (emit) the expression, emit any assignment
+ of the result to an IOSTAT= variable, and emit any checking of the
+ result for errors. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffeste_io_dofio_ (ffebld expr)
+{
+ tree num_elements;
+ tree variable;
+ tree size;
+ tree arglist;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ bool is_complex;
+
+ bt = ffeinfo_basictype (ffebld_info (expr));
+ kt = ffeinfo_kindtype (ffebld_info (expr));
+
+ if ((bt == FFEINFO_basictypeANY)
+ || (kt == FFEINFO_kindtypeANY))
+ return error_mark_node;
+
+ if (bt == FFEINFO_basictypeCOMPLEX)
+ {
+ is_complex = TRUE;
+ bt = FFEINFO_basictypeREAL;
+ }
+ else
+ is_complex = FALSE;
+
+ ffecom_push_calltemps ();
+
+ variable = ffecom_arg_ptr_to_expr (expr, &size);
+
+ if ((variable == error_mark_node)
+ || (size == error_mark_node))
+ {
+ ffecom_pop_calltemps ();
+ return error_mark_node;
+ }
+
+ if (size == NULL_TREE) /* Already filled in for CHARACTER type. */
+ { /* "(ftnlen) sizeof(type)" */
+ size = size_binop (CEIL_DIV_EXPR,
+ TYPE_SIZE (ffecom_tree_type[bt][kt]),
+ size_int (TYPE_PRECISION (char_type_node)));
+#if 0 /* Assume that while it is possible that char * is wider than
+ ftnlen, no object in Fortran space can get big enough for its
+ size to be wider than ftnlen. I really hope nobody wastes
+ time debugging a case where it can! */
+ assert (TYPE_PRECISION (ffecom_f2c_ftnlen_type_node)
+ >= TYPE_PRECISION (TREE_TYPE (size)));
+#endif
+ size = convert (ffecom_f2c_ftnlen_type_node, size);
+ }
+
+ if ((ffeinfo_rank (ffebld_info (expr)) == 0)
+ || (TREE_CODE (TREE_TYPE (TREE_TYPE (variable))) != ARRAY_TYPE))
+ num_elements = is_complex ? ffecom_f2c_ftnlen_two_node
+ : ffecom_f2c_ftnlen_one_node;
+ else
+ {
+ num_elements = size_binop (CEIL_DIV_EXPR,
+ TYPE_SIZE (TREE_TYPE (TREE_TYPE (variable))), size);
+ num_elements = size_binop (CEIL_DIV_EXPR,
+ num_elements,
+ size_int (TYPE_PRECISION
+ (char_type_node)));
+ num_elements = convert (ffecom_f2c_ftnlen_type_node,
+ num_elements);
+ }
+
+ num_elements
+ = ffecom_1 (ADDR_EXPR, ffecom_f2c_ptr_to_ftnlen_type_node,
+ num_elements);
+
+ variable = convert (string_type_node, variable);
+
+ arglist = build_tree_list (NULL_TREE, num_elements);
+ TREE_CHAIN (arglist) = build_tree_list (NULL_TREE, variable);
+ TREE_CHAIN (TREE_CHAIN (arglist)) = build_tree_list (NULL_TREE, size);
+
+ ffecom_pop_calltemps ();
+
+ return ffecom_call_gfrt (FFECOM_gfrtDOFIO, arglist);
+}
+
+#endif
+/* ffeste_io_dolio_ -- Generate call to do_lio for list-directed I/O item
+
+ ffebld expr;
+ tree call;
+ call = ffeste_io_dolio_(expr);
+
+ Returns a tree for a CALL_EXPR to the do_lio function, which handles
+ a list-directed I/O list item, along with the appropriate arguments for
+ the function. It is up to the caller to set the TREE_SIDE_EFFECTS flag
+ for the CALL_EXPR, expand (emit) the expression, emit any assignment
+ of the result to an IOSTAT= variable, and emit any checking of the
+ result for errors. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffeste_io_dolio_ (ffebld expr)
+{
+ tree type_id;
+ tree num_elements;
+ tree variable;
+ tree size;
+ tree arglist;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ int tc;
+
+ bt = ffeinfo_basictype (ffebld_info (expr));
+ kt = ffeinfo_kindtype (ffebld_info (expr));
+
+ if ((bt == FFEINFO_basictypeANY)
+ || (kt == FFEINFO_kindtypeANY))
+ return error_mark_node;
+
+ ffecom_push_calltemps ();
+
+ tc = ffecom_f2c_typecode (bt, kt);
+ assert (tc != -1);
+ type_id = build_int_2 (tc, 0);
+
+ type_id
+ = ffecom_1 (ADDR_EXPR, ffecom_f2c_ptr_to_ftnint_type_node,
+ convert (ffecom_f2c_ftnint_type_node,
+ type_id));
+
+ variable = ffecom_arg_ptr_to_expr (expr, &size);
+
+ if ((type_id == error_mark_node)
+ || (variable == error_mark_node)
+ || (size == error_mark_node))
+ {
+ ffecom_pop_calltemps ();
+ return error_mark_node;
+ }
+
+ if (size == NULL_TREE) /* Already filled in for CHARACTER type. */
+ { /* "(ftnlen) sizeof(type)" */
+ size = size_binop (CEIL_DIV_EXPR,
+ TYPE_SIZE (ffecom_tree_type[bt][kt]),
+ size_int (TYPE_PRECISION (char_type_node)));
+#if 0 /* Assume that while it is possible that char * is wider than
+ ftnlen, no object in Fortran space can get big enough for its
+ size to be wider than ftnlen. I really hope nobody wastes
+ time debugging a case where it can! */
+ assert (TYPE_PRECISION (ffecom_f2c_ftnlen_type_node)
+ >= TYPE_PRECISION (TREE_TYPE (size)));
+#endif
+ size = convert (ffecom_f2c_ftnlen_type_node, size);
+ }
+
+ if ((ffeinfo_rank (ffebld_info (expr)) == 0)
+ || (TREE_CODE (TREE_TYPE (TREE_TYPE (variable))) != ARRAY_TYPE))
+ num_elements = ffecom_integer_one_node;
+ else
+ {
+ num_elements = size_binop (CEIL_DIV_EXPR,
+ TYPE_SIZE (TREE_TYPE (TREE_TYPE (variable))), size);
+ num_elements = size_binop (CEIL_DIV_EXPR,
+ num_elements,
+ size_int (TYPE_PRECISION
+ (char_type_node)));
+ num_elements = convert (ffecom_f2c_ftnlen_type_node,
+ num_elements);
+ }
+
+ num_elements
+ = ffecom_1 (ADDR_EXPR, ffecom_f2c_ptr_to_ftnlen_type_node,
+ num_elements);
+
+ variable = convert (string_type_node, variable);
+
+ arglist = build_tree_list (NULL_TREE, type_id);
+ TREE_CHAIN (arglist) = build_tree_list (NULL_TREE, num_elements);
+ TREE_CHAIN (TREE_CHAIN (arglist)) = build_tree_list (NULL_TREE, variable);
+ TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist)))
+ = build_tree_list (NULL_TREE, size);
+
+ ffecom_pop_calltemps ();
+
+ return ffecom_call_gfrt (FFECOM_gfrtDOLIO, arglist);
+}
+
+#endif
+/* ffeste_io_douio_ -- Generate call to do_uio for unformatted I/O item
+
+ ffebld expr;
+ tree call;
+ call = ffeste_io_douio_(expr);
+
+ Returns a tree for a CALL_EXPR to the do_uio function, which handles
+ an unformatted I/O list item, along with the appropriate arguments for
+ the function. It is up to the caller to set the TREE_SIDE_EFFECTS flag
+ for the CALL_EXPR, expand (emit) the expression, emit any assignment
+ of the result to an IOSTAT= variable, and emit any checking of the
+ result for errors. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffeste_io_douio_ (ffebld expr)
+{
+ tree num_elements;
+ tree variable;
+ tree size;
+ tree arglist;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ bool is_complex;
+
+ bt = ffeinfo_basictype (ffebld_info (expr));
+ kt = ffeinfo_kindtype (ffebld_info (expr));
+
+ if ((bt == FFEINFO_basictypeANY)
+ || (kt == FFEINFO_kindtypeANY))
+ return error_mark_node;
+
+ if (bt == FFEINFO_basictypeCOMPLEX)
+ {
+ is_complex = TRUE;
+ bt = FFEINFO_basictypeREAL;
+ }
+ else
+ is_complex = FALSE;
+
+ ffecom_push_calltemps ();
+
+ variable = ffecom_arg_ptr_to_expr (expr, &size);
+
+ if ((variable == error_mark_node)
+ || (size == error_mark_node))
+ {
+ ffecom_pop_calltemps ();
+ return error_mark_node;
+ }
+
+ if (size == NULL_TREE) /* Already filled in for CHARACTER type. */
+ { /* "(ftnlen) sizeof(type)" */
+ size = size_binop (CEIL_DIV_EXPR,
+ TYPE_SIZE (ffecom_tree_type[bt][kt]),
+ size_int (TYPE_PRECISION (char_type_node)));
+#if 0 /* Assume that while it is possible that char * is wider than
+ ftnlen, no object in Fortran space can get big enough for its
+ size to be wider than ftnlen. I really hope nobody wastes
+ time debugging a case where it can! */
+ assert (TYPE_PRECISION (ffecom_f2c_ftnlen_type_node)
+ >= TYPE_PRECISION (TREE_TYPE (size)));
+#endif
+ size = convert (ffecom_f2c_ftnlen_type_node, size);
+ }
+
+ if ((ffeinfo_rank (ffebld_info (expr)) == 0)
+ || (TREE_CODE (TREE_TYPE (TREE_TYPE (variable))) != ARRAY_TYPE))
+ num_elements = is_complex ? ffecom_f2c_ftnlen_two_node
+ : ffecom_f2c_ftnlen_one_node;
+ else
+ {
+ num_elements = size_binop (CEIL_DIV_EXPR,
+ TYPE_SIZE (TREE_TYPE (TREE_TYPE (variable))), size);
+ num_elements = size_binop (CEIL_DIV_EXPR, num_elements,
+ size_int (TYPE_PRECISION
+ (char_type_node)));
+ num_elements = convert (ffecom_f2c_ftnlen_type_node,
+ num_elements);
+ }
+
+ num_elements
+ = ffecom_1 (ADDR_EXPR, ffecom_f2c_ptr_to_ftnlen_type_node,
+ num_elements);
+
+ variable = convert (string_type_node, variable);
+
+ arglist = build_tree_list (NULL_TREE, num_elements);
+ TREE_CHAIN (arglist) = build_tree_list (NULL_TREE, variable);
+ TREE_CHAIN (TREE_CHAIN (arglist)) = build_tree_list (NULL_TREE, size);
+
+ ffecom_pop_calltemps ();
+
+ return ffecom_call_gfrt (FFECOM_gfrtDOUIO, arglist);
+}
+
+#endif
+/* ffeste_io_ialist_ -- Make arglist with ptr to B/E/R control list
+
+ tree arglist;
+ arglist = ffeste_io_ialist_(...);
+
+ Returns a tree suitable as an argument list containing a pointer to
+ a BACKSPACE/ENDFILE/REWIND control list. First, generates that control
+ list, if necessary, along with any static and run-time initializations
+ that are needed as specified by the arguments to this function. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffeste_io_ialist_ (bool have_err,
+ ffestvUnit unit,
+ ffebld unit_expr,
+ int unit_dflt)
+{
+ static tree f2c_alist_struct = NULL_TREE;
+ tree t;
+ tree ttype;
+ int yes;
+ tree field;
+ tree inits, initn;
+ bool constantp = TRUE;
+ static tree errfield, unitfield;
+ tree errinit, unitinit;
+ tree unitexp;
+ static int mynumber = 0;
+
+ if (f2c_alist_struct == NULL_TREE)
+ {
+ tree ref;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ ref = make_node (RECORD_TYPE);
+
+ errfield = ffecom_decl_field (ref, NULL_TREE, "err",
+ ffecom_f2c_flag_type_node);
+ unitfield = ffecom_decl_field (ref, errfield, "unit",
+ ffecom_f2c_ftnint_type_node);
+
+ TYPE_FIELDS (ref) = errfield;
+ layout_type (ref);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ f2c_alist_struct = ref;
+ }
+
+ ffeste_f2c_flagspec_ (have_err, errinit);
+
+ switch (unit)
+ {
+ case FFESTV_unitNONE:
+ case FFESTV_unitASTERISK:
+ unitinit = build_int_2 (unit_dflt, 0);
+ unitexp = NULL_TREE;
+ break;
+
+ case FFESTV_unitINTEXPR:
+ unitexp = ffecom_expr (unit_expr);
+ if (TREE_CONSTANT (unitexp))
+ {
+ unitinit = unitexp;
+ unitexp = NULL_TREE;
+ }
+ else
+ {
+ unitinit = ffecom_integer_zero_node;
+ constantp = FALSE;
+ }
+ break;
+
+ default:
+ assert ("bad unit spec" == NULL);
+ unitexp = NULL_TREE;
+ unitinit = ffecom_integer_zero_node;
+ break;
+ }
+
+ inits = build_tree_list ((field = TYPE_FIELDS (f2c_alist_struct)), errinit);
+ initn = inits;
+ ffeste_f2c_init_ (unitinit);
+
+ inits = build (CONSTRUCTOR, f2c_alist_struct, NULL_TREE, inits);
+ TREE_CONSTANT (inits) = constantp ? 1 : 0;
+ TREE_STATIC (inits) = 1;
+
+ yes = suspend_momentary ();
+
+ t = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_alist_%d", NULL,
+ mynumber++),
+ f2c_alist_struct);
+ TREE_STATIC (t) = 1;
+ t = ffecom_start_decl (t, 1);
+ ffecom_finish_decl (t, inits, 0);
+
+ resume_momentary (yes);
+
+ ffeste_f2c_exp_ (unitfield, unitexp);
+
+ ttype = build_pointer_type (TREE_TYPE (t));
+ t = ffecom_1 (ADDR_EXPR, ttype, t);
+
+ t = build_tree_list (NULL_TREE, t);
+
+ return t;
+}
+
+#endif
+/* ffeste_io_cilist_ -- Make arglist with ptr to external I/O control list
+
+ tree arglist;
+ arglist = ffeste_io_cilist_(...);
+
+ Returns a tree suitable as an argument list containing a pointer to
+ an external-file I/O control list. First, generates that control
+ list, if necessary, along with any static and run-time initializations
+ that are needed as specified by the arguments to this function. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffeste_io_cilist_ (bool have_err,
+ ffestvUnit unit,
+ ffebld unit_expr,
+ int unit_dflt,
+ bool have_end,
+ ffestvFormat format,
+ ffestpFile *format_spec,
+ bool rec,
+ ffebld rec_expr)
+{
+ static tree f2c_cilist_struct = NULL_TREE;
+ tree t;
+ tree ttype;
+ int yes;
+ tree field;
+ tree inits, initn;
+ bool constantp = TRUE;
+ static tree errfield, unitfield, endfield, formatfield, recfield;
+ tree errinit, unitinit, endinit, formatinit, recinit;
+ tree unitexp, formatexp, recexp;
+ static int mynumber = 0;
+
+ if (f2c_cilist_struct == NULL_TREE)
+ {
+ tree ref;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ ref = make_node (RECORD_TYPE);
+
+ errfield = ffecom_decl_field (ref, NULL_TREE, "err",
+ ffecom_f2c_flag_type_node);
+ unitfield = ffecom_decl_field (ref, errfield, "unit",
+ ffecom_f2c_ftnint_type_node);
+ endfield = ffecom_decl_field (ref, unitfield, "end",
+ ffecom_f2c_flag_type_node);
+ formatfield = ffecom_decl_field (ref, endfield, "format",
+ string_type_node);
+ recfield = ffecom_decl_field (ref, formatfield, "rec",
+ ffecom_f2c_ftnint_type_node);
+
+ TYPE_FIELDS (ref) = errfield;
+ layout_type (ref);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ f2c_cilist_struct = ref;
+ }
+
+ ffeste_f2c_flagspec_ (have_err, errinit);
+
+ switch (unit)
+ {
+ case FFESTV_unitNONE:
+ case FFESTV_unitASTERISK:
+ unitinit = build_int_2 (unit_dflt, 0);
+ unitexp = NULL_TREE;
+ break;
+
+ case FFESTV_unitINTEXPR:
+ unitexp = ffecom_expr (unit_expr);
+ if (TREE_CONSTANT (unitexp))
+ {
+ unitinit = unitexp;
+ unitexp = NULL_TREE;
+ }
+ else
+ {
+ unitinit = ffecom_integer_zero_node;
+ constantp = FALSE;
+ }
+ break;
+
+ default:
+ assert ("bad unit spec" == NULL);
+ unitexp = NULL_TREE;
+ unitinit = ffecom_integer_zero_node;
+ break;
+ }
+
+ switch (format)
+ {
+ case FFESTV_formatNONE:
+ formatinit = null_pointer_node;
+ formatexp = NULL_TREE;
+ break;
+
+ case FFESTV_formatLABEL:
+ formatexp = NULL_TREE;
+ formatinit = ffecom_lookup_label (format_spec->u.label);
+ if ((formatinit == NULL_TREE)
+ || (TREE_CODE (formatinit) == ERROR_MARK))
+ break;
+ formatinit = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (void_type_node),
+ formatinit);
+ TREE_CONSTANT (formatinit) = 1;
+ break;
+
+ case FFESTV_formatCHAREXPR:
+ formatexp = ffecom_arg_ptr_to_expr (format_spec->u.expr, NULL);
+ if (TREE_CONSTANT (formatexp))
+ {
+ formatinit = formatexp;
+ formatexp = NULL_TREE;
+ }
+ else
+ {
+ formatinit = null_pointer_node;
+ constantp = FALSE;
+ }
+ break;
+
+ case FFESTV_formatASTERISK:
+ formatinit = null_pointer_node;
+ formatexp = NULL_TREE;
+ break;
+
+ case FFESTV_formatINTEXPR:
+ formatinit = null_pointer_node;
+ formatexp = ffecom_expr_assign (format_spec->u.expr);
+ if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (formatexp)))
+ < GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (null_pointer_node))))
+ error ("ASSIGNed FORMAT specifier is too small");
+ formatexp = convert (string_type_node, formatexp);
+ break;
+
+ case FFESTV_formatNAMELIST:
+ formatinit = ffecom_expr (format_spec->u.expr);
+ formatexp = NULL_TREE;
+ break;
+
+ default:
+ assert ("bad format spec" == NULL);
+ formatexp = NULL_TREE;
+ formatinit = integer_zero_node;
+ break;
+ }
+
+ ffeste_f2c_flagspec_ (have_end, endinit);
+
+ if (rec)
+ recexp = ffecom_expr (rec_expr);
+ else
+ recexp = ffecom_integer_zero_node;
+ if (TREE_CONSTANT (recexp))
+ {
+ recinit = recexp;
+ recexp = NULL_TREE;
+ }
+ else
+ {
+ recinit = ffecom_integer_zero_node;
+ constantp = FALSE;
+ }
+
+ inits = build_tree_list ((field = TYPE_FIELDS (f2c_cilist_struct)), errinit);
+ initn = inits;
+ ffeste_f2c_init_ (unitinit);
+ ffeste_f2c_init_ (endinit);
+ ffeste_f2c_init_ (formatinit);
+ ffeste_f2c_init_ (recinit);
+
+ inits = build (CONSTRUCTOR, f2c_cilist_struct, NULL_TREE, inits);
+ TREE_CONSTANT (inits) = constantp ? 1 : 0;
+ TREE_STATIC (inits) = 1;
+
+ yes = suspend_momentary ();
+
+ t = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_cilist_%d", NULL,
+ mynumber++),
+ f2c_cilist_struct);
+ TREE_STATIC (t) = 1;
+ t = ffecom_start_decl (t, 1);
+ ffecom_finish_decl (t, inits, 0);
+
+ resume_momentary (yes);
+
+ ffeste_f2c_exp_ (unitfield, unitexp);
+ ffeste_f2c_exp_ (formatfield, formatexp);
+ ffeste_f2c_exp_ (recfield, recexp);
+
+ ttype = build_pointer_type (TREE_TYPE (t));
+ t = ffecom_1 (ADDR_EXPR, ttype, t);
+
+ t = build_tree_list (NULL_TREE, t);
+
+ return t;
+}
+
+#endif
+/* ffeste_io_cllist_ -- Make arglist with ptr to CLOSE control list
+
+ tree arglist;
+ arglist = ffeste_io_cllist_(...);
+
+ Returns a tree suitable as an argument list containing a pointer to
+ a CLOSE-statement control list. First, generates that control
+ list, if necessary, along with any static and run-time initializations
+ that are needed as specified by the arguments to this function. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffeste_io_cllist_ (bool have_err,
+ ffebld unit_expr,
+ ffestpFile *stat_spec)
+{
+ static tree f2c_close_struct = NULL_TREE;
+ tree t;
+ tree ttype;
+ int yes;
+ tree field;
+ tree inits, initn;
+ tree ignore; /* Ignore length info for certain fields. */
+ bool constantp = TRUE;
+ static tree errfield, unitfield, statfield;
+ tree errinit, unitinit, statinit;
+ tree unitexp, statexp;
+ static int mynumber = 0;
+
+ if (f2c_close_struct == NULL_TREE)
+ {
+ tree ref;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ ref = make_node (RECORD_TYPE);
+
+ errfield = ffecom_decl_field (ref, NULL_TREE, "err",
+ ffecom_f2c_flag_type_node);
+ unitfield = ffecom_decl_field (ref, errfield, "unit",
+ ffecom_f2c_ftnint_type_node);
+ statfield = ffecom_decl_field (ref, unitfield, "stat",
+ string_type_node);
+
+ TYPE_FIELDS (ref) = errfield;
+ layout_type (ref);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ f2c_close_struct = ref;
+ }
+
+ ffeste_f2c_flagspec_ (have_err, errinit);
+
+ unitexp = ffecom_expr (unit_expr);
+ if (TREE_CONSTANT (unitexp))
+ {
+ unitinit = unitexp;
+ unitexp = NULL_TREE;
+ }
+ else
+ {
+ unitinit = ffecom_integer_zero_node;
+ constantp = FALSE;
+ }
+
+ ffeste_f2c_charnolenspec_ (stat_spec, statexp, statinit);
+
+ inits = build_tree_list ((field = TYPE_FIELDS (f2c_close_struct)), errinit);
+ initn = inits;
+ ffeste_f2c_init_ (unitinit);
+ ffeste_f2c_init_ (statinit);
+
+ inits = build (CONSTRUCTOR, f2c_close_struct, NULL_TREE, inits);
+ TREE_CONSTANT (inits) = constantp ? 1 : 0;
+ TREE_STATIC (inits) = 1;
+
+ yes = suspend_momentary ();
+
+ t = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_cllist_%d", NULL,
+ mynumber++),
+ f2c_close_struct);
+ TREE_STATIC (t) = 1;
+ t = ffecom_start_decl (t, 1);
+ ffecom_finish_decl (t, inits, 0);
+
+ resume_momentary (yes);
+
+ ffeste_f2c_exp_ (unitfield, unitexp);
+ ffeste_f2c_exp_ (statfield, statexp);
+
+ ttype = build_pointer_type (TREE_TYPE (t));
+ t = ffecom_1 (ADDR_EXPR, ttype, t);
+
+ t = build_tree_list (NULL_TREE, t);
+
+ return t;
+}
+
+#endif
+/* ffeste_io_icilist_ -- Make arglist with ptr to internal I/O control list
+
+ tree arglist;
+ arglist = ffeste_io_icilist_(...);
+
+ Returns a tree suitable as an argument list containing a pointer to
+ an internal-file I/O control list. First, generates that control
+ list, if necessary, along with any static and run-time initializations
+ that are needed as specified by the arguments to this function. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffeste_io_icilist_ (bool have_err,
+ ffebld unit_expr,
+ bool have_end,
+ ffestvFormat format,
+ ffestpFile *format_spec)
+{
+ static tree f2c_icilist_struct = NULL_TREE;
+ tree t;
+ tree ttype;
+ int yes;
+ tree field;
+ tree inits, initn;
+ bool constantp = TRUE;
+ static tree errfield, unitfield, endfield, formatfield, unitlenfield,
+ unitnumfield;
+ tree errinit, unitinit, endinit, formatinit, unitleninit, unitnuminit;
+ tree unitexp, formatexp, unitlenexp, unitnumexp;
+ static int mynumber = 0;
+
+ if (f2c_icilist_struct == NULL_TREE)
+ {
+ tree ref;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ ref = make_node (RECORD_TYPE);
+
+ errfield = ffecom_decl_field (ref, NULL_TREE, "err",
+ ffecom_f2c_flag_type_node);
+ unitfield = ffecom_decl_field (ref, errfield, "unit",
+ string_type_node);
+ endfield = ffecom_decl_field (ref, unitfield, "end",
+ ffecom_f2c_flag_type_node);
+ formatfield = ffecom_decl_field (ref, endfield, "format",
+ string_type_node);
+ unitlenfield = ffecom_decl_field (ref, formatfield, "unitlen",
+ ffecom_f2c_ftnint_type_node);
+ unitnumfield = ffecom_decl_field (ref, unitlenfield, "unitnum",
+ ffecom_f2c_ftnint_type_node);
+
+ TYPE_FIELDS (ref) = errfield;
+ layout_type (ref);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ f2c_icilist_struct = ref;
+ }
+
+ ffeste_f2c_flagspec_ (have_err, errinit);
+
+ unitexp = ffecom_arg_ptr_to_expr (unit_expr, &unitlenexp);
+ if ((ffeinfo_rank (ffebld_info (unit_expr)) == 0)
+ || (TREE_CODE (TREE_TYPE (TREE_TYPE (unitexp))) != ARRAY_TYPE))
+ unitnumexp = ffecom_integer_one_node;
+ else
+ {
+ unitnumexp = size_binop (CEIL_DIV_EXPR,
+ TYPE_SIZE (TREE_TYPE (TREE_TYPE (unitexp))), unitlenexp);
+ unitnumexp = size_binop (CEIL_DIV_EXPR,
+ unitnumexp, size_int (TYPE_PRECISION
+ (char_type_node)));
+ }
+ if (TREE_CONSTANT (unitexp))
+ {
+ unitinit = unitexp;
+ unitexp = NULL_TREE;
+ }
+ else
+ {
+ unitinit = null_pointer_node;
+ constantp = FALSE;
+ }
+ if ((unitlenexp != NULL_TREE) && TREE_CONSTANT (unitlenexp))
+ {
+ unitleninit = unitlenexp;
+ unitlenexp = NULL_TREE;
+ }
+ else
+ {
+ unitleninit = ffecom_integer_zero_node;
+ constantp = FALSE;
+ }
+ if (TREE_CONSTANT (unitnumexp))
+ {
+ unitnuminit = unitnumexp;
+ unitnumexp = NULL_TREE;
+ }
+ else
+ {
+ unitnuminit = ffecom_integer_zero_node;
+ constantp = FALSE;
+ }
+
+ switch (format)
+ {
+ case FFESTV_formatNONE:
+ formatinit = null_pointer_node;
+ formatexp = NULL_TREE;
+ break;
+
+ case FFESTV_formatLABEL:
+ formatexp = NULL_TREE;
+ formatinit = ffecom_lookup_label (format_spec->u.label);
+ if ((formatinit == NULL_TREE)
+ || (TREE_CODE (formatinit) == ERROR_MARK))
+ break;
+ formatinit = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (void_type_node),
+ formatinit);
+ TREE_CONSTANT (formatinit) = 1;
+ break;
+
+ case FFESTV_formatCHAREXPR:
+ formatexp = ffecom_arg_ptr_to_expr (format_spec->u.expr, NULL);
+ if (TREE_CONSTANT (formatexp))
+ {
+ formatinit = formatexp;
+ formatexp = NULL_TREE;
+ }
+ else
+ {
+ formatinit = null_pointer_node;
+ constantp = FALSE;
+ }
+ break;
+
+ case FFESTV_formatASTERISK:
+ formatinit = null_pointer_node;
+ formatexp = NULL_TREE;
+ break;
+
+ case FFESTV_formatINTEXPR:
+ formatinit = null_pointer_node;
+ formatexp = ffecom_expr_assign (format_spec->u.expr);
+ if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (formatexp)))
+ < GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (null_pointer_node))))
+ error ("ASSIGNed FORMAT specifier is too small");
+ formatexp = convert (string_type_node, formatexp);
+ break;
+
+ default:
+ assert ("bad format spec" == NULL);
+ formatexp = NULL_TREE;
+ formatinit = ffecom_integer_zero_node;
+ break;
+ }
+
+ ffeste_f2c_flagspec_ (have_end, endinit);
+
+ inits = build_tree_list ((field = TYPE_FIELDS (f2c_icilist_struct)),
+ errinit);
+ initn = inits;
+ ffeste_f2c_init_ (unitinit);
+ ffeste_f2c_init_ (endinit);
+ ffeste_f2c_init_ (formatinit);
+ ffeste_f2c_init_ (unitleninit);
+ ffeste_f2c_init_ (unitnuminit);
+
+ inits = build (CONSTRUCTOR, f2c_icilist_struct, NULL_TREE, inits);
+ TREE_CONSTANT (inits) = constantp ? 1 : 0;
+ TREE_STATIC (inits) = 1;
+
+ yes = suspend_momentary ();
+
+ t = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_icilist_%d", NULL,
+ mynumber++),
+ f2c_icilist_struct);
+ TREE_STATIC (t) = 1;
+ t = ffecom_start_decl (t, 1);
+ ffecom_finish_decl (t, inits, 0);
+
+ resume_momentary (yes);
+
+ ffeste_f2c_exp_ (unitfield, unitexp);
+ ffeste_f2c_exp_ (formatfield, formatexp);
+ ffeste_f2c_exp_ (unitlenfield, unitlenexp);
+ ffeste_f2c_exp_ (unitnumfield, unitnumexp);
+
+ ttype = build_pointer_type (TREE_TYPE (t));
+ t = ffecom_1 (ADDR_EXPR, ttype, t);
+
+ t = build_tree_list (NULL_TREE, t);
+
+ return t;
+}
+
+#endif
+/* ffeste_io_impdo_ -- Handle implied-DO in I/O list
+
+ ffebld expr;
+ ffeste_io_impdo_(expr);
+
+ Expands code to start up the DO loop. Then for each item in the
+ DO loop, handles appropriately (possibly including recursively calling
+ itself). Then expands code to end the DO loop. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffeste_io_impdo_ (ffebld impdo, ffelexToken impdo_token)
+{
+ ffebld var = ffebld_head (ffebld_right (impdo));
+ ffebld start = ffebld_head (ffebld_trail (ffebld_right (impdo)));
+ ffebld end = ffebld_head (ffebld_trail (ffebld_trail
+ (ffebld_right (impdo))));
+ ffebld incr = ffebld_head (ffebld_trail (ffebld_trail
+ (ffebld_trail (ffebld_right (impdo)))));
+ ffebld list; /* Used for list of items in left part of
+ impdo. */
+ ffebld item; /* I/O item from head of given list. */
+ tree tvar;
+ tree tincr;
+ tree titervar;
+
+ if (incr == NULL)
+ {
+ incr = ffebld_new_conter (ffebld_constant_new_integerdefault_val (1));
+ ffebld_set_info (incr, ffeinfo_new
+ (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ }
+
+ /* Start the DO loop. */
+
+ start = ffeexpr_convert_expr (start, impdo_token, var, impdo_token,
+ FFEEXPR_contextLET);
+ end = ffeexpr_convert_expr (end, impdo_token, var, impdo_token,
+ FFEEXPR_contextLET);
+ incr = ffeexpr_convert_expr (incr, impdo_token, var, impdo_token,
+ FFEEXPR_contextLET);
+
+ ffeste_begin_iterdo_ (NULL, &tvar, &tincr, &titervar, var,
+ start, impdo_token,
+ end, impdo_token,
+ incr, impdo_token,
+ "Implied DO loop");
+
+ /* Handle the list of items. */
+
+ for (list = ffebld_left (impdo); list != NULL; list = ffebld_trail (list))
+ {
+ item = ffebld_head (list);
+ if (item == NULL)
+ continue;
+ while (ffebld_op (item) == FFEBLD_opPAREN)
+ item = ffebld_left (item);
+ if (ffebld_op (item) == FFEBLD_opANY)
+ continue;
+ if (ffebld_op (item) == FFEBLD_opIMPDO)
+ ffeste_io_impdo_ (item, impdo_token);
+ else
+ ffeste_io_call_ ((*ffeste_io_driver_) (item), TRUE);
+ clear_momentary ();
+ }
+
+ /* Generate end of implied-do construct. */
+
+ ffeste_end_iterdo_ (tvar, tincr, titervar);
+}
+
+#endif
+/* ffeste_io_inlist_ -- Make arglist with ptr to INQUIRE control list
+
+ tree arglist;
+ arglist = ffeste_io_inlist_(...);
+
+ Returns a tree suitable as an argument list containing a pointer to
+ an INQUIRE-statement control list. First, generates that control
+ list, if necessary, along with any static and run-time initializations
+ that are needed as specified by the arguments to this function. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffeste_io_inlist_ (bool have_err,
+ ffestpFile *unit_spec,
+ ffestpFile *file_spec,
+ ffestpFile *exist_spec,
+ ffestpFile *open_spec,
+ ffestpFile *number_spec,
+ ffestpFile *named_spec,
+ ffestpFile *name_spec,
+ ffestpFile *access_spec,
+ ffestpFile *sequential_spec,
+ ffestpFile *direct_spec,
+ ffestpFile *form_spec,
+ ffestpFile *formatted_spec,
+ ffestpFile *unformatted_spec,
+ ffestpFile *recl_spec,
+ ffestpFile *nextrec_spec,
+ ffestpFile *blank_spec)
+{
+ static tree f2c_inquire_struct = NULL_TREE;
+ tree t;
+ tree ttype;
+ int yes;
+ tree field;
+ tree inits, initn;
+ bool constantp = TRUE;
+ static tree errfield, unitfield, filefield, filelenfield, existfield,
+ openfield, numberfield, namedfield, namefield, namelenfield, accessfield,
+ accesslenfield, sequentialfield, sequentiallenfield, directfield, directlenfield,
+ formfield, formlenfield, formattedfield, formattedlenfield, unformattedfield,
+ unformattedlenfield, reclfield, nextrecfield, blankfield, blanklenfield;
+ tree errinit, unitinit, fileinit, fileleninit, existinit, openinit, numberinit,
+ namedinit, nameinit, nameleninit, accessinit, accessleninit, sequentialinit,
+ sequentialleninit, directinit, directleninit, forminit, formleninit,
+ formattedinit, formattedleninit, unformattedinit, unformattedleninit,
+ reclinit, nextrecinit, blankinit, blankleninit;
+ tree
+ unitexp, fileexp, filelenexp, existexp, openexp, numberexp, namedexp,
+ nameexp, namelenexp, accessexp, accesslenexp, sequentialexp, sequentiallenexp,
+ directexp, directlenexp, formexp, formlenexp, formattedexp, formattedlenexp,
+ unformattedexp, unformattedlenexp, reclexp, nextrecexp, blankexp, blanklenexp;
+ static int mynumber = 0;
+
+ if (f2c_inquire_struct == NULL_TREE)
+ {
+ tree ref;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ ref = make_node (RECORD_TYPE);
+
+ errfield = ffecom_decl_field (ref, NULL_TREE, "err",
+ ffecom_f2c_flag_type_node);
+ unitfield = ffecom_decl_field (ref, errfield, "unit",
+ ffecom_f2c_ftnint_type_node);
+ filefield = ffecom_decl_field (ref, unitfield, "file",
+ string_type_node);
+ filelenfield = ffecom_decl_field (ref, filefield, "filelen",
+ ffecom_f2c_ftnlen_type_node);
+ existfield = ffecom_decl_field (ref, filelenfield, "exist",
+ ffecom_f2c_ptr_to_ftnint_type_node);
+ openfield = ffecom_decl_field (ref, existfield, "open",
+ ffecom_f2c_ptr_to_ftnint_type_node);
+ numberfield = ffecom_decl_field (ref, openfield, "number",
+ ffecom_f2c_ptr_to_ftnint_type_node);
+ namedfield = ffecom_decl_field (ref, numberfield, "named",
+ ffecom_f2c_ptr_to_ftnint_type_node);
+ namefield = ffecom_decl_field (ref, namedfield, "name",
+ string_type_node);
+ namelenfield = ffecom_decl_field (ref, namefield, "namelen",
+ ffecom_f2c_ftnlen_type_node);
+ accessfield = ffecom_decl_field (ref, namelenfield, "access",
+ string_type_node);
+ accesslenfield = ffecom_decl_field (ref, accessfield, "accesslen",
+ ffecom_f2c_ftnlen_type_node);
+ sequentialfield = ffecom_decl_field (ref, accesslenfield, "sequential",
+ string_type_node);
+ sequentiallenfield = ffecom_decl_field (ref, sequentialfield,
+ "sequentiallen",
+ ffecom_f2c_ftnlen_type_node);
+ directfield = ffecom_decl_field (ref, sequentiallenfield, "direct",
+ string_type_node);
+ directlenfield = ffecom_decl_field (ref, directfield, "directlen",
+ ffecom_f2c_ftnlen_type_node);
+ formfield = ffecom_decl_field (ref, directlenfield, "form",
+ string_type_node);
+ formlenfield = ffecom_decl_field (ref, formfield, "formlen",
+ ffecom_f2c_ftnlen_type_node);
+ formattedfield = ffecom_decl_field (ref, formlenfield, "formatted",
+ string_type_node);
+ formattedlenfield = ffecom_decl_field (ref, formattedfield,
+ "formattedlen",
+ ffecom_f2c_ftnlen_type_node);
+ unformattedfield = ffecom_decl_field (ref, formattedlenfield,
+ "unformatted",
+ string_type_node);
+ unformattedlenfield = ffecom_decl_field (ref, unformattedfield,
+ "unformattedlen",
+ ffecom_f2c_ftnlen_type_node);
+ reclfield = ffecom_decl_field (ref, unformattedlenfield, "recl",
+ ffecom_f2c_ptr_to_ftnint_type_node);
+ nextrecfield = ffecom_decl_field (ref, reclfield, "nextrec",
+ ffecom_f2c_ptr_to_ftnint_type_node);
+ blankfield = ffecom_decl_field (ref, nextrecfield, "blank",
+ string_type_node);
+ blanklenfield = ffecom_decl_field (ref, blankfield, "blanklen",
+ ffecom_f2c_ftnlen_type_node);
+
+ TYPE_FIELDS (ref) = errfield;
+ layout_type (ref);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ f2c_inquire_struct = ref;
+ }
+
+ ffeste_f2c_flagspec_ (have_err, errinit);
+ ffeste_f2c_intspec_ (unit_spec, unitexp, unitinit);
+ ffeste_f2c_charspec_ (file_spec, fileexp, fileinit, filelenexp, fileleninit);
+ ffeste_f2c_ptrtointspec_ (exist_spec, existexp, existinit);
+ ffeste_f2c_ptrtointspec_ (open_spec, openexp, openinit);
+ ffeste_f2c_ptrtointspec_ (number_spec, numberexp, numberinit);
+ ffeste_f2c_ptrtointspec_ (named_spec, namedexp, namedinit);
+ ffeste_f2c_charspec_ (name_spec, nameexp, nameinit, namelenexp, nameleninit);
+ ffeste_f2c_charspec_ (access_spec, accessexp, accessinit, accesslenexp,
+ accessleninit);
+ ffeste_f2c_charspec_ (sequential_spec, sequentialexp, sequentialinit,
+ sequentiallenexp, sequentialleninit);
+ ffeste_f2c_charspec_ (direct_spec, directexp, directinit, directlenexp,
+ directleninit);
+ ffeste_f2c_charspec_ (form_spec, formexp, forminit, formlenexp, formleninit);
+ ffeste_f2c_charspec_ (formatted_spec, formattedexp, formattedinit,
+ formattedlenexp, formattedleninit);
+ ffeste_f2c_charspec_ (unformatted_spec, unformattedexp, unformattedinit,
+ unformattedlenexp, unformattedleninit);
+ ffeste_f2c_ptrtointspec_ (recl_spec, reclexp, reclinit);
+ ffeste_f2c_ptrtointspec_ (nextrec_spec, nextrecexp, nextrecinit);
+ ffeste_f2c_charspec_ (blank_spec, blankexp, blankinit, blanklenexp,
+ blankleninit);
+
+ inits = build_tree_list ((field = TYPE_FIELDS (f2c_inquire_struct)),
+ errinit);
+ initn = inits;
+ ffeste_f2c_init_ (unitinit);
+ ffeste_f2c_init_ (fileinit);
+ ffeste_f2c_init_ (fileleninit);
+ ffeste_f2c_init_ (existinit);
+ ffeste_f2c_init_ (openinit);
+ ffeste_f2c_init_ (numberinit);
+ ffeste_f2c_init_ (namedinit);
+ ffeste_f2c_init_ (nameinit);
+ ffeste_f2c_init_ (nameleninit);
+ ffeste_f2c_init_ (accessinit);
+ ffeste_f2c_init_ (accessleninit);
+ ffeste_f2c_init_ (sequentialinit);
+ ffeste_f2c_init_ (sequentialleninit);
+ ffeste_f2c_init_ (directinit);
+ ffeste_f2c_init_ (directleninit);
+ ffeste_f2c_init_ (forminit);
+ ffeste_f2c_init_ (formleninit);
+ ffeste_f2c_init_ (formattedinit);
+ ffeste_f2c_init_ (formattedleninit);
+ ffeste_f2c_init_ (unformattedinit);
+ ffeste_f2c_init_ (unformattedleninit);
+ ffeste_f2c_init_ (reclinit);
+ ffeste_f2c_init_ (nextrecinit);
+ ffeste_f2c_init_ (blankinit);
+ ffeste_f2c_init_ (blankleninit);
+
+ inits = build (CONSTRUCTOR, f2c_inquire_struct, NULL_TREE, inits);
+ TREE_CONSTANT (inits) = constantp ? 1 : 0;
+ TREE_STATIC (inits) = 1;
+
+ yes = suspend_momentary ();
+
+ t = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_inlist_%d", NULL,
+ mynumber++),
+ f2c_inquire_struct);
+ TREE_STATIC (t) = 1;
+ t = ffecom_start_decl (t, 1);
+ ffecom_finish_decl (t, inits, 0);
+
+ resume_momentary (yes);
+
+ ffeste_f2c_exp_ (unitfield, unitexp);
+ ffeste_f2c_exp_ (filefield, fileexp);
+ ffeste_f2c_exp_ (filelenfield, filelenexp);
+ ffeste_f2c_exp_ (existfield, existexp);
+ ffeste_f2c_exp_ (openfield, openexp);
+ ffeste_f2c_exp_ (numberfield, numberexp);
+ ffeste_f2c_exp_ (namedfield, namedexp);
+ ffeste_f2c_exp_ (namefield, nameexp);
+ ffeste_f2c_exp_ (namelenfield, namelenexp);
+ ffeste_f2c_exp_ (accessfield, accessexp);
+ ffeste_f2c_exp_ (accesslenfield, accesslenexp);
+ ffeste_f2c_exp_ (sequentialfield, sequentialexp);
+ ffeste_f2c_exp_ (sequentiallenfield, sequentiallenexp);
+ ffeste_f2c_exp_ (directfield, directexp);
+ ffeste_f2c_exp_ (directlenfield, directlenexp);
+ ffeste_f2c_exp_ (formfield, formexp);
+ ffeste_f2c_exp_ (formlenfield, formlenexp);
+ ffeste_f2c_exp_ (formattedfield, formattedexp);
+ ffeste_f2c_exp_ (formattedlenfield, formattedlenexp);
+ ffeste_f2c_exp_ (unformattedfield, unformattedexp);
+ ffeste_f2c_exp_ (unformattedlenfield, unformattedlenexp);
+ ffeste_f2c_exp_ (reclfield, reclexp);
+ ffeste_f2c_exp_ (nextrecfield, nextrecexp);
+ ffeste_f2c_exp_ (blankfield, blankexp);
+ ffeste_f2c_exp_ (blanklenfield, blanklenexp);
+
+ ttype = build_pointer_type (TREE_TYPE (t));
+ t = ffecom_1 (ADDR_EXPR, ttype, t);
+
+ t = build_tree_list (NULL_TREE, t);
+
+ return t;
+}
+
+#endif
+/* ffeste_io_olist_ -- Make arglist with ptr to OPEN control list
+
+ tree arglist;
+ arglist = ffeste_io_olist_(...);
+
+ Returns a tree suitable as an argument list containing a pointer to
+ an OPEN-statement control list. First, generates that control
+ list, if necessary, along with any static and run-time initializations
+ that are needed as specified by the arguments to this function. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static tree
+ffeste_io_olist_ (bool have_err,
+ ffebld unit_expr,
+ ffestpFile *file_spec,
+ ffestpFile *stat_spec,
+ ffestpFile *access_spec,
+ ffestpFile *form_spec,
+ ffestpFile *recl_spec,
+ ffestpFile *blank_spec)
+{
+ static tree f2c_open_struct = NULL_TREE;
+ tree t;
+ tree ttype;
+ int yes;
+ tree field;
+ tree inits, initn;
+ tree ignore; /* Ignore length info for certain fields. */
+ bool constantp = TRUE;
+ static tree errfield, unitfield, filefield, filelenfield, statfield,
+ accessfield, formfield, reclfield, blankfield;
+ tree errinit, unitinit, fileinit, fileleninit, statinit, accessinit,
+ forminit, reclinit, blankinit;
+ tree
+ unitexp, fileexp, filelenexp, statexp, accessexp, formexp, reclexp,
+ blankexp;
+ static int mynumber = 0;
+
+ if (f2c_open_struct == NULL_TREE)
+ {
+ tree ref;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ ref = make_node (RECORD_TYPE);
+
+ errfield = ffecom_decl_field (ref, NULL_TREE, "err",
+ ffecom_f2c_flag_type_node);
+ unitfield = ffecom_decl_field (ref, errfield, "unit",
+ ffecom_f2c_ftnint_type_node);
+ filefield = ffecom_decl_field (ref, unitfield, "file",
+ string_type_node);
+ filelenfield = ffecom_decl_field (ref, filefield, "filelen",
+ ffecom_f2c_ftnlen_type_node);
+ statfield = ffecom_decl_field (ref, filelenfield, "stat",
+ string_type_node);
+ accessfield = ffecom_decl_field (ref, statfield, "access",
+ string_type_node);
+ formfield = ffecom_decl_field (ref, accessfield, "form",
+ string_type_node);
+ reclfield = ffecom_decl_field (ref, formfield, "recl",
+ ffecom_f2c_ftnint_type_node);
+ blankfield = ffecom_decl_field (ref, reclfield, "blank",
+ string_type_node);
+
+ TYPE_FIELDS (ref) = errfield;
+ layout_type (ref);
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ f2c_open_struct = ref;
+ }
+
+ ffeste_f2c_flagspec_ (have_err, errinit);
+
+ unitexp = ffecom_expr (unit_expr);
+ if (TREE_CONSTANT (unitexp))
+ {
+ unitinit = unitexp;
+ unitexp = NULL_TREE;
+ }
+ else
+ {
+ unitinit = ffecom_integer_zero_node;
+ constantp = FALSE;
+ }
+
+ ffeste_f2c_charspec_ (file_spec, fileexp, fileinit, filelenexp, fileleninit);
+ ffeste_f2c_charnolenspec_ (stat_spec, statexp, statinit);
+ ffeste_f2c_charnolenspec_ (access_spec, accessexp, accessinit);
+ ffeste_f2c_charnolenspec_ (form_spec, formexp, forminit);
+ ffeste_f2c_intspec_ (recl_spec, reclexp, reclinit);
+ ffeste_f2c_charnolenspec_ (blank_spec, blankexp, blankinit);
+
+ inits = build_tree_list ((field = TYPE_FIELDS (f2c_open_struct)), errinit);
+ initn = inits;
+ ffeste_f2c_init_ (unitinit);
+ ffeste_f2c_init_ (fileinit);
+ ffeste_f2c_init_ (fileleninit);
+ ffeste_f2c_init_ (statinit);
+ ffeste_f2c_init_ (accessinit);
+ ffeste_f2c_init_ (forminit);
+ ffeste_f2c_init_ (reclinit);
+ ffeste_f2c_init_ (blankinit);
+
+ inits = build (CONSTRUCTOR, f2c_open_struct, NULL_TREE, inits);
+ TREE_CONSTANT (inits) = constantp ? 1 : 0;
+ TREE_STATIC (inits) = 1;
+
+ yes = suspend_momentary ();
+
+ t = build_decl (VAR_DECL,
+ ffecom_get_invented_identifier ("__g77_olist_%d", NULL,
+ mynumber++),
+ f2c_open_struct);
+ TREE_STATIC (t) = 1;
+ t = ffecom_start_decl (t, 1);
+ ffecom_finish_decl (t, inits, 0);
+
+ resume_momentary (yes);
+
+ ffeste_f2c_exp_ (unitfield, unitexp);
+ ffeste_f2c_exp_ (filefield, fileexp);
+ ffeste_f2c_exp_ (filelenfield, filelenexp);
+ ffeste_f2c_exp_ (statfield, statexp);
+ ffeste_f2c_exp_ (accessfield, accessexp);
+ ffeste_f2c_exp_ (formfield, formexp);
+ ffeste_f2c_exp_ (reclfield, reclexp);
+ ffeste_f2c_exp_ (blankfield, blankexp);
+
+ ttype = build_pointer_type (TREE_TYPE (t));
+ t = ffecom_1 (ADDR_EXPR, ttype, t);
+
+ t = build_tree_list (NULL_TREE, t);
+
+ return t;
+}
+
+#endif
+/* ffeste_subr_file_ -- Display file-statement specifier
+
+ ffeste_subr_file_(&specifier); */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+static void
+ffeste_subr_file_ (char *kw, ffestpFile *spec)
+{
+ if (!spec->kw_or_val_present)
+ return;
+ fputs (kw, dmpout);
+ if (spec->value_present)
+ {
+ fputc ('=', dmpout);
+ if (spec->value_is_label)
+ {
+ assert (spec->value_is_label == 2); /* Temporary checking only. */
+ fprintf (dmpout, "%" ffelabValue_f "u",
+ ffelab_value (spec->u.label));
+ }
+ else
+ ffebld_dump (spec->u.expr);
+ }
+ fputc (',', dmpout);
+}
+#endif
+
+/* ffeste_subr_beru_ -- Generate code for BACKSPACE/ENDFILE/REWIND
+
+ ffeste_subr_beru_(FFECOM_gfrtFBACK); */
+
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+static void
+ffeste_subr_beru_ (ffestpBeruStmt *info, ffecomGfrt rt)
+{
+ tree alist;
+ bool iostat;
+ bool errl;
+
+#define specified(something) (info->beru_spec[something].kw_or_val_present)
+
+ ffeste_emit_line_note_ ();
+
+ /* Do the real work. */
+
+ iostat = specified (FFESTP_beruixIOSTAT);
+ errl = specified (FFESTP_beruixERR);
+
+ /* ~~For now, we assume the unit number is specified and is not ASTERISK,
+ because the FFE doesn't support BACKSPACE(*) and rejects a BACKSPACE
+ without any unit specifier. f2c, however, supports the former
+ construct. When it is time to add this feature to the FFE, which
+ probably is fairly easy, ffestc_R919 and company will want to pass an
+ ffestvUnit indicator of FFESTV_unitINTEXPR or _unitASTERISK to
+ ffeste_R919 and company, and they will want to pass that same value to
+ this function, and that argument will replace the constant _unitINTEXPR_
+ in the call below. Right now, the default unit number, 6, is ignored. */
+
+ ffecom_push_calltemps ();
+
+ alist = ffeste_io_ialist_ (errl || iostat, FFESTV_unitINTEXPR,
+ info->beru_spec[FFESTP_beruixUNIT].u.expr, 6);
+
+ if (errl)
+ { /* ERR= */
+ ffeste_io_err_
+ = ffeste_io_abort_
+ = ffecom_lookup_label
+ (info->beru_spec[FFESTP_beruixERR].u.label);
+ ffeste_io_abort_is_temp_ = FALSE;
+ }
+ else
+ { /* no ERR= */
+ ffeste_io_err_ = NULL_TREE;
+
+ if ((ffeste_io_abort_is_temp_ = iostat))
+ ffeste_io_abort_ = ffecom_temp_label ();
+ else
+ ffeste_io_abort_ = NULL_TREE;
+ }
+
+ if (iostat)
+ { /* IOSTAT= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = ffecom_expr
+ (info->beru_spec[FFESTP_beruixIOSTAT].u.expr);
+ }
+ else if (ffeste_io_abort_ != NULL_TREE)
+ { /* no IOSTAT= but ERR= */
+ ffeste_io_iostat_is_temp_ = TRUE;
+ ffeste_io_iostat_
+ = ffecom_push_tempvar (ffecom_integer_type_node,
+ FFETARGET_charactersizeNONE, -1, FALSE);
+ }
+ else
+ { /* no IOSTAT=, or ERR= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = NULL_TREE;
+ }
+
+ /* Don't generate "if (iostat != 0) goto label;" if label is temp abort
+ label, since we're gonna fall through to there anyway. */
+
+ ffeste_io_call_ (ffecom_call_gfrt (rt, alist),
+ !ffeste_io_abort_is_temp_);
+
+ /* If we've got a temp label, generate its code here. */
+
+ if (ffeste_io_abort_is_temp_)
+ {
+ DECL_INITIAL (ffeste_io_abort_) = error_mark_node;
+ emit_nop ();
+ expand_label (ffeste_io_abort_);
+
+ assert (ffeste_io_err_ == NULL_TREE);
+ }
+
+ /* If we've got a temp iostat, pop the temp. */
+
+ if (ffeste_io_iostat_is_temp_)
+ ffecom_pop_tempvar (ffeste_io_iostat_);
+
+ ffecom_pop_calltemps ();
+
+#undef specified
+
+ clear_momentary ();
+}
+
+#endif
+/* ffeste_do -- End of statement following DO-term-stmt etc
+
+ ffeste_do(TRUE);
+
+ Also invoked by _labeldef_branch_finish_ (or, in cases
+ of errors, other _labeldef_ functions) when the label definition is
+ for a DO-target (LOOPEND) label, once per matching/outstanding DO
+ block on the stack. These cases invoke this function with ok==TRUE, so
+ only forced stack popping (via ffeste_eof_()) invokes it with ok==FALSE. */
+
+void
+ffeste_do (ffestw block)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ END_DO\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ if (ffestw_do_tvar (block) == 0)
+ expand_end_loop (); /* DO WHILE and just DO. */
+ else
+ ffeste_end_iterdo_ (ffestw_do_tvar (block),
+ ffestw_do_incr_saved (block),
+ ffestw_do_count_var (block));
+
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_end_R807 -- End of statement following logical IF
+
+ ffeste_end_R807(TRUE);
+
+ Applies ONLY to logical IF, not to IF-THEN. For example, does not
+ ffelex_token_kill the construct name for an IF-THEN block (the name
+ field is invalid for logical IF). ok==TRUE iff statement following
+ logical IF (substatement) is valid; else, statement is invalid or
+ stack forcibly popped due to ffeste_eof_(). */
+
+void
+ffeste_end_R807 ()
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ END_IF\n", dmpout); /* Also see ffeste_R806. */
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ expand_end_cond ();
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_labeldef_branch -- Generate "code" for branch label def
+
+ ffeste_labeldef_branch(label); */
+
+void
+ffeste_labeldef_branch (ffelab label)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "+ label %lu\n", ffelab_value (label));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree glabel;
+
+ glabel = ffecom_lookup_label (label);
+ assert (glabel != NULL_TREE);
+ if (TREE_CODE (glabel) == ERROR_MARK)
+ return;
+ assert (DECL_INITIAL (glabel) == NULL_TREE);
+ DECL_INITIAL (glabel) = error_mark_node;
+ DECL_SOURCE_FILE (glabel) = ffelab_definition_filename (label);
+ DECL_SOURCE_LINE (glabel) = ffelab_definition_filelinenum (label);
+ emit_nop ();
+ expand_label (glabel);
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_labeldef_format -- Generate "code" for FORMAT label def
+
+ ffeste_labeldef_format(label); */
+
+void
+ffeste_labeldef_format (ffelab label)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "$ label %lu\n", ffelab_value (label));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_label_formatdef_ = label;
+#else
+#error
+#endif
+}
+
+/* ffeste_R737A -- Assignment statement outside of WHERE
+
+ ffeste_R737A(dest_expr,source_expr); */
+
+void
+ffeste_R737A (ffebld dest, ffebld source)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ let ", dmpout);
+ ffebld_dump (dest);
+ fputs ("=", dmpout);
+ ffebld_dump (source);
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ ffecom_push_calltemps ();
+
+ ffecom_expand_let_stmt (dest, source);
+
+ ffecom_pop_calltemps ();
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R803 -- Block IF (IF-THEN) statement
+
+ ffeste_R803(construct_name,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffeste_R803 (ffebld expr)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ IF_block (", dmpout);
+ ffebld_dump (expr);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ ffecom_push_calltemps ();
+
+ expand_start_cond (ffecom_truth_value (ffecom_expr (expr)), 0);
+
+ ffecom_pop_calltemps ();
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R804 -- ELSE IF statement
+
+ ffeste_R804(expr,expr_token,name_token);
+
+ Make sure ffeste_kind_ identifies an IF block. If not
+ NULL, make sure name_token gives the correct name. Implement the else
+ of the IF block. */
+
+void
+ffeste_R804 (ffebld expr)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ ELSE_IF (", dmpout);
+ ffebld_dump (expr);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ ffecom_push_calltemps ();
+
+ expand_start_elseif (ffecom_truth_value (ffecom_expr (expr)));
+
+ ffecom_pop_calltemps ();
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R805 -- ELSE statement
+
+ ffeste_R805(name_token);
+
+ Make sure ffeste_kind_ identifies an IF block. If not
+ NULL, make sure name_token gives the correct name. Implement the ELSE
+ of the IF block. */
+
+void
+ffeste_R805 ()
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ ELSE\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ expand_start_else ();
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R806 -- End an IF-THEN
+
+ ffeste_R806(TRUE); */
+
+void
+ffeste_R806 ()
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ END_IF_then\n", dmpout); /* Also see ffeste_shriek_if_. */
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ expand_end_cond ();
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R807 -- Logical IF statement
+
+ ffeste_R807(expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffeste_R807 (ffebld expr)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ IF_logical (", dmpout);
+ ffebld_dump (expr);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ ffecom_push_calltemps ();
+
+ expand_start_cond (ffecom_truth_value (ffecom_expr (expr)), 0);
+
+ ffecom_pop_calltemps ();
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R809 -- SELECT CASE statement
+
+ ffeste_R809(construct_name,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffeste_R809 (ffestw block, ffebld expr)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ SELECT_CASE (", dmpout);
+ ffebld_dump (expr);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffecom_push_calltemps ();
+
+ {
+ tree texpr;
+
+ ffeste_emit_line_note_ ();
+
+ if ((expr == NULL)
+ || (ffeinfo_basictype (ffebld_info (expr))
+ == FFEINFO_basictypeANY))
+ {
+ ffestw_set_select_texpr (block, error_mark_node);
+ clear_momentary ();
+ }
+ else
+ {
+ texpr = ffecom_expr (expr);
+ if (ffeinfo_basictype (ffebld_info (expr))
+ != FFEINFO_basictypeCHARACTER)
+ {
+ expand_start_case (1, texpr, TREE_TYPE (texpr),
+ "SELECT CASE statement");
+ ffestw_set_select_texpr (block, texpr);
+ ffestw_set_select_break (block, FALSE);
+ push_momentary ();
+ }
+ else
+ {
+ ffebad_start_msg ("SELECT CASE on CHARACTER type (at %0) not supported -- sorry",
+ FFEBAD_severityFATAL);
+ ffebad_here (0, ffestw_line (block), ffestw_col (block));
+ ffebad_finish ();
+ ffestw_set_select_texpr (block, error_mark_node);
+ }
+ }
+ }
+
+ ffecom_pop_calltemps ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R810 -- CASE statement
+
+ ffeste_R810(case_value_range_list,name);
+
+ If casenum is 0, it's CASE DEFAULT. Else it's the case ranges at
+ the start of the first_stmt list in the select object at the top of
+ the stack that match casenum. */
+
+void
+ffeste_R810 (ffestw block, unsigned long casenum)
+{
+ ffestwSelect s = ffestw_select (block);
+ ffestwCase c;
+
+ ffeste_check_simple_ ();
+
+ if (s->first_stmt == (ffestwCase) &s->first_rel)
+ c = NULL;
+ else
+ c = s->first_stmt;
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if ((c == NULL) || (casenum != c->casenum))
+ {
+ if (casenum == 0) /* Intentional CASE DEFAULT. */
+ fputs ("+ CASE_DEFAULT", dmpout);
+ }
+ else
+ {
+ bool comma = FALSE;
+
+ fputs ("+ CASE (", dmpout);
+ do
+ {
+ if (comma)
+ fputc (',', dmpout);
+ else
+ comma = TRUE;
+ if (c->low != NULL)
+ ffebld_constant_dump (c->low);
+ if (c->low != c->high)
+ {
+ fputc (':', dmpout);
+ if (c->high != NULL)
+ ffebld_constant_dump (c->high);
+ }
+ c = c->next_stmt;
+ /* Unlink prev. */
+ c->previous_stmt->previous_stmt->next_stmt = c;
+ c->previous_stmt = c->previous_stmt->previous_stmt;
+ }
+ while ((c != (ffestwCase) &s->first_rel) && (casenum == c->casenum));
+ fputc (')', dmpout);
+ }
+
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree texprlow;
+ tree texprhigh;
+ tree tlabel = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+ int pushok;
+ tree duplicate;
+
+ ffeste_emit_line_note_ ();
+
+ if (TREE_CODE (ffestw_select_texpr (block)) == ERROR_MARK)
+ {
+ clear_momentary ();
+ return;
+ }
+
+ if (ffestw_select_break (block))
+ expand_exit_something ();
+ else
+ ffestw_set_select_break (block, TRUE);
+
+ if ((c == NULL) || (casenum != c->casenum))
+ {
+ if (casenum == 0) /* Intentional CASE DEFAULT. */
+ {
+ pushok = pushcase (NULL_TREE, 0, tlabel, &duplicate);
+ assert (pushok == 0);
+ }
+ }
+ else
+ do
+ {
+ texprlow = (c->low == NULL) ? NULL_TREE
+ : ffecom_constantunion (&ffebld_constant_union (c->low), s->type,
+ s->kindtype, ffecom_tree_type[s->type][s->kindtype]);
+ if (c->low != c->high)
+ {
+ texprhigh = (c->high == NULL) ? NULL_TREE
+ : ffecom_constantunion (&ffebld_constant_union (c->high),
+ s->type, s->kindtype, ffecom_tree_type[s->type][s->kindtype]);
+ pushok = pushcase_range (texprlow, texprhigh, convert,
+ tlabel, &duplicate);
+ }
+ else
+ pushok = pushcase (texprlow, convert, tlabel, &duplicate);
+ assert (pushok == 0);
+ c = c->next_stmt;
+ /* Unlink prev. */
+ c->previous_stmt->previous_stmt->next_stmt = c;
+ c->previous_stmt = c->previous_stmt->previous_stmt;
+ }
+ while ((c != (ffestwCase) &s->first_rel) && (casenum == c->casenum));
+
+ clear_momentary ();
+ } /* ~~~handle character, character*1 */
+#else
+#error
+#endif
+}
+
+/* ffeste_R811 -- End a SELECT
+
+ ffeste_R811(TRUE); */
+
+void
+ffeste_R811 (ffestw block)
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ END_SELECT\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+
+ if (TREE_CODE (ffestw_select_texpr (block)) == ERROR_MARK)
+ {
+ clear_momentary ();
+ return;
+ }
+
+ expand_end_case (ffestw_select_texpr (block));
+ pop_momentary ();
+ clear_momentary (); /* ~~~handle character and character*1 */
+#else
+#error
+#endif
+}
+
+/* Iterative DO statement. */
+
+void
+ffeste_R819A (ffestw block, ffelab label UNUSED, ffebld var,
+ ffebld start, ffelexToken start_token,
+ ffebld end, ffelexToken end_token,
+ ffebld incr, ffelexToken incr_token)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if ((ffebld_op (incr) == FFEBLD_opCONTER)
+ && (ffebld_constant_is_zero (ffebld_conter (incr))))
+ {
+ ffebad_start (FFEBAD_DO_STEP_ZERO);
+ ffebad_here (0, ffelex_token_where_line (incr_token),
+ ffelex_token_where_column (incr_token));
+ ffebad_string ("Iterative DO loop");
+ ffebad_finish ();
+ /* Don't bother replacing it with 1 yet. */
+ }
+
+ if (label == NULL)
+ fputs ("+ DO_iterative_nonlabeled (", dmpout);
+ else
+ fprintf (dmpout, "+ DO_iterative_labeled %lu (", ffelab_value (label));
+ ffebld_dump (var);
+ fputc ('=', dmpout);
+ ffebld_dump (start);
+ fputc (',', dmpout);
+ ffebld_dump (end);
+ fputc (',', dmpout);
+ ffebld_dump (incr);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ ffeste_emit_line_note_ ();
+ ffecom_push_calltemps ();
+
+ /* Start the DO loop. */
+
+ ffeste_begin_iterdo_ (block, NULL, NULL, NULL,
+ var,
+ start, start_token,
+ end, end_token,
+ incr, incr_token,
+ "Iterative DO loop");
+
+ ffecom_pop_calltemps ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R819B -- DO WHILE statement
+
+ ffeste_R819B(construct_name,label_token,expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffeste_R819B (ffestw block, ffelab label UNUSED, ffebld expr)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if (label == NULL)
+ fputs ("+ DO_WHILE_nonlabeled (", dmpout);
+ else
+ fprintf (dmpout, "+ DO_WHILE_labeled %lu (", ffelab_value (label));
+ ffebld_dump (expr);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ ffeste_emit_line_note_ ();
+ ffecom_push_calltemps ();
+
+ ffestw_set_do_hook (block, expand_start_loop (1));
+ ffestw_set_do_tvar (block, 0); /* Means DO WHILE vs. iter DO. */
+ if (expr != NULL)
+ expand_exit_loop_if_false (0, ffecom_truth_value (ffecom_expr (expr)));
+
+ ffecom_pop_calltemps ();
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R825 -- END DO statement
+
+ ffeste_R825(name_token);
+
+ Make sure ffeste_kind_ identifies a DO block. If not
+ NULL, make sure name_token gives the correct name. Do whatever
+ is specific to seeing END DO with a DO-target label definition on it,
+ where the END DO is really treated as a CONTINUE (i.e. generate th
+ same code you would for CONTINUE). ffeste_do handles the actual
+ generation of end-loop code. */
+
+void
+ffeste_R825 ()
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ END_DO_sugar\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ emit_nop ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R834 -- CYCLE statement
+
+ ffeste_R834(name_token);
+
+ Handle a CYCLE within a loop. */
+
+void
+ffeste_R834 (ffestw block)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "+ CYCLE block #%lu\n", ffestw_blocknum (block));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ expand_continue_loop (ffestw_do_hook (block));
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R835 -- EXIT statement
+
+ ffeste_R835(name_token);
+
+ Handle a EXIT within a loop. */
+
+void
+ffeste_R835 (ffestw block)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "+ EXIT block #%lu\n", ffestw_blocknum (block));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ expand_exit_loop (ffestw_do_hook (block));
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R836 -- GOTO statement
+
+ ffeste_R836(label);
+
+ Make sure label_token identifies a valid label for a GOTO. Update
+ that label's info to indicate it is the target of a GOTO. */
+
+void
+ffeste_R836 (ffelab label)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "+ GOTO %lu\n", ffelab_value (label));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree glabel;
+
+ ffeste_emit_line_note_ ();
+ glabel = ffecom_lookup_label (label);
+ if ((glabel != NULL_TREE)
+ && (TREE_CODE (glabel) != ERROR_MARK))
+ {
+ TREE_USED (glabel) = 1;
+ expand_goto (glabel);
+ clear_momentary ();
+ }
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R837 -- Computed GOTO statement
+
+ ffeste_R837(labels,count,expr);
+
+ Make sure label_list identifies valid labels for a GOTO. Update
+ each label's info to indicate it is the target of a GOTO. */
+
+void
+ffeste_R837 (ffelab *labels, int count, ffebld expr)
+{
+ int i;
+
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ CGOTO (", dmpout);
+ for (i = 0; i < count; ++i)
+ {
+ if (i != 0)
+ fputc (',', dmpout);
+ fprintf (dmpout, "%" ffelabValue_f "u", ffelab_value (labels[i]));
+ }
+ fputs ("),", dmpout);
+ ffebld_dump (expr);
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree texpr;
+ tree value;
+ tree tlabel;
+ int pushok;
+ tree duplicate;
+
+ ffeste_emit_line_note_ ();
+ ffecom_push_calltemps ();
+
+ texpr = ffecom_expr (expr);
+ expand_start_case (0, texpr, TREE_TYPE (texpr), "computed GOTO statement");
+ push_momentary (); /* In case of lots of labels, keep clearing
+ them out. */
+ for (i = 0; i < count; ++i)
+ {
+ value = build_int_2 (i + 1, 0);
+ tlabel = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ pushok = pushcase (value, convert, tlabel, &duplicate);
+ assert (pushok == 0);
+ tlabel = ffecom_lookup_label (labels[i]);
+ if ((tlabel == NULL_TREE)
+ || (TREE_CODE (tlabel) == ERROR_MARK))
+ continue;
+ TREE_USED (tlabel) = 1;
+ expand_goto (tlabel);
+ clear_momentary ();
+ }
+ pop_momentary ();
+ expand_end_case (texpr);
+
+ ffecom_pop_calltemps ();
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R838 -- ASSIGN statement
+
+ ffeste_R838(label_token,target_variable,target_token);
+
+ Make sure label_token identifies a valid label for an assignment. Update
+ that label's info to indicate it is the source of an assignment. Update
+ target_variable's info to indicate it is the target the assignment of that
+ label. */
+
+void
+ffeste_R838 (ffelab label, ffebld target)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "+ ASSIGN %lu TO ", ffelab_value (label));
+ ffebld_dump (target);
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree expr_tree;
+ tree label_tree;
+ tree target_tree;
+
+ ffeste_emit_line_note_ ();
+ ffecom_push_calltemps ();
+
+ label_tree = ffecom_lookup_label (label);
+ if ((label_tree != NULL_TREE)
+ && (TREE_CODE (label_tree) != ERROR_MARK))
+ {
+ label_tree = ffecom_1 (ADDR_EXPR,
+ build_pointer_type (void_type_node),
+ label_tree);
+ TREE_CONSTANT (label_tree) = 1;
+ target_tree = ffecom_expr_assign_w (target);
+ if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (target_tree)))
+ < GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (label_tree))))
+ error ("ASSIGN to variable that is too small");
+ label_tree = convert (TREE_TYPE (target_tree), label_tree);
+ expr_tree = ffecom_modify (void_type_node,
+ target_tree,
+ label_tree);
+ expand_expr_stmt (expr_tree);
+ clear_momentary ();
+ }
+
+ ffecom_pop_calltemps ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R839 -- Assigned GOTO statement
+
+ ffeste_R839(target,target_token,label_list);
+
+ Make sure label_list identifies valid labels for a GOTO. Update
+ each label's info to indicate it is the target of a GOTO. */
+
+void
+ffeste_R839 (ffebld target)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ AGOTO ", dmpout);
+ ffebld_dump (target);
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree t;
+
+ ffeste_emit_line_note_ ();
+ ffecom_push_calltemps ();
+
+ t = ffecom_expr_assign (target);
+ if (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (t)))
+ < GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (null_pointer_node))))
+ error ("ASSIGNed GOTO target variable is too small");
+ expand_computed_goto (convert (TREE_TYPE (null_pointer_node), t));
+
+ ffecom_pop_calltemps ();
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R840 -- Arithmetic IF statement
+
+ ffeste_R840(expr,expr_token,neg,zero,pos);
+
+ Make sure the labels are valid; implement. */
+
+void
+ffeste_R840 (ffebld expr, ffelab neg, ffelab zero, ffelab pos)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ IF_arithmetic (", dmpout);
+ ffebld_dump (expr);
+ fprintf (dmpout, ") %" ffelabValue_f "u,%" ffelabValue_f "u,%" ffelabValue_f "u\n",
+ ffelab_value (neg), ffelab_value (zero), ffelab_value (pos));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree gneg = ffecom_lookup_label (neg);
+ tree gzero = ffecom_lookup_label (zero);
+ tree gpos = ffecom_lookup_label (pos);
+ tree texpr;
+
+ if ((gneg == NULL_TREE) || (gzero == NULL_TREE) || (gpos == NULL_TREE))
+ return;
+ if ((TREE_CODE (gneg) == ERROR_MARK)
+ || (TREE_CODE (gzero) == ERROR_MARK)
+ || (TREE_CODE (gpos) == ERROR_MARK))
+ return;
+
+ ffecom_push_calltemps ();
+
+ if (neg == zero)
+ {
+ if (neg == pos)
+ expand_goto (gzero);
+ else
+ { /* IF (expr.LE.0) THEN GOTO neg/zero ELSE
+ GOTO pos. */
+ texpr = ffecom_expr (expr);
+ texpr = ffecom_2 (LE_EXPR, integer_type_node,
+ texpr,
+ convert (TREE_TYPE (texpr),
+ integer_zero_node));
+ expand_start_cond (ffecom_truth_value (texpr), 0);
+ expand_goto (gzero);
+ expand_start_else ();
+ expand_goto (gpos);
+ expand_end_cond ();
+ }
+ }
+ else if (neg == pos)
+ { /* IF (expr.NE.0) THEN GOTO neg/pos ELSE GOTO
+ zero. */
+ texpr = ffecom_expr (expr);
+ texpr = ffecom_2 (NE_EXPR, integer_type_node,
+ texpr,
+ convert (TREE_TYPE (texpr),
+ integer_zero_node));
+ expand_start_cond (ffecom_truth_value (texpr), 0);
+ expand_goto (gneg);
+ expand_start_else ();
+ expand_goto (gzero);
+ expand_end_cond ();
+ }
+ else if (zero == pos)
+ { /* IF (expr.GE.0) THEN GOTO zero/pos ELSE
+ GOTO neg. */
+ texpr = ffecom_expr (expr);
+ texpr = ffecom_2 (GE_EXPR, integer_type_node,
+ texpr,
+ convert (TREE_TYPE (texpr),
+ integer_zero_node));
+ expand_start_cond (ffecom_truth_value (texpr), 0);
+ expand_goto (gzero);
+ expand_start_else ();
+ expand_goto (gneg);
+ expand_end_cond ();
+ }
+ else
+ { /* Use a SAVE_EXPR in combo with:
+ IF (expr.LT.0) THEN GOTO neg
+ ELSEIF (expr.GT.0) THEN GOTO pos
+ ELSE GOTO zero. */
+ tree expr_saved = ffecom_save_tree (ffecom_expr (expr));
+
+ texpr = ffecom_2 (LT_EXPR, integer_type_node,
+ expr_saved,
+ convert (TREE_TYPE (expr_saved),
+ integer_zero_node));
+ expand_start_cond (ffecom_truth_value (texpr), 0);
+ expand_goto (gneg);
+ texpr = ffecom_2 (GT_EXPR, integer_type_node,
+ expr_saved,
+ convert (TREE_TYPE (expr_saved),
+ integer_zero_node));
+ expand_start_elseif (ffecom_truth_value (texpr));
+ expand_goto (gpos);
+ expand_start_else ();
+ expand_goto (gzero);
+ expand_end_cond ();
+ }
+ ffeste_emit_line_note_ ();
+
+ ffecom_pop_calltemps ();
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R841 -- CONTINUE statement
+
+ ffeste_R841(); */
+
+void
+ffeste_R841 ()
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ CONTINUE\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_emit_line_note_ ();
+ emit_nop ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R842 -- STOP statement
+
+ ffeste_R842(expr); */
+
+void
+ffeste_R842 (ffebld expr)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if (expr == NULL)
+ {
+ fputs ("+ STOP\n", dmpout);
+ }
+ else
+ {
+ fputs ("+ STOP_coded ", dmpout);
+ ffebld_dump (expr);
+ fputc ('\n', dmpout);
+ }
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree callit;
+ ffelexToken msg;
+
+ ffeste_emit_line_note_ ();
+ if ((expr == NULL)
+ || (ffeinfo_basictype (ffebld_info (expr))
+ == FFEINFO_basictypeANY))
+ {
+ msg = ffelex_token_new_character ("", ffelex_token_where_line
+ (ffesta_tokens[0]), ffelex_token_where_column
+ (ffesta_tokens[0]));
+ expr = ffebld_new_conter (ffebld_constant_new_characterdefault
+ (msg));
+ ffelex_token_kill (msg);
+ ffebld_set_info (expr, ffeinfo_new (FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTERDEFAULT, 0, FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT, 0));
+ }
+ else if (ffeinfo_basictype (ffebld_info (expr))
+ == FFEINFO_basictypeINTEGER)
+ {
+ char num[50];
+
+ assert (ffebld_op (expr) == FFEBLD_opCONTER);
+ assert (ffeinfo_kindtype (ffebld_info (expr))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ sprintf (num, "%" ffetargetIntegerDefault_f "d",
+ ffebld_constant_integer1 (ffebld_conter (expr)));
+ msg = ffelex_token_new_character (num, ffelex_token_where_line
+ (ffesta_tokens[0]), ffelex_token_where_column
+ (ffesta_tokens[0]));
+ expr = ffebld_new_conter (ffebld_constant_new_characterdefault
+ (msg));
+ ffelex_token_kill (msg);
+ ffebld_set_info (expr, ffeinfo_new (FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTERDEFAULT, 0, FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT, 0));
+ }
+ else
+ {
+ assert (ffeinfo_basictype (ffebld_info (expr))
+ == FFEINFO_basictypeCHARACTER);
+ assert (ffebld_op (expr) == FFEBLD_opCONTER);
+ assert (ffeinfo_kindtype (ffebld_info (expr))
+ == FFEINFO_kindtypeCHARACTERDEFAULT);
+ }
+
+ ffecom_push_calltemps ();
+ callit = ffecom_call_gfrt (FFECOM_gfrtSTOP,
+ ffecom_list_ptr_to_expr (ffebld_new_item (expr, NULL)));
+ ffecom_pop_calltemps ();
+ TREE_SIDE_EFFECTS (callit) = 1;
+ expand_expr_stmt (callit);
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R843 -- PAUSE statement
+
+ ffeste_R843(expr,expr_token);
+
+ Make sure statement is valid here; implement. expr and expr_token are
+ both NULL if there was no expression. */
+
+void
+ffeste_R843 (ffebld expr)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if (expr == NULL)
+ {
+ fputs ("+ PAUSE\n", dmpout);
+ }
+ else
+ {
+ fputs ("+ PAUSE_coded ", dmpout);
+ ffebld_dump (expr);
+ fputc ('\n', dmpout);
+ }
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree callit;
+ ffelexToken msg;
+
+ ffeste_emit_line_note_ ();
+ if ((expr == NULL)
+ || (ffeinfo_basictype (ffebld_info (expr))
+ == FFEINFO_basictypeANY))
+ {
+ msg = ffelex_token_new_character ("", ffelex_token_where_line
+ (ffesta_tokens[0]), ffelex_token_where_column
+ (ffesta_tokens[0]));
+ expr = ffebld_new_conter (ffebld_constant_new_characterdefault
+ (msg));
+ ffelex_token_kill (msg);
+ ffebld_set_info (expr, ffeinfo_new (FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTERDEFAULT, 0, FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT, 0));
+ }
+ else if (ffeinfo_basictype (ffebld_info (expr))
+ == FFEINFO_basictypeINTEGER)
+ {
+ char num[50];
+
+ assert (ffebld_op (expr) == FFEBLD_opCONTER);
+ assert (ffeinfo_kindtype (ffebld_info (expr))
+ == FFEINFO_kindtypeINTEGERDEFAULT);
+ sprintf (num, "%" ffetargetIntegerDefault_f "d",
+ ffebld_constant_integer1 (ffebld_conter (expr)));
+ msg = ffelex_token_new_character (num, ffelex_token_where_line
+ (ffesta_tokens[0]), ffelex_token_where_column
+ (ffesta_tokens[0]));
+ expr = ffebld_new_conter (ffebld_constant_new_characterdefault
+ (msg));
+ ffelex_token_kill (msg);
+ ffebld_set_info (expr, ffeinfo_new (FFEINFO_basictypeCHARACTER,
+ FFEINFO_kindtypeCHARACTERDEFAULT, 0, FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT, 0));
+ }
+ else
+ {
+ assert (ffeinfo_basictype (ffebld_info (expr))
+ == FFEINFO_basictypeCHARACTER);
+ assert (ffebld_op (expr) == FFEBLD_opCONTER);
+ assert (ffeinfo_kindtype (ffebld_info (expr))
+ == FFEINFO_kindtypeCHARACTERDEFAULT);
+ }
+
+ ffecom_push_calltemps ();
+ callit = ffecom_call_gfrt (FFECOM_gfrtPAUSE,
+ ffecom_list_ptr_to_expr (ffebld_new_item (expr, NULL)));
+ ffecom_pop_calltemps ();
+ TREE_SIDE_EFFECTS (callit) = 1;
+ expand_expr_stmt (callit);
+ clear_momentary ();
+ }
+#if 0 /* Old approach for phantom g77 run-time
+ library. */
+ {
+ tree callit;
+
+ ffeste_emit_line_note_ ();
+ if (expr == NULL)
+ callit = ffecom_call_gfrt (FFECOM_gfrtPAUSENIL, NULL_TREE);
+ else if (ffeinfo_basictype (ffebld_info (expr))
+ == FFEINFO_basictypeINTEGER)
+ {
+ ffecom_push_calltemps ();
+ callit = ffecom_call_gfrt (FFECOM_gfrtPAUSEINT,
+ ffecom_list_ptr_to_expr (ffebld_new_item (expr, NULL)));
+ ffecom_pop_calltemps ();
+ }
+ else
+ {
+ if (ffeinfo_basictype (ffebld_info (expr))
+ != FFEINFO_basictypeCHARACTER)
+ break;
+ ffecom_push_calltemps ();
+ callit = ffecom_call_gfrt (FFECOM_gfrtPAUSECHAR,
+ ffecom_list_ptr_to_expr (ffebld_new_item (expr, NULL)));
+ ffecom_pop_calltemps ();
+ }
+ TREE_SIDE_EFFECTS (callit) = 1;
+ expand_expr_stmt (callit);
+ clear_momentary ();
+ }
+#endif
+#else
+#error
+#endif
+}
+
+/* ffeste_R904 -- OPEN statement
+
+ ffeste_R904();
+
+ Make sure an OPEN is valid in the current context, and implement it. */
+
+void
+ffeste_R904 (ffestpOpenStmt *info)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ OPEN (", dmpout);
+ ffeste_subr_file_ ("UNIT", &info->open_spec[FFESTP_openixUNIT]);
+ ffeste_subr_file_ ("ACCESS", &info->open_spec[FFESTP_openixACCESS]);
+ ffeste_subr_file_ ("ACTION", &info->open_spec[FFESTP_openixACTION]);
+ ffeste_subr_file_ ("ASSOCIATEVARIABLE", &info->open_spec[FFESTP_openixASSOCIATEVARIABLE]);
+ ffeste_subr_file_ ("BLANK", &info->open_spec[FFESTP_openixBLANK]);
+ ffeste_subr_file_ ("BLOCKSIZE", &info->open_spec[FFESTP_openixBLOCKSIZE]);
+ ffeste_subr_file_ ("BUFFERCOUNT", &info->open_spec[FFESTP_openixBUFFERCOUNT]);
+ ffeste_subr_file_ ("CARRIAGECONTROL", &info->open_spec[FFESTP_openixCARRIAGECONTROL]);
+ ffeste_subr_file_ ("DEFAULTFILE", &info->open_spec[FFESTP_openixDEFAULTFILE]);
+ ffeste_subr_file_ ("DELIM", &info->open_spec[FFESTP_openixDELIM]);
+ ffeste_subr_file_ ("DISPOSE", &info->open_spec[FFESTP_openixDISPOSE]);
+ ffeste_subr_file_ ("ERR", &info->open_spec[FFESTP_openixERR]);
+ ffeste_subr_file_ ("EXTENDSIZE", &info->open_spec[FFESTP_openixEXTENDSIZE]);
+ ffeste_subr_file_ ("FILE", &info->open_spec[FFESTP_openixFILE]);
+ ffeste_subr_file_ ("FORM", &info->open_spec[FFESTP_openixFORM]);
+ ffeste_subr_file_ ("INITIALSIZE", &info->open_spec[FFESTP_openixINITIALSIZE]);
+ ffeste_subr_file_ ("IOSTAT", &info->open_spec[FFESTP_openixIOSTAT]);
+ ffeste_subr_file_ ("KEY", &info->open_spec[FFESTP_openixKEY]);
+ ffeste_subr_file_ ("MAXREC", &info->open_spec[FFESTP_openixMAXREC]);
+ ffeste_subr_file_ ("NOSPANBLOCKS", &info->open_spec[FFESTP_openixNOSPANBLOCKS]);
+ ffeste_subr_file_ ("ORGANIZATION", &info->open_spec[FFESTP_openixORGANIZATION]);
+ ffeste_subr_file_ ("PAD", &info->open_spec[FFESTP_openixPAD]);
+ ffeste_subr_file_ ("POSITION", &info->open_spec[FFESTP_openixPOSITION]);
+ ffeste_subr_file_ ("READONLY", &info->open_spec[FFESTP_openixREADONLY]);
+ ffeste_subr_file_ ("RECL", &info->open_spec[FFESTP_openixRECL]);
+ ffeste_subr_file_ ("RECORDTYPE", &info->open_spec[FFESTP_openixRECORDTYPE]);
+ ffeste_subr_file_ ("SHARED", &info->open_spec[FFESTP_openixSHARED]);
+ ffeste_subr_file_ ("STATUS", &info->open_spec[FFESTP_openixSTATUS]);
+ ffeste_subr_file_ ("USEROPEN", &info->open_spec[FFESTP_openixUSEROPEN]);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree args;
+ bool iostat;
+ bool errl;
+
+#define specified(something) (info->open_spec[something].kw_or_val_present)
+
+ ffeste_emit_line_note_ ();
+
+ iostat = specified (FFESTP_openixIOSTAT);
+ errl = specified (FFESTP_openixERR);
+
+ ffecom_push_calltemps ();
+
+ args = ffeste_io_olist_ (errl || iostat,
+ info->open_spec[FFESTP_openixUNIT].u.expr,
+ &info->open_spec[FFESTP_openixFILE],
+ &info->open_spec[FFESTP_openixSTATUS],
+ &info->open_spec[FFESTP_openixACCESS],
+ &info->open_spec[FFESTP_openixFORM],
+ &info->open_spec[FFESTP_openixRECL],
+ &info->open_spec[FFESTP_openixBLANK]);
+
+ if (errl)
+ {
+ ffeste_io_err_
+ = ffeste_io_abort_
+ = ffecom_lookup_label
+ (info->open_spec[FFESTP_openixERR].u.label);
+ ffeste_io_abort_is_temp_ = FALSE;
+ }
+ else
+ {
+ ffeste_io_err_ = NULL_TREE;
+
+ if ((ffeste_io_abort_is_temp_ = iostat))
+ ffeste_io_abort_ = ffecom_temp_label ();
+ else
+ ffeste_io_abort_ = NULL_TREE;
+ }
+
+ if (iostat)
+ { /* IOSTAT= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = ffecom_expr
+ (info->open_spec[FFESTP_openixIOSTAT].u.expr);
+ }
+ else if (ffeste_io_abort_ != NULL_TREE)
+ { /* no IOSTAT= but ERR= */
+ ffeste_io_iostat_is_temp_ = TRUE;
+ ffeste_io_iostat_
+ = ffecom_push_tempvar (ffecom_integer_type_node,
+ FFETARGET_charactersizeNONE, -1, FALSE);
+ }
+ else
+ { /* no IOSTAT=, or ERR= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = NULL_TREE;
+ }
+
+ /* Don't generate "if (iostat != 0) goto label;" if label is temp abort
+ label, since we're gonna fall through to there anyway. */
+
+ ffeste_io_call_ (ffecom_call_gfrt (FFECOM_gfrtFOPEN, args),
+ !ffeste_io_abort_is_temp_);
+
+ /* If we've got a temp label, generate its code here. */
+
+ if (ffeste_io_abort_is_temp_)
+ {
+ DECL_INITIAL (ffeste_io_abort_) = error_mark_node;
+ emit_nop ();
+ expand_label (ffeste_io_abort_);
+
+ assert (ffeste_io_err_ == NULL_TREE);
+ }
+
+ /* If we've got a temp iostat, pop the temp. */
+
+ if (ffeste_io_iostat_is_temp_)
+ ffecom_pop_tempvar (ffeste_io_iostat_);
+
+ ffecom_pop_calltemps ();
+
+#undef specified
+ }
+
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R907 -- CLOSE statement
+
+ ffeste_R907();
+
+ Make sure a CLOSE is valid in the current context, and implement it. */
+
+void
+ffeste_R907 (ffestpCloseStmt *info)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ CLOSE (", dmpout);
+ ffeste_subr_file_ ("UNIT", &info->close_spec[FFESTP_closeixUNIT]);
+ ffeste_subr_file_ ("ERR", &info->close_spec[FFESTP_closeixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->close_spec[FFESTP_closeixIOSTAT]);
+ ffeste_subr_file_ ("STATUS", &info->close_spec[FFESTP_closeixSTATUS]);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree args;
+ bool iostat;
+ bool errl;
+
+#define specified(something) (info->close_spec[something].kw_or_val_present)
+
+ ffeste_emit_line_note_ ();
+
+ iostat = specified (FFESTP_closeixIOSTAT);
+ errl = specified (FFESTP_closeixERR);
+
+ ffecom_push_calltemps ();
+
+ args = ffeste_io_cllist_ (errl || iostat,
+ info->close_spec[FFESTP_closeixUNIT].u.expr,
+ &info->close_spec[FFESTP_closeixSTATUS]);
+
+ if (errl)
+ {
+ ffeste_io_err_
+ = ffeste_io_abort_
+ = ffecom_lookup_label
+ (info->close_spec[FFESTP_closeixERR].u.label);
+ ffeste_io_abort_is_temp_ = FALSE;
+ }
+ else
+ {
+ ffeste_io_err_ = NULL_TREE;
+
+ if ((ffeste_io_abort_is_temp_ = iostat))
+ ffeste_io_abort_ = ffecom_temp_label ();
+ else
+ ffeste_io_abort_ = NULL_TREE;
+ }
+
+ if (iostat)
+ { /* IOSTAT= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = ffecom_expr
+ (info->close_spec[FFESTP_closeixIOSTAT].u.expr);
+ }
+ else if (ffeste_io_abort_ != NULL_TREE)
+ { /* no IOSTAT= but ERR= */
+ ffeste_io_iostat_is_temp_ = TRUE;
+ ffeste_io_iostat_
+ = ffecom_push_tempvar (ffecom_integer_type_node,
+ FFETARGET_charactersizeNONE, -1, FALSE);
+ }
+ else
+ { /* no IOSTAT=, or ERR= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = NULL_TREE;
+ }
+
+ /* Don't generate "if (iostat != 0) goto label;" if label is temp abort
+ label, since we're gonna fall through to there anyway. */
+
+ ffeste_io_call_ (ffecom_call_gfrt (FFECOM_gfrtFCLOS, args),
+ !ffeste_io_abort_is_temp_);
+
+ /* If we've got a temp label, generate its code here. */
+
+ if (ffeste_io_abort_is_temp_)
+ {
+ DECL_INITIAL (ffeste_io_abort_) = error_mark_node;
+ emit_nop ();
+ expand_label (ffeste_io_abort_);
+
+ assert (ffeste_io_err_ == NULL_TREE);
+ }
+
+ /* If we've got a temp iostat, pop the temp. */
+
+ if (ffeste_io_iostat_is_temp_)
+ ffecom_pop_tempvar (ffeste_io_iostat_);
+
+ ffecom_pop_calltemps ();
+
+#undef specified
+ }
+
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R909_start -- READ(...) statement list begin
+
+ ffeste_R909_start(FALSE);
+
+ Verify that READ is valid here, and begin accepting items in the
+ list. */
+
+void
+ffeste_R909_start (ffestpReadStmt *info, bool only_format UNUSED,
+ ffestvUnit unit, ffestvFormat format, bool rec,
+ bool key UNUSED)
+{
+ ffeste_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ switch (format)
+ {
+ case FFESTV_formatNONE:
+ if (rec)
+ fputs ("+ READ_ufdac", dmpout);
+ else if (key)
+ fputs ("+ READ_ufidx", dmpout);
+ else
+ fputs ("+ READ_ufseq", dmpout);
+ break;
+
+ case FFESTV_formatLABEL:
+ case FFESTV_formatCHAREXPR:
+ case FFESTV_formatINTEXPR:
+ if (rec)
+ fputs ("+ READ_fmdac", dmpout);
+ else if (key)
+ fputs ("+ READ_fmidx", dmpout);
+ else if (unit == FFESTV_unitCHAREXPR)
+ fputs ("+ READ_fmint", dmpout);
+ else
+ fputs ("+ READ_fmseq", dmpout);
+ break;
+
+ case FFESTV_formatASTERISK:
+ if (unit == FFESTV_unitCHAREXPR)
+ fputs ("+ READ_lsint", dmpout);
+ else
+ fputs ("+ READ_lsseq", dmpout);
+ break;
+
+ case FFESTV_formatNAMELIST:
+ fputs ("+ READ_nlseq", dmpout);
+ break;
+
+ default:
+ assert ("Unexpected kind of format item in R909 READ" == NULL);
+ }
+
+ if (only_format)
+ {
+ fputc (' ', dmpout);
+ ffeste_subr_file_ ("FORMAT", &info->read_spec[FFESTP_readixFORMAT]);
+ fputc (' ', dmpout);
+
+ return;
+ }
+
+ fputs (" (", dmpout);
+ ffeste_subr_file_ ("UNIT", &info->read_spec[FFESTP_readixUNIT]);
+ ffeste_subr_file_ ("FORMAT", &info->read_spec[FFESTP_readixFORMAT]);
+ ffeste_subr_file_ ("ADVANCE", &info->read_spec[FFESTP_readixADVANCE]);
+ ffeste_subr_file_ ("EOR", &info->read_spec[FFESTP_readixEOR]);
+ ffeste_subr_file_ ("ERR", &info->read_spec[FFESTP_readixERR]);
+ ffeste_subr_file_ ("END", &info->read_spec[FFESTP_readixEND]);
+ ffeste_subr_file_ ("IOSTAT", &info->read_spec[FFESTP_readixIOSTAT]);
+ ffeste_subr_file_ ("KEYEQ", &info->read_spec[FFESTP_readixKEYEQ]);
+ ffeste_subr_file_ ("KEYGE", &info->read_spec[FFESTP_readixKEYGE]);
+ ffeste_subr_file_ ("KEYGT", &info->read_spec[FFESTP_readixKEYGT]);
+ ffeste_subr_file_ ("KEYID", &info->read_spec[FFESTP_readixKEYID]);
+ ffeste_subr_file_ ("NULLS", &info->read_spec[FFESTP_readixNULLS]);
+ ffeste_subr_file_ ("REC", &info->read_spec[FFESTP_readixREC]);
+ ffeste_subr_file_ ("SIZE", &info->read_spec[FFESTP_readixSIZE]);
+ fputs (") ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+
+#define specified(something) (info->read_spec[something].kw_or_val_present)
+
+ ffeste_emit_line_note_ ();
+
+ /* Do the real work. */
+
+ {
+ ffecomGfrt start;
+ ffecomGfrt end;
+ tree cilist;
+ bool iostat;
+ bool errl;
+ bool endl;
+
+ /* First determine the start, per-item, and end run-time functions to
+ call. The per-item function is picked by choosing an ffeste functio
+ to call to handle a given item; it knows how to generate a call to the
+ appropriate run-time function, and is called an "io driver". It
+ handles the implied-DO construct, for example. */
+
+ switch (format)
+ {
+ case FFESTV_formatNONE: /* no FMT= */
+ ffeste_io_driver_ = ffeste_io_douio_;
+ if (rec)
+ start = FFECOM_gfrtSRDUE, end = FFECOM_gfrtERDUE;
+#if 0
+ else if (key)
+ start = FFECOM_gfrtSRIUE, end = FFECOM_gfrtERIUE;
+#endif
+ else
+ start = FFECOM_gfrtSRSUE, end = FFECOM_gfrtERSUE;
+ break;
+
+ case FFESTV_formatLABEL: /* FMT=10 */
+ case FFESTV_formatCHAREXPR: /* FMT='(I10)' */
+ case FFESTV_formatINTEXPR: /* FMT=I [after ASSIGN 10 TO I] */
+ ffeste_io_driver_ = ffeste_io_dofio_;
+ if (rec)
+ start = FFECOM_gfrtSRDFE, end = FFECOM_gfrtERDFE;
+#if 0
+ else if (key)
+ start = FFECOM_gfrtSRIFE, end = FFECOM_gfrtERIFE;
+#endif
+ else if (unit == FFESTV_unitCHAREXPR)
+ start = FFECOM_gfrtSRSFI, end = FFECOM_gfrtERSFI;
+ else
+ start = FFECOM_gfrtSRSFE, end = FFECOM_gfrtERSFE;
+ break;
+
+ case FFESTV_formatASTERISK: /* FMT=* */
+ ffeste_io_driver_ = ffeste_io_dolio_;
+ if (unit == FFESTV_unitCHAREXPR)
+ start = FFECOM_gfrtSRSLI, end = FFECOM_gfrtERSLI;
+ else
+ start = FFECOM_gfrtSRSLE, end = FFECOM_gfrtERSLE;
+ break;
+
+ case FFESTV_formatNAMELIST: /* FMT=FOO or NML=FOO [NAMELIST
+ /FOO/] */
+ ffeste_io_driver_ = NULL; /* No start or driver function. */
+ start = FFECOM_gfrtSRSNE, end = FFECOM_gfrt;
+ break;
+
+ default:
+ assert ("Weird stuff" == NULL);
+ start = FFECOM_gfrt, end = FFECOM_gfrt;
+ break;
+ }
+ ffeste_io_endgfrt_ = end;
+
+ iostat = specified (FFESTP_readixIOSTAT);
+ errl = specified (FFESTP_readixERR);
+ endl = specified (FFESTP_readixEND);
+
+ ffecom_push_calltemps ();
+
+ if (unit == FFESTV_unitCHAREXPR)
+ {
+ cilist = ffeste_io_icilist_ (errl || iostat,
+ info->read_spec[FFESTP_readixUNIT].u.expr,
+ endl || iostat, format,
+ &info->read_spec[FFESTP_readixFORMAT]);
+ }
+ else
+ {
+ cilist = ffeste_io_cilist_ (errl || iostat, unit,
+ info->read_spec[FFESTP_readixUNIT].u.expr,
+ 5, endl || iostat, format,
+ &info->read_spec[FFESTP_readixFORMAT],
+ rec,
+ info->read_spec[FFESTP_readixREC].u.expr);
+ }
+
+ if (errl)
+ { /* ERR= */
+ ffeste_io_err_
+ = ffecom_lookup_label
+ (info->read_spec[FFESTP_readixERR].u.label);
+
+ if (endl)
+ { /* ERR= END= */
+ ffeste_io_end_
+ = ffecom_lookup_label
+ (info->read_spec[FFESTP_readixEND].u.label);
+ ffeste_io_abort_is_temp_ = TRUE;
+ ffeste_io_abort_ = ffecom_temp_label ();
+ }
+ else
+ { /* ERR= but no END= */
+ ffeste_io_end_ = NULL_TREE;
+ if ((ffeste_io_abort_is_temp_ = iostat))
+ ffeste_io_abort_ = ffecom_temp_label ();
+ else
+ ffeste_io_abort_ = ffeste_io_err_;
+ }
+ }
+ else
+ { /* no ERR= */
+ ffeste_io_err_ = NULL_TREE;
+ if (endl)
+ { /* END= but no ERR= */
+ ffeste_io_end_
+ = ffecom_lookup_label
+ (info->read_spec[FFESTP_readixEND].u.label);
+ if ((ffeste_io_abort_is_temp_ = iostat))
+ ffeste_io_abort_ = ffecom_temp_label ();
+ else
+ ffeste_io_abort_ = ffeste_io_end_;
+ }
+ else
+ { /* no ERR= or END= */
+ ffeste_io_end_ = NULL_TREE;
+ if ((ffeste_io_abort_is_temp_ = iostat))
+ ffeste_io_abort_ = ffecom_temp_label ();
+ else
+ ffeste_io_abort_ = NULL_TREE;
+ }
+ }
+
+ if (iostat)
+ { /* IOSTAT= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = ffecom_expr
+ (info->read_spec[FFESTP_readixIOSTAT].u.expr);
+ }
+ else if (ffeste_io_abort_ != NULL_TREE)
+ { /* no IOSTAT= but ERR= or END= or both */
+ ffeste_io_iostat_is_temp_ = TRUE;
+ ffeste_io_iostat_
+ = ffecom_push_tempvar (ffecom_integer_type_node,
+ FFETARGET_charactersizeNONE, -1, FALSE);
+ }
+ else
+ { /* no IOSTAT=, ERR=, or END= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = NULL_TREE;
+ }
+
+ /* If there is no end function, then there are no item functions (i.e.
+ it's a NAMELIST), and vice versa by the way. In this situation, don't
+ generate the "if (iostat != 0) goto label;" if the label is temp abort
+ label, since we're gonna fall through to there anyway. */
+
+ ffeste_io_call_ (ffecom_call_gfrt (start, cilist),
+ !ffeste_io_abort_is_temp_ || (end != FFECOM_gfrt));
+ }
+
+#undef specified
+
+ push_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R909_item -- READ statement i/o item
+
+ ffeste_R909_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffeste_R909_item (ffebld expr, ffelexToken expr_token)
+{
+ ffeste_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (expr);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ if (expr == NULL)
+ return;
+ while (ffebld_op (expr) == FFEBLD_opPAREN)
+ expr = ffebld_left (expr); /* "READ *,(A)" -- really a bug in the user's
+ code, but I've been told lots of code does
+ this (blech)! */
+ if (ffebld_op (expr) == FFEBLD_opANY)
+ return;
+ if (ffebld_op (expr) == FFEBLD_opIMPDO)
+ ffeste_io_impdo_ (expr, expr_token);
+ else
+ ffeste_io_call_ ((*ffeste_io_driver_) (expr), TRUE);
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R909_finish -- READ statement list complete
+
+ ffeste_R909_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffeste_R909_finish ()
+{
+ ffeste_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+
+ /* Don't generate "if (iostat != 0) goto label;" if label is temp abort
+ label, since we're gonna fall through to there anyway. */
+
+ {
+ if (ffeste_io_endgfrt_ != FFECOM_gfrt)
+ ffeste_io_call_ (ffecom_call_gfrt (ffeste_io_endgfrt_, NULL_TREE),
+ !ffeste_io_abort_is_temp_);
+
+ clear_momentary ();
+ pop_momentary ();
+
+ /* If we've got a temp label, generate its code here and have it fan out
+ to the END= or ERR= label as appropriate. */
+
+ if (ffeste_io_abort_is_temp_)
+ {
+ DECL_INITIAL (ffeste_io_abort_) = error_mark_node;
+ emit_nop ();
+ expand_label (ffeste_io_abort_);
+
+ /* if (iostat<0) goto end_label; */
+
+ if ((ffeste_io_end_ != NULL_TREE)
+ && (TREE_CODE (ffeste_io_end_) != ERROR_MARK))
+ {
+ expand_start_cond (ffecom_truth_value
+ (ffecom_2 (LT_EXPR, integer_type_node,
+ ffeste_io_iostat_,
+ ffecom_integer_zero_node)),
+ 0);
+ expand_goto (ffeste_io_end_);
+ expand_end_cond ();
+ }
+
+ /* if (iostat>0) goto err_label; */
+
+ if ((ffeste_io_err_ != NULL_TREE)
+ && (TREE_CODE (ffeste_io_err_) != ERROR_MARK))
+ {
+ expand_start_cond (ffecom_truth_value
+ (ffecom_2 (GT_EXPR, integer_type_node,
+ ffeste_io_iostat_,
+ ffecom_integer_zero_node)),
+ 0);
+ expand_goto (ffeste_io_err_);
+ expand_end_cond ();
+ }
+
+ }
+
+ /* If we've got a temp iostat, pop the temp. */
+
+ if (ffeste_io_iostat_is_temp_)
+ ffecom_pop_tempvar (ffeste_io_iostat_);
+
+ ffecom_pop_calltemps ();
+
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R910_start -- WRITE(...) statement list begin
+
+ ffeste_R910_start();
+
+ Verify that WRITE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffeste_R910_start (ffestpWriteStmt *info, ffestvUnit unit,
+ ffestvFormat format, bool rec)
+{
+ ffeste_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ switch (format)
+ {
+ case FFESTV_formatNONE:
+ if (rec)
+ fputs ("+ WRITE_ufdac (", dmpout);
+ else
+ fputs ("+ WRITE_ufseq_or_idx (", dmpout);
+ break;
+
+ case FFESTV_formatLABEL:
+ case FFESTV_formatCHAREXPR:
+ case FFESTV_formatINTEXPR:
+ if (rec)
+ fputs ("+ WRITE_fmdac (", dmpout);
+ else if (unit == FFESTV_unitCHAREXPR)
+ fputs ("+ WRITE_fmint (", dmpout);
+ else
+ fputs ("+ WRITE_fmseq_or_idx (", dmpout);
+ break;
+
+ case FFESTV_formatASTERISK:
+ if (unit == FFESTV_unitCHAREXPR)
+ fputs ("+ WRITE_lsint (", dmpout);
+ else
+ fputs ("+ WRITE_lsseq (", dmpout);
+ break;
+
+ case FFESTV_formatNAMELIST:
+ fputs ("+ WRITE_nlseq (", dmpout);
+ break;
+
+ default:
+ assert ("Unexpected kind of format item in R910 WRITE" == NULL);
+ }
+
+ ffeste_subr_file_ ("UNIT", &info->write_spec[FFESTP_writeixUNIT]);
+ ffeste_subr_file_ ("FORMAT", &info->write_spec[FFESTP_writeixFORMAT]);
+ ffeste_subr_file_ ("ADVANCE", &info->write_spec[FFESTP_writeixADVANCE]);
+ ffeste_subr_file_ ("EOR", &info->write_spec[FFESTP_writeixEOR]);
+ ffeste_subr_file_ ("ERR", &info->write_spec[FFESTP_writeixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->write_spec[FFESTP_writeixIOSTAT]);
+ ffeste_subr_file_ ("REC", &info->write_spec[FFESTP_writeixREC]);
+ fputs (") ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+
+#define specified(something) (info->write_spec[something].kw_or_val_present)
+
+ ffeste_emit_line_note_ ();
+
+ /* Do the real work. */
+
+ {
+ ffecomGfrt start;
+ ffecomGfrt end;
+ tree cilist;
+ bool iostat;
+ bool errl;
+
+ /* First determine the start, per-item, and end run-time functions to
+ call. The per-item function is picked by choosing an ffeste functio
+ to call to handle a given item; it knows how to generate a call to the
+ appropriate run-time function, and is called an "io driver". It
+ handles the implied-DO construct, for example. */
+
+ switch (format)
+ {
+ case FFESTV_formatNONE: /* no FMT= */
+ ffeste_io_driver_ = ffeste_io_douio_;
+ if (rec)
+ start = FFECOM_gfrtSWDUE, end = FFECOM_gfrtEWDUE;
+ else
+ start = FFECOM_gfrtSWSUE, end = FFECOM_gfrtEWSUE;
+ break;
+
+ case FFESTV_formatLABEL: /* FMT=10 */
+ case FFESTV_formatCHAREXPR: /* FMT='(I10)' */
+ case FFESTV_formatINTEXPR: /* FMT=I [after ASSIGN 10 TO I] */
+ ffeste_io_driver_ = ffeste_io_dofio_;
+ if (rec)
+ start = FFECOM_gfrtSWDFE, end = FFECOM_gfrtEWDFE;
+ else if (unit == FFESTV_unitCHAREXPR)
+ start = FFECOM_gfrtSWSFI, end = FFECOM_gfrtEWSFI;
+ else
+ start = FFECOM_gfrtSWSFE, end = FFECOM_gfrtEWSFE;
+ break;
+
+ case FFESTV_formatASTERISK: /* FMT=* */
+ ffeste_io_driver_ = ffeste_io_dolio_;
+ if (unit == FFESTV_unitCHAREXPR)
+ start = FFECOM_gfrtSWSLI, end = FFECOM_gfrtEWSLI;
+ else
+ start = FFECOM_gfrtSWSLE, end = FFECOM_gfrtEWSLE;
+ break;
+
+ case FFESTV_formatNAMELIST: /* FMT=FOO or NML=FOO [NAMELIST
+ /FOO/] */
+ ffeste_io_driver_ = NULL; /* No start or driver function. */
+ start = FFECOM_gfrtSWSNE, end = FFECOM_gfrt;
+ break;
+
+ default:
+ assert ("Weird stuff" == NULL);
+ start = FFECOM_gfrt, end = FFECOM_gfrt;
+ break;
+ }
+ ffeste_io_endgfrt_ = end;
+
+ iostat = specified (FFESTP_writeixIOSTAT);
+ errl = specified (FFESTP_writeixERR);
+
+ ffecom_push_calltemps ();
+
+ if (unit == FFESTV_unitCHAREXPR)
+ {
+ cilist = ffeste_io_icilist_ (errl || iostat,
+ info->write_spec[FFESTP_writeixUNIT].u.expr,
+ FALSE, format,
+ &info->write_spec[FFESTP_writeixFORMAT]);
+ }
+ else
+ {
+ cilist = ffeste_io_cilist_ (errl || iostat, unit,
+ info->write_spec[FFESTP_writeixUNIT].u.expr,
+ 6, FALSE, format,
+ &info->write_spec[FFESTP_writeixFORMAT],
+ rec,
+ info->write_spec[FFESTP_writeixREC].u.expr);
+ }
+
+ ffeste_io_end_ = NULL_TREE;
+
+ if (errl)
+ { /* ERR= */
+ ffeste_io_err_
+ = ffeste_io_abort_
+ = ffecom_lookup_label
+ (info->write_spec[FFESTP_writeixERR].u.label);
+ ffeste_io_abort_is_temp_ = FALSE;
+ }
+ else
+ { /* no ERR= */
+ ffeste_io_err_ = NULL_TREE;
+
+ if ((ffeste_io_abort_is_temp_ = iostat))
+ ffeste_io_abort_ = ffecom_temp_label ();
+ else
+ ffeste_io_abort_ = NULL_TREE;
+ }
+
+ if (iostat)
+ { /* IOSTAT= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = ffecom_expr
+ (info->write_spec[FFESTP_writeixIOSTAT].u.expr);
+ }
+ else if (ffeste_io_abort_ != NULL_TREE)
+ { /* no IOSTAT= but ERR= */
+ ffeste_io_iostat_is_temp_ = TRUE;
+ ffeste_io_iostat_
+ = ffecom_push_tempvar (ffecom_integer_type_node,
+ FFETARGET_charactersizeNONE, -1, FALSE);
+ }
+ else
+ { /* no IOSTAT=, or ERR= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = NULL_TREE;
+ }
+
+ /* If there is no end function, then there are no item functions (i.e.
+ it's a NAMELIST), and vice versa by the way. In this situation, don't
+ generate the "if (iostat != 0) goto label;" if the label is temp abort
+ label, since we're gonna fall through to there anyway. */
+
+ ffeste_io_call_ (ffecom_call_gfrt (start, cilist),
+ !ffeste_io_abort_is_temp_ || (end != FFECOM_gfrt));
+ }
+
+#undef specified
+
+ push_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R910_item -- WRITE statement i/o item
+
+ ffeste_R910_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffeste_R910_item (ffebld expr, ffelexToken expr_token)
+{
+ ffeste_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (expr);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ if (expr == NULL)
+ return;
+ if (ffebld_op (expr) == FFEBLD_opANY)
+ return;
+ if (ffebld_op (expr) == FFEBLD_opIMPDO)
+ ffeste_io_impdo_ (expr, expr_token);
+ else
+ ffeste_io_call_ ((*ffeste_io_driver_) (expr), TRUE);
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R910_finish -- WRITE statement list complete
+
+ ffeste_R910_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffeste_R910_finish ()
+{
+ ffeste_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+
+ /* Don't generate "if (iostat != 0) goto label;" if label is temp abort
+ label, since we're gonna fall through to there anyway. */
+
+ {
+ if (ffeste_io_endgfrt_ != FFECOM_gfrt)
+ ffeste_io_call_ (ffecom_call_gfrt (ffeste_io_endgfrt_, NULL_TREE),
+ !ffeste_io_abort_is_temp_);
+
+ clear_momentary ();
+ pop_momentary ();
+
+ /* If we've got a temp label, generate its code here. */
+
+ if (ffeste_io_abort_is_temp_)
+ {
+ DECL_INITIAL (ffeste_io_abort_) = error_mark_node;
+ emit_nop ();
+ expand_label (ffeste_io_abort_);
+
+ assert (ffeste_io_err_ == NULL_TREE);
+ }
+
+ /* If we've got a temp iostat, pop the temp. */
+
+ if (ffeste_io_iostat_is_temp_)
+ ffecom_pop_tempvar (ffeste_io_iostat_);
+
+ ffecom_pop_calltemps ();
+
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R911_start -- PRINT statement list begin
+
+ ffeste_R911_start();
+
+ Verify that PRINT is valid here, and begin accepting items in the
+ list. */
+
+void
+ffeste_R911_start (ffestpPrintStmt *info, ffestvFormat format)
+{
+ ffeste_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ switch (format)
+ {
+ case FFESTV_formatLABEL:
+ case FFESTV_formatCHAREXPR:
+ case FFESTV_formatINTEXPR:
+ fputs ("+ PRINT_fm ", dmpout);
+ break;
+
+ case FFESTV_formatASTERISK:
+ fputs ("+ PRINT_ls ", dmpout);
+ break;
+
+ case FFESTV_formatNAMELIST:
+ fputs ("+ PRINT_nl ", dmpout);
+ break;
+
+ default:
+ assert ("Unexpected kind of format item in R911 PRINT" == NULL);
+ }
+ ffeste_subr_file_ ("FORMAT", &info->print_spec[FFESTP_printixFORMAT]);
+ fputc (' ', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+
+ ffeste_emit_line_note_ ();
+
+ /* Do the real work. */
+
+ {
+ ffecomGfrt start;
+ ffecomGfrt end;
+ tree cilist;
+
+ /* First determine the start, per-item, and end run-time functions to
+ call. The per-item function is picked by choosing an ffeste functio
+ to call to handle a given item; it knows how to generate a call to the
+ appropriate run-time function, and is called an "io driver". It
+ handles the implied-DO construct, for example. */
+
+ switch (format)
+ {
+ case FFESTV_formatLABEL: /* FMT=10 */
+ case FFESTV_formatCHAREXPR: /* FMT='(I10)' */
+ case FFESTV_formatINTEXPR: /* FMT=I [after ASSIGN 10 TO I] */
+ ffeste_io_driver_ = ffeste_io_dofio_;
+ start = FFECOM_gfrtSWSFE, end = FFECOM_gfrtEWSFE;
+ break;
+
+ case FFESTV_formatASTERISK: /* FMT=* */
+ ffeste_io_driver_ = ffeste_io_dolio_;
+ start = FFECOM_gfrtSWSLE, end = FFECOM_gfrtEWSLE;
+ break;
+
+ case FFESTV_formatNAMELIST: /* FMT=FOO or NML=FOO [NAMELIST
+ /FOO/] */
+ ffeste_io_driver_ = NULL; /* No start or driver function. */
+ start = FFECOM_gfrtSWSNE, end = FFECOM_gfrt;
+ break;
+
+ default:
+ assert ("Weird stuff" == NULL);
+ start = FFECOM_gfrt, end = FFECOM_gfrt;
+ break;
+ }
+ ffeste_io_endgfrt_ = end;
+
+ ffecom_push_calltemps ();
+
+ cilist = ffeste_io_cilist_ (FALSE, FFESTV_unitNONE, NULL, 6, FALSE, format,
+ &info->print_spec[FFESTP_printixFORMAT], FALSE, NULL);
+
+ ffeste_io_end_ = NULL_TREE;
+ ffeste_io_err_ = NULL_TREE;
+ ffeste_io_abort_ = NULL_TREE;
+ ffeste_io_abort_is_temp_ = FALSE;
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = NULL_TREE;
+
+ /* If there is no end function, then there are no item functions (i.e.
+ it's a NAMELIST), and vice versa by the way. In this situation, don't
+ generate the "if (iostat != 0) goto label;" if the label is temp abort
+ label, since we're gonna fall through to there anyway. */
+
+ ffeste_io_call_ (ffecom_call_gfrt (start, cilist),
+ !ffeste_io_abort_is_temp_ || (end != FFECOM_gfrt));
+ }
+
+ push_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R911_item -- PRINT statement i/o item
+
+ ffeste_R911_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffeste_R911_item (ffebld expr, ffelexToken expr_token)
+{
+ ffeste_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (expr);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ if (expr == NULL)
+ return;
+ if (ffebld_op (expr) == FFEBLD_opANY)
+ return;
+ if (ffebld_op (expr) == FFEBLD_opIMPDO)
+ ffeste_io_impdo_ (expr, expr_token);
+ else
+ ffeste_io_call_ ((*ffeste_io_driver_) (expr), FALSE);
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R911_finish -- PRINT statement list complete
+
+ ffeste_R911_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffeste_R911_finish ()
+{
+ ffeste_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ if (ffeste_io_endgfrt_ != FFECOM_gfrt)
+ ffeste_io_call_ (ffecom_call_gfrt (ffeste_io_endgfrt_, NULL_TREE),
+ FALSE);
+
+ ffecom_pop_calltemps ();
+
+ clear_momentary ();
+ pop_momentary ();
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R919 -- BACKSPACE statement
+
+ ffeste_R919();
+
+ Make sure a BACKSPACE is valid in the current context, and implement it. */
+
+void
+ffeste_R919 (ffestpBeruStmt *info)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ BACKSPACE (", dmpout);
+ ffeste_subr_file_ ("UNIT", &info->beru_spec[FFESTP_beruixUNIT]);
+ ffeste_subr_file_ ("ERR", &info->beru_spec[FFESTP_beruixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->beru_spec[FFESTP_beruixIOSTAT]);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_subr_beru_ (info, FFECOM_gfrtFBACK);
+#else
+#error
+#endif
+}
+
+/* ffeste_R920 -- ENDFILE statement
+
+ ffeste_R920();
+
+ Make sure a ENDFILE is valid in the current context, and implement it. */
+
+void
+ffeste_R920 (ffestpBeruStmt *info)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ ENDFILE (", dmpout);
+ ffeste_subr_file_ ("UNIT", &info->beru_spec[FFESTP_beruixUNIT]);
+ ffeste_subr_file_ ("ERR", &info->beru_spec[FFESTP_beruixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->beru_spec[FFESTP_beruixIOSTAT]);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_subr_beru_ (info, FFECOM_gfrtFEND);
+#else
+#error
+#endif
+}
+
+/* ffeste_R921 -- REWIND statement
+
+ ffeste_R921();
+
+ Make sure a REWIND is valid in the current context, and implement it. */
+
+void
+ffeste_R921 (ffestpBeruStmt *info)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ REWIND (", dmpout);
+ ffeste_subr_file_ ("UNIT", &info->beru_spec[FFESTP_beruixUNIT]);
+ ffeste_subr_file_ ("ERR", &info->beru_spec[FFESTP_beruixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->beru_spec[FFESTP_beruixIOSTAT]);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ ffeste_subr_beru_ (info, FFECOM_gfrtFREW);
+#else
+#error
+#endif
+}
+
+/* ffeste_R923A -- INQUIRE statement (non-IOLENGTH version)
+
+ ffeste_R923A(bool by_file);
+
+ Make sure an INQUIRE is valid in the current context, and implement it. */
+
+void
+ffeste_R923A (ffestpInquireStmt *info, bool by_file UNUSED)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if (by_file)
+ {
+ fputs ("+ INQUIRE_file (", dmpout);
+ ffeste_subr_file_ ("FILE", &info->inquire_spec[FFESTP_inquireixFILE]);
+ }
+ else
+ {
+ fputs ("+ INQUIRE_unit (", dmpout);
+ ffeste_subr_file_ ("UNIT", &info->inquire_spec[FFESTP_inquireixUNIT]);
+ }
+ ffeste_subr_file_ ("ACCESS", &info->inquire_spec[FFESTP_inquireixACCESS]);
+ ffeste_subr_file_ ("ACTION", &info->inquire_spec[FFESTP_inquireixACTION]);
+ ffeste_subr_file_ ("BLANK", &info->inquire_spec[FFESTP_inquireixBLANK]);
+ ffeste_subr_file_ ("CARRIAGECONTROL", &info->inquire_spec[FFESTP_inquireixCARRIAGECONTROL]);
+ ffeste_subr_file_ ("DEFAULTFILE", &info->inquire_spec[FFESTP_inquireixDEFAULTFILE]);
+ ffeste_subr_file_ ("DELIM", &info->inquire_spec[FFESTP_inquireixDELIM]);
+ ffeste_subr_file_ ("DIRECT", &info->inquire_spec[FFESTP_inquireixDIRECT]);
+ ffeste_subr_file_ ("ERR", &info->inquire_spec[FFESTP_inquireixERR]);
+ ffeste_subr_file_ ("EXIST", &info->inquire_spec[FFESTP_inquireixEXIST]);
+ ffeste_subr_file_ ("FORM", &info->inquire_spec[FFESTP_inquireixFORM]);
+ ffeste_subr_file_ ("FORMATTED", &info->inquire_spec[FFESTP_inquireixFORMATTED]);
+ ffeste_subr_file_ ("IOSTAT", &info->inquire_spec[FFESTP_inquireixIOSTAT]);
+ ffeste_subr_file_ ("KEYED", &info->inquire_spec[FFESTP_inquireixKEYED]);
+ ffeste_subr_file_ ("NAME", &info->inquire_spec[FFESTP_inquireixNAME]);
+ ffeste_subr_file_ ("NAMED", &info->inquire_spec[FFESTP_inquireixNAMED]);
+ ffeste_subr_file_ ("NEXTREC", &info->inquire_spec[FFESTP_inquireixNEXTREC]);
+ ffeste_subr_file_ ("NUMBER", &info->inquire_spec[FFESTP_inquireixNUMBER]);
+ ffeste_subr_file_ ("OPENED", &info->inquire_spec[FFESTP_inquireixOPENED]);
+ ffeste_subr_file_ ("ORGANIZATION", &info->inquire_spec[FFESTP_inquireixORGANIZATION]);
+ ffeste_subr_file_ ("PAD", &info->inquire_spec[FFESTP_inquireixPAD]);
+ ffeste_subr_file_ ("POSITION", &info->inquire_spec[FFESTP_inquireixPOSITION]);
+ ffeste_subr_file_ ("READ", &info->inquire_spec[FFESTP_inquireixREAD]);
+ ffeste_subr_file_ ("READWRITE", &info->inquire_spec[FFESTP_inquireixREADWRITE]);
+ ffeste_subr_file_ ("RECL", &info->inquire_spec[FFESTP_inquireixRECL]);
+ ffeste_subr_file_ ("RECORDTYPE", &info->inquire_spec[FFESTP_inquireixRECORDTYPE]);
+ ffeste_subr_file_ ("SEQUENTIAL", &info->inquire_spec[FFESTP_inquireixSEQUENTIAL]);
+ ffeste_subr_file_ ("UNFORMATTED", &info->inquire_spec[FFESTP_inquireixUNFORMATTED]);
+ ffeste_subr_file_ ("WRITE", &info->inquire_spec[FFESTP_inquireixWRITE]);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree args;
+ bool iostat;
+ bool errl;
+
+#define specified(something) (info->inquire_spec[something].kw_or_val_present)
+
+ ffeste_emit_line_note_ ();
+
+ iostat = specified (FFESTP_inquireixIOSTAT);
+ errl = specified (FFESTP_inquireixERR);
+
+ ffecom_push_calltemps ();
+
+ args = ffeste_io_inlist_ (errl || iostat,
+ &info->inquire_spec[FFESTP_inquireixUNIT],
+ &info->inquire_spec[FFESTP_inquireixFILE],
+ &info->inquire_spec[FFESTP_inquireixEXIST],
+ &info->inquire_spec[FFESTP_inquireixOPENED],
+ &info->inquire_spec[FFESTP_inquireixNUMBER],
+ &info->inquire_spec[FFESTP_inquireixNAMED],
+ &info->inquire_spec[FFESTP_inquireixNAME],
+ &info->inquire_spec[FFESTP_inquireixACCESS],
+ &info->inquire_spec[FFESTP_inquireixSEQUENTIAL],
+ &info->inquire_spec[FFESTP_inquireixDIRECT],
+ &info->inquire_spec[FFESTP_inquireixFORM],
+ &info->inquire_spec[FFESTP_inquireixFORMATTED],
+ &info->inquire_spec[FFESTP_inquireixUNFORMATTED],
+ &info->inquire_spec[FFESTP_inquireixRECL],
+ &info->inquire_spec[FFESTP_inquireixNEXTREC],
+ &info->inquire_spec[FFESTP_inquireixBLANK]);
+
+ if (errl)
+ {
+ ffeste_io_err_
+ = ffeste_io_abort_
+ = ffecom_lookup_label
+ (info->inquire_spec[FFESTP_inquireixERR].u.label);
+ ffeste_io_abort_is_temp_ = FALSE;
+ }
+ else
+ {
+ ffeste_io_err_ = NULL_TREE;
+
+ if ((ffeste_io_abort_is_temp_ = iostat))
+ ffeste_io_abort_ = ffecom_temp_label ();
+ else
+ ffeste_io_abort_ = NULL_TREE;
+ }
+
+ if (iostat)
+ { /* IOSTAT= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = ffecom_expr
+ (info->inquire_spec[FFESTP_inquireixIOSTAT].u.expr);
+ }
+ else if (ffeste_io_abort_ != NULL_TREE)
+ { /* no IOSTAT= but ERR= */
+ ffeste_io_iostat_is_temp_ = TRUE;
+ ffeste_io_iostat_
+ = ffecom_push_tempvar (ffecom_integer_type_node,
+ FFETARGET_charactersizeNONE, -1, FALSE);
+ }
+ else
+ { /* no IOSTAT=, or ERR= */
+ ffeste_io_iostat_is_temp_ = FALSE;
+ ffeste_io_iostat_ = NULL_TREE;
+ }
+
+ /* Don't generate "if (iostat != 0) goto label;" if label is temp abort
+ label, since we're gonna fall through to there anyway. */
+
+ ffeste_io_call_ (ffecom_call_gfrt (FFECOM_gfrtFINQU, args),
+ !ffeste_io_abort_is_temp_);
+
+ /* If we've got a temp label, generate its code here. */
+
+ if (ffeste_io_abort_is_temp_)
+ {
+ DECL_INITIAL (ffeste_io_abort_) = error_mark_node;
+ emit_nop ();
+ expand_label (ffeste_io_abort_);
+
+ assert (ffeste_io_err_ == NULL_TREE);
+ }
+
+ /* If we've got a temp iostat, pop the temp. */
+
+ if (ffeste_io_iostat_is_temp_)
+ ffecom_pop_tempvar (ffeste_io_iostat_);
+
+ ffecom_pop_calltemps ();
+
+#undef specified
+ }
+
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R923B_start -- INQUIRE(IOLENGTH=expr) statement list begin
+
+ ffeste_R923B_start();
+
+ Verify that INQUIRE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffeste_R923B_start (ffestpInquireStmt *info UNUSED)
+{
+ ffeste_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ INQUIRE (", dmpout);
+ ffeste_subr_file_ ("IOLENGTH", &info->inquire_spec[FFESTP_inquireixIOLENGTH]);
+ fputs (") ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ assert ("INQUIRE(IOLENGTH=<var>) not implemented yet! ~~~" == NULL);
+ ffeste_emit_line_note_ ();
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R923B_item -- INQUIRE statement i/o item
+
+ ffeste_R923B_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffeste_R923B_item (ffebld expr UNUSED)
+{
+ ffeste_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (expr);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R923B_finish -- INQUIRE statement list complete
+
+ ffeste_R923B_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffeste_R923B_finish ()
+{
+ ffeste_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ clear_momentary ();
+#else
+#error
+#endif
+}
+
+/* ffeste_R1001 -- FORMAT statement
+
+ ffeste_R1001(format_list); */
+
+void
+ffeste_R1001 (ffests s)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "$ FORMAT %.*s\n", (int) ffests_length (s), ffests_text (s));
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree t;
+ tree ttype;
+ tree maxindex;
+ tree var;
+
+ assert (ffeste_label_formatdef_ != NULL);
+
+ ffeste_emit_line_note_ ();
+
+ t = build_string (ffests_length (s), ffests_text (s));
+
+ TREE_TYPE (t)
+ = build_type_variant (build_array_type
+ (char_type_node,
+ build_range_type (integer_type_node,
+ integer_one_node,
+ build_int_2 (ffests_length (s),
+ 0))),
+ 1, 0);
+ TREE_CONSTANT (t) = 1;
+ TREE_STATIC (t) = 1;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ var = ffecom_lookup_label (ffeste_label_formatdef_);
+ if ((var != NULL_TREE)
+ && (TREE_CODE (var) == VAR_DECL))
+ {
+ DECL_INITIAL (var) = t;
+ maxindex = build_int_2 (ffests_length (s) - 1, 0);
+ ttype = TREE_TYPE (var);
+ TYPE_DOMAIN (ttype) = build_range_type (integer_type_node,
+ integer_zero_node,
+ maxindex);
+ if (!TREE_TYPE (maxindex))
+ TREE_TYPE (maxindex) = TYPE_DOMAIN (ttype);
+ layout_type (ttype);
+ rest_of_decl_compilation (var, NULL, 1, 0);
+ expand_decl (var);
+ expand_decl_init (var);
+ }
+
+ resume_temporary_allocation ();
+ pop_obstacks ();
+
+ ffeste_label_formatdef_ = NULL;
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R1103 -- End a PROGRAM
+
+ ffeste_R1103(); */
+
+void
+ffeste_R1103 ()
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ END_PROGRAM\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_R1112 -- End a BLOCK DATA
+
+ ffeste_R1112(TRUE); */
+
+void
+ffeste_R1112 ()
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("* END_BLOCK_DATA\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_R1212 -- CALL statement
+
+ ffeste_R1212(expr,expr_token);
+
+ Make sure statement is valid here; implement. */
+
+void
+ffeste_R1212 (ffebld expr)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ CALL ", dmpout);
+ ffebld_dump (expr);
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ ffebld args = ffebld_right (expr);
+ ffebld arg;
+ ffebld labels = NULL; /* First in list of LABTERs. */
+ ffebld prevlabels = NULL;
+ ffebld prevargs = NULL;
+
+ ffeste_emit_line_note_ ();
+
+ /* Here we split the list at ffebld_right(expr) into two lists: one at
+ ffebld_right(expr) consisting of all items that are not LABTERs, the
+ other at labels consisting of all items that are LABTERs. Then, if
+ the latter list is NULL, we have an ordinary call, else we have a call
+ with alternate returns. */
+
+ for (args = ffebld_right (expr); args != NULL; args = ffebld_trail (args))
+ {
+ if (((arg = ffebld_head (args)) == NULL)
+ || (ffebld_op (arg) != FFEBLD_opLABTER))
+ {
+ if (prevargs == NULL)
+ {
+ prevargs = args;
+ ffebld_set_right (expr, args);
+ }
+ else
+ {
+ ffebld_set_trail (prevargs, args);
+ prevargs = args;
+ }
+ }
+ else
+ {
+ if (prevlabels == NULL)
+ {
+ prevlabels = labels = args;
+ }
+ else
+ {
+ ffebld_set_trail (prevlabels, args);
+ prevlabels = args;
+ }
+ }
+ }
+ if (prevlabels == NULL)
+ labels = NULL;
+ else
+ ffebld_set_trail (prevlabels, NULL);
+ if (prevargs == NULL)
+ ffebld_set_right (expr, NULL);
+ else
+ ffebld_set_trail (prevargs, NULL);
+
+ if (labels == NULL)
+ expand_expr_stmt (ffecom_expr (expr));
+ else
+ {
+ tree texpr;
+ tree value;
+ tree tlabel;
+ int caseno;
+ int pushok;
+ tree duplicate;
+
+ texpr = ffecom_expr (expr);
+ expand_start_case (0, texpr, TREE_TYPE (texpr), "CALL statement");
+ push_momentary (); /* In case of many labels, keep 'em cleared
+ out. */
+ for (caseno = 1;
+ labels != NULL;
+ ++caseno, labels = ffebld_trail (labels))
+ {
+ value = build_int_2 (caseno, 0);
+ tlabel = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+
+ pushok = pushcase (value, convert, tlabel, &duplicate);
+ assert (pushok == 0);
+ tlabel
+ = ffecom_lookup_label (ffebld_labter (ffebld_head (labels)));
+ if ((tlabel == NULL_TREE)
+ || (TREE_CODE (tlabel) == ERROR_MARK))
+ continue;
+ TREE_USED (tlabel) = 1;
+ expand_goto (tlabel);
+ clear_momentary ();
+ }
+
+ pop_momentary ();
+ expand_end_case (texpr);
+ }
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R1221 -- End a FUNCTION
+
+ ffeste_R1221(TRUE); */
+
+void
+ffeste_R1221 ()
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ END_FUNCTION\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_R1225 -- End a SUBROUTINE
+
+ ffeste_R1225(TRUE); */
+
+void
+ffeste_R1225 ()
+{
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "+ END_SUBROUTINE\n");
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_R1226 -- ENTRY statement
+
+ ffeste_R1226(entryname,arglist,ending_token);
+
+ Make sure we're in a SUBROUTINE or FUNCTION, register arguments for the
+ entry point name, and so on. */
+
+void
+ffeste_R1226 (ffesymbol entry)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fprintf (dmpout, "+ ENTRY %s", ffesymbol_text (entry));
+ if (ffesymbol_dummyargs (entry) != NULL)
+ {
+ ffebld argh;
+
+ fputc ('(', dmpout);
+ for (argh = ffesymbol_dummyargs (entry);
+ argh != NULL;
+ argh = ffebld_trail (argh))
+ {
+ assert (ffebld_head (argh) != NULL);
+ switch (ffebld_op (ffebld_head (argh)))
+ {
+ case FFEBLD_opSYMTER:
+ fputs (ffesymbol_text (ffebld_symter (ffebld_head (argh))),
+ dmpout);
+ break;
+
+ case FFEBLD_opSTAR:
+ fputc ('*', dmpout);
+ break;
+
+ default:
+ fputc ('?', dmpout);
+ ffebld_dump (ffebld_head (argh));
+ fputc ('?', dmpout);
+ break;
+ }
+ if (ffebld_trail (argh) != NULL)
+ fputc (',', dmpout);
+ }
+ fputc (')', dmpout);
+ }
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree label = ffesymbol_hook (entry).length_tree;
+
+ ffeste_emit_line_note_ ();
+
+ DECL_INITIAL (label) = error_mark_node;
+ emit_nop ();
+ expand_label (label);
+
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_R1227 -- RETURN statement
+
+ ffeste_R1227(expr);
+
+ Make sure statement is valid here; implement. expr and expr_token are
+ both NULL if there was no expression. */
+
+void
+ffeste_R1227 (ffestw block UNUSED, ffebld expr)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ if (expr == NULL)
+ {
+ fputs ("+ RETURN\n", dmpout);
+ }
+ else
+ {
+ fputs ("+ RETURN_alternate ", dmpout);
+ ffebld_dump (expr);
+ fputc ('\n', dmpout);
+ }
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+ {
+ tree rtn;
+
+ ffeste_emit_line_note_ ();
+ ffecom_push_calltemps ();
+
+ rtn = ffecom_return_expr (expr);
+
+ if ((rtn == NULL_TREE)
+ || (rtn == error_mark_node))
+ expand_null_return ();
+ else
+ {
+ tree result = DECL_RESULT (current_function_decl);
+
+ if ((result != error_mark_node)
+ && (TREE_TYPE (result) != error_mark_node))
+ expand_return (ffecom_modify (NULL_TREE,
+ result,
+ convert (TREE_TYPE (result),
+ rtn)));
+ else
+ expand_null_return ();
+ }
+
+ ffecom_pop_calltemps ();
+ clear_momentary ();
+ }
+#else
+#error
+#endif
+}
+
+/* ffeste_V018_start -- REWRITE(...) statement list begin
+
+ ffeste_V018_start();
+
+ Verify that REWRITE is valid here, and begin accepting items in the
+ list. */
+
+#if FFESTR_VXT
+void
+ffeste_V018_start (ffestpRewriteStmt *info, ffestvFormat format)
+{
+ ffeste_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ switch (format)
+ {
+ case FFESTV_formatNONE:
+ fputs ("+ REWRITE_uf (", dmpout);
+ break;
+
+ case FFESTV_formatLABEL:
+ case FFESTV_formatCHAREXPR:
+ case FFESTV_formatINTEXPR:
+ fputs ("+ REWRITE_fm (", dmpout);
+ break;
+
+ default:
+ assert ("Unexpected kind of format item in V018 REWRITE" == NULL);
+ }
+ ffeste_subr_file_ ("UNIT", &info->rewrite_spec[FFESTP_rewriteixUNIT]);
+ ffeste_subr_file_ ("FMT", &info->rewrite_spec[FFESTP_rewriteixFMT]);
+ ffeste_subr_file_ ("ERR", &info->rewrite_spec[FFESTP_rewriteixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->rewrite_spec[FFESTP_rewriteixIOSTAT]);
+ fputs (") ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V018_item -- REWRITE statement i/o item
+
+ ffeste_V018_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffeste_V018_item (ffebld expr)
+{
+ ffeste_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (expr);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V018_finish -- REWRITE statement list complete
+
+ ffeste_V018_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffeste_V018_finish ()
+{
+ ffeste_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V019_start -- ACCEPT statement list begin
+
+ ffeste_V019_start();
+
+ Verify that ACCEPT is valid here, and begin accepting items in the
+ list. */
+
+void
+ffeste_V019_start (ffestpAcceptStmt *info, ffestvFormat format)
+{
+ ffeste_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ switch (format)
+ {
+ case FFESTV_formatLABEL:
+ case FFESTV_formatCHAREXPR:
+ case FFESTV_formatINTEXPR:
+ fputs ("+ ACCEPT_fm ", dmpout);
+ break;
+
+ case FFESTV_formatASTERISK:
+ fputs ("+ ACCEPT_ls ", dmpout);
+ break;
+
+ case FFESTV_formatNAMELIST:
+ fputs ("+ ACCEPT_nl ", dmpout);
+ break;
+
+ default:
+ assert ("Unexpected kind of format item in V019 ACCEPT" == NULL);
+ }
+ ffeste_subr_file_ ("FORMAT", &info->accept_spec[FFESTP_acceptixFORMAT]);
+ fputc (' ', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V019_item -- ACCEPT statement i/o item
+
+ ffeste_V019_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffeste_V019_item (ffebld expr)
+{
+ ffeste_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (expr);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V019_finish -- ACCEPT statement list complete
+
+ ffeste_V019_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffeste_V019_finish ()
+{
+ ffeste_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+#endif
+/* ffeste_V020_start -- TYPE statement list begin
+
+ ffeste_V020_start();
+
+ Verify that TYPE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffeste_V020_start (ffestpTypeStmt *info UNUSED,
+ ffestvFormat format UNUSED)
+{
+ ffeste_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ switch (format)
+ {
+ case FFESTV_formatLABEL:
+ case FFESTV_formatCHAREXPR:
+ case FFESTV_formatINTEXPR:
+ fputs ("+ TYPE_fm ", dmpout);
+ break;
+
+ case FFESTV_formatASTERISK:
+ fputs ("+ TYPE_ls ", dmpout);
+ break;
+
+ case FFESTV_formatNAMELIST:
+ fputs ("* TYPE_nl ", dmpout);
+ break;
+
+ default:
+ assert ("Unexpected kind of format item in V020 TYPE" == NULL);
+ }
+ ffeste_subr_file_ ("FORMAT", &info->type_spec[FFESTP_typeixFORMAT]);
+ fputc (' ', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V020_item -- TYPE statement i/o item
+
+ ffeste_V020_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffeste_V020_item (ffebld expr UNUSED)
+{
+ ffeste_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (expr);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V020_finish -- TYPE statement list complete
+
+ ffeste_V020_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffeste_V020_finish ()
+{
+ ffeste_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V021 -- DELETE statement
+
+ ffeste_V021();
+
+ Make sure a DELETE is valid in the current context, and implement it. */
+
+#if FFESTR_VXT
+void
+ffeste_V021 (ffestpDeleteStmt *info)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ DELETE (", dmpout);
+ ffeste_subr_file_ ("UNIT", &info->delete_spec[FFESTP_deleteixUNIT]);
+ ffeste_subr_file_ ("REC", &info->delete_spec[FFESTP_deleteixREC]);
+ ffeste_subr_file_ ("ERR", &info->delete_spec[FFESTP_deleteixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->delete_spec[FFESTP_deleteixIOSTAT]);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V022 -- UNLOCK statement
+
+ ffeste_V022();
+
+ Make sure a UNLOCK is valid in the current context, and implement it. */
+
+void
+ffeste_V022 (ffestpBeruStmt *info)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ UNLOCK (", dmpout);
+ ffeste_subr_file_ ("UNIT", &info->beru_spec[FFESTP_beruixUNIT]);
+ ffeste_subr_file_ ("ERR", &info->beru_spec[FFESTP_beruixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->beru_spec[FFESTP_beruixIOSTAT]);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V023_start -- ENCODE(...) statement list begin
+
+ ffeste_V023_start();
+
+ Verify that ENCODE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffeste_V023_start (ffestpVxtcodeStmt *info)
+{
+ ffeste_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ ENCODE (", dmpout);
+ ffeste_subr_file_ ("C", &info->vxtcode_spec[FFESTP_vxtcodeixC]);
+ ffeste_subr_file_ ("F", &info->vxtcode_spec[FFESTP_vxtcodeixF]);
+ ffeste_subr_file_ ("B", &info->vxtcode_spec[FFESTP_vxtcodeixB]);
+ ffeste_subr_file_ ("ERR", &info->vxtcode_spec[FFESTP_vxtcodeixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->vxtcode_spec[FFESTP_vxtcodeixIOSTAT]);
+ fputs (") ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V023_item -- ENCODE statement i/o item
+
+ ffeste_V023_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffeste_V023_item (ffebld expr)
+{
+ ffeste_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (expr);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V023_finish -- ENCODE statement list complete
+
+ ffeste_V023_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffeste_V023_finish ()
+{
+ ffeste_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V024_start -- DECODE(...) statement list begin
+
+ ffeste_V024_start();
+
+ Verify that DECODE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffeste_V024_start (ffestpVxtcodeStmt *info)
+{
+ ffeste_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ DECODE (", dmpout);
+ ffeste_subr_file_ ("C", &info->vxtcode_spec[FFESTP_vxtcodeixC]);
+ ffeste_subr_file_ ("F", &info->vxtcode_spec[FFESTP_vxtcodeixF]);
+ ffeste_subr_file_ ("B", &info->vxtcode_spec[FFESTP_vxtcodeixB]);
+ ffeste_subr_file_ ("ERR", &info->vxtcode_spec[FFESTP_vxtcodeixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->vxtcode_spec[FFESTP_vxtcodeixIOSTAT]);
+ fputs (") ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V024_item -- DECODE statement i/o item
+
+ ffeste_V024_item(expr,expr_token);
+
+ Implement output-list expression. */
+
+void
+ffeste_V024_item (ffebld expr)
+{
+ ffeste_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (expr);
+ fputc (',', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V024_finish -- DECODE statement list complete
+
+ ffeste_V024_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffeste_V024_finish ()
+{
+ ffeste_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V025_start -- DEFINEFILE statement list begin
+
+ ffeste_V025_start();
+
+ Verify that DEFINEFILE is valid here, and begin accepting items in the
+ list. */
+
+void
+ffeste_V025_start ()
+{
+ ffeste_check_start_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ DEFINE_FILE ", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V025_item -- DEFINE FILE statement item
+
+ ffeste_V025_item(u,ut,m,mt,n,nt,asv,asvt);
+
+ Implement item. */
+
+void
+ffeste_V025_item (ffebld u, ffebld m, ffebld n, ffebld asv)
+{
+ ffeste_check_item_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ ffebld_dump (u);
+ fputc ('(', dmpout);
+ ffebld_dump (m);
+ fputc (',', dmpout);
+ ffebld_dump (n);
+ fputs (",U,", dmpout);
+ ffebld_dump (asv);
+ fputs ("),", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V025_finish -- DEFINE FILE statement list complete
+
+ ffeste_V025_finish();
+
+ Just wrap up any local activities. */
+
+void
+ffeste_V025_finish ()
+{
+ ffeste_check_finish_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputc ('\n', dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+/* ffeste_V026 -- FIND statement
+
+ ffeste_V026();
+
+ Make sure a FIND is valid in the current context, and implement it. */
+
+void
+ffeste_V026 (ffestpFindStmt *info)
+{
+ ffeste_check_simple_ ();
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ fputs ("+ FIND (", dmpout);
+ ffeste_subr_file_ ("UNIT", &info->find_spec[FFESTP_findixUNIT]);
+ ffeste_subr_file_ ("REC", &info->find_spec[FFESTP_findixREC]);
+ ffeste_subr_file_ ("ERR", &info->find_spec[FFESTP_findixERR]);
+ ffeste_subr_file_ ("IOSTAT", &info->find_spec[FFESTP_findixIOSTAT]);
+ fputs (")\n", dmpout);
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+#else
+#error
+#endif
+}
+
+#endif
diff --git a/contrib/gcc/f/ste.h b/contrib/gcc/f/ste.h
new file mode 100644
index 0000000..0ee0d0f
--- /dev/null
+++ b/contrib/gcc/f/ste.h
@@ -0,0 +1,168 @@
+/* ste.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ ste.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_ste
+#define _H_f_ste
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "bld.h"
+#include "lab.h"
+#include "lex.h"
+#include "stp.h"
+#include "str.h"
+#include "sts.h"
+#include "stt.h"
+#include "stv.h"
+#include "stw.h"
+#include "symbol.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+void ffeste_do (ffestw block);
+void ffeste_end_R807 (void);
+void ffeste_labeldef_branch (ffelab label);
+void ffeste_labeldef_format (ffelab label);
+void ffeste_R737A (ffebld dest, ffebld source);
+void ffeste_R803 (ffebld expr);
+void ffeste_R804 (ffebld expr);
+void ffeste_R805 (void);
+void ffeste_R806 (void);
+void ffeste_R807 (ffebld expr);
+void ffeste_R809 (ffestw block, ffebld expr);
+void ffeste_R810 (ffestw block, unsigned long casenum);
+void ffeste_R811 (ffestw block);
+void ffeste_R819A (ffestw block, ffelab label, ffebld var,
+ ffebld start, ffelexToken start_token,
+ ffebld end, ffelexToken end_token,
+ ffebld incr, ffelexToken incr_token);
+void ffeste_R819B (ffestw block, ffelab label, ffebld expr);
+void ffeste_R825 (void);
+void ffeste_R834 (ffestw block);
+void ffeste_R835 (ffestw block);
+void ffeste_R836 (ffelab label);
+void ffeste_R837 (ffelab *labels, int count, ffebld expr);
+void ffeste_R838 (ffelab label, ffebld target);
+void ffeste_R839 (ffebld target);
+void ffeste_R840 (ffebld expr, ffelab neg, ffelab zero, ffelab pos);
+void ffeste_R841 (void);
+void ffeste_R842 (ffebld expr);
+void ffeste_R843 (ffebld expr);
+void ffeste_R904 (ffestpOpenStmt *info);
+void ffeste_R907 (ffestpCloseStmt *info);
+void ffeste_R909_start (ffestpReadStmt *info, bool only_format,
+ ffestvUnit unit, ffestvFormat format, bool rec, bool key);
+void ffeste_R909_item (ffebld expr, ffelexToken expr_token);
+void ffeste_R909_finish (void);
+void ffeste_R910_start (ffestpWriteStmt *info, ffestvUnit unit,
+ ffestvFormat format, bool rec);
+void ffeste_R910_item (ffebld expr, ffelexToken expr_token);
+void ffeste_R910_finish (void);
+void ffeste_R911_start (ffestpPrintStmt *info, ffestvFormat format);
+void ffeste_R911_item (ffebld expr, ffelexToken expr_token);
+void ffeste_R911_finish (void);
+void ffeste_R919 (ffestpBeruStmt *info);
+void ffeste_R920 (ffestpBeruStmt *info);
+void ffeste_R921 (ffestpBeruStmt *info);
+void ffeste_R923A (ffestpInquireStmt *info, bool by_file);
+void ffeste_R923B_start (ffestpInquireStmt *info);
+void ffeste_R923B_item (ffebld expr);
+void ffeste_R923B_finish (void);
+void ffeste_R1001 (ffests s);
+void ffeste_R1103 (void);
+void ffeste_R1112 (void);
+void ffeste_R1212 (ffebld expr);
+void ffeste_R1221 (void);
+void ffeste_R1225 (void);
+void ffeste_R1226 (ffesymbol entry);
+void ffeste_R1227 (ffestw block, ffebld expr);
+#if FFESTR_VXT
+void ffeste_V018_start (ffestpRewriteStmt *info, ffestvFormat format);
+void ffeste_V018_item (ffebld expr);
+void ffeste_V018_finish (void);
+void ffeste_V019_start (ffestpAcceptStmt *info, ffestvFormat format);
+void ffeste_V019_item (ffebld expr);
+void ffeste_V019_finish (void);
+#endif
+void ffeste_V020_start (ffestpTypeStmt *info, ffestvFormat format);
+void ffeste_V020_item (ffebld expr);
+void ffeste_V020_finish (void);
+#if FFESTR_VXT
+void ffeste_V021 (ffestpDeleteStmt *info);
+void ffeste_V022 (ffestpBeruStmt *info);
+void ffeste_V023_start (ffestpVxtcodeStmt *info);
+void ffeste_V023_item (ffebld expr);
+void ffeste_V023_finish (void);
+void ffeste_V024_start (ffestpVxtcodeStmt *info);
+void ffeste_V024_item (ffebld expr);
+void ffeste_V024_finish (void);
+void ffeste_V025_start (void);
+void ffeste_V025_item (ffebld u, ffebld m, ffebld n, ffebld asv);
+void ffeste_V025_finish (void);
+void ffeste_V026 (ffestpFindStmt *info);
+#endif
+
+/* Define macros. */
+
+#define ffeste_init_0()
+#define ffeste_init_1()
+#define ffeste_init_2()
+#define ffeste_init_3()
+#define ffeste_init_4()
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#define ffeste_filename() input_filename
+#define ffeste_filelinenum() lineno
+#define ffeste_set_line(name,num) \
+ (input_filename = (name), lineno = (num))
+#elif FFECOM_targetCURRENT == FFECOM_targetFFE
+#define ffeste_set_line(name,num)
+#else
+#error
+#endif /* FFECOM_targetCURRENT == FFECOM_targetFFE */
+#define ffeste_terminate_0()
+#define ffeste_terminate_1()
+#define ffeste_terminate_2()
+#define ffeste_terminate_3()
+#define ffeste_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/storag.c b/contrib/gcc/f/storag.c
new file mode 100644
index 0000000..76f5cd3
--- /dev/null
+++ b/contrib/gcc/f/storag.c
@@ -0,0 +1,573 @@
+/* storag.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Maintains information on storage (memory) relationships between
+ COMMON, dummy, and local variables, plus their equivalences (dummies
+ don't have equivalences, however).
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "storag.h"
+#include "data.h"
+#include "malloc.h"
+#include "symbol.h"
+#include "target.h"
+
+/* Externals defined here. */
+
+ffestoragList_ ffestorag_list_;
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+static ffetargetOffset ffestorag_local_size_; /* #units allocated so far. */
+static bool ffestorag_reported_;/* Reports happen only once. */
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+#define ffestorag_next_(s) ((s)->next)
+#define ffestorag_previous_(s) ((s)->previous)
+
+/* ffestorag_drive -- Drive fn from list of storage objects
+
+ ffestoragList sl;
+ void (*fn)(ffestorag mst,ffestorag st);
+ ffestorag mst; // the master ffestorag object (or whatever)
+ ffestorag_drive(sl,fn,mst);
+
+ Calls (*fn)(mst,st) for every st in the list sl. */
+
+void
+ffestorag_drive (ffestoragList sl, void (*fn) (ffestorag mst, ffestorag st),
+ ffestorag mst)
+{
+ ffestorag st;
+
+ for (st = sl->first;
+ st != (ffestorag) &sl->first;
+ st = st->next)
+ (*fn) (mst, st);
+}
+
+/* ffestorag_dump -- Dump information on storage object
+
+ ffestorag s; // the ffestorag object
+ ffestorag_dump(s);
+
+ Dumps information in the storage object. */
+
+void
+ffestorag_dump (ffestorag s)
+{
+ if (s == NULL)
+ {
+ fprintf (dmpout, "(no storage object)");
+ return;
+ }
+
+ switch (s->type)
+ {
+ case FFESTORAG_typeCBLOCK:
+ fprintf (dmpout, "CBLOCK ");
+ break;
+
+ case FFESTORAG_typeCOMMON:
+ fprintf (dmpout, "COMMON ");
+ break;
+
+ case FFESTORAG_typeLOCAL:
+ fprintf (dmpout, "LOCAL ");
+ break;
+
+ case FFESTORAG_typeEQUIV:
+ fprintf (dmpout, "EQUIV ");
+ break;
+
+ default:
+ fprintf (dmpout, "?%d? ", s->type);
+ break;
+ }
+
+ if (s->symbol != NULL)
+ fprintf (dmpout, "\"%s\" ", ffesymbol_text (s->symbol));
+
+ fprintf (dmpout, "at %" ffetargetOffset_f "d size %" ffetargetOffset_f
+ "d, align loc%%%"
+ ffetargetAlign_f "u=%" ffetargetAlign_f "u, bt=%s, kt=%s",
+ s->offset,
+ s->size, (unsigned int) s->alignment, (unsigned int) s->modulo,
+ ffeinfo_basictype_string (s->basic_type),
+ ffeinfo_kindtype_string (s->kind_type));
+
+ if (s->equivs_.first != (ffestorag) &s->equivs_.first)
+ {
+ ffestorag sq;
+
+ fprintf (dmpout, " with equivs");
+ for (sq = s->equivs_.first;
+ sq != (ffestorag) &s->equivs_.first;
+ sq = ffestorag_next_ (sq))
+ {
+ if (ffestorag_previous_ (sq) == (ffestorag) &s->equivs_.first)
+ fputc (' ', dmpout);
+ else
+ fputc (',', dmpout);
+ fprintf (dmpout, "%s", ffesymbol_text (ffestorag_symbol (sq)));
+ }
+ }
+}
+
+/* ffestorag_init_2 -- Initialize for new program unit
+
+ ffestorag_init_2(); */
+
+void
+ffestorag_init_2 ()
+{
+ ffestorag_list_.first = ffestorag_list_.last
+ = (ffestorag) &ffestorag_list_.first;
+ ffestorag_local_size_ = 0;
+ ffestorag_reported_ = FALSE;
+}
+
+/* ffestorag_end_layout -- Do final layout for symbol
+
+ ffesymbol s;
+ ffestorag_end_layout(s); */
+
+void
+ffestorag_end_layout (ffesymbol s)
+{
+ if (ffesymbol_storage (s) != NULL)
+ return; /* Already laid out. */
+
+ ffestorag_exec_layout (s); /* Do what we have in common. */
+#if 0
+ assert (ffesymbol_storage (s) == NULL); /* I'd like to know what
+ cases miss going through
+ ffecom_sym_learned, and
+ why; I don't think we
+ should have to do the
+ exec_layout thing at all
+ here. */
+ /* Now I think I know: we have to do exec_layout here, because equivalence
+ handling could encounter an error that takes a variable off of its
+ equivalence object (and vice versa), and we should then layout the var
+ as a local entity. */
+#endif
+}
+
+/* ffestorag_exec_layout -- Do initial layout for symbol
+
+ ffesymbol s;
+ ffestorag_exec_layout(s); */
+
+void
+ffestorag_exec_layout (ffesymbol s)
+{
+ ffetargetAlign alignment;
+ ffetargetAlign modulo;
+ ffetargetOffset size;
+ ffetargetOffset num_elements;
+ ffetargetAlign pad;
+ ffestorag st;
+ ffestorag stv;
+ ffebld list;
+ ffebld item;
+ ffesymbol var;
+ bool init;
+
+ if (ffesymbol_storage (s) != NULL)
+ return; /* Already laid out. */
+
+ switch (ffesymbol_kind (s))
+ {
+ default:
+ return; /* Do nothing. */
+
+ case FFEINFO_kindENTITY:
+ switch (ffesymbol_where (s))
+ {
+ case FFEINFO_whereLOCAL:
+ if (ffesymbol_equiv (s) != NULL)
+ return; /* Let ffeequiv handle this guy. */
+ if (ffesymbol_rank (s) == 0)
+ num_elements = 1;
+ else
+ {
+ if (ffebld_op (ffesymbol_arraysize (s))
+ != FFEBLD_opCONTER)
+ return; /* An adjustable local array, just like a dummy. */
+ num_elements
+ = ffebld_constant_integerdefault (ffebld_conter
+ (ffesymbol_arraysize (s)));
+ }
+ ffetarget_layout (ffesymbol_text (s), &alignment, &modulo,
+ &size, ffesymbol_basictype (s),
+ ffesymbol_kindtype (s), ffesymbol_size (s),
+ num_elements);
+ st = ffestorag_new (ffestorag_list_master ());
+ st->parent = NULL; /* Initializations happen at sym level. */
+ st->init = NULL;
+ st->accretion = NULL;
+ st->symbol = s;
+ st->size = size;
+ st->offset = 0;
+ st->alignment = alignment;
+ st->modulo = modulo;
+ st->type = FFESTORAG_typeLOCAL;
+ st->basic_type = ffesymbol_basictype (s);
+ st->kind_type = ffesymbol_kindtype (s);
+ st->type_symbol = s;
+ st->is_save = ffesymbol_is_save (s);
+ st->is_init = ffesymbol_is_init (s);
+ ffesymbol_set_storage (s, st);
+ if (ffesymbol_is_init (s))
+ ffecom_notify_init_symbol (s); /* Init completed before, but
+ we didn't have a storage
+ object for it; maybe back
+ end wants to see the sym
+ again now. */
+ ffesymbol_signal_unreported (s);
+ return;
+
+ case FFEINFO_whereCOMMON:
+ return; /* Allocate storage for entire common block
+ at once. */
+
+ case FFEINFO_whereDUMMY:
+ return; /* Don't do anything about dummies for now. */
+
+ case FFEINFO_whereRESULT:
+ case FFEINFO_whereIMMEDIATE:
+ case FFEINFO_whereCONSTANT:
+ case FFEINFO_whereNONE:
+ return; /* These don't get storage (esp. NONE, which
+ is UNCERTAIN). */
+
+ default:
+ assert ("bad ENTITY where" == NULL);
+ return;
+ }
+ break;
+
+ case FFEINFO_kindCOMMON:
+ assert (ffesymbol_where (s) == FFEINFO_whereLOCAL);
+ st = ffestorag_new (ffestorag_list_master ());
+ st->parent = NULL; /* Initializations happen here. */
+ st->init = NULL;
+ st->accretion = NULL;
+ st->symbol = s;
+ st->size = 0;
+ st->offset = 0;
+ st->alignment = 1;
+ st->modulo = 0;
+ st->type = FFESTORAG_typeCBLOCK;
+ if (ffesymbol_commonlist (s) != NULL)
+ {
+ var = ffebld_symter (ffebld_head (ffesymbol_commonlist (s)));
+ st->basic_type = ffesymbol_basictype (var);
+ st->kind_type = ffesymbol_kindtype (var);
+ st->type_symbol = var;
+ }
+ else
+ { /* Special case for empty common area:
+ NONE/NONE means nothing. */
+ st->basic_type = FFEINFO_basictypeNONE;
+ st->kind_type = FFEINFO_kindtypeNONE;
+ st->type_symbol = NULL;
+ }
+ st->is_save = ffesymbol_is_save (s);
+ st->is_init = ffesymbol_is_init (s);
+ if (!ffe_is_mainprog ())
+ ffeglobal_save_common (s,
+ st->is_save || ffe_is_saveall (),
+ ffesymbol_where_line (s),
+ ffesymbol_where_column (s));
+ ffesymbol_set_storage (s, st);
+
+ init = FALSE;
+ for (list = ffesymbol_commonlist (s);
+ list != NULL;
+ list = ffebld_trail (list))
+ {
+ item = ffebld_head (list);
+ assert (ffebld_op (item) == FFEBLD_opSYMTER);
+ var = ffebld_symter (item);
+ if (ffesymbol_basictype (var) == FFEINFO_basictypeANY)
+ continue; /* Ignore any symbols that have errors. */
+ if (ffesymbol_rank (var) == 0)
+ num_elements = 1;
+ else
+ num_elements = ffebld_constant_integerdefault (ffebld_conter
+ (ffesymbol_arraysize (var)));
+ ffetarget_layout (ffesymbol_text (var), &alignment, &modulo,
+ &size, ffesymbol_basictype (var),
+ ffesymbol_kindtype (var), ffesymbol_size (var),
+ num_elements);
+ pad = ffetarget_align (&st->alignment, &st->modulo, st->size,
+ alignment, modulo);
+ if (pad != 0)
+ { /* Warn about padding in the midst of a
+ common area. */
+ char padding[20];
+
+ sprintf (&padding[0], "%" ffetargetAlign_f "u", pad);
+ ffebad_start (FFEBAD_COMMON_PAD);
+ ffebad_string (padding);
+ ffebad_string (ffesymbol_text (var));
+ ffebad_string (ffesymbol_text (s));
+ ffebad_string ((pad == 1)
+ ? FFECOM_SIZE_UNIT : FFECOM_SIZE_UNITS);
+ ffebad_here (0, ffesymbol_where_line (s), ffesymbol_where_column (s));
+ ffebad_finish ();
+ }
+ stv = ffestorag_new (ffestorag_list_master ());
+ stv->parent = st; /* Initializations happen in COMMON block. */
+ stv->init = NULL;
+ stv->accretion = NULL;
+ stv->symbol = var;
+ stv->size = size;
+ if (!ffetarget_offset_add (&stv->offset, st->size, pad))
+ { /* Common block size plus pad, complain if
+ overflow. */
+ ffetarget_offset_overflow (ffesymbol_text (s));
+ }
+ if (!ffetarget_offset_add (&st->size, stv->offset, stv->size))
+ { /* Adjust size of common block, complain if
+ overflow. */
+ ffetarget_offset_overflow (ffesymbol_text (s));
+ }
+ stv->alignment = alignment;
+ stv->modulo = modulo;
+ stv->type = FFESTORAG_typeCOMMON;
+ stv->basic_type = ffesymbol_basictype (var);
+ stv->kind_type = ffesymbol_kindtype (var);
+ stv->type_symbol = var;
+ stv->is_save = st->is_save;
+ stv->is_init = st->is_init;
+ ffesymbol_set_storage (var, stv);
+ ffesymbol_signal_unreported (var);
+ ffestorag_update (st, var, ffesymbol_basictype (var),
+ ffesymbol_kindtype (var));
+ if (ffesymbol_is_init (var))
+ init = TRUE; /* Must move inits over to COMMON's
+ ffestorag. */
+ }
+ if (ffeequiv_layout_cblock (st))
+ init = TRUE;
+ ffeglobal_pad_common (s, st->modulo, ffesymbol_where_line (s),
+ ffesymbol_where_column (s));
+ if (init)
+ ffedata_gather (st); /* Gather subordinate inits into one init. */
+ ffesymbol_signal_unreported (s);
+ return;
+ }
+}
+
+/* ffestorag_new -- Create new ffestorag object, append to list
+
+ ffestorag s;
+ ffestoragList sl;
+ s = ffestorag_new(sl); */
+
+ffestorag
+ffestorag_new (ffestoragList sl)
+{
+ ffestorag s;
+
+ s = (ffestorag) malloc_new_kp (ffe_pool_program_unit (), "ffestorag",
+ sizeof (*s));
+ s->next = (ffestorag) &sl->first;
+ s->previous = sl->last;
+#ifdef FFECOM_storageHOOK
+ s->hook = FFECOM_storageNULL;
+#endif
+ s->previous->next = s;
+ sl->last = s;
+ s->equivs_.first = s->equivs_.last = (ffestorag) &s->equivs_.first;
+
+ return s;
+}
+
+/* Report info on LOCAL non-sym-assoc'ed entities if needed. */
+
+void
+ffestorag_report ()
+{
+ ffestorag s;
+
+ if (ffestorag_reported_)
+ return;
+
+ for (s = ffestorag_list_.first;
+ s != (ffestorag) &ffestorag_list_.first;
+ s = s->next)
+ {
+ if (s->symbol == NULL)
+ {
+ ffestorag_reported_ = TRUE;
+ fputs ("Storage area: ", dmpout);
+ ffestorag_dump (s);
+ fputc ('\n', dmpout);
+ }
+ }
+}
+
+/* ffestorag_update -- Update type info for ffestorag object
+
+ ffestorag s; // existing object
+ ffeinfoBasictype bt; // basic type for newly added member of object
+ ffeinfoKindtype kt; // kind type for it
+ ffestorag_update(s,bt,kt);
+
+ If the existing type for the storage object agrees with the new type
+ info, just returns. If the basic types agree but not the kind types,
+ sets the kind type for the object to NONE. If the basic types
+ disagree, sets the kind type to NONE, and the basic type to NONE if the
+ basic types both are not CHARACTER, otherwise to ANY. If the basic
+ type for the object already is NONE, it is set to ANY if the new basic
+ type is CHARACTER. Any time a transition is made to ANY and pedantic
+ mode is on, a message is issued that mixing CHARACTER and non-CHARACTER
+ stuff in the same COMMON/EQUIVALENCE is invalid. */
+
+void
+ffestorag_update (ffestorag s, ffesymbol sym, ffeinfoBasictype bt,
+ ffeinfoKindtype kt)
+{
+ if (s->basic_type == bt)
+ {
+ if (s->kind_type == kt)
+ return;
+ s->kind_type = FFEINFO_kindtypeNONE;
+ return;
+ }
+
+ switch (s->basic_type)
+ {
+ case FFEINFO_basictypeANY:
+ return; /* No need to do anything further. */
+
+ case FFEINFO_basictypeCHARACTER:
+ any: /* :::::::::::::::::::: */
+ s->basic_type = FFEINFO_basictypeANY;
+ s->kind_type = FFEINFO_kindtypeANY;
+ if (ffe_is_pedantic ())
+ {
+ ffebad_start (FFEBAD_MIXED_TYPES);
+ ffebad_string (ffesymbol_text (s->type_symbol));
+ ffebad_string (ffesymbol_text (sym));
+ ffebad_finish ();
+ }
+ return;
+
+ default:
+ if (bt == FFEINFO_basictypeCHARACTER)
+ goto any; /* :::::::::::::::::::: */
+ s->basic_type = FFEINFO_basictypeNONE;
+ s->kind_type = FFEINFO_kindtypeNONE;
+ return;
+ }
+}
+
+/* Update INIT flag for storage object.
+
+ If the INIT flag for the <s> object is already TRUE, return. Else,
+ set it to TRUE and call ffe*_update_init for all contained objects. */
+
+void
+ffestorag_update_init (ffestorag s)
+{
+ ffestorag sq;
+
+ if (s->is_init)
+ return;
+
+ s->is_init = TRUE;
+
+ if ((s->symbol != NULL)
+ && !ffesymbol_is_init (s->symbol))
+ ffesymbol_update_init (s->symbol);
+
+ if (s->parent != NULL)
+ ffestorag_update_init (s->parent);
+
+ for (sq = s->equivs_.first;
+ sq != (ffestorag) &s->equivs_.first;
+ sq = ffestorag_next_ (sq))
+ {
+ if (!sq->is_init)
+ ffestorag_update_init (sq);
+ }
+}
+
+/* Update SAVE flag for storage object.
+
+ If the SAVE flag for the <s> object is already TRUE, return. Else,
+ set it to TRUE and call ffe*_update_save for all contained objects. */
+
+void
+ffestorag_update_save (ffestorag s)
+{
+ ffestorag sq;
+
+ if (s->is_save)
+ return;
+
+ s->is_save = TRUE;
+
+ if ((s->symbol != NULL)
+ && !ffesymbol_is_save (s->symbol))
+ ffesymbol_update_save (s->symbol);
+
+ if (s->parent != NULL)
+ ffestorag_update_save (s->parent);
+
+ for (sq = s->equivs_.first;
+ sq != (ffestorag) &s->equivs_.first;
+ sq = ffestorag_next_ (sq))
+ {
+ if (!sq->is_save)
+ ffestorag_update_save (sq);
+ }
+}
diff --git a/contrib/gcc/f/storag.h b/contrib/gcc/f/storag.h
new file mode 100644
index 0000000..5addab5
--- /dev/null
+++ b/contrib/gcc/f/storag.h
@@ -0,0 +1,167 @@
+/* storag.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ storag.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_storag
+#define _H_f_storag
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFESTORAG_typeNONE,
+ FFESTORAG_typeCBLOCK, /* A COMMON block. */
+ FFESTORAG_typeCOMMON, /* A COMMON variable. */
+ FFESTORAG_typeLOCAL, /* A local entity (var/array/equivalence). */
+ FFESTORAG_typeEQUIV, /* An entity equivalenced into a COMMON/LOCAL
+ entity. */
+ FFESTORAG_type
+ } ffestoragType;
+
+/* Typedefs. */
+
+typedef struct _ffestorag_ *ffestorag;
+typedef struct _ffestorag_list_ *ffestoragList;
+typedef struct _ffestorag_list_ ffestoragList_;
+
+/* Include files needed by this one. */
+
+#include "bld.h"
+#include "info.h"
+#include "symbol.h"
+#include "target.h"
+
+/* Structure definitions. */
+
+struct _ffestorag_list_
+ {
+ ffestorag first; /* First storage area in list. */
+ ffestorag last; /* Last storage area in list. */
+ };
+
+struct _ffestorag_
+ {
+ ffestorag next; /* Next storage area in list. */
+ ffestorag previous; /* Previous storage area in list. */
+ ffestorag parent; /* Parent who holds aggregate
+ initializations. */
+ ffebld init; /* Initialization expression. */
+ ffebld accretion; /* Initializations seen so far for aggregate. */
+ ffetargetOffset accretes; /* # inits needed to fill entire aggregate. */
+ ffesymbol symbol; /* NULL if typeLOCAL and non-NULL equivs
+ and the first "rooted" symbol not known. */
+ ffestoragList_ equivs_; /* NULL if typeLOCAL and not an EQUIVALENCE
+ area. */
+ ffetargetOffset size; /* Size of area. */
+ ffetargetOffset offset; /* Offset of entity within area, 0 for CBLOCK
+ and non-equivalence LOCAL, <= 0 for equivalence
+ LOCAL. */
+ ffetargetAlign alignment; /* Initial alignment for entity. */
+ ffetargetAlign modulo; /* Modulo within alignment. */
+#ifdef FFECOM_storageHOOK
+ ffecomStorage hook; /* Whatever the backend needs here. */
+#endif
+ ffestoragType type;
+ ffeinfoBasictype basic_type;/* NONE= >1 non-CHARACTER; ANY=
+ CHAR+non-CHAR. */
+ ffeinfoKindtype kind_type; /* NONE= >1 kind type or NONE/ANY basic_type. */
+ ffesymbol type_symbol; /* First symbol for basic_type/kind_type. */
+ bool is_save; /* SAVE flag set for this storage area. */
+ bool is_init; /* INIT flag set for this storage area. */
+ };
+
+/* Global objects accessed by users of this module. */
+
+extern ffestoragList_ ffestorag_list_;
+
+/* Declare functions with prototypes. */
+
+void ffestorag_drive (ffestoragList sl, void (*fn) (ffestorag mst, ffestorag st),
+ ffestorag mst);
+void ffestorag_dump (ffestorag s);
+void ffestorag_end_layout (ffesymbol s);
+void ffestorag_exec_layout (ffesymbol s);
+void ffestorag_init_2 (void);
+ffestorag ffestorag_new (ffestoragList sl);
+void ffestorag_report (void);
+void ffestorag_update (ffestorag s, ffesymbol sym, ffeinfoBasictype bt,
+ ffeinfoKindtype kt);
+void ffestorag_update_init (ffestorag s);
+void ffestorag_update_save (ffestorag s);
+
+/* Define macros. */
+
+#define ffestorag_accretes(s) ((s)->accretes)
+#define ffestorag_accretion(s) ((s)->accretion)
+#define ffestorag_alignment(s) ((s)->alignment)
+#define ffestorag_basictype(s) ((s)->basic_type)
+#define ffestorag_hook(s) ((s)->hook)
+#define ffestorag_init(s) ((s)->init)
+#define ffestorag_init_0()
+#define ffestorag_init_1()
+#define ffestorag_init_3()
+#define ffestorag_init_4()
+#define ffestorag_is_init(s) ((s)->is_init)
+#define ffestorag_is_save(s) ((s)->is_save)
+#define ffestorag_kindtype(s) ((s)->kind_type)
+#define ffestorag_list_equivs(s) (&(s)->equivs_)
+#define ffestorag_list_master() (&ffestorag_list_)
+#define ffestorag_modulo(s) ((s)->modulo)
+#define ffestorag_offset(s) ((s)->offset)
+#define ffestorag_parent(s) ((s)->parent)
+#define ffestorag_ptr_to_alignment(s) (&(s)->alignment)
+#define ffestorag_ptr_to_modulo(s) (&(s)->modulo)
+#define ffestorag_set_accretes(s,a) ((s)->accretes = (a))
+#define ffestorag_set_accretion(s,a) ((s)->accretion = (a))
+#define ffestorag_set_alignment(s,a) ((s)->alignment = (a))
+#define ffestorag_set_basictype(s,b) ((s)->basic_type = (b))
+#define ffestorag_set_hook(s,h) ((s)->hook = (h))
+#define ffestorag_set_init(s,i) ((s)->init = (i))
+#define ffestorag_set_is_init(s,in) ((s)->is_init = (in))
+#define ffestorag_set_is_save(s,sa) ((s)->is_save = (sa))
+#define ffestorag_set_kindtype(s,k) ((s)->kind_type = (k))
+#define ffestorag_set_modulo(s,m) ((s)->modulo = (m))
+#define ffestorag_set_offset(s,o) ((s)->offset = (o))
+#define ffestorag_set_parent(s,p) ((s)->parent = (p))
+#define ffestorag_set_size(s,si) ((s)->size = (si))
+#define ffestorag_set_symbol(s,sy) ((s)->symbol = (sy))
+#define ffestorag_set_type(s,t) ((s)->type = (t))
+#define ffestorag_set_typesymbol(s,sy) ((s)->type_symbol = (sy))
+#define ffestorag_size(s) ((s)->size)
+#define ffestorag_symbol(s) ((s)->symbol)
+#define ffestorag_terminate_0()
+#define ffestorag_terminate_1()
+#define ffestorag_terminate_2()
+#define ffestorag_terminate_3()
+#define ffestorag_terminate_4()
+#define ffestorag_type(s) ((s)->type)
+#define ffestorag_typesymbol(s) ((s)->type_symbol)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/stp.c b/contrib/gcc/f/stp.c
new file mode 100644
index 0000000..6c95c74
--- /dev/null
+++ b/contrib/gcc/f/stp.c
@@ -0,0 +1,59 @@
+/* stp.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Keeps track of some information needed while parsing (and usually
+ before the exact statement is not confirmed).
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "stp.h"
+
+/* Externals defined here. */
+
+union _ffestp_fileu_ ffestp_file;
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
diff --git a/contrib/gcc/f/stp.h b/contrib/gcc/f/stp.h
new file mode 100644
index 0000000..edfccc6
--- /dev/null
+++ b/contrib/gcc/f/stp.h
@@ -0,0 +1,508 @@
+/* stp.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ stp.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_stp
+#define _H_f_stp
+
+/* Simple definitions and enumerations. */
+
+enum _ffestp_acceptix_
+ {
+ FFESTP_acceptixFORMAT,
+ FFESTP_acceptix
+ };
+typedef enum _ffestp_acceptix_ ffestpAcceptIx;
+
+enum _ffestp_attrib_
+ {
+#if FFESTR_F90
+ FFESTP_attribALLOCATABLE,
+#endif
+ FFESTP_attribDIMENSION,
+ FFESTP_attribEXTERNAL,
+#if FFESTR_F90
+ FFESTP_attribINTENT,
+#endif
+ FFESTP_attribINTRINSIC,
+#if FFESTR_F90
+ FFESTP_attribOPTIONAL,
+#endif
+ FFESTP_attribPARAMETER,
+#if FFESTR_F90
+ FFESTP_attribPOINTER,
+#endif
+#if FFESTR_F90
+ FFESTP_attribPRIVATE,
+ FFESTP_attribPUBLIC,
+#endif
+ FFESTP_attribSAVE,
+#if FFESTR_F90
+ FFESTP_attribTARGET,
+#endif
+ FFESTP_attrib
+ };
+typedef enum _ffestp_attrib_ ffestpAttrib;
+
+enum _ffestp_beruix_
+ {
+ FFESTP_beruixERR,
+ FFESTP_beruixIOSTAT,
+ FFESTP_beruixUNIT,
+ FFESTP_beruix
+ };
+typedef enum _ffestp_beruix_ ffestpBeruIx;
+
+enum _ffestp_closeix_
+ {
+ FFESTP_closeixERR,
+ FFESTP_closeixIOSTAT,
+ FFESTP_closeixSTATUS,
+ FFESTP_closeixUNIT,
+ FFESTP_closeix
+ };
+typedef enum _ffestp_closeix_ ffestpCloseIx;
+
+enum _ffestp_deleteix_
+ {
+ FFESTP_deleteixERR,
+ FFESTP_deleteixIOSTAT,
+ FFESTP_deleteixREC,
+ FFESTP_deleteixUNIT,
+ FFESTP_deleteix
+ };
+typedef enum _ffestp_deleteix_ ffestpDeleteIx;
+
+enum _ffestp_findix_
+ {
+ FFESTP_findixERR,
+ FFESTP_findixIOSTAT,
+ FFESTP_findixREC,
+ FFESTP_findixUNIT,
+ FFESTP_findix
+ };
+typedef enum _ffestp_findix_ ffestpFindIx;
+
+enum _ffestp_inquireix_
+ {
+ FFESTP_inquireixACCESS,
+ FFESTP_inquireixACTION,
+ FFESTP_inquireixBLANK,
+ FFESTP_inquireixCARRIAGECONTROL,
+ FFESTP_inquireixDEFAULTFILE,
+ FFESTP_inquireixDELIM,
+ FFESTP_inquireixDIRECT,
+ FFESTP_inquireixERR,
+ FFESTP_inquireixEXIST,
+ FFESTP_inquireixFILE,
+ FFESTP_inquireixFORM,
+ FFESTP_inquireixFORMATTED,
+ FFESTP_inquireixIOLENGTH,
+ FFESTP_inquireixIOSTAT,
+ FFESTP_inquireixKEYED,
+ FFESTP_inquireixNAME,
+ FFESTP_inquireixNAMED,
+ FFESTP_inquireixNEXTREC,
+ FFESTP_inquireixNUMBER,
+ FFESTP_inquireixOPENED,
+ FFESTP_inquireixORGANIZATION,
+ FFESTP_inquireixPAD,
+ FFESTP_inquireixPOSITION,
+ FFESTP_inquireixREAD,
+ FFESTP_inquireixREADWRITE,
+ FFESTP_inquireixRECL,
+ FFESTP_inquireixRECORDTYPE,
+ FFESTP_inquireixSEQUENTIAL,
+ FFESTP_inquireixUNFORMATTED,
+ FFESTP_inquireixUNIT,
+ FFESTP_inquireixWRITE,
+ FFESTP_inquireix
+ };
+typedef enum _ffestp_inquireix_ ffestpInquireIx;
+
+enum _ffestp_openix_
+ {
+ FFESTP_openixACCESS,
+ FFESTP_openixACTION,
+ FFESTP_openixASSOCIATEVARIABLE,
+ FFESTP_openixBLANK,
+ FFESTP_openixBLOCKSIZE,
+ FFESTP_openixBUFFERCOUNT,
+ FFESTP_openixCARRIAGECONTROL,
+ FFESTP_openixDEFAULTFILE,
+ FFESTP_openixDELIM,
+ FFESTP_openixDISPOSE,
+ FFESTP_openixERR,
+ FFESTP_openixEXTENDSIZE,
+ FFESTP_openixFILE,
+ FFESTP_openixFORM,
+ FFESTP_openixINITIALSIZE,
+ FFESTP_openixIOSTAT,
+ FFESTP_openixKEY,
+ FFESTP_openixMAXREC,
+ FFESTP_openixNOSPANBLOCKS,
+ FFESTP_openixORGANIZATION,
+ FFESTP_openixPAD,
+ FFESTP_openixPOSITION,
+ FFESTP_openixREADONLY,
+ FFESTP_openixRECL,
+ FFESTP_openixRECORDTYPE,
+ FFESTP_openixSHARED,
+ FFESTP_openixSTATUS,
+ FFESTP_openixUNIT,
+ FFESTP_openixUSEROPEN,
+ FFESTP_openix
+ };
+typedef enum _ffestp_openix_ ffestpOpenIx;
+
+enum _ffestp_printix_
+ {
+ FFESTP_printixFORMAT,
+ FFESTP_printix
+ };
+typedef enum _ffestp_printix_ ffestpPrintIx;
+
+enum _ffestp_readix_
+ {
+ FFESTP_readixADVANCE,
+ FFESTP_readixEND,
+ FFESTP_readixEOR,
+ FFESTP_readixERR,
+ FFESTP_readixFORMAT, /* Or NAMELIST (use expr info to
+ distinguish). */
+ FFESTP_readixIOSTAT,
+ FFESTP_readixKEYEQ,
+ FFESTP_readixKEYGE,
+ FFESTP_readixKEYGT,
+ FFESTP_readixKEYID,
+ FFESTP_readixNULLS,
+ FFESTP_readixREC,
+ FFESTP_readixSIZE,
+ FFESTP_readixUNIT,
+ FFESTP_readix
+ };
+typedef enum _ffestp_readix_ ffestpReadIx;
+
+enum _ffestp_rewriteix_
+ {
+ FFESTP_rewriteixERR,
+ FFESTP_rewriteixFMT,
+ FFESTP_rewriteixIOSTAT,
+ FFESTP_rewriteixUNIT,
+ FFESTP_rewriteix
+ };
+typedef enum _ffestp_rewriteix_ ffestpRewriteIx;
+
+enum _ffestp_typeix_
+ {
+ FFESTP_typeixFORMAT,
+ FFESTP_typeix
+ };
+typedef enum _ffestp_typeix_ ffestpTypeIx;
+
+enum _ffestp_vxtcodeix_
+ {
+ FFESTP_vxtcodeixB,
+ FFESTP_vxtcodeixC,
+ FFESTP_vxtcodeixERR,
+ FFESTP_vxtcodeixF,
+ FFESTP_vxtcodeixIOSTAT,
+ FFESTP_vxtcodeix
+ };
+typedef enum _ffestp_vxtcodeix_ ffestpVxtcodeIx;
+
+enum _ffestp_writeix_
+ {
+ FFESTP_writeixADVANCE,
+ FFESTP_writeixEOR,
+ FFESTP_writeixERR,
+ FFESTP_writeixFORMAT, /* Or NAMELIST (use expr info to
+ distinguish). */
+ FFESTP_writeixIOSTAT,
+ FFESTP_writeixREC,
+ FFESTP_writeixUNIT,
+ FFESTP_writeix
+ };
+typedef enum _ffestp_writeix_ ffestpWriteIx;
+
+#if FFESTR_F90
+enum _ffestp_definedoperator_
+ {
+ FFESTP_definedoperatorNone, /* INTERFACE generic-name. */
+ FFESTP_definedoperatorOPERATOR, /* INTERFACE
+ OPERATOR(defined-operator). */
+ FFESTP_definedoperatorASSIGNMENT, /* INTERFACE ASSIGNMENT(=). */
+ FFESTP_definedoperatorPOWER,
+ FFESTP_definedoperatorMULT,
+ FFESTP_definedoperatorADD,
+ FFESTP_definedoperatorCONCAT,
+ FFESTP_definedoperatorDIVIDE,
+ FFESTP_definedoperatorSUBTRACT,
+ FFESTP_definedoperatorNOT,
+ FFESTP_definedoperatorAND,
+ FFESTP_definedoperatorOR,
+ FFESTP_definedoperatorEQV,
+ FFESTP_definedoperatorNEQV,
+ FFESTP_definedoperatorEQ,
+ FFESTP_definedoperatorNE,
+ FFESTP_definedoperatorLT,
+ FFESTP_definedoperatorLE,
+ FFESTP_definedoperatorGT,
+ FFESTP_definedoperatorGE,
+ FFESTP_definedoperator
+ };
+typedef enum _ffestp_definedoperator_ ffestpDefinedOperator;
+#endif
+
+enum _ffestp_dimtype_
+ {
+ FFESTP_dimtypeNONE,
+ FFESTP_dimtypeKNOWN, /* Known-bounds dimension list. */
+ FFESTP_dimtypeADJUSTABLE, /* Adjustable dimension list. */
+ FFESTP_dimtypeASSUMED, /* Assumed dimension list (known except for
+ last). */
+ FFESTP_dimtypeADJUSTABLEASSUMED, /* Both. */
+ FFESTP_dimtype
+ };
+typedef enum _ffestp_dimtype_ ffestpDimtype;
+
+enum _ffestp_formattype_
+ {
+ FFESTP_formattypeNone,
+ FFESTP_formattypeI,
+ FFESTP_formattypeB,
+ FFESTP_formattypeO,
+ FFESTP_formattypeZ,
+ FFESTP_formattypeF,
+ FFESTP_formattypeE,
+ FFESTP_formattypeEN,
+ FFESTP_formattypeG,
+ FFESTP_formattypeL,
+ FFESTP_formattypeA,
+ FFESTP_formattypeD,
+ FFESTP_formattypeQ,
+ FFESTP_formattypeDOLLAR, /* $ (V-extension). */
+ FFESTP_formattypeP,
+ FFESTP_formattypeT,
+ FFESTP_formattypeTL,
+ FFESTP_formattypeTR,
+ FFESTP_formattypeX,
+ FFESTP_formattypeS,
+ FFESTP_formattypeSP,
+ FFESTP_formattypeSS,
+ FFESTP_formattypeBN,
+ FFESTP_formattypeBZ,
+ FFESTP_formattypeH, /* Hollerith, used only for error-reporting. */
+ FFESTP_formattypeSLASH,
+ FFESTP_formattypeCOLON,
+ FFESTP_formattypeR1016, /* char-literal-constant or cHchars. */
+ FFESTP_formattypeFORMAT, /* [r](format-item-list). */
+ FFESTP_formattype
+ };
+typedef enum _ffestp_formattype_ ffestpFormatType;
+
+enum _ffestp_type_
+ {
+ FFESTP_typeNone,
+ FFESTP_typeINTEGER,
+ FFESTP_typeREAL,
+ FFESTP_typeCOMPLEX,
+ FFESTP_typeLOGICAL,
+ FFESTP_typeCHARACTER,
+ FFESTP_typeDBLPRCSN,
+ FFESTP_typeDBLCMPLX,
+ FFESTP_typeBYTE,
+ FFESTP_typeWORD,
+#if FFESTR_F90
+ FFESTP_typeTYPE,
+#endif
+ FFESTP_type
+ };
+typedef enum _ffestp_type_ ffestpType;
+
+/* Typedefs. */
+
+typedef struct _ffest_accept_stmt_ ffestpAcceptStmt;
+typedef struct _ffest_beru_stmt_ ffestpBeruStmt;
+typedef struct _ffest_close_stmt_ ffestpCloseStmt;
+typedef struct _ffest_delete_stmt_ ffestpDeleteStmt;
+typedef struct _ffestp_file ffestpFile;
+typedef struct _ffest_find_stmt_ ffestpFindStmt;
+typedef struct _ffest_inquire_stmt_ ffestpInquireStmt;
+typedef struct _ffest_open_stmt_ ffestpOpenStmt;
+typedef struct _ffest_print_stmt_ ffestpPrintStmt;
+typedef struct _ffest_read_stmt_ ffestpReadStmt;
+typedef struct _ffest_rewrite_stmt_ ffestpRewriteStmt;
+typedef struct _ffest_type_stmt_ ffestpTypeStmt;
+typedef struct _ffest_vxtcode_stmt_ ffestpVxtcodeStmt;
+typedef struct _ffest_write_stmt_ ffestpWriteStmt;
+
+/* Include files needed by this one. */
+
+#include "bld.h"
+#include "lab.h"
+#include "lex.h"
+#include "stp.h"
+#include "stt.h"
+
+/* Structure definitions. */
+
+struct _ffestp_file
+ {
+ bool kw_or_val_present; /* If FALSE, all else is n/a. */
+ bool kw_present; /* Indicates whether kw has a token. */
+ bool value_present; /* Indicates whether value/expr are valid. */
+ bool value_is_label; /* TRUE if expr has no expression, value is
+ NUMBER. */
+ ffelexToken kw; /* The keyword, iff kw_or_val_present &&
+ kw_present. */
+ ffelexToken value; /* The value, iff kw_or_val_present &&
+ value_present. */
+ union
+ {
+ ffebld expr; /* The expr, iff kw_or_val_present &&
+ value_present && !value_is_label. */
+ ffelab label; /* The label, iff kw_or_val_present &&
+ value_present && value_is_label. */
+ }
+ u;
+ };
+
+struct _ffest_accept_stmt_
+ {
+ ffestpFile accept_spec[FFESTP_acceptix];
+ };
+
+struct _ffest_beru_stmt_
+ {
+ ffestpFile beru_spec[FFESTP_beruix];
+ };
+
+struct _ffest_close_stmt_
+ {
+ ffestpFile close_spec[FFESTP_closeix];
+ };
+
+struct _ffest_delete_stmt_
+ {
+ ffestpFile delete_spec[FFESTP_deleteix];
+ };
+
+struct _ffest_find_stmt_
+ {
+ ffestpFile find_spec[FFESTP_findix];
+ };
+
+struct _ffest_imp_list_
+ {
+ ffesttImpList next;
+ ffesttImpList previous;
+ ffelexToken first;
+ ffelexToken last; /* NULL if a single letter. */
+ };
+
+struct _ffest_inquire_stmt_
+ {
+ ffestpFile inquire_spec[FFESTP_inquireix];
+ };
+
+struct _ffest_open_stmt_
+ {
+ ffestpFile open_spec[FFESTP_openix];
+ };
+
+struct _ffest_print_stmt_
+ {
+ ffestpFile print_spec[FFESTP_printix];
+ };
+
+struct _ffest_read_stmt_
+ {
+ ffestpFile read_spec[FFESTP_readix];
+ };
+
+struct _ffest_rewrite_stmt_
+ {
+ ffestpFile rewrite_spec[FFESTP_rewriteix];
+ };
+
+struct _ffest_type_stmt_
+ {
+ ffestpFile type_spec[FFESTP_typeix];
+ };
+
+struct _ffest_vxtcode_stmt_
+ {
+ ffestpFile vxtcode_spec[FFESTP_vxtcodeix];
+ };
+
+struct _ffest_write_stmt_
+ {
+ ffestpFile write_spec[FFESTP_writeix];
+ };
+
+union _ffestp_fileu_
+ {
+ ffestpAcceptStmt accept;
+ ffestpBeruStmt beru;
+ ffestpCloseStmt close;
+ ffestpDeleteStmt delete;
+ ffestpFindStmt find;
+ ffestpInquireStmt inquire;
+ ffestpOpenStmt open;
+ ffestpPrintStmt print;
+ ffestpReadStmt read;
+ ffestpRewriteStmt rewrite;
+ ffestpTypeStmt type;
+ ffestpVxtcodeStmt vxtcode;
+ ffestpWriteStmt write;
+ };
+
+/* Global objects accessed by users of this module. */
+
+extern union _ffestp_fileu_ ffestp_file;
+
+/* Declare functions with prototypes. */
+
+
+/* Define macros. */
+
+#define ffestp_init_0()
+#define ffestp_init_1()
+#define ffestp_init_2()
+#define ffestp_init_3()
+#define ffestp_init_4()
+#define ffestp_terminate_0()
+#define ffestp_terminate_1()
+#define ffestp_terminate_2()
+#define ffestp_terminate_3()
+#define ffestp_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/str-1t.fin b/contrib/gcc/f/str-1t.fin
new file mode 100644
index 0000000..674c92d
--- /dev/null
+++ b/contrib/gcc/f/str-1t.fin
@@ -0,0 +1,135 @@
+{
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+}
+
+FFESTR_first // // ffestrFirst ffestr_first 1 1
+;Accept ACCEPT
+;Allocatable ALLOCATABLE
+;Allocate ALLOCATE
+Assign ASSIGN
+Backspace BACKSPACE
+Block BLOCK
+BlockData BLOCKDATA
+Byte BYTE
+Call CALL
+Case CASE
+CaseDefault CASEDEFAULT
+Character CHRCTR
+Close CLOSE
+Common COMMON
+Complex CMPLX
+;Contains CONTAINS
+Continue CONTINUE
+Cycle CYCLE
+Data DATA
+;Deallocate DEALLOCATE
+Decode DECODE
+Define DEFINE
+;DefineFile DEFINEFILE
+Delete DELETE
+Dimension DIMENSION
+Do DO
+Double DBL
+DoubleComplex DBLCMPLX
+DoublePrecision DBLPRCSN
+DoWhile DOWHILE
+Else ELSE
+ElseIf ELSEIF
+;ElseWhere ELSEWHERE
+Encode ENCODE
+End END
+EndBlock ENDBLOCK
+EndBlockData ENDBLOCKDATA
+EndDo ENDDO
+EndFile ENDFILE
+EndFunction ENDFUNCTION
+EndIf ENDIF
+;EndInterface ENDINTERFACE
+;EndMap ENDMAP
+;EndModule ENDMODULE
+EndProgram ENDPROGRAM
+EndSelect ENDSELECT
+;EndStructure ENDSTRUCTURE
+EndSubroutine ENDSUBROUTINE
+;EndType ENDTYPE
+;EndUnion ENDUNION
+;EndWhere ENDWHERE
+Entry ENTRY
+Equivalence EQUIVALENCE
+Exit EXIT
+External EXTERNAL
+Find FIND
+Format FORMAT
+Function FUNCTION
+Go GO
+GoTo GOTO
+If IF
+Implicit IMPLICIT
+Include INCLUDE
+Inquire INQUIRE
+Integer INTGR
+;Intent INTENT
+;Interface INTERFACE
+;InterfaceAssignment INTERFACEASSGNMNT
+;InterfaceOperator INTERFACEOPERATOR
+Intrinsic INTRINSIC
+Logical LGCL
+;Map MAP
+;Module MODULE
+;ModuleProcedure MODULEPROCEDURE
+NameList NAMELIST
+;Nullify NULLIFY
+Open OPEN
+;Optional OPTIONAL
+Parameter PARAMETER
+Pause PAUSE
+;Pointer POINTER
+Print PRINT
+;Private PRIVATE
+Program PROGRAM
+;Public PUBLIC
+Read READ
+Real REAL
+;Record RECORD
+;Recursive RECURSIVE
+;RecursiveFunction RECURSIVEFNCTN
+Return RETURN
+Rewind REWIND
+;Rewrite REWRITE
+Save SAVE
+Select SELECT
+SelectCase SELECTCASE
+;Sequence SEQUENCE
+Stop STOP
+;Structure STRUCTURE
+Subroutine SUBROUTINE
+;Target TARGET
+Then THEN
+Type TYPE
+;Union UNION
+;Unlock UNLOCK
+;Use USE
+Virtual VIRTUAL
+Volatile VOLATILE
+;Where WHERE
+Word WORD
+Write WRITE
diff --git a/contrib/gcc/f/str-2t.fin b/contrib/gcc/f/str-2t.fin
new file mode 100644
index 0000000..ea86819
--- /dev/null
+++ b/contrib/gcc/f/str-2t.fin
@@ -0,0 +1,60 @@
+{
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+}
+
+FFESTR_second // // ffestrSecond ffestr_second 1 0
+;Assignment ASSIGNMENT
+Block BLOCK
+BlockData BLOCKDATA
+Byte BYTE
+Case CASE
+Character CHARACTER
+Complex COMPLEX
+Data DATA
+Default DEFAULT
+Do DO
+Double DOUBLE
+DoubleComplex DOUBLECOMPLEX
+DoublePrecision DOUBLEPRECISION
+File FILE
+Function FUNCTION
+If IF
+Integer INTEGER
+;Interface INTERFACE
+Logical LOGICAL
+;Map MAP
+;Module MODULE
+None NONE
+;Operator OPERATOR
+Precision PRECISION
+;Procedure PROCEDURE
+Program PROGRAM
+Real REAL
+Select SELECT
+;Structure STRUCTURE
+Subroutine SUBROUTINE
+To TO
+;Type TYPE
+;Union UNION
+;Where WHERE
+While WHILE
+Word WORD
diff --git a/contrib/gcc/f/str-fo.fin b/contrib/gcc/f/str-fo.fin
new file mode 100644
index 0000000..243941f
--- /dev/null
+++ b/contrib/gcc/f/str-fo.fin
@@ -0,0 +1,55 @@
+{
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+}
+
+FFESTR_format // // ffestrFormat ffestr_format 0 1
+$ DOLLAR
+A A
+B B
+BN BN
+BZ BZ
+D D
+E E
+En EN
+F F
+G G
+H H
+I I
+L L
+N N
+O O
+P P
+PD PD
+PE PE
+PEn PEN
+PF PF
+PG PG
+Q Q
+R R
+S S
+SP SP
+SS SS
+T T
+TL TL
+TR TR
+X X
+Z Z
diff --git a/contrib/gcc/f/str-io.fin b/contrib/gcc/f/str-io.fin
new file mode 100644
index 0000000..4124da6
--- /dev/null
+++ b/contrib/gcc/f/str-io.fin
@@ -0,0 +1,43 @@
+{
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+}
+
+FFESTR_genio // // ffestrGenio ffestr_genio 1 0
+Advance ADVANCE
+Disp DISP
+Dispose DISPOSE
+End END
+EoR EOR
+Err ERR
+Fmt FMT
+IOStat IOSTAT
+Key KEY
+KeyEQ KEYEQ
+KeyGE KEYGE
+KeyGT KEYGT
+KeyID KEYID
+Nml NML
+Nulls NULLS
+Rec REC
+Size SIZE
+Status STATUS
+Unit UNIT
diff --git a/contrib/gcc/f/str-nq.fin b/contrib/gcc/f/str-nq.fin
new file mode 100644
index 0000000..cce8745
--- /dev/null
+++ b/contrib/gcc/f/str-nq.fin
@@ -0,0 +1,55 @@
+{
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+}
+
+FFESTR_inquire // // ffestrInquire ffestr_inquire 1 0
+Access ACCESS
+Action ACTION
+Blank BLANK
+CarriageControl CARRIAGECONTROL
+DefaultFile DEFAULTFILE
+Delim DELIM
+Direct DIRECT
+Err ERR
+Exist EXIST
+File FILE
+Form FORM
+Formatted FORMATTED
+IOLength IOLENGTH
+IOStat IOSTAT
+Keyed KEYED
+Name NAME
+Named NAMED
+NextRec NEXTREC
+Number NUMBER
+Opened OPENED
+Organization ORGANIZATION
+Pad PAD
+Position POSITION
+Read READ
+ReadWrite READWRITE
+RecL RECL
+RecordType RECORDTYPE
+Sequential SEQUENTIAL
+Unformatted UNFORMATTED
+Unit UNIT
+Write WRITE
diff --git a/contrib/gcc/f/str-op.fin b/contrib/gcc/f/str-op.fin
new file mode 100644
index 0000000..62396f2
--- /dev/null
+++ b/contrib/gcc/f/str-op.fin
@@ -0,0 +1,57 @@
+{
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+}
+
+FFESTR_open // // ffestrOpen ffestr_open 1 0
+Access ACCESS
+Action ACTION
+AssociateVariable ASSOCIATEVARIABLE
+Blank BLANK
+BlockSize BLOCKSIZE
+BufferCount BUFFERCOUNT
+CarriageControl CARRIAGECONTROL
+DefaultFile DEFAULTFILE
+Delim DELIM
+Disp DISP
+Dispose DISPOSE
+Err ERR
+ExtendSize EXTENDSIZE
+File FILE
+Form FORM
+InitialSize INITIALSIZE
+IOStat IOSTAT
+Key KEY
+MaxRec MAXREC
+Name NAME
+NoSpanBlocks NOSPANBLOCKS
+Organization ORGANIZATION
+Pad PAD
+Position POSITION
+Readonly READONLY
+Recl RECL
+RecordSize RECORDSIZE
+RecordType RECORDTYPE
+Shared SHARED
+Status STATUS
+Type TYPE
+Unit UNIT
+UserOpen USEROPEN
diff --git a/contrib/gcc/f/str-ot.fin b/contrib/gcc/f/str-ot.fin
new file mode 100644
index 0000000..a4ad768
--- /dev/null
+++ b/contrib/gcc/f/str-ot.fin
@@ -0,0 +1,50 @@
+{
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+}
+
+FFESTR_other // // ffestrOther ffestr_other 1 1
+And AND
+;Dimension DIMENSION
+Eq EQ
+Eqv EQV
+False FALSE
+GE GE
+GT GT
+In IN
+InOut INOUT
+Kind KIND
+LE LE
+Len LEN
+LT LT
+NE NE
+NEqv NEQV
+Not NOT
+;Only ONLY
+Or OR
+Out OUT
+;Pointer POINTER
+;Private PRIVATE
+;Public PUBLIC
+Result RESULT
+;Stat STAT
+True TRUE
+XOr XOR
diff --git a/contrib/gcc/f/str.c b/contrib/gcc/f/str.c
new file mode 100644
index 0000000..8622789
--- /dev/null
+++ b/contrib/gcc/f/str.c
@@ -0,0 +1,217 @@
+/* str.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Handles recognition of keywords.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "src.h"
+#include "str.h"
+#include "lex.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+
+/* ffestr_first -- Look up the first names in a statement
+
+ ffestrFirst kw;
+ ffelexToken t;
+ kw = ffestr_first(t);
+
+ Returns FFESTR_firstNone if no matches, else FFESTR_firstXYZ if the
+ NAME or NAMES token matches XYZ. t must be a NAME or NAMES token or this
+ routine will crash.
+
+ This routine's code is actually written by a utility called FINI, itself
+ written specifically for the Gnu Fortran project. FINI takes an input
+ file, in this case "ffe_first.fini", consisting primarily of a
+ list of statements (ASSIGN, IF, DO, DOWHILE), and outputs a C file,
+ "str-1t.j", that contains the definition of the
+ ffestr_first function. We #include that file here.
+
+ 30-Jan-90 JCB 2.0
+ Updated for Fortran 90.
+*/
+
+#ifndef MAKING_DEPENDENCIES
+#include "str-1t.j"
+#endif
+/* ffestr_format -- Look up format names in a statement
+
+ ffestrFormat kw;
+ ffelexToken t;
+ kw = ffestr_format(t);
+
+ Returns FFESTR_formatNone if no matches, else FFESTR_formatXYZ if the
+ NAME or NAMES token matches XYZ. t must be a NAME or NAMES token or this
+ routine will crash.
+
+ This routine's code is actually written by a utility called FINI, itself
+ written specifically for the Gnu Fortran project. FINI takes an input
+ file, in this case "ffe_format.fini", consisting primarily of a
+ list of format keywords (I, F, TL, TR), and outputs a C file,
+ "str-fo.j", that contains the definition of the
+ ffestr_format function. We #include that file here.
+
+*/
+
+#ifndef MAKING_DEPENDENCIES
+#include "str-fo.j"
+#endif
+/* ffestr_genio -- Look up genio names in a statement
+
+ ffestrGenio kw;
+ ffelexToken t;
+ kw = ffestr_genio(t);
+
+ Returns FFESTR_genioNone if no matches, else FFESTR_genioXYZ if the
+ NAME or NAMES token matches XYZ. t must be a NAME or NAMES token or this
+ routine will crash.
+
+ This routine's code is actually written by a utility called FINI, itself
+ written specifically for the Gnu Fortran project. FINI takes an input
+ file, in this case "ffe_genio.fini", consisting primarily of a
+ list of statement keywords (TO, FUNCTION), and outputs a C file,
+ "str-io.j", that contains the definition of the
+ ffestr_genio function. We #include that file here.
+
+*/
+
+#ifndef MAKING_DEPENDENCIES
+#include "str-io.j"
+#endif
+/* ffestr_inquire -- Look up inquire names in a statement
+
+ ffestrInquire kw;
+ ffelexToken t;
+ kw = ffestr_inquire(t);
+
+ Returns FFESTR_inquireNone if no matches, else FFESTR_inquireXYZ if the
+ NAME or NAMES token matches XYZ. t must be a NAME or NAMES token or this
+ routine will crash.
+
+ This routine's code is actually written by a utility called FINI, itself
+ written specifically for the Gnu Fortran project. FINI takes an input
+ file, in this case "ffe_inquire.fini", consisting primarily of a
+ list of statement keywords (TO, FUNCTION), and outputs a C file,
+ "str-nq.j", that contains the definition of the
+ ffestr_inquire function. We #include that file here.
+
+*/
+
+#ifndef MAKING_DEPENDENCIES
+#include "str-nq.j"
+#endif
+/* ffestr_open -- Look up open names in a statement
+
+ ffestrOpen kw;
+ ffelexToken t;
+ kw = ffestr_open(t);
+
+ Returns FFESTR_openNone if no matches, else FFESTR_openXYZ if the
+ NAME or NAMES token matches XYZ. t must be a NAME or NAMES token or this
+ routine will crash.
+
+ This routine's code is actually written by a utility called FINI, itself
+ written specifically for the Gnu Fortran project. FINI takes an input
+ file, in this case "ffe_open.fini", consisting primarily of a
+ list of statement keywords (TO, FUNCTION), and outputs a C file,
+ "str-op.j", that contains the definition of the
+ ffestr_open function. We #include that file here.
+
+*/
+
+#ifndef MAKING_DEPENDENCIES
+#include "str-op.j"
+#endif
+/* ffestr_other -- Look up other names in a statement
+
+ ffestrOther kw;
+ ffelexToken t;
+ kw = ffestr_other(t);
+
+ Returns FFESTR_otherNone if no matches, else FFESTR_otherXYZ if the
+ NAME or NAMES token matches XYZ. t must be a NAME or NAMES token or this
+ routine will crash.
+
+ This routine's code is actually written by a utility called FINI, itself
+ written specifically for the Gnu Fortran project. FINI takes an input
+ file, in this case "ffe_other.fini", consisting primarily of a
+ list of statement keywords (TO, FUNCTION), and outputs a C file,
+ "str-ot.j", that contains the definition of the
+ ffestr_other function. We #include that file here.
+
+*/
+
+#ifndef MAKING_DEPENDENCIES
+#include "str-ot.j"
+#endif
+/* ffestr_second -- Look up the second name in a statement
+
+ ffestrSecond kw;
+ ffelexToken t;
+ kw = ffestr_second(t);
+
+ Returns FFESTR_secondNone if no matches, else FFESTR_secondXYZ if the
+ NAME or NAMES token matches XYZ. t must be a NAME or NAMES token or this
+ routine will crash.
+
+ This routine's code is actually written by a utility called FINI, itself
+ written specifically for the Gnu Fortran project. FINI takes an input
+ file, in this case "ffe_second.fini", consisting primarily of a
+ list of statement keywords (TO, FUNCTION), and outputs a C file,
+ "str-2t.j", that contains the definition of the
+ ffestr_second function. We #include that file here.
+
+*/
+
+#ifndef MAKING_DEPENDENCIES
+#include "str-2t.j"
+#endif
diff --git a/contrib/gcc/f/str.h b/contrib/gcc/f/str.h
new file mode 100644
index 0000000..17b58ea
--- /dev/null
+++ b/contrib/gcc/f/str.h
@@ -0,0 +1,85 @@
+/* str.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ str.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_str
+#define _H_f_str
+
+/* Simple definitions and enumerations. */
+
+#define FFESTR_F90 0 /* Unsupported F90 stuff. */
+#define FFESTR_VXT 0 /* Unsupported VXT stuff. */
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "lex.h"
+#ifndef MAKING_DEPENDENCIES
+#include "str-1t.h"
+#include "str-fo.h"
+#include "str-io.h"
+#include "str-nq.h"
+#include "str-ot.h"
+#include "str-op.h"
+#include "str-2t.h"
+#endif
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+ffestrFirst ffestr_first (ffelexToken t);
+ffestrFormat ffestr_format (ffelexToken t);
+ffestrGenio ffestr_genio (ffelexToken t);
+ffestrInquire ffestr_inquire (ffelexToken t);
+ffestrOpen ffestr_open (ffelexToken t);
+ffestrOther ffestr_other (ffelexToken t);
+ffestrSecond ffestr_second (ffelexToken t);
+
+/* Define macros. */
+
+#define ffestr_init_0()
+#define ffestr_init_1()
+#define ffestr_init_2()
+#define ffestr_init_3()
+#define ffestr_init_4()
+#define ffestr_terminate_0()
+#define ffestr_terminate_1()
+#define ffestr_terminate_2()
+#define ffestr_terminate_3()
+#define ffestr_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/sts.c b/contrib/gcc/f/sts.c
new file mode 100644
index 0000000..1229ad5
--- /dev/null
+++ b/contrib/gcc/f/sts.c
@@ -0,0 +1,273 @@
+/* sts.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None (despite the name, it doesn't really depend on ffest*)
+
+ Description:
+ Provides an arbitrary-length string facility for the limited needs of
+ GNU Fortran FORMAT statement generation.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "sts.h"
+#include "com.h"
+#include "malloc.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+
+/* ffests_kill -- Kill a varying-length string
+
+ ffests s;
+ ffests_kill(s);
+
+ The storage associated with the string <s> is freed. */
+
+void
+ffests_kill (ffests s)
+{
+ if (s->text_ != NULL)
+ malloc_kill_ksr (s->pool_, s->text_, s->max_);
+}
+
+/* ffests_new -- Make a varying-length string
+
+ ffests s;
+ ffests_new(s,malloc_pool_image(),0);
+
+ The string is initialized to hold, in this case, 0 characters, and
+ current and future heap manipulations to hold the string will use
+ the image pool. */
+
+void
+ffests_new (ffests s, mallocPool pool, ffestsLength size)
+{
+ s->pool_ = pool;
+ s->len_ = 0;
+ s->max_ = size;
+
+ if (size == 0)
+ s->text_ = NULL;
+ else
+ s->text_ = malloc_new_ksr (pool, "ffests", size);
+}
+
+/* ffests_printf_1D -- printf("...%ld...",(long)) to a string
+
+ ffests s;
+ ffests_printf_1D(s,"...%ld...",1);
+
+ Like printf, but into a string. */
+
+void
+ffests_printf_1D (ffests s, char *ctl, long arg1)
+{
+ char quickbuf[40];
+ char *buff;
+ ffestsLength len;
+
+ if ((len = strlen (ctl) + 21) < ARRAY_SIZE (quickbuf))
+ /* No # bigger than 20 digits. */
+ {
+ sprintf (&quickbuf[0], ctl, arg1);
+ ffests_puttext (s, &quickbuf[0], strlen (quickbuf));
+ }
+ else
+ {
+ buff = malloc_new_ks (malloc_pool_image (), "ffests_printf_1D", len);
+ sprintf (buff, ctl, arg1);
+ ffests_puttext (s, buff, strlen (buff));
+ malloc_kill_ks (malloc_pool_image (), buff, len);
+ }
+}
+
+/* ffests_printf_1U -- printf("...%lu...",(unsigned long)) to a string
+
+ ffests s;
+ ffests_printf_1U(s,"...%lu...",1);
+
+ Like printf, but into a string. */
+
+void
+ffests_printf_1U (ffests s, char *ctl, unsigned long arg1)
+{
+ char quickbuf[40];
+ char *buff;
+ ffestsLength len;
+
+ if ((len = strlen (ctl) + 21) < ARRAY_SIZE (quickbuf))
+ /* No # bigger than 20 digits. */
+ {
+ sprintf (&quickbuf[0], ctl, arg1);
+ ffests_puttext (s, &quickbuf[0], strlen (quickbuf));
+ }
+ else
+ {
+ buff = malloc_new_ks (malloc_pool_image (), "ffests_printf_1U", len);
+ sprintf (buff, ctl, arg1);
+ ffests_puttext (s, buff, strlen (buff));
+ malloc_kill_ks (malloc_pool_image (), buff, len);
+ }
+}
+
+/* ffests_printf_1s -- printf("...%s...",(char *)) to a string
+
+ ffests s;
+ ffests_printf_1s(s,"...%s...","hi there!");
+
+ Like printf, but into a string. */
+
+void
+ffests_printf_1s (ffests s, char *ctl, char *arg1)
+{
+ char quickbuf[40];
+ char *buff;
+ ffestsLength len;
+
+ if ((len = strlen (ctl) + strlen (arg1) - 1) < ARRAY_SIZE (quickbuf))
+ {
+ sprintf (&quickbuf[0], ctl, arg1);
+ ffests_puttext (s, &quickbuf[0], strlen (quickbuf));
+ }
+ else
+ {
+ buff = malloc_new_ks (malloc_pool_image (), "ffests_printf_1s", len);
+ sprintf (buff, ctl, arg1);
+ ffests_puttext (s, buff, strlen (buff));
+ malloc_kill_ks (malloc_pool_image (), buff, len);
+ }
+}
+
+/* ffests_printf_2Us -- printf("...%lu...%s...",...) to a string
+
+ ffests s;
+ ffests_printf_2Us(s,"...%lu...%s...",1,"hi there!");
+
+ Like printf, but into a string. */
+
+void
+ffests_printf_2Us (ffests s, char *ctl, unsigned long arg1, char *arg2)
+{
+ char quickbuf[60];
+ char *buff;
+ ffestsLength len;
+
+ if ((len = strlen (ctl) + 21 + strlen (arg2) - 1) < ARRAY_SIZE (quickbuf))
+ /* No # bigger than 20 digits. */
+ {
+ sprintf (&quickbuf[0], ctl, arg1, arg2);
+ ffests_puttext (s, &quickbuf[0], strlen (quickbuf));
+ }
+ else
+ {
+ buff = malloc_new_ks (malloc_pool_image (), "ffests_printf_2Us", len);
+ sprintf (buff, ctl, arg1, arg2);
+ ffests_puttext (s, buff, strlen (buff));
+ malloc_kill_ks (malloc_pool_image (), buff, len);
+ }
+}
+
+/* ffests_putc -- Put a single character into string
+
+ ffests s;
+ ffests_putc(s,'*'); */
+
+void
+ffests_putc (ffests s, char c)
+{
+ ffests_puttext (s, &c, 1);
+}
+
+/* ffests_puts -- Put a zero-terminated (C-style) string into string
+
+ ffests s;
+ ffests_puts(s,"append me"); */
+
+void
+ffests_puts (ffests s, char *string)
+{
+ ffests_puttext (s, string, strlen (string));
+}
+
+/* ffests_puttext -- Put a number of characters into string
+
+ ffests s;
+ ffests_puttext(s,"hi there",8);
+
+ The string need not be 0-terminated, because the passed length is used,
+ and may be 0. */
+
+void
+ffests_puttext (ffests s, char *text, ffestsLength length)
+{
+ ffestsLength newlen;
+ ffestsLength newmax;
+
+ if (length <= 0)
+ return;
+
+ newlen = s->len_ + length;
+ if (newlen > s->max_)
+ {
+ if (s->text_ == NULL)
+ {
+ s->max_ = 40;
+ s->text_ = malloc_new_ksr (s->pool_, "ffests", s->max_);
+ }
+ else
+ {
+ newmax = s->max_ << 1;
+ while (newmax < newlen)
+ newmax <<= 1;
+ s->text_ = malloc_resize_ksr (s->pool_, s->text_, newmax, s->max_);
+ s->max_ = newmax;
+ }
+ }
+
+ memcpy (s->text_ + s->len_, text, length);
+ s->len_ = newlen;
+}
diff --git a/contrib/gcc/f/sts.h b/contrib/gcc/f/sts.h
new file mode 100644
index 0000000..d2c2b6e
--- /dev/null
+++ b/contrib/gcc/f/sts.h
@@ -0,0 +1,89 @@
+/* sts.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ sts.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_sts
+#define _H_f_sts
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+typedef struct _ffests_ *ffests;
+typedef struct _ffests_ ffestsHolder;
+typedef unsigned long int ffestsLength;
+
+/* Include files needed by this one. */
+
+#include "malloc.h"
+
+/* Structure definitions. */
+
+struct _ffests_
+ {
+ char *text_;
+ mallocPool pool_;
+ ffestsLength len_;
+ ffestsLength max_;
+ };
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+void ffests_kill (ffests s);
+void ffests_new (ffests s, mallocPool pool, ffestsLength size);
+void ffests_printf_1D (ffests s, char *ctl, long arg1);
+void ffests_printf_1U (ffests s, char *ctl, unsigned long arg1);
+void ffests_printf_1s (ffests s, char *ctl, char *arg1);
+void ffests_printf_2Us (ffests s, char *ctl, unsigned long arg1,
+ char *arg2);
+void ffests_putc (ffests s, char c);
+void ffests_puts (ffests s, char *string);
+void ffests_puttext (ffests s, char *text, ffestsLength length);
+
+/* Define macros. */
+
+#define ffests_init_0()
+#define ffests_init_1()
+#define ffests_init_2()
+#define ffests_init_3()
+#define ffests_init_4()
+#define ffests_length(s) ((s)->len_)
+#define ffests_terminate_0()
+#define ffests_terminate_1()
+#define ffests_terminate_2()
+#define ffests_terminate_3()
+#define ffests_terminate_4()
+#define ffests_text(s) ((s)->text_)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/stt.c b/contrib/gcc/f/stt.c
new file mode 100644
index 0000000..d2db379
--- /dev/null
+++ b/contrib/gcc/f/stt.c
@@ -0,0 +1,1044 @@
+/* stt.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995, 1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Manages lists of tokens and related info for parsing.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "stt.h"
+#include "bld.h"
+#include "expr.h"
+#include "info.h"
+#include "lex.h"
+#include "malloc.h"
+#include "sta.h"
+#include "stp.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+
+/* ffestt_caselist_append -- Append case to list of cases
+
+ ffesttCaseList list;
+ ffelexToken t;
+ ffestt_caselist_append(list,range,case1,case2,t);
+
+ list must have already been created by ffestt_caselist_create. The
+ list is allocated out of the scratch pool. The token is consumed. */
+
+void
+ffestt_caselist_append (ffesttCaseList list, bool range, ffebld case1,
+ ffebld case2, ffelexToken t)
+{
+ ffesttCaseList new;
+
+ new = (ffesttCaseList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST case list", sizeof (*new));
+ new->next = list->previous->next;
+ new->previous = list->previous;
+ new->next->previous = new;
+ new->previous->next = new;
+ new->expr1 = case1;
+ new->expr2 = case2;
+ new->range = range;
+ new->t = t;
+}
+
+/* ffestt_caselist_create -- Create new list of cases
+
+ ffesttCaseList list;
+ list = ffestt_caselist_create();
+
+ The list is allocated out of the scratch pool. */
+
+ffesttCaseList
+ffestt_caselist_create ()
+{
+ ffesttCaseList new;
+
+ new = (ffesttCaseList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST case list root",
+ sizeof (*new));
+ new->next = new->previous = new;
+ new->t = NULL;
+ new->expr1 = NULL;
+ new->expr2 = NULL;
+ new->range = FALSE;
+ return new;
+}
+
+/* ffestt_caselist_dump -- Dump list of cases
+
+ ffesttCaseList list;
+ ffestt_caselist_dump(list);
+
+ The cases in the list are dumped with commas separating them. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffestt_caselist_dump (ffesttCaseList list)
+{
+ ffesttCaseList next;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ if (next != list->next)
+ fputc (',', dmpout);
+ if (next->expr1 != NULL)
+ ffebld_dump (next->expr1);
+ if (next->range)
+ {
+ fputc (':', dmpout);
+ if (next->expr2 != NULL)
+ ffebld_dump (next->expr2);
+ }
+ }
+}
+#endif
+
+/* ffestt_caselist_kill -- Kill list of cases
+
+ ffesttCaseList list;
+ ffestt_caselist_kill(list);
+
+ The tokens on the list are killed.
+
+ 02-Mar-90 JCB 1.1
+ Don't kill the list itself or change it, since it will be trashed when
+ ffesta_scratch_pool is killed anyway, so kill only the lex tokens. */
+
+void
+ffestt_caselist_kill (ffesttCaseList list)
+{
+ ffesttCaseList next;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ ffelex_token_kill (next->t);
+ }
+}
+
+/* ffestt_dimlist_append -- Append dim to list of dims
+
+ ffesttDimList list;
+ ffelexToken t;
+ ffestt_dimlist_append(list,lower,upper,t);
+
+ list must have already been created by ffestt_dimlist_create. The
+ list is allocated out of the scratch pool. The token is consumed. */
+
+void
+ffestt_dimlist_append (ffesttDimList list, ffebld lower, ffebld upper,
+ ffelexToken t)
+{
+ ffesttDimList new;
+
+ new = (ffesttDimList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST dim list", sizeof (*new));
+ new->next = list->previous->next;
+ new->previous = list->previous;
+ new->next->previous = new;
+ new->previous->next = new;
+ new->lower = lower;
+ new->upper = upper;
+ new->t = t;
+}
+
+/* Convert list of dims into ffebld format.
+
+ ffesttDimList list;
+ ffeinfoRank rank;
+ ffebld array_size;
+ ffebld extents;
+ ffestt_dimlist_as_expr (list, &rank, &array_size, &extents);
+
+ The dims in the list are converted to a list of ITEMs; the rank of the
+ array, an expression representing the array size, a list of extent
+ expressions, and the list of ITEMs are returned.
+
+ If is_ugly_assumed, treat a final dimension with no lower bound
+ and an upper bound of 1 as a * bound. */
+
+ffebld
+ffestt_dimlist_as_expr (ffesttDimList list, ffeinfoRank *rank,
+ ffebld *array_size, ffebld *extents,
+ bool is_ugly_assumed)
+{
+ ffesttDimList next;
+ ffebld expr;
+ ffebld as;
+ ffebld ex; /* List of extents. */
+ ffebld ext; /* Extent of a given dimension. */
+ ffebldListBottom bottom;
+ ffeinfoRank r;
+ ffeinfoKindtype nkt;
+ ffetargetIntegerDefault low;
+ ffetargetIntegerDefault high;
+ bool zero = FALSE; /* Zero-size array. */
+ bool any = FALSE;
+ bool star = FALSE; /* Adjustable array. */
+
+ assert (list != NULL);
+
+ r = 0;
+ ffebld_init_list (&expr, &bottom);
+ for (next = list->next; next != list; next = next->next)
+ {
+ ++r;
+ if (((next->lower == NULL)
+ || (ffebld_op (next->lower) == FFEBLD_opCONTER))
+ && (ffebld_op (next->upper) == FFEBLD_opCONTER))
+ {
+ if (next->lower == NULL)
+ low = 1;
+ else
+ low = ffebld_constant_integerdefault (ffebld_conter (next->lower));
+ high = ffebld_constant_integerdefault (ffebld_conter (next->upper));
+ if (low
+ > high)
+ zero = TRUE;
+ if ((next->next == list)
+ && is_ugly_assumed
+ && (next->lower == NULL)
+ && (high == 1)
+ && (ffebld_conter_orig (next->upper) == NULL))
+ {
+ star = TRUE;
+ ffebld_append_item (&bottom,
+ ffebld_new_bounds (NULL, ffebld_new_star ()));
+ continue;
+ }
+ }
+ else if (((next->lower != NULL)
+ && (ffebld_op (next->lower) == FFEBLD_opANY))
+ || (ffebld_op (next->upper) == FFEBLD_opANY))
+ any = TRUE;
+ else if (ffebld_op (next->upper) == FFEBLD_opSTAR)
+ star = TRUE;
+ ffebld_append_item (&bottom,
+ ffebld_new_bounds (next->lower, next->upper));
+ }
+ ffebld_end_list (&bottom);
+
+ if (zero)
+ {
+ as = ffebld_new_conter (ffebld_constant_new_integerdefault_val (0));
+ ffebld_set_info (as, ffeinfo_new
+ (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ ex = NULL;
+ }
+ else if (any)
+ {
+ as = ffebld_new_any ();
+ ffebld_set_info (as, ffeinfo_new_any ());
+ ex = ffebld_copy (as);
+ }
+ else if (star)
+ {
+ as = ffebld_new_star ();
+ ex = ffebld_new_star (); /* ~~Should really be list as below. */
+ }
+ else
+ {
+ as = NULL;
+ ffebld_init_list (&ex, &bottom);
+ for (next = list->next; next != list; next = next->next)
+ {
+ if ((next->lower == NULL)
+ || ((ffebld_op (next->lower) == FFEBLD_opCONTER)
+ && (ffebld_constant_integerdefault (ffebld_conter
+ (next->lower)) == 1)))
+ ext = ffebld_copy (next->upper);
+ else
+ {
+ ext = ffebld_new_subtract (next->upper, next->lower);
+ nkt
+ = ffeinfo_kindtype_max (FFEINFO_basictypeINTEGER,
+ ffeinfo_kindtype (ffebld_info
+ (next->lower)),
+ ffeinfo_kindtype (ffebld_info
+ (next->upper)));
+ ffebld_set_info (ext,
+ ffeinfo_new (FFEINFO_basictypeINTEGER,
+ nkt,
+ 0,
+ FFEINFO_kindENTITY,
+ ((ffebld_op (ffebld_left (ext))
+ == FFEBLD_opCONTER)
+ && (ffebld_op (ffebld_right
+ (ext))
+ == FFEBLD_opCONTER))
+ ? FFEINFO_whereCONSTANT
+ : FFEINFO_whereFLEETING,
+ FFETARGET_charactersizeNONE));
+ ffebld_set_left (ext,
+ ffeexpr_convert_expr (ffebld_left (ext),
+ next->t, ext, next->t,
+ FFEEXPR_contextLET));
+ ffebld_set_right (ext,
+ ffeexpr_convert_expr (ffebld_right (ext),
+ next->t, ext,
+ next->t,
+ FFEEXPR_contextLET));
+ ext = ffeexpr_collapse_subtract (ext, next->t);
+
+ nkt
+ = ffeinfo_kindtype_max (FFEINFO_basictypeINTEGER,
+ ffeinfo_kindtype (ffebld_info (ext)),
+ FFEINFO_kindtypeINTEGERDEFAULT);
+ ext
+ = ffebld_new_add (ext,
+ ffebld_new_conter
+ (ffebld_constant_new_integerdefault_val
+ (1)));
+ ffebld_set_info (ffebld_right (ext), ffeinfo_new
+ (FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT,
+ 0,
+ FFEINFO_kindENTITY,
+ FFEINFO_whereCONSTANT,
+ FFETARGET_charactersizeNONE));
+ ffebld_set_info (ext,
+ ffeinfo_new (FFEINFO_basictypeINTEGER,
+ nkt, 0, FFEINFO_kindENTITY,
+ (ffebld_op (ffebld_left (ext))
+ == FFEBLD_opCONTER)
+ ? FFEINFO_whereCONSTANT
+ : FFEINFO_whereFLEETING,
+ FFETARGET_charactersizeNONE));
+ ffebld_set_left (ext,
+ ffeexpr_convert_expr (ffebld_left (ext),
+ next->t, ext,
+ next->t,
+ FFEEXPR_contextLET));
+ ffebld_set_right (ext,
+ ffeexpr_convert_expr (ffebld_right (ext),
+ next->t, ext,
+ next->t,
+ FFEEXPR_contextLET));
+ ext = ffeexpr_collapse_add (ext, next->t);
+ }
+ ffebld_append_item (&bottom, ext);
+ if (as == NULL)
+ as = ext;
+ else
+ {
+ nkt
+ = ffeinfo_kindtype_max (FFEINFO_basictypeINTEGER,
+ ffeinfo_kindtype (ffebld_info (as)),
+ ffeinfo_kindtype (ffebld_info (ext)));
+ as = ffebld_new_multiply (as, ext);
+ ffebld_set_info (as,
+ ffeinfo_new (FFEINFO_basictypeINTEGER,
+ nkt, 0, FFEINFO_kindENTITY,
+ ((ffebld_op (ffebld_left (as))
+ == FFEBLD_opCONTER)
+ && (ffebld_op (ffebld_right
+ (as))
+ == FFEBLD_opCONTER))
+ ? FFEINFO_whereCONSTANT
+ : FFEINFO_whereFLEETING,
+ FFETARGET_charactersizeNONE));
+ ffebld_set_left (as,
+ ffeexpr_convert_expr (ffebld_left (as),
+ next->t, as, next->t,
+ FFEEXPR_contextLET));
+ ffebld_set_right (as,
+ ffeexpr_convert_expr (ffebld_right (as),
+ next->t, as,
+ next->t,
+ FFEEXPR_contextLET));
+ as = ffeexpr_collapse_multiply (as, next->t);
+ }
+ }
+ ffebld_end_list (&bottom);
+ as = ffeexpr_convert (as, list->next->t, NULL,
+ FFEINFO_basictypeINTEGER,
+ FFEINFO_kindtypeINTEGERDEFAULT, 0,
+ FFETARGET_charactersizeNONE,
+ FFEEXPR_contextLET);
+ }
+
+ *rank = r;
+ *array_size = as;
+ *extents = ex;
+ return expr;
+}
+
+/* ffestt_dimlist_create -- Create new list of dims
+
+ ffesttDimList list;
+ list = ffestt_dimlist_create();
+
+ The list is allocated out of the scratch pool. */
+
+ffesttDimList
+ffestt_dimlist_create ()
+{
+ ffesttDimList new;
+
+ new = (ffesttDimList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST dim list root", sizeof (*new));
+ new->next = new->previous = new;
+ new->t = NULL;
+ new->lower = NULL;
+ new->upper = NULL;
+ return new;
+}
+
+/* ffestt_dimlist_dump -- Dump list of dims
+
+ ffesttDimList list;
+ ffestt_dimlist_dump(list);
+
+ The dims in the list are dumped with commas separating them. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffestt_dimlist_dump (ffesttDimList list)
+{
+ ffesttDimList next;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ if (next != list->next)
+ fputc (',', dmpout);
+ if (next->lower != NULL)
+ ffebld_dump (next->lower);
+ fputc (':', dmpout);
+ if (next->upper != NULL)
+ ffebld_dump (next->upper);
+ }
+}
+#endif
+
+/* ffestt_dimlist_kill -- Kill list of dims
+
+ ffesttDimList list;
+ ffestt_dimlist_kill(list);
+
+ The tokens on the list are killed. */
+
+void
+ffestt_dimlist_kill (ffesttDimList list)
+{
+ ffesttDimList next;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ ffelex_token_kill (next->t);
+ }
+}
+
+/* Determine type of list of dimensions.
+
+ Return KNOWN for all-constant bounds, ADJUSTABLE for constant
+ and variable but no * bounds, ASSUMED for constant and * but
+ not variable bounds, ADJUSTABLEASSUMED for constant and variable
+ and * bounds.
+
+ If is_ugly_assumed, treat a final dimension with no lower bound
+ and an upper bound of 1 as a * bound. */
+
+ffestpDimtype
+ffestt_dimlist_type (ffesttDimList list, bool is_ugly_assumed)
+{
+ ffesttDimList next;
+ ffestpDimtype type;
+
+ if (list == NULL)
+ return FFESTP_dimtypeNONE;
+
+ type = FFESTP_dimtypeKNOWN;
+ for (next = list->next; next != list; next = next->next)
+ {
+ bool ugly_assumed = FALSE;
+
+ if ((next->next == list)
+ && is_ugly_assumed
+ && (next->lower == NULL)
+ && (next->upper != NULL)
+ && (ffebld_op (next->upper) == FFEBLD_opCONTER)
+ && (ffebld_constant_integerdefault (ffebld_conter (next->upper))
+ == 1)
+ && (ffebld_conter_orig (next->upper) == NULL))
+ ugly_assumed = TRUE;
+
+ if (next->lower != NULL)
+ {
+ if (ffebld_op (next->lower) != FFEBLD_opCONTER)
+ {
+ if (type == FFESTP_dimtypeASSUMED)
+ type = FFESTP_dimtypeADJUSTABLEASSUMED;
+ else
+ type = FFESTP_dimtypeADJUSTABLE;
+ }
+ }
+ if (next->upper != NULL)
+ {
+ if (ugly_assumed
+ || (ffebld_op (next->upper) == FFEBLD_opSTAR))
+ {
+ if (type == FFESTP_dimtypeADJUSTABLE)
+ type = FFESTP_dimtypeADJUSTABLEASSUMED;
+ else
+ type = FFESTP_dimtypeASSUMED;
+ }
+ else if (ffebld_op (next->upper) != FFEBLD_opCONTER)
+ type = FFESTP_dimtypeADJUSTABLE;
+ }
+ }
+
+ return type;
+}
+
+/* ffestt_exprlist_append -- Append expr to list of exprs
+
+ ffesttExprList list;
+ ffelexToken t;
+ ffestt_exprlist_append(list,expr,t);
+
+ list must have already been created by ffestt_exprlist_create. The
+ list is allocated out of the scratch pool. The token is consumed. */
+
+void
+ffestt_exprlist_append (ffesttExprList list, ffebld expr, ffelexToken t)
+{
+ ffesttExprList new;
+
+ new = (ffesttExprList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST expr list", sizeof (*new));
+ new->next = list->previous->next;
+ new->previous = list->previous;
+ new->next->previous = new;
+ new->previous->next = new;
+ new->expr = expr;
+ new->t = t;
+}
+
+/* ffestt_exprlist_create -- Create new list of exprs
+
+ ffesttExprList list;
+ list = ffestt_exprlist_create();
+
+ The list is allocated out of the scratch pool. */
+
+ffesttExprList
+ffestt_exprlist_create ()
+{
+ ffesttExprList new;
+
+ new = (ffesttExprList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST expr list root", sizeof (*new));
+ new->next = new->previous = new;
+ new->expr = NULL;
+ new->t = NULL;
+ return new;
+}
+
+/* ffestt_exprlist_drive -- Drive list of token pairs into function
+
+ ffesttExprList list;
+ void fn(ffebld expr,ffelexToken t);
+ ffestt_exprlist_drive(list,fn);
+
+ The expr/token pairs in the list are passed to the function one pair
+ at a time. */
+
+void
+ffestt_exprlist_drive (ffesttExprList list, void (*fn) ())
+{
+ ffesttExprList next;
+
+ if (list == NULL)
+ return;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ (*fn) (next->expr, next->t);
+ }
+}
+
+/* ffestt_exprlist_dump -- Dump list of exprs
+
+ ffesttExprList list;
+ ffestt_exprlist_dump(list);
+
+ The exprs in the list are dumped with commas separating them. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffestt_exprlist_dump (ffesttExprList list)
+{
+ ffesttExprList next;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ if (next != list->next)
+ fputc (',', dmpout);
+ ffebld_dump (next->expr);
+ }
+}
+#endif
+
+/* ffestt_exprlist_kill -- Kill list of exprs
+
+ ffesttExprList list;
+ ffestt_exprlist_kill(list);
+
+ The tokens on the list are killed.
+
+ 02-Mar-90 JCB 1.1
+ Don't kill the list itself or change it, since it will be trashed when
+ ffesta_scratch_pool is killed anyway, so kill only the lex tokens. */
+
+void
+ffestt_exprlist_kill (ffesttExprList list)
+{
+ ffesttExprList next;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ ffelex_token_kill (next->t);
+ }
+}
+
+/* ffestt_formatlist_append -- Append null format to list of formats
+
+ ffesttFormatList list, new;
+ new = ffestt_formatlist_append(list);
+
+ list must have already been created by ffestt_formatlist_create. The
+ new item is allocated out of the scratch pool. The caller must initialize
+ it appropriately. */
+
+ffesttFormatList
+ffestt_formatlist_append (ffesttFormatList list)
+{
+ ffesttFormatList new;
+
+ new = (ffesttFormatList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST format list", sizeof (*new));
+ new->next = list->previous->next;
+ new->previous = list->previous;
+ new->next->previous = new;
+ new->previous->next = new;
+ return new;
+}
+
+/* ffestt_formatlist_create -- Create new list of formats
+
+ ffesttFormatList list;
+ list = ffestt_formatlist_create(NULL);
+
+ The list is allocated out of the scratch pool. */
+
+ffesttFormatList
+ffestt_formatlist_create (ffesttFormatList parent, ffelexToken t)
+{
+ ffesttFormatList new;
+
+ new = (ffesttFormatList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST format list root", sizeof (*new));
+ new->next = new->previous = new;
+ new->type = FFESTP_formattypeNone;
+ new->t = t;
+ new->u.root.parent = parent;
+ return new;
+}
+
+/* ffestt_formatlist_kill -- Kill tokens on list of formats
+
+ ffesttFormatList list;
+ ffestt_formatlist_kill(list);
+
+ The tokens on the list are killed. */
+
+void
+ffestt_formatlist_kill (ffesttFormatList list)
+{
+ ffesttFormatList next;
+
+ /* Always kill from the very top on down. */
+
+ while (list->u.root.parent != NULL)
+ list = list->u.root.parent->next;
+
+ /* Kill first token for this list. */
+
+ if (list->t != NULL)
+ ffelex_token_kill (list->t);
+
+ /* Kill each item in this list. */
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ ffelex_token_kill (next->t);
+ switch (next->type)
+ {
+ case FFESTP_formattypeI:
+ case FFESTP_formattypeB:
+ case FFESTP_formattypeO:
+ case FFESTP_formattypeZ:
+ case FFESTP_formattypeF:
+ case FFESTP_formattypeE:
+ case FFESTP_formattypeEN:
+ case FFESTP_formattypeG:
+ case FFESTP_formattypeL:
+ case FFESTP_formattypeA:
+ case FFESTP_formattypeD:
+ if (next->u.R1005.R1004.t != NULL)
+ ffelex_token_kill (next->u.R1005.R1004.t);
+ if (next->u.R1005.R1006.t != NULL)
+ ffelex_token_kill (next->u.R1005.R1006.t);
+ if (next->u.R1005.R1007_or_R1008.t != NULL)
+ ffelex_token_kill (next->u.R1005.R1007_or_R1008.t);
+ if (next->u.R1005.R1009.t != NULL)
+ ffelex_token_kill (next->u.R1005.R1009.t);
+ break;
+
+ case FFESTP_formattypeQ:
+ case FFESTP_formattypeDOLLAR:
+ case FFESTP_formattypeP:
+ case FFESTP_formattypeT:
+ case FFESTP_formattypeTL:
+ case FFESTP_formattypeTR:
+ case FFESTP_formattypeX:
+ case FFESTP_formattypeS:
+ case FFESTP_formattypeSP:
+ case FFESTP_formattypeSS:
+ case FFESTP_formattypeBN:
+ case FFESTP_formattypeBZ:
+ case FFESTP_formattypeSLASH:
+ case FFESTP_formattypeCOLON:
+ if (next->u.R1010.val.t != NULL)
+ ffelex_token_kill (next->u.R1010.val.t);
+ break;
+
+ case FFESTP_formattypeR1016:
+ break; /* Nothing more to do. */
+
+ case FFESTP_formattypeFORMAT:
+ if (next->u.R1003D.R1004.t != NULL)
+ ffelex_token_kill (next->u.R1003D.R1004.t);
+ next->u.R1003D.format->u.root.parent = NULL; /* Parent already dying. */
+ ffestt_formatlist_kill (next->u.R1003D.format);
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+}
+
+/* ffestt_implist_append -- Append token pair to list of token pairs
+
+ ffesttImpList list;
+ ffelexToken t;
+ ffestt_implist_append(list,start_token,end_token);
+
+ list must have already been created by ffestt_implist_create. The
+ list is allocated out of the scratch pool. The tokens are consumed. */
+
+void
+ffestt_implist_append (ffesttImpList list, ffelexToken first, ffelexToken last)
+{
+ ffesttImpList new;
+
+ new = (ffesttImpList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST token list", sizeof (*new));
+ new->next = list->previous->next;
+ new->previous = list->previous;
+ new->next->previous = new;
+ new->previous->next = new;
+ new->first = first;
+ new->last = last;
+}
+
+/* ffestt_implist_create -- Create new list of token pairs
+
+ ffesttImpList list;
+ list = ffestt_implist_create();
+
+ The list is allocated out of the scratch pool. */
+
+ffesttImpList
+ffestt_implist_create ()
+{
+ ffesttImpList new;
+
+ new = (ffesttImpList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST token list root",
+ sizeof (*new));
+ new->next = new->previous = new;
+ new->first = NULL;
+ new->last = NULL;
+ return new;
+}
+
+/* ffestt_implist_drive -- Drive list of token pairs into function
+
+ ffesttImpList list;
+ void fn(ffelexToken first,ffelexToken last);
+ ffestt_implist_drive(list,fn);
+
+ The token pairs in the list are passed to the function one pair at a time. */
+
+void
+ffestt_implist_drive (ffesttImpList list, void (*fn) ())
+{
+ ffesttImpList next;
+
+ if (list == NULL)
+ return;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ (*fn) (next->first, next->last);
+ }
+}
+
+/* ffestt_implist_dump -- Dump list of token pairs
+
+ ffesttImpList list;
+ ffestt_implist_dump(list);
+
+ The token pairs in the list are dumped with commas separating them. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffestt_implist_dump (ffesttImpList list)
+{
+ ffesttImpList next;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ if (next != list->next)
+ fputc (',', dmpout);
+ assert (ffelex_token_type (next->first) == FFELEX_typeNAME);
+ fputs (ffelex_token_text (next->first), dmpout);
+ if (next->last != NULL)
+ {
+ fputc ('-', dmpout);
+ assert (ffelex_token_type (next->last) == FFELEX_typeNAME);
+ fputs (ffelex_token_text (next->last), dmpout);
+ }
+ }
+}
+#endif
+
+/* ffestt_implist_kill -- Kill list of token pairs
+
+ ffesttImpList list;
+ ffestt_implist_kill(list);
+
+ The tokens on the list are killed. */
+
+void
+ffestt_implist_kill (ffesttImpList list)
+{
+ ffesttImpList next;
+
+ for (next = list->next; next != list; next = next->next)
+ {
+ ffelex_token_kill (next->first);
+ if (next->last != NULL)
+ ffelex_token_kill (next->last);
+ }
+}
+
+/* ffestt_tokenlist_append -- Append token to list of tokens
+
+ ffesttTokenList tl;
+ ffelexToken t;
+ ffestt_tokenlist_append(tl,t);
+
+ tl must have already been created by ffestt_tokenlist_create. The
+ list is allocated out of the scratch pool. The token is consumed. */
+
+void
+ffestt_tokenlist_append (ffesttTokenList tl, ffelexToken t)
+{
+ ffesttTokenItem ti;
+
+ ti = (ffesttTokenItem) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST token item", sizeof (*ti));
+ ti->next = (ffesttTokenItem) &tl->first;
+ ti->previous = tl->last;
+ ti->next->previous = ti;
+ ti->previous->next = ti;
+ ti->t = t;
+ ++tl->count;
+}
+
+/* ffestt_tokenlist_create -- Create new list of tokens
+
+ ffesttTokenList tl;
+ tl = ffestt_tokenlist_create();
+
+ The list is allocated out of the scratch pool. */
+
+ffesttTokenList
+ffestt_tokenlist_create ()
+{
+ ffesttTokenList tl;
+
+ tl = (ffesttTokenList) malloc_new_kp (ffesta_scratch_pool,
+ "FFEST token list", sizeof (*tl));
+ tl->first = tl->last = (ffesttTokenItem) &tl->first;
+ tl->count = 0;
+ return tl;
+}
+
+/* ffestt_tokenlist_drive -- Drive list of tokens
+
+ ffesttTokenList tl;
+ void fn(ffelexToken t);
+ ffestt_tokenlist_drive(tl,fn);
+
+ The tokens in the list are passed to the given function. */
+
+void
+ffestt_tokenlist_drive (ffesttTokenList tl, void (*fn) ())
+{
+ ffesttTokenItem ti;
+
+ if (tl == NULL)
+ return;
+
+ for (ti = tl->first; ti != (ffesttTokenItem) &tl->first; ti = ti->next)
+ {
+ (*fn) (ti->t);
+ }
+}
+
+/* ffestt_tokenlist_dump -- Dump list of tokens
+
+ ffesttTokenList tl;
+ ffestt_tokenlist_dump(tl);
+
+ The tokens in the list are dumped with commas separating them. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffestt_tokenlist_dump (ffesttTokenList tl)
+{
+ ffesttTokenItem ti;
+
+ for (ti = tl->first; ti != (ffesttTokenItem) &tl->first; ti = ti->next)
+ {
+ if (ti != tl->first)
+ fputc (',', dmpout);
+ switch (ffelex_token_type (ti->t))
+ {
+ case FFELEX_typeNUMBER:
+ case FFELEX_typeNAME:
+ case FFELEX_typeNAMES:
+ fputs (ffelex_token_text (ti->t), dmpout);
+ break;
+
+ case FFELEX_typeASTERISK:
+ fputc ('*', dmpout);
+ break;
+
+ default:
+ assert (FALSE);
+ fputc ('?', dmpout);
+ break;
+ }
+ }
+}
+#endif
+
+/* ffestt_tokenlist_handle -- Handle list of tokens
+
+ ffesttTokenList tl;
+ ffelexHandler handler;
+ handler = ffestt_tokenlist_handle(tl,handler);
+
+ The tokens in the list are passed to the handler(s). */
+
+ffelexHandler
+ffestt_tokenlist_handle (ffesttTokenList tl, ffelexHandler handler)
+{
+ ffesttTokenItem ti;
+
+ for (ti = tl->first; ti != (ffesttTokenItem) &tl->first; ti = ti->next)
+ handler = (ffelexHandler) (*handler) (ti->t);
+
+ return (ffelexHandler) handler;
+}
+
+/* ffestt_tokenlist_kill -- Kill list of tokens
+
+ ffesttTokenList tl;
+ ffestt_tokenlist_kill(tl);
+
+ The tokens on the list are killed.
+
+ 02-Mar-90 JCB 1.1
+ Don't kill the list itself or change it, since it will be trashed when
+ ffesta_scratch_pool is killed anyway, so kill only the lex tokens. */
+
+void
+ffestt_tokenlist_kill (ffesttTokenList tl)
+{
+ ffesttTokenItem ti;
+
+ for (ti = tl->first; ti != (ffesttTokenItem) &tl->first; ti = ti->next)
+ {
+ ffelex_token_kill (ti->t);
+ }
+}
diff --git a/contrib/gcc/f/stt.h b/contrib/gcc/f/stt.h
new file mode 100644
index 0000000..38ffa41
--- /dev/null
+++ b/contrib/gcc/f/stt.h
@@ -0,0 +1,230 @@
+/* stt.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ stt.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_stt
+#define _H_f_stt
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+typedef struct _ffest_case_list_ *ffesttCaseList;
+typedef struct _ffest_dim_list_ *ffesttDimList;
+typedef struct _ffest_expr_list_ *ffesttExprList;
+typedef struct _ffest_format_value_ ffesttFormatValue;
+typedef struct _ffest_format_list_ *ffesttFormatList;
+typedef struct _ffest_imp_list_ *ffesttImpList;
+typedef struct _ffest_token_item_ *ffesttTokenItem;
+typedef struct _ffest_token_list_ *ffesttTokenList;
+
+/* Include files needed by this one. */
+
+#include "top.h"
+#include "bld.h"
+#include "info.h"
+#include "lex.h"
+#include "stp.h"
+
+/* Structure definitions. */
+
+struct _ffest_case_list_
+ {
+ ffesttCaseList next;
+ ffesttCaseList previous;
+ ffelexToken t;
+ ffebld expr1;
+ ffebld expr2;
+ bool range; /* TRUE if "[expr1]:[expr2]", FALSE if
+ "expr1". */
+ };
+
+struct _ffest_dim_list_
+ {
+ ffesttDimList next;
+ ffesttDimList previous;
+ ffelexToken t;
+ ffebld lower;
+ ffebld upper;
+ };
+
+struct _ffest_expr_list_
+ {
+ ffesttExprList next;
+ ffesttExprList previous;
+ ffelexToken t;
+ ffebld expr;
+ };
+
+struct _ffest_token_item_
+ {
+ ffesttTokenItem next;
+ ffesttTokenItem previous;
+ ffelexToken t;
+ };
+
+struct _ffest_token_list_
+ {
+ ffesttTokenItem first;
+ ffesttTokenItem last;
+ int count; /* Number of tokens in list. */
+ };
+
+struct _ffest_format_value_
+ {
+ bool present; /* TRUE if value supplied (needed for
+ optional values only). */
+ bool rtexpr; /* FALSE if constant value here, TRUE if
+ run-time expr (VXT). */
+ ffelexToken t; /* The first token, or perhaps just prior if
+ can't get it. */
+ union
+ {
+ ffeUnionLongPtr unused; /* Make sure all the info gets copied. */
+ long signed_val; /* for R1011. */
+ unsigned long unsigned_val; /* For other constant values. */
+ ffebld expr; /* For run-time expression (VXT). */
+ }
+ u;
+ };
+
+struct _ffest_format_list_
+ {
+ ffesttFormatList next;
+ ffesttFormatList previous;
+ ffelexToken t; /* The NAME, CHARACTER, or HOLLERITH token. */
+ ffestpFormatType type;
+ union ffest_format_
+ {
+ struct
+ {
+ ffesttFormatValue R1004; /* r, the repeat count. */
+ ffesttFormatValue R1006; /* w, the field width. */
+ ffesttFormatValue R1007_or_R1008; /* m, the minimum number of
+ digits; d, the number of
+ decimal digits. */
+ ffesttFormatValue R1009; /* e, the number of exponent digits. */
+ }
+ R1005; /* data-edit-desc. */
+ struct
+ {
+ ffesttFormatValue val; /* r, the repeat count; k, the
+ precision magnitude adjustment; n,
+ the column number (abs or rel). */
+ }
+ R1010; /* control-edit-desc. */
+ struct
+ {
+ ffesttFormatValue R1004; /* r, the repeat count. */
+ ffesttFormatList format; /* the parenthesized
+ format-item-list. */
+ }
+ R1003D; /* format-item of for [r](format-item-list). */
+ struct
+ {
+ ffesttFormatList parent; /* NULL if outer list, else parent
+ item. */
+ }
+ root; /* FFESTP_formattypeNone case. */
+ }
+ u;
+ };
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+void ffestt_caselist_append (ffesttCaseList list, bool range, ffebld case1,
+ ffebld case2, ffelexToken t);
+ffesttCaseList ffestt_caselist_create (void);
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffestt_caselist_dump (ffesttCaseList list);
+#endif
+void ffestt_caselist_kill (ffesttCaseList list);
+void ffestt_dimlist_append (ffesttDimList list, ffebld lower, ffebld upper,
+ ffelexToken t);
+ffebld ffestt_dimlist_as_expr (ffesttDimList list, ffeinfoRank *rank,
+ ffebld *array_size, ffebld *extents,
+ bool is_ugly_assumed);
+ffesttDimList ffestt_dimlist_create (void);
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffestt_dimlist_dump (ffesttDimList list);
+#endif
+void ffestt_dimlist_kill (ffesttDimList list);
+ffestpDimtype ffestt_dimlist_type (ffesttDimList dims, bool is_ugly_assumed);
+void ffestt_exprlist_append (ffesttExprList list, ffebld expr, ffelexToken t);
+ffesttExprList ffestt_exprlist_create (void);
+void ffestt_exprlist_drive (ffesttExprList list, void (*fn) ());
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffestt_exprlist_dump (ffesttExprList list);
+#endif
+void ffestt_exprlist_kill (ffesttExprList list);
+ffesttFormatList ffestt_formatlist_append (ffesttFormatList list);
+ffesttFormatList ffestt_formatlist_create (ffesttFormatList parent,
+ ffelexToken t);
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffestt_formatlist_dump (ffesttFormatList list);
+#endif
+void ffestt_formatlist_kill (ffesttFormatList list);
+void ffestt_implist_append (ffesttImpList list, ffelexToken first,
+ ffelexToken last);
+ffesttImpList ffestt_implist_create (void);
+void ffestt_implist_drive (ffesttImpList list, void (*fn) ());
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffestt_implist_dump (ffesttImpList list);
+#endif
+void ffestt_implist_kill (ffesttImpList list);
+void ffestt_tokenlist_append (ffesttTokenList list, ffelexToken t);
+ffesttTokenList ffestt_tokenlist_create (void);
+void ffestt_tokenlist_drive (ffesttTokenList list, void (*fn) ());
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffestt_tokenlist_dump (ffesttTokenList list);
+#endif
+ffelexHandler ffestt_tokenlist_handle (ffesttTokenList list,
+ ffelexHandler handler);
+void ffestt_tokenlist_kill (ffesttTokenList list);
+
+/* Define macros. */
+
+#define ffestt_init_0()
+#define ffestt_init_1()
+#define ffestt_init_2()
+#define ffestt_init_3()
+#define ffestt_init_4()
+#define ffestt_terminate_0()
+#define ffestt_terminate_1()
+#define ffestt_terminate_2()
+#define ffestt_terminate_3()
+#define ffestt_terminate_4()
+#define ffestt_tokenlist_count(tl) ((tl)->count)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/stu.c b/contrib/gcc/f/stu.c
new file mode 100644
index 0000000..7dcbdcb
--- /dev/null
+++ b/contrib/gcc/f/stu.c
@@ -0,0 +1,1161 @@
+/* stu.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "bld.h"
+#include "com.h"
+#include "equiv.h"
+#include "global.h"
+#include "info.h"
+#include "implic.h"
+#include "intrin.h"
+#include "stu.h"
+#include "storag.h"
+#include "sta.h"
+#include "symbol.h"
+#include "target.h"
+
+/* Externals defined here. */
+
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+static void ffestu_list_exec_transition_ (ffebld list);
+static bool ffestu_symter_end_transition_ (ffebld expr);
+static bool ffestu_symter_exec_transition_ (ffebld expr);
+static bool ffestu_dummies_transition_ (ffesymbol (*symfunc) (),
+ ffebld list);
+
+/* Internal macros. */
+
+#define ffestu_equiv_(s) (((ffesymbol_equiv (s) == NULL) \
+ || (ffeequiv_common (ffesymbol_equiv (s)) == NULL)) ? FFEINFO_whereLOCAL \
+ : FFEINFO_whereCOMMON)
+
+/* Update symbol info just before end of unit. */
+
+ffesymbol
+ffestu_sym_end_transition (ffesymbol s)
+{
+ ffeinfoKind skd;
+ ffeinfoWhere swh;
+ ffeinfoKind nkd;
+ ffeinfoWhere nwh;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffesymbolState ss;
+ ffesymbolState ns;
+ bool needs_type = TRUE; /* Implicit type assignment might be
+ necessary. */
+
+ assert (s != NULL);
+ ss = ffesymbol_state (s);
+ sa = ffesymbol_attrs (s);
+ skd = ffesymbol_kind (s);
+ swh = ffesymbol_where (s);
+
+ switch (ss)
+ {
+ case FFESYMBOL_stateUNCERTAIN:
+ if ((swh == FFEINFO_whereDUMMY)
+ && (ffesymbol_numentries (s) == 0))
+ { /* Not actually in any dummy list! */
+ ffesymbol_error (s, ffesta_tokens[0]);
+ return s;
+ }
+ else if (((swh == FFEINFO_whereLOCAL)
+ || (swh == FFEINFO_whereNONE))
+ && (skd == FFEINFO_kindENTITY)
+ && ffestu_symter_end_transition_ (ffesymbol_dims (s)))
+ { /* Bad dimension expressions. */
+ ffesymbol_error (s, NULL);
+ return s;
+ }
+ break;
+
+ case FFESYMBOL_stateUNDERSTOOD:
+ if ((swh == FFEINFO_whereLOCAL)
+ && ((skd == FFEINFO_kindFUNCTION)
+ || (skd == FFEINFO_kindSUBROUTINE)))
+ {
+ int n_args;
+ ffebld list;
+ ffebld item;
+ ffeglobalArgSummary as;
+ ffeinfoBasictype bt;
+ ffeinfoKindtype kt;
+ bool array;
+ char *name = NULL;
+
+ ffestu_dummies_transition_ (ffecom_sym_end_transition,
+ ffesymbol_dummyargs (s));
+
+ n_args = ffebld_list_length (ffesymbol_dummyargs (s));
+ ffeglobal_proc_def_nargs (s, n_args);
+ for (list = ffesymbol_dummyargs (s), n_args = 0;
+ list != NULL;
+ list = ffebld_trail (list), ++n_args)
+ {
+ item = ffebld_head (list);
+ array = FALSE;
+ if (item != NULL)
+ {
+ bt = ffeinfo_basictype (ffebld_info (item));
+ kt = ffeinfo_kindtype (ffebld_info (item));
+ array = (ffeinfo_rank (ffebld_info (item)) > 0);
+ switch (ffebld_op (item))
+ {
+ case FFEBLD_opSTAR:
+ as = FFEGLOBAL_argsummaryALTRTN;
+ break;
+
+ case FFEBLD_opSYMTER:
+ name = ffesymbol_text (ffebld_symter (item));
+ as = FFEGLOBAL_argsummaryNONE;
+
+ switch (ffeinfo_kind (ffebld_info (item)))
+ {
+ case FFEINFO_kindFUNCTION:
+ as = FFEGLOBAL_argsummaryFUNC;
+ break;
+
+ case FFEINFO_kindSUBROUTINE:
+ as = FFEGLOBAL_argsummarySUBR;
+ break;
+
+ case FFEINFO_kindNONE:
+ as = FFEGLOBAL_argsummaryPROC;
+ break;
+
+ default:
+ break;
+ }
+
+ if (as != FFEGLOBAL_argsummaryNONE)
+ break;
+
+ /* Fall through. */
+ default:
+ if (bt == FFEINFO_basictypeCHARACTER)
+ as = FFEGLOBAL_argsummaryDESCR;
+ else
+ as = FFEGLOBAL_argsummaryREF;
+ break;
+ }
+ }
+ else
+ {
+ as = FFEGLOBAL_argsummaryNONE;
+ bt = FFEINFO_basictypeNONE;
+ kt = FFEINFO_kindtypeNONE;
+ }
+ ffeglobal_proc_def_arg (s, n_args, name, as, bt, kt, array);
+ }
+ }
+ else if (swh == FFEINFO_whereDUMMY)
+ {
+ if (ffesymbol_numentries (s) == 0)
+ { /* Not actually in any dummy list! */
+ ffesymbol_error (s, ffesta_tokens[0]);
+ return s;
+ }
+ if (ffestu_symter_end_transition_ (ffesymbol_dims (s)))
+ { /* Bad dimension expressions. */
+ ffesymbol_error (s, NULL);
+ return s;
+ }
+ }
+ else if ((swh == FFEINFO_whereLOCAL)
+ && ffestu_symter_end_transition_ (ffesymbol_dims (s)))
+ { /* Bad dimension expressions. */
+ ffesymbol_error (s, NULL);
+ return s;
+ }
+
+ ffestorag_end_layout (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ return s;
+
+ default:
+ assert ("bad status" == NULL);
+ return s;
+ }
+
+ ns = FFESYMBOL_stateUNDERSTOOD;
+ na = sa = ffesymbol_attrs (s);
+
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ nkd = skd;
+ nwh = swh;
+
+ /* Figure out what kind of object we've got based on previous declarations
+ of or references to the object. */
+
+ if (sa & FFESYMBOL_attrsEXTERNAL)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsACTUALARG
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ if (sa & FFESYMBOL_attrsTYPE)
+ nwh = FFEINFO_whereGLOBAL;
+ else
+ /* Not TYPE. */
+ {
+ if (sa & FFESYMBOL_attrsDUMMY)
+ { /* Not TYPE. */
+ ns = FFESYMBOL_stateUNCERTAIN; /* FUNCTION/SUBROUTINE. */
+ needs_type = FALSE; /* Don't assign type to SUBROUTINE! */
+ }
+ else if (sa & FFESYMBOL_attrsACTUALARG)
+ { /* Not DUMMY or TYPE. */
+ ns = FFESYMBOL_stateUNCERTAIN; /* FUNCTION/SUBROUTINE. */
+ needs_type = FALSE; /* Don't assign type to SUBROUTINE! */
+ }
+ else
+ /* Not ACTUALARG, DUMMY, or TYPE. */
+ { /* This is an assumption, essentially. */
+ nkd = FFEINFO_kindBLOCKDATA;
+ nwh = FFEINFO_whereGLOBAL;
+ needs_type = FALSE;
+ }
+ }
+ }
+ else if (sa & FFESYMBOL_attrsDUMMY)
+ {
+ assert (!(sa & FFESYMBOL_attrsEXTERNAL)); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ /* Honestly, this appears to be a guess. I can't find anyplace in the
+ standard that makes clear whether this unreferenced dummy argument
+ is an ENTITY or a FUNCTION. And yet, for the f2c interface, picking
+ one is critical for CHARACTER entities because it determines whether
+ to expect an additional argument specifying the length of an ENTITY
+ that is not expected (or needed) for a FUNCTION. HOWEVER, F90 makes
+ this guess a correct one, and it does seem that the Section 18 Notes
+ in Appendix B of F77 make it clear the F77 standard at least
+ intended to make this guess correct as well, so this seems ok. */
+
+ nkd = FFEINFO_kindENTITY;
+ }
+ else if (sa & FFESYMBOL_attrsARRAY)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsTYPE)));
+
+ if (ffestu_symter_end_transition_ (ffesymbol_dims (s)))
+ {
+ ffesymbol_error (s, NULL);
+ return s;
+ }
+
+ if (sa & FFESYMBOL_attrsADJUSTABLE)
+ { /* Not actually in any dummy list! */
+ if (ffe_is_pedantic ()
+ && ffebad_start_msg ("Local adjustable symbol `%A' at %0",
+ FFEBAD_severityPEDANTIC))
+ {
+ ffebad_string (ffesymbol_text (s));
+ ffebad_here (0, ffesymbol_where_line (s),
+ ffesymbol_where_column (s));
+ ffebad_finish ();
+ }
+ }
+ nwh = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsSFARG)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ nwh = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsTYPE)
+ {
+ assert (!(sa & (FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsTYPE
+ | FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG)));
+
+ if (sa & FFESYMBOL_attrsANYLEN)
+ { /* Can't touch this. */
+ ffesymbol_signal_change (s);
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ s = ffecom_sym_learned (s);
+ ffesymbol_reference (s, NULL, FALSE);
+ ffestorag_end_layout (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ return s;
+ }
+
+ nkd = FFEINFO_kindENTITY;
+ nwh = FFEINFO_whereLOCAL;
+ }
+ else
+ assert ("unexpected attribute set" == NULL);
+
+ /* Now see what we've got for a new object: NONE means a new error cropped
+ up; ANY means an old error to be ignored; otherwise, everything's ok,
+ update the object (symbol) and continue on. */
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, ffesta_tokens[0]);
+ else if (!(na & FFESYMBOL_attrsANY))
+ {
+ ffesymbol_signal_change (s);
+ ffesymbol_set_attrs (s, na); /* Establish new info. */
+ ffesymbol_set_state (s, ns);
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ nkd,
+ nwh,
+ ffesymbol_size (s)));
+ if (needs_type && !ffeimplic_establish_symbol (s))
+ ffesymbol_error (s, ffesta_tokens[0]);
+ else
+ ffesymbol_resolve_intrin (s);
+ s = ffecom_sym_learned (s);
+ ffesymbol_reference (s, NULL, FALSE);
+ ffestorag_end_layout (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* ffestu_sym_exec_transition -- Update symbol just before first exec stmt
+
+ ffesymbol s;
+ ffestu_sym_exec_transition(s); */
+
+ffesymbol
+ffestu_sym_exec_transition (ffesymbol s)
+{
+ ffeinfoKind skd;
+ ffeinfoWhere swh;
+ ffeinfoKind nkd;
+ ffeinfoWhere nwh;
+ ffesymbolAttrs sa;
+ ffesymbolAttrs na;
+ ffesymbolState ss;
+ ffesymbolState ns;
+ ffeintrinGen gen;
+ ffeintrinSpec spec;
+ ffeintrinImp imp;
+ bool needs_type = TRUE; /* Implicit type assignment might be
+ necessary. */
+ bool resolve_intrin = TRUE; /* Might need to resolve intrinsic. */
+
+ assert (s != NULL);
+
+ sa = ffesymbol_attrs (s);
+ skd = ffesymbol_kind (s);
+ swh = ffesymbol_where (s);
+ ss = ffesymbol_state (s);
+
+ switch (ss)
+ {
+ case FFESYMBOL_stateNONE:
+ return s; /* Assume caller will handle it. */
+
+ case FFESYMBOL_stateSEEN:
+ break;
+
+ case FFESYMBOL_stateUNCERTAIN:
+ ffestorag_exec_layout (s);
+ return s; /* Already processed this one, or not
+ necessary. */
+
+ case FFESYMBOL_stateUNDERSTOOD:
+ if (skd == FFEINFO_kindNAMELIST)
+ {
+ ffebld_end_list (ffesymbol_ptr_to_listbottom (s));
+ ffestu_list_exec_transition_ (ffesymbol_namelist (s));
+ }
+ else if ((swh == FFEINFO_whereLOCAL)
+ && ((skd == FFEINFO_kindFUNCTION)
+ || (skd == FFEINFO_kindSUBROUTINE)))
+ {
+ ffestu_dummies_transition_ (ffecom_sym_exec_transition,
+ ffesymbol_dummyargs (s));
+ if ((skd == FFEINFO_kindFUNCTION)
+ && !ffeimplic_establish_symbol (s))
+ ffesymbol_error (s, ffesta_tokens[0]);
+ }
+
+ ffesymbol_reference (s, NULL, FALSE);
+ ffestorag_exec_layout (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ return s;
+
+ default:
+ assert ("bad status" == NULL);
+ return s;
+ }
+
+ ns = FFESYMBOL_stateUNDERSTOOD; /* Only a few UNCERTAIN exceptions. */
+
+ na = sa;
+ nkd = skd;
+ nwh = swh;
+
+ assert (!(sa & FFESYMBOL_attrsANY));
+
+ if (sa & FFESYMBOL_attrsCOMMON)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ nkd = FFEINFO_kindENTITY;
+ nwh = FFEINFO_whereCOMMON;
+ }
+ else if (sa & FFESYMBOL_attrsRESULT)
+ { /* Result variable for function. */
+ assert (!(sa & ~(FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsRESULT
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ nkd = FFEINFO_kindENTITY;
+ nwh = FFEINFO_whereRESULT;
+ }
+ else if (sa & FFESYMBOL_attrsSFUNC)
+ { /* Statement function. */
+ assert (!(sa & ~(FFESYMBOL_attrsSFUNC
+ | FFESYMBOL_attrsTYPE)));
+
+ nkd = FFEINFO_kindFUNCTION;
+ nwh = FFEINFO_whereCONSTANT;
+ }
+ else if (sa & FFESYMBOL_attrsEXTERNAL)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsTYPE)));
+
+ if (sa & FFESYMBOL_attrsTYPE)
+ {
+ nkd = FFEINFO_kindFUNCTION;
+
+ if (sa & FFESYMBOL_attrsDUMMY)
+ nwh = FFEINFO_whereDUMMY;
+ else
+ {
+ if (ffesta_is_entry_valid)
+ {
+ nwh = FFEINFO_whereNONE; /* DUMMY, GLOBAL. */
+ ns = FFESYMBOL_stateUNCERTAIN;
+ }
+ else
+ nwh = FFEINFO_whereGLOBAL;
+ }
+ }
+ else
+ /* No TYPE. */
+ {
+ nkd = FFEINFO_kindNONE; /* FUNCTION, SUBROUTINE, BLOCKDATA. */
+ needs_type = FALSE; /* Only gets type if FUNCTION. */
+ ns = FFESYMBOL_stateUNCERTAIN;
+
+ if (sa & FFESYMBOL_attrsDUMMY)
+ nwh = FFEINFO_whereDUMMY; /* Not BLOCKDATA. */
+ else
+ {
+ if (ffesta_is_entry_valid)
+ nwh = FFEINFO_whereNONE; /* DUMMY, GLOBAL. */
+ else
+ nwh = FFEINFO_whereGLOBAL;
+ }
+ }
+ }
+ else if (sa & FFESYMBOL_attrsDUMMY)
+ {
+ assert (!(sa & FFESYMBOL_attrsEXTERNAL)); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTABLE /* Possible. */
+ | FFESYMBOL_attrsADJUSTS /* Possible. */
+ | FFESYMBOL_attrsANYLEN /* Possible. */
+ | FFESYMBOL_attrsANYSIZE /* Possible. */
+ | FFESYMBOL_attrsARRAY /* Possible. */
+ | FFESYMBOL_attrsDUMMY /* Have it. */
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsSFARG /* Possible. */
+ | FFESYMBOL_attrsTYPE))); /* Possible. */
+
+ nwh = FFEINFO_whereDUMMY;
+
+ if (ffestu_symter_exec_transition_ (ffesymbol_dims (s)))
+ na = FFESYMBOL_attrsetNONE;
+
+ if (sa & (FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSFARG))
+ nkd = FFEINFO_kindENTITY;
+ else if (sa & FFESYMBOL_attrsDUMMY) /* Still okay. */
+ {
+ if (!(sa & FFESYMBOL_attrsTYPE))
+ needs_type = FALSE; /* Don't assign type to SUBROUTINE! */
+ nkd = FFEINFO_kindNONE; /* ENTITY, FUNCTION, SUBROUTINE. */
+ ns = FFESYMBOL_stateUNCERTAIN;
+ }
+ }
+ else if (sa & FFESYMBOL_attrsADJUSTS)
+ { /* Must be DUMMY or COMMON at some point. */
+ assert (!(sa & (FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTS /* Have it. */
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV /* Possible. */
+ | FFESYMBOL_attrsINIT /* Possible. */
+ | FFESYMBOL_attrsNAMELIST /* Possible. */
+ | FFESYMBOL_attrsSFARG /* Possible. */
+ | FFESYMBOL_attrsTYPE))); /* Possible. */
+
+ nkd = FFEINFO_kindENTITY;
+
+ if (sa & FFESYMBOL_attrsEQUIV)
+ {
+ if ((ffesymbol_equiv (s) == NULL)
+ || (ffeequiv_common (ffesymbol_equiv (s)) == NULL))
+ na = FFESYMBOL_attrsetNONE; /* Not equiv'd into COMMON. */
+ else
+ nwh = FFEINFO_whereCOMMON;
+ }
+ else if (!ffesta_is_entry_valid
+ || (sa & (FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST)))
+ na = FFESYMBOL_attrsetNONE;
+ else
+ nwh = FFEINFO_whereDUMMY;
+ }
+ else if (sa & FFESYMBOL_attrsSAVE)
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsTYPE)));
+
+ nkd = FFEINFO_kindENTITY;
+ nwh = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsEQUIV)
+ {
+ assert (!(sa & FFESYMBOL_attrsCOMMON)); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTS /* Possible. */
+ | FFESYMBOL_attrsARRAY /* Possible. */
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV /* Have it. */
+ | FFESYMBOL_attrsINIT /* Possible. */
+ | FFESYMBOL_attrsNAMELIST /* Possible. */
+ | FFESYMBOL_attrsSAVE /* Possible. */
+ | FFESYMBOL_attrsSFARG /* Possible. */
+ | FFESYMBOL_attrsTYPE))); /* Possible. */
+
+ nkd = FFEINFO_kindENTITY;
+ nwh = ffestu_equiv_ (s);
+ }
+ else if (sa & FFESYMBOL_attrsNAMELIST)
+ {
+ assert (!(sa & (FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsSAVE))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsARRAY /* Possible. */
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT /* Possible. */
+ | FFESYMBOL_attrsNAMELIST /* Have it. */
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsSFARG /* Possible. */
+ | FFESYMBOL_attrsTYPE))); /* Possible. */
+
+ nkd = FFEINFO_kindENTITY;
+ nwh = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsINIT)
+ {
+ assert (!(sa & (FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSAVE))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsARRAY /* Possible. */
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT /* Have it. */
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsSFARG /* Possible. */
+ | FFESYMBOL_attrsTYPE))); /* Possible. */
+
+ nkd = FFEINFO_kindENTITY;
+ nwh = FFEINFO_whereLOCAL;
+ }
+ else if (sa & FFESYMBOL_attrsSFARG)
+ {
+ assert (!(sa & (FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsRESULT
+ | FFESYMBOL_attrsSAVE))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsRESULT
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsSFARG /* Have it. */
+ | FFESYMBOL_attrsTYPE))); /* Possible. */
+
+ nkd = FFEINFO_kindENTITY;
+
+ if (ffesta_is_entry_valid)
+ {
+ nwh = FFEINFO_whereNONE; /* DUMMY, LOCAL. */
+ ns = FFESYMBOL_stateUNCERTAIN;
+ }
+ else
+ nwh = FFEINFO_whereLOCAL;
+ }
+ else if (sa & (FFESYMBOL_attrsADJUSTABLE | FFESYMBOL_attrsANYSIZE))
+ {
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsANYSIZE
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsTYPE)));
+
+ nkd = FFEINFO_kindENTITY;
+
+ if (ffestu_symter_exec_transition_ (ffesymbol_dims (s)))
+ na = FFESYMBOL_attrsetNONE;
+
+ if (sa & (FFESYMBOL_attrsANYLEN | FFESYMBOL_attrsANYSIZE))
+ nwh = FFEINFO_whereDUMMY;
+ else if (sa & (FFESYMBOL_attrsADJUSTABLE | FFESYMBOL_attrsANYSIZE))
+ /* Still okay. */
+ {
+ nwh = FFEINFO_whereNONE; /* DUMMY, LOCAL. */
+ ns = FFESYMBOL_stateUNCERTAIN;
+ }
+ }
+ else if (sa & FFESYMBOL_attrsARRAY)
+ {
+ assert (!(sa & (FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYSIZE
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSAVE))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN /* Possible. */
+ | FFESYMBOL_attrsANYSIZE
+ | FFESYMBOL_attrsARRAY /* Have it. */
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsTYPE))); /* Possible. */
+
+ nkd = FFEINFO_kindENTITY;
+
+ if (sa & FFESYMBOL_attrsANYLEN)
+ {
+ assert (ffesta_is_entry_valid); /* Already diagnosed. */
+ nwh = FFEINFO_whereDUMMY;
+ }
+ else
+ {
+ if (ffesta_is_entry_valid)
+ {
+ nwh = FFEINFO_whereNONE; /* DUMMY, LOCAL. */
+ ns = FFESYMBOL_stateUNCERTAIN;
+ }
+ else
+ nwh = FFEINFO_whereLOCAL;
+ }
+ }
+ else if (sa & FFESYMBOL_attrsANYLEN)
+ {
+ assert (!(sa & (FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYSIZE
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsRESULT))); /* Handled above. */
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsANYLEN /* Have it. */
+ | FFESYMBOL_attrsANYSIZE
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsRESULT
+ | FFESYMBOL_attrsTYPE))); /* Have it too. */
+
+ if (ffesta_is_entry_valid)
+ {
+ nkd = FFEINFO_kindNONE; /* ENTITY, FUNCTION. */
+ nwh = FFEINFO_whereNONE; /* DUMMY, INTRINSIC, RESULT. */
+ ns = FFESYMBOL_stateUNCERTAIN;
+ resolve_intrin = FALSE;
+ }
+ else if (ffeintrin_is_intrinsic (ffesymbol_text (s), NULL, FALSE,
+ &gen, &spec, &imp))
+ {
+ ffesymbol_signal_change (s);
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_set_generic (s, gen);
+ ffesymbol_set_specific (s, spec);
+ ffesymbol_set_implementation (s, imp);
+ ffesymbol_set_info (s,
+ ffeinfo_new (FFEINFO_basictypeNONE,
+ FFEINFO_kindtypeNONE,
+ 0,
+ FFEINFO_kindNONE,
+ FFEINFO_whereINTRINSIC,
+ FFETARGET_charactersizeNONE));
+ ffesymbol_resolve_intrin (s);
+ ffesymbol_reference (s, NULL, FALSE);
+ ffestorag_exec_layout (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ return s;
+ }
+ else
+ { /* SPECIAL: can't have CHAR*(*) var in
+ PROGRAM/BLOCKDATA, unless it isn't
+ referenced anywhere in the code. */
+ ffesymbol_signal_change (s); /* Can't touch this. */
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ ffesymbol_resolve_intrin (s);
+ ffesymbol_reference (s, NULL, FALSE);
+ ffestorag_exec_layout (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ return s;
+ }
+ }
+ else if (sa & FFESYMBOL_attrsTYPE)
+ {
+ assert (!(sa & (FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsANYSIZE
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsRESULT
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsSFUNC)));
+ assert (!(sa & ~(FFESYMBOL_attrsADJUSTABLE
+ | FFESYMBOL_attrsADJUSTS
+ | FFESYMBOL_attrsANYLEN
+ | FFESYMBOL_attrsANYSIZE
+ | FFESYMBOL_attrsARRAY
+ | FFESYMBOL_attrsCOMMON
+ | FFESYMBOL_attrsDUMMY
+ | FFESYMBOL_attrsEQUIV
+ | FFESYMBOL_attrsEXTERNAL
+ | FFESYMBOL_attrsINIT
+ | FFESYMBOL_attrsINTRINSIC /* UNDERSTOOD. */
+ | FFESYMBOL_attrsNAMELIST
+ | FFESYMBOL_attrsRESULT
+ | FFESYMBOL_attrsSAVE
+ | FFESYMBOL_attrsSFARG
+ | FFESYMBOL_attrsSFUNC
+ | FFESYMBOL_attrsTYPE))); /* Have it. */
+
+ nkd = FFEINFO_kindNONE; /* ENTITY, FUNCTION. */
+ nwh = FFEINFO_whereNONE; /* DUMMY, GLOBAL, INTRINSIC, LOCAL, RESULT. */
+ ns = FFESYMBOL_stateUNCERTAIN;
+ resolve_intrin = FALSE;
+ }
+ else if (sa & (FFESYMBOL_attrsCBLOCK | FFESYMBOL_attrsSAVECBLOCK))
+ { /* COMMON block. */
+ assert (!(sa & ~(FFESYMBOL_attrsCBLOCK
+ | FFESYMBOL_attrsSAVECBLOCK)));
+
+ if (sa & FFESYMBOL_attrsCBLOCK)
+ ffebld_end_list (ffesymbol_ptr_to_listbottom (s));
+ else
+ ffesymbol_set_commonlist (s, NULL);
+ ffestu_list_exec_transition_ (ffesymbol_commonlist (s));
+ nkd = FFEINFO_kindCOMMON;
+ nwh = FFEINFO_whereLOCAL;
+ needs_type = FALSE;
+ }
+ else
+ { /* First seen in stmt func definition. */
+ assert (sa == FFESYMBOL_attrsetNONE);
+ assert ("Why are we here again?" == NULL); /* ~~~~~ */
+
+ nkd = FFEINFO_kindNONE; /* ENTITY, FUNCTION. */
+ nwh = FFEINFO_whereNONE; /* DUMMY, GLOBAL, LOCAL. */
+ ns = FFESYMBOL_stateUNCERTAIN; /* Will get repromoted by caller. */
+ needs_type = FALSE;
+ }
+
+ if (na == FFESYMBOL_attrsetNONE)
+ ffesymbol_error (s, ffesta_tokens[0]);
+ else if (!(na & FFESYMBOL_attrsANY)
+ && (needs_type || (nkd != skd) || (nwh != swh)
+ || (na != sa) || (ns != ss)))
+ {
+ ffesymbol_signal_change (s);
+ ffesymbol_set_attrs (s, na); /* Establish new info. */
+ ffesymbol_set_state (s, ns);
+ if ((ffesymbol_common (s) == NULL)
+ && (ffesymbol_equiv (s) != NULL))
+ ffesymbol_set_common (s, ffeequiv_common (ffesymbol_equiv (s)));
+ ffesymbol_set_info (s,
+ ffeinfo_new (ffesymbol_basictype (s),
+ ffesymbol_kindtype (s),
+ ffesymbol_rank (s),
+ nkd,
+ nwh,
+ ffesymbol_size (s)));
+ if (needs_type && !ffeimplic_establish_symbol (s))
+ ffesymbol_error (s, ffesta_tokens[0]);
+ else if (resolve_intrin)
+ ffesymbol_resolve_intrin (s);
+ ffesymbol_reference (s, NULL, FALSE);
+ ffestorag_exec_layout (s);
+ ffesymbol_signal_unreported (s); /* For debugging purposes. */
+ }
+
+ return s;
+}
+
+/* ffestu_list_exec_transition_ -- Update SYMTERs in ITEM list w/in symbol
+
+ ffebld list;
+ ffestu_list_exec_transition_(list);
+
+ list contains an FFEBLD_opITEM list of SYMTERs (possibly STARs and
+ other things, too, but we'll ignore the known ones). For each SYMTER,
+ we run sym_exec_transition_ on the corresponding ffesymbol (a recursive
+ call, since that's the function that's calling us) to update it's
+ information. Then we copy that information into the SYMTER.
+
+ Make sure we don't get called recursively ourselves! */
+
+static void
+ffestu_list_exec_transition_ (ffebld list)
+{
+ static bool in_progress = FALSE;
+ ffebld item;
+ ffesymbol symbol;
+
+ assert (!in_progress);
+ in_progress = TRUE;
+
+ for (; list != NULL; list = ffebld_trail (list))
+ {
+ if ((item = ffebld_head (list)) == NULL)
+ continue; /* Try next item. */
+
+ switch (ffebld_op (item))
+ {
+ case FFEBLD_opSTAR:
+ break;
+
+ case FFEBLD_opSYMTER:
+ symbol = ffebld_symter (item);
+ if (symbol == NULL)
+ break; /* Detached from stmt func dummy list. */
+ symbol = ffecom_sym_exec_transition (symbol);
+ assert (ffesymbol_kind (symbol) != FFEINFO_kindNONE);
+ assert (ffesymbol_where (symbol) != FFEINFO_whereNONE);
+ ffebld_set_info (item, ffesymbol_info (symbol));
+ break;
+
+ default:
+ assert ("Unexpected item on list" == NULL);
+ break;
+ }
+ }
+
+ in_progress = FALSE;
+}
+
+/* ffestu_symter_end_transition_ -- Update SYMTERs in expr w/in symbol
+
+ ffebld expr;
+ ffestu_symter_end_transition_(expr);
+
+ Any SYMTER in expr's tree with whereNONE gets updated to the
+ (recursively transitioned) sym it identifies (DUMMY or COMMON). */
+
+static bool
+ffestu_symter_end_transition_ (ffebld expr)
+{
+ ffesymbol symbol;
+ bool any = FALSE;
+
+ /* Label used for tail recursion (reset expr and go here instead of calling
+ self). */
+
+tail: /* :::::::::::::::::::: */
+
+ if (expr == NULL)
+ return any;
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opITEM:
+ while (ffebld_trail (expr) != NULL)
+ {
+ if (ffestu_symter_end_transition_ (ffebld_head (expr)))
+ any = TRUE;
+ expr = ffebld_trail (expr);
+ }
+ expr = ffebld_head (expr);
+ goto tail; /* :::::::::::::::::::: */
+
+ case FFEBLD_opSYMTER:
+ symbol = ffecom_sym_end_transition (ffebld_symter (expr));
+ if ((symbol != NULL)
+ && ffesymbol_attr (symbol, FFESYMBOL_attrANY))
+ any = TRUE;
+ ffebld_set_info (expr, ffesymbol_info (symbol));
+ break;
+
+ case FFEBLD_opANY:
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ switch (ffebld_arity (expr))
+ {
+ case 2:
+ if (ffestu_symter_end_transition_ (ffebld_left (expr)))
+ any = TRUE;
+ expr = ffebld_right (expr);
+ goto tail; /* :::::::::::::::::::: */
+
+ case 1:
+ expr = ffebld_left (expr);
+ goto tail; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+
+ return any;
+}
+
+/* ffestu_symter_exec_transition_ -- Update SYMTERs in expr w/in symbol
+
+ ffebld expr;
+ ffestu_symter_exec_transition_(expr);
+
+ Any SYMTER in expr's tree with whereNONE gets updated to the
+ (recursively transitioned) sym it identifies (DUMMY or COMMON). */
+
+static bool
+ffestu_symter_exec_transition_ (ffebld expr)
+{
+ ffesymbol symbol;
+ bool any = FALSE;
+
+ /* Label used for tail recursion (reset expr and go here instead of calling
+ self). */
+
+tail: /* :::::::::::::::::::: */
+
+ if (expr == NULL)
+ return any;
+
+ switch (ffebld_op (expr))
+ {
+ case FFEBLD_opITEM:
+ while (ffebld_trail (expr) != NULL)
+ {
+ if (ffestu_symter_exec_transition_ (ffebld_head (expr)))
+ any = TRUE;
+ expr = ffebld_trail (expr);
+ }
+ expr = ffebld_head (expr);
+ goto tail; /* :::::::::::::::::::: */
+
+ case FFEBLD_opSYMTER:
+ symbol = ffecom_sym_exec_transition (ffebld_symter (expr));
+ if ((symbol != NULL)
+ && ffesymbol_attr (symbol, FFESYMBOL_attrANY))
+ any = TRUE;
+ ffebld_set_info (expr, ffesymbol_info (symbol));
+ break;
+
+ case FFEBLD_opANY:
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ switch (ffebld_arity (expr))
+ {
+ case 2:
+ if (ffestu_symter_exec_transition_ (ffebld_left (expr)))
+ any = TRUE;
+ expr = ffebld_right (expr);
+ goto tail; /* :::::::::::::::::::: */
+
+ case 1:
+ expr = ffebld_left (expr);
+ goto tail; /* :::::::::::::::::::: */
+
+ default:
+ break;
+ }
+
+ return any;
+}
+
+/* ffestu_dummies_transition_ -- Update SYMTERs in ITEM list w/in entry
+
+ ffebld list;
+ ffesymbol symfunc(ffesymbol s);
+ if (ffestu_dummies_transition_(symfunc,list))
+ // One or more items are still UNCERTAIN.
+
+ list contains an FFEBLD_opITEM list of SYMTERs (possibly STARs and
+ other things, too, but we'll ignore the known ones). For each SYMTER,
+ we run symfunc on the corresponding ffesymbol (a recursive
+ call, since that's the function that's calling us) to update it's
+ information. Then we copy that information into the SYMTER.
+
+ Return TRUE if any of the SYMTER's has incomplete information.
+
+ Make sure we don't get called recursively ourselves! */
+
+static bool
+ffestu_dummies_transition_ (ffesymbol (*symfunc) (), ffebld list)
+{
+ static bool in_progress = FALSE;
+ ffebld item;
+ ffesymbol symbol;
+ bool uncertain = FALSE;
+
+ assert (!in_progress);
+ in_progress = TRUE;
+
+ for (; list != NULL; list = ffebld_trail (list))
+ {
+ if ((item = ffebld_head (list)) == NULL)
+ continue; /* Try next item. */
+
+ switch (ffebld_op (item))
+ {
+ case FFEBLD_opSTAR:
+ break;
+
+ case FFEBLD_opSYMTER:
+ symbol = ffebld_symter (item);
+ if (symbol == NULL)
+ break; /* Detached from stmt func dummy list. */
+ symbol = (*symfunc) (symbol);
+ if (ffesymbol_state (symbol) == FFESYMBOL_stateUNCERTAIN)
+ uncertain = TRUE;
+ else
+ {
+ assert (ffesymbol_kind (symbol) != FFEINFO_kindNONE);
+ assert (ffesymbol_where (symbol) != FFEINFO_whereNONE);
+ }
+ ffebld_set_info (item, ffesymbol_info (symbol));
+ break;
+
+ default:
+ assert ("Unexpected item on list" == NULL);
+ break;
+ }
+ }
+
+ in_progress = FALSE;
+
+ return uncertain;
+}
diff --git a/contrib/gcc/f/stu.h b/contrib/gcc/f/stu.h
new file mode 100644
index 0000000..61d7b40
--- /dev/null
+++ b/contrib/gcc/f/stu.h
@@ -0,0 +1,69 @@
+/* stu.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ stu.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_stu
+#define _H_f_stu
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "symbol.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+
+/* Declare functions with prototypes. */
+
+ffesymbol ffestu_sym_end_transition (ffesymbol s);
+ffesymbol ffestu_sym_exec_transition (ffesymbol s);
+
+/* Define macros. */
+
+#define ffestu_init_0()
+#define ffestu_init_1()
+#define ffestu_init_2()
+#define ffestu_init_3()
+#define ffestu_init_4()
+#define ffestu_terminate_0()
+#define ffestu_terminate_1()
+#define ffestu_terminate_2()
+#define ffestu_terminate_3()
+#define ffestu_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/stv.c b/contrib/gcc/f/stv.c
new file mode 100644
index 0000000..c652356
--- /dev/null
+++ b/contrib/gcc/f/stv.c
@@ -0,0 +1,66 @@
+/* stv.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None (despite the name, it doesn't really depend on ffest*)
+
+ Description:
+ Various and sundry info.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "stv.h"
+#include "lab.h"
+#include "where.h"
+
+/* Externals defined here. */
+
+ffestvSavestate ffestv_save_state_;
+ffewhereLine ffestv_save_line_;
+ffewhereColumn ffestv_save_col_;
+ffestvAccessstate ffestv_access_state_;
+ffewhereLine ffestv_access_line_;
+ffewhereColumn ffestv_access_col_;
+ffelabNumber ffestv_num_label_defines_;
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
diff --git a/contrib/gcc/f/stv.h b/contrib/gcc/f/stv.h
new file mode 100644
index 0000000..9ecdd80
--- /dev/null
+++ b/contrib/gcc/f/stv.h
@@ -0,0 +1,165 @@
+/* stv.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ stv.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_stv
+#define _H_f_stv
+
+/* Simple definitions and enumerations. */
+
+typedef enum
+ {
+ FFESTV_accessstateNONE, /* Haven't seen PUBLIC or PRIVATE yet. */
+ FFESTV_accessstatePUBLIC, /* Seen PUBLIC stmt w/o args. */
+ FFESTV_accessstatePRIVATE, /* Seen PRIVATE stmt w/o args. */
+ FFESTV_accessstateANY, /* Conflict seen and reported, so stop
+ whining. */
+ FFESTV_accessstate
+ } ffestvAccessstate;
+
+typedef enum
+ { /* Format specifier in an I/O statement. */
+ FFESTV_formatNONE, /* None. */
+ FFESTV_formatLABEL, /* Label (normal format). */
+ FFESTV_formatCHAREXPR, /* Character expression (normal format). */
+ FFESTV_formatASTERISK, /* Asterisk (list-directed). */
+ FFESTV_formatINTEXPR, /* Integer expression (assigned label). */
+ FFESTV_formatNAMELIST, /* Namelist (namelist-directed). */
+ FFESTV_format
+ } ffestvFormat;
+
+typedef enum
+ {
+ FFESTV_savestateNONE, /* Haven't seen SAVE stmt or attribute yet. */
+ FFESTV_savestateSPECIFIC, /* Seen SAVE stmt w/args or SAVE attr. */
+ FFESTV_savestateALL, /* Seen SAVE stmt w/o args. */
+ FFESTV_savestateANY, /* Conflict seen and reported, so stop
+ whining. */
+ FFESTV_savestate
+ } ffestvSavestate;
+
+typedef enum
+ {
+ FFESTV_stateNIL, /* Initial state, and after end of outer prog
+ unit. */
+ FFESTV_statePROGRAM0, /* After PROGRAM. */
+ FFESTV_statePROGRAM1, /* Before first non-USE statement. */
+ FFESTV_statePROGRAM2, /* After IMPLICIT NONE. */
+ FFESTV_statePROGRAM3, /* After IMPLICIT, PARAMETER, FORMAT. */
+ FFESTV_statePROGRAM4, /* Before executable stmt or CONTAINS. */
+ FFESTV_statePROGRAM5, /* After CONTAINS. */
+ FFESTV_stateSUBROUTINE0, /* After SUBROUTINE. */
+ FFESTV_stateSUBROUTINE1, /* Before first non-USE statement. */
+ FFESTV_stateSUBROUTINE2, /* After IMPLICIT NONE. */
+ FFESTV_stateSUBROUTINE3, /* After IMPLICIT, PARAMETER, FORMAT, ENTRY. */
+ FFESTV_stateSUBROUTINE4, /* Before executable stmt or CONTAINS. */
+ FFESTV_stateSUBROUTINE5, /* After CONTAINS. */
+ FFESTV_stateFUNCTION0, /* After FUNCTION. */
+ FFESTV_stateFUNCTION1, /* Before first non-USE statement. */
+ FFESTV_stateFUNCTION2, /* After IMPLICIT NONE. */
+ FFESTV_stateFUNCTION3, /* After IMPLICIT, PARAMETER, FORMAT, ENTRY. */
+ FFESTV_stateFUNCTION4, /* Before executable stmt or CONTAINS. */
+ FFESTV_stateFUNCTION5, /* After CONTAINS. */
+ FFESTV_stateMODULE0, /* After MODULE. */
+ FFESTV_stateMODULE1, /* Before first non-USE statement. */
+ FFESTV_stateMODULE2, /* After IMPLICIT NONE. */
+ FFESTV_stateMODULE3, /* After IMPLICIT, PARAMETER, FORMAT, ENTRY. */
+ FFESTV_stateMODULE4, /* Before executable stmt or CONTAINS. */
+ FFESTV_stateMODULE5, /* After CONTAINS. */
+ FFESTV_stateBLOCKDATA0, /* After BLOCKDATA. */
+ FFESTV_stateBLOCKDATA1, /* Before first non-USE statement. */
+ FFESTV_stateBLOCKDATA2, /* After IMPLICIT NONE. */
+ FFESTV_stateBLOCKDATA3, /* After IMPLICIT, PARAMETER, FORMAT, ENTRY. */
+ FFESTV_stateBLOCKDATA4, /* Before executable stmt or CONTAINS. */
+ FFESTV_stateBLOCKDATA5, /* After CONTAINS. */
+ FFESTV_stateUSE, /* Before first USE thru last USE. */
+ FFESTV_stateTYPE, /* After TYPE thru END TYPE. */
+ FFESTV_stateINTERFACE0, /* After INTERFACE thru MODULE PROCEDURE. */
+ FFESTV_stateINTERFACE1, /* After MODULE PROCEDURE thru END INTERFACE. */
+ FFESTV_stateSTRUCTURE, /* After STRUCTURE thru END STRUCTURE. */
+ FFESTV_stateUNION, /* After UNION thru END UNION. */
+ FFESTV_stateMAP, /* After MAP thru END MAP. */
+ FFESTV_stateWHERETHEN, /* After WHERE-construct thru END WHERE. */
+ FFESTV_stateWHERE, /* After WHERE-stmt thru next stmt. */
+ FFESTV_stateIFTHEN, /* After IF THEN thru END IF. */
+ FFESTV_stateIF, /* After IF thru next stmt. */
+ FFESTV_stateDO, /* After DO thru END DO or terminating label. */
+ FFESTV_stateSELECT0, /* After SELECT to before first CASE. */
+ FFESTV_stateSELECT1, /* First CASE in SELECT thru END SELECT. */
+ FFESTV_state
+ } ffestvState;
+
+typedef enum
+ { /* Unit specifier. */
+ FFESTV_unitNONE, /* None. */
+ FFESTV_unitINTEXPR, /* Integer expression (external file unit). */
+ FFESTV_unitASTERISK, /* Default unit. */
+ FFESTV_unitCHAREXPR, /* Character expression (internal file unit). */
+ FFESTV_unit
+ } ffestvUnit;
+
+/* Typedefs. */
+
+
+/* Include files needed by this one. */
+
+#include "lab.h"
+#include "where.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+extern ffestvSavestate ffestv_save_state_;
+extern ffewhereLine ffestv_save_line_;
+extern ffewhereColumn ffestv_save_col_;
+extern ffestvAccessstate ffestv_access_state_;
+extern ffewhereLine ffestv_access_line_;
+extern ffewhereColumn ffestv_access_col_;
+extern ffelabNumber ffestv_num_label_defines_;
+
+/* Declare functions with prototypes. */
+
+
+/* Define macros. */
+
+#define ffestv_init_0()
+#define ffestv_init_1()
+#define ffestv_init_2()
+#define ffestv_init_3()
+#define ffestv_init_4()
+#define ffestv_terminate_0()
+#define ffestv_terminate_1()
+#define ffestv_terminate_2()
+#define ffestv_terminate_3()
+#define ffestv_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/stw.c b/contrib/gcc/f/stw.c
new file mode 100644
index 0000000..90a19a5
--- /dev/null
+++ b/contrib/gcc/f/stw.c
@@ -0,0 +1,428 @@
+/* stw.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None (despite the name, it doesn't really depend on ffest*)
+
+ Description:
+ Provides abstraction and stack mechanism to track the block structure
+ of a Fortran program.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "stw.h"
+#include "bld.h"
+#include "com.h"
+#include "info.h"
+#include "lab.h"
+#include "lex.h"
+#include "malloc.h"
+#include "sta.h"
+#include "stv.h"
+#include "symbol.h"
+#include "where.h"
+
+/* Externals defined here. */
+
+ffestw ffestw_stack_top_ = NULL;
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+
+/* Internal macros. */
+
+
+/* ffestw_display_state -- DEBUGGING; display current block state
+
+ ffestw_display_state(); */
+
+void
+ffestw_display_state ()
+{
+ assert (ffestw_stack_top_ != NULL);
+
+ if (!ffe_is_ffedebug ())
+ return;
+
+ fprintf (dmpout, "; block %lu, state ", ffestw_stack_top_->blocknum_);
+ switch (ffestw_stack_top_->state_)
+ {
+ case FFESTV_stateNIL:
+ fputs ("NIL", dmpout);
+ break;
+
+ case FFESTV_statePROGRAM0:
+ fputs ("PROGRAM0", dmpout);
+ break;
+
+ case FFESTV_statePROGRAM1:
+ fputs ("PROGRAM1", dmpout);
+ break;
+
+ case FFESTV_statePROGRAM2:
+ fputs ("PROGRAM2", dmpout);
+ break;
+
+ case FFESTV_statePROGRAM3:
+ fputs ("PROGRAM3", dmpout);
+ break;
+
+ case FFESTV_statePROGRAM4:
+ fputs ("PROGRAM4", dmpout);
+ break;
+
+ case FFESTV_statePROGRAM5:
+ fputs ("PROGRAM5", dmpout);
+ break;
+
+ case FFESTV_stateSUBROUTINE0:
+ fputs ("SUBROUTINE0", dmpout);
+ break;
+
+ case FFESTV_stateSUBROUTINE1:
+ fputs ("SUBROUTINE1", dmpout);
+ break;
+
+ case FFESTV_stateSUBROUTINE2:
+ fputs ("SUBROUTINE2", dmpout);
+ break;
+
+ case FFESTV_stateSUBROUTINE3:
+ fputs ("SUBROUTINE3", dmpout);
+ break;
+
+ case FFESTV_stateSUBROUTINE4:
+ fputs ("SUBROUTINE4", dmpout);
+ break;
+
+ case FFESTV_stateSUBROUTINE5:
+ fputs ("SUBROUTINE5", dmpout);
+ break;
+
+ case FFESTV_stateFUNCTION0:
+ fputs ("FUNCTION0", dmpout);
+ break;
+
+ case FFESTV_stateFUNCTION1:
+ fputs ("FUNCTION1", dmpout);
+ break;
+
+ case FFESTV_stateFUNCTION2:
+ fputs ("FUNCTION2", dmpout);
+ break;
+
+ case FFESTV_stateFUNCTION3:
+ fputs ("FUNCTION3", dmpout);
+ break;
+
+ case FFESTV_stateFUNCTION4:
+ fputs ("FUNCTION4", dmpout);
+ break;
+
+ case FFESTV_stateFUNCTION5:
+ fputs ("FUNCTION5", dmpout);
+ break;
+
+ case FFESTV_stateMODULE0:
+ fputs ("MODULE0", dmpout);
+ break;
+
+ case FFESTV_stateMODULE1:
+ fputs ("MODULE1", dmpout);
+ break;
+
+ case FFESTV_stateMODULE2:
+ fputs ("MODULE2", dmpout);
+ break;
+
+ case FFESTV_stateMODULE3:
+ fputs ("MODULE3", dmpout);
+ break;
+
+ case FFESTV_stateMODULE4:
+ fputs ("MODULE4", dmpout);
+ break;
+
+ case FFESTV_stateMODULE5:
+ fputs ("MODULE5", dmpout);
+ break;
+
+ case FFESTV_stateBLOCKDATA0:
+ fputs ("BLOCKDATA0", dmpout);
+ break;
+
+ case FFESTV_stateBLOCKDATA1:
+ fputs ("BLOCKDATA1", dmpout);
+ break;
+
+ case FFESTV_stateBLOCKDATA2:
+ fputs ("BLOCKDATA2", dmpout);
+ break;
+
+ case FFESTV_stateBLOCKDATA3:
+ fputs ("BLOCKDATA3", dmpout);
+ break;
+
+ case FFESTV_stateBLOCKDATA4:
+ fputs ("BLOCKDATA4", dmpout);
+ break;
+
+ case FFESTV_stateBLOCKDATA5:
+ fputs ("BLOCKDATA5", dmpout);
+ break;
+
+ case FFESTV_stateUSE:
+ fputs ("USE", dmpout);
+ break;
+
+ case FFESTV_stateTYPE:
+ fputs ("TYPE", dmpout);
+ break;
+
+ case FFESTV_stateINTERFACE0:
+ fputs ("INTERFACE0", dmpout);
+ break;
+
+ case FFESTV_stateINTERFACE1:
+ fputs ("INTERFACE1", dmpout);
+ break;
+
+ case FFESTV_stateSTRUCTURE:
+ fputs ("STRUCTURE", dmpout);
+ break;
+
+ case FFESTV_stateUNION:
+ fputs ("UNION", dmpout);
+ break;
+
+ case FFESTV_stateMAP:
+ fputs ("MAP", dmpout);
+ break;
+
+ case FFESTV_stateWHERETHEN:
+ fputs ("WHERETHEN", dmpout);
+ break;
+
+ case FFESTV_stateWHERE:
+ fputs ("WHERE", dmpout);
+ break;
+
+ case FFESTV_stateIFTHEN:
+ fputs ("IFTHEN", dmpout);
+ break;
+
+ case FFESTV_stateIF:
+ fputs ("IF", dmpout);
+ break;
+
+ case FFESTV_stateDO:
+ fputs ("DO", dmpout);
+ break;
+
+ case FFESTV_stateSELECT0:
+ fputs ("SELECT0", dmpout);
+ break;
+
+ case FFESTV_stateSELECT1:
+ fputs ("SELECT1", dmpout);
+ break;
+
+ default:
+ assert ("bad state" == NULL);
+ break;
+ }
+ if (ffestw_stack_top_->top_do_ != NULL)
+ fputs (" (within DO)", dmpout);
+ fputc ('\n', dmpout);
+}
+
+/* ffestw_init_0 -- Initialize ffestw structures
+
+ ffestw_init_0(); */
+
+void
+ffestw_init_0 ()
+{
+ ffestw b;
+
+ ffestw_stack_top_ = b = (ffestw) malloc_new_kp (malloc_pool_image (),
+ "FFESTW stack base", sizeof (*b));
+ b->uses_ = 0; /* catch if anyone uses, kills, &c this
+ block. */
+ b->next_ = NULL;
+ b->previous_ = NULL;
+ b->top_do_ = NULL;
+ b->blocknum_ = 0;
+ b->shriek_ = NULL;
+ b->state_ = FFESTV_stateNIL;
+ b->line_ = ffewhere_line_unknown ();
+ b->col_ = ffewhere_column_unknown ();
+}
+
+/* ffestw_kill -- Kill block
+
+ ffestw b;
+ ffestw_kill(b); */
+
+void
+ffestw_kill (ffestw b)
+{
+ assert (b != NULL);
+ assert (b->uses_ > 0);
+
+ if (--b->uses_ != 0)
+ return;
+
+ ffewhere_line_kill (b->line_);
+ ffewhere_column_kill (b->col_);
+}
+
+/* ffestw_new -- Create block
+
+ ffestw b;
+ b = ffestw_new(); */
+
+ffestw
+ffestw_new ()
+{
+ ffestw b;
+
+ b = (ffestw) malloc_new_kp (malloc_pool_image (), "FFESTW", sizeof (*b));
+ b->uses_ = 1;
+
+ return b;
+}
+
+/* ffestw_pop -- Pop block off stack
+
+ ffestw_pop(); */
+
+ffestw
+ffestw_pop ()
+{
+ ffestw b;
+ ffestw oldb = ffestw_stack_top_;
+
+ assert (oldb != NULL);
+ ffestw_stack_top_ = b = ffestw_stack_top_->previous_;
+ assert (b != NULL);
+ if ((ffewhere_line_is_unknown (b->line_) || ffewhere_column_is_unknown (b->col_))
+ && (ffesta_tokens[0] != NULL))
+ {
+ assert (b->state_ == FFESTV_stateNIL);
+ if (ffewhere_line_is_unknown (b->line_))
+ b->line_
+ = ffewhere_line_use (ffelex_token_where_line (ffesta_tokens[0]));
+ if (ffewhere_column_is_unknown (b->col_))
+ b->col_
+ = ffewhere_column_use (ffelex_token_where_column (ffesta_tokens[0]));
+ }
+
+ return oldb;
+}
+
+/* ffestw_push -- Push block onto stack, return its address
+
+ ffestw b; // NULL if new block to be obtained first.
+ ffestw_push(b);
+
+ Returns address of block if desired, also updates ffestw_stack_top_
+ to point to it.
+
+ 30-Oct-91 JCB 2.0
+ Takes block as arg, or NULL if new block needed. */
+
+ffestw
+ffestw_push (ffestw b)
+{
+ if (b == NULL)
+ b = ffestw_new ();
+
+ b->next_ = NULL;
+ b->previous_ = ffestw_stack_top_;
+ b->line_ = ffewhere_line_unknown ();
+ b->col_ = ffewhere_column_unknown ();
+ ffestw_stack_top_ = b;
+ return b;
+}
+
+/* ffestw_update -- Update current block line/col info
+
+ ffestw_update();
+
+ Updates block to point to current statement. */
+
+ffestw
+ffestw_update (ffestw b)
+{
+ if (b == NULL)
+ {
+ b = ffestw_stack_top_;
+ assert (b != NULL);
+ }
+
+ if (ffesta_tokens[0] == NULL)
+ return b;
+
+ ffewhere_line_kill (b->line_);
+ ffewhere_column_kill (b->col_);
+ b->line_ = ffewhere_line_use (ffelex_token_where_line (ffesta_tokens[0]));
+ b->col_ = ffewhere_column_use (ffelex_token_where_column (ffesta_tokens[0]));
+
+ return b;
+}
+
+/* ffestw_use -- Mark extra use of block
+
+ ffestw b;
+ b = ffestw_use(b); // will always return original copy of b
+
+ Increments use counter for b. */
+
+ffestw
+ffestw_use (ffestw b)
+{
+ assert (b != NULL);
+ assert (b->uses_ != 0);
+
+ ++b->uses_;
+
+ return b;
+}
diff --git a/contrib/gcc/f/stw.h b/contrib/gcc/f/stw.h
new file mode 100644
index 0000000..8caefbd
--- /dev/null
+++ b/contrib/gcc/f/stw.h
@@ -0,0 +1,184 @@
+/* stw.h -- Private #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ stw.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_stw
+#define _H_f_stw
+
+/* Simple definitions and enumerations. */
+
+
+/* Typedefs. */
+
+typedef struct _ffestw_ *ffestw;
+typedef struct _ffestw_case_ *ffestwCase;
+typedef struct _ffestw_select_ *ffestwSelect;
+typedef void (*ffestwShriek) (bool ok);
+
+/* Include files needed by this one. */
+
+#include "bld.h"
+#include "com.h"
+#include "info.h"
+#include "lab.h"
+#include "lex.h"
+#include "malloc.h"
+#include "stv.h"
+#include "symbol.h"
+#include "where.h"
+
+/* Structure definitions. */
+
+struct _ffestw_
+ {
+ ffestw next_; /* Next (unused) block, or NULL. */
+ ffestw previous_; /* Previous block, NULL if this is NIL state. */
+ ffestw top_do_; /* Previous or current DO state, or NULL. */
+ unsigned long blocknum_; /* Block # w/in procedure/program. */
+ ffestwShriek shriek_; /* Call me to pop block in a hurry. */
+ ffesymbol sym_; /* Related symbol (if there is one). */
+ ffelexToken name_; /* Construct name (IFTHEN, SELECT, DO only). */
+ ffestwSelect select_; /* Info for SELECT CASE blocks. */
+ ffelab label_; /* For DO blocks w/labels, the target label. */
+ ffesymbol do_iter_var_; /* For iter DO blocks, the iter var or NULL. */
+ ffelexToken do_iter_var_t_; /* The token for do_iter_var. */
+ ffewhereLine line_; /* Where first token of statement triggering
+ state */
+ ffewhereColumn col_; /* was seen in source file. */
+ char uses_; /* # uses (new+use-kill calls). */
+ ffestvState state_;
+ int substate_; /* Used on a per-block-state basis. */
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+ struct nesting *do_hook_; /* backend id for given loop (EXIT/CYCLE). */
+ tree do_tvar_; /* tree form of do_iter_var. */
+ tree do_incr_saved_; /* tree SAVED_EXPR of incr expr. */
+ tree do_count_var_; /* tree of countdown variable. */
+ tree select_texpr_; /* tree for end case. */
+ bool select_break_; /* TRUE when CASE should start with gen
+ "break;". */
+#endif /* FFECOM_targetCURRENT == FFECOM_targetGCC*/
+ };
+
+struct _ffestw_case_
+ {
+ ffestwCase next_rel; /* Next case range in relational order. */
+ ffestwCase previous_rel; /* Previous case range in relational order. */
+ ffestwCase next_stmt; /* Next range in stmt or first in next stmt. */
+ ffestwCase previous_stmt; /* Previous range. */
+ ffebldConstant low; /* Low value in range. */
+ ffebldConstant high; /* High value in range. */
+ unsigned long casenum; /* CASE stmt index for this range/value. */
+ ffelexToken t; /* Token for this range/value; ffestc only. */
+ };
+
+struct _ffestw_select_
+ {
+ ffestwCase first_rel; /* First CASE range (after low) in order. */
+ ffestwCase last_rel; /* Last CASE range (before high) in order. */
+ ffestwCase first_stmt; /* First range in first CASE stmt. */
+ ffestwCase last_stmt; /* Last range in last CASE stmt. */
+ mallocPool pool; /* Pool in which this and all cases are
+ allocated. */
+ unsigned long cases; /* Number of CASE stmts seen so far. */
+ ffelexToken t; /* First token of selected expression; ffestc
+ only. */
+ ffeinfoBasictype type; /* Basic type (integer, character, or
+ logical). */
+ ffeinfoKindtype kindtype; /* Kind type. */
+ };
+
+/* Global objects accessed by users of this module. */
+
+extern ffestw ffestw_stack_top_;
+
+/* Declare functions with prototypes. */
+
+void ffestw_display_state ();
+void ffestw_kill (ffestw block);
+void ffestw_init_0 (void);
+ffestw ffestw_new ();
+ffestw ffestw_pop ();
+ffestw ffestw_push (ffestw block);
+ffestw ffestw_update (ffestw block);
+ffestw ffestw_use (ffestw block);
+
+/* Define macros. */
+
+#define ffestw_blocknum(b) ((b)->blocknum_)
+#define ffestw_col(b) ((b)->col_)
+#define ffestw_do_count_var(b) ((b)->do_count_var_)
+#define ffestw_do_hook(b) ((b)->do_hook_)
+#define ffestw_do_incr_saved(b) ((b)->do_incr_saved_)
+#define ffestw_do_iter_var(b) ((b)->do_iter_var_)
+#define ffestw_do_iter_var_t(b) ((b)->do_iter_var_t_)
+#define ffestw_do_tvar(b) ((b)->do_tvar_)
+#define ffestw_init_1()
+#define ffestw_init_2()
+#define ffestw_init_3()
+#define ffestw_init_4()
+#define ffestw_label(b) ((b)->label_)
+#define ffestw_line(b) ((b)->line_)
+#define ffestw_name(b) ((b)->name_)
+#define ffestw_previous(b) ((b)->previous_)
+#define ffestw_select(b) ((b)->select_)
+#define ffestw_select_break(b) ((b)->select_break_)
+#define ffestw_select_texpr(b) ((b)->select_texpr_)
+#define ffestw_set_blocknum(b,bl) ((b)->blocknum_ = (bl))
+#define ffestw_set_col(b,c) ((b)->col_ = (c))
+#define ffestw_set_do_count_var(b,d) ((b)->do_count_var_ = (d))
+#define ffestw_set_do_hook(b,d) ((b)->do_hook_ = (d))
+#define ffestw_set_do_incr_saved(b,d) ((b)->do_incr_saved_ = (d))
+#define ffestw_set_do_iter_var(b,v) ((b)->do_iter_var_ = (v))
+#define ffestw_set_do_iter_var_t(b,t) ((b)->do_iter_var_t_ = (t))
+#define ffestw_set_do_tvar(b,d) ((b)->do_tvar_ = (d))
+#define ffestw_set_label(b,l) ((b)->label_ = (l))
+#define ffestw_set_line(b,l) ((b)->line_ = (l))
+#define ffestw_set_name(b,n) ((b)->name_ = (n))
+#define ffestw_set_select(b,s) ((b)->select_ = (s))
+#define ffestw_set_select_break(b,br) ((b)->select_break_ = (br))
+#define ffestw_set_select_texpr(b,t) ((b)->select_texpr_ = (t))
+#define ffestw_set_shriek(b,s) ((b)->shriek_ = (s))
+#define ffestw_set_state(b,s) ((b)->state_ = (s))
+#define ffestw_set_substate(b,s) ((b)->substate_ = (s))
+#define ffestw_set_sym(b,s) ((b)->sym_= (s))
+#define ffestw_set_top_do(b,t) ((b)->top_do_ = (t))
+#define ffestw_shriek(b) ((b)->shriek_)
+#define ffestw_stack_top() ffestw_stack_top_
+#define ffestw_state(b) ((b)->state_)
+#define ffestw_substate(b) ((b)->substate_)
+#define ffestw_sym(b) ((b)->sym_)
+#define ffestw_terminate_0()
+#define ffestw_terminate_1()
+#define ffestw_terminate_2()
+#define ffestw_terminate_3()
+#define ffestw_terminate_4()
+#define ffestw_top_do(b) ((b)->top_do_)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/symbol.c b/contrib/gcc/f/symbol.c
new file mode 100644
index 0000000..8aa7230
--- /dev/null
+++ b/contrib/gcc/f/symbol.c
@@ -0,0 +1,1477 @@
+/* Implementation of Fortran symbol manager
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "proj.h"
+#include "symbol.h"
+#include "bad.h"
+#include "bld.h"
+#include "com.h"
+#include "equiv.h"
+#include "global.h"
+#include "info.h"
+#include "intrin.h"
+#include "lex.h"
+#include "malloc.h"
+#include "src.h"
+#include "st.h"
+#include "storag.h"
+#include "target.h"
+#include "where.h"
+
+/* Choice of how to handle global symbols -- either global only within the
+ program unit being defined or global within the entire source file.
+ The former is appropriate for systems where an object file can
+ easily be taken apart program unit by program unit, the latter is the
+ UNIX/C model where the object file is essentially a monolith. */
+
+#define FFESYMBOL_globalPROGUNIT_ 1
+#define FFESYMBOL_globalFILE_ 2
+
+/* Choose how to handle global symbols here. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+#define FFESYMBOL_globalCURRENT_ FFESYMBOL_globalPROGUNIT_
+#elif FFECOM_targetCURRENT == FFECOM_targetGCC
+/* Would be good to understand why PROGUNIT in this case too.
+ (1995-08-22). */
+#define FFESYMBOL_globalCURRENT_ FFESYMBOL_globalPROGUNIT_
+#else
+#error
+#endif
+
+/* Choose how to handle memory pools based on global symbol stuff. */
+
+#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_
+#define FFESYMBOL_SPACE_POOL_ ffe_pool_program_unit()
+#elif FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalFILE_
+#define FFESYMBOL_SPACE_POOL_ ffe_pool_file()
+#else
+#error
+#endif
+
+/* What kind of retraction is needed for a symbol? */
+
+enum _ffesymbol_retractcommand_
+ {
+ FFESYMBOL_retractcommandDELETE_,
+ FFESYMBOL_retractcommandRETRACT_,
+ FFESYMBOL_retractcommand_
+ };
+typedef enum _ffesymbol_retractcommand_ ffesymbolRetractCommand_;
+
+/* This object keeps track of retraction for a symbol and links to the next
+ such object. */
+
+typedef struct _ffesymbol_retract_ *ffesymbolRetract_;
+struct _ffesymbol_retract_
+ {
+ ffesymbolRetract_ next;
+ ffesymbolRetractCommand_ command;
+ ffesymbol live; /* Live symbol. */
+ ffesymbol symbol; /* Backup copy of symbol. */
+ };
+
+static ffebad ffesymbol_check_token_ (ffelexToken t, char *c);
+static void ffesymbol_kill_manifest_ (void);
+static ffesymbol ffesymbol_new_ (ffename n);
+static ffesymbol ffesymbol_unhook_ (ffesymbol s);
+static void ffesymbol_whine_state_ (ffebad bad, ffelexToken t, char c);
+
+/* Manifest names for unnamed things (as tokens) so we make them only
+ once. */
+
+static ffelexToken ffesymbol_token_blank_common_ = NULL;
+static ffelexToken ffesymbol_token_unnamed_main_ = NULL;
+static ffelexToken ffesymbol_token_unnamed_blockdata_ = NULL;
+
+/* Name spaces currently in force. */
+
+static ffenameSpace ffesymbol_global_ = NULL;
+static ffenameSpace ffesymbol_local_ = NULL;
+static ffenameSpace ffesymbol_sfunc_ = NULL;
+
+/* Keep track of retraction. */
+
+static bool ffesymbol_retractable_ = FALSE;
+static mallocPool ffesymbol_retract_pool_;
+static ffesymbolRetract_ ffesymbol_retract_first_;
+static ffesymbolRetract_ *ffesymbol_retract_list_;
+
+/* List of state names. */
+
+static char *ffesymbol_state_name_[] =
+{
+ "?",
+ "@",
+ "&",
+ "$",
+};
+
+/* List of attribute names. */
+
+static char *ffesymbol_attr_name_[] =
+{
+#define DEFATTR(ATTR,ATTRS,NAME) NAME,
+#include "symbol.def"
+#undef DEFATTR
+};
+
+
+/* Check whether the token text has any invalid characters. If not,
+ return FALSE. If so, if error messages inhibited, return TRUE
+ so caller knows to try again later, else report error and return
+ FALSE. */
+
+static ffebad
+ffesymbol_check_token_ (ffelexToken t, char *c)
+{
+ char *p = ffelex_token_text (t);
+ ffeTokenLength len = ffelex_token_length (t);
+ ffebad bad;
+ ffeTokenLength i = 0;
+ ffebad skip_me = ((ffe_case_symbol () == FFE_caseINITCAP)
+ ? FFEBAD_SYMBOL_NOLOWER_INITCAP : FFEBAD + 1);
+ ffebad stop_me = ((ffe_case_symbol () == FFE_caseINITCAP)
+ ? FFEBAD : FFEBAD + 1);
+ if (len == 0)
+ return FFEBAD;
+
+ bad = ffesrc_bad_char_symbol_init (*p);
+ if (bad == FFEBAD)
+ {
+ for (++i, ++p; i < len; ++i, ++p)
+ {
+ bad = ffesrc_bad_char_symbol_noninit (*p);
+ if (bad == skip_me)
+ continue; /* Keep looking for good InitCap character. */
+ if (bad == stop_me)
+ break; /* Found good InitCap character. */
+ if (bad != FFEBAD)
+ break; /* Bad character found. */
+ }
+ }
+
+ if (bad != FFEBAD)
+ {
+ if (i >= len)
+ *c = *(ffelex_token_text (t));
+ else
+ *c = *p;
+ }
+
+ return bad;
+}
+
+/* Kill manifest (g77-picked) names. */
+
+static void
+ffesymbol_kill_manifest_ ()
+{
+ if (ffesymbol_token_blank_common_ != NULL)
+ ffelex_token_kill (ffesymbol_token_blank_common_);
+ if (ffesymbol_token_unnamed_main_ != NULL)
+ ffelex_token_kill (ffesymbol_token_unnamed_main_);
+ if (ffesymbol_token_unnamed_blockdata_ != NULL)
+ ffelex_token_kill (ffesymbol_token_unnamed_blockdata_);
+
+ ffesymbol_token_blank_common_ = NULL;
+ ffesymbol_token_unnamed_main_ = NULL;
+ ffesymbol_token_unnamed_blockdata_ = NULL;
+}
+
+/* Make new symbol.
+
+ If the "retractable" flag is not set, just return the new symbol.
+ Else, add symbol to the "retract" list as a delete item, set
+ the "have_old" flag, and return the new symbol. */
+
+static ffesymbol
+ffesymbol_new_ (ffename n)
+{
+ ffesymbol s;
+ ffesymbolRetract_ r;
+
+ assert (n != NULL);
+
+ s = (ffesymbol) malloc_new_ks (FFESYMBOL_SPACE_POOL_, "FFESYMBOL",
+ sizeof (*s));
+ s->name = n;
+ s->other_space_name = NULL;
+#if FFEGLOBAL_ENABLED
+ s->global = NULL;
+#endif
+ s->attrs = FFESYMBOL_attrsetNONE;
+ s->state = FFESYMBOL_stateNONE;
+ s->info = ffeinfo_new_null ();
+ s->dims = NULL;
+ s->extents = NULL;
+ s->dim_syms = NULL;
+ s->array_size = NULL;
+ s->init = NULL;
+ s->accretion = NULL;
+ s->accretes = 0;
+ s->dummy_args = NULL;
+ s->namelist = NULL;
+ s->common_list = NULL;
+ s->sfunc_expr = NULL;
+ s->list_bottom = NULL;
+ s->common = NULL;
+ s->equiv = NULL;
+ s->storage = NULL;
+#ifdef FFECOM_symbolHOOK
+ s->hook = FFECOM_symbolNULL;
+#endif
+ s->sfa_dummy_parent = NULL;
+ s->func_result = NULL;
+ s->value = 0;
+ s->check_state = FFESYMBOL_checkstateNONE_;
+ s->check_token = NULL;
+ s->max_entry_num = 0;
+ s->num_entries = 0;
+ s->generic = FFEINTRIN_genNONE;
+ s->specific = FFEINTRIN_specNONE;
+ s->implementation = FFEINTRIN_impNONE;
+ s->is_save = FALSE;
+ s->is_init = FALSE;
+ s->do_iter = FALSE;
+ s->reported = FALSE;
+ s->explicit_where = FALSE;
+ s->namelisted = FALSE;
+
+ ffename_set_symbol (n, s);
+
+ if (!ffesymbol_retractable_)
+ {
+ s->have_old = FALSE;
+ return s;
+ }
+
+ r = (ffesymbolRetract_) malloc_new_kp (ffesymbol_retract_pool_,
+ "FFESYMBOL retract", sizeof (*r));
+ r->next = NULL;
+ r->command = FFESYMBOL_retractcommandDELETE_;
+ r->live = s;
+ r->symbol = NULL; /* No backup copy. */
+
+ *ffesymbol_retract_list_ = r;
+ ffesymbol_retract_list_ = &r->next;
+
+ s->have_old = TRUE;
+ return s;
+}
+
+/* Unhook a symbol from its (soon-to-be-killed) name obj.
+
+ NULLify the names to which this symbol points. Do other cleanup as
+ needed. */
+
+static ffesymbol
+ffesymbol_unhook_ (ffesymbol s)
+{
+ s->other_space_name = s->name = NULL;
+ if ((ffesymbol_attrs (s) & FFESYMBOL_attrsCBLOCK)
+ || (ffesymbol_kind (s) == FFEINFO_kindNAMELIST))
+ ffebld_end_list (ffesymbol_ptr_to_listbottom (s));
+ if (s->check_state == FFESYMBOL_checkstatePENDING_)
+ ffelex_token_kill (s->check_token);
+
+ return s;
+}
+
+/* Issue diagnostic about bad character in token representing user-defined
+ symbol name. */
+
+static void
+ffesymbol_whine_state_ (ffebad bad, ffelexToken t, char c)
+{
+ char badstr[2];
+
+ badstr[0] = c;
+ badstr[1] = '\0';
+
+ ffebad_start (bad);
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_string (badstr);
+ ffebad_finish ();
+}
+
+/* Returns a string representing the attributes set. */
+
+char *
+ffesymbol_attrs_string (ffesymbolAttrs attrs)
+{
+ static char string[FFESYMBOL_attr * 12 + 20];
+ char *p;
+ ffesymbolAttr attr;
+
+ p = &string[0];
+
+ if (attrs == FFESYMBOL_attrsetNONE)
+ {
+ strcpy (p, "NONE");
+ return &string[0];
+ }
+
+ for (attr = 0; attr < FFESYMBOL_attr; ++attr)
+ {
+ if (attrs & ((ffesymbolAttrs) 1 << attr))
+ {
+ attrs &= ~((ffesymbolAttrs) 1 << attr);
+ strcpy (p, ffesymbol_attr_name_[attr]);
+ while (*p)
+ ++p;
+ *(p++) = '|';
+ }
+ }
+ if (attrs == FFESYMBOL_attrsetNONE)
+ *--p = '\0';
+ else
+ sprintf (p, "?0x%" ffesymbolAttrs_f "x?", attrs);
+ assert (((size_t) (p - &string[0])) < ARRAY_SIZE (string));
+ return &string[0];
+}
+
+/* Check symbol's name for validity, considering that it might actually
+ be an intrinsic and thus should not be complained about just yet. */
+
+void
+ffesymbol_check (ffesymbol s, ffelexToken t, bool maybe_intrin)
+{
+ char c;
+ ffebad bad;
+ ffeintrinGen gen;
+ ffeintrinSpec spec;
+ ffeintrinImp imp;
+
+ if (!ffesrc_check_symbol ()
+ || ((s->check_state != FFESYMBOL_checkstateNONE_)
+ && ((s->check_state != FFESYMBOL_checkstateINHIBITED_)
+ || ffebad_inhibit ())))
+ return;
+
+ bad = ffesymbol_check_token_ (t, &c);
+
+ if (bad == FFEBAD)
+ {
+ s->check_state = FFESYMBOL_checkstateCHECKED_;
+ return;
+ }
+
+ if (maybe_intrin
+ && ffeintrin_is_intrinsic (ffelex_token_text (t), NULL, FALSE,
+ &gen, &spec, &imp))
+ {
+ s->check_state = FFESYMBOL_checkstatePENDING_;
+ s->check_token = ffelex_token_use (t);
+ return;
+ }
+
+ if (ffebad_inhibit ())
+ {
+ s->check_state = FFESYMBOL_checkstateINHIBITED_;
+ return; /* Don't complain now, do it later. */
+ }
+
+ s->check_state = FFESYMBOL_checkstateCHECKED_;
+
+ ffesymbol_whine_state_ (bad, t, c);
+}
+
+/* Declare a BLOCKDATA unit.
+
+ Retrieves or creates the ffesymbol for the specified BLOCKDATA (unnamed
+ if t is NULL). Doesn't actually ensure the named item is a
+ BLOCKDATA; the caller must handle that. */
+
+ffesymbol
+ffesymbol_declare_blockdataunit (ffelexToken t, ffewhereLine wl,
+ ffewhereColumn wc)
+{
+ ffename n;
+ ffesymbol s;
+ bool user = (t != NULL);
+
+ assert (!ffesymbol_retractable_);
+
+ if (t == NULL)
+ {
+ if (ffesymbol_token_unnamed_blockdata_ == NULL)
+ ffesymbol_token_unnamed_blockdata_
+ = ffelex_token_new_name (FFETARGET_nameUNNAMED_BLOCK_DATA, wl, wc);
+ t = ffesymbol_token_unnamed_blockdata_;
+ }
+
+ n = ffename_lookup (ffesymbol_local_, t);
+ if (n != NULL)
+ return ffename_symbol (n); /* This will become an error. */
+
+ n = ffename_find (ffesymbol_global_, t);
+ s = ffename_symbol (n);
+ if (s != NULL)
+ {
+ if (user)
+ ffesymbol_check (s, t, FALSE);
+ return s;
+ }
+
+ s = ffesymbol_new_ (n);
+ if (user)
+ ffesymbol_check (s, t, FALSE);
+
+ /* A program unit name also is in the local name space. */
+
+ n = ffename_find (ffesymbol_local_, t);
+ ffename_set_symbol (n, s);
+ s->other_space_name = n;
+
+ ffeglobal_new_blockdata (s, t); /* Detect conflicts, when
+ appropriate. */
+
+ return s;
+}
+
+/* Declare a common block (named or unnamed).
+
+ Retrieves or creates the ffesymbol for the specified common block (blank
+ common if t is NULL). Doesn't actually ensure the named item is a
+ common block; the caller must handle that. */
+
+ffesymbol
+ffesymbol_declare_cblock (ffelexToken t, ffewhereLine wl, ffewhereColumn wc)
+{
+ ffename n;
+ ffesymbol s;
+ bool blank;
+
+ assert (!ffesymbol_retractable_);
+
+ if (t == NULL)
+ {
+ blank = TRUE;
+ if (ffesymbol_token_blank_common_ == NULL)
+ ffesymbol_token_blank_common_
+ = ffelex_token_new_name (FFETARGET_nameBLANK_COMMON, wl, wc);
+ t = ffesymbol_token_blank_common_;
+ }
+ else
+ blank = FALSE;
+
+ n = ffename_find (ffesymbol_global_, t);
+ s = ffename_symbol (n);
+ if (s != NULL)
+ {
+ if (!blank)
+ ffesymbol_check (s, t, FALSE);
+ return s;
+ }
+
+ s = ffesymbol_new_ (n);
+ if (!blank)
+ ffesymbol_check (s, t, FALSE);
+
+ ffeglobal_new_common (s, t, blank); /* Detect conflicts. */
+
+ return s;
+}
+
+/* Declare a FUNCTION program unit (with distinct RESULT() name).
+
+ Retrieves or creates the ffesymbol for the specified function. Doesn't
+ actually ensure the named item is a function; the caller must handle
+ that.
+
+ If FUNCTION with RESULT() is specified but the names are the same,
+ pretend as though RESULT() was not specified, and don't call this
+ function; use ffesymbol_declare_funcunit() instead. */
+
+ffesymbol
+ffesymbol_declare_funcnotresunit (ffelexToken t)
+{
+ ffename n;
+ ffesymbol s;
+
+ assert (t != NULL);
+ assert (!ffesymbol_retractable_);
+
+ n = ffename_lookup (ffesymbol_local_, t);
+ if (n != NULL)
+ return ffename_symbol (n); /* This will become an error. */
+
+ n = ffename_find (ffesymbol_global_, t);
+ s = ffename_symbol (n);
+ if (s != NULL)
+ {
+ ffesymbol_check (s, t, FALSE);
+ return s;
+ }
+
+ s = ffesymbol_new_ (n);
+ ffesymbol_check (s, t, FALSE);
+
+ /* A FUNCTION program unit name also is in the local name space; handle it
+ here since RESULT() is a different name and is handled separately. */
+
+ n = ffename_find (ffesymbol_local_, t);
+ ffename_set_symbol (n, s);
+ s->other_space_name = n;
+
+ ffeglobal_new_function (s, t);/* Detect conflicts, when appropriate. */
+
+ return s;
+}
+
+/* Declare a function result.
+
+ Retrieves or creates the ffesymbol for the specified function result,
+ whether specified via a distinct RESULT() or by default in a FUNCTION or
+ ENTRY statement. */
+
+ffesymbol
+ffesymbol_declare_funcresult (ffelexToken t)
+{
+ ffename n;
+ ffesymbol s;
+
+ assert (t != NULL);
+ assert (!ffesymbol_retractable_);
+
+ n = ffename_find (ffesymbol_local_, t);
+ s = ffename_symbol (n);
+ if (s != NULL)
+ return s;
+
+ return ffesymbol_new_ (n);
+}
+
+/* Declare a FUNCTION program unit with no RESULT().
+
+ Retrieves or creates the ffesymbol for the specified function. Doesn't
+ actually ensure the named item is a function; the caller must handle
+ that.
+
+ This is the function to call when the FUNCTION or ENTRY statement has
+ no separate and distinct name specified via RESULT(). That's because
+ this function enters the global name of the function in only the global
+ name space. ffesymbol_declare_funcresult() must still be called to
+ declare the name for the function result in the local name space. */
+
+ffesymbol
+ffesymbol_declare_funcunit (ffelexToken t)
+{
+ ffename n;
+ ffesymbol s;
+
+ assert (t != NULL);
+ assert (!ffesymbol_retractable_);
+
+ n = ffename_find (ffesymbol_global_, t);
+ s = ffename_symbol (n);
+ if (s != NULL)
+ {
+ ffesymbol_check (s, t, FALSE);
+ return s;
+ }
+
+ s = ffesymbol_new_ (n);
+ ffesymbol_check (s, t, FALSE);
+
+ ffeglobal_new_function (s, t);/* Detect conflicts. */
+
+ return s;
+}
+
+/* Declare a local entity.
+
+ Retrieves or creates the ffesymbol for the specified local entity.
+ Set maybe_intrin TRUE if this name might turn out to name an
+ intrinsic (legitimately); otherwise if the name doesn't meet the
+ requirements for a user-defined symbol name, a diagnostic will be
+ issued right away rather than waiting until the intrinsicness of the
+ symbol is determined. */
+
+ffesymbol
+ffesymbol_declare_local (ffelexToken t, bool maybe_intrin)
+{
+ ffename n;
+ ffesymbol s;
+
+ assert (t != NULL);
+
+ /* If we're parsing within a statement function definition, return the
+ symbol if already known (a dummy argument for the statement function).
+ Otherwise continue on, which means the symbol is declared within the
+ containing (local) program unit rather than the statement function
+ definition. */
+
+ if ((ffesymbol_sfunc_ != NULL)
+ && ((n = ffename_lookup (ffesymbol_sfunc_, t)) != NULL))
+ return ffename_symbol (n);
+
+ n = ffename_find (ffesymbol_local_, t);
+ s = ffename_symbol (n);
+ if (s != NULL)
+ {
+ ffesymbol_check (s, t, maybe_intrin);
+ return s;
+ }
+
+ s = ffesymbol_new_ (n);
+ ffesymbol_check (s, t, maybe_intrin);
+ return s;
+}
+
+/* Declare a main program unit.
+
+ Retrieves or creates the ffesymbol for the specified main program unit
+ (unnamed main program unit if t is NULL). Doesn't actually ensure the
+ named item is a program; the caller must handle that. */
+
+ffesymbol
+ffesymbol_declare_programunit (ffelexToken t, ffewhereLine wl,
+ ffewhereColumn wc)
+{
+ ffename n;
+ ffesymbol s;
+ bool user = (t != NULL);
+
+ assert (!ffesymbol_retractable_);
+
+ if (t == NULL)
+ {
+ if (ffesymbol_token_unnamed_main_ == NULL)
+ ffesymbol_token_unnamed_main_
+ = ffelex_token_new_name (FFETARGET_nameUNNAMED_MAIN, wl, wc);
+ t = ffesymbol_token_unnamed_main_;
+ }
+
+ n = ffename_lookup (ffesymbol_local_, t);
+ if (n != NULL)
+ return ffename_symbol (n); /* This will become an error. */
+
+ n = ffename_find (ffesymbol_global_, t);
+ s = ffename_symbol (n);
+ if (s != NULL)
+ {
+ if (user)
+ ffesymbol_check (s, t, FALSE);
+ return s;
+ }
+
+ s = ffesymbol_new_ (n);
+ if (user)
+ ffesymbol_check (s, t, FALSE);
+
+ /* A program unit name also is in the local name space. */
+
+ n = ffename_find (ffesymbol_local_, t);
+ ffename_set_symbol (n, s);
+ s->other_space_name = n;
+
+ ffeglobal_new_program (s, t); /* Detect conflicts. */
+
+ return s;
+}
+
+/* Declare a statement-function dummy.
+
+ Retrieves or creates the ffesymbol for the specified statement
+ function dummy. Also ensures that it has a link to the parent (local)
+ ffesymbol with the same name, creating it if necessary. */
+
+ffesymbol
+ffesymbol_declare_sfdummy (ffelexToken t)
+{
+ ffename n;
+ ffesymbol s;
+ ffesymbol sp; /* Parent symbol in local area. */
+
+ assert (t != NULL);
+
+ n = ffename_find (ffesymbol_local_, t);
+ sp = ffename_symbol (n);
+ if (sp == NULL)
+ sp = ffesymbol_new_ (n);
+ ffesymbol_check (sp, t, FALSE);
+
+ n = ffename_find (ffesymbol_sfunc_, t);
+ s = ffename_symbol (n);
+ if (s == NULL)
+ {
+ s = ffesymbol_new_ (n);
+ s->sfa_dummy_parent = sp;
+ }
+ else
+ assert (s->sfa_dummy_parent == sp);
+
+ return s;
+}
+
+/* Declare a subroutine program unit.
+
+ Retrieves or creates the ffesymbol for the specified subroutine
+ Doesn't actually ensure the named item is a subroutine; the caller must
+ handle that. */
+
+ffesymbol
+ffesymbol_declare_subrunit (ffelexToken t)
+{
+ ffename n;
+ ffesymbol s;
+
+ assert (!ffesymbol_retractable_);
+ assert (t != NULL);
+
+ n = ffename_lookup (ffesymbol_local_, t);
+ if (n != NULL)
+ return ffename_symbol (n); /* This will become an error. */
+
+ n = ffename_find (ffesymbol_global_, t);
+ s = ffename_symbol (n);
+ if (s != NULL)
+ {
+ ffesymbol_check (s, t, FALSE);
+ return s;
+ }
+
+ s = ffesymbol_new_ (n);
+ ffesymbol_check (s, t, FALSE);
+
+ /* A program unit name also is in the local name space. */
+
+ n = ffename_find (ffesymbol_local_, t);
+ ffename_set_symbol (n, s);
+ s->other_space_name = n;
+
+ ffeglobal_new_subroutine (s, t); /* Detect conflicts, when
+ appropriate. */
+
+ return s;
+}
+
+/* Call given fn with all local/global symbols.
+
+ ffesymbol (*fn) (ffesymbol s);
+ ffesymbol_drive (fn); */
+
+void
+ffesymbol_drive (ffesymbol (*fn) ())
+{
+ assert (ffesymbol_sfunc_ == NULL); /* Might be ok, but not for current
+ uses. */
+ ffename_space_drive_symbol (ffesymbol_local_, fn);
+ ffename_space_drive_symbol (ffesymbol_global_, fn);
+}
+
+/* Call given fn with all sfunc-only symbols.
+
+ ffesymbol (*fn) (ffesymbol s);
+ ffesymbol_drive_sfnames (fn); */
+
+void
+ffesymbol_drive_sfnames (ffesymbol (*fn) ())
+{
+ ffename_space_drive_symbol (ffesymbol_sfunc_, fn);
+}
+
+/* Dump info on the symbol for debugging purposes. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffesymbol_dump (ffesymbol s)
+{
+ ffeinfoKind k;
+ ffeinfoWhere w;
+
+ assert (s != NULL);
+
+ if (ffeinfo_size (s->info) != FFETARGET_charactersizeNONE)
+ fprintf (dmpout, "%s:%d%s%s*%" ffetargetCharacterSize_f "u",
+ ffesymbol_text (s),
+ (int) ffeinfo_rank (s->info),
+ ffeinfo_basictype_string (ffeinfo_basictype (s->info)),
+ ffeinfo_kindtype_string (ffeinfo_kindtype (s->info)),
+ ffeinfo_size (s->info));
+ else
+ fprintf (dmpout, "%s:%d%s%s",
+ ffesymbol_text (s),
+ (int) ffeinfo_rank (s->info),
+ ffeinfo_basictype_string (ffeinfo_basictype (s->info)),
+ ffeinfo_kindtype_string (ffeinfo_kindtype (s->info)));
+ if ((k = ffeinfo_kind (s->info)) != FFEINFO_kindNONE)
+ fprintf (dmpout, "/%s", ffeinfo_kind_string (k));
+ if ((w = ffeinfo_where (s->info)) != FFEINFO_whereNONE)
+ fprintf (dmpout, "@%s", ffeinfo_where_string (w));
+
+ if ((s->generic != FFEINTRIN_genNONE)
+ || (s->specific != FFEINTRIN_specNONE)
+ || (s->implementation != FFEINTRIN_impNONE))
+ fprintf (dmpout, "{%s:%s:%s}",
+ ffeintrin_name_generic (s->generic),
+ ffeintrin_name_specific (s->specific),
+ ffeintrin_name_implementation (s->implementation));
+}
+#endif
+
+/* Produce generic error message about a symbol.
+
+ For now, just output error message using symbol's name and pointing to
+ the token. */
+
+void
+ffesymbol_error (ffesymbol s, ffelexToken t)
+{
+ if ((t != NULL)
+ && ffest_ffebad_start (FFEBAD_SYMERR))
+ {
+ ffebad_string (ffesymbol_text (s));
+ ffebad_here (0, ffelex_token_where_line (t),
+ ffelex_token_where_column (t));
+ ffebad_here (1, ffesymbol_where_line (s), ffesymbol_where_column (s));
+ ffebad_finish ();
+ }
+
+ if (ffesymbol_attr (s, FFESYMBOL_attrANY))
+ return;
+
+ ffesymbol_signal_change (s); /* May need to back up to previous version. */
+ if ((ffesymbol_attrs (s) & FFESYMBOL_attrsCBLOCK)
+ || (ffesymbol_kind (s) == FFEINFO_kindNAMELIST))
+ ffebld_end_list (ffesymbol_ptr_to_listbottom (s));
+ ffesymbol_set_attr (s, FFESYMBOL_attrANY);
+ ffesymbol_set_info (s, ffeinfo_new_any ());
+ ffesymbol_set_state (s, FFESYMBOL_stateUNDERSTOOD);
+ if (s->check_state == FFESYMBOL_checkstatePENDING_)
+ ffelex_token_kill (s->check_token);
+ s->check_state = FFESYMBOL_checkstateCHECKED_;
+ s = ffecom_sym_learned (s);
+ ffesymbol_signal_unreported (s);
+}
+
+void
+ffesymbol_init_0 ()
+{
+ ffesymbolAttrs attrs = FFESYMBOL_attrsetNONE;
+
+ assert (FFESYMBOL_state == ARRAY_SIZE (ffesymbol_state_name_));
+ assert (FFESYMBOL_attr == ARRAY_SIZE (ffesymbol_attr_name_));
+ assert (attrs == FFESYMBOL_attrsetNONE);
+ attrs = ((ffesymbolAttrs) 1 << FFESYMBOL_attr);
+ assert (attrs != 0);
+}
+
+void
+ffesymbol_init_1 ()
+{
+#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalFILE_
+ ffesymbol_global_ = ffename_space_new (ffe_pool_file ());
+#endif
+}
+
+void
+ffesymbol_init_2 ()
+{
+}
+
+void
+ffesymbol_init_3 ()
+{
+#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_
+ ffesymbol_global_ = ffename_space_new (ffe_pool_program_unit ());
+#endif
+ ffesymbol_local_ = ffename_space_new (ffe_pool_program_unit ());
+}
+
+void
+ffesymbol_init_4 ()
+{
+ ffesymbol_sfunc_ = ffename_space_new (ffe_pool_program_unit ());
+}
+
+/* Look up a local entity.
+
+ Retrieves the ffesymbol for the specified local entity, or returns NULL
+ if no local entity by that name exists. */
+
+ffesymbol
+ffesymbol_lookup_local (ffelexToken t)
+{
+ ffename n;
+ ffesymbol s;
+
+ assert (t != NULL);
+
+ n = ffename_lookup (ffesymbol_local_, t);
+ if (n == NULL)
+ return NULL;
+
+ s = ffename_symbol (n);
+ return s; /* May be NULL here, too. */
+}
+
+/* Registers the symbol as one that is referenced by the
+ current program unit. Currently applies only to
+ symbols known to have global interest (globals and
+ intrinsics).
+
+ s is the (global/intrinsic) symbol referenced; t is the
+ referencing token; explicit is TRUE if the reference
+ is, e.g., INTRINSIC FOO. */
+
+void
+ffesymbol_reference (ffesymbol s, ffelexToken t, bool explicit)
+{
+ ffename gn;
+ ffesymbol gs = NULL;
+ ffeinfoKind kind;
+ ffeinfoWhere where;
+ bool okay;
+
+ if (ffesymbol_retractable_)
+ return;
+
+ if (t == NULL)
+ t = ffename_token (s->name); /* Use the first reference in this program unit. */
+
+ kind = ffesymbol_kind (s);
+ where = ffesymbol_where (s);
+
+ if (where == FFEINFO_whereINTRINSIC)
+ {
+ ffeglobal_ref_intrinsic (s, t,
+ explicit
+ || s->explicit_where
+ || ffeintrin_is_standard (s->generic, s->specific));
+ return;
+ }
+
+ if ((where != FFEINFO_whereGLOBAL)
+ && ((where != FFEINFO_whereLOCAL)
+ || ((kind != FFEINFO_kindFUNCTION)
+ && (kind != FFEINFO_kindSUBROUTINE))))
+ return;
+
+ gn = ffename_lookup (ffesymbol_global_, t);
+ if (gn != NULL)
+ gs = ffename_symbol (gn);
+ if ((gs != NULL) && (gs != s))
+ {
+ /* We have just discovered another global symbol with the same name
+ but a different `nature'. Complain. Note that COMMON /FOO/ can
+ coexist with local symbol FOO, e.g. local variable, just not with
+ CALL FOO, hence the separate namespaces. */
+
+ ffesymbol_error (gs, t);
+ ffesymbol_error (s, NULL);
+ return;
+ }
+
+ switch (kind)
+ {
+ case FFEINFO_kindBLOCKDATA:
+ okay = ffeglobal_ref_blockdata (s, t);
+ break;
+
+ case FFEINFO_kindSUBROUTINE:
+ okay = ffeglobal_ref_subroutine (s, t);
+ break;
+
+ case FFEINFO_kindFUNCTION:
+ okay = ffeglobal_ref_function (s, t);
+ break;
+
+ case FFEINFO_kindNONE:
+ okay = ffeglobal_ref_external (s, t);
+ break;
+
+ default:
+ assert ("bad kind in global ref" == NULL);
+ return;
+ }
+
+ if (! okay)
+ ffesymbol_error (s, NULL);
+}
+
+/* Report info on the symbol for debugging purposes. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ffesymbol
+ffesymbol_report (ffesymbol s)
+{
+ ffeinfoKind k;
+ ffeinfoWhere w;
+
+ assert (s != NULL);
+
+ if (s->reported)
+ return s;
+
+ s->reported = TRUE;
+
+ if (ffeinfo_size (s->info) != FFETARGET_charactersizeNONE)
+ fprintf (dmpout, "\"%s\": %s %s %d%s%s*%" ffetargetCharacterSize_f "u",
+ ffesymbol_text (s),
+ ffesymbol_state_string (s->state),
+ ffesymbol_attrs_string (s->attrs),
+ (int) ffeinfo_rank (s->info),
+ ffeinfo_basictype_string (ffeinfo_basictype (s->info)),
+ ffeinfo_kindtype_string (ffeinfo_kindtype (s->info)),
+ ffeinfo_size (s->info));
+ else
+ fprintf (dmpout, "\"%s\": %s %s %d%s%s",
+ ffesymbol_text (s),
+ ffesymbol_state_string (s->state),
+ ffesymbol_attrs_string (s->attrs),
+ (int) ffeinfo_rank (s->info),
+ ffeinfo_basictype_string (ffeinfo_basictype (s->info)),
+ ffeinfo_kindtype_string (ffeinfo_kindtype (s->info)));
+ if ((k = ffeinfo_kind (s->info)) != FFEINFO_kindNONE)
+ fprintf (dmpout, "/%s", ffeinfo_kind_string (k));
+ if ((w = ffeinfo_where (s->info)) != FFEINFO_whereNONE)
+ fprintf (dmpout, "@%s", ffeinfo_where_string (w));
+ fputc ('\n', dmpout);
+
+ if (s->dims != NULL)
+ {
+ fprintf (dmpout, " dims: ");
+ ffebld_dump (s->dims);
+ fputs ("\n", dmpout);
+ }
+
+ if (s->extents != NULL)
+ {
+ fprintf (dmpout, " extents: ");
+ ffebld_dump (s->extents);
+ fputs ("\n", dmpout);
+ }
+
+ if (s->dim_syms != NULL)
+ {
+ fprintf (dmpout, " dim syms: ");
+ ffebld_dump (s->dim_syms);
+ fputs ("\n", dmpout);
+ }
+
+ if (s->array_size != NULL)
+ {
+ fprintf (dmpout, " array size: ");
+ ffebld_dump (s->array_size);
+ fputs ("\n", dmpout);
+ }
+
+ if (s->init != NULL)
+ {
+ fprintf (dmpout, " init-value: ");
+ if (ffebld_op (s->init) == FFEBLD_opANY)
+ fputs ("<any>\n", dmpout);
+ else
+ {
+ ffebld_dump (s->init);
+ fputs ("\n", dmpout);
+ }
+ }
+
+ if (s->accretion != NULL)
+ {
+ fprintf (dmpout, " accretion (%" ffetargetOffset_f "d left): ",
+ s->accretes);
+ ffebld_dump (s->accretion);
+ fputs ("\n", dmpout);
+ }
+ else if (s->accretes != 0)
+ fprintf (dmpout, " accretes!! = %" ffetargetOffset_f "d left\n",
+ s->accretes);
+
+ if (s->dummy_args != NULL)
+ {
+ fprintf (dmpout, " dummies: ");
+ ffebld_dump (s->dummy_args);
+ fputs ("\n", dmpout);
+ }
+
+ if (s->namelist != NULL)
+ {
+ fprintf (dmpout, " namelist: ");
+ ffebld_dump (s->namelist);
+ fputs ("\n", dmpout);
+ }
+
+ if (s->common_list != NULL)
+ {
+ fprintf (dmpout, " common-list: ");
+ ffebld_dump (s->common_list);
+ fputs ("\n", dmpout);
+ }
+
+ if (s->sfunc_expr != NULL)
+ {
+ fprintf (dmpout, " sfunc expression: ");
+ ffebld_dump (s->sfunc_expr);
+ fputs ("\n", dmpout);
+ }
+
+ if (s->is_save)
+ {
+ fprintf (dmpout, " SAVEd\n");
+ }
+
+ if (s->is_init)
+ {
+ fprintf (dmpout, " initialized\n");
+ }
+
+ if (s->do_iter)
+ {
+ fprintf (dmpout, " DO-loop iteration variable (currently)\n");
+ }
+
+ if (s->explicit_where)
+ {
+ fprintf (dmpout, " Explicit INTRINSIC/EXTERNAL\n");
+ }
+
+ if (s->namelisted)
+ {
+ fprintf (dmpout, " Namelisted\n");
+ }
+
+ if (s->common != NULL)
+ {
+ fprintf (dmpout, " COMMON area: %s\n", ffesymbol_text (s->common));
+ }
+
+ if (s->equiv != NULL)
+ {
+ fprintf (dmpout, " EQUIVALENCE information: ");
+ ffeequiv_dump (s->equiv);
+ fputs ("\n", dmpout);
+ }
+
+ if (s->storage != NULL)
+ {
+ fprintf (dmpout, " Storage: ");
+ ffestorag_dump (s->storage);
+ fputs ("\n", dmpout);
+ }
+
+ return s;
+}
+#endif
+
+/* Report info on the symbols. */
+
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void
+ffesymbol_report_all ()
+{
+ ffename_space_drive_symbol (ffesymbol_sfunc_, ffesymbol_report);
+ ffename_space_drive_symbol (ffesymbol_local_, ffesymbol_report);
+ ffename_space_drive_symbol (ffesymbol_global_, ffesymbol_report);
+}
+#endif
+
+/* Resolve symbol that has become known intrinsic or non-intrinsic. */
+
+void
+ffesymbol_resolve_intrin (ffesymbol s)
+{
+ char c;
+ ffebad bad;
+
+ if (!ffesrc_check_symbol ())
+ return;
+ if (s->check_state != FFESYMBOL_checkstatePENDING_)
+ return;
+ if (ffebad_inhibit ())
+ return; /* We'll get back to this later. */
+
+ if (ffesymbol_where (s) != FFEINFO_whereINTRINSIC)
+ {
+ bad = ffesymbol_check_token_ (s->check_token, &c);
+ assert (bad != FFEBAD); /* How did this suddenly become ok? */
+ ffesymbol_whine_state_ (bad, s->check_token, c);
+ }
+
+ s->check_state = FFESYMBOL_checkstateCHECKED_;
+ ffelex_token_kill (s->check_token);
+}
+
+/* Retract or cancel retract list. */
+
+void
+ffesymbol_retract (bool retract)
+{
+ ffesymbolRetract_ r;
+ ffename name;
+ ffename other_space_name;
+ ffesymbol ls;
+ ffesymbol os;
+
+ assert (ffesymbol_retractable_);
+
+ ffesymbol_retractable_ = FALSE;
+
+ for (r = ffesymbol_retract_first_; r != NULL; r = r->next)
+ {
+ ls = r->live;
+ os = r->symbol;
+ switch (r->command)
+ {
+ case FFESYMBOL_retractcommandDELETE_:
+ if (retract)
+ {
+ ffecom_sym_retract (ls);
+ name = ls->name;
+ other_space_name = ls->other_space_name;
+ ffesymbol_unhook_ (ls);
+ malloc_kill_ks (FFESYMBOL_SPACE_POOL_, ls, sizeof (*ls));
+ if (name != NULL)
+ ffename_set_symbol (name, NULL);
+ if (other_space_name != NULL)
+ ffename_set_symbol (other_space_name, NULL);
+ }
+ else
+ {
+ ffecom_sym_commit (ls);
+ ls->have_old = FALSE;
+ }
+ break;
+
+ case FFESYMBOL_retractcommandRETRACT_:
+ if (retract)
+ {
+ ffecom_sym_retract (ls);
+ ffesymbol_unhook_ (ls);
+ *ls = *os;
+ malloc_kill_ks (FFESYMBOL_SPACE_POOL_, os, sizeof (*os));
+ }
+ else
+ {
+ ffecom_sym_commit (ls);
+ ffesymbol_unhook_ (os);
+ malloc_kill_ks (FFESYMBOL_SPACE_POOL_, os, sizeof (*os));
+ ls->have_old = FALSE;
+ }
+ break;
+
+ default:
+ assert ("bad command" == NULL);
+ break;
+ }
+ }
+}
+
+/* Return retractable flag. */
+
+bool
+ffesymbol_retractable ()
+{
+ return ffesymbol_retractable_;
+}
+
+/* Set retractable flag, retract pool.
+
+ Between this call and ffesymbol_retract, any changes made to existing
+ symbols cause the previous versions of those symbols to be saved, and any
+ newly created symbols to have their previous nonexistence saved. When
+ ffesymbol_retract is called, this information either is used to retract
+ the changes and new symbols, or is discarded. */
+
+void
+ffesymbol_set_retractable (mallocPool pool)
+{
+ assert (!ffesymbol_retractable_);
+
+ ffesymbol_retractable_ = TRUE;
+ ffesymbol_retract_pool_ = pool;
+ ffesymbol_retract_list_ = &ffesymbol_retract_first_;
+ ffesymbol_retract_first_ = NULL;
+}
+
+/* Existing symbol about to be changed; save?
+
+ Call this function before changing a symbol if it is possible that
+ the current actions may need to be undone (i.e. one of several possible
+ statement forms are being used to analyze the current system).
+
+ If the "retractable" flag is not set, just return.
+ Else, if the symbol's "have_old" flag is set, just return.
+ Else, make a copy of the symbol and add it to the "retract" list, set
+ the "have_old" flag, and return. */
+
+void
+ffesymbol_signal_change (ffesymbol s)
+{
+ ffesymbolRetract_ r;
+ ffesymbol sym;
+
+ if (!ffesymbol_retractable_ || s->have_old)
+ return;
+
+ r = (ffesymbolRetract_) malloc_new_kp (ffesymbol_retract_pool_,
+ "FFESYMBOL retract", sizeof (*r));
+ r->next = NULL;
+ r->command = FFESYMBOL_retractcommandRETRACT_;
+ r->live = s;
+ r->symbol = sym = (ffesymbol) malloc_new_ks (FFESYMBOL_SPACE_POOL_,
+ "FFESYMBOL", sizeof (*sym));
+ *sym = *s; /* Make an exact copy of the symbol in case
+ we need it back. */
+ sym->info = ffeinfo_use (s->info);
+ if (s->check_state == FFESYMBOL_checkstatePENDING_)
+ sym->check_token = ffelex_token_use (s->check_token);
+
+ *ffesymbol_retract_list_ = r;
+ ffesymbol_retract_list_ = &r->next;
+
+ s->have_old = TRUE;
+}
+
+/* Returns the string based on the state. */
+
+char *
+ffesymbol_state_string (ffesymbolState state)
+{
+ if (state >= ARRAY_SIZE (ffesymbol_state_name_))
+ return "?\?\?";
+ return ffesymbol_state_name_[state];
+}
+
+void
+ffesymbol_terminate_0 ()
+{
+}
+
+void
+ffesymbol_terminate_1 ()
+{
+#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalFILE_
+ ffename_space_drive_symbol (ffesymbol_global_, ffesymbol_unhook_);
+ ffename_space_kill (ffesymbol_global_);
+ ffesymbol_global_ = NULL;
+
+ ffesymbol_kill_manifest_ ();
+#endif
+}
+
+void
+ffesymbol_terminate_2 ()
+{
+#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_
+ ffesymbol_kill_manifest_ ();
+#endif
+}
+
+void
+ffesymbol_terminate_3 ()
+{
+#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_
+ ffename_space_drive_symbol (ffesymbol_global_, ffesymbol_unhook_);
+ ffename_space_kill (ffesymbol_global_);
+#endif
+ ffename_space_drive_symbol (ffesymbol_local_, ffesymbol_unhook_);
+ ffename_space_kill (ffesymbol_local_);
+#if FFESYMBOL_globalCURRENT_ == FFESYMBOL_globalPROGUNIT_
+ ffesymbol_global_ = NULL;
+#endif
+ ffesymbol_local_ = NULL;
+}
+
+void
+ffesymbol_terminate_4 ()
+{
+ ffename_space_drive_symbol (ffesymbol_sfunc_, ffesymbol_unhook_);
+ ffename_space_kill (ffesymbol_sfunc_);
+ ffesymbol_sfunc_ = NULL;
+}
+
+/* Update INIT info to TRUE and all equiv/storage too.
+
+ If INIT flag is TRUE, does nothing. Else sets it to TRUE and calls
+ on the ffeequiv and ffestorag modules to update their INIT flags if
+ the <s> symbol has those objects, and also updates the common area if
+ it exists. */
+
+void
+ffesymbol_update_init (ffesymbol s)
+{
+ ffebld item;
+
+ if (s->is_init)
+ return;
+
+ s->is_init = TRUE;
+
+ if ((s->equiv != NULL)
+ && !ffeequiv_is_init (s->equiv))
+ ffeequiv_update_init (s->equiv);
+
+ if ((s->storage != NULL)
+ && !ffestorag_is_init (s->storage))
+ ffestorag_update_init (s->storage);
+
+ if ((s->common != NULL)
+ && (!ffesymbol_is_init (s->common)))
+ ffesymbol_update_init (s->common);
+
+ for (item = s->common_list; item != NULL; item = ffebld_trail (item))
+ {
+ if (!ffesymbol_is_init (ffebld_symter (ffebld_head (item))))
+ ffesymbol_update_init (ffebld_symter (ffebld_head (item)));
+ }
+}
+
+/* Update SAVE info to TRUE and all equiv/storage too.
+
+ If SAVE flag is TRUE, does nothing. Else sets it to TRUE and calls
+ on the ffeequiv and ffestorag modules to update their SAVE flags if
+ the <s> symbol has those objects, and also updates the common area if
+ it exists. */
+
+void
+ffesymbol_update_save (ffesymbol s)
+{
+ ffebld item;
+
+ if (s->is_save)
+ return;
+
+ s->is_save = TRUE;
+
+ if ((s->equiv != NULL)
+ && !ffeequiv_is_save (s->equiv))
+ ffeequiv_update_save (s->equiv);
+
+ if ((s->storage != NULL)
+ && !ffestorag_is_save (s->storage))
+ ffestorag_update_save (s->storage);
+
+ if ((s->common != NULL)
+ && (!ffesymbol_is_save (s->common)))
+ ffesymbol_update_save (s->common);
+
+ for (item = s->common_list; item != NULL; item = ffebld_trail (item))
+ {
+ if (!ffesymbol_is_save (ffebld_symter (ffebld_head (item))))
+ ffesymbol_update_save (ffebld_symter (ffebld_head (item)));
+ }
+}
diff --git a/contrib/gcc/f/symbol.def b/contrib/gcc/f/symbol.def
new file mode 100644
index 0000000..343f80e
--- /dev/null
+++ b/contrib/gcc/f/symbol.def
@@ -0,0 +1,654 @@
+/* Definitions and documentations for attributes used in GNU F77 compiler
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+/* "How g77 learns about symbols"
+
+ There are three primary things in a symbol that g77 uses to keep
+ track of what it has learned about that symbol:
+
+ 1. The state
+ 2. The attributes
+ 3. The info
+
+ State, attributes, and info (see f-info* files) all start out with
+ "NONE" fields when a symbol is first created.
+
+ In a PROGRAM or BLOCK DATA program unit, info where cannot be DUMMY
+ or RESULT. Any combinations including those possibilities are not
+ considered possible in such program units.
+
+ As soon as a symbol is created, it _must_ have its state changed to
+ SEEN, UNCERTAIN, or UNDERSTOOD.
+
+ If SEEN, some info might be set, such as the type info (as in when
+ the TYPE attribute is present) or kind/where info.
+
+ If UNCERTAIN, the permitted combinations of attributes and info are
+ listed below. Only the attributes ACTUALARG, ADJUSTABLE, ANYLEN, ARRAY,
+ DUMMY, EXTERNAL, SFARG, and TYPE are permitted. (All these attributes
+ are contrasted to each attribute below, even though some combinations
+ wouldn't be permitted in SEEN state either.) Note that DUMMY and
+ RESULT are not permitted in a PROGRAM/BLOCKDATA program unit, which
+ results in some of the combinations below not occurring (not UNCERTAIN,
+ but UNDERSTOOD).
+
+ ANYLEN|TYPE & ~(ACTUALARG|ADJUSTABLE|ARRAY|DUMMY|EXTERNAL|SFARG):
+ ENTITY/DUMMY, ENTITY/RESULT, FUNCTION/INTRINSIC.
+
+ ARRAY & ~(ACTUALARG|ANYLEN|DUMMY|EXTERNAL|SFARG|TYPE):
+ ENTITY/DUMMY, ENTITY/LOCAL.
+
+ ARRAY|TYPE & ~(ACTUALARG|ANYLEN|DUMMY|EXTERNAL|SFARG):
+ ENTITY/DUMMY, ENTITY/LOCAL.
+
+ DUMMY & ~(ACTUALARG|ADJUSTABLE|ANYLEN|ARRAY|EXTERNAL|SFARG|TYPE):
+ ENTITY/DUMMY, FUNCTION/DUMMY, SUBROUTINE/DUMMY.
+
+ DUMMY|TYPE & ~(ACTUALARG|ADJUSTABLE|ANYLEN|ARRAY|EXTERNAL|SFARG):
+ ENTITY/DUMMY, FUNCTION/DUMMY.
+
+ EXTERNAL & ~(ACTUALARG|ADJUSTABLE|ANYLEN|ARRAY|DUMMY|SFARG|TYPE):
+ FUNCTION/DUMMY, FUNCTION/GLOBAL, SUBROUTINE/DUMMY,
+ SUBROUTINE/GLOBAL, BLOCKDATA/GLOBAL.
+
+ EXTERNAL|ACTUALARG & ~(ADJUSTABLE|ANYLEN|ARRAY|DUMMY|SFARG|TYPE):
+ FUNCTION/GLOBAL, SUBROUTINE/GLOBAL.
+
+ EXTERNAL|DUMMY & ~(ACTUALARG|ADJUSTABLE|ANYLEN|ARRAY|SFARG|TYPE):
+ FUNCTION/DUMMY, SUBROUTINE/DUMMY.
+
+ EXTERNAL|TYPE & ~(ACTUALARG|ADJUSTABLE|ANYLEN|ARRAY|DUMMY|SFARG):
+ FUNCTION/DUMMY, FUNCTION/GLOBAL.
+
+ SFARG & ~(ACTUALARG|ADJUSTABLE|ANYLEN|ARRAY|DUMMY|EXTERNAL|TYPE):
+ ENTITY/DUMMY, ENTITY/LOCAL.
+
+ SFARG|TYPE & ~(ACTUALARG|ADJUSTABLE|ANYLEN|ARRAY|DUMMY|EXTERNAL):
+ ENTITY/DUMMY, ENTITY/LOCAL.
+
+ TYPE & ~(ACTUALARG|ANYLEN|ARRAY|DUMMY|EXTERNAL|SFARG):
+ ENTITY/DUMMY, ENTITY/LOCAL, ENTITY/RESULT, FUNCTION/DUMMY,
+ FUNCTION/GLOBAL, FUNCTION/INTRINSIC.
+
+ If UNDERSTOOD, the attributes are no longer considered, and the info
+ field is considered to be as fully filled in as possible by analyzing
+ a single program unit.
+
+ Each of the attributes (used only for SEEN/UNCERTAIN states) is
+ defined and described below. In many cases, a symbol starts out as
+ SEEN and has attributes set as it is seen in various contexts prior
+ to the first executable statement being seen (the "exec transition").
+ Once that happens, either it becomes immediately UNDERSTOOD and all
+ its info filled in, or it becomes UNCERTAIN and its info only partially
+ filled in until it becomes UNDERSTOOD. While UNCERTAIN, only a
+ subset of attributes are possible/important.
+
+ Not all symbols reach the UNDERSTOOD state, and in some cases symbols
+ go immediately from NONE to the UNDERSTOOD or even UNCERTAIN state.
+ For example, given "PROGRAM FOO", everything is known about the name
+ "FOO", so it becomes immediately UNDERSTOOD.
+
+ Also, there are multiple name spaces, and not all attributes are
+ possible/permitted in all name spaces.
+
+ The only attributes permitted in the global name space are:
+
+ ANY, CBLOCK, SAVECBLOCK.
+
+ The only attributes permitted in the local name space are:
+
+ ANY, ACTUALARG, ADJUSTABLE, ADJUSTS, ANYLEN, ANYSIZE, ARRAY, COMMON,
+ DUMMY, EQUIV, EXTERNAL, INIT, INTRINSIC, NAMELIST, RESULT, SAVE, SFARG,
+ SFUNC, TYPE.
+
+ In the stmt-func name space, no attributes are used, just the states.
+
+*/
+
+
+/* Actual argument. Always accompanied by EXTERNAL.
+
+ Context is a name used as an actual argument passed to a procedure
+ other than a statement function.
+
+ Valid in UNCERTAIN state and local name space only.
+
+ This attribute is used only to flag the fact that an EXTERNAL'ed name
+ has been seen as an actual argument, and therefore cannot be
+ discovered later to be a DUMMY argument (via an ENTRY statement).
+
+ If DUMMY + EXTERNAL already, it is permitted to see the name
+ as an actual argument, but ACTUALARG is not added as an attribute since
+ that fact does not improve knowledge about the name. Hence it is not
+ permitted to transition ACTUALARG + EXTERNAL += DUMMY, and the
+ transition DUMMY + EXTERNAL += ACTUALARG is not actually done.
+
+ Cannot be combined with: ANYLEN, ARRAY, DUMMY, SFARG, TYPE.
+
+ Can be combined with: ACTUALARG, ANY, EXTERNAL.
+
+ Unrelated: ADJUSTABLE, ADJUSTS, ANYSIZE, CBLOCK, COMMON, EQUIV, INIT,
+ INTRINSIC, NAMELIST, RESULT, SAVE, SAVECBLOCK, SFUNC.
+
+*/
+
+DEFATTR (FFESYMBOL_attrACTUALARG, FFESYMBOL_attrsACTUALARG, "ACTUALARG")
+#ifndef FFESYMBOL_attrsACTUALARG
+#define FFESYMBOL_attrsACTUALARG ((ffesymbolAttrs) 1 << FFESYMBOL_attrACTUALARG)
+#endif
+
+/* Has adjustable dimension(s). Always accompanied by ARRAY.
+
+ Context is an ARRAY-attributed name with an adjustable dimension (at
+ least one dimension containing a variable reference).
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADJUSTABLE, ADJUSTS, COMMON, EQUIV, EXTERNAL,
+ NAMELIST, INIT, INTRINSIC, RESULT, SAVE, SFARG, SFUNC.
+
+ Can be combined with: ANY, ANYLEN, ANYSIZE, ARRAY, TYPE.
+
+ Must be combined with: DUMMY.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrADJUSTABLE, FFESYMBOL_attrsADJUSTABLE, "ADJUSTABLE")
+#ifndef FFESYMBOL_attrsADJUSTABLE
+#define FFESYMBOL_attrsADJUSTABLE ((ffesymbolAttrs) 1 << FFESYMBOL_attrADJUSTABLE)
+#endif
+
+/* Adjusts an array.
+
+ Context is an expression in an array declarator, such as in a
+ DIMENSION, COMMON, or type-specification statement.
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADJUSTABLE, ANYLEN, ANYSIZE, ARRAY,
+ EXTERNAL, INTRINSIC, RESULT, SAVE, SFUNC.
+
+ Can be combined with: ADJUSTS, ANY, COMMON, DUMMY, EQUIV, INIT,
+ NAMELIST, SFARG, TYPE.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrADJUSTS, FFESYMBOL_attrsADJUSTS, "ADJUSTS")
+#ifndef FFESYMBOL_attrsADJUSTS
+#define FFESYMBOL_attrsADJUSTS ((ffesymbolAttrs) 1 << FFESYMBOL_attrADJUSTS)
+#endif
+
+/* Can be anything now, diagnostic has been issued at least once.
+
+ Valid in UNDERSTOOD state only. Valid in any name space.
+
+ Can be combined with anything.
+
+*/
+
+DEFATTR (FFESYMBOL_attrANY, FFESYMBOL_attrsANY, "ANY")
+#ifndef FFESYMBOL_attrsANY
+#define FFESYMBOL_attrsANY ((ffesymbolAttrs) 1 << FFESYMBOL_attrANY)
+#endif
+
+/* Assumed (any) length. Always accompanied by TYPE.
+
+ Context is a name listed in a CHARACTER statement and given a length
+ specification of (*).
+
+ Valid in SEEN and UNCERTAIN states. Valid in local name space only.
+
+ In SEEN state, attributes marked below with "=" are unrelated.
+
+ In UNCERTAIN state, attributes marked below with "+" are unrelated,
+ attributes marked below with "-" cannot be combined with ANYLEN,
+ and attributes marked below with "!" transition to state UNDERSTOOD
+ instead of acquiring the new attribute. Any other subsequent mentioning
+ of the name transitions to state UNDERSTOOD. UNCERTAIN state is not
+ valid for this attribute in PROGRAM/BLOCKDATA program unit.
+
+ Cannot be combined with: ACTUALARG=, ADJUSTS+, ANYLEN, COMMON+, EQUIV+,
+ EXTERNAL, INIT+, INTRINSIC+, NAMELIST+, SAVE+, SFARG, SFUNC+.
+
+ Can be combined with: ADJUSTABLE+, ANY, ANYSIZE+, ARRAY-, DUMMY!, RESULT+,
+ TYPE.
+
+ Unrelated: CBLOCK, SAVECBLOCK.
+
+ In PROGRAM/BLOCKDATA, cannot be combined with ARRAY.
+
+*/
+
+DEFATTR (FFESYMBOL_attrANYLEN, FFESYMBOL_attrsANYLEN, "ANYLEN")
+#ifndef FFESYMBOL_attrsANYLEN
+#define FFESYMBOL_attrsANYLEN ((ffesymbolAttrs) 1 << FFESYMBOL_attrANYLEN)
+#endif
+
+/* Has assumed (any) size. Always accompanied by ARRAY.
+
+ Context is an ARRAY-attributed name with its last dimension having
+ an upper bound of "*".
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADJUSTS, ANYSIZE, COMMON, EQUIV, EXTERNAL,
+ NAMELIST, INIT, INTRINSIC, RESULT, SAVE, SFARG, SFUNC.
+
+ Can be combined with: ADJUSTABLE, ANY, ANYLEN, ARRAY, TYPE.
+
+ Must be combined with: DUMMY.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrANYSIZE, FFESYMBOL_attrsANYSIZE, "ANYSIZE")
+#ifndef FFESYMBOL_attrsANYSIZE
+#define FFESYMBOL_attrsANYSIZE ((ffesymbolAttrs) 1 << FFESYMBOL_attrANYSIZE)
+#endif
+
+/* Array.
+
+ Context is a name followed by an array declarator, such as in a
+ type-statement-decl, a DIMENSION statement, or a COMMON statement.
+
+ Valid in SEEN and UNCERTAIN states. Valid in local name space only.
+
+ In SEEN state, attributes marked below with "=" are unrelated.
+
+ In UNCERTAIN state, attributes marked below with "+" are unrelated,
+ attributes marked below with "-" cannot be combined with ARRAY,
+ and attributes marked below with "!" transition to state UNDERSTOOD
+ instead of acquiring the new attribute. Any other subsequent mentioning
+ of the name transitions to state UNDERSTOOD. UNCERTAIN state is not
+ valid for this attribute in PROGRAM/BLOCKDATA program unit.
+
+ Cannot be combined with: ACTUALARG=, ADJUSTS+, ARRAY, EXTERNAL,
+ INTRINSIC+, RESULT+, SFARG, SFUNC+.
+
+ Can be combined with: ADJUSTABLE+, ANY, ANYLEN-, ANYSIZE+, COMMON+,
+ DUMMY!, EQUIV+, INIT+, NAMELIST+, SAVE+, TYPE.
+
+ Unrelated: CBLOCK, SAVECBLOCK.
+
+ In PROGRAM/BLOCKDATA, cannot be combined with ANYLEN.
+ Cannot follow INIT.
+
+*/
+
+DEFATTR (FFESYMBOL_attrARRAY, FFESYMBOL_attrsARRAY, "ARRAY")
+#ifndef FFESYMBOL_attrsARRAY
+#define FFESYMBOL_attrsARRAY ((ffesymbolAttrs) 1 << FFESYMBOL_attrARRAY)
+#endif
+
+/* COMMON block.
+
+ Context is a name enclosed in slashes in a COMMON statement.
+
+ Valid in SEEN state and global name space only.
+
+ Cannot be combined with:
+
+ Can be combined with: CBLOCK, SAVECBLOCK.
+
+ Unrelated: ACTUALARG, ADJUSTABLE, ADJUSTS, ANY, ANYLEN, ANYSIZE,
+ ARRAY, COMMON, DUMMY, EQUIV, EXTERNAL, INIT, INTRINSIC, NAMELIST,
+ RESULT, SAVE, SFARG, SFUNC, TYPE.
+
+*/
+
+DEFATTR (FFESYMBOL_attrCBLOCK, FFESYMBOL_attrsCBLOCK, "CBLOCK")
+#ifndef FFESYMBOL_attrsCBLOCK
+#define FFESYMBOL_attrsCBLOCK ((ffesymbolAttrs) 1 << FFESYMBOL_attrCBLOCK)
+#endif
+
+/* Placed in COMMON.
+
+ Context is a name listed in a COMMON statement but not enclosed in
+ slashes.
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADJUSTABLE, ANYLEN, ANYSIZE, COMMON, DUMMY,
+ EXTERNAL, INTRINSIC, RESULT, SAVE, SFUNC.
+
+ Can be combined with: ADJUSTS, ANY, ARRAY, EQUIV, INIT, NAMELIST,
+ SFARG, TYPE.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrCOMMON, FFESYMBOL_attrsCOMMON, "COMMON")
+#ifndef FFESYMBOL_attrsCOMMON
+#define FFESYMBOL_attrsCOMMON ((ffesymbolAttrs) 1 << FFESYMBOL_attrCOMMON)
+#endif
+
+/* Dummy argument.
+
+ Context is a name listed in the arglist of FUNCTION, SUBROUTINE, ENTRY.
+ (Statement-function definitions have dummy arguments, but since they're
+ the only possible entities in the statement-function name space, this
+ attribution mechanism isn't used for them.)
+
+ Valid in SEEN and UNCERTAIN states. Valid in local name space only.
+
+ In SEEN state, attributes marked below with "=" are unrelated.
+
+ In UNCERTAIN state, attributes marked below with "+" are unrelated,
+ attributes marked below with "-" cannot be combined with DUMMY,
+ and attributes marked below with "!" transition to state UNDERSTOOD
+ instead of acquiring the new attribute. Any other subsequent mentioning
+ of the name transitions to state UNDERSTOOD. UNCERTAIN state is not
+ valid for this attribute in PROGRAM/BLOCKDATA program unit.
+
+ Cannot be combined with: ACTUALARG=, COMMON+, EQUIV+, INIT+, INTRINSIC+,
+ NAMELIST+, RESULT+, SAVE+, SFUNC+.
+
+ Can be combined with: ADJUSTABLE+, ADJUSTS+, ANY, ANYLEN-, ANYSIZE+,
+ ARRAY-, DUMMY, EXTERNAL, SFARG-, TYPE.
+
+ Unrelated: CBLOCK, SAVECBLOCK.
+
+ VXT Fortran disallows DUMMY + NAMELIST.
+ F90 allows DUMMY + NAMELIST (with some restrictions), g77 doesn't yet.
+
+*/
+
+DEFATTR (FFESYMBOL_attrDUMMY, FFESYMBOL_attrsDUMMY, "DUMMY")
+#ifndef FFESYMBOL_attrsDUMMY
+#define FFESYMBOL_attrsDUMMY ((ffesymbolAttrs) 1 << FFESYMBOL_attrDUMMY)
+#endif
+
+/* EQUIVALENCE'd.
+
+ Context is a name given in an EQUIVALENCE statement.
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADJUSTABLE, ANYLEN, ANYSIZE, DUMMY,
+ EXTERNAL, INTRINSIC, RESULT, SFUNC.
+
+ Can be combined with: ADJUSTS, ANY, ARRAY, COMMON, EQUIV, INIT,
+ NAMELIST, SAVE, SFARG, TYPE.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrEQUIV, FFESYMBOL_attrsEQUIV, "EQUIV")
+#ifndef FFESYMBOL_attrsEQUIV
+#define FFESYMBOL_attrsEQUIV ((ffesymbolAttrs) 1 << FFESYMBOL_attrEQUIV)
+#endif
+
+/* EXTERNAL.
+
+ Context is a name listed in an EXTERNAL statement.
+
+ Valid in SEEN and UNCERTAIN states. Valid in local name space only.
+
+ In SEEN state, attributes marked below with "=" are unrelated.
+
+ In UNCERTAIN state, attributes marked below with "+" are unrelated,
+ attributes marked below with "-" cannot be combined with EXTERNAL,
+ and attributes marked below with "!" transition to state UNDERSTOOD
+ instead of acquiring the new attribute. Many other subsequent mentionings
+ of the name transitions to state UNDERSTOOD. UNCERTAIN state is not
+ valid for this attribute in PROGRAM/BLOCKDATA program unit.
+
+ Cannot be combined with: ADJUSTABLE+, ADJUSTS+, ANYLEN, ANYSIZE+,
+ ARRAY, COMMON+, EQUIV+, EXTERNAL, INIT+, INTRINSIC+, NAMELIST+, RESULT+,
+ SAVE+, SFARG, SFUNC+.
+
+ Can be combined with: ACTUALARG=, ANY, DUMMY, TYPE.
+
+ Unrelated: CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrEXTERNAL, FFESYMBOL_attrsEXTERNAL, "EXTERNAL")
+#ifndef FFESYMBOL_attrsEXTERNAL
+#define FFESYMBOL_attrsEXTERNAL ((ffesymbolAttrs) 1 << FFESYMBOL_attrEXTERNAL)
+#endif
+
+/* Given an initial value.
+
+ Context is a name listed in a type-def-stmt such as INTEGER or REAL
+ and given an initial value or values. Someday will also include
+ names in DATA statements, which currently immediately exec-transition
+ their targets.
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADJUSTABLE, ANYLEN, ANYSIZE, DUMMY, EXTERNAL,
+ INIT, INTRINSIC, RESULT, SFUNC.
+
+ Can be combined with: ADJUSTS, ANY, ARRAY, COMMON, EQUIV, NAMELIST,
+ SAVE, SFARG, TYPE.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+ Cannot be followed by ARRAY.
+
+*/
+
+DEFATTR (FFESYMBOL_attrINIT, FFESYMBOL_attrsINIT, "INIT")
+#ifndef FFESYMBOL_attrsINIT
+#define FFESYMBOL_attrsINIT ((ffesymbolAttrs) 1 << FFESYMBOL_attrINIT)
+#endif
+
+/* INTRINSIC.
+
+ Context is a name listed in an INTRINSIC statement.
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADJUSTABLE, ADJUSTS, ANYLEN, ANYSIZE, ARRAY,
+ COMMON, DUMMY, EQUIV, EXTERNAL, INIT, INTRINSIC, NAMELIST, RESULT,
+ SAVE, SFARG, SFUNC.
+
+ Can be combined with: ANY, TYPE.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrINTRINSIC, FFESYMBOL_attrsINTRINSIC, "INTRINSIC")
+#ifndef FFESYMBOL_attrsINTRINSIC
+#define FFESYMBOL_attrsINTRINSIC ((ffesymbolAttrs) 1 << FFESYMBOL_attrINTRINSIC)
+#endif
+
+/* NAMELISTed.
+
+ Context is a name listed in a NAMELIST statement but not enclosed in
+ slashes.
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADJUSTABLE, ANYLEN, ANYSIZE, DUMMY, EXTERNAL,
+ INTRINSIC, RESULT, SFUNC.
+
+ Can be combined with: ADJUSTS, ANY, ARRAY, COMMON, EQUIV, INIT,
+ NAMELIST, SAVE, SFARG, TYPE.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrNAMELIST, FFESYMBOL_attrsNAMELIST, "NAMELIST")
+#ifndef FFESYMBOL_attrsNAMELIST
+#define FFESYMBOL_attrsNAMELIST ((ffesymbolAttrs) 1 << FFESYMBOL_attrNAMELIST)
+#endif
+
+/* RESULT of a function.
+
+ Context is name in RESULT() clause in FUNCTION or ENTRY statement, or
+ the name in a FUNCTION or ENTRY statement (within a FUNCTION subprogram)
+ that has no RESULT() clause.
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADJUSTABLE, ADJUSTS, ANYSIZE, ARRAY, COMMON,
+ DUMMY, EQUIV, EXTERNAL, INIT, INTRINSIC, NAMELIST, RESULT, SAVE, SFUNC.
+
+ Can be combined with: ANY, ANYLEN, SFARG, TYPE.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+ Cannot be preceded by SFARG.
+
+*/
+
+DEFATTR (FFESYMBOL_attrRESULT, FFESYMBOL_attrsRESULT, "RESULT")
+#ifndef FFESYMBOL_attrsRESULT
+#define FFESYMBOL_attrsRESULT ((ffesymbolAttrs) 1 << FFESYMBOL_attrRESULT)
+#endif
+
+/* SAVEd (not enclosed in slashes).
+
+ Context is a name listed in a SAVE statement but not enclosed in slashes.
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADUSTABLE, ADJUSTS, ANYLEN, ANYSIZE, COMMON,
+ DUMMY, EXTERNAL, INTRINSIC, RESULT, SAVE, SFUNC.
+
+ Can be combined with: ANY, ARRAY, EQUIV, INIT, NAMELIST,
+ SFARG, TYPE.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrSAVE, FFESYMBOL_attrsSAVE, "SAVE")
+#ifndef FFESYMBOL_attrsSAVE
+#define FFESYMBOL_attrsSAVE ((ffesymbolAttrs) 1 << FFESYMBOL_attrSAVE)
+#endif
+
+/* SAVEd (enclosed in slashes).
+
+ Context is a name enclosed in slashes in a SAVE statement.
+
+ Valid in SEEN state and global name space only.
+
+ Cannot be combined with: SAVECBLOCK.
+
+ Can be combined with: CBLOCK.
+
+ Unrelated: ACTUALARG, ADJUSTABLE, ADJUSTS, ANY, ANYLEN, ANYSIZE,
+ ARRAY, COMMON, DUMMY, EQUIV, EXTERNAL, INIT, INTRINSIC, NAMELIST,
+ RESULT, SAVE, SFARG, SFUNC, TYPE.
+
+*/
+
+DEFATTR (FFESYMBOL_attrSAVECBLOCK, FFESYMBOL_attrsSAVECBLOCK, "SAVECBLOCK")
+#ifndef FFESYMBOL_attrsSAVECBLOCK
+#define FFESYMBOL_attrsSAVECBLOCK ((ffesymbolAttrs) 1 << FFESYMBOL_attrSAVECBLOCK)
+#endif
+
+/* Name used as a statement function arg or DATA implied-DO iterator.
+
+ Context is a name listed in the arglist of statement-function-definition
+ or as the iterator in an implied-DO construct in a DATA statement.
+
+ Valid in SEEN and UNCERTAIN states. Valid in local name space only.
+
+ In SEEN state, attributes marked below with "=" are unrelated.
+
+ In UNCERTAIN state, attributes marked below with "+" are unrelated,
+ attributes marked below with "-" cannot be combined with SFARG,
+ and attributes marked below with "!" transition to state UNDERSTOOD
+ instead of acquiring the new attribute. Any other subsequent mentioning
+ of the name transitions to state UNDERSTOOD. UNCERTAIN state is not
+ valid for this attribute in PROGRAM/BLOCKDATA program unit.
+
+ Cannot be combined with: ACTUALARG=, ADJUSTABLE+, ANYLEN, ANYSIZE+,
+ ARRAY, EXTERNAL, INTRINSIC+, SFUNC+.
+
+ Can be combined with: ADJUSTS+, ANY, COMMON+, DUMMY!, EQUIV+, INIT+,
+ NAMELIST+, RESULT+, SAVE+, SFARG, TYPE.
+
+ Unrelated: CBLOCK, SAVECBLOCK.
+
+ Cannot be followed by RESULT.
+
+*/
+
+DEFATTR (FFESYMBOL_attrSFARG, FFESYMBOL_attrsSFARG, "SFARG")
+#ifndef FFESYMBOL_attrsSFARG
+#define FFESYMBOL_attrsSFARG ((ffesymbolAttrs) 1 << FFESYMBOL_attrSFARG)
+#endif
+
+/* Statement function name.
+
+ Context is a statement-function-definition statement, the name being
+ defined.
+
+ Valid in SEEN state and local name space only.
+
+ Cannot be combined with: ADJUSTABLE, ADJUSTS, ANYLEN, ANYSIZE, ARRAY,
+ COMMON, DUMMY, EQUIV, EXTERNAL, INIT, INTRINSIC, NAMELIST, RESULT,
+ SAVE, SFARG, SFUNC.
+
+ Can be combined with: ANY, TYPE.
+
+ Unrelated: ACTUALARG, CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrSFUNC, FFESYMBOL_attrsSFUNC, "SFUNC")
+#ifndef FFESYMBOL_attrsSFUNC
+#define FFESYMBOL_attrsSFUNC ((ffesymbolAttrs) 1 << FFESYMBOL_attrSFUNC)
+#endif
+
+/* Explicitly typed.
+
+ Context is a name listed in a type-def-stmt such as INTEGER or REAL.
+
+ Valid in SEEN and UNCERTAIN states. Valid in local name space only.
+
+ In SEEN state, attributes marked below with "=" are unrelated.
+
+ In UNCERTAIN state, attributes marked below with "+" are unrelated,
+ attributes marked below with "-" cannot be combined with TYPE,
+ and attributes marked below with "!" transition to state UNDERSTOOD
+ instead of acquiring the new attribute. Many other subsequent mentionings
+ of the name transitions to state UNDERSTOOD. UNCERTAIN state is not
+ valid for this attribute in PROGRAM/BLOCKDATA program unit.
+
+ Cannot be combined with: ACTUALARG=, TYPE.
+
+ Can be combined with: ADJUSTABLE+, ADJUSTS+, ANY, ANYLEN, ANYSIZE+,
+ ARRAY, COMMON+, DUMMY, EQUIV+, EXTERNAL, INIT+, INTRINSIC+, NAMELIST+,
+ RESULT+, SAVE+, SFARG, SFUNC+.
+
+ Unrelated: CBLOCK, SAVECBLOCK.
+
+*/
+
+DEFATTR (FFESYMBOL_attrTYPE, FFESYMBOL_attrsTYPE, "TYPE")
+#ifndef FFESYMBOL_attrsTYPE
+#define FFESYMBOL_attrsTYPE ((ffesymbolAttrs) 1 << FFESYMBOL_attrTYPE)
+#endif
diff --git a/contrib/gcc/f/symbol.h b/contrib/gcc/f/symbol.h
new file mode 100644
index 0000000..b534ae6
--- /dev/null
+++ b/contrib/gcc/f/symbol.h
@@ -0,0 +1,293 @@
+/* Interface definitions for Fortran symbol manager
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef _H_f_symbol
+#define _H_f_symbol
+
+/* The main symbol type. */
+
+typedef struct _ffesymbol_ *ffesymbol;
+
+/* State of understanding about what the symbol represents. */
+
+enum _ffesymbol_state_
+ {
+/* See ffesymbol_state_is_exec() macro below when making changes. */
+ FFESYMBOL_stateNONE, /* Never before seen. */
+ FFESYMBOL_stateSEEN, /* Seen before exec transition and not yet
+ understood (info not filled in, etc). */
+ FFESYMBOL_stateUNCERTAIN, /* Almost understood (info partly filled in). */
+ FFESYMBOL_stateUNDERSTOOD, /* Fully understood (info filled in). */
+ FFESYMBOL_state
+ };
+typedef enum _ffesymbol_state_ ffesymbolState;
+#define ffesymbolState_f ""
+
+/* Attributes. Symbols acquire attributes while their state is SEEN.
+ These attributes are basically ignored once the symbol becomes
+ UNDERSTOOD. */
+
+typedef long int ffesymbolAttrs;/* Holds set of attributes. */
+#define ffesymbolAttrs_f "l"
+
+enum _ffesymbol_attr_
+ {
+#define DEFATTR(ATTR,ATTRS,NAME) ATTR,
+#include "symbol.def"
+#undef DEFATTR
+ FFESYMBOL_attr
+ }; /* A given attribute. */
+typedef enum _ffesymbol_attr_ ffesymbolAttr;
+#define ffesymbolAttr_f ""
+
+#define FFESYMBOL_attrsetNONE 0
+#define FFESYMBOL_attrsetALL (((ffesymbolAttrs) 1 << FFESYMBOL_attr) - 1)
+
+/* This is just for avoiding complaining about, e.g., "I = IABS(3)", that
+ IABS doesn't meet the requirements for a user-defined symbol name as
+ a result of, say, --symbol-case-lower, if IABS turns out to indeed be
+ a reference to the intrinsic IABS (in which case it's a Fortran keyword
+ like CALL) and not a user-defined name. */
+
+enum _ffesymbol_checkstate_
+ {
+ FFESYMBOL_checkstateNONE_, /* Not checked/never necessary to check. */
+ FFESYMBOL_checkstateINHIBITED_, /* Bad name, but inhibited. */
+ FFESYMBOL_checkstatePENDING_, /* Bad name, might be intrinsic. */
+ FFESYMBOL_checkstateCHECKED_, /* Ok name, intrinsic, or bad name
+ reported. */
+ FFESYMBOL_checkstate_
+ };
+typedef enum _ffesymbol_checkstate_ ffesymbolCheckState_;
+#define ffesymbolCheckState_f_ ""
+
+#include "bld.h"
+#include "com.h"
+#include "equiv.h"
+#include "global.h"
+#include "info.h"
+#include "intrin.h"
+#include "lex.h"
+#include "malloc.h"
+#include "name.h"
+#include "storag.h"
+#include "target.h"
+#include "top.h"
+#include "where.h"
+
+struct _ffesymbol_
+ {
+ ffename name;
+ ffename other_space_name; /* For dual-space objects. */
+ ffeglobal global; /* In filewide name space. */
+ ffesymbolAttrs attrs; /* What kind of symbol am I? */
+ ffesymbolState state; /* What state am I in? */
+ ffeinfo info; /* Info filled in when _stateUNDERSTOOD. */
+ ffebld dims; /* Dimension list expression. */
+ ffebld extents; /* Extents list expression. */
+ ffebld dim_syms; /* List of SYMTERs of all symbols in dims. */
+ ffebld array_size; /* Size as an expression involving some of
+ dims. */
+ ffebld init; /* Initialization expression or expr list or
+ PARAMETER value. */
+ ffebld accretion; /* Initializations seen so far for
+ array/substr. */
+ ffetargetOffset accretes; /* # inits needed to fill entire array. */
+ ffebld dummy_args; /* For functions, subroutines, and entry
+ points. */
+ ffebld namelist; /* List of symbols in NML. */
+ ffebld common_list; /* List of entities in BCB/NCB. */
+ ffebld sfunc_expr; /* SFN's expression. */
+ ffebldListBottom list_bottom; /* For BCB, NCB, NML. */
+ ffesymbol common; /* Who is my containing COMMON area? */
+ ffeequiv equiv; /* Who have I been equivalenced with? */
+ ffestorag storage; /* Where am I in relation to my outside
+ world? */
+#ifdef FFECOM_symbolHOOK
+ ffecomSymbol hook; /* Whatever the compiler/backend wants! */
+#endif
+ ffesymbol sfa_dummy_parent; /* "X" outside sfunc "CIRC(X) = 3.14 * X". */
+ ffesymbol func_result; /* FUN sym's corresponding RES sym, & vice
+ versa. */
+ ffetargetIntegerDefault value; /* IMMEDIATE (DATA impdo) value. */
+ ffesymbolCheckState_ check_state; /* Valid name? */
+ ffelexToken check_token; /* checkstatePENDING_ only. */
+ int max_entry_num; /* For detecting dummy arg listed twice/IMPDO
+ iterator nesting violation; also for id of
+ sfunc dummy arg. */
+ int num_entries; /* Number of entry points in which this
+ symbol appears as a dummy arg; helps
+ determine whether arg might not be passed,
+ for example. */
+ ffeintrinGen generic; /* Generic intrinsic id, if any. */
+ ffeintrinSpec specific; /* Specific intrinsic id, if any. */
+ ffeintrinImp implementation;/* Implementation id, if any. */
+ bool is_save; /* SAVE flag set for this symbol (see also
+ ffe_is_saveall()). */
+ bool is_init; /* INIT flag set for this symbol. */
+ bool do_iter; /* Is currently a DO-loop iter (can't be
+ changed in loop). */
+ bool reported; /* (Debug) TRUE if the latest version has
+ been reported. */
+ bool have_old; /* TRUE if old copy of this symbol saved
+ away. */
+ bool explicit_where; /* TRUE if INTRINSIC/EXTERNAL explicit. */
+ bool namelisted; /* TRUE if in NAMELIST (needs static alloc). */
+ };
+
+#define ffesymbol_accretes(s) ((s)->accretes)
+#define ffesymbol_accretion(s) ((s)->accretion)
+#define ffesymbol_arraysize(s) ((s)->array_size)
+#define ffesymbol_attr(s,a) ((s)->attrs & ((ffesymbolAttrs) 1 << (a)))
+#define ffesymbol_attrs(s) ((s)->attrs)
+char *ffesymbol_attrs_string (ffesymbolAttrs attrs);
+#define ffesymbol_basictype(s) ffeinfo_basictype((s)->info)
+void ffesymbol_check (ffesymbol s, ffelexToken t, bool maybe_intrin);
+#define ffesymbol_common(s) ((s)->common)
+#define ffesymbol_commonlist(s) ((s)->common_list)
+ffesymbol ffesymbol_declare_blockdataunit (ffelexToken t, ffewhereLine wl,
+ ffewhereColumn wc);
+ffesymbol ffesymbol_declare_cblock (ffelexToken t, ffewhereLine wl,
+ ffewhereColumn wc);
+ffesymbol ffesymbol_declare_funcnotresunit (ffelexToken t);
+ffesymbol ffesymbol_declare_funcresult (ffelexToken t);
+ffesymbol ffesymbol_declare_funcunit (ffelexToken t);
+ffesymbol ffesymbol_declare_local (ffelexToken t, bool maybe_intrin);
+ffesymbol ffesymbol_declare_programunit (ffelexToken t, ffewhereLine wl,
+ ffewhereColumn wc);
+ffesymbol ffesymbol_declare_sfdummy (ffelexToken t);
+ffesymbol ffesymbol_declare_subrunit (ffelexToken t);
+#define ffesymbol_dims(s) ((s)->dims)
+#define ffesymbol_dim_syms(s) ((s)->dim_syms)
+void ffesymbol_drive (ffesymbol (*fn) ());
+void ffesymbol_drive_sfnames (ffesymbol (*fn) ());
+#define ffesymbol_dummyargs(s) ((s)->dummy_args)
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+void ffesymbol_dump (ffesymbol s);
+#endif
+void ffesymbol_error (ffesymbol s, ffelexToken t);
+#define ffesymbol_equiv(s) ((s)->equiv)
+#define ffesymbol_explicitwhere(s) ((s)->explicit_where)
+#define ffesymbol_extents(s) ((s)->extents)
+#define ffesymbol_first_token(s) ((s)->name == NULL ? NULL \
+ : ffename_first_token((s)->name))
+#define ffesymbol_funcresult(s) ((s)->func_result)
+#define ffesymbol_generic(s) ((s)->generic)
+#define ffesymbol_global(s) ((s)->global)
+#define ffesymbol_hook(s) ((s)->hook)
+#define ffesymbol_implementation(s) ((s)->implementation)
+#define ffesymbol_info(s) ((s)->info)
+#define ffesymbol_init(s) ((s)->init)
+void ffesymbol_init_0 (void);
+void ffesymbol_init_1 (void);
+void ffesymbol_init_2 (void);
+void ffesymbol_init_3 (void);
+void ffesymbol_init_4 (void);
+#define ffesymbol_is_doiter(s) ((s)->do_iter)
+#define ffesymbol_is_dualspace(s) ((s)->other_space_name != NULL)
+#define ffesymbol_is_f2c(s) (ffe_is_f2c())
+#define ffesymbol_is_init(s) ((s)->is_init)
+#define ffesymbol_is_reported(s) ((s)->reported)
+#define ffesymbol_is_save(s) ((s)->is_save)
+#define ffesymbol_is_specable(s) ffesymbol_state_is_specable(s->state)
+#define ffesymbol_kindtype(s) ffeinfo_kindtype((s)->info)
+#define ffesymbol_kind(s) ffeinfo_kind((s)->info)
+ffesymbol ffesymbol_lookup_local (ffelexToken t);
+#define ffesymbol_maxentrynum(s) ((s)->max_entry_num)
+#define ffesymbol_name(s) ((s)->name)
+#define ffesymbol_namelist(s) ((s)->namelist)
+#define ffesymbol_namelisted(s) ((s)->namelisted)
+#define ffesymbol_numentries(s) ((s)->num_entries)
+#define ffesymbol_ptr_to_commonlist(s) (&(s)->common_list)
+#define ffesymbol_ptr_to_listbottom(s) (&(s)->list_bottom)
+#define ffesymbol_ptr_to_namelist(s) (&(s)->namelist)
+#define ffesymbol_rank(s) ffeinfo_rank((s)->info)
+void ffesymbol_reference (ffesymbol s, ffelexToken t, bool explicit);
+#if FFECOM_targetCURRENT == FFECOM_targetFFE
+ffesymbol ffesymbol_report (ffesymbol s);
+void ffesymbol_report_all (void);
+#endif
+void ffesymbol_resolve_intrin (ffesymbol s);
+void ffesymbol_retract (bool retract);
+bool ffesymbol_retractable (void);
+#define ffesymbol_set_accretes(s,a) ((s)->accretes = (a))
+#define ffesymbol_set_accretion(s,a) ((s)->accretion = (a))
+#define ffesymbol_set_arraysize(s,a) ((s)->array_size = (a))
+#define ffesymbol_set_attr(s,a) ((s)->attrs |= ((ffesymbolAttrs) 1 << (a)))
+#define ffesymbol_set_attrs(s,a) ((s)->attrs = (a))
+#define ffesymbol_set_common(s,c) ((s)->common = (c))
+#define ffesymbol_set_commonlist(s,c) ((s)->common_list = (c))
+#define ffesymbol_set_dims(s,d) ((s)->dims = (d))
+#define ffesymbol_set_dim_syms(s,d) ((s)->dim_syms = (d))
+#define ffesymbol_set_dummyargs(s,d) ((s)->dummy_args = (d))
+#define ffesymbol_set_equiv(s,e) ((s)->equiv = (e))
+#define ffesymbol_set_explicitwhere(s,e) ((s)->explicit_where = (e))
+#define ffesymbol_set_extents(s,e) ((s)->extents = (e))
+#define ffesymbol_set_funcresult(s,f) ((s)->func_result = (f))
+#define ffesymbol_set_generic(s,g) ((s)->generic = (g))
+#define ffesymbol_set_global(s,g) ((s)->global = (g))
+#define ffesymbol_set_hook(s,h) ((s)->hook = (h))
+#define ffesymbol_set_implementation(s,im) ((s)->implementation = (im))
+#define ffesymbol_set_init(s,i) ((s)->init = (i))
+#define ffesymbol_set_info(s,i) ((s)->info = (i))
+#define ffesymbol_set_is_doiter(s,f) ((s)->do_iter = (f))
+#define ffesymbol_set_is_init(s,in) ((s)->is_init = (in))
+#define ffesymbol_set_is_save(s,sa) ((s)->is_save = (sa))
+#define ffesymbol_set_maxentrynum(s,m) ((s)->max_entry_num = (m))
+#define ffesymbol_set_namelist(s,n) ((s)->namelist = (n))
+#define ffesymbol_set_namelisted(s,n) ((s)->namelisted = (n))
+#define ffesymbol_set_numentries(s,n) ((s)->num_entries = (n))
+void ffesymbol_set_retractable (mallocPool pool);
+#define ffesymbol_set_sfexpr(s,e) ((s)->sfunc_expr = (e))
+#define ffesymbol_set_specific(s,sp) ((s)->specific = (sp))
+#define ffesymbol_set_state(s,st) ((s)->state = (st))
+#define ffesymbol_set_storage(s,st) ((s)->storage = (st))
+#define ffesymbol_set_value(s,v) ((s)->value = (v))
+#define ffesymbol_sfdummyparent(s) ((s)->sfa_dummy_parent)
+#define ffesymbol_sfexpr(s) ((s)->sfunc_expr)
+void ffesymbol_signal_change (ffesymbol s);
+#define ffesymbol_signal_unreported(s) ((s)->reported = FALSE)
+#define ffesymbol_size(s) ffeinfo_size((s)->info)
+#define ffesymbol_specific(s) ((s)->specific)
+#define ffesymbol_state(s) ((s)->state)
+#define ffesymbol_state_is_specable(s) ((s) <= FFESYMBOL_stateSEEN)
+char *ffesymbol_state_string (ffesymbolState state);
+#define ffesymbol_storage(s) ((s)->storage)
+void ffesymbol_terminate_0 (void);
+void ffesymbol_terminate_1 (void);
+void ffesymbol_terminate_2 (void);
+void ffesymbol_terminate_3 (void);
+void ffesymbol_terminate_4 (void);
+#define ffesymbol_text(s) (((s)->name == NULL) ? "<->" : ffename_text((s)->name))
+void ffesymbol_update_init (ffesymbol s);
+void ffesymbol_update_save (ffesymbol s);
+#define ffesymbol_value(s) ((s)->value)
+#define ffesymbol_where(s) ffeinfo_where((s)->info)
+#define ffesymbol_where_column(s) (((s)->name == NULL) \
+ ? ffewhere_column_unknown() : ffename_where_column((s)->name))
+#define ffesymbol_where_filename(s) \
+ ffewhere_line_filename(ffesymbol_where_line(s))
+#define ffesymbol_where_filelinenum(s) \
+ ffewhere_line_filelinenum(ffesymbol_where_line(s))
+#define ffesymbol_where_line(s) (((s)->name == NULL) ? ffewhere_line_unknown() \
+ : ffename_where_line((s)->name))
+
+#endif
diff --git a/contrib/gcc/f/system.j b/contrib/gcc/f/system.j
new file mode 100644
index 0000000..6a37324
--- /dev/null
+++ b/contrib/gcc/f/system.j
@@ -0,0 +1,27 @@
+/* system.j -- Wrapper for GCC's system.h
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_system
+#define _J_f_system
+#include "system.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/target.c b/contrib/gcc/f/target.c
new file mode 100644
index 0000000..5de05ff
--- /dev/null
+++ b/contrib/gcc/f/target.c
@@ -0,0 +1,2564 @@
+/* target.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995-1998 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None
+
+ Description:
+ Implements conversion of lexer tokens to machine-dependent numerical
+ form and accordingly issues diagnostic messages when necessary.
+
+ Also, this module, especially its .h file, provides nearly all of the
+ information on the target machine's data type, kind type, and length
+ type capabilities. The idea is that by carefully going through
+ target.h and changing things properly, one can accomplish much
+ towards the porting of the FFE to a new machine. There are limits
+ to how much this can accomplish towards that end, however. For one
+ thing, the ffeexpr_collapse_convert function doesn't contain all the
+ conversion cases necessary, because the text file would be
+ enormous (even though most of the function would be cut during the
+ cpp phase because of the absence of the types), so when adding to
+ the number of supported kind types for a given type, one must look
+ to see if ffeexpr_collapse_convert needs modification in this area,
+ in addition to providing the appropriate macros and functions in
+ ffetarget. Note that if combinatorial explosion actually becomes a
+ problem for a given machine, one might have to modify the way conversion
+ expressions are built so that instead of just one conversion expr, a
+ series of conversion exprs are built to make a path from one type to
+ another that is not a "near neighbor". For now, however, with a handful
+ of each of the numeric types and only one character type, things appear
+ manageable.
+
+ A nonobvious change to ffetarget would be if the target machine was
+ not a 2's-complement machine. Any item with the word "magical" (case-
+ insensitive) in the FFE's source code (at least) indicates an assumption
+ that a 2's-complement machine is the target, and thus that there exists
+ a magnitude that can be represented as a negative number but not as
+ a positive number. It is possible that this situation can be dealt
+ with by changing only ffetarget, for example, on a 1's-complement
+ machine, perhaps #defineing ffetarget_constant_is_magical to simply
+ FALSE along with making the appropriate changes in ffetarget's number
+ parsing functions would be sufficient to effectively "comment out" code
+ in places like ffeexpr that do certain magical checks. But it is
+ possible there are other 2's-complement dependencies lurking in the
+ FFE (as possibly is true of any large program); if you find any, please
+ report them so we can replace them with dependencies on ffetarget
+ instead.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "glimits.j"
+#include "target.h"
+#include "bad.h"
+#include "info.h"
+#include "lex.h"
+#include "malloc.h"
+
+/* Externals defined here. */
+
+char ffetarget_string_[40]; /* Temp for ascii-to-double (atof). */
+HOST_WIDE_INT ffetarget_long_val_;
+HOST_WIDE_INT ffetarget_long_junk_;
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+static void ffetarget_print_char_ (FILE *f, unsigned char c);
+
+/* Internal macros. */
+
+#ifdef REAL_VALUE_ATOF
+#define FFETARGET_ATOF_(p,m) REAL_VALUE_ATOF ((p),(m))
+#else
+#define FFETARGET_ATOF_(p,m) atof ((p))
+#endif
+
+
+/* ffetarget_print_char_ -- Print a single character (in apostrophe context)
+
+ See prototype.
+
+ Outputs char so it prints or is escaped C style. */
+
+static void
+ffetarget_print_char_ (FILE *f, unsigned char c)
+{
+ switch (c)
+ {
+ case '\\':
+ fputs ("\\\\", f);
+ break;
+
+ case '\'':
+ fputs ("\\\'", f);
+ break;
+
+ default:
+ if (ISPRINT (c))
+ fputc (c, f);
+ else
+ fprintf (f, "\\%03o", (unsigned int) c);
+ break;
+ }
+}
+
+/* ffetarget_aggregate_info -- Determine type for aggregate storage area
+
+ See prototype.
+
+ If aggregate type is distinct, just return it. Else return a type
+ representing a common denominator for the nondistinct type (for now,
+ just return default character, since that'll work on almost all target
+ machines).
+
+ The rules for abt/akt are (as implemented by ffestorag_update):
+
+ abt == FFEINFO_basictypeANY (akt == FFEINFO_kindtypeANY also, by
+ definition): CHARACTER and non-CHARACTER types mixed.
+
+ abt == FFEINFO_basictypeNONE (akt == FFEINFO_kindtypeNONE also, by
+ definition): More than one non-CHARACTER type mixed, but no CHARACTER
+ types mixed in.
+
+ abt some other value, akt == FFEINFO_kindtypeNONE: abt indicates the
+ only basic type mixed in, but more than one kind type is mixed in.
+
+ abt some other value, akt some other value: abt and akt indicate the
+ only type represented in the aggregation. */
+
+void
+ffetarget_aggregate_info (ffeinfoBasictype *ebt, ffeinfoKindtype *ekt,
+ ffetargetAlign *units, ffeinfoBasictype abt,
+ ffeinfoKindtype akt)
+{
+ ffetype type;
+
+ if ((abt == FFEINFO_basictypeNONE) || (abt == FFEINFO_basictypeANY)
+ || (akt == FFEINFO_kindtypeNONE))
+ {
+ *ebt = FFEINFO_basictypeCHARACTER;
+ *ekt = FFEINFO_kindtypeCHARACTERDEFAULT;
+ }
+ else
+ {
+ *ebt = abt;
+ *ekt = akt;
+ }
+
+ type = ffeinfo_type (*ebt, *ekt);
+ assert (type != NULL);
+
+ *units = ffetype_size (type);
+}
+
+/* ffetarget_align -- Align one storage area to superordinate, update super
+
+ See prototype.
+
+ updated_alignment/updated_modulo contain the already existing
+ alignment requirements for the storage area at whose offset the
+ object with alignment requirements alignment/modulo is to be placed.
+ Find the smallest pad such that the requirements are maintained and
+ return it, but only after updating the updated_alignment/_modulo
+ requirements as necessary to indicate the placement of the new object. */
+
+ffetargetAlign
+ffetarget_align (ffetargetAlign *updated_alignment,
+ ffetargetAlign *updated_modulo, ffetargetOffset offset,
+ ffetargetAlign alignment, ffetargetAlign modulo)
+{
+ ffetargetAlign pad;
+ ffetargetAlign min_pad; /* Minimum amount of padding needed. */
+ ffetargetAlign min_m = 0; /* Minimum-padding m. */
+ ffetargetAlign ua; /* Updated alignment. */
+ ffetargetAlign um; /* Updated modulo. */
+ ffetargetAlign ucnt; /* Multiplier applied to ua. */
+ ffetargetAlign m; /* Copy of modulo. */
+ ffetargetAlign cnt; /* Multiplier applied to alignment. */
+ ffetargetAlign i;
+ ffetargetAlign j;
+
+ assert (alignment > 0);
+ assert (*updated_alignment > 0);
+
+ assert (*updated_modulo < *updated_alignment);
+ assert (modulo < alignment);
+
+ /* The easy case: similar alignment requirements. */
+ if (*updated_alignment == alignment)
+ {
+ if (modulo > *updated_modulo)
+ pad = alignment - (modulo - *updated_modulo);
+ else
+ pad = *updated_modulo - modulo;
+ if (offset < 0)
+ /* De-negatize offset, since % wouldn't do the expected thing. */
+ offset = alignment - ((- offset) % alignment);
+ pad = (offset + pad) % alignment;
+ if (pad != 0)
+ pad = alignment - pad;
+ return pad;
+ }
+
+ /* Sigh, find LCM (Least Common Multiple) for the two alignment factors. */
+
+ for (ua = *updated_alignment, ucnt = 1;
+ ua % alignment != 0;
+ ua += *updated_alignment)
+ ++ucnt;
+
+ cnt = ua / alignment;
+
+ if (offset < 0)
+ /* De-negatize offset, since % wouldn't do the expected thing. */
+ offset = ua - ((- offset) % ua);
+
+ /* Set to largest value. */
+ min_pad = ~(ffetargetAlign) 0;
+
+ /* Find all combinations of modulo values the two alignment requirements
+ have; pick the combination that results in the smallest padding
+ requirement. Of course, if a zero-pad requirement is encountered, just
+ use that one. */
+
+ for (um = *updated_modulo, i = 0; i < ucnt; um += *updated_alignment, ++i)
+ {
+ for (m = modulo, j = 0; j < cnt; m += alignment, ++j)
+ {
+ /* This code is similar to the "easy case" code above. */
+ if (m > um)
+ pad = ua - (m - um);
+ else
+ pad = um - m;
+ pad = (offset + pad) % ua;
+ if (pad == 0)
+ {
+ /* A zero pad means we've got something useful. */
+ *updated_alignment = ua;
+ *updated_modulo = um;
+ return 0;
+ }
+ pad = ua - pad;
+ if (pad < min_pad)
+ { /* New minimum padding value. */
+ min_pad = pad;
+ min_m = um;
+ }
+ }
+ }
+
+ *updated_alignment = ua;
+ *updated_modulo = min_m;
+ return min_pad;
+}
+
+/* Always append a null byte to the end, in case this is wanted in
+ a special case such as passing a string as a FORMAT or %REF.
+ Done to save a bit of hassle, nothing more, but it's a kludge anyway,
+ because it isn't a "feature" that is self-documenting. Use the
+ string "FFETARGET-NULL-KLUDGE" to flag anyplace you use this feature
+ in the code. */
+
+#if FFETARGET_okCHARACTER1
+bool
+ffetarget_character1 (ffetargetCharacter1 *val, ffelexToken character,
+ mallocPool pool)
+{
+ val->length = ffelex_token_length (character);
+ if (val->length == 0)
+ val->text = NULL;
+ else
+ {
+ val->text = malloc_new_kp (pool, "ffetargetCharacter1", val->length + 1);
+ memcpy (val->text, ffelex_token_text (character), val->length);
+ val->text[val->length] = '\0';
+ }
+
+ return TRUE;
+}
+
+#endif
+/* Produce orderable comparison between two constants
+
+ Compare lengths, if equal then use memcmp. */
+
+#if FFETARGET_okCHARACTER1
+int
+ffetarget_cmp_character1 (ffetargetCharacter1 l, ffetargetCharacter1 r)
+{
+ if (l.length < r.length)
+ return -1;
+ if (l.length > r.length)
+ return 1;
+ if (l.length == 0)
+ return 0;
+ return memcmp (l.text, r.text, l.length);
+}
+
+#endif
+/* ffetarget_concatenate_character1 -- Perform CONCAT op on two constants
+
+ Always append a null byte to the end, in case this is wanted in
+ a special case such as passing a string as a FORMAT or %REF.
+ Done to save a bit of hassle, nothing more, but it's a kludge anyway,
+ because it isn't a "feature" that is self-documenting. Use the
+ string "FFETARGET-NULL-KLUDGE" to flag anyplace you use this feature
+ in the code. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_concatenate_character1 (ffetargetCharacter1 *res,
+ ffetargetCharacter1 l, ffetargetCharacter1 r, mallocPool pool,
+ ffetargetCharacterSize *len)
+{
+ res->length = *len = l.length + r.length;
+ if (*len == 0)
+ res->text = NULL;
+ else
+ {
+ res->text = malloc_new_kp (pool, "ffetargetCharacter1(CONCAT)", *len + 1);
+ if (l.length != 0)
+ memcpy (res->text, l.text, l.length);
+ if (r.length != 0)
+ memcpy (res->text + l.length, r.text, r.length);
+ res->text[*len] = '\0';
+ }
+
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_eq_character1 -- Perform relational comparison on char constants
+
+ Compare lengths, if equal then use memcmp. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_eq_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r)
+{
+ assert (l.length == r.length);
+ *res = (memcmp (l.text, r.text, l.length) == 0);
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_le_character1 -- Perform relational comparison on char constants
+
+ Compare lengths, if equal then use memcmp. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_le_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r)
+{
+ assert (l.length == r.length);
+ *res = (memcmp (l.text, r.text, l.length) <= 0);
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_lt_character1 -- Perform relational comparison on char constants
+
+ Compare lengths, if equal then use memcmp. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_lt_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r)
+{
+ assert (l.length == r.length);
+ *res = (memcmp (l.text, r.text, l.length) < 0);
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_ge_character1 -- Perform relational comparison on char constants
+
+ Compare lengths, if equal then use memcmp. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_ge_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r)
+{
+ assert (l.length == r.length);
+ *res = (memcmp (l.text, r.text, l.length) >= 0);
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_gt_character1 -- Perform relational comparison on char constants
+
+ Compare lengths, if equal then use memcmp. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_gt_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r)
+{
+ assert (l.length == r.length);
+ *res = (memcmp (l.text, r.text, l.length) > 0);
+ return FFEBAD;
+}
+#endif
+
+#if FFETARGET_okCHARACTER1
+bool
+ffetarget_iszero_character1 (ffetargetCharacter1 constant)
+{
+ ffetargetCharacterSize i;
+
+ for (i = 0; i < constant.length; ++i)
+ if (constant.text[i] != 0)
+ return FALSE;
+ return TRUE;
+}
+#endif
+
+bool
+ffetarget_iszero_hollerith (ffetargetHollerith constant)
+{
+ ffetargetHollerithSize i;
+
+ for (i = 0; i < constant.length; ++i)
+ if (constant.text[i] != 0)
+ return FALSE;
+ return TRUE;
+}
+
+/* ffetarget_layout -- Do storage requirement analysis for entity
+
+ Return the alignment/modulo requirements along with the size, given the
+ data type info and the number of elements an array (1 for a scalar). */
+
+void
+ffetarget_layout (char *error_text UNUSED, ffetargetAlign *alignment,
+ ffetargetAlign *modulo, ffetargetOffset *size,
+ ffeinfoBasictype bt, ffeinfoKindtype kt,
+ ffetargetCharacterSize charsize,
+ ffetargetIntegerDefault num_elements)
+{
+ bool ok; /* For character type. */
+ ffetargetOffset numele; /* Converted from num_elements. */
+ ffetype type;
+
+ type = ffeinfo_type (bt, kt);
+ assert (type != NULL);
+
+ *alignment = ffetype_alignment (type);
+ *modulo = ffetype_modulo (type);
+ if (bt == FFEINFO_basictypeCHARACTER)
+ {
+ ok = ffetarget_offset_charsize (size, charsize, ffetype_size (type));
+#ifdef ffetarget_offset_overflow
+ if (!ok)
+ ffetarget_offset_overflow (error_text);
+#endif
+ }
+ else
+ *size = ffetype_size (type);
+
+ if ((num_elements < 0)
+ || !ffetarget_offset (&numele, num_elements)
+ || !ffetarget_offset_multiply (size, *size, numele))
+ {
+ ffetarget_offset_overflow (error_text);
+ *alignment = 1;
+ *modulo = 0;
+ *size = 0;
+ }
+}
+
+/* ffetarget_ne_character1 -- Perform relational comparison on char constants
+
+ Compare lengths, if equal then use memcmp. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_ne_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r)
+{
+ assert (l.length == r.length);
+ *res = (memcmp (l.text, r.text, l.length) != 0);
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_substr_character1 -- Perform SUBSTR op on three constants
+
+ Always append a null byte to the end, in case this is wanted in
+ a special case such as passing a string as a FORMAT or %REF.
+ Done to save a bit of hassle, nothing more, but it's a kludge anyway,
+ because it isn't a "feature" that is self-documenting. Use the
+ string "FFETARGET-NULL-KLUDGE" to flag anyplace you use this feature
+ in the code. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_substr_character1 (ffetargetCharacter1 *res,
+ ffetargetCharacter1 l,
+ ffetargetCharacterSize first,
+ ffetargetCharacterSize last, mallocPool pool,
+ ffetargetCharacterSize *len)
+{
+ if (last < first)
+ {
+ res->length = *len = 0;
+ res->text = NULL;
+ }
+ else
+ {
+ res->length = *len = last - first + 1;
+ res->text = malloc_new_kp (pool, "ffetargetCharacter1(SUBSTR)", *len + 1);
+ memcpy (res->text, l.text + first - 1, *len);
+ res->text[*len] = '\0';
+ }
+
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_cmp_hollerith -- Produce orderable comparison between two
+ constants
+
+ Compare lengths, if equal then use memcmp. */
+
+int
+ffetarget_cmp_hollerith (ffetargetHollerith l, ffetargetHollerith r)
+{
+ if (l.length < r.length)
+ return -1;
+ if (l.length > r.length)
+ return 1;
+ return memcmp (l.text, r.text, l.length);
+}
+
+ffebad
+ffetarget_convert_any_character1_ (char *res, size_t size,
+ ffetargetCharacter1 l)
+{
+ if (size <= (size_t) l.length)
+ {
+ char *p;
+ ffetargetCharacterSize i;
+
+ memcpy (res, l.text, size);
+ for (p = &l.text[0] + size, i = l.length - size;
+ i > 0;
+ ++p, --i)
+ if (*p != ' ')
+ return FFEBAD_TRUNCATING_CHARACTER;
+ }
+ else
+ {
+ memcpy (res, l.text, size);
+ memset (res + l.length, ' ', size - l.length);
+ }
+
+ return FFEBAD;
+}
+
+ffebad
+ffetarget_convert_any_hollerith_ (char *res, size_t size,
+ ffetargetHollerith l)
+{
+ if (size <= (size_t) l.length)
+ {
+ char *p;
+ ffetargetCharacterSize i;
+
+ memcpy (res, l.text, size);
+ for (p = &l.text[0] + size, i = l.length - size;
+ i > 0;
+ ++p, --i)
+ if (*p != ' ')
+ return FFEBAD_TRUNCATING_HOLLERITH;
+ }
+ else
+ {
+ memcpy (res, l.text, size);
+ memset (res + l.length, ' ', size - l.length);
+ }
+
+ return FFEBAD;
+}
+
+ffebad
+ffetarget_convert_any_typeless_ (char *res, size_t size,
+ ffetargetTypeless l)
+{
+ unsigned long long int l1;
+ unsigned long int l2;
+ unsigned int l3;
+ unsigned short int l4;
+ unsigned char l5;
+ size_t size_of;
+ char *p;
+
+ if (size >= sizeof (l1))
+ {
+ l1 = l;
+ p = (char *) &l1;
+ size_of = sizeof (l1);
+ }
+ else if (size >= sizeof (l2))
+ {
+ l2 = l;
+ p = (char *) &l2;
+ size_of = sizeof (l2);
+ l1 = l2;
+ }
+ else if (size >= sizeof (l3))
+ {
+ l3 = l;
+ p = (char *) &l3;
+ size_of = sizeof (l3);
+ l1 = l3;
+ }
+ else if (size >= sizeof (l4))
+ {
+ l4 = l;
+ p = (char *) &l4;
+ size_of = sizeof (l4);
+ l1 = l4;
+ }
+ else if (size >= sizeof (l5))
+ {
+ l5 = l;
+ p = (char *) &l5;
+ size_of = sizeof (l5);
+ l1 = l5;
+ }
+ else
+ {
+ assert ("stumped by conversion from typeless!" == NULL);
+ abort ();
+ }
+
+ if (size <= size_of)
+ {
+ int i = size_of - size;
+
+ memcpy (res, p + i, size);
+ for (; i > 0; ++p, --i)
+ if (*p != '\0')
+ return FFEBAD_TRUNCATING_TYPELESS;
+ }
+ else
+ {
+ int i = size - size_of;
+
+ memset (res, 0, i);
+ memcpy (res + i, p, size_of);
+ }
+
+ if (l1 != l)
+ return FFEBAD_TRUNCATING_TYPELESS;
+ return FFEBAD;
+}
+
+/* Always append a null byte to the end, in case this is wanted in
+ a special case such as passing a string as a FORMAT or %REF.
+ Done to save a bit of hassle, nothing more, but it's a kludge anyway,
+ because it isn't a "feature" that is self-documenting. Use the
+ string "FFETARGET-NULL-KLUDGE" to flag anyplace you use this feature
+ in the code. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_convert_character1_character1 (ffetargetCharacter1 *res,
+ ffetargetCharacterSize size,
+ ffetargetCharacter1 l,
+ mallocPool pool)
+{
+ res->length = size;
+ if (size == 0)
+ res->text = NULL;
+ else
+ {
+ res->text = malloc_new_kp (pool, "FFETARGET cvt char1", size + 1);
+ if (size <= l.length)
+ memcpy (res->text, l.text, size);
+ else
+ {
+ memcpy (res->text, l.text, l.length);
+ memset (res->text + l.length, ' ', size - l.length);
+ }
+ res->text[size] = '\0';
+ }
+
+ return FFEBAD;
+}
+
+#endif
+
+/* Always append a null byte to the end, in case this is wanted in
+ a special case such as passing a string as a FORMAT or %REF.
+ Done to save a bit of hassle, nothing more, but it's a kludge anyway,
+ because it isn't a "feature" that is self-documenting. Use the
+ string "FFETARGET-NULL-KLUDGE" to flag anyplace you use this feature
+ in the code. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_convert_character1_hollerith (ffetargetCharacter1 *res,
+ ffetargetCharacterSize size,
+ ffetargetHollerith l, mallocPool pool)
+{
+ res->length = size;
+ if (size == 0)
+ res->text = NULL;
+ else
+ {
+ res->text = malloc_new_kp (pool, "FFETARGET cvt char1", size + 1);
+ res->text[size] = '\0';
+ if (size <= l.length)
+ {
+ char *p;
+ ffetargetCharacterSize i;
+
+ memcpy (res->text, l.text, size);
+ for (p = &l.text[0] + size, i = l.length - size;
+ i > 0;
+ ++p, --i)
+ if (*p != ' ')
+ return FFEBAD_TRUNCATING_HOLLERITH;
+ }
+ else
+ {
+ memcpy (res->text, l.text, l.length);
+ memset (res->text + l.length, ' ', size - l.length);
+ }
+ }
+
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_convert_character1_integer4 -- Raw conversion.
+
+ Always append a null byte to the end, in case this is wanted in
+ a special case such as passing a string as a FORMAT or %REF.
+ Done to save a bit of hassle, nothing more, but it's a kludge anyway,
+ because it isn't a "feature" that is self-documenting. Use the
+ string "FFETARGET-NULL-KLUDGE" to flag anyplace you use this feature
+ in the code. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_convert_character1_integer4 (ffetargetCharacter1 *res,
+ ffetargetCharacterSize size,
+ ffetargetInteger4 l, mallocPool pool)
+{
+ long long int l1;
+ long int l2;
+ int l3;
+ short int l4;
+ char l5;
+ size_t size_of;
+ char *p;
+
+ if (((size_t) size) >= sizeof (l1))
+ {
+ l1 = l;
+ p = (char *) &l1;
+ size_of = sizeof (l1);
+ }
+ else if (((size_t) size) >= sizeof (l2))
+ {
+ l2 = l;
+ p = (char *) &l2;
+ size_of = sizeof (l2);
+ l1 = l2;
+ }
+ else if (((size_t) size) >= sizeof (l3))
+ {
+ l3 = l;
+ p = (char *) &l3;
+ size_of = sizeof (l3);
+ l1 = l3;
+ }
+ else if (((size_t) size) >= sizeof (l4))
+ {
+ l4 = l;
+ p = (char *) &l4;
+ size_of = sizeof (l4);
+ l1 = l4;
+ }
+ else if (((size_t) size) >= sizeof (l5))
+ {
+ l5 = l;
+ p = (char *) &l5;
+ size_of = sizeof (l5);
+ l1 = l5;
+ }
+ else
+ {
+ assert ("stumped by conversion from integer1!" == NULL);
+ abort ();
+ }
+
+ res->length = size;
+ if (size == 0)
+ res->text = NULL;
+ else
+ {
+ res->text = malloc_new_kp (pool, "FFETARGET cvt char1", size + 1);
+ res->text[size] = '\0';
+ if (((size_t) size) <= size_of)
+ {
+ int i = size_of - size;
+
+ memcpy (res->text, p + i, size);
+ for (; i > 0; ++p, --i)
+ if (*p != 0)
+ return FFEBAD_TRUNCATING_NUMERIC;
+ }
+ else
+ {
+ int i = size - size_of;
+
+ memset (res->text, 0, i);
+ memcpy (res->text + i, p, size_of);
+ }
+ }
+
+ if (l1 != l)
+ return FFEBAD_TRUNCATING_NUMERIC;
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_convert_character1_logical4 -- Raw conversion.
+
+ Always append a null byte to the end, in case this is wanted in
+ a special case such as passing a string as a FORMAT or %REF.
+ Done to save a bit of hassle, nothing more, but it's a kludge anyway,
+ because it isn't a "feature" that is self-documenting. Use the
+ string "FFETARGET-NULL-KLUDGE" to flag anyplace you use this feature
+ in the code. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_convert_character1_logical4 (ffetargetCharacter1 *res,
+ ffetargetCharacterSize size,
+ ffetargetLogical4 l, mallocPool pool)
+{
+ long long int l1;
+ long int l2;
+ int l3;
+ short int l4;
+ char l5;
+ size_t size_of;
+ char *p;
+
+ if (((size_t) size) >= sizeof (l1))
+ {
+ l1 = l;
+ p = (char *) &l1;
+ size_of = sizeof (l1);
+ }
+ else if (((size_t) size) >= sizeof (l2))
+ {
+ l2 = l;
+ p = (char *) &l2;
+ size_of = sizeof (l2);
+ l1 = l2;
+ }
+ else if (((size_t) size) >= sizeof (l3))
+ {
+ l3 = l;
+ p = (char *) &l3;
+ size_of = sizeof (l3);
+ l1 = l3;
+ }
+ else if (((size_t) size) >= sizeof (l4))
+ {
+ l4 = l;
+ p = (char *) &l4;
+ size_of = sizeof (l4);
+ l1 = l4;
+ }
+ else if (((size_t) size) >= sizeof (l5))
+ {
+ l5 = l;
+ p = (char *) &l5;
+ size_of = sizeof (l5);
+ l1 = l5;
+ }
+ else
+ {
+ assert ("stumped by conversion from logical1!" == NULL);
+ abort ();
+ }
+
+ res->length = size;
+ if (size == 0)
+ res->text = NULL;
+ else
+ {
+ res->text = malloc_new_kp (pool, "FFETARGET cvt char1", size + 1);
+ res->text[size] = '\0';
+ if (((size_t) size) <= size_of)
+ {
+ int i = size_of - size;
+
+ memcpy (res->text, p + i, size);
+ for (; i > 0; ++p, --i)
+ if (*p != 0)
+ return FFEBAD_TRUNCATING_NUMERIC;
+ }
+ else
+ {
+ int i = size - size_of;
+
+ memset (res->text, 0, i);
+ memcpy (res->text + i, p, size_of);
+ }
+ }
+
+ if (l1 != l)
+ return FFEBAD_TRUNCATING_NUMERIC;
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_convert_character1_typeless -- Raw conversion.
+
+ Always append a null byte to the end, in case this is wanted in
+ a special case such as passing a string as a FORMAT or %REF.
+ Done to save a bit of hassle, nothing more, but it's a kludge anyway,
+ because it isn't a "feature" that is self-documenting. Use the
+ string "FFETARGET-NULL-KLUDGE" to flag anyplace you use this feature
+ in the code. */
+
+#if FFETARGET_okCHARACTER1
+ffebad
+ffetarget_convert_character1_typeless (ffetargetCharacter1 *res,
+ ffetargetCharacterSize size,
+ ffetargetTypeless l, mallocPool pool)
+{
+ unsigned long long int l1;
+ unsigned long int l2;
+ unsigned int l3;
+ unsigned short int l4;
+ unsigned char l5;
+ size_t size_of;
+ char *p;
+
+ if (((size_t) size) >= sizeof (l1))
+ {
+ l1 = l;
+ p = (char *) &l1;
+ size_of = sizeof (l1);
+ }
+ else if (((size_t) size) >= sizeof (l2))
+ {
+ l2 = l;
+ p = (char *) &l2;
+ size_of = sizeof (l2);
+ l1 = l2;
+ }
+ else if (((size_t) size) >= sizeof (l3))
+ {
+ l3 = l;
+ p = (char *) &l3;
+ size_of = sizeof (l3);
+ l1 = l3;
+ }
+ else if (((size_t) size) >= sizeof (l4))
+ {
+ l4 = l;
+ p = (char *) &l4;
+ size_of = sizeof (l4);
+ l1 = l4;
+ }
+ else if (((size_t) size) >= sizeof (l5))
+ {
+ l5 = l;
+ p = (char *) &l5;
+ size_of = sizeof (l5);
+ l1 = l5;
+ }
+ else
+ {
+ assert ("stumped by conversion from typeless!" == NULL);
+ abort ();
+ }
+
+ res->length = size;
+ if (size == 0)
+ res->text = NULL;
+ else
+ {
+ res->text = malloc_new_kp (pool, "FFETARGET cvt char1", size + 1);
+ res->text[size] = '\0';
+ if (((size_t) size) <= size_of)
+ {
+ int i = size_of - size;
+
+ memcpy (res->text, p + i, size);
+ for (; i > 0; ++p, --i)
+ if (*p != 0)
+ return FFEBAD_TRUNCATING_TYPELESS;
+ }
+ else
+ {
+ int i = size - size_of;
+
+ memset (res->text, 0, i);
+ memcpy (res->text + i, p, size_of);
+ }
+ }
+
+ if (l1 != l)
+ return FFEBAD_TRUNCATING_TYPELESS;
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_divide_complex1 -- Divide function
+
+ See prototype. */
+
+#if FFETARGET_okCOMPLEX1
+ffebad
+ffetarget_divide_complex1 (ffetargetComplex1 *res, ffetargetComplex1 l,
+ ffetargetComplex1 r)
+{
+ ffebad bad;
+ ffetargetReal1 tmp1, tmp2, tmp3, tmp4;
+
+ bad = ffetarget_multiply_real1 (&tmp1, r.real, r.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp2, r.imaginary, r.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_add_real1 (&tmp3, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+
+ if (ffetarget_iszero_real1 (tmp3))
+ {
+ ffetarget_real1_zero (&(res)->real);
+ ffetarget_real1_zero (&(res)->imaginary);
+ return FFEBAD_DIV_BY_ZERO;
+ }
+
+ bad = ffetarget_multiply_real1 (&tmp1, l.real, r.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp2, l.imaginary, r.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_add_real1 (&tmp4, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_divide_real1 (&res->real, tmp4, tmp3);
+ if (bad != FFEBAD)
+ return bad;
+
+ bad = ffetarget_multiply_real1 (&tmp1, r.real, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp2, l.real, r.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_subtract_real1 (&tmp4, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_divide_real1 (&res->imaginary, tmp4, tmp3);
+
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_divide_complex2 -- Divide function
+
+ See prototype. */
+
+#if FFETARGET_okCOMPLEX2
+ffebad
+ffetarget_divide_complex2 (ffetargetComplex2 *res, ffetargetComplex2 l,
+ ffetargetComplex2 r)
+{
+ ffebad bad;
+ ffetargetReal2 tmp1, tmp2, tmp3, tmp4;
+
+ bad = ffetarget_multiply_real2 (&tmp1, r.real, r.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp2, r.imaginary, r.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_add_real2 (&tmp3, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+
+ if (ffetarget_iszero_real2 (tmp3))
+ {
+ ffetarget_real2_zero (&(res)->real);
+ ffetarget_real2_zero (&(res)->imaginary);
+ return FFEBAD_DIV_BY_ZERO;
+ }
+
+ bad = ffetarget_multiply_real2 (&tmp1, l.real, r.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp2, l.imaginary, r.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_add_real2 (&tmp4, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_divide_real2 (&res->real, tmp4, tmp3);
+ if (bad != FFEBAD)
+ return bad;
+
+ bad = ffetarget_multiply_real2 (&tmp1, r.real, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp2, l.real, r.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_subtract_real2 (&tmp4, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_divide_real2 (&res->imaginary, tmp4, tmp3);
+
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_hollerith -- Convert token to a hollerith constant
+
+ Always append a null byte to the end, in case this is wanted in
+ a special case such as passing a string as a FORMAT or %REF.
+ Done to save a bit of hassle, nothing more, but it's a kludge anyway,
+ because it isn't a "feature" that is self-documenting. Use the
+ string "FFETARGET-NULL-KLUDGE" to flag anyplace you use this feature
+ in the code. */
+
+bool
+ffetarget_hollerith (ffetargetHollerith *val, ffelexToken integer,
+ mallocPool pool)
+{
+ val->length = ffelex_token_length (integer);
+ val->text = malloc_new_kp (pool, "ffetargetHollerith", val->length + 1);
+ memcpy (val->text, ffelex_token_text (integer), val->length);
+ val->text[val->length] = '\0';
+
+ return TRUE;
+}
+
+/* ffetarget_integer_bad_magical -- Complain about a magical number
+
+ Just calls ffebad with the arguments. */
+
+void
+ffetarget_integer_bad_magical (ffelexToken t)
+{
+ ffebad_start (FFEBAD_BAD_MAGICAL);
+ ffebad_here (0, ffelex_token_where_line (t), ffelex_token_where_column (t));
+ ffebad_finish ();
+}
+
+/* ffetarget_integer_bad_magical_binary -- Complain about a magical number
+
+ Just calls ffebad with the arguments. */
+
+void
+ffetarget_integer_bad_magical_binary (ffelexToken integer,
+ ffelexToken minus)
+{
+ ffebad_start (FFEBAD_BAD_MAGICAL_BINARY);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_here (1, ffelex_token_where_line (minus),
+ ffelex_token_where_column (minus));
+ ffebad_finish ();
+}
+
+/* ffetarget_integer_bad_magical_precedence -- Complain about a magical
+ number
+
+ Just calls ffebad with the arguments. */
+
+void
+ffetarget_integer_bad_magical_precedence (ffelexToken integer,
+ ffelexToken uminus,
+ ffelexToken higher_op)
+{
+ ffebad_start (FFEBAD_BAD_MAGICAL_PRECEDENCE);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_here (1, ffelex_token_where_line (uminus),
+ ffelex_token_where_column (uminus));
+ ffebad_here (2, ffelex_token_where_line (higher_op),
+ ffelex_token_where_column (higher_op));
+ ffebad_finish ();
+}
+
+/* ffetarget_integer_bad_magical_precedence_binary -- Complain...
+
+ Just calls ffebad with the arguments. */
+
+void
+ffetarget_integer_bad_magical_precedence_binary (ffelexToken integer,
+ ffelexToken minus,
+ ffelexToken higher_op)
+{
+ ffebad_start (FFEBAD_BAD_MAGICAL_PRECEDENCE_BINARY);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_here (1, ffelex_token_where_line (minus),
+ ffelex_token_where_column (minus));
+ ffebad_here (2, ffelex_token_where_line (higher_op),
+ ffelex_token_where_column (higher_op));
+ ffebad_finish ();
+}
+
+/* ffetarget_integer1 -- Convert token to an integer
+
+ See prototype.
+
+ Token use count not affected overall. */
+
+#if FFETARGET_okINTEGER1
+bool
+ffetarget_integer1 (ffetargetInteger1 *val, ffelexToken integer)
+{
+ ffetargetInteger1 x;
+ char *p;
+ char c;
+
+ assert (ffelex_token_type (integer) == FFELEX_typeNUMBER);
+
+ p = ffelex_token_text (integer);
+ x = 0;
+
+ /* Skip past leading zeros. */
+
+ while (((c = *p) != '\0') && (c == '0'))
+ ++p;
+
+ /* Interpret rest of number. */
+
+ while (c != '\0')
+ {
+ if ((x == FFETARGET_integerALMOST_BIG_MAGICAL)
+ && (c == '0' + FFETARGET_integerFINISH_BIG_MAGICAL)
+ && (*(p + 1) == '\0'))
+ {
+ *val = (ffetargetInteger1) FFETARGET_integerBIG_MAGICAL;
+ return TRUE;
+ }
+ else if (x == FFETARGET_integerALMOST_BIG_MAGICAL)
+ {
+ if ((c > '0' + FFETARGET_integerFINISH_BIG_MAGICAL)
+ || (*(p + 1) != '\0'))
+ {
+ ffebad_start (FFEBAD_INTEGER_TOO_LARGE);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ *val = 0;
+ return FALSE;
+ }
+ }
+ else if (x > FFETARGET_integerALMOST_BIG_MAGICAL)
+ {
+ ffebad_start (FFEBAD_INTEGER_TOO_LARGE);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ *val = 0;
+ return FALSE;
+ }
+ x = x * 10 + c - '0';
+ c = *(++p);
+ };
+
+ *val = x;
+ return TRUE;
+}
+
+#endif
+/* ffetarget_integerbinary -- Convert token to a binary integer
+
+ ffetarget_integerbinary x;
+ if (ffetarget_integerdefault_8(&x,integer_token))
+ // conversion ok.
+
+ Token use count not affected overall. */
+
+bool
+ffetarget_integerbinary (ffetargetIntegerDefault *val, ffelexToken integer)
+{
+ ffetargetIntegerDefault x;
+ char *p;
+ char c;
+ bool bad_digit;
+
+ assert ((ffelex_token_type (integer) == FFELEX_typeNAME)
+ || (ffelex_token_type (integer) == FFELEX_typeNUMBER));
+
+ p = ffelex_token_text (integer);
+ x = 0;
+
+ /* Skip past leading zeros. */
+
+ while (((c = *p) != '\0') && (c == '0'))
+ ++p;
+
+ /* Interpret rest of number. */
+
+ bad_digit = FALSE;
+ while (c != '\0')
+ {
+ if ((c >= '0') && (c <= '1'))
+ c -= '0';
+ else
+ {
+ bad_digit = TRUE;
+ c = 0;
+ }
+
+#if 0 /* Don't complain about signed overflow; just
+ unsigned overflow. */
+ if ((x == FFETARGET_integerALMOST_BIG_OVERFLOW_BINARY)
+ && (c == FFETARGET_integerFINISH_BIG_OVERFLOW_BINARY)
+ && (*(p + 1) == '\0'))
+ {
+ *val = FFETARGET_integerBIG_OVERFLOW_BINARY;
+ return TRUE;
+ }
+ else
+#endif
+#if FFETARGET_integerFINISH_BIG_OVERFLOW_BINARY == 0
+ if ((x & FFETARGET_integerALMOST_BIG_OVERFLOW_BINARY) != 0)
+#else
+ if (x == FFETARGET_integerALMOST_BIG_OVERFLOW_BINARY)
+ {
+ if ((c > FFETARGET_integerFINISH_BIG_OVERFLOW_BINARY)
+ || (*(p + 1) != '\0'))
+ {
+ ffebad_start (FFEBAD_INTEGER_TOO_LARGE);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ *val = 0;
+ return FALSE;
+ }
+ }
+ else if (x > FFETARGET_integerALMOST_BIG_OVERFLOW_BINARY)
+#endif
+ {
+ ffebad_start (FFEBAD_INTEGER_TOO_LARGE);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ *val = 0;
+ return FALSE;
+ }
+ x = (x << 1) + c;
+ c = *(++p);
+ };
+
+ if (bad_digit)
+ {
+ ffebad_start (FFEBAD_INVALID_BINARY_DIGIT);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ }
+
+ *val = x;
+ return !bad_digit;
+}
+
+/* ffetarget_integerhex -- Convert token to a hex integer
+
+ ffetarget_integerhex x;
+ if (ffetarget_integerdefault_8(&x,integer_token))
+ // conversion ok.
+
+ Token use count not affected overall. */
+
+bool
+ffetarget_integerhex (ffetargetIntegerDefault *val, ffelexToken integer)
+{
+ ffetargetIntegerDefault x;
+ char *p;
+ char c;
+ bool bad_digit;
+
+ assert ((ffelex_token_type (integer) == FFELEX_typeNAME)
+ || (ffelex_token_type (integer) == FFELEX_typeNUMBER));
+
+ p = ffelex_token_text (integer);
+ x = 0;
+
+ /* Skip past leading zeros. */
+
+ while (((c = *p) != '\0') && (c == '0'))
+ ++p;
+
+ /* Interpret rest of number. */
+
+ bad_digit = FALSE;
+ while (c != '\0')
+ {
+ if ((c >= 'A') && (c <= 'F'))
+ c = c - 'A' + 10;
+ else if ((c >= 'a') && (c <= 'f'))
+ c = c - 'a' + 10;
+ else if ((c >= '0') && (c <= '9'))
+ c -= '0';
+ else
+ {
+ bad_digit = TRUE;
+ c = 0;
+ }
+
+#if 0 /* Don't complain about signed overflow; just
+ unsigned overflow. */
+ if ((x == FFETARGET_integerALMOST_BIG_OVERFLOW_HEX)
+ && (c == FFETARGET_integerFINISH_BIG_OVERFLOW_HEX)
+ && (*(p + 1) == '\0'))
+ {
+ *val = FFETARGET_integerBIG_OVERFLOW_HEX;
+ return TRUE;
+ }
+ else
+#endif
+#if FFETARGET_integerFINISH_BIG_OVERFLOW_HEX == 0
+ if (x >= FFETARGET_integerALMOST_BIG_OVERFLOW_HEX)
+#else
+ if (x == FFETARGET_integerALMOST_BIG_OVERFLOW_HEX)
+ {
+ if ((c > FFETARGET_integerFINISH_BIG_OVERFLOW_HEX)
+ || (*(p + 1) != '\0'))
+ {
+ ffebad_start (FFEBAD_INTEGER_TOO_LARGE);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ *val = 0;
+ return FALSE;
+ }
+ }
+ else if (x > FFETARGET_integerALMOST_BIG_OVERFLOW_HEX)
+#endif
+ {
+ ffebad_start (FFEBAD_INTEGER_TOO_LARGE);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ *val = 0;
+ return FALSE;
+ }
+ x = (x << 4) + c;
+ c = *(++p);
+ };
+
+ if (bad_digit)
+ {
+ ffebad_start (FFEBAD_INVALID_HEX_DIGIT);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ }
+
+ *val = x;
+ return !bad_digit;
+}
+
+/* ffetarget_integeroctal -- Convert token to an octal integer
+
+ ffetarget_integeroctal x;
+ if (ffetarget_integerdefault_8(&x,integer_token))
+ // conversion ok.
+
+ Token use count not affected overall. */
+
+bool
+ffetarget_integeroctal (ffetargetIntegerDefault *val, ffelexToken integer)
+{
+ ffetargetIntegerDefault x;
+ char *p;
+ char c;
+ bool bad_digit;
+
+ assert ((ffelex_token_type (integer) == FFELEX_typeNAME)
+ || (ffelex_token_type (integer) == FFELEX_typeNUMBER));
+
+ p = ffelex_token_text (integer);
+ x = 0;
+
+ /* Skip past leading zeros. */
+
+ while (((c = *p) != '\0') && (c == '0'))
+ ++p;
+
+ /* Interpret rest of number. */
+
+ bad_digit = FALSE;
+ while (c != '\0')
+ {
+ if ((c >= '0') && (c <= '7'))
+ c -= '0';
+ else
+ {
+ bad_digit = TRUE;
+ c = 0;
+ }
+
+#if 0 /* Don't complain about signed overflow; just
+ unsigned overflow. */
+ if ((x == FFETARGET_integerALMOST_BIG_OVERFLOW_OCTAL)
+ && (c == FFETARGET_integerFINISH_BIG_OVERFLOW_OCTAL)
+ && (*(p + 1) == '\0'))
+ {
+ *val = FFETARGET_integerBIG_OVERFLOW_OCTAL;
+ return TRUE;
+ }
+ else
+#endif
+#if FFETARGET_integerFINISH_BIG_OVERFLOW_OCTAL == 0
+ if (x >= FFETARGET_integerALMOST_BIG_OVERFLOW_OCTAL)
+#else
+ if (x == FFETARGET_integerALMOST_BIG_OVERFLOW_OCTAL)
+ {
+ if ((c > FFETARGET_integerFINISH_BIG_OVERFLOW_OCTAL)
+ || (*(p + 1) != '\0'))
+ {
+ ffebad_start (FFEBAD_INTEGER_TOO_LARGE);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ *val = 0;
+ return FALSE;
+ }
+ }
+ else if (x > FFETARGET_integerALMOST_BIG_OVERFLOW_OCTAL)
+#endif
+ {
+ ffebad_start (FFEBAD_INTEGER_TOO_LARGE);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ *val = 0;
+ return FALSE;
+ }
+ x = (x << 3) + c;
+ c = *(++p);
+ };
+
+ if (bad_digit)
+ {
+ ffebad_start (FFEBAD_INVALID_OCTAL_DIGIT);
+ ffebad_here (0, ffelex_token_where_line (integer),
+ ffelex_token_where_column (integer));
+ ffebad_finish ();
+ }
+
+ *val = x;
+ return !bad_digit;
+}
+
+/* ffetarget_multiply_complex1 -- Multiply function
+
+ See prototype. */
+
+#if FFETARGET_okCOMPLEX1
+ffebad
+ffetarget_multiply_complex1 (ffetargetComplex1 *res, ffetargetComplex1 l,
+ ffetargetComplex1 r)
+{
+ ffebad bad;
+ ffetargetReal1 tmp1, tmp2;
+
+ bad = ffetarget_multiply_real1 (&tmp1, l.real, r.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp2, l.imaginary, r.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_subtract_real1 (&res->real, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp1, l.imaginary, r.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp2, l.real, r.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_add_real1 (&res->imaginary, tmp1, tmp2);
+
+ return bad;
+}
+
+#endif
+/* ffetarget_multiply_complex2 -- Multiply function
+
+ See prototype. */
+
+#if FFETARGET_okCOMPLEX2
+ffebad
+ffetarget_multiply_complex2 (ffetargetComplex2 *res, ffetargetComplex2 l,
+ ffetargetComplex2 r)
+{
+ ffebad bad;
+ ffetargetReal2 tmp1, tmp2;
+
+ bad = ffetarget_multiply_real2 (&tmp1, l.real, r.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp2, l.imaginary, r.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_subtract_real2 (&res->real, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp1, l.imaginary, r.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp2, l.real, r.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_add_real2 (&res->imaginary, tmp1, tmp2);
+
+ return bad;
+}
+
+#endif
+/* ffetarget_power_complexdefault_integerdefault -- Power function
+
+ See prototype. */
+
+ffebad
+ffetarget_power_complexdefault_integerdefault (ffetargetComplexDefault *res,
+ ffetargetComplexDefault l,
+ ffetargetIntegerDefault r)
+{
+ ffebad bad;
+ ffetargetRealDefault tmp;
+ ffetargetRealDefault tmp1;
+ ffetargetRealDefault tmp2;
+ ffetargetRealDefault two;
+
+ if (ffetarget_iszero_real1 (l.real)
+ && ffetarget_iszero_real1 (l.imaginary))
+ {
+ ffetarget_real1_zero (&res->real);
+ ffetarget_real1_zero (&res->imaginary);
+ return FFEBAD;
+ }
+
+ if (r == 0)
+ {
+ ffetarget_real1_one (&res->real);
+ ffetarget_real1_zero (&res->imaginary);
+ return FFEBAD;
+ }
+
+ if (r < 0)
+ {
+ r = -r;
+ bad = ffetarget_multiply_real1 (&tmp1, l.real, l.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp2, l.imaginary, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_add_real1 (&tmp, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_divide_real1 (&l.real, l.real, tmp);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_divide_real1 (&l.imaginary, l.imaginary, tmp);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_uminus_real1 (&l.imaginary, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ }
+
+ ffetarget_real1_two (&two);
+
+ while ((r & 1) == 0)
+ {
+ bad = ffetarget_multiply_real1 (&tmp1, l.real, l.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp2, l.imaginary, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_subtract_real1 (&tmp, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&l.imaginary, l.real, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&l.imaginary, l.imaginary, two);
+ if (bad != FFEBAD)
+ return bad;
+ l.real = tmp;
+ r >>= 1;
+ }
+
+ *res = l;
+ r >>= 1;
+
+ while (r != 0)
+ {
+ bad = ffetarget_multiply_real1 (&tmp1, l.real, l.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp2, l.imaginary, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_subtract_real1 (&tmp, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&l.imaginary, l.real, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&l.imaginary, l.imaginary, two);
+ if (bad != FFEBAD)
+ return bad;
+ l.real = tmp;
+ if ((r & 1) == 1)
+ {
+ bad = ffetarget_multiply_real1 (&tmp1, res->real, l.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp2, res->imaginary,
+ l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_subtract_real1 (&tmp, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp1, res->imaginary, l.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real1 (&tmp2, res->real, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_add_real1 (&res->imaginary, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ res->real = tmp;
+ }
+ r >>= 1;
+ }
+
+ return FFEBAD;
+}
+
+/* ffetarget_power_complexdouble_integerdefault -- Power function
+
+ See prototype. */
+
+#if FFETARGET_okCOMPLEXDOUBLE
+ffebad
+ffetarget_power_complexdouble_integerdefault (ffetargetComplexDouble *res,
+ ffetargetComplexDouble l, ffetargetIntegerDefault r)
+{
+ ffebad bad;
+ ffetargetRealDouble tmp;
+ ffetargetRealDouble tmp1;
+ ffetargetRealDouble tmp2;
+ ffetargetRealDouble two;
+
+ if (ffetarget_iszero_real2 (l.real)
+ && ffetarget_iszero_real2 (l.imaginary))
+ {
+ ffetarget_real2_zero (&res->real);
+ ffetarget_real2_zero (&res->imaginary);
+ return FFEBAD;
+ }
+
+ if (r == 0)
+ {
+ ffetarget_real2_one (&res->real);
+ ffetarget_real2_zero (&res->imaginary);
+ return FFEBAD;
+ }
+
+ if (r < 0)
+ {
+ r = -r;
+ bad = ffetarget_multiply_real2 (&tmp1, l.real, l.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp2, l.imaginary, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_add_real2 (&tmp, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_divide_real2 (&l.real, l.real, tmp);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_divide_real2 (&l.imaginary, l.imaginary, tmp);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_uminus_real2 (&l.imaginary, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ }
+
+ ffetarget_real2_two (&two);
+
+ while ((r & 1) == 0)
+ {
+ bad = ffetarget_multiply_real2 (&tmp1, l.real, l.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp2, l.imaginary, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_subtract_real2 (&tmp, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&l.imaginary, l.real, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&l.imaginary, l.imaginary, two);
+ if (bad != FFEBAD)
+ return bad;
+ l.real = tmp;
+ r >>= 1;
+ }
+
+ *res = l;
+ r >>= 1;
+
+ while (r != 0)
+ {
+ bad = ffetarget_multiply_real2 (&tmp1, l.real, l.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp2, l.imaginary, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_subtract_real2 (&tmp, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&l.imaginary, l.real, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&l.imaginary, l.imaginary, two);
+ if (bad != FFEBAD)
+ return bad;
+ l.real = tmp;
+ if ((r & 1) == 1)
+ {
+ bad = ffetarget_multiply_real2 (&tmp1, res->real, l.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp2, res->imaginary,
+ l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_subtract_real2 (&tmp, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp1, res->imaginary, l.real);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_multiply_real2 (&tmp2, res->real, l.imaginary);
+ if (bad != FFEBAD)
+ return bad;
+ bad = ffetarget_add_real2 (&res->imaginary, tmp1, tmp2);
+ if (bad != FFEBAD)
+ return bad;
+ res->real = tmp;
+ }
+ r >>= 1;
+ }
+
+ return FFEBAD;
+}
+
+#endif
+/* ffetarget_power_integerdefault_integerdefault -- Power function
+
+ See prototype. */
+
+ffebad
+ffetarget_power_integerdefault_integerdefault (ffetargetIntegerDefault *res,
+ ffetargetIntegerDefault l, ffetargetIntegerDefault r)
+{
+ if (l == 0)
+ {
+ *res = 0;
+ return FFEBAD;
+ }
+
+ if (r == 0)
+ {
+ *res = 1;
+ return FFEBAD;
+ }
+
+ if (r < 0)
+ {
+ if (l == 1)
+ *res = 1;
+ else if (l == 0)
+ *res = 1;
+ else if (l == -1)
+ *res = ((-r) & 1) == 0 ? 1 : -1;
+ else
+ *res = 0;
+ return FFEBAD;
+ }
+
+ while ((r & 1) == 0)
+ {
+ l *= l;
+ r >>= 1;
+ }
+
+ *res = l;
+ r >>= 1;
+
+ while (r != 0)
+ {
+ l *= l;
+ if ((r & 1) == 1)
+ *res *= l;
+ r >>= 1;
+ }
+
+ return FFEBAD;
+}
+
+/* ffetarget_power_realdefault_integerdefault -- Power function
+
+ See prototype. */
+
+ffebad
+ffetarget_power_realdefault_integerdefault (ffetargetRealDefault *res,
+ ffetargetRealDefault l, ffetargetIntegerDefault r)
+{
+ ffebad bad;
+
+ if (ffetarget_iszero_real1 (l))
+ {
+ ffetarget_real1_zero (res);
+ return FFEBAD;
+ }
+
+ if (r == 0)
+ {
+ ffetarget_real1_one (res);
+ return FFEBAD;
+ }
+
+ if (r < 0)
+ {
+ ffetargetRealDefault one;
+
+ ffetarget_real1_one (&one);
+ r = -r;
+ bad = ffetarget_divide_real1 (&l, one, l);
+ if (bad != FFEBAD)
+ return bad;
+ }
+
+ while ((r & 1) == 0)
+ {
+ bad = ffetarget_multiply_real1 (&l, l, l);
+ if (bad != FFEBAD)
+ return bad;
+ r >>= 1;
+ }
+
+ *res = l;
+ r >>= 1;
+
+ while (r != 0)
+ {
+ bad = ffetarget_multiply_real1 (&l, l, l);
+ if (bad != FFEBAD)
+ return bad;
+ if ((r & 1) == 1)
+ {
+ bad = ffetarget_multiply_real1 (res, *res, l);
+ if (bad != FFEBAD)
+ return bad;
+ }
+ r >>= 1;
+ }
+
+ return FFEBAD;
+}
+
+/* ffetarget_power_realdouble_integerdefault -- Power function
+
+ See prototype. */
+
+ffebad
+ffetarget_power_realdouble_integerdefault (ffetargetRealDouble *res,
+ ffetargetRealDouble l,
+ ffetargetIntegerDefault r)
+{
+ ffebad bad;
+
+ if (ffetarget_iszero_real2 (l))
+ {
+ ffetarget_real2_zero (res);
+ return FFEBAD;
+ }
+
+ if (r == 0)
+ {
+ ffetarget_real2_one (res);
+ return FFEBAD;
+ }
+
+ if (r < 0)
+ {
+ ffetargetRealDouble one;
+
+ ffetarget_real2_one (&one);
+ r = -r;
+ bad = ffetarget_divide_real2 (&l, one, l);
+ if (bad != FFEBAD)
+ return bad;
+ }
+
+ while ((r & 1) == 0)
+ {
+ bad = ffetarget_multiply_real2 (&l, l, l);
+ if (bad != FFEBAD)
+ return bad;
+ r >>= 1;
+ }
+
+ *res = l;
+ r >>= 1;
+
+ while (r != 0)
+ {
+ bad = ffetarget_multiply_real2 (&l, l, l);
+ if (bad != FFEBAD)
+ return bad;
+ if ((r & 1) == 1)
+ {
+ bad = ffetarget_multiply_real2 (res, *res, l);
+ if (bad != FFEBAD)
+ return bad;
+ }
+ r >>= 1;
+ }
+
+ return FFEBAD;
+}
+
+/* ffetarget_print_binary -- Output typeless binary integer
+
+ ffetargetTypeless val;
+ ffetarget_typeless_binary(dmpout,val); */
+
+void
+ffetarget_print_binary (FILE *f, ffetargetTypeless value)
+{
+ char *p;
+ char digits[sizeof (value) * CHAR_BIT + 1];
+
+ if (f == NULL)
+ f = dmpout;
+
+ p = &digits[ARRAY_SIZE (digits) - 1];
+ *p = '\0';
+ do
+ {
+ *--p = (value & 1) + '0';
+ value >>= 1;
+ } while (value == 0);
+
+ fputs (p, f);
+}
+
+/* ffetarget_print_character1 -- Output character string
+
+ ffetargetCharacter1 val;
+ ffetarget_print_character1(dmpout,val); */
+
+void
+ffetarget_print_character1 (FILE *f, ffetargetCharacter1 value)
+{
+ unsigned char *p;
+ ffetargetCharacterSize i;
+
+ fputc ('\'', dmpout);
+ for (i = 0, p = value.text; i < value.length; ++i, ++p)
+ ffetarget_print_char_ (f, *p);
+ fputc ('\'', dmpout);
+}
+
+/* ffetarget_print_hollerith -- Output hollerith string
+
+ ffetargetHollerith val;
+ ffetarget_print_hollerith(dmpout,val); */
+
+void
+ffetarget_print_hollerith (FILE *f, ffetargetHollerith value)
+{
+ unsigned char *p;
+ ffetargetHollerithSize i;
+
+ fputc ('\'', dmpout);
+ for (i = 0, p = value.text; i < value.length; ++i, ++p)
+ ffetarget_print_char_ (f, *p);
+ fputc ('\'', dmpout);
+}
+
+/* ffetarget_print_octal -- Output typeless octal integer
+
+ ffetargetTypeless val;
+ ffetarget_print_octal(dmpout,val); */
+
+void
+ffetarget_print_octal (FILE *f, ffetargetTypeless value)
+{
+ char *p;
+ char digits[sizeof (value) * CHAR_BIT / 3 + 1];
+
+ if (f == NULL)
+ f = dmpout;
+
+ p = &digits[ARRAY_SIZE (digits) - 3];
+ *p = '\0';
+ do
+ {
+ *--p = (value & 3) + '0';
+ value >>= 3;
+ } while (value == 0);
+
+ fputs (p, f);
+}
+
+/* ffetarget_print_hex -- Output typeless hex integer
+
+ ffetargetTypeless val;
+ ffetarget_print_hex(dmpout,val); */
+
+void
+ffetarget_print_hex (FILE *f, ffetargetTypeless value)
+{
+ char *p;
+ char digits[sizeof (value) * CHAR_BIT / 4 + 1];
+ static char hexdigits[16] = "0123456789ABCDEF";
+
+ if (f == NULL)
+ f = dmpout;
+
+ p = &digits[ARRAY_SIZE (digits) - 3];
+ *p = '\0';
+ do
+ {
+ *--p = hexdigits[value & 4];
+ value >>= 4;
+ } while (value == 0);
+
+ fputs (p, f);
+}
+
+/* ffetarget_real1 -- Convert token to a single-precision real number
+
+ See prototype.
+
+ Pass NULL for any token not provided by the user, but a valid Fortran
+ real number must be provided somehow. For example, it is ok for
+ exponent_sign_token and exponent_digits_token to be NULL as long as
+ exponent_token not only starts with "E" or "e" but also contains at least
+ one digit following it. Token use counts not affected overall. */
+
+#if FFETARGET_okREAL1
+bool
+ffetarget_real1 (ffetargetReal1 *value, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits)
+{
+ size_t sz = 1; /* Allow room for '\0' byte at end. */
+ char *ptr = &ffetarget_string_[0];
+ char *p = ptr;
+ char *q;
+
+#define dotok(x) if (x != NULL) ++sz;
+#define dotoktxt(x) if (x != NULL) sz += ffelex_token_length(x)
+
+ dotoktxt (integer);
+ dotok (decimal);
+ dotoktxt (fraction);
+ dotoktxt (exponent);
+ dotok (exponent_sign);
+ dotoktxt (exponent_digits);
+
+#undef dotok
+#undef dotoktxt
+
+ if (sz > ARRAY_SIZE (ffetarget_string_))
+ p = ptr = (char *) malloc_new_ks (malloc_pool_image (), "ffetarget_real1",
+ sz);
+
+#define dotoktxt(x) if (x != NULL) \
+ { \
+ for (q = ffelex_token_text(x); *q != '\0'; ++q) \
+ *p++ = *q; \
+ }
+
+ dotoktxt (integer);
+
+ if (decimal != NULL)
+ *p++ = '.';
+
+ dotoktxt (fraction);
+ dotoktxt (exponent);
+
+ if (exponent_sign != NULL)
+ {
+ if (ffelex_token_type (exponent_sign) == FFELEX_typePLUS)
+ *p++ = '+';
+ else
+ {
+ assert (ffelex_token_type (exponent_sign) == FFELEX_typeMINUS);
+ *p++ = '-';
+ }
+ }
+
+ dotoktxt (exponent_digits);
+
+#undef dotoktxt
+
+ *p = '\0';
+
+ ffetarget_make_real1 (value,
+ FFETARGET_ATOF_ (ptr,
+ SFmode));
+
+ if (sz > ARRAY_SIZE (ffetarget_string_))
+ malloc_kill_ks (malloc_pool_image (), ptr, sz);
+
+ return TRUE;
+}
+
+#endif
+/* ffetarget_real2 -- Convert token to a single-precision real number
+
+ See prototype.
+
+ Pass NULL for any token not provided by the user, but a valid Fortran
+ real number must be provided somehow. For example, it is ok for
+ exponent_sign_token and exponent_digits_token to be NULL as long as
+ exponent_token not only starts with "E" or "e" but also contains at least
+ one digit following it. Token use counts not affected overall. */
+
+#if FFETARGET_okREAL2
+bool
+ffetarget_real2 (ffetargetReal2 *value, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits)
+{
+ size_t sz = 1; /* Allow room for '\0' byte at end. */
+ char *ptr = &ffetarget_string_[0];
+ char *p = ptr;
+ char *q;
+
+#define dotok(x) if (x != NULL) ++sz;
+#define dotoktxt(x) if (x != NULL) sz += ffelex_token_length(x)
+
+ dotoktxt (integer);
+ dotok (decimal);
+ dotoktxt (fraction);
+ dotoktxt (exponent);
+ dotok (exponent_sign);
+ dotoktxt (exponent_digits);
+
+#undef dotok
+#undef dotoktxt
+
+ if (sz > ARRAY_SIZE (ffetarget_string_))
+ p = ptr = (char *) malloc_new_ks (malloc_pool_image (), "ffetarget_real1", sz);
+
+#define dotoktxt(x) if (x != NULL) \
+ { \
+ for (q = ffelex_token_text(x); *q != '\0'; ++q) \
+ *p++ = *q; \
+ }
+#define dotoktxtexp(x) if (x != NULL) \
+ { \
+ *p++ = 'E'; \
+ for (q = ffelex_token_text(x) + 1; *q != '\0'; ++q) \
+ *p++ = *q; \
+ }
+
+ dotoktxt (integer);
+
+ if (decimal != NULL)
+ *p++ = '.';
+
+ dotoktxt (fraction);
+ dotoktxtexp (exponent);
+
+ if (exponent_sign != NULL)
+ {
+ if (ffelex_token_type (exponent_sign) == FFELEX_typePLUS)
+ *p++ = '+';
+ else
+ {
+ assert (ffelex_token_type (exponent_sign) == FFELEX_typeMINUS);
+ *p++ = '-';
+ }
+ }
+
+ dotoktxt (exponent_digits);
+
+#undef dotoktxt
+
+ *p = '\0';
+
+ ffetarget_make_real2 (value,
+ FFETARGET_ATOF_ (ptr,
+ DFmode));
+
+ if (sz > ARRAY_SIZE (ffetarget_string_))
+ malloc_kill_ks (malloc_pool_image (), ptr, sz);
+
+ return TRUE;
+}
+
+#endif
+bool
+ffetarget_typeless_binary (ffetargetTypeless *xvalue, ffelexToken token)
+{
+ char *p;
+ char c;
+ ffetargetTypeless value = 0;
+ ffetargetTypeless new_value = 0;
+ bool bad_digit = FALSE;
+ bool overflow = FALSE;
+
+ p = ffelex_token_text (token);
+
+ for (c = *p; c != '\0'; c = *++p)
+ {
+ new_value <<= 1;
+ if ((new_value >> 1) != value)
+ overflow = TRUE;
+ if (ISDIGIT (c))
+ new_value += c - '0';
+ else
+ bad_digit = TRUE;
+ value = new_value;
+ }
+
+ if (bad_digit)
+ {
+ ffebad_start (FFEBAD_INVALID_TYPELESS_BINARY_DIGIT);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_finish ();
+ }
+ else if (overflow)
+ {
+ ffebad_start (FFEBAD_TYPELESS_OVERFLOW);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_finish ();
+ }
+
+ *xvalue = value;
+
+ return !bad_digit && !overflow;
+}
+
+bool
+ffetarget_typeless_octal (ffetargetTypeless *xvalue, ffelexToken token)
+{
+ char *p;
+ char c;
+ ffetargetTypeless value = 0;
+ ffetargetTypeless new_value = 0;
+ bool bad_digit = FALSE;
+ bool overflow = FALSE;
+
+ p = ffelex_token_text (token);
+
+ for (c = *p; c != '\0'; c = *++p)
+ {
+ new_value <<= 3;
+ if ((new_value >> 3) != value)
+ overflow = TRUE;
+ if (ISDIGIT (c))
+ new_value += c - '0';
+ else
+ bad_digit = TRUE;
+ value = new_value;
+ }
+
+ if (bad_digit)
+ {
+ ffebad_start (FFEBAD_INVALID_TYPELESS_OCTAL_DIGIT);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_finish ();
+ }
+ else if (overflow)
+ {
+ ffebad_start (FFEBAD_TYPELESS_OVERFLOW);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_finish ();
+ }
+
+ *xvalue = value;
+
+ return !bad_digit && !overflow;
+}
+
+bool
+ffetarget_typeless_hex (ffetargetTypeless *xvalue, ffelexToken token)
+{
+ char *p;
+ char c;
+ ffetargetTypeless value = 0;
+ ffetargetTypeless new_value = 0;
+ bool bad_digit = FALSE;
+ bool overflow = FALSE;
+
+ p = ffelex_token_text (token);
+
+ for (c = *p; c != '\0'; c = *++p)
+ {
+ new_value <<= 4;
+ if ((new_value >> 4) != value)
+ overflow = TRUE;
+ if (ISDIGIT (c))
+ new_value += c - '0';
+ else if ((c >= 'A') && (c <= 'F'))
+ new_value += c - 'A' + 10;
+ else if ((c >= 'a') && (c <= 'f'))
+ new_value += c - 'a' + 10;
+ else
+ bad_digit = TRUE;
+ value = new_value;
+ }
+
+ if (bad_digit)
+ {
+ ffebad_start (FFEBAD_INVALID_TYPELESS_HEX_DIGIT);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_finish ();
+ }
+ else if (overflow)
+ {
+ ffebad_start (FFEBAD_TYPELESS_OVERFLOW);
+ ffebad_here (0, ffelex_token_where_line (token),
+ ffelex_token_where_column (token));
+ ffebad_finish ();
+ }
+
+ *xvalue = value;
+
+ return !bad_digit && !overflow;
+}
+
+void
+ffetarget_verify_character1 (mallocPool pool, ffetargetCharacter1 val)
+{
+ if (val.length != 0)
+ malloc_verify_kp (pool, val.text, val.length);
+}
+
+/* This is like memcpy. It is needed because some systems' header files
+ don't declare memcpy as a function but instead
+ "#define memcpy(to,from,len) something". */
+
+void *
+ffetarget_memcpy_ (void *dst, void *src, size_t len)
+{
+ return (void *) memcpy (dst, src, len);
+}
+
+/* ffetarget_num_digits_ -- Determine number of non-space characters in token
+
+ ffetarget_num_digits_(token);
+
+ All non-spaces are assumed to be binary, octal, or hex digits. */
+
+int
+ffetarget_num_digits_ (ffelexToken token)
+{
+ int i;
+ char *c;
+
+ switch (ffelex_token_type (token))
+ {
+ case FFELEX_typeNAME:
+ case FFELEX_typeNUMBER:
+ return ffelex_token_length (token);
+
+ case FFELEX_typeCHARACTER:
+ i = 0;
+ for (c = ffelex_token_text (token); *c != '\0'; ++c)
+ {
+ if (*c != ' ')
+ ++i;
+ }
+ return i;
+
+ default:
+ assert ("weird token" == NULL);
+ return 1;
+ }
+}
diff --git a/contrib/gcc/f/target.h b/contrib/gcc/f/target.h
new file mode 100644
index 0000000..ef59f90d
--- /dev/null
+++ b/contrib/gcc/f/target.h
@@ -0,0 +1,1865 @@
+/* target.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ target.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_target
+#define _H_f_target
+
+#ifdef FFE_STANDALONE
+#define HOST_WIDE_INT long
+#else
+#ifndef TREE_CODE
+#include "tree.j"
+#endif
+#endif
+
+/* For now, g77 requires the ability to determine the exact bit pattern
+ of a float on the target machine. (Hopefully this will be changed
+ soon). Make sure we can do this. */
+
+#if !defined (REAL_ARITHMETIC) \
+ && ((TARGET_FLOAT_FORMAT != HOST_FLOAT_FORMAT) \
+ || (FLOAT_WORDS_BIG_ENDIAN != HOST_FLOAT_WORDS_BIG_ENDIAN))
+#error "g77 requires ability to access exact FP representation of target machine"
+#endif
+
+/* Simple definitions and enumerations. */
+
+#define FFETARGET_charactersizeNONE (-1)
+#ifndef FFETARGET_charactersizeMAXIMUM
+#define FFETARGET_charactersizeMAXIMUM 2147483647
+#endif
+
+#ifndef FFETARGET_defaultIS_90
+#define FFETARGET_defaultIS_90 0
+#endif
+#ifndef FFETARGET_defaultIS_AUTOMATIC
+#define FFETARGET_defaultIS_AUTOMATIC 1
+#endif
+#ifndef FFETARGET_defaultIS_BACKSLASH
+#define FFETARGET_defaultIS_BACKSLASH 1
+#endif
+#ifndef FFETARGET_defaultIS_INIT_LOCAL_ZERO
+#define FFETARGET_defaultIS_INIT_LOCAL_ZERO 0
+#endif
+#ifndef FFETARGET_defaultIS_DOLLAR_OK
+#define FFETARGET_defaultIS_DOLLAR_OK 0
+#endif
+#ifndef FFETARGET_defaultIS_F2C
+#define FFETARGET_defaultIS_F2C 1
+#endif
+#ifndef FFETARGET_defaultIS_F2C_LIBRARY
+#define FFETARGET_defaultIS_F2C_LIBRARY 1
+#endif
+#ifndef FFETARGET_defaultIS_FREE_FORM
+#define FFETARGET_defaultIS_FREE_FORM 0
+#endif
+#ifndef FFETARGET_defaultIS_PEDANTIC
+#define FFETARGET_defaultIS_PEDANTIC 0
+#endif
+#ifndef FFETARGET_defaultCASE_INTRIN
+#define FFETARGET_defaultCASE_INTRIN FFE_caseLOWER
+#endif
+#ifndef FFETARGET_defaultCASE_MATCH
+#define FFETARGET_defaultCASE_MATCH FFE_caseLOWER
+#endif
+#ifndef FFETARGET_defaultCASE_SOURCE
+#define FFETARGET_defaultCASE_SOURCE FFE_caseLOWER
+#endif
+#ifndef FFETARGET_defaultCASE_SYMBOL
+#define FFETARGET_defaultCASE_SYMBOL FFE_caseNONE
+#endif
+
+#ifndef FFETARGET_defaultFIXED_LINE_LENGTH
+#define FFETARGET_defaultFIXED_LINE_LENGTH 72
+#endif
+
+/* 1 if external Fortran names ("FOO" in SUBROUTINE FOO, COMMON /FOO/,
+ and even enforced/default-for-unnamed PROGRAM, blank-COMMON, and
+ BLOCK DATA names, but not names of library functions implementing
+ intrinsics or names of local/internal variables) should have an
+ underscore appended (for compatibility with existing systems). */
+
+#ifndef FFETARGET_defaultEXTERNAL_UNDERSCORED
+#define FFETARGET_defaultEXTERNAL_UNDERSCORED 1
+#endif
+
+/* 1 if external Fortran names with underscores already in them should
+ have an extra underscore appended (in addition to the one they
+ might already have appened if FFETARGET_defaultEXTERNAL_UNDERSCORED). */
+
+#ifndef FFETARGET_defaultUNDERSCORED_EXTERNAL_UNDERSCORED
+#define FFETARGET_defaultUNDERSCORED_EXTERNAL_UNDERSCORED 1
+#endif
+
+/* If FFETARGET_defaultEXTERNAL_UNDERSCORED is 0, the following definitions
+ might also need to be overridden to make g77 objects compatible with
+ f2c+gcc objects. Although I don't think the unnamed BLOCK DATA one
+ is an issue at all. Of course, on some systems it isn't f2c
+ compatibility that is the issue -- maybe compatibility with some
+ other compiler(s). I don't know what to recommend for systems where
+ there is no existing Fortran compiler -- I suppose porting f2c and
+ pretending it's the existing one is best for now. */
+
+/* 1 if the "FOO" in "PROGRAM FOO" should be overridden and a particular
+ name imposed in place of it in the actual code (normally the case,
+ because the library's main entry point on most systems calls the main
+ function by a particular name). Someday g77 might do the f2c trick
+ of also outputting a "FOO" procedure that just calls the main procedure,
+ but that'll wait until somebody shows why it is needed. */
+
+#ifndef FFETARGET_isENFORCED_MAIN
+#define FFETARGET_isENFORCED_MAIN 1
+#endif
+
+/* The enforced name of the main program if ENFORCED_MAIN is 1. */
+
+#ifndef FFETARGET_nameENFORCED_MAIN_NAME
+#define FFETARGET_nameENFORCED_MAIN_NAME "MAIN__"
+#endif
+
+/* The name used for an unnamed main program if ENFORCED_MAIN is 0. */
+
+#ifndef FFETARGET_nameUNNAMED_MAIN
+#define FFETARGET_nameUNNAMED_MAIN "MAIN__"
+#endif
+
+/* The name used for an unnamed block data program. */
+
+#ifndef FFETARGET_nameUNNAMED_BLOCK_DATA
+#define FFETARGET_nameUNNAMED_BLOCK_DATA "_BLOCK_DATA__"
+#endif
+
+/* The name used for blank common. */
+
+#ifndef FFETARGET_nameBLANK_COMMON
+#define FFETARGET_nameBLANK_COMMON "_BLNK__"
+#endif
+
+#ifndef FFETARGET_integerSMALLEST_POSITIVE
+#define FFETARGET_integerSMALLEST_POSITIVE 0
+#endif
+#ifndef FFETARGET_integerLARGEST_POSITIVE
+#define FFETARGET_integerLARGEST_POSITIVE 2147483647
+#endif
+#ifndef FFETARGET_integerBIG_MAGICAL
+#define FFETARGET_integerBIG_MAGICAL 020000000000 /* 2147483648 */
+#endif
+#ifndef FFETARGET_integerALMOST_BIG_MAGICAL
+#define FFETARGET_integerALMOST_BIG_MAGICAL 214748364
+#endif
+#ifndef FFETARGET_integerALMOST_BIG_OVERFLOW_BINARY
+#define FFETARGET_integerALMOST_BIG_OVERFLOW_BINARY 0x80000000
+#endif
+#ifndef FFETARGET_integerALMOST_BIG_OVERFLOW_HEX
+#define FFETARGET_integerALMOST_BIG_OVERFLOW_HEX 0x10000000
+#endif
+#ifndef FFETARGET_integerALMOST_BIG_OVERFLOW_OCTAL
+#define FFETARGET_integerALMOST_BIG_OVERFLOW_OCTAL 0x20000000
+#endif
+#ifndef FFETARGET_integerFINISH_BIG_MAGICAL
+#define FFETARGET_integerFINISH_BIG_MAGICAL 8
+#endif
+#ifndef FFETARGET_integerFINISH_BIG_OVERFLOW_BINARY
+#define FFETARGET_integerFINISH_BIG_OVERFLOW_BINARY 0
+#endif
+#ifndef FFETARGET_integerFINISH_BIG_OVERFLOW_HEX
+#define FFETARGET_integerFINISH_BIG_OVERFLOW_HEX 0
+#endif
+#ifndef FFETARGET_integerFINISH_BIG_OVERFLOW_OCTAL
+#define FFETARGET_integerFINISH_BIG_OVERFLOW_OCTAL 0
+#endif
+
+#ifndef FFETARGET_offsetNONE
+#define FFETARGET_offsetNONE 0 /* Not used by FFE, for backend if needed. */
+#endif
+
+#define FFETARGET_okINTEGER1 1
+#define FFETARGET_okINTEGER2 1
+#define FFETARGET_okINTEGER3 1
+#define FFETARGET_okINTEGER4 1
+#define FFETARGET_okLOGICAL1 1
+#define FFETARGET_okLOGICAL2 1
+#define FFETARGET_okLOGICAL3 1
+#define FFETARGET_okLOGICAL4 1
+#define FFETARGET_okREAL1 1
+#define FFETARGET_okREAL2 1
+#define FFETARGET_okREAL3 0
+#define FFETARGET_okREALQUAD FFETARGET_okREAL3
+#define FFETARGET_okCOMPLEX1 1
+#define FFETARGET_okCOMPLEX2 1
+#define FFETARGET_okCOMPLEX3 0
+#define FFETARGET_okCOMPLEXDOUBLE FFETARGET_okCOMPLEX2
+#define FFETARGET_okCOMPLEXQUAD FFETARGET_okCOMPLEX3
+#define FFETARGET_okCHARACTER1 1
+
+#define FFETARGET_f2cTYUNKNOWN 0
+#define FFETARGET_f2cTYADDR 1
+#define FFETARGET_f2cTYSHORT 2
+#define FFETARGET_f2cTYLONG 3
+#define FFETARGET_f2cTYREAL 4
+#define FFETARGET_f2cTYDREAL 5
+#define FFETARGET_f2cTYCOMPLEX 6
+#define FFETARGET_f2cTYDCOMPLEX 7
+#define FFETARGET_f2cTYLOGICAL 8
+#define FFETARGET_f2cTYCHAR 9
+#define FFETARGET_f2cTYSUBR 10
+#define FFETARGET_f2cTYINT1 11
+#define FFETARGET_f2cTYLOGICAL1 12
+#define FFETARGET_f2cTYLOGICAL2 13
+#define FFETARGET_f2cTYQUAD 14
+
+/* Typedefs. */
+
+typedef unsigned char ffetargetAlign; /* ffetargetOffset for alignment. */
+#define ffetargetAlign_f ""
+typedef long ffetargetCharacterSize;
+#define ffetargetCharacterSize_f "l"
+typedef void (*ffetargetCopyfunc) (void *, void *, size_t);
+typedef ffetargetCharacterSize ffetargetHollerithSize;
+#define ffetargetHollerithSize_f "l"
+typedef long long ffetargetOffset;
+#define ffetargetOffset_f "ll"
+
+#if FFETARGET_okINTEGER1
+#ifndef __alpha__
+typedef long int ffetargetInteger1;
+#define ffetargetInteger1_f "l"
+#else
+typedef int ffetargetInteger1;
+#define ffetargetInteger1_f ""
+#endif
+#endif
+#if FFETARGET_okINTEGER2
+typedef signed char ffetargetInteger2;
+#define ffetargetInteger2_f ""
+#endif
+#if FFETARGET_okINTEGER3
+typedef short int ffetargetInteger3;
+#define ffetargetInteger3_f ""
+#endif
+#if FFETARGET_okINTEGER4
+typedef long long int ffetargetInteger4;
+#define ffetargetInteger4_f "ll"
+#endif
+#if FFETARGET_okINTEGER5
+typedef ? ffetargetInteger5;
+#define ffetargetInteger5_f
+?
+#endif
+#if FFETARGET_okINTEGER6
+typedef ? ffetargetInteger6;
+#define ffetargetInteger6_f
+?
+#endif
+#if FFETARGET_okINTEGER7
+typedef ? ffetargetInteger7;
+#define ffetargetInteger7_f
+?
+#endif
+#if FFETARGET_okINTEGER8
+typedef ? ffetargetInteger8;
+#define ffetargetInteger8_f
+?
+#endif
+#if FFETARGET_okLOGICAL1
+#ifndef __alpha__
+typedef long int ffetargetLogical1;
+#define ffetargetLogical1_f "l"
+#else
+typedef int ffetargetLogical1;
+#define ffetargetLogical1_f ""
+#endif
+#endif
+#if FFETARGET_okLOGICAL2
+typedef signed char ffetargetLogical2;
+#define ffetargetLogical2_f ""
+#endif
+#if FFETARGET_okLOGICAL3
+typedef short int ffetargetLogical3;
+#define ffetargetLogical3_f ""
+#endif
+#if FFETARGET_okLOGICAL4
+typedef long long int ffetargetLogical4;
+#define ffetargetLogical4_f "ll"
+#endif
+#if FFETARGET_okLOGICAL5
+typedef ? ffetargetLogical5;
+#define ffetargetLogical5_f
+?
+#endif
+#if FFETARGET_okLOGICAL6
+typedef ? ffetargetLogical6;
+#define ffetargetLogical6_f
+?
+#endif
+#if FFETARGET_okLOGICAL7
+typedef ? ffetargetLogical7;
+#define ffetargetLogical7_f
+?
+#endif
+#if FFETARGET_okLOGICAL8
+typedef ? ffetargetLogical8;
+#define ffetargetLogical8_f
+?
+#endif
+#if FFETARGET_okREAL1
+#ifdef REAL_ARITHMETIC
+#ifndef __alpha__
+typedef long int ffetargetReal1;
+#define ffetargetReal1_f "l"
+#define ffetarget_cvt_r1_to_rv_ REAL_VALUE_UNTO_TARGET_SINGLE
+#define ffetarget_cvt_rv_to_r1_ REAL_VALUE_TO_TARGET_SINGLE
+#else
+typedef int ffetargetReal1;
+#define ffetargetReal1_f ""
+#define ffetarget_cvt_r1_to_rv_(in) \
+ ({ REAL_VALUE_TYPE _rv; \
+ _rv = REAL_VALUE_UNTO_TARGET_SINGLE ((long) (in)); \
+ _rv; })
+#define ffetarget_cvt_rv_to_r1_(in, out) \
+ ({ long _tmp; \
+ REAL_VALUE_TO_TARGET_SINGLE ((in), _tmp); \
+ (out) = (ffetargetReal1) _tmp; })
+#endif
+#else /* REAL_ARITHMETIC */
+typedef float ffetargetReal1;
+#define ffetargetReal1_f ""
+#endif /* REAL_ARITHMETIC */
+#endif
+#if FFETARGET_okREAL2
+#ifdef REAL_ARITHMETIC
+#ifndef __alpha__
+typedef struct
+ {
+ long int v[2];
+ }
+ffetargetReal2;
+#define ffetargetReal2_f "l"
+#define ffetarget_cvt_r2_to_rv_ REAL_VALUE_UNTO_TARGET_DOUBLE
+#define ffetarget_cvt_rv_to_r2_ REAL_VALUE_TO_TARGET_DOUBLE
+#else
+typedef struct
+ {
+ int v[2];
+ }
+ffetargetReal2;
+#define ffetargetReal2_f ""
+#define ffetarget_cvt_r2_to_rv_(in) \
+ ({ REAL_VALUE_TYPE _rv; \
+ long _tmp[2]; \
+ _tmp[0] = (in)[0]; \
+ _tmp[1] = (in)[1]; \
+ _rv = REAL_VALUE_UNTO_TARGET_DOUBLE (_tmp); \
+ _rv; })
+#define ffetarget_cvt_rv_to_r2_(in, out) \
+ ({ long _tmp[2]; \
+ REAL_VALUE_TO_TARGET_DOUBLE ((in), _tmp); \
+ (out)[0] = (int) (_tmp[0]); \
+ (out)[1] = (int) (_tmp[1]); })
+#endif
+#else
+typedef double ffetargetReal2;
+#define ffetargetReal2_f ""
+#endif
+#endif
+#if FFETARGET_okREAL3
+#ifdef REAL_ARITHMETIC
+typedef long ffetargetReal3[?];
+#else
+typedef ? ffetargetReal3;
+#define ffetargetReal3_f
+#endif
+?
+#endif
+#if FFETARGET_okREAL4
+#ifdef REAL_ARITHMETIC
+typedef long ffetargetReal4[?];
+#else
+typedef ? ffetargetReal4;
+#define ffetargetReal4_f
+#endif
+?
+#endif
+#if FFETARGET_okREAL5
+#ifdef REAL_ARITHMETIC
+typedef long ffetargetReal5[?];
+#else
+typedef ? ffetargetReal5;
+#define ffetargetReal5_f
+#endif
+?
+#endif
+#if FFETARGET_okREAL6
+#ifdef REAL_ARITHMETIC
+typedef long ffetargetReal6[?];
+#else
+typedef ? ffetargetReal6;
+#define ffetargetReal6_f
+#endif
+?
+#endif
+#if FFETARGET_okREAL7
+#ifdef REAL_ARITHMETIC
+typedef long ffetargetReal7[?];
+#else
+typedef ? ffetargetReal7;
+#define ffetargetReal7_f
+#endif
+?
+#endif
+#if FFETARGET_okREAL8
+#ifdef REAL_ARITHMETIC
+typedef long ffetargetReal8[?];
+#else
+typedef ? ffetargetReal8;
+#define ffetargetReal8_f
+#endif
+?
+#endif
+#if FFETARGET_okCOMPLEX1
+struct _ffetarget_complex_1_
+ {
+ ffetargetReal1 real;
+ ffetargetReal1 imaginary;
+ };
+typedef struct _ffetarget_complex_1_ ffetargetComplex1;
+#endif
+#if FFETARGET_okCOMPLEX2
+struct _ffetarget_complex_2_
+ {
+ ffetargetReal2 real;
+ ffetargetReal2 imaginary;
+ };
+typedef struct _ffetarget_complex_2_ ffetargetComplex2;
+#endif
+#if FFETARGET_okCOMPLEX3
+struct _ffetarget_complex_3_
+ {
+ ffetargetReal3 real;
+ ffetargetReal3 imaginary;
+ };
+typedef struct _ffetarget_complex_3_ ffetargetComplex3;
+#endif
+#if FFETARGET_okCOMPLEX4
+struct _ffetarget_complex_4_
+ {
+ ffetargetReal4 real;
+ ffetargetReal4 imaginary;
+ };
+typedef struct _ffetarget_complex_4_ ffetargetComplex4;
+#endif
+#if FFETARGET_okCOMPLEX5
+struct _ffetarget_complex_5_
+ {
+ ffetargetReal5 real;
+ ffetargetReal5 imaginary;
+ };
+typedef struct _ffetarget_complex_5_ ffetargetComplex5;
+#endif
+#if FFETARGET_okCOMPLEX6
+struct _ffetarget_complex_6_
+ {
+ ffetargetReal6 real;
+ ffetargetReal6 imaginary;
+ };
+typedef struct _ffetarget_complex_6_ ffetargetComplex6;
+#endif
+#if FFETARGET_okCOMPLEX7
+struct _ffetarget_complex_7_
+ {
+ ffetargetReal7 real;
+ ffetargetReal7 imaginary;
+ };
+typedef struct _ffetarget_complex_7_ ffetargetComplex7;
+#endif
+#if FFETARGET_okCOMPLEX8
+struct _ffetarget_complex_8_
+ {
+ ffetargetReal8 real;
+ ffetargetReal8 imaginary;
+ };
+typedef struct _ffetarget_complex_8_ ffetargetComplex8;
+#endif
+#if FFETARGET_okCHARACTER1
+struct _ffetarget_char_1_
+ {
+ ffetargetCharacterSize length;
+ unsigned char *text;
+ };
+typedef struct _ffetarget_char_1_ ffetargetCharacter1;
+typedef unsigned char ffetargetCharacterUnit1;
+#endif
+#if FFETARGET_okCHARACTER2
+typedef ? ffetargetCharacter2;
+typedef ? ffetargetCharacterUnit2;
+#endif
+#if FFETARGET_okCHARACTER3
+typedef ? ffetargetCharacter3;
+typedef ? ffetargetCharacterUnit3;
+#endif
+#if FFETARGET_okCHARACTER4
+typedef ? ffetargetCharacter4;
+typedef ? ffetargetCharacterUnit4;
+#endif
+#if FFETARGET_okCHARACTER5
+typedef ? ffetargetCharacter5;
+typedef ? ffetargetCharacterUnit5;
+#endif
+#if FFETARGET_okCHARACTER6
+typedef ? ffetargetCharacter6;
+typedef ? ffetargetCharacterUnit6;
+#endif
+#if FFETARGET_okCHARACTER7
+typedef ? ffetargetCharacter7;
+typedef ? ffetargetCharacterUnit7;
+#endif
+#if FFETARGET_okCHARACTER8
+typedef ? ffetargetCharacter8;
+typedef ? ffetargetCharacterUnit8;
+#endif
+
+typedef unsigned long long int ffetargetTypeless;
+
+struct _ffetarget_hollerith_
+ {
+ ffetargetHollerithSize length;
+ unsigned char *text;
+ };
+typedef struct _ffetarget_hollerith_ ffetargetHollerith;
+
+typedef ffetargetCharacter1 ffetargetCharacterDefault;
+typedef ffetargetComplex1 ffetargetComplexDefault;
+#if FFETARGET_okCOMPLEXDOUBLE
+typedef ffetargetComplex2 ffetargetComplexDouble;
+#endif
+#if FFETARGET_okCOMPLEXQUAD
+typedef ffetargetComplex3 ffetargetComplexQuad;
+#endif
+typedef ffetargetInteger1 ffetargetIntegerDefault;
+#define ffetargetIntegerDefault_f ffetargetInteger1_f
+typedef ffetargetLogical1 ffetargetLogicalDefault;
+#define ffetargetLogicalDefault_f ffetargetLogical1_f
+typedef ffetargetReal1 ffetargetRealDefault;
+#define ffetargetRealDefault_f ffetargetReal1_f
+typedef ffetargetReal2 ffetargetRealDouble;
+#define ffetargetRealDouble_f ffetargetReal2_f
+#if FFETARGET_okREALQUAD
+typedef ffetargetReal3 ffetargetRealQuad;
+#define ffetargetRealQuad_f ffetargetReal3_f
+#endif
+
+/* Include files needed by this one. */
+
+#include "bad.h"
+#include "info.h"
+#include "lex.h"
+#include "malloc.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+extern char ffetarget_string_[40]; /* Temp for ascii-to-double (atof). */
+extern HOST_WIDE_INT ffetarget_long_val_;
+extern HOST_WIDE_INT ffetarget_long_junk_;
+
+/* Declare functions with prototypes. */
+
+void ffetarget_aggregate_info (ffeinfoBasictype *ebt, ffeinfoKindtype *ekt,
+ ffetargetAlign *units, ffeinfoBasictype abt,
+ ffeinfoKindtype akt);
+ffetargetAlign ffetarget_align (ffetargetAlign *updated_alignment,
+ ffetargetAlign *updated_modulo,
+ ffetargetOffset offset,
+ ffetargetAlign alignment,
+ ffetargetAlign modulo);
+#if FFETARGET_okCHARACTER1
+bool ffetarget_character1 (ffetargetCharacter1 *val, ffelexToken character,
+ mallocPool pool);
+int ffetarget_cmp_character1 (ffetargetCharacter1 l, ffetargetCharacter1 r);
+ffebad ffetarget_concatenate_character1 (ffetargetCharacter1 *res,
+ ffetargetCharacter1 l,
+ ffetargetCharacter1 r,
+ mallocPool pool,
+ ffetargetCharacterSize *len);
+ffebad ffetarget_convert_character1_character1 (ffetargetCharacter1 *res,
+ ffetargetCharacterSize res_size,
+ ffetargetCharacter1 l,
+ mallocPool pool);
+ffebad ffetarget_convert_character1_hollerith (ffetargetCharacter1 *res,
+ ffetargetCharacterSize res_size,
+ ffetargetHollerith l,
+ mallocPool pool);
+ffebad ffetarget_convert_character1_integer4 (ffetargetCharacter1 *res,
+ ffetargetCharacterSize res_size,
+ ffetargetInteger4 l,
+ mallocPool pool);
+ffebad ffetarget_convert_character1_logical4 (ffetargetCharacter1 *res,
+ ffetargetCharacterSize res_size,
+ ffetargetLogical4 l,
+ mallocPool pool);
+ffebad ffetarget_convert_character1_typeless (ffetargetCharacter1 *res,
+ ffetargetCharacterSize res_size,
+ ffetargetTypeless l,
+ mallocPool pool);
+ffebad ffetarget_eq_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r);
+ffebad ffetarget_le_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r);
+ffebad ffetarget_ge_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r);
+ffebad ffetarget_gt_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r);
+ffebad ffetarget_lt_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r);
+ffebad ffetarget_ne_character1 (bool *res, ffetargetCharacter1 l,
+ ffetargetCharacter1 r);
+ffebad ffetarget_substr_character1 (ffetargetCharacter1 *res,
+ ffetargetCharacter1 l,
+ ffetargetCharacterSize first,
+ ffetargetCharacterSize last,
+ mallocPool pool,
+ ffetargetCharacterSize *len);
+#endif
+int ffetarget_cmp_hollerith (ffetargetHollerith l, ffetargetHollerith r);
+bool ffetarget_hollerith (ffetargetHollerith *val, ffelexToken hollerith,
+ mallocPool pool);
+int ffetarget_cmp_typeless (ffetargetTypeless l, ffetargetTypeless r);
+ffebad ffetarget_convert_any_character1_ (char *res, size_t size,
+ ffetargetCharacter1 l);
+ffebad ffetarget_convert_any_hollerith_ (char *res, size_t size,
+ ffetargetHollerith l);
+ffebad ffetarget_convert_any_typeless_ (char *res, size_t size,
+ ffetargetTypeless l);
+#if FFETARGET_okCOMPLEX1
+ffebad ffetarget_divide_complex1 (ffetargetComplex1 *res, ffetargetComplex1 l,
+ ffetargetComplex1 r);
+#endif
+#if FFETARGET_okCOMPLEX2
+ffebad ffetarget_divide_complex2 (ffetargetComplex2 *res, ffetargetComplex2 l,
+ ffetargetComplex2 r);
+#endif
+#if FFETARGET_okCOMPLEX3
+ffebad ffetarget_divide_complex3 (ffetargetComplex3 *res, ffetargetComplex3 l,
+ ffetargetComplex3 r);
+#endif
+#if FFETARGET_okCOMPLEX4
+ffebad ffetarget_divide_complex4 (ffetargetComplex4 *res, ffetargetComplex4 l,
+ ffetargetComplex4 r);
+#endif
+#if FFETARGET_okCOMPLEX5
+ffebad ffetarget_divide_complex5 (ffetargetComplex5 *res, ffetargetComplex5 l,
+ ffetargetComplex5 r);
+#endif
+#if FFETARGET_okCOMPLEX6
+ffebad ffetarget_divide_complex6 (ffetargetComplex6 *res, ffetargetComplex6 l,
+ ffetargetComplex6 r);
+#endif
+#if FFETARGET_okCOMPLEX7
+ffebad ffetarget_divide_complex7 (ffetargetComplex7 *res, ffetargetComplex7 l,
+ ffetargetComplex7 r);
+#endif
+#if FFETARGET_okCOMPLEX8
+ffebad ffetarget_divide_complex8 (ffetargetComplex8 *res, ffetargetComplex8 l,
+ ffetargetComplex8 r);
+#endif
+#if FFETARGET_okINTEGER1
+bool ffetarget_integer1 (ffetargetInteger1 *val, ffelexToken integer);
+#endif
+#if FFETARGET_okINTEGER2
+bool ffetarget_integer2 (ffetargetInteger2 *val, ffelexToken integer);
+#endif
+#if FFETARGET_okINTEGER3
+bool ffetarget_integer3 (ffetargetInteger3 *val, ffelexToken integer);
+#endif
+#if FFETARGET_okINTEGER4
+bool ffetarget_integer4 (ffetargetInteger4 *val, ffelexToken integer);
+#endif
+#if FFETARGET_okINTEGER5
+bool ffetarget_integer5 (ffetargetInteger5 *val, ffelexToken integer);
+#endif
+#if FFETARGET_okINTEGER6
+bool ffetarget_integer6 (ffetargetInteger6 *val, ffelexToken integer);
+#endif
+#if FFETARGET_okINTEGER7
+bool ffetarget_integer7 (ffetargetInteger7 *val, ffelexToken integer);
+#endif
+#if FFETARGET_okINTEGER8
+bool ffetarget_integer8 (ffetargetInteger8 *val, ffelexToken integer);
+#endif
+bool ffetarget_integerbinary (ffetargetIntegerDefault *val,
+ ffelexToken integer);
+bool ffetarget_integerhex (ffetargetIntegerDefault *val,
+ ffelexToken integer);
+bool ffetarget_integeroctal (ffetargetIntegerDefault *val,
+ ffelexToken integer);
+void ffetarget_integer_bad_magical (ffelexToken t);
+void ffetarget_integer_bad_magical_binary (ffelexToken integer, ffelexToken minus);
+void ffetarget_integer_bad_magical_precedence (ffelexToken integer,
+ ffelexToken uminus,
+ ffelexToken higher_op);
+void ffetarget_integer_bad_magical_precedence_binary (ffelexToken integer,
+ ffelexToken minus,
+ ffelexToken higher_op);
+#if FFETARGET_okCHARACTER1
+bool ffetarget_iszero_character1 (ffetargetCharacter1 constant);
+#endif
+bool ffetarget_iszero_hollerith (ffetargetHollerith constant);
+void ffetarget_layout (char *error_text, ffetargetAlign *alignment,
+ ffetargetAlign *modulo, ffetargetOffset *size,
+ ffeinfoBasictype bt, ffeinfoKindtype kt,
+ ffetargetCharacterSize charsize,
+ ffetargetIntegerDefault num_elements);
+#if FFETARGET_okCOMPLEX1
+ffebad ffetarget_multiply_complex1 (ffetargetComplex1 *res,
+ ffetargetComplex1 l,
+ ffetargetComplex1 r);
+#endif
+#if FFETARGET_okCOMPLEX2
+ffebad ffetarget_multiply_complex2 (ffetargetComplex2 *res,
+ ffetargetComplex2 l,
+ ffetargetComplex2 r);
+#endif
+#if FFETARGET_okCOMPLEX3
+ffebad ffetarget_multiply_complex3 (ffetargetComplex3 *res,
+ ffetargetComplex3 l,
+ ffetargetComplex3 r);
+#endif
+#if FFETARGET_okCOMPLEX4
+ffebad ffetarget_multiply_complex4 (ffetargetComplex4 *res,
+ ffetargetComplex4 l,
+ ffetargetComplex4 r);
+#endif
+#if FFETARGET_okCOMPLEX5
+ffebad ffetarget_multiply_complex5 (ffetargetComplex5 *res,
+ ffetargetComplex5 l,
+ ffetargetComplex5 r);
+#endif
+#if FFETARGET_okCOMPLEX6
+ffebad ffetarget_multiply_complex6 (ffetargetComplex6 *res,
+ ffetargetComplex6 l,
+ ffetargetComplex6 r);
+#endif
+#if FFETARGET_okCOMPLEX7
+ffebad ffetarget_multiply_complex7 (ffetargetComplex7 *res,
+ ffetargetComplex7 l,
+ ffetargetComplex7 r);
+#endif
+#if FFETARGET_okCOMPLEX8
+ffebad ffetarget_multiply_complex8 (ffetargetComplex8 *res,
+ ffetargetComplex8 l,
+ ffetargetComplex8 r);
+#endif
+ffebad ffetarget_power_complexdefault_integerdefault (ffetargetComplexDefault *res,
+ ffetargetComplexDefault l,
+ ffetargetIntegerDefault r);
+#if FFETARGET_okCOMPLEXDOUBLE
+ffebad ffetarget_power_complexdouble_integerdefault (ffetargetComplexDouble *res,
+ ffetargetComplexDouble l,
+ ffetargetIntegerDefault r);
+#endif
+ffebad ffetarget_power_integerdefault_integerdefault (ffetargetIntegerDefault *res,
+ ffetargetIntegerDefault l,
+ ffetargetIntegerDefault r);
+ffebad ffetarget_power_realdefault_integerdefault (ffetargetRealDefault *res,
+ ffetargetRealDefault l,
+ ffetargetIntegerDefault r);
+ffebad ffetarget_power_realdouble_integerdefault (ffetargetRealDouble *res,
+ ffetargetRealDouble l,
+ ffetargetIntegerDefault r);
+void ffetarget_print_binary (FILE *f, ffetargetTypeless val);
+void ffetarget_print_character1 (FILE *f, ffetargetCharacter1 val);
+void ffetarget_print_hollerith (FILE *f, ffetargetHollerith val);
+void ffetarget_print_octal (FILE *f, ffetargetTypeless val);
+void ffetarget_print_hex (FILE *f, ffetargetTypeless val);
+#if FFETARGET_okREAL1
+bool ffetarget_real1 (ffetargetReal1 *value, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits);
+#endif
+#if FFETARGET_okREAL2
+bool ffetarget_real2 (ffetargetReal2 *value, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits);
+#endif
+#if FFETARGET_okREAL3
+bool ffetarget_real3 (ffetargetReal3 *value, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits);
+#endif
+#if FFETARGET_okREAL4
+bool ffetarget_real4 (ffetargetReal4 *value, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits);
+#endif
+#if FFETARGET_okREAL5
+bool ffetarget_real5 (ffetargetReal5 *value, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits);
+#endif
+#if FFETARGET_okREAL6
+bool ffetarget_real6 (ffetargetReal6 *value, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits);
+#endif
+#if FFETARGET_okREAL7
+bool ffetarget_real7 (ffetargetReal7 *value, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits);
+#endif
+#if FFETARGET_okREAL8
+bool ffetarget_real8 (ffetargetReal8 *value, ffelexToken integer,
+ ffelexToken decimal, ffelexToken fraction,
+ ffelexToken exponent, ffelexToken exponent_sign,
+ ffelexToken exponent_digits);
+#endif
+bool ffetarget_typeless_binary (ffetargetTypeless *value, ffelexToken token);
+bool ffetarget_typeless_octal (ffetargetTypeless *value, ffelexToken token);
+bool ffetarget_typeless_hex (ffetargetTypeless *value, ffelexToken token);
+void ffetarget_verify_character1 (mallocPool pool, ffetargetCharacter1 val);
+int ffetarget_num_digits_ (ffelexToken t);
+void *ffetarget_memcpy_ (void *dst, void *src, size_t len);
+
+/* Define macros. */
+
+#if BUILT_FOR_280
+#define FFETARGET_REAL_VALUE_FROM_INT_(resr, lf, kt) \
+ REAL_VALUE_FROM_INT (resr, (long) lf, (long) ((lf < 0) ? -1 : 0), ((kt == 1) ? SFmode : DFmode))
+#else
+#define FFETARGET_REAL_VALUE_FROM_INT_(resr, lf, kt) \
+ REAL_VALUE_FROM_INT (resr, (long) lf, (long) ((lf < 0) ? -1 : 0))
+#endif
+
+#ifdef REAL_ARITHMETIC
+#define ffetarget_add_complex1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, li, rr, ri, resr, resi; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l).real); \
+ li = ffetarget_cvt_r1_to_rv_ ((l).imaginary); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r).real); \
+ ri = ffetarget_cvt_r1_to_rv_ ((r).imaginary); \
+ REAL_ARITHMETIC (resr, PLUS_EXPR, lr, rr); \
+ REAL_ARITHMETIC (resi, PLUS_EXPR, li, ri); \
+ ffetarget_cvt_rv_to_r1_ (resr, (res)->real); \
+ ffetarget_cvt_rv_to_r1_ (resi, (res)->imaginary); \
+ FFEBAD; })
+#define ffetarget_add_complex2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, li, rr, ri, resr, resi; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).real.v[0])); \
+ li = ffetarget_cvt_r2_to_rv_ (&((l).imaginary.v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).real.v[0])); \
+ ri = ffetarget_cvt_r2_to_rv_ (&((r).imaginary.v[0])); \
+ REAL_ARITHMETIC (resr, PLUS_EXPR, lr, rr); \
+ REAL_ARITHMETIC (resi, PLUS_EXPR, li, ri); \
+ ffetarget_cvt_rv_to_r2_ (resr, &((res)->real.v[0])); \
+ ffetarget_cvt_rv_to_r2_ (resi, &((res)->imaginary.v[0])); \
+ FFEBAD; })
+#else
+#define ffetarget_add_complex1(res,l,r) \
+ ((res)->real = (l).real + (r).real, \
+ (res)->imaginary = (l).imaginary + (r).imaginary, FFEBAD)
+#define ffetarget_add_complex2(res,l,r) \
+ ((res)->real = (l).real + (r).real, \
+ (res)->imaginary = (l).imaginary + (r).imaginary, FFEBAD)
+#endif
+#define ffetarget_add_integer1(res,l,r) (*(res) = (l) + (r), FFEBAD)
+#define ffetarget_add_integer2(res,l,r) (*(res) = (l) + (r), FFEBAD)
+#define ffetarget_add_integer3(res,l,r) (*(res) = (l) + (r), FFEBAD)
+#define ffetarget_add_integer4(res,l,r) (*(res) = (l) + (r), FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_add_real1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr, resr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r)); \
+ REAL_ARITHMETIC (resr, PLUS_EXPR, lr, rr); \
+ ffetarget_cvt_rv_to_r1_ (resr, *(res)); \
+ FFEBAD; })
+#define ffetarget_add_real2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr, resr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).v[0])); \
+ REAL_ARITHMETIC (resr, PLUS_EXPR, lr, rr); \
+ ffetarget_cvt_rv_to_r2_ (resr, &((res)->v[0])); \
+ FFEBAD; })
+#else
+#define ffetarget_add_real1(res,l,r) (*(res) = (l) + (r), FFEBAD)
+#define ffetarget_add_real2(res,l,r) (*(res) = (l) + (r), FFEBAD)
+#endif
+#define ffetarget_aggregate_ptr_memcpy(dbt,dkt,sbt,skt) \
+ ((ffetargetCopyfunc) ffetarget_memcpy_)
+#define ffetarget_and_integer1(res,l,r) (*(res) = (l) & (r), FFEBAD)
+#define ffetarget_and_integer2(res,l,r) (*(res) = (l) & (r), FFEBAD)
+#define ffetarget_and_integer3(res,l,r) (*(res) = (l) & (r), FFEBAD)
+#define ffetarget_and_integer4(res,l,r) (*(res) = (l) & (r), FFEBAD)
+#define ffetarget_and_logical1(res,l,r) (*(res) = (l) && (r), FFEBAD)
+#define ffetarget_and_logical2(res,l,r) (*(res) = (l) && (r), FFEBAD)
+#define ffetarget_and_logical3(res,l,r) (*(res) = (l) && (r), FFEBAD)
+#define ffetarget_and_logical4(res,l,r) (*(res) = (l) && (r), FFEBAD)
+#define ffetarget_binarymil(v,t) ffetarget_typeless_binary (v, t)
+#define ffetarget_binaryvxt(v,t) ffetarget_typeless_binary (v, t)
+#define ffetarget_cmp_integer1(l,r) ((l) == (r) ? 0 : ((l) < (r) ? -1 : 1))
+#define ffetarget_cmp_integer2(l,r) ((l) == (r) ? 0 : ((l) < (r) ? -1 : 1))
+#define ffetarget_cmp_integer3(l,r) ((l) == (r) ? 0 : ((l) < (r) ? -1 : 1))
+#define ffetarget_cmp_integer4(l,r) ((l) == (r) ? 0 : ((l) < (r) ? -1 : 1))
+#define ffetarget_cmp_logical1(l,r) ((l) == (r) ? 0 : ((l) < (r) ? -1 : 1))
+#define ffetarget_cmp_logical2(l,r) ((l) == (r) ? 0 : ((l) < (r) ? -1 : 1))
+#define ffetarget_cmp_logical3(l,r) ((l) == (r) ? 0 : ((l) < (r) ? -1 : 1))
+#define ffetarget_cmp_logical4(l,r) ((l) == (r) ? 0 : ((l) < (r) ? -1 : 1))
+#define ffetarget_cmp_real1(l,r) memcmp (&(l), &(r), sizeof(l))
+#define ffetarget_cmp_real2(l,r) memcmp (&(l), &(r), sizeof(l))
+#define ffetarget_cmp_real3(l,r) memcmp (&(l), &(r), sizeof(l))
+#define ffetarget_cmp_typeless(l,r) \
+ memcmp (&(l), &(r), sizeof ((l)))
+#define ffetarget_convert_character1_integer1(res,res_size,l,pool) \
+ ffetarget_convert_character1_integer4(res,res_size,(ffetargetInteger4)l,pool)
+#define ffetarget_convert_character1_integer2(res,res_size,l,pool) \
+ ffetarget_convert_character1_integer4(res,res_size,(ffetargetInteger4)l,pool)
+#define ffetarget_convert_character1_integer3(res,res_size,l,pool) \
+ ffetarget_convert_character1_integer4(res,res_size,(ffetargetInteger4)l,pool)
+#define ffetarget_convert_character1_logical1(res,res_size,l,pool) \
+ ffetarget_convert_character1_logical4(res,res_size,(ffetargetLogical4)l,pool)
+#define ffetarget_convert_character1_logical2(res,res_size,l,pool) \
+ ffetarget_convert_character1_logical4(res,res_size,(ffetargetLogical4)l,pool)
+#define ffetarget_convert_character1_logical3(res,res_size,l,pool) \
+ ffetarget_convert_character1_logical4(res,res_size,(ffetargetLogical4)l,pool)
+#define ffetarget_convert_complex1_character1(res,l) \
+ ffetarget_convert_any_character1_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_complex1_hollerith(res,l) \
+ ffetarget_convert_any_hollerith_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_complex1_typeless(res,l) \
+ ffetarget_convert_any_typeless_ ((char *) (res), sizeof(*(res)), l)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_complex1_complex2(res,l) \
+ ({ REAL_VALUE_TYPE lr, li; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).real.v[0])); \
+ li = ffetarget_cvt_r2_to_rv_ (&((l).imaginary.v[0])); \
+ ffetarget_cvt_rv_to_r1_ (lr, (res)->real); \
+ ffetarget_cvt_rv_to_r1_ (li, (res)->imaginary), \
+ FFEBAD; })
+#else
+#define ffetarget_convert_complex1_complex2(res,l) \
+ ((res)->real = (l).real, (res)->imaginary = (l).imaginary, FFEBAD)
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_complex1_integer(res,l) \
+ ({ REAL_VALUE_TYPE resi, resr; \
+ ffetargetInteger1 lf = (l); \
+ FFETARGET_REAL_VALUE_FROM_INT_ (resr, lf, 1); \
+ resi = dconst0; \
+ ffetarget_cvt_rv_to_r1_ (resr, (res)->real); \
+ ffetarget_cvt_rv_to_r1_ (resi, (res)->imaginary); \
+ FFEBAD; })
+#else
+#define ffetarget_convert_complex1_integer(res,l) \
+ ((res)->real = (l), (res)->imaginary = 0, FFEBAD)
+#endif
+#define ffetarget_convert_complex1_integer1 ffetarget_convert_complex1_integer
+#define ffetarget_convert_complex1_integer2 ffetarget_convert_complex1_integer
+#define ffetarget_convert_complex1_integer3 ffetarget_convert_complex1_integer
+#define ffetarget_convert_complex1_integer4 ffetarget_convert_complex1_integer
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_complex1_real1(res,l) \
+ ((res)->real = (l), \
+ ffetarget_cvt_rv_to_r1_ (dconst0, (res)->imaginary), \
+ FFEBAD)
+#define ffetarget_convert_complex1_real2(res,l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ ffetarget_cvt_rv_to_r1_ (lr, (res)->real); \
+ ffetarget_cvt_rv_to_r1_ (dconst0, (res)->imaginary), \
+ FFEBAD; })
+#else
+#define ffetarget_convert_complex1_real1(res,l) \
+ ((res)->real = (l), (res)->imaginary = 0, FFEBAD)
+#define ffetarget_convert_complex1_real2(res,l) \
+ ((res)->real = (l), (res)->imaginary = 0, FFEBAD)
+#endif
+#define ffetarget_convert_complex2_character1(res,l) \
+ ffetarget_convert_any_character1_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_complex2_hollerith(res,l) \
+ ffetarget_convert_any_hollerith_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_complex2_typeless(res,l) \
+ ffetarget_convert_any_typeless_ ((char *) (res), sizeof(*(res)), l)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_complex2_complex1(res,l) \
+ ({ REAL_VALUE_TYPE lr, li; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l).real); \
+ li = ffetarget_cvt_r1_to_rv_ ((l).imaginary); \
+ ffetarget_cvt_rv_to_r2_ (lr, &((res)->real.v[0])); \
+ ffetarget_cvt_rv_to_r2_ (li, &((res)->imaginary.v[0])), \
+ FFEBAD; })
+#else
+#define ffetarget_convert_complex2_complex1(res,l) \
+ ((res)->real = (l).real, (res)->imaginary = (l).imaginary, FFEBAD)
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_complex2_integer(res,l) \
+ ({ REAL_VALUE_TYPE resi, resr; \
+ ffetargetInteger1 lf = (l); \
+ FFETARGET_REAL_VALUE_FROM_INT_ (resr, lf, 2); \
+ resi = dconst0; \
+ ffetarget_cvt_rv_to_r2_ (resr, &((res)->real.v[0])); \
+ ffetarget_cvt_rv_to_r2_ (resi, &((res)->imaginary.v[0])); \
+ FFEBAD; })
+#else
+#define ffetarget_convert_complex2_integer(res,l) \
+ ((res)->real = (l), (res)->imaginary = 0, FFEBAD)
+#endif
+#define ffetarget_convert_complex2_integer1 ffetarget_convert_complex2_integer
+#define ffetarget_convert_complex2_integer2 ffetarget_convert_complex2_integer
+#define ffetarget_convert_complex2_integer3 ffetarget_convert_complex2_integer
+#define ffetarget_convert_complex2_integer4 ffetarget_convert_complex2_integer
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_complex2_real1(res,l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r1_to_rv_ (l); \
+ ffetarget_cvt_rv_to_r2_ (lr, &((res)->real.v[0])); \
+ ffetarget_cvt_rv_to_r2_ (dconst0, &((res)->imaginary.v[0])), \
+ FFEBAD; })
+#define ffetarget_convert_complex2_real2(res,l) \
+ ((res)->real = (l), \
+ ffetarget_cvt_rv_to_r2_ (dconst0, &((res)->imaginary.v[0])), \
+ FFEBAD)
+#else
+#define ffetarget_convert_complex2_real1(res,l) \
+ ((res)->real = (l), (res)->imaginary = 0, FFEBAD)
+#define ffetarget_convert_complex2_real2(res,l) \
+ ((res)->real = (l), (res)->imaginary = 0, FFEBAD)
+#endif
+#define ffetarget_convert_integer2_character1(res,l) \
+ ffetarget_convert_integer1_character1(res,l)
+#define ffetarget_convert_integer2_complex1(res,l) \
+ ffetarget_convert_integer1_complex1(res,l)
+#define ffetarget_convert_integer2_complex2(res,l) \
+ ffetarget_convert_integer1_complex2(res,l)
+#define ffetarget_convert_integer2_hollerith(res,l) \
+ ffetarget_convert_integer1_hollerith(res,l)
+#define ffetarget_convert_integer2_integer1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer2_integer3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer2_integer4(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer2_logical1(res,l) \
+ ffetarget_convert_integer1_logical1(res,l)
+#define ffetarget_convert_integer2_logical2(res,l) \
+ ffetarget_convert_integer2_logical1(res,l)
+#define ffetarget_convert_integer2_logical3(res,l) \
+ ffetarget_convert_integer2_logical1(res,l)
+#define ffetarget_convert_integer2_logical4(res,l) \
+ ffetarget_convert_integer2_logical1(res,l)
+#define ffetarget_convert_integer2_real1(res,l) \
+ ffetarget_convert_integer1_real1(res,l)
+#define ffetarget_convert_integer2_real2(res,l) \
+ ffetarget_convert_integer1_real2(res,l)
+#define ffetarget_convert_integer2_typeless(res,l) \
+ ffetarget_convert_integer1_typeless(res,l)
+#define ffetarget_convert_integer3_character1(res,l) \
+ ffetarget_convert_integer1_character1(res,l)
+#define ffetarget_convert_integer3_complex1(res,l) \
+ ffetarget_convert_integer1_complex1(res,l)
+#define ffetarget_convert_integer3_complex2(res,l) \
+ ffetarget_convert_integer1_complex2(res,l)
+#define ffetarget_convert_integer3_hollerith(res,l) \
+ ffetarget_convert_integer1_hollerith(res,l)
+#define ffetarget_convert_integer3_integer1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer3_integer2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer3_integer4(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer3_logical1(res,l) \
+ ffetarget_convert_integer1_logical1(res,l)
+#define ffetarget_convert_integer3_logical2(res,l) \
+ ffetarget_convert_integer3_logical1(res,l)
+#define ffetarget_convert_integer3_logical3(res,l) \
+ ffetarget_convert_integer3_logical1(res,l)
+#define ffetarget_convert_integer3_logical4(res,l) \
+ ffetarget_convert_integer3_logical1(res,l)
+#define ffetarget_convert_integer3_real1(res,l) \
+ ffetarget_convert_integer1_real1(res,l)
+#define ffetarget_convert_integer3_real2(res,l) \
+ ffetarget_convert_integer1_real2(res,l)
+#define ffetarget_convert_integer3_typeless(res,l) \
+ ffetarget_convert_integer1_typeless(res,l)
+#define ffetarget_convert_integer4_character1(res,l) \
+ ffetarget_convert_integer1_character1(res,l)
+#define ffetarget_convert_integer4_complex1(res,l) \
+ ffetarget_convert_integer1_complex1(res,l)
+#define ffetarget_convert_integer4_complex2(res,l) \
+ ffetarget_convert_integer1_complex2(res,l)
+#define ffetarget_convert_integer4_hollerith(res,l) \
+ ffetarget_convert_integer1_hollerith(res,l)
+#define ffetarget_convert_integer4_integer1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer4_integer2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer4_integer3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer4_logical1(res,l) \
+ ffetarget_convert_integer1_logical1(res,l)
+#define ffetarget_convert_integer4_logical2(res,l) \
+ ffetarget_convert_integer1_logical1(res,l)
+#define ffetarget_convert_integer4_logical3(res,l) \
+ ffetarget_convert_integer1_logical1(res,l)
+#define ffetarget_convert_integer4_logical4(res,l) \
+ ffetarget_convert_integer1_logical1(res,l)
+#define ffetarget_convert_integer4_real1(res,l) \
+ ffetarget_convert_integer1_real1(res,l)
+#define ffetarget_convert_integer4_real2(res,l) \
+ ffetarget_convert_integer1_real2(res,l)
+#define ffetarget_convert_integer4_typeless(res,l) \
+ ffetarget_convert_integer1_typeless(res,l)
+#define ffetarget_convert_logical1_character1(res,l) \
+ ffetarget_convert_any_character1_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical1_hollerith(res,l) \
+ ffetarget_convert_any_hollerith_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical1_typeless(res,l) \
+ ffetarget_convert_any_typeless_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical1_logical2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical1_logical3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical1_logical4(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical1_integer1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical1_integer2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical1_integer3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical1_integer4(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical2_character1(res,l) \
+ ffetarget_convert_any_character1_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical2_hollerith(res,l) \
+ ffetarget_convert_any_hollerith_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical2_typeless(res,l) \
+ ffetarget_convert_any_typeless_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical2_logical1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical2_logical3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical2_logical4(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical2_integer1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical2_integer2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical2_integer3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical2_integer4(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical3_character1(res,l) \
+ ffetarget_convert_any_character1_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical3_hollerith(res,l) \
+ ffetarget_convert_any_hollerith_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical3_typeless(res,l) \
+ ffetarget_convert_any_typeless_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical3_logical1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical3_logical2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical3_logical4(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical3_integer1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical3_integer2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical3_integer3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical3_integer4(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical4_character1(res,l) \
+ ffetarget_convert_any_character1_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical4_hollerith(res,l) \
+ ffetarget_convert_any_hollerith_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical4_typeless(res,l) \
+ ffetarget_convert_any_typeless_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_logical4_logical1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical4_logical2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical4_logical3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical4_integer1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical4_integer2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical4_integer3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_logical4_integer4(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer1_character1(res,l) \
+ ffetarget_convert_any_character1_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_integer1_hollerith(res,l) \
+ ffetarget_convert_any_hollerith_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_integer1_typeless(res,l) \
+ ffetarget_convert_any_typeless_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_integer1_integer2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer1_integer3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer1_integer4(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer1_logical1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer1_logical2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer1_logical3(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer1_logical4(res,l) (*(res) = (l), FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_integer1_real1(res,l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r1_to_rv_ (l); \
+ REAL_VALUE_TO_INT (&ffetarget_long_val_, &ffetarget_long_junk_, lr); \
+ *(res) = ffetarget_long_val_; \
+ FFEBAD; })
+#define ffetarget_convert_integer1_real2(res,l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ REAL_VALUE_TO_INT (&ffetarget_long_val_, &ffetarget_long_junk_, lr); \
+ *(res) = ffetarget_long_val_; \
+ FFEBAD; })
+#define ffetarget_convert_integer1_complex1(res,l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l).real); \
+ REAL_VALUE_TO_INT (&ffetarget_long_val_, &ffetarget_long_junk_, lr); \
+ *(res) = ffetarget_long_val_; \
+ FFEBAD; })
+#define ffetarget_convert_integer1_complex2(res,l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).real.v[0])); \
+ REAL_VALUE_TO_INT (&ffetarget_long_val_, &ffetarget_long_junk_, lr); \
+ *(res) = ffetarget_long_val_; \
+ FFEBAD; })
+#else
+#define ffetarget_convert_integer1_real1(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer1_real2(res,l) (*(res) = (l), FFEBAD)
+#define ffetarget_convert_integer1_complex1(res,l) (*(res) = (l).real, FFEBAD)
+#define ffetarget_convert_integer1_complex2(res,l) (*(res) = (l).real, FFEBAD)
+#endif
+#define ffetarget_convert_real1_character1(res,l) \
+ ffetarget_convert_any_character1_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_real1_hollerith(res,l) \
+ ffetarget_convert_any_hollerith_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_real1_integer2(res,l) \
+ ffetarget_convert_real1_integer1(res,l)
+#define ffetarget_convert_real1_integer3(res,l) \
+ ffetarget_convert_real1_integer1(res,l)
+#define ffetarget_convert_real1_integer4(res,l) \
+ ffetarget_convert_real1_integer1(res,l)
+#define ffetarget_convert_real1_typeless(res,l) \
+ ffetarget_convert_any_typeless_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_real1_complex1(res,l) (*(res) = (l).real, FFEBAD)
+#define ffetarget_convert_real1_complex2(res,l) \
+ ffetarget_convert_real1_real2 ((res), (l).real)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_real1_integer1(res,l) \
+ ({ REAL_VALUE_TYPE resr; \
+ ffetargetInteger1 lf = (l); \
+ FFETARGET_REAL_VALUE_FROM_INT_ (resr, lf, 1); \
+ ffetarget_cvt_rv_to_r1_ (resr, *(res)); \
+ FFEBAD; })
+#else
+#define ffetarget_convert_real1_integer1(res,l) (*(res) = (l), FFEBAD)
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_real1_real2(res,l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ ffetarget_cvt_rv_to_r1_ (lr, *(res)); \
+ FFEBAD; })
+#else
+#define ffetarget_convert_real1_real2(res,l) (*(res) = (l), FFEBAD)
+#endif
+#define ffetarget_convert_real2_character1(res,l) \
+ ffetarget_convert_any_character1_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_real2_hollerith(res,l) \
+ ffetarget_convert_any_hollerith_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_real2_integer2(res,l) \
+ ffetarget_convert_real2_integer1(res,l)
+#define ffetarget_convert_real2_integer3(res,l) \
+ ffetarget_convert_real2_integer1(res,l)
+#define ffetarget_convert_real2_integer4(res,l) \
+ ffetarget_convert_real2_integer1(res,l)
+#define ffetarget_convert_real2_typeless(res,l) \
+ ffetarget_convert_any_typeless_ ((char *) (res), sizeof(*(res)), l)
+#define ffetarget_convert_real2_complex1(res,l) \
+ ffetarget_convert_real2_real1 ((res), (l).real)
+#define ffetarget_convert_real2_complex2(res,l) (*(res) = (l).real, FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_real2_integer(res,l) \
+ ({ REAL_VALUE_TYPE resr; \
+ ffetargetInteger1 lf = (l); \
+ FFETARGET_REAL_VALUE_FROM_INT_ (resr, lf, 2); \
+ ffetarget_cvt_rv_to_r2_ (resr, &((res)->v[0])); \
+ FFEBAD; })
+#define ffetarget_convert_real2_integer1 ffetarget_convert_real2_integer
+#else
+#define ffetarget_convert_real2_integer1(res,l) (*(res) = (l), FFEBAD)
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_convert_real2_real1(res,l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ ffetarget_cvt_rv_to_r2_ (lr, &((res)->v[0])); \
+ FFEBAD; })
+#else
+#define ffetarget_convert_real2_real1(res,l) (*(res) = (l), FFEBAD)
+#endif
+#define ffetarget_divide_integer1(res,l,r) \
+ (((r) == 0) ? (*(res) = 0, FFEBAD_DIV_BY_ZERO) \
+ : (*(res) = (l) / (r), FFEBAD))
+#define ffetarget_divide_integer2(res,l,r) \
+ ffetarget_divide_integer1(res,l,r)
+#define ffetarget_divide_integer3(res,l,r) \
+ ffetarget_divide_integer1(res,l,r)
+#define ffetarget_divide_integer4(res,l,r) \
+ ffetarget_divide_integer1(res,l,r)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_divide_real1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr, resr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r)); \
+ REAL_VALUES_EQUAL (rr, dconst0) \
+ ? ({ ffetarget_cvt_rv_to_r1_ (dconst0, *(res)); \
+ FFEBAD_DIV_BY_ZERO; \
+ }) \
+ : ({ REAL_ARITHMETIC (resr, RDIV_EXPR, lr, rr); \
+ ffetarget_cvt_rv_to_r1_ (resr, *(res)); \
+ FFEBAD; \
+ }); \
+ })
+#define ffetarget_divide_real2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr, resr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).v[0])); \
+ REAL_VALUES_EQUAL (rr, dconst0) \
+ ? ({ ffetarget_cvt_rv_to_r2_ (dconst0, &((res)->v[0])); \
+ FFEBAD_DIV_BY_ZERO; \
+ }) \
+ : ({ REAL_ARITHMETIC (resr, RDIV_EXPR, lr, rr); \
+ ffetarget_cvt_rv_to_r2_ (resr, &((res)->v[0])); \
+ FFEBAD; \
+ }); \
+ })
+#else
+#define ffetarget_divide_real1(res,l,r) \
+ (((r) == 0) ? (*(res) = 0, FFEBAD_DIV_BY_ZERO) \
+ : (*(res) = (l) / (r), FFEBAD))
+#define ffetarget_divide_real2(res,l,r) \
+ (((r) == 0) ? (*(res) = 0, FFEBAD_DIV_BY_ZERO) \
+ : (*(res) = (l) / (r), FFEBAD))
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_eq_complex1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, li, rr, ri; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l).real); \
+ li = ffetarget_cvt_r1_to_rv_ ((l).imaginary); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r).real); \
+ ri = ffetarget_cvt_r1_to_rv_ ((r).imaginary); \
+ *(res) = (REAL_VALUES_EQUAL (lr, rr) && REAL_VALUES_EQUAL (li, ri)) \
+ ? TRUE : FALSE; \
+ FFEBAD; })
+#define ffetarget_eq_complex2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, li, rr, ri; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).real.v[0])); \
+ li = ffetarget_cvt_r2_to_rv_ (&((l).imaginary.v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).real.v[0])); \
+ ri = ffetarget_cvt_r2_to_rv_ (&((r).imaginary.v[0])); \
+ *(res) = (REAL_VALUES_EQUAL (lr, rr) && REAL_VALUES_EQUAL (li, ri)) \
+ ? TRUE : FALSE; \
+ FFEBAD; })
+#else
+#define ffetarget_eq_complex1(res,l,r) \
+ (*(res) = (((l).real == (r).real) && ((l).imaginary == (r).imaginary)) \
+ ? TRUE : FALSE, FFEBAD)
+#define ffetarget_eq_complex2(res,l,r) \
+ (*(res) = (((l).real == (r).real) && ((l).imaginary == (r).imaginary)) \
+ ? TRUE : FALSE, FFEBAD)
+#endif
+#define ffetarget_eq_integer1(res,l,r) \
+ (*(res) = ((l) == (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_eq_integer2(res,l,r) \
+ (*(res) = ((l) == (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_eq_integer3(res,l,r) \
+ (*(res) = ((l) == (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_eq_integer4(res,l,r) \
+ (*(res) = ((l) == (r)) ? TRUE : FALSE, FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_eq_real1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r)); \
+ *(res) = REAL_VALUES_EQUAL (lr, rr) ? TRUE : FALSE; \
+ FFEBAD; })
+#define ffetarget_eq_real2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).v[0])); \
+ *(res) = REAL_VALUES_EQUAL (lr, rr) ? TRUE : FALSE; \
+ FFEBAD; })
+#else
+#define ffetarget_eq_real1(res,l,r) \
+ (*(res) = ((l) == (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_eq_real2(res,l,r) \
+ (*(res) = ((l) == (r)) ? TRUE : FALSE, FFEBAD)
+#endif
+#define ffetarget_eqv_integer1(res,l,r) (*(res) = (l) ^ ~(r), FFEBAD)
+#define ffetarget_eqv_integer2(res,l,r) (*(res) = (l) ^ ~(r), FFEBAD)
+#define ffetarget_eqv_integer3(res,l,r) (*(res) = (l) ^ ~(r), FFEBAD)
+#define ffetarget_eqv_integer4(res,l,r) (*(res) = (l) ^ ~(r), FFEBAD)
+#define ffetarget_eqv_logical1(res,l,r) (*(res) = (l) == (r), FFEBAD)
+#define ffetarget_eqv_logical2(res,l,r) (*(res) = (l) == (r), FFEBAD)
+#define ffetarget_eqv_logical3(res,l,r) (*(res) = (l) == (r), FFEBAD)
+#define ffetarget_eqv_logical4(res,l,r) (*(res) = (l) == (r), FFEBAD)
+#define ffetarget_ge_integer1(res,l,r) \
+ (*(res) = ((l) >= (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_ge_integer2(res,l,r) \
+ (*(res) = ((l) >= (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_ge_integer3(res,l,r) \
+ (*(res) = ((l) >= (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_ge_integer4(res,l,r) \
+ (*(res) = ((l) >= (r)) ? TRUE : FALSE, FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_ge_real1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r)); \
+ *(res) = REAL_VALUES_LESS (lr, rr) ? FALSE : TRUE; \
+ FFEBAD; })
+#define ffetarget_ge_real2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).v[0])); \
+ *(res) = REAL_VALUES_LESS (lr, rr) ? FALSE : TRUE; \
+ FFEBAD; })
+#else
+#define ffetarget_ge_real1(res,l,r) \
+ (*(res) = ((l) >= (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_ge_real2(res,l,r) \
+ (*(res) = ((l) >= (r)) ? TRUE : FALSE, FFEBAD)
+#endif
+#define ffetarget_gt_integer1(res,l,r) \
+ (*(res) = ((l) > (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_gt_integer2(res,l,r) \
+ (*(res) = ((l) > (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_gt_integer3(res,l,r) \
+ (*(res) = ((l) > (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_gt_integer4(res,l,r) \
+ (*(res) = ((l) > (r)) ? TRUE : FALSE, FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_gt_real1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r)); \
+ *(res) = (REAL_VALUES_LESS (lr, rr) || REAL_VALUES_EQUAL (lr, rr)) \
+ ? FALSE : TRUE; \
+ FFEBAD; })
+#define ffetarget_gt_real2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).v[0])); \
+ *(res) = (REAL_VALUES_LESS (lr, rr) || REAL_VALUES_EQUAL (lr, rr)) \
+ ? FALSE : TRUE; \
+ FFEBAD; })
+#else
+#define ffetarget_gt_real1(res,l,r) \
+ (*(res) = ((l) > (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_gt_real2(res,l,r) \
+ (*(res) = ((l) > (r)) ? TRUE : FALSE, FFEBAD)
+#endif
+#define ffetarget_hexxmil(v,t) ffetarget_typeless_hex (v, t)
+#define ffetarget_hexxvxt(v,t) ffetarget_typeless_hex (v, t)
+#define ffetarget_hexzmil(v,t) ffetarget_typeless_hex (v, t)
+#define ffetarget_hexzvxt(v,t) ffetarget_typeless_hex (v, t)
+#define ffetarget_init_0()
+#define ffetarget_init_1()
+#define ffetarget_init_2()
+#define ffetarget_init_3()
+#define ffetarget_init_4()
+#ifndef __alpha__
+#define ffetarget_integerdefault_is_magical(i) \
+ (((unsigned long int) i) == FFETARGET_integerBIG_MAGICAL)
+#else
+#define ffetarget_integerdefault_is_magical(i) \
+ (((unsigned int) i) == FFETARGET_integerBIG_MAGICAL)
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_iszero_real1(l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ REAL_VALUES_EQUAL (lr, dconst0); \
+ })
+#define ffetarget_iszero_real2(l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ REAL_VALUES_EQUAL (lr, dconst0); \
+ })
+#else
+#define ffetarget_iszero_real1(l) ((l) == 0.)
+#define ffetarget_iszero_real2(l) ((l) == 0.)
+#endif
+#define ffetarget_iszero_typeless(l) ((l) == 0)
+#define ffetarget_logical1(v,truth) (*(v) = truth ? 1 : 0)
+#define ffetarget_le_integer1(res,l,r) \
+ (*(res) = ((l) <= (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_le_integer2(res,l,r) \
+ (*(res) = ((l) <= (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_le_integer3(res,l,r) \
+ (*(res) = ((l) <= (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_le_integer4(res,l,r) \
+ (*(res) = ((l) <= (r)) ? TRUE : FALSE, FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_le_real1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r)); \
+ *(res) = (REAL_VALUES_LESS (lr, rr) || REAL_VALUES_EQUAL (lr, rr)) \
+ ? TRUE : FALSE; \
+ FFEBAD; })
+#define ffetarget_le_real2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).v[0])); \
+ *(res) = (REAL_VALUES_LESS (lr, rr) || REAL_VALUES_EQUAL (lr, rr)) \
+ ? TRUE : FALSE; \
+ FFEBAD; })
+#else
+#define ffetarget_le_real1(res,l,r) \
+ (*(res) = ((l) <= (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_le_real2(res,l,r) \
+ (*(res) = ((l) <= (r)) ? TRUE : FALSE, FFEBAD)
+#endif
+#define ffetarget_lt_integer1(res,l,r) \
+ (*(res) = ((l) < (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_lt_integer2(res,l,r) \
+ (*(res) = ((l) < (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_lt_integer3(res,l,r) \
+ (*(res) = ((l) < (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_lt_integer4(res,l,r) \
+ (*(res) = ((l) < (r)) ? TRUE : FALSE, FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_lt_real1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r)); \
+ *(res) = REAL_VALUES_LESS (lr, rr) ? TRUE : FALSE; \
+ FFEBAD; })
+#define ffetarget_lt_real2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).v[0])); \
+ *(res) = REAL_VALUES_LESS (lr, rr) ? TRUE : FALSE; \
+ FFEBAD; })
+#else
+#define ffetarget_lt_real1(res,l,r) \
+ (*(res) = ((l) < (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_lt_real2(res,l,r) \
+ (*(res) = ((l) < (r)) ? TRUE : FALSE, FFEBAD)
+#endif
+#define ffetarget_length_character1(c) ((c).length)
+#define ffetarget_length_characterdefault ffetarget_length_character1
+#ifdef REAL_ARITHMETIC
+#define ffetarget_make_real1(res,lr) \
+ ffetarget_cvt_rv_to_r1_ ((lr), *(res))
+#define ffetarget_make_real2(res,lr) \
+ ffetarget_cvt_rv_to_r2_ ((lr), &((res)->v[0]))
+#else
+#define ffetarget_make_real1(res,lr) (*(res) = (lr))
+#define ffetarget_make_real2(res,lr) (*(res) = (lr))
+#endif
+#define ffetarget_multiply_integer1(res,l,r) (*(res) = (l) * (r), FFEBAD)
+#define ffetarget_multiply_integer2(res,l,r) (*(res) = (l) * (r), FFEBAD)
+#define ffetarget_multiply_integer3(res,l,r) (*(res) = (l) * (r), FFEBAD)
+#define ffetarget_multiply_integer4(res,l,r) (*(res) = (l) * (r), FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_multiply_real1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr, resr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r)); \
+ REAL_ARITHMETIC (resr, MULT_EXPR, lr, rr); \
+ ffetarget_cvt_rv_to_r1_ (resr, *(res)); \
+ FFEBAD; })
+#define ffetarget_multiply_real2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr, resr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).v[0])); \
+ REAL_ARITHMETIC (resr, MULT_EXPR, lr, rr); \
+ ffetarget_cvt_rv_to_r2_ (resr, &((res)->v[0])); \
+ FFEBAD; })
+#else
+#define ffetarget_multiply_real1(res,l,r) (*(res) = (l) * (r), FFEBAD)
+#define ffetarget_multiply_real2(res,l,r) (*(res) = (l) * (r), FFEBAD)
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_ne_complex1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, li, rr, ri; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l).real); \
+ li = ffetarget_cvt_r1_to_rv_ ((l).imaginary); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r).real); \
+ ri = ffetarget_cvt_r1_to_rv_ ((r).imaginary); \
+ *(res) = (REAL_VALUES_EQUAL (lr, rr) && REAL_VALUES_EQUAL (li, ri)) \
+ ? FALSE : TRUE; \
+ FFEBAD; })
+#define ffetarget_ne_complex2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, li, rr, ri; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).real.v[0])); \
+ li = ffetarget_cvt_r2_to_rv_ (&((l).imaginary.v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).real.v[0])); \
+ ri = ffetarget_cvt_r2_to_rv_ (&((r).imaginary.v[0])); \
+ *(res) = (REAL_VALUES_EQUAL (lr, rr) && REAL_VALUES_EQUAL (li, ri)) \
+ ? FALSE : TRUE; \
+ FFEBAD; })
+#else
+#define ffetarget_ne_complex1(res,l,r) \
+ (*(res) = (((l).real != (r).real) || ((l).imaginary != (r).imaginary)) \
+ ? TRUE : FALSE, FFEBAD)
+#define ffetarget_ne_complex2(res,l,r) \
+ (*(res) = (((l).real != (r).real) || ((l).imaginary != (r).imaginary)) \
+ ? TRUE : FALSE, FFEBAD)
+#endif
+#define ffetarget_ne_integer1(res,l,r) \
+ (*(res) = ((l) != (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_ne_integer2(res,l,r) \
+ (*(res) = ((l) != (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_ne_integer3(res,l,r) \
+ (*(res) = ((l) != (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_ne_integer4(res,l,r) \
+ (*(res) = ((l) != (r)) ? TRUE : FALSE, FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_ne_real1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r)); \
+ *(res) = REAL_VALUES_EQUAL (lr, rr) ? FALSE : TRUE; \
+ FFEBAD; })
+#define ffetarget_ne_real2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).v[0])); \
+ *(res) = REAL_VALUES_EQUAL (lr, rr) ? FALSE : TRUE; \
+ FFEBAD; })
+#else
+#define ffetarget_ne_real1(res,l,r) \
+ (*(res) = ((l) != (r)) ? TRUE : FALSE, FFEBAD)
+#define ffetarget_ne_real2(res,l,r) \
+ (*(res) = ((l) != (r)) ? TRUE : FALSE, FFEBAD)
+#endif
+#define ffetarget_neqv_integer1(res,l,r) (*(res) = (l) ^ (r), FFEBAD)
+#define ffetarget_neqv_integer2(res,l,r) (*(res) = (l) ^ (r), FFEBAD)
+#define ffetarget_neqv_integer3(res,l,r) (*(res) = (l) ^ (r), FFEBAD)
+#define ffetarget_neqv_integer4(res,l,r) (*(res) = (l) ^ (r), FFEBAD)
+#define ffetarget_neqv_logical1(res,l,r) (*(res) = (l) != (r), FFEBAD)
+#define ffetarget_neqv_logical2(res,l,r) (*(res) = (l) != (r), FFEBAD)
+#define ffetarget_neqv_logical3(res,l,r) (*(res) = (l) != (r), FFEBAD)
+#define ffetarget_neqv_logical4(res,l,r) (*(res) = (l) != (r), FFEBAD)
+#define ffetarget_not_integer1(res,l) (*(res) = ~(l), FFEBAD)
+#define ffetarget_not_integer2(res,l) (*(res) = ~(l), FFEBAD)
+#define ffetarget_not_integer3(res,l) (*(res) = ~(l), FFEBAD)
+#define ffetarget_not_integer4(res,l) (*(res) = ~(l), FFEBAD)
+#define ffetarget_not_logical1(res,l) (*(res) = !(l), FFEBAD)
+#define ffetarget_not_logical2(res,l) (*(res) = !(l), FFEBAD)
+#define ffetarget_not_logical3(res,l) (*(res) = !(l), FFEBAD)
+#define ffetarget_not_logical4(res,l) (*(res) = !(l), FFEBAD)
+#define ffetarget_octalmil(v,t) ffetarget_typeless_octal (v, t)
+#define ffetarget_octalvxt(v,t) ffetarget_typeless_octal (v, t)
+#define ffetarget_offset(res,l) (*(res) = (l), TRUE) /* Overflow? */
+#define ffetarget_offset_add(res,l,r) (*(res) = (l) + (r), TRUE) /* Overflow? */
+#define ffetarget_offset_charsize(res,l,u) (*(res) = (l) * (u), TRUE) /* Ov? */
+#define ffetarget_offset_multiply(res,l,r) (*(res) = (l) * (r), TRUE) /* Ov? */
+#define ffetarget_offset_overflow(text) ((void) 0) /* ~~no message? */
+#define ffetarget_or_integer1(res,l,r) (*(res) = (l) | (r), FFEBAD)
+#define ffetarget_or_integer2(res,l,r) (*(res) = (l) | (r), FFEBAD)
+#define ffetarget_or_integer3(res,l,r) (*(res) = (l) | (r), FFEBAD)
+#define ffetarget_or_integer4(res,l,r) (*(res) = (l) | (r), FFEBAD)
+#define ffetarget_or_logical1(res,l,r) (*(res) = (l) || (r), FFEBAD)
+#define ffetarget_or_logical2(res,l,r) (*(res) = (l) || (r), FFEBAD)
+#define ffetarget_or_logical3(res,l,r) (*(res) = (l) || (r), FFEBAD)
+#define ffetarget_or_logical4(res,l,r) (*(res) = (l) || (r), FFEBAD)
+#define ffetarget_print_binarymil(f,v) ffetarget_print_binary (f, v)
+#define ffetarget_print_binaryvxt(f,v) ffetarget_print_binary (f, v)
+#define ffetarget_print_hexxmil(f,v) ffetarget_print_hex (f, v)
+#define ffetarget_print_hexxvxt(f,v) ffetarget_print_hex (f, v)
+#define ffetarget_print_hexzmil(f,v) ffetarget_print_hex (f, v)
+#define ffetarget_print_hexzvxt(f,v) ffetarget_print_hex (f, v)
+#define ffetarget_print_integer1(f,v) \
+ fprintf ((f), "%" ffetargetInteger1_f "d", (v))
+#define ffetarget_print_integer2(f,v) \
+ fprintf ((f), "%" ffetargetInteger2_f "d", (v))
+#define ffetarget_print_integer3(f,v) \
+ fprintf ((f), "%" ffetargetInteger3_f "d", (v))
+#define ffetarget_print_integer4(f,v) \
+ fprintf ((f), "%" ffetargetInteger4_f "d", (v))
+#define ffetarget_print_logical1(f,v) \
+ fprintf ((f), "%" ffetargetLogical1_f "d", (v))
+#define ffetarget_print_logical2(f,v) \
+ fprintf ((f), "%" ffetargetLogical2_f "d", (v))
+#define ffetarget_print_logical3(f,v) \
+ fprintf ((f), "%" ffetargetLogical3_f "d", (v))
+#define ffetarget_print_logical4(f,v) \
+ fprintf ((f), "%" ffetargetLogical4_f "d", (v))
+#define ffetarget_print_octalmil(f,v) ffetarget_print_octal(f,v)
+#define ffetarget_print_octalvxt(f,v) ffetarget_print_octal(f,v)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_print_real1(f,l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ REAL_VALUE_TO_DECIMAL (lr, bad_fmt_val??, ffetarget_string_); \
+ fputs (ffetarget_string_, (f)); \
+ })
+#define ffetarget_print_real2(f,l) \
+ ({ REAL_VALUE_TYPE lr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ REAL_VALUE_TO_DECIMAL (lr, bad_fmt_val??, ffetarget_string_); \
+ fputs (ffetarget_string_, (f)); \
+ })
+#else
+#define ffetarget_print_real1(f,v) \
+ fprintf ((f), "%" ffetargetReal1_f "g", (v))
+#define ffetarget_print_real2(f,v) \
+ fprintf ((f), "%" ffetargetReal2_f "g", (v))
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_real1_one(res) ffetarget_cvt_rv_to_r1_ (dconst1, *(res))
+#define ffetarget_real2_one(res) ffetarget_cvt_rv_to_r2_ (dconst1, &((res)->v[0]))
+#else
+#define ffetarget_real1_one(res) (*(res) = (float) 1.)
+#define ffetarget_real2_one(res) (*(res) = 1.)
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_real1_two(res) ffetarget_cvt_rv_to_r1_ (dconst2, *(res))
+#define ffetarget_real2_two(res) ffetarget_cvt_rv_to_r2_ (dconst2, &((res)->v[0]))
+#else
+#define ffetarget_real1_two(res) (*(res) = (float) 2.)
+#define ffetarget_real2_two(res) (*(res) = 2.)
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_real1_zero(res) ffetarget_cvt_rv_to_r1_ (dconst0, *(res))
+#define ffetarget_real2_zero(res) ffetarget_cvt_rv_to_r2_ (dconst0, &((res)->v[0]))
+#else
+#define ffetarget_real1_zero(res) (*(res) = (float) 0.)
+#define ffetarget_real2_zero(res) (*(res) = 0.)
+#endif
+#define ffetarget_size_typeless_binary(t) ((ffetarget_num_digits_(t) + 7) / 8)
+#define ffetarget_size_typeless_octal(t) \
+ ((ffetarget_num_digits_(t) * 3 + 7) / 8)
+#define ffetarget_size_typeless_hex(t) ((ffetarget_num_digits_(t) + 1) / 2)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_subtract_complex1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, li, rr, ri, resr, resi; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l).real); \
+ li = ffetarget_cvt_r1_to_rv_ ((l).imaginary); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r).real); \
+ ri = ffetarget_cvt_r1_to_rv_ ((r).imaginary); \
+ REAL_ARITHMETIC (resr, MINUS_EXPR, lr, rr); \
+ REAL_ARITHMETIC (resi, MINUS_EXPR, li, ri); \
+ ffetarget_cvt_rv_to_r1_ (resr, (res)->real); \
+ ffetarget_cvt_rv_to_r1_ (resi, (res)->imaginary); \
+ FFEBAD; })
+#define ffetarget_subtract_complex2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, li, rr, ri, resr, resi; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).real.v[0])); \
+ li = ffetarget_cvt_r2_to_rv_ (&((l).imaginary.v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).real.v[0])); \
+ ri = ffetarget_cvt_r2_to_rv_ (&((r).imaginary.v[0])); \
+ REAL_ARITHMETIC (resr, MINUS_EXPR, lr, rr); \
+ REAL_ARITHMETIC (resi, MINUS_EXPR, li, ri); \
+ ffetarget_cvt_rv_to_r2_ (resr, &((res)->real.v[0])); \
+ ffetarget_cvt_rv_to_r2_ (resi, &((res)->imaginary.v[0])); \
+ FFEBAD; })
+#else
+#define ffetarget_subtract_complex1(res,l,r) \
+ ((res)->real = (l).real - (r).real, \
+ (res)->imaginary = (l).imaginary - (r).imaginary, FFEBAD)
+#define ffetarget_subtract_complex2(res,l,r) \
+ ((res)->real = (l).real - (r).real, \
+ (res)->imaginary = (l).imaginary - (r).imaginary, FFEBAD)
+#endif
+#define ffetarget_subtract_integer1(res,l,r) (*(res) = (l) - (r), FFEBAD)
+#define ffetarget_subtract_integer2(res,l,r) (*(res) = (l) - (r), FFEBAD)
+#define ffetarget_subtract_integer3(res,l,r) (*(res) = (l) - (r), FFEBAD)
+#define ffetarget_subtract_integer4(res,l,r) (*(res) = (l) - (r), FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_subtract_real1(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr, resr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ rr = ffetarget_cvt_r1_to_rv_ ((r)); \
+ REAL_ARITHMETIC (resr, MINUS_EXPR, lr, rr); \
+ ffetarget_cvt_rv_to_r1_ (resr, *(res)); \
+ FFEBAD; })
+#define ffetarget_subtract_real2(res,l,r) \
+ ({ REAL_VALUE_TYPE lr, rr, resr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ rr = ffetarget_cvt_r2_to_rv_ (&((r).v[0])); \
+ REAL_ARITHMETIC (resr, MINUS_EXPR, lr, rr); \
+ ffetarget_cvt_rv_to_r2_ (resr, &((res)->v[0])); \
+ FFEBAD; })
+#else
+#define ffetarget_subtract_real1(res,l,r) (*(res) = (l) - (r), FFEBAD)
+#define ffetarget_subtract_real2(res,l,r) (*(res) = (l) - (r), FFEBAD)
+#endif
+#define ffetarget_terminate_0()
+#define ffetarget_terminate_1()
+#define ffetarget_terminate_2()
+#define ffetarget_terminate_3()
+#define ffetarget_terminate_4()
+#define ffetarget_text_character1(c) ((c).text)
+#define ffetarget_text_characterdefault ffetarget_text_character1
+#ifdef REAL_ARITHMETIC
+#define ffetarget_uminus_complex1(res,l) \
+ ({ REAL_VALUE_TYPE lr, li, resr, resi; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l).real); \
+ li = ffetarget_cvt_r1_to_rv_ ((l).imaginary); \
+ resr = REAL_VALUE_NEGATE (lr); \
+ resi = REAL_VALUE_NEGATE (li); \
+ ffetarget_cvt_rv_to_r1_ (resr, (res)->real); \
+ ffetarget_cvt_rv_to_r1_ (resi, (res)->imaginary); \
+ FFEBAD; })
+#define ffetarget_uminus_complex2(res,l) \
+ ({ REAL_VALUE_TYPE lr, li, resr, resi; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).real.v[0])); \
+ li = ffetarget_cvt_r2_to_rv_ (&((l).imaginary.v[0])); \
+ resr = REAL_VALUE_NEGATE (lr); \
+ resi = REAL_VALUE_NEGATE (li); \
+ ffetarget_cvt_rv_to_r2_ (resr, &((res)->real.v[0])); \
+ ffetarget_cvt_rv_to_r2_ (resi, &((res)->imaginary.v[0])); \
+ FFEBAD; })
+#else
+#define ffetarget_uminus_complex1(res,l) \
+ ((res)->real = -(l).real, (res)->imaginary = -(l).imaginary, FFEBAD)
+#define ffetarget_uminus_complex2(res,l) \
+ ((res)->real = -(l).real, (res)->imaginary = -(l).imaginary, FFEBAD)
+#endif
+#define ffetarget_uminus_integer1(res,l) (*(res) = -(l), FFEBAD)
+#define ffetarget_uminus_integer2(res,l) (*(res) = -(l), FFEBAD)
+#define ffetarget_uminus_integer3(res,l) (*(res) = -(l), FFEBAD)
+#define ffetarget_uminus_integer4(res,l) (*(res) = -(l), FFEBAD)
+#ifdef REAL_ARITHMETIC
+#define ffetarget_uminus_real1(res,l) \
+ ({ REAL_VALUE_TYPE lr, resr; \
+ lr = ffetarget_cvt_r1_to_rv_ ((l)); \
+ resr = REAL_VALUE_NEGATE (lr); \
+ ffetarget_cvt_rv_to_r1_ (resr, *(res)); \
+ FFEBAD; })
+#define ffetarget_uminus_real2(res,l) \
+ ({ REAL_VALUE_TYPE lr, resr; \
+ lr = ffetarget_cvt_r2_to_rv_ (&((l).v[0])); \
+ resr = REAL_VALUE_NEGATE (lr); \
+ ffetarget_cvt_rv_to_r2_ (resr, &((res)->v[0])); \
+ FFEBAD; })
+#else
+#define ffetarget_uminus_real1(res,l) (*(res) = -(l), FFEBAD)
+#define ffetarget_uminus_real2(res,l) (*(res) = -(l), FFEBAD)
+#endif
+#ifdef REAL_ARITHMETIC
+#define ffetarget_value_real1(lr) ffetarget_cvt_r1_to_rv_ ((lr))
+#define ffetarget_value_real2(lr) ffetarget_cvt_r2_to_rv_ (&((lr).v[0]))
+#else
+#define ffetarget_value_real1
+#define ffetarget_value_real2
+#endif
+#define ffetarget_xor_integer1(res,l,r) (*(res) = (l) ^ (r), FFEBAD)
+#define ffetarget_xor_integer2(res,l,r) (*(res) = (l) ^ (r), FFEBAD)
+#define ffetarget_xor_integer3(res,l,r) (*(res) = (l) ^ (r), FFEBAD)
+#define ffetarget_xor_integer4(res,l,r) (*(res) = (l) ^ (r), FFEBAD)
+#define ffetarget_xor_logical1(res,l,r) (*(res) = (l) != (r), FFEBAD)
+#define ffetarget_xor_logical2(res,l,r) (*(res) = (l) != (r), FFEBAD)
+#define ffetarget_xor_logical3(res,l,r) (*(res) = (l) != (r), FFEBAD)
+#define ffetarget_xor_logical4(res,l,r) (*(res) = (l) != (r), FFEBAD)
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/tconfig.j b/contrib/gcc/f/tconfig.j
new file mode 100644
index 0000000..4135291
--- /dev/null
+++ b/contrib/gcc/f/tconfig.j
@@ -0,0 +1,27 @@
+/* tconfig.j -- Wrapper for GCC's tconfig.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_tconfig
+#define _J_f_tconfig
+#include "tconfig.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/tm.j b/contrib/gcc/f/tm.j
new file mode 100644
index 0000000..443fd53
--- /dev/null
+++ b/contrib/gcc/f/tm.j
@@ -0,0 +1,27 @@
+/* tm.j -- Wrapper for GCC's tm.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_tm
+#define _J_f_tm
+#include "tm.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/top.c b/contrib/gcc/f/top.c
new file mode 100644
index 0000000..17e4139
--- /dev/null
+++ b/contrib/gcc/f/top.c
@@ -0,0 +1,922 @@
+/* top.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+ None.
+
+ Description:
+ The GNU Fortran Front End.
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "top.h"
+#include "bad.h"
+#include "bit.h"
+#include "bld.h"
+#include "com.h"
+#include "data.h"
+#include "equiv.h"
+#include "expr.h"
+#include "global.h"
+#include "implic.h"
+#include "info.h"
+#include "intrin.h"
+#include "lab.h"
+#include "lex.h"
+#include "malloc.h"
+#include "name.h"
+#include "src.h"
+#include "st.h"
+#include "storag.h"
+#include "symbol.h"
+#include "target.h"
+#include "where.h"
+#if FFECOM_targetCURRENT == FFECOM_targetGCC
+#include "flags.j"
+#include "toplev.j"
+#endif
+
+/* Externals defined here. */
+
+int flag_traditional; /* Shouldn't need this (C front end only)! */
+bool ffe_is_do_internal_checks_ = FALSE;
+bool ffe_is_90_ = FFETARGET_defaultIS_90;
+bool ffe_is_automatic_ = FFETARGET_defaultIS_AUTOMATIC;
+bool ffe_is_backslash_ = FFETARGET_defaultIS_BACKSLASH;
+bool ffe_is_emulate_complex_ = TRUE;
+bool ffe_is_underscoring_ = FFETARGET_defaultEXTERNAL_UNDERSCORED
+ || FFETARGET_defaultUNDERSCORED_EXTERNAL_UNDERSCORED;
+bool ffe_is_second_underscore_ = FFETARGET_defaultUNDERSCORED_EXTERNAL_UNDERSCORED;
+bool ffe_is_debug_kludge_ = FALSE;
+bool ffe_is_dollar_ok_ = FFETARGET_defaultIS_DOLLAR_OK;
+bool ffe_is_f2c_ = FFETARGET_defaultIS_F2C;
+bool ffe_is_f2c_library_ = FFETARGET_defaultIS_F2C_LIBRARY;
+bool ffe_is_ffedebug_ = FALSE;
+bool ffe_is_free_form_ = FFETARGET_defaultIS_FREE_FORM;
+bool ffe_is_globals_ = TRUE;
+bool ffe_is_ident_ = TRUE;
+bool ffe_is_init_local_zero_ = FFETARGET_defaultIS_INIT_LOCAL_ZERO;
+bool ffe_is_mainprog_; /* TRUE if current prog unit known to be
+ main. */
+bool ffe_is_null_version_ = FALSE;
+bool ffe_is_onetrip_ = FALSE;
+bool ffe_is_silent_ = TRUE;
+bool ffe_is_typeless_boz_ = FALSE;
+bool ffe_is_pedantic_ = FFETARGET_defaultIS_PEDANTIC;
+bool ffe_is_saveall_; /* TRUE if mainprog or SAVE (no args) seen. */
+bool ffe_is_ugly_args_ = TRUE;
+bool ffe_is_ugly_assign_ = FALSE; /* Try and store pointer to ASSIGN labels in INTEGER vars. */
+bool ffe_is_ugly_assumed_ = FALSE; /* DIMENSION X([...,]1) => DIMENSION X([...,]*) */
+bool ffe_is_ugly_comma_ = FALSE;
+bool ffe_is_ugly_complex_ = FALSE;
+bool ffe_is_ugly_init_ = TRUE;
+bool ffe_is_ugly_logint_ = FALSE;
+bool ffe_is_version_ = FALSE;
+bool ffe_is_vxt_ = FALSE;
+bool ffe_is_warn_globals_ = TRUE;
+bool ffe_is_warn_implicit_ = FALSE;
+bool ffe_is_warn_surprising_ = FALSE;
+bool ffe_is_zeros_ = FALSE;
+ffeCase ffe_case_intrin_ = FFETARGET_defaultCASE_INTRIN;
+ffeCase ffe_case_match_ = FFETARGET_defaultCASE_MATCH;
+ffeCase ffe_case_source_ = FFETARGET_defaultCASE_SOURCE;
+ffeCase ffe_case_symbol_ = FFETARGET_defaultCASE_SYMBOL;
+ffeIntrinsicState ffe_intrinsic_state_badu77_ = FFE_intrinsicstateENABLED;
+ffeIntrinsicState ffe_intrinsic_state_gnu_ = FFE_intrinsicstateENABLED;
+ffeIntrinsicState ffe_intrinsic_state_f2c_ = FFE_intrinsicstateENABLED;
+ffeIntrinsicState ffe_intrinsic_state_f90_ = FFE_intrinsicstateENABLED;
+ffeIntrinsicState ffe_intrinsic_state_mil_ = FFE_intrinsicstateENABLED;
+ffeIntrinsicState ffe_intrinsic_state_unix_ = FFE_intrinsicstateENABLED;
+ffeIntrinsicState ffe_intrinsic_state_vxt_ = FFE_intrinsicstateENABLED;
+int ffe_fixed_line_length_ = FFETARGET_defaultFIXED_LINE_LENGTH;
+mallocPool ffe_file_pool_ = NULL;
+mallocPool ffe_any_unit_pool_ = NULL;
+mallocPool ffe_program_unit_pool_ = NULL;
+ffeCounter ffe_count_0 = 0;
+ffeCounter ffe_count_1 = 0;
+ffeCounter ffe_count_2 = 0;
+ffeCounter ffe_count_3 = 0;
+ffeCounter ffe_count_4 = 0;
+bool ffe_in_0 = FALSE;
+bool ffe_in_1 = FALSE;
+bool ffe_in_2 = FALSE;
+bool ffe_in_3 = FALSE;
+bool ffe_in_4 = FALSE;
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+
+/* Static objects accessed by functions in this module. */
+
+
+/* Static functions (internal). */
+
+static bool ffe_is_digit_string_ (char *s);
+
+/* Internal macros. */
+
+static bool
+ffe_is_digit_string_ (char *s)
+{
+ char *p;
+
+ for (p = s; ISDIGIT (*p); ++p)
+ ;
+
+ return (p != s) && (*p == '\0');
+}
+
+/* Handle command-line options. Returns 0 if unrecognized, 1 if
+ recognized and handled. */
+
+int
+ffe_decode_option (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *opt = argv[0];
+ if (opt[0] != '-')
+ return 0;
+ if (opt[1] == 'f')
+ {
+ if (strcmp (&opt[2], "version") == 0)
+ {
+ ffe_set_is_version (TRUE);
+ ffe_set_is_do_internal_checks (TRUE);
+ }
+ else if (strcmp (&opt[2], "null-version") == 0)
+ ffe_set_is_null_version (TRUE);
+ else if (strcmp (&opt[2], "ident") == 0)
+ ffe_set_is_ident (TRUE);
+ else if (strcmp (&opt[2], "no-ident") == 0)
+ ffe_set_is_ident (FALSE);
+ else if (strcmp (&opt[2], "f66") == 0)
+ {
+ ffe_set_is_onetrip (TRUE);
+ ffe_set_is_ugly_assumed (TRUE);
+ }
+ else if (strcmp (&opt[2], "no-f66") == 0)
+ {
+ ffe_set_is_onetrip (FALSE);
+ ffe_set_is_ugly_assumed (FALSE);
+ }
+ else if (strcmp (&opt[2], "f77") == 0)
+ {
+ ffe_set_is_backslash (TRUE);
+ ffe_set_is_typeless_boz (FALSE);
+ }
+ else if (strcmp (&opt[2], "no-f77") == 0)
+ {
+ ffe_set_is_backslash (FALSE);
+ }
+ else if (strcmp (&opt[2], "f90") == 0)
+ ffe_set_is_90 (TRUE);
+ else if (strcmp (&opt[2], "no-f90") == 0)
+ ffe_set_is_90 (FALSE);
+ else if (strcmp (&opt[2], "automatic") == 0)
+ ffe_set_is_automatic (TRUE);
+ else if (strcmp (&opt[2], "no-automatic") == 0)
+ ffe_set_is_automatic (FALSE);
+ else if (strcmp (&opt[2], "dollar-ok") == 0)
+ ffe_set_is_dollar_ok (TRUE);
+ else if (strcmp (&opt[2], "no-dollar-ok") == 0)
+ ffe_set_is_dollar_ok (FALSE);
+ else if (strcmp (&opt[2], "f2c") == 0)
+ ffe_set_is_f2c (TRUE);
+ else if (strcmp (&opt[2], "no-f2c") == 0)
+ ffe_set_is_f2c (FALSE);
+ else if (strcmp (&opt[2], "f2c-library") == 0)
+ ffe_set_is_f2c_library (TRUE);
+ else if (strcmp (&opt[2], "no-f2c-library") == 0)
+ ffe_set_is_f2c_library (FALSE);
+ else if (strcmp (&opt[2], "free-form") == 0)
+ ffe_set_is_free_form (TRUE);
+ else if (strcmp (&opt[2], "no-free-form") == 0)
+ ffe_set_is_free_form (FALSE);
+ else if (strcmp (&opt[2], "fixed-form") == 0)
+ ffe_set_is_free_form (FALSE);
+ else if (strcmp (&opt[2], "no-fixed-form") == 0)
+ ffe_set_is_free_form (TRUE);
+ else if (strcmp (&opt[2], "pedantic") == 0)
+ ffe_set_is_pedantic (TRUE);
+ else if (strcmp (&opt[2], "no-pedantic") == 0)
+ ffe_set_is_pedantic (FALSE);
+ else if (strcmp (&opt[2], "vxt") == 0)
+ ffe_set_is_vxt (TRUE);
+ else if (strcmp (&opt[2], "not-vxt") == 0)
+ ffe_set_is_vxt (FALSE);
+ else if (strcmp (&opt[2], "vxt-not-f90") == 0)
+ warning ("%s no longer supported -- try -fvxt", opt);
+ else if (strcmp (&opt[2], "f90-not-vxt") == 0)
+ warning ("%s no longer supported -- try -fno-vxt -ff90", opt);
+ else if (strcmp (&opt[2], "ugly") == 0)
+ {
+ warning ("%s is overloaded with meanings and likely to be removed;", opt);
+ warning ("use only the specific -fugly-* options you need");
+ ffe_set_is_ugly_args (TRUE);
+ ffe_set_is_ugly_assign (TRUE);
+ ffe_set_is_ugly_assumed (TRUE);
+ ffe_set_is_ugly_comma (TRUE);
+ ffe_set_is_ugly_complex (TRUE);
+ ffe_set_is_ugly_init (TRUE);
+ ffe_set_is_ugly_logint (TRUE);
+ }
+ else if (strcmp (&opt[2], "no-ugly") == 0)
+ {
+ ffe_set_is_ugly_args (FALSE);
+ ffe_set_is_ugly_assign (FALSE);
+ ffe_set_is_ugly_assumed (FALSE);
+ ffe_set_is_ugly_comma (FALSE);
+ ffe_set_is_ugly_complex (FALSE);
+ ffe_set_is_ugly_init (FALSE);
+ ffe_set_is_ugly_logint (FALSE);
+ }
+ else if (strcmp (&opt[2], "ugly-args") == 0)
+ ffe_set_is_ugly_args (TRUE);
+ else if (strcmp (&opt[2], "no-ugly-args") == 0)
+ ffe_set_is_ugly_args (FALSE);
+ else if (strcmp (&opt[2], "ugly-assign") == 0)
+ ffe_set_is_ugly_assign (TRUE);
+ else if (strcmp (&opt[2], "no-ugly-assign") == 0)
+ ffe_set_is_ugly_assign (FALSE);
+ else if (strcmp (&opt[2], "ugly-assumed") == 0)
+ ffe_set_is_ugly_assumed (TRUE);
+ else if (strcmp (&opt[2], "no-ugly-assumed") == 0)
+ ffe_set_is_ugly_assumed (FALSE);
+ else if (strcmp (&opt[2], "ugly-comma") == 0)
+ ffe_set_is_ugly_comma (TRUE);
+ else if (strcmp (&opt[2], "no-ugly-comma") == 0)
+ ffe_set_is_ugly_comma (FALSE);
+ else if (strcmp (&opt[2], "ugly-complex") == 0)
+ ffe_set_is_ugly_complex (TRUE);
+ else if (strcmp (&opt[2], "no-ugly-complex") == 0)
+ ffe_set_is_ugly_complex (FALSE);
+ else if (strcmp (&opt[2], "ugly-init") == 0)
+ ffe_set_is_ugly_init (TRUE);
+ else if (strcmp (&opt[2], "no-ugly-init") == 0)
+ ffe_set_is_ugly_init (FALSE);
+ else if (strcmp (&opt[2], "ugly-logint") == 0)
+ ffe_set_is_ugly_logint (TRUE);
+ else if (strcmp (&opt[2], "no-ugly-logint") == 0)
+ ffe_set_is_ugly_logint (FALSE);
+ else if (strcmp (&opt[2], "xyzzy") == 0)
+ ffe_set_is_ffedebug (TRUE);
+ else if (strcmp (&opt[2], "no-xyzzy") == 0)
+ ffe_set_is_ffedebug (FALSE);
+ else if (strcmp (&opt[2], "init-local-zero") == 0)
+ ffe_set_is_init_local_zero (TRUE);
+ else if (strcmp (&opt[2], "no-init-local-zero") == 0)
+ ffe_set_is_init_local_zero (FALSE);
+ else if (strcmp (&opt[2], "emulate-complex") == 0)
+ ffe_set_is_emulate_complex (TRUE);
+ else if (strcmp (&opt[2], "no-emulate-complex") == 0)
+ ffe_set_is_emulate_complex (FALSE);
+ else if (strcmp (&opt[2], "backslash") == 0)
+ ffe_set_is_backslash (TRUE);
+ else if (strcmp (&opt[2], "no-backslash") == 0)
+ ffe_set_is_backslash (FALSE);
+ else if (strcmp (&opt[2], "underscoring") == 0)
+ ffe_set_is_underscoring (TRUE);
+ else if (strcmp (&opt[2], "no-underscoring") == 0)
+ ffe_set_is_underscoring (FALSE);
+ else if (strcmp (&opt[2], "second-underscore") == 0)
+ ffe_set_is_second_underscore (TRUE);
+ else if (strcmp (&opt[2], "no-second-underscore") == 0)
+ ffe_set_is_second_underscore (FALSE);
+ else if (strcmp (&opt[2], "zeros") == 0)
+ ffe_set_is_zeros (TRUE);
+ else if (strcmp (&opt[2], "no-zeros") == 0)
+ ffe_set_is_zeros (FALSE);
+ else if (strcmp (&opt[2], "debug-kludge") == 0)
+ ffe_set_is_debug_kludge (TRUE);
+ else if (strcmp (&opt[2], "no-debug-kludge") == 0)
+ ffe_set_is_debug_kludge (FALSE);
+ else if (strcmp (&opt[2], "onetrip") == 0)
+ ffe_set_is_onetrip (TRUE);
+ else if (strcmp (&opt[2], "no-onetrip") == 0)
+ ffe_set_is_onetrip (FALSE);
+ else if (strcmp (&opt[2], "silent") == 0)
+ ffe_set_is_silent (TRUE);
+ else if (strcmp (&opt[2], "no-silent") == 0)
+ ffe_set_is_silent (FALSE);
+ else if (strcmp (&opt[2], "globals") == 0)
+ ffe_set_is_globals (TRUE);
+ else if (strcmp (&opt[2], "no-globals") == 0)
+ ffe_set_is_globals (FALSE);
+ else if (strcmp (&opt[2], "typeless-boz") == 0)
+ ffe_set_is_typeless_boz (TRUE);
+ else if (strcmp (&opt[2], "no-typeless-boz") == 0)
+ ffe_set_is_typeless_boz (FALSE);
+ else if (strcmp (&opt[2], "intrin-case-initcap") == 0)
+ ffe_set_case_intrin (FFE_caseINITCAP);
+ else if (strcmp (&opt[2], "intrin-case-upper") == 0)
+ ffe_set_case_intrin (FFE_caseUPPER);
+ else if (strcmp (&opt[2], "intrin-case-lower") == 0)
+ ffe_set_case_intrin (FFE_caseLOWER);
+ else if (strcmp (&opt[2], "intrin-case-any") == 0)
+ ffe_set_case_intrin (FFE_caseNONE);
+ else if (strcmp (&opt[2], "match-case-initcap") == 0)
+ ffe_set_case_match (FFE_caseINITCAP);
+ else if (strcmp (&opt[2], "match-case-upper") == 0)
+ ffe_set_case_match (FFE_caseUPPER);
+ else if (strcmp (&opt[2], "match-case-lower") == 0)
+ ffe_set_case_match (FFE_caseLOWER);
+ else if (strcmp (&opt[2], "match-case-any") == 0)
+ ffe_set_case_match (FFE_caseNONE);
+ else if (strcmp (&opt[2], "source-case-upper") == 0)
+ ffe_set_case_source (FFE_caseUPPER);
+ else if (strcmp (&opt[2], "source-case-lower") == 0)
+ ffe_set_case_source (FFE_caseLOWER);
+ else if (strcmp (&opt[2], "source-case-preserve") == 0)
+ ffe_set_case_source (FFE_caseNONE);
+ else if (strcmp (&opt[2], "symbol-case-initcap") == 0)
+ ffe_set_case_symbol (FFE_caseINITCAP);
+ else if (strcmp (&opt[2], "symbol-case-upper") == 0)
+ ffe_set_case_symbol (FFE_caseUPPER);
+ else if (strcmp (&opt[2], "symbol-case-lower") == 0)
+ ffe_set_case_symbol (FFE_caseLOWER);
+ else if (strcmp (&opt[2], "symbol-case-any") == 0)
+ ffe_set_case_symbol (FFE_caseNONE);
+ else if (strcmp (&opt[2], "case-strict-upper") == 0)
+ {
+ ffe_set_case_intrin (FFE_caseUPPER);
+ ffe_set_case_match (FFE_caseUPPER);
+ ffe_set_case_source (FFE_caseNONE);
+ ffe_set_case_symbol (FFE_caseUPPER);
+ }
+ else if (strcmp (&opt[2], "case-strict-lower") == 0)
+ {
+ ffe_set_case_intrin (FFE_caseLOWER);
+ ffe_set_case_match (FFE_caseLOWER);
+ ffe_set_case_source (FFE_caseNONE);
+ ffe_set_case_symbol (FFE_caseLOWER);
+ }
+ else if (strcmp (&opt[2], "case-initcap") == 0)
+ {
+ ffe_set_case_intrin (FFE_caseINITCAP);
+ ffe_set_case_match (FFE_caseINITCAP);
+ ffe_set_case_source (FFE_caseNONE);
+ ffe_set_case_symbol (FFE_caseINITCAP);
+ }
+ else if (strcmp (&opt[2], "case-upper") == 0)
+ {
+ ffe_set_case_intrin (FFE_caseNONE);
+ ffe_set_case_match (FFE_caseNONE);
+ ffe_set_case_source (FFE_caseUPPER);
+ ffe_set_case_symbol (FFE_caseNONE);
+ }
+ else if (strcmp (&opt[2], "case-lower") == 0)
+ {
+ ffe_set_case_intrin (FFE_caseNONE);
+ ffe_set_case_match (FFE_caseNONE);
+ ffe_set_case_source (FFE_caseLOWER);
+ ffe_set_case_symbol (FFE_caseNONE);
+ }
+ else if (strcmp (&opt[2], "case-preserve") == 0)
+ {
+ ffe_set_case_intrin (FFE_caseNONE);
+ ffe_set_case_match (FFE_caseNONE);
+ ffe_set_case_source (FFE_caseNONE);
+ ffe_set_case_symbol (FFE_caseNONE);
+ }
+ else if (strcmp (&opt[2], "badu77-intrinsics-delete") == 0)
+ ffe_set_intrinsic_state_badu77 (FFE_intrinsicstateDELETED);
+ else if (strcmp (&opt[2], "badu77-intrinsics-hide") == 0)
+ ffe_set_intrinsic_state_badu77 (FFE_intrinsicstateHIDDEN);
+ else if (strcmp (&opt[2], "badu77-intrinsics-disable") == 0)
+ ffe_set_intrinsic_state_badu77 (FFE_intrinsicstateDISABLED);
+ else if (strcmp (&opt[2], "badu77-intrinsics-enable") == 0)
+ ffe_set_intrinsic_state_badu77 (FFE_intrinsicstateENABLED);
+ else if (strcmp (&opt[2], "gnu-intrinsics-delete") == 0)
+ ffe_set_intrinsic_state_gnu (FFE_intrinsicstateDELETED);
+ else if (strcmp (&opt[2], "gnu-intrinsics-hide") == 0)
+ ffe_set_intrinsic_state_gnu (FFE_intrinsicstateHIDDEN);
+ else if (strcmp (&opt[2], "gnu-intrinsics-disable") == 0)
+ ffe_set_intrinsic_state_gnu (FFE_intrinsicstateDISABLED);
+ else if (strcmp (&opt[2], "gnu-intrinsics-enable") == 0)
+ ffe_set_intrinsic_state_gnu (FFE_intrinsicstateENABLED);
+ else if (strcmp (&opt[2], "f2c-intrinsics-delete") == 0)
+ ffe_set_intrinsic_state_f2c (FFE_intrinsicstateDELETED);
+ else if (strcmp (&opt[2], "f2c-intrinsics-hide") == 0)
+ ffe_set_intrinsic_state_f2c (FFE_intrinsicstateHIDDEN);
+ else if (strcmp (&opt[2], "f2c-intrinsics-disable") == 0)
+ ffe_set_intrinsic_state_f2c (FFE_intrinsicstateDISABLED);
+ else if (strcmp (&opt[2], "f2c-intrinsics-enable") == 0)
+ ffe_set_intrinsic_state_f2c (FFE_intrinsicstateENABLED);
+ else if (strcmp (&opt[2], "f90-intrinsics-delete") == 0)
+ ffe_set_intrinsic_state_f90 (FFE_intrinsicstateDELETED);
+ else if (strcmp (&opt[2], "f90-intrinsics-hide") == 0)
+ ffe_set_intrinsic_state_f90 (FFE_intrinsicstateHIDDEN);
+ else if (strcmp (&opt[2], "f90-intrinsics-disable") == 0)
+ ffe_set_intrinsic_state_f90 (FFE_intrinsicstateDISABLED);
+ else if (strcmp (&opt[2], "f90-intrinsics-enable") == 0)
+ ffe_set_intrinsic_state_f90 (FFE_intrinsicstateENABLED);
+ else if (strcmp (&opt[2], "mil-intrinsics-delete") == 0)
+ ffe_set_intrinsic_state_mil (FFE_intrinsicstateDELETED);
+ else if (strcmp (&opt[2], "mil-intrinsics-hide") == 0)
+ ffe_set_intrinsic_state_mil (FFE_intrinsicstateHIDDEN);
+ else if (strcmp (&opt[2], "mil-intrinsics-disable") == 0)
+ ffe_set_intrinsic_state_mil (FFE_intrinsicstateDISABLED);
+ else if (strcmp (&opt[2], "mil-intrinsics-enable") == 0)
+ ffe_set_intrinsic_state_mil (FFE_intrinsicstateENABLED);
+ else if (strcmp (&opt[2], "unix-intrinsics-delete") == 0)
+ ffe_set_intrinsic_state_unix (FFE_intrinsicstateDELETED);
+ else if (strcmp (&opt[2], "unix-intrinsics-hide") == 0)
+ ffe_set_intrinsic_state_unix (FFE_intrinsicstateHIDDEN);
+ else if (strcmp (&opt[2], "unix-intrinsics-disable") == 0)
+ ffe_set_intrinsic_state_unix (FFE_intrinsicstateDISABLED);
+ else if (strcmp (&opt[2], "unix-intrinsics-enable") == 0)
+ ffe_set_intrinsic_state_unix (FFE_intrinsicstateENABLED);
+ else if (strcmp (&opt[2], "vxt-intrinsics-delete") == 0)
+ ffe_set_intrinsic_state_vxt (FFE_intrinsicstateDELETED);
+ else if (strcmp (&opt[2], "vxt-intrinsics-hide") == 0)
+ ffe_set_intrinsic_state_vxt (FFE_intrinsicstateHIDDEN);
+ else if (strcmp (&opt[2], "vxt-intrinsics-disable") == 0)
+ ffe_set_intrinsic_state_vxt (FFE_intrinsicstateDISABLED);
+ else if (strcmp (&opt[2], "vxt-intrinsics-enable") == 0)
+ ffe_set_intrinsic_state_vxt (FFE_intrinsicstateENABLED);
+ else if (strncmp (&opt[2], "fixed-line-length-",
+ strlen ("fixed-line-length-")) == 0)
+ {
+ char *len = &opt[2] + strlen ("fixed-line-length-");
+
+ if (strcmp (len, "none") == 0)
+ ffe_set_fixed_line_length (0);
+ else if (ffe_is_digit_string_ (len))
+ ffe_set_fixed_line_length (atol (len));
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+ else if (opt[1] == 'W')
+ {
+ if (!strcmp (&opt[2], "comment"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (&opt[2], "no-comment"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (&opt[2], "comments"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (&opt[2], "no-comments"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (&opt[2], "trigraphs"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (&opt[2], "no-trigraphs"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (&opt[2], "import"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (&opt[2], "no-import"))
+ ; /* cpp handles this one. */
+ else if (!strcmp (&opt[2], "globals"))
+ ffe_set_is_warn_globals (TRUE);
+ else if (!strcmp (&opt[2], "no-globals"))
+ ffe_set_is_warn_globals (FALSE);
+ else if (!strcmp (&opt[2], "implicit"))
+ ffe_set_is_warn_implicit (TRUE);
+ else if (!strcmp (&opt[2], "no-implicit"))
+ ffe_set_is_warn_implicit (FALSE);
+ else if (!strcmp (&opt[2], "surprising"))
+ ffe_set_is_warn_surprising (TRUE);
+ else if (!strcmp (&opt[2], "no-surprising"))
+ ffe_set_is_warn_surprising (FALSE);
+ else if (!strcmp (&opt[2], "all"))
+ {
+ /* We save the value of warn_uninitialized, since if they put
+ -Wuninitialized on the command line, we need to generate a
+ warning about not using it without also specifying -O. */
+ if (warn_uninitialized != 1)
+ warn_uninitialized = 2;
+ warn_unused = 1;
+ }
+ else
+ return 0;
+ }
+ else if (opt[1] == 'I')
+ return ffecom_decode_include_option (&opt[2]);
+ else
+ return 0;
+
+ return 1;
+}
+
+/* Run the FFE on a source file (not an INCLUDEd file).
+
+ Runs the whole shebang.
+
+ Prepare and invoke the appropriate lexer. */
+
+void
+ffe_file (ffewhereFile wf, FILE *f)
+{
+ ffe_init_1 ();
+ ffelex_set_handler ((ffelexHandler) ffest_first);
+ ffewhere_file_set (wf, TRUE, 0);
+ if (ffe_is_free_form_)
+ ffelex_file_free (wf, f);
+ else
+ ffelex_file_fixed (wf, f);
+ ffest_eof ();
+ ffe_terminate_1 ();
+}
+
+/* ffe_init_0 -- Initialize the FFE per image invocation
+
+ ffe_init_0();
+
+ Performs per-image invocation. */
+
+void
+ffe_init_0 ()
+{
+ ++ffe_count_0;
+ ffe_in_0 = TRUE;
+
+ ffebad_init_0 ();
+ ffebit_init_0 ();
+ ffebld_init_0 ();
+ ffecom_init_0 ();
+ ffedata_init_0 ();
+ ffeequiv_init_0 ();
+ ffeexpr_init_0 ();
+ ffeglobal_init_0 ();
+ ffeimplic_init_0 ();
+ ffeinfo_init_0 ();
+ ffeintrin_init_0 ();
+ ffelab_init_0 ();
+ ffelex_init_0 ();
+ ffename_init_0 ();
+ ffesrc_init_0 ();
+ ffest_init_0 ();
+ ffestorag_init_0 ();
+ ffesymbol_init_0 ();
+ ffetarget_init_0 ();
+ ffetype_init_0 ();
+ ffewhere_init_0 ();
+}
+
+/* ffe_init_1 -- Initialize the FFE per source file
+
+ ffe_init_1();
+
+ Performs per-source-file invocation (not including INCLUDEd files). */
+
+void
+ffe_init_1 ()
+{
+ ++ffe_count_1;
+ ffe_in_1 = TRUE;
+
+ assert (ffe_file_pool_ == NULL);
+ ffe_file_pool_ = malloc_pool_new ("File", malloc_pool_image (), 1024);
+
+ ffebad_init_1 ();
+ ffebit_init_1 ();
+ ffebld_init_1 ();
+ ffecom_init_1 ();
+ ffedata_init_1 ();
+ ffeequiv_init_1 ();
+ ffeexpr_init_1 ();
+ ffeglobal_init_1 ();
+ ffeimplic_init_1 ();
+ ffeinfo_init_1 ();
+ ffeintrin_init_1 ();
+ ffelab_init_1 ();
+ ffelex_init_1 ();
+ ffename_init_1 ();
+ ffesrc_init_1 ();
+ ffest_init_1 ();
+ ffestorag_init_1 ();
+ ffesymbol_init_1 ();
+ ffetarget_init_1 ();
+ ffetype_init_1 ();
+ ffewhere_init_1 ();
+
+ ffe_init_2 ();
+}
+
+/* ffe_init_2 -- Initialize the FFE per outer program unit
+
+ ffe_init_2();
+
+ Performs per-program-unit invocation. */
+
+void
+ffe_init_2 ()
+{
+ ++ffe_count_2;
+ ffe_in_2 = TRUE;
+
+ assert (ffe_program_unit_pool_ == NULL);
+ ffe_program_unit_pool_ = malloc_pool_new ("Program unit", ffe_file_pool_, 1024);
+ ffe_is_mainprog_ = FALSE;
+ ffe_is_saveall_ = !ffe_is_automatic_;
+
+ ffebad_init_2 ();
+ ffebit_init_2 ();
+ ffebld_init_2 ();
+ ffecom_init_2 ();
+ ffedata_init_2 ();
+ ffeequiv_init_2 ();
+ ffeexpr_init_2 ();
+ ffeglobal_init_2 ();
+ ffeimplic_init_2 ();
+ ffeinfo_init_2 ();
+ ffeintrin_init_2 ();
+ ffelab_init_2 ();
+ ffelex_init_2 ();
+ ffename_init_2 ();
+ ffesrc_init_2 ();
+ ffest_init_2 ();
+ ffestorag_init_2 ();
+ ffesymbol_init_2 ();
+ ffetarget_init_2 ();
+ ffetype_init_2 ();
+ ffewhere_init_2 ();
+
+ ffe_init_3 ();
+}
+
+/* ffe_init_3 -- Initialize the FFE per any program unit
+
+ ffe_init_3();
+
+ Performs per-any-unit initialization; does NOT do
+ per-statement-function-definition initialization (i.e. the chain
+ of inits, from 0-3, breaks here; level 4 must be invoked independently). */
+
+void
+ffe_init_3 ()
+{
+ ++ffe_count_3;
+ ffe_in_3 = TRUE;
+
+ assert (ffe_any_unit_pool_ == NULL);
+ ffe_any_unit_pool_ = malloc_pool_new ("Any unit", ffe_program_unit_pool_, 1024);
+
+ ffebad_init_3 ();
+ ffebit_init_3 ();
+ ffebld_init_3 ();
+ ffecom_init_3 ();
+ ffedata_init_3 ();
+ ffeequiv_init_3 ();
+ ffeexpr_init_3 ();
+ ffeglobal_init_3 ();
+ ffeimplic_init_3 ();
+ ffeinfo_init_3 ();
+ ffeintrin_init_3 ();
+ ffelab_init_3 ();
+ ffelex_init_3 ();
+ ffename_init_3 ();
+ ffesrc_init_3 ();
+ ffest_init_3 ();
+ ffestorag_init_3 ();
+ ffesymbol_init_3 ();
+ ffetarget_init_3 ();
+ ffetype_init_3 ();
+ ffewhere_init_3 ();
+}
+
+/* ffe_init_4 -- Initialize the FFE per statement function definition
+
+ ffe_init_4(); */
+
+void
+ffe_init_4 ()
+{
+ ++ffe_count_4;
+ ffe_in_4 = TRUE;
+
+ ffebad_init_4 ();
+ ffebit_init_4 ();
+ ffebld_init_4 ();
+ ffecom_init_4 ();
+ ffedata_init_4 ();
+ ffeequiv_init_4 ();
+ ffeexpr_init_4 ();
+ ffeglobal_init_4 ();
+ ffeimplic_init_4 ();
+ ffeinfo_init_4 ();
+ ffeintrin_init_4 ();
+ ffelab_init_4 ();
+ ffelex_init_4 ();
+ ffename_init_4 ();
+ ffesrc_init_4 ();
+ ffest_init_4 ();
+ ffestorag_init_4 ();
+ ffesymbol_init_4 ();
+ ffetarget_init_4 ();
+ ffetype_init_4 ();
+ ffewhere_init_4 ();
+}
+
+/* ffe_terminate_0 -- Terminate the FFE prior to image termination
+
+ ffe_terminate_0(); */
+
+void
+ffe_terminate_0 ()
+{
+ ffe_count_1 = 0;
+ ffe_in_0 = FALSE;
+
+ ffebad_terminate_0 ();
+ ffebit_terminate_0 ();
+ ffebld_terminate_0 ();
+ ffecom_terminate_0 ();
+ ffedata_terminate_0 ();
+ ffeequiv_terminate_0 ();
+ ffeexpr_terminate_0 ();
+ ffeglobal_terminate_0 ();
+ ffeimplic_terminate_0 ();
+ ffeinfo_terminate_0 ();
+ ffeintrin_terminate_0 ();
+ ffelab_terminate_0 ();
+ ffelex_terminate_0 ();
+ ffename_terminate_0 ();
+ ffesrc_terminate_0 ();
+ ffest_terminate_0 ();
+ ffestorag_terminate_0 ();
+ ffesymbol_terminate_0 ();
+ ffetarget_terminate_0 ();
+ ffetype_terminate_0 ();
+ ffewhere_terminate_0 ();
+}
+
+/* ffe_terminate_1 -- Terminate the FFE after seeing source file EOF
+
+ ffe_terminate_1(); */
+
+void
+ffe_terminate_1 ()
+{
+ ffe_count_2 = 0;
+ ffe_in_1 = FALSE;
+
+ ffe_terminate_2 ();
+
+ ffebad_terminate_1 ();
+ ffebit_terminate_1 ();
+ ffebld_terminate_1 ();
+ ffecom_terminate_1 ();
+ ffedata_terminate_1 ();
+ ffeequiv_terminate_1 ();
+ ffeexpr_terminate_1 ();
+ ffeglobal_terminate_1 ();
+ ffeimplic_terminate_1 ();
+ ffeinfo_terminate_1 ();
+ ffeintrin_terminate_1 ();
+ ffelab_terminate_1 ();
+ ffelex_terminate_1 ();
+ ffename_terminate_1 ();
+ ffesrc_terminate_1 ();
+ ffest_terminate_1 ();
+ ffestorag_terminate_1 ();
+ ffesymbol_terminate_1 ();
+ ffetarget_terminate_1 ();
+ ffetype_terminate_1 ();
+ ffewhere_terminate_1 ();
+
+ assert (ffe_file_pool_ != NULL);
+ malloc_pool_kill (ffe_file_pool_);
+ ffe_file_pool_ = NULL;
+}
+
+/* ffe_terminate_2 -- Terminate the FFE after seeing outer program unit END
+
+ ffe_terminate_2(); */
+
+void
+ffe_terminate_2 ()
+{
+ ffe_count_3 = 0;
+ ffe_in_2 = FALSE;
+
+ ffe_terminate_3 ();
+
+ ffebad_terminate_2 ();
+ ffebit_terminate_2 ();
+ ffebld_terminate_2 ();
+ ffecom_terminate_2 ();
+ ffedata_terminate_2 ();
+ ffeequiv_terminate_2 ();
+ ffeexpr_terminate_2 ();
+ ffeglobal_terminate_2 ();
+ ffeimplic_terminate_2 ();
+ ffeinfo_terminate_2 ();
+ ffeintrin_terminate_2 ();
+ ffelab_terminate_2 ();
+ ffelex_terminate_2 ();
+ ffename_terminate_2 ();
+ ffesrc_terminate_2 ();
+ ffest_terminate_2 ();
+ ffestorag_terminate_2 ();
+ ffesymbol_terminate_2 ();
+ ffetarget_terminate_2 ();
+ ffetype_terminate_2 ();
+ ffewhere_terminate_2 ();
+
+ assert (ffe_program_unit_pool_ != NULL);
+ malloc_pool_kill (ffe_program_unit_pool_);
+ ffe_program_unit_pool_ = NULL;
+}
+
+/* ffe_terminate_3 -- Terminate the FFE after seeing any program unit END
+
+ ffe_terminate_3(); */
+
+void
+ffe_terminate_3 ()
+{
+ ffe_count_4 = 0;
+ ffe_in_3 = FALSE;
+
+ ffebad_terminate_3 ();
+ ffebit_terminate_3 ();
+ ffebld_terminate_3 ();
+ ffecom_terminate_3 ();
+ ffedata_terminate_3 ();
+ ffeequiv_terminate_3 ();
+ ffeexpr_terminate_3 ();
+ ffeglobal_terminate_3 ();
+ ffeimplic_terminate_3 ();
+ ffeinfo_terminate_3 ();
+ ffeintrin_terminate_3 ();
+ ffelab_terminate_3 ();
+ ffelex_terminate_3 ();
+ ffename_terminate_3 ();
+ ffesrc_terminate_3 ();
+ ffest_terminate_3 ();
+ ffestorag_terminate_3 ();
+ ffesymbol_terminate_3 ();
+ ffetarget_terminate_3 ();
+ ffetype_terminate_3 ();
+ ffewhere_terminate_3 ();
+
+ assert (ffe_any_unit_pool_ != NULL);
+ malloc_pool_kill (ffe_any_unit_pool_);
+ ffe_any_unit_pool_ = NULL;
+}
+
+/* ffe_terminate_4 -- Terminate the FFE after seeing sfunc def expression
+
+ ffe_terminate_4(); */
+
+void
+ffe_terminate_4 ()
+{
+ ffe_in_4 = FALSE;
+
+ ffebad_terminate_4 ();
+ ffebit_terminate_4 ();
+ ffebld_terminate_4 ();
+ ffecom_terminate_4 ();
+ ffedata_terminate_4 ();
+ ffeequiv_terminate_4 ();
+ ffeexpr_terminate_4 ();
+ ffeglobal_terminate_4 ();
+ ffeimplic_terminate_4 ();
+ ffeinfo_terminate_4 ();
+ ffeintrin_terminate_4 ();
+ ffelab_terminate_4 ();
+ ffelex_terminate_4 ();
+ ffename_terminate_4 ();
+ ffesrc_terminate_4 ();
+ ffest_terminate_4 ();
+ ffestorag_terminate_4 ();
+ ffesymbol_terminate_4 ();
+ ffetarget_terminate_4 ();
+ ffetype_terminate_4 ();
+ ffewhere_terminate_4 ();
+}
diff --git a/contrib/gcc/f/top.h b/contrib/gcc/f/top.h
new file mode 100644
index 0000000..bae6787
--- /dev/null
+++ b/contrib/gcc/f/top.h
@@ -0,0 +1,264 @@
+/* top.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995-1997 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ top.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_parse
+#define _H_f_parse
+
+/* Simple definitions and enumerations. */
+
+enum _ffe_case_
+ {
+ FFE_caseNONE, /* No case conversion, match
+ case-insensitive. */
+ FFE_caseUPPER, /* Convert lowercase to uppercase, match
+ upper. */
+ FFE_caseLOWER, /* Convert uppercase to lowercase, match
+ lower. */
+ FFE_caseINITCAP, /* Match InitialCap (no meaning for
+ conversion). */
+ FFE_case
+ };
+typedef enum _ffe_case_ ffeCase;
+
+enum _ffeintrinsic_state_
+ { /* State of a family of intrinsics. NOTE:
+ order IS important, see
+ ffe_intrinsic_state_max (). */
+ FFE_intrinsicstateDELETED, /* Doesn't exist at all. */
+ FFE_intrinsicstateDISABLED, /* Diagnostic if used as intrinsic. */
+ FFE_intrinsicstateHIDDEN, /* Exists only if INTRINSIC stmt. */
+ FFE_intrinsicstateENABLED, /* Exists as normal. */
+ FFE_intrinsicstate
+ };
+typedef enum _ffeintrinsic_state_ ffeIntrinsicState;
+
+/* Typedefs. */
+
+typedef unsigned long ffeCounter;
+#define ffeCounter_f "l"
+typedef unsigned int ffeKwIndex;
+typedef unsigned long int ffeTokenLength;
+#define ffeTokenLength_f "l"
+typedef void *ffeUnionLongPtr; /* unused type to cover union of long and
+ ptr. */
+
+/* Include files needed by this one. */
+
+#include "malloc.h"
+#include "where.h"
+
+/* Structure definitions. */
+
+
+/* Global objects accessed by users of this module. */
+
+extern bool ffe_is_do_internal_checks_;
+extern bool ffe_is_90_;
+extern bool ffe_is_automatic_;
+extern bool ffe_is_backslash_;
+extern bool ffe_is_emulate_complex_;
+extern bool ffe_is_underscoring_;
+extern bool ffe_is_second_underscore_;
+extern bool ffe_is_debug_kludge_;
+extern bool ffe_is_dollar_ok_;
+extern bool ffe_is_f2c_;
+extern bool ffe_is_f2c_library_;
+extern bool ffe_is_ffedebug_;
+extern bool ffe_is_free_form_;
+extern bool ffe_is_globals_;
+extern bool ffe_is_ident_;
+extern bool ffe_is_init_local_zero_;
+extern bool ffe_is_mainprog_;
+extern bool ffe_is_null_version_;
+extern bool ffe_is_onetrip_;
+extern bool ffe_is_silent_;
+extern bool ffe_is_typeless_boz_;
+extern bool ffe_is_pedantic_;
+extern bool ffe_is_saveall_;
+extern bool ffe_is_ugly_args_;
+extern bool ffe_is_ugly_assign_;
+extern bool ffe_is_ugly_assumed_;
+extern bool ffe_is_ugly_comma_;
+extern bool ffe_is_ugly_complex_;
+extern bool ffe_is_ugly_init_;
+extern bool ffe_is_ugly_logint_;
+extern bool ffe_is_version_;
+extern bool ffe_is_vxt_;
+extern bool ffe_is_warn_globals_;
+extern bool ffe_is_warn_implicit_;
+extern bool ffe_is_warn_surprising_;
+extern bool ffe_is_zeros_;
+extern ffeCase ffe_case_intrin_;
+extern ffeCase ffe_case_match_;
+extern ffeCase ffe_case_source_;
+extern ffeCase ffe_case_symbol_;
+extern ffeIntrinsicState ffe_intrinsic_state_badu77_;
+extern ffeIntrinsicState ffe_intrinsic_state_gnu_;
+extern ffeIntrinsicState ffe_intrinsic_state_f2c_;
+extern ffeIntrinsicState ffe_intrinsic_state_f90_;
+extern ffeIntrinsicState ffe_intrinsic_state_mil_;
+extern ffeIntrinsicState ffe_intrinsic_state_unix_;
+extern ffeIntrinsicState ffe_intrinsic_state_vxt_;
+extern int ffe_fixed_line_length_;
+extern mallocPool ffe_file_pool_;
+extern mallocPool ffe_any_unit_pool_;
+extern mallocPool ffe_program_unit_pool_;
+extern ffeCounter ffe_count_0;
+extern ffeCounter ffe_count_1;
+extern ffeCounter ffe_count_2;
+extern ffeCounter ffe_count_3;
+extern ffeCounter ffe_count_4;
+extern bool ffe_in_0;
+extern bool ffe_in_1;
+extern bool ffe_in_2;
+extern bool ffe_in_3;
+extern bool ffe_in_4;
+
+/* Declare functions with prototypes. */
+
+int ffe_decode_option (int argc, char **argv);
+void ffe_file (ffewhereFile wf, FILE *f);
+void ffe_init_0 (void);
+void ffe_init_1 (void);
+void ffe_init_2 (void);
+void ffe_init_3 (void);
+void ffe_init_4 (void);
+void ffe_terminate_0 (void);
+void ffe_terminate_1 (void);
+void ffe_terminate_2 (void);
+void ffe_terminate_3 (void);
+void ffe_terminate_4 (void);
+
+/* Define macros. */
+
+#define ffe_case_intrin() ffe_case_intrin_
+#define ffe_case_match() ffe_case_match_
+#define ffe_case_source() ffe_case_source_
+#define ffe_case_symbol() ffe_case_symbol_
+#define ffe_intrinsic_state_badu77() ffe_intrinsic_state_badu77_
+#define ffe_intrinsic_state_f2c() ffe_intrinsic_state_f2c_
+#define ffe_intrinsic_state_f90() ffe_intrinsic_state_f90_
+#define ffe_intrinsic_state_gnu() ffe_intrinsic_state_gnu_
+#define ffe_intrinsic_state_mil() ffe_intrinsic_state_mil_
+#define ffe_intrinsic_state_unix() ffe_intrinsic_state_unix_
+#define ffe_intrinsic_state_vxt() ffe_intrinsic_state_vxt_
+#define ffe_is_90() ffe_is_90_
+#define ffe_is_automatic() ffe_is_automatic_
+#define ffe_is_backslash() ffe_is_backslash_
+#define ffe_is_debug_kludge() ffe_is_debug_kludge_
+#define ffe_is_do_internal_checks() ffe_is_do_internal_checks_
+#define ffe_is_dollar_ok() ffe_is_dollar_ok_
+#define ffe_is_emulate_complex() ffe_is_emulate_complex_
+#define ffe_is_f2c() ffe_is_f2c_
+#define ffe_is_f2c_library() ffe_is_f2c_library_
+#define ffe_is_ffedebug() ffe_is_ffedebug_
+#define ffe_is_free_form() ffe_is_free_form_
+#define ffe_is_globals() ffe_is_globals_
+#define ffe_is_ident() ffe_is_ident_
+#define ffe_is_init_local_zero() ffe_is_init_local_zero_
+#define ffe_is_mainprog() ffe_is_mainprog_
+#define ffe_is_null_version() ffe_is_null_version_
+#define ffe_is_onetrip() ffe_is_onetrip_
+#define ffe_is_pedantic() ffe_is_pedantic_
+#define ffe_is_pedantic_not_90() (ffe_is_pedantic_ && !ffe_is_90_)
+#define ffe_is_saveall() ffe_is_saveall_
+#define ffe_is_second_underscore() ffe_is_second_underscore_
+#define ffe_is_silent() ffe_is_silent_
+#define ffe_is_typeless_boz() ffe_is_typeless_boz_
+#define ffe_is_ugly_args() ffe_is_ugly_args_
+#define ffe_is_ugly_assign() ffe_is_ugly_assign_
+#define ffe_is_ugly_assumed() ffe_is_ugly_assumed_
+#define ffe_is_ugly_comma() ffe_is_ugly_comma_
+#define ffe_is_ugly_complex() ffe_is_ugly_complex_
+#define ffe_is_ugly_init() ffe_is_ugly_init_
+#define ffe_is_ugly_logint() ffe_is_ugly_logint_
+#define ffe_is_underscoring() ffe_is_underscoring_
+#define ffe_is_version() ffe_is_version_
+#define ffe_is_vxt() ffe_is_vxt_
+#define ffe_is_warn_globals() ffe_is_warn_globals_
+#define ffe_is_warn_implicit() ffe_is_warn_implicit_
+#define ffe_is_warn_surprising() ffe_is_warn_surprising_
+#define ffe_is_zeros() ffe_is_zeros_
+#define ffe_fixed_line_length() ffe_fixed_line_length_
+#define ffe_pool_file() (ffe_file_pool_)
+#define ffe_pool_any_unit() (ffe_any_unit_pool_)
+#define ffe_pool_program_unit() (ffe_program_unit_pool_)
+#define ffe_set_case_intrin(f) (ffe_case_intrin_ = (f))
+#define ffe_set_case_match(f) (ffe_case_match_ = (f))
+#define ffe_set_case_source(f) (ffe_case_source_ = (f))
+#define ffe_set_case_symbol(f) (ffe_case_symbol_ = (f))
+#define ffe_set_intrinsic_state_badu77(s) (ffe_intrinsic_state_badu77_ = (s))
+#define ffe_set_intrinsic_state_f2c(s) (ffe_intrinsic_state_f2c_ = (s))
+#define ffe_set_intrinsic_state_f90(s) (ffe_intrinsic_state_f90_ = (s))
+#define ffe_set_intrinsic_state_gnu(s) (ffe_intrinsic_state_gnu_ = (s))
+#define ffe_set_intrinsic_state_mil(s) (ffe_intrinsic_state_mil_ = (s))
+#define ffe_set_intrinsic_state_unix(s) (ffe_intrinsic_state_unix_ = (s))
+#define ffe_set_intrinsic_state_vxt(s) (ffe_intrinsic_state_vxt_ = (s))
+#define ffe_set_is_90(f) (ffe_is_90_ = (f))
+#define ffe_set_is_automatic(f) (ffe_is_automatic_ = (f))
+#define ffe_set_is_backslash(f) (ffe_is_backslash_ = (f))
+#define ffe_set_is_debug_kludge(f) (ffe_is_debug_kludge_ = (f))
+#define ffe_set_is_do_internal_checks(f) (ffe_is_do_internal_checks_ = (f))
+#define ffe_set_is_dollar_ok(f) (ffe_is_dollar_ok_ = (f))
+#define ffe_set_is_emulate_complex(f) (ffe_is_emulate_complex_ = (f))
+#define ffe_set_is_f2c(f) (ffe_is_f2c_ = (f))
+#define ffe_set_is_f2c_library(f) (ffe_is_f2c_library_ = (f))
+#define ffe_set_is_ffedebug(f) (ffe_is_ffedebug_ = (f))
+#define ffe_set_is_free_form(f) (ffe_is_free_form_ = (f))
+#define ffe_set_is_globals(f) (ffe_is_globals_ = (f))
+#define ffe_set_is_ident(f) (ffe_is_ident_ = (f))
+#define ffe_set_is_init_local_zero(f) (ffe_is_init_local_zero_ = (f))
+#define ffe_set_is_mainprog(f) (ffe_is_mainprog_ = (f))
+#define ffe_set_is_null_version(f) (ffe_is_null_version_ = (f))
+#define ffe_set_is_onetrip(f) (ffe_is_onetrip_ = (f))
+#define ffe_set_is_pedantic(f) (ffe_is_pedantic_ = (f))
+#define ffe_set_is_saveall(f) (ffe_is_saveall_ = (f))
+#define ffe_set_is_second_underscore(f) (ffe_is_second_underscore_ = (f))
+#define ffe_set_is_silent(f) (ffe_is_silent_ = (f))
+#define ffe_set_is_typeless_boz(f) (ffe_is_typeless_boz_ = (f))
+#define ffe_set_is_ugly_args(f) (ffe_is_ugly_args_ = (f))
+#define ffe_set_is_ugly_assign(f) (ffe_is_ugly_assign_ = (f))
+#define ffe_set_is_ugly_assumed(f) (ffe_is_ugly_assumed_ = (f))
+#define ffe_set_is_ugly_comma(f) (ffe_is_ugly_comma_ = (f))
+#define ffe_set_is_ugly_complex(f) (ffe_is_ugly_complex_ = (f))
+#define ffe_set_is_ugly_init(f) (ffe_is_ugly_init_ = (f))
+#define ffe_set_is_ugly_logint(f) (ffe_is_ugly_logint_ = (f))
+#define ffe_set_is_underscoring(f) (ffe_is_underscoring_ = (f))
+#define ffe_set_is_version(f) (ffe_is_version_ = (f))
+#define ffe_set_is_vxt(f) (ffe_is_vxt_ = (f))
+#define ffe_set_is_warn_globals(f) (ffe_is_warn_globals_ = (f))
+#define ffe_set_is_warn_implicit(f) (ffe_is_warn_implicit_ = (f))
+#define ffe_set_is_warn_surprising(f) (ffe_is_warn_surprising_ = (f))
+#define ffe_set_is_zeros(f) (ffe_is_zeros_ = (f))
+#define ffe_set_fixed_line_length(l) (ffe_fixed_line_length_ = (l))
+#define ffe_state_max(s1,s2) ((s1) > (s2) ? (s1) : (s2))
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/f/toplev.j b/contrib/gcc/f/toplev.j
new file mode 100644
index 0000000..9ee892b
--- /dev/null
+++ b/contrib/gcc/f/toplev.j
@@ -0,0 +1,27 @@
+/* toplev.j -- Wrapper for GCC's toplev.h
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_toplev
+#define _J_f_toplev
+#include "toplev.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/tree.j b/contrib/gcc/f/tree.j
new file mode 100644
index 0000000..009af12
--- /dev/null
+++ b/contrib/gcc/f/tree.j
@@ -0,0 +1,28 @@
+/* tree.j -- Wrapper for GCC's tree.h
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef MAKING_DEPENDENCIES
+#ifndef _J_f_tree
+#define _J_f_tree
+#include "config.j"
+#include "tree.h"
+#endif
+#endif
diff --git a/contrib/gcc/f/type.c b/contrib/gcc/f/type.c
new file mode 100644
index 0000000..76f0e87
--- /dev/null
+++ b/contrib/gcc/f/type.c
@@ -0,0 +1,107 @@
+/* Implementation of Fortran type abstraction
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "proj.h"
+#include "type.h"
+#include "malloc.h"
+
+
+/* Look up a type given its base type and kind value. */
+
+ffetype
+ffetype_lookup_kind (ffetype base_type, int kind)
+{
+ if ((base_type->kinds_ == NULL)
+ || (kind < 0)
+ || (((size_t) kind) >= ARRAY_SIZE (base_type->kinds_->type_)))
+ return NULL;
+
+ return base_type->kinds_->type_[kind];
+}
+
+ffetype
+ffetype_lookup_star (ffetype base_type, int star)
+{
+ if ((base_type->stars_ == NULL)
+ || (star < 0)
+ || (((size_t) star) >= ARRAY_SIZE (base_type->stars_->type_)))
+ return NULL;
+
+ return base_type->stars_->type_[star];
+}
+
+ffetype
+ffetype_new (void)
+{
+ ffetype type;
+
+ type = (ffetype) malloc_new_kp (malloc_pool_image (), "ffetype",
+ sizeof (*type));
+ type->kinds_ = NULL;
+ type->stars_ = NULL;
+ type->alignment_ = 0;
+ type->modulo_ = 0;
+ type->size_ = 0;
+
+ return type;
+}
+
+void
+ffetype_set_kind (ffetype base_type, int kind, ffetype type)
+{
+ assert (kind < (int) sizeof (*(base_type->kinds_)));
+
+ if (base_type->kinds_ == NULL)
+ {
+ int i;
+
+ base_type->kinds_
+ = (ffetype_indexes_) malloc_new_kp (malloc_pool_image (),
+ "ffetype_indexes_[kinds]",
+ sizeof (*(base_type->kinds_)));
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (base_type->kinds_->type_); ++i)
+ base_type->kinds_->type_[i] = NULL;
+ }
+
+ assert (base_type->kinds_->type_[kind] == NULL);
+
+ base_type->kinds_->type_[kind] = type;
+}
+
+void
+ffetype_set_star (ffetype base_type, int star, ffetype type)
+{
+ if (base_type->stars_ == NULL)
+ {
+ int i;
+
+ base_type->stars_
+ = (ffetype_indexes_) malloc_new_kp (malloc_pool_image (),
+ "ffetype_indexes_[stars]",
+ sizeof (*(base_type->stars_)));
+ for (i = 0; ((size_t) i) < ARRAY_SIZE (base_type->stars_->type_); ++i)
+ base_type->stars_->type_[i] = NULL;
+ }
+
+ assert (base_type->stars_->type_[star] == NULL);
+
+ base_type->stars_->type_[star] = type;
+}
diff --git a/contrib/gcc/f/type.h b/contrib/gcc/f/type.h
new file mode 100644
index 0000000..94d6404
--- /dev/null
+++ b/contrib/gcc/f/type.h
@@ -0,0 +1,64 @@
+/* Interface definitions for Fortran type abstraction
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#ifndef _H_f_type
+#define _H_f_type
+
+typedef struct _ffetype_ *ffetype;
+typedef struct _ffetype_indexes_ *ffetype_indexes_;
+
+struct _ffetype_
+ {
+ ffetype_indexes_ kinds_;
+ ffetype_indexes_ stars_;
+ int alignment_;
+ int modulo_;
+ int size_;
+ };
+
+struct _ffetype_indexes_
+ {
+ ffetype type_[40]; /* *n, KIND=n: 0 <= n <= 39. */
+ };
+
+#define ffetype_alignment(t) ((t)->alignment_)
+#define ffetype_init_0()
+#define ffetype_init_1()
+#define ffetype_init_2()
+#define ffetype_init_3()
+#define ffetype_init_4()
+ffetype ffetype_lookup_kind (ffetype base_type, int kind);
+ffetype ffetype_lookup_star (ffetype base_type, int star);
+#define ffetype_modulo(t) ((t)->modulo_)
+ffetype ffetype_new (void);
+#define ffetype_set_ams(t,a,m,s) ((t)->alignment_ = (a), \
+ (t)->modulo_ = (m), \
+ (t)->size_ = (s))
+void ffetype_set_kind (ffetype base_type, int kind, ffetype type);
+void ffetype_set_star (ffetype base_type, int star, ffetype type);
+#define ffetype_size(t) ((t)->size_)
+#define ffetype_terminate_0()
+#define ffetype_terminate_1()
+#define ffetype_terminate_2()
+#define ffetype_terminate_3()
+#define ffetype_terminate_4()
+
+#endif
diff --git a/contrib/gcc/f/version.c b/contrib/gcc/f/version.c
new file mode 100644
index 0000000..3d5baf7
--- /dev/null
+++ b/contrib/gcc/f/version.c
@@ -0,0 +1 @@
+char *ffe_version_string = "0.5.24-19981002";
diff --git a/contrib/gcc/f/version.h b/contrib/gcc/f/version.h
new file mode 100644
index 0000000..cd578a8
--- /dev/null
+++ b/contrib/gcc/f/version.h
@@ -0,0 +1,6 @@
+#ifndef _H_f_version
+#define _H_f_version
+
+extern char *ffe_version_string;
+
+#endif
diff --git a/contrib/gcc/f/where.c b/contrib/gcc/f/where.c
new file mode 100644
index 0000000..89e0f85
--- /dev/null
+++ b/contrib/gcc/f/where.c
@@ -0,0 +1,542 @@
+/* where.c -- Implementation File (module.c template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Related Modules:
+
+ Description:
+ Simple data abstraction for Fortran source lines (called card images).
+
+ Modifications:
+*/
+
+/* Include files. */
+
+#include "proj.h"
+#include "where.h"
+#include "lex.h"
+#include "malloc.h"
+
+/* Externals defined here. */
+
+struct _ffewhere_line_ ffewhere_unknown_line_
+=
+{NULL, NULL, 0, 0, 0};
+
+/* Simple definitions and enumerations. */
+
+
+/* Internal typedefs. */
+
+typedef struct _ffewhere_ll_ *ffewhereLL_;
+
+/* Private include files. */
+
+
+/* Internal structure definitions. */
+
+struct _ffewhere_ll_
+ {
+ ffewhereLL_ next;
+ ffewhereLL_ previous;
+ ffewhereFile wf;
+ ffewhereLineNumber line_no; /* ffelex_line_number() at time of creation. */
+ ffewhereLineNumber offset; /* User-desired offset (usually 1). */
+ };
+
+struct _ffewhere_root_ll_
+ {
+ ffewhereLL_ first;
+ ffewhereLL_ last;
+ };
+
+struct _ffewhere_root_line_
+ {
+ ffewhereLine first;
+ ffewhereLine last;
+ ffewhereLineNumber none;
+ };
+
+/* Static objects accessed by functions in this module. */
+
+static struct _ffewhere_root_ll_ ffewhere_root_ll_;
+static struct _ffewhere_root_line_ ffewhere_root_line_;
+
+/* Static functions (internal). */
+
+static ffewhereLL_ ffewhere_ll_lookup_ (ffewhereLineNumber ln);
+
+/* Internal macros. */
+
+
+/* Look up line-to-line object from absolute line num. */
+
+static ffewhereLL_
+ffewhere_ll_lookup_ (ffewhereLineNumber ln)
+{
+ ffewhereLL_ ll;
+
+ if (ln == 0)
+ return ffewhere_root_ll_.first;
+
+ for (ll = ffewhere_root_ll_.last;
+ ll != (ffewhereLL_) &ffewhere_root_ll_.first;
+ ll = ll->previous)
+ {
+ if (ll->line_no <= ln)
+ return ll;
+ }
+
+ assert ("no line num" == NULL);
+ return NULL;
+}
+
+/* Kill file object.
+
+ Note that this object must not have been passed in a call
+ to any other ffewhere function except ffewhere_file_name and
+ ffewhere_file_namelen. */
+
+void
+ffewhere_file_kill (ffewhereFile wf)
+{
+ malloc_kill_ks (ffe_pool_file (), wf,
+ offsetof (struct _ffewhere_file_, text)
+ + wf->length + 1);
+}
+
+/* Create file object. */
+
+ffewhereFile
+ffewhere_file_new (char *name, size_t length)
+{
+ ffewhereFile wf;
+
+ wf = malloc_new_ks (ffe_pool_file (), "ffewhereFile",
+ offsetof (struct _ffewhere_file_, text)
+ + length + 1);
+ wf->length = length;
+ memcpy (&wf->text[0], name, length);
+ wf->text[length] = '\0';
+
+ return wf;
+}
+
+/* Set file and first line number.
+
+ Pass FALSE if no line number is specified. */
+
+void
+ffewhere_file_set (ffewhereFile wf, bool have_num, ffewhereLineNumber ln)
+{
+ ffewhereLL_ ll;
+
+ ll = malloc_new_kp (ffe_pool_file (), "ffewhereLL_", sizeof (*ll));
+ ll->next = (ffewhereLL_) &ffewhere_root_ll_.first;
+ ll->previous = ffewhere_root_ll_.last;
+ ll->next->previous = ll;
+ ll->previous->next = ll;
+ if (wf == NULL)
+ {
+ if (ll->previous == ll->next)
+ ll->wf = NULL;
+ else
+ ll->wf = ll->previous->wf;
+ }
+ else
+ ll->wf = wf;
+ ll->line_no = ffelex_line_number ();
+ if (have_num)
+ ll->offset = ln;
+ else
+ {
+ if (ll->previous == ll->next)
+ ll->offset = 1;
+ else
+ ll->offset
+ = ll->line_no - ll->previous->line_no + ll->previous->offset;
+ }
+}
+
+/* Do initializations. */
+
+void
+ffewhere_init_1 ()
+{
+ ffewhere_root_line_.first = ffewhere_root_line_.last
+ = (ffewhereLine) &ffewhere_root_line_.first;
+ ffewhere_root_line_.none = 0;
+
+ ffewhere_root_ll_.first = ffewhere_root_ll_.last
+ = (ffewhereLL_) &ffewhere_root_ll_.first;
+}
+
+/* Return the textual content of the line. */
+
+char *
+ffewhere_line_content (ffewhereLine wl)
+{
+ assert (wl != NULL);
+ return wl->content;
+}
+
+/* Look up file object from line object. */
+
+ffewhereFile
+ffewhere_line_file (ffewhereLine wl)
+{
+ ffewhereLL_ ll;
+
+ assert (wl != NULL);
+ ll = ffewhere_ll_lookup_ (wl->line_num);
+ return ll->wf;
+}
+
+/* Lookup file object from line object, calc line#. */
+
+ffewhereLineNumber
+ffewhere_line_filelinenum (ffewhereLine wl)
+{
+ ffewhereLL_ ll;
+
+ assert (wl != NULL);
+ ll = ffewhere_ll_lookup_ (wl->line_num);
+ return wl->line_num + ll->offset - ll->line_no;
+}
+
+/* Decrement use count for line, deallocate if no uses left. */
+
+void
+ffewhere_line_kill (ffewhereLine wl)
+{
+#if 0
+ if (!ffewhere_line_is_unknown (wl))
+ fprintf (dmpout, "; ffewhere_line_kill %" ffewhereLineNumber_f "u, uses=%"
+ ffewhereUses_f_ "u\n",
+ wl->line_num, wl->uses);
+#endif
+ assert (ffewhere_line_is_unknown (wl) || (wl->uses != 0));
+ if (!ffewhere_line_is_unknown (wl) && (--wl->uses == 0))
+ {
+ wl->previous->next = wl->next;
+ wl->next->previous = wl->previous;
+ malloc_kill_ks (ffe_pool_file (), wl,
+ offsetof (struct _ffewhere_line_, content)
+ + wl->length + 1);
+ }
+}
+
+/* Make a new line or increment use count of existing one.
+
+ Find out where line object is, if anywhere. If in lexer, it might also
+ be at the end of the list of lines, else put it on the end of the list.
+ Then, if in the list of lines, increment the use count and return the
+ line object. Else, make an empty line object (no line) and return
+ that. */
+
+ffewhereLine
+ffewhere_line_new (ffewhereLineNumber ln)
+{
+ ffewhereLine wl = ffewhere_root_line_.last;
+
+ /* If this is the lexer's current line, see if it is already at the end of
+ the list, and if not, make it and return it. */
+
+ if (((ln == 0) /* Presumably asking for EOF pointer. */
+ || (wl->line_num != ln))
+ && (ffelex_line_number () == ln))
+ {
+#if 0
+ fprintf (dmpout,
+ "; ffewhere_line_new %" ffewhereLineNumber_f "u, lexer\n",
+ ln);
+#endif
+ wl = malloc_new_ks (ffe_pool_file (), "FFEWHERE line",
+ offsetof (struct _ffewhere_line_, content)
+ + (size_t) ffelex_line_length () + 1);
+ wl->next = (ffewhereLine) &ffewhere_root_line_;
+ wl->previous = ffewhere_root_line_.last;
+ wl->previous->next = wl;
+ wl->next->previous = wl;
+ wl->line_num = ln;
+ wl->uses = 1;
+ wl->length = ffelex_line_length ();
+ strcpy (wl->content, ffelex_line ());
+ return wl;
+ }
+
+ /* See if line is on list already. */
+
+ while (wl->line_num > ln)
+ wl = wl->previous;
+
+ /* If line is there, increment its use count and return. */
+
+ if (wl->line_num == ln)
+ {
+#if 0
+ fprintf (dmpout, "; ffewhere_line_new %" ffewhereLineNumber_f "u, uses=%"
+ ffewhereUses_f_ "u\n", ln,
+ wl->uses);
+#endif
+ wl->uses++;
+ return wl;
+ }
+
+ /* Else, make a new one with a blank line (since we've obviously lost it,
+ which should never happen) and return it. */
+
+ fprintf (stderr,
+ "(Cannot resurrect line %lu for error reporting purposes.)\n",
+ ln);
+
+ wl = malloc_new_ks (ffe_pool_file (), "FFEWHERE line",
+ offsetof (struct _ffewhere_line_, content)
+ + 1);
+ wl->next = (ffewhereLine) &ffewhere_root_line_;
+ wl->previous = ffewhere_root_line_.last;
+ wl->previous->next = wl;
+ wl->next->previous = wl;
+ wl->line_num = ln;
+ wl->uses = 1;
+ wl->length = 0;
+ *(wl->content) = '\0';
+ return wl;
+}
+
+/* Increment use count of line, as in a copy. */
+
+ffewhereLine
+ffewhere_line_use (ffewhereLine wl)
+{
+#if 0
+ fprintf (dmpout, "; ffewhere_line_use %" ffewhereLineNumber_f "u, uses=%" ffewhereUses_f_
+ "u\n", wl->line_num, wl->uses);
+#endif
+ assert (ffewhere_line_is_unknown (wl) || (wl->uses != 0));
+ if (!ffewhere_line_is_unknown (wl))
+ ++wl->uses;
+ return wl;
+}
+
+/* Set an ffewhere object based on a track index.
+
+ Determines the absolute line and column number of a character at a given
+ index into an ffewhereTrack array. wr* is the reference position, wt is
+ the tracking information, and i is the index desired. wo* is set to wr*
+ plus the continual offsets described by wt[0...i-1], or unknown if any of
+ the continual offsets are not known. */
+
+void
+ffewhere_set_from_track (ffewhereLine *wol, ffewhereColumn *woc,
+ ffewhereLine wrl, ffewhereColumn wrc,
+ ffewhereTrack wt, ffewhereIndex i)
+{
+ ffewhereLineNumber ln;
+ ffewhereColumnNumber cn;
+ ffewhereIndex j;
+ ffewhereIndex k;
+
+ if ((i == 0) || (i >= FFEWHERE_indexMAX))
+ {
+ *wol = ffewhere_line_use (wrl);
+ *woc = ffewhere_column_use (wrc);
+ }
+ else
+ {
+ ln = ffewhere_line_number (wrl);
+ cn = ffewhere_column_number (wrc);
+ for (j = 0, k = 0; j < i; ++j, k += 2)
+ {
+ if ((wt[k] == FFEWHERE_indexUNKNOWN)
+ || (wt[k + 1] == FFEWHERE_indexUNKNOWN))
+ {
+ *wol = ffewhere_line_unknown ();
+ *woc = ffewhere_column_unknown ();
+ return;
+ }
+ if (wt[k] == 0)
+ cn += wt[k + 1] + 1;
+ else
+ {
+ ln += wt[k];
+ cn = wt[k + 1] + 1;
+ }
+ }
+ if (ln == ffewhere_line_number (wrl))
+ { /* Already have the line object, just use it
+ directly. */
+ *wol = ffewhere_line_use (wrl);
+ }
+ else /* Must search for the line object. */
+ *wol = ffewhere_line_new (ln);
+ *woc = ffewhere_column_new (cn);
+ }
+}
+
+/* Build next tracking index.
+
+ Set wt[i-1] continual offset so that it offsets from w* to (ln,cn). Update
+ w* to contain (ln,cn). DO NOT call this routine if i >= FFEWHERE_indexMAX
+ or i == 0. */
+
+void
+ffewhere_track (ffewhereLine *wl, ffewhereColumn *wc, ffewhereTrack wt,
+ ffewhereIndex i, ffewhereLineNumber ln,
+ ffewhereColumnNumber cn)
+{
+ unsigned int lo;
+ unsigned int co;
+
+ if ((ffewhere_line_is_unknown (*wl))
+ || (ffewhere_column_is_unknown (*wc))
+ || ((lo = ln - ffewhere_line_number (*wl)) >= FFEWHERE_indexUNKNOWN))
+ {
+ wt[i * 2 - 2] = wt[i * 2 - 1] = FFEWHERE_indexUNKNOWN;
+ ffewhere_line_kill (*wl);
+ ffewhere_column_kill (*wc);
+ *wl = FFEWHERE_lineUNKNOWN;
+ *wc = FFEWHERE_columnUNKNOWN;
+ }
+ else if (lo == 0)
+ {
+ wt[i * 2 - 2] = 0;
+ if ((co = cn - ffewhere_column_number (*wc)) > FFEWHERE_indexUNKNOWN)
+ {
+ wt[i * 2 - 1] = FFEWHERE_indexUNKNOWN;
+ ffewhere_line_kill (*wl);
+ ffewhere_column_kill (*wc);
+ *wl = FFEWHERE_lineUNKNOWN;
+ *wc = FFEWHERE_columnUNKNOWN;
+ }
+ else
+ {
+ wt[i * 2 - 1] = co - 1;
+ ffewhere_column_kill (*wc);
+ *wc = ffewhere_column_use (ffewhere_column_new (cn));
+ }
+ }
+ else
+ {
+ wt[i * 2 - 2] = lo;
+ if (cn > FFEWHERE_indexUNKNOWN)
+ {
+ wt[i * 2 - 1] = FFEWHERE_indexUNKNOWN;
+ ffewhere_line_kill (*wl);
+ ffewhere_column_kill (*wc);
+ *wl = ffewhere_line_unknown ();
+ *wc = ffewhere_column_unknown ();
+ }
+ else
+ {
+ wt[i * 2 - 1] = cn - 1;
+ ffewhere_line_kill (*wl);
+ ffewhere_column_kill (*wc);
+ *wl = ffewhere_line_use (ffewhere_line_new (ln));
+ *wc = ffewhere_column_use (ffewhere_column_new (cn));
+ }
+ }
+}
+
+/* Clear tracking index for internally created track.
+
+ Set the tracking information to indicate that the tracking is at its
+ simplest (no spaces or newlines within the tracking). This means set
+ everything to zero in the current implementation. Length is the total
+ length of the token; length must be 2 or greater, since length-1 tracking
+ characters are set. */
+
+void
+ffewhere_track_clear (ffewhereTrack wt, ffewhereIndex length)
+{
+ ffewhereIndex i;
+
+ if (length > FFEWHERE_indexMAX)
+ length = FFEWHERE_indexMAX;
+
+ for (i = 1; i < length; ++i)
+ wt[i * 2 - 2] = wt[i * 2 - 1] = 0;
+}
+
+/* Copy tracking index from one place to another.
+
+ Copy tracking information from swt[start] to dwt[0] and so on, presumably
+ after an ffewhere_set_from_track call. Length is the total
+ length of the token; length must be 2 or greater, since length-1 tracking
+ characters are set. */
+
+void
+ffewhere_track_copy (ffewhereTrack dwt, ffewhereTrack swt, ffewhereIndex start,
+ ffewhereIndex length)
+{
+ ffewhereIndex i;
+ ffewhereIndex copy;
+
+ if (length > FFEWHERE_indexMAX)
+ length = FFEWHERE_indexMAX;
+
+ if (length + start > FFEWHERE_indexMAX)
+ copy = FFEWHERE_indexMAX - start;
+ else
+ copy = length;
+
+ for (i = 1; i < copy; ++i)
+ {
+ dwt[i * 2 - 2] = swt[(i + start) * 2 - 2];
+ dwt[i * 2 - 1] = swt[(i + start) * 2 - 1];
+ }
+
+ for (; i < length; ++i)
+ {
+ dwt[i * 2 - 2] = 0;
+ dwt[i * 2 - 1] = 0;
+ }
+}
+
+/* Kill tracking data.
+
+ Kill all the tracking information by killing incremented lines from the
+ first line number. */
+
+void
+ffewhere_track_kill (ffewhereLine wrl, ffewhereColumn wrc UNUSED,
+ ffewhereTrack wt, ffewhereIndex length)
+{
+ ffewhereLineNumber ln;
+ unsigned int lo;
+ ffewhereIndex i;
+
+ ln = ffewhere_line_number (wrl);
+
+ if (length > FFEWHERE_indexMAX)
+ length = FFEWHERE_indexMAX;
+
+ for (i = 0; i < length - 1; ++i)
+ {
+ if ((lo = wt[i * 2]) == FFEWHERE_indexUNKNOWN)
+ break;
+ else if (lo != 0)
+ {
+ ln += lo;
+ wrl = ffewhere_line_new (ln);
+ ffewhere_line_kill (wrl);
+ }
+ }
+}
diff --git a/contrib/gcc/f/where.h b/contrib/gcc/f/where.h
new file mode 100644
index 0000000..2091f36
--- /dev/null
+++ b/contrib/gcc/f/where.h
@@ -0,0 +1,138 @@
+/* where.h -- Public #include File (module.h template V1.0)
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by James Craig Burley (burley@gnu.org).
+
+This file is part of GNU Fortran.
+
+GNU Fortran 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, or (at your option)
+any later version.
+
+GNU Fortran 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 GNU Fortran; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.
+
+ Owning Modules:
+ where.c
+
+ Modifications:
+*/
+
+/* Allow multiple inclusion to work. */
+
+#ifndef _H_f_where
+#define _H_f_where
+
+/* Simple definitions and enumerations. */
+
+#define FFEWHERE_columnMAX UCHAR_MAX
+#define FFEWHERE_columnUNKNOWN 0
+#define FFEWHERE_indexMAX 36
+#define FFEWHERE_indexUNKNOWN UCHAR_MAX
+#define FFEWHERE_lineMAX ULONG_MAX
+#define FFEWHERE_lineUNKNOWN (&ffewhere_unknown_line_)
+#define FFEWHERE_filenameUNKNOWN ("(input file)")
+
+/* Typedefs. */
+
+typedef unsigned char ffewhereColumnNumber; /* Change FFEWHERE_columnMAX
+ too. */
+#define ffewhereColumnNumber_f ""
+typedef unsigned char ffewhereColumn;
+typedef struct _ffewhere_file_ *ffewhereFile;
+typedef unsigned short ffewhereLength_;
+#define ffewhereLength_f_ ""
+typedef unsigned long ffewhereLineNumber; /* Change FFEWHERE_lineMAX
+ too. */
+#define ffewhereLineNumber_f "l"
+typedef struct _ffewhere_line_ *ffewhereLine;
+typedef unsigned char ffewhereIndex;
+#define ffewhereIndex_f ""
+typedef ffewhereIndex ffewhereTrack[FFEWHERE_indexMAX * 2 - 2];
+typedef unsigned int ffewhereUses_;
+#define ffewhereUses_f_ ""
+
+/* Include files needed by this one. */
+
+#include "glimits.j"
+#include "top.h"
+
+/* Structure definitions. */
+
+struct _ffewhere_file_
+ {
+ size_t length;
+ char text[1];
+ };
+
+struct _ffewhere_line_
+ {
+ ffewhereLine next;
+ ffewhereLine previous;
+ ffewhereLineNumber line_num;
+ ffewhereUses_ uses;
+ ffewhereLength_ length;
+ char content[1];
+ };
+
+/* Global objects accessed by users of this module. */
+
+extern struct _ffewhere_line_ ffewhere_unknown_line_;
+
+/* Declare functions with prototypes. */
+
+void ffewhere_file_kill (ffewhereFile wf);
+ffewhereFile ffewhere_file_new (char *name, size_t length);
+void ffewhere_file_set (ffewhereFile wf, bool have_num, ffewhereLineNumber ln);
+void ffewhere_init_1 (void);
+char *ffewhere_line_content (ffewhereLine l);
+ffewhereFile ffewhere_line_file (ffewhereLine l);
+ffewhereLineNumber ffewhere_line_filelinenum (ffewhereLine l);
+void ffewhere_line_kill (ffewhereLine l);
+ffewhereLine ffewhere_line_new (ffewhereLineNumber ln);
+ffewhereLine ffewhere_line_use (ffewhereLine wl);
+void ffewhere_set_from_track (ffewhereLine *wol, ffewhereColumn *woc,
+ ffewhereLine wrl, ffewhereColumn wrc, ffewhereTrack wt,
+ ffewhereIndex i);
+void ffewhere_track (ffewhereLine *wl, ffewhereColumn *wc, ffewhereTrack wt,
+ ffewhereIndex i, ffewhereLineNumber ln, ffewhereColumnNumber cn);
+void ffewhere_track_clear (ffewhereTrack wt, ffewhereIndex length);
+void ffewhere_track_copy (ffewhereTrack dwt, ffewhereTrack swt,
+ ffewhereIndex start, ffewhereIndex length);
+void ffewhere_track_kill (ffewhereLine wrl, ffewhereColumn wrc, ffewhereTrack wt,
+ ffewhereIndex length);
+
+/* Define macros. */
+
+#define ffewhere_column_is_unknown(c) (c == FFEWHERE_columnUNKNOWN)
+#define ffewhere_column_kill(c) ((void) 0)
+#define ffewhere_column_new(cn) (cn)
+#define ffewhere_column_number(c) (c)
+#define ffewhere_column_unknown() (FFEWHERE_columnUNKNOWN)
+#define ffewhere_column_use(c) (c)
+#define ffewhere_file_name(f) ((f)->text)
+#define ffewhere_file_namelen(f) ((f)->length)
+#define ffewhere_init_0()
+#define ffewhere_init_2()
+#define ffewhere_init_3()
+#define ffewhere_init_4()
+#define ffewhere_line_filename(l) (ffewhere_line_file(l)->text)
+#define ffewhere_line_is_unknown(l) (l == FFEWHERE_lineUNKNOWN)
+#define ffewhere_line_number(l) ((l)->line_num)
+#define ffewhere_line_unknown() (FFEWHERE_lineUNKNOWN)
+#define ffewhere_terminate_0()
+#define ffewhere_terminate_1()
+#define ffewhere_terminate_2()
+#define ffewhere_terminate_3()
+#define ffewhere_terminate_4()
+
+/* End of #include file. */
+
+#endif
diff --git a/contrib/gcc/final.c b/contrib/gcc/final.c
index 481782e..4b05fc7 100644
--- a/contrib/gcc/final.c
+++ b/contrib/gcc/final.c
@@ -1,5 +1,5 @@
/* Convert RTL to assembler code and output it, for GNU compiler.
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -50,8 +50,7 @@ Boston, MA 02111-1307, USA. */
#else
#include <varargs.h>
#endif
-#include <stdio.h>
-#include <ctype.h>
+#include "system.h"
#include "tree.h"
#include "rtl.h"
@@ -67,20 +66,37 @@ Boston, MA 02111-1307, USA. */
#include "hard-reg-set.h"
#include "defaults.h"
#include "output.h"
+#include "except.h"
+#include "toplev.h"
+#include "reload.h"
/* Get N_SLINE and N_SOL from stab.h if we can expect the file to exist. */
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
-#if defined (USG) || defined (NO_STAB_H)
+#include "dbxout.h"
+#if defined (USG) || !defined (HAVE_STAB_H)
#include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */
#else
-#include <stab.h> /* On BSD, use the system's stab.h. */
-#endif /* not USG */
+#include <stab.h>
+#endif
+
#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
#endif
+#ifdef DWARF_DEBUGGING_INFO
+#include "dwarfout.h"
+#endif
+
+#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
+#include "dwarf2out.h"
+#endif
+
+#ifdef SDB_DEBUGGING_INFO
+#include "sdbout.h"
+#endif
+
/* .stabd code for line number. */
#ifndef N_SLINE
#define N_SLINE 0x44
@@ -95,6 +111,10 @@ Boston, MA 02111-1307, USA. */
#define INT_TYPE_SIZE BITS_PER_WORD
#endif
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
/* If we aren't using cc0, CC_STATUS_INIT shouldn't exist. So define a
null default for it to save conditionalization later. */
#ifndef CC_STATUS_INIT
@@ -111,6 +131,10 @@ Boston, MA 02111-1307, USA. */
#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';')
#endif
+#ifndef JUMP_TABLES_IN_TEXT_SECTION
+#define JUMP_TABLES_IN_TEXT_SECTION 0
+#endif
+
/* Nonzero means this function is a leaf function, with no function calls.
This variable exists to be examined in FUNCTION_PROLOGUE
and FUNCTION_EPILOGUE. Always zero, unless set by some action. */
@@ -135,13 +159,18 @@ static char *last_filename;
used if profile_block_flag is set. */
static int count_basic_blocks;
+/* Number of instrumented arcs when profile_arc_flag is set. */
+extern int count_instrumented_arcs;
+
+extern int length_unit_log; /* This is defined in insn-attrtab.c. */
+
/* Nonzero while outputting an `asm' with operands.
This means that inconsistencies are the user's fault, so don't abort.
The precise value is the insn being output, to pass to error_for_asm. */
static rtx this_is_asm_operands;
/* Number of operands of this insn, for an `asm' with operands. */
-static int insn_noperands;
+static unsigned int insn_noperands;
/* Compare optimization flag. */
@@ -269,17 +298,23 @@ static struct bb_str *sbb_head = 0; /* Head of string list. */
static struct bb_str **sbb_tail = &sbb_head; /* Ptr to store next bb str */
static int sbb_label_num = 0; /* Last label used */
+#ifdef HAVE_ATTR_length
static int asm_insn_count PROTO((rtx));
+#endif
static void profile_function PROTO((FILE *));
static void profile_after_prologue PROTO((FILE *));
static void add_bb PROTO((FILE *));
static int add_bb_string PROTO((char *, int));
static void output_source_line PROTO((FILE *, rtx));
static rtx walk_alter_subreg PROTO((rtx));
-static int alter_cond PROTO((rtx));
static void output_asm_name PROTO((void));
static void output_operand PROTO((rtx, int));
+#ifdef LEAF_REGISTERS
static void leaf_renumber_regs PROTO((rtx));
+#endif
+#ifdef HAVE_cc0
+static int alter_cond PROTO((rtx));
+#endif
extern char *getpwd ();
@@ -309,14 +344,21 @@ end_final (filename)
{
int i;
- if (profile_block_flag)
+ if (profile_block_flag || profile_arc_flag)
{
char name[20];
int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
- int size = (POINTER_SIZE / BITS_PER_UNIT) * count_basic_blocks;
- int rounded = size;
+ int size, rounded;
struct bb_list *ptr;
struct bb_str *sptr;
+ int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT;
+ int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT;
+
+ if (profile_block_flag)
+ size = long_bytes * count_basic_blocks;
+ else
+ size = long_bytes * count_instrumented_arcs;
+ rounded = size;
rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
@@ -324,8 +366,8 @@ end_final (filename)
data_section ();
- /* Output the main header, of 10 words:
- 0: 1 if this file's initialized, else 0.
+ /* Output the main header, of 11 words:
+ 0: 1 if this file is initialized, else 0.
1: address of file name (LPBX1).
2: address of table of counts (LPBX2).
3: number of counts in the table.
@@ -337,53 +379,73 @@ end_final (filename)
6: Number of bytes in this header.
7: address of table of function names (LPBX4).
8: address of table of line numbers (LPBX5) or 0.
- 9: address of table of file names (LPBX6) or 0. */
+ 9: address of table of file names (LPBX6) or 0.
+ 10: space reserved for basic block profiling. */
ASM_OUTPUT_ALIGN (asm_out_file, align);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
/* zero word */
- assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+ assemble_integer (const0_rtx, long_bytes, 1);
/* address of filename */
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
- assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
/* address of count table */
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
- assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
- /* count of the # of basic blocks */
- assemble_integer (GEN_INT (count_basic_blocks), UNITS_PER_WORD, 1);
+ /* count of the # of basic blocks or # of instrumented arcs */
+ if (profile_block_flag)
+ assemble_integer (GEN_INT (count_basic_blocks), long_bytes, 1);
+ else
+ assemble_integer (GEN_INT (count_instrumented_arcs), long_bytes,
+ 1);
/* zero word (link field) */
- assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+ assemble_integer (const0_rtx, pointer_bytes, 1);
/* address of basic block start address table */
- ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
- assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+ if (profile_block_flag)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
+ 1);
+ }
+ else
+ assemble_integer (const0_rtx, pointer_bytes, 1);
/* byte count for extended structure. */
- assemble_integer (GEN_INT (10 * UNITS_PER_WORD), UNITS_PER_WORD, 1);
+ assemble_integer (GEN_INT (10 * UNITS_PER_WORD), long_bytes, 1);
/* address of function name table */
- ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 4);
- assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+ if (profile_block_flag)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 4);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
+ 1);
+ }
+ else
+ assemble_integer (const0_rtx, pointer_bytes, 1);
/* address of line number and filename tables if debugging. */
- if (write_symbols != NO_DEBUG)
+ if (write_symbols != NO_DEBUG && profile_block_flag)
{
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 5);
- assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 6);
- assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes, 1);
}
else
{
- assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
- assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+ assemble_integer (const0_rtx, pointer_bytes, 1);
+ assemble_integer (const0_rtx, pointer_bytes, 1);
}
+ /* space for extension ptr (link field) */
+ assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+
/* Output the file name changing the suffix to .d for Sun tcov
compatibility. */
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
@@ -396,12 +458,15 @@ end_final (filename)
strcat (data_file, "/");
strcat (data_file, filename);
strip_off_ending (data_file, len);
- strcat (data_file, ".d");
+ if (profile_block_flag)
+ strcat (data_file, ".d");
+ else
+ strcat (data_file, ".da");
assemble_string (data_file, strlen (data_file) + 1);
}
/* Make space for the table of counts. */
- if (flag_no_common || size == 0)
+ if (size == 0)
{
/* Realign data section. */
ASM_OUTPUT_ALIGN (asm_out_file, align);
@@ -417,63 +482,79 @@ end_final (filename)
ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
else
#endif
+#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
+ ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
+ BIGGEST_ALIGNMENT);
+#else
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
BIGGEST_ALIGNMENT);
#else
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
#endif
+#endif
}
/* Output any basic block strings */
- readonly_data_section ();
- if (sbb_head)
+ if (profile_block_flag)
{
- ASM_OUTPUT_ALIGN (asm_out_file, align);
- for (sptr = sbb_head; sptr != 0; sptr = sptr->next)
+ readonly_data_section ();
+ if (sbb_head)
{
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBC", sptr->label_num);
- assemble_string (sptr->string, sptr->length);
+ ASM_OUTPUT_ALIGN (asm_out_file, align);
+ for (sptr = sbb_head; sptr != 0; sptr = sptr->next)
+ {
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBC",
+ sptr->label_num);
+ assemble_string (sptr->string, sptr->length);
+ }
}
}
/* Output the table of addresses. */
- /* Realign in new section */
- ASM_OUTPUT_ALIGN (asm_out_file, align);
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3);
- for (i = 0; i < count_basic_blocks; i++)
+ if (profile_block_flag)
{
- ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i);
- assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name),
- UNITS_PER_WORD, 1);
+ /* Realign in new section */
+ ASM_OUTPUT_ALIGN (asm_out_file, align);
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 3);
+ for (i = 0; i < count_basic_blocks; i++)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (name, "LPB", i);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
+ pointer_bytes, 1);
+ }
}
/* Output the table of function names. */
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 4);
- for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
+ if (profile_block_flag)
{
- if (ptr->func_label_num >= 0)
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 4);
+ for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
{
- ASM_GENERATE_INTERNAL_LABEL (name, "LPBC", ptr->func_label_num);
- assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name),
- UNITS_PER_WORD, 1);
+ if (ptr->func_label_num >= 0)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (name, "LPBC",
+ ptr->func_label_num);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
+ pointer_bytes, 1);
+ }
+ else
+ assemble_integer (const0_rtx, pointer_bytes, 1);
}
- else
- assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
- }
- for ( ; i < count_basic_blocks; i++)
- assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+ for ( ; i < count_basic_blocks; i++)
+ assemble_integer (const0_rtx, pointer_bytes, 1);
+ }
- if (write_symbols != NO_DEBUG)
+ if (write_symbols != NO_DEBUG && profile_block_flag)
{
/* Output the table of line numbers. */
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 5);
for ((ptr = bb_head), (i = 0); ptr != 0; (ptr = ptr->next), i++)
- assemble_integer (GEN_INT (ptr->line_num), UNITS_PER_WORD, 1);
+ assemble_integer (GEN_INT (ptr->line_num), long_bytes, 1);
for ( ; i < count_basic_blocks; i++)
- assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+ assemble_integer (const0_rtx, long_bytes, 1);
/* Output the table of file names. */
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 6);
@@ -481,22 +562,27 @@ end_final (filename)
{
if (ptr->file_label_num >= 0)
{
- ASM_GENERATE_INTERNAL_LABEL (name, "LPBC", ptr->file_label_num);
- assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name),
- UNITS_PER_WORD, 1);
+ ASM_GENERATE_INTERNAL_LABEL (name, "LPBC",
+ ptr->file_label_num);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name),
+ pointer_bytes, 1);
}
else
- assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+ assemble_integer (const0_rtx, pointer_bytes, 1);
}
for ( ; i < count_basic_blocks; i++)
- assemble_integer (const0_rtx, UNITS_PER_WORD, 1);
+ assemble_integer (const0_rtx, pointer_bytes, 1);
}
/* End with the address of the table of addresses,
so we can find it easily, as the last word in the file's text. */
- ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
- assemble_integer (gen_rtx (SYMBOL_REF, Pmode, name), UNITS_PER_WORD, 1);
+ if (profile_block_flag)
+ {
+ ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 3);
+ assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
+ 1);
+ }
}
}
@@ -508,7 +594,7 @@ app_enable ()
{
if (! app_on)
{
- fprintf (asm_out_file, ASM_APP_ON);
+ fputs (ASM_APP_ON, asm_out_file);
app_on = 1;
}
}
@@ -521,7 +607,7 @@ app_disable ()
{
if (app_on)
{
- fprintf (asm_out_file, ASM_APP_OFF);
+ fputs (ASM_APP_OFF, asm_out_file);
app_on = 0;
}
}
@@ -553,12 +639,60 @@ int *insn_addresses;
/* Address of insn being processed. Used by `insn_current_length'. */
int insn_current_address;
+/* Address of insn being processed in previous iteration. */
+int insn_last_address;
+
+/* konwn invariant alignment of insn being processed. */
+int insn_current_align;
+
+/* After shorten_branches, for any insn, uid_align[INSN_UID (insn)]
+ gives the next following alignment insn that increases the known
+ alignment, or NULL_RTX if there is no such insn.
+ For any alignment obtained this way, we can again index uid_align with
+ its uid to obtain the next following align that in turn increases the
+ alignment, till we reach NULL_RTX; the sequence obtained this way
+ for each insn we'll call the alignment chain of this insn in the following
+ comments. */
+
+struct label_alignment {
+ short alignment;
+ short max_skip;
+};
+
+static rtx *uid_align;
+static int *uid_shuid;
+static struct label_alignment *label_align;
+
/* Indicate that branch shortening hasn't yet been done. */
void
init_insn_lengths ()
{
- insn_lengths = 0;
+ if (label_align)
+ {
+ free (label_align);
+ label_align = 0;
+ }
+ if (uid_shuid)
+ {
+ free (uid_shuid);
+ uid_shuid = 0;
+ }
+ if (insn_lengths)
+ {
+ free (insn_lengths);
+ insn_lengths = 0;
+ }
+ if (insn_addresses)
+ {
+ free (insn_addresses);
+ insn_addresses = 0;
+ }
+ if (uid_align)
+ {
+ free (uid_align);
+ uid_align = 0;
+ }
}
/* Obtain the current length of an insn. If branch shortening has been done,
@@ -591,16 +725,8 @@ get_attr_length (insn)
body = PATTERN (insn);
if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
{
- /* This only takes room if jump tables go into the text section. */
-#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION)
- length = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)
- * GET_MODE_SIZE (GET_MODE (body)));
-
- /* Be pessimistic and assume worst-case alignment. */
- length += (GET_MODE_SIZE (GET_MODE (body)) - 1);
-#else
- return 0;
-#endif
+ /* Alignment is machine-dependent and should be handled by
+ ADDR_VEC_ALIGN. */
}
else
length = insn_default_length (insn);
@@ -618,6 +744,10 @@ get_attr_length (insn)
length += get_attr_length (XVECEXP (body, 0, i));
else
length = insn_default_length (insn);
+ break;
+
+ default:
+ break;
}
#ifdef ADJUST_INSN_LENGTH
@@ -629,6 +759,209 @@ get_attr_length (insn)
#endif /* not HAVE_ATTR_length */
}
+/* Code to handle alignment inside shorten_branches. */
+
+/* Here is an explanation how the algorithm in align_fuzz can give
+ proper results:
+
+ Call a sequence of instructions beginning with alignment point X
+ and continuing until the next alignment point `block X'. When `X'
+ is used in an expression, it means the alignment value of the
+ alignment point.
+
+ Call the distance between the start of the first insn of block X, and
+ the end of the last insn of block X `IX', for the `inner size of X'.
+ This is clearly the sum of the instruction lengths.
+
+ Likewise with the next alignment-delimited block following X, which we
+ shall call block Y.
+
+ Call the distance between the start of the first insn of block X, and
+ the start of the first insn of block Y `OX', for the `outer size of X'.
+
+ The estimated padding is then OX - IX.
+
+ OX can be safely estimated as
+
+ if (X >= Y)
+ OX = round_up(IX, Y)
+ else
+ OX = round_up(IX, X) + Y - X
+
+ Clearly est(IX) >= real(IX), because that only depends on the
+ instruction lengths, and those being overestimated is a given.
+
+ Clearly round_up(foo, Z) >= round_up(bar, Z) if foo >= bar, so
+ we needn't worry about that when thinking about OX.
+
+ When X >= Y, the alignment provided by Y adds no uncertainty factor
+ for branch ranges starting before X, so we can just round what we have.
+ But when X < Y, we don't know anything about the, so to speak,
+ `middle bits', so we have to assume the worst when aligning up from an
+ address mod X to one mod Y, which is Y - X. */
+
+#ifndef LABEL_ALIGN
+#define LABEL_ALIGN(LABEL) 0
+#endif
+
+#ifndef LABEL_ALIGN_MAX_SKIP
+#define LABEL_ALIGN_MAX_SKIP 0
+#endif
+
+#ifndef LOOP_ALIGN
+#define LOOP_ALIGN(LABEL) 0
+#endif
+
+#ifndef LOOP_ALIGN_MAX_SKIP
+#define LOOP_ALIGN_MAX_SKIP 0
+#endif
+
+#ifndef LABEL_ALIGN_AFTER_BARRIER
+#define LABEL_ALIGN_AFTER_BARRIER(LABEL) 0
+#endif
+
+#ifndef LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP
+#define LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP 0
+#endif
+
+#ifndef ADDR_VEC_ALIGN
+int
+final_addr_vec_align (addr_vec)
+ rtx addr_vec;
+{
+ int align = exact_log2 (GET_MODE_SIZE (GET_MODE (PATTERN (addr_vec))));
+
+ if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
+ align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+ return align;
+
+}
+#define ADDR_VEC_ALIGN(ADDR_VEC) final_addr_vec_align (ADDR_VEC)
+#endif
+
+#ifndef INSN_LENGTH_ALIGNMENT
+#define INSN_LENGTH_ALIGNMENT(INSN) length_unit_log
+#endif
+
+#define INSN_SHUID(INSN) (uid_shuid[INSN_UID (INSN)])
+
+static int min_labelno, max_labelno;
+
+#define LABEL_TO_ALIGNMENT(LABEL) \
+ (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].alignment)
+
+#define LABEL_TO_MAX_SKIP(LABEL) \
+ (label_align[CODE_LABEL_NUMBER (LABEL) - min_labelno].max_skip)
+
+/* For the benefit of port specific code do this also as a function. */
+int
+label_to_alignment (label)
+ rtx label;
+{
+ return LABEL_TO_ALIGNMENT (label);
+}
+
+#ifdef HAVE_ATTR_length
+/* The differences in addresses
+ between a branch and its target might grow or shrink depending on
+ the alignment the start insn of the range (the branch for a forward
+ branch or the label for a backward branch) starts out on; if these
+ differences are used naively, they can even oscillate infinitely.
+ We therefore want to compute a 'worst case' address difference that
+ is independent of the alignment the start insn of the range end
+ up on, and that is at least as large as the actual difference.
+ The function align_fuzz calculates the amount we have to add to the
+ naively computed difference, by traversing the part of the alignment
+ chain of the start insn of the range that is in front of the end insn
+ of the range, and considering for each alignment the maximum amount
+ that it might contribute to a size increase.
+
+ For casesi tables, we also want to know worst case minimum amounts of
+ address difference, in case a machine description wants to introduce
+ some common offset that is added to all offsets in a table.
+ For this purpose, align_fuzz with a growth argument of 0 comuptes the
+ appropriate adjustment. */
+
+
+/* Compute the maximum delta by which the difference of the addresses of
+ START and END might grow / shrink due to a different address for start
+ which changes the size of alignment insns between START and END.
+ KNOWN_ALIGN_LOG is the alignment known for START.
+ GROWTH should be ~0 if the objective is to compute potential code size
+ increase, and 0 if the objective is to compute potential shrink.
+ The return value is undefined for any other value of GROWTH. */
+int
+align_fuzz (start, end, known_align_log, growth)
+ rtx start, end;
+ int known_align_log;
+ unsigned growth;
+{
+ int uid = INSN_UID (start);
+ rtx align_label;
+ int known_align = 1 << known_align_log;
+ int end_shuid = INSN_SHUID (end);
+ int fuzz = 0;
+
+ for (align_label = uid_align[uid]; align_label; align_label = uid_align[uid])
+ {
+ int align_addr, new_align;
+
+ uid = INSN_UID (align_label);
+ align_addr = insn_addresses[uid] - insn_lengths[uid];
+ if (uid_shuid[uid] > end_shuid)
+ break;
+ known_align_log = LABEL_TO_ALIGNMENT (align_label);
+ new_align = 1 << known_align_log;
+ if (new_align < known_align)
+ continue;
+ fuzz += (-align_addr ^ growth) & (new_align - known_align);
+ known_align = new_align;
+ }
+ return fuzz;
+}
+
+/* Compute a worst-case reference address of a branch so that it
+ can be safely used in the presence of aligned labels. Since the
+ size of the branch itself is unknown, the size of the branch is
+ not included in the range. I.e. for a forward branch, the reference
+ address is the end address of the branch as known from the previous
+ branch shortening pass, minus a value to account for possible size
+ increase due to alignment. For a backward branch, it is the start
+ address of the branch as known from the current pass, plus a value
+ to account for possible size increase due to alignment.
+ NB.: Therefore, the maximum offset allowed for backward branches needs
+ to exclude the branch size. */
+int
+insn_current_reference_address (branch)
+ rtx branch;
+{
+ rtx dest;
+ rtx seq = NEXT_INSN (PREV_INSN (branch));
+ int seq_uid = INSN_UID (seq);
+ if (GET_CODE (branch) != JUMP_INSN)
+ /* This can happen for example on the PA; the objective is to know the
+ offset to address something in front of the start of the function.
+ Thus, we can treat it like a backward branch.
+ We assume here that FUNCTION_BOUNDARY / BITS_PER_UNIT is larger than
+ any alignment we'd encounter, so we skip the call to align_fuzz. */
+ return insn_current_address;
+ dest = JUMP_LABEL (branch);
+ /* BRANCH has no proper alignment chain set, so use SEQ. */
+ if (INSN_SHUID (branch) < INSN_SHUID (dest))
+ {
+ /* Forward branch. */
+ return (insn_last_address + insn_lengths[seq_uid]
+ - align_fuzz (seq, dest, length_unit_log, ~0));
+ }
+ else
+ {
+ /* Backward branch. */
+ return (insn_current_address
+ + align_fuzz (dest, seq, length_unit_log, ~0));
+ }
+}
+#endif /* HAVE_ATTR_length */
+
/* Make a pass over all insns and compute their actual lengths by shortening
any branches of variable length if possible. */
@@ -638,27 +971,263 @@ get_attr_length (insn)
#define FIRST_INSN_ADDRESS 0
#endif
+/* shorten_branches might be called multiple times: for example, the SH
+ port splits out-of-range conditional branches in MACHINE_DEPENDENT_REORG.
+ In order to do this, it needs proper length information, which it obtains
+ by calling shorten_branches. This cannot be collapsed with
+ shorten_branches itself into a single pass unless we also want to intergate
+ reorg.c, since the branch splitting exposes new instructions with delay
+ slots. */
+
void
shorten_branches (first)
rtx first;
{
-#ifdef HAVE_ATTR_length
rtx insn;
+ int max_uid;
+ int i;
+ int max_log;
+ int max_skip;
+#ifdef HAVE_ATTR_length
+#define MAX_CODE_ALIGN 16
+ rtx seq;
int something_changed = 1;
- int max_uid = 0;
char *varying_length;
rtx body;
int uid;
+ rtx align_tab[MAX_CODE_ALIGN];
- /* Compute maximum UID and allocate arrays. */
- for (insn = first; insn; insn = NEXT_INSN (insn))
- if (INSN_UID (insn) > max_uid)
- max_uid = INSN_UID (insn);
+ /* In order to make sure that all instructions have valid length info,
+ we must split them before we compute the address/length info. */
+
+ for (insn = NEXT_INSN (first); insn; insn = NEXT_INSN (insn))
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ rtx old = insn;
+ insn = try_split (PATTERN (old), old, 1);
+ /* When not optimizing, the old insn will be still left around
+ with only the 'deleted' bit set. Transform it into a note
+ to avoid confusion of subsequent processing. */
+ if (INSN_DELETED_P (old))
+ {
+ PUT_CODE (old , NOTE);
+ NOTE_LINE_NUMBER (old) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (old) = 0;
+ }
+ }
+#endif
+
+ /* We must do some computations even when not actually shortening, in
+ order to get the alignment information for the labels. */
+
+ init_insn_lengths ();
+
+ /* Compute maximum UID and allocate label_align / uid_shuid. */
+ max_uid = get_max_uid ();
+
+ max_labelno = max_label_num ();
+ min_labelno = get_first_label_num ();
+ label_align = (struct label_alignment *) xmalloc (
+ (max_labelno - min_labelno + 1) * sizeof (struct label_alignment));
+ bzero ((char *) label_align,
+ (max_labelno - min_labelno + 1) * sizeof (struct label_alignment));
+
+ uid_shuid = (int *) xmalloc (max_uid * sizeof *uid_shuid);
+
+ /* Initialize label_align and set up uid_shuid to be strictly
+ monotonically rising with insn order. */
+ /* We use max_log here to keep track of the maximum alignment we want to
+ impose on the next CODE_LABEL (or the current one if we are processing
+ the CODE_LABEL itself). */
+
+ max_log = 0;
+ max_skip = 0;
+
+ for (insn = get_insns (), i = 1; insn; insn = NEXT_INSN (insn))
+ {
+ int log;
+
+ INSN_SHUID (insn) = i++;
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ /* reorg might make the first insn of a loop being run once only,
+ and delete the label in front of it. Then we want to apply
+ the loop alignment to the new label created by reorg, which
+ is separated by the former loop start insn from the
+ NOTE_INSN_LOOP_BEG. */
+ }
+ else if (GET_CODE (insn) == CODE_LABEL)
+ {
+ rtx next;
+
+ log = LABEL_ALIGN (insn);
+ if (max_log < log)
+ {
+ max_log = log;
+ max_skip = LABEL_ALIGN_MAX_SKIP;
+ }
+ next = NEXT_INSN (insn);
+ /* ADDR_VECs only take room if read-only data goes into the text
+ section. */
+ if (JUMP_TABLES_IN_TEXT_SECTION
+#if !defined(READONLY_DATA_SECTION)
+ || 1
+#endif
+ )
+ if (next && GET_CODE (next) == JUMP_INSN)
+ {
+ rtx nextbody = PATTERN (next);
+ if (GET_CODE (nextbody) == ADDR_VEC
+ || GET_CODE (nextbody) == ADDR_DIFF_VEC)
+ {
+ log = ADDR_VEC_ALIGN (next);
+ if (max_log < log)
+ {
+ max_log = log;
+ max_skip = LABEL_ALIGN_MAX_SKIP;
+ }
+ }
+ }
+ LABEL_TO_ALIGNMENT (insn) = max_log;
+ LABEL_TO_MAX_SKIP (insn) = max_skip;
+ max_log = 0;
+ max_skip = 0;
+ }
+ else if (GET_CODE (insn) == BARRIER)
+ {
+ rtx label;
+
+ for (label = insn; label && GET_RTX_CLASS (GET_CODE (label)) != 'i';
+ label = NEXT_INSN (label))
+ if (GET_CODE (label) == CODE_LABEL)
+ {
+ log = LABEL_ALIGN_AFTER_BARRIER (insn);
+ if (max_log < log)
+ {
+ max_log = log;
+ max_skip = LABEL_ALIGN_AFTER_BARRIER_MAX_SKIP;
+ }
+ break;
+ }
+ }
+ /* Again, we allow NOTE_INSN_LOOP_BEG - INSN - CODE_LABEL
+ sequences in order to handle reorg output efficiently. */
+ else if (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+ {
+ rtx label;
+
+ for (label = insn; label; label = NEXT_INSN (label))
+ if (GET_CODE (label) == CODE_LABEL)
+ {
+ log = LOOP_ALIGN (insn);
+ if (max_log < log)
+ {
+ max_log = log;
+ max_skip = LOOP_ALIGN_MAX_SKIP;
+ }
+ break;
+ }
+ }
+ else
+ continue;
+ }
+#ifdef HAVE_ATTR_length
+
+ /* Allocate the rest of the arrays. */
+ insn_lengths = (short *) xmalloc (max_uid * sizeof (short));
+ insn_addresses = (int *) xmalloc (max_uid * sizeof (int));
+ /* Syntax errors can lead to labels being outside of the main insn stream.
+ Initialize insn_addresses, so that we get reproducible results. */
+ bzero ((char *)insn_addresses, max_uid * sizeof *insn_addresses);
+ uid_align = (rtx *) xmalloc (max_uid * sizeof *uid_align);
+
+ varying_length = (char *) xmalloc (max_uid * sizeof (char));
+
+ bzero (varying_length, max_uid);
+
+ /* Initialize uid_align. We scan instructions
+ from end to start, and keep in align_tab[n] the last seen insn
+ that does an alignment of at least n+1, i.e. the successor
+ in the alignment chain for an insn that does / has a known
+ alignment of n. */
+
+ bzero ((char *) uid_align, max_uid * sizeof *uid_align);
+
+ for (i = MAX_CODE_ALIGN; --i >= 0; )
+ align_tab[i] = NULL_RTX;
+ seq = get_last_insn ();
+ for (; seq; seq = PREV_INSN (seq))
+ {
+ int uid = INSN_UID (seq);
+ int log;
+ log = (GET_CODE (seq) == CODE_LABEL ? LABEL_TO_ALIGNMENT (seq) : 0);
+ uid_align[uid] = align_tab[0];
+ if (log)
+ {
+ /* Found an alignment label. */
+ uid_align[uid] = align_tab[log];
+ for (i = log - 1; i >= 0; i--)
+ align_tab[i] = seq;
+ }
+ }
+#ifdef CASE_VECTOR_SHORTEN_MODE
+ if (optimize)
+ {
+ /* Look for ADDR_DIFF_VECs, and initialize their minimum and maximum
+ label fields. */
+
+ int min_shuid = INSN_SHUID (get_insns ()) - 1;
+ int max_shuid = INSN_SHUID (get_last_insn ()) + 1;
+ int rel;
+
+ for (insn = first; insn != 0; insn = NEXT_INSN (insn))
+ {
+ rtx min_lab = NULL_RTX, max_lab = NULL_RTX, pat;
+ int len, i, min, max, insn_shuid;
+ int min_align;
+ addr_diff_vec_flags flags;
+
+ if (GET_CODE (insn) != JUMP_INSN
+ || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
+ continue;
+ pat = PATTERN (insn);
+ len = XVECLEN (pat, 1);
+ if (len <= 0)
+ abort ();
+ min_align = MAX_CODE_ALIGN;
+ for (min = max_shuid, max = min_shuid, i = len - 1; i >= 0; i--)
+ {
+ rtx lab = XEXP (XVECEXP (pat, 1, i), 0);
+ int shuid = INSN_SHUID (lab);
+ if (shuid < min)
+ {
+ min = shuid;
+ min_lab = lab;
+ }
+ if (shuid > max)
+ {
+ max = shuid;
+ max_lab = lab;
+ }
+ if (min_align > LABEL_TO_ALIGNMENT (lab))
+ min_align = LABEL_TO_ALIGNMENT (lab);
+ }
+ XEXP (pat, 2) = gen_rtx_LABEL_REF (VOIDmode, min_lab);
+ XEXP (pat, 3) = gen_rtx_LABEL_REF (VOIDmode, max_lab);
+ insn_shuid = INSN_SHUID (insn);
+ rel = INSN_SHUID (XEXP (XEXP (pat, 0), 0));
+ flags.min_align = min_align;
+ flags.base_after_vec = rel > insn_shuid;
+ flags.min_after_vec = min > insn_shuid;
+ flags.max_after_vec = max > insn_shuid;
+ flags.min_after_base = min > rel;
+ flags.max_after_base = max > rel;
+ ADDR_DIFF_VEC_FLAGS (pat) = flags;
+ }
+ }
+#endif /* CASE_VECTOR_SHORTEN_MODE */
- max_uid++;
- insn_lengths = (short *) oballoc (max_uid * sizeof (short));
- insn_addresses = (int *) oballoc (max_uid * sizeof (int));
- varying_length = (char *) oballoc (max_uid * sizeof (char));
/* Compute initial lengths, addresses, and varying flags for each insn. */
for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
@@ -666,31 +1235,43 @@ shorten_branches (first)
insn_current_address += insn_lengths[uid], insn = NEXT_INSN (insn))
{
uid = INSN_UID (insn);
- insn_addresses[uid] = insn_current_address;
+
insn_lengths[uid] = 0;
- varying_length[uid] = 0;
+
+ if (GET_CODE (insn) == CODE_LABEL)
+ {
+ int log = LABEL_TO_ALIGNMENT (insn);
+ if (log)
+ {
+ int align = 1 << log;
+ int new_address = (insn_current_address + align - 1) & -align;
+ insn_lengths[uid] = new_address - insn_current_address;
+ insn_current_address = new_address;
+ }
+ }
+
+ insn_addresses[uid] = insn_current_address;
if (GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER
|| GET_CODE (insn) == CODE_LABEL)
continue;
+ if (INSN_DELETED_P (insn))
+ continue;
body = PATTERN (insn);
if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
{
/* This only takes room if read-only data goes into the text
section. */
-#if !defined(READONLY_DATA_SECTION) || defined(JUMP_TABLES_IN_TEXT_SECTION)
- int unitsize = GET_MODE_SIZE (GET_MODE (body));
-
- insn_lengths[uid] = (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)
- * GET_MODE_SIZE (GET_MODE (body)));
-
- /* Account for possible alignment. */
- insn_lengths[uid]
- += unitsize - (insn_current_address & (unitsize - 1));
-#else
- ;
+ if (JUMP_TABLES_IN_TEXT_SECTION
+#if !defined(READONLY_DATA_SECTION)
+ || 1
#endif
+ )
+ insn_lengths[uid] = (XVECLEN (body,
+ GET_CODE (body) == ADDR_DIFF_VEC)
+ * GET_MODE_SIZE (GET_MODE (body)));
+ /* Alignment is handled by ADDR_VEC_ALIGN. */
}
else if (asm_noperands (body) >= 0)
insn_lengths[uid] = asm_insn_count (body) * insn_default_length (insn);
@@ -705,7 +1286,7 @@ shorten_branches (first)
#endif
/* Inside a delay slot sequence, we do not do any branch shortening
if the shortening could change the number of delay slots
- of the branch. */
+ of the branch. */
for (i = 0; i < XVECLEN (body, 0); i++)
{
rtx inner_insn = XVECEXP (body, 0, i);
@@ -751,16 +1332,154 @@ shorten_branches (first)
while (something_changed)
{
something_changed = 0;
+ insn_current_align = MAX_CODE_ALIGN - 1;
for (insn_current_address = FIRST_INSN_ADDRESS, insn = first;
insn != 0;
insn = NEXT_INSN (insn))
{
int new_length;
+#ifdef ADJUST_INSN_LENGTH
int tmp_length;
+#endif
+ int length_align;
uid = INSN_UID (insn);
+
+ if (GET_CODE (insn) == CODE_LABEL)
+ {
+ int log = LABEL_TO_ALIGNMENT (insn);
+ if (log > insn_current_align)
+ {
+ int align = 1 << log;
+ int new_address= (insn_current_address + align - 1) & -align;
+ insn_lengths[uid] = new_address - insn_current_address;
+ insn_current_align = log;
+ insn_current_address = new_address;
+ }
+ else
+ insn_lengths[uid] = 0;
+ insn_addresses[uid] = insn_current_address;
+ continue;
+ }
+
+ length_align = INSN_LENGTH_ALIGNMENT (insn);
+ if (length_align < insn_current_align)
+ insn_current_align = length_align;
+
+ insn_last_address = insn_addresses[uid];
insn_addresses[uid] = insn_current_address;
- if (! varying_length[uid])
+
+#ifdef CASE_VECTOR_SHORTEN_MODE
+ if (optimize && GET_CODE (insn) == JUMP_INSN
+ && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
+ {
+ rtx body = PATTERN (insn);
+ int old_length = insn_lengths[uid];
+ rtx rel_lab = XEXP (XEXP (body, 0), 0);
+ rtx min_lab = XEXP (XEXP (body, 2), 0);
+ rtx max_lab = XEXP (XEXP (body, 3), 0);
+ addr_diff_vec_flags flags = ADDR_DIFF_VEC_FLAGS (body);
+ int rel_addr = insn_addresses[INSN_UID (rel_lab)];
+ int min_addr = insn_addresses[INSN_UID (min_lab)];
+ int max_addr = insn_addresses[INSN_UID (max_lab)];
+ rtx prev;
+ int rel_align = 0;
+
+ /* Try to find a known alignment for rel_lab. */
+ for (prev = rel_lab;
+ prev
+ && ! insn_lengths[INSN_UID (prev)]
+ && ! (varying_length[INSN_UID (prev)] & 1);
+ prev = PREV_INSN (prev))
+ if (varying_length[INSN_UID (prev)] & 2)
+ {
+ rel_align = LABEL_TO_ALIGNMENT (prev);
+ break;
+ }
+
+ /* See the comment on addr_diff_vec_flags in rtl.h for the
+ meaning of the flags values. base: REL_LAB vec: INSN */
+ /* Anything after INSN has still addresses from the last
+ pass; adjust these so that they reflect our current
+ estimate for this pass. */
+ if (flags.base_after_vec)
+ rel_addr += insn_current_address - insn_last_address;
+ if (flags.min_after_vec)
+ min_addr += insn_current_address - insn_last_address;
+ if (flags.max_after_vec)
+ max_addr += insn_current_address - insn_last_address;
+ /* We want to know the worst case, i.e. lowest possible value
+ for the offset of MIN_LAB. If MIN_LAB is after REL_LAB,
+ its offset is positive, and we have to be wary of code shrink;
+ otherwise, it is negative, and we have to be vary of code
+ size increase. */
+ if (flags.min_after_base)
+ {
+ /* If INSN is between REL_LAB and MIN_LAB, the size
+ changes we are about to make can change the alignment
+ within the observed offset, therefore we have to break
+ it up into two parts that are independent. */
+ if (! flags.base_after_vec && flags.min_after_vec)
+ {
+ min_addr -= align_fuzz (rel_lab, insn, rel_align, 0);
+ min_addr -= align_fuzz (insn, min_lab, 0, 0);
+ }
+ else
+ min_addr -= align_fuzz (rel_lab, min_lab, rel_align, 0);
+ }
+ else
+ {
+ if (flags.base_after_vec && ! flags.min_after_vec)
+ {
+ min_addr -= align_fuzz (min_lab, insn, 0, ~0);
+ min_addr -= align_fuzz (insn, rel_lab, 0, ~0);
+ }
+ else
+ min_addr -= align_fuzz (min_lab, rel_lab, 0, ~0);
+ }
+ /* Likewise, determine the highest lowest possible value
+ for the offset of MAX_LAB. */
+ if (flags.max_after_base)
+ {
+ if (! flags.base_after_vec && flags.max_after_vec)
+ {
+ max_addr += align_fuzz (rel_lab, insn, rel_align, ~0);
+ max_addr += align_fuzz (insn, max_lab, 0, ~0);
+ }
+ else
+ max_addr += align_fuzz (rel_lab, max_lab, rel_align, ~0);
+ }
+ else
+ {
+ if (flags.base_after_vec && ! flags.max_after_vec)
+ {
+ max_addr += align_fuzz (max_lab, insn, 0, 0);
+ max_addr += align_fuzz (insn, rel_lab, 0, 0);
+ }
+ else
+ max_addr += align_fuzz (max_lab, rel_lab, 0, 0);
+ }
+ PUT_MODE (body, CASE_VECTOR_SHORTEN_MODE (min_addr - rel_addr,
+ max_addr - rel_addr,
+ body));
+ if (JUMP_TABLES_IN_TEXT_SECTION
+#if !defined(READONLY_DATA_SECTION)
+ || 1
+#endif
+ )
+ {
+ insn_lengths[uid]
+ = (XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body)));
+ insn_current_address += insn_lengths[uid];
+ if (insn_lengths[uid] != old_length)
+ something_changed = 1;
+ }
+
+ continue;
+ }
+#endif /* CASE_VECTOR_SHORTEN_MODE */
+
+ if (! (varying_length[uid]))
{
insn_current_address += insn_lengths[uid];
continue;
@@ -801,14 +1520,12 @@ shorten_branches (first)
insn_current_address += new_length;
}
-#ifdef SHORTEN_WITH_ADJUST_INSN_LENGTH
#ifdef ADJUST_INSN_LENGTH
/* If needed, do any adjustment. */
tmp_length = new_length;
ADJUST_INSN_LENGTH (insn, new_length);
insn_current_address += (new_length - tmp_length);
#endif
-#endif
if (new_length != insn_lengths[uid])
{
@@ -820,6 +1537,9 @@ shorten_branches (first)
if (!optimize)
break;
}
+
+ free (varying_length);
+
#endif /* HAVE_ATTR_length */
}
@@ -890,10 +1610,16 @@ final_start_function (first, file, optimize)
last_linenum = high_block_linenum = high_function_linenum
= NOTE_LINE_NUMBER (first);
+#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
+ /* Output DWARF definition of the function. */
+ if (dwarf2out_do_frame ())
+ dwarf2out_begin_prologue ();
+#endif
+
/* For SDB and XCOFF, the function beginning must be marked between
the function label and the prologue. We always need this, even when
-g1 was used. Defer on MIPS systems so that parameter descriptions
- follow function entry. */
+ follow function entry. */
#if defined(SDB_DEBUGGING_INFO) && !defined(MIPS_DEBUGGING_INFO)
if (write_symbols == SDB_DEBUG)
sdbout_begin_function (last_linenum);
@@ -921,6 +1647,11 @@ final_start_function (first, file, optimize)
profile_function (file);
#endif /* PROFILE_BEFORE_PROLOGUE */
+#if defined (DWARF2_UNWIND_INFO) && defined (HAVE_prologue)
+ if (dwarf2out_do_frame ())
+ dwarf2out_frame_debug (NULL_RTX);
+#endif
+
#ifdef FUNCTION_PROLOGUE
/* First output the function prologue: code to set up the stack frame. */
FUNCTION_PROLOGUE (file, get_frame_size ());
@@ -944,9 +1675,8 @@ final_start_function (first, file, optimize)
of the function name. */
if (profile_block_flag)
{
- char *junk = "function";
- bb_func_label_num =
- add_bb_string ((*decl_printable_name) (current_function_decl, &junk), FALSE);
+ bb_func_label_num
+ = add_bb_string ((*decl_printable_name) (current_function_decl, 2), FALSE);
}
}
@@ -957,7 +1687,7 @@ profile_after_prologue (file)
#ifdef FUNCTION_BLOCK_PROFILER
if (profile_block_flag)
{
- FUNCTION_BLOCK_PROFILER (file, profile_label_no);
+ FUNCTION_BLOCK_PROFILER (file, count_basic_blocks);
}
#endif /* FUNCTION_BLOCK_PROFILER */
@@ -971,60 +1701,70 @@ static void
profile_function (file)
FILE *file;
{
- int align = MIN (BIGGEST_ALIGNMENT, POINTER_SIZE);
+ int align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
+#if defined(ASM_OUTPUT_REG_PUSH)
+#if defined(STRUCT_VALUE_INCOMING_REGNUM) || defined(STRUCT_VALUE_REGNUM)
int sval = current_function_returns_struct;
+#endif
+#if defined(STATIC_CHAIN_INCOMING_REGNUM) || defined(STATIC_CHAIN_REGNUM)
int cxt = current_function_needs_context;
+#endif
+#endif /* ASM_OUTPUT_REG_PUSH */
data_section ();
ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
ASM_OUTPUT_INTERNAL_LABEL (file, "LP", profile_label_no);
- assemble_integer (const0_rtx, POINTER_SIZE / BITS_PER_UNIT, 1);
+ assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, 1);
- text_section ();
+ function_section (current_function_decl);
-#ifdef STRUCT_VALUE_INCOMING_REGNUM
+#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (sval)
ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_INCOMING_REGNUM);
#else
-#ifdef STRUCT_VALUE_REGNUM
+#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (sval)
- ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);
+ {
+ ASM_OUTPUT_REG_PUSH (file, STRUCT_VALUE_REGNUM);
+ }
#endif
#endif
-#if 0
-#ifdef STATIC_CHAIN_INCOMING_REGNUM
+#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (cxt)
ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_INCOMING_REGNUM);
#else
-#ifdef STATIC_CHAIN_REGNUM
+#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (cxt)
- ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
+ {
+ ASM_OUTPUT_REG_PUSH (file, STATIC_CHAIN_REGNUM);
+ }
#endif
#endif
-#endif /* 0 */
FUNCTION_PROFILER (file, profile_label_no);
-#if 0
-#ifdef STATIC_CHAIN_INCOMING_REGNUM
+#if defined(STATIC_CHAIN_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (cxt)
ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_INCOMING_REGNUM);
#else
-#ifdef STATIC_CHAIN_REGNUM
+#if defined(STATIC_CHAIN_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (cxt)
- ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
+ {
+ ASM_OUTPUT_REG_POP (file, STATIC_CHAIN_REGNUM);
+ }
#endif
#endif
-#endif /* 0 */
-#ifdef STRUCT_VALUE_INCOMING_REGNUM
+#if defined(STRUCT_VALUE_INCOMING_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (sval)
ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_INCOMING_REGNUM);
#else
-#ifdef STRUCT_VALUE_REGNUM
+#if defined(STRUCT_VALUE_REGNUM) && defined(ASM_OUTPUT_REG_PUSH)
if (sval)
- ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);
+ {
+ ASM_OUTPUT_REG_POP (file, STRUCT_VALUE_REGNUM);
+ }
#endif
#endif
}
@@ -1041,7 +1781,7 @@ final_end_function (first, file, optimize)
{
if (app_on)
{
- fprintf (file, ASM_APP_OFF);
+ fputs (ASM_APP_OFF, file);
app_on = 0;
}
@@ -1076,6 +1816,11 @@ final_end_function (first, file, optimize)
dwarfout_end_epilogue ();
#endif
+#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
+ if (dwarf2out_do_frame ())
+ dwarf2out_end_epilogue ();
+#endif
+
#ifdef XCOFF_DEBUGGING_INFO
if (write_symbols == XCOFF_DEBUG)
xcoffout_end_epilogue (file);
@@ -1113,6 +1858,8 @@ add_bb (file)
count of times it was entered. */
#ifdef BLOCK_PROFILER
BLOCK_PROFILER (file, count_basic_blocks);
+#endif
+#ifdef HAVE_cc0
CC_STATUS_INIT;
#endif
@@ -1148,7 +1895,7 @@ add_bb_string (string, perm_p)
string = p;
}
else
- for (ptr = sbb_head; ptr != (struct bb_str *)0; ptr = ptr->next)
+ for (ptr = sbb_head; ptr != (struct bb_str *) 0; ptr = ptr->next)
if (ptr->string == string)
break;
@@ -1188,10 +1935,13 @@ final (first, file, optimize, prescan)
{
register rtx insn;
int max_line = 0;
+ int max_uid = 0;
last_ignored_compare = 0;
new_block = 1;
+ check_exception_handler_labels ();
+
/* Make a map indicating which line numbers appear in this function.
When producing SDB debugging info, delete troublesome line number
notes from inlined functions in other files as well as duplicate
@@ -1230,8 +1980,16 @@ final (first, file, optimize, prescan)
bzero (line_note_exists, max_line + 1);
for (insn = first; insn; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
- line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
+ {
+ if (INSN_UID (insn) > max_uid) /* find largest UID */
+ max_uid = INSN_UID (insn);
+ if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ line_note_exists[NOTE_LINE_NUMBER (insn)] = 1;
+ }
+
+ /* Initialize insn_eh_region table if eh is being used. */
+
+ init_insn_eh_region (first, max_uid);
init_recog ();
@@ -1239,12 +1997,19 @@ final (first, file, optimize, prescan)
/* Output the insns. */
for (insn = NEXT_INSN (first); insn;)
- insn = final_scan_insn (insn, file, optimize, prescan, 0);
+ {
+#ifdef HAVE_ATTR_length
+ insn_current_address = insn_addresses[INSN_UID (insn)];
+#endif
+ insn = final_scan_insn (insn, file, optimize, prescan, 0);
+ }
/* Do basic-block profiling here
if the last insn was a conditional branch. */
if (profile_block_flag && new_block)
add_bb (file);
+
+ free_insn_eh_region ();
}
/* The final scan for one insn, INSN.
@@ -1264,6 +2029,10 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
int nopeepholes;
{
register int i;
+#ifdef HAVE_cc0
+ rtx set;
+#endif
+
insn_counter++;
/* Ignore deleted insns. These can occur when we split insns (due to a
@@ -1280,19 +2049,34 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
/* Align the beginning of a loop, for higher speed
on certain machines. */
- if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG && optimize > 0)
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+ break; /* This used to depend on optimize, but that was bogus. */
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+ break;
+
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
+ && ! exceptions_via_longjmp)
{
-#ifdef ASM_OUTPUT_LOOP_ALIGN
- rtx next = next_nonnote_insn (insn);
- if (next && GET_CODE (next) == CODE_LABEL)
- {
- ASM_OUTPUT_LOOP_ALIGN (asm_out_file);
- }
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LEHB", NOTE_BLOCK_NUMBER (insn));
+ if (! flag_new_exceptions)
+ add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
+#ifdef ASM_OUTPUT_EH_REGION_BEG
+ ASM_OUTPUT_EH_REGION_BEG (file, NOTE_BLOCK_NUMBER (insn));
+#endif
+ break;
+ }
+
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
+ && ! exceptions_via_longjmp)
+ {
+ ASM_OUTPUT_INTERNAL_LABEL (file, "LEHE", NOTE_BLOCK_NUMBER (insn));
+ if (flag_new_exceptions)
+ add_eh_table_entry (NOTE_BLOCK_NUMBER (insn));
+#ifdef ASM_OUTPUT_EH_REGION_END
+ ASM_OUTPUT_EH_REGION_END (file, NOTE_BLOCK_NUMBER (insn));
#endif
break;
}
- if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
- break;
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_PROLOGUE_END)
{
@@ -1317,7 +2101,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
{
#if defined(SDB_DEBUGGING_INFO) && defined(MIPS_DEBUGGING_INFO)
/* MIPS stabs require the parameter descriptions to be after the
- function entry point rather than before. */
+ function entry point rather than before. */
if (write_symbols == SDB_DEBUG)
sdbout_begin_function (last_linenum);
else
@@ -1334,17 +2118,14 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
break; /* An insn that was "deleted" */
if (app_on)
{
- fprintf (file, ASM_APP_OFF);
+ fputs (ASM_APP_OFF, file);
app_on = 0;
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
&& (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
-#ifdef DWARF_DEBUGGING_INFO
|| write_symbols == DWARF_DEBUG
-#endif
- )
- )
+ || write_symbols == DWARF2_DEBUG))
{
/* Beginning of a symbol-block. Assign it a sequence number
and push the number onto the stack PENDING_BLOCKS. */
@@ -1376,20 +2157,21 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
ASM_OUTPUT_INTERNAL_LABEL (file, "LBB", next_block_index);
#endif
#ifdef DWARF_DEBUGGING_INFO
- if (write_symbols == DWARF_DEBUG && block_depth > 1)
+ if (write_symbols == DWARF_DEBUG)
dwarfout_begin_block (next_block_index);
#endif
+#ifdef DWARF2_DEBUGGING_INFO
+ if (write_symbols == DWARF2_DEBUG)
+ dwarf2out_begin_block (next_block_index);
+#endif
next_block_index++;
}
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
&& (debug_info_level == DINFO_LEVEL_NORMAL
|| debug_info_level == DINFO_LEVEL_VERBOSE
-#ifdef DWARF_DEBUGGING_INFO
|| write_symbols == DWARF_DEBUG
-#endif
- )
- )
+ || write_symbols == DWARF2_DEBUG))
{
/* End of a symbol-block. Pop its sequence number off
PENDING_BLOCKS and output debugging info based on that. */
@@ -1412,9 +2194,13 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
pending_blocks[block_depth]);
#endif
#ifdef DWARF_DEBUGGING_INFO
- if (write_symbols == DWARF_DEBUG && block_depth >= 1)
+ if (write_symbols == DWARF_DEBUG && block_depth >= 0)
dwarfout_end_block (pending_blocks[block_depth]);
#endif
+#ifdef DWARF2_DEBUGGING_INFO
+ if (write_symbols == DWARF2_DEBUG && block_depth >= 0)
+ dwarf2out_end_block (pending_blocks[block_depth]);
+#endif
}
else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL
&& (debug_info_level == DINFO_LEVEL_NORMAL
@@ -1424,6 +2210,10 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
if (write_symbols == DWARF_DEBUG)
dwarfout_label (insn);
#endif
+#ifdef DWARF2_DEBUGGING_INFO
+ if (write_symbols == DWARF2_DEBUG)
+ dwarf2out_label (insn);
+#endif
}
else if (NOTE_LINE_NUMBER (insn) > 0)
/* This note is a line-number. */
@@ -1473,20 +2263,40 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
break;
case BARRIER:
-#ifdef ASM_OUTPUT_ALIGN_CODE
- /* Don't litter the assembler output with needless alignments. A
- BARRIER will be placed at the end of every function if HAVE_epilogue
- is true. */
- if (NEXT_INSN (insn))
- ASM_OUTPUT_ALIGN_CODE (file);
+#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS)
+ /* If we push arguments, we need to check all insns for stack
+ adjustments. */
+ if (dwarf2out_do_frame ())
+ dwarf2out_frame_debug (insn);
#endif
break;
case CODE_LABEL:
+ /* The target port might emit labels in the output function for
+ some insn, e.g. sh.c output_branchy_insn. */
+ if (CODE_LABEL_NUMBER (insn) <= max_labelno)
+ {
+ int align = LABEL_TO_ALIGNMENT (insn);
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
+ int max_skip = LABEL_TO_MAX_SKIP (insn);
+#endif
+
+ if (align && NEXT_INSN (insn))
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
+ ASM_OUTPUT_MAX_SKIP_ALIGN (file, align, max_skip);
+#else
+ ASM_OUTPUT_ALIGN (file, align);
+#endif
+ }
CC_STATUS_INIT;
if (prescan > 0)
break;
new_block = 1;
+
+#ifdef FINAL_PRESCAN_LABEL
+ FINAL_PRESCAN_INSN (insn, NULL_PTR, 0);
+#endif
+
#ifdef SDB_DEBUGGING_INFO
if (write_symbols == SDB_DEBUG && LABEL_NAME (insn))
sdbout_label (insn);
@@ -1495,9 +2305,13 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
if (write_symbols == DWARF_DEBUG && LABEL_NAME (insn))
dwarfout_label (insn);
#endif
+#ifdef DWARF2_DEBUGGING_INFO
+ if (write_symbols == DWARF2_DEBUG && LABEL_NAME (insn))
+ dwarf2out_label (insn);
+#endif
if (app_on)
{
- fprintf (file, ASM_APP_OFF);
+ fputs (ASM_APP_OFF, file);
app_on = 0;
}
if (NEXT_INSN (insn) != 0
@@ -1512,16 +2326,18 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
if (GET_CODE (nextbody) == ADDR_VEC
|| GET_CODE (nextbody) == ADDR_DIFF_VEC)
{
-#ifndef JUMP_TABLES_IN_TEXT_SECTION
- readonly_data_section ();
+ if (! JUMP_TABLES_IN_TEXT_SECTION)
+ {
+ readonly_data_section ();
#ifdef READONLY_DATA_SECTION
- ASM_OUTPUT_ALIGN (file,
- exact_log2 (BIGGEST_ALIGNMENT
- / BITS_PER_UNIT));
+ ASM_OUTPUT_ALIGN (file,
+ exact_log2 (BIGGEST_ALIGNMENT
+ / BITS_PER_UNIT));
#endif /* READONLY_DATA_SECTION */
-#else /* JUMP_TABLES_IN_TEXT_SECTION */
- function_section (current_function_decl);
-#endif /* JUMP_TABLES_IN_TEXT_SECTION */
+ }
+ else
+ function_section (current_function_decl);
+
#ifdef ASM_OUTPUT_CASE_LABEL
ASM_OUTPUT_CASE_LABEL (file, "L", CODE_LABEL_NUMBER (insn),
NEXT_INSN (insn));
@@ -1540,7 +2356,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
register rtx body = PATTERN (insn);
int insn_code_number;
char *template;
+#ifdef HAVE_cc0
rtx note;
+#endif
/* An INSN, JUMP_INSN or CALL_INSN.
First check for special kinds that recog doesn't recognize. */
@@ -1575,7 +2393,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
if (app_on)
{
- fprintf (file, ASM_APP_OFF);
+ fputs (ASM_APP_OFF, file);
app_on = 0;
}
@@ -1596,6 +2414,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
#ifdef ASM_OUTPUT_ADDR_DIFF_ELT
ASM_OUTPUT_ADDR_DIFF_ELT
(file,
+ body,
CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
CODE_LABEL_NUMBER (XEXP (XEXP (body, 0), 0)));
#else
@@ -1627,7 +2446,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
break;
if (! app_on)
{
- fprintf (file, ASM_APP_ON);
+ fputs (ASM_APP_ON, file);
app_on = 1;
}
fprintf (asm_out_file, "\t%s\n", XSTR (body, 0));
@@ -1637,7 +2456,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
/* Detect `asm' construct with operands. */
if (asm_noperands (body) >= 0)
{
- int noperands = asm_noperands (body);
+ unsigned int noperands = asm_noperands (body);
rtx *ops = (rtx *) alloca (noperands * sizeof (rtx));
char *string;
@@ -1648,7 +2467,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
if (! app_on)
{
- fprintf (file, ASM_APP_ON);
+ fputs (ASM_APP_ON, file);
app_on = 1;
}
@@ -1667,7 +2486,7 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
if (prescan <= 0 && app_on)
{
- fprintf (file, ASM_APP_OFF);
+ fputs (ASM_APP_OFF, file);
app_on = 0;
}
@@ -1714,7 +2533,9 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
actions in these insns and the CC must be marked as being
clobbered by the function. */
if (GET_CODE (XVECEXP (body, 0, 0)) == CALL_INSN)
- CC_STATUS_INIT;
+ {
+ CC_STATUS_INIT;
+ }
/* Following a conditional branch sequence, we have a new basic
block. */
@@ -1739,6 +2560,8 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
body = PATTERN (insn);
#ifdef HAVE_cc0
+ set = single_set(insn);
+
/* Check for redundant test and compare instructions
(when the condition codes are already set up as desired).
This is done only when optimizing; if not optimizing,
@@ -1747,35 +2570,41 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
and the next statement should reexamine the variable
to compute the condition codes. */
- if (optimize
- && GET_CODE (body) == SET
- && GET_CODE (SET_DEST (body)) == CC0
- && insn != last_ignored_compare)
+ if (optimize)
{
- if (GET_CODE (SET_SRC (body)) == SUBREG)
- SET_SRC (body) = alter_subreg (SET_SRC (body));
- else if (GET_CODE (SET_SRC (body)) == COMPARE)
- {
- if (GET_CODE (XEXP (SET_SRC (body), 0)) == SUBREG)
- XEXP (SET_SRC (body), 0)
- = alter_subreg (XEXP (SET_SRC (body), 0));
- if (GET_CODE (XEXP (SET_SRC (body), 1)) == SUBREG)
- XEXP (SET_SRC (body), 1)
- = alter_subreg (XEXP (SET_SRC (body), 1));
- }
- if ((cc_status.value1 != 0
- && rtx_equal_p (SET_SRC (body), cc_status.value1))
- || (cc_status.value2 != 0
- && rtx_equal_p (SET_SRC (body), cc_status.value2)))
+#if 0
+ rtx set = single_set(insn);
+#endif
+
+ if (set
+ && GET_CODE (SET_DEST (set)) == CC0
+ && insn != last_ignored_compare)
{
- /* Don't delete insn if it has an addressing side-effect. */
- if (! FIND_REG_INC_NOTE (insn, 0)
- /* or if anything in it is volatile. */
- && ! volatile_refs_p (PATTERN (insn)))
+ if (GET_CODE (SET_SRC (set)) == SUBREG)
+ SET_SRC (set) = alter_subreg (SET_SRC (set));
+ else if (GET_CODE (SET_SRC (set)) == COMPARE)
{
- /* We don't really delete the insn; just ignore it. */
- last_ignored_compare = insn;
- break;
+ if (GET_CODE (XEXP (SET_SRC (set), 0)) == SUBREG)
+ XEXP (SET_SRC (set), 0)
+ = alter_subreg (XEXP (SET_SRC (set), 0));
+ if (GET_CODE (XEXP (SET_SRC (set), 1)) == SUBREG)
+ XEXP (SET_SRC (set), 1)
+ = alter_subreg (XEXP (SET_SRC (set), 1));
+ }
+ if ((cc_status.value1 != 0
+ && rtx_equal_p (SET_SRC (set), cc_status.value1))
+ || (cc_status.value2 != 0
+ && rtx_equal_p (SET_SRC (set), cc_status.value2)))
+ {
+ /* Don't delete insn if it has an addressing side-effect. */
+ if (! FIND_REG_INC_NOTE (insn, 0)
+ /* or if anything in it is volatile. */
+ && ! volatile_refs_p (PATTERN (insn)))
+ {
+ /* We don't really delete the insn; just ignore it. */
+ last_ignored_compare = insn;
+ break;
+ }
}
}
}
@@ -1856,12 +2685,29 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
}
/* Make same adjustments to instructions that examine the
- condition codes without jumping (if this machine has them). */
+ condition codes without jumping and instructions that
+ handle conditional moves (if this machine has either one). */
if (cc_status.flags != 0
- && GET_CODE (body) == SET)
+ && set != 0)
{
- switch (GET_CODE (SET_SRC (body)))
+ rtx cond_rtx, then_rtx, else_rtx;
+
+ if (GET_CODE (insn) != JUMP_INSN
+ && GET_CODE (SET_SRC (set)) == IF_THEN_ELSE)
+ {
+ cond_rtx = XEXP (SET_SRC (set), 0);
+ then_rtx = XEXP (SET_SRC (set), 1);
+ else_rtx = XEXP (SET_SRC (set), 2);
+ }
+ else
+ {
+ cond_rtx = SET_SRC (set);
+ then_rtx = const_true_rtx;
+ else_rtx = const0_rtx;
+ }
+
+ switch (GET_CODE (cond_rtx))
{
case GTU:
case GT:
@@ -1875,18 +2721,29 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
case NE:
{
register int result;
- if (XEXP (SET_SRC (body), 0) != cc0_rtx)
+ if (XEXP (cond_rtx, 0) != cc0_rtx)
break;
- result = alter_cond (SET_SRC (body));
+ result = alter_cond (cond_rtx);
if (result == 1)
- validate_change (insn, &SET_SRC (body), const_true_rtx, 0);
+ validate_change (insn, &SET_SRC (set), then_rtx, 0);
else if (result == -1)
- validate_change (insn, &SET_SRC (body), const0_rtx, 0);
+ validate_change (insn, &SET_SRC (set), else_rtx, 0);
else if (result == 2)
INSN_CODE (insn) = -1;
+ if (SET_DEST (set) == SET_SRC (set))
+ {
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ }
}
+ break;
+
+ default:
+ break;
}
}
+
#endif
/* Do machine-specific peephole optimizations if desired. */
@@ -1971,6 +2828,12 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
debug_insn = insn;
+#if defined (DWARF2_UNWIND_INFO) && !defined (ACCUMULATE_OUTGOING_ARGS)
+ /* If we push arguments, we want to know where the calls are. */
+ if (GET_CODE (insn) == CALL_INSN && dwarf2out_do_frame ())
+ dwarf2out_frame_debug (insn);
+#endif
+
/* If the proper template needs to be chosen by some C code,
run that code and get the real template. */
@@ -1999,8 +2862,15 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
/* If we didn't split the insn, go away. */
if (new == insn && PATTERN (new) == body)
- abort ();
+ fatal_insn ("Could not split insn", insn);
+#ifdef HAVE_ATTR_length
+ /* This instruction should have been split in shorten_branches,
+ to ensure that we would have valid length info for the
+ splitees. */
+ abort ();
+#endif
+
new_block = 0;
return new;
}
@@ -2012,6 +2882,22 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
output_asm_insn (template, recog_operand);
+#if defined (DWARF2_UNWIND_INFO)
+#if !defined (ACCUMULATE_OUTGOING_ARGS)
+ /* If we push arguments, we need to check all insns for stack
+ adjustments. */
+ if (GET_CODE (insn) == INSN && dwarf2out_do_frame ())
+ dwarf2out_frame_debug (insn);
+#else
+#if defined (HAVE_prologue)
+ /* If this insn is part of the prologue, emit DWARF v2
+ call frame info. */
+ if (RTX_FRAME_RELATED_P (insn) && dwarf2out_do_frame ())
+ dwarf2out_frame_debug (insn);
+#endif
+#endif
+#endif
+
#if 0
/* It's not at all clear why we did this and doing so interferes
with tests we'd like to do to use REG_WAS_0 notes, so let's try
@@ -2085,6 +2971,11 @@ output_source_line (file, insn)
if (write_symbols == DWARF_DEBUG)
dwarfout_line (filename, NOTE_LINE_NUMBER (insn));
#endif
+
+#ifdef DWARF2_DEBUGGING_INFO
+ if (write_symbols == DWARF2_DEBUG)
+ dwarf2out_line (filename, NOTE_LINE_NUMBER (insn));
+#endif
}
}
@@ -2096,14 +2987,31 @@ alter_subreg (x)
register rtx x;
{
register rtx y = SUBREG_REG (x);
+
if (GET_CODE (y) == SUBREG)
y = alter_subreg (y);
+ /* If reload is operating, we may be replacing inside this SUBREG.
+ Check for that and make a new one if so. */
+ if (reload_in_progress && find_replacement (&SUBREG_REG (x)) != 0)
+ x = copy_rtx (x);
+
if (GET_CODE (y) == REG)
{
- /* If the containing reg really gets a hard reg, so do we. */
+ /* If the word size is larger than the size of this register,
+ adjust the register number to compensate. */
+ /* ??? Note that this just catches stragglers created by/for
+ integrate. It would be better if we either caught these
+ earlier, or kept _all_ subregs until now and eliminate
+ gen_lowpart and friends. */
+
PUT_CODE (x, REG);
+#ifdef ALTER_HARD_SUBREG
+ REGNO (x) = ALTER_HARD_SUBREG(GET_MODE (x), SUBREG_WORD (x),
+ GET_MODE (y), REGNO (y));
+#else
REGNO (x) = REGNO (y) + SUBREG_WORD (x);
+#endif
}
else if (GET_CODE (y) == MEM)
{
@@ -2113,6 +3021,8 @@ alter_subreg (x)
- MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (y))));
PUT_CODE (x, MEM);
MEM_VOLATILE_P (x) = MEM_VOLATILE_P (y);
+ MEM_IN_STRUCT_P (x) = MEM_IN_STRUCT_P (y);
+ MEM_ALIAS_SET (x) = MEM_ALIAS_SET (y);
XEXP (x, 0) = plus_constant (XEXP (y, 0), offset);
}
@@ -2139,6 +3049,9 @@ walk_alter_subreg (x)
case SUBREG:
return alter_subreg (x);
+
+ default:
+ break;
}
return x;
@@ -2197,6 +3110,9 @@ alter_cond (cond)
PUT_CODE (cond, NE);
value = 2;
break;
+
+ default:
+ break;
}
if (cc_status.flags & CC_NOT_NEGATIVE)
@@ -2223,6 +3139,9 @@ alter_cond (cond)
PUT_CODE (cond, NE);
value = 2;
break;
+
+ default:
+ break;
}
if (cc_status.flags & CC_NO_OVERFLOW)
@@ -2245,19 +3164,15 @@ alter_cond (cond)
case LTU:
/* Jump becomes no-op. */
return -1;
+
+ default:
+ break;
}
if (cc_status.flags & (CC_Z_IN_NOT_N | CC_Z_IN_N))
switch (GET_CODE (cond))
{
- case LE:
- case LEU:
- case GE:
- case GEU:
- case LT:
- case LTU:
- case GT:
- case GTU:
+ default:
abort ();
case NE:
@@ -2295,6 +3210,9 @@ alter_cond (cond)
PUT_CODE (cond, GEU);
value = 2;
break;
+
+ default:
+ break;
}
return value;
@@ -2311,7 +3229,7 @@ output_operand_lossage (str)
if (this_is_asm_operands)
error_for_asm (this_is_asm_operands, "invalid `asm': %s", str);
else
- abort ();
+ fatal ("Internal compiler error, output_operand_lossage `%s'", str);
}
/* Output of assembler code from a template, and its subroutines. */
@@ -2360,7 +3278,7 @@ output_asm_insn (template, operands)
rtx *operands;
{
register char *p;
- register int c, i;
+ register int c;
/* An insn may return a null string template
in a case where no assembler code is needed. */
@@ -2374,7 +3292,7 @@ output_asm_insn (template, operands)
ASM_OUTPUT_OPCODE (asm_out_file, p);
#endif
- while (c = *p++)
+ while ((c = *p++))
switch (c)
{
case '\n':
@@ -2392,16 +3310,20 @@ output_asm_insn (template, operands)
#ifdef ASSEMBLER_DIALECT
case '{':
- /* If we want the first dialect, do nothing. Otherwise, skip
- DIALECT_NUMBER of strings ending with '|'. */
- for (i = 0; i < dialect_number; i++)
- {
- while (*p && *p++ != '|')
- ;
+ {
+ register int i;
+
+ /* If we want the first dialect, do nothing. Otherwise, skip
+ DIALECT_NUMBER of strings ending with '|'. */
+ for (i = 0; i < dialect_number; i++)
+ {
+ while (*p && *p++ != '|')
+ ;
- if (*p == '|')
- p++;
- }
+ if (*p == '|')
+ p++;
+ }
+ }
break;
case '|':
@@ -2442,7 +3364,7 @@ output_asm_insn (template, operands)
if (! (*p >= '0' && *p <= '9'))
output_operand_lossage ("operand number missing after %-letter");
- else if (this_is_asm_operands && c >= (unsigned) insn_noperands)
+ else if (this_is_asm_operands && (c < 0 || (unsigned int) c >= insn_noperands))
output_operand_lossage ("operand number out of range");
else if (letter == 'l')
output_asm_label (operands[c]);
@@ -2458,12 +3380,7 @@ output_asm_insn (template, operands)
else if (letter == 'n')
{
if (GET_CODE (operands[c]) == CONST_INT)
- fprintf (asm_out_file,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- "%d",
-#else
- "%ld",
-#endif
+ fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC,
- INTVAL (operands[c]));
else
{
@@ -2480,7 +3397,7 @@ output_asm_insn (template, operands)
else if (*p >= '0' && *p <= '9')
{
c = atoi (p);
- if (this_is_asm_operands && c >= (unsigned) insn_noperands)
+ if (this_is_asm_operands && (c < 0 || (unsigned int) c >= insn_noperands))
output_operand_lossage ("operand number out of range");
else
output_operand (operands[c], 0);
@@ -2599,13 +3516,7 @@ output_addr_const (file, x)
break;
case CONST_INT:
- fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- "%d",
-#else
- "%ld",
-#endif
- INTVAL (x));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
break;
case CONST:
@@ -2619,37 +3530,12 @@ output_addr_const (file, x)
{
/* We can use %d if the number is one word and positive. */
if (CONST_DOUBLE_HIGH (x))
- fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == 64
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
- "0x%lx%016lx",
-#else
- "0x%x%016x",
-#endif
-#else
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
- "0x%lx%08lx",
-#else
- "0x%x%08x",
-#endif
-#endif
+ fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
else if (CONST_DOUBLE_LOW (x) < 0)
- fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- "0x%x",
-#else
- "0x%lx",
-#endif
- CONST_DOUBLE_LOW (x));
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
else
- fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- "%d",
-#else
- "%ld",
-#endif
- CONST_DOUBLE_LOW (x));
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
}
else
/* We can't handle floating point constants;
@@ -2725,32 +3611,35 @@ asm_fprintf VPROTO((FILE *file, char *p, ...))
va_list argptr;
char buf[10];
char *q, c;
- int i;
VA_START (argptr, p);
#ifndef __STDC__
- file = va_arg (argptr, FILE*);
- p = va_arg (argptr, char*);
+ file = va_arg (argptr, FILE *);
+ p = va_arg (argptr, char *);
#endif
buf[0] = '%';
- while (c = *p++)
+ while ((c = *p++))
switch (c)
{
#ifdef ASSEMBLER_DIALECT
case '{':
- /* If we want the first dialect, do nothing. Otherwise, skip
- DIALECT_NUMBER of strings ending with '|'. */
- for (i = 0; i < dialect_number; i++)
- {
- while (*p && *p++ != '|')
- ;
+ {
+ int i;
- if (*p == '|')
- p++;
+ /* If we want the first dialect, do nothing. Otherwise, skip
+ DIALECT_NUMBER of strings ending with '|'. */
+ for (i = 0; i < dialect_number; i++)
+ {
+ while (*p && *p++ != '|')
+ ;
+
+ if (*p == '|')
+ p++;
}
+ }
break;
case '|':
@@ -2790,9 +3679,15 @@ asm_fprintf VPROTO((FILE *file, char *p, ...))
but we do not check for those cases. It means that the value
is a HOST_WIDE_INT, which may be either `int' or `long'. */
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
+ *q++ = 'l';
+#else
+ *q++ = 'l';
*q++ = 'l';
#endif
+#endif
*q++ = *p++;
*q = 0;
@@ -2875,16 +3770,18 @@ split_double (value, first, second)
if (HOST_BITS_PER_WIDE_INT >= (2 * BITS_PER_WORD))
{
/* In this case the CONST_INT holds both target words.
- Extract the bits from it into two word-sized pieces. */
+ Extract the bits from it into two word-sized pieces.
+ Sign extend each half to HOST_WIDE_INT. */
rtx low, high;
- HOST_WIDE_INT word_mask;
- /* Avoid warnings for shift count >= BITS_PER_WORD. */
- int shift_count = BITS_PER_WORD - 1;
-
- word_mask = (HOST_WIDE_INT) 1 << shift_count;
- word_mask |= word_mask - 1;
- low = GEN_INT (INTVAL (value) & word_mask);
- high = GEN_INT ((INTVAL (value) >> (shift_count + 1)) & word_mask);
+ /* On machines where HOST_BITS_PER_WIDE_INT == BITS_PER_WORD
+ the shift below will cause a compiler warning, even though
+ this code won't be executed. So put the shift amounts in
+ variables to avoid the warning. */
+ int rshift = HOST_BITS_PER_WIDE_INT - BITS_PER_WORD;
+ int lshift = HOST_BITS_PER_WIDE_INT - 2 * BITS_PER_WORD;
+
+ low = GEN_INT ((INTVAL (value) << rshift) >> rshift);
+ high = GEN_INT ((INTVAL (value) << lshift) >> rshift);
if (WORDS_BIG_ENDIAN)
{
*first = high;
@@ -2953,7 +3850,7 @@ split_double (value, first, second)
/* Note, this converts the REAL_VALUE_TYPE to the target's
format, splits up the floating point double and outputs
exactly 32 bits of it into each of l[0] and l[1] --
- not necessarily BITS_PER_WORD bits. */
+ not necessarily BITS_PER_WORD bits. */
REAL_VALUE_TO_TARGET_DOUBLE (r, l);
*first = GEN_INT ((HOST_WIDE_INT) l[0]);
@@ -2992,7 +3889,7 @@ leaf_function_p ()
{
rtx insn;
- if (profile_flag || profile_block_flag)
+ if (profile_flag || profile_block_flag || profile_arc_flag)
return 0;
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
@@ -3039,11 +3936,16 @@ only_leaf_regs_used ()
int i;
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- {
- if ((regs_ever_live[i] || global_regs[i])
- && ! permitted_reg_in_leaf_functions[i])
- return 0;
- }
+ if ((regs_ever_live[i] || global_regs[i])
+ && ! permitted_reg_in_leaf_functions[i])
+ return 0;
+
+ if (current_function_uses_pic_offset_table
+ && pic_offset_table_rtx != 0
+ && GET_CODE (pic_offset_table_rtx) == REG
+ && ! permitted_reg_in_leaf_functions[REGNO (pic_offset_table_rtx)])
+ return 0;
+
return 1;
}
diff --git a/contrib/gcc/fix-header.c b/contrib/gcc/fix-header.c
index 7059d12..8ba79ff 100644
--- a/contrib/gcc/fix-header.c
+++ b/contrib/gcc/fix-header.c
@@ -1,5 +1,5 @@
/* fix-header.c - Make C header file suitable for C++.
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 94-97, 1998 Free Software Foundation, Inc.
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
@@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This program massages a system include file (such as stdio.h),
- into a form more conforming with ANSI/POSIX, and more suitable for C++:
+ into a form that is compatible with GNU C and GNU C++.
* extern "C" { ... } braces are added (inside #ifndef __cplusplus),
if they seem to be needed. These prevent C++ compilers from name
@@ -26,7 +26,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
an argument list), and it is a "standard" function listed in
the file sys-protos.h (and with a non-empty argument list), then
the declaration is converted to a complete prototype by replacing
- the empty parameter list with the argument lust from sys-protos.h.
+ the empty parameter list with the argument list from sys-protos.h.
* The program can be given a list of (names of) required standard
functions (such as fclose for stdio.h). If a required function
@@ -68,21 +68,22 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
if anything needs to be done. (e.g. ./include/stdio.h)
* OPTIONS are such as you would pass to cpp.
- Written by Per Bothner <bothner@cygnus.com>, July 1993. */
+ Written by Per Bothner <bothner@cygnus.com>, July 1993. */
-#include <stdio.h>
-#include <ctype.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
+#include "gansidecl.h"
#include "obstack.h"
#include "scan.h"
#include "cpplib.h"
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
+#include "cpphash.h"
-#if !__STDC__
-#define const /* nothing */
-#endif
+void fatal PVPROTO ((const char *, ...)) ATTRIBUTE_PRINTF_1;
sstring buf;
@@ -97,12 +98,11 @@ int warnings = 0;
#if ADD_MISSING_EXTERN_C
int missing_extern_C_count = 0;
#endif
-int missing_errno = 0;
#include "xsys-protos.h"
#ifdef FIXPROTO_IGNORE_LIST
-/* This is a currently unused feature. */
+/* This is a currently unused feature. */
/* List of files and directories to ignore.
A directory name (ending in '/') means ignore anything in that
@@ -125,148 +125,245 @@ char *inf_ptr;
enum special_file
{
no_special,
+#ifdef errno_h
+#undef errno_h
+#endif
errno_h,
+#ifdef stdio_h
+#undef stdio_h
+#endif
stdio_h,
+#ifdef stdlib_h
+#undef stdlib_h
+#endif
+ stdlib_h,
+#ifdef sys_stat_h
+#undef sys_stat_h
+#endif
sys_stat_h
};
/* A NAMELIST is a sequence of names, separated by '\0', and terminated
- by an empty name (i.e. by "\0\0"). */
+ by an empty name (i.e. by "\0\0"). */
+
+typedef const char *namelist;
+
+/* The following macros provide the bits for symbol_flags. */
+typedef int symbol_flags;
+
+/* Used to mark names defined in the ANSI/ISO C standard. */
+#define ANSI_SYMBOL 1
+
+/* We no longer massage include files for POSIX or XOPEN symbols,
+ as there are now several versions of the POSIX and XOPEN standards,
+ and it would be a maintenance nightmare for us to track them all.
+ Better to be compatible with the system include files. */
+/*#define ADD_MISSING_POSIX 1 */
+/*#define ADD_MISSING_XOPEN 1 */
+
+#if ADD_MISSING_POSIX
+/* Used to mark names defined in the Posix.1 or Posix.2 standard. */
+#define POSIX1_SYMBOL 2
+#define POSIX2_SYMBOL 4
+#else
+#define POSIX1_SYMBOL 0
+#define POSIX2_SYMBOL 0
+#endif
-typedef const char* namelist;
+#if ADD_MISSING_XOPEN
+/* Used to mark names defined in X/Open Portability Guide. */
+#define XOPEN_SYMBOL 8
+/* Used to mark names defined in X/Open UNIX Extensions. */
+#define XOPEN_EXTENDED_SYMBOL 16
+#else
+#define XOPEN_SYMBOL 0
+#define XOPEN_EXTENDED_SYMBOL 0
+#endif
-struct std_include_entry {
- const char *name;
- namelist required;
- namelist extra;
- int special;
+/* Used to indicate names that are not functions */
+#define MACRO_SYMBOL 512
+
+struct symbol_list {
+ symbol_flags flags;
+ namelist names;
};
-/* End of namelist NAMES. */
+#define SYMBOL_TABLE_SIZE 10
+struct symbol_list symbol_table[SYMBOL_TABLE_SIZE];
+int cur_symbol_table_size;
-namelist
-namelist_end (names)
+void
+add_symbols (flags, names)
+ symbol_flags flags;
namelist names;
{
- register namelist ptr;
- for (ptr = names; ; ptr++)
- {
- if (*ptr == '\0')
- {
- ptr++;
- if (*ptr == '\0')
- return ptr;
- }
- }
+ symbol_table[cur_symbol_table_size].flags = flags;
+ symbol_table[cur_symbol_table_size].names = names;
+ cur_symbol_table_size++;
+ if (cur_symbol_table_size >= SYMBOL_TABLE_SIZE)
+ fatal ("too many calls to add_symbols");
+ symbol_table[cur_symbol_table_size].names = NULL; /* Termination. */
}
-const char NONE[] = "";
+struct std_include_entry {
+ const char *name;
+ symbol_flags flags;
+ namelist names;
+};
+
+const char NONE[] = ""; /* The empty namelist. */
+
+/* Special name to indicate a continuation line in std_include_table. */
+const char CONTINUED[] = "";
struct std_include_entry *include_entry;
struct std_include_entry std_include_table [] = {
- { "ctype.h",
+ { "ctype.h", ANSI_SYMBOL,
"isalnum\0isalpha\0iscntrl\0isdigit\0isgraph\0islower\0\
-isprint\0ispunct\0isspace\0isupper\0isxdigit\0tolower\0toupper\0", NONE },
+isprint\0ispunct\0isspace\0isupper\0isxdigit\0tolower\0toupper\0" },
- { "dirent.h", "closedir\0opendir\0readdir\0rewinddir\0", NONE},
+ { "dirent.h", POSIX1_SYMBOL, "closedir\0opendir\0readdir\0rewinddir\0"},
- { "errno.h", NONE, "errno\0" },
+ { "errno.h", ANSI_SYMBOL|MACRO_SYMBOL, "errno\0" },
- { "curses.h", "box\0delwin\0endwin\0getcurx\0getcury\0initscr\0\
+ /* ANSI_SYMBOL is wrong, but ... */
+ { "curses.h", ANSI_SYMBOL, "box\0delwin\0endwin\0getcurx\0getcury\0initscr\0\
mvcur\0mvwprintw\0mvwscanw\0newwin\0overlay\0overwrite\0\
scroll\0subwin\0touchwin\0waddstr\0wclear\0wclrtobot\0wclrtoeol\0\
waddch\0wdelch\0wdeleteln\0werase\0wgetch\0wgetstr\0winsch\0winsertln\0\
-wmove\0wprintw\0wrefresh\0wscanw\0wstandend\0wstandout\0", NONE },
+wmove\0wprintw\0wrefresh\0wscanw\0wstandend\0wstandout\0" },
- { "fcntl.h", "creat\0fcntl\0open\0", NONE },
+ { "fcntl.h", POSIX1_SYMBOL, "creat\0fcntl\0open\0" },
/* Maybe also "getgrent fgetgrent setgrent endgrent" */
- { "grp.h", "getgrgid\0getgrnam\0", NONE },
+ { "grp.h", POSIX1_SYMBOL, "getgrgid\0getgrnam\0" },
/*{ "limit.h", ... provided by gcc }, */
- { "locale.h", "localeconv\0setlocale\0", NONE },
+ { "locale.h", ANSI_SYMBOL, "localeconv\0setlocale\0" },
- { "math.h", "acos\0asin\0atan\0atan2\0ceil\0cos\0cosh\0exp\0\
+ { "math.h", ANSI_SYMBOL,
+ "acos\0asin\0atan\0atan2\0ceil\0cos\0cosh\0exp\0\
fabs\0floor\0fmod\0frexp\0ldexp\0log10\0log\0modf\0pow\0sin\0sinh\0sqrt\0\
-tan\0tanh\0", "HUGE_VAL\0" },
+tan\0tanh\0" },
- { "pwd.h", "getpwnam\0getpwuid\0", NONE },
+ { CONTINUED, ANSI_SYMBOL|MACRO_SYMBOL, "HUGE_VAL\0" },
- /* Left out siglongjmp sigsetjmp - these depend on sigjmp_buf. */
- { "setjmp.h", "longjmp\0setjmp\0", NONE },
+ { "pwd.h", POSIX1_SYMBOL, "getpwnam\0getpwuid\0" },
+
+ /* Left out siglongjmp sigsetjmp - these depend on sigjmp_buf. */
+ { "setjmp.h", ANSI_SYMBOL, "longjmp\0setjmp\0" },
/* Left out signal() - its prototype is too complex for us!
Also left out "sigaction sigaddset sigdelset sigemptyset
sigfillset sigismember sigpending sigprocmask sigsuspend"
because these need sigset_t or struct sigaction.
- Most systems that provide them will also declare them. */
- { "signal.h", "kill\0raise\0", NONE },
+ Most systems that provide them will also declare them. */
+ { "signal.h", ANSI_SYMBOL, "kill\0raise\0" },
- { "stdio.h", "clearerr\0fclose\0feof\0ferror\0fflush\0fgetc\0fgetpos\0\
+ { "stdio.h", ANSI_SYMBOL,
+ "clearerr\0fclose\0feof\0ferror\0fflush\0fgetc\0fgetpos\0\
fgets\0fopen\0fprintf\0fputc\0fputs\0fread\0freopen\0fscanf\0fseek\0\
-fsetpos\0ftell\0fwrite\0getc\0getchar\0gets\0pclose\0perror\0popen\0\
+fsetpos\0ftell\0fwrite\0getc\0getchar\0gets\0perror\0\
printf\0putc\0putchar\0puts\0remove\0rename\0rewind\0scanf\0setbuf\0\
setvbuf\0sprintf\0sscanf\0vprintf\0vsprintf\0vfprintf\0tmpfile\0\
-tmpnam\0ungetc\0", NONE },
+tmpnam\0ungetc\0" },
+ { CONTINUED, POSIX1_SYMBOL, "fdopen\0fileno\0" },
+ { CONTINUED, POSIX2_SYMBOL, "pclose\0popen\0" }, /* I think ... */
/* Should perhaps also handle NULL, EOF, ... ? */
/* "div ldiv", - ignored because these depend on div_t, ldiv_t
ignore these: "mblen mbstowcs mbstowc wcstombs wctomb"
Left out getgroups, because SunOS4 has incompatible BSD and SVR4 versions.
Should perhaps also add NULL */
- { "stdlib.h", "abort\0abs\0atexit\0atof\0atoi\0atol\0bsearch\0calloc\0\
+ { "stdlib.h", ANSI_SYMBOL,
+ "abort\0abs\0atexit\0atof\0atoi\0atol\0bsearch\0calloc\0\
exit\0free\0getenv\0labs\0malloc\0putenv\0qsort\0rand\0realloc\0\
-srand\0strtod\0strtol\0strtoul\0system\0", NONE },
+srand\0strtod\0strtol\0strtoul\0system\0" },
+ { CONTINUED, ANSI_SYMBOL|MACRO_SYMBOL, "EXIT_FAILURE\0EXIT_SUCCESS\0" },
- { "string.h", "memchr\0memcmp\0memcpy\0memmove\0memset\0\
+ { "string.h", ANSI_SYMBOL, "memchr\0memcmp\0memcpy\0memmove\0memset\0\
strcat\0strchr\0strcmp\0strcoll\0strcpy\0strcspn\0strerror\0\
strlen\0strncat\0strncmp\0strncpy\0strpbrk\0strrchr\0strspn\0strstr\0\
-strtok\0strxfrm\0", NONE },
+strtok\0strxfrm\0" },
/* Should perhaps also add NULL and size_t */
- { "sys/stat.h", "chmod\0fstat\0mkdir\0mkfifo\0stat\0lstat\0umask\0",
+ { "strings.h", XOPEN_EXTENDED_SYMBOL,
+ "bcmp\0bcopy\0bzero\0ffs\0index\0rindex\0strcasecmp\0strncasecmp\0" },
+
+ { "strops.h", XOPEN_EXTENDED_SYMBOL, "ioctl\0" },
+
+ /* Actually, XPG4 does not seem to have <sys/ioctl.h>, but defines
+ ioctl in <strops.h>. However, many systems have it is sys/ioctl.h,
+ and many systems do have <sys/ioctl.h> but not <strops.h>. */
+ { "sys/ioctl.h", XOPEN_EXTENDED_SYMBOL, "ioctl\0" },
+
+ { "sys/socket.h", XOPEN_EXTENDED_SYMBOL, "socket\0" },
+
+ { "sys/stat.h", POSIX1_SYMBOL,
+ "chmod\0fstat\0mkdir\0mkfifo\0stat\0lstat\0umask\0" },
+ { CONTINUED, POSIX1_SYMBOL|MACRO_SYMBOL,
"S_ISDIR\0S_ISBLK\0S_ISCHR\0S_ISFIFO\0S_ISREG\0S_ISLNK\0S_IFDIR\0\
S_IFBLK\0S_IFCHR\0S_IFIFO\0S_IFREG\0S_IFLNK\0" },
+ { CONTINUED, XOPEN_EXTENDED_SYMBOL, "fchmod\0" },
+
+#if 0
+/* How do we handle fd_set? */
+ { "sys/time.h", XOPEN_EXTENDED_SYMBOL, "select\0" },
+ { "sys/select.h", XOPEN_EXTENDED_SYMBOL /* fake */, "select\0" },
+#endif
- { "sys/times.h", "times\0", NONE },
+ { "sys/times.h", POSIX1_SYMBOL, "times\0" },
/* "sys/types.h" add types (not in old g++-include) */
- { "sys/utsname.h", "uname\0", NONE },
+ { "sys/utsname.h", POSIX1_SYMBOL, "uname\0" },
- { "sys/wait.h", "wait\0waitpid\0",
+ { "sys/wait.h", POSIX1_SYMBOL, "wait\0waitpid\0" },
+ { CONTINUED, POSIX1_SYMBOL|MACRO_SYMBOL,
"WEXITSTATUS\0WIFEXITED\0WIFSIGNALED\0WIFSTOPPED\0WSTOPSIG\0\
WTERMSIG\0WNOHANG\0WNOTRACED\0" },
- { "tar.h", NONE, NONE },
+ { "tar.h", POSIX1_SYMBOL, NONE },
- { "termios.h", "cfgetispeed\0cfgetospeed\0cfsetispeed\0cfsetospeed\0tcdrain\0tcflow\0tcflush\0tcgetattr\0tcsendbreak\0tcsetattr\0", NONE },
+ { "termios.h", POSIX1_SYMBOL,
+ "cfgetispeed\0cfgetospeed\0cfsetispeed\0cfsetospeed\0tcdrain\0tcflow\0tcflush\0tcgetattr\0tcsendbreak\0tcsetattr\0" },
- { "time.h", "asctime\0clock\0ctime\0difftime\0gmtime\0localtime\0mktime\0strftime\0time\0tzset\0", NONE },
+ { "time.h", ANSI_SYMBOL,
+ "asctime\0clock\0ctime\0difftime\0gmtime\0localtime\0mktime\0strftime\0time\0tzset\0" },
- { "unistd.h", "_exit\0access\0alarm\0chdir\0chown\0close\0ctermid\0cuserid\0\
+ { "unistd.h", POSIX1_SYMBOL,
+ "_exit\0access\0alarm\0chdir\0chown\0close\0ctermid\0cuserid\0\
dup\0dup2\0execl\0execle\0execlp\0execv\0execve\0execvp\0fork\0fpathconf\0\
-getcwd\0getegid\0geteuid\0getgid\0getlogin\0getopt\0getpgrp\0getpid\0\
+getcwd\0getegid\0geteuid\0getgid\0getlogin\0getpgrp\0getpid\0\
getppid\0getuid\0isatty\0link\0lseek\0pathconf\0pause\0pipe\0read\0rmdir\0\
setgid\0setpgid\0setsid\0setuid\0sleep\0sysconf\0tcgetpgrp\0tcsetpgrp\0\
-ttyname\0unlink\0write\0", NONE },
+ttyname\0unlink\0write\0" },
+ { CONTINUED, POSIX2_SYMBOL, "getopt\0" },
+ { CONTINUED, XOPEN_EXTENDED_SYMBOL,
+ "lockf\0gethostid\0gethostname\0readlink\0" },
- { 0, NONE, NONE }
+ { "utime.h", POSIX1_SYMBOL, "utime\0" },
+
+ { NULL, 0, NONE }
};
enum special_file special_file_handling = no_special;
+/* They are set if the corresponding macro has been seen. */
/* The following are only used when handling sys/stat.h */
-/* They are set if the corresponding macro has been seen. */
int seen_S_IFBLK = 0, seen_S_ISBLK = 0;
int seen_S_IFCHR = 0, seen_S_ISCHR = 0;
int seen_S_IFDIR = 0, seen_S_ISDIR = 0;
int seen_S_IFIFO = 0, seen_S_ISFIFO = 0;
int seen_S_IFLNK = 0, seen_S_ISLNK = 0;
int seen_S_IFREG = 0, seen_S_ISREG = 0;
+/* The following are only used when handling errno.h */
+int seen_errno = 0;
+/* The following are only used when handling stdlib.h */
+int seen_EXIT_FAILURE = 0, seen_EXIT_SUCCESS = 0;
-/* Wrapper around free, to avoid prototype clashes. */
+/* Wrapper around free, to avoid prototype clashes. */
void
xfree (ptr)
@@ -290,6 +387,7 @@ fancy_abort ()
struct obstack scan_file_obstack;
/* NOTE: If you edit this, also edit gen-protos.c !! */
+
struct fn_decl *
lookup_std_proto (name, name_length)
const char *name;
@@ -320,8 +418,8 @@ sstring line;
int lbrac_line, rbrac_line;
-namelist required_functions_list;
int required_unseen_count = 0;
+int required_other = 0;
void
write_lbrac ()
@@ -364,10 +462,10 @@ void
recognized_macro (fname)
char *fname;
{
- /* The original include file defines fname as a macro. */
+ /* The original include file defines fname as a macro. */
struct fn_decl *fn = lookup_std_proto (fname, strlen (fname));
- /* Since fname is a macro, don't require a prototype for it. */
+ /* Since fname is a macro, don't require a prototype for it. */
if (fn)
{
if (REQUIRED (fn))
@@ -378,7 +476,14 @@ recognized_macro (fname)
switch (special_file_handling)
{
case errno_h:
- if (strcmp (fname, "errno") == 0) missing_errno = 0;
+ if (strcmp (fname, "errno") == 0 && !seen_errno)
+ seen_errno = 1, required_other--;
+ break;
+ case stdlib_h:
+ if (strcmp (fname, "EXIT_FAILURE") == 0 && !seen_EXIT_FAILURE)
+ seen_EXIT_FAILURE = 1, required_other--;
+ if (strcmp (fname, "EXIT_SUCCESS") == 0 && !seen_EXIT_SUCCESS)
+ seen_EXIT_SUCCESS = 1, required_other--;
break;
case sys_stat_h:
if (fname[0] == 'S' && fname[1] == '_')
@@ -396,6 +501,10 @@ recognized_macro (fname)
else if (strcmp (fname, "S_IFREG") == 0) seen_S_IFREG++;
else if (strcmp (fname, "S_ISREG") == 0) seen_S_ISREG++;
}
+ break;
+
+ default:
+ break;
}
}
@@ -408,7 +517,11 @@ recognized_extern (name, name_length, type, type_length)
switch (special_file_handling)
{
case errno_h:
- if (strncmp (name, "errno", name_length) == 0) missing_errno = 0;
+ if (name_length == 5 && strncmp (name, "errno", 5) == 0 && !seen_errno)
+ seen_errno = 1, required_other--;
+ break;
+
+ default:
break;
}
}
@@ -419,7 +532,7 @@ recognized_extern (name, name_length, type, type_length)
KIND is 'I' for an inline function;
'F' if a normal function declaration preceded by 'extern "C"'
(or nested inside 'extern "C"' braces); or
- 'f' for other function declarations. */
+ 'f' for other function declarations. */
void
recognized_function (fname, fname_length,
@@ -444,7 +557,7 @@ recognized_function (fname, fname_length,
fn = lookup_std_proto (fname, fname_length);
- /* Remove the function from the list of required function. */
+ /* Remove the function from the list of required function. */
if (fn)
{
if (REQUIRED (fn))
@@ -452,7 +565,7 @@ recognized_function (fname, fname_length,
SET_SEEN (fn);
}
- /* If we have a full prototype, we're done. */
+ /* If we have a full prototype, we're done. */
if (have_arg_list)
return;
@@ -460,7 +573,7 @@ recognized_function (fname, fname_length,
return;
/* If the partial prototype was included from some other file,
- we don't need to patch it up (in this run). */
+ we don't need to patch it up (in this run). */
i = strlen (file_seen);
if (i < inc_filename_length
|| strcmp (inc_filename, file_seen + (i - inc_filename_length)) != 0)
@@ -472,9 +585,9 @@ recognized_function (fname, fname_length,
return;
/* We only have a partial function declaration,
- so remember that we have to add a complete prototype. */
+ so remember that we have to add a complete prototype. */
partial_count++;
- partial = (struct partial_proto*)
+ partial = (struct partial_proto *)
obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto));
partial->fname = obstack_alloc (&scan_file_obstack, fname_length + 1);
bcopy (fname, partial->fname, fname_length);
@@ -494,11 +607,11 @@ recognized_function (fname, fname_length,
}
/* For any name in NAMES that is defined as a macro,
- call recognized_macro on it. */
+ call recognized_macro on it. */
void
check_macro_names (pfile, names)
- struct parse_file *pfile;
+ cpp_reader *pfile;
namelist names;
{
while (*names)
@@ -519,57 +632,51 @@ read_scan_file (in_fname, argc, argv)
cpp_options scan_options;
struct fn_decl *fn;
int i;
+ register struct symbol_list *cur_symbols;
obstack_init (&scan_file_obstack);
- init_parse_file (&scan_in);
+ cpp_reader_init (&scan_in);
scan_in.data = &scan_options;
- init_parse_options (&scan_options);
+ cpp_options_init (&scan_options);
i = cpp_handle_options (&scan_in, argc, argv);
- if (i < argc)
- fatal ("Invalid option `%s'", argv[i]);
- push_parse_file (&scan_in, in_fname);
- CPP_OPTIONS (&scan_in)->no_line_commands = 1;
+ if (i < argc && ! CPP_FATAL_ERRORS (&scan_in))
+ cpp_fatal (&scan_in, "Invalid option `%s'", argv[i]);
+ if (CPP_FATAL_ERRORS (&scan_in))
+ exit (FATAL_EXIT_CODE);
-#ifdef FIXPROTO_INIT
- /* Some targets may assume special definitions (for example
- OSF header files assume __LANGUAGE_C__). These macros
- are normally passed to cpplib by gcc - but we here invoke
- cpplib directly, without going through gcc.
- Handle these and other target-dependent initializations here. */
- FIXPROTO_INIT (&scan_in);
-#endif
+ if (! cpp_start_read (&scan_in, in_fname))
+ exit (FATAL_EXIT_CODE);
+ CPP_OPTIONS (&scan_in)->no_line_commands = 1;
- /* Actually (pre-)process the header file. */
scan_decls (&scan_in, argc, argv);
-
- check_macro_names (&scan_in, include_entry->required);
- check_macro_names (&scan_in, include_entry->extra);
+ for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
+ check_macro_names (&scan_in, cur_symbols->names);
if (verbose && (scan_in.errors + warnings) > 0)
fprintf (stderr, "(%s: %d errors and %d warnings from cpp)\n",
inc_filename, scan_in.errors, warnings);
if (scan_in.errors)
- exit (0);
+ exit (SUCCESS_EXIT_CODE);
/* Traditionally, getc and putc are defined in terms of _filbuf and _flsbuf.
- If so, those functions are also required. */
+ If so, those functions are also required. */
if (special_file_handling == stdio_h
&& (fn = lookup_std_proto ("_filbuf", 7)) != NULL)
{
static char getchar_call[] = "getchar();";
- cpp_buffer *buf =
- cpp_push_buffer (&scan_in, getchar_call, sizeof(getchar_call) - 1);
+ cpp_buffer *buf
+ = cpp_push_buffer (&scan_in, getchar_call, sizeof(getchar_call) - 1);
int old_written = CPP_WRITTEN (&scan_in);
int seen_filbuf = 0;
- /* Scan the macro expansion of "getchar();". */
+ /* Scan the macro expansion of "getchar();". */
for (;;)
{
enum cpp_token token = cpp_get_token (&scan_in);
int length = CPP_WRITTEN (&scan_in) - old_written;
CPP_SET_WRITTEN (&scan_in, old_written);
- if (token == CPP_EOF) /* Should not happen ... */
+ if (token == CPP_EOF) /* Should not happen ... */
break;
if (token == CPP_POP && CPP_BUFFER (&scan_in) == buf)
{
@@ -587,34 +694,27 @@ read_scan_file (in_fname, argc, argv)
int need_flsbuf
= flsbuf_fn && !SEEN (flsbuf_fn) && !REQUIRED (flsbuf_fn);
- /* Append "_filbuf" and/or "_flsbuf" to end of
- required_functions_list. */
+ /* Append "_filbuf" and/or "_flsbuf" to the required functions. */
if (need_filbuf + need_flsbuf)
{
- int old_len = namelist_end (required_functions_list)
- - required_functions_list;
- char *new_list = (char*) xmalloc (old_len + 20);
- bcopy (required_functions_list, new_list, old_len);
+ char *new_list;
if (need_filbuf)
- {
- strcpy (new_list + old_len, "_filbuf");
- old_len += 8;
- SET_REQUIRED (fn);
- }
+ SET_REQUIRED (fn);
if (need_flsbuf)
- {
- strcpy (new_list + old_len, "_flsbuf");
- old_len += 8;
- SET_REQUIRED (flsbuf_fn);
- }
- new_list[old_len] = '\0';
- required_functions_list = (namelist)new_list;
+ SET_REQUIRED (flsbuf_fn);
+ if (need_flsbuf + need_filbuf == 2)
+ new_list = "_filbuf\0_flsbuf\0";
+ else if (need_flsbuf)
+ new_list = "_flsbuf\0";
+ else /* if (need_flsbuf) */
+ new_list = "_filbuf\0";
+ add_symbols (ANSI_SYMBOL, new_list);
required_unseen_count += need_filbuf + need_flsbuf;
}
}
}
- if (required_unseen_count + partial_count + missing_errno
+ if (required_unseen_count + partial_count + required_other
#if ADD_MISSING_EXTERN_C
+ missing_extern_C_count
#endif
@@ -622,7 +722,7 @@ read_scan_file (in_fname, argc, argv)
{
if (verbose)
fprintf (stderr, "%s: OK, nothing needs to be done.\n", inc_filename);
- exit (0);
+ exit (SUCCESS_EXIT_CODE);
}
if (!verbose)
fprintf (stderr, "%s: fixing %s\n", progname, inc_filename);
@@ -648,58 +748,102 @@ write_rbrac ()
{
struct fn_decl *fn;
const char *cptr;
+ register struct symbol_list *cur_symbols;
if (required_unseen_count)
{
- fprintf (outf,
- "#if defined(__cplusplus) || defined(__USE_FIXED_PROTOTYPES__)\n");
#ifdef NO_IMPLICIT_EXTERN_C
fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
#endif
}
- /* Now we print out prototypes for those functions that we haven't seen. */
- for (cptr = required_functions_list; *cptr!= '\0'; )
+ /* Now we print out prototypes for those functions that we haven't seen. */
+ for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
{
- int macro_protect = 0;
- int name_len = strlen (cptr);
+ int if_was_emitted = 0;
+ int name_len;
+ cptr = cur_symbols->names;
+ for ( ; (name_len = strlen (cptr)) != 0; cptr+= name_len + 1)
+ {
+ int macro_protect = 0;
- fn = lookup_std_proto (cptr, name_len);
- cptr+= name_len + 1;
- if (fn == NULL || !REQUIRED (fn))
- continue;
+ if (cur_symbols->flags & MACRO_SYMBOL)
+ continue;
+
+ fn = lookup_std_proto (cptr, name_len);
+ if (fn == NULL || !REQUIRED (fn))
+ continue;
- /* In the case of memmove, protect in case the application
- defines it as a macro before including the header. */
- if (!strcmp (fn->fname, "memmove")
- || !strcmp (fn->fname, "vprintf")
- || !strcmp (fn->fname, "vfprintf")
- || !strcmp (fn->fname, "vsprintf")
- || !strcmp (fn->fname, "rewinddir"))
- macro_protect = 1;
-
- if (macro_protect)
- fprintf (outf, "#ifndef %s\n", fn->fname);
- fprintf (outf, "extern %s %s (%s);\n",
- fn->rtype, fn->fname, fn->params);
- if (macro_protect)
- fprintf (outf, "#endif\n");
+ if (!if_was_emitted)
+ {
+/* what about curses. ??? or _flsbuf/_filbuf ??? */
+ if (cur_symbols->flags & ANSI_SYMBOL)
+ fprintf (outf,
+ "#if defined(__USE_FIXED_PROTOTYPES__) || defined(__cplusplus) || defined (__STRICT_ANSI__)\n");
+ else if (cur_symbols->flags & (POSIX1_SYMBOL|POSIX2_SYMBOL))
+ fprintf (outf,
+ "#if defined(__USE_FIXED_PROTOTYPES__) || (defined(__cplusplus) \\\n\
+ ? (!defined(__STRICT_ANSI__) || defined(_POSIX_SOURCE)) \\\n\
+ : (defined(__STRICT_ANSI__) && defined(_POSIX_SOURCE)))\n");
+ else if (cur_symbols->flags & XOPEN_SYMBOL)
+ {
+ fprintf (outf,
+ "#if defined(__USE_FIXED_PROTOTYPES__) \\\n\
+ || (defined(__STRICT_ANSI__) && defined(_XOPEN_SOURCE))\n");
+ }
+ else if (cur_symbols->flags & XOPEN_EXTENDED_SYMBOL)
+ {
+ fprintf (outf,
+ "#if defined(__USE_FIXED_PROTOTYPES__) \\\n\
+ || (defined(__STRICT_ANSI__) && defined(_XOPEN_EXTENDED_SOURCE))\n");
+ }
+ else
+ {
+ fatal ("internal error for function %s", fn->fname);
+ }
+ if_was_emitted = 1;
+ }
+
+ /* In the case of memmove, protect in case the application
+ defines it as a macro before including the header. */
+ if (!strcmp (fn->fname, "memmove")
+ || !strcmp (fn->fname, "vprintf")
+ || !strcmp (fn->fname, "vfprintf")
+ || !strcmp (fn->fname, "vsprintf")
+ || !strcmp (fn->fname, "rewinddir")
+ || !strcmp (fn->fname, "abort"))
+ macro_protect = 1;
+
+ if (macro_protect)
+ fprintf (outf, "#ifndef %s\n", fn->fname);
+ fprintf (outf, "extern %s %s (%s);\n",
+ fn->rtype, fn->fname, fn->params);
+ if (macro_protect)
+ fprintf (outf, "#endif\n");
+ }
+ if (if_was_emitted)
+ fprintf (outf,
+ "#endif /* defined(__USE_FIXED_PROTOTYPES__) || ... */\n");
}
if (required_unseen_count)
{
#ifdef NO_IMPLICIT_EXTERN_C
fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
#endif
- fprintf (outf,
- "#endif /* defined(__cplusplus) || defined(__USE_FIXED_PROTOTYPES__*/\n");
}
switch (special_file_handling)
{
case errno_h:
- if (missing_errno)
+ if (!seen_errno)
fprintf (outf, "extern int errno;\n");
break;
+ case stdlib_h:
+ if (!seen_EXIT_FAILURE)
+ fprintf (outf, "#define EXIT_FAILURE 1\n");
+ if (!seen_EXIT_SUCCESS)
+ fprintf (outf, "#define EXIT_SUCCESS 0\n");
+ break;
case sys_stat_h:
if (!seen_S_ISBLK && seen_S_IFBLK)
fprintf (outf,
@@ -720,6 +864,9 @@ write_rbrac ()
fprintf (outf,
"#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n");
break;
+
+ default:
+ break;
}
@@ -745,7 +892,7 @@ xstrdup (str)
*/
-#define INF_GET() (inf_ptr < inf_limit ? *(unsigned char*)inf_ptr++ : EOF)
+#define INF_GET() (inf_ptr < inf_limit ? *(unsigned char *) inf_ptr++ : EOF)
#define INF_UNGET(c) ((c)!=EOF && inf_ptr--)
int
@@ -761,7 +908,7 @@ inf_skip_spaces (c)
c = INF_GET ();
if (c != '*')
{
- INF_UNGET (c);
+ (void) INF_UNGET (c);
return '/';
}
c = INF_GET ();
@@ -785,7 +932,7 @@ inf_skip_spaces (c)
return c;
}
-/* Read into STR from inf_buffer upto DELIM. */
+/* Read into STR from inf_buffer upto DELIM. */
int
inf_read_upto (str, delim)
@@ -811,13 +958,13 @@ inf_scan_ident (s, c)
int c;
{
s->ptr = s->base;
- if (isalpha (c) || c == '_')
+ if (ISALPHA (c) || c == '_')
{
for (;;)
{
SSTRING_PUT (s, c);
c = INF_GET ();
- if (c == EOF || !(isalnum (c) || c == '_'))
+ if (c == EOF || !(ISALNUM (c) || c == '_'))
break;
}
}
@@ -829,7 +976,7 @@ inf_scan_ident (s, c)
/* Returns 1 if the file is correctly protected against multiple
inclusion, setting *ifndef_line to the line number of the initial #ifndef
and setting *endif_line to the final #endif.
- Otherwise return 0. */
+ Otherwise return 0. */
int
check_protection (ifndef_line, endif_line)
@@ -840,7 +987,7 @@ check_protection (ifndef_line, endif_line)
char *protect_name = NULL; /* Identifier following initial #ifndef */
int define_seen = 0;
- /* Skip initial white space (including comments). */
+ /* Skip initial white space (including comments). */
for (;; lineno++)
{
c = inf_skip_spaces (' ');
@@ -855,14 +1002,14 @@ check_protection (ifndef_line, endif_line)
if (SSTRING_LENGTH (&buf) == 0 || strcmp (buf.base, "ifndef") != 0)
return 0;
- /* So far so good: We've seen an initial #ifndef. */
+ /* So far so good: We've seen an initial #ifndef. */
*ifndef_line = lineno;
c = inf_scan_ident (&buf, inf_skip_spaces (c));
if (SSTRING_LENGTH (&buf) == 0 || c == EOF)
return 0;
protect_name = xstrdup (buf.base);
- INF_UNGET (c);
+ (void) INF_UNGET (c);
c = inf_read_upto (&buf, '\n');
if (c == EOF)
return 0;
@@ -923,7 +1070,7 @@ check_protection (ifndef_line, endif_line)
if (!define_seen)
return 0;
*endif_line = lineno;
- /* Skip final white space (including comments). */
+ /* Skip final white space (including comments). */
for (;;)
{
c = inf_skip_spaces (' ');
@@ -944,12 +1091,15 @@ main (argc, argv)
int inf_fd;
struct stat sbuf;
int c;
- int i, done;
- const char *cptr, **pptr;
+#ifdef FIXPROTO_IGNORE_LIST
+ int i;
+#endif
+ const char *cptr;
int ifndef_line;
int endif_line;
long to_read;
long int inf_size;
+ register struct symbol_list *cur_symbols;
if (argv[0] && argv[0][0])
{
@@ -966,7 +1116,7 @@ main (argc, argv)
{
fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h options\n",
progname);
- exit (-1);
+ exit (FATAL_EXIT_CODE);
}
inc_filename = argv[1];
@@ -984,7 +1134,7 @@ main (argc, argv)
{
if (verbose)
fprintf (stderr, "%s: ignoring %s\n", progname, inc_filename);
- exit (0);
+ exit (SUCCESS_EXIT_CODE);
}
}
@@ -994,27 +1144,49 @@ main (argc, argv)
if (strcmp (inc_filename, "sys/stat.h") == 0)
special_file_handling = sys_stat_h;
else if (strcmp (inc_filename, "errno.h") == 0)
- special_file_handling = errno_h, missing_errno = 1;
+ special_file_handling = errno_h, required_other++;
+ else if (strcmp (inc_filename, "stdlib.h") == 0)
+ special_file_handling = stdlib_h, required_other+=2;
else if (strcmp (inc_filename, "stdio.h") == 0)
special_file_handling = stdio_h;
include_entry = std_include_table;
while (include_entry->name != NULL
- && strcmp (inc_filename, include_entry->name) != 0)
+ && (include_entry->name == CONTINUED
+ || strcmp (inc_filename, include_entry->name) != 0))
include_entry++;
- required_functions_list = include_entry->required;
+ if (include_entry->name != NULL)
+ {
+ struct std_include_entry *entry;
+ cur_symbol_table_size = 0;
+ for (entry = include_entry; ;)
+ {
+ if (entry->flags)
+ add_symbols (entry->flags, entry->names);
+ entry++;
+ if (entry->name != CONTINUED)
+ break;
+ }
+ }
+ else
+ symbol_table[0].names = NULL;
- /* Count and mark the prototypes required for this include file. */
- for (cptr = required_functions_list; *cptr!= '\0'; )
+ /* Count and mark the prototypes required for this include file. */
+ for (cur_symbols = &symbol_table[0]; cur_symbols->names; cur_symbols++)
{
- int name_len = strlen (cptr);
- struct fn_decl *fn = lookup_std_proto (cptr, name_len);
- required_unseen_count++;
- if (fn == NULL)
- fprintf (stderr, "Internal error: No prototype for %s\n", cptr);
- else
- SET_REQUIRED (fn);
- cptr += name_len + 1;
+ int name_len;
+ if (cur_symbols->flags & MACRO_SYMBOL)
+ continue;
+ cptr = cur_symbols->names;
+ for ( ; (name_len = strlen (cptr)) != 0; cptr+= name_len + 1)
+ {
+ struct fn_decl *fn = lookup_std_proto (cptr, name_len);
+ required_unseen_count++;
+ if (fn == NULL)
+ fprintf (stderr, "Internal error: No prototype for %s\n", cptr);
+ else
+ SET_REQUIRED (fn);
+ }
}
read_scan_file (argv[2], argc - 4, argv + 4);
@@ -1025,16 +1197,16 @@ main (argc, argv)
fprintf (stderr, "%s: Cannot open '%s' for reading -",
progname, argv[2]);
perror (NULL);
- exit (-1);
+ exit (FATAL_EXIT_CODE);
}
if (fstat (inf_fd, &sbuf) < 0)
{
fprintf (stderr, "%s: Cannot get size of '%s' -", progname, argv[2]);
perror (NULL);
- exit (-1);
+ exit (FATAL_EXIT_CODE);
}
inf_size = sbuf.st_size;
- inf_buffer = (char*) xmalloc (inf_size + 2);
+ inf_buffer = (char *) xmalloc (inf_size + 2);
inf_buffer[inf_size] = '\n';
inf_buffer[inf_size + 1] = '\0';
inf_limit = inf_buffer + inf_size;
@@ -1048,7 +1220,7 @@ main (argc, argv)
{
fprintf (stderr, "%s: Failed to read '%s' -", progname, argv[2]);
perror (NULL);
- exit (-1);
+ exit (FATAL_EXIT_CODE);
}
if (i == 0)
{
@@ -1060,7 +1232,7 @@ main (argc, argv)
close (inf_fd);
- /* If file doesn't end with '\n', add one. */
+ /* If file doesn't end with '\n', add one. */
if (inf_limit > inf_buffer && inf_limit[-1] != '\n')
inf_limit++;
@@ -1071,7 +1243,7 @@ main (argc, argv)
fprintf (stderr, "%s: Cannot open '%s' for writing -",
progname, argv[3]);
perror (NULL);
- exit (-1);
+ exit (FATAL_EXIT_CODE);
}
lineno = 1;
@@ -1087,7 +1259,7 @@ main (argc, argv)
rbrac_line = -1;
}
- /* Reset input file. */
+ /* Reset input file. */
inf_ptr = inf_buffer;
lineno = 1;
@@ -1103,15 +1275,15 @@ main (argc, argv)
c = INF_GET ();
if (c == EOF)
break;
- if (isalpha (c) || c == '_')
+ if (ISALPHA (c) || c == '_')
{
c = inf_scan_ident (&buf, c);
- INF_UNGET (c);
+ (void) INF_UNGET (c);
fputs (buf.base, outf);
fn = lookup_std_proto (buf.base, strlen (buf.base));
/* We only want to edit the declaration matching the one
seen by scan-decls, as there can be multiple
- declarations, selected by #ifdef __STDC__ or whatever. */
+ declarations, selected by #ifdef __STDC__ or whatever. */
if (fn && fn->partial && fn->partial->line_seen == lineno)
{
c = inf_skip_spaces (' ');
@@ -1127,7 +1299,7 @@ main (argc, argv)
else
{
putc ('(', outf);
- INF_UNGET (c);
+ (void) INF_UNGET (c);
}
}
else
@@ -1154,11 +1326,11 @@ main (argc, argv)
}
/* Stub error functions. These replace cpperror.c,
- because we want to suppress error messages. */
+ because we want to suppress error messages. */
void
cpp_file_line_for_message (pfile, filename, line, column)
- cpp_reader *pfile;
+ cpp_reader * pfile;
char *filename;
int line, column;
{
@@ -1172,41 +1344,107 @@ cpp_file_line_for_message (pfile, filename, line, column)
void
cpp_print_containing_files (pfile)
- cpp_reader *pfile;
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
{
}
-/* IS_ERROR is 1 for error, 0 for warning */
-void cpp_message (pfile, is_error, msg, arg1, arg2, arg3)
- int is_error;
+/* IS_ERROR is 2 for fatal error, 1 for error, 0 for warning */
+
+void
+v_cpp_message (pfile, is_error, msg, ap)
cpp_reader *pfile;
- char *msg;
- char *arg1, *arg2, *arg3;
+ int is_error;
+ const char *msg;
+ va_list ap;
{
- if (is_error)
+ if (is_error == 1)
pfile->errors++;
+ else if (is_error > 1)
+ pfile->errors = CPP_FATAL_LIMIT;
if (!verbose)
return;
if (!is_error)
fprintf (stderr, "warning: ");
- fprintf (stderr, msg, arg1, arg2, arg3);
+ vfprintf (stderr, msg, ap);
fprintf (stderr, "\n");
}
void
-fatal (str, arg)
- char *str, *arg;
+cpp_message VPROTO ((cpp_reader *pfile, int is_error, const char *msg, ...))
+{
+#ifndef __STDC__
+ cpp_reader *pfile;
+ int is_error;
+ const char *msg;
+#endif
+ va_list ap;
+
+ VA_START (ap, msg);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ is_error = va_arg (ap, const int);
+ msg = va_arg (ap, const char *);
+#endif
+
+ v_cpp_message(pfile, is_error, msg, ap);
+ va_end(ap);
+}
+
+static void
+v_fatal (str, ap)
+ const char * str;
+ va_list ap;
{
fprintf (stderr, "%s: %s: ", progname, inc_filename);
- fprintf (stderr, str, arg);
+ vfprintf (stderr, str, ap);
fprintf (stderr, "\n");
+
exit (FATAL_EXIT_CODE);
}
void
+fatal VPROTO ((const char *str, ...))
+{
+#ifndef __STDC__
+ const char *str;
+#endif
+ va_list ap;
+
+ VA_START(ap, str);
+
+#ifndef __STDC__
+ str = va_arg (ap, const char *);
+#endif
+
+ v_fatal(str, ap);
+ va_end(ap);
+}
+
+void
+cpp_fatal VPROTO ((cpp_reader * pfile, const char *str, ...))
+{
+#ifndef __STDC__
+ cpp_reader * pfile;
+ const char *str;
+#endif
+ va_list ap;
+
+ VA_START(ap, str);
+
+#ifndef __STDC__
+ pfile = va_arg (ap, cpp_reader *);
+ str = va_arg (ap, const char *);
+#endif
+
+ v_fatal(str, ap);
+ va_end(ap);
+}
+
+void
cpp_pfatal_with_name (pfile, name)
cpp_reader *pfile;
- char *name;
+ const char *name;
{
cpp_perror_with_name (pfile, name);
exit (FATAL_EXIT_CODE);
diff --git a/contrib/gcc/fixinc.ptx b/contrib/gcc/fixinc.ptx
index 031b8f4..93a8f2c 100644
--- a/contrib/gcc/fixinc.ptx
+++ b/contrib/gcc/fixinc.ptx
@@ -1,7 +1,7 @@
#! /bin/sh
# Install modified versions of certain ANSI-incompatible
# native Sequent DYNIX/ptx System V Release 3.2 system include files.
-# Copyright (C) 1994 Free Software Foundation, Inc.
+# Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
# Contributed by Bill Burton <billb@progress.com>
# Portions adapted from fixinc.svr4 and fixincludes.
#
@@ -125,11 +125,12 @@ if [ \! -z "$file_to_fix" ]; then
if grep stdio $file_to_fix > /dev/null; then
true
else
- sed -e '/#include \<sys\types\.h\>/a\
+ sed -e '/#include <sys\/types\.h>/a\
\
#if defined(__STDC__) || defined(__cplusplus)\
#include <stdio.h>\
-#endif /* __STDC__ */' \
+#endif /* __STDC__ */
+' \
$file_to_fix > ${LIB}/${file}.sed
rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
echo Fixed $file_to_fix
@@ -183,10 +184,69 @@ if [ \! -z "$file_to_fix" ]; then
\
#if defined (__GNUC__) || defined (__GNUG__)\
#include <sys/byteorder.h>\
-#else /* not __GNUC__ */\
+#else /* not __GNUC__ */
' \
-e '/#endif[ ]*\/\* NETSWAP \*\//i\
-#endif /* not __GNUC__ */' \
+#endif /* not __GNUC__ */
+' \
+ $file_to_fix > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ echo Fixed $file_to_fix
+ fi
+fi
+
+# /usr/include/sys/mc_param.h has an embedded asm for the cpuid instruction
+# on the P5. This is not used by anything else so we ifdef it out.
+file=sys/mc_param.h
+if [ -r ${LIB}/$file ]; then
+ file_to_fix=${LIB}/$file
+else
+ if [ -r ${INPUT}/$file ]; then
+ file_to_fix=${INPUT}/$file
+ else
+ file_to_fix=""
+ fi
+fi
+if [ \! -z "$file_to_fix" ]; then
+ echo Checking $file_to_fix
+ if grep __GNUC__ $file_to_fix > /dev/null; then
+ true
+ else
+ sed -e '/__asm/,/}/{
+/__asm/i\
+#if !defined (__GNUC__) && !defined (__GNUG__)
+/}/a\
+#endif
+}' \
+ $file_to_fix > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ echo Fixed $file_to_fix
+ fi
+fi
+
+# /usr/include/sys/mc_param.h has an embedded asm for the cpuid instruction
+# on the P5. This is not used by anything else so we ifdef it out.
+file=sys/mc_param.h
+if [ -r ${LIB}/$file ]; then
+ file_to_fix=${LIB}/$file
+else
+ if [ -r ${INPUT}/$file ]; then
+ file_to_fix=${INPUT}/$file
+ else
+ file_to_fix=""
+ fi
+fi
+if [ \! -z "$file_to_fix" ]; then
+ echo Checking $file_to_fix
+ if grep __GNUC__ $file_to_fix > /dev/null; then
+ true
+ else
+ sed -e '/__asm/,/}/{
+/__asm/i\
+#if !defined (__GNUC__) && !defined (__GNUG__)
+/}/a\
+#endif
+}' \
$file_to_fix > ${LIB}/${file}.sed
rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
echo Fixed $file_to_fix
diff --git a/contrib/gcc/fixinc.sco b/contrib/gcc/fixinc.sco
index b3301e1..5caaf7f 100755
--- a/contrib/gcc/fixinc.sco
+++ b/contrib/gcc/fixinc.sco
@@ -6,6 +6,8 @@
# Based on fixinc.svr4 script by Ron Guilmette (rfg@ncd.com) (SCO
# modifications by Ian Lance Taylor (ian@airs.com)).
#
+# Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
+#
# This file is part of GNU CC.
#
# GNU CC is free software; you can redistribute it and/or modify
@@ -169,6 +171,9 @@ while [ $# != 0 ]; do
shift; shift
done
+# We shouldn't stay in the directory we just copied.
+cd ${INPUT}
+
# Fix first broken decl of getcwd present on some svr4 systems.
file=stdlib.h
@@ -290,6 +295,113 @@ if [ -r ${LIB}/$file ]; then
fi
fi
+# This function is borrowed from fixinclude.svr4
+# The OpenServer math.h defines struct exception, which conflicts with
+# the class exception defined in the C++ file std/stdexcept.h. We
+# redefine it to __math_exception. This is not a great fix, but I
+# haven't been able to think of anything better.
+#
+# OpenServer's math.h declares abs as inline int abs... Unfortunately,
+# we blow over that one (with C++ linkage) and stick a new one in stdlib.h
+# with C linkage. So we eat the one out of math.h.
+file=math.h
+base=`basename $file`
+if [ -r ${LIB}/$file ]; then
+ file_to_fix=${LIB}/$file
+else
+ if [ -r ${INPUT}/$file ]; then
+ file_to_fix=${INPUT}/$file
+ else
+ file_to_fix=""
+ fi
+fi
+if [ \! -z "$file_to_fix" ]; then
+ echo Checking $file_to_fix
+ sed -e '/struct exception/i\
+#ifdef __cplusplus\
+#define exception __math_exception\
+#endif'\
+ -e '/struct exception/a\
+#ifdef __cplusplus\
+#undef exception\
+#endif' \
+ -e 's@inline int abs(int [a-z][a-z]*) {.*}@extern "C" int abs(int);@' \
+ $file_to_fix > /tmp/$base
+ if cmp $file_to_fix /tmp/$base >/dev/null 2>&1; then \
+ true
+ else
+ echo Fixed $file_to_fix
+ rm -f ${LIB}/$file
+ cp /tmp/$base ${LIB}/$file
+ chmod a+r ${LIB}/$file
+ fi
+ rm -f /tmp/$base
+fi
+
+#
+# Also, the static functions lstat() and fchmod() in <sys/stat.h>
+# cause G++ grief since they're not wrapped in "if __cplusplus".
+# Fix that up now.
+#
+file=sys/stat.h
+if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+fi
+
+if [ -r ${LIB}/$file ]; then
+ echo Fixing $file, static definitions not C++-aware.
+ sed -e '/^static int[ ]*/i\
+#if __cplusplus\
+extern "C"\
+{\
+#endif /* __cplusplus */ \
+' \
+-e '/^}$/a\
+#if __cplusplus\
+}\
+#endif /* __cplusplus */ \
+' ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ fi
+fi
+
+# This fix has the regex modified from the from fixinc.wrap
+# Avoid the definition of the bool type in the following files when using
+# g++, since it's now an official type in the C++ language.
+for file in term.h tinfo.h
+do
+ if [ -r $INPUT/$file ]; then
+ echo Checking $INPUT/$file
+ w='[ ]'
+ if grep "typedef$w.*char$w.*bool$w*;" $INPUT/$file >/dev/null
+ then
+ echo Fixed $file
+ rm -f $LIB/$file
+ cat << __EOF__ >$LIB/$file
+#ifndef _CURSES_H_WRAPPER
+#ifdef __cplusplus
+# define bool __curses_bool_t
+#endif
+#include_next <$file>
+#ifdef __cplusplus
+# undef bool
+#endif
+#define _CURSES_H_WRAPPER
+#endif /* _CURSES_H_WRAPPER */
+__EOF__
+ # Define _CURSES_H_WRAPPER at the end of the wrapper, not the start,
+ # so that if #include_next gets another instance of the wrapper,
+ # this will follow the #include_next chain until we arrive at
+ # the real system include file.
+ chmod a+r $LIB/$file
+ fi
+ fi
+done
+
echo 'Removing unneeded directories:'
cd $LIB
files=`find . -type d -print | sort -r`
diff --git a/contrib/gcc/fixinc.svr4 b/contrib/gcc/fixinc.svr4
index 582c6fb..46e07ce 100755
--- a/contrib/gcc/fixinc.svr4
+++ b/contrib/gcc/fixinc.svr4
@@ -1,9 +1,8 @@
#! /bin/sh
-#
-# fixinc.svr4 -- Install modified versions of certain ANSI-incompatible
-# native System V Release 4 system include files.
-#
-# Written by Ron Guilmette (rfg@ncd.com).
+# Install modified versions of certain ANSI-incompatible
+# native System V Release 4 system include files.
+# Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
+# Contributed by Ron Guilmette (rfg@monkeys.com).
#
# This file is part of GNU CC.
#
@@ -74,7 +73,7 @@ fi
echo 'Making directories:'
cd ${INPUT}
if $LINKS; then
- files=`ls -LR | sed -n s/:$//p`
+ files=`find . -follow -type d -print 2>/dev/null | sed '/^.$/d'`
else
files=`find . -type d -print | sed '/^.$/d'`
fi
@@ -99,6 +98,7 @@ if $LINKS; then
# In case $dest is relative, get to $file's dir first.
cd ${INPUT}
cd `echo ./$file | sed -n 's&[^/]*$&&p'`
+ rwd=`pwd`
# Check that the target directory exists.
# Redirections changed to avoid bug in sh on Ultrix.
(cd $dest) > /dev/null 2>&1
@@ -108,7 +108,11 @@ if $LINKS; then
x=`pwd`
# If link leads back into ${INPUT},
# make a similar link here.
- if expr $x : "${INPUT}/.*" > /dev/null; then
+ if expr "$dest" : '[^/][^/]*' >/dev/null && [ ! -h $dest ]; then
+ echo $file '->' $dest': Making link'
+ rm -fr ${LIB}/$file > /dev/null 2>&1
+ ln -s $dest ${LIB}/$file > /dev/null 2>&1
+ elif expr $x : "${INPUT}/.*" > /dev/null; then
# Y gets the actual target dir name, relative to ${INPUT}.
y=`echo $x | sed -n "s&${INPUT}/&&p"`
# DOTS is the relative path from ${LIB}/$file's dir back to ${LIB}.
@@ -117,6 +121,15 @@ if $LINKS; then
echo $file '->' $dots$y ': Making link'
rm -fr ${LIB}/$file > /dev/null 2>&1
ln -s $dots$y ${LIB}/$file > /dev/null 2>&1
+ elif expr $x : "${rwd}/.*" > /dev/null; then
+ # Y gets the actual target dir name, relative to the directory where the link is.
+ y=`echo $x | sed -n "s&${rwd}/&&p"`
+ # DOTS is the relative path from ${LIB}/$file's dir back to ${LIB}.
+ dots=`echo "$file" |
+ sed -e 's@^./@@' -e 's@/./@/@g' -e 's@[^/][^/]*@..@g' -e 's@..$@@'`
+ echo $file '->' $dots$y ': Making link'
+ rm -fr ${LIB}/$file > /dev/null 2>&1
+ ln -s $dots$y ${LIB}/$file > /dev/null 2>&1
else
# If the link is to outside ${INPUT},
# treat this directory as if it actually contained the files.
@@ -188,7 +201,9 @@ while [ $# != 0 ]; do
s/__STDC__[ ][ ]*==[ ][ ]*0/!defined (__STRICT_ANSI__)/g
s/__STDC__[ ][ ]*==[ ][ ]*1/defined (__STRICT_ANSI__)/g
s/__STDC__[ ][ ]*!=[ ][ ]*0/defined (__STRICT_ANSI__)/g
+ s/__STDC__[ ][ ]*!=[ ][ ]*1/!defined (__STRICT_ANSI__)/g
s/__STDC__ - 0 == 0/!defined (__STRICT_ANSI__)/g
+ s/__STDC__ - 0 == 1/defined (__STRICT_ANSI__)/g
/^typedef[ ][ ]*[unsigned ]*long[ ][ ]*[u_]*longlong_t;/s/long/long long/
' $2/$file > $2/$file.sed
mv $2/$file.sed $2/$file
@@ -475,14 +490,16 @@ else
static\
#else\
extern\
-#endif'\
+#endif
+'\
-e 's/extern \(int ftw(const.*\)$/\1/' \
-e '/^extern int nftw/i\
#if defined(_STYPES)\
static\
#else\
extern\
-#endif'\
+#endif
+'\
-e 's/extern \(int nftw.*\)$/\1/' \
-e '/^extern int ftw(),/c\
#if !defined(_STYPES)\
@@ -1028,9 +1045,11 @@ fi
# true
# else
# sed -e '/#ifdef INKERNEL/i\
-# #ifdef _KERNEL' \
+# #ifdef _KERNEL
+# ' \
# -e '/#endif[ ]*\/\* INKERNEL \*\//a\
-# #endif /* _KERNEL */' \
+# #endif /* _KERNEL */
+# ' \
# $file_to_fix > ${LIB}/${file}.sed
# rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
# echo Fixed $file_to_fix
@@ -1056,10 +1075,12 @@ if [ \! -z "$file_to_fix" ]; then
true
else
sed -e '/# ifdef __STDC__/i\
-# if !defined (__GNUC__) && !defined (__GNUG__)' \
+# if !defined (__GNUC__) && !defined (__GNUG__)
+' \
-e '/# include <sys\/byteorder.h>/s/ / /'\
-e '/# include <sys\/byteorder.h>/i\
-# endif /* !defined (__GNUC__) && !defined (__GNUG__) */'\
+# endif /* !defined (__GNUC__) && !defined (__GNUG__) */
+'\
$file_to_fix > ${LIB}/${file}.sed
rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
echo Fixed $file_to_fix
@@ -1335,29 +1356,41 @@ fi
if [ \! -z "$file_to_fix" ]; then
echo Checking $file_to_fix
sed -e '/[ ]FLT_MIN[ ]/i\
-#ifndef FLT_MIN'\
+#ifndef FLT_MIN
+'\
-e '/[ ]FLT_MIN[ ]/a\
-#endif'\
+#endif
+'\
-e '/[ ]FLT_MAX[ ]/i\
-#ifndef FLT_MAX'\
+#ifndef FLT_MAX
+'\
-e '/[ ]FLT_MAX[ ]/a\
-#endif'\
+#endif
+'\
-e '/[ ]FLT_DIG[ ]/i\
-#ifndef FLT_DIG'\
+#ifndef FLT_DIG
+'\
-e '/[ ]FLT_DIG[ ]/a\
-#endif'\
+#endif
+'\
-e '/[ ]DBL_MIN[ ]/i\
-#ifndef DBL_MIN'\
+#ifndef DBL_MIN
+'\
-e '/[ ]DBL_MIN[ ]/a\
-#endif'\
+#endif
+'\
-e '/[ ]DBL_MAX[ ]/i\
-#ifndef DBL_MAX'\
+#ifndef DBL_MAX
+'\
-e '/[ ]DBL_MAX[ ]/a\
-#endif'\
+#endif
+'\
-e '/[ ]DBL_DIG[ ]/i\
-#ifndef DBL_DIG'\
+#ifndef DBL_DIG
+'\
-e '/[ ]DBL_DIG[ ]/a\
-#endif' $file_to_fix > /tmp/$base
+#endif
+' $file_to_fix > /tmp/$base
if cmp $file_to_fix /tmp/$base >/dev/null 2>&1; then \
true
else
@@ -1408,9 +1441,11 @@ fi
if [ \! -z "$file_to_fix" ]; then
echo Checking $file_to_fix
sed -e '/define[ ]HUGE_VAL[ ]/i\
-#ifndef HUGE_VAL'\
+#ifndef HUGE_VAL
+'\
-e '/define[ ]HUGE_VAL[ ]/a\
-#endif' $file_to_fix > /tmp/$base
+#endif
+' $file_to_fix > /tmp/$base
if cmp $file_to_fix /tmp/$base >/dev/null 2>&1; then \
true
else
@@ -1439,9 +1474,11 @@ for file in math.h floatingpoint.h; do
if [ \! -z "$file_to_fix" ]; then
echo Checking $file_to_fix
sed -e '/^#define[ ]*__P/i\
-#ifndef __P'\
+#ifndef __P
+'\
-e '/^#define[ ]*__P/a\
-#endif' $file_to_fix > /tmp/$base
+#endif
+' $file_to_fix > /tmp/$base
if cmp $file_to_fix /tmp/$base >/dev/null 2>&1; then \
true
else
@@ -1454,6 +1491,42 @@ for file in math.h floatingpoint.h; do
fi
done
+# The Solaris math.h defines struct exception, which conflicts with
+# the class exception defined in the C++ file std/stdexcept.h. We
+# redefine it to __math_exception. This is not a great fix, but I
+# haven't been able to think of anything better.
+file=math.h
+base=`basename $file`
+if [ -r ${LIB}/$file ]; then
+ file_to_fix=${LIB}/$file
+else
+ if [ -r ${INPUT}/$file ]; then
+ file_to_fix=${INPUT}/$file
+ else
+ file_to_fix=""
+ fi
+fi
+if [ \! -z "$file_to_fix" ]; then
+ echo Checking $file_to_fix
+ sed -e '/struct exception/i\
+#ifdef __cplusplus\
+#define exception __math_exception\
+#endif'\
+ -e '/struct exception/a\
+#ifdef __cplusplus\
+#undef exception\
+#endif' $file_to_fix > /tmp/$base
+ if cmp $file_to_fix /tmp/$base >/dev/null 2>&1; then \
+ true
+ else
+ echo Fixed $file_to_fix
+ rm -f ${LIB}/$file
+ cp /tmp/$base ${LIB}/$file
+ chmod a+r ${LIB}/$file
+ fi
+ rm -f /tmp/$base
+fi
+
echo 'Removing unneeded directories:'
cd $LIB
files=`find . -type d -print | sort -r`
@@ -1468,7 +1541,7 @@ if $LINKS; then
for file in $files; do
dest=`ls -ld $file | sed -n 's/.*-> //p'`
if expr "$dest" : '[^/].*' > /dev/null; then
- target=${LIB}/`echo file | sed "s|[^/]*\$|$dest|"`
+ target=${LIB}/`echo $file | sed "s|[^/]*\$|$dest|"`
if [ -f $target ]; then
ln -s $dest ${LIB}/$file >/dev/null 2>&1
fi
diff --git a/contrib/gcc/fixincludes b/contrib/gcc/fixincludes
index cc8801d..09e10bb 100755
--- a/contrib/gcc/fixincludes
+++ b/contrib/gcc/fixincludes
@@ -12,6 +12,14 @@ INPUT=${2-${INPUT-/usr/include}}
# Directory in which to store the results.
LIB=${1?"fixincludes: output directory not specified"}
+# Define what target system we're fixing.
+if test -r ./Makefile; then
+ target_canonical="`sed -n -e 's,^target[ ]*=[ ]*\(.*\)$,\1,p' < Makefile`"
+ test -z "${target_canonical}" && target_canonical=unknown
+else
+ target_canonical=unknown
+fi
+
# Define PWDCMD as a command to use to get the working dir
# in the form that we want.
PWDCMD=pwd
@@ -75,14 +83,11 @@ do
for d in $dirs
do
echo " Searching $INPUT/$d"
- if [ "$d" != . ]
- then
- d=$d/.
- fi
# Find all directories under $d, relative to $d, excluding $d itself.
- files="$files `find $d -type d -print | \
- sed -e '/\/\.$/d' -e '/^\.$/d'`"
+ # (The /. is needed after $d in case $d is a symlink.)
+ files="$files `find $d/. -type d -print | \
+ sed -e '/\/\.$/d' -e 's@/./@/@g'`"
# Find all links to directories.
# Using `-exec test -d' in find fails on some systems,
# and trying to run test via sh fails on others,
@@ -90,7 +95,7 @@ do
# First find all the links, then test each one.
theselinks=
$LINKS && \
- theselinks=`find $d -type l -print`
+ theselinks=`find $d/. -type l -print | sed -e 's@/./@/@g'`
for d1 in $theselinks --dummy--
do
# If the link points to a directory,
@@ -185,7 +190,7 @@ if $LINKS; then
# root area.
for file2 in $files; do
case $file2 in
- $file/./*)
+ $file/*)
dupdir=${LIB}/root$x/`echo $file2 | sed -n "s|^${file}/||p"`
echo "Duplicating ${file}'s ${dupdir}"
if [ -d ${dupdir} ]
@@ -247,9 +252,10 @@ while [ $# != 0 ]; do
# But the argument to egrep must be kept small, or many versions of egrep
# won't be able to handle it.
#
-# We use the pattern [!-.0-~] instead of [^/ ] to match a noncomment
+# We use the pattern [!-.0-z{|}~] instead of [^/ ] to match a noncomment
# following #else or #endif because some buggy egreps think [^/] matches
# newline, and they thus think `#else ' matches `#e[ndiflse]*[ ]+[^/ ]'.
+# [!-.0-~] does not work properly on AIX 4.1.
#
# We use the pattern [^a-zA-Z0-9_][_a-ce-km-z][a-z0-9] to match an identifier
# following #if or #elif that is not surrounded by __. The `a-ce-km-z'
@@ -258,12 +264,14 @@ while [ $# != 0 ]; do
# identifiers below start with `d' or `l'. It also greatly improves
# performance, since many files contain lines of the form `#if ... defined ...'
# or `#if lint'.
- if egrep '//|[ _]_IO|CTRL|^#define.NULL|^#e[nl][ds][ief]*[ ]+[!-.0-~]|^#[el]*if.*[^a-zA-Z0-9_][_a-ce-km-zA-Z][a-zA-Z0-9]' $file >/dev/null; then
+ if egrep '//|[ _]_IO|CTRL|^#define.NULL|^#e[nl][ds][ief]*[ ]+[!-.0-z\{\|\}\~]|^#[el]*if.*[^a-zA-Z0-9_][_a-ce-km-zA-Z][a-zA-Z0-9]' $file >/dev/null; then
if [ -r $file ]; then
cp $file $2/$file >/dev/null 2>&1 \
|| echo "Can't copy $file"
chmod +w $2/$file
chmod a+r $2/$file
+ # The fixinc_eol stuff is to work around a bug in the sed
+ # program on HP/UX 10.20.
# Here is how the sed commands in braces work.
# (It doesn't work to put the comments inside the sed commands.)
# Surround each word with spaces, to simplify matching below.
@@ -273,22 +281,26 @@ while [ $# != 0 ]; do
sed -e '
:loop
/\\$/ N
+ s/\\$/\\*fixinc_eol*/
/\\$/ b loop
+ s/\\\*fixinc_eol\*/\\/g
s%^\([ ]*#[ ]*else\)[ ]*/[^*].*%\1%
s%^\([ ]*#[ ]*else\)[ ]*[^/ ].*%\1%
s%^\([ ]*#[ ]*endif\)[ ]*/[^*].*%\1%
s%^\([ ]*#[ ]*endif\)[ ]*\*[^/].*%\1%
s%^\([ ]*#[ ]*endif\)[ ]*[^/* ].*%\1%
/\/\/[^*]/ s|//\(.*\)$|/*\1*/|
+ /^[ ]*\/\/[ ]*/s///
/[ ]_IO[A-Z]*[ ]*(/ s/\(_IO[A-Z]*[ ]*(\)\(.\),/\1'\''\2'\'',/
/[ ]BSD43__IO[A-Z]*[ ]*(/ s/(\(.\),/('\''\1'\'',/
- /#define._IO/ s/'\''\([cgxtf]\)'\''/\1/g
- /#define.BSD43__IO/ s/'\''\([cgx]\)'\''/\1/g
+ /#[ ]*define[ ]*[ ]_IO/ s/'\''\([cgxtf]\)'\''/\1/g
+ /#[ ]*define[ ]*[ ]BSD43__IO/ s/'\''\([cgx]\)'\''/\1/g
+ /#[ ]*define[ ]*[ ]DESIOC/ s/'\''\([cdgx]\)'\''/\1/g
/[^A-Z0-9_]CTRL[ ]*(/ s/\([^'\'']\))/'\''\1'\'')/
/[^A-Z0-9]_CTRL[ ]*(/ s/\([^'\'']\))/'\''\1'\'')/
- /#define[ ]*[ ]CTRL/ s/'\''\([cgx]\)'\''/\1/g
- /#define[ ]*[ ]_CTRL/ s/'\''\([cgx]\)'\''/\1/g
- /#define.BSD43_CTRL/ s/'\''\([cgx]\)'\''/\1/g
+ /#[ ]*define[ ]*[ ]CTRL/ s/'\''\([cgx]\)'\''/\1/g
+ /#[ ]*define[ ]*[ ]_CTRL/ s/'\''\([cgx]\)'\''/\1/g
+ /#[ ]*define.BSD43_CTRL/ s/'\''\([cgx]\)'\''/\1/g
/#[ ]*[el]*if/{
s/[a-zA-Z0-9_][a-zA-Z0-9_]*/ & /g
@@ -356,6 +368,13 @@ for file in sys/types.h stdlib.h sys/stdtypes.h stddef.h memory.h unistd.h; do
if [ -r ${LIB}/$file ]; then
echo Fixing size_t, ptrdiff_t and wchar_t in $file
sed \
+ -e '/^[ ]*\*[ ]*typedef unsigned int size_t;/N' \
+ -e 's/^\([ ]*\*[ ]*typedef unsigned int size_t;\n[ ]*\*\/\)/\1\
+#ifndef __SIZE_TYPE__\
+#define __SIZE_TYPE__ long unsigned int\
+#endif\
+typedef __SIZE_TYPE__ size_t;\
+/' \
-e '/typedef[ ][ ]*[a-z_][ a-z_]*[ ]size_t/i\
#ifndef __SIZE_TYPE__\
#define __SIZE_TYPE__ long unsigned int\
@@ -392,6 +411,37 @@ for file in sys/types.h stdlib.h sys/stdtypes.h stddef.h memory.h unistd.h; do
fi
done
+# Fix #defines under Alpha OSF/1:
+# The following files contain '#pragma extern_prefix "_FOO"' followed by
+# a '#define something(x,y,z) _FOOsomething(x,y,z)'. The intent of these
+# statements is to reduce namespace pollution. While these macros work
+# properly in most cases, they don't allow you to take a pointer to the
+# "something" being modified. To get around this limitation, change these
+# statements to be of the form '#define something _FOOsomething'.
+for file in libgen.h dirent.h ftw.h grp.h ndbm.h pthread.h pwd.h signal.h standards.h stdlib.h string.h stropts.h time.h unistd.h
+do
+ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+ fi
+
+ if [ -r ${LIB}/$file ]; then
+ echo Fixing $file extern_prefix
+ sed -e 's/^[ ]*#[ ]*define[ ]*\([^(]*\)\(([^)]*)\)[ ]*\(_.\)\1\2[ ]*$/#define \1 \3\1/' ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+ fi
+done
+
# Fix one other error in this file: a mismatched quote not inside a C comment.
file=sundev/vuid_event.h
if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
@@ -905,17 +955,21 @@ fi
if [ -r ${LIB}/$file ]; then
echo Fixing $file
+ if grep _GCC_SIZE_T ${LIB}/$file >/dev/null
+ then size_t_pattern='<<< do not double-wrap the size_t typedef >>>'
+ else size_t_pattern='typedef[ a-zA-Z_]*[ ]size_t[ ]*;'
+ fi
sed -e 's/int abort/void abort/g' \
-e 's/int free/void free/g' \
-e 's/char[ ]*\*[ ]*calloc/void \* calloc/g' \
-e 's/char[ ]*\*[ ]*malloc/void \* malloc/g' \
-e 's/char[ ]*\*[ ]*realloc/void \* realloc/g' \
-e 's/int[ ][ ]*exit/void exit/g' \
- -e '/typedef[ a-zA-Z_]*[ ]size_t[ ]*;/i\
+ -e "/$size_t_pattern/"'i\
#ifndef _GCC_SIZE_T\
#define _GCC_SIZE_T
' \
- -e '/typedef[ a-zA-Z_]*[ ]size_t[ ]*;/a\
+ -e "/$size_t_pattern/"'a\
#endif
' \
${LIB}/$file > ${LIB}/${file}.sed
@@ -1112,6 +1166,60 @@ if [ -r ${LIB}/$file ]; then
fi
fi
+# And also with the HP-UX 10 and HP-UX 11 sys/pci.h file
+file=sys/pci.h
+if [ -r ${LIB}/$file ]; then
+ if egrep 'System Private Structures' ${LIB}/$file > /dev/null; then
+ echo Fixing $file, overeager sed script
+ rm ${LIB}/$file
+ sed -e 's|//.*$||g' $file > ${LIB}/$file
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+ fi
+fi
+
+# And also with a few more HP-UX 11 headers which are only broken
+# after they are "fixed".
+file=sys/ki_iface.h
+if [ -r ${LIB}/$file ]; then
+ if egrep 'These definitions are for HP Internal developers' ${LIB}/$file > /dev/null; then
+ echo Fixing $file, overeager sed script
+ rm ${LIB}/$file
+ fi
+fi
+
+file=sys/ki.h
+if [ -r ${LIB}/$file ]; then
+ if egrep '11.00 HP-UX LP64' ${LIB}/$file > /dev/null; then
+ echo Fixing $file, overeager sed script
+ rm ${LIB}/$file
+ fi
+fi
+
+file=sys/ki_calls.h
+if [ -r ${LIB}/$file ]; then
+ if egrep 'KI_MAX_PROCS is an arbitrary number' ${LIB}/$file > /dev/null; then
+ echo Fixing $file, overeager sed script
+ rm ${LIB}/$file
+ fi
+fi
+
+file=sys/ki_defs.h
+if [ -r ${LIB}/$file ] ; then
+ if egrep 'Kernel Instrumentation Definitions' ${LIB}/$file > /dev/null; then
+ echo Fixing $file, overeager sed script
+ rm ${LIB}/$file
+ fi
+fi
+
+file=sys/time.h
+if [ -r ${LIB}/$file ] ; then
+ if egrep 'For CASPEC, look in' ${LIB}/$file > /dev/null; then
+ echo Fixing $file, overeager sed script
+ rm ${LIB}/$file
+ fi
+fi
+
# Some IRIX header files contains the string "//"
for file in elf_abi.h elf.h; do
if [ -r ${LIB}/$file ]; then
@@ -1201,8 +1309,9 @@ fi
# declaration on Sun OS 4.x. We must only fix this on Sun OS 4.x, because
# many other systems have similar text but correct versions of the file.
# To ensure only Sun's is fixed, we grep for a likely unique string.
+# Fix also on sysV68 R3V7.1 (head/memory.h\t50.1\t )
file=memory.h
-if [ -r $file ] && egrep '/\* @\(#\)memory\.h 1\.[2-4] 8./../.. SMI; from S5R2 1\.2 \*/' $file > /dev/null; then
+if [ -r $file ] && egrep '/\* @\(#\)(head/memory.h 50.1 |memory\.h 1\.[2-4] 8./../.. SMI; from S5R2 1\.2 )\*/' $file > /dev/null; then
if [ ! -r ${LIB}/$file ]; then
cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
chmod +w ${LIB}/$file 2>/dev/null
@@ -1234,6 +1343,31 @@ EOF
fi
fi
+# Fix return type of fread and fwrite on sysV68
+file=stdio.h
+if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+fi
+
+if [ -r ${LIB}/$file ]; then
+ echo Fixing $file, fread and fwrite return type
+ sed -e 's/^\(extern int fclose(), fflush()\), \(fread(), fwrite()\)\(.*\)$/extern unsigned int \2;\
+\1\3/' \
+ ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+fi
+
# parameters not const on DECstation Ultrix V4.0 and OSF/1.
file=stdio.h
if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
@@ -1299,7 +1433,7 @@ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
fi
if [ -r ${LIB}/$file ]; then
- if grep 'class[(]' ${LIB}/$file >/dev/null; then
+ if grep '[^a-zA-Z_]class[(]' ${LIB}/$file >/dev/null; then
echo Fixing $file
sed -e '/class[(]/i\
#ifndef __cplusplus
@@ -1456,7 +1590,10 @@ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
fi
if [ -r ${LIB}/$file ]; then
echo Fixing $file
- sed -e '/^extern.*double.*__const__.*cos(/s/__const__//' \
+ sed -e '/^extern.*double.*__const__.*sqrt(/s/__const__//' \
+ -e '/^extern.*double.*__const__.*fabs(/s/__const__//' \
+ -e '/^extern.*double.*__const__.*cos(/s/__const__//' \
+ -e '/^extern.*double.*__const__.*hypot(/s/__const__//' \
-e '/^extern.*double.*__const__.*sin(/s/__const__//' ${LIB}/$file > ${LIB}/${file}.sed
rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
if cmp $file ${LIB}/$file >/dev/null 2>&1; then
@@ -1757,6 +1894,40 @@ if [ -r ${LIB}/$file ]; then
fi
fi
+# rpc/types.h on OSF1/2.0 is not C++ ready, even though NO_IMPLICIT_EXTERN_C
+# is defined for the alpha. The problem is the declaration of malloc.
+file=rpc/types.h
+if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ mkdir ${LIB}/rpc 2>/dev/null
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+fi
+if [ -r ${LIB}/$file ]; then
+ if egrep '"C"' ${LIB}/$file >/dev/null 2>&1; then
+ true
+ else
+ echo Fixing $file
+ echo '#ifdef __cplusplus
+extern "C" {
+#endif' > ${LIB}/${file}.sed
+ cat ${LIB}/${file} >> ${LIB}/${file}.sed
+ echo '#ifdef __cplusplus
+}
+#endif' >> ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+ fi
+fi
+
# In limits.h, put #ifndefs around things that are supposed to be defined
# in float.h to avoid redefinition errors if float.h is included first.
# On HP/UX this patch does not work, because on HP/UX limits.h uses
@@ -1764,6 +1935,7 @@ fi
# comment. Fortunately, HP/UX already uses #ifndefs in limits.h; if
# we find a #ifndef FLT_MIN we assume that all the required #ifndefs
# are there, and we do not add them ourselves.
+# Also fix a nested comment problem in sys/limits.h on Motorola sysV68 R3V7.1
for file in limits.h sys/limits.h; do
if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
mkdir ${LIB}/sys 2>/dev/null
@@ -1813,6 +1985,7 @@ for file in limits.h sys/limits.h; do
-e '/[ ]DBL_DIG[ ]/a\
#endif
'\
+ -e '/^\(\/\*#define HUGE_VAL 3\.[0-9e+]* *\)\/\*/s//\1/'\
${LIB}/$file > ${LIB}/${file}.sed
rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
fi
@@ -1906,6 +2079,7 @@ fi
# Correct the return type for strlen in string.h on Lynx.
# Correct the argument type for ffs in string.h on Alpha OSF/1 V2.0.
# Add missing const for strdup on OSF/1 V3.0.
+# On sysV88 layout is slightly different.
file=string.h
if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
@@ -1924,6 +2098,8 @@ if [ -r ${LIB}/$file ]; then
-e 's/^\( strncmp()\),\n\( strlen(),\)$/\1;\
extern unsigned int\
\2/'\
+ -e '/^extern int$/N'\
+ -e 's/^extern int\(\n strlen(),\)/extern size_t\1/' \
${LIB}/$file > ${LIB}/${file}.sed
rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
if cmp $file ${LIB}/$file >/dev/null 2>&1; then
@@ -2021,13 +2197,17 @@ for files in curses.h; do
echo Fixing $file
sed -e '/^#[ ]*define[ ][ ]*bool[ ][ ]*char[ ]*$/i\
-#ifndef __cplusplus'\
+#ifndef __cplusplus
+'\
-e '/^#[ ]*define[ ][ ]*bool[ ][ ]*char[ ]*$/a\
-#endif'\
+#endif
+'\
-e '/^typedef[ ][ ]*char[ ][ ]*bool[ ]*;/i\
-#ifndef __cplusplus'\
+#ifndef __cplusplus
+'\
-e '/^typedef[ ][ ]*char[ ][ ]*bool[ ]*;/a\
-#endif'\
+#endif
+'\
${LIB}/$file > ${LIB}/${file}.sed
rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
if cmp $file ${LIB}/$file >/dev/null 2>&1; then
@@ -2067,6 +2247,31 @@ if [ -r ${LIB}/$file ]; then
fi
fi
+# Fix nested comments in Motorola's <limits.h> and <sys/limits.h>
+for file in limits.h sys/limits.h; do
+ if [ $target_canonical = m88k-motorola-sysv3 -o \
+ $target_canonical = m68k-motorola-sysv ]; then
+
+ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+ fi
+
+ if [ -r ${LIB}/$file ]; then
+ echo "Fixing nested comments in Motorola's $file"
+ sed \
+ -e 's@^\(#undef[ ][ ]*PIPE_BUF[ ]*/\* max # bytes atomic in write to a\)$@\1 */@' \
+ -e 's@\(/\*#define HUGE_VAL 3.40282346638528860e+38 \)\(/\*error value returned by Math lib\*/\)$@\1*/ \2@' \
+ < ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ fi
+ fi
+ fi
+done
+
# Fix getopt declarations in stdio.h and stdlib.h on Alpha OSF/1 and AIX.
for file in stdio.h stdlib.h; do
if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
@@ -2092,6 +2297,33 @@ for file in stdio.h stdlib.h; do
fi
done
+# Fix __page_size* declarations in pthread.h AIX 4.1.[34].
+# The original ones fail if uninitialized externs are not common.
+# This is the default for all ANSI standard C++ compilers.
+for file in pthread.h; do
+ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+ fi
+
+ if [ -r ${LIB}/$file ]; then
+ echo Fixing $file, __page_size* declarations
+ sed -e 's/^int __page_size/extern int __page_size/' \
+ ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+ fi
+done
+
# Determine if we're on Interactive Unix 2.2 or later, in which case we
# need to fix some additional files. This is the same test for ISC that
# Autoconf uses.
@@ -2178,6 +2410,45 @@ do
fi
done
+# libm.a on m88k-motorola-sysv3 contains a stupid optimization for function
+# hypot(), which returns the second argument without even looking at its value
+# if the other is 0.0
+# Another drawback is that fix-header doesn't fix fabs' prototype, and I have
+# no idea why.
+file=math.h
+if [ $target_canonical = m88k-motorola-sysv3 ]; then
+ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+ fi
+
+ if [ -r ${LIB}/$file ]; then
+ echo Fixing $file, fabs/hypot definition
+ sed \
+ -e 's/extern double floor(), ceil(), fmod(), fabs();/extern double floor(), ceil(), fmod(), fabs _PARAMS((double));/' \
+ -e '/^extern double hypot();$/a\
+\/* Workaround a stupid Motorola optimization if one\
+ of x or y is 0.0 and the other is negative! *\/\
+#ifdef __STDC__\
+static __inline__ double fake_hypot (double x, double y)\
+#else\
+static __inline__ double fake_hypot (x, y)\
+ double x, y;\
+#endif\
+{\
+ return fabs (hypot (x, y));\
+}\
+#define hypot fake_hypot
+' \
+ ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ fi
+ fi
+fi
+
# math.h on SunOS 4 puts the declaration of matherr before the definition
# of struct exception, so the prototype (added by fixproto) causes havoc.
file=math.h
@@ -2206,43 +2477,44 @@ struct exception;
fi
fi
-# assert.h on HP/UX is not C++ ready, even though NO_IMPLICIT_EXTERN_C
-# is defined on HP/UX.
-file=assert.h
-if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
- cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
- chmod +w ${LIB}/$file 2>/dev/null
- chmod a+r ${LIB}/$file 2>/dev/null
-fi
+# sys/mman.h on HP/UX is not C++ ready, even though
+# NO_IMPLICIT_EXTERN_C is defined on HP/UX.
+for file in sys/mman.h; do
+ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+ fi
-if [ -r ${LIB}/$file ]; then
- if egrep '"C"' ${LIB}/$file >/dev/null 2>&1 \
- || egrep '__BEGIN_DECLS' ${LIB}/$file >/dev/null 2>&1; then
- true
- else
- echo Fixing $file
- echo '#ifdef __cplusplus
+ if [ -r ${LIB}/$file ]; then
+ if egrep '"C"' ${LIB}/$file >/dev/null 2>&1 \
+ || egrep '__BEGIN_DECLS' ${LIB}/$file >/dev/null 2>&1; then
+ true
+ else
+ echo Fixing $file
+ echo '#ifdef __cplusplus
extern "C" {
#endif' > ${LIB}/${file}.sed
- cat ${LIB}/${file} >> ${LIB}/${file}.sed
- echo '#ifdef __cplusplus
+ cat ${LIB}/${file} >> ${LIB}/${file}.sed
+ echo '#ifdef __cplusplus
}
#endif' >> ${LIB}/${file}.sed
- rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ fi
if cmp $file ${LIB}/$file >/dev/null 2>&1; then
rm -f ${LIB}/$file
else
# Find any include directives that use "file".
for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
- dir=`echo $file | sed -e s'|/[^/]*$||'`
- required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
done
fi
fi
-fi
+done
-# check for broken assert.h that needs stdio.h or stdlib.h
-file=assert.h
+# Fix return value of sbrk in unistd.h on Alpha OSF/1 V2.0
+file=unistd.h
if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
chmod +w ${LIB}/$file 2>/dev/null
@@ -2250,27 +2522,10 @@ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
fi
if [ -r ${LIB}/$file ]; then
- if grep 'stderr' ${LIB}/$file >/dev/null 2>/dev/null; then
- if grep 'include.*stdio.h' ${LIB}/$file >/dev/null 2>/dev/null; then
- true
- else
- echo "Fixing $file (needs stdio.h)"
- echo '#ifdef __cplusplus
-#include <stdio.h>
-#endif' >>${LIB}/$file
- fi
- fi
- if grep 'exit *(' ${LIB}/$file >/dev/null 2>/dev/null ||
- grep 'abort *(' ${LIB}/$file >/dev/null 2>/dev/null; then
- if grep 'include.*stdlib.h' ${LIB}/$file >/dev/null 2>/dev/null; then
- true
- else
- echo "Fixing $file (needs stdlib.h)"
- echo '#ifdef __cplusplus
-#include <stdlib.h>
-#endif' >>${LIB}/$file
- fi
- fi
+ echo Fixing $file, sbrk declaration
+ sed -e 's/char\([ ]*\*[ ]*sbrk[ ]*(\)/void\1/' \
+ ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
if cmp $file ${LIB}/$file >/dev/null 2>&1; then
rm -f ${LIB}/$file
else
@@ -2282,8 +2537,10 @@ if [ -r ${LIB}/$file ]; then
fi
fi
-# Fix return value of sbrk in unistd.h on Alpha OSF/1 V2.0
-file=unistd.h
+# Fix <c_asm.h> on Digital UNIX V4.0:
+# It contains a prototype for a DEC C internal asm() function, clashing with
+# gcc's asm keyword. So protect this with __DECC.
+file=c_asm.h
if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
chmod +w ${LIB}/$file 2>/dev/null
@@ -2291,12 +2548,16 @@ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
fi
if [ -r ${LIB}/$file ]; then
- echo Fixing $file, sbrk declaration
- sed -e 's/char\([ ]*\*[ ]*sbrk[ ]*(\)/void\1/' \
- ${LIB}/$file > ${LIB}/${file}.sed
+ echo Fixing $file
+ sed -e '/^[ ]*float[ ]*fasm/i\
+#ifdef __DECC
+' \
+ -e '/^[ ]*#[ ]*pragma[ ]*intrinsic([ ]*dasm/a\
+#endif
+' ${LIB}/$file > ${LIB}/${file}.sed
rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
if cmp $file ${LIB}/$file >/dev/null 2>&1; then
- rm -f ${LIB}/$file
+ rm ${LIB}/$file
else
# Find any include directives that use "file".
for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
@@ -2492,6 +2753,375 @@ if [ -r ${LIB}/$file ]; then
fi
fi
+# Fix hpux10.20 <sys/time.h> to avoid invalid forward decl
+file=sys/time.h
+if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ mkdir ${LIB}/sys 2>/dev/null
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+fi
+
+if [ -r ${LIB}/$file ]; then
+ if egrep '^extern struct sigevent;' ${LIB}/$file >/dev/null 2>&1; then
+ echo Fixing $file
+ sed -e 's/^extern struct sigevent;/struct sigevent;/' ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ fi
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+fi
+
+# Another bad dependency in VxWorks 5.2 <time.h>.
+file=time.h
+if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ mkdir ${LIB}/sys 2>/dev/null
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+fi
+
+if [ -r ${LIB}/$file ]; then
+ if egrep VOIDFUNCPTR ${LIB}/$file >/dev/null 2>&1; then
+ if [ -r vxWorks.h ]; then
+ echo Fixing $file
+ sed -e '/VOIDFUNCPTR/i\
+#ifndef __gcc_VOIDFUNCPTR_defined\
+#ifdef __cplusplus\
+typedef void (*__gcc_VOIDFUNCPTR) (...);\
+#else\
+typedef void (*__gcc_VOIDFUNCPTR) ();\
+#endif\
+#define __gcc_VOIDFUNCPTR_defined\
+#endif
+' \
+ -e 's/VOIDFUNCPTR/__gcc_VOIDFUNCPTR/g' \
+ ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ fi
+ fi
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+fi
+
+# This file in A/UX 3.0.x/3.1.x contains an __asm directive for c89; gcc
+# doesn't understand it.
+file=sys/param.h
+if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+fi
+
+if [ -r ${LIB}/$file ]; then
+ echo "Fixing __asm directive in sys/param.h"
+ sed -e 's|#ifndef NOINLINE|#if !defined(NOINLINE) \&\& !defined(__GNUC__)|' \
+ ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+fi
+
+# signal.h on SunOS defines signal using (), which causes trouble when
+# compiling with g++ -pedantic.
+for file in signal.h sys/signal.h; do
+ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+ fi
+
+ if [ -r ${LIB}/$file ]; then
+ echo "Checking for bad C++ prototype in $file"
+ sed -e '/^void (\*signal())();$/i\
+ #ifdef __cplusplus\
+ void (*signal(...))(...);\
+ #else
+ ' \
+ -e '/^void (\*signal())();$/a\
+ #endif
+ ' \
+ ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+ fi
+done
+
+# sys/signal.h on some versions of AIX uses volatile in the typedef of
+# sig_atomic_t, which causes gcc to generate a warning about duplicate
+# volatile when a sig_atomic_t variable is declared volatile, as
+# required by ANSI C.
+file=sys/signal.h
+if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+fi
+
+if [ -r ${LIB}/$file ]; then
+ echo "Checking for duplicate volatile in sys/signal.h"
+ sed -e 's/typedef volatile int sig_atomic_t/typedef int sig_atomic_t/' \
+ ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+fi
+
+# Some math.h files define struct exception, which conflicts with
+# the class exception defined in the C++ file std/stdexcept.h. We
+# redefine it to __math_exception. This is not a great fix, but I
+# haven't been able to think of anything better.
+file=math.h
+if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+fi
+
+if [ -r ${LIB}/$file ]; then
+ echo Fixing $file, exception
+ sed -e '/struct exception/i\
+#ifdef __cplusplus\
+#define exception __math_exception\
+#endif
+'\
+ -e '/struct exception/a\
+#ifdef __cplusplus\
+#undef exception\
+#endif
+' ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if egrep 'matherr()' ${LIB}/$file >/dev/null 2>&1; then
+ sed -e '/matherr/i\
+#ifdef __cplusplus\
+#define exception __math_exception\
+#endif
+'\
+ -e '/matherr/a\
+#ifdef __cplusplus\
+#undef exception\
+#endif
+' ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ fi
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+fi
+
+# rpc/auth.h on SunOS needs prototypes for its AUTH->auth_ops function pointers
+# Similarly for
+# rpc/clnt.h CLIENT->clnt_ops
+# rpc/svc.h SVCXPRT->xp_ops
+# rpc/xdr.h XDR->xdr_ops
+for file in rpc/auth.h rpc/clnt.h rpc/svc.h rpc/xdr.h; do
+ # each file has a different name to replace, so if you add a file to
+ # that list please update the following case statement.
+ case "$file" in
+ rpc/auth.h)
+ prefix="ah_"
+ ;;
+ rpc/clnt.h)
+ prefix="cl_"
+ ;;
+ rpc/svc.h)
+ prefix="xp_"
+ ;;
+ rpc/xdr.h)
+ prefix="x_"
+ ;;
+ *)
+ # Oh Oh, we shouldn't be here
+ exit 1;
+ ;;
+ esac
+
+ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+ fi
+
+ if [ -r ${LIB}/$file ]; then
+ echo "Checking for needed C++ prototype in $file"
+ sed -e 's/^\(.*\)\*\('$prefix'.*\)();\(.*\)/\
+#ifdef __cplusplus\
+\1*\2(...);\3\
+#else\
+\1*\2();\3\
+#endif/g' \
+ $LIB/$file > ${LIB}/${file}.sed
+
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+ fi
+done
+
+# sys/lc_core.h on some versions of OSF1/4.x pollutes the namespace by
+# defining regex.h types. This causes C++ library build and usage failures.
+# Fixing this correctly requires checking and modifying 3 files.
+for file in reg_types.h regex.h sys/lc_core.h; do
+ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+ fi
+done
+if [ -r ${LIB}/reg_types.h ]; then
+ if egrep '} regex_t;' ${LIB}/reg_types.h >/dev/null 2>&1; then
+ if [ -r ${LIB}/sys/lc_core.h ]; then
+ if egrep ' regex_t ' ${LIB}/sys/lc_core.h >/dev/null 2>&1; then
+ if [ -r ${LIB}/regex.h ]; then
+ if egrep '__regex_t' ${LIB}/regex.h >/dev/null 2>&1; then
+ true;
+ else
+ echo Fixing reg_types.h, regex.h, sys/lc_core.h
+ for file in reg_types.h sys/lc_core.h; do
+ sed -e 's/regex_t/__regex_t/g' \
+ -e 's/regoff_t/__regoff_t/g' \
+ -e 's/regmatch_t/__regmatch_t/g' \
+ ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ done
+ sed -e '/#include <reg_types.h>/a\
+typedef __regex_t regex_t;\
+typedef __regoff_t regoff_t;\
+typedef __regmatch_t regmatch_t;\
+' \
+ ${LIB}/regex.h > ${LIB}/regex.h.sed
+ rm -f ${LIB}/regex.h; mv ${LIB}/regex.h.sed ${LIB}/regex.h
+ fi
+ fi
+ fi
+ fi
+ fi
+fi
+for file in reg_types.h regex.h sys/lc_core.h; do
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+done
+
+# AIX headers define NULL to be cast to a void pointer, which is illegal
+# in ANSI C++.
+for file in curses.h dbm.h locale.h stdio.h stdlib.h string.h time.h unistd.h sys/dir.h sys/param.h sys/types.h ; do
+ if [ -r $file ] && [ ! -r ${LIB}/$file ]; then
+ cp $file ${LIB}/$file >/dev/null 2>&1 || echo "Can't copy $file"
+ chmod +w ${LIB}/$file 2>/dev/null
+ chmod a+r ${LIB}/$file 2>/dev/null
+ fi
+
+ if [ -r ${LIB}/$file ]; then
+ if egrep '#.*define.*NULL.*void' ${LIB}/$file >/dev/null 2>&1; then
+ echo "Fixing $file, bad NULL macro"
+ sed -e 's/^#[ ]*define[ ]*NULL[ ]*((void[ ]*\*)0)/#define NULL 0/' \
+ ${LIB}/$file > ${LIB}/${file}.sed
+ rm -f ${LIB}/$file; mv ${LIB}/${file}.sed ${LIB}/$file
+ if cmp $file ${LIB}/$file >/dev/null 2>&1; then
+ rm -f ${LIB}/$file
+ else
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+ fi
+ fi
+done
+
+# HPUX 10.x sys/param.h defines MAXINT which clashes with values.h
+file=sys/param.h
+base=`basename $file`
+if [ -r ${LIB}/$file ]; then
+ file_to_fix=${LIB}/$file
+else
+ if [ -r ${INPUT}/$file ]; then
+ file_to_fix=${INPUT}/$file
+ else
+ file_to_fix=""
+ fi
+fi
+if [ \! -z "$file_to_fix" ]; then
+ echo Checking $file_to_fix
+ sed -e '/^#[ ]*define[ ]*MAXINT[ ]/i\
+#ifndef MAXINT
+'\
+ -e '/^#[ ]*define[ ]*MAXINT[ ]/a\
+#endif
+' $file_to_fix > /tmp/$base
+ if cmp $file_to_fix /tmp/$base >/dev/null 2>&1; then \
+ true
+ else
+ echo Fixed $file_to_fix
+ rm -f ${LIB}/$file
+ cp /tmp/$base ${LIB}/$file
+ chmod a+r ${LIB}/$file
+ # Find any include directives that use "file".
+ for include in `egrep '^[ ]*#[ ]*include[ ]*"[^/]' ${LIB}/$file | sed -e 's/^[ ]*#[ ]*include[ ]*"\([^"]*\)".*$/\1/'`; do
+ dir=`echo $file | sed -e s'|/[^/]*$||'`
+ required="$required ${INPUT} $dir/$include ${LIB}/$dir/$include"
+ done
+ fi
+ rm -f /tmp/$base
+fi
+
# This loop does not appear to do anything, because it uses file
# rather than $file when setting target. It also appears to be
@@ -2552,4 +3182,5 @@ for file in $files; do
rmdir $LIB/$file > /dev/null 2>&1
done
+
exit 0
diff --git a/contrib/gcc/fixproto b/contrib/gcc/fixproto
index 79c8dfc..cd495e6 100755
--- a/contrib/gcc/fixproto
+++ b/contrib/gcc/fixproto
@@ -65,7 +65,7 @@ if [ `echo $1 | wc -w` = 0 ] ; then
exit 1
fi
-std_files="ctype.h dirent.h errno.h curses.h fcntl.h grp.h locale.h math.h pwd.h setjmp.h signal.h stdio.h stdlib.h string.h sys/stat.h sys/times.h sys/resource.h sys/utsname.h sys/wait.h tar.h termios.h time.h unistd.h"
+std_files="ctype.h dirent.h errno.h curses.h fcntl.h grp.h locale.h math.h pwd.h setjmp.h signal.h stdio.h stdlib.h string.h sys/socket.h sys/stat.h sys/times.h sys/resource.h sys/utsname.h sys/wait.h tar.h termios.h time.h unistd.h utime.h"
rel_target_dir=$1
# All files in $src_dir_all (normally same as $rel_target_dir) are
@@ -120,6 +120,7 @@ required_stdlib_h="abort abs atexit atof atoi atol bsearch calloc exit free gete
required_unistd_h="_exit access alarm chdir chown close ctermid cuserid dup dup2 execl execle execlp execv execve execvp fork fpathconf getcwd getegid geteuid getgid getlogin getopt getpgrp getpid getppid getuid isatty link lseek pathconf pause pipe read rmdir setgid setpgid setsid setuid sleep sysconf tcgetpgrp tcsetpgrp ttyname unlink write"
done_dirs=""
+subdirs_made=""
echo "" >fixproto.list
for code in ALL STD ; do
@@ -142,7 +143,7 @@ for code in ALL STD ; do
# for C++, so skip those.
subdirs="$subdirs "`cd $rel_source_dir/$d; find . -type d -print | \
sed -e '/^\.$/d' -e "s|^\./|${d}/|" -e 's|^\./||' \
- -e '/CC$/d' -e '/\+\+/d'`
+ -e '/CC$/d' -e '/[+][+]/d'`
links=
links=`cd $rel_source_dir; find $d/. -type l -print | \
sed -e "s|$d/./|$d/|" -e 's|^\./||'`
@@ -174,7 +175,9 @@ for code in ALL STD ; do
abs_target_subdir=${abs_target_dir}/${rel_source_subdir}
if [ \! -d $abs_target_subdir ] ; then
- mkdir $abs_target_subdir
+ if mkdir $abs_target_subdir ; then
+ subdirs_made="$abs_target_subdir $subdirs_made"
+ fi
fi
# Append "/"; remove initial "./". Hence "." -> "" and "sys" -> "sys/".
rel_source_prefix=`echo $rel_source_subdir | sed -e 's|$|/|' -e 's|^./||'`
@@ -199,7 +202,9 @@ for code in ALL STD ; do
# Create the dir where this file will go when fixed.
xxdir=`echo ./$file | sed -e 's|/[^/]*$||'`
if [ \! -d $abs_target_subdir/$xxdir ] ; then
- mkdir $abs_target_subdir/$xxdir
+ if mkdir $abs_target_subdir/$xxdir ; then
+ subdirs_made="$abs_target_subdir/$xxdir $subdirs_made"
+ fi
fi
# Just in case we have edited out a symbolic link
if [ -f $src_dir_std/$file -a -f $src_dir_std/$xxfile ] ; then
@@ -262,12 +267,28 @@ do
rel_source_ident=`echo $rel_source_file | tr ./ __`
required_list=`eval echo '${required_'${rel_source_ident}'-}'`
cat >tmp.h <<EOF
-#ifndef ${rel_source_ident}
-#define ${rel_source_ident}
-#endif
+#ifndef __${rel_source_ident}
+#define __${rel_source_ident}
+EOF
+ if test $rel_source_file = stdlib.h
+ then
+ # Make sure it contains a definition of size_t.
+ cat >>tmp.h <<EOF
+
+#define __need_size_t
+#include <stddef.h>
+EOF
+ fi
+ cat >>tmp.h <<EOF
+
+#endif /* __${rel_source_ident} */
EOF
${FIX_HEADER} $rel_source_file tmp.h $abs_target_dir/$rel_source_file ${DEFINES} $include_path
rm tmp.h
fi
done
+
+# Remove any directories that we made that are still empty.
+rmdir $subdirs_made 2>/dev/null
+
exit 0
diff --git a/contrib/gcc/flags.h b/contrib/gcc/flags.h
index ed1cf57..9fa976b 100644
--- a/contrib/gcc/flags.h
+++ b/contrib/gcc/flags.h
@@ -1,5 +1,5 @@
/* Compilation switch flag definitions for GNU CC.
- Copyright (C) 1987, 1988, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -27,6 +27,7 @@ enum debug_info_type
DBX_DEBUG, /* Write BSD .stabs for DBX (using dbxout.c). */
SDB_DEBUG, /* Write COFF for (old) SDB (using sdbout.c). */
DWARF_DEBUG, /* Write Dwarf debug info (using dwarfout.c). */
+ DWARF2_DEBUG, /* Write Dwarf v2 debug info (using dwarf2out.c). */
XCOFF_DEBUG /* Write IBM/Xcoff debug info (using dbxout.c). */
};
@@ -52,6 +53,10 @@ extern int use_gnu_debug_info_extensions;
extern int optimize;
+/* Nonzero means optimize for size. -Os. */
+
+extern int optimize_size;
+
/* Nonzero means do stupid register allocation. -noreg.
Currently, this is 1 if `optimize' is 0. */
@@ -82,6 +87,14 @@ extern int warn_inline;
extern int warn_uninitialized;
+/* Zero if unknown pragmas are ignored
+ One if the compiler should warn about an unknown pragma not in
+ a system include file.
+ Greater than one if the compiler should warn for all unknown
+ pragmas. */
+
+extern int warn_unknown_pragmas;
+
/* Nonzero means warn about all declarations which shadow others. */
extern int warn_shadow;
@@ -132,6 +145,18 @@ extern int profile_flag;
extern int profile_block_flag;
+/* Nonzero if generating code to profile program flow graph arcs. */
+
+extern int profile_arc_flag;
+
+/* Nonzero if generating info for gcov to calculate line test coverage. */
+
+extern int flag_test_coverage;
+
+/* Nonzero indicates that branch taken probabilities should be calculated. */
+
+extern int flag_branch_probabilities;
+
/* Nonzero for -pedantic switch: warn about anything
that standard C forbids. */
@@ -203,6 +228,16 @@ extern int flag_unroll_loops;
extern int flag_unroll_all_loops;
+/* Nonzero forces all invariant computations in loops to be moved
+ outside the loop. */
+
+extern int flag_move_all_movables;
+
+/* Nonzero forces all general induction variables in loops to be
+ strength reduced. */
+
+extern int flag_reduce_all_givs;
+
/* Nonzero for -fcse-follow-jumps:
have cse follow jumps to do a more extensive job. */
@@ -252,6 +287,15 @@ extern int flag_volatile_global;
extern int flag_fast_math;
+/* Nonzero means to run loop optimizations twice. */
+
+extern int flag_rerun_loop_opt;
+
+/* Nonzero means to assume that a structure or an array reference at
+ a varying address cannot alias a scalar at a fixed address. */
+
+extern int flag_structure_noalias;
+
/* Nonzero means make functions that look like good inline candidates
go inline. */
@@ -291,13 +335,31 @@ extern int flag_shared_data;
extern int flag_schedule_insns;
extern int flag_schedule_insns_after_reload;
-/* Nonzero means put things in delayed-branch slots if supported. */
+#ifdef HAIFA
+/* The following flags have effect only for scheduling before register
+ allocation:
-extern int flag_delayed_branch;
+ flag_schedule_interblock means schedule insns accross basic blocks.
+ flag_schedule_speculative means allow speculative motion of non-load insns.
+ flag_schedule_speculative_load means allow speculative motion of some
+ load insns.
+ flag_schedule_speculative_load_dangerous allows speculative motion of more
+ load insns. */
+
+extern int flag_schedule_interblock;
+extern int flag_schedule_speculative;
+extern int flag_schedule_speculative_load;
+extern int flag_schedule_speculative_load_dangerous;
+
+/* flag_on_branch_count_reg means try to replace add-1,compare,branch tupple
+ by a cheaper branch, on a count register. */
+extern int flag_branch_on_count_reg;
+#endif /* HAIFA */
-/* Nonzero means to run cleanups after CALL_EXPRs. */
-extern int flag_short_temps;
+/* Nonzero means put things in delayed-branch slots if supported. */
+
+extern int flag_delayed_branch;
/* Nonzero means pretend it is OK to examine bits of target floats,
even if that isn't true. The resulting code will have incorrect constants,
@@ -315,7 +377,18 @@ extern int flag_pedantic_errors;
extern int flag_pic;
-/* Nonzero means place uninitialized global data in the bss section. */
+/* Nonzero means generate extra code for exception handling and enable
+ exception handling. */
+
+extern int flag_exceptions;
+
+/* Nonzero means use the new model for exception handling. Replaces
+ -DNEW_EH_MODEL as a compile option. */
+
+extern int flag_new_exceptions;
+
+/* Nonzero means don't place uninitialized global data in common storage
+ by default. */
extern int flag_no_common;
@@ -325,19 +398,57 @@ extern int flag_no_common;
needed for crtstuff.c on other systems. */
extern int flag_inhibit_size_directive;
+/* Nonzero means place each function into its own section on those platforms
+ which support arbitrary section names and unlimited numbers of sections. */
+
+extern int flag_function_sections;
+
/* -fverbose-asm causes extra commentary information to be produced in
the generated assembly code (to make it more readable). This option
is generally only of use to those who actually need to read the
- generated assembly code (perhaps while debugging the compiler itself). */
+ generated assembly code (perhaps while debugging the compiler itself).
+ -fno-verbose-asm, the default, causes the extra information
+ to not be added and is useful when comparing two assembler files. */
extern int flag_verbose_asm;
+/* -dA causes debug information to be produced in
+ the generated assembly code (to make it more readable). This option
+ is generally only of use to those who actually need to read the
+ generated assembly code (perhaps while debugging the compiler itself).
+ Currently, this switch is only used by dwarfout.c; however, it is intended
+ to be a catchall for printing debug information in the assembler file. */
+
+extern int flag_debug_asm;
+
/* -fgnu-linker specifies use of the GNU linker for initializations.
-fno-gnu-linker says that collect will be used. */
extern int flag_gnu_linker;
/* Tag all structures with __attribute__(packed) */
extern int flag_pack_struct;
+
+/* This flag is only tested if alias checking is enabled.
+ 0 if pointer arguments may alias each other. True in C.
+ 1 if pointer arguments may not alias each other but may alias
+ global variables.
+ 2 if pointer arguments may not alias each other and may not
+ alias global variables. True in Fortran.
+ The value is ignored if flag_alias_check is 0. */
+extern int flag_argument_noalias;
+
+/* Nonzero if we should do (language-dependent) alias analysis.
+ Typically, this analysis will assume that expressions of certain
+ types do not alias expressions of certain other types. Only used
+ if alias analysis (in general) is enabled. */
+extern int flag_strict_aliasing;
+
+/* Emit code to check for stack overflow; also may cause large objects
+ to be allocated dynamically. */
+extern int flag_stack_check;
+
+/* Do the full regmove optimization pass. */
+extern int flag_regmove;
/* Other basic status info about current function. */
@@ -361,3 +472,26 @@ extern int current_function_has_nonlocal_label;
function. */
extern int current_function_has_nonlocal_goto;
+
+/* Nonzero if this function has a computed goto.
+
+ It is computed during find_basic_blocks or during stupid life
+ analysis. */
+
+extern int current_function_has_computed_jump;
+
+/* Nonzero if GCC must add code to check memory access (used by Checker). */
+
+extern int flag_check_memory_usage;
+
+/* Nonzero if GCC must prefix function names (used with
+ flag_check_memory_usage). */
+
+extern int flag_prefix_function_name;
+/* Nonzero if the current function is a thunk, so we should try to cut
+ corners where we can. */
+extern int current_function_is_thunk;
+
+/* Value of the -G xx switch, and whether it was passed or not. */
+extern int g_switch_value;
+extern int g_switch_set;
diff --git a/contrib/gcc/floatlib.c b/contrib/gcc/floatlib.c
index 2e20d70..e9e9dea 100644
--- a/contrib/gcc/floatlib.c
+++ b/contrib/gcc/floatlib.c
@@ -54,6 +54,7 @@ If you'd like to work on completing this, please talk to rms@gnu.ai.mit.edu.
*/
/* the following deal with IEEE single-precision numbers */
+#define D_PHANTOM_BIT 0x00100000
#define EXCESS 126
#define SIGNBIT 0x80000000
#define HIDDEN (1 << 23)
@@ -93,7 +94,38 @@ union float_long
long l;
};
+ struct _ieee {
+#ifdef SWAP
+ unsigned mantissa2 : 32;
+ unsigned mantissa1 : 20;
+ unsigned exponent : 11;
+ unsigned sign : 1;
+#else
+ unsigned exponent : 11;
+ unsigned sign : 1;
+ unsigned mantissa2 : 32;
+ unsigned mantissa1 : 20;
+#endif
+ };
+
+ union _doubleu {
+ double d;
+ struct _ieee ieee;
+#ifdef SWAP
+ struct {
+ unsigned long lower;
+ long upper;
+ } l;
+#else
+ struct {
+ long upper;
+ unsigned long lower;
+ } l;
+#endif
+ };
+
/* add two floats */
+
float
__addsf3 (float a1, float a2)
{
@@ -183,6 +215,7 @@ __addsf3 (float a1, float a2)
}
/* subtract two floats */
+
float
__subsf3 (float a1, float a2)
{
@@ -203,6 +236,7 @@ __subsf3 (float a1, float a2)
}
/* compare two floats */
+
long
__cmpsf2 (float a1, float a2)
{
@@ -224,6 +258,7 @@ __cmpsf2 (float a1, float a2)
}
/* multiply two floats */
+
float
__mulsf3 (float a1, float a2)
{
@@ -273,6 +308,7 @@ __mulsf3 (float a1, float a2)
}
/* divide two floats */
+
float
__divsf3 (float a1, float a2)
{
@@ -339,6 +375,7 @@ __divsf3 (float a1, float a2)
}
/* convert int to double */
+
double
__floatsidf (register long a1)
{
@@ -379,6 +416,7 @@ __floatsidf (register long a1)
}
/* negate a float */
+
float
__negsf2 (float a1)
{
@@ -393,6 +431,7 @@ __negsf2 (float a1)
}
/* negate a double */
+
double
__negdf2 (double a1)
{
@@ -408,6 +447,7 @@ __negdf2 (double a1)
}
/* convert float to double */
+
double
__extendsfdf2 (float a1)
{
@@ -433,6 +473,7 @@ __extendsfdf2 (float a1)
}
/* convert double to float */
+
float
__truncdfsf2 (double a1)
{
@@ -470,6 +511,7 @@ __truncdfsf2 (double a1)
}
/* compare two doubles */
+
long
__cmpdf2 (double a1, double a2)
{
@@ -495,6 +537,7 @@ __cmpdf2 (double a1, double a2)
}
/* convert double to int */
+
long
__fixdfsi (double a1)
{
@@ -523,6 +566,7 @@ __fixdfsi (double a1)
}
/* convert double to unsigned int */
+
unsigned
long __fixunsdfsi (double a1)
{
@@ -553,6 +597,7 @@ long __fixunsdfsi (double a1)
/* For now, the hard double-precision routines simply
punt and do it in single */
/* addtwo doubles */
+
double
__adddf3 (double a1, double a2)
{
@@ -560,6 +605,7 @@ __adddf3 (double a1, double a2)
}
/* subtract two doubles */
+
double
__subdf3 (double a1, double a2)
{
@@ -567,15 +613,226 @@ __subdf3 (double a1, double a2)
}
/* multiply two doubles */
+
double
__muldf3 (double a1, double a2)
{
return ((float) a1 * (float) a2);
}
+/*
+ *
+ * Name: Barrett Richardson
+ * E-mail: barrett@iglou.com
+ * When: Thu Dec 15 10:31:11 EST 1994
+ *
+ * callable function:
+ *
+ * double __divdf3(double a1, double a2);
+ *
+ * Does software divide of a1 / a2.
+ *
+ * Based largely on __divsf3() in floatlib.c in the gcc
+ * distribution.
+ *
+ * Purpose: To be used in conjunction with the -msoft-float
+ * option of gcc. You should be able to tack it to the
+ * end of floatlib.c included in the gcc distribution,
+ * and delete the __divdf3() already there which just
+ * calls the single precision function (or may just
+ * use the floating point processor with some configurations).
+ *
+ * You may use this code for whatever your heart desires.
+ */
+
+
+
+
+/*
+ * Compare the mantissas of two doubles.
+ * Each mantissa is in two longs.
+ *
+ * return 1 if x1's mantissa is greater than x2's
+ * -1 if x1's mantissa is less than x2's
+ * 0 if the two mantissa's are equal.
+ *
+ * The Mantissas won't fit into a 4 byte word, so they are
+ * broken up into two parts.
+ *
+ * This function is used internally by __divdf3()
+ */
+
+int
+__dcmp (long x1m1, long x1m2, long x2m1, long x2m2)
+{
+ if (x1m1 > x2m1)
+ return 1;
+
+ if (x1m1 < x2m1)
+ return -1;
+
+ /* If the first word in the two mantissas were equal check the second word */
+
+ if (x1m2 > x2m2)
+ return 1;
+
+ if (x1m2 < x2m2)
+ return -1;
+
+ return 0;
+}
+
+
/* divide two doubles */
+
double
__divdf3 (double a1, double a2)
{
- return ((float) a1 / (float) a2);
+
+ int sign,
+ exponent,
+ bit_bucket;
+
+ register unsigned long mantissa1,
+ mantissa2,
+ x1m1,
+ x1m2,
+ x2m1,
+ x2m2,
+ mask;
+
+ union _doubleu x1,
+ x2,
+ result;
+
+
+ x1.d = a1;
+ x2.d = a2;
+
+ exponent = x1.ieee.exponent - x2.ieee.exponent + EXCESSD;
+
+ sign = x1.ieee.sign ^ x2.ieee.sign;
+
+ x2.ieee.sign = 0; /* don't want the sign bit to affect any zero */
+ /* comparisons when checking for zero divide */
+
+ if (!x2.l.lower && !x2.l.upper) { /* check for zero divide */
+ result.l.lower = 0x0;
+ if (sign)
+ result.l.upper = 0xFFF00000; /* negative infinity */
+ else
+ result.l.upper = 0x7FF00000; /* positive infinity */
+ return result.d;
+ }
+
+ if (!x1.l.upper && !x1.l.lower) /* check for 0.0 numerator */
+ return (0.0);
+
+ x1m1 = x1.ieee.mantissa1 | D_PHANTOM_BIT; /* turn on phantom bit */
+ x1m2 = x1.ieee.mantissa2;
+
+ x2m1 = x2.ieee.mantissa1 | D_PHANTOM_BIT; /* turn on phantom bit */
+ x2m2 = x2.ieee.mantissa2;
+
+ if (__dcmp(x1m1,x1m2,x2m1,x2m2) < 0) {
+
+ /* if x1's mantissa is less than x2's shift it left one and decrement */
+ /* the exponent to accommodate the change in the mantissa */
+
+ x1m1 <<= 1; /* */
+ bit_bucket = x1m2 >> 31; /* Shift mantissa left one */
+ x1m1 |= bit_bucket; /* */
+ x1m2 <<= 1; /* */
+
+ exponent--;
+ }
+
+
+ mantissa1 = 0;
+ mantissa2 = 0;
+
+
+ /* Get the first part of the results mantissa using successive */
+ /* subtraction. */
+
+ mask = 0x00200000;
+ while (mask) {
+
+ if (__dcmp(x1m1,x1m2,x2m1,x2m2) >= 0) {
+
+ /* subtract x2's mantissa from x1's */
+
+ mantissa1 |= mask; /* turn on a bit in the result */
+
+ if (x2m2 > x1m2)
+ x1m1--;
+ x1m2 -= x2m2;
+ x1m1 -= x2m1;
+ }
+
+ x1m1 <<= 1; /* */
+ bit_bucket = x1m2 >> 31; /* Shift mantissa left one */
+ x1m1 |= bit_bucket; /* */
+ x1m2 <<= 1; /* */
+
+ mask >>= 1;
+ }
+
+ /* Get the second part of the results mantissa using successive */
+ /* subtraction. */
+
+ mask = 0x80000000;
+ while (mask) {
+
+ if (__dcmp(x1m1,x1m2,x2m1,x2m2) >= 0) {
+
+ /* subtract x2's mantissa from x1's */
+
+ mantissa2 |= mask; /* turn on a bit in the result */
+
+ if (x2m2 > x1m2)
+ x1m1--;
+ x1m2 -= x2m2;
+ x1m1 -= x2m1;
+ }
+ x1m1 <<= 1; /* */
+ bit_bucket = x1m2 >> 31; /* Shift mantissa left one */
+ x1m1 |= bit_bucket; /* */
+ x1m2 <<= 1; /* */
+
+ mask >>= 1;
+ }
+
+ /* round up by adding 1 to mantissa */
+
+ if (mantissa2 == 0xFFFFFFFF) { /* check for over flow */
+
+ /* spill if overflow */
+
+ mantissa2 = 0;
+ mantissa1++;
+ }
+ else
+ mantissa2++;
+
+ exponent++; /* increment exponent (mantissa must be shifted right */
+ /* also) */
+
+ /* shift mantissa right one and assume a phantom bit (which really gives */
+ /* 53 bits of precision in the mantissa) */
+
+ mantissa2 >>= 1;
+ bit_bucket = mantissa1 & 1;
+ mantissa2 |= (bit_bucket << 31);
+ mantissa1 >>= 1;
+
+ /* put all the info into the result */
+
+ result.ieee.exponent = exponent;
+ result.ieee.sign = sign;
+ result.ieee.mantissa1 = mantissa1;
+ result.ieee.mantissa2 = mantissa2;
+
+
+ return result.d;
}
diff --git a/contrib/gcc/flow.c b/contrib/gcc/flow.c
index 1e4ff88..43ea11d 100644
--- a/contrib/gcc/flow.c
+++ b/contrib/gcc/flow.c
@@ -1,5 +1,5 @@
/* Data flow analysis for GNU compiler.
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -108,8 +108,8 @@ Boston, MA 02111-1307, USA. */
register usage: reg_n_refs, reg_n_deaths, reg_n_sets, reg_live_length,
reg_n_calls_crosses and reg_basic_block. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "basic-block.h"
#include "insn-config.h"
@@ -117,11 +117,20 @@ Boston, MA 02111-1307, USA. */
#include "hard-reg-set.h"
#include "flags.h"
#include "output.h"
+#include "except.h"
+#include "toplev.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
+/* The contents of the current function definition are allocated
+ in this obstack, and all are freed at the end of the function.
+ For top-level functions, this is temporary_obstack.
+ Separate obstacks are made for nested functions. */
+
+extern struct obstack *function_obstack;
+
/* List of labels that must never be deleted. */
extern rtx forced_labels;
@@ -139,7 +148,7 @@ static int max_uid_for_flow;
This is set up by find_basic_blocks and used there and in life_analysis,
and then freed. */
-static int *uid_block_number;
+int *uid_block_number;
/* INSN_VOLATILE (insn) is 1 if the insn refers to anything volatile. */
@@ -154,7 +163,8 @@ int n_basic_blocks;
int max_regno;
-/* Maximum number of SCRATCH rtx's used in any basic block of this function. */
+/* Maximum number of SCRATCH rtx's used in any basic block of this
+ function. */
int max_scratch;
@@ -162,56 +172,13 @@ int max_scratch;
static int num_scratch;
-/* Indexed by n, gives number of basic block that (REG n) is used in.
- If the value is REG_BLOCK_GLOBAL (-2),
- it means (REG n) is used in more than one basic block.
- REG_BLOCK_UNKNOWN (-1) means it hasn't been seen yet so we don't know.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation. */
-
-int *reg_basic_block;
-
-/* Indexed by n, gives number of times (REG n) is used or set, each
- weighted by its loop-depth.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation. */
-
-int *reg_n_refs;
-
-/* Indexed by N; says whether a pseudo register N was ever used
- within a SUBREG that changes the size of the reg. Some machines prohibit
- such objects to be in certain (usually floating-point) registers. */
-
-char *reg_changes_size;
-
-/* Indexed by N, gives number of places register N dies.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation. */
-
-short *reg_n_deaths;
-
-/* Indexed by N, gives 1 if that reg is live across any CALL_INSNs.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation. */
-
-int *reg_n_calls_crossed;
-
-/* Total number of instructions at which (REG n) is live.
- The larger this is, the less priority (REG n) gets for
- allocation in a real register.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation.
+/* Indexed by n, giving various register information */
- local-alloc.c may alter this number to change the priority.
+varray_type reg_n_info;
- Negative values are special.
- -1 is used to mark a pseudo reg which has a constant or memory equivalent
- and is used infrequently enough that it should not get a hard register.
- -2 is used to mark a pseudo reg for a parameter, when a frame pointer
- is not required. global.c makes an allocno for this but does
- not try to assign a hard register to it. */
+/* Size of the reg_n_info table. */
-int *reg_live_length;
+unsigned int reg_n_max;
/* Element N is the next insn that uses (hard or pseudo) register number N
within the current basic block; or zero, if there is no such insn.
@@ -235,6 +202,11 @@ rtx *basic_block_head;
rtx *basic_block_end;
+/* Element N indicates whether basic block N can be reached through a
+ computed jump. */
+
+char *basic_block_computed_jump_target;
+
/* Element N is a regset describing the registers live
at the start of basic block N.
This info lasts until we finish compiling the function. */
@@ -286,12 +258,9 @@ static rtx last_mem_set;
static HARD_REG_SET elim_reg_set;
/* Forward declarations */
-static void find_basic_blocks PROTO((rtx, rtx));
-static int uses_reg_or_mem PROTO((rtx));
+static void find_basic_blocks_1 PROTO((rtx, rtx, int));
static void mark_label_ref PROTO((rtx, rtx, int));
-static void life_analysis PROTO((rtx, int));
-void allocate_for_life_analysis PROTO((void));
-static void init_regset_vector PROTO((regset *, regset, int, int));
+static void life_analysis_1 PROTO((rtx, int));
static void propagate_block PROTO((regset, rtx, rtx, int,
regset, int));
static rtx flow_delete_insn PROTO((rtx));
@@ -301,53 +270,60 @@ static void mark_set_regs PROTO((regset, regset, rtx,
rtx, regset));
static void mark_set_1 PROTO((regset, regset, rtx,
rtx, regset));
+#ifdef AUTO_INC_DEC
static void find_auto_inc PROTO((regset, rtx, rtx));
-static void mark_used_regs PROTO((regset, regset, rtx, int, rtx));
static int try_pre_increment_1 PROTO((rtx));
static int try_pre_increment PROTO((rtx, rtx, HOST_WIDE_INT));
-static rtx find_use_as_address PROTO((rtx, rtx, HOST_WIDE_INT));
+#endif
+static void mark_used_regs PROTO((regset, regset, rtx, int, rtx));
void dump_flow_info PROTO((FILE *));
+static void add_pred_succ PROTO ((int, int, int_list_ptr *,
+ int_list_ptr *, int *, int *));
+static int_list_ptr alloc_int_list_node PROTO ((int_list_block **));
+static int_list_ptr add_int_list_node PROTO ((int_list_block **,
+ int_list **, int));
+static void init_regset_vector PROTO ((regset *, int,
+ struct obstack *));
+static void count_reg_sets_1 PROTO ((rtx));
+static void count_reg_sets PROTO ((rtx));
+static void count_reg_references PROTO ((rtx));
-/* Find basic blocks of the current function and perform data flow analysis.
+/* Find basic blocks of the current function.
F is the first insn of the function and NREGS the number of register numbers
- in use. */
+ in use.
+ LIVE_REACHABLE_P is non-zero if the caller needs all live blocks to
+ be reachable. This turns on a kludge that causes the control flow
+ information to be inaccurate and not suitable for passes like GCSE. */
void
-flow_analysis (f, nregs, file)
+find_basic_blocks (f, nregs, file, live_reachable_p)
rtx f;
int nregs;
FILE *file;
+ int live_reachable_p;
{
register rtx insn;
register int i;
rtx nonlocal_label_list = nonlocal_label_rtx_list ();
-
-#ifdef ELIMINABLE_REGS
- static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
-#endif
-
- /* Record which registers will be eliminated. We use this in
- mark_used_regs. */
-
- CLEAR_HARD_REG_SET (elim_reg_set);
-
-#ifdef ELIMINABLE_REGS
- for (i = 0; i < sizeof eliminables / sizeof eliminables[0]; i++)
- SET_HARD_REG_BIT (elim_reg_set, eliminables[i].from);
-#else
- SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
-#endif
+ int in_libcall_block = 0;
/* Count the basic blocks. Also find maximum insn uid value used. */
{
register RTX_CODE prev_code = JUMP_INSN;
register RTX_CODE code;
+ int eh_region = 0;
max_uid_for_flow = 0;
for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
{
+
+ /* Track when we are inside in LIBCALL block. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ in_libcall_block = 1;
+
code = GET_CODE (insn);
if (INSN_UID (insn) > max_uid_for_flow)
max_uid_for_flow = INSN_UID (insn);
@@ -355,72 +331,98 @@ flow_analysis (f, nregs, file)
|| (GET_RTX_CLASS (code) == 'i'
&& (prev_code == JUMP_INSN
|| (prev_code == CALL_INSN
- && nonlocal_label_list != 0)
+ && (nonlocal_label_list != 0 || eh_region)
+ && ! in_libcall_block)
|| prev_code == BARRIER)))
i++;
+
+ if (code == CALL_INSN && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ code = INSN;
+
if (code != NOTE)
prev_code = code;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+ ++eh_region;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+ --eh_region;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ in_libcall_block = 0;
}
}
+ n_basic_blocks = i;
+
#ifdef AUTO_INC_DEC
- /* Leave space for insns we make in some cases for auto-inc. These cases
- are rare, so we don't need too much space. */
+ /* Leave space for insns life_analysis makes in some cases for auto-inc.
+ These cases are rare, so we don't need too much space. */
max_uid_for_flow += max_uid_for_flow / 10;
#endif
/* Allocate some tables that last till end of compiling this function
and some needed only in find_basic_blocks and life_analysis. */
- n_basic_blocks = i;
- basic_block_head = (rtx *) oballoc (n_basic_blocks * sizeof (rtx));
- basic_block_end = (rtx *) oballoc (n_basic_blocks * sizeof (rtx));
- basic_block_drops_in = (char *) alloca (n_basic_blocks);
- basic_block_loop_depth = (short *) alloca (n_basic_blocks * sizeof (short));
+ basic_block_head = (rtx *) xmalloc (n_basic_blocks * sizeof (rtx));
+ basic_block_end = (rtx *) xmalloc (n_basic_blocks * sizeof (rtx));
+ basic_block_drops_in = (char *) xmalloc (n_basic_blocks);
+ basic_block_computed_jump_target = (char *) oballoc (n_basic_blocks);
+ basic_block_loop_depth = (short *) xmalloc (n_basic_blocks * sizeof (short));
uid_block_number
- = (int *) alloca ((max_uid_for_flow + 1) * sizeof (int));
- uid_volatile = (char *) alloca (max_uid_for_flow + 1);
+ = (int *) xmalloc ((max_uid_for_flow + 1) * sizeof (int));
+ uid_volatile = (char *) xmalloc (max_uid_for_flow + 1);
bzero (uid_volatile, max_uid_for_flow + 1);
- find_basic_blocks (f, nonlocal_label_list);
- life_analysis (f, nregs);
- if (file)
- dump_flow_info (file);
-
- basic_block_drops_in = 0;
- uid_block_number = 0;
- basic_block_loop_depth = 0;
+ find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p);
}
-
+
/* Find all basic blocks of the function whose first insn is F.
Store the correct data in the tables that describe the basic blocks,
set up the chains of references for each CODE_LABEL, and
delete any entire basic blocks that cannot be reached.
- NONLOCAL_LABEL_LIST is the same local variable from flow_analysis. */
+ NONLOCAL_LABEL_LIST is a list of non-local labels in the function.
+ Blocks that are otherwise unreachable may be reachable with a non-local
+ goto.
+ LIVE_REACHABLE_P is non-zero if the caller needs all live blocks to
+ be reachable. This turns on a kludge that causes the control flow
+ information to be inaccurate and not suitable for passes like GCSE. */
static void
-find_basic_blocks (f, nonlocal_label_list)
+find_basic_blocks_1 (f, nonlocal_label_list, live_reachable_p)
rtx f, nonlocal_label_list;
+ int live_reachable_p;
{
register rtx insn;
register int i;
register char *block_live = (char *) alloca (n_basic_blocks);
register char *block_marked = (char *) alloca (n_basic_blocks);
+ /* An array of CODE_LABELs, indexed by UID for the start of the active
+ EH handler for each insn in F. */
+ int *active_eh_region;
+ int *nested_eh_region;
/* List of label_refs to all labels whose addresses are taken
and used as data. */
rtx label_value_list;
- rtx x, note;
+ rtx x, note, eh_note;
enum rtx_code prev_code, code;
int depth, pass;
+ int in_libcall_block = 0;
+ int deleted_handler = 0;
pass = 1;
+ active_eh_region = (int *) alloca ((max_uid_for_flow + 1) * sizeof (int));
+ nested_eh_region = (int *) alloca ((max_label_num () + 1) * sizeof (int));
restart:
label_value_list = 0;
block_live_static = block_live;
bzero (block_live, n_basic_blocks);
bzero (block_marked, n_basic_blocks);
+ bzero (basic_block_computed_jump_target, n_basic_blocks);
+ bzero ((char *) active_eh_region, (max_uid_for_flow + 1) * sizeof (int));
+ bzero ((char *) nested_eh_region, (max_label_num () + 1) * sizeof (int));
+ current_function_has_computed_jump = 0;
/* Initialize with just block 0 reachable and no blocks marked. */
if (n_basic_blocks > 0)
@@ -431,9 +433,15 @@ find_basic_blocks (f, nonlocal_label_list)
the block it is in. Also mark as reachable any blocks headed by labels
that must not be deleted. */
- for (insn = f, i = -1, prev_code = JUMP_INSN, depth = 1;
+ for (eh_note = NULL_RTX, insn = f, i = -1, prev_code = JUMP_INSN, depth = 1;
insn; insn = NEXT_INSN (insn))
{
+
+ /* Track when we are inside in LIBCALL block. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ in_libcall_block = 1;
+
code = GET_CODE (insn);
if (code == NOTE)
{
@@ -448,7 +456,8 @@ find_basic_blocks (f, nonlocal_label_list)
|| (GET_RTX_CLASS (code) == 'i'
&& (prev_code == JUMP_INSN
|| (prev_code == CALL_INSN
- && nonlocal_label_list != 0)
+ && (nonlocal_label_list != 0 || eh_note)
+ && ! in_libcall_block)
|| prev_code == BARRIER)))
{
basic_block_head[++i] = insn;
@@ -476,14 +485,45 @@ find_basic_blocks (f, nonlocal_label_list)
/* Make a list of all labels referred to other than by jumps. */
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_LABEL)
- label_value_list = gen_rtx (EXPR_LIST, VOIDmode, XEXP (note, 0),
- label_value_list);
+ label_value_list = gen_rtx_EXPR_LIST (VOIDmode, XEXP (note, 0),
+ label_value_list);
}
+ /* Keep a lifo list of the currently active exception notes. */
+ if (GET_CODE (insn) == NOTE)
+ {
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+ {
+ if (eh_note)
+ nested_eh_region [NOTE_BLOCK_NUMBER (insn)] =
+ NOTE_BLOCK_NUMBER (XEXP (eh_note, 0));
+ else
+ nested_eh_region [NOTE_BLOCK_NUMBER (insn)] = 0;
+ eh_note = gen_rtx_EXPR_LIST (VOIDmode,
+ insn, eh_note);
+ }
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+ eh_note = XEXP (eh_note, 1);
+ }
+ /* If we encounter a CALL_INSN, note which exception handler it
+ might pass control to.
+
+ If doing asynchronous exceptions, record the active EH handler
+ for every insn, since most insns can throw. */
+ else if (eh_note
+ && (asynchronous_exceptions
+ || (GET_CODE (insn) == CALL_INSN
+ && ! in_libcall_block)))
+ active_eh_region[INSN_UID (insn)] =
+ NOTE_BLOCK_NUMBER (XEXP (eh_note, 0));
BLOCK_NUM (insn) = i;
if (code != NOTE)
prev_code = code;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ in_libcall_block = 0;
}
/* During the second pass, `n_basic_blocks' is only an upper bound.
@@ -493,17 +533,6 @@ find_basic_blocks (f, nonlocal_label_list)
abort ();
n_basic_blocks = i + 1;
- /* Don't delete the labels (in this function)
- that are referenced by non-jump instructions. */
-
- for (x = label_value_list; x; x = XEXP (x, 1))
- if (! LABEL_REF_NONLOCAL_P (x))
- block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
-
- for (x = forced_labels; x; x = XEXP (x, 1))
- if (! LABEL_REF_NONLOCAL_P (x))
- block_live[BLOCK_NUM (XEXP (x, 0))] = 1;
-
/* Record which basic blocks control can drop in to. */
for (i = 0; i < n_basic_blocks; i++)
@@ -524,76 +553,6 @@ find_basic_blocks (f, nonlocal_label_list)
int something_marked = 1;
int deleted;
- /* Find all indirect jump insns and mark them as possibly jumping to all
- the labels whose addresses are explicitly used. This is because,
- when there are computed gotos, we can't tell which labels they jump
- to, of all the possibilities.
-
- Tablejumps and casesi insns are OK and we can recognize them by
- a (use (label_ref)). */
-
- for (insn = f; insn; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == JUMP_INSN)
- {
- rtx pat = PATTERN (insn);
- int computed_jump = 0;
-
- if (GET_CODE (pat) == PARALLEL)
- {
- int len = XVECLEN (pat, 0);
- int has_use_labelref = 0;
-
- for (i = len - 1; i >= 0; i--)
- if (GET_CODE (XVECEXP (pat, 0, i)) == USE
- && (GET_CODE (XEXP (XVECEXP (pat, 0, i), 0))
- == LABEL_REF))
- has_use_labelref = 1;
-
- if (! has_use_labelref)
- for (i = len - 1; i >= 0; i--)
- if (GET_CODE (XVECEXP (pat, 0, i)) == SET
- && SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx
- && uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))
- computed_jump = 1;
- }
- else if (GET_CODE (pat) == SET
- && SET_DEST (pat) == pc_rtx
- && uses_reg_or_mem (SET_SRC (pat)))
- computed_jump = 1;
-
- if (computed_jump)
- {
- for (x = label_value_list; x; x = XEXP (x, 1))
- mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
- insn, 0);
-
- for (x = forced_labels; x; x = XEXP (x, 1))
- mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
- insn, 0);
- }
- }
-
- /* Find all call insns and mark them as possibly jumping
- to all the nonlocal goto handler labels. */
-
- for (insn = f; insn; insn = NEXT_INSN (insn))
- if (GET_CODE (insn) == CALL_INSN)
- {
- for (x = nonlocal_label_list; x; x = XEXP (x, 1))
- mark_label_ref (gen_rtx (LABEL_REF, VOIDmode, XEXP (x, 0)),
- insn, 0);
-
- /* ??? This could be made smarter:
- in some cases it's possible to tell that certain
- calls will not do a nonlocal goto.
-
- For example, if the nested functions that do the
- nonlocal gotos do not have their addresses taken, then
- only calls to those functions or to other nested
- functions that use them could possibly do nonlocal
- gotos. */
- }
-
/* Pass over all blocks, marking each block that is reachable
and has not yet been marked.
Keep doing this until, in one pass, no blocks have been marked.
@@ -613,22 +572,144 @@ find_basic_blocks (f, nonlocal_label_list)
insn = basic_block_end[i];
if (GET_CODE (insn) == JUMP_INSN)
mark_label_ref (PATTERN (insn), insn, 0);
+
+ /* If we have any forced labels, mark them as potentially
+ reachable from this block. */
+ for (x = forced_labels; x; x = XEXP (x, 1))
+ if (! LABEL_REF_NONLOCAL_P (x))
+ mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, XEXP (x, 0)),
+ insn, 0);
+
+ /* Now scan the insns for this block, we may need to make
+ edges for some of them to various non-obvious locations
+ (exception handlers, nonlocal labels, etc). */
+ for (insn = basic_block_head[i];
+ insn != NEXT_INSN (basic_block_end[i]);
+ insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+
+ /* References to labels in non-jumping insns have
+ REG_LABEL notes attached to them.
+
+ This can happen for computed gotos; we don't care
+ about them here since the values are also on the
+ label_value_list and will be marked live if we find
+ a live computed goto.
+
+ This can also happen when we take the address of
+ a label to pass as an argument to __throw. Note
+ throw only uses the value to determine what handler
+ should be called -- ie the label is not used as
+ a jump target, it just marks regions in the code.
+
+ In theory we should be able to ignore the REG_LABEL
+ notes, but we have to make sure that the label and
+ associated insns aren't marked dead, so we make
+ the block in question live and create an edge from
+ this insn to the label. This is not strictly
+ correct, but it is close enough for now. */
+ for (note = REG_NOTES (insn);
+ note;
+ note = XEXP (note, 1))
+ {
+ if (REG_NOTE_KIND (note) == REG_LABEL)
+ {
+ x = XEXP (note, 0);
+ block_live[BLOCK_NUM (x)] = 1;
+ mark_label_ref (gen_rtx_LABEL_REF (VOIDmode, x),
+ insn, 0);
+ }
+ }
+
+ /* If this is a computed jump, then mark it as
+ reaching everything on the label_value_list
+ and forced_labels list. */
+ if (computed_jump_p (insn))
+ {
+ current_function_has_computed_jump = 1;
+ for (x = label_value_list; x; x = XEXP (x, 1))
+ {
+ int b = BLOCK_NUM (XEXP (x, 0));
+ basic_block_computed_jump_target[b] = 1;
+ mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
+ XEXP (x, 0)),
+ insn, 0);
+ }
+
+ for (x = forced_labels; x; x = XEXP (x, 1))
+ {
+ int b = BLOCK_NUM (XEXP (x, 0));
+ basic_block_computed_jump_target[b] = 1;
+ mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
+ XEXP (x, 0)),
+ insn, 0);
+ }
+ }
+
+ /* If this is a CALL_INSN, then mark it as reaching
+ the active EH handler for this CALL_INSN. If
+ we're handling asynchronous exceptions mark every
+ insn as reaching the active EH handler.
+
+ Also mark the CALL_INSN as reaching any nonlocal
+ goto sites. */
+ else if (asynchronous_exceptions
+ || (GET_CODE (insn) == CALL_INSN
+ && ! find_reg_note (insn, REG_RETVAL,
+ NULL_RTX)))
+ {
+ if (active_eh_region[INSN_UID (insn)])
+ {
+ int region;
+ handler_info *ptr;
+ region = active_eh_region[INSN_UID (insn)];
+ for ( ; region;
+ region = nested_eh_region[region])
+ {
+ ptr = get_first_handler (region);
+ for ( ; ptr ; ptr = ptr->next)
+ mark_label_ref (gen_rtx_LABEL_REF
+ (VOIDmode, ptr->handler_label), insn, 0);
+ }
+ }
+ if (!asynchronous_exceptions)
+ {
+ for (x = nonlocal_label_list;
+ x;
+ x = XEXP (x, 1))
+ mark_label_ref (gen_rtx_LABEL_REF (VOIDmode,
+ XEXP (x, 0)),
+ insn, 0);
+ }
+ /* ??? This could be made smarter:
+ in some cases it's possible to tell that
+ certain calls will not do a nonlocal goto.
+
+ For example, if the nested functions that
+ do the nonlocal gotos do not have their
+ addresses taken, then only calls to those
+ functions or to other nested functions that
+ use them could possibly do nonlocal gotos. */
+ }
+ }
+ }
}
}
- /* ??? See if we have a "live" basic block that is not reachable.
- This can happen if it is headed by a label that is preserved or
- in one of the label lists, but no call or computed jump is in
- the loop. It's not clear if we can delete the block or not,
- but don't for now. However, we will mess up register status if
- it remains unreachable, so add a fake reachability from the
- previous block. */
+ /* This should never happen. If it does that means we've computed an
+ incorrect flow graph, which can lead to aborts/crashes later in the
+ compiler or incorrect code generation.
+ We used to try and continue here, but that's just asking for trouble
+ later during the compile or at runtime. It's easier to debug the
+ problem here than later! */
for (i = 1; i < n_basic_blocks; i++)
if (block_live[i] && ! basic_block_drops_in[i]
&& GET_CODE (basic_block_head[i]) == CODE_LABEL
&& LABEL_REFS (basic_block_head[i]) == basic_block_head[i])
- basic_block_drops_in[i] = 1;
+ abort ();
/* Now delete the code for any basic blocks that can't be reached.
They can occur because jump_optimize does not recognize
@@ -672,6 +753,37 @@ find_basic_blocks (f, nonlocal_label_list)
/* Turn the head into a deleted insn note. */
if (GET_CODE (insn) == BARRIER)
abort ();
+
+ /* If the head of this block is a CODE_LABEL, then it might
+ be the label for an exception handler which can't be
+ reached.
+
+ We need to remove the label from the exception_handler_label
+ list and remove the associated NOTE_EH_REGION_BEG and
+ NOTE_EH_REGION_END notes. */
+ if (GET_CODE (insn) == CODE_LABEL)
+ {
+ rtx x, *prev = &exception_handler_labels;
+
+ for (x = exception_handler_labels; x; x = XEXP (x, 1))
+ {
+ if (XEXP (x, 0) == insn)
+ {
+ /* Found a match, splice this label out of the
+ EH label list. */
+ *prev = XEXP (x, 1);
+ XEXP (x, 1) = NULL_RTX;
+ XEXP (x, 0) = NULL_RTX;
+
+ /* Remove the handler from all regions */
+ remove_handler (insn);
+ deleted_handler = 1;
+ break;
+ }
+ prev = &XEXP (x, 1);
+ }
+ }
+
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
@@ -716,6 +828,14 @@ find_basic_blocks (f, nonlocal_label_list)
&& INSN_UID (label) != 0
&& BLOCK_NUM (label) == j)
{
+ int k;
+
+ /* The deleted blocks still show up in the cfg,
+ so we must set basic_block_drops_in for blocks
+ I to J inclusive to keep the cfg accurate. */
+ for (k = i; k <= j; k++)
+ basic_block_drops_in[k] = 1;
+
PUT_CODE (insn, NOTE);
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
NOTE_SOURCE_FILE (insn) = 0;
@@ -727,6 +847,24 @@ find_basic_blocks (f, nonlocal_label_list)
}
}
}
+ /* If we deleted an exception handler, we may have EH region
+ begin/end blocks to remove as well. */
+ if (deleted_handler)
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == NOTE)
+ {
+ if ((NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG) ||
+ (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END))
+ {
+ int num = CODE_LABEL_NUMBER (insn);
+ /* A NULL handler indicates a region is no longer needed */
+ if (get_first_handler (num) == NULL)
+ {
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ }
+ }
+ }
/* There are pathological cases where one function calling hundreds of
nested inline functions can generate lots and lots of unreachable
@@ -756,41 +894,27 @@ find_basic_blocks (f, nonlocal_label_list)
}
}
}
-
-/* Subroutines of find_basic_blocks. */
-/* Return 1 if X contain a REG or MEM that is not in the constant pool. */
+/* Record INSN's block number as BB. */
-static int
-uses_reg_or_mem (x)
- rtx x;
+void
+set_block_num (insn, bb)
+ rtx insn;
+ int bb;
{
- enum rtx_code code = GET_CODE (x);
- int i, j;
- char *fmt;
-
- if (code == REG
- || (code == MEM
- && ! (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))))
- return 1;
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (INSN_UID (insn) >= max_uid_for_flow)
{
- if (fmt[i] == 'e'
- && uses_reg_or_mem (XEXP (x, i)))
- return 1;
-
- if (fmt[i] == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- if (uses_reg_or_mem (XVECEXP (x, i, j)))
- return 1;
+ /* Add one-eighth the size so we don't keep calling xrealloc. */
+ max_uid_for_flow = INSN_UID (insn) + (INSN_UID (insn) + 7) / 8;
+ uid_block_number = (int *)
+ xrealloc (uid_block_number, (max_uid_for_flow + 1) * sizeof (int));
}
-
- return 0;
+ BLOCK_NUM (insn) = bb;
}
+
+/* Subroutines of find_basic_blocks. */
+
/* Check expression X for label references;
if one is found, add INSN to the label's chain of references.
@@ -866,6 +990,80 @@ flow_delete_insn (insn)
return NEXT_INSN (insn);
}
+/* Perform data flow analysis.
+ F is the first insn of the function and NREGS the number of register numbers
+ in use. */
+
+void
+life_analysis (f, nregs, file)
+ rtx f;
+ int nregs;
+ FILE *file;
+{
+#ifdef ELIMINABLE_REGS
+ register size_t i;
+ static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
+#endif
+
+ /* Record which registers will be eliminated. We use this in
+ mark_used_regs. */
+
+ CLEAR_HARD_REG_SET (elim_reg_set);
+
+#ifdef ELIMINABLE_REGS
+ for (i = 0; i < sizeof eliminables / sizeof eliminables[0]; i++)
+ SET_HARD_REG_BIT (elim_reg_set, eliminables[i].from);
+#else
+ SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM);
+#endif
+
+ life_analysis_1 (f, nregs);
+ if (file)
+ dump_flow_info (file);
+
+ free_basic_block_vars (1);
+}
+
+/* Free the variables allocated by find_basic_blocks.
+
+ KEEP_HEAD_END_P is non-zero if basic_block_head and basic_block_end
+ are not to be freed. */
+
+void
+free_basic_block_vars (keep_head_end_p)
+ int keep_head_end_p;
+{
+ if (basic_block_drops_in)
+ {
+ free (basic_block_drops_in);
+ /* Tell dump_flow_info this isn't available anymore. */
+ basic_block_drops_in = 0;
+ }
+ if (basic_block_loop_depth)
+ {
+ free (basic_block_loop_depth);
+ basic_block_loop_depth = 0;
+ }
+ if (uid_block_number)
+ {
+ free (uid_block_number);
+ uid_block_number = 0;
+ }
+ if (uid_volatile)
+ {
+ free (uid_volatile);
+ uid_volatile = 0;
+ }
+
+ if (! keep_head_end_p && basic_block_head)
+ {
+ free (basic_block_head);
+ basic_block_head = 0;
+ free (basic_block_end);
+ basic_block_end = 0;
+ }
+}
+
/* Determine which registers are live at the start of each
basic block of the function whose first insn is F.
NREGS is the number of registers used in F.
@@ -874,11 +1072,10 @@ flow_delete_insn (insn)
regset_size and regset_bytes are also set here. */
static void
-life_analysis (f, nregs)
+life_analysis_1 (f, nregs)
rtx f;
int nregs;
{
- register regset tem;
int first_pass;
int changed;
/* For each basic block, a bitmask of regs
@@ -924,28 +1121,20 @@ life_analysis (f, nregs)
if there isn't enough space.
Don't use oballoc since we may need to allocate other things during
this function on the temporary obstack. */
- tem = (regset) obstack_alloc (&flow_obstack, n_basic_blocks * regset_bytes);
- bzero ((char *) tem, n_basic_blocks * regset_bytes);
- init_regset_vector (basic_block_live_at_end, tem,
- n_basic_blocks, regset_bytes);
+ init_regset_vector (basic_block_live_at_end, n_basic_blocks, &flow_obstack);
basic_block_new_live_at_end
= (regset *) alloca (n_basic_blocks * sizeof (regset));
- tem = (regset) obstack_alloc (&flow_obstack, n_basic_blocks * regset_bytes);
- bzero ((char *) tem, n_basic_blocks * regset_bytes);
- init_regset_vector (basic_block_new_live_at_end, tem,
- n_basic_blocks, regset_bytes);
+ init_regset_vector (basic_block_new_live_at_end, n_basic_blocks,
+ &flow_obstack);
basic_block_significant
= (regset *) alloca (n_basic_blocks * sizeof (regset));
- tem = (regset) obstack_alloc (&flow_obstack, n_basic_blocks * regset_bytes);
- bzero ((char *) tem, n_basic_blocks * regset_bytes);
- init_regset_vector (basic_block_significant, tem,
- n_basic_blocks, regset_bytes);
+ init_regset_vector (basic_block_significant, n_basic_blocks, &flow_obstack);
/* Record which insns refer to any volatile memory
or for any reason can't be deleted just because they are dead stores.
- Also, delete any insns that copy a register to itself. */
+ Also, delete any insns that copy a register to itself. */
for (insn = f; insn; insn = NEXT_INSN (insn))
{
@@ -958,8 +1147,25 @@ life_analysis (f, nregs)
if (GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (insn))) == REG
&& GET_CODE (SET_SRC (PATTERN (insn))) == REG
- && REGNO (SET_DEST (PATTERN (insn))) ==
- REGNO (SET_SRC (PATTERN (insn)))
+ && (REGNO (SET_DEST (PATTERN (insn)))
+ == REGNO (SET_SRC (PATTERN (insn))))
+ /* Insns carrying these notes are useful later on. */
+ && ! find_reg_note (insn, REG_EQUAL, NULL_RTX))
+ {
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ }
+ /* Delete (in effect) any obvious no-op moves. */
+ else if (GET_CODE (PATTERN (insn)) == SET
+ && GET_CODE (SET_DEST (PATTERN (insn))) == SUBREG
+ && GET_CODE (SUBREG_REG (SET_DEST (PATTERN (insn)))) == REG
+ && GET_CODE (SET_SRC (PATTERN (insn))) == SUBREG
+ && GET_CODE (SUBREG_REG (SET_SRC (PATTERN (insn)))) == REG
+ && (REGNO (SUBREG_REG (SET_DEST (PATTERN (insn))))
+ == REGNO (SUBREG_REG (SET_SRC (PATTERN (insn)))))
+ && SUBREG_WORD (SET_DEST (PATTERN (insn))) ==
+ SUBREG_WORD (SET_SRC (PATTERN (insn)))
/* Insns carrying these notes are useful later on. */
&& ! find_reg_note (insn, REG_EQUAL, NULL_RTX))
{
@@ -1020,17 +1226,17 @@ life_analysis (f, nregs)
if (n_basic_blocks > 0)
#ifdef EXIT_IGNORE_STACK
if (! EXIT_IGNORE_STACK
- || (! FRAME_POINTER_REQUIRED && flag_omit_frame_pointer))
+ || (! FRAME_POINTER_REQUIRED
+ && ! current_function_calls_alloca
+ && flag_omit_frame_pointer))
#endif
{
/* If exiting needs the right stack value,
consider the stack pointer live at the end of the function. */
- basic_block_live_at_end[n_basic_blocks - 1]
- [STACK_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS);
- basic_block_new_live_at_end[n_basic_blocks - 1]
- [STACK_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1],
+ STACK_POINTER_REGNUM);
+ SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1],
+ STACK_POINTER_REGNUM);
}
/* Mark the frame pointer is needed at the end of the function. If
@@ -1039,38 +1245,33 @@ life_analysis (f, nregs)
if (n_basic_blocks > 0)
{
- basic_block_live_at_end[n_basic_blocks - 1]
- [FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (FRAME_POINTER_REGNUM % REGSET_ELT_BITS);
- basic_block_new_live_at_end[n_basic_blocks - 1]
- [FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (FRAME_POINTER_REGNUM % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1],
+ FRAME_POINTER_REGNUM);
+ SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1],
+ FRAME_POINTER_REGNUM);
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
/* If they are different, also mark the hard frame pointer as live */
- basic_block_live_at_end[n_basic_blocks - 1]
- [HARD_FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (HARD_FRAME_POINTER_REGNUM
- % REGSET_ELT_BITS);
- basic_block_new_live_at_end[n_basic_blocks - 1]
- [HARD_FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (HARD_FRAME_POINTER_REGNUM
- % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1],
+ HARD_FRAME_POINTER_REGNUM);
+ SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1],
+ HARD_FRAME_POINTER_REGNUM);
#endif
}
- /* Mark all global registers as being live at the end of the function
- since they may be referenced by our caller. */
+ /* Mark all global registers and all registers used by the epilogue
+ as being live at the end of the function since they may be
+ referenced by our caller. */
if (n_basic_blocks > 0)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (global_regs[i])
+ if (global_regs[i]
+#ifdef EPILOGUE_USES
+ || EPILOGUE_USES (i)
+#endif
+ )
{
- basic_block_live_at_end[n_basic_blocks - 1]
- [i / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
- basic_block_new_live_at_end[n_basic_blocks - 1]
- [i / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (basic_block_live_at_end[n_basic_blocks - 1], i);
+ SET_REGNO_REG_SET (basic_block_new_live_at_end[n_basic_blocks - 1], i);
}
/* Propagate life info through the basic blocks
@@ -1105,21 +1306,18 @@ life_analysis (f, nregs)
reg that is live at the end now but was not live there before
is one of the significant regs of this basic block). */
- for (j = 0; j < regset_size; j++)
- {
- register REGSET_ELT_TYPE x
- = (basic_block_new_live_at_end[i][j]
- & ~basic_block_live_at_end[i][j]);
- if (x)
- consider = 1;
- if (x & basic_block_significant[i][j])
- {
- must_rescan = 1;
- consider = 1;
- break;
- }
- }
-
+ EXECUTE_IF_AND_COMPL_IN_REG_SET
+ (basic_block_new_live_at_end[i],
+ basic_block_live_at_end[i], 0, j,
+ {
+ consider = 1;
+ if (REGNO_REG_SET_P (basic_block_significant[i], j))
+ {
+ must_rescan = 1;
+ goto done;
+ }
+ });
+ done:
if (! consider)
continue;
}
@@ -1133,23 +1331,22 @@ life_analysis (f, nregs)
/* No complete rescan needed;
just record those variables newly known live at end
as live at start as well. */
- for (j = 0; j < regset_size; j++)
- {
- register REGSET_ELT_TYPE x
- = (basic_block_new_live_at_end[i][j]
- & ~basic_block_live_at_end[i][j]);
- basic_block_live_at_start[i][j] |= x;
- basic_block_live_at_end[i][j] |= x;
- }
+ IOR_AND_COMPL_REG_SET (basic_block_live_at_start[i],
+ basic_block_new_live_at_end[i],
+ basic_block_live_at_end[i]);
+
+ IOR_AND_COMPL_REG_SET (basic_block_live_at_end[i],
+ basic_block_new_live_at_end[i],
+ basic_block_live_at_end[i]);
}
else
{
/* Update the basic_block_live_at_start
by propagation backwards through the block. */
- bcopy ((char *) basic_block_new_live_at_end[i],
- (char *) basic_block_live_at_end[i], regset_bytes);
- bcopy ((char *) basic_block_live_at_end[i],
- (char *) basic_block_live_at_start[i], regset_bytes);
+ COPY_REG_SET (basic_block_live_at_end[i],
+ basic_block_new_live_at_end[i]);
+ COPY_REG_SET (basic_block_live_at_start[i],
+ basic_block_live_at_end[i]);
propagate_block (basic_block_live_at_start[i],
basic_block_head[i], basic_block_end[i], 0,
first_pass ? basic_block_significant[i]
@@ -1164,12 +1361,8 @@ life_analysis (f, nregs)
that falls through into this one (if any). */
head = basic_block_head[i];
if (basic_block_drops_in[i])
- {
- register int j;
- for (j = 0; j < regset_size; j++)
- basic_block_new_live_at_end[i-1][j]
- |= basic_block_live_at_start[i][j];
- }
+ IOR_REG_SET (basic_block_new_live_at_end[i-1],
+ basic_block_live_at_start[i]);
/* Update the basic_block_new_live_at_end's of
all the blocks that jump to this one. */
@@ -1179,10 +1372,8 @@ life_analysis (f, nregs)
jump = LABEL_NEXTREF (jump))
{
register int from_block = BLOCK_NUM (CONTAINING_INSN (jump));
- register int j;
- for (j = 0; j < regset_size; j++)
- basic_block_new_live_at_end[from_block][j]
- |= basic_block_live_at_start[i][j];
+ IOR_REG_SET (basic_block_new_live_at_end[from_block],
+ basic_block_live_at_start[i]);
}
}
#ifdef USE_C_ALLOCA
@@ -1198,10 +1389,11 @@ life_analysis (f, nregs)
one basic block. */
if (n_basic_blocks > 0)
- for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (basic_block_live_at_start[0][i / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS)))
- reg_basic_block[i] = REG_BLOCK_GLOBAL;
+ EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[0],
+ FIRST_PSEUDO_REGISTER, i,
+ {
+ REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL;
+ });
/* Now the life information is accurate.
Make one more pass over each basic block
@@ -1232,14 +1424,16 @@ life_analysis (f, nregs)
But we don't need to do this for the user's variables, since
ANSI says only volatile variables need this. */
#ifdef LONGJMP_RESTORE_FROM_STACK
- for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
- if (regs_live_at_setjmp[i / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS))
- && regno_reg_rtx[i] != 0 && ! REG_USERVAR_P (regno_reg_rtx[i]))
- {
- reg_live_length[i] = -1;
- reg_basic_block[i] = -1;
- }
+ EXECUTE_IF_SET_IN_REG_SET (regs_live_at_setjmp,
+ FIRST_PSEUDO_REGISTER, i,
+ {
+ if (regno_reg_rtx[i] != 0
+ && ! REG_USERVAR_P (regno_reg_rtx[i]))
+ {
+ REG_LIVE_LENGTH (i) = -1;
+ REG_BASIC_BLOCK (i) = -1;
+ }
+ });
#endif
#endif
@@ -1252,14 +1446,23 @@ life_analysis (f, nregs)
If the pseudo goes in a hard reg, some other value may occupy
that hard reg where this pseudo is dead, thus clobbering the pseudo.
Conclusion: such a pseudo must not go in a hard reg. */
- for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
- if ((regs_live_at_setjmp[i / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS)))
- && regno_reg_rtx[i] != 0)
- {
- reg_live_length[i] = -1;
- reg_basic_block[i] = -1;
- }
+ EXECUTE_IF_SET_IN_REG_SET (regs_live_at_setjmp,
+ FIRST_PSEUDO_REGISTER, i,
+ {
+ if (regno_reg_rtx[i] != 0)
+ {
+ REG_LIVE_LENGTH (i) = -1;
+ REG_BASIC_BLOCK (i) = -1;
+ }
+ });
+
+
+ free_regset_vector (basic_block_live_at_end, n_basic_blocks);
+ free_regset_vector (basic_block_new_live_at_end, n_basic_blocks);
+ free_regset_vector (basic_block_significant, n_basic_blocks);
+ basic_block_live_at_end = (regset *)0;
+ basic_block_new_live_at_end = (regset *)0;
+ basic_block_significant = (regset *)0;
obstack_free (&flow_obstack, NULL_PTR);
}
@@ -1273,66 +1476,60 @@ void
allocate_for_life_analysis ()
{
register int i;
- register regset tem;
-
- regset_size = ((max_regno + REGSET_ELT_BITS - 1) / REGSET_ELT_BITS);
- regset_bytes = regset_size * sizeof (*(regset)0);
-
- reg_n_refs = (int *) oballoc (max_regno * sizeof (int));
- bzero ((char *) reg_n_refs, max_regno * sizeof (int));
-
- reg_n_sets = (short *) oballoc (max_regno * sizeof (short));
- bzero ((char *) reg_n_sets, max_regno * sizeof (short));
-
- reg_n_deaths = (short *) oballoc (max_regno * sizeof (short));
- bzero ((char *) reg_n_deaths, max_regno * sizeof (short));
-
- reg_changes_size = (char *) oballoc (max_regno * sizeof (char));
- bzero (reg_changes_size, max_regno * sizeof (char));;
-
- reg_live_length = (int *) oballoc (max_regno * sizeof (int));
- bzero ((char *) reg_live_length, max_regno * sizeof (int));
- reg_n_calls_crossed = (int *) oballoc (max_regno * sizeof (int));
- bzero ((char *) reg_n_calls_crossed, max_regno * sizeof (int));
+ /* Recalculate the register space, in case it has grown. Old style
+ vector oriented regsets would set regset_{size,bytes} here also. */
+ allocate_reg_info (max_regno, FALSE, FALSE);
- reg_basic_block = (int *) oballoc (max_regno * sizeof (int));
+ /* Because both reg_scan and flow_analysis want to set up the REG_N_SETS
+ information, explicitly reset it here. The allocation should have
+ already happened on the previous reg_scan pass. Make sure in case
+ some more registers were allocated. */
for (i = 0; i < max_regno; i++)
- reg_basic_block[i] = REG_BLOCK_UNKNOWN;
+ REG_N_SETS (i) = 0;
basic_block_live_at_start
= (regset *) oballoc (n_basic_blocks * sizeof (regset));
- tem = (regset) oballoc (n_basic_blocks * regset_bytes);
- bzero ((char *) tem, n_basic_blocks * regset_bytes);
- init_regset_vector (basic_block_live_at_start, tem,
- n_basic_blocks, regset_bytes);
+ init_regset_vector (basic_block_live_at_start, n_basic_blocks,
+ function_obstack);
- regs_live_at_setjmp = (regset) oballoc (regset_bytes);
- bzero ((char *) regs_live_at_setjmp, regset_bytes);
+ regs_live_at_setjmp = OBSTACK_ALLOC_REG_SET (function_obstack);
+ CLEAR_REG_SET (regs_live_at_setjmp);
}
-/* Make each element of VECTOR point at a regset,
- taking the space for all those regsets from SPACE.
- SPACE is of type regset, but it is really as long as NELTS regsets.
- BYTES_PER_ELT is the number of bytes in one regset. */
+/* Make each element of VECTOR point at a regset. The vector has
+ NELTS elements, and space is allocated from the ALLOC_OBSTACK
+ obstack. */
static void
-init_regset_vector (vector, space, nelts, bytes_per_elt)
+init_regset_vector (vector, nelts, alloc_obstack)
regset *vector;
- regset space;
int nelts;
- int bytes_per_elt;
+ struct obstack *alloc_obstack;
{
register int i;
- register regset p = space;
for (i = 0; i < nelts; i++)
{
- vector[i] = p;
- p += bytes_per_elt / sizeof (*p);
+ vector[i] = OBSTACK_ALLOC_REG_SET (alloc_obstack);
+ CLEAR_REG_SET (vector[i]);
}
}
+/* Release any additional space allocated for each element of VECTOR point
+ other than the regset header itself. The vector has NELTS elements. */
+
+void
+free_regset_vector (vector, nelts)
+ regset *vector;
+ int nelts;
+{
+ register int i;
+
+ for (i = 0; i < nelts; i++)
+ FREE_REG_SET (vector[i]);
+}
+
/* Compute the registers live at the beginning of a basic block
from those live at the end.
@@ -1369,11 +1566,8 @@ propagate_block (old, first, last, final, significant, bnum)
/* The following variables are used only if FINAL is nonzero. */
/* This vector gets one element for each reg that has been live
at any point in the basic block that has been scanned so far.
- SOMETIMES_MAX says how many elements are in use so far.
- In each element, OFFSET is the byte-number within a regset
- for the register described by the element, and BIT is a mask
- for that register's bit within the byte. */
- register struct sometimes { short offset; short bit; } *regs_sometimes_live;
+ SOMETIMES_MAX says how many elements are in use so far. */
+ register int *regs_sometimes_live;
int sometimes_max = 0;
/* This regset has 1 for each reg that we have seen live so far.
It and REGS_SOMETIMES_LIVE are updated together. */
@@ -1384,8 +1578,8 @@ propagate_block (old, first, last, final, significant, bnum)
current basic block, and adjust as we pass ends and starts of loops. */
loop_depth = basic_block_loop_depth[bnum];
- dead = (regset) alloca (regset_bytes);
- live = (regset) alloca (regset_bytes);
+ dead = ALLOCA_REG_SET ();
+ live = ALLOCA_REG_SET ();
cc0_live = 0;
last_mem_set = 0;
@@ -1405,32 +1599,22 @@ propagate_block (old, first, last, final, significant, bnum)
if (final)
{
- register int i, offset;
- REGSET_ELT_TYPE bit;
+ register int i;
num_scratch = 0;
- maxlive = (regset) alloca (regset_bytes);
- bcopy ((char *) old, (char *) maxlive, regset_bytes);
- regs_sometimes_live
- = (struct sometimes *) alloca (max_regno * sizeof (struct sometimes));
+ maxlive = ALLOCA_REG_SET ();
+ COPY_REG_SET (maxlive, old);
+ regs_sometimes_live = (int *) alloca (max_regno * sizeof (int));
/* Process the regs live at the end of the block.
Enter them in MAXLIVE and REGS_SOMETIMES_LIVE.
- Also mark them as not local to any one basic block. */
-
- for (offset = 0, i = 0; offset < regset_size; offset++)
- for (bit = 1; bit; bit <<= 1, i++)
- {
- if (i == max_regno)
- break;
- if (old[offset] & bit)
- {
- reg_basic_block[i] = REG_BLOCK_GLOBAL;
- regs_sometimes_live[sometimes_max].offset = offset;
- regs_sometimes_live[sometimes_max].bit = i % REGSET_ELT_BITS;
- sometimes_max++;
- }
- }
+ Also mark them as not local to any one basic block. */
+ EXECUTE_IF_SET_IN_REG_SET (old, 0, i,
+ {
+ REG_BASIC_BLOCK (i) = REG_BLOCK_GLOBAL;
+ regs_sometimes_live[sometimes_max] = i;
+ sometimes_max++;
+ });
}
/* Scan the block an insn at a time from end to beginning. */
@@ -1457,11 +1641,7 @@ propagate_block (old, first, last, final, significant, bnum)
warn if any non-volatile datum is live. */
if (final && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
- {
- int i;
- for (i = 0; i < regset_size; i++)
- regs_live_at_setjmp[i] |= old[i];
- }
+ IOR_REG_SET (regs_live_at_setjmp, old);
}
/* Update the life-status of regs for this insn.
@@ -1517,19 +1697,17 @@ propagate_block (old, first, last, final, significant, bnum)
goto flushed;
}
- for (i = 0; i < regset_size; i++)
- {
- dead[i] = 0; /* Faster than bzero here */
- live[i] = 0; /* since regset_size is usually small */
- }
+ CLEAR_REG_SET (dead);
+ CLEAR_REG_SET (live);
/* See if this is an increment or decrement that can be
merged into a following memory address. */
#ifdef AUTO_INC_DEC
{
- register rtx x = PATTERN (insn);
+ register rtx x = single_set (insn);
+
/* Does this instruction increment or decrement a register? */
- if (final && GET_CODE (x) == SET
+ if (final && x != 0
&& GET_CODE (SET_DEST (x)) == REG
&& (GET_CODE (SET_SRC (x)) == PLUS
|| GET_CODE (SET_SRC (x)) == MINUS)
@@ -1604,26 +1782,24 @@ propagate_block (old, first, last, final, significant, bnum)
final, insn);
/* Each call clobbers all call-clobbered regs that are not
- global. Note that the function-value reg is a
+ global or fixed. Note that the function-value reg is a
call-clobbered reg, and mark_set_regs has already had
a chance to handle it. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (call_used_regs[i] && ! global_regs[i])
- dead[i / REGSET_ELT_BITS]
- |= ((REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS));
+ if (call_used_regs[i] && ! global_regs[i]
+ && ! fixed_regs[i])
+ SET_REGNO_REG_SET (dead, i);
/* The stack ptr is used (honorarily) by a CALL insn. */
- live[STACK_POINTER_REGNUM / REGSET_ELT_BITS]
- |= ((REGSET_ELT_TYPE) 1
- << (STACK_POINTER_REGNUM % REGSET_ELT_BITS));
+ SET_REGNO_REG_SET (live, STACK_POINTER_REGNUM);
/* Calls may also reference any of the global registers,
so they are made live. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
if (global_regs[i])
mark_used_regs (old, live,
- gen_rtx (REG, reg_raw_mode[i], i),
+ gen_rtx_REG (reg_raw_mode[i], i),
final, insn);
/* Calls also clobber memory. */
@@ -1631,11 +1807,8 @@ propagate_block (old, first, last, final, significant, bnum)
}
/* Update OLD for the registers used or set. */
- for (i = 0; i < regset_size; i++)
- {
- old[i] &= ~dead[i];
- old[i] |= live[i];
- }
+ AND_COMPL_REG_SET (old, dead);
+ IOR_REG_SET (old, live);
if (GET_CODE (insn) == CALL_INSN && final)
{
@@ -1643,11 +1816,11 @@ propagate_block (old, first, last, final, significant, bnum)
must not go in a register clobbered by calls.
Find all regs now live and record this for them. */
- register struct sometimes *p = regs_sometimes_live;
+ register int *p = regs_sometimes_live;
for (i = 0; i < sometimes_max; i++, p++)
- if (old[p->offset] & ((REGSET_ELT_TYPE) 1 << p->bit))
- reg_n_calls_crossed[p->offset * REGSET_ELT_BITS + p->bit]+= 1;
+ if (REGNO_REG_SET_P (old, *p))
+ REG_N_CALLS_CROSSED (*p)++;
}
}
@@ -1657,33 +1830,23 @@ propagate_block (old, first, last, final, significant, bnum)
if (final)
{
- for (i = 0; i < regset_size; i++)
+ register int regno;
+ register int *p;
+
+ EXECUTE_IF_AND_COMPL_IN_REG_SET
+ (live, maxlive, 0, regno,
+ {
+ regs_sometimes_live[sometimes_max++] = regno;
+ SET_REGNO_REG_SET (maxlive, regno);
+ });
+
+ p = regs_sometimes_live;
+ for (i = 0; i < sometimes_max; i++)
{
- register REGSET_ELT_TYPE diff = live[i] & ~maxlive[i];
-
- if (diff)
- {
- register int regno;
- maxlive[i] |= diff;
- for (regno = 0; diff && regno < REGSET_ELT_BITS; regno++)
- if (diff & ((REGSET_ELT_TYPE) 1 << regno))
- {
- regs_sometimes_live[sometimes_max].offset = i;
- regs_sometimes_live[sometimes_max].bit = regno;
- diff &= ~ ((REGSET_ELT_TYPE) 1 << regno);
- sometimes_max++;
- }
- }
+ regno = *p++;
+ if (REGNO_REG_SET_P (old, regno))
+ REG_LIVE_LENGTH (regno)++;
}
-
- {
- register struct sometimes *p = regs_sometimes_live;
- for (i = 0; i < sometimes_max; i++, p++)
- {
- if (old[p->offset] & ((REGSET_ELT_TYPE) 1 << p->bit))
- reg_live_length[p->offset * REGSET_ELT_BITS + p->bit]++;
- }
- }
}
}
flushed: ;
@@ -1691,6 +1854,11 @@ propagate_block (old, first, last, final, significant, bnum)
break;
}
+ FREE_REG_SET (dead);
+ FREE_REG_SET (live);
+ if (final)
+ FREE_REG_SET (maxlive);
+
if (num_scratch > max_scratch)
max_scratch = num_scratch;
}
@@ -1707,13 +1875,15 @@ insn_dead_p (x, needed, call_ok)
regset needed;
int call_ok;
{
- register RTX_CODE code = GET_CODE (x);
+ enum rtx_code code = GET_CODE (x);
+
/* If setting something that's a reg or part of one,
see if that register's altered value will be live. */
if (code == SET)
{
- register rtx r = SET_DEST (x);
+ rtx r = SET_DEST (x);
+
/* A SET that is a subroutine call cannot be dead. */
if (! call_ok && GET_CODE (SET_SRC (x)) == CALL)
return 0;
@@ -1727,18 +1897,13 @@ insn_dead_p (x, needed, call_ok)
&& rtx_equal_p (r, last_mem_set))
return 1;
- while (GET_CODE (r) == SUBREG
- || GET_CODE (r) == STRICT_LOW_PART
- || GET_CODE (r) == ZERO_EXTRACT
- || GET_CODE (r) == SIGN_EXTRACT)
+ while (GET_CODE (r) == SUBREG || GET_CODE (r) == STRICT_LOW_PART
+ || GET_CODE (r) == ZERO_EXTRACT)
r = SUBREG_REG (r);
if (GET_CODE (r) == REG)
{
- register int regno = REGNO (r);
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
+ int regno = REGNO (r);
/* Don't delete insns to set global regs. */
if ((regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
@@ -1750,10 +1915,10 @@ insn_dead_p (x, needed, call_ok)
#if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
/* Make sure insns to set arg pointer are never deleted
(if the arg pointer isn't fixed, there will be a USE for
- it, so we can treat it normally). */
+ it, so we can treat it normally). */
|| (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
#endif
- || (needed[offset] & bit) != 0)
+ || REGNO_REG_SET_P (needed, regno))
return 0;
/* If this is a hard register, verify that subsequent words are
@@ -1763,35 +1928,40 @@ insn_dead_p (x, needed, call_ok)
int n = HARD_REGNO_NREGS (regno, GET_MODE (r));
while (--n > 0)
- if ((needed[(regno + n) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno + n) % REGSET_ELT_BITS))) != 0)
+ if (REGNO_REG_SET_P (needed, regno+n))
return 0;
}
return 1;
}
}
+
/* If performing several activities,
insn is dead if each activity is individually dead.
Also, CLOBBERs and USEs can be ignored; a CLOBBER or USE
that's inside a PARALLEL doesn't make the insn worth keeping. */
else if (code == PARALLEL)
{
- register int i = XVECLEN (x, 0);
+ int i = XVECLEN (x, 0);
+
for (i--; i >= 0; i--)
- {
- rtx elt = XVECEXP (x, 0, i);
- if (!insn_dead_p (elt, needed, call_ok)
- && GET_CODE (elt) != CLOBBER
- && GET_CODE (elt) != USE)
- return 0;
- }
+ if (GET_CODE (XVECEXP (x, 0, i)) != CLOBBER
+ && GET_CODE (XVECEXP (x, 0, i)) != USE
+ && ! insn_dead_p (XVECEXP (x, 0, i), needed, call_ok))
+ return 0;
+
return 1;
}
- /* We do not check CLOBBER or USE here.
- An insn consisting of just a CLOBBER or just a USE
- should not be deleted. */
+
+ /* A CLOBBER of a pseudo-register that is dead serves no purpose. That
+ is not necessarily true for hard registers. */
+ else if (code == CLOBBER && GET_CODE (XEXP (x, 0)) == REG
+ && REGNO (XEXP (x, 0)) >= FIRST_PSEUDO_REGISTER
+ && ! REGNO_REG_SET_P (needed, REGNO (XEXP (x, 0))))
+ return 1;
+
+ /* We do not check other CLOBBER or USE here. An insn consisting of just
+ a CLOBBER or just a USE should not be deleted. */
return 0;
}
@@ -1862,18 +2032,19 @@ libcall_dead_p (x, needed, note, insn)
/* Return 1 if register REGNO was used before it was set.
In other words, if it is live at function entry.
- Don't count global register variables, though. */
+ Don't count global register variables or variables in registers
+ that can be used for function arg passing, though. */
int
regno_uninitialized (regno)
int regno;
{
if (n_basic_blocks == 0
- || (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]))
+ || (regno < FIRST_PSEUDO_REGISTER
+ && (global_regs[regno] || FUNCTION_ARG_REGNO_P (regno))))
return 0;
- return (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS)));
+ return REGNO_REG_SET_P (basic_block_live_at_start[0], regno);
}
/* 1 if register REGNO was alive at a place where `setjmp' was called
@@ -1887,11 +2058,9 @@ regno_clobbered_at_setjmp (regno)
if (n_basic_blocks == 0)
return 0;
- return ((reg_n_sets[regno] > 1
- || (basic_block_live_at_start[0][regno / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))))
- && (regs_live_at_setjmp[regno / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS))));
+ return ((REG_N_SETS (regno) > 1
+ || REGNO_REG_SET_P (basic_block_live_at_start[0], regno))
+ && REGNO_REG_SET_P (regs_live_at_setjmp, regno));
}
/* Process the registers that are set within X.
@@ -1984,18 +2153,15 @@ mark_set_1 (needed, dead, x, insn, significant)
&& ! (regno < FIRST_PSEUDO_REGISTER && global_regs[regno]))
/* && regno != STACK_POINTER_REGNUM) -- let's try without this. */
{
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
- REGSET_ELT_TYPE all_needed = (needed[offset] & bit);
- REGSET_ELT_TYPE some_needed = (needed[offset] & bit);
+ int some_needed = REGNO_REG_SET_P (needed, regno);
+ int some_not_needed = ! some_needed;
/* Mark it as a significant register for this basic block. */
if (significant)
- significant[offset] |= bit;
+ SET_REGNO_REG_SET (significant, regno);
- /* Mark it as as dead before this insn. */
- dead[offset] |= bit;
+ /* Mark it as dead before this insn. */
+ SET_REGNO_REG_SET (dead, regno);
/* A hard reg in a wide mode may really be multiple registers.
If so, mark all of them just like the first. */
@@ -2011,17 +2177,14 @@ mark_set_1 (needed, dead, x, insn, significant)
n = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (--n > 0)
{
+ int regno_n = regno + n;
+ int needed_regno = REGNO_REG_SET_P (needed, regno_n);
if (significant)
- significant[(regno + n) / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS);
- dead[(regno + n) / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS);
- some_needed
- |= (needed[(regno + n) / REGSET_ELT_BITS]
- & (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS));
- all_needed
- &= (needed[(regno + n) / REGSET_ELT_BITS]
- & (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS));
+ SET_REGNO_REG_SET (significant, regno_n);
+
+ SET_REGNO_REG_SET (dead, regno_n);
+ some_needed |= needed_regno;
+ some_not_needed |= ! needed_regno;
}
}
/* Additional data to record if this is the final pass. */
@@ -2044,7 +2207,7 @@ mark_set_1 (needed, dead, x, insn, significant)
reg_next_use[i] = 0;
regs_ever_live[i] = 1;
- reg_n_sets[i]++;
+ REG_N_SETS (i)++;
}
}
else
@@ -2055,25 +2218,25 @@ mark_set_1 (needed, dead, x, insn, significant)
/* Keep track of which basic blocks each reg appears in. */
- if (reg_basic_block[regno] == REG_BLOCK_UNKNOWN)
- reg_basic_block[regno] = blocknum;
- else if (reg_basic_block[regno] != blocknum)
- reg_basic_block[regno] = REG_BLOCK_GLOBAL;
+ if (REG_BASIC_BLOCK (regno) == REG_BLOCK_UNKNOWN)
+ REG_BASIC_BLOCK (regno) = blocknum;
+ else if (REG_BASIC_BLOCK (regno) != blocknum)
+ REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
/* Count (weighted) references, stores, etc. This counts a
register twice if it is modified, but that is correct. */
- reg_n_sets[regno]++;
+ REG_N_SETS (regno)++;
- reg_n_refs[regno] += loop_depth;
+ REG_N_REFS (regno) += loop_depth;
/* The insns where a reg is live are normally counted
elsewhere, but we want the count to include the insn
where the reg is set, and the normal counting mechanism
would not count it. */
- reg_live_length[regno]++;
+ REG_LIVE_LENGTH (regno)++;
}
- if (all_needed)
+ if (! some_not_needed)
{
/* Make a logical link from the next following insn
that uses this register, back to this insn.
@@ -2088,7 +2251,7 @@ mark_set_1 (needed, dead, x, insn, significant)
&& (regno >= FIRST_PSEUDO_REGISTER
|| asm_noperands (PATTERN (y)) < 0))
LOG_LINKS (y)
- = gen_rtx (INSN_LIST, VOIDmode, insn, LOG_LINKS (y));
+ = gen_rtx_INSN_LIST (VOIDmode, insn, LOG_LINKS (y));
}
else if (! some_needed)
{
@@ -2097,8 +2260,8 @@ mark_set_1 (needed, dead, x, insn, significant)
be eliminated (because the same insn does something useful).
Indicate this by marking the reg being set as dying here. */
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_UNUSED, reg, REG_NOTES (insn));
- reg_n_deaths[REGNO (reg)]++;
+ = gen_rtx_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
+ REG_N_DEATHS (REGNO (reg))++;
}
else
{
@@ -2112,14 +2275,12 @@ mark_set_1 (needed, dead, x, insn, significant)
for (i = HARD_REGNO_NREGS (regno, GET_MODE (reg)) - 1;
i >= 0; i--)
- if ((needed[(regno + i) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno + i) % REGSET_ELT_BITS))) == 0)
+ if (!REGNO_REG_SET_P (needed, regno + i))
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_UNUSED,
- gen_rtx (REG, reg_raw_mode[regno + i],
- regno + i),
- REG_NOTES (insn));
+ = gen_rtx_EXPR_LIST (REG_UNUSED,
+ gen_rtx_REG (reg_raw_mode[regno + i],
+ regno + i),
+ REG_NOTES (insn));
}
}
}
@@ -2131,7 +2292,7 @@ mark_set_1 (needed, dead, x, insn, significant)
else if (GET_CODE (reg) == SCRATCH && insn != 0)
{
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_UNUSED, reg, REG_NOTES (insn));
+ = gen_rtx_EXPR_LIST (REG_UNUSED, reg, REG_NOTES (insn));
num_scratch++;
}
}
@@ -2205,18 +2366,22 @@ find_auto_inc (needed, x, insn)
we can't, we are done. Otherwise, we will do any
needed updates below. */
if (! validate_change (insn, &XEXP (x, 0),
- gen_rtx (inc_code, Pmode, addr),
+ gen_rtx_fmt_e (inc_code, Pmode, addr),
0))
return;
}
else if (GET_CODE (q) == REG
/* PREV_INSN used here to check the semi-open interval
[insn,incr). */
- && ! reg_used_between_p (q, PREV_INSN (insn), incr))
+ && ! reg_used_between_p (q, PREV_INSN (insn), incr)
+ /* We must also check for sets of q as q may be
+ a call clobbered hard register and there may
+ be a call between PREV_INSN (insn) and incr. */
+ && ! reg_set_between_p (q, PREV_INSN (insn), incr))
{
/* We have *p followed sometime later by q = p+size.
Both p and q must be live afterward,
- and q is not used between INSN and it's assignment.
+ and q is not used between INSN and its assignment.
Change it to q = p, ...*q..., q = q+size.
Then fall into the usual case. */
rtx insns, temp;
@@ -2242,7 +2407,7 @@ find_auto_inc (needed, x, insn)
so is not correct in the pre-inc case. */
validate_change (insn, &XEXP (x, 0),
- gen_rtx (inc_code, Pmode, q),
+ gen_rtx_fmt_e (inc_code, Pmode, q),
1);
validate_change (incr, &XEXP (y, 0), q, 1);
if (! apply_change_group ())
@@ -2273,14 +2438,13 @@ find_auto_inc (needed, x, insn)
it previously wasn't live here. If we don't mark
it as needed, we'll put a REG_DEAD note for it
on this insn, which is incorrect. */
- needed[regno / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (needed, regno);
/* If there are any calls between INSN and INCR, show
that REGNO now crosses them. */
for (temp = insn; temp != incr; temp = NEXT_INSN (temp))
if (GET_CODE (temp) == CALL_INSN)
- reg_n_calls_crossed[regno]++;
+ REG_N_CALLS_CROSSED (regno)++;
}
else
return;
@@ -2290,7 +2454,7 @@ find_auto_inc (needed, x, insn)
has an implicit side effect. */
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_INC, addr, REG_NOTES (insn));
+ = gen_rtx_EXPR_LIST (REG_INC, addr, REG_NOTES (insn));
/* Modify the old increment-insn to simply copy
the already-incremented value of our register. */
@@ -2312,11 +2476,11 @@ find_auto_inc (needed, x, insn)
/* Count an extra reference to the reg. When a reg is
incremented, spilling it is worse, so we want to make
that less likely. */
- reg_n_refs[regno] += loop_depth;
+ REG_N_REFS (regno) += loop_depth;
/* Count the increment as a setting of the register,
even though it isn't a SET in rtl. */
- reg_n_sets[regno]++;
+ REG_N_SETS (regno)++;
}
}
}
@@ -2374,9 +2538,13 @@ mark_used_regs (needed, live, x, final, insn)
return;
case MEM:
- /* Invalidate the data for the last MEM stored. We could do this only
- if the addresses conflict, but this doesn't seem worthwhile. */
- last_mem_set = 0;
+ /* Invalidate the data for the last MEM stored, but only if MEM is
+ something that can be stored into. */
+ if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))
+ ; /* needn't clear last_mem_set */
+ else
+ last_mem_set = 0;
#ifdef AUTO_INC_DEC
if (final)
@@ -2389,7 +2557,7 @@ mark_used_regs (needed, live, x, final, insn)
&& REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (x))
!= GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
- reg_changes_size[REGNO (SUBREG_REG (x))] = 1;
+ REG_CHANGES_SIZE (REGNO (SUBREG_REG (x))) = 1;
/* While we're here, optimize this case. */
x = SUBREG_REG (x);
@@ -2401,7 +2569,7 @@ mark_used_regs (needed, live, x, final, insn)
return;
}
- /* ... fall through ... */
+ /* ... fall through ... */
case REG:
/* See a register other than being set
@@ -2409,13 +2577,11 @@ mark_used_regs (needed, live, x, final, insn)
regno = REGNO (x);
{
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
- REGSET_ELT_TYPE all_needed = needed[offset] & bit;
- REGSET_ELT_TYPE some_needed = needed[offset] & bit;
+ int some_needed = REGNO_REG_SET_P (needed, regno);
+ int some_not_needed = ! some_needed;
+
+ SET_REGNO_REG_SET (live, regno);
- live[offset] |= bit;
/* A hard reg in a wide mode may really be multiple registers.
If so, mark all of them just like the first. */
if (regno < FIRST_PSEUDO_REGISTER)
@@ -2456,14 +2622,12 @@ mark_used_regs (needed, live, x, final, insn)
n = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--n > 0)
{
- live[(regno + n) / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS);
- some_needed
- |= (needed[(regno + n) / REGSET_ELT_BITS]
- & (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS));
- all_needed
- &= (needed[(regno + n) / REGSET_ELT_BITS]
- & (REGSET_ELT_TYPE) 1 << ((regno + n) % REGSET_ELT_BITS));
+ int regno_n = regno + n;
+ int needed_regno = REGNO_REG_SET_P (needed, regno_n);
+
+ SET_REGNO_REG_SET (live, regno_n);
+ some_needed |= needed_regno;
+ some_not_needed |= ! needed_regno;
}
}
if (final)
@@ -2491,14 +2655,14 @@ mark_used_regs (needed, live, x, final, insn)
register int blocknum = BLOCK_NUM (insn);
- if (reg_basic_block[regno] == REG_BLOCK_UNKNOWN)
- reg_basic_block[regno] = blocknum;
- else if (reg_basic_block[regno] != blocknum)
- reg_basic_block[regno] = REG_BLOCK_GLOBAL;
+ if (REG_BASIC_BLOCK (regno) == REG_BLOCK_UNKNOWN)
+ REG_BASIC_BLOCK (regno) = blocknum;
+ else if (REG_BASIC_BLOCK (regno) != blocknum)
+ REG_BASIC_BLOCK (regno) = REG_BLOCK_GLOBAL;
/* Count (weighted) number of uses of each reg. */
- reg_n_refs[regno] += loop_depth;
+ REG_N_REFS (regno) += loop_depth;
}
/* Record and count the insns in which a reg dies.
@@ -2507,7 +2671,7 @@ mark_used_regs (needed, live, x, final, insn)
we do not make a REG_DEAD note; likewise if we already
made such a note. */
- if (! all_needed
+ if (some_not_needed
&& ! dead_or_set_p (insn, x)
#if 0
&& (regno >= FIRST_PSEUDO_REGISTER || ! fixed_regs[regno])
@@ -2529,8 +2693,8 @@ mark_used_regs (needed, live, x, final, insn)
if (! some_needed)
{
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_DEAD, x, REG_NOTES (insn));
- reg_n_deaths[regno]++;
+ = gen_rtx_EXPR_LIST (REG_DEAD, x, REG_NOTES (insn));
+ REG_N_DEATHS (regno)++;
}
else
{
@@ -2541,15 +2705,13 @@ mark_used_regs (needed, live, x, final, insn)
for (i = HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1;
i >= 0; i--)
- if ((needed[(regno + i) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno + i) % REGSET_ELT_BITS))) == 0
+ if (!REGNO_REG_SET_P (needed, regno + i)
&& ! dead_or_set_regno_p (insn, regno + i))
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_DEAD,
- gen_rtx (REG, reg_raw_mode[regno + i],
- regno + i),
- REG_NOTES (insn));
+ = gen_rtx_EXPR_LIST (REG_DEAD,
+ gen_rtx_REG (reg_raw_mode[regno + i],
+ regno + i),
+ REG_NOTES (insn));
}
}
}
@@ -2591,7 +2753,7 @@ mark_used_regs (needed, live, x, final, insn)
&& REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER
&& (GET_MODE_SIZE (GET_MODE (testreg))
!= GET_MODE_SIZE (GET_MODE (SUBREG_REG (testreg)))))
- reg_changes_size[REGNO (SUBREG_REG (testreg))] = 1;
+ REG_CHANGES_SIZE (REGNO (SUBREG_REG (testreg))) = 1;
/* Modifying a single register in an alternate mode
does not use any of the old value. But these other
@@ -2631,19 +2793,26 @@ mark_used_regs (needed, live, x, final, insn)
case RETURN:
/* If exiting needs the right stack value, consider this insn as
using the stack pointer. In any event, consider it as using
- all global registers. */
+ all global registers and all registers used by return. */
#ifdef EXIT_IGNORE_STACK
if (! EXIT_IGNORE_STACK
- || (! FRAME_POINTER_REQUIRED && flag_omit_frame_pointer))
+ || (! FRAME_POINTER_REQUIRED
+ && ! current_function_calls_alloca
+ && flag_omit_frame_pointer))
#endif
- live[STACK_POINTER_REGNUM / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (STACK_POINTER_REGNUM % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (live, STACK_POINTER_REGNUM);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (global_regs[i])
- live[i / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
+ if (global_regs[i]
+#ifdef EPILOGUE_USES
+ || EPILOGUE_USES (i)
+#endif
+ )
+ SET_REGNO_REG_SET (live, i);
+ break;
+
+ default:
break;
}
@@ -2683,7 +2852,7 @@ try_pre_increment_1 (insn)
{
/* Find the next use of this reg. If in same basic block,
make it do pre-increment or pre-decrement if appropriate. */
- rtx x = PATTERN (insn);
+ rtx x = single_set (insn);
HOST_WIDE_INT amount = ((GET_CODE (SET_SRC (x)) == PLUS ? 1 : -1)
* INTVAL (XEXP (SET_SRC (x), 1)));
int regno = REGNO (SET_DEST (x));
@@ -2691,10 +2860,9 @@ try_pre_increment_1 (insn)
if (y != 0
&& BLOCK_NUM (y) == BLOCK_NUM (insn)
/* Don't do this if the reg dies, or gets set in y; a standard addressing
- mode would be better. */
+ mode would be better. */
&& ! dead_or_set_p (y, SET_DEST (x))
- && try_pre_increment (y, SET_DEST (PATTERN (insn)),
- amount))
+ && try_pre_increment (y, SET_DEST (x), amount))
{
/* We have found a suitable auto-increment
and already changed insn Y to do it.
@@ -2708,8 +2876,8 @@ try_pre_increment_1 (insn)
less likely. */
if (regno >= FIRST_PSEUDO_REGISTER)
{
- reg_n_refs[regno] += loop_depth;
- reg_n_sets[regno]++;
+ REG_N_REFS (regno) += loop_depth;
+ REG_N_SETS (regno)++;
}
return 1;
}
@@ -2788,14 +2956,14 @@ try_pre_increment (insn, reg, amount)
/* See if this combination of instruction and addressing mode exists. */
if (! validate_change (insn, &XEXP (use, 0),
- gen_rtx (amount > 0
- ? (do_post ? POST_INC : PRE_INC)
- : (do_post ? POST_DEC : PRE_DEC),
- Pmode, reg), 0))
+ gen_rtx_fmt_e (amount > 0
+ ? (do_post ? POST_INC : PRE_INC)
+ : (do_post ? POST_DEC : PRE_DEC),
+ Pmode, reg), 0))
return 0;
/* Record that this insn now has an implicit side effect on X. */
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_INC, reg, REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, reg, REG_NOTES (insn));
return 1;
}
@@ -2810,7 +2978,7 @@ try_pre_increment (insn, reg, amount)
If REG appears more than once, or is used other than in such an address,
return (rtx)1. */
-static rtx
+rtx
find_use_as_address (x, reg, plusconst)
register rtx x;
rtx reg;
@@ -2882,19 +3050,24 @@ dump_flow_info (file)
fprintf (file, "%d registers.\n", max_regno);
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_n_refs[i])
+ if (REG_N_REFS (i))
{
enum reg_class class, altclass;
fprintf (file, "\nRegister %d used %d times across %d insns",
- i, reg_n_refs[i], reg_live_length[i]);
- if (reg_basic_block[i] >= 0)
- fprintf (file, " in block %d", reg_basic_block[i]);
- if (reg_n_deaths[i] != 1)
- fprintf (file, "; dies in %d places", reg_n_deaths[i]);
- if (reg_n_calls_crossed[i] == 1)
+ i, REG_N_REFS (i), REG_LIVE_LENGTH (i));
+ if (REG_BASIC_BLOCK (i) >= 0)
+ fprintf (file, " in block %d", REG_BASIC_BLOCK (i));
+ if (REG_N_SETS (i))
+ fprintf (file, "; set %d time%s", REG_N_SETS (i),
+ (REG_N_SETS (i) == 1) ? "" : "s");
+ if (REG_USERVAR_P (regno_reg_rtx[i]))
+ fprintf (file, "; user var");
+ if (REG_N_DEATHS (i) != 1)
+ fprintf (file, "; dies in %d places", REG_N_DEATHS (i));
+ if (REG_N_CALLS_CROSSED (i) == 1)
fprintf (file, "; crosses 1 call");
- else if (reg_n_calls_crossed[i])
- fprintf (file, "; crosses %d calls", reg_n_calls_crossed[i]);
+ else if (REG_N_CALLS_CROSSED (i))
+ fprintf (file, "; crosses %d calls", REG_N_CALLS_CROSSED (i));
if (PSEUDO_REGNO_BYTES (i) != UNITS_PER_WORD)
fprintf (file, "; %d bytes", PSEUDO_REGNO_BYTES (i));
class = reg_preferred_class (i);
@@ -2943,14 +3116,1168 @@ dump_flow_info (file)
}
fprintf (file, "\nRegisters live at start:");
for (regno = 0; regno < max_regno; regno++)
+ if (REGNO_REG_SET_P (basic_block_live_at_start[i], regno))
+ fprintf (file, " %d", regno);
+ fprintf (file, "\n");
+ }
+ fprintf (file, "\n");
+}
+
+
+/* Like print_rtl, but also print out live information for the start of each
+ basic block. */
+
+void
+print_rtl_with_bb (outf, rtx_first)
+ FILE *outf;
+ rtx rtx_first;
+{
+ extern int flag_dump_unnumbered;
+ register rtx tmp_rtx;
+
+ if (rtx_first == 0)
+ fprintf (outf, "(nil)\n");
+
+ else
+ {
+ int i, bb;
+ enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
+ int max_uid = get_max_uid ();
+ int *start = (int *) alloca (max_uid * sizeof (int));
+ int *end = (int *) alloca (max_uid * sizeof (int));
+ char *in_bb_p = (char *) alloca (max_uid * sizeof (enum bb_state));
+
+ for (i = 0; i < max_uid; i++)
+ {
+ start[i] = end[i] = -1;
+ in_bb_p[i] = NOT_IN_BB;
+ }
+
+ for (i = n_basic_blocks-1; i >= 0; i--)
+ {
+ rtx x;
+ start[INSN_UID (basic_block_head[i])] = i;
+ end[INSN_UID (basic_block_end[i])] = i;
+ for (x = basic_block_head[i]; x != NULL_RTX; x = NEXT_INSN (x))
+ {
+ in_bb_p[ INSN_UID(x)]
+ = (in_bb_p[ INSN_UID(x)] == NOT_IN_BB)
+ ? IN_ONE_BB : IN_MULTIPLE_BB;
+ if (x == basic_block_end[i])
+ break;
+ }
+ }
+
+ for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
+ {
+ if ((bb = start[INSN_UID (tmp_rtx)]) >= 0)
+ {
+ fprintf (outf, ";; Start of basic block %d, registers live:",
+ bb);
+
+ EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i,
+ {
+ fprintf (outf, " %d", i);
+ if (i < FIRST_PSEUDO_REGISTER)
+ fprintf (outf, " [%s]",
+ reg_names[i]);
+ });
+ putc ('\n', outf);
+ }
+
+ if (in_bb_p[ INSN_UID(tmp_rtx)] == NOT_IN_BB
+ && GET_CODE (tmp_rtx) != NOTE
+ && GET_CODE (tmp_rtx) != BARRIER)
+ fprintf (outf, ";; Insn is not within a basic block\n");
+ else if (in_bb_p[ INSN_UID(tmp_rtx)] == IN_MULTIPLE_BB)
+ fprintf (outf, ";; Insn is in multiple basic blocks\n");
+
+ print_rtl_single (outf, tmp_rtx);
+
+ if ((bb = end[INSN_UID (tmp_rtx)]) >= 0)
+ fprintf (outf, ";; End of basic block %d\n", bb);
+
+ if (! flag_dump_unnumbered
+ || GET_CODE (tmp_rtx) != NOTE || NOTE_LINE_NUMBER (tmp_rtx) < 0)
+ putc ('\n', outf);
+ }
+ }
+}
+
+
+/* Integer list support. */
+
+/* Allocate a node from list *HEAD_PTR. */
+
+static int_list_ptr
+alloc_int_list_node (head_ptr)
+ int_list_block **head_ptr;
+{
+ struct int_list_block *first_blk = *head_ptr;
+
+ if (first_blk == NULL || first_blk->nodes_left <= 0)
+ {
+ first_blk = (struct int_list_block *) xmalloc (sizeof (struct int_list_block));
+ first_blk->nodes_left = INT_LIST_NODES_IN_BLK;
+ first_blk->next = *head_ptr;
+ *head_ptr = first_blk;
+ }
+
+ first_blk->nodes_left--;
+ return &first_blk->nodes[first_blk->nodes_left];
+}
+
+/* Pointer to head of predecessor/successor block list. */
+static int_list_block *pred_int_list_blocks;
+
+/* Add a new node to integer list LIST with value VAL.
+ LIST is a pointer to a list object to allow for different implementations.
+ If *LIST is initially NULL, the list is empty.
+ The caller must not care whether the element is added to the front or
+ to the end of the list (to allow for different implementations). */
+
+static int_list_ptr
+add_int_list_node (blk_list, list, val)
+ int_list_block **blk_list;
+ int_list **list;
+ int val;
+{
+ int_list_ptr p = alloc_int_list_node (blk_list);
+
+ p->val = val;
+ p->next = *list;
+ *list = p;
+ return p;
+}
+
+/* Free the blocks of lists at BLK_LIST. */
+
+void
+free_int_list (blk_list)
+ int_list_block **blk_list;
+{
+ int_list_block *p, *next;
+
+ for (p = *blk_list; p != NULL; p = next)
+ {
+ next = p->next;
+ free (p);
+ }
+
+ /* Mark list as empty for the next function we compile. */
+ *blk_list = NULL;
+}
+
+/* Predecessor/successor computation. */
+
+/* Mark PRED_BB a precessor of SUCC_BB,
+ and conversely SUCC_BB a successor of PRED_BB. */
+
+static void
+add_pred_succ (pred_bb, succ_bb, s_preds, s_succs, num_preds, num_succs)
+ int pred_bb;
+ int succ_bb;
+ int_list_ptr *s_preds;
+ int_list_ptr *s_succs;
+ int *num_preds;
+ int *num_succs;
+{
+ if (succ_bb != EXIT_BLOCK)
+ {
+ add_int_list_node (&pred_int_list_blocks, &s_preds[succ_bb], pred_bb);
+ num_preds[succ_bb]++;
+ }
+ if (pred_bb != ENTRY_BLOCK)
+ {
+ add_int_list_node (&pred_int_list_blocks, &s_succs[pred_bb], succ_bb);
+ num_succs[pred_bb]++;
+ }
+}
+
+/* Compute the predecessors and successors for each block. */
+void
+compute_preds_succs (s_preds, s_succs, num_preds, num_succs)
+ int_list_ptr *s_preds;
+ int_list_ptr *s_succs;
+ int *num_preds;
+ int *num_succs;
+{
+ int bb, clear_local_bb_vars = 0;
+
+ bzero ((char *) s_preds, n_basic_blocks * sizeof (int_list_ptr));
+ bzero ((char *) s_succs, n_basic_blocks * sizeof (int_list_ptr));
+ bzero ((char *) num_preds, n_basic_blocks * sizeof (int));
+ bzero ((char *) num_succs, n_basic_blocks * sizeof (int));
+
+ /* This routine can be called after life analysis; in that case
+ basic_block_drops_in and uid_block_number will not be available
+ and we must recompute their values. */
+ if (basic_block_drops_in == NULL || uid_block_number == NULL)
+ {
+ clear_local_bb_vars = 1;
+ basic_block_drops_in = (char *) alloca (n_basic_blocks);
+ uid_block_number = (int *) alloca ((get_max_uid () + 1) * sizeof (int));
+
+ bzero ((char *) basic_block_drops_in, n_basic_blocks * sizeof (char));
+ bzero ((char *) uid_block_number, n_basic_blocks * sizeof (int));
+
+ /* Scan each basic block setting basic_block_drops_in and
+ uid_block_number as needed. */
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ rtx insn, stop_insn;
+
+ if (bb == 0)
+ stop_insn = NULL_RTX;
+ else
+ stop_insn = basic_block_end[bb-1];
+
+ /* Look backwards from the start of this block. Stop if we
+ hit the start of the function or the end of a previous
+ block. Don't walk backwards through blocks that are just
+ deleted insns! */
+ for (insn = PREV_INSN (basic_block_head[bb]);
+ insn && insn != stop_insn && GET_CODE (insn) == NOTE;
+ insn = PREV_INSN (insn))
+ ;
+
+ /* Never set basic_block_drops_in for the first block. It is
+ implicit.
+
+ If we stopped on anything other than a BARRIER, then this
+ block drops in. */
+ if (bb != 0)
+ basic_block_drops_in[bb] = (insn ? GET_CODE (insn) != BARRIER : 1);
+
+ insn = basic_block_head[bb];
+ while (insn)
+ {
+ BLOCK_NUM (insn) = bb;
+ if (insn == basic_block_end[bb])
+ break;
+ insn = NEXT_INSN (insn);
+ }
+ }
+ }
+
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ rtx head;
+ rtx jump;
+
+ head = BLOCK_HEAD (bb);
+
+ if (GET_CODE (head) == CODE_LABEL)
+ for (jump = LABEL_REFS (head);
+ jump != head;
+ jump = LABEL_NEXTREF (jump))
+ {
+ if (! INSN_DELETED_P (CONTAINING_INSN (jump))
+ && (GET_CODE (CONTAINING_INSN (jump)) != NOTE
+ || (NOTE_LINE_NUMBER (CONTAINING_INSN (jump))
+ != NOTE_INSN_DELETED)))
+ add_pred_succ (BLOCK_NUM (CONTAINING_INSN (jump)), bb,
+ s_preds, s_succs, num_preds, num_succs);
+ }
+
+ jump = BLOCK_END (bb);
+ /* If this is a RETURN insn or a conditional jump in the last
+ basic block, or a non-jump insn in the last basic block, then
+ this block reaches the exit block. */
+ if ((GET_CODE (jump) == JUMP_INSN && GET_CODE (PATTERN (jump)) == RETURN)
+ || (((GET_CODE (jump) == JUMP_INSN
+ && condjump_p (jump) && !simplejump_p (jump))
+ || GET_CODE (jump) != JUMP_INSN)
+ && (bb == n_basic_blocks - 1)))
+ add_pred_succ (bb, EXIT_BLOCK, s_preds, s_succs, num_preds, num_succs);
+
+ if (basic_block_drops_in[bb])
+ add_pred_succ (bb - 1, bb, s_preds, s_succs, num_preds, num_succs);
+ }
+
+ add_pred_succ (ENTRY_BLOCK, 0, s_preds, s_succs, num_preds, num_succs);
+
+
+ /* If we allocated any variables in temporary storage, clear out the
+ pointer to the local storage to avoid dangling pointers. */
+ if (clear_local_bb_vars)
+ {
+ basic_block_drops_in = NULL;
+ uid_block_number = NULL;
+
+ }
+}
+
+void
+dump_bb_data (file, preds, succs)
+ FILE *file;
+ int_list_ptr *preds;
+ int_list_ptr *succs;
+{
+ int bb;
+ int_list_ptr p;
+
+ fprintf (file, "BB data\n\n");
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ fprintf (file, "BB %d, start %d, end %d\n", bb,
+ INSN_UID (BLOCK_HEAD (bb)), INSN_UID (BLOCK_END (bb)));
+ fprintf (file, " preds:");
+ for (p = preds[bb]; p != NULL; p = p->next)
{
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
- if (basic_block_live_at_start[i][offset] & bit)
- fprintf (file, " %d", regno);
+ int pred_bb = INT_LIST_VAL (p);
+ if (pred_bb == ENTRY_BLOCK)
+ fprintf (file, " entry");
+ else
+ fprintf (file, " %d", pred_bb);
+ }
+ fprintf (file, "\n");
+ fprintf (file, " succs:");
+ for (p = succs[bb]; p != NULL; p = p->next)
+ {
+ int succ_bb = INT_LIST_VAL (p);
+ if (succ_bb == EXIT_BLOCK)
+ fprintf (file, " exit");
+ else
+ fprintf (file, " %d", succ_bb);
}
fprintf (file, "\n");
}
fprintf (file, "\n");
}
+
+void
+dump_sbitmap (file, bmap)
+ FILE *file;
+ sbitmap bmap;
+{
+ int i,j,n;
+ int set_size = bmap->size;
+ int total_bits = bmap->n_bits;
+
+ fprintf (file, " ");
+ for (i = n = 0; i < set_size && n < total_bits; i++)
+ {
+ for (j = 0; j < SBITMAP_ELT_BITS && n < total_bits; j++, n++)
+ {
+ if (n != 0 && n % 10 == 0)
+ fprintf (file, " ");
+ fprintf (file, "%d", (bmap->elms[i] & (1L << j)) != 0);
+ }
+ }
+ fprintf (file, "\n");
+}
+
+void
+dump_sbitmap_vector (file, title, subtitle, bmaps, n_maps)
+ FILE *file;
+ char *title, *subtitle;
+ sbitmap *bmaps;
+ int n_maps;
+{
+ int bb;
+
+ fprintf (file, "%s\n", title);
+ for (bb = 0; bb < n_maps; bb++)
+ {
+ fprintf (file, "%s %d\n", subtitle, bb);
+ dump_sbitmap (file, bmaps[bb]);
+ }
+ fprintf (file, "\n");
+}
+
+/* Free basic block data storage. */
+
+void
+free_bb_mem ()
+{
+ free_int_list (&pred_int_list_blocks);
+}
+
+/* Bitmap manipulation routines. */
+
+/* Allocate a simple bitmap of N_ELMS bits. */
+
+sbitmap
+sbitmap_alloc (n_elms)
+ int n_elms;
+{
+ int bytes, size, amt;
+ sbitmap bmap;
+
+ size = SBITMAP_SET_SIZE (n_elms);
+ bytes = size * sizeof (SBITMAP_ELT_TYPE);
+ amt = (sizeof (struct simple_bitmap_def)
+ + bytes - sizeof (SBITMAP_ELT_TYPE));
+ bmap = (sbitmap) xmalloc (amt);
+ bmap->n_bits = n_elms;
+ bmap->size = size;
+ bmap->bytes = bytes;
+ return bmap;
+}
+
+/* Allocate a vector of N_VECS bitmaps of N_ELMS bits. */
+
+sbitmap *
+sbitmap_vector_alloc (n_vecs, n_elms)
+ int n_vecs, n_elms;
+{
+ int i, bytes, offset, elm_bytes, size, amt, vector_bytes;
+ sbitmap *bitmap_vector;
+
+ size = SBITMAP_SET_SIZE (n_elms);
+ bytes = size * sizeof (SBITMAP_ELT_TYPE);
+ elm_bytes = (sizeof (struct simple_bitmap_def)
+ + bytes - sizeof (SBITMAP_ELT_TYPE));
+ vector_bytes = n_vecs * sizeof (sbitmap *);
+
+ /* Round up `vector_bytes' to account for the alignment requirements
+ of an sbitmap. One could allocate the vector-table and set of sbitmaps
+ separately, but that requires maintaining two pointers or creating
+ a cover struct to hold both pointers (so our result is still just
+ one pointer). Neither is a bad idea, but this is simpler for now. */
+ {
+ /* Based on DEFAULT_ALIGNMENT computation in obstack.c. */
+ struct { char x; SBITMAP_ELT_TYPE y; } align;
+ int alignment = (char *) & align.y - & align.x;
+ vector_bytes = (vector_bytes + alignment - 1) & ~ (alignment - 1);
+ }
+
+ amt = vector_bytes + (n_vecs * elm_bytes);
+ bitmap_vector = (sbitmap *) xmalloc (amt);
+
+ for (i = 0, offset = vector_bytes;
+ i < n_vecs;
+ i++, offset += elm_bytes)
+ {
+ sbitmap b = (sbitmap) ((char *) bitmap_vector + offset);
+ bitmap_vector[i] = b;
+ b->n_bits = n_elms;
+ b->size = size;
+ b->bytes = bytes;
+ }
+
+ return bitmap_vector;
+}
+
+/* Copy sbitmap SRC to DST. */
+
+void
+sbitmap_copy (dst, src)
+ sbitmap dst, src;
+{
+ int i;
+ sbitmap_ptr d,s;
+
+ s = src->elms;
+ d = dst->elms;
+ for (i = 0; i < dst->size; i++)
+ *d++ = *s++;
+}
+
+/* Zero all elements in a bitmap. */
+
+void
+sbitmap_zero (bmap)
+ sbitmap bmap;
+{
+ bzero ((char *) bmap->elms, bmap->bytes);
+}
+
+/* Set to ones all elements in a bitmap. */
+
+void
+sbitmap_ones (bmap)
+ sbitmap bmap;
+{
+ memset (bmap->elms, -1, bmap->bytes);
+}
+
+/* Zero a vector of N_VECS bitmaps. */
+
+void
+sbitmap_vector_zero (bmap, n_vecs)
+ sbitmap *bmap;
+ int n_vecs;
+{
+ int i;
+
+ for (i = 0; i < n_vecs; i++)
+ sbitmap_zero (bmap[i]);
+}
+
+/* Set to ones a vector of N_VECS bitmaps. */
+
+void
+sbitmap_vector_ones (bmap, n_vecs)
+ sbitmap *bmap;
+ int n_vecs;
+{
+ int i;
+
+ for (i = 0; i < n_vecs; i++)
+ sbitmap_ones (bmap[i]);
+}
+
+/* Set DST to be A union (B - C).
+ DST = A | (B & ~C).
+ Return non-zero if any change is made. */
+
+int
+sbitmap_union_of_diff (dst, a, b, c)
+ sbitmap dst, a, b, c;
+{
+ int i,changed;
+ sbitmap_ptr dstp, ap, bp, cp;
+
+ changed = 0;
+ dstp = dst->elms;
+ ap = a->elms;
+ bp = b->elms;
+ cp = c->elms;
+ for (i = 0; i < dst->size; i++)
+ {
+ SBITMAP_ELT_TYPE tmp = *ap | (*bp & ~*cp);
+ if (*dstp != tmp)
+ changed = 1;
+ *dstp = tmp;
+ dstp++; ap++; bp++; cp++;
+ }
+ return changed;
+}
+
+/* Set bitmap DST to the bitwise negation of the bitmap SRC. */
+
+void
+sbitmap_not (dst, src)
+ sbitmap dst, src;
+{
+ int i;
+ sbitmap_ptr dstp, ap;
+
+ dstp = dst->elms;
+ ap = src->elms;
+ for (i = 0; i < dst->size; i++)
+ {
+ SBITMAP_ELT_TYPE tmp = ~(*ap);
+ *dstp = tmp;
+ dstp++; ap++;
+ }
+}
+
+/* Set the bits in DST to be the difference between the bits
+ in A and the bits in B. i.e. dst = a - b.
+ The - operator is implemented as a & (~b). */
+
+void
+sbitmap_difference (dst, a, b)
+ sbitmap dst, a, b;
+{
+ int i;
+ sbitmap_ptr dstp, ap, bp;
+
+ dstp = dst->elms;
+ ap = a->elms;
+ bp = b->elms;
+ for (i = 0; i < dst->size; i++)
+ *dstp++ = *ap++ & (~*bp++);
+}
+
+/* Set DST to be (A and B)).
+ Return non-zero if any change is made. */
+
+int
+sbitmap_a_and_b (dst, a, b)
+ sbitmap dst, a, b;
+{
+ int i,changed;
+ sbitmap_ptr dstp, ap, bp;
+
+ changed = 0;
+ dstp = dst->elms;
+ ap = a->elms;
+ bp = b->elms;
+ for (i = 0; i < dst->size; i++)
+ {
+ SBITMAP_ELT_TYPE tmp = *ap & *bp;
+ if (*dstp != tmp)
+ changed = 1;
+ *dstp = tmp;
+ dstp++; ap++; bp++;
+ }
+ return changed;
+}
+/* Set DST to be (A or B)).
+ Return non-zero if any change is made. */
+
+int
+sbitmap_a_or_b (dst, a, b)
+ sbitmap dst, a, b;
+{
+ int i,changed;
+ sbitmap_ptr dstp, ap, bp;
+
+ changed = 0;
+ dstp = dst->elms;
+ ap = a->elms;
+ bp = b->elms;
+ for (i = 0; i < dst->size; i++)
+ {
+ SBITMAP_ELT_TYPE tmp = *ap | *bp;
+ if (*dstp != tmp)
+ changed = 1;
+ *dstp = tmp;
+ dstp++; ap++; bp++;
+ }
+ return changed;
+}
+
+/* Set DST to be (A or (B and C)).
+ Return non-zero if any change is made. */
+
+int
+sbitmap_a_or_b_and_c (dst, a, b, c)
+ sbitmap dst, a, b, c;
+{
+ int i,changed;
+ sbitmap_ptr dstp, ap, bp, cp;
+
+ changed = 0;
+ dstp = dst->elms;
+ ap = a->elms;
+ bp = b->elms;
+ cp = c->elms;
+ for (i = 0; i < dst->size; i++)
+ {
+ SBITMAP_ELT_TYPE tmp = *ap | (*bp & *cp);
+ if (*dstp != tmp)
+ changed = 1;
+ *dstp = tmp;
+ dstp++; ap++; bp++; cp++;
+ }
+ return changed;
+}
+
+/* Set DST to be (A ann (B or C)).
+ Return non-zero if any change is made. */
+
+int
+sbitmap_a_and_b_or_c (dst, a, b, c)
+ sbitmap dst, a, b, c;
+{
+ int i,changed;
+ sbitmap_ptr dstp, ap, bp, cp;
+
+ changed = 0;
+ dstp = dst->elms;
+ ap = a->elms;
+ bp = b->elms;
+ cp = c->elms;
+ for (i = 0; i < dst->size; i++)
+ {
+ SBITMAP_ELT_TYPE tmp = *ap & (*bp | *cp);
+ if (*dstp != tmp)
+ changed = 1;
+ *dstp = tmp;
+ dstp++; ap++; bp++; cp++;
+ }
+ return changed;
+}
+
+/* Set the bitmap DST to the intersection of SRC of all predecessors or
+ successors of block number BB (PRED_SUCC says which). */
+
+void
+sbitmap_intersect_of_predsucc (dst, src, bb, pred_succ)
+ sbitmap dst;
+ sbitmap *src;
+ int bb;
+ int_list_ptr *pred_succ;
+{
+ int_list_ptr ps;
+ int ps_bb;
+ int set_size = dst->size;
+
+ ps = pred_succ[bb];
+
+ /* It is possible that there are no predecessors(/successors).
+ This can happen for example in unreachable code. */
+
+ if (ps == NULL)
+ {
+ /* In APL-speak this is the `and' reduction of the empty set and thus
+ the result is the identity for `and'. */
+ sbitmap_ones (dst);
+ return;
+ }
+
+ /* Set result to first predecessor/successor. */
+
+ for ( ; ps != NULL; ps = ps->next)
+ {
+ ps_bb = INT_LIST_VAL (ps);
+ if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
+ continue;
+ sbitmap_copy (dst, src[ps_bb]);
+ /* Break out since we're only doing first predecessor. */
+ break;
+ }
+ if (ps == NULL)
+ return;
+
+ /* Now do the remaining predecessors/successors. */
+
+ for (ps = ps->next; ps != NULL; ps = ps->next)
+ {
+ int i;
+ sbitmap_ptr p,r;
+
+ ps_bb = INT_LIST_VAL (ps);
+ if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
+ continue;
+
+ p = src[ps_bb]->elms;
+ r = dst->elms;
+
+ for (i = 0; i < set_size; i++)
+ *r++ &= *p++;
+ }
+}
+
+/* Set the bitmap DST to the intersection of SRC of all predecessors
+ of block number BB. */
+
+void
+sbitmap_intersect_of_predecessors (dst, src, bb, s_preds)
+ sbitmap dst;
+ sbitmap *src;
+ int bb;
+ int_list_ptr *s_preds;
+{
+ sbitmap_intersect_of_predsucc (dst, src, bb, s_preds);
+}
+
+/* Set the bitmap DST to the intersection of SRC of all successors
+ of block number BB. */
+
+void
+sbitmap_intersect_of_successors (dst, src, bb, s_succs)
+ sbitmap dst;
+ sbitmap *src;
+ int bb;
+ int_list_ptr *s_succs;
+{
+ sbitmap_intersect_of_predsucc (dst, src, bb, s_succs);
+}
+
+/* Set the bitmap DST to the union of SRC of all predecessors/successors of
+ block number BB. */
+
+void
+sbitmap_union_of_predsucc (dst, src, bb, pred_succ)
+ sbitmap dst;
+ sbitmap *src;
+ int bb;
+ int_list_ptr *pred_succ;
+{
+ int_list_ptr ps;
+ int ps_bb;
+ int set_size = dst->size;
+
+ ps = pred_succ[bb];
+
+ /* It is possible that there are no predecessors(/successors).
+ This can happen for example in unreachable code. */
+
+ if (ps == NULL)
+ {
+ /* In APL-speak this is the `or' reduction of the empty set and thus
+ the result is the identity for `or'. */
+ sbitmap_zero (dst);
+ return;
+ }
+
+ /* Set result to first predecessor/successor. */
+
+ for ( ; ps != NULL; ps = ps->next)
+ {
+ ps_bb = INT_LIST_VAL (ps);
+ if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
+ continue;
+ sbitmap_copy (dst, src[ps_bb]);
+ /* Break out since we're only doing first predecessor. */
+ break;
+ }
+ if (ps == NULL)
+ return;
+
+ /* Now do the remaining predecessors/successors. */
+
+ for (ps = ps->next; ps != NULL; ps = ps->next)
+ {
+ int i;
+ sbitmap_ptr p,r;
+
+ ps_bb = INT_LIST_VAL (ps);
+ if (ps_bb == ENTRY_BLOCK || ps_bb == EXIT_BLOCK)
+ continue;
+
+ p = src[ps_bb]->elms;
+ r = dst->elms;
+
+ for (i = 0; i < set_size; i++)
+ *r++ |= *p++;
+ }
+}
+
+/* Set the bitmap DST to the union of SRC of all predecessors of
+ block number BB. */
+
+void
+sbitmap_union_of_predecessors (dst, src, bb, s_preds)
+ sbitmap dst;
+ sbitmap *src;
+ int bb;
+ int_list_ptr *s_preds;
+{
+ sbitmap_union_of_predsucc (dst, src, bb, s_preds);
+}
+
+/* Set the bitmap DST to the union of SRC of all predecessors of
+ block number BB. */
+
+void
+sbitmap_union_of_successors (dst, src, bb, s_succ)
+ sbitmap dst;
+ sbitmap *src;
+ int bb;
+ int_list_ptr *s_succ;
+{
+ sbitmap_union_of_predsucc (dst, src, bb, s_succ);
+}
+
+/* Compute dominator relationships. */
+void
+compute_dominators (dominators, post_dominators, s_preds, s_succs)
+ sbitmap *dominators;
+ sbitmap *post_dominators;
+ int_list_ptr *s_preds;
+ int_list_ptr *s_succs;
+{
+ int bb, changed, passes;
+ sbitmap *temp_bitmap;
+
+ temp_bitmap = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
+ sbitmap_vector_ones (dominators, n_basic_blocks);
+ sbitmap_vector_ones (post_dominators, n_basic_blocks);
+ sbitmap_vector_zero (temp_bitmap, n_basic_blocks);
+
+ sbitmap_zero (dominators[0]);
+ SET_BIT (dominators[0], 0);
+
+ sbitmap_zero (post_dominators[n_basic_blocks-1]);
+ SET_BIT (post_dominators[n_basic_blocks-1], 0);
+
+ passes = 0;
+ changed = 1;
+ while (changed)
+ {
+ changed = 0;
+ for (bb = 1; bb < n_basic_blocks; bb++)
+ {
+ sbitmap_intersect_of_predecessors (temp_bitmap[bb], dominators,
+ bb, s_preds);
+ SET_BIT (temp_bitmap[bb], bb);
+ changed |= sbitmap_a_and_b (dominators[bb],
+ dominators[bb],
+ temp_bitmap[bb]);
+ sbitmap_intersect_of_successors (temp_bitmap[bb], post_dominators,
+ bb, s_succs);
+ SET_BIT (temp_bitmap[bb], bb);
+ changed |= sbitmap_a_and_b (post_dominators[bb],
+ post_dominators[bb],
+ temp_bitmap[bb]);
+ }
+ passes++;
+ }
+
+ free (temp_bitmap);
+}
+
+/* Count for a single SET rtx, X. */
+
+static void
+count_reg_sets_1 (x)
+ rtx x;
+{
+ register int regno;
+ register rtx reg = SET_DEST (x);
+
+ /* Find the register that's set/clobbered. */
+ while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
+ || GET_CODE (reg) == SIGN_EXTRACT
+ || GET_CODE (reg) == STRICT_LOW_PART)
+ reg = XEXP (reg, 0);
+
+ if (GET_CODE (reg) == REG)
+ {
+ regno = REGNO (reg);
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ /* Count (weighted) references, stores, etc. This counts a
+ register twice if it is modified, but that is correct. */
+ REG_N_SETS (regno)++;
+
+ REG_N_REFS (regno) += loop_depth;
+ }
+ }
+}
+
+/* Increment REG_N_SETS for each SET or CLOBBER found in X; also increment
+ REG_N_REFS by the current loop depth for each SET or CLOBBER found. */
+
+static void
+count_reg_sets (x)
+ rtx x;
+{
+ register RTX_CODE code = GET_CODE (x);
+
+ if (code == SET || code == CLOBBER)
+ count_reg_sets_1 (x);
+ else if (code == PARALLEL)
+ {
+ register int i;
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ {
+ code = GET_CODE (XVECEXP (x, 0, i));
+ if (code == SET || code == CLOBBER)
+ count_reg_sets_1 (XVECEXP (x, 0, i));
+ }
+ }
+}
+
+/* Increment REG_N_REFS by the current loop depth each register reference
+ found in X. */
+
+static void
+count_reg_references (x)
+ rtx x;
+{
+ register RTX_CODE code;
+ register int regno;
+ int i;
+
+ retry:
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST_INT:
+ case CONST:
+ case CONST_DOUBLE:
+ case PC:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ case ASM_INPUT:
+ return;
+
+#ifdef HAVE_cc0
+ case CC0:
+ return;
+#endif
+
+ case CLOBBER:
+ /* If we are clobbering a MEM, mark any registers inside the address
+ as being used. */
+ if (GET_CODE (XEXP (x, 0)) == MEM)
+ count_reg_references (XEXP (XEXP (x, 0), 0));
+ return;
+
+ case SUBREG:
+ /* While we're here, optimize this case. */
+ x = SUBREG_REG (x);
+
+ /* In case the SUBREG is not of a register, don't optimize */
+ if (GET_CODE (x) != REG)
+ {
+ count_reg_references (x);
+ return;
+ }
+
+ /* ... fall through ... */
+
+ case REG:
+ if (REGNO (x) >= FIRST_PSEUDO_REGISTER)
+ REG_N_REFS (REGNO (x)) += loop_depth;
+ return;
+
+ case SET:
+ {
+ register rtx testreg = SET_DEST (x);
+ int mark_dest = 0;
+
+ /* If storing into MEM, don't show it as being used. But do
+ show the address as being used. */
+ if (GET_CODE (testreg) == MEM)
+ {
+ count_reg_references (XEXP (testreg, 0));
+ count_reg_references (SET_SRC (x));
+ return;
+ }
+
+ /* Storing in STRICT_LOW_PART is like storing in a reg
+ in that this SET might be dead, so ignore it in TESTREG.
+ but in some other ways it is like using the reg.
+
+ Storing in a SUBREG or a bit field is like storing the entire
+ register in that if the register's value is not used
+ then this SET is not needed. */
+ while (GET_CODE (testreg) == STRICT_LOW_PART
+ || GET_CODE (testreg) == ZERO_EXTRACT
+ || GET_CODE (testreg) == SIGN_EXTRACT
+ || GET_CODE (testreg) == SUBREG)
+ {
+ /* Modifying a single register in an alternate mode
+ does not use any of the old value. But these other
+ ways of storing in a register do use the old value. */
+ if (GET_CODE (testreg) == SUBREG
+ && !(REG_SIZE (SUBREG_REG (testreg)) > REG_SIZE (testreg)))
+ ;
+ else
+ mark_dest = 1;
+
+ testreg = XEXP (testreg, 0);
+ }
+
+ /* If this is a store into a register,
+ recursively scan the value being stored. */
+
+ if (GET_CODE (testreg) == REG)
+ {
+ count_reg_references (SET_SRC (x));
+ if (mark_dest)
+ count_reg_references (SET_DEST (x));
+ return;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /* Recursively scan the operands of this expression. */
+
+ {
+ register char *fmt = GET_RTX_FORMAT (code);
+ register int i;
+
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ /* Tail recursive case: save a function call level. */
+ if (i == 0)
+ {
+ x = XEXP (x, 0);
+ goto retry;
+ }
+ count_reg_references (XEXP (x, i));
+ }
+ else if (fmt[i] == 'E')
+ {
+ register int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ count_reg_references (XVECEXP (x, i, j));
+ }
+ }
+ }
+}
+
+/* Recompute register set/reference counts immediately prior to register
+ allocation.
+
+ This avoids problems with set/reference counts changing to/from values
+ which have special meanings to the register allocators.
+
+ Additionally, the reference counts are the primary component used by the
+ register allocators to prioritize pseudos for allocation to hard regs.
+ More accurate reference counts generally lead to better register allocation.
+
+ It might be worthwhile to update REG_LIVE_LENGTH, REG_BASIC_BLOCK and
+ possibly other information which is used by the register allocators. */
+
+void
+recompute_reg_usage (f)
+ rtx f;
+{
+ rtx insn;
+ int i, max_reg;
+
+ /* Clear out the old data. */
+ max_reg = max_reg_num ();
+ for (i = FIRST_PSEUDO_REGISTER; i < max_reg; i++)
+ {
+ REG_N_SETS (i) = 0;
+ REG_N_REFS (i) = 0;
+ }
+
+ /* Scan each insn in the chain and count how many times each register is
+ set/used. */
+ loop_depth = 1;
+ for (insn = f; insn; insn = NEXT_INSN (insn))
+ {
+ /* Keep track of loop depth. */
+ if (GET_CODE (insn) == NOTE)
+ {
+ /* Look for loop boundaries. */
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+ loop_depth--;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+ loop_depth++;
+
+ /* If we have LOOP_DEPTH == 0, there has been a bookkeeping error.
+ Abort now rather than setting register status incorrectly. */
+ if (loop_depth == 0)
+ abort ();
+ }
+ else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ rtx links;
+
+ /* This call will increment REG_N_SETS for each SET or CLOBBER
+ of a register in INSN. It will also increment REG_N_REFS
+ by the loop depth for each set of a register in INSN. */
+ count_reg_sets (PATTERN (insn));
+
+ /* count_reg_sets does not detect autoincrement address modes, so
+ detect them here by looking at the notes attached to INSN. */
+ for (links = REG_NOTES (insn); links; links = XEXP (links, 1))
+ {
+ if (REG_NOTE_KIND (links) == REG_INC)
+ /* Count (weighted) references, stores, etc. This counts a
+ register twice if it is modified, but that is correct. */
+ REG_N_SETS (REGNO (XEXP (links, 0)))++;
+ }
+
+ /* This call will increment REG_N_REFS by the current loop depth for
+ each reference to a register in INSN. */
+ count_reg_references (PATTERN (insn));
+
+ /* count_reg_references will not include counts for arguments to
+ function calls, so detect them here by examining the
+ CALL_INSN_FUNCTION_USAGE data. */
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ rtx note;
+
+ for (note = CALL_INSN_FUNCTION_USAGE (insn);
+ note;
+ note = XEXP (note, 1))
+ if (GET_CODE (XEXP (note, 0)) == USE)
+ count_reg_references (SET_DEST (XEXP (note, 0)));
+ }
+ }
+ }
+}
diff --git a/contrib/gcc/fold-const.c b/contrib/gcc/fold-const.c
index cf57a37..926e1eb 100644
--- a/contrib/gcc/fold-const.c
+++ b/contrib/gcc/fold-const.c
@@ -1,5 +1,5 @@
/* Fold a constant sub-tree into a single node for C-compiler
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -27,7 +27,8 @@ Boston, MA 02111-1307, USA. */
@@ for cross-compilers. */
-/* The entry points in this file are fold, size_int and size_binop.
+/* The entry points in this file are fold, size_int_wide, size_binop
+ and force_fit_type.
fold takes a tree as argument and returns a simplified tree.
@@ -36,57 +37,69 @@ Boston, MA 02111-1307, USA. */
result, assuming the type comes from `sizetype'.
size_int takes an integer value, and creates a tree constant
- with type from `sizetype'. */
-
-#include <stdio.h>
-#include <setjmp.h>
+ with type from `sizetype'.
+
+ force_fit_type takes a constant and prior overflow indicator, and
+ forces the value to fit the type. It returns an overflow indicator. */
+
#include "config.h"
+#include "system.h"
+#include <setjmp.h>
#include "flags.h"
#include "tree.h"
+#include "toplev.h"
/* Handle floating overflow for `const_binop'. */
static jmp_buf float_error;
-static void encode PROTO((HOST_WIDE_INT *, HOST_WIDE_INT, HOST_WIDE_INT));
-static void decode PROTO((HOST_WIDE_INT *, HOST_WIDE_INT *, HOST_WIDE_INT *));
-int div_and_round_double PROTO((enum tree_code, int, HOST_WIDE_INT,
+static void encode PROTO((HOST_WIDE_INT *,
+ HOST_WIDE_INT, HOST_WIDE_INT));
+static void decode PROTO((HOST_WIDE_INT *,
+ HOST_WIDE_INT *, HOST_WIDE_INT *));
+int div_and_round_double PROTO((enum tree_code, int, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT *,
HOST_WIDE_INT *, HOST_WIDE_INT *,
HOST_WIDE_INT *));
-static int split_tree PROTO((tree, enum tree_code, tree *, tree *, int *));
-static tree const_binop PROTO((enum tree_code, tree, tree, int));
-static tree fold_convert PROTO((tree, tree));
+static int split_tree PROTO((tree, enum tree_code, tree *,
+ tree *, int *));
+static tree int_const_binop PROTO((enum tree_code, tree, tree, int, int));
+static tree const_binop PROTO((enum tree_code, tree, tree, int));
+static tree fold_convert PROTO((tree, tree));
static enum tree_code invert_tree_comparison PROTO((enum tree_code));
static enum tree_code swap_tree_comparison PROTO((enum tree_code));
-static int truth_value_p PROTO((enum tree_code));
+static int truth_value_p PROTO((enum tree_code));
static int operand_equal_for_comparison_p PROTO((tree, tree, tree));
-static int twoval_comparison_p PROTO((tree, tree *, tree *, int *));
-static tree eval_subst PROTO((tree, tree, tree, tree, tree));
-static tree omit_one_operand PROTO((tree, tree, tree));
+static int twoval_comparison_p PROTO((tree, tree *, tree *, int *));
+static tree eval_subst PROTO((tree, tree, tree, tree, tree));
+static tree omit_one_operand PROTO((tree, tree, tree));
static tree pedantic_omit_one_operand PROTO((tree, tree, tree));
static tree distribute_bit_expr PROTO((enum tree_code, tree, tree, tree));
-static tree make_bit_field_ref PROTO((tree, tree, int, int, int));
+static tree make_bit_field_ref PROTO((tree, tree, int, int, int));
static tree optimize_bit_field_compare PROTO((enum tree_code, tree,
tree, tree));
static tree decode_field_reference PROTO((tree, int *, int *,
enum machine_mode *, int *,
int *, tree *, tree *));
-static int all_ones_mask_p PROTO((tree, int));
-static int simple_operand_p PROTO((tree));
-static tree range_test PROTO((enum tree_code, tree, enum tree_code,
- enum tree_code, tree, tree, tree));
-static tree unextend PROTO((tree, int, int, tree));
-static tree fold_truthop PROTO((enum tree_code, tree, tree, tree));
+static int all_ones_mask_p PROTO((tree, int));
+static int simple_operand_p PROTO((tree));
+static tree range_binop PROTO((enum tree_code, tree, tree, int,
+ tree, int));
+static tree make_range PROTO((tree, int *, tree *, tree *));
+static tree build_range_check PROTO((tree, tree, int, tree, tree));
+static int merge_ranges PROTO((int *, tree *, tree *, int, tree, tree,
+ int, tree, tree));
+static tree fold_range_test PROTO((tree));
+static tree unextend PROTO((tree, int, int, tree));
+static tree fold_truthop PROTO((enum tree_code, tree, tree, tree));
static tree strip_compound_expr PROTO((tree, tree));
+static int multiple_of_p PROTO((tree, tree, tree));
+static tree constant_boolean_node PROTO((int, tree));
#ifndef BRANCH_COST
#define BRANCH_COST 1
#endif
-/* Yield nonzero if a signed left shift of A by B bits overflows. */
-#define left_shift_overflows(a, b) ((a) != ((a) << (b)) >> (b))
-
/* Suppose A1 + B1 = SUM1, using 2's complement arithmetic ignoring overflow.
Suppose A, B and SUM have the same respective signs as A1, B1, and SUM1.
Then this yields nonzero if overflow occurred during the addition.
@@ -165,7 +178,7 @@ force_fit_type (t, overflow)
low = TREE_INT_CST_LOW (t);
high = TREE_INT_CST_HIGH (t);
- if (TREE_CODE (TREE_TYPE (t)) == POINTER_TYPE)
+ if (POINTER_TYPE_P (TREE_TYPE (t)))
prec = POINTER_SIZE;
else
prec = TYPE_PRECISION (TREE_TYPE (t));
@@ -345,13 +358,13 @@ lshift_double (l1, h1, count, prec, lv, hv, arith)
if (count >= HOST_BITS_PER_WIDE_INT)
{
- *hv = (unsigned HOST_WIDE_INT) l1 << count - HOST_BITS_PER_WIDE_INT;
+ *hv = (unsigned HOST_WIDE_INT) l1 << (count - HOST_BITS_PER_WIDE_INT);
*lv = 0;
}
else
{
*hv = (((unsigned HOST_WIDE_INT) h1 << count)
- | ((unsigned HOST_WIDE_INT) l1 >> HOST_BITS_PER_WIDE_INT - count - 1 >> 1));
+ | ((unsigned HOST_WIDE_INT) l1 >> (HOST_BITS_PER_WIDE_INT - count - 1) >> 1));
*lv = (unsigned HOST_WIDE_INT) l1 << count;
}
}
@@ -381,14 +394,14 @@ rshift_double (l1, h1, count, prec, lv, hv, arith)
if (count >= HOST_BITS_PER_WIDE_INT)
{
*hv = signmask;
- *lv = ((signmask << 2 * HOST_BITS_PER_WIDE_INT - count - 1 << 1)
- | ((unsigned HOST_WIDE_INT) h1 >> count - HOST_BITS_PER_WIDE_INT));
+ *lv = ((signmask << (2 * HOST_BITS_PER_WIDE_INT - count - 1) << 1)
+ | ((unsigned HOST_WIDE_INT) h1 >> (count - HOST_BITS_PER_WIDE_INT)));
}
else
{
*lv = (((unsigned HOST_WIDE_INT) l1 >> count)
- | ((unsigned HOST_WIDE_INT) h1 << HOST_BITS_PER_WIDE_INT - count - 1 << 1));
- *hv = ((signmask << HOST_BITS_PER_WIDE_INT - count)
+ | ((unsigned HOST_WIDE_INT) h1 << (HOST_BITS_PER_WIDE_INT - count - 1) << 1));
+ *hv = ((signmask << (HOST_BITS_PER_WIDE_INT - count))
| ((unsigned HOST_WIDE_INT) h1 >> count));
}
}
@@ -470,7 +483,7 @@ div_and_round_double (code, uns,
int overflow = 0;
if ((hden == 0) && (lden == 0))
- abort ();
+ overflow = 1, lden = 1;
/* calculate quotient sign and convert operands to unsigned. */
if (!uns)
@@ -862,6 +875,94 @@ target_negative (x)
return x < 0;
}
#endif /* Target not IEEE */
+
+/* Try to change R into its exact multiplicative inverse in machine mode
+ MODE. Return nonzero function value if successful. */
+
+int
+exact_real_inverse (mode, r)
+ enum machine_mode mode;
+ REAL_VALUE_TYPE *r;
+{
+ union
+ {
+ double d;
+ unsigned short i[4];
+ }x, t, y;
+ int i;
+
+ /* Usually disable if bounds checks are not reliable. */
+ if ((HOST_FLOAT_FORMAT != TARGET_FLOAT_FORMAT) && !flag_pretend_float)
+ return 0;
+
+ /* Set array index to the less significant bits in the unions, depending
+ on the endian-ness of the host doubles.
+ Disable if insufficient information on the data structure. */
+#if HOST_FLOAT_FORMAT == UNKNOWN_FLOAT_FORMAT
+ return 0;
+#else
+#if HOST_FLOAT_FORMAT == VAX_FLOAT_FORMAT
+#define K 2
+#else
+#if HOST_FLOAT_FORMAT == IBM_FLOAT_FORMAT
+#define K 2
+#else
+#define K (2 * HOST_FLOAT_WORDS_BIG_ENDIAN)
+#endif
+#endif
+#endif
+
+ if (setjmp (float_error))
+ {
+ /* Don't do the optimization if there was an arithmetic error. */
+fail:
+ set_float_handler (NULL_PTR);
+ return 0;
+ }
+ set_float_handler (float_error);
+
+ /* Domain check the argument. */
+ x.d = *r;
+ if (x.d == 0.0)
+ goto fail;
+
+#ifdef REAL_INFINITY
+ if (REAL_VALUE_ISINF (x.d) || REAL_VALUE_ISNAN (x.d))
+ goto fail;
+#endif
+
+ /* Compute the reciprocal and check for numerical exactness.
+ It is unnecessary to check all the significand bits to determine
+ whether X is a power of 2. If X is not, then it is impossible for
+ the bottom half significand of both X and 1/X to be all zero bits.
+ Hence we ignore the data structure of the top half and examine only
+ the low order bits of the two significands. */
+ t.d = 1.0 / x.d;
+ if (x.i[K] != 0 || x.i[K + 1] != 0 || t.i[K] != 0 || t.i[K + 1] != 0)
+ goto fail;
+
+ /* Truncate to the required mode and range-check the result. */
+ y.d = REAL_VALUE_TRUNCATE (mode, t.d);
+#ifdef CHECK_FLOAT_VALUE
+ i = 0;
+ if (CHECK_FLOAT_VALUE (mode, y.d, i))
+ goto fail;
+#endif
+
+ /* Fail if truncation changed the value. */
+ if (y.d != t.d || y.d == 0.0)
+ goto fail;
+
+#ifdef REAL_INFINITY
+ if (REAL_VALUE_ISINF (y.d) || REAL_VALUE_ISNAN (y.d))
+ goto fail;
+#endif
+
+ /* Output the reciprocal and return success flag. */
+ set_float_handler (NULL_PTR);
+ *r = y.d;
+ return 1;
+}
#endif /* no REAL_ARITHMETIC */
/* Split a tree IN into a constant and a variable part
@@ -953,200 +1054,217 @@ split_tree (in, code, varp, conp, varsignp)
return 0;
}
-/* Combine two constants NUM and ARG2 under operation CODE
+/* Combine two integer constants ARG1 and ARG2 under operation CODE
to produce a new constant.
- We assume ARG1 and ARG2 have the same data type,
- or at least are the same kind of constant and the same machine mode.
- If NOTRUNC is nonzero, do not truncate the result to fit the data type. */
+ If NOTRUNC is nonzero, do not truncate the result to fit the data type.
+ If FORSIZE is nonzero, compute overflow for unsigned types. */
static tree
-const_binop (code, arg1, arg2, notrunc)
+int_const_binop (code, arg1, arg2, notrunc, forsize)
enum tree_code code;
register tree arg1, arg2;
- int notrunc;
+ int notrunc, forsize;
{
- if (TREE_CODE (arg1) == INTEGER_CST)
+ HOST_WIDE_INT int1l, int1h, int2l, int2h;
+ HOST_WIDE_INT low, hi;
+ HOST_WIDE_INT garbagel, garbageh;
+ register tree t;
+ int uns = TREE_UNSIGNED (TREE_TYPE (arg1));
+ int overflow = 0;
+ int no_overflow = 0;
+
+ int1l = TREE_INT_CST_LOW (arg1);
+ int1h = TREE_INT_CST_HIGH (arg1);
+ int2l = TREE_INT_CST_LOW (arg2);
+ int2h = TREE_INT_CST_HIGH (arg2);
+
+ switch (code)
{
- register HOST_WIDE_INT int1l = TREE_INT_CST_LOW (arg1);
- register HOST_WIDE_INT int1h = TREE_INT_CST_HIGH (arg1);
- HOST_WIDE_INT int2l = TREE_INT_CST_LOW (arg2);
- HOST_WIDE_INT int2h = TREE_INT_CST_HIGH (arg2);
- HOST_WIDE_INT low, hi;
- HOST_WIDE_INT garbagel, garbageh;
- register tree t;
- int uns = TREE_UNSIGNED (TREE_TYPE (arg1));
- int overflow = 0;
+ case BIT_IOR_EXPR:
+ low = int1l | int2l, hi = int1h | int2h;
+ break;
- switch (code)
- {
- case BIT_IOR_EXPR:
- t = build_int_2 (int1l | int2l, int1h | int2h);
- break;
+ case BIT_XOR_EXPR:
+ low = int1l ^ int2l, hi = int1h ^ int2h;
+ break;
- case BIT_XOR_EXPR:
- t = build_int_2 (int1l ^ int2l, int1h ^ int2h);
- break;
+ case BIT_AND_EXPR:
+ low = int1l & int2l, hi = int1h & int2h;
+ break;
- case BIT_AND_EXPR:
- t = build_int_2 (int1l & int2l, int1h & int2h);
- break;
+ case BIT_ANDTC_EXPR:
+ low = int1l & ~int2l, hi = int1h & ~int2h;
+ break;
- case BIT_ANDTC_EXPR:
- t = build_int_2 (int1l & ~int2l, int1h & ~int2h);
- break;
+ case RSHIFT_EXPR:
+ int2l = - int2l;
+ case LSHIFT_EXPR:
+ /* It's unclear from the C standard whether shifts can overflow.
+ The following code ignores overflow; perhaps a C standard
+ interpretation ruling is needed. */
+ lshift_double (int1l, int1h, int2l,
+ TYPE_PRECISION (TREE_TYPE (arg1)),
+ &low, &hi,
+ !uns);
+ no_overflow = 1;
+ break;
- case RSHIFT_EXPR:
- int2l = - int2l;
- case LSHIFT_EXPR:
- /* It's unclear from the C standard whether shifts can overflow.
- The following code ignores overflow; perhaps a C standard
- interpretation ruling is needed. */
- lshift_double (int1l, int1h, int2l,
- TYPE_PRECISION (TREE_TYPE (arg1)),
- &low, &hi,
- !uns);
- t = build_int_2 (low, hi);
- TREE_TYPE (t) = TREE_TYPE (arg1);
- if (!notrunc)
- force_fit_type (t, 0);
- TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2);
- TREE_CONSTANT_OVERFLOW (t)
- = TREE_CONSTANT_OVERFLOW (arg1) | TREE_CONSTANT_OVERFLOW (arg2);
- return t;
+ case RROTATE_EXPR:
+ int2l = - int2l;
+ case LROTATE_EXPR:
+ lrotate_double (int1l, int1h, int2l,
+ TYPE_PRECISION (TREE_TYPE (arg1)),
+ &low, &hi);
+ break;
- case RROTATE_EXPR:
- int2l = - int2l;
- case LROTATE_EXPR:
- lrotate_double (int1l, int1h, int2l,
- TYPE_PRECISION (TREE_TYPE (arg1)),
- &low, &hi);
- t = build_int_2 (low, hi);
- break;
+ case PLUS_EXPR:
+ overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi);
+ break;
- case PLUS_EXPR:
- if (int1h == 0)
- {
- int2l += int1l;
- if ((unsigned HOST_WIDE_INT) int2l < int1l)
- {
- hi = int2h++;
- overflow = int2h < hi;
- }
- t = build_int_2 (int2l, int2h);
- break;
- }
- if (int2h == 0)
- {
- int1l += int2l;
- if ((unsigned HOST_WIDE_INT) int1l < int2l)
- {
- hi = int1h++;
- overflow = int1h < hi;
- }
- t = build_int_2 (int1l, int1h);
- break;
- }
- overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi);
- t = build_int_2 (low, hi);
- break;
+ case MINUS_EXPR:
+ neg_double (int2l, int2h, &low, &hi);
+ add_double (int1l, int1h, low, hi, &low, &hi);
+ overflow = overflow_sum_sign (hi, int2h, int1h);
+ break;
- case MINUS_EXPR:
- if (int2h == 0 && int2l == 0)
- {
- t = build_int_2 (int1l, int1h);
- break;
- }
- neg_double (int2l, int2h, &low, &hi);
- add_double (int1l, int1h, low, hi, &low, &hi);
- overflow = overflow_sum_sign (hi, int2h, int1h);
- t = build_int_2 (low, hi);
- break;
+ case MULT_EXPR:
+ overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi);
+ break;
- case MULT_EXPR:
- overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi);
- t = build_int_2 (low, hi);
+ case TRUNC_DIV_EXPR:
+ case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ /* This is a shortcut for a common special case. */
+ if (int2h == 0 && int2l > 0
+ && ! TREE_CONSTANT_OVERFLOW (arg1)
+ && ! TREE_CONSTANT_OVERFLOW (arg2)
+ && int1h == 0 && int1l >= 0)
+ {
+ if (code == CEIL_DIV_EXPR)
+ int1l += int2l - 1;
+ low = int1l / int2l, hi = 0;
break;
+ }
- case TRUNC_DIV_EXPR:
- case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR:
- case EXACT_DIV_EXPR:
- /* This is a shortcut for a common special case.
- It reduces the number of tree nodes generated
- and saves time. */
- if (int2h == 0 && int2l > 0
- && TREE_TYPE (arg1) == sizetype
- && int1h == 0 && int1l >= 0)
- {
- if (code == CEIL_DIV_EXPR)
- int1l += int2l-1;
- return size_int (int1l / int2l);
- }
- case ROUND_DIV_EXPR:
- if (int2h == 0 && int2l == 1)
- {
- t = build_int_2 (int1l, int1h);
- break;
- }
- if (int1l == int2l && int1h == int2h)
- {
- if ((int1l | int1h) == 0)
- abort ();
- t = build_int_2 (1, 0);
- break;
- }
- overflow = div_and_round_double (code, uns,
- int1l, int1h, int2l, int2h,
- &low, &hi, &garbagel, &garbageh);
- t = build_int_2 (low, hi);
- break;
+ /* ... fall through ... */
- case TRUNC_MOD_EXPR: case ROUND_MOD_EXPR:
- case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR:
- overflow = div_and_round_double (code, uns,
- int1l, int1h, int2l, int2h,
- &garbagel, &garbageh, &low, &hi);
- t = build_int_2 (low, hi);
+ case ROUND_DIV_EXPR:
+ if (int2h == 0 && int2l == 1)
+ {
+ low = int1l, hi = int1h;
break;
+ }
+ if (int1l == int2l && int1h == int2h
+ && ! (int1l == 0 && int1h == 0))
+ {
+ low = 1, hi = 0;
+ break;
+ }
+ overflow = div_and_round_double (code, uns,
+ int1l, int1h, int2l, int2h,
+ &low, &hi, &garbagel, &garbageh);
+ break;
- case MIN_EXPR:
- case MAX_EXPR:
- if (uns)
- {
- low = (((unsigned HOST_WIDE_INT) int1h
- < (unsigned HOST_WIDE_INT) int2h)
- || (((unsigned HOST_WIDE_INT) int1h
- == (unsigned HOST_WIDE_INT) int2h)
- && ((unsigned HOST_WIDE_INT) int1l
- < (unsigned HOST_WIDE_INT) int2l)));
- }
- else
- {
- low = ((int1h < int2h)
- || ((int1h == int2h)
- && ((unsigned HOST_WIDE_INT) int1l
- < (unsigned HOST_WIDE_INT) int2l)));
- }
- if (low == (code == MIN_EXPR))
- t = build_int_2 (int1l, int1h);
- else
- t = build_int_2 (int2l, int2h);
+ case TRUNC_MOD_EXPR:
+ case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR:
+ /* This is a shortcut for a common special case. */
+ if (int2h == 0 && int2l > 0
+ && ! TREE_CONSTANT_OVERFLOW (arg1)
+ && ! TREE_CONSTANT_OVERFLOW (arg2)
+ && int1h == 0 && int1l >= 0)
+ {
+ if (code == CEIL_MOD_EXPR)
+ int1l += int2l - 1;
+ low = int1l % int2l, hi = 0;
break;
+ }
- default:
- abort ();
+ /* ... fall through ... */
+
+ case ROUND_MOD_EXPR:
+ overflow = div_and_round_double (code, uns,
+ int1l, int1h, int2l, int2h,
+ &garbagel, &garbageh, &low, &hi);
+ break;
+
+ case MIN_EXPR:
+ case MAX_EXPR:
+ if (uns)
+ {
+ low = (((unsigned HOST_WIDE_INT) int1h
+ < (unsigned HOST_WIDE_INT) int2h)
+ || (((unsigned HOST_WIDE_INT) int1h
+ == (unsigned HOST_WIDE_INT) int2h)
+ && ((unsigned HOST_WIDE_INT) int1l
+ < (unsigned HOST_WIDE_INT) int2l)));
+ }
+ else
+ {
+ low = ((int1h < int2h)
+ || ((int1h == int2h)
+ && ((unsigned HOST_WIDE_INT) int1l
+ < (unsigned HOST_WIDE_INT) int2l)));
}
- got_it:
+ if (low == (code == MIN_EXPR))
+ low = int1l, hi = int1h;
+ else
+ low = int2l, hi = int2h;
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (TREE_TYPE (arg1) == sizetype && hi == 0
+ && low >= 0
+ && (TYPE_MAX_VALUE (sizetype) == NULL
+ || low <= TREE_INT_CST_LOW (TYPE_MAX_VALUE (sizetype)))
+ && ! overflow
+ && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2))
+ t = size_int (low);
+ else
+ {
+ t = build_int_2 (low, hi);
TREE_TYPE (t) = TREE_TYPE (arg1);
- TREE_OVERFLOW (t)
- = ((notrunc ? !uns && overflow : force_fit_type (t, overflow && !uns))
- | TREE_OVERFLOW (arg1)
- | TREE_OVERFLOW (arg2));
- TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t)
- | TREE_CONSTANT_OVERFLOW (arg1)
- | TREE_CONSTANT_OVERFLOW (arg2));
- return t;
}
+
+ TREE_OVERFLOW (t)
+ = ((notrunc ? (!uns || forsize) && overflow
+ : force_fit_type (t, (!uns || forsize) && overflow) && ! no_overflow)
+ | TREE_OVERFLOW (arg1)
+ | TREE_OVERFLOW (arg2));
+ /* If we're doing a size calculation, unsigned arithmetic does overflow.
+ So check if force_fit_type truncated the value. */
+ if (forsize
+ && ! TREE_OVERFLOW (t)
+ && (TREE_INT_CST_HIGH (t) != hi
+ || TREE_INT_CST_LOW (t) != low))
+ TREE_OVERFLOW (t) = 1;
+ TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t)
+ | TREE_CONSTANT_OVERFLOW (arg1)
+ | TREE_CONSTANT_OVERFLOW (arg2));
+ return t;
+}
+
+/* Combine two constants ARG1 and ARG2 under operation CODE
+ to produce a new constant.
+ We assume ARG1 and ARG2 have the same data type,
+ or at least are the same kind of constant and the same machine mode.
+
+ If NOTRUNC is nonzero, do not truncate the result to fit the data type. */
+
+static tree
+const_binop (code, arg1, arg2, notrunc)
+ enum tree_code code;
+ register tree arg1, arg2;
+ int notrunc;
+{
+ STRIP_NOPS (arg1); STRIP_NOPS (arg2);
+
+ if (TREE_CODE (arg1) == INTEGER_CST)
+ return int_const_binop (code, arg1, arg2, notrunc, 0);
+
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
if (TREE_CODE (arg1) == REAL_CST)
{
@@ -1229,6 +1347,7 @@ const_binop (code, arg1, arg2, notrunc)
#endif /* not REAL_IS_NOT_DOUBLE, or REAL_ARITHMETIC */
if (TREE_CODE (arg1) == COMPLEX_CST)
{
+ register tree type = TREE_TYPE (arg1);
register tree r1 = TREE_REALPART (arg1);
register tree i1 = TREE_IMAGPART (arg1);
register tree r2 = TREE_REALPART (arg2);
@@ -1238,17 +1357,20 @@ const_binop (code, arg1, arg2, notrunc)
switch (code)
{
case PLUS_EXPR:
- t = build_complex (const_binop (PLUS_EXPR, r1, r2, notrunc),
+ t = build_complex (type,
+ const_binop (PLUS_EXPR, r1, r2, notrunc),
const_binop (PLUS_EXPR, i1, i2, notrunc));
break;
case MINUS_EXPR:
- t = build_complex (const_binop (MINUS_EXPR, r1, r2, notrunc),
+ t = build_complex (type,
+ const_binop (MINUS_EXPR, r1, r2, notrunc),
const_binop (MINUS_EXPR, i1, i2, notrunc));
break;
case MULT_EXPR:
- t = build_complex (const_binop (MINUS_EXPR,
+ t = build_complex (type,
+ const_binop (MINUS_EXPR,
const_binop (MULT_EXPR,
r1, r2, notrunc),
const_binop (MULT_EXPR,
@@ -1270,64 +1392,69 @@ const_binop (code, arg1, arg2, notrunc)
const_binop (MULT_EXPR, i2, i2, notrunc),
notrunc);
- t = build_complex
- (const_binop (INTEGRAL_TYPE_P (TREE_TYPE (r1))
- ? TRUNC_DIV_EXPR : RDIV_EXPR,
- const_binop (PLUS_EXPR,
- const_binop (MULT_EXPR, r1, r2,
- notrunc),
- const_binop (MULT_EXPR, i1, i2,
- notrunc),
- notrunc),
- magsquared, notrunc),
- const_binop (INTEGRAL_TYPE_P (TREE_TYPE (r1))
- ? TRUNC_DIV_EXPR : RDIV_EXPR,
- const_binop (MINUS_EXPR,
- const_binop (MULT_EXPR, i1, r2,
- notrunc),
- const_binop (MULT_EXPR, r1, i2,
- notrunc),
- notrunc),
- magsquared, notrunc));
+ t = build_complex (type,
+ const_binop
+ (INTEGRAL_TYPE_P (TREE_TYPE (r1))
+ ? TRUNC_DIV_EXPR : RDIV_EXPR,
+ const_binop (PLUS_EXPR,
+ const_binop (MULT_EXPR, r1, r2,
+ notrunc),
+ const_binop (MULT_EXPR, i1, i2,
+ notrunc),
+ notrunc),
+ magsquared, notrunc),
+ const_binop
+ (INTEGRAL_TYPE_P (TREE_TYPE (r1))
+ ? TRUNC_DIV_EXPR : RDIV_EXPR,
+ const_binop (MINUS_EXPR,
+ const_binop (MULT_EXPR, i1, r2,
+ notrunc),
+ const_binop (MULT_EXPR, r1, i2,
+ notrunc),
+ notrunc),
+ magsquared, notrunc));
}
break;
default:
abort ();
}
- TREE_TYPE (t) = TREE_TYPE (arg1);
return t;
}
return 0;
}
-/* Return an INTEGER_CST with value V and type from `sizetype'. */
+/* Return an INTEGER_CST with value V . The type is determined by bit_p:
+ if it is zero, the type is taken from sizetype; if it is one, the type
+ is taken from bitsizetype. */
tree
-size_int (number)
- unsigned HOST_WIDE_INT number;
+size_int_wide (number, high, bit_p)
+ unsigned HOST_WIDE_INT number, high;
+ int bit_p;
{
register tree t;
/* Type-size nodes already made for small sizes. */
- static tree size_table[2*HOST_BITS_PER_WIDE_INT + 1];
+ static tree size_table[2*HOST_BITS_PER_WIDE_INT + 1][2];
- if (number < 2*HOST_BITS_PER_WIDE_INT + 1
- && size_table[number] != 0)
- return size_table[number];
- if (number < 2*HOST_BITS_PER_WIDE_INT + 1)
+ if (number < 2*HOST_BITS_PER_WIDE_INT + 1 && ! high
+ && size_table[number][bit_p] != 0)
+ return size_table[number][bit_p];
+ if (number < 2*HOST_BITS_PER_WIDE_INT + 1 && ! high)
{
push_obstacks_nochange ();
/* Make this a permanent node. */
end_temporary_allocation ();
t = build_int_2 (number, 0);
- TREE_TYPE (t) = sizetype;
- size_table[number] = t;
+ TREE_TYPE (t) = bit_p ? bitsizetype : sizetype;
+ size_table[number][bit_p] = t;
pop_obstacks ();
}
else
{
- t = build_int_2 (number, 0);
- TREE_TYPE (t) = sizetype;
+ t = build_int_2 (number, high);
+ TREE_TYPE (t) = bit_p ? bitsizetype : sizetype;
+ TREE_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (t) = force_fit_type (t, 0);
}
return t;
}
@@ -1345,20 +1472,16 @@ size_binop (code, arg0, arg1)
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
{
/* And some specific cases even faster than that. */
- if (code == PLUS_EXPR
- && TREE_INT_CST_LOW (arg0) == 0
- && TREE_INT_CST_HIGH (arg0) == 0)
+ if (code == PLUS_EXPR && integer_zerop (arg0))
return arg1;
- if (code == MINUS_EXPR
- && TREE_INT_CST_LOW (arg1) == 0
- && TREE_INT_CST_HIGH (arg1) == 0)
+ else if ((code == MINUS_EXPR || code == PLUS_EXPR)
+ && integer_zerop (arg1))
return arg0;
- if (code == MULT_EXPR
- && TREE_INT_CST_LOW (arg0) == 1
- && TREE_INT_CST_HIGH (arg0) == 0)
+ else if (code == MULT_EXPR && integer_onep (arg0))
return arg1;
+
/* Handle general case of two integer constants. */
- return const_binop (code, arg0, arg1, 0);
+ return int_const_binop (code, arg0, arg1, 0, 1);
}
if (arg0 == error_mark_node || arg1 == error_mark_node)
@@ -1366,6 +1489,40 @@ size_binop (code, arg0, arg1)
return fold (build (code, sizetype, arg0, arg1));
}
+
+/* Combine operands OP1 and OP2 with arithmetic operation CODE.
+ CODE is a tree code. Data type is taken from `ssizetype',
+ If the operands are constant, so is the result. */
+
+tree
+ssize_binop (code, arg0, arg1)
+ enum tree_code code;
+ tree arg0, arg1;
+{
+ /* Handle the special case of two integer constants faster. */
+ if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
+ {
+ /* And some specific cases even faster than that. */
+ if (code == PLUS_EXPR && integer_zerop (arg0))
+ return arg1;
+ else if ((code == MINUS_EXPR || code == PLUS_EXPR)
+ && integer_zerop (arg1))
+ return arg0;
+ else if (code == MULT_EXPR && integer_onep (arg0))
+ return arg1;
+
+ /* Handle general case of two integer constants. We convert
+ arg0 to ssizetype because int_const_binop uses its type for the
+ return value. */
+ arg0 = convert (ssizetype, arg0);
+ return int_const_binop (code, arg0, arg1, 0, 0);
+ }
+
+ if (arg0 == error_mark_node || arg1 == error_mark_node)
+ return error_mark_node;
+
+ return fold (build (code, ssizetype, arg0, arg1));
+}
/* Given T, a tree representing type conversion of ARG1, a constant,
return a constant tree representing the result of conversion. */
@@ -1378,7 +1535,7 @@ fold_convert (t, arg1)
register tree type = TREE_TYPE (t);
int overflow = 0;
- if (TREE_CODE (type) == POINTER_TYPE || INTEGRAL_TYPE_P (type))
+ if (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type))
{
if (TREE_CODE (arg1) == INTEGER_CST)
{
@@ -1395,13 +1552,15 @@ fold_convert (t, arg1)
/* Indicate an overflow if (1) ARG1 already overflowed,
or (2) force_fit_type indicates an overflow.
Tell force_fit_type that an overflow has already occurred
- if ARG1 is a too-large unsigned value and T is signed. */
+ if ARG1 is a too-large unsigned value and T is signed.
+ But don't indicate an overflow if converting a pointer. */
TREE_OVERFLOW (t)
- = (TREE_OVERFLOW (arg1)
- | force_fit_type (t,
- (TREE_INT_CST_HIGH (arg1) < 0
- & (TREE_UNSIGNED (type)
- < TREE_UNSIGNED (TREE_TYPE (arg1))))));
+ = ((force_fit_type (t,
+ (TREE_INT_CST_HIGH (arg1) < 0
+ && (TREE_UNSIGNED (type)
+ < TREE_UNSIGNED (TREE_TYPE (arg1)))))
+ && ! POINTER_TYPE_P (TREE_TYPE (arg1)))
+ || TREE_OVERFLOW (arg1));
TREE_CONSTANT_OVERFLOW (t)
= TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg1);
}
@@ -1413,25 +1572,35 @@ fold_convert (t, arg1)
REAL_VALUE_TYPE x;
REAL_VALUE_TYPE l;
REAL_VALUE_TYPE u;
+ tree type1 = TREE_TYPE (arg1);
+ int no_upper_bound;
x = TREE_REAL_CST (arg1);
- l = real_value_from_int_cst (TYPE_MIN_VALUE (type));
- u = real_value_from_int_cst (TYPE_MAX_VALUE (type));
+ l = real_value_from_int_cst (type1, TYPE_MIN_VALUE (type));
+
+ no_upper_bound = (TYPE_MAX_VALUE (type) == NULL);
+ if (!no_upper_bound)
+ u = real_value_from_int_cst (type1, TYPE_MAX_VALUE (type));
+
/* See if X will be in range after truncation towards 0.
To compensate for truncation, move the bounds away from 0,
but reject if X exactly equals the adjusted bounds. */
#ifdef REAL_ARITHMETIC
REAL_ARITHMETIC (l, MINUS_EXPR, l, dconst1);
- REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);
+ if (!no_upper_bound)
+ REAL_ARITHMETIC (u, PLUS_EXPR, u, dconst1);
#else
l--;
- u++;
+ if (!no_upper_bound)
+ u++;
#endif
/* If X is a NaN, use zero instead and show we have an overflow.
Otherwise, range check. */
if (REAL_VALUE_ISNAN (x))
overflow = 1, x = dconst0;
- else if (! (REAL_VALUES_LESS (l, x) && REAL_VALUES_LESS (x, u)))
+ else if (! (REAL_VALUES_LESS (l, x)
+ && !no_upper_bound
+ && REAL_VALUES_LESS (x, u)))
overflow = 1;
#ifndef REAL_ARITHMETIC
@@ -1481,7 +1650,11 @@ fold_convert (t, arg1)
if (TREE_CODE (arg1) == REAL_CST)
{
if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)))
- return arg1;
+ {
+ t = arg1;
+ TREE_TYPE (arg1) = type;
+ return t;
+ }
else if (setjmp (float_error))
{
overflow = 1;
@@ -1643,46 +1816,63 @@ operand_equal_p (arg0, arg1, only_const)
STRIP_NOPS (arg0);
STRIP_NOPS (arg1);
- /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal.
- We don't care about side effects in that case because the SAVE_EXPR
- takes care of that for us. */
- if (TREE_CODE (arg0) == SAVE_EXPR && arg0 == arg1)
- return ! only_const;
-
- if (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1))
+ if (TREE_CODE (arg0) != TREE_CODE (arg1)
+ /* This is needed for conversions and for COMPONENT_REF.
+ Might as well play it safe and always test this. */
+ || TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1)))
return 0;
- if (TREE_CODE (arg0) == TREE_CODE (arg1)
- && TREE_CODE (arg0) == ADDR_EXPR
- && TREE_OPERAND (arg0, 0) == TREE_OPERAND (arg1, 0))
- return 1;
-
- if (TREE_CODE (arg0) == TREE_CODE (arg1)
- && TREE_CODE (arg0) == INTEGER_CST
- && TREE_INT_CST_LOW (arg0) == TREE_INT_CST_LOW (arg1)
- && TREE_INT_CST_HIGH (arg0) == TREE_INT_CST_HIGH (arg1))
+ /* If ARG0 and ARG1 are the same SAVE_EXPR, they are necessarily equal.
+ We don't care about side effects in that case because the SAVE_EXPR
+ takes care of that for us. In all other cases, two expressions are
+ equal if they have no side effects. If we have two identical
+ expressions with side effects that should be treated the same due
+ to the only side effects being identical SAVE_EXPR's, that will
+ be detected in the recursive calls below. */
+ if (arg0 == arg1 && ! only_const
+ && (TREE_CODE (arg0) == SAVE_EXPR
+ || (! TREE_SIDE_EFFECTS (arg0) && ! TREE_SIDE_EFFECTS (arg1))))
return 1;
- /* Detect when real constants are equal. */
- if (TREE_CODE (arg0) == TREE_CODE (arg1)
- && TREE_CODE (arg0) == REAL_CST)
- return !bcmp ((char *) &TREE_REAL_CST (arg0),
- (char *) &TREE_REAL_CST (arg1),
- sizeof (REAL_VALUE_TYPE));
+ /* Next handle constant cases, those for which we can return 1 even
+ if ONLY_CONST is set. */
+ if (TREE_CONSTANT (arg0) && TREE_CONSTANT (arg1))
+ switch (TREE_CODE (arg0))
+ {
+ case INTEGER_CST:
+ return (! TREE_CONSTANT_OVERFLOW (arg0)
+ && ! TREE_CONSTANT_OVERFLOW (arg1)
+ && TREE_INT_CST_LOW (arg0) == TREE_INT_CST_LOW (arg1)
+ && TREE_INT_CST_HIGH (arg0) == TREE_INT_CST_HIGH (arg1));
+
+ case REAL_CST:
+ return (! TREE_CONSTANT_OVERFLOW (arg0)
+ && ! TREE_CONSTANT_OVERFLOW (arg1)
+ && REAL_VALUES_IDENTICAL (TREE_REAL_CST (arg0),
+ TREE_REAL_CST (arg1)));
+
+ case COMPLEX_CST:
+ return (operand_equal_p (TREE_REALPART (arg0), TREE_REALPART (arg1),
+ only_const)
+ && operand_equal_p (TREE_IMAGPART (arg0), TREE_IMAGPART (arg1),
+ only_const));
+
+ case STRING_CST:
+ return (TREE_STRING_LENGTH (arg0) == TREE_STRING_LENGTH (arg1)
+ && ! strncmp (TREE_STRING_POINTER (arg0),
+ TREE_STRING_POINTER (arg1),
+ TREE_STRING_LENGTH (arg0)));
+
+ case ADDR_EXPR:
+ return operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0),
+ 0);
+ default:
+ break;
+ }
if (only_const)
return 0;
- if (arg0 == arg1)
- return 1;
-
- if (TREE_CODE (arg0) != TREE_CODE (arg1))
- return 0;
- /* This is needed for conversions and for COMPONENT_REF.
- Might as well play it safe and always test this. */
- if (TYPE_MODE (TREE_TYPE (arg0)) != TYPE_MODE (TREE_TYPE (arg1)))
- return 0;
-
switch (TREE_CODE_CLASS (TREE_CODE (arg0)))
{
case '1':
@@ -1697,10 +1887,22 @@ operand_equal_p (arg0, arg1, only_const)
case '<':
case '2':
- return (operand_equal_p (TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg1, 0), 0)
+ if (operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 0), 0)
+ && operand_equal_p (TREE_OPERAND (arg0, 1), TREE_OPERAND (arg1, 1),
+ 0))
+ return 1;
+
+ /* For commutative ops, allow the other order. */
+ return ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MULT_EXPR
+ || TREE_CODE (arg0) == MIN_EXPR || TREE_CODE (arg0) == MAX_EXPR
+ || TREE_CODE (arg0) == BIT_IOR_EXPR
+ || TREE_CODE (arg0) == BIT_XOR_EXPR
+ || TREE_CODE (arg0) == BIT_AND_EXPR
+ || TREE_CODE (arg0) == NE_EXPR || TREE_CODE (arg0) == EQ_EXPR)
+ && operand_equal_p (TREE_OPERAND (arg0, 0),
+ TREE_OPERAND (arg1, 1), 0)
&& operand_equal_p (TREE_OPERAND (arg0, 1),
- TREE_OPERAND (arg1, 1), 0));
+ TREE_OPERAND (arg1, 0), 0));
case 'r':
switch (TREE_CODE (arg0))
@@ -1723,11 +1925,13 @@ operand_equal_p (arg0, arg1, only_const)
TREE_OPERAND (arg1, 1), 0)
&& operand_equal_p (TREE_OPERAND (arg0, 2),
TREE_OPERAND (arg1, 2), 0));
+ default:
+ return 0;
}
- break;
+
+ default:
+ return 0;
}
-
- return 0;
}
/* Similar to operand_equal_p, but see if ARG0 might have been made by
@@ -1741,7 +1945,7 @@ operand_equal_for_comparison_p (arg0, arg1, other)
tree other;
{
int unsignedp1, unsignedpo;
- tree primarg1, primother;
+ tree primarg0, primarg1, primother;
unsigned correct_width;
if (operand_equal_p (arg0, arg1, 0))
@@ -1751,6 +1955,14 @@ operand_equal_for_comparison_p (arg0, arg1, other)
|| ! INTEGRAL_TYPE_P (TREE_TYPE (arg1)))
return 0;
+ /* Discard any conversions that don't change the modes of ARG0 and ARG1
+ and see if the inner values are the same. This removes any
+ signedness comparison, which doesn't matter here. */
+ primarg0 = arg0, primarg1 = arg1;
+ STRIP_NOPS (primarg0); STRIP_NOPS (primarg1);
+ if (operand_equal_p (primarg0, primarg1, 0))
+ return 1;
+
/* Duplicate what shorten_compare does to ARG1 and see if that gives the
actual comparison operand, ARG0.
@@ -1878,9 +2090,10 @@ twoval_comparison_p (arg, cval1, cval2, save_p)
return 0;
return 1;
- }
- return 0;
+ default:
+ return 0;
+ }
}
/* ARG is a tree that is known to contain just arithmetic operations and
@@ -1935,7 +2148,10 @@ eval_subst (arg, old0, new0, old1, new1)
old0, new0, old1, new1),
eval_subst (TREE_OPERAND (arg, 2),
old0, new0, old1, new1)));
+ default:
+ break;
}
+ /* fall through (???) */
case '<':
{
@@ -1958,9 +2174,10 @@ eval_subst (arg, old0, new0, old1, new1)
return fold (build (code, type, arg0, arg1));
}
- }
- return arg;
+ default:
+ return arg;
+ }
}
/* Return a tree for the case when the result of an expression is RESULT
@@ -2098,6 +2315,9 @@ invert_truthvalue (arg)
case CLEANUP_POINT_EXPR:
return build1 (CLEANUP_POINT_EXPR, type,
invert_truthvalue (TREE_OPERAND (arg, 0)));
+
+ default:
+ break;
}
if (TREE_CODE (TREE_TYPE (arg)) != BOOLEAN_TYPE)
abort ();
@@ -2170,7 +2390,7 @@ make_bit_field_ref (inner, type, bitsize, bitpos, unsignedp)
int unsignedp;
{
tree result = build (BIT_FIELD_REF, type, inner,
- size_int (bitsize), size_int (bitpos));
+ size_int (bitsize), bitsize_int (bitpos, 0L));
TREE_UNSIGNED (result) = unsignedp;
@@ -2204,14 +2424,15 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
tree lhs, rhs;
{
int lbitpos, lbitsize, rbitpos, rbitsize;
- int lnbitpos, lnbitsize, rnbitpos, rnbitsize;
+ int lnbitpos, lnbitsize, rnbitpos = 0, rnbitsize = 0;
tree type = TREE_TYPE (lhs);
tree signed_type, unsigned_type;
int const_p = TREE_CODE (rhs) == INTEGER_CST;
- enum machine_mode lmode, rmode, lnmode, rnmode;
+ enum machine_mode lmode, rmode, lnmode, rnmode = VOIDmode;
int lunsignedp, runsignedp;
int lvolatilep = 0, rvolatilep = 0;
- tree linner, rinner;
+ int alignment;
+ tree linner, rinner = NULL_TREE;
tree mask;
tree offset;
@@ -2219,7 +2440,7 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
if the same as the size of the underlying object, we aren't doing an
extraction at all and so can do nothing. */
linner = get_inner_reference (lhs, &lbitsize, &lbitpos, &offset, &lmode,
- &lunsignedp, &lvolatilep);
+ &lunsignedp, &lvolatilep, &alignment);
if (linner == lhs || lbitsize == GET_MODE_BITSIZE (lmode) || lbitsize < 0
|| offset != 0)
return 0;
@@ -2228,8 +2449,8 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
{
/* If this is not a constant, we can only do something if bit positions,
sizes, and signedness are the same. */
- rinner = get_inner_reference (rhs, &rbitsize, &rbitpos, &offset,
- &rmode, &runsignedp, &rvolatilep);
+ rinner = get_inner_reference (rhs, &rbitsize, &rbitpos, &offset, &rmode,
+ &runsignedp, &rvolatilep, &alignment);
if (rinner == rhs || lbitpos != rbitpos || lbitsize != rbitsize
|| lunsignedp != runsignedp || offset != 0)
@@ -2383,7 +2604,7 @@ optimize_bit_field_compare (code, compare_type, lhs, rhs)
*PMASK is set to the mask used. This is either contained in a
BIT_AND_EXPR or derived from the width of the field.
- *PAND_MASK is set the the mask found in a BIT_AND_EXPR, if any.
+ *PAND_MASK is set to the mask found in a BIT_AND_EXPR, if any.
Return 0 if this is not a component reference or is one that we can't
do anything with. */
@@ -2402,6 +2623,7 @@ decode_field_reference (exp, pbitsize, pbitpos, pmode, punsignedp,
tree mask, inner, offset;
tree unsigned_type;
int precision;
+ int alignment;
/* All the optimizations using this function assume integer fields.
There are problems with FP fields since the type_for_size call
@@ -2422,7 +2644,7 @@ decode_field_reference (exp, pbitsize, pbitpos, pmode, punsignedp,
inner = get_inner_reference (exp, pbitsize, pbitpos, &offset, pmode,
- punsignedp, pvolatilep);
+ punsignedp, pvolatilep, &alignment);
if ((inner == exp && and_mask == 0)
|| *pbitsize < 0 || offset != 0)
return 0;
@@ -2500,128 +2722,616 @@ simple_operand_p (exp)
&& (! TREE_STATIC (exp) || DECL_REGISTER (exp))));
}
-/* Subroutine for fold_truthop: try to optimize a range test.
+/* The following functions are subroutines to fold_range_test and allow it to
+ try to change a logical combination of comparisons into a range test.
+
+ For example, both
+ X == 2 && X == 3 && X == 4 && X == 5
+ and
+ X >= 2 && X <= 5
+ are converted to
+ (unsigned) (X - 2) <= 3
+
+ We describe each set of comparisons as being either inside or outside
+ a range, using a variable named like IN_P, and then describe the
+ range with a lower and upper bound. If one of the bounds is omitted,
+ it represents either the highest or lowest value of the type.
+
+ In the comments below, we represent a range by two numbers in brackets
+ preceded by a "+" to designate being inside that range, or a "-" to
+ designate being outside that range, so the condition can be inverted by
+ flipping the prefix. An omitted bound is represented by a "-". For
+ example, "- [-, 10]" means being outside the range starting at the lowest
+ possible value and ending at 10, in other words, being greater than 10.
+ The range "+ [-, -]" is always true and hence the range "- [-, -]" is
+ always false.
+
+ We set up things so that the missing bounds are handled in a consistent
+ manner so neither a missing bound nor "true" and "false" need to be
+ handled using a special case. */
+
+/* Return the result of applying CODE to ARG0 and ARG1, but handle the case
+ of ARG0 and/or ARG1 being omitted, meaning an unlimited range. UPPER0_P
+ and UPPER1_P are nonzero if the respective argument is an upper bound
+ and zero for a lower. TYPE, if nonzero, is the type of the result; it
+ must be specified for a comparison. ARG1 will be converted to ARG0's
+ type if both are specified. */
- For example, "i >= 2 && i =< 9" can be done as "(unsigned) (i - 2) <= 7".
+static tree
+range_binop (code, type, arg0, upper0_p, arg1, upper1_p)
+ enum tree_code code;
+ tree type;
+ tree arg0, arg1;
+ int upper0_p, upper1_p;
+{
+ tree tem;
+ int result;
+ int sgn0, sgn1;
- JCODE is the logical combination of the two terms. It is TRUTH_AND_EXPR
- (representing TRUTH_ANDIF_EXPR and TRUTH_AND_EXPR) or TRUTH_OR_EXPR
- (representing TRUTH_ORIF_EXPR and TRUTH_OR_EXPR). TYPE is the type of
- the result.
+ /* If neither arg represents infinity, do the normal operation.
+ Else, if not a comparison, return infinity. Else handle the special
+ comparison rules. Note that most of the cases below won't occur, but
+ are handled for consistency. */
- VAR is the value being tested. LO_CODE and HI_CODE are the comparison
- operators comparing VAR to LO_CST and HI_CST. LO_CST is known to be no
- larger than HI_CST (they may be equal).
+ if (arg0 != 0 && arg1 != 0)
+ {
+ tem = fold (build (code, type != 0 ? type : TREE_TYPE (arg0),
+ arg0, convert (TREE_TYPE (arg0), arg1)));
+ STRIP_NOPS (tem);
+ return TREE_CODE (tem) == INTEGER_CST ? tem : 0;
+ }
- We return the simplified tree or 0 if no optimization is possible. */
+ if (TREE_CODE_CLASS (code) != '<')
+ return 0;
+
+ /* Set SGN[01] to -1 if ARG[01] is a lower bound, 1 for upper, and 0
+ for neither. In real maths, we cannot assume open ended ranges are
+ the same. But, this is computer arithmetic, where numbers are finite.
+ We can therefore make the transformation of any unbounded range with
+ the value Z, Z being greater than any representable number. This permits
+ us to treat unbounded ranges as equal. */
+ sgn0 = arg0 != 0 ? 0 : (upper0_p ? 1 : -1);
+ sgn1 = arg1 != 0 ? 0 : (upper1_p ? 1 : -1);
+ switch (code)
+ {
+ case EQ_EXPR:
+ result = sgn0 == sgn1;
+ break;
+ case NE_EXPR:
+ result = sgn0 != sgn1;
+ break;
+ case LT_EXPR:
+ result = sgn0 < sgn1;
+ break;
+ case LE_EXPR:
+ result = sgn0 <= sgn1;
+ break;
+ case GT_EXPR:
+ result = sgn0 > sgn1;
+ break;
+ case GE_EXPR:
+ result = sgn0 >= sgn1;
+ break;
+ default:
+ abort ();
+ }
+
+ return convert (type, result ? integer_one_node : integer_zero_node);
+}
+
+/* Given EXP, a logical expression, set the range it is testing into
+ variables denoted by PIN_P, PLOW, and PHIGH. Return the expression
+ actually being tested. *PLOW and *PHIGH will have be made the same type
+ as the returned expression. If EXP is not a comparison, we will most
+ likely not be returning a useful value and range. */
static tree
-range_test (jcode, type, lo_code, hi_code, var, lo_cst, hi_cst)
- enum tree_code jcode, lo_code, hi_code;
- tree type, var, lo_cst, hi_cst;
+make_range (exp, pin_p, plow, phigh)
+ tree exp;
+ int *pin_p;
+ tree *plow, *phigh;
{
- tree utype;
- enum tree_code rcode;
+ enum tree_code code;
+ tree arg0, arg1, type = NULL_TREE;
+ tree orig_type = NULL_TREE;
+ int in_p, n_in_p;
+ tree low, high, n_low, n_high;
+
+ /* Start with simply saying "EXP != 0" and then look at the code of EXP
+ and see if we can refine the range. Some of the cases below may not
+ happen, but it doesn't seem worth worrying about this. We "continue"
+ the outer loop when we've changed something; otherwise we "break"
+ the switch, which will "break" the while. */
- /* See if this is a range test and normalize the constant terms. */
+ in_p = 0, low = high = convert (TREE_TYPE (exp), integer_zero_node);
- if (jcode == TRUTH_AND_EXPR)
+ while (1)
{
- switch (lo_code)
+ code = TREE_CODE (exp);
+
+ if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
{
- case NE_EXPR:
- /* See if we have VAR != CST && VAR != CST+1. */
- if (! (hi_code == NE_EXPR
- && TREE_INT_CST_LOW (hi_cst) - TREE_INT_CST_LOW (lo_cst) == 1
- && tree_int_cst_equal (integer_one_node,
- const_binop (MINUS_EXPR,
- hi_cst, lo_cst, 0))))
- return 0;
+ arg0 = TREE_OPERAND (exp, 0);
+ if (TREE_CODE_CLASS (code) == '<'
+ || TREE_CODE_CLASS (code) == '1'
+ || TREE_CODE_CLASS (code) == '2')
+ type = TREE_TYPE (arg0);
+ if (TREE_CODE_CLASS (code) == '2'
+ || TREE_CODE_CLASS (code) == '<'
+ || (TREE_CODE_CLASS (code) == 'e'
+ && tree_code_length[(int) code] > 1))
+ arg1 = TREE_OPERAND (exp, 1);
+ }
- rcode = GT_EXPR;
- break;
+ switch (code)
+ {
+ case TRUTH_NOT_EXPR:
+ in_p = ! in_p, exp = arg0;
+ continue;
+
+ case EQ_EXPR: case NE_EXPR:
+ case LT_EXPR: case LE_EXPR: case GE_EXPR: case GT_EXPR:
+ /* We can only do something if the range is testing for zero
+ and if the second operand is an integer constant. Note that
+ saying something is "in" the range we make is done by
+ complementing IN_P since it will set in the initial case of
+ being not equal to zero; "out" is leaving it alone. */
+ if (low == 0 || high == 0
+ || ! integer_zerop (low) || ! integer_zerop (high)
+ || TREE_CODE (arg1) != INTEGER_CST)
+ break;
- case GT_EXPR:
- case GE_EXPR:
- if (hi_code == LT_EXPR)
- hi_cst = const_binop (MINUS_EXPR, hi_cst, integer_one_node, 0);
- else if (hi_code != LE_EXPR)
- return 0;
+ switch (code)
+ {
+ case NE_EXPR: /* - [c, c] */
+ low = high = arg1;
+ break;
+ case EQ_EXPR: /* + [c, c] */
+ in_p = ! in_p, low = high = arg1;
+ break;
+ case GT_EXPR: /* - [-, c] */
+ low = 0, high = arg1;
+ break;
+ case GE_EXPR: /* + [c, -] */
+ in_p = ! in_p, low = arg1, high = 0;
+ break;
+ case LT_EXPR: /* - [c, -] */
+ low = arg1, high = 0;
+ break;
+ case LE_EXPR: /* + [-, c] */
+ in_p = ! in_p, low = 0, high = arg1;
+ break;
+ default:
+ abort ();
+ }
- if (lo_code == GT_EXPR)
- lo_cst = const_binop (PLUS_EXPR, lo_cst, integer_one_node, 0);
+ exp = arg0;
- /* We now have VAR >= LO_CST && VAR <= HI_CST. */
- rcode = LE_EXPR;
- break;
+ /* If this is an unsigned comparison, we also know that EXP is
+ greater than or equal to zero. We base the range tests we make
+ on that fact, so we record it here so we can parse existing
+ range tests. */
+ if (TREE_UNSIGNED (type) && (low == 0 || high == 0))
+ {
+ if (! merge_ranges (&n_in_p, &n_low, &n_high, in_p, low, high,
+ 1, convert (type, integer_zero_node),
+ NULL_TREE))
+ break;
+
+ in_p = n_in_p, low = n_low, high = n_high;
+
+ /* If the high bound is missing, reverse the range so it
+ goes from zero to the low bound minus 1. */
+ if (high == 0)
+ {
+ in_p = ! in_p;
+ high = range_binop (MINUS_EXPR, NULL_TREE, low, 0,
+ integer_one_node, 0);
+ low = convert (type, integer_zero_node);
+ }
+ }
+ continue;
+
+ case NEGATE_EXPR:
+ /* (-x) IN [a,b] -> x in [-b, -a] */
+ n_low = range_binop (MINUS_EXPR, type,
+ convert (type, integer_zero_node), 0, high, 1);
+ n_high = range_binop (MINUS_EXPR, type,
+ convert (type, integer_zero_node), 0, low, 0);
+ low = n_low, high = n_high;
+ exp = arg0;
+ continue;
+
+ case BIT_NOT_EXPR:
+ /* ~ X -> -X - 1 */
+ exp = build (MINUS_EXPR, type, build1 (NEGATE_EXPR, type, arg0),
+ convert (type, integer_one_node));
+ continue;
+
+ case PLUS_EXPR: case MINUS_EXPR:
+ if (TREE_CODE (arg1) != INTEGER_CST)
+ break;
+
+ /* If EXP is signed, any overflow in the computation is undefined,
+ so we don't worry about it so long as our computations on
+ the bounds don't overflow. For unsigned, overflow is defined
+ and this is exactly the right thing. */
+ n_low = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR,
+ type, low, 0, arg1, 0);
+ n_high = range_binop (code == MINUS_EXPR ? PLUS_EXPR : MINUS_EXPR,
+ type, high, 1, arg1, 0);
+ if ((n_low != 0 && TREE_OVERFLOW (n_low))
+ || (n_high != 0 && TREE_OVERFLOW (n_high)))
+ break;
+
+ /* Check for an unsigned range which has wrapped around the maximum
+ value thus making n_high < n_low, and normalize it. */
+ if (n_low && n_high && tree_int_cst_lt (n_high, n_low))
+ {
+ low = range_binop (PLUS_EXPR, type, n_high, 0,
+ integer_one_node, 0);
+ high = range_binop (MINUS_EXPR, type, n_low, 0,
+ integer_one_node, 0);
+ in_p = ! in_p;
+ }
+ else
+ low = n_low, high = n_high;
+
+ exp = arg0;
+ continue;
+
+ case NOP_EXPR: case NON_LVALUE_EXPR: case CONVERT_EXPR:
+ if (orig_type == NULL_TREE)
+ orig_type = type;
+ if (TYPE_PRECISION (type) > TYPE_PRECISION (orig_type))
+ break;
+
+ if (! INTEGRAL_TYPE_P (type)
+ || (low != 0 && ! int_fits_type_p (low, type))
+ || (high != 0 && ! int_fits_type_p (high, type)))
+ break;
+
+ n_low = low, n_high = high;
+
+ if (n_low != 0)
+ n_low = convert (type, n_low);
+
+ if (n_high != 0)
+ n_high = convert (type, n_high);
+
+ /* If we're converting from an unsigned to a signed type,
+ we will be doing the comparison as unsigned. The tests above
+ have already verified that LOW and HIGH are both positive.
+
+ So we have to make sure that the original unsigned value will
+ be interpreted as positive. */
+ if (TREE_UNSIGNED (type) && ! TREE_UNSIGNED (TREE_TYPE (exp)))
+ {
+ tree equiv_type = type_for_mode (TYPE_MODE (type), 1);
+ tree high_positive;
+
+ /* A range without an upper bound is, naturally, unbounded.
+ Since convert would have cropped a very large value, use
+ the max value for the destination type. */
+
+ high_positive = TYPE_MAX_VALUE (equiv_type);
+ if (!high_positive)
+ {
+ high_positive = TYPE_MAX_VALUE (type);
+ if (!high_positive)
+ abort();
+ }
+ high_positive = fold (build (RSHIFT_EXPR, type,
+ convert (type, high_positive),
+ convert (type, integer_one_node)));
+
+ /* If the low bound is specified, "and" the range with the
+ range for which the original unsigned value will be
+ positive. */
+ if (low != 0)
+ {
+ if (! merge_ranges (&n_in_p, &n_low, &n_high,
+ 1, n_low, n_high,
+ 1, convert (type, integer_zero_node),
+ high_positive))
+ break;
+
+ in_p = (n_in_p == in_p);
+ }
+ else
+ {
+ /* Otherwise, "or" the range with the range of the input
+ that will be interpreted as negative. */
+ if (! merge_ranges (&n_in_p, &n_low, &n_high,
+ 0, n_low, n_high,
+ 1, convert (type, integer_zero_node),
+ high_positive))
+ break;
+
+ in_p = (in_p != n_in_p);
+ }
+ }
+
+ exp = arg0;
+ low = n_low, high = n_high;
+ continue;
default:
- return 0;
+ break;
}
+
+ break;
}
- else
+
+ /* If EXP is a constant, we can evaluate whether this is true or false. */
+ if (TREE_CODE (exp) == INTEGER_CST)
{
- switch (lo_code)
- {
- case EQ_EXPR:
- /* See if we have VAR == CST || VAR == CST+1. */
- if (! (hi_code == EQ_EXPR
- && TREE_INT_CST_LOW (hi_cst) - TREE_INT_CST_LOW (lo_cst) == 1
- && tree_int_cst_equal (integer_one_node,
- const_binop (MINUS_EXPR,
- hi_cst, lo_cst, 0))))
- return 0;
+ in_p = in_p == (integer_onep (range_binop (GE_EXPR, integer_type_node,
+ exp, 0, low, 0))
+ && integer_onep (range_binop (LE_EXPR, integer_type_node,
+ exp, 1, high, 1)));
+ low = high = 0;
+ exp = 0;
+ }
- rcode = LE_EXPR;
- break;
+ *pin_p = in_p, *plow = low, *phigh = high;
+ return exp;
+}
+
+/* Given a range, LOW, HIGH, and IN_P, an expression, EXP, and a result
+ type, TYPE, return an expression to test if EXP is in (or out of, depending
+ on IN_P) the range. */
- case LE_EXPR:
- case LT_EXPR:
- if (hi_code == GE_EXPR)
- hi_cst = const_binop (MINUS_EXPR, hi_cst, integer_one_node, 0);
- else if (hi_code != GT_EXPR)
- return 0;
+static tree
+build_range_check (type, exp, in_p, low, high)
+ tree type;
+ tree exp;
+ int in_p;
+ tree low, high;
+{
+ tree etype = TREE_TYPE (exp);
+ tree utype, value;
- if (lo_code == LE_EXPR)
- lo_cst = const_binop (PLUS_EXPR, lo_cst, integer_one_node, 0);
+ if (! in_p
+ && (0 != (value = build_range_check (type, exp, 1, low, high))))
+ return invert_truthvalue (value);
- /* We now have VAR < LO_CST || VAR > HI_CST. */
- rcode = GT_EXPR;
- break;
+ else if (low == 0 && high == 0)
+ return convert (type, integer_one_node);
- default:
- return 0;
- }
+ else if (low == 0)
+ return fold (build (LE_EXPR, type, exp, high));
+
+ else if (high == 0)
+ return fold (build (GE_EXPR, type, exp, low));
+
+ else if (operand_equal_p (low, high, 0))
+ return fold (build (EQ_EXPR, type, exp, low));
+
+ else if (TREE_UNSIGNED (etype) && integer_zerop (low))
+ return build_range_check (type, exp, 1, 0, high);
+
+ else if (integer_zerop (low))
+ {
+ utype = unsigned_type (etype);
+ return build_range_check (type, convert (utype, exp), 1, 0,
+ convert (utype, high));
}
- /* When normalizing, it is possible to both increment the smaller constant
- and decrement the larger constant. See if they are still ordered. */
- if (tree_int_cst_lt (hi_cst, lo_cst))
+ else if (0 != (value = const_binop (MINUS_EXPR, high, low, 0))
+ && ! TREE_OVERFLOW (value))
+ return build_range_check (type,
+ fold (build (MINUS_EXPR, etype, exp, low)),
+ 1, convert (etype, integer_zero_node), value);
+ else
return 0;
+}
+
+/* Given two ranges, see if we can merge them into one. Return 1 if we
+ can, 0 if we can't. Set the output range into the specified parameters. */
- /* Fail if VAR isn't an integer. */
- utype = TREE_TYPE (var);
- if (! INTEGRAL_TYPE_P (utype))
- return 0;
+static int
+merge_ranges (pin_p, plow, phigh, in0_p, low0, high0, in1_p, low1, high1)
+ int *pin_p;
+ tree *plow, *phigh;
+ int in0_p, in1_p;
+ tree low0, high0, low1, high1;
+{
+ int no_overlap;
+ int subset;
+ int temp;
+ tree tem;
+ int in_p;
+ tree low, high;
+ int lowequal = ((low0 == 0 && low1 == 0)
+ || integer_onep (range_binop (EQ_EXPR, integer_type_node,
+ low0, 0, low1, 0)));
+ int highequal = ((high0 == 0 && high1 == 0)
+ || integer_onep (range_binop (EQ_EXPR, integer_type_node,
+ high0, 1, high1, 1)));
+
+ /* Make range 0 be the range that starts first, or ends last if they
+ start at the same value. Swap them if it isn't. */
+ if (integer_onep (range_binop (GT_EXPR, integer_type_node,
+ low0, 0, low1, 0))
+ || (lowequal
+ && integer_onep (range_binop (GT_EXPR, integer_type_node,
+ high1, 1, high0, 1))))
+ {
+ temp = in0_p, in0_p = in1_p, in1_p = temp;
+ tem = low0, low0 = low1, low1 = tem;
+ tem = high0, high0 = high1, high1 = tem;
+ }
- /* The range test is invalid if subtracting the two constants results
- in overflow. This can happen in traditional mode. */
- if (! int_fits_type_p (hi_cst, TREE_TYPE (var))
- || ! int_fits_type_p (lo_cst, TREE_TYPE (var)))
- return 0;
+ /* Now flag two cases, whether the ranges are disjoint or whether the
+ second range is totally subsumed in the first. Note that the tests
+ below are simplified by the ones above. */
+ no_overlap = integer_onep (range_binop (LT_EXPR, integer_type_node,
+ high0, 1, low1, 0));
+ subset = integer_onep (range_binop (LE_EXPR, integer_type_node,
+ high1, 1, high0, 1));
+
+ /* We now have four cases, depending on whether we are including or
+ excluding the two ranges. */
+ if (in0_p && in1_p)
+ {
+ /* If they don't overlap, the result is false. If the second range
+ is a subset it is the result. Otherwise, the range is from the start
+ of the second to the end of the first. */
+ if (no_overlap)
+ in_p = 0, low = high = 0;
+ else if (subset)
+ in_p = 1, low = low1, high = high1;
+ else
+ in_p = 1, low = low1, high = high0;
+ }
- if (! TREE_UNSIGNED (utype))
+ else if (in0_p && ! in1_p)
{
- utype = unsigned_type (utype);
- var = convert (utype, var);
- lo_cst = convert (utype, lo_cst);
- hi_cst = convert (utype, hi_cst);
+ /* If they don't overlap, the result is the first range. If they are
+ equal, the result is false. If the second range is a subset of the
+ first, and the ranges begin at the same place, we go from just after
+ the end of the first range to the end of the second. If the second
+ range is not a subset of the first, or if it is a subset and both
+ ranges end at the same place, the range starts at the start of the
+ first range and ends just before the second range.
+ Otherwise, we can't describe this as a single range. */
+ if (no_overlap)
+ in_p = 1, low = low0, high = high0;
+ else if (lowequal && highequal)
+ in_p = 0, low = high = 0;
+ else if (subset && lowequal)
+ {
+ in_p = 1, high = high0;
+ low = range_binop (PLUS_EXPR, NULL_TREE, high1, 0,
+ integer_one_node, 0);
+ }
+ else if (! subset || highequal)
+ {
+ in_p = 1, low = low0;
+ high = range_binop (MINUS_EXPR, NULL_TREE, low1, 0,
+ integer_one_node, 0);
+ }
+ else
+ return 0;
+ }
+
+ else if (! in0_p && in1_p)
+ {
+ /* If they don't overlap, the result is the second range. If the second
+ is a subset of the first, the result is false. Otherwise,
+ the range starts just after the first range and ends at the
+ end of the second. */
+ if (no_overlap)
+ in_p = 1, low = low1, high = high1;
+ else if (subset)
+ in_p = 0, low = high = 0;
+ else
+ {
+ in_p = 1, high = high1;
+ low = range_binop (PLUS_EXPR, NULL_TREE, high0, 1,
+ integer_one_node, 0);
+ }
+ }
+
+ else
+ {
+ /* The case where we are excluding both ranges. Here the complex case
+ is if they don't overlap. In that case, the only time we have a
+ range is if they are adjacent. If the second is a subset of the
+ first, the result is the first. Otherwise, the range to exclude
+ starts at the beginning of the first range and ends at the end of the
+ second. */
+ if (no_overlap)
+ {
+ if (integer_onep (range_binop (EQ_EXPR, integer_type_node,
+ range_binop (PLUS_EXPR, NULL_TREE,
+ high0, 1,
+ integer_one_node, 1),
+ 1, low1, 0)))
+ in_p = 0, low = low0, high = high1;
+ else
+ return 0;
+ }
+ else if (subset)
+ in_p = 0, low = low0, high = high0;
+ else
+ in_p = 0, low = low0, high = high1;
}
- return fold (convert (type,
- build (rcode, utype,
- build (MINUS_EXPR, utype, var, lo_cst),
- const_binop (MINUS_EXPR, hi_cst, lo_cst, 0))));
+ *pin_p = in_p, *plow = low, *phigh = high;
+ return 1;
+}
+
+/* EXP is some logical combination of boolean tests. See if we can
+ merge it into some range test. Return the new tree if so. */
+
+static tree
+fold_range_test (exp)
+ tree exp;
+{
+ int or_op = (TREE_CODE (exp) == TRUTH_ORIF_EXPR
+ || TREE_CODE (exp) == TRUTH_OR_EXPR);
+ int in0_p, in1_p, in_p;
+ tree low0, low1, low, high0, high1, high;
+ tree lhs = make_range (TREE_OPERAND (exp, 0), &in0_p, &low0, &high0);
+ tree rhs = make_range (TREE_OPERAND (exp, 1), &in1_p, &low1, &high1);
+ tree tem;
+
+ /* If this is an OR operation, invert both sides; we will invert
+ again at the end. */
+ if (or_op)
+ in0_p = ! in0_p, in1_p = ! in1_p;
+
+ /* If both expressions are the same, if we can merge the ranges, and we
+ can build the range test, return it or it inverted. If one of the
+ ranges is always true or always false, consider it to be the same
+ expression as the other. */
+ if ((lhs == 0 || rhs == 0 || operand_equal_p (lhs, rhs, 0))
+ && merge_ranges (&in_p, &low, &high, in0_p, low0, high0,
+ in1_p, low1, high1)
+ && 0 != (tem = (build_range_check (TREE_TYPE (exp),
+ lhs != 0 ? lhs
+ : rhs != 0 ? rhs : integer_zero_node,
+ in_p, low, high))))
+ return or_op ? invert_truthvalue (tem) : tem;
+
+ /* On machines where the branch cost is expensive, if this is a
+ short-circuited branch and the underlying object on both sides
+ is the same, make a non-short-circuit operation. */
+ else if (BRANCH_COST >= 2
+ && (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
+ || TREE_CODE (exp) == TRUTH_ORIF_EXPR)
+ && operand_equal_p (lhs, rhs, 0))
+ {
+ /* If simple enough, just rewrite. Otherwise, make a SAVE_EXPR
+ unless we are at top level or LHS contains a PLACEHOLDER_EXPR, in
+ which cases we can't do this. */
+ if (simple_operand_p (lhs))
+ return build (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
+ ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
+ TREE_TYPE (exp), TREE_OPERAND (exp, 0),
+ TREE_OPERAND (exp, 1));
+
+ else if (current_function_decl != 0
+ && ! contains_placeholder_p (lhs))
+ {
+ tree common = save_expr (lhs);
+
+ if (0 != (lhs = build_range_check (TREE_TYPE (exp), common,
+ or_op ? ! in0_p : in0_p,
+ low0, high0))
+ && (0 != (rhs = build_range_check (TREE_TYPE (exp), common,
+ or_op ? ! in1_p : in1_p,
+ low1, high1))))
+ return build (TREE_CODE (exp) == TRUTH_ANDIF_EXPR
+ ? TRUTH_AND_EXPR : TRUTH_OR_EXPR,
+ TREE_TYPE (exp), lhs, rhs);
+ }
+ }
+
+
+ return 0;
}
/* Subroutine for fold_truthop: C is an INTEGER_CST interpreted as a P
@@ -2643,18 +3353,28 @@ unextend (c, p, unsignedp, mask)
if (p == modesize || unsignedp)
return c;
- if (TREE_UNSIGNED (type))
- c = convert (signed_type (type), c);
-
/* We work by getting just the sign bit into the low-order bit, then
into the high-order bit, then sign-extend. We then XOR that value
with C. */
temp = const_binop (RSHIFT_EXPR, c, size_int (p - 1), 0);
temp = const_binop (BIT_AND_EXPR, temp, size_int (1), 0);
+
+ /* We must use a signed type in order to get an arithmetic right shift.
+ However, we must also avoid introducing accidental overflows, so that
+ a subsequent call to integer_zerop will work. Hence we must
+ do the type conversion here. At this point, the constant is either
+ zero or one, and the conversion to a signed type can never overflow.
+ We could get an overflow if this conversion is done anywhere else. */
+ if (TREE_UNSIGNED (type))
+ temp = convert (signed_type (type), temp);
+
temp = const_binop (LSHIFT_EXPR, temp, size_int (modesize - 1), 0);
temp = const_binop (RSHIFT_EXPR, temp, size_int (modesize - p - 1), 0);
if (mask != 0)
temp = const_binop (BIT_AND_EXPR, temp, convert (TREE_TYPE (c), mask), 0);
+ /* If necessary, convert the type back to match the type of C. */
+ if (TREE_UNSIGNED (type))
+ temp = convert (type, temp);
return convert (type, const_binop (BIT_XOR_EXPR, c, temp, 0));
}
@@ -2715,13 +3435,11 @@ fold_truthop (code, truth_type, lhs, rhs)
int first_bit, end_bit;
int volatilep;
- /* Start by getting the comparison codes and seeing if this looks like
- a range test. Fail if anything is volatile. If one operand is a
- BIT_AND_EXPR with the constant one, treat it as if it were surrounded
- with a NE_EXPR. */
+ /* Start by getting the comparison codes. Fail if anything is volatile.
+ If one operand is a BIT_AND_EXPR with the constant one, treat it as if
+ it were surrounded with a NE_EXPR. */
- if (TREE_SIDE_EFFECTS (lhs)
- || TREE_SIDE_EFFECTS (rhs))
+ if (TREE_SIDE_EFFECTS (lhs) || TREE_SIDE_EFFECTS (rhs))
return 0;
lcode = TREE_CODE (lhs);
@@ -2733,8 +3451,7 @@ fold_truthop (code, truth_type, lhs, rhs)
if (rcode == BIT_AND_EXPR && integer_onep (TREE_OPERAND (rhs, 1)))
rcode = NE_EXPR, rhs = build (NE_EXPR, truth_type, rhs, integer_zero_node);
- if (TREE_CODE_CLASS (lcode) != '<'
- || TREE_CODE_CLASS (rcode) != '<')
+ if (TREE_CODE_CLASS (lcode) != '<' || TREE_CODE_CLASS (rcode) != '<')
return 0;
code = ((code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR)
@@ -2745,36 +3462,6 @@ fold_truthop (code, truth_type, lhs, rhs)
rl_arg = TREE_OPERAND (rhs, 0);
rr_arg = TREE_OPERAND (rhs, 1);
- if (TREE_CODE (lr_arg) == INTEGER_CST
- && TREE_CODE (rr_arg) == INTEGER_CST
- && operand_equal_p (ll_arg, rl_arg, 0))
- {
- if (tree_int_cst_lt (lr_arg, rr_arg))
- result = range_test (code, truth_type, lcode, rcode,
- ll_arg, lr_arg, rr_arg);
- else
- result = range_test (code, truth_type, rcode, lcode,
- ll_arg, rr_arg, lr_arg);
-
- /* If this isn't a range test, it also isn't a comparison that
- can be merged. However, it wins to evaluate the RHS unconditionally
- on machines with expensive branches. */
-
- if (result == 0 && BRANCH_COST >= 2)
- {
- if (TREE_CODE (ll_arg) != VAR_DECL
- && TREE_CODE (ll_arg) != PARM_DECL)
- {
- /* Avoid evaluating the variable part twice. */
- ll_arg = save_expr (ll_arg);
- lhs = build (lcode, TREE_TYPE (lhs), ll_arg, lr_arg);
- rhs = build (rcode, TREE_TYPE (rhs), ll_arg, rr_arg);
- }
- return build (code, truth_type, lhs, rhs);
- }
- return result;
- }
-
/* If the RHS can be evaluated unconditionally and its operands are
simple, it wins to evaluate the RHS unconditionally on machines
with expensive branches. In this case, this isn't a comparison
@@ -2839,7 +3526,17 @@ fold_truthop (code, truth_type, lhs, rhs)
if (lcode != wanted_code)
{
if (l_const && integer_zerop (l_const) && integer_pow2p (ll_mask))
- l_const = ll_mask;
+ {
+ if (ll_unsignedp || tree_log2 (ll_mask) + 1 < ll_bitsize)
+ l_const = ll_mask;
+ else
+ /* Since ll_arg is a single bit bit mask, we can sign extend
+ it appropriately with a NEGATE_EXPR.
+ l_const is made a signed value here, but since for l_const != NULL
+ lr_unsignedp is not used, we don't need to clear the latter. */
+ l_const = fold (build1 (NEGATE_EXPR, TREE_TYPE (ll_arg),
+ convert (TREE_TYPE (ll_arg), ll_mask)));
+ }
else
return 0;
}
@@ -2847,7 +3544,14 @@ fold_truthop (code, truth_type, lhs, rhs)
if (rcode != wanted_code)
{
if (r_const && integer_zerop (r_const) && integer_pow2p (rl_mask))
- r_const = rl_mask;
+ {
+ if (rl_unsignedp || tree_log2 (rl_mask) + 1 < rl_bitsize)
+ r_const = rl_mask;
+ else
+ /* This is analogous to the code for l_const above. */
+ r_const = fold (build1 (NEGATE_EXPR, TREE_TYPE (rl_arg),
+ convert (TREE_TYPE (rl_arg), rl_mask)));
+ }
else
return 0;
}
@@ -3036,7 +3740,6 @@ strip_compound_expr (t, s)
tree t;
tree s;
{
- tree type = TREE_TYPE (t);
enum tree_code code = TREE_CODE (t);
/* See if this is the COMPOUND_EXPR we want to eliminate. */
@@ -3064,6 +3767,27 @@ strip_compound_expr (t, s)
return t;
}
+/* Return a node which has the indicated constant VALUE (either 0 or
+ 1), and is of the indicated TYPE. */
+
+static tree
+constant_boolean_node (value, type)
+ int value;
+ tree type;
+{
+ if (type == integer_type_node)
+ return value ? integer_one_node : integer_zero_node;
+ else if (TREE_CODE (type) == BOOLEAN_TYPE)
+ return truthvalue_conversion (value ? integer_one_node :
+ integer_zero_node);
+ else
+ {
+ tree t = build_int_2 (value, 0);
+ TREE_TYPE (t) = type;
+ return t;
+ }
+}
+
/* Perform constant folding and related simplification of EXPR.
The related simplifications include x*1 => x, x*0 => 0, etc.,
and application of the associative law.
@@ -3080,7 +3804,7 @@ fold (expr)
tree t1 = NULL_TREE;
tree tem;
tree type = TREE_TYPE (expr);
- register tree arg0, arg1;
+ register tree arg0 = NULL_TREE, arg1 = NULL_TREE;
register enum tree_code code = TREE_CODE (t);
register int kind;
int invert;
@@ -3090,8 +3814,9 @@ fold (expr)
int wins = 1;
- /* Don't try to process an RTL_EXPR since its operands aren't trees. */
- if (code == RTL_EXPR)
+ /* Don't try to process an RTL_EXPR since its operands aren't trees.
+ Likewise for a SAVE_EXPR that's already been evaluated. */
+ if (code == RTL_EXPR || (code == SAVE_EXPR && SAVE_EXPR_RTL (t)) != 0)
return t;
/* Return right away if already constant. */
@@ -3102,6 +3827,10 @@ fold (expr)
return t;
}
+#ifdef MAX_INTEGER_COMPUTATION_MODE
+ check_max_integer_computation_mode (expr);
+#endif
+
kind = TREE_CODE_CLASS (code);
if (code == NOP_EXPR || code == FLOAT_EXPR || code == CONVERT_EXPR)
{
@@ -3279,10 +4008,15 @@ fold (expr)
return build (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0),
fold (build (code, type,
arg0, TREE_OPERAND (arg1, 1))));
- else if (TREE_CODE (arg1) == COND_EXPR
- || TREE_CODE_CLASS (TREE_CODE (arg1)) == '<')
+ else if ((TREE_CODE (arg1) == COND_EXPR
+ || (TREE_CODE_CLASS (TREE_CODE (arg1)) == '<'
+ && TREE_CODE_CLASS (code) != '<'))
+ && (! TREE_SIDE_EFFECTS (arg0)
+ || (current_function_decl != 0
+ && ! contains_placeholder_p (arg0))))
{
tree test, true_value, false_value;
+ tree lhs = 0, rhs = 0;
if (TREE_CODE (arg1) == COND_EXPR)
{
@@ -3305,25 +4039,37 @@ fold (expr)
to make this SAVE_EXPR. Since we do this optimization
primarily to see if we do end up with constant and this
SAVE_EXPR interferes with later optimizations, suppressing
- it when we can is important. */
+ it when we can is important.
- if (TREE_CODE (arg0) != SAVE_EXPR
+ If we are not in a function, we can't make a SAVE_EXPR, so don't
+ try to do so. Don't try to see if the result is a constant
+ if an arm is a COND_EXPR since we get exponential behavior
+ in that case. */
+
+ if (TREE_CODE (arg0) != SAVE_EXPR && ! TREE_CONSTANT (arg0)
+ && current_function_decl != 0
&& ((TREE_CODE (arg0) != VAR_DECL
&& TREE_CODE (arg0) != PARM_DECL)
|| TREE_SIDE_EFFECTS (arg0)))
{
- tree lhs = fold (build (code, type, arg0, true_value));
- tree rhs = fold (build (code, type, arg0, false_value));
+ if (TREE_CODE (true_value) != COND_EXPR)
+ lhs = fold (build (code, type, arg0, true_value));
- if (TREE_CONSTANT (lhs) || TREE_CONSTANT (rhs))
- return fold (build (COND_EXPR, type, test, lhs, rhs));
+ if (TREE_CODE (false_value) != COND_EXPR)
+ rhs = fold (build (code, type, arg0, false_value));
- arg0 = save_expr (arg0);
+ if ((lhs == 0 || ! TREE_CONSTANT (lhs))
+ && (rhs == 0 || !TREE_CONSTANT (rhs)))
+ arg0 = save_expr (arg0), lhs = rhs = 0;
}
- test = fold (build (COND_EXPR, type, test,
- fold (build (code, type, arg0, true_value)),
- fold (build (code, type, arg0, false_value))));
+ if (lhs == 0)
+ lhs = fold (build (code, type, arg0, true_value));
+ if (rhs == 0)
+ rhs = fold (build (code, type, arg0, false_value));
+
+ test = fold (build (COND_EXPR, type, test, lhs, rhs));
+
if (TREE_CODE (arg0) == SAVE_EXPR)
return build (COMPOUND_EXPR, type,
convert (void_type_node, arg0),
@@ -3335,10 +4081,15 @@ fold (expr)
else if (TREE_CODE (arg0) == COMPOUND_EXPR)
return build (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0),
fold (build (code, type, TREE_OPERAND (arg0, 1), arg1)));
- else if (TREE_CODE (arg0) == COND_EXPR
- || TREE_CODE_CLASS (TREE_CODE (arg0)) == '<')
+ else if ((TREE_CODE (arg0) == COND_EXPR
+ || (TREE_CODE_CLASS (TREE_CODE (arg0)) == '<'
+ && TREE_CODE_CLASS (code) != '<'))
+ && (! TREE_SIDE_EFFECTS (arg1)
+ || (current_function_decl != 0
+ && ! contains_placeholder_p (arg1))))
{
tree test, true_value, false_value;
+ tree lhs = 0, rhs = 0;
if (TREE_CODE (arg0) == COND_EXPR)
{
@@ -3354,24 +4105,30 @@ fold (expr)
false_value = convert (testtype, integer_zero_node);
}
- if (TREE_CODE (arg1) != SAVE_EXPR
+ if (TREE_CODE (arg1) != SAVE_EXPR && ! TREE_CONSTANT (arg0)
+ && current_function_decl != 0
&& ((TREE_CODE (arg1) != VAR_DECL
&& TREE_CODE (arg1) != PARM_DECL)
|| TREE_SIDE_EFFECTS (arg1)))
{
- tree lhs = fold (build (code, type, true_value, arg1));
- tree rhs = fold (build (code, type, false_value, arg1));
+ if (TREE_CODE (true_value) != COND_EXPR)
+ lhs = fold (build (code, type, true_value, arg1));
- if (TREE_CONSTANT (lhs) || TREE_CONSTANT (rhs)
- || TREE_CONSTANT (arg1))
- return fold (build (COND_EXPR, type, test, lhs, rhs));
+ if (TREE_CODE (false_value) != COND_EXPR)
+ rhs = fold (build (code, type, false_value, arg1));
- arg1 = save_expr (arg1);
+ if ((lhs == 0 || ! TREE_CONSTANT (lhs))
+ && (rhs == 0 || !TREE_CONSTANT (rhs)))
+ arg1 = save_expr (arg1), lhs = rhs = 0;
}
- test = fold (build (COND_EXPR, type, test,
- fold (build (code, type, true_value, arg1)),
- fold (build (code, type, false_value, arg1))));
+ if (lhs == 0)
+ lhs = fold (build (code, type, true_value, arg1));
+
+ if (rhs == 0)
+ rhs = fold (build (code, type, false_value, arg1));
+
+ test = fold (build (COND_EXPR, type, test, lhs, rhs));
if (TREE_CODE (arg1) == SAVE_EXPR)
return build (COMPOUND_EXPR, type,
convert (void_type_node, arg1),
@@ -3457,6 +4214,13 @@ fold (expr)
&& ! final_ptr)
return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
+ /* If we have a sign-extension of a zero-extended value, we can
+ replace that by a single zero-extension. */
+ if (inside_int && inter_int && final_int
+ && inside_prec < inter_prec && inter_prec < final_prec
+ && inside_unsignedp && !inter_unsignedp)
+ return convert (final_type, TREE_OPERAND (TREE_OPERAND (t, 0), 0));
+
/* Two conversions in a row are not needed unless:
- some conversion is floating-point (overstrict for now), or
- the intermediate type is narrower than both initial and
@@ -3549,13 +4313,12 @@ fold (expr)
TREE_TYPE (t) = type;
TREE_OVERFLOW (t)
= (TREE_OVERFLOW (arg0)
- | force_fit_type (t, overflow));
+ | force_fit_type (t, overflow && !TREE_UNSIGNED (type)));
TREE_CONSTANT_OVERFLOW (t)
= TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
}
else if (TREE_CODE (arg0) == REAL_CST)
t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
- TREE_TYPE (t) = type;
}
else if (TREE_CODE (arg0) == NEGATE_EXPR)
return TREE_OPERAND (arg0, 0);
@@ -3594,7 +4357,6 @@ fold (expr)
t = build_real (type,
REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
}
- TREE_TYPE (t) = type;
}
else if (TREE_CODE (arg0) == ABS_EXPR || TREE_CODE (arg0) == NEGATE_EXPR)
return build1 (ABS_EXPR, type, TREE_OPERAND (arg0, 0));
@@ -3610,7 +4372,7 @@ fold (expr)
TREE_TYPE (TREE_TYPE (arg0)),
TREE_OPERAND (arg0, 1))));
else if (TREE_CODE (arg0) == COMPLEX_CST)
- return build_complex (TREE_OPERAND (arg0, 0),
+ return build_complex (type, TREE_OPERAND (arg0, 0),
fold (build1 (NEGATE_EXPR,
TREE_TYPE (TREE_TYPE (arg0)),
TREE_OPERAND (arg0, 1))));
@@ -3627,9 +4389,8 @@ fold (expr)
case BIT_NOT_EXPR:
if (wins)
{
- if (TREE_CODE (arg0) == INTEGER_CST)
- t = build_int_2 (~ TREE_INT_CST_LOW (arg0),
- ~ TREE_INT_CST_HIGH (arg0));
+ t = build_int_2 (~ TREE_INT_CST_LOW (arg0),
+ ~ TREE_INT_CST_HIGH (arg0));
TREE_TYPE (t) = type;
force_fit_type (t, 0);
TREE_OVERFLOW (t) = TREE_OVERFLOW (arg0);
@@ -3796,7 +4557,9 @@ fold (expr)
{
/* The return value should always have
the same type as the original expression. */
- TREE_TYPE (t1) = TREE_TYPE (t);
+ if (TREE_TYPE (t1) != TREE_TYPE (t))
+ t1 = convert (TREE_TYPE (t), t1);
+
return t1;
}
return t;
@@ -3888,7 +4651,8 @@ fold (expr)
if (real_onep (arg1))
return non_lvalue (convert (type, arg0));
/* x*2 is x+x */
- if (! wins && real_twop (arg1))
+ if (! wins && real_twop (arg1) && current_function_decl != 0
+ && ! contains_placeholder_p (arg0))
{
tree arg = save_expr (arg0);
return build (PLUS_EXPR, type, arg, arg);
@@ -3898,6 +4662,9 @@ fold (expr)
case BIT_IOR_EXPR:
bit_ior:
+ {
+ register enum tree_code code0, code1;
+
if (integer_all_onesp (arg1))
return omit_one_operand (type, arg1, arg0);
if (integer_zerop (arg1))
@@ -3906,28 +4673,53 @@ fold (expr)
if (t1 != NULL_TREE)
return t1;
- /* (a << C1) | (a >> C2) if A is unsigned and C1+C2 is the size of A
+ /* (A << C1) | (A >> C2) if A is unsigned and C1+C2 is the size of A
is a rotate of A by C1 bits. */
+ /* (A << B) | (A >> (Z - B)) if A is unsigned and Z is the size of A
+ is a rotate of A by B bits. */
- if ((TREE_CODE (arg0) == RSHIFT_EXPR
- || TREE_CODE (arg0) == LSHIFT_EXPR)
- && (TREE_CODE (arg1) == RSHIFT_EXPR
- || TREE_CODE (arg1) == LSHIFT_EXPR)
- && TREE_CODE (arg0) != TREE_CODE (arg1)
+ code0 = TREE_CODE (arg0);
+ code1 = TREE_CODE (arg1);
+ if (((code0 == RSHIFT_EXPR && code1 == LSHIFT_EXPR)
+ || (code1 == RSHIFT_EXPR && code0 == LSHIFT_EXPR))
&& operand_equal_p (TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1,0), 0)
- && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0)))
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
- && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST
- && TREE_INT_CST_HIGH (TREE_OPERAND (arg0, 1)) == 0
- && TREE_INT_CST_HIGH (TREE_OPERAND (arg1, 1)) == 0
- && ((TREE_INT_CST_LOW (TREE_OPERAND (arg0, 1))
- + TREE_INT_CST_LOW (TREE_OPERAND (arg1, 1)))
+ && TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 0))))
+ {
+ register tree tree01, tree11;
+ register enum tree_code code01, code11;
+
+ tree01 = TREE_OPERAND (arg0, 1);
+ tree11 = TREE_OPERAND (arg1, 1);
+ code01 = TREE_CODE (tree01);
+ code11 = TREE_CODE (tree11);
+ if (code01 == INTEGER_CST
+ && code11 == INTEGER_CST
+ && TREE_INT_CST_HIGH (tree01) == 0
+ && TREE_INT_CST_HIGH (tree11) == 0
+ && ((TREE_INT_CST_LOW (tree01) + TREE_INT_CST_LOW (tree11))
== TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
- return build (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
- TREE_CODE (arg0) == LSHIFT_EXPR
- ? TREE_OPERAND (arg0, 1) : TREE_OPERAND (arg1, 1));
+ return build (LROTATE_EXPR, type, TREE_OPERAND (arg0, 0),
+ code0 == LSHIFT_EXPR ? tree01 : tree11);
+ else if (code11 == MINUS_EXPR
+ && TREE_CODE (TREE_OPERAND (tree11, 0)) == INTEGER_CST
+ && TREE_INT_CST_HIGH (TREE_OPERAND (tree11, 0)) == 0
+ && TREE_INT_CST_LOW (TREE_OPERAND (tree11, 0))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))
+ && operand_equal_p (tree01, TREE_OPERAND (tree11, 1), 0))
+ return build (code0 == LSHIFT_EXPR ? LROTATE_EXPR : RROTATE_EXPR,
+ type, TREE_OPERAND (arg0, 0), tree01);
+ else if (code01 == MINUS_EXPR
+ && TREE_CODE (TREE_OPERAND (tree01, 0)) == INTEGER_CST
+ && TREE_INT_CST_HIGH (TREE_OPERAND (tree01, 0)) == 0
+ && TREE_INT_CST_LOW (TREE_OPERAND (tree01, 0))
+ == TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg0, 0)))
+ && operand_equal_p (tree11, TREE_OPERAND (tree01, 1), 0))
+ return build (code0 != LSHIFT_EXPR ? LROTATE_EXPR : RROTATE_EXPR,
+ type, TREE_OPERAND (arg0, 0), tree11);
+ }
goto associate;
+ }
case BIT_XOR_EXPR:
if (integer_zerop (arg1))
@@ -3998,11 +4790,24 @@ fold (expr)
so only do this if -ffast-math. We can actually always safely
do it if ARG1 is a power of two, but it's hard to tell if it is
or not in a portable manner. */
- if (TREE_CODE (arg1) == REAL_CST && flag_fast_math
- && 0 != (tem = const_binop (code, build_real (type, dconst1),
- arg1, 0)))
- return fold (build (MULT_EXPR, type, arg0, tem));
-
+ if (TREE_CODE (arg1) == REAL_CST)
+ {
+ if (flag_fast_math
+ && 0 != (tem = const_binop (code, build_real (type, dconst1),
+ arg1, 0)))
+ return fold (build (MULT_EXPR, type, arg0, tem));
+ /* Find the reciprocal if optimizing and the result is exact. */
+ else if (optimize)
+ {
+ REAL_VALUE_TYPE r;
+ r = TREE_REAL_CST (arg1);
+ if (exact_real_inverse (TYPE_MODE(TREE_TYPE(arg0)), &r))
+ {
+ tem = build_real (type, r);
+ return fold (build (MULT_EXPR, type, arg0, tem));
+ }
+ }
+ }
goto binary;
case TRUNC_DIV_EXPR:
@@ -4015,6 +4820,16 @@ fold (expr)
if (integer_zerop (arg1))
return t;
+ /* If arg0 is a multiple of arg1, then rewrite to the fastest div
+ operation, EXACT_DIV_EXPR.
+
+ Note that only CEIL_DIV_EXPR and FLOOR_DIV_EXPR are rewritten now.
+ At one time others generated faster code, it's not clear if they do
+ after the last round to changes to the DIV code in expmed.c. */
+ if ((code == CEIL_DIV_EXPR || code == FLOOR_DIV_EXPR)
+ && multiple_of_p (type, arg0, arg1))
+ return fold (build (EXACT_DIV_EXPR, type, arg0, arg1));
+
/* If we have ((a / C1) / C2) where both division are the same type, try
to simplify. First see if C1 * C2 overflows or not. */
if (TREE_CODE (arg0) == code && TREE_CODE (arg1) == INTEGER_CST
@@ -4048,11 +4863,42 @@ fold (expr)
tree c2 = integer_zero_node;
tree xarg0 = arg0;
- if (TREE_CODE (xarg0) == SAVE_EXPR)
+ if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0)
have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0);
STRIP_NOPS (xarg0);
+ /* Look inside the dividend and simplify using EXACT_DIV_EXPR
+ if possible. */
+ if (TREE_CODE (xarg0) == MULT_EXPR
+ && multiple_of_p (type, TREE_OPERAND (xarg0, 0), arg1))
+ {
+ tree t;
+
+ t = fold (build (MULT_EXPR, type,
+ fold (build (EXACT_DIV_EXPR, type,
+ TREE_OPERAND (xarg0, 0), arg1)),
+ TREE_OPERAND (xarg0, 1)));
+ if (have_save_expr)
+ t = save_expr (t);
+ return t;
+
+ }
+
+ if (TREE_CODE (xarg0) == MULT_EXPR
+ && multiple_of_p (type, TREE_OPERAND (xarg0, 1), arg1))
+ {
+ tree t;
+
+ t = fold (build (MULT_EXPR, type,
+ fold (build (EXACT_DIV_EXPR, type,
+ TREE_OPERAND (xarg0, 1), arg1)),
+ TREE_OPERAND (xarg0, 0)));
+ if (have_save_expr)
+ t = save_expr (t);
+ return t;
+ }
+
if (TREE_CODE (xarg0) == PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (xarg0, 1)) == INTEGER_CST)
c2 = TREE_OPERAND (xarg0, 1), xarg0 = TREE_OPERAND (xarg0, 0);
@@ -4066,7 +4912,7 @@ fold (expr)
xarg0 = TREE_OPERAND (xarg0, 0);
}
- if (TREE_CODE (xarg0) == SAVE_EXPR)
+ if (TREE_CODE (xarg0) == SAVE_EXPR && SAVE_EXPR_RTL (xarg0) == 0)
have_save_expr = 1, xarg0 = TREE_OPERAND (xarg0, 0);
STRIP_NOPS (xarg0);
@@ -4222,6 +5068,7 @@ fold (expr)
if (operand_equal_p (arg0, arg1, 0))
return arg0;
if (INTEGRAL_TYPE_P (type)
+ && TYPE_MAX_VALUE (type)
&& operand_equal_p (arg1, TYPE_MAX_VALUE (type), 1))
return omit_one_operand (type, arg1, arg0);
goto associate;
@@ -4254,6 +5101,10 @@ fold (expr)
must be evaluated. */
if (integer_zerop (arg1))
return omit_one_operand (type, arg1, arg0);
+ /* Likewise for first arg, but note that only the TRUTH_AND_EXPR
+ case will be handled here. */
+ if (integer_zerop (arg0))
+ return omit_one_operand (type, arg0, arg1);
truth_andor:
/* We only do these simplifications if we are optimizing. */
@@ -4264,12 +5115,14 @@ fold (expr)
to A || (B && C). Note that either operator can be any of the four
truth and/or operations and the transformation will still be
valid. Also note that we only care about order for the
- ANDIF and ORIF operators. */
+ ANDIF and ORIF operators. If B contains side effects, this
+ might change the truth-value of A. */
if (TREE_CODE (arg0) == TREE_CODE (arg1)
&& (TREE_CODE (arg0) == TRUTH_ANDIF_EXPR
|| TREE_CODE (arg0) == TRUTH_ORIF_EXPR
|| TREE_CODE (arg0) == TRUTH_AND_EXPR
- || TREE_CODE (arg0) == TRUTH_OR_EXPR))
+ || TREE_CODE (arg0) == TRUTH_OR_EXPR)
+ && ! TREE_SIDE_EFFECTS (TREE_OPERAND (arg0, 1)))
{
tree a00 = TREE_OPERAND (arg0, 0);
tree a01 = TREE_OPERAND (arg0, 1);
@@ -4300,6 +5153,10 @@ fold (expr)
a01));
}
+ /* See if we can build a range comparison. */
+ if (0 != (tem = fold_range_test (t)))
+ return tem;
+
/* Check for the possibility of merging component references. If our
lhs is another similar operation, try to merge its rhs with our
rhs. Then try to merge our lhs and rhs. */
@@ -4330,6 +5187,10 @@ fold (expr)
evaluate first arg. */
if (TREE_CODE (arg1) == INTEGER_CST && ! integer_zerop (arg1))
return omit_one_operand (type, arg1, arg0);
+ /* Likewise for first arg, but note this only occurs here for
+ TRUTH_OR_EXPR. */
+ if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0))
+ return omit_one_operand (type, arg0, arg1);
goto truth_andor;
case TRUTH_XOR_EXPR:
@@ -4367,7 +5228,7 @@ fold (expr)
First, see if one arg is constant; find the constant arg
and the other one. */
{
- tree constop = 0, varop;
+ tree constop = 0, varop = NULL_TREE;
int constopnum = -1;
if (TREE_CONSTANT (arg1))
@@ -4381,7 +5242,7 @@ fold (expr)
if CONST+INCR overflows or if foo+incr might overflow.
This optimization is invalid for floating point due to rounding.
For pointer types we assume overflow doesn't happen. */
- if (TREE_CODE (TREE_TYPE (varop)) == POINTER_TYPE
+ if (POINTER_TYPE_P (TREE_TYPE (varop))
|| (! FLOAT_TYPE_P (TREE_TYPE (varop))
&& (code == EQ_EXPR || code == NE_EXPR)))
{
@@ -4390,6 +5251,48 @@ fold (expr)
constop, TREE_OPERAND (varop, 1)));
TREE_SET_CODE (varop, PREINCREMENT_EXPR);
+ /* If VAROP is a reference to a bitfield, we must mask
+ the constant by the width of the field. */
+ if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
+ && DECL_BIT_FIELD(TREE_OPERAND
+ (TREE_OPERAND (varop, 0), 1)))
+ {
+ int size
+ = TREE_INT_CST_LOW (DECL_SIZE
+ (TREE_OPERAND
+ (TREE_OPERAND (varop, 0), 1)));
+ tree mask, unsigned_type;
+ int precision;
+ tree folded_compare;
+
+ /* First check whether the comparison would come out
+ always the same. If we don't do that we would
+ change the meaning with the masking. */
+ if (constopnum == 0)
+ folded_compare = fold (build (code, type, constop,
+ TREE_OPERAND (varop, 0)));
+ else
+ folded_compare = fold (build (code, type,
+ TREE_OPERAND (varop, 0),
+ constop));
+ if (integer_zerop (folded_compare)
+ || integer_onep (folded_compare))
+ return omit_one_operand (type, folded_compare, varop);
+
+ unsigned_type = type_for_size (size, 1);
+ precision = TYPE_PRECISION (unsigned_type);
+ mask = build_int_2 (~0, ~0);
+ TREE_TYPE (mask) = unsigned_type;
+ force_fit_type (mask, 0);
+ mask = const_binop (RSHIFT_EXPR, mask,
+ size_int (precision - size), 0);
+ newconst = fold (build (BIT_AND_EXPR,
+ TREE_TYPE (varop), newconst,
+ convert (TREE_TYPE (varop),
+ mask)));
+ }
+
+
t = build (code, type, TREE_OPERAND (t, 0),
TREE_OPERAND (t, 1));
TREE_OPERAND (t, constopnum) = newconst;
@@ -4398,7 +5301,7 @@ fold (expr)
}
else if (constop && TREE_CODE (varop) == POSTDECREMENT_EXPR)
{
- if (TREE_CODE (TREE_TYPE (varop)) == POINTER_TYPE
+ if (POINTER_TYPE_P (TREE_TYPE (varop))
|| (! FLOAT_TYPE_P (TREE_TYPE (varop))
&& (code == EQ_EXPR || code == NE_EXPR)))
{
@@ -4406,6 +5309,44 @@ fold (expr)
= fold (build (MINUS_EXPR, TREE_TYPE (varop),
constop, TREE_OPERAND (varop, 1)));
TREE_SET_CODE (varop, PREDECREMENT_EXPR);
+
+ if (TREE_CODE (TREE_OPERAND (varop, 0)) == COMPONENT_REF
+ && DECL_BIT_FIELD(TREE_OPERAND
+ (TREE_OPERAND (varop, 0), 1)))
+ {
+ int size
+ = TREE_INT_CST_LOW (DECL_SIZE
+ (TREE_OPERAND
+ (TREE_OPERAND (varop, 0), 1)));
+ tree mask, unsigned_type;
+ int precision;
+ tree folded_compare;
+
+ if (constopnum == 0)
+ folded_compare = fold (build (code, type, constop,
+ TREE_OPERAND (varop, 0)));
+ else
+ folded_compare = fold (build (code, type,
+ TREE_OPERAND (varop, 0),
+ constop));
+ if (integer_zerop (folded_compare)
+ || integer_onep (folded_compare))
+ return omit_one_operand (type, folded_compare, varop);
+
+ unsigned_type = type_for_size (size, 1);
+ precision = TYPE_PRECISION (unsigned_type);
+ mask = build_int_2 (~0, ~0);
+ TREE_TYPE (mask) = TREE_TYPE (varop);
+ force_fit_type (mask, 0);
+ mask = const_binop (RSHIFT_EXPR, mask,
+ size_int (precision - size), 0);
+ newconst = fold (build (BIT_AND_EXPR,
+ TREE_TYPE (varop), newconst,
+ convert (TREE_TYPE (varop),
+ mask)));
+ }
+
+
t = build (code, type, TREE_OPERAND (t, 0),
TREE_OPERAND (t, 1));
TREE_OPERAND (t, constopnum) = newconst;
@@ -4432,13 +5373,16 @@ fold (expr)
arg1 = const_binop (MINUS_EXPR, arg1, integer_one_node, 0);
t = build (code, type, TREE_OPERAND (t, 0), arg1);
break;
+
+ default:
+ break;
}
}
/* If this is an EQ or NE comparison with zero and ARG0 is
(1 << foo) & bar, convert it to (bar >> foo) & 1. Both require
two operations, but the latter can be done in one less insn
- one machine that have only two-operand insns or on which a
+ on machines that have only two-operand insns or on which a
constant cannot be the first operand. */
if (integer_zerop (arg1) && (code == EQ_EXPR || code == NE_EXPR)
&& TREE_CODE (arg0) == BIT_AND_EXPR)
@@ -4539,11 +5483,7 @@ fold (expr)
case GE_EXPR:
case LE_EXPR:
if (INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
- {
- t = build_int_2 (1, 0);
- TREE_TYPE (t) = type;
- return t;
- }
+ return constant_boolean_node (1, type);
code = EQ_EXPR;
TREE_SET_CODE (t, code);
break;
@@ -4552,19 +5492,19 @@ fold (expr)
/* For NE, we can only do this simplification if integer. */
if (! INTEGRAL_TYPE_P (TREE_TYPE (arg0)))
break;
- /* ... fall through ... */
+ /* ... fall through ... */
case GT_EXPR:
case LT_EXPR:
- t = build_int_2 (0, 0);
- TREE_TYPE (t) = type;
- return t;
+ return constant_boolean_node (0, type);
+ default:
+ abort ();
}
}
/* An unsigned comparison against 0 can be simplified. */
if (integer_zerop (arg1)
&& (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
- || TREE_CODE (TREE_TYPE (arg1)) == POINTER_TYPE)
+ || POINTER_TYPE_P (TREE_TYPE (arg1)))
&& TREE_UNSIGNED (TREE_TYPE (arg1)))
{
switch (TREE_CODE (t))
@@ -4585,9 +5525,43 @@ fold (expr)
return omit_one_operand (type,
convert (type, integer_zero_node),
arg0);
+ default:
+ break;
}
}
+ /* An unsigned <= 0x7fffffff can be simplified. */
+ {
+ int width = TYPE_PRECISION (TREE_TYPE (arg1));
+ if (TREE_CODE (arg1) == INTEGER_CST
+ && ! TREE_CONSTANT_OVERFLOW (arg1)
+ && width <= HOST_BITS_PER_WIDE_INT
+ && TREE_INT_CST_LOW (arg1) == ((HOST_WIDE_INT) 1 << (width - 1)) - 1
+ && TREE_INT_CST_HIGH (arg1) == 0
+ && (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
+ || POINTER_TYPE_P (TREE_TYPE (arg1)))
+ && TREE_UNSIGNED (TREE_TYPE (arg1)))
+ {
+ switch (TREE_CODE (t))
+ {
+ case LE_EXPR:
+ return fold (build (GE_EXPR, type,
+ convert (signed_type (TREE_TYPE (arg0)),
+ arg0),
+ convert (signed_type (TREE_TYPE (arg1)),
+ integer_zero_node)));
+ case GT_EXPR:
+ return fold (build (LT_EXPR, type,
+ convert (signed_type (TREE_TYPE (arg0)),
+ arg0),
+ convert (signed_type (TREE_TYPE (arg1)),
+ integer_zero_node)));
+ default:
+ break;
+ }
+ }
+ }
+
/* If we are comparing an expression that just has comparisons
of two integer values, arithmetic expressions of those comparisons,
and constants, we can simplify it. There are only three cases
@@ -4613,6 +5587,8 @@ fold (expr)
&& ! (TREE_CONSTANT (cval1) && TREE_CONSTANT (cval2))
&& TREE_TYPE (cval1) == TREE_TYPE (cval2)
&& INTEGRAL_TYPE_P (TREE_TYPE (cval1))
+ && TYPE_MAX_VALUE (TREE_TYPE (cval1))
+ && TYPE_MAX_VALUE (TREE_TYPE (cval2))
&& ! operand_equal_p (TYPE_MIN_VALUE (TREE_TYPE (cval1)),
TYPE_MAX_VALUE (TREE_TYPE (cval2)), 0))
{
@@ -4689,30 +5665,36 @@ fold (expr)
/* If this is a comparison of a field, we may be able to simplify it. */
if ((TREE_CODE (arg0) == COMPONENT_REF
- || TREE_CODE (arg0) == BIT_FIELD_REF)
- && (code == EQ_EXPR || code == NE_EXPR)
- /* Handle the constant case even without -O
- to make sure the warnings are given. */
- && (optimize || TREE_CODE (arg1) == INTEGER_CST))
+ || TREE_CODE (arg0) == BIT_FIELD_REF)
+ && (code == EQ_EXPR || code == NE_EXPR)
+ /* Handle the constant case even without -O
+ to make sure the warnings are given. */
+ && (optimize || TREE_CODE (arg1) == INTEGER_CST))
{
t1 = optimize_bit_field_compare (code, type, arg0, arg1);
return t1 ? t1 : t;
}
- /* If this is a comparison of complex values and either or both
- sizes are a COMPLEX_EXPR, it is best to split up the comparisons
- and join them with a TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR. This
- may prevent needless evaluations. */
+ /* If this is a comparison of complex values and either or both sides
+ are a COMPLEX_EXPR or COMPLEX_CST, it is best to split up the
+ comparisons and join them with a TRUTH_ANDIF_EXPR or TRUTH_ORIF_EXPR.
+ This may prevent needless evaluations. */
if ((code == EQ_EXPR || code == NE_EXPR)
&& TREE_CODE (TREE_TYPE (arg0)) == COMPLEX_TYPE
&& (TREE_CODE (arg0) == COMPLEX_EXPR
- || TREE_CODE (arg1) == COMPLEX_EXPR))
+ || TREE_CODE (arg1) == COMPLEX_EXPR
+ || TREE_CODE (arg0) == COMPLEX_CST
+ || TREE_CODE (arg1) == COMPLEX_CST))
{
tree subtype = TREE_TYPE (TREE_TYPE (arg0));
- tree real0 = fold (build1 (REALPART_EXPR, subtype, arg0));
- tree imag0 = fold (build1 (IMAGPART_EXPR, subtype, arg0));
- tree real1 = fold (build1 (REALPART_EXPR, subtype, arg1));
- tree imag1 = fold (build1 (IMAGPART_EXPR, subtype, arg1));
+ tree real0, imag0, real1, imag1;
+
+ arg0 = save_expr (arg0);
+ arg1 = save_expr (arg1);
+ real0 = fold (build1 (REALPART_EXPR, subtype, arg0));
+ imag0 = fold (build1 (IMAGPART_EXPR, subtype, arg0));
+ real1 = fold (build1 (REALPART_EXPR, subtype, arg1));
+ imag1 = fold (build1 (IMAGPART_EXPR, subtype, arg1));
return fold (build ((code == EQ_EXPR ? TRUTH_ANDIF_EXPR
: TRUTH_ORIF_EXPR),
@@ -4764,6 +5746,7 @@ fold (expr)
0);
}
+#if 0 /* This is no longer useful, but breaks some real code. */
/* Assume a nonexplicit constant cannot equal an explicit one,
since such code would be undefined anyway.
Exception: on sysvr4, using #pragma weak,
@@ -4774,7 +5757,7 @@ fold (expr)
&& TREE_CODE (arg0) == ADDR_EXPR
&& code == EQ_EXPR)
t1 = build_int_2 (0, 0);
-
+#endif
/* Two real constants can be compared explicitly. */
else if (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
{
@@ -4806,6 +5789,8 @@ fold (expr)
TREE_INT_CST_LOW (t1) ^= 1;
TREE_TYPE (t1) = type;
+ if (TREE_CODE (type) == BOOLEAN_TYPE)
+ return truthvalue_conversion (t1);
return t1;
case COND_EXPR:
@@ -4888,6 +5873,8 @@ fold (expr)
fold (build1 (ABS_EXPR,
TREE_TYPE (arg1),
arg1))))));
+ default:
+ abort ();
}
/* If this is A != 0 ? A : 0, this is simply A. For ==, it is
@@ -4919,14 +5906,28 @@ fold (expr)
return pedantic_non_lvalue (convert (type, arg1));
case LE_EXPR:
case LT_EXPR:
+ /* In C++ a ?: expression can be an lvalue, so put the
+ operand which will be used if they are equal first
+ so that we can convert this back to the
+ corresponding COND_EXPR. */
return pedantic_non_lvalue
(convert (type, (fold (build (MIN_EXPR, comp_type,
- comp_op0, comp_op1)))));
+ (comp_code == LE_EXPR
+ ? comp_op0 : comp_op1),
+ (comp_code == LE_EXPR
+ ? comp_op1 : comp_op0))))));
+ break;
case GE_EXPR:
case GT_EXPR:
return pedantic_non_lvalue
(convert (type, fold (build (MAX_EXPR, comp_type,
- comp_op0, comp_op1))));
+ (comp_code == GE_EXPR
+ ? comp_op0 : comp_op1),
+ (comp_code == GE_EXPR
+ ? comp_op1 : comp_op0)))));
+ break;
+ default:
+ abort ();
}
}
@@ -4987,6 +5988,10 @@ fold (expr)
return pedantic_non_lvalue
(fold (build (MAX_EXPR, type, arg1, arg2)));
break;
+ case NE_EXPR:
+ break;
+ default:
+ abort ();
}
}
@@ -5049,7 +6054,7 @@ fold (expr)
case COMPLEX_EXPR:
if (wins)
- return build_complex (arg0, arg1);
+ return build_complex (type, arg0, arg1);
return t;
case REALPART_EXPR:
@@ -5087,8 +6092,8 @@ fold (expr)
/* Pull arithmetic ops out of the CLEANUP_POINT_EXPR where
appropriate. */
case CLEANUP_POINT_EXPR:
- if (! TREE_SIDE_EFFECTS (arg0))
- return convert (type, arg0);
+ if (! has_cleanups (arg0))
+ return TREE_OPERAND (t, 0);
{
enum tree_code code0 = TREE_CODE (arg0);
@@ -5108,12 +6113,14 @@ fold (expr)
{
arg01 = TREE_OPERAND (arg0, 1);
- if (! TREE_SIDE_EFFECTS (arg00))
+ if (TREE_CONSTANT (arg00)
+ || ((code0 == TRUTH_ANDIF_EXPR || code0 == TRUTH_ORIF_EXPR)
+ && ! has_cleanups (arg00)))
return fold (build (code0, type, arg00,
fold (build1 (CLEANUP_POINT_EXPR,
TREE_TYPE (arg01), arg01))));
- if (! TREE_SIDE_EFFECTS (arg01))
+ if (TREE_CONSTANT (arg01))
return fold (build (code0, type,
fold (build1 (CLEANUP_POINT_EXPR,
TREE_TYPE (arg00), arg00)),
@@ -5127,3 +6134,104 @@ fold (expr)
return t;
} /* switch (code) */
}
+
+/* Determine if first argument is a multiple of second argument.
+ Return 0 if it is not, or is not easily determined to so be.
+
+ An example of the sort of thing we care about (at this point --
+ this routine could surely be made more general, and expanded
+ to do what the *_DIV_EXPR's fold() cases do now) is discovering
+ that
+
+ SAVE_EXPR (I) * SAVE_EXPR (J * 8)
+
+ is a multiple of
+
+ SAVE_EXPR (J * 8)
+
+ when we know that the two `SAVE_EXPR (J * 8)' nodes are the
+ same node (which means they will have the same value at run
+ time, even though we don't know when they'll be assigned).
+
+ This code also handles discovering that
+
+ SAVE_EXPR (I) * SAVE_EXPR (J * 8)
+
+ is a multiple of
+
+ 8
+
+ (of course) so we don't have to worry about dealing with a
+ possible remainder.
+
+ Note that we _look_ inside a SAVE_EXPR only to determine
+ how it was calculated; it is not safe for fold() to do much
+ of anything else with the internals of a SAVE_EXPR, since
+ fold() cannot know when it will be evaluated at run time.
+ For example, the latter example above _cannot_ be implemented
+ as
+
+ SAVE_EXPR (I) * J
+
+ or any variant thereof, since the value of J at evaluation time
+ of the original SAVE_EXPR is not necessarily the same at the time
+ the new expression is evaluated. The only optimization of this
+ sort that would be valid is changing
+
+ SAVE_EXPR (I) * SAVE_EXPR (SAVE_EXPR (J) * 8)
+ divided by
+ 8
+
+ to
+
+ SAVE_EXPR (I) * SAVE_EXPR (J)
+
+ (where the same SAVE_EXPR (J) is used in the original and the
+ transformed version). */
+
+static int
+multiple_of_p (type, top, bottom)
+ tree type;
+ tree top;
+ tree bottom;
+{
+ if (operand_equal_p (top, bottom, 0))
+ return 1;
+
+ if (TREE_CODE (type) != INTEGER_TYPE)
+ return 0;
+
+ switch (TREE_CODE (top))
+ {
+ case MULT_EXPR:
+ return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
+ || multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ return (multiple_of_p (type, TREE_OPERAND (top, 0), bottom)
+ && multiple_of_p (type, TREE_OPERAND (top, 1), bottom));
+
+ case NOP_EXPR:
+ /* Punt if conversion from non-integral or wider integral type. */
+ if ((TREE_CODE (TREE_TYPE (TREE_OPERAND (top, 0))) != INTEGER_TYPE)
+ || (TYPE_PRECISION (type)
+ < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (top, 0)))))
+ return 0;
+ /* Fall through. */
+ case SAVE_EXPR:
+ return multiple_of_p (type, TREE_OPERAND (top, 0), bottom);
+
+ case INTEGER_CST:
+ if ((TREE_CODE (bottom) != INTEGER_CST)
+ || (tree_int_cst_sgn (top) < 0)
+ || (tree_int_cst_sgn (bottom) < 0))
+ return 0;
+ return integer_zerop (const_binop (TRUNC_MOD_EXPR,
+ top, bottom, 0));
+
+ default:
+ return 0;
+ }
+}
+
diff --git a/contrib/gcc/fp-test.c b/contrib/gcc/fp-test.c
new file mode 100644
index 0000000..667059c
--- /dev/null
+++ b/contrib/gcc/fp-test.c
@@ -0,0 +1,231 @@
+/* fp-test.c - Check that all floating-point operations are available.
+ Copyright (C) 1995 Free Software Foundation, Inc.
+ Contributed by Ronald F. Guilmette <rfg@monkeys.com>.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This is a trivial test program which may be useful to people who are
+ porting the GCC or G++ compilers to a new system. The intent here is
+ merely to check that all floating-point operations have been provided
+ by the port. (Note that I say ``provided'' rather than ``implemented''.)
+
+ To use this file, simply compile it (with GCC or G++) and then try to
+ link it in the normal way (also using GCC or G++ respectively). If
+ all of the floating -point operations (including conversions) have
+ been provided, then this file will link without incident. If however
+ one or more of the primitive floating-point operations have not been
+ properly provided, you will get link-time errors indicating which
+ floating-point operations are unavailable.
+
+ This file will typically be used when porting the GNU compilers to
+ some system which lacks floating-point hardware, and for which
+ software emulation routines (for FP ops) are needed in order to
+ complete the port. */
+
+#if 0
+#include <math.h>
+#endif
+
+extern double acos (double);
+extern double asin (double);
+extern double atan (double);
+extern double atan2 (double, double);
+extern double cos (double);
+extern double sin (double);
+extern double tan (double);
+extern double cosh (double);
+extern double sinh (double);
+extern double tanh (double);
+extern double exp (double);
+extern double frexp (double, int *);
+extern double ldexp (double, int);
+extern double log (double);
+extern double log10 (double);
+extern double modf (double, double *);
+extern double pow (double, double);
+extern double sqrt (double);
+extern double ceil (double);
+extern double fabs (double);
+extern double floor (double);
+extern double fmod (double, double);
+
+int i1, i2 = 2;
+
+volatile signed char sc;
+volatile unsigned char uc;
+
+volatile signed short ss;
+volatile unsigned short us;
+
+volatile signed int si;
+volatile unsigned int ui;
+
+volatile signed long sl;
+volatile unsigned long ul;
+
+volatile float f1 = 1.0, f2 = 1.0, f3 = 1.0;
+volatile double d1 = 1.0, d2 = 1.0, d3 = 1.0;
+volatile long double D1 = 1.0, D2 = 1.0, D3 = 1.0;
+
+int
+main ()
+{
+ /* TYPE: float */
+
+ f1 = -f2;
+ f1 = f2 + f3;
+ f1 = f2 - f3;
+ f1 = f2 * f3;
+ f1 = f2 / f3;
+ f1 += f2;
+ f1 -= f2;
+ f1 *= f2;
+ f1 /= f2;
+
+ si = f1 == f2;
+ si = f1 != f2;
+ si = f1 > f2;
+ si = f1 < f2;
+ si = f1 >= f2;
+ si = f1 <= f2;
+
+ sc = f1;
+ uc = f1;
+ ss = f1;
+ us = f1;
+ si = f1;
+ ui = f1;
+ sl = f1;
+ ul = f1;
+ d1 = f1;
+ D1 = f1;
+
+ f1 = sc;
+ f1 = uc;
+ f1 = ss;
+ f1 = us;
+ f1 = si;
+ f1 = ui;
+ f1 = sl;
+ f1 = ul;
+ f1 = d1;
+ f1 = D1;
+
+ d1 = -d2;
+ d1 = d2 + d3;
+ d1 = d2 - d3;
+ d1 = d2 * d3;
+ d1 = d2 / d3;
+ d1 += d2;
+ d1 -= d2;
+ d1 *= d2;
+ d1 /= d2;
+
+ si = d1 == d2;
+ si = d1 != d2;
+ si = d1 > d2;
+ si = d1 < d2;
+ si = d1 >= d2;
+ si = d1 <= d2;
+
+ sc = d1;
+ uc = d1;
+ ss = d1;
+ us = d1;
+ si = d1;
+ ui = d1;
+ sl = d1;
+ ul = d1;
+ f1 = d1;
+ D1 = d1;
+
+ d1 = sc;
+ d1 = uc;
+ d1 = ss;
+ d1 = us;
+ d1 = si;
+ d1 = ui;
+ d1 = sl;
+ d1 = ul;
+ d1 = f1;
+ d1 = D1;
+
+ D1 = -D2;
+ D1 = D2 + D3;
+ D1 = D2 - D3;
+ D1 = D2 * D3;
+ D1 = D2 / D3;
+ D1 += D2;
+ D1 -= D2;
+ D1 *= D2;
+ D1 /= D2;
+
+ si = D1 == D2;
+ si = D1 != D2;
+ si = D1 > D2;
+ si = D1 < D2;
+ si = D1 >= D2;
+ si = D1 <= D2;
+
+ sc = D1;
+ uc = D1;
+ ss = D1;
+ us = D1;
+ si = D1;
+ ui = D1;
+ sl = D1;
+ ul = D1;
+ f1 = D1;
+ d1 = D1;
+
+ D1 = sc;
+ D1 = uc;
+ D1 = ss;
+ D1 = us;
+ D1 = si;
+ D1 = ui;
+ D1 = sl;
+ D1 = ul;
+ D1 = f1;
+ D1 = d1;
+
+ d1 = acos (d2);
+ d1 = asin (d2);
+ d1 = atan (d2);
+ d1 = atan2 (d2, d3);
+ d1 = cos (d2);
+ d1 = sin (d2);
+ d1 = tan (d2);
+ d1 = cosh (d2);
+ d1 = sinh (d2);
+ d1 = tanh (d2);
+ d1 = exp (d2);
+ d1 = frexp (d2, &i1);
+ d1 = ldexp (d2, i2);
+ d1 = log (d2);
+ d1 = log10 (d2);
+ d1 = modf (d2, &d3);
+ d1 = pow (d2, d3);
+ d1 = sqrt (d2);
+ d1 = ceil (d2);
+ d1 = fabs (d2);
+ d1 = floor (d2);
+ d1 = fmod (d2, d3);
+
+ return 0;
+}
diff --git a/contrib/gcc/frame.c b/contrib/gcc/frame.c
new file mode 100644
index 0000000..4b62759
--- /dev/null
+++ b/contrib/gcc/frame.c
@@ -0,0 +1,815 @@
+/* Subroutines needed for unwinding stack frames for exception handling. */
+/* Compile this one with gcc. */
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+ Contributed by Jason Merrill <jason@cygnus.com>.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+/* It is incorrect to include config.h here, because this file is being
+ compiled for the target, and hence definitions concerning only the host
+ do not apply. */
+
+#include "tconfig.h"
+
+/* We disable this when inhibit_libc, so that gcc can still be built without
+ needing header files first. */
+/* ??? This is not a good solution, since prototypes may be required in
+ some cases for correct code. See also libgcc2.c. */
+#ifndef inhibit_libc
+/* fixproto guarantees these system headers exist. */
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
+#include "defaults.h"
+
+#ifdef DWARF2_UNWIND_INFO
+#include "gansidecl.h"
+#include "dwarf2.h"
+#include <stddef.h>
+#include "frame.h"
+#include "gthr.h"
+
+#ifdef __GTHREAD_MUTEX_INIT
+static __gthread_mutex_t object_mutex = __GTHREAD_MUTEX_INIT;
+#else
+static __gthread_mutex_t object_mutex;
+#endif
+
+/* Don't use `fancy_abort' here even if config.h says to use it. */
+#ifdef abort
+#undef abort
+#endif
+
+/* Some types used by the DWARF 2 spec. */
+
+typedef int sword __attribute__ ((mode (SI)));
+typedef unsigned int uword __attribute__ ((mode (SI)));
+typedef unsigned int uaddr __attribute__ ((mode (pointer)));
+typedef int saddr __attribute__ ((mode (pointer)));
+typedef unsigned char ubyte;
+
+/* The first few fields of a CIE. The CIE_id field is 0 for a CIE,
+ to distinguish it from a valid FDE. FDEs are aligned to an addressing
+ unit boundary, but the fields within are unaligned. */
+
+struct dwarf_cie {
+ uword length;
+ sword CIE_id;
+ ubyte version;
+ char augmentation[0];
+} __attribute__ ((packed, aligned (__alignof__ (void *))));
+
+/* The first few fields of an FDE. */
+
+struct dwarf_fde {
+ uword length;
+ sword CIE_delta;
+ void* pc_begin;
+ uaddr pc_range;
+} __attribute__ ((packed, aligned (__alignof__ (void *))));
+
+typedef struct dwarf_fde fde;
+
+/* Objects to be searched for frame unwind info. */
+
+static struct object *objects;
+
+/* The information we care about from a CIE. */
+
+struct cie_info {
+ char *augmentation;
+ void *eh_ptr;
+ int code_align;
+ int data_align;
+ unsigned ra_regno;
+};
+
+/* The current unwind state, plus a saved copy for DW_CFA_remember_state. */
+
+struct frame_state_internal
+{
+ struct frame_state s;
+ struct frame_state_internal *saved_state;
+};
+
+/* Decode the unsigned LEB128 constant at BUF into the variable pointed to
+ by R, and return the new value of BUF. */
+
+static void *
+decode_uleb128 (unsigned char *buf, unsigned *r)
+{
+ unsigned shift = 0;
+ unsigned result = 0;
+
+ while (1)
+ {
+ unsigned byte = *buf++;
+ result |= (byte & 0x7f) << shift;
+ if ((byte & 0x80) == 0)
+ break;
+ shift += 7;
+ }
+ *r = result;
+ return buf;
+}
+
+/* Decode the signed LEB128 constant at BUF into the variable pointed to
+ by R, and return the new value of BUF. */
+
+static void *
+decode_sleb128 (unsigned char *buf, int *r)
+{
+ unsigned shift = 0;
+ unsigned result = 0;
+ unsigned byte;
+
+ while (1)
+ {
+ byte = *buf++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ if ((byte & 0x80) == 0)
+ break;
+ }
+ if (shift < (sizeof (*r) * 8) && (byte & 0x40) != 0)
+ result |= - (1 << shift);
+
+ *r = result;
+ return buf;
+}
+
+/* Read unaligned data from the instruction buffer. */
+
+union unaligned {
+ void *p;
+ unsigned b2 __attribute__ ((mode (HI)));
+ unsigned b4 __attribute__ ((mode (SI)));
+ unsigned b8 __attribute__ ((mode (DI)));
+} __attribute__ ((packed));
+static inline void *
+read_pointer (void *p)
+{ union unaligned *up = p; return up->p; }
+static inline unsigned
+read_1byte (void *p)
+{ return *(unsigned char *)p; }
+static inline unsigned
+read_2byte (void *p)
+{ union unaligned *up = p; return up->b2; }
+static inline unsigned
+read_4byte (void *p)
+{ union unaligned *up = p; return up->b4; }
+static inline unsigned long
+read_8byte (void *p)
+{ union unaligned *up = p; return up->b8; }
+
+/* Ordering function for FDEs. Functions can't overlap, so we just compare
+ their starting addresses. */
+
+static inline saddr
+fde_compare (fde *x, fde *y)
+{
+ return (saddr)x->pc_begin - (saddr)y->pc_begin;
+}
+
+/* Return the address of the FDE after P. */
+
+static inline fde *
+next_fde (fde *p)
+{
+ return (fde *)(((char *)p) + p->length + sizeof (p->length));
+}
+
+/* Sorting an array of FDEs by address.
+ (Ideally we would have the linker sort the FDEs so we don't have to do
+ it at run time. But the linkers are not yet prepared for this.) */
+
+/* This is a special mix of insertion sort and heap sort, optimized for
+ the data sets that actually occur. They look like
+ 101 102 103 127 128 105 108 110 190 111 115 119 125 160 126 129 130.
+ I.e. a linearly increasing sequence (coming from functions in the text
+ section), with additionally a few unordered elements (coming from functions
+ in gnu_linkonce sections) whose values are higher than the values in the
+ surrounding linear sequence (but not necessarily higher than the values
+ at the end of the linear sequence!).
+ The worst-case total run time is O(N) + O(n log (n)), where N is the
+ total number of FDEs and n is the number of erratic ones. */
+
+typedef struct fde_vector
+{
+ fde **array;
+ size_t count;
+} fde_vector;
+
+typedef struct fde_accumulator
+{
+ fde_vector linear;
+ fde_vector erratic;
+} fde_accumulator;
+
+static inline void
+start_fde_sort (fde_accumulator *accu, size_t count)
+{
+ accu->linear.array = (fde **) malloc (sizeof (fde *) * count);
+ accu->erratic.array = (fde **) malloc (sizeof (fde *) * count);
+ accu->linear.count = 0;
+ accu->erratic.count = 0;
+}
+
+static inline void
+fde_insert (fde_accumulator *accu, fde *this_fde)
+{
+ accu->linear.array[accu->linear.count++] = this_fde;
+}
+
+/* Split LINEAR into a linear sequence with low values and an erratic
+ sequence with high values, put the linear one (of longest possible
+ length) into LINEAR and the erratic one into ERRATIC. This is O(N). */
+static inline void
+fde_split (fde_vector *linear, fde_vector *erratic)
+{
+ size_t count = linear->count;
+ size_t linear_max = (size_t) -1;
+ size_t previous_max[count];
+ size_t i, j;
+
+ for (i = 0; i < count; i++)
+ {
+ for (j = linear_max;
+ j != (size_t) -1
+ && fde_compare (linear->array[i], linear->array[j]) < 0;
+ j = previous_max[j])
+ {
+ erratic->array[erratic->count++] = linear->array[j];
+ linear->array[j] = (fde *) NULL;
+ }
+ previous_max[i] = j;
+ linear_max = i;
+ }
+
+ for (i = 0, j = 0; i < count; i++)
+ if (linear->array[i] != (fde *) NULL)
+ linear->array[j++] = linear->array[i];
+ linear->count = j;
+}
+
+/* This is O(n log(n)). BSD/OS defines heapsort in stdlib.h, so we must
+ use a name that does not conflict. */
+static inline void
+frame_heapsort (fde_vector *erratic)
+{
+ /* For a description of this algorithm, see:
+ Samuel P. Harbison, Guy L. Steele Jr.: C, a reference manual, 2nd ed.,
+ p. 60-61. */
+ fde ** a = erratic->array;
+ /* A portion of the array is called a "heap" if for all i>=0:
+ If i and 2i+1 are valid indices, then a[i] >= a[2i+1].
+ If i and 2i+2 are valid indices, then a[i] >= a[2i+2]. */
+#define SWAP(x,y) do { fde * tmp = x; x = y; y = tmp; } while (0)
+ size_t n = erratic->count;
+ size_t m = n;
+ size_t i;
+
+ while (m > 0)
+ {
+ /* Invariant: a[m..n-1] is a heap. */
+ m--;
+ for (i = m; 2*i+1 < n; )
+ {
+ if (2*i+2 < n
+ && fde_compare (a[2*i+2], a[2*i+1]) > 0
+ && fde_compare (a[2*i+2], a[i]) > 0)
+ {
+ SWAP (a[i], a[2*i+2]);
+ i = 2*i+2;
+ }
+ else if (fde_compare (a[2*i+1], a[i]) > 0)
+ {
+ SWAP (a[i], a[2*i+1]);
+ i = 2*i+1;
+ }
+ else
+ break;
+ }
+ }
+ while (n > 1)
+ {
+ /* Invariant: a[0..n-1] is a heap. */
+ n--;
+ SWAP (a[0], a[n]);
+ for (i = 0; 2*i+1 < n; )
+ {
+ if (2*i+2 < n
+ && fde_compare (a[2*i+2], a[2*i+1]) > 0
+ && fde_compare (a[2*i+2], a[i]) > 0)
+ {
+ SWAP (a[i], a[2*i+2]);
+ i = 2*i+2;
+ }
+ else if (fde_compare (a[2*i+1], a[i]) > 0)
+ {
+ SWAP (a[i], a[2*i+1]);
+ i = 2*i+1;
+ }
+ else
+ break;
+ }
+ }
+#undef SWAP
+}
+
+/* Merge V1 and V2, both sorted, and put the result into V1. */
+static void
+fde_merge (fde_vector *v1, const fde_vector *v2)
+{
+ size_t i1, i2;
+ fde * fde2;
+
+ i2 = v2->count;
+ if (i2 > 0)
+ {
+ i1 = v1->count;
+ do {
+ i2--;
+ fde2 = v2->array[i2];
+ while (i1 > 0 && fde_compare (v1->array[i1-1], fde2) > 0)
+ {
+ v1->array[i1+i2] = v1->array[i1-1];
+ i1--;
+ }
+ v1->array[i1+i2] = fde2;
+ } while (i2 > 0);
+ v1->count += v2->count;
+ }
+}
+
+static fde **
+end_fde_sort (fde_accumulator *accu, size_t count)
+{
+ if (accu->linear.count != count)
+ abort ();
+ fde_split (&accu->linear, &accu->erratic);
+ if (accu->linear.count + accu->erratic.count != count)
+ abort ();
+ frame_heapsort (&accu->erratic);
+ fde_merge (&accu->linear, &accu->erratic);
+ free (accu->erratic.array);
+ return accu->linear.array;
+}
+
+static size_t
+count_fdes (fde *this_fde)
+{
+ size_t count;
+
+ for (count = 0; this_fde->length != 0; this_fde = next_fde (this_fde))
+ {
+ /* Skip CIEs and linked once FDE entries. */
+ if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
+ continue;
+
+ ++count;
+ }
+
+ return count;
+}
+
+static void
+add_fdes (fde *this_fde, fde_accumulator *accu, void **beg_ptr, void **end_ptr)
+{
+ void *pc_begin = *beg_ptr;
+ void *pc_end = *end_ptr;
+
+ for (; this_fde->length != 0; this_fde = next_fde (this_fde))
+ {
+ /* Skip CIEs and linked once FDE entries. */
+ if (this_fde->CIE_delta == 0 || this_fde->pc_begin == 0)
+ continue;
+
+ fde_insert (accu, this_fde);
+
+ if (this_fde->pc_begin < pc_begin)
+ pc_begin = this_fde->pc_begin;
+ if (this_fde->pc_begin + this_fde->pc_range > pc_end)
+ pc_end = this_fde->pc_begin + this_fde->pc_range;
+ }
+
+ *beg_ptr = pc_begin;
+ *end_ptr = pc_end;
+}
+
+/* Set up a sorted array of pointers to FDEs for a loaded object. We
+ count up the entries before allocating the array because it's likely to
+ be faster. */
+
+static void
+frame_init (struct object* ob)
+{
+ size_t count;
+ fde_accumulator accu;
+ void *pc_begin, *pc_end;
+
+ if (ob->fde_array)
+ {
+ fde **p = ob->fde_array;
+ for (count = 0; *p; ++p)
+ count += count_fdes (*p);
+ }
+ else
+ count = count_fdes (ob->fde_begin);
+
+ ob->count = count;
+
+ start_fde_sort (&accu, count);
+ pc_begin = (void*)(uaddr)-1;
+ pc_end = 0;
+
+ if (ob->fde_array)
+ {
+ fde **p = ob->fde_array;
+ for (; *p; ++p)
+ add_fdes (*p, &accu, &pc_begin, &pc_end);
+ }
+ else
+ add_fdes (ob->fde_begin, &accu, &pc_begin, &pc_end);
+
+ ob->fde_array = end_fde_sort (&accu, count);
+ ob->pc_begin = pc_begin;
+ ob->pc_end = pc_end;
+}
+
+/* Return a pointer to the FDE for the function containing PC. */
+
+static fde *
+find_fde (void *pc)
+{
+ struct object *ob;
+ size_t lo, hi;
+
+ __gthread_mutex_lock (&object_mutex);
+
+ for (ob = objects; ob; ob = ob->next)
+ {
+ if (ob->pc_begin == 0)
+ frame_init (ob);
+ if (pc >= ob->pc_begin && pc < ob->pc_end)
+ break;
+ }
+
+ __gthread_mutex_unlock (&object_mutex);
+
+ if (ob == 0)
+ return 0;
+
+ /* Standard binary search algorithm. */
+ for (lo = 0, hi = ob->count; lo < hi; )
+ {
+ size_t i = (lo + hi) / 2;
+ fde *f = ob->fde_array[i];
+
+ if (pc < f->pc_begin)
+ hi = i;
+ else if (pc >= f->pc_begin + f->pc_range)
+ lo = i + 1;
+ else
+ return f;
+ }
+
+ return 0;
+}
+
+static inline struct dwarf_cie *
+get_cie (fde *f)
+{
+ return ((void *)&f->CIE_delta) - f->CIE_delta;
+}
+
+/* Extract any interesting information from the CIE for the translation
+ unit F belongs to. */
+
+static void *
+extract_cie_info (fde *f, struct cie_info *c)
+{
+ void *p;
+ int i;
+
+ c->augmentation = get_cie (f)->augmentation;
+
+ if (strcmp (c->augmentation, "") != 0
+ && strcmp (c->augmentation, "eh") != 0
+ && c->augmentation[0] != 'z')
+ return 0;
+
+ p = c->augmentation + strlen (c->augmentation) + 1;
+
+ if (strcmp (c->augmentation, "eh") == 0)
+ {
+ c->eh_ptr = read_pointer (p);
+ p += sizeof (void *);
+ }
+ else
+ c->eh_ptr = 0;
+
+ p = decode_uleb128 (p, &c->code_align);
+ p = decode_sleb128 (p, &c->data_align);
+ c->ra_regno = *(unsigned char *)p++;
+
+ /* If the augmentation starts with 'z', we now see the length of the
+ augmentation fields. */
+ if (c->augmentation[0] == 'z')
+ {
+ p = decode_uleb128 (p, &i);
+ p += i;
+ }
+
+ return p;
+}
+
+/* Decode one instruction's worth of DWARF 2 call frame information.
+ Used by __frame_state_for. Takes pointers P to the instruction to
+ decode, STATE to the current register unwind information, INFO to the
+ current CIE information, and PC to the current PC value. Returns a
+ pointer to the next instruction. */
+
+static void *
+execute_cfa_insn (void *p, struct frame_state_internal *state,
+ struct cie_info *info, void **pc)
+{
+ unsigned insn = *(unsigned char *)p++;
+ unsigned reg;
+ int offset;
+
+ if (insn & DW_CFA_advance_loc)
+ *pc += ((insn & 0x3f) * info->code_align);
+ else if (insn & DW_CFA_offset)
+ {
+ reg = (insn & 0x3f);
+ p = decode_uleb128 (p, &offset);
+ offset *= info->data_align;
+ state->s.saved[reg] = REG_SAVED_OFFSET;
+ state->s.reg_or_offset[reg] = offset;
+ }
+ else if (insn & DW_CFA_restore)
+ {
+ reg = (insn & 0x3f);
+ state->s.saved[reg] = REG_UNSAVED;
+ }
+ else switch (insn)
+ {
+ case DW_CFA_set_loc:
+ *pc = read_pointer (p);
+ p += sizeof (void *);
+ break;
+ case DW_CFA_advance_loc1:
+ *pc += read_1byte (p);
+ p += 1;
+ break;
+ case DW_CFA_advance_loc2:
+ *pc += read_2byte (p);
+ p += 2;
+ break;
+ case DW_CFA_advance_loc4:
+ *pc += read_4byte (p);
+ p += 4;
+ break;
+
+ case DW_CFA_offset_extended:
+ p = decode_uleb128 (p, &reg);
+ p = decode_uleb128 (p, &offset);
+ offset *= info->data_align;
+ state->s.saved[reg] = REG_SAVED_OFFSET;
+ state->s.reg_or_offset[reg] = offset;
+ break;
+ case DW_CFA_restore_extended:
+ p = decode_uleb128 (p, &reg);
+ state->s.saved[reg] = REG_UNSAVED;
+ break;
+
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_nop:
+ break;
+
+ case DW_CFA_register:
+ {
+ unsigned reg2;
+ p = decode_uleb128 (p, &reg);
+ p = decode_uleb128 (p, &reg2);
+ state->s.saved[reg] = REG_SAVED_REG;
+ state->s.reg_or_offset[reg] = reg2;
+ }
+ break;
+
+ case DW_CFA_def_cfa:
+ p = decode_uleb128 (p, &reg);
+ p = decode_uleb128 (p, &offset);
+ state->s.cfa_reg = reg;
+ state->s.cfa_offset = offset;
+ break;
+ case DW_CFA_def_cfa_register:
+ p = decode_uleb128 (p, &reg);
+ state->s.cfa_reg = reg;
+ break;
+ case DW_CFA_def_cfa_offset:
+ p = decode_uleb128 (p, &offset);
+ state->s.cfa_offset = offset;
+ break;
+
+ case DW_CFA_remember_state:
+ {
+ struct frame_state_internal *save =
+ (struct frame_state_internal *)
+ malloc (sizeof (struct frame_state_internal));
+ memcpy (save, state, sizeof (struct frame_state_internal));
+ state->saved_state = save;
+ }
+ break;
+ case DW_CFA_restore_state:
+ {
+ struct frame_state_internal *save = state->saved_state;
+ memcpy (state, save, sizeof (struct frame_state_internal));
+ free (save);
+ }
+ break;
+
+ /* FIXME: Hardcoded for SPARC register window configuration. */
+ case DW_CFA_GNU_window_save:
+ for (reg = 16; reg < 32; ++reg)
+ {
+ state->s.saved[reg] = REG_SAVED_OFFSET;
+ state->s.reg_or_offset[reg] = (reg - 16) * sizeof (void *);
+ }
+ break;
+
+ case DW_CFA_GNU_args_size:
+ p = decode_uleb128 (p, &offset);
+ state->s.args_size = offset;
+ break;
+
+ default:
+ abort ();
+ }
+ return p;
+}
+
+/* Called from crtbegin.o to register the unwind info for an object. */
+
+void
+__register_frame_info (void *begin, struct object *ob)
+{
+ ob->fde_begin = begin;
+
+ ob->pc_begin = ob->pc_end = 0;
+ ob->fde_array = 0;
+ ob->count = 0;
+
+ __gthread_mutex_lock (&object_mutex);
+
+ ob->next = objects;
+ objects = ob;
+
+ __gthread_mutex_unlock (&object_mutex);
+}
+
+void
+__register_frame (void *begin)
+{
+ struct object *ob = (struct object *) malloc (sizeof (struct object));
+ __register_frame_info (begin, ob);
+}
+
+/* Similar, but BEGIN is actually a pointer to a table of unwind entries
+ for different translation units. Called from the file generated by
+ collect2. */
+
+void
+__register_frame_info_table (void *begin, struct object *ob)
+{
+ ob->fde_begin = begin;
+ ob->fde_array = begin;
+
+ ob->pc_begin = ob->pc_end = 0;
+ ob->count = 0;
+
+ __gthread_mutex_lock (&object_mutex);
+
+ ob->next = objects;
+ objects = ob;
+
+ __gthread_mutex_unlock (&object_mutex);
+}
+
+void
+__register_frame_table (void *begin)
+{
+ struct object *ob = (struct object *) malloc (sizeof (struct object));
+ __register_frame_info_table (begin, ob);
+}
+
+/* Called from crtbegin.o to deregister the unwind info for an object. */
+
+void *
+__deregister_frame_info (void *begin)
+{
+ struct object **p;
+
+ __gthread_mutex_lock (&object_mutex);
+
+ p = &objects;
+ while (*p)
+ {
+ if ((*p)->fde_begin == begin)
+ {
+ struct object *ob = *p;
+ *p = (*p)->next;
+
+ /* If we've run init_frame for this object, free the FDE array. */
+ if (ob->pc_begin)
+ free (ob->fde_array);
+
+ __gthread_mutex_unlock (&object_mutex);
+ return (void *) ob;
+ }
+ p = &((*p)->next);
+ }
+
+ __gthread_mutex_unlock (&object_mutex);
+ abort ();
+}
+
+void
+__deregister_frame (void *begin)
+{
+ free (__deregister_frame_info (begin));
+}
+
+/* Called from __throw to find the registers to restore for a given
+ PC_TARGET. The caller should allocate a local variable of `struct
+ frame_state' (declared in frame.h) and pass its address to STATE_IN. */
+
+struct frame_state *
+__frame_state_for (void *pc_target, struct frame_state *state_in)
+{
+ fde *f;
+ void *insn, *end, *pc;
+ struct cie_info info;
+ struct frame_state_internal state;
+
+ f = find_fde (pc_target);
+ if (f == 0)
+ return 0;
+
+ insn = extract_cie_info (f, &info);
+ if (insn == 0)
+ return 0;
+
+ memset (&state, 0, sizeof (state));
+ state.s.retaddr_column = info.ra_regno;
+ state.s.eh_ptr = info.eh_ptr;
+
+ /* First decode all the insns in the CIE. */
+ end = next_fde ((fde*) get_cie (f));
+ while (insn < end)
+ insn = execute_cfa_insn (insn, &state, &info, 0);
+
+ insn = ((fde *)f) + 1;
+
+ if (info.augmentation[0] == 'z')
+ {
+ int i;
+ insn = decode_uleb128 (insn, &i);
+ insn += i;
+ }
+
+ /* Then the insns in the FDE up to our target PC. */
+ end = next_fde (f);
+ pc = f->pc_begin;
+ while (insn < end && pc <= pc_target)
+ insn = execute_cfa_insn (insn, &state, &info, &pc);
+
+ memcpy (state_in, &state.s, sizeof (state.s));
+ return state_in;
+}
+#endif /* DWARF2_UNWIND_INFO */
diff --git a/contrib/gcc/frame.h b/contrib/gcc/frame.h
new file mode 100644
index 0000000..9d0d693
--- /dev/null
+++ b/contrib/gcc/frame.h
@@ -0,0 +1,65 @@
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+ This file is part of GNU CC. */
+
+typedef struct frame_state
+{
+ void *cfa;
+ void *eh_ptr;
+ long cfa_offset;
+ long args_size;
+ long reg_or_offset[FIRST_PSEUDO_REGISTER+1];
+ unsigned short cfa_reg;
+ unsigned short retaddr_column;
+ char saved[FIRST_PSEUDO_REGISTER+1];
+} frame_state;
+
+/* Values for 'saved' above. */
+#define REG_UNSAVED 0
+#define REG_SAVED_OFFSET 1
+#define REG_SAVED_REG 2
+
+/* The representation for an "object" to be searched for frame unwind info.
+ For targets with named sections, one object is an executable or shared
+ library; for other targets, one object is one translation unit.
+
+ A copy of this structure declaration is printed by collect2.c;
+ keep the copies synchronized! */
+
+struct object {
+ void *pc_begin;
+ void *pc_end;
+ struct dwarf_fde *fde_begin;
+ struct dwarf_fde **fde_array;
+ size_t count;
+ struct object *next;
+};
+
+/* Note the following routines are exported interfaces from libgcc; do not
+ change these interfaces. Instead create new interfaces. Also note
+ references to these functions may be made weak in files where they
+ are referenced. */
+
+extern void __register_frame (void * );
+extern void __register_frame_table (void *);
+extern void __deregister_frame (void *);
+
+/* Called either from crtbegin.o or a static constructor to register the
+ unwind info for an object or translation unit, respectively. */
+
+extern void __register_frame_info (void *, struct object *);
+
+/* Similar, but BEGIN is actually a pointer to a table of unwind entries
+ for different translation units. Called from the file generated by
+ collect2. */
+extern void __register_frame_info_table (void *, struct object *);
+
+/* Called from crtend.o to deregister the unwind info for an object. */
+
+extern void *__deregister_frame_info (void *);
+
+/* Called from __throw to find the registers to restore for a given
+ PC_TARGET. The caller should allocate a local variable of `struct
+ frame_state' (declared in frame.h) and pass its address to STATE_IN.
+ Returns NULL on failure, otherwise returns STATE_IN. */
+
+extern struct frame_state *__frame_state_for (void *, struct frame_state *);
diff --git a/contrib/gcc/function.c b/contrib/gcc/function.c
index 4d15f71..cf9542b 100644
--- a/contrib/gcc/function.c
+++ b/contrib/gcc/function.c
@@ -1,5 +1,5 @@
/* Expands front end tree to back end RTL for GNU C-Compiler
- Copyright (C) 1987, 88, 89, 91-94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 91-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -39,12 +39,11 @@ Boston, MA 02111-1307, USA. */
then scans all the RTL instructions so far generated to correct them. */
#include "config.h"
-
-#include <stdio.h>
-
+#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
+#include "except.h"
#include "function.h"
#include "insn-flags.h"
#include "expr.h"
@@ -56,12 +55,16 @@ Boston, MA 02111-1307, USA. */
#include "output.h"
#include "basic-block.h"
#include "obstack.h"
-#include "bytecode.h"
+#include "toplev.h"
+
+#ifndef TRAMPOLINE_ALIGNMENT
+#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
+#endif
/* Some systems use __main in a way incompatible with its use in gcc, in these
cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
give the same symbol without quotes for an alternative entry point. You
- must define both, or neither. */
+ must define both, or neither. */
#ifndef NAME__MAIN
#define NAME__MAIN "__main"
#define SYMBOL__MAIN __main
@@ -124,10 +127,22 @@ int current_function_has_nonlocal_label;
int current_function_has_nonlocal_goto;
+/* Nonzero if this function has a computed goto.
+
+ It is computed during find_basic_blocks or during stupid life
+ analysis. */
+
+int current_function_has_computed_jump;
+
/* Nonzero if function being compiled contains nested functions. */
int current_function_contains_functions;
+/* Nonzero if the current function is a thunk (a lightweight function that
+ just adjusts one of its arguments and forwards to another function), so
+ we should try to cut corners where we can. */
+int current_function_is_thunk;
+
/* Nonzero if function being compiled can call alloca,
either as a subroutine or builtin. */
@@ -154,7 +169,7 @@ int current_function_args_size;
int current_function_pretend_args_size;
/* # of bytes of outgoing arguments. If ACCUMULATE_OUTGOING_ARGS is
- defined, the needed space is pushed by the prologue. */
+ defined, the needed space is pushed by the prologue. */
int current_function_outgoing_args_size;
@@ -182,10 +197,10 @@ CUMULATIVE_ARGS current_function_args_info;
char *current_function_name;
-/* If non-zero, an RTL expression for that location at which the current
- function returns its result. Always equal to
- DECL_RTL (DECL_RESULT (current_function_decl)), but provided
- independently of the tree structures. */
+/* If non-zero, an RTL expression for the location at which the current
+ function returns its result. If the current function returns its
+ result in a register, current_function_return_rtx will always be
+ the hard register containing the result. */
rtx current_function_return_rtx;
@@ -199,6 +214,9 @@ int current_function_uses_pic_offset_table;
/* The arg pointer hard register, or the pseudo into which it was copied. */
rtx current_function_internal_arg_pointer;
+/* Language-specific reason why the current function cannot be made inline. */
+char *current_function_cannot_inline;
+
/* The FUNCTION_DECL for an inline function currently being expanded. */
tree inline_function_decl;
@@ -263,7 +281,7 @@ rtx arg_pointer_save_area;
/* Offset to end of allocated area of stack frame.
If stack grows down, this is the address of the last stack slot allocated.
If stack grows up, this is the address for the next slot. */
-int frame_offset;
+HOST_WIDE_INT frame_offset;
/* List (chain of TREE_LISTs) of static chains for containing functions.
Each link has a FUNCTION_DECL in the TREE_PURPOSE and a reg rtx
@@ -291,21 +309,15 @@ static int invalid_stack_slot;
/* Last insn of those whose job was to put parms into their nominal homes. */
static rtx last_parm_insn;
-/* 1 + last pseudo register number used for loading a copy
- of a parameter of this function. */
-static int max_parm_reg;
+/* 1 + last pseudo register number possibly used for loading a copy
+ of a parameter of this function. */
+int max_parm_reg;
/* Vector indexed by REGNO, containing location on stack in which
to put the parm which is nominally in pseudo register REGNO,
- if we discover that that parm must go in the stack. */
-static rtx *parm_reg_stack_loc;
-
-#if 0 /* Turned off because 0 seems to work just as well. */
-/* Cleanup lists are required for binding levels regardless of whether
- that binding level has cleanups or not. This node serves as the
- cleanup list whenever an empty list is required. */
-static tree empty_cleanup_list;
-#endif
+ if we discover that that parm must go in the stack. The highest
+ element in this vector is one less than MAX_PARM_REG, above. */
+rtx *parm_reg_stack_loc;
/* Nonzero once virtual register instantiation has been done.
assign_stack_local uses frame_pointer_rtx when this is nonzero. */
@@ -314,8 +326,8 @@ static int virtuals_instantiated;
/* These variables hold pointers to functions to
save and restore machine-specific data,
in push_function_context and pop_function_context. */
-void (*save_machine_status) ();
-void (*restore_machine_status) ();
+void (*save_machine_status) PROTO((struct function *));
+void (*restore_machine_status) PROTO((struct function *));
/* Nonzero if we need to distinguish between the return value of this function
and the return value of a function called by this function. This helps
@@ -323,10 +335,6 @@ void (*restore_machine_status) ();
extern int rtx_equal_function_value_matters;
extern tree sequence_rtl_expr;
-extern tree bc_runtime_type_code ();
-extern rtx bc_build_calldesc ();
-extern char *bc_emit_trampoline ();
-extern char *bc_end_function ();
/* In order to evaluate some expressions, such as function calls returning
structures in memory, we need to temporarily allocate stack locations.
@@ -350,13 +358,13 @@ struct temp_slot
{
/* Points to next temporary slot. */
struct temp_slot *next;
- /* The rtx to used to reference the slot. */
+ /* The rtx to used to reference the slot. */
rtx slot;
/* The rtx used to represent the address if not the address of the
slot above. May be an EXPR_LIST if multiple addresses exist. */
rtx address;
/* The size, in units, of the slot. */
- int size;
+ HOST_WIDE_INT size;
/* The value of `sequence_rtl_expr' when this temporary is allocated. */
tree rtl_expr;
/* Non-zero if this temporary is currently in use. */
@@ -369,10 +377,10 @@ struct temp_slot
int keep;
/* The offset of the slot from the frame_pointer, including extra space
for alignment. This info is for combine_temp_slots. */
- int base_offset;
+ HOST_WIDE_INT base_offset;
/* The size of the slot, including extra space for alignment. This
info is for combine_temp_slots. */
- int full_size;
+ HOST_WIDE_INT full_size;
};
/* List of all temporaries allocated, both available and in use. */
@@ -382,32 +390,17 @@ struct temp_slot *temp_slots;
/* Current nesting level for temporaries. */
int temp_slot_level;
-
-/* The FUNCTION_DECL node for the current function. */
-static tree this_function_decl;
-
-/* Callinfo pointer for the current function. */
-static rtx this_function_callinfo;
-
-/* The label in the bytecode file of this function's actual bytecode.
- Not an rtx. */
-static char *this_function_bytecode;
-
-/* The call description vector for the current function. */
-static rtx this_function_calldesc;
-/* Size of the local variables allocated for the current function. */
-int local_vars_size;
+/* Current nesting level for variables in a block. */
-/* Current depth of the bytecode evaluation stack. */
-int stack_depth;
-
-/* Maximum depth of the evaluation stack in this function. */
-int max_stack_depth;
-
-/* Current depth in statement expressions. */
-static int stmt_expr_depth;
+int var_temp_slot_level;
+/* When temporaries are created by TARGET_EXPRs, they are created at
+ this level of temp_slot_level, so that they can remain allocated
+ until no longer needed. CLEANUP_POINT_EXPRs define the lifetime
+ of TARGET_EXPRs. */
+int target_temp_slot_level;
+
/* This structure is used to record MEMs or pseudos used to replace VAR, any
SUBREGs of VAR, and any MEMs containing VAR as an address. We need to
maintain this list in case two operands of an insn were required to match;
@@ -422,10 +415,12 @@ struct fixup_replacement
/* Forward declarations. */
+static rtx assign_outer_stack_local PROTO ((enum machine_mode, HOST_WIDE_INT,
+ int, struct function *));
static struct temp_slot *find_temp_slot_from_address PROTO((rtx));
static void put_reg_into_stack PROTO((struct function *, rtx, tree,
enum machine_mode, enum machine_mode,
- int));
+ int, int, int));
static void fixup_var_refs PROTO((rtx, enum machine_mode, int));
static struct fixup_replacement
*find_fixup_replacement PROTO((struct fixup_replacement **, rtx));
@@ -443,14 +438,22 @@ static void instantiate_decl PROTO((rtx, int, int));
static int instantiate_virtual_regs_1 PROTO((rtx *, rtx, int));
static void delete_handlers PROTO((void));
static void pad_to_arg_alignment PROTO((struct args_size *, int));
+#ifndef ARGS_GROW_DOWNWARD
static void pad_below PROTO((struct args_size *, enum machine_mode,
tree));
+#endif
+#ifdef ARGS_GROW_DOWNWARD
static tree round_down PROTO((tree, int));
+#endif
static rtx round_trampoline_addr PROTO((rtx));
static tree blocks_nreverse PROTO((tree));
static int all_blocks PROTO((tree, tree *));
+#if defined (HAVE_prologue) || defined (HAVE_epilogue)
static int *record_insns PROTO((rtx));
static int contains PROTO((rtx, int *));
+#endif /* HAVE_prologue || HAVE_epilogue */
+static void put_addressof_into_stack PROTO((rtx));
+static void purge_addressof_1 PROTO((rtx *, rtx, int));
/* Pointer to chain of `struct function' for containing functions. */
struct function *outer_function_chain;
@@ -463,9 +466,11 @@ find_function_data (decl)
tree decl;
{
struct function *p;
+
for (p = outer_function_chain; p; p = p->next)
if (p->decl == decl)
return p;
+
abort ();
}
@@ -488,6 +493,7 @@ push_function_context_to (context)
p->pops_args = current_function_pops_args;
p->returns_struct = current_function_returns_struct;
p->returns_pcc_struct = current_function_returns_pcc_struct;
+ p->returns_pointer = current_function_returns_pointer;
p->needs_context = current_function_needs_context;
p->calls_setjmp = current_function_calls_setjmp;
p->calls_longjmp = current_function_calls_longjmp;
@@ -495,6 +501,7 @@ push_function_context_to (context)
p->has_nonlocal_label = current_function_has_nonlocal_label;
p->has_nonlocal_goto = current_function_has_nonlocal_goto;
p->contains_functions = current_function_contains_functions;
+ p->is_thunk = current_function_is_thunk;
p->args_size = current_function_args_size;
p->pretend_args_size = current_function_pretend_args_size;
p->arg_offset_rtx = current_function_arg_offset_rtx;
@@ -503,6 +510,7 @@ push_function_context_to (context)
p->uses_const_pool = current_function_uses_const_pool;
p->uses_pic_offset_table = current_function_uses_pic_offset_table;
p->internal_arg_pointer = current_function_internal_arg_pointer;
+ p->cannot_inline = current_function_cannot_inline;
p->max_parm_reg = max_parm_reg;
p->parm_reg_stack_loc = parm_reg_stack_loc;
p->outgoing_args_size = current_function_outgoing_args_size;
@@ -526,17 +534,18 @@ push_function_context_to (context)
p->function_call_count = function_call_count;
p->temp_slots = temp_slots;
p->temp_slot_level = temp_slot_level;
+ p->target_temp_slot_level = target_temp_slot_level;
+ p->var_temp_slot_level = var_temp_slot_level;
p->fixup_var_refs_queue = 0;
p->epilogue_delay_list = current_function_epilogue_delay_list;
+ p->args_info = current_function_args_info;
save_tree_status (p, context);
save_storage_status (p);
save_emit_status (p);
- init_emit ();
save_expr_status (p);
save_stmt_status (p);
- save_varasm_status (p);
-
+ save_varasm_status (p, context);
if (save_machine_status)
(*save_machine_status) (p);
}
@@ -555,6 +564,7 @@ pop_function_context_from (context)
tree context;
{
struct function *p = outer_function_chain;
+ struct var_refs_queue *queue;
outer_function_chain = p->next;
@@ -566,12 +576,14 @@ pop_function_context_from (context)
current_function_pops_args = p->pops_args;
current_function_returns_struct = p->returns_struct;
current_function_returns_pcc_struct = p->returns_pcc_struct;
+ current_function_returns_pointer = p->returns_pointer;
current_function_needs_context = p->needs_context;
current_function_calls_setjmp = p->calls_setjmp;
current_function_calls_longjmp = p->calls_longjmp;
current_function_calls_alloca = p->calls_alloca;
current_function_has_nonlocal_label = p->has_nonlocal_label;
current_function_has_nonlocal_goto = p->has_nonlocal_goto;
+ current_function_is_thunk = p->is_thunk;
current_function_args_size = p->args_size;
current_function_pretend_args_size = p->pretend_args_size;
current_function_arg_offset_rtx = p->arg_offset_rtx;
@@ -580,6 +592,7 @@ pop_function_context_from (context)
current_function_uses_const_pool = p->uses_const_pool;
current_function_uses_pic_offset_table = p->uses_pic_offset_table;
current_function_internal_arg_pointer = p->internal_arg_pointer;
+ current_function_cannot_inline = p->cannot_inline;
max_parm_reg = p->max_parm_reg;
parm_reg_stack_loc = p->parm_reg_stack_loc;
current_function_outgoing_args_size = p->outgoing_args_size;
@@ -603,10 +616,13 @@ pop_function_context_from (context)
function_call_count = p->function_call_count;
temp_slots = p->temp_slots;
temp_slot_level = p->temp_slot_level;
+ target_temp_slot_level = p->target_temp_slot_level;
+ var_temp_slot_level = p->var_temp_slot_level;
current_function_epilogue_delay_list = p->epilogue_delay_list;
reg_renumber = 0;
+ current_function_args_info = p->args_info;
- restore_tree_status (p);
+ restore_tree_status (p, context);
restore_storage_status (p);
restore_expr_status (p);
restore_emit_status (p);
@@ -618,11 +634,8 @@ pop_function_context_from (context)
/* Finish doing put_var_into_stack for any of our variables
which became addressable during the nested function. */
- {
- struct var_refs_queue *queue = p->fixup_var_refs_queue;
- for (; queue; queue = queue->next)
- fixup_var_refs (queue->modified, queue->promoted_mode, queue->unsignedp);
- }
+ for (queue = p->fixup_var_refs_queue; queue; queue = queue->next)
+ fixup_var_refs (queue->modified, queue->promoted_mode, queue->unsignedp);
free (p);
@@ -642,7 +655,7 @@ void pop_function_context ()
This size counts from zero. It is not rounded to STACK_BOUNDARY;
the caller may have to do that. */
-int
+HOST_WIDE_INT
get_frame_size ()
{
#ifdef FRAME_GROWS_DOWNWARD
@@ -665,7 +678,7 @@ get_frame_size ()
rtx
assign_stack_local (mode, size, align)
enum machine_mode mode;
- int size;
+ HOST_WIDE_INT size;
int align;
{
register rtx x, addr;
@@ -720,9 +733,9 @@ assign_stack_local (mode, size, align)
frame_offset += size;
#endif
- x = gen_rtx (MEM, mode, addr);
+ x = gen_rtx_MEM (mode, addr);
- stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, x, stack_slot_list);
+ stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, x, stack_slot_list);
return x;
}
@@ -731,10 +744,10 @@ assign_stack_local (mode, size, align)
First three arguments are same as in preceding function.
The last argument specifies the function to allocate in. */
-rtx
+static rtx
assign_outer_stack_local (mode, size, align, function)
enum machine_mode mode;
- int size;
+ HOST_WIDE_INT size;
int align;
struct function *function;
{
@@ -782,10 +795,10 @@ assign_outer_stack_local (mode, size, align, function)
function->frame_offset += size;
#endif
- x = gen_rtx (MEM, mode, addr);
+ x = gen_rtx_MEM (mode, addr);
function->stack_slot_list
- = gen_rtx (EXPR_LIST, VOIDmode, x, function->stack_slot_list);
+ = gen_rtx_EXPR_LIST (VOIDmode, x, function->stack_slot_list);
pop_obstacks ();
@@ -802,13 +815,15 @@ assign_outer_stack_local (mode, size, align, function)
KEEP is 1 if this slot is to be retained after a call to
free_temp_slots. Automatic variables for a block are allocated
- with this flag. KEEP is 2, if we allocate a longer term temporary,
- whose lifetime is controlled by CLEANUP_POINT_EXPRs. */
+ with this flag. KEEP is 2 if we allocate a longer term temporary,
+ whose lifetime is controlled by CLEANUP_POINT_EXPRs. KEEP is 3
+ if we are to allocate something at an inner level to be treated as
+ a variable in the block (e.g., a SAVE_EXPR). */
rtx
assign_stack_temp (mode, size, keep)
enum machine_mode mode;
- int size;
+ HOST_WIDE_INT size;
int keep;
{
struct temp_slot *p, *best_p = 0;
@@ -841,7 +856,7 @@ assign_stack_temp (mode, size, keep)
if (GET_MODE (best_p->slot) == BLKmode)
{
int alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
- int rounded_size = CEIL_ROUND (size, alignment);
+ HOST_WIDE_INT rounded_size = CEIL_ROUND (size, alignment);
if (best_p->size - rounded_size >= alignment)
{
@@ -850,16 +865,16 @@ assign_stack_temp (mode, size, keep)
p->size = best_p->size - rounded_size;
p->base_offset = best_p->base_offset + rounded_size;
p->full_size = best_p->full_size - rounded_size;
- p->slot = gen_rtx (MEM, BLKmode,
- plus_constant (XEXP (best_p->slot, 0),
- rounded_size));
+ p->slot = gen_rtx_MEM (BLKmode,
+ plus_constant (XEXP (best_p->slot, 0),
+ rounded_size));
p->address = 0;
p->rtl_expr = 0;
p->next = temp_slots;
temp_slots = p;
- stack_slot_list = gen_rtx (EXPR_LIST, VOIDmode, p->slot,
- stack_slot_list);
+ stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, p->slot,
+ stack_slot_list);
best_p->size = rounded_size;
best_p->full_size = rounded_size;
@@ -872,11 +887,14 @@ assign_stack_temp (mode, size, keep)
/* If we still didn't find one, make a new temporary. */
if (p == 0)
{
- int frame_offset_old = frame_offset;
+ HOST_WIDE_INT frame_offset_old = frame_offset;
+
p = (struct temp_slot *) oballoc (sizeof (struct temp_slot));
+
/* If the temp slot mode doesn't indicate the alignment,
use the largest possible, so no one will be disappointed. */
p->slot = assign_stack_local (mode, size, mode == BLKmode ? -1 : 0);
+
/* The following slot size computation is necessary because we don't
know the actual size of the temporary slot until assign_stack_local
has performed all the frame alignment and size rounding for the
@@ -889,6 +907,7 @@ assign_stack_temp (mode, size, keep)
#else
p->size = size;
#endif
+
/* Now define the fields used by combine_temp_slots. */
#ifdef FRAME_GROWS_DOWNWARD
p->base_offset = frame_offset;
@@ -911,14 +930,68 @@ assign_stack_temp (mode, size, keep)
p->level = target_temp_slot_level;
p->keep = 0;
}
+ else if (keep == 3)
+ {
+ p->level = var_temp_slot_level;
+ p->keep = 0;
+ }
else
{
p->level = temp_slot_level;
p->keep = keep;
}
+
+ /* We may be reusing an old slot, so clear any MEM flags that may have been
+ set from before. */
+ RTX_UNCHANGING_P (p->slot) = 0;
+ MEM_IN_STRUCT_P (p->slot) = 0;
return p->slot;
}
+
+/* Assign a temporary of given TYPE.
+ KEEP is as for assign_stack_temp.
+ MEMORY_REQUIRED is 1 if the result must be addressable stack memory;
+ it is 0 if a register is OK.
+ DONT_PROMOTE is 1 if we should not promote values in register
+ to wider modes. */
+rtx
+assign_temp (type, keep, memory_required, dont_promote)
+ tree type;
+ int keep;
+ int memory_required;
+ int dont_promote;
+{
+ enum machine_mode mode = TYPE_MODE (type);
+ int unsignedp = TREE_UNSIGNED (type);
+
+ if (mode == BLKmode || memory_required)
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ rtx tmp;
+
+ /* Unfortunately, we don't yet know how to allocate variable-sized
+ temporaries. However, sometimes we have a fixed upper limit on
+ the size (which is stored in TYPE_ARRAY_MAX_SIZE) and can use that
+ instead. This is the case for Chill variable-sized strings. */
+ if (size == -1 && TREE_CODE (type) == ARRAY_TYPE
+ && TYPE_ARRAY_MAX_SIZE (type) != NULL_TREE
+ && TREE_CODE (TYPE_ARRAY_MAX_SIZE (type)) == INTEGER_CST)
+ size = TREE_INT_CST_LOW (TYPE_ARRAY_MAX_SIZE (type));
+
+ tmp = assign_stack_temp (mode, size, keep);
+ MEM_IN_STRUCT_P (tmp) = AGGREGATE_TYPE_P (type);
+ return tmp;
+ }
+
+#ifndef PROMOTE_FOR_CALL_ONLY
+ if (! dont_promote)
+ mode = promote_mode (type, mode, &unsignedp, 0);
+#endif
+
+ return gen_reg_rtx (mode);
+}
+
/* Combine temporary stack slots which are adjacent on the stack.
This allows for better use of already allocated stack space. This is only
@@ -930,12 +1003,19 @@ combine_temp_slots ()
{
struct temp_slot *p, *q;
struct temp_slot *prev_p, *prev_q;
- /* Determine where to free back to after this function. */
- rtx free_pointer = rtx_alloc (CONST_INT);
+ int num_slots;
+
+ /* If there are a lot of temp slots, don't do anything unless
+ high levels of optimizaton. */
+ if (! flag_expensive_optimizations)
+ for (p = temp_slots, num_slots = 0; p; p = p->next, num_slots++)
+ if (num_slots > 100 || (num_slots > 10 && optimize == 0))
+ return;
for (p = temp_slots, prev_p = 0; p; p = prev_p ? prev_p->next : temp_slots)
{
int delete_p = 0;
+
if (! p->in_use && GET_MODE (p->slot) == BLKmode)
for (q = p->next, prev_q = p; q; q = prev_q->next)
{
@@ -975,9 +1055,6 @@ combine_temp_slots ()
else
prev_p = p;
}
-
- /* Free all the RTL made by plus_constant. */
- rtx_free (free_pointer);
}
/* Find the temp slot corresponding to the object at address X. */
@@ -993,8 +1070,14 @@ find_temp_slot_from_address (x)
{
if (! p->in_use)
continue;
+
else if (XEXP (p->slot, 0) == x
- || p->address == x)
+ || p->address == x
+ || (GET_CODE (x) == PLUS
+ && XEXP (x, 0) == virtual_stack_vars_rtx
+ && GET_CODE (XEXP (x, 1)) == CONST_INT
+ && INTVAL (XEXP (x, 1)) >= p->base_offset
+ && INTVAL (XEXP (x, 1)) < p->base_offset + p->full_size))
return p;
else if (p->address != 0 && GET_CODE (p->address) == EXPR_LIST)
@@ -1007,7 +1090,7 @@ find_temp_slot_from_address (x)
}
/* Indicate that NEW is an alternate way of referring to the temp slot
- that previous was known by OLD. */
+ that previously was known by OLD. */
void
update_temp_slot_address (old, new)
@@ -1023,9 +1106,9 @@ update_temp_slot_address (old, new)
else
{
if (GET_CODE (p->address) != EXPR_LIST)
- p->address = gen_rtx (EXPR_LIST, VOIDmode, p->address, NULL_RTX);
+ p->address = gen_rtx_EXPR_LIST (VOIDmode, p->address, NULL_RTX);
- p->address = gen_rtx (EXPR_LIST, VOIDmode, new, p->address);
+ p->address = gen_rtx_EXPR_LIST (VOIDmode, new, p->address);
}
}
@@ -1051,10 +1134,11 @@ mark_temp_addr_taken (x)
p->addr_taken = 1;
}
-/* If X could be a reference to a temporary slot, mark that slot as belonging
- to the to one level higher. If X matched one of our slots, just mark that
- one. Otherwise, we can't easily predict which it is, so upgrade all of
- them. Kept slots need not be touched.
+/* If X could be a reference to a temporary slot, mark that slot as
+ belonging to the to one level higher than the current level. If X
+ matched one of our slots, just mark that one. Otherwise, we can't
+ easily predict which it is, so upgrade all of them. Kept slots
+ need not be touched.
This is called when an ({...}) construct occurs and a statement
returns a value in memory. */
@@ -1105,12 +1189,15 @@ preserve_temp_slots (x)
level in case we used its address. */
struct temp_slot *q;
- for (q = temp_slots; q; q = q->next)
- if (q != p && q->addr_taken && q->level == p->level)
- q->level--;
+ if (p->level == temp_slot_level)
+ {
+ for (q = temp_slots; q; q = q->next)
+ if (q != p && q->addr_taken && q->level == p->level)
+ q->level--;
- p->level--;
- p->addr_taken = 0;
+ p->level--;
+ p->addr_taken = 0;
+ }
return;
}
@@ -1183,6 +1270,21 @@ free_temps_for_rtl_expr (t)
combine_temp_slots ();
}
+/* Mark all temporaries ever allocated in this function as not suitable
+ for reuse until the current level is exited. */
+
+void
+mark_all_temps_used ()
+{
+ struct temp_slot *p;
+
+ for (p = temp_slots; p; p = p->next)
+ {
+ p->in_use = p->keep = 1;
+ p->level = MIN (p->level, temp_slot_level);
+ }
+}
+
/* Push deeper into the nesting level for stack temporaries. */
void
@@ -1191,6 +1293,44 @@ push_temp_slots ()
temp_slot_level++;
}
+/* Likewise, but save the new level as the place to allocate variables
+ for blocks. */
+
+void
+push_temp_slots_for_block ()
+{
+ push_temp_slots ();
+
+ var_temp_slot_level = temp_slot_level;
+}
+
+/* Likewise, but save the new level as the place to allocate temporaries
+ for TARGET_EXPRs. */
+
+void
+push_temp_slots_for_target ()
+{
+ push_temp_slots ();
+
+ target_temp_slot_level = temp_slot_level;
+}
+
+/* Set and get the value of target_temp_slot_level. The only
+ permitted use of these functions is to save and restore this value. */
+
+int
+get_target_temp_slot_level ()
+{
+ return target_temp_slot_level;
+}
+
+void
+set_target_temp_slot_level (level)
+ int level;
+{
+ target_temp_slot_level = level;
+}
+
/* Pop a temporary nesting level. All slots in use in the current level
are freed. */
@@ -1207,6 +1347,18 @@ pop_temp_slots ()
temp_slot_level--;
}
+
+/* Initialize temporary slots. */
+
+void
+init_temp_slots ()
+{
+ /* We have not allocated any temporaries yet. */
+ temp_slots = 0;
+ temp_slot_level = 0;
+ var_temp_slot_level = 0;
+ target_temp_slot_level = 0;
+}
/* Retroactively move an auto variable from a register to a stack slot.
This is done when an address-reference to the variable is seen. */
@@ -1219,13 +1371,11 @@ put_var_into_stack (decl)
enum machine_mode promoted_mode, decl_mode;
struct function *function = 0;
tree context;
+ int can_use_addressof;
- if (output_bytecode)
- return;
-
context = decl_function_context (decl);
- /* Get the current rtl used for this object and it's original mode. */
+ /* Get the current rtl used for this object and its original mode. */
reg = TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl) : DECL_RTL (decl);
/* No need to do anything if decl has no rtx yet
@@ -1242,7 +1392,7 @@ put_var_into_stack (decl)
/* If this variable comes from an outer function,
find that function's saved context. */
- if (context != current_function_decl)
+ if (context != current_function_decl && context != inline_function_decl)
for (function = outer_function_chain; function; function = function->next)
if (function->decl == context)
break;
@@ -1258,11 +1408,38 @@ put_var_into_stack (decl)
decl_mode = promoted_mode = GET_MODE (reg);
}
+ can_use_addressof
+ = (function == 0
+ && optimize > 0
+ /* FIXME make it work for promoted modes too */
+ && decl_mode == promoted_mode
+#ifdef NON_SAVING_SETJMP
+ && ! (NON_SAVING_SETJMP && current_function_calls_setjmp)
+#endif
+ );
+
+ /* If we can't use ADDRESSOF, make sure we see through one we already
+ generated. */
+ if (! can_use_addressof && GET_CODE (reg) == MEM
+ && GET_CODE (XEXP (reg, 0)) == ADDRESSOF)
+ reg = XEXP (XEXP (reg, 0), 0);
+
/* Now we should have a value that resides in one or more pseudo regs. */
if (GET_CODE (reg) == REG)
- put_reg_into_stack (function, reg, TREE_TYPE (decl),
- promoted_mode, decl_mode, TREE_SIDE_EFFECTS (decl));
+ {
+ /* If this variable lives in the current function and we don't need
+ to put things in the stack for the sake of setjmp, try to keep it
+ in a register until we know we actually need the address. */
+ if (can_use_addressof)
+ gen_mem_addressof (reg, decl);
+ else
+ put_reg_into_stack (function, reg, TREE_TYPE (decl),
+ promoted_mode, decl_mode,
+ TREE_SIDE_EFFECTS (decl), 0,
+ TREE_USED (decl)
+ || DECL_INITIAL (decl) != 0);
+ }
else if (GET_CODE (reg) == CONCAT)
{
/* A CONCAT contains two pseudos; put them both in the stack.
@@ -1272,19 +1449,24 @@ put_var_into_stack (decl)
#ifdef FRAME_GROWS_DOWNWARD
/* Since part 0 should have a lower address, do it second. */
put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
- part_mode, TREE_SIDE_EFFECTS (decl));
+ part_mode, TREE_SIDE_EFFECTS (decl), 0,
+ TREE_USED (decl) || DECL_INITIAL (decl) != 0);
put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
- part_mode, TREE_SIDE_EFFECTS (decl));
+ part_mode, TREE_SIDE_EFFECTS (decl), 0,
+ TREE_USED (decl) || DECL_INITIAL (decl) != 0);
#else
put_reg_into_stack (function, XEXP (reg, 0), part_type, part_mode,
- part_mode, TREE_SIDE_EFFECTS (decl));
+ part_mode, TREE_SIDE_EFFECTS (decl), 0,
+ TREE_USED (decl) || DECL_INITIAL (decl) != 0);
put_reg_into_stack (function, XEXP (reg, 1), part_type, part_mode,
- part_mode, TREE_SIDE_EFFECTS (decl));
+ part_mode, TREE_SIDE_EFFECTS (decl), 0,
+ TREE_USED (decl) || DECL_INITIAL (decl) != 0);
#endif
/* Change the CONCAT into a combined MEM for both parts. */
PUT_CODE (reg, MEM);
MEM_VOLATILE_P (reg) = MEM_VOLATILE_P (XEXP (reg, 0));
+ MEM_ALIAS_SET (reg) = get_alias_set (decl);
/* The two parts are in memory order already.
Use the lower parts address as ours. */
@@ -1293,36 +1475,54 @@ put_var_into_stack (decl)
if (GET_CODE (XEXP (reg, 0)) == PLUS)
XEXP (reg, 0) = copy_rtx (XEXP (reg, 0));
}
+ else
+ return;
+
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ XEXP (reg, 0), ptr_mode,
+ GEN_INT (GET_MODE_SIZE (GET_MODE (reg))),
+ TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_RW),
+ TYPE_MODE (integer_type_node));
}
/* Subroutine of put_var_into_stack. This puts a single pseudo reg REG
into the stack frame of FUNCTION (0 means the current function).
DECL_MODE is the machine mode of the user-level data type.
PROMOTED_MODE is the machine mode of the register.
- VOLATILE_P is nonzero if this is for a "volatile" decl. */
+ VOLATILE_P is nonzero if this is for a "volatile" decl.
+ USED_P is nonzero if this reg might have already been used in an insn. */
static void
-put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p)
+put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p,
+ original_regno, used_p)
struct function *function;
rtx reg;
tree type;
enum machine_mode promoted_mode, decl_mode;
int volatile_p;
+ int original_regno;
+ int used_p;
{
rtx new = 0;
+ int regno = original_regno;
+
+ if (regno == 0)
+ regno = REGNO (reg);
if (function)
{
- if (REGNO (reg) < function->max_parm_reg)
- new = function->parm_reg_stack_loc[REGNO (reg)];
+ if (regno < function->max_parm_reg)
+ new = function->parm_reg_stack_loc[regno];
if (new == 0)
new = assign_outer_stack_local (decl_mode, GET_MODE_SIZE (decl_mode),
0, function);
}
else
{
- if (REGNO (reg) < max_parm_reg)
- new = parm_reg_stack_loc[REGNO (reg)];
+ if (regno < max_parm_reg)
+ new = parm_reg_stack_loc[regno];
if (new == 0)
new = assign_stack_local (decl_mode, GET_MODE_SIZE (decl_mode), 0);
}
@@ -1334,12 +1534,17 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p)
PUT_CODE (reg, MEM);
/* If this is a memory ref that contains aggregate components,
- mark it as such for cse and loop optimize. */
- MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type);
+ mark it as such for cse and loop optimize. If we are reusing a
+ previously generated stack slot, then we need to copy the bit in
+ case it was set for other reasons. For instance, it is set for
+ __builtin_va_alist. */
+ MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type) | MEM_IN_STRUCT_P (new);
+ MEM_ALIAS_SET (reg) = get_alias_set (type);
/* Now make sure that all refs to the variable, previously made
when it was a register, are fixed up to be valid again. */
- if (function)
+
+ if (used_p && function != 0)
{
struct var_refs_queue *temp;
@@ -1358,7 +1563,7 @@ put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p)
function->fixup_var_refs_queue = temp;
pop_obstacks ();
}
- else
+ else if (used_p)
/* Variable is local; fix it up now. */
fixup_var_refs (reg, promoted_mode, TREE_UNSIGNED (type));
}
@@ -1404,7 +1609,7 @@ fixup_var_refs (var, promoted_mode, unsignedp)
/* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
some part of an insn. Return a struct fixup_replacement whose OLD
- value is equal to X. Allocate a new structure if no such entry exists. */
+ value is equal to X. Allocate a new structure if no such entry exists. */
static struct fixup_replacement *
find_fixup_replacement (replacements, x)
@@ -1446,7 +1651,9 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
while (insn)
{
rtx next = NEXT_INSN (insn);
+ rtx set, prev, prev_set;
rtx note;
+
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
/* If this is a CLOBBER of VAR, delete it.
@@ -1454,7 +1661,10 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
If it has a REG_LIBCALL note, delete the REG_LIBCALL
and REG_RETVAL notes too. */
if (GET_CODE (PATTERN (insn)) == CLOBBER
- && XEXP (PATTERN (insn), 0) == var)
+ && (XEXP (PATTERN (insn), 0) == var
+ || (GET_CODE (XEXP (PATTERN (insn), 0)) == CONCAT
+ && (XEXP (XEXP (PATTERN (insn), 0), 0) == var
+ || XEXP (XEXP (PATTERN (insn), 0), 1) == var))))
{
if ((note = find_reg_note (insn, REG_LIBCALL, NULL_RTX)) != 0)
/* The REG_LIBCALL note will go away since we are going to
@@ -1472,14 +1682,22 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
}
/* The insn to load VAR from a home in the arglist
- is now a no-op. When we see it, just delete it. */
+ is now a no-op. When we see it, just delete it.
+ Similarly if this is storing VAR from a register from which
+ it was loaded in the previous insn. This will occur
+ when an ADDRESSOF was made for an arglist slot. */
else if (toplevel
- && GET_CODE (PATTERN (insn)) == SET
- && SET_DEST (PATTERN (insn)) == var
+ && (set = single_set (insn)) != 0
+ && SET_DEST (set) == var
/* If this represents the result of an insn group,
don't delete the insn. */
&& find_reg_note (insn, REG_RETVAL, NULL_RTX) == 0
- && rtx_equal_p (SET_SRC (PATTERN (insn)), var))
+ && (rtx_equal_p (SET_SRC (set), var)
+ || (GET_CODE (SET_SRC (set)) == REG
+ && (prev = prev_nonnote_insn (insn)) != 0
+ && (prev_set = single_set (prev)) != 0
+ && SET_DEST (prev_set) == SET_SRC (set)
+ && rtx_equal_p (SET_SRC (prev_set), var))))
{
/* In unoptimized compilation, we shouldn't call delete_insn
except in jump.c doing warnings. */
@@ -1494,42 +1712,43 @@ fixup_var_refs_insns (var, promoted_mode, unsignedp, insn, toplevel)
struct fixup_replacement *replacements = 0;
rtx next_insn = NEXT_INSN (insn);
-#ifdef SMALL_REGISTER_CLASSES
- /* If the insn that copies the results of a CALL_INSN
- into a pseudo now references VAR, we have to use an
- intermediate pseudo since we want the life of the
- return value register to be only a single insn.
-
- If we don't use an intermediate pseudo, such things as
- address computations to make the address of VAR valid
- if it is not can be placed between the CALL_INSN and INSN.
-
- To make sure this doesn't happen, we record the destination
- of the CALL_INSN and see if the next insn uses both that
- and VAR. */
-
- if (call_dest != 0 && GET_CODE (insn) == INSN
- && reg_mentioned_p (var, PATTERN (insn))
- && reg_mentioned_p (call_dest, PATTERN (insn)))
+ if (SMALL_REGISTER_CLASSES)
{
- rtx temp = gen_reg_rtx (GET_MODE (call_dest));
+ /* If the insn that copies the results of a CALL_INSN
+ into a pseudo now references VAR, we have to use an
+ intermediate pseudo since we want the life of the
+ return value register to be only a single insn.
+
+ If we don't use an intermediate pseudo, such things as
+ address computations to make the address of VAR valid
+ if it is not can be placed between the CALL_INSN and INSN.
+
+ To make sure this doesn't happen, we record the destination
+ of the CALL_INSN and see if the next insn uses both that
+ and VAR. */
+
+ if (call_dest != 0 && GET_CODE (insn) == INSN
+ && reg_mentioned_p (var, PATTERN (insn))
+ && reg_mentioned_p (call_dest, PATTERN (insn)))
+ {
+ rtx temp = gen_reg_rtx (GET_MODE (call_dest));
- emit_insn_before (gen_move_insn (temp, call_dest), insn);
+ emit_insn_before (gen_move_insn (temp, call_dest), insn);
- PATTERN (insn) = replace_rtx (PATTERN (insn),
- call_dest, temp);
- }
+ PATTERN (insn) = replace_rtx (PATTERN (insn),
+ call_dest, temp);
+ }
- if (GET_CODE (insn) == CALL_INSN
- && GET_CODE (PATTERN (insn)) == SET)
- call_dest = SET_DEST (PATTERN (insn));
- else if (GET_CODE (insn) == CALL_INSN
- && GET_CODE (PATTERN (insn)) == PARALLEL
- && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
- call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
- else
- call_dest = 0;
-#endif
+ if (GET_CODE (insn) == CALL_INSN
+ && GET_CODE (PATTERN (insn)) == SET)
+ call_dest = SET_DEST (PATTERN (insn));
+ else if (GET_CODE (insn) == CALL_INSN
+ && GET_CODE (PATTERN (insn)) == PARALLEL
+ && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == SET)
+ call_dest = SET_DEST (XVECEXP (PATTERN (insn), 0, 0));
+ else
+ call_dest = 0;
+ }
/* See if we have to do anything to INSN now that VAR is in
memory. If it needs to be loaded into a pseudo, use a single
@@ -1632,6 +1851,27 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
switch (code)
{
+ case ADDRESSOF:
+ if (XEXP (x, 0) == var)
+ {
+ /* Prevent sharing of rtl that might lose. */
+ rtx sub = copy_rtx (XEXP (var, 0));
+
+ start_sequence ();
+
+ if (! validate_change (insn, loc, sub, 0))
+ {
+ rtx y = force_operand (sub, NULL_RTX);
+
+ if (! validate_change (insn, loc, y, 0))
+ *loc = copy_to_reg (y);
+ }
+
+ emit_insn_before (gen_sequence (), insn);
+ end_sequence ();
+ }
+ return;
+
case MEM:
if (var == x)
{
@@ -1699,8 +1939,20 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
tem = XEXP (x, 0);
if (GET_CODE (tem) == SUBREG)
- tem = fixup_memory_subreg (tem, insn, 1);
- tem = fixup_stack_1 (tem, insn);
+ {
+ if (GET_MODE_BITSIZE (GET_MODE (tem))
+ > GET_MODE_BITSIZE (GET_MODE (var)))
+ {
+ replacement = find_fixup_replacement (replacements, var);
+ if (replacement->new == 0)
+ replacement->new = gen_reg_rtx (GET_MODE (var));
+ SUBREG_REG (tem) = replacement->new;
+ }
+ else
+ tem = fixup_memory_subreg (tem, insn, 0);
+ }
+ else
+ tem = fixup_stack_1 (tem, insn);
/* Unless we want to load from memory, get TEM into the proper mode
for an extract from memory. This can only be done if the
@@ -1713,8 +1965,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
{
enum machine_mode wanted_mode = VOIDmode;
enum machine_mode is_mode = GET_MODE (tem);
- int width = INTVAL (XEXP (x, 1));
- int pos = INTVAL (XEXP (x, 2));
+ HOST_WIDE_INT pos = INTVAL (XEXP (x, 2));
#ifdef HAVE_extzv
if (GET_CODE (x) == ZERO_EXTRACT)
@@ -1728,7 +1979,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
if (wanted_mode != VOIDmode
&& GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
{
- int offset = pos / BITS_PER_UNIT;
+ HOST_WIDE_INT offset = pos / BITS_PER_UNIT;
rtx old_pos = XEXP (x, 2);
rtx newmem;
@@ -1740,8 +1991,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
pos %= GET_MODE_BITSIZE (wanted_mode);
- newmem = gen_rtx (MEM, wanted_mode,
- plus_constant (XEXP (tem, 0), offset));
+ newmem = gen_rtx_MEM (wanted_mode,
+ plus_constant (XEXP (tem, 0), offset));
RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem);
MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (tem);
MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (tem);
@@ -1829,8 +2080,24 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
|| GET_CODE (SET_SRC (x)) == ZERO_EXTRACT)
optimize_bit_field (x, insn, NULL_PTR);
+ /* For a paradoxical SUBREG inside a ZERO_EXTRACT, load the object
+ into a register and then store it back out. */
+ if (GET_CODE (SET_DEST (x)) == ZERO_EXTRACT
+ && GET_CODE (XEXP (SET_DEST (x), 0)) == SUBREG
+ && SUBREG_REG (XEXP (SET_DEST (x), 0)) == var
+ && (GET_MODE_SIZE (GET_MODE (XEXP (SET_DEST (x), 0)))
+ > GET_MODE_SIZE (GET_MODE (var))))
+ {
+ replacement = find_fixup_replacement (replacements, var);
+ if (replacement->new == 0)
+ replacement->new = gen_reg_rtx (GET_MODE (var));
+
+ SUBREG_REG (XEXP (SET_DEST (x), 0)) = replacement->new;
+ emit_insn_after (gen_move_insn (var, replacement->new), insn);
+ }
+
/* If SET_DEST is now a paradoxical SUBREG, put the result of this
- insn into a pseudo and store the low part of the pseudo into VAR. */
+ insn into a pseudo and store the low part of the pseudo into VAR. */
if (GET_CODE (SET_DEST (x)) == SUBREG
&& SUBREG_REG (SET_DEST (x)) == var
&& (GET_MODE_SIZE (GET_MODE (SET_DEST (x)))
@@ -1846,7 +2113,9 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
{
rtx dest = SET_DEST (x);
rtx src = SET_SRC (x);
+#ifdef HAVE_insv
rtx outerdest = dest;
+#endif
while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
|| GET_CODE (dest) == SIGN_EXTRACT
@@ -1884,7 +2153,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
This was legitimate when the MEM was a REG. */
if (GET_CODE (tem) == SUBREG
&& SUBREG_REG (tem) == var)
- tem = fixup_memory_subreg (tem, insn, 1);
+ tem = fixup_memory_subreg (tem, insn, 0);
else
tem = fixup_stack_1 (tem, insn);
@@ -1896,13 +2165,12 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
enum machine_mode wanted_mode
= insn_operand_mode[(int) CODE_FOR_insv][0];
enum machine_mode is_mode = GET_MODE (tem);
- int width = INTVAL (XEXP (outerdest, 1));
- int pos = INTVAL (XEXP (outerdest, 2));
+ HOST_WIDE_INT pos = INTVAL (XEXP (outerdest, 2));
/* If we have a narrower mode, we can do something. */
if (GET_MODE_SIZE (wanted_mode) < GET_MODE_SIZE (is_mode))
{
- int offset = pos / BITS_PER_UNIT;
+ HOST_WIDE_INT offset = pos / BITS_PER_UNIT;
rtx old_pos = XEXP (outerdest, 2);
rtx newmem;
@@ -1912,8 +2180,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
pos %= GET_MODE_BITSIZE (wanted_mode);
- newmem = gen_rtx (MEM, wanted_mode,
- plus_constant (XEXP (tem, 0), offset));
+ newmem = gen_rtx_MEM (wanted_mode,
+ plus_constant (XEXP (tem, 0), offset));
RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (tem);
MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (tem);
MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (tem);
@@ -1968,7 +2236,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
&& (GET_CODE (SET_DEST (x)) == REG
|| (GET_CODE (SET_DEST (x)) == SUBREG
&& GET_CODE (SUBREG_REG (SET_DEST (x))) == REG))
- && x == single_set (PATTERN (insn)))
+ && GET_MODE (var) == promoted_mode
+ && x == single_set (insn))
{
rtx pat;
@@ -2013,7 +2282,8 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
&& (GET_CODE (SET_SRC (x)) == REG
|| (GET_CODE (SET_SRC (x)) == SUBREG
&& GET_CODE (SUBREG_REG (SET_SRC (x))) == REG))
- && x == single_set (PATTERN (insn)))
+ && GET_MODE (var) == promoted_mode
+ && x == single_set (insn))
{
rtx pat;
@@ -2076,6 +2346,9 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
SET_DEST (x) = temp;
}
}
+
+ default:
+ break;
}
/* Nothing special about this RTX; fix its operands. */
@@ -2100,7 +2373,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
If any insns must be emitted to compute NEWADDR, put them before INSN.
UNCRITICAL nonzero means accept paradoxical subregs.
- This is used for subregs found inside of ZERO_EXTRACTs and in REG_NOTES. */
+ This is used for subregs found inside REG_NOTES. */
static rtx
fixup_memory_subreg (x, insn, uncritical)
@@ -2111,7 +2384,7 @@ fixup_memory_subreg (x, insn, uncritical)
int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
rtx addr = XEXP (SUBREG_REG (x), 0);
enum machine_mode mode = GET_MODE (x);
- rtx saved, result;
+ rtx result;
/* Paradoxical SUBREGs are usually invalid during RTL generation. */
if (GET_MODE_SIZE (mode) > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
@@ -2201,6 +2474,12 @@ fixup_stack_1 (x, insn)
&& GET_CODE (XEXP (ad, 0)) == REG
&& ((REGNO (XEXP (ad, 0)) >= FIRST_VIRTUAL_REGISTER
&& REGNO (XEXP (ad, 0)) <= LAST_VIRTUAL_REGISTER)
+ || REGNO (XEXP (ad, 0)) == FRAME_POINTER_REGNUM
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ || REGNO (XEXP (ad, 0)) == HARD_FRAME_POINTER_REGNUM
+#endif
+ || REGNO (XEXP (ad, 0)) == STACK_POINTER_REGNUM
+ || REGNO (XEXP (ad, 0)) == ARG_POINTER_REGNUM
|| XEXP (ad, 0) == current_function_internal_arg_pointer)
&& GET_CODE (XEXP (ad, 1)) == CONST_INT)
{
@@ -2296,7 +2575,7 @@ optimize_bit_field (body, insn, equiv_mem)
that we are now getting rid of,
and then for which byte of the word is wanted. */
- register int offset = INTVAL (XEXP (bitfield, 2));
+ HOST_WIDE_INT offset = INTVAL (XEXP (bitfield, 2));
rtx insns;
/* Adjust OFFSET to count bits from low-address byte. */
@@ -2441,6 +2720,174 @@ static int out_arg_offset;
#endif
#endif
+/* Build up a (MEM (ADDRESSOF (REG))) rtx for a register REG that just had
+ its address taken. DECL is the decl for the object stored in the
+ register, for later use if we do need to force REG into the stack.
+ REG is overwritten by the MEM like in put_reg_into_stack. */
+
+rtx
+gen_mem_addressof (reg, decl)
+ rtx reg;
+ tree decl;
+{
+ tree type = TREE_TYPE (decl);
+
+ rtx r = gen_rtx_ADDRESSOF (Pmode, gen_reg_rtx (GET_MODE (reg)), REGNO (reg));
+ SET_ADDRESSOF_DECL (r, decl);
+
+ XEXP (reg, 0) = r;
+ PUT_CODE (reg, MEM);
+ PUT_MODE (reg, DECL_MODE (decl));
+ MEM_VOLATILE_P (reg) = TREE_SIDE_EFFECTS (decl);
+ MEM_IN_STRUCT_P (reg) = AGGREGATE_TYPE_P (type);
+ MEM_ALIAS_SET (reg) = get_alias_set (decl);
+
+ if (TREE_USED (decl) || DECL_INITIAL (decl) != 0)
+ fixup_var_refs (reg, GET_MODE (reg), TREE_UNSIGNED (type));
+
+ return reg;
+}
+
+/* If DECL has an RTL that is an ADDRESSOF rtx, put it into the stack. */
+
+void
+flush_addressof (decl)
+ tree decl;
+{
+ if ((TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL)
+ && DECL_RTL (decl) != 0
+ && GET_CODE (DECL_RTL (decl)) == MEM
+ && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF
+ && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == REG)
+ put_addressof_into_stack (XEXP (DECL_RTL (decl), 0));
+}
+
+/* Force the register pointed to by R, an ADDRESSOF rtx, into the stack. */
+
+static void
+put_addressof_into_stack (r)
+ rtx r;
+{
+ tree decl = ADDRESSOF_DECL (r);
+ rtx reg = XEXP (r, 0);
+
+ if (GET_CODE (reg) != REG)
+ abort ();
+
+ put_reg_into_stack (0, reg, TREE_TYPE (decl), GET_MODE (reg),
+ DECL_MODE (decl), TREE_SIDE_EFFECTS (decl),
+ ADDRESSOF_REGNO (r),
+ TREE_USED (decl) || DECL_INITIAL (decl) != 0);
+}
+
+/* Helper function for purge_addressof. See if the rtx expression at *LOC
+ in INSN needs to be changed. If FORCE, always put any ADDRESSOFs into
+ the stack. */
+
+static void
+purge_addressof_1 (loc, insn, force)
+ rtx *loc;
+ rtx insn;
+ int force;
+{
+ rtx x;
+ RTX_CODE code;
+ int i, j;
+ char *fmt;
+
+ /* Re-start here to avoid recursion in common cases. */
+ restart:
+
+ x = *loc;
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+
+ if (code == ADDRESSOF && GET_CODE (XEXP (x, 0)) == MEM)
+ {
+ rtx insns;
+ /* We must create a copy of the rtx because it was created by
+ overwriting a REG rtx which is always shared. */
+ rtx sub = copy_rtx (XEXP (XEXP (x, 0), 0));
+
+ if (validate_change (insn, loc, sub, 0))
+ return;
+
+ start_sequence ();
+ if (! validate_change (insn, loc,
+ force_operand (sub, NULL_RTX),
+ 0))
+ abort ();
+
+ insns = get_insns ();
+ end_sequence ();
+ emit_insns_before (insns, insn);
+ return;
+ }
+ else if (code == MEM && GET_CODE (XEXP (x, 0)) == ADDRESSOF && ! force)
+ {
+ rtx sub = XEXP (XEXP (x, 0), 0);
+
+ if (GET_CODE (sub) == MEM)
+ sub = gen_rtx_MEM (GET_MODE (x), copy_rtx (XEXP (sub, 0)));
+
+ if (GET_CODE (sub) == REG
+ && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
+ {
+ put_addressof_into_stack (XEXP (x, 0));
+ return;
+ }
+ else if (GET_CODE (sub) == REG && GET_MODE (x) != GET_MODE (sub))
+ {
+ if (! BYTES_BIG_ENDIAN && ! WORDS_BIG_ENDIAN)
+ {
+ rtx sub2 = gen_rtx_SUBREG (GET_MODE (x), sub, 0);
+ if (validate_change (insn, loc, sub2, 0))
+ goto restart;
+ }
+ }
+ else if (validate_change (insn, loc, sub, 0))
+ goto restart;
+ /* else give up and put it into the stack */
+ }
+ else if (code == ADDRESSOF)
+ {
+ put_addressof_into_stack (x);
+ return;
+ }
+
+ /* Scan all subexpressions. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
+ {
+ if (*fmt == 'e')
+ purge_addressof_1 (&XEXP (x, i), insn, force);
+ else if (*fmt == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ purge_addressof_1 (&XVECEXP (x, i, j), insn, force);
+ }
+}
+
+/* Eliminate all occurrences of ADDRESSOF from INSNS. Elide any remaining
+ (MEM (ADDRESSOF)) patterns, and force any needed registers into the
+ stack. */
+
+void
+purge_addressof (insns)
+ rtx insns;
+{
+ rtx insn;
+ for (insn = insns; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
+ || GET_CODE (insn) == CALL_INSN)
+ {
+ purge_addressof_1 (&PATTERN (insn), insn,
+ asm_noperands (PATTERN (insn)) > 0);
+ purge_addressof_1 (&REG_NOTES (insn), NULL_RTX, 0);
+ }
+}
+
/* Pass through the INSNS of function FNDECL and convert virtual register
references to hard register references. */
@@ -2450,6 +2897,7 @@ instantiate_virtual_regs (fndecl, insns)
rtx insns;
{
rtx insn;
+ int i;
/* Compute the offsets to use for this function. */
in_arg_offset = FIRST_PARM_OFFSET (fndecl);
@@ -2476,6 +2924,12 @@ instantiate_virtual_regs (fndecl, insns)
instantiate_virtual_regs_1 (&REG_NOTES (insn), NULL_RTX, 0);
}
+ /* Instantiate the stack slots for the parm registers, for later use in
+ addressof elimination. */
+ for (i = 0; i < max_parm_reg; ++i)
+ if (parm_reg_stack_loc[i])
+ instantiate_virtual_regs_1 (&parm_reg_stack_loc[i], NULL_RTX, 0);
+
/* Now instantiate the remaining register equivalences for debugging info.
These will not be valid addresses. */
instantiate_decls (fndecl, 0);
@@ -2498,7 +2952,7 @@ instantiate_decls (fndecl, valid_only)
{
tree decl;
- if (DECL_INLINE (fndecl) || DECL_DEFER_OUTPUT (fndecl))
+ if (DECL_SAVED_INSNS (fndecl))
/* When compiling an inline function, the obstack used for
rtl allocation is the maybepermanent_obstack. Calling
`resume_temporary_allocation' switches us back to that
@@ -2508,13 +2962,18 @@ instantiate_decls (fndecl, valid_only)
/* Process all parameters of the function. */
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
{
- instantiate_decl (DECL_RTL (decl), int_size_in_bytes (TREE_TYPE (decl)),
- valid_only);
- instantiate_decl (DECL_INCOMING_RTL (decl),
- int_size_in_bytes (TREE_TYPE (decl)), valid_only);
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+
+ instantiate_decl (DECL_RTL (decl), size, valid_only);
+
+ /* If the parameter was promoted, then the incoming RTL mode may be
+ larger than the declared type size. We must use the larger of
+ the two sizes. */
+ size = MAX (GET_MODE_SIZE (GET_MODE (DECL_INCOMING_RTL (decl))), size);
+ instantiate_decl (DECL_INCOMING_RTL (decl), size, valid_only);
}
- /* Now process all variables defined in the function or its subblocks. */
+ /* Now process all variables defined in the function or its subblocks. */
instantiate_decls_1 (DECL_INITIAL (fndecl), valid_only);
if (DECL_INLINE (fndecl) || DECL_DEFER_OUTPUT (fndecl))
@@ -2569,6 +3028,7 @@ instantiate_decl (x, size, valid_only)
addr = XEXP (x, 0);
if (CONSTANT_P (addr)
+ || (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == REG)
|| (GET_CODE (addr) == REG
&& (REGNO (addr) < FIRST_VIRTUAL_REGISTER
|| REGNO (addr) > LAST_VIRTUAL_REGISTER)))
@@ -2584,28 +3044,28 @@ instantiate_decl (x, size, valid_only)
instantiate_virtual_regs_1 (&addr, NULL_RTX, 0);
- if (! valid_only)
- return;
-
- /* Now verify that the resulting address is valid for every integer or
- floating-point mode up to and including SIZE bytes long. We do this
- since the object might be accessed in any mode and frame addresses
- are shared. */
-
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
- mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
- mode = GET_MODE_WIDER_MODE (mode))
- if (! memory_address_p (mode, addr))
- return;
+ if (valid_only)
+ {
+ /* Now verify that the resulting address is valid for every integer or
+ floating-point mode up to and including SIZE bytes long. We do this
+ since the object might be accessed in any mode and frame addresses
+ are shared. */
+
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+ mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
+ mode = GET_MODE_WIDER_MODE (mode))
+ if (! memory_address_p (mode, addr))
+ return;
- for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
- mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
- mode = GET_MODE_WIDER_MODE (mode))
- if (! memory_address_p (mode, addr))
- return;
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
+ mode != VOIDmode && GET_MODE_SIZE (mode) <= size;
+ mode = GET_MODE_WIDER_MODE (mode))
+ if (! memory_address_p (mode, addr))
+ return;
+ }
- /* Otherwise, put back the address, now that we have updated it and we
- know it is valid. */
+ /* Put back the address now that we have updated it and we either know
+ it is valid or we don't care whether it is valid. */
XEXP (x, 0) = addr;
}
@@ -2633,7 +3093,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
rtx x;
RTX_CODE code;
rtx new = 0;
- int offset;
+ HOST_WIDE_INT offset;
rtx temp;
rtx seq;
int i, j;
@@ -2666,7 +3126,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
case SET:
/* We are allowed to set the virtual registers. This means that
- that the actual register should receive the source minus the
+ the actual register should receive the source minus the
appropriate offset. This is used, for example, in the handling
of non-local gotos. */
if (SET_DEST (x) == virtual_incoming_args_rtx)
@@ -2698,7 +3158,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
emit_insns_before (seq, object);
SET_DEST (x) = new;
- if (!validate_change (object, &SET_SRC (x), temp, 0)
+ if (! validate_change (object, &SET_SRC (x), temp, 0)
|| ! extra_insns)
abort ();
@@ -2736,7 +3196,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 1), object,
extra_insns);
- new = gen_rtx (PLUS, Pmode, new, XEXP (XEXP (x, 0), 1));
+ new = gen_rtx_PLUS (Pmode, new, XEXP (XEXP (x, 0), 1));
}
else if (XEXP (x, 0) == virtual_incoming_args_rtx)
@@ -2773,7 +3233,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
in the case of old offset equals new just changing the register
will yield a valid insn. In the interests of a little efficiency,
however, we only call validate change once (we don't queue up the
- changes and then call apply_change_group). */
+ changes and then call apply_change_group). */
old = XEXP (x, 0);
if (offset == 0
@@ -2799,7 +3259,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
register containing the sum. */
XEXP (x, 0) = old;
- new = gen_rtx (PLUS, Pmode, new, new_offset);
+ new = gen_rtx_PLUS (Pmode, new, new_offset);
start_sequence ();
temp = force_operand (new, NULL_RTX);
@@ -2837,7 +3297,7 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
case MEM:
/* Most cases of MEM that convert to valid addresses have already been
- handled by our scan of regno_reg_rtx. The only special handling we
+ handled by our scan of decls. The only special handling we
need here is to make a copy of the rtx to ensure it isn't being
shared if we have to change it to a pseudo.
@@ -2895,7 +3355,9 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
??? Also note that this can still lose if OBJECT is an insn that
has less restrictions on an address that some other insn.
In that case, we will modify the shared address. This case
- doesn't seem very likely, though. */
+ doesn't seem very likely, though. One case where this could
+ happen is in the case of a USE or CLOBBER reference, but we
+ take care of that below. */
if (instantiate_virtual_regs_1 (&XEXP (x, 0),
object ? object : x, 0))
@@ -2908,8 +3370,6 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
}
/* Fall through to generic unary operation case. */
- case USE:
- case CLOBBER:
case SUBREG:
case STRICT_LOW_PART:
case NEG: case NOT:
@@ -2926,6 +3386,23 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
loc = &XEXP (x, 0);
goto restart;
+ case USE:
+ case CLOBBER:
+ /* If the operand is a MEM, see if the change is a valid MEM. If not,
+ go ahead and make the invalid one, but do it to a copy. For a REG,
+ just make the recursive call, since there's no chance of a problem. */
+
+ if ((GET_CODE (XEXP (x, 0)) == MEM
+ && instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), XEXP (x, 0),
+ 0))
+ || (GET_CODE (XEXP (x, 0)) == REG
+ && instantiate_virtual_regs_1 (&XEXP (x, 0), object, 0)))
+ return 1;
+
+ XEXP (x, 0) = copy_rtx (XEXP (x, 0));
+ loc = &XEXP (x, 0);
+ goto restart;
+
case REG:
/* Try to replace with a PLUS. If that doesn't work, compute the sum
in front of this insn and substitute the temporary. */
@@ -2959,6 +3436,23 @@ instantiate_virtual_regs_1 (loc, object, extra_insns)
}
return 1;
+
+ case ADDRESSOF:
+ if (GET_CODE (XEXP (x, 0)) == REG)
+ return 1;
+
+ else if (GET_CODE (XEXP (x, 0)) == MEM)
+ {
+ /* If we have a (addressof (mem ..)), do any instantiation inside
+ since we know we'll be making the inside valid when we finally
+ remove the ADDRESSOF. */
+ instantiate_virtual_regs_1 (&XEXP (XEXP (x, 0), 0), NULL_RTX, 0);
+ return 1;
+ }
+ break;
+
+ default:
+ break;
}
/* Scan all subexpressions. */
@@ -3032,7 +3526,7 @@ nonlocal_label_rtx_list ()
rtx x = 0;
for (t = nonlocal_labels; t; t = TREE_CHAIN (t))
- x = gen_rtx (EXPR_LIST, VOIDmode, label_rtx (TREE_VALUE (t)), x);
+ x = gen_rtx_EXPR_LIST (VOIDmode, label_rtx (TREE_VALUE (t)), x);
return x;
}
@@ -3047,14 +3541,14 @@ use_variable (rtl)
{
if (GET_CODE (rtl) == REG)
/* This is a register variable. */
- emit_insn (gen_rtx (USE, VOIDmode, rtl));
+ emit_insn (gen_rtx_USE (VOIDmode, rtl));
else if (GET_CODE (rtl) == MEM
&& GET_CODE (XEXP (rtl, 0)) == REG
&& (REGNO (XEXP (rtl, 0)) < FIRST_VIRTUAL_REGISTER
|| REGNO (XEXP (rtl, 0)) > LAST_VIRTUAL_REGISTER)
&& XEXP (rtl, 0) != current_function_internal_arg_pointer)
/* This is a variable-sized structure. */
- emit_insn (gen_rtx (USE, VOIDmode, XEXP (rtl, 0)));
+ emit_insn (gen_rtx_USE (VOIDmode, XEXP (rtl, 0)));
}
/* Like use_variable except that it outputs the USEs after INSN
@@ -3066,14 +3560,14 @@ use_variable_after (rtl, insn)
{
if (GET_CODE (rtl) == REG)
/* This is a register variable. */
- emit_insn_after (gen_rtx (USE, VOIDmode, rtl), insn);
+ emit_insn_after (gen_rtx_USE (VOIDmode, rtl), insn);
else if (GET_CODE (rtl) == MEM
&& GET_CODE (XEXP (rtl, 0)) == REG
&& (REGNO (XEXP (rtl, 0)) < FIRST_VIRTUAL_REGISTER
|| REGNO (XEXP (rtl, 0)) > LAST_VIRTUAL_REGISTER)
&& XEXP (rtl, 0) != current_function_internal_arg_pointer)
/* This is a variable-sized structure. */
- emit_insn_after (gen_rtx (USE, VOIDmode, XEXP (rtl, 0)), insn);
+ emit_insn_after (gen_rtx_USE (VOIDmode, XEXP (rtl, 0)), insn);
}
int
@@ -3129,11 +3623,21 @@ aggregate_value_p (exp)
if (RETURN_IN_MEMORY (type))
return 1;
+ /* Types that are TREE_ADDRESSABLE must be constructed in memory,
+ and thus can't be returned in registers. */
+ if (TREE_ADDRESSABLE (type))
+ return 1;
if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type))
return 1;
/* Make sure we have suitable call-clobbered regs to return
the value in; if not, we must return it in memory. */
reg = hard_function_value (type, 0);
+
+ /* If we have something other than a REG (e.g. a PARALLEL), then assume
+ it is OK. */
+ if (GET_CODE (reg) != REG)
+ return 0;
+
regno = REGNO (reg);
nregs = HARD_REGNO_NREGS (regno, TYPE_MODE (type));
for (i = 0; i < nregs; i++)
@@ -3175,12 +3679,8 @@ assign_parms (fndecl, second_time)
/* This is a dummy PARM_DECL that we used for the function result if
the function returns a structure. */
tree function_result_decl = 0;
- int nparmregs = list_length (fnargs) + LAST_VIRTUAL_REGISTER + 1;
int varargs_setup = 0;
rtx conversion_insns = 0;
- /* FUNCTION_ARG may look at this variable. Since this is not
- expanding a call it will always be zero in this function. */
- int current_call_is_indirect = 0;
/* Nonzero if the last arg is named `__builtin_va_alist',
which is used on some machines for old-fashioned non-ANSI varargs.h;
@@ -3195,7 +3695,7 @@ assign_parms (fndecl, second_time)
/* Nonzero if function takes extra anonymous args.
This means the last named arg must be on the stack
- right before the anonymous ones. */
+ right before the anonymous ones. */
int stdarg
= (TYPE_ARG_TYPES (fntype) != 0
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
@@ -3227,7 +3727,7 @@ assign_parms (fndecl, second_time)
&& ! current_function_returns_pcc_struct
&& struct_value_incoming_rtx == 0)
{
- tree type = build_pointer_type (fntype);
+ tree type = build_pointer_type (TREE_TYPE (fntype));
function_result_decl = build_decl (PARM_DECL, NULL_TREE, type);
@@ -3236,13 +3736,14 @@ assign_parms (fndecl, second_time)
fnargs = function_result_decl;
}
- parm_reg_stack_loc = (rtx *) oballoc (nparmregs * sizeof (rtx));
- bzero ((char *) parm_reg_stack_loc, nparmregs * sizeof (rtx));
+ max_parm_reg = LAST_VIRTUAL_REGISTER + 1;
+ parm_reg_stack_loc = (rtx *) savealloc (max_parm_reg * sizeof (rtx));
+ bzero ((char *) parm_reg_stack_loc, max_parm_reg * sizeof (rtx));
#ifdef INIT_CUMULATIVE_INCOMING_ARGS
INIT_CUMULATIVE_INCOMING_ARGS (args_so_far, fntype, NULL_RTX);
#else
- INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX);
+ INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0);
#endif
/* We haven't yet found an argument that we must push and pretend the
@@ -3260,10 +3761,14 @@ assign_parms (fndecl, second_time)
tree nominal_type = TREE_TYPE (parm);
/* Set LAST_NAMED if this is last named arg before some
- anonymous args. We treat it as if it were anonymous too. */
+ anonymous args. */
int last_named = ((TREE_CHAIN (parm) == 0
|| DECL_NAME (TREE_CHAIN (parm)) == 0)
&& (stdarg || current_function_varargs));
+ /* Set NAMED_ARG if this arg should be treated as a named arg. For
+ most machines, if this is a varargs/stdarg function, then we treat
+ the last named arg as if it were anonymous too. */
+ int named_arg = STRICT_ARGUMENT_NAMING ? 1 : ! last_named;
if (TREE_TYPE (parm) == error_mark_node
/* This can happen after weird syntax errors
@@ -3271,8 +3776,8 @@ assign_parms (fndecl, second_time)
|| TREE_CODE (parm) != PARM_DECL
|| passed_type == NULL)
{
- DECL_INCOMING_RTL (parm) = DECL_RTL (parm) = gen_rtx (MEM, BLKmode,
- const0_rtx);
+ DECL_INCOMING_RTL (parm) = DECL_RTL (parm)
+ = gen_rtx_MEM (BLKmode, const0_rtx);
TREE_USED (parm) = 1;
continue;
}
@@ -3312,7 +3817,7 @@ assign_parms (fndecl, second_time)
|| TREE_ADDRESSABLE (passed_type)
#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
|| FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, passed_mode,
- passed_type, ! last_named)
+ passed_type, named_arg)
#endif
)
{
@@ -3325,6 +3830,7 @@ assign_parms (fndecl, second_time)
#ifdef PROMOTE_FUNCTION_ARGS
/* Compute the mode in which the arg is actually extended to. */
+ unsignedp = TREE_UNSIGNED (passed_type);
promoted_mode = promote_mode (passed_type, promoted_mode, &unsignedp, 1);
#endif
@@ -3332,10 +3838,10 @@ assign_parms (fndecl, second_time)
0 means it arrives on the stack. */
#ifdef FUNCTION_INCOMING_ARG
entry_parm = FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
- passed_type, ! last_named);
+ passed_type, named_arg);
#else
entry_parm = FUNCTION_ARG (args_so_far, promoted_mode,
- passed_type, ! last_named);
+ passed_type, named_arg);
#endif
if (entry_parm == 0)
@@ -3381,12 +3887,12 @@ assign_parms (fndecl, second_time)
#ifdef FUNCTION_INCOMING_ARG
FUNCTION_INCOMING_ARG (args_so_far, promoted_mode,
passed_type,
- (! last_named
+ (named_arg
|| varargs_setup)) != 0,
#else
FUNCTION_ARG (args_so_far, promoted_mode,
passed_type,
- ! last_named || varargs_setup) != 0,
+ named_arg || varargs_setup) != 0,
#endif
#endif
fndecl, &stack_args_size, &stack_offset, &arg_size);
@@ -3396,15 +3902,19 @@ assign_parms (fndecl, second_time)
rtx offset_rtx = ARGS_SIZE_RTX (stack_offset);
if (offset_rtx == const0_rtx)
- stack_parm = gen_rtx (MEM, promoted_mode, internal_arg_pointer);
+ stack_parm = gen_rtx_MEM (promoted_mode, internal_arg_pointer);
else
- stack_parm = gen_rtx (MEM, promoted_mode,
- gen_rtx (PLUS, Pmode,
- internal_arg_pointer, offset_rtx));
+ stack_parm = gen_rtx_MEM (promoted_mode,
+ gen_rtx_PLUS (Pmode,
+ internal_arg_pointer,
+ offset_rtx));
/* If this is a memory ref that contains aggregate components,
- mark it as such for cse and loop optimize. */
+ mark it as such for cse and loop optimize. Likewise if it
+ is readonly. */
MEM_IN_STRUCT_P (stack_parm) = aggregate;
+ RTX_UNCHANGING_P (stack_parm) = TREE_READONLY (parm);
+ MEM_ALIAS_SET (stack_parm) = get_alias_set (parm);
}
/* If this parameter was passed both in registers and in the stack,
@@ -3424,7 +3934,7 @@ assign_parms (fndecl, second_time)
if (entry_parm)
{
int nregs = FUNCTION_ARG_PARTIAL_NREGS (args_so_far, promoted_mode,
- passed_type, ! last_named);
+ passed_type, named_arg);
if (nregs > 0)
{
@@ -3434,9 +3944,19 @@ assign_parms (fndecl, second_time)
* (PARM_BOUNDARY / BITS_PER_UNIT));
if (! second_time)
- move_block_from_reg (REGNO (entry_parm),
- validize_mem (stack_parm), nregs,
- int_size_in_bytes (TREE_TYPE (parm)));
+ {
+ /* Handle calls that pass values in multiple non-contiguous
+ locations. The Irix 6 ABI has examples of this. */
+ if (GET_CODE (entry_parm) == PARALLEL)
+ emit_group_store (validize_mem (stack_parm), entry_parm,
+ int_size_in_bytes (TREE_TYPE (parm)),
+ (TYPE_ALIGN (TREE_TYPE (parm))
+ / BITS_PER_UNIT));
+ else
+ move_block_from_reg (REGNO (entry_parm),
+ validize_mem (stack_parm), nregs,
+ int_size_in_bytes (TREE_TYPE (parm)));
+ }
entry_parm = stack_parm;
}
}
@@ -3481,9 +4001,9 @@ assign_parms (fndecl, second_time)
/* Update info on where next arg arrives in registers. */
FUNCTION_ARG_ADVANCE (args_so_far, promoted_mode,
- passed_type, ! last_named);
+ passed_type, named_arg);
- /* If this is our second time through, we are done with this parm. */
+ /* If this is our second time through, we are done with this parm. */
if (second_time)
continue;
@@ -3523,11 +4043,12 @@ assign_parms (fndecl, second_time)
offset_rtx = ARGS_SIZE_RTX (stack_offset);
if (offset_rtx == const0_rtx)
- stack_parm = gen_rtx (MEM, nominal_mode, internal_arg_pointer);
+ stack_parm = gen_rtx_MEM (nominal_mode, internal_arg_pointer);
else
- stack_parm = gen_rtx (MEM, nominal_mode,
- gen_rtx (PLUS, Pmode,
- internal_arg_pointer, offset_rtx));
+ stack_parm = gen_rtx_MEM (nominal_mode,
+ gen_rtx_PLUS (Pmode,
+ internal_arg_pointer,
+ offset_rtx));
/* If this is a memory ref that contains aggregate components,
mark it as such for cse and loop optimize. */
@@ -3543,7 +4064,7 @@ assign_parms (fndecl, second_time)
have been optimised away. */
if (GET_CODE (entry_parm) == REG && !(hide_last_arg && last_named))
- emit_insn (gen_rtx (USE, GET_MODE (entry_parm), entry_parm));
+ emit_insn (gen_rtx_USE (GET_MODE (entry_parm), entry_parm));
#endif
/* ENTRY_PARM is an RTX for the parameter as it arrives,
@@ -3560,10 +4081,13 @@ assign_parms (fndecl, second_time)
Set DECL_RTL to that place. */
- if (nominal_mode == BLKmode)
+ if (nominal_mode == BLKmode || GET_CODE (entry_parm) == PARALLEL)
{
- /* If a BLKmode arrives in registers, copy it to a stack slot. */
- if (GET_CODE (entry_parm) == REG)
+ /* If a BLKmode arrives in registers, copy it to a stack slot.
+ Handle calls that pass values in multiple non-contiguous
+ locations. The Irix 6 ABI has examples of this. */
+ if (GET_CODE (entry_parm) == REG
+ || GET_CODE (entry_parm) == PARALLEL)
{
int size_stored
= CEIL_ROUND (int_size_in_bytes (TREE_TYPE (parm)),
@@ -3594,10 +4118,18 @@ assign_parms (fndecl, second_time)
if (TREE_READONLY (parm))
RTX_UNCHANGING_P (stack_parm) = 1;
- move_block_from_reg (REGNO (entry_parm),
- validize_mem (stack_parm),
- size_stored / UNITS_PER_WORD,
- int_size_in_bytes (TREE_TYPE (parm)));
+ /* Handle calls that pass values in multiple non-contiguous
+ locations. The Irix 6 ABI has examples of this. */
+ if (GET_CODE (entry_parm) == PARALLEL)
+ emit_group_store (validize_mem (stack_parm), entry_parm,
+ int_size_in_bytes (TREE_TYPE (parm)),
+ (TYPE_ALIGN (TREE_TYPE (parm))
+ / BITS_PER_UNIT));
+ else
+ move_block_from_reg (REGNO (entry_parm),
+ validize_mem (stack_parm),
+ size_stored / UNITS_PER_WORD,
+ int_size_in_bytes (TREE_TYPE (parm)));
}
DECL_RTL (parm) = stack_parm;
}
@@ -3618,7 +4150,7 @@ assign_parms (fndecl, second_time)
may need to do it in a wider mode. */
register rtx parmreg;
- int regno, regnoi, regnor;
+ int regno, regnoi = 0, regnor = 0;
unsignedp = TREE_UNSIGNED (TREE_TYPE (parm));
@@ -3626,14 +4158,14 @@ assign_parms (fndecl, second_time)
= promote_mode (TREE_TYPE (parm), nominal_mode, &unsignedp, 0);
parmreg = gen_reg_rtx (promoted_nominal_mode);
- REG_USERVAR_P (parmreg) = 1;
+ mark_user_reg (parmreg);
/* If this was an item that we received a pointer to, set DECL_RTL
appropriately. */
if (passed_pointer)
{
DECL_RTL (parm)
- = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
+ = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
MEM_IN_STRUCT_P (DECL_RTL (parm)) = aggregate;
}
else
@@ -3646,7 +4178,7 @@ assign_parms (fndecl, second_time)
/* ENTRY_PARM has been converted to PROMOTED_MODE, its
mode, by the caller. We now have to convert it to
NOMINAL_MODE, if different. However, PARMREG may be in
- a diffent mode than NOMINAL_MODE if it is being stored
+ a different mode than NOMINAL_MODE if it is being stored
promoted.
If ENTRY_PARM is a hard register, it might be in a register
@@ -3694,7 +4226,7 @@ assign_parms (fndecl, second_time)
/* We can't use nominal_mode, because it will have been set to
Pmode above. We must use the actual mode of the parm. */
parmreg = gen_reg_rtx (TYPE_MODE (TREE_TYPE (parm)));
- REG_USERVAR_P (parmreg) = 1;
+ mark_user_reg (parmreg);
emit_move_insn (parmreg, DECL_RTL (parm));
DECL_RTL (parm) = parmreg;
/* STACK_PARM is the pointer, not the parm, and PARMREG is
@@ -3714,7 +4246,7 @@ assign_parms (fndecl, second_time)
&& FUNCTION_ARG_CALLEE_COPIES (args_so_far,
TYPE_MODE (DECL_ARG_TYPE (parm)),
DECL_ARG_TYPE (parm),
- ! last_named)
+ named_arg)
&& ! TREE_ADDRESSABLE (DECL_ARG_TYPE (parm)))
{
rtx copy;
@@ -3728,17 +4260,25 @@ assign_parms (fndecl, second_time)
if (TYPE_SIZE (type) == 0
|| TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
/* This is a variable sized object. */
- copy = gen_rtx (MEM, BLKmode,
- allocate_dynamic_stack_space
- (expr_size (parm), NULL_RTX,
- TYPE_ALIGN (type)));
+ copy = gen_rtx_MEM (BLKmode,
+ allocate_dynamic_stack_space
+ (expr_size (parm), NULL_RTX,
+ TYPE_ALIGN (type)));
else
copy = assign_stack_temp (TYPE_MODE (type),
int_size_in_bytes (type), 1);
MEM_IN_STRUCT_P (copy) = AGGREGATE_TYPE_P (type);
+ RTX_UNCHANGING_P (copy) = TREE_READONLY (parm);
store_expr (parm, copy, 0);
emit_move_insn (parmreg, XEXP (copy, 0));
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ XEXP (copy, 0), ptr_mode,
+ GEN_INT (int_size_in_bytes (type)),
+ TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_RW),
+ TYPE_MODE (integer_type_node));
conversion_insns = get_insns ();
did_conversion = 1;
end_sequence ();
@@ -3756,17 +4296,20 @@ assign_parms (fndecl, second_time)
else
regno = REGNO (parmreg);
- if (regno >= nparmregs)
+ if (regno >= max_parm_reg)
{
rtx *new;
- int old_nparmregs = nparmregs;
+ int old_max_parm_reg = max_parm_reg;
- nparmregs = regno + 5;
- new = (rtx *) oballoc (nparmregs * sizeof (rtx));
+ /* It's slow to expand this one register at a time,
+ but it's also rare and we need max_parm_reg to be
+ precisely correct. */
+ max_parm_reg = regno + 1;
+ new = (rtx *) savealloc (max_parm_reg * sizeof (rtx));
bcopy ((char *) parm_reg_stack_loc, (char *) new,
- old_nparmregs * sizeof (rtx));
- bzero ((char *) (new + old_nparmregs),
- (nparmregs - old_nparmregs) * sizeof (rtx));
+ old_max_parm_reg * sizeof (rtx));
+ bzero ((char *) (new + old_max_parm_reg),
+ (max_parm_reg - old_max_parm_reg) * sizeof (rtx));
parm_reg_stack_loc = new;
}
@@ -3801,41 +4344,48 @@ assign_parms (fndecl, second_time)
as we make here would screw up life analysis for it. */
if (nominal_mode == passed_mode
&& ! did_conversion
- && GET_CODE (entry_parm) == MEM
- && entry_parm == stack_parm
+ && stack_parm != 0
+ && GET_CODE (stack_parm) == MEM
&& stack_offset.var == 0
&& reg_mentioned_p (virtual_incoming_args_rtx,
- XEXP (entry_parm, 0)))
+ XEXP (stack_parm, 0)))
{
rtx linsn = get_last_insn ();
+ rtx sinsn, set;
/* Mark complex types separately. */
if (GET_CODE (parmreg) == CONCAT)
- {
- REG_NOTES (linsn)
- = gen_rtx (EXPR_LIST, REG_EQUIV,
- parm_reg_stack_loc[regnoi], REG_NOTES (linsn));
-
- /* Now search backward for where we set the real part. */
- for (; linsn != 0
- && ! reg_referenced_p (parm_reg_stack_loc[regnor],
- PATTERN (linsn));
- linsn = prev_nonnote_insn (linsn))
- ;
-
- REG_NOTES (linsn)
- = gen_rtx (EXPR_LIST, REG_EQUIV,
- parm_reg_stack_loc[regnor], REG_NOTES (linsn));
- }
- else
+ /* Scan backwards for the set of the real and
+ imaginary parts. */
+ for (sinsn = linsn; sinsn != 0;
+ sinsn = prev_nonnote_insn (sinsn))
+ {
+ set = single_set (sinsn);
+ if (set != 0
+ && SET_DEST (set) == regno_reg_rtx [regnoi])
+ REG_NOTES (sinsn)
+ = gen_rtx_EXPR_LIST (REG_EQUIV,
+ parm_reg_stack_loc[regnoi],
+ REG_NOTES (sinsn));
+ else if (set != 0
+ && SET_DEST (set) == regno_reg_rtx [regnor])
+ REG_NOTES (sinsn)
+ = gen_rtx_EXPR_LIST (REG_EQUIV,
+ parm_reg_stack_loc[regnor],
+ REG_NOTES (sinsn));
+ }
+ else if ((set = single_set (linsn)) != 0
+ && SET_DEST (set) == parmreg)
REG_NOTES (linsn)
- = gen_rtx (EXPR_LIST, REG_EQUIV,
- entry_parm, REG_NOTES (linsn));
+ = gen_rtx_EXPR_LIST (REG_EQUIV,
+ stack_parm, REG_NOTES (linsn));
}
/* For pointer data type, suggest pointer register. */
- if (TREE_CODE (TREE_TYPE (parm)) == POINTER_TYPE)
- mark_reg_pointer (parmreg);
+ if (POINTER_TYPE_P (TREE_TYPE (parm)))
+ mark_reg_pointer (parmreg,
+ (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm)))
+ / BITS_PER_UNIT));
}
else
{
@@ -3852,6 +4402,12 @@ assign_parms (fndecl, second_time)
push_to_sequence (conversion_insns);
entry_parm = convert_to_mode (nominal_mode, tempreg,
TREE_UNSIGNED (TREE_TYPE (parm)));
+ if (stack_parm)
+ {
+ /* ??? This may need a big-endian conversion on sparc64. */
+ stack_parm = change_address (stack_parm, nominal_mode,
+ NULL_RTX);
+ }
conversion_insns = get_insns ();
did_conversion = 1;
end_sequence ();
@@ -3881,7 +4437,20 @@ assign_parms (fndecl, second_time)
emit_move_insn (validize_mem (stack_parm),
validize_mem (entry_parm));
}
+ if (flag_check_memory_usage)
+ {
+ push_to_sequence (conversion_insns);
+ emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
+ XEXP (stack_parm, 0), ptr_mode,
+ GEN_INT (GET_MODE_SIZE (GET_MODE
+ (entry_parm))),
+ TYPE_MODE (sizetype),
+ GEN_INT (MEMORY_USE_RW),
+ TYPE_MODE (integer_type_node));
+ conversion_insns = get_insns ();
+ end_sequence ();
+ }
DECL_RTL (parm) = stack_parm;
}
@@ -3893,7 +4462,7 @@ assign_parms (fndecl, second_time)
tree restype = TREE_TYPE (result);
DECL_RTL (result)
- = gen_rtx (MEM, DECL_MODE (result), DECL_RTL (parm));
+ = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
MEM_IN_STRUCT_P (DECL_RTL (result)) = AGGREGATE_TYPE_P (restype);
}
@@ -3908,7 +4477,6 @@ assign_parms (fndecl, second_time)
now that all parameters have been copied out of hard registers. */
emit_insns (conversion_insns);
- max_parm_reg = max_reg_num ();
last_parm_insn = get_last_insn ();
current_function_args_size = stack_args_size.constant;
@@ -3936,7 +4504,7 @@ assign_parms (fndecl, second_time)
= (stack_args_size.var == 0 ? GEN_INT (-stack_args_size.constant)
: expand_expr (size_binop (MINUS_EXPR, stack_args_size.var,
size_int (-stack_args_size.constant)),
- NULL_RTX, VOIDmode, 0));
+ NULL_RTX, VOIDmode, EXPAND_MEMORY_USE_BAD));
#else
current_function_arg_offset_rtx = ARGS_SIZE_RTX (stack_args_size);
#endif
@@ -4045,14 +4613,14 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
= type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
- int boundary_in_bytes = boundary / BITS_PER_UNIT;
- int reg_parm_stack_space = 0;
#ifdef REG_PARM_STACK_SPACE
/* If we have found a stack parm before we reach the end of the
area reserved for registers, skip that area. */
if (! in_regs)
{
+ int reg_parm_stack_space = 0;
+
#ifdef MAYBE_REG_PARM_STACK_SPACE
reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
#else
@@ -4105,8 +4673,8 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
}
else
{
- arg_size_ptr->constant = (- initial_offset_ptr->constant -
- offset_ptr->constant);
+ arg_size_ptr->constant = (- initial_offset_ptr->constant
+ - offset_ptr->constant);
}
#else /* !ARGS_GROW_DOWNWARD */
pad_to_arg_alignment (initial_offset_ptr, boundary);
@@ -4168,6 +4736,7 @@ pad_to_arg_alignment (offset_ptr, boundary)
}
}
+#ifndef ARGS_GROW_DOWNWARD
static void
pad_below (offset_ptr, passed_mode, sizetree)
struct args_size *offset_ptr;
@@ -4195,7 +4764,9 @@ pad_below (offset_ptr, passed_mode, sizetree)
}
}
}
+#endif
+#ifdef ARGS_GROW_DOWNWARD
static tree
round_down (value, divisor)
tree value;
@@ -4205,6 +4776,7 @@ round_down (value, divisor)
size_binop (FLOOR_DIV_EXPR, value, size_int (divisor)),
size_int (divisor));
}
+#endif
/* Walk the tree of blocks describing the binding levels within a function
and warn about uninitialized variables.
@@ -4267,9 +4839,11 @@ setjmp_protect (block)
if ((TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == PARM_DECL)
&& DECL_RTL (decl) != 0
- && GET_CODE (DECL_RTL (decl)) == REG
+ && (GET_CODE (DECL_RTL (decl)) == REG
+ || (GET_CODE (DECL_RTL (decl)) == MEM
+ && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
/* If this variable came from an inline function, it must be
- that it's life doesn't overlap the setjmp. If there was a
+ that its life doesn't overlap the setjmp. If there was a
setjmp in the function, it would already be in memory. We
must exclude such variable because their DECL_RTL might be
set to strange things such as virtual_stack_vars_rtx. */
@@ -4292,13 +4866,15 @@ setjmp_protect (block)
void
setjmp_protect_args ()
{
- register tree decl, sub;
+ register tree decl;
for (decl = DECL_ARGUMENTS (current_function_decl);
decl; decl = TREE_CHAIN (decl))
if ((TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == PARM_DECL)
&& DECL_RTL (decl) != 0
- && GET_CODE (DECL_RTL (decl)) == REG
+ && (GET_CODE (DECL_RTL (decl)) == REG
+ || (GET_CODE (DECL_RTL (decl)) == MEM
+ && GET_CODE (XEXP (DECL_RTL (decl), 0)) == ADDRESSOF))
&& (
/* If longjmp doesn't restore the registers,
don't put anything in them. */
@@ -4320,9 +4896,10 @@ lookup_static_chain (decl)
tree context = decl_function_context (decl);
tree link;
- if (context == 0)
+ if (context == 0
+ || (TREE_CODE (decl) == FUNCTION_DECL && DECL_NO_STATIC_CHAIN (decl)))
return 0;
-
+
/* We treat inline_function_decl as an alias for the current function
because that is the inline function whose vars, types, etc.
are being merged into the current function.
@@ -4347,7 +4924,7 @@ fix_lexical_addr (addr, var)
tree var;
{
rtx basereg;
- int displacement;
+ HOST_WIDE_INT displacement;
tree context = decl_function_context (var);
struct function *fp;
rtx base = 0;
@@ -4363,6 +4940,9 @@ fix_lexical_addr (addr, var)
if (fp == 0)
abort ();
+ if (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == MEM)
+ addr = XEXP (XEXP (addr, 0), 0);
+
/* Decode given address as base reg plus displacement. */
if (GET_CODE (addr) == REG)
basereg = addr, displacement = 0;
@@ -4394,7 +4974,7 @@ fix_lexical_addr (addr, var)
addr = fix_lexical_addr (XEXP (fp->arg_pointer_save_area, 0), var);
addr = memory_address (Pmode, addr);
- base = copy_to_reg (gen_rtx (MEM, Pmode, addr));
+ base = copy_to_reg (gen_rtx_MEM (Pmode, addr));
#else
displacement += (FIRST_PARM_OFFSET (context) - STARTING_FRAME_OFFSET);
base = lookup_static_chain (var);
@@ -4457,7 +5037,8 @@ trampoline_address (function)
/* Find the `struct function' for the function containing FUNCTION. */
fp = 0;
fn_context = decl_function_context (function);
- if (fn_context != current_function_decl)
+ if (fn_context != current_function_decl
+ && fn_context != inline_function_decl)
for (fp = outer_function_chain; fp; fp = fp->next)
if (fp->decl == fn_context)
break;
@@ -4470,7 +5051,8 @@ trampoline_address (function)
/* If rounding needed, allocate extra space
to ensure we have TRAMPOLINE_SIZE bytes left after rounding up. */
#ifdef TRAMPOLINE_ALIGNMENT
-#define TRAMPOLINE_REAL_SIZE (TRAMPOLINE_SIZE + TRAMPOLINE_ALIGNMENT - 1)
+#define TRAMPOLINE_REAL_SIZE \
+ (TRAMPOLINE_SIZE + (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT) - 1)
#else
#define TRAMPOLINE_REAL_SIZE (TRAMPOLINE_SIZE)
#endif
@@ -4518,10 +5100,10 @@ round_trampoline_addr (tramp)
/* Round address up to desired boundary. */
rtx temp = gen_reg_rtx (Pmode);
temp = expand_binop (Pmode, add_optab, tramp,
- GEN_INT (TRAMPOLINE_ALIGNMENT - 1),
+ GEN_INT (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT - 1),
temp, 0, OPTAB_LIB_WIDEN);
tramp = expand_binop (Pmode, and_optab, temp,
- GEN_INT (- TRAMPOLINE_ALIGNMENT),
+ GEN_INT (- TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT),
temp, 0, OPTAB_LIB_WIDEN);
#endif
return tramp;
@@ -4532,33 +5114,34 @@ round_trampoline_addr (tramp)
duplicate portions of the RTL code. Call identify_blocks before
changing the RTL, and call reorder_blocks after. */
-/* Put all this function's BLOCK nodes into a vector, and return it.
+/* Put all this function's BLOCK nodes including those that are chained
+ onto the first block into a vector, and return it.
Also store in each NOTE for the beginning or end of a block
the index of that block in the vector.
- The arguments are TOP_BLOCK, the top-level block of the function,
+ The arguments are BLOCK, the chain of top-level blocks of the function,
and INSNS, the insn chain of the function. */
tree *
-identify_blocks (top_block, insns)
- tree top_block;
+identify_blocks (block, insns)
+ tree block;
rtx insns;
{
int n_blocks;
tree *block_vector;
int *block_stack;
int depth = 0;
- int next_block_number = 0;
- int current_block_number = 0;
+ int next_block_number = 1;
+ int current_block_number = 1;
rtx insn;
- if (top_block == 0)
+ if (block == 0)
return 0;
- n_blocks = all_blocks (top_block, 0);
+ n_blocks = all_blocks (block, 0);
block_vector = (tree *) xmalloc (n_blocks * sizeof (tree));
block_stack = (int *) alloca (n_blocks * sizeof (int));
- all_blocks (top_block, block_vector);
+ all_blocks (block, block_vector);
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE)
@@ -4571,11 +5154,14 @@ identify_blocks (top_block, insns)
}
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
{
- current_block_number = block_stack[--depth];
NOTE_BLOCK_NUMBER (insn) = current_block_number;
+ current_block_number = block_stack[--depth];
}
}
+ if (n_blocks != next_block_number)
+ abort ();
+
return block_vector;
}
@@ -4586,19 +5172,20 @@ identify_blocks (top_block, insns)
Returns the current top-level block. */
tree
-reorder_blocks (block_vector, top_block, insns)
+reorder_blocks (block_vector, block, insns)
tree *block_vector;
- tree top_block;
+ tree block;
rtx insns;
{
- tree current_block = top_block;
+ tree current_block = block;
rtx insn;
if (block_vector == 0)
- return top_block;
+ return block;
- /* Prune the old tree away, so that it doesn't get in the way. */
+ /* Prune the old trees away, so that it doesn't get in the way. */
BLOCK_SUBBLOCKS (current_block) = 0;
+ BLOCK_CHAIN (current_block) = 0;
for (insn = insns; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == NOTE)
@@ -4626,6 +5213,8 @@ reorder_blocks (block_vector, top_block, insns)
}
}
+ BLOCK_SUBBLOCKS (current_block)
+ = blocks_nreverse (BLOCK_SUBBLOCKS (current_block));
return current_block;
}
@@ -4646,74 +5235,36 @@ blocks_nreverse (t)
return prev;
}
-/* Count the subblocks of BLOCK, and list them all into the vector VECTOR.
- Also clear TREE_ASM_WRITTEN in all blocks. */
+/* Count the subblocks of the list starting with BLOCK, and list them
+ all into the vector VECTOR. Also clear TREE_ASM_WRITTEN in all
+ blocks. */
static int
all_blocks (block, vector)
tree block;
tree *vector;
{
- int n_blocks = 1;
- tree subblocks;
-
- TREE_ASM_WRITTEN (block) = 0;
- /* Record this block. */
- if (vector)
- vector[0] = block;
-
- /* Record the subblocks, and their subblocks. */
- for (subblocks = BLOCK_SUBBLOCKS (block);
- subblocks; subblocks = BLOCK_CHAIN (subblocks))
- n_blocks += all_blocks (subblocks, vector ? vector + n_blocks : 0);
-
- return n_blocks;
-}
-
-/* Build bytecode call descriptor for function SUBR. */
-
-rtx
-bc_build_calldesc (subr)
- tree subr;
-{
- tree calldesc = 0, arg;
- int nargs = 0;
+ int n_blocks = 0;
- /* Build the argument description vector in reverse order. */
- DECL_ARGUMENTS (subr) = nreverse (DECL_ARGUMENTS (subr));
- nargs = 0;
-
- for (arg = DECL_ARGUMENTS (subr); arg; arg = TREE_CHAIN (arg))
+ while (block)
{
- ++nargs;
-
- calldesc = tree_cons ((tree) 0, size_in_bytes (TREE_TYPE (arg)), calldesc);
- calldesc = tree_cons ((tree) 0, bc_runtime_type_code (TREE_TYPE (arg)), calldesc);
- }
-
- DECL_ARGUMENTS (subr) = nreverse (DECL_ARGUMENTS (subr));
+ TREE_ASM_WRITTEN (block) = 0;
- /* Prepend the function's return type. */
- calldesc = tree_cons ((tree) 0,
- size_in_bytes (TREE_TYPE (TREE_TYPE (subr))),
- calldesc);
+ /* Record this block. */
+ if (vector)
+ vector[n_blocks] = block;
- calldesc = tree_cons ((tree) 0,
- bc_runtime_type_code (TREE_TYPE (TREE_TYPE (subr))),
- calldesc);
-
- /* Prepend the arg count. */
- calldesc = tree_cons ((tree) 0, build_int_2 (nargs, 0), calldesc);
-
- /* Output the call description vector and get its address. */
- calldesc = build_nt (CONSTRUCTOR, (tree) 0, calldesc);
- TREE_TYPE (calldesc) = build_array_type (integer_type_node,
- build_index_type (build_int_2 (nargs * 2, 0)));
+ ++n_blocks;
+
+ /* Record the subblocks, and their subblocks... */
+ n_blocks += all_blocks (BLOCK_SUBBLOCKS (block),
+ vector ? vector + n_blocks : 0);
+ block = BLOCK_CHAIN (block);
+ }
- return output_constant_def (calldesc);
+ return n_blocks;
}
-
-
+
/* Generate RTL for the start of the function SUBR (a FUNCTION_DECL tree node)
and initialize static variables for generating RTL for the statements
of the function. */
@@ -4724,19 +5275,6 @@ init_function_start (subr, filename, line)
char *filename;
int line;
{
- char *junk;
-
- if (output_bytecode)
- {
- this_function_decl = subr;
- this_function_calldesc = bc_build_calldesc (subr);
- local_vars_size = 0;
- stack_depth = 0;
- max_stack_depth = 0;
- stmt_expr_depth = 0;
- return;
- }
-
init_stmt_for_function ();
cse_not_expected = ! optimize;
@@ -4773,12 +5311,13 @@ init_function_start (subr, filename, line)
init_const_rtx_hash_table ();
- current_function_name = (*decl_printable_name) (subr, &junk);
+ current_function_name = (*decl_printable_name) (subr, 2);
/* Nonzero if this is a nested function that uses a static chain. */
current_function_needs_context
- = (decl_function_context (current_function_decl) != 0);
+ = (decl_function_context (current_function_decl) != 0
+ && ! DECL_NO_STATIC_CHAIN (current_function_decl));
/* Set if a call to setjmp is seen. */
current_function_calls_setjmp = 0;
@@ -4790,12 +5329,14 @@ init_function_start (subr, filename, line)
current_function_has_nonlocal_label = 0;
current_function_has_nonlocal_goto = 0;
current_function_contains_functions = 0;
+ current_function_is_thunk = 0;
current_function_returns_pcc_struct = 0;
current_function_returns_struct = 0;
current_function_epilogue_delay_list = 0;
current_function_uses_const_pool = 0;
current_function_uses_pic_offset_table = 0;
+ current_function_cannot_inline = 0;
/* We have not yet needed to make a label to jump to for tail-recursion. */
tail_recursion_label = 0;
@@ -4813,10 +5354,8 @@ init_function_start (subr, filename, line)
/* No RTL_EXPRs in this function yet. */
rtl_expr_chain = 0;
- /* We have not allocated any temporaries yet. */
- temp_slots = 0;
- temp_slot_level = 0;
- target_temp_slot_level = 0;
+ /* Set up to allocate temporaries. */
+ init_temp_slots ();
/* Within function body, compute a type's size as soon it is laid out. */
immediate_size_expand++;
@@ -4830,8 +5369,10 @@ init_function_start (subr, filename, line)
current_function_outgoing_args_size = 0;
/* Prevent ever trying to delete the first instruction of a function.
- Also tell final how to output a linenum before the function prologue. */
- emit_line_note (filename, line);
+ Also tell final how to output a linenum before the function prologue.
+ Note linenums could be missing, e.g. when compiling a Java .class file. */
+ if (line > 0)
+ emit_line_note (filename, line);
/* Make sure first insn is a note even if we don't want linenums.
This makes sure the first insn will never be deleted.
@@ -4890,99 +5431,14 @@ mark_varargs ()
void
expand_main_function ()
{
- if (!output_bytecode)
- {
- /* The zero below avoids a possible parse error */
- 0;
#if !defined (HAS_INIT_SECTION)
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, NAME__MAIN), 0,
- VOIDmode, 0);
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, NAME__MAIN), 0,
+ VOIDmode, 0);
#endif /* not HAS_INIT_SECTION */
- }
}
extern struct obstack permanent_obstack;
-/* Expand start of bytecode function. See comment at
- expand_function_start below for details. */
-
-void
-bc_expand_function_start (subr, parms_have_cleanups)
- tree subr;
- int parms_have_cleanups;
-{
- char label[20], *name;
- static int nlab;
- tree thisarg;
- int argsz;
-
- if (TREE_PUBLIC (subr))
- bc_globalize_label (IDENTIFIER_POINTER (DECL_NAME (subr)));
-
-#ifdef DEBUG_PRINT_CODE
- fprintf (stderr, "\n<func %s>\n", IDENTIFIER_POINTER (DECL_NAME (subr)));
-#endif
-
- for (argsz = 0, thisarg = DECL_ARGUMENTS (subr); thisarg; thisarg = TREE_CHAIN (thisarg))
- {
- if (DECL_RTL (thisarg))
- abort (); /* Should be NULL here I think. */
- else if (TREE_CONSTANT (DECL_SIZE (thisarg)))
- {
- DECL_RTL (thisarg) = bc_gen_rtx ((char *) 0, argsz, (struct bc_label *) 0);
- argsz += TREE_INT_CST_LOW (DECL_SIZE (thisarg));
- }
- else
- {
- /* Variable-sized objects are pointers to their storage. */
- DECL_RTL (thisarg) = bc_gen_rtx ((char *) 0, argsz, (struct bc_label *) 0);
- argsz += POINTER_SIZE;
- }
- }
-
- bc_begin_function (bc_xstrdup (IDENTIFIER_POINTER (DECL_NAME (subr))));
-
- ASM_GENERATE_INTERNAL_LABEL (label, "LX", nlab);
-
- ++nlab;
- name = (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
- this_function_callinfo = bc_gen_rtx (name, 0, (struct bc_label *) 0);
- this_function_bytecode =
- bc_emit_trampoline (BYTECODE_LABEL (this_function_callinfo));
-}
-
-
-/* Expand end of bytecode function. See details the comment of
- expand_function_end(), below. */
-
-void
-bc_expand_function_end ()
-{
- char *ptrconsts;
-
- expand_null_return ();
-
- /* Emit any fixup code. This must be done before the call to
- to BC_END_FUNCTION (), since that will cause the bytecode
- segment to be finished off and closed. */
-
- expand_fixups (NULL_RTX);
-
- ptrconsts = bc_end_function ();
-
- bc_align_const (2 /* INT_ALIGN */);
-
- /* If this changes also make sure to change bc-interp.h! */
-
- bc_emit_const_labeldef (BYTECODE_LABEL (this_function_callinfo));
- bc_emit_const ((char *) &max_stack_depth, sizeof max_stack_depth);
- bc_emit_const ((char *) &local_vars_size, sizeof local_vars_size);
- bc_emit_const_labelref (this_function_bytecode, 0);
- bc_emit_const_labelref (ptrconsts, 0);
- bc_emit_const_labelref (BYTECODE_LABEL (this_function_calldesc), 0);
-}
-
-
/* Start the RTL for a new function, and set variables used for
emitting RTL.
SUBR is the FUNCTION_DECL node.
@@ -4996,13 +5452,7 @@ expand_function_start (subr, parms_have_cleanups)
{
register int i;
tree tem;
- rtx last_ptr;
-
- if (output_bytecode)
- {
- bc_expand_function_start (subr, parms_have_cleanups);
- return;
- }
+ rtx last_ptr = NULL_RTX;
/* Make sure volatile mem refs aren't considered
valid operands of arithmetic insns. */
@@ -5014,11 +5464,10 @@ expand_function_start (subr, parms_have_cleanups)
{
last_ptr = assign_stack_local (Pmode, GET_MODE_SIZE (Pmode), 0);
-#ifdef SMALL_REGISTER_CLASSES
/* Delay copying static chain if it is not a register to avoid
conflicts with regs used for parameters. */
- if (GET_CODE (static_chain_incoming_rtx) == REG)
-#endif
+ if (! SMALL_REGISTER_CLASSES
+ || GET_CODE (static_chain_incoming_rtx) == REG)
emit_move_insn (last_ptr, static_chain_incoming_rtx);
}
@@ -5075,7 +5524,7 @@ expand_function_start (subr, parms_have_cleanups)
if (value_address)
{
DECL_RTL (DECL_RESULT (subr))
- = gen_rtx (MEM, DECL_MODE (DECL_RESULT (subr)), value_address);
+ = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
MEM_IN_STRUCT_P (DECL_RTL (DECL_RESULT (subr)))
= AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr)));
}
@@ -5127,14 +5576,12 @@ expand_function_start (subr, parms_have_cleanups)
assign_parms (subr, 0);
-#ifdef SMALL_REGISTER_CLASSES
/* Copy the static chain now if it wasn't a register. The delay is to
avoid conflicts with the parameter passing registers. */
- if (current_function_needs_context)
+ if (SMALL_REGISTER_CLASSES && current_function_needs_context)
if (GET_CODE (static_chain_incoming_rtx) != REG)
emit_move_insn (last_ptr, static_chain_incoming_rtx);
-#endif
/* The following was moved from init_function_start.
The move is supposed to make sdb output more accurate. */
@@ -5157,48 +5604,50 @@ expand_function_start (subr, parms_have_cleanups)
use_variable (current_function_internal_arg_pointer);
}
- /* Fetch static chain values for containing functions. */
- tem = decl_function_context (current_function_decl);
- /* If not doing stupid register allocation copy the static chain
- pointer into a pseudo. If we have small register classes, copy the
- value from memory if static_chain_incoming_rtx is a REG. If we do
- stupid register allocation, we use the stack address generated above. */
- if (tem && ! obey_regdecls)
- {
-#ifdef SMALL_REGISTER_CLASSES
- /* If the static chain originally came in a register, put it back
- there, then move it out in the next insn. The reason for
- this peculiar code is to satisfy function integration. */
- if (GET_CODE (static_chain_incoming_rtx) == REG)
- emit_move_insn (static_chain_incoming_rtx, last_ptr);
-#endif
-
- last_ptr = copy_to_reg (static_chain_incoming_rtx);
- }
-
context_display = 0;
- while (tem)
+ if (current_function_needs_context)
{
- tree rtlexp = make_node (RTL_EXPR);
+ /* Fetch static chain values for containing functions. */
+ tem = decl_function_context (current_function_decl);
+ /* If not doing stupid register allocation copy the static chain
+ pointer into a pseudo. If we have small register classes, copy
+ the value from memory if static_chain_incoming_rtx is a REG. If
+ we do stupid register allocation, we use the stack address
+ generated above. */
+ if (tem && ! obey_regdecls)
+ {
+ /* If the static chain originally came in a register, put it back
+ there, then move it out in the next insn. The reason for
+ this peculiar code is to satisfy function integration. */
+ if (SMALL_REGISTER_CLASSES
+ && GET_CODE (static_chain_incoming_rtx) == REG)
+ emit_move_insn (static_chain_incoming_rtx, last_ptr);
+ last_ptr = copy_to_reg (static_chain_incoming_rtx);
+ }
- RTL_EXPR_RTL (rtlexp) = last_ptr;
- context_display = tree_cons (tem, rtlexp, context_display);
- tem = decl_function_context (tem);
- if (tem == 0)
- break;
- /* Chain thru stack frames, assuming pointer to next lexical frame
- is found at the place we always store it. */
+ while (tem)
+ {
+ tree rtlexp = make_node (RTL_EXPR);
+
+ RTL_EXPR_RTL (rtlexp) = last_ptr;
+ context_display = tree_cons (tem, rtlexp, context_display);
+ tem = decl_function_context (tem);
+ if (tem == 0)
+ break;
+ /* Chain thru stack frames, assuming pointer to next lexical frame
+ is found at the place we always store it. */
#ifdef FRAME_GROWS_DOWNWARD
- last_ptr = plus_constant (last_ptr, - GET_MODE_SIZE (Pmode));
+ last_ptr = plus_constant (last_ptr, - GET_MODE_SIZE (Pmode));
#endif
- last_ptr = copy_to_reg (gen_rtx (MEM, Pmode,
- memory_address (Pmode, last_ptr)));
-
- /* If we are not optimizing, ensure that we know that this
- piece of context is live over the entire function. */
- if (! optimize)
- save_expr_regs = gen_rtx (EXPR_LIST, VOIDmode, last_ptr,
- save_expr_regs);
+ last_ptr = copy_to_reg (gen_rtx_MEM (Pmode,
+ memory_address (Pmode, last_ptr)));
+
+ /* If we are not optimizing, ensure that we know that this
+ piece of context is live over the entire function. */
+ if (! optimize)
+ save_expr_regs = gen_rtx_EXPR_LIST (VOIDmode, last_ptr,
+ save_expr_regs);
+ }
}
/* After the display initializations is where the tail-recursion label
@@ -5208,7 +5657,13 @@ expand_function_start (subr, parms_have_cleanups)
/* Evaluate now the sizes of any types declared among the arguments. */
for (tem = nreverse (get_pending_sizes ()); tem; tem = TREE_CHAIN (tem))
- expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode, 0);
+ {
+ expand_expr (TREE_VALUE (tem), const0_rtx, VOIDmode,
+ EXPAND_MEMORY_USE_BAD);
+ /* Flush the queue in case this parameter declaration has
+ side-effects. */
+ emit_queue ();
+ }
/* Make sure there is a line number after the function entry setup code. */
force_next_line_note ();
@@ -5233,12 +5688,6 @@ expand_function_end (filename, line, end_bindings)
static rtx initial_trampoline;
#endif
- if (output_bytecode)
- {
- bc_expand_function_end ();
- return;
- }
-
#ifdef NON_SAVING_SETJMP
/* Don't put any variables in registers if we call setjmp
on a machine that fails to restore the registers. */
@@ -5264,7 +5713,9 @@ expand_function_end (filename, line, end_bindings)
tree function = TREE_PURPOSE (link);
rtx context = lookup_static_chain (function);
rtx tramp = RTL_EXPR_RTL (TREE_VALUE (link));
+#ifdef TRAMPOLINE_TEMPLATE
rtx blktramp;
+#endif
rtx seq;
#ifdef TRAMPOLINE_TEMPLATE
@@ -5274,7 +5725,7 @@ expand_function_end (filename, line, end_bindings)
{
end_temporary_allocation ();
initial_trampoline
- = gen_rtx (MEM, BLKmode, assemble_trampoline_template ());
+ = gen_rtx_MEM (BLKmode, assemble_trampoline_template ());
resume_temporary_allocation ();
}
#endif
@@ -5286,7 +5737,7 @@ expand_function_end (filename, line, end_bindings)
blktramp = change_address (initial_trampoline, BLKmode, tramp);
emit_block_move (blktramp, initial_trampoline,
GEN_INT (TRAMPOLINE_SIZE),
- FUNCTION_BOUNDARY / BITS_PER_UNIT);
+ TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
#endif
INITIALIZE_TRAMPOLINE (tramp, XEXP (DECL_RTL (function), 0), context);
seq = get_insns ();
@@ -5296,6 +5747,26 @@ expand_function_end (filename, line, end_bindings)
emit_insns_before (seq, tail_recursion_reentry);
}
+ /* If we are doing stack checking and this function makes calls,
+ do a stack probe at the start of the function to ensure we have enough
+ space for another stack frame. */
+ if (flag_stack_check && ! STACK_CHECK_BUILTIN)
+ {
+ rtx insn, seq;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ start_sequence ();
+ probe_stack_range (STACK_CHECK_PROTECT,
+ GEN_INT (STACK_CHECK_MAX_FRAME_SIZE));
+ seq = get_insns ();
+ end_sequence ();
+ emit_insns_before (seq, tail_recursion_reentry);
+ break;
+ }
+ }
+
/* Warn about unused parms if extra warnings were specified. */
if (warn_unused && extra_warnings)
{
@@ -5349,6 +5820,14 @@ expand_function_end (filename, line, end_bindings)
without returning a value. */
emit_note (NULL_PTR, NOTE_INSN_FUNCTION_END);
+ /* Must mark the last line number note in the function, so that the test
+ coverage code can avoid counting the last line twice. This just tells
+ the code to ignore the immediately following line note, since there
+ already exists a copy of this note somewhere above. This line number
+ note is still needed for debugging though, so we can't delete it. */
+ if (flag_test_coverage)
+ emit_note (NULL_PTR, NOTE_REPEATED_LINE_NUMBER);
+
/* Output a linenumber for the end of the function.
SDB depends on this. */
emit_line_note_force (filename, line);
@@ -5366,6 +5845,24 @@ expand_function_end (filename, line, end_bindings)
if (end_bindings)
expand_end_bindings (0, 0, 0);
+ /* Now handle any leftover exception regions that may have been
+ created for the parameters. */
+ {
+ rtx last = get_last_insn ();
+ rtx label;
+
+ expand_leftover_cleanups ();
+
+ /* If the above emitted any code, may sure we jump around it. */
+ if (last != get_last_insn ())
+ {
+ label = gen_label_rtx ();
+ last = emit_jump_insn_after (gen_jump (label), last);
+ last = emit_barrier_after (last);
+ emit_label (label);
+ }
+ }
+
/* If we had calls to alloca, and this machine needs
an accurate stack pointer to exit the function,
insert some code to save and restore the stack pointer. */
@@ -5399,9 +5896,19 @@ expand_function_end (filename, line, end_bindings)
current_function_decl);
#endif
REG_FUNCTION_VALUE_P (real_decl_result) = 1;
+ /* If this is a BLKmode structure being returned in registers, then use
+ the mode computed in expand_return. */
+ if (GET_MODE (real_decl_result) == BLKmode)
+ PUT_MODE (real_decl_result,
+ GET_MODE (DECL_RTL (DECL_RESULT (current_function_decl))));
emit_move_insn (real_decl_result,
DECL_RTL (DECL_RESULT (current_function_decl)));
- emit_insn (gen_rtx (USE, VOIDmode, real_decl_result));
+ emit_insn (gen_rtx_USE (VOIDmode, real_decl_result));
+
+ /* The delay slot scheduler assumes that current_function_return_rtx
+ holds the hard register containing the return value, not a temporary
+ pseudo. */
+ current_function_return_rtx = real_decl_result;
}
/* If returning a structure, arrange to return the address of the value
@@ -5463,6 +5970,7 @@ static int *epilogue;
/* Create an array that records the INSN_UIDs of INSNS (either a sequence
or a single insn). */
+#if defined (HAVE_prologue) || defined (HAVE_epilogue)
static int *
record_insns (insns)
rtx insns;
@@ -5513,6 +6021,7 @@ contains (insn, vec)
}
return 0;
}
+#endif /* HAVE_prologue || HAVE_epilogue */
/* Generate the prologue and epilogue RTL if the machine supports it. Thread
this into place with notes indicating where the prologue ends and where
@@ -5525,7 +6034,7 @@ thread_prologue_and_epilogue_insns (f)
#ifdef HAVE_prologue
if (HAVE_prologue)
{
- rtx head, seq, insn;
+ rtx head, seq;
/* The first insn (a NOTE_INSN_DELETED) is followed by zero or more
prologue insns and a NOTE_INSN_PROLOGUE_END. */
@@ -5652,7 +6161,7 @@ reposition_prologue_and_epilogue_notes (f)
move it to just after the last prologue insn. */
if (note == 0)
{
- for (note = insn; note = NEXT_INSN (note);)
+ for (note = insn; (note = NEXT_INSN (note));)
if (GET_CODE (note) == NOTE
&& NOTE_LINE_NUMBER (note) == NOTE_INSN_PROLOGUE_END)
break;
@@ -5690,7 +6199,7 @@ reposition_prologue_and_epilogue_notes (f)
move it to just before the first epilogue insn. */
if (note == 0)
{
- for (note = insn; note = PREV_INSN (note);)
+ for (note = insn; (note = PREV_INSN (note));)
if (GET_CODE (note) == NOTE
&& NOTE_LINE_NUMBER (note) == NOTE_INSN_EPILOGUE_BEG)
break;
diff --git a/contrib/gcc/function.h b/contrib/gcc/function.h
index 24b4be2..0382a4e 100644
--- a/contrib/gcc/function.h
+++ b/contrib/gcc/function.h
@@ -1,5 +1,5 @@
/* Structure for saving state for a nested function.
- Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,11 +19,13 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#ifndef NULL_TREE
-#define tree int *
+#if !defined(NULL_TREE) && !defined(tree)
+typedef union union_node *_function_tree;
+#define tree _function_tree
#endif
-#ifndef GET_CODE
-#define rtx int *
+#if !defined(NULL_RTX) && !defined(rtx)
+typedef struct rtx_def *_function_rtx;
+#define rtx _function_rtx
#endif
struct var_refs_queue
@@ -70,6 +72,7 @@ struct function
int pops_args;
int returns_struct;
int returns_pcc_struct;
+ int returns_pointer;
int needs_context;
int calls_setjmp;
int calls_longjmp;
@@ -77,6 +80,7 @@ struct function
int has_nonlocal_label;
int has_nonlocal_goto;
int contains_functions;
+ int is_thunk;
rtx nonlocal_goto_handler_slot;
rtx nonlocal_goto_stack_level;
tree nonlocal_labels;
@@ -94,10 +98,11 @@ struct function
rtx save_expr_regs;
rtx stack_slot_list;
rtx parm_birth_insn;
- int frame_offset;
+ HOST_WIDE_INT frame_offset;
rtx tail_recursion_label;
rtx tail_recursion_reentry;
rtx internal_arg_pointer;
+ char *cannot_inline;
rtx arg_pointer_save_area;
tree rtl_expr_chain;
rtx last_parm_insn;
@@ -106,9 +111,12 @@ struct function
int function_call_count;
struct temp_slot *temp_slots;
int temp_slot_level;
+ int target_temp_slot_level;
+ int var_temp_slot_level;
/* This slot is initialized as 0 and is added to
during the nested function. */
struct var_refs_queue *fixup_var_refs_queue;
+ CUMULATIVE_ARGS args_info;
/* For stmt.c */
struct nesting *block_stack;
@@ -126,10 +134,20 @@ struct function
int emit_lineno;
struct goto_fixup *goto_fixup_chain;
+ /* For exception handling information. */
+ struct eh_stack ehstack;
+ struct eh_stack catchstack;
+ struct eh_queue ehqueue;
+ rtx catch_clauses;
+ struct label_node *false_label_stack;
+ struct label_node *caught_return_label_stack;
+ tree protect_list;
+ rtx ehc;
+
/* For expr.c. */
+ rtx pending_chain;
int pending_stack_adjust;
int inhibit_defer_pop;
- tree cleanups_this_call;
rtx saveregs_value;
rtx apply_args_value;
rtx forced_labels;
@@ -145,6 +163,7 @@ struct function
int last_linenum;
char *last_filename;
char *regno_pointer_flag;
+ char *regno_pointer_align;
int regno_pointer_flag_length;
rtx *regno_reg_rtx;
@@ -187,6 +206,7 @@ struct function
struct pool_sym **const_rtx_sym_hash_table;
struct pool_constant *first_pool, *last_pool;
int pool_offset;
+ rtx const_double_chain;
};
/* The FUNCTION_DECL for an inline function currently being expanded. */
@@ -213,15 +233,34 @@ extern struct function *outer_function_chain;
the index of that block in the vector. */
extern tree *identify_blocks PROTO((tree, rtx));
+/* Return size needed for stack frame based on slots so far allocated.
+ This size counts from zero. It is not rounded to STACK_BOUNDARY;
+ the caller may have to do that. */
+extern HOST_WIDE_INT get_frame_size PROTO((void));
+
/* These variables hold pointers to functions to
save and restore machine-specific data,
in push_function_context and pop_function_context. */
-extern void (*save_machine_status) ();
-extern void (*restore_machine_status) ();
+extern void (*save_machine_status) PROTO((struct function *));
+extern void (*restore_machine_status) PROTO((struct function *));
-/* Save and restore varasm.c status for a nested function. */
-extern void save_varasm_status PROTO((struct function *));
+/* Save and restore status information for a nested function. */
+extern void save_tree_status PROTO((struct function *, tree));
+extern void restore_tree_status PROTO((struct function *, tree));
+extern void save_varasm_status PROTO((struct function *, tree));
extern void restore_varasm_status PROTO((struct function *));
+extern void save_eh_status PROTO((struct function *));
+extern void restore_eh_status PROTO((struct function *));
+extern void save_stmt_status PROTO((struct function *));
+extern void restore_stmt_status PROTO((struct function *));
+extern void save_expr_status PROTO((struct function *));
+extern void restore_expr_status PROTO((struct function *));
+extern void save_emit_status PROTO((struct function *));
+extern void restore_emit_status PROTO((struct function *));
+extern void save_storage_status PROTO((struct function *));
+extern void restore_storage_status PROTO((struct function *));
+
+extern rtx get_first_block_beg PROTO((void));
#ifdef rtx
#undef rtx
diff --git a/contrib/gcc/future.options b/contrib/gcc/future.options
new file mode 100644
index 0000000..214be80
--- /dev/null
+++ b/contrib/gcc/future.options
@@ -0,0 +1,29 @@
+From: friedman@gnu.ai.mit.edu (Noah Friedman)
+To: roland@gnu.ai.mit.edu (Roland McGrath),
+ rms@gnu.ai.mit.edu (Richard Stallman),
+ jimb@gnu.ai.mit.edu (Jim Blandy),
+ mib@gnu.ai.mit.edu (Michael Bushnell)
+Cc: cgw@sol.acs.unt.edu (chris williams),
+ clc@gnu.ai.mit.edu (Christian Longshore Claiborn)
+Subject: Some gcc options we'd like to see.
+Date: Mon, 28 Jun 93 00:45:09 EST
+Reply-To: friedman@gnu.ai.mit.edu
+
+-Waggravate-return
+-Wcast-spell
+-Wcaste-align
+-Win
+-Wmissing-protons
+-Wredundant-repetitions
+-antsy
+-fbungee-jump
+-fexpensive-operations
+-fextra-strength
+-fjesus-saves
+-fkeep-programmers-inline
+-fno-peeping-toms
+-fruit-roll-ups
+-fshort-enough
+-mno-dialogue
+-pedophile
+-vomit-frame-pointer
diff --git a/contrib/gcc/gansidecl.h b/contrib/gcc/gansidecl.h
new file mode 100644
index 0000000..4f4bb42
--- /dev/null
+++ b/contrib/gcc/gansidecl.h
@@ -0,0 +1,91 @@
+/* ANSI and traditional C compatibility macros.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file mimics some of the support provided by include/ansidecl.h
+ in binutils and gdb releases.
+ ??? Over time the two should be merged into one. */
+
+#ifndef ANSIDECL_H
+#define ANSIDECL_H
+
+/* Add prototype support. */
+#ifndef PROTO
+#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
+#define PROTO(ARGS) ARGS
+#else
+#define PROTO(ARGS) ()
+#endif
+#endif
+
+#ifndef VPROTO
+#ifdef __STDC__
+#define PVPROTO(ARGS) ARGS
+#define VPROTO(ARGS) ARGS
+#define VA_START(va_list,var) va_start(va_list,var)
+#else
+#define PVPROTO(ARGS) ()
+#define VPROTO(ARGS) (va_alist) va_dcl
+#define VA_START(va_list,var) va_start(va_list)
+#endif
+#endif
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif /* ATTRIBUTE_UNUSED */
+
+#ifndef ATTRIBUTE_PRINTF
+#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((format (__printf__, m, n)))
+#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
+#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
+#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
+#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
+#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
+#endif /* ATTRIBUTE_PRINTF */
+
+#ifndef GENERIC_PTR
+#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
+#define GENERIC_PTR void *
+#else
+#define GENERIC_PTR char *
+#endif
+#endif
+
+#ifndef NULL_PTR
+#define NULL_PTR ((GENERIC_PTR) 0)
+#endif
+
+#ifdef __STDC__
+
+#define PTR void *
+
+#else
+
+#define PTR char *
+#ifndef const
+#define const
+#endif
+
+#endif /* ! __STDC__ */
+
+#endif /* ANSIDECL_H */
diff --git a/contrib/gcc/gbl-ctors.h b/contrib/gcc/gbl-ctors.h
index 537df501..86b1c0e 100644
--- a/contrib/gcc/gbl-ctors.h
+++ b/contrib/gcc/gbl-ctors.h
@@ -2,7 +2,7 @@
for getting g++ file-scope static objects constructed. This file
will get included either by libgcc2.c (for systems that don't support
a .init section) or by crtstuff.c (for those that do).
- Copyright (C) 1991, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1995, 1996, 1998 Free Software Foundation, Inc.
Contributed by Ron Guilmette (rfg@segfault.us.com)
This file is part of GNU CC.
@@ -30,16 +30,20 @@ Boston, MA 02111-1307, USA. */
Note that this file should only be compiled with GCC.
*/
+#ifdef NEED_ATEXIT
+#ifndef HAVE_ATEXIT
+#define HAVE_ATEXIT 1 /* Take it from libgcc2.c */
+#endif
+#endif
+
#ifdef HAVE_ATEXIT
-#ifdef WINNT
+#if defined (WINNT) || defined (NEED_ATEXIT)
extern int atexit (void (*) (void));
-#else
-extern void atexit (void (*) (void));
#endif
#define ON_EXIT(FUNC,ARG) atexit ((FUNC))
#else
#ifdef sun
-extern void on_exit (void*, void*);
+extern int on_exit (void *, void *); /* The man page says it returns int. */
#define ON_EXIT(FUNC,ARG) on_exit ((FUNC), (ARG))
#endif
#endif
@@ -56,7 +60,7 @@ extern func_ptr __DTOR_LIST__[];
/* Declare the routine which need to get invoked at program exit time. */
-extern void __do_global_dtors ();
+extern void __do_global_dtors (void);
/* Define a macro with the code which needs to be executed at program
start-up time. This macro is used in two places in crtstuff.c (for
@@ -79,7 +83,7 @@ extern void __do_global_dtors ();
do { \
unsigned long nptrs = (unsigned long) __CTOR_LIST__[0]; \
unsigned i; \
- if (nptrs == -1) \
+ if (nptrs == (unsigned long)-1) \
for (nptrs = 0; __CTOR_LIST__[nptrs + 1] != 0; nptrs++); \
for (i = nptrs; i >= 1; i--) \
__CTOR_LIST__[i] (); \
diff --git a/contrib/gcc/gcc.1 b/contrib/gcc/gcc.1
index e422b39..c0cf44a 100644
--- a/contrib/gcc/gcc.1
+++ b/contrib/gcc/gcc.1
@@ -20,10 +20,10 @@
.if n .sp
.if t .sp 0.4
..
-.Id $Id: gcc.1,v 1.4 1993/10/13 23:19:12 pesch Exp $
+.Id $Id: gcc.1,v 1.8 1998/08/29 10:37:47 law Exp $
.TH GCC 1 "\*(Dt" "GNU Tools" "GNU Tools"
.SH NAME
-gcc, g++ \- GNU project C and C++ Compiler (v2.7)
+gcc, g++ \- GNU project C and C++ Compiler (egcs-1.1.2)
.SH SYNOPSIS
.B gcc
.RI "[ " option " | " filename " ].\|.\|."
@@ -157,6 +157,10 @@ in the following sections.
\-fexternal\-templates
\-fno\-asm
\-fno\-builtin
+\-fhosted
+\-fno\-hosted
+\-ffreestanding
+\-fno\-freestanding
\-fno\-strict\-prototype
\-fsigned\-bitfields
\-fsigned\-char
@@ -186,7 +190,11 @@ in the following sections.
\-Wformat
.RI \-Wid\-clash\- len
\-Wimplicit
+\-Wimplicit\-int
+\-Wimplicit\-function\-declaration
\-Winline
+\-Wlong\-long
+\-Wmain
\-Wmissing\-prototypes
\-Wmissing\-declarations
\-Wnested\-externs
@@ -255,6 +263,7 @@ in the following sections.
\-funroll\-loops
\-O
\-O2
+\-O3
.TP
.B Preprocessor Options
.RI \-A assertion
@@ -793,6 +802,20 @@ The `\|\c
\& from
being builtin functions.
.TP
+.B \-fhosted
+Compile for a hosted environment; this implies the `\|\c
+.B \-fbuiltin\c
+\&\|' option, and implies that suspicious declarations of
+.B main\c
+\& should be warned about.
+.TP
+.B \-ffreestanding
+Compile for a freestanding environment; this implies the `\|\c
+.B \-fno-builtin\c
+\&\|' option, and implies that
+.B main\c
+\& has no special requirements.
+.TP
.B \-fno\-strict\-prototype
Treat a function declaration with no arguments, such as `\|\c
.B int foo
@@ -1698,8 +1721,24 @@ An unsigned value is compared against zero with `\|\c
\&\|'.
.PP
.TP
+.B \-Wimplicit-int
+Warn whenever a declaration does not specify a type.
+.TP
+.B \-Wimplicit-function-declaration
+Warn whenever a function is used before being declared.
+.TP
.B \-Wimplicit
-Warn whenever a function or parameter is implicitly declared.
+Same as -Wimplicit-int and -Wimplicit-function-declaration.
+.TP
+.B \-Wmain
+Warn if the
+.B main
+function is declared or defined with a suspicious type.
+Typically, it is a function with external linkage, returning
+.B int\c
+\&, and
+taking zero or two arguments.
+
.TP
.B \-Wreturn\-type
Warn whenever a function is defined with a return-type that defaults
@@ -1966,6 +2005,20 @@ Warn if an \c
.B \-Wenum\-clash
Warn about conversion between different enumeration types (C++ only).
.TP
+.B \-Wlong-long
+Warn if
+.B long long \c
+type is used. This is default. To inhibit
+the warning messages, use flag `\|\c
+.B \-Wno\-long\-long\c
+\&\|'. Flags `\|\c
+.B \-W\-long\-long\c
+\&\|' and `\|\c
+.B \-Wno\-long\-long\c
+\&\|' are taken into account only when flag `\|\c
+.B \-pedantic\c
+\&\|' is used.
+.TP
.B \-Woverloaded\-virtual
(C++ only.)
In a derived class, the definitions of virtual functions must match
@@ -2125,6 +2178,25 @@ Eventually GNU \c
.B gprof\c
\& should be extended to process this data.
.TP
+.B \-ax
+Generate extra code to read basic block profiling parameters from
+file `bb.in' and write profiling results to file `bb.out'.
+`bb.in' contains a list of functions. Whenever a function on the list
+is entered, profiling is turned on. When the outmost function is left,
+profiling is turned off. If a function name is prefixed with `-'
+the function is excluded from profiling. If a function name is not
+unique it can be disambiguated by writing
+`/path/filename.d:functionname'. `bb.out' will list some available
+filenames.
+Four function names have a special meaning:
+`__bb_jumps__' will cause jump frequencies to be written to `bb.out'.
+`__bb_trace__' will cause the sequence of basic blocks to be piped
+into `gzip' and written to file `bbtrace.gz'.
+`__bb_hidecall__' will cause call instructions to be excluded from
+the trace.
+`__bb_showret__' will cause return instructions to be included in
+the trace.
+.TP
.BI "\-d" "letters"
Says to make debugging dumps during compilation at times specified by
.I letters\c
@@ -3490,7 +3562,7 @@ be compiled with the same
value.
.TP
.B \-nocpp
-Tell the MIPS assembler to not run it's preprocessor over user
+Tell the MIPS assembler to not run its preprocessor over user
assembler files (with a `\|\c
.B .s\c
\&\|' suffix) when assembling them.
@@ -3942,7 +4014,7 @@ three-way choice.
.BI "\-fcall\-used\-" "reg"
Treat the register named \c
.I reg\c
-\& as an allocatable register that is
+\& as an allocable register that is
clobbered by function calls. It may be allocated for temporaries or
variables that do not live across a call. Functions compiled this way
will not save and restore the register \c
@@ -3959,7 +4031,7 @@ three-way choice.
.BI "\-fcall\-saved\-" "reg"
Treat the register named \c
.I reg\c
-\& as an allocatable register saved by
+\& as an allocable register saved by
functions. It may be allocated even for temporaries or variables that
live across a call. Functions compiled this way will save and restore
the register \c
diff --git a/contrib/gcc/gcc.c b/contrib/gcc/gcc.c
index fe7de5b..06a688f 100644
--- a/contrib/gcc/gcc.c
+++ b/contrib/gcc/gcc.c
@@ -1,5 +1,5 @@
/* Compiler driver program that can handle many languages.
- Copyright (C) 1987, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -31,37 +31,32 @@ CC recognizes how to compile each input file by suffixes in the file names.
Once it knows which kind of compilation to perform, the procedure for
compilation is specified by a string called a "spec". */
-#include <sys/types.h>
-#include <ctype.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <errno.h>
-
-#ifndef _WIN32
-#include <sys/file.h> /* May get R_OK, etc. on some systems. */
-#else
-#include <process.h>
-int __spawnv ();
-int __spawnvp ();
-#endif
-
#include "config.h"
-#include "obstack.h"
+
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
-#include <stdio.h>
+#include "system.h"
+#include <signal.h>
+#include <sys/stat.h>
-/* Include multi-lib information. */
-#include "multilib.h"
+#include "gansidecl.h"
+#include "obstack.h"
-#ifndef R_OK
-#define R_OK 4
-#define W_OK 2
-#define X_OK 1
-#endif
+
+/* ??? Need to find a GCC header to put these in. */
+extern int pexecute PROTO ((const char *, char * const *, const char *,
+ const char *, char **, char **, int));
+extern int pwait PROTO ((int, int *, int));
+extern char *update_path PROTO((char *, char *));
+extern void set_std_prefix PROTO((char *, int));
+/* Flag arguments to pexecute. */
+#define PEXECUTE_FIRST 1
+#define PEXECUTE_LAST 2
+#define PEXECUTE_SEARCH 4
+#define PEXECUTE_VERBOSE 8
#ifndef WIFSIGNALED
#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
@@ -76,62 +71,14 @@ int __spawnvp ();
#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
#endif
-/* Add prototype support. */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
-#ifndef VPROTO
-#ifdef __STDC__
-#define PVPROTO(ARGS) ARGS
-#define VPROTO(ARGS) ARGS
-#define VA_START(va_list,var) va_start(va_list,var)
-#else
-#define PVPROTO(ARGS) ()
-#define VPROTO(ARGS) (va_alist) va_dcl
-#define VA_START(va_list,var) va_start(va_list)
-#endif
-#endif
-
-/* Define a generic NULL if one hasn't already been defined. */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/* Define O_RDONLY if the system hasn't defined it for us. */
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
-
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
-#endif
-#endif
-
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
+#ifdef VMS
+#define exit __posix_exit
#endif
#ifdef USG
#define vfork fork
#endif /* USG */
-/* On MSDOS, write temp files in current dir
- because there's no place else we can expect to use. */
-#ifdef __MSDOS__
-#ifndef P_tmpdir
-#define P_tmpdir "."
-#endif
-#endif
-
/* Test if something is a normal file. */
#ifndef S_ISREG
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
@@ -143,11 +90,13 @@ int __spawnvp ();
#endif
/* By default there is no special suffix for executables. */
-#ifndef EXECUTABLE_SUFFIX
+#ifdef EXECUTABLE_SUFFIX
+#define HAVE_EXECUTABLE_SUFFIX
+#else
#define EXECUTABLE_SUFFIX ""
#endif
-/* By default, the suffix for object files is ".o". */
+/* By default, the suffix for object files is ".o". */
#ifdef OBJECT_SUFFIX
#define HAVE_OBJECT_SUFFIX
#else
@@ -168,25 +117,15 @@ static char dir_separator_str[] = {DIR_SEPARATOR, 0};
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern char *getenv ();
-
-#ifndef errno
-extern int errno;
+#ifndef GET_ENVIRONMENT
+#define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ENV_VALUE = getenv (ENV_NAME)
#endif
-extern int sys_nerr;
-#ifndef HAVE_STRERROR
-#if defined(bsd4_4)
-extern const char *const sys_errlist[];
-#else
-extern char *sys_errlist[];
-#endif
-#else
-extern char *strerror();
-#endif
+extern char *my_strerror PROTO((int));
-extern int execv (), execvp ();
+#ifndef HAVE_KILL
+#define kill(p,s) raise(s)
+#endif
/* If a stage of compilation returns an exit status >= 1,
compilation of that file ceases. */
@@ -203,7 +142,7 @@ static int print_search_dirs;
static char *print_file_name = NULL;
-/* As print_file_name, but search for executable file. */
+/* As print_file_name, but search for executable file. */
static char *print_prog_name = NULL;
@@ -217,6 +156,11 @@ static int print_multi_directory;
static int print_multi_lib;
+/* Flag saying to print the command line options understood by gcc and its
+ sub-processes. */
+
+static int print_help_list;
+
/* Flag indicating whether we should print the command and arguments */
static int verbose_flag;
@@ -242,9 +186,9 @@ static char *spec_machine = DEFAULT_TARGET_MACHINE;
When -b is used, the value comes from the `specs' file. */
#ifdef CROSS_COMPILE
-static int cross_compile = 1;
+static char *cross_compile = "1";
#else
-static int cross_compile = 0;
+static char *cross_compile = "0";
#endif
/* The number of errors that have occurred; the link phase will not be
@@ -267,54 +211,57 @@ extern char *version_string;
/* Forward declaration for prototypes. */
struct path_prefix;
+static void init_spec PROTO((void));
+static void read_specs PROTO((char *, int));
static void set_spec PROTO((char *, char *));
-static struct compiler *lookup_compiler PROTO((char *, int, char *));
+static struct compiler *lookup_compiler PROTO((char *, size_t, char *));
static char *build_search_list PROTO((struct path_prefix *, char *, int));
static void putenv_from_prefixes PROTO((struct path_prefix *, char *));
static char *find_a_file PROTO((struct path_prefix *, char *, int));
-static void add_prefix PROTO((struct path_prefix *, char *, int, int, int *));
+static void add_prefix PROTO((struct path_prefix *, char *, char *,
+ int, int, int *));
static char *skip_whitespace PROTO((char *));
static void record_temp_file PROTO((char *, int, int));
static void delete_if_ordinary PROTO((char *));
static void delete_temp_files PROTO((void));
static void delete_failure_queue PROTO((void));
static void clear_failure_queue PROTO((void));
-static char *choose_temp_base_try PROTO((char *, char *));
-static void choose_temp_base PROTO((void));
static int check_live_switch PROTO((int, int));
static char *handle_braces PROTO((char *));
static char *save_string PROTO((char *, int));
-static char *concat PROTO((char *, char *));
-static char *concat3 PROTO((char *, char *, char *));
-static char *concat4 PROTO((char *, char *, char *, char *));
-static char *concat6 PROTO((char *, char *, char *, char *, char *, \
- char *));
-static int do_spec PROTO((char *));
+static char *concat PVPROTO((char *, ...));
+extern int do_spec PROTO((char *));
static int do_spec_1 PROTO((char *, int, char *));
static char *find_file PROTO((char *));
static int is_directory PROTO((char *, char *, int));
static void validate_switches PROTO((char *));
static void validate_all_switches PROTO((void));
-static void give_switch PROTO((int, int));
+static void give_switch PROTO((int, int, int));
static int used_arg PROTO((char *, int));
static int default_arg PROTO((char *, int));
static void set_multilib_dir PROTO((void));
static void print_multilib_info PROTO((void));
static void pfatal_with_name PROTO((char *));
static void perror_with_name PROTO((char *));
-static void perror_exec PROTO((char *));
-#ifdef HAVE_VPRINTF
+static void pfatal_pexecute PROTO((char *, char *));
static void fatal PVPROTO((char *, ...));
static void error PVPROTO((char *, ...));
-#else
-/* We must not provide any prototype here, even if ANSI C. */
-static void fatal PROTO(());
-static void error PROTO(());
-#endif
+static void display_help PROTO((void));
void fancy_abort ();
char *xmalloc ();
char *xrealloc ();
+
+#ifdef LANG_SPECIFIC_DRIVER
+/* Called before processing to change/add/remove arguments. */
+extern void lang_specific_driver PROTO ((void (*) PVPROTO((char *, ...)), int *, char ***, int *));
+
+/* Called before linking. Returns 0 on success and -1 on failure. */
+extern int lang_specific_pre_link ();
+
+/* Number of extra output files that lang_specific_pre_link may generate. */
+extern int lang_specific_extra_outfiles;
+#endif
/* Specs are strings containing lines, each of which (if not blank)
is made up of a program name, and arguments separated by spaces.
@@ -334,12 +281,30 @@ or with constant text in a single argument.
%b substitute the basename of the input file being processed.
This is the substring up to (and not including) the last period
and not including the directory.
- %g substitute the temporary-file-name-base. This is a string chosen
- once per compilation. Different temporary file names are made by
- concatenation of constant strings on the end, as in `%g.s'.
- %g also has the same effect of %d.
- %u like %g, but make the temporary file name unique.
- %U returns the last file name generated with %u.
+ %gSUFFIX
+ substitute a file name that has suffix SUFFIX and is chosen
+ once per compilation, and mark the argument a la %d. To reduce
+ exposure to denial-of-service attacks, the file name is now
+ chosen in a way that is hard to predict even when previously
+ chosen file names are known. For example, `%g.s ... %g.o ... %g.s'
+ might turn into `ccUVUUAU.s ccXYAXZ12.o ccUVUUAU.s'. SUFFIX matches
+ the regexp "[.A-Za-z]*" or the special string "%O", which is
+ treated exactly as if %O had been pre-processed. Previously, %g
+ was simply substituted with a file name chosen once per compilation,
+ without regard to any appended suffix (which was therefore treated
+ just like ordinary text), making such attacks more likely to succeed.
+ %uSUFFIX
+ like %g, but generates a new temporary file name even if %uSUFFIX
+ was already seen.
+ %USUFFIX
+ substitutes the last file name generated with %uSUFFIX, generating a
+ new one if there is no such last file name. In the absence of any
+ %uSUFFIX, this is just like %gSUFFIX, except they don't share
+ the same suffix "space", so `%g.s ... %U.s ... %g.s ... %U.s'
+ would involve the generation of two distinct file names, one
+ for each `%g.s' and another for each `%U.s'. Previously, %U was
+ simply substituted with a file name chosen for the previous %u,
+ without regard to any appended suffix.
%d marks the argument containing or following the %d as a
temporary file name, so that that file will be deleted if CC exits
successfully. Unlike %g, this contributes no text to the argument.
@@ -356,7 +321,13 @@ or with constant text in a single argument.
Input files whose names have no recognized suffix are not compiled
at all, but they are included among the output files, so they will
be linked.
- %O substitutes the suffix for object files.
+ %O substitutes the suffix for object files. Note that this is
+ handled specially when it immediately follows %g, %u, or %U,
+ because of the need for those to form complete file names. The
+ handling is such that %O is treated exactly as if it had already
+ been substituted, except that %g, %u, and %U do not currently
+ support additional SUFFIX characters following %O as they would
+ following, for example, `.o'.
%p substitutes the standard macro predefinitions for the
current target machine. Use this when running cpp.
%P like %p, but puts `__' before and after the name of each macro.
@@ -380,7 +351,7 @@ or with constant text in a single argument.
This allows config.h to specify part of the spec for running as.
%A process ASM_FINAL_SPEC as a spec. A capital A is actually
used here. This can be used to run a post-processor after the
- assembler has done it's job.
+ assembler has done its job.
%D Dump out a -L option for each directory in startfile_prefixes.
If multilib_dir is set, extra entries are generated with it affixed.
%l process LINK_SPEC as a spec.
@@ -404,6 +375,7 @@ or with constant text in a single argument.
arguments. CC considers `-o foo' as being one switch whose
name starts with `o'. %{o*} would substitute this text,
including the space; thus, two arguments would be generated.
+ %{^S*} likewise, but don't put a blank between a switch and any args.
%{S*:X} substitutes X if one or more switches whose names start with -S are
specified to CC. Note that the tail part of the -S option
(i.e. the part matched by the `*') will be substituted for each
@@ -414,6 +386,8 @@ or with constant text in a single argument.
%{|!S:X} like %{!S:X}, but if there is an S switch, substitute `-'.
%{.S:X} substitutes X, but only if processing a file with suffix S.
%{!.S:X} substitutes X, but only if NOT processing a file with suffix S.
+ %{S|P:X} substitutes X if either -S or -P was given to CC. This may be
+ combined with ! and . as above binding stronger than the OR.
%(Spec) processes a specification defined in a specs file as *Spec:
%[Spec] as above, but put __ around -D arguments
@@ -427,8 +401,9 @@ constructs. If another value of -O or the negated form of a -f, -m, or
value is ignored, except with {S*} where S is just one letter; this
passes all matching options.
-The character | is used to indicate that a command should be piped to
-the following command, but only if -pipe is specified.
+The character | at the beginning of the predicate text is used to indicate
+that a command should be piped to the following command, but only if -pipe
+is specified.
Note that it is built into CC which switches take arguments and which
do not. You might think it would be useful to generalize this to
@@ -490,9 +465,9 @@ proper position among the other output files. */
#ifndef LIBGCC_SPEC
#if defined(LINK_LIBGCC_SPECIAL) || defined(LINK_LIBGCC_SPECIAL_1)
/* Have gcc do the search for libgcc.a. */
-#define LIBGCC_SPEC "%{!shared:libgcc.a%s}"
+#define LIBGCC_SPEC "libgcc.a%s"
#else
-#define LIBGCC_SPEC "%{!shared:-lgcc}"
+#define LIBGCC_SPEC "-lgcc"
#endif
#endif
@@ -502,8 +477,8 @@ proper position among the other output files. */
"%{!shared:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}"
#endif
-/* config.h can define SWITCHES_NEED_SPACES to control passing -o and -L.
- Make the string nonempty to require spaces there. */
+/* config.h can define SWITCHES_NEED_SPACES to control which options
+ require spaces between the option and the argument. */
#ifndef SWITCHES_NEED_SPACES
#define SWITCHES_NEED_SPACES ""
#endif
@@ -524,11 +499,8 @@ proper position among the other output files. */
#endif
#endif
-/* MULTILIB_SELECT comes from multilib.h. It gives a
- string interpreted by set_multilib_dir to select a library
- subdirectory based on the compiler options. */
-#ifndef MULTILIB_SELECT
-#define MULTILIB_SELECT ". ;"
+#ifndef LINKER_NAME
+#define LINKER_NAME "collect2"
#endif
static char *cpp_spec = CPP_SPEC;
@@ -544,16 +516,43 @@ static char *libgcc_spec = LIBGCC_SPEC;
static char *endfile_spec = ENDFILE_SPEC;
static char *startfile_spec = STARTFILE_SPEC;
static char *switches_need_spaces = SWITCHES_NEED_SPACES;
-static char *multilib_select = MULTILIB_SELECT;
+static char *linker_name_spec = LINKER_NAME;
+
+/* Some compilers have limits on line lengths, and the multilib_select
+ and/or multilib_matches strings can be very long, so we build them at
+ run time. */
+static struct obstack multilib_obstack;
+static char *multilib_select;
+static char *multilib_matches;
+static char *multilib_defaults;
+#include "multilib.h"
+
+/* Check whether a particular argument is a default argument. */
+
+#ifndef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "" }
+#endif
+
+static char *multilib_defaults_raw[] = MULTILIB_DEFAULTS;
+
+struct user_specs {
+ struct user_specs *next;
+ char *filename;
+};
+
+static struct user_specs *user_specs_head, *user_specs_tail;
/* This defines which switch letters take arguments. */
-#ifndef SWITCH_TAKES_ARG
-#define SWITCH_TAKES_ARG(CHAR) \
+#define DEFAULT_SWITCH_TAKES_ARG(CHAR) \
((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
|| (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
|| (CHAR) == 'I' || (CHAR) == 'm' || (CHAR) == 'x' \
- || (CHAR) == 'L' || (CHAR) == 'A')
+ || (CHAR) == 'L' || (CHAR) == 'A' || (CHAR) == 'V' \
+ || (CHAR) == 'B' || (CHAR) == 'b')
+
+#ifndef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
#endif
/* This defines which multi-letter switches take arguments. */
@@ -564,12 +563,24 @@ static char *multilib_select = MULTILIB_SELECT;
|| !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
|| !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
|| !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
- || !strcmp (STR, "isystem"))
+ || !strcmp (STR, "isystem") || !strcmp (STR, "specs"))
#ifndef WORD_SWITCH_TAKES_ARG
#define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
#endif
+
+#ifdef HAVE_EXECUTABLE_SUFFIX
+/* This defines which switches stop a full compilation. */
+#define DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR) \
+ ((CHAR) == 'c' || (CHAR) == 'S')
+
+#ifndef SWITCH_CURTAILS_COMPILATION
+#define SWITCH_CURTAILS_COMPILATION(CHAR) \
+ DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR)
+#endif
+#endif
+
/* Record the mapping from file suffixes for compilation specs. */
struct compiler
@@ -600,54 +611,105 @@ static int n_compilers;
static struct compiler default_compilers[] =
{
- {".c", "@c"},
+ /* Add lists of suffixes of known languages here. If those languages
+ were not present when we built the driver, we will hit these copies
+ and be given a more meaningful error than "file not used since
+ linking is not done". */
+ {".cc", {"#C++"}}, {".cxx", {"#C++"}}, {".cpp", {"#C++"}}, {".c++", {"#C++"}},
+ {".C", {"#C++"}}, {".ads", {"#Ada"}}, {".adb", {"#Ada"}}, {".ada", {"#Ada"}},
+ {".f", {"#Fortran"}}, {".for", {"#Fortran"}}, {".F", {"#Fortran"}},
+ {".fpp", {"#Fortran"}},
+ {".p", {"#Pascal"}}, {".pas", {"#Pascal"}},
+ /* Next come the entries for C. */
+ {".c", {"@c"}},
{"@c",
- "cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ {
+#if USE_CPPLIB
+ "%{E|M|MM:cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ %{C:%{!E:%eGNU C does not support -C without using -E}}\
+ %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
+ -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
+ %{ansi:-trigraphs -D__STRICT_ANSI__}\
+ %{!undef:%{!ansi:%p} %P} %{trigraphs} \
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
+ %{traditional-cpp:-traditional}\
+ %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
+ %i %{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}}\n}\
+ %{!E:%{!M:%{!MM:cc1 %i %1 \
+ -lang-c%{ansi:89} %{nostdinc*} %{A*} %{I*} %I\
+ %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a*}\
+ %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
+ -undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
+ %{ansi:-trigraphs -D__STRICT_ANSI__}\
+ %{!undef:%{!ansi:%p} %P} %{trigraphs} \
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{H} %C %{D*} %{U*} %{i*} %Z\
+ %{ftraditional:-traditional}\
+ %{traditional-cpp:-traditional}\
+ %{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
+ %{aux-info*}\
+ %{--help:--help} \
+ %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
+ %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
+ %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
+ %{!S:as %a %Y\
+ %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
+ %{!pipe:%g.s} %A\n }}}}"
+ }},
+#else /* ! USE_CPPLIB */
+ "cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
-undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
- %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+ %{ansi:-trigraphs -D__STRICT_ANSI__}\
%{!undef:%{!ansi:%p} %P} %{trigraphs} \
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
"%{!M:%{!MM:%{!E:cc1 %{!pipe:%g.i} %1 \
- %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a}\
+ %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a*}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
%{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
%{aux-info*}\
+ %{--help:--help} \
%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %{!pipe:%g.s} %A\n }}}}"},
+ %{!pipe:%g.s} %A\n }}}}"
+ }},
+#endif /* ! USE_CPPLIB */
{"-",
- "%{E:cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ {"%{E:cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
-undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
- %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+ %{ansi:-trigraphs -D__STRICT_ANSI__}\
%{!undef:%{!ansi:%p} %P} %{trigraphs}\
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %W{o*}}\
- %{!E:%e-E required when input is from standard input}"},
- {".m", "@objective-c"},
+ %{!E:%e-E required when input is from standard input}"}},
+ {".m", {"@objective-c"}},
{"@objective-c",
- "cpp -lang-objc %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ {"cpp -lang-objc %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
-undef -D__OBJC__ -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
- %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+ %{ansi:-trigraphs -D__STRICT_ANSI__}\
%{!undef:%{!ansi:%p} %P} %{trigraphs}\
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.i}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
- "%{!M:%{!MM:%{!E:cc1obj %{!pipe:%g.i} %1 \
- %{!Q:-quiet} -dumpbase %b.m %{d*} %{m*} %{a}\
+ "%{!M:%{!MM:%{!E:cc1obj %{!pipe:%g.i} %1 \
+ %{!Q:-quiet} -dumpbase %b.m %{d*} %{m*} %{a*}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi} \
%{traditional} %{v:-version} %{pg:-p} %{p} %{f*} \
-lang-objc %{gen-decls} \
@@ -656,23 +718,24 @@ static struct compiler default_compilers[] =
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %{!pipe:%g.s} %A\n }}}}"},
- {".h", "@c-header"},
+ %{!pipe:%g.s} %A\n }}}}"}},
+ {".h", {"@c-header"}},
{"@c-header",
- "%{!E:%eCompilation of header file requested} \
+ {"%{!E:%eCompilation of header file requested} \
cpp %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
-undef -D__GNUC__=%v1 -D__GNUC_MINOR__=%v2\
- %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+ %{ansi:-trigraphs -D__STRICT_ANSI__}\
%{!undef:%{!ansi:%p} %P} %{trigraphs}\
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
- %i %W{o*}"},
- {".i", "@cpp-output"},
+ %i %W{o*}"}},
+ {".i", {"@cpp-output"}},
{"@cpp-output",
- "%{!M:%{!MM:%{!E:cc1 %i %1 %{!Q:-quiet} %{d*} %{m*} %{a}\
+ {"%{!M:%{!MM:%{!E:cc1 %i %1 %{!Q:-quiet} %{d*} %{m*} %{a*}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi}\
%{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
%{aux-info*}\
@@ -680,28 +743,29 @@ static struct compiler default_compilers[] =
%{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\
%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %{!pipe:%g.s} %A\n }}}}"},
- {".s", "@assembler"},
+ %{!pipe:%g.s} %A\n }}}}"}},
+ {".s", {"@assembler"}},
{"@assembler",
- "%{!M:%{!MM:%{!E:%{!S:as %a %Y\
+ {"%{!M:%{!MM:%{!E:%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %i %A\n }}}}"},
- {".S", "@assembler-with-cpp"},
+ %i %A\n }}}}"}},
+ {".S", {"@assembler-with-cpp"}},
{"@assembler-with-cpp",
- "cpp -lang-asm %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
+ {"cpp -lang-asm %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
%{C:%{!E:%eGNU C does not support -C without using -E}}\
%{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG} %{trigraphs}\
-undef -$ %{!undef:%p %P} -D__ASSEMBLER__ \
- %c %{O*:%{!O0:-D__OPTIMIZE__}} %{traditional} %{ftraditional:-traditional}\
+ %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
+ %{traditional} %{ftraditional:-traditional}\
%{traditional-cpp:-traditional}\
%{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*} %{U*} %{i*} %Z\
%i %{!M:%{!MM:%{!E:%{!pipe:%g.s}}}}%{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}} |\n",
- "%{!M:%{!MM:%{!E:%{!S:as %a %Y\
+ "%{!M:%{!MM:%{!E:%{!S:as %a %Y\
%{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\
- %{!pipe:%g.s} %A\n }}}}"},
+ %{!pipe:%g.s} %A\n }}}}"}},
#include "specs.h"
/* Mark end of table */
- {0, 0}
+ {0, {0}}
};
/* Number of elements in default_compilers, not counting the terminator. */
@@ -717,26 +781,37 @@ static int n_default_compilers
/* We want %{T*} after %{L*} and %D so that it can be used to specify linker
scripts which exist in user specified directories, or in standard
directories. */
+#ifdef LINK_COMMAND_SPEC
+/* Provide option to override link_command_spec from machine specific
+ configuration files. */
+static char *link_command_spec =
+ LINK_COMMAND_SPEC;
+#else
#ifdef LINK_LIBGCC_SPECIAL
/* Don't generate -L options. */
static char *link_command_spec = "\
%{!fsyntax-only: \
- %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+ %{!c:%{!M:%{!MM:%{!E:%{!S:%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
%{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
%{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
- %{static:} %{L*} %{T*} %o\
+ %{static:} %{L*} %o\
%{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
- %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\n }}}}}}";
+ %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\
+ %{T*}\
+ \n }}}}}}";
#else
/* Use -L. */
static char *link_command_spec = "\
%{!fsyntax-only: \
- %{!c:%{!M:%{!MM:%{!E:%{!S:ld %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
+ %{!c:%{!M:%{!MM:%{!E:%{!S:%(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} \
%{r} %{s} %{t} %{u*} %{x} %{z} %{Z}\
%{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
- %{static:} %{L*} %D %{T*} %o\
+ %{static:} %{L*} %D %o\
%{!nostdlib:%{!nodefaultlibs:%G %L %G}}\
- %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\n }}}}}}";
+ %{!A:%{!nostdlib:%{!nostartfiles:%E}}}\
+ %{T*}\
+ \n }}}}}}";
+#endif
#endif
/* A vector of options to give to the linker.
@@ -786,7 +861,7 @@ struct option_map option_map[] =
{"--comments", "-C", 0},
{"--compile", "-c", 0},
{"--debug", "-g", "oj"},
- {"--define-macro", "-D", "a"},
+ {"--define-macro", "-D", "aj"},
{"--dependencies", "-M", 0},
{"--dump", "-d", "a"},
{"--dumpbase", "-dumpbase", "a"},
@@ -798,7 +873,7 @@ struct option_map option_map[] =
{"--imacros", "-imacros", "a"},
{"--include", "-include", "a"},
{"--include-barrier", "-I-", 0},
- {"--include-directory", "-I", "a"},
+ {"--include-directory", "-I", "aj"},
{"--include-directory-after", "-idirafter", "a"},
{"--include-prefix", "-iprefix", "a"},
{"--include-with-prefix", "-iwithprefix", "a"},
@@ -833,6 +908,7 @@ struct option_map option_map[] =
{"--save-temps", "-save-temps", 0},
{"--shared", "-shared", 0},
{"--silent", "-q", 0},
+ {"--specs", "-specs=", "aj"},
{"--static", "-static", 0},
{"--symbolic", "-symbolic", 0},
{"--target", "-b", "a"},
@@ -840,7 +916,7 @@ struct option_map option_map[] =
{"--traditional", "-traditional", 0},
{"--traditional-cpp", "-traditional-cpp", 0},
{"--trigraphs", "-trigraphs", 0},
- {"--undefine-macro", "-U", "a"},
+ {"--undefine-macro", "-U", "aj"},
{"--use-version", "-V", "a"},
{"--user-dependencies", "-MM", 0},
{"--verbose", "-v", 0},
@@ -877,9 +953,9 @@ translate_options (argcp, argvp)
/* Find a mapping that applies to this option. */
for (j = 0; j < sizeof (option_map) / sizeof (option_map[0]); j++)
{
- int optlen = strlen (option_map[j].name);
- int arglen = strlen (argv[i]);
- int complen = arglen > optlen ? optlen : arglen;
+ size_t optlen = strlen (option_map[j].name);
+ size_t arglen = strlen (argv[i]);
+ size_t complen = arglen > optlen ? optlen : arglen;
char *arginfo = option_map[j].arg_info;
if (arginfo == 0)
@@ -955,7 +1031,8 @@ translate_options (argcp, argvp)
/* Store the translation as one argv elt or as two. */
if (arg != 0 && index (arginfo, 'j') != 0)
- newv[newindex++] = concat (option_map[j].equivalent, arg);
+ newv[newindex++] = concat (option_map[j].equivalent, arg,
+ NULL_PTR);
else if (arg != 0)
{
newv[newindex++] = option_map[j].equivalent;
@@ -1015,15 +1092,15 @@ char *
my_strerror(e)
int e;
{
-
#ifdef HAVE_STRERROR
+
return strerror(e);
#else
static char buffer[30];
if (!e)
- return "";
+ return "cannot access";
if (e > 0 && e < sys_nerr)
return sys_errlist[e];
@@ -1033,126 +1110,6 @@ my_strerror(e)
#endif
}
-/* Read compilation specs from a file named FILENAME,
- replacing the default ones.
-
- A suffix which starts with `*' is a definition for
- one of the machine-specific sub-specs. The "suffix" should be
- *asm, *cc1, *cpp, *link, *startfile, *signed_char, etc.
- The corresponding spec is stored in asm_spec, etc.,
- rather than in the `compilers' vector.
-
- Anything invalid in the file is a fatal error. */
-
-static void
-read_specs (filename)
- char *filename;
-{
- int desc;
- int readlen;
- struct stat statbuf;
- char *buffer;
- register char *p;
-
- if (verbose_flag)
- fprintf (stderr, "Reading specs from %s\n", filename);
-
- /* Open and stat the file. */
- desc = open (filename, O_RDONLY, 0);
- if (desc < 0)
- pfatal_with_name (filename);
- if (stat (filename, &statbuf) < 0)
- pfatal_with_name (filename);
-
- /* Read contents of file into BUFFER. */
- buffer = xmalloc ((unsigned) statbuf.st_size + 1);
- readlen = read (desc, buffer, (unsigned) statbuf.st_size);
- if (readlen < 0)
- pfatal_with_name (filename);
- buffer[readlen] = 0;
- close (desc);
-
- /* Scan BUFFER for specs, putting them in the vector. */
- p = buffer;
- while (1)
- {
- char *suffix;
- char *spec;
- char *in, *out, *p1, *p2;
-
- /* Advance P in BUFFER to the next nonblank nocomment line. */
- p = skip_whitespace (p);
- if (*p == 0)
- break;
-
- /* Find the colon that should end the suffix. */
- p1 = p;
- while (*p1 && *p1 != ':' && *p1 != '\n') p1++;
- /* The colon shouldn't be missing. */
- if (*p1 != ':')
- fatal ("specs file malformed after %d characters", p1 - buffer);
- /* Skip back over trailing whitespace. */
- p2 = p1;
- while (p2 > buffer && (p2[-1] == ' ' || p2[-1] == '\t')) p2--;
- /* Copy the suffix to a string. */
- suffix = save_string (p, p2 - p);
- /* Find the next line. */
- p = skip_whitespace (p1 + 1);
- if (p[1] == 0)
- fatal ("specs file malformed after %d characters", p - buffer);
- p1 = p;
- /* Find next blank line. */
- while (*p1 && !(*p1 == '\n' && p1[1] == '\n')) p1++;
- /* Specs end at the blank line and do not include the newline. */
- spec = save_string (p, p1 - p);
- p = p1;
-
- /* Delete backslash-newline sequences from the spec. */
- in = spec;
- out = spec;
- while (*in != 0)
- {
- if (in[0] == '\\' && in[1] == '\n')
- in += 2;
- else if (in[0] == '#')
- {
- while (*in && *in != '\n') in++;
- }
- else
- *out++ = *in++;
- }
- *out = 0;
-
- if (suffix[0] == '*')
- {
- if (! strcmp (suffix, "*link_command"))
- link_command_spec = spec;
- else
- set_spec (suffix + 1, spec);
- }
- else
- {
- /* Add this pair to the vector. */
- compilers
- = ((struct compiler *)
- xrealloc (compilers, (n_compilers + 2) * sizeof (struct compiler)));
- compilers[n_compilers].suffix = suffix;
- bzero ((char *) compilers[n_compilers].spec,
- sizeof compilers[n_compilers].spec);
- compilers[n_compilers].spec[0] = spec;
- n_compilers++;
- bzero ((char *) &compilers[n_compilers],
- sizeof compilers[n_compilers]);
- }
-
- if (*suffix == 0)
- link_command_spec = spec;
- }
-
- if (link_command_spec == 0)
- fatal ("spec file has no spec for linking");
-}
-
static char *
skip_whitespace (p)
char *p;
@@ -1177,23 +1134,101 @@ skip_whitespace (p)
return p;
}
-/* Structure to keep track of the specs that have been defined so far. These
- are accessed using %(specname) or %[specname] in a compiler or link spec. */
+/* Structure to keep track of the specs that have been defined so far.
+ These are accessed using %(specname) or %[specname] in a compiler
+ or link spec. */
struct spec_list
{
- char *name; /* Name of the spec. */
- char *spec; /* The spec itself. */
- struct spec_list *next; /* Next spec in linked list. */
+ /* The following 2 fields must be first */
+ /* to allow EXTRA_SPECS to be initialized */
+ char *name; /* name of the spec. */
+ char *ptr; /* available ptr if no static pointer */
+
+ /* The following fields are not initialized */
+ /* by EXTRA_SPECS */
+ char **ptr_spec; /* pointer to the spec itself. */
+ struct spec_list *next; /* Next spec in linked list. */
+ int name_len; /* length of the name */
+ int alloc_p; /* whether string was allocated */
};
-/* List of specs that have been defined so far. */
+#define INIT_STATIC_SPEC(NAME,PTR) \
+{ NAME, NULL_PTR, PTR, (struct spec_list *)0, sizeof (NAME)-1, 0 }
+
+/* List of statically defined specs */
+static struct spec_list static_specs[] = {
+ INIT_STATIC_SPEC ("asm", &asm_spec),
+ INIT_STATIC_SPEC ("asm_final", &asm_final_spec),
+ INIT_STATIC_SPEC ("cpp", &cpp_spec),
+ INIT_STATIC_SPEC ("cc1", &cc1_spec),
+ INIT_STATIC_SPEC ("cc1plus", &cc1plus_spec),
+ INIT_STATIC_SPEC ("endfile", &endfile_spec),
+ INIT_STATIC_SPEC ("link", &link_spec),
+ INIT_STATIC_SPEC ("lib", &lib_spec),
+ INIT_STATIC_SPEC ("libgcc", &libgcc_spec),
+ INIT_STATIC_SPEC ("startfile", &startfile_spec),
+ INIT_STATIC_SPEC ("switches_need_spaces", &switches_need_spaces),
+ INIT_STATIC_SPEC ("signed_char", &signed_char_spec),
+ INIT_STATIC_SPEC ("predefines", &cpp_predefines),
+ INIT_STATIC_SPEC ("cross_compile", &cross_compile),
+ INIT_STATIC_SPEC ("version", &compiler_version),
+ INIT_STATIC_SPEC ("multilib", &multilib_select),
+ INIT_STATIC_SPEC ("multilib_defaults", &multilib_defaults),
+ INIT_STATIC_SPEC ("multilib_extra", &multilib_extra),
+ INIT_STATIC_SPEC ("multilib_matches", &multilib_matches),
+ INIT_STATIC_SPEC ("linker", &linker_name_spec),
+};
+
+#ifdef EXTRA_SPECS /* additional specs needed */
+static struct spec_list extra_specs[] = { EXTRA_SPECS };
+#endif
+
+/* List of dynamically allocates specs that have been defined so far. */
+
+static struct spec_list *specs = (struct spec_list *)0;
+
+
+/* Initialize the specs lookup routines. */
+
+static void
+init_spec ()
+{
+ struct spec_list *next = (struct spec_list *)0;
+ struct spec_list *sl = (struct spec_list *)0;
+ int i;
+
+ if (specs)
+ return; /* already initialized */
+
+ if (verbose_flag)
+ fprintf (stderr, "Using builtin specs.\n");
+
+#ifdef EXTRA_SPECS
+ for (i = (sizeof (extra_specs) / sizeof (extra_specs[0])) - 1; i >= 0; i--)
+ {
+ sl = &extra_specs[i];
+ sl->next = next;
+ sl->name_len = strlen (sl->name);
+ sl->ptr_spec = &sl->ptr;
+ next = sl;
+ }
+#endif
+
+ for (i = (sizeof (static_specs) / sizeof (static_specs[0])) - 1; i >= 0; i--)
+ {
+ sl = &static_specs[i];
+ sl->next = next;
+ next = sl;
+ }
+
+ specs = sl;
+}
-static struct spec_list *specs = (struct spec_list *) 0;
/* Change the value of spec NAME to SPEC. If SPEC is empty, then the spec is
removed; If the spec starts with a + then SPEC is added to the end of the
- current spec. */
+ current spec. */
static void
set_spec (name, spec)
@@ -1202,10 +1237,26 @@ set_spec (name, spec)
{
struct spec_list *sl;
char *old_spec;
+ int name_len = strlen (name);
+ int i;
+
+ /* If this is the first call, initialize the statically allocated specs */
+ if (!specs)
+ {
+ struct spec_list *next = (struct spec_list *)0;
+ for (i = (sizeof (static_specs) / sizeof (static_specs[0])) - 1;
+ i >= 0; i--)
+ {
+ sl = &static_specs[i];
+ sl->next = next;
+ next = sl;
+ }
+ specs = sl;
+ }
/* See if the spec already exists */
for (sl = specs; sl; sl = sl->next)
- if (strcmp (sl->name, name) == 0)
+ if (name_len == sl->name_len && !strcmp (sl->name, name))
break;
if (!sl)
@@ -1213,50 +1264,29 @@ set_spec (name, spec)
/* Not found - make it */
sl = (struct spec_list *) xmalloc (sizeof (struct spec_list));
sl->name = save_string (name, strlen (name));
- sl->spec = save_string ("", 0);
+ sl->name_len = name_len;
+ sl->ptr_spec = &sl->ptr;
+ sl->alloc_p = 0;
+ *(sl->ptr_spec) = "";
sl->next = specs;
specs = sl;
}
- old_spec = sl->spec;
- if (name && spec[0] == '+' && isspace (spec[1]))
- sl->spec = concat (old_spec, spec + 1);
- else
- sl->spec = save_string (spec, strlen (spec));
-
- if (! strcmp (name, "asm"))
- asm_spec = sl->spec;
- else if (! strcmp (name, "asm_final"))
- asm_final_spec = sl->spec;
- else if (! strcmp (name, "cc1"))
- cc1_spec = sl->spec;
- else if (! strcmp (name, "cc1plus"))
- cc1plus_spec = sl->spec;
- else if (! strcmp (name, "cpp"))
- cpp_spec = sl->spec;
- else if (! strcmp (name, "endfile"))
- endfile_spec = sl->spec;
- else if (! strcmp (name, "lib"))
- lib_spec = sl->spec;
- else if (! strcmp (name, "libgcc"))
- libgcc_spec = sl->spec;
- else if (! strcmp (name, "link"))
- link_spec = sl->spec;
- else if (! strcmp (name, "predefines"))
- cpp_predefines = sl->spec;
- else if (! strcmp (name, "signed_char"))
- signed_char_spec = sl->spec;
- else if (! strcmp (name, "startfile"))
- startfile_spec = sl->spec;
- else if (! strcmp (name, "switches_need_spaces"))
- switches_need_spaces = sl->spec;
- else if (! strcmp (name, "cross_compile"))
- cross_compile = atoi (sl->spec);
- else if (! strcmp (name, "multilib"))
- multilib_select = sl->spec;
+ old_spec = *(sl->ptr_spec);
+ *(sl->ptr_spec) = ((spec[0] == '+' && ISSPACE (spec[1]))
+ ? concat (old_spec, spec + 1, NULL_PTR)
+ : save_string (spec, strlen (spec)));
+
+#ifdef DEBUG_SPECS
+ if (verbose_flag)
+ fprintf (stderr, "Setting spec %s to '%s'\n\n", name, *(sl->ptr_spec));
+#endif
+
/* Free the old spec */
- if (old_spec)
+ if (old_spec && sl->alloc_p)
free (old_spec);
+
+ sl->alloc_p = 1;
}
/* Accumulate a command (program name and args), and run it. */
@@ -1273,8 +1303,15 @@ static int argbuf_length;
static int argbuf_index;
+/* We want this on by default all the time now. */
+#define MKTEMP_EACH_FILE
+
+#ifdef MKTEMP_EACH_FILE
+
+extern char *make_temp_file PROTO((char *));
+
/* This is the list of suffixes and codes (%g/%u/%U) and the associated
- temp file. Used only if MKTEMP_EACH_FILE. */
+ temp file. */
static struct temp_name {
char *suffix; /* suffix associated with the code. */
@@ -1284,6 +1321,10 @@ static struct temp_name {
int filename_length; /* strlen (filename). */
struct temp_name *next;
} *temp_names;
+#else
+extern char *choose_temp_base PROTO((void));
+#endif
+
/* Number of commands executed so far. */
@@ -1297,12 +1338,12 @@ static int signal_count;
static char *programname;
-/* Structures to keep track of prefixes to try when looking for files. */
+/* Structures to keep track of prefixes to try when looking for files. */
struct prefix_list
{
- char *prefix; /* String to prepend to the path. */
- struct prefix_list *next; /* Next in linked list. */
+ char *prefix; /* String to prepend to the path. */
+ struct prefix_list *next; /* Next in linked list. */
int require_machine_suffix; /* Don't use without machine_suffix. */
/* 2 means try both machine_suffix and just_machine_suffix. */
int *used_flag_ptr; /* 1 if a file was found with this prefix. */
@@ -1315,11 +1356,11 @@ struct path_prefix
char *name; /* Name of this list (used in config stuff) */
};
-/* List of prefixes to try when looking for executables. */
+/* List of prefixes to try when looking for executables. */
static struct path_prefix exec_prefixes = { 0, 0, "exec" };
-/* List of prefixes to try when looking for startup (crt0) files. */
+/* List of prefixes to try when looking for startup (crt0) files. */
static struct path_prefix startfile_prefixes = { 0, 0, "startfile" };
@@ -1405,9 +1446,8 @@ store_arg (arg, delete_always, delete_failure)
int delete_always, delete_failure;
{
if (argbuf_index + 1 == argbuf_length)
- {
- argbuf = (char **) xrealloc (argbuf, (argbuf_length *= 2) * sizeof (char *));
- }
+ argbuf
+ = (char **) xrealloc (argbuf, (argbuf_length *= 2) * sizeof (char *));
argbuf[argbuf_index++] = arg;
argbuf[argbuf_index] = 0;
@@ -1416,6 +1456,262 @@ store_arg (arg, delete_always, delete_failure)
record_temp_file (arg, delete_always, delete_failure);
}
+/* Read compilation specs from a file named FILENAME,
+ replacing the default ones.
+
+ A suffix which starts with `*' is a definition for
+ one of the machine-specific sub-specs. The "suffix" should be
+ *asm, *cc1, *cpp, *link, *startfile, *signed_char, etc.
+ The corresponding spec is stored in asm_spec, etc.,
+ rather than in the `compilers' vector.
+
+ Anything invalid in the file is a fatal error. */
+
+static void
+read_specs (filename, main_p)
+ char *filename;
+ int main_p;
+{
+ int desc;
+ int readlen;
+ struct stat statbuf;
+ char *buffer;
+ register char *p;
+
+ if (verbose_flag)
+ fprintf (stderr, "Reading specs from %s\n", filename);
+
+ /* Open and stat the file. */
+ desc = open (filename, O_RDONLY, 0);
+ if (desc < 0)
+ pfatal_with_name (filename);
+ if (stat (filename, &statbuf) < 0)
+ pfatal_with_name (filename);
+
+ /* Read contents of file into BUFFER. */
+ buffer = xmalloc ((unsigned) statbuf.st_size + 1);
+ readlen = read (desc, buffer, (unsigned) statbuf.st_size);
+ if (readlen < 0)
+ pfatal_with_name (filename);
+ buffer[readlen] = 0;
+ close (desc);
+
+ /* Scan BUFFER for specs, putting them in the vector. */
+ p = buffer;
+ while (1)
+ {
+ char *suffix;
+ char *spec;
+ char *in, *out, *p1, *p2, *p3;
+
+ /* Advance P in BUFFER to the next nonblank nocomment line. */
+ p = skip_whitespace (p);
+ if (*p == 0)
+ break;
+
+ /* Is this a special command that starts with '%'? */
+ /* Don't allow this for the main specs file, since it would
+ encourage people to overwrite it. */
+ if (*p == '%' && !main_p)
+ {
+ p1 = p;
+ while (*p && *p != '\n')
+ p++;
+
+ p++; /* Skip '\n' */
+
+ if (!strncmp (p1, "%include", sizeof ("%include")-1)
+ && (p1[sizeof "%include" - 1] == ' '
+ || p1[sizeof "%include" - 1] == '\t'))
+ {
+ char *new_filename;
+
+ p1 += sizeof ("%include");
+ while (*p1 == ' ' || *p1 == '\t')
+ p1++;
+
+ if (*p1++ != '<' || p[-2] != '>')
+ fatal ("specs %%include syntax malformed after %d characters",
+ p1 - buffer + 1);
+
+ p[-2] = '\0';
+ new_filename = find_a_file (&startfile_prefixes, p1, R_OK);
+ read_specs (new_filename ? new_filename : p1, FALSE);
+ continue;
+ }
+ else if (!strncmp (p1, "%include_noerr", sizeof "%include_noerr" - 1)
+ && (p1[sizeof "%include_noerr" - 1] == ' '
+ || p1[sizeof "%include_noerr" - 1] == '\t'))
+ {
+ char *new_filename;
+
+ p1 += sizeof "%include_noerr";
+ while (*p1 == ' ' || *p1 == '\t') p1++;
+
+ if (*p1++ != '<' || p[-2] != '>')
+ fatal ("specs %%include syntax malformed after %d characters",
+ p1 - buffer + 1);
+
+ p[-2] = '\0';
+ new_filename = find_a_file (&startfile_prefixes, p1, R_OK);
+ if (new_filename)
+ read_specs (new_filename, FALSE);
+ else if (verbose_flag)
+ fprintf (stderr, "Could not find specs file %s\n", p1);
+ continue;
+ }
+ else if (!strncmp (p1, "%rename", sizeof "%rename" - 1)
+ && (p1[sizeof "%rename" - 1] == ' '
+ || p1[sizeof "%rename" - 1] == '\t'))
+ {
+ int name_len;
+ struct spec_list *sl;
+
+ /* Get original name */
+ p1 += sizeof "%rename";
+ while (*p1 == ' ' || *p1 == '\t')
+ p1++;
+
+ if (! ISALPHA (*p1))
+ fatal ("specs %%rename syntax malformed after %d characters",
+ p1 - buffer);
+
+ p2 = p1;
+ while (*p2 && !ISSPACE (*p2))
+ p2++;
+
+ if (*p2 != ' ' && *p2 != '\t')
+ fatal ("specs %%rename syntax malformed after %d characters",
+ p2 - buffer);
+
+ name_len = p2 - p1;
+ *p2++ = '\0';
+ while (*p2 == ' ' || *p2 == '\t')
+ p2++;
+
+ if (! ISALPHA (*p2))
+ fatal ("specs %%rename syntax malformed after %d characters",
+ p2 - buffer);
+
+ /* Get new spec name */
+ p3 = p2;
+ while (*p3 && !ISSPACE (*p3))
+ p3++;
+
+ if (p3 != p-1)
+ fatal ("specs %%rename syntax malformed after %d characters",
+ p3 - buffer);
+ *p3 = '\0';
+
+ for (sl = specs; sl; sl = sl->next)
+ if (name_len == sl->name_len && !strcmp (sl->name, p1))
+ break;
+
+ if (!sl)
+ fatal ("specs %s spec was not found to be renamed", p1);
+
+ if (strcmp (p1, p2) == 0)
+ continue;
+
+ if (verbose_flag)
+ {
+ fprintf (stderr, "rename spec %s to %s\n", p1, p2);
+#ifdef DEBUG_SPECS
+ fprintf (stderr, "spec is '%s'\n\n", *(sl->ptr_spec));
+#endif
+ }
+
+ set_spec (p2, *(sl->ptr_spec));
+ if (sl->alloc_p)
+ free (*(sl->ptr_spec));
+
+ *(sl->ptr_spec) = "";
+ sl->alloc_p = 0;
+ continue;
+ }
+ else
+ fatal ("specs unknown %% command after %d characters",
+ p1 - buffer);
+ }
+
+ /* Find the colon that should end the suffix. */
+ p1 = p;
+ while (*p1 && *p1 != ':' && *p1 != '\n')
+ p1++;
+
+ /* The colon shouldn't be missing. */
+ if (*p1 != ':')
+ fatal ("specs file malformed after %d characters", p1 - buffer);
+
+ /* Skip back over trailing whitespace. */
+ p2 = p1;
+ while (p2 > buffer && (p2[-1] == ' ' || p2[-1] == '\t'))
+ p2--;
+
+ /* Copy the suffix to a string. */
+ suffix = save_string (p, p2 - p);
+ /* Find the next line. */
+ p = skip_whitespace (p1 + 1);
+ if (p[1] == 0)
+ fatal ("specs file malformed after %d characters", p - buffer);
+
+ p1 = p;
+ /* Find next blank line or end of string. */
+ while (*p1 && !(*p1 == '\n' && (p1[1] == '\n' || p1[1] == '\0')))
+ p1++;
+
+ /* Specs end at the blank line and do not include the newline. */
+ spec = save_string (p, p1 - p);
+ p = p1;
+
+ /* Delete backslash-newline sequences from the spec. */
+ in = spec;
+ out = spec;
+ while (*in != 0)
+ {
+ if (in[0] == '\\' && in[1] == '\n')
+ in += 2;
+ else if (in[0] == '#')
+ while (*in && *in != '\n')
+ in++;
+
+ else
+ *out++ = *in++;
+ }
+ *out = 0;
+
+ if (suffix[0] == '*')
+ {
+ if (! strcmp (suffix, "*link_command"))
+ link_command_spec = spec;
+ else
+ set_spec (suffix + 1, spec);
+ }
+ else
+ {
+ /* Add this pair to the vector. */
+ compilers
+ = ((struct compiler *)
+ xrealloc (compilers,
+ (n_compilers + 2) * sizeof (struct compiler)));
+
+ compilers[n_compilers].suffix = suffix;
+ bzero ((char *) compilers[n_compilers].spec,
+ sizeof compilers[n_compilers].spec);
+ compilers[n_compilers].spec[0] = spec;
+ n_compilers++;
+ bzero ((char *) &compilers[n_compilers],
+ sizeof compilers[n_compilers]);
+ }
+
+ if (*suffix == 0)
+ link_command_spec = spec;
+ }
+
+ if (link_command_spec == 0)
+ fatal ("spec file has no spec for linking");
+}
+
/* Record the names of temporary files we tell compilers to write,
and delete them at the end of the run. */
@@ -1427,7 +1723,8 @@ store_arg (arg, delete_always, delete_failure)
This prefix comes from the envvar TMPDIR if it is defined;
otherwise, from the P_tmpdir macro if that is defined;
- otherwise, in /usr/tmp or /tmp. */
+ otherwise, in /usr/tmp or /tmp;
+ or finally the current directory if all else fails. */
static char *temp_filename;
@@ -1470,10 +1767,12 @@ record_temp_file (filename, always_delete, fail_delete)
for (temp = always_delete_queue; temp; temp = temp->next)
if (! strcmp (name, temp->name))
goto already1;
+
temp = (struct temp_file *) xmalloc (sizeof (struct temp_file));
temp->next = always_delete_queue;
temp->name = name;
always_delete_queue = temp;
+
already1:;
}
@@ -1483,10 +1782,12 @@ record_temp_file (filename, always_delete, fail_delete)
for (temp = failure_delete_queue; temp; temp = temp->next)
if (! strcmp (name, temp->name))
goto already2;
+
temp = (struct temp_file *) xmalloc (sizeof (struct temp_file));
temp->next = failure_delete_queue;
temp->name = name;
failure_delete_queue = temp;
+
already2:;
}
}
@@ -1505,7 +1806,9 @@ delete_if_ordinary (name)
fflush (stdout);
i = getchar ();
if (i != '\n')
- while ((c = getchar ()) != '\n' && c != EOF) ;
+ while ((c = getchar ()) != '\n' && c != EOF)
+ ;
+
if (i == 'y' || i == 'Y')
#endif /* DEBUG */
if (stat (name, &st) >= 0 && S_ISREG (st.st_mode))
@@ -1540,65 +1843,7 @@ clear_failure_queue ()
{
failure_delete_queue = 0;
}
-
-/* Compute a string to use as the base of all temporary file names.
- It is substituted for %g. */
-
-static char *
-choose_temp_base_try (try, base)
- char *try;
- char *base;
-{
- char *rv;
- if (base)
- rv = base;
- else if (try == (char *)0)
- rv = 0;
- else if (access (try, R_OK | W_OK) != 0)
- rv = 0;
- else
- rv = try;
- return rv;
-}
-
-static void
-choose_temp_base ()
-{
- char *base = 0;
- int len;
-
- base = choose_temp_base_try (getenv ("TMPDIR"), base);
- base = choose_temp_base_try (getenv ("TMP"), base);
- base = choose_temp_base_try (getenv ("TEMP"), base);
-
-#ifdef P_tmpdir
- base = choose_temp_base_try (P_tmpdir, base);
-#endif
-
- base = choose_temp_base_try (concat4 (dir_separator_str, "usr",
- dir_separator_str, "tmp"),
- base);
- base = choose_temp_base_try (concat (dir_separator_str, "tmp"), base);
-
- /* If all else fails, use the current directory! */
- if (base == (char *)0) base = concat(".", dir_separator_str);
-
- len = strlen (base);
- temp_filename = xmalloc (len + strlen (concat (dir_separator_str,
- "ccXXXXXX")) + 1);
- strcpy (temp_filename, base);
- if (len > 0 && temp_filename[len-1] != '/'
- && temp_filename[len-1] != DIR_SEPARATOR)
- temp_filename[len++] = DIR_SEPARATOR;
- strcpy (temp_filename + len, "ccXXXXXX");
-
- mktemp (temp_filename);
- temp_filename_length = strlen (temp_filename);
- if (temp_filename_length == 0)
- abort ();
-}
-
/* Routine to add variables to the environment. We do this to pass
the pathname of the gcc driver, and the directories search to the
collect2 program, which is being run as ld. This way, we can be
@@ -1679,7 +1924,7 @@ build_search_list (paths, prefix, check_dir_p)
int len = strlen (pprefix->prefix);
if (machine_suffix
- && (!check_dir_p
+ && (! check_dir_p
|| is_directory (pprefix->prefix, machine_suffix, 0)))
{
if (!first_time)
@@ -1692,10 +1937,10 @@ build_search_list (paths, prefix, check_dir_p)
if (just_machine_suffix
&& pprefix->require_machine_suffix == 2
- && (!check_dir_p
+ && (! check_dir_p
|| is_directory (pprefix->prefix, just_machine_suffix, 0)))
{
- if (!first_time)
+ if (! first_time)
obstack_1grow (&collect_obstack, PATH_SEPARATOR);
first_time = FALSE;
@@ -1704,20 +1949,22 @@ build_search_list (paths, prefix, check_dir_p)
just_suffix_len);
}
- if (!pprefix->require_machine_suffix)
+ if (! pprefix->require_machine_suffix)
{
- if (!first_time)
+ if (! first_time)
obstack_1grow (&collect_obstack, PATH_SEPARATOR);
first_time = FALSE;
obstack_grow (&collect_obstack, pprefix->prefix, len);
}
}
+
obstack_1grow (&collect_obstack, '\0');
return obstack_finish (&collect_obstack);
}
-/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect. */
+/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
+ for collect. */
static void
putenv_from_prefixes (paths, env_var)
@@ -1729,7 +1976,7 @@ putenv_from_prefixes (paths, env_var)
/* Search for NAME using the prefix list PREFIXES. MODE is passed to
access to check permissions.
- Return 0 if not found, otherwise return its name, allocated with malloc. */
+ Return 0 if not found, otherwise return its name, allocated with malloc. */
static char *
find_a_file (pprefix, name, mode)
@@ -1749,7 +1996,10 @@ find_a_file (pprefix, name, mode)
/* Determine the filename to execute (special case for absolute paths). */
- if (*name == '/' || *name == DIR_SEPARATOR)
+ if (*name == '/' || *name == DIR_SEPARATOR
+ /* Check for disk name on MS-DOS-based systems. */
+ || (DIR_SEPARATOR == '\\' && name[1] == ':'
+ && (name[2] == DIR_SEPARATOR || name[2] == '/')))
{
if (access (name, mode))
{
@@ -1823,7 +2073,7 @@ find_a_file (pprefix, name, mode)
/* Certain prefixes can't be used without the machine suffix
when the machine or version is explicitly specified. */
- if (!pl->require_machine_suffix)
+ if (! pl->require_machine_suffix)
{
/* Some systems have a suffix for executable files.
So try appending that first. */
@@ -1862,14 +2112,17 @@ find_a_file (pprefix, name, mode)
through this prefix. WARN should point to an int
which will be set to 1 if this entry is used.
+ COMPONENT is the value to be passed to update_path.
+
REQUIRE_MACHINE_SUFFIX is 1 if this prefix can't be used without
the complete value of machine_suffix.
2 means try both machine_suffix and just_machine_suffix. */
static void
-add_prefix (pprefix, prefix, first, require_machine_suffix, warn)
+add_prefix (pprefix, prefix, component, first, require_machine_suffix, warn)
struct path_prefix *pprefix;
char *prefix;
+ char *component;
int first;
int require_machine_suffix;
int *warn;
@@ -1877,7 +2130,7 @@ add_prefix (pprefix, prefix, first, require_machine_suffix, warn)
struct prefix_list *pl, **prev;
int len;
- if (!first && pprefix->plist)
+ if (! first && pprefix->plist)
{
for (pl = pprefix->plist; pl->next; pl = pl->next)
;
@@ -1888,6 +2141,7 @@ add_prefix (pprefix, prefix, first, require_machine_suffix, warn)
/* Keep track of the longest prefix */
+ prefix = update_path (prefix, component);
len = strlen (prefix);
if (len > pprefix->max_len)
pprefix->max_len = len;
@@ -1918,228 +2172,20 @@ unused_prefix_warnings (pprefix)
{
if (pl->used_flag_ptr != 0 && !*pl->used_flag_ptr)
{
- error ("file path prefix `%s' never used",
- pl->prefix);
+ if (pl->require_machine_suffix && machine_suffix)
+ error ("file path prefix `%s%s' never used", pl->prefix,
+ machine_suffix);
+ else
+ error ("file path prefix `%s' never used", pl->prefix);
+
/* Prevent duplicate warnings. */
*pl->used_flag_ptr = 1;
}
- pl = pl->next;
- }
-}
-/* Get rid of all prefixes built up so far in *PLISTP. */
-
-static void
-free_path_prefix (pprefix)
- struct path_prefix *pprefix;
-{
- struct prefix_list *pl = pprefix->plist;
- struct prefix_list *temp;
-
- while (pl)
- {
- temp = pl;
pl = pl->next;
- free (temp->prefix);
- free ((char *) temp);
- }
- pprefix->plist = (struct prefix_list *) 0;
-}
-
-/* stdin file number. */
-#define STDIN_FILE_NO 0
-
-/* stdout file number. */
-#define STDOUT_FILE_NO 1
-
-/* value of `pipe': port index for reading. */
-#define READ_PORT 0
-
-/* value of `pipe': port index for writing. */
-#define WRITE_PORT 1
-
-/* Pipe waiting from last process, to be used as input for the next one.
- Value is STDIN_FILE_NO if no pipe is waiting
- (i.e. the next command is the first of a group). */
-
-static int last_pipe_input;
-
-/* Fork one piped subcommand. FUNC is the system call to use
- (either execv or execvp). ARGV is the arg vector to use.
- NOT_LAST is nonzero if this is not the last subcommand
- (i.e. its output should be piped to the next one.) */
-
-#ifdef __MSDOS__
-
-#include <process.h>
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
-#ifdef __GO32__
- int i = (search_flag ? spawnv : spawnvp) (1, program, argv);
-#else
- char *scmd, *rf;
- FILE *argfile;
- int i, el = search_flag ? 0 : 4;
-
- scmd = (char *)malloc (strlen (program) + strlen (temp_filename) + 6 + el);
- rf = scmd + strlen(program) + 2 + el;
- sprintf (scmd, "%s%s @%s.gp", program,
- (search_flag ? "" : ".exe"), temp_filename);
- argfile = fopen (rf, "w");
- if (argfile == 0)
- pfatal_with_name (rf);
-
- for (i=1; argv[i]; i++)
- {
- char *cp;
- for (cp = argv[i]; *cp; cp++)
- {
- if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
- fputc ('\\', argfile);
- fputc (*cp, argfile);
- }
- fputc ('\n', argfile);
- }
- fclose (argfile);
-
- i = system (scmd);
-
- remove (rf);
-#endif
-
- if (i == -1)
- {
- perror_exec (program);
- return MIN_FATAL_STATUS << 8;
- }
- return i << 8;
-}
-
-#endif
-
-#if !defined(__MSDOS__) && !defined(OS2) && !defined(_WIN32)
-
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
- int (*func)() = (search_flag ? execv : execvp);
- int pid;
- int pdes[2];
- int input_desc = last_pipe_input;
- int output_desc = STDOUT_FILE_NO;
- int retries, sleep_interval;
-
- /* If this isn't the last process, make a pipe for its output,
- and record it as waiting to be the input to the next process. */
-
- if (not_last)
- {
- if (pipe (pdes) < 0)
- pfatal_with_name ("pipe");
- output_desc = pdes[WRITE_PORT];
- last_pipe_input = pdes[READ_PORT];
- }
- else
- last_pipe_input = STDIN_FILE_NO;
-
- /* Fork a subprocess; wait and retry if it fails. */
- sleep_interval = 1;
- for (retries = 0; retries < 4; retries++)
- {
- pid = vfork ();
- if (pid >= 0)
- break;
- sleep (sleep_interval);
- sleep_interval *= 2;
- }
-
- switch (pid)
- {
- case -1:
-#ifdef vfork
- pfatal_with_name ("fork");
-#else
- pfatal_with_name ("vfork");
-#endif
- /* NOTREACHED */
- return 0;
-
- case 0: /* child */
- /* Move the input and output pipes into place, if nec. */
- if (input_desc != STDIN_FILE_NO)
- {
- close (STDIN_FILE_NO);
- dup (input_desc);
- close (input_desc);
- }
- if (output_desc != STDOUT_FILE_NO)
- {
- close (STDOUT_FILE_NO);
- dup (output_desc);
- close (output_desc);
- }
-
- /* Close the parent's descs that aren't wanted here. */
- if (last_pipe_input != STDIN_FILE_NO)
- close (last_pipe_input);
-
- /* Exec the program. */
- (*func) (program, argv);
- perror_exec (program);
- exit (-1);
- /* NOTREACHED */
- return 0;
-
- default:
- /* In the parent, after forking.
- Close the descriptors that we made for this child. */
- if (input_desc != STDIN_FILE_NO)
- close (input_desc);
- if (output_desc != STDOUT_FILE_NO)
- close (output_desc);
-
- /* Return child's process number. */
- return pid;
}
}
-#endif /* not __MSDOS__ and not OS2 and not _WIN32 */
-
-#if defined(OS2)
-
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
- return (search_flag ? spawnv : spawnvp) (1, program, argv);
-}
-#endif /* OS2 */
-
-#if defined(_WIN32)
-
-static int
-pexecute (search_flag, program, argv, not_last)
- int search_flag;
- char *program;
- char *argv[];
- int not_last;
-{
- return (search_flag ? __spawnv : __spawnvp) (1, program, argv);
-}
-#endif /* _WIN32 */
-
/* Execute the command specified by the arguments on the current line of spec.
When using pipes, this includes several piped-together commands
@@ -2178,14 +2224,15 @@ execute ()
commands[0].prog = argbuf[0]; /* first command. */
commands[0].argv = &argbuf[0];
string = find_a_file (&exec_prefixes, commands[0].prog, X_OK);
+
if (string)
commands[0].argv[0] = string;
for (n_commands = 1, i = 0; i < argbuf_index; i++)
if (strcmp (argbuf[i], "|") == 0)
{ /* each command. */
-#ifdef __MSDOS__
- fatal ("-pipe not supported under MS-DOS");
+#if defined (__MSDOS__) || (defined (_WIN32) && defined (__CYGWIN32_)) || defined (OS2) || defined (VMS)
+ fatal ("-pipe not supported");
#endif
argbuf[i] = 0; /* termination of command args. */
commands[n_commands].prog = argbuf[i + 1];
@@ -2202,6 +2249,10 @@ execute ()
if (verbose_flag)
{
+ /* For help listings, put a blank line between sub-processes. */
+ if (print_help_list)
+ fputc ('\n', stderr);
+
/* Print each piped command as a separate line. */
for (i = 0; i < n_commands ; i++)
{
@@ -2221,7 +2272,9 @@ execute ()
fflush (stderr);
i = getchar ();
if (i != '\n')
- while (getchar () != '\n') ;
+ while (getchar () != '\n')
+ ;
+
if (i != 'y' && i != 'Y')
return 0;
#endif /* DEBUG */
@@ -2229,14 +2282,22 @@ execute ()
/* Run each piped subprocess. */
- last_pipe_input = STDIN_FILE_NO;
for (i = 0; i < n_commands; i++)
{
+ char *errmsg_fmt, *errmsg_arg;
char *string = commands[i].argv[0];
- commands[i].pid = pexecute (string != commands[i].prog,
- string, commands[i].argv,
- i + 1 < n_commands);
+ commands[i].pid = pexecute (string, commands[i].argv,
+ programname, temp_filename,
+ &errmsg_fmt, &errmsg_arg,
+ ((i == 0 ? PEXECUTE_FIRST : 0)
+ | (i + 1 == n_commands ? PEXECUTE_LAST : 0)
+ | (string == commands[i].prog
+ ? PEXECUTE_SEARCH : 0)
+ | (verbose_flag ? PEXECUTE_VERBOSE : 0)));
+
+ if (commands[i].pid == -1)
+ pfatal_pexecute (errmsg_fmt, errmsg_arg);
if (string != commands[i].prog)
free (string);
@@ -2259,15 +2320,7 @@ execute ()
int status;
int pid;
-#ifdef __MSDOS__
- status = pid = commands[i].pid;
-#else
-#ifdef _WIN32
- pid = cwait (&status, commands[i].pid, WAIT_CHILD);
-#else
- pid = wait (&status);
-#endif
-#endif
+ pid = pwait (commands[i].pid, &status, 0);
if (pid < 0)
abort ();
@@ -2330,10 +2383,177 @@ static struct infile *infiles;
static int n_infiles;
+/* This counts the number of libraries added by LANG_SPECIFIC_DRIVER, so that
+ we can tell if there were any user supplied any files or libraries. */
+
+static int added_libraries;
+
/* And a vector of corresponding output files is made up later. */
static char **outfiles;
+/* Used to track if none of the -B paths are used. */
+static int warn_B;
+
+/* Used to track if standard path isn't used and -b or -V is specified. */
+static int warn_std;
+
+/* Gives value to pass as "warn" to add_prefix for standard prefixes. */
+static int *warn_std_ptr = 0;
+
+
+#if defined(HAVE_OBJECT_SUFFIX) || defined(HAVE_EXECUTABLE_SUFFIX)
+
+/* Convert NAME to a new name if it is the standard suffix. DO_EXE
+ is true if we should look for an executable suffix as well. */
+
+static char *
+convert_filename (name, do_exe)
+ char *name;
+ int do_exe;
+{
+ int i;
+ int len = strlen (name);
+
+#ifdef HAVE_OBJECT_SUFFIX
+ /* Convert x.o to x.obj if OBJECT_SUFFIX is ".obj". */
+ if (len > 2
+ && name[len - 2] == '.'
+ && name[len - 1] == 'o')
+ {
+ obstack_grow (&obstack, name, len - 2);
+ obstack_grow0 (&obstack, OBJECT_SUFFIX, strlen (OBJECT_SUFFIX));
+ name = obstack_finish (&obstack);
+ }
+#endif
+
+#ifdef HAVE_EXECUTABLE_SUFFIX
+ /* If there is no filetype, make it the executable suffix (which includes
+ the "."). But don't get confused if we have just "-o". */
+ if (! do_exe || EXECUTABLE_SUFFIX[0] == 0 || (len == 2 && name[0] == '-'))
+ return name;
+
+ for (i = len - 1; i >= 0; i--)
+ if (name[i] == '/' || name[i] == DIR_SEPARATOR)
+ break;
+
+ for (i++; i < len; i++)
+ if (name[i] == '.')
+ return name;
+
+ obstack_grow (&obstack, name, len);
+ obstack_grow0 (&obstack, EXECUTABLE_SUFFIX, strlen (EXECUTABLE_SUFFIX));
+ name = obstack_finish (&obstack);
+#endif
+
+ return name;
+}
+#endif
+
+/* Display the command line switches accepted by gcc. */
+static void
+display_help ()
+{
+ printf ("Usage: %s [options] file...\n", programname);
+ printf ("Options:\n");
+
+ printf (" --help Display this information\n");
+ if (! verbose_flag)
+ printf (" (Use '-v --help' to display command line options of sub-processes)\n");
+ printf (" -dumpspecs Display all of the built in spec strings\n");
+ printf (" -dumpversion Display the version of the compiler\n");
+ printf (" -dumpmachine Display the compiler's target processor\n");
+ printf (" -print-search-dirs Display the directories in the compiler's search path\n");
+ printf (" -print-libgcc-file-name Display the name of the compiler's companion library\n");
+ printf (" -print-file-name=<lib> Display the full path to library <lib>\n");
+ printf (" -print-prog-name=<prog> Display the full path to compiler component <prog>\n");
+ printf (" -print-multi-directory Display the root directory for versions of libgcc\n");
+ printf (" -print-multi-lib Display the mapping between command line options and\n");
+ printf (" multiple library search directories\n");
+ printf (" -Wa,<options> Pass comma-separated <options> on to the assembler\n");
+ printf (" -Wp,<options> Pass comma-separated <options> on to the preprocessor\n");
+ printf (" -Wl,<options> Pass comma-separated <options> on to the linker\n");
+ printf (" -Xlinker <arg> Pass <arg> on to the linker\n");
+ printf (" -save-temps Do not delete intermediate files\n");
+ printf (" -pipe Use pipes rather than intermediate files\n");
+ printf (" -specs=<file> Override builtin specs with the contents of <file>\n");
+ printf (" -B <directory> Add <directory> to the compiler's search paths\n");
+ printf (" -b <machine> Run gcc for target <machine>, if installed\n");
+ printf (" -V <version> Run gcc version number <version>, if installed\n");
+ printf (" -v Display the programs invoked by the compiler\n");
+ printf (" -E Preprocess only; do not compile, assemble or link\n");
+ printf (" -S Compile only; do not assemble or link\n");
+ printf (" -c Compile and assemble, but do not link\n");
+ printf (" -o <file> Place the output into <file>\n");
+ printf (" -x <language> Specify the language of the following input files\n");
+ printf (" Permissable languages include: c c++ assembler none\n");
+ printf (" 'none' means revert to the default behaviour of\n");
+ printf (" guessing the language based on the file's extension\n");
+
+ printf ("\nOptions starting with -g, -f, -m, -O or -W are automatically passed on to\n");
+ printf ("the various sub-processes invoked by %s. In order to pass other options\n",
+ programname);
+ printf ("on to these processes the -W<letter> options must be used.\n");
+
+ /* The rest of the options are displayed by invocations of the various
+ sub-processes. */
+}
+
+static void
+add_preprocessor_option (option, len)
+ char * option;
+ int len;
+{
+ n_preprocessor_options++;
+
+ if (! preprocessor_options)
+ preprocessor_options
+ = (char **) xmalloc (n_preprocessor_options * sizeof (char **));
+ else
+ preprocessor_options
+ = (char **) xrealloc (preprocessor_options,
+ n_preprocessor_options * sizeof (char **));
+
+ preprocessor_options [n_preprocessor_options - 1] = save_string (option, len);
+}
+
+static void
+add_assembler_option (option, len)
+ char * option;
+ int len;
+{
+ n_assembler_options++;
+
+ if (! assembler_options)
+ assembler_options
+ = (char **) xmalloc (n_assembler_options * sizeof (char **));
+ else
+ assembler_options
+ = (char **) xrealloc (assembler_options,
+ n_assembler_options * sizeof (char **));
+
+ assembler_options [n_assembler_options - 1] = save_string (option, len);
+}
+
+static void
+add_linker_option (option, len)
+ char * option;
+ int len;
+{
+ n_linker_options++;
+
+ if (! linker_options)
+ linker_options
+ = (char **) xmalloc (n_linker_options * sizeof (char **));
+ else
+ linker_options
+ = (char **) xrealloc (linker_options,
+ n_linker_options * sizeof (char **));
+
+ linker_options [n_linker_options - 1] = save_string (option, len);
+}
+
+
/* Create the vector `switches' and its contents.
Store its length in `n_switches'. */
@@ -2346,11 +2566,15 @@ process_command (argc, argv)
char *temp;
char *spec_lang = 0;
int last_language_n_infiles;
+ int have_c = 0;
+ int have_o = 0;
+ int lang_n_infiles = 0;
- gcc_exec_prefix = getenv ("GCC_EXEC_PREFIX");
+ GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX");
n_switches = 0;
n_infiles = 0;
+ added_libraries = 0;
/* Figure compiler version from version string. */
@@ -2368,14 +2592,28 @@ process_command (argc, argv)
if (gcc_exec_prefix)
{
- add_prefix (&exec_prefixes, gcc_exec_prefix, 0, 0, NULL_PTR);
- add_prefix (&startfile_prefixes, gcc_exec_prefix, 0, 0, NULL_PTR);
+ int len = strlen (gcc_exec_prefix);
+ if (len > sizeof ("/lib/gcc-lib/")-1
+ && (gcc_exec_prefix[len-1] == '/'
+ || gcc_exec_prefix[len-1] == DIR_SEPARATOR))
+ {
+ temp = gcc_exec_prefix + len - sizeof ("/lib/gcc-lib/") + 1;
+ if ((*temp == '/' || *temp == DIR_SEPARATOR)
+ && strncmp (temp+1, "lib", 3) == 0
+ && (temp[4] == '/' || temp[4] == DIR_SEPARATOR)
+ && strncmp (temp+5, "gcc-lib", 7) == 0)
+ len -= sizeof ("/lib/gcc-lib/") - 1;
+ }
+
+ set_std_prefix (gcc_exec_prefix, len);
+ add_prefix (&exec_prefixes, gcc_exec_prefix, "GCC", 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, gcc_exec_prefix, "GCC", 0, 0, NULL_PTR);
}
/* COMPILER_PATH and LIBRARY_PATH have values
that are lists of directory names with colons. */
- temp = getenv ("COMPILER_PATH");
+ GET_ENVIRONMENT (temp, "COMPILER_PATH");
if (temp)
{
char *startp, *endp;
@@ -2388,7 +2626,7 @@ process_command (argc, argv)
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
- strcpy (nstore, concat (".", dir_separator_str));
+ strcpy (nstore, concat (".", dir_separator_str, NULL_PTR));
else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
{
nstore[endp-startp] = DIR_SEPARATOR;
@@ -2396,7 +2634,10 @@ process_command (argc, argv)
}
else
nstore[endp-startp] = 0;
- add_prefix (&exec_prefixes, nstore, 0, 0, NULL_PTR);
+ add_prefix (&exec_prefixes, nstore, 0, 0, 0, NULL_PTR);
+ add_prefix (&include_prefixes,
+ concat (nstore, "include", NULL_PTR),
+ 0, 0, 0, NULL_PTR);
if (*endp == 0)
break;
endp = startp = endp + 1;
@@ -2406,8 +2647,8 @@ process_command (argc, argv)
}
}
- temp = getenv ("LIBRARY_PATH");
- if (temp && ! cross_compile)
+ GET_ENVIRONMENT (temp, "LIBRARY_PATH");
+ if (temp && *cross_compile == '0')
{
char *startp, *endp;
char *nstore = (char *) alloca (strlen (temp) + 3);
@@ -2419,7 +2660,7 @@ process_command (argc, argv)
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
- strcpy (nstore, concat (".", dir_separator_str));
+ strcpy (nstore, concat (".", dir_separator_str, NULL_PTR));
else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
{
nstore[endp-startp] = DIR_SEPARATOR;
@@ -2427,7 +2668,8 @@ process_command (argc, argv)
}
else
nstore[endp-startp] = 0;
- add_prefix (&startfile_prefixes, nstore, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, nstore, NULL_PTR,
+ 0, 0, NULL_PTR);
if (*endp == 0)
break;
endp = startp = endp + 1;
@@ -2438,8 +2680,8 @@ process_command (argc, argv)
}
/* Use LPATH like LIBRARY_PATH (for the CMU build program). */
- temp = getenv ("LPATH");
- if (temp && ! cross_compile)
+ GET_ENVIRONMENT (temp, "LPATH");
+ if (temp && *cross_compile == '0')
{
char *startp, *endp;
char *nstore = (char *) alloca (strlen (temp) + 3);
@@ -2451,7 +2693,7 @@ process_command (argc, argv)
{
strncpy (nstore, startp, endp-startp);
if (endp == startp)
- strcpy (nstore, concat (".", dir_separator_str));
+ strcpy (nstore, concat (".", dir_separator_str, NULL_PTR));
else if (endp[-1] != '/' && endp[-1] != DIR_SEPARATOR)
{
nstore[endp-startp] = DIR_SEPARATOR;
@@ -2459,7 +2701,8 @@ process_command (argc, argv)
}
else
nstore[endp-startp] = 0;
- add_prefix (&startfile_prefixes, nstore, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, nstore, NULL_PTR,
+ 0, 0, NULL_PTR);
if (*endp == 0)
break;
endp = startp = endp + 1;
@@ -2472,6 +2715,11 @@ process_command (argc, argv)
/* Convert new-style -- options to old-style. */
translate_options (&argc, &argv);
+#ifdef LANG_SPECIFIC_DRIVER
+ /* Do language-specific adjustment/addition of flags. */
+ lang_specific_driver (fatal, &argc, &argv, &added_libraries);
+#endif
+
/* Scan argv twice. Here, the first time, just count how many switches
there will be in their vector, and how many input files in theirs.
Here we also parse the switches that cc itself uses (e.g. -v). */
@@ -2480,27 +2728,15 @@ process_command (argc, argv)
{
if (! strcmp (argv[i], "-dumpspecs"))
{
- printf ("*asm:\n%s\n\n", asm_spec);
- printf ("*asm_final:\n%s\n\n", asm_final_spec);
- printf ("*cpp:\n%s\n\n", cpp_spec);
- printf ("*cc1:\n%s\n\n", cc1_spec);
- printf ("*cc1plus:\n%s\n\n", cc1plus_spec);
- printf ("*endfile:\n%s\n\n", endfile_spec);
- printf ("*link:\n%s\n\n", link_spec);
- printf ("*lib:\n%s\n\n", lib_spec);
- printf ("*libgcc:\n%s\n\n", libgcc_spec);
- printf ("*startfile:\n%s\n\n", startfile_spec);
- printf ("*switches_need_spaces:\n%s\n\n", switches_need_spaces);
- printf ("*signed_char:\n%s\n\n", signed_char_spec);
- printf ("*predefines:\n%s\n\n", cpp_predefines);
- printf ("*cross_compile:\n%d\n\n", cross_compile);
- printf ("*multilib:\n%s\n\n", multilib_select);
-
+ struct spec_list *sl;
+ init_spec ();
+ for (sl = specs; sl; sl = sl->next)
+ printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec));
exit (0);
}
else if (! strcmp (argv[i], "-dumpversion"))
{
- printf ("%s\n", version_string);
+ printf ("%s\n", spec_version);
exit (0);
}
else if (! strcmp (argv[i], "-dumpmachine"))
@@ -2508,6 +2744,19 @@ process_command (argc, argv)
printf ("%s\n", spec_machine);
exit (0);
}
+ else if (strcmp (argv[i], "-fhelp") == 0)
+ {
+ /* translate_options () has turned --help into -fhelp. */
+ print_help_list = 1;
+
+ /* We will be passing a dummy file on to the sub-processes. */
+ n_infiles++;
+ n_switches++;
+
+ add_preprocessor_option ("--help", 6);
+ add_assembler_option ("--help", 6);
+ add_linker_option ("--help", 6);
+ }
else if (! strcmp (argv[i], "-print-search-dirs"))
print_search_dirs = 1;
else if (! strcmp (argv[i], "-print-libgcc-file-name"))
@@ -2525,60 +2774,34 @@ process_command (argc, argv)
int prev, j;
/* Pass the rest of this option to the assembler. */
- n_assembler_options++;
- if (!assembler_options)
- assembler_options
- = (char **) xmalloc (n_assembler_options * sizeof (char **));
- else
- assembler_options
- = (char **) xrealloc (assembler_options,
- n_assembler_options * sizeof (char **));
-
/* Split the argument at commas. */
prev = 4;
for (j = 4; argv[i][j]; j++)
if (argv[i][j] == ',')
{
- assembler_options[n_assembler_options - 1]
- = save_string (argv[i] + prev, j - prev);
- n_assembler_options++;
- assembler_options
- = (char **) xrealloc (assembler_options,
- n_assembler_options * sizeof (char **));
+ add_assembler_option (argv[i] + prev, j - prev);
prev = j + 1;
}
+
/* Record the part after the last comma. */
- assembler_options[n_assembler_options - 1] = argv[i] + prev;
+ add_assembler_option (argv[i] + prev, j - prev);
}
else if (! strncmp (argv[i], "-Wp,", 4))
{
int prev, j;
/* Pass the rest of this option to the preprocessor. */
- n_preprocessor_options++;
- if (!preprocessor_options)
- preprocessor_options
- = (char **) xmalloc (n_preprocessor_options * sizeof (char **));
- else
- preprocessor_options
- = (char **) xrealloc (preprocessor_options,
- n_preprocessor_options * sizeof (char **));
-
/* Split the argument at commas. */
prev = 4;
for (j = 4; argv[i][j]; j++)
if (argv[i][j] == ',')
{
- preprocessor_options[n_preprocessor_options - 1]
- = save_string (argv[i] + prev, j - prev);
- n_preprocessor_options++;
- preprocessor_options
- = (char **) xrealloc (preprocessor_options,
- n_preprocessor_options * sizeof (char **));
+ add_preprocessor_option (argv[i] + prev, j - prev);
prev = j + 1;
}
+
/* Record the part after the last comma. */
- preprocessor_options[n_preprocessor_options - 1] = argv[i] + prev;
+ add_preprocessor_option (argv[i] + prev, j - prev);
}
else if (argv[i][0] == '+' && argv[i][1] == 'e')
/* The +e options to the C++ front-end. */
@@ -2600,6 +2823,41 @@ process_command (argc, argv)
}
else if (strncmp (argv[i], "-l", 2) == 0)
n_infiles++;
+ else if (strcmp (argv[i], "-save-temps") == 0)
+ {
+ save_temps_flag = 1;
+ n_switches++;
+ }
+ else if (strcmp (argv[i], "-specs") == 0)
+ {
+ struct user_specs *user = (struct user_specs *)
+ xmalloc (sizeof (struct user_specs));
+ if (++i >= argc)
+ fatal ("argument to `-specs' is missing");
+
+ user->next = (struct user_specs *)0;
+ user->filename = argv[i];
+ if (user_specs_tail)
+ user_specs_tail->next = user;
+ else
+ user_specs_head = user;
+ user_specs_tail = user;
+ }
+ else if (strncmp (argv[i], "-specs=", 7) == 0)
+ {
+ struct user_specs *user = (struct user_specs *)
+ xmalloc (sizeof (struct user_specs));
+ if (strlen (argv[i]) == 7)
+ fatal ("argument to `-specs=' is missing");
+
+ user->next = (struct user_specs *)0;
+ user->filename = argv[i]+7;
+ if (user_specs_tail)
+ user_specs_tail->next = user;
+ else
+ user_specs_head = user;
+ user_specs_tail = user;
+ }
else if (argv[i][0] == '-' && argv[i][1] != 0)
{
register char *p = &argv[i][1];
@@ -2608,17 +2866,19 @@ process_command (argc, argv)
switch (c)
{
case 'b':
+ n_switches++;
if (p[1] == 0 && i + 1 == argc)
fatal ("argument to `-b' is missing");
if (p[1] == 0)
spec_machine = argv[++i];
else
spec_machine = p + 1;
+
+ warn_std_ptr = &warn_std;
break;
case 'B':
{
- int *temp = (int *) xmalloc (sizeof (int));
char *value;
if (p[1] == 0 && i + 1 == argc)
fatal ("argument to `-B' is missing");
@@ -2626,10 +2886,12 @@ process_command (argc, argv)
value = argv[++i];
else
value = p + 1;
- add_prefix (&exec_prefixes, value, 1, 0, temp);
- add_prefix (&startfile_prefixes, value, 1, 0, temp);
- add_prefix (&include_prefixes, concat (value, "include"),
- 1, 0, 0);
+ add_prefix (&exec_prefixes, value, NULL_PTR, 1, 0, &warn_B);
+ add_prefix (&startfile_prefixes, value, NULL_PTR,
+ 1, 0, &warn_B);
+ add_prefix (&include_prefixes, concat (value, "include",
+ NULL_PTR),
+ NULL_PTR, 1, 0, NULL_PTR);
/* As a kludge, if the arg is "[foo/]stageN/", just add
"[foo/]include" to the include prefix. */
@@ -2640,21 +2902,24 @@ process_command (argc, argv)
&& (value[len - 8] == '/'
|| value[len - 8] == DIR_SEPARATOR)))
&& strncmp (value + len - 7, "stage", 5) == 0
- && isdigit (value[len - 2])
+ && ISDIGIT (value[len - 2])
&& (value[len - 1] == '/'
|| value[len - 1] == DIR_SEPARATOR))
{
if (len == 7)
- add_prefix (&include_prefixes, "include", 1, 0, 0);
+ add_prefix (&include_prefixes, "include", NULL_PTR,
+ 1, 0, NULL_PTR);
else
{
char *string = xmalloc (len + 1);
strncpy (string, value, len-7);
- strcat (string, "include");
- add_prefix (&include_prefixes, string, 1, 0, 0);
+ strcpy (string+len-7, "include");
+ add_prefix (&include_prefixes, string, NULL_PTR,
+ 1, 0, NULL_PTR);
}
}
}
+ n_switches++;
}
break;
@@ -2668,6 +2933,7 @@ process_command (argc, argv)
break;
case 'V':
+ n_switches++;
if (p[1] == 0 && i + 1 == argc)
fatal ("argument to `-V' is missing");
if (p[1] == 0)
@@ -2675,16 +2941,90 @@ process_command (argc, argv)
else
spec_version = p + 1;
compiler_version = spec_version;
+ warn_std_ptr = &warn_std;
+
+ /* Validate the version number. Use the same checks
+ done when inserting it into a spec.
+
+ The format of the version string is
+ ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)? */
+ {
+ char *v = compiler_version;
+
+ /* Ignore leading non-digits. i.e. "foo-" in "foo-2.7.2". */
+ while (! ISDIGIT (*v))
+ v++;
+
+ if (v > compiler_version && v[-1] != '-')
+ fatal ("invalid version number format");
+
+ /* Set V after the first period. */
+ while (ISDIGIT (*v))
+ v++;
+
+ if (*v != '.')
+ fatal ("invalid version number format");
+
+ v++;
+ while (ISDIGIT (*v))
+ v++;
+
+ if (*v != 0 && *v != ' ' && *v != '.' && *v != '-')
+ fatal ("invalid version number format");
+ }
break;
- case 's':
- if (!strcmp (p, "save-temps"))
+ case 'S':
+ case 'c':
+ if (p[1] == 0)
{
- save_temps_flag = 1;
+ have_c = 1;
n_switches++;
break;
}
+ goto normal_switch;
+
+ case 'o':
+ have_o = 1;
+#if defined(HAVE_EXECUTABLE_SUFFIX)
+ if (! have_c)
+ {
+ int skip;
+
+ /* Forward scan, just in case -S or -c is specified
+ after -o. */
+ int j = i + 1;
+ if (p[1] == 0)
+ ++j;
+ while (j < argc)
+ {
+ if (argv[j][0] == '-')
+ {
+ if (SWITCH_CURTAILS_COMPILATION (argv[j][1])
+ && argv[j][2] == 0)
+ {
+ have_c = 1;
+ break;
+ }
+ else if (skip = SWITCH_TAKES_ARG (argv[j][1]))
+ j += skip - (argv[j][2] != 0);
+ else if (skip = WORD_SWITCH_TAKES_ARG (argv[j] + 1))
+ j += skip;
+ }
+ j++;
+ }
+ }
+#endif
+#if defined(HAVE_EXECUTABLE_SUFFIX) || defined(HAVE_OBJECT_SUFFIX)
+ if (p[1] == 0)
+ argv[i+1] = convert_filename (argv[i+1], ! have_c);
+ else
+ argv[i] = convert_filename (argv[i], ! have_c);
+#endif
+ goto normal_switch;
+
default:
+ normal_switch:
n_switches++;
if (SWITCH_TAKES_ARG (c) > (p[1] != 0))
@@ -2694,9 +3034,15 @@ process_command (argc, argv)
}
}
else
- n_infiles++;
+ {
+ n_infiles++;
+ lang_n_infiles++;
+ }
}
+ if (have_c && have_o && lang_n_infiles > 1)
+ fatal ("cannot specify -o with -c or -S and multiple compilations");
+
/* Set up the search paths before we go looking for config files. */
/* These come before the md prefixes so that we will find gcc's subcommands
@@ -2704,15 +3050,19 @@ process_command (argc, argv)
/* Use 2 as fourth arg meaning try just the machine as a suffix,
as well as trying the machine and the version. */
#ifndef OS2
- add_prefix (&exec_prefixes, standard_exec_prefix, 0, 2, NULL_PTR);
- add_prefix (&exec_prefixes, standard_exec_prefix_1, 0, 2, NULL_PTR);
+ add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS",
+ 0, 2, warn_std_ptr);
+ add_prefix (&exec_prefixes, standard_exec_prefix_1, "BINUTILS",
+ 0, 2, warn_std_ptr);
#endif
- add_prefix (&startfile_prefixes, standard_exec_prefix, 0, 1, NULL_PTR);
- add_prefix (&startfile_prefixes, standard_exec_prefix_1, 0, 1, NULL_PTR);
+ add_prefix (&startfile_prefixes, standard_exec_prefix, "BINUTILS",
+ 0, 1, warn_std_ptr);
+ add_prefix (&startfile_prefixes, standard_exec_prefix_1, "BINUTILS",
+ 0, 1, warn_std_ptr);
- tooldir_prefix = concat3 (tooldir_base_prefix, spec_machine,
- dir_separator_str);
+ tooldir_prefix = concat (tooldir_base_prefix, spec_machine,
+ dir_separator_str, NULL_PTR);
/* If tooldir is relative, base it on exec_prefixes. A relative
tooldir lets us move the installed tree as a unit.
@@ -2726,30 +3076,30 @@ process_command (argc, argv)
if (gcc_exec_prefix)
{
char *gcc_exec_tooldir_prefix
- = concat6 (gcc_exec_prefix, spec_machine, dir_separator_str,
- spec_version, dir_separator_str, tooldir_prefix);
+ = concat (gcc_exec_prefix, spec_machine, dir_separator_str,
+ spec_version, dir_separator_str, tooldir_prefix, NULL_PTR);
add_prefix (&exec_prefixes,
- concat3 (gcc_exec_tooldir_prefix, "bin",
- dir_separator_str),
- 0, 0, NULL_PTR);
+ concat (gcc_exec_tooldir_prefix, "bin",
+ dir_separator_str, NULL_PTR),
+ NULL_PTR, 0, 0, NULL_PTR);
add_prefix (&startfile_prefixes,
- concat3 (gcc_exec_tooldir_prefix, "lib",
- dir_separator_str),
- 0, 0, NULL_PTR);
+ concat (gcc_exec_tooldir_prefix, "lib",
+ dir_separator_str, NULL_PTR),
+ NULL_PTR, 0, 0, NULL_PTR);
}
- tooldir_prefix = concat6 (standard_exec_prefix, spec_machine,
- dir_separator_str, spec_version,
- dir_separator_str, tooldir_prefix);
+ tooldir_prefix = concat (standard_exec_prefix, spec_machine,
+ dir_separator_str, spec_version,
+ dir_separator_str, tooldir_prefix, NULL_PTR);
}
add_prefix (&exec_prefixes,
- concat3 (tooldir_prefix, "bin", dir_separator_str),
- 0, 0, NULL_PTR);
+ concat (tooldir_prefix, "bin", dir_separator_str, NULL_PTR),
+ "BINUTILS", 0, 0, NULL_PTR);
add_prefix (&startfile_prefixes,
- concat3 (tooldir_prefix, "lib", dir_separator_str),
- 0, 0, NULL_PTR);
+ concat (tooldir_prefix, "lib", dir_separator_str, NULL_PTR),
+ "BINUTILS", 0, 0, NULL_PTR);
/* More prefixes are enabled in main, after we read the specs file
and determine whether this is cross-compilation or not. */
@@ -2787,6 +3137,25 @@ process_command (argc, argv)
;
else if (! strcmp (argv[i], "-print-multi-directory"))
;
+ else if (strcmp (argv[i], "-fhelp") == 0)
+ {
+ if (verbose_flag)
+ {
+ /* Create a dummy input file, so that we can pass --help on to
+ the various sub-processes. */
+ infiles[n_infiles].language = "c";
+ infiles[n_infiles++].name = "help-dummy";
+
+ /* Preserve the --help switch so that it can be caught by the
+ cc1 spec string. */
+ switches[n_switches].part1 = "--help";
+ switches[n_switches].args = 0;
+ switches[n_switches].live_cond = 0;
+ switches[n_switches].valid = 0;
+
+ n_switches++;
+ }
+ }
else if (argv[i][0] == '+' && argv[i][1] == 'e')
{
/* Compensate for the +e options to the C++ front-end;
@@ -2808,37 +3177,37 @@ process_command (argc, argv)
for (j = 4; argv[i][j]; j++)
if (argv[i][j] == ',')
{
- infiles[n_infiles].language = 0;
+ infiles[n_infiles].language = "*";
infiles[n_infiles++].name
= save_string (argv[i] + prev, j - prev);
prev = j + 1;
}
/* Record the part after the last comma. */
- infiles[n_infiles].language = 0;
+ infiles[n_infiles].language = "*";
infiles[n_infiles++].name = argv[i] + prev;
}
else if (strcmp (argv[i], "-Xlinker") == 0)
{
- infiles[n_infiles].language = 0;
+ infiles[n_infiles].language = "*";
infiles[n_infiles++].name = argv[++i];
}
else if (strncmp (argv[i], "-l", 2) == 0)
{
- infiles[n_infiles].language = 0;
+ infiles[n_infiles].language = "*";
infiles[n_infiles++].name = argv[i];
}
+ else if (strcmp (argv[i], "-specs") == 0)
+ i++;
+ else if (strncmp (argv[i], "-specs=", 7) == 0)
+ ;
+ /* -save-temps overrides -pipe, so that temp files are produced */
+ else if (save_temps_flag && strcmp (argv[i], "-pipe") == 0)
+ error ("Warning: -pipe ignored since -save-temps specified");
else if (argv[i][0] == '-' && argv[i][1] != 0)
{
register char *p = &argv[i][1];
register int c = *p;
- if (c == 'B' || c == 'b' || c == 'V')
- {
- /* Skip a separate arg, if any. */
- if (p[1] == 0)
- i++;
- continue;
- }
if (c == 'x')
{
if (p[1] == 0 && i + 1 == argc)
@@ -2878,11 +3247,15 @@ process_command (argc, argv)
/* Null-terminate the vector. */
switches[n_switches].args[j] = 0;
}
- else if (*switches_need_spaces != 0 && (c == 'o' || c == 'L'))
+ else if (index (switches_need_spaces, c))
{
- /* On some systems, ld cannot handle -o or -L without space.
- So split the -o or -L from its argument. */
- switches[n_switches].part1 = (c == 'o' ? "o" : "L");
+ /* On some systems, ld cannot handle some options without
+ a space. So split the option from its argument. */
+ char *part1 = (char *) xmalloc (2);
+ part1[0] = c;
+ part1[1] = '\0';
+
+ switches[n_switches].part1 = part1;
switches[n_switches].args = (char **) xmalloc (2 * sizeof (char *));
switches[n_switches].args[0] = xmalloc (strlen (p));
strcpy (switches[n_switches].args[0], &p[1]);
@@ -2896,25 +3269,18 @@ process_command (argc, argv)
/* This is always valid, since gcc.c itself understands it. */
if (!strcmp (p, "save-temps"))
switches[n_switches].valid = 1;
+ else
+ {
+ char ch = switches[n_switches].part1[0];
+ if (ch == 'V' || ch == 'b' || ch == 'B')
+ switches[n_switches].valid = 1;
+ }
n_switches++;
}
else
{
#ifdef HAVE_OBJECT_SUFFIX
- /* Convert x.o to x.obj if OBJECT_SUFFIX is ".obj". */
- if (strlen (argv[i]) > 2
- && argv[i][strlen (argv[i]) - 2] == '.'
- && argv[i][strlen (argv[i]) - 1] == 'o')
- {
- int j;
-
- for (j = 0; j < strlen (argv[i]) - 2; j++)
- obstack_1grow (&obstack, argv[i][j]);
-
- obstack_grow (&obstack, OBJECT_SUFFIX, strlen (OBJECT_SUFFIX));
- obstack_1grow (&obstack, 0);
- argv[i] = obstack_finish (&obstack);
- }
+ argv[i] = convert_filename (argv[i], 0);
#endif
if (strcmp (argv[i], "-") != 0 && access (argv[i], R_OK) < 0)
@@ -2946,9 +3312,9 @@ process_command (argc, argv)
sans all directory names, and basename_length is the number
of characters starting there excluding the suffix .c or whatever. */
-static char *input_filename;
+char *input_filename;
static int input_file_number;
-static int input_filename_length;
+size_t input_filename_length;
static int basename_length;
static char *input_basename;
static char *input_suffix;
@@ -2978,7 +3344,7 @@ static int input_from_pipe;
/* Process the spec SPEC and run the commands specified therein.
Returns 0 if the spec is successfully processed; -1 if failed. */
-static int
+int
do_spec (spec)
char *spec;
{
@@ -3031,7 +3397,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
char *string;
int value;
- while (c = *p++)
+ while ((c = *p++))
/* If substituting a switch, treat all chars like letters.
Otherwise, NL, SPC, TAB and % are special. */
switch (inswitch ? 'a' : c)
@@ -3144,7 +3510,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
case 'D':
{
struct prefix_list *pl = startfile_prefixes.plist;
- int bufsize = 100;
+ size_t bufsize = 100;
char *buffer = (char *) xmalloc (bufsize);
int idx;
@@ -3279,16 +3645,30 @@ do_spec_1 (spec, inswitch, soft_matched_part)
That matters for the names of object files.
In 2.4, do something about that. */
struct temp_name *t;
+ int suffix_length;
char *suffix = p;
- while (*p == '.' || isalpha (*p)
- || (p[0] == '%' && p[1] == 'O'))
- p++;
+
+ if (p[0] == '%' && p[1] == 'O')
+ {
+ p += 2;
+ /* We don't support extra suffix characters after %O. */
+ if (*p == '.' || ISALPHA (*p))
+ abort ();
+ suffix = OBJECT_SUFFIX;
+ suffix_length = strlen (OBJECT_SUFFIX);
+ }
+ else
+ {
+ while (*p == '.' || ISALPHA (*p))
+ p++;
+ suffix_length = p - suffix;
+ }
/* See if we already have an association of %g/%u/%U and
suffix. */
for (t = temp_names; t; t = t->next)
- if (t->length == p - suffix
- && strncmp (t->suffix, suffix, p - suffix) == 0
+ if (t->length == suffix_length
+ && strncmp (t->suffix, suffix, suffix_length) == 0
&& t->unique == (c != 'g'))
break;
@@ -3301,10 +3681,11 @@ do_spec_1 (spec, inswitch, soft_matched_part)
t->next = temp_names;
temp_names = t;
}
- t->length = p - suffix;
- t->suffix = save_string (suffix, p - suffix);
+ t->length = suffix_length;
+ t->suffix = save_string (suffix, suffix_length);
t->unique = (c != 'g');
- choose_temp_base ();
+ temp_filename = make_temp_file (t->suffix);
+ temp_filename_length = strlen (temp_filename);
t->filename = temp_filename;
t->filename_length = temp_filename_length;
}
@@ -3377,7 +3758,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
case 'W':
{
- int index = argbuf_index;
+ int cur_index = argbuf_index;
/* Handle the {...} following the %W. */
if (*p != '{')
abort ();
@@ -3386,7 +3767,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
return -1;
/* If any args were output, mark the last one for deletion
on failure. */
- if (argbuf_index != index)
+ if (argbuf_index != cur_index)
record_temp_file (argbuf[argbuf_index - 1], 0, 1);
break;
}
@@ -3413,16 +3794,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
}
/* This option is new; add it. */
- n_linker_options++;
- if (!linker_options)
- linker_options
- = (char **) xmalloc (n_linker_options * sizeof (char **));
- else
- linker_options
- = (char **) xrealloc (linker_options,
- n_linker_options * sizeof (char **));
-
- linker_options[n_linker_options - 1] = string;
+ add_linker_option (string, strlen (string));
}
break;
@@ -3568,7 +3940,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
*x++ = *y++;
if (*y != '_'
- || (*(y+1) != '_' && ! isupper (*(y+1))))
+ || (*(y+1) != '_' && ! ISUPPER (*(y+1))))
{
/* Stick __ at front of macro name. */
*x++ = '_';
@@ -3610,7 +3982,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
y += 2;
if (*y != '_'
- || (*(y+1) != '_' && ! isupper (*(y+1))))
+ || (*(y+1) != '_' && ! ISUPPER (*(y+1))))
{
/* Stick -D__ at front of macro name. */
*x++ = '-';
@@ -3694,23 +4066,28 @@ do_spec_1 (spec, inswitch, soft_matched_part)
to add and use their own specs.
%[...] modifies -D options the way %P does;
%(...) uses the spec unmodified. */
- case '(':
case '[':
+ error ("Warning: use of obsolete %%[ operator in specs");
+ case '(':
{
char *name = p;
struct spec_list *sl;
int len;
/* The string after the S/P is the name of a spec that is to be
- processed. */
+ processed. */
while (*p && *p != ')' && *p != ']')
p++;
/* See if it's in the list */
for (len = p - name, sl = specs; sl; sl = sl->next)
- if (strncmp (sl->name, name, len) == 0 && !sl->name[len])
+ if (sl->name_len == len && !strncmp (sl->name, name, len))
{
- name = sl->spec;
+ name = *(sl->ptr_spec);
+#ifdef DEBUG_SPECS
+ fprintf (stderr, "Processing spec %c%s%c, which is '%s'\n",
+ c, sl->name, (c == '(') ? ')' : ']', name);
+#endif
break;
}
@@ -3727,6 +4104,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
char *x = (char *) alloca (strlen (name) * 2 + 1);
char *buf = x;
char *y = name;
+ int flag = 0;
/* Copy all of NAME into BUF, but put __ after
every -D and at the end of each arg, */
@@ -3739,16 +4117,18 @@ do_spec_1 (spec, inswitch, soft_matched_part)
*x++ = '_';
*x++ = '_';
y += 2;
+ flag = 1;
+ continue;
}
- else if (*y == ' ' || *y == 0)
+ else if (flag && (*y == ' ' || *y == '\t' || *y == '='
+ || *y == '}' || *y == 0))
{
*x++ = '_';
*x++ = '_';
- if (*y == 0)
- break;
- else
- *x++ = *y++;
+ flag = 0;
}
+ if (*y == 0)
+ break;
else
*x++ = *y++;
}
@@ -3770,26 +4150,35 @@ do_spec_1 (spec, inswitch, soft_matched_part)
{
int c1 = *p++; /* Select first or second version number. */
char *v = compiler_version;
- char *q, *copy;
+ char *q;
+
+ /* The format of the version string is
+ ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)? */
+
+ /* Ignore leading non-digits. i.e. "foo-" in "foo-2.7.2". */
+ while (! ISDIGIT (*v))
+ v++;
+ if (v > compiler_version && v[-1] != '-')
+ abort ();
+
/* If desired, advance to second version number. */
if (c1 == '2')
{
- /* Set P after the first period. */
- while (*v != 0 && *v != ' ' && *v != '.')
- v++;
- if (*v == '.')
+ /* Set V after the first period. */
+ while (ISDIGIT (*v))
v++;
+ if (*v != '.')
+ abort ();
+ v++;
}
+
/* Set Q at the next period or at the end. */
q = v;
- while (*q != 0 && *q != ' ' && *q != '.')
+ while (ISDIGIT (*q))
q++;
- /* Empty string means zero. */
- if (p == q)
- {
- v = "0";
- q = v + 1;
- }
+ if (*q != 0 && *q != ' ' && *q != '.' && *q != '-')
+ abort ();
+
/* Put that part into the command. */
obstack_grow (&obstack, v, q - v);
arg_going = 1;
@@ -3826,17 +4215,24 @@ static char *
handle_braces (p)
register char *p;
{
- register char *q;
- char *filter;
- int pipe = 0;
- int negate = 0;
- int suffix = 0;
+ char *filter, *body = NULL, *endbody;
+ int pipe_p = 0;
+ int negate;
+ int suffix;
+ int include_blanks = 1;
+
+ if (*p == '^')
+ /* A '^' after the open-brace means to not give blanks before args. */
+ include_blanks = 0, ++p;
if (*p == '|')
/* A `|' after the open-brace means,
if the test fails, output a single minus sign rather than nothing.
This is used in %{|!pipe:...}. */
- pipe = 1, ++p;
+ pipe_p = 1, ++p;
+
+next_member:
+ negate = suffix = 0;
if (*p == '!')
/* A `!' after the open-brace negates the condition:
@@ -3846,7 +4242,7 @@ handle_braces (p)
if (*p == '.')
/* A `.' after the open-brace means test against the current suffix. */
{
- if (pipe)
+ if (pipe_p)
abort ();
suffix = 1;
@@ -3854,24 +4250,36 @@ handle_braces (p)
}
filter = p;
- while (*p != ':' && *p != '}') p++;
- if (*p != '}')
+ while (*p != ':' && *p != '}' && *p != '|') p++;
+
+ if (*p == '|' && pipe_p)
+ abort ();
+
+ if (!body)
{
- register int count = 1;
- q = p + 1;
- while (count > 0)
- {
- if (*q == '{')
- count++;
- else if (*q == '}')
- count--;
- else if (*q == 0)
- abort ();
- q++;
+ if (*p != '}')
+ {
+ register int count = 1;
+ register char *q = p;
+
+ while (*q++ != ':') continue;
+ body = q;
+
+ while (count > 0)
+ {
+ if (*q == '{')
+ count++;
+ else if (*q == '}')
+ count--;
+ else if (*q == 0)
+ abort ();
+ q++;
+ }
+ endbody = q;
}
+ else
+ body = p, endbody = p+1;
}
- else
- q = p + 1;
if (suffix)
{
@@ -3879,14 +4287,12 @@ handle_braces (p)
&& strlen (input_suffix) == p - filter
&& strncmp (input_suffix, filter, p - filter) == 0);
- if (p[0] == '}')
+ if (body[0] == '}')
abort ();
if (negate != found
- && do_spec_1 (save_string (p + 1, q - p - 2), 0, NULL_PTR) < 0)
+ && do_spec_1 (save_string (body, endbody-body-1), 0, NULL_PTR) < 0)
return 0;
-
- return q;
}
else if (p[-1] == '*' && p[0] == '}')
{
@@ -3896,7 +4302,7 @@ handle_braces (p)
for (i = 0; i < n_switches; i++)
if (!strncmp (switches[i].part1, filter, p - filter)
&& check_live_switch (i, p - filter))
- give_switch (i, 0);
+ give_switch (i, 0, include_blanks);
}
else
{
@@ -3909,11 +4315,11 @@ handle_braces (p)
if (p[-1] == '*' && !negate)
{
int substitution;
- char *r = p;
+ char *r = body;
/* First see whether we have %*. */
substitution = 0;
- while (r < q)
+ while (r < endbody)
{
if (*r == '%' && r[1] == '*')
substitution = 1;
@@ -3927,7 +4333,7 @@ handle_braces (p)
in the text that follows the colon. */
unsigned hard_match_len = p - filter - 1;
- char *string = save_string (p + 1, q - p - 2);
+ char *string = save_string (body, endbody - body - 1);
for (i = 0; i < n_switches; i++)
if (!strncmp (switches[i].part1, filter, hard_match_len)
@@ -3935,10 +4341,13 @@ handle_braces (p)
{
do_spec_1 (string, 0, &switches[i].part1[hard_match_len]);
/* Pass any arguments this switch has. */
- give_switch (i, 1);
+ give_switch (i, 1, 1);
}
- return q;
+ /* We didn't match. Try again. */
+ if (*p++ == '|')
+ goto next_member;
+ return endbody;
}
}
@@ -3972,30 +4381,36 @@ handle_braces (p)
}
}
- /* If it is as desired (present for %{s...}, absent for %{-s...})
+ /* If it is as desired (present for %{s...}, absent for %{!s...})
then substitute either the switch or the specified
conditional text. */
if (present != negate)
{
if (*p == '}')
{
- give_switch (i, 0);
+ give_switch (i, 0, include_blanks);
}
else
{
- if (do_spec_1 (save_string (p + 1, q - p - 2), 0, NULL_PTR) < 0)
+ if (do_spec_1 (save_string (body, endbody - body - 1),
+ 0, NULL_PTR) < 0)
return 0;
}
}
- else if (pipe)
+ else if (pipe_p)
{
/* Here if a %{|...} conditional fails: output a minus sign,
which means "standard output" or "standard input". */
do_spec_1 ("-", 0, NULL_PTR);
+ return endbody;
}
}
- return q;
+ /* We didn't match; try again. */
+ if (*p++ == '|')
+ goto next_member;
+
+ return endbody;
}
/* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch
@@ -4041,7 +4456,7 @@ check_live_switch (switchnum, prefix_length)
case 'W': case 'f': case 'm':
if (! strncmp (name + 1, "no-", 3))
{
- /* We have Xno-YYY, search for XYYY. */
+ /* We have Xno-YYY, search for XYYY. */
for (i = switchnum + 1; i < n_switches; i++)
if (switches[i].part1[0] == name[0]
&& ! strcmp (&switches[i].part1[1], &name[4]))
@@ -4080,28 +4495,35 @@ check_live_switch (switchnum, prefix_length)
the vector of switches gcc received, which is `switches'.
This cannot fail since it never finishes a command line.
- If OMIT_FIRST_WORD is nonzero, then we omit .part1 of the argument. */
+ If OMIT_FIRST_WORD is nonzero, then we omit .part1 of the argument.
+
+ If INCLUDE_BLANKS is nonzero, then we include blanks before each argument
+ of the switch. */
static void
-give_switch (switchnum, omit_first_word)
+give_switch (switchnum, omit_first_word, include_blanks)
int switchnum;
int omit_first_word;
+ int include_blanks;
{
if (!omit_first_word)
{
do_spec_1 ("-", 0, NULL_PTR);
do_spec_1 (switches[switchnum].part1, 1, NULL_PTR);
}
- do_spec_1 (" ", 0, NULL_PTR);
+
if (switches[switchnum].args != 0)
{
char **p;
for (p = switches[switchnum].args; *p; p++)
{
+ if (include_blanks)
+ do_spec_1 (" ", 0, NULL_PTR);
do_spec_1 (*p, 1, NULL_PTR);
- do_spec_1 (" ", 0, NULL_PTR);
}
}
+
+ do_spec_1 (" ", 0, NULL_PTR);
switches[switchnum].valid = 1;
}
@@ -4173,12 +4595,12 @@ is_directory (path1, path2, linker)
/* Exclude directories that the linker is known to search. */
if (linker
&& ((cp - path == 6
- && strcmp (path, concat4 (dir_separator_str, "lib",
- dir_separator_str, ".")) == 0)
+ && strcmp (path, concat (dir_separator_str, "lib",
+ dir_separator_str, ".", NULL_PTR)) == 0)
|| (cp - path == 10
- && strcmp (path, concat6 (dir_separator_str, "usr",
- dir_separator_str, "lib",
- dir_separator_str, ".")) == 0)))
+ && strcmp (path, concat (dir_separator_str, "usr",
+ dir_separator_str, "lib",
+ dir_separator_str, ".", NULL_PTR)) == 0)))
return 0;
return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
@@ -4203,13 +4625,14 @@ main (argc, argv)
int argc;
char **argv;
{
- register int i;
- int j;
+ register size_t i;
+ size_t j;
int value;
int linker_was_run = 0;
char *explicit_link_files;
char *specs_file;
char *p;
+ struct user_specs *uptr;
p = argv[0] + strlen (argv[0]);
while (p != argv[0] && p[-1] != '/' && p[-1] != DIR_SEPARATOR) --p;
@@ -4233,6 +4656,43 @@ main (argc, argv)
obstack_init (&obstack);
+ /* Build multilib_select, et. al from the separate lines that make up each
+ multilib selection. */
+ {
+ char **q = multilib_raw;
+ int need_space;
+
+ obstack_init (&multilib_obstack);
+ while ((p = *q++) != (char *) 0)
+ obstack_grow (&multilib_obstack, p, strlen (p));
+
+ obstack_1grow (&multilib_obstack, 0);
+ multilib_select = obstack_finish (&multilib_obstack);
+
+ q = multilib_matches_raw;
+ while ((p = *q++) != (char *) 0)
+ obstack_grow (&multilib_obstack, p, strlen (p));
+
+ obstack_1grow (&multilib_obstack, 0);
+ multilib_matches = obstack_finish (&multilib_obstack);
+
+ need_space = FALSE;
+ for (i = 0;
+ i < sizeof (multilib_defaults_raw) / sizeof (multilib_defaults_raw[0]);
+ i++)
+ {
+ if (need_space)
+ obstack_1grow (&multilib_obstack, ' ');
+ obstack_grow (&multilib_obstack,
+ multilib_defaults_raw[i],
+ strlen (multilib_defaults_raw[i]));
+ need_space = TRUE;
+ }
+
+ obstack_1grow (&multilib_obstack, 0);
+ multilib_defaults = obstack_finish (&multilib_obstack);
+ }
+
/* Set up to remember the pathname of gcc and any options
needed for collect. We use argv[0] instead of programname because
we need the complete pathname. */
@@ -4248,7 +4708,10 @@ main (argc, argv)
/* Choose directory for temp files. */
- choose_temp_base ();
+#ifndef MKTEMP_EACH_FILE
+ temp_filename = choose_temp_base ();
+ temp_filename_length = strlen (temp_filename);
+#endif
/* Make a table of what switches there are (switches, n_switches).
Make a table of specified input files (infiles, n_infiles).
@@ -4256,6 +4719,52 @@ main (argc, argv)
process_command (argc, argv);
+ {
+ int first_time;
+
+ /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
+ the compiler. */
+ obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
+ sizeof ("COLLECT_GCC_OPTIONS=")-1);
+
+ first_time = TRUE;
+ for (i = 0; i < n_switches; i++)
+ {
+ char **args;
+ char *p, *q;
+ if (!first_time)
+ obstack_grow (&collect_obstack, " ", 1);
+
+ first_time = FALSE;
+ obstack_grow (&collect_obstack, "'-", 2);
+ q = switches[i].part1;
+ while ((p = index (q,'\'')))
+ {
+ obstack_grow (&collect_obstack, q, p-q);
+ obstack_grow (&collect_obstack, "'\\''", 4);
+ q = ++p;
+ }
+ obstack_grow (&collect_obstack, q, strlen (q));
+ obstack_grow (&collect_obstack, "'", 1);
+
+ for (args = switches[i].args; args && *args; args++)
+ {
+ obstack_grow (&collect_obstack, " '", 2);
+ q = *args;
+ while ((p = index (q,'\'')))
+ {
+ obstack_grow (&collect_obstack, q, p-q);
+ obstack_grow (&collect_obstack, "'\\''", 4);
+ q = ++p;
+ }
+ obstack_grow (&collect_obstack, q, strlen (q));
+ obstack_grow (&collect_obstack, "'", 1);
+ }
+ }
+ obstack_grow (&collect_obstack, "\0", 1);
+ putenv (obstack_finish (&collect_obstack));
+ }
+
/* Initialize the vector of specs to just the default.
This means one element containing 0s, as a terminator. */
@@ -4266,42 +4775,56 @@ main (argc, argv)
/* Read specs from a file if there is one. */
- machine_suffix = concat4 (spec_machine, dir_separator_str,
- spec_version, dir_separator_str);
- just_machine_suffix = concat (spec_machine, dir_separator_str);
+ machine_suffix = concat (spec_machine, dir_separator_str,
+ spec_version, dir_separator_str, NULL_PTR);
+ just_machine_suffix = concat (spec_machine, dir_separator_str, NULL_PTR);
specs_file = find_a_file (&startfile_prefixes, "specs", R_OK);
/* Read the specs file unless it is a default one. */
if (specs_file != 0 && strcmp (specs_file, "specs"))
- read_specs (specs_file);
+ read_specs (specs_file, TRUE);
+ else
+ init_spec ();
/* We need to check standard_exec_prefix/just_machine_suffix/specs
- for any override of as, ld and libraries. */
- specs_file =(char *) alloca (strlen (standard_exec_prefix) +
- strlen (just_machine_suffix) + sizeof ("specs"));
- strcpy (specs_file, standard_exec_prefix);
- strcat (specs_file, just_machine_suffix);
- strcat (specs_file, "specs");
- if (access (specs_file, R_OK) == 0)
- read_specs (specs_file, TRUE);
+ for any override of as, ld and libraries. */
+ specs_file = (char *) alloca (strlen (standard_exec_prefix)
+ + strlen (just_machine_suffix)
+ + sizeof ("specs"));
+
+ strcpy (specs_file, standard_exec_prefix);
+ strcat (specs_file, just_machine_suffix);
+ strcat (specs_file, "specs");
+ if (access (specs_file, R_OK) == 0)
+ read_specs (specs_file, TRUE);
+
+ /* Process any user specified specs in the order given on the command
+ line. */
+ for (uptr = user_specs_head; uptr; uptr = uptr->next)
+ {
+ char *filename = find_a_file (&startfile_prefixes, uptr->filename, R_OK);
+ read_specs (filename ? filename : uptr->filename, FALSE);
+ }
/* If not cross-compiling, look for startfiles in the standard places. */
/* The fact that these are done here, after reading the specs file,
means that it cannot be found in these directories.
But that's okay. It should never be there anyway. */
- if (!cross_compile)
+ if (*cross_compile == '0')
{
#ifdef MD_EXEC_PREFIX
- add_prefix (&exec_prefixes, md_exec_prefix, 0, 0, NULL_PTR);
- add_prefix (&startfile_prefixes, md_exec_prefix, 0, 0, NULL_PTR);
+ add_prefix (&exec_prefixes, md_exec_prefix, "GCC", 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, md_exec_prefix, "GCC", 0, 0, NULL_PTR);
#endif
#ifdef MD_STARTFILE_PREFIX
- add_prefix (&startfile_prefixes, md_startfile_prefix, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, md_startfile_prefix, "GCC",
+ 0, 0, NULL_PTR);
#endif
#ifdef MD_STARTFILE_PREFIX_1
- add_prefix (&startfile_prefixes, md_startfile_prefix_1, 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, md_startfile_prefix_1, "GCC",
+ 0, 0, NULL_PTR);
#endif
/* If standard_startfile_prefix is relative, base it on
@@ -4309,38 +4832,46 @@ main (argc, argv)
as a unit. If GCC_EXEC_PREFIX is defined, base
standard_startfile_prefix on that as well. */
if (*standard_startfile_prefix == '/'
- || *standard_startfile_prefix == DIR_SEPARATOR)
- add_prefix (&startfile_prefixes, standard_startfile_prefix, 0, 0,
- NULL_PTR);
+ || *standard_startfile_prefix == DIR_SEPARATOR
+ || *standard_startfile_prefix == '$'
+#ifdef __MSDOS__
+ /* Check for disk name on MS-DOS-based systems. */
+ || (standard_startfile_prefix[1] == ':'
+ && (standard_startfile_prefix[2] == DIR_SEPARATOR
+ || standard_startfile_prefix[2] == '/'))
+#endif
+ )
+ add_prefix (&startfile_prefixes, standard_startfile_prefix, "BINUTILS",
+ 0, 0, NULL_PTR);
else
{
if (gcc_exec_prefix)
add_prefix (&startfile_prefixes,
- concat3 (gcc_exec_prefix, machine_suffix,
- standard_startfile_prefix),
- 0, 0, NULL_PTR);
+ concat (gcc_exec_prefix, machine_suffix,
+ standard_startfile_prefix, NULL_PTR),
+ NULL_PTR, 0, 0, NULL_PTR);
add_prefix (&startfile_prefixes,
- concat3 (standard_exec_prefix,
- machine_suffix,
- standard_startfile_prefix),
- 0, 0, NULL_PTR);
+ concat (standard_exec_prefix,
+ machine_suffix,
+ standard_startfile_prefix, NULL_PTR),
+ NULL_PTR, 0, 0, NULL_PTR);
}
- add_prefix (&startfile_prefixes, standard_startfile_prefix_1, 0, 0,
- NULL_PTR);
- add_prefix (&startfile_prefixes, standard_startfile_prefix_2, 0, 0,
- NULL_PTR);
+ add_prefix (&startfile_prefixes, standard_startfile_prefix_1,
+ "BINUTILS", 0, 0, NULL_PTR);
+ add_prefix (&startfile_prefixes, standard_startfile_prefix_2,
+ "BINUTILS", 0, 0, NULL_PTR);
#if 0 /* Can cause surprises, and one can use -B./ instead. */
- add_prefix (&startfile_prefixes, "./", 0, 1, NULL_PTR);
+ add_prefix (&startfile_prefixes, "./", NULL_PTR, 0, 1, NULL_PTR);
#endif
}
else
{
if (*standard_startfile_prefix != DIR_SEPARATOR && gcc_exec_prefix)
add_prefix (&startfile_prefixes,
- concat3 (gcc_exec_prefix, machine_suffix,
- standard_startfile_prefix),
- 0, 0, NULL_PTR);
+ concat (gcc_exec_prefix, machine_suffix,
+ standard_startfile_prefix, NULL_PTR),
+ "BINUTILS", 0, 0, NULL_PTR);
}
/* If we have a GCC_EXEC_PREFIX envvar, modify it for cpp's sake. */
@@ -4410,9 +4941,36 @@ main (argc, argv)
exit (0);
}
+ if (print_help_list)
+ {
+ display_help ();
+
+ if (! verbose_flag)
+ {
+ printf ("\nReport bugs to egcs-bugs@egcs.cygnus.com.\n");
+ printf ("Please see the file BUGS (included with the sources) first.\n");
+
+ exit (0);
+ }
+
+ /* We do not exit here. Instead we have created a fake input file
+ called 'help-dummy' which needs to be compiled, and we pass this
+ on the the various sub-processes, along with the --help switch. */
+ }
+
if (verbose_flag)
{
- if (! strcmp (version_string, compiler_version))
+ int n;
+
+ /* compiler_version is truncated at the first space when initialized
+ from version string, so truncate version_string at the first space
+ before comparing. */
+ for (n = 0; version_string[n]; n++)
+ if (version_string[n] == ' ')
+ break;
+
+ if (! strncmp (version_string, compiler_version, n)
+ && compiler_version[n] == 0)
fprintf (stderr, "gcc version %s\n", version_string);
else
fprintf (stderr, "gcc driver version %s executing gcc version %s\n",
@@ -4422,13 +4980,17 @@ main (argc, argv)
exit (0);
}
- if (n_infiles == 0)
+ if (n_infiles == added_libraries)
fatal ("No input files");
/* Make a place to record the compiler output file names
that correspond to the input files. */
- outfiles = (char **) xmalloc (n_infiles * sizeof (char *));
+ i = n_infiles;
+#ifdef LANG_SPECIFIC_DRIVER
+ i += lang_specific_extra_outfiles;
+#endif
+ outfiles = (char **) xmalloc (i * sizeof (char *));
bzero ((char *) outfiles, n_infiles * sizeof (char *));
/* Record which files were specified explicitly as link input. */
@@ -4463,6 +5025,10 @@ main (argc, argv)
register char *p;
int len;
+ if (cp->spec[0][0] == '#')
+ error ("%s: %s compiler not installed on this system",
+ input_filename, &cp->spec[0][1]);
+
input_basename = input_filename;
for (p = input_filename; *p; p++)
if (*p == '/' || *p == DIR_SEPARATOR)
@@ -4520,45 +5086,30 @@ main (argc, argv)
clear_failure_queue ();
}
+#ifdef LANG_SPECIFIC_DRIVER
+ if (error_count == 0
+ && lang_specific_pre_link ())
+ error_count++;
+#endif
+
/* Run ld to link all the compiler output files. */
if (error_count == 0)
{
int tmp = execution_count;
- int i;
- int first_time;
+ /* We'll use ld if we can't find collect2. */
+ if (! strcmp (linker_name_spec, "collect2"))
+ {
+ char *s = find_a_file (&exec_prefixes, "collect2", X_OK);
+ if (s == NULL)
+ linker_name_spec = "ld";
+ }
/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
for collect. */
putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH=");
putenv_from_prefixes (&startfile_prefixes, "LIBRARY_PATH=");
- /* Build COLLECT_GCC_OPTIONS to have all of the options specified to
- the compiler. */
- obstack_grow (&collect_obstack, "COLLECT_GCC_OPTIONS=",
- sizeof ("COLLECT_GCC_OPTIONS=")-1);
-
- first_time = TRUE;
- for (i = 0; i < n_switches; i++)
- {
- char **args;
- if (!first_time)
- obstack_grow (&collect_obstack, " ", 1);
-
- first_time = FALSE;
- obstack_grow (&collect_obstack, "-", 1);
- obstack_grow (&collect_obstack, switches[i].part1,
- strlen (switches[i].part1));
-
- for (args = switches[i].args; args && *args; args++)
- {
- obstack_grow (&collect_obstack, " ", 1);
- obstack_grow (&collect_obstack, *args, strlen (*args));
- }
- }
- obstack_grow (&collect_obstack, "\0", 1);
- putenv (obstack_finish (&collect_obstack));
-
value = do_spec (link_command_spec);
if (value < 0)
error_count = 1;
@@ -4584,6 +5135,12 @@ main (argc, argv)
delete_failure_queue ();
delete_temp_files ();
+ if (print_help_list)
+ {
+ printf ("\nReport bugs to egcs-bugs@egcs.cygnus.com.\n");
+ printf ("Please see the file BUGS (included with the sources) first.\n");
+ }
+
exit (error_count > 0 ? (signal_count ? 2 : 1) : 0);
/* NOTREACHED */
return 0;
@@ -4591,29 +5148,29 @@ main (argc, argv)
/* Find the proper compilation spec for the file name NAME,
whose length is LENGTH. LANGUAGE is the specified language,
- or 0 if none specified. */
+ or 0 if this file is to be passed to the linker. */
static struct compiler *
lookup_compiler (name, length, language)
char *name;
- int length;
+ size_t length;
char *language;
{
struct compiler *cp;
- /* Look for the language, if one is spec'd. */
+ /* If this was specified by the user to be a linker input, indicate that. */
+ if (language != 0 && language[0] == '*')
+ return 0;
+
+ /* Otherwise, look for the language, if one is spec'd. */
if (language != 0)
{
for (cp = compilers + n_compilers - 1; cp >= compilers; cp--)
- {
- if (language != 0)
- {
- if (cp->suffix[0] == '@'
- && !strcmp (cp->suffix + 1, language))
- return cp;
- }
- }
+ if (cp->suffix[0] == '@' && !strcmp (cp->suffix + 1, language))
+ return cp;
+
error ("language %s not recognized", language);
+ return 0;
}
/* Look for a suffix. */
@@ -4621,23 +5178,24 @@ lookup_compiler (name, length, language)
{
if (/* The suffix `-' matches only the file name `-'. */
(!strcmp (cp->suffix, "-") && !strcmp (name, "-"))
- ||
- (strlen (cp->suffix) < length
- /* See if the suffix matches the end of NAME. */
+ || (strlen (cp->suffix) < length
+ /* See if the suffix matches the end of NAME. */
#ifdef OS2
- && (!strcmp (cp->suffix,
- name + length - strlen (cp->suffix))
- || !strpbrk (cp->suffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
- && !strcasecmp (cp->suffix,
- name + length - strlen (cp->suffix)))))
+ && ((!strcmp (cp->suffix,
+ name + length - strlen (cp->suffix))
+ || !strpbrk (cp->suffix, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
+ && !strcasecmp (cp->suffix,
+ name + length - strlen (cp->suffix)))
#else
- && !strcmp (cp->suffix,
- name + length - strlen (cp->suffix))))
+ && !strcmp (cp->suffix,
+ name + length - strlen (cp->suffix))
#endif
+ ))
{
if (cp->spec[0][0] == '@')
{
struct compiler *new;
+
/* An alias entry maps a suffix to a language.
Search for the language; pass 0 for NAME and LENGTH
to avoid infinite recursion if language not found.
@@ -4649,6 +5207,7 @@ lookup_compiler (name, length, language)
(char *) new->spec, sizeof new->spec);
return new;
}
+
/* A non-alias entry: return it. */
return cp;
}
@@ -4678,42 +5237,58 @@ xrealloc (ptr, size)
return value;
}
-/* Return a newly-allocated string whose contents concatenate those of s1, s2 */
+/* This function is based on the one in libiberty. */
static char *
-concat (s1, s2)
- char *s1, *s2;
+concat VPROTO((char *first, ...))
{
- int len1 = strlen (s1);
- int len2 = strlen (s2);
- char *result = xmalloc (len1 + len2 + 1);
+ register int length;
+ register char *newstr;
+ register char *end;
+ register char *arg;
+ va_list args;
+#ifndef __STDC__
+ char *first;
+#endif
- strcpy (result, s1);
- strcpy (result + len1, s2);
- *(result + len1 + len2) = 0;
+ /* First compute the size of the result and get sufficient memory. */
- return result;
-}
+ VA_START (args, first);
+#ifndef __STDC__
+ first = va_arg (args, char *);
+#endif
-static char *
-concat3 (s1, s2, s3)
- char *s1, *s2, *s3;
-{
- return concat (concat (s1, s2), s3);
-}
+ arg = first;
+ length = 0;
-static char *
-concat4 (s1, s2, s3, s4)
- char *s1, *s2, *s3, *s4;
-{
- return concat (concat (s1, s2), concat (s3, s4));
-}
+ while (arg != 0)
+ {
+ length += strlen (arg);
+ arg = va_arg (args, char *);
+ }
-static char *
-concat6 (s1, s2, s3, s4, s5, s6)
- char *s1, *s2, *s3, *s4, *s5, *s6;
-{
- return concat3 (concat (s1, s2), concat (s3, s4), concat (s5, s6));
+ newstr = (char *) xmalloc (length + 1);
+ va_end (args);
+
+ /* Now copy the individual pieces to the result string. */
+
+ VA_START (args, first);
+#ifndef __STDC__
+ first = va_arg (args, char *);
+#endif
+
+ end = newstr;
+ arg = first;
+ while (arg != 0)
+ {
+ while (*arg)
+ *end++ = *arg++;
+ arg = va_arg (args, char *);
+ }
+ *end = '\000';
+ va_end (args);
+
+ return (newstr);
}
static char *
@@ -4732,40 +5307,32 @@ static void
pfatal_with_name (name)
char *name;
{
- char *s;
-
- if (errno < sys_nerr)
- s = concat ("%s: ", my_strerror( errno ));
- else
- s = "cannot open `%s'";
- fatal (s, name);
+ fatal ("%s: %s", name, my_strerror (errno));
}
static void
perror_with_name (name)
char *name;
{
- char *s;
-
- if (errno < sys_nerr)
- s = concat ("%s: ", my_strerror( errno ));
- else
- s = "cannot open `%s'";
- error (s, name);
+ error ("%s: %s", name, my_strerror (errno));
}
static void
-perror_exec (name)
- char *name;
+pfatal_pexecute (errmsg_fmt, errmsg_arg)
+ char *errmsg_fmt;
+ char *errmsg_arg;
{
- char *s;
+ int save_errno = errno;
- if (errno < sys_nerr)
- s = concat ("installation problem, cannot exec `%s': ",
- my_strerror (errno));
- else
- s = "installation problem, cannot exec `%s'";
- error (s, name);
+ if (errmsg_arg)
+ {
+ /* Space for trailing '\0' is in %s. */
+ char *msg = xmalloc (strlen (errmsg_fmt) + strlen (errmsg_arg));
+ sprintf (msg, errmsg_fmt, errmsg_arg);
+ errmsg_fmt = msg;
+ }
+
+ fatal ("%s: %s", errmsg_fmt, my_strerror (save_errno));
}
/* More 'friendly' abort that prints the line and file.
@@ -4777,8 +5344,6 @@ fancy_abort ()
fatal ("Internal gcc abort.");
}
-#ifdef HAVE_VPRINTF
-
/* Output an error message and exit */
static void
@@ -4792,7 +5357,7 @@ fatal VPROTO((char *format, ...))
VA_START (ap, format);
#ifndef __STDC__
- format = va_arg (ap, char*);
+ format = va_arg (ap, char *);
#endif
fprintf (stderr, "%s: ", programname);
@@ -4814,7 +5379,7 @@ error VPROTO((char *format, ...))
VA_START (ap, format);
#ifndef __STDC__
- format = va_arg (ap, char*);
+ format = va_arg (ap, char *);
#endif
fprintf (stderr, "%s: ", programname);
@@ -4823,29 +5388,6 @@ error VPROTO((char *format, ...))
fprintf (stderr, "\n");
}
-
-#else /* not HAVE_VPRINTF */
-
-static void
-fatal (msg, arg1, arg2)
- char *msg, *arg1, *arg2;
-{
- error (msg, arg1, arg2);
- delete_temp_files ();
- exit (1);
-}
-
-static void
-error (msg, arg1, arg2)
- char *msg, *arg1, *arg2;
-{
- fprintf (stderr, "%s: ", programname);
- fprintf (stderr, msg, arg1, arg2);
- fprintf (stderr, "\n");
-}
-
-#endif /* not HAVE_VPRINTF */
-
static void
validate_all_switches ()
@@ -4857,91 +5399,29 @@ validate_all_switches ()
for (comp = compilers; comp->spec[0]; comp++)
{
- int i;
+ size_t i;
for (i = 0; i < sizeof comp->spec / sizeof comp->spec[0] && comp->spec[i]; i++)
{
p = comp->spec[i];
- while (c = *p++)
+ while ((c = *p++))
if (c == '%' && *p == '{')
/* We have a switch spec. */
validate_switches (p + 1);
}
}
- /* look through the linked list of extra specs read from the specs file */
+ /* look through the linked list of specs read from the specs file */
for (spec = specs; spec ; spec = spec->next)
{
- p = spec->spec;
- while (c = *p++)
+ p = *(spec->ptr_spec);
+ while ((c = *p++))
if (c == '%' && *p == '{')
/* We have a switch spec. */
validate_switches (p + 1);
}
p = link_command_spec;
- while (c = *p++)
- if (c == '%' && *p == '{')
- /* We have a switch spec. */
- validate_switches (p + 1);
-
- /* Now notice switches mentioned in the machine-specific specs. */
-
- p = asm_spec;
- while (c = *p++)
- if (c == '%' && *p == '{')
- /* We have a switch spec. */
- validate_switches (p + 1);
-
- p = asm_final_spec;
- while (c = *p++)
- if (c == '%' && *p == '{')
- /* We have a switch spec. */
- validate_switches (p + 1);
-
- p = cpp_spec;
- while (c = *p++)
- if (c == '%' && *p == '{')
- /* We have a switch spec. */
- validate_switches (p + 1);
-
- p = signed_char_spec;
- while (c = *p++)
- if (c == '%' && *p == '{')
- /* We have a switch spec. */
- validate_switches (p + 1);
-
- p = cc1_spec;
- while (c = *p++)
- if (c == '%' && *p == '{')
- /* We have a switch spec. */
- validate_switches (p + 1);
-
- p = cc1plus_spec;
- while (c = *p++)
- if (c == '%' && *p == '{')
- /* We have a switch spec. */
- validate_switches (p + 1);
-
- p = link_spec;
- while (c = *p++)
- if (c == '%' && *p == '{')
- /* We have a switch spec. */
- validate_switches (p + 1);
-
- p = lib_spec;
- while (c = *p++)
- if (c == '%' && *p == '{')
- /* We have a switch spec. */
- validate_switches (p + 1);
-
- p = libgcc_spec;
- while (c = *p++)
- if (c == '%' && *p == '{')
- /* We have a switch spec. */
- validate_switches (p + 1);
-
- p = startfile_spec;
- while (c = *p++)
+ while ((c = *p++))
if (c == '%' && *p == '{')
/* We have a switch spec. */
validate_switches (p + 1);
@@ -4993,43 +5473,121 @@ validate_switches (start)
}
}
-/* Check whether a particular argument was used. */
+/* Check whether a particular argument was used. The first time we
+ canonicalize the switches to keep only the ones we care about. */
static int
used_arg (p, len)
char *p;
int len;
{
- int i;
+ struct mswitchstr {
+ char *str;
+ char *replace;
+ int len;
+ int rep_len;
+ };
+
+ static struct mswitchstr *mswitches;
+ static int n_mswitches;
+ int i, j;
+
+ if (!mswitches)
+ {
+ struct mswitchstr *matches;
+ char *q;
+ int cnt = 0;
+
+ /* Break multilib_matches into the component strings of string and replacement
+ string */
+ for (q = multilib_matches; *q != '\0'; q++)
+ if (*q == ';')
+ cnt++;
+
+ matches = (struct mswitchstr *) alloca ((sizeof (struct mswitchstr)) * cnt);
+ i = 0;
+ q = multilib_matches;
+ while (*q != '\0')
+ {
+ matches[i].str = q;
+ while (*q != ' ')
+ {
+ if (*q == '\0')
+ abort ();
+ q++;
+ }
+ *q = '\0';
+ matches[i].len = q - matches[i].str;
- for (i = 0; i < n_switches; i++)
- if (! strncmp (switches[i].part1, p, len)
- && strlen (switches[i].part1) == len)
- return 1;
- return 0;
-}
+ matches[i].replace = ++q;
+ while (*q != ';' && *q != '\0')
+ {
+ if (*q == ' ')
+ abort ();
+ q++;
+ }
+ matches[i].rep_len = q - matches[i].replace;
+ i++;
+ if (*q == ';')
+ *q++ = '\0';
+ else
+ break;
+ }
-/* Check whether a particular argument is a default argument. */
+ /* Now build a list of the replacement string for switches that we care
+ about. Make sure we allocate at least one entry. This prevents
+ xmalloc from calling fatal, and prevents us from re-executing this
+ block of code. */
+ mswitches
+ = (struct mswitchstr *) xmalloc ((sizeof (struct mswitchstr))
+ * (n_switches ? n_switches : 1));
+ for (i = 0; i < n_switches; i++)
+ {
+ int xlen = strlen (switches[i].part1);
+ for (j = 0; j < cnt; j++)
+ if (xlen == matches[j].len && ! strcmp (switches[i].part1, matches[j].str))
+ {
+ mswitches[n_mswitches].str = matches[j].replace;
+ mswitches[n_mswitches].len = matches[j].rep_len;
+ mswitches[n_mswitches].replace = (char *)0;
+ mswitches[n_mswitches].rep_len = 0;
+ n_mswitches++;
+ break;
+ }
+ }
+ }
-#ifndef MULTILIB_DEFAULTS
-#define MULTILIB_DEFAULTS { NULL }
-#endif
+ for (i = 0; i < n_mswitches; i++)
+ if (len == mswitches[i].len && ! strncmp (p, mswitches[i].str, len))
+ return 1;
-static char *multilib_defaults[] = MULTILIB_DEFAULTS;
+ return 0;
+}
static int
default_arg (p, len)
char *p;
int len;
{
- int count = sizeof multilib_defaults / sizeof multilib_defaults[0];
- int i;
+ char *start, *end;
- for (i = 0; i < count; i++)
- if (multilib_defaults[i] != NULL
- && strncmp (multilib_defaults[i], p, len) == 0
- && multilib_defaults[i][len] == '\0')
- return 1;
+ for (start = multilib_defaults; *start != '\0'; start = end+1)
+ {
+ while (*start == ' ' || *start == '\t')
+ start++;
+
+ if (*start == '\0')
+ break;
+
+ for (end = start+1; *end != ' ' && *end != '\t' && *end != '\0'; end++)
+ ;
+
+ if ((end - start) == len && strncmp (p, start, len) == 0)
+ return 1;
+
+ if (*end == '\0')
+ break;
+ }
return 0;
}
@@ -5257,7 +5815,28 @@ print_multilib_info ()
}
if (! skip)
- putchar ('\n');
+ {
+ /* If there are extra options, print them now */
+ if (multilib_extra && *multilib_extra)
+ {
+ int print_at = TRUE;
+ char *q;
+
+ for (q = multilib_extra; *q != '\0'; q++)
+ {
+ if (*q == ' ')
+ print_at = TRUE;
+ else
+ {
+ if (print_at)
+ putchar ('@');
+ putchar (*q);
+ print_at = FALSE;
+ }
+ }
+ }
+ putchar ('\n');
+ }
++p;
}
diff --git a/contrib/gcc/gcc.texi b/contrib/gcc/gcc.texi
index f858591..6eb51c1 100644
--- a/contrib/gcc/gcc.texi
+++ b/contrib/gcc/gcc.texi
@@ -1,5 +1,5 @@
\input texinfo @c -*-texinfo-*-
-@c %**start of header
+@c %**start of header
@setfilename gcc.info
@c @setfilename usegcc.info
@c @setfilename portgcc.info
@@ -14,26 +14,23 @@
@c and make sure the following does NOT begin with '@c':
@c @clear USING
-@c i have commented out the smallbook command below, and reformatted
-@c this manual in the regular book size for distribution. in addition,
-@c i commented out the commands that shift the text to one or the other
-@c side of the page for smallbook printing (which makes it easier for
-@c the photocopying people to handle...). -mew, 15june93
-
-@c (For FSF printing, turn on smallbook, comment out finalout below;
+@c (For FSF printing, turn on smallbook, comment out finalout below;
@c that is all that is needed.)
-@c smallbook
+@c 6/27/96 FSF DO wants smallbook fmt for 1st bound edition.
+@c @smallbook
@c i also commented out the finalout command, so if there *are* any
@c overfulls, you'll (hopefully) see the rectangle in the right hand
@c margin. -mew 15june93
-@c finalout
+@c @finalout
@c NOTE: checks/things to do:
-@c
+@c
@c -have bob do a search in all seven files for "mew" (ideally --mew,
-@c but i may have forgotten the occasional "--"..).
+@c but i may have forgotten the occasional "--"..).
+@c Just checked... all have `--'! Bob 22Jul96
+@c Use this to search: grep -n '\-\-mew' *.texi
@c -item/itemx, text after all (sub/sub)section titles, etc..
@c -consider putting the lists of options on pp 17--> etc in columns or
@c some such.
@@ -59,7 +56,7 @@
@end ifclear
@ifclear USING
@settitle Porting GNU CC
-@end ifclear
+@end ifclear
@syncodeindex fn cp
@syncodeindex vr cp
@@ -74,7 +71,7 @@
@c The text on right hand pages is pushed towards the right hand
@c margin and the text on left hand pages is pushed toward the left
-@c hand margin.
+@c hand margin.
@c (To provide the reverse effect, set bindingoffset to -0.75in.)
@c @tex
@@ -83,6 +80,10 @@
@c @end tex
@ifinfo
+@dircategory Programming
+@direntry
+* gcc: (gcc). The GNU C compiler.
+@end direntry
@ifset INTERNALS
@ifset USING
This file documents the use and the internals of the GNU compiler.
@@ -99,7 +100,7 @@ Published by the Free Software Foundation
59 Temple Place - Suite 330
Boston, MA 02111-1307 USA
-Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+Copyright (C) 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
@@ -114,23 +115,21 @@ notice identical to this one except for the removal of this paragraph
@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided also that the
-sections entitled ``GNU General Public License,'' ``Funding for Free
-Software,'' and ``Protect Your Freedom---Fight `Look And Feel'@w{}'' are
-included exactly as in the original, and provided that the entire
-resulting derived work is distributed under the terms of a permission
-notice identical to this one.
+sections entitled ``GNU General Public License'' and ``Funding for Free
+Software'' are included exactly as in the original, and provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
-except that the sections entitled ``GNU General Public License,''
-``Funding for Free Software,'' and ``Protect Your Freedom---Fight `Look
-And Feel'@w{}'', and this permission notice, may be included in
-translations approved by the Free Software Foundation instead of in the
-original English.
+except that the sections entitled ``GNU General Public License'' and
+``Funding for Free Software'', and this permission notice, may be
+included in translations approved by the Free Software Foundation
+instead of in the original English.
@end ifinfo
@setchapternewpage odd
-
+@c @finalout
@titlepage
@ifset INTERNALS
@ifset USING
@@ -147,23 +146,23 @@ original English.
@sp 2
@center Richard M. Stallman
@sp 3
-@center Last updated 29 June 1996
+@center Last updated 16 March 1998
@sp 1
-@c The version number appears twice more in this file.
+@c The version number appears five times more in this file.
-@center for version 2.7.2.1
+@center for egcs-1.1.2
@page
@vskip 0pt plus 1filll
-Copyright @copyright{} 1988, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+Copyright @copyright{} 1988, 89, 92, 93, 94, 95, 96, 98 Free Software Foundation, Inc.
@sp 2
-For GCC Version 2.7.2@*
+For EGCS Version 1.0@*
@sp 1
Published by the Free Software Foundation @*
59 Temple Place - Suite 330@*
Boston, MA 02111-1307, USA@*
-Last printed November, 1995.@*
+Last printed April, 1998.@*
Printed copies are available for $50 each.@*
-ISBN 1-882114-66-3
+ISBN 1-882114-37-X
@sp 1
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
@@ -171,25 +170,23 @@ are preserved on all copies.
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided also that the
-sections entitled ``GNU General Public License,'' ``Funding for Free
-Software,'' and ``Protect Your Freedom---Fight `Look And Feel'@w{}'' are
-included exactly as in the original, and provided that the entire
-resulting derived work is distributed under the terms of a permission
-notice identical to this one.
+sections entitled ``GNU General Public License'' and ``Funding for Free
+Software'' are included exactly as in the original, and provided that
+the entire resulting derived work is distributed under the terms of a
+permission notice identical to this one.
Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
-except that the sections entitled ``GNU General Public License,''
-``Funding for Free Software,'' and ``Protect Your Freedom---Fight `Look
-And Feel'@w{}'', and this permission notice, may be included in
-translations approved by the Free Software Foundation instead of in the
-original English.
+except that the sections entitled ``GNU General Public License'' and
+``Funding for Free Software'', and this permission notice, may be
+included in translations approved by the Free Software Foundation
+instead of in the original English.
@end titlepage
@page
@ifinfo
-@node Top, Copying,, (DIR)
+@node Top, G++ and GCC,, (DIR)
@top Introduction
@cindex introduction
@@ -197,37 +194,34 @@ original English.
@ifset USING
This manual documents how to run, install and port the GNU
compiler, as well as its new features and incompatibilities, and how to
-report bugs. It corresponds to GNU CC version 2.7.2.
+report bugs. It corresponds to EGCS version 1.1.2.
@end ifset
@end ifset
@ifclear INTERNALS
This manual documents how to run and install the GNU compiler,
as well as its new features and incompatibilities, and how to report
-bugs. It corresponds to GNU CC version 2.7.2.
+bugs. It corresponds to EGCS version 1.1.2.
@end ifclear
@ifclear USING
This manual documents how to port the GNU compiler,
as well as its new features and incompatibilities, and how to report
-bugs. It corresponds to GNU CC version 2.7.1.
+bugs. It corresponds to EGCS version 1.1.2.
@end ifclear
@end ifinfo
@menu
-* Copying:: GNU General Public License says
- how you can copy and share GNU CC.
-* Contributors:: People who have contributed to GNU CC.
-* Funding:: How to help assure funding for free software.
-* Look and Feel:: Protect your freedom---fight ``look and feel''.
@ifset USING
* G++ and GCC:: You can compile C or C++ programs.
* Invoking GCC:: Command options supported by @samp{gcc}.
* Installation:: How to configure, compile and install GNU CC.
* C Extensions:: GNU extensions to the C language family.
* C++ Extensions:: GNU extensions to the C++ language.
+* Gcov:: gcov: a GNU CC test coverage program.
* Trouble:: If you have trouble installing GNU CC.
* Bugs:: How, why and where to report bugs.
* Service:: How to find suppliers of support for GNU CC.
+* Contributing:: How to contribute to testing and developing GNU CC.
* VMS:: Using GNU CC on VMS.
@end ifset
@ifset INTERNALS
@@ -241,818 +235,16 @@ bugs. It corresponds to GNU CC version 2.7.1.
* Fragments:: Writing the @file{t-@var{target}} and @file{x-@var{host}} files.
@end ifset
-* Index:: Index of concepts and symbol names.
-@end menu
-
-@node Copying
-@unnumbered GNU GENERAL PUBLIC LICENSE
-@center Version 2, June 1991
-
-@display
-Copyright @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.
-@end display
-
-@unnumberedsec 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.
-
-@iftex
-@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-@end iftex
-@ifinfo
-@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-@end ifinfo
-
-@enumerate 0
-@item
-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.
-
-@item
-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.
-
-@item
-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:
-
-@enumerate a
-@item
-You must cause the modified files to carry prominent notices
-stating that you changed the files and the date of any change.
-
-@item
-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.
-
-@item
-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.)
-@end enumerate
-
-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.
-
-@item
-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:
-
-@enumerate a
-@item
-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,
-
-@item
-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,
-
-@item
-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.)
-@end enumerate
-
-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.
-
-@item
-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.
-
-@item
-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.
-
-@item
-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.
-
-@item
-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.
-
-@item
-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.
-
-@item
-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.
-
-@item
-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.
-
-@iftex
-@heading NO WARRANTY
-@end iftex
-@ifinfo
-@center NO WARRANTY
-@end ifinfo
-
-@item
-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.
-
-@item
-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.
-@end enumerate
-
-@iftex
-@heading END OF TERMS AND CONDITIONS
-@end iftex
-@ifinfo
-@center END OF TERMS AND CONDITIONS
-@end ifinfo
-
-@page
-@unnumberedsec 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.
-
-@smallexample
-@var{one line to give the program's name and a brief idea of what it does.}
-Copyright (C) 19@var{yy} @var{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.
-@end smallexample
-
-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:
-
-@smallexample
-Gnomovision version 69, Copyright (C) 19@var{yy} @var{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.
-@end smallexample
-
-The hypothetical commands @samp{show w} and @samp{show c} should show
-the appropriate parts of the General Public License. Of course, the
-commands you use may be called something other than @samp{show w} and
-@samp{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:
-
-@smallexample
-Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-`Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-@var{signature of Ty Coon}, 1 April 1989
-Ty Coon, President of Vice
-@end smallexample
-
-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
-@unnumbered Contributors to GNU CC
-@cindex contributors
-
-In addition to Richard Stallman, several people have written parts
-of GNU CC.
-
-@itemize @bullet
-@item
-The idea of using RTL and some of the optimization ideas came from the
-program PO written at the University of Arizona by Jack Davidson and
-Christopher Fraser. See ``Register Allocation and Exhaustive Peephole
-Optimization'', Software Practice and Experience 14 (9), Sept. 1984,
-857-866.
-
-@item
-Paul Rubin wrote most of the preprocessor.
-
-@item
-Leonard Tower wrote parts of the parser, RTL generator, and RTL
-definitions, and of the Vax machine description.
-
-@item
-Ted Lemon wrote parts of the RTL reader and printer.
-
-@item
-Jim Wilson implemented loop strength reduction and some other
-loop optimizations.
-
-@item
-Nobuyuki Hikichi of Software Research Associates, Tokyo, contributed
-the support for the Sony NEWS machine.
-
-@item
-Charles LaBrec contributed the support for the Integrated Solutions
-68020 system.
-
-@item
-Michael Tiemann of Cygnus Support wrote the front end for C++, as well
-as the support for inline functions and instruction scheduling. Also
-the descriptions of the National Semiconductor 32000 series cpu, the
-SPARC cpu and part of the Motorola 88000 cpu.
-
-@item
-Gerald Baumgartner added the signature extension to the C++ front-end.
-
-@item
-Jan Stein of the Chalmers Computer Society provided support for
-Genix, as well as part of the 32000 machine description.
-
-@item
-Randy Smith finished the Sun FPA support.
-
-@item
-Robert Brown implemented the support for Encore 32000 systems.
-
-@item
-David Kashtan of SRI adapted GNU CC to VMS.
-
-@item
-Alex Crain provided changes for the 3b1.
-
-@item
-Greg Satz and Chris Hanson assisted in making GNU CC work on HP-UX for
-the 9000 series 300.
-
-@item
-William Schelter did most of the work on the Intel 80386 support.
-
-@item
-Christopher Smith did the port for Convex machines.
-
-@item
-Paul Petersen wrote the machine description for the Alliant FX/8.
-
-@item
-Dario Dariol contributed the four varieties of sample programs
-that print a copy of their source.
-
-@item
-Alain Lichnewsky ported GNU CC to the Mips cpu.
-
-@item
-Devon Bowen, Dale Wiles and Kevin Zachmann ported GNU CC to the Tahoe.
-
-@item
-Jonathan Stone wrote the machine description for the Pyramid computer.
-
-@item
-Gary Miller ported GNU CC to Charles River Data Systems machines.
-
-@item
-Richard Kenner of the New York University Ultracomputer Research
-Laboratory wrote the machine descriptions for the AMD 29000, the DEC
-Alpha, the IBM RT PC, and the IBM RS/6000 as well as the support for
-instruction attributes. He also made changes to better support RISC
-processors including changes to common subexpression elimination,
-strength reduction, function calling sequence handling, and condition
-code support, in addition to generalizing the code for frame pointer
-elimination.
-
-@item
-Richard Kenner and Michael Tiemann jointly developed reorg.c, the delay
-slot scheduler.
-
-@item
-Mike Meissner and Tom Wood of Data General finished the port to the
-Motorola 88000.
-
-@item
-Masanobu Yuhara of Fujitsu Laboratories implemented the machine
-description for the Tron architecture (specifically, the Gmicro).
-
-@item
-NeXT, Inc.@: donated the front end that supports the Objective C
-language.
-@c We need to be careful to make it clear that "Objective C"
-@c is the name of a language, not that of a program or product.
-
-@item
-James van Artsdalen wrote the code that makes efficient use of
-the Intel 80387 register stack.
-
-@item
-Mike Meissner at the Open Software Foundation finished the port to the
-MIPS cpu, including adding ECOFF debug support, and worked on the
-Intel port for the Intel 80386 cpu.
-
-@item
-Ron Guilmette implemented the @code{protoize} and @code{unprotoize}
-tools, the support for Dwarf symbolic debugging information, and much of
-the support for System V Release 4. He has also worked heavily on the
-Intel 386 and 860 support.
-
-@item
-Torbjorn Granlund implemented multiply- and divide-by-constant
-optimization, improved long long support, and improved leaf function
-register allocation.
-
-@item
-Mike Stump implemented the support for Elxsi 64 bit CPU.
-
-@item
-John Wehle added the machine description for the Western Electric 32000
-processor used in several 3b series machines (no relation to the
-National Semiconductor 32000 processor).
-
-@ignore @c These features aren't advertised yet, since they don't fully work.
-@item
-Analog Devices helped implement the support for complex data types
-and iterators.
-@end ignore
-
-@item
-Holger Teutsch provided the support for the Clipper cpu.
-
-@item
-Kresten Krab Thorup wrote the run time support for the Objective C
-language.
-
-@item
-Stephen Moshier contributed the floating point emulator that assists in
-cross-compilation and permits support for floating point numbers wider
-than 64 bits.
-
-@item
-David Edelsohn contributed the changes to RS/6000 port to make it
-support the PowerPC and POWER2 architectures.
-
-@item
-Steve Chamberlain wrote the support for the Hitachi SH processor.
-
-@item
-Peter Schauer wrote the code to allow debugging to work on the Alpha.
-
-@item
-Oliver M. Kellogg of Deutsche Aerospace contributed the port to the
-MIL-STD-1750A.
-
-@item
-Michael K. Gschwind contributed the port to the PDP-11.
-@end itemize
-
-@node Funding
-@chapter Funding Free Software
-
-If you want to have more free software a few years from now, it makes
-sense for you to help encourage people to contribute funds for its
-development. The most effective approach known is to encourage
-commercial redistributors to donate.
-
-Users of free software systems can boost the pace of development by
-encouraging for-a-fee distributors to donate part of their selling price
-to free software developers---the Free Software Foundation, and others.
-
-The way to convince distributors to do this is to demand it and expect
-it from them. So when you compare distributors, judge them partly by
-how much they give to free software development. Show distributors
-they must compete to be the one who gives the most.
-
-To make this approach work, you must insist on numbers that you can
-compare, such as, ``We will donate ten dollars to the Frobnitz project
-for each disk sold.'' Don't be satisfied with a vague promise, such as
-``A portion of the profits are donated,'' since it doesn't give a basis
-for comparison.
-
-Even a precise fraction ``of the profits from this disk'' is not very
-meaningful, since creative accounting and unrelated business decisions
-can greatly alter what fraction of the sales price counts as profit.
-If the price you pay is $50, ten percent of the profit is probably
-less than a dollar; it might be a few cents, or nothing at all.
-
-Some redistributors do development work themselves. This is useful too;
-but to keep everyone honest, you need to inquire how much they do, and
-what kind. Some kinds of development make much more long-term
-difference than others. For example, maintaining a separate version of
-a program contributes very little; maintaining the standard version of a
-program for the whole community contributes much. Easy new ports
-contribute little, since someone else would surely do them; difficult
-ports such as adding a new CPU to the GNU C compiler contribute more;
-major new features or packages contribute the most.
-
-By establishing the idea that supporting further development is ``the
-proper thing to do'' when distributing free software for a fee, we can
-assure a steady flow of resources into making more free software.
-
-@display
-Copyright (C) 1994 Free Software Foundation, Inc.
-Verbatim copying and redistribution of this section is permitted
-without royalty; alteration is not permitted.
-@end display
-
-@node Look and Feel
-@chapter Protect Your Freedom---Fight ``Look And Feel''
-@c the above chapter heading overflows onto the next line. --mew 1/26/93
-
-@quotation
-@i{This section is a political message from the League for Programming
-Freedom to the users of GNU CC. We have included it here because the
-issue of interface copyright is important to the GNU project.}
-@end quotation
-
-Apple, Lotus, and now CDC have tried to create a new form of legal
-monopoly: a copyright on a user interface.
-
-An interface is a kind of language---a set of conventions for
-communication between two entities, human or machine. Until a few years
-ago, the law seemed clear: interfaces were outside the domain of
-copyright, so programmers could program freely and implement whatever
-interface the users demanded. Imitating de-facto standard interfaces,
-sometimes with improvements, was standard practice in the computer
-field. These improvements, if accepted by the users, caught on and
-became the norm; in this way, much progress took place.
-
-Computer users, and most software developers, were happy with this state
-of affairs. However, large companies such as Apple and Lotus would
-prefer a different system---one in which they can own interfaces and
-thereby rid themselves of all serious competitors. They hope that
-interface copyright will give them, in effect, monopolies on major
-classes of software.
-
-Other large companies such as IBM and Digital also favor interface
-monopolies, for the same reason: if languages become property, they
-expect to own many de-facto standard languages. But Apple and Lotus are
-the ones who have actually sued. Apple's lawsuit was defeated, for
-reasons only partly related to the general issue of interface copyright.
-
-Lotus won lawsuits against two small companies, which were thus put out
-of business. Then Lotus sued Borland; Lotus won in the trial court (no
-surprise, since it was the same court that had ruled for Lotus twice
-before), but the court of appeals ruled in favor of Borland, which was
-assisted by a friend-of-the-court brief from the League for Programming
-Freedom.
-
-Lotus appealed the case to the Supreme Court, which heard the case but
-was unable to reach a decision. This failure means that the appeals
-court decision stands, in one portion of the United States, and may
-influence the other appeals courts, but it does not set a nationwide
-precedent. The battle is not over, and it is not limited to the United
-States.
-
-The battle is extending into other areas of software as well. In 1995 a
-company that produced a simulator for a CDC computer was shut down by a
-copyright lawsuit, in which CDC charged that the simulator infringed the
-copyright on the manuals for the computer.
-
-If the monopolists get their way, they will hobble the software field:
-
-@itemize @bullet
-@item
-Gratuitous incompatibilities will burden users. Imagine if each car
-manufacturer had to design a different way to start, stop, and steer a
-car.
-
-@item
-Users will be ``locked in'' to whichever interface they learn; then they
-will be prisoners of one supplier, who will charge a monopolistic price.
-
-@item
-Large companies have an unfair advantage wherever lawsuits become
-commonplace. Since they can afford to sue, they can intimidate smaller
-developers with threats even when they don't really have a case.
-
-@item
-Interface improvements will come slower, since incremental evolution
-through creative partial imitation will no longer occur.
-@end itemize
-
-If interface monopolies are accepted, other large companies are waiting
-to grab theirs:
-
-@itemize @bullet
-@item
-Adobe is expected to claim a monopoly on the interfaces of various
-popular application programs, if Lotus ultimately wins the case against
-Borland.
-
-@item
-Open Computing magazine reported a Microsoft vice president as threatening
-to sue people who imitate the interface of Windows.
-@end itemize
-
-Users invest a great deal of time and money in learning to use computer
-interfaces. Far more, in fact, than software developers invest in
-developing @emph{and even implementing} the interfaces. Whoever can own
-an interface, has made its users into captives, and misappropriated
-their investment.
-
-To protect our freedom from monopolies like these, a group of
-programmers and users have formed a grass-roots political organization,
-the League for Programming Freedom.
-
-The purpose of the League is to oppose monopolistic practices such as
-interface copyright and software patents. The League calls for a return
-to the legal policies of the recent past, in which programmers could
-program freely. The League is not concerned with free software as an
-issue, and is not affiliated with the Free Software Foundation.
-
-The League's activities include publicizing the issues, as is being done
-here, and filing friend-of-the-court briefs on behalf of defendants sued
-by monopolists.
-
-The League's membership rolls include Donald Knuth, the foremost
-authority on algorithms, John McCarthy, inventor of Lisp, Marvin Minsky,
-founder of the MIT Artificial Intelligence lab, Guy L. Steele, Jr.,
-author of well-known books on Lisp and C, as well as Richard Stallman,
-the developer of GNU CC. Please join and add your name to the list.
-Membership dues in the League are $42 per year for programmers, managers
-and professionals; $10.50 for students; $21 for others.
-
-Activist members are especially important, but members who have no time
-to give are also important. Surveys at major ACM conferences have
-indicated a vast majority of attendees agree with the League on both
-issues (interface copyrights and software patents). If just ten percent
-of the programmers who agree with the League join the League, we will
-probably triumph.
-
-To join, or for more information, phone (617) 243-4091 or write to:
-
-@display
-League for Programming Freedom
-1 Kendall Square #143
-P.O. Box 9171
-Cambridge, MA 02139
-@end display
-
-You can also send electronic mail to @code{lpf@@uunet.uu.net}.
-
-In addition to joining the League, here are some suggestions from the
-League for other things you can do to protect your freedom to write
-programs:
-
-@itemize @bullet
-@item
-Tell your friends and colleagues about this issue and how it threatens
-to ruin the computer industry.
-
-@item
-Mention that you are a League member in your @file{.signature}, and
-mention the League's email address for inquiries.
-
-@item
-Ask the companies you consider working for or working with to make
-statements against software monopolies, and give preference to those
-that do.
-
-@item
-When employers ask you to sign contracts giving them copyright on your
-work, insist on a clause saying they will not claim the copyright covers
-imitating the interface.
-
-@item
-When employers ask you to sign contracts giving them patent rights,
-insist on clauses saying they can use these rights only defensively.
-Don't rely on ``company policy,'' since that can change at any time;
-don't rely on an individual executive's private word, since that person
-may be replaced. Get a commitment just as binding as the commitment
-they get from you.
-
-@item
-Write to Congress to explain the importance of these issues.
-
-@display
-House Subcommittee on Intellectual Property
-2137 Rayburn Bldg
-Washington, DC 20515
+* Funding:: How to help assure funding for free software.
+* GNU/Linux:: Linux and the GNU Project
-Senate Subcommittee on Patents, Trademarks and Copyrights
-United States Senate
-Washington, DC 20510
-@end display
+* Copying:: GNU General Public License says
+ how you can copy and share GNU CC.
+* Contributors:: People who have contributed to GNU CC.
-(These committees have received lots of mail already; let's give them
-even more.)
-@end itemize
+* Index:: Index of concepts and symbol names.
+@end menu
-Democracy means nothing if you don't use it. Stand up and be counted!
@ifset USING
@node G++ and GCC
@chapter Compile C, C++, or Objective C
@@ -1113,6 +305,8 @@ give you comprehensive C++ source-level editing capabilities
@include extend.texi
+@include gcov.texi
+
@node Trouble
@chapter Known Causes of Trouble with GNU CC
@cindex bugs, known
@@ -1137,7 +331,7 @@ where people's opinions differ as to what is best.
* Incompatibilities:: GNU CC is incompatible with traditional C.
* Fixed Headers:: GNU C uses corrected versions of system header files.
This is necessary, but doesn't always work smoothly.
-* Standard Libraries:: GNU C uses the system C library, which might not be
+* Standard Libraries:: GNU C uses the system C library, which might not be
compliant with the ISO/ANSI C standard.
* Disappointments:: Regrettable things we can't change, but not quite bugs.
* C++ Misunderstandings:: Common misunderstandings with GNU C++.
@@ -1165,7 +359,7 @@ edit the offending file and place the typedef in front of the
prototypes.
@item
-There are several obscure case of mis-using struct, union, and
+There are several obscure case of mis-using struct, union, and
enum tags that are not detected as errors by the compiler.
@item
@@ -1242,12 +436,12 @@ causes errors while linking @code{enquire}, which is part of building
GNU CC. The fix is to get rid of the file @code{real-ld} which purify
installs---so that GNU CC won't try to use it.
-@item
-On SLS 1.01, a Linux-based GNU system, there is a problem with
-@file{libc.a}: it does not contain the obstack functions. However, GNU
-CC assumes that the obstack functions are in @file{libc.a} when it is
-the GNU C library. To work around this problem, change the
-@code{__GNU_LIBRARY__} conditional around line 31 to @samp{#if 1}.
+@item
+On GNU/Linux SLS 1.01, there is a problem with @file{libc.a}: it does not
+contain the obstack functions. However, GNU CC assumes that the obstack
+functions are in @file{libc.a} when it is the GNU C library. To work
+around this problem, change the @code{__GNU_LIBRARY__} conditional
+around line 31 to @samp{#if 1}.
@item
On some 386 systems, building the compiler never finishes because
@@ -1331,7 +525,7 @@ documentation.
For Solaris 2.0 and 2.1, GNU CC needs six packages: @samp{SUNWarc},
@samp{SUNWbtool}, @samp{SUNWesu}, @samp{SUNWhea}, @samp{SUNWlibm}, and
-@samp{SUNWtoo}.
+@samp{SUNWtoo}.
For Solaris 2.2, GNU CC needs an additional seventh package: @samp{SUNWsprot}.
@@ -1400,7 +594,7 @@ On System V release 3, you may get this error message
while linking:
@smallexample
-ld fatal: failed to write symbol name @var{something}
+ld fatal: failed to write symbol name @var{something}
in strings table for file @var{whatever}
@end smallexample
@@ -1774,8 +968,8 @@ with GNU CC. Specifically, it fails to work on functions that use
generate HP-UX unwind descriptors for such functions. It may even be
impossible to generate them.
-@item
-Debugging (@samp{-g}) is not supported on the HP PA machine, unless you use
+@item
+Debugging (@samp{-g}) is not supported on the HP PA machine, unless you use
the preliminary GNU tools (@pxref{Installation}).
@item
@@ -1928,7 +1122,7 @@ the ordinary C compiler. If you do so, you must specify the following
options:
@smallexample
--L/usr/local/lib/gcc-lib/we32k-att-sysv/2.7.1 -lgcc -lc_s
+-L/usr/local/lib/gcc-lib/we32k-att-sysv/2.8.1 -lgcc -lc_s
@end smallexample
The first specifies where to find the library @file{libgcc.a}
@@ -1983,7 +1177,7 @@ header files by adding this:
@item
If you have trouble compiling Perl on a SunOS 4 system, it may be
because Perl specifies @samp{-I/usr/ucbinclude}. This accesses the
-unfixed header files. Perl specifies the options
+unfixed header files. Perl specifies the options
@example
-traditional -Dvolatile=__volatile__
@@ -2012,7 +1206,7 @@ If you have installed GNU malloc as a separate library package, use this
option when you relink GNU CC:
@example
-MALLOC=/usr/local/lib/libgmalloc.a
+MALLOC=/usr/local/lib/libgmalloc.a
@end example
Alternatively, if you have compiled @file{gmalloc.c} from Emacs 19, copy
@@ -2252,7 +1446,7 @@ operator. Actually, this string is a single @dfn{preprocessing token}.
Each such token must correspond to one token in C. Since this does not,
GNU C prints an error message. Although it may appear obvious that what
is meant is an operator and two values, the ANSI C standard specifically
-requires that this be treated as erroneous.
+requires that this be treated as erroneous.
A @dfn{preprocessing token} is a @dfn{preprocessing number} if it
begins with a digit and is followed by letters, underscores, digits,
@@ -2412,11 +1606,12 @@ directory and delete the files @file{stmp-fixinc} and
@samp{make install} again.
@item
-On 68000 systems, you can get paradoxical results if you test the
-precise values of floating point numbers. For example, you can find
-that a floating point value which is not a NaN is not equal to itself.
-This results from the fact that the the floating point registers hold a
-few more bits of precision than fit in a @code{double} in memory.
+@cindex floating point precision
+On 68000 and x86 systems, for instance, you can get paradoxical results
+if you test the precise values of floating point numbers. For example,
+you can find that a floating point value which is not a NaN is not equal
+to itself. This results from the fact that the floating point registers
+hold a few more bits of precision than fit in a @code{double} in memory.
Compiled code moves values between memory and floating point registers
at its convenience, and moving them into memory truncates them.
@@ -2433,6 +1628,13 @@ floating point register, rather than an integer register.
If the code is rewritten to use the ANSI standard @file{stdarg.h}
method of variable arguments, and the prototype is in scope at
the time of the call, everything will work fine.
+
+@item
+On the H8/300 and H8/300H, variable argument functions must be
+implemented using the ANSI standard @file{stdarg.h} method of
+variable arguments. Furthermore, calls to functions using @file{stdarg.h}
+variable arguments must have a prototype for the called function
+in scope at the time of the call.
@end itemize
@node C++ Misunderstandings
@@ -2442,7 +1644,7 @@ the time of the call, everything will work fine.
@cindex surprises in C++
@cindex C++ misunderstandings
C++ is a complex language and an evolving one, and its standard definition
-(the ANSI C++ draft standard) is also evolving. As a result,
+(the ANSI C++ draft standard) is also evolving. As a result,
your C++ compiler may occasionally surprise you, even when its behavior is
correct. This section discusses some areas that frequently give rise to
questions of this sort.
@@ -2590,7 +1792,7 @@ them manually.
@item
@code{protoize} cannot get the argument types for a function whose
definition was not actually compiled due to preprocessing conditionals.
-When this happens, @code{protoize} changes nothing in regard to such
+When this happens, @code{protoize} changes nothing in regard to such
a function. @code{protoize} tries to detect such instances and warn
about them.
@@ -2634,7 +1836,7 @@ This section lists changes that people frequently request, but which
we do not make because we think GNU CC is better without them.
@itemize @bullet
-@item
+@item
Checking the number and type of arguments to a function which has an
old-fashioned definition and no prototype.
@@ -2644,7 +1846,7 @@ only way to check all calls reliably is to add a prototype for the
function. But adding a prototype eliminates the motivation for this
feature. So the feature is not worthwhile.
-@item
+@item
Warning about using an expression whose type is signed as a shift count.
Shift count operands are probably signed more often than unsigned.
@@ -2656,7 +1858,7 @@ Warning about assigning a signed value to an unsigned variable.
Such assignments must be very common; warning about them would cause
more annoyance than good.
-@item
+@item
Warning about unreachable code.
It's very common to have unreachable code in machine-generated
@@ -2773,6 +1975,14 @@ compilers such as plain @samp{gcc}. Whatever the ANSI C standard says
is relevant to the design of plain @samp{gcc} without @samp{-ansi} only
for pragmatic reasons, not as a requirement.
+GNU CC normally defines @code{__STDC__} to be 1, and in addition
+defines @code{__STRICT_ANSI__} if you specify the @samp{-ansi} option.
+On some hosts, system include files use a different convention, where
+@code{__STDC__} is normally 0, but is 1 if the user specifies strict
+conformance to the C Standard. GNU CC follows the host convention when
+processing system include files, but when processing user files it follows
+the usual GNU C convention.
+
@item
Undefining @code{__STDC__} in C++.
@@ -2842,7 +2052,7 @@ The GNU compiler can produce two kinds of diagnostics: errors and
warnings. Each kind has a different purpose:
@itemize @w{}
-@item
+@item
@emph{Errors} report problems that make it impossible to compile your
program. GNU CC reports errors with the source file name and line
number where the problem is apparent.
@@ -2894,7 +2104,7 @@ better. Bug reports are your contribution to the maintenance of GNU CC.
Since the maintainers are very overloaded, we cannot respond to every
bug report. However, if the bug has not been fixed, we are likely to
-send you a patch and ask you to tell us whether it works.
+send you a patch and ask you to tell us whether it works.
In order for a bug report to serve its purpose, you must include the
information that makes for fixing the bug.
@@ -2978,24 +2188,13 @@ for improvement of GNU CC or GNU C++ are welcome in any case.
@node Bug Lists
@section Where to Report Bugs
@cindex bug report mailing lists
-@kindex bug-gcc@@prep.ai.mit.edu
-Send bug reports for GNU C to @samp{bug-gcc@@prep.ai.mit.edu}.
-
-@kindex bug-g++@@prep.ai.mit.edu
-@kindex bug-libg++@@prep.ai.mit.edu
-Send bug reports for GNU C++ to @samp{bug-g++@@prep.ai.mit.edu}.
-If your bug involves the C++ class library libg++, send mail to
-@samp{bug-lib-g++@@prep.ai.mit.edu}. If you're not sure, you can send
-the bug report to both lists.
-
-@strong{Do not send bug reports to @samp{help-gcc@@prep.ai.mit.edu} or
-to the newsgroup @samp{gnu.gcc.help}.} Most users of GNU CC do not want
-to receive bug reports. Those that do, have asked to be on
-@samp{bug-gcc} and/or @samp{bug-g++}.
+@kindex egcs-bugs@@egcs.cygnus.com
+Send bug reports for GNU C to @samp{egcs-bugs@@egcs.cygnus.com}.
-The mailing lists @samp{bug-gcc} and @samp{bug-g++} both have newsgroups
-which serve as repeaters: @samp{gnu.gcc.bug} and @samp{gnu.g++.bug}.
-Each mailing list and its newsgroup carry exactly the same messages.
+@kindex egcs-bugs@@egcs.cygnus.com
+@kindex egcs-bugs@@egcs.cygnus.com
+Send bug reports for GNU C++ and the C++ runtime libraries to
+@samp{egcs-bugs@@egcs.cygnus.com}.
Often people think of posting bug reports to the newsgroup instead of
mailing them. This appears to work, but it has one problem which can be
@@ -3049,11 +2248,19 @@ Please report each bug in a separate message. This makes it easier for
us to track which bugs have been fixed and to forward your bugs reports
to the appropriate maintainer.
-Do not compress and encode any part of your bug report using programs
-such as @file{uuencode}. If you do so it will slow down the processing
-of your bug. If you must submit multiple large files, use @file{shar},
-which allows us to read your message without having to run any
-decompression programs.
+If you include source code in your message, you can send it as clear
+text if it is small. If the message is larger, you may compress it using
+@file{gzip}, @file{bzip2}, or @file{pkzip}. Please be aware that sending
+compressed files needs an additional binary-safe mechanism such as
+@code{MIME} or @code{uuencode}. There is a 100k message limit on the
+@samp{egcs-bugs@@egcs.cygnus.com} mailing list at the time of this
+writing (March 1999). We're trying to create some mechanism for larger
+bug reports to be submitted; please check the on-line FAQ for more
+up-to-date instructions. Don't think that just posting a URL to the
+code is better, we do want to archive bug reports, and not all
+maintainers have good network connectivity to download large pieces of
+software when they need them; it's much easier for them to have them in
+their mailboxes.
To enable someone to investigate the bug, you should include all these
things:
@@ -3281,7 +2488,7 @@ we should be able to reproduce the crash ourselves.
If you would like to write bug fixes or improvements for the GNU C
compiler, that is very helpful. Send suggested fixes to the bug report
-mailing list, @code{bug-gcc@@prep.ai.mit.edu}.
+mailing list, @code{egcs-bugs@@egcs.cygnus.com}.
Please follow these guidelines so we can study your patches efficiently.
If you don't follow these guidelines, your information might still be
@@ -3401,8 +2608,8 @@ ways to find it:
@itemize @bullet
@item
Send a message to a suitable network mailing list. First try
-@code{bug-gcc@@prep.ai.mit.edu}, and if that brings no response, try
-@code{help-gcc@@prep.ai.mit.edu}.
+@code{egcs-bugs@@egcs.cygnus.com}, and if that brings no response, try
+@code{egcs@@egcs.cygnus.com}.
@item
Look in the service directory for someone who might help you for a fee.
@@ -3410,6 +2617,21 @@ The service directory is found in the file named @file{SERVICE} in the
GNU CC distribution.
@end itemize
+@node Contributing
+@chapter Contributing to GNU CC Development
+
+If you would like to help pretest GNU CC releases to assure they work
+well, or if you would like to work on improving GNU CC, please contact
+the maintainers at @code{egcs@@egcs.cygnus.com}. A pretester should
+be willing to try to investigate bugs as well as report them.
+
+If you'd like to work on improvements, please ask for suggested projects
+or suggest your own ideas. If you have already written an improvement,
+please tell us about it. If you have not yet started work, it is useful
+to contact @code{egcs@@egcs.cygnus.com} before you start; the
+maintainers may be able to suggest ways to make your extension fit in
+better with the rest of GNU CC and with other development plans.
+
@node VMS
@chapter Using GNU CC on VMS
@@ -3448,7 +2670,7 @@ list is suitable for use with a rooted logical.
The next prefix tried is @samp{SYS$SYSROOT:[SYSLIB.]}. This is where
VAX-C header files are traditionally stored.
-@item
+@item
If the include file specification by itself is a valid VMS filename, the
preprocessor then uses this name with no prefix in an attempt to open
the include file.
@@ -3456,7 +2678,7 @@ the include file.
@item
If the file specification is not a valid VMS filename (i.e. does not
contain a device or a directory specifier, and contains a @samp{/}
-character), the preprocessor tries to convert it from Unix syntax to
+character), the preprocessor tries to convert it from Unix syntax to
VMS syntax.
Conversion works like this: the first directory name becomes a device,
@@ -3551,7 +2773,7 @@ feature in a fairly natural way:
asm ("_$$PsectAttributes_GLOBALSYMBOL$$" #NAME) \
= VALUE
#define GLOBALVALUEREF(TYPE,NAME) \
- const TYPE NAME[1] \
+ const TYPE NAME[1] \
asm ("_$$PsectAttributes_GLOBALVALUE$$" #NAME)
#define GLOBALVALUEDEF(TYPE,NAME,VALUE) \
const TYPE NAME[1] \
@@ -3951,14 +3173,14 @@ There are also header files @file{tree.h} and @file{tree.def}
which define the format of the tree representation.@refill
@c Avoiding overfull is tricky here.
-The source files to parse C are
-@file{c-parse.in},
+The source files to parse C are
+@file{c-parse.in},
@file{c-decl.c},
-@file{c-typeck.c},
+@file{c-typeck.c},
@file{c-aux-info.c},
-@file{c-convert.c},
+@file{c-convert.c},
and @file{c-lang.c}
-along with header files
+along with header files
@file{c-lex.h}, and
@file{c-tree.h}.
@@ -3999,15 +3221,15 @@ recursion is detected at this time also. Decisions are made about how
best to arrange loops and how to output @code{switch} statements.
@c Avoiding overfull is tricky here.
-The source files for RTL generation include
+The source files for RTL generation include
@file{stmt.c},
-@file{calls.c},
-@file{expr.c},
+@file{calls.c},
+@file{expr.c},
@file{explow.c},
-@file{expmed.c},
-@file{function.c},
-@file{optabs.c}
-and @file{emit-rtl.c}.
+@file{expmed.c},
+@file{function.c},
+@file{optabs.c}
+and @file{emit-rtl.c}.
Also, the file
@file{insn-emit.c}, generated from the machine description by the
program @code{genemit}, is used in this pass. The header file
@@ -4092,6 +3314,22 @@ The option @samp{-ds} causes a debugging dump of the RTL code after
this pass. This dump file's name is made by appending @samp{.cse} to
the input file name.
+@cindex global common subexpression elimination
+@cindex constant propagation
+@cindex copy propagation
+@item
+Global common subexpression elimination. This pass performs GCSE
+using Morel-Renvoise Partial Redundancy Elimination, with the exception
+that it does not try to move invariants out of loops - that is left to
+the loop optimization pass. This pass also performs global constant
+and copy propagation.
+
+The source file for this pass is gcse.c.
+
+The option @samp{-dG} causes a debugging dump of the RTL code after
+this pass. This dump file's name is made by appending @samp{.gcse} to
+the input file name.
+
@cindex loop optimization
@cindex code motion
@cindex strength-reduction
@@ -4243,7 +3481,7 @@ to the input file name.
@item
Delayed branch scheduling. This optional pass attempts to find
instructions that can go into the delay slots of other instructions,
-usually jumps and calls. The source file name is @file{reorg.c}.
+usually jumps and calls. The source file name is @file{reorg.c}.
The option @samp{-dd} causes a debugging dump of the RTL code after
this pass. This dump file's name is made by appending @samp{.dbr}
@@ -4467,12 +3705,6 @@ Define this macro to indicate that the host compiler does not properly
handle converting a function value to a pointer-to-function when it is
used in an expression.
-@findex HAVE_VPRINTF
-@findex vprintf
-@item HAVE_VPRINTF
-Define this if the library function @code{vprintf} is available on your
-system.
-
@findex MULTIBYTE_CHARS
@item MULTIBYTE_CHARS
Define this macro to enable support for multibyte characters in the
@@ -4480,12 +3712,6 @@ input to GNU CC. This requires that the host system support the ANSI C
library functions for converting multibyte characters to wide
characters.
-@findex HAVE_PUTENV
-@findex putenv
-@item HAVE_PUTENV
-Define this if the library function @code{putenv} is available on your
-system.
-
@findex POSIX
@item POSIX
Define this if your system is POSIX.1 compliant.
@@ -4495,10 +3721,18 @@ Define this if your system is POSIX.1 compliant.
Define this if your system @emph{does not} provide the variable
@code{sys_siglist}.
-@findex DONT_DECLARE_SYS_SIGLIST
-@item DONT_DECLARE_SYS_SIGLIST
-Define this if your system has the variable @code{sys_siglist}, and
-there is already a declaration of it in the system header files.
+@vindex sys_siglist
+Some systems do provide this variable, but with a different name such
+as @code{_sys_siglist}. On these systems, you can define
+@code{sys_siglist} as a macro which expands into the name actually
+provided.
+
+Autoconf normally defines @code{SYS_SIGLIST_DECLARED} when it finds a
+declaration of @code{sys_siglist} in the system header files.
+However, when you define @code{sys_siglist} to a different name
+autoconf will not automatically define @code{SYS_SIGLIST_DECLARED}.
+Therefore, if you define @code{sys_siglist}, you should also define
+@code{SYS_SIGLIST_DECLARED}.
@findex USE_PROTOTYPES
@item USE_PROTOTYPES
@@ -4528,22 +3762,10 @@ no effect. As soon as all of the machine descriptions are
modified to have the appropriate number of arguments, this macro
will be removed.
-@vindex sys_siglist
-Some systems do provide this variable, but with a different name such
-as @code{_sys_siglist}. On these systems, you can define
-@code{sys_siglist} as a macro which expands into the name actually
-provided.
-
-@findex NO_STAB_H
-@item NO_STAB_H
-Define this if your system does not have the include file
-@file{stab.h}. If @samp{USG} is defined, @samp{NO_STAB_H} is
-assumed.
-
@findex PATH_SEPARATOR
@item PATH_SEPARATOR
Define this macro to be a C character constant representing the
-character used to separate components in paths. The default value is.
+character used to separate components in paths. The default value is
the colon character
@findex DIR_SEPARATOR
@@ -4610,7 +3832,7 @@ target dependent variables and targets used in the @file{Makefile}:
@table @code
@findex LIBGCC1
@item LIBGCC1
-The rule to use to build @file{libgcc1.a}.
+The rule to use to build @file{libgcc1.a}.
If your target does not need to use the functions in @file{libgcc1.a},
set this to empty.
@xref{Interface}.
@@ -4635,6 +3857,13 @@ into @file{libgcc.a}.
Special flags used when compiling @file{crtstuff.c}.
@xref{Initialization}.
+@findex CRTSTUFF_T_CFLAGS_S
+@item CRTSTUFF_T_CFLAGS_S
+Special flags used when compiling @file{crtstuff.c} for shared
+linking. Used if you use @file{crtbeginS.o} and @file{crtendS.o}
+in @code{EXTRA-PARTS}.
+@xref{Initialization}.
+
@findex MULTILIB_OPTIONS
@item MULTILIB_OPTIONS
For some targets, invoking GNU CC in different ways produces objects
@@ -4653,9 +3882,9 @@ procedure will build all combinations of compatible options.
For example, if you set @code{MULTILIB_OPTIONS} to @samp{m68000/m68020
msoft-float}, @file{Makefile} will build special versions of
-@file{libgcc.a} using the options @samp{-m68000}, @samp{-m68020},
-@samp{-msoft-float}, @samp{-m68000 -msoft-float}, and @samp{-m68020
--msoft-float}.
+@file{libgcc.a} using the following sets of options: @samp{-m68000},
+@samp{-m68020}, @samp{-msoft-float}, @samp{-m68000 -msoft-float}, and
+@samp{-m68020 -msoft-float}.
@findex MULTILIB_DIRNAMES
@item MULTILIB_DIRNAMES
@@ -4666,7 +3895,7 @@ Write one element in @code{MULTILIB_DIRNAMES} for each element in
default value will be @code{MULTILIB_OPTIONS}, with all slashes treated
as spaces.
-For example, if @code{MULTILIB_OPTIONS} is @samp{m68000/m68020
+For example, if @code{MULTILIB_OPTIONS} is set to @samp{m68000/m68020
msoft-float}, then the default value of @code{MULTILIB_DIRNAMES} is
@samp{m68000 m68020 msoft-float}. You may specify a different value if
you desire a different set of directory names.
@@ -4678,6 +3907,26 @@ option is listed in @code{MULTILIB_OPTIONS}, GNU CC needs to know about
any synonyms. In that case, set @code{MULTILIB_MATCHES} to a list of
items of the form @samp{option=option} to describe all relevant
synonyms. For example, @samp{m68000=mc68000 m68020=mc68020}.
+
+@findex MULTILIB_EXCEPTIONS
+@item MULTILIB_EXCEPTIONS
+Sometimes when there are multiple sets of @code{MULTILIB_OPTIONS} being
+specified, there are combinations that should not be built. In that
+case, set @code{MULTILIB_EXCEPTIONS} to be all of the switch exceptions
+in shell case syntax that should not be built.
+
+For example, in the PowerPC embedded ABI support, it was not desirable
+to build libraries that compiled with the @samp{-mcall-aixdesc} option
+and either of the @samp{-mcall-aixdesc} or @samp{-mlittle} options at
+the same time, and therefore @code{MULTILIB_EXCEPTIONS} is set to
+@code{*mrelocatable/*mcall-aixdesc* *mlittle/*mcall-aixdesc*}.
+
+@findex MULTILIB_EXTRA_OPTS
+@item MULTILIB_EXTRA_OPTS
+Sometimes it is desirable that when building multiple versions of
+@file{libgcc.a} certain options should always be passed on to the
+compiler. In that case, set @code{MULTILIB_EXTRA_OPTS} to be the list
+of options to be used for all builds.
@end table
@node Host Fragment
@@ -4712,6 +3961,734 @@ compilation.
The install program to use.
@end table
+@node Funding
+@unnumbered Funding Free Software
+
+If you want to have more free software a few years from now, it makes
+sense for you to help encourage people to contribute funds for its
+development. The most effective approach known is to encourage
+commercial redistributors to donate.
+
+Users of free software systems can boost the pace of development by
+encouraging for-a-fee distributors to donate part of their selling price
+to free software developers---the Free Software Foundation, and others.
+
+The way to convince distributors to do this is to demand it and expect
+it from them. So when you compare distributors, judge them partly by
+how much they give to free software development. Show distributors
+they must compete to be the one who gives the most.
+
+To make this approach work, you must insist on numbers that you can
+compare, such as, ``We will donate ten dollars to the Frobnitz project
+for each disk sold.'' Don't be satisfied with a vague promise, such as
+``A portion of the profits are donated,'' since it doesn't give a basis
+for comparison.
+
+Even a precise fraction ``of the profits from this disk'' is not very
+meaningful, since creative accounting and unrelated business decisions
+can greatly alter what fraction of the sales price counts as profit.
+If the price you pay is $50, ten percent of the profit is probably
+less than a dollar; it might be a few cents, or nothing at all.
+
+Some redistributors do development work themselves. This is useful too;
+but to keep everyone honest, you need to inquire how much they do, and
+what kind. Some kinds of development make much more long-term
+difference than others. For example, maintaining a separate version of
+a program contributes very little; maintaining the standard version of a
+program for the whole community contributes much. Easy new ports
+contribute little, since someone else would surely do them; difficult
+ports such as adding a new CPU to the GNU C compiler contribute more;
+major new features or packages contribute the most.
+
+By establishing the idea that supporting further development is ``the
+proper thing to do'' when distributing free software for a fee, we can
+assure a steady flow of resources into making more free software.
+
+@display
+Copyright (C) 1994 Free Software Foundation, Inc.
+Verbatim copying and redistribution of this section is permitted
+without royalty; alteration is not permitted.
+@end display
+
+@node GNU/Linux
+@unnumbered Linux and the GNU Project
+
+Many computer users run a modified version of the GNU system every
+day, without realizing it. Through a peculiar turn of events, the
+version of GNU which is widely used today is more often known as
+``Linux'', and many users are not aware of the extent of its
+connection with the GNU Project.
+
+There really is a Linux; it is a kernel, and these people are using
+it. But you can't use a kernel by itself; a kernel is useful only as
+part of a whole system. The system in which Linux is typically used
+is a modified variant of the GNU system---in other words, a Linux-based
+GNU system.
+
+Many users are not fully aware of the distinction between the kernel,
+which is Linux, and the whole system, which they also call ``Linux''.
+The ambiguous use of the name doesn't promote understanding.
+
+Programmers generally know that Linux is a kernel. But since they
+have generally heard the whole system called ``Linux'' as well, they
+often envisage a history which fits that name. For example, many
+believe that once Linus Torvalds finished writing the kernel, his
+friends looked around for other free software, and for no particular
+reason most everything necessary to make a Unix-like system was
+already available.
+
+What they found was no accident---it was the GNU system. The available
+free software added up to a complete system because the GNU Project
+had been working since 1984 to make one. The GNU Manifesto
+had set forth the goal of developing a free Unix-like system, called
+GNU. By the time Linux was written, the system was almost finished.
+
+Most free software projects have the goal of developing a particular
+program for a particular job. For example, Linus Torvalds set out to
+write a Unix-like kernel (Linux); Donald Knuth set out to write a text
+formatter (TeX); Bob Scheifler set out to develop a window system (X
+Windows). It's natural to measure the contribution of this kind of
+project by specific programs that came from the project.
+
+If we tried to measure the GNU Project's contribution in this way,
+what would we conclude? One CD-ROM vendor found that in their ``Linux
+distribution'', GNU software was the largest single contingent, around
+28% of the total source code, and this included some of the essential
+major components without which there could be no system. Linux itself
+was about 3%. So if you were going to pick a name for the system
+based on who wrote the programs in the system, the most appropriate
+single choice would be ``GNU''.
+
+But we don't think that is the right way to consider the question.
+The GNU Project was not, is not, a project to develop specific
+software packages. It was not a project to develop a C compiler,
+although we did. It was not a project to develop a text editor,
+although we developed one. The GNU Project's aim was to develop
+@emph{a complete free Unix-like system}.
+
+Many people have made major contributions to the free software in the
+system, and they all deserve credit. But the reason it is @emph{a
+system}---and not just a collection of useful programs---is because the
+GNU Project set out to make it one. We wrote the programs that were
+needed to make a @emph{complete} free system. We wrote essential but
+unexciting major components, such as the assembler and linker, because
+you can't have a system without them. A complete system needs more
+than just programming tools, so we wrote other components as well,
+such as the Bourne Again SHell, the PostScript interpreter
+Ghostscript, and the GNU C library.
+
+By the early 90s we had put together the whole system aside from the
+kernel (and we were also working on a kernel, the GNU Hurd, which runs
+on top of Mach). Developing this kernel has been a lot harder than we
+expected, and we are still working on finishing it.
+
+Fortunately, you don't have to wait for it, because Linux is working
+now. When Linus Torvalds wrote Linux, he filled the last major gap.
+People could then put Linux together with the GNU system to make a
+complete free system: a Linux-based GNU system (or GNU/Linux system,
+for short).
+
+Putting them together sounds simple, but it was not a trivial job.
+The GNU C library (called glibc for short) needed substantial changes.
+Integrating a complete system as a distribution that would work ``out
+of the box'' was a big job, too. It required addressing the issue of
+how to install and boot the system---a problem we had not tackled,
+because we hadn't yet reached that point. The people who developed
+the various system distributions made a substantial contribution.
+
+The GNU Project supports GNU/Linux systems as well as @emph{the}
+GNU system---even with funds. We funded the rewriting of the
+Linux-related extensions to the GNU C library, so that now they are
+well integrated, and the newest GNU/Linux systems use the current
+library release with no changes. We also funded an early stage of the
+development of Debian GNU/Linux.
+
+We use Linux-based GNU systems today for most of our work, and we hope
+you use them too. But please don't confuse the public by using the
+name ``Linux'' ambiguously. Linux is the kernel, one of the essential
+major components of the system. The system as a whole is more or less
+the GNU system.
+
+@node Copying
+@unnumbered GNU GENERAL PUBLIC LICENSE
+@center Version 2, June 1991
+
+@display
+Copyright @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.
+@end display
+
+@unnumberedsec 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.
+
+@iftex
+@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end iftex
+@ifinfo
+@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+@end ifinfo
+
+@enumerate 0
+@item
+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.
+
+@item
+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.
+
+@item
+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:
+
+@enumerate a
+@item
+You must cause the modified files to carry prominent notices
+stating that you changed the files and the date of any change.
+
+@item
+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.
+
+@item
+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.)
+@end enumerate
+
+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.
+
+@item
+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:
+
+@enumerate a
+@item
+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,
+
+@item
+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,
+
+@item
+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.)
+@end enumerate
+
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@item
+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.
+
+@iftex
+@heading NO WARRANTY
+@end iftex
+@ifinfo
+@center NO WARRANTY
+@end ifinfo
+
+@item
+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.
+
+@item
+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.
+@end enumerate
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+
+@page
+@unnumberedsec 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.
+
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) 19@var{yy} @var{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.
+@end smallexample
+
+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:
+
+@smallexample
+Gnomovision version 69, Copyright (C) 19@var{yy} @var{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.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than @samp{show w} and
+@samp{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:
+
+@smallexample
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+`Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+@var{signature of Ty Coon}, 1 April 1989
+Ty Coon, President of Vice
+@end smallexample
+
+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
+@unnumbered Contributors to GNU CC
+@cindex contributors
+
+In addition to Richard Stallman, several people have written parts
+of GNU CC.
+
+@itemize @bullet
+@item
+The idea of using RTL and some of the optimization ideas came from the
+program PO written at the University of Arizona by Jack Davidson and
+Christopher Fraser. See ``Register Allocation and Exhaustive Peephole
+Optimization'', Software Practice and Experience 14 (9), Sept. 1984,
+857-866.
+
+@item
+Paul Rubin wrote most of the preprocessor.
+
+@item
+Leonard Tower wrote parts of the parser, RTL generator, and RTL
+definitions, and of the Vax machine description.
+
+@item
+Ted Lemon wrote parts of the RTL reader and printer.
+
+@item
+Jim Wilson implemented loop strength reduction and some other
+loop optimizations.
+
+@item
+Nobuyuki Hikichi of Software Research Associates, Tokyo, contributed
+the support for the Sony NEWS machine.
+
+@item
+Charles LaBrec contributed the support for the Integrated Solutions
+68020 system.
+
+@item
+Michael Tiemann of Cygnus Support wrote the front end for C++, as well
+as the support for inline functions and instruction scheduling. Also
+the descriptions of the National Semiconductor 32000 series cpu, the
+SPARC cpu and part of the Motorola 88000 cpu.
+
+@item
+Gerald Baumgartner added the signature extension to the C++ front-end.
+
+@item
+Jan Stein of the Chalmers Computer Society provided support for
+Genix, as well as part of the 32000 machine description.
+
+@item
+Randy Smith finished the Sun FPA support.
+
+@item
+Robert Brown implemented the support for Encore 32000 systems.
+
+@item
+David Kashtan of SRI adapted GNU CC to VMS.
+
+@item
+Alex Crain provided changes for the 3b1.
+
+@item
+Greg Satz and Chris Hanson assisted in making GNU CC work on HP-UX for
+the 9000 series 300.
+
+@item
+William Schelter did most of the work on the Intel 80386 support.
+
+@item
+Christopher Smith did the port for Convex machines.
+
+@item
+Paul Petersen wrote the machine description for the Alliant FX/8.
+
+@item
+Dario Dariol contributed the four varieties of sample programs
+that print a copy of their source.
+
+@item
+Alain Lichnewsky ported GNU CC to the Mips cpu.
+
+@item
+Devon Bowen, Dale Wiles and Kevin Zachmann ported GNU CC to the Tahoe.
+
+@item
+Jonathan Stone wrote the machine description for the Pyramid computer.
+
+@item
+Gary Miller ported GNU CC to Charles River Data Systems machines.
+
+@item
+Richard Kenner of the New York University Ultracomputer Research
+Laboratory wrote the machine descriptions for the AMD 29000, the DEC
+Alpha, the IBM RT PC, and the IBM RS/6000 as well as the support for
+instruction attributes. He also made changes to better support RISC
+processors including changes to common subexpression elimination,
+strength reduction, function calling sequence handling, and condition
+code support, in addition to generalizing the code for frame pointer
+elimination.
+
+@item
+Richard Kenner and Michael Tiemann jointly developed reorg.c, the delay
+slot scheduler.
+
+@item
+Mike Meissner and Tom Wood of Data General finished the port to the
+Motorola 88000.
+
+@item
+Masanobu Yuhara of Fujitsu Laboratories implemented the machine
+description for the Tron architecture (specifically, the Gmicro).
+
+@item
+NeXT, Inc.@: donated the front end that supports the Objective C
+language.
+@c We need to be careful to make it clear that "Objective C"
+@c is the name of a language, not that of a program or product.
+
+@item
+James van Artsdalen wrote the code that makes efficient use of
+the Intel 80387 register stack.
+
+@item
+Mike Meissner at the Open Software Foundation finished the port to the
+MIPS cpu, including adding ECOFF debug support, and worked on the
+Intel port for the Intel 80386 cpu. Later at Cygnus Support, he worked
+on the rs6000 and PowerPC ports.
+
+@item
+Ron Guilmette implemented the @code{protoize} and @code{unprotoize}
+tools, the support for Dwarf symbolic debugging information, and much of
+the support for System V Release 4. He has also worked heavily on the
+Intel 386 and 860 support.
+
+@item
+Torbjorn Granlund implemented multiply- and divide-by-constant
+optimization, improved long long support, and improved leaf function
+register allocation.
+
+@item
+Mike Stump implemented the support for Elxsi 64 bit CPU.
+
+@item
+John Wehle added the machine description for the Western Electric 32000
+processor used in several 3b series machines (no relation to the
+National Semiconductor 32000 processor).
+
+@ignore @c These features aren't advertised yet, since they don't fully work.
+@item
+Analog Devices helped implement the support for complex data types
+and iterators.
+@end ignore
+
+@item
+Holger Teutsch provided the support for the Clipper cpu.
+
+@item
+Kresten Krab Thorup wrote the run time support for the Objective C
+language.
+
+@item
+Stephen Moshier contributed the floating point emulator that assists in
+cross-compilation and permits support for floating point numbers wider
+than 64 bits.
+
+@item
+David Edelsohn contributed the changes to RS/6000 port to make it
+support the PowerPC and POWER2 architectures.
+
+@item
+Steve Chamberlain wrote the support for the Hitachi SH processor.
+
+@item
+Peter Schauer wrote the code to allow debugging to work on the Alpha.
+
+@item
+Oliver M. Kellogg of Deutsche Aerospace contributed the port to the
+MIL-STD-1750A.
+
+@item
+Michael K. Gschwind contributed the port to the PDP-11.
+
+@item
+David Reese of Sun Microsystems contributed to the Solaris on PowerPC
+port.
+@end itemize
+
@node Index
@unnumbered Index
@end ifset
@@ -4722,6 +4699,7 @@ The install program to use.
@end ifclear
@printindex cp
+
@summarycontents
@contents
@bye
diff --git a/contrib/gcc/gcov-io.h b/contrib/gcc/gcov-io.h
new file mode 100644
index 0000000..c2949a3
--- /dev/null
+++ b/contrib/gcc/gcov-io.h
@@ -0,0 +1,142 @@
+/* Machine-independent I/O routines for gcov.
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Bob Manson <manson@cygnus.com>.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#ifndef GCOV_IO_H
+#define GCOV_IO_H
+#include <stdio.h>
+#include <sys/types.h>
+
+static int __fetch_long PROTO ((long *, char *, int));
+static int __store_long PROTO ((long, char *, size_t));
+static int __read_long PROTO ((long *, FILE *, size_t));
+static int __write_long PROTO ((long, FILE *, size_t));
+
+/* These routines only work for signed values. */
+
+/* Store a portable representation of VALUE in DEST using BYTES*8-1 bits.
+ Return a non-zero value if VALUE requires more than BYTES*8-1 bits
+ to store. */
+
+static int
+__store_long (value, dest, bytes)
+ long value;
+ char *dest;
+ size_t bytes;
+{
+ int upper_bit = (value < 0 ? 128 : 0);
+ size_t i;
+
+ if (value < 0)
+ {
+ long oldvalue = value;
+ value = -value;
+ if (oldvalue != -value)
+ return 1;
+ }
+
+ for(i = 0 ; i < (sizeof (value) < bytes ? sizeof (value) : bytes) ; i++) {
+ dest[i] = value & (i == (bytes - 1) ? 127 : 255);
+ value = value / 256;
+ }
+
+ if (value && value != -1)
+ return 1;
+
+ for(; i < bytes ; i++)
+ dest[i] = 0;
+ dest[bytes - 1] |= upper_bit;
+ return 0;
+}
+
+/* Retrieve a quantity containing BYTES*8-1 bits from SOURCE and store
+ the result in DEST. Returns a non-zero value if the value in SOURCE
+ will not fit in DEST. */
+
+static int
+__fetch_long (dest, source, bytes)
+ long *dest;
+ char *source;
+ int bytes;
+{
+ long value = 0;
+ int i;
+
+ for (i = bytes - 1; i > (sizeof (*dest) - 1); i--)
+ if (source[i] & (i == (bytes - 1) ? 127 : 255 ))
+ return 1;
+
+ for (; i >= 0; i--)
+ value = value * 256 + (source[i] & (i == (bytes - 1) ? 127 : 255));
+
+ if ((source[bytes - 1] & 128) && (value > 0))
+ value = - value;
+
+ *dest = value;
+ return 0;
+}
+
+/* Write a BYTES*8-bit quantity to FILE, portably. Returns a non-zero
+ value if the write fails, or if VALUE can't be stored in BYTES*8
+ bits.
+
+ Note that VALUE may not actually be large enough to hold BYTES*8
+ bits, but BYTES characters will be written anyway.
+
+ BYTES may be a maximum of 10. */
+
+static int
+__write_long (value, file, bytes)
+ long value;
+ FILE *file;
+ size_t bytes;
+{
+ char c[10];
+
+ if (bytes > 10 || __store_long (value, c, bytes))
+ return 1;
+ else
+ return fwrite(c, 1, bytes, file) != bytes;
+}
+
+/* Read a quantity containing BYTES bytes from FILE, portably. Return
+ a non-zero value if the read fails or if the value will not fit
+ in DEST.
+
+ Note that DEST may not be large enough to hold all of the requested
+ data, but the function will read BYTES characters anyway.
+
+ BYTES may be a maximum of 10. */
+
+static int
+__read_long (dest, file, bytes)
+ long *dest;
+ FILE *file;
+ size_t bytes;
+{
+ char c[10];
+
+ if (bytes > 10 || fread(c, 1, bytes, file) != bytes)
+ return 1;
+ else
+ return __fetch_long (dest, c, bytes);
+}
+
+#endif
diff --git a/contrib/gcc/gcov.c b/contrib/gcc/gcov.c
new file mode 100644
index 0000000..eff68f1
--- /dev/null
+++ b/contrib/gcc/gcov.c
@@ -0,0 +1,1375 @@
+/* Gcov.c: prepend line execution counts and branch probabilities to a
+ source file.
+ Copyright (C) 1990, 91, 92, 93, 94, 96, 1997 Free Software Foundation, Inc.
+ Contributed by James E. Wilson of Cygnus Support.
+ Mangled by Bob Manson of Cygnus Support.
+
+Gcov 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, or (at your option)
+any later version.
+
+Gcov 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 Gcov; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ??? The code in final.c that produces the struct bb assumes that there is
+ no padding between the fields. This is not necessary true. The current
+ code can only be trusted if longs and pointers are the same size. */
+
+/* ??? No need to print an execution count on every line, could just print
+ it on the first line of each block, and only print it on a subsequent
+ line in the same block if the count changes. */
+
+/* ??? Print a list of the ten blocks with the highest execution counts,
+ and list the line numbers corresponding to those blocks. Also, perhaps
+ list the line numbers with the highest execution counts, only printing
+ the first if there are several which are all listed in the same block. */
+
+/* ??? Should have an option to print the number of basic blocks, and the
+ percent of them that are covered. */
+
+/* ??? Does not correctly handle the case where two .bb files refer to the
+ same included source file. For example, if one has a short file containing
+ only inline functions, which is then included in two other files, then
+ there will be two .bb files which refer to the include file, but there
+ is no way to get the total execution counts for the included file, can
+ only get execution counts for one or the other of the including files. */
+
+#include "config.h"
+#include "system.h"
+#include <sys/stat.h>
+#include "gansidecl.h"
+
+#include "gcov-io.h"
+
+/* The .bb file format consists of several lists of 4-byte integers
+ which are the line numbers of each basic block in the file. Each
+ list is terminated by a zero. These lists correspond to the basic
+ blocks in the reconstructed program flow graph.
+
+ A line number of -1 indicates that a source file name (padded to a
+ long boundary) follows. The padded file name is followed by
+ another -1 to make it easy to scan past file names. A -2 indicates
+ that a function name (padded to a long boundary) follows; the name
+ is followed by another -2 to make it easy to scan past the function
+ name.
+
+ The .bbg file contains enough info to enable gcov to reconstruct the
+ program flow graph. The first word is the number of basic blocks,
+ the second word is the number of arcs, followed by the list of arcs
+ (source bb, dest bb pairs), then a -1, then the number of instrumented
+ arcs followed by the instrumented arcs, followed by another -1. This
+ is repeated for each function.
+
+ The .da file contains the execution count for each instrumented branch.
+
+ The .bb and .bbg files are created by giving GCC the -ftest-coverage option,
+ and the .da files are created when an executable compiled with
+ -fprofile-arcs is run. */
+
+/* The functions in this file for creating and solution program flow graphs
+ are very similar to functions in the gcc source file profile.c. */
+
+char gcov_version_string[] = "GNU gcov version 1.5\n";
+
+/* This is the size of the buffer used to read in source file lines. */
+
+#define STRING_SIZE 200
+
+/* One copy of this structure is created for each source file mentioned in the
+ .bb file. */
+
+struct sourcefile
+{
+ char *name;
+ int maxlineno;
+ struct sourcefile *next;
+};
+
+/* This points to the head of the sourcefile structure list. */
+
+struct sourcefile *sources;
+
+/* One of these is dynamically created whenever we identify an arc in the
+ function. */
+
+struct adj_list {
+ int source;
+ int target;
+ int arc_count;
+ unsigned int count_valid : 1;
+ unsigned int on_tree : 1;
+ unsigned int fake : 1;
+ unsigned int fall_through : 1;
+#if 0
+ /* Not needed for gcov, but defined in profile.c. */
+ rtx branch_insn;
+#endif
+ struct adj_list *pred_next;
+ struct adj_list *succ_next;
+};
+
+/* Count the number of basic blocks, and create an array of these structures,
+ one for each bb in the function. */
+
+struct bb_info {
+ struct adj_list *succ;
+ struct adj_list *pred;
+ int succ_count;
+ int pred_count;
+ int exec_count;
+ unsigned int count_valid : 1;
+ unsigned int on_tree : 1;
+#if 0
+ /* Not needed for gcov, but defined in profile.c. */
+ rtx first_insn;
+#endif
+};
+
+/* When outputting branch probabilities, one of these structures is created
+ for each branch/call. */
+
+struct arcdata
+{
+ int prob;
+ int call_insn;
+ struct arcdata *next;
+};
+
+/* Used to save the list of bb_graphs, one per function. */
+
+struct bb_info_list {
+ /* Indexed by block number, holds the basic block graph for one function. */
+ struct bb_info *bb_graph;
+ int num_blocks;
+ struct bb_info_list *next;
+};
+
+/* Holds a list of function basic block graphs. */
+
+static struct bb_info_list *bb_graph_list = 0;
+
+/* Name and file pointer of the input file for the basic block graph. */
+
+static char *bbg_file_name;
+static FILE *bbg_file;
+
+/* Name and file pointer of the input file for the arc count data. */
+
+static char *da_file_name;
+static FILE *da_file;
+
+/* Name and file pointer of the input file for the basic block line counts. */
+
+static char *bb_file_name;
+static FILE *bb_file;
+
+/* Holds the entire contents of the bb_file read into memory. */
+
+static char *bb_data;
+
+/* Size of bb_data array in longs. */
+
+static long bb_data_size;
+
+/* Name and file pointer of the output file. */
+
+static char *gcov_file_name;
+static FILE *gcov_file;
+
+/* Name of the file mentioned on the command line. */
+
+static char *input_file_name = 0;
+
+/* Output branch probabilities if true. */
+
+static int output_branch_probs = 0;
+
+/* Output a gcov file if this is true. This is on by default, and can
+ be turned off by the -n option. */
+
+static int output_gcov_file = 1;
+
+/* For included files, make the gcov output file name include the name of
+ the input source file. For example, if x.h is included in a.c, then the
+ output file name is a.c.x.h.gcov instead of x.h.gcov. This works only
+ when a single source file is specified. */
+
+static int output_long_names = 0;
+
+/* Output summary info for each function. */
+
+static int output_function_summary = 0;
+
+/* Object directory file prefix. This is the directory where .bb and .bbg
+ files are looked for, if non-zero. */
+
+static char *object_directory = 0;
+
+/* Forward declarations. */
+static void process_args PROTO ((int, char **));
+static void open_files PROTO ((void));
+static void read_files PROTO ((void));
+static void scan_for_source_files PROTO ((void));
+static void output_data PROTO ((void));
+static void print_usage PROTO ((void));
+char * xmalloc ();
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ process_args (argc, argv);
+
+ open_files ();
+
+ read_files ();
+
+ scan_for_source_files ();
+
+ output_data ();
+
+ return 0;
+}
+
+char *
+xmalloc (size)
+ unsigned size;
+{
+ register char *value = (char *) malloc (size);
+ if (value == 0)
+ {
+ fprintf (stderr, "error: virtual memory exhausted");
+ exit (FATAL_EXIT_CODE);
+ }
+ return value;
+}
+
+/* More 'friendly' abort that prints the line and file.
+ config.h can #define abort fancy_abort if you like that sort of thing. */
+
+void
+fancy_abort ()
+{
+ fprintf (stderr, "Internal gcc abort.\n");
+ exit (FATAL_EXIT_CODE);
+}
+
+/* Print a usage message and exit. */
+
+static void
+print_usage ()
+{
+ fprintf (stderr, "gcov [-b] [-v] [-n] [-l] [-f] [-o OBJDIR] file\n");
+ exit (FATAL_EXIT_CODE);
+}
+
+/* Parse the command line. */
+
+static void
+process_args (argc, argv)
+ int argc;
+ char **argv;
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (argv[i][0] == '-')
+ {
+ if (argv[i][1] == 'b')
+ output_branch_probs = 1;
+ else if (argv[i][1] == 'v')
+ fputs (gcov_version_string, stderr);
+ else if (argv[i][1] == 'n')
+ output_gcov_file = 0;
+ else if (argv[i][1] == 'l')
+ output_long_names = 1;
+ else if (argv[i][1] == 'f')
+ output_function_summary = 1;
+ else if (argv[i][1] == 'o' && argv[i][2] == '\0')
+ object_directory = argv[++i];
+ else
+ print_usage ();
+ }
+ else if (! input_file_name)
+ input_file_name = argv[i];
+ else
+ print_usage ();
+ }
+
+ if (! input_file_name)
+ print_usage ();
+}
+
+
+/* Find and open the .bb, .da, and .bbg files. */
+
+static void
+open_files ()
+{
+ int count, objdir_count;
+ char *cptr;
+
+ /* Determine the names of the .bb, .bbg, and .da files. Strip off the
+ extension, if any, and append the new extensions. */
+ count = strlen (input_file_name);
+ if (object_directory)
+ objdir_count = strlen (object_directory);
+ else
+ objdir_count = 0;
+
+ da_file_name = xmalloc (count + objdir_count + 4);
+ bb_file_name = xmalloc (count + objdir_count + 4);
+ bbg_file_name = xmalloc (count + objdir_count + 5);
+
+ if (object_directory)
+ {
+ strcpy (da_file_name, object_directory);
+ strcpy (bb_file_name, object_directory);
+ strcpy (bbg_file_name, object_directory);
+
+ if (object_directory[objdir_count - 1] != '/')
+ {
+ strcat (da_file_name, "/");
+ strcat (bb_file_name, "/");
+ strcat (bbg_file_name, "/");
+ }
+
+ cptr = rindex (input_file_name, '/');
+ if (cptr)
+ {
+ strcat (da_file_name, cptr + 1);
+ strcat (bb_file_name, cptr + 1);
+ strcat (bbg_file_name, cptr + 1);
+ }
+ else
+ {
+ strcat (da_file_name, input_file_name);
+ strcat (bb_file_name, input_file_name);
+ strcat (bbg_file_name, input_file_name);
+ }
+ }
+ else
+ {
+ strcpy (da_file_name, input_file_name);
+ strcpy (bb_file_name, input_file_name);
+ strcpy (bbg_file_name, input_file_name);
+ }
+
+ cptr = rindex (bb_file_name, '.');
+ if (cptr)
+ strcpy (cptr, ".bb");
+ else
+ strcat (bb_file_name, ".bb");
+
+ cptr = rindex (da_file_name, '.');
+ if (cptr)
+ strcpy (cptr, ".da");
+ else
+ strcat (da_file_name, ".da");
+
+ cptr = rindex (bbg_file_name, '.');
+ if (cptr)
+ strcpy (cptr, ".bbg");
+ else
+ strcat (bbg_file_name, ".bbg");
+
+ bb_file = fopen (bb_file_name, "r");
+ if (bb_file == NULL)
+ {
+ fprintf (stderr, "Could not open basic block file %s.\n", bb_file_name);
+ exit (FATAL_EXIT_CODE);
+ }
+
+ /* If none of the functions in the file were executed, then there won't
+ be a .da file. Just assume that all counts are zero in this case. */
+ da_file = fopen (da_file_name, "r");
+ if (da_file == NULL)
+ {
+ fprintf (stderr, "Could not open data file %s.\n", da_file_name);
+ fprintf (stderr, "Assuming that all execution counts are zero.\n");
+ }
+
+ bbg_file = fopen (bbg_file_name, "r");
+ if (bbg_file == NULL)
+ {
+ fprintf (stderr, "Could not open program flow graph file %s.\n",
+ bbg_file_name);
+ exit (FATAL_EXIT_CODE);
+ }
+
+ /* Check for empty .bbg file. This indicates that there is no executable
+ code in this source file. */
+ /* Set the EOF condition if at the end of file. */
+ ungetc (getc (bbg_file), bbg_file);
+ if (feof (bbg_file))
+ {
+ fprintf (stderr, "No executable code associated with file %s.\n",
+ input_file_name);
+ exit (FATAL_EXIT_CODE);
+ }
+}
+
+/* Initialize a new arc. */
+
+static void
+init_arc (arcptr, source, target, bb_graph)
+ struct adj_list *arcptr;
+ int source, target;
+ struct bb_info *bb_graph;
+{
+ arcptr->target = target;
+ arcptr->source = source;
+
+ arcptr->arc_count = 0;
+ arcptr->count_valid = 0;
+ arcptr->on_tree = 0;
+ arcptr->fake = 0;
+ arcptr->fall_through = 0;
+
+ arcptr->succ_next = bb_graph[source].succ;
+ bb_graph[source].succ = arcptr;
+ bb_graph[source].succ_count++;
+
+ arcptr->pred_next = bb_graph[target].pred;
+ bb_graph[target].pred = arcptr;
+ bb_graph[target].pred_count++;
+}
+
+
+/* Reverse the arcs on a arc list. */
+
+static struct adj_list *
+reverse_arcs (arcptr)
+ struct adj_list *arcptr;
+{
+ struct adj_list *prev = 0;
+ struct adj_list *next;
+
+ for ( ; arcptr; arcptr = next)
+ {
+ next = arcptr->succ_next;
+ arcptr->succ_next = prev;
+ prev = arcptr;
+ }
+
+ return prev;
+}
+
+
+/* Construct the program flow graph from the .bbg file, and read in the data
+ in the .da file. */
+
+static void
+create_program_flow_graph (bptr)
+ struct bb_info_list *bptr;
+{
+ long num_blocks, number_arcs, src, dest, flag_bits, num_arcs_per_block;
+ int i;
+ struct adj_list *arcptr;
+ struct bb_info *bb_graph;
+
+ /* Read the number of blocks. */
+ __read_long (&num_blocks, bbg_file, 4);
+
+ /* Create an array of size bb number of bb_info structs. Bzero it. */
+ bb_graph = (struct bb_info *) xmalloc (num_blocks
+ * sizeof (struct bb_info));
+ bzero ((char *) bb_graph, sizeof (struct bb_info) * num_blocks);
+
+ bptr->bb_graph = bb_graph;
+ bptr->num_blocks = num_blocks;
+
+ /* Read and create each arc from the .bbg file. */
+ __read_long (&number_arcs, bbg_file, 4);
+ for (i = 0; i < num_blocks; i++)
+ {
+ int j;
+
+ __read_long (&num_arcs_per_block, bbg_file, 4);
+ for (j = 0; j < num_arcs_per_block; j++)
+ {
+ if (number_arcs-- < 0)
+ abort ();
+
+ src = i;
+ __read_long (&dest, bbg_file, 4);
+
+ arcptr = (struct adj_list *) xmalloc (sizeof (struct adj_list));
+ init_arc (arcptr, src, dest, bb_graph);
+
+ __read_long (&flag_bits, bbg_file, 4);
+ arcptr->on_tree = flag_bits & 0x1;
+ arcptr->fake = !! (flag_bits & 0x2);
+ arcptr->fall_through = !! (flag_bits & 0x4);
+ }
+ }
+
+ if (number_arcs)
+ abort ();
+
+ /* Read and ignore the -1 separating the arc list from the arc list of the
+ next function. */
+ __read_long (&src, bbg_file, 4);
+ if (src != -1)
+ abort ();
+
+ /* Must reverse the order of all succ arcs, to ensure that they match
+ the order of the data in the .da file. */
+
+ for (i = 0; i < num_blocks; i++)
+ if (bb_graph[i].succ)
+ bb_graph[i].succ = reverse_arcs (bb_graph[i].succ);
+
+ /* For each arc not on the spanning tree, set its execution count from
+ the .da file. */
+
+ /* The first count in the .da file is the number of times that the function
+ was entered. This is the exec_count for block zero. */
+
+ /* This duplicates code in branch_prob in profile.c. */
+
+ for (i = 0; i < num_blocks; i++)
+ for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
+ if (! arcptr->on_tree)
+ {
+ long tmp_count = 0;;
+ if (da_file && __read_long (&tmp_count, da_file, 8))
+ abort();
+
+ arcptr->arc_count = tmp_count;
+ arcptr->count_valid = 1;
+ bb_graph[i].succ_count--;
+ bb_graph[arcptr->target].pred_count--;
+ }
+}
+
+static void
+solve_program_flow_graph (bptr)
+ struct bb_info_list *bptr;
+{
+ int passes, changes, total;
+ int i;
+ struct adj_list *arcptr;
+ struct bb_info *bb_graph;
+ int num_blocks;
+
+ num_blocks = bptr->num_blocks;
+ bb_graph = bptr->bb_graph;
+
+ /* For every block in the file,
+ - if every exit/entrance arc has a known count, then set the block count
+ - if the block count is known, and every exit/entrance arc but one has
+ a known execution count, then set the count of the remaining arc
+
+ As arc counts are set, decrement the succ/pred count, but don't delete
+ the arc, that way we can easily tell when all arcs are known, or only
+ one arc is unknown. */
+
+ /* The order that the basic blocks are iterated through is important.
+ Since the code that finds spanning trees starts with block 0, low numbered
+ arcs are put on the spanning tree in preference to high numbered arcs.
+ Hence, most instrumented arcs are at the end. Graph solving works much
+ faster if we propagate numbers from the end to the start.
+
+ This takes an average of slightly more than 3 passes. */
+
+ changes = 1;
+ passes = 0;
+ while (changes)
+ {
+ passes++;
+ changes = 0;
+
+ for (i = num_blocks - 1; i >= 0; i--)
+ {
+ if (! bb_graph[i].count_valid)
+ {
+ if (bb_graph[i].succ_count == 0)
+ {
+ total = 0;
+ for (arcptr = bb_graph[i].succ; arcptr;
+ arcptr = arcptr->succ_next)
+ total += arcptr->arc_count;
+ bb_graph[i].exec_count = total;
+ bb_graph[i].count_valid = 1;
+ changes = 1;
+ }
+ else if (bb_graph[i].pred_count == 0)
+ {
+ total = 0;
+ for (arcptr = bb_graph[i].pred; arcptr;
+ arcptr = arcptr->pred_next)
+ total += arcptr->arc_count;
+ bb_graph[i].exec_count = total;
+ bb_graph[i].count_valid = 1;
+ changes = 1;
+ }
+ }
+ if (bb_graph[i].count_valid)
+ {
+ if (bb_graph[i].succ_count == 1)
+ {
+ total = 0;
+ /* One of the counts will be invalid, but it is zero,
+ so adding it in also doesn't hurt. */
+ for (arcptr = bb_graph[i].succ; arcptr;
+ arcptr = arcptr->succ_next)
+ total += arcptr->arc_count;
+ /* Calculate count for remaining arc by conservation. */
+ total = bb_graph[i].exec_count - total;
+ /* Search for the invalid arc, and set its count. */
+ for (arcptr = bb_graph[i].succ; arcptr;
+ arcptr = arcptr->succ_next)
+ if (! arcptr->count_valid)
+ break;
+ if (! arcptr)
+ abort ();
+ arcptr->count_valid = 1;
+ arcptr->arc_count = total;
+ bb_graph[i].succ_count--;
+
+ bb_graph[arcptr->target].pred_count--;
+ changes = 1;
+ }
+ if (bb_graph[i].pred_count == 1)
+ {
+ total = 0;
+ /* One of the counts will be invalid, but it is zero,
+ so adding it in also doesn't hurt. */
+ for (arcptr = bb_graph[i].pred; arcptr;
+ arcptr = arcptr->pred_next)
+ total += arcptr->arc_count;
+ /* Calculate count for remaining arc by conservation. */
+ total = bb_graph[i].exec_count - total;
+ /* Search for the invalid arc, and set its count. */
+ for (arcptr = bb_graph[i].pred; arcptr;
+ arcptr = arcptr->pred_next)
+ if (! arcptr->count_valid)
+ break;
+ if (! arcptr)
+ abort ();
+ arcptr->count_valid = 1;
+ arcptr->arc_count = total;
+ bb_graph[i].pred_count--;
+
+ bb_graph[arcptr->source].succ_count--;
+ changes = 1;
+ }
+ }
+ }
+ }
+
+ /* If the graph has been correctly solved, every block will have a
+ succ and pred count of zero. */
+ for (i = 0; i < num_blocks; i++)
+ if (bb_graph[i].succ_count || bb_graph[i].pred_count)
+ abort ();
+}
+
+
+static void
+read_files ()
+{
+ struct stat buf;
+ struct bb_info_list *list_end = 0;
+ struct bb_info_list *b_ptr;
+ long total;
+
+ /* Read and ignore the first word of the .da file, which is the count of
+ how many numbers follow. */
+ if (da_file && __read_long (&total, da_file, 8))
+ abort();
+
+ while (! feof (bbg_file))
+ {
+ b_ptr = (struct bb_info_list *) xmalloc (sizeof (struct bb_info_list));
+
+ b_ptr->next = 0;
+ if (list_end)
+ list_end->next = b_ptr;
+ else
+ bb_graph_list = b_ptr;
+ list_end = b_ptr;
+
+ /* Read in the data in the .bbg file and reconstruct the program flow
+ graph for one function. */
+ create_program_flow_graph (b_ptr);
+
+ /* Set the EOF condition if at the end of file. */
+ ungetc (getc (bbg_file), bbg_file);
+ }
+
+ /* Check to make sure the .da file data is valid. */
+
+ if (da_file)
+ {
+ if (feof (da_file))
+ fprintf (stderr, ".da file contents exhausted too early\n");
+ /* Should be at end of file now. */
+ if (__read_long (&total, da_file, 8) == 0)
+ fprintf (stderr, ".da file contents not exhausted\n");
+ }
+
+ /* Calculate all of the basic block execution counts and branch
+ taken probabilities. */
+
+ for (b_ptr = bb_graph_list; b_ptr; b_ptr = b_ptr->next)
+ solve_program_flow_graph (b_ptr);
+
+ /* Read in all of the data from the .bb file. This info will be accessed
+ sequentially twice. */
+ stat (bb_file_name, &buf);
+ bb_data_size = buf.st_size / 4;
+
+ bb_data = (char *) xmalloc ((unsigned) buf.st_size);
+ fread (bb_data, sizeof (char), buf.st_size, bb_file);
+
+ fclose (bb_file);
+ if (da_file)
+ fclose (da_file);
+ fclose (bbg_file);
+}
+
+
+/* Scan the data in the .bb file to find all source files referenced,
+ and the largest line number mentioned in each one. */
+
+static void
+scan_for_source_files ()
+{
+ struct sourcefile *s_ptr = NULL;
+ char *ptr;
+ int count;
+ long line_num;
+
+ /* Search the bb_data to find:
+ 1) The number of sources files contained herein, and
+ 2) The largest line number for each source file. */
+
+ ptr = bb_data;
+ sources = 0;
+ for (count = 0; count < bb_data_size; count++)
+ {
+ __fetch_long (&line_num, ptr, 4);
+ ptr += 4;
+ if (line_num == -1)
+ {
+ /* A source file name follows. Check to see if we already have
+ a sourcefile structure for this file. */
+ s_ptr = sources;
+ while (s_ptr && strcmp (s_ptr->name, ptr))
+ s_ptr = s_ptr->next;
+
+ if (s_ptr == 0)
+ {
+ /* No sourcefile structure for this file name exists, create
+ a new one, and append it to the front of the sources list. */
+ s_ptr = (struct sourcefile *) xmalloc (sizeof(struct sourcefile));
+ s_ptr->name = xmalloc (strlen ((char *) ptr) + 1);
+ strcpy (s_ptr->name, (char *) ptr);
+ s_ptr->maxlineno = 0;
+ s_ptr->next = sources;
+ sources = s_ptr;
+ }
+
+ /* Scan past the file name. */
+ {
+ long delim;
+ do {
+ count++;
+ __fetch_long (&delim, ptr, 4);
+ ptr += 4;
+ } while (delim != line_num);
+ }
+ }
+ else if (line_num == -2)
+ {
+ long delim;
+
+ /* A function name follows. Ignore it. */
+ do {
+ count++;
+ __fetch_long (&delim, ptr, 4);
+ ptr += 4;
+ } while (delim != line_num);
+ }
+ /* There will be a zero before the first file name, in which case s_ptr
+ will still be uninitialized. So, only try to set the maxlineno
+ field if line_num is non-zero. */
+ else if (line_num > 0)
+ {
+ if (s_ptr->maxlineno <= line_num)
+ s_ptr->maxlineno = line_num + 1;
+ }
+ else if (line_num < 0)
+ {
+ /* Don't know what this is, but it's garbage. */
+ abort();
+ }
+ }
+}
+
+/* For calculating coverage at the function level. */
+
+static int function_source_lines;
+static int function_source_lines_executed;
+static int function_branches;
+static int function_branches_executed;
+static int function_branches_taken;
+static int function_calls;
+static int function_calls_executed;
+static char *function_name;
+
+/* Calculate the branch taken probabilities for all arcs branches at the
+ end of this block. */
+
+static void
+calculate_branch_probs (current_graph, block_num, branch_probs, last_line_num)
+ struct bb_info_list *current_graph;
+ int block_num;
+ struct arcdata **branch_probs;
+ int last_line_num;
+{
+ int total;
+ struct adj_list *arcptr;
+ struct arcdata *end_ptr, *a_ptr;
+
+ total = current_graph->bb_graph[block_num].exec_count;
+ for (arcptr = current_graph->bb_graph[block_num].succ; arcptr;
+ arcptr = arcptr->succ_next)
+ {
+ /* Ignore fall through arcs as they aren't really branches. */
+
+ if (arcptr->fall_through)
+ continue;
+
+ a_ptr = (struct arcdata *) xmalloc (sizeof (struct arcdata));
+ if (total == 0)
+ a_ptr->prob = -1;
+ else
+ a_ptr->prob = ((arcptr->arc_count * 100) + (total >> 1)) / total;
+ a_ptr->call_insn = arcptr->fake;
+
+ if (output_function_summary)
+ {
+ if (a_ptr->call_insn)
+ {
+ function_calls++;
+ if (a_ptr->prob != -1)
+ function_calls_executed++;
+ }
+ else
+ {
+ function_branches++;
+ if (a_ptr->prob != -1)
+ function_branches_executed++;
+ if (a_ptr->prob > 0)
+ function_branches_taken++;
+ }
+ }
+
+ /* Append the new branch to the end of the list. */
+ a_ptr->next = 0;
+ if (! branch_probs[last_line_num])
+ branch_probs[last_line_num] = a_ptr;
+ else
+ {
+ end_ptr = branch_probs[last_line_num];
+ while (end_ptr->next != 0)
+ end_ptr = end_ptr->next;
+ end_ptr->next = a_ptr;
+ }
+ }
+}
+
+/* Output summary info for a function. */
+
+static void
+function_summary ()
+{
+ if (function_source_lines)
+ fprintf (stdout, "%6.2f%% of %d source lines executed in function %s\n",
+ (((double) function_source_lines_executed / function_source_lines)
+ * 100), function_source_lines, function_name);
+ else
+ fprintf (stdout, "No executable source lines in function %s\n",
+ function_name);
+
+ if (output_branch_probs)
+ {
+ if (function_branches)
+ {
+ fprintf (stdout, "%6.2f%% of %d branches executed in function %s\n",
+ (((double) function_branches_executed / function_branches)
+ * 100), function_branches, function_name);
+ fprintf (stdout,
+ "%6.2f%% of %d branches taken at least once in function %s\n",
+ (((double) function_branches_taken / function_branches)
+ * 100), function_branches, function_name);
+ }
+ else
+ fprintf (stdout, "No branches in function %s\n", function_name);
+ if (function_calls)
+ fprintf (stdout, "%6.2f%% of %d calls executed in function %s\n",
+ (((double) function_calls_executed / function_calls)
+ * 100), function_calls, function_name);
+ else
+ fprintf (stdout, "No calls in function %s\n", function_name);
+ }
+}
+
+/* Calculate line execution counts, and output the data to a .tcov file. */
+
+static void
+output_data ()
+{
+ /* When scanning data, this is true only if the data applies to the
+ current source file. */
+ int this_file;
+ /* An array indexed by line number which indicates how many times that line
+ was executed. */
+ long *line_counts;
+ /* An array indexed by line number which indicates whether the line was
+ present in the bb file (i.e. whether it had code associate with it).
+ Lines never executed are those which both exist, and have zero execution
+ counts. */
+ char *line_exists;
+ /* An array indexed by line number, which contains a list of branch
+ probabilities, one for each branch on that line. */
+ struct arcdata **branch_probs = NULL;
+ struct sourcefile *s_ptr;
+ char *source_file_name;
+ FILE *source_file;
+ struct bb_info_list *current_graph;
+ int count;
+ char *cptr;
+ long block_num;
+ long line_num;
+ long last_line_num = 0;
+ int i;
+ struct arcdata *a_ptr;
+ /* Buffer used for reading in lines from the source file. */
+ char string[STRING_SIZE];
+ /* For calculating coverage at the file level. */
+ int total_source_lines;
+ int total_source_lines_executed;
+ int total_branches;
+ int total_branches_executed;
+ int total_branches_taken;
+ int total_calls;
+ int total_calls_executed;
+
+ /* Now, for each source file, allocate an array big enough to hold a count
+ for each line. Scan through the bb_data, and when the file name matches
+ the current file name, then for each following line number, increment
+ the line number execution count indicated by the execution count of
+ the appropriate basic block. */
+
+ for (s_ptr = sources; s_ptr; s_ptr = s_ptr->next)
+ {
+ /* If this is a relative file name, and an object directory has been
+ specified, then make it relative to the object directory name. */
+ if (*s_ptr->name != '/' && object_directory != 0
+ && *object_directory != '\0')
+ {
+ int objdir_count = strlen (object_directory);
+ source_file_name = xmalloc (objdir_count + strlen (s_ptr->name) + 2);
+ strcpy (source_file_name, object_directory);
+ if (object_directory[objdir_count - 1] != '/')
+ source_file_name[objdir_count++] = '/';
+ strcpy (source_file_name + objdir_count, s_ptr->name);
+ }
+ else
+ source_file_name = s_ptr->name;
+
+ line_counts = (long *) xmalloc (sizeof (long) * s_ptr->maxlineno);
+ bzero ((char *) line_counts, sizeof (long) * s_ptr->maxlineno);
+ line_exists = xmalloc (s_ptr->maxlineno);
+ bzero (line_exists, s_ptr->maxlineno);
+ if (output_branch_probs)
+ {
+ branch_probs = (struct arcdata **) xmalloc (sizeof (struct arcdata **)
+ * s_ptr->maxlineno);
+ bzero ((char *) branch_probs,
+ sizeof (struct arcdata **) * s_ptr->maxlineno);
+ }
+
+ /* There will be a zero at the beginning of the bb info, before the
+ first list of line numbers, so must initialize block_num to 0. */
+ block_num = 0;
+ this_file = 0;
+ current_graph = 0;
+ {
+ /* Pointer into the bb_data, incremented while scanning the data. */
+ char *ptr = bb_data;
+ for (count = 0; count < bb_data_size; count++)
+ {
+ long delim;
+
+ __fetch_long (&line_num, ptr, 4);
+ ptr += 4;
+ if (line_num == -1)
+ {
+ /* Marks the beginning of a file name. Check to see whether
+ this is the filename we are currently collecting data for. */
+
+ if (strcmp (s_ptr->name, ptr))
+ this_file = 0;
+ else
+ this_file = 1;
+
+ /* Scan past the file name. */
+ do {
+ count++;
+ __fetch_long (&delim, ptr, 4);
+ ptr += 4;
+ } while (delim != line_num);
+ }
+ else if (line_num == -2)
+ {
+ /* Marks the start of a new function. Advance to the next
+ program flow graph. */
+
+ if (! current_graph)
+ current_graph = bb_graph_list;
+ else
+ {
+ if (block_num == current_graph->num_blocks - 1)
+ /* Last block falls through to exit. */
+ ;
+ else if (block_num == current_graph->num_blocks - 2)
+ {
+ if (output_branch_probs && this_file)
+ calculate_branch_probs (current_graph, block_num,
+ branch_probs, last_line_num);
+ }
+ else
+ {
+ fprintf (stderr,
+ "didn't use all bb entries of graph, function %s\n",
+ function_name);
+ fprintf (stderr, "block_num = %ld, num_blocks = %d\n",
+ block_num, current_graph->num_blocks);
+ }
+
+ current_graph = current_graph->next;
+ block_num = 0;
+
+ if (output_function_summary && this_file)
+ function_summary ();
+ }
+
+ if (output_function_summary)
+ {
+ function_source_lines = 0;
+ function_source_lines_executed = 0;
+ function_branches = 0;
+ function_branches_executed = 0;
+ function_branches_taken = 0;
+ function_calls = 0;
+ function_calls_executed = 0;
+ }
+
+ /* Save the function name for later use. */
+ function_name = ptr;
+
+ /* Scan past the file name. */
+ do {
+ count++;
+ __fetch_long (&delim, ptr, 4);
+ ptr += 4;
+ } while (delim != line_num);
+ }
+ else if (line_num == 0)
+ {
+ /* Marks the end of a block. */
+
+ if (block_num >= current_graph->num_blocks)
+ {
+ fprintf (stderr, "ERROR: too many basic blocks in .bb file %s\n",
+ function_name);
+ abort ();
+ }
+
+ if (output_branch_probs && this_file)
+ calculate_branch_probs (current_graph, block_num,
+ branch_probs, last_line_num);
+
+ block_num++;
+ }
+ else if (this_file)
+ {
+ if (output_function_summary)
+ {
+ if (line_exists[line_num] == 0)
+ function_source_lines++;
+ if (line_counts[line_num] == 0
+ && current_graph->bb_graph[block_num].exec_count != 0)
+ function_source_lines_executed++;
+ }
+
+ /* Accumulate execution data for this line number. */
+
+ line_counts[line_num]
+ += current_graph->bb_graph[block_num].exec_count;
+ line_exists[line_num] = 1;
+ last_line_num = line_num;
+ }
+ }
+ }
+
+ if (output_function_summary && this_file)
+ function_summary ();
+
+ /* Calculate summary test coverage statistics. */
+
+ total_source_lines = 0;
+ total_source_lines_executed = 0;
+ total_branches = 0;
+ total_branches_executed = 0;
+ total_branches_taken = 0;
+ total_calls = 0;
+ total_calls_executed = 0;
+
+ for (count = 1; count < s_ptr->maxlineno; count++)
+ {
+ if (line_exists[count])
+ {
+ total_source_lines++;
+ if (line_counts[count])
+ total_source_lines_executed++;
+ }
+ if (output_branch_probs)
+ {
+ for (a_ptr = branch_probs[count]; a_ptr; a_ptr = a_ptr->next)
+ {
+ if (a_ptr->call_insn)
+ {
+ total_calls++;
+ if (a_ptr->prob != -1)
+ total_calls_executed++;
+ }
+ else
+ {
+ total_branches++;
+ if (a_ptr->prob != -1)
+ total_branches_executed++;
+ if (a_ptr->prob > 0)
+ total_branches_taken++;
+ }
+ }
+ }
+ }
+
+ if (total_source_lines)
+ fprintf (stdout,
+ "%6.2f%% of %d source lines executed in file %s\n",
+ (((double) total_source_lines_executed / total_source_lines)
+ * 100), total_source_lines, source_file_name);
+ else
+ fprintf (stdout, "No executable source lines in file %s\n",
+ source_file_name);
+
+ if (output_branch_probs)
+ {
+ if (total_branches)
+ {
+ fprintf (stdout, "%6.2f%% of %d branches executed in file %s\n",
+ (((double) total_branches_executed / total_branches)
+ * 100), total_branches, source_file_name);
+ fprintf (stdout,
+ "%6.2f%% of %d branches taken at least once in file %s\n",
+ (((double) total_branches_taken / total_branches)
+ * 100), total_branches, source_file_name);
+ }
+ else
+ fprintf (stdout, "No branches in file %s\n", source_file_name);
+ if (total_calls)
+ fprintf (stdout, "%6.2f%% of %d calls executed in file %s\n",
+ (((double) total_calls_executed / total_calls)
+ * 100), total_calls, source_file_name);
+ else
+ fprintf (stdout, "No calls in file %s\n", source_file_name);
+ }
+
+ if (output_gcov_file)
+ {
+ /* Now the statistics are ready. Read in the source file one line
+ at a time, and output that line to the gcov file preceded by
+ its execution count if non zero. */
+
+ source_file = fopen (source_file_name, "r");
+ if (source_file == NULL)
+ {
+ fprintf (stderr, "Could not open source file %s.\n",
+ source_file_name);
+ free (line_counts);
+ free (line_exists);
+ continue;
+ }
+
+ count = strlen (source_file_name);
+ cptr = rindex (s_ptr->name, '/');
+ if (cptr)
+ cptr = cptr + 1;
+ else
+ cptr = s_ptr->name;
+ if (output_long_names && strcmp (cptr, input_file_name))
+ {
+ gcov_file_name = xmalloc (count + 7 + strlen (input_file_name));
+
+ cptr = rindex (input_file_name, '/');
+ if (cptr)
+ strcpy (gcov_file_name, cptr + 1);
+ else
+ strcpy (gcov_file_name, input_file_name);
+
+ strcat (gcov_file_name, ".");
+
+ cptr = rindex (source_file_name, '/');
+ if (cptr)
+ strcat (gcov_file_name, cptr + 1);
+ else
+ strcat (gcov_file_name, source_file_name);
+ }
+ else
+ {
+ gcov_file_name = xmalloc (count + 6);
+ cptr = rindex (source_file_name, '/');
+ if (cptr)
+ strcpy (gcov_file_name, cptr + 1);
+ else
+ strcpy (gcov_file_name, source_file_name);
+ }
+
+ /* Don't strip off the ending for compatibility with tcov, since
+ this results in confusion if there is more than one file with
+ the same basename, e.g. tmp.c and tmp.h. */
+ strcat (gcov_file_name, ".gcov");
+
+ gcov_file = fopen (gcov_file_name, "w");
+
+ if (gcov_file == NULL)
+ {
+ fprintf (stderr, "Could not open output file %s.\n",
+ gcov_file_name);
+ fclose (source_file);
+ free (line_counts);
+ free (line_exists);
+ continue;
+ }
+
+ fprintf (stdout, "Creating %s.\n", gcov_file_name);
+
+ for (count = 1; count < s_ptr->maxlineno; count++)
+ {
+ char *retval;
+ int len;
+
+ retval = fgets (string, STRING_SIZE, source_file);
+
+ /* For lines which don't exist in the .bb file, print nothing
+ before the source line. For lines which exist but were never
+ executed, print ###### before the source line. Otherwise,
+ print the execution count before the source line. */
+ /* There are 16 spaces of indentation added before the source
+ line so that tabs won't be messed up. */
+ if (line_exists[count])
+ {
+ if (line_counts[count])
+ fprintf (gcov_file, "%12ld %s", line_counts[count],
+ string);
+ else
+ fprintf (gcov_file, " ###### %s", string);
+ }
+ else
+ fprintf (gcov_file, "\t\t%s", string);
+
+ /* In case the source file line is larger than our buffer, keep
+ reading and outputting lines until we get a newline. */
+ len = strlen (string);
+ while ((len == 0 || string[strlen (string) - 1] != '\n')
+ && retval != NULL)
+ {
+ retval = fgets (string, STRING_SIZE, source_file);
+ fputs (string, gcov_file);
+ }
+
+ if (output_branch_probs)
+ {
+ for (i = 0, a_ptr = branch_probs[count]; a_ptr;
+ a_ptr = a_ptr->next, i++)
+ {
+ if (a_ptr->call_insn)
+ {
+ if (a_ptr->prob == -1)
+ fprintf (gcov_file, "call %d never executed\n", i);
+ else
+ fprintf (gcov_file,
+ "call %d returns = %d%%\n",
+ i, 100 - a_ptr->prob);
+ }
+ else
+ {
+ if (a_ptr->prob == -1)
+ fprintf (gcov_file, "branch %d never executed\n",
+ i);
+ else
+ fprintf (gcov_file, "branch %d taken = %d%%\n", i,
+ a_ptr->prob);
+ }
+ }
+ }
+
+ /* Gracefully handle errors while reading the source file. */
+ if (retval == NULL)
+ {
+ fprintf (stderr,
+ "Unexpected EOF while reading source file %s.\n",
+ source_file_name);
+ break;
+ }
+ }
+
+ /* Handle all remaining source lines. There may be lines
+ after the last line of code. */
+
+ {
+ char *retval = fgets (string, STRING_SIZE, source_file);
+ while (retval != NULL)
+ {
+ int len;
+
+ fprintf (gcov_file, "\t\t%s", string);
+
+ /* In case the source file line is larger than our buffer, keep
+ reading and outputting lines until we get a newline. */
+ len = strlen (string);
+ while ((len == 0 || string[strlen (string) - 1] != '\n')
+ && retval != NULL)
+ {
+ retval = fgets (string, STRING_SIZE, source_file);
+ fputs (string, gcov_file);
+ }
+
+ retval = fgets (string, STRING_SIZE, source_file);
+ }
+ }
+
+ fclose (source_file);
+ fclose (gcov_file);
+ }
+
+ free (line_counts);
+ free (line_exists);
+ }
+}
diff --git a/contrib/gcc/gcov.texi b/contrib/gcc/gcov.texi
new file mode 100644
index 0000000..9c6d77d
--- /dev/null
+++ b/contrib/gcc/gcov.texi
@@ -0,0 +1,344 @@
+@c Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+@c This is part of the GCC manual.
+@c For copying conditions, see the file gcc.texi.
+
+@node Gcov
+@chapter @code{gcov}: a Test Coverage Program
+
+@code{gcov} is a tool you can use in conjunction with @sc{gnu} CC to
+test code coverage in your programs.
+
+This chapter describes version 1.5 of @code{gcov}.
+
+@menu
+* Gcov Intro:: Introduction to gcov.
+* Invoking Gcov:: How to use gcov.
+* Gcov and Optimization:: Using gcov with GCC optimization.
+* Gcov Data Files:: The files used by gcov.
+@end menu
+
+@node Gcov Intro
+@section Introduction to @code{gcov}
+
+@code{gcov} is a test coverage program. Use it in concert with @sc{gnu}
+CC to analyze your programs to help create more efficient, faster
+running code. You can use @code{gcov} as a profiling tool to help
+discover where your optimization efforts will best affect your code. You
+can also use @code{gcov} along with the other profiling tool,
+@code{gprof}, to assess which parts of your code use the greatest amount
+of computing time.
+
+Profiling tools help you analyze your code's performance. Using a
+profiler such as @code{gcov} or @code{gprof}, you can find out some
+basic performance statistics, such as:
+
+@itemize @bullet
+@item
+how often each line of code executes
+
+@item
+what lines of code are actually executed
+
+@item
+how much computing time each section of code uses
+@end itemize
+
+Once you know these things about how your code works when compiled, you
+can look at each module to see which modules should be optimized.
+@code{gcov} helps you determine where to work on optimization.
+
+Software developers also use coverage testing in concert with
+testsuites, to make sure software is actually good enough for a release.
+Testsuites can verify that a program works as expected; a coverage
+program tests to see how much of the program is exercised by the
+testsuite. Developers can then determine what kinds of test cases need
+to be added to the testsuites to create both better testing and a better
+final product.
+
+You should compile your code without optimization if you plan to use
+@code{gcov} because the optimization, by combining some lines of code
+into one function, may not give you as much information as you need to
+look for `hot spots' where the code is using a great deal of computer
+time. Likewise, because @code{gcov} accumulates statistics by line (at
+the lowest resolution), it works best with a programming style that
+places only one statement on each line. If you use complicated macros
+that expand to loops or to other control structures, the statistics are
+less helpful---they only report on the line where the macro call
+appears. If your complex macros behave like functions, you can replace
+them with inline functions to solve this problem.
+
+@code{gcov} creates a logfile called @file{@var{sourcefile}.gcov} which
+indicates how many times each line of a source file @file{@var{sourcefile}.c}
+has executed. You can use these logfiles along with @code{gprof} to aid
+in fine-tuning the performance of your programs. @code{gprof} gives
+timing information you can use along with the information you get from
+@code{gcov}.
+
+@code{gcov} works only on code compiled with @sc{gnu} CC. It is not
+compatible with any other profiling or test coverage mechanism.
+
+@node Invoking Gcov
+@section Invoking gcov
+
+@smallexample
+gcov [-b] [-v] [-n] [-l] [-f] [-o directory] @var{sourcefile}
+@end smallexample
+
+@table @code
+@item -b
+Write branch frequencies to the output file, and write branch summary
+info to the standard output. This option allows you to see how often
+each branch in your program was taken.
+
+@item -v
+Display the @code{gcov} version number (on the standard error stream).
+
+@item -n
+Do not create the @code{gcov} output file.
+
+@item -l
+Create long file names for included source files. For example, if the
+header file @samp{x.h} contains code, and was included in the file
+@samp{a.c}, then running @code{gcov} on the file @samp{a.c} will produce
+an output file called @samp{a.c.x.h.gcov} instead of @samp{x.h.gcov}.
+This can be useful if @samp{x.h} is included in multiple source files.
+
+@item -f
+Output summaries for each function in addition to the file level summary.
+
+@item -o
+The directory where the object files live. Gcov will search for @code{.bb},
+@code{.bbg}, and @code{.da} files in this directory.
+@end table
+
+@need 3000
+When using @code{gcov}, you must first compile your program with two
+special @sc{gnu} CC options: @samp{-fprofile-arcs -ftest-coverage}.
+This tells the compiler to generate additional information needed by
+gcov (basically a flow graph of the program) and also includes
+additional code in the object files for generating the extra profiling
+information needed by gcov. These additional files are placed in the
+directory where the source code is located.
+
+Running the program will cause profile output to be generated. For each
+source file compiled with -fprofile-arcs, an accompanying @code{.da}
+file will be placed in the source directory.
+
+Running @code{gcov} with your program's source file names as arguments
+will now produce a listing of the code along with frequency of execution
+for each line. For example, if your program is called @samp{tmp.c}, this
+is what you see when you use the basic @code{gcov} facility:
+
+@smallexample
+$ 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.
+@end smallexample
+
+The file @file{tmp.c.gcov} contains output from @code{gcov}.
+Here is a sample:
+
+@smallexample
+ 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 @}
+@end smallexample
+
+@need 450
+When you use the @samp{-b} option, your output looks like this:
+
+@smallexample
+$ 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.
+@end smallexample
+
+Here is a sample of a resulting @file{tmp.c.gcov} file:
+
+@smallexample
+ 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 @}
+@end smallexample
+
+For each basic block, a line is printed after the last line of the basic
+block describing the branch or call that ends the basic block. There can
+be multiple branches and calls listed for a single source line if there
+are multiple basic blocks that end on that line. In this case, the
+branches and calls are each given a number. There is no simple way to map
+these branches and calls back to source constructs. In general, though,
+the lowest numbered branch or call will correspond to the leftmost construct
+on the source line.
+
+For a branch, if it was executed at least once, then a percentage
+indicating the number of times the branch was taken divided by the
+number of times the branch was executed will be printed. Otherwise, the
+message ``never executed'' is printed.
+
+For a call, if it was executed at least once, then a percentage
+indicating the number of times the call returned divided by the number
+of times the call was executed will be printed. This will usually be
+100%, but may be less for functions call @code{exit} or @code{longjmp},
+and thus may not return everytime they are called.
+
+The execution counts are cumulative. If the example program were
+executed again without removing the @code{.da} file, the count for the
+number of times each line in the source was executed would be added to
+the results of the previous run(s). This is potentially useful in
+several ways. For example, it could be used to accumulate data over a
+number of program runs as part of a test verification suite, or to
+provide more accurate long-term information over a large number of
+program runs.
+
+The data in the @code{.da} files is saved immediately before the program
+exits. For each source file compiled with -fprofile-arcs, the profiling
+code first attempts to read in an existing @code{.da} file; if the file
+doesn't match the executable (differing number of basic block counts) it
+will ignore the contents of the file. It then adds in the new execution
+counts and finally writes the data to the file.
+
+@node Gcov and Optimization
+@section Using @code{gcov} with GCC Optimization
+
+If you plan to use @code{gcov} to help optimize your code, you must
+first compile your program with two special @sc{gnu} CC options:
+@samp{-fprofile-arcs -ftest-coverage}. Aside from that, you can use any
+other @sc{gnu} CC options; but if you want to prove that every single line
+in your program was executed, you should not compile with optimization
+at the same time. On some machines the optimizer can eliminate some
+simple code lines by combining them with other lines. For example, code
+like this:
+
+@smallexample
+if (a != b)
+ c = 1;
+else
+ c = 0;
+@end smallexample
+
+@noindent
+can be compiled into one instruction on some machines. In this case,
+there is no way for @code{gcov} to calculate separate execution counts
+for each line because there isn't separate code for each line. Hence
+the @code{gcov} output looks like this if you compiled the program with
+optimization:
+
+@smallexample
+ 100 if (a != b)
+ 100 c = 1;
+ 100 else
+ 100 c = 0;
+@end smallexample
+
+The output shows that this block of code, combined by optimization,
+executed 100 times. In one sense this result is correct, because there
+was only one instruction representing all four of these lines. However,
+the output does not indicate how many times the result was 0 and how
+many times the result was 1.
+
+@node Gcov Data Files
+@section Brief description of @code{gcov} data files
+
+@code{gcov} uses three files for doing profiling. The names of these
+files are derived from the original @emph{source} file by substituting
+the file suffix with either @code{.bb}, @code{.bbg}, or @code{.da}. All
+of these files are placed in the same directory as the source file, and
+contain data stored in a platform-independent method.
+
+The @code{.bb} and @code{.bbg} files are generated when the source file
+is compiled with the @sc{gnu} CC @samp{-ftest-coverage} option. The
+@code{.bb} file contains a list of source files (including headers),
+functions within those files, and line numbers corresponding to each
+basic block in the source file.
+
+The @code{.bb} file format consists of several lists of 4-byte integers
+which correspond to the line numbers of each basic block in the
+file. Each list is terminated by a line number of 0. A line number of -1
+is used to designate that the source file name (padded to a 4-byte
+boundary and followed by another -1) follows. In addition, a line number
+of -2 is used to designate that the name of a function (also padded to a
+4-byte boundary and followed by a -2) follows.
+
+The @code{.bbg} file is used to reconstruct the program flow graph for
+the source file. It contains a list of the program flow arcs (possible
+branches taken from one basic block to another) for each function which,
+in combination with the @code{.bb} file, enables gcov to reconstruct the
+program flow.
+
+In the @code{.bbg} file, the format is:
+@smallexample
+ number of basic blocks for function #0 (4-byte number)
+ total number of arcs for function #0 (4-byte number)
+ count of arcs in basic block #0 (4-byte number)
+ destination basic block of arc #0 (4-byte number)
+ flag bits (4-byte number)
+ destination basic block of arc #1 (4-byte number)
+ flag bits (4-byte number)
+ ...
+ destination basic block of arc #N (4-byte number)
+ flag bits (4-byte number)
+ count of arcs in basic block #1 (4-byte number)
+ destination basic block of arc #0 (4-byte number)
+ flag bits (4-byte number)
+ ...
+@end smallexample
+
+A -1 (stored as a 4-byte number) is used to separate each function's
+list of basic blocks, and to verify that the file has been read
+correctly.
+
+The @code{.da} file is generated when a program containing object files
+built with the @sc{gnu} CC @samp{-fprofile-arcs} option is executed. A
+separate @code{.da} file is created for each source file compiled with
+this option, and the name of the @code{.da} file is stored as an
+absolute pathname in the resulting object file. This path name is
+derived from the source file name by substituting a @code{.da} suffix.
+
+The format of the @code{.da} file is fairly simple. The first 8-byte
+number is the number of counts in the file, followed by the counts
+(stored as 8-byte numbers). Each count corresponds to the number of
+times each arc in the program is executed. The counts are cumulative;
+each time the program is executed, it attemps to combine the existing
+@code{.da} files with the new counts for this invocation of the
+program. It ignores the contents of any @code{.da} files whose number of
+arcs doesn't correspond to the current program, and merely overwrites
+them instead.
+
+All three of these files use the functions in @code{gcov-io.h} to store
+integers; the functions in this header provide a machine-independent
+mechanism for storing and retrieving data from a stream.
+
diff --git a/contrib/gcc/gcse.c b/contrib/gcc/gcse.c
new file mode 100644
index 0000000..f0efdb7
--- /dev/null
+++ b/contrib/gcc/gcse.c
@@ -0,0 +1,4758 @@
+/* Global common subexpression elimination
+ and global constant/copy propagation for GNU compiler.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* TODO
+ - reordering of memory allocation and freeing to be more space efficient
+ - do rough calc of how many regs are needed in each block, and a rough
+ calc of how many regs are available in each class and use that to
+ throttle back the code in cases where RTX_COST is minimal.
+ - memory aliasing support
+ - ability to realloc sbitmap vectors would allow one initial computation
+ of reg_set_in_block with only subsequent additions, rather than
+ recomputing it for each pass
+
+ NOTES
+ - the classic gcse implementation is kept in for now for comparison
+*/
+
+/* References searched while implementing this.
+ This list will eventually be deleted but I wanted to have a record of it
+ for now.
+
+ Compilers Principles, Techniques and Tools
+ Aho, Sethi, Ullman
+ Addison-Wesley, 1988
+
+ Global Optimization by Suppression of Partial Redundancies
+ E. Morel, C. Renvoise
+ communications of the acm, Vol. 22, Num. 2, Feb. 1979
+
+ A Portable Machine-Independent Global Optimizer - Design and Measurements
+ Frederick Chow
+ Stanford Ph.D. thesis, Dec. 1983
+
+xxx
+ Elimination Algorithms for Data Flow Analysis
+ B.G. Ryder, M.C. Paull
+ ACM Computing Surveys, Vol. 18, Num. 3, Sep. 1986
+
+reread
+ A Fast Algorithm for Code Movement Optimization
+ D.M. Dhamdhere
+ SIGPLAN Notices, Vol. 23, Num. 10, Oct. 1988
+
+ A Solution to a Problem with Morel and Renvoise's
+ Global Optimization by Suppression of Partial Redundancies
+ K-H Drechsler, M.P. Stadel
+ ACM TOPLAS, Vol. 10, Num. 4, Oct. 1988
+
+ Practical Adaptation of the Global Optimization
+ Algorithm of Morel and Renvoise
+ D.M. Dhamdhere
+ ACM TOPLAS, Vol. 13, Num. 2. Apr. 1991
+
+ Efficiently Computing Static Single Assignment Form and the Control
+ Dependence Graph
+ R. Cytron, J. Ferrante, B.K. Rosen, M.N. Wegman, and F.K. Zadeck
+ ACM TOPLAS, Vol. 13, Num. 4, Oct. 1991
+
+yyy
+ How to Analyze Large Programs Efficiently and Informatively
+ D.M. Dhamdhere, B.K. Rosen, F.K. Zadeck
+ ACM SIGPLAN Notices Vol. 27, Num. 7, Jul. 1992, '92 Conference on PLDI
+
+ Lazy Code Motion
+ J. Knoop, O. Ruthing, B. Steffen
+ ACM SIGPLAN Notices Vol. 27, Num. 7, Jul. 1992, '92 Conference on PLDI
+
+ What's In a Region? Or Computing Control Dependence Regions in Near-Linear
+ Time for Reducible Flow Control
+ Thomas Ball
+ ACM Letters on Programming Languages and Systems,
+ Vol. 2, Num. 1-4, Mar-Dec 1993
+
+ An Efficient Representation for Sparse Sets
+ Preston Briggs, Linda Torczon
+ ACM Letters on Programming Languages and Systems,
+ Vol. 2, Num. 1-4, Mar-Dec 1993
+
+ A Variation of Knoop, Ruthing, and Steffen's Lazy Code Motion
+ K-H Drechsler, M.P. Stadel
+ ACM SIGPLAN Notices, Vol. 28, Num. 5, May 1993
+
+ Partial Dead Code Elimination
+ J. Knoop, O. Ruthing, B. Steffen
+ ACM SIGPLAN Notices, Vol. 29, Num. 6, Jun. 1994
+
+ Effective Partial Redundancy Elimination
+ P. Briggs, K.D. Cooper
+ ACM SIGPLAN Notices, Vol. 29, Num. 6, Jun. 1994
+
+ The Program Structure Tree: Computing Control Regions in Linear Time
+ R. Johnson, D. Pearson, K. Pingali
+ ACM SIGPLAN Notices, Vol. 29, Num. 6, Jun. 1994
+
+ Optimal Code Motion: Theory and Practice
+ J. Knoop, O. Ruthing, B. Steffen
+ ACM TOPLAS, Vol. 16, Num. 4, Jul. 1994
+
+ The power of assignment motion
+ J. Knoop, O. Ruthing, B. Steffen
+ ACM SIGPLAN Notices Vol. 30, Num. 6, Jun. 1995, '95 Conference on PLDI
+
+ Global code motion / global value numbering
+ C. Click
+ ACM SIGPLAN Notices Vol. 30, Num. 6, Jun. 1995, '95 Conference on PLDI
+
+ Value Driven Redundancy Elimination
+ L.T. Simpson
+ Rice University Ph.D. thesis, Apr. 1996
+
+ Value Numbering
+ L.T. Simpson
+ Massively Scalar Compiler Project, Rice University, Sep. 1996
+
+ High Performance Compilers for Parallel Computing
+ Michael Wolfe
+ Addison-Wesley, 1996
+
+ People wishing to speed up the code here should read xxx, yyy.
+ People wishing to do something different can find various possibilities
+ in the above papers and elsewhere.
+*/
+
+#include "config.h"
+/* Must precede rtl.h for FFS. */
+#include "system.h"
+
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "flags.h"
+#include "real.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "basic-block.h"
+#include "output.h"
+
+#include "obstack.h"
+#define obstack_chunk_alloc gmalloc
+#define obstack_chunk_free free
+
+/* Maximum number of passes to perform. */
+#define MAX_PASSES 1
+
+/* Propagate flow information through back edges and thus enable PRE's
+ moving loop invariant calculations out of loops.
+
+ Originally this tended to create worse overall code, but several
+ improvements during the development of PRE seem to have made following
+ back edges generally a win.
+
+ Note much of the loop invariant code motion done here would normally
+ be done by loop.c, which has more heuristics for when to move invariants
+ out of loops. At some point we might need to move some of those
+ heuristics into gcse.c. */
+#define FOLLOW_BACK_EDGES 1
+
+/* We support two GCSE implementations: Classic GCSE (i.e. Dragon Book)
+ and PRE (Partial Redundancy Elimination) GCSE (based on Fred Chow's thesis).
+ The default is PRE.
+
+ In either case we perform the following steps:
+
+ 1) Compute basic block information.
+
+ 2) Compute table of places where registers are set.
+
+ 3) Perform copy/constant propagation.
+
+ 4) Perform global cse.
+
+ 5) Perform another pass of copy/constant propagation [only if PRE].
+
+ Two passes of copy/constant propagation are done because the first one
+ enables more GCSE and the second one helps to clean up the copies that
+ GCSE creates. This is needed more for PRE than for Classic because Classic
+ GCSE will try to use an existing register containing the common
+ subexpression rather than create a new one. This is harder to do for PRE
+ because of the code motion (which Classic GCSE doesn't do).
+
+ Expressions we are interested in GCSE-ing are of the form
+ (set (pseudo-reg) (expression)).
+ Function want_to_gcse_p says what these are.
+
+ PRE handles moving invariant expressions out of loops (by treating them as
+ partially redundant). This feature of PRE is disabled here (by not
+ propagating dataflow information along back edges) because loop.c has more
+ involved (and thus typically better) heuristics for what to move out of
+ loops.
+
+ Eventually it would be nice to replace cse.c/gcse.c with SSA (static single
+ assignment) based GVN (global value numbering). L. T. Simpson's paper
+ (Rice University) on value numbering is a useful reference for this.
+
+ **********************
+
+ We used to support multiple passes but there are diminishing returns in
+ doing so. The first pass usually makes 90% of the changes that are doable.
+ A second pass can make a few more changes made possible by the first pass.
+ Experiments show any further passes don't make enough changes to justify
+ the expense.
+
+ A study of spec92 using an unlimited number of passes:
+ [1 pass] = 1208 substitutions, [2] = 577, [3] = 202, [4] = 192, [5] = 83,
+ [6] = 34, [7] = 17, [8] = 9, [9] = 4, [10] = 4, [11] = 2,
+ [12] = 2, [13] = 1, [15] = 1, [16] = 2, [41] = 1
+
+ It was found doing copy propagation between each pass enables further
+ substitutions.
+
+ PRE is quite expensive in complicated functions because the DFA can take
+ awhile to converge. Hence we only perform one pass. Macro MAX_PASSES can
+ be modified if one wants to experiment.
+
+ **********************
+
+ The steps for PRE are:
+
+ 1) Build the hash table of expressions we wish to GCSE (expr_hash_table).
+
+ 2) Perform the data flow analysis for PRE.
+
+ 3) Delete the redundant instructions
+
+ 4) Insert the required copies [if any] that make the partially
+ redundant instructions fully redundant.
+
+ 5) For other reaching expressions, insert an instruction to copy the value
+ to a newly created pseudo that will reach the redundant instruction.
+
+ The deletion is done first so that when we do insertions we
+ know which pseudo reg to use.
+
+ Various papers have argued that PRE DFA is expensive (O(n^2)) and others
+ argue it is not. The number of iterations for the algorithm to converge
+ is typically 2-4 so I don't view it as that expensive (relatively speaking).
+
+ PRE GCSE depends heavily on the seconds CSE pass to clean up the copies
+ we create. To make an expression reach the place where it's redundant,
+ the result of the expression is copied to a new register, and the redundant
+ expression is deleted by replacing it with this new register. Classic GCSE
+ doesn't have this problem as much as it computes the reaching defs of
+ each register in each block and thus can try to use an existing register.
+
+ **********************
+
+ When -fclassic-gcse, we perform a classic global CSE pass.
+ It is based on the algorithms in the Dragon book, and is based on code
+ written by Devor Tevi at Intel.
+
+ The steps for Classic GCSE are:
+
+ 1) Build the hash table of expressions we wish to GCSE (expr_hash_table).
+ Also recorded are reaching definition "gen" statements (rd_gen)
+
+ 2) Compute the reaching definitions (reaching_defs).
+ This is a bitmap for each basic block indexed by INSN_CUID that is 1
+ for each statement containing a definition that reaches the block.
+
+ 3) Compute the available expressions (ae_in).
+ This is a bitmap for each basic block indexed by expression number
+ that is 1 for each expression that is available at the beginning of
+ the block.
+
+ 4) Perform GCSE.
+ This is done by scanning each instruction looking for sets of the form
+ (set (pseudo-reg) (expression)) and checking if `expression' is in the
+ hash table. If it is, and if the expression is available, and if only
+ one computation of the expression reaches the instruction, we substitute
+ the expression for a register containing its value. If there is no
+ such register, but the expression is expensive enough we create an
+ instruction to copy the result of the expression into and use that.
+
+ **********************
+
+ A fair bit of simplicity is created by creating small functions for simple
+ tasks, even when the function is only called in one place. This may
+ measurably slow things down [or may not] by creating more function call
+ overhead than is necessary. The source is laid out so that it's trivial
+ to make the affected functions inline so that one can measure what speed
+ up, if any, can be achieved, and maybe later when things settle things can
+ be rearranged.
+
+ Help stamp out big monolithic functions! */
+
+/* GCSE global vars. */
+
+/* -dG dump file. */
+static FILE *gcse_file;
+
+/* Bitmaps are normally not included in debugging dumps.
+ However it's useful to be able to print them from GDB.
+ We could create special functions for this, but it's simpler to
+ just allow passing stderr to the dump_foo fns. Since stderr can
+ be a macro, we store a copy here. */
+static FILE *debug_stderr;
+
+/* An obstack for our working variables. */
+static struct obstack gcse_obstack;
+
+/* Non-zero for each mode that supports (set (reg) (reg)).
+ This is trivially true for integer and floating point values.
+ It may or may not be true for condition codes. */
+static char can_copy_p[(int) NUM_MACHINE_MODES];
+
+/* Non-zero if can_copy_p has been initialized. */
+static int can_copy_init_p;
+
+/* Element I is a list of I's predecessors/successors. */
+static int_list_ptr *s_preds;
+static int_list_ptr *s_succs;
+
+/* Element I is the number of predecessors/successors of basic block I. */
+static int *num_preds;
+static int *num_succs;
+
+/* Hash table of expressions. */
+
+struct expr
+{
+ /* The expression (SET_SRC for expressions, PATTERN for assignments). */
+ rtx expr;
+ /* Index in the available expression bitmaps. */
+ int bitmap_index;
+ /* Next entry with the same hash. */
+ struct expr *next_same_hash;
+ /* List of anticipatable occurrences in basic blocks in the function.
+ An "anticipatable occurrence" is one that is the first occurrence in the
+ basic block and the operands are not modified in the basic block prior
+ to the occurrence. */
+ struct occr *antic_occr;
+ /* List of available occurrence in basic blocks in the function.
+ An "available occurrence" is one that is the last occurrence in the
+ basic block and the operands are not modified by following statements in
+ the basic block [including this insn]. */
+ struct occr *avail_occr;
+ /* Non-null if the computation is PRE redundant.
+ The value is the newly created pseudo-reg to record a copy of the
+ expression in all the places that reach the redundant copy. */
+ rtx reaching_reg;
+};
+
+/* Occurrence of an expression.
+ There is one per basic block. If a pattern appears more than once the
+ last appearance is used [or first for anticipatable expressions]. */
+
+struct occr
+{
+ /* Next occurrence of this expression. */
+ struct occr *next;
+ /* The insn that computes the expression. */
+ rtx insn;
+ /* Non-zero if this [anticipatable] occurrence has been deleted. */
+ char deleted_p;
+ /* Non-zero if this [available] occurrence has been copied to
+ reaching_reg. */
+ /* ??? This is mutually exclusive with deleted_p, so they could share
+ the same byte. */
+ char copied_p;
+};
+
+/* Expression and copy propagation hash tables.
+ Each hash table is an array of buckets.
+ ??? It is known that if it were an array of entries, structure elements
+ `next_same_hash' and `bitmap_index' wouldn't be necessary. However, it is
+ not clear whether in the final analysis a sufficient amount of memory would
+ be saved as the size of the available expression bitmaps would be larger
+ [one could build a mapping table without holes afterwards though].
+ Someday I'll perform the computation and figure it out.
+*/
+
+/* Total size of the expression hash table, in elements. */
+static int expr_hash_table_size;
+/* The table itself.
+ This is an array of `expr_hash_table_size' elements. */
+static struct expr **expr_hash_table;
+
+/* Total size of the copy propagation hash table, in elements. */
+static int set_hash_table_size;
+/* The table itself.
+ This is an array of `set_hash_table_size' elements. */
+static struct expr **set_hash_table;
+
+/* Mapping of uids to cuids.
+ Only real insns get cuids. */
+static int *uid_cuid;
+
+/* Highest UID in UID_CUID. */
+static int max_uid;
+
+/* Get the cuid of an insn. */
+#define INSN_CUID(INSN) (uid_cuid[INSN_UID (INSN)])
+
+/* Number of cuids. */
+static int max_cuid;
+
+/* Mapping of cuids to insns. */
+static rtx *cuid_insn;
+
+/* Get insn from cuid. */
+#define CUID_INSN(CUID) (cuid_insn[CUID])
+
+/* Maximum register number in function prior to doing gcse + 1.
+ Registers created during this pass have regno >= max_gcse_regno.
+ This is named with "gcse" to not collide with global of same name. */
+static int max_gcse_regno;
+
+/* Maximum number of cse-able expressions found. */
+static int n_exprs;
+/* Maximum number of assignments for copy propagation found. */
+static int n_sets;
+
+/* Table of registers that are modified.
+ For each register, each element is a list of places where the pseudo-reg
+ is set.
+
+ For simplicity, GCSE is done on sets of pseudo-regs only. PRE GCSE only
+ requires knowledge of which blocks kill which regs [and thus could use
+ a bitmap instead of the lists `reg_set_table' uses]. The classic GCSE
+ uses the information in lists.
+
+ If the classic GCSE pass is deleted `reg_set_table' and could be turned
+ into an array of bitmaps (num-bbs x num-regs)
+ [however perhaps it may be useful to keep the data as is].
+ One advantage of recording things this way is that `reg_set_table' is
+ fairly sparse with respect to pseudo regs but for hard regs could be
+ fairly dense [relatively speaking].
+ And recording sets of pseudo-regs in lists speeds
+ up functions like compute_transp since in the case of pseudo-regs we only
+ need to iterate over the number of times a pseudo-reg is set, not over the
+ number of basic blocks [clearly there is a bit of a slow down in the cases
+ where a pseudo is set more than once in a block, however it is believed
+ that the net effect is to speed things up]. This isn't done for hard-regs
+ because recording call-clobbered hard-regs in `reg_set_table' at each
+ function call can consume a fair bit of memory, and iterating over hard-regs
+ stored this way in compute_transp will be more expensive. */
+
+typedef struct reg_set {
+ /* The next setting of this register. */
+ struct reg_set *next;
+ /* The insn where it was set. */
+ rtx insn;
+} reg_set;
+static reg_set **reg_set_table;
+/* Size of `reg_set_table'.
+ The table starts out at max_gcse_regno + slop, and is enlarged as
+ necessary. */
+static int reg_set_table_size;
+/* Amount to grow `reg_set_table' by when it's full. */
+#define REG_SET_TABLE_SLOP 100
+
+/* Bitmap containing one bit for each register in the program.
+ Used when performing GCSE to track which registers have been set since
+ the start of the basic block. */
+static sbitmap reg_set_bitmap;
+
+/* For each block, a bitmap of registers set in the block.
+ This is used by expr_killed_p and compute_transp.
+ It is computed during hash table computation and not by compute_sets
+ as it includes registers added since the last pass (or between cprop and
+ gcse) and it's currently not easy to realloc sbitmap vectors. */
+static sbitmap *reg_set_in_block;
+
+/* For each block, non-zero if memory is set in that block.
+ This is computed during hash table computation and is used by
+ expr_killed_p and compute_transp.
+ ??? Handling of memory is very simple, we don't make any attempt
+ to optimize things (later).
+ ??? This can be computed by compute_sets since the information
+ doesn't change. */
+static char *mem_set_in_block;
+
+/* Various variables for statistics gathering. */
+
+/* Memory used in a pass.
+ This isn't intended to be absolutely precise. Its intent is only
+ to keep an eye on memory usage. */
+static int bytes_used;
+/* GCSE substitutions made. */
+static int gcse_subst_count;
+/* Number of copy instructions created. */
+static int gcse_create_count;
+/* Number of constants propagated. */
+static int const_prop_count;
+/* Number of copys propagated. */
+static int copy_prop_count;
+
+extern char *current_function_name;
+extern int current_function_calls_setjmp;
+extern int current_function_calls_longjmp;
+
+/* These variables are used by classic GCSE.
+ Normally they'd be defined a bit later, but `rd_gen' needs to
+ be declared sooner. */
+
+/* A bitmap of all ones for implementing the algorithm for available
+ expressions and reaching definitions. */
+/* ??? Available expression bitmaps have a different size than reaching
+ definition bitmaps. This should be the larger of the two, however, it
+ is not currently used for reaching definitions. */
+static sbitmap u_bitmap;
+
+/* Each block has a bitmap of each type.
+ The length of each blocks bitmap is:
+
+ max_cuid - for reaching definitions
+ n_exprs - for available expressions
+
+ Thus we view the bitmaps as 2 dimensional arrays. i.e.
+ rd_kill[block_num][cuid_num]
+ ae_kill[block_num][expr_num]
+*/
+
+/* For reaching defs */
+static sbitmap *rd_kill, *rd_gen, *reaching_defs, *rd_out;
+
+/* for available exprs */
+static sbitmap *ae_kill, *ae_gen, *ae_in, *ae_out;
+
+static void compute_can_copy PROTO ((void));
+
+static char *gmalloc PROTO ((unsigned int));
+static char *grealloc PROTO ((char *, unsigned int));
+static char *gcse_alloc PROTO ((unsigned long));
+static void alloc_gcse_mem PROTO ((rtx));
+static void free_gcse_mem PROTO ((void));
+extern void dump_cuid_table PROTO ((FILE *));
+
+static void alloc_reg_set_mem PROTO ((int));
+static void free_reg_set_mem PROTO ((void));
+static void record_one_set PROTO ((int, rtx));
+static void record_set_info PROTO ((rtx, rtx));
+static void compute_sets PROTO ((rtx));
+
+static void hash_scan_insn PROTO ((rtx, int, int));
+static void hash_scan_set PROTO ((rtx, rtx, int));
+static void hash_scan_clobber PROTO ((rtx, rtx));
+static void hash_scan_call PROTO ((rtx, rtx));
+static void maybe_set_rd_gen PROTO ((int, rtx));
+static int want_to_gcse_p PROTO ((rtx));
+static int oprs_unchanged_p PROTO ((rtx, rtx, int));
+static int oprs_anticipatable_p PROTO ((rtx, rtx));
+static int oprs_available_p PROTO ((rtx, rtx));
+static void insert_expr_in_table PROTO ((rtx, enum machine_mode, rtx, int, int));
+static void insert_set_in_table PROTO ((rtx, rtx));
+static unsigned int hash_expr PROTO ((rtx, enum machine_mode, int *, int));
+static unsigned int hash_expr_1 PROTO ((rtx, enum machine_mode, int *));
+static unsigned int hash_set PROTO ((int, int));
+static int expr_equiv_p PROTO ((rtx, rtx));
+static void record_last_reg_set_info PROTO ((rtx, int));
+static void record_last_mem_set_info PROTO ((rtx));
+static void record_last_set_info PROTO ((rtx, rtx));
+static void compute_hash_table PROTO ((rtx, int));
+static void alloc_set_hash_table PROTO ((int));
+static void free_set_hash_table PROTO ((void));
+static void compute_set_hash_table PROTO ((rtx));
+static void alloc_expr_hash_table PROTO ((int));
+static void free_expr_hash_table PROTO ((void));
+static void compute_expr_hash_table PROTO ((rtx));
+static void dump_hash_table PROTO ((FILE *, char *, struct expr **, int, int));
+static struct expr *lookup_expr PROTO ((rtx));
+static struct expr *lookup_set PROTO ((int, rtx));
+static struct expr *next_set PROTO ((int, struct expr *));
+static void reset_opr_set_tables PROTO ((void));
+static int oprs_not_set_p PROTO ((rtx, rtx));
+static void mark_call PROTO ((rtx, rtx));
+static void mark_set PROTO ((rtx, rtx));
+static void mark_clobber PROTO ((rtx, rtx));
+static void mark_oprs_set PROTO ((rtx));
+
+static void alloc_rd_mem PROTO ((int, int));
+static void free_rd_mem PROTO ((void));
+static void compute_kill_rd PROTO ((void));
+static void handle_rd_kill_set PROTO ((rtx, int, int));
+static void compute_rd PROTO ((void));
+extern void dump_rd_table PROTO ((FILE *, char *, sbitmap *));
+
+static void alloc_avail_expr_mem PROTO ((int, int));
+static void free_avail_expr_mem PROTO ((void));
+static void compute_ae_gen PROTO ((void));
+static void compute_ae_kill PROTO ((void));
+static int expr_killed_p PROTO ((rtx, int));
+static void compute_available PROTO ((void));
+
+static int expr_reaches_here_p PROTO ((struct occr *, struct expr *,
+ int, int, char *));
+static rtx computing_insn PROTO ((struct expr *, rtx));
+static int def_reaches_here_p PROTO ((rtx, rtx));
+static int can_disregard_other_sets PROTO ((struct reg_set **, rtx, int));
+static int handle_avail_expr PROTO ((rtx, struct expr *));
+static int classic_gcse PROTO ((void));
+static int one_classic_gcse_pass PROTO ((rtx, int));
+
+static void alloc_cprop_mem PROTO ((int, int));
+static void free_cprop_mem PROTO ((void));
+extern void dump_cprop_data PROTO ((FILE *));
+static void compute_transp PROTO ((rtx, int, sbitmap *, int));
+static void compute_cprop_local_properties PROTO ((void));
+static void compute_cprop_avinout PROTO ((void));
+static void compute_cprop_data PROTO ((void));
+static void find_used_regs PROTO ((rtx));
+static int try_replace_reg PROTO ((rtx, rtx, rtx));
+static struct expr *find_avail_set PROTO ((int, rtx));
+static int cprop_insn PROTO ((rtx));
+static int cprop PROTO ((void));
+static int one_cprop_pass PROTO ((rtx, int));
+
+static void alloc_pre_mem PROTO ((int, int));
+static void free_pre_mem PROTO ((void));
+extern void dump_pre_data PROTO ((FILE *));
+static void compute_pre_local_properties PROTO ((void));
+static void compute_pre_avinout PROTO ((void));
+static void compute_pre_antinout PROTO ((void));
+static void compute_pre_pavinout PROTO ((void));
+static void compute_pre_ppinout PROTO ((void));
+static void compute_pre_data PROTO ((void));
+static int pre_expr_reaches_here_p PROTO ((struct occr *, struct expr *,
+ int, char *));
+static void pre_insert_insn PROTO ((struct expr *, int));
+static void pre_insert PROTO ((struct expr **));
+static void pre_insert_copy_insn PROTO ((struct expr *, rtx));
+static void pre_insert_copies PROTO ((void));
+static int pre_delete PROTO ((void));
+static int pre_gcse PROTO ((void));
+static int one_pre_gcse_pass PROTO ((rtx, int));
+
+static void add_label_notes PROTO ((rtx, rtx));
+
+/* Entry point for global common subexpression elimination.
+ F is the first instruction in the function. */
+
+void
+gcse_main (f, file)
+ rtx f;
+ FILE *file;
+{
+ int changed, pass;
+ /* Bytes used at start of pass. */
+ int initial_bytes_used;
+ /* Maximum number of bytes used by a pass. */
+ int max_pass_bytes;
+ /* Point to release obstack data from for each pass. */
+ char *gcse_obstack_bottom;
+
+ /* It's impossible to construct a correct control flow graph in the
+ presense of setjmp, so just punt to be safe. */
+ if (current_function_calls_setjmp)
+ return;
+
+ /* For calling dump_foo fns from gdb. */
+ debug_stderr = stderr;
+
+ max_gcse_regno = max_reg_num ();
+ find_basic_blocks (f, max_gcse_regno, file, 0);
+
+ /* Return if there's nothing to do. */
+ if (n_basic_blocks <= 1)
+ {
+ /* Free storage allocated by find_basic_blocks. */
+ free_basic_block_vars (0);
+ return;
+ }
+
+ /* See what modes support reg/reg copy operations. */
+ if (! can_copy_init_p)
+ {
+ compute_can_copy ();
+ can_copy_init_p = 1;
+ }
+
+ gcc_obstack_init (&gcse_obstack);
+
+ gcse_file = file;
+
+ /* Allocate and compute predecessors/successors. */
+
+ s_preds = (int_list_ptr *) alloca (n_basic_blocks * sizeof (int_list_ptr));
+ s_succs = (int_list_ptr *) alloca (n_basic_blocks * sizeof (int_list_ptr));
+ num_preds = (int *) alloca (n_basic_blocks * sizeof (int));
+ num_succs = (int *) alloca (n_basic_blocks * sizeof (int));
+ bytes_used = 4 * n_basic_blocks * sizeof (int_list_ptr);
+ compute_preds_succs (s_preds, s_succs, num_preds, num_succs);
+
+ if (file)
+ {
+ dump_bb_data (file, s_preds, s_succs);
+ }
+
+ /* Record where pseudo-registers are set.
+ This data is kept accurate during each pass.
+ ??? We could also record hard-reg and memory information here
+ [since it's unchanging], however it is currently done during
+ hash table computation. */
+
+ alloc_reg_set_mem (max_gcse_regno);
+ compute_sets (f);
+
+ pass = 0;
+ initial_bytes_used = bytes_used;
+ max_pass_bytes = 0;
+ gcse_obstack_bottom = gcse_alloc (1);
+ changed = 1;
+ while (changed && pass < MAX_PASSES)
+ {
+ changed = 0;
+ if (file)
+ fprintf (file, "GCSE pass %d\n\n", pass + 1);
+
+ /* Initialize bytes_used to the space for the pred/succ lists,
+ and the reg_set_table data. */
+ bytes_used = initial_bytes_used;
+
+ /* Each pass may create new registers, so recalculate each time. */
+ max_gcse_regno = max_reg_num ();
+
+ alloc_gcse_mem (f);
+
+ changed = one_cprop_pass (f, pass + 1);
+
+ if (optimize_size)
+ changed |= one_classic_gcse_pass (f, pass + 1);
+ else
+ changed |= one_pre_gcse_pass (f, pass + 1);
+
+ if (max_pass_bytes < bytes_used)
+ max_pass_bytes = bytes_used;
+
+ free_gcse_mem ();
+
+ if (file)
+ {
+ fprintf (file, "\n");
+ fflush (file);
+ }
+ obstack_free (&gcse_obstack, gcse_obstack_bottom);
+ pass++;
+ }
+
+ /* If we're doing PRE, do one last pass of copy propagation. */
+ if (! optimize_size)
+ {
+ max_gcse_regno = max_reg_num ();
+ alloc_gcse_mem (f);
+ one_cprop_pass (f, pass + 1);
+ free_gcse_mem ();
+ }
+
+ if (file)
+ {
+ fprintf (file, "GCSE of %s: %d basic blocks, ",
+ current_function_name, n_basic_blocks);
+ fprintf (file, "%d pass%s, %d bytes\n\n",
+ pass, pass > 1 ? "es" : "", max_pass_bytes);
+ }
+
+ /* Free our obstack. */
+ obstack_free (&gcse_obstack, NULL_PTR);
+ /* Free reg_set_table. */
+ free_reg_set_mem ();
+ /* Free storage used to record predecessor/successor data. */
+ free_bb_mem ();
+ /* Free storage allocated by find_basic_blocks. */
+ free_basic_block_vars (0);
+}
+
+/* Misc. utilities. */
+
+/* Compute which modes support reg/reg copy operations. */
+
+static void
+compute_can_copy ()
+{
+ int i;
+#ifndef AVOID_CCMODE_COPIES
+ rtx reg,insn;
+#endif
+ char *free_point = (char *) oballoc (1);
+
+ bzero (can_copy_p, NUM_MACHINE_MODES);
+
+ start_sequence ();
+ for (i = 0; i < NUM_MACHINE_MODES; i++)
+ {
+ switch (GET_MODE_CLASS (i))
+ {
+ case MODE_CC :
+#ifdef AVOID_CCMODE_COPIES
+ can_copy_p[i] = 0;
+#else
+ reg = gen_rtx_REG ((enum machine_mode) i, LAST_VIRTUAL_REGISTER + 1);
+ insn = emit_insn (gen_rtx_SET (VOIDmode, reg, reg));
+ if (recog (PATTERN (insn), insn, NULL_PTR) >= 0)
+ can_copy_p[i] = 1;
+#endif
+ break;
+ default :
+ can_copy_p[i] = 1;
+ break;
+ }
+ }
+ end_sequence ();
+
+ /* Free the objects we just allocated. */
+ obfree (free_point);
+}
+
+/* Cover function to xmalloc to record bytes allocated. */
+
+static char *
+gmalloc (size)
+ unsigned int size;
+{
+ bytes_used += size;
+ return xmalloc (size);
+}
+
+/* Cover function to xrealloc.
+ We don't record the additional size since we don't know it.
+ It won't affect memory usage stats much anyway. */
+
+static char *
+grealloc (ptr, size)
+ char *ptr;
+ unsigned int size;
+{
+ return xrealloc (ptr, size);
+}
+
+/* Cover function to obstack_alloc.
+ We don't need to record the bytes allocated here since
+ obstack_chunk_alloc is set to gmalloc. */
+
+static char *
+gcse_alloc (size)
+ unsigned long size;
+{
+ return (char *) obstack_alloc (&gcse_obstack, size);
+}
+
+/* Allocate memory for the cuid mapping array,
+ and reg/memory set tracking tables.
+
+ This is called at the start of each pass. */
+
+static void
+alloc_gcse_mem (f)
+ rtx f;
+{
+ int i,n;
+ rtx insn;
+
+ /* Find the largest UID and create a mapping from UIDs to CUIDs.
+ CUIDs are like UIDs except they increase monotonically, have no gaps,
+ and only apply to real insns. */
+
+ max_uid = get_max_uid ();
+ n = (max_uid + 1) * sizeof (int);
+ uid_cuid = (int *) gmalloc (n);
+ bzero ((char *) uid_cuid, n);
+ for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ INSN_CUID (insn) = i++;
+ else
+ INSN_CUID (insn) = i;
+ }
+
+ /* Create a table mapping cuids to insns. */
+
+ max_cuid = i;
+ n = (max_cuid + 1) * sizeof (rtx);
+ cuid_insn = (rtx *) gmalloc (n);
+ bzero ((char *) cuid_insn, n);
+ for (insn = f, i = 0; insn; insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ CUID_INSN (i) = insn;
+ i++;
+ }
+ }
+
+ /* Allocate vars to track sets of regs. */
+
+ reg_set_bitmap = (sbitmap) sbitmap_alloc (max_gcse_regno);
+
+ /* Allocate vars to track sets of regs, memory per block. */
+
+ reg_set_in_block = (sbitmap *) sbitmap_vector_alloc (n_basic_blocks,
+ max_gcse_regno);
+ mem_set_in_block = (char *) gmalloc (n_basic_blocks);
+}
+
+/* Free memory allocated by alloc_gcse_mem. */
+
+static void
+free_gcse_mem ()
+{
+ free (uid_cuid);
+ free (cuid_insn);
+
+ free (reg_set_bitmap);
+
+ free (reg_set_in_block);
+ free (mem_set_in_block);
+}
+
+void
+dump_cuid_table (file)
+ FILE *file;
+{
+ int i,n;
+
+ fprintf (file, "CUID table\n");
+ for (i = n = 0; i < max_cuid; i++)
+ {
+ rtx insn = CUID_INSN (i);
+ if (n != 0 && n % 10 == 0)
+ fprintf (file, "\n");
+ if (insn != NULL)
+ fprintf (file, " %d", INSN_UID (insn));
+ }
+ fprintf (file, "\n\n");
+}
+
+/* Register set information.
+
+ `reg_set_table' records where each register is set or otherwise
+ modified. */
+
+static struct obstack reg_set_obstack;
+
+static void
+alloc_reg_set_mem (n_regs)
+ int n_regs;
+{
+ int n;
+
+ reg_set_table_size = n_regs + REG_SET_TABLE_SLOP;
+ n = reg_set_table_size * sizeof (struct reg_set *);
+ reg_set_table = (struct reg_set **) gmalloc (n);
+ bzero ((char *) reg_set_table, n);
+
+ gcc_obstack_init (&reg_set_obstack);
+}
+
+static void
+free_reg_set_mem ()
+{
+ free (reg_set_table);
+ obstack_free (&reg_set_obstack, NULL_PTR);
+}
+
+/* Record REGNO in the reg_set table. */
+
+static void
+record_one_set (regno, insn)
+ int regno;
+ rtx insn;
+{
+ /* allocate a new reg_set element and link it onto the list */
+ struct reg_set *new_reg_info, *reg_info_ptr1, *reg_info_ptr2;
+
+ /* If the table isn't big enough, enlarge it. */
+ if (regno >= reg_set_table_size)
+ {
+ int new_size = regno + REG_SET_TABLE_SLOP;
+ reg_set_table = (struct reg_set **)
+ grealloc ((char *) reg_set_table,
+ new_size * sizeof (struct reg_set *));
+ bzero ((char *) (reg_set_table + reg_set_table_size),
+ (new_size - reg_set_table_size) * sizeof (struct reg_set *));
+ reg_set_table_size = new_size;
+ }
+
+ new_reg_info = (struct reg_set *) obstack_alloc (&reg_set_obstack,
+ sizeof (struct reg_set));
+ bytes_used += sizeof (struct reg_set);
+ new_reg_info->insn = insn;
+ new_reg_info->next = NULL;
+ if (reg_set_table[regno] == NULL)
+ reg_set_table[regno] = new_reg_info;
+ else
+ {
+ reg_info_ptr1 = reg_info_ptr2 = reg_set_table[regno];
+ /* ??? One could keep a "last" pointer to speed this up. */
+ while (reg_info_ptr1 != NULL)
+ {
+ reg_info_ptr2 = reg_info_ptr1;
+ reg_info_ptr1 = reg_info_ptr1->next;
+ }
+ reg_info_ptr2->next = new_reg_info;
+ }
+}
+
+/* For communication between next two functions (via note_stores). */
+static rtx record_set_insn;
+
+/* Called from compute_sets via note_stores to handle one
+ SET or CLOBBER in an insn. */
+
+static void
+record_set_info (dest, setter)
+ rtx dest, setter ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+
+ if (GET_CODE (dest) == REG)
+ {
+ if (REGNO (dest) >= FIRST_PSEUDO_REGISTER)
+ record_one_set (REGNO (dest), record_set_insn);
+ }
+}
+
+/* Scan the function and record each set of each pseudo-register.
+
+ This is called once, at the start of the gcse pass.
+ See the comments for `reg_set_table' for further docs. */
+
+static void
+compute_sets (f)
+ rtx f;
+{
+ rtx insn = f;
+
+ while (insn)
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ record_set_insn = insn;
+ note_stores (PATTERN (insn), record_set_info);
+ }
+ insn = NEXT_INSN (insn);
+ }
+}
+
+/* Hash table support. */
+
+#define NEVER_SET -1
+
+/* For each register, the cuid of the first/last insn in the block to set it,
+ or zero if not set. */
+static int *reg_first_set;
+static int *reg_last_set;
+
+/* While computing "first/last set" info, this is the CUID of first/last insn
+ to set memory or zero if not set. `mem_last_set' is also used when
+ performing GCSE to record whether memory has been set since the beginning
+ of the block.
+ Note that handling of memory is very simple, we don't make any attempt
+ to optimize things (later). */
+static int mem_first_set;
+static int mem_last_set;
+
+/* Set the appropriate bit in `rd_gen' [the gen for reaching defs] if the
+ register set in this insn is not set after this insn in this block. */
+
+static void
+maybe_set_rd_gen (regno, insn)
+ int regno;
+ rtx insn;
+{
+ if (reg_last_set[regno] <= INSN_CUID (insn))
+ SET_BIT (rd_gen[BLOCK_NUM (insn)], INSN_CUID (insn));
+}
+
+/* Perform a quick check whether X, the source of a set, is something
+ we want to consider for GCSE. */
+
+static int
+want_to_gcse_p (x)
+ rtx x;
+{
+ enum rtx_code code = GET_CODE (x);
+
+ switch (code)
+ {
+ case REG:
+ case SUBREG:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CALL:
+ return 0;
+
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+/* Return non-zero if the operands of expression X are unchanged from the
+ start of INSN's basic block up to but not including INSN (if AVAIL_P == 0),
+ or from INSN to the end of INSN's basic block (if AVAIL_P != 0). */
+
+static int
+oprs_unchanged_p (x, insn, avail_p)
+ rtx x, insn;
+ int avail_p;
+{
+ int i;
+ enum rtx_code code;
+ char *fmt;
+
+ /* repeat is used to turn tail-recursion into iteration. */
+ repeat:
+
+ if (x == 0)
+ return 1;
+
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case REG:
+ if (avail_p)
+ return (reg_last_set[REGNO (x)] == NEVER_SET
+ || reg_last_set[REGNO (x)] < INSN_CUID (insn));
+ else
+ return (reg_first_set[REGNO (x)] == NEVER_SET
+ || reg_first_set[REGNO (x)] >= INSN_CUID (insn));
+
+ case MEM:
+ if (avail_p)
+ {
+ if (mem_last_set != NEVER_SET
+ && mem_last_set >= INSN_CUID (insn))
+ return 0;
+ }
+ else
+ {
+ if (mem_first_set != NEVER_SET
+ && mem_first_set < INSN_CUID (insn))
+ return 0;
+ }
+ x = XEXP (x, 0);
+ goto repeat;
+
+ case PRE_DEC:
+ case PRE_INC:
+ case POST_DEC:
+ case POST_INC:
+ return 0;
+
+ case PC:
+ case CC0: /*FIXME*/
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ return 1;
+
+ default:
+ break;
+ }
+
+ i = GET_RTX_LENGTH (code) - 1;
+ fmt = GET_RTX_FORMAT (code);
+ for (; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ rtx tem = XEXP (x, i);
+
+ /* If we are about to do the last recursive call
+ needed at this level, change it into iteration.
+ This function is called enough to be worth it. */
+ if (i == 0)
+ {
+ x = tem;
+ goto repeat;
+ }
+ if (! oprs_unchanged_p (tem, insn, avail_p))
+ return 0;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ {
+ if (! oprs_unchanged_p (XVECEXP (x, i, j), insn, avail_p))
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/* Return non-zero if the operands of expression X are unchanged from
+ the start of INSN's basic block up to but not including INSN. */
+
+static int
+oprs_anticipatable_p (x, insn)
+ rtx x, insn;
+{
+ return oprs_unchanged_p (x, insn, 0);
+}
+
+/* Return non-zero if the operands of expression X are unchanged from
+ INSN to the end of INSN's basic block. */
+
+static int
+oprs_available_p (x, insn)
+ rtx x, insn;
+{
+ return oprs_unchanged_p (x, insn, 1);
+}
+
+/* Hash expression X.
+ MODE is only used if X is a CONST_INT.
+ A boolean indicating if a volatile operand is found or if the expression
+ contains something we don't want to insert in the table is stored in
+ DO_NOT_RECORD_P.
+
+ ??? One might want to merge this with canon_hash. Later. */
+
+static unsigned int
+hash_expr (x, mode, do_not_record_p, hash_table_size)
+ rtx x;
+ enum machine_mode mode;
+ int *do_not_record_p;
+ int hash_table_size;
+{
+ unsigned int hash;
+
+ *do_not_record_p = 0;
+
+ hash = hash_expr_1 (x, mode, do_not_record_p);
+ return hash % hash_table_size;
+}
+
+/* Subroutine of hash_expr to do the actual work. */
+
+static unsigned int
+hash_expr_1 (x, mode, do_not_record_p)
+ rtx x;
+ enum machine_mode mode;
+ int *do_not_record_p;
+{
+ int i, j;
+ unsigned hash = 0;
+ enum rtx_code code;
+ char *fmt;
+
+ /* repeat is used to turn tail-recursion into iteration. */
+ repeat:
+
+ if (x == 0)
+ return hash;
+
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case REG:
+ {
+ register int regno = REGNO (x);
+ hash += ((unsigned) REG << 7) + regno;
+ return hash;
+ }
+
+ case CONST_INT:
+ {
+ unsigned HOST_WIDE_INT tem = INTVAL (x);
+ hash += ((unsigned) CONST_INT << 7) + (unsigned) mode + tem;
+ return hash;
+ }
+
+ case CONST_DOUBLE:
+ /* This is like the general case, except that it only counts
+ the integers representing the constant. */
+ hash += (unsigned) code + (unsigned) GET_MODE (x);
+ if (GET_MODE (x) != VOIDmode)
+ for (i = 2; i < GET_RTX_LENGTH (CONST_DOUBLE); i++)
+ {
+ unsigned tem = XINT (x, i);
+ hash += tem;
+ }
+ else
+ hash += ((unsigned) CONST_DOUBLE_LOW (x)
+ + (unsigned) CONST_DOUBLE_HIGH (x));
+ return hash;
+
+ /* Assume there is only one rtx object for any given label. */
+ case LABEL_REF:
+ /* We don't hash on the address of the CODE_LABEL to avoid bootstrap
+ differences and differences between each stage's debugging dumps. */
+ hash += ((unsigned) LABEL_REF << 7) + CODE_LABEL_NUMBER (XEXP (x, 0));
+ return hash;
+
+ case SYMBOL_REF:
+ {
+ /* Don't hash on the symbol's address to avoid bootstrap differences.
+ Different hash values may cause expressions to be recorded in
+ different orders and thus different registers to be used in the
+ final assembler. This also avoids differences in the dump files
+ between various stages. */
+ unsigned int h = 0;
+ unsigned char *p = (unsigned char *) XSTR (x, 0);
+ while (*p)
+ h += (h << 7) + *p++; /* ??? revisit */
+ hash += ((unsigned) SYMBOL_REF << 7) + h;
+ return hash;
+ }
+
+ case MEM:
+ if (MEM_VOLATILE_P (x))
+ {
+ *do_not_record_p = 1;
+ return 0;
+ }
+ hash += (unsigned) MEM;
+ x = XEXP (x, 0);
+ goto repeat;
+
+ case PRE_DEC:
+ case PRE_INC:
+ case POST_DEC:
+ case POST_INC:
+ case PC:
+ case CC0:
+ case CALL:
+ case UNSPEC_VOLATILE:
+ *do_not_record_p = 1;
+ return 0;
+
+ case ASM_OPERANDS:
+ if (MEM_VOLATILE_P (x))
+ {
+ *do_not_record_p = 1;
+ return 0;
+ }
+
+ default:
+ break;
+ }
+
+ i = GET_RTX_LENGTH (code) - 1;
+ hash += (unsigned) code + (unsigned) GET_MODE (x);
+ fmt = GET_RTX_FORMAT (code);
+ for (; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ rtx tem = XEXP (x, i);
+
+ /* If we are about to do the last recursive call
+ needed at this level, change it into iteration.
+ This function is called enough to be worth it. */
+ if (i == 0)
+ {
+ x = tem;
+ goto repeat;
+ }
+ hash += hash_expr_1 (tem, 0, do_not_record_p);
+ if (*do_not_record_p)
+ return 0;
+ }
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ {
+ hash += hash_expr_1 (XVECEXP (x, i, j), 0, do_not_record_p);
+ if (*do_not_record_p)
+ return 0;
+ }
+ else if (fmt[i] == 's')
+ {
+ register unsigned char *p = (unsigned char *) XSTR (x, i);
+ if (p)
+ while (*p)
+ hash += *p++;
+ }
+ else if (fmt[i] == 'i')
+ {
+ register unsigned tem = XINT (x, i);
+ hash += tem;
+ }
+ else
+ abort ();
+ }
+
+ return hash;
+}
+
+/* Hash a set of register REGNO.
+
+ Sets are hashed on the register that is set.
+ This simplifies the PRE copy propagation code.
+
+ ??? May need to make things more elaborate. Later, as necessary. */
+
+static unsigned int
+hash_set (regno, hash_table_size)
+ int regno;
+ int hash_table_size;
+{
+ unsigned int hash;
+
+ hash = regno;
+ return hash % hash_table_size;
+}
+
+/* Return non-zero if exp1 is equivalent to exp2.
+ ??? Borrowed from cse.c. Might want to remerge with cse.c. Later. */
+
+static int
+expr_equiv_p (x, y)
+ rtx x, y;
+{
+ register int i, j;
+ register enum rtx_code code;
+ register char *fmt;
+
+ if (x == y)
+ return 1;
+ if (x == 0 || y == 0)
+ return x == y;
+
+ code = GET_CODE (x);
+ if (code != GET_CODE (y))
+ return 0;
+
+ /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */
+ if (GET_MODE (x) != GET_MODE (y))
+ return 0;
+
+ switch (code)
+ {
+ case PC:
+ case CC0:
+ return x == y;
+
+ case CONST_INT:
+ return INTVAL (x) == INTVAL (y);
+
+ case LABEL_REF:
+ return XEXP (x, 0) == XEXP (y, 0);
+
+ case SYMBOL_REF:
+ return XSTR (x, 0) == XSTR (y, 0);
+
+ case REG:
+ return REGNO (x) == REGNO (y);
+
+ /* For commutative operations, check both orders. */
+ case PLUS:
+ case MULT:
+ case AND:
+ case IOR:
+ case XOR:
+ case NE:
+ case EQ:
+ return ((expr_equiv_p (XEXP (x, 0), XEXP (y, 0))
+ && expr_equiv_p (XEXP (x, 1), XEXP (y, 1)))
+ || (expr_equiv_p (XEXP (x, 0), XEXP (y, 1))
+ && expr_equiv_p (XEXP (x, 1), XEXP (y, 0))));
+
+ default:
+ break;
+ }
+
+ /* Compare the elements. If any pair of corresponding elements
+ fail to match, return 0 for the whole thing. */
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ switch (fmt[i])
+ {
+ case 'e':
+ if (! expr_equiv_p (XEXP (x, i), XEXP (y, i)))
+ return 0;
+ break;
+
+ case 'E':
+ if (XVECLEN (x, i) != XVECLEN (y, i))
+ return 0;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (! expr_equiv_p (XVECEXP (x, i, j), XVECEXP (y, i, j)))
+ return 0;
+ break;
+
+ case 's':
+ if (strcmp (XSTR (x, i), XSTR (y, i)))
+ return 0;
+ break;
+
+ case 'i':
+ if (XINT (x, i) != XINT (y, i))
+ return 0;
+ break;
+
+ case 'w':
+ if (XWINT (x, i) != XWINT (y, i))
+ return 0;
+ break;
+
+ case '0':
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
+ return 1;
+}
+
+/* Insert expression X in INSN in the hash table.
+ If it is already present, record it as the last occurrence in INSN's
+ basic block.
+
+ MODE is the mode of the value X is being stored into.
+ It is only used if X is a CONST_INT.
+
+ ANTIC_P is non-zero if X is an anticipatable expression.
+ AVAIL_P is non-zero if X is an available expression. */
+
+static void
+insert_expr_in_table (x, mode, insn, antic_p, avail_p)
+ rtx x;
+ enum machine_mode mode;
+ rtx insn;
+ int antic_p, avail_p;
+{
+ int found, do_not_record_p;
+ unsigned int hash;
+ struct expr *cur_expr, *last_expr = NULL;
+ struct occr *antic_occr, *avail_occr;
+ struct occr *last_occr = NULL;
+
+ hash = hash_expr (x, mode, &do_not_record_p, expr_hash_table_size);
+
+ /* Do not insert expression in table if it contains volatile operands,
+ or if hash_expr determines the expression is something we don't want
+ to or can't handle. */
+ if (do_not_record_p)
+ return;
+
+ cur_expr = expr_hash_table[hash];
+ found = 0;
+
+ while (cur_expr && ! (found = expr_equiv_p (cur_expr->expr, x)))
+ {
+ /* If the expression isn't found, save a pointer to the end of
+ the list. */
+ last_expr = cur_expr;
+ cur_expr = cur_expr->next_same_hash;
+ }
+
+ if (! found)
+ {
+ cur_expr = (struct expr *) gcse_alloc (sizeof (struct expr));
+ bytes_used += sizeof (struct expr);
+ if (expr_hash_table[hash] == NULL)
+ {
+ /* This is the first pattern that hashed to this index. */
+ expr_hash_table[hash] = cur_expr;
+ }
+ else
+ {
+ /* Add EXPR to end of this hash chain. */
+ last_expr->next_same_hash = cur_expr;
+ }
+ /* Set the fields of the expr element. */
+ cur_expr->expr = x;
+ cur_expr->bitmap_index = n_exprs++;
+ cur_expr->next_same_hash = NULL;
+ cur_expr->antic_occr = NULL;
+ cur_expr->avail_occr = NULL;
+ }
+
+ /* Now record the occurrence(s). */
+
+ if (antic_p)
+ {
+ antic_occr = cur_expr->antic_occr;
+
+ /* Search for another occurrence in the same basic block. */
+ while (antic_occr && BLOCK_NUM (antic_occr->insn) != BLOCK_NUM (insn))
+ {
+ /* If an occurrence isn't found, save a pointer to the end of
+ the list. */
+ last_occr = antic_occr;
+ antic_occr = antic_occr->next;
+ }
+
+ if (antic_occr)
+ {
+ /* Found another instance of the expression in the same basic block.
+ Prefer the currently recorded one. We want the first one in the
+ block and the block is scanned from start to end. */
+ ; /* nothing to do */
+ }
+ else
+ {
+ /* First occurrence of this expression in this basic block. */
+ antic_occr = (struct occr *) gcse_alloc (sizeof (struct occr));
+ bytes_used += sizeof (struct occr);
+ /* First occurrence of this expression in any block? */
+ if (cur_expr->antic_occr == NULL)
+ cur_expr->antic_occr = antic_occr;
+ else
+ last_occr->next = antic_occr;
+ antic_occr->insn = insn;
+ antic_occr->next = NULL;
+ }
+ }
+
+ if (avail_p)
+ {
+ avail_occr = cur_expr->avail_occr;
+
+ /* Search for another occurrence in the same basic block. */
+ while (avail_occr && BLOCK_NUM (avail_occr->insn) != BLOCK_NUM (insn))
+ {
+ /* If an occurrence isn't found, save a pointer to the end of
+ the list. */
+ last_occr = avail_occr;
+ avail_occr = avail_occr->next;
+ }
+
+ if (avail_occr)
+ {
+ /* Found another instance of the expression in the same basic block.
+ Prefer this occurrence to the currently recorded one. We want
+ the last one in the block and the block is scanned from start
+ to end. */
+ avail_occr->insn = insn;
+ }
+ else
+ {
+ /* First occurrence of this expression in this basic block. */
+ avail_occr = (struct occr *) gcse_alloc (sizeof (struct occr));
+ bytes_used += sizeof (struct occr);
+ /* First occurrence of this expression in any block? */
+ if (cur_expr->avail_occr == NULL)
+ cur_expr->avail_occr = avail_occr;
+ else
+ last_occr->next = avail_occr;
+ avail_occr->insn = insn;
+ avail_occr->next = NULL;
+ }
+ }
+}
+
+/* Insert pattern X in INSN in the hash table.
+ X is a SET of a reg to either another reg or a constant.
+ If it is already present, record it as the last occurrence in INSN's
+ basic block. */
+
+static void
+insert_set_in_table (x, insn)
+ rtx x;
+ rtx insn;
+{
+ int found;
+ unsigned int hash;
+ struct expr *cur_expr, *last_expr = NULL;
+ struct occr *cur_occr, *last_occr = NULL;
+
+ if (GET_CODE (x) != SET
+ || GET_CODE (SET_DEST (x)) != REG)
+ abort ();
+
+ hash = hash_set (REGNO (SET_DEST (x)), set_hash_table_size);
+
+ cur_expr = set_hash_table[hash];
+ found = 0;
+
+ while (cur_expr && ! (found = expr_equiv_p (cur_expr->expr, x)))
+ {
+ /* If the expression isn't found, save a pointer to the end of
+ the list. */
+ last_expr = cur_expr;
+ cur_expr = cur_expr->next_same_hash;
+ }
+
+ if (! found)
+ {
+ cur_expr = (struct expr *) gcse_alloc (sizeof (struct expr));
+ bytes_used += sizeof (struct expr);
+ if (set_hash_table[hash] == NULL)
+ {
+ /* This is the first pattern that hashed to this index. */
+ set_hash_table[hash] = cur_expr;
+ }
+ else
+ {
+ /* Add EXPR to end of this hash chain. */
+ last_expr->next_same_hash = cur_expr;
+ }
+ /* Set the fields of the expr element.
+ We must copy X because it can be modified when copy propagation is
+ performed on its operands. */
+ /* ??? Should this go in a different obstack? */
+ cur_expr->expr = copy_rtx (x);
+ cur_expr->bitmap_index = n_sets++;
+ cur_expr->next_same_hash = NULL;
+ cur_expr->antic_occr = NULL;
+ cur_expr->avail_occr = NULL;
+ }
+
+ /* Now record the occurrence. */
+
+ cur_occr = cur_expr->avail_occr;
+
+ /* Search for another occurrence in the same basic block. */
+ while (cur_occr && BLOCK_NUM (cur_occr->insn) != BLOCK_NUM (insn))
+ {
+ /* If an occurrence isn't found, save a pointer to the end of
+ the list. */
+ last_occr = cur_occr;
+ cur_occr = cur_occr->next;
+ }
+
+ if (cur_occr)
+ {
+ /* Found another instance of the expression in the same basic block.
+ Prefer this occurrence to the currently recorded one. We want
+ the last one in the block and the block is scanned from start
+ to end. */
+ cur_occr->insn = insn;
+ }
+ else
+ {
+ /* First occurrence of this expression in this basic block. */
+ cur_occr = (struct occr *) gcse_alloc (sizeof (struct occr));
+ bytes_used += sizeof (struct occr);
+ /* First occurrence of this expression in any block? */
+ if (cur_expr->avail_occr == NULL)
+ cur_expr->avail_occr = cur_occr;
+ else
+ last_occr->next = cur_occr;
+ cur_occr->insn = insn;
+ cur_occr->next = NULL;
+ }
+}
+
+/* Scan pattern PAT of INSN and add an entry to the hash table.
+ If SET_P is non-zero, this is for the assignment hash table,
+ otherwise it is for the expression hash table. */
+
+static void
+hash_scan_set (pat, insn, set_p)
+ rtx pat, insn;
+ int set_p;
+{
+ rtx src = SET_SRC (pat);
+ rtx dest = SET_DEST (pat);
+
+ if (GET_CODE (src) == CALL)
+ hash_scan_call (src, insn);
+
+ if (GET_CODE (dest) == REG)
+ {
+ int regno = REGNO (dest);
+ rtx tmp;
+
+ /* Only record sets of pseudo-regs in the hash table. */
+ if (! set_p
+ && regno >= FIRST_PSEUDO_REGISTER
+ /* Don't GCSE something if we can't do a reg/reg copy. */
+ && can_copy_p [GET_MODE (dest)]
+ /* Is SET_SRC something we want to gcse? */
+ && want_to_gcse_p (src))
+ {
+ /* An expression is not anticipatable if its operands are
+ modified before this insn. */
+ int antic_p = ! optimize_size && oprs_anticipatable_p (src, insn);
+ /* An expression is not available if its operands are
+ subsequently modified, including this insn. */
+ int avail_p = oprs_available_p (src, insn);
+ insert_expr_in_table (src, GET_MODE (dest), insn, antic_p, avail_p);
+ }
+ /* Record sets for constant/copy propagation. */
+ else if (set_p
+ && regno >= FIRST_PSEUDO_REGISTER
+ && ((GET_CODE (src) == REG
+ && REGNO (src) >= FIRST_PSEUDO_REGISTER
+ && can_copy_p [GET_MODE (dest)])
+ /* ??? CONST_INT:wip */
+ || GET_CODE (src) == CONST_INT)
+ /* A copy is not available if its src or dest is subsequently
+ modified. Here we want to search from INSN+1 on, but
+ oprs_available_p searches from INSN on. */
+ && (insn == BLOCK_END (BLOCK_NUM (insn))
+ || ((tmp = next_nonnote_insn (insn)) != NULL_RTX
+ && oprs_available_p (pat, tmp))))
+ insert_set_in_table (pat, insn);
+ }
+
+ /* Check if first/last set in this block for classic gcse,
+ but not for copy/constant propagation. */
+ if (optimize_size && !set_p)
+
+ {
+ rtx dest = SET_DEST (pat);
+
+ while (GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == ZERO_EXTRACT
+ || GET_CODE (dest) == SIGN_EXTRACT
+ || GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+ if (GET_CODE (dest) == REG)
+ maybe_set_rd_gen (REGNO (dest), insn);
+ }
+}
+
+static void
+hash_scan_clobber (x, insn)
+ rtx x ATTRIBUTE_UNUSED, insn ATTRIBUTE_UNUSED;
+{
+ /* Currently nothing to do. */
+}
+
+static void
+hash_scan_call (x, insn)
+ rtx x ATTRIBUTE_UNUSED, insn ATTRIBUTE_UNUSED;
+{
+ /* Currently nothing to do. */
+}
+
+/* Process INSN and add hash table entries as appropriate.
+
+ Only available expressions that set a single pseudo-reg are recorded.
+
+ Single sets in a PARALLEL could be handled, but it's an extra complication
+ that isn't dealt with right now. The trick is handling the CLOBBERs that
+ are also in the PARALLEL. Later.
+
+ If SET_P is non-zero, this is for the assignment hash table,
+ otherwise it is for the expression hash table.
+ If IN_LIBCALL_BLOCK nonzero, we are in a libcall block, and should
+ not record any expressions. */
+
+static void
+hash_scan_insn (insn, set_p, in_libcall_block)
+ rtx insn;
+ int set_p;
+ int in_libcall_block;
+{
+ rtx pat = PATTERN (insn);
+
+ /* Pick out the sets of INSN and for other forms of instructions record
+ what's been modified. */
+
+ if (GET_CODE (pat) == SET && ! in_libcall_block)
+ hash_scan_set (pat, insn, set_p);
+ else if (GET_CODE (pat) == PARALLEL)
+ {
+ int i;
+
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ {
+ rtx x = XVECEXP (pat, 0, i);
+
+ if (GET_CODE (x) == SET)
+ {
+ if (GET_CODE (SET_SRC (x)) == CALL)
+ hash_scan_call (SET_SRC (x), insn);
+
+ /* Check if first/last set in this block for classic
+ gcse, but not for constant/copy propagation. */
+ if (optimize_size && !set_p)
+ {
+ rtx dest = SET_DEST (x);
+
+ while (GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == ZERO_EXTRACT
+ || GET_CODE (dest) == SIGN_EXTRACT
+ || GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+ if (GET_CODE (dest) == REG)
+ maybe_set_rd_gen (REGNO (dest), insn);
+ }
+ }
+ else if (GET_CODE (x) == CLOBBER)
+ hash_scan_clobber (x, insn);
+ else if (GET_CODE (x) == CALL)
+ hash_scan_call (x, insn);
+ }
+ }
+ else if (GET_CODE (pat) == CLOBBER)
+ hash_scan_clobber (pat, insn);
+ else if (GET_CODE (pat) == CALL)
+ hash_scan_call (pat, insn);
+}
+
+static void
+dump_hash_table (file, name, table, table_size, total_size)
+ FILE *file;
+ char *name;
+ struct expr **table;
+ int table_size, total_size;
+{
+ int i;
+ /* Flattened out table, so it's printed in proper order. */
+ struct expr **flat_table = (struct expr **) alloca (total_size * sizeof (struct expr *));
+ unsigned int *hash_val = (unsigned int *) alloca (total_size * sizeof (unsigned int));
+
+ bzero ((char *) flat_table, total_size * sizeof (struct expr *));
+ for (i = 0; i < table_size; i++)
+ {
+ struct expr *expr;
+
+ for (expr = table[i]; expr != NULL; expr = expr->next_same_hash)
+ {
+ flat_table[expr->bitmap_index] = expr;
+ hash_val[expr->bitmap_index] = i;
+ }
+ }
+
+ fprintf (file, "%s hash table (%d buckets, %d entries)\n",
+ name, table_size, total_size);
+
+ for (i = 0; i < total_size; i++)
+ {
+ struct expr *expr = flat_table[i];
+
+ fprintf (file, "Index %d (hash value %d)\n ",
+ expr->bitmap_index, hash_val[i]);
+ print_rtl (file, expr->expr);
+ fprintf (file, "\n");
+ }
+
+ fprintf (file, "\n");
+}
+
+/* Record register first/last/block set information for REGNO in INSN.
+ reg_first_set records the first place in the block where the register
+ is set and is used to compute "anticipatability".
+ reg_last_set records the last place in the block where the register
+ is set and is used to compute "availability".
+ reg_set_in_block records whether the register is set in the block
+ and is used to compute "transparency". */
+
+static void
+record_last_reg_set_info (insn, regno)
+ rtx insn;
+ int regno;
+{
+ if (reg_first_set[regno] == NEVER_SET)
+ reg_first_set[regno] = INSN_CUID (insn);
+ reg_last_set[regno] = INSN_CUID (insn);
+ SET_BIT (reg_set_in_block[BLOCK_NUM (insn)], regno);
+}
+
+/* Record memory first/last/block set information for INSN. */
+
+static void
+record_last_mem_set_info (insn)
+ rtx insn;
+{
+ if (mem_first_set == NEVER_SET)
+ mem_first_set = INSN_CUID (insn);
+ mem_last_set = INSN_CUID (insn);
+ mem_set_in_block[BLOCK_NUM (insn)] = 1;
+}
+
+/* Used for communicating between next two routines. */
+static rtx last_set_insn;
+
+/* Called from compute_hash_table via note_stores to handle one
+ SET or CLOBBER in an insn. */
+
+static void
+record_last_set_info (dest, setter)
+ rtx dest, setter ATTRIBUTE_UNUSED;
+{
+ if (GET_CODE (dest) == SUBREG)
+ dest = SUBREG_REG (dest);
+
+ if (GET_CODE (dest) == REG)
+ record_last_reg_set_info (last_set_insn, REGNO (dest));
+ else if (GET_CODE (dest) == MEM
+ /* Ignore pushes, they clobber nothing. */
+ && ! push_operand (dest, GET_MODE (dest)))
+ record_last_mem_set_info (last_set_insn);
+}
+
+/* Top level function to create an expression or assignment hash table.
+
+ Expression entries are placed in the hash table if
+ - they are of the form (set (pseudo-reg) src),
+ - src is something we want to perform GCSE on,
+ - none of the operands are subsequently modified in the block
+
+ Assignment entries are placed in the hash table if
+ - they are of the form (set (pseudo-reg) src),
+ - src is something we want to perform const/copy propagation on,
+ - none of the operands or target are subsequently modified in the block
+ Currently src must be a pseudo-reg or a const_int.
+
+ F is the first insn.
+ SET_P is non-zero for computing the assignment hash table. */
+
+static void
+compute_hash_table (f, set_p)
+ rtx f ATTRIBUTE_UNUSED;
+ int set_p;
+{
+ int bb;
+
+ /* While we compute the hash table we also compute a bit array of which
+ registers are set in which blocks.
+ We also compute which blocks set memory, in the absence of aliasing
+ support [which is TODO].
+ ??? This isn't needed during const/copy propagation, but it's cheap to
+ compute. Later. */
+ sbitmap_vector_zero (reg_set_in_block, n_basic_blocks);
+ bzero ((char *) mem_set_in_block, n_basic_blocks);
+
+ /* Some working arrays used to track first and last set in each block. */
+ /* ??? One could use alloca here, but at some size a threshold is crossed
+ beyond which one should use malloc. Are we at that threshold here? */
+ reg_first_set = (int *) gmalloc (max_gcse_regno * sizeof (int));
+ reg_last_set = (int *) gmalloc (max_gcse_regno * sizeof (int));
+
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ rtx insn;
+ int regno;
+ int in_libcall_block;
+ int i;
+
+ /* First pass over the instructions records information used to
+ determine when registers and memory are first and last set.
+ ??? The mem_set_in_block and hard-reg reg_set_in_block computation
+ could be moved to compute_sets since they currently don't change. */
+
+ for (i = 0; i < max_gcse_regno; i++)
+ reg_first_set[i] = reg_last_set[i] = NEVER_SET;
+ mem_first_set = NEVER_SET;
+ mem_last_set = NEVER_SET;
+
+ for (insn = basic_block_head[bb];
+ insn && insn != NEXT_INSN (basic_block_end[bb]);
+ insn = NEXT_INSN (insn))
+ {
+#ifdef NON_SAVING_SETJMP
+ if (NON_SAVING_SETJMP && GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+ {
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ record_last_reg_set_info (insn, regno);
+ continue;
+ }
+#endif
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ continue;
+
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (call_used_regs[regno])
+ record_last_reg_set_info (insn, regno);
+ if (! CONST_CALL_P (insn))
+ record_last_mem_set_info (insn);
+ }
+
+ last_set_insn = insn;
+ note_stores (PATTERN (insn), record_last_set_info);
+ }
+
+ /* The next pass builds the hash table. */
+
+ for (insn = basic_block_head[bb], in_libcall_block = 0;
+ insn && insn != NEXT_INSN (basic_block_end[bb]);
+ insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ in_libcall_block = 1;
+ else if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
+ in_libcall_block = 0;
+ hash_scan_insn (insn, set_p, in_libcall_block);
+ }
+ }
+ }
+
+ free (reg_first_set);
+ free (reg_last_set);
+ /* Catch bugs early. */
+ reg_first_set = reg_last_set = 0;
+}
+
+/* Allocate space for the set hash table.
+ N_INSNS is the number of instructions in the function.
+ It is used to determine the number of buckets to use. */
+
+static void
+alloc_set_hash_table (n_insns)
+ int n_insns;
+{
+ int n;
+
+ set_hash_table_size = n_insns / 4;
+ if (set_hash_table_size < 11)
+ set_hash_table_size = 11;
+ /* Attempt to maintain efficient use of hash table.
+ Making it an odd number is simplest for now.
+ ??? Later take some measurements. */
+ set_hash_table_size |= 1;
+ n = set_hash_table_size * sizeof (struct expr *);
+ set_hash_table = (struct expr **) gmalloc (n);
+}
+
+/* Free things allocated by alloc_set_hash_table. */
+
+static void
+free_set_hash_table ()
+{
+ free (set_hash_table);
+}
+
+/* Compute the hash table for doing copy/const propagation. */
+
+static void
+compute_set_hash_table (f)
+ rtx f;
+{
+ /* Initialize count of number of entries in hash table. */
+ n_sets = 0;
+ bzero ((char *) set_hash_table, set_hash_table_size * sizeof (struct expr *));
+
+ compute_hash_table (f, 1);
+}
+
+/* Allocate space for the expression hash table.
+ N_INSNS is the number of instructions in the function.
+ It is used to determine the number of buckets to use. */
+
+static void
+alloc_expr_hash_table (n_insns)
+ int n_insns;
+{
+ int n;
+
+ expr_hash_table_size = n_insns / 2;
+ /* Make sure the amount is usable. */
+ if (expr_hash_table_size < 11)
+ expr_hash_table_size = 11;
+ /* Attempt to maintain efficient use of hash table.
+ Making it an odd number is simplest for now.
+ ??? Later take some measurements. */
+ expr_hash_table_size |= 1;
+ n = expr_hash_table_size * sizeof (struct expr *);
+ expr_hash_table = (struct expr **) gmalloc (n);
+}
+
+/* Free things allocated by alloc_expr_hash_table. */
+
+static void
+free_expr_hash_table ()
+{
+ free (expr_hash_table);
+}
+
+/* Compute the hash table for doing GCSE. */
+
+static void
+compute_expr_hash_table (f)
+ rtx f;
+{
+ /* Initialize count of number of entries in hash table. */
+ n_exprs = 0;
+ bzero ((char *) expr_hash_table, expr_hash_table_size * sizeof (struct expr *));
+
+ compute_hash_table (f, 0);
+}
+
+/* Expression tracking support. */
+
+/* Lookup pattern PAT in the expression table.
+ The result is a pointer to the table entry, or NULL if not found. */
+
+static struct expr *
+lookup_expr (pat)
+ rtx pat;
+{
+ int do_not_record_p;
+ unsigned int hash = hash_expr (pat, GET_MODE (pat), &do_not_record_p,
+ expr_hash_table_size);
+ struct expr *expr;
+
+ if (do_not_record_p)
+ return NULL;
+
+ expr = expr_hash_table[hash];
+
+ while (expr && ! expr_equiv_p (expr->expr, pat))
+ expr = expr->next_same_hash;
+
+ return expr;
+}
+
+/* Lookup REGNO in the set table.
+ If PAT is non-NULL look for the entry that matches it, otherwise return
+ the first entry for REGNO.
+ The result is a pointer to the table entry, or NULL if not found. */
+
+static struct expr *
+lookup_set (regno, pat)
+ int regno;
+ rtx pat;
+{
+ unsigned int hash = hash_set (regno, set_hash_table_size);
+ struct expr *expr;
+
+ expr = set_hash_table[hash];
+
+ if (pat)
+ {
+ while (expr && ! expr_equiv_p (expr->expr, pat))
+ expr = expr->next_same_hash;
+ }
+ else
+ {
+ while (expr && REGNO (SET_DEST (expr->expr)) != regno)
+ expr = expr->next_same_hash;
+ }
+
+ return expr;
+}
+
+/* Return the next entry for REGNO in list EXPR. */
+
+static struct expr *
+next_set (regno, expr)
+ int regno;
+ struct expr *expr;
+{
+ do
+ expr = expr->next_same_hash;
+ while (expr && REGNO (SET_DEST (expr->expr)) != regno);
+ return expr;
+}
+
+/* Reset tables used to keep track of what's still available [since the
+ start of the block]. */
+
+static void
+reset_opr_set_tables ()
+{
+ /* Maintain a bitmap of which regs have been set since beginning of
+ the block. */
+ sbitmap_zero (reg_set_bitmap);
+ /* Also keep a record of the last instruction to modify memory.
+ For now this is very trivial, we only record whether any memory
+ location has been modified. */
+ mem_last_set = 0;
+}
+
+/* Return non-zero if the operands of X are not set before INSN in
+ INSN's basic block. */
+
+static int
+oprs_not_set_p (x, insn)
+ rtx x, insn;
+{
+ int i;
+ enum rtx_code code;
+ char *fmt;
+
+ /* repeat is used to turn tail-recursion into iteration. */
+repeat:
+
+ if (x == 0)
+ return 1;
+
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case PC:
+ case CC0:
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ return 1;
+
+ case MEM:
+ if (mem_last_set != 0)
+ return 0;
+ x = XEXP (x, 0);
+ goto repeat;
+
+ case REG:
+ return ! TEST_BIT (reg_set_bitmap, REGNO (x));
+
+ default:
+ break;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ int not_set_p;
+ /* If we are about to do the last recursive call
+ needed at this level, change it into iteration.
+ This function is called enough to be worth it. */
+ if (i == 0)
+ {
+ x = XEXP (x, 0);
+ goto repeat;
+ }
+ not_set_p = oprs_not_set_p (XEXP (x, i), insn);
+ if (! not_set_p)
+ return 0;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ {
+ int not_set_p = oprs_not_set_p (XVECEXP (x, i, j), insn);
+ if (! not_set_p)
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/* Mark things set by a CALL. */
+
+static void
+mark_call (pat, insn)
+ rtx pat ATTRIBUTE_UNUSED, insn;
+{
+ mem_last_set = INSN_CUID (insn);
+}
+
+/* Mark things set by a SET. */
+
+static void
+mark_set (pat, insn)
+ rtx pat, insn;
+{
+ rtx dest = SET_DEST (pat);
+
+ while (GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == ZERO_EXTRACT
+ || GET_CODE (dest) == SIGN_EXTRACT
+ || GET_CODE (dest) == STRICT_LOW_PART)
+ dest = XEXP (dest, 0);
+
+ if (GET_CODE (dest) == REG)
+ SET_BIT (reg_set_bitmap, REGNO (dest));
+ else if (GET_CODE (dest) == MEM)
+ mem_last_set = INSN_CUID (insn);
+
+ if (GET_CODE (SET_SRC (pat)) == CALL)
+ mark_call (SET_SRC (pat), insn);
+}
+
+/* Record things set by a CLOBBER. */
+
+static void
+mark_clobber (pat, insn)
+ rtx pat, insn;
+{
+ rtx clob = XEXP (pat, 0);
+
+ while (GET_CODE (clob) == SUBREG || GET_CODE (clob) == STRICT_LOW_PART)
+ clob = XEXP (clob, 0);
+
+ if (GET_CODE (clob) == REG)
+ SET_BIT (reg_set_bitmap, REGNO (clob));
+ else
+ mem_last_set = INSN_CUID (insn);
+}
+
+/* Record things set by INSN.
+ This data is used by oprs_not_set_p. */
+
+static void
+mark_oprs_set (insn)
+ rtx insn;
+{
+ rtx pat = PATTERN (insn);
+
+ if (GET_CODE (pat) == SET)
+ mark_set (pat, insn);
+ else if (GET_CODE (pat) == PARALLEL)
+ {
+ int i;
+
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ {
+ rtx x = XVECEXP (pat, 0, i);
+
+ if (GET_CODE (x) == SET)
+ mark_set (x, insn);
+ else if (GET_CODE (x) == CLOBBER)
+ mark_clobber (x, insn);
+ else if (GET_CODE (x) == CALL)
+ mark_call (x, insn);
+ }
+ }
+ else if (GET_CODE (pat) == CLOBBER)
+ mark_clobber (pat, insn);
+ else if (GET_CODE (pat) == CALL)
+ mark_call (pat, insn);
+}
+
+/* Classic GCSE reaching definition support. */
+
+/* Allocate reaching def variables. */
+
+static void
+alloc_rd_mem (n_blocks, n_insns)
+ int n_blocks, n_insns;
+{
+ rd_kill = (sbitmap *) sbitmap_vector_alloc (n_blocks, n_insns);
+ sbitmap_vector_zero (rd_kill, n_basic_blocks);
+
+ rd_gen = (sbitmap *) sbitmap_vector_alloc (n_blocks, n_insns);
+ sbitmap_vector_zero (rd_gen, n_basic_blocks);
+
+ reaching_defs = (sbitmap *) sbitmap_vector_alloc (n_blocks, n_insns);
+ sbitmap_vector_zero (reaching_defs, n_basic_blocks);
+
+ rd_out = (sbitmap *) sbitmap_vector_alloc (n_blocks, n_insns);
+ sbitmap_vector_zero (rd_out, n_basic_blocks);
+}
+
+/* Free reaching def variables. */
+
+static void
+free_rd_mem ()
+{
+ free (rd_kill);
+ free (rd_gen);
+ free (reaching_defs);
+ free (rd_out);
+}
+
+/* Add INSN to the kills of BB.
+ REGNO, set in BB, is killed by INSN. */
+
+static void
+handle_rd_kill_set (insn, regno, bb)
+ rtx insn;
+ int regno, bb;
+{
+ struct reg_set *this_reg = reg_set_table[regno];
+
+ while (this_reg)
+ {
+ if (BLOCK_NUM (this_reg->insn) != BLOCK_NUM (insn))
+ SET_BIT (rd_kill[bb], INSN_CUID (this_reg->insn));
+ this_reg = this_reg->next;
+ }
+}
+
+void
+dump_rd_table (file, title, bmap)
+ FILE *file;
+ char *title;
+ sbitmap *bmap;
+{
+ int bb,cuid,i,j,n;
+
+ fprintf (file, "%s\n", title);
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ fprintf (file, "BB %d\n", bb);
+ dump_sbitmap (file, bmap[bb]);
+ for (i = n = cuid = 0; i < bmap[bb]->size; i++)
+ {
+ for (j = 0; j < SBITMAP_ELT_BITS; j++, cuid++)
+ {
+ if ((bmap[bb]->elms[i] & (1 << j)) != 0)
+ {
+ if (n % 10 == 0)
+ fprintf (file, " ");
+ fprintf (file, " %d", INSN_UID (CUID_INSN (cuid)));
+ n++;
+ }
+ }
+ }
+ if (n != 0)
+ fprintf (file, "\n");
+ }
+ fprintf (file, "\n");
+}
+
+/* Compute the set of kill's for reaching definitions. */
+
+static void
+compute_kill_rd ()
+{
+ int bb,cuid;
+
+ /* For each block
+ For each set bit in `gen' of the block (i.e each insn which
+ generates a definition in the block)
+ Call the reg set by the insn corresponding to that bit regx
+ Look at the linked list starting at reg_set_table[regx]
+ For each setting of regx in the linked list, which is not in
+ this block
+ Set the bit in `kill' corresponding to that insn
+ */
+
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ for (cuid = 0; cuid < max_cuid; cuid++)
+ {
+ if (TEST_BIT (rd_gen[bb], cuid))
+ {
+ rtx insn = CUID_INSN (cuid);
+ rtx pat = PATTERN (insn);
+
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ int regno;
+
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ {
+ if (call_used_regs[regno])
+ handle_rd_kill_set (insn, regno, bb);
+ }
+ }
+
+ if (GET_CODE (pat) == PARALLEL)
+ {
+ int i;
+
+ /* We work backwards because ... */
+ for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
+ {
+ enum rtx_code code = GET_CODE (XVECEXP (pat, 0, i));
+ if ((code == SET || code == CLOBBER)
+ && GET_CODE (XEXP (XVECEXP (pat, 0, i), 0)) == REG)
+ handle_rd_kill_set (insn,
+ REGNO (XEXP (XVECEXP (pat, 0, i), 0)),
+ bb);
+ }
+ }
+ else if (GET_CODE (pat) == SET)
+ {
+ if (GET_CODE (SET_DEST (pat)) == REG)
+ {
+ /* Each setting of this register outside of this block
+ must be marked in the set of kills in this block. */
+ handle_rd_kill_set (insn, REGNO (SET_DEST (pat)), bb);
+ }
+ }
+ /* FIXME: CLOBBER? */
+ }
+ }
+ }
+}
+
+/* Compute the reaching definitions as in
+ Compilers Principles, Techniques, and Tools. Aho, Sethi, Ullman,
+ Chapter 10. It is the same algorithm as used for computing available
+ expressions but applied to the gens and kills of reaching definitions. */
+
+static void
+compute_rd ()
+{
+ int bb, changed, passes;
+
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ sbitmap_copy (rd_out[bb] /*dst*/, rd_gen[bb] /*src*/);
+
+ passes = 0;
+ changed = 1;
+ while (changed)
+ {
+ changed = 0;
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ sbitmap_union_of_predecessors (reaching_defs[bb], rd_out,
+ bb, s_preds);
+ changed |= sbitmap_union_of_diff (rd_out[bb], rd_gen[bb],
+ reaching_defs[bb], rd_kill[bb]);
+ }
+ passes++;
+ }
+
+ if (gcse_file)
+ fprintf (gcse_file, "reaching def computation: %d passes\n", passes);
+}
+
+/* Classic GCSE available expression support. */
+
+/* Allocate memory for available expression computation. */
+
+static void
+alloc_avail_expr_mem (n_blocks, n_exprs)
+ int n_blocks, n_exprs;
+{
+ ae_kill = (sbitmap *) sbitmap_vector_alloc (n_blocks, n_exprs);
+ sbitmap_vector_zero (ae_kill, n_basic_blocks);
+
+ ae_gen = (sbitmap *) sbitmap_vector_alloc (n_blocks, n_exprs);
+ sbitmap_vector_zero (ae_gen, n_basic_blocks);
+
+ ae_in = (sbitmap *) sbitmap_vector_alloc (n_blocks, n_exprs);
+ sbitmap_vector_zero (ae_in, n_basic_blocks);
+
+ ae_out = (sbitmap *) sbitmap_vector_alloc (n_blocks, n_exprs);
+ sbitmap_vector_zero (ae_out, n_basic_blocks);
+
+ u_bitmap = (sbitmap) sbitmap_alloc (n_exprs);
+ sbitmap_ones (u_bitmap);
+}
+
+static void
+free_avail_expr_mem ()
+{
+ free (ae_kill);
+ free (ae_gen);
+ free (ae_in);
+ free (ae_out);
+ free (u_bitmap);
+}
+
+/* Compute the set of available expressions generated in each basic block. */
+
+static void
+compute_ae_gen ()
+{
+ int i;
+
+ /* For each recorded occurrence of each expression, set ae_gen[bb][expr].
+ This is all we have to do because an expression is not recorded if it
+ is not available, and the only expressions we want to work with are the
+ ones that are recorded. */
+
+ for (i = 0; i < expr_hash_table_size; i++)
+ {
+ struct expr *expr = expr_hash_table[i];
+ while (expr != NULL)
+ {
+ struct occr *occr = expr->avail_occr;
+ while (occr != NULL)
+ {
+ SET_BIT (ae_gen[BLOCK_NUM (occr->insn)], expr->bitmap_index);
+ occr = occr->next;
+ }
+ expr = expr->next_same_hash;
+ }
+ }
+}
+
+/* Return non-zero if expression X is killed in BB. */
+
+static int
+expr_killed_p (x, bb)
+ rtx x;
+ int bb;
+{
+ int i;
+ enum rtx_code code;
+ char *fmt;
+
+ /* repeat is used to turn tail-recursion into iteration. */
+ repeat:
+
+ if (x == 0)
+ return 1;
+
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case REG:
+ return TEST_BIT (reg_set_in_block[bb], REGNO (x));
+
+ case MEM:
+ if (mem_set_in_block[bb])
+ return 1;
+ x = XEXP (x, 0);
+ goto repeat;
+
+ case PC:
+ case CC0: /*FIXME*/
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ return 0;
+
+ default:
+ break;
+ }
+
+ i = GET_RTX_LENGTH (code) - 1;
+ fmt = GET_RTX_FORMAT (code);
+ for (; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ rtx tem = XEXP (x, i);
+
+ /* If we are about to do the last recursive call
+ needed at this level, change it into iteration.
+ This function is called enough to be worth it. */
+ if (i == 0)
+ {
+ x = tem;
+ goto repeat;
+ }
+ if (expr_killed_p (tem, bb))
+ return 1;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ {
+ if (expr_killed_p (XVECEXP (x, i, j), bb))
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Compute the set of available expressions killed in each basic block. */
+
+static void
+compute_ae_kill ()
+{
+ int bb,i;
+
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ for (i = 0; i < expr_hash_table_size; i++)
+ {
+ struct expr *expr = expr_hash_table[i];
+
+ for ( ; expr != NULL; expr = expr->next_same_hash)
+ {
+ /* Skip EXPR if generated in this block. */
+ if (TEST_BIT (ae_gen[bb], expr->bitmap_index))
+ continue;
+
+ if (expr_killed_p (expr->expr, bb))
+ SET_BIT (ae_kill[bb], expr->bitmap_index);
+ }
+ }
+ }
+}
+
+/* Compute available expressions.
+
+ Implement the algorithm to find available expressions
+ as given in the Aho Sethi Ullman book, pages 627-631. */
+
+static void
+compute_available ()
+{
+ int bb, changed, passes;
+
+ sbitmap_zero (ae_in[0]);
+
+ sbitmap_copy (ae_out[0] /*dst*/, ae_gen[0] /*src*/);
+
+ for (bb = 1; bb < n_basic_blocks; bb++)
+ sbitmap_difference (ae_out[bb], u_bitmap, ae_kill[bb]);
+
+ passes = 0;
+ changed = 1;
+ while (changed)
+ {
+ changed = 0;
+ for (bb = 1; bb < n_basic_blocks; bb++)
+ {
+ sbitmap_intersect_of_predecessors (ae_in[bb], ae_out,
+ bb, s_preds);
+ changed |= sbitmap_union_of_diff (ae_out[bb], ae_gen[bb],
+ ae_in[bb], ae_kill[bb]);
+ }
+ passes++;
+ }
+
+ if (gcse_file)
+ fprintf (gcse_file, "avail expr computation: %d passes\n", passes);
+}
+
+/* Actually perform the Classic GCSE optimizations. */
+
+/* Return non-zero if occurrence OCCR of expression EXPR reaches block BB.
+
+ CHECK_SELF_LOOP is non-zero if we should consider a block reaching itself
+ as a positive reach. We want to do this when there are two computations
+ of the expression in the block.
+
+ VISITED is a pointer to a working buffer for tracking which BB's have
+ been visited. It is NULL for the top-level call.
+
+ We treat reaching expressions that go through blocks containing the same
+ reaching expression as "not reaching". E.g. if EXPR is generated in blocks
+ 2 and 3, INSN is in block 4, and 2->3->4, we treat the expression in block
+ 2 as not reaching. The intent is to improve the probability of finding
+ only one reaching expression and to reduce register lifetimes by picking
+ the closest such expression. */
+
+static int
+expr_reaches_here_p (occr, expr, bb, check_self_loop, visited)
+ struct occr *occr;
+ struct expr *expr;
+ int bb;
+ int check_self_loop;
+ char *visited;
+{
+ int_list_ptr pred;
+
+ if (visited == NULL)
+ {
+ visited = (char *) alloca (n_basic_blocks);
+ bzero (visited, n_basic_blocks);
+ }
+
+ for (pred = s_preds[bb]; pred != NULL; pred = pred->next)
+ {
+ int pred_bb = INT_LIST_VAL (pred);
+
+ if (visited[pred_bb])
+ {
+ /* This predecessor has already been visited.
+ Nothing to do. */
+ ;
+ }
+ else if (pred_bb == bb)
+ {
+ /* BB loops on itself. */
+ if (check_self_loop
+ && TEST_BIT (ae_gen[pred_bb], expr->bitmap_index)
+ && BLOCK_NUM (occr->insn) == pred_bb)
+ return 1;
+ visited[pred_bb] = 1;
+ }
+ /* Ignore this predecessor if it kills the expression. */
+ else if (TEST_BIT (ae_kill[pred_bb], expr->bitmap_index))
+ visited[pred_bb] = 1;
+ /* Does this predecessor generate this expression? */
+ else if (TEST_BIT (ae_gen[pred_bb], expr->bitmap_index))
+ {
+ /* Is this the occurrence we're looking for?
+ Note that there's only one generating occurrence per block
+ so we just need to check the block number. */
+ if (BLOCK_NUM (occr->insn) == pred_bb)
+ return 1;
+ visited[pred_bb] = 1;
+ }
+ /* Neither gen nor kill. */
+ else
+ {
+ visited[pred_bb] = 1;
+ if (expr_reaches_here_p (occr, expr, pred_bb, check_self_loop, visited))
+ return 1;
+ }
+ }
+
+ /* All paths have been checked. */
+ return 0;
+}
+
+/* Return the instruction that computes EXPR that reaches INSN's basic block.
+ If there is more than one such instruction, return NULL.
+
+ Called only by handle_avail_expr. */
+
+static rtx
+computing_insn (expr, insn)
+ struct expr *expr;
+ rtx insn;
+{
+ int bb = BLOCK_NUM (insn);
+
+ if (expr->avail_occr->next == NULL)
+ {
+ if (BLOCK_NUM (expr->avail_occr->insn) == bb)
+ {
+ /* The available expression is actually itself
+ (i.e. a loop in the flow graph) so do nothing. */
+ return NULL;
+ }
+ /* (FIXME) Case that we found a pattern that was created by
+ a substitution that took place. */
+ return expr->avail_occr->insn;
+ }
+ else
+ {
+ /* Pattern is computed more than once.
+ Search backwards from this insn to see how many of these
+ computations actually reach this insn. */
+ struct occr *occr;
+ rtx insn_computes_expr = NULL;
+ int can_reach = 0;
+
+ for (occr = expr->avail_occr; occr != NULL; occr = occr->next)
+ {
+ if (BLOCK_NUM (occr->insn) == bb)
+ {
+ /* The expression is generated in this block.
+ The only time we care about this is when the expression
+ is generated later in the block [and thus there's a loop].
+ We let the normal cse pass handle the other cases. */
+ if (INSN_CUID (insn) < INSN_CUID (occr->insn))
+ {
+ if (expr_reaches_here_p (occr, expr, bb, 1, NULL))
+ {
+ can_reach++;
+ if (can_reach > 1)
+ return NULL;
+ insn_computes_expr = occr->insn;
+ }
+ }
+ }
+ else /* Computation of the pattern outside this block. */
+ {
+ if (expr_reaches_here_p (occr, expr, bb, 0, NULL))
+ {
+ can_reach++;
+ if (can_reach > 1)
+ return NULL;
+ insn_computes_expr = occr->insn;
+ }
+ }
+ }
+
+ if (insn_computes_expr == NULL)
+ abort ();
+ return insn_computes_expr;
+ }
+}
+
+/* Return non-zero if the definition in DEF_INSN can reach INSN.
+ Only called by can_disregard_other_sets. */
+
+static int
+def_reaches_here_p (insn, def_insn)
+ rtx insn, def_insn;
+{
+ rtx reg;
+
+ if (TEST_BIT (reaching_defs[BLOCK_NUM (insn)], INSN_CUID (def_insn)))
+ return 1;
+
+ if (BLOCK_NUM (insn) == BLOCK_NUM (def_insn))
+ {
+ if (INSN_CUID (def_insn) < INSN_CUID (insn))
+ {
+ if (GET_CODE (PATTERN (def_insn)) == PARALLEL)
+ return 1;
+ if (GET_CODE (PATTERN (def_insn)) == CLOBBER)
+ reg = XEXP (PATTERN (def_insn), 0);
+ else if (GET_CODE (PATTERN (def_insn)) == SET)
+ reg = SET_DEST (PATTERN (def_insn));
+ else
+ abort ();
+ return ! reg_set_between_p (reg, NEXT_INSN (def_insn), insn);
+ }
+ else
+ return 0;
+ }
+
+ return 0;
+}
+
+/* Return non-zero if *ADDR_THIS_REG can only have one value at INSN.
+ The value returned is the number of definitions that reach INSN.
+ Returning a value of zero means that [maybe] more than one definition
+ reaches INSN and the caller can't perform whatever optimization it is
+ trying. i.e. it is always safe to return zero. */
+
+static int
+can_disregard_other_sets (addr_this_reg, insn, for_combine)
+ struct reg_set **addr_this_reg;
+ rtx insn;
+ int for_combine;
+{
+ int number_of_reaching_defs = 0;
+ struct reg_set *this_reg = *addr_this_reg;
+
+ while (this_reg)
+ {
+ if (def_reaches_here_p (insn, this_reg->insn))
+ {
+ number_of_reaching_defs++;
+ /* Ignore parallels for now. */
+ if (GET_CODE (PATTERN (this_reg->insn)) == PARALLEL)
+ return 0;
+ if (!for_combine
+ && (GET_CODE (PATTERN (this_reg->insn)) == CLOBBER
+ || ! rtx_equal_p (SET_SRC (PATTERN (this_reg->insn)),
+ SET_SRC (PATTERN (insn)))))
+ {
+ /* A setting of the reg to a different value reaches INSN. */
+ return 0;
+ }
+ if (number_of_reaching_defs > 1)
+ {
+ /* If in this setting the value the register is being
+ set to is equal to the previous value the register
+ was set to and this setting reaches the insn we are
+ trying to do the substitution on then we are ok. */
+
+ if (GET_CODE (PATTERN (this_reg->insn)) == CLOBBER)
+ return 0;
+ if (! rtx_equal_p (SET_SRC (PATTERN (this_reg->insn)),
+ SET_SRC (PATTERN (insn))))
+ return 0;
+ }
+ *addr_this_reg = this_reg;
+ }
+
+ /* prev_this_reg = this_reg; */
+ this_reg = this_reg->next;
+ }
+
+ return number_of_reaching_defs;
+}
+
+/* Expression computed by insn is available and the substitution is legal,
+ so try to perform the substitution.
+
+ The result is non-zero if any changes were made. */
+
+static int
+handle_avail_expr (insn, expr)
+ rtx insn;
+ struct expr *expr;
+{
+ rtx pat, insn_computes_expr;
+ rtx to;
+ struct reg_set *this_reg;
+ int found_setting, use_src;
+ int changed = 0;
+
+ /* We only handle the case where one computation of the expression
+ reaches this instruction. */
+ insn_computes_expr = computing_insn (expr, insn);
+ if (insn_computes_expr == NULL)
+ return 0;
+
+ found_setting = 0;
+ use_src = 0;
+
+ /* At this point we know only one computation of EXPR outside of this
+ block reaches this insn. Now try to find a register that the
+ expression is computed into. */
+
+ if (GET_CODE (SET_SRC (PATTERN (insn_computes_expr))) == REG)
+ {
+ /* This is the case when the available expression that reaches
+ here has already been handled as an available expression. */
+ int regnum_for_replacing = REGNO (SET_SRC (PATTERN (insn_computes_expr)));
+ /* If the register was created by GCSE we can't use `reg_set_table',
+ however we know it's set only once. */
+ if (regnum_for_replacing >= max_gcse_regno
+ /* If the register the expression is computed into is set only once,
+ or only one set reaches this insn, we can use it. */
+ || (((this_reg = reg_set_table[regnum_for_replacing]),
+ this_reg->next == NULL)
+ || can_disregard_other_sets (&this_reg, insn, 0)))
+ {
+ use_src = 1;
+ found_setting = 1;
+ }
+ }
+
+ if (!found_setting)
+ {
+ int regnum_for_replacing = REGNO (SET_DEST (PATTERN (insn_computes_expr)));
+ /* This shouldn't happen. */
+ if (regnum_for_replacing >= max_gcse_regno)
+ abort ();
+ this_reg = reg_set_table[regnum_for_replacing];
+ /* If the register the expression is computed into is set only once,
+ or only one set reaches this insn, use it. */
+ if (this_reg->next == NULL
+ || can_disregard_other_sets (&this_reg, insn, 0))
+ found_setting = 1;
+ }
+
+ if (found_setting)
+ {
+ pat = PATTERN (insn);
+ if (use_src)
+ to = SET_SRC (PATTERN (insn_computes_expr));
+ else
+ to = SET_DEST (PATTERN (insn_computes_expr));
+ changed = validate_change (insn, &SET_SRC (pat), to, 0);
+
+ /* We should be able to ignore the return code from validate_change but
+ to play it safe we check. */
+ if (changed)
+ {
+ gcse_subst_count++;
+ if (gcse_file != NULL)
+ {
+ fprintf (gcse_file, "GCSE: Replacing the source in insn %d with reg %d %s insn %d\n",
+ INSN_UID (insn), REGNO (to),
+ use_src ? "from" : "set in",
+ INSN_UID (insn_computes_expr));
+ }
+
+ }
+ }
+ /* The register that the expr is computed into is set more than once. */
+ else if (1 /*expensive_op(this_pattrn->op) && do_expensive_gcse)*/)
+ {
+ /* Insert an insn after insnx that copies the reg set in insnx
+ into a new pseudo register call this new register REGN.
+ From insnb until end of basic block or until REGB is set
+ replace all uses of REGB with REGN. */
+ rtx new_insn;
+
+ to = gen_reg_rtx (GET_MODE (SET_DEST (PATTERN (insn_computes_expr))));
+
+ /* Generate the new insn. */
+ /* ??? If the change fails, we return 0, even though we created
+ an insn. I think this is ok. */
+ new_insn
+ = emit_insn_after (gen_rtx_SET (VOIDmode, to,
+ SET_DEST (PATTERN (insn_computes_expr))),
+ insn_computes_expr);
+ /* Keep block number table up to date. */
+ set_block_num (new_insn, BLOCK_NUM (insn_computes_expr));
+ /* Keep register set table up to date. */
+ record_one_set (REGNO (to), new_insn);
+
+ gcse_create_count++;
+ if (gcse_file != NULL)
+ {
+ fprintf (gcse_file, "GCSE: Creating insn %d to copy value of reg %d, computed in insn %d,\n",
+ INSN_UID (NEXT_INSN (insn_computes_expr)),
+ REGNO (SET_SRC (PATTERN (NEXT_INSN (insn_computes_expr)))),
+ INSN_UID (insn_computes_expr));
+ fprintf (gcse_file, " into newly allocated reg %d\n", REGNO (to));
+ }
+
+ pat = PATTERN (insn);
+
+ /* Do register replacement for INSN. */
+ changed = validate_change (insn, &SET_SRC (pat),
+ SET_DEST (PATTERN (NEXT_INSN (insn_computes_expr))),
+ 0);
+
+ /* We should be able to ignore the return code from validate_change but
+ to play it safe we check. */
+ if (changed)
+ {
+ gcse_subst_count++;
+ if (gcse_file != NULL)
+ {
+ fprintf (gcse_file, "GCSE: Replacing the source in insn %d with reg %d set in insn %d\n",
+ INSN_UID (insn),
+ REGNO (SET_DEST (PATTERN (NEXT_INSN (insn_computes_expr)))),
+ INSN_UID (insn_computes_expr));
+ }
+
+ }
+ }
+
+ return changed;
+}
+
+/* Perform classic GCSE.
+ This is called by one_classic_gcse_pass after all the dataflow analysis
+ has been done.
+
+ The result is non-zero if a change was made. */
+
+static int
+classic_gcse ()
+{
+ int bb, changed;
+ rtx insn;
+
+ /* Note we start at block 1. */
+
+ changed = 0;
+ for (bb = 1; bb < n_basic_blocks; bb++)
+ {
+ /* Reset tables used to keep track of what's still valid [since the
+ start of the block]. */
+ reset_opr_set_tables ();
+
+ for (insn = basic_block_head[bb];
+ insn != NULL && insn != NEXT_INSN (basic_block_end[bb]);
+ insn = NEXT_INSN (insn))
+ {
+ /* Is insn of form (set (pseudo-reg) ...)? */
+
+ if (GET_CODE (insn) == INSN
+ && GET_CODE (PATTERN (insn)) == SET
+ && GET_CODE (SET_DEST (PATTERN (insn))) == REG
+ && REGNO (SET_DEST (PATTERN (insn))) >= FIRST_PSEUDO_REGISTER)
+ {
+ rtx pat = PATTERN (insn);
+ rtx src = SET_SRC (pat);
+ struct expr *expr;
+
+ if (want_to_gcse_p (src)
+ /* Is the expression recorded? */
+ && ((expr = lookup_expr (src)) != NULL)
+ /* Is the expression available [at the start of the
+ block]? */
+ && TEST_BIT (ae_in[bb], expr->bitmap_index)
+ /* Are the operands unchanged since the start of the
+ block? */
+ && oprs_not_set_p (src, insn))
+ changed |= handle_avail_expr (insn, expr);
+ }
+
+ /* Keep track of everything modified by this insn. */
+ /* ??? Need to be careful w.r.t. mods done to INSN. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ mark_oprs_set (insn);
+ }
+ }
+
+ return changed;
+}
+
+/* Top level routine to perform one classic GCSE pass.
+
+ Return non-zero if a change was made. */
+
+static int
+one_classic_gcse_pass (f, pass)
+ rtx f;
+ int pass;
+{
+ int changed = 0;
+
+ gcse_subst_count = 0;
+ gcse_create_count = 0;
+
+ alloc_expr_hash_table (max_cuid);
+ alloc_rd_mem (n_basic_blocks, max_cuid);
+ compute_expr_hash_table (f);
+ if (gcse_file)
+ dump_hash_table (gcse_file, "Expression", expr_hash_table,
+ expr_hash_table_size, n_exprs);
+ if (n_exprs > 0)
+ {
+ compute_kill_rd ();
+ compute_rd ();
+ alloc_avail_expr_mem (n_basic_blocks, n_exprs);
+ compute_ae_gen ();
+ compute_ae_kill ();
+ compute_available ();
+ changed = classic_gcse ();
+ free_avail_expr_mem ();
+ }
+ free_rd_mem ();
+ free_expr_hash_table ();
+
+ if (gcse_file)
+ {
+ fprintf (gcse_file, "\n");
+ fprintf (gcse_file, "GCSE of %s, pass %d: %d bytes needed, %d substs, %d insns created\n",
+ current_function_name, pass,
+ bytes_used, gcse_subst_count, gcse_create_count);
+ }
+
+ return changed;
+}
+
+/* Compute copy/constant propagation working variables. */
+
+/* Local properties of assignments. */
+
+static sbitmap *cprop_pavloc;
+static sbitmap *cprop_absaltered;
+
+/* Global properties of assignments (computed from the local properties). */
+
+static sbitmap *cprop_avin;
+static sbitmap *cprop_avout;
+
+/* Allocate vars used for copy/const propagation.
+ N_BLOCKS is the number of basic blocks.
+ N_SETS is the number of sets. */
+
+static void
+alloc_cprop_mem (n_blocks, n_sets)
+ int n_blocks, n_sets;
+{
+ cprop_pavloc = sbitmap_vector_alloc (n_blocks, n_sets);
+ cprop_absaltered = sbitmap_vector_alloc (n_blocks, n_sets);
+
+ cprop_avin = sbitmap_vector_alloc (n_blocks, n_sets);
+ cprop_avout = sbitmap_vector_alloc (n_blocks, n_sets);
+}
+
+/* Free vars used by copy/const propagation. */
+
+static void
+free_cprop_mem ()
+{
+ free (cprop_pavloc);
+ free (cprop_absaltered);
+ free (cprop_avin);
+ free (cprop_avout);
+}
+
+/* Dump copy/const propagation data. */
+
+void
+dump_cprop_data (file)
+ FILE *file;
+{
+ dump_sbitmap_vector (file, "CPROP partially locally available sets", "BB",
+ cprop_pavloc, n_basic_blocks);
+ dump_sbitmap_vector (file, "CPROP absolutely altered sets", "BB",
+ cprop_absaltered, n_basic_blocks);
+
+ dump_sbitmap_vector (file, "CPROP available incoming sets", "BB",
+ cprop_avin, n_basic_blocks);
+ dump_sbitmap_vector (file, "CPROP available outgoing sets", "BB",
+ cprop_avout, n_basic_blocks);
+}
+
+/* For each block, compute whether X is transparent.
+ X is either an expression or an assignment [though we don't care which,
+ for this context an assignment is treated as an expression].
+ For each block where an element of X is modified, set (SET_P == 1) or reset
+ (SET_P == 0) the INDX bit in BMAP. */
+
+static void
+compute_transp (x, indx, bmap, set_p)
+ rtx x;
+ int indx;
+ sbitmap *bmap;
+ int set_p;
+{
+ int bb,i;
+ enum rtx_code code;
+ char *fmt;
+
+ /* repeat is used to turn tail-recursion into iteration. */
+ repeat:
+
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case REG:
+ {
+ reg_set *r;
+ int regno = REGNO (x);
+
+ if (set_p)
+ {
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ if (TEST_BIT (reg_set_in_block[bb], regno))
+ SET_BIT (bmap[bb], indx);
+ }
+ else
+ {
+ for (r = reg_set_table[regno]; r != NULL; r = r->next)
+ {
+ bb = BLOCK_NUM (r->insn);
+ SET_BIT (bmap[bb], indx);
+ }
+ }
+ }
+ else
+ {
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ if (TEST_BIT (reg_set_in_block[bb], regno))
+ RESET_BIT (bmap[bb], indx);
+ }
+ else
+ {
+ for (r = reg_set_table[regno]; r != NULL; r = r->next)
+ {
+ bb = BLOCK_NUM (r->insn);
+ RESET_BIT (bmap[bb], indx);
+ }
+ }
+ }
+ return;
+ }
+
+ case MEM:
+ if (set_p)
+ {
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ if (mem_set_in_block[bb])
+ SET_BIT (bmap[bb], indx);
+ }
+ else
+ {
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ if (mem_set_in_block[bb])
+ RESET_BIT (bmap[bb], indx);
+ }
+ x = XEXP (x, 0);
+ goto repeat;
+
+ case PC:
+ case CC0: /*FIXME*/
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ return;
+
+ default:
+ break;
+ }
+
+ i = GET_RTX_LENGTH (code) - 1;
+ fmt = GET_RTX_FORMAT (code);
+ for (; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ rtx tem = XEXP (x, i);
+
+ /* If we are about to do the last recursive call
+ needed at this level, change it into iteration.
+ This function is called enough to be worth it. */
+ if (i == 0)
+ {
+ x = tem;
+ goto repeat;
+ }
+ compute_transp (tem, indx, bmap, set_p);
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ compute_transp (XVECEXP (x, i, j), indx, bmap, set_p);
+ }
+ }
+}
+
+static void
+compute_cprop_local_properties ()
+{
+ int i;
+
+ sbitmap_vector_zero (cprop_absaltered, n_basic_blocks);
+ sbitmap_vector_zero (cprop_pavloc, n_basic_blocks);
+
+ for (i = 0; i < set_hash_table_size; i++)
+ {
+ struct expr *expr;
+
+ for (expr = set_hash_table[i]; expr != NULL; expr = expr->next_same_hash)
+ {
+ struct occr *occr;
+ int indx = expr->bitmap_index;
+
+ /* The assignment is absolutely altered if any operand is modified
+ by this block [excluding the assignment itself].
+ We start by assuming all are transparent [none are killed], and
+ then setting the bits for those that are. */
+
+ compute_transp (expr->expr, indx, cprop_absaltered, 1);
+
+ /* The occurrences recorded in avail_occr are exactly those that
+ we want to set to non-zero in PAVLOC. */
+
+ for (occr = expr->avail_occr; occr != NULL; occr = occr->next)
+ {
+ int bb = BLOCK_NUM (occr->insn);
+ SET_BIT (cprop_pavloc[bb], indx);
+ }
+ }
+ }
+}
+
+static void
+compute_cprop_avinout ()
+{
+ int bb, changed, passes;
+
+ sbitmap_zero (cprop_avin[0]);
+ sbitmap_vector_ones (cprop_avout, n_basic_blocks);
+
+ passes = 0;
+ changed = 1;
+ while (changed)
+ {
+ changed = 0;
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ if (bb != 0)
+ sbitmap_intersect_of_predecessors (cprop_avin[bb], cprop_avout,
+ bb, s_preds);
+ changed |= sbitmap_union_of_diff (cprop_avout[bb],
+ cprop_pavloc[bb],
+ cprop_avin[bb],
+ cprop_absaltered[bb]);
+ }
+ passes++;
+ }
+
+ if (gcse_file)
+ fprintf (gcse_file, "cprop avail expr computation: %d passes\n", passes);
+}
+
+/* Top level routine to do the dataflow analysis needed by copy/const
+ propagation. */
+
+static void
+compute_cprop_data ()
+{
+ compute_cprop_local_properties ();
+ compute_cprop_avinout ();
+}
+
+/* Copy/constant propagation. */
+
+struct reg_use {
+ rtx reg_rtx;
+};
+
+/* Maximum number of register uses in an insn that we handle. */
+#define MAX_USES 8
+
+/* Table of uses found in an insn.
+ Allocated statically to avoid alloc/free complexity and overhead. */
+static struct reg_use reg_use_table[MAX_USES];
+
+/* Index into `reg_use_table' while building it. */
+static int reg_use_count;
+
+/* Set up a list of register numbers used in INSN.
+ The found uses are stored in `reg_use_table'.
+ `reg_use_count' is initialized to zero before entry, and
+ contains the number of uses in the table upon exit.
+
+ ??? If a register appears multiple times we will record it multiple
+ times. This doesn't hurt anything but it will slow things down. */
+
+static void
+find_used_regs (x)
+ rtx x;
+{
+ int i;
+ enum rtx_code code;
+ char *fmt;
+
+ /* repeat is used to turn tail-recursion into iteration. */
+ repeat:
+
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+ switch (code)
+ {
+ case REG:
+ if (reg_use_count == MAX_USES)
+ return;
+ reg_use_table[reg_use_count].reg_rtx = x;
+ reg_use_count++;
+ return;
+
+ case MEM:
+ x = XEXP (x, 0);
+ goto repeat;
+
+ case PC:
+ case CC0:
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ case CLOBBER:
+ case ADDR_VEC:
+ case ADDR_DIFF_VEC:
+ case ASM_INPUT: /*FIXME*/
+ return;
+
+ case SET:
+ if (GET_CODE (SET_DEST (x)) == MEM)
+ find_used_regs (SET_DEST (x));
+ x = SET_SRC (x);
+ goto repeat;
+
+ default:
+ break;
+ }
+
+ /* Recursively scan the operands of this expression. */
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ /* If we are about to do the last recursive call
+ needed at this level, change it into iteration.
+ This function is called enough to be worth it. */
+ if (i == 0)
+ {
+ x = XEXP (x, 0);
+ goto repeat;
+ }
+ find_used_regs (XEXP (x, i));
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ find_used_regs (XVECEXP (x, i, j));
+ }
+ }
+}
+
+/* Try to replace all non-SET_DEST occurrences of FROM in INSN with TO.
+ Returns non-zero is successful. */
+
+static int
+try_replace_reg (from, to, insn)
+ rtx from, to, insn;
+{
+ return validate_replace_src (from, to, insn);
+}
+
+/* Find a set of REGNO that is available on entry to INSN's block.
+ Returns NULL if not found. */
+
+static struct expr *
+find_avail_set (regno, insn)
+ int regno;
+ rtx insn;
+{
+ struct expr *set = lookup_set (regno, NULL_RTX);
+
+ while (set)
+ {
+ if (TEST_BIT (cprop_avin[BLOCK_NUM (insn)], set->bitmap_index))
+ break;
+ set = next_set (regno, set);
+ }
+
+ return set;
+}
+
+/* Perform constant and copy propagation on INSN.
+ The result is non-zero if a change was made. */
+
+static int
+cprop_insn (insn)
+ rtx insn;
+{
+ struct reg_use *reg_used;
+ int changed = 0;
+
+ /* ??? For now only propagate into SETs. */
+ if (GET_CODE (insn) != INSN
+ || GET_CODE (PATTERN (insn)) != SET)
+ return 0;
+
+ reg_use_count = 0;
+ find_used_regs (PATTERN (insn));
+
+ reg_used = &reg_use_table[0];
+ for ( ; reg_use_count > 0; reg_used++, reg_use_count--)
+ {
+ rtx pat, src;
+ struct expr *set;
+ int regno = REGNO (reg_used->reg_rtx);
+
+ /* Ignore registers created by GCSE.
+ We do this because ... */
+ if (regno >= max_gcse_regno)
+ continue;
+
+ /* If the register has already been set in this block, there's
+ nothing we can do. */
+ if (! oprs_not_set_p (reg_used->reg_rtx, insn))
+ continue;
+
+ /* Find an assignment that sets reg_used and is available
+ at the start of the block. */
+ set = find_avail_set (regno, insn);
+ if (! set)
+ continue;
+
+ pat = set->expr;
+ /* ??? We might be able to handle PARALLELs. Later. */
+ if (GET_CODE (pat) != SET)
+ abort ();
+ src = SET_SRC (pat);
+
+ if (GET_CODE (src) == CONST_INT)
+ {
+ if (try_replace_reg (reg_used->reg_rtx, src, insn))
+ {
+ changed = 1;
+ const_prop_count++;
+ if (gcse_file != NULL)
+ {
+ fprintf (gcse_file, "CONST-PROP: Replacing reg %d in insn %d with constant ",
+ regno, INSN_UID (insn));
+ fprintf (gcse_file, HOST_WIDE_INT_PRINT_DEC, INTVAL (src));
+ fprintf (gcse_file, "\n");
+ }
+
+ /* The original insn setting reg_used may or may not now be
+ deletable. We leave the deletion to flow. */
+ }
+ }
+ else if (GET_CODE (src) == REG
+ && REGNO (src) >= FIRST_PSEUDO_REGISTER
+ && REGNO (src) != regno)
+ {
+ /* We know the set is available.
+ Now check that SET_SRC is ANTLOC (i.e. none of the source operands
+ have changed since the start of the block). */
+ if (oprs_not_set_p (src, insn))
+ {
+ if (try_replace_reg (reg_used->reg_rtx, src, insn))
+ {
+ changed = 1;
+ copy_prop_count++;
+ if (gcse_file != NULL)
+ {
+ fprintf (gcse_file, "COPY-PROP: Replacing reg %d in insn %d with reg %d\n",
+ regno, INSN_UID (insn), REGNO (src));
+ }
+
+ /* The original insn setting reg_used may or may not now be
+ deletable. We leave the deletion to flow. */
+ /* FIXME: If it turns out that the insn isn't deletable,
+ then we may have unnecessarily extended register lifetimes
+ and made things worse. */
+ }
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* Forward propagate copies.
+ This includes copies and constants.
+ Return non-zero if a change was made. */
+
+static int
+cprop ()
+{
+ int bb, changed;
+ rtx insn;
+
+ /* Note we start at block 1. */
+
+ changed = 0;
+ for (bb = 1; bb < n_basic_blocks; bb++)
+ {
+ /* Reset tables used to keep track of what's still valid [since the
+ start of the block]. */
+ reset_opr_set_tables ();
+
+ for (insn = basic_block_head[bb];
+ insn != NULL && insn != NEXT_INSN (basic_block_end[bb]);
+ insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ changed |= cprop_insn (insn);
+
+ /* Keep track of everything modified by this insn. */
+ /* ??? Need to be careful w.r.t. mods done to INSN. */
+ mark_oprs_set (insn);
+ }
+ }
+ }
+
+ if (gcse_file != NULL)
+ fprintf (gcse_file, "\n");
+
+ return changed;
+}
+
+/* Perform one copy/constant propagation pass.
+ F is the first insn in the function.
+ PASS is the pass count. */
+
+static int
+one_cprop_pass (f, pass)
+ rtx f;
+ int pass;
+{
+ int changed = 0;
+
+ const_prop_count = 0;
+ copy_prop_count = 0;
+
+ alloc_set_hash_table (max_cuid);
+ compute_set_hash_table (f);
+ if (gcse_file)
+ dump_hash_table (gcse_file, "SET", set_hash_table, set_hash_table_size,
+ n_sets);
+ if (n_sets > 0)
+ {
+ alloc_cprop_mem (n_basic_blocks, n_sets);
+ compute_cprop_data ();
+ changed = cprop ();
+ free_cprop_mem ();
+ }
+ free_set_hash_table ();
+
+ if (gcse_file)
+ {
+ fprintf (gcse_file, "CPROP of %s, pass %d: %d bytes needed, %d const props, %d copy props\n",
+ current_function_name, pass,
+ bytes_used, const_prop_count, copy_prop_count);
+ fprintf (gcse_file, "\n");
+ }
+
+ return changed;
+}
+
+/* Compute PRE working variables. */
+
+/* Local properties of expressions. */
+/* Nonzero for expressions that are transparent in the block. */
+static sbitmap *pre_transp;
+/* Nonzero for expressions that are computed (available) in the block. */
+static sbitmap *pre_comp;
+/* Nonzero for expressions that are locally anticipatable in the block. */
+static sbitmap *pre_antloc;
+
+/* Global properties (computed from the expression local properties). */
+/* Nonzero for expressions that are available on block entry/exit. */
+static sbitmap *pre_avin;
+static sbitmap *pre_avout;
+/* Nonzero for expressions that are anticipatable on block entry/exit. */
+static sbitmap *pre_antin;
+static sbitmap *pre_antout;
+/* Nonzero for expressions that are partially available on block entry/exit. */
+static sbitmap *pre_pavin;
+static sbitmap *pre_pavout;
+/* Nonzero for expressions that are "placement possible" on block entry/exit. */
+static sbitmap *pre_ppin;
+static sbitmap *pre_ppout;
+
+/* Used while performing PRE to denote which insns are redundant. */
+static sbitmap pre_redundant;
+
+/* Allocate vars used for PRE analysis. */
+
+static void
+alloc_pre_mem (n_blocks, n_exprs)
+ int n_blocks, n_exprs;
+{
+ pre_transp = sbitmap_vector_alloc (n_blocks, n_exprs);
+ pre_comp = sbitmap_vector_alloc (n_blocks, n_exprs);
+ pre_antloc = sbitmap_vector_alloc (n_blocks, n_exprs);
+
+ pre_avin = sbitmap_vector_alloc (n_blocks, n_exprs);
+ pre_avout = sbitmap_vector_alloc (n_blocks, n_exprs);
+ pre_antin = sbitmap_vector_alloc (n_blocks, n_exprs);
+ pre_antout = sbitmap_vector_alloc (n_blocks, n_exprs);
+
+ pre_pavin = sbitmap_vector_alloc (n_blocks, n_exprs);
+ pre_pavout = sbitmap_vector_alloc (n_blocks, n_exprs);
+ pre_ppin = sbitmap_vector_alloc (n_blocks, n_exprs);
+ pre_ppout = sbitmap_vector_alloc (n_blocks, n_exprs);
+}
+
+/* Free vars used for PRE analysis. */
+
+static void
+free_pre_mem ()
+{
+ free (pre_transp);
+ free (pre_comp);
+ free (pre_antloc);
+
+ free (pre_avin);
+ free (pre_avout);
+ free (pre_antin);
+ free (pre_antout);
+
+ free (pre_pavin);
+ free (pre_pavout);
+ free (pre_ppin);
+ free (pre_ppout);
+}
+
+/* Dump PRE data. */
+
+void
+dump_pre_data (file)
+ FILE *file;
+{
+ dump_sbitmap_vector (file, "PRE locally transparent expressions", "BB",
+ pre_transp, n_basic_blocks);
+ dump_sbitmap_vector (file, "PRE locally available expressions", "BB",
+ pre_comp, n_basic_blocks);
+ dump_sbitmap_vector (file, "PRE locally anticipatable expressions", "BB",
+ pre_antloc, n_basic_blocks);
+
+ dump_sbitmap_vector (file, "PRE available incoming expressions", "BB",
+ pre_avin, n_basic_blocks);
+ dump_sbitmap_vector (file, "PRE available outgoing expressions", "BB",
+ pre_avout, n_basic_blocks);
+ dump_sbitmap_vector (file, "PRE anticipatable incoming expressions", "BB",
+ pre_antin, n_basic_blocks);
+ dump_sbitmap_vector (file, "PRE anticipatable outgoing expressions", "BB",
+ pre_antout, n_basic_blocks);
+
+ dump_sbitmap_vector (file, "PRE partially available incoming expressions", "BB",
+ pre_pavin, n_basic_blocks);
+ dump_sbitmap_vector (file, "PRE partially available outgoing expressions", "BB",
+ pre_pavout, n_basic_blocks);
+ dump_sbitmap_vector (file, "PRE placement possible on incoming", "BB",
+ pre_ppin, n_basic_blocks);
+ dump_sbitmap_vector (file, "PRE placement possible on outgoing", "BB",
+ pre_ppout, n_basic_blocks);
+}
+
+/* Compute the local properties of each recorded expression.
+ Local properties are those that are defined by the block, irrespective
+ of other blocks.
+
+ An expression is transparent in a block if its operands are not modified
+ in the block.
+
+ An expression is computed (locally available) in a block if it is computed
+ at least once and expression would contain the same value if the
+ computation was moved to the end of the block.
+
+ An expression is locally anticipatable in a block if it is computed at
+ least once and expression would contain the same value if the computation
+ was moved to the beginning of the block. */
+
+static void
+compute_pre_local_properties ()
+{
+ int i;
+
+ sbitmap_vector_ones (pre_transp, n_basic_blocks);
+ sbitmap_vector_zero (pre_comp, n_basic_blocks);
+ sbitmap_vector_zero (pre_antloc, n_basic_blocks);
+
+ for (i = 0; i < expr_hash_table_size; i++)
+ {
+ struct expr *expr;
+
+ for (expr = expr_hash_table[i]; expr != NULL; expr = expr->next_same_hash)
+ {
+ struct occr *occr;
+ int indx = expr->bitmap_index;
+
+ /* The expression is transparent in this block if it is not killed.
+ We start by assuming all are transparent [none are killed], and then
+ reset the bits for those that are. */
+
+ compute_transp (expr->expr, indx, pre_transp, 0);
+
+ /* The occurrences recorded in antic_occr are exactly those that
+ we want to set to non-zero in ANTLOC. */
+
+ for (occr = expr->antic_occr; occr != NULL; occr = occr->next)
+ {
+ int bb = BLOCK_NUM (occr->insn);
+ SET_BIT (pre_antloc[bb], indx);
+
+ /* While we're scanning the table, this is a good place to
+ initialize this. */
+ occr->deleted_p = 0;
+ }
+
+ /* The occurrences recorded in avail_occr are exactly those that
+ we want to set to non-zero in COMP. */
+
+ for (occr = expr->avail_occr; occr != NULL; occr = occr->next)
+ {
+ int bb = BLOCK_NUM (occr->insn);
+ SET_BIT (pre_comp[bb], indx);
+
+ /* While we're scanning the table, this is a good place to
+ initialize this. */
+ occr->copied_p = 0;
+ }
+
+ /* While we're scanning the table, this is a good place to
+ initialize this. */
+ expr->reaching_reg = 0;
+ }
+ }
+}
+
+/* Compute expression availability at entrance and exit of each block. */
+
+static void
+compute_pre_avinout ()
+{
+ int bb, changed, passes;
+
+ sbitmap_zero (pre_avin[0]);
+ sbitmap_vector_ones (pre_avout, n_basic_blocks);
+
+ passes = 0;
+ changed = 1;
+ while (changed)
+ {
+ changed = 0;
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ if (bb != 0)
+ sbitmap_intersect_of_predecessors (pre_avin[bb], pre_avout,
+ bb, s_preds);
+ changed |= sbitmap_a_or_b_and_c (pre_avout[bb], pre_comp[bb],
+ pre_transp[bb], pre_avin[bb]);
+ }
+ passes++;
+ }
+
+ if (gcse_file)
+ fprintf (gcse_file, "avail expr computation: %d passes\n", passes);
+}
+
+/* Compute expression anticipatability at entrance and exit of each block. */
+
+static void
+compute_pre_antinout ()
+{
+ int bb, changed, passes;
+
+ sbitmap_zero (pre_antout[n_basic_blocks - 1]);
+ sbitmap_vector_ones (pre_antin, n_basic_blocks);
+
+ passes = 0;
+ changed = 1;
+ while (changed)
+ {
+ changed = 0;
+ /* We scan the blocks in the reverse order to speed up
+ the convergence. */
+ for (bb = n_basic_blocks - 1; bb >= 0; bb--)
+ {
+ if (bb != n_basic_blocks - 1)
+ sbitmap_intersect_of_successors (pre_antout[bb], pre_antin,
+ bb, s_succs);
+ changed |= sbitmap_a_or_b_and_c (pre_antin[bb], pre_antloc[bb],
+ pre_transp[bb], pre_antout[bb]);
+ }
+ passes++;
+ }
+
+ if (gcse_file)
+ fprintf (gcse_file, "antic expr computation: %d passes\n", passes);
+}
+
+/* Compute expression partial availability at entrance and exit of
+ each block. */
+
+static void
+compute_pre_pavinout ()
+{
+ int bb, changed, passes;
+
+ sbitmap_zero (pre_pavin[0]);
+ sbitmap_vector_zero (pre_pavout, n_basic_blocks);
+
+ passes = 0;
+ changed = 1;
+ while (changed)
+ {
+ changed = 0;
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ if (bb != 0)
+ sbitmap_union_of_predecessors (pre_pavin[bb], pre_pavout,
+ bb, s_preds);
+ changed |= sbitmap_a_or_b_and_c (pre_pavout[bb], pre_comp[bb],
+ pre_transp[bb], pre_pavin[bb]);
+ }
+ passes++;
+ }
+
+ if (gcse_file)
+ fprintf (gcse_file, "partially avail expr computation: %d passes\n", passes);
+}
+
+/* Compute "placement possible" information on entrance and exit of
+ each block.
+
+ From Fred Chow's Thesis:
+ A computation `e' is PP at a point `p' if it is anticipated at `p' and
+ all the anticipated e's can be rendered redundant by zero or more
+ insertions at that point and some other points in the procedure, and
+ these insertions satisfy the conditions that the insertions are always
+ at points that `e' is anticipated and the first anticipated e's after the
+ insertions are rendered redundant. */
+
+static void
+compute_pre_ppinout ()
+{
+ int bb, i, changed, size, passes;
+
+ sbitmap_vector_ones (pre_ppin, n_basic_blocks);
+ /* ??? Inefficient as we set pre_ppin[0] twice, but simple. */
+ sbitmap_zero (pre_ppin[0]);
+
+ sbitmap_vector_ones (pre_ppout, n_basic_blocks);
+ /* ??? Inefficient as we set pre_ppout[n_basic_blocks-1] twice, but simple. */
+ sbitmap_zero (pre_ppout[n_basic_blocks - 1]);
+
+ size = pre_ppin[0]->size;
+ passes = 0;
+ changed = 1;
+ while (changed)
+ {
+ changed = 0;
+ for (bb = 1; bb < n_basic_blocks; bb++)
+ {
+ sbitmap_ptr antin = pre_antin[bb]->elms;
+ sbitmap_ptr pavin = pre_pavin[bb]->elms;
+ sbitmap_ptr antloc = pre_antloc[bb]->elms;
+ sbitmap_ptr transp = pre_transp[bb]->elms;
+ sbitmap_ptr ppout = pre_ppout[bb]->elms;
+ sbitmap_ptr ppin = pre_ppin[bb]->elms;
+
+ for (i = 0; i < size; i++)
+ {
+ int_list_ptr pred;
+ SBITMAP_ELT_TYPE tmp = *antin & *pavin & (*antloc | (*transp & *ppout));
+ SBITMAP_ELT_TYPE pred_val = -1L;
+
+ for (pred = s_preds[bb]; pred != NULL; pred = pred->next)
+ {
+ int pred_bb = INT_LIST_VAL (pred);
+ sbitmap_ptr ppout_j,avout_j;
+
+ if (pred_bb == ENTRY_BLOCK)
+ continue;
+
+ /* If this is a back edge, propagate info along the back
+ edge to allow for loop invariant code motion.
+
+ See FOLLOW_BACK_EDGES at the top of this file for a longer
+ discussion about loop invariant code motion in pre. */
+ if (! FOLLOW_BACK_EDGES
+ && (INSN_CUID (BLOCK_HEAD (bb))
+ < INSN_CUID (BLOCK_END (pred_bb))))
+ {
+ pred_val = 0;
+ }
+ else
+ {
+ ppout_j = pre_ppout[pred_bb]->elms + i;
+ avout_j = pre_avout[pred_bb]->elms + i;
+ pred_val &= *ppout_j | *avout_j;
+ }
+ }
+ tmp &= pred_val;
+ *ppin = tmp;
+ antin++; pavin++; antloc++; transp++; ppout++; ppin++;
+ }
+ }
+
+ for (bb = 0; bb < n_basic_blocks - 1; bb++)
+ {
+ sbitmap_ptr ppout = pre_ppout[bb]->elms;
+
+ for (i = 0; i < size; i++)
+ {
+ int_list_ptr succ;
+ SBITMAP_ELT_TYPE tmp = -1L;
+
+ for (succ = s_succs[bb]; succ != NULL; succ = succ->next)
+ {
+ int succ_bb = INT_LIST_VAL (succ);
+ sbitmap_ptr ppin;
+
+ if (succ_bb == EXIT_BLOCK)
+ continue;
+
+ ppin = pre_ppin[succ_bb]->elms + i;
+ tmp &= *ppin;
+ }
+ if (*ppout != tmp)
+ {
+ changed = 1;
+ *ppout++ = tmp;
+ }
+ else
+ ppout++;
+ }
+ }
+
+ passes++;
+ }
+
+ if (gcse_file)
+ fprintf (gcse_file, "placement possible computation: %d passes\n", passes);
+}
+
+/* Top level routine to do the dataflow analysis needed by PRE. */
+
+static void
+compute_pre_data ()
+{
+ compute_pre_local_properties ();
+ compute_pre_avinout ();
+ compute_pre_antinout ();
+ compute_pre_pavinout ();
+ compute_pre_ppinout ();
+ if (gcse_file)
+ fprintf (gcse_file, "\n");
+}
+
+/* PRE utilities */
+
+/* Return non-zero if occurrence OCCR of expression EXPR reaches block BB.
+
+ VISITED is a pointer to a working buffer for tracking which BB's have
+ been visited. It is NULL for the top-level call.
+
+ We treat reaching expressions that go through blocks containing the same
+ reaching expression as "not reaching". E.g. if EXPR is generated in blocks
+ 2 and 3, INSN is in block 4, and 2->3->4, we treat the expression in block
+ 2 as not reaching. The intent is to improve the probability of finding
+ only one reaching expression and to reduce register lifetimes by picking
+ the closest such expression. */
+
+static int
+pre_expr_reaches_here_p (occr, expr, bb, visited)
+ struct occr *occr;
+ struct expr *expr;
+ int bb;
+ char *visited;
+{
+ int_list_ptr pred;
+
+ if (visited == NULL)
+ {
+ visited = (char *) alloca (n_basic_blocks);
+ bzero (visited, n_basic_blocks);
+ }
+
+ for (pred = s_preds[bb]; pred != NULL; pred = pred->next)
+ {
+ int pred_bb = INT_LIST_VAL (pred);
+
+ if (pred_bb == ENTRY_BLOCK
+ /* Has predecessor has already been visited? */
+ || visited[pred_bb])
+ {
+ /* Nothing to do. */
+ }
+ /* Does this predecessor generate this expression? */
+ else if (TEST_BIT (pre_comp[pred_bb], expr->bitmap_index))
+ {
+ /* Is this the occurrence we're looking for?
+ Note that there's only one generating occurrence per block
+ so we just need to check the block number. */
+ if (BLOCK_NUM (occr->insn) == pred_bb)
+ return 1;
+ visited[pred_bb] = 1;
+ }
+ /* Ignore this predecessor if it kills the expression. */
+ else if (! TEST_BIT (pre_transp[pred_bb], expr->bitmap_index))
+ visited[pred_bb] = 1;
+ /* Neither gen nor kill. */
+ else
+ {
+ visited[pred_bb] = 1;
+ if (pre_expr_reaches_here_p (occr, expr, pred_bb, visited))
+ return 1;
+ }
+ }
+
+ /* All paths have been checked. */
+ return 0;
+}
+
+/* Add EXPR to the end of basic block BB. */
+
+static void
+pre_insert_insn (expr, bb)
+ struct expr *expr;
+ int bb;
+{
+ rtx insn = BLOCK_END (bb);
+ rtx new_insn;
+ rtx reg = expr->reaching_reg;
+ int regno = REGNO (reg);
+ rtx pat;
+
+ pat = gen_rtx_SET (VOIDmode, reg, copy_rtx (expr->expr));
+
+ /* If the last insn is a jump, insert EXPR in front [taking care to
+ handle cc0, etc. properly]. */
+
+ if (GET_CODE (insn) == JUMP_INSN)
+ {
+#ifdef HAVE_cc0
+ rtx note;
+#endif
+
+ /* If this is a jump table, then we can't insert stuff here. Since
+ we know the previous real insn must be the tablejump, we insert
+ the new instruction just before the tablejump. */
+ if (GET_CODE (PATTERN (insn)) == ADDR_VEC
+ || GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
+ insn = prev_real_insn (insn);
+
+#ifdef HAVE_cc0
+ /* FIXME: 'twould be nice to call prev_cc0_setter here but it aborts
+ if cc0 isn't set. */
+ note = find_reg_note (insn, REG_CC_SETTER, NULL_RTX);
+ if (note)
+ insn = XEXP (note, 0);
+ else
+ {
+ rtx maybe_cc0_setter = prev_nonnote_insn (insn);
+ if (maybe_cc0_setter
+ && GET_RTX_CLASS (GET_CODE (maybe_cc0_setter)) == 'i'
+ && sets_cc0_p (PATTERN (maybe_cc0_setter)))
+ insn = maybe_cc0_setter;
+ }
+#endif
+ /* FIXME: What if something in cc0/jump uses value set in new insn? */
+ new_insn = emit_insn_before (pat, insn);
+ add_label_notes (SET_SRC (pat), new_insn);
+ if (BLOCK_HEAD (bb) == insn)
+ BLOCK_HEAD (bb) = new_insn;
+ /* Keep block number table up to date. */
+ set_block_num (new_insn, bb);
+ /* Keep register set table up to date. */
+ record_one_set (regno, new_insn);
+ }
+ else
+ {
+ new_insn = emit_insn_after (pat, insn);
+ add_label_notes (SET_SRC (pat), new_insn);
+ BLOCK_END (bb) = new_insn;
+ /* Keep block number table up to date. */
+ set_block_num (new_insn, bb);
+ /* Keep register set table up to date. */
+ record_one_set (regno, new_insn);
+ }
+
+ gcse_create_count++;
+
+ if (gcse_file)
+ {
+ fprintf (gcse_file, "PRE: end of bb %d, insn %d, copying expression %d to reg %d\n",
+ bb, INSN_UID (new_insn), expr->bitmap_index, regno);
+ }
+}
+
+/* Insert partially redundant expressions at the ends of appropriate basic
+ blocks making them now redundant. */
+
+static void
+pre_insert (index_map)
+ struct expr **index_map;
+{
+ int bb, i, size;
+
+ /* Compute INSERT = PPOUT & (~AVOUT) & (~PPIN | ~TRANSP) for each
+ expression. Where INSERT == TRUE, add the expression at the end of
+ the basic block. */
+
+ size = pre_ppout[0]->size;
+ for (bb = 0; bb < n_basic_blocks; bb++)
+ {
+ int indx;
+ sbitmap_ptr ppout = pre_ppout[bb]->elms;
+ sbitmap_ptr avout = pre_avout[bb]->elms;
+ sbitmap_ptr ppin = pre_ppin[bb]->elms;
+ sbitmap_ptr transp = pre_transp[bb]->elms;
+
+ for (i = indx = 0;
+ i < size;
+ i++, indx += SBITMAP_ELT_BITS, ppout++, avout++, ppin++, transp++)
+ {
+ int j;
+ SBITMAP_ELT_TYPE insert = *ppout & (~*avout) & (~*ppin | ~*transp);
+
+ for (j = indx; insert != 0 && j < n_exprs; j++, insert >>= 1)
+ {
+ if ((insert & 1) != 0
+ /* If the basic block isn't reachable, PPOUT will be TRUE.
+ However, we don't want to insert a copy here because the
+ expression may not really be redundant. So only insert
+ an insn if the expression was deleted. */
+ && index_map[j]->reaching_reg != NULL)
+ pre_insert_insn (index_map[j], bb);
+ }
+ }
+ }
+}
+
+/* Copy the result of INSN to REG.
+ INDX is the expression number. */
+
+static void
+pre_insert_copy_insn (expr, insn)
+ struct expr *expr;
+ rtx insn;
+{
+ rtx reg = expr->reaching_reg;
+ int regno = REGNO (reg);
+ int indx = expr->bitmap_index;
+ rtx set = single_set (insn);
+ rtx new_insn;
+
+ if (!set)
+ abort ();
+ new_insn = emit_insn_after (gen_rtx_SET (VOIDmode, reg, SET_DEST (set)),
+ insn);
+ /* Keep block number table up to date. */
+ set_block_num (new_insn, BLOCK_NUM (insn));
+ /* Keep register set table up to date. */
+ record_one_set (regno, new_insn);
+
+ gcse_create_count++;
+
+ if (gcse_file)
+ {
+ fprintf (gcse_file, "PRE: bb %d, insn %d, copying expression %d in insn %d to reg %d\n",
+ BLOCK_NUM (insn), INSN_UID (new_insn), indx, INSN_UID (insn), regno);
+ }
+}
+
+/* Copy available expressions that reach the redundant expression
+ to `reaching_reg'. */
+
+static void
+pre_insert_copies ()
+{
+ int i;
+
+ /* For each available expression in the table, copy the result to
+ `reaching_reg' if the expression reaches a deleted one.
+
+ ??? The current algorithm is rather brute force.
+ Need to do some profiling. */
+
+ for (i = 0; i < expr_hash_table_size; i++)
+ {
+ struct expr *expr;
+
+ for (expr = expr_hash_table[i]; expr != NULL; expr = expr->next_same_hash)
+ {
+ struct occr *occr;
+
+ /* If the basic block isn't reachable, PPOUT will be TRUE.
+ However, we don't want to insert a copy here because the
+ expression may not really be redundant. So only insert
+ an insn if the expression was deleted.
+ This test also avoids further processing if the expression
+ wasn't deleted anywhere. */
+ if (expr->reaching_reg == NULL)
+ continue;
+
+ for (occr = expr->antic_occr; occr != NULL; occr = occr->next)
+ {
+ struct occr *avail;
+
+ if (! occr->deleted_p)
+ continue;
+
+ for (avail = expr->avail_occr; avail != NULL; avail = avail->next)
+ {
+ rtx insn = avail->insn;
+
+ /* No need to handle this one if handled already. */
+ if (avail->copied_p)
+ continue;
+ /* Don't handle this one if it's a redundant one. */
+ if (TEST_BIT (pre_redundant, INSN_CUID (insn)))
+ continue;
+ /* Or if the expression doesn't reach the deleted one. */
+ if (! pre_expr_reaches_here_p (avail, expr,
+ BLOCK_NUM (occr->insn),
+ NULL))
+ continue;
+
+ /* Copy the result of avail to reaching_reg. */
+ pre_insert_copy_insn (expr, insn);
+ avail->copied_p = 1;
+ }
+ }
+ }
+ }
+}
+
+/* Delete redundant computations.
+ These are ones that satisy ANTLOC & PPIN.
+ Deletion is done by changing the insn to copy the `reaching_reg' of
+ the expression into the result of the SET. It is left to later passes
+ (cprop, cse2, flow, combine, regmove) to propagate the copy or eliminate it.
+
+ Returns non-zero if a change is made. */
+
+static int
+pre_delete ()
+{
+ int i, changed;
+
+ changed = 0;
+ for (i = 0; i < expr_hash_table_size; i++)
+ {
+ struct expr *expr;
+
+ for (expr = expr_hash_table[i]; expr != NULL; expr = expr->next_same_hash)
+ {
+ struct occr *occr;
+ int indx = expr->bitmap_index;
+
+ /* We only need to search antic_occr since we require
+ ANTLOC != 0. */
+
+ for (occr = expr->antic_occr; occr != NULL; occr = occr->next)
+ {
+ rtx insn = occr->insn;
+ rtx set;
+ int bb = BLOCK_NUM (insn);
+ sbitmap ppin = pre_ppin[bb];
+
+ if (TEST_BIT (ppin, indx))
+ {
+ set = single_set (insn);
+ if (! set)
+ abort ();
+
+ /* Create a pseudo-reg to store the result of reaching
+ expressions into. Get the mode for the new pseudo
+ from the mode of the original destination pseudo. */
+ if (expr->reaching_reg == NULL)
+ expr->reaching_reg
+ = gen_reg_rtx (GET_MODE (SET_DEST (set)));
+
+ /* In theory this should never fail since we're creating
+ a reg->reg copy.
+
+ However, on the x86 some of the movXX patterns actually
+ contain clobbers of scratch regs. This may cause the
+ insn created by validate_change to not patch any pattern
+ and thus cause validate_change to fail. */
+ if (validate_change (insn, &SET_SRC (set),
+ expr->reaching_reg, 0))
+ {
+ occr->deleted_p = 1;
+ SET_BIT (pre_redundant, INSN_CUID (insn));
+ changed = 1;
+ gcse_subst_count++;
+ }
+
+ if (gcse_file)
+ {
+ fprintf (gcse_file, "PRE: redundant insn %d (expression %d) in bb %d, reaching reg is %d\n",
+ INSN_UID (insn), indx, bb, REGNO (expr->reaching_reg));
+ }
+ }
+ }
+ }
+ }
+
+ return changed;
+}
+
+/* Perform GCSE optimizations using PRE.
+ This is called by one_pre_gcse_pass after all the dataflow analysis
+ has been done.
+
+ This is based on the original Morel-Renvoise paper and Fred Chow's thesis.
+
+ The M-R paper uses "TRANSP" to describe an expression as being transparent
+ in a block where as Chow's thesis uses "ALTERED". We use TRANSP.
+
+ ??? A new pseudo reg is created to hold the reaching expression.
+ The nice thing about the classical approach is that it would try to
+ use an existing reg. If the register can't be adequately optimized
+ [i.e. we introduce reload problems], one could add a pass here to
+ propagate the new register through the block.
+
+ ??? We don't handle single sets in PARALLELs because we're [currently]
+ not able to copy the rest of the parallel when we insert copies to create
+ full redundancies from partial redundancies. However, there's no reason
+ why we can't handle PARALLELs in the cases where there are no partial
+ redundancies. */
+
+static int
+pre_gcse ()
+{
+ int i;
+ int changed;
+ struct expr **index_map;
+
+ /* Compute a mapping from expression number (`bitmap_index') to
+ hash table entry. */
+
+ index_map = (struct expr **) alloca (n_exprs * sizeof (struct expr *));
+ bzero ((char *) index_map, n_exprs * sizeof (struct expr *));
+ for (i = 0; i < expr_hash_table_size; i++)
+ {
+ struct expr *expr;
+
+ for (expr = expr_hash_table[i]; expr != NULL; expr = expr->next_same_hash)
+ index_map[expr->bitmap_index] = expr;
+ }
+
+ /* Reset bitmap used to track which insns are redundant. */
+ pre_redundant = sbitmap_alloc (max_cuid);
+ sbitmap_zero (pre_redundant);
+
+ /* Delete the redundant insns first so that
+ - we know what register to use for the new insns and for the other
+ ones with reaching expressions
+ - we know which insns are redundant when we go to create copies */
+ changed = pre_delete ();
+
+ /* Insert insns in places that make partially redundant expressions
+ fully redundant. */
+ pre_insert (index_map);
+
+ /* In other places with reaching expressions, copy the expression to the
+ specially allocated pseudo-reg that reaches the redundant expression. */
+ pre_insert_copies ();
+
+ free (pre_redundant);
+
+ return changed;
+}
+
+/* Top level routine to perform one PRE GCSE pass.
+
+ Return non-zero if a change was made. */
+
+static int
+one_pre_gcse_pass (f, pass)
+ rtx f;
+ int pass;
+{
+ int changed = 0;
+
+ gcse_subst_count = 0;
+ gcse_create_count = 0;
+
+ alloc_expr_hash_table (max_cuid);
+ compute_expr_hash_table (f);
+ if (gcse_file)
+ dump_hash_table (gcse_file, "Expression", expr_hash_table,
+ expr_hash_table_size, n_exprs);
+ if (n_exprs > 0)
+ {
+ alloc_pre_mem (n_basic_blocks, n_exprs);
+ compute_pre_data ();
+ changed |= pre_gcse ();
+ free_pre_mem ();
+ }
+ free_expr_hash_table ();
+
+ if (gcse_file)
+ {
+ fprintf (gcse_file, "\n");
+ fprintf (gcse_file, "PRE GCSE of %s, pass %d: %d bytes needed, %d substs, %d insns created\n",
+ current_function_name, pass,
+ bytes_used, gcse_subst_count, gcse_create_count);
+ }
+
+ return changed;
+}
+
+/* If X contains any LABEL_REF's, add REG_LABEL notes for them to INSN.
+ We have to add REG_LABEL notes, because the following loop optimization
+ pass requires them. */
+
+/* ??? This is very similar to the loop.c add_label_notes function. We
+ could probably share code here. */
+
+/* ??? If there was a jump optimization pass after gcse and before loop,
+ then we would not need to do this here, because jump would add the
+ necessary REG_LABEL notes. */
+
+static void
+add_label_notes (x, insn)
+ rtx x;
+ rtx insn;
+{
+ enum rtx_code code = GET_CODE (x);
+ int i, j;
+ char *fmt;
+
+ if (code == LABEL_REF && !LABEL_REF_NONLOCAL_P (x))
+ {
+ /* This code used to ignore labels that referred to dispatch tables to
+ avoid flow generating (slighly) worse code.
+
+ We no longer ignore such label references (see LABEL_REF handling in
+ mark_jump_label for additional information). */
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL, XEXP (x, 0),
+ REG_NOTES (insn));
+ return;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ add_label_notes (XEXP (x, i), insn);
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ add_label_notes (XVECEXP (x, i, j), insn);
+ }
+}
diff --git a/contrib/gcc/gen-protos.c b/contrib/gcc/gen-protos.c
index 44c900a..8b018cd 100644
--- a/contrib/gcc/gen-protos.c
+++ b/contrib/gcc/gen-protos.c
@@ -1,5 +1,5 @@
/* gen-protos.c - massages a list of prototypes, for use by fixproto.
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 94-96, 1998 Free Software Foundation, Inc.
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
@@ -15,18 +15,23 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#include <stdio.h>
-#include <ctype.h>
#include "hconfig.h"
+#include "system.h"
+#include "gansidecl.h"
#include "scan.h"
#include "cpplib.h"
#include "cpphash.h"
+int verbose = 0;
+char *progname;
+
#define HASH_SIZE 2503 /* a prime */
+int hash_tab[HASH_SIZE];
+int next_index;
int
hashf (name, len, hashsize)
- register U_CHAR *name;
+ register const U_CHAR *name;
register int len;
int hashsize;
{
@@ -38,40 +43,128 @@ hashf (name, len, hashsize)
return MAKE_POS (r) % hashsize;
}
-int hash_tab[HASH_SIZE];
-int verbose = 0;
+static void
+add_hash (fname)
+ char *fname;
+{
+ int i, i0;
-sstring linebuf;
+ /* NOTE: If you edit this, also edit lookup_std_proto in fix-header.c !! */
+ i = hashf (fname, strlen (fname), HASH_SIZE);
+ i0 = i;
+ if (hash_tab[i] != 0)
+ {
+ for (;;)
+ {
+ i = (i+1) % HASH_SIZE;
+ if (i == i0)
+ abort ();
+ if (hash_tab[i] == 0)
+ break;
+ }
+ }
+ hash_tab[i] = next_index;
-/* Avoid error if config defines abort as fancy_abort.
- It's not worth "really" implementing this because ordinary
- compiler users never run fix-header. */
+ next_index++;
+}
-void
-fancy_abort ()
+/* Given a function prototype, fill in the fields of FN.
+ The result is a boolean indicating if a function prototype was found.
+
+ The input string is modified (trailing NULs are inserted).
+ The fields of FN point to the input string. */
+
+static int
+parse_fn_proto (start, end, fn)
+ char *start, *end;
+ struct fn_decl *fn;
{
- abort ();
+ register char *ptr;
+ int param_nesting = 1;
+ char *param_start, *param_end, *decl_start, *name_start, *name_end;
+
+ ptr = end - 1;
+ while (*ptr == ' ' || *ptr == '\t') ptr--;
+ if (*ptr-- != ';')
+ {
+ fprintf (stderr, "Funny input line: %s\n", start);
+ return 0;
+ }
+ while (*ptr == ' ' || *ptr == '\t') ptr--;
+ if (*ptr != ')')
+ {
+ fprintf (stderr, "Funny input line: %s\n", start);
+ return 0;
+ }
+ param_end = ptr;
+ for (;;)
+ {
+ int c = *--ptr;
+ if (c == '(' && --param_nesting == 0)
+ break;
+ else if (c == ')')
+ param_nesting++;
+ }
+ param_start = ptr+1;
+
+ ptr--;
+ while (*ptr == ' ' || *ptr == '\t') ptr--;
+
+ if (!ISALNUM (*ptr))
+ {
+ if (verbose)
+ fprintf (stderr, "%s: Can't handle this complex prototype: %s\n",
+ progname, start);
+ return 0;
+ }
+ name_end = ptr+1;
+
+ while (ISALNUM (*ptr) || *ptr == '_') --ptr;
+ name_start = ptr+1;
+ while (*ptr == ' ' || *ptr == '\t') ptr--;
+ ptr[1] = 0;
+ *param_end = 0;
+ *name_end = 0;
+
+ decl_start = start;
+ if (strncmp (decl_start, "typedef ", 8) == 0)
+ return 0;
+ if (strncmp (decl_start, "extern ", 7) == 0)
+ decl_start += 7;
+
+ fn->fname = name_start;
+ fn->rtype = decl_start;
+ fn->params = param_start;
+ return 1;
}
int
main (argc, argv)
int argc;
- char** argv;
+ char **argv;
{
FILE *inf = stdin;
FILE *outf = stdout;
- int next_index = 0;
- int i, i0;
+ int i;
+ sstring linebuf;
+ struct fn_decl fn_decl;
+
+ i = strlen (argv[0]);
+ while (i > 0 && argv[0][i-1] != '/') --i;
+ progname = &argv[0][i];
+
+ INIT_SSTRING (&linebuf);
fprintf (outf, "struct fn_decl std_protos[] = {\n");
+ /* A hash table entry of 0 means "unused" so reserve it. */
+ fprintf (outf, " {\"\", \"\", \"\"},\n");
+ next_index = 1;
+
for (;;)
{
int c = skip_spaces (inf, ' ');
- int param_nesting = 1;
- char *param_start, *param_end, *decl_start,
- *name_start, *name_end;
- register char *ptr;
+
if (c == EOF)
break;
linebuf.ptr = linebuf.base;
@@ -82,83 +175,18 @@ main (argc, argv)
if (linebuf.base[0] == '\0') /* skip empty line */
continue;
- ptr = linebuf.ptr - 1;
- while (*ptr == ' ' || *ptr == '\t') ptr--;
- if (*ptr-- != ';')
- {
- fprintf (stderr, "Funny input line: %s\n", linebuf.base);
- continue;
- }
- while (*ptr == ' ' || *ptr == '\t') ptr--;
- if (*ptr != ')')
- {
- fprintf (stderr, "Funny input line: %s\n", linebuf.base);
- continue;
- }
- param_end = ptr;
- for (;;)
- {
- int c = *--ptr;
- if (c == '(' && --param_nesting == 0)
- break;
- else if (c == ')')
- param_nesting++;
- }
- param_start = ptr+1;
-
- ptr--;
- while (*ptr == ' ' || *ptr == '\t') ptr--;
-
- if (!isalnum (*ptr))
- {
- if (verbose)
- fprintf (stderr, "%s: Can't handle this complex prototype: %s\n",
- argv[0], linebuf.base);
- continue;
- }
- name_end = ptr+1;
-
- while (isalnum (*ptr) || *ptr == '_') --ptr;
- name_start = ptr+1;
- while (*ptr == ' ' || *ptr == '\t') ptr--;
- ptr[1] = 0;
- *name_end = 0;
- *param_end = 0;
- *name_end = 0;
-
- decl_start = linebuf.base;
- if (strncmp (decl_start, "typedef ", 8) == 0)
+ if (! parse_fn_proto (linebuf.base, linebuf.ptr, &fn_decl))
continue;
- if (strncmp (decl_start, "extern ", 7) == 0)
- decl_start += 7;
-
-
- /* NOTE: If you edit this,
- also edit lookup_std_proto in fix-header.c !! */
- i = hashf (name_start, name_end - name_start, HASH_SIZE);
- i0 = i;
- if (hash_tab[i] != 0)
- {
- for (;;)
- {
- i = (i+1) % HASH_SIZE;
- if (i == i0)
- abort ();
- if (hash_tab[i] == 0)
- break;
- }
- }
- hash_tab[i] = next_index;
- fprintf (outf, " {\"%s\", \"%s\", \"%s\" },\n",
- name_start, decl_start, param_start);
+ add_hash (fn_decl.fname);
- next_index++;
+ fprintf (outf, " {\"%s\", \"%s\", \"%s\"},\n",
+ fn_decl.fname, fn_decl.rtype, fn_decl.params);
if (c == EOF)
break;
}
- fprintf (outf, "{0, 0, 0}\n};\n");
+ fprintf (outf, " {0, 0, 0}\n};\n");
fprintf (outf, "#define HASH_SIZE %d\n", HASH_SIZE);
@@ -170,6 +198,16 @@ main (argc, argv)
return 0;
}
+/* Avoid error if config defines abort as fancy_abort.
+ It's not worth "really" implementing this because ordinary
+ compiler users never run fix-header. */
+
+void
+fancy_abort ()
+{
+ abort ();
+}
+
void
fatal (s)
char *s;
diff --git a/contrib/gcc/genattr.c b/contrib/gcc/genattr.c
index f87ce06..c50e0fd4 100644
--- a/contrib/gcc/genattr.c
+++ b/contrib/gcc/genattr.c
@@ -1,5 +1,5 @@
/* Generate attribute information (insn-attr.h) from machine description.
- Copyright (C) 1991, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1994, 1996, 1998 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GNU CC.
@@ -20,8 +20,13 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
@@ -31,13 +36,13 @@ struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free PROTO((void *));
-extern rtx read_rtx PROTO((FILE *));
-
char *xmalloc PROTO((unsigned));
-static void fatal ();
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
void fancy_abort PROTO((void));
+/* Define this so we can link with print-rtl.o to get debug_rtx function. */
+char **insn_name_ptr = 0;
+
/* A range of values. */
struct range
@@ -60,6 +65,13 @@ struct function_unit
struct range issue_delay; /* Range of issue delay values. */
};
+static void extend_range PROTO((struct range *, int, int));
+static void init_range PROTO((struct range *));
+static void write_upcase PROTO((char *));
+static void gen_attr PROTO((rtx));
+static void write_units PROTO((int, struct range *, struct range *,
+ struct range *, struct range *,
+ struct range *));
static void
extend_range (range, min, max)
struct range *range;
@@ -214,11 +226,22 @@ xrealloc (ptr, size)
}
static void
-fatal (s, a1, a2)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genattr: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
@@ -275,14 +298,6 @@ from the machine description file `md'. */\n\n");
/* For compatibility, define the attribute `alternative', which is just
a reference to the variable `which_alternative'. */
- printf("#ifndef PROTO\n");
- printf("#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)\n");
- printf("#define PROTO(ARGS) ARGS\n");
- printf("#else\n");
- printf("#define PROTO(ARGS) ()\n");
- printf("#endif\n");
- printf("#endif\n");
-
printf ("#define HAVE_ATTR_alternative\n");
printf ("#define get_attr_alternative(insn) which_alternative\n");
diff --git a/contrib/gcc/genattrtab.c b/contrib/gcc/genattrtab.c
index c764871..686bf5c 100644
--- a/contrib/gcc/genattrtab.c
+++ b/contrib/gcc/genattrtab.c
@@ -1,5 +1,5 @@
/* Generate code from machine description to compute values of attributes.
- Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1991, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
This file is part of GNU CC.
@@ -96,21 +96,18 @@ Boston, MA 02111-1307, USA. */
#include "hconfig.h"
-/* varargs must always be included after *config.h. */
+/* varargs must always be included after *config.h, but before stdio.h. */
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
+#include "system.h"
#include "rtl.h"
#include "insn-config.h" /* For REGISTER_CONSTRAINTS */
-#include <stdio.h>
-#ifndef VMS
-#ifndef USG
-#include <sys/time.h>
-#include <sys/resource.h>
-#endif
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
#endif
/* We must include obstack.h after <sys/time.h>, to avoid lossage with
@@ -128,11 +125,8 @@ struct obstack *temp_obstack = &obstack2;
/* Define this so we can link with print-rtl.o to get debug_rtx function. */
char **insn_name_ptr = 0;
-extern void free ();
-extern rtx read_rtx ();
-
-static void fatal ();
-void fancy_abort ();
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
+void fancy_abort PROTO((void));
/* enough space to reserve for printing out ints */
#define MAX_DIGITS (HOST_BITS_PER_INT * 3 / 10 + 3)
@@ -146,12 +140,12 @@ void fancy_abort ();
struct insn_def
{
- int insn_code; /* Instruction number. */
- int insn_index; /* Expression numer in file, for errors. */
- struct insn_def *next; /* Next insn in chain. */
- rtx def; /* The DEFINE_... */
+ int insn_code; /* Instruction number. */
+ int insn_index; /* Expression numer in file, for errors. */
+ struct insn_def *next; /* Next insn in chain. */
+ rtx def; /* The DEFINE_... */
int num_alternatives; /* Number of alternatives. */
- int vec_idx; /* Index of attribute vector in `def'. */
+ int vec_idx; /* Index of attribute vector in `def'. */
};
/* Once everything has been read in, we store in each attribute value a list
@@ -182,15 +176,17 @@ struct attr_value
struct attr_desc
{
- char *name; /* Name of attribute. */
- struct attr_desc *next; /* Next attribute. */
- int is_numeric; /* Values of this attribute are numeric. */
- int negative_ok; /* Allow negative numeric values. */
- int unsigned_p; /* Make the output function unsigned int. */
- int is_const; /* Attribute value constant for each run. */
- int is_special; /* Don't call `write_attr_set'. */
- struct attr_value *first_value; /* First value of this attribute. */
- struct attr_value *default_val; /* Default value for this attribute. */
+ char *name; /* Name of attribute. */
+ struct attr_desc *next; /* Next attribute. */
+ unsigned is_numeric : 1; /* Values of this attribute are numeric. */
+ unsigned negative_ok : 1; /* Allow negative numeric values. */
+ unsigned unsigned_p : 1; /* Make the output function unsigned int. */
+ unsigned is_const : 1; /* Attribute value constant for each run. */
+ unsigned is_special : 1; /* Don't call `write_attr_set'. */
+ unsigned func_units_p : 1; /* this is the function_units attribute */
+ unsigned blockage_p : 1; /* this is the blockage range function */
+ struct attr_value *first_value; /* First value of this attribute. */
+ struct attr_value *default_val; /* Default value for this attribute. */
};
#define NULL_ATTR (struct attr_desc *) NULL
@@ -208,7 +204,7 @@ struct range
struct delay_desc
{
rtx def; /* DEFINE_DELAY expression. */
- struct delay_desc *next; /* Next DEFINE_DELAY. */
+ struct delay_desc *next; /* Next DEFINE_DELAY. */
int num; /* Number of DEFINE_DELAY, starting at 1. */
};
@@ -236,7 +232,7 @@ struct function_unit
int multiplicity; /* Number of units of this type. */
int simultaneity; /* Maximum number of simultaneous insns
on this function unit or 0 if unlimited. */
- rtx condexp; /* Expression TRUE for insn needing unit. */
+ rtx condexp; /* Expression TRUE for insn needing unit. */
int num_opclasses; /* Number of different operation types. */
struct function_unit_op *ops; /* Pointer to first operation type. */
int needs_conflict_function; /* Nonzero if a conflict function required. */
@@ -299,7 +295,7 @@ struct dimension
int num_values; /* Length of the values list. */
};
-/* Other variables. */
+/* Other variables. */
static int insn_code_number;
static int insn_index_number;
@@ -310,12 +306,12 @@ static int address_used;
static int length_used;
static int num_delays;
static int have_annul_true, have_annul_false;
-static int num_units;
+static int num_units, num_unit_opclasses;
static int num_insn_ents;
/* Used as operand to `operate_exp': */
-enum operator {PLUS_OP, MINUS_OP, POS_MINUS_OP, EQ_OP, OR_OP, MAX_OP, MIN_OP, RANGE_OP};
+enum operator {PLUS_OP, MINUS_OP, POS_MINUS_OP, EQ_OP, OR_OP, ORX_OP, MAX_OP, MIN_OP, RANGE_OP};
/* Stores, for each insn code, the number of constraint alternatives. */
@@ -340,6 +336,16 @@ static rtx true_rtx, false_rtx;
static char *alternative_name;
+/* Indicate that REG_DEAD notes are valid if dead_or_set_p is ever
+ called. */
+
+int reload_completed = 0;
+
+/* Some machines test `optimize' in macros called from rtlanal.c, so we need
+ to define it here. */
+
+int optimize = 0;
+
/* Simplify an expression. Only call the routine if there is something to
simplify. */
#define SIMPLIFY_TEST_EXP(EXP,INSN_CODE,INSN_INDEX) \
@@ -358,23 +364,22 @@ static char *alternative_name;
/* These are referenced by rtlanal.c and hence need to be defined somewhere.
They won't actually be used. */
-rtx frame_pointer_rtx, hard_frame_pointer_rtx, stack_pointer_rtx;
-rtx arg_pointer_rtx;
+struct _global_rtl global_rtl;
+rtx pic_offset_table_rtx;
+static void attr_hash_add_rtx PROTO((int, rtx));
+static void attr_hash_add_string PROTO((int, char *));
static rtx attr_rtx PVPROTO((enum rtx_code, ...));
-#ifdef HAVE_VPRINTF
static char *attr_printf PVPROTO((int, char *, ...));
-#else
-static char *attr_printf ();
-#endif
-
static char *attr_string PROTO((char *, int));
static rtx check_attr_test PROTO((rtx, int));
static rtx check_attr_value PROTO((rtx, struct attr_desc *));
static rtx convert_set_attr_alternative PROTO((rtx, int, int, int));
static rtx convert_set_attr PROTO((rtx, int, int, int));
static void check_defs PROTO((void));
+#if 0
static rtx convert_const_symbol_ref PROTO((rtx, struct attr_desc *));
+#endif
static rtx make_canonical PROTO((struct attr_desc *, rtx));
static struct attr_value *get_attr_value PROTO((rtx, struct attr_desc *, int));
static rtx copy_rtx_unchanging PROTO((rtx));
@@ -392,8 +397,11 @@ static rtx identity_fn PROTO((rtx));
static rtx zero_fn PROTO((rtx));
static rtx one_fn PROTO((rtx));
static rtx max_fn PROTO((rtx));
+static void write_length_unit_log PROTO ((void));
static rtx simplify_cond PROTO((rtx, int, int));
+#if 0
static rtx simplify_by_alternatives PROTO((rtx, int, int));
+#endif
static rtx simplify_by_exploding PROTO((rtx));
static int find_and_mark_used_attributes PROTO((rtx, rtx *, int *));
static void unmark_used_attributes PROTO((rtx, struct dimension *, int));
@@ -423,6 +431,7 @@ static void gen_delay PROTO((rtx));
static void gen_unit PROTO((rtx));
static void write_test_expr PROTO((rtx, int));
static int max_attr_value PROTO((rtx));
+static int or_attr_value PROTO((rtx));
static void walk_attr_value PROTO((rtx));
static void write_attr_get PROTO((struct attr_desc *));
static rtx eliminate_known_true PROTO((rtx, rtx, int, int));
@@ -430,6 +439,7 @@ static void write_attr_set PROTO((struct attr_desc *, int, rtx, char *,
char *, rtx, int, int));
static void write_attr_case PROTO((struct attr_desc *, struct attr_value *,
int, char *, char *, int, rtx));
+static void write_unit_name PROTO((char *, int, char *));
static void write_attr_valueq PROTO((struct attr_desc *, char *));
static void write_attr_value PROTO((struct attr_desc *, rtx));
static void write_upcase PROTO((char *));
@@ -438,6 +448,8 @@ static void write_eligible_delay PROTO((char *));
static void write_function_unit_info PROTO((void));
static void write_complex_function PROTO((struct function_unit *, char *,
char *));
+static int write_expr_attr_cache PROTO((rtx, struct attr_desc *));
+static void write_toplevel_expr PROTO((rtx));
static int n_comma_elts PROTO((char *));
static char *next_comma_elt PROTO((char **));
static struct attr_desc *find_attr PROTO((char *, int));
@@ -481,7 +493,7 @@ struct attr_hash *attr_hash_table[RTL_HASH_SIZE];
/* Here is how primitive or already-shared RTL's hash
codes are made. */
-#define RTL_HASH(RTL) ((HOST_WIDE_INT) (RTL) & 0777777)
+#define RTL_HASH(RTL) ((long) (RTL) & 0777777)
/* Add an entry to the hash table for RTL with hash code HASHCODE. */
@@ -724,8 +736,6 @@ attr_rtx VPROTO((enum rtx_code code, ...))
rtx attr_printf (len, format, [arg1, ..., argn]) */
-#ifdef HAVE_VPRINTF
-
/*VARARGS2*/
static char *
attr_printf VPROTO((register int len, char *fmt, ...))
@@ -741,7 +751,7 @@ attr_printf VPROTO((register int len, char *fmt, ...))
#ifndef __STDC__
len = va_arg (p, int);
- fmt = va_arg (p, char*);
+ fmt = va_arg (p, char *);
#endif
/* Print the string into a temporary location. */
@@ -752,24 +762,6 @@ attr_printf VPROTO((register int len, char *fmt, ...))
return attr_string (str, strlen (str));
}
-#else /* not HAVE_VPRINTF */
-
-static char *
-attr_printf (len, fmt, arg1, arg2, arg3)
- int len;
- char *fmt;
- char *arg1, *arg2, *arg3; /* also int */
-{
- register char *str;
-
- /* Print the string into a temporary location. */
- str = (char *) alloca (len);
- sprintf (str, fmt, arg1, arg2, arg3);
-
- return attr_string (str, strlen (str));
-}
-#endif /* not HAVE_VPRINTF */
-
rtx
attr_eq (name, value)
char *name, *value;
@@ -862,6 +854,9 @@ attr_copy_rtx (orig)
case PC:
case CC0:
return orig;
+
+ default:
+ break;
}
copy = rtx_alloc (code);
@@ -962,12 +957,12 @@ check_attr_test (exp, is_const)
return exp;
}
else
- fatal ("Unknown attribute `%s' in EQ_ATTR", XEXP (exp, 0));
+ fatal ("Unknown attribute `%s' in EQ_ATTR", XSTR (exp, 0));
}
if (is_const && ! attr->is_const)
fatal ("Constant expression uses insn attribute `%s' in EQ_ATTR",
- XEXP (exp, 0));
+ XSTR (exp, 0));
/* Copy this just to make it permanent,
so expressions using it can be permanent too. */
@@ -984,7 +979,7 @@ check_attr_test (exp, is_const)
for (p = XSTR (exp, 1); *p; p++)
if (*p < '0' || *p > '9')
fatal ("Attribute `%s' takes only numeric values",
- XEXP (exp, 0));
+ XSTR (exp, 0));
}
else
{
@@ -995,7 +990,7 @@ check_attr_test (exp, is_const)
if (av == NULL)
fatal ("Unknown value `%s' for `%s' attribute",
- XEXP (exp, 1), XEXP (exp, 0));
+ XSTR (exp, 1), XSTR (exp, 0));
}
}
else
@@ -1033,14 +1028,15 @@ check_attr_test (exp, is_const)
XEXP (exp, 0) = check_attr_test (XEXP (exp, 0), is_const);
break;
+ case MATCH_INSN:
case MATCH_OPERAND:
if (is_const)
fatal ("RTL operator \"%s\" not valid in constant attribute test",
- GET_RTX_NAME (MATCH_OPERAND));
+ GET_RTX_NAME (GET_CODE (exp)));
/* These cases can't be simplified. */
RTX_UNCHANGING_P (exp) = 1;
break;
-
+
case LE: case LT: case GT: case GE:
case LEU: case LTU: case GTU: case GEU:
case NE: case EQ:
@@ -1132,6 +1128,16 @@ check_attr_value (exp, attr)
XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
break;
+ case IOR:
+ case AND:
+ XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
+ XEXP (exp, 1) = check_attr_value (XEXP (exp, 1), attr);
+ break;
+
+ case FFS:
+ XEXP (exp, 0) = check_attr_value (XEXP (exp, 0), attr);
+ break;
+
case COND:
if (XVECLEN (exp, 0) % 2 != 0)
fatal ("First operand of COND must have even length");
@@ -1152,7 +1158,7 @@ check_attr_value (exp, attr)
/* A constant SYMBOL_REF is valid as a constant attribute test and
is expanded later by make_canonical into a COND. */
return attr_rtx (SYMBOL_REF, XSTR (exp, 0));
- /* Otherwise, fall through... */
+ /* Otherwise, fall through... */
default:
fatal ("Invalid operation `%s' for attribute value",
@@ -1239,7 +1245,7 @@ convert_set_attr (exp, num_alt, insn_code, insn_index)
/* Scan all definitions, checking for validity. Also, convert any SET_ATTR
and SET_ATTR_ALTERNATIVE expressions to the corresponding SET
- expressions. */
+ expressions. */
static void
check_defs ()
@@ -1291,6 +1297,7 @@ check_defs ()
}
}
+#if 0
/* Given a constant SYMBOL_REF expression, convert to a COND that
explicitly tests each enumerated value. */
@@ -1341,6 +1348,7 @@ convert_const_symbol_ref (exp, attr)
return condexp;
}
+#endif
/* Given a valid expression for an attribute value, remove any IF_THEN_ELSE
expressions by converting them into a COND. This removes cases from this
@@ -1378,13 +1386,21 @@ make_canonical (attr, exp)
This makes the COND something that won't be considered an arbitrary
expression by walk_attr_value. */
RTX_UNCHANGING_P (exp) = 1;
+#if 0
+ /* ??? Why do we do this? With attribute values { A B C D E }, this
+ tends to generate (!(x==A) && !(x==B) && !(x==C) && !(x==D)) rather
+ than (x==E). */
exp = convert_const_symbol_ref (exp, attr);
RTX_UNCHANGING_P (exp) = 1;
exp = check_attr_value (exp, attr);
/* Goto COND case since this is now a COND. Note that while the
- new expression is rescanned, all symbol_ref notes are mared as
+ new expression is rescanned, all symbol_ref notes are marked as
unchanging. */
goto cond;
+#else
+ exp = check_attr_value (exp, attr);
+ break;
+#endif
case IF_THEN_ELSE:
newexp = rtx_alloc (COND);
@@ -1398,12 +1414,11 @@ make_canonical (attr, exp)
/* Fall through to COND case since this is now a COND. */
case COND:
- cond:
{
int allsame = 1;
rtx defval;
- /* First, check for degenerate COND. */
+ /* First, check for degenerate COND. */
if (XVECLEN (exp, 0) == 0)
return make_canonical (attr, XEXP (exp, 1));
defval = XEXP (exp, 1) = make_canonical (attr, XEXP (exp, 1));
@@ -1418,8 +1433,11 @@ make_canonical (attr, exp)
}
if (allsame)
return defval;
- break;
}
+ break;
+
+ default:
+ break;
}
return exp;
@@ -1619,6 +1637,7 @@ operate_exp (op, left, right)
break;
case OR_OP:
+ case ORX_OP:
i = left_value | right_value;
break;
@@ -1648,6 +1667,10 @@ operate_exp (op, left, right)
abort ();
}
+ if (i == left_value)
+ return left;
+ if (i == right_value)
+ return right;
return make_numeric_value (i);
}
else if (GET_CODE (right) == IF_THEN_ELSE)
@@ -1700,6 +1723,13 @@ operate_exp (op, left, right)
fatal ("Badly formed attribute value");
}
+ /* A hack to prevent expand_units from completely blowing up: ORX_OP does
+ not associate through IF_THEN_ELSE. */
+ else if (op == ORX_OP && GET_CODE (right) == IF_THEN_ELSE)
+ {
+ return attr_rtx (IOR, left, right);
+ }
+
/* Otherwise, do recursion the other way. */
else if (GET_CODE (left) == IF_THEN_ELSE)
{
@@ -1842,19 +1872,49 @@ expand_units ()
newexp = rtx_alloc (IF_THEN_ELSE);
XEXP (newexp, 2) = make_numeric_value (0);
- /* Merge each function unit into the unit mask attributes. */
- for (unit = units; unit; unit = unit->next)
+ /* If we have just a few units, we may be all right expanding the whole
+ thing. But the expansion is 2**N in space on the number of opclasses,
+ so we can't do this for very long -- Alpha and MIPS in particular have
+ problems with this. So in that situation, we fall back on an alternate
+ implementation method. */
+#define NUM_UNITOP_CUTOFF 20
+
+ if (num_unit_opclasses < NUM_UNITOP_CUTOFF)
+ {
+ /* Merge each function unit into the unit mask attributes. */
+ for (unit = units; unit; unit = unit->next)
+ {
+ XEXP (newexp, 0) = unit->condexp;
+ XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
+ unitsmask = operate_exp (OR_OP, unitsmask, newexp);
+ }
+ }
+ else
{
- XEXP (newexp, 0) = unit->condexp;
- XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
- unitsmask = operate_exp (OR_OP, unitsmask, newexp);
+ /* Merge each function unit into the unit mask attributes. */
+ for (unit = units; unit; unit = unit->next)
+ {
+ XEXP (newexp, 0) = unit->condexp;
+ XEXP (newexp, 1) = make_numeric_value (1 << unit->num);
+ unitsmask = operate_exp (ORX_OP, unitsmask, attr_copy_rtx (newexp));
+ }
}
/* Simplify the unit mask expression, encode it, and make an attribute
for the function_units_used function. */
unitsmask = simplify_by_exploding (unitsmask);
- unitsmask = encode_units_mask (unitsmask);
- make_internal_attr ("*function_units_used", unitsmask, 2);
+
+ if (num_unit_opclasses < NUM_UNITOP_CUTOFF)
+ unitsmask = encode_units_mask (unitsmask);
+ else
+ {
+ /* We can no longer encode unitsmask at compile time, so emit code to
+ calculate it at runtime. Rather, put a marker for where we'd do
+ the code, and actually output it in write_attr_get(). */
+ unitsmask = attr_rtx (FFS, unitsmask);
+ }
+
+ make_internal_attr ("*function_units_used", unitsmask, 10);
/* Create an array of ops for each unit. Add an extra unit for the
result_ready_cost function that has the ops of all other units. */
@@ -2003,6 +2063,9 @@ expand_units ()
for (op = unit->ops; op; op = op->next)
{
+#ifdef HAIFA
+ rtx blockage = op->issue_exp;
+#else
rtx blockage = operate_exp (POS_MINUS_OP, readycost,
make_numeric_value (1));
@@ -2018,6 +2081,7 @@ expand_units ()
blockage);
blockage = operate_exp (MAX_OP, blockage, op->issue_exp);
+#endif
blockage = simplify_knowing (blockage, unit->condexp);
/* Add this op's contribution to MAX (BLOCKAGE (E,*)) and
@@ -2063,13 +2127,13 @@ expand_units ()
if (unit->needs_range_function)
{
/* Compute the blockage range function and make an attribute
- for writing it's value. */
+ for writing its value. */
newexp = operate_exp (RANGE_OP, min_blockage, max_blockage);
newexp = simplify_knowing (newexp, unit->condexp);
str = attr_printf (strlen (unit->name) + sizeof ("*_unit_blockage_range"),
"*%s_unit_blockage_range", unit->name);
- make_internal_attr (str, newexp, 4);
+ make_internal_attr (str, newexp, 20);
}
str = attr_printf (strlen (unit->name) + sizeof ("*_unit_ready_cost"),
@@ -2175,6 +2239,9 @@ encode_units_mask (x)
case CC0:
case EQ_ATTR:
return x;
+
+ default:
+ break;
}
/* Compare the elements. If any pair of corresponding elements
@@ -2330,7 +2397,7 @@ make_length_attrs ()
"*insn_current_length"};
static rtx (*no_address_fn[]) PROTO((rtx)) = {identity_fn, zero_fn, zero_fn};
static rtx (*address_fn[]) PROTO((rtx)) = {max_fn, one_fn, identity_fn};
- int i;
+ size_t i;
struct attr_desc *length_attr, *new_attr;
struct attr_value *av, *new_av;
struct insn_ent *ie, *new_ie;
@@ -2381,14 +2448,14 @@ identity_fn (exp)
static rtx
zero_fn (exp)
- rtx exp;
+ rtx exp ATTRIBUTE_UNUSED;
{
return make_numeric_value (0);
}
static rtx
one_fn (exp)
- rtx exp;
+ rtx exp ATTRIBUTE_UNUSED;
{
return make_numeric_value (1);
}
@@ -2399,6 +2466,26 @@ max_fn (exp)
{
return make_numeric_value (max_attr_value (exp));
}
+
+static void
+write_length_unit_log ()
+{
+ struct attr_desc *length_attr = find_attr ("length", 0);
+ struct attr_value *av;
+ struct insn_ent *ie;
+ unsigned int length_unit_log, length_or;
+
+ if (length_attr == 0)
+ return;
+ length_or = or_attr_value (length_attr->default_val->value);
+ for (av = length_attr->first_value; av; av = av->next)
+ for (ie = av->first_insn; ie; ie = ie->next)
+ length_or |= or_attr_value (av->value);
+ length_or = ~length_or;
+ for (length_unit_log = 0; length_or & 1; length_or >>= 1)
+ length_unit_log++;
+ printf ("int length_unit_log = %u;\n", length_unit_log);
+}
/* Take a COND expression and see if any of the conditions in it can be
simplified. If any are known true or known false for the particular insn
@@ -2418,16 +2505,15 @@ simplify_cond (exp, insn_code, insn_index)
then build a new expression if they don't match EXP. */
rtx defval = XEXP (exp, 1);
rtx new_defval = XEXP (exp, 1);
-
int len = XVECLEN (exp, 0);
- rtx *tests = (rtx *) alloca (len * sizeof (rtx));
+ rtunion *tests = (rtunion *) alloca (len * sizeof (rtunion));
int allsame = 1;
char *first_spacer;
/* This lets us free all storage allocated below, if appropriate. */
first_spacer = (char *) obstack_finish (rtl_obstack);
- bcopy ((char *) &XVECEXP (exp, 0, 0), (char *) tests, len * sizeof (rtx));
+ bcopy ((char *) XVEC (exp, 0)->elem, (char *) tests, len * sizeof (rtunion));
/* See if default value needs simplification. */
if (GET_CODE (defval) == COND)
@@ -2440,10 +2526,10 @@ simplify_cond (exp, insn_code, insn_index)
rtx newtest, newval;
/* Simplify this test. */
- newtest = SIMPLIFY_TEST_EXP (tests[i], insn_code, insn_index);
- tests[i] = newtest;
+ newtest = SIMPLIFY_TEST_EXP (tests[i].rtx, insn_code, insn_index);
+ tests[i].rtx = newtest;
- newval = tests[i + 1];
+ newval = tests[i + 1].rtx;
/* See if this value may need simplification. */
if (GET_CODE (newval) == COND)
newval = simplify_cond (newval, insn_code, insn_index);
@@ -2454,7 +2540,7 @@ simplify_cond (exp, insn_code, insn_index)
/* If test is true, make this value the default
and discard this + any following tests. */
len = i;
- defval = tests[i + 1];
+ defval = tests[i + 1].rtx;
new_defval = newval;
}
@@ -2462,33 +2548,33 @@ simplify_cond (exp, insn_code, insn_index)
{
/* If test is false, discard it and its value. */
for (j = i; j < len - 2; j++)
- tests[j] = tests[j + 2];
+ tests[j].rtx = tests[j + 2].rtx;
len -= 2;
}
- else if (i > 0 && attr_equal_p (newval, tests[i - 1]))
+ else if (i > 0 && attr_equal_p (newval, tests[i - 1].rtx))
{
/* If this value and the value for the prev test are the same,
merge the tests. */
- tests[i - 2]
- = insert_right_side (IOR, tests[i - 2], newtest,
+ tests[i - 2].rtx
+ = insert_right_side (IOR, tests[i - 2].rtx, newtest,
insn_code, insn_index);
/* Delete this test/value. */
for (j = i; j < len - 2; j++)
- tests[j] = tests[j + 2];
+ tests[j].rtx = tests[j + 2].rtx;
len -= 2;
}
else
- tests[i + 1] = newval;
+ tests[i + 1].rtx = newval;
}
/* If the last test in a COND has the same value
as the default value, that test isn't needed. */
- while (len > 0 && attr_equal_p (tests[len - 1], new_defval))
+ while (len > 0 && attr_equal_p (tests[len - 1].rtx, new_defval))
len -= 2;
/* See if we changed anything. */
@@ -2496,7 +2582,7 @@ simplify_cond (exp, insn_code, insn_index)
allsame = 0;
else
for (i = 0; i < len; i++)
- if (! attr_equal_p (tests[i], XVECEXP (exp, 0, i)))
+ if (! attr_equal_p (tests[i].rtx, XVECEXP (exp, 0, i)))
{
allsame = 0;
break;
@@ -2519,8 +2605,8 @@ simplify_cond (exp, insn_code, insn_index)
rtx newexp = rtx_alloc (COND);
XVEC (newexp, 0) = rtvec_alloc (len);
- bcopy ((char *) tests, (char *) &XVECEXP (newexp, 0, 0),
- len * sizeof (rtx));
+ bcopy ((char *) tests, (char *) XVEC (newexp, 0)->elem,
+ len * sizeof (rtunion));
XEXP (newexp, 1) = new_defval;
return newexp;
}
@@ -2716,6 +2802,26 @@ evaluate_eq_attr (exp, value, insn_code, insn_index)
else
newexp = false_rtx;
}
+ else if (GET_CODE (value) == SYMBOL_REF)
+ {
+ char *p, *string;
+
+ if (GET_CODE (exp) != EQ_ATTR)
+ abort();
+
+ string = (char *) alloca (2 + strlen (XSTR (exp, 0))
+ + strlen (XSTR (exp, 1)));
+ strcpy (string, XSTR (exp, 0));
+ strcat (string, "_");
+ strcat (string, XSTR (exp, 1));
+ for (p = string; *p ; p++)
+ if (*p >= 'a' && *p <= 'z')
+ *p -= 'a' - 'A';
+
+ newexp = attr_rtx (EQ, value,
+ attr_rtx (SYMBOL_REF,
+ attr_string(string, strlen(string))));
+ }
else if (GET_CODE (value) == COND)
{
/* We construct an IOR of all the cases for which the requested attribute
@@ -2728,7 +2834,7 @@ evaluate_eq_attr (exp, value, insn_code, insn_index)
For each possible COND value, call ourselves recursively.
The extra TRUE and FALSE expressions will be eliminated by another
- call to the simplification routine. */
+ call to the simplification routine. */
orexp = false_rtx;
andexp = true_rtx;
@@ -3089,7 +3195,7 @@ simplify_test_exp (exp, insn_code, insn_index)
fatal ("Invalid alternative specified for pattern number %d",
insn_index);
- /* If all alternatives are excluded, this is false. */
+ /* If all alternatives are excluded, this is false. */
i ^= insn_alternatives[insn_code];
if (i == 0)
return false_rtx;
@@ -3182,7 +3288,7 @@ simplify_test_exp (exp, insn_code, insn_index)
fatal ("Invalid alternative specified for pattern number %d",
insn_index);
- /* If all alternatives are included, this is true. */
+ /* If all alternatives are included, this is true. */
i ^= insn_alternatives[insn_code];
if (i == 0)
return true_rtx;
@@ -3269,6 +3375,10 @@ simplify_test_exp (exp, insn_code, insn_index)
for (ie = av->first_insn; ie; ie = ie->next)
if (ie->insn_code == insn_code)
return evaluate_eq_attr (exp, av->value, insn_code, insn_index);
+ break;
+
+ default:
+ break;
}
/* We have already simplified this expression. Simplifying it again
@@ -3436,7 +3546,7 @@ static rtx
simplify_by_exploding (exp)
rtx exp;
{
- rtx list = 0, link, condexp, defval;
+ rtx list = 0, link, condexp, defval = NULL_RTX;
struct dimension *space;
rtx *condtest, *condval;
int i, j, total, ndim = 0;
@@ -3600,6 +3710,7 @@ find_and_mark_used_attributes (exp, terms, nterms)
MEM_VOLATILE_P (exp) = 1;
}
case CONST_STRING:
+ case CONST_INT:
return 1;
case IF_THEN_ELSE:
@@ -3621,9 +3732,10 @@ find_and_mark_used_attributes (exp, terms, nterms)
if (! find_and_mark_used_attributes (XEXP (exp, 1), terms, nterms))
return 0;
return 1;
- }
- return 0;
+ default:
+ return 0;
+ }
}
/* Clear the MEM_VOLATILE_P flag in all EQ_ATTR expressions on LIST and
@@ -3804,6 +3916,7 @@ simplify_with_current_value_aux (exp)
else
return true_rtx;
case CONST_STRING:
+ case CONST_INT:
return exp;
case IF_THEN_ELSE:
@@ -3859,8 +3972,10 @@ simplify_with_current_value_aux (exp)
have been selected. */
}
return simplify_with_current_value_aux (XEXP (exp, 1));
+
+ default:
+ abort ();
}
- abort ();
}
/* Clear the MEM_IN_STRUCT_P flag in EXP and its subexpressions. */
@@ -3893,6 +4008,9 @@ clear_struct_flag (x)
case EQ_ATTR:
case ATTR_FLAG:
return;
+
+ default:
+ break;
}
/* Compare the elements. If any pair of corresponding elements
@@ -3917,7 +4035,7 @@ clear_struct_flag (x)
}
/* Return the number of RTX objects making up the expression X.
- But if we count more more than MAX objects, stop counting. */
+ But if we count more than MAX objects, stop counting. */
static int
count_sub_rtxs (x, max)
@@ -3945,6 +4063,9 @@ count_sub_rtxs (x, max)
case EQ_ATTR:
case ATTR_FLAG:
return 1;
+
+ default:
+ break;
}
/* Compare the elements. If any pair of corresponding elements
@@ -4019,7 +4140,7 @@ gen_attr (exp)
if (! strcmp (attr->name, "length") && ! attr->is_numeric)
fatal ("`length' attribute must take numeric values");
- /* Set up the default value. */
+ /* Set up the default value. */
XEXP (exp, 2) = check_attr_value (XEXP (exp, 2), attr);
attr->default_val = get_attr_value (XEXP (exp, 2), attr, -2);
}
@@ -4169,6 +4290,9 @@ gen_insn (exp)
id->vec_idx = 0;
got_define_asm_attributes = 1;
break;
+
+ default:
+ abort ();
}
}
@@ -4255,6 +4379,7 @@ gen_unit (def)
op->issue_delay = issue_delay;
op->next = unit->ops;
unit->ops = op;
+ num_unit_opclasses++;
/* Set our issue expression based on whether or not an optional conflict
vector was specified. */
@@ -4281,15 +4406,18 @@ gen_unit (def)
unit->condexp = insert_right_side (IOR, unit->condexp, op->condexp, -2, -2);
}
-/* Given a piece of RTX, print a C expression to test it's truth value.
+/* Given a piece of RTX, print a C expression to test its truth value.
We use AND and IOR both for logical and bit-wise operations, so
interpret them as logical unless they are inside a comparison expression.
- The second operand of this function will be non-zero in that case. */
+ The first bit of FLAGS will be non-zero in that case.
+
+ Set the second bit of FLAGS to make references to attribute values use
+ a cached local variable instead of calling a function. */
static void
-write_test_expr (exp, in_comparison)
+write_test_expr (exp, flags)
rtx exp;
- int in_comparison;
+ int flags;
{
int comparison_operator = 0;
RTX_CODE code;
@@ -4311,7 +4439,7 @@ write_test_expr (exp, in_comparison)
case PLUS: case MINUS: case MULT: case DIV: case MOD:
case AND: case IOR: case XOR:
case ASHIFT: case LSHIFTRT: case ASHIFTRT:
- write_test_expr (XEXP (exp, 0), in_comparison || comparison_operator);
+ write_test_expr (XEXP (exp, 0), flags | comparison_operator);
switch (code)
{
case EQ:
@@ -4360,13 +4488,13 @@ write_test_expr (exp, in_comparison)
printf (" %% ");
break;
case AND:
- if (in_comparison)
+ if (flags & 1)
printf (" & ");
else
printf (" && ");
break;
case IOR:
- if (in_comparison)
+ if (flags & 1)
printf (" | ");
else
printf (" || ");
@@ -4381,14 +4509,16 @@ write_test_expr (exp, in_comparison)
case ASHIFTRT:
printf (" >> ");
break;
+ default:
+ abort ();
}
- write_test_expr (XEXP (exp, 1), in_comparison || comparison_operator);
+ write_test_expr (XEXP (exp, 1), flags | comparison_operator);
break;
case NOT:
/* Special-case (not (eq_attrq "alternative" "x")) */
- if (! in_comparison && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
+ if (! (flags & 1) && GET_CODE (XEXP (exp, 0)) == EQ_ATTR
&& XSTR (XEXP (exp, 0), 0) == alternative_name)
{
printf ("which_alternative != %s", XSTR (XEXP (exp, 0), 1));
@@ -4402,7 +4532,7 @@ write_test_expr (exp, in_comparison)
switch (code)
{
case NOT:
- if (in_comparison)
+ if (flags & 1)
printf ("~ ");
else
printf ("! ");
@@ -4413,16 +4543,18 @@ write_test_expr (exp, in_comparison)
case NEG:
printf ("-");
break;
+ default:
+ abort ();
}
- write_test_expr (XEXP (exp, 0), in_comparison);
+ write_test_expr (XEXP (exp, 0), flags);
break;
/* Comparison test of an attribute with a value. Most of these will
have been removed by optimization. Handle "alternative"
specially and give error if EQ_ATTR present inside a comparison. */
case EQ_ATTR:
- if (in_comparison)
+ if (flags & 1)
fatal ("EQ_ATTR not valid inside comparison");
if (XSTR (exp, 0) == alternative_name)
@@ -4439,18 +4571,22 @@ write_test_expr (exp, in_comparison)
{
write_test_expr (evaluate_eq_attr (exp, attr->default_val->value,
-2, -2),
- in_comparison);
+ flags);
}
else
{
- printf ("get_attr_%s (insn) == ", attr->name);
- write_attr_valueq (attr, XSTR (exp, 1));
+ if (flags & 2)
+ printf ("attr_%s", attr->name);
+ else
+ printf ("get_attr_%s (insn)", attr->name);
+ printf (" == ");
+ write_attr_valueq (attr, XSTR (exp, 1));
}
break;
/* Comparison test of flags for define_delays. */
case ATTR_FLAG:
- if (in_comparison)
+ if (flags & 1)
fatal ("ATTR_FLAG not valid inside comparison");
printf ("(flags & ATTR_FLAG_%s) != 0", XSTR (exp, 0));
break;
@@ -4472,31 +4608,45 @@ write_test_expr (exp, in_comparison)
XSTR (exp, 1), XINT (exp, 0), GET_MODE_NAME (GET_MODE (exp)));
break;
- /* Constant integer. */
+ case MATCH_INSN:
+ printf ("%s (insn)", XSTR (exp, 0));
+ break;
+
+ /* Constant integer. */
case CONST_INT:
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- printf ("%d", XWINT (exp, 0));
-#else
- printf ("%ld", XWINT (exp, 0));
-#endif
+ printf (HOST_WIDE_INT_PRINT_DEC, XWINT (exp, 0));
break;
- /* A random C expression. */
+ /* A random C expression. */
case SYMBOL_REF:
printf ("%s", XSTR (exp, 0));
break;
/* The address of the branch target. */
case MATCH_DUP:
- printf ("insn_addresses[INSN_UID (operands[%d])]", XINT (exp, 0));
+ printf ("insn_addresses[INSN_UID (GET_CODE (operands[%d]) == LABEL_REF ? XEXP (operands[%d], 0) : operands[%d])]",
+ XINT (exp, 0), XINT (exp, 0), XINT (exp, 0));
break;
- /* The address of the current insn. It would be more consistent with
- other usage to make this the address of the NEXT insn, but this gets
- too confusing because of the ambiguity regarding the length of the
- current insn. */
case PC:
- printf ("insn_current_address");
+ /* The address of the current insn. We implement this actually as the
+ address of the current insn for backward branches, but the last
+ address of the next insn for forward branches, and both with
+ adjustments that account for the worst-case possible stretching of
+ intervening alignments between this insn and its destination. */
+ printf("insn_current_reference_address (insn)");
+ break;
+
+ case CONST_STRING:
+ printf ("%s", XSTR (exp, 0));
+ break;
+
+ case IF_THEN_ELSE:
+ write_test_expr (XEXP (exp, 0), flags & 2);
+ printf (" ? ");
+ write_test_expr (XEXP (exp, 1), flags | 1);
+ printf (" : ");
+ write_test_expr (XEXP (exp, 2), flags | 1);
break;
default:
@@ -4548,6 +4698,42 @@ max_attr_value (exp)
return current_max;
}
+
+/* Given an attribute value, return the result of ORing together all
+ CONST_STRING arguments encountered. It is assumed that they are
+ all numeric. */
+
+static int
+or_attr_value (exp)
+ rtx exp;
+{
+ int current_or = 0;
+ int i;
+
+ if (GET_CODE (exp) == CONST_STRING)
+ return atoi (XSTR (exp, 0));
+
+ else if (GET_CODE (exp) == COND)
+ {
+ for (i = 0; i < XVECLEN (exp, 0); i += 2)
+ {
+ current_or |= or_attr_value (XVECEXP (exp, 0, i + 1));
+ }
+
+ current_or |= or_attr_value (XEXP (exp, 1));
+ }
+
+ else if (GET_CODE (exp) == IF_THEN_ELSE)
+ {
+ current_or = or_attr_value (XEXP (exp, 1));
+ current_or |= or_attr_value (XEXP (exp, 2));
+ }
+
+ else
+ abort ();
+
+ return current_or;
+}
/* Scan an attribute value, possibly a conditional, and record what actions
will be required to do any conditional tests in it.
@@ -4603,6 +4789,9 @@ walk_attr_value (exp)
case ATTR_FLAG:
return;
+
+ default:
+ break;
}
for (i = 0, fmt = GET_RTX_FORMAT (code); i < GET_RTX_LENGTH (code); i++)
@@ -4630,7 +4819,7 @@ write_attr_get (attr)
struct attr_value *av, *common_av;
/* Find the most used attribute value. Handle that as the `default' of the
- switch we will generate. */
+ switch we will generate. */
common_av = find_most_used (attr);
/* Write out start of function, then all values with explicit `case' lines,
@@ -4662,17 +4851,40 @@ write_attr_get (attr)
printf ("}\n\n");
return;
}
+
printf (" rtx insn;\n");
printf ("{\n");
- printf (" switch (recog_memoized (insn))\n");
- printf (" {\n");
- for (av = attr->first_value; av; av = av->next)
- if (av != common_av)
- write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
+ if (GET_CODE (common_av->value) == FFS)
+ {
+ rtx p = XEXP (common_av->value, 0);
- write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
- printf (" }\n}\n\n");
+ /* No need to emit code to abort if the insn is unrecognized; the
+ other get_attr_foo functions will do that when we call them. */
+
+ write_toplevel_expr (p);
+
+ printf ("\n if (accum && accum == (accum & -accum))\n");
+ printf (" {\n");
+ printf (" int i;\n");
+ printf (" for (i = 0; accum >>= 1; ++i) continue;\n");
+ printf (" accum = i;\n");
+ printf (" }\n else\n");
+ printf (" accum = ~accum;\n");
+ printf (" return accum;\n}\n\n");
+ }
+ else
+ {
+ printf (" switch (recog_memoized (insn))\n");
+ printf (" {\n");
+
+ for (av = attr->first_value; av; av = av->next)
+ if (av != common_av)
+ write_attr_case (attr, av, 1, "return", ";", 4, true_rtx);
+
+ write_attr_case (attr, common_av, 0, "return", ";", 4, true_rtx);
+ printf (" }\n}\n\n");
+ }
}
/* Given an AND tree of known true terms (because we are inside an `if' with
@@ -4882,19 +5094,148 @@ write_attr_case (attr, av, write_case_lines, prefix, suffix, indent,
printf ("\n");
}
+/* Search for uses of non-const attributes and write code to cache them. */
+
+static int
+write_expr_attr_cache (p, attr)
+ rtx p;
+ struct attr_desc *attr;
+{
+ char *fmt;
+ int i, ie, j, je;
+
+ if (GET_CODE (p) == EQ_ATTR)
+ {
+ if (XSTR (p, 0) != attr->name)
+ return 0;
+
+ if (!attr->is_numeric)
+ printf (" register enum attr_%s ", attr->name);
+ else if (attr->unsigned_p)
+ printf (" register unsigned int ");
+ else
+ printf (" register int ");
+
+ printf ("attr_%s = get_attr_%s (insn);\n", attr->name, attr->name);
+ return 1;
+ }
+
+ fmt = GET_RTX_FORMAT (GET_CODE (p));
+ ie = GET_RTX_LENGTH (GET_CODE (p));
+ for (i = 0; i < ie; i++)
+ {
+ switch (*fmt++)
+ {
+ case 'e':
+ if (write_expr_attr_cache (XEXP (p, i), attr))
+ return 1;
+ break;
+
+ case 'E':
+ je = XVECLEN (p, i);
+ for (j = 0; j < je; ++j)
+ if (write_expr_attr_cache (XVECEXP (p, i, j), attr))
+ return 1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/* Evaluate an expression at top level. A front end to write_test_expr,
+ in which we cache attribute values and break up excessively large
+ expressions to cater to older compilers. */
+
+static void
+write_toplevel_expr (p)
+ rtx p;
+{
+ struct attr_desc *attr;
+ int i;
+
+ for (i = 0; i < MAX_ATTRS_INDEX; ++i)
+ for (attr = attrs[i]; attr ; attr = attr->next)
+ if (!attr->is_const)
+ write_expr_attr_cache (p, attr);
+
+ printf(" register unsigned long accum = 0;\n\n");
+
+ while (GET_CODE (p) == IOR)
+ {
+ rtx e;
+ if (GET_CODE (XEXP (p, 0)) == IOR)
+ e = XEXP (p, 1), p = XEXP (p, 0);
+ else
+ e = XEXP (p, 0), p = XEXP (p, 1);
+
+ printf (" accum |= ");
+ write_test_expr (e, 3);
+ printf (";\n");
+ }
+ printf (" accum |= ");
+ write_test_expr (p, 3);
+ printf (";\n");
+}
+
/* Utilities to write names in various forms. */
static void
+write_unit_name (prefix, num, suffix)
+ char *prefix;
+ int num;
+ char *suffix;
+{
+ struct function_unit *unit;
+
+ for (unit = units; unit; unit = unit->next)
+ if (unit->num == num)
+ {
+ printf ("%s%s%s", prefix, unit->name, suffix);
+ return;
+ }
+
+ printf ("%s<unknown>%s", prefix, suffix);
+}
+
+static void
write_attr_valueq (attr, s)
struct attr_desc *attr;
char *s;
{
if (attr->is_numeric)
{
- printf ("%s", s);
- /* Make the blockage range values easier to read. */
- if (strlen (s) > 1)
- printf (" /* 0x%x */", atoi (s));
+ int num = atoi (s);
+
+ printf ("%d", num);
+
+ /* Make the blockage range values and function units used values easier
+ to read. */
+ if (attr->func_units_p)
+ {
+ if (num == -1)
+ printf (" /* units: none */");
+ else if (num >= 0)
+ write_unit_name (" /* units: ", num, " */");
+ else
+ {
+ int i;
+ char *sep = " /* units: ";
+ for (i = 0, num = ~num; num; i++, num >>= 1)
+ if (num & 1)
+ {
+ write_unit_name (sep, i, (num == 1) ? " */" : "");
+ sep = ", ";
+ }
+ }
+ }
+
+ else if (attr->blockage_p)
+ printf (" /* min %d, max %d */", num >> (HOST_BITS_PER_INT / 2),
+ num & ((1 << (HOST_BITS_PER_INT / 2)) - 1));
+
+ else if (num > 9 || num < 0)
+ printf (" /* 0x%x */", num);
}
else
{
@@ -5221,6 +5562,10 @@ write_complex_function (unit, name, connection)
}
}
+ /* This default case should not be needed, but gcc's analysis is not
+ good enough to realize that the default case is not needed for the
+ second switch statement. */
+ printf (" default:\n abort ();\n");
printf (" }\n}\n\n");
}
@@ -5330,6 +5675,8 @@ make_internal_attr (name, value, special)
attr->is_special = (special & 1) != 0;
attr->negative_ok = (special & 2) != 0;
attr->unsigned_p = (special & 4) != 0;
+ attr->func_units_p = (special & 8) != 0;
+ attr->blockage_p = (special & 16) != 0;
attr->default_val = get_attr_value (value, attr, -2);
}
@@ -5457,6 +5804,9 @@ copy_rtx_unchanging (orig)
case SYMBOL_REF:
case CODE_LABEL:
return orig;
+
+ default:
+ break;
}
copy = rtx_alloc (code);
@@ -5470,11 +5820,22 @@ copy_rtx_unchanging (orig)
}
static void
-fatal (s, a1, a2)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genattrtab: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
@@ -5497,7 +5858,6 @@ write_const_num_delay_slots ()
struct attr_desc *attr = find_attr ("*num_delay_slots", 0);
struct attr_value *av;
struct insn_ent *ie;
- int i;
if (attr)
{
@@ -5522,7 +5882,7 @@ write_const_num_delay_slots ()
printf (" default:\n");
printf (" return 1;\n");
- printf (" }\n}\n");
+ printf (" }\n}\n\n");
}
}
@@ -5540,17 +5900,17 @@ main (argc, argv)
rtx tem;
int i;
-#ifdef RLIMIT_STACK
+#if defined (RLIMIT_STACK) && defined (HAVE_GETRLIMIT) && defined (HAVE_SETRLIMIT)
/* Get rid of any avoidable limit on stack size. */
{
struct rlimit rlim;
- /* Set the stack limit huge so that alloca does not fail. */
+ /* Set the stack limit huge so that alloca does not fail. */
getrlimit (RLIMIT_STACK, &rlim);
rlim.rlim_cur = rlim.rlim_max;
setrlimit (RLIMIT_STACK, &rlim);
}
-#endif /* RLIMIT_STACK defined */
+#endif
obstack_init (rtl_obstack);
obstack_init (hash_obstack);
@@ -5638,6 +5998,7 @@ from the machine description file `md'. */\n\n");
expand_units ();
printf ("#include \"config.h\"\n");
+ printf ("#include \"system.h\"\n");
printf ("#include \"rtl.h\"\n");
printf ("#include \"insn-config.h\"\n");
printf ("#include \"recog.h\"\n");
@@ -5675,7 +6036,7 @@ from the machine description file `md'. */\n\n");
/* Construct extra attributes for `length'. */
make_length_attrs ();
- /* Perform any possible optimizations to speed up compilation. */
+ /* Perform any possible optimizations to speed up compilation. */
optimize_attrs ();
/* Now write out all the `gen_attr_...' routines. Do these before the
@@ -5685,7 +6046,7 @@ from the machine description file `md'. */\n\n");
for (i = 0; i < MAX_ATTRS_INDEX; i++)
for (attr = attrs[i]; attr; attr = attr->next)
{
- if (! attr->is_special)
+ if (! attr->is_special && ! attr->is_const)
write_attr_get (attr);
}
@@ -5708,6 +6069,8 @@ from the machine description file `md'. */\n\n");
/* Write out constant delay slot info */
write_const_num_delay_slots ();
+ write_length_unit_log ();
+
fflush (stdout);
exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
/* NOTREACHED */
diff --git a/contrib/gcc/gencheck.c b/contrib/gcc/gencheck.c
new file mode 100644
index 0000000..f7548ce
--- /dev/null
+++ b/contrib/gcc/gencheck.c
@@ -0,0 +1,82 @@
+/* Generate check macros for tree codes.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "hconfig.h"
+#include "system.h"
+
+#define DEFTREECODE(SYM, NAME, TYPE, LEN) STRINGIFY(SYM),
+
+char *tree_codes[] = {
+#include "tree.def"
+(char*)0
+};
+
+void usage ()
+{
+ fprintf (stderr,"Usage: gencheck\n");
+}
+
+int main (argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+
+ switch (argc)
+ {
+ case 1:
+ break;
+
+ default:
+ usage ();
+ exit (1);
+ }
+
+ printf ("/* This file is generated using gencheck. Do not edit. */\n");
+ for (i = 0; tree_codes[i]; i++)
+ {
+ printf ("#define %s_CHECK(t)\tTREE_CHECK (t, %s)\n",
+ tree_codes[i], tree_codes[i]);
+ printf ("#define %s_CHECK1(t)\tTREE_CHECK1 (t, %s)\n",
+ tree_codes[i], tree_codes[i]);
+ }
+
+ return 0;
+}
+
+#if defined(USE_C_ALLOCA) && !defined(__GNUC__)
+/* FIXME: We only need an xmalloc definition because we are forced to
+ link with alloca.o on some platforms. This should go away if/when
+ we link against libiberty.a. (ghazi@caip.rutgers.edu 6/3/98) */
+char *
+xmalloc (nbytes)
+ int nbytes;
+{
+ char *tmp = (char *) malloc (nbytes);
+
+ if (!tmp)
+ {
+ fprintf (stderr, "can't allocate %d bytes (out of virtual memory)\n", nbytes);
+ exit (FATAL_EXIT_CODE);
+ }
+
+ return tmp;
+}
+#endif /* USE_C_ALLOCA && !__GNUC__ */
diff --git a/contrib/gcc/gencodes.c b/contrib/gcc/gencodes.c
index 8baf3b8..a3aa1fe 100644
--- a/contrib/gcc/gencodes.c
+++ b/contrib/gcc/gencodes.c
@@ -22,8 +22,13 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
@@ -33,15 +38,17 @@ struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern rtx read_rtx ();
+char *xmalloc PROTO((unsigned));
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
+void fancy_abort PROTO((void));
-char *xmalloc ();
-static void fatal ();
-void fancy_abort ();
+/* Define this so we can link with print-rtl.o to get debug_rtx function. */
+char **insn_name_ptr = 0;
static int insn_code_number;
+static void gen_insn PROTO((rtx));
+
static void
gen_insn (insn)
rtx insn;
@@ -77,11 +84,22 @@ xrealloc (ptr, size)
}
static void
-fatal (s, a1, a2)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "gencodes: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
diff --git a/contrib/gcc/genconfig.c b/contrib/gcc/genconfig.c
index 404534e..b01a24b 100644
--- a/contrib/gcc/genconfig.c
+++ b/contrib/gcc/genconfig.c
@@ -1,7 +1,6 @@
/* Generate from machine description:
-
- some #define configuration flags.
- Copyright (C) 1987, 1991 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1991, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -21,8 +20,13 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
@@ -32,8 +36,8 @@ struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern rtx read_rtx ();
+/* Define this so we can link with print-rtl.o to get debug_rtx function. */
+char **insn_name_ptr = 0;
/* flags to determine output of machine description dependent #define's. */
static int max_recog_operands; /* Largest operand number seen. */
@@ -50,9 +54,15 @@ static int max_insns_per_split = 1;
static int clobbers_seen_this_insn;
static int dup_operands_seen_this_insn;
-char *xmalloc ();
-static void fatal ();
-void fancy_abort ();
+char *xmalloc PROTO((unsigned));
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
+void fancy_abort PROTO((void));
+
+static void walk_insn_part PROTO((rtx, int, int));
+static void gen_insn PROTO((rtx));
+static void gen_expand PROTO((rtx));
+static void gen_split PROTO((rtx));
+static void gen_peephole PROTO((rtx));
/* RECOG_P will be non-zero if this pattern was seen in a context where it will
be used to recognize, rather than just generate an insn.
@@ -142,6 +152,9 @@ walk_insn_part (part, recog_p, non_pc_set_src)
case REG: case CONST_INT: case SYMBOL_REF:
case PC:
return;
+
+ default:
+ break;
}
format_ptr = GET_RTX_FORMAT (GET_CODE (part));
@@ -260,11 +273,22 @@ xrealloc (ptr, size)
}
static void
-fatal (s, a1, a2)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genconfig: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
diff --git a/contrib/gcc/genemit.c b/contrib/gcc/genemit.c
index ebed4f3..e4341b8 100644
--- a/contrib/gcc/genemit.c
+++ b/contrib/gcc/genemit.c
@@ -1,5 +1,5 @@
/* Generate code from machine description to emit insns as rtl.
- Copyright (C) 1987, 1988, 1991, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91, 94, 95, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,8 +19,13 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
@@ -30,12 +35,12 @@ struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern rtx read_rtx ();
+char *xmalloc PROTO((unsigned));
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
+void fancy_abort PROTO((void));
-char *xmalloc ();
-static void fatal ();
-void fancy_abort ();
+/* Define this so we can link with print-rtl.o to get debug_rtx function. */
+char **insn_name_ptr = 0;
static int max_opno;
static int max_dup_opno;
@@ -63,6 +68,17 @@ struct clobber_ent
struct clobber_ent *next;
};
+static void max_operand_1 PROTO((rtx));
+static int max_operand_vec PROTO((rtx, int));
+static void print_code PROTO((RTX_CODE));
+static void gen_exp PROTO((rtx));
+static void gen_insn PROTO((rtx));
+static void gen_expand PROTO((rtx));
+static void gen_split PROTO((rtx));
+static void output_add_clobbers PROTO((void));
+static void output_init_mov_optab PROTO((void));
+
+
static void
max_operand_1 (x)
rtx x;
@@ -161,8 +177,11 @@ gen_exp (x)
return;
case MATCH_OP_DUP:
- printf ("gen_rtx (GET_CODE (operand%d), GET_MODE (operand%d)",
- XINT (x, 0), XINT (x, 0));
+ printf ("gen_rtx (GET_CODE (operand%d), ", XINT (x, 0));
+ if (GET_MODE (x) == VOIDmode)
+ printf ("GET_MODE (operand%d)", XINT (x, 0));
+ else
+ printf ("%smode", GET_MODE_NAME (GET_MODE (x)));
for (i = 0; i < XVECLEN (x, 1); i++)
{
printf (",\n\t\t");
@@ -188,7 +207,7 @@ gen_exp (x)
return;
case MATCH_SCRATCH:
- printf ("gen_rtx (SCRATCH, %smode, 0)", GET_MODE_NAME (GET_MODE (x)));
+ printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x)));
return;
case ADDRESS:
@@ -212,24 +231,25 @@ gen_exp (x)
else if (INTVAL (x) == STORE_FLAG_VALUE)
printf ("const_true_rtx");
else
- printf (
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- "GEN_INT (%d)",
-#else
- "GEN_INT (%ld)",
-#endif
- INTVAL (x));
+ {
+ printf ("GEN_INT (");
+ printf (HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
+ printf (")");
+ }
return;
case CONST_DOUBLE:
/* These shouldn't be written in MD files. Instead, the appropriate
routines in varasm.c should be called. */
abort ();
+
+ default:
+ break;
}
- printf ("gen_rtx (");
+ printf ("gen_rtx_");
print_code (code);
- printf (", %smode", GET_MODE_NAME (GET_MODE (x)));
+ printf (" (%smode", GET_MODE_NAME (GET_MODE (x)));
fmt = GET_RTX_FORMAT (code);
len = GET_RTX_LENGTH (code);
@@ -272,7 +292,7 @@ gen_insn (insn)
/* See if the pattern for this insn ends with a group of CLOBBERs of (hard)
registers or MATCH_SCRATCHes. If so, store away the information for
- later. */
+ later. */
if (XVEC (insn, 1))
{
@@ -368,7 +388,7 @@ gen_insn (insn)
}
else
{
- printf (" return gen_rtx (PARALLEL, VOIDmode, gen_rtvec (%d", XVECLEN (insn, 1));
+ printf (" return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (%d", XVECLEN (insn, 1));
for (i = 0; i < XVECLEN (insn, 1); i++)
{
printf (",\n\t\t");
@@ -498,14 +518,13 @@ gen_expand (expand)
/* Call `gen_sequence' to make a SEQUENCE out of all the
insns emitted within this gen_... function. */
- printf (" _done:\n");
printf (" _val = gen_sequence ();\n");
- printf (" _fail:\n");
printf (" end_sequence ();\n");
printf (" return _val;\n}\n\n");
}
/* Like gen_expand, but generates a SEQUENCE. */
+
static void
gen_split (split)
rtx split;
@@ -587,9 +606,7 @@ gen_split (split)
/* Call `gen_sequence' to make a SEQUENCE out of all the
insns emitted within this gen_... function. */
- printf (" _done:\n");
printf (" _val = gen_sequence ();\n");
- printf (" _fail:\n");
printf (" end_sequence ();\n");
printf (" return _val;\n}\n\n");
}
@@ -608,7 +625,6 @@ output_add_clobbers ()
printf ("\n\nvoid\nadd_clobbers (pattern, insn_code_number)\n");
printf (" rtx pattern;\n int insn_code_number;\n");
printf ("{\n");
- printf (" int i;\n\n");
printf (" switch (insn_code_number)\n");
printf (" {\n");
@@ -642,7 +658,7 @@ output_init_mov_optab ()
#ifdef EXTRA_CC_NAMES
static char *cc_names[] = { EXTRA_CC_NAMES };
char *p;
- int i;
+ size_t i;
printf ("\nvoid\ninit_mov_optab ()\n{\n");
@@ -691,11 +707,22 @@ xrealloc (ptr, size)
}
static void
-fatal (s, a1, a2)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genemit: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
@@ -742,18 +769,21 @@ main (argc, argv)
from the machine description file `md'. */\n\n");
printf ("#include \"config.h\"\n");
+ printf ("#include \"system.h\"\n");
printf ("#include \"rtl.h\"\n");
printf ("#include \"expr.h\"\n");
printf ("#include \"real.h\"\n");
+ printf ("#include \"flags.h\"\n");
printf ("#include \"output.h\"\n");
printf ("#include \"insn-config.h\"\n\n");
printf ("#include \"insn-flags.h\"\n\n");
printf ("#include \"insn-codes.h\"\n\n");
+ printf ("#include \"reload.h\"\n");
printf ("extern char *insn_operand_constraint[][MAX_RECOG_OPERANDS];\n\n");
printf ("extern rtx recog_operand[];\n");
printf ("#define operands emit_operand\n\n");
- printf ("#define FAIL goto _fail\n\n");
- printf ("#define DONE goto _done\n\n");
+ printf ("#define FAIL do {end_sequence (); return _val;} while (0)\n");
+ printf ("#define DONE do {_val = gen_sequence (); end_sequence (); return _val;} while (0)\n");
/* Read the machine description. */
diff --git a/contrib/gcc/genextract.c b/contrib/gcc/genextract.c
index 3861bd5..c06a74c 100644
--- a/contrib/gcc/genextract.c
+++ b/contrib/gcc/genextract.c
@@ -1,5 +1,5 @@
/* Generate code from machine description to extract operands from insn as rtl.
- Copyright (C) 1987, 1991, 1992, 1993 Free Software Foundation, Inc.
+ Copyright (C) 1987, 91, 92, 93, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,8 +19,13 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
#include "insn-config.h"
@@ -31,9 +36,6 @@ struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern rtx read_rtx ();
-
/* Names for patterns. Need to allow linking with print-rtl. */
char **insn_name_ptr;
@@ -98,14 +100,15 @@ static int dupnums[MAX_DUP_OPERANDS];
static struct code_ptr *peepholes;
-static void walk_rtx ();
-static void print_path ();
-char *xmalloc ();
-char *xrealloc ();
-static void fatal ();
-static char *copystr ();
+static void gen_insn PROTO ((rtx));
+static void walk_rtx PROTO ((rtx, char *));
+static void print_path PROTO ((char *));
+char *xmalloc PROTO ((unsigned));
+char *xrealloc PROTO ((char *, unsigned));
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
+static char *copystr PROTO ((char *));
static void mybzero ();
-void fancy_abort ();
+void fancy_abort PROTO ((void));
static void
gen_insn (insn)
@@ -140,7 +143,7 @@ gen_insn (insn)
link = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
link->insn_code = insn_code_number;
- /* See if we find something that already had this extraction method. */
+ /* See if we find something that already had this extraction method. */
for (p = extractions; p; p = p->next)
{
@@ -196,7 +199,6 @@ walk_rtx (x, path)
register int i;
register int len;
register char *fmt;
- register struct code_ptr *link;
int depth = strlen (path);
char *newpath;
@@ -275,6 +277,9 @@ walk_rtx (x, path)
case ADDRESS:
walk_rtx (XEXP (x, 0), path);
return;
+
+ default:
+ break;
}
newpath = (char *) alloca (depth + 2);
@@ -313,6 +318,14 @@ print_path (path)
register int len = strlen (path);
register int i;
+ if (len == 0)
+ {
+ /* Don't emit "pat", since we may try to take the address of it,
+ which isn't what is intended. */
+ printf("PATTERN (insn)");
+ return;
+ }
+
/* We first write out the operations (XEXP or XVECEXP) in reverse
order, then write "insn", then the indices in forward order. */
@@ -362,11 +375,22 @@ xrealloc (ptr, size)
}
static void
-fatal (s, a1, a2)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genextract: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
@@ -438,11 +462,12 @@ main (argc, argv)
from the machine description file `md'. */\n\n");
printf ("#include \"config.h\"\n");
+ printf ("#include \"system.h\"\n");
printf ("#include \"rtl.h\"\n\n");
/* This variable exists only so it can be the "location"
of any missing operand whose numbers are skipped by a given pattern. */
- printf ("static rtx junk;\n");
+ printf ("static rtx junk ATTRIBUTE_UNUSED;\n");
printf ("extern rtx recog_operand[];\n");
printf ("extern rtx *recog_operand_loc[];\n");
@@ -455,6 +480,7 @@ from the machine description file `md'. */\n\n");
printf (" register rtx *ro = recog_operand;\n");
printf (" register rtx **ro_loc = recog_operand_loc;\n");
printf (" rtx pat = PATTERN (insn);\n");
+ printf (" int i ATTRIBUTE_UNUSED;\n\n");
printf (" switch (INSN_CODE (insn))\n");
printf (" {\n");
printf (" case -1:\n");
@@ -502,11 +528,8 @@ from the machine description file `md'. */\n\n");
/* The vector in the insn says how many operands it has.
And all it contains are operands. In fact, the vector was
created just for the sake of this function. */
- printf ("#if __GNUC__ > 1 && !defined (bcopy)\n");
- printf ("#define bcopy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT)\n");
- printf ("#endif\n");
- printf (" bcopy (&XVECEXP (pat, 0, 0), ro,\n");
- printf (" sizeof (rtx) * XVECLEN (pat, 0));\n");
+ printf (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n");
+ printf (" ro[i] = XVECEXP (pat, 0, i);\n");
printf (" break;\n\n");
}
diff --git a/contrib/gcc/genflags.c b/contrib/gcc/genflags.c
index e91b45d..d389a73 100644
--- a/contrib/gcc/genflags.c
+++ b/contrib/gcc/genflags.c
@@ -2,7 +2,7 @@
- some flags HAVE_... saying which simple standard instructions are
available for this machine.
- Copyright (C) 1987, 1991, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1991, 1995, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -22,8 +22,13 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
@@ -33,12 +38,9 @@ struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern rtx read_rtx ();
-
-char *xmalloc ();
-static void fatal ();
-void fancy_abort ();
+char *xmalloc PROTO((unsigned));
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
+void fancy_abort PROTO((void));
/* Names for patterns. Need to allow linking with print-rtl. */
char **insn_name_ptr;
@@ -49,7 +51,14 @@ static struct obstack call_obstack, normal_obstack;
/* Max size of names encountered. */
static int max_id_len;
+static int num_operands PROTO((rtx));
+static void gen_proto PROTO((rtx));
+static void gen_nonproto PROTO((rtx));
+static void gen_insn PROTO((rtx));
+
+
/* Count the number of match_operand's found. */
+
static int
num_operands (x)
rtx x;
@@ -87,6 +96,7 @@ num_operands (x)
}
/* Print out prototype information for a function. */
+
static void
gen_proto (insn)
rtx insn;
@@ -108,6 +118,7 @@ gen_proto (insn)
}
/* Print out a function declaration without a prototype. */
+
static void
gen_nonproto (insn)
rtx insn;
@@ -193,11 +204,22 @@ xrealloc (ptr, size)
}
static void
-fatal (s, a1, a2)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genflags: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
@@ -258,7 +280,7 @@ from the machine description file `md'. */\n\n");
}
/* Print out the prototypes now. */
- dummy = (rtx)0;
+ dummy = (rtx) 0;
obstack_grow (&call_obstack, &dummy, sizeof (rtx));
call_insns = (rtx *) obstack_finish (&call_obstack);
diff --git a/contrib/gcc/gengenrtl.c b/contrib/gcc/gengenrtl.c
new file mode 100644
index 0000000..ade07ff
--- /dev/null
+++ b/contrib/gcc/gengenrtl.c
@@ -0,0 +1,337 @@
+/* Generate code to allocate RTL structures.
+ Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+#include "hconfig.h"
+#include "system.h"
+
+#include "obstack.h"
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+#define NO_GENRTL_H
+#include "rtl.h"
+
+
+struct rtx_definition
+{
+ const char *enumname, *name, *format;
+};
+
+#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) { STRINGIFY(ENUM), NAME, FORMAT },
+
+struct rtx_definition defs[] =
+{
+#include "rtl.def" /* rtl expressions are documented here */
+};
+
+const char *formats[NUM_RTX_CODE];
+
+static const char *type_from_format PROTO((int));
+static const char *accessor_from_format PROTO((int));
+static int special_format PROTO((const char *));
+static int special_rtx PROTO((int));
+static void find_formats PROTO((void));
+static void gendecl PROTO((FILE *, const char *));
+static void genmacro PROTO((FILE *, int));
+static void gendef PROTO((FILE *, const char *));
+static void genlegend PROTO((FILE *));
+static void genheader PROTO((FILE *));
+static void gencode PROTO((FILE *));
+
+static const char *
+type_from_format (c)
+ int c;
+{
+ switch (c)
+ {
+ case 'i':
+ return "int";
+ case 'w':
+ return "HOST_WIDE_INT";
+ case 's':
+ return "char *";
+ case 'e':
+ case 'u':
+ return "rtx";
+ case 'E':
+ return "rtvec";
+ /* ?!? These should be bitmap and tree respectively, but those types
+ are not available in many of the files which include the output
+ of gengenrtl.
+
+ These are only used in prototypes, so I think we can assume that
+ void * is useable. */
+ case 'b':
+ return "void *";
+ case 't':
+ return "void *";
+ default:
+ abort ();
+ }
+}
+
+static const char *
+accessor_from_format (c)
+ int c;
+{
+ switch (c)
+ {
+ case 'i':
+ return "XINT";
+ case 'w':
+ return "XWINT";
+ case 's':
+ return "XSTR";
+ case 'e':
+ case 'u':
+ return "XEXP";
+ case 'E':
+ return "XVEC";
+ case 'b':
+ return "XBITMAP";
+ case 't':
+ return "XTREE";
+ default:
+ abort ();
+ }
+}
+
+static int
+special_format (fmt)
+ const char *fmt;
+{
+ return (strchr (fmt, '*') != 0
+ || strchr (fmt, 'V') != 0
+ || strchr (fmt, 'S') != 0
+ || strchr (fmt, 'n') != 0);
+}
+
+static int
+special_rtx (idx)
+ int idx;
+{
+ return (strcmp (defs[idx].enumname, "CONST_INT") == 0
+ || strcmp (defs[idx].enumname, "REG") == 0
+ || strcmp (defs[idx].enumname, "MEM") == 0);
+}
+
+static void
+find_formats ()
+{
+ int i;
+
+ for (i = 0; i < NUM_RTX_CODE; ++i)
+ {
+ const char **f;
+
+ if (special_format (defs[i].format))
+ continue;
+
+ for (f = formats; *f ; ++f)
+ if (!strcmp(*f, defs[i].format))
+ break;
+
+ if (!*f)
+ *f = defs[i].format;
+ }
+}
+
+static void
+gendecl (f, format)
+ FILE *f;
+ const char *format;
+{
+ const char *p;
+ int i;
+
+ fprintf (f, "extern rtx gen_rtx_fmt_%s PROTO((RTX_CODE, enum machine_mode mode",
+ format);
+ for (p = format, i = 0; *p ; ++p)
+ if (*p != '0')
+ fprintf (f, ", %s arg%d", type_from_format (*p), i++);
+ fprintf (f, "));\n");
+}
+
+static void
+genmacro (f, idx)
+ FILE *f;
+ int idx;
+{
+ const char *p;
+ int i;
+
+ fprintf (f, "#define gen_rtx_%s%s(mode",
+ (special_rtx (idx) ? "raw_" : ""), defs[idx].enumname);
+
+ for (p = defs[idx].format, i = 0; *p ; ++p)
+ if (*p != '0')
+ fprintf (f, ", arg%d", i++);
+ fprintf (f, ") ");
+
+ fprintf (f, "gen_rtx_fmt_%s(%s,(mode)", defs[idx].format, defs[idx].enumname);
+ for (p = defs[idx].format, i = 0; *p ; ++p)
+ if (*p != '0')
+ fprintf (f, ",(arg%d)", i++);
+ fprintf (f, ")\n");
+}
+
+static void
+gendef (f, format)
+ FILE *f;
+ const char *format;
+{
+ const char *p;
+ int i, j;
+
+ fprintf (f, "rtx\ngen_rtx_fmt_%s (code, mode", format);
+ for (p = format, i = 0; *p ; ++p)
+ if (*p != '0')
+ fprintf (f, ", arg%d", i++);
+
+ fprintf (f, ")\n RTX_CODE code;\n enum machine_mode mode;\n");
+ for (p = format, i = 0; *p ; ++p)
+ if (*p != '0')
+ fprintf (f, " %s arg%d;\n", type_from_format (*p), i++);
+
+ /* See rtx_alloc in rtl.c for comments. */
+ fprintf (f, "{\n");
+ fprintf (f, " rtx rt = obstack_alloc_rtx (sizeof (struct rtx_def) + %d * sizeof (rtunion));\n",
+ (int) strlen (format) - 1);
+
+ fprintf (f, " PUT_CODE (rt, code);\n");
+ fprintf (f, " PUT_MODE (rt, mode);\n");
+
+ for (p = format, i = j = 0; *p ; ++p, ++i)
+ if (*p != '0')
+ {
+ fprintf (f, " %s (rt, %d) = arg%d;\n",
+ accessor_from_format (*p), i, j++);
+ }
+
+ fprintf (f, "\n return rt;\n}\n\n");
+}
+
+static void
+genlegend (f)
+ FILE *f;
+{
+ fprintf (f, "/* Generated automaticaly by the program `gengenrtl'\n");
+ fprintf (f, " from the RTL description file `rtl.def' */\n\n");
+}
+
+static void
+genheader (f)
+ FILE *f;
+{
+ int i;
+ const char **fmt;
+
+ for (fmt = formats; *fmt; ++fmt)
+ gendecl (f, *fmt);
+
+ fprintf(f, "\n");
+
+ for (i = 0; i < NUM_RTX_CODE; i++)
+ {
+ if (special_format (defs[i].format))
+ continue;
+ genmacro (f, i);
+ }
+}
+
+static void
+gencode (f)
+ FILE *f;
+{
+ const char **fmt;
+
+ fputs ("#include \"config.h\"\n", f);
+ fputs ("#include \"system.h\"\n", f);
+ fputs ("#include \"obstack.h\"\n", f);
+ fputs ("#include \"rtl.h\"\n\n", f);
+ fputs ("extern struct obstack *rtl_obstack;\n\n", f);
+ fputs ("static rtx obstack_alloc_rtx PROTO((int length));\n", f);
+ fputs ("static rtx obstack_alloc_rtx (length)\n", f);
+ fputs (" register int length;\n{\n", f);
+ fputs (" rtx rt = (rtx) obstack_alloc (rtl_obstack, length);\n\n", f);
+ fputs (" if (sizeof(struct rtx_def) - sizeof(rtunion) == sizeof(int))\n", f);
+ fputs (" *(int *)rt = 0;\n", f);
+ fputs (" else if (sizeof(struct rtx_def) - sizeof(rtunion) == sizeof(HOST_WIDE_INT))\n", f);
+ fputs (" *(HOST_WIDE_INT *)rt = 0;\n", f);
+ fputs (" else\n", f);
+ fputs (" bzero((char *) rt, sizeof(struct rtx_def) - sizeof(rtunion));\n\n", f);
+ fputs (" return rt;\n}\n\n", f);
+
+ for (fmt = formats; *fmt; ++fmt)
+ gendef (f, *fmt);
+}
+
+#if defined(USE_C_ALLOCA) && !defined(__GNUC__)
+char *
+xmalloc (nbytes)
+ int nbytes;
+{
+ char *tmp = (char *) malloc (nbytes);
+
+ if (!tmp)
+ {
+ fprintf (stderr, "can't allocate %d bytes (out of virtual memory)\n", nbytes);
+ exit (FATAL_EXIT_CODE);
+ }
+
+ return tmp;
+}
+#endif /* USE_C_ALLOCA && !__GNUC__ */
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ FILE *f;
+
+ if (argc != 3)
+ exit (1);
+
+ find_formats ();
+
+ f = fopen (argv[1], "w");
+ if (f == NULL)
+ {
+ perror(argv[1]);
+ exit (1);
+ }
+ genlegend (f);
+ genheader (f);
+ fclose(f);
+
+ f = fopen (argv[2], "w");
+ if (f == NULL)
+ {
+ perror(argv[2]);
+ exit (1);
+ }
+ genlegend (f);
+ gencode (f);
+ fclose(f);
+
+ exit (0);
+}
diff --git a/contrib/gcc/genopinit.c b/contrib/gcc/genopinit.c
index 3939126..a31a444 100644
--- a/contrib/gcc/genopinit.c
+++ b/contrib/gcc/genopinit.c
@@ -1,5 +1,5 @@
/* Generate code to initialize optabs from machine description.
- Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1993, 94-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,11 +19,15 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
-#include <ctype.h>
static struct obstack obstack;
struct obstack *rtl_obstack = &obstack;
@@ -31,12 +35,9 @@ struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern rtx read_rtx ();
-
-char *xmalloc ();
-static void fatal ();
-void fancy_abort ();
+char *xmalloc PROTO((unsigned));
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
+void fancy_abort PROTO((void));
/* Many parts of GCC use arrays that are indexed by machine mode and
contain the insn codes for pattern in the MD file that perform a given
@@ -122,21 +123,23 @@ char *optabs[] =
"movcc_gen_code[(int) %A] = CODE_FOR_%(mov%acc%)",
"reload_in_optab[(int) %A] = CODE_FOR_%(reload_in%a%)",
"reload_out_optab[(int) %A] = CODE_FOR_%(reload_out%a%)",
- "movstr_optab[(int) %A] = CODE_FOR_%(movstr%a%)" };
+ "movstr_optab[(int) %A] = CODE_FOR_%(movstr%a%)",
+ "clrstr_optab[(int) %A] = CODE_FOR_%(clrstr%a%)" };
/* Allow linking with print-rtl.c. */
char **insn_name_ptr;
+static void gen_insn PROTO((rtx));
+
static void
gen_insn (insn)
rtx insn;
{
char *name = XSTR (insn, 0);
int m1, m2, op;
- int pindex;
+ size_t pindex;
int i;
char *np, *pp, *p, *q;
- struct obstack *obstack_ptr;
/* Don't mention instructions whose names are the null string.
They are in the machine description just to be recognized. */
@@ -184,9 +187,7 @@ gen_insn (insn)
/* We have to be concerned about matching "gt" and
missing "gtu", e.g., so verify we have reached the
- end of thing we are to match. We do not have this
- problem with modes since no mode is a prefix of
- another. */
+ end of thing we are to match. */
if (*p == 0 && *q == 0 && rtx_class[op] == '<')
break;
}
@@ -198,7 +199,11 @@ gen_insn (insn)
break;
case 'a':
case 'b':
- for (i = 0; i < (int) MAX_MACHINE_MODE; i++)
+ /* This loop will stop at the first prefix match, so
+ look through the modes in reverse order, in case
+ EXTRA_CC_MODES was used and CC is a prefix of the
+ CC modes (as it should be). */
+ for (i = ((int) MAX_MACHINE_MODE) - 1; i >= 0; i--)
{
for (p = mode_name[i], q = np; *p; p++, q++)
if (tolower (*p) != *q)
@@ -210,7 +215,7 @@ gen_insn (insn)
break;
}
- if (i == (int) MAX_MACHINE_MODE)
+ if (i < 0)
matches = 0;
else if (*pp == 'a')
m1 = i, np += strlen (mode_name[i]);
@@ -304,11 +309,22 @@ xrealloc (ptr, size)
}
static void
-fatal (s, a1, a2)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genopinit: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
@@ -328,8 +344,6 @@ main (argc, argv)
char **argv;
{
rtx desc;
- rtx dummy;
- rtx *insn_ptr;
FILE *infile;
register int c;
@@ -351,6 +365,7 @@ main (argc, argv)
from the machine description file `md'. */\n\n");
printf ("#include \"config.h\"\n");
+ printf ("#include \"system.h\"\n");
printf ("#include \"rtl.h\"\n");
printf ("#include \"flags.h\"\n");
printf ("#include \"insn-flags.h\"\n");
diff --git a/contrib/gcc/genoutput.c b/contrib/gcc/genoutput.c
index bbf6200..9f40c85 100644
--- a/contrib/gcc/genoutput.c
+++ b/contrib/gcc/genoutput.c
@@ -1,5 +1,5 @@
/* Generate code from to output assembler insns as recognized from rtl.
- Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92, 94, 95, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -90,8 +90,13 @@ insn_template[24] to be "clrd %0", and insn_n_operands[24] to be 1.
It would not make an case in output_insn_hairy because the template
given in the entry is a constant (it does not start with `*'). */
-#include <stdio.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
@@ -107,16 +112,16 @@ struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern rtx read_rtx ();
-
-char *xmalloc ();
-static void fatal ();
-void fancy_abort ();
-static void error ();
+char *xmalloc PROTO((unsigned));
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
+void fancy_abort PROTO((void));
+static void error PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
static void mybcopy ();
static void mybzero ();
-static int n_occurrences ();
+static int n_occurrences PROTO((int, char *));
+
+/* Define this so we can link with print-rtl.o to get debug_rtx function. */
+char **insn_name_ptr = 0;
/* insns in the machine description are assigned sequential code numbers
that are used by insn-recog.c (produced by genrecog) to communicate
@@ -172,14 +177,26 @@ int have_constraints;
static int have_error;
+static void output_prologue PROTO((void));
+static void output_epilogue PROTO((void));
+static void scan_operands PROTO((rtx, int, int));
+static void process_template PROTO((struct data *, char *));
+static void validate_insn_alternatives PROTO((struct data *));
+static void gen_insn PROTO((rtx));
+static void gen_peephole PROTO((rtx));
+static void gen_expand PROTO((rtx));
+static void gen_split PROTO((rtx));
+static int n_occurrences PROTO((int, char *));
+
static void
output_prologue ()
{
-
printf ("/* Generated automatically by the program `genoutput'\n\
from the machine description file `md'. */\n\n");
printf ("#include \"config.h\"\n");
+ printf ("#include \"system.h\"\n");
+ printf ("#include \"flags.h\"\n");
printf ("#include \"rtl.h\"\n");
printf ("#include \"regs.h\"\n");
printf ("#include \"hard-reg-set.h\"\n");
@@ -191,7 +208,6 @@ from the machine description file `md'. */\n\n");
printf ("#include \"insn-codes.h\"\n\n");
printf ("#include \"recog.h\"\n\n");
- printf ("#include <stdio.h>\n");
printf ("#include \"output.h\"\n");
}
@@ -235,7 +251,7 @@ output_epilogue ()
int offset = 0;
int next;
char * last_name = 0;
- char * next_name;
+ char * next_name = 0;
register struct data *n;
for (n = insn_data, next = 1; n; n = n->next, next++)
@@ -514,6 +530,9 @@ scan_operands (part, this_address_p, this_strict_low)
case STRICT_LOW_PART:
scan_operands (XEXP (part, 0), 0, 1);
return;
+
+ default:
+ break;
}
format_ptr = GET_RTX_FORMAT (GET_CODE (part));
@@ -522,6 +541,7 @@ scan_operands (part, this_address_p, this_strict_low)
switch (*format_ptr++)
{
case 'e':
+ case 'u':
scan_operands (XEXP (part, i), 0, 0);
break;
case 'E':
@@ -560,8 +580,8 @@ process_template (d, template)
printf ("\nstatic char *\n");
printf ("output_%d (operands, insn)\n", d->code_number);
- printf (" rtx *operands;\n");
- printf (" rtx insn;\n");
+ printf (" rtx *operands ATTRIBUTE_UNUSED;\n");
+ printf (" rtx insn ATTRIBUTE_UNUSED;\n");
printf ("{\n");
/* If the assembler code template starts with a @ it is a newline-separated
@@ -581,7 +601,10 @@ process_template (d, template)
printf (" \"");
while (*cp != '\n' && *cp != '\0')
- putchar (*cp++);
+ {
+ putchar (*cp);
+ cp++;
+ }
printf ("\",\n");
i++;
@@ -601,7 +624,11 @@ process_template (d, template)
VAX-11 "C" on VMS. It is the equivalent of:
printf ("%s\n", &template[1])); */
cp = &template[1];
- while (*cp) putchar (*cp++);
+ while (*cp)
+ {
+ putchar (*cp);
+ cp++;
+ }
putchar ('\n');
}
@@ -900,11 +927,22 @@ mybcopy (b1, b2, length)
}
static void
-fatal (s, a1, a2, a3, a4)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genoutput: ");
- fprintf (stderr, s, a1, a2, a3, a4);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
@@ -919,11 +957,22 @@ fancy_abort ()
}
static void
-error (s, a1, a2)
- char *s;
+error VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genoutput: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
have_error = 1;
diff --git a/contrib/gcc/genpeep.c b/contrib/gcc/genpeep.c
index ba2328d..ab65df7 100644
--- a/contrib/gcc/genpeep.c
+++ b/contrib/gcc/genpeep.c
@@ -1,5 +1,5 @@
/* Generate code from machine description to perform peephole optimizations.
- Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1989, 1992, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,8 +19,13 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
@@ -30,8 +35,8 @@ struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern rtx read_rtx ();
+/* Define this so we can link with print-rtl.o to get debug_rtx function. */
+char **insn_name_ptr = 0;
/* While tree-walking an instruction pattern, we keep a chain
of these `struct link's to record how to get down to the
@@ -46,11 +51,9 @@ struct link
int vecelt;
};
-char *xmalloc ();
-static void match_rtx ();
-static void gen_exp ();
-static void fatal ();
-void fancy_abort ();
+char *xmalloc PROTO((unsigned));
+static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
+void fancy_abort PROTO((void));
static int max_opno;
@@ -63,8 +66,10 @@ static int n_operands;
static int insn_code_number = 0;
-static void print_path ();
-static void print_code ();
+static void gen_peephole PROTO((rtx));
+static void match_rtx PROTO((rtx, struct link *, int));
+static void print_path PROTO((struct link *));
+static void print_code PROTO((RTX_CODE));
static void
gen_peephole (peep)
@@ -123,7 +128,7 @@ gen_peephole (peep)
So use a simple regular form: a PARALLEL containing a vector
of all the operands. */
- printf (" PATTERN (ins1) = gen_rtx (PARALLEL, VOIDmode, gen_rtvec_v (%d, operands));\n", n_operands);
+ printf (" PATTERN (ins1) = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (%d, operands));\n", n_operands);
#if 0
printf (" if (want_jump && GET_CODE (ins1) != JUMP_INSN)\n");
@@ -264,6 +269,9 @@ match_rtx (x, path, fail_label)
case ADDRESS:
match_rtx (XEXP (x, 0), path, fail_label);
return;
+
+ default:
+ break;
}
printf (" x = ");
@@ -323,13 +331,9 @@ match_rtx (x, path, fail_label)
printf (";\n");
}
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- printf (" if (XWINT (x, %d) != %d) goto L%d;\n",
- i, XWINT (x, i), fail_label);
-#else
- printf (" if (XWINT (x, %d) != %ld) goto L%d;\n",
- i, XWINT (x, i), fail_label);
-#endif
+ printf (" if (XWINT (x, %d) != ", i);
+ printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i));
+ printf (") goto L%d;\n", fail_label);
}
else if (fmt[i] == 's')
{
@@ -408,11 +412,22 @@ xrealloc (ptr, size)
}
static void
-fatal (s, a1, a2)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genpeep: ");
- fprintf (stderr, s, a1, a2);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
@@ -455,17 +470,18 @@ main (argc, argv)
from the machine description file `md'. */\n\n");
printf ("#include \"config.h\"\n");
+ printf ("#include \"system.h\"\n");
printf ("#include \"rtl.h\"\n");
printf ("#include \"regs.h\"\n");
printf ("#include \"output.h\"\n");
- printf ("#include \"real.h\"\n\n");
+ printf ("#include \"real.h\"\n");
+ printf ("#include \"except.h\"\n\n");
printf ("extern rtx peep_operand[];\n\n");
printf ("#define operands peep_operand\n\n");
printf ("rtx\npeephole (ins1)\n rtx ins1;\n{\n");
- printf (" rtx insn, x, pat;\n");
- printf (" int i;\n\n");
+ printf (" rtx insn ATTRIBUTE_UNUSED, x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n");
/* Early out: no peepholes for insns followed by barriers. */
printf (" if (NEXT_INSN (ins1)\n");
diff --git a/contrib/gcc/genrecog.c b/contrib/gcc/genrecog.c
index 21f1c06..a4b14e3 100644
--- a/contrib/gcc/genrecog.c
+++ b/contrib/gcc/genrecog.c
@@ -1,5 +1,5 @@
/* Generate code from machine description to recognize rtl as insns.
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92, 93, 94, 95, 97, 98 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -46,8 +46,13 @@ Boston, MA 02111-1307, USA. */
which returns 0 if the rtl could not be split, or
it returns the split rtl in a SEQUENCE. */
-#include <stdio.h>
#include "hconfig.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
@@ -57,8 +62,8 @@ struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-extern void free ();
-extern rtx read_rtx ();
+/* Define this so we can link with print-rtl.o to get debug_rtx function. */
+char **insn_name_ptr = 0;
/* Data structure for a listhead of decision trees. The alternatives
to a node are kept in a doublely-linked list so we can easily add nodes
@@ -120,7 +125,7 @@ static int next_number;
static int next_insn_code;
/* Similar, but counts all expressions in the MD file; used for
- error messages. */
+ error messages. */
static int next_index;
@@ -191,8 +196,7 @@ static void change_state PROTO((char *, char *, int));
static char *copystr PROTO((char *));
static void mybzero PROTO((char *, unsigned));
static void mybcopy PROTO((char *, char *, unsigned));
-static char *concat PROTO((char *, char *));
-static void fatal PROTO((char *));
+static void fatal PVPROTO((char *, ...)) ATTRIBUTE_PRINTF_1;
char *xrealloc PROTO((char *, unsigned));
char *xmalloc PROTO((unsigned));
void fancy_abort PROTO((void));
@@ -301,7 +305,7 @@ add_to_sequence (pattern, last, position)
struct decision *this;
char *newpos;
register char *fmt;
- register int i;
+ register size_t i;
int depth = strlen (position);
int len;
@@ -354,6 +358,7 @@ add_to_sequence (pattern, last, position)
case MATCH_SCRATCH:
case MATCH_OPERATOR:
case MATCH_PARALLEL:
+ case MATCH_INSN2:
new->opno = XINT (pattern, 0);
new->code = (code == MATCH_PARALLEL ? PARALLEL : UNKNOWN);
new->enforce_mode = 0;
@@ -498,7 +503,7 @@ add_to_sequence (pattern, last, position)
if (GET_CODE (XEXP (pattern, 0)) == CC0)
break;
- /* ... fall through ... */
+ /* ... fall through ... */
case COMPARE:
/* Enforce the mode on the first operand to avoid ambiguous insns. */
@@ -508,6 +513,9 @@ add_to_sequence (pattern, last, position)
newpos[depth] = '1';
new = add_to_sequence (XEXP (pattern, 1), &new->success, newpos);
return new;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -572,7 +580,7 @@ not_both_true (d1, d2, toplevel)
struct decision *p1, *p2;
/* If they are both to test modes and the modes are different, they aren't
- both true. Similarly for codes, integer elements, and vector lengths. */
+ both true. Similarly for codes, integer elements, and vector lengths. */
if ((d1->enforce_mode && d2->enforce_mode
&& d1->mode != VOIDmode && d2->mode != VOIDmode && d1->mode != d2->mode)
@@ -995,19 +1003,19 @@ write_subroutine (tree, type)
printf (", pnum_clobbers");
printf (")\n");
- printf (" register rtx x0;\n rtx insn;\n");
+ printf (" register rtx x0;\n rtx insn ATTRIBUTE_UNUSED;\n");
if (type == RECOG)
- printf (" int *pnum_clobbers;\n");
+ printf (" int *pnum_clobbers ATTRIBUTE_UNUSED;\n");
printf ("{\n");
printf (" register rtx *ro = &recog_operand[0];\n");
printf (" register rtx ");
for (i = 1; i < max_depth; i++)
- printf ("x%d, ", i);
+ printf ("x%d ATTRIBUTE_UNUSED, ", i);
- printf ("x%d;\n", max_depth);
- printf (" %s tem;\n", type == SPLIT ? "rtx" : "int");
+ printf ("x%d ATTRIBUTE_UNUSED;\n", max_depth);
+ printf (" %s tem ATTRIBUTE_UNUSED;\n", type == SPLIT ? "rtx" : "int");
write_tree (tree, "", NULL_PTR, 1, type);
printf (" ret0: return %d;\n}\n\n", type == SPLIT ? 0 : -1);
}
@@ -1072,7 +1080,7 @@ write_tree_1 (tree, prevpos, afterward, type)
In the latter case, we are branching to a node that is not the first
node in a decision list. We have already checked that it is possible
for both the node we originally tested at this level and the node we
- are branching to to be both match some pattern. That means that they
+ are branching to to both match some pattern. That means that they
usually will be testing the same mode and code. So it is normally safe
for such labels to be inside switch statements, since the tests done
by virtue of arriving at that label will usually already have been
@@ -1139,7 +1147,7 @@ write_tree_1 (tree, prevpos, afterward, type)
seen any of the codes that are valid for the predicate, we
can write a series of "case" statement, one for each possible
code. Since we are already in a switch, these redundant tests
- are very cheap and will reduce the number of predicate called. */
+ are very cheap and will reduce the number of predicate called. */
if (p->pred >= 0)
{
@@ -1286,6 +1294,8 @@ write_tree_1 (tree, prevpos, afterward, type)
printf ("%sswitch (GET_MODE (x%d))\n", indents[indent], depth);
printf ("%s{\n", indents[indent + 2]);
indent += 4;
+ printf ("%sdefault:\n%sbreak;\n", indents[indent - 2],
+ indents[indent]);
printf ("%scase %smode:\n", indents[indent - 2],
GET_MODE_NAME (mode));
modemap[(int) mode] = 1;
@@ -1301,6 +1311,8 @@ write_tree_1 (tree, prevpos, afterward, type)
printf ("%sswitch (GET_CODE (x%d))\n", indents[indent], depth);
printf ("%s{\n", indents[indent + 2]);
indent += 4;
+ printf ("%sdefault:\n%sbreak;\n", indents[indent - 2],
+ indents[indent]);
printf ("%scase ", indents[indent - 2]);
print_code (p->code);
printf (":\n");
@@ -1309,7 +1321,7 @@ write_tree_1 (tree, prevpos, afterward, type)
}
/* Now that most mode and code tests have been done, we can write out
- a label for an inner node, if we haven't already. */
+ a label for an inner node, if we haven't already. */
if (p->label_needed)
printf ("%sL%d:\n", indents[indent - 2], p->number);
@@ -1351,13 +1363,9 @@ write_tree_1 (tree, prevpos, afterward, type)
must fit in 32 bit, thus it suffices to check only
for 1 << 31 . */
HOST_WIDE_INT offset = p->elt_zero_wide == -2147483647 - 1;
- printf (
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- "XWINT (x%d, 0) == %d%s && ",
-#else
- "XWINT (x%d, 0) == %ld%s && ",
-#endif
- depth, p->elt_zero_wide + offset, offset ? "-1" : "");
+ printf ("XWINT (x%d, 0) == ", depth);
+ printf (HOST_WIDE_INT_PRINT_DEC, p->elt_zero_wide + offset);
+ printf ("%s && ", offset ? "-1" : "");
}
if (p->veclen)
printf ("XVECLEN (x%d, 0) == %d && ", depth, p->veclen);
@@ -1643,25 +1651,6 @@ mybcopy (in, out, length)
*out++ = *in++;
}
-static char *
-concat (s1, s2)
- char *s1, *s2;
-{
- register char *tem;
-
- if (s1 == 0)
- return s2;
- if (s2 == 0)
- return s1;
-
- tem = (char *) xmalloc (strlen (s1) + strlen (s2) + 2);
- strcpy (tem, s1);
- strcat (tem, " ");
- strcat (tem, s2);
-
- return tem;
-}
-
char *
xrealloc (ptr, size)
char *ptr;
@@ -1685,11 +1674,22 @@ xmalloc (size)
}
static void
-fatal (s)
- char *s;
+fatal VPROTO ((char *format, ...))
{
+#ifndef __STDC__
+ char *format;
+#endif
+ va_list ap;
+
+ VA_START (ap, format);
+
+#ifndef __STDC__
+ format = va_arg (ap, char *);
+#endif
+
fprintf (stderr, "genrecog: ");
- fprintf (stderr, s);
+ vfprintf (stderr, format, ap);
+ va_end (ap);
fprintf (stderr, "\n");
fprintf (stderr, "after %d definitions\n", next_index);
exit (FATAL_EXIT_CODE);
@@ -1736,6 +1736,7 @@ main (argc, argv)
from the machine description file `md'. */\n\n");
printf ("#include \"config.h\"\n");
+ printf ("#include \"system.h\"\n");
printf ("#include \"rtl.h\"\n");
printf ("#include \"insn-config.h\"\n");
printf ("#include \"recog.h\"\n");
@@ -1774,8 +1775,7 @@ from the machine description file `md'. */\n\n");
If the rtx is valid, recog returns a nonnegative number\n\
which is the insn code number for the pattern that matched.\n");
printf (" This is the same as the order in the machine description of\n\
- the entry that matched. This number can be used as an index into\n\
- entry that matched. This number can be used as an index into various\n\
+ the entry that matched. This number can be used as an index into various\n\
insn_* tables, such as insn_templates, insn_outfun, and insn_n_operands\n\
(found in insn-output.c).\n\n");
printf (" The third argument to recog is an optional pointer to an int.\n\
diff --git a/contrib/gcc/getopt.c b/contrib/gcc/getopt.c
index beb7450..9207271 100644
--- a/contrib/gcc/getopt.c
+++ b/contrib/gcc/getopt.c
@@ -1,11 +1,14 @@
/* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
- "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
+ "Keep this file name-space clean" means, talk to drepper@gnu.org
before changing it!
- Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98
Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@gnu.org.
+
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, or (at your option) any
@@ -18,24 +21,25 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
Ditto for AIX 3.2 and <stdlib.h>. */
#ifndef _NO_PROTO
-#define _NO_PROTO
+# define _NO_PROTO
#endif
#ifdef HAVE_CONFIG_H
-#include <config.h>
+# include <config.h>
#endif
-#if !defined (__STDC__) || !__STDC__
+#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
-#ifndef const
-#define const
-#endif
+# ifndef const
+# define const
+# endif
#endif
#include <stdio.h>
@@ -48,7 +52,15 @@
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
-#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+# define ELIDE_CODE
+# endif
+#endif
+
+#ifndef ELIDE_CODE
/* This needs to come after some library #include
@@ -56,18 +68,26 @@
#ifdef __GNU_LIBRARY__
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
-#include <stdlib.h>
+# include <stdlib.h>
+# include <unistd.h>
#endif /* GNU C library. */
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+# include <string.h>
+# endif
+#endif
+
#ifndef _
/* This is for other GNU distributions with internationalized messages.
When compiling libc, the _ macro is predefined. */
-#ifdef HAVE_LIBINTL_H
-# include <libintl.h>
-# define _(msgid) gettext (msgid)
-#else
-# define _(msgid) (msgid)
-#endif
+# ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid) gettext (msgid)
+# else
+# define _(msgid) (msgid)
+# endif
#endif
/* This version of `getopt' appears to the caller like standard Unix `getopt'
@@ -100,14 +120,20 @@ char *optarg = NULL;
On entry to `getopt', zero means this is the first call; initialize.
- When `getopt' returns EOF, this is the index of the first of the
+ When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
-/* XXX 1003.2 says this must be 1 before any call. */
-int optind = 0;
+/* 1003.2 says this must be 1 before any call. */
+int optind = 1;
+
+/* Formerly, initialization of getopt depended on optind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+int __getopt_initialized = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
@@ -156,7 +182,7 @@ int optopt = '?';
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
- `--' can cause `getopt' to return EOF with `optind' != ARGC. */
+ `--' can cause `getopt' to return -1 with `optind' != ARGC. */
static enum
{
@@ -171,14 +197,22 @@ static char *posixly_correct;
because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work
in GCC. */
-#include <string.h>
-#define my_index strchr
+# include <string.h>
+# define my_index strchr
#else
+# if HAVE_STRING_H
+# include <string.h>
+# else
+# include <strings.h>
+# endif
+
/* Avoid depending on library functions or files
whose names are inconsistent. */
-char *getenv ();
+#ifndef getenv
+extern char *getenv ();
+#endif
static char *
my_index (str, chr)
@@ -199,11 +233,11 @@ my_index (str, chr)
#ifdef __GNUC__
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
That was relevant to code that was here before. */
-#if !defined (__STDC__) || !__STDC__
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
/* gcc with -traditional declares the built-in strlen to return int,
and has done so at least since version 2.4.5. -- rms. */
extern int strlen (const char *);
-#endif /* not __STDC__ */
+# endif /* not __STDC__ */
#endif /* __GNUC__ */
#endif /* not __GNU_LIBRARY__ */
@@ -217,6 +251,46 @@ extern int strlen (const char *);
static int first_nonopt;
static int last_nonopt;
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+ indicating ARGV elements that should not be considered arguments. */
+
+/* Defined in getopt_init.c */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+ is valid for the getopt call we must make sure that the ARGV passed
+ to getopt is that one passed to the process. */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char *const *argv)
+{
+ /* XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+ original_argc = argc;
+ original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# define SWAP_FLAGS(ch1, ch2) \
+ if (nonoption_flags_len > 0) \
+ { \
+ char __tmp = __getopt_nonoption_flags[ch1]; \
+ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
+ __getopt_nonoption_flags[ch2] = __tmp; \
+ }
+#else /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
@@ -226,6 +300,10 @@ static int last_nonopt;
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
static void
exchange (argv)
char **argv;
@@ -240,6 +318,28 @@ exchange (argv)
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
+#ifdef _LIBC
+ /* First make sure the handling of the `__getopt_nonoption_flags'
+ string can work normally. Our top argument must be in the range
+ of the string. */
+ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+ {
+ /* We must extend the array. The user plays games with us and
+ presents new arguments. */
+ char *new_str = malloc (top + 1);
+ if (new_str == NULL)
+ nonoption_flags_len = nonoption_flags_max_len = 0;
+ else
+ {
+ memset (__mempcpy (new_str, __getopt_nonoption_flags,
+ nonoption_flags_max_len),
+ '\0', top + 1 - nonoption_flags_max_len);
+ nonoption_flags_max_len = top + 1;
+ __getopt_nonoption_flags = new_str;
+ }
+ }
+#endif
+
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
@@ -254,6 +354,7 @@ exchange (argv)
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
+ SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
@@ -270,6 +371,7 @@ exchange (argv)
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
+ SWAP_FLAGS (bottom + i, middle + i);
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
@@ -284,15 +386,20 @@ exchange (argv)
/* Initialize the internal data when the first call is made. */
+#if defined __STDC__ && __STDC__
+static const char *_getopt_initialize (int, char *const *, const char *);
+#endif
static const char *
-_getopt_initialize (optstring)
+_getopt_initialize (argc, argv, optstring)
+ int argc;
+ char *const *argv;
const char *optstring;
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
- first_nonopt = last_nonopt = optind = 1;
+ first_nonopt = last_nonopt = optind;
nextchar = NULL;
@@ -315,6 +422,36 @@ _getopt_initialize (optstring)
else
ordering = PERMUTE;
+#ifdef _LIBC
+ if (posixly_correct == NULL
+ && argc == original_argc && argv == original_argv)
+ {
+ if (nonoption_flags_max_len == 0)
+ {
+ if (__getopt_nonoption_flags == NULL
+ || __getopt_nonoption_flags[0] == '\0')
+ nonoption_flags_max_len = -1;
+ else
+ {
+ const char *orig_str = __getopt_nonoption_flags;
+ int len = nonoption_flags_max_len = strlen (orig_str);
+ if (nonoption_flags_max_len < argc)
+ nonoption_flags_max_len = argc;
+ __getopt_nonoption_flags =
+ (char *) malloc (nonoption_flags_max_len);
+ if (__getopt_nonoption_flags == NULL)
+ nonoption_flags_max_len = -1;
+ else
+ memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+ '\0', nonoption_flags_max_len - len);
+ }
+ }
+ nonoption_flags_len = nonoption_flags_max_len;
+ }
+ else
+ nonoption_flags_len = 0;
+#endif
+
return optstring;
}
@@ -331,7 +468,7 @@ _getopt_initialize (optstring)
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
- If there are no more option characters, `getopt' returns `EOF'.
+ If there are no more option characters, `getopt' returns -1.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
@@ -385,16 +522,37 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
{
optarg = NULL;
- if (optind == 0)
+ if (optind == 0 || !__getopt_initialized)
{
- optstring = _getopt_initialize (optstring);
- optind = 1; /* Don't scan ARGV[0], the program name. */
+ if (optind == 0)
+ optind = 1; /* Don't scan ARGV[0], the program name. */
+ optstring = _getopt_initialize (argc, argv, optstring);
+ __getopt_initialized = 1;
}
+ /* Test whether ARGV[optind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#ifdef _LIBC
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
+ || (optind < nonoption_flags_len \
+ && __getopt_nonoption_flags[optind] == '1'))
+#else
+# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
+#endif
+
if (nextchar == NULL || *nextchar == '\0')
{
/* Advance to the next ARGV-element. */
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (last_nonopt > optind)
+ last_nonopt = optind;
+ if (first_nonopt > optind)
+ first_nonopt = optind;
+
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
@@ -408,8 +566,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
- while (optind < argc
- && (argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ while (optind < argc && NONOPTION_P)
optind++;
last_nonopt = optind;
}
@@ -441,16 +598,16 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
- return EOF;
+ return -1;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
- if ((argv[optind][0] != '-' || argv[optind][1] == '\0'))
+ if (NONOPTION_P)
{
if (ordering == REQUIRE_ORDER)
- return EOF;
+ return -1;
optarg = argv[optind++];
return 1;
}
@@ -486,7 +643,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
- int indfound;
+ int indfound = -1;
int option_index;
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
@@ -497,7 +654,8 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
- if (nameend - nextchar == strlen (p->name))
+ if ((unsigned int) (nameend - nextchar)
+ == (unsigned int) strlen (p->name))
{
/* Exact match found. */
pfound = p;
@@ -523,6 +681,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
+ optopt = 0;
return '?';
}
@@ -539,19 +698,23 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
else
{
if (opterr)
- if (argv[optind - 1][1] == '-')
- /* --option */
- fprintf (stderr,
- _("%s: option `--%s' doesn't allow an argument\n"),
- argv[0], pfound->name);
- else
- /* +option or -option */
- fprintf (stderr,
- _("%s: option `%c%s' doesn't allow an argument\n"),
- argv[0], argv[optind - 1][0], pfound->name);
-
- nextchar += strlen (nextchar);
- return '?';
+ {
+ if (argv[optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ _("%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ _("%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[optind - 1][0], pfound->name);
+
+ nextchar += strlen (nextchar);
+
+ optopt = pfound->val;
+ return '?';
+ }
}
}
else if (pfound->has_arg == 1)
@@ -565,6 +728,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
_("%s: option `%s' requires an argument\n"),
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
+ optopt = pfound->val;
return optstring[0] == ':' ? ':' : '?';
}
}
@@ -599,6 +763,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
}
nextchar = (char *) "";
optind++;
+ optopt = 0;
return '?';
}
}
@@ -628,6 +793,130 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only)
optopt = c;
return '?';
}
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct option *p;
+ const struct option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ optind++;
+ }
+ else if (optind == argc)
+ {
+ if (opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ optarg = argv[optind++];
+
+ /* optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (opterr)
+ fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[optind]);
+ nextchar += strlen (nextchar);
+ optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ optarg = nameend + 1;
+ else
+ {
+ if (opterr)
+ fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (optind < argc)
+ optarg = argv[optind++];
+ else
+ {
+ if (opterr)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
if (temp[1] == ':')
{
if (temp[2] == ':')
@@ -690,7 +979,7 @@ getopt (argc, argv, optstring)
0);
}
-#endif /* _LIBC or not __GNU_LIBRARY__. */
+#endif /* Not ELIDE_CODE. */
#ifdef TEST
@@ -710,7 +999,7 @@ main (argc, argv)
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
- if (c == EOF)
+ if (c == -1)
break;
switch (c)
diff --git a/contrib/gcc/getopt.h b/contrib/gcc/getopt.h
index 4ac33b7..fb30719 100644
--- a/contrib/gcc/getopt.h
+++ b/contrib/gcc/getopt.h
@@ -1,5 +1,8 @@
/* Declarations for getopt.
- Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@gnu.org.
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
@@ -13,7 +16,8 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
@@ -36,7 +40,7 @@ extern char *optarg;
On entry to `getopt', zero means this is the first call; initialize.
- When `getopt' returns EOF, this is the index of the first of the
+ When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
@@ -126,4 +130,4 @@ extern int _getopt_internal ();
}
#endif
-#endif /* _GETOPT_H */
+#endif /* getopt.h */
diff --git a/contrib/gcc/getopt1.c b/contrib/gcc/getopt1.c
index 4580211..ff25737 100644
--- a/contrib/gcc/getopt1.c
+++ b/contrib/gcc/getopt1.c
@@ -1,6 +1,9 @@
/* getopt_long and getopt_long_only entry points for GNU getopt.
- Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994
- Free Software Foundation, Inc.
+ Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
+ Free Software Foundation, Inc.
+
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@gnu.org.
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
@@ -14,7 +17,8 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -22,7 +26,7 @@
#include "getopt.h"
-#if !defined (__STDC__) || !__STDC__
+#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
@@ -40,15 +44,21 @@
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
-#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
-#else
-char *getenv ();
#endif
#ifndef NULL
@@ -83,7 +93,7 @@ getopt_long_only (argc, argv, options, long_options, opt_index)
}
-#endif /* _LIBC or not __GNU_LIBRARY__. */
+#endif /* Not ELIDE_CODE. */
#ifdef TEST
@@ -114,7 +124,7 @@ main (argc, argv)
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
- if (c == EOF)
+ if (c == -1)
break;
switch (c)
diff --git a/contrib/gcc/getpwd.c b/contrib/gcc/getpwd.c
index 3692e92..947383e 100644
--- a/contrib/gcc/getpwd.c
+++ b/contrib/gcc/getpwd.c
@@ -1,22 +1,14 @@
/* getpwd.c - get the working directory */
#include "config.h"
-
-#include <errno.h>
-#include <sys/types.h>
+#include "system.h"
#include <sys/stat.h>
-#ifndef errno
-extern int errno;
-#endif
-
/* Virtually every UN*X system now in common use (except for pre-4.3-tahoe
BSD systems) now provides getcwd as called for by POSIX. Allow for
the few exceptions to the general rule here. */
#if !(defined (POSIX) || defined (USG) || defined (VMS)) || defined (HAVE_GETWD)
-#include <sys/param.h>
-extern char *getwd ();
#define getcwd(buf,len) getwd(buf)
#ifdef MAXPATHLEN
#define GUESSPATHLEN (MAXPATHLEN + 1)
@@ -24,18 +16,13 @@ extern char *getwd ();
#define GUESSPATHLEN 100
#endif
#else /* (defined (USG) || defined (VMS)) */
-extern char *getcwd ();
/* We actually use this as a starting point, not a limit. */
#define GUESSPATHLEN 100
#endif /* (defined (USG) || defined (VMS)) */
-#ifdef _WIN32
-#include <direct.h>
-#endif
-char *getenv ();
char *xmalloc ();
-#ifndef VMS
+#if !(defined (VMS) || (defined(_WIN32) && !defined(__CYGWIN32__)))
/* Get the working directory. Use the PWD environment variable if it's
set correctly, since this is faster and gives more uniform answers
@@ -83,7 +70,7 @@ getpwd ()
return p;
}
-#else /* VMS */
+#else /* VMS || _WIN32 && !__CYGWIN32__ */
#ifndef MAXPATHLEN
#define MAXPATHLEN 255
@@ -94,8 +81,13 @@ getpwd ()
{
static char *pwd = 0;
- if (!pwd) pwd = getcwd (xmalloc (MAXPATHLEN+1), MAXPATHLEN+1);
+ if (!pwd)
+ pwd = getcwd (xmalloc (MAXPATHLEN + 1), MAXPATHLEN + 1
+#ifdef VMS
+ , 0
+#endif
+ );
return pwd;
}
-#endif /* VMS */
+#endif /* VMS || _WIN32 && !__CYGWIN32__ */
diff --git a/contrib/gcc/glimits.h b/contrib/gcc/glimits.h
index ff25a97..0e3228b 100644
--- a/contrib/gcc/glimits.h
+++ b/contrib/gcc/glimits.h
@@ -39,7 +39,8 @@
/* Minimum and maximum values a `signed short int' can hold. */
#undef SHRT_MIN
-#define SHRT_MIN (-32768)
+/* For the sake of 16 bit hosts, we may not use -32768 */
+#define SHRT_MIN (-32767-1)
#undef SHRT_MAX
#define SHRT_MAX 32767
@@ -63,7 +64,11 @@
/* Minimum and maximum values a `signed long int' can hold.
(Same as `int'). */
#ifndef __LONG_MAX__
+#if defined (__alpha__) || (defined (__sparc_v9__) && defined (__arch64__))
+#define __LONG_MAX__ 9223372036854775807L
+#else
#define __LONG_MAX__ 2147483647L
+#endif /* __alpha__ || sparc64 */
#endif
#undef LONG_MIN
#define LONG_MIN (-LONG_MAX-1)
diff --git a/contrib/gcc/global.c b/contrib/gcc/global.c
index e9941e6..d382537 100644
--- a/contrib/gcc/global.c
+++ b/contrib/gcc/global.c
@@ -1,5 +1,5 @@
/* Allocate registers for pseudo-registers that span basic blocks.
- Copyright (C) 1987, 1988, 1991, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91, 94, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,15 +19,18 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
+
+#include "machmode.h"
+#include "hard-reg-set.h"
#include "rtl.h"
#include "flags.h"
#include "basic-block.h"
-#include "hard-reg-set.h"
#include "regs.h"
#include "insn-config.h"
#include "output.h"
+#include "toplev.h"
/* This pass of the compiler performs global register allocation.
It assigns hard register numbers to all the pseudo registers
@@ -75,7 +78,7 @@ static int max_allocno;
/* Indexed by (pseudo) reg number, gives the allocno, or -1
for pseudo registers already allocated by local_allocate. */
-static int *reg_allocno;
+int *reg_allocno;
/* Indexed by allocno, gives the reg number. */
@@ -251,7 +254,7 @@ static int n_regs_set;
static HARD_REG_SET eliminable_regset;
-static int allocno_compare PROTO((int *, int *));
+static int allocno_compare PROTO((const GENERIC_PTR, const GENERIC_PTR));
static void global_conflicts PROTO((void));
static void expand_preferences PROTO((void));
static void prune_preferences PROTO((void));
@@ -277,6 +280,7 @@ int
global_alloc (file)
FILE *file;
{
+ int retval;
#ifdef ELIMINABLE_REGS
static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
#endif
@@ -287,7 +291,7 @@ global_alloc (file)
#endif
|| FRAME_POINTER_REQUIRED);
- register int i;
+ register size_t i;
rtx x;
max_allocno = 0;
@@ -385,17 +389,17 @@ global_alloc (file)
/* Note that reg_live_length[i] < 0 indicates a "constant" reg
that we are supposed to refrain from putting in a hard reg.
-2 means do make an allocno but don't allocate it. */
- if (reg_n_refs[i] != 0 && reg_renumber[i] < 0 && reg_live_length[i] != -1
+ if (REG_N_REFS (i) != 0 && reg_renumber[i] < 0 && REG_LIVE_LENGTH (i) != -1
/* Don't allocate pseudos that cross calls,
if this function receives a nonlocal goto. */
&& (! current_function_has_nonlocal_label
- || reg_n_calls_crossed[i] == 0))
+ || REG_N_CALLS_CROSSED (i) == 0))
{
if (reg_may_share[i] && reg_allocno[reg_may_share[i]] >= 0)
reg_allocno[i] = reg_allocno[reg_may_share[i]];
else
reg_allocno[i] = max_allocno++;
- if (reg_live_length[i] == 0)
+ if (REG_LIVE_LENGTH (i) == 0)
abort ();
}
else
@@ -417,10 +421,10 @@ global_alloc (file)
int allocno = reg_allocno[i];
allocno_reg[allocno] = i;
allocno_size[allocno] = PSEUDO_REGNO_SIZE (i);
- allocno_calls_crossed[allocno] += reg_n_calls_crossed[i];
- allocno_n_refs[allocno] += reg_n_refs[i];
- if (allocno_live_length[allocno] < reg_live_length[i])
- allocno_live_length[allocno] = reg_live_length[i];
+ allocno_calls_crossed[allocno] += REG_N_CALLS_CROSSED (i);
+ allocno_n_refs[allocno] += REG_N_REFS (i);
+ if (allocno_live_length[allocno] < REG_LIVE_LENGTH (i))
+ allocno_live_length[allocno] = REG_LIVE_LENGTH (i);
}
/* Calculate amount of usage of each hard reg by pseudos
@@ -437,8 +441,8 @@ global_alloc (file)
for (j = regno; j < endregno; j++)
{
- local_reg_n_refs[j] += reg_n_refs[i];
- local_reg_live_length[j] += reg_live_length[i];
+ local_reg_n_refs[j] += REG_N_REFS (i);
+ local_reg_live_length[j] += REG_LIVE_LENGTH (i);
}
}
@@ -486,8 +490,11 @@ global_alloc (file)
allocno_row_words = (max_allocno + INT_BITS - 1) / INT_BITS;
- conflicts = (INT_TYPE *) alloca (max_allocno * allocno_row_words
- * sizeof (INT_TYPE));
+ /* We used to use alloca here, but the size of what it would try to
+ allocate would occasionally cause it to exceed the stack limit and
+ cause unpredictable core dumps. Some examples were > 2Mb in size. */
+ conflicts = (INT_TYPE *) xmalloc (max_allocno * allocno_row_words
+ * sizeof (INT_TYPE));
bzero ((char *) conflicts,
max_allocno * allocno_row_words * sizeof (INT_TYPE));
@@ -554,19 +561,19 @@ global_alloc (file)
except for parameters marked with reg_live_length[regno] == -2. */
for (i = 0; i < max_allocno; i++)
- if (reg_live_length[allocno_reg[allocno_order[i]]] >= 0)
+ if (REG_LIVE_LENGTH (allocno_reg[allocno_order[i]]) >= 0)
{
/* If we have more than one register class,
first try allocating in the class that is cheapest
for this pseudo-reg. If that fails, try any reg. */
if (N_REG_CLASSES > 1)
{
- find_reg (allocno_order[i], HARD_CONST (0), 0, 0, 0);
+ find_reg (allocno_order[i], 0, 0, 0, 0);
if (reg_renumber[allocno_reg[allocno_order[i]]] >= 0)
continue;
}
if (reg_alternate_class (allocno_reg[allocno_order[i]]) != NO_REGS)
- find_reg (allocno_order[i], HARD_CONST (0), 1, 0, 0);
+ find_reg (allocno_order[i], 0, 1, 0, 0);
}
}
@@ -577,34 +584,39 @@ global_alloc (file)
for the sake of debugging information. */
if (n_basic_blocks > 0)
#endif
- return reload (get_insns (), 1, file);
+ retval = reload (get_insns (), 1, file);
+
+ free (conflicts);
+ return retval;
}
/* Sort predicate for ordering the allocnos.
Returns -1 (1) if *v1 should be allocated before (after) *v2. */
static int
-allocno_compare (v1, v2)
- int *v1, *v2;
+allocno_compare (v1p, v2p)
+ const GENERIC_PTR v1p;
+ const GENERIC_PTR v2p;
{
+ int v1 = *(int *)v1p, v2 = *(int *)v2p;
/* Note that the quotient will never be bigger than
the value of floor_log2 times the maximum number of
times a register can occur in one insn (surely less than 100).
Multiplying this by 10000 can't overflow. */
register int pri1
- = (((double) (floor_log2 (allocno_n_refs[*v1]) * allocno_n_refs[*v1])
- / allocno_live_length[*v1])
- * 10000 * allocno_size[*v1]);
+ = (((double) (floor_log2 (allocno_n_refs[v1]) * allocno_n_refs[v1])
+ / allocno_live_length[v1])
+ * 10000 * allocno_size[v1]);
register int pri2
- = (((double) (floor_log2 (allocno_n_refs[*v2]) * allocno_n_refs[*v2])
- / allocno_live_length[*v2])
- * 10000 * allocno_size[*v2]);
+ = (((double) (floor_log2 (allocno_n_refs[v2]) * allocno_n_refs[v2])
+ / allocno_live_length[v2])
+ * 10000 * allocno_size[v2]);
if (pri2 - pri1)
return pri2 - pri1;
/* If regs are equally good, sort by allocno,
so that the results of qsort leave nothing to chance. */
- return *v1 - *v2;
+ return v1 - v2;
}
/* Scan the rtl code and record all conflicts and register preferences in the
@@ -640,41 +652,36 @@ global_conflicts ()
are explicitly marked in basic_block_live_at_start. */
{
- register int offset;
- REGSET_ELT_TYPE bit;
register regset old = basic_block_live_at_start[b];
int ax = 0;
-#ifdef HARD_REG_SET
- hard_regs_live = old[0];
-#else
- COPY_HARD_REG_SET (hard_regs_live, old);
-#endif
- for (offset = 0, i = 0; offset < regset_size; offset++)
- if (old[offset] == 0)
- i += REGSET_ELT_BITS;
- else
- for (bit = 1; bit; bit <<= 1, i++)
- {
- if (i >= max_regno)
- break;
- if (old[offset] & bit)
- {
- register int a = reg_allocno[i];
- if (a >= 0)
- {
- SET_ALLOCNO_LIVE (a);
- block_start_allocnos[ax++] = a;
- }
- else if ((a = reg_renumber[i]) >= 0)
- mark_reg_live_nc (a, PSEUDO_REGNO_MODE (i));
- }
- }
+ REG_SET_TO_HARD_REG_SET (hard_regs_live, old);
+ EXECUTE_IF_SET_IN_REG_SET (old, FIRST_PSEUDO_REGISTER, i,
+ {
+ register int a = reg_allocno[i];
+ if (a >= 0)
+ {
+ SET_ALLOCNO_LIVE (a);
+ block_start_allocnos[ax++] = a;
+ }
+ else if ((a = reg_renumber[i]) >= 0)
+ mark_reg_live_nc
+ (a, PSEUDO_REGNO_MODE (i));
+ });
/* Record that each allocno now live conflicts with each other
allocno now live, and with each hard reg now live. */
record_conflicts (block_start_allocnos, ax);
+
+#ifdef STACK_REGS
+ /* Pseudos can't go in stack regs at the start of a basic block
+ that can be reached through a computed goto, since reg-stack
+ can't handle computed gotos. */
+ if (basic_block_computed_jump_target[b])
+ for (ax = FIRST_STACK_REG; ax <= LAST_STACK_REG; ax++)
+ record_one_conflict (ax);
+#endif
}
insn = basic_block_head[b];
@@ -869,7 +876,8 @@ prune_preferences ()
we want to give the lower-priority allocno the first chance for
these registers). */
for (j = i + 1; j < max_allocno; j++)
- if (CONFLICTP (allocno, allocno_order[j]))
+ if (CONFLICTP (allocno, allocno_order[j])
+ || CONFLICTP (allocno_order[j], allocno))
{
COPY_HARD_REG_SET (temp,
hard_reg_full_preferences[allocno_order[j]]);
@@ -937,7 +945,7 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
IOR_HARD_REG_SET (used1, hard_reg_conflicts[allocno]);
#ifdef CLASS_CANNOT_CHANGE_SIZE
- if (reg_changes_size[allocno_reg[allocno]])
+ if (REG_CHANGES_SIZE (allocno_reg[allocno]))
IOR_HARD_REG_SET (used1,
reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE]);
#endif
@@ -1085,7 +1093,14 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
&& CALLER_SAVE_PROFITABLE (allocno_n_refs[allocno],
allocno_calls_crossed[allocno]))
{
- find_reg (allocno, losers, alt_regs_p, 1, retrying);
+ HARD_REG_SET new_losers;
+ if (! losers)
+ CLEAR_HARD_REG_SET (new_losers);
+ else
+ COPY_HARD_REG_SET (new_losers, losers);
+
+ IOR_HARD_REG_SET(new_losers, losing_caller_save_reg_set);
+ find_reg (allocno, new_losers, alt_regs_p, 1, retrying);
if (reg_renumber[allocno_reg[allocno]] >= 0)
{
caller_save_needed = 1;
@@ -1117,7 +1132,7 @@ find_reg (allocno, losers, alt_regs_p, accept_call_clobbered, retrying)
&& ! TEST_HARD_REG_BIT (used2, regno)
&& HARD_REGNO_MODE_OK (regno, mode)
#ifdef CLASS_CANNOT_CHANGE_SIZE
- && ! (reg_changes_size[allocno_reg[allocno]]
+ && ! (REG_CHANGES_SIZE (allocno_reg[allocno])
&& (TEST_HARD_REG_BIT
(reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
regno)))
@@ -1630,13 +1645,10 @@ mark_elimination (from, to)
int i;
for (i = 0; i < n_basic_blocks; i++)
- if ((basic_block_live_at_start[i][from / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1 << (from % REGSET_ELT_BITS))) != 0)
+ if (REGNO_REG_SET_P (basic_block_live_at_start[i], from))
{
- basic_block_live_at_start[i][from / REGSET_ELT_BITS]
- &= ~ ((REGSET_ELT_TYPE) 1 << (from % REGSET_ELT_BITS));
- basic_block_live_at_start[i][to / REGSET_ELT_BITS]
- |= ((REGSET_ELT_TYPE) 1 << (to % REGSET_ELT_BITS));
+ CLEAR_REGNO_REG_SET (basic_block_live_at_start[i], from);
+ SET_REGNO_REG_SET (basic_block_live_at_start[i], to);
}
}
diff --git a/contrib/gcc/gmon.c b/contrib/gcc/gmon.c
index bda7d96..04fc13a 100644
--- a/contrib/gcc/gmon.c
+++ b/contrib/gcc/gmon.c
@@ -84,10 +84,10 @@ monstartup(lowpc, highpc)
* so the rest of the scaling (here and in gprof) stays in ints.
*/
lowpc = (char *)
- ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
+ ROUNDDOWN((unsigned) lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
s_lowpc = lowpc;
highpc = (char *)
- ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
+ ROUNDUP((unsigned) highpc, HISTFRACTION*sizeof(HISTCOUNTER));
s_highpc = highpc;
s_textsize = highpc - lowpc;
monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
@@ -220,12 +220,12 @@ mcount()
* for example: signal catchers get called from the stack,
* not from text space. too bad.
*/
- frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
- if ((unsigned long)frompcindex > s_textsize) {
+ frompcindex = (unsigned short *) ((long) frompcindex - (long) s_lowpc);
+ if ((unsigned long) frompcindex > s_textsize) {
goto done;
}
frompcindex =
- &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
+ &froms[((long) frompcindex) / (HASHFRACTION * sizeof(*froms))];
toindex = *frompcindex;
if (toindex == 0) {
/*
@@ -308,11 +308,10 @@ overflow:
goto out;
}
-/*
- * Control profiling
- * profiling is what mcount checks to see if
- * all the data structures are ready.
- */
+/* Control profiling;
+ profiling is what mcount checks to see if
+ all the data structures are ready. */
+
moncontrol(mode)
int mode;
{
@@ -323,7 +322,7 @@ moncontrol(mode)
profiling = 0;
} else {
/* stop */
- profil((char *)0, 0, 0, 0);
+ profil((char *) 0, 0, 0, 0);
profiling = 3;
}
}
diff --git a/contrib/gcc/gsyms.h b/contrib/gcc/gsyms.h
index a2054bb..03bde93 100644
--- a/contrib/gcc/gsyms.h
+++ b/contrib/gcc/gsyms.h
@@ -54,6 +54,9 @@ enum sdb_type
T_USHORT = 13,
T_UINT = 14,
T_ULONG = 15
+#ifdef EXTENDED_SDB_BASIC_TYPES
+ , T_LNGDBL = 16
+#endif
};
enum sdb_type_class
@@ -66,11 +69,18 @@ enum sdb_type_class
enum sdb_masks
{
+#ifdef EXTENDED_SDB_BASIC_TYPES
+ N_BTMASK = 0x1f,
+ N_TMASK = 0x60,
+ N_TMASK1 = 0x300,
+ N_TMASK2 = 0x360,
+ N_BTSHFT = 5,
+#else
N_BTMASK = 017,
N_TMASK = 060,
N_TMASK1 = 0300,
N_TMASK2 = 0360,
N_BTSHFT = 4,
+#endif
N_TSHIFT = 2
};
-
diff --git a/contrib/gcc/gthr-dce.h b/contrib/gcc/gthr-dce.h
new file mode 100644
index 0000000..3cba8a0
--- /dev/null
+++ b/contrib/gcc/gthr-dce.h
@@ -0,0 +1,150 @@
+
+/* Compile this one with gcc. */
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#ifndef __gthr_dce_h
+#define __gthr_dce_h
+
+/* DCE threads interface.
+ DCE threads are based on POSIX threads draft 4, and many things
+ have changed since then. */
+
+#define __GTHREADS 1
+
+#include <pthread.h>
+
+typedef pthread_key_t __gthread_key_t;
+typedef pthread_once_t __gthread_once_t;
+typedef pthread_mutex_t __gthread_mutex_t;
+
+#define __GTHREAD_ONCE_INIT pthread_once_init
+/* Howto define __GTHREAD_MUTEX_INIT? */
+
+#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
+
+#pragma weak pthread_once
+#pragma weak pthread_once_init
+#pragma weak pthread_key_create
+#pragma weak pthread_key_delete
+#pragma weak pthread_getspecific
+#pragma weak pthread_setspecific
+#pragma weak pthread_create
+
+#pragma weak pthread_mutex_lock
+#pragma weak pthread_mutex_trylock
+#pragma weak pthread_mutex_unlock
+
+static void *__gthread_active_ptr = &pthread_create;
+
+static inline int
+__gthread_active_p ()
+{
+ return __gthread_active_ptr != 0;
+}
+
+#else /* not SUPPORTS_WEAK */
+
+static inline int
+__gthread_active_p ()
+{
+ return 1;
+}
+
+#endif /* SUPPORTS_WEAK */
+
+static inline int
+__gthread_once (__gthread_once_t *once, void (*func) ())
+{
+ if (__gthread_active_p ())
+ return pthread_once (once, func);
+ else
+ return -1;
+}
+
+static inline int
+__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
+{
+ return pthread_keycreate (key, dtor);
+}
+
+static inline int
+__gthread_key_dtor (__gthread_key_t key, void *ptr)
+{
+ /* Nothing needed. */
+ return 0;
+}
+
+static inline int
+__gthread_key_delete (__gthread_key_t key)
+{
+ return pthread_key_delete (key);
+}
+
+static inline void *
+__gthread_getspecific (__gthread_key_t key)
+{
+ void *ptr;
+ if (pthread_getspecific (key, &ptr) == 0)
+ return ptr;
+ else
+ return 0;
+}
+
+static inline int
+__gthread_setspecific (__gthread_key_t key, const void *ptr)
+{
+ return pthread_setspecific (key, (void *) ptr);
+}
+
+static inline int
+__gthread_mutex_lock (__gthread_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return pthread_mutex_lock (mutex);
+ else
+ return 0;
+}
+
+static inline int
+__gthread_mutex_trylock (__gthread_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return pthread_mutex_trylock (mutex);
+ else
+ return 0;
+}
+
+static inline int
+__gthread_mutex_unlock (__gthread_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return pthread_mutex_unlock (mutex);
+ else
+ return 0;
+}
+
+#endif /* not __gthr_dce_h */
diff --git a/contrib/gcc/gthr-posix.h b/contrib/gcc/gthr-posix.h
new file mode 100644
index 0000000..19231c3
--- /dev/null
+++ b/contrib/gcc/gthr-posix.h
@@ -0,0 +1,147 @@
+/* Threads compatibily routines for libgcc2. */
+/* Compile this one with gcc. */
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#ifndef __gthr_posix_h
+#define __gthr_posix_h
+
+/* POSIX threads specific definitions.
+ Easy, since the interface is just one-to-one mapping. */
+
+#define __GTHREADS 1
+
+#include <pthread.h>
+
+typedef pthread_key_t __gthread_key_t;
+typedef pthread_once_t __gthread_once_t;
+typedef pthread_mutex_t __gthread_mutex_t;
+
+#define __GTHREAD_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
+#define __GTHREAD_ONCE_INIT PTHREAD_ONCE_INIT
+
+#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
+
+#pragma weak pthread_once
+#pragma weak pthread_key_create
+#pragma weak pthread_key_delete
+#pragma weak pthread_getspecific
+#pragma weak pthread_setspecific
+#pragma weak pthread_create
+
+#pragma weak pthread_mutex_lock
+#pragma weak pthread_mutex_trylock
+#pragma weak pthread_mutex_unlock
+
+static void *__gthread_active_ptr = &pthread_create;
+
+static inline int
+__gthread_active_p ()
+{
+ return __gthread_active_ptr != 0;
+}
+
+#else /* not SUPPORTS_WEAK */
+
+static inline int
+__gthread_active_p ()
+{
+ return 1;
+}
+
+#endif /* SUPPORTS_WEAK */
+
+static inline int
+__gthread_once (__gthread_once_t *once, void (*func) ())
+{
+ if (__gthread_active_p ())
+ return pthread_once (once, func);
+ else
+ return -1;
+}
+
+static inline int
+__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
+{
+ return pthread_key_create (key, dtor);
+}
+
+static inline int
+__gthread_key_dtor (__gthread_key_t key, void *ptr)
+{
+ /* Just reset the key value to zero. */
+ if (ptr)
+ return pthread_setspecific (key, 0);
+ else
+ return 0;
+}
+
+static inline int
+__gthread_key_delete (__gthread_key_t key)
+{
+ return pthread_key_delete (key);
+}
+
+static inline void *
+__gthread_getspecific (__gthread_key_t key)
+{
+ return pthread_getspecific (key);
+}
+
+static inline int
+__gthread_setspecific (__gthread_key_t key, const void *ptr)
+{
+ return pthread_setspecific (key, ptr);
+}
+
+static inline int
+__gthread_mutex_lock (__gthread_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return pthread_mutex_lock (mutex);
+ else
+ return 0;
+}
+
+static inline int
+__gthread_mutex_trylock (__gthread_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return pthread_mutex_trylock (mutex);
+ else
+ return 0;
+}
+
+static inline int
+__gthread_mutex_unlock (__gthread_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return pthread_mutex_unlock (mutex);
+ else
+ return 0;
+}
+
+#endif /* not __gthr_posix_h */
diff --git a/contrib/gcc/gthr-single.h b/contrib/gcc/gthr-single.h
new file mode 100644
index 0000000..f8dfbff
--- /dev/null
+++ b/contrib/gcc/gthr-single.h
@@ -0,0 +1,62 @@
+/* Threads compatibily routines for libgcc2. */
+/* Compile this one with gcc. */
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#ifndef __gthr_single_h
+#define __gthr_single_h
+
+/* Just provide compatibility for mutex handling. */
+
+typedef int __gthread_mutex_t;
+
+#define __GTHREAD_MUTEX_INIT 0
+
+static inline int
+__gthread_active_p ()
+{
+ return 0;
+}
+
+static inline int
+__gthread_mutex_lock (__gthread_mutex_t *mutex __attribute__ ((__unused__)))
+{
+ return 0;
+}
+
+static inline int
+__gthread_mutex_trylock (__gthread_mutex_t *mutex __attribute__ ((__unused__)))
+{
+ return 0;
+}
+
+static inline int
+__gthread_mutex_unlock (__gthread_mutex_t *mutex __attribute__ ((__unused__)))
+{
+ return 0;
+}
+
+#endif /* not __gthr_single_h */
diff --git a/contrib/gcc/gthr-solaris.h b/contrib/gcc/gthr-solaris.h
new file mode 100644
index 0000000..a6f669c
--- /dev/null
+++ b/contrib/gcc/gthr-solaris.h
@@ -0,0 +1,177 @@
+/* Threads compatibily routines for libgcc2. */
+/* Compile this one with gcc. */
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#ifndef __gthr_solaris_h
+#define __gthr_solaris_h
+
+/* Solaris threads as found in Solaris 2.[456].
+ Actually these are Unix International (UI) threads, but I don't
+ know if anyone else implements these. */
+
+#define __GTHREADS 1
+
+#include <thread.h>
+#include <errno.h>
+
+typedef thread_key_t __gthread_key_t;
+typedef struct
+{
+ mutex_t mutex;
+ int once;
+} __gthread_once_t;
+typedef mutex_t __gthread_mutex_t;
+
+#define __GTHREAD_ONCE_INIT { DEFAULTMUTEX, 0 }
+#define __GTHREAD_MUTEX_INIT DEFAULTMUTEX
+
+#if SUPPORTS_WEAK && GTHREAD_USE_WEAK
+
+#pragma weak thr_keycreate
+#pragma weak thr_getspecific
+#pragma weak thr_setspecific
+#pragma weak thr_create
+
+#pragma weak mutex_lock
+#pragma weak mutex_trylock
+#pragma weak mutex_unlock
+
+/* This will not actually work in Solaris 2.5, since libc contains
+ dummy symbols of all thr_* routines. */
+
+static void *__gthread_active_ptr = &thr_create;
+
+static inline int
+__gthread_active_p ()
+{
+ return __gthread_active_ptr != 0;
+}
+
+#else /* not SUPPORTS_WEAK */
+
+static inline int
+__gthread_active_p ()
+{
+ return 1;
+}
+
+#endif /* SUPPORTS_WEAK */
+
+static inline int
+__gthread_once (__gthread_once_t *once, void (*func) ())
+{
+ if (! __gthread_active_p ())
+ return -1;
+
+ if (once == 0 || func == 0)
+ return EINVAL;
+
+ if (once->once == 0)
+ {
+ int status = mutex_lock (&once->mutex);
+ if (status != 0)
+ return status;
+ if (once->once == 0)
+ {
+ (*func) ();
+ once->once ++;
+ }
+ mutex_unlock (&once->mutex);
+ }
+ return 0;
+}
+
+static inline int
+__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
+{
+ /* Solaris 2.5 contains thr_* routines no-op in libc, so test if we actually
+ got a reasonable key value, and if not, fail. */
+ *key = -1;
+ if (thr_keycreate (key, dtor) != 0 || *key == -1)
+ return -1;
+ else
+ return 0;
+}
+
+static inline int
+__gthread_key_dtor (__gthread_key_t key, void *ptr)
+{
+ /* Nothing needed. */
+ return 0;
+}
+
+static inline int
+__gthread_key_delete (__gthread_key_t key)
+{
+ /* Not possible. */
+ return -1;
+}
+
+static inline void *
+__gthread_getspecific (__gthread_key_t key)
+{
+ void *ptr;
+ if (thr_getspecific (key, &ptr) == 0)
+ return ptr;
+ else
+ return 0;
+}
+
+static inline int
+__gthread_setspecific (__gthread_key_t key, const void *ptr)
+{
+ return thr_setspecific (key, (void *) ptr);
+}
+
+static inline int
+__gthread_mutex_lock (__gthread_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return mutex_lock (mutex);
+ else
+ return 0;
+}
+
+static inline int
+__gthread_mutex_trylock (__gthread_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return mutex_trylock (mutex);
+ else
+ return 0;
+}
+
+static inline int
+__gthread_mutex_unlock (__gthread_mutex_t *mutex)
+{
+ if (__gthread_active_p ())
+ return mutex_unlock (mutex);
+ else
+ return 0;
+}
+
+#endif /* not __gthr_solaris_h */
diff --git a/contrib/gcc/gthr-vxworks.h b/contrib/gcc/gthr-vxworks.h
new file mode 100644
index 0000000..9876646
--- /dev/null
+++ b/contrib/gcc/gthr-vxworks.h
@@ -0,0 +1,132 @@
+/* Threads compatibily routines for libgcc2 for VxWorks. */
+/* Compile this one with gcc. */
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+ Contributed by Mike Stump <mrs@wrs.com>.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#ifndef __gthr_vxworks_h
+#define __gthr_vxworks_h
+
+/* POSIX threads specific definitions.
+ Easy, since the interface is just one-to-one mapping. */
+
+#define __GTHREADS 1
+
+#include <vxWorks.h>
+#include <semLib.h>
+/* typedef void *SEM_ID; */
+
+typedef int __gthread_key_t;
+typedef char __gthread_once_t;
+typedef SEM_ID __gthread_mutex_t;
+
+#define __GTHREAD_MUTEX_INIT 0
+#define __GTHREAD_ONCE_INIT 0
+
+#ifndef REG_SAVED_REG
+static inline int
+__gthread_once (__gthread_once_t *once, void (*func) ())
+{
+ (*func)();
+ return 0;
+}
+
+extern __gthread_key_t eh_context_key;
+
+/* This is not the right way to do it, but the semantic of pthreads
+ don't map well enough onto VxWorks. */
+
+static void
+__ehdtor ()
+{
+ if (eh_context_key)
+ free ((void*)eh_context_key);
+ eh_context_key = 0;
+}
+
+/* This only works for the code in libgcc2.c. */
+
+static inline int
+__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
+{
+ *key = 0;
+
+ /* We don't have a way to track dtor here, so instead, we
+ register a generic routine that can cleanup any task. */
+
+ taskDeleteHookAdd (__ehdtor);
+
+ return 0;
+}
+
+#define __gthread_setspecific(key, ptr) \
+ (key = (int) ptr, 0)
+
+static inline int
+__gthread_key_dtor (__gthread_key_t key, void *ptr)
+{
+ /* Just reset the key value to zero. */
+ if (ptr)
+ return __gthread_setspecific (key, 0);
+ else
+ return 0;
+}
+
+#define __gthread_key_delete(key) \
+ taskVarDelete (taskIdSelf (), &key)
+
+#define __gthread_getspecific(key) \
+ ((key == 0) \
+ ? ((taskVarAdd (taskIdSelf (), &key) != OK) \
+ ? (__terminate (), (void*)0) \
+ : (void*)0) \
+ : (void*)key)
+#endif
+
+static inline int
+__gthread_mutex_lock (__gthread_mutex_t *mutex)
+{
+ if (*mutex == 0)
+ *mutex = semMCreate (SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE);
+ return semTake (*mutex, WAIT_FOREVER);
+}
+
+static inline int
+__gthread_mutex_trylock (__gthread_mutex_t *mutex)
+{
+ if (*mutex == 0)
+ *mutex = semMCreate (SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE);
+ return semTake (*mutex, NO_WAIT);
+}
+
+static inline int
+__gthread_mutex_unlock (__gthread_mutex_t *mutex)
+{
+ /* We could return the */
+ return semGive (*mutex);
+}
+
+#endif /* not __gthr_vxworks_h */
diff --git a/contrib/gcc/gthr.h b/contrib/gcc/gthr.h
new file mode 100644
index 0000000..d1028cb
--- /dev/null
+++ b/contrib/gcc/gthr.h
@@ -0,0 +1,99 @@
+/* Threads compatibily routines for libgcc2. */
+/* Compile this one with gcc. */
+/* Copyright (C) 1997 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#ifndef __gthr_h
+#define __gthr_h
+
+/* If this file is compiled with threads support, it must
+ #define __GTHREADS 1
+ to indicate that threads support is present. Also it has define
+ function
+ int __gthread_active_p ()
+ that returns 1 if thread system is active, 0 if not.
+
+ The threads interface must define the following types:
+ __gthread_key_t
+ __gthread_once_t
+ __gthread_mutex_t
+
+ The threads interface must define the following macros:
+
+ __GTHREAD_ONCE_INIT
+ to initialize __gthread_once_t
+ __GTHREAD_MUTEX_INIT
+ to initialize __gthread_mutex_t to get a fast
+ non-recursive mutex.
+
+ The threads interface must define the following static functions:
+
+ int __gthread_once (__gthread_once_t *once, void (*func) ())
+
+ int __gthread_key_create (__gthread_key_t *keyp, void (*dtor) (void *))
+ int __gthread_key_delete (__gthread_key_t key)
+
+ int __gthread_key_dtor (__gthread_key_t key, void *ptr)
+
+ void *__gthread_getspecific (__gthread_key_t key)
+ int __gthread_setspecific (__gthread_key_t key, const void *ptr)
+
+ int __gthread_mutex_lock (__gthread_mutex_t *mutex);
+ int __gthread_mutex_trylock (__gthread_mutex_t *mutex);
+ int __gthread_mutex_unlock (__gthread_mutex_t *mutex);
+
+ All functions returning int should return zero on success or the error
+ number. If the operation is not supported, -1 is returned.
+
+ Currently supported threads packages are
+ POSIX threads with -D_PTHREADS
+ DCE threads with -D_DCE_THREADS
+ Solaris/UI threads with -D_SOLARIS_THREADS
+*/
+
+/* Check first for thread specific defines. */
+#if _PTHREADS
+#include "gthr-posix.h"
+#elif _DCE_THREADS
+#include "gthr-dce.h"
+#elif _SOLARIS_THREADS
+#include "gthr-solaris.h"
+
+/* Include GTHREAD_FILE if one is defined. */
+#elif defined(HAVE_GTHR_DEFAULT)
+#if SUPPORTS_WEAK
+#ifndef GTHREAD_USE_WEAK
+#define GTHREAD_USE_WEAK 1
+#endif
+#endif
+#include "gthr-default.h"
+
+/* Fallback to single thread definitions. */
+#else
+#include "gthr-single.h"
+#endif
+
+#endif /* not __gthr_h */
diff --git a/contrib/gcc/haifa-sched.c b/contrib/gcc/haifa-sched.c
new file mode 100644
index 0000000..0eebda9
--- /dev/null
+++ b/contrib/gcc/haifa-sched.c
@@ -0,0 +1,8738 @@
+/* Instruction scheduling pass.
+ Copyright (C) 1992, 93-97, 1998 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann (tiemann@cygnus.com) Enhanced by,
+ and currently maintained by, Jim Wilson (wilson@cygnus.com)
+
+ This file is part of GNU CC.
+
+ GNU CC 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, or (at your option)
+ any later version.
+
+ GNU CC 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 GNU CC; see the file COPYING. If not, write to the Free
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+
+/* Instruction scheduling pass.
+
+ This pass implements list scheduling within basic blocks. It is
+ run twice: (1) after flow analysis, but before register allocation,
+ and (2) after register allocation.
+
+ The first run performs interblock scheduling, moving insns between
+ different blocks in the same "region", and the second runs only
+ basic block scheduling.
+
+ Interblock motions performed are useful motions and speculative
+ motions, including speculative loads. Motions requiring code
+ duplication are not supported. The identification of motion type
+ and the check for validity of speculative motions requires
+ construction and analysis of the function's control flow graph.
+ The scheduler works as follows:
+
+ We compute insn priorities based on data dependencies. Flow
+ analysis only creates a fraction of the data-dependencies we must
+ observe: namely, only those dependencies which the combiner can be
+ expected to use. For this pass, we must therefore create the
+ remaining dependencies we need to observe: register dependencies,
+ memory dependencies, dependencies to keep function calls in order,
+ and the dependence between a conditional branch and the setting of
+ condition codes are all dealt with here.
+
+ The scheduler first traverses the data flow graph, starting with
+ the last instruction, and proceeding to the first, assigning values
+ to insn_priority as it goes. This sorts the instructions
+ topologically by data dependence.
+
+ Once priorities have been established, we order the insns using
+ list scheduling. This works as follows: starting with a list of
+ all the ready insns, and sorted according to priority number, we
+ schedule the insn from the end of the list by placing its
+ predecessors in the list according to their priority order. We
+ consider this insn scheduled by setting the pointer to the "end" of
+ the list to point to the previous insn. When an insn has no
+ predecessors, we either queue it until sufficient time has elapsed
+ or add it to the ready list. As the instructions are scheduled or
+ when stalls are introduced, the queue advances and dumps insns into
+ the ready list. When all insns down to the lowest priority have
+ been scheduled, the critical path of the basic block has been made
+ as short as possible. The remaining insns are then scheduled in
+ remaining slots.
+
+ Function unit conflicts are resolved during forward list scheduling
+ by tracking the time when each insn is committed to the schedule
+ and from that, the time the function units it uses must be free.
+ As insns on the ready list are considered for scheduling, those
+ that would result in a blockage of the already committed insns are
+ queued until no blockage will result.
+
+ The following list shows the order in which we want to break ties
+ among insns in the ready list:
+
+ 1. choose insn with the longest path to end of bb, ties
+ broken by
+ 2. choose insn with least contribution to register pressure,
+ ties broken by
+ 3. prefer in-block upon interblock motion, ties broken by
+ 4. prefer useful upon speculative motion, ties broken by
+ 5. choose insn with largest control flow probability, ties
+ broken by
+ 6. choose insn with the least dependences upon the previously
+ scheduled insn, or finally
+ 7 choose the insn which has the most insns dependent on it.
+ 8. choose insn with lowest UID.
+
+ Memory references complicate matters. Only if we can be certain
+ that memory references are not part of the data dependency graph
+ (via true, anti, or output dependence), can we move operations past
+ memory references. To first approximation, reads can be done
+ independently, while writes introduce dependencies. Better
+ approximations will yield fewer dependencies.
+
+ Before reload, an extended analysis of interblock data dependences
+ is required for interblock scheduling. This is performed in
+ compute_block_backward_dependences ().
+
+ Dependencies set up by memory references are treated in exactly the
+ same way as other dependencies, by using LOG_LINKS backward
+ dependences. LOG_LINKS are translated into INSN_DEPEND forward
+ dependences for the purpose of forward list scheduling.
+
+ Having optimized the critical path, we may have also unduly
+ extended the lifetimes of some registers. If an operation requires
+ that constants be loaded into registers, it is certainly desirable
+ to load those constants as early as necessary, but no earlier.
+ I.e., it will not do to load up a bunch of registers at the
+ beginning of a basic block only to use them at the end, if they
+ could be loaded later, since this may result in excessive register
+ utilization.
+
+ Note that since branches are never in basic blocks, but only end
+ basic blocks, this pass will not move branches. But that is ok,
+ since we can use GNU's delayed branch scheduling pass to take care
+ of this case.
+
+ Also note that no further optimizations based on algebraic
+ identities are performed, so this pass would be a good one to
+ perform instruction splitting, such as breaking up a multiply
+ instruction into shifts and adds where that is profitable.
+
+ Given the memory aliasing analysis that this pass should perform,
+ it should be possible to remove redundant stores to memory, and to
+ load values from registers instead of hitting memory.
+
+ Before reload, speculative insns are moved only if a 'proof' exists
+ that no exception will be caused by this, and if no live registers
+ exist that inhibit the motion (live registers constraints are not
+ represented by data dependence edges).
+
+ This pass must update information that subsequent passes expect to
+ be correct. Namely: reg_n_refs, reg_n_sets, reg_n_deaths,
+ reg_n_calls_crossed, and reg_live_length. Also, basic_block_head,
+ basic_block_end.
+
+ The information in the line number notes is carefully retained by
+ this pass. Notes that refer to the starting and ending of
+ exception regions are also carefully retained by this pass. All
+ other NOTE insns are grouped in their same relative order at the
+ beginning of basic blocks and regions that have been scheduled.
+
+ The main entry point for this pass is schedule_insns(), called for
+ each function. The work of the scheduler is organized in three
+ levels: (1) function level: insns are subject to splitting,
+ control-flow-graph is constructed, regions are computed (after
+ reload, each region is of one block), (2) region level: control
+ flow graph attributes required for interblock scheduling are
+ computed (dominators, reachability, etc.), data dependences and
+ priorities are computed, and (3) block level: insns in the block
+ are actually scheduled. */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "basic-block.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "flags.h"
+#include "insn-config.h"
+#include "insn-attr.h"
+#include "except.h"
+#include "toplev.h"
+
+extern char *reg_known_equiv_p;
+extern rtx *reg_known_value;
+
+#ifdef INSN_SCHEDULING
+
+/* target_units bitmask has 1 for each unit in the cpu. It should be
+ possible to compute this variable from the machine description.
+ But currently it is computed by examinning the insn list. Since
+ this is only needed for visualization, it seems an acceptable
+ solution. (For understanding the mapping of bits to units, see
+ definition of function_units[] in "insn-attrtab.c") */
+
+static int target_units = 0;
+
+/* issue_rate is the number of insns that can be scheduled in the same
+ machine cycle. It can be defined in the config/mach/mach.h file,
+ otherwise we set it to 1. */
+
+static int issue_rate;
+
+#ifndef ISSUE_RATE
+#define ISSUE_RATE 1
+#endif
+
+/* sched-verbose controls the amount of debugging output the
+ scheduler prints. It is controlled by -fsched-verbose-N:
+ N>0 and no -DSR : the output is directed to stderr.
+ N>=10 will direct the printouts to stderr (regardless of -dSR).
+ N=1: same as -dSR.
+ N=2: bb's probabilities, detailed ready list info, unit/insn info.
+ N=3: rtl at abort point, control-flow, regions info.
+ N=5: dependences info. */
+
+#define MAX_RGN_BLOCKS 10
+#define MAX_RGN_INSNS 100
+
+static int sched_verbose_param = 0;
+static int sched_verbose = 0;
+
+/* nr_inter/spec counts interblock/speculative motion for the function */
+static int nr_inter, nr_spec;
+
+
+/* debugging file. all printouts are sent to dump, which is always set,
+ either to stderr, or to the dump listing file (-dRS). */
+static FILE *dump = 0;
+
+/* fix_sched_param() is called from toplev.c upon detection
+ of the -fsched-***-N options. */
+
+void
+fix_sched_param (param, val)
+ char *param, *val;
+{
+ if (!strcmp (param, "verbose"))
+ sched_verbose_param = atoi (val);
+ else
+ warning ("fix_sched_param: unknown param: %s", param);
+}
+
+
+/* Arrays set up by scheduling for the same respective purposes as
+ similar-named arrays set up by flow analysis. We work with these
+ arrays during the scheduling pass so we can compare values against
+ unscheduled code.
+
+ Values of these arrays are copied at the end of this pass into the
+ arrays set up by flow analysis. */
+static int *sched_reg_n_calls_crossed;
+static int *sched_reg_live_length;
+static int *sched_reg_basic_block;
+
+/* We need to know the current block number during the post scheduling
+ update of live register information so that we can also update
+ REG_BASIC_BLOCK if a register changes blocks. */
+static int current_block_num;
+
+/* Element N is the next insn that sets (hard or pseudo) register
+ N within the current basic block; or zero, if there is no
+ such insn. Needed for new registers which may be introduced
+ by splitting insns. */
+static rtx *reg_last_uses;
+static rtx *reg_last_sets;
+static regset reg_pending_sets;
+static int reg_pending_sets_all;
+
+/* Vector indexed by INSN_UID giving the original ordering of the insns. */
+static int *insn_luid;
+#define INSN_LUID(INSN) (insn_luid[INSN_UID (INSN)])
+
+/* Vector indexed by INSN_UID giving each instruction a priority. */
+static int *insn_priority;
+#define INSN_PRIORITY(INSN) (insn_priority[INSN_UID (INSN)])
+
+static short *insn_costs;
+#define INSN_COST(INSN) insn_costs[INSN_UID (INSN)]
+
+/* Vector indexed by INSN_UID giving an encoding of the function units
+ used. */
+static short *insn_units;
+#define INSN_UNIT(INSN) insn_units[INSN_UID (INSN)]
+
+/* Vector indexed by INSN_UID giving each instruction a register-weight.
+ This weight is an estimation of the insn contribution to registers pressure. */
+static int *insn_reg_weight;
+#define INSN_REG_WEIGHT(INSN) (insn_reg_weight[INSN_UID (INSN)])
+
+/* Vector indexed by INSN_UID giving list of insns which
+ depend upon INSN. Unlike LOG_LINKS, it represents forward dependences. */
+static rtx *insn_depend;
+#define INSN_DEPEND(INSN) insn_depend[INSN_UID (INSN)]
+
+/* Vector indexed by INSN_UID. Initialized to the number of incoming
+ edges in forward dependence graph (= number of LOG_LINKS). As
+ scheduling procedes, dependence counts are decreased. An
+ instruction moves to the ready list when its counter is zero. */
+static int *insn_dep_count;
+#define INSN_DEP_COUNT(INSN) (insn_dep_count[INSN_UID (INSN)])
+
+/* Vector indexed by INSN_UID giving an encoding of the blockage range
+ function. The unit and the range are encoded. */
+static unsigned int *insn_blockage;
+#define INSN_BLOCKAGE(INSN) insn_blockage[INSN_UID (INSN)]
+#define UNIT_BITS 5
+#define BLOCKAGE_MASK ((1 << BLOCKAGE_BITS) - 1)
+#define ENCODE_BLOCKAGE(U, R) \
+((((U) << UNIT_BITS) << BLOCKAGE_BITS \
+ | MIN_BLOCKAGE_COST (R)) << BLOCKAGE_BITS \
+ | MAX_BLOCKAGE_COST (R))
+#define UNIT_BLOCKED(B) ((B) >> (2 * BLOCKAGE_BITS))
+#define BLOCKAGE_RANGE(B) \
+ (((((B) >> BLOCKAGE_BITS) & BLOCKAGE_MASK) << (HOST_BITS_PER_INT / 2)) \
+ | ((B) & BLOCKAGE_MASK))
+
+/* Encodings of the `<name>_unit_blockage_range' function. */
+#define MIN_BLOCKAGE_COST(R) ((R) >> (HOST_BITS_PER_INT / 2))
+#define MAX_BLOCKAGE_COST(R) ((R) & ((1 << (HOST_BITS_PER_INT / 2)) - 1))
+
+#define DONE_PRIORITY -1
+#define MAX_PRIORITY 0x7fffffff
+#define TAIL_PRIORITY 0x7ffffffe
+#define LAUNCH_PRIORITY 0x7f000001
+#define DONE_PRIORITY_P(INSN) (INSN_PRIORITY (INSN) < 0)
+#define LOW_PRIORITY_P(INSN) ((INSN_PRIORITY (INSN) & 0x7f000000) == 0)
+
+/* Vector indexed by INSN_UID giving number of insns referring to this insn. */
+static int *insn_ref_count;
+#define INSN_REF_COUNT(INSN) (insn_ref_count[INSN_UID (INSN)])
+
+/* Vector indexed by INSN_UID giving line-number note in effect for each
+ insn. For line-number notes, this indicates whether the note may be
+ reused. */
+static rtx *line_note;
+#define LINE_NOTE(INSN) (line_note[INSN_UID (INSN)])
+
+/* Vector indexed by basic block number giving the starting line-number
+ for each basic block. */
+static rtx *line_note_head;
+
+/* List of important notes we must keep around. This is a pointer to the
+ last element in the list. */
+static rtx note_list;
+
+/* Regsets telling whether a given register is live or dead before the last
+ scheduled insn. Must scan the instructions once before scheduling to
+ determine what registers are live or dead at the end of the block. */
+static regset bb_live_regs;
+
+/* Regset telling whether a given register is live after the insn currently
+ being scheduled. Before processing an insn, this is equal to bb_live_regs
+ above. This is used so that we can find registers that are newly born/dead
+ after processing an insn. */
+static regset old_live_regs;
+
+/* The chain of REG_DEAD notes. REG_DEAD notes are removed from all insns
+ during the initial scan and reused later. If there are not exactly as
+ many REG_DEAD notes in the post scheduled code as there were in the
+ prescheduled code then we trigger an abort because this indicates a bug. */
+static rtx dead_notes;
+
+/* Queues, etc. */
+
+/* An instruction is ready to be scheduled when all insns preceding it
+ have already been scheduled. It is important to ensure that all
+ insns which use its result will not be executed until its result
+ has been computed. An insn is maintained in one of four structures:
+
+ (P) the "Pending" set of insns which cannot be scheduled until
+ their dependencies have been satisfied.
+ (Q) the "Queued" set of insns that can be scheduled when sufficient
+ time has passed.
+ (R) the "Ready" list of unscheduled, uncommitted insns.
+ (S) the "Scheduled" list of insns.
+
+ Initially, all insns are either "Pending" or "Ready" depending on
+ whether their dependencies are satisfied.
+
+ Insns move from the "Ready" list to the "Scheduled" list as they
+ are committed to the schedule. As this occurs, the insns in the
+ "Pending" list have their dependencies satisfied and move to either
+ the "Ready" list or the "Queued" set depending on whether
+ sufficient time has passed to make them ready. As time passes,
+ insns move from the "Queued" set to the "Ready" list. Insns may
+ move from the "Ready" list to the "Queued" set if they are blocked
+ due to a function unit conflict.
+
+ The "Pending" list (P) are the insns in the INSN_DEPEND of the unscheduled
+ insns, i.e., those that are ready, queued, and pending.
+ The "Queued" set (Q) is implemented by the variable `insn_queue'.
+ The "Ready" list (R) is implemented by the variables `ready' and
+ `n_ready'.
+ The "Scheduled" list (S) is the new insn chain built by this pass.
+
+ The transition (R->S) is implemented in the scheduling loop in
+ `schedule_block' when the best insn to schedule is chosen.
+ The transition (R->Q) is implemented in `queue_insn' when an
+ insn is found to have a function unit conflict with the already
+ committed insns.
+ The transitions (P->R and P->Q) are implemented in `schedule_insn' as
+ insns move from the ready list to the scheduled list.
+ The transition (Q->R) is implemented in 'queue_to_insn' as time
+ passes or stalls are introduced. */
+
+/* Implement a circular buffer to delay instructions until sufficient
+ time has passed. INSN_QUEUE_SIZE is a power of two larger than
+ MAX_BLOCKAGE and MAX_READY_COST computed by genattr.c. This is the
+ longest time an isnsn may be queued. */
+static rtx insn_queue[INSN_QUEUE_SIZE];
+static int q_ptr = 0;
+static int q_size = 0;
+#define NEXT_Q(X) (((X)+1) & (INSN_QUEUE_SIZE-1))
+#define NEXT_Q_AFTER(X, C) (((X)+C) & (INSN_QUEUE_SIZE-1))
+
+/* Vector indexed by INSN_UID giving the minimum clock tick at which
+ the insn becomes ready. This is used to note timing constraints for
+ insns in the pending list. */
+static int *insn_tick;
+#define INSN_TICK(INSN) (insn_tick[INSN_UID (INSN)])
+
+/* Data structure for keeping track of register information
+ during that register's life. */
+
+struct sometimes
+ {
+ int regno;
+ int live_length;
+ int calls_crossed;
+ };
+
+/* Forward declarations. */
+static void add_dependence PROTO ((rtx, rtx, enum reg_note));
+static void remove_dependence PROTO ((rtx, rtx));
+static rtx find_insn_list PROTO ((rtx, rtx));
+static int insn_unit PROTO ((rtx));
+static unsigned int blockage_range PROTO ((int, rtx));
+static void clear_units PROTO ((void));
+static int actual_hazard_this_instance PROTO ((int, int, rtx, int, int));
+static void schedule_unit PROTO ((int, rtx, int));
+static int actual_hazard PROTO ((int, rtx, int, int));
+static int potential_hazard PROTO ((int, rtx, int));
+static int insn_cost PROTO ((rtx, rtx, rtx));
+static int priority PROTO ((rtx));
+static void free_pending_lists PROTO ((void));
+static void add_insn_mem_dependence PROTO ((rtx *, rtx *, rtx, rtx));
+static void flush_pending_lists PROTO ((rtx, int));
+static void sched_analyze_1 PROTO ((rtx, rtx));
+static void sched_analyze_2 PROTO ((rtx, rtx));
+static void sched_analyze_insn PROTO ((rtx, rtx, rtx));
+static void sched_analyze PROTO ((rtx, rtx));
+static void sched_note_set PROTO ((rtx, int));
+static int rank_for_schedule PROTO ((const GENERIC_PTR, const GENERIC_PTR));
+static void swap_sort PROTO ((rtx *, int));
+static void queue_insn PROTO ((rtx, int));
+static int schedule_insn PROTO ((rtx, rtx *, int, int));
+static void create_reg_dead_note PROTO ((rtx, rtx));
+static void attach_deaths PROTO ((rtx, rtx, int));
+static void attach_deaths_insn PROTO ((rtx));
+static int new_sometimes_live PROTO ((struct sometimes *, int, int));
+static void finish_sometimes_live PROTO ((struct sometimes *, int));
+static int schedule_block PROTO ((int, int));
+static rtx regno_use_in PROTO ((int, rtx));
+static void split_hard_reg_notes PROTO ((rtx, rtx, rtx));
+static void new_insn_dead_notes PROTO ((rtx, rtx, rtx, rtx));
+static void update_n_sets PROTO ((rtx, int));
+static void update_flow_info PROTO ((rtx, rtx, rtx, rtx));
+static char *safe_concat PROTO ((char *, char *, char *));
+static int insn_issue_delay PROTO ((rtx));
+static int birthing_insn_p PROTO ((rtx));
+static void adjust_priority PROTO ((rtx));
+
+/* Mapping of insns to their original block prior to scheduling. */
+static int *insn_orig_block;
+#define INSN_BLOCK(insn) (insn_orig_block[INSN_UID (insn)])
+
+/* Some insns (e.g. call) are not allowed to move across blocks. */
+static char *cant_move;
+#define CANT_MOVE(insn) (cant_move[INSN_UID (insn)])
+
+/* Control flow graph edges are kept in circular lists. */
+typedef struct
+ {
+ int from_block;
+ int to_block;
+ int next_in;
+ int next_out;
+ }
+edge;
+static edge *edge_table;
+
+#define NEXT_IN(edge) (edge_table[edge].next_in)
+#define NEXT_OUT(edge) (edge_table[edge].next_out)
+#define FROM_BLOCK(edge) (edge_table[edge].from_block)
+#define TO_BLOCK(edge) (edge_table[edge].to_block)
+
+/* Number of edges in the control flow graph. (in fact larger than
+ that by 1, since edge 0 is unused.) */
+static int nr_edges;
+
+/* Circular list of incoming/outgoing edges of a block */
+static int *in_edges;
+static int *out_edges;
+
+#define IN_EDGES(block) (in_edges[block])
+#define OUT_EDGES(block) (out_edges[block])
+
+/* List of labels which cannot be deleted, needed for control
+ flow graph construction. */
+extern rtx forced_labels;
+
+
+static int is_cfg_nonregular PROTO ((void));
+static int build_control_flow PROTO ((int_list_ptr *, int_list_ptr *,
+ int *, int *));
+static void new_edge PROTO ((int, int));
+
+
+/* A region is the main entity for interblock scheduling: insns
+ are allowed to move between blocks in the same region, along
+ control flow graph edges, in the 'up' direction. */
+typedef struct
+ {
+ int rgn_nr_blocks; /* number of blocks in region */
+ int rgn_blocks; /* blocks in the region (actually index in rgn_bb_table) */
+ }
+region;
+
+/* Number of regions in the procedure */
+static int nr_regions;
+
+/* Table of region descriptions */
+static region *rgn_table;
+
+/* Array of lists of regions' blocks */
+static int *rgn_bb_table;
+
+/* Topological order of blocks in the region (if b2 is reachable from
+ b1, block_to_bb[b2] > block_to_bb[b1]).
+ Note: A basic block is always referred to by either block or b,
+ while its topological order name (in the region) is refered to by
+ bb.
+ */
+static int *block_to_bb;
+
+/* The number of the region containing a block. */
+static int *containing_rgn;
+
+#define RGN_NR_BLOCKS(rgn) (rgn_table[rgn].rgn_nr_blocks)
+#define RGN_BLOCKS(rgn) (rgn_table[rgn].rgn_blocks)
+#define BLOCK_TO_BB(block) (block_to_bb[block])
+#define CONTAINING_RGN(block) (containing_rgn[block])
+
+void debug_regions PROTO ((void));
+static void find_single_block_region PROTO ((void));
+static void find_rgns PROTO ((int_list_ptr *, int_list_ptr *,
+ int *, int *, sbitmap *));
+static int too_large PROTO ((int, int *, int *));
+
+extern void debug_live PROTO ((int, int));
+
+/* Blocks of the current region being scheduled. */
+static int current_nr_blocks;
+static int current_blocks;
+
+/* The mapping from bb to block */
+#define BB_TO_BLOCK(bb) (rgn_bb_table[current_blocks + (bb)])
+
+
+/* Bit vectors and bitset operations are needed for computations on
+ the control flow graph. */
+
+typedef unsigned HOST_WIDE_INT *bitset;
+typedef struct
+ {
+ int *first_member; /* pointer to the list start in bitlst_table. */
+ int nr_members; /* the number of members of the bit list. */
+ }
+bitlst;
+
+static int bitlst_table_last;
+static int bitlst_table_size;
+static int *bitlst_table;
+
+static char bitset_member PROTO ((bitset, int, int));
+static void extract_bitlst PROTO ((bitset, int, bitlst *));
+
+/* target info declarations.
+
+ The block currently being scheduled is referred to as the "target" block,
+ while other blocks in the region from which insns can be moved to the
+ target are called "source" blocks. The candidate structure holds info
+ about such sources: are they valid? Speculative? Etc. */
+typedef bitlst bblst;
+typedef struct
+ {
+ char is_valid;
+ char is_speculative;
+ int src_prob;
+ bblst split_bbs;
+ bblst update_bbs;
+ }
+candidate;
+
+static candidate *candidate_table;
+
+/* A speculative motion requires checking live information on the path
+ from 'source' to 'target'. The split blocks are those to be checked.
+ After a speculative motion, live information should be modified in
+ the 'update' blocks.
+
+ Lists of split and update blocks for each candidate of the current
+ target are in array bblst_table */
+static int *bblst_table, bblst_size, bblst_last;
+
+#define IS_VALID(src) ( candidate_table[src].is_valid )
+#define IS_SPECULATIVE(src) ( candidate_table[src].is_speculative )
+#define SRC_PROB(src) ( candidate_table[src].src_prob )
+
+/* The bb being currently scheduled. */
+static int target_bb;
+
+/* List of edges. */
+typedef bitlst edgelst;
+
+/* target info functions */
+static void split_edges PROTO ((int, int, edgelst *));
+static void compute_trg_info PROTO ((int));
+void debug_candidate PROTO ((int));
+void debug_candidates PROTO ((int));
+
+
+/* Bit-set of bbs, where bit 'i' stands for bb 'i'. */
+typedef bitset bbset;
+
+/* Number of words of the bbset. */
+static int bbset_size;
+
+/* Dominators array: dom[i] contains the bbset of dominators of
+ bb i in the region. */
+static bbset *dom;
+
+/* bb 0 is the only region entry */
+#define IS_RGN_ENTRY(bb) (!bb)
+
+/* Is bb_src dominated by bb_trg. */
+#define IS_DOMINATED(bb_src, bb_trg) \
+( bitset_member (dom[bb_src], bb_trg, bbset_size) )
+
+/* Probability: Prob[i] is a float in [0, 1] which is the probability
+ of bb i relative to the region entry. */
+static float *prob;
+
+/* The probability of bb_src, relative to bb_trg. Note, that while the
+ 'prob[bb]' is a float in [0, 1], this macro returns an integer
+ in [0, 100]. */
+#define GET_SRC_PROB(bb_src, bb_trg) ((int) (100.0 * (prob[bb_src] / \
+ prob[bb_trg])))
+
+/* Bit-set of edges, where bit i stands for edge i. */
+typedef bitset edgeset;
+
+/* Number of edges in the region. */
+static int rgn_nr_edges;
+
+/* Array of size rgn_nr_edges. */
+static int *rgn_edges;
+
+/* Number of words in an edgeset. */
+static int edgeset_size;
+
+/* Mapping from each edge in the graph to its number in the rgn. */
+static int *edge_to_bit;
+#define EDGE_TO_BIT(edge) (edge_to_bit[edge])
+
+/* The split edges of a source bb is different for each target
+ bb. In order to compute this efficiently, the 'potential-split edges'
+ are computed for each bb prior to scheduling a region. This is actually
+ the split edges of each bb relative to the region entry.
+
+ pot_split[bb] is the set of potential split edges of bb. */
+static edgeset *pot_split;
+
+/* For every bb, a set of its ancestor edges. */
+static edgeset *ancestor_edges;
+
+static void compute_dom_prob_ps PROTO ((int));
+
+#define ABS_VALUE(x) (((x)<0)?(-(x)):(x))
+#define INSN_PROBABILITY(INSN) (SRC_PROB (BLOCK_TO_BB (INSN_BLOCK (INSN))))
+#define IS_SPECULATIVE_INSN(INSN) (IS_SPECULATIVE (BLOCK_TO_BB (INSN_BLOCK (INSN))))
+#define INSN_BB(INSN) (BLOCK_TO_BB (INSN_BLOCK (INSN)))
+
+/* parameters affecting the decision of rank_for_schedule() */
+#define MIN_DIFF_PRIORITY 2
+#define MIN_PROBABILITY 40
+#define MIN_PROB_DIFF 10
+
+/* speculative scheduling functions */
+static int check_live_1 PROTO ((int, rtx));
+static void update_live_1 PROTO ((int, rtx));
+static int check_live PROTO ((rtx, int));
+static void update_live PROTO ((rtx, int));
+static void set_spec_fed PROTO ((rtx));
+static int is_pfree PROTO ((rtx, int, int));
+static int find_conditional_protection PROTO ((rtx, int));
+static int is_conditionally_protected PROTO ((rtx, int, int));
+static int may_trap_exp PROTO ((rtx, int));
+static int haifa_classify_insn PROTO ((rtx));
+static int is_prisky PROTO ((rtx, int, int));
+static int is_exception_free PROTO ((rtx, int, int));
+
+static char find_insn_mem_list PROTO ((rtx, rtx, rtx, rtx));
+static void compute_block_forward_dependences PROTO ((int));
+static void init_rgn_data_dependences PROTO ((int));
+static void add_branch_dependences PROTO ((rtx, rtx));
+static void compute_block_backward_dependences PROTO ((int));
+void debug_dependencies PROTO ((void));
+
+/* Notes handling mechanism:
+ =========================
+ Generally, NOTES are saved before scheduling and restored after scheduling.
+ The scheduler distinguishes between three types of notes:
+
+ (1) LINE_NUMBER notes, generated and used for debugging. Here,
+ before scheduling a region, a pointer to the LINE_NUMBER note is
+ added to the insn following it (in save_line_notes()), and the note
+ is removed (in rm_line_notes() and unlink_line_notes()). After
+ scheduling the region, this pointer is used for regeneration of
+ the LINE_NUMBER note (in restore_line_notes()).
+
+ (2) LOOP_BEGIN, LOOP_END, SETJMP, EHREGION_BEG, EHREGION_END notes:
+ Before scheduling a region, a pointer to the note is added to the insn
+ that follows or precedes it. (This happens as part of the data dependence
+ computation). After scheduling an insn, the pointer contained in it is
+ used for regenerating the corresponding note (in reemit_notes).
+
+ (3) All other notes (e.g. INSN_DELETED): Before scheduling a block,
+ these notes are put in a list (in rm_other_notes() and
+ unlink_other_notes ()). After scheduling the block, these notes are
+ inserted at the beginning of the block (in schedule_block()). */
+
+static rtx unlink_other_notes PROTO ((rtx, rtx));
+static rtx unlink_line_notes PROTO ((rtx, rtx));
+static void rm_line_notes PROTO ((int));
+static void save_line_notes PROTO ((int));
+static void restore_line_notes PROTO ((int));
+static void rm_redundant_line_notes PROTO ((void));
+static void rm_other_notes PROTO ((rtx, rtx));
+static rtx reemit_notes PROTO ((rtx, rtx));
+
+static void get_block_head_tail PROTO ((int, rtx *, rtx *));
+
+static void find_pre_sched_live PROTO ((int));
+static void find_post_sched_live PROTO ((int));
+static void update_reg_usage PROTO ((void));
+static int queue_to_ready PROTO ((rtx [], int));
+
+static void debug_ready_list PROTO ((rtx[], int));
+static void init_target_units PROTO ((void));
+static void insn_print_units PROTO ((rtx));
+static int get_visual_tbl_length PROTO ((void));
+static void init_block_visualization PROTO ((void));
+static void print_block_visualization PROTO ((int, char *));
+static void visualize_scheduled_insns PROTO ((int, int));
+static void visualize_no_unit PROTO ((rtx));
+static void visualize_stall_cycles PROTO ((int, int));
+static void print_exp PROTO ((char *, rtx, int));
+static void print_value PROTO ((char *, rtx, int));
+static void print_pattern PROTO ((char *, rtx, int));
+static void print_insn PROTO ((char *, rtx, int));
+void debug_reg_vector PROTO ((regset));
+
+static rtx move_insn1 PROTO ((rtx, rtx));
+static rtx move_insn PROTO ((rtx, rtx));
+static rtx group_leader PROTO ((rtx));
+static int set_priorities PROTO ((int));
+static void init_rtx_vector PROTO ((rtx **, rtx *, int, int));
+static void schedule_region PROTO ((int));
+static void split_block_insns PROTO ((int));
+
+#endif /* INSN_SCHEDULING */
+
+#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
+
+/* Helper functions for instruction scheduling. */
+
+/* An INSN_LIST containing all INSN_LISTs allocated but currently unused. */
+static rtx unused_insn_list;
+
+/* An EXPR_LIST containing all EXPR_LISTs allocated but currently unused. */
+static rtx unused_expr_list;
+
+static void free_list PROTO ((rtx *, rtx *));
+static rtx alloc_INSN_LIST PROTO ((rtx, rtx));
+static rtx alloc_EXPR_LIST PROTO ((int, rtx, rtx));
+
+static void
+free_list (listp, unused_listp)
+ rtx *listp, *unused_listp;
+{
+ register rtx link, prev_link;
+
+ if (*listp == 0)
+ return;
+
+ prev_link = *listp;
+ link = XEXP (prev_link, 1);
+
+ while (link)
+ {
+ prev_link = link;
+ link = XEXP (link, 1);
+ }
+
+ XEXP (prev_link, 1) = *unused_listp;
+ *unused_listp = *listp;
+ *listp = 0;
+}
+
+static rtx
+alloc_INSN_LIST (val, next)
+ rtx val, next;
+{
+ rtx r;
+
+ if (unused_insn_list)
+ {
+ r = unused_insn_list;
+ unused_insn_list = XEXP (r, 1);
+ XEXP (r, 0) = val;
+ XEXP (r, 1) = next;
+ PUT_REG_NOTE_KIND (r, VOIDmode);
+ }
+ else
+ r = gen_rtx_INSN_LIST (VOIDmode, val, next);
+
+ return r;
+}
+
+static rtx
+alloc_EXPR_LIST (kind, val, next)
+ int kind;
+ rtx val, next;
+{
+ rtx r;
+
+ if (unused_expr_list)
+ {
+ r = unused_expr_list;
+ unused_expr_list = XEXP (r, 1);
+ XEXP (r, 0) = val;
+ XEXP (r, 1) = next;
+ PUT_REG_NOTE_KIND (r, kind);
+ }
+ else
+ r = gen_rtx_EXPR_LIST (kind, val, next);
+
+ return r;
+}
+
+/* Add ELEM wrapped in an INSN_LIST with reg note kind DEP_TYPE to the
+ LOG_LINKS of INSN, if not already there. DEP_TYPE indicates the type
+ of dependence that this link represents. */
+
+static void
+add_dependence (insn, elem, dep_type)
+ rtx insn;
+ rtx elem;
+ enum reg_note dep_type;
+{
+ rtx link, next;
+
+ /* Don't depend an insn on itself. */
+ if (insn == elem)
+ return;
+
+ /* If elem is part of a sequence that must be scheduled together, then
+ make the dependence point to the last insn of the sequence.
+ When HAVE_cc0, it is possible for NOTEs to exist between users and
+ setters of the condition codes, so we must skip past notes here.
+ Otherwise, NOTEs are impossible here. */
+
+ next = NEXT_INSN (elem);
+
+#ifdef HAVE_cc0
+ while (next && GET_CODE (next) == NOTE)
+ next = NEXT_INSN (next);
+#endif
+
+ if (next && SCHED_GROUP_P (next)
+ && GET_CODE (next) != CODE_LABEL)
+ {
+ /* Notes will never intervene here though, so don't bother checking
+ for them. */
+ /* We must reject CODE_LABELs, so that we don't get confused by one
+ that has LABEL_PRESERVE_P set, which is represented by the same
+ bit in the rtl as SCHED_GROUP_P. A CODE_LABEL can never be
+ SCHED_GROUP_P. */
+ while (NEXT_INSN (next) && SCHED_GROUP_P (NEXT_INSN (next))
+ && GET_CODE (NEXT_INSN (next)) != CODE_LABEL)
+ next = NEXT_INSN (next);
+
+ /* Again, don't depend an insn on itself. */
+ if (insn == next)
+ return;
+
+ /* Make the dependence to NEXT, the last insn of the group, instead
+ of the original ELEM. */
+ elem = next;
+ }
+
+#ifdef INSN_SCHEDULING
+ /* (This code is guarded by INSN_SCHEDULING, otherwise INSN_BB is undefined.)
+ No need for interblock dependences with calls, since
+ calls are not moved between blocks. Note: the edge where
+ elem is a CALL is still required. */
+ if (GET_CODE (insn) == CALL_INSN
+ && (INSN_BB (elem) != INSN_BB (insn)))
+ return;
+
+#endif
+
+ /* Check that we don't already have this dependence. */
+ for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
+ if (XEXP (link, 0) == elem)
+ {
+ /* If this is a more restrictive type of dependence than the existing
+ one, then change the existing dependence to this type. */
+ if ((int) dep_type < (int) REG_NOTE_KIND (link))
+ PUT_REG_NOTE_KIND (link, dep_type);
+ return;
+ }
+ /* Might want to check one level of transitivity to save conses. */
+
+ link = alloc_INSN_LIST (elem, LOG_LINKS (insn));
+ LOG_LINKS (insn) = link;
+
+ /* Insn dependency, not data dependency. */
+ PUT_REG_NOTE_KIND (link, dep_type);
+}
+
+/* Remove ELEM wrapped in an INSN_LIST from the LOG_LINKS
+ of INSN. Abort if not found. */
+
+static void
+remove_dependence (insn, elem)
+ rtx insn;
+ rtx elem;
+{
+ rtx prev, link, next;
+ int found = 0;
+
+ for (prev = 0, link = LOG_LINKS (insn); link; link = next)
+ {
+ next = XEXP (link, 1);
+ if (XEXP (link, 0) == elem)
+ {
+ if (prev)
+ XEXP (prev, 1) = next;
+ else
+ LOG_LINKS (insn) = next;
+
+ XEXP (link, 1) = unused_insn_list;
+ unused_insn_list = link;
+
+ found = 1;
+ }
+ else
+ prev = link;
+ }
+
+ if (!found)
+ abort ();
+ return;
+}
+
+#ifndef INSN_SCHEDULING
+void
+schedule_insns (dump_file)
+ FILE *dump_file;
+{
+}
+#else
+#ifndef __GNUC__
+#define __inline
+#endif
+
+#ifndef HAIFA_INLINE
+#define HAIFA_INLINE __inline
+#endif
+
+/* Computation of memory dependencies. */
+
+/* The *_insns and *_mems are paired lists. Each pending memory operation
+ will have a pointer to the MEM rtx on one list and a pointer to the
+ containing insn on the other list in the same place in the list. */
+
+/* We can't use add_dependence like the old code did, because a single insn
+ may have multiple memory accesses, and hence needs to be on the list
+ once for each memory access. Add_dependence won't let you add an insn
+ to a list more than once. */
+
+/* An INSN_LIST containing all insns with pending read operations. */
+static rtx pending_read_insns;
+
+/* An EXPR_LIST containing all MEM rtx's which are pending reads. */
+static rtx pending_read_mems;
+
+/* An INSN_LIST containing all insns with pending write operations. */
+static rtx pending_write_insns;
+
+/* An EXPR_LIST containing all MEM rtx's which are pending writes. */
+static rtx pending_write_mems;
+
+/* Indicates the combined length of the two pending lists. We must prevent
+ these lists from ever growing too large since the number of dependencies
+ produced is at least O(N*N), and execution time is at least O(4*N*N), as
+ a function of the length of these pending lists. */
+
+static int pending_lists_length;
+
+/* The last insn upon which all memory references must depend.
+ This is an insn which flushed the pending lists, creating a dependency
+ between it and all previously pending memory references. This creates
+ a barrier (or a checkpoint) which no memory reference is allowed to cross.
+
+ This includes all non constant CALL_INSNs. When we do interprocedural
+ alias analysis, this restriction can be relaxed.
+ This may also be an INSN that writes memory if the pending lists grow
+ too large. */
+
+static rtx last_pending_memory_flush;
+
+/* The last function call we have seen. All hard regs, and, of course,
+ the last function call, must depend on this. */
+
+static rtx last_function_call;
+
+/* The LOG_LINKS field of this is a list of insns which use a pseudo register
+ that does not already cross a call. We create dependencies between each
+ of those insn and the next call insn, to ensure that they won't cross a call
+ after scheduling is done. */
+
+static rtx sched_before_next_call;
+
+/* Pointer to the last instruction scheduled. Used by rank_for_schedule,
+ so that insns independent of the last scheduled insn will be preferred
+ over dependent instructions. */
+
+static rtx last_scheduled_insn;
+
+/* Data structures for the computation of data dependences in a regions. We
+ keep one copy of each of the declared above variables for each bb in the
+ region. Before analyzing the data dependences for a bb, its variables
+ are initialized as a function of the variables of its predecessors. When
+ the analysis for a bb completes, we save the contents of each variable X
+ to a corresponding bb_X[bb] variable. For example, pending_read_insns is
+ copied to bb_pending_read_insns[bb]. Another change is that few
+ variables are now a list of insns rather than a single insn:
+ last_pending_memory_flash, last_function_call, reg_last_sets. The
+ manipulation of these variables was changed appropriately. */
+
+static rtx **bb_reg_last_uses;
+static rtx **bb_reg_last_sets;
+
+static rtx *bb_pending_read_insns;
+static rtx *bb_pending_read_mems;
+static rtx *bb_pending_write_insns;
+static rtx *bb_pending_write_mems;
+static int *bb_pending_lists_length;
+
+static rtx *bb_last_pending_memory_flush;
+static rtx *bb_last_function_call;
+static rtx *bb_sched_before_next_call;
+
+/* functions for construction of the control flow graph. */
+
+/* Return 1 if control flow graph should not be constructed, 0 otherwise.
+
+ We decide not to build the control flow graph if there is possibly more
+ than one entry to the function, if computed branches exist, of if we
+ have nonlocal gotos. */
+
+static int
+is_cfg_nonregular ()
+{
+ int b;
+ rtx insn;
+ RTX_CODE code;
+
+ /* If we have a label that could be the target of a nonlocal goto, then
+ the cfg is not well structured. */
+ if (nonlocal_label_rtx_list () != NULL)
+ return 1;
+
+ /* If we have any forced labels, then the cfg is not well structured. */
+ if (forced_labels)
+ return 1;
+
+ /* If this function has a computed jump, then we consider the cfg
+ not well structured. */
+ if (current_function_has_computed_jump)
+ return 1;
+
+ /* If we have exception handlers, then we consider the cfg not well
+ structured. ?!? We should be able to handle this now that flow.c
+ computes an accurate cfg for EH. */
+ if (exception_handler_labels)
+ return 1;
+
+ /* If we have non-jumping insns which refer to labels, then we consider
+ the cfg not well structured. */
+ /* check for labels referred to other thn by jumps */
+ for (b = 0; b < n_basic_blocks; b++)
+ for (insn = basic_block_head[b];; insn = NEXT_INSN (insn))
+ {
+ code = GET_CODE (insn);
+ if (GET_RTX_CLASS (code) == 'i')
+ {
+ rtx note;
+
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_LABEL)
+ return 1;
+ }
+
+ if (insn == basic_block_end[b])
+ break;
+ }
+
+ /* All the tests passed. Consider the cfg well structured. */
+ return 0;
+}
+
+/* Build the control flow graph and set nr_edges.
+
+ Instead of trying to build a cfg ourselves, we rely on flow to
+ do it for us. Stamp out useless code (and bug) duplication.
+
+ Return nonzero if an irregularity in the cfg is found which would
+ prevent cross block scheduling. */
+
+static int
+build_control_flow (s_preds, s_succs, num_preds, num_succs)
+ int_list_ptr *s_preds;
+ int_list_ptr *s_succs;
+ int *num_preds;
+ int *num_succs;
+{
+ int i;
+ int_list_ptr succ;
+ int unreachable;
+
+ /* Count the number of edges in the cfg. */
+ nr_edges = 0;
+ unreachable = 0;
+ for (i = 0; i < n_basic_blocks; i++)
+ {
+ nr_edges += num_succs[i];
+
+ /* Unreachable loops with more than one basic block are detected
+ during the DFS traversal in find_rgns.
+
+ Unreachable loops with a single block are detected here. This
+ test is redundant with the one in find_rgns, but it's much
+ cheaper to go ahead and catch the trivial case here. */
+ if (num_preds[i] == 0
+ || (num_preds[i] == 1 && INT_LIST_VAL (s_preds[i]) == i))
+ unreachable = 1;
+ }
+
+ /* Account for entry/exit edges. */
+ nr_edges += 2;
+
+ in_edges = (int *) xmalloc (n_basic_blocks * sizeof (int));
+ out_edges = (int *) xmalloc (n_basic_blocks * sizeof (int));
+ bzero ((char *) in_edges, n_basic_blocks * sizeof (int));
+ bzero ((char *) out_edges, n_basic_blocks * sizeof (int));
+
+ edge_table = (edge *) xmalloc ((nr_edges) * sizeof (edge));
+ bzero ((char *) edge_table, ((nr_edges) * sizeof (edge)));
+
+ nr_edges = 0;
+ for (i = 0; i < n_basic_blocks; i++)
+ for (succ = s_succs[i]; succ; succ = succ->next)
+ {
+ if (INT_LIST_VAL (succ) != EXIT_BLOCK)
+ new_edge (i, INT_LIST_VAL (succ));
+ }
+
+ /* increment by 1, since edge 0 is unused. */
+ nr_edges++;
+
+ return unreachable;
+}
+
+
+/* Record an edge in the control flow graph from SOURCE to TARGET.
+
+ In theory, this is redundant with the s_succs computed above, but
+ we have not converted all of haifa to use information from the
+ integer lists. */
+
+static void
+new_edge (source, target)
+ int source, target;
+{
+ int e, next_edge;
+ int curr_edge, fst_edge;
+
+ /* check for duplicates */
+ fst_edge = curr_edge = OUT_EDGES (source);
+ while (curr_edge)
+ {
+ if (FROM_BLOCK (curr_edge) == source
+ && TO_BLOCK (curr_edge) == target)
+ {
+ return;
+ }
+
+ curr_edge = NEXT_OUT (curr_edge);
+
+ if (fst_edge == curr_edge)
+ break;
+ }
+
+ e = ++nr_edges;
+
+ FROM_BLOCK (e) = source;
+ TO_BLOCK (e) = target;
+
+ if (OUT_EDGES (source))
+ {
+ next_edge = NEXT_OUT (OUT_EDGES (source));
+ NEXT_OUT (OUT_EDGES (source)) = e;
+ NEXT_OUT (e) = next_edge;
+ }
+ else
+ {
+ OUT_EDGES (source) = e;
+ NEXT_OUT (e) = e;
+ }
+
+ if (IN_EDGES (target))
+ {
+ next_edge = NEXT_IN (IN_EDGES (target));
+ NEXT_IN (IN_EDGES (target)) = e;
+ NEXT_IN (e) = next_edge;
+ }
+ else
+ {
+ IN_EDGES (target) = e;
+ NEXT_IN (e) = e;
+ }
+}
+
+
+/* BITSET macros for operations on the control flow graph. */
+
+/* Compute bitwise union of two bitsets. */
+#define BITSET_UNION(set1, set2, len) \
+do { register bitset tp = set1, sp = set2; \
+ register int i; \
+ for (i = 0; i < len; i++) \
+ *(tp++) |= *(sp++); } while (0)
+
+/* Compute bitwise intersection of two bitsets. */
+#define BITSET_INTER(set1, set2, len) \
+do { register bitset tp = set1, sp = set2; \
+ register int i; \
+ for (i = 0; i < len; i++) \
+ *(tp++) &= *(sp++); } while (0)
+
+/* Compute bitwise difference of two bitsets. */
+#define BITSET_DIFFER(set1, set2, len) \
+do { register bitset tp = set1, sp = set2; \
+ register int i; \
+ for (i = 0; i < len; i++) \
+ *(tp++) &= ~*(sp++); } while (0)
+
+/* Inverts every bit of bitset 'set' */
+#define BITSET_INVERT(set, len) \
+do { register bitset tmpset = set; \
+ register int i; \
+ for (i = 0; i < len; i++, tmpset++) \
+ *tmpset = ~*tmpset; } while (0)
+
+/* Turn on the index'th bit in bitset set. */
+#define BITSET_ADD(set, index, len) \
+{ \
+ if (index >= HOST_BITS_PER_WIDE_INT * len) \
+ abort (); \
+ else \
+ set[index/HOST_BITS_PER_WIDE_INT] |= \
+ 1 << (index % HOST_BITS_PER_WIDE_INT); \
+}
+
+/* Turn off the index'th bit in set. */
+#define BITSET_REMOVE(set, index, len) \
+{ \
+ if (index >= HOST_BITS_PER_WIDE_INT * len) \
+ abort (); \
+ else \
+ set[index/HOST_BITS_PER_WIDE_INT] &= \
+ ~(1 << (index%HOST_BITS_PER_WIDE_INT)); \
+}
+
+
+/* Check if the index'th bit in bitset set is on. */
+
+static char
+bitset_member (set, index, len)
+ bitset set;
+ int index, len;
+{
+ if (index >= HOST_BITS_PER_WIDE_INT * len)
+ abort ();
+ return (set[index / HOST_BITS_PER_WIDE_INT] &
+ 1 << (index % HOST_BITS_PER_WIDE_INT)) ? 1 : 0;
+}
+
+
+/* Translate a bit-set SET to a list BL of the bit-set members. */
+
+static void
+extract_bitlst (set, len, bl)
+ bitset set;
+ int len;
+ bitlst *bl;
+{
+ int i, j, offset;
+ unsigned HOST_WIDE_INT word;
+
+ /* bblst table space is reused in each call to extract_bitlst */
+ bitlst_table_last = 0;
+
+ bl->first_member = &bitlst_table[bitlst_table_last];
+ bl->nr_members = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ word = set[i];
+ offset = i * HOST_BITS_PER_WIDE_INT;
+ for (j = 0; word; j++)
+ {
+ if (word & 1)
+ {
+ bitlst_table[bitlst_table_last++] = offset;
+ (bl->nr_members)++;
+ }
+ word >>= 1;
+ ++offset;
+ }
+ }
+
+}
+
+
+/* functions for the construction of regions */
+
+/* Print the regions, for debugging purposes. Callable from debugger. */
+
+void
+debug_regions ()
+{
+ int rgn, bb;
+
+ fprintf (dump, "\n;; ------------ REGIONS ----------\n\n");
+ for (rgn = 0; rgn < nr_regions; rgn++)
+ {
+ fprintf (dump, ";;\trgn %d nr_blocks %d:\n", rgn,
+ rgn_table[rgn].rgn_nr_blocks);
+ fprintf (dump, ";;\tbb/block: ");
+
+ for (bb = 0; bb < rgn_table[rgn].rgn_nr_blocks; bb++)
+ {
+ current_blocks = RGN_BLOCKS (rgn);
+
+ if (bb != BLOCK_TO_BB (BB_TO_BLOCK (bb)))
+ abort ();
+
+ fprintf (dump, " %d/%d ", bb, BB_TO_BLOCK (bb));
+ }
+
+ fprintf (dump, "\n\n");
+ }
+}
+
+
+/* Build a single block region for each basic block in the function.
+ This allows for using the same code for interblock and basic block
+ scheduling. */
+
+static void
+find_single_block_region ()
+{
+ int i;
+
+ for (i = 0; i < n_basic_blocks; i++)
+ {
+ rgn_bb_table[i] = i;
+ RGN_NR_BLOCKS (i) = 1;
+ RGN_BLOCKS (i) = i;
+ CONTAINING_RGN (i) = i;
+ BLOCK_TO_BB (i) = 0;
+ }
+ nr_regions = n_basic_blocks;
+}
+
+
+/* Update number of blocks and the estimate for number of insns
+ in the region. Return 1 if the region is "too large" for interblock
+ scheduling (compile time considerations), otherwise return 0. */
+
+static int
+too_large (block, num_bbs, num_insns)
+ int block, *num_bbs, *num_insns;
+{
+ (*num_bbs)++;
+ (*num_insns) += (INSN_LUID (basic_block_end[block]) -
+ INSN_LUID (basic_block_head[block]));
+ if ((*num_bbs > MAX_RGN_BLOCKS) || (*num_insns > MAX_RGN_INSNS))
+ return 1;
+ else
+ return 0;
+}
+
+
+/* Update_loop_relations(blk, hdr): Check if the loop headed by max_hdr[blk]
+ is still an inner loop. Put in max_hdr[blk] the header of the most inner
+ loop containing blk. */
+#define UPDATE_LOOP_RELATIONS(blk, hdr) \
+{ \
+ if (max_hdr[blk] == -1) \
+ max_hdr[blk] = hdr; \
+ else if (dfs_nr[max_hdr[blk]] > dfs_nr[hdr]) \
+ RESET_BIT (inner, hdr); \
+ else if (dfs_nr[max_hdr[blk]] < dfs_nr[hdr]) \
+ { \
+ RESET_BIT (inner,max_hdr[blk]); \
+ max_hdr[blk] = hdr; \
+ } \
+}
+
+
+/* Find regions for interblock scheduling.
+
+ A region for scheduling can be:
+
+ * A loop-free procedure, or
+
+ * A reducible inner loop, or
+
+ * A basic block not contained in any other region.
+
+
+ ?!? In theory we could build other regions based on extended basic
+ blocks or reverse extended basic blocks. Is it worth the trouble?
+
+ Loop blocks that form a region are put into the region's block list
+ in topological order.
+
+ This procedure stores its results into the following global (ick) variables
+
+ * rgn_nr
+ * rgn_table
+ * rgn_bb_table
+ * block_to_bb
+ * containing region
+
+
+ We use dominator relationships to avoid making regions out of non-reducible
+ loops.
+
+ This procedure needs to be converted to work on pred/succ lists instead
+ of edge tables. That would simplify it somewhat. */
+
+static void
+find_rgns (s_preds, s_succs, num_preds, num_succs, dom)
+ int_list_ptr *s_preds;
+ int_list_ptr *s_succs;
+ int *num_preds;
+ int *num_succs;
+ sbitmap *dom;
+{
+ int *max_hdr, *dfs_nr, *stack, *queue, *degree;
+ char no_loops = 1;
+ int node, child, loop_head, i, head, tail;
+ int count = 0, sp, idx = 0, current_edge = out_edges[0];
+ int num_bbs, num_insns, unreachable;
+ int too_large_failure;
+
+ /* Note if an edge has been passed. */
+ sbitmap passed;
+
+ /* Note if a block is a natural loop header. */
+ sbitmap header;
+
+ /* Note if a block is an natural inner loop header. */
+ sbitmap inner;
+
+ /* Note if a block is in the block queue. */
+ sbitmap in_queue;
+
+ /* Note if a block is in the block queue. */
+ sbitmap in_stack;
+
+ /* Perform a DFS traversal of the cfg. Identify loop headers, inner loops
+ and a mapping from block to its loop header (if the block is contained
+ in a loop, else -1).
+
+ Store results in HEADER, INNER, and MAX_HDR respectively, these will
+ be used as inputs to the second traversal.
+
+ STACK, SP and DFS_NR are only used during the first traversal. */
+
+ /* Allocate and initialize variables for the first traversal. */
+ max_hdr = (int *) alloca (n_basic_blocks * sizeof (int));
+ dfs_nr = (int *) alloca (n_basic_blocks * sizeof (int));
+ bzero ((char *) dfs_nr, n_basic_blocks * sizeof (int));
+ stack = (int *) alloca (nr_edges * sizeof (int));
+
+ inner = sbitmap_alloc (n_basic_blocks);
+ sbitmap_ones (inner);
+
+ header = sbitmap_alloc (n_basic_blocks);
+ sbitmap_zero (header);
+
+ passed = sbitmap_alloc (nr_edges);
+ sbitmap_zero (passed);
+
+ in_queue = sbitmap_alloc (n_basic_blocks);
+ sbitmap_zero (in_queue);
+
+ in_stack = sbitmap_alloc (n_basic_blocks);
+ sbitmap_zero (in_stack);
+
+ for (i = 0; i < n_basic_blocks; i++)
+ max_hdr[i] = -1;
+
+ /* DFS traversal to find inner loops in the cfg. */
+
+ sp = -1;
+ while (1)
+ {
+ if (current_edge == 0 || TEST_BIT (passed, current_edge))
+ {
+ /* We have reached a leaf node or a node that was already
+ processed. Pop edges off the stack until we find
+ an edge that has not yet been processed. */
+ while (sp >= 0
+ && (current_edge == 0 || TEST_BIT (passed, current_edge)))
+ {
+ /* Pop entry off the stack. */
+ current_edge = stack[sp--];
+ node = FROM_BLOCK (current_edge);
+ child = TO_BLOCK (current_edge);
+ RESET_BIT (in_stack, child);
+ if (max_hdr[child] >= 0 && TEST_BIT (in_stack, max_hdr[child]))
+ UPDATE_LOOP_RELATIONS (node, max_hdr[child]);
+ current_edge = NEXT_OUT (current_edge);
+ }
+
+ /* See if have finished the DFS tree traversal. */
+ if (sp < 0 && TEST_BIT (passed, current_edge))
+ break;
+
+ /* Nope, continue the traversal with the popped node. */
+ continue;
+ }
+
+ /* Process a node. */
+ node = FROM_BLOCK (current_edge);
+ child = TO_BLOCK (current_edge);
+ SET_BIT (in_stack, node);
+ dfs_nr[node] = ++count;
+
+ /* If the successor is in the stack, then we've found a loop.
+ Mark the loop, if it is not a natural loop, then it will
+ be rejected during the second traversal. */
+ if (TEST_BIT (in_stack, child))
+ {
+ no_loops = 0;
+ SET_BIT (header, child);
+ UPDATE_LOOP_RELATIONS (node, child);
+ SET_BIT (passed, current_edge);
+ current_edge = NEXT_OUT (current_edge);
+ continue;
+ }
+
+ /* If the child was already visited, then there is no need to visit
+ it again. Just update the loop relationships and restart
+ with a new edge. */
+ if (dfs_nr[child])
+ {
+ if (max_hdr[child] >= 0 && TEST_BIT (in_stack, max_hdr[child]))
+ UPDATE_LOOP_RELATIONS (node, max_hdr[child]);
+ SET_BIT (passed, current_edge);
+ current_edge = NEXT_OUT (current_edge);
+ continue;
+ }
+
+ /* Push an entry on the stack and continue DFS traversal. */
+ stack[++sp] = current_edge;
+ SET_BIT (passed, current_edge);
+ current_edge = OUT_EDGES (child);
+ }
+
+ /* Another check for unreachable blocks. The earlier test in
+ is_cfg_nonregular only finds unreachable blocks that do not
+ form a loop.
+
+ The DFS traversal will mark every block that is reachable from
+ the entry node by placing a nonzero value in dfs_nr. Thus if
+ dfs_nr is zero for any block, then it must be unreachable. */
+ unreachable = 0;
+ for (i = 0; i < n_basic_blocks; i++)
+ if (dfs_nr[i] == 0)
+ {
+ unreachable = 1;
+ break;
+ }
+
+ /* Gross. To avoid wasting memory, the second pass uses the dfs_nr array
+ to hold degree counts. */
+ degree = dfs_nr;
+
+ /* Compute the in-degree of every block in the graph */
+ for (i = 0; i < n_basic_blocks; i++)
+ degree[i] = num_preds[i];
+
+ /* Do not perform region scheduling if there are any unreachable
+ blocks. */
+ if (!unreachable)
+ {
+ if (no_loops)
+ SET_BIT (header, 0);
+
+ /* Second travsersal:find reducible inner loops and topologically sort
+ block of each region. */
+
+ queue = (int *) alloca (n_basic_blocks * sizeof (int));
+
+ /* Find blocks which are inner loop headers. We still have non-reducible
+ loops to consider at this point. */
+ for (i = 0; i < n_basic_blocks; i++)
+ {
+ if (TEST_BIT (header, i) && TEST_BIT (inner, i))
+ {
+ int_list_ptr ps;
+ int j;
+
+ /* Now check that the loop is reducible. We do this separate
+ from finding inner loops so that we do not find a reducible
+ loop which contains an inner non-reducible loop.
+
+ A simple way to find reducible/natrual loops is to verify
+ that each block in the loop is dominated by the loop
+ header.
+
+ If there exists a block that is not dominated by the loop
+ header, then the block is reachable from outside the loop
+ and thus the loop is not a natural loop. */
+ for (j = 0; j < n_basic_blocks; j++)
+ {
+ /* First identify blocks in the loop, except for the loop
+ entry block. */
+ if (i == max_hdr[j] && i != j)
+ {
+ /* Now verify that the block is dominated by the loop
+ header. */
+ if (!TEST_BIT (dom[j], i))
+ break;
+ }
+ }
+
+ /* If we exited the loop early, then I is the header of a non
+ reducible loop and we should quit processing it now. */
+ if (j != n_basic_blocks)
+ continue;
+
+ /* I is a header of an inner loop, or block 0 in a subroutine
+ with no loops at all. */
+ head = tail = -1;
+ too_large_failure = 0;
+ loop_head = max_hdr[i];
+
+ /* Decrease degree of all I's successors for topological
+ ordering. */
+ for (ps = s_succs[i]; ps; ps = ps->next)
+ if (INT_LIST_VAL (ps) != EXIT_BLOCK
+ && INT_LIST_VAL (ps) != ENTRY_BLOCK)
+ --degree[INT_LIST_VAL(ps)];
+
+ /* Estimate # insns, and count # blocks in the region. */
+ num_bbs = 1;
+ num_insns = (INSN_LUID (basic_block_end[i])
+ - INSN_LUID (basic_block_head[i]));
+
+
+ /* Find all loop latches (blocks which back edges to the loop
+ header) or all the leaf blocks in the cfg has no loops.
+
+ Place those blocks into the queue. */
+ if (no_loops)
+ {
+ for (j = 0; j < n_basic_blocks; j++)
+ /* Leaf nodes have only a single successor which must
+ be EXIT_BLOCK. */
+ if (num_succs[j] == 1
+ && INT_LIST_VAL (s_succs[j]) == EXIT_BLOCK)
+ {
+ queue[++tail] = j;
+ SET_BIT (in_queue, j);
+
+ if (too_large (j, &num_bbs, &num_insns))
+ {
+ too_large_failure = 1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ int_list_ptr ps;
+
+ for (ps = s_preds[i]; ps; ps = ps->next)
+ {
+ node = INT_LIST_VAL (ps);
+
+ if (node == ENTRY_BLOCK || node == EXIT_BLOCK)
+ continue;
+
+ if (max_hdr[node] == loop_head && node != i)
+ {
+ /* This is a loop latch. */
+ queue[++tail] = node;
+ SET_BIT (in_queue, node);
+
+ if (too_large (node, &num_bbs, &num_insns))
+ {
+ too_large_failure = 1;
+ break;
+ }
+ }
+
+ }
+ }
+
+ /* Now add all the blocks in the loop to the queue.
+
+ We know the loop is a natural loop; however the algorithm
+ above will not always mark certain blocks as being in the
+ loop. Consider:
+ node children
+ a b,c
+ b c
+ c a,d
+ d b
+
+
+ The algorithm in the DFS traversal may not mark B & D as part
+ of the loop (ie they will not have max_hdr set to A).
+
+ We know they can not be loop latches (else they would have
+ had max_hdr set since they'd have a backedge to a dominator
+ block). So we don't need them on the initial queue.
+
+ We know they are part of the loop because they are dominated
+ by the loop header and can be reached by a backwards walk of
+ the edges starting with nodes on the initial queue.
+
+ It is safe and desirable to include those nodes in the
+ loop/scheduling region. To do so we would need to decrease
+ the degree of a node if it is the target of a backedge
+ within the loop itself as the node is placed in the queue.
+
+ We do not do this because I'm not sure that the actual
+ scheduling code will properly handle this case. ?!? */
+
+ while (head < tail && !too_large_failure)
+ {
+ int_list_ptr ps;
+ child = queue[++head];
+
+ for (ps = s_preds[child]; ps; ps = ps->next)
+ {
+ node = INT_LIST_VAL (ps);
+
+ /* See discussion above about nodes not marked as in
+ this loop during the initial DFS traversal. */
+ if (node == ENTRY_BLOCK || node == EXIT_BLOCK
+ || max_hdr[node] != loop_head)
+ {
+ tail = -1;
+ break;
+ }
+ else if (!TEST_BIT (in_queue, node) && node != i)
+ {
+ queue[++tail] = node;
+ SET_BIT (in_queue, node);
+
+ if (too_large (node, &num_bbs, &num_insns))
+ {
+ too_large_failure = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (tail >= 0 && !too_large_failure)
+ {
+ /* Place the loop header into list of region blocks. */
+ degree[i] = -1;
+ rgn_bb_table[idx] = i;
+ RGN_NR_BLOCKS (nr_regions) = num_bbs;
+ RGN_BLOCKS (nr_regions) = idx++;
+ CONTAINING_RGN (i) = nr_regions;
+ BLOCK_TO_BB (i) = count = 0;
+
+ /* Remove blocks from queue[] when their in degree becomes
+ zero. Repeat until no blocks are left on the list. This
+ produces a topological list of blocks in the region. */
+ while (tail >= 0)
+ {
+ int_list_ptr ps;
+
+ if (head < 0)
+ head = tail;
+ child = queue[head];
+ if (degree[child] == 0)
+ {
+ degree[child] = -1;
+ rgn_bb_table[idx++] = child;
+ BLOCK_TO_BB (child) = ++count;
+ CONTAINING_RGN (child) = nr_regions;
+ queue[head] = queue[tail--];
+
+ for (ps = s_succs[child]; ps; ps = ps->next)
+ if (INT_LIST_VAL (ps) != ENTRY_BLOCK
+ && INT_LIST_VAL (ps) != EXIT_BLOCK)
+ --degree[INT_LIST_VAL (ps)];
+ }
+ else
+ --head;
+ }
+ ++nr_regions;
+ }
+ }
+ }
+ }
+
+ /* Any block that did not end up in a region is placed into a region
+ by itself. */
+ for (i = 0; i < n_basic_blocks; i++)
+ if (degree[i] >= 0)
+ {
+ rgn_bb_table[idx] = i;
+ RGN_NR_BLOCKS (nr_regions) = 1;
+ RGN_BLOCKS (nr_regions) = idx++;
+ CONTAINING_RGN (i) = nr_regions++;
+ BLOCK_TO_BB (i) = 0;
+ }
+
+ free (passed);
+ free (header);
+ free (inner);
+ free (in_queue);
+ free (in_stack);
+}
+
+
+/* functions for regions scheduling information */
+
+/* Compute dominators, probability, and potential-split-edges of bb.
+ Assume that these values were already computed for bb's predecessors. */
+
+static void
+compute_dom_prob_ps (bb)
+ int bb;
+{
+ int nxt_in_edge, fst_in_edge, pred;
+ int fst_out_edge, nxt_out_edge, nr_out_edges, nr_rgn_out_edges;
+
+ prob[bb] = 0.0;
+ if (IS_RGN_ENTRY (bb))
+ {
+ BITSET_ADD (dom[bb], 0, bbset_size);
+ prob[bb] = 1.0;
+ return;
+ }
+
+ fst_in_edge = nxt_in_edge = IN_EDGES (BB_TO_BLOCK (bb));
+
+ /* intialize dom[bb] to '111..1' */
+ BITSET_INVERT (dom[bb], bbset_size);
+
+ do
+ {
+ pred = FROM_BLOCK (nxt_in_edge);
+ BITSET_INTER (dom[bb], dom[BLOCK_TO_BB (pred)], bbset_size);
+
+ BITSET_UNION (ancestor_edges[bb], ancestor_edges[BLOCK_TO_BB (pred)],
+ edgeset_size);
+
+ BITSET_ADD (ancestor_edges[bb], EDGE_TO_BIT (nxt_in_edge), edgeset_size);
+
+ nr_out_edges = 1;
+ nr_rgn_out_edges = 0;
+ fst_out_edge = OUT_EDGES (pred);
+ nxt_out_edge = NEXT_OUT (fst_out_edge);
+ BITSET_UNION (pot_split[bb], pot_split[BLOCK_TO_BB (pred)],
+ edgeset_size);
+
+ BITSET_ADD (pot_split[bb], EDGE_TO_BIT (fst_out_edge), edgeset_size);
+
+ /* the successor doesn't belong the region? */
+ if (CONTAINING_RGN (TO_BLOCK (fst_out_edge)) !=
+ CONTAINING_RGN (BB_TO_BLOCK (bb)))
+ ++nr_rgn_out_edges;
+
+ while (fst_out_edge != nxt_out_edge)
+ {
+ ++nr_out_edges;
+ /* the successor doesn't belong the region? */
+ if (CONTAINING_RGN (TO_BLOCK (nxt_out_edge)) !=
+ CONTAINING_RGN (BB_TO_BLOCK (bb)))
+ ++nr_rgn_out_edges;
+ BITSET_ADD (pot_split[bb], EDGE_TO_BIT (nxt_out_edge), edgeset_size);
+ nxt_out_edge = NEXT_OUT (nxt_out_edge);
+
+ }
+
+ /* now nr_rgn_out_edges is the number of region-exit edges from pred,
+ and nr_out_edges will be the number of pred out edges not leaving
+ the region. */
+ nr_out_edges -= nr_rgn_out_edges;
+ if (nr_rgn_out_edges > 0)
+ prob[bb] += 0.9 * prob[BLOCK_TO_BB (pred)] / nr_out_edges;
+ else
+ prob[bb] += prob[BLOCK_TO_BB (pred)] / nr_out_edges;
+ nxt_in_edge = NEXT_IN (nxt_in_edge);
+ }
+ while (fst_in_edge != nxt_in_edge);
+
+ BITSET_ADD (dom[bb], bb, bbset_size);
+ BITSET_DIFFER (pot_split[bb], ancestor_edges[bb], edgeset_size);
+
+ if (sched_verbose >= 2)
+ fprintf (dump, ";; bb_prob(%d, %d) = %3d\n", bb, BB_TO_BLOCK (bb), (int) (100.0 * prob[bb]));
+} /* compute_dom_prob_ps */
+
+/* functions for target info */
+
+/* Compute in BL the list of split-edges of bb_src relatively to bb_trg.
+ Note that bb_trg dominates bb_src. */
+
+static void
+split_edges (bb_src, bb_trg, bl)
+ int bb_src;
+ int bb_trg;
+ edgelst *bl;
+{
+ int es = edgeset_size;
+ edgeset src = (edgeset) alloca (es * sizeof (HOST_WIDE_INT));
+
+ while (es--)
+ src[es] = (pot_split[bb_src])[es];
+ BITSET_DIFFER (src, pot_split[bb_trg], edgeset_size);
+ extract_bitlst (src, edgeset_size, bl);
+}
+
+
+/* Find the valid candidate-source-blocks for the target block TRG, compute
+ their probability, and check if they are speculative or not.
+ For speculative sources, compute their update-blocks and split-blocks. */
+
+static void
+compute_trg_info (trg)
+ int trg;
+{
+ register candidate *sp;
+ edgelst el;
+ int check_block, update_idx;
+ int i, j, k, fst_edge, nxt_edge;
+
+ /* define some of the fields for the target bb as well */
+ sp = candidate_table + trg;
+ sp->is_valid = 1;
+ sp->is_speculative = 0;
+ sp->src_prob = 100;
+
+ for (i = trg + 1; i < current_nr_blocks; i++)
+ {
+ sp = candidate_table + i;
+
+ sp->is_valid = IS_DOMINATED (i, trg);
+ if (sp->is_valid)
+ {
+ sp->src_prob = GET_SRC_PROB (i, trg);
+ sp->is_valid = (sp->src_prob >= MIN_PROBABILITY);
+ }
+
+ if (sp->is_valid)
+ {
+ split_edges (i, trg, &el);
+ sp->is_speculative = (el.nr_members) ? 1 : 0;
+ if (sp->is_speculative && !flag_schedule_speculative)
+ sp->is_valid = 0;
+ }
+
+ if (sp->is_valid)
+ {
+ sp->split_bbs.first_member = &bblst_table[bblst_last];
+ sp->split_bbs.nr_members = el.nr_members;
+ for (j = 0; j < el.nr_members; bblst_last++, j++)
+ bblst_table[bblst_last] =
+ TO_BLOCK (rgn_edges[el.first_member[j]]);
+ sp->update_bbs.first_member = &bblst_table[bblst_last];
+ update_idx = 0;
+ for (j = 0; j < el.nr_members; j++)
+ {
+ check_block = FROM_BLOCK (rgn_edges[el.first_member[j]]);
+ fst_edge = nxt_edge = OUT_EDGES (check_block);
+ do
+ {
+ for (k = 0; k < el.nr_members; k++)
+ if (EDGE_TO_BIT (nxt_edge) == el.first_member[k])
+ break;
+
+ if (k >= el.nr_members)
+ {
+ bblst_table[bblst_last++] = TO_BLOCK (nxt_edge);
+ update_idx++;
+ }
+
+ nxt_edge = NEXT_OUT (nxt_edge);
+ }
+ while (fst_edge != nxt_edge);
+ }
+ sp->update_bbs.nr_members = update_idx;
+
+ }
+ else
+ {
+ sp->split_bbs.nr_members = sp->update_bbs.nr_members = 0;
+
+ sp->is_speculative = 0;
+ sp->src_prob = 0;
+ }
+ }
+} /* compute_trg_info */
+
+
+/* Print candidates info, for debugging purposes. Callable from debugger. */
+
+void
+debug_candidate (i)
+ int i;
+{
+ if (!candidate_table[i].is_valid)
+ return;
+
+ if (candidate_table[i].is_speculative)
+ {
+ int j;
+ fprintf (dump, "src b %d bb %d speculative \n", BB_TO_BLOCK (i), i);
+
+ fprintf (dump, "split path: ");
+ for (j = 0; j < candidate_table[i].split_bbs.nr_members; j++)
+ {
+ int b = candidate_table[i].split_bbs.first_member[j];
+
+ fprintf (dump, " %d ", b);
+ }
+ fprintf (dump, "\n");
+
+ fprintf (dump, "update path: ");
+ for (j = 0; j < candidate_table[i].update_bbs.nr_members; j++)
+ {
+ int b = candidate_table[i].update_bbs.first_member[j];
+
+ fprintf (dump, " %d ", b);
+ }
+ fprintf (dump, "\n");
+ }
+ else
+ {
+ fprintf (dump, " src %d equivalent\n", BB_TO_BLOCK (i));
+ }
+}
+
+
+/* Print candidates info, for debugging purposes. Callable from debugger. */
+
+void
+debug_candidates (trg)
+ int trg;
+{
+ int i;
+
+ fprintf (dump, "----------- candidate table: target: b=%d bb=%d ---\n",
+ BB_TO_BLOCK (trg), trg);
+ for (i = trg + 1; i < current_nr_blocks; i++)
+ debug_candidate (i);
+}
+
+
+/* functions for speculative scheduing */
+
+/* Return 0 if x is a set of a register alive in the beginning of one
+ of the split-blocks of src, otherwise return 1. */
+
+static int
+check_live_1 (src, x)
+ int src;
+ rtx x;
+{
+ register int i;
+ register int regno;
+ register rtx reg = SET_DEST (x);
+
+ if (reg == 0)
+ return 1;
+
+ while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
+ || GET_CODE (reg) == SIGN_EXTRACT
+ || GET_CODE (reg) == STRICT_LOW_PART)
+ reg = XEXP (reg, 0);
+
+ if (GET_CODE (reg) != REG)
+ return 1;
+
+ regno = REGNO (reg);
+
+ if (regno < FIRST_PSEUDO_REGISTER && global_regs[regno])
+ {
+ /* Global registers are assumed live */
+ return 0;
+ }
+ else
+ {
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ /* check for hard registers */
+ int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+ while (--j >= 0)
+ {
+ for (i = 0; i < candidate_table[src].split_bbs.nr_members; i++)
+ {
+ int b = candidate_table[src].split_bbs.first_member[i];
+
+ if (REGNO_REG_SET_P (basic_block_live_at_start[b], regno + j))
+ {
+ return 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* check for psuedo registers */
+ for (i = 0; i < candidate_table[src].split_bbs.nr_members; i++)
+ {
+ int b = candidate_table[src].split_bbs.first_member[i];
+
+ if (REGNO_REG_SET_P (basic_block_live_at_start[b], regno))
+ {
+ return 0;
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+/* If x is a set of a register R, mark that R is alive in the beginning
+ of every update-block of src. */
+
+static void
+update_live_1 (src, x)
+ int src;
+ rtx x;
+{
+ register int i;
+ register int regno;
+ register rtx reg = SET_DEST (x);
+
+ if (reg == 0)
+ return;
+
+ while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == ZERO_EXTRACT
+ || GET_CODE (reg) == SIGN_EXTRACT
+ || GET_CODE (reg) == STRICT_LOW_PART)
+ reg = XEXP (reg, 0);
+
+ if (GET_CODE (reg) != REG)
+ return;
+
+ /* Global registers are always live, so the code below does not apply
+ to them. */
+
+ regno = REGNO (reg);
+
+ if (regno >= FIRST_PSEUDO_REGISTER || !global_regs[regno])
+ {
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+ while (--j >= 0)
+ {
+ for (i = 0; i < candidate_table[src].update_bbs.nr_members; i++)
+ {
+ int b = candidate_table[src].update_bbs.first_member[i];
+
+ SET_REGNO_REG_SET (basic_block_live_at_start[b], regno + j);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < candidate_table[src].update_bbs.nr_members; i++)
+ {
+ int b = candidate_table[src].update_bbs.first_member[i];
+
+ SET_REGNO_REG_SET (basic_block_live_at_start[b], regno);
+ }
+ }
+ }
+}
+
+
+/* Return 1 if insn can be speculatively moved from block src to trg,
+ otherwise return 0. Called before first insertion of insn to
+ ready-list or before the scheduling. */
+
+static int
+check_live (insn, src)
+ rtx insn;
+ int src;
+{
+ /* find the registers set by instruction */
+ if (GET_CODE (PATTERN (insn)) == SET
+ || GET_CODE (PATTERN (insn)) == CLOBBER)
+ return check_live_1 (src, PATTERN (insn));
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ {
+ int j;
+ for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
+ if ((GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
+ || GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == CLOBBER)
+ && !check_live_1 (src, XVECEXP (PATTERN (insn), 0, j)))
+ return 0;
+
+ return 1;
+ }
+
+ return 1;
+}
+
+
+/* Update the live registers info after insn was moved speculatively from
+ block src to trg. */
+
+static void
+update_live (insn, src)
+ rtx insn;
+ int src;
+{
+ /* find the registers set by instruction */
+ if (GET_CODE (PATTERN (insn)) == SET
+ || GET_CODE (PATTERN (insn)) == CLOBBER)
+ update_live_1 (src, PATTERN (insn));
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ {
+ int j;
+ for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
+ if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
+ || GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == CLOBBER)
+ update_live_1 (src, XVECEXP (PATTERN (insn), 0, j));
+ }
+}
+
+/* Exception Free Loads:
+
+ We define five classes of speculative loads: IFREE, IRISKY,
+ PFREE, PRISKY, and MFREE.
+
+ IFREE loads are loads that are proved to be exception-free, just
+ by examining the load insn. Examples for such loads are loads
+ from TOC and loads of global data.
+
+ IRISKY loads are loads that are proved to be exception-risky,
+ just by examining the load insn. Examples for such loads are
+ volatile loads and loads from shared memory.
+
+ PFREE loads are loads for which we can prove, by examining other
+ insns, that they are exception-free. Currently, this class consists
+ of loads for which we are able to find a "similar load", either in
+ the target block, or, if only one split-block exists, in that split
+ block. Load2 is similar to load1 if both have same single base
+ register. We identify only part of the similar loads, by finding
+ an insn upon which both load1 and load2 have a DEF-USE dependence.
+
+ PRISKY loads are loads for which we can prove, by examining other
+ insns, that they are exception-risky. Currently we have two proofs for
+ such loads. The first proof detects loads that are probably guarded by a
+ test on the memory address. This proof is based on the
+ backward and forward data dependence information for the region.
+ Let load-insn be the examined load.
+ Load-insn is PRISKY iff ALL the following hold:
+
+ - insn1 is not in the same block as load-insn
+ - there is a DEF-USE dependence chain (insn1, ..., load-insn)
+ - test-insn is either a compare or a branch, not in the same block as load-insn
+ - load-insn is reachable from test-insn
+ - there is a DEF-USE dependence chain (insn1, ..., test-insn)
+
+ This proof might fail when the compare and the load are fed
+ by an insn not in the region. To solve this, we will add to this
+ group all loads that have no input DEF-USE dependence.
+
+ The second proof detects loads that are directly or indirectly
+ fed by a speculative load. This proof is affected by the
+ scheduling process. We will use the flag fed_by_spec_load.
+ Initially, all insns have this flag reset. After a speculative
+ motion of an insn, if insn is either a load, or marked as
+ fed_by_spec_load, we will also mark as fed_by_spec_load every
+ insn1 for which a DEF-USE dependence (insn, insn1) exists. A
+ load which is fed_by_spec_load is also PRISKY.
+
+ MFREE (maybe-free) loads are all the remaining loads. They may be
+ exception-free, but we cannot prove it.
+
+ Now, all loads in IFREE and PFREE classes are considered
+ exception-free, while all loads in IRISKY and PRISKY classes are
+ considered exception-risky. As for loads in the MFREE class,
+ these are considered either exception-free or exception-risky,
+ depending on whether we are pessimistic or optimistic. We have
+ to take the pessimistic approach to assure the safety of
+ speculative scheduling, but we can take the optimistic approach
+ by invoking the -fsched_spec_load_dangerous option. */
+
+enum INSN_TRAP_CLASS
+{
+ TRAP_FREE = 0, IFREE = 1, PFREE_CANDIDATE = 2,
+ PRISKY_CANDIDATE = 3, IRISKY = 4, TRAP_RISKY = 5
+};
+
+#define WORST_CLASS(class1, class2) \
+((class1 > class2) ? class1 : class2)
+
+/* Indexed by INSN_UID, and set if there's DEF-USE dependence between */
+/* some speculatively moved load insn and this one. */
+char *fed_by_spec_load;
+char *is_load_insn;
+
+/* Non-zero if block bb_to is equal to, or reachable from block bb_from. */
+#define IS_REACHABLE(bb_from, bb_to) \
+(bb_from == bb_to \
+ || IS_RGN_ENTRY (bb_from) \
+ || (bitset_member (ancestor_edges[bb_to], \
+ EDGE_TO_BIT (IN_EDGES (BB_TO_BLOCK (bb_from))), \
+ edgeset_size)))
+#define FED_BY_SPEC_LOAD(insn) (fed_by_spec_load[INSN_UID (insn)])
+#define IS_LOAD_INSN(insn) (is_load_insn[INSN_UID (insn)])
+
+/* Non-zero iff the address is comprised from at most 1 register */
+#define CONST_BASED_ADDRESS_P(x) \
+ (GET_CODE (x) == REG \
+ || ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS \
+ || (GET_CODE (x) == LO_SUM)) \
+ && (GET_CODE (XEXP (x, 0)) == CONST_INT \
+ || GET_CODE (XEXP (x, 1)) == CONST_INT)))
+
+/* Turns on the fed_by_spec_load flag for insns fed by load_insn. */
+
+static void
+set_spec_fed (load_insn)
+ rtx load_insn;
+{
+ rtx link;
+
+ for (link = INSN_DEPEND (load_insn); link; link = XEXP (link, 1))
+ if (GET_MODE (link) == VOIDmode)
+ FED_BY_SPEC_LOAD (XEXP (link, 0)) = 1;
+} /* set_spec_fed */
+
+/* On the path from the insn to load_insn_bb, find a conditional branch */
+/* depending on insn, that guards the speculative load. */
+
+static int
+find_conditional_protection (insn, load_insn_bb)
+ rtx insn;
+ int load_insn_bb;
+{
+ rtx link;
+
+ /* iterate through DEF-USE forward dependences */
+ for (link = INSN_DEPEND (insn); link; link = XEXP (link, 1))
+ {
+ rtx next = XEXP (link, 0);
+ if ((CONTAINING_RGN (INSN_BLOCK (next)) ==
+ CONTAINING_RGN (BB_TO_BLOCK (load_insn_bb)))
+ && IS_REACHABLE (INSN_BB (next), load_insn_bb)
+ && load_insn_bb != INSN_BB (next)
+ && GET_MODE (link) == VOIDmode
+ && (GET_CODE (next) == JUMP_INSN
+ || find_conditional_protection (next, load_insn_bb)))
+ return 1;
+ }
+ return 0;
+} /* find_conditional_protection */
+
+/* Returns 1 if the same insn1 that participates in the computation
+ of load_insn's address is feeding a conditional branch that is
+ guarding on load_insn. This is true if we find a the two DEF-USE
+ chains:
+ insn1 -> ... -> conditional-branch
+ insn1 -> ... -> load_insn,
+ and if a flow path exist:
+ insn1 -> ... -> conditional-branch -> ... -> load_insn,
+ and if insn1 is on the path
+ region-entry -> ... -> bb_trg -> ... load_insn.
+
+ Locate insn1 by climbing on LOG_LINKS from load_insn.
+ Locate the branch by following INSN_DEPEND from insn1. */
+
+static int
+is_conditionally_protected (load_insn, bb_src, bb_trg)
+ rtx load_insn;
+ int bb_src, bb_trg;
+{
+ rtx link;
+
+ for (link = LOG_LINKS (load_insn); link; link = XEXP (link, 1))
+ {
+ rtx insn1 = XEXP (link, 0);
+
+ /* must be a DEF-USE dependence upon non-branch */
+ if (GET_MODE (link) != VOIDmode
+ || GET_CODE (insn1) == JUMP_INSN)
+ continue;
+
+ /* must exist a path: region-entry -> ... -> bb_trg -> ... load_insn */
+ if (INSN_BB (insn1) == bb_src
+ || (CONTAINING_RGN (INSN_BLOCK (insn1))
+ != CONTAINING_RGN (BB_TO_BLOCK (bb_src)))
+ || (!IS_REACHABLE (bb_trg, INSN_BB (insn1))
+ && !IS_REACHABLE (INSN_BB (insn1), bb_trg)))
+ continue;
+
+ /* now search for the conditional-branch */
+ if (find_conditional_protection (insn1, bb_src))
+ return 1;
+
+ /* recursive step: search another insn1, "above" current insn1. */
+ return is_conditionally_protected (insn1, bb_src, bb_trg);
+ }
+
+ /* the chain does not exsist */
+ return 0;
+} /* is_conditionally_protected */
+
+/* Returns 1 if a clue for "similar load" 'insn2' is found, and hence
+ load_insn can move speculatively from bb_src to bb_trg. All the
+ following must hold:
+
+ (1) both loads have 1 base register (PFREE_CANDIDATEs).
+ (2) load_insn and load1 have a def-use dependence upon
+ the same insn 'insn1'.
+ (3) either load2 is in bb_trg, or:
+ - there's only one split-block, and
+ - load1 is on the escape path, and
+
+ From all these we can conclude that the two loads access memory
+ addresses that differ at most by a constant, and hence if moving
+ load_insn would cause an exception, it would have been caused by
+ load2 anyhow. */
+
+static int
+is_pfree (load_insn, bb_src, bb_trg)
+ rtx load_insn;
+ int bb_src, bb_trg;
+{
+ rtx back_link;
+ register candidate *candp = candidate_table + bb_src;
+
+ if (candp->split_bbs.nr_members != 1)
+ /* must have exactly one escape block */
+ return 0;
+
+ for (back_link = LOG_LINKS (load_insn);
+ back_link; back_link = XEXP (back_link, 1))
+ {
+ rtx insn1 = XEXP (back_link, 0);
+
+ if (GET_MODE (back_link) == VOIDmode)
+ {
+ /* found a DEF-USE dependence (insn1, load_insn) */
+ rtx fore_link;
+
+ for (fore_link = INSN_DEPEND (insn1);
+ fore_link; fore_link = XEXP (fore_link, 1))
+ {
+ rtx insn2 = XEXP (fore_link, 0);
+ if (GET_MODE (fore_link) == VOIDmode)
+ {
+ /* found a DEF-USE dependence (insn1, insn2) */
+ if (haifa_classify_insn (insn2) != PFREE_CANDIDATE)
+ /* insn2 not guaranteed to be a 1 base reg load */
+ continue;
+
+ if (INSN_BB (insn2) == bb_trg)
+ /* insn2 is the similar load, in the target block */
+ return 1;
+
+ if (*(candp->split_bbs.first_member) == INSN_BLOCK (insn2))
+ /* insn2 is a similar load, in a split-block */
+ return 1;
+ }
+ }
+ }
+ }
+
+ /* couldn't find a similar load */
+ return 0;
+} /* is_pfree */
+
+/* Returns a class that insn with GET_DEST(insn)=x may belong to,
+ as found by analyzing insn's expression. */
+
+static int
+may_trap_exp (x, is_store)
+ rtx x;
+ int is_store;
+{
+ enum rtx_code code;
+
+ if (x == 0)
+ return TRAP_FREE;
+ code = GET_CODE (x);
+ if (is_store)
+ {
+ if (code == MEM)
+ return TRAP_RISKY;
+ else
+ return TRAP_FREE;
+ }
+ if (code == MEM)
+ {
+ /* The insn uses memory */
+ /* a volatile load */
+ if (MEM_VOLATILE_P (x))
+ return IRISKY;
+ /* an exception-free load */
+ if (!may_trap_p (x))
+ return IFREE;
+ /* a load with 1 base register, to be further checked */
+ if (CONST_BASED_ADDRESS_P (XEXP (x, 0)))
+ return PFREE_CANDIDATE;
+ /* no info on the load, to be further checked */
+ return PRISKY_CANDIDATE;
+ }
+ else
+ {
+ char *fmt;
+ int i, insn_class = TRAP_FREE;
+
+ /* neither store nor load, check if it may cause a trap */
+ if (may_trap_p (x))
+ return TRAP_RISKY;
+ /* recursive step: walk the insn... */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ int tmp_class = may_trap_exp (XEXP (x, i), is_store);
+ insn_class = WORST_CLASS (insn_class, tmp_class);
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ {
+ int tmp_class = may_trap_exp (XVECEXP (x, i, j), is_store);
+ insn_class = WORST_CLASS (insn_class, tmp_class);
+ if (insn_class == TRAP_RISKY || insn_class == IRISKY)
+ break;
+ }
+ }
+ if (insn_class == TRAP_RISKY || insn_class == IRISKY)
+ break;
+ }
+ return insn_class;
+ }
+} /* may_trap_exp */
+
+
+/* Classifies insn for the purpose of verifying that it can be
+ moved speculatively, by examining it's patterns, returning:
+ TRAP_RISKY: store, or risky non-load insn (e.g. division by variable).
+ TRAP_FREE: non-load insn.
+ IFREE: load from a globaly safe location.
+ IRISKY: volatile load.
+ PFREE_CANDIDATE, PRISKY_CANDIDATE: load that need to be checked for
+ being either PFREE or PRISKY. */
+
+static int
+haifa_classify_insn (insn)
+ rtx insn;
+{
+ rtx pat = PATTERN (insn);
+ int tmp_class = TRAP_FREE;
+ int insn_class = TRAP_FREE;
+ enum rtx_code code;
+
+ if (GET_CODE (pat) == PARALLEL)
+ {
+ int i, len = XVECLEN (pat, 0);
+
+ for (i = len - 1; i >= 0; i--)
+ {
+ code = GET_CODE (XVECEXP (pat, 0, i));
+ switch (code)
+ {
+ case CLOBBER:
+ /* test if it is a 'store' */
+ tmp_class = may_trap_exp (XEXP (XVECEXP (pat, 0, i), 0), 1);
+ break;
+ case SET:
+ /* test if it is a store */
+ tmp_class = may_trap_exp (SET_DEST (XVECEXP (pat, 0, i)), 1);
+ if (tmp_class == TRAP_RISKY)
+ break;
+ /* test if it is a load */
+ tmp_class =
+ WORST_CLASS (tmp_class,
+ may_trap_exp (SET_SRC (XVECEXP (pat, 0, i)), 0));
+ break;
+ case TRAP_IF:
+ tmp_class = TRAP_RISKY;
+ break;
+ default:;
+ }
+ insn_class = WORST_CLASS (insn_class, tmp_class);
+ if (insn_class == TRAP_RISKY || insn_class == IRISKY)
+ break;
+ }
+ }
+ else
+ {
+ code = GET_CODE (pat);
+ switch (code)
+ {
+ case CLOBBER:
+ /* test if it is a 'store' */
+ tmp_class = may_trap_exp (XEXP (pat, 0), 1);
+ break;
+ case SET:
+ /* test if it is a store */
+ tmp_class = may_trap_exp (SET_DEST (pat), 1);
+ if (tmp_class == TRAP_RISKY)
+ break;
+ /* test if it is a load */
+ tmp_class =
+ WORST_CLASS (tmp_class,
+ may_trap_exp (SET_SRC (pat), 0));
+ break;
+ case TRAP_IF:
+ tmp_class = TRAP_RISKY;
+ break;
+ default:;
+ }
+ insn_class = tmp_class;
+ }
+
+ return insn_class;
+
+} /* haifa_classify_insn */
+
+/* Return 1 if load_insn is prisky (i.e. if load_insn is fed by
+ a load moved speculatively, or if load_insn is protected by
+ a compare on load_insn's address). */
+
+static int
+is_prisky (load_insn, bb_src, bb_trg)
+ rtx load_insn;
+ int bb_src, bb_trg;
+{
+ if (FED_BY_SPEC_LOAD (load_insn))
+ return 1;
+
+ if (LOG_LINKS (load_insn) == NULL)
+ /* dependence may 'hide' out of the region. */
+ return 1;
+
+ if (is_conditionally_protected (load_insn, bb_src, bb_trg))
+ return 1;
+
+ return 0;
+} /* is_prisky */
+
+/* Insn is a candidate to be moved speculatively from bb_src to bb_trg.
+ Return 1 if insn is exception-free (and the motion is valid)
+ and 0 otherwise. */
+
+static int
+is_exception_free (insn, bb_src, bb_trg)
+ rtx insn;
+ int bb_src, bb_trg;
+{
+ int insn_class = haifa_classify_insn (insn);
+
+ /* handle non-load insns */
+ switch (insn_class)
+ {
+ case TRAP_FREE:
+ return 1;
+ case TRAP_RISKY:
+ return 0;
+ default:;
+ }
+
+ /* handle loads */
+ if (!flag_schedule_speculative_load)
+ return 0;
+ IS_LOAD_INSN (insn) = 1;
+ switch (insn_class)
+ {
+ case IFREE:
+ return (1);
+ case IRISKY:
+ return 0;
+ case PFREE_CANDIDATE:
+ if (is_pfree (insn, bb_src, bb_trg))
+ return 1;
+ /* don't 'break' here: PFREE-candidate is also PRISKY-candidate */
+ case PRISKY_CANDIDATE:
+ if (!flag_schedule_speculative_load_dangerous
+ || is_prisky (insn, bb_src, bb_trg))
+ return 0;
+ break;
+ default:;
+ }
+
+ return flag_schedule_speculative_load_dangerous;
+} /* is_exception_free */
+
+
+/* Process an insn's memory dependencies. There are four kinds of
+ dependencies:
+
+ (0) read dependence: read follows read
+ (1) true dependence: read follows write
+ (2) anti dependence: write follows read
+ (3) output dependence: write follows write
+
+ We are careful to build only dependencies which actually exist, and
+ use transitivity to avoid building too many links. */
+
+/* Return the INSN_LIST containing INSN in LIST, or NULL
+ if LIST does not contain INSN. */
+
+HAIFA_INLINE static rtx
+find_insn_list (insn, list)
+ rtx insn;
+ rtx list;
+{
+ while (list)
+ {
+ if (XEXP (list, 0) == insn)
+ return list;
+ list = XEXP (list, 1);
+ }
+ return 0;
+}
+
+
+/* Return 1 if the pair (insn, x) is found in (LIST, LIST1), or 0 otherwise. */
+
+HAIFA_INLINE static char
+find_insn_mem_list (insn, x, list, list1)
+ rtx insn, x;
+ rtx list, list1;
+{
+ while (list)
+ {
+ if (XEXP (list, 0) == insn
+ && XEXP (list1, 0) == x)
+ return 1;
+ list = XEXP (list, 1);
+ list1 = XEXP (list1, 1);
+ }
+ return 0;
+}
+
+
+/* Compute the function units used by INSN. This caches the value
+ returned by function_units_used. A function unit is encoded as the
+ unit number if the value is non-negative and the compliment of a
+ mask if the value is negative. A function unit index is the
+ non-negative encoding. */
+
+HAIFA_INLINE static int
+insn_unit (insn)
+ rtx insn;
+{
+ register int unit = INSN_UNIT (insn);
+
+ if (unit == 0)
+ {
+ recog_memoized (insn);
+
+ /* A USE insn, or something else we don't need to understand.
+ We can't pass these directly to function_units_used because it will
+ trigger a fatal error for unrecognizable insns. */
+ if (INSN_CODE (insn) < 0)
+ unit = -1;
+ else
+ {
+ unit = function_units_used (insn);
+ /* Increment non-negative values so we can cache zero. */
+ if (unit >= 0)
+ unit++;
+ }
+ /* We only cache 16 bits of the result, so if the value is out of
+ range, don't cache it. */
+ if (FUNCTION_UNITS_SIZE < HOST_BITS_PER_SHORT
+ || unit >= 0
+ || (~unit & ((1 << (HOST_BITS_PER_SHORT - 1)) - 1)) == 0)
+ INSN_UNIT (insn) = unit;
+ }
+ return (unit > 0 ? unit - 1 : unit);
+}
+
+/* Compute the blockage range for executing INSN on UNIT. This caches
+ the value returned by the blockage_range_function for the unit.
+ These values are encoded in an int where the upper half gives the
+ minimum value and the lower half gives the maximum value. */
+
+HAIFA_INLINE static unsigned int
+blockage_range (unit, insn)
+ int unit;
+ rtx insn;
+{
+ unsigned int blockage = INSN_BLOCKAGE (insn);
+ unsigned int range;
+
+ if (UNIT_BLOCKED (blockage) != unit + 1)
+ {
+ range = function_units[unit].blockage_range_function (insn);
+ /* We only cache the blockage range for one unit and then only if
+ the values fit. */
+ if (HOST_BITS_PER_INT >= UNIT_BITS + 2 * BLOCKAGE_BITS)
+ INSN_BLOCKAGE (insn) = ENCODE_BLOCKAGE (unit + 1, range);
+ }
+ else
+ range = BLOCKAGE_RANGE (blockage);
+
+ return range;
+}
+
+/* A vector indexed by function unit instance giving the last insn to use
+ the unit. The value of the function unit instance index for unit U
+ instance I is (U + I * FUNCTION_UNITS_SIZE). */
+static rtx unit_last_insn[FUNCTION_UNITS_SIZE * MAX_MULTIPLICITY];
+
+/* A vector indexed by function unit instance giving the minimum time when
+ the unit will unblock based on the maximum blockage cost. */
+static int unit_tick[FUNCTION_UNITS_SIZE * MAX_MULTIPLICITY];
+
+/* A vector indexed by function unit number giving the number of insns
+ that remain to use the unit. */
+static int unit_n_insns[FUNCTION_UNITS_SIZE];
+
+/* Reset the function unit state to the null state. */
+
+static void
+clear_units ()
+{
+ bzero ((char *) unit_last_insn, sizeof (unit_last_insn));
+ bzero ((char *) unit_tick, sizeof (unit_tick));
+ bzero ((char *) unit_n_insns, sizeof (unit_n_insns));
+}
+
+/* Return the issue-delay of an insn */
+
+HAIFA_INLINE static int
+insn_issue_delay (insn)
+ rtx insn;
+{
+ int i, delay = 0;
+ int unit = insn_unit (insn);
+
+ /* efficiency note: in fact, we are working 'hard' to compute a
+ value that was available in md file, and is not available in
+ function_units[] structure. It would be nice to have this
+ value there, too. */
+ if (unit >= 0)
+ {
+ if (function_units[unit].blockage_range_function &&
+ function_units[unit].blockage_function)
+ delay = function_units[unit].blockage_function (insn, insn);
+ }
+ else
+ for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
+ if ((unit & 1) != 0 && function_units[i].blockage_range_function
+ && function_units[i].blockage_function)
+ delay = MAX (delay, function_units[i].blockage_function (insn, insn));
+
+ return delay;
+}
+
+/* Return the actual hazard cost of executing INSN on the unit UNIT,
+ instance INSTANCE at time CLOCK if the previous actual hazard cost
+ was COST. */
+
+HAIFA_INLINE static int
+actual_hazard_this_instance (unit, instance, insn, clock, cost)
+ int unit, instance, clock, cost;
+ rtx insn;
+{
+ int tick = unit_tick[instance]; /* issue time of the last issued insn */
+
+ if (tick - clock > cost)
+ {
+ /* The scheduler is operating forward, so unit's last insn is the
+ executing insn and INSN is the candidate insn. We want a
+ more exact measure of the blockage if we execute INSN at CLOCK
+ given when we committed the execution of the unit's last insn.
+
+ The blockage value is given by either the unit's max blockage
+ constant, blockage range function, or blockage function. Use
+ the most exact form for the given unit. */
+
+ if (function_units[unit].blockage_range_function)
+ {
+ if (function_units[unit].blockage_function)
+ tick += (function_units[unit].blockage_function
+ (unit_last_insn[instance], insn)
+ - function_units[unit].max_blockage);
+ else
+ tick += ((int) MAX_BLOCKAGE_COST (blockage_range (unit, insn))
+ - function_units[unit].max_blockage);
+ }
+ if (tick - clock > cost)
+ cost = tick - clock;
+ }
+ return cost;
+}
+
+/* Record INSN as having begun execution on the units encoded by UNIT at
+ time CLOCK. */
+
+HAIFA_INLINE static void
+schedule_unit (unit, insn, clock)
+ int unit, clock;
+ rtx insn;
+{
+ int i;
+
+ if (unit >= 0)
+ {
+ int instance = unit;
+#if MAX_MULTIPLICITY > 1
+ /* Find the first free instance of the function unit and use that
+ one. We assume that one is free. */
+ for (i = function_units[unit].multiplicity - 1; i > 0; i--)
+ {
+ if (!actual_hazard_this_instance (unit, instance, insn, clock, 0))
+ break;
+ instance += FUNCTION_UNITS_SIZE;
+ }
+#endif
+ unit_last_insn[instance] = insn;
+ unit_tick[instance] = (clock + function_units[unit].max_blockage);
+ }
+ else
+ for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
+ if ((unit & 1) != 0)
+ schedule_unit (i, insn, clock);
+}
+
+/* Return the actual hazard cost of executing INSN on the units encoded by
+ UNIT at time CLOCK if the previous actual hazard cost was COST. */
+
+HAIFA_INLINE static int
+actual_hazard (unit, insn, clock, cost)
+ int unit, clock, cost;
+ rtx insn;
+{
+ int i;
+
+ if (unit >= 0)
+ {
+ /* Find the instance of the function unit with the minimum hazard. */
+ int instance = unit;
+ int best_cost = actual_hazard_this_instance (unit, instance, insn,
+ clock, cost);
+ int this_cost;
+
+#if MAX_MULTIPLICITY > 1
+ if (best_cost > cost)
+ {
+ for (i = function_units[unit].multiplicity - 1; i > 0; i--)
+ {
+ instance += FUNCTION_UNITS_SIZE;
+ this_cost = actual_hazard_this_instance (unit, instance, insn,
+ clock, cost);
+ if (this_cost < best_cost)
+ {
+ best_cost = this_cost;
+ if (this_cost <= cost)
+ break;
+ }
+ }
+ }
+#endif
+ cost = MAX (cost, best_cost);
+ }
+ else
+ for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
+ if ((unit & 1) != 0)
+ cost = actual_hazard (i, insn, clock, cost);
+
+ return cost;
+}
+
+/* Return the potential hazard cost of executing an instruction on the
+ units encoded by UNIT if the previous potential hazard cost was COST.
+ An insn with a large blockage time is chosen in preference to one
+ with a smaller time; an insn that uses a unit that is more likely
+ to be used is chosen in preference to one with a unit that is less
+ used. We are trying to minimize a subsequent actual hazard. */
+
+HAIFA_INLINE static int
+potential_hazard (unit, insn, cost)
+ int unit, cost;
+ rtx insn;
+{
+ int i, ncost;
+ unsigned int minb, maxb;
+
+ if (unit >= 0)
+ {
+ minb = maxb = function_units[unit].max_blockage;
+ if (maxb > 1)
+ {
+ if (function_units[unit].blockage_range_function)
+ {
+ maxb = minb = blockage_range (unit, insn);
+ maxb = MAX_BLOCKAGE_COST (maxb);
+ minb = MIN_BLOCKAGE_COST (minb);
+ }
+
+ if (maxb > 1)
+ {
+ /* Make the number of instructions left dominate. Make the
+ minimum delay dominate the maximum delay. If all these
+ are the same, use the unit number to add an arbitrary
+ ordering. Other terms can be added. */
+ ncost = minb * 0x40 + maxb;
+ ncost *= (unit_n_insns[unit] - 1) * 0x1000 + unit;
+ if (ncost > cost)
+ cost = ncost;
+ }
+ }
+ }
+ else
+ for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
+ if ((unit & 1) != 0)
+ cost = potential_hazard (i, insn, cost);
+
+ return cost;
+}
+
+/* Compute cost of executing INSN given the dependence LINK on the insn USED.
+ This is the number of cycles between instruction issue and
+ instruction results. */
+
+HAIFA_INLINE static int
+insn_cost (insn, link, used)
+ rtx insn, link, used;
+{
+ register int cost = INSN_COST (insn);
+
+ if (cost == 0)
+ {
+ recog_memoized (insn);
+
+ /* A USE insn, or something else we don't need to understand.
+ We can't pass these directly to result_ready_cost because it will
+ trigger a fatal error for unrecognizable insns. */
+ if (INSN_CODE (insn) < 0)
+ {
+ INSN_COST (insn) = 1;
+ return 1;
+ }
+ else
+ {
+ cost = result_ready_cost (insn);
+
+ if (cost < 1)
+ cost = 1;
+
+ INSN_COST (insn) = cost;
+ }
+ }
+
+ /* in this case estimate cost without caring how insn is used. */
+ if (link == 0 && used == 0)
+ return cost;
+
+ /* A USE insn should never require the value used to be computed. This
+ allows the computation of a function's result and parameter values to
+ overlap the return and call. */
+ recog_memoized (used);
+ if (INSN_CODE (used) < 0)
+ LINK_COST_FREE (link) = 1;
+
+ /* If some dependencies vary the cost, compute the adjustment. Most
+ commonly, the adjustment is complete: either the cost is ignored
+ (in the case of an output- or anti-dependence), or the cost is
+ unchanged. These values are cached in the link as LINK_COST_FREE
+ and LINK_COST_ZERO. */
+
+ if (LINK_COST_FREE (link))
+ cost = 1;
+#ifdef ADJUST_COST
+ else if (!LINK_COST_ZERO (link))
+ {
+ int ncost = cost;
+
+ ADJUST_COST (used, link, insn, ncost);
+ if (ncost <= 1)
+ LINK_COST_FREE (link) = ncost = 1;
+ if (cost == ncost)
+ LINK_COST_ZERO (link) = 1;
+ cost = ncost;
+ }
+#endif
+ return cost;
+}
+
+/* Compute the priority number for INSN. */
+
+static int
+priority (insn)
+ rtx insn;
+{
+ int this_priority;
+ rtx link;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ return 0;
+
+ if ((this_priority = INSN_PRIORITY (insn)) == 0)
+ {
+ if (INSN_DEPEND (insn) == 0)
+ this_priority = insn_cost (insn, 0, 0);
+ else
+ for (link = INSN_DEPEND (insn); link; link = XEXP (link, 1))
+ {
+ rtx next;
+ int next_priority;
+
+ if (RTX_INTEGRATED_P (link))
+ continue;
+
+ next = XEXP (link, 0);
+
+ /* critical path is meaningful in block boundaries only */
+ if (INSN_BLOCK (next) != INSN_BLOCK (insn))
+ continue;
+
+ next_priority = insn_cost (insn, link, next) + priority (next);
+ if (next_priority > this_priority)
+ this_priority = next_priority;
+ }
+ INSN_PRIORITY (insn) = this_priority;
+ }
+ return this_priority;
+}
+
+
+/* Remove all INSN_LISTs and EXPR_LISTs from the pending lists and add
+ them to the unused_*_list variables, so that they can be reused. */
+
+static void
+free_pending_lists ()
+{
+ if (current_nr_blocks <= 1)
+ {
+ free_list (&pending_read_insns, &unused_insn_list);
+ free_list (&pending_write_insns, &unused_insn_list);
+ free_list (&pending_read_mems, &unused_expr_list);
+ free_list (&pending_write_mems, &unused_expr_list);
+ }
+ else
+ {
+ /* interblock scheduling */
+ int bb;
+
+ for (bb = 0; bb < current_nr_blocks; bb++)
+ {
+ free_list (&bb_pending_read_insns[bb], &unused_insn_list);
+ free_list (&bb_pending_write_insns[bb], &unused_insn_list);
+ free_list (&bb_pending_read_mems[bb], &unused_expr_list);
+ free_list (&bb_pending_write_mems[bb], &unused_expr_list);
+ }
+ }
+}
+
+/* Add an INSN and MEM reference pair to a pending INSN_LIST and MEM_LIST.
+ The MEM is a memory reference contained within INSN, which we are saving
+ so that we can do memory aliasing on it. */
+
+static void
+add_insn_mem_dependence (insn_list, mem_list, insn, mem)
+ rtx *insn_list, *mem_list, insn, mem;
+{
+ register rtx link;
+
+ link = alloc_INSN_LIST (insn, *insn_list);
+ *insn_list = link;
+
+ link = alloc_EXPR_LIST (VOIDmode, mem, *mem_list);
+ *mem_list = link;
+
+ pending_lists_length++;
+}
+
+
+/* Make a dependency between every memory reference on the pending lists
+ and INSN, thus flushing the pending lists. If ONLY_WRITE, don't flush
+ the read list. */
+
+static void
+flush_pending_lists (insn, only_write)
+ rtx insn;
+ int only_write;
+{
+ rtx u;
+ rtx link;
+
+ while (pending_read_insns && ! only_write)
+ {
+ add_dependence (insn, XEXP (pending_read_insns, 0), REG_DEP_ANTI);
+
+ link = pending_read_insns;
+ pending_read_insns = XEXP (pending_read_insns, 1);
+ XEXP (link, 1) = unused_insn_list;
+ unused_insn_list = link;
+
+ link = pending_read_mems;
+ pending_read_mems = XEXP (pending_read_mems, 1);
+ XEXP (link, 1) = unused_expr_list;
+ unused_expr_list = link;
+ }
+ while (pending_write_insns)
+ {
+ add_dependence (insn, XEXP (pending_write_insns, 0), REG_DEP_ANTI);
+
+ link = pending_write_insns;
+ pending_write_insns = XEXP (pending_write_insns, 1);
+ XEXP (link, 1) = unused_insn_list;
+ unused_insn_list = link;
+
+ link = pending_write_mems;
+ pending_write_mems = XEXP (pending_write_mems, 1);
+ XEXP (link, 1) = unused_expr_list;
+ unused_expr_list = link;
+ }
+ pending_lists_length = 0;
+
+ /* last_pending_memory_flush is now a list of insns */
+ for (u = last_pending_memory_flush; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+
+ free_list (&last_pending_memory_flush, &unused_insn_list);
+ last_pending_memory_flush = alloc_INSN_LIST (insn, NULL_RTX);
+}
+
+/* Analyze a single SET or CLOBBER rtx, X, creating all dependencies generated
+ by the write to the destination of X, and reads of everything mentioned. */
+
+static void
+sched_analyze_1 (x, insn)
+ rtx x;
+ rtx insn;
+{
+ register int regno;
+ register rtx dest = SET_DEST (x);
+
+ if (dest == 0)
+ return;
+
+ while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
+ {
+ if (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
+ {
+ /* The second and third arguments are values read by this insn. */
+ sched_analyze_2 (XEXP (dest, 1), insn);
+ sched_analyze_2 (XEXP (dest, 2), insn);
+ }
+ dest = SUBREG_REG (dest);
+ }
+
+ if (GET_CODE (dest) == REG)
+ {
+ register int i;
+
+ regno = REGNO (dest);
+
+ /* A hard reg in a wide mode may really be multiple registers.
+ If so, mark all of them just like the first. */
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ i = HARD_REGNO_NREGS (regno, GET_MODE (dest));
+ while (--i >= 0)
+ {
+ rtx u;
+
+ for (u = reg_last_uses[regno + i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+ reg_last_uses[regno + i] = 0;
+
+ for (u = reg_last_sets[regno + i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_OUTPUT);
+
+ SET_REGNO_REG_SET (reg_pending_sets, regno + i);
+
+ if ((call_used_regs[regno + i] || global_regs[regno + i]))
+ /* Function calls clobber all call_used regs. */
+ for (u = last_function_call; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+ }
+ }
+ else
+ {
+ rtx u;
+
+ for (u = reg_last_uses[regno]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+ reg_last_uses[regno] = 0;
+
+ for (u = reg_last_sets[regno]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_OUTPUT);
+
+ SET_REGNO_REG_SET (reg_pending_sets, regno);
+
+ /* Pseudos that are REG_EQUIV to something may be replaced
+ by that during reloading. We need only add dependencies for
+ the address in the REG_EQUIV note. */
+ if (!reload_completed
+ && reg_known_equiv_p[regno]
+ && GET_CODE (reg_known_value[regno]) == MEM)
+ sched_analyze_2 (XEXP (reg_known_value[regno], 0), insn);
+
+ /* Don't let it cross a call after scheduling if it doesn't
+ already cross one. */
+
+ if (REG_N_CALLS_CROSSED (regno) == 0)
+ for (u = last_function_call; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+ }
+ }
+ else if (GET_CODE (dest) == MEM)
+ {
+ /* Writing memory. */
+
+ if (pending_lists_length > 32)
+ {
+ /* Flush all pending reads and writes to prevent the pending lists
+ from getting any larger. Insn scheduling runs too slowly when
+ these lists get long. The number 32 was chosen because it
+ seems like a reasonable number. When compiling GCC with itself,
+ this flush occurs 8 times for sparc, and 10 times for m88k using
+ the number 32. */
+ flush_pending_lists (insn, 0);
+ }
+ else
+ {
+ rtx u;
+ rtx pending, pending_mem;
+
+ pending = pending_read_insns;
+ pending_mem = pending_read_mems;
+ while (pending)
+ {
+ /* If a dependency already exists, don't create a new one. */
+ if (!find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))
+ if (anti_dependence (XEXP (pending_mem, 0), dest))
+ add_dependence (insn, XEXP (pending, 0), REG_DEP_ANTI);
+
+ pending = XEXP (pending, 1);
+ pending_mem = XEXP (pending_mem, 1);
+ }
+
+ pending = pending_write_insns;
+ pending_mem = pending_write_mems;
+ while (pending)
+ {
+ /* If a dependency already exists, don't create a new one. */
+ if (!find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))
+ if (output_dependence (XEXP (pending_mem, 0), dest))
+ add_dependence (insn, XEXP (pending, 0), REG_DEP_OUTPUT);
+
+ pending = XEXP (pending, 1);
+ pending_mem = XEXP (pending_mem, 1);
+ }
+
+ for (u = last_pending_memory_flush; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+
+ add_insn_mem_dependence (&pending_write_insns, &pending_write_mems,
+ insn, dest);
+ }
+ sched_analyze_2 (XEXP (dest, 0), insn);
+ }
+
+ /* Analyze reads. */
+ if (GET_CODE (x) == SET)
+ sched_analyze_2 (SET_SRC (x), insn);
+}
+
+/* Analyze the uses of memory and registers in rtx X in INSN. */
+
+static void
+sched_analyze_2 (x, insn)
+ rtx x;
+ rtx insn;
+{
+ register int i;
+ register int j;
+ register enum rtx_code code;
+ register char *fmt;
+
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case CONST:
+ case LABEL_REF:
+ /* Ignore constants. Note that we must handle CONST_DOUBLE here
+ because it may have a cc0_rtx in its CONST_DOUBLE_CHAIN field, but
+ this does not mean that this insn is using cc0. */
+ return;
+
+#ifdef HAVE_cc0
+ case CC0:
+ {
+ rtx link, prev;
+
+ /* User of CC0 depends on immediately preceding insn. */
+ SCHED_GROUP_P (insn) = 1;
+
+ /* There may be a note before this insn now, but all notes will
+ be removed before we actually try to schedule the insns, so
+ it won't cause a problem later. We must avoid it here though. */
+ prev = prev_nonnote_insn (insn);
+
+ /* Make a copy of all dependencies on the immediately previous insn,
+ and add to this insn. This is so that all the dependencies will
+ apply to the group. Remove an explicit dependence on this insn
+ as SCHED_GROUP_P now represents it. */
+
+ if (find_insn_list (prev, LOG_LINKS (insn)))
+ remove_dependence (insn, prev);
+
+ for (link = LOG_LINKS (prev); link; link = XEXP (link, 1))
+ add_dependence (insn, XEXP (link, 0), REG_NOTE_KIND (link));
+
+ return;
+ }
+#endif
+
+ case REG:
+ {
+ rtx u;
+ int regno = REGNO (x);
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int i;
+
+ i = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ while (--i >= 0)
+ {
+ reg_last_uses[regno + i]
+ = alloc_INSN_LIST (insn, reg_last_uses[regno + i]);
+
+ for (u = reg_last_sets[regno + i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), 0);
+
+ if ((call_used_regs[regno + i] || global_regs[regno + i]))
+ /* Function calls clobber all call_used regs. */
+ for (u = last_function_call; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+ }
+ }
+ else
+ {
+ reg_last_uses[regno] = alloc_INSN_LIST (insn, reg_last_uses[regno]);
+
+ for (u = reg_last_sets[regno]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), 0);
+
+ /* Pseudos that are REG_EQUIV to something may be replaced
+ by that during reloading. We need only add dependencies for
+ the address in the REG_EQUIV note. */
+ if (!reload_completed
+ && reg_known_equiv_p[regno]
+ && GET_CODE (reg_known_value[regno]) == MEM)
+ sched_analyze_2 (XEXP (reg_known_value[regno], 0), insn);
+
+ /* If the register does not already cross any calls, then add this
+ insn to the sched_before_next_call list so that it will still
+ not cross calls after scheduling. */
+ if (REG_N_CALLS_CROSSED (regno) == 0)
+ add_dependence (sched_before_next_call, insn, REG_DEP_ANTI);
+ }
+ return;
+ }
+
+ case MEM:
+ {
+ /* Reading memory. */
+ rtx u;
+ rtx pending, pending_mem;
+
+ pending = pending_read_insns;
+ pending_mem = pending_read_mems;
+ while (pending)
+ {
+ /* If a dependency already exists, don't create a new one. */
+ if (!find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))
+ if (read_dependence (XEXP (pending_mem, 0), x))
+ add_dependence (insn, XEXP (pending, 0), REG_DEP_ANTI);
+
+ pending = XEXP (pending, 1);
+ pending_mem = XEXP (pending_mem, 1);
+ }
+
+ pending = pending_write_insns;
+ pending_mem = pending_write_mems;
+ while (pending)
+ {
+ /* If a dependency already exists, don't create a new one. */
+ if (!find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))
+ if (true_dependence (XEXP (pending_mem, 0), VOIDmode,
+ x, rtx_varies_p))
+ add_dependence (insn, XEXP (pending, 0), 0);
+
+ pending = XEXP (pending, 1);
+ pending_mem = XEXP (pending_mem, 1);
+ }
+
+ for (u = last_pending_memory_flush; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+
+ /* Always add these dependencies to pending_reads, since
+ this insn may be followed by a write. */
+ add_insn_mem_dependence (&pending_read_insns, &pending_read_mems,
+ insn, x);
+
+ /* Take advantage of tail recursion here. */
+ sched_analyze_2 (XEXP (x, 0), insn);
+ return;
+ }
+
+ /* Force pending stores to memory in case a trap handler needs them. */
+ case TRAP_IF:
+ flush_pending_lists (insn, 1);
+ break;
+
+ case ASM_OPERANDS:
+ case ASM_INPUT:
+ case UNSPEC_VOLATILE:
+ {
+ rtx u;
+
+ /* Traditional and volatile asm instructions must be considered to use
+ and clobber all hard registers, all pseudo-registers and all of
+ memory. So must TRAP_IF and UNSPEC_VOLATILE operations.
+
+ Consider for instance a volatile asm that changes the fpu rounding
+ mode. An insn should not be moved across this even if it only uses
+ pseudo-regs because it might give an incorrectly rounded result. */
+ if (code != ASM_OPERANDS || MEM_VOLATILE_P (x))
+ {
+ int max_reg = max_reg_num ();
+ for (i = 0; i < max_reg; i++)
+ {
+ for (u = reg_last_uses[i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+ reg_last_uses[i] = 0;
+
+ /* reg_last_sets[r] is now a list of insns */
+ for (u = reg_last_sets[i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), 0);
+ }
+ reg_pending_sets_all = 1;
+
+ flush_pending_lists (insn, 0);
+ }
+
+ /* For all ASM_OPERANDS, we must traverse the vector of input operands.
+ We can not just fall through here since then we would be confused
+ by the ASM_INPUT rtx inside ASM_OPERANDS, which do not indicate
+ traditional asms unlike their normal usage. */
+
+ if (code == ASM_OPERANDS)
+ {
+ for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
+ sched_analyze_2 (ASM_OPERANDS_INPUT (x, j), insn);
+ return;
+ }
+ break;
+ }
+
+ case PRE_DEC:
+ case POST_DEC:
+ case PRE_INC:
+ case POST_INC:
+ /* These both read and modify the result. We must handle them as writes
+ to get proper dependencies for following instructions. We must handle
+ them as reads to get proper dependencies from this to previous
+ instructions. Thus we need to pass them to both sched_analyze_1
+ and sched_analyze_2. We must call sched_analyze_2 first in order
+ to get the proper antecedent for the read. */
+ sched_analyze_2 (XEXP (x, 0), insn);
+ sched_analyze_1 (x, insn);
+ return;
+
+ default:
+ break;
+ }
+
+ /* Other cases: walk the insn. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ sched_analyze_2 (XEXP (x, i), insn);
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ sched_analyze_2 (XVECEXP (x, i, j), insn);
+ }
+}
+
+/* Analyze an INSN with pattern X to find all dependencies. */
+
+static void
+sched_analyze_insn (x, insn, loop_notes)
+ rtx x, insn;
+ rtx loop_notes;
+{
+ register RTX_CODE code = GET_CODE (x);
+ rtx link;
+ int maxreg = max_reg_num ();
+ int i;
+
+ if (code == SET || code == CLOBBER)
+ sched_analyze_1 (x, insn);
+ else if (code == PARALLEL)
+ {
+ register int i;
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ {
+ code = GET_CODE (XVECEXP (x, 0, i));
+ if (code == SET || code == CLOBBER)
+ sched_analyze_1 (XVECEXP (x, 0, i), insn);
+ else
+ sched_analyze_2 (XVECEXP (x, 0, i), insn);
+ }
+ }
+ else
+ sched_analyze_2 (x, insn);
+
+ /* Mark registers CLOBBERED or used by called function. */
+ if (GET_CODE (insn) == CALL_INSN)
+ for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+ {
+ if (GET_CODE (XEXP (link, 0)) == CLOBBER)
+ sched_analyze_1 (XEXP (link, 0), insn);
+ else
+ sched_analyze_2 (XEXP (link, 0), insn);
+ }
+
+ /* If there is a {LOOP,EHREGION}_{BEG,END} note in the middle of a basic block, then
+ we must be sure that no instructions are scheduled across it.
+ Otherwise, the reg_n_refs info (which depends on loop_depth) would
+ become incorrect. */
+
+ if (loop_notes)
+ {
+ int max_reg = max_reg_num ();
+ rtx link;
+
+ for (i = 0; i < max_reg; i++)
+ {
+ rtx u;
+ for (u = reg_last_uses[i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+ reg_last_uses[i] = 0;
+
+ /* reg_last_sets[r] is now a list of insns */
+ for (u = reg_last_sets[i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), 0);
+ }
+ reg_pending_sets_all = 1;
+
+ flush_pending_lists (insn, 0);
+
+ link = loop_notes;
+ while (XEXP (link, 1))
+ link = XEXP (link, 1);
+ XEXP (link, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = loop_notes;
+ }
+
+ /* After reload, it is possible for an instruction to have a REG_DEAD note
+ for a register that actually dies a few instructions earlier. For
+ example, this can happen with SECONDARY_MEMORY_NEEDED reloads.
+ In this case, we must consider the insn to use the register mentioned
+ in the REG_DEAD note. Otherwise, we may accidentally move this insn
+ after another insn that sets the register, thus getting obviously invalid
+ rtl. This confuses reorg which believes that REG_DEAD notes are still
+ meaningful.
+
+ ??? We would get better code if we fixed reload to put the REG_DEAD
+ notes in the right places, but that may not be worth the effort. */
+
+ if (reload_completed)
+ {
+ rtx note;
+
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_DEAD)
+ sched_analyze_2 (XEXP (note, 0), insn);
+ }
+
+ EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i,
+ {
+ /* reg_last_sets[r] is now a list of insns */
+ free_list (&reg_last_sets[i], &unused_insn_list);
+ reg_last_sets[i]
+ = alloc_INSN_LIST (insn, NULL_RTX);
+ });
+ CLEAR_REG_SET (reg_pending_sets);
+
+ if (reg_pending_sets_all)
+ {
+ for (i = 0; i < maxreg; i++)
+ {
+ /* reg_last_sets[r] is now a list of insns */
+ free_list (&reg_last_sets[i], &unused_insn_list);
+ reg_last_sets[i] = alloc_INSN_LIST (insn, NULL_RTX);
+ }
+
+ reg_pending_sets_all = 0;
+ }
+
+ /* Handle function calls and function returns created by the epilogue
+ threading code. */
+ if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
+ {
+ rtx dep_insn;
+ rtx prev_dep_insn;
+
+ /* When scheduling instructions, we make sure calls don't lose their
+ accompanying USE insns by depending them one on another in order.
+
+ Also, we must do the same thing for returns created by the epilogue
+ threading code. Note this code works only in this special case,
+ because other passes make no guarantee that they will never emit
+ an instruction between a USE and a RETURN. There is such a guarantee
+ for USE instructions immediately before a call. */
+
+ prev_dep_insn = insn;
+ dep_insn = PREV_INSN (insn);
+ while (GET_CODE (dep_insn) == INSN
+ && GET_CODE (PATTERN (dep_insn)) == USE
+ && GET_CODE (XEXP (PATTERN (dep_insn), 0)) == REG)
+ {
+ SCHED_GROUP_P (prev_dep_insn) = 1;
+
+ /* Make a copy of all dependencies on dep_insn, and add to insn.
+ This is so that all of the dependencies will apply to the
+ group. */
+
+ for (link = LOG_LINKS (dep_insn); link; link = XEXP (link, 1))
+ add_dependence (insn, XEXP (link, 0), REG_NOTE_KIND (link));
+
+ prev_dep_insn = dep_insn;
+ dep_insn = PREV_INSN (dep_insn);
+ }
+ }
+}
+
+/* Analyze every insn between HEAD and TAIL inclusive, creating LOG_LINKS
+ for every dependency. */
+
+static void
+sched_analyze (head, tail)
+ rtx head, tail;
+{
+ register rtx insn;
+ register rtx u;
+ rtx loop_notes = 0;
+
+ for (insn = head;; insn = NEXT_INSN (insn))
+ {
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
+ {
+ /* Make each JUMP_INSN a scheduling barrier for memory references. */
+ if (GET_CODE (insn) == JUMP_INSN)
+ last_pending_memory_flush
+ = alloc_INSN_LIST (insn, last_pending_memory_flush);
+ sched_analyze_insn (PATTERN (insn), insn, loop_notes);
+ loop_notes = 0;
+ }
+ else if (GET_CODE (insn) == CALL_INSN)
+ {
+ rtx x;
+ register int i;
+
+ CANT_MOVE (insn) = 1;
+
+ /* Any instruction using a hard register which may get clobbered
+ by a call needs to be marked as dependent on this call.
+ This prevents a use of a hard return reg from being moved
+ past a void call (i.e. it does not explicitly set the hard
+ return reg). */
+
+ /* If this call is followed by a NOTE_INSN_SETJMP, then assume that
+ all registers, not just hard registers, may be clobbered by this
+ call. */
+
+ /* Insn, being a CALL_INSN, magically depends on
+ `last_function_call' already. */
+
+ if (NEXT_INSN (insn) && GET_CODE (NEXT_INSN (insn)) == NOTE
+ && NOTE_LINE_NUMBER (NEXT_INSN (insn)) == NOTE_INSN_SETJMP)
+ {
+ int max_reg = max_reg_num ();
+ for (i = 0; i < max_reg; i++)
+ {
+ for (u = reg_last_uses[i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+
+ reg_last_uses[i] = 0;
+
+ /* reg_last_sets[r] is now a list of insns */
+ for (u = reg_last_sets[i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), 0);
+ }
+ reg_pending_sets_all = 1;
+
+ /* Add a pair of fake REG_NOTE which we will later
+ convert back into a NOTE_INSN_SETJMP note. See
+ reemit_notes for why we use a pair of NOTEs. */
+ REG_NOTES (insn) = alloc_EXPR_LIST (REG_DEAD,
+ GEN_INT (0),
+ REG_NOTES (insn));
+ REG_NOTES (insn) = alloc_EXPR_LIST (REG_DEAD,
+ GEN_INT (NOTE_INSN_SETJMP),
+ REG_NOTES (insn));
+ }
+ else
+ {
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (call_used_regs[i] || global_regs[i])
+ {
+ for (u = reg_last_uses[i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+ reg_last_uses[i] = 0;
+
+ /* reg_last_sets[r] is now a list of insns */
+ for (u = reg_last_sets[i]; u; u = XEXP (u, 1))
+ add_dependence (insn, XEXP (u, 0), REG_DEP_ANTI);
+
+ SET_REGNO_REG_SET (reg_pending_sets, i);
+ }
+ }
+
+ /* For each insn which shouldn't cross a call, add a dependence
+ between that insn and this call insn. */
+ x = LOG_LINKS (sched_before_next_call);
+ while (x)
+ {
+ add_dependence (insn, XEXP (x, 0), REG_DEP_ANTI);
+ x = XEXP (x, 1);
+ }
+ LOG_LINKS (sched_before_next_call) = 0;
+
+ sched_analyze_insn (PATTERN (insn), insn, loop_notes);
+ loop_notes = 0;
+
+ /* In the absence of interprocedural alias analysis, we must flush
+ all pending reads and writes, and start new dependencies starting
+ from here. But only flush writes for constant calls (which may
+ be passed a pointer to something we haven't written yet). */
+ flush_pending_lists (insn, CONST_CALL_P (insn));
+
+ /* Depend this function call (actually, the user of this
+ function call) on all hard register clobberage. */
+
+ /* last_function_call is now a list of insns */
+ free_list(&last_function_call, &unused_insn_list);
+ last_function_call = alloc_INSN_LIST (insn, NULL_RTX);
+ }
+
+ /* See comments on reemit_notes as to why we do this. */
+ else if (GET_CODE (insn) == NOTE
+ && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_START
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_END
+ || (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP
+ && GET_CODE (PREV_INSN (insn)) != CALL_INSN)))
+ {
+ loop_notes = alloc_EXPR_LIST (REG_DEAD,
+ GEN_INT (NOTE_BLOCK_NUMBER (insn)),
+ loop_notes);
+ loop_notes = alloc_EXPR_LIST (REG_DEAD,
+ GEN_INT (NOTE_LINE_NUMBER (insn)),
+ loop_notes);
+ CONST_CALL_P (loop_notes) = CONST_CALL_P (insn);
+ }
+
+ if (insn == tail)
+ return;
+ }
+ abort ();
+}
+
+/* Called when we see a set of a register. If death is true, then we are
+ scanning backwards. Mark that register as unborn. If nobody says
+ otherwise, that is how things will remain. If death is false, then we
+ are scanning forwards. Mark that register as being born. */
+
+static void
+sched_note_set (x, death)
+ rtx x;
+ int death;
+{
+ register int regno;
+ register rtx reg = SET_DEST (x);
+ int subreg_p = 0;
+
+ if (reg == 0)
+ return;
+
+ while (GET_CODE (reg) == SUBREG || GET_CODE (reg) == STRICT_LOW_PART
+ || GET_CODE (reg) == SIGN_EXTRACT || GET_CODE (reg) == ZERO_EXTRACT)
+ {
+ /* Must treat modification of just one hardware register of a multi-reg
+ value or just a byte field of a register exactly the same way that
+ mark_set_1 in flow.c does, i.e. anything except a paradoxical subreg
+ does not kill the entire register. */
+ if (GET_CODE (reg) != SUBREG
+ || REG_SIZE (SUBREG_REG (reg)) > REG_SIZE (reg))
+ subreg_p = 1;
+
+ reg = SUBREG_REG (reg);
+ }
+
+ if (GET_CODE (reg) != REG)
+ return;
+
+ /* Global registers are always live, so the code below does not apply
+ to them. */
+
+ regno = REGNO (reg);
+ if (regno >= FIRST_PSEUDO_REGISTER || !global_regs[regno])
+ {
+ if (death)
+ {
+ /* If we only set part of the register, then this set does not
+ kill it. */
+ if (subreg_p)
+ return;
+
+ /* Try killing this register. */
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+ while (--j >= 0)
+ {
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
+ }
+ }
+ else
+ {
+ /* Recompute REG_BASIC_BLOCK as we update all the other
+ dataflow information. */
+ if (sched_reg_basic_block[regno] == REG_BLOCK_UNKNOWN)
+ sched_reg_basic_block[regno] = current_block_num;
+ else if (sched_reg_basic_block[regno] != current_block_num)
+ sched_reg_basic_block[regno] = REG_BLOCK_GLOBAL;
+
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+ }
+ }
+ else
+ {
+ /* Make the register live again. */
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
+ while (--j >= 0)
+ {
+ SET_REGNO_REG_SET (bb_live_regs, regno + j);
+ }
+ }
+ else
+ {
+ SET_REGNO_REG_SET (bb_live_regs, regno);
+ }
+ }
+ }
+}
+
+/* Macros and functions for keeping the priority queue sorted, and
+ dealing with queueing and dequeueing of instructions. */
+
+#define SCHED_SORT(READY, N_READY) \
+do { if ((N_READY) == 2) \
+ swap_sort (READY, N_READY); \
+ else if ((N_READY) > 2) \
+ qsort (READY, N_READY, sizeof (rtx), rank_for_schedule); } \
+while (0)
+
+/* Returns a positive value if x is preferred; returns a negative value if
+ y is preferred. Should never return 0, since that will make the sort
+ unstable. */
+
+static int
+rank_for_schedule (x, y)
+ const GENERIC_PTR x;
+ const GENERIC_PTR y;
+{
+ rtx tmp = *(rtx *)y;
+ rtx tmp2 = *(rtx *)x;
+ rtx link;
+ int tmp_class, tmp2_class, depend_count1, depend_count2;
+ int val, priority_val, spec_val, prob_val, weight_val;
+
+
+ /* prefer insn with higher priority */
+ priority_val = INSN_PRIORITY (tmp2) - INSN_PRIORITY (tmp);
+ if (priority_val)
+ return priority_val;
+
+ /* prefer an insn with smaller contribution to registers-pressure */
+ if (!reload_completed &&
+ (weight_val = INSN_REG_WEIGHT (tmp) - INSN_REG_WEIGHT (tmp2)))
+ return (weight_val);
+
+ /* some comparison make sense in interblock scheduling only */
+ if (INSN_BB (tmp) != INSN_BB (tmp2))
+ {
+ /* prefer an inblock motion on an interblock motion */
+ if ((INSN_BB (tmp2) == target_bb) && (INSN_BB (tmp) != target_bb))
+ return 1;
+ if ((INSN_BB (tmp) == target_bb) && (INSN_BB (tmp2) != target_bb))
+ return -1;
+
+ /* prefer a useful motion on a speculative one */
+ if ((spec_val = IS_SPECULATIVE_INSN (tmp) - IS_SPECULATIVE_INSN (tmp2)))
+ return (spec_val);
+
+ /* prefer a more probable (speculative) insn */
+ prob_val = INSN_PROBABILITY (tmp2) - INSN_PROBABILITY (tmp);
+ if (prob_val)
+ return (prob_val);
+ }
+
+ /* compare insns based on their relation to the last-scheduled-insn */
+ if (last_scheduled_insn)
+ {
+ /* Classify the instructions into three classes:
+ 1) Data dependent on last schedule insn.
+ 2) Anti/Output dependent on last scheduled insn.
+ 3) Independent of last scheduled insn, or has latency of one.
+ Choose the insn from the highest numbered class if different. */
+ link = find_insn_list (tmp, INSN_DEPEND (last_scheduled_insn));
+ if (link == 0 || insn_cost (last_scheduled_insn, link, tmp) == 1)
+ tmp_class = 3;
+ else if (REG_NOTE_KIND (link) == 0) /* Data dependence. */
+ tmp_class = 1;
+ else
+ tmp_class = 2;
+
+ link = find_insn_list (tmp2, INSN_DEPEND (last_scheduled_insn));
+ if (link == 0 || insn_cost (last_scheduled_insn, link, tmp2) == 1)
+ tmp2_class = 3;
+ else if (REG_NOTE_KIND (link) == 0) /* Data dependence. */
+ tmp2_class = 1;
+ else
+ tmp2_class = 2;
+
+ if ((val = tmp2_class - tmp_class))
+ return val;
+ }
+
+ /* Prefer the insn which has more later insns that depend on it.
+ This gives the scheduler more freedom when scheduling later
+ instructions at the expense of added register pressure. */
+ depend_count1 = 0;
+ for (link = INSN_DEPEND (tmp); link; link = XEXP (link, 1))
+ depend_count1++;
+
+ depend_count2 = 0;
+ for (link = INSN_DEPEND (tmp2); link; link = XEXP (link, 1))
+ depend_count2++;
+
+ val = depend_count2 - depend_count1;
+ if (val)
+ return val;
+
+ /* If insns are equally good, sort by INSN_LUID (original insn order),
+ so that we make the sort stable. This minimizes instruction movement,
+ thus minimizing sched's effect on debugging and cross-jumping. */
+ return INSN_LUID (tmp) - INSN_LUID (tmp2);
+}
+
+/* Resort the array A in which only element at index N may be out of order. */
+
+HAIFA_INLINE static void
+swap_sort (a, n)
+ rtx *a;
+ int n;
+{
+ rtx insn = a[n - 1];
+ int i = n - 2;
+
+ while (i >= 0 && rank_for_schedule (a + i, &insn) >= 0)
+ {
+ a[i + 1] = a[i];
+ i -= 1;
+ }
+ a[i + 1] = insn;
+}
+
+static int max_priority;
+
+/* Add INSN to the insn queue so that it can be executed at least
+ N_CYCLES after the currently executing insn. Preserve insns
+ chain for debugging purposes. */
+
+HAIFA_INLINE static void
+queue_insn (insn, n_cycles)
+ rtx insn;
+ int n_cycles;
+{
+ int next_q = NEXT_Q_AFTER (q_ptr, n_cycles);
+ rtx link = alloc_INSN_LIST (insn, insn_queue[next_q]);
+ insn_queue[next_q] = link;
+ q_size += 1;
+
+ if (sched_verbose >= 2)
+ {
+ fprintf (dump, ";;\t\tReady-->Q: insn %d: ", INSN_UID (insn));
+
+ if (INSN_BB (insn) != target_bb)
+ fprintf (dump, "(b%d) ", INSN_BLOCK (insn));
+
+ fprintf (dump, "queued for %d cycles.\n", n_cycles);
+ }
+
+}
+
+/* Return nonzero if PAT is the pattern of an insn which makes a
+ register live. */
+
+HAIFA_INLINE static int
+birthing_insn_p (pat)
+ rtx pat;
+{
+ int j;
+
+ if (reload_completed == 1)
+ return 0;
+
+ if (GET_CODE (pat) == SET
+ && GET_CODE (SET_DEST (pat)) == REG)
+ {
+ rtx dest = SET_DEST (pat);
+ int i = REGNO (dest);
+
+ /* It would be more accurate to use refers_to_regno_p or
+ reg_mentioned_p to determine when the dest is not live before this
+ insn. */
+
+ if (REGNO_REG_SET_P (bb_live_regs, i))
+ return (REG_N_SETS (i) == 1);
+
+ return 0;
+ }
+ if (GET_CODE (pat) == PARALLEL)
+ {
+ for (j = 0; j < XVECLEN (pat, 0); j++)
+ if (birthing_insn_p (XVECEXP (pat, 0, j)))
+ return 1;
+ }
+ return 0;
+}
+
+/* PREV is an insn that is ready to execute. Adjust its priority if that
+ will help shorten register lifetimes. */
+
+HAIFA_INLINE static void
+adjust_priority (prev)
+ rtx prev;
+{
+ /* Trying to shorten register lives after reload has completed
+ is useless and wrong. It gives inaccurate schedules. */
+ if (reload_completed == 0)
+ {
+ rtx note;
+ int n_deaths = 0;
+
+ /* ??? This code has no effect, because REG_DEAD notes are removed
+ before we ever get here. */
+ for (note = REG_NOTES (prev); note; note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_DEAD)
+ n_deaths += 1;
+
+ /* Defer scheduling insns which kill registers, since that
+ shortens register lives. Prefer scheduling insns which
+ make registers live for the same reason. */
+ switch (n_deaths)
+ {
+ default:
+ INSN_PRIORITY (prev) >>= 3;
+ break;
+ case 3:
+ INSN_PRIORITY (prev) >>= 2;
+ break;
+ case 2:
+ case 1:
+ INSN_PRIORITY (prev) >>= 1;
+ break;
+ case 0:
+ if (birthing_insn_p (PATTERN (prev)))
+ {
+ int max = max_priority;
+
+ if (max > INSN_PRIORITY (prev))
+ INSN_PRIORITY (prev) = max;
+ }
+ break;
+ }
+#ifdef ADJUST_PRIORITY
+ ADJUST_PRIORITY (prev);
+#endif
+ }
+}
+
+/* INSN is the "currently executing insn". Launch each insn which was
+ waiting on INSN. READY is a vector of insns which are ready to fire.
+ N_READY is the number of elements in READY. CLOCK is the current
+ cycle. */
+
+static int
+schedule_insn (insn, ready, n_ready, clock)
+ rtx insn;
+ rtx *ready;
+ int n_ready;
+ int clock;
+{
+ rtx link;
+ int unit;
+
+ unit = insn_unit (insn);
+
+ if (sched_verbose >= 2)
+ {
+ fprintf (dump, ";;\t\t--> scheduling insn <<<%d>>> on unit ", INSN_UID (insn));
+ insn_print_units (insn);
+ fprintf (dump, "\n");
+ }
+
+ if (sched_verbose && unit == -1)
+ visualize_no_unit (insn);
+
+ if (MAX_BLOCKAGE > 1 || issue_rate > 1 || sched_verbose)
+ schedule_unit (unit, insn, clock);
+
+ if (INSN_DEPEND (insn) == 0)
+ return n_ready;
+
+ /* This is used by the function adjust_priority above. */
+ if (n_ready > 0)
+ max_priority = MAX (INSN_PRIORITY (ready[0]), INSN_PRIORITY (insn));
+ else
+ max_priority = INSN_PRIORITY (insn);
+
+ for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
+ {
+ rtx next = XEXP (link, 0);
+ int cost = insn_cost (insn, link, next);
+
+ INSN_TICK (next) = MAX (INSN_TICK (next), clock + cost);
+
+ if ((INSN_DEP_COUNT (next) -= 1) == 0)
+ {
+ int effective_cost = INSN_TICK (next) - clock;
+
+ /* For speculative insns, before inserting to ready/queue,
+ check live, exception-free, and issue-delay */
+ if (INSN_BB (next) != target_bb
+ && (!IS_VALID (INSN_BB (next))
+ || CANT_MOVE (next)
+ || (IS_SPECULATIVE_INSN (next)
+ && (insn_issue_delay (next) > 3
+ || !check_live (next, INSN_BB (next))
+ || !is_exception_free (next, INSN_BB (next), target_bb)))))
+ continue;
+
+ if (sched_verbose >= 2)
+ {
+ fprintf (dump, ";;\t\tdependences resolved: insn %d ", INSN_UID (next));
+
+ if (current_nr_blocks > 1 && INSN_BB (next) != target_bb)
+ fprintf (dump, "/b%d ", INSN_BLOCK (next));
+
+ if (effective_cost <= 1)
+ fprintf (dump, "into ready\n");
+ else
+ fprintf (dump, "into queue with cost=%d\n", effective_cost);
+ }
+
+ /* Adjust the priority of NEXT and either put it on the ready
+ list or queue it. */
+ adjust_priority (next);
+ if (effective_cost <= 1)
+ ready[n_ready++] = next;
+ else
+ queue_insn (next, effective_cost);
+ }
+ }
+
+ return n_ready;
+}
+
+
+/* Add a REG_DEAD note for REG to INSN, reusing a REG_DEAD note from the
+ dead_notes list. */
+
+static void
+create_reg_dead_note (reg, insn)
+ rtx reg, insn;
+{
+ rtx link;
+
+ /* The number of registers killed after scheduling must be the same as the
+ number of registers killed before scheduling. The number of REG_DEAD
+ notes may not be conserved, i.e. two SImode hard register REG_DEAD notes
+ might become one DImode hard register REG_DEAD note, but the number of
+ registers killed will be conserved.
+
+ We carefully remove REG_DEAD notes from the dead_notes list, so that
+ there will be none left at the end. If we run out early, then there
+ is a bug somewhere in flow, combine and/or sched. */
+
+ if (dead_notes == 0)
+ {
+ if (current_nr_blocks <= 1)
+ abort ();
+ else
+ link = alloc_EXPR_LIST (REG_DEAD, NULL_RTX, NULL_RTX);
+ }
+ else
+ {
+ /* Number of regs killed by REG. */
+ int regs_killed = (REGNO (reg) >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)));
+ /* Number of regs killed by REG_DEAD notes taken off the list. */
+ int reg_note_regs;
+
+ link = dead_notes;
+ reg_note_regs = (REGNO (XEXP (link, 0)) >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (REGNO (XEXP (link, 0)),
+ GET_MODE (XEXP (link, 0))));
+ while (reg_note_regs < regs_killed)
+ {
+ link = XEXP (link, 1);
+
+ /* LINK might be zero if we killed more registers after scheduling
+ than before, and the last hard register we kill is actually
+ multiple hard regs.
+
+ This is normal for interblock scheduling, so deal with it in
+ that case, else abort. */
+ if (link == NULL_RTX && current_nr_blocks <= 1)
+ abort ();
+ else if (link == NULL_RTX)
+ link = alloc_EXPR_LIST (REG_DEAD, gen_rtx_REG (word_mode, 0),
+ NULL_RTX);
+
+ reg_note_regs += (REGNO (XEXP (link, 0)) >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (REGNO (XEXP (link, 0)),
+ GET_MODE (XEXP (link, 0))));
+ }
+ dead_notes = XEXP (link, 1);
+
+ /* If we took too many regs kills off, put the extra ones back. */
+ while (reg_note_regs > regs_killed)
+ {
+ rtx temp_reg, temp_link;
+
+ temp_reg = gen_rtx_REG (word_mode, 0);
+ temp_link = alloc_EXPR_LIST (REG_DEAD, temp_reg, dead_notes);
+ dead_notes = temp_link;
+ reg_note_regs--;
+ }
+ }
+
+ XEXP (link, 0) = reg;
+ XEXP (link, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = link;
+}
+
+/* Subroutine on attach_deaths_insn--handles the recursive search
+ through INSN. If SET_P is true, then x is being modified by the insn. */
+
+static void
+attach_deaths (x, insn, set_p)
+ rtx x;
+ rtx insn;
+ int set_p;
+{
+ register int i;
+ register int j;
+ register enum rtx_code code;
+ register char *fmt;
+
+ if (x == 0)
+ return;
+
+ code = GET_CODE (x);
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ /* Get rid of the easy cases first. */
+ return;
+
+ case REG:
+ {
+ /* If the register dies in this insn, queue that note, and mark
+ this register as needing to die. */
+ /* This code is very similar to mark_used_1 (if set_p is false)
+ and mark_set_1 (if set_p is true) in flow.c. */
+
+ register int regno;
+ int some_needed;
+ int all_needed;
+
+ if (set_p)
+ return;
+
+ regno = REGNO (x);
+ all_needed = some_needed = REGNO_REG_SET_P (old_live_regs, regno);
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int n;
+
+ n = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ while (--n > 0)
+ {
+ int needed = (REGNO_REG_SET_P (old_live_regs, regno + n));
+ some_needed |= needed;
+ all_needed &= needed;
+ }
+ }
+
+ /* If it wasn't live before we started, then add a REG_DEAD note.
+ We must check the previous lifetime info not the current info,
+ because we may have to execute this code several times, e.g.
+ once for a clobber (which doesn't add a note) and later
+ for a use (which does add a note).
+
+ Always make the register live. We must do this even if it was
+ live before, because this may be an insn which sets and uses
+ the same register, in which case the register has already been
+ killed, so we must make it live again.
+
+ Global registers are always live, and should never have a REG_DEAD
+ note added for them, so none of the code below applies to them. */
+
+ if (regno >= FIRST_PSEUDO_REGISTER || ! global_regs[regno])
+ {
+ /* Never add REG_DEAD notes for the FRAME_POINTER_REGNUM or the
+ STACK_POINTER_REGNUM, since these are always considered to be
+ live. Similarly for ARG_POINTER_REGNUM if it is fixed. */
+ if (regno != FRAME_POINTER_REGNUM
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ && ! (regno == HARD_FRAME_POINTER_REGNUM)
+#endif
+#if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
+ && ! (regno == ARG_POINTER_REGNUM && fixed_regs[regno])
+#endif
+ && regno != STACK_POINTER_REGNUM)
+ {
+ if (! all_needed && ! dead_or_set_p (insn, x))
+ {
+ /* Check for the case where the register dying partially
+ overlaps the register set by this insn. */
+ if (regno < FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
+ {
+ int n = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ while (--n >= 0)
+ some_needed |= dead_or_set_regno_p (insn, regno + n);
+ }
+
+ /* If none of the words in X is needed, make a REG_DEAD
+ note. Otherwise, we must make partial REG_DEAD
+ notes. */
+ if (! some_needed)
+ create_reg_dead_note (x, insn);
+ else
+ {
+ int i;
+
+ /* Don't make a REG_DEAD note for a part of a
+ register that is set in the insn. */
+ for (i = HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1;
+ i >= 0; i--)
+ if (! REGNO_REG_SET_P (old_live_regs, regno+i)
+ && ! dead_or_set_regno_p (insn, regno + i))
+ create_reg_dead_note (gen_rtx_REG (reg_raw_mode[regno + i],
+ regno + i),
+ insn);
+ }
+ }
+ }
+
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int j = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ while (--j >= 0)
+ {
+ SET_REGNO_REG_SET (bb_live_regs, regno + j);
+ }
+ }
+ else
+ {
+ /* Recompute REG_BASIC_BLOCK as we update all the other
+ dataflow information. */
+ if (sched_reg_basic_block[regno] == REG_BLOCK_UNKNOWN)
+ sched_reg_basic_block[regno] = current_block_num;
+ else if (sched_reg_basic_block[regno] != current_block_num)
+ sched_reg_basic_block[regno] = REG_BLOCK_GLOBAL;
+
+ SET_REGNO_REG_SET (bb_live_regs, regno);
+ }
+ }
+ return;
+ }
+
+ case MEM:
+ /* Handle tail-recursive case. */
+ attach_deaths (XEXP (x, 0), insn, 0);
+ return;
+
+ case SUBREG:
+ attach_deaths (SUBREG_REG (x), insn,
+ set_p && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+ <= UNITS_PER_WORD)
+ || (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+ == GET_MODE_SIZE (GET_MODE ((x))))));
+ return;
+
+ case STRICT_LOW_PART:
+ attach_deaths (XEXP (x, 0), insn, 0);
+ return;
+
+ case ZERO_EXTRACT:
+ case SIGN_EXTRACT:
+ attach_deaths (XEXP (x, 0), insn, 0);
+ attach_deaths (XEXP (x, 1), insn, 0);
+ attach_deaths (XEXP (x, 2), insn, 0);
+ return;
+
+ default:
+ /* Other cases: walk the insn. */
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ attach_deaths (XEXP (x, i), insn, 0);
+ else if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ attach_deaths (XVECEXP (x, i, j), insn, 0);
+ }
+ }
+}
+
+/* After INSN has executed, add register death notes for each register
+ that is dead after INSN. */
+
+static void
+attach_deaths_insn (insn)
+ rtx insn;
+{
+ rtx x = PATTERN (insn);
+ register RTX_CODE code = GET_CODE (x);
+ rtx link;
+
+ if (code == SET)
+ {
+ attach_deaths (SET_SRC (x), insn, 0);
+
+ /* A register might die here even if it is the destination, e.g.
+ it is the target of a volatile read and is otherwise unused.
+ Hence we must always call attach_deaths for the SET_DEST. */
+ attach_deaths (SET_DEST (x), insn, 1);
+ }
+ else if (code == PARALLEL)
+ {
+ register int i;
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ {
+ code = GET_CODE (XVECEXP (x, 0, i));
+ if (code == SET)
+ {
+ attach_deaths (SET_SRC (XVECEXP (x, 0, i)), insn, 0);
+
+ attach_deaths (SET_DEST (XVECEXP (x, 0, i)), insn, 1);
+ }
+ /* Flow does not add REG_DEAD notes to registers that die in
+ clobbers, so we can't either. */
+ else if (code != CLOBBER)
+ attach_deaths (XVECEXP (x, 0, i), insn, 0);
+ }
+ }
+ /* If this is a CLOBBER, only add REG_DEAD notes to registers inside a
+ MEM being clobbered, just like flow. */
+ else if (code == CLOBBER && GET_CODE (XEXP (x, 0)) == MEM)
+ attach_deaths (XEXP (XEXP (x, 0), 0), insn, 0);
+ /* Otherwise don't add a death note to things being clobbered. */
+ else if (code != CLOBBER)
+ attach_deaths (x, insn, 0);
+
+ /* Make death notes for things used in the called function. */
+ if (GET_CODE (insn) == CALL_INSN)
+ for (link = CALL_INSN_FUNCTION_USAGE (insn); link; link = XEXP (link, 1))
+ attach_deaths (XEXP (XEXP (link, 0), 0), insn,
+ GET_CODE (XEXP (link, 0)) == CLOBBER);
+}
+
+/* functions for handlnig of notes */
+
+/* Delete notes beginning with INSN and put them in the chain
+ of notes ended by NOTE_LIST.
+ Returns the insn following the notes. */
+
+static rtx
+unlink_other_notes (insn, tail)
+ rtx insn, tail;
+{
+ rtx prev = PREV_INSN (insn);
+
+ while (insn != tail && GET_CODE (insn) == NOTE)
+ {
+ rtx next = NEXT_INSN (insn);
+ /* Delete the note from its current position. */
+ if (prev)
+ NEXT_INSN (prev) = next;
+ if (next)
+ PREV_INSN (next) = prev;
+
+ /* Don't save away NOTE_INSN_SETJMPs, because they must remain
+ immediately after the call they follow. We use a fake
+ (REG_DEAD (const_int -1)) note to remember them.
+ Likewise with NOTE_INSN_{LOOP,EHREGION}_{BEG, END}. */
+ if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_START
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_END
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
+ {
+ /* Insert the note at the end of the notes list. */
+ PREV_INSN (insn) = note_list;
+ if (note_list)
+ NEXT_INSN (note_list) = insn;
+ note_list = insn;
+ }
+
+ insn = next;
+ }
+ return insn;
+}
+
+/* Delete line notes beginning with INSN. Record line-number notes so
+ they can be reused. Returns the insn following the notes. */
+
+static rtx
+unlink_line_notes (insn, tail)
+ rtx insn, tail;
+{
+ rtx prev = PREV_INSN (insn);
+
+ while (insn != tail && GET_CODE (insn) == NOTE)
+ {
+ rtx next = NEXT_INSN (insn);
+
+ if (write_symbols != NO_DEBUG && NOTE_LINE_NUMBER (insn) > 0)
+ {
+ /* Delete the note from its current position. */
+ if (prev)
+ NEXT_INSN (prev) = next;
+ if (next)
+ PREV_INSN (next) = prev;
+
+ /* Record line-number notes so they can be reused. */
+ LINE_NOTE (insn) = insn;
+ }
+ else
+ prev = insn;
+
+ insn = next;
+ }
+ return insn;
+}
+
+/* Return the head and tail pointers of BB. */
+
+HAIFA_INLINE static void
+get_block_head_tail (bb, headp, tailp)
+ int bb;
+ rtx *headp;
+ rtx *tailp;
+{
+
+ rtx head;
+ rtx tail;
+ int b;
+
+ b = BB_TO_BLOCK (bb);
+
+ /* HEAD and TAIL delimit the basic block being scheduled. */
+ head = basic_block_head[b];
+ tail = basic_block_end[b];
+
+ /* Don't include any notes or labels at the beginning of the
+ basic block, or notes at the ends of basic blocks. */
+ while (head != tail)
+ {
+ if (GET_CODE (head) == NOTE)
+ head = NEXT_INSN (head);
+ else if (GET_CODE (tail) == NOTE)
+ tail = PREV_INSN (tail);
+ else if (GET_CODE (head) == CODE_LABEL)
+ head = NEXT_INSN (head);
+ else
+ break;
+ }
+
+ *headp = head;
+ *tailp = tail;
+}
+
+/* Delete line notes from bb. Save them so they can be later restored
+ (in restore_line_notes ()). */
+
+static void
+rm_line_notes (bb)
+ int bb;
+{
+ rtx next_tail;
+ rtx tail;
+ rtx head;
+ rtx insn;
+
+ get_block_head_tail (bb, &head, &tail);
+
+ if (head == tail
+ && (GET_RTX_CLASS (GET_CODE (head)) != 'i'))
+ return;
+
+ next_tail = NEXT_INSN (tail);
+ for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
+ {
+ rtx prev;
+
+ /* Farm out notes, and maybe save them in NOTE_LIST.
+ This is needed to keep the debugger from
+ getting completely deranged. */
+ if (GET_CODE (insn) == NOTE)
+ {
+ prev = insn;
+ insn = unlink_line_notes (insn, next_tail);
+
+ if (prev == tail)
+ abort ();
+ if (prev == head)
+ abort ();
+ if (insn == next_tail)
+ abort ();
+ }
+ }
+}
+
+/* Save line number notes for each insn in bb. */
+
+static void
+save_line_notes (bb)
+ int bb;
+{
+ rtx head, tail;
+ rtx next_tail;
+
+ /* We must use the true line number for the first insn in the block
+ that was computed and saved at the start of this pass. We can't
+ use the current line number, because scheduling of the previous
+ block may have changed the current line number. */
+
+ rtx line = line_note_head[BB_TO_BLOCK (bb)];
+ rtx insn;
+
+ get_block_head_tail (bb, &head, &tail);
+ next_tail = NEXT_INSN (tail);
+
+ for (insn = basic_block_head[BB_TO_BLOCK (bb)];
+ insn != next_tail;
+ insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ line = insn;
+ else
+ LINE_NOTE (insn) = line;
+}
+
+
+/* After bb was scheduled, insert line notes into the insns list. */
+
+static void
+restore_line_notes (bb)
+ int bb;
+{
+ rtx line, note, prev, new;
+ int added_notes = 0;
+ int b;
+ rtx head, next_tail, insn;
+
+ b = BB_TO_BLOCK (bb);
+
+ head = basic_block_head[b];
+ next_tail = NEXT_INSN (basic_block_end[b]);
+
+ /* Determine the current line-number. We want to know the current
+ line number of the first insn of the block here, in case it is
+ different from the true line number that was saved earlier. If
+ different, then we need a line number note before the first insn
+ of this block. If it happens to be the same, then we don't want to
+ emit another line number note here. */
+ for (line = head; line; line = PREV_INSN (line))
+ if (GET_CODE (line) == NOTE && NOTE_LINE_NUMBER (line) > 0)
+ break;
+
+ /* Walk the insns keeping track of the current line-number and inserting
+ the line-number notes as needed. */
+ for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ line = insn;
+ /* This used to emit line number notes before every non-deleted note.
+ However, this confuses a debugger, because line notes not separated
+ by real instructions all end up at the same address. I can find no
+ use for line number notes before other notes, so none are emitted. */
+ else if (GET_CODE (insn) != NOTE
+ && (note = LINE_NOTE (insn)) != 0
+ && note != line
+ && (line == 0
+ || NOTE_LINE_NUMBER (note) != NOTE_LINE_NUMBER (line)
+ || NOTE_SOURCE_FILE (note) != NOTE_SOURCE_FILE (line)))
+ {
+ line = note;
+ prev = PREV_INSN (insn);
+ if (LINE_NOTE (note))
+ {
+ /* Re-use the original line-number note. */
+ LINE_NOTE (note) = 0;
+ PREV_INSN (note) = prev;
+ NEXT_INSN (prev) = note;
+ PREV_INSN (insn) = note;
+ NEXT_INSN (note) = insn;
+ }
+ else
+ {
+ added_notes++;
+ new = emit_note_after (NOTE_LINE_NUMBER (note), prev);
+ NOTE_SOURCE_FILE (new) = NOTE_SOURCE_FILE (note);
+ RTX_INTEGRATED_P (new) = RTX_INTEGRATED_P (note);
+ }
+ }
+ if (sched_verbose && added_notes)
+ fprintf (dump, ";; added %d line-number notes\n", added_notes);
+}
+
+/* After scheduling the function, delete redundant line notes from the
+ insns list. */
+
+static void
+rm_redundant_line_notes ()
+{
+ rtx line = 0;
+ rtx insn = get_insns ();
+ int active_insn = 0;
+ int notes = 0;
+
+ /* Walk the insns deleting redundant line-number notes. Many of these
+ are already present. The remainder tend to occur at basic
+ block boundaries. */
+ for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
+ if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
+ {
+ /* If there are no active insns following, INSN is redundant. */
+ if (active_insn == 0)
+ {
+ notes++;
+ NOTE_SOURCE_FILE (insn) = 0;
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ }
+ /* If the line number is unchanged, LINE is redundant. */
+ else if (line
+ && NOTE_LINE_NUMBER (line) == NOTE_LINE_NUMBER (insn)
+ && NOTE_SOURCE_FILE (line) == NOTE_SOURCE_FILE (insn))
+ {
+ notes++;
+ NOTE_SOURCE_FILE (line) = 0;
+ NOTE_LINE_NUMBER (line) = NOTE_INSN_DELETED;
+ line = insn;
+ }
+ else
+ line = insn;
+ active_insn = 0;
+ }
+ else if (!((GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
+ || (GET_CODE (insn) == INSN
+ && (GET_CODE (PATTERN (insn)) == USE
+ || GET_CODE (PATTERN (insn)) == CLOBBER))))
+ active_insn++;
+
+ if (sched_verbose && notes)
+ fprintf (dump, ";; deleted %d line-number notes\n", notes);
+}
+
+/* Delete notes between head and tail and put them in the chain
+ of notes ended by NOTE_LIST. */
+
+static void
+rm_other_notes (head, tail)
+ rtx head;
+ rtx tail;
+{
+ rtx next_tail;
+ rtx insn;
+
+ if (head == tail
+ && (GET_RTX_CLASS (GET_CODE (head)) != 'i'))
+ return;
+
+ next_tail = NEXT_INSN (tail);
+ for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
+ {
+ rtx prev;
+
+ /* Farm out notes, and maybe save them in NOTE_LIST.
+ This is needed to keep the debugger from
+ getting completely deranged. */
+ if (GET_CODE (insn) == NOTE)
+ {
+ prev = insn;
+
+ insn = unlink_other_notes (insn, next_tail);
+
+ if (prev == tail)
+ abort ();
+ if (prev == head)
+ abort ();
+ if (insn == next_tail)
+ abort ();
+ }
+ }
+}
+
+/* Constructor for `sometimes' data structure. */
+
+static int
+new_sometimes_live (regs_sometimes_live, regno, sometimes_max)
+ struct sometimes *regs_sometimes_live;
+ int regno;
+ int sometimes_max;
+{
+ register struct sometimes *p;
+
+ /* There should never be a register greater than max_regno here. If there
+ is, it means that a define_split has created a new pseudo reg. This
+ is not allowed, since there will not be flow info available for any
+ new register, so catch the error here. */
+ if (regno >= max_regno)
+ abort ();
+
+ p = &regs_sometimes_live[sometimes_max];
+ p->regno = regno;
+ p->live_length = 0;
+ p->calls_crossed = 0;
+ sometimes_max++;
+ return sometimes_max;
+}
+
+/* Count lengths of all regs we are currently tracking,
+ and find new registers no longer live. */
+
+static void
+finish_sometimes_live (regs_sometimes_live, sometimes_max)
+ struct sometimes *regs_sometimes_live;
+ int sometimes_max;
+{
+ int i;
+
+ for (i = 0; i < sometimes_max; i++)
+ {
+ register struct sometimes *p = &regs_sometimes_live[i];
+ int regno = p->regno;
+
+ sched_reg_live_length[regno] += p->live_length;
+ sched_reg_n_calls_crossed[regno] += p->calls_crossed;
+ }
+}
+
+/* functions for computation of registers live/usage info */
+
+/* It is assumed that prior to scheduling basic_block_live_at_start (b)
+ contains the registers that are alive at the entry to b.
+
+ Two passes follow: The first pass is performed before the scheduling
+ of a region. It scans each block of the region forward, computing
+ the set of registers alive at the end of the basic block and
+ discard REG_DEAD notes (done by find_pre_sched_live ()).
+
+ The second path is invoked after scheduling all region blocks.
+ It scans each block of the region backward, a block being traversed
+ only after its succesors in the region. When the set of registers
+ live at the end of a basic block may be changed by the scheduling
+ (this may happen for multiple blocks region), it is computed as
+ the union of the registers live at the start of its succesors.
+ The last-use information is updated by inserting REG_DEAD notes.
+ (done by find_post_sched_live ()) */
+
+/* Scan all the insns to be scheduled, removing register death notes.
+ Register death notes end up in DEAD_NOTES.
+ Recreate the register life information for the end of this basic
+ block. */
+
+static void
+find_pre_sched_live (bb)
+ int bb;
+{
+ rtx insn, next_tail, head, tail;
+ int b = BB_TO_BLOCK (bb);
+
+ get_block_head_tail (bb, &head, &tail);
+ COPY_REG_SET (bb_live_regs, basic_block_live_at_start[b]);
+ next_tail = NEXT_INSN (tail);
+
+ for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
+ {
+ rtx prev, next, link;
+ int reg_weight = 0;
+
+ /* Handle register life information. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ /* See if the register gets born here. */
+ /* We must check for registers being born before we check for
+ registers dying. It is possible for a register to be born and
+ die in the same insn, e.g. reading from a volatile memory
+ location into an otherwise unused register. Such a register
+ must be marked as dead after this insn. */
+ if (GET_CODE (PATTERN (insn)) == SET
+ || GET_CODE (PATTERN (insn)) == CLOBBER)
+ {
+ sched_note_set (PATTERN (insn), 0);
+ reg_weight++;
+ }
+
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ {
+ int j;
+ for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
+ if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
+ || GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == CLOBBER)
+ {
+ sched_note_set (XVECEXP (PATTERN (insn), 0, j), 0);
+ reg_weight++;
+ }
+
+ /* ??? This code is obsolete and should be deleted. It
+ is harmless though, so we will leave it in for now. */
+ for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
+ if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == USE)
+ sched_note_set (XVECEXP (PATTERN (insn), 0, j), 0);
+ }
+
+ /* Each call cobbers (makes live) all call-clobbered regs
+ that are not global or fixed. Note that the function-value
+ reg is a call_clobbered reg. */
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ int j;
+ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+ if (call_used_regs[j] && !global_regs[j]
+ && ! fixed_regs[j])
+ {
+ SET_REGNO_REG_SET (bb_live_regs, j);
+ }
+ }
+
+ /* Need to know what registers this insn kills. */
+ for (prev = 0, link = REG_NOTES (insn); link; link = next)
+ {
+ next = XEXP (link, 1);
+ if ((REG_NOTE_KIND (link) == REG_DEAD
+ || REG_NOTE_KIND (link) == REG_UNUSED)
+ /* Verify that the REG_NOTE has a valid value. */
+ && GET_CODE (XEXP (link, 0)) == REG)
+ {
+ register int regno = REGNO (XEXP (link, 0));
+
+ reg_weight--;
+
+ /* Only unlink REG_DEAD notes; leave REG_UNUSED notes
+ alone. */
+ if (REG_NOTE_KIND (link) == REG_DEAD)
+ {
+ if (prev)
+ XEXP (prev, 1) = next;
+ else
+ REG_NOTES (insn) = next;
+ XEXP (link, 1) = dead_notes;
+ dead_notes = link;
+ }
+ else
+ prev = link;
+
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ int j = HARD_REGNO_NREGS (regno,
+ GET_MODE (XEXP (link, 0)));
+ while (--j >= 0)
+ {
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno+j);
+ }
+ }
+ else
+ {
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+ }
+ }
+ else
+ prev = link;
+ }
+ }
+
+ INSN_REG_WEIGHT (insn) = reg_weight;
+ }
+}
+
+/* Update register life and usage information for block bb
+ after scheduling. Put register dead notes back in the code. */
+
+static void
+find_post_sched_live (bb)
+ int bb;
+{
+ int sometimes_max;
+ int j, i;
+ int b;
+ rtx insn;
+ rtx head, tail, prev_head, next_tail;
+
+ register struct sometimes *regs_sometimes_live;
+
+ b = BB_TO_BLOCK (bb);
+
+ /* compute live regs at the end of bb as a function of its successors. */
+ if (current_nr_blocks > 1)
+ {
+ int e;
+ int first_edge;
+
+ first_edge = e = OUT_EDGES (b);
+ CLEAR_REG_SET (bb_live_regs);
+
+ if (e)
+ do
+ {
+ int b_succ;
+
+ b_succ = TO_BLOCK (e);
+ IOR_REG_SET (bb_live_regs, basic_block_live_at_start[b_succ]);
+ e = NEXT_OUT (e);
+ }
+ while (e != first_edge);
+ }
+
+ get_block_head_tail (bb, &head, &tail);
+ next_tail = NEXT_INSN (tail);
+ prev_head = PREV_INSN (head);
+
+ EXECUTE_IF_SET_IN_REG_SET (bb_live_regs, FIRST_PSEUDO_REGISTER, i,
+ {
+ sched_reg_basic_block[i] = REG_BLOCK_GLOBAL;
+ });
+
+ /* if the block is empty, same regs are alive at its end and its start.
+ since this is not guaranteed after interblock scheduling, make sure they
+ are truly identical. */
+ if (NEXT_INSN (prev_head) == tail
+ && (GET_RTX_CLASS (GET_CODE (tail)) != 'i'))
+ {
+ if (current_nr_blocks > 1)
+ COPY_REG_SET (basic_block_live_at_start[b], bb_live_regs);
+
+ return;
+ }
+
+ b = BB_TO_BLOCK (bb);
+ current_block_num = b;
+
+ /* Keep track of register lives. */
+ old_live_regs = ALLOCA_REG_SET ();
+ regs_sometimes_live
+ = (struct sometimes *) alloca (max_regno * sizeof (struct sometimes));
+ sometimes_max = 0;
+
+ /* initiate "sometimes" data, starting with registers live at end */
+ sometimes_max = 0;
+ COPY_REG_SET (old_live_regs, bb_live_regs);
+ EXECUTE_IF_SET_IN_REG_SET (bb_live_regs, 0, j,
+ {
+ sometimes_max
+ = new_sometimes_live (regs_sometimes_live,
+ j, sometimes_max);
+ });
+
+ /* scan insns back, computing regs live info */
+ for (insn = tail; insn != prev_head; insn = PREV_INSN (insn))
+ {
+ /* First we kill registers set by this insn, and then we
+ make registers used by this insn live. This is the opposite
+ order used above because we are traversing the instructions
+ backwards. */
+
+ /* Strictly speaking, we should scan REG_UNUSED notes and make
+ every register mentioned there live, however, we will just
+ kill them again immediately below, so there doesn't seem to
+ be any reason why we bother to do this. */
+
+ /* See if this is the last notice we must take of a register. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ continue;
+
+ if (GET_CODE (PATTERN (insn)) == SET
+ || GET_CODE (PATTERN (insn)) == CLOBBER)
+ sched_note_set (PATTERN (insn), 1);
+ else if (GET_CODE (PATTERN (insn)) == PARALLEL)
+ {
+ for (j = XVECLEN (PATTERN (insn), 0) - 1; j >= 0; j--)
+ if (GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == SET
+ || GET_CODE (XVECEXP (PATTERN (insn), 0, j)) == CLOBBER)
+ sched_note_set (XVECEXP (PATTERN (insn), 0, j), 1);
+ }
+
+ /* This code keeps life analysis information up to date. */
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ register struct sometimes *p;
+
+ /* A call kills all call used registers that are not
+ global or fixed, except for those mentioned in the call
+ pattern which will be made live again later. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (call_used_regs[i] && ! global_regs[i]
+ && ! fixed_regs[i])
+ {
+ CLEAR_REGNO_REG_SET (bb_live_regs, i);
+ }
+
+ /* Regs live at the time of a call instruction must not
+ go in a register clobbered by calls. Record this for
+ all regs now live. Note that insns which are born or
+ die in a call do not cross a call, so this must be done
+ after the killings (above) and before the births
+ (below). */
+ p = regs_sometimes_live;
+ for (i = 0; i < sometimes_max; i++, p++)
+ if (REGNO_REG_SET_P (bb_live_regs, p->regno))
+ p->calls_crossed += 1;
+ }
+
+ /* Make every register used live, and add REG_DEAD notes for
+ registers which were not live before we started. */
+ attach_deaths_insn (insn);
+
+ /* Find registers now made live by that instruction. */
+ EXECUTE_IF_AND_COMPL_IN_REG_SET (bb_live_regs, old_live_regs, 0, j,
+ {
+ sometimes_max
+ = new_sometimes_live (regs_sometimes_live,
+ j, sometimes_max);
+ });
+ IOR_REG_SET (old_live_regs, bb_live_regs);
+
+ /* Count lengths of all regs we are worrying about now,
+ and handle registers no longer live. */
+
+ for (i = 0; i < sometimes_max; i++)
+ {
+ register struct sometimes *p = &regs_sometimes_live[i];
+ int regno = p->regno;
+
+ p->live_length += 1;
+
+ if (!REGNO_REG_SET_P (bb_live_regs, regno))
+ {
+ /* This is the end of one of this register's lifetime
+ segments. Save the lifetime info collected so far,
+ and clear its bit in the old_live_regs entry. */
+ sched_reg_live_length[regno] += p->live_length;
+ sched_reg_n_calls_crossed[regno] += p->calls_crossed;
+ CLEAR_REGNO_REG_SET (old_live_regs, p->regno);
+
+ /* Delete the reg_sometimes_live entry for this reg by
+ copying the last entry over top of it. */
+ *p = regs_sometimes_live[--sometimes_max];
+ /* ...and decrement i so that this newly copied entry
+ will be processed. */
+ i--;
+ }
+ }
+ }
+
+ finish_sometimes_live (regs_sometimes_live, sometimes_max);
+
+ /* In interblock scheduling, basic_block_live_at_start may have changed. */
+ if (current_nr_blocks > 1)
+ COPY_REG_SET (basic_block_live_at_start[b], bb_live_regs);
+
+
+ FREE_REG_SET (old_live_regs);
+} /* find_post_sched_live */
+
+/* After scheduling the subroutine, restore information about uses of
+ registers. */
+
+static void
+update_reg_usage ()
+{
+ int regno;
+
+ if (n_basic_blocks > 0)
+ EXECUTE_IF_SET_IN_REG_SET (bb_live_regs, FIRST_PSEUDO_REGISTER, regno,
+ {
+ sched_reg_basic_block[regno]
+ = REG_BLOCK_GLOBAL;
+ });
+
+ for (regno = 0; regno < max_regno; regno++)
+ if (sched_reg_live_length[regno])
+ {
+ if (sched_verbose)
+ {
+ if (REG_LIVE_LENGTH (regno) > sched_reg_live_length[regno])
+ fprintf (dump,
+ ";; register %d life shortened from %d to %d\n",
+ regno, REG_LIVE_LENGTH (regno),
+ sched_reg_live_length[regno]);
+ /* Negative values are special; don't overwrite the current
+ reg_live_length value if it is negative. */
+ else if (REG_LIVE_LENGTH (regno) < sched_reg_live_length[regno]
+ && REG_LIVE_LENGTH (regno) >= 0)
+ fprintf (dump,
+ ";; register %d life extended from %d to %d\n",
+ regno, REG_LIVE_LENGTH (regno),
+ sched_reg_live_length[regno]);
+
+ if (!REG_N_CALLS_CROSSED (regno)
+ && sched_reg_n_calls_crossed[regno])
+ fprintf (dump,
+ ";; register %d now crosses calls\n", regno);
+ else if (REG_N_CALLS_CROSSED (regno)
+ && !sched_reg_n_calls_crossed[regno]
+ && REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL)
+ fprintf (dump,
+ ";; register %d no longer crosses calls\n", regno);
+
+ if (REG_BASIC_BLOCK (regno) != sched_reg_basic_block[regno]
+ && sched_reg_basic_block[regno] != REG_BLOCK_UNKNOWN
+ && REG_BASIC_BLOCK(regno) != REG_BLOCK_UNKNOWN)
+ fprintf (dump,
+ ";; register %d changed basic block from %d to %d\n",
+ regno, REG_BASIC_BLOCK(regno),
+ sched_reg_basic_block[regno]);
+
+ }
+ /* Negative values are special; don't overwrite the current
+ reg_live_length value if it is negative. */
+ if (REG_LIVE_LENGTH (regno) >= 0)
+ REG_LIVE_LENGTH (regno) = sched_reg_live_length[regno];
+
+ if (sched_reg_basic_block[regno] != REG_BLOCK_UNKNOWN
+ && REG_BASIC_BLOCK(regno) != REG_BLOCK_UNKNOWN)
+ REG_BASIC_BLOCK(regno) = sched_reg_basic_block[regno];
+
+ /* We can't change the value of reg_n_calls_crossed to zero for
+ pseudos which are live in more than one block.
+
+ This is because combine might have made an optimization which
+ invalidated basic_block_live_at_start and reg_n_calls_crossed,
+ but it does not update them. If we update reg_n_calls_crossed
+ here, the two variables are now inconsistent, and this might
+ confuse the caller-save code into saving a register that doesn't
+ need to be saved. This is only a problem when we zero calls
+ crossed for a pseudo live in multiple basic blocks.
+
+ Alternatively, we could try to correctly update basic block live
+ at start here in sched, but that seems complicated.
+
+ Note: it is possible that a global register became local, as result
+ of interblock motion, but will remain marked as a global register. */
+ if (sched_reg_n_calls_crossed[regno]
+ || REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL)
+ REG_N_CALLS_CROSSED (regno) = sched_reg_n_calls_crossed[regno];
+
+ }
+}
+
+/* Scheduling clock, modified in schedule_block() and queue_to_ready () */
+static int clock_var;
+
+/* Move insns that became ready to fire from queue to ready list. */
+
+static int
+queue_to_ready (ready, n_ready)
+ rtx ready[];
+ int n_ready;
+{
+ rtx insn;
+ rtx link;
+
+ q_ptr = NEXT_Q (q_ptr);
+
+ /* Add all pending insns that can be scheduled without stalls to the
+ ready list. */
+ for (link = insn_queue[q_ptr]; link; link = XEXP (link, 1))
+ {
+
+ insn = XEXP (link, 0);
+ q_size -= 1;
+
+ if (sched_verbose >= 2)
+ fprintf (dump, ";;\t\tQ-->Ready: insn %d: ", INSN_UID (insn));
+
+ if (sched_verbose >= 2 && INSN_BB (insn) != target_bb)
+ fprintf (dump, "(b%d) ", INSN_BLOCK (insn));
+
+ ready[n_ready++] = insn;
+ if (sched_verbose >= 2)
+ fprintf (dump, "moving to ready without stalls\n");
+ }
+ insn_queue[q_ptr] = 0;
+
+ /* If there are no ready insns, stall until one is ready and add all
+ of the pending insns at that point to the ready list. */
+ if (n_ready == 0)
+ {
+ register int stalls;
+
+ for (stalls = 1; stalls < INSN_QUEUE_SIZE; stalls++)
+ {
+ if ((link = insn_queue[NEXT_Q_AFTER (q_ptr, stalls)]))
+ {
+ for (; link; link = XEXP (link, 1))
+ {
+ insn = XEXP (link, 0);
+ q_size -= 1;
+
+ if (sched_verbose >= 2)
+ fprintf (dump, ";;\t\tQ-->Ready: insn %d: ", INSN_UID (insn));
+
+ if (sched_verbose >= 2 && INSN_BB (insn) != target_bb)
+ fprintf (dump, "(b%d) ", INSN_BLOCK (insn));
+
+ ready[n_ready++] = insn;
+ if (sched_verbose >= 2)
+ fprintf (dump, "moving to ready with %d stalls\n", stalls);
+ }
+ insn_queue[NEXT_Q_AFTER (q_ptr, stalls)] = 0;
+
+ if (n_ready)
+ break;
+ }
+ }
+
+ if (sched_verbose && stalls)
+ visualize_stall_cycles (BB_TO_BLOCK (target_bb), stalls);
+ q_ptr = NEXT_Q_AFTER (q_ptr, stalls);
+ clock_var += stalls;
+ }
+ return n_ready;
+}
+
+/* Print the ready list for debugging purposes. Callable from debugger. */
+
+static void
+debug_ready_list (ready, n_ready)
+ rtx ready[];
+ int n_ready;
+{
+ int i;
+
+ for (i = 0; i < n_ready; i++)
+ {
+ fprintf (dump, " %d", INSN_UID (ready[i]));
+ if (current_nr_blocks > 1 && INSN_BB (ready[i]) != target_bb)
+ fprintf (dump, "/b%d", INSN_BLOCK (ready[i]));
+ }
+ fprintf (dump, "\n");
+}
+
+/* Print names of units on which insn can/should execute, for debugging. */
+
+static void
+insn_print_units (insn)
+ rtx insn;
+{
+ int i;
+ int unit = insn_unit (insn);
+
+ if (unit == -1)
+ fprintf (dump, "none");
+ else if (unit >= 0)
+ fprintf (dump, "%s", function_units[unit].name);
+ else
+ {
+ fprintf (dump, "[");
+ for (i = 0, unit = ~unit; unit; i++, unit >>= 1)
+ if (unit & 1)
+ {
+ fprintf (dump, "%s", function_units[i].name);
+ if (unit != 1)
+ fprintf (dump, " ");
+ }
+ fprintf (dump, "]");
+ }
+}
+
+/* MAX_VISUAL_LINES is the maximum number of lines in visualization table
+ of a basic block. If more lines are needed, table is splitted to two.
+ n_visual_lines is the number of lines printed so far for a block.
+ visual_tbl contains the block visualization info.
+ vis_no_unit holds insns in a cycle that are not mapped to any unit. */
+#define MAX_VISUAL_LINES 100
+#define INSN_LEN 30
+int n_visual_lines;
+char *visual_tbl;
+int n_vis_no_unit;
+rtx vis_no_unit[10];
+
+/* Finds units that are in use in this fuction. Required only
+ for visualization. */
+
+static void
+init_target_units ()
+{
+ rtx insn;
+ int unit;
+
+ for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ continue;
+
+ unit = insn_unit (insn);
+
+ if (unit < 0)
+ target_units |= ~unit;
+ else
+ target_units |= (1 << unit);
+ }
+}
+
+/* Return the length of the visualization table */
+
+static int
+get_visual_tbl_length ()
+{
+ int unit, i;
+ int n, n1;
+ char *s;
+
+ /* compute length of one field in line */
+ s = (char *) alloca (INSN_LEN + 5);
+ sprintf (s, " %33s", "uname");
+ n1 = strlen (s);
+
+ /* compute length of one line */
+ n = strlen (";; ");
+ n += n1;
+ for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++)
+ if (function_units[unit].bitmask & target_units)
+ for (i = 0; i < function_units[unit].multiplicity; i++)
+ n += n1;
+ n += n1;
+ n += strlen ("\n") + 2;
+
+ /* compute length of visualization string */
+ return (MAX_VISUAL_LINES * n);
+}
+
+/* Init block visualization debugging info */
+
+static void
+init_block_visualization ()
+{
+ strcpy (visual_tbl, "");
+ n_visual_lines = 0;
+ n_vis_no_unit = 0;
+}
+
+#define BUF_LEN 256
+
+static char *
+safe_concat (buf, cur, str)
+ char *buf;
+ char *cur;
+ char *str;
+{
+ char *end = buf + BUF_LEN - 2; /* leave room for null */
+ int c;
+
+ if (cur > end)
+ {
+ *end = '\0';
+ return end;
+ }
+
+ while (cur < end && (c = *str++) != '\0')
+ *cur++ = c;
+
+ *cur = '\0';
+ return cur;
+}
+
+/* This recognizes rtx, I classified as expressions. These are always */
+/* represent some action on values or results of other expression, */
+/* that may be stored in objects representing values. */
+
+static void
+print_exp (buf, x, verbose)
+ char *buf;
+ rtx x;
+ int verbose;
+{
+ char tmp[BUF_LEN];
+ char *st[4];
+ char *cur = buf;
+ char *fun = (char *)0;
+ char *sep;
+ rtx op[4];
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ st[i] = (char *)0;
+ op[i] = NULL_RTX;
+ }
+
+ switch (GET_CODE (x))
+ {
+ case PLUS:
+ op[0] = XEXP (x, 0);
+ st[1] = "+";
+ op[1] = XEXP (x, 1);
+ break;
+ case LO_SUM:
+ op[0] = XEXP (x, 0);
+ st[1] = "+low(";
+ op[1] = XEXP (x, 1);
+ st[2] = ")";
+ break;
+ case MINUS:
+ op[0] = XEXP (x, 0);
+ st[1] = "-";
+ op[1] = XEXP (x, 1);
+ break;
+ case COMPARE:
+ fun = "cmp";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case NEG:
+ st[0] = "-";
+ op[0] = XEXP (x, 0);
+ break;
+ case MULT:
+ op[0] = XEXP (x, 0);
+ st[1] = "*";
+ op[1] = XEXP (x, 1);
+ break;
+ case DIV:
+ op[0] = XEXP (x, 0);
+ st[1] = "/";
+ op[1] = XEXP (x, 1);
+ break;
+ case UDIV:
+ fun = "udiv";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case MOD:
+ op[0] = XEXP (x, 0);
+ st[1] = "%";
+ op[1] = XEXP (x, 1);
+ break;
+ case UMOD:
+ fun = "umod";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case SMIN:
+ fun = "smin";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case SMAX:
+ fun = "smax";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case UMIN:
+ fun = "umin";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case UMAX:
+ fun = "umax";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case NOT:
+ st[0] = "!";
+ op[0] = XEXP (x, 0);
+ break;
+ case AND:
+ op[0] = XEXP (x, 0);
+ st[1] = "&";
+ op[1] = XEXP (x, 1);
+ break;
+ case IOR:
+ op[0] = XEXP (x, 0);
+ st[1] = "|";
+ op[1] = XEXP (x, 1);
+ break;
+ case XOR:
+ op[0] = XEXP (x, 0);
+ st[1] = "^";
+ op[1] = XEXP (x, 1);
+ break;
+ case ASHIFT:
+ op[0] = XEXP (x, 0);
+ st[1] = "<<";
+ op[1] = XEXP (x, 1);
+ break;
+ case LSHIFTRT:
+ op[0] = XEXP (x, 0);
+ st[1] = " 0>>";
+ op[1] = XEXP (x, 1);
+ break;
+ case ASHIFTRT:
+ op[0] = XEXP (x, 0);
+ st[1] = ">>";
+ op[1] = XEXP (x, 1);
+ break;
+ case ROTATE:
+ op[0] = XEXP (x, 0);
+ st[1] = "<-<";
+ op[1] = XEXP (x, 1);
+ break;
+ case ROTATERT:
+ op[0] = XEXP (x, 0);
+ st[1] = ">->";
+ op[1] = XEXP (x, 1);
+ break;
+ case ABS:
+ fun = "abs";
+ op[0] = XEXP (x, 0);
+ break;
+ case SQRT:
+ fun = "sqrt";
+ op[0] = XEXP (x, 0);
+ break;
+ case FFS:
+ fun = "ffs";
+ op[0] = XEXP (x, 0);
+ break;
+ case EQ:
+ op[0] = XEXP (x, 0);
+ st[1] = "==";
+ op[1] = XEXP (x, 1);
+ break;
+ case NE:
+ op[0] = XEXP (x, 0);
+ st[1] = "!=";
+ op[1] = XEXP (x, 1);
+ break;
+ case GT:
+ op[0] = XEXP (x, 0);
+ st[1] = ">";
+ op[1] = XEXP (x, 1);
+ break;
+ case GTU:
+ fun = "gtu";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case LT:
+ op[0] = XEXP (x, 0);
+ st[1] = "<";
+ op[1] = XEXP (x, 1);
+ break;
+ case LTU:
+ fun = "ltu";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case GE:
+ op[0] = XEXP (x, 0);
+ st[1] = ">=";
+ op[1] = XEXP (x, 1);
+ break;
+ case GEU:
+ fun = "geu";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case LE:
+ op[0] = XEXP (x, 0);
+ st[1] = "<=";
+ op[1] = XEXP (x, 1);
+ break;
+ case LEU:
+ fun = "leu";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ break;
+ case SIGN_EXTRACT:
+ fun = (verbose) ? "sign_extract" : "sxt";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ op[2] = XEXP (x, 2);
+ break;
+ case ZERO_EXTRACT:
+ fun = (verbose) ? "zero_extract" : "zxt";
+ op[0] = XEXP (x, 0);
+ op[1] = XEXP (x, 1);
+ op[2] = XEXP (x, 2);
+ break;
+ case SIGN_EXTEND:
+ fun = (verbose) ? "sign_extend" : "sxn";
+ op[0] = XEXP (x, 0);
+ break;
+ case ZERO_EXTEND:
+ fun = (verbose) ? "zero_extend" : "zxn";
+ op[0] = XEXP (x, 0);
+ break;
+ case FLOAT_EXTEND:
+ fun = (verbose) ? "float_extend" : "fxn";
+ op[0] = XEXP (x, 0);
+ break;
+ case TRUNCATE:
+ fun = (verbose) ? "trunc" : "trn";
+ op[0] = XEXP (x, 0);
+ break;
+ case FLOAT_TRUNCATE:
+ fun = (verbose) ? "float_trunc" : "ftr";
+ op[0] = XEXP (x, 0);
+ break;
+ case FLOAT:
+ fun = (verbose) ? "float" : "flt";
+ op[0] = XEXP (x, 0);
+ break;
+ case UNSIGNED_FLOAT:
+ fun = (verbose) ? "uns_float" : "ufl";
+ op[0] = XEXP (x, 0);
+ break;
+ case FIX:
+ fun = "fix";
+ op[0] = XEXP (x, 0);
+ break;
+ case UNSIGNED_FIX:
+ fun = (verbose) ? "uns_fix" : "ufx";
+ op[0] = XEXP (x, 0);
+ break;
+ case PRE_DEC:
+ st[0] = "--";
+ op[0] = XEXP (x, 0);
+ break;
+ case PRE_INC:
+ st[0] = "++";
+ op[0] = XEXP (x, 0);
+ break;
+ case POST_DEC:
+ op[0] = XEXP (x, 0);
+ st[1] = "--";
+ break;
+ case POST_INC:
+ op[0] = XEXP (x, 0);
+ st[1] = "++";
+ break;
+ case CALL:
+ st[0] = "call ";
+ op[0] = XEXP (x, 0);
+ if (verbose)
+ {
+ st[1] = " argc:";
+ op[1] = XEXP (x, 1);
+ }
+ break;
+ case IF_THEN_ELSE:
+ st[0] = "{(";
+ op[0] = XEXP (x, 0);
+ st[1] = ")?";
+ op[1] = XEXP (x, 1);
+ st[2] = ":";
+ op[2] = XEXP (x, 2);
+ st[3] = "}";
+ break;
+ case TRAP_IF:
+ fun = "trap_if";
+ op[0] = TRAP_CONDITION (x);
+ break;
+ case UNSPEC:
+ case UNSPEC_VOLATILE:
+ {
+ cur = safe_concat (buf, cur, "unspec");
+ if (GET_CODE (x) == UNSPEC_VOLATILE)
+ cur = safe_concat (buf, cur, "/v");
+ cur = safe_concat (buf, cur, "[");
+ sep = "";
+ for (i = 0; i < XVECLEN (x, 0); i++)
+ {
+ print_pattern (tmp, XVECEXP (x, 0, i), verbose);
+ cur = safe_concat (buf, cur, sep);
+ cur = safe_concat (buf, cur, tmp);
+ sep = ",";
+ }
+ cur = safe_concat (buf, cur, "] ");
+ sprintf (tmp, "%d", XINT (x, 1));
+ cur = safe_concat (buf, cur, tmp);
+ }
+ break;
+ default:
+ /* if (verbose) debug_rtx (x); */
+ st[0] = GET_RTX_NAME (GET_CODE (x));
+ break;
+ }
+
+ /* Print this as a function? */
+ if (fun)
+ {
+ cur = safe_concat (buf, cur, fun);
+ cur = safe_concat (buf, cur, "(");
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ if (st[i])
+ cur = safe_concat (buf, cur, st[i]);
+
+ if (op[i])
+ {
+ if (fun && i != 0)
+ cur = safe_concat (buf, cur, ",");
+
+ print_value (tmp, op[i], verbose);
+ cur = safe_concat (buf, cur, tmp);
+ }
+ }
+
+ if (fun)
+ cur = safe_concat (buf, cur, ")");
+} /* print_exp */
+
+/* Prints rtxes, i customly classified as values. They're constants, */
+/* registers, labels, symbols and memory accesses. */
+
+static void
+print_value (buf, x, verbose)
+ char *buf;
+ rtx x;
+ int verbose;
+{
+ char t[BUF_LEN];
+ char *cur = buf;
+
+ switch (GET_CODE (x))
+ {
+ case CONST_INT:
+ sprintf (t, "0x%lx", (long)INTVAL (x));
+ cur = safe_concat (buf, cur, t);
+ break;
+ case CONST_DOUBLE:
+ sprintf (t, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
+ cur = safe_concat (buf, cur, t);
+ break;
+ case CONST_STRING:
+ cur = safe_concat (buf, cur, "\"");
+ cur = safe_concat (buf, cur, XSTR (x, 0));
+ cur = safe_concat (buf, cur, "\"");
+ break;
+ case SYMBOL_REF:
+ cur = safe_concat (buf, cur, "`");
+ cur = safe_concat (buf, cur, XSTR (x, 0));
+ cur = safe_concat (buf, cur, "'");
+ break;
+ case LABEL_REF:
+ sprintf (t, "L%d", INSN_UID (XEXP (x, 0)));
+ cur = safe_concat (buf, cur, t);
+ break;
+ case CONST:
+ print_value (t, XEXP (x, 0), verbose);
+ cur = safe_concat (buf, cur, "const(");
+ cur = safe_concat (buf, cur, t);
+ cur = safe_concat (buf, cur, ")");
+ break;
+ case HIGH:
+ print_value (t, XEXP (x, 0), verbose);
+ cur = safe_concat (buf, cur, "high(");
+ cur = safe_concat (buf, cur, t);
+ cur = safe_concat (buf, cur, ")");
+ break;
+ case REG:
+ if (REGNO (x) < FIRST_PSEUDO_REGISTER)
+ {
+ int c = reg_names[ REGNO (x) ][0];
+ if (c >= '0' && c <= '9')
+ cur = safe_concat (buf, cur, "%");
+
+ cur = safe_concat (buf, cur, reg_names[ REGNO (x) ]);
+ }
+ else
+ {
+ sprintf (t, "r%d", REGNO (x));
+ cur = safe_concat (buf, cur, t);
+ }
+ break;
+ case SUBREG:
+ print_value (t, SUBREG_REG (x), verbose);
+ cur = safe_concat (buf, cur, t);
+ sprintf (t, "#%d", SUBREG_WORD (x));
+ cur = safe_concat (buf, cur, t);
+ break;
+ case SCRATCH:
+ cur = safe_concat (buf, cur, "scratch");
+ break;
+ case CC0:
+ cur = safe_concat (buf, cur, "cc0");
+ break;
+ case PC:
+ cur = safe_concat (buf, cur, "pc");
+ break;
+ case MEM:
+ print_value (t, XEXP (x, 0), verbose);
+ cur = safe_concat (buf, cur, "[");
+ cur = safe_concat (buf, cur, t);
+ cur = safe_concat (buf, cur, "]");
+ break;
+ default:
+ print_exp (t, x, verbose);
+ cur = safe_concat (buf, cur, t);
+ break;
+ }
+} /* print_value */
+
+/* The next step in insn detalization, its pattern recognition */
+
+static void
+print_pattern (buf, x, verbose)
+ char *buf;
+ rtx x;
+ int verbose;
+{
+ char t1[BUF_LEN], t2[BUF_LEN], t3[BUF_LEN];
+
+ switch (GET_CODE (x))
+ {
+ case SET:
+ print_value (t1, SET_DEST (x), verbose);
+ print_value (t2, SET_SRC (x), verbose);
+ sprintf (buf, "%s=%s", t1, t2);
+ break;
+ case RETURN:
+ sprintf (buf, "return");
+ break;
+ case CALL:
+ print_exp (buf, x, verbose);
+ break;
+ case CLOBBER:
+ print_value (t1, XEXP (x, 0), verbose);
+ sprintf (buf, "clobber %s", t1);
+ break;
+ case USE:
+ print_value (t1, XEXP (x, 0), verbose);
+ sprintf (buf, "use %s", t1);
+ break;
+ case PARALLEL:
+ {
+ int i;
+
+ sprintf (t1, "{");
+ for (i = 0; i < XVECLEN (x, 0); i++)
+ {
+ print_pattern (t2, XVECEXP (x, 0, i), verbose);
+ sprintf (t3, "%s%s;", t1, t2);
+ strcpy (t1, t3);
+ }
+ sprintf (buf, "%s}", t1);
+ }
+ break;
+ case SEQUENCE:
+ {
+ int i;
+
+ sprintf (t1, "%%{");
+ for (i = 0; i < XVECLEN (x, 0); i++)
+ {
+ print_insn (t2, XVECEXP (x, 0, i), verbose);
+ sprintf (t3, "%s%s;", t1, t2);
+ strcpy (t1, t3);
+ }
+ sprintf (buf, "%s%%}", t1);
+ }
+ break;
+ case ASM_INPUT:
+ sprintf (buf, "asm {%s}", XSTR (x, 0));
+ break;
+ case ADDR_VEC:
+ break;
+ case ADDR_DIFF_VEC:
+ print_value (buf, XEXP (x, 0), verbose);
+ break;
+ case TRAP_IF:
+ print_value (t1, TRAP_CONDITION (x), verbose);
+ sprintf (buf, "trap_if %s", t1);
+ break;
+ case UNSPEC:
+ {
+ int i;
+
+ sprintf (t1, "unspec{");
+ for (i = 0; i < XVECLEN (x, 0); i++)
+ {
+ print_pattern (t2, XVECEXP (x, 0, i), verbose);
+ sprintf (t3, "%s%s;", t1, t2);
+ strcpy (t1, t3);
+ }
+ sprintf (buf, "%s}", t1);
+ }
+ break;
+ case UNSPEC_VOLATILE:
+ {
+ int i;
+
+ sprintf (t1, "unspec/v{");
+ for (i = 0; i < XVECLEN (x, 0); i++)
+ {
+ print_pattern (t2, XVECEXP (x, 0, i), verbose);
+ sprintf (t3, "%s%s;", t1, t2);
+ strcpy (t1, t3);
+ }
+ sprintf (buf, "%s}", t1);
+ }
+ break;
+ default:
+ print_value (buf, x, verbose);
+ }
+} /* print_pattern */
+
+/* This is the main function in rtl visualization mechanism. It
+ accepts an rtx and tries to recognize it as an insn, then prints it
+ properly in human readable form, resembling assembler mnemonics. */
+/* For every insn it prints its UID and BB the insn belongs */
+/* too. (probably the last "option" should be extended somehow, since */
+/* it depends now on sched.c inner variables ...) */
+
+static void
+print_insn (buf, x, verbose)
+ char *buf;
+ rtx x;
+ int verbose;
+{
+ char t[BUF_LEN];
+ rtx insn = x;
+
+ switch (GET_CODE (x))
+ {
+ case INSN:
+ print_pattern (t, PATTERN (x), verbose);
+ if (verbose)
+ sprintf (buf, "b%d: i% 4d: %s", INSN_BB (x),
+ INSN_UID (x), t);
+ else
+ sprintf (buf, "%-4d %s", INSN_UID (x), t);
+ break;
+ case JUMP_INSN:
+ print_pattern (t, PATTERN (x), verbose);
+ if (verbose)
+ sprintf (buf, "b%d: i% 4d: jump %s", INSN_BB (x),
+ INSN_UID (x), t);
+ else
+ sprintf (buf, "%-4d %s", INSN_UID (x), t);
+ break;
+ case CALL_INSN:
+ x = PATTERN (insn);
+ if (GET_CODE (x) == PARALLEL)
+ {
+ x = XVECEXP (x, 0, 0);
+ print_pattern (t, x, verbose);
+ }
+ else
+ strcpy (t, "call <...>");
+ if (verbose)
+ sprintf (buf, "b%d: i% 4d: %s", INSN_BB (insn),
+ INSN_UID (insn), t);
+ else
+ sprintf (buf, "%-4d %s", INSN_UID (insn), t);
+ break;
+ case CODE_LABEL:
+ sprintf (buf, "L%d:", INSN_UID (x));
+ break;
+ case BARRIER:
+ sprintf (buf, "i% 4d: barrier", INSN_UID (x));
+ break;
+ case NOTE:
+ if (NOTE_LINE_NUMBER (x) > 0)
+ sprintf (buf, "%4d note \"%s\" %d", INSN_UID (x),
+ NOTE_SOURCE_FILE (x), NOTE_LINE_NUMBER (x));
+ else
+ sprintf (buf, "%4d %s", INSN_UID (x),
+ GET_NOTE_INSN_NAME (NOTE_LINE_NUMBER (x)));
+ break;
+ default:
+ if (verbose)
+ {
+ sprintf (buf, "Not an INSN at all\n");
+ debug_rtx (x);
+ }
+ else
+ sprintf (buf, "i%-4d <What?>", INSN_UID (x));
+ }
+} /* print_insn */
+
+/* Print visualization debugging info */
+
+static void
+print_block_visualization (b, s)
+ int b;
+ char *s;
+{
+ int unit, i;
+
+ /* print header */
+ fprintf (dump, "\n;; ==================== scheduling visualization for block %d %s \n", b, s);
+
+ /* Print names of units */
+ fprintf (dump, ";; %-8s", "clock");
+ for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++)
+ if (function_units[unit].bitmask & target_units)
+ for (i = 0; i < function_units[unit].multiplicity; i++)
+ fprintf (dump, " %-33s", function_units[unit].name);
+ fprintf (dump, " %-8s\n", "no-unit");
+
+ fprintf (dump, ";; %-8s", "=====");
+ for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++)
+ if (function_units[unit].bitmask & target_units)
+ for (i = 0; i < function_units[unit].multiplicity; i++)
+ fprintf (dump, " %-33s", "==============================");
+ fprintf (dump, " %-8s\n", "=======");
+
+ /* Print insns in each cycle */
+ fprintf (dump, "%s\n", visual_tbl);
+}
+
+/* Print insns in the 'no_unit' column of visualization */
+
+static void
+visualize_no_unit (insn)
+ rtx insn;
+{
+ vis_no_unit[n_vis_no_unit] = insn;
+ n_vis_no_unit++;
+}
+
+/* Print insns scheduled in clock, for visualization. */
+
+static void
+visualize_scheduled_insns (b, clock)
+ int b, clock;
+{
+ int i, unit;
+
+ /* if no more room, split table into two */
+ if (n_visual_lines >= MAX_VISUAL_LINES)
+ {
+ print_block_visualization (b, "(incomplete)");
+ init_block_visualization ();
+ }
+
+ n_visual_lines++;
+
+ sprintf (visual_tbl + strlen (visual_tbl), ";; %-8d", clock);
+ for (unit = 0; unit < FUNCTION_UNITS_SIZE; unit++)
+ if (function_units[unit].bitmask & target_units)
+ for (i = 0; i < function_units[unit].multiplicity; i++)
+ {
+ int instance = unit + i * FUNCTION_UNITS_SIZE;
+ rtx insn = unit_last_insn[instance];
+
+ /* print insns that still keep the unit busy */
+ if (insn &&
+ actual_hazard_this_instance (unit, instance, insn, clock, 0))
+ {
+ char str[BUF_LEN];
+ print_insn (str, insn, 0);
+ str[INSN_LEN] = '\0';
+ sprintf (visual_tbl + strlen (visual_tbl), " %-33s", str);
+ }
+ else
+ sprintf (visual_tbl + strlen (visual_tbl), " %-33s", "------------------------------");
+ }
+
+ /* print insns that are not assigned to any unit */
+ for (i = 0; i < n_vis_no_unit; i++)
+ sprintf (visual_tbl + strlen (visual_tbl), " %-8d",
+ INSN_UID (vis_no_unit[i]));
+ n_vis_no_unit = 0;
+
+ sprintf (visual_tbl + strlen (visual_tbl), "\n");
+}
+
+/* Print stalled cycles */
+
+static void
+visualize_stall_cycles (b, stalls)
+ int b, stalls;
+{
+ int i;
+
+ /* if no more room, split table into two */
+ if (n_visual_lines >= MAX_VISUAL_LINES)
+ {
+ print_block_visualization (b, "(incomplete)");
+ init_block_visualization ();
+ }
+
+ n_visual_lines++;
+
+ sprintf (visual_tbl + strlen (visual_tbl), ";; ");
+ for (i = 0; i < stalls; i++)
+ sprintf (visual_tbl + strlen (visual_tbl), ".");
+ sprintf (visual_tbl + strlen (visual_tbl), "\n");
+}
+
+/* move_insn1: Remove INSN from insn chain, and link it after LAST insn */
+
+static rtx
+move_insn1 (insn, last)
+ rtx insn, last;
+{
+ NEXT_INSN (PREV_INSN (insn)) = NEXT_INSN (insn);
+ PREV_INSN (NEXT_INSN (insn)) = PREV_INSN (insn);
+
+ NEXT_INSN (insn) = NEXT_INSN (last);
+ PREV_INSN (NEXT_INSN (last)) = insn;
+
+ NEXT_INSN (last) = insn;
+ PREV_INSN (insn) = last;
+
+ return insn;
+}
+
+/* Search INSN for fake REG_DEAD note pairs for NOTE_INSN_SETJMP,
+ NOTE_INSN_{LOOP,EHREGION}_{BEG,END}; and convert them back into
+ NOTEs. The REG_DEAD note following first one is contains the saved
+ value for NOTE_BLOCK_NUMBER which is useful for
+ NOTE_INSN_EH_REGION_{BEG,END} NOTEs. LAST is the last instruction
+ output by the instruction scheduler. Return the new value of LAST. */
+
+static rtx
+reemit_notes (insn, last)
+ rtx insn;
+ rtx last;
+{
+ rtx note, retval;
+
+ retval = last;
+ for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
+ {
+ if (REG_NOTE_KIND (note) == REG_DEAD
+ && GET_CODE (XEXP (note, 0)) == CONST_INT)
+ {
+ if (INTVAL (XEXP (note, 0)) == NOTE_INSN_SETJMP)
+ {
+ retval = emit_note_after (INTVAL (XEXP (note, 0)), insn);
+ CONST_CALL_P (retval) = CONST_CALL_P (note);
+ remove_note (insn, note);
+ note = XEXP (note, 1);
+ }
+ else
+ {
+ last = emit_note_before (INTVAL (XEXP (note, 0)), last);
+ remove_note (insn, note);
+ note = XEXP (note, 1);
+ NOTE_BLOCK_NUMBER (last) = INTVAL (XEXP (note, 0));
+ }
+ remove_note (insn, note);
+ }
+ }
+ return retval;
+}
+
+/* Move INSN, and all insns which should be issued before it,
+ due to SCHED_GROUP_P flag. Reemit notes if needed.
+
+ Return the last insn emitted by the scheduler, which is the
+ return value from the first call to reemit_notes. */
+
+static rtx
+move_insn (insn, last)
+ rtx insn, last;
+{
+ rtx retval = NULL;
+
+ /* If INSN has SCHED_GROUP_P set, then issue it and any other
+ insns with SCHED_GROUP_P set first. */
+ while (SCHED_GROUP_P (insn))
+ {
+ rtx prev = PREV_INSN (insn);
+
+ /* Move a SCHED_GROUP_P insn. */
+ move_insn1 (insn, last);
+ /* If this is the first call to reemit_notes, then record
+ its return value. */
+ if (retval == NULL_RTX)
+ retval = reemit_notes (insn, insn);
+ else
+ reemit_notes (insn, insn);
+ insn = prev;
+ }
+
+ /* Now move the first non SCHED_GROUP_P insn. */
+ move_insn1 (insn, last);
+
+ /* If this is the first call to reemit_notes, then record
+ its return value. */
+ if (retval == NULL_RTX)
+ retval = reemit_notes (insn, insn);
+ else
+ reemit_notes (insn, insn);
+
+ return retval;
+}
+
+/* Return an insn which represents a SCHED_GROUP, which is
+ the last insn in the group. */
+
+static rtx
+group_leader (insn)
+ rtx insn;
+{
+ rtx prev;
+
+ do
+ {
+ prev = insn;
+ insn = next_nonnote_insn (insn);
+ }
+ while (insn && SCHED_GROUP_P (insn) && (GET_CODE (insn) != CODE_LABEL));
+
+ return prev;
+}
+
+/* Use forward list scheduling to rearrange insns of block BB in region RGN,
+ possibly bringing insns from subsequent blocks in the same region.
+ Return number of insns scheduled. */
+
+static int
+schedule_block (bb, rgn_n_insns)
+ int bb;
+ int rgn_n_insns;
+{
+ /* Local variables. */
+ rtx insn, last;
+ rtx *ready;
+ int i;
+ int n_ready = 0;
+ int can_issue_more;
+
+ /* flow block of this bb */
+ int b = BB_TO_BLOCK (bb);
+
+ /* target_n_insns == number of insns in b before scheduling starts.
+ sched_target_n_insns == how many of b's insns were scheduled.
+ sched_n_insns == how many insns were scheduled in b */
+ int target_n_insns = 0;
+ int sched_target_n_insns = 0;
+ int sched_n_insns = 0;
+
+#define NEED_NOTHING 0
+#define NEED_HEAD 1
+#define NEED_TAIL 2
+ int new_needs;
+
+ /* head/tail info for this block */
+ rtx prev_head;
+ rtx next_tail;
+ rtx head;
+ rtx tail;
+ int bb_src;
+
+ /* We used to have code to avoid getting parameters moved from hard
+ argument registers into pseudos.
+
+ However, it was removed when it proved to be of marginal benefit
+ and caused problems because schedule_block and compute_forward_dependences
+ had different notions of what the "head" insn was. */
+ get_block_head_tail (bb, &head, &tail);
+
+ /* Interblock scheduling could have moved the original head insn from this
+ block into a proceeding block. This may also cause schedule_block and
+ compute_forward_dependences to have different notions of what the
+ "head" insn was.
+
+ If the interblock movement happened to make this block start with
+ some notes (LOOP, EH or SETJMP) before the first real insn, then
+ HEAD will have various special notes attached to it which must be
+ removed so that we don't end up with extra copies of the notes. */
+ if (GET_RTX_CLASS (GET_CODE (head)) == 'i')
+ {
+ rtx note;
+
+ for (note = REG_NOTES (head); note; note = XEXP (note, 1))
+ if (REG_NOTE_KIND (note) == REG_DEAD
+ && GET_CODE (XEXP (note, 0)) == CONST_INT)
+ remove_note (head, note);
+ }
+
+ next_tail = NEXT_INSN (tail);
+ prev_head = PREV_INSN (head);
+
+ /* If the only insn left is a NOTE or a CODE_LABEL, then there is no need
+ to schedule this block. */
+ if (head == tail
+ && (GET_RTX_CLASS (GET_CODE (head)) != 'i'))
+ return (sched_n_insns);
+
+ /* debug info */
+ if (sched_verbose)
+ {
+ fprintf (dump, ";; ======================================================\n");
+ fprintf (dump,
+ ";; -- basic block %d from %d to %d -- %s reload\n",
+ b, INSN_UID (basic_block_head[b]),
+ INSN_UID (basic_block_end[b]),
+ (reload_completed ? "after" : "before"));
+ fprintf (dump, ";; ======================================================\n");
+ fprintf (dump, "\n");
+
+ visual_tbl = (char *) alloca (get_visual_tbl_length ());
+ init_block_visualization ();
+ }
+
+ /* remove remaining note insns from the block, save them in
+ note_list. These notes are restored at the end of
+ schedule_block (). */
+ note_list = 0;
+ rm_other_notes (head, tail);
+
+ target_bb = bb;
+
+ /* prepare current target block info */
+ if (current_nr_blocks > 1)
+ {
+ candidate_table = (candidate *) alloca (current_nr_blocks * sizeof (candidate));
+
+ bblst_last = 0;
+ /* ??? It is not clear why bblst_size is computed this way. The original
+ number was clearly too small as it resulted in compiler failures.
+ Multiplying by the original number by 2 (to account for update_bbs
+ members) seems to be a reasonable solution. */
+ /* ??? Or perhaps there is a bug somewhere else in this file? */
+ bblst_size = (current_nr_blocks - bb) * rgn_nr_edges * 2;
+ bblst_table = (int *) alloca (bblst_size * sizeof (int));
+
+ bitlst_table_last = 0;
+ bitlst_table_size = rgn_nr_edges;
+ bitlst_table = (int *) alloca (rgn_nr_edges * sizeof (int));
+
+ compute_trg_info (bb);
+ }
+
+ clear_units ();
+
+ /* Allocate the ready list */
+ ready = (rtx *) alloca ((rgn_n_insns + 1) * sizeof (rtx));
+
+ /* Print debugging information. */
+ if (sched_verbose >= 5)
+ debug_dependencies ();
+
+
+ /* Initialize ready list with all 'ready' insns in target block.
+ Count number of insns in the target block being scheduled. */
+ n_ready = 0;
+ for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
+ {
+ rtx next;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ continue;
+ next = NEXT_INSN (insn);
+
+ if (INSN_DEP_COUNT (insn) == 0
+ && (SCHED_GROUP_P (next) == 0 || GET_RTX_CLASS (GET_CODE (next)) != 'i'))
+ ready[n_ready++] = insn;
+ if (!(SCHED_GROUP_P (insn)))
+ target_n_insns++;
+ }
+
+ /* Add to ready list all 'ready' insns in valid source blocks.
+ For speculative insns, check-live, exception-free, and
+ issue-delay. */
+ for (bb_src = bb + 1; bb_src < current_nr_blocks; bb_src++)
+ if (IS_VALID (bb_src))
+ {
+ rtx src_head;
+ rtx src_next_tail;
+ rtx tail, head;
+
+ get_block_head_tail (bb_src, &head, &tail);
+ src_next_tail = NEXT_INSN (tail);
+ src_head = head;
+
+ if (head == tail
+ && (GET_RTX_CLASS (GET_CODE (head)) != 'i'))
+ continue;
+
+ for (insn = src_head; insn != src_next_tail; insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ continue;
+
+ if (!CANT_MOVE (insn)
+ && (!IS_SPECULATIVE_INSN (insn)
+ || (insn_issue_delay (insn) <= 3
+ && check_live (insn, bb_src)
+ && is_exception_free (insn, bb_src, target_bb))))
+
+ {
+ rtx next;
+
+ next = NEXT_INSN (insn);
+ if (INSN_DEP_COUNT (insn) == 0
+ && (SCHED_GROUP_P (next) == 0
+ || GET_RTX_CLASS (GET_CODE (next)) != 'i'))
+ ready[n_ready++] = insn;
+ }
+ }
+ }
+
+#ifdef MD_SCHED_INIT
+ MD_SCHED_INIT (dump, sched_verbose);
+#endif
+
+ /* no insns scheduled in this block yet */
+ last_scheduled_insn = 0;
+
+ /* Sort the ready list */
+ SCHED_SORT (ready, n_ready);
+#ifdef MD_SCHED_REORDER
+ MD_SCHED_REORDER (dump, sched_verbose, ready, n_ready);
+#endif
+
+ if (sched_verbose >= 2)
+ {
+ fprintf (dump, ";;\t\tReady list initially: ");
+ debug_ready_list (ready, n_ready);
+ }
+
+ /* Q_SIZE is the total number of insns in the queue. */
+ q_ptr = 0;
+ q_size = 0;
+ clock_var = 0;
+ bzero ((char *) insn_queue, sizeof (insn_queue));
+
+ /* We start inserting insns after PREV_HEAD. */
+ last = prev_head;
+
+ /* Initialize INSN_QUEUE, LIST and NEW_NEEDS. */
+ new_needs = (NEXT_INSN (prev_head) == basic_block_head[b]
+ ? NEED_HEAD : NEED_NOTHING);
+ if (PREV_INSN (next_tail) == basic_block_end[b])
+ new_needs |= NEED_TAIL;
+
+ /* loop until all the insns in BB are scheduled. */
+ while (sched_target_n_insns < target_n_insns)
+ {
+ int b1;
+
+ clock_var++;
+
+ /* Add to the ready list all pending insns that can be issued now.
+ If there are no ready insns, increment clock until one
+ is ready and add all pending insns at that point to the ready
+ list. */
+ n_ready = queue_to_ready (ready, n_ready);
+
+ if (n_ready == 0)
+ abort ();
+
+ if (sched_verbose >= 2)
+ {
+ fprintf (dump, ";;\t\tReady list after queue_to_ready: ");
+ debug_ready_list (ready, n_ready);
+ }
+
+ /* Sort the ready list. */
+ SCHED_SORT (ready, n_ready);
+#ifdef MD_SCHED_REORDER
+ MD_SCHED_REORDER (dump, sched_verbose, ready, n_ready);
+#endif
+
+ if (sched_verbose)
+ {
+ fprintf (dump, "\n;;\tReady list (t =%3d): ", clock_var);
+ debug_ready_list (ready, n_ready);
+ }
+
+ /* Issue insns from ready list.
+ It is important to count down from n_ready, because n_ready may change
+ as insns are issued. */
+ can_issue_more = issue_rate;
+ for (i = n_ready - 1; i >= 0 && can_issue_more; i--)
+ {
+ rtx insn = ready[i];
+ int cost = actual_hazard (insn_unit (insn), insn, clock_var, 0);
+
+ if (cost > 1)
+ {
+ queue_insn (insn, cost);
+ ready[i] = ready[--n_ready]; /* remove insn from ready list */
+ }
+ else if (cost == 0)
+ {
+ /* an interblock motion? */
+ if (INSN_BB (insn) != target_bb)
+ {
+ rtx temp;
+
+ if (IS_SPECULATIVE_INSN (insn))
+ {
+
+ if (!check_live (insn, INSN_BB (insn)))
+ {
+ /* speculative motion, live check failed, remove
+ insn from ready list */
+ ready[i] = ready[--n_ready];
+ continue;
+ }
+ update_live (insn, INSN_BB (insn));
+
+ /* for speculative load, mark insns fed by it. */
+ if (IS_LOAD_INSN (insn) || FED_BY_SPEC_LOAD (insn))
+ set_spec_fed (insn);
+
+ nr_spec++;
+ }
+ nr_inter++;
+
+ temp = insn;
+ while (SCHED_GROUP_P (temp))
+ temp = PREV_INSN (temp);
+
+ /* Update source block boundaries. */
+ b1 = INSN_BLOCK (temp);
+ if (temp == basic_block_head[b1]
+ && insn == basic_block_end[b1])
+ {
+ /* We moved all the insns in the basic block.
+ Emit a note after the last insn and update the
+ begin/end boundaries to point to the note. */
+ emit_note_after (NOTE_INSN_DELETED, insn);
+ basic_block_end[b1] = NEXT_INSN (insn);
+ basic_block_head[b1] = NEXT_INSN (insn);
+ }
+ else if (insn == basic_block_end[b1])
+ {
+ /* We took insns from the end of the basic block,
+ so update the end of block boundary so that it
+ points to the first insn we did not move. */
+ basic_block_end[b1] = PREV_INSN (temp);
+ }
+ else if (temp == basic_block_head[b1])
+ {
+ /* We took insns from the start of the basic block,
+ so update the start of block boundary so that
+ it points to the first insn we did not move. */
+ basic_block_head[b1] = NEXT_INSN (insn);
+ }
+ }
+ else
+ {
+ /* in block motion */
+ sched_target_n_insns++;
+ }
+
+ last_scheduled_insn = insn;
+ last = move_insn (insn, last);
+ sched_n_insns++;
+
+#ifdef MD_SCHED_VARIABLE_ISSUE
+ MD_SCHED_VARIABLE_ISSUE (dump, sched_verbose, insn, can_issue_more);
+#else
+ can_issue_more--;
+#endif
+
+ n_ready = schedule_insn (insn, ready, n_ready, clock_var);
+
+ /* remove insn from ready list */
+ ready[i] = ready[--n_ready];
+
+ /* close this block after scheduling its jump */
+ if (GET_CODE (last_scheduled_insn) == JUMP_INSN)
+ break;
+ }
+ }
+
+ /* debug info */
+ if (sched_verbose)
+ {
+ visualize_scheduled_insns (b, clock_var);
+ }
+ }
+
+ /* debug info */
+ if (sched_verbose)
+ {
+ fprintf (dump, ";;\tReady list (final): ");
+ debug_ready_list (ready, n_ready);
+ print_block_visualization (b, "");
+ }
+
+ /* Sanity check -- queue must be empty now. Meaningless if region has
+ multiple bbs. */
+ if (current_nr_blocks > 1)
+ if (!flag_schedule_interblock && q_size != 0)
+ abort ();
+
+ /* update head/tail boundaries. */
+ head = NEXT_INSN (prev_head);
+ tail = last;
+
+ /* Restore-other-notes: NOTE_LIST is the end of a chain of notes
+ previously found among the insns. Insert them at the beginning
+ of the insns. */
+ if (note_list != 0)
+ {
+ rtx note_head = note_list;
+
+ while (PREV_INSN (note_head))
+ {
+ note_head = PREV_INSN (note_head);
+ }
+
+ PREV_INSN (note_head) = PREV_INSN (head);
+ NEXT_INSN (PREV_INSN (head)) = note_head;
+ PREV_INSN (head) = note_list;
+ NEXT_INSN (note_list) = head;
+ head = note_head;
+ }
+
+ /* update target block boundaries. */
+ if (new_needs & NEED_HEAD)
+ basic_block_head[b] = head;
+
+ if (new_needs & NEED_TAIL)
+ basic_block_end[b] = tail;
+
+ /* debugging */
+ if (sched_verbose)
+ {
+ fprintf (dump, ";; total time = %d\n;; new basic block head = %d\n",
+ clock_var, INSN_UID (basic_block_head[b]));
+ fprintf (dump, ";; new basic block end = %d\n\n",
+ INSN_UID (basic_block_end[b]));
+ }
+
+ return (sched_n_insns);
+} /* schedule_block () */
+
+
+/* print the bit-set of registers, S. callable from debugger */
+
+extern void
+debug_reg_vector (s)
+ regset s;
+{
+ int regno;
+
+ EXECUTE_IF_SET_IN_REG_SET (s, 0, regno,
+ {
+ fprintf (dump, " %d", regno);
+ });
+
+ fprintf (dump, "\n");
+}
+
+/* Use the backward dependences from LOG_LINKS to build
+ forward dependences in INSN_DEPEND. */
+
+static void
+compute_block_forward_dependences (bb)
+ int bb;
+{
+ rtx insn, link;
+ rtx tail, head;
+ rtx next_tail;
+ enum reg_note dep_type;
+
+ get_block_head_tail (bb, &head, &tail);
+ next_tail = NEXT_INSN (tail);
+ for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ continue;
+
+ insn = group_leader (insn);
+
+ for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
+ {
+ rtx x = group_leader (XEXP (link, 0));
+ rtx new_link;
+
+ if (x != XEXP (link, 0))
+ continue;
+
+ /* Ignore dependences upon deleted insn */
+ if (GET_CODE (x) == NOTE || INSN_DELETED_P (x))
+ continue;
+ if (find_insn_list (insn, INSN_DEPEND (x)))
+ continue;
+
+ new_link = alloc_INSN_LIST (insn, INSN_DEPEND (x));
+
+ dep_type = REG_NOTE_KIND (link);
+ PUT_REG_NOTE_KIND (new_link, dep_type);
+
+ INSN_DEPEND (x) = new_link;
+ INSN_DEP_COUNT (insn) += 1;
+ }
+ }
+}
+
+/* Initialize variables for region data dependence analysis.
+ n_bbs is the number of region blocks */
+
+__inline static void
+init_rgn_data_dependences (n_bbs)
+ int n_bbs;
+{
+ int bb;
+
+ /* variables for which one copy exists for each block */
+ bzero ((char *) bb_pending_read_insns, n_bbs * sizeof (rtx));
+ bzero ((char *) bb_pending_read_mems, n_bbs * sizeof (rtx));
+ bzero ((char *) bb_pending_write_insns, n_bbs * sizeof (rtx));
+ bzero ((char *) bb_pending_write_mems, n_bbs * sizeof (rtx));
+ bzero ((char *) bb_pending_lists_length, n_bbs * sizeof (rtx));
+ bzero ((char *) bb_last_pending_memory_flush, n_bbs * sizeof (rtx));
+ bzero ((char *) bb_last_function_call, n_bbs * sizeof (rtx));
+ bzero ((char *) bb_sched_before_next_call, n_bbs * sizeof (rtx));
+
+ /* Create an insn here so that we can hang dependencies off of it later. */
+ for (bb = 0; bb < n_bbs; bb++)
+ {
+ bb_sched_before_next_call[bb] =
+ gen_rtx_INSN (VOIDmode, 0, NULL_RTX, NULL_RTX,
+ NULL_RTX, 0, NULL_RTX, NULL_RTX);
+ LOG_LINKS (bb_sched_before_next_call[bb]) = 0;
+ }
+}
+
+/* Add dependences so that branches are scheduled to run last in their block */
+
+static void
+add_branch_dependences (head, tail)
+ rtx head, tail;
+{
+
+ rtx insn, last;
+
+ /* For all branches, calls, uses, and cc0 setters, force them to remain
+ in order at the end of the block by adding dependencies and giving
+ the last a high priority. There may be notes present, and prev_head
+ may also be a note.
+
+ Branches must obviously remain at the end. Calls should remain at the
+ end since moving them results in worse register allocation. Uses remain
+ at the end to ensure proper register allocation. cc0 setters remaim
+ at the end because they can't be moved away from their cc0 user. */
+ insn = tail;
+ last = 0;
+ while (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
+ || (GET_CODE (insn) == INSN
+ && (GET_CODE (PATTERN (insn)) == USE
+#ifdef HAVE_cc0
+ || sets_cc0_p (PATTERN (insn))
+#endif
+ ))
+ || GET_CODE (insn) == NOTE)
+ {
+ if (GET_CODE (insn) != NOTE)
+ {
+ if (last != 0
+ && !find_insn_list (insn, LOG_LINKS (last)))
+ {
+ add_dependence (last, insn, REG_DEP_ANTI);
+ INSN_REF_COUNT (insn)++;
+ }
+
+ CANT_MOVE (insn) = 1;
+
+ last = insn;
+ /* Skip over insns that are part of a group.
+ Make each insn explicitly depend on the previous insn.
+ This ensures that only the group header will ever enter
+ the ready queue (and, when scheduled, will automatically
+ schedule the SCHED_GROUP_P block). */
+ while (SCHED_GROUP_P (insn))
+ {
+ rtx temp = prev_nonnote_insn (insn);
+ add_dependence (insn, temp, REG_DEP_ANTI);
+ insn = temp;
+ }
+ }
+
+ /* Don't overrun the bounds of the basic block. */
+ if (insn == head)
+ break;
+
+ insn = PREV_INSN (insn);
+ }
+
+ /* make sure these insns are scheduled last in their block */
+ insn = last;
+ if (insn != 0)
+ while (insn != head)
+ {
+ insn = prev_nonnote_insn (insn);
+
+ if (INSN_REF_COUNT (insn) != 0)
+ continue;
+
+ if (!find_insn_list (last, LOG_LINKS (insn)))
+ add_dependence (last, insn, REG_DEP_ANTI);
+ INSN_REF_COUNT (insn) = 1;
+
+ /* Skip over insns that are part of a group. */
+ while (SCHED_GROUP_P (insn))
+ insn = prev_nonnote_insn (insn);
+ }
+}
+
+/* Compute bacward dependences inside BB. In a multiple blocks region:
+ (1) a bb is analyzed after its predecessors, and (2) the lists in
+ effect at the end of bb (after analyzing for bb) are inherited by
+ bb's successrs.
+
+ Specifically for reg-reg data dependences, the block insns are
+ scanned by sched_analyze () top-to-bottom. Two lists are
+ naintained by sched_analyze (): reg_last_defs[] for register DEFs,
+ and reg_last_uses[] for register USEs.
+
+ When analysis is completed for bb, we update for its successors:
+ ; - DEFS[succ] = Union (DEFS [succ], DEFS [bb])
+ ; - USES[succ] = Union (USES [succ], DEFS [bb])
+
+ The mechanism for computing mem-mem data dependence is very
+ similar, and the result is interblock dependences in the region. */
+
+static void
+compute_block_backward_dependences (bb)
+ int bb;
+{
+ int b;
+ rtx x;
+ rtx head, tail;
+ int max_reg = max_reg_num ();
+
+ b = BB_TO_BLOCK (bb);
+
+ if (current_nr_blocks == 1)
+ {
+ reg_last_uses = (rtx *) alloca (max_reg * sizeof (rtx));
+ reg_last_sets = (rtx *) alloca (max_reg * sizeof (rtx));
+
+ bzero ((char *) reg_last_uses, max_reg * sizeof (rtx));
+ bzero ((char *) reg_last_sets, max_reg * sizeof (rtx));
+
+ pending_read_insns = 0;
+ pending_read_mems = 0;
+ pending_write_insns = 0;
+ pending_write_mems = 0;
+ pending_lists_length = 0;
+ last_function_call = 0;
+ last_pending_memory_flush = 0;
+ sched_before_next_call
+ = gen_rtx_INSN (VOIDmode, 0, NULL_RTX, NULL_RTX,
+ NULL_RTX, 0, NULL_RTX, NULL_RTX);
+ LOG_LINKS (sched_before_next_call) = 0;
+ }
+ else
+ {
+ reg_last_uses = bb_reg_last_uses[bb];
+ reg_last_sets = bb_reg_last_sets[bb];
+
+ pending_read_insns = bb_pending_read_insns[bb];
+ pending_read_mems = bb_pending_read_mems[bb];
+ pending_write_insns = bb_pending_write_insns[bb];
+ pending_write_mems = bb_pending_write_mems[bb];
+ pending_lists_length = bb_pending_lists_length[bb];
+ last_function_call = bb_last_function_call[bb];
+ last_pending_memory_flush = bb_last_pending_memory_flush[bb];
+
+ sched_before_next_call = bb_sched_before_next_call[bb];
+ }
+
+ /* do the analysis for this block */
+ get_block_head_tail (bb, &head, &tail);
+ sched_analyze (head, tail);
+ add_branch_dependences (head, tail);
+
+ if (current_nr_blocks > 1)
+ {
+ int e, first_edge;
+ int b_succ, bb_succ;
+ int reg;
+ rtx link_insn, link_mem;
+ rtx u;
+
+ /* these lists should point to the right place, for correct freeing later. */
+ bb_pending_read_insns[bb] = pending_read_insns;
+ bb_pending_read_mems[bb] = pending_read_mems;
+ bb_pending_write_insns[bb] = pending_write_insns;
+ bb_pending_write_mems[bb] = pending_write_mems;
+
+ /* bb's structures are inherited by it's successors */
+ first_edge = e = OUT_EDGES (b);
+ if (e > 0)
+ do
+ {
+ b_succ = TO_BLOCK (e);
+ bb_succ = BLOCK_TO_BB (b_succ);
+
+ /* only bbs "below" bb, in the same region, are interesting */
+ if (CONTAINING_RGN (b) != CONTAINING_RGN (b_succ)
+ || bb_succ <= bb)
+ {
+ e = NEXT_OUT (e);
+ continue;
+ }
+
+ for (reg = 0; reg < max_reg; reg++)
+ {
+
+ /* reg-last-uses lists are inherited by bb_succ */
+ for (u = reg_last_uses[reg]; u; u = XEXP (u, 1))
+ {
+ if (find_insn_list (XEXP (u, 0), (bb_reg_last_uses[bb_succ])[reg]))
+ continue;
+
+ (bb_reg_last_uses[bb_succ])[reg]
+ = alloc_INSN_LIST (XEXP (u, 0),
+ (bb_reg_last_uses[bb_succ])[reg]);
+ }
+
+ /* reg-last-defs lists are inherited by bb_succ */
+ for (u = reg_last_sets[reg]; u; u = XEXP (u, 1))
+ {
+ if (find_insn_list (XEXP (u, 0), (bb_reg_last_sets[bb_succ])[reg]))
+ continue;
+
+ (bb_reg_last_sets[bb_succ])[reg]
+ = alloc_INSN_LIST (XEXP (u, 0),
+ (bb_reg_last_sets[bb_succ])[reg]);
+ }
+ }
+
+ /* mem read/write lists are inherited by bb_succ */
+ link_insn = pending_read_insns;
+ link_mem = pending_read_mems;
+ while (link_insn)
+ {
+ if (!(find_insn_mem_list (XEXP (link_insn, 0), XEXP (link_mem, 0),
+ bb_pending_read_insns[bb_succ],
+ bb_pending_read_mems[bb_succ])))
+ add_insn_mem_dependence (&bb_pending_read_insns[bb_succ],
+ &bb_pending_read_mems[bb_succ],
+ XEXP (link_insn, 0), XEXP (link_mem, 0));
+ link_insn = XEXP (link_insn, 1);
+ link_mem = XEXP (link_mem, 1);
+ }
+
+ link_insn = pending_write_insns;
+ link_mem = pending_write_mems;
+ while (link_insn)
+ {
+ if (!(find_insn_mem_list (XEXP (link_insn, 0), XEXP (link_mem, 0),
+ bb_pending_write_insns[bb_succ],
+ bb_pending_write_mems[bb_succ])))
+ add_insn_mem_dependence (&bb_pending_write_insns[bb_succ],
+ &bb_pending_write_mems[bb_succ],
+ XEXP (link_insn, 0), XEXP (link_mem, 0));
+
+ link_insn = XEXP (link_insn, 1);
+ link_mem = XEXP (link_mem, 1);
+ }
+
+ /* last_function_call is inherited by bb_succ */
+ for (u = last_function_call; u; u = XEXP (u, 1))
+ {
+ if (find_insn_list (XEXP (u, 0), bb_last_function_call[bb_succ]))
+ continue;
+
+ bb_last_function_call[bb_succ]
+ = alloc_INSN_LIST (XEXP (u, 0),
+ bb_last_function_call[bb_succ]);
+ }
+
+ /* last_pending_memory_flush is inherited by bb_succ */
+ for (u = last_pending_memory_flush; u; u = XEXP (u, 1))
+ {
+ if (find_insn_list (XEXP (u, 0), bb_last_pending_memory_flush[bb_succ]))
+ continue;
+
+ bb_last_pending_memory_flush[bb_succ]
+ = alloc_INSN_LIST (XEXP (u, 0),
+ bb_last_pending_memory_flush[bb_succ]);
+ }
+
+ /* sched_before_next_call is inherited by bb_succ */
+ x = LOG_LINKS (sched_before_next_call);
+ for (; x; x = XEXP (x, 1))
+ add_dependence (bb_sched_before_next_call[bb_succ],
+ XEXP (x, 0), REG_DEP_ANTI);
+
+ e = NEXT_OUT (e);
+ }
+ while (e != first_edge);
+ }
+
+ /* Free up the INSN_LISTs
+
+ Note this loop is executed max_reg * nr_regions times. It's first
+ implementation accounted for over 90% of the calls to free_list.
+ The list was empty for the vast majority of those calls. On the PA,
+ not calling free_list in those cases improves -O2 compile times by
+ 3-5% on average. */
+ for (b = 0; b < max_reg; ++b)
+ {
+ if (reg_last_sets[b])
+ free_list (&reg_last_sets[b], &unused_insn_list);
+ if (reg_last_uses[b])
+ free_list (&reg_last_uses[b], &unused_insn_list);
+ }
+
+ /* Assert that we won't need bb_reg_last_* for this block anymore. */
+ if (current_nr_blocks > 1)
+ {
+ bb_reg_last_uses[bb] = (rtx *) NULL_RTX;
+ bb_reg_last_sets[bb] = (rtx *) NULL_RTX;
+ }
+}
+
+/* Print dependences for debugging, callable from debugger */
+
+void
+debug_dependencies ()
+{
+ int bb;
+
+ fprintf (dump, ";; --------------- forward dependences: ------------ \n");
+ for (bb = 0; bb < current_nr_blocks; bb++)
+ {
+ if (1)
+ {
+ rtx head, tail;
+ rtx next_tail;
+ rtx insn;
+
+ get_block_head_tail (bb, &head, &tail);
+ next_tail = NEXT_INSN (tail);
+ fprintf (dump, "\n;; --- Region Dependences --- b %d bb %d \n",
+ BB_TO_BLOCK (bb), bb);
+
+ fprintf (dump, ";; %7s%6s%6s%6s%6s%6s%11s%6s\n",
+ "insn", "code", "bb", "dep", "prio", "cost", "blockage", "units");
+ fprintf (dump, ";; %7s%6s%6s%6s%6s%6s%11s%6s\n",
+ "----", "----", "--", "---", "----", "----", "--------", "-----");
+ for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
+ {
+ rtx link;
+ int unit, range;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ {
+ int n;
+ fprintf (dump, ";; %6d ", INSN_UID (insn));
+ if (GET_CODE (insn) == NOTE)
+ {
+ n = NOTE_LINE_NUMBER (insn);
+ if (n < 0)
+ fprintf (dump, "%s\n", GET_NOTE_INSN_NAME (n));
+ else
+ fprintf (dump, "line %d, file %s\n", n,
+ NOTE_SOURCE_FILE (insn));
+ }
+ else
+ fprintf (dump, " {%s}\n", GET_RTX_NAME (GET_CODE (insn)));
+ continue;
+ }
+
+ unit = insn_unit (insn);
+ range = (unit < 0
+ || function_units[unit].blockage_range_function == 0) ? 0 :
+ function_units[unit].blockage_range_function (insn);
+ fprintf (dump,
+ ";; %s%5d%6d%6d%6d%6d%6d %3d -%3d ",
+ (SCHED_GROUP_P (insn) ? "+" : " "),
+ INSN_UID (insn),
+ INSN_CODE (insn),
+ INSN_BB (insn),
+ INSN_DEP_COUNT (insn),
+ INSN_PRIORITY (insn),
+ insn_cost (insn, 0, 0),
+ (int) MIN_BLOCKAGE_COST (range),
+ (int) MAX_BLOCKAGE_COST (range));
+ insn_print_units (insn);
+ fprintf (dump, "\t: ");
+ for (link = INSN_DEPEND (insn); link; link = XEXP (link, 1))
+ fprintf (dump, "%d ", INSN_UID (XEXP (link, 0)));
+ fprintf (dump, "\n");
+ }
+ }
+ }
+ fprintf (dump, "\n");
+}
+
+/* Set_priorities: compute priority of each insn in the block */
+
+static int
+set_priorities (bb)
+ int bb;
+{
+ rtx insn;
+ int n_insn;
+
+ rtx tail;
+ rtx prev_head;
+ rtx head;
+
+ get_block_head_tail (bb, &head, &tail);
+ prev_head = PREV_INSN (head);
+
+ if (head == tail
+ && (GET_RTX_CLASS (GET_CODE (head)) != 'i'))
+ return 0;
+
+ n_insn = 0;
+ for (insn = tail; insn != prev_head; insn = PREV_INSN (insn))
+ {
+
+ if (GET_CODE (insn) == NOTE)
+ continue;
+
+ if (!(SCHED_GROUP_P (insn)))
+ n_insn++;
+ (void) priority (insn);
+ }
+
+ return n_insn;
+}
+
+/* Make each element of VECTOR point at an rtx-vector,
+ taking the space for all those rtx-vectors from SPACE.
+ SPACE is of type (rtx *), but it is really as long as NELTS rtx-vectors.
+ BYTES_PER_ELT is the number of bytes in one rtx-vector.
+ (this is the same as init_regset_vector () in flow.c) */
+
+static void
+init_rtx_vector (vector, space, nelts, bytes_per_elt)
+ rtx **vector;
+ rtx *space;
+ int nelts;
+ int bytes_per_elt;
+{
+ register int i;
+ register rtx *p = space;
+
+ for (i = 0; i < nelts; i++)
+ {
+ vector[i] = p;
+ p += bytes_per_elt / sizeof (*p);
+ }
+}
+
+/* Schedule a region. A region is either an inner loop, a loop-free
+ subroutine, or a single basic block. Each bb in the region is
+ scheduled after its flow predecessors. */
+
+static void
+schedule_region (rgn)
+ int rgn;
+{
+ int bb;
+ int rgn_n_insns = 0;
+ int sched_rgn_n_insns = 0;
+
+ /* set variables for the current region */
+ current_nr_blocks = RGN_NR_BLOCKS (rgn);
+ current_blocks = RGN_BLOCKS (rgn);
+
+ reg_pending_sets = ALLOCA_REG_SET ();
+ reg_pending_sets_all = 0;
+
+ /* initializations for region data dependence analyisis */
+ if (current_nr_blocks > 1)
+ {
+ rtx *space;
+ int maxreg = max_reg_num ();
+
+ bb_reg_last_uses = (rtx **) alloca (current_nr_blocks * sizeof (rtx *));
+ space = (rtx *) alloca (current_nr_blocks * maxreg * sizeof (rtx));
+ bzero ((char *) space, current_nr_blocks * maxreg * sizeof (rtx));
+ init_rtx_vector (bb_reg_last_uses, space, current_nr_blocks, maxreg * sizeof (rtx *));
+
+ bb_reg_last_sets = (rtx **) alloca (current_nr_blocks * sizeof (rtx *));
+ space = (rtx *) alloca (current_nr_blocks * maxreg * sizeof (rtx));
+ bzero ((char *) space, current_nr_blocks * maxreg * sizeof (rtx));
+ init_rtx_vector (bb_reg_last_sets, space, current_nr_blocks, maxreg * sizeof (rtx *));
+
+ bb_pending_read_insns = (rtx *) alloca (current_nr_blocks * sizeof (rtx));
+ bb_pending_read_mems = (rtx *) alloca (current_nr_blocks * sizeof (rtx));
+ bb_pending_write_insns = (rtx *) alloca (current_nr_blocks * sizeof (rtx));
+ bb_pending_write_mems = (rtx *) alloca (current_nr_blocks * sizeof (rtx));
+ bb_pending_lists_length = (int *) alloca (current_nr_blocks * sizeof (int));
+ bb_last_pending_memory_flush = (rtx *) alloca (current_nr_blocks * sizeof (rtx));
+ bb_last_function_call = (rtx *) alloca (current_nr_blocks * sizeof (rtx));
+ bb_sched_before_next_call = (rtx *) alloca (current_nr_blocks * sizeof (rtx));
+
+ init_rgn_data_dependences (current_nr_blocks);
+ }
+
+ /* compute LOG_LINKS */
+ for (bb = 0; bb < current_nr_blocks; bb++)
+ compute_block_backward_dependences (bb);
+
+ /* compute INSN_DEPEND */
+ for (bb = current_nr_blocks - 1; bb >= 0; bb--)
+ compute_block_forward_dependences (bb);
+
+ /* Delete line notes, compute live-regs at block end, and set priorities. */
+ dead_notes = 0;
+ for (bb = 0; bb < current_nr_blocks; bb++)
+ {
+ if (reload_completed == 0)
+ find_pre_sched_live (bb);
+
+ if (write_symbols != NO_DEBUG)
+ {
+ save_line_notes (bb);
+ rm_line_notes (bb);
+ }
+
+ rgn_n_insns += set_priorities (bb);
+ }
+
+ /* compute interblock info: probabilities, split-edges, dominators, etc. */
+ if (current_nr_blocks > 1)
+ {
+ int i;
+
+ prob = (float *) alloca ((current_nr_blocks) * sizeof (float));
+
+ bbset_size = current_nr_blocks / HOST_BITS_PER_WIDE_INT + 1;
+ dom = (bbset *) alloca (current_nr_blocks * sizeof (bbset));
+ for (i = 0; i < current_nr_blocks; i++)
+ {
+ dom[i] = (bbset) alloca (bbset_size * sizeof (HOST_WIDE_INT));
+ bzero ((char *) dom[i], bbset_size * sizeof (HOST_WIDE_INT));
+ }
+
+ /* edge to bit */
+ rgn_nr_edges = 0;
+ edge_to_bit = (int *) alloca (nr_edges * sizeof (int));
+ for (i = 1; i < nr_edges; i++)
+ if (CONTAINING_RGN (FROM_BLOCK (i)) == rgn)
+ EDGE_TO_BIT (i) = rgn_nr_edges++;
+ rgn_edges = (int *) alloca (rgn_nr_edges * sizeof (int));
+
+ rgn_nr_edges = 0;
+ for (i = 1; i < nr_edges; i++)
+ if (CONTAINING_RGN (FROM_BLOCK (i)) == (rgn))
+ rgn_edges[rgn_nr_edges++] = i;
+
+ /* split edges */
+ edgeset_size = rgn_nr_edges / HOST_BITS_PER_WIDE_INT + 1;
+ pot_split = (edgeset *) alloca (current_nr_blocks * sizeof (edgeset));
+ ancestor_edges = (edgeset *) alloca (current_nr_blocks * sizeof (edgeset));
+ for (i = 0; i < current_nr_blocks; i++)
+ {
+ pot_split[i] =
+ (edgeset) alloca (edgeset_size * sizeof (HOST_WIDE_INT));
+ bzero ((char *) pot_split[i],
+ edgeset_size * sizeof (HOST_WIDE_INT));
+ ancestor_edges[i] =
+ (edgeset) alloca (edgeset_size * sizeof (HOST_WIDE_INT));
+ bzero ((char *) ancestor_edges[i],
+ edgeset_size * sizeof (HOST_WIDE_INT));
+ }
+
+ /* compute probabilities, dominators, split_edges */
+ for (bb = 0; bb < current_nr_blocks; bb++)
+ compute_dom_prob_ps (bb);
+ }
+
+ /* now we can schedule all blocks */
+ for (bb = 0; bb < current_nr_blocks; bb++)
+ {
+ sched_rgn_n_insns += schedule_block (bb, rgn_n_insns);
+
+#ifdef USE_C_ALLOCA
+ alloca (0);
+#endif
+ }
+
+ /* sanity check: verify that all region insns were scheduled */
+ if (sched_rgn_n_insns != rgn_n_insns)
+ abort ();
+
+ /* update register life and usage information */
+ if (reload_completed == 0)
+ {
+ for (bb = current_nr_blocks - 1; bb >= 0; bb--)
+ find_post_sched_live (bb);
+
+ if (current_nr_blocks <= 1)
+ /* Sanity check. There should be no REG_DEAD notes leftover at the end.
+ In practice, this can occur as the result of bugs in flow, combine.c,
+ and/or sched.c. The values of the REG_DEAD notes remaining are
+ meaningless, because dead_notes is just used as a free list. */
+ if (dead_notes != 0)
+ abort ();
+ }
+
+ /* restore line notes. */
+ if (write_symbols != NO_DEBUG)
+ {
+ for (bb = 0; bb < current_nr_blocks; bb++)
+ restore_line_notes (bb);
+ }
+
+ /* Done with this region */
+ free_pending_lists ();
+
+ FREE_REG_SET (reg_pending_sets);
+}
+
+/* Subroutine of split_hard_reg_notes. Searches X for any reference to
+ REGNO, returning the rtx of the reference found if any. Otherwise,
+ returns 0. */
+
+static rtx
+regno_use_in (regno, x)
+ int regno;
+ rtx x;
+{
+ register char *fmt;
+ int i, j;
+ rtx tem;
+
+ if (GET_CODE (x) == REG && REGNO (x) == regno)
+ return x;
+
+ fmt = GET_RTX_FORMAT (GET_CODE (x));
+ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if ((tem = regno_use_in (regno, XEXP (x, i))))
+ return tem;
+ }
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if ((tem = regno_use_in (regno, XVECEXP (x, i, j))))
+ return tem;
+ }
+
+ return 0;
+}
+
+/* Subroutine of update_flow_info. Determines whether any new REG_NOTEs are
+ needed for the hard register mentioned in the note. This can happen
+ if the reference to the hard register in the original insn was split into
+ several smaller hard register references in the split insns. */
+
+static void
+split_hard_reg_notes (note, first, last)
+ rtx note, first, last;
+{
+ rtx reg, temp, link;
+ int n_regs, i, new_reg;
+ rtx insn;
+
+ /* Assume that this is a REG_DEAD note. */
+ if (REG_NOTE_KIND (note) != REG_DEAD)
+ abort ();
+
+ reg = XEXP (note, 0);
+
+ n_regs = HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg));
+
+ for (i = 0; i < n_regs; i++)
+ {
+ new_reg = REGNO (reg) + i;
+
+ /* Check for references to new_reg in the split insns. */
+ for (insn = last;; insn = PREV_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && (temp = regno_use_in (new_reg, PATTERN (insn))))
+ {
+ /* Create a new reg dead note ere. */
+ link = alloc_EXPR_LIST (REG_DEAD, temp, REG_NOTES (insn));
+ REG_NOTES (insn) = link;
+
+ /* If killed multiple registers here, then add in the excess. */
+ i += HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) - 1;
+
+ break;
+ }
+ /* It isn't mentioned anywhere, so no new reg note is needed for
+ this register. */
+ if (insn == first)
+ break;
+ }
+ }
+}
+
+/* Subroutine of update_flow_info. Determines whether a SET or CLOBBER in an
+ insn created by splitting needs a REG_DEAD or REG_UNUSED note added. */
+
+static void
+new_insn_dead_notes (pat, insn, last, orig_insn)
+ rtx pat, insn, last, orig_insn;
+{
+ rtx dest, tem, set;
+
+ /* PAT is either a CLOBBER or a SET here. */
+ dest = XEXP (pat, 0);
+
+ while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == STRICT_LOW_PART
+ || GET_CODE (dest) == SIGN_EXTRACT)
+ dest = XEXP (dest, 0);
+
+ if (GET_CODE (dest) == REG)
+ {
+ /* If the original insn already used this register, we may not add new
+ notes for it. One example for a split that needs this test is
+ when a multi-word memory access with register-indirect addressing
+ is split into multiple memory accesses with auto-increment and
+ one adjusting add instruction for the address register. */
+ if (reg_referenced_p (dest, PATTERN (orig_insn)))
+ return;
+ for (tem = last; tem != insn; tem = PREV_INSN (tem))
+ {
+ if (GET_RTX_CLASS (GET_CODE (tem)) == 'i'
+ && reg_overlap_mentioned_p (dest, PATTERN (tem))
+ && (set = single_set (tem)))
+ {
+ rtx tem_dest = SET_DEST (set);
+
+ while (GET_CODE (tem_dest) == ZERO_EXTRACT
+ || GET_CODE (tem_dest) == SUBREG
+ || GET_CODE (tem_dest) == STRICT_LOW_PART
+ || GET_CODE (tem_dest) == SIGN_EXTRACT)
+ tem_dest = XEXP (tem_dest, 0);
+
+ if (!rtx_equal_p (tem_dest, dest))
+ {
+ /* Use the same scheme as combine.c, don't put both REG_DEAD
+ and REG_UNUSED notes on the same insn. */
+ if (!find_regno_note (tem, REG_UNUSED, REGNO (dest))
+ && !find_regno_note (tem, REG_DEAD, REGNO (dest)))
+ {
+ rtx note = alloc_EXPR_LIST (REG_DEAD, dest,
+ REG_NOTES (tem));
+ REG_NOTES (tem) = note;
+ }
+ /* The reg only dies in one insn, the last one that uses
+ it. */
+ break;
+ }
+ else if (reg_overlap_mentioned_p (dest, SET_SRC (set)))
+ /* We found an instruction that both uses the register,
+ and sets it, so no new REG_NOTE is needed for this set. */
+ break;
+ }
+ }
+ /* If this is a set, it must die somewhere, unless it is the dest of
+ the original insn, and hence is live after the original insn. Abort
+ if it isn't supposed to be live after the original insn.
+
+ If this is a clobber, then just add a REG_UNUSED note. */
+ if (tem == insn)
+ {
+ int live_after_orig_insn = 0;
+ rtx pattern = PATTERN (orig_insn);
+ int i;
+
+ if (GET_CODE (pat) == CLOBBER)
+ {
+ rtx note = alloc_EXPR_LIST (REG_UNUSED, dest, REG_NOTES (insn));
+ REG_NOTES (insn) = note;
+ return;
+ }
+
+ /* The original insn could have multiple sets, so search the
+ insn for all sets. */
+ if (GET_CODE (pattern) == SET)
+ {
+ if (reg_overlap_mentioned_p (dest, SET_DEST (pattern)))
+ live_after_orig_insn = 1;
+ }
+ else if (GET_CODE (pattern) == PARALLEL)
+ {
+ for (i = 0; i < XVECLEN (pattern, 0); i++)
+ if (GET_CODE (XVECEXP (pattern, 0, i)) == SET
+ && reg_overlap_mentioned_p (dest,
+ SET_DEST (XVECEXP (pattern,
+ 0, i))))
+ live_after_orig_insn = 1;
+ }
+
+ if (!live_after_orig_insn)
+ abort ();
+ }
+ }
+}
+
+/* Subroutine of update_flow_info. Update the value of reg_n_sets for all
+ registers modified by X. INC is -1 if the containing insn is being deleted,
+ and is 1 if the containing insn is a newly generated insn. */
+
+static void
+update_n_sets (x, inc)
+ rtx x;
+ int inc;
+{
+ rtx dest = SET_DEST (x);
+
+ while (GET_CODE (dest) == STRICT_LOW_PART || GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
+ dest = SUBREG_REG (dest);
+
+ if (GET_CODE (dest) == REG)
+ {
+ int regno = REGNO (dest);
+
+ if (regno < FIRST_PSEUDO_REGISTER)
+ {
+ register int i;
+ int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (dest));
+
+ for (i = regno; i < endregno; i++)
+ REG_N_SETS (i) += inc;
+ }
+ else
+ REG_N_SETS (regno) += inc;
+ }
+}
+
+/* Updates all flow-analysis related quantities (including REG_NOTES) for
+ the insns from FIRST to LAST inclusive that were created by splitting
+ ORIG_INSN. NOTES are the original REG_NOTES. */
+
+static void
+update_flow_info (notes, first, last, orig_insn)
+ rtx notes;
+ rtx first, last;
+ rtx orig_insn;
+{
+ rtx insn, note;
+ rtx next;
+ rtx orig_dest, temp;
+ rtx set;
+
+ /* Get and save the destination set by the original insn. */
+
+ orig_dest = single_set (orig_insn);
+ if (orig_dest)
+ orig_dest = SET_DEST (orig_dest);
+
+ /* Move REG_NOTES from the original insn to where they now belong. */
+
+ for (note = notes; note; note = next)
+ {
+ next = XEXP (note, 1);
+ switch (REG_NOTE_KIND (note))
+ {
+ case REG_DEAD:
+ case REG_UNUSED:
+ /* Move these notes from the original insn to the last new insn where
+ the register is now set. */
+
+ for (insn = last;; insn = PREV_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+ {
+ /* If this note refers to a multiple word hard register, it
+ may have been split into several smaller hard register
+ references, so handle it specially. */
+ temp = XEXP (note, 0);
+ if (REG_NOTE_KIND (note) == REG_DEAD
+ && GET_CODE (temp) == REG
+ && REGNO (temp) < FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_NREGS (REGNO (temp), GET_MODE (temp)) > 1)
+ split_hard_reg_notes (note, first, last);
+ else
+ {
+ XEXP (note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = note;
+ }
+
+ /* Sometimes need to convert REG_UNUSED notes to REG_DEAD
+ notes. */
+ /* ??? This won't handle multiple word registers correctly,
+ but should be good enough for now. */
+ if (REG_NOTE_KIND (note) == REG_UNUSED
+ && GET_CODE (XEXP (note, 0)) != SCRATCH
+ && !dead_or_set_p (insn, XEXP (note, 0)))
+ PUT_REG_NOTE_KIND (note, REG_DEAD);
+
+ /* The reg only dies in one insn, the last one that uses
+ it. */
+ break;
+ }
+ /* It must die somewhere, fail it we couldn't find where it died.
+
+ If this is a REG_UNUSED note, then it must be a temporary
+ register that was not needed by this instantiation of the
+ pattern, so we can safely ignore it. */
+ if (insn == first)
+ {
+ /* After reload, REG_DEAD notes come sometimes an
+ instruction after the register actually dies. */
+ if (reload_completed && REG_NOTE_KIND (note) == REG_DEAD)
+ {
+ XEXP (note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = note;
+ break;
+ }
+
+ if (REG_NOTE_KIND (note) != REG_UNUSED)
+ abort ();
+
+ break;
+ }
+ }
+ break;
+
+ case REG_WAS_0:
+ /* If the insn that set the register to 0 was deleted, this
+ note cannot be relied on any longer. The destination might
+ even have been moved to memory.
+ This was observed for SH4 with execute/920501-6.c compilation,
+ -O2 -fomit-frame-pointer -finline-functions . */
+ if (GET_CODE (XEXP (note, 0)) == NOTE
+ || INSN_DELETED_P (XEXP (note, 0)))
+ break;
+ /* This note applies to the dest of the original insn. Find the
+ first new insn that now has the same dest, and move the note
+ there. */
+
+ if (!orig_dest)
+ abort ();
+
+ for (insn = first;; insn = NEXT_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && (temp = single_set (insn))
+ && rtx_equal_p (SET_DEST (temp), orig_dest))
+ {
+ XEXP (note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = note;
+ /* The reg is only zero before one insn, the first that
+ uses it. */
+ break;
+ }
+ /* If this note refers to a multiple word hard
+ register, it may have been split into several smaller
+ hard register references. We could split the notes,
+ but simply dropping them is good enough. */
+ if (GET_CODE (orig_dest) == REG
+ && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_NREGS (REGNO (orig_dest),
+ GET_MODE (orig_dest)) > 1)
+ break;
+ /* It must be set somewhere, fail if we couldn't find where it
+ was set. */
+ if (insn == last)
+ abort ();
+ }
+ break;
+
+ case REG_EQUAL:
+ case REG_EQUIV:
+ /* A REG_EQUIV or REG_EQUAL note on an insn with more than one
+ set is meaningless. Just drop the note. */
+ if (!orig_dest)
+ break;
+
+ case REG_NO_CONFLICT:
+ /* These notes apply to the dest of the original insn. Find the last
+ new insn that now has the same dest, and move the note there. */
+
+ if (!orig_dest)
+ abort ();
+
+ for (insn = last;; insn = PREV_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && (temp = single_set (insn))
+ && rtx_equal_p (SET_DEST (temp), orig_dest))
+ {
+ XEXP (note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = note;
+ /* Only put this note on one of the new insns. */
+ break;
+ }
+
+ /* The original dest must still be set someplace. Abort if we
+ couldn't find it. */
+ if (insn == first)
+ {
+ /* However, if this note refers to a multiple word hard
+ register, it may have been split into several smaller
+ hard register references. We could split the notes,
+ but simply dropping them is good enough. */
+ if (GET_CODE (orig_dest) == REG
+ && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_NREGS (REGNO (orig_dest),
+ GET_MODE (orig_dest)) > 1)
+ break;
+ /* Likewise for multi-word memory references. */
+ if (GET_CODE (orig_dest) == MEM
+ && SIZE_FOR_MODE (orig_dest) > UNITS_PER_WORD)
+ break;
+ abort ();
+ }
+ }
+ break;
+
+ case REG_LIBCALL:
+ /* Move a REG_LIBCALL note to the first insn created, and update
+ the corresponding REG_RETVAL note. */
+ XEXP (note, 1) = REG_NOTES (first);
+ REG_NOTES (first) = note;
+
+ insn = XEXP (note, 0);
+ note = find_reg_note (insn, REG_RETVAL, NULL_RTX);
+ if (note)
+ XEXP (note, 0) = first;
+ break;
+
+ case REG_EXEC_COUNT:
+ /* Move a REG_EXEC_COUNT note to the first insn created. */
+ XEXP (note, 1) = REG_NOTES (first);
+ REG_NOTES (first) = note;
+ break;
+
+ case REG_RETVAL:
+ /* Move a REG_RETVAL note to the last insn created, and update
+ the corresponding REG_LIBCALL note. */
+ XEXP (note, 1) = REG_NOTES (last);
+ REG_NOTES (last) = note;
+
+ insn = XEXP (note, 0);
+ note = find_reg_note (insn, REG_LIBCALL, NULL_RTX);
+ if (note)
+ XEXP (note, 0) = last;
+ break;
+
+ case REG_NONNEG:
+ case REG_BR_PROB:
+ /* This should be moved to whichever instruction is a JUMP_INSN. */
+
+ for (insn = last;; insn = PREV_INSN (insn))
+ {
+ if (GET_CODE (insn) == JUMP_INSN)
+ {
+ XEXP (note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = note;
+ /* Only put this note on one of the new insns. */
+ break;
+ }
+ /* Fail if we couldn't find a JUMP_INSN. */
+ if (insn == first)
+ abort ();
+ }
+ break;
+
+ case REG_INC:
+ /* reload sometimes leaves obsolete REG_INC notes around. */
+ if (reload_completed)
+ break;
+ /* This should be moved to whichever instruction now has the
+ increment operation. */
+ abort ();
+
+ case REG_LABEL:
+ /* Should be moved to the new insn(s) which use the label. */
+ for (insn = first; insn != NEXT_INSN (last); insn = NEXT_INSN (insn))
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
+ {
+ REG_NOTES (insn) = alloc_EXPR_LIST (REG_LABEL,
+ XEXP (note, 0),
+ REG_NOTES (insn));
+ }
+ break;
+
+ case REG_CC_SETTER:
+ case REG_CC_USER:
+ /* These two notes will never appear until after reorg, so we don't
+ have to handle them here. */
+ default:
+ abort ();
+ }
+ }
+
+ /* Each new insn created, except the last, has a new set. If the destination
+ is a register, then this reg is now live across several insns, whereas
+ previously the dest reg was born and died within the same insn. To
+ reflect this, we now need a REG_DEAD note on the insn where this
+ dest reg dies.
+
+ Similarly, the new insns may have clobbers that need REG_UNUSED notes. */
+
+ for (insn = first; insn != last; insn = NEXT_INSN (insn))
+ {
+ rtx pat;
+ int i;
+
+ pat = PATTERN (insn);
+ if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
+ new_insn_dead_notes (pat, insn, last, orig_insn);
+ else if (GET_CODE (pat) == PARALLEL)
+ {
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ if (GET_CODE (XVECEXP (pat, 0, i)) == SET
+ || GET_CODE (XVECEXP (pat, 0, i)) == CLOBBER)
+ new_insn_dead_notes (XVECEXP (pat, 0, i), insn, last, orig_insn);
+ }
+ }
+
+ /* If any insn, except the last, uses the register set by the last insn,
+ then we need a new REG_DEAD note on that insn. In this case, there
+ would not have been a REG_DEAD note for this register in the original
+ insn because it was used and set within one insn. */
+
+ set = single_set (last);
+ if (set)
+ {
+ rtx dest = SET_DEST (set);
+
+ while (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SUBREG
+ || GET_CODE (dest) == STRICT_LOW_PART
+ || GET_CODE (dest) == SIGN_EXTRACT)
+ dest = XEXP (dest, 0);
+
+ if (GET_CODE (dest) == REG
+ /* Global registers are always live, so the code below does not
+ apply to them. */
+ && (REGNO (dest) >= FIRST_PSEUDO_REGISTER
+ || ! global_regs[REGNO (dest)]))
+ {
+ rtx stop_insn = PREV_INSN (first);
+
+ /* If the last insn uses the register that it is setting, then
+ we don't want to put a REG_DEAD note there. Search backwards
+ to find the first insn that sets but does not use DEST. */
+
+ insn = last;
+ if (reg_overlap_mentioned_p (dest, SET_SRC (set)))
+ {
+ for (insn = PREV_INSN (insn); insn != first;
+ insn = PREV_INSN (insn))
+ {
+ if ((set = single_set (insn))
+ && reg_mentioned_p (dest, SET_DEST (set))
+ && ! reg_overlap_mentioned_p (dest, SET_SRC (set)))
+ break;
+ }
+ }
+
+ /* Now find the first insn that uses but does not set DEST. */
+
+ for (insn = PREV_INSN (insn); insn != stop_insn;
+ insn = PREV_INSN (insn))
+ {
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && reg_mentioned_p (dest, PATTERN (insn))
+ && (set = single_set (insn)))
+ {
+ rtx insn_dest = SET_DEST (set);
+
+ while (GET_CODE (insn_dest) == ZERO_EXTRACT
+ || GET_CODE (insn_dest) == SUBREG
+ || GET_CODE (insn_dest) == STRICT_LOW_PART
+ || GET_CODE (insn_dest) == SIGN_EXTRACT)
+ insn_dest = XEXP (insn_dest, 0);
+
+ if (insn_dest != dest)
+ {
+ note = alloc_EXPR_LIST (REG_DEAD, dest, REG_NOTES (insn));
+ REG_NOTES (insn) = note;
+ /* The reg only dies in one insn, the last one
+ that uses it. */
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ /* If the original dest is modifying a multiple register target, and the
+ original instruction was split such that the original dest is now set
+ by two or more SUBREG sets, then the split insns no longer kill the
+ destination of the original insn.
+
+ In this case, if there exists an instruction in the same basic block,
+ before the split insn, which uses the original dest, and this use is
+ killed by the original insn, then we must remove the REG_DEAD note on
+ this insn, because it is now superfluous.
+
+ This does not apply when a hard register gets split, because the code
+ knows how to handle overlapping hard registers properly. */
+ if (orig_dest && GET_CODE (orig_dest) == REG)
+ {
+ int found_orig_dest = 0;
+ int found_split_dest = 0;
+
+ for (insn = first;; insn = NEXT_INSN (insn))
+ {
+ rtx pat;
+ int i;
+
+ /* I'm not sure if this can happen, but let's be safe. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ continue;
+
+ pat = PATTERN (insn);
+ i = GET_CODE (pat) == PARALLEL ? XVECLEN (pat, 0) : 0;
+ set = pat;
+
+ for (;;)
+ {
+ if (GET_CODE (set) == SET)
+ {
+ if (GET_CODE (SET_DEST (set)) == REG
+ && REGNO (SET_DEST (set)) == REGNO (orig_dest))
+ {
+ found_orig_dest = 1;
+ break;
+ }
+ else if (GET_CODE (SET_DEST (set)) == SUBREG
+ && SUBREG_REG (SET_DEST (set)) == orig_dest)
+ {
+ found_split_dest = 1;
+ break;
+ }
+ }
+ if (--i < 0)
+ break;
+ set = XVECEXP (pat, 0, i);
+ }
+
+ if (insn == last)
+ break;
+ }
+
+ if (found_split_dest)
+ {
+ /* Search backwards from FIRST, looking for the first insn that uses
+ the original dest. Stop if we pass a CODE_LABEL or a JUMP_INSN.
+ If we find an insn, and it has a REG_DEAD note, then delete the
+ note. */
+
+ for (insn = first; insn; insn = PREV_INSN (insn))
+ {
+ if (GET_CODE (insn) == CODE_LABEL
+ || GET_CODE (insn) == JUMP_INSN)
+ break;
+ else if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+ && reg_mentioned_p (orig_dest, insn))
+ {
+ note = find_regno_note (insn, REG_DEAD, REGNO (orig_dest));
+ if (note)
+ remove_note (insn, note);
+ }
+ }
+ }
+ else if (!found_orig_dest)
+ {
+ /* This should never happen. */
+ abort ();
+ }
+ }
+
+ /* Update reg_n_sets. This is necessary to prevent local alloc from
+ converting REG_EQUAL notes to REG_EQUIV when splitting has modified
+ a reg from set once to set multiple times. */
+
+ {
+ rtx x = PATTERN (orig_insn);
+ RTX_CODE code = GET_CODE (x);
+
+ if (code == SET || code == CLOBBER)
+ update_n_sets (x, -1);
+ else if (code == PARALLEL)
+ {
+ int i;
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ {
+ code = GET_CODE (XVECEXP (x, 0, i));
+ if (code == SET || code == CLOBBER)
+ update_n_sets (XVECEXP (x, 0, i), -1);
+ }
+ }
+
+ for (insn = first;; insn = NEXT_INSN (insn))
+ {
+ x = PATTERN (insn);
+ code = GET_CODE (x);
+
+ if (code == SET || code == CLOBBER)
+ update_n_sets (x, 1);
+ else if (code == PARALLEL)
+ {
+ int i;
+ for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+ {
+ code = GET_CODE (XVECEXP (x, 0, i));
+ if (code == SET || code == CLOBBER)
+ update_n_sets (XVECEXP (x, 0, i), 1);
+ }
+ }
+
+ if (insn == last)
+ break;
+ }
+ }
+}
+
+/* Do the splitting of insns in the block b. */
+
+static void
+split_block_insns (b)
+ int b;
+{
+ rtx insn, next;
+
+ for (insn = basic_block_head[b];; insn = next)
+ {
+ rtx set, last, first, notes;
+
+ /* Can't use `next_real_insn' because that
+ might go across CODE_LABELS and short-out basic blocks. */
+ next = NEXT_INSN (insn);
+ if (GET_CODE (insn) != INSN)
+ {
+ if (insn == basic_block_end[b])
+ break;
+
+ continue;
+ }
+
+ /* Don't split no-op move insns. These should silently disappear
+ later in final. Splitting such insns would break the code
+ that handles REG_NO_CONFLICT blocks. */
+ set = single_set (insn);
+ if (set && rtx_equal_p (SET_SRC (set), SET_DEST (set)))
+ {
+ if (insn == basic_block_end[b])
+ break;
+
+ /* Nops get in the way while scheduling, so delete them now if
+ register allocation has already been done. It is too risky
+ to try to do this before register allocation, and there are
+ unlikely to be very many nops then anyways. */
+ if (reload_completed)
+ {
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ }
+
+ continue;
+ }
+
+ /* Split insns here to get max fine-grain parallelism. */
+ first = PREV_INSN (insn);
+ notes = REG_NOTES (insn);
+ last = try_split (PATTERN (insn), insn, 1);
+ if (last != insn)
+ {
+ /* try_split returns the NOTE that INSN became. */
+ first = NEXT_INSN (first);
+ update_flow_info (notes, first, last, insn);
+
+ PUT_CODE (insn, NOTE);
+ NOTE_SOURCE_FILE (insn) = 0;
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ if (insn == basic_block_head[b])
+ basic_block_head[b] = first;
+ if (insn == basic_block_end[b])
+ {
+ basic_block_end[b] = last;
+ break;
+ }
+ }
+
+ if (insn == basic_block_end[b])
+ break;
+ }
+}
+
+/* The one entry point in this file. DUMP_FILE is the dump file for
+ this pass. */
+
+void
+schedule_insns (dump_file)
+ FILE *dump_file;
+{
+
+ int max_uid;
+ int b;
+ rtx insn;
+ int rgn;
+
+ int luid;
+
+ /* disable speculative loads in their presence if cc0 defined */
+#ifdef HAVE_cc0
+ flag_schedule_speculative_load = 0;
+#endif
+
+ /* Taking care of this degenerate case makes the rest of
+ this code simpler. */
+ if (n_basic_blocks == 0)
+ return;
+
+ /* set dump and sched_verbose for the desired debugging output. If no
+ dump-file was specified, but -fsched-verbose-N (any N), print to stderr.
+ For -fsched-verbose-N, N>=10, print everything to stderr. */
+ sched_verbose = sched_verbose_param;
+ if (sched_verbose_param == 0 && dump_file)
+ sched_verbose = 1;
+ dump = ((sched_verbose_param >= 10 || !dump_file) ? stderr : dump_file);
+
+ nr_inter = 0;
+ nr_spec = 0;
+
+ /* Initialize the unused_*_lists. We can't use the ones left over from
+ the previous function, because gcc has freed that memory. We can use
+ the ones left over from the first sched pass in the second pass however,
+ so only clear them on the first sched pass. The first pass is before
+ reload if flag_schedule_insns is set, otherwise it is afterwards. */
+
+ if (reload_completed == 0 || !flag_schedule_insns)
+ {
+ unused_insn_list = 0;
+ unused_expr_list = 0;
+ }
+
+ /* initialize issue_rate */
+ issue_rate = ISSUE_RATE;
+
+ /* do the splitting first for all blocks */
+ for (b = 0; b < n_basic_blocks; b++)
+ split_block_insns (b);
+
+ max_uid = (get_max_uid () + 1);
+
+ cant_move = (char *) xmalloc (max_uid * sizeof (char));
+ bzero ((char *) cant_move, max_uid * sizeof (char));
+
+ fed_by_spec_load = (char *) xmalloc (max_uid * sizeof (char));
+ bzero ((char *) fed_by_spec_load, max_uid * sizeof (char));
+
+ is_load_insn = (char *) xmalloc (max_uid * sizeof (char));
+ bzero ((char *) is_load_insn, max_uid * sizeof (char));
+
+ insn_orig_block = (int *) xmalloc (max_uid * sizeof (int));
+ insn_luid = (int *) xmalloc (max_uid * sizeof (int));
+
+ luid = 0;
+ for (b = 0; b < n_basic_blocks; b++)
+ for (insn = basic_block_head[b];; insn = NEXT_INSN (insn))
+ {
+ INSN_BLOCK (insn) = b;
+ INSN_LUID (insn) = luid++;
+
+ if (insn == basic_block_end[b])
+ break;
+ }
+
+ /* after reload, remove inter-blocks dependences computed before reload. */
+ if (reload_completed)
+ {
+ int b;
+ rtx insn;
+
+ for (b = 0; b < n_basic_blocks; b++)
+ for (insn = basic_block_head[b];; insn = NEXT_INSN (insn))
+ {
+ rtx link, prev;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ prev = NULL_RTX;
+ link = LOG_LINKS (insn);
+ while (link)
+ {
+ rtx x = XEXP (link, 0);
+
+ if (INSN_BLOCK (x) != b)
+ {
+ remove_dependence (insn, x);
+ link = prev ? XEXP (prev, 1) : LOG_LINKS (insn);
+ }
+ else
+ prev = link, link = XEXP (prev, 1);
+ }
+ }
+
+ if (insn == basic_block_end[b])
+ break;
+ }
+ }
+
+ nr_regions = 0;
+ rgn_table = (region *) alloca ((n_basic_blocks) * sizeof (region));
+ rgn_bb_table = (int *) alloca ((n_basic_blocks) * sizeof (int));
+ block_to_bb = (int *) alloca ((n_basic_blocks) * sizeof (int));
+ containing_rgn = (int *) alloca ((n_basic_blocks) * sizeof (int));
+
+ /* compute regions for scheduling */
+ if (reload_completed
+ || n_basic_blocks == 1
+ || !flag_schedule_interblock)
+ {
+ find_single_block_region ();
+ }
+ else
+ {
+ /* verify that a 'good' control flow graph can be built */
+ if (is_cfg_nonregular ())
+ {
+ find_single_block_region ();
+ }
+ else
+ {
+ int_list_ptr *s_preds, *s_succs;
+ int *num_preds, *num_succs;
+ sbitmap *dom, *pdom;
+
+ s_preds = (int_list_ptr *) alloca (n_basic_blocks
+ * sizeof (int_list_ptr));
+ s_succs = (int_list_ptr *) alloca (n_basic_blocks
+ * sizeof (int_list_ptr));
+ num_preds = (int *) alloca (n_basic_blocks * sizeof (int));
+ num_succs = (int *) alloca (n_basic_blocks * sizeof (int));
+ dom = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
+ pdom = sbitmap_vector_alloc (n_basic_blocks, n_basic_blocks);
+
+ /* The scheduler runs after flow; therefore, we can't blindly call
+ back into find_basic_blocks since doing so could invalidate the
+ info in basic_block_live_at_start.
+
+ Consider a block consisting entirely of dead stores; after life
+ analysis it would be a block of NOTE_INSN_DELETED notes. If
+ we call find_basic_blocks again, then the block would be removed
+ entirely and invalidate our the register live information.
+
+ We could (should?) recompute register live information. Doing
+ so may even be beneficial. */
+
+ compute_preds_succs (s_preds, s_succs, num_preds, num_succs);
+
+ /* Compute the dominators and post dominators. We don't currently use
+ post dominators, but we should for speculative motion analysis. */
+ compute_dominators (dom, pdom, s_preds, s_succs);
+
+ /* build_control_flow will return nonzero if it detects unreachable
+ blocks or any other irregularity with the cfg which prevents
+ cross block scheduling. */
+ if (build_control_flow (s_preds, s_succs, num_preds, num_succs) != 0)
+ find_single_block_region ();
+ else
+ find_rgns (s_preds, s_succs, num_preds, num_succs, dom);
+
+ if (sched_verbose >= 3)
+ debug_regions ();
+
+ /* For now. This will move as more and more of haifa is converted
+ to using the cfg code in flow.c */
+ free_bb_mem ();
+ free (dom);
+ free (pdom);
+ }
+ }
+
+ /* Allocate data for this pass. See comments, above,
+ for what these vectors do.
+
+ We use xmalloc instead of alloca, because max_uid can be very large
+ when there is a lot of function inlining. If we used alloca, we could
+ exceed stack limits on some hosts for some inputs. */
+ insn_priority = (int *) xmalloc (max_uid * sizeof (int));
+ insn_reg_weight = (int *) xmalloc (max_uid * sizeof (int));
+ insn_tick = (int *) xmalloc (max_uid * sizeof (int));
+ insn_costs = (short *) xmalloc (max_uid * sizeof (short));
+ insn_units = (short *) xmalloc (max_uid * sizeof (short));
+ insn_blockage = (unsigned int *) xmalloc (max_uid * sizeof (unsigned int));
+ insn_ref_count = (int *) xmalloc (max_uid * sizeof (int));
+
+ /* Allocate for forward dependencies */
+ insn_dep_count = (int *) xmalloc (max_uid * sizeof (int));
+ insn_depend = (rtx *) xmalloc (max_uid * sizeof (rtx));
+
+ if (reload_completed == 0)
+ {
+ int i;
+
+ sched_reg_n_calls_crossed = (int *) alloca (max_regno * sizeof (int));
+ sched_reg_live_length = (int *) alloca (max_regno * sizeof (int));
+ sched_reg_basic_block = (int *) alloca (max_regno * sizeof (int));
+ bb_live_regs = ALLOCA_REG_SET ();
+ bzero ((char *) sched_reg_n_calls_crossed, max_regno * sizeof (int));
+ bzero ((char *) sched_reg_live_length, max_regno * sizeof (int));
+
+ for (i = 0; i < max_regno; i++)
+ sched_reg_basic_block[i] = REG_BLOCK_UNKNOWN;
+ }
+ else
+ {
+ sched_reg_n_calls_crossed = 0;
+ sched_reg_live_length = 0;
+ bb_live_regs = 0;
+ }
+ init_alias_analysis ();
+
+ if (write_symbols != NO_DEBUG)
+ {
+ rtx line;
+
+ line_note = (rtx *) xmalloc (max_uid * sizeof (rtx));
+ bzero ((char *) line_note, max_uid * sizeof (rtx));
+ line_note_head = (rtx *) alloca (n_basic_blocks * sizeof (rtx));
+ bzero ((char *) line_note_head, n_basic_blocks * sizeof (rtx));
+
+ /* Save-line-note-head:
+ Determine the line-number at the start of each basic block.
+ This must be computed and saved now, because after a basic block's
+ predecessor has been scheduled, it is impossible to accurately
+ determine the correct line number for the first insn of the block. */
+
+ for (b = 0; b < n_basic_blocks; b++)
+ for (line = basic_block_head[b]; line; line = PREV_INSN (line))
+ if (GET_CODE (line) == NOTE && NOTE_LINE_NUMBER (line) > 0)
+ {
+ line_note_head[b] = line;
+ break;
+ }
+ }
+
+ bzero ((char *) insn_priority, max_uid * sizeof (int));
+ bzero ((char *) insn_reg_weight, max_uid * sizeof (int));
+ bzero ((char *) insn_tick, max_uid * sizeof (int));
+ bzero ((char *) insn_costs, max_uid * sizeof (short));
+ bzero ((char *) insn_units, max_uid * sizeof (short));
+ bzero ((char *) insn_blockage, max_uid * sizeof (unsigned int));
+ bzero ((char *) insn_ref_count, max_uid * sizeof (int));
+
+ /* Initialize for forward dependencies */
+ bzero ((char *) insn_depend, max_uid * sizeof (rtx));
+ bzero ((char *) insn_dep_count, max_uid * sizeof (int));
+
+ /* Find units used in this fuction, for visualization */
+ if (sched_verbose)
+ init_target_units ();
+
+ /* ??? Add a NOTE after the last insn of the last basic block. It is not
+ known why this is done. */
+
+ insn = basic_block_end[n_basic_blocks - 1];
+ if (NEXT_INSN (insn) == 0
+ || (GET_CODE (insn) != NOTE
+ && GET_CODE (insn) != CODE_LABEL
+ /* Don't emit a NOTE if it would end up between an unconditional
+ jump and a BARRIER. */
+ && !(GET_CODE (insn) == JUMP_INSN
+ && GET_CODE (NEXT_INSN (insn)) == BARRIER)))
+ emit_note_after (NOTE_INSN_DELETED, basic_block_end[n_basic_blocks - 1]);
+
+ /* Schedule every region in the subroutine */
+ for (rgn = 0; rgn < nr_regions; rgn++)
+ {
+ schedule_region (rgn);
+
+#ifdef USE_C_ALLOCA
+ alloca (0);
+#endif
+ }
+
+ /* Reposition the prologue and epilogue notes in case we moved the
+ prologue/epilogue insns. */
+ if (reload_completed)
+ reposition_prologue_and_epilogue_notes (get_insns ());
+
+ /* delete redundant line notes. */
+ if (write_symbols != NO_DEBUG)
+ rm_redundant_line_notes ();
+
+ /* Update information about uses of registers in the subroutine. */
+ if (reload_completed == 0)
+ update_reg_usage ();
+
+ if (sched_verbose)
+ {
+ if (reload_completed == 0 && flag_schedule_interblock)
+ {
+ fprintf (dump, "\n;; Procedure interblock/speculative motions == %d/%d \n",
+ nr_inter, nr_spec);
+ }
+ else
+ {
+ if (nr_inter > 0)
+ abort ();
+ }
+ fprintf (dump, "\n\n");
+ }
+
+ free (cant_move);
+ free (fed_by_spec_load);
+ free (is_load_insn);
+ free (insn_orig_block);
+ free (insn_luid);
+
+ free (insn_priority);
+ free (insn_reg_weight);
+ free (insn_tick);
+ free (insn_costs);
+ free (insn_units);
+ free (insn_blockage);
+ free (insn_ref_count);
+
+ free (insn_dep_count);
+ free (insn_depend);
+
+ if (write_symbols != NO_DEBUG)
+ free (line_note);
+
+ if (bb_live_regs)
+ FREE_REG_SET (bb_live_regs);
+
+ if (edge_table)
+ {
+ free (edge_table);
+ edge_table = NULL;
+ }
+
+ if (in_edges)
+ {
+ free (in_edges);
+ in_edges = NULL;
+ }
+ if (out_edges)
+ {
+ free (out_edges);
+ out_edges = NULL;
+ }
+}
+#endif /* INSN_SCHEDULING */
diff --git a/contrib/gcc/halfpic.c b/contrib/gcc/halfpic.c
index d4ae36e..2c19c55 100644
--- a/contrib/gcc/halfpic.c
+++ b/contrib/gcc/halfpic.c
@@ -1,5 +1,5 @@
/* OSF/rose half-pic support functions.
- Copyright (C) 1992 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -32,16 +32,15 @@ Boston, MA 02111-1307, USA. */
#ifdef HALF_PIC_INIT
+#include "system.h"
#include "tree.h"
#include "rtl.h"
-#include <stdio.h>
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern char *xmalloc ();
-extern void free ();
extern rtx eliminate_constant_term ();
extern void assemble_name ();
extern void output_addr_const ();
@@ -135,7 +134,7 @@ half_pic_hash (name, len, create_p)
/* name not in hash table. */
if (!create_p)
- return (struct all_refs *)0;
+ return (struct all_refs *) 0;
ptr = (struct all_refs *) obstack_alloc (&half_pic_obstack, sizeof (struct all_refs));
*ptr = zero_all_refs;
@@ -144,7 +143,7 @@ half_pic_hash (name, len, create_p)
ptr->real_len = len;
/* Update circular links. */
- if (first == (struct all_refs *)0)
+ if (first == (struct all_refs *) 0)
ptr->hash_next = ptr;
else
@@ -188,7 +187,7 @@ half_pic_finish (stream)
if (p->pointer_p)
{
ASM_OUTPUT_LABEL (stream, p->ref_name);
- ASM_OUTPUT_INT (stream, gen_rtx (SYMBOL_REF, Pmode, p->real_name));
+ ASM_OUTPUT_INT (stream, gen_rtx_SYMBOL_REF (Pmode, p->real_name));
}
}
}
@@ -342,7 +341,7 @@ half_pic_address_p (addr)
return FALSE;
ptr = half_pic_hash (name, len, FALSE);
- if (ptr == (struct all_refs *)0)
+ if (ptr == (struct all_refs *) 0)
return FALSE;
if (ptr->external_p)
@@ -376,7 +375,7 @@ half_pic_ptr (operand)
name = XSTR (operand, 0);
len = strlen (name);
p = half_pic_hash (name, len, FALSE);
- if (p == (struct all_refs *)0 || !p->external_p)
+ if (p == (struct all_refs *) 0 || !p->external_p)
return operand;
if (!p->pointer_p)
@@ -394,7 +393,7 @@ half_pic_ptr (operand)
}
half_pic_number_refs++;
- return gen_rtx (SYMBOL_REF, Pmode, p->ref_name);
+ return gen_rtx_SYMBOL_REF (Pmode, p->ref_name);
}
#endif /* HALF_PIC_INIT */
diff --git a/contrib/gcc/halfpic.h b/contrib/gcc/halfpic.h
index 10f6972..80e6543 100644
--- a/contrib/gcc/halfpic.h
+++ b/contrib/gcc/halfpic.h
@@ -1,5 +1,5 @@
/* OSF/rose half-pic support definitions.
- Copyright (C) 1992 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1996, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,22 +20,7 @@ Boston, MA 02111-1307, USA. */
#ifndef NO_HALF_PIC
-/* Add prototype support. */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
-#if !defined(STDIO_PROTO) && !defined(NO_STDIO_H)
-#ifndef BUFSIZ
-#include <stdio.h>
-#endif
-
-#define STDIO_PROTO(ARGS) PROTO(ARGS)
-#endif
+#include "gansidecl.h"
#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
union tree_node; /* forward reference */
@@ -47,7 +32,7 @@ struct rtx_def;
strict ANSI). This is because rtl.c now refers to the
CONSTANT_ADDRESS_P macro, which in turn refers to flag_half_pic,
and wants to call half_pic_address_p, whose address we also store
- in in a BSS variable. This way, the gen* programs won't get
+ in a BSS variable. This way, the gen* programs won't get
unknown symbol errors when being linked (flag_half_pic will never
be true in the gen* programs). */
@@ -62,9 +47,8 @@ extern void half_pic_external PROTO((char *)); /* declare object external */
extern void half_pic_init PROTO((void)); /* half_pic initialization */
extern int half_pic_address_p PROTO((struct rtx_def *)); /* true if an address is half-pic */
extern struct rtx_def *half_pic_ptr PROTO((struct rtx_def *)); /* return RTX for half-pic pointer */
-#ifdef STDIO_PROTO
-extern void half_pic_finish STDIO_PROTO((FILE *)); /* half_pic termination */
-#endif
+/* Can't use prototype since FILE isn't defined yet. */
+extern void half_pic_finish (/* FILE * */); /* half_pic termination */
/* Macros to provide access to the half-pic stuff (so they can easily
be stubbed out. */
diff --git a/contrib/gcc/hard-reg-set.h b/contrib/gcc/hard-reg-set.h
index 084785e..5064dbc 100644
--- a/contrib/gcc/hard-reg-set.h
+++ b/contrib/gcc/hard-reg-set.h
@@ -123,6 +123,199 @@ typedef HARD_REG_ELT_TYPE HARD_REG_SET[HARD_REG_SET_LONGS];
((SET)[(BIT) / UHOST_BITS_PER_WIDE_INT] \
& (HARD_CONST (1) << ((BIT) % UHOST_BITS_PER_WIDE_INT)))
+#if FIRST_PSEUDO_REGISTER <= 2*HOST_BITS_PER_WIDE_INT
+#define CLEAR_HARD_REG_SET(TO) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO); \
+ scan_tp_[0] = 0; \
+ scan_tp_[1] = 0; } while (0)
+
+#define SET_HARD_REG_SET(TO) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO); \
+ scan_tp_[0] = -1; \
+ scan_tp_[1] = -1; } while (0)
+
+#define COPY_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] = scan_fp_[0]; \
+ scan_tp_[1] = scan_fp_[1]; } while (0)
+
+#define COMPL_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] = ~ scan_fp_[0]; \
+ scan_tp_[1] = ~ scan_fp_[1]; } while (0)
+
+#define AND_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] &= scan_fp_[0]; \
+ scan_tp_[1] &= scan_fp_[1]; } while (0)
+
+#define AND_COMPL_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] &= ~ scan_fp_[0]; \
+ scan_tp_[1] &= ~ scan_fp_[1]; } while (0)
+
+#define IOR_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] |= scan_fp_[0]; \
+ scan_tp_[1] |= scan_fp_[1]; } while (0)
+
+#define IOR_COMPL_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] |= ~ scan_fp_[0]; \
+ scan_tp_[1] |= ~ scan_fp_[1]; } while (0)
+
+#define GO_IF_HARD_REG_SUBSET(X,Y,TO) \
+do { register HARD_REG_ELT_TYPE *scan_xp_ = (X), *scan_yp_ = (Y); \
+ if ((0 == (scan_xp_[0] & ~ scan_yp_[0])) \
+ && (0 == (scan_xp_[1] & ~ scan_yp_[1]))) \
+ goto TO; } while (0)
+
+#define GO_IF_HARD_REG_EQUAL(X,Y,TO) \
+do { register HARD_REG_ELT_TYPE *scan_xp_ = (X), *scan_yp_ = (Y); \
+ if ((scan_xp_[0] == scan_yp_[0]) \
+ && (scan_xp_[1] == scan_yp_[1])) \
+ goto TO; } while (0)
+
+#else
+#if FIRST_PSEUDO_REGISTER <= 3*HOST_BITS_PER_WIDE_INT
+#define CLEAR_HARD_REG_SET(TO) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO); \
+ scan_tp_[0] = 0; \
+ scan_tp_[1] = 0; \
+ scan_tp_[2] = 0; } while (0)
+
+#define SET_HARD_REG_SET(TO) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO); \
+ scan_tp_[0] = -1; \
+ scan_tp_[1] = -1; \
+ scan_tp_[2] = -1; } while (0)
+
+#define COPY_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] = scan_fp_[0]; \
+ scan_tp_[1] = scan_fp_[1]; \
+ scan_tp_[2] = scan_fp_[2]; } while (0)
+
+#define COMPL_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] = ~ scan_fp_[0]; \
+ scan_tp_[1] = ~ scan_fp_[1]; \
+ scan_tp_[2] = ~ scan_fp_[2]; } while (0)
+
+#define AND_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] &= scan_fp_[0]; \
+ scan_tp_[1] &= scan_fp_[1]; \
+ scan_tp_[2] &= scan_fp_[2]; } while (0)
+
+#define AND_COMPL_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] &= ~ scan_fp_[0]; \
+ scan_tp_[1] &= ~ scan_fp_[1]; \
+ scan_tp_[2] &= ~ scan_fp_[2]; } while (0)
+
+#define IOR_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] |= scan_fp_[0]; \
+ scan_tp_[1] |= scan_fp_[1]; \
+ scan_tp_[2] |= scan_fp_[2]; } while (0)
+
+#define IOR_COMPL_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] |= ~ scan_fp_[0]; \
+ scan_tp_[1] |= ~ scan_fp_[1]; \
+ scan_tp_[2] |= ~ scan_fp_[2]; } while (0)
+
+#define GO_IF_HARD_REG_SUBSET(X,Y,TO) \
+do { register HARD_REG_ELT_TYPE *scan_xp_ = (X), *scan_yp_ = (Y); \
+ if ((0 == (scan_xp_[0] & ~ scan_yp_[0])) \
+ && (0 == (scan_xp_[1] & ~ scan_yp_[1])) \
+ && (0 == (scan_xp_[2] & ~ scan_yp_[2]))) \
+ goto TO; } while (0)
+
+#define GO_IF_HARD_REG_EQUAL(X,Y,TO) \
+do { register HARD_REG_ELT_TYPE *scan_xp_ = (X), *scan_yp_ = (Y); \
+ if ((scan_xp_[0] == scan_yp_[0]) \
+ && (scan_xp_[1] == scan_yp_[1]) \
+ && (scan_xp_[2] == scan_yp_[2])) \
+ goto TO; } while (0)
+
+#else
+#if FIRST_PSEUDO_REGISTER <= 4*HOST_BITS_PER_WIDE_INT
+#define CLEAR_HARD_REG_SET(TO) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO); \
+ scan_tp_[0] = 0; \
+ scan_tp_[1] = 0; \
+ scan_tp_[2] = 0; \
+ scan_tp_[3] = 0; } while (0)
+
+#define SET_HARD_REG_SET(TO) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO); \
+ scan_tp_[0] = -1; \
+ scan_tp_[1] = -1; \
+ scan_tp_[2] = -1; \
+ scan_tp_[3] = -1; } while (0)
+
+#define COPY_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] = scan_fp_[0]; \
+ scan_tp_[1] = scan_fp_[1]; \
+ scan_tp_[2] = scan_fp_[2]; \
+ scan_tp_[3] = scan_fp_[3]; } while (0)
+
+#define COMPL_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] = ~ scan_fp_[0]; \
+ scan_tp_[1] = ~ scan_fp_[1]; \
+ scan_tp_[2] = ~ scan_fp_[2]; \
+ scan_tp_[3] = ~ scan_fp_[3]; } while (0)
+
+#define AND_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] &= scan_fp_[0]; \
+ scan_tp_[1] &= scan_fp_[1]; \
+ scan_tp_[2] &= scan_fp_[2]; \
+ scan_tp_[3] &= scan_fp_[3]; } while (0)
+
+#define AND_COMPL_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] &= ~ scan_fp_[0]; \
+ scan_tp_[1] &= ~ scan_fp_[1]; \
+ scan_tp_[2] &= ~ scan_fp_[2]; \
+ scan_tp_[3] &= ~ scan_fp_[3]; } while (0)
+
+#define IOR_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] |= scan_fp_[0]; \
+ scan_tp_[1] |= scan_fp_[1]; \
+ scan_tp_[2] |= scan_fp_[2]; \
+ scan_tp_[3] |= scan_fp_[3]; } while (0)
+
+#define IOR_COMPL_HARD_REG_SET(TO, FROM) \
+do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO), *scan_fp_ = (FROM); \
+ scan_tp_[0] |= ~ scan_fp_[0]; \
+ scan_tp_[1] |= ~ scan_fp_[1]; \
+ scan_tp_[2] |= ~ scan_fp_[2]; \
+ scan_tp_[3] |= ~ scan_fp_[3]; } while (0)
+
+#define GO_IF_HARD_REG_SUBSET(X,Y,TO) \
+do { register HARD_REG_ELT_TYPE *scan_xp_ = (X), *scan_yp_ = (Y); \
+ if ((0 == (scan_xp_[0] & ~ scan_yp_[0])) \
+ && (0 == (scan_xp_[1] & ~ scan_yp_[1])) \
+ && (0 == (scan_xp_[2] & ~ scan_yp_[2])) \
+ && (0 == (scan_xp_[3] & ~ scan_yp_[3]))) \
+ goto TO; } while (0)
+
+#define GO_IF_HARD_REG_EQUAL(X,Y,TO) \
+do { register HARD_REG_ELT_TYPE *scan_xp_ = (X), *scan_yp_ = (Y); \
+ if ((scan_xp_[0] == scan_yp_[0]) \
+ && (scan_xp_[1] == scan_yp_[1]) \
+ && (scan_xp_[2] == scan_yp_[2]) \
+ && (scan_xp_[3] == scan_yp_[3])) \
+ goto TO; } while (0)
+
+#else /* FIRST_PSEUDO_REGISTER > 3*HOST_BITS_PER_WIDE_INT */
+
#define CLEAR_HARD_REG_SET(TO) \
do { register HARD_REG_ELT_TYPE *scan_tp_ = (TO); \
register int i; \
@@ -186,6 +379,9 @@ do { register HARD_REG_ELT_TYPE *scan_xp_ = (X), *scan_yp_ = (Y); \
if (i == HARD_REG_SET_LONGS) goto TO; } while (0)
#endif
+#endif
+#endif
+#endif
/* Define some standard sets of registers. */
@@ -211,6 +407,9 @@ extern char call_used_regs[FIRST_PSEUDO_REGISTER];
extern HARD_REG_SET call_used_reg_set;
+/* Registers that we don't want to caller save. */
+extern HARD_REG_SET losing_caller_save_reg_set;
+
/* Indexed by hard register number, contains 1 for registers that are
fixed use -- i.e. in fixed_regs -- or a function value return register
or STRUCT_VALUE_REGNUM or STATIC_CHAIN_REGNUM. These are the
diff --git a/contrib/gcc/hash.c b/contrib/gcc/hash.c
new file mode 100644
index 0000000..1428ae1
--- /dev/null
+++ b/contrib/gcc/hash.c
@@ -0,0 +1,204 @@
+/* hash.c -- hash table routines
+ Copyright (C) 1993, 94 Free Software Foundation, Inc.
+ Written by Steve Chamberlain <sac@cygnus.com>
+
+This file was lifted from BFD, the Binary File Descriptor library.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "hash.h"
+#include "obstack.h"
+#include "gansidecl.h"
+#include "toplev.h"
+
+/* Obstack allocation and deallocation routines. */
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+extern char * xmalloc ();
+
+/* The default number of entries to use when creating a hash table. */
+#define DEFAULT_SIZE (1009)
+
+/* Create a new hash table, given a number of entries. */
+
+boolean
+hash_table_init_n (table, newfunc, size)
+ struct hash_table *table;
+ struct hash_entry *(*newfunc) PARAMS ((struct hash_entry *,
+ struct hash_table *,
+ const char *));
+ unsigned int size;
+{
+ unsigned int alloc;
+
+ alloc = size * sizeof (struct hash_entry *);
+ if (!obstack_begin (&table->memory, alloc))
+ {
+ error ("no memory");
+ return false;
+ }
+ table->table = ((struct hash_entry **)
+ obstack_alloc (&table->memory, alloc));
+ if (!table->table)
+ {
+ error ("no memory");
+ return false;
+ }
+ memset ((PTR) table->table, 0, alloc);
+ table->size = size;
+ table->newfunc = newfunc;
+ return true;
+}
+
+/* Create a new hash table with the default number of entries. */
+
+boolean
+hash_table_init (table, newfunc)
+ struct hash_table *table;
+ struct hash_entry *(*newfunc) PARAMS ((struct hash_entry *,
+ struct hash_table *,
+ const char *));
+{
+ return hash_table_init_n (table, newfunc, DEFAULT_SIZE);
+}
+
+/* Free a hash table. */
+
+void
+hash_table_free (table)
+ struct hash_table *table;
+{
+ obstack_free (&table->memory, (PTR) NULL);
+}
+
+/* Look up a string in a hash table. */
+
+struct hash_entry *
+hash_lookup (table, string, create, copy)
+ struct hash_table *table;
+ const char *string;
+ boolean create;
+ boolean copy;
+{
+ register const unsigned char *s;
+ register unsigned long hash;
+ register unsigned int c;
+ struct hash_entry *hashp;
+ unsigned int len;
+ unsigned int index;
+
+ hash = 0;
+ len = 0;
+ s = (const unsigned char *) string;
+ while ((c = *s++) != '\0')
+ {
+ hash += c + (c << 17);
+ hash ^= hash >> 2;
+ ++len;
+ }
+ hash += len + (len << 17);
+ hash ^= hash >> 2;
+
+ index = hash % table->size;
+ for (hashp = table->table[index];
+ hashp != (struct hash_entry *) NULL;
+ hashp = hashp->next)
+ {
+ if (hashp->hash == hash
+ && strcmp (hashp->string, string) == 0)
+ return hashp;
+ }
+
+ if (! create)
+ return (struct hash_entry *) NULL;
+
+ hashp = (*table->newfunc) ((struct hash_entry *) NULL, table, string);
+ if (hashp == (struct hash_entry *) NULL)
+ return (struct hash_entry *) NULL;
+ if (copy)
+ {
+ char *new;
+
+ new = (char *) obstack_alloc (&table->memory, len + 1);
+ if (!new)
+ {
+ error ("no memory");
+ return (struct hash_entry *) NULL;
+ }
+ strcpy (new, string);
+ string = new;
+ }
+ hashp->string = string;
+ hashp->hash = hash;
+ hashp->next = table->table[index];
+ table->table[index] = hashp;
+
+ return hashp;
+}
+
+/* Base method for creating a new hash table entry. */
+
+/*ARGSUSED*/
+struct hash_entry *
+hash_newfunc (entry, table, string)
+ struct hash_entry *entry;
+ struct hash_table *table;
+ const char *string;
+{
+ if (entry == (struct hash_entry *) NULL)
+ entry = ((struct hash_entry *)
+ hash_allocate (table, sizeof (struct hash_entry)));
+ return entry;
+}
+
+/* Allocate space in a hash table. */
+
+PTR
+hash_allocate (table, size)
+ struct hash_table *table;
+ unsigned int size;
+{
+ PTR ret;
+
+ ret = obstack_alloc (&table->memory, size);
+ if (ret == NULL && size != 0)
+ error ("no memory");
+ return ret;
+}
+
+/* Traverse a hash table. */
+
+void
+hash_traverse (table, func, info)
+ struct hash_table *table;
+ boolean (*func) PARAMS ((struct hash_entry *, PTR));
+ PTR info;
+{
+ unsigned int i;
+
+ for (i = 0; i < table->size; i++)
+ {
+ struct hash_entry *p;
+
+ for (p = table->table[i]; p != NULL; p = p->next)
+ {
+ if (! (*func) (p, info))
+ return;
+ }
+ }
+}
diff --git a/contrib/gcc/hash.h b/contrib/gcc/hash.h
new file mode 100644
index 0000000..5a3838c
--- /dev/null
+++ b/contrib/gcc/hash.h
@@ -0,0 +1,130 @@
+/* Header file for generic hash table support.
+ Copyright (C) 1993, 94 Free Software Foundation, Inc.
+ Written by Steve Chamberlain <sac@cygnus.com>
+
+This file was lifted from BFD, the Binary File Descriptor library.
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef IN_GCC
+
+/* Add prototype support. */
+#ifndef PROTO
+#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
+#define PROTO(ARGS) ARGS
+#else
+#define PROTO(ARGS) ()
+#endif
+#endif
+
+#define PARAMS(ARGS) PROTO(ARGS)
+
+#ifdef __STDC__
+#define PTR void *
+#else
+#ifndef const
+#define const
+#endif
+#define PTR char *
+#endif
+
+#else /* ! IN_GCC */
+#include <ansidecl.h>
+#endif /* IN_GCC */
+
+#include "obstack.h"
+
+typedef enum {false, true} boolean;
+
+/* Hash table routines. There is no way to free up a hash table. */
+
+/* An element in the hash table. Most uses will actually use a larger
+ structure, and an instance of this will be the first field. */
+
+struct hash_entry
+{
+ /* Next entry for this hash code. */
+ struct hash_entry *next;
+ /* String being hashed. */
+ const char *string;
+ /* Hash code. This is the full hash code, not the index into the
+ table. */
+ unsigned long hash;
+};
+
+/* A hash table. */
+
+struct hash_table
+{
+ /* The hash array. */
+ struct hash_entry **table;
+ /* The number of slots in the hash table. */
+ unsigned int size;
+ /* A function used to create new elements in the hash table. The
+ first entry is itself a pointer to an element. When this
+ function is first invoked, this pointer will be NULL. However,
+ having the pointer permits a hierarchy of method functions to be
+ built each of which calls the function in the superclass. Thus
+ each function should be written to allocate a new block of memory
+ only if the argument is NULL. */
+ struct hash_entry *(*newfunc) PARAMS ((struct hash_entry *,
+ struct hash_table *,
+ const char *));
+ /* An obstack for this hash table. */
+ struct obstack memory;
+};
+
+/* Initialize a hash table. */
+extern boolean hash_table_init
+ PARAMS ((struct hash_table *,
+ struct hash_entry *(*) (struct hash_entry *,
+ struct hash_table *,
+ const char *)));
+
+/* Initialize a hash table specifying a size. */
+extern boolean hash_table_init_n
+ PARAMS ((struct hash_table *,
+ struct hash_entry *(*) (struct hash_entry *,
+ struct hash_table *,
+ const char *),
+ unsigned int size));
+
+/* Free up a hash table. */
+extern void hash_table_free PARAMS ((struct hash_table *));
+
+/* Look up a string in a hash table. If CREATE is true, a new entry
+ will be created for this string if one does not already exist. The
+ COPY argument must be true if this routine should copy the string
+ into newly allocated memory when adding an entry. */
+extern struct hash_entry *hash_lookup
+ PARAMS ((struct hash_table *, const char *, boolean create,
+ boolean copy));
+
+/* Base method for creating a hash table entry. */
+extern struct hash_entry *hash_newfunc
+ PARAMS ((struct hash_entry *, struct hash_table *,
+ const char *));
+
+/* Grab some space for a hash table entry. */
+extern PTR hash_allocate PARAMS ((struct hash_table *,
+ unsigned int));
+
+/* Traverse a hash table in a random order, calling a function on each
+ element. If the function returns false, the traversal stops. The
+ INFO argument is passed to the function. */
+extern void hash_traverse PARAMS ((struct hash_table *,
+ boolean (*) (struct hash_entry *,
+ PTR),
+ PTR info));
diff --git a/contrib/gcc/input.h b/contrib/gcc/input.h
index 7c71c24..7bcde83 100644
--- a/contrib/gcc/input.h
+++ b/contrib/gcc/input.h
@@ -1,7 +1,6 @@
/* Declarations for variables relating to reading the source file.
Used by parsers, lexical analyzers, and error message routines.
-
- Copyright (C) 1993 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -37,6 +36,7 @@ struct file_stack
char *name;
struct file_stack *next;
int line;
+ int indent_level;
};
/* Stack of currently pending input files.
diff --git a/contrib/gcc/integrate.c b/contrib/gcc/integrate.c
index fcd242c..38a900a 100644
--- a/contrib/gcc/integrate.c
+++ b/contrib/gcc/integrate.c
@@ -1,5 +1,5 @@
/* Procedure integration for GNU CC.
- Copyright (C) 1988, 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1988, 91, 93-97, 1998 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
@@ -20,20 +20,23 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
-
#include "config.h"
+#include "system.h"
+
#include "rtl.h"
#include "tree.h"
+#include "regs.h"
#include "flags.h"
#include "insn-config.h"
#include "insn-flags.h"
#include "expr.h"
#include "output.h"
+#include "recog.h"
#include "integrate.h"
#include "real.h"
+#include "except.h"
#include "function.h"
-#include "bytecode.h"
+#include "toplev.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
@@ -41,9 +44,6 @@ Boston, MA 02111-1307, USA. */
extern struct obstack *function_maybepermanent_obstack;
-extern tree pushdecl ();
-extern tree poplevel ();
-
/* Similar, but round to the next highest integer that meets the
alignment. */
#define CEIL_ROUND(VALUE,ALIGN) (((VALUE) + (ALIGN) - 1) & ~((ALIGN)- 1))
@@ -51,8 +51,12 @@ extern tree poplevel ();
/* Default max number of insns a function can have and still be inline.
This is overridden on RISC machines. */
#ifndef INTEGRATE_THRESHOLD
+/* Inlining small functions might save more space then not inlining at
+ all. Assume 1 instruction for the call and 1.5 insns per argument. */
#define INTEGRATE_THRESHOLD(DECL) \
- (8 * (8 + list_length (DECL_ARGUMENTS (DECL))))
+ (optimize_size \
+ ? (1 + (3 * list_length (DECL_ARGUMENTS (DECL)) / 2)) \
+ : (8 * (8 + list_length (DECL_ARGUMENTS (DECL)))))
#endif
static rtx initialize_for_inline PROTO((tree, int, int, int, int));
@@ -66,6 +70,7 @@ static void note_modified_parmregs PROTO((rtx, rtx));
static rtx copy_for_inline PROTO((rtx));
static void integrate_parm_decls PROTO((tree, struct inline_remap *, rtvec));
static void integrate_decl_tree PROTO((tree, int, struct inline_remap *));
+static void save_constants_in_decl_trees PROTO ((tree));
static void subst_constants PROTO((rtx *, rtx, struct inline_remap *));
static void restore_constants PROTO((rtx *));
static void set_block_origin_self PROTO((tree));
@@ -74,6 +79,29 @@ static void set_block_abstract_flags PROTO((tree, int));
void set_decl_abstract_flags PROTO((tree, int));
+/* Returns the Ith entry in the label_map contained in MAP. If the
+ Ith entry has not yet been set, return a fresh label. This function
+ performs a lazy initialization of label_map, thereby avoiding huge memory
+ explosions when the label_map gets very large. */
+
+rtx
+get_label_from_map (map, i)
+ struct inline_remap *map;
+ int i;
+{
+ rtx x = map->label_map[i];
+
+ if (x == NULL_RTX)
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ x = map->label_map[i] = gen_label_rtx();
+ pop_obstacks ();
+ }
+
+ return x;
+}
+
/* Zero if the current function (whose FUNCTION_DECL is FNDECL)
is safe and reasonable to integrate into other functions.
Nonzero means value is a warning message with a single %s
@@ -88,10 +116,9 @@ function_cannot_inline_p (fndecl)
int max_insns = INTEGRATE_THRESHOLD (fndecl);
register int ninsns = 0;
register tree parms;
+ rtx result;
- /* No inlines with varargs. `grokdeclarator' gives a warning
- message about that if `inline' is specified. This code
- it put in to catch the volunteers. */
+ /* No inlines with varargs. */
if ((last && TREE_VALUE (last) != void_type_node)
|| current_function_varargs)
return "varargs function cannot be inline";
@@ -102,19 +129,14 @@ function_cannot_inline_p (fndecl)
if (current_function_contains_functions)
return "function with nested functions cannot be inline";
+ if (current_function_cannot_inline)
+ return current_function_cannot_inline;
+
/* If its not even close, don't even look. */
if (!DECL_INLINE (fndecl) && get_max_uid () > 3 * max_insns)
return "function too large to be inline";
#if 0
- /* Large stacks are OK now that inlined functions can share them. */
- /* Don't inline functions with large stack usage,
- since they can make other recursive functions burn up stack. */
- if (!DECL_INLINE (fndecl) && get_frame_size () > 100)
- return "function stack frame for inlining";
-#endif
-
-#if 0
/* Don't inline functions which do not specify a function prototype and
have BLKmode argument or take the address of a parameter. */
for (parms = DECL_ARGUMENTS (fndecl); parms; parms = TREE_CHAIN (parms))
@@ -152,12 +174,11 @@ function_cannot_inline_p (fndecl)
if (!DECL_INLINE (fndecl) && get_max_uid () > max_insns)
{
- for (ninsns = 0, insn = get_first_nonparm_insn (); insn && ninsns < max_insns;
+ for (ninsns = 0, insn = get_first_nonparm_insn ();
+ insn && ninsns < max_insns;
insn = NEXT_INSN (insn))
- {
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
- ninsns++;
- }
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ ninsns++;
if (ninsns >= max_insns)
return "function too large to be inline";
@@ -177,6 +198,24 @@ function_cannot_inline_p (fndecl)
if (current_function_has_nonlocal_goto)
return "function with nonlocal goto cannot be inline";
+ /* This is a hack, until the inliner is taught about eh regions at
+ the start of the function. */
+ for (insn = get_insns ();
+ insn
+ && ! (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG);
+ insn = NEXT_INSN (insn))
+ {
+ if (insn && GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+ return "function with complex parameters cannot be inline";
+ }
+
+ /* We can't inline functions that return a PARALLEL rtx. */
+ result = DECL_RTL (DECL_RESULT (fndecl));
+ if (result && GET_CODE (result) == PARALLEL)
+ return "inline functions not supported for this return value type";
+
return 0;
}
@@ -205,7 +244,8 @@ static rtx *insn_map;
static tree *parmdecl_map;
/* Keep track of first pseudo-register beyond those that are parms. */
-static int max_parm_reg;
+extern int max_parm_reg;
+extern rtx *parm_reg_stack_loc;
/* When an insn is being copied by copy_for_inline,
this is nonzero if we have copied an ASM_OPERANDS.
@@ -261,6 +301,14 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
parms = TREE_CHAIN (parms), i++)
{
rtx p = DECL_RTL (parms);
+ int copied_incoming = 0;
+
+ /* If we have (mem (addressof (mem ...))), use the inner MEM since
+ otherwise the copy_rtx call below will not unshare the MEM since
+ it shares ADDRESSOF. */
+ if (GET_CODE (p) == MEM && GET_CODE (XEXP (p, 0)) == ADDRESSOF
+ && GET_CODE (XEXP (XEXP (p, 0), 0)) == MEM)
+ p = XEXP (XEXP (p, 0), 0);
if (GET_CODE (p) == MEM && copy)
{
@@ -276,7 +324,8 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
&& GET_CODE (DECL_INCOMING_RTL (parms)) == MEM
&& (XEXP (DECL_RTL (parms), 0)
== XEXP (DECL_INCOMING_RTL (parms), 0))))
- DECL_INCOMING_RTL (parms) = new;
+ DECL_INCOMING_RTL (parms) = new, copied_incoming = 1;
+
DECL_RTL (parms) = new;
}
@@ -298,6 +347,23 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
/* This flag is cleared later
if the function ever modifies the value of the parm. */
TREE_READONLY (parms) = 1;
+
+ /* Copy DECL_INCOMING_RTL if not done already. This can
+ happen if DECL_RTL is a reg. */
+ if (copy && ! copied_incoming)
+ {
+ p = DECL_INCOMING_RTL (parms);
+
+ /* If we have (mem (addressof (mem ...))), use the inner MEM since
+ otherwise the copy_rtx call below will not unshare the MEM since
+ it shares ADDRESSOF. */
+ if (GET_CODE (p) == MEM && GET_CODE (XEXP (p, 0)) == ADDRESSOF
+ && GET_CODE (XEXP (XEXP (p, 0), 0)) == MEM)
+ p = XEXP (XEXP (p, 0), 0);
+
+ if (GET_CODE (p) == MEM)
+ DECL_INCOMING_RTL (parms) = copy_rtx (p);
+ }
}
/* Assume we start out in the insns that set up the parameters. */
@@ -316,10 +382,12 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
the size of the incoming stack area for parameters,
the number of bytes popped on return,
the stack slot list,
+ the labels that are forced to exist,
some flags that are used to restore compiler globals,
the value of current_function_outgoing_args_size,
the original argument vector,
- and the original DECL_INITIAL. */
+ the original DECL_INITIAL,
+ and pointers to the table of pseudo regs, pointer flags, and alignment. */
return gen_inline_header_rtx (NULL_RTX, NULL_RTX, min_labelno, max_labelno,
max_parm_reg, max_reg,
@@ -327,7 +395,10 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
current_function_pops_args,
stack_slot_list, forced_labels, function_flags,
current_function_outgoing_args_size,
- arg_vector, (rtx) DECL_INITIAL (fndecl));
+ arg_vector, (rtx) DECL_INITIAL (fndecl),
+ (rtvec) regno_reg_rtx, regno_pointer_flag,
+ regno_pointer_align,
+ (rtvec) parm_reg_stack_loc);
}
/* Subroutine for `save_for_inline{copying,nocopy}'. Finishes up the
@@ -339,7 +410,7 @@ finish_inline (fndecl, head)
tree fndecl;
rtx head;
{
- NEXT_INSN (head) = get_first_nonparm_insn ();
+ FIRST_FUNCTION_INSN (head) = get_first_nonparm_insn ();
FIRST_PARM_INSN (head) = get_insns ();
DECL_SAVED_INSNS (fndecl) = head;
DECL_FRAME_SIZE (fndecl) = get_frame_size ();
@@ -395,9 +466,12 @@ save_for_inline_copying (fndecl)
int max_reg;
int max_uid;
rtx first_nonparm_insn;
+ char *new, *new1;
+ rtx *new_parm_reg_stack_loc;
+ rtx *new2;
/* Make and emit a return-label if we have not already done so.
- Do this before recording the bounds on label numbers. */
+ Do this before recording the bounds on label numbers. */
if (return_label == 0)
{
@@ -417,7 +491,6 @@ save_for_inline_copying (fndecl)
for the parms, prior to elimination of virtual registers.
These values are needed for substituting parms properly. */
- max_parm_reg = max_parm_reg_num ();
parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));
head = initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, 1);
@@ -434,6 +507,10 @@ save_for_inline_copying (fndecl)
save_constants (&REG_NOTES (insn));
}
+ /* Also scan all decls, and replace any constant pool references with the
+ actual constant. */
+ save_constants_in_decl_trees (DECL_INITIAL (fndecl));
+
/* Clear out the constant pool so that we can recreate it with the
copied constants below. */
init_const_rtx_hash_table ();
@@ -473,25 +550,38 @@ save_for_inline_copying (fndecl)
Make these new rtx's now, and install them in regno_reg_rtx, so they
will be the official pseudo-reg rtx's for the rest of compilation. */
- reg_map = (rtx *) alloca ((max_reg + 1) * sizeof (rtx));
+ reg_map = (rtx *) savealloc (regno_pointer_flag_length * sizeof (rtx));
len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion);
for (i = max_reg - 1; i > LAST_VIRTUAL_REGISTER; i--)
reg_map[i] = (rtx)obstack_copy (function_maybepermanent_obstack,
regno_reg_rtx[i], len);
- bcopy ((char *) (reg_map + LAST_VIRTUAL_REGISTER + 1),
- (char *) (regno_reg_rtx + LAST_VIRTUAL_REGISTER + 1),
- (max_reg - (LAST_VIRTUAL_REGISTER + 1)) * sizeof (rtx));
+ regno_reg_rtx = reg_map;
+
+ /* Put copies of all the virtual register rtx into the new regno_reg_rtx. */
+ regno_reg_rtx[VIRTUAL_INCOMING_ARGS_REGNUM] = virtual_incoming_args_rtx;
+ regno_reg_rtx[VIRTUAL_STACK_VARS_REGNUM] = virtual_stack_vars_rtx;
+ regno_reg_rtx[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
+ regno_reg_rtx[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
/* Likewise each label rtx must have a unique rtx as its copy. */
- label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
- label_map -= min_labelno;
+ /* We used to use alloca here, but the size of what it would try to
+ allocate would occasionally cause it to exceed the stack limit and
+ cause unpredictable core dumps. Some examples were > 2Mb in size. */
+ label_map = (rtx *) xmalloc ((max_labelno) * sizeof (rtx));
for (i = min_labelno; i < max_labelno; i++)
label_map[i] = gen_label_rtx ();
+ /* Likewise for parm_reg_stack_slot. */
+ new_parm_reg_stack_loc = (rtx *) savealloc (max_parm_reg * sizeof (rtx));
+ for (i = 0; i < max_parm_reg; i++)
+ new_parm_reg_stack_loc[i] = copy_for_inline (parm_reg_stack_loc[i]);
+
+ parm_reg_stack_loc = new_parm_reg_stack_loc;
+
/* Record the mapping of old insns to copied insns. */
insn_map = (rtx *) alloca (max_uid * sizeof (rtx));
@@ -510,6 +600,16 @@ save_for_inline_copying (fndecl)
XEXP (regno_reg_rtx[i], 0)
= copy_for_inline (XEXP (regno_reg_rtx[i], 0));
+ /* Copy the parm_reg_stack_loc array, and substitute for all of the rtx
+ contained in it. */
+ new2 = (rtx *) savealloc (max_parm_reg * sizeof (rtx));
+ bcopy ((char *) parm_reg_stack_loc, (char *) new2,
+ max_parm_reg * sizeof (rtx));
+ parm_reg_stack_loc = new2;
+ for (i = LAST_VIRTUAL_REGISTER + 1; i < max_parm_reg; ++i)
+ if (parm_reg_stack_loc[i])
+ parm_reg_stack_loc[i] = copy_for_inline (parm_reg_stack_loc[i]);
+
/* Copy the tree of subblocks of the function, and the decls in them.
We will use the copy for compiling this function, then restore the original
subblocks and decls for use when inlining this function.
@@ -560,6 +660,34 @@ save_for_inline_copying (fndecl)
NOTE_SOURCE_FILE (insn) = (char *) copy;
NOTE_SOURCE_FILE (copy) = 0;
}
+ if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
+ || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END)
+ {
+ int new_region = CODE_LABEL_NUMBER
+ (label_map[NOTE_BLOCK_NUMBER (copy)]);
+
+ /* we have to duplicate the handlers for the original */
+ if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
+ {
+ handler_info *ptr, *temp;
+ int nr;
+ nr = new_eh_region_entry (new_region);
+ ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
+ for ( ; ptr; ptr = ptr->next)
+ {
+ temp = get_new_handler (
+ label_map[CODE_LABEL_NUMBER (ptr->handler_label)],
+ ptr->type_info);
+ add_new_handler (nr, temp);
+ }
+ }
+
+ /* We have to forward these both to match the new exception
+ region. */
+ NOTE_BLOCK_NUMBER (copy) = new_region;
+
+ }
+ RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);
break;
case INSN:
@@ -568,8 +696,8 @@ save_for_inline_copying (fndecl)
copy = rtx_alloc (GET_CODE (insn));
if (GET_CODE (insn) == CALL_INSN)
- CALL_INSN_FUNCTION_USAGE (copy) =
- copy_for_inline (CALL_INSN_FUNCTION_USAGE (insn));
+ CALL_INSN_FUNCTION_USAGE (copy)
+ = copy_for_inline (CALL_INSN_FUNCTION_USAGE (insn));
PATTERN (copy) = copy_for_inline (PATTERN (insn));
INSN_CODE (copy) = -1;
@@ -609,7 +737,19 @@ save_for_inline_copying (fndecl)
finish_inline (fndecl, head);
+ /* Make new versions of the register tables. */
+ new = (char *) savealloc (regno_pointer_flag_length);
+ bcopy (regno_pointer_flag, new, regno_pointer_flag_length);
+ new1 = (char *) savealloc (regno_pointer_flag_length);
+ bcopy (regno_pointer_align, new1, regno_pointer_flag_length);
+
+ regno_pointer_flag = new;
+ regno_pointer_align = new1;
+
set_new_first_and_last_insn (first_insn, last_insn);
+
+ if (label_map)
+ free (label_map);
}
/* Return a copy of a chain of nodes, chained through the TREE_CHAIN field.
@@ -726,7 +866,6 @@ save_for_inline_nocopy (fndecl)
for the parms, prior to elimination of virtual registers.
These values are needed for substituting parms properly. */
- max_parm_reg = max_parm_reg_num ();
parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));
/* Make and emit a return-label if we have not already done so. */
@@ -780,6 +919,10 @@ save_for_inline_nocopy (fndecl)
}
}
+ /* Also scan all decls, and replace any constant pool references with the
+ actual constant. */
+ save_constants_in_decl_trees (DECL_INITIAL (fndecl));
+
/* We have now allocated all that needs to be allocated permanently
on the rtx obstack. Set our high-water mark, so that we
can free the rest of this when the time comes. */
@@ -793,8 +936,8 @@ save_for_inline_nocopy (fndecl)
pool. Replace each with a CONST that has the mode of the original
constant, contains the constant, and has RTX_INTEGRATED_P set.
Similarly, constant pool addresses not enclosed in a MEM are replaced
- with an ADDRESS rtx which also gives the constant, mode, and has
- RTX_INTEGRATED_P set. */
+ with an ADDRESS and CONST rtx which also gives the constant, its
+ mode, the mode of the address, and has RTX_INTEGRATED_P set. */
static void
save_constants (px)
@@ -814,7 +957,7 @@ save_constants (px)
&& CONSTANT_POOL_ADDRESS_P (XEXP (x,0)))
{
enum machine_mode const_mode = get_pool_mode (XEXP (x, 0));
- rtx new = gen_rtx (CONST, const_mode, get_pool_constant (XEXP (x, 0)));
+ rtx new = gen_rtx_CONST (const_mode, get_pool_constant (XEXP (x, 0)));
RTX_INTEGRATED_P (new) = 1;
/* If the MEM was in a different mode than the constant (perhaps we
@@ -823,7 +966,7 @@ save_constants (px)
if (GET_MODE (x) != const_mode)
{
- new = gen_rtx (SUBREG, GET_MODE (x), new, 0);
+ new = gen_rtx_SUBREG (GET_MODE (x), new, 0);
RTX_INTEGRATED_P (new) = 1;
}
@@ -833,7 +976,9 @@ save_constants (px)
else if (GET_CODE (x) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (x))
{
- *px = gen_rtx (ADDRESS, get_pool_mode (x), get_pool_constant (x));
+ *px = gen_rtx_ADDRESS (GET_MODE (x),
+ gen_rtx_CONST (get_pool_mode (x),
+ get_pool_constant (x)));
save_constants (&XEXP (*px, 0));
RTX_INTEGRATED_P (*px) = 1;
}
@@ -873,7 +1018,7 @@ save_constants (px)
static void
note_modified_parmregs (reg, x)
rtx reg;
- rtx x;
+ rtx x ATTRIBUTE_UNUSED;
{
if (GET_CODE (reg) == REG && in_nonparm_insns
&& REGNO (reg) < max_parm_reg
@@ -900,6 +1045,7 @@ copy_for_inline (orig)
rtx orig;
{
register rtx x = orig;
+ register rtx new;
register int i;
register enum rtx_code code;
register char *format_ptr;
@@ -945,9 +1091,8 @@ copy_for_inline (orig)
/* Get constant pool entry, but access in different mode. */
if (RTX_INTEGRATED_P (x))
{
- rtx new
- = force_const_mem (GET_MODE (SUBREG_REG (x)),
- copy_for_inline (XEXP (SUBREG_REG (x), 0)));
+ new = force_const_mem (GET_MODE (SUBREG_REG (x)),
+ copy_for_inline (XEXP (SUBREG_REG (x), 0)));
PUT_MODE (new, GET_MODE (x));
return validize_mem (new);
@@ -960,8 +1105,16 @@ copy_for_inline (orig)
if (! RTX_INTEGRATED_P (x))
abort ();
- return XEXP (force_const_mem (GET_MODE (x),
- copy_for_inline (XEXP (x, 0))), 0);
+ new = force_const_mem (GET_MODE (XEXP (x, 0)),
+ copy_for_inline (XEXP (XEXP (x, 0), 0)));
+ new = XEXP (new, 0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+ if (GET_MODE (new) != GET_MODE (x))
+ new = convert_memory_address (GET_MODE (x), new);
+#endif
+
+ return new;
case ASM_OPERANDS:
/* If a single asm insn contains multiple output operands
@@ -1019,9 +1172,9 @@ copy_for_inline (orig)
case LABEL_REF:
/* If this is a non-local label, just make a new LABEL_REF.
Otherwise, use the new label as well. */
- x = gen_rtx (LABEL_REF, GET_MODE (orig),
- LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
- : label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
+ x = gen_rtx_LABEL_REF (GET_MODE (orig),
+ LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
+ : label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
LABEL_REF_NONLOCAL_P (x) = LABEL_REF_NONLOCAL_P (orig);
LABEL_OUTSIDE_LOOP_P (x) = LABEL_OUTSIDE_LOOP_P (orig);
return x;
@@ -1070,6 +1223,8 @@ copy_for_inline (orig)
}
break;
#endif
+ default:
+ break;
}
/* Replace this rtx with a copy of itself. */
@@ -1105,7 +1260,7 @@ copy_for_inline (orig)
{
register int j;
- XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0));
+ XVEC (x, i) = gen_rtvec_vv (XVECLEN (x, i), XVEC (x, i)->elem);
for (j = 0; j < XVECLEN (x, i); j++)
XVECEXP (x, i, j)
= copy_for_inline (XVECEXP (x, i, j));
@@ -1151,7 +1306,8 @@ int global_const_equiv_map_size;
else an rtx for where the value is stored. */
rtx
-expand_inline_function (fndecl, parms, target, ignore, type, structure_value_addr)
+expand_inline_function (fndecl, parms, target, ignore, type,
+ structure_value_addr)
tree fndecl, parms;
rtx target;
int ignore;
@@ -1175,10 +1331,16 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
rtx stack_save = 0;
rtx temp;
struct inline_remap *map;
+#ifdef HAVE_cc0
rtx cc0_insn = 0;
+#endif
rtvec arg_vector = ORIGINAL_ARG_VECTOR (header);
rtx static_chain_value = 0;
+ /* The pointer used to track the true location of the memory used
+ for MAP->LABEL_MAP. */
+ rtx *real_label_map = 0;
+
/* Allow for equivalences of the pseudos we make for virtual fp and ap. */
max_regno = MAX_REGNUM (header) + 3;
if (max_regno < FIRST_PSEUDO_REGISTER)
@@ -1190,11 +1352,9 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
passed. Since the appropriate conversions or default promotions have
already been applied, the machine modes should match exactly. */
- for (formal = DECL_ARGUMENTS (fndecl),
- actual = parms;
+ for (formal = DECL_ARGUMENTS (fndecl), actual = parms;
formal;
- formal = TREE_CHAIN (formal),
- actual = TREE_CHAIN (actual))
+ formal = TREE_CHAIN (formal), actual = TREE_CHAIN (actual))
{
tree arg;
enum machine_mode mode;
@@ -1203,13 +1363,15 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
return (rtx) (HOST_WIDE_INT) -1;
arg = TREE_VALUE (actual);
- mode= TYPE_MODE (DECL_ARG_TYPE (formal));
+ mode = TYPE_MODE (DECL_ARG_TYPE (formal));
if (mode != TYPE_MODE (TREE_TYPE (arg))
/* If they are block mode, the types should match exactly.
They don't match exactly if TREE_TYPE (FORMAL) == ERROR_MARK_NODE,
which could happen if the parameter has incomplete type. */
- || (mode == BLKmode && TREE_TYPE (arg) != TREE_TYPE (formal)))
+ || (mode == BLKmode
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (arg))
+ != TYPE_MAIN_VARIANT (TREE_TYPE (formal)))))
return (rtx) (HOST_WIDE_INT) -1;
}
@@ -1224,10 +1386,6 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
parameter declarations. */
pushlevel (0);
- /* Make a fresh binding contour that we can easily remove. */
- pushlevel (0);
- expand_start_bindings (0);
-
/* Expand the function arguments. Do this first so that any
new registers get created before we allocate the maps. */
@@ -1303,6 +1461,12 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
handle SUBREGs in addresses. */
|| (GET_CODE (arg_vals[i]) == SUBREG)))
arg_vals[i] = copy_to_mode_reg (GET_MODE (loc), arg_vals[i]);
+
+ if (arg_vals[i] != 0 && GET_CODE (arg_vals[i]) == REG
+ && POINTER_TYPE_P (TREE_TYPE (formal)))
+ mark_reg_pointer (arg_vals[i],
+ (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (formal)))
+ / BITS_PER_UNIT));
}
/* Allocate the structures we use to remap things. */
@@ -1313,8 +1477,12 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
map->reg_map = (rtx *) alloca (max_regno * sizeof (rtx));
bzero ((char *) map->reg_map, max_regno * sizeof (rtx));
- map->label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
- map->label_map -= min_labelno;
+ /* We used to use alloca here, but the size of what it would try to
+ allocate would occasionally cause it to exceed the stack limit and
+ cause unpredictable core dumps. */
+ real_label_map
+ = (rtx *) xmalloc ((max_labelno) * sizeof (rtx));
+ map->label_map = real_label_map;
map->insn_map = (rtx *) alloca (INSN_UID (header) * sizeof (rtx));
bzero ((char *) map->insn_map, INSN_UID (header) * sizeof (rtx));
@@ -1350,8 +1518,14 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
map->const_age = 0;
/* Record the current insn in case we have to set up pointers to frame
- and argument memory blocks. */
+ and argument memory blocks. If there are no insns yet, add a dummy
+ insn that can be used as an insertion point. */
map->insns_at_start = get_last_insn ();
+ if (map->insns_at_start == 0)
+ map->insns_at_start = emit_note (NULL_PTR, NOTE_INSN_DELETED);
+
+ map->regno_pointer_flag = INLINE_REGNO_POINTER_FLAG (header);
+ map->regno_pointer_align = INLINE_REGNO_POINTER_ALIGN (header);
/* Update the outgoing argument size to allow for those in the inlined
function. */
@@ -1437,7 +1611,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
that flag set if it is a register.
Also, don't allow hard registers here; they might not be valid
- when substituted into insns. */
+ when substituted into insns. */
if ((GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG)
|| (GET_CODE (copy) == REG && REG_USERVAR_P (loc)
@@ -1468,7 +1642,7 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
that flag set if it is a register.
Also, don't allow hard registers here; they might not be valid
- when substituted into insns. */
+ when substituted into insns. */
rtx locreal = gen_realpart (GET_MODE (XEXP (loc, 0)), loc);
rtx locimag = gen_imagpart (GET_MODE (XEXP (loc, 0)), loc);
rtx copyreal = gen_realpart (GET_MODE (locreal), copy);
@@ -1570,9 +1744,11 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
if (GET_CODE (XEXP (loc, 0)) == REG)
{
- temp = force_reg (Pmode, structure_value_addr);
+ temp = force_reg (Pmode,
+ force_operand (structure_value_addr, NULL_RTX));
map->reg_map[REGNO (XEXP (loc, 0))] = temp;
if ((CONSTANT_P (structure_value_addr)
+ || GET_CODE (structure_value_addr) == ADDRESSOF
|| (GET_CODE (structure_value_addr) == PLUS
&& XEXP (structure_value_addr, 0) == virtual_stack_vars_rtx
&& GET_CODE (XEXP (structure_value_addr, 1)) == CONST_INT))
@@ -1603,9 +1779,11 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
/* Machine mode function was declared to return. */
enum machine_mode departing_mode = TYPE_MODE (type);
/* (Possibly wider) machine mode it actually computes
- (for the sake of callers that fail to declare it right). */
+ (for the sake of callers that fail to declare it right).
+ We have to use the mode of the result's RTL, rather than
+ its type, since expand_function_start may have promoted it. */
enum machine_mode arriving_mode
- = TYPE_MODE (TREE_TYPE (DECL_RESULT (fndecl)));
+ = GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
rtx reg_to_map;
/* Don't use MEMs as direct targets because on some machines
@@ -1619,7 +1797,21 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
avoid machine mode mismatch when we substitute INLINE_TARGET.
But TARGET is what we will return to the caller. */
if (arriving_mode != departing_mode)
- reg_to_map = gen_rtx (SUBREG, arriving_mode, target, 0);
+ {
+ /* Avoid creating a paradoxical subreg wider than
+ BITS_PER_WORD, since that is illegal. */
+ if (GET_MODE_BITSIZE (arriving_mode) > BITS_PER_WORD)
+ {
+ if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (departing_mode),
+ GET_MODE_BITSIZE (arriving_mode)))
+ /* Maybe could be handled by using convert_move () ? */
+ abort ();
+ reg_to_map = gen_reg_rtx (arriving_mode);
+ target = gen_lowpart (departing_mode, reg_to_map);
+ }
+ else
+ reg_to_map = gen_rtx_SUBREG (arriving_mode, target, 0);
+ }
else
reg_to_map = target;
@@ -1630,10 +1822,18 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
else
map->reg_map[REGNO (loc)] = reg_to_map;
}
+ else
+ abort ();
- /* Make new label equivalences for the labels in the called function. */
- for (i = min_labelno; i < max_labelno; i++)
- map->label_map[i] = gen_label_rtx ();
+ /* Make a fresh binding contour that we can easily remove. Do this after
+ expanding our arguments so cleanups are properly scoped. */
+ pushlevel (0);
+ expand_start_bindings (0);
+
+ /* Initialize label_map. get_label_from_map will actually make
+ the labels. */
+ bzero ((char *) &map->label_map [min_labelno],
+ (max_labelno - min_labelno) * sizeof (rtx));
/* Perform postincrements before actually calling the function. */
emit_queue ();
@@ -1678,6 +1878,12 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
inline_target. */
break;
+ /* If the inline fn needs eh context, make sure that
+ the current fn has one. */
+ if (GET_CODE (pattern) == USE
+ && find_reg_note (insn, REG_EH_CONTEXT, 0) != 0)
+ get_eh_context ();
+
/* Ignore setting a function value that we don't want to use. */
if (map->inline_target == 0
&& set != 0
@@ -1761,7 +1967,9 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
break;
case JUMP_INSN:
- if (GET_CODE (PATTERN (insn)) == RETURN)
+ if (GET_CODE (PATTERN (insn)) == RETURN
+ || (GET_CODE (PATTERN (insn)) == PARALLEL
+ && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == RETURN))
{
if (local_return_label == 0)
local_return_label = gen_label_rtx ();
@@ -1808,8 +2016,8 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
/* Because the USAGE information potentially contains objects other
than hard registers, we need to copy it. */
- CALL_INSN_FUNCTION_USAGE (copy) =
- copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn), map);
+ CALL_INSN_FUNCTION_USAGE (copy)
+ = copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn), map);
#ifdef HAVE_cc0
if (cc0_insn)
@@ -1824,7 +2032,8 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
break;
case CODE_LABEL:
- copy = emit_label (map->label_map[CODE_LABEL_NUMBER (insn)]);
+ copy = emit_label (get_label_from_map (map,
+ CODE_LABEL_NUMBER (insn)));
LABEL_NAME (copy) = LABEL_NAME (insn);
map->const_age++;
break;
@@ -1842,7 +2051,37 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
- copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
+ {
+ copy = emit_note (NOTE_SOURCE_FILE (insn),
+ NOTE_LINE_NUMBER (insn));
+ if (copy
+ && (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
+ || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END))
+ {
+ rtx label
+ = get_label_from_map (map, NOTE_BLOCK_NUMBER (copy));
+
+ /* we have to duplicate the handlers for the original */
+ if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG)
+ {
+ handler_info *ptr, *temp;
+ int nr;
+ nr = new_eh_region_entry (CODE_LABEL_NUMBER (label));
+ ptr = get_first_handler (NOTE_BLOCK_NUMBER (copy));
+ for ( ; ptr; ptr = ptr->next)
+ {
+ temp = get_new_handler ( get_label_from_map (map,
+ CODE_LABEL_NUMBER (ptr->handler_label)),
+ ptr->type_info);
+ add_new_handler (nr, temp);
+ }
+ }
+
+ /* We have to forward these both to match the new exception
+ region. */
+ NOTE_BLOCK_NUMBER (copy) = CODE_LABEL_NUMBER (label);
+ }
+ }
else
copy = 0;
break;
@@ -1900,14 +2139,30 @@ expand_inline_function (fndecl, parms, target, ignore, type, structure_value_add
BLOCK_ABSTRACT_ORIGIN (block) = (DECL_ABSTRACT_ORIGIN (fndecl) == NULL
? fndecl : DECL_ABSTRACT_ORIGIN (fndecl));
poplevel (0, 0, 0);
+
+ /* Must mark the line number note after inlined functions as a repeat, so
+ that the test coverage code can avoid counting the call twice. This
+ just tells the code to ignore the immediately following line note, since
+ there already exists a copy of this note before the expanded inline call.
+ This line number note is still needed for debugging though, so we can't
+ delete it. */
+ if (flag_test_coverage)
+ emit_note (0, NOTE_REPEATED_LINE_NUMBER);
+
emit_line_note (input_filename, lineno);
if (structure_value_addr)
{
- target = gen_rtx (MEM, TYPE_MODE (type),
- memory_address (TYPE_MODE (type), structure_value_addr));
+ target = gen_rtx_MEM (TYPE_MODE (type),
+ memory_address (TYPE_MODE (type),
+ structure_value_addr));
MEM_IN_STRUCT_P (target) = 1;
}
+
+ /* Make sure we free the things we explicitly allocated with xmalloc. */
+ if (real_label_map)
+ free (real_label_map);
+
return target;
}
@@ -1973,7 +2228,6 @@ integrate_decl_tree (let, level, map)
for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
{
tree d;
- tree newd;
push_obstacks_nochange ();
saveable_allocation ();
@@ -1992,28 +2246,13 @@ integrate_decl_tree (let, level, map)
}
/* These args would always appear unused, if not for this. */
TREE_USED (d) = 1;
+ /* Prevent warning for shadowing with these. */
+ DECL_ABSTRACT_ORIGIN (d) = t;
if (DECL_LANG_SPECIFIC (d))
copy_lang_decl (d);
- /* Must set DECL_ABSTRACT_ORIGIN here for local variables, to ensure
- that we don't get -Wshadow warnings. But don't set it here if
- pushdecl might return a duplicate decl, as that will result in
- incorrect DWARF debug info. */
- if (! DECL_EXTERNAL (d) || ! TREE_PUBLIC (d))
- /* Prevent warning for shadowing with these. */
- DECL_ABSTRACT_ORIGIN (d) = t;
-
- newd = pushdecl (d);
-
- /* If we didn't set DECL_ABSTRACT_ORIGIN above, then set it now.
- Simpler to just set it always rather than checking.
- If the decl we get back is the copy of 't' that we started with,
- then set the DECL_ABSTRACT_ORIGIN. Otherwise, we must have a
- duplicate decl, and we got the older one back. In that case, setting
- DECL_ABSTRACT_ORIGIN is not appropriate. */
- if (newd == d)
- DECL_ABSTRACT_ORIGIN (d) = t;
+ pushdecl (d);
}
for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
@@ -2029,6 +2268,23 @@ integrate_decl_tree (let, level, map)
}
}
}
+
+/* Given a BLOCK node LET, search for all DECL_RTL fields, and pass them
+ through save_constants. */
+
+static void
+save_constants_in_decl_trees (let)
+ tree let;
+{
+ tree t;
+
+ for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
+ if (DECL_RTL (t) != 0)
+ save_constants (&DECL_RTL (t));
+
+ for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
+ save_constants_in_decl_trees (t);
+}
/* Create a new copy of an rtx.
Recursively copies the operands of the rtx,
@@ -2086,22 +2342,31 @@ copy_rtx_and_substitute (orig, map)
{
rtx loc, seq;
int size = DECL_FRAME_SIZE (map->fndecl);
- int rounded;
+#ifdef FRAME_GROWS_DOWNWARD
+ /* In this case, virtual_stack_vars_rtx points to one byte
+ higher than the top of the frame area. So make sure we
+ allocate a big enough chunk to keep the frame pointer
+ aligned like a real one. */
+ size = CEIL_ROUND (size, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+#endif
start_sequence ();
loc = assign_stack_temp (BLKmode, size, 1);
loc = XEXP (loc, 0);
#ifdef FRAME_GROWS_DOWNWARD
/* In this case, virtual_stack_vars_rtx points to one byte
higher than the top of the frame area. So compute the offset
- to one byte higher than our substitute frame.
- Keep the fake frame pointer aligned like a real one. */
- rounded = CEIL_ROUND (size, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
- loc = plus_constant (loc, rounded);
+ to one byte higher than our substitute frame. */
+ loc = plus_constant (loc, size);
#endif
map->reg_map[regno] = temp
= force_reg (Pmode, force_operand (loc, NULL_RTX));
+#ifdef STACK_BOUNDARY
+ mark_reg_pointer (map->reg_map[regno],
+ STACK_BOUNDARY / BITS_PER_UNIT);
+#endif
+
if (REGNO (temp) < map->const_equiv_map_size)
{
map->const_equiv_map[REGNO (temp)] = loc;
@@ -2116,7 +2381,7 @@ copy_rtx_and_substitute (orig, map)
else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
{
/* Do the same for a block to contain any arguments referenced
- in memory. */
+ in memory. */
rtx loc, seq;
int size = FUNCTION_ARGS_SIZE (DECL_SAVED_INSNS (map->fndecl));
@@ -2125,13 +2390,18 @@ copy_rtx_and_substitute (orig, map)
loc = XEXP (loc, 0);
/* When arguments grow downward, the virtual incoming
args pointer points to the top of the argument block,
- so the remapped location better do the same. */
+ so the remapped location better do the same. */
#ifdef ARGS_GROW_DOWNWARD
loc = plus_constant (loc, size);
#endif
map->reg_map[regno] = temp
= force_reg (Pmode, force_operand (loc, NULL_RTX));
+#ifdef STACK_BOUNDARY
+ mark_reg_pointer (map->reg_map[regno],
+ STACK_BOUNDARY / BITS_PER_UNIT);
+#endif
+
if (REGNO (temp) < map->const_equiv_map_size)
{
map->const_equiv_map[REGNO (temp)] = loc;
@@ -2166,6 +2436,10 @@ copy_rtx_and_substitute (orig, map)
REG_LOOP_TEST_P (map->reg_map[regno]) = REG_LOOP_TEST_P (orig);
RTX_UNCHANGING_P (map->reg_map[regno]) = RTX_UNCHANGING_P (orig);
/* A reg with REG_FUNCTION_VALUE_P true will never reach here. */
+
+ if (map->regno_pointer_flag[regno])
+ mark_reg_pointer (map->reg_map[regno],
+ map->regno_pointer_align[regno]);
}
return map->reg_map[regno];
@@ -2173,13 +2447,37 @@ copy_rtx_and_substitute (orig, map)
copy = copy_rtx_and_substitute (SUBREG_REG (orig), map);
/* SUBREG is ordinary, but don't make nested SUBREGs. */
if (GET_CODE (copy) == SUBREG)
- return gen_rtx (SUBREG, GET_MODE (orig), SUBREG_REG (copy),
- SUBREG_WORD (orig) + SUBREG_WORD (copy));
+ return gen_rtx_SUBREG (GET_MODE (orig), SUBREG_REG (copy),
+ SUBREG_WORD (orig) + SUBREG_WORD (copy));
else if (GET_CODE (copy) == CONCAT)
return (subreg_realpart_p (orig) ? XEXP (copy, 0) : XEXP (copy, 1));
else
- return gen_rtx (SUBREG, GET_MODE (orig), copy,
- SUBREG_WORD (orig));
+ return gen_rtx_SUBREG (GET_MODE (orig), copy,
+ SUBREG_WORD (orig));
+
+ case ADDRESSOF:
+ copy = gen_rtx_ADDRESSOF (mode,
+ copy_rtx_and_substitute (XEXP (orig, 0), map), 0);
+ SET_ADDRESSOF_DECL (copy, ADDRESSOF_DECL (orig));
+ regno = ADDRESSOF_REGNO (orig);
+ if (map->reg_map[regno])
+ regno = REGNO (map->reg_map[regno]);
+ else if (regno > LAST_VIRTUAL_REGISTER)
+ {
+ temp = XEXP (orig, 0);
+ map->reg_map[regno] = gen_reg_rtx (GET_MODE (temp));
+ REG_USERVAR_P (map->reg_map[regno]) = REG_USERVAR_P (temp);
+ REG_LOOP_TEST_P (map->reg_map[regno]) = REG_LOOP_TEST_P (temp);
+ RTX_UNCHANGING_P (map->reg_map[regno]) = RTX_UNCHANGING_P (temp);
+ /* A reg with REG_FUNCTION_VALUE_P true will never reach here. */
+
+ if (map->regno_pointer_flag[regno])
+ mark_reg_pointer (map->reg_map[regno],
+ map->regno_pointer_align[regno]);
+ regno = REGNO (map->reg_map[regno]);
+ }
+ ADDRESSOF_REGNO (copy) = regno;
+ return copy;
case USE:
case CLOBBER:
@@ -2190,17 +2488,18 @@ copy_rtx_and_substitute (orig, map)
copy = copy_rtx_and_substitute (XEXP (orig, 0), map);
if (GET_CODE (copy) == SUBREG && GET_CODE (XEXP (orig, 0)) != SUBREG)
copy = SUBREG_REG (copy);
- return gen_rtx (code, VOIDmode, copy);
+ return gen_rtx_fmt_e (code, VOIDmode, copy);
case CODE_LABEL:
- LABEL_PRESERVE_P (map->label_map[CODE_LABEL_NUMBER (orig)])
+ LABEL_PRESERVE_P (get_label_from_map (map, CODE_LABEL_NUMBER (orig)))
= LABEL_PRESERVE_P (orig);
- return map->label_map[CODE_LABEL_NUMBER (orig)];
+ return get_label_from_map (map, CODE_LABEL_NUMBER (orig));
case LABEL_REF:
- copy = gen_rtx (LABEL_REF, mode,
- LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
- : map->label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
+ copy = gen_rtx_LABEL_REF (mode,
+ LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
+ : get_label_from_map (map,
+ CODE_LABEL_NUMBER (XEXP (orig, 0))));
LABEL_OUTSIDE_LOOP_P (copy) = LABEL_OUTSIDE_LOOP_P (orig);
/* The fact that this label was previously nonlocal does not mean
@@ -2233,7 +2532,7 @@ copy_rtx_and_substitute (orig, map)
{
rtx constant = get_pool_constant (orig);
if (GET_CODE (constant) == LABEL_REF)
- return XEXP (force_const_mem (Pmode,
+ return XEXP (force_const_mem (GET_MODE (orig),
copy_rtx_and_substitute (constant,
map)),
0);
@@ -2280,8 +2579,10 @@ copy_rtx_and_substitute (orig, map)
if (! RTX_INTEGRATED_P (orig))
abort ();
- temp = force_const_mem (GET_MODE (orig),
- copy_rtx_and_substitute (XEXP (orig, 0), map));
+ temp
+ = force_const_mem (GET_MODE (XEXP (orig, 0)),
+ copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0),
+ map));
#if 0
/* Legitimizing the address here is incorrect.
@@ -2300,13 +2601,20 @@ copy_rtx_and_substitute (orig, map)
will not have valid reg_map entries. This can cause try_constants()
to fail because assumes that all registers in the rtx have valid
reg_map entries, and it may end up replacing one of these new
- registers with junk. */
+ registers with junk. */
if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0)))
temp = change_address (temp, GET_MODE (temp), XEXP (temp, 0));
#endif
- return XEXP (temp, 0);
+ temp = XEXP (temp, 0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+ if (GET_MODE (temp) != GET_MODE (orig))
+ temp = convert_memory_address (GET_MODE (orig), temp);
+#endif
+
+ return temp;
case ASM_OPERANDS:
/* If a single asm insn contains multiple output operands
@@ -2335,9 +2643,9 @@ copy_rtx_and_substitute (orig, map)
#ifndef NO_FUNCTION_CSE
if (! (optimize && ! flag_no_function_cse))
#endif
- return gen_rtx (CALL, GET_MODE (orig),
- gen_rtx (MEM, GET_MODE (XEXP (orig, 0)),
- copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0), map)),
+ return gen_rtx_CALL (GET_MODE (orig),
+ gen_rtx_MEM (GET_MODE (XEXP (orig, 0)),
+ copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0), map)),
copy_rtx_and_substitute (XEXP (orig, 1), map));
break;
@@ -2349,13 +2657,29 @@ copy_rtx_and_substitute (orig, map)
case SET:
/* If this is setting fp or ap, it means that we have a nonlocal goto.
- Don't alter that.
+ Adjust the setting by the offset of the area we made.
If the nonlocal goto is into the current function,
this will result in unnecessarily bad code, but should work. */
if (SET_DEST (orig) == virtual_stack_vars_rtx
|| SET_DEST (orig) == virtual_incoming_args_rtx)
- return gen_rtx (SET, VOIDmode, SET_DEST (orig),
- copy_rtx_and_substitute (SET_SRC (orig), map));
+ {
+ /* In case a translation hasn't occurred already, make one now. */
+ rtx equiv_reg;
+ rtx equiv_loc;
+ HOST_WIDE_INT loc_offset;
+
+ copy_rtx_and_substitute (SET_DEST (orig), map);
+ equiv_reg = map->reg_map[REGNO (SET_DEST (orig))];
+ equiv_loc = map->const_equiv_map[REGNO (equiv_reg)];
+ loc_offset
+ = GET_CODE (equiv_loc) == REG ? 0 : INTVAL (XEXP (equiv_loc, 1));
+ return gen_rtx_SET (VOIDmode, SET_DEST (orig),
+ force_operand
+ (plus_constant
+ (copy_rtx_and_substitute (SET_SRC (orig), map),
+ - loc_offset),
+ NULL_RTX));
+ }
break;
case MEM:
@@ -2364,6 +2688,7 @@ copy_rtx_and_substitute (orig, map)
XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (orig, 0), map);
MEM_IN_STRUCT_P (copy) = MEM_IN_STRUCT_P (orig);
MEM_VOLATILE_P (copy) = MEM_VOLATILE_P (orig);
+ MEM_ALIAS_SET (copy) = MEM_ALIAS_SET (orig);
/* If doing function inlining, this MEM might not be const in the
function that it is being inlined into, and thus may not be
@@ -2374,6 +2699,9 @@ copy_rtx_and_substitute (orig, map)
RTX_UNCHANGING_P (copy) = RTX_UNCHANGING_P (orig);
return copy;
+
+ default:
+ break;
}
copy = rtx_alloc (code);
@@ -2389,6 +2717,7 @@ copy_rtx_and_substitute (orig, map)
switch (*format_ptr++)
{
case '0':
+ XEXP (copy, i) = XEXP (orig, i);
break;
case 'e':
@@ -2580,6 +2909,7 @@ subst_constants (loc, insn, map)
new = operand_subword (inner, SUBREG_WORD (x), 0,
GET_MODE (SUBREG_REG (x)));
+ cancel_changes (num_changes);
if (new == 0 && subreg_lowpart_p (x))
new = gen_lowpart_common (GET_MODE (x), inner);
@@ -2612,8 +2942,6 @@ subst_constants (loc, insn, map)
src = SET_SRC (x);
while (GET_CODE (*dest_loc) == ZERO_EXTRACT
- /* By convention, we always use ZERO_EXTRACT in the dest. */
-/* || GET_CODE (*dest_loc) == SIGN_EXTRACT */
|| GET_CODE (*dest_loc) == SUBREG
|| GET_CODE (*dest_loc) == STRICT_LOW_PART)
{
@@ -2667,9 +2995,11 @@ subst_constants (loc, insn, map)
map->equiv_sets[map->num_sets].equiv = copy_rtx (src);
map->equiv_sets[map->num_sets++].dest = dest;
}
-
- return;
}
+ return;
+
+ default:
+ break;
}
format_ptr = GET_RTX_FORMAT (code);
@@ -2767,7 +3097,7 @@ subst_constants (loc, insn, map)
void
mark_stores (dest, x)
rtx dest;
- rtx x;
+ rtx x ATTRIBUTE_UNUSED;
{
int regno = -1;
enum machine_mode mode;
@@ -2789,9 +3119,13 @@ mark_stores (dest, x)
: regno + HARD_REGNO_NREGS (regno, mode) - 1);
int i;
- for (i = regno; i <= last_reg; i++)
- if (i < global_const_equiv_map_size)
- global_const_equiv_map[i] = 0;
+ /* Ignore virtual stack var or virtual arg register since those
+ are handled separately. */
+ if (regno != VIRTUAL_INCOMING_ARGS_REGNUM
+ && regno != VIRTUAL_STACK_VARS_REGNUM)
+ for (i = regno; i <= last_reg; i++)
+ if (i < global_const_equiv_map_size)
+ global_const_equiv_map[i] = 0;
}
}
@@ -2846,8 +3180,16 @@ restore_constants (px)
}
else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == ADDRESS)
{
- restore_constants (&XEXP (x, 0));
- *px = XEXP (force_const_mem (GET_MODE (x), XEXP (x, 0)), 0);
+ rtx new = XEXP (force_const_mem (GET_MODE (XEXP (x, 0)),
+ XEXP (XEXP (x, 0), 0)),
+ 0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+ if (GET_MODE (new) != GET_MODE (x))
+ new = convert_memory_address (GET_MODE (x), new);
+#endif
+
+ *px = new;
}
else
{
@@ -2948,25 +3290,20 @@ set_block_abstract_flags (stmt, setting)
register tree stmt;
register int setting;
{
- BLOCK_ABSTRACT (stmt) = setting;
-
- {
- register tree local_decl;
+ register tree local_decl;
+ register tree subblock;
- for (local_decl = BLOCK_VARS (stmt);
- local_decl != NULL_TREE;
- local_decl = TREE_CHAIN (local_decl))
- set_decl_abstract_flags (local_decl, setting);
- }
+ BLOCK_ABSTRACT (stmt) = setting;
- {
- register tree subblock;
+ for (local_decl = BLOCK_VARS (stmt);
+ local_decl != NULL_TREE;
+ local_decl = TREE_CHAIN (local_decl))
+ set_decl_abstract_flags (local_decl, setting);
- for (subblock = BLOCK_SUBBLOCKS (stmt);
- subblock != NULL_TREE;
- subblock = BLOCK_CHAIN (subblock))
- set_block_abstract_flags (subblock, setting);
- }
+ for (subblock = BLOCK_SUBBLOCKS (stmt);
+ subblock != NULL_TREE;
+ subblock = BLOCK_CHAIN (subblock))
+ set_block_abstract_flags (subblock, setting);
}
/* Given a pointer to some ..._DECL node, and a boolean value to set the
@@ -3003,13 +3340,6 @@ output_inline_function (fndecl)
{
rtx head;
rtx last;
- int save_flag_no_inline = flag_no_inline;
-
- if (output_bytecode)
- {
- warning ("`inline' ignored for bytecode output");
- return;
- }
/* Things we allocate from here on are part of this function, not
permanent. */
@@ -3028,8 +3358,15 @@ output_inline_function (fndecl)
/* Set stack frame size. */
assign_stack_local (BLKmode, DECL_FRAME_SIZE (fndecl), 0);
- restore_reg_data (FIRST_PARM_INSN (head));
-
+ /* The first is a bit of a lie (the array may be larger), but doesn't
+ matter too much and it isn't worth saving the actual bound. */
+ reg_rtx_no = regno_pointer_flag_length = MAX_REGNUM (head);
+ regno_reg_rtx = (rtx *) INLINE_REGNO_REG_RTX (head);
+ regno_pointer_flag = INLINE_REGNO_POINTER_FLAG (head);
+ regno_pointer_align = INLINE_REGNO_POINTER_ALIGN (head);
+ max_parm_reg = MAX_PARMREG (head);
+ parm_reg_stack_loc = (rtx *) PARMREG_STACK_LOC (head);
+
stack_slot_list = STACK_SLOT_LIST (head);
forced_labels = FORCED_LABELS (head);
@@ -3098,15 +3435,11 @@ output_inline_function (fndecl)
/* We're not deferring this any longer. */
DECL_DEFER_OUTPUT (fndecl) = 0;
- /* Integrating function calls isn't safe anymore, so turn on
- flag_no_inline. */
- flag_no_inline = 1;
+ /* We can't inline this anymore. */
+ DECL_INLINE (fndecl) = 0;
/* Compile this function all the way down to assembly code. */
rest_of_compilation (fndecl);
- /* Reset flag_no_inline to its original value. */
- flag_no_inline = save_flag_no_inline;
-
current_function_decl = 0;
}
diff --git a/contrib/gcc/integrate.h b/contrib/gcc/integrate.h
index 2b14f88..23e2e56 100644
--- a/contrib/gcc/integrate.h
+++ b/contrib/gcc/integrate.h
@@ -1,5 +1,5 @@
/* Function integration definitions for GNU C-Compiler
- Copyright (C) 1990 Free Software Foundation, Inc.
+ Copyright (C) 1990, 1995, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -93,6 +93,10 @@ struct inline_remap
/* Likewise, this is the copied constraints vector. */
rtvec copy_asm_constraints_vector;
+ /* Indications for regs being pointers and their alignment. */
+ char *regno_pointer_flag;
+ char *regno_pointer_align;
+
/* The next few fields are used for subst_constants to record the SETs
that it saw. */
int num_sets;
@@ -118,6 +122,12 @@ extern void try_constants PROTO((rtx, struct inline_remap *));
extern void mark_stores PROTO((rtx, rtx));
+/* Return the label indicated. */
+extern rtx get_label_from_map PROTO((struct inline_remap *, int));
+
+/* Set the label indicated. */
+#define set_label_in_map(MAP, I, X) ((MAP)->label_map[I] = (X))
+
/* Unfortunately, we need a global copy of const_equiv map for communication
with a function called from note_stores. Be *very* careful that this
is used properly in the presence of recursion. */
diff --git a/contrib/gcc/invoke.texi b/contrib/gcc/invoke.texi
index 17b94dc..01dd7a8 100644
--- a/contrib/gcc/invoke.texi
+++ b/contrib/gcc/invoke.texi
@@ -1,4 +1,4 @@
-@c Copyright (C) 1988, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+@c Copyright (C) 1988,89,92,93,94,95,96,97,1998 Free Software Foundation, Inc.
@c This is part of the GCC manual.
@c For copying conditions, see the file gcc.texi.
@@ -87,14 +87,14 @@ in the following sections.
@item Overall Options
@xref{Overall Options,,Options Controlling the Kind of Output}.
@smallexample
--c -S -E -o @var{file} -pipe -v -x @var{language}
+-c -S -E -o @var{file} -pipe -v -x @var{language}
@end smallexample
@item C Language Options
@xref{C Dialect Options,,Options Controlling C Dialect}.
@smallexample
--ansi -fallow-single-precision -fcond-mismatch -fno-asm
--fno-builtin -fsigned-bitfields -fsigned-char
+-ansi -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
@end smallexample
@@ -103,10 +103,12 @@ in the following sections.
@xref{C++ Dialect Options,,Options Controlling C++ Dialect}.
@smallexample
-fall-virtual -fdollars-in-identifiers -felide-constructors
--fenum-int-equiv -fexternal-templates -ffor-scope -fno-for-scope
--fhandle-signatures -fmemoize-lookups -fno-default-inline -fno-gnu-keywords
--fnonnull-objects -foperator-names -fstrict-prototype
--fthis-is-variable -nostdinc++ -traditional +e@var{n}
+-fenum-int-equiv -fexternal-templates -ffor-scope
+-fno-for-scope -fhandle-signatures -fmemoize-lookups
+-fname-mangling-version-@var{n} -fno-default-inline
+-fno-gnu-keywords -fnonnull-objects -fguiding-decls
+-foperator-names -fno-optional-diags -fstrict-prototype -fthis-is-variable
+-ftemplate-depth-@var{n} -nostdinc++ -traditional +e@var{n}
@end smallexample
@item Warning Options
@@ -114,23 +116,28 @@ in the following sections.
@smallexample
-fsyntax-only -pedantic -pedantic-errors
-w -W -Wall -Waggregate-return -Wbad-function-cast
--Wcast-align -Wcast-qual -Wchar-subscript -Wcomment
--Wconversion -Wenum-clash -Werror -Wformat
--Wid-clash-@var{len} -Wimplicit -Wimport -Winline
--Wlarger-than-@var{len} -Wmissing-declarations
--Wmissing-prototypes -Wnested-externs
--Wno-import -Woverloaded-virtual -Wparentheses
--Wpointer-arith -Wredundant-decls -Wreorder -Wreturn-type -Wshadow
--Wstrict-prototypes -Wswitch -Wsynth -Wtemplate-debugging
--Wtraditional -Wtrigraphs -Wuninitialized -Wunused
--Wwrite-strings
+-Wcast-align -Wcast-qual -Wchar-subscript -Wcomment
+-Wconversion -Werror -Wformat
+-Wid-clash-@var{len} -Wimplicit -Wimplicit-int
+-Wimplicit-function-declaration -Wimport
+-Werror-implicit-function-declaration -Winline
+-Wlarger-than-@var{len} -Wlong-long
+-Wmain -Wmissing-declarations
+-Wmissing-prototypes -Wmultichar -Wnested-externs -Wno-import
+-Wold-style-cast -Woverloaded-virtual -Wparentheses
+-Wpointer-arith -Wredundant-decls -Wreorder -Wreturn-type
+-Wshadow -Wsign-compare -Wstrict-prototypes -Wswitch
+-Wsynth -Wtemplate-debugging -Wtraditional -Wtrigraphs
+-Wundef -Wuninitialized -Wunused -Wwrite-strings
+-Wunknown-pragmas
@end smallexample
@item Debugging Options
@xref{Debugging Options,,Options for Debugging Your Program or GCC}.
@smallexample
--a -d@var{letters} -fpretend-float
--g -g@var{level} -gcoff -gdwarf -gdwarf+
+-a -ax -d@var{letters} -fpretend-float
+-fprofile-arcs -ftest-coverage
+-g -g@var{level} -gcoff -gdwarf -gdwarf-1 -gdwarf-1+ -gdwarf-2
-ggdb -gstabs -gstabs+ -gxcoff -gxcoff+
-p -pg -print-file-name=@var{library} -print-libgcc-file-name
-print-prog-name=@var{program} -print-search-dirs -save-temps
@@ -139,16 +146,20 @@ in the following sections.
@item Optimization Options
@xref{Optimize Options,,Options that Control Optimization}.
@smallexample
+-fbranch-probabilities -foptimize-register-moves
-fcaller-saves -fcse-follow-jumps -fcse-skip-blocks
--fdelayed-branch -fexpensive-optimizations
+-fdelayed-branch -fexpensive-optimizations
-ffast-math -ffloat-store -fforce-addr -fforce-mem
--finline-functions -fkeep-inline-functions
--fno-default-inline -fno-defer-pop -fno-function-cse
--fno-inline -fno-peephole -fomit-frame-pointer
--frerun-cse-after-loop -fschedule-insns
--fschedule-insns2 -fstrength-reduce -fthread-jumps
+-ffunction-sections -fgcse -finline-functions
+-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
--O -O0 -O1 -O2 -O3
+-fmove-all-movables -freduce-all-givs -fstrict-aliasing
+-fstructure-noalias
+-O -O0 -O1 -O2 -O3 -Os
@end smallexample
@item Preprocessor Options
@@ -174,8 +185,8 @@ in the following sections.
@xref{Link Options,,Options for Linking}.
@smallexample
@var{object-file-name} -l@var{library}
--nostartfiles -nodefaultlibs -nostdlib
--s -static -shared -symbolic
+-nostartfiles -nodefaultlibs -nostdlib
+-s -static -shared -symbolic
-Wl,@var{option} -Xlinker @var{option}
-u @var{symbol}
@end smallexample
@@ -183,7 +194,7 @@ in the following sections.
@item Directory Options
@xref{Directory Options,,Options for Directory Search}.
@smallexample
--B@var{prefix} -I@var{dir} -I- -L@var{dir}
+-B@var{prefix} -I@var{dir} -I- -L@var{dir} -specs=@var{file}
@end smallexample
@item Target Options
@@ -197,26 +208,28 @@ in the following sections.
@xref{Submodel Options,,Hardware Models and Configurations}.
@smallexample
@emph{M680x0 Options}
--m68000 -m68020 -m68020-40 -m68030 -m68040 -m68881
--mbitfield -mc68000 -mc68020 -mfpa -mnobitfield
--mrtd -mshort -msoft-float
+-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040
+-m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020
+-mfpa -mnobitfield -mrtd -mshort -msoft-float
+-malign-int
@emph{VAX Options}
-mg -mgnu -munix
@emph{SPARC Options}
--mapp-regs -mcypress -mepilogue -mflat -mfpu -mhard-float
--mhard-quad-float -mno-app-regs -mno-flat -mno-fpu
--mno-epilogue -mno-unaligned-doubles
--msoft-float -msoft-quad-float
--msparclite -msupersparc -munaligned-doubles -mv8
-
-SPARC V9 compilers support the following options
-in addition to the above:
-
--mmedlow -mmedany
--mint32 -mint64 -mlong32 -mlong64
--mno-stack-bias -mstack-bias
+-mcpu=@var{cpu type}
+-mtune=@var{cpu type}
+-mcmodel=@var{code model}
+-malign-jumps=@var{num} -malign-loops=@var{num}
+-malign-functions=@var{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
@emph{Convex Options}
-mc1 -mc2 -mc32 -mc34 -mc38
@@ -224,7 +237,7 @@ in addition to the above:
-mlong32 -mlong64
-mvolatile-cache -mvolatile-nocache
-@emph{AMD29K Options}
+@emph{AMD29K Options}
-m29000 -m29050 -mbw -mnbw -mdw -mndw
-mlarge -mnormal -msmall
-mkernel-registers -mno-reuse-arg-regs
@@ -233,34 +246,70 @@ in addition to the above:
-mstorem-bug -muser-registers
@emph{ARM Options}
--mapcs -m2 -m3 -m6 -mbsd -mxopen -mno-symrename
+-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
+
+@emph{Thumb Options}
+-mtpcs-frame -mno-tpcs-frame
+-mtpcs-leaf-frame -mno-tpcs-leaf-frame
+-mlittle-endian -mbig-endian
+-mthumb-interwork -mno-thumb-interwork
+-mstructure-size-boundary=
+
+@emph{MN10200 Options}
+-mrelax
+
+@emph{MN10300 Options}
+-mmult-bug
+-mno-mult-bug
+-mrelax
+
+@emph{M32R/D Options}
+-mcode-model=@var{model type} -msdata=@var{sdata type}
+-G @var{num}
@emph{M88K Options}
--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
+-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-@var{num} -msvr3
--msvr4 -mtrap-large-shift -muse-div-instruction
+-mserialize-volatile -mshort-data-@var{num} -msvr3
+-msvr4 -mtrap-large-shift -muse-div-instruction
-mversion-03.00 -mwarn-passed-structs
@emph{RS/6000 and PowerPC Options}
--mcpu=@var{cpu type}
+-mcpu=@var{cpu type}
+-mtune=@var{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
--msoft-float -mhard-float -mmultiple -mno-multiple
--mstring -mno-string -mbit-align -mno-bit-align
--mstrict-align -mno-strict-align -mrelocatable -mno-relocatable
--mtoc -mno-toc -mtraceback -mno-traceback
--mlittle -mlittle-endian -mbig -mbig-endian
--mcall-aix -mcall-sysv -mprototype
+-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=@var{opt} -G @var{num}
@emph{RT Options}
-mcall-lib-mul -mfp-arg-in-fpregs -mfp-arg-in-gregs
@@ -268,33 +317,39 @@ in addition to the above:
-mminimum-fp-blocks -mnohc-struct-return
@emph{MIPS Options}
--mabicalls -mcpu=@var{cpu type} -membedded-data
+-mabicalls -mcpu=@var{cpu type} -membedded-data
-membedded-pic -mfp32 -mfp64 -mgas -mgp32 -mgp64
--mgpopt -mhalf-pic -mhard-float -mint64 -mips1
--mips2 -mips3 -mlong64 -mlong-calls -mmemcpy
+-mgpopt -mhalf-pic -mhard-float -mint64 -mips1
+-mips2 -mips3 -mips4 -mlong64 -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
+-mrnames -msoft-float
+-m4650 -msingle-float -mmad
-mstats -EL -EB -G @var{num} -nocpp
+-mabi=32 -mabi=n32 -mabi=64 -mabi=eabi
@emph{i386 Options}
--m486 -m386 -mieee-fp -mno-fancy-math-387
--mno-fp-ret-in-387 -msoft-float -msvr3-shlib
--mno-wide-multiply -mrtd -malign-double
--mreg-alloc=@var{list} -mregparm=@var{num}
--malign-jumps=@var{num} -malign-loops=@var{num}
+-mcpu=@var{cpu type}
+-march=@var{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=@var{list} -mregparm=@var{num}
+-malign-jumps=@var{num} -malign-loops=@var{num}
-malign-functions=@var{num}
@emph{HPPA Options}
--mdisable-fpregs -mdisable-indexing -mfast-indirect-calls
--mgas -mjump-in-delay -mlong-millicode-calls -mno-disable-fpregs
--mno-disable-indexing -mno-fast-indirect-calls -mno-gas
--mno-jump-in-delay -mno-millicode-long-calls
--mno-portable-runtime -mno-soft-float -msoft-float
--mpa-risc-1-0 -mpa-risc-1-1 -mportable-runtime -mschedule=@var{list}
+-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 -mportable-runtime
+-mschedule=@var{list} -mspace -mspace-regs
@emph{Intel 960 Options}
-m@var{cpu type} -masm-compat -mclean-linkage
@@ -307,29 +362,52 @@ in addition to the above:
-mtail-call
@emph{DEC Alpha Options}
--mfp-regs -mno-fp-regs -mno-soft-float
--msoft-float
+-mfp-regs -mno-fp-regs -mno-soft-float -msoft-float
+-malpha-as -mgas
+-mieee -mieee-with-inexact -mieee-conformant
+-mfp-trap-mode=@var{mode} -mfp-rounding-mode=@var{mode}
+-mtrap-precision=@var{mode} -mbuild-constants
+-mcpu=@var{cpu type}
+-mbwx -mno-bwx -mcix -mno-cix -mmax -mno-max
+-mmemory-latency=@var{time}
@emph{Clipper Options}
--mc300 -mc400
+-mc300 -mc400
@emph{H8/300 Options}
--mrelax -mh
+-mrelax -mh -ms -mint32 -malign-300
+
+@emph{SH Options}
+-m1 -m2 -m3 -m3e -mb -ml -mdalign -mrelax
@emph{System V Options}
-Qy -Qn -YP,@var{paths} -Ym,@var{dir}
+
+@emph{ARC Options}
+-EB -EL
+-mmangle-cpu -mcpu=@var{cpu} -mtext=@var{text section}
+-mdata=@var{data section} -mrodata=@var{readonly data section}
+
+@emph{V850 Options}
+-mlong-calls -mno-long-calls -mep -mno-ep
+-mprolog-function -mno-prolog-function -mspace
+-mtda=@var{n} -msda=@var{n} -mzda=@var{n}
+-mv850 -mbig-switch
@end smallexample
@item Code Generation Options
@xref{Code Gen Options,,Options for Code Generation Conventions}.
@smallexample
--fcall-saved-@var{reg} -fcall-used-@var{reg}
--ffixed-@var{reg} -finhibit-size-directive
+-fcall-saved-@var{reg} -fcall-used-@var{reg}
+-fexceptions -ffixed-@var{reg} -finhibit-size-directive
+-fcheck-memory-usage -fprefix-function-name
-fno-common -fno-ident -fno-gnu-linker
--fpcc-struct-return -fpic -fPIC
+-fpcc-struct-return -fpic -fPIC
-freg-struct-return -fshared-data -fshort-enums
-fshort-double -fvolatile -fvolatile-global
--fverbose-asm -fpack-struct +e0 +e1
+-fverbose-asm -fpack-struct -fstack-check +e0 +e1
+-fargument-alias -fargument-noalias
+-fargument-noalias-global
@end smallexample
@end table
@@ -389,7 +467,7 @@ C++ source code which must be preprocessed. Note that in @samp{.cxx},
the last two letters must both be literally @samp{x}. Likewise,
@samp{.C} refers to a literal capital C.
-@item @var{file}.s
+@item @var{file}.s
Assembler code.
@item @var{file}.S
@@ -500,8 +578,8 @@ compiler that understands the C++ language---and under some
circumstances, you might want to compile programs from standard input,
or otherwise without a suffix that flags them as C++ programs.
@code{g++} is a program that calls GNU CC with the default language
-set to C++, and automatically specifies linking against the GNU class
-library libg++.
+set to C++, and automatically specifies linking against the C++
+library.
@cindex @code{g++ 1.@var{xx}}
@cindex @code{g++}, separate compiler
@cindex @code{g++} older version
@@ -542,8 +620,8 @@ This turns off certain features of GNU C that are incompatible with ANSI
C, such as the @code{asm}, @code{inline} and @code{typeof} keywords, and
predefined macros such as @code{unix} and @code{vax} that identify the
type of system you are using. It also enables the undesirable and
-rarely used ANSI trigraph feature, disallows @samp{$} as part of
-identifiers, and disables recognition of C++ style @samp{//} comments.
+rarely used ANSI trigraph feature, and it disables recognition of C++
+style @samp{//} comments.
The alternate keywords @code{__asm__}, @code{__extension__},
@code{__inline__} and @code{__typeof__} continue to work despite
@@ -594,8 +672,8 @@ other, C++-specific, extension keywords such as @code{headof}.
@findex strcmp
@findex strcpy
@findex strlen
-Don't recognize builtin functions that do not begin with two leading
-underscores. Currently, the functions affected include @code{abort},
+Don't recognize builtin functions that do not begin with `__builtin_'
+as prefix. Currently, the functions affected include @code{abort},
@code{abs}, @code{alloca}, @code{cos}, @code{exit}, @code{fabs},
@code{ffs}, @code{labs}, @code{memcmp}, @code{memcpy}, @code{sin},
@code{sqrt}, @code{strcmp}, @code{strcpy}, and @code{strlen}.
@@ -612,6 +690,24 @@ The @samp{-ansi} option prevents @code{alloca} and @code{ffs} from being
builtin functions, since these functions do not have an ANSI standard
meaning.
+@item -fhosted
+@cindex hosted environment
+
+Assert that compilation takes place in a hosted environment. This implies
+@samp{-fbuiltin}. A hosted environment is one in which the
+entire standard library is available, and in which @code{main} has a return
+type of @code{int}. Examples are nearly everything except a kernel.
+This is equivalent to @samp{-fno-freestanding}.
+
+@item -ffreestanding
+@cindex hosted environment
+
+Assert that compilation takes place in a freestanding environment. This
+implies @samp{-fno-builtin}. A freestanding environment
+is one in which the standard library may not exist, and program startup may
+not necessarily be at @code{main}. The most obvious example is an OS kernel.
+This is equivalent to @samp{-fno-hosted}.
+
@item -trigraphs
Support ANSI C trigraphs. You don't want to know about this
brain-damage. The @samp{-ansi} option implies @samp{-trigraphs}.
@@ -684,20 +780,27 @@ rely on ANSI C features. Some vendors are starting to ship systems with
ANSI C header files and you cannot use @samp{-traditional} on such
systems to compile files that include any system headers.
+The @samp{-traditional} option also enables @samp{-traditional-cpp},
+which is described next.
+
+@item -traditional-cpp
+Attempt to support some aspects of traditional C preprocessors.
+Specifically:
+
+@itemize @bullet
@item
-In the preprocessor, comments convert to nothing at all, rather than
-to a space. This allows traditional token concatenation.
+Comments convert to nothing at all, rather than to a space. This allows
+traditional token concatenation.
@item
-In preprocessing directive, the @samp{#} symbol must appear as the first
+In a preprocessing directive, the @samp{#} symbol must appear as the first
character of a line.
@item
-In the preprocessor, macro arguments are recognized within string
-constants in a macro definition (and their values are stringified,
-though without additional quote marks, when they appear in such a
-context). The preprocessor always considers a string constant to end
-at a newline.
+Macro arguments are recognized within string constants in a macro
+definition (and their values are stringified, though without additional
+quote marks, when they appear in such a context). The preprocessor
+always considers a string constant to end at a newline.
@item
@cindex detecting @w{@samp{-traditional}}
@@ -719,11 +822,7 @@ for more discussion of these and other predefined macros.
The preprocessor considers a string constant to end at a newline (unless
the newline is escaped with @samp{\}). (Without @w{@samp{-traditional}},
string constants can contain the newline character as typed.)
-
-@item -traditional-cpp
-Attempt to support some aspects of traditional C preprocessors.
-This includes the last five items in the table immediately above,
-but none of the other effects of @samp{-traditional}.
+@end itemize
@item -fcond-mismatch
Allow conditional expressions with mismatched types in the second and
@@ -754,6 +853,15 @@ Note that this is equivalent to @samp{-fno-unsigned-char}, which is
the negative form of @samp{-funsigned-char}. Likewise, the option
@samp{-fno-signed-char} is equivalent to @samp{-funsigned-char}.
+You may wish to use @samp{-fno-builtin} as well as @samp{-traditional}
+if your program uses names that are normally GNU C builtin functions for
+other purposes of its own.
+
+You cannot use @samp{-traditional} if you include any header files that
+rely on ANSI C features. Some vendors are starting to ship systems with
+ANSI C header files and you cannot use @samp{-traditional} on such
+systems to compile files that include any system headers.
+
@item -fsigned-bitfields
@itemx -funsigned-bitfields
@itemx -fno-signed-bitfields
@@ -844,8 +952,8 @@ two definitions were merged.
@item -fdollars-in-identifiers
Accept @samp{$} in identifiers. You can also explicitly prohibit use of
-@samp{$} with the option @samp{-fno-dollars-in-identifiers}. (GNU C++
-allows @samp{$} by default on some target systems but not others.)
+@samp{$} with the option @samp{-fno-dollars-in-identifiers}. (GNU C allows
+@samp{$} by default on most target systems, but there are a few exceptions.)
Traditional C allowed the character @samp{$} to form part of
identifiers. However, ANSI C and C++ forbid @samp{$} in identifiers.
@@ -860,13 +968,17 @@ Cause template instantiations to obey @samp{#pragma interface} and
to the location of the template definition. @xref{Template
Instantiation}, for more information.
+This option is deprecated.
+
@item -falt-external-templates
Similar to -fexternal-templates, but template instances are emitted or
not according to the place where they are first instantiated.
@xref{Template Instantiation}, for more information.
+This option is deprecated.
+
@item -ffor-scope
-@item -fno-for-scope
+@itemx -fno-for-scope
If -ffor-scope is specified, the scope of variables declared in
a @i{for-init-statement} is limited to the @samp{for} loop itself,
as specified by the draft C++ standard.
@@ -887,6 +999,18 @@ words as identifiers. You can use the keywords @code{__classof__},
@code{__typeof__} instead. @samp{-ansi} implies
@samp{-fno-gnu-keywords}.
+@item -fguiding-decls
+Treat a function declaration with the same type as a potential function
+template instantiation as though it declares that instantiation, not a
+normal function. If a definition is given for the function later in the
+translation unit (or another translation unit if the target supports
+weak symbols), that definition will be used; otherwise the template will
+be instantiated. This behavior reflects the C++ language prior to
+September 1996, when guiding declarations were removed.
+
+This option implies @samp{-fname-mangling-version-0}, and will not work
+with other name mangling versions.
+
@item -fno-implicit-templates
Never emit code for templates which are instantiated implicitly (i.e. by
use); only emit code for explicit instantiations. @xref{Template
@@ -903,7 +1027,7 @@ Support virtual function calls for objects that exceed the size
representable by a @samp{short int}. Users should not use this flag by
default; if you need to use it, the compiler will tell you so. If you
compile any of your code with this flag, you must compile @emph{all} of
-your code with this flag (including libg++, if you use it).
+your code with this flag (including the C++ library, if you use it).
This flag is not useful when compiling with -fvtable-thunks.
@@ -964,6 +1088,17 @@ overridden with @samp{-fno-strict-prototype}.
This flag no longer affects declarations with C++ linkage.
+@item -fname-mangling-version-@var{n}
+Control the way in which names are mangled. Version 0 is compatible
+with versions of g++ before 2.8. Version 1 is the default. Version 1
+will allow correct mangling of function templates. For example,
+version 0 mangling does not mangle foo<int, double> and foo<int, char>
+given this declaration:
+
+@example
+template <class T, class U> void foo(T t);
+@end example
+
@item -fno-nonnull-objects
Don't assume that a reference is initialized to refer to a valid object.
Although the current C++ Working Paper prohibits null references, some
@@ -979,6 +1114,25 @@ Recognize the operator name keywords @code{and}, @code{bitand},
synonyms for the symbols they refer to. @samp{-ansi} implies
@samp{-foperator-names}.
+@item -fno-optional-diags
+Disable diagnostics that the standard says a compiler does not need to
+issue. Currently, this means the diagnostic for a name having multiple
+meanings within a class.
+
+@item -frepo
+Enable automatic template instantiation. This option also implies
+@samp{-fno-implicit-templates}. @xref{Template Instantiation}, for more
+information.
+
+@item -fsquangle
+@itemx -fno-squangle
+@samp{-fsquangle} will enable a compressed form of name mangling for
+identifiers. In particular, it helps to shorten very long names by recognizing
+types and class names which occur more than once, replacing them with special
+short ID codes. This option also requires any C++ libraries being used to
+be compiled with this option as well. The compiler has this disabled (the
+equivalent of @samp{-fno-squangle}) by default.
+
@item -fthis-is-variable
Permit assignment to @code{this}. The incorporation of user-defined
free store management into C++ has made assignment to @samp{this} an
@@ -1001,10 +1155,16 @@ vtables; if a class has any non-inline virtual functions, the vtable
will be emitted in the translation unit containing the first one of
those.
+@item -ftemplate-depth-@var{n}
+Set the maximum instantiation depth for template classes to @var{n}.
+A limit on the template instantiation depth is needed to detect
+endless recursions during template class instantiation. ANSI/ISO C++
+conforming programs must not rely on a maximum depth greater than 17.
+
@item -nostdinc++
Do not search for header files in the standard directories specific to
C++, but do still search the other standard directories. (This option
-is used when building libg++.)
+is used when building the C++ library.)
@item -traditional
For C++ programs (in addition to the effects that apply to both C and
@@ -1020,12 +1180,15 @@ have meanings only for C++ programs:
Do not assume @samp{inline} for functions defined inside a class scope.
@xref{Optimize Options,,Options That Control Optimization}.
-@item -Wenum-clash
+@item -Wold-style-cast
@itemx -Woverloaded-virtual
@itemx -Wtemplate-debugging
Warnings that apply only to C++ programs. @xref{Warning
Options,,Options to Request or Suppress Warnings}.
+@item -Weffc++
+Warn about violation of some style rules from Effective C++ by Scott Myers.
+
@item +e@var{n}
Control how virtual function definitions are used, in a fashion
compatible with @code{cfront} 1.x. @xref{Code Gen Options,,Options for
@@ -1059,13 +1222,13 @@ CC:
Check the code for syntax errors, but don't do anything beyond that.
@item -pedantic
-Issue all the warnings demanded by strict ANSI standard C; reject
-all programs that use forbidden extensions.
+Issue all the warnings demanded by strict ANSI C and ISO C++;
+reject all programs that use forbidden extensions.
-Valid ANSI standard C programs should compile properly with or without
+Valid ANSI C and ISO C++ programs should compile properly with or without
this option (though a rare few will require @samp{-ansi}). However,
-without this option, certain GNU extensions and traditional C features
-are supported as well. With this option, they are rejected.
+without this option, certain GNU extensions and traditional C and C++
+features are supported as well. With this option, they are rejected.
@samp{-pedantic} does not cause warning messages for use of the
alternate keywords whose names begin and end with @samp{__}. Pedantic
@@ -1107,22 +1270,77 @@ of error, as programmers often forget that this type is signed on some
machines.
@item -Wcomment
-Warn whenever a comment-start sequence @samp{/*} appears in a comment.
+Warn whenever a comment-start sequence @samp{/*} appears in a @samp{/*}
+comment, or whenever a Backslash-Newline appears in a @samp{//} comment.
@item -Wformat
Check calls to @code{printf} and @code{scanf}, etc., to make sure that
the arguments supplied have types appropriate to the format string
specified.
-@item -Wimplicit
-Warn whenever a function or parameter is implicitly declared.
+@item -Wimplicit-int
+Warn when a declaration does not specify a type.
+
+@item -Wimplicit-function-declaration
+@itemx -Werror-implicit-function-declaration
+Give a warning (or error) whenever a function is used before being
+declared.
+@item -Wimplicit
+Same as @samp{-Wimplicit-int} and @samp{-Wimplicit-function-}@*
+@samp{declaration}.
+
+@item -Wmain
+Warn if the type of @samp{main} is suspicious. @samp{main} should be a
+function with external linkage, returning int, taking either zero
+arguments, two, or three arguments of appropriate types.
+
+@item -Wmultichar
+Warn if a multicharacter constant (@samp{'FOOF'}) is used. Usually they
+indicate a typo in the user's code, as they have implementation-defined
+values, and should not be used in portable code.
+
@item -Wparentheses
Warn if parentheses are omitted in certain contexts, such
as when there is an assignment in a context where a truth value
is expected, or when operators are nested whose precedence people
often get confused about.
+Also warn about constructions where there may be confusion to which
+@code{if} statement an @code{else} branch belongs. Here is an example of
+such a case:
+
+@smallexample
+@{
+ if (a)
+ if (b)
+ foo ();
+ else
+ bar ();
+@}
+@end smallexample
+
+In C, every @code{else} branch belongs to the innermost possible @code{if}
+statement, which in this example is @code{if (b)}. This is often not
+what the programmer expected, as illustrated in the above example by
+indentation the programmer chose. When there is the potential for this
+confusion, GNU C will issue a warning when this flag is specified.
+To eliminate the warning, add explicit braces around the innermost
+@code{if} statement so there is no way the @code{else} could belong to
+the enclosing @code{if}. The resulting code would look like this:
+
+@smallexample
+@{
+ if (a)
+ @{
+ if (b)
+ foo ();
+ else
+ bar ();
+ @}
+@}
+@end smallexample
+
@item -Wreturn-type
Warn whenever a function is defined with a return-type that defaults
to @code{int}. Also warn about any @code{return} statement with no
@@ -1144,6 +1362,9 @@ whenever a function is declared static but never defined, whenever a
label is declared but not used, and whenever a statement computes a
result that is explicitly not used.
+In order to get a warning about an unused function parameter, you must
+specify both @samp{-W} and @samp{-Wunused}.
+
To suppress this warning for an expression, simply cast it to void. For
unused variables and parameters, use the @samp{unused} attribute
(@pxref{Variable Attributes}).
@@ -1208,12 +1429,6 @@ Some spurious warnings can be avoided if you declare all the functions
you use that never return as @code{noreturn}. @xref{Function
Attributes}.
-@item -Wenum-clash
-@cindex enumeration clash warnings
-@cindex warning for enumeration conversions
-Warn about conversion between different enumeration types.
-(C++ only).
-
@item -Wreorder (C++ only)
@cindex reordering, warning
@cindex warning for reordering of member initializers
@@ -1237,15 +1452,28 @@ members.
When using templates in a C++ program, warn if debugging is not yet
fully available (C++ only).
+@item -Wunknown-pragmas
+@cindex warning for unknown pragmas
+@cindex unknown pragmas, warning
+@cindex pragmas, warning of unknown
+Warn when a #pragma directive is encountered which is not understood by
+GCC. If this command line option is used, warnings will even be issued
+for unknown pragmas in system header files. This is not the case if
+the warnings were only enabled by the @samp{-Wall} command line option.
+
@item -Wall
-All of the above @samp{-W} options combined. These are all the
-options which pertain to usage that we recommend avoiding and that we
-believe is easy to avoid, even in conjunction with macros.
+All of the above @samp{-W} options combined. This enables all the
+warnings about constructions that some users consider questionable, and
+that are easy to avoid (or modify to prevent the warning), even in
+conjunction with macros.
@end table
-The remaining @samp{-W@dots{}} options are not implied by @samp{-Wall}
-because they warn about constructions that we consider reasonable to
-use, on occasion, in clean programs.
+The following @samp{-W@dots{}} options are not implied by @samp{-Wall}.
+Some of them warn about constructions that users generally do not
+consider questionable, but which occasionally you might wish to check
+for; others warn about constructions that are necessary or hard to avoid
+in some cases, and there is no simple way to modify the code to suppress
+the warning.
@table @code
@item -W
@@ -1282,7 +1510,7 @@ foo (a)
@item
An expression-statement or the left-hand side of a comma expression
-contains no side effects.
+contains no side effects.
To suppress the warning, cast the unused expression to void.
For example, an expression such as @samp{x[i,j]} will cause a warning,
but @samp{x[(void)i,j]} will not.
@@ -1304,6 +1532,11 @@ If @samp{-Wall} or @samp{-Wunused} is also specified, warn about unused
arguments.
@item
+A comparison between signed and unsigned values could produce an
+incorrect result when the signed value is converted to unsigned.
+(But don't warn if @samp{-Wno-sign-compare} is also specified.)
+
+@item
An aggregate has a partly bracketed initializer.
For example, the following code would evoke such a warning,
because braces are missing around the initializer for @code{x.h}:
@@ -1313,6 +1546,16 @@ struct s @{ int f, g; @};
struct t @{ struct s h; int i; @};
struct t x = @{ 1, 2, 3 @};
@end smallexample
+
+@item
+An aggregate has an initializer which does not initialize all members.
+For example, the following code would cause such a warning, because
+@code{x.h} would be implicitly initialized to zero:
+
+@smallexample
+struct s @{ int f, g, h; @};
+struct s x = @{ 3, 4 @};
+@end smallexample
@end itemize
@item -Wtraditional
@@ -1333,6 +1576,9 @@ the block.
A @code{switch} statement has an operand of type @code{long}.
@end itemize
+@item -Wundef
+Warn if an undefined identifier is evaluated in an @samp{#if} directive.
+
@item -Wshadow
Warn whenever a local variable shadows another local variable.
@@ -1386,6 +1632,15 @@ converted to an unsigned type. For example, warn about the assignment
@code{x = -1} if @code{x} is unsigned. But do not warn about explicit
casts like @code{(unsigned) -1}.
+@item -Wsign-compare
+@cindex warning for comparison of signed and unsigned values
+@cindex comparison of signed and unsigned values, warning
+@cindex signed and unsigned values, comparison warning
+Warn when a comparison between signed and unsigned values could produce
+an incorrect result when the signed value is converted to unsigned.
+This warning is also enabled by @samp{-W}; to get the other warnings
+of @samp{-W} without this warning, use @samp{-W -Wno-sign-compare}.
+
@item -Waggregate-return
Warn if any functions that return structures or unions are defined or
called. (In languages where you can return an array, this also elicits
@@ -1420,6 +1675,9 @@ Warn if an @code{extern} declaration is encountered within an function.
Warn if a function can not be inlined, and either it was declared as inline,
or else the @samp{-finline-functions} option was given.
+@item -Wold-style-cast
+Warn if an old-style (C-style) cast is used within a program.
+
@item -Woverloaded-virtual
@cindex overloaded virtual fn, warning
@cindex warning for overloaded virtual fn
@@ -1453,6 +1711,12 @@ main ()
In this example, g++ will synthesize a default @samp{A& operator =
(const A&);}, while cfront will use the user-defined @samp{operator =}.
+@item -Wlong-long
+Warn if @samp{long long} type is used. This is default. To inhibit
+the warning messages, use @samp{-Wno-long-long}. Flags
+@samp{-Wlong-long} and @samp{-Wno-long-long} are taken into account
+only when @samp{-pedantic} flag is used.
+
@item -Werror
Make all warnings into errors.
@end table
@@ -1477,7 +1741,7 @@ makes debugging work better in GDB but will probably make other debuggers
crash or
refuse to read the program. If you want to control for certain whether
to generate the extra information, use @samp{-gstabs+}, @samp{-gstabs},
-@samp{-gxcoff+}, @samp{-gxcoff}, @samp{-gdwarf+}, or @samp{-gdwarf}
+@samp{-gxcoff+}, @samp{-gxcoff}, @samp{-gdwarf-1+}, or @samp{-gdwarf-1}
(see below).
Unlike most other C compilers, GNU CC allows you to use @samp{-g} with
@@ -1495,8 +1759,10 @@ The following options are useful when GNU CC is generated with the
capability for more than one debugging format.
@item -ggdb
-Produce debugging information in the native format (if that is supported),
-including GDB extensions if at all possible.
+Produce debugging information for use by GDB. This means to use the
+most expressive format available (DWARF 2, stabs, or the native format
+if neither of those are supported), including GDB extensions if at all
+possible.
@item -gstabs
Produce debugging information in stabs format (if that is supported),
@@ -1528,14 +1794,19 @@ refuse to read the program, and may cause assemblers other than the GNU
assembler (GAS) to fail with an error.
@item -gdwarf
-Produce debugging information in DWARF format (if that is supported).
-This is the format used by SDB on most System V Release 4 systems.
+Produce debugging information in DWARF version 1 format (if that is
+supported). This is the format used by SDB on most System V Release 4
+systems.
@item -gdwarf+
-Produce debugging information in DWARF format (if that is supported),
-using GNU extensions understood only by the GNU debugger (GDB). The
-use of these extensions is likely to make other debuggers crash or
-refuse to read the program.
+Produce debugging information in DWARF version 1 format (if that is
+supported), using GNU extensions understood only by the GNU debugger
+(GDB). The use of these extensions is likely to make other debuggers
+crash or refuse to read the program.
+
+@item -gdwarf-2
+Produce debugging information in DWARF version 2 format (if that is
+supported). This is the format used by DBX on IRIX 6.
@item -g@var{level}
@itemx -ggdb@var{level}
@@ -1543,6 +1814,7 @@ refuse to read the program.
@itemx -gcoff@var{level}
@itemx -gxcoff@var{level}
@itemx -gdwarf@var{level}
+@itemx -gdwarf-2@var{level}
Request debugging information and also use @var{level} to specify how
much information. The default level is 2.
@@ -1582,6 +1854,135 @@ This data could be analyzed by a program like @code{tcov}. Note,
however, that the format of the data is not what @code{tcov} expects.
Eventually GNU @code{gprof} should be extended to process this data.
+@item -Q
+Makes the compiler print out each function name as it is compiled, and
+print some statistics about each pass when it finishes.
+
+@item -ax
+Generate extra code to profile basic blocks. Your executable will
+produce output that is a superset of that produced when @samp{-a} is
+used. Additional output is the source and target address of the basic
+blocks where a jump takes place, the number of times a jump is executed,
+and (optionally) the complete sequence of basic blocks being executed.
+The output is appended to file @file{bb.out}.
+
+You can examine different profiling aspects without recompilation. Your
+executable will read a list of function names from file @file{bb.in}.
+Profiling starts when a function on the list is entered and stops when
+that invocation is exited. To exclude a function from profiling, prefix
+its name with `-'. If a function name is not unique, you can
+disambiguate it by writing it in the form
+@samp{/path/filename.d:functionname}. Your executable will write the
+available paths and filenames in file @file{bb.out}.
+
+Several function names have a special meaning:
+@table @code
+@item __bb_jumps__
+Write source, target and frequency of jumps to file @file{bb.out}.
+@item __bb_hidecall__
+Exclude function calls from frequency count.
+@item __bb_showret__
+Include function returns in frequency count.
+@item __bb_trace__
+Write the sequence of basic blocks executed to file @file{bbtrace.gz}.
+The file will be compressed using the program @samp{gzip}, which must
+exist in your @code{PATH}. On systems without the @samp{popen}
+function, the file will be named @file{bbtrace} and will not be
+compressed. @strong{Profiling for even a few seconds on these systems
+will produce a very large file.} Note: @code{__bb_hidecall__} and
+@code{__bb_showret__} will not affect the sequence written to
+@file{bbtrace.gz}.
+@end table
+
+Here's a short example using different profiling parameters
+in file @file{bb.in}. Assume function @code{foo} consists of basic blocks
+1 and 2 and is called twice from block 3 of function @code{main}. After
+the calls, block 3 transfers control to block 4 of @code{main}.
+
+With @code{__bb_trace__} and @code{main} contained in file @file{bb.in},
+the following sequence of blocks is written to file @file{bbtrace.gz}:
+0 3 1 2 1 2 4. The return from block 2 to block 3 is not shown, because
+the return is to a point inside the block and not to the top. The
+block address 0 always indicates, that control is transferred
+to the trace from somewhere outside the observed functions. With
+@samp{-foo} added to @file{bb.in}, the blocks of function
+@code{foo} are removed from the trace, so only 0 3 4 remains.
+
+With @code{__bb_jumps__} and @code{main} contained in file @file{bb.in},
+jump frequencies will be written to file @file{bb.out}. The
+frequencies are obtained by constructing a trace of blocks
+and incrementing a counter for every neighbouring pair of blocks
+in the trace. The trace 0 3 1 2 1 2 4 displays the following
+frequencies:
+
+@example
+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)
+@end example
+
+With @code{__bb_hidecall__}, control transfer due to call instructions
+is removed from the trace, that is the trace is cut into three parts: 0
+3 4, 0 1 2 and 0 1 2. With @code{__bb_showret__}, control transfer due
+to return instructions is added to the trace. The trace becomes: 0 3 1
+2 3 1 2 3 4. Note, that this trace is not the same, as the sequence
+written to @file{bbtrace.gz}. It is solely used for counting jump
+frequencies.
+
+@item -fprofile-arcs
+Instrument @dfn{arcs} during compilation. For each function of your
+program, GNU CC creates a program flow graph, then finds a spanning tree
+for the graph. Only arcs that are not on the spanning tree have to be
+instrumented: the compiler adds code to count the number of times that these
+arcs are executed. When an arc is the only exit or only entrance to a
+block, the instrumentation code can be added to the block; otherwise, a
+new basic block must be created to hold the instrumentation code.
+
+Since not every arc in the program must be instrumented, programs
+compiled with this option run faster than programs compiled with
+@samp{-a}, which adds instrumentation code to every basic block in the
+program. The tradeoff: since @code{gcov} does not have
+execution counts for all branches, it must start with the execution
+counts for the instrumented branches, and then iterate over the program
+flow graph until the entire graph has been solved. Hence, @code{gcov}
+runs a little more slowly than a program which uses information from
+@samp{-a}.
+
+@samp{-fprofile-arcs} also makes it possible to estimate branch
+probabilities, and to calculate basic block execution counts. In
+general, basic block execution counts do not give enough information to
+estimate all branch probabilities. When the compiled program exits, it
+saves the arc execution counts to a file called
+@file{@var{sourcename}.da}. Use the compiler option
+@samp{-fbranch-probabilities} (@pxref{Optimize Options,,Options that
+Control Optimization}) when recompiling, to optimize using estimated
+branch probabilities.
+
+@need 2000
+@item -ftest-coverage
+Create data files for the @code{gcov} code-coverage utility
+(@pxref{Gcov,, @code{gcov}: a GNU CC Test Coverage Program}).
+The data file names begin with the name of your source file:
+
+@table @code
+@item @var{sourcename}.bb
+A mapping from basic blocks to line numbers, which @code{gcov} uses to
+associate basic block execution counts with line numbers.
+
+@item @var{sourcename}.bbg
+A list of all arcs in the program flow graph. This allows @code{gcov}
+to reconstruct the program flow graph, so that it can compute all basic
+block and arc execution counts from the information in the
+@code{@var{sourcename}.da} file (this last file is the output from
+@samp{-fprofile-arcs}).
+@end table
+
+@item -Q
+Makes the compiler print out each function name as it is compiled, and
+print some statistics about each pass when it finishes.
+
@item -d@var{letters}
Says to make debugging dumps during compilation at times specified by
@var{letters}. This is used for debugging the compiler. The file names
@@ -1590,11 +1991,12 @@ name (e.g. @file{foo.c.rtl} or @file{foo.c.jump}). Here are the
possible letters for use in @var{letters}, and their meanings:
@table @samp
-@item M
-Dump all macro definitions, at the end of preprocessing, and write no
-output.
-@item N
-Dump all macro names, at the end of preprocessing.
+@item b
+Dump after computing branch probabilities, to @file{@var{file}.bp}.
+@item c
+Dump after instruction combination, to the file @file{@var{file}.combine}.
+@item d
+Dump after delayed branch scheduling, to @file{@var{file}.dbr}.
@item D
Dump all macro definitions, at the end of preprocessing, in addition to
normal output.
@@ -1610,34 +2012,44 @@ Dump after first jump optimization, to @file{@var{file}.jump}.
@item s
Dump after CSE (including the jump optimization that sometimes
follows CSE), to @file{@var{file}.cse}.
-@item L
-Dump after loop optimization, to @file{@var{file}.loop}.
-@item t
-Dump after the second CSE pass (including the jump optimization that
-sometimes follows CSE), to @file{@var{file}.cse2}.
+@item F
+Dump after purging ADDRESSOF, to @file{@var{file}.addressof}.
@item f
Dump after flow analysis, to @file{@var{file}.flow}.
-@item c
-Dump after instruction combination, to the file
-@file{@var{file}.combine}.
-@item S
-Dump after the first instruction scheduling pass, to
-@file{@var{file}.sched}.
-@item l
-Dump after local register allocation, to
-@file{@var{file}.lreg}.
@item g
-Dump after global register allocation, to
-@file{@var{file}.greg}.
-@item R
-Dump after the second instruction scheduling pass, to
-@file{@var{file}.sched2}.
+Dump after global register allocation, to @file{@var{file}.greg}.
+@item G
+Dump after GCSE, to @file{@var{file}.gcse}.
+@item j
+Dump after first jump optimization, to @file{@var{file}.jump}.
@item J
Dump after last jump optimization, to @file{@var{file}.jump2}.
-@item d
-Dump after delayed branch scheduling, to @file{@var{file}.dbr}.
@item k
Dump after conversion from registers to stack, to @file{@var{file}.stack}.
+@item l
+Dump after local register allocation, to @file{@var{file}.lreg}.
+@item L
+Dump after loop optimization, to @file{@var{file}.loop}.
+@item M
+Dump after performing the machine dependent reorganisation pass, to
+@file{@var{file}.mach}.
+@item N
+Dump after the register move pass, to @file{@var{file}.regmove}.
+@item r
+Dump after RTL generation, to @file{@var{file}.rtl}.
+@item R
+Dump after the second instruction scheduling pass, to @file{@var{file}.sched2}.
+@item s
+Dump after CSE (including the jump optimization that sometimes follows
+CSE), to @file{@var{file}.cse}.
+@item S
+Dump after the first instruction scheduling pass, to @file{@var{file}.sched}.
+@item t
+Dump after the second CSE pass (including the jump optimization that
+sometimes follows CSE), to @file{@var{file}.cse2}.
+@item x
+Just generate RTL for a function instead of compiling it. Usually used
+with @samp{r}.
@item a
Produce all the dumps listed above.
@item m
@@ -1646,6 +2058,10 @@ standard error.
@item p
Annotate the assembler output with a comment indicating which
pattern and alternative was used.
+@item y
+Dump debugging information during parsing, to standard error.
+@item A
+Annotate the assembler output with miscellaneous debugging information.
@end table
@item -fpretend-float
@@ -1746,6 +2162,11 @@ Optimize yet more. @samp{-O3} turns on all optimizations specified by
@item -O0
Do not optimize.
+@item -Os
+Optimize for size. @samp{-Os} enables all @samp{-O2} optimizations that
+do not typically increase code size. It also performs further
+optimizations designed to reduce code size.
+
If you use multiple @samp{-O} options, with or without level numbers,
the last such option is the one that is effective.
@end table
@@ -1763,12 +2184,13 @@ Do not store floating point variables in registers, and inhibit other
options that might change whether a floating point value is taken from a
register or memory.
+@cindex floating point precision
This option prevents undesirable excess precision on machines such as
the 68000 where the floating registers (of the 68881) keep more
-precision than a @code{double} is supposed to have. For most programs,
-the excess precision does only good, but a few programs rely on the
-precise definition of IEEE floating point. Use @samp{-ffloat-store} for
-such programs.
+precision than a @code{double} is supposed to have. Similarly for the
+x86 architecture. For most programs, the excess precision does only
+good, but a few programs rely on the precise definition of IEEE floating
+point. Use @samp{-ffloat-store} for such programs.
@item -fno-default-inline
Do not make member functions inline by default merely because they are
@@ -1835,7 +2257,16 @@ assembler code in its own right.
@item -fkeep-inline-functions
Even if all calls to a given function are integrated, and the function
is declared @code{static}, nevertheless output a separate run-time
-callable version of the function.
+callable version of the function. This switch does not affect
+@code{extern inline} functions.
+
+@item -fkeep-static-consts
+Emit variables declared @code{static const} when optimization isn't turned
+on, even if the variables aren't referenced.
+
+GNU CC enables this option by default. If you want to force the compiler to
+check if the variable was referenced, regardless of whether or not
+optimization is turned on, use the @samp{-fno-keep-static-consts} option.
@item -fno-function-cse
Do not put function addresses in registers; make each instruction that
@@ -1852,8 +2283,8 @@ example, it allows the compiler to assume arguments to the @code{sqrt}
function are non-negative numbers and that no floating-point values
are NaNs.
-This option should never be turned on by any @samp{-O} option since
-it can result in incorrect output for programs which depend on
+This option should never be turned on by any @samp{-O} option since
+it can result in incorrect output for programs which depend on
an exact implementation of IEEE or ANSI rules/specifications for
math functions.
@end table
@@ -1897,11 +2328,29 @@ body of the @code{if}.
@item -frerun-cse-after-loop
Re-run common subexpression elimination after loop optimizations has been
-performed.
+performed.
+
+@item -frerun-loop-opt
+Run the loop optimizer twice.
+
+@item -fgcse
+Perform a global common subexpression elimination pass.
+This pass also performs global constant and copy propagation.
@item -fexpensive-optimizations
Perform a number of minor optimizations that are relatively expensive.
+@item -foptimize-register-moves
+@item -fregmove
+Attempt to reassign register numbers in move instructions and as
+operands of other simple instructions in order to maximize the amount of
+register tying. This is especially helpful on machines with two-operand
+instructions. GNU CC enables this optimization by default with @samp{-O2}
+or higher.
+
+Note @code{-fregmove} and @code{-foptimize-register-moves} are the same
+optimization.
+
@item -fdelayed-branch
If supported for the target machine, attempt to reorder instructions
to exploit instruction slots available after delayed branch
@@ -1920,6 +2369,24 @@ instruction scheduling after register allocation has been done. This is
especially useful on machines with a relatively small number of
registers and where memory load instructions take more than one cycle.
+@item -ffunction-sections
+Place each function into its own section in the output file if the
+target supports arbitrary sections. The function's name determines
+the section's name in the output file.
+
+Use this option on systems where the linker can perform optimizations
+to improve locality of reference in the instruction space. HPPA
+processors running HP-UX and Sparc processors running Solaris 2 have
+linkers with such optimizations. Other systems using the ELF object format
+as well as AIX may have these optimizations in the future.
+
+Only use this option when there are significant benefits from doing
+so. When you specify this option, the assembler and linker will
+create larger object and executable files and will also be slower.
+You will not be able to use @code{gprof} on all systems if you
+specify this option and you may have problems with debugging if
+you specify both this option and @samp{-g}.
+
@item -fcaller-saves
Enable values to be allocated in registers that will be clobbered by
function calls, by emitting extra instructions to save and restore the
@@ -1940,8 +2407,112 @@ Perform the optimization of loop unrolling. This is done for all loops
and usually makes programs run more slowly. @samp{-funroll-all-loops}
implies @samp{-fstrength-reduce} as well as @samp{-frerun-cse-after-loop}.
+@item -fmove-all-movables
+Forces all invariant computations in loops to be moved
+outside the loop.
+
+@item -freduce-all-givs
+Forces all general-induction variables in loops to be
+strength-reduced.
+
+@emph{Note:} When compiling programs written in Fortran,
+@samp{-fmove-all-moveables} and @samp{-freduce-all-givs} are enabled
+by default when you use the optimizer.
+
+These options may generate better or worse code; results are highly
+dependent on the structure of loops within the source code.
+
+These two options are intended to be removed someday, once
+they have helped determine the efficacy of various
+approaches to improving loop optimizations.
+
+Please let us (@code{egcs@@egcs.cygnus.com} and @code{fortran@@gnu.org})
+know how use of these options affects
+the performance of your production code.
+We're very interested in code that runs @emph{slower}
+when these options are @emph{enabled}.
+
@item -fno-peephole
Disable any machine-specific peephole optimizations.
+
+@item -fbranch-probabilities
+After running a program compiled with @samp{-fprofile-arcs}
+(@pxref{Debugging Options,, Options for Debugging Your Program or
+@code{gcc}}), you can compile it a second time using
+@samp{-fbranch-probabilities}, to improve optimizations based on
+guessing the path a branch might take.
+
+@ifset INTERNALS
+With @samp{-fbranch-probabilities}, GCC puts a @samp{REG_EXEC_COUNT}
+note on the first instruction of each basic block, and a
+@samp{REG_BR_PROB} note on each @samp{JUMP_INSN} and @samp{CALL_INSN}.
+These can be used to improve optimization. Currently, they are only
+used in one place: in @file{reorg.c}, instead of guessing which path a
+branch is mostly to take, the @samp{REG_BR_PROB} values are used to
+exactly determine which path is taken more often.
+@end ifset
+
+@item -fstrict-aliasing
+Allows the compiler to assume the strictest aliasing rules applicable to
+the language being compiled. For C (and C++), this activates
+optimizations based on the type of expressions. In particular, an
+object of one type is assumed never to reside at the same address as an
+object of a different type, unless the types are almost the same. For
+example, an @code{unsigned int} can alias an @code{int}, but not a
+@code{void*} or a @code{double}. A character type may alias any other
+type.
+
+Pay special attention to code like this:
+@example
+union a_union @{
+ int i;
+ double d;
+@};
+
+int f() @{
+ a_union t;
+ t.d = 3.0;
+ return t.i;
+@}
+@end example
+The practice of reading from a different union member than the one most
+recently written to (called ``type-punning'') is common. Even with
+@samp{-fstrict-aliasing}, type-punning is allowed, provided the memory
+is accessed through the union type. So, the code above will work as
+expected. However, this code might not:
+@example
+int f() @{
+ a_union t;
+ int* ip;
+ t.d = 3.0;
+ ip = &t.i;
+ return *ip;
+@}
+@end example
+
+This option is not enabled by default at any optimization level because
+it is new and has yet to be subjected to thorough testing. You may
+of course enable it manually with @samp{-fstrict-aliasing}.
+
+@ifset INTERNALS
+Every language that wishes to perform language-specific alias analysis
+should define a function that computes, given an @code{tree}
+node, an alias set for the node. Nodes in different alias sets are not
+allowed to alias. For an example, see the C front-end function
+@code{c_get_alias_set}.
+@end ifset
+
+@item -fstructure-noalias
+Allows the compiler to assume that structure / varying array references
+do not alias fixed scalars.
+
+Although this optimization is safe, GCC can occasionally lose track
+of which references refer to scalars and which to structures,
+leading it to perform unsafe transformations. Release 1.2 of EGCS
+will incorporate changes which allow GCC to track the
+scalar/structure distinction safely. Thus, the optimization will
+always be same, and this option will likely be removed or will have
+no effect.
@end table
@node Preprocessor Options
@@ -2192,12 +2763,20 @@ or @code{-nodefaultlibs} is used.
Do not use the standard system libraries when linking.
Only the libraries you specify will be passed to the linker.
The standard startup files are used normally, unless @code{-nostartfiles}
-is used.
+is used. The compiler may generate calls to memcmp, memset, and memcpy
+for System V (and ANSI C) environments or to bcopy and bzero for
+BSD environments. These entries are usually resolved by entries in
+libc. These entry points should be supplied through some other
+mechanism when this option is specified.
@item -nostdlib
Do not use the standard system startup files or libraries when linking.
No startup files and only the libraries you specify will be passed to
-the linker.
+the linker. The compiler may generate calls to memcmp, memset, and memcpy
+for System V (and ANSI C) environments or to bcopy and bzero for
+BSD environments. These entries are usually resolved by entries in
+libc. These entry points should be supplied through some other
+mechanism when this option is specified.
@cindex @code{-lgcc}, use with @code{-nostdlib}
@cindex @code{-nostdlib} and unresolved references
@@ -2233,7 +2812,9 @@ libraries. On other systems, this option has no effect.
@item -shared
Produce a shared object which can then be linked with other objects to
-form an executable. Only a few systems support this option.
+form an executable. Not all systems support this option. You must
+also specify @samp{-fpic} or @samp{-fPIC} on some systems when
+you specify this option.
@item -symbolic
Bind references to global symbols when building a shared object. Warn
@@ -2274,9 +2855,9 @@ libraries and for parts of the compiler:
@table @code
@item -I@var{dir}
-Add the directory @var{directory} to the head of the list of directories
-to be searched for header files. This can be used to override a system
-header file, substituting your own version, since these directories are
+Add the directory @var{dir} to the head of the list of directories to be
+searched for header files. This can be used to override a system header
+file, substituting your own version, since these directories are
searched before the system header file directories. If you use more
than one @samp{-I} option, the directories are scanned in left-to-right
order; the standard system directories come after.
@@ -2339,6 +2920,14 @@ out of the link if it is not found by those means.
Another way to specify a prefix much like the @samp{-B} prefix is to use
the environment variable @code{GCC_EXEC_PREFIX}. @xref{Environment
Variables}.
+
+@item -specs=@var{file}
+Process @var{file} after the compiler reads in the standard @file{specs}
+file, in order to override the defaults that the @file{gcc} driver
+program uses when determining what switches to pass to @file{cc1},
+@file{cc1plus}, @file{as}, @file{ld}, etc. More than one
+@samp{-specs=}@var{file} can be specified on the command line, and they
+are processed in order, from left to right.
@end table
@node Target Options
@@ -2456,6 +3045,10 @@ that macro, which enables you to change the defaults.
* Convex Options::
* AMD29K Options::
* ARM Options::
+* Thumb Options::
+* MN10200 Options::
+* MN10300 Options::
+* M32R/D Options::
* M88K Options::
* RS/6000 and PowerPC Options::
* RT Options::
@@ -2466,7 +3059,10 @@ that macro, which enables you to change the defaults.
* DEC Alpha Options::
* Clipper Options::
* H8/300 Options::
+* SH Options::
* System V Options::
+* V850 Options::
+* ARC Options::
@end menu
@node M680x0 Options
@@ -2484,6 +3080,9 @@ given below.
Generate output for a 68000. This is the default
when the compiler is configured for 68000-based systems.
+Use this option for microcontrollers with a 68000 or EC000 core,
+including the 68008, 68302, 68306, 68307, 68322, 68328 and 68356.
+
@item -m68020
@itemx -mc68020
Generate output for a 68020. This is the default
@@ -2503,8 +3102,32 @@ Generate output for a 68040. This is the default when the compiler is
configured for 68040-based systems.
This option inhibits the use of 68881/68882 instructions that have to be
-emulated by software on the 68040. If your 68040 does not have code to
-emulate those instructions, use @samp{-m68040}.
+emulated by software on the 68040. Use this option if your 68040 does not
+have code to emulate those instructions.
+
+@item -m68060
+Generate output for a 68060. This is the default when the compiler is
+configured for 68060-based systems.
+
+This option inhibits the use of 68020 and 68881/68882 instructions that
+have to be emulated by software on the 68060. Use this option if your 68060
+does not have code to emulate those instructions.
+
+@item -mcpu32
+Generate output for a CPU32. This is the default
+when the compiler is configured for CPU32-based systems.
+
+Use this option for microcontrollers with a
+CPU32 or CPU32+ core, including the 68330, 68331, 68332, 68333, 68334,
+68336, 68340, 68341, 68349 and 68360.
+
+@item -m5200
+Generate output for a 520X "coldfire" family cpu. This is the default
+when the compiler is configured for 520X-based systems.
+
+Use this option for microcontroller with a 5200 core, including
+the MCF5202, MCF5203, MCF5204 and MCF5202.
+
@item -m68020-40
Generate output for a 68040, without using any of the new instructions.
@@ -2512,6 +3135,12 @@ This results in code which can run relatively efficiently on either a
68020/68881 or a 68030 or a 68040. The generated code does use the
68881 instructions that are emulated on the 68040.
+@item -m68020-60
+Generate output for a 68060, without using any of the new instructions.
+This results in code which can run relatively efficiently on either a
+68020/68881 or a 68030 or a 68040. The generated code does use the
+68881 instructions that are emulated on the 68060.
+
@item -mfpa
Generate output containing Sun FPA instructions for floating point.
@@ -2528,8 +3157,8 @@ cross-compilation. The embedded targets @samp{m68k-*-aout} and
Consider type @code{int} to be 16 bits wide, like @code{short int}.
@item -mnobitfield
-Do not use the bit-field instructions. The @samp{-m68000} option
-implies @w{@samp{-mnobitfield}}.
+Do not use the bit-field instructions. The @samp{-m68000}, @samp{-mcpu32}
+and @samp{-m5200} options imply @w{@samp{-mnobitfield}}.
@item -mbitfield
Do use the bit-field instructions. The @samp{-m68020} option implies
@@ -2556,8 +3185,21 @@ In addition, seriously incorrect code will result if you call a
function with too many arguments. (Normally, extra arguments are
harmlessly ignored.)
-The @code{rtd} instruction is supported by the 68010 and 68020
-processors, but not by the 68000.
+The @code{rtd} instruction is supported by the 68010, 68020, 68030,
+68040, 68060 and CPU32 processors, but not by the 68000 or 5200.
+
+@item -malign-int
+@itemx -mno-align-int
+Control whether GNU CC aligns @code{int}, @code{long}, @code{long long},
+@code{float}, @code{double}, and @code{long double} variables on a 32-bit
+boundary (@samp{-malign-int}) or a 16-bit boundary (@samp{-mno-align-int}).
+Aligning variables on 32-bit boundaries produces code that runs somewhat
+faster on processors with 32-bit busses at the expense of more memory.
+
+@strong{Warning:} if you use the @samp{-malign-int} switch, GNU CC will
+align structures containing the above types differently than
+most published application binary interface specifications for the m68k.
+
@end table
@node VAX Options
@@ -2649,10 +3291,9 @@ at every function exit.
With @samp{-mflat}, the compiler does not generate save/restore instructions
and will use a "flat" or single register window calling convention.
This model uses %i7 as the frame pointer and is compatible with the normal
-register window model. Code from either may be intermixed although
-debugger support is still incomplete. The local registers and the input
-registers (0-5) are still treated as "call saved" registers and will be
-saved on the stack as necessary.
+register window model. Code from either may be intermixed.
+The local registers and the input registers (0-5) are still treated as
+"call saved" registers and will be saved on the stack as necessary.
With @samp{-mno-flat} (the default), the compiler emits save/restore
instructions (except for leaf functions) and is the normal mode of operation.
@@ -2683,6 +3324,9 @@ divide instructions which exist in SPARC v8 but not in SPARC v7.
multiply, integer divide step and scan (@code{ffs}) instructions which
exist in SPARClite but not in SPARC v7.
+These options are deprecated and will be deleted in GNU CC 2.9.
+They have been replaced with @samp{-mcpu=xxx}.
+
@item -mcypress
@itemx -msupersparc
These two options select the processor for which the code is optimised.
@@ -2694,39 +3338,117 @@ This is also appropriate for the older SparcStation 1, 2, IPX etc.
With @samp{-msupersparc} the compiler optimizes code for the SuperSparc cpu, as
used in the SparcStation 10, 1000 and 2000 series. This flag also enables use
of the full SPARC v8 instruction set.
-@end table
-In a future version of GCC, these options will very likely be
-renamed to @samp{-mcpu=cypress} and @samp{-mcpu=supersparc}.
+These options are deprecated and will be deleted in GNU CC 2.9.
+They have been replaced with @samp{-mcpu=xxx}.
-These @samp{-m} switches are supported in addition to the above
-on SPARC V9 processors:
+@item -mcpu=@var{cpu_type}
+Set the instruction set, register set, and instruction scheduling parameters
+for machine type @var{cpu_type}. Supported values for @var{cpu_type} are
+@samp{v7}, @samp{cypress}, @samp{v8}, @samp{supersparc}, @samp{sparclite},
+@samp{f930}, @samp{f934}, @samp{sparclet}, @samp{tsc701}, @samp{v9}, and
+@samp{ultrasparc}.
-@table @code
-@item -mmedlow
-Generate code for the Medium/Low code model: assume a 32 bit address space.
-Programs are statically linked, PIC is not supported. Pointers are still
-64 bits.
+Default instruction scheduling parameters are used for values that select
+an architecture and not an implementation. These are @samp{v7}, @samp{v8},
+@samp{sparclite}, @samp{sparclet}, @samp{v9}.
-It is very likely that a future version of GCC will rename this option.
+Here is a list of each supported architecture and their supported
+implementations.
-@item -mmedany
-Generate code for the Medium/Anywhere code model: assume a 32 bit text
-segment starting at offset 0, and a 32 bit data segment starting anywhere
-(determined at link time). Programs are statically linked, PIC is not
-supported. Pointers are still 64 bits.
+@smallexample
+ v7: cypress
+ v8: supersparc
+ sparclite: f930, f934
+ sparclet: tsc701
+ v9: ultrasparc
+@end smallexample
-It is very likely that a future version of GCC will rename this option.
+@item -mtune=@var{cpu_type}
+Set the instruction scheduling parameters for machine type
+@var{cpu_type}, but do not set the instruction set or register set that the
+option @samp{-mcpu=}@var{cpu_type} would.
-@item -mint64
-Types long and int are 64 bits.
+The same values for @samp{-mcpu=}@var{cpu_type} are used for
+@samp{-mtune=}@*@var{cpu_type}, though the only useful values are those that
+select a particular cpu implementation: @samp{cypress}, @samp{supersparc},
+@samp{f930}, @samp{f934}, @samp{tsc701}, @samp{ultrasparc}.
-@item -mlong32
-Types long and int are 32 bits.
+@item -malign-loops=@var{num}
+Align loops to a 2 raised to a @var{num} byte boundary. If
+@samp{-malign-loops} is not specified, the default is 2.
-@item -mlong64
-@itemx -mint32
-Type long is 64 bits, and type int is 32 bits.
+@item -malign-jumps=@var{num}
+Align instructions that are only jumped to to a 2 raised to a @var{num}
+byte boundary. If @samp{-malign-jumps} is not specified, the default is 2.
+
+@item -malign-functions=@var{num}
+Align the start of functions to a 2 raised to @var{num} byte boundary.
+If @samp{-malign-functions} is not specified, the default is 2 if compiling
+for 32 bit sparc, and 5 if compiling for 64 bit sparc.
+
+@end table
+
+These @samp{-m} switches are supported in addition to the above
+on the SPARCLET processor.
+
+@table @code
+@item -mlittle-endian
+Generate code for a processor running in little-endian mode.
+
+@item -mlive-g0
+Treat register @code{%g0} as a normal register.
+GCC will continue to clobber it as necessary but will not assume
+it always reads as 0.
+
+@item -mbroken-saverestore
+Generate code that does not use non-trivial forms of the @code{save} and
+@code{restore} instructions. Early versions of the SPARCLET processor do
+not correctly handle @code{save} and @code{restore} instructions used with
+arguments. They correctly handle them used without arguments. A @code{save}
+instruction used without arguments increments the current window pointer
+but does not allocate a new stack frame. It is assumed that the window
+overflow trap handler will properly handle this case as will interrupt
+handlers.
+@end table
+
+These @samp{-m} switches are supported in addition to the above
+on SPARC V9 processors in 64 bit environments.
+
+@table @code
+@item -mlittle-endian
+Generate code for a processor running in little-endian mode.
+
+@item -m32
+@itemx -m64
+Generate code for a 32 bit or 64 bit environment.
+The 32 bit environment sets int, long and pointer to 32 bits.
+The 64 bit environment sets int to 32 bits and long and pointer
+to 64 bits.
+
+@item -mcmodel=medlow
+Generate code for the Medium/Low code model: the program must be linked
+in the low 32 bits of the address space. Pointers are 64 bits.
+Programs can be statically or dynamically linked.
+
+@item -mcmodel=medmid
+Generate code for the Medium/Middle code model: the program must be linked
+in the low 44 bits of the address space, the text segment must be less than
+2G bytes, and data segment must be within 2G of the text segment.
+Pointers are 64 bits.
+
+@item -mcmodel=medany
+Generate code for the Medium/Anywhere code model: the program may be linked
+anywhere in the address space, the text segment must be less than
+2G bytes, and data segment must be within 2G of the text segment.
+Pointers are 64 bits.
+
+@item -mcmodel=embmedany
+Generate code for the Medium/Anywhere code model for embedded systems:
+assume a 32 bit text and a 32 bit data segment, both starting anywhere
+(determined at link time). Register %g4 points to the base of the
+data segment. Pointers still 64 bits.
+Programs are statically linked, PIC is not supported.
@item -mstack-bias
@itemx -mno-stack-bias
@@ -2888,6 +3610,12 @@ to date, but not the 29050).
registers for copying out arguments. This helps detect calling a function
with fewer arguments than it was declared with.
+@item -mno-impure-text
+@itemx -mimpure-text
+@kindex -mimpure-text
+@samp{-mimpure-text}, used in addition to @samp{-shared}, tells the compiler to
+not pass @samp{-assert pure-text} to the linker when linking a shared object.
+
@item -msoft-float
@kindex -msoft-float
Generate output containing library calls for floating point.
@@ -2906,25 +3634,134 @@ These @samp{-m} options are defined for Advanced RISC Machines (ARM)
architectures:
@table @code
-@item -m2
-@itemx -m3
-@kindex -m2
-@kindex -m3
-These options are identical. Generate code for the ARM2 and ARM3
-processors. This option is the default. You should also use this
-option to generate code for ARM6 processors that are running with a
-26-bit program counter.
-
-@item -m6
-@kindex -m6
-Generate code for the ARM6 processor when running with a 32-bit program
-counter.
+@item -mapcs-frame
+@kindex -mapcs-frame
+Generate a stack frame that is compliant with the ARM Procedure Call
+Standard for all functions, even if this is not strictly necessary for
+correct execution of the code. Specifying @samp{-fomit-frame-pointer}
+with this option will cause the stack frames not to be generated for
+leaf functions. The default is @samp{-mno-apcs-frame}.
@item -mapcs
@kindex -mapcs
-Generate a stack frame that is compliant with the ARM Procedure Call
-Standard for all functions, even if this is not strictly necessary for
-correct execution of the code.
+This is a synonym for @samp{-mapcs-frame}.
+
+@item -mapcs-26
+@kindex -mapcs-26
+Generate code for a processor running with a 26-bit program counter,
+and conforming to the function calling standards for the APCS 26-bit
+option. This option replaces the @samp{-m2} and @samp{-m3} options
+of previous releases of the compiler.
+
+@item -mapcs-32
+@kindex -mapcs-32
+Generate code for a processor running with a 32-bit program counter,
+and conforming to the function calling standards for the APCS 32-bit
+option. This option replaces the @samp{-m6} option of previous releases
+of the compiler.
+
+@item -mapcs-stack-check
+@kindex -mapcs-stack-check
+@kindex -mno-apcs-stack-check
+Generate code to check the amount of stack space available upon entry to
+every function (that actually uses some stack space). If there is
+insufficient space available then either the function
+@samp{__rt_stkovf_split_small} or @samp{__rt_stkovf_split_big} will be
+called, depending upon the amount of stack space required. The run time
+system is required to provide these functions. The default is
+@samp{-mno-apcs-stack-check}, since this produces smaller code.
+
+@item -mapcs-float
+@kindex -mapcs-float
+@kindex -mno-apcs-float
+Pass floating point arguments using the float point registers. This is
+one of the variants of the APCS. This option is reccommended if the
+target hardware has a floating point unit or if a lot of floating point
+arithmetic is going to be performed by the code. The default is
+@samp{-mno-apcs-float}, since integer only code is slightly increased in
+size if @samp{-mapcs-float} is used.
+
+@item -mapcs-reentrant
+@kindex -mapcs-reentrant
+@kindex -mno-apcs-reentrant
+Generate reentrant, position independent code. This is the equivalent
+to specifying the @samp{-fpic} option. The default is
+@samp{-mno-apcs-reentrant}.
+
+@item -mthumb-interwork
+@kindex -mthumb-interwork
+@kindex -mno-thumb-interwork
+Generate code which supports calling between the ARM and THUMB
+instruction sets. Without this option the two instruction sets cannot
+be reliably used inside one program. The default is
+@samp{-mno-thumb-interwork}, since slightly larger code is generated
+when @samp{-mthumb-interwork} is specified.
+
+@item -mno-sched-prolog
+@kindex -mno-sched-prolog
+@kindex -msched-prolog
+Prevent the reordering of instructions in the function prolog, or the
+merging of those instruction with the instructions in the function's
+body. This means that all functions will start with a recognisable set
+of instructions (or in fact one of a chioce from a small set of
+different function prologues), and this information can be used to
+locate the start if functions inside an executable piece of code. The
+default is @samp{-msched-prolog}.
+
+@item -mhard-float
+Generate output containing floating point instructions. This is the
+default.
+
+@item -msoft-float
+Generate output containing library calls for floating point.
+@strong{Warning:} the requisite libraries are not available for all ARM
+targets. Normally the facilities of the machine's usual C compiler are
+used, but this cannot be done directly in cross-compilation. You must make
+your own arrangements to provide suitable library functions for
+cross-compilation.
+
+@samp{-msoft-float} changes the calling convention in the output file;
+therefore, it is only useful if you compile @emph{all} of a program with
+this option. In particular, you need to compile @file{libgcc.a}, the
+library that comes with GNU CC, with @samp{-msoft-float} in order for
+this to work.
+
+@item -mlittle-endian
+Generate code for a processor running in little-endian mode. This is
+the default for all standard configurations.
+
+@item -mbig-endian
+Generate code for a processor running in big-endian mode; the default is
+to compile code for a little-endian processor.
+
+@item -mwords-little-endian
+This option only applies when generating code for big-endian processors.
+Generate code for a little-endian word order but a big-endian byte
+order. That is, a byte order of the form @samp{32107654}. Note: this
+option should only be used if you require compatibility with code for
+big-endian ARM processors generated by versions of the compiler prior to
+2.8.
+
+@item -mshort-load-bytes
+@kindex -mshort-load-bytes
+Do not try to load half-words (eg @samp{short}s) by loading a word from
+an unaligned address. For some targets the MMU is configured to trap
+unaligned loads; use this option to generate code that is safe in these
+environments.
+
+@item -mno-short-load-bytes
+@kindex -mno-short-load-bytes
+Use unaligned word loads to load half-words (eg @samp{short}s). This
+option produces more efficient code, but the MMU is sometimes configured
+to trap these instructions.
+
+@item -mshort-load-words
+@kindex -mshort-load-words
+This is a synonym for the @samp{-mno-short-load-bytes}.
+
+@item -mno-short-load-words
+@kindex -mno-short-load-words
+This is a synonym for the @samp{-mshort-load-bytes}.
@item -mbsd
@kindex -mbsd
@@ -2944,6 +3781,193 @@ Normally it is necessary to modify some of the standard symbols in
preparation for linking with the RISC iX C library; this option
suppresses this pass. The post-processor is never run when the
compiler is built for cross-compilation.
+
+@item -mcpu=<name>
+@kindex -mcpu=
+This specifies the name of the target ARM processor. GCC uses this name
+to determine what kind of instructions it can use when generating
+assembly code. Permissable names are: 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
+
+@item -march=<name>
+@kindex -march=
+This specifies the name of the target ARM architecture. GCC uses this
+name to determine what kind of instructions it can use when generating
+assembly code. This option can be used in conjunction with or instead
+of the @samp{-mcpu=} option. Permissable names are: armv2, armv2a,
+armv3, armv3m, armv4, armv4t
+
+@item -mfpe=<number>
+@kindex -mfpe=
+This specifes the version of the floating point emulation available on
+the target. Permissable values are 2 and 3.
+
+@item -mstructure-size-boundary=<n>
+@kindex -mstructure-size-boundary
+The size of all structures and unions will be rounded up to a multiple
+of the number of bits set by this option. Permissable values are 8 and
+32. The default value varies for different toolchains. For the COFF
+targeted toolchain the default value is 8. Specifying the larger number
+can produced faster, more efficient code, but can also increase the size
+of the program. The two values are potentially incompatible. Code
+compiled with one value cannot necessarily expect to work with code or
+libraries compiled with the other value, if they exchange information
+using structures or unions. Programmers are encouraged to use the 32
+value as future versions of the toolchain may default to this value.
+
+@end table
+
+@node Thumb Options
+@subsection Thumb Options
+@cindex Thumb Options
+
+@table @code
+
+@item -mthumb-interwork
+@kindex -mthumb-interwork
+@kindex -mno-thumb-interwork
+Generate code which supports calling between the THUMB and ARM
+instruction sets. Without this option the two instruction sets cannot
+be reliably used inside one program. The default is
+@samp{-mno-thumb-interwork}, since slightly smaller code is generated
+with this option.
+
+@item -mtpcs-frame
+@kindex -mtpcs-frame
+@kindex -mno-tpcs-frame
+Generate a stack frame that is compliant with the Thumb Procedure Call
+Standard for all non-leaf functions. (A leaf function is one that does
+not call any other functions). The default is @samp{-mno-apcs-frame}.
+
+@item -mtpcs-leaf-frame
+@kindex -mtpcs-leaf-frame
+@kindex -mno-tpcs-leaf-frame
+Generate a stack frame that is compliant with the Thumb Procedure Call
+Standard for all leaf functions. (A leaf function is one that does
+not call any other functions). The default is @samp{-mno-apcs-leaf-frame}.
+
+@item -mlittle-endian
+@kindex -mlittle-endian
+Generate code for a processor running in little-endian mode. This is
+the default for all standard configurations.
+
+@item -mbig-endian
+@kindex -mbig-endian
+Generate code for a processor running in big-endian mode.
+
+@item -mstructure-size-boundary=<n>
+@kindex -mstructure-size-boundary
+The size of all structures and unions will be rounded up to a multiple
+of the number of bits set by this option. Permissable values are 8 and
+32. The default value varies for different toolchains. For the COFF
+targeted toolchain the default value is 8. Specifying the larger number
+can produced faster, more efficient code, but can also increase the size
+of the program. The two values are potentially incompatible. Code
+compiled with one value cannot necessarily expect to work with code or
+libraries compiled with the other value, if they exchange information
+using structures or unions. Programmers are encouraged to use the 32
+value as future versions of the toolchain may default to this value.
+
+@end table
+
+@node MN10200 Options
+@subsection MN10200 Options
+@cindex MN10200 options
+These @samp{-m} options are defined for Matsushita MN10200 architectures:
+@table @code
+
+@item -mrelax
+Indicate to the linker that it should perform a relaxation optimization pass
+to shorten branches, calls and absolute memory addresses. This option only
+has an effect when used on the command line for the final link step.
+
+This option makes symbolic debugging impossible.
+@end table
+
+@node MN10300 Options
+@subsection MN10300 Options
+@cindex MN10300 options
+These @samp{-m} options are defined for Matsushita MN10300 architectures:
+
+@table @code
+@item -mmult-bug
+Generate code to avoid bugs in the multiply instructions for the MN10300
+processors. This is the default.
+
+@item -mno-mult-bug
+Do not generate code to avoid bugs in the multiply instructions for the
+MN10300 processors.
+
+@item -mrelax
+Indicate to the linker that it should perform a relaxation optimization pass
+to shorten branches, calls and absolute memory addresses. This option only
+has an effect when used on the command line for the final link step.
+
+This option makes symbolic debugging impossible.
+@end table
+
+
+@node M32R/D Options
+@subsection M32R/D Options
+@cindex M32R/D options
+
+These @samp{-m} options are defined for Mitsubishi M32R/D architectures:
+
+@table @code
+@item -mcode-model=small
+Assume all objects live in the lower 16MB of memory (so that their addresses
+can be loaded with the @code{ld24} instruction), and assume all subroutines
+are reachable with the @code{bl} instruction.
+This is the default.
+
+The addressability of a particular object can be set with the
+@code{model} attribute.
+
+@item -mcode-model=medium
+Assume objects may be anywhere in the 32 bit address space (the compiler
+will generate @code{seth/add3} instructions to load their addresses), and
+assume all subroutines are reachable with the @code{bl} instruction.
+
+@item -mcode-model=large
+Assume objects may be anywhere in the 32 bit address space (the compiler
+will generate @code{seth/add3} instructions to load their addresses), and
+assume subroutines may not be reachable with the @code{bl} instruction
+(the compiler will generate the much slower @code{seth/add3/jl}
+instruction sequence).
+
+@item -msdata=none
+Disable use of the small data area. Variables will be put into
+one of @samp{.data}, @samp{bss}, or @samp{.rodata} (unless the
+@code{section} attribute has been specified).
+This is the default.
+
+The small data area consists of sections @samp{.sdata} and @samp{.sbss}.
+Objects may be explicitly put in the small data area with the
+@code{section} attribute using one of these sections.
+
+@item -msdata=sdata
+Put small global and static data in the small data area, but do not
+generate special code to reference them.
+
+@item -msdata=use
+Put small global and static data in the small data area, and generate
+special instructions to reference them.
+
+@item -G @var{num}
+@cindex smaller data references
+Put global and static objects less than or equal to @var{num} bytes
+into the small data or bss sections instead of the normal data or bss
+sections. The default value of @var{num} is 8.
+The @samp{-msdata} option must be set to one of @samp{sdata} or @samp{use}
+for this option to have any effect.
+
+All modules should be compiled with the same @samp{-G @var{num}} value.
+Compiling with different values of @var{num} may or may not work; if it
+doesn't the linker will give an error message - incorrect code will not be
+generated.
+
@end table
@node M88K Options
@@ -3083,14 +4107,14 @@ Turn on (@samp{-msvr4}) or off (@samp{-msvr3}) compiler extensions
related to System V release 4 (SVr4). This controls the following:
@enumerate
-@item
+@item
Which variant of the assembler syntax to emit.
@item
@samp{-msvr4} makes the C preprocessor recognize @samp{#pragma weak}
that is used on System V release 4.
@item
@samp{-msvr4} makes GNU CC issue additional declaration directives used in
-SVr4.
+SVr4.
@end enumerate
@samp{-msvr4} is the default for the m88k-motorola-sysv4 and
@@ -3122,7 +4146,7 @@ GNU C assumes that the MC88110 processor correctly detects all
instances of integer division by zero. When @samp{-m88110} is
specified, both @samp{-mcheck-zero-division} and
@samp{-mno-check-zero-division} are ignored, and no explicit checks for
-zero-valued divisors are generated.
+zero-valued divisors are generated.
@item -muse-div-instruction
@kindex -muse-div-instruction
@@ -3189,18 +4213,20 @@ These @samp{-m} options are defined for the IBM RS/6000 and PowerPC:
@itemx -mno-powerpc-gpopt
@itemx -mpowerpc-gfxopt
@itemx -mno-powerpc-gfxopt
+@itemx -mpowerpc64
+@itemx -mno-powerpc64
@kindex -mpower
@kindex -mpower2
@kindex -mpowerpc
@kindex -mpowerpc-gpopt
@kindex -mpowerpc-gfxopt
+@kindex -mpowerpc64
GNU CC supports two related instruction set architectures for the
RS/6000 and PowerPC. The @dfn{POWER} instruction set are those
instructions supported by the @samp{rios} chip set used in the original
RS/6000 systems and the @dfn{PowerPC} instruction set is the
-architecture of the Motorola MPC6xx microprocessors. The PowerPC
-architecture defines 64-bit instructions, but they are not supported by
-any current processors.
+architecture of the Motorola MPC5xx, MPC6xx, MPC8xx microprocessors, and
+the IBM 4xx microprocessors.
Neither architecture is a subset of the other. However there is a
large common subset of instructions supported by both. An MQ
@@ -3210,7 +4236,8 @@ You use these options to specify which instructions are available on the
processor you are using. The default value of these options is
determined when configuring GNU CC. Specifying the
@samp{-mcpu=@var{cpu_type}} overrides the specification of these
-options. We recommend you use that option rather than these.
+options. We recommend you use the @samp{-mcpu=@var{cpu_type}} option
+rather than the options listed above.
The @samp{-mpower} option allows GNU CC to generate instructions that
are found only in the POWER architecture and to use the MQ register.
@@ -3227,6 +4254,11 @@ General Purpose group, including floating-point square root. Specifying
use the optional PowerPC architecture instructions in the Graphics
group, including floating-point select.
+The @samp{-mpowerpc64} option allows GNU CC to generate the additional
+64-bit instructions that are found in the full PowerPC64 architecture
+and to treat GPRs as 64-bit, doubleword quantities. GNU CC defaults to
+@samp{-mno-powerpc64}.
+
If you specify both @samp{-mno-power} and @samp{-mno-powerpc}, GNU CC
will use only the instructions in the common subset of both
architectures plus some special AIX common-mode calls, and will not use
@@ -3246,52 +4278,88 @@ Instructions defined in only one architecture have only one mnemonic;
GNU CC uses that mnemonic irrespective of which of these options is
specified.
-PowerPC assemblers support both the old and new mnemonics, as will later
-POWER assemblers. Current POWER assemblers only support the old
-mnemonics. Specify @samp{-mnew-mnemonics} if you have an assembler that
-supports them, otherwise specify @samp{-mold-mnemonics}.
-
-The default value of these options depends on how GNU CC was configured.
-Specifying @samp{-mcpu=@var{cpu_type}} sometimes overrides the value of
-these option. Unless you are building a cross-compiler, you should
-normally not specify either @samp{-mnew-mnemonics} or
+GNU CC defaults to the mnemonics appropriate for the architecture in
+use. Specifying @samp{-mcpu=@var{cpu_type}} sometimes overrides the
+value of these option. Unless you are building a cross-compiler, you
+should normally not specify either @samp{-mnew-mnemonics} or
@samp{-mold-mnemonics}, but should instead accept the default.
@item -mcpu=@var{cpu_type}
-Set architecture type, register usage, choice of mnemonics, and instruction
-scheduling parameters for machine type @var{cpu_type}. By default,
-@var{cpu_type} is the target system defined when GNU CC was configured.
-Supported values for @var{cpu_type} are @samp{rios1}, @samp{rios2}, @samp{rsc},
-@samp{601}, @samp{603}, @samp{604}, @samp{power}, @samp{powerpc}, @samp{403},
-and @samp{common}. @samp{-mcpu=power} and @samp{-mcpu=powerpc} specify generic
-POWER and pure PowerPC (i.e., not MPC601) architecture machine types, with an
-appropriate, generic processor model assumed for scheduling purposes.@refill
-
-Specifying @samp{-mcpu=rios1}, @samp{-mcpu=rios2}, @samp{-mcpu=rsc}, or
-@samp{-mcpu=power} enables the @samp{-mpower} option and disables the
-@samp{-mpowerpc} option; @samp{-mcpu=601} enables both the @samp{-mpower} and
-@samp{-mpowerpc} options; @samp{-mcpu=603}, @samp{-mcpu=604}, @samp{-mcpu=403},
-and @samp{-mcpu=powerpc} enable the @samp{-mpowerpc} option and disable the
-@samp{-mpower} option; @samp{-mcpu=common} disables both the @samp{-mpower} and
-@samp{-mpowerpc} options.@refill
-
-To generate code that will operate on all members of the RS/6000 and
-PowerPC families, specify @samp{-mcpu=common}. In that case, GNU CC
-will use only the instructions in the common subset of both
-architectures plus some special AIX common-mode calls, and will not use
-the MQ register. GNU CC assumes a generic processor model for scheduling
-purposes.
-
-Specifying @samp{-mcpu=rios1}, @samp{-mcpu=rios2}, @samp{-mcpu=rsc}, or
-@samp{-mcpu=power} also disables the @samp{new-mnemonics} option.
-Specifying @samp{-mcpu=601}, @samp{-mcpu=603}, @samp{-mcpu=604},
-@samp{403}, or @samp{-mcpu=powerpc} also enables the @samp{new-mnemonics}
-option.@refill
+@kindex -mcpu
+Set architecture type, register usage, choice of mnemonics, and
+instruction scheduling parameters for machine type @var{cpu_type}.
+Supported values for @var{cpu_type} are @samp{rs6000}, @samp{rios1},
+@samp{rios2}, @samp{rsc}, @samp{601}, @samp{602}, @samp{603},
+@samp{603e}, @samp{604}, @samp{604e}, @samp{620}, @samp{power},
+@samp{power2}, @samp{powerpc}, @samp{403}, @samp{505}, @samp{801},
+@samp{821}, @samp{823}, and @samp{860} and @samp{common}.
+@samp{-mcpu=power}, @samp{-mcpu=power2}, and @samp{-mcpu=powerpc}
+specify generic POWER, POWER2 and pure PowerPC (i.e., not MPC601)
+architecture machine types, with an appropriate, generic processor model
+assumed for scheduling purposes.@refill
+
+@c overfull hbox here --bob 22 jul96
+@c original text between ignore ... end ignore
+@ignore
+Specifying any of the @samp{-mcpu=rios1}, @samp{-mcpu=rios2},
+@samp{-mcpu=rsc}, @samp{-mcpu=power}, or @samp{-mcpu=power2} options
+enables the @samp{-mpower} option and disables the @samp{-mpowerpc}
+option; @samp{-mcpu=601} enables both the @samp{-mpower} and
+@samp{-mpowerpc} options; all of @samp{-mcpu=602}, @samp{-mcpu=603},
+@samp{-mcpu=603e}, @samp{-mcpu=604}, @samp{-mcpu=604e},
+@samp{-mcpu=620}, @samp{-mcpu=403}, @samp{-mcpu=505}, @samp{-mcpu=801},
+@samp{-mcpu=821}, @samp{-mcpu=823}, @samp{-mcpu=860} and
+@samp{-mcpu=powerpc} enable the @samp{-mpowerpc} option and disable the
+@samp{-mpower} option; @samp{-mcpu=common} disables both the
+@samp{-mpower} and @samp{-mpowerpc} options.@refill
+@end ignore
+@c changed paragraph
+Specifying any of the following options:
+@samp{-mcpu=rios1}, @samp{-mcpu=rios2}, @samp{-mcpu=rsc},
+@samp{-mcpu=power}, or @samp{-mcpu=power2}
+enables the @samp{-mpower} option and disables the @samp{-mpowerpc} option;
+@samp{-mcpu=601} enables both the @samp{-mpower} and @samp{-mpowerpc} options.
+All of @samp{-mcpu=602}, @samp{-mcpu=603}, @samp{-mcpu=603e},
+@samp{-mcpu=604}, @samp{-mcpu=620},
+enable the @samp{-mpowerpc} option and disable the @samp{-mpower} option.
+Exactly similarly, all of @samp{-mcpu=403},
+@samp{-mcpu=505}, @samp{-mcpu=821}, @samp{-mcpu=860} and @samp{-mcpu=powerpc}
+enable the @samp{-mpowerpc} option and disable the @samp{-mpower} option.
+@samp{-mcpu=common} disables both the
+@samp{-mpower} and @samp{-mpowerpc} options.@refill
+@c end changes to prevent overfull hboxes
+
+AIX versions 4 or greater selects @samp{-mcpu=common} by default, so
+that code will operate on all members of the RS/6000 and PowerPC
+families. In that case, GNU CC will use only the instructions in the
+common subset of both architectures plus some special AIX common-mode
+calls, and will not use the MQ register. GNU CC assumes a generic
+processor model for scheduling purposes.
+
+Specifying any of the options @samp{-mcpu=rios1}, @samp{-mcpu=rios2},
+@samp{-mcpu=rsc}, @samp{-mcpu=power}, or @samp{-mcpu=power2} also
+disables the @samp{new-mnemonics} option. Specifying @samp{-mcpu=601},
+@samp{-mcpu=602}, @samp{-mcpu=603}, @samp{-mcpu=603e}, @samp{-mcpu=604},
+@samp{620}, @samp{403}, or @samp{-mcpu=powerpc} also enables the
+@samp{new-mnemonics} option.@refill
+
+Specifying @samp{-mcpu=403}, @samp{-mcpu=821}, or @samp{-mcpu=860} also
+enables the @samp{-msoft-float} option.
+
+@item -mtune=@var{cpu_type}
+Set the instruction scheduling parameters for machine type
+@var{cpu_type}, but do not set the architecture type, register usage,
+choice of mnemonics like @samp{-mcpu=}@var{cpu_type} would. The same
+values for @var{cpu_type} are used for @samp{-mtune=}@var{cpu_type} as
+for @samp{-mcpu=}@var{cpu_type}. The @samp{-mtune=}@var{cpu_type}
+option overrides the @samp{-mcpu=}@var{cpu_type} option in terms of
+instruction scheduling parameters.
@item -mfull-toc
@itemx -mno-fp-in-toc
@itemx -mno-sum-in-toc
@itemx -mminimal-toc
+@kindex -mminimal-toc
Modify generation of the TOC (Table Of Contents), which is created for
every executable file. The @samp{-mfull-toc} option is selected by
default. In that case, GNU CC will allocate at least one TOC entry for
@@ -3316,8 +4384,51 @@ option, GNU CC will produce code that is slower and larger but which
uses extremely little TOC space. You may wish to use this option
only on files that contain less frequently executed code. @refill
+@item -maix64
+@itemx -maix32
+@kindex -maix64
+@kindex -maix32
+Enable AIX 64-bit ABI and calling convention: 64-bit pointers, 64-bit
+@code{long} type, and the infrastructure needed to support them.
+Specifying @samp{-maix64} implies @samp{-mpowerpc64} and
+@samp{-mpowerpc}, while @samp{-maix32} disables the 64-bit ABI and
+implies @samp{-mno-powerpc64}. GNU CC defaults to @samp{-maix32}.
+
+@item -mxl-call
+@itemx -mno-xl-call
+@kindex -mxl-call
+On AIX, pass floating-point arguments to prototyped functions beyond the
+register save area (RSA) on the stack in addition to argument FPRs. The
+AIX calling convention was extended but not initially documented to
+handle an obscure K&R C case of calling a function that takes the
+address of its arguments with fewer arguments than declared. AIX XL
+compilers access floating point arguments which do not fit in the
+RSA from the stack when a subroutine is compiled without
+optimization. Because always storing floating-point arguments on the
+stack is inefficient and rarely needed, this option is not enabled by
+default and only is necessary when calling subroutines compiled by AIX
+XL compilers without optimization.
+
+@item -mthreads
+@kindex -mthreads
+Support @dfn{AIX Threads}. Link an application written to use
+@dfn{pthreads} with special libraries and startup code to enable the
+application to run.
+
+@item -mpe
+@kindex -mpe
+Support @dfn{IBM RS/6000 SP} @dfn{Parallel Environment} (PE). Link an
+application written to use message passing with special startup code to
+enable the application to run. The system must have PE installed in the
+standard location (@file{/usr/lpp/ppe.poe/}), or the @file{specs} file
+must be overridden with the @samp{-specs=} option to specify the
+appropriate directory location. The Parallel Environment does not
+support threads, so the @samp{-mpe} option and the @samp{-mthreads}
+option are incompatible.
+
@item -msoft-float
@itemx -mhard-float
+@kindex -msoft-float
Generate code that does not use (uses) the floating-point register set.
Software floating point emulation is provided if you use the
@samp{-msoft-float} option, and pass the option to GNU CC when linking.
@@ -3333,15 +4444,35 @@ processor is in little endian mode.
@item -mstring
@itemx -mno-string
+@kindex -mstring
Generate code that uses (does not use) the load string instructions and the
store string word instructions to save multiple registers and do small block
-moves. These instructions are generated by default on POWER systems, anod not
+moves. These instructions are generated by default on POWER systems, and not
generated on PowerPC systems. Do not use @samp{-mstring} on little endian
PowerPC systems, since those instructions do not work when the processor is in
little endian mode.
+@item -mupdate
+@itemx -mno-update
+@kindex -mupdate
+Generate code that uses (does not use) the load or store instructions
+that update the base register to the address of the calculated memory
+location. These instructions are generated by default. If you use
+@samp{-mno-update}, there is a small window between the time that the
+stack pointer is updated and the address of the previous frame is
+stored, which means code that walks the stack frame across interrupts or
+signals may get corrupted data.
+
+@item -mfused-madd
+@itemx -mno-fused-madd
+@kindex -mfused-madd
+Generate code that uses (does not use) the floating point multiply and
+accumulate instructions. These instructions are generated by default if
+hardware floating is used.
+
@item -mno-bit-align
@itemx -mbit-align
+@kindex -mbit-align
On System V.4 and embedded PowerPC systems do not (do) force structures
and unions that contain bit fields to be aligned to the base type of the
bit field.
@@ -3354,13 +4485,25 @@ size.
@item -mno-strict-align
@itemx -mstrict-align
+@kindex -mstrict-align
On System V.4 and embedded PowerPC systems do not (do) assume that
unaligned memory references will be handled by the system.
@item -mrelocatable
@itemx -mno-relocatable
+@kindex -mrelocatable
+On embedded PowerPC systems generate code that allows (does not allow)
+the program to be relocated to a different address at runtime. If you
+use @samp{-mrelocatable} on any module, all objects linked together must
+be compiled with @samp{-mrelocatable} or @samp{-mrelocatable-lib}.
+
+@item -mrelocatable-lib
+@itemx -mno-relocatable-lib
On embedded PowerPC systems generate code that allows (does not allow)
-the program to be relocated to a different address at runtime.
+the program to be relocated to a different address at runtime. Modules
+compiled with @samp{-mrelocatable-lib} can be linked with either modules
+compiled without @samp{-mrelocatable} and @samp{-mrelocatable-lib} or
+with modules compiled with the @samp{-mrelocatable} options.
@item -mno-toc
@itemx -mtoc
@@ -3368,12 +4511,6 @@ On System V.4 and embedded PowerPC systems do not (do) assume that
register 2 contains a pointer to a global area pointing to the addresses
used in the program.
-@item -mno-traceback
-@itemx -mtraceback
-On embedded PowerPC systems do not (do) generate a traceback tag before
-the start of the function. This tag can be used by the debugger to
-identify where the start of a function is.
-
@item -mlittle
@itemx -mlittle-endian
On System V.4 and embedded PowerPC systems compile code for the
@@ -3392,13 +4529,27 @@ conventions that adheres to the March 1995 draft of the System V
Application Binary Interface, PowerPC processor supplement. This is the
default unless you configured GCC using @samp{powerpc-*-eabiaix}.
+@item -mcall-sysv-eabi
+Specify both @samp{-mcall-sysv} and @samp{-meabi} options.
+
+@item -mcall-sysv-noeabi
+Specify both @samp{-mcall-sysv} and @samp{-mno-eabi} options.
+
@item -mcall-aix
On System V.4 and embedded PowerPC systems compile code using calling
conventions that are similar to those used on AIX. This is the
default if you configured GCC using @samp{powerpc-*-eabiaix}.
+@item -mcall-solaris
+On System V.4 and embedded PowerPC systems compile code for the Solaris
+operating system.
+
+@item -mcall-linux
+On System V.4 and embedded PowerPC systems compile code for the
+Linux-based GNU system.
+
@item -mprototype
-@item -mno-prototype
+@itemx -mno-prototype
On System V.4 and embedded PowerPC systems assume that all calls to
variable argument functions are properly prototyped. Otherwise, the
compiler must insert an instruction before every non prototyped call to
@@ -3407,6 +4558,98 @@ indicate whether floating point values were passed in the floating point
registers in case the function takes a variable arguments. With
@samp{-mprototype}, only calls to prototyped variable argument functions
will set or clear the bit.
+
+@item -msim
+On embedded PowerPC systems, assume that the startup module is called
+@file{sim-crt0.o} and that the standard C libraries are @file{libsim.a} and
+@file{libc.a}. This is the default for @samp{powerpc-*-eabisim}.
+configurations.
+
+@item -mmvme
+On embedded PowerPC systems, assume that the startup module is called
+@file{crt0.o} and the standard C libraries are @file{libmvme.a} and
+@file{libc.a}.
+
+@item -mads
+On embedded PowerPC systems, assume that the startup module is called
+@file{crt0.o} and the standard C libraries are @file{libads.a} and
+@file{libc.a}.
+
+@item -myellowknife
+On embedded PowerPC systems, assume that the startup module is called
+@file{crt0.o} and the standard C libraries are @file{libyk.a} and
+@file{libc.a}.
+
+@item -memb
+On embedded PowerPC systems, set the @var{PPC_EMB} bit in the ELF flags
+header to indicate that @samp{eabi} extended relocations are used.
+
+@item -meabi
+@itemx -mno-eabi
+On System V.4 and embedded PowerPC systems do (do not) adhere to the
+Embedded Applications Binary Interface (eabi) which is a set of
+modifications to the System V.4 specifications. Selecting @code{-meabi}
+means that the stack is aligned to an 8 byte boundary, a function
+@code{__eabi} is called to from @code{main} to set up the eabi
+environment, and the @samp{-msdata} option can use both @code{r2} and
+@code{r13} to point to two separate small data areas. Selecting
+@code{-mno-eabi} means that the stack is aligned to a 16 byte boundary,
+do not call an initialization function from @code{main}, and the
+@samp{-msdata} option will only use @code{r13} to point to a single
+small data area. The @samp{-meabi} option is on by default if you
+configured GCC using one of the @samp{powerpc*-*-eabi*} options.
+
+@item -msdata=eabi
+On System V.4 and embedded PowerPC systems, put small initialized
+@code{const} global and static data in the @samp{.sdata2} section, which
+is pointed to by register @code{r2}. Put small initialized
+non-@code{const} global and static data in the @samp{.sdata} section,
+which is pointed to by register @code{r13}. Put small uninitialized
+global and static data in the @samp{.sbss} section, which is adjacent to
+the @samp{.sdata} section. The @samp{-msdata=eabi} option is
+incompatible with the @samp{-mrelocatable} option. The
+@samp{-msdata=eabi} option also sets the @samp{-memb} option.
+
+@item -msdata=sysv
+On System V.4 and embedded PowerPC systems, put small global and static
+data in the @samp{.sdata} section, which is pointed to by register
+@code{r13}. Put small uninitialized global and static data in the
+@samp{.sbss} section, which is adjacent to the @samp{.sdata} section.
+The @samp{-msdata=sysv} option is incompatible with the
+@samp{-mrelocatable} option.
+
+@item -msdata=default
+@itemx -msdata
+On System V.4 and embedded PowerPC systems, if @samp{-meabi} is used,
+compile code the same as @samp{-msdata=eabi}, otherwise compile code the
+same as @samp{-msdata=sysv}.
+
+@item -msdata-data
+On System V.4 and embedded PowerPC systems, put small global and static
+data in the @samp{.sdata} section. Put small uninitialized global and
+static data in the @samp{.sbss} section. Do not use register @code{r13}
+to address small data however. This is the default behavior unless
+other @samp{-msdata} options are used.
+
+@item -msdata=none
+@itemx -mno-sdata
+On embedded PowerPC systems, put all initialized global and static data
+in the @samp{.data} section, and all uninitialized data in the
+@samp{.bss} section.
+
+@item -G @var{num}
+@cindex smaller data references (PowerPC)
+@cindex .sdata/.sdata2 references (PowerPC)
+On embedded PowerPC systems, put global and static items less than or
+equal to @var{num} bytes into the small data or bss sections instead of
+the normal data or bss section. By default, @var{num} is 8. The
+@samp{-G @var{num}} switch is also passed to the linker.
+All modules should be compiled with the same @samp{-G @var{num}} value.
+
+@item -mregnames
+@itemx -mno-regnames
+On System V.4 and embedded PowerPC systems do (do not) emit register
+names in the assembly language output using symbolic forms.
@end table
@node RT Options
@subsection IBM RT Options
@@ -3487,6 +4730,10 @@ Issue instructions from level 3 of the MIPS ISA (64 bit instructions).
@samp{r4000} is the default @var{cpu type} at this ISA level.
This option does not change the sizes of any of the C data types.
+@item -mips4
+Issue instructions from level 4 of the MIPS ISA. @samp{r8000} is the
+default @var{cpu type} at this ISA level.
+
@item -mfp32
Assume that 32 32-bit floating point registers are available. This is
the default.
@@ -3511,6 +4758,12 @@ is also specified.
Types long and pointer are 64 bits, and type int is 32 bits.
This works only if @samp{-mips3} is also specified.
+@itemx -mabi=32
+@itemx -mabi=n32
+@itemx -mabi=64
+@itemx -mabi=eabi
+Generate code for the indicated ABI.
+
@item -mmips-as
Generate code for the MIPS assembler, and invoke @file{mips-tfile} to
add normal debug information. This is the default for all
@@ -3521,7 +4774,16 @@ stabs within MIPS ECOFF.
@item -mgas
Generate code for the GNU assembler. This is the default on the OSF/1
-reference platform, using the OSF/rose object format.
+reference platform, using the OSF/rose object format. Also, this is
+the default if the configure option @samp{--with-gnu-as} is used.
+
+@item -msplit-addresses
+@itemx -mno-split-addresses
+Generate code to load the high and low parts of address constants separately.
+This allows @code{gcc} to optimize away redundant loads of the high order
+bits of addresses. This optimization requires GNU as and GNU ld.
+This optimization is enabled by default for some embedded targets where
+GNU as and GNU ld are standard.
@item -mrnames
@itemx -mno-rnames
@@ -3596,9 +4858,11 @@ up, rather than put the references in the text section.
@item -membedded-pic
@itemx -mno-embedded-pic
-Generate PIC code suitable for some embedded systems. All calls are made
-using PC relative address, and all data is addressed using the $gp register.
-This requires GNU as and GNU ld which do most of the work.
+Generate PIC code suitable for some embedded systems. All calls are
+made using PC relative address, and all data is addressed using the $gp
+register. No more than 65536 bytes of global data may be used. This
+requires GNU as and GNU ld which do most of the work. This currently
+only works on targets which use ECOFF; it does not work with ELF.
@item -membedded-data
@itemx -mno-embedded-data
@@ -3645,7 +4909,7 @@ All modules should be compiled with the same @samp{-G @var{num}}
value.
@item -nocpp
-Tell the MIPS assembler to not run it's preprocessor over user
+Tell the MIPS assembler to not run its preprocessor over user
assembler files (with a @samp{.s} suffix) when assembling them.
@end table
@@ -3664,10 +4928,27 @@ defaults.
These @samp{-m} options are defined for the i386 family of computers:
@table @code
-@item -m486
-@itemx -m386
-Control whether or not code is optimized for a 486 instead of an
-386. Code generated for an 486 will run on a 386 and vice versa.
+@item -mcpu=@var{cpu type}
+Assume the defaults for the machine type @var{cpu type} when scheduling
+instructions. The choices for @var{cpu type} are: @samp{i386},
+@samp{i486}, @samp{i586} (@samp{pentium}), @samp{pentium}, @samp{i686}
+(@samp{pentiumpro}) and @samp{pentiumpro}. While picking a specific
+@var{cpu type} will schedule things appropriately for that particular
+chip, the compiler will not generate any code that does not run on the
+i386 without the @samp{-march=@var{cpu type}} option being used.
+
+@item -march=@var{cpu type}
+Generate instructions for the machine type @var{cpu type}. The choices
+for @var{cpu type} are: @samp{i386}, @samp{i486}, @samp{pentium}, and
+@samp{pentiumpro}. Specifying @samp{-march=@var{cpu type}} implies
+@samp{-mcpu=@var{cpu type}}.
+
+@item -m386
+@itemx -m486
+@itemx -mpentium
+@itemx -mpentiumpro
+Synonyms for -mcpu=i386, -mcpu=i486, -mcpu=pentium, and -mcpu=pentiumpro
+respectively.
@item -mieee-fp
@itemx -mno-ieee-fp
@@ -3739,7 +5020,7 @@ there.
You can specify that an individual function is called with this calling
sequence with the function attribute @samp{stdcall}. You can also
override the @samp{-mrtd} option by using the function attribute
-@samp{cdecl}. @xref{Function Attributes}
+@samp{cdecl}. @xref{Function Attributes}.
@strong{Warning:} this calling convention is incompatible with the one
normally used on Unix, so you cannot use it if you need to call
@@ -3765,7 +5046,8 @@ supported letters are: @code{a} allocate EAX; @code{b} allocate EBX;
Control how many registers are used to pass integer arguments. By
default, no registers are used to pass arguments, and at most 3
registers can be used. You can control this behavior for a specific
-function by using the function attribute @samp{regparm}. @xref{Function Attributes}
+function by using the function attribute @samp{regparm}.
+@xref{Function Attributes}.
@strong{Warning:} if you use this switch, and
@var{num} is nonzero, then you must build all modules with the same
@@ -3774,16 +5056,22 @@ startup modules.
@item -malign-loops=@var{num}
Align loops to a 2 raised to a @var{num} byte boundary. If
-@samp{-malign-loops} is not specified, the default is 2.
+@samp{-malign-loops} is not specified, the default is 2 unless
+gas 2.8 (or later) is being used in which case the default is
+to align the loop on a 16 byte boundary if it is less than 8
+bytes away.
@item -malign-jumps=@var{num}
Align instructions that are only jumped to to a 2 raised to a @var{num}
byte boundary. If @samp{-malign-jumps} is not specified, the default is
-2 if optimizing for a 386, and 4 if optimizing for a 486.
+2 if optimizing for a 386, and 4 if optimizing for a 486 unless
+gas 2.8 (or later) is being used in which case the default is
+to align the instruction on a 16 byte boundary if it is less
+than 8 bytes away.
@item -malign-functions=@var{num}
Align the start of functions to a 2 raised to @var{num} byte boundary.
-If @samp{-malign-jumps} is not specified, the default is 2 if optimizing
+If @samp{-malign-functions} is not specified, the default is 2 if optimizing
for a 386, and 4 if optimizing for a 486.
@end table
@@ -3800,18 +5088,16 @@ Generate code for a PA 1.0 processor.
@item -mpa-risc-1-1
Generate code for a PA 1.1 processor.
+@item -mbig-switch
+Generate code suitable for big switch tables. Use this option only if
+the assembler/linker complain about out of range branches within a switch
+table.
+
@item -mjump-in-delay
Fill delay slots of function calls with unconditional jump instructions
by modifying the return pointer for the function call to be the target
of the conditional jump.
-@item -mmillicode-long-calls
-Generate code which assumes millicode routines can not be reached
-by the standard millicode call sequence, linker-generated long-calls,
-or linker-modified millicode calls. In practice this should only be
-needed for dynamicly linked executables with extremely large SHLIB_INFO
-sections.
-
@item -mdisable-fpregs
Prevent floating point registers from being used in any manner. This is
necessary for compiling kernels which perform lazy context switching of
@@ -3822,11 +5108,28 @@ floating point operations, the compiler will abort.
Prevent the compiler from using indexing address modes. This avoids some
rather obscure problems when compiling MIG generated code under MACH.
+@item -mno-space-regs
+Generate code that assumes the target has no space registers. This allows
+GCC to generate faster indirect calls and use unscaled index address modes.
+
+Such code is suitable for level 0 PA systems and kernels.
+
@item -mfast-indirect-calls
-Generate code which performs faster indirect calls. Such code is suitable
-for kernels and for static linking. The fast indirect call code will fail
-miserably if it's part of a dynamically linked executable and in the presense
-of nested functions.
+Generate code that assumes calls never cross space boundaries. This
+allows GCC to emit code which performs faster indirect calls.
+
+This option will not work in the presense of shared libraries or nested
+functions.
+
+@item -mspace
+Optimize for space rather than execution time. Currently this only
+enables out of line function prologues and epilogues. This option is
+incompatible with PIC code generation and profiling.
+
+@item -mlong-load-store
+Generate 3-instruction load and store sequences as sometimes required by
+the HP-UX 10 linker. This is equivalent to the @samp{+k} option to
+the HP compilers.
@item -mportable-runtime
Use the portable calling conventions proposed by HP for ELF systems.
@@ -3837,20 +5140,25 @@ Enable the use of assembler directives only GAS understands.
@item -mschedule=@var{cpu type}
Schedule code according to the constraints for the machine type
@var{cpu type}. The choices for @var{cpu type} are @samp{700} for
-7@var{n}0 machines, @samp{7100} for 7@var{n}5 machines, and @samp{7100}
-for 7@var{n}2 machines. @samp{700} is the default for @var{cpu type}.
+7@var{n}0 machines, @samp{7100} for 7@var{n}5 machines, and @samp{7100LC}
+for 7@var{n}2 machines. @samp{7100} is the default for @var{cpu type}.
Note the @samp{7100LC} scheduling information is incomplete and using
@samp{7100LC} often leads to bad schedules. For now it's probably best
to use @samp{7100} instead of @samp{7100LC} for the 7@var{n}2 machines.
+@item -mlinker-opt
+Enable the optimization pass in the HPUX linker. Note this makes symbolic
+debugging impossible. It also triggers a bug in the HPUX 8 and HPUX 9 linkers
+in which they give bogus error messages when linking some programs.
+
@item -msoft-float
Generate output containing library calls for floating point.
@strong{Warning:} the requisite libraries are not available for all HPPA
targets. Normally the facilities of the machine's usual C compiler are
used, but this cannot be done directly in cross-compilation. You must make
your own arrangements to provide suitable library functions for
-cross-compilation. The embedded target @samp{hppa1.1-*-pro}
+cross-compilation. The embedded target @samp{hppa1.1-*-pro}
does provide software floating point support.
@samp{-msoft-float} changes the calling convention in the output file;
@@ -3932,8 +5240,7 @@ Do not permit (do permit) unaligned accesses.
@item -mold-align
Enable structure-alignment compatibility with Intel's gcc release version
-1.3 (based on gcc 1.37). Currently this is buggy in that @samp{#pragma
-align 1} is always assumed as well, and cannot be turned off.
+1.3 (based on gcc 1.37). This option implies @samp{-mstrict-align}.
@end table
@node DEC Alpha Options
@@ -3970,6 +5277,218 @@ option.
A typical use of this option is building a kernel that does not use,
and hence need not save and restore, any floating-point registers.
+
+@item -mieee
+The Alpha architecture implements floating-point hardware optimized for
+maximum performance. It is mostly compliant with the IEEE floating
+point standard. However, for full compliance, software assistance is
+required. This option generates code fully IEEE compliant code
+@emph{except} that the @var{inexact flag} is not maintained (see below).
+If this option is turned on, the CPP macro @code{_IEEE_FP} is defined
+during compilation. The option is a shorthand for: @samp{-D_IEEE_FP
+-mfp-trap-mode=su -mtrap-precision=i -mieee-conformant}. The resulting
+code is less efficient but is able to correctly support denormalized
+numbers and exceptional IEEE values such as not-a-number and plus/minus
+infinity. Other Alpha compilers call this option
+@code{-ieee_with_no_inexact}.
+
+@item -mieee-with-inexact
+@c overfull hbox here --bob 22 jul96
+@c original text between ignore ... end ignore
+@ignore
+This is like @samp{-mieee} except the generated code also maintains the
+IEEE @var{inexact flag}. Turning on this option causes the generated
+code to implement fully-compliant IEEE math. The option is a shorthand
+for @samp{-D_IEEE_FP -D_IEEE_FP_INEXACT} plus @samp{-mieee-conformant},
+@samp{-mfp-trap-mode=sui}, and @samp{-mtrap-precision=i}. On some Alpha
+implementations the resulting code may execute significantly slower than
+the code generated by default. Since there is very little code that
+depends on the @var{inexact flag}, you should normally not specify this
+option. Other Alpha compilers call this option
+@samp{-ieee_with_inexact}.
+@end ignore
+@c changed paragraph
+This is like @samp{-mieee} except the generated code also maintains the
+IEEE @var{inexact flag}. Turning on this option causes the generated
+code to implement fully-compliant IEEE math. The option is a shorthand
+for @samp{-D_IEEE_FP -D_IEEE_FP_INEXACT} plus the three following:
+@samp{-mieee-conformant},
+@samp{-mfp-trap-mode=sui},
+and @samp{-mtrap-precision=i}.
+On some Alpha implementations the resulting code may execute
+significantly slower than the code generated by default. Since there
+is very little code that depends on the @var{inexact flag}, you should
+normally not specify this option. Other Alpha compilers call this
+option @samp{-ieee_with_inexact}.
+@c end changes to prevent overfull hboxes
+
+@item -mfp-trap-mode=@var{trap mode}
+This option controls what floating-point related traps are enabled.
+Other Alpha compilers call this option @samp{-fptm }@var{trap mode}.
+The trap mode can be set to one of four values:
+
+@table @samp
+@item n
+This is the default (normal) setting. The only traps that are enabled
+are the ones that cannot be disabled in software (e.g., division by zero
+trap).
+
+@item u
+In addition to the traps enabled by @samp{n}, underflow traps are enabled
+as well.
+
+@item su
+Like @samp{su}, but the instructions are marked to be safe for software
+completion (see Alpha architecture manual for details).
+
+@item sui
+Like @samp{su}, but inexact traps are enabled as well.
+@end table
+
+@item -mfp-rounding-mode=@var{rounding mode}
+Selects the IEEE rounding mode. Other Alpha compilers call this option
+@samp{-fprm }@var{rounding mode}. The @var{rounding mode} can be one
+of:
+
+@table @samp
+@item n
+Normal IEEE rounding mode. Floating point numbers are rounded towards
+the nearest machine number or towards the even machine number in case
+of a tie.
+
+@item m
+Round towards minus infinity.
+
+@item c
+Chopped rounding mode. Floating point numbers are rounded towards zero.
+
+@item d
+Dynamic rounding mode. A field in the floating point control register
+(@var{fpcr}, see Alpha architecture reference manual) controls the
+rounding mode in effect. The C library initializes this register for
+rounding towards plus infinity. Thus, unless your program modifies the
+@var{fpcr}, @samp{d} corresponds to round towards plus infinity.@end table
+
+@item -mtrap-precision=@var{trap precision}
+In the Alpha architecture, floating point traps are imprecise. This
+means without software assistance it is impossible to recover from a
+floating trap and program execution normally needs to be terminated.
+GNU CC can generate code that can assist operating system trap handlers
+in determining the exact location that caused a floating point trap.
+Depending on the requirements of an application, different levels of
+precisions can be selected:
+
+@table @samp
+@item p
+Program precision. This option is the default and means a trap handler
+can only identify which program caused a floating point exception.
+
+@item f
+Function precision. The trap handler can determine the function that
+caused a floating point exception.
+
+@item i
+Instruction precision. The trap handler can determine the exact
+instruction that caused a floating point exception.
+@end table
+
+Other Alpha compilers provide the equivalent options called
+@samp{-scope_safe} and @samp{-resumption_safe}.
+
+@item -mieee-conformant
+This option marks the generated code as IEEE conformant. You must not
+use this option unless you also specify @samp{-mtrap-precision=i} and either
+@samp{-mfp-trap-mode=su} or @samp{-mfp-trap-mode=sui}. Its only effect
+is to emit the line @samp{.eflag 48} in the function prologue of the
+generated assembly file. Under DEC Unix, this has the effect that
+IEEE-conformant math library routines will be linked in.
+
+@item -mbuild-constants
+Normally GNU CC examines a 32- or 64-bit integer constant to
+see if it can construct it from smaller constants in two or three
+instructions. If it cannot, it will output the constant as a literal and
+generate code to load it from the data segment at runtime.
+
+Use this option to require GNU CC to construct @emph{all} integer constants
+using code, even if it takes more instructions (the maximum is six).
+
+You would typically use this option to build a shared library dynamic
+loader. Itself a shared library, it must relocate itself in memory
+before it can find the variables and constants in its own data segment.
+
+@item -malpha-as
+@itemx -mgas
+Select whether to generate code to be assembled by the vendor-supplied
+assembler (@samp{-malpha-as}) or by the GNU assembler @samp{-mgas}.
+
+@item -mbwx
+@itemx -mno-bwx
+@itemx -mcix
+@itemx -mno-cix
+@itemx -mmax
+@itemx -mno-max
+Indicate whether GNU CC should generate code to use the optional BWX,
+CIX, and MAX instruction sets. The default is to use the instruction sets
+supported by the CPU type specified via @samp{-mcpu=} option or that
+of the CPU on which GNU CC was built if none was specified.
+
+@item -mcpu=@var{cpu_type}
+Set the instruction set, register set, and instruction scheduling
+parameters for machine type @var{cpu_type}. You can specify either the
+@samp{EV} style name or the corresponding chip number. GNU CC
+supports scheduling parameters for the EV4 and EV5 family of processors
+and will choose the default values for the instruction set from
+the processor you specify. If you do not specify a processor type,
+GNU CC will default to the processor on which the compiler was built.
+
+Supported values for @var{cpu_type} are
+
+@table @samp
+@item ev4
+@itemx 21064
+Schedules as an EV4 and has no instruction set extensions.
+
+@item ev5
+@itemx 21164
+Schedules as an EV5 and has no instruction set extensions.
+
+@item ev56
+@itemx 21164a
+Schedules as an EV5 and supports the BWX extension.
+
+@item pca56
+@itemx 21164pc
+@itemx 21164PC
+Schedules as an EV5 and supports the BWX and MAX extensions.
+
+@item ev6
+@itemx 21264
+Schedules as an EV5 (until Digital releases the scheduling parameters
+for the EV6) and supports the BWX, CIX, and MAX extensions.
+@end table
+
+@item -mmemory-latency=@var{time}
+Sets the latency the scheduler should assume for typical memory
+references as seen by the application. This number is highly
+dependant on the memory access patterns used by the application
+and the size of the external cache on the machine.
+
+Valid options for @var{time} are
+
+@table @samp
+@item @var{number}
+A decimal number representing clock cycles.
+
+@item L1
+@itemx L2
+@itemx L3
+@itemx main
+The compiler contains estimates of the number of clock cycles for
+``typical'' EV4 & EV5 hardware for the Level 1, 2 & 3 caches
+(also called Dcache, Scache, and Bcache), as well as to main memory.
+Note that L3 is only valid for EV5.
+
+@end table
@end table
@node Clipper Options
@@ -3999,6 +5518,52 @@ ld.info, Using ld}, for a fuller description.
@item -mh
Generate code for the H8/300H.
+
+@item -ms
+Generate code for the H8/S.
+
+@item -mint32
+Make @code{int} data 32 bits by default.
+
+@item -malign-300
+On the h8/300h, use the same alignment rules as for the h8/300.
+The default for the h8/300h is to align longs and floats on 4 byte boundaries.
+@samp{-malign-300} causes them to be aligned on 2 byte boundaries.
+This option has no effect on the h8/300.
+@end table
+
+@node SH Options
+@subsection SH Options
+
+These @samp{-m} options are defined for the SH implementations:
+
+@table @code
+@item -m1
+Generate code for the SH1.
+
+@item -m2
+Generate code for the SH2.
+
+@item -m3
+Generate code for the SH3.
+
+@item -m3e
+Generate code for the SH3e.
+
+@item -mb
+Compile code for the processor in big endian mode.
+
+@item -ml
+Compile code for the processor in little endian mode.
+
+@item -mdalign
+Align doubles at 64 bit boundaries. Note that this changes the calling
+conventions, and thus some functions from the standard C library will
+not work unless you recompile it first with -mdalign.
+
+@item -mrelax
+Shorten some address references at link time, when possible; uses the
+linker option @samp{-relax}.
@end table
@node System V Options
@@ -4008,16 +5573,9 @@ These additional options are available on System V Release 4 for
compatibility with other compilers on those systems:
@table @code
-@ignore
-This should say *what the option does* and only then say
-"For compatibility only..."
@item -G
-On SVr4 systems, @code{gcc} accepts the option @samp{-G} (and passes
-it to the system linker), for compatibility with other compilers.
-However, we suggest you use @samp{-symbolic} or @samp{-shared} as
-appropriate, instead of supplying linker options on the @code{gcc}
-command line.
-@end ignore
+Create a shared object.
+It is recommended that @samp{-symbolic} or @samp{-shared} be used instead.
@item -Qy
Identify the versions of each tool used by the compiler, in a
@@ -4034,14 +5592,106 @@ specified with @samp{-l}.
@item -Ym,@var{dir}
Look in the directory @var{dir} to find the M4 preprocessor.
The assembler uses this option.
-@c This is supposed to go with a -Yd for predefined M4 macro files, but
+@c This is supposed to go with a -Yd for predefined M4 macro files, but
@c the generic assembler that comes with Solaris takes just -Ym.
@end table
+@node V850 Options
+@subsection V850 Options
+@cindex V850 Options
+
+These @samp{-m} options are defined for V850 implementations:
+
+@table @code
+@item -mlong-calls
+@itemx -mno-long-calls
+Treat all calls as being far away (near). If calls are assumed to be
+far away, the compiler will always load the functions address up into a
+register, and call indirect through the pointer.
+
+@item -mno-ep
+@itemx -mep
+Do not optimize (do optimize) basic blocks that use the same index
+pointer 4 or more times to copy pointer into the @code{ep} register, and
+use the shorter @code{sld} and @code{sst} instructions. The @samp{-mep}
+option is on by default if you optimize.
+
+@item -mno-prolog-function
+@itemx -mprolog-function
+Do not use (do use) external functions to save and restore registers at
+the prolog and epilog of a function. The external functions are slower,
+but use less code space if more than one function saves the same number
+of registers. The @samp{-mprolog-function} option is on by default if
+you optimize.
+
+@item -mspace
+Try to make the code as small as possible. At present, this just turns
+on the @samp{-mep} and @samp{-mprolog-function} options.
+
+@item -mtda=@var{n}
+Put static or global variables whose size is @var{n} bytes or less into
+the tiny data area that register @code{ep} points to. The tiny data
+area can hold up to 256 bytes in total (128 bytes for byte references).
+
+@item -msda=@var{n}
+Put static or global variables whose size is @var{n} bytes or less into
+the small data area that register @code{gp} points to. The small data
+area can hold up to 64 kilobytes.
+
+@item -mzda=@var{n}
+Put static or global variables whose size is @var{n} bytes or less into
+the first 32 kilobytes of memory.
+
+@item -mv850
+Specify that the target processor is the V850.
+
+@item -mbig-switch
+Generate code suitable for big switch tables. Use this option only if
+the assembler/linker complain about out of range branches within a switch
+table.
+@end table
+
+@node ARC Options
+@subsection ARC Options
+@cindex ARC Options
+
+These options are defined for ARC implementations:
+
+@table @code
+@item -EL
+Compile code for little endian mode. This is the default.
+
+@item -EB
+Compile code for big endian mode.
+
+@item -mmangle-cpu
+Prepend the name of the cpu to all public symbol names.
+In multiple-processor systems, there are many ARC variants with different
+instruction and register set characteristics. This flag prevents code
+compiled for one cpu to be linked with code compiled for another.
+No facility exists for handling variants that are "almost identical".
+This is an all or nothing option.
+
+@item -mcpu=@var{cpu}
+Compile code for ARC variant @var{cpu}.
+Which variants are supported depend on the configuration.
+All variants support @samp{-mcpu=base}, this is the default.
+
+@item -mtext=@var{text section}
+@item -mdata=@var{data section}
+@item -mrodata=@var{readonly data section}
+Put functions, data, and readonly data in @var{text section},
+@var{data section}, and @var{readonly data section} respectively
+by default. This can be overridden with the @code{section} attribute.
+@xref{Variable Attributes}.
+
+@end table
+
+
@node Code Gen Options
@section Options for Code Generation Conventions
@cindex code generation conventions
-@cindex options, code generation
+@cindex options, code generation
@cindex run-time options
These machine-independent options control the interface conventions
@@ -4054,6 +5704,16 @@ can figure out the other form by either removing @samp{no-} or adding
it.
@table @code
+@item -fexceptions
+Enable exception handling, and generate extra code needed to propagate
+exceptions. If you do not specify this option, GNU CC enables it by
+default for languages like C++ that normally require exception handling,
+and disabled for languages like C that do not normally require it.
+However, when compiling C code that needs to interoperate properly with
+exception handlers written in C++, you may need to enable this option.
+You may also wish to disable this option is you are compiling older C++
+programs that don't use exception handling.
+
@item -fpcc-struct-return
Return ``short'' @code{struct} and @code{union} values in memory like
longer ones, rather than in registers. This convention is less
@@ -4116,7 +5776,7 @@ compiler driver @code{gcc} is configured to do this automatically.
@item -finhibit-size-directive
Don't output a @code{.size} assembler directive, or anything else that
-would cause trouble if the function is split in the middle, and the
+would cause trouble if the function is split in the middle, and the
two halves are placed at locations far apart in memory. This option is
used when compiling @file{crtstuff.c}; you should not need to use it
for anything else.
@@ -4127,6 +5787,10 @@ make it more readable. This option is generally only of use to those
who actually need to read the generated assembly code (perhaps while
debugging the compiler itself).
+@samp{-fno-verbose-asm}, the default, causes the
+extra information to be omitted and is useful when comparing two assembler
+files.
+
@item -fvolatile
Consider all memory references through pointers to be volatile.
@@ -4139,27 +5803,24 @@ be volatile.
@cindex PIC
Generate position-independent code (PIC) suitable for use in a shared
library, if supported for the target machine. Such code accesses all
-constant addresses through a global offset table (GOT). If the GOT size
-for the linked executable exceeds a machine-specific maximum size, you
-get an error message from the linker indicating that @samp{-fpic} does
-not work; in that case, recompile with @samp{-fPIC} instead. (These
-maximums are 16k on the m88k, 8k on the Sparc, and 32k on the m68k and
-RS/6000. The 386 has no such limit.)
+constant addresses through a global offset table (GOT). The dynamic
+loader resolves the GOT entries when the program starts (the dynamic
+loader is not part of GNU CC; it is part of the operating system). If
+the GOT size for the linked executable exceeds a machine-specific
+maximum size, you get an error message from the linker indicating that
+@samp{-fpic} does not work; in that case, recompile with @samp{-fPIC}
+instead. (These maximums are 16k on the m88k, 8k on the Sparc, and 32k
+on the m68k and RS/6000. The 386 has no such limit.)
Position-independent code requires special support, and therefore works
only on certain machines. For the 386, GNU CC supports PIC for System V
but not for the Sun 386i. Code generated for the IBM RS/6000 is always
position-independent.
-The GNU assembler does not fully support PIC. Currently, you must use
-some other assembler in order for PIC to work. We would welcome
-volunteers to upgrade GAS to handle this; the first part of the job is
-to figure out what the assembler must do differently.
-
@item -fPIC
If supported for the target machine, emit position-independent code,
suitable for dynamic linking and avoiding any limit on the size of the
-global offset table. This option makes a difference on the m68k, m88k
+global offset table. This option makes a difference on the m68k, m88k,
and the Sparc.
Position-independent code requires special support, and therefore works
@@ -4178,7 +5839,7 @@ This flag does not have a negative form, because it specifies a
three-way choice.
@item -fcall-used-@var{reg}
-Treat the register named @var{reg} as an allocatable register that is
+Treat the register named @var{reg} as an allocable register that is
clobbered by function calls. It may be allocated for temporaries or
variables that do not live across a call. Functions compiled this way
will not save and restore the register @var{reg}.
@@ -4191,7 +5852,7 @@ This flag does not have a negative form, because it specifies a
three-way choice.
@item -fcall-saved-@var{reg}
-Treat the register named @var{reg} as an allocatable register saved by
+Treat the register named @var{reg} as an allocable register saved by
functions. It may be allocated even for temporaries or variables that
live across a call. Functions compiled this way will save and restore
the register @var{reg} if they use it.
@@ -4211,6 +5872,69 @@ Pack all structure members together without holes. Usually you would
not want to use this option, since it makes the code suboptimal, and
the offsets of structure members won't agree with system libraries.
+@item -fcheck-memory-usage
+Generate extra code to check each memory access. GNU CC will generate
+code that is suitable for a detector of bad memory accesses such as
+@file{Checker}. If you specify this option, you can not use the
+@code{asm} or @code{__asm__} keywords.
+
+You must also specify this option when you compile functions you call that
+have side effects. If you do not, you may get erroneous messages from
+the detector. Normally, you should compile all your code with this option.
+If you use functions from a library that have side-effects (such as
+@code{read}), you may not be able to recompile the library and
+specify this option. In that case, you can enable the
+@samp{-fprefix-function-name} option, which requests GNU CC to encapsulate
+your code and make other functions look as if they were compiled with
+@samp{-fcheck-memory-usage}. This is done by calling ``stubs'',
+which are provided by the detector. If you cannot find or build
+stubs for every function you call, you may have to specify
+@samp{-fcheck-memory-usage} without @samp{-fprefix-function-name}.
+
+@item -fprefix-function-name
+Request GNU CC to add a prefix to the symbols generated for function names.
+GNU CC adds a prefix to the names of functions defined as well as
+functions called. Code compiled with this option and code compiled
+without the option can't be linked together, unless or stubs are used.
+
+If you compile the following code with @samp{-fprefix-function-name}
+@example
+extern void bar (int);
+void
+foo (int a)
+@{
+ return bar (a + 5);
+
+@}
+@end example
+
+@noindent
+GNU CC will compile the code as if it was written:
+@example
+extern void prefix_bar (int);
+void
+prefix_foo (int a)
+@{
+ return prefix_bar (a + 5);
+@}
+@end example
+This option is designed to be used with @samp{-fcheck-memory-usage}.
+
+@item -fstack-check
+Generate code to verify that you do not go beyond the boundary of the
+stack. You should specify this flag if you are running in an
+environment with multiple threads, but only rarely need to specify it in
+a single-threaded environment since stack overflow is automatically
+detected on nearly all systems if there is only one stack.
+
+@item -fexceptions
+Enable exception handling. For some targets, this implies
+generation of frame unwind information for all functions, which can produce
+significant data size overhead, though it does not affect execution.
+
+This option is on by default for languages that support exception
+handling (such as C++), and off for those that don't (such as C).
+
@item +e0
@itemx +e1
Control whether virtual function definitions in classes are used to
@@ -4228,6 +5952,24 @@ compilation).
With @samp{+e1}, G++ actually generates the code implementing virtual
functions defined in the code, and makes them publicly visible.
+
+@cindex aliasing of parameters
+@cindex parameters, aliased
+@item -fargument-alias
+@itemx -fargument-noalias
+@itemx -fargument-noalias-global
+Specify the possible relationships among parameters and between
+parameters and global data.
+
+@samp{-fargument-alias} specifies that arguments (parameters) may
+alias each other and may alias global storage.
+@samp{-fargument-noalias} specifies that arguments do not alias
+each other, but may alias global storage.
+@samp{-fargument-noalias-global} specifies that arguments do not
+alias each other and do not alias global storage.
+
+Each language will automatically use whatever option is required by
+the language standard. You should not need to use these options yourself.
@end table
@node Environment Variables
@@ -4243,7 +5985,7 @@ Note that you can also specify places to search using options such as
@samp{-B}, @samp{-I} and @samp{-L} (@pxref{Directory Options}). These
take precedence over places specified using environment variables, which
in turn take precedence over those specified by the configuration of GNU
-CC.
+CC.
@end ifclear
@ifset INTERNALS
Note that you can also specify places to search using options such as
@@ -4324,7 +6066,7 @@ file directories.
@item DEPENDENCIES_OUTPUT
@findex DEPENDENCIES_OUTPUT
-@cindex dependencies for make as output
+@cindex dependencies for make as output
If this variable is set, its value specifies how to output dependencies
for Make based on the header files processed by the compiler. This
output looks much like the output from the @samp{-M} option
@@ -4385,7 +6127,7 @@ with @samp{-q}.
The output from @code{protoize} or @code{unprotoize} replaces the
original source file. The original file is renamed to a name ending
-with @samp{.save}. If the @samp{.save} file already exists, then
+with @samp{.save}. If the @samp{.save} file already exists, then
the source file is simply discarded.
@code{protoize} and @code{unprotoize} both depend on GNU CC itself to
diff --git a/contrib/gcc/jump.c b/contrib/gcc/jump.c
index 88a6c3a..ff4680c 100644
--- a/contrib/gcc/jump.c
+++ b/contrib/gcc/jump.c
@@ -1,5 +1,5 @@
/* Optimize jump instructions, for GNU compiler.
- Copyright (C) 1987, 88, 89, 91-94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 91-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -52,14 +52,19 @@ Boston, MA 02111-1307, USA. */
from other passes as well. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "flags.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "insn-config.h"
#include "insn-flags.h"
+#include "insn-attr.h"
+#include "recog.h"
#include "expr.h"
#include "real.h"
+#include "except.h"
+#include "toplev.h"
/* ??? Eventually must record somehow the labels used by jumps
from nested functions. */
@@ -100,7 +105,7 @@ int can_reach_end;
Normally they are not significant, because of A and B jump to C,
and R dies in A, it must die in B. But this might not be true after
stack register conversion, and we must compare death notes in that
- case. */
+ case. */
static int cross_jump_death_matters = 0;
@@ -113,7 +118,11 @@ static void mark_jump_label PROTO((rtx, rtx, int));
static void delete_computation PROTO((rtx));
static void delete_from_jump_chain PROTO((rtx));
static int delete_labelref_insn PROTO((rtx, rtx, int));
+static void mark_modified_reg PROTO((rtx, rtx));
static void redirect_tablejump PROTO((rtx, rtx));
+#ifndef HAVE_cc0
+static rtx find_insert_position PROTO((rtx, rtx));
+#endif
/* Delete no-op jumps and optimize jumps to jumps
and jumps around jumps.
@@ -143,6 +152,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
{
register rtx insn, next, note;
int changed;
+ int old_max_reg;
int first = 1;
int max_uid = 0;
rtx last_insn;
@@ -173,6 +183,12 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
max_uid++;
+ /* If we are performing cross jump optimizations, then initialize
+ tables mapping UIDs to EH regions to avoid incorrect movement
+ of insns from one EH region to another. */
+ if (flag_exceptions && cross_jump)
+ init_insn_eh_region (f, max_uid);
+
/* Delete insns following barriers, up to next label. */
for (insn = f; insn;)
@@ -208,11 +224,10 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
also make a chain of all returns. */
for (insn = f; insn; insn = NEXT_INSN (insn))
- if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
- && ! INSN_DELETED_P (insn))
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
mark_jump_label (PATTERN (insn), insn, cross_jump);
- if (GET_CODE (insn) == JUMP_INSN)
+ if (! INSN_DELETED_P (insn) && GET_CODE (insn) == JUMP_INSN)
{
if (JUMP_LABEL (insn) != 0 && simplejump_p (insn))
{
@@ -234,6 +249,16 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
for (insn = forced_labels; insn; insn = XEXP (insn, 1))
LABEL_NUSES (XEXP (insn, 0))++;
+ check_exception_handler_labels ();
+
+ /* Keep track of labels used for marking handlers for exception
+ regions; they cannot usually be deleted. */
+
+ for (insn = exception_handler_labels; insn; insn = XEXP (insn, 1))
+ LABEL_NUSES (XEXP (insn, 0))++;
+
+ exception_optimize ();
+
/* Delete all labels already not referenced.
Also find the last insn. */
@@ -283,6 +308,9 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
/* Zero the "deleted" flag of all the "deleted" insns. */
for (insn = f; insn; insn = NEXT_INSN (insn))
INSN_DELETED_P (insn) = 0;
+
+ /* Show that the jump chain is not valid. */
+ jump_chain = 0;
return;
}
@@ -381,9 +409,14 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
if (GET_CODE (p) != INSN)
break;
pbody = PATTERN (p);
- if (GET_CODE (pbody) == SET)
+ if (GET_CODE (pbody) != SET)
break;
dest = SET_DEST (pbody);
+ /* Allow a no-op move between the adjust and the push. */
+ if (GET_CODE (dest) == REG
+ && GET_CODE (SET_SRC (pbody)) == REG
+ && REGNO (dest) == REGNO (SET_SRC (pbody)))
+ continue;
if (! (GET_CODE (dest) == MEM
&& GET_CODE (XEXP (dest, 0)) == POST_INC
&& XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx))
@@ -438,28 +471,40 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
sreg, NULL_PTR, dreg,
GET_MODE (SET_SRC (body)));
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
- /* Deleting insn could lose a death-note for SREG or DREG
- so don't do it if final needs accurate death-notes. */
- if (! PRESERVE_DEATH_INFO_REGNO_P (sreg)
- && ! PRESERVE_DEATH_INFO_REGNO_P (dreg))
-#endif
+ if (tem != 0
+ && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
{
/* DREG may have been the target of a REG_DEAD note in
the insn which makes INSN redundant. If so, reorg
would still think it is dead. So search for such a
note and delete it if we find it. */
- for (trial = prev_nonnote_insn (insn);
- trial && GET_CODE (trial) != CODE_LABEL;
- trial = prev_nonnote_insn (trial))
- if (find_regno_note (trial, REG_DEAD, dreg))
- {
- remove_death (dreg, trial);
- break;
- }
-
- if (tem != 0
- && GET_MODE (tem) == GET_MODE (SET_DEST (body)))
+ if (! find_regno_note (insn, REG_UNUSED, dreg))
+ for (trial = prev_nonnote_insn (insn);
+ trial && GET_CODE (trial) != CODE_LABEL;
+ trial = prev_nonnote_insn (trial))
+ if (find_regno_note (trial, REG_DEAD, dreg))
+ {
+ remove_death (dreg, trial);
+ break;
+ }
+#ifdef PRESERVE_DEATH_INFO_REGNO_P
+ /* Deleting insn could lose a death-note for SREG
+ so don't do it if final needs accurate
+ death-notes. */
+ if (PRESERVE_DEATH_INFO_REGNO_P (sreg)
+ && (trial = find_regno_note (insn, REG_DEAD, sreg)))
+ {
+ /* Change this into a USE so that we won't emit
+ code for it, but still can keep the note. */
+ PATTERN (insn)
+ = gen_rtx_USE (VOIDmode, XEXP (trial, 0));
+ INSN_CODE (insn) = -1;
+ /* Remove all reg notes but the REG_DEAD one. */
+ REG_NOTES (insn) = trial;
+ XEXP (trial, 1) = NULL_RTX;
+ }
+ else
+#endif
delete_insn (insn);
}
}
@@ -499,7 +544,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
else if (GET_CODE (body) == PARALLEL)
{
/* If each part is a set between two identical registers or
- a USE or CLOBBER, delete the insn. */
+ a USE or CLOBBER, delete the insn. */
int i, sreg, dreg;
rtx tem;
@@ -547,11 +592,11 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
if (set && GET_CODE (SET_DEST (set)) == REG
&& REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
- && regno_first_uid[REGNO (SET_DEST (set))] == INSN_UID (insn)
+ && REGNO_FIRST_UID (REGNO (SET_DEST (set))) == INSN_UID (insn)
/* We use regno_last_note_uid so as not to delete the setting
of a reg that's used in notes. A subsequent optimization
might arrange to use that reg for real. */
- && regno_last_note_uid[REGNO (SET_DEST (set))] == INSN_UID (insn)
+ && REGNO_LAST_NOTE_UID (REGNO (SET_DEST (set))) == INSN_UID (insn)
&& ! side_effects_p (SET_SRC (set))
&& ! find_reg_note (insn, REG_RETVAL, 0))
delete_insn (insn);
@@ -559,6 +604,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
/* Now iterate optimizing jumps until nothing changes over one pass. */
changed = 1;
+ old_max_reg = max_reg_num ();
while (changed)
{
changed = 0;
@@ -568,8 +614,9 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
rtx reallabelprev;
rtx temp, temp1, temp2, temp3, temp4, temp5, temp6;
rtx nlabel;
- int this_is_simplejump, this_is_condjump, reversep;
+ int this_is_simplejump, this_is_condjump, reversep = 0;
int this_is_condjump_in_parallel;
+
#if 0
/* If NOT the first iteration, if this is the last jump pass
(just before final), do the special peephole optimizations.
@@ -682,7 +729,15 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& (temp1 = prev_nonnote_insn (JUMP_LABEL (insn))) != 0
&& (GET_CODE (temp1) == BARRIER
|| (GET_CODE (temp1) == INSN
- && rtx_equal_p (PATTERN (temp), PATTERN (temp1)))))
+ && rtx_equal_p (PATTERN (temp), PATTERN (temp1))))
+ /* Don't do this optimization if we have a loop containing only
+ the USE instruction, and the loop start label has a usage
+ count of 1. This is because we will redo this optimization
+ everytime through the outer loop, and jump opt will never
+ exit. */
+ && ! ((temp2 = prev_nonnote_insn (temp)) != 0
+ && temp2 == JUMP_LABEL (insn)
+ && LABEL_NUSES (temp2) == 1))
{
if (GET_CODE (temp1) == BARRIER)
{
@@ -729,16 +784,14 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& GET_CODE (temp3) == INSN
&& (temp4 = single_set (temp3)) != 0
&& GET_CODE (temp1 = SET_DEST (temp4)) == REG
-#ifdef SMALL_REGISTER_CLASSES
- && REGNO (temp1) >= FIRST_PSEUDO_REGISTER
-#endif
+ && (! SMALL_REGISTER_CLASSES
+ || REGNO (temp1) >= FIRST_PSEUDO_REGISTER)
&& (temp2 = next_active_insn (insn)) != 0
&& GET_CODE (temp2) == INSN
&& (temp4 = single_set (temp2)) != 0
&& rtx_equal_p (SET_DEST (temp4), temp1)
- && (GET_CODE (SET_SRC (temp4)) == REG
- || GET_CODE (SET_SRC (temp4)) == SUBREG
- || CONSTANT_P (SET_SRC (temp4)))
+ && ! side_effects_p (SET_SRC (temp4))
+ && ! may_trap_p (SET_SRC (temp4))
&& (REG_NOTES (temp2) == 0
|| ((REG_NOTE_KIND (REG_NOTES (temp2)) == REG_EQUAL
|| REG_NOTE_KIND (REG_NOTES (temp2)) == REG_EQUIV)
@@ -765,7 +818,10 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
or a jump to somewhere else. */
rtx target = JUMP_LABEL (temp);
int nuses = LABEL_NUSES (target);
- rtx p, q;
+ rtx p;
+#ifdef HAVE_cc0
+ rtx q;
+#endif
/* Set P to the first jump insn that goes around "x = a;". */
for (p = temp; nuses && p; p = prev_nonnote_insn (p))
@@ -806,7 +862,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& ! reg_referenced_between_p (temp1, p, NEXT_INSN (temp3))
&& ! reg_set_between_p (temp1, p, temp3)
&& (GET_CODE (SET_SRC (temp4)) == CONST_INT
- || ! reg_set_between_p (SET_SRC (temp4), p, temp2)))
+ || ! modified_between_p (SET_SRC (temp4), p, temp2)))
{
emit_insn_after_with_line_notes (PATTERN (temp2), p, temp2);
delete_insn (temp2);
@@ -833,6 +889,93 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
}
}
+ /* Simplify if (...) { x = a; goto l; } x = b; by converting it
+ to x = a; if (...) goto l; x = b;
+ if A is sufficiently simple, the test doesn't involve X,
+ and nothing in the test modifies A or X.
+
+ If we have small register classes, we also can't do this if X
+ is a hard register.
+
+ If the "x = a;" insn has any REG_NOTES, we don't do this because
+ of the possibility that we are running after CSE and there is a
+ REG_EQUAL note that is only valid if the branch has already been
+ taken. If we move the insn with the REG_EQUAL note, we may
+ fold the comparison to always be false in a later CSE pass.
+ (We could also delete the REG_NOTES when moving the insn, but it
+ seems simpler to not move it.) An exception is that we can move
+ the insn if the only note is a REG_EQUAL or REG_EQUIV whose
+ value is the same as "a".
+
+ INSN is the goto.
+
+ We set:
+
+ TEMP to the jump insn preceding "x = a;"
+ TEMP1 to X
+ TEMP2 to the insn that sets "x = b;"
+ TEMP3 to the insn that sets "x = a;"
+ TEMP4 to the set of "x = a"; */
+
+ if (this_is_simplejump
+ && (temp2 = next_active_insn (insn)) != 0
+ && GET_CODE (temp2) == INSN
+ && (temp4 = single_set (temp2)) != 0
+ && GET_CODE (temp1 = SET_DEST (temp4)) == REG
+ && (! SMALL_REGISTER_CLASSES
+ || REGNO (temp1) >= FIRST_PSEUDO_REGISTER)
+ && (temp3 = prev_active_insn (insn)) != 0
+ && GET_CODE (temp3) == INSN
+ && (temp4 = single_set (temp3)) != 0
+ && rtx_equal_p (SET_DEST (temp4), temp1)
+ && ! side_effects_p (SET_SRC (temp4))
+ && ! may_trap_p (SET_SRC (temp4))
+ && (REG_NOTES (temp3) == 0
+ || ((REG_NOTE_KIND (REG_NOTES (temp3)) == REG_EQUAL
+ || REG_NOTE_KIND (REG_NOTES (temp3)) == REG_EQUIV)
+ && XEXP (REG_NOTES (temp3), 1) == 0
+ && rtx_equal_p (XEXP (REG_NOTES (temp3), 0),
+ SET_SRC (temp4))))
+ && (temp = prev_active_insn (temp3)) != 0
+ && condjump_p (temp) && ! simplejump_p (temp)
+ /* TEMP must skip over the "x = a;" insn */
+ && prev_real_insn (JUMP_LABEL (temp)) == insn
+ && no_labels_between_p (temp, insn))
+ {
+ rtx prev_label = JUMP_LABEL (temp);
+ rtx insert_after = prev_nonnote_insn (temp);
+
+#ifdef HAVE_cc0
+ /* We cannot insert anything between a set of cc and its use. */
+ if (insert_after && GET_RTX_CLASS (GET_CODE (insert_after)) == 'i'
+ && sets_cc0_p (PATTERN (insert_after)))
+ insert_after = prev_nonnote_insn (insert_after);
+#endif
+ ++LABEL_NUSES (prev_label);
+
+ if (insert_after
+ && no_labels_between_p (insert_after, temp)
+ && ! reg_referenced_between_p (temp1, insert_after, temp3)
+ && ! reg_referenced_between_p (temp1, temp3,
+ NEXT_INSN (temp2))
+ && ! reg_set_between_p (temp1, insert_after, temp)
+ && ! modified_between_p (SET_SRC (temp4), insert_after, temp)
+ && invert_jump (temp, JUMP_LABEL (insn)))
+ {
+ emit_insn_after_with_line_notes (PATTERN (temp3),
+ insert_after, temp3);
+ delete_insn (temp3);
+ delete_insn (insn);
+ /* Set NEXT to an insn that we know won't go away. */
+ next = temp2;
+ changed = 1;
+ }
+ if (prev_label && --LABEL_NUSES (prev_label) == 0)
+ delete_insn (prev_label);
+ if (changed)
+ continue;
+ }
+
#ifndef HAVE_cc0
/* If we have if (...) x = exp; and branches are expensive,
EXP is a single insn, does not have any side effects, cannot
@@ -847,7 +990,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
We set:
TEMP to the "x = exp;" insn.
- TEMP1 to the single set in the "x = exp; insn.
+ TEMP1 to the single set in the "x = exp;" insn.
TEMP2 to "x". */
if (! reload_completed
@@ -862,10 +1005,8 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& JUMP_LABEL (temp2) == JUMP_LABEL (insn)))
&& (temp1 = single_set (temp)) != 0
&& (temp2 = SET_DEST (temp1), GET_CODE (temp2) == REG)
- && GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT
-#ifdef SMALL_REGISTER_CLASSES
- && REGNO (temp2) >= FIRST_PSEUDO_REGISTER
-#endif
+ && (! SMALL_REGISTER_CLASSES
+ || REGNO (temp2) >= FIRST_PSEUDO_REGISTER)
&& GET_CODE (SET_SRC (temp1)) != REG
&& GET_CODE (SET_SRC (temp1)) != SUBREG
&& GET_CODE (SET_SRC (temp1)) != CONST_INT
@@ -875,13 +1016,20 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
{
rtx new = gen_reg_rtx (GET_MODE (temp2));
- if (validate_change (temp, &SET_DEST (temp1), new, 0))
+ if ((temp3 = find_insert_position (insn, temp))
+ && validate_change (temp, &SET_DEST (temp1), new, 0))
{
next = emit_insn_after (gen_move_insn (temp2, new), insn);
emit_insn_after_with_line_notes (PATTERN (temp),
- PREV_INSN (insn), temp);
+ PREV_INSN (temp3), temp);
delete_insn (temp);
reallabelprev = prev_active_insn (JUMP_LABEL (insn));
+
+ if (after_regscan)
+ {
+ reg_scan_update (temp3, NEXT_INSN (next), old_max_reg);
+ old_max_reg = max_reg_num ();
+ }
}
}
@@ -905,9 +1053,8 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& (temp1 = single_set (temp)) != 0
&& (temp2 = SET_DEST (temp1), GET_CODE (temp2) == REG)
&& GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT
-#ifdef SMALL_REGISTER_CLASSES
- && REGNO (temp2) >= FIRST_PSEUDO_REGISTER
-#endif
+ && (! SMALL_REGISTER_CLASSES
+ || REGNO (temp2) >= FIRST_PSEUDO_REGISTER)
&& ! side_effects_p (SET_SRC (temp1))
&& ! may_trap_p (SET_SRC (temp1))
&& rtx_cost (SET_SRC (temp1), SET) < 10
@@ -919,23 +1066,34 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
{
rtx new = gen_reg_rtx (GET_MODE (temp2));
- if (validate_change (temp, &SET_DEST (temp1), new, 0))
+ if ((temp5 = find_insert_position (insn, temp))
+ && (temp6 = find_insert_position (insn, temp3))
+ && validate_change (temp, &SET_DEST (temp1), new, 0))
{
+ /* Use the earliest of temp5 and temp6. */
+ if (temp5 != insn)
+ temp6 = temp5;
next = emit_insn_after (gen_move_insn (temp2, new), insn);
emit_insn_after_with_line_notes (PATTERN (temp),
- PREV_INSN (insn), temp);
+ PREV_INSN (temp6), temp);
emit_insn_after_with_line_notes
(replace_rtx (PATTERN (temp3), temp2, new),
- PREV_INSN (insn), temp3);
+ PREV_INSN (temp6), temp3);
delete_insn (temp);
delete_insn (temp3);
reallabelprev = prev_active_insn (JUMP_LABEL (insn));
+
+ if (after_regscan)
+ {
+ reg_scan_update (temp6, NEXT_INSN (next), old_max_reg);
+ old_max_reg = max_reg_num ();
+ }
}
}
/* Finally, handle the case where two insns are used to
compute EXP but a temporary register is used. Here we must
- ensure that the temporary register is not used anywhere else. */
+ ensure that the temporary register is not used anywhere else. */
if (! reload_completed
&& after_regscan
@@ -958,17 +1116,16 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& (temp5 = SUBREG_REG (temp5),
GET_CODE (temp5) == REG))))
&& REGNO (temp5) >= FIRST_PSEUDO_REGISTER
- && regno_first_uid[REGNO (temp5)] == INSN_UID (temp)
- && regno_last_uid[REGNO (temp5)] == INSN_UID (temp3)
+ && REGNO_FIRST_UID (REGNO (temp5)) == INSN_UID (temp)
+ && REGNO_LAST_UID (REGNO (temp5)) == INSN_UID (temp3)
&& ! side_effects_p (SET_SRC (temp1))
&& ! may_trap_p (SET_SRC (temp1))
&& rtx_cost (SET_SRC (temp1), SET) < 10
&& (temp4 = single_set (temp3)) != 0
&& (temp2 = SET_DEST (temp4), GET_CODE (temp2) == REG)
&& GET_MODE_CLASS (GET_MODE (temp2)) == MODE_INT
-#ifdef SMALL_REGISTER_CLASSES
- && REGNO (temp2) >= FIRST_PSEUDO_REGISTER
-#endif
+ && (! SMALL_REGISTER_CLASSES
+ || REGNO (temp2) >= FIRST_PSEUDO_REGISTER)
&& rtx_equal_p (SET_DEST (temp4), temp2)
&& ! side_effects_p (SET_SRC (temp4))
&& ! may_trap_p (SET_SRC (temp4))
@@ -976,16 +1133,27 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
{
rtx new = gen_reg_rtx (GET_MODE (temp2));
- if (validate_change (temp3, &SET_DEST (temp4), new, 0))
+ if ((temp5 = find_insert_position (insn, temp))
+ && (temp6 = find_insert_position (insn, temp3))
+ && validate_change (temp3, &SET_DEST (temp4), new, 0))
{
+ /* Use the earliest of temp5 and temp6. */
+ if (temp5 != insn)
+ temp6 = temp5;
next = emit_insn_after (gen_move_insn (temp2, new), insn);
emit_insn_after_with_line_notes (PATTERN (temp),
- PREV_INSN (insn), temp);
+ PREV_INSN (temp6), temp);
emit_insn_after_with_line_notes (PATTERN (temp3),
- PREV_INSN (insn), temp3);
+ PREV_INSN (temp6), temp3);
delete_insn (temp);
delete_insn (temp3);
reallabelprev = prev_active_insn (JUMP_LABEL (insn));
+
+ if (after_regscan)
+ {
+ reg_scan_update (temp6, NEXT_INSN (next), old_max_reg);
+ old_max_reg = max_reg_num ();
+ }
}
}
#endif /* HAVE_cc0 */
@@ -1019,19 +1187,19 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& GET_CODE (temp) == INSN
&& GET_CODE (PATTERN (temp)) == SET
&& GET_CODE (temp1 = SET_DEST (PATTERN (temp))) == REG
-#ifdef SMALL_REGISTER_CLASSES
- && REGNO (temp1) >= FIRST_PSEUDO_REGISTER
-#endif
- && (GET_CODE (temp2 = SET_SRC (PATTERN (temp))) == REG
- || GET_CODE (temp2) == SUBREG
- /* ??? How about floating point constants? */
- || GET_CODE (temp2) == CONST_INT)
+ && (! SMALL_REGISTER_CLASSES
+ || REGNO (temp1) >= FIRST_PSEUDO_REGISTER)
+ && ! side_effects_p (temp2 = SET_SRC (PATTERN (temp)))
+ && ! may_trap_p (temp2)
/* Allow either form, but prefer the former if both apply.
There is no point in using the old value of TEMP1 if
it is a register, since cse will alias them. It can
lose if the old value were a hard register since CSE
- won't replace hard registers. */
- && (((temp3 = reg_set_last (temp1, insn)) != 0)
+ won't replace hard registers. Avoid using TEMP3 if
+ small register classes and it is a hard register. */
+ && (((temp3 = reg_set_last (temp1, insn)) != 0
+ && ! (SMALL_REGISTER_CLASSES && GET_CODE (temp3) == REG
+ && REGNO (temp3) < FIRST_PSEUDO_REGISTER))
/* Make the latter case look like x = x; if (...) x = b; */
|| (temp3 = temp1, 1))
/* INSN must either branch to the insn after TEMP or the insn
@@ -1045,13 +1213,9 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
We could handle BLKmode if (1) emit_store_flag could
and (2) we could find the size reliably. */
&& GET_MODE (XEXP (temp4, 0)) != BLKmode
- /* No point in doing any of this if branches are cheap or we
- don't have conditional moves. */
- && (BRANCH_COST >= 2
-#ifdef HAVE_conditional_move
- || 1
-#endif
- )
+ /* Even if branches are cheap, the store_flag optimization
+ can win when the operation to be performed can be
+ expressed directly. */
#ifdef HAVE_cc0
/* If the previous insn sets CC0 and something else, we can't
do this since we are going to delete that insn. */
@@ -1101,7 +1265,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
if (target)
{
- rtx seq1,seq2;
+ rtx seq1,seq2,last;
/* Save the conditional move sequence but don't emit it
yet. On some machines, like the alpha, it is possible
@@ -1121,13 +1285,22 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
end_sequence ();
emit_insns_before (seq1, temp5);
- emit_insns_before (seq2, insn);
+ /* Insert conditional move after insn, to be sure that
+ the jump and a possible compare won't be separated */
+ last = emit_insns_after (seq2, insn);
/* ??? We can also delete the insn that sets X to A.
Flow will do it too though. */
delete_insn (temp);
next = NEXT_INSN (insn);
delete_jump (insn);
+
+ if (after_regscan)
+ {
+ reg_scan_update (seq1, NEXT_INSN (last), old_max_reg);
+ old_max_reg = max_reg_num ();
+ }
+
changed = 1;
continue;
}
@@ -1160,8 +1333,21 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
can reverse the condition. See if (3) applies possibly
by reversing the condition. Prefer reversing to (4) when
branches are very expensive. */
- && ((reversep = 0, temp2 == const0_rtx)
- || (temp3 == const0_rtx
+ && (((BRANCH_COST >= 2
+ || STORE_FLAG_VALUE == -1
+ || (STORE_FLAG_VALUE == 1
+ /* Check that the mask is a power of two,
+ so that it can probably be generated
+ with a shift. */
+ && GET_CODE (temp3) == CONST_INT
+ && exact_log2 (INTVAL (temp3)) >= 0))
+ && (reversep = 0, temp2 == const0_rtx))
+ || ((BRANCH_COST >= 2
+ || STORE_FLAG_VALUE == -1
+ || (STORE_FLAG_VALUE == 1
+ && GET_CODE (temp2) == CONST_INT
+ && exact_log2 (INTVAL (temp2)) >= 0))
+ && temp3 == const0_rtx
&& (reversep = can_reverse_comparison_p (temp4, insn)))
|| (BRANCH_COST >= 2
&& GET_CODE (temp2) == CONST_INT
@@ -1297,6 +1483,13 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
delete_insn (temp);
next = NEXT_INSN (insn);
delete_jump (insn);
+
+ if (after_regscan)
+ {
+ reg_scan_update (seq, NEXT_INSN (next), old_max_reg);
+ old_max_reg = max_reg_num ();
+ }
+
changed = 1;
continue;
}
@@ -1362,6 +1555,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
into our sequence. */
if ((temp5 = prev_active_insn (insn)) != 0
+ && no_labels_between_p (temp5, insn)
&& GET_CODE (temp5) == INSN
&& (temp6 = single_set (temp5)) != 0
&& rtx_equal_p (temp2, SET_DEST (temp6))
@@ -1415,6 +1609,13 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
delete_insn (prev_nonnote_insn (insn));
#endif
delete_insn (insn);
+
+ if (after_regscan)
+ {
+ reg_scan_update (seq, NEXT_INSN (next), old_max_reg);
+ old_max_reg = max_reg_num ();
+ }
+
changed = 1;
continue;
}
@@ -1505,7 +1706,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
else if (ultimate && GET_CODE (ultimate) != RETURN)
ultimate = XEXP (ultimate, 0);
- if (ultimate)
+ if (ultimate && JUMP_LABEL(insn) != ultimate)
changed |= redirect_jump (insn, ultimate);
}
}
@@ -1730,10 +1931,96 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
&& (next_active_insn (JUMP_LABEL (insn))
== next_active_insn (JUMP_LABEL (temp))))
{
- delete_jump (insn);
- changed = 1;
- continue;
+ rtx tem = temp;
+
+ /* ??? Optional. Disables some optimizations, but makes
+ gcov output more accurate with -O. */
+ if (flag_test_coverage && !reload_completed)
+ for (tem = insn; tem != temp; tem = NEXT_INSN (tem))
+ if (GET_CODE (tem) == NOTE && NOTE_LINE_NUMBER (tem) > 0)
+ break;
+
+ if (tem == temp)
+ {
+ delete_jump (insn);
+ changed = 1;
+ continue;
+ }
}
+#ifdef HAVE_trap
+ /* Detect a conditional jump jumping over an unconditional trap. */
+ else if (HAVE_trap
+ && this_is_condjump && ! this_is_simplejump
+ && reallabelprev != 0
+ && GET_CODE (reallabelprev) == INSN
+ && GET_CODE (PATTERN (reallabelprev)) == TRAP_IF
+ && TRAP_CONDITION (PATTERN (reallabelprev)) == const_true_rtx
+ && prev_active_insn (reallabelprev) == insn
+ && no_labels_between_p (insn, reallabelprev)
+ && (temp2 = get_condition (insn, &temp4))
+ && can_reverse_comparison_p (temp2, insn))
+ {
+ rtx new = gen_cond_trap (reverse_condition (GET_CODE (temp2)),
+ XEXP (temp2, 0), XEXP (temp2, 1),
+ TRAP_CODE (PATTERN (reallabelprev)));
+
+ if (new)
+ {
+ emit_insn_before (new, temp4);
+ delete_insn (reallabelprev);
+ delete_jump (insn);
+ changed = 1;
+ continue;
+ }
+ }
+ /* Detect a jump jumping to an unconditional trap. */
+ else if (HAVE_trap && this_is_condjump
+ && (temp = next_active_insn (JUMP_LABEL (insn)))
+ && GET_CODE (temp) == INSN
+ && GET_CODE (PATTERN (temp)) == TRAP_IF
+ && (this_is_simplejump
+ || (temp2 = get_condition (insn, &temp4))))
+ {
+ rtx tc = TRAP_CONDITION (PATTERN (temp));
+
+ if (tc == const_true_rtx
+ || (! this_is_simplejump && rtx_equal_p (temp2, tc)))
+ {
+ rtx new;
+ /* Replace an unconditional jump to a trap with a trap. */
+ if (this_is_simplejump)
+ {
+ emit_barrier_after (emit_insn_before (gen_trap (), insn));
+ delete_jump (insn);
+ changed = 1;
+ continue;
+ }
+ new = gen_cond_trap (GET_CODE (temp2), XEXP (temp2, 0),
+ XEXP (temp2, 1),
+ TRAP_CODE (PATTERN (temp)));
+ if (new)
+ {
+ emit_insn_before (new, temp4);
+ delete_jump (insn);
+ changed = 1;
+ continue;
+ }
+ }
+ /* If the trap condition and jump condition are mutually
+ exclusive, redirect the jump to the following insn. */
+ else if (GET_RTX_CLASS (GET_CODE (tc)) == '<'
+ && ! this_is_simplejump
+ && swap_condition (GET_CODE (temp2)) == GET_CODE (tc)
+ && rtx_equal_p (XEXP (tc, 0), XEXP (temp2, 0))
+ && rtx_equal_p (XEXP (tc, 1), XEXP (temp2, 1))
+ && redirect_jump (insn, get_label_after (temp)))
+ {
+ changed = 1;
+ continue;
+ }
+ }
+#endif
+
/* Detect a conditional jump jumping over an unconditional jump. */
else if ((this_is_condjump || this_is_condjump_in_parallel)
@@ -1916,7 +2203,7 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
/* Now that the jump has been tensioned,
try cross jumping: check for identical code
- before the jump and before its target label. */
+ before the jump and before its target label. */
/* First, cross jumping of conditional jumps: */
@@ -1947,11 +2234,11 @@ jump_optimize (f, cross_jump, noop_moves, after_regscan)
/* Make the old conditional jump
into an unconditional one. */
SET_SRC (PATTERN (insn))
- = gen_rtx (LABEL_REF, VOIDmode, JUMP_LABEL (insn));
+ = gen_rtx_LABEL_REF (VOIDmode, JUMP_LABEL (insn));
INSN_CODE (insn) = -1;
emit_barrier_after (insn);
/* Add to jump_chain unless this is a new label
- whose UID is too large. */
+ whose UID is too large. */
if (INSN_UID (JUMP_LABEL (insn)) < max_jump_chain)
{
jump_chain[INSN_UID (insn)]
@@ -2147,6 +2434,11 @@ duplicate_loop_exit_test (loop_start)
is a NOTE_INSN_LOOP_BEG because this means we have a nested loop
is a NOTE_INSN_BLOCK_{BEG,END} because duplicating these notes
are not valid
+
+
+ We also do not do this if we find an insn with ASM_OPERANDS. While
+ this restriction should not be necessary, copying an insn with
+ ASM_OPERANDS can confuse asm_noperands in some cases.
Also, don't do this if the exit code is more than 20 insns. */
@@ -2172,18 +2464,29 @@ duplicate_loop_exit_test (loop_start)
This can be avoided by checking here for NOTE_INSN_LOOP_CONT. */
if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END
|| NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_CONT)
return 0;
+
+ if (optimize < 2
+ && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
+ /* If we were to duplicate this code, we would not move
+ the BLOCK notes, and so debugging the moved code would
+ be difficult. Thus, we only move the code with -O2 or
+ higher. */
+ return 0;
+
break;
case JUMP_INSN:
case INSN:
if (++num_insns > 20
|| find_reg_note (insn, REG_RETVAL, NULL_RTX)
- || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+ || find_reg_note (insn, REG_LIBCALL, NULL_RTX)
+ || asm_noperands (PATTERN (insn)) > 0)
return 0;
break;
+ default:
+ break;
}
}
@@ -2202,10 +2505,10 @@ duplicate_loop_exit_test (loop_start)
|| (GET_CODE (reg) == SUBREG
&& (reg = SUBREG_REG (reg), GET_CODE (reg) == REG)))
&& REGNO (reg) >= FIRST_PSEUDO_REGISTER
- && regno_first_uid[REGNO (reg)] == INSN_UID (insn))
+ && REGNO_FIRST_UID (REGNO (reg)) == INSN_UID (insn))
{
for (p = NEXT_INSN (insn); p != lastexit; p = NEXT_INSN (p))
- if (regno_last_uid[REGNO (reg)] == INSN_UID (p))
+ if (REGNO_LAST_UID (REGNO (reg)) == INSN_UID (p))
break;
if (p != lastexit)
@@ -2252,8 +2555,9 @@ duplicate_loop_exit_test (loop_start)
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) != REG_LABEL)
REG_NOTES (copy)
- = copy_rtx (gen_rtx (EXPR_LIST, REG_NOTE_KIND (link),
- XEXP (link, 0), REG_NOTES (copy)));
+ = copy_rtx (gen_rtx_EXPR_LIST (REG_NOTE_KIND (link),
+ XEXP (link, 0),
+ REG_NOTES (copy)));
if (reg_map && REG_NOTES (copy))
replace_regs (REG_NOTES (copy), reg_map, max_reg, 1);
break;
@@ -2379,7 +2683,6 @@ find_cross_jump (e1, e2, minimum, f1, f2)
rtx last1 = 0, last2 = 0;
rtx afterlast1 = 0, afterlast2 = 0;
- rtx prev1;
*f1 = 0;
*f2 = 0;
@@ -2412,6 +2715,13 @@ find_cross_jump (e1, e2, minimum, f1, f2)
if (i2 == 0 || GET_CODE (i1) != GET_CODE (i2))
break;
+ /* Avoid moving insns across EH regions.
+
+ ??? This is only necessary if i1 or i2 can throw an exception. */
+ if (flag_exceptions
+ && !in_same_eh_region (i1, i2))
+ break;
+
p1 = PATTERN (i1);
p2 = PATTERN (i2);
@@ -2433,13 +2743,13 @@ find_cross_jump (e1, e2, minimum, f1, f2)
#ifdef STACK_REGS
/* If cross_jump_death_matters is not 0, the insn's mode
indicates whether or not the insn contains any stack-like
- regs. */
+ regs. */
if (!lose && cross_jump_death_matters && GET_MODE (i1) == QImode)
{
/* If register stack conversion has already been done, then
death notes must also be compared before it is certain that
- the two instruction streams match. */
+ the two instruction streams match. */
rtx note;
HARD_REG_SET i1_regset, i2_regset;
@@ -2466,7 +2776,19 @@ find_cross_jump (e1, e2, minimum, f1, f2)
}
#endif
- if (lose || GET_CODE (p1) != GET_CODE (p2)
+ /* Don't allow old-style asm or volatile extended asms to be accepted
+ for cross jumping purposes. It is conceptually correct to allow
+ them, since cross-jumping preserves the dynamic instruction order
+ even though it is changing the static instruction order. However,
+ if an asm is being used to emit an assembler pseudo-op, such as
+ the MIPS `.set reorder' pseudo-op, then the static instruction order
+ matters and it must be preserved. */
+ if (GET_CODE (p1) == ASM_INPUT || GET_CODE (p2) == ASM_INPUT
+ || (GET_CODE (p1) == ASM_OPERANDS && MEM_VOLATILE_P (p1))
+ || (GET_CODE (p2) == ASM_OPERANDS && MEM_VOLATILE_P (p2)))
+ lose = 1;
+
+ if (lose || GET_CODE (p1) != GET_CODE (p2)
|| ! rtx_renumbered_equal_p (p1, p2))
{
/* The following code helps take care of G++ cleanups. */
@@ -2922,6 +3244,9 @@ comparison_dominates_p (code1, code2)
if (code2 == GEU || code2 == NE)
return 1;
break;
+
+ default:
+ break;
}
return 0;
@@ -3054,7 +3379,8 @@ follow_jumps (label)
(depth < 10
&& (insn = next_active_insn (value)) != 0
&& GET_CODE (insn) == JUMP_INSN
- && (JUMP_LABEL (insn) != 0 || GET_CODE (PATTERN (insn)) == RETURN)
+ && ((JUMP_LABEL (insn) != 0 && simplejump_p (insn))
+ || GET_CODE (PATTERN (insn)) == RETURN)
&& (next = NEXT_INSN (insn))
&& GET_CODE (next) == BARRIER);
depth++)
@@ -3067,7 +3393,10 @@ follow_jumps (label)
if (!reload_completed)
for (tem = value; tem != insn; tem = NEXT_INSN (tem))
if (GET_CODE (tem) == NOTE
- && NOTE_LINE_NUMBER (tem) == NOTE_INSN_LOOP_BEG)
+ && (NOTE_LINE_NUMBER (tem) == NOTE_INSN_LOOP_BEG
+ /* ??? Optional. Disables some optimizations, but makes
+ gcov output more accurate with -O. */
+ || (flag_test_coverage && NOTE_LINE_NUMBER (tem) > 0)))
return value;
/* If we have found a cycle, make the insn jump to itself. */
@@ -3188,12 +3517,16 @@ mark_jump_label (x, insn, cross_jump)
break;
else if (! cross_jump
&& (NOTE_LINE_NUMBER (next) == NOTE_INSN_LOOP_BEG
- || NOTE_LINE_NUMBER (next) == NOTE_INSN_FUNCTION_END))
+ || NOTE_LINE_NUMBER (next) == NOTE_INSN_FUNCTION_END
+ /* ??? Optional. Disables some optimizations, but
+ makes gcov output more accurate with -O. */
+ || (flag_test_coverage && NOTE_LINE_NUMBER (next) > 0)))
break;
}
XEXP (x, 0) = label;
- ++LABEL_NUSES (label);
+ if (! insn || ! INSN_DELETED_P (insn))
+ ++LABEL_NUSES (label);
if (insn)
{
@@ -3210,17 +3543,21 @@ mark_jump_label (x, insn, cross_jump)
is one. */
else if (! find_reg_note (insn, REG_LABEL, label))
{
- rtx next = next_real_insn (label);
- /* Don't record labels that refer to dispatch tables.
- This is not necessary, since the tablejump
- references the same label.
- And if we did record them, flow.c would make worse code. */
- if (next == 0
- || ! (GET_CODE (next) == JUMP_INSN
- && (GET_CODE (PATTERN (next)) == ADDR_VEC
- || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC)))
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_LABEL, label,
- REG_NOTES (insn));
+ /* This code used to ignore labels which refered to dispatch
+ tables to avoid flow.c generating worse code.
+
+ However, in the presense of global optimizations like
+ gcse which call find_basic_blocks without calling
+ life_analysis, not recording such labels will lead
+ to compiler aborts because of inconsistencies in the
+ flow graph. So we go ahead and record the label.
+
+ It may also be the case that the optimization argument
+ is no longer valid because of the more accurate cfg
+ we build in find_basic_blocks -- it no longer pessimizes
+ code when it finds a REG_LABEL note. */
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+ REG_NOTES (insn));
}
}
return;
@@ -3230,13 +3567,17 @@ mark_jump_label (x, insn, cross_jump)
ADDR_DIFF_VEC. Don't set the JUMP_LABEL of a vector. */
case ADDR_VEC:
case ADDR_DIFF_VEC:
- {
- int eltnum = code == ADDR_DIFF_VEC ? 1 : 0;
+ if (! INSN_DELETED_P (insn))
+ {
+ int eltnum = code == ADDR_DIFF_VEC ? 1 : 0;
- for (i = 0; i < XVECLEN (x, eltnum); i++)
- mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX, cross_jump);
- return;
- }
+ for (i = 0; i < XVECLEN (x, eltnum); i++)
+ mark_jump_label (XVECEXP (x, eltnum, i), NULL_RTX, cross_jump);
+ }
+ return;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -3304,12 +3645,23 @@ delete_computation (insn)
delete_computation (prev);
else
/* Otherwise, show that cc0 won't be used. */
- REG_NOTES (prev) = gen_rtx (EXPR_LIST, REG_UNUSED,
- cc0_rtx, REG_NOTES (prev));
+ REG_NOTES (prev) = gen_rtx_EXPR_LIST (REG_UNUSED,
+ cc0_rtx, REG_NOTES (prev));
}
}
#endif
+#ifdef INSN_SCHEDULING
+ /* ?!? The schedulers do not keep REG_DEAD notes accurate after
+ reload has completed. The schedulers need to be fixed. Until
+ they are, we must not rely on the death notes here. */
+ if (reload_completed && flag_schedule_insns_after_reload)
+ {
+ delete_insn (insn);
+ return;
+ }
+#endif
+
for (note = REG_NOTES (insn); note; note = next)
{
rtx our_prev;
@@ -3603,7 +3955,21 @@ invert_jump (jump, nlabel)
return 0;
if (redirect_jump (jump, nlabel))
- return 1;
+ {
+ if (flag_branch_probabilities)
+ {
+ rtx note = find_reg_note (jump, REG_BR_PROB, 0);
+
+ /* An inverted jump means that a probability taken becomes a
+ probability not taken. Subtract the branch probability from the
+ probability base to convert it back to a taken probability.
+ (We don't flip the probability on a branch that's never taken. */
+ if (note && XINT (XEXP (note, 0), 0) >= 0)
+ XINT (XEXP (note, 0), 0) = REG_BR_PROB_BASE - XINT (XEXP (note, 0), 0);
+ }
+
+ return 1;
+ }
if (! invert_exp (PATTERN (jump), jump))
/* This should just be putting it back the way it was. */
@@ -3640,9 +4006,9 @@ invert_exp (x, insn)
if (can_reverse_comparison_p (comp, insn)
&& validate_change (insn, &XEXP (x, 0),
- gen_rtx (reverse_condition (GET_CODE (comp)),
- GET_MODE (comp), XEXP (comp, 0),
- XEXP (comp, 1)), 0))
+ gen_rtx_fmt_ee (reverse_condition (GET_CODE (comp)),
+ GET_MODE (comp), XEXP (comp, 0),
+ XEXP (comp, 1)), 0))
return 1;
tem = XEXP (x, 1);
@@ -3783,22 +4149,22 @@ redirect_exp (loc, olabel, nlabel, insn)
if (nlabel)
XEXP (x, 0) = nlabel;
else
- return validate_change (insn, loc, gen_rtx (RETURN, VOIDmode), 0);
+ return validate_change (insn, loc, gen_rtx_RETURN (VOIDmode), 0);
return 1;
}
}
else if (code == RETURN && olabel == 0)
{
- x = gen_rtx (LABEL_REF, VOIDmode, nlabel);
+ x = gen_rtx_LABEL_REF (VOIDmode, nlabel);
if (loc == &PATTERN (insn))
- x = gen_rtx (SET, VOIDmode, pc_rtx, x);
+ x = gen_rtx_SET (VOIDmode, pc_rtx, x);
return validate_change (insn, loc, x, 0);
}
if (code == SET && nlabel == 0 && SET_DEST (x) == pc_rtx
&& GET_CODE (SET_SRC (x)) == LABEL_REF
&& XEXP (SET_SRC (x), 0) == olabel)
- return validate_change (insn, loc, gen_rtx (RETURN, VOIDmode), 0);
+ return validate_change (insn, loc, gen_rtx_RETURN (VOIDmode), 0);
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
@@ -3990,6 +4356,13 @@ rtx_renumbered_equal_p (x, y)
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
+
+ case CODE_LABEL:
+ /* If we didn't match EQ equality above, they aren't the same. */
+ return 0;
+
+ default:
+ break;
}
/* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */
@@ -4134,7 +4507,7 @@ static int modified_mem;
static void
mark_modified_reg (dest, x)
rtx dest;
- rtx x;
+ rtx x ATTRIBUTE_UNUSED;
{
int regno, i;
@@ -4279,7 +4652,10 @@ thread_jumps (f, max_reg, flag_before_loop)
if (rtx_equal_for_thread_p (b1op0, b2op0, b2)
&& rtx_equal_for_thread_p (b1op1, b2op1, b2)
&& (comparison_dominates_p (code1, code2)
- || comparison_dominates_p (code1, reverse_condition (code2))))
+ || (comparison_dominates_p (code1, reverse_condition (code2))
+ && can_reverse_comparison_p (XEXP (SET_SRC (PATTERN (b1)),
+ 0),
+ b1))))
{
t1 = prev_nonnote_insn (b1);
t2 = prev_nonnote_insn (b2);
@@ -4308,6 +4684,7 @@ thread_jumps (f, max_reg, flag_before_loop)
rtx prev = PREV_INSN (new_label);
if (flag_before_loop
+ && GET_CODE (prev) == NOTE
&& NOTE_LINE_NUMBER (prev) == NOTE_INSN_LOOP_BEG)
{
/* Don't thread to the loop label. If a loop
@@ -4366,6 +4743,13 @@ rtx_equal_for_thread_p (x, y, yinsn)
if (GET_MODE (x) != GET_MODE (y))
return 0;
+ /* For floating-point, consider everything unequal. This is a bit
+ pessimistic, but this pass would only rarely do anything for FP
+ anyway. */
+ if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
+ && FLOAT_MODE_P (GET_MODE (x)) && ! flag_fast_math)
+ return 0;
+
/* For commutative operations, the RTX match if the operand match in any
order. Also handle the simple binary and unary cases without a loop. */
if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
@@ -4401,7 +4785,7 @@ rtx_equal_for_thread_p (x, y, yinsn)
/* If this is the first time we are seeing a register on the `Y'
side, see if it is the last use. If not, we can't thread the
jump, so mark it as not equivalent. */
- if (regno_last_uid[REGNO (y)] != INSN_UID (yinsn))
+ if (REGNO_LAST_UID (REGNO (y)) != INSN_UID (yinsn))
return 0;
return 1;
@@ -4413,7 +4797,7 @@ rtx_equal_for_thread_p (x, y, yinsn)
case MEM:
/* If memory modified or either volatile, not equivalent.
- Else, check address. */
+ Else, check address. */
if (modified_mem || MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
return 0;
@@ -4450,6 +4834,9 @@ rtx_equal_for_thread_p (x, y, yinsn)
case SYMBOL_REF:
return XSTR (x, 0) == XSTR (y, 0);
+
+ default:
+ break;
}
if (x == y)
@@ -4511,3 +4898,47 @@ rtx_equal_for_thread_p (x, y, yinsn)
}
return 1;
}
+
+
+#ifndef HAVE_cc0
+/* Return the insn that NEW can be safely inserted in front of starting at
+ the jump insn INSN. Return 0 if it is not safe to do this jump
+ optimization. Note that NEW must contain a single set. */
+
+static rtx
+find_insert_position (insn, new)
+ rtx insn;
+ rtx new;
+{
+ int i;
+ rtx prev;
+
+ /* If NEW does not clobber, it is safe to insert NEW before INSN. */
+ if (GET_CODE (PATTERN (new)) != PARALLEL)
+ return insn;
+
+ for (i = XVECLEN (PATTERN (new), 0) - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (PATTERN (new), 0, i)) == CLOBBER
+ && reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (new), 0, i), 0),
+ insn))
+ break;
+
+ if (i < 0)
+ return insn;
+
+ /* There is a good chance that the previous insn PREV sets the thing
+ being clobbered (often the CC in a hard reg). If PREV does not
+ use what NEW sets, we can insert NEW before PREV. */
+
+ prev = prev_active_insn (insn);
+ for (i = XVECLEN (PATTERN (new), 0) - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (PATTERN (new), 0, i)) == CLOBBER
+ && reg_overlap_mentioned_p (XEXP (XVECEXP (PATTERN (new), 0, i), 0),
+ insn)
+ && ! modified_in_p (XEXP (XVECEXP (PATTERN (new), 0, i), 0),
+ prev))
+ return 0;
+
+ return reg_mentioned_p (SET_DEST (single_set (new)), prev) ? 0 : prev;
+}
+#endif /* !HAVE_cc0 */
diff --git a/contrib/gcc/just-fixinc b/contrib/gcc/just-fixinc
index 4a196a0..a7d1968 100755
--- a/contrib/gcc/just-fixinc
+++ b/contrib/gcc/just-fixinc
@@ -1,5 +1,5 @@
#!/bin/sh
-# $Id: just-fixinc,v 1.5 1994/08/16 20:42:48 friedman Exp $
+# $Id: just-fixinc,v 1.2 1998/04/03 16:35:58 law Exp $
# This script exists for use after installing
# the GCC binaries from a distribution tape/CD-ROM.
# Use it *after* copying the directory of binaries
diff --git a/contrib/gcc/libgcc1-test.c b/contrib/gcc/libgcc1-test.c
index 392d4fc..d9c250e 100644
--- a/contrib/gcc/libgcc1-test.c
+++ b/contrib/gcc/libgcc1-test.c
@@ -95,6 +95,12 @@ dfoo ()
message saying the start address is defaulted. */
extern void start() __asm__("start");
extern void _start() __asm__("_start");
+extern void __start() __asm__("__start");
+
+/* Provide functions that might be needed by soft-float emulation routines. */
+void memcpy() {}
void start() {}
void _start() {}
+void __start() {}
+void mainCRTStartup() {}
diff --git a/contrib/gcc/libgcc2.c b/contrib/gcc/libgcc2.c
index 1e01e91..d1854ed 100644
--- a/contrib/gcc/libgcc2.c
+++ b/contrib/gcc/libgcc2.c
@@ -1,6 +1,6 @@
/* More subroutines needed by GCC output code on some machines. */
/* Compile this one with gcc. */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+/* Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -31,6 +31,17 @@ Boston, MA 02111-1307, USA. */
do not apply. */
#include "tconfig.h"
+
+/* We disable this when inhibit_libc, so that gcc can still be built without
+ needing header files first. */
+/* ??? This is not a good solution, since prototypes may be required in
+ some cases for correct code. See also frame.c. */
+#ifndef inhibit_libc
+/* fixproto guarantees these system headers exist. */
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+
#include "machmode.h"
#include "defaults.h"
#ifndef L_trampoline
@@ -42,10 +53,17 @@ Boston, MA 02111-1307, USA. */
#undef abort
#endif
-#if (SUPPORTS_WEAK == 1) && defined (ASM_OUTPUT_DEF)
+#if (SUPPORTS_WEAK == 1) && (defined (ASM_OUTPUT_DEF) || defined (ASM_OUTPUT_WEAK_ALIAS))
#define WEAK_ALIAS
#endif
+/* In a cross-compilation situation, default to inhibiting compilation
+ of routines that use libc. */
+
+#if defined(CROSS_COMPILE) && !defined(inhibit_libc)
+#define inhibit_libc
+#endif
+
/* Permit the tm.h file to select the endianness to use just for this
file. This is used when the endianness is determined when the
compiler is run. */
@@ -138,8 +156,7 @@ extern DItype __fixunstfdi (TFtype a);
static inline
#endif
DItype
-__negdi2 (u)
- DItype u;
+__negdi2 (DItype u)
{
DIunion w;
DIunion uu;
@@ -153,11 +170,11 @@ __negdi2 (u)
}
#endif
+/* Unless shift functions are defined whith full ANSI prototypes,
+ parameter b will be promoted to int if word_type is smaller than an int. */
#ifdef L_lshrdi3
DItype
-__lshrdi3 (u, b)
- DItype u;
- word_type b;
+__lshrdi3 (DItype u, word_type b)
{
DIunion w;
word_type bm;
@@ -187,9 +204,7 @@ __lshrdi3 (u, b)
#ifdef L_ashldi3
DItype
-__ashldi3 (u, b)
- DItype u;
- word_type b;
+__ashldi3 (DItype u, word_type b)
{
DIunion w;
word_type bm;
@@ -219,9 +234,7 @@ __ashldi3 (u, b)
#ifdef L_ashrdi3
DItype
-__ashrdi3 (u, b)
- DItype u;
- word_type b;
+__ashrdi3 (DItype u, word_type b)
{
DIunion w;
word_type bm;
@@ -252,8 +265,7 @@ __ashrdi3 (u, b)
#ifdef L_ffsdi2
DItype
-__ffsdi2 (u)
- DItype u;
+__ffsdi2 (DItype u)
{
DIunion uu, w;
uu.ll = u;
@@ -273,8 +285,7 @@ __ffsdi2 (u)
#ifdef L_muldi3
DItype
-__muldi3 (u, v)
- DItype u, v;
+__muldi3 (DItype u, DItype v)
{
DIunion w;
DIunion uu, vv;
@@ -293,8 +304,7 @@ __muldi3 (u, v)
#ifdef L_udiv_w_sdiv
#if defined (sdiv_qrnnd)
USItype
-__udiv_w_sdiv (rp, a1, a0, d)
- USItype *rp, a1, a0, d;
+__udiv_w_sdiv (USItype *rp, USItype a1, USItype a0, USItype d)
{
USItype q, r;
USItype c0, c1, b1;
@@ -392,9 +402,13 @@ __udiv_w_sdiv (rp, a1, a0, d)
#else
/* If sdiv_qrnnd doesn't exist, define dummy __udiv_w_sdiv. */
USItype
-__udiv_w_sdiv (rp, a1, a0, d)
- USItype *rp, a1, a0, d;
-{}
+__udiv_w_sdiv (USItype *rp __attribute__ ((__unused__)),
+ USItype a1 __attribute__ ((__unused__)),
+ USItype a0 __attribute__ ((__unused__)),
+ USItype d __attribute__ ((__unused__)))
+{
+ return 0;
+}
#endif
#endif
@@ -421,9 +435,7 @@ static const UQItype __clz_tab[] =
static inline
#endif
UDItype
-__udivmoddi4 (n, d, rp)
- UDItype n, d;
- UDItype *rp;
+__udivmoddi4 (UDItype n, UDItype d, UDItype *rp)
{
DIunion ww;
DIunion nn, dd;
@@ -533,7 +545,7 @@ __udivmoddi4 (n, d, rp)
udiv_qrnnd (q1, n1, n2, n1, d0);
}
- /* n1 != d0... */
+ /* n1 != d0... */
udiv_qrnnd (q0, n0, n1, n0, d0);
@@ -644,8 +656,7 @@ __udivmoddi4 (n, d, rp)
UDItype __udivmoddi4 ();
DItype
-__divdi3 (u, v)
- DItype u, v;
+__divdi3 (DItype u, DItype v)
{
word_type c = 0;
DIunion uu, vv;
@@ -672,8 +683,7 @@ __divdi3 (u, v)
#ifdef L_moddi3
UDItype __udivmoddi4 ();
DItype
-__moddi3 (u, v)
- DItype u, v;
+__moddi3 (DItype u, DItype v)
{
word_type c = 0;
DIunion uu, vv;
@@ -699,8 +709,7 @@ __moddi3 (u, v)
#ifdef L_umoddi3
UDItype __udivmoddi4 ();
UDItype
-__umoddi3 (u, v)
- UDItype u, v;
+__umoddi3 (UDItype u, UDItype v)
{
UDItype w;
@@ -713,8 +722,7 @@ __umoddi3 (u, v)
#ifdef L_udivdi3
UDItype __udivmoddi4 ();
UDItype
-__udivdi3 (n, d)
- UDItype n, d;
+__udivdi3 (UDItype n, UDItype d)
{
return __udivmoddi4 (n, d, (UDItype *) 0);
}
@@ -722,8 +730,7 @@ __udivdi3 (n, d)
#ifdef L_cmpdi2
word_type
-__cmpdi2 (a, b)
- DItype a, b;
+__cmpdi2 (DItype a, DItype b)
{
DIunion au, bu;
@@ -743,8 +750,7 @@ __cmpdi2 (a, b)
#ifdef L_ucmpdi2
word_type
-__ucmpdi2 (a, b)
- DItype a, b;
+__ucmpdi2 (DItype a, DItype b)
{
DIunion au, bu;
@@ -767,8 +773,7 @@ __ucmpdi2 (a, b)
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
DItype
-__fixunstfdi (a)
- TFtype a;
+__fixunstfdi (TFtype a)
{
TFtype b;
UDItype v;
@@ -797,8 +802,7 @@ __fixunstfdi (a)
#if defined(L_fixtfdi) && (LONG_DOUBLE_TYPE_SIZE == 128)
DItype
-__fixtfdi (a)
- TFtype a;
+__fixtfdi (TFtype a)
{
if (a < 0)
return - __fixunstfdi (-a);
@@ -811,8 +815,7 @@ __fixtfdi (a)
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
DItype
-__fixunsxfdi (a)
- XFtype a;
+__fixunsxfdi (XFtype a)
{
XFtype b;
UDItype v;
@@ -841,8 +844,7 @@ __fixunsxfdi (a)
#if defined(L_fixxfdi) && (LONG_DOUBLE_TYPE_SIZE == 96)
DItype
-__fixxfdi (a)
- XFtype a;
+__fixxfdi (XFtype a)
{
if (a < 0)
return - __fixunsxfdi (-a);
@@ -855,8 +857,7 @@ __fixxfdi (a)
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
DItype
-__fixunsdfdi (a)
- DFtype a;
+__fixunsdfdi (DFtype a)
{
DFtype b;
UDItype v;
@@ -885,8 +886,7 @@ __fixunsdfdi (a)
#ifdef L_fixdfdi
DItype
-__fixdfdi (a)
- DFtype a;
+__fixdfdi (DFtype a)
{
if (a < 0)
return - __fixunsdfdi (-a);
@@ -946,21 +946,16 @@ __fixsfdi (SFtype a)
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
XFtype
-__floatdixf (u)
- DItype u;
+__floatdixf (DItype u)
{
XFtype d;
- SItype negate = 0;
- if (u < 0)
- u = -u, negate = 1;
-
- d = (USItype) (u >> WORD_SIZE);
+ d = (SItype) (u >> WORD_SIZE);
d *= HIGH_HALFWORD_COEFF;
d *= HIGH_HALFWORD_COEFF;
d += (USItype) (u & (HIGH_WORD_COEFF - 1));
- return (negate ? -d : d);
+ return d;
}
#endif
@@ -970,21 +965,16 @@ __floatdixf (u)
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
TFtype
-__floatditf (u)
- DItype u;
+__floatditf (DItype u)
{
TFtype d;
- SItype negate = 0;
-
- if (u < 0)
- u = -u, negate = 1;
- d = (USItype) (u >> WORD_SIZE);
+ d = (SItype) (u >> WORD_SIZE);
d *= HIGH_HALFWORD_COEFF;
d *= HIGH_HALFWORD_COEFF;
d += (USItype) (u & (HIGH_WORD_COEFF - 1));
- return (negate ? -d : d);
+ return d;
}
#endif
@@ -994,21 +984,16 @@ __floatditf (u)
#define HIGH_WORD_COEFF (((UDItype) 1) << WORD_SIZE)
DFtype
-__floatdidf (u)
- DItype u;
+__floatdidf (DItype u)
{
DFtype d;
- SItype negate = 0;
-
- if (u < 0)
- u = -u, negate = 1;
- d = (USItype) (u >> WORD_SIZE);
+ d = (SItype) (u >> WORD_SIZE);
d *= HIGH_HALFWORD_COEFF;
d *= HIGH_HALFWORD_COEFF;
d += (USItype) (u & (HIGH_WORD_COEFF - 1));
- return (negate ? -d : d);
+ return d;
}
#endif
@@ -1047,17 +1032,12 @@ __floatdidf (u)
#endif
SFtype
-__floatdisf (u)
- DItype u;
+__floatdisf (DItype u)
{
/* Do the calculation in DFmode
so that we don't lose any of the precision of the high word
while multiplying it. */
DFtype f;
- SItype negate = 0;
-
- if (u < 0)
- u = -u, negate = 1;
/* Protect against double-rounding error.
Represent any low-order bits, that might be truncated in DFmode,
@@ -1069,18 +1049,19 @@ __floatdisf (u)
&& DF_SIZE > (DI_SIZE - DF_SIZE + SF_SIZE))
{
#define REP_BIT ((USItype) 1 << (DI_SIZE - DF_SIZE))
- if (u >= ((UDItype) 1 << DF_SIZE))
+ if (! (- ((DItype) 1 << DF_SIZE) < u
+ && u < ((DItype) 1 << DF_SIZE)))
{
if ((USItype) u & (REP_BIT - 1))
u |= REP_BIT;
}
}
- f = (USItype) (u >> WORD_SIZE);
+ f = (SItype) (u >> WORD_SIZE);
f *= HIGH_HALFWORD_COEFF;
f *= HIGH_HALFWORD_COEFF;
f += (USItype) (u & (HIGH_WORD_COEFF - 1));
- return (SFtype) (negate ? -f : f);
+ return (SFtype) f;
}
#endif
@@ -1098,8 +1079,7 @@ __floatdisf (u)
#include <limits.h>
USItype
-__fixunsxfsi (a)
- XFtype a;
+__fixunsxfsi (XFtype a)
{
if (a >= - (DFtype) LONG_MIN)
return (SItype) (a + LONG_MIN) - LONG_MIN;
@@ -1121,8 +1101,7 @@ __fixunsxfsi (a)
#include <limits.h>
USItype
-__fixunsdfsi (a)
- DFtype a;
+__fixunsdfsi (DFtype a)
{
if (a >= - (DFtype) LONG_MIN)
return (SItype) (a + LONG_MIN) - LONG_MIN;
@@ -1176,9 +1155,7 @@ __fixunssfsi (SFtype a)
positive if S1 is greater, 0 if S1 and S2 are equal. */
int
-__gcc_bcmp (s1, s2, size)
- unsigned char *s1, *s2;
- size_t size;
+__gcc_bcmp (unsigned char *s1, unsigned char *s2, size_t size)
{
while (size > 0)
{
@@ -1192,6 +1169,11 @@ __gcc_bcmp (s1, s2, size)
#endif
+#ifdef L__dummy
+void
+__dummy () {}
+#endif
+
#ifdef L_varargs
#ifdef __i860__
#if defined(__svr4__) || defined(__alliant__)
@@ -1390,6 +1372,9 @@ asm ("___builtin_saveregs:");
#if defined(__MIPSEL__) | defined(__R3000__) | defined(__R2000__) | defined(__mips__)
asm (" .text");
+#ifdef __mips16
+ asm (" .set nomips16");
+#endif
asm (" .ent __builtin_saveregs");
asm (" .globl __builtin_saveregs");
asm ("__builtin_saveregs:");
@@ -1399,7 +1384,7 @@ asm ("___builtin_saveregs:");
asm (" sw $7,12($30)");
asm (" j $31");
asm (" .end __builtin_saveregs");
-#else /* not __mips__, etc. */
+#else /* not __mips__, etc. */
void *
__builtin_saveregs ()
@@ -1419,11 +1404,8 @@ __builtin_saveregs ()
#include <stdio.h>
/* This is used by the `assert' macro. */
void
-__eprintf (string, expression, line, filename)
- const char *string;
- const char *expression;
- int line;
- const char *filename;
+__eprintf (const char *string, const char *expression,
+ unsigned int line, const char *filename)
{
fprintf (stderr, string, expression, line, filename);
fflush (stderr);
@@ -1450,6 +1432,7 @@ struct bb
const char **functions;
const long *line_nums;
const char **filenames;
+ char *flags;
};
#ifdef BLOCK_PROFILER_CODE
@@ -1465,19 +1448,9 @@ BLOCK_PROFILER_CODE
#include <stdio.h>
char *ctime ();
-#ifdef HAVE_ATEXIT
-#ifdef WINNT
-extern int atexit (void (*) (void));
-#else
-extern void atexit (void (*) (void));
-#endif
-#define ON_EXIT(FUNC,ARG) atexit ((FUNC))
-#else
-#ifdef sun
-extern void on_exit (void*, void*);
-#define ON_EXIT(FUNC,ARG) on_exit ((FUNC), (ARG))
-#endif
-#endif
+#include "gbl-ctors.h"
+#include "gcov-io.h"
+#include <string.h>
static struct bb *bb_head;
@@ -1501,8 +1474,111 @@ static struct bb *bb_head;
void
__bb_exit_func (void)
{
- FILE *file = fopen ("bb.out", "a");
+ FILE *da_file, *file;
long time_value;
+ int i;
+
+ if (bb_head == 0)
+ return;
+
+ i = strlen (bb_head->filename) - 3;
+
+ if (!strcmp (bb_head->filename+i, ".da"))
+ {
+ /* Must be -fprofile-arcs not -a.
+ Dump data in a form that gcov expects. */
+
+ struct bb *ptr;
+
+ for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
+ {
+ /* If the file exists, and the number of counts in it is the same,
+ then merge them in. */
+
+ if ((da_file = fopen (ptr->filename, "r")) != 0)
+ {
+ long n_counts = 0;
+
+ if (__read_long (&n_counts, da_file, 8) != 0)
+ {
+ fprintf (stderr, "arc profiling: Can't read output file %s.\n",
+ ptr->filename);
+ continue;
+ }
+
+ if (n_counts == ptr->ncounts)
+ {
+ int i;
+
+ for (i = 0; i < n_counts; i++)
+ {
+ long v = 0;
+
+ if (__read_long (&v, da_file, 8) != 0)
+ {
+ fprintf (stderr, "arc profiling: Can't read output file %s.\n",
+ ptr->filename);
+ break;
+ }
+ ptr->counts[i] += v;
+ }
+ }
+
+ if (fclose (da_file) == EOF)
+ fprintf (stderr, "arc profiling: Error closing output file %s.\n",
+ ptr->filename);
+ }
+ if ((da_file = fopen (ptr->filename, "w")) == 0)
+ {
+ fprintf (stderr, "arc profiling: Can't open output file %s.\n",
+ ptr->filename);
+ continue;
+ }
+
+ /* ??? Should first write a header to the file. Preferably, a 4 byte
+ magic number, 4 bytes containing the time the program was
+ compiled, 4 bytes containing the last modification time of the
+ source file, and 4 bytes indicating the compiler options used.
+
+ That way we can easily verify that the proper source/executable/
+ data file combination is being used from gcov. */
+
+ if (__write_long (ptr->ncounts, da_file, 8) != 0)
+ {
+
+ fprintf (stderr, "arc profiling: Error writing output file %s.\n",
+ ptr->filename);
+ }
+ else
+ {
+ int j;
+ long *count_ptr = ptr->counts;
+ int ret = 0;
+ for (j = ptr->ncounts; j > 0; j--)
+ {
+ if (__write_long (*count_ptr, da_file, 8) != 0)
+ {
+ ret=1;
+ break;
+ }
+ count_ptr++;
+ }
+ if (ret)
+ fprintf (stderr, "arc profiling: Error writing output file %s.\n",
+ ptr->filename);
+ }
+
+ if (fclose (da_file) == EOF)
+ fprintf (stderr, "arc profiling: Error closing output file %s.\n",
+ ptr->filename);
+ }
+
+ return;
+ }
+
+ /* Must be basic block profiling. Emit a human readable output file. */
+
+ file = fopen ("bb.out", "a");
if (!file)
perror ("bb.out");
@@ -1513,22 +1589,25 @@ __bb_exit_func (void)
/* This is somewhat type incorrect, but it avoids worrying about
exactly where time.h is included from. It should be ok unless
- a void * differs from other pointer formats, or if sizeof(long)
+ a void * differs from other pointer formats, or if sizeof (long)
is < sizeof (time_t). It would be nice if we could assume the
use of rationale standards here. */
- time((void *) &time_value);
+ time ((void *) &time_value);
fprintf (file, "Basic block profiling finished on %s\n", ctime ((void *) &time_value));
/* We check the length field explicitly in order to allow compatibility
with older GCC's which did not provide it. */
- for (ptr = bb_head; ptr != (struct bb *)0; ptr = ptr->next)
+ for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
{
int i;
- int func_p = (ptr->nwords >= sizeof (struct bb) && ptr->nwords <= 1000);
+ int func_p = (ptr->nwords >= sizeof (struct bb)
+ && ptr->nwords <= 1000
+ && ptr->functions);
int line_p = (func_p && ptr->line_nums);
int file_p = (func_p && ptr->filenames);
+ int addr_p = (ptr->addresses != 0);
long ncounts = ptr->ncounts;
long cnt_max = 0;
long line_max = 0;
@@ -1552,7 +1631,7 @@ __bb_exit_func (void)
if (cnt_max < ptr->counts[i])
cnt_max = ptr->counts[i];
- if (addr_max < ptr->addresses[i])
+ if (addr_p && addr_max < ptr->addresses[i])
addr_max = ptr->addresses[i];
if (line_p && line_max < ptr->line_nums[i])
@@ -1583,10 +1662,13 @@ __bb_exit_func (void)
for (i = 0; i < ncounts; i++)
{
fprintf (file,
- " Block #%*d: executed %*ld time(s) address= 0x%.*lx",
+ " Block #%*d: executed %*ld time(s)",
blk_len, i+1,
- cnt_len, ptr->counts[i],
- addr_len, ptr->addresses[i]);
+ cnt_len, ptr->counts[i]);
+
+ if (addr_p)
+ fprintf (file, " address= 0x%.*lx", addr_len,
+ ptr->addresses[i]);
if (func_p)
fprintf (file, " function= %-*s", func_len,
@@ -1615,7 +1697,7 @@ void
__bb_init_func (struct bb *blocks)
{
/* User is supposed to check whether the first word is non-0,
- but just in case.... */
+ but just in case.... */
if (blocks->zero_word)
return;
@@ -1632,160 +1714,729 @@ __bb_init_func (struct bb *blocks)
bb_head = blocks;
}
-#endif /* not inhibit_libc */
-#endif /* not BLOCK_PROFILER_CODE */
-#endif /* L_bb */
-
-/* Default free-store management functions for C++, per sections 12.5 and
- 17.3.3 of the Working Paper. */
+#ifndef MACHINE_STATE_SAVE
+#define MACHINE_STATE_SAVE(ID)
+#endif
+#ifndef MACHINE_STATE_RESTORE
+#define MACHINE_STATE_RESTORE(ID)
+#endif
-#ifdef L_op_new
-/* operator new (size_t), described in 17.3.3.5. This function is used by
- C++ programs to allocate a block of memory to hold a single object. */
+/* Number of buckets in hashtable of basic block addresses. */
-typedef void (*vfp)(void);
-extern vfp __new_handler;
-extern void __default_new_handler (void);
+#define BB_BUCKETS 311
-#ifdef WEAK_ALIAS
-void * __builtin_new (size_t sz)
- __attribute__ ((weak, alias ("___builtin_new")));
-void *
-___builtin_new (size_t sz)
-#else
-void *
-__builtin_new (size_t sz)
-#endif
+/* Maximum length of string in file bb.in. */
+
+#define BBINBUFSIZE 500
+
+/* BBINBUFSIZE-1 with double quotes. We could use #BBINBUFSIZE or
+ "BBINBUFSIZE" but want to avoid trouble with preprocessors. */
+
+#define BBINBUFSIZESTR "499"
+
+struct bb_edge
{
- void *p;
- vfp handler = (__new_handler) ? __new_handler : __default_new_handler;
+ struct bb_edge *next;
+ unsigned long src_addr;
+ unsigned long dst_addr;
+ unsigned long count;
+};
- /* malloc (0) is unpredictable; avoid it. */
- if (sz == 0)
- sz = 1;
- p = (void *) malloc (sz);
- while (p == 0)
+enum bb_func_mode
+{
+ TRACE_KEEP = 0, TRACE_ON = 1, TRACE_OFF = 2
+};
+
+struct bb_func
+{
+ struct bb_func *next;
+ char *funcname;
+ char *filename;
+ enum bb_func_mode mode;
+};
+
+/* This is the connection to the outside world.
+ The BLOCK_PROFILER macro must set __bb.blocks
+ and __bb.blockno. */
+
+struct {
+ unsigned long blockno;
+ struct bb *blocks;
+} __bb;
+
+/* Vars to store addrs of source and destination basic blocks
+ of a jump. */
+
+static unsigned long bb_src = 0;
+static unsigned long bb_dst = 0;
+
+static FILE *bb_tracefile = (FILE *) 0;
+static struct bb_edge **bb_hashbuckets = (struct bb_edge **) 0;
+static struct bb_func *bb_func_head = (struct bb_func *) 0;
+static unsigned long bb_callcount = 0;
+static int bb_mode = 0;
+
+static unsigned long *bb_stack = (unsigned long *) 0;
+static size_t bb_stacksize = 0;
+
+static int reported = 0;
+
+/* Trace modes:
+Always : Print execution frequencies of basic blocks
+ to file bb.out.
+bb_mode & 1 != 0 : Dump trace of basic blocks to file bbtrace[.gz]
+bb_mode & 2 != 0 : Print jump frequencies to file bb.out.
+bb_mode & 4 != 0 : Cut call instructions from basic block flow.
+bb_mode & 8 != 0 : Insert return instructions in basic block flow.
+*/
+
+#ifdef HAVE_POPEN
+
+/*#include <sys/types.h>*/
+#include <sys/stat.h>
+/*#include <malloc.h>*/
+
+/* Commands executed by gopen. */
+
+#define GOPENDECOMPRESS "gzip -cd "
+#define GOPENCOMPRESS "gzip -c >"
+
+/* Like fopen but pipes through gzip. mode may only be "r" or "w".
+ If it does not compile, simply replace gopen by fopen and delete
+ '.gz' from any first parameter to gopen. */
+
+static FILE *
+gopen (char *fn, char *mode)
+{
+ int use_gzip;
+ char *p;
+
+ if (mode[1])
+ return (FILE *) 0;
+
+ if (mode[0] != 'r' && mode[0] != 'w')
+ return (FILE *) 0;
+
+ p = fn + strlen (fn)-1;
+ use_gzip = ((p[-1] == '.' && (p[0] == 'Z' || p[0] == 'z'))
+ || (p[-2] == '.' && p[-1] == 'g' && p[0] == 'z'));
+
+ if (use_gzip)
{
- (*handler) ();
- p = (void *) malloc (sz);
+ if (mode[0]=='r')
+ {
+ FILE *f;
+ char *s = (char *) malloc (sizeof (char) * strlen (fn)
+ + sizeof (GOPENDECOMPRESS));
+ strcpy (s, GOPENDECOMPRESS);
+ strcpy (s + (sizeof (GOPENDECOMPRESS)-1), fn);
+ f = popen (s, mode);
+ free (s);
+ return f;
+ }
+
+ else
+ {
+ FILE *f;
+ char *s = (char *) malloc (sizeof (char) * strlen (fn)
+ + sizeof (GOPENCOMPRESS));
+ strcpy (s, GOPENCOMPRESS);
+ strcpy (s + (sizeof (GOPENCOMPRESS)-1), fn);
+ if (!(f = popen (s, mode)))
+ f = fopen (s, mode);
+ free (s);
+ return f;
+ }
}
-
- return p;
+
+ else
+ return fopen (fn, mode);
}
-#endif /* L_op_new */
-#ifdef L_op_vnew
-/* void * operator new [] (size_t), described in 17.3.3.6. This function
- is used by C++ programs to allocate a block of memory for an array. */
+static int
+gclose (FILE *f)
+{
+ struct stat buf;
-extern void * __builtin_new (size_t);
+ if (f != 0)
+ {
+ if (!fstat (fileno (f), &buf) && S_ISFIFO (buf.st_mode))
+ return pclose (f);
-#ifdef WEAK_ALIAS
-void * __builtin_vec_new (size_t sz)
- __attribute__ ((weak, alias ("___builtin_vec_new")));
-void *
-___builtin_vec_new (size_t sz)
-#else
-void *
-__builtin_vec_new (size_t sz)
-#endif
+ return fclose (f);
+ }
+ return 0;
+}
+
+#endif /* HAVE_POPEN */
+
+/* Called once per program. */
+
+static void
+__bb_exit_trace_func ()
{
- return __builtin_new (sz);
+ FILE *file = fopen ("bb.out", "a");
+ struct bb_func *f;
+ struct bb *b;
+
+ if (!file)
+ perror ("bb.out");
+
+ if (bb_mode & 1)
+ {
+ if (!bb_tracefile)
+ perror ("bbtrace");
+ else
+#ifdef HAVE_POPEN
+ gclose (bb_tracefile);
+#else
+ fclose (bb_tracefile);
+#endif /* HAVE_POPEN */
+ }
+
+ /* Check functions in `bb.in'. */
+
+ if (file)
+ {
+ long time_value;
+ const struct bb_func *p;
+ int printed_something = 0;
+ struct bb *ptr;
+ long blk;
+
+ /* This is somewhat type incorrect. */
+ time ((void *) &time_value);
+
+ for (p = bb_func_head; p != (struct bb_func *) 0; p = p->next)
+ {
+ for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next)
+ {
+ if (!ptr->filename || (p->filename != (char *) 0 && strcmp (p->filename, ptr->filename)))
+ continue;
+ for (blk = 0; blk < ptr->ncounts; blk++)
+ {
+ if (!strcmp (p->funcname, ptr->functions[blk]))
+ goto found;
+ }
+ }
+
+ if (!printed_something)
+ {
+ fprintf (file, "Functions in `bb.in' not executed during basic block profiling on %s\n", ctime ((void *) &time_value));
+ printed_something = 1;
+ }
+
+ fprintf (file, "\tFunction %s", p->funcname);
+ if (p->filename)
+ fprintf (file, " of file %s", p->filename);
+ fprintf (file, "\n" );
+
+found: ;
+ }
+
+ if (printed_something)
+ fprintf (file, "\n");
+
+ }
+
+ if (bb_mode & 2)
+ {
+ if (!bb_hashbuckets)
+ {
+ if (!reported)
+ {
+ fprintf (stderr, "Profiler: out of memory\n");
+ reported = 1;
+ }
+ return;
+ }
+
+ else if (file)
+ {
+ long time_value;
+ int i;
+ unsigned long addr_max = 0;
+ unsigned long cnt_max = 0;
+ int cnt_len;
+ int addr_len;
+
+ /* This is somewhat type incorrect, but it avoids worrying about
+ exactly where time.h is included from. It should be ok unless
+ a void * differs from other pointer formats, or if sizeof (long)
+ is < sizeof (time_t). It would be nice if we could assume the
+ use of rationale standards here. */
+
+ time ((void *) &time_value);
+ fprintf (file, "Basic block jump tracing");
+
+ switch (bb_mode & 12)
+ {
+ case 0:
+ fprintf (file, " (with call)");
+ break;
+
+ case 4:
+ /* Print nothing. */
+ break;
+
+ case 8:
+ fprintf (file, " (with call & ret)");
+ break;
+
+ case 12:
+ fprintf (file, " (with ret)");
+ break;
+ }
+
+ fprintf (file, " finished on %s\n", ctime ((void *) &time_value));
+
+ for (i = 0; i < BB_BUCKETS; i++)
+ {
+ struct bb_edge *bucket = bb_hashbuckets[i];
+ for ( ; bucket; bucket = bucket->next )
+ {
+ if (addr_max < bucket->src_addr)
+ addr_max = bucket->src_addr;
+ if (addr_max < bucket->dst_addr)
+ addr_max = bucket->dst_addr;
+ if (cnt_max < bucket->count)
+ cnt_max = bucket->count;
+ }
+ }
+ addr_len = num_digits (addr_max, 16);
+ cnt_len = num_digits (cnt_max, 10);
+
+ for ( i = 0; i < BB_BUCKETS; i++)
+ {
+ struct bb_edge *bucket = bb_hashbuckets[i];
+ for ( ; bucket; bucket = bucket->next )
+ {
+ fprintf (file, "Jump from block 0x%.*lx to "
+ "block 0x%.*lx executed %*lu time(s)\n",
+ addr_len, bucket->src_addr,
+ addr_len, bucket->dst_addr,
+ cnt_len, bucket->count);
+ }
+ }
+
+ fprintf (file, "\n");
+
+ }
+ }
+
+ if (file)
+ fclose (file);
+
+ /* Free allocated memory. */
+
+ f = bb_func_head;
+ while (f)
+ {
+ struct bb_func *old = f;
+
+ f = f->next;
+ if (old->funcname) free (old->funcname);
+ if (old->filename) free (old->filename);
+ free (old);
+ }
+
+ if (bb_stack)
+ free (bb_stack);
+
+ if (bb_hashbuckets)
+ {
+ int i;
+
+ for (i = 0; i < BB_BUCKETS; i++)
+ {
+ struct bb_edge *old, *bucket = bb_hashbuckets[i];
+
+ while (bucket)
+ {
+ old = bucket;
+ bucket = bucket->next;
+ free (old);
+ }
+ }
+ free (bb_hashbuckets);
+ }
+
+ for (b = bb_head; b; b = b->next)
+ if (b->flags) free (b->flags);
}
-#endif /* L_op_vnew */
-#ifdef L_new_handler
-/* set_new_handler (fvoid_t *) and the default new handler, described in
- 17.3.3.2 and 17.3.3.5. These functions define the result of a failure
- to allocate the amount of memory requested from operator new or new []. */
+/* Called once per program. */
-#ifndef inhibit_libc
-/* This gets us __GNU_LIBRARY__. */
-#undef NULL /* Avoid errors if stdio.h and our stddef.h mismatch. */
-#include <stdio.h>
+static void
+__bb_init_prg ()
+{
-#ifdef __GNU_LIBRARY__
- /* Avoid forcing the library's meaning of `write' on the user program
- by using the "internal" name (for use within the library) */
-#define write(fd, buf, n) __write((fd), (buf), (n))
+ FILE *file;
+ char buf[BBINBUFSIZE];
+ const char *p;
+ const char *pos;
+ enum bb_func_mode m;
+
+#ifdef ON_EXIT
+ /* Initialize destructor. */
+ ON_EXIT (__bb_exit_func, 0);
#endif
-#endif /* inhibit_libc */
-typedef void (*vfp)(void);
-void __default_new_handler (void);
+ if (!(file = fopen ("bb.in", "r")))
+ return;
+
+ while(fscanf (file, " %" BBINBUFSIZESTR "s ", buf) != EOF)
+ {
+ p = buf;
+ if (*p == '-')
+ {
+ m = TRACE_OFF;
+ p++;
+ }
+ else
+ {
+ m = TRACE_ON;
+ }
+ if (!strcmp (p, "__bb_trace__"))
+ bb_mode |= 1;
+ else if (!strcmp (p, "__bb_jumps__"))
+ bb_mode |= 2;
+ else if (!strcmp (p, "__bb_hidecall__"))
+ bb_mode |= 4;
+ else if (!strcmp (p, "__bb_showret__"))
+ bb_mode |= 8;
+ else
+ {
+ struct bb_func *f = (struct bb_func *) malloc (sizeof (struct bb_func));
+ if (f)
+ {
+ unsigned long l;
+ f->next = bb_func_head;
+ if ((pos = strchr (p, ':')))
+ {
+ if (!(f->funcname = (char *) malloc (strlen (pos+1)+1)))
+ continue;
+ strcpy (f->funcname, pos+1);
+ l = pos-p;
+ if ((f->filename = (char *) malloc (l+1)))
+ {
+ strncpy (f->filename, p, l);
+ f->filename[l] = '\0';
+ }
+ else
+ f->filename = (char *) 0;
+ }
+ else
+ {
+ if (!(f->funcname = (char *) malloc (strlen (p)+1)))
+ continue;
+ strcpy (f->funcname, p);
+ f->filename = (char *) 0;
+ }
+ f->mode = m;
+ bb_func_head = f;
+ }
+ }
+ }
+ fclose (file);
+
+#ifdef HAVE_POPEN
-vfp __new_handler = (vfp)0;
+ if (bb_mode & 1)
+ bb_tracefile = gopen ("bbtrace.gz", "w");
-vfp
-set_new_handler (vfp handler)
-{
- vfp prev_handler;
+#else
+
+ if (bb_mode & 1)
+ bb_tracefile = fopen ("bbtrace", "w");
+
+#endif /* HAVE_POPEN */
+
+ if (bb_mode & 2)
+ {
+ bb_hashbuckets = (struct bb_edge **)
+ malloc (BB_BUCKETS * sizeof (struct bb_edge *));
+ if (bb_hashbuckets)
+ memset (bb_hashbuckets, 0, BB_BUCKETS * sizeof (struct bb_edge *));
+ }
+
+ if (bb_mode & 12)
+ {
+ bb_stacksize = 10;
+ bb_stack = (unsigned long *) malloc (bb_stacksize * sizeof (*bb_stack));
+ }
+
+#ifdef ON_EXIT
+ /* Initialize destructor. */
+ ON_EXIT (__bb_exit_trace_func, 0);
+#endif
- prev_handler = __new_handler;
- if (handler == 0) handler = __default_new_handler;
- __new_handler = handler;
- return prev_handler;
}
-#define MESSAGE "Virtual memory exceeded in `new'\n"
+/* Called upon entering a basic block. */
void
-__default_new_handler ()
+__bb_trace_func ()
{
-#ifndef inhibit_libc
- /* don't use fprintf (stderr, ...) because it may need to call malloc. */
- /* This should really print the name of the program, but that is hard to
- do. We need a standard, clean way to get at the name. */
- write (2, MESSAGE, sizeof (MESSAGE));
-#endif
- /* don't call exit () because that may call global destructors which
- may cause a loop. */
- _exit (-1);
+ struct bb_edge *bucket;
+
+ MACHINE_STATE_SAVE("1")
+
+ if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
+ goto skip;
+
+ bb_dst = __bb.blocks->addresses[__bb.blockno];
+ __bb.blocks->counts[__bb.blockno]++;
+
+ if (bb_tracefile)
+ {
+ fwrite (&bb_dst, sizeof (unsigned long), 1, bb_tracefile);
+ }
+
+ if (bb_hashbuckets)
+ {
+ struct bb_edge **startbucket, **oldnext;
+
+ oldnext = startbucket
+ = & bb_hashbuckets[ (((int) bb_src*8) ^ (int) bb_dst) % BB_BUCKETS ];
+ bucket = *startbucket;
+
+ for (bucket = *startbucket; bucket;
+ oldnext = &(bucket->next), bucket = *oldnext)
+ {
+ if (bucket->src_addr == bb_src
+ && bucket->dst_addr == bb_dst)
+ {
+ bucket->count++;
+ *oldnext = bucket->next;
+ bucket->next = *startbucket;
+ *startbucket = bucket;
+ goto ret;
+ }
+ }
+
+ bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
+
+ if (!bucket)
+ {
+ if (!reported)
+ {
+ fprintf (stderr, "Profiler: out of memory\n");
+ reported = 1;
+ }
+ }
+
+ else
+ {
+ bucket->src_addr = bb_src;
+ bucket->dst_addr = bb_dst;
+ bucket->next = *startbucket;
+ *startbucket = bucket;
+ bucket->count = 1;
+ }
+ }
+
+ret:
+ bb_src = bb_dst;
+
+skip:
+ ;
+
+ MACHINE_STATE_RESTORE("1")
+
}
-#endif
-#ifdef L_op_delete
-/* operator delete (void *), described in 17.3.3.3. This function is used
- by C++ programs to return to the free store a block of memory allocated
- as a single object. */
+/* Called when returning from a function and `__bb_showret__' is set. */
-#ifdef WEAK_ALIAS
-void __builtin_delete (void *ptr)
- __attribute__ ((weak, alias ("___builtin_delete")));
-void
-___builtin_delete (void *ptr)
-#else
-void
-__builtin_delete (void *ptr)
-#endif
+static void
+__bb_trace_func_ret ()
{
- if (ptr)
- free (ptr);
+ struct bb_edge *bucket;
+
+ if (!bb_callcount || (__bb.blocks->flags && (__bb.blocks->flags[__bb.blockno] & TRACE_OFF)))
+ goto skip;
+
+ if (bb_hashbuckets)
+ {
+ struct bb_edge **startbucket, **oldnext;
+
+ oldnext = startbucket
+ = & bb_hashbuckets[ (((int) bb_dst * 8) ^ (int) bb_src) % BB_BUCKETS ];
+ bucket = *startbucket;
+
+ for (bucket = *startbucket; bucket;
+ oldnext = &(bucket->next), bucket = *oldnext)
+ {
+ if (bucket->src_addr == bb_dst
+ && bucket->dst_addr == bb_src)
+ {
+ bucket->count++;
+ *oldnext = bucket->next;
+ bucket->next = *startbucket;
+ *startbucket = bucket;
+ goto ret;
+ }
+ }
+
+ bucket = (struct bb_edge *) malloc (sizeof (struct bb_edge));
+
+ if (!bucket)
+ {
+ if (!reported)
+ {
+ fprintf (stderr, "Profiler: out of memory\n");
+ reported = 1;
+ }
+ }
+
+ else
+ {
+ bucket->src_addr = bb_dst;
+ bucket->dst_addr = bb_src;
+ bucket->next = *startbucket;
+ *startbucket = bucket;
+ bucket->count = 1;
+ }
+ }
+
+ret:
+ bb_dst = bb_src;
+
+skip:
+ ;
+
}
-#endif
-#ifdef L_op_vdel
-/* operator delete [] (void *), described in 17.3.3.4. This function is
- used by C++ programs to return to the free store a block of memory
- allocated as an array. */
+/* Called upon entering the first function of a file. */
+
+static void
+__bb_init_file (struct bb *blocks)
+{
-extern void __builtin_delete (void *);
+ const struct bb_func *p;
+ long blk, ncounts = blocks->ncounts;
+ const char **functions = blocks->functions;
+
+ /* Set up linked list. */
+ blocks->zero_word = 1;
+ blocks->next = bb_head;
+ bb_head = blocks;
+
+ blocks->flags = 0;
+ if (!bb_func_head
+ || !(blocks->flags = (char *) malloc (sizeof (char) * blocks->ncounts)))
+ return;
+
+ for (blk = 0; blk < ncounts; blk++)
+ blocks->flags[blk] = 0;
+
+ for (blk = 0; blk < ncounts; blk++)
+ {
+ for (p = bb_func_head; p; p = p->next)
+ {
+ if (!strcmp (p->funcname, functions[blk])
+ && (!p->filename || !strcmp (p->filename, blocks->filename)))
+ {
+ blocks->flags[blk] |= p->mode;
+ }
+ }
+ }
+
+}
+
+/* Called when exiting from a function. */
-#ifdef WEAK_ALIAS
-void __builtin_vec_delete (void *ptr)
- __attribute__ ((weak, alias ("___builtin_vec_delete")));
void
-___builtin_vec_delete (void *ptr)
-#else
+__bb_trace_ret ()
+{
+
+ MACHINE_STATE_SAVE("2")
+
+ if (bb_callcount)
+ {
+ if ((bb_mode & 12) && bb_stacksize > bb_callcount)
+ {
+ bb_src = bb_stack[bb_callcount];
+ if (bb_mode & 8)
+ __bb_trace_func_ret ();
+ }
+
+ bb_callcount -= 1;
+ }
+
+ MACHINE_STATE_RESTORE("2")
+
+}
+
+/* Called when entering a function. */
+
void
-__builtin_vec_delete (void *ptr)
-#endif
+__bb_init_trace_func (struct bb *blocks, unsigned long blockno)
{
- __builtin_delete (ptr);
+ static int trace_init = 0;
+
+ MACHINE_STATE_SAVE("3")
+
+ if (!blocks->zero_word)
+ {
+ if (!trace_init)
+ {
+ trace_init = 1;
+ __bb_init_prg ();
+ }
+ __bb_init_file (blocks);
+ }
+
+ if (bb_callcount)
+ {
+
+ bb_callcount += 1;
+
+ if (bb_mode & 12)
+ {
+ if (bb_callcount >= bb_stacksize)
+ {
+ size_t newsize = bb_callcount + 100;
+
+ bb_stack = (unsigned long *) realloc (bb_stack, newsize);
+ if (! bb_stack)
+ {
+ if (!reported)
+ {
+ fprintf (stderr, "Profiler: out of memory\n");
+ reported = 1;
+ }
+ bb_stacksize = 0;
+ goto stack_overflow;
+ }
+ bb_stacksize = newsize;
+ }
+ bb_stack[bb_callcount] = bb_src;
+
+ if (bb_mode & 4)
+ bb_src = 0;
+
+ }
+
+stack_overflow:;
+
+ }
+
+ else if (blocks->flags && (blocks->flags[blockno] & TRACE_ON))
+ {
+ bb_callcount = 1;
+ bb_src = 0;
+
+ if (bb_stack)
+ bb_stack[bb_callcount] = bb_src;
+ }
+
+ MACHINE_STATE_RESTORE("3")
}
-#endif
-/* End of C++ free-store management functions */
+#endif /* not inhibit_libc */
+#endif /* not BLOCK_PROFILER_CODE */
+#endif /* L_bb */
#ifdef L_shtab
unsigned int __shtab[] = {
@@ -1806,8 +2457,7 @@ unsigned int __shtab[] = {
#define INSN_CACHE_PLANE_SIZE (INSN_CACHE_SIZE / INSN_CACHE_DEPTH)
void
-__clear_cache (beg, end)
- char *beg, *end;
+__clear_cache (char *beg, char *end)
{
#ifdef CLEAR_INSN_CACHE
CLEAR_INSN_CACHE (beg, end);
@@ -1837,7 +2487,7 @@ __clear_cache (beg, end)
= JUMP_AHEAD_INSTRUCTION + INSN_CACHE_LINE_WIDTH;
ptr += INSN_CACHE_LINE_WIDTH;
}
- *(INSTRUCTION_TYPE *)(ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
+ *(INSTRUCTION_TYPE *) (ptr - INSN_CACHE_LINE_WIDTH) = RETURN_INSTRUCTION;
initialized = 1;
}
@@ -1919,7 +2569,7 @@ __clear_cache (beg, end)
/* Jump to a trampoline, loading the static chain address. */
-#ifdef WINNT
+#if defined(WINNT) && ! defined(__CYGWIN32__)
long getpagesize()
{
@@ -1930,24 +2580,32 @@ long getpagesize()
#endif
}
-int mprotect(addr, len, prot)
- char *addr;
- int len, prot;
+#ifdef i386
+extern int VirtualProtect (char *, int, int, int *) __attribute__((stdcall));
+#endif
+
+int
+mprotect (char *addr, int len, int prot)
{
int np, op;
- if (prot == 7) np = 0x40;
- else if (prot == 5) np = 0x20;
- else if (prot == 4) np = 0x10;
- else if (prot == 3) np = 0x04;
- else if (prot == 1) np = 0x02;
- else if (prot == 0) np = 0x01;
+ if (prot == 7)
+ np = 0x40;
+ else if (prot == 5)
+ np = 0x20;
+ else if (prot == 4)
+ np = 0x10;
+ else if (prot == 3)
+ np = 0x04;
+ else if (prot == 1)
+ np = 0x02;
+ else if (prot == 0)
+ np = 0x01;
if (VirtualProtect (addr, len, np, &op))
return 0;
else
return -1;
-
}
#endif
@@ -1967,8 +2625,7 @@ TRANSFER_FROM_TRAMPOLINE
#endif
void
-__enable_execute_stack (addr)
- char *addr;
+__enable_execute_stack (char *addr)
{
kern_return_t r;
char *eaddr = addr + TRAMPOLINE_SIZE;
@@ -2016,14 +2673,14 @@ __enable_execute_stack ()
lowest = current;
}
- /* Clear instruction cache in case an old trampoline is in it. */
+ /* Clear instruction cache in case an old trampoline is in it. */
asm ("pich");
}
#endif /* __convex__ */
-#ifdef __DOLPHIN__
+#ifdef __sysV88__
-/* Modified from the convex -code above. */
+/* Modified from the convex -code above. */
#include <sys/param.h>
#include <errno.h>
@@ -2051,7 +2708,52 @@ __enable_execute_stack ()
errno=save_errno;
}
-#endif /* __DOLPHIN__ */
+#endif /* __sysV88__ */
+
+#ifdef __sysV68__
+
+#include <sys/signal.h>
+#include <errno.h>
+
+/* Motorola forgot to put memctl.o in the libp version of libc881.a,
+ so define it here, because we need it in __clear_insn_cache below */
+/* On older versions of this OS, no memctl or MCT_TEXT are defined;
+ hence we enable this stuff only if MCT_TEXT is #define'd. */
+
+#ifdef MCT_TEXT
+asm("\n\
+ global memctl\n\
+memctl:\n\
+ movq &75,%d0\n\
+ trap &0\n\
+ bcc.b noerror\n\
+ jmp cerror%\n\
+noerror:\n\
+ movq &0,%d0\n\
+ rts");
+#endif
+
+/* Clear instruction cache so we can call trampolines on stack.
+ This is called from FINALIZE_TRAMPOLINE in mot3300.h. */
+
+void
+__clear_insn_cache ()
+{
+#ifdef MCT_TEXT
+ int save_errno;
+
+ /* Preserve errno, because users would be surprised to have
+ errno changing without explicitly calling any system-call. */
+ save_errno = errno;
+
+ /* Keep it simple : memctl (MCT_TEXT) always fully clears the insn cache.
+ No need to use an address derived from _start or %sp, as 0 works also. */
+ memctl(0, 4096, MCT_TEXT);
+ errno = save_errno;
+#endif
+}
+
+#endif /* __sysV68__ */
#ifdef __pyr__
@@ -2063,7 +2765,7 @@ __enable_execute_stack ()
#include <sys/vmmac.h>
/* Modified from the convex -code above.
- mremap promises to clear the i-cache. */
+ mremap promises to clear the i-cache. */
void
__enable_execute_stack ()
@@ -2078,21 +2780,52 @@ __enable_execute_stack ()
}
}
#endif /* __pyr__ */
+
+#if defined (sony_news) && defined (SYSTYPE_BSD)
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <syscall.h>
+#include <machine/sysnews.h>
+
+/* cacheflush function for NEWS-OS 4.2.
+ This function is called from trampoline-initialize code
+ defined in config/mips/mips.h. */
+
+void
+cacheflush (char *beg, int size, int flag)
+{
+ if (syscall (SYS_sysnews, NEWS_CACHEFLUSH, beg, size, FLUSH_BCACHE))
+ {
+ perror ("cache_flush");
+ fflush (stderr);
+ abort ();
+ }
+}
+
+#endif /* sony_news */
#endif /* L_trampoline */
+#ifndef __CYGWIN32__
#ifdef L__main
#include "gbl-ctors.h"
/* Some systems use __main in a way incompatible with its use in gcc, in these
cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN to
give the same symbol without quotes for an alternative entry point. You
- must define both, or neither. */
+ must define both, or neither. */
#ifndef NAME__MAIN
#define NAME__MAIN "__main"
#define SYMBOL__MAIN __main
#endif
-#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
+#ifdef INIT_SECTION_ASM_OP
+#undef HAS_INIT_SECTION
+#define HAS_INIT_SECTION
+#endif
+
+#if !defined (HAS_INIT_SECTION) || !defined (OBJECT_FORMAT_ELF)
/* Run all the global destructors on exit from the program. */
void
@@ -2101,14 +2834,17 @@ __do_global_dtors ()
#ifdef DO_GLOBAL_DTORS_BODY
DO_GLOBAL_DTORS_BODY;
#else
- func_ptr *p;
- for (p = __DTOR_LIST__ + 1; *p; )
- (*p++) ();
+ static func_ptr *p = __DTOR_LIST__ + 1;
+ while (*p)
+ {
+ p++;
+ (*(p-1)) ();
+ }
#endif
}
#endif
-#ifndef INIT_SECTION_ASM_OP
+#ifndef HAS_INIT_SECTION
/* Run all the global constructors on entry to the program. */
#ifndef ON_EXIT
@@ -2128,9 +2864,9 @@ __do_global_ctors ()
DO_GLOBAL_CTORS_BODY;
ON_EXIT (__do_global_dtors, 0);
}
-#endif /* no INIT_SECTION_ASM_OP */
+#endif /* no HAS_INIT_SECTION */
-#if !defined (INIT_SECTION_ASM_OP) || defined (INVOKE__main)
+#if !defined (HAS_INIT_SECTION) || defined (INVOKE__main)
/* Subroutine called automatically by `main'.
Compiling a global function named `main'
produces an automatic call to this function at the beginning.
@@ -2150,9 +2886,10 @@ SYMBOL__MAIN ()
__do_global_ctors ();
}
}
-#endif /* no INIT_SECTION_ASM_OP or INVOKE__main */
+#endif /* no HAS_INIT_SECTION or INVOKE__main */
#endif /* L__main */
+#endif /* __CYGWIN32__ */
#ifdef L_ctors
@@ -2181,23 +2918,83 @@ func_ptr __DTOR_LIST__[2];
#include "gbl-ctors.h"
+#ifdef NEED_ATEXIT
+# ifdef ON_EXIT
+# undef ON_EXIT
+# endif
+int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
+#endif
+
#ifndef ON_EXIT
+#ifdef NEED_ATEXIT
+# include <errno.h>
+
+static func_ptr *atexit_chain = 0;
+static long atexit_chain_length = 0;
+static volatile long last_atexit_chain_slot = -1;
+
+int atexit (func_ptr func)
+{
+ if (++last_atexit_chain_slot == atexit_chain_length)
+ {
+ atexit_chain_length += 32;
+ if (atexit_chain)
+ atexit_chain = (func_ptr *) realloc (atexit_chain, atexit_chain_length
+ * sizeof (func_ptr));
+ else
+ atexit_chain = (func_ptr *) malloc (atexit_chain_length
+ * sizeof (func_ptr));
+ if (! atexit_chain)
+ {
+ atexit_chain_length = 0;
+ last_atexit_chain_slot = -1;
+ errno = ENOMEM;
+ return (-1);
+ }
+ }
+ atexit_chain[last_atexit_chain_slot] = func;
+ return (0);
+}
+#endif /* NEED_ATEXIT */
+
/* If we have no known way of registering our own __do_global_dtors
routine so that it will be invoked at program exit time, then we
have to define our own exit routine which will get this to happen. */
extern void __do_global_dtors ();
+extern void __bb_exit_func ();
extern void _cleanup ();
extern void _exit () __attribute__ ((noreturn));
void
-exit (status)
- int status;
+exit (int status)
{
#if !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF)
+#ifdef NEED_ATEXIT
+ if (atexit_chain)
+ {
+ for ( ; last_atexit_chain_slot-- >= 0; )
+ {
+ (*atexit_chain[last_atexit_chain_slot + 1]) ();
+ atexit_chain[last_atexit_chain_slot + 1] = 0;
+ }
+ free (atexit_chain);
+ atexit_chain = 0;
+ }
+#else /* No NEED_ATEXIT */
__do_global_dtors ();
+#endif /* No NEED_ATEXIT */
+#endif /* !defined (INIT_SECTION_ASM_OP) || !defined (OBJECT_FORMAT_ELF) */
+/* In gbl-ctors.h, ON_EXIT is defined if HAVE_ATEXIT is defined. In
+ __bb_init_func and _bb_init_prg, __bb_exit_func is registered with
+ ON_EXIT if ON_EXIT is defined. Thus we must not call __bb_exit_func here
+ if HAVE_ATEXIT is defined. */
+#ifndef HAVE_ATEXIT
+#ifndef inhibit_libc
+ __bb_exit_func ();
#endif
+#endif /* !HAVE_ATEXIT */
#ifdef EXIT_BODY
EXIT_BODY;
#else
@@ -2206,245 +3003,775 @@ exit (status)
_exit (status);
}
-#else
+#else /* ON_EXIT defined */
int _exit_dummy_decl = 0; /* prevent compiler & linker warnings */
-#endif
+
+# ifndef HAVE_ATEXIT
+/* Provide a fake for atexit() using ON_EXIT. */
+int atexit (func_ptr func)
+{
+ return ON_EXIT (func, NULL);
+}
+# endif /* HAVE_ATEXIT */
+#endif /* ON_EXIT defined */
#endif /* L_exit */
#ifdef L_eh
-typedef struct {
- void *start;
- void *end;
- void *exception_handler;
-} exception_table;
-
-struct exception_table_node {
- exception_table *table;
- void *start;
- void *end;
- struct exception_table_node *next;
-};
-static int except_table_pos;
-static void *except_pc;
-static struct exception_table_node *exception_table_list;
+#include "gthr.h"
+
+/* Shared exception handling support routines. */
+
+void
+__default_terminate ()
+{
+ abort ();
+}
+
+void (*__terminate_func)() = __default_terminate;
+
+void
+__terminate ()
+{
+ (*__terminate_func)();
+}
+
+void *
+__throw_type_match (void *catch_type, void *throw_type, void *obj)
+{
+#if 0
+ printf ("__throw_type_match (): catch_type = %s, throw_type = %s\n",
+ catch_type, throw_type);
+#endif
+ if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
+ return obj;
+ return 0;
+}
+
+void
+__empty ()
+{
+}
+
+
+/* Include definitions of EH context and table layout */
+
+#include "eh-common.h"
+
+/* Allocate and return a new EH context structure. */
+
+extern void __throw ();
-static exception_table *
-find_exception_table (pc)
- void* pc;
+static void *
+new_eh_context ()
{
- register struct exception_table_node *table = exception_table_list;
- for ( ; table != 0; table = table->next)
+ struct eh_full_context {
+ struct eh_context c;
+ void *top_elt[2];
+ } *ehfc = (struct eh_full_context *) malloc (sizeof *ehfc);
+
+ if (! ehfc)
+ __terminate ();
+
+ memset (ehfc, 0, sizeof *ehfc);
+
+ ehfc->c.dynamic_handler_chain = (void **) ehfc->top_elt;
+
+ /* This should optimize out entirely. This should always be true,
+ but just in case it ever isn't, don't allow bogus code to be
+ generated. */
+
+ if ((void*)(&ehfc->c) != (void*)ehfc)
+ __terminate ();
+
+ return &ehfc->c;
+}
+
+#if __GTHREADS
+static __gthread_key_t eh_context_key;
+
+/* Destructor for struct eh_context. */
+static void
+eh_context_free (void *ptr)
+{
+ __gthread_key_dtor (eh_context_key, ptr);
+ if (ptr)
+ free (ptr);
+}
+#endif
+
+/* Pointer to function to return EH context. */
+
+static struct eh_context *eh_context_initialize ();
+static struct eh_context *eh_context_static ();
+#if __GTHREADS
+static struct eh_context *eh_context_specific ();
+#endif
+
+static struct eh_context *(*get_eh_context) () = &eh_context_initialize;
+
+/* Routine to get EH context.
+ This one will simply call the function pointer. */
+
+void *
+__get_eh_context ()
+{
+ return (void *) (*get_eh_context) ();
+}
+
+/* Get and set the language specific info pointer. */
+
+void **
+__get_eh_info ()
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ return &eh->info;
+}
+
+#if __GTHREADS
+static void
+eh_threads_initialize ()
+{
+ /* Try to create the key. If it fails, revert to static method,
+ otherwise start using thread specific EH contexts. */
+ if (__gthread_key_create (&eh_context_key, &eh_context_free) == 0)
+ get_eh_context = &eh_context_specific;
+ else
+ get_eh_context = &eh_context_static;
+}
+#endif /* no __GTHREADS */
+
+/* Initialize EH context.
+ This will be called only once, since we change GET_EH_CONTEXT
+ pointer to another routine. */
+
+static struct eh_context *
+eh_context_initialize ()
+{
+#if __GTHREADS
+
+ static __gthread_once_t once = __GTHREAD_ONCE_INIT;
+ /* Make sure that get_eh_context does not point to us anymore.
+ Some systems have dummy thread routines in their libc that
+ return a success (Solaris 2.6 for example). */
+ if (__gthread_once (&once, eh_threads_initialize) != 0
+ || get_eh_context == &eh_context_initialize)
{
- if (table->start <= pc && table->end > pc)
- return table->table;
+ /* Use static version of EH context. */
+ get_eh_context = &eh_context_static;
}
- return 0;
+
+#else /* no __GTHREADS */
+
+ /* Use static version of EH context. */
+ get_eh_context = &eh_context_static;
+
+#endif /* no __GTHREADS */
+
+ return (*get_eh_context) ();
}
-/* this routine takes a pc, and the address of the exception handler associated
- with the closest exception table handler entry associated with that PC,
- or 0 if there are no table entries the PC fits in. The algorithm works
- something like this:
+/* Return a static EH context. */
- while(current_entry exists) {
- if(current_entry.start < pc )
- current_entry = next_entry;
- else {
- if(prev_entry.start <= pc && prev_entry.end > pc) {
- save pointer to prev_entry;
- return prev_entry.exception_handler;
- }
- else return 0;
- }
- }
- return 0;
+static struct eh_context *
+eh_context_static ()
+{
+ static struct eh_context *eh;
+ if (! eh)
+ eh = new_eh_context ();
+ return eh;
+}
- Assuming a correctly sorted table (ascending order) this routine should
- return the tightest match...
+#if __GTHREADS
+/* Return a thread specific EH context. */
- In the advent of a tie, we have to give the last entry, as it represents
- an inner block.
- */
+static struct eh_context *
+eh_context_specific ()
+{
+ struct eh_context *eh;
+ eh = (struct eh_context *) __gthread_getspecific (eh_context_key);
+ if (! eh)
+ {
+ eh = new_eh_context ();
+ if (__gthread_setspecific (eh_context_key, (void *) eh) != 0)
+ __terminate ();
+ }
+ return eh;
+}
+#endif __GTHREADS
+
+/* Support routines for setjmp/longjmp exception handling. */
-void *
-__find_first_exception_table_match(pc)
-void *pc;
-{
- exception_table *table = find_exception_table (pc);
- int pos = 0;
- int best = 0;
- if (table == 0)
- return (void*)0;
-#if 0
- printf("find_first_exception_table_match(): pc = %x!\n",pc);
+/* Calls to __sjthrow are generated by the compiler when an exception
+ is raised when using the setjmp/longjmp exception handling codegen
+ method. */
+
+#ifdef DONT_USE_BUILTIN_SETJMP
+extern void longjmp (void *, int);
#endif
- except_pc = pc;
+/* Routine to get the head of the current thread's dynamic handler chain
+ use for exception handling. */
-#if 0
- /* We can't do this yet, as we don't know that the table is sorted. */
- do {
- ++pos;
- if (table[pos].start > except_pc)
- /* found the first table[pos].start > except_pc, so the previous
- entry better be the one we want! */
- break;
- } while(table[pos].exception_handler != (void*)-1);
-
- --pos;
- if (table[pos].start <= except_pc && table[pos].end > except_pc)
+void ***
+__get_dynamic_handler_chain ()
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ return &eh->dynamic_handler_chain;
+}
+
+/* This is used to throw an exception when the setjmp/longjmp codegen
+ method is used for exception handling.
+
+ We call __terminate if there are no handlers left. Otherwise we run the
+ cleanup actions off the dynamic cleanup stack, and pop the top of the
+ dynamic handler chain, and use longjmp to transfer back to the associated
+ handler. */
+
+void
+__sjthrow ()
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ void ***dhc = &eh->dynamic_handler_chain;
+ void *jmpbuf;
+ void (*func)(void *, int);
+ void *arg;
+ void ***cleanup;
+
+ /* The cleanup chain is one word into the buffer. Get the cleanup
+ chain. */
+ cleanup = (void***)&(*dhc)[1];
+
+ /* If there are any cleanups in the chain, run them now. */
+ if (cleanup[0])
{
- except_table_pos = pos;
-#if 0
- printf("find_first_eh_table_match(): found match: %x\n",table[pos].exception_handler);
+ double store[200];
+ void **buf = (void**)store;
+ buf[1] = 0;
+ buf[0] = (*dhc);
+
+ /* try { */
+#ifdef DONT_USE_BUILTIN_SETJMP
+ if (! setjmp (&buf[2]))
+#else
+ if (! __builtin_setjmp (&buf[2]))
#endif
- return table[pos].exception_handler;
+ {
+ *dhc = buf;
+ while (cleanup[0])
+ {
+ func = (void(*)(void*, int))cleanup[0][1];
+ arg = (void*)cleanup[0][2];
+
+ /* Update this before running the cleanup. */
+ cleanup[0] = (void **)cleanup[0][0];
+
+ (*func)(arg, 2);
+ }
+ *dhc = buf[0];
+ }
+ /* catch (...) */
+ else
+ {
+ __terminate ();
+ }
}
+
+ /* We must call terminate if we try and rethrow an exception, when
+ there is no exception currently active and when there are no
+ handlers left. */
+ if (! eh->info || (*dhc)[0] == 0)
+ __terminate ();
+
+ /* Find the jmpbuf associated with the top element of the dynamic
+ handler chain. The jumpbuf starts two words into the buffer. */
+ jmpbuf = &(*dhc)[2];
+
+ /* Then we pop the top element off the dynamic handler chain. */
+ *dhc = (void**)(*dhc)[0];
+
+ /* And then we jump to the handler. */
+
+#ifdef DONT_USE_BUILTIN_SETJMP
+ longjmp (jmpbuf, 1);
#else
- while (table[++pos].exception_handler != (void*)-1) {
- if (table[pos].start <= except_pc && table[pos].end > except_pc)
- {
- /* This can apply. Make sure it is better or as good as the previous
- best. */
- /* The best one ends first. */
- if (best == 0 || (table[pos].end <= table[best].end
- /* The best one starts last. */
- && table[pos].start >= table[best].start))
- best = pos;
- }
- }
- if (best != 0)
- return table[best].exception_handler;
+ __builtin_longjmp (jmpbuf, 1);
#endif
+}
-#if 0
- printf("find_first_eh_table_match(): else: returning NULL!\n");
+/* Run cleanups on the dynamic cleanup stack for the current dynamic
+ handler, then pop the handler off the dynamic handler stack, and
+ then throw. This is used to skip the first handler, and transfer
+ control to the next handler in the dynamic handler stack. */
+
+void
+__sjpopnthrow ()
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ void ***dhc = &eh->dynamic_handler_chain;
+ void (*func)(void *, int);
+ void *arg;
+ void ***cleanup;
+
+ /* The cleanup chain is one word into the buffer. Get the cleanup
+ chain. */
+ cleanup = (void***)&(*dhc)[1];
+
+ /* If there are any cleanups in the chain, run them now. */
+ if (cleanup[0])
+ {
+ double store[200];
+ void **buf = (void**)store;
+ buf[1] = 0;
+ buf[0] = (*dhc);
+
+ /* try { */
+#ifdef DONT_USE_BUILTIN_SETJMP
+ if (! setjmp (&buf[2]))
+#else
+ if (! __builtin_setjmp (&buf[2]))
#endif
- return (void*)0;
+ {
+ *dhc = buf;
+ while (cleanup[0])
+ {
+ func = (void(*)(void*, int))cleanup[0][1];
+ arg = (void*)cleanup[0][2];
+
+ /* Update this before running the cleanup. */
+ cleanup[0] = (void **)cleanup[0][0];
+
+ (*func)(arg, 2);
+ }
+ *dhc = buf[0];
+ }
+ /* catch (...) */
+ else
+ {
+ __terminate ();
+ }
+ }
+
+ /* Then we pop the top element off the dynamic handler chain. */
+ *dhc = (void**)(*dhc)[0];
+
+ __sjthrow ();
}
+
+/* Support code for all exception region-based exception handling. */
-void *
-__throw_type_match (void *catch_type, void *throw_type, void* obj)
+/* This value identifies the place from which an exception is being
+ thrown. */
+
+#ifdef EH_TABLE_LOOKUP
+
+EH_TABLE_LOOKUP
+
+#else
+
+#ifdef DWARF2_UNWIND_INFO
+
+
+/* Return the table version of an exception descriptor */
+
+short
+__get_eh_table_version (exception_descriptor *table)
{
-#if 0
- printf("__throw_type_match (): catch_type = %s, throw_type = %s\n",
- catch_type, throw_type);
-#endif
- if (strcmp ((const char *)catch_type, (const char *)throw_type) == 0)
- return obj;
- return 0;
+ return table->lang.version;
}
-void
-__register_exceptions (exception_table *table)
+/* Return the originating table language of an exception descriptor */
+
+short
+__get_eh_table_language (exception_descriptor *table)
{
- struct exception_table_node *node;
- exception_table *range = table + 1;
+ return table->lang.language;
+}
- if (range->start == (void*)-1)
- return;
+/* This routine takes a PC and a pointer to the exception region TABLE for
+ its translation unit, and returns the address of the exception handler
+ associated with the closest exception table handler entry associated
+ with that PC, or 0 if there are no table entries the PC fits in.
- node = (struct exception_table_node*)
- malloc (sizeof (struct exception_table_node));
- node->table = table;
+ In the advent of a tie, we have to give the last entry, as it represents
+ an inner block. */
- /* This look can be optimized away either if the table
- is sorted, or if we pass in extra parameters. */
- node->start = range->start;
- node->end = range->end;
- for (range++ ; range->start != (void*)(-1); range++)
+static void *
+old_find_exception_handler (void *pc, old_exception_table *table)
+{
+ if (table)
{
- if (range->start < node->start)
- node->start = range->start;
- if (range->end > node->end)
- node->end = range->end;
+ int pos;
+ int best = -1;
+
+ /* We can't do a binary search because the table isn't guaranteed
+ to be sorted from function to function. */
+ for (pos = 0; table[pos].start_region != (void *) -1; ++pos)
+ {
+ if (table[pos].start_region <= pc && table[pos].end_region > pc)
+ {
+ /* This can apply. Make sure it is at least as small as
+ the previous best. */
+ if (best == -1 || (table[pos].end_region <= table[best].end_region
+ && table[pos].start_region >= table[best].start_region))
+ best = pos;
+ }
+ /* But it is sorted by starting PC within a function. */
+ else if (best >= 0 && table[pos].start_region > pc)
+ break;
+ }
+ if (best != -1)
+ return table[best].exception_handler;
}
- node->next = exception_table_list;
- exception_table_list = node;
+ return (void *) 0;
}
-#if #machine(i386)
-void
-__unwind_function(void *ptr)
-{
- asm("movl 8(%esp),%ecx");
- /* Undo current frame */
- asm("movl %ebp,%esp");
- asm("popl %ebp");
- /* like ret, but stay here */
- asm("addl $4,%esp");
-
- /* Now, undo previous frame. */
- /* This is a test routine, as we have to dynamically probe to find out
- what to pop for certain, this is just a guess. */
- asm("leal -16(%ebp),%esp");
- asm("pop %ebx");
- asm("pop %esi");
- asm("pop %edi");
- asm("movl %ebp,%esp");
- asm("popl %ebp");
-
- asm("movl %ecx,0(%esp)");
- asm("ret");
-}
-#elif #machine(rs6000)
-__unwind_function(void *ptr)
-{
- asm("mr 31,1");
- asm("l 1,0(1)");
- asm("l 31,-4(1)");
- asm("# br");
-
- asm("mr 31,1");
- asm("l 1,0(1)");
- /* use 31 as a scratch register to restore the link register. */
- asm("l 31, 8(1);mtlr 31 # l lr,8(1)");
- asm("l 31,-4(1)");
- asm("# br");
- asm("mtctr 3;bctr # b 3");
-}
-#elif #machine(powerpc)
-__unwind_function(void *ptr)
-{
- asm("mr 31,1");
- asm("lwz 1,0(1)");
- asm("lwz 31,-4(1)");
- asm("# br");
-
- asm("mr 31,1");
- asm("lwz 1,0(1)");
- /* use 31 as a scratch register to restore the link register. */
- asm("lwz 31, 8(1);mtlr 31 # l lr,8(1)");
- asm("lwz 31,-4(1)");
- asm("# br");
- asm("mtctr 3;bctr # b 3");
-}
-#elif #machine(vax)
-__unwind_function(void *ptr)
-{
- __label__ return_again;
-
- /* Replace our frame's return address with the label below.
- During execution, we will first return here instead of to
- caller, then second return takes caller's frame off the stack.
- Two returns matches two actual calls, so is less likely to
- confuse debuggers. `16' corresponds to RETURN_ADDRESS_OFFSET. */
- __asm ("movl %0,16(fp)" : : "p" (&& return_again));
- return;
-
- return_again:
- return;
+static void *
+find_exception_handler (void *pc, exception_descriptor *table, void *eh_info)
+{
+ if (table)
+ {
+ /* The new model assumed the table is sorted inner-most out so the
+ first region we find which matches is the correct one */
+
+ int pos;
+ void *ret;
+ exception_table *tab = &(table->table[0]);
+
+ /* Subtract 1 from the PC to avoid hitting the next region */
+ pc--;
+
+ /* We can't do a binary search because the table is in inner-most
+ to outermost address ranges within functions */
+ for (pos = 0; tab[pos].start_region != (void *) -1; pos++)
+ {
+ if (tab[pos].start_region <= pc && tab[pos].end_region > pc)
+ {
+ if (tab[pos].match_info)
+ {
+ __eh_matcher matcher = ((__eh_info *)eh_info)->match_function;
+ /* match info but no matcher is NOT a match */
+ if (matcher)
+ {
+ ret = (*matcher)(eh_info, tab[pos].match_info, table);
+ if (ret)
+ return tab[pos].exception_handler;
+ }
+ }
+ else
+ return tab[pos].exception_handler;
+ }
+ }
+ }
+
+ return (void *) 0;
}
-#else
-__unwind_function(void *ptr)
+#endif /* DWARF2_UNWIND_INFO */
+#endif /* EH_TABLE_LOOKUP */
+
+#ifdef DWARF2_UNWIND_INFO
+/* Support code for exception handling using static unwind information. */
+
+#include "frame.h"
+
+/* This type is used in get_reg and put_reg to deal with ABIs where a void*
+ is smaller than a word, such as the Irix 6 n32 ABI. We cast twice to
+ avoid a warning about casting between int and pointer of different
+ sizes. */
+
+typedef int ptr_type __attribute__ ((mode (pointer)));
+
+/* Get the value of register REG as saved in UDATA, where SUB_UDATA is a
+ frame called by UDATA or 0. */
+
+static void*
+get_reg (unsigned reg, frame_state *udata, frame_state *sub_udata)
{
- abort ();
+ if (udata->saved[reg] == REG_SAVED_OFFSET)
+ return (void *)(ptr_type)
+ *(word_type *)(udata->cfa + udata->reg_or_offset[reg]);
+ else if (udata->saved[reg] == REG_SAVED_REG && sub_udata)
+ return get_reg (udata->reg_or_offset[reg], sub_udata, 0);
+ else
+ abort ();
+}
+
+/* Overwrite the saved value for register REG in frame UDATA with VAL. */
+
+static void
+put_reg (unsigned reg, void *val, frame_state *udata)
+{
+ if (udata->saved[reg] == REG_SAVED_OFFSET)
+ *(word_type *)(udata->cfa + udata->reg_or_offset[reg])
+ = (word_type)(ptr_type) val;
+ else
+ abort ();
+}
+
+/* Copy the saved value for register REG from frame UDATA to frame
+ TARGET_UDATA. Unlike the previous two functions, this can handle
+ registers that are not one word large. */
+
+static void
+copy_reg (unsigned reg, frame_state *udata, frame_state *target_udata)
+{
+ if (udata->saved[reg] == REG_SAVED_OFFSET
+ && target_udata->saved[reg] == REG_SAVED_OFFSET)
+ memcpy (target_udata->cfa + target_udata->reg_or_offset[reg],
+ udata->cfa + udata->reg_or_offset[reg],
+ __builtin_dwarf_reg_size (reg));
+ else
+ abort ();
+}
+
+/* Retrieve the return address for frame UDATA, where SUB_UDATA is a
+ frame called by UDATA or 0. */
+
+static inline void *
+get_return_addr (frame_state *udata, frame_state *sub_udata)
+{
+ return __builtin_extract_return_addr
+ (get_reg (udata->retaddr_column, udata, sub_udata));
+}
+
+/* Overwrite the return address for frame UDATA with VAL. */
+
+static inline void
+put_return_addr (void *val, frame_state *udata)
+{
+ val = __builtin_frob_return_addr (val);
+ put_reg (udata->retaddr_column, val, udata);
+}
+
+/* Given the current frame UDATA and its return address PC, return the
+ information about the calling frame in CALLER_UDATA. */
+
+static void *
+next_stack_level (void *pc, frame_state *udata, frame_state *caller_udata)
+{
+ caller_udata = __frame_state_for (pc, caller_udata);
+ if (! caller_udata)
+ return 0;
+
+ /* Now go back to our caller's stack frame. If our caller's CFA register
+ was saved in our stack frame, restore it; otherwise, assume the CFA
+ register is SP and restore it to our CFA value. */
+ if (udata->saved[caller_udata->cfa_reg])
+ caller_udata->cfa = get_reg (caller_udata->cfa_reg, udata, 0);
+ else
+ caller_udata->cfa = udata->cfa;
+ caller_udata->cfa += caller_udata->cfa_offset;
+
+ return caller_udata;
+}
+
+#ifdef INCOMING_REGNO
+/* Is the saved value for register REG in frame UDATA stored in a register
+ window in the previous frame? */
+
+static int
+in_reg_window (int reg, frame_state *udata)
+{
+ if (udata->saved[reg] != REG_SAVED_OFFSET)
+ return 0;
+
+#ifdef STACK_GROWS_DOWNWARD
+ return udata->reg_or_offset[reg] > 0;
+#else
+ return udata->reg_or_offset[reg] < 0;
+#endif
+}
+#endif /* INCOMING_REGNO */
+
+/* We first search for an exception handler, and if we don't find
+ it, we call __terminate on the current stack frame so that we may
+ use the debugger to walk the stack and understand why no handler
+ was found.
+
+ If we find one, then we unwind the frames down to the one that
+ has the handler and transfer control into the handler. */
+
+void
+__throw ()
+{
+ struct eh_context *eh = (*get_eh_context) ();
+ void *saved_pc, *pc, *handler, *retaddr;
+ frame_state ustruct, ustruct2;
+ frame_state *udata = &ustruct;
+ frame_state *sub_udata = &ustruct2;
+ frame_state my_ustruct, *my_udata = &my_ustruct;
+ long args_size;
+ int new_exception_model;
+
+ /* This is required for C++ semantics. We must call terminate if we
+ try and rethrow an exception, when there is no exception currently
+ active. */
+ if (! eh->info)
+ __terminate ();
+
+ /* Start at our stack frame. */
+label:
+ udata = __frame_state_for (&&label, udata);
+ if (! udata)
+ __terminate ();
+
+ /* We need to get the value from the CFA register. At this point in
+ compiling __throw we don't know whether or not we will use the frame
+ pointer register for the CFA, so we check our unwind info. */
+ if (udata->cfa_reg == __builtin_dwarf_fp_regnum ())
+ udata->cfa = __builtin_fp ();
+ else
+ udata->cfa = __builtin_sp ();
+ udata->cfa += udata->cfa_offset;
+
+ memcpy (my_udata, udata, sizeof (*udata));
+
+ /* Do any necessary initialization to access arbitrary stack frames.
+ On the SPARC, this means flushing the register windows. */
+ __builtin_unwind_init ();
+
+ /* Now reset pc to the right throw point. */
+ pc = __builtin_extract_return_addr (__builtin_return_address (0)) - 1;
+ saved_pc = pc;
+
+ handler = 0;
+ for (;;)
+ {
+ frame_state *p = udata;
+ udata = next_stack_level (pc, udata, sub_udata);
+ sub_udata = p;
+
+ /* If we couldn't find the next frame, we lose. */
+ if (! udata)
+ break;
+
+ if (udata->eh_ptr == NULL)
+ new_exception_model = 0;
+ else
+ new_exception_model = (((exception_descriptor *)(udata->eh_ptr))->
+ runtime_id_field == NEW_EH_RUNTIME);
+
+ if (new_exception_model)
+ handler = find_exception_handler (pc, udata->eh_ptr, eh->info);
+ else
+ handler = old_find_exception_handler (pc, udata->eh_ptr);
+
+ /* If we found one, we can stop searching. */
+ if (handler)
+ {
+ args_size = udata->args_size;
+ break;
+ }
+
+ /* Otherwise, we continue searching. We subtract 1 from PC to avoid
+ hitting the beginning of the next region. */
+ pc = get_return_addr (udata, sub_udata) - 1;
+ }
+
+ /* If we haven't found a handler by now, this is an unhandled
+ exception. */
+ if (! handler)
+ __terminate ();
+
+ eh->handler_label = handler;
+
+ if (pc == saved_pc)
+ /* We found a handler in the throw context, no need to unwind. */
+ udata = my_udata;
+ else
+ {
+ int i;
+
+ /* Unwind all the frames between this one and the handler by copying
+ their saved register values into our register save slots. */
+
+ /* Remember the PC where we found the handler. */
+ void *handler_pc = pc;
+
+ /* Start from the throw context again. */
+ pc = saved_pc;
+ memcpy (udata, my_udata, sizeof (*udata));
+
+ while (pc != handler_pc)
+ {
+ frame_state *p = udata;
+ udata = next_stack_level (pc, udata, sub_udata);
+ sub_udata = p;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
+ if (i != udata->retaddr_column && udata->saved[i])
+ {
+#ifdef INCOMING_REGNO
+ /* If you modify the saved value of the return address
+ register on the SPARC, you modify the return address for
+ your caller's frame. Don't do that here, as it will
+ confuse get_return_addr. */
+ if (in_reg_window (i, udata)
+ && udata->saved[udata->retaddr_column] == REG_SAVED_REG
+ && udata->reg_or_offset[udata->retaddr_column] == i)
+ continue;
+#endif
+ copy_reg (i, udata, my_udata);
+ }
+
+ pc = get_return_addr (udata, sub_udata) - 1;
+ }
+
+#ifdef INCOMING_REGNO
+ /* But we do need to update the saved return address register from
+ the last frame we unwind, or the handler frame will have the wrong
+ return address. */
+ if (udata->saved[udata->retaddr_column] == REG_SAVED_REG)
+ {
+ i = udata->reg_or_offset[udata->retaddr_column];
+ if (in_reg_window (i, udata))
+ copy_reg (i, udata, my_udata);
+ }
+#endif
+ }
+ /* udata now refers to the frame called by the handler frame. */
+
+ /* Emit the stub to adjust sp and jump to the handler. */
+ if (new_exception_model)
+ retaddr = __builtin_eh_stub ();
+ else
+ retaddr = __builtin_eh_stub_old ();
+
+ /* And then set our return address to point to the stub. */
+ if (my_udata->saved[my_udata->retaddr_column] == REG_SAVED_OFFSET)
+ put_return_addr (retaddr, my_udata);
+ else
+ __builtin_set_return_addr_reg (retaddr);
+
+ /* Set up the registers we use to communicate with the stub.
+ We check STACK_GROWS_DOWNWARD so the stub can use adjust_stack. */
+
+ if (new_exception_model)
+ __builtin_set_eh_regs ((void *)eh,
+#ifdef STACK_GROWS_DOWNWARD
+ udata->cfa - my_udata->cfa
+#else
+ my_udata->cfa - udata->cfa
+#endif
+ + args_size);
+ else
+ __builtin_set_eh_regs (handler,
+
+#ifdef STACK_GROWS_DOWNWARD
+ udata->cfa - my_udata->cfa
+#else
+ my_udata->cfa - udata->cfa
+#endif
+ + args_size);
+
+ /* Epilogue: restore the handler frame's register values and return
+ to the stub. */
}
-#endif /* powerpc */
+#endif /* DWARF2_UNWIND_INFO */
+
#endif /* L_eh */
#ifdef L_pure
diff --git a/contrib/gcc/listing b/contrib/gcc/listing
index 08abb1d..dc989f6 100755
--- a/contrib/gcc/listing
+++ b/contrib/gcc/listing
@@ -32,7 +32,7 @@
# mc68030 for Motorola 68030 (Sun-3, ..)
# sparc for SPARC (SUN-4, ..)
# i386 for i386 (Sun i386, ...)
-# i386-linux for i386 (Linux, ...)
+# i386-gnu-linux for i386 (GNU/Linux, ...)
# Guess what kind of objects we are creating and thus what type of assembler
# symbols to look for
@@ -62,7 +62,7 @@ cd $WD
# MYSYS=mc68030
# MYSYS=sparc
# MYSYS=i386
-# MYSYS=i386-linux
+# MYSYS=i386-gnu-linux
# MYSYS=`mach` # this will work on Suns with SunOS > 4.0.0
# MYSYS=elf
# MYSYS=coff
@@ -103,7 +103,7 @@ BEGIN {
line_delimiter = ",";
line_offset = 0;
}
- else if (sys == "mc68020" || sys == "mc68030" || sys == "i386-linux") {
+ else if (sys == "mc68020" || sys == "mc68030" || sys == "i386-gnu-linux") {
line_hint = "^[ \t]*\.stabd.*"
line_field = 3;
line_delimiter = ",";
diff --git a/contrib/gcc/local-alloc.c b/contrib/gcc/local-alloc.c
index 647b2d5..ee2ffe9 100644
--- a/contrib/gcc/local-alloc.c
+++ b/contrib/gcc/local-alloc.c
@@ -1,5 +1,5 @@
/* Allocate registers within a basic block, for GNU compiler.
- Copyright (C) 1987, 88, 91, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91, 93-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -55,28 +55,23 @@ Boston, MA 02111-1307, USA. */
But this is currently disabled since tying in global_alloc is not
yet implemented. */
-#include <stdio.h>
+/* Pseudos allocated here cannot be reallocated by global.c if the hard
+ register is used as a spill register. So we don't allocate such pseudos
+ here if their preferred class is likely to be used by spills. */
+
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "flags.h"
#include "basic-block.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "insn-config.h"
+#include "insn-attr.h"
#include "recog.h"
#include "output.h"
+#include "toplev.h"
-/* Pseudos allocated here cannot be reallocated by global.c if the hard
- register is used as a spill register. So we don't allocate such pseudos
- here if their preferred class is likely to be used by spills.
-
- On most machines, the appropriate test is if the class has one
- register, so we default to that. */
-
-#ifndef CLASS_LIKELY_SPILLED_P
-#define CLASS_LIKELY_SPILLED_P(CLASS) (reg_class_size[(int) (CLASS)] == 1)
-#endif
-
/* Next quantity number available for allocation. */
static int next_qty;
@@ -110,7 +105,7 @@ static HARD_REG_SET *qty_phys_sugg;
static short *qty_phys_num_copy_sugg;
-/* Element Q is the number of suggested registers in qty_phys_sugg. */
+/* Element Q is the number of suggested registers in qty_phys_sugg. */
static short *qty_phys_num_sugg;
@@ -242,24 +237,28 @@ static int scratch_index;
static int this_insn_number;
static rtx this_insn;
+/* Used to communicate changes made by update_equiv_regs to
+ memref_referenced_p. reg_equiv_replacement is set for any REG_EQUIV note
+ found or created, so that we can keep track of what memory accesses might
+ be created later, e.g. by reload. */
+
+static rtx *reg_equiv_replacement;
+
static void alloc_qty PROTO((int, enum machine_mode, int, int));
static void alloc_qty_for_scratch PROTO((rtx, int, rtx, int, int));
static void validate_equiv_mem_from_store PROTO((rtx, rtx));
static int validate_equiv_mem PROTO((rtx, rtx, rtx));
+static int contains_replace_regs PROTO((rtx, char *));
static int memref_referenced_p PROTO((rtx, rtx));
static int memref_used_between_p PROTO((rtx, rtx, rtx));
-static void optimize_reg_copy_1 PROTO((rtx, rtx, rtx));
-static void optimize_reg_copy_2 PROTO((rtx, rtx, rtx));
static void update_equiv_regs PROTO((void));
static void block_alloc PROTO((int));
static int qty_sugg_compare PROTO((int, int));
-static int qty_sugg_compare_1 PROTO((int *, int *));
+static int qty_sugg_compare_1 PROTO((const GENERIC_PTR, const GENERIC_PTR));
static int qty_compare PROTO((int, int));
-static int qty_compare_1 PROTO((int *, int *));
+static int qty_compare_1 PROTO((const GENERIC_PTR, const GENERIC_PTR));
static int combine_regs PROTO((rtx, rtx, int, int, rtx, int));
static int reg_meets_class_p PROTO((int, enum reg_class));
-static int reg_classes_overlap_p PROTO((enum reg_class, enum reg_class,
- int));
static void update_qty_class PROTO((int, int));
static void reg_is_set PROTO((rtx, rtx));
static void reg_is_born PROTO((rtx, int));
@@ -291,11 +290,11 @@ alloc_qty (regno, mode, size, birth)
qty_size[qty] = size;
qty_mode[qty] = mode;
qty_birth[qty] = birth;
- qty_n_calls_crossed[qty] = reg_n_calls_crossed[regno];
+ qty_n_calls_crossed[qty] = REG_N_CALLS_CROSSED (regno);
qty_min_class[qty] = reg_preferred_class (regno);
qty_alternate_class[qty] = reg_alternate_class (regno);
- qty_n_refs[qty] = reg_n_refs[regno];
- qty_changes_size[qty] = reg_changes_size[regno];
+ qty_n_refs[qty] = REG_N_REFS (regno);
+ qty_changes_size[qty] = REG_CHANGES_SIZE (regno);
}
/* Similar to `alloc_qty', but allocates a quantity for a SCRATCH rtx
@@ -449,13 +448,12 @@ local_alloc ()
qty_n_refs = (int *) alloca (max_qty * sizeof (int));
qty_changes_size = (char *) alloca (max_qty * sizeof (char));
- reg_qty = (int *) alloca (max_regno * sizeof (int));
- reg_offset = (char *) alloca (max_regno * sizeof (char));
- reg_next_in_qty = (int *) alloca (max_regno * sizeof (int));
+ reg_qty = (int *) xmalloc (max_regno * sizeof (int));
+ reg_offset = (char *) xmalloc (max_regno * sizeof (char));
+ reg_next_in_qty = (int *) xmalloc(max_regno * sizeof (int));
- reg_renumber = (short *) oballoc (max_regno * sizeof (short));
- for (i = 0; i < max_regno; i++)
- reg_renumber[i] = -1;
+ /* Allocate the reg_renumber array */
+ allocate_reg_info (max_regno, FALSE, TRUE);
/* Determine which pseudo-registers can be allocated by local-alloc.
In general, these are the registers used only in a single block and
@@ -469,7 +467,7 @@ local_alloc ()
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
{
- if (reg_basic_block[i] >= 0 && reg_n_deaths[i] == 1
+ if (REG_BASIC_BLOCK (i) >= 0 && REG_N_DEATHS (i) == 1
&& (reg_alternate_class (i) == NO_REGS
|| ! CLASS_LIKELY_SPILLED_P (reg_preferred_class (i))))
reg_qty[i] = -2;
@@ -521,6 +519,10 @@ local_alloc ()
alloca (0);
#endif
}
+
+ free (reg_qty);
+ free (reg_offset);
+ free (reg_next_in_qty);
}
/* Depth of loops we are in while in update_equiv_regs. */
@@ -544,7 +546,7 @@ validate_equiv_mem_from_store (dest, set)
if ((GET_CODE (dest) == REG
&& reg_overlap_mentioned_p (dest, equiv_mem))
|| (GET_CODE (dest) == MEM
- && true_dependence (dest, equiv_mem)))
+ && true_dependence (dest, VOIDmode, equiv_mem, rtx_varies_p)))
equiv_mem_modified = 1;
}
@@ -601,6 +603,55 @@ validate_equiv_mem (start, reg, memref)
return 0;
}
+
+/* TRUE if X uses any registers for which reg_equiv_replace is true. */
+
+static int
+contains_replace_regs (x, reg_equiv_replace)
+ rtx x;
+ char *reg_equiv_replace;
+{
+ int i, j;
+ char *fmt;
+ enum rtx_code code = GET_CODE (x);
+
+ switch (code)
+ {
+ case CONST_INT:
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST_DOUBLE:
+ case PC:
+ case CC0:
+ case HIGH:
+ case LO_SUM:
+ return 0;
+
+ case REG:
+ return reg_equiv_replace[REGNO (x)];
+
+ default:
+ break;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ switch (fmt[i])
+ {
+ case 'e':
+ if (contains_replace_regs (XEXP (x, i), reg_equiv_replace))
+ return 1;
+ break;
+ case 'E':
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ if (contains_replace_regs (XVECEXP (x, i, j), reg_equiv_replace))
+ return 1;
+ break;
+ }
+
+ return 0;
+}
/* TRUE if X references a memory location that would be affected by a store
to MEMREF. */
@@ -616,7 +667,6 @@ memref_referenced_p (memref, x)
switch (code)
{
- case REG:
case CONST_INT:
case CONST:
case LABEL_REF:
@@ -628,8 +678,13 @@ memref_referenced_p (memref, x)
case LO_SUM:
return 0;
+ case REG:
+ return (reg_equiv_replacement[REGNO (x)]
+ && memref_referenced_p (memref,
+ reg_equiv_replacement[REGNO (x)]));
+
case MEM:
- if (true_dependence (memref, x))
+ if (true_dependence (memref, VOIDmode, x, rtx_varies_p))
return 1;
break;
@@ -645,6 +700,9 @@ memref_referenced_p (memref, x)
return 1;
return memref_referenced_p (memref, SET_SRC (x));
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -685,256 +743,6 @@ memref_used_between_p (memref, start, end)
return 0;
}
-/* INSN is a copy from SRC to DEST, both registers, and SRC does not die
- in INSN.
-
- Search forward to see if SRC dies before either it or DEST is modified,
- but don't scan past the end of a basic block. If so, we can replace SRC
- with DEST and let SRC die in INSN.
-
- This will reduce the number of registers live in that range and may enable
- DEST to be tied to SRC, thus often saving one register in addition to a
- register-register copy. */
-
-static void
-optimize_reg_copy_1 (insn, dest, src)
- rtx insn;
- rtx dest;
- rtx src;
-{
- rtx p, q;
- rtx note;
- rtx dest_death = 0;
- int sregno = REGNO (src);
- int dregno = REGNO (dest);
-
- if (sregno == dregno
-#ifdef SMALL_REGISTER_CLASSES
- /* We don't want to mess with hard regs if register classes are small. */
- || sregno < FIRST_PSEUDO_REGISTER || dregno < FIRST_PSEUDO_REGISTER
-#endif
- /* We don't see all updates to SP if they are in an auto-inc memory
- reference, so we must disallow this optimization on them. */
- || sregno == STACK_POINTER_REGNUM || dregno == STACK_POINTER_REGNUM)
- return;
-
- for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
- {
- if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
- || (GET_CODE (p) == NOTE
- && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
- || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
- break;
-
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
- continue;
-
- if (reg_set_p (src, p) || reg_set_p (dest, p)
- /* Don't change a USE of a register. */
- || (GET_CODE (PATTERN (p)) == USE
- && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
- break;
-
- /* See if all of SRC dies in P. This test is slightly more
- conservative than it needs to be. */
- if ((note = find_regno_note (p, REG_DEAD, sregno)) != 0
- && GET_MODE (XEXP (note, 0)) == GET_MODE (src))
- {
- int failed = 0;
- int length = 0;
- int d_length = 0;
- int n_calls = 0;
- int d_n_calls = 0;
-
- /* We can do the optimization. Scan forward from INSN again,
- replacing regs as we go. Set FAILED if a replacement can't
- be done. In that case, we can't move the death note for SRC.
- This should be rare. */
-
- /* Set to stop at next insn. */
- for (q = next_real_insn (insn);
- q != next_real_insn (p);
- q = next_real_insn (q))
- {
- if (reg_overlap_mentioned_p (src, PATTERN (q)))
- {
- /* If SRC is a hard register, we might miss some
- overlapping registers with validate_replace_rtx,
- so we would have to undo it. We can't if DEST is
- present in the insn, so fail in that combination
- of cases. */
- if (sregno < FIRST_PSEUDO_REGISTER
- && reg_mentioned_p (dest, PATTERN (q)))
- failed = 1;
-
- /* Replace all uses and make sure that the register
- isn't still present. */
- else if (validate_replace_rtx (src, dest, q)
- && (sregno >= FIRST_PSEUDO_REGISTER
- || ! reg_overlap_mentioned_p (src,
- PATTERN (q))))
- {
- /* We assume that a register is used exactly once per
- insn in the updates below. If this is not correct,
- no great harm is done. */
- if (sregno >= FIRST_PSEUDO_REGISTER)
- reg_n_refs[sregno] -= loop_depth;
- if (dregno >= FIRST_PSEUDO_REGISTER)
- reg_n_refs[dregno] += loop_depth;
- }
- else
- {
- validate_replace_rtx (dest, src, q);
- failed = 1;
- }
- }
-
- /* Count the insns and CALL_INSNs passed. If we passed the
- death note of DEST, show increased live length. */
- length++;
- if (dest_death)
- d_length++;
-
- /* If the insn in which SRC dies is a CALL_INSN, don't count it
- as a call that has been crossed. Otherwise, count it. */
- if (q != p && GET_CODE (q) == CALL_INSN)
- {
- n_calls++;
- if (dest_death)
- d_n_calls++;
- }
-
- /* If DEST dies here, remove the death note and save it for
- later. Make sure ALL of DEST dies here; again, this is
- overly conservative. */
- if (dest_death == 0
- && (dest_death = find_regno_note (q, REG_DEAD, dregno)) != 0
- && GET_MODE (XEXP (dest_death, 0)) == GET_MODE (dest))
- remove_note (q, dest_death);
- }
-
- if (! failed)
- {
- if (sregno >= FIRST_PSEUDO_REGISTER)
- {
- reg_live_length[sregno] -= length;
- /* reg_live_length is only an approximation after combine
- if sched is not run, so make sure that we still have
- a reasonable value. */
- if (reg_live_length[sregno] < 2)
- reg_live_length[sregno] = 2;
- reg_n_calls_crossed[sregno] -= n_calls;
- }
-
- if (dregno >= FIRST_PSEUDO_REGISTER)
- {
- reg_live_length[dregno] += d_length;
- reg_n_calls_crossed[dregno] += d_n_calls;
- }
-
- /* Move death note of SRC from P to INSN. */
- remove_note (p, note);
- XEXP (note, 1) = REG_NOTES (insn);
- REG_NOTES (insn) = note;
- }
-
- /* Put death note of DEST on P if we saw it die. */
- if (dest_death)
- {
- XEXP (dest_death, 1) = REG_NOTES (p);
- REG_NOTES (p) = dest_death;
- }
-
- return;
- }
-
- /* If SRC is a hard register which is set or killed in some other
- way, we can't do this optimization. */
- else if (sregno < FIRST_PSEUDO_REGISTER
- && dead_or_set_p (p, src))
- break;
- }
-}
-
-/* INSN is a copy of SRC to DEST, in which SRC dies. See if we now have
- a sequence of insns that modify DEST followed by an insn that sets
- SRC to DEST in which DEST dies, with no prior modification of DEST.
- (There is no need to check if the insns in between actually modify
- DEST. We should not have cases where DEST is not modified, but
- the optimization is safe if no such modification is detected.)
- In that case, we can replace all uses of DEST, starting with INSN and
- ending with the set of SRC to DEST, with SRC. We do not do this
- optimization if a CALL_INSN is crossed unless SRC already crosses a
- call.
-
- It is assumed that DEST and SRC are pseudos; it is too complicated to do
- this for hard registers since the substitutions we may make might fail. */
-
-static void
-optimize_reg_copy_2 (insn, dest, src)
- rtx insn;
- rtx dest;
- rtx src;
-{
- rtx p, q;
- rtx set;
- int sregno = REGNO (src);
- int dregno = REGNO (dest);
-
- for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
- {
- if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
- || (GET_CODE (p) == NOTE
- && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
- || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
- break;
-
- if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
- continue;
-
- set = single_set (p);
- if (set && SET_SRC (set) == dest && SET_DEST (set) == src
- && find_reg_note (p, REG_DEAD, dest))
- {
- /* We can do the optimization. Scan forward from INSN again,
- replacing regs as we go. */
-
- /* Set to stop at next insn. */
- for (q = insn; q != NEXT_INSN (p); q = NEXT_INSN (q))
- if (GET_RTX_CLASS (GET_CODE (q)) == 'i')
- {
- if (reg_mentioned_p (dest, PATTERN (q)))
- {
- PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
-
- /* We assume that a register is used exactly once per
- insn in the updates below. If this is not correct,
- no great harm is done. */
- reg_n_refs[dregno] -= loop_depth;
- reg_n_refs[sregno] += loop_depth;
- }
-
-
- if (GET_CODE (q) == CALL_INSN)
- {
- reg_n_calls_crossed[dregno]--;
- reg_n_calls_crossed[sregno]++;
- }
- }
-
- remove_note (p, find_reg_note (p, REG_DEAD, dest));
- reg_n_deaths[dregno]--;
- remove_note (insn, find_reg_note (insn, REG_DEAD, src));
- reg_n_deaths[sregno]--;
- return;
- }
-
- if (reg_set_p (src, p)
- || (GET_CODE (p) == CALL_INSN && reg_n_calls_crossed[sregno] == 0))
- break;
- }
-}
-
/* Find registers that are equivalent to a single value throughout the
compilation (either because they can be referenced in memory or are set once
from a single constant). Lower their priority for a register.
@@ -947,11 +755,18 @@ static void
update_equiv_regs ()
{
rtx *reg_equiv_init_insn = (rtx *) alloca (max_regno * sizeof (rtx *));
- rtx *reg_equiv_replacement = (rtx *) alloca (max_regno * sizeof (rtx *));
+ /* Set when an attempt should be made to replace a register with the
+ associated reg_equiv_replacement entry at the end of this function. */
+ char *reg_equiv_replace
+ = (char *) alloca (max_regno * sizeof *reg_equiv_replace);
rtx insn;
+ int block, depth;
+
+ reg_equiv_replacement = (rtx *) alloca (max_regno * sizeof (rtx *));
bzero ((char *) reg_equiv_init_insn, max_regno * sizeof (rtx *));
bzero ((char *) reg_equiv_replacement, max_regno * sizeof (rtx *));
+ bzero ((char *) reg_equiv_replace, max_regno * sizeof *reg_equiv_replace);
init_alias_analysis ();
@@ -964,7 +779,7 @@ update_equiv_regs ()
{
rtx note;
rtx set = single_set (insn);
- rtx dest;
+ rtx dest, src;
int regno;
if (GET_CODE (insn) == NOTE)
@@ -980,49 +795,68 @@ update_equiv_regs ()
continue;
dest = SET_DEST (set);
+ src = SET_SRC (set);
/* If this sets a MEM to the contents of a REG that is only used
in a single basic block, see if the register is always equivalent
to that memory location and if moving the store from INSN to the
insn that set REG is safe. If so, put a REG_EQUIV note on the
- initializing insn. */
+ initializing insn.
+
+ Don't add a REG_EQUIV note if the insn already has one. The existing
+ REG_EQUIV is likely more useful than the one we are adding.
+
+ If one of the regs in the address is marked as reg_equiv_replace,
+ then we can't add this REG_EQUIV note. The reg_equiv_replace
+ optimization may move the set of this register immediately before
+ insn, which puts it after reg_equiv_init_insn[regno], and hence
+ the mention in the REG_EQUIV note would be to an uninitialized
+ pseudo. */
if (GET_CODE (dest) == MEM && GET_CODE (SET_SRC (set)) == REG
&& (regno = REGNO (SET_SRC (set))) >= FIRST_PSEUDO_REGISTER
- && reg_basic_block[regno] >= 0
+ && REG_BASIC_BLOCK (regno) >= 0
&& reg_equiv_init_insn[regno] != 0
+ && ! find_reg_note (insn, REG_EQUIV, NULL_RTX)
+ && ! contains_replace_regs (XEXP (dest, 0), reg_equiv_replace)
&& validate_equiv_mem (reg_equiv_init_insn[regno], SET_SRC (set),
dest)
&& ! memref_used_between_p (SET_DEST (set),
reg_equiv_init_insn[regno], insn))
REG_NOTES (reg_equiv_init_insn[regno])
- = gen_rtx (EXPR_LIST, REG_EQUIV, dest,
- REG_NOTES (reg_equiv_init_insn[regno]));
-
- /* If this is a register-register copy where SRC is not dead, see if we
- can optimize it. */
- if (flag_expensive_optimizations && GET_CODE (dest) == REG
- && GET_CODE (SET_SRC (set)) == REG
- && ! find_reg_note (insn, REG_DEAD, SET_SRC (set)))
- optimize_reg_copy_1 (insn, dest, SET_SRC (set));
-
- /* Similarly for a pseudo-pseudo copy when SRC is dead. */
- else if (flag_expensive_optimizations && GET_CODE (dest) == REG
- && REGNO (dest) >= FIRST_PSEUDO_REGISTER
- && GET_CODE (SET_SRC (set)) == REG
- && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER
- && find_reg_note (insn, REG_DEAD, SET_SRC (set)))
- optimize_reg_copy_2 (insn, dest, SET_SRC (set));
-
- /* Otherwise, we only handle the case of a pseudo register being set
- once. */
+ = gen_rtx_EXPR_LIST (REG_EQUIV, dest,
+ REG_NOTES (reg_equiv_init_insn[regno]));
+
+ /* We only handle the case of a pseudo register being set
+ once and only if neither the source nor the destination are
+ in a register class that's likely to be spilled. */
if (GET_CODE (dest) != REG
|| (regno = REGNO (dest)) < FIRST_PSEUDO_REGISTER
- || reg_n_sets[regno] != 1)
+ || REG_N_SETS (regno) != 1
+ || CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (dest)))
+ || (GET_CODE (src) == REG
+ && REGNO (src) >= FIRST_PSEUDO_REGISTER
+ && CLASS_LIKELY_SPILLED_P (reg_preferred_class (REGNO (src)))))
continue;
note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+#ifdef DONT_RECORD_EQUIVALENCE
+ /* Allow the target to reject promotions of some REG_EQUAL notes to
+ REG_EQUIV notes.
+
+ In some cases this can improve register allocation if the existence
+ of the REG_EQUIV note is likely to increase the lifetime of a register
+ that is likely to be spilled.
+
+ It may also be necessary if the target can't handle certain constant
+ expressions appearing randomly in insns, but for whatever reason
+ those expressions must be considered legitimate constant expressions
+ to prevent them from being forced into memory. */
+ if (note && DONT_RECORD_EQUIVALENCE (note))
+ note = NULL;
+#endif
+
/* Record this insn as initializing this register. */
reg_equiv_init_insn[regno] = insn;
@@ -1048,71 +882,139 @@ update_equiv_regs ()
note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
- if (note == 0 && reg_basic_block[regno] >= 0
+ if (note == 0 && REG_BASIC_BLOCK (regno) >= 0
&& GET_CODE (SET_SRC (set)) == MEM
&& validate_equiv_mem (insn, dest, SET_SRC (set)))
- REG_NOTES (insn) = note = gen_rtx (EXPR_LIST, REG_EQUIV, SET_SRC (set),
- REG_NOTES (insn));
+ REG_NOTES (insn) = note = gen_rtx_EXPR_LIST (REG_EQUIV, SET_SRC (set),
+ REG_NOTES (insn));
- /* Don't mess with things live during setjmp. */
- if (note && reg_live_length[regno] >= 0)
+ if (note)
{
int regno = REGNO (dest);
- /* Note that the statement below does not affect the priority
- in local-alloc! */
- reg_live_length[regno] *= 2;
+ reg_equiv_replacement[regno] = XEXP (note, 0);
- /* If the register is referenced exactly twice, meaning it is set
- once and used once, indicate that the reference may be replaced
- by the equivalence we computed above. If the register is only
- used in one basic block, this can't succeed or combine would
- have done it.
+ /* Don't mess with things live during setjmp. */
+ if (REG_LIVE_LENGTH (regno) >= 0)
+ {
+ /* Note that the statement below does not affect the priority
+ in local-alloc! */
+ REG_LIVE_LENGTH (regno) *= 2;
+
+
+ /* If the register is referenced exactly twice, meaning it is
+ set once and used once, indicate that the reference may be
+ replaced by the equivalence we computed above. If the
+ register is only used in one basic block, this can't succeed
+ or combine would have done it.
- It would be nice to use "loop_depth * 2" in the compare
- below. Unfortunately, LOOP_DEPTH need not be constant within
- a basic block so this would be too complicated.
+ It would be nice to use "loop_depth * 2" in the compare
+ below. Unfortunately, LOOP_DEPTH need not be constant within
+ a basic block so this would be too complicated.
- This case normally occurs when a parameter is read from memory
- and then used exactly once, not in a loop. */
+ This case normally occurs when a parameter is read from
+ memory and then used exactly once, not in a loop. */
- if (reg_n_refs[regno] == 2
- && reg_basic_block[regno] < 0
- && rtx_equal_p (XEXP (note, 0), SET_SRC (set)))
- reg_equiv_replacement[regno] = SET_SRC (set);
+ if (REG_N_REFS (regno) == 2
+ && REG_BASIC_BLOCK (regno) < 0
+ && rtx_equal_p (XEXP (note, 0), SET_SRC (set)))
+ reg_equiv_replace[regno] = 1;
+ }
}
}
- /* Now scan all regs killed in an insn to see if any of them are registers
- only used that once. If so, see if we can replace the reference with
- the equivalent from. If we can, delete the initializing reference
- and this register will go away. */
- for (insn = next_active_insn (get_insns ());
- insn;
- insn = next_active_insn (insn))
+ /* Now scan all regs killed in an insn to see if any of them are
+ registers only used that once. If so, see if we can replace the
+ reference with the equivalent from. If we can, delete the
+ initializing reference and this register will go away. If we
+ can't replace the reference, and the instruction is not in a
+ loop, then move the register initialization just before the use,
+ so that they are in the same basic block. */
+ block = -1;
+ depth = 0;
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
{
rtx link;
+ /* Keep track of which basic block we are in. */
+ if (block + 1 < n_basic_blocks
+ && basic_block_head[block + 1] == insn)
+ ++block;
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ {
+ if (GET_CODE (insn) == NOTE)
+ {
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+ ++depth;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+ {
+ --depth;
+ if (depth < 0)
+ abort ();
+ }
+ }
+
+ continue;
+ }
+
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
- if (REG_NOTE_KIND (link) == REG_DEAD
- /* Make sure this insn still refers to the register. */
- && reg_mentioned_p (XEXP (link, 0), PATTERN (insn)))
- {
- int regno = REGNO (XEXP (link, 0));
-
- if (reg_equiv_replacement[regno]
- && validate_replace_rtx (regno_reg_rtx[regno],
- reg_equiv_replacement[regno], insn))
- {
- rtx equiv_insn = reg_equiv_init_insn[regno];
-
- remove_death (regno, insn);
- reg_n_refs[regno] = 0;
- PUT_CODE (equiv_insn, NOTE);
- NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
- NOTE_SOURCE_FILE (equiv_insn) = 0;
- }
- }
+ {
+ if (REG_NOTE_KIND (link) == REG_DEAD
+ /* Make sure this insn still refers to the register. */
+ && reg_mentioned_p (XEXP (link, 0), PATTERN (insn)))
+ {
+ int regno = REGNO (XEXP (link, 0));
+ rtx equiv_insn;
+
+ if (! reg_equiv_replace[regno])
+ continue;
+
+ equiv_insn = reg_equiv_init_insn[regno];
+
+ if (validate_replace_rtx (regno_reg_rtx[regno],
+ reg_equiv_replacement[regno], insn))
+ {
+ remove_death (regno, insn);
+ REG_N_REFS (regno) = 0;
+ PUT_CODE (equiv_insn, NOTE);
+ NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (equiv_insn) = 0;
+ }
+ /* If we aren't in a loop, and there are no calls in
+ INSN or in the initialization of the register, then
+ move the initialization of the register to just
+ before INSN. Update the flow information. */
+ else if (depth == 0
+ && GET_CODE (equiv_insn) == INSN
+ && GET_CODE (insn) == INSN
+ && REG_BASIC_BLOCK (regno) < 0)
+ {
+ int l;
+
+ emit_insn_before (copy_rtx (PATTERN (equiv_insn)), insn);
+ REG_NOTES (PREV_INSN (insn)) = REG_NOTES (equiv_insn);
+
+ PUT_CODE (equiv_insn, NOTE);
+ NOTE_LINE_NUMBER (equiv_insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (equiv_insn) = 0;
+ REG_NOTES (equiv_insn) = 0;
+
+ if (block < 0)
+ REG_BASIC_BLOCK (regno) = 0;
+ else
+ REG_BASIC_BLOCK (regno) = block;
+ REG_N_CALLS_CROSSED (regno) = 0;
+ REG_LIVE_LENGTH (regno) = 2;
+
+ if (block >= 0 && insn == basic_block_head[block])
+ basic_block_head[block] = PREV_INSN (insn);
+
+ for (l = 0; l < n_basic_blocks; l++)
+ CLEAR_REGNO_REG_SET (basic_block_live_at_start[l], regno);
+ }
+ }
+ }
}
}
@@ -1156,11 +1058,7 @@ block_alloc (b)
/* Initialize table of hardware registers currently live. */
-#ifdef HARD_REG_SET
- regs_live = *basic_block_live_at_start[b];
-#else
- COPY_HARD_REG_SET (regs_live, basic_block_live_at_start[b]);
-#endif
+ REG_SET_TO_HARD_REG_SET (regs_live, basic_block_live_at_start[b]);
/* This loop scans the instructions of the basic block
and assigns quantities to registers.
@@ -1446,13 +1344,13 @@ block_alloc (b)
if (qty_sugg_compare (1, 2) > 0)
EXCHANGE (2, 1);
- /* ... Fall through ... */
+ /* ... Fall through ... */
case 2:
/* Put the best one to allocate in qty_order[0]. */
if (qty_sugg_compare (0, 1) > 0)
EXCHANGE (0, 1);
- /* ... Fall through ... */
+ /* ... Fall through ... */
case 1:
case 0:
@@ -1495,13 +1393,13 @@ block_alloc (b)
if (qty_compare (1, 2) > 0)
EXCHANGE (2, 1);
- /* ... Fall through ... */
+ /* ... Fall through ... */
case 2:
/* Put the best one to allocate in qty_order[0]. */
if (qty_compare (0, 1) > 0)
EXCHANGE (0, 1);
- /* ... Fall through ... */
+ /* ... Fall through ... */
case 1:
case 0:
@@ -1522,8 +1420,50 @@ block_alloc (b)
q = qty_order[i];
if (qty_phys_reg[q] < 0)
{
+#ifdef INSN_SCHEDULING
+ /* These values represent the adjusted lifetime of a qty so
+ that it conflicts with qtys which appear near the start/end
+ of this qty's lifetime.
+
+ The purpose behind extending the lifetime of this qty is to
+ discourage the register allocator from creating false
+ dependencies.
+
+ The adjustment by the value +-3 indicates precisely that
+ this qty conflicts with qtys in the instructions immediately
+ before and after the lifetime of this qty.
+
+ Experiments have shown that higher values tend to hurt
+ overall code performance.
+
+ If allocation using the extended lifetime fails we will try
+ again with the qty's unadjusted lifetime. */
+ int fake_birth = MAX (0, qty_birth[q] - 3);
+ int fake_death = MIN (insn_number * 2 + 1, qty_death[q] + 3);
+#endif
+
if (N_REG_CLASSES > 1)
{
+#ifdef INSN_SCHEDULING
+ /* We try to avoid using hard registers allocated to qtys which
+ are born immediately after this qty or die immediately before
+ this qty.
+
+ This optimization is only appropriate when we will run
+ a scheduling pass after reload and we are not optimizing
+ for code size. */
+ if (flag_schedule_insns_after_reload
+ && !optimize_size
+ && !SMALL_REGISTER_CLASSES)
+ {
+
+ qty_phys_reg[q] = find_free_reg (qty_min_class[q],
+ qty_mode[q], q, 0, 0,
+ fake_birth, fake_death);
+ if (qty_phys_reg[q] >= 0)
+ continue;
+ }
+#endif
qty_phys_reg[q] = find_free_reg (qty_min_class[q],
qty_mode[q], q, 0, 0,
qty_birth[q], qty_death[q]);
@@ -1531,6 +1471,16 @@ block_alloc (b)
continue;
}
+#ifdef INSN_SCHEDULING
+ /* Similarly, avoid false dependencies. */
+ if (flag_schedule_insns_after_reload
+ && !optimize_size
+ && !SMALL_REGISTER_CLASSES
+ && qty_alternate_class[q] != NO_REGS)
+ qty_phys_reg[q] = find_free_reg (qty_alternate_class[q],
+ qty_mode[q], q, 0, 0,
+ fake_birth, fake_death);
+#endif
if (qty_alternate_class[q] != NO_REGS)
qty_phys_reg[q] = find_free_reg (qty_alternate_class[q],
qty_mode[q], q, 0, 0,
@@ -1550,17 +1500,11 @@ block_alloc (b)
{
if (GET_CODE (qty_scratch_rtx[q]) == REG)
abort ();
- PUT_CODE (qty_scratch_rtx[q], REG);
- REGNO (qty_scratch_rtx[q]) = qty_phys_reg[q];
-
+ qty_scratch_rtx[q] = gen_rtx_REG (GET_MODE (qty_scratch_rtx[q]),
+ qty_phys_reg[q]);
scratch_block[scratch_index] = b;
scratch_list[scratch_index++] = qty_scratch_rtx[q];
- /* Must clear the USED field, because it will have been set by
- copy_rtx_if_shared, but the leaf_register code expects that
- it is zero in all REG rtx. copy_rtx_if_shared does not set the
- used bit for REGs, but does for SCRATCHes. */
- qty_scratch_rtx[q]->used = 0;
}
}
}
@@ -1575,51 +1519,37 @@ block_alloc (b)
the same algorithm in both local- and global-alloc can speed up execution
of some programs by as much as a factor of three! */
+/* Note that the quotient will never be bigger than
+ the value of floor_log2 times the maximum number of
+ times a register can occur in one insn (surely less than 100).
+ Multiplying this by 10000 can't overflow.
+ QTY_CMP_PRI is also used by qty_sugg_compare. */
+
+#define QTY_CMP_PRI(q) \
+ ((int) (((double) (floor_log2 (qty_n_refs[q]) * qty_n_refs[q] * qty_size[q]) \
+ / (qty_death[q] - qty_birth[q])) * 10000))
+
static int
qty_compare (q1, q2)
int q1, q2;
{
- /* Note that the quotient will never be bigger than
- the value of floor_log2 times the maximum number of
- times a register can occur in one insn (surely less than 100).
- Multiplying this by 10000 can't overflow. */
- register int pri1
- = (((double) (floor_log2 (qty_n_refs[q1]) * qty_n_refs[q1] * qty_size[q1])
- / (qty_death[q1] - qty_birth[q1]))
- * 10000);
- register int pri2
- = (((double) (floor_log2 (qty_n_refs[q2]) * qty_n_refs[q2] * qty_size[q2])
- / (qty_death[q2] - qty_birth[q2]))
- * 10000);
- return pri2 - pri1;
+ return QTY_CMP_PRI (q2) - QTY_CMP_PRI (q1);
}
static int
-qty_compare_1 (q1, q2)
- int *q1, *q2;
+qty_compare_1 (q1p, q2p)
+ const GENERIC_PTR q1p;
+ const GENERIC_PTR q2p;
{
- register int tem;
-
- /* Note that the quotient will never be bigger than
- the value of floor_log2 times the maximum number of
- times a register can occur in one insn (surely less than 100).
- Multiplying this by 10000 can't overflow. */
- register int pri1
- = (((double) (floor_log2 (qty_n_refs[*q1]) * qty_n_refs[*q1]
- * qty_size[*q1])
- / (qty_death[*q1] - qty_birth[*q1]))
- * 10000);
- register int pri2
- = (((double) (floor_log2 (qty_n_refs[*q2]) * qty_n_refs[*q2]
- * qty_size[*q2])
- / (qty_death[*q2] - qty_birth[*q2]))
- * 10000);
-
- tem = pri2 - pri1;
- if (tem != 0) return tem;
+ register int q1 = *(int *)q1p, q2 = *(int *)q2p;
+ register int tem = QTY_CMP_PRI (q2) - QTY_CMP_PRI (q1);
+
+ if (tem != 0)
+ return tem;
+
/* If qtys are equally good, sort by qty number,
so that the results of qsort leave nothing to chance. */
- return *q1 - *q2;
+ return q1 - q2;
}
/* Compare two quantities' priority for getting real registers. This version
@@ -1629,71 +1559,45 @@ qty_compare_1 (q1, q2)
number of preferences have the highest priority. Of those, we use the same
algorithm as above. */
+#define QTY_CMP_SUGG(q) \
+ (qty_phys_num_copy_sugg[q] \
+ ? qty_phys_num_copy_sugg[q] \
+ : qty_phys_num_sugg[q] * FIRST_PSEUDO_REGISTER)
+
static int
qty_sugg_compare (q1, q2)
int q1, q2;
{
- register int sugg1 = (qty_phys_num_copy_sugg[q1]
- ? qty_phys_num_copy_sugg[q1]
- : qty_phys_num_sugg[q1] * FIRST_PSEUDO_REGISTER);
- register int sugg2 = (qty_phys_num_copy_sugg[q2]
- ? qty_phys_num_copy_sugg[q2]
- : qty_phys_num_sugg[q2] * FIRST_PSEUDO_REGISTER);
- /* Note that the quotient will never be bigger than
- the value of floor_log2 times the maximum number of
- times a register can occur in one insn (surely less than 100).
- Multiplying this by 10000 can't overflow. */
- register int pri1
- = (((double) (floor_log2 (qty_n_refs[q1]) * qty_n_refs[q1] * qty_size[q1])
- / (qty_death[q1] - qty_birth[q1]))
- * 10000);
- register int pri2
- = (((double) (floor_log2 (qty_n_refs[q2]) * qty_n_refs[q2] * qty_size[q2])
- / (qty_death[q2] - qty_birth[q2]))
- * 10000);
-
- if (sugg1 != sugg2)
- return sugg1 - sugg2;
+ register int tem = QTY_CMP_SUGG (q1) - QTY_CMP_SUGG (q2);
+
+ if (tem != 0)
+ return tem;
- return pri2 - pri1;
+ return QTY_CMP_PRI (q2) - QTY_CMP_PRI (q1);
}
static int
-qty_sugg_compare_1 (q1, q2)
- int *q1, *q2;
+qty_sugg_compare_1 (q1p, q2p)
+ const GENERIC_PTR q1p;
+ const GENERIC_PTR q2p;
{
- register int sugg1 = (qty_phys_num_copy_sugg[*q1]
- ? qty_phys_num_copy_sugg[*q1]
- : qty_phys_num_sugg[*q1] * FIRST_PSEUDO_REGISTER);
- register int sugg2 = (qty_phys_num_copy_sugg[*q2]
- ? qty_phys_num_copy_sugg[*q2]
- : qty_phys_num_sugg[*q2] * FIRST_PSEUDO_REGISTER);
-
- /* Note that the quotient will never be bigger than
- the value of floor_log2 times the maximum number of
- times a register can occur in one insn (surely less than 100).
- Multiplying this by 10000 can't overflow. */
- register int pri1
- = (((double) (floor_log2 (qty_n_refs[*q1]) * qty_n_refs[*q1]
- * qty_size[*q1])
- / (qty_death[*q1] - qty_birth[*q1]))
- * 10000);
- register int pri2
- = (((double) (floor_log2 (qty_n_refs[*q2]) * qty_n_refs[*q2]
- * qty_size[*q2])
- / (qty_death[*q2] - qty_birth[*q2]))
- * 10000);
-
- if (sugg1 != sugg2)
- return sugg1 - sugg2;
-
- if (pri1 != pri2)
- return pri2 - pri1;
+ register int q1 = *(int *)q1p, q2 = *(int *)q2p;
+ register int tem = QTY_CMP_SUGG (q1) - QTY_CMP_SUGG (q2);
+
+ if (tem != 0)
+ return tem;
+
+ tem = QTY_CMP_PRI (q2) - QTY_CMP_PRI (q1);
+ if (tem != 0)
+ return tem;
/* If qtys are equally good, sort by qty number,
so that the results of qsort leave nothing to chance. */
- return *q1 - *q2;
+ return q1 - q2;
}
+
+#undef QTY_CMP_SUGG
+#undef QTY_CMP_PRI
/* Attempt to combine the two registers (rtx's) USEDREG and SETREG.
Returns 1 if have done so, or 0 if cannot.
@@ -1767,7 +1671,7 @@ combine_regs (usedreg, setreg, may_save_copy, insn_number, insn, already_dead)
|| (offset > 0 && usize + offset > ssize)
|| (offset < 0 && usize + offset < ssize)
/* Do not combine with a smaller already-assigned object
- if that smaller object is already combined with something bigger. */
+ if that smaller object is already combined with something bigger. */
|| (ssize > usize && ureg >= FIRST_PSEUDO_REGISTER
&& usize < qty_size[reg_qty[ureg]])
/* Can't combine if SREG is not a register we can allocate. */
@@ -1844,8 +1748,8 @@ combine_regs (usedreg, setreg, may_save_copy, insn_number, insn, already_dead)
/* If we are not going to let any regs live across calls,
don't tie a call-crossing reg to a non-call-crossing reg. */
|| (current_function_has_nonlocal_label
- && ((reg_n_calls_crossed[ureg] > 0)
- != (reg_n_calls_crossed[sreg] > 0))))
+ && ((REG_N_CALLS_CROSSED (ureg) > 0)
+ != (REG_N_CALLS_CROSSED (sreg) > 0))))
return 0;
/* We don't already know about SREG, so tie it to UREG
@@ -1866,8 +1770,8 @@ combine_regs (usedreg, setreg, may_save_copy, insn_number, insn, already_dead)
update_qty_class (sqty, sreg);
/* Update info about quantity SQTY. */
- qty_n_calls_crossed[sqty] += reg_n_calls_crossed[sreg];
- qty_n_refs[sqty] += reg_n_refs[sreg];
+ qty_n_calls_crossed[sqty] += REG_N_CALLS_CROSSED (sreg);
+ qty_n_refs[sqty] += REG_N_REFS (sreg);
if (usize < ssize)
{
register int i;
@@ -1899,29 +1803,6 @@ reg_meets_class_p (reg, class)
|| reg_class_subset_p (class, rclass));
}
-/* Return 1 if the two specified classes have registers in common.
- If CALL_SAVED, then consider only call-saved registers. */
-
-static int
-reg_classes_overlap_p (c1, c2, call_saved)
- register enum reg_class c1;
- register enum reg_class c2;
- int call_saved;
-{
- HARD_REG_SET c;
- int i;
-
- COPY_HARD_REG_SET (c, reg_class_contents[(int) c1]);
- AND_HARD_REG_SET (c, reg_class_contents[(int) c2]);
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (TEST_HARD_REG_BIT (c, i)
- && (! call_saved || ! call_used_regs[i]))
- return 1;
-
- return 0;
-}
-
/* Update the class of QTY assuming that REG is being tied to it. */
static void
@@ -1937,7 +1818,7 @@ update_qty_class (qty, reg)
if (reg_class_subset_p (rclass, qty_alternate_class[qty]))
qty_alternate_class[qty] = rclass;
- if (reg_changes_size[reg])
+ if (REG_CHANGES_SIZE (reg))
qty_changes_size[qty] = 1;
}
@@ -2105,6 +1986,9 @@ find_free_reg (class, mode, qty, accept_call_clobbered, just_try_suggested,
else
COPY_HARD_REG_SET (used, call_used_reg_set);
+ if (accept_call_clobbered)
+ IOR_HARD_REG_SET (used, losing_caller_save_reg_set);
+
for (ins = born_index; ins < dead_index; ins++)
IOR_HARD_REG_SET (used, regs_live_at[ins]);
@@ -2121,7 +2005,7 @@ find_free_reg (class, mode, qty, accept_call_clobbered, just_try_suggested,
SET_HARD_REG_BIT (used, eliminables[i].from);
#if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
/* If FRAME_POINTER_REGNUM is not a real register, then protect the one
- that it might be eliminated into. */
+ that it might be eliminated into. */
SET_HARD_REG_BIT (used, HARD_FRAME_POINTER_REGNUM);
#endif
#else
@@ -2303,8 +2187,12 @@ no_conflict_p (insn, r0, r1)
if (find_reg_note (p, REG_DEAD, r1))
ok = 1;
- if (reg_mentioned_p (r1, PATTERN (p))
- && ! find_reg_note (p, REG_NO_CONFLICT, r1))
+ /* There must be a REG_NO_CONFLICT note on every insn, otherwise
+ some earlier optimization pass has inserted instructions into
+ the sequence, and it is not safe to perform this optimization.
+ Note that emit_no_conflict_block always ensures that this is
+ true when these sequences are created. */
+ if (! find_reg_note (p, REG_NO_CONFLICT, r1))
return 0;
}
@@ -2326,7 +2214,7 @@ requires_inout (p)
int reg_allowed = 0;
int num_matching_alts = 0;
- while (c = *p++)
+ while ((c = *p++))
switch (c)
{
case '=': case '+': case '?':
diff --git a/contrib/gcc/longlong.h b/contrib/gcc/longlong.h
index f824b5f..f86f894 100644
--- a/contrib/gcc/longlong.h
+++ b/contrib/gcc/longlong.h
@@ -1,5 +1,5 @@
/* longlong.h -- definitions for mixed size 32/64 bit arithmetic.
- Copyright (C) 1991, 1992, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1991, 92, 94, 95, 96, 1997 Free Software Foundation, Inc.
This definition file is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public
@@ -91,65 +91,96 @@
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("add %1,%4,%5
addc %0,%2,%3" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%r" ((USItype)(ah)), \
- "rI" ((USItype)(bh)), \
- "%r" ((USItype)(al)), \
- "rI" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%r" ((USItype) (ah)), \
+ "rI" ((USItype) (bh)), \
+ "%r" ((USItype) (al)), \
+ "rI" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("sub %1,%4,%5
subc %0,%2,%3" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "r" ((USItype)(ah)), \
- "rI" ((USItype)(bh)), \
- "r" ((USItype)(al)), \
- "rI" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "r" ((USItype) (ah)), \
+ "rI" ((USItype) (bh)), \
+ "r" ((USItype) (al)), \
+ "rI" ((USItype) (bl)))
#define umul_ppmm(xh, xl, m0, m1) \
do { \
USItype __m0 = (m0), __m1 = (m1); \
__asm__ ("multiplu %0,%1,%2" \
- : "=r" ((USItype)(xl)) \
+ : "=r" ((USItype) (xl)) \
: "r" (__m0), \
"r" (__m1)); \
__asm__ ("multmu %0,%1,%2" \
- : "=r" ((USItype)(xh)) \
+ : "=r" ((USItype) (xh)) \
: "r" (__m0), \
"r" (__m1)); \
} while (0)
#define udiv_qrnnd(q, r, n1, n0, d) \
__asm__ ("dividu %0,%3,%4" \
- : "=r" ((USItype)(q)), \
- "=q" ((USItype)(r)) \
- : "1" ((USItype)(n1)), \
- "r" ((USItype)(n0)), \
- "r" ((USItype)(d)))
+ : "=r" ((USItype) (q)), \
+ "=q" ((USItype) (r)) \
+ : "1" ((USItype) (n1)), \
+ "r" ((USItype) (n0)), \
+ "r" ((USItype) (d)))
#define count_leading_zeros(count, x) \
__asm__ ("clz %0,%1" \
- : "=r" ((USItype)(count)) \
- : "r" ((USItype)(x)))
+ : "=r" ((USItype) (count)) \
+ : "r" ((USItype) (x)))
#endif /* __a29k__ */
+#if defined (__arc__)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ __asm__ ("add.f %1, %4, %5
+ adc %0, %2, %3" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%r" ((USItype) (ah)), \
+ "rIJ" ((USItype) (bh)), \
+ "%r" ((USItype) (al)), \
+ "rIJ" ((USItype) (bl)))
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ __asm__ ("sub.f %1, %4, %5
+ sbc %0, %2, %3" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "r" ((USItype) (ah)), \
+ "rIJ" ((USItype) (bh)), \
+ "r" ((USItype) (al)), \
+ "rIJ" ((USItype) (bl)))
+/* Call libgcc1 routine. */
+#define umul_ppmm(w1, w0, u, v) \
+do { \
+ DIunion __w; \
+ __w.ll = __umulsidi3 (u, v); \
+ w1 = __w.s.high; \
+ w0 = __w.s.low; \
+} while (0)
+#define __umulsidi3 __umulsidi3
+UDItype __umulsidi3 (USItype, USItype);
+#endif
+
#if defined (__arm__)
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("adds %1, %4, %5
adc %0, %2, %3" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%r" ((USItype)(ah)), \
- "rI" ((USItype)(bh)), \
- "%r" ((USItype)(al)), \
- "rI" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%r" ((USItype) (ah)), \
+ "rI" ((USItype) (bh)), \
+ "%r" ((USItype) (al)), \
+ "rI" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subs %1, %4, %5
sbc %0, %2, %3" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "r" ((USItype)(ah)), \
- "rI" ((USItype)(bh)), \
- "r" ((USItype)(al)), \
- "rI" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "r" ((USItype) (ah)), \
+ "rI" ((USItype) (bh)), \
+ "r" ((USItype) (al)), \
+ "rI" ((USItype) (bl)))
#define umul_ppmm(xh, xl, a, b) \
{register USItype __t0, __t1, __t2; \
__asm__ ("%@ Inlined umul_ppmm
@@ -165,11 +196,11 @@
addcs %0, %0, #65536
adds %1, %1, %3, lsl #16
adc %0, %0, %3, lsr #16" \
- : "=&r" ((USItype)(xh)), \
- "=r" ((USItype)(xl)), \
+ : "=&r" ((USItype) (xh)), \
+ "=r" ((USItype) (xl)), \
"=&r" (__t0), "=&r" (__t1), "=r" (__t2) \
- : "r" ((USItype)(a)), \
- "r" ((USItype)(b)));}
+ : "r" ((USItype) (a)), \
+ "r" ((USItype) (b)));}
#define UMUL_TIME 20
#define UDIV_TIME 100
#endif /* __arm__ */
@@ -181,8 +212,8 @@
} __xx; \
__asm__ ("mulwux %2,%0" \
: "=r" (__xx.__ll) \
- : "%0" ((USItype)(u)), \
- "r" ((USItype)(v))); \
+ : "%0" ((USItype) (u)), \
+ "r" ((USItype) (v))); \
(w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
#define smul_ppmm(w1, w0, u, v) \
({union {DItype __ll; \
@@ -190,15 +221,15 @@
} __xx; \
__asm__ ("mulwx %2,%0" \
: "=r" (__xx.__ll) \
- : "%0" ((SItype)(u)), \
- "r" ((SItype)(v))); \
+ : "%0" ((SItype) (u)), \
+ "r" ((SItype) (v))); \
(w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
#define __umulsidi3(u, v) \
({UDItype __w; \
__asm__ ("mulwux %2,%0" \
: "=r" (__w) \
- : "%0" ((USItype)(u)), \
- "r" ((USItype)(v))); \
+ : "%0" ((USItype) (u)), \
+ "r" ((USItype) (v))); \
__w; })
#endif /* __clipper__ */
@@ -206,60 +237,60 @@
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("add.w %5,%1
addx %3,%0" \
- : "=g" ((USItype)(sh)), \
- "=&g" ((USItype)(sl)) \
- : "%0" ((USItype)(ah)), \
- "g" ((USItype)(bh)), \
- "%1" ((USItype)(al)), \
- "g" ((USItype)(bl)))
+ : "=g" ((USItype) (sh)), \
+ "=&g" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("sub.w %5,%1
subx %3,%0" \
- : "=g" ((USItype)(sh)), \
- "=&g" ((USItype)(sl)) \
- : "0" ((USItype)(ah)), \
- "g" ((USItype)(bh)), \
- "1" ((USItype)(al)), \
- "g" ((USItype)(bl)))
+ : "=g" ((USItype) (sh)), \
+ "=&g" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
#define umul_ppmm(ph, pl, m0, m1) \
__asm__ ("mulx %3,%0,%1" \
- : "=g" ((USItype)(ph)), \
- "=r" ((USItype)(pl)) \
- : "%0" ((USItype)(m0)), \
- "g" ((USItype)(m1)))
+ : "=g" ((USItype) (ph)), \
+ "=r" ((USItype) (pl)) \
+ : "%0" ((USItype) (m0)), \
+ "g" ((USItype) (m1)))
#define udiv_qrnnd(q, r, nh, nl, d) \
__asm__ ("divx %4,%0,%1" \
- : "=g" ((USItype)(q)), \
- "=r" ((USItype)(r)) \
- : "1" ((USItype)(nh)), \
- "0" ((USItype)(nl)), \
- "g" ((USItype)(d)))
+ : "=g" ((USItype) (q)), \
+ "=r" ((USItype) (r)) \
+ : "1" ((USItype) (nh)), \
+ "0" ((USItype) (nl)), \
+ "g" ((USItype) (d)))
#define count_leading_zeros(count, x) \
__asm__ ("bsch/1 %1,%0" \
: "=g" (count) \
- : "g" ((USItype)(x)), \
- "0" ((USItype)0))
+ : "g" ((USItype) (x)), \
+ "0" ((USItype) 0))
#endif
#if defined (__hppa)
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("add %4,%5,%1
addc %2,%3,%0" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%rM" ((USItype)(ah)), \
- "rM" ((USItype)(bh)), \
- "%rM" ((USItype)(al)), \
- "rM" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%rM" ((USItype) (ah)), \
+ "rM" ((USItype) (bh)), \
+ "%rM" ((USItype) (al)), \
+ "rM" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("sub %4,%5,%1
subb %2,%3,%0" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "rM" ((USItype)(ah)), \
- "rM" ((USItype)(bh)), \
- "rM" ((USItype)(al)), \
- "rM" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "rM" ((USItype) (ah)), \
+ "rM" ((USItype) (bh)), \
+ "rM" ((USItype) (al)), \
+ "rM" ((USItype) (bl)))
#if defined (_PA_RISC1_1)
#define umul_ppmm(w1, w0, u, v) \
do { \
@@ -270,8 +301,8 @@
} __t; \
__asm__ ("xmpyu %1,%2,%0" \
: "=x" (__t.__f) \
- : "x" ((USItype)(u)), \
- "x" ((USItype)(v))); \
+ : "x" ((USItype) (u)), \
+ "x" ((USItype) (v))); \
(w1) = __t.__w1w0.__w1; \
(w0) = __t.__w1w0.__w0; \
} while (0)
@@ -307,39 +338,39 @@
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addl %5,%1
adcl %3,%0" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%0" ((USItype)(ah)), \
- "g" ((USItype)(bh)), \
- "%1" ((USItype)(al)), \
- "g" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subl %5,%1
sbbl %3,%0" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "0" ((USItype)(ah)), \
- "g" ((USItype)(bh)), \
- "1" ((USItype)(al)), \
- "g" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("mull %3" \
- : "=a" ((USItype)(w0)), \
- "=d" ((USItype)(w1)) \
- : "%0" ((USItype)(u)), \
- "rm" ((USItype)(v)))
+ : "=a" ((USItype) (w0)), \
+ "=d" ((USItype) (w1)) \
+ : "%0" ((USItype) (u)), \
+ "rm" ((USItype) (v)))
#define udiv_qrnnd(q, r, n1, n0, d) \
__asm__ ("divl %4" \
- : "=a" ((USItype)(q)), \
- "=d" ((USItype)(r)) \
- : "0" ((USItype)(n0)), \
- "1" ((USItype)(n1)), \
- "rm" ((USItype)(d)))
+ : "=a" ((USItype) (q)), \
+ "=d" ((USItype) (r)) \
+ : "0" ((USItype) (n0)), \
+ "1" ((USItype) (n1)), \
+ "rm" ((USItype) (d)))
#define count_leading_zeros(count, x) \
do { \
USItype __cbtmp; \
__asm__ ("bsrl %1,%0" \
- : "=r" (__cbtmp) : "rm" ((USItype)(x))); \
+ : "=r" (__cbtmp) : "rm" ((USItype) (x))); \
(count) = __cbtmp ^ 31; \
} while (0)
#define UMUL_TIME 40
@@ -394,65 +425,96 @@
} __xx; \
__asm__ ("emul %2,%1,%0" \
: "=d" (__xx.__ll) \
- : "%dI" ((USItype)(u)), \
- "dI" ((USItype)(v))); \
+ : "%dI" ((USItype) (u)), \
+ "dI" ((USItype) (v))); \
(w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
#define __umulsidi3(u, v) \
({UDItype __w; \
__asm__ ("emul %2,%1,%0" \
: "=d" (__w) \
- : "%dI" ((USItype)(u)), \
- "dI" ((USItype)(v))); \
+ : "%dI" ((USItype) (u)), \
+ "dI" ((USItype) (v))); \
__w; })
#endif /* __i960__ */
+#if defined (__M32R__)
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ /* The cmp clears the condition bit. */ \
+ __asm__ ("cmp %0,%0
+ addx %%5,%1
+ addx %%3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "r" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "r" ((USItype) (bl)) \
+ : "cbit")
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ /* The cmp clears the condition bit. */ \
+ __asm__ ("cmp %0,%0
+ subx %5,%1
+ subx %3,%0" \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "r" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "r" ((USItype) (bl)) \
+ : "cbit")
+#endif /* __M32R__ */
+
#if defined (__mc68000__)
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("add%.l %5,%1
addx%.l %3,%0" \
- : "=d" ((USItype)(sh)), \
- "=&d" ((USItype)(sl)) \
- : "%0" ((USItype)(ah)), \
- "d" ((USItype)(bh)), \
- "%1" ((USItype)(al)), \
- "g" ((USItype)(bl)))
+ : "=d" ((USItype) (sh)), \
+ "=&d" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "d" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("sub%.l %5,%1
subx%.l %3,%0" \
- : "=d" ((USItype)(sh)), \
- "=&d" ((USItype)(sl)) \
- : "0" ((USItype)(ah)), \
- "d" ((USItype)(bh)), \
- "1" ((USItype)(al)), \
- "g" ((USItype)(bl)))
-#if defined (__mc68020__) || defined (__NeXT__) || defined(mc68020)
+ : "=d" ((USItype) (sh)), \
+ "=&d" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "d" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
+
+/* The '020, '030, '040 and CPU32 have 32x32->64 and 64/32->32q-32r. */
+#if defined (__mc68020__) || defined(mc68020) \
+ || defined(__mc68030__) || defined(mc68030) \
+ || defined(__mc68040__) || defined(mc68040) \
+ || defined(__mcpu32__) || defined(mcpu32) \
+ || defined(__NeXT__)
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("mulu%.l %3,%1:%0" \
- : "=d" ((USItype)(w0)), \
- "=d" ((USItype)(w1)) \
- : "%0" ((USItype)(u)), \
- "dmi" ((USItype)(v)))
+ : "=d" ((USItype) (w0)), \
+ "=d" ((USItype) (w1)) \
+ : "%0" ((USItype) (u)), \
+ "dmi" ((USItype) (v)))
#define UMUL_TIME 45
#define udiv_qrnnd(q, r, n1, n0, d) \
__asm__ ("divu%.l %4,%1:%0" \
- : "=d" ((USItype)(q)), \
- "=d" ((USItype)(r)) \
- : "0" ((USItype)(n0)), \
- "1" ((USItype)(n1)), \
- "dmi" ((USItype)(d)))
+ : "=d" ((USItype) (q)), \
+ "=d" ((USItype) (r)) \
+ : "0" ((USItype) (n0)), \
+ "1" ((USItype) (n1)), \
+ "dmi" ((USItype) (d)))
#define UDIV_TIME 90
#define sdiv_qrnnd(q, r, n1, n0, d) \
__asm__ ("divs%.l %4,%1:%0" \
- : "=d" ((USItype)(q)), \
- "=d" ((USItype)(r)) \
- : "0" ((USItype)(n0)), \
- "1" ((USItype)(n1)), \
- "dmi" ((USItype)(d)))
-#define count_leading_zeros(count, x) \
- __asm__ ("bfffo %1{%b2:%b2},%0" \
- : "=d" ((USItype)(count)) \
- : "od" ((USItype)(x)), "n" (0))
+ : "=d" ((USItype) (q)), \
+ "=d" ((USItype) (r)) \
+ : "0" ((USItype) (n0)), \
+ "1" ((USItype) (n1)), \
+ "dmi" ((USItype) (d)))
+
#else /* not mc68020 */
+#if !defined(__mcf5200__)
/* %/ inserts REGISTER_PREFIX, %# inserts IMMEDIATE_PREFIX. */
#define umul_ppmm(xh, xl, a, b) \
__asm__ ("| Inlined umul_ppmm
@@ -481,41 +543,54 @@
move%.l %/d2,%1
add%.l %/d1,%/d0
move%.l %/d0,%0" \
- : "=g" ((USItype)(xh)), \
- "=g" ((USItype)(xl)) \
- : "g" ((USItype)(a)), \
- "g" ((USItype)(b)) \
+ : "=g" ((USItype) (xh)), \
+ "=g" ((USItype) (xl)) \
+ : "g" ((USItype) (a)), \
+ "g" ((USItype) (b)) \
: "d0", "d1", "d2", "d3", "d4")
#define UMUL_TIME 100
#define UDIV_TIME 400
+#endif /* not mcf5200 */
#endif /* not mc68020 */
+
+/* The '020, '030, '040 and '060 have bitfield insns. */
+#if defined (__mc68020__) || defined(mc68020) \
+ || defined(__mc68030__) || defined(mc68030) \
+ || defined(__mc68040__) || defined(mc68040) \
+ || defined(__mc68060__) || defined(mc68060) \
+ || defined(__NeXT__)
+#define count_leading_zeros(count, x) \
+ __asm__ ("bfffo %1{%b2:%b2},%0" \
+ : "=d" ((USItype) (count)) \
+ : "od" ((USItype) (x)), "n" (0))
+#endif
#endif /* mc68000 */
#if defined (__m88000__)
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addu.co %1,%r4,%r5
addu.ci %0,%r2,%r3" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%rJ" ((USItype)(ah)), \
- "rJ" ((USItype)(bh)), \
- "%rJ" ((USItype)(al)), \
- "rJ" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%rJ" ((USItype) (ah)), \
+ "rJ" ((USItype) (bh)), \
+ "%rJ" ((USItype) (al)), \
+ "rJ" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subu.co %1,%r4,%r5
subu.ci %0,%r2,%r3" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "rJ" ((USItype)(ah)), \
- "rJ" ((USItype)(bh)), \
- "rJ" ((USItype)(al)), \
- "rJ" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "rJ" ((USItype) (ah)), \
+ "rJ" ((USItype) (bh)), \
+ "rJ" ((USItype) (al)), \
+ "rJ" ((USItype) (bl)))
#define count_leading_zeros(count, x) \
do { \
USItype __cbtmp; \
__asm__ ("ff1 %0,%1" \
: "=r" (__cbtmp) \
- : "r" ((USItype)(x))); \
+ : "r" ((USItype) (x))); \
(count) = __cbtmp ^ 31; \
} while (0)
#if defined (__mc88110__)
@@ -526,8 +601,8 @@
} __xx; \
__asm__ ("mulu.d %0,%1,%2" \
: "=r" (__xx.__ll) \
- : "r" ((USItype)(u)), \
- "r" ((USItype)(v))); \
+ : "r" ((USItype) (u)), \
+ "r" ((USItype) (v))); \
(wh) = __xx.__i.__h; \
(wl) = __xx.__i.__l; \
} while (0)
@@ -540,7 +615,7 @@
__asm__ ("divu.d %0,%1,%2" \
: "=r" (__q) \
: "r" (__xx.__ll), \
- "r" ((USItype)(d))); \
+ "r" ((USItype) (d))); \
(r) = (n0) - __q * (d); (q) = __q; })
#define UMUL_TIME 5
#define UDIV_TIME 25
@@ -553,10 +628,10 @@
#if defined (__mips__)
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("multu %2,%3" \
- : "=l" ((USItype)(w0)), \
- "=h" ((USItype)(w1)) \
- : "d" ((USItype)(u)), \
- "d" ((USItype)(v)))
+ : "=l" ((USItype) (w0)), \
+ "=h" ((USItype) (w1)) \
+ : "d" ((USItype) (u)), \
+ "d" ((USItype) (v)))
#define UMUL_TIME 10
#define UDIV_TIME 100
#endif /* __mips__ */
@@ -568,15 +643,15 @@
} __xx; \
__asm__ ("meid %2,%0" \
: "=g" (__xx.__ll) \
- : "%0" ((USItype)(u)), \
- "g" ((USItype)(v))); \
+ : "%0" ((USItype) (u)), \
+ "g" ((USItype) (v))); \
(w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
#define __umulsidi3(u, v) \
({UDItype __w; \
__asm__ ("meid %2,%0" \
: "=g" (__w) \
- : "%0" ((USItype)(u)), \
- "g" ((USItype)(v))); \
+ : "%0" ((USItype) (u)), \
+ "g" ((USItype) (v))); \
__w; })
#define udiv_qrnnd(q, r, n1, n0, d) \
({union {UDItype __ll; \
@@ -586,7 +661,7 @@
__asm__ ("deid %2,%0" \
: "=g" (__xx.__ll) \
: "0" (__xx.__ll), \
- "g" ((USItype)(d))); \
+ "g" ((USItype) (d))); \
(r) = __xx.__i.__l; (q) = __xx.__i.__h; })
#endif /* __ns32000__ */
@@ -595,70 +670,70 @@
do { \
if (__builtin_constant_p (bh) && (bh) == 0) \
__asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%r" ((USItype)(ah)), \
- "%r" ((USItype)(al)), \
- "rI" ((USItype)(bl))); \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%r" ((USItype) (ah)), \
+ "%r" ((USItype) (al)), \
+ "rI" ((USItype) (bl))); \
else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \
__asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%r" ((USItype)(ah)), \
- "%r" ((USItype)(al)), \
- "rI" ((USItype)(bl))); \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%r" ((USItype) (ah)), \
+ "%r" ((USItype) (al)), \
+ "rI" ((USItype) (bl))); \
else \
__asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%r" ((USItype)(ah)), \
- "r" ((USItype)(bh)), \
- "%r" ((USItype)(al)), \
- "rI" ((USItype)(bl))); \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%r" ((USItype) (ah)), \
+ "r" ((USItype) (bh)), \
+ "%r" ((USItype) (al)), \
+ "rI" ((USItype) (bl))); \
} while (0)
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
do { \
if (__builtin_constant_p (ah) && (ah) == 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "r" ((USItype)(bh)), \
- "rI" ((USItype)(al)), \
- "r" ((USItype)(bl))); \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "r" ((USItype) (bh)), \
+ "rI" ((USItype) (al)), \
+ "r" ((USItype) (bl))); \
else if (__builtin_constant_p (ah) && (ah) ==~(USItype) 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "r" ((USItype)(bh)), \
- "rI" ((USItype)(al)), \
- "r" ((USItype)(bl))); \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "r" ((USItype) (bh)), \
+ "rI" ((USItype) (al)), \
+ "r" ((USItype) (bl))); \
else if (__builtin_constant_p (bh) && (bh) == 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "r" ((USItype)(ah)), \
- "rI" ((USItype)(al)), \
- "r" ((USItype)(bl))); \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "r" ((USItype) (ah)), \
+ "rI" ((USItype) (al)), \
+ "r" ((USItype) (bl))); \
else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \
__asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "r" ((USItype)(ah)), \
- "rI" ((USItype)(al)), \
- "r" ((USItype)(bl))); \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "r" ((USItype) (ah)), \
+ "rI" ((USItype) (al)), \
+ "r" ((USItype) (bl))); \
else \
__asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "r" ((USItype)(ah)), \
- "r" ((USItype)(bh)), \
- "rI" ((USItype)(al)), \
- "r" ((USItype)(bl))); \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "r" ((USItype) (ah)), \
+ "r" ((USItype) (bh)), \
+ "rI" ((USItype) (al)), \
+ "r" ((USItype) (bl))); \
} while (0)
#define count_leading_zeros(count, x) \
__asm__ ("{cntlz|cntlzw} %0,%1" \
- : "=r" ((USItype)(count)) \
- : "r" ((USItype)(x)))
+ : "=r" ((USItype) (count)) \
+ : "r" ((USItype) (x)))
#if defined (_ARCH_PPC)
#define umul_ppmm(ph, pl, m0, m1) \
do { \
@@ -686,8 +761,8 @@
do { \
USItype __m0 = (m0), __m1 = (m1); \
__asm__ ("mul %0,%2,%3" \
- : "=r" ((USItype)(xh)), \
- "=q" ((USItype)(xl)) \
+ : "=r" ((USItype) (xh)), \
+ "=q" ((USItype) (xl)) \
: "r" (__m0), \
"r" (__m1)); \
(xh) += ((((SItype) __m0 >> 31) & __m1) \
@@ -696,15 +771,15 @@
#define UMUL_TIME 8
#define smul_ppmm(xh, xl, m0, m1) \
__asm__ ("mul %0,%2,%3" \
- : "=r" ((SItype)(xh)), \
- "=q" ((SItype)(xl)) \
+ : "=r" ((SItype) (xh)), \
+ "=q" ((SItype) (xl)) \
: "r" (m0), \
"r" (m1))
#define SMUL_TIME 4
#define sdiv_qrnnd(q, r, nh, nl, d) \
__asm__ ("div %0,%2,%4" \
- : "=r" ((SItype)(q)), "=q" ((SItype)(r)) \
- : "r" ((SItype)(nh)), "1" ((SItype)(nl)), "r" ((SItype)(d)))
+ : "=r" ((SItype) (q)), "=q" ((SItype) (r)) \
+ : "r" ((SItype) (nh)), "1" ((SItype) (nl)), "r" ((SItype) (d)))
#define UDIV_TIME 100
#endif
#endif /* Power architecture variants. */
@@ -713,21 +788,21 @@
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addw %5,%1
addwc %3,%0" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%0" ((USItype)(ah)), \
- "g" ((USItype)(bh)), \
- "%1" ((USItype)(al)), \
- "g" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subw %5,%1
subwb %3,%0" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "0" ((USItype)(ah)), \
- "g" ((USItype)(bh)), \
- "1" ((USItype)(al)), \
- "g" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
/* This insn works on Pyramids with AP, XP, or MI CPUs, but not with SP. */
#define umul_ppmm(w1, w0, u, v) \
({union {UDItype __ll; \
@@ -737,7 +812,7 @@
uemul %2,%0" \
: "=&r" (__xx.__ll) \
: "g" ((USItype) (u)), \
- "g" ((USItype)(v))); \
+ "g" ((USItype) (v))); \
(w1) = __xx.__i.__h; (w0) = __xx.__i.__l;})
#endif /* __pyr__ */
@@ -745,21 +820,21 @@
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("a %1,%5
ae %0,%3" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%0" ((USItype)(ah)), \
- "r" ((USItype)(bh)), \
- "%1" ((USItype)(al)), \
- "r" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "r" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "r" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("s %1,%5
se %0,%3" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "0" ((USItype)(ah)), \
- "r" ((USItype)(bh)), \
- "1" ((USItype)(al)), \
- "r" ((USItype)(bl)))
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "r" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "r" ((USItype) (bl)))
#define umul_ppmm(ph, pl, m0, m1) \
do { \
USItype __m0 = (m0), __m1 = (m1); \
@@ -784,8 +859,8 @@
m r2,%3
cas %0,r2,r0
mfs r10,%1" \
- : "=r" ((USItype)(ph)), \
- "=r" ((USItype)(pl)) \
+ : "=r" ((USItype) (ph)), \
+ "=r" ((USItype) (pl)) \
: "%r" (__m0), \
"r" (__m1) \
: "r2"); \
@@ -798,13 +873,13 @@
do { \
if ((x) >= 0x10000) \
__asm__ ("clz %0,%1" \
- : "=r" ((USItype)(count)) \
- : "r" ((USItype)(x) >> 16)); \
+ : "=r" ((USItype) (count)) \
+ : "r" ((USItype) (x) >> 16)); \
else \
{ \
__asm__ ("clz %0,%1" \
- : "=r" ((USItype)(count)) \
- : "r" ((USItype)(x))); \
+ : "=r" ((USItype) (count)) \
+ : "r" ((USItype) (x))); \
(count) += 16; \
} \
} while (0)
@@ -814,47 +889,47 @@
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addcc %r4,%5,%1
addx %r2,%3,%0" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "%rJ" ((USItype)(ah)), \
- "rI" ((USItype)(bh)), \
- "%rJ" ((USItype)(al)), \
- "rI" ((USItype)(bl)) \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "%rJ" ((USItype) (ah)), \
+ "rI" ((USItype) (bh)), \
+ "%rJ" ((USItype) (al)), \
+ "rI" ((USItype) (bl)) \
__CLOBBER_CC)
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subcc %r4,%5,%1
subx %r2,%3,%0" \
- : "=r" ((USItype)(sh)), \
- "=&r" ((USItype)(sl)) \
- : "rJ" ((USItype)(ah)), \
- "rI" ((USItype)(bh)), \
- "rJ" ((USItype)(al)), \
- "rI" ((USItype)(bl)) \
+ : "=r" ((USItype) (sh)), \
+ "=&r" ((USItype) (sl)) \
+ : "rJ" ((USItype) (ah)), \
+ "rI" ((USItype) (bh)), \
+ "rJ" ((USItype) (al)), \
+ "rI" ((USItype) (bl)) \
__CLOBBER_CC)
#if defined (__sparc_v8__)
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("umul %2,%3,%1;rd %%y,%0" \
- : "=r" ((USItype)(w1)), \
- "=r" ((USItype)(w0)) \
- : "r" ((USItype)(u)), \
- "r" ((USItype)(v)))
+ : "=r" ((USItype) (w1)), \
+ "=r" ((USItype) (w0)) \
+ : "r" ((USItype) (u)), \
+ "r" ((USItype) (v)))
#define udiv_qrnnd(q, r, n1, n0, d) \
__asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\
- : "=&r" ((USItype)(q)), \
- "=&r" ((USItype)(r)) \
- : "r" ((USItype)(n1)), \
- "r" ((USItype)(n0)), \
- "r" ((USItype)(d)))
+ : "=&r" ((USItype) (q)), \
+ "=&r" ((USItype) (r)) \
+ : "r" ((USItype) (n1)), \
+ "r" ((USItype) (n0)), \
+ "r" ((USItype) (d)))
#else
#if defined (__sparclite__)
/* This has hardware multiply but not divide. It also has two additional
instructions scan (ffs from high bit) and divscc. */
#define umul_ppmm(w1, w0, u, v) \
__asm__ ("umul %2,%3,%1;rd %%y,%0" \
- : "=r" ((USItype)(w1)), \
- "=r" ((USItype)(w0)) \
- : "r" ((USItype)(u)), \
- "r" ((USItype)(v)))
+ : "=r" ((USItype) (w1)), \
+ "=r" ((USItype) (w0)) \
+ : "r" ((USItype) (u)), \
+ "r" ((USItype) (v)))
#define udiv_qrnnd(q, r, n1, n0, d) \
__asm__ ("! Inlined udiv_qrnnd
wr %%g0,%2,%%y ! Not a delayed write for sparclite
@@ -895,17 +970,17 @@
bl,a 1f
add %1,%4,%1
1: ! End of inline udiv_qrnnd" \
- : "=r" ((USItype)(q)), \
- "=r" ((USItype)(r)) \
- : "r" ((USItype)(n1)), \
- "r" ((USItype)(n0)), \
- "rI" ((USItype)(d)) \
+ : "=r" ((USItype) (q)), \
+ "=r" ((USItype) (r)) \
+ : "r" ((USItype) (n1)), \
+ "r" ((USItype) (n0)), \
+ "rI" ((USItype) (d)) \
: "%g1" __AND_CLOBBER_CC)
#define UDIV_TIME 37
#define count_leading_zeros(count, x) \
__asm__ ("scan %1,0,%0" \
- : "=r" ((USItype)(x)) \
- : "r" ((USItype)(count)))
+ : "=r" ((USItype) (x)) \
+ : "r" ((USItype) (count)))
#else
/* SPARC without integer multiplication and divide instructions.
(i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */
@@ -950,10 +1025,10 @@
mulscc %%g1,0,%%g1
add %%g1,%%g2,%0
rd %%y,%1" \
- : "=r" ((USItype)(w1)), \
- "=r" ((USItype)(w0)) \
- : "%rI" ((USItype)(u)), \
- "r" ((USItype)(v)) \
+ : "=r" ((USItype) (w1)), \
+ "=r" ((USItype) (w0)) \
+ : "%rI" ((USItype) (u)), \
+ "r" ((USItype) (v)) \
: "%g1", "%g2" __AND_CLOBBER_CC)
#define UMUL_TIME 39 /* 39 instructions */
/* It's quite necessary to add this much assembler for the sparc.
@@ -983,11 +1058,11 @@
sub %1,%2,%1
3: xnor %0,0,%0
! End of inline udiv_qrnnd" \
- : "=&r" ((USItype)(q)), \
- "=&r" ((USItype)(r)) \
- : "r" ((USItype)(d)), \
- "1" ((USItype)(n1)), \
- "0" ((USItype)(n0)) : "%g1" __AND_CLOBBER_CC)
+ : "=&r" ((USItype) (q)), \
+ "=&r" ((USItype) (r)) \
+ : "r" ((USItype) (d)), \
+ "1" ((USItype) (n1)), \
+ "0" ((USItype) (n0)) : "%g1" __AND_CLOBBER_CC)
#define UDIV_TIME (3+7*32) /* 7 instructions/iteration. 32 iterations. */
#endif /* __sparclite__ */
#endif /* __sparc_v8__ */
@@ -997,21 +1072,21 @@
#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
__asm__ ("addl2 %5,%1
adwc %3,%0" \
- : "=g" ((USItype)(sh)), \
- "=&g" ((USItype)(sl)) \
- : "%0" ((USItype)(ah)), \
- "g" ((USItype)(bh)), \
- "%1" ((USItype)(al)), \
- "g" ((USItype)(bl)))
+ : "=g" ((USItype) (sh)), \
+ "=&g" ((USItype) (sl)) \
+ : "%0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "%1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
__asm__ ("subl2 %5,%1
sbwc %3,%0" \
- : "=g" ((USItype)(sh)), \
- "=&g" ((USItype)(sl)) \
- : "0" ((USItype)(ah)), \
- "g" ((USItype)(bh)), \
- "1" ((USItype)(al)), \
- "g" ((USItype)(bl)))
+ : "=g" ((USItype) (sh)), \
+ "=&g" ((USItype) (sl)) \
+ : "0" ((USItype) (ah)), \
+ "g" ((USItype) (bh)), \
+ "1" ((USItype) (al)), \
+ "g" ((USItype) (bl)))
#define umul_ppmm(xh, xl, m0, m1) \
do { \
union { \
@@ -1161,9 +1236,9 @@ extern const UQItype __clz_tab[];
\
if (SI_TYPE_SIZE <= 32) \
{ \
- __a = __xr < (1<<2*__BITS4) \
- ? (__xr < (1<<__BITS4) ? 0 : __BITS4) \
- : (__xr < (1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \
+ __a = __xr < ((USItype)1<<2*__BITS4) \
+ ? (__xr < ((USItype)1<<__BITS4) ? 0 : __BITS4) \
+ : (__xr < ((USItype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \
} \
else \
{ \
diff --git a/contrib/gcc/loop.c b/contrib/gcc/loop.c
index 338f968..04c8083 100644
--- a/contrib/gcc/loop.c
+++ b/contrib/gcc/loop.c
@@ -1,5 +1,5 @@
/* Perform various loop optimizations, including strength reduction.
- Copyright (C) 1987, 88, 89, 91-4, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 91-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -34,8 +34,8 @@ Boston, MA 02111-1307, USA. */
Most of the complexity is in heuristics to decide when it is worth
while to do these things. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "obstack.h"
#include "expr.h"
@@ -47,6 +47,8 @@ Boston, MA 02111-1307, USA. */
#include "flags.h"
#include "real.h"
#include "loop.h"
+#include "except.h"
+#include "toplev.h"
/* Vector mapping INSN_UIDs to luids.
The luids are like uids but increase monotonically always.
@@ -80,6 +82,35 @@ static rtx *loop_number_loop_starts, *loop_number_loop_ends;
int *loop_outer_loop;
+#ifdef HAIFA
+/* The main output of analyze_loop_iterations is placed here */
+
+int *loop_can_insert_bct;
+
+/* For each loop, determines whether some of its inner loops has used
+ count register */
+
+int *loop_used_count_register;
+
+/* loop parameters for arithmetic loops. These loops have a loop variable
+ which is initialized to loop_start_value, incremented in each iteration
+ by "loop_increment". At the end of the iteration the loop variable is
+ compared to the loop_comparison_value (using loop_comparison_code). */
+
+rtx *loop_increment;
+rtx *loop_comparison_value;
+rtx *loop_start_value;
+enum rtx_code *loop_comparison_code;
+#endif /* HAIFA */
+
+/* For each loop, keep track of its unrolling factor.
+ Potential values:
+ 0: unrolled
+ 1: not unrolled.
+ -1: completely unrolled
+ >0: holds the unroll exact factor. */
+int *loop_unroll_factor;
+
/* Indexed by loop number, contains a nonzero value if the "loop" isn't
really a loop (an insn outside the loop branches into it). */
@@ -105,13 +136,12 @@ int *loop_number_exit_count;
/* Holds the number of loop iterations. It is zero if the number could not be
calculated. Must be unsigned since the number of iterations can
be as high as 2^wordsize-1. For loops with a wider iterator, this number
- will will be zero if the number of loop iterations is too large for an
+ will be zero if the number of loop iterations is too large for an
unsigned integer to hold. */
unsigned HOST_WIDE_INT loop_n_iterations;
-/* Nonzero if there is a subroutine call in the current loop.
- (unknown_address_altered is also nonzero in this case.) */
+/* Nonzero if there is a subroutine call in the current loop. */
static int loop_has_call;
@@ -138,13 +168,13 @@ static rtx loop_continue;
Therefore, at all times, == 0 indicates an invariant register;
< 0 a conditionally invariant one. */
-static short *n_times_set;
+static int *n_times_set;
/* Original value of n_times_set; same except that this value
is not set negative for a reg whose sets have been made candidates
and not set to 0 for a reg that is moved. */
-static short *n_times_used;
+static int *n_times_used;
/* Index by register number, 1 indicates that the register
cannot be moved or strength reduced. */
@@ -159,12 +189,15 @@ static char *moved_once;
/* Array of MEMs that are stored in this loop. If there are too many to fit
here, we just turn on unknown_address_altered. */
-#define NUM_STORES 20
+#define NUM_STORES 30
static rtx loop_store_mems[NUM_STORES];
/* Index of first available slot in above array. */
static int loop_store_mems_idx;
+/* The insn where the first of these was found. */
+static rtx first_loop_store_insn;
+
/* Nonzero if we don't know what MEMs were changed in the current loop.
This happens if the loop contains a call (in which case `loop_has_call'
will also be set) or if we store into more than NUM_STORES MEMs. */
@@ -197,8 +230,6 @@ extern struct obstack *rtl_obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-
-extern char *oballoc ();
/* During the analysis of a loop, a chain of `struct movable's
is made to record all the movable insns found.
@@ -207,10 +238,10 @@ extern char *oballoc ();
struct movable
{
rtx insn; /* A movable insn */
- rtx set_src; /* The expression this reg is set from. */
- rtx set_dest; /* The destination of this SET. */
+ rtx set_src; /* The expression this reg is set from. */
+ rtx set_dest; /* The destination of this SET. */
rtx dependencies; /* When INSN is libcall, this is an EXPR_LIST
- of any registers used within the LIBCALL. */
+ of any registers used within the LIBCALL. */
int consec; /* Number of consecutive following insns
that must be moved with this one. */
int regno; /* The register it sets */
@@ -233,7 +264,9 @@ struct movable
invariant. */
unsigned int move_insn : 1; /* 1 means that we call emit_move_insn to
load SRC, rather than copying INSN. */
- unsigned int is_equiv : 1; /* 1 means a REG_EQUIV is present on INSN. */
+ unsigned int move_insn_first:1;/* Same as above, if this is necessary for the
+ first insn of a consecutive sets group. */
+ unsigned int is_equiv : 1; /* 1 means a REG_EQUIV is present on INSN. */
enum machine_mode savemode; /* Nonzero means it is a mode for a low part
that we should avoid changing when clearing
the rest of the reg. */
@@ -246,46 +279,77 @@ FILE *loop_dump_stream;
/* Forward declarations. */
-static void find_and_verify_loops ();
-static void mark_loop_jump ();
-static void prescan_loop ();
-static int reg_in_basic_block_p ();
-static int consec_sets_invariant_p ();
-static rtx libcall_other_reg ();
-static int labels_in_range_p ();
-static void count_loop_regs_set ();
-static void note_addr_stored ();
-static int loop_reg_used_before_p ();
-static void scan_loop ();
-static void replace_call_address ();
-static rtx skip_consec_insns ();
-static int libcall_benefit ();
-static void ignore_some_movables ();
-static void force_movables ();
-static void combine_movables ();
-static int rtx_equal_for_loop_p ();
-static void move_movables ();
-static void strength_reduce ();
-static int valid_initial_value_p ();
-static void find_mem_givs ();
-static void record_biv ();
-static void check_final_value ();
-static void record_giv ();
-static void update_giv_derive ();
-static int basic_induction_var ();
-static rtx simplify_giv_expr ();
-static int general_induction_var ();
-static int consec_sets_giv ();
-static int check_dbra_loop ();
-static rtx express_from ();
-static int combine_givs_p ();
-static void combine_givs ();
-static int product_cheap_p ();
-static int maybe_eliminate_biv ();
-static int maybe_eliminate_biv_1 ();
-static int last_use_this_basic_block ();
-static void record_initial ();
-static void update_reg_last_use ();
+static void find_and_verify_loops PROTO((rtx));
+static void mark_loop_jump PROTO((rtx, int));
+static void prescan_loop PROTO((rtx, rtx));
+static int reg_in_basic_block_p PROTO((rtx, rtx));
+static int consec_sets_invariant_p PROTO((rtx, int, rtx));
+static rtx libcall_other_reg PROTO((rtx, rtx));
+static int labels_in_range_p PROTO((rtx, int));
+static void count_loop_regs_set PROTO((rtx, rtx, char *, rtx *, int *, int));
+static void note_addr_stored PROTO((rtx, rtx));
+static int loop_reg_used_before_p PROTO((rtx, rtx, rtx, rtx, rtx));
+static void scan_loop PROTO((rtx, rtx, int, int));
+#if 0
+static void replace_call_address PROTO((rtx, rtx, rtx));
+#endif
+static rtx skip_consec_insns PROTO((rtx, int));
+static int libcall_benefit PROTO((rtx));
+static void ignore_some_movables PROTO((struct movable *));
+static void force_movables PROTO((struct movable *));
+static void combine_movables PROTO((struct movable *, int));
+static int regs_match_p PROTO((rtx, rtx, struct movable *));
+static int rtx_equal_for_loop_p PROTO((rtx, rtx, struct movable *));
+static void add_label_notes PROTO((rtx, rtx));
+static void move_movables PROTO((struct movable *, int, int, rtx, rtx, int));
+static int count_nonfixed_reads PROTO((rtx));
+static void strength_reduce PROTO((rtx, rtx, rtx, int, rtx, rtx, int));
+static void find_single_use_in_loop PROTO((rtx, rtx, rtx *));
+static int valid_initial_value_p PROTO((rtx, rtx, int, rtx));
+static void find_mem_givs PROTO((rtx, rtx, int, rtx, rtx));
+static void record_biv PROTO((struct induction *, rtx, rtx, rtx, rtx, int, int));
+static void check_final_value PROTO((struct induction *, rtx, rtx));
+static void record_giv PROTO((struct induction *, rtx, rtx, rtx, rtx, rtx, int, enum g_types, int, rtx *, rtx, rtx));
+static void update_giv_derive PROTO((rtx));
+static int basic_induction_var PROTO((rtx, enum machine_mode, rtx, rtx, rtx *, rtx *));
+static rtx simplify_giv_expr PROTO((rtx, int *));
+static int general_induction_var PROTO((rtx, rtx *, rtx *, rtx *));
+static int consec_sets_giv PROTO((int, rtx, rtx, rtx, rtx *, rtx *));
+static int check_dbra_loop PROTO((rtx, int, rtx));
+#ifdef ADDRESS_COST
+static rtx express_from PROTO((struct induction *, struct induction *));
+#endif
+static int combine_givs_p PROTO((struct induction *, struct induction *));
+#ifdef GIV_SORT_CRITERION
+static int giv_sort PROTO((struct induction **, struct induction **));
+#endif
+static void combine_givs PROTO((struct iv_class *));
+static int product_cheap_p PROTO((rtx, rtx));
+static int maybe_eliminate_biv PROTO((struct iv_class *, rtx, rtx, int, int, int));
+static int maybe_eliminate_biv_1 PROTO((rtx, rtx, struct iv_class *, int, rtx));
+static int last_use_this_basic_block PROTO((rtx, rtx));
+static void record_initial PROTO((rtx, rtx));
+static void update_reg_last_use PROTO((rtx, rtx));
+
+#ifdef HAIFA
+/* This is extern from unroll.c */
+extern void iteration_info PROTO((rtx, rtx *, rtx *, rtx, rtx));
+
+/* Two main functions for implementing bct:
+ first - to be called before loop unrolling, and the second - after */
+#ifdef HAVE_decrement_and_branch_on_count
+static void analyze_loop_iterations PROTO((rtx, rtx));
+static void insert_bct PROTO((rtx, rtx));
+
+/* Auxiliary function that inserts the bct pattern into the loop */
+static void instrument_loop_bct PROTO((rtx, rtx, rtx));
+#endif /* HAVE_decrement_and_branch_on_count */
+#endif /* HAIFA */
+
+/* Indirect_jump_in_function is computed once per function. */
+int indirect_jump_in_function = 0;
+static int indirect_jump_in_function_p PROTO((rtx));
+
/* Relative gain of eliminating various kinds of operations. */
int add_cost;
@@ -302,9 +366,9 @@ void
init_loop ()
{
char *free_point = (char *) oballoc (1);
- rtx reg = gen_rtx (REG, word_mode, 0);
+ rtx reg = gen_rtx_REG (word_mode, LAST_VIRTUAL_REGISTER + 1);
- add_cost = rtx_cost (gen_rtx (PLUS, word_mode, reg, reg), SET);
+ add_cost = rtx_cost (gen_rtx_PLUS (word_mode, reg, reg), SET);
/* We multiply by 2 to reconcile the difference in scale between
these two ways of computing costs. Otherwise the cost of a copy
@@ -325,10 +389,11 @@ init_loop ()
(or 0 if none should be output). */
void
-loop_optimize (f, dumpfile)
+loop_optimize (f, dumpfile, unroll_p)
/* f is the first instruction of a chain of insns for one function */
rtx f;
FILE *dumpfile;
+ int unroll_p;
{
register rtx insn;
register int i;
@@ -337,7 +402,6 @@ loop_optimize (f, dumpfile)
loop_dump_stream = dumpfile;
init_recog_no_volatile ();
- init_alias_analysis ();
max_reg_before_loop = max_reg_num ();
@@ -346,7 +410,7 @@ loop_optimize (f, dumpfile)
regs_may_share = 0;
- /* Count the number of loops. */
+ /* Count the number of loops. */
max_loop_num = 0;
for (insn = f; insn; insn = NEXT_INSN (insn))
@@ -379,6 +443,32 @@ loop_optimize (f, dumpfile)
loop_number_exit_labels = (rtx *) alloca (max_loop_num * sizeof (rtx));
loop_number_exit_count = (int *) alloca (max_loop_num * sizeof (int));
+ /* This is initialized by the unrolling code, so we go ahead
+ and clear them just in case we are not performing loop
+ unrolling. */
+ loop_unroll_factor = (int *) alloca (max_loop_num *sizeof (int));
+ bzero ((char *) loop_unroll_factor, max_loop_num * sizeof (int));
+
+#ifdef HAIFA
+ /* Allocate for BCT optimization */
+ loop_can_insert_bct = (int *) alloca (max_loop_num * sizeof (int));
+ bzero ((char *) loop_can_insert_bct, max_loop_num * sizeof (int));
+
+ loop_used_count_register = (int *) alloca (max_loop_num * sizeof (int));
+ bzero ((char *) loop_used_count_register, max_loop_num * sizeof (int));
+
+ loop_increment = (rtx *) alloca (max_loop_num * sizeof (rtx));
+ loop_comparison_value = (rtx *) alloca (max_loop_num * sizeof (rtx));
+ loop_start_value = (rtx *) alloca (max_loop_num * sizeof (rtx));
+ bzero ((char *) loop_increment, max_loop_num * sizeof (rtx));
+ bzero ((char *) loop_comparison_value, max_loop_num * sizeof (rtx));
+ bzero ((char *) loop_start_value, max_loop_num * sizeof (rtx));
+
+ loop_comparison_code
+ = (enum rtx_code *) alloca (max_loop_num * sizeof (enum rtx_code));
+ bzero ((char *) loop_comparison_code, max_loop_num * sizeof (enum rtx_code));
+#endif /* HAIFA */
+
/* Find and process each loop.
First, find them, and record them in order of their beginnings. */
find_and_verify_loops (f);
@@ -388,9 +478,18 @@ loop_optimize (f, dumpfile)
function. */
reg_scan (f, max_reg_num (), 1);
+ /* This must occur after reg_scan so that registers created by gcse
+ will have entries in the register tables.
+
+ We could have added a call to reg_scan after gcse_main in toplev.c,
+ but moving this call to init_alias_analysis is more efficient. */
+ init_alias_analysis ();
+
/* See if we went too far. */
if (get_max_uid () > max_uid_for_loop)
abort ();
+ /* Now reset it to the actual size we need. See above. */
+ max_uid_for_loop = get_max_uid () + 1;
/* Compute the mapping from uids to luids.
LUIDs are numbers assigned to insns, like uids,
@@ -427,20 +526,24 @@ loop_optimize (f, dumpfile)
uid_luid[i] = uid_luid[i - 1];
/* Create a mapping from loops to BLOCK tree nodes. */
- if (flag_unroll_loops && write_symbols != NO_DEBUG)
+ if (unroll_p && write_symbols != NO_DEBUG)
find_loop_tree_blocks ();
+ /* Determine if the function has indirect jump. On some systems
+ this prevents low overhead loop instructions from being used. */
+ indirect_jump_in_function = indirect_jump_in_function_p (f);
+
/* Now scan the loops, last ones first, since this means inner ones are done
before outer ones. */
for (i = max_loop_num-1; i >= 0; i--)
if (! loop_invalid[i] && loop_number_loop_ends[i])
scan_loop (loop_number_loop_starts[i], loop_number_loop_ends[i],
- max_reg_num ());
+ max_reg_num (), unroll_p);
/* If debugging and unrolling loops, we must replicate the tree nodes
corresponding to the blocks inside the loop, so that the original one
to one mapping will remain. */
- if (flag_unroll_loops && write_symbols != NO_DEBUG)
+ if (unroll_p && write_symbols != NO_DEBUG)
unroll_block_trees ();
}
@@ -455,9 +558,10 @@ loop_optimize (f, dumpfile)
write, then we can also mark the memory read as invariant. */
static void
-scan_loop (loop_start, end, nregs)
+scan_loop (loop_start, end, nregs, unroll_p)
rtx loop_start, end;
int nregs;
+ int unroll_p;
{
register int i;
register rtx p;
@@ -496,8 +600,8 @@ scan_loop (loop_start, end, nregs)
/* Nonzero if we are scanning instructions in a sub-loop. */
int loop_depth = 0;
- n_times_set = (short *) alloca (nregs * sizeof (short));
- n_times_used = (short *) alloca (nregs * sizeof (short));
+ n_times_set = (int *) alloca (nregs * sizeof (int));
+ n_times_used = (int *) alloca (nregs * sizeof (int));
may_not_optimize = (char *) alloca (nregs);
/* Determine whether this loop starts with a jump down to a test at
@@ -580,7 +684,7 @@ scan_loop (loop_start, end, nregs)
the setting of register I. If this loop has calls, set
reg_single_usage[I]. */
- bzero ((char *) n_times_set, nregs * sizeof (short));
+ bzero ((char *) n_times_set, nregs * sizeof (int));
bzero (may_not_optimize, nregs);
if (loop_has_call)
@@ -594,7 +698,7 @@ scan_loop (loop_start, end, nregs)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
may_not_optimize[i] = 1, n_times_set[i] = 1;
- bcopy ((char *) n_times_set, (char *) n_times_used, nregs * sizeof (short));
+ bcopy ((char *) n_times_set, (char *) n_times_used, nregs * sizeof (int));
if (loop_dump_stream)
{
@@ -685,19 +789,14 @@ scan_loop (loop_start, end, nregs)
We don't know its life-span, so we can't compute the benefit. */
if (REGNO (SET_DEST (set)) >= max_reg_before_loop)
;
- /* In order to move a register, we need to have one of three cases:
+ /* In order to move a register, we need to have either:
(1) it is used only in the same basic block as the set
- (2) it is not a user variable and it is not used in the
- exit test (this can cause the variable to be used
- before it is set just like a user-variable).
- (3) the set is guaranteed to be executed once the loop starts,
+ (2) the set is guaranteed to be executed once the loop starts,
and the reg is not used until after that. */
- else if (! ((! maybe_never
- && ! loop_reg_used_before_p (set, p, loop_start,
- scan_start, end))
- || (! REG_USERVAR_P (SET_DEST (set))
- && ! REG_LOOP_TEST_P (SET_DEST (set)))
- || reg_in_basic_block_p (p, SET_DEST (set))))
+ else if (! (reg_in_basic_block_p (p, SET_DEST (set))
+ || (! maybe_never
+ && ! loop_reg_used_before_p (set, p, loop_start,
+ scan_start, end))))
;
else if ((tem = invariant_p (src))
&& (dependencies == 0
@@ -734,16 +833,15 @@ scan_loop (loop_start, end, nregs)
if (reg_single_usage && reg_single_usage[regno] != 0
&& reg_single_usage[regno] != const0_rtx
- && regno_first_uid[regno] == INSN_UID (p)
- && (regno_last_uid[regno]
+ && REGNO_FIRST_UID (regno) == INSN_UID (p)
+ && (REGNO_LAST_UID (regno)
== INSN_UID (reg_single_usage[regno]))
&& n_times_set[REGNO (SET_DEST (set))] == 1
&& ! side_effects_p (SET_SRC (set))
&& ! find_reg_note (p, REG_RETVAL, NULL_RTX)
-#ifdef SMALL_REGISTER_CLASSES
- && ! (GET_CODE (SET_SRC (set)) == REG
- && REGNO (SET_SRC (set)) < FIRST_PSEUDO_REGISTER)
-#endif
+ && (! SMALL_REGISTER_CLASSES
+ || (! (GET_CODE (SET_SRC (set)) == REG
+ && REGNO (SET_SRC (set)) < FIRST_PSEUDO_REGISTER)))
/* This test is not redundant; SET_SRC (set) might be
a call-clobbered register and the life of REGNO
might span a call. */
@@ -779,17 +877,18 @@ scan_loop (loop_start, end, nregs)
m->forces = 0;
m->partial = 0;
m->move_insn = move_insn;
+ m->move_insn_first = 0;
m->is_equiv = (find_reg_note (p, REG_EQUIV, NULL_RTX) != 0);
m->savemode = VOIDmode;
m->regno = regno;
/* Set M->cond if either invariant_p or consec_sets_invariant_p
returned 2 (only conditionally invariant). */
m->cond = ((tem | tem1 | tem2) > 1);
- m->global = (uid_luid[regno_last_uid[regno]] > INSN_LUID (end)
- || uid_luid[regno_first_uid[regno]] < INSN_LUID (loop_start));
+ m->global = (uid_luid[REGNO_LAST_UID (regno)] > INSN_LUID (end)
+ || uid_luid[REGNO_FIRST_UID (regno)] < INSN_LUID (loop_start));
m->match = 0;
- m->lifetime = (uid_luid[regno_last_uid[regno]]
- - uid_luid[regno_first_uid[regno]]);
+ m->lifetime = (uid_luid[REGNO_LAST_UID (regno)]
+ - uid_luid[REGNO_FIRST_UID (regno)]);
m->savings = n_times_used[regno];
if (find_reg_note (p, REG_RETVAL, NULL_RTX))
m->savings += libcall_benefit (p);
@@ -803,6 +902,12 @@ scan_loop (loop_start, end, nregs)
if (m->consec > 0)
{
+ /* It is possible for the first instruction to have a
+ REG_EQUAL note but a non-invariant SET_SRC, so we must
+ remember the status of the first instruction in case
+ the last instruction doesn't have a REG_EQUAL note. */
+ m->move_insn_first = m->move_insn;
+
/* Skip this insn, not checking REG_LIBCALL notes. */
p = next_nonnote_insn (p);
/* Skip the consecutive insns, if there are any. */
@@ -859,6 +964,7 @@ scan_loop (loop_start, end, nregs)
m->done = 0;
m->forces = 0;
m->move_insn = 0;
+ m->move_insn_first = 0;
m->partial = 1;
/* If the insn may not be executed on some cycles,
we can't clear the whole reg; clear just high part.
@@ -877,14 +983,14 @@ scan_loop (loop_start, end, nregs)
If this insn was made by loop, we don't know its
INSN_LUID and hence must make a conservative
- assumption. */
+ assumption. */
m->global = (INSN_UID (p) >= max_uid_for_loop
- || (uid_luid[regno_last_uid[regno]]
+ || (uid_luid[REGNO_LAST_UID (regno)]
> INSN_LUID (end))
- || (uid_luid[regno_first_uid[regno]]
+ || (uid_luid[REGNO_FIRST_UID (regno)]
< INSN_LUID (p))
|| (labels_in_range_p
- (p, uid_luid[regno_first_uid[regno]])));
+ (p, uid_luid[REGNO_FIRST_UID (regno)])));
if (maybe_never && m->global)
m->savemode = GET_MODE (SET_SRC (set1));
else
@@ -892,8 +998,8 @@ scan_loop (loop_start, end, nregs)
m->regno = regno;
m->cond = 0;
m->match = 0;
- m->lifetime = (uid_luid[regno_last_uid[regno]]
- - uid_luid[regno_first_uid[regno]]);
+ m->lifetime = (uid_luid[REGNO_LAST_UID (regno)]
+ - uid_luid[REGNO_FIRST_UID (regno)]);
m->savings = 1;
n_times_set[regno] = -1;
/* Add M to the end of the chain MOVABLES. */
@@ -916,8 +1022,7 @@ scan_loop (loop_start, end, nregs)
executed during each iteration. Therefore, we can
only move out sets of trivial variables
(those not used after the loop). */
- /* This code appears in three places, once in scan_loop, and twice
- in strength_reduce. */
+ /* Similar code appears twice in strength_reduce. */
else if ((GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
/* If we enter the loop in the middle, and scan around to the
beginning, don't set maybe_never for that. This must be an
@@ -961,10 +1066,14 @@ scan_loop (loop_start, end, nregs)
combine_movables (movables, nregs);
/* Now consider each movable insn to decide whether it is worth moving.
- Store 0 in n_times_set for each reg that is moved. */
+ Store 0 in n_times_set for each reg that is moved.
- move_movables (movables, threshold,
- insn_count, loop_start, end, nregs);
+ Generally this increases code size, so do not move moveables when
+ optimizing for code size. */
+
+ if (! optimize_size)
+ move_movables (movables, threshold,
+ insn_count, loop_start, end, nregs);
/* Now candidates that still are negative are those not moved.
Change n_times_set to indicate that those are not actually invariant. */
@@ -974,7 +1083,7 @@ scan_loop (loop_start, end, nregs)
if (flag_strength_reduce)
strength_reduce (scan_start, end, loop_top,
- insn_count, loop_start, end);
+ insn_count, loop_start, end, unroll_p);
}
/* Add elements to *OUTPUT to record all the pseudo-regs
@@ -1005,8 +1114,11 @@ record_excess_regs (in_this, not_in_this, output)
case REG:
if (REGNO (in_this) >= FIRST_PSEUDO_REGISTER
&& ! reg_mentioned_p (in_this, not_in_this))
- *output = gen_rtx (EXPR_LIST, VOIDmode, in_this, *output);
+ *output = gen_rtx_EXPR_LIST (VOIDmode, in_this, *output);
return;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -1065,7 +1177,7 @@ reg_in_basic_block_p (insn, reg)
int regno = REGNO (reg);
rtx p;
- if (regno_first_uid[regno] != INSN_UID (insn))
+ if (REGNO_FIRST_UID (regno) != INSN_UID (insn))
return 0;
/* Search this basic block for the already recorded last use of the reg. */
@@ -1079,13 +1191,13 @@ reg_in_basic_block_p (insn, reg)
case INSN:
case CALL_INSN:
/* Ordinary insn: if this is the last use, we win. */
- if (regno_last_uid[regno] == INSN_UID (p))
+ if (REGNO_LAST_UID (regno) == INSN_UID (p))
return 1;
break;
case JUMP_INSN:
/* Jump insn: if this is the last use, we win. */
- if (regno_last_uid[regno] == INSN_UID (p))
+ if (REGNO_LAST_UID (regno) == INSN_UID (p))
return 1;
/* Otherwise, it's the end of the basic block, so we lose. */
return 0;
@@ -1094,6 +1206,9 @@ reg_in_basic_block_p (insn, reg)
case BARRIER:
/* It's the end of the basic block, so we lose. */
return 0;
+
+ default:
+ break;
}
}
@@ -1117,7 +1232,7 @@ libcall_benefit (last)
{
if (GET_CODE (insn) == CALL_INSN)
benefit += 10; /* Assume at least this many insns in a library
- routine. */
+ routine. */
else if (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) != USE
&& GET_CODE (PATTERN (insn)) != CLOBBER)
@@ -1206,7 +1321,7 @@ force_movables (movables)
this insn M->insn might not be where it dies.
But very likely this doesn't matter; what matters is
that M's reg is computed from M1's reg. */
- if (INSN_UID (m->insn) == regno_last_uid[regno]
+ if (INSN_UID (m->insn) == REGNO_LAST_UID (regno)
&& !m->done)
break;
if (m != 0 && m->set_src == m1->set_dest
@@ -1220,7 +1335,7 @@ force_movables (movables)
{
m->forces = m1;
m1->lifetime += m->lifetime;
- m1->savings += m1->savings;
+ m1->savings += m->savings;
}
}
}
@@ -1250,7 +1365,9 @@ combine_movables (movables, nregs)
bzero (matched_regs, nregs);
matched_regs[regno] = 1;
- for (m1 = movables; m1; m1 = m1->next)
+ /* We want later insns to match the first one. Don't make the first
+ one match any later ones. So start this loop at m->next. */
+ for (m1 = m->next; m1; m1 = m1->next)
if (m != m1 && m1->match == 0 && n_times_used[m1->regno] == 1
/* A reg used outside the loop mustn't be eliminated. */
&& !m1->global
@@ -1303,8 +1420,8 @@ combine_movables (movables, nregs)
&& mode == GET_MODE (SET_SRC (PATTERN (NEXT_INSN (m->insn)))))
{
register struct movable *m1;
- int first = uid_luid[regno_first_uid[m->regno]];
- int last = uid_luid[regno_last_uid[m->regno]];
+ int first = uid_luid[REGNO_FIRST_UID (m->regno)];
+ int last = uid_luid[REGNO_LAST_UID (m->regno)];
if (m0 == 0)
{
@@ -1322,8 +1439,8 @@ combine_movables (movables, nregs)
already combined together. */
for (m1 = movables; m1 != m; m1 = m1->next)
if (m1 == m0 || (m1->partial && m1->match == m0))
- if (! (uid_luid[regno_first_uid[m1->regno]] > last
- || uid_luid[regno_last_uid[m1->regno]] < first))
+ if (! (uid_luid[REGNO_FIRST_UID (m1->regno)] > last
+ || uid_luid[REGNO_LAST_UID (m1->regno)] < first))
goto overlap;
/* No overlap: we can combine this with the others. */
@@ -1390,17 +1507,20 @@ rtx_equal_for_loop_p (x, y, movables)
equal. */
if (GET_CODE (x) == REG && n_times_set[REGNO (x)] == -2
&& CONSTANT_P (y))
- for (m = movables; m; m = m->next)
- if (m->move_insn && m->regno == REGNO (x)
- && rtx_equal_p (m->set_src, y))
- return 1;
-
+ {
+ for (m = movables; m; m = m->next)
+ if (m->move_insn && m->regno == REGNO (x)
+ && rtx_equal_p (m->set_src, y))
+ return 1;
+ }
else if (GET_CODE (y) == REG && n_times_set[REGNO (y)] == -2
&& CONSTANT_P (x))
- for (m = movables; m; m = m->next)
- if (m->move_insn && m->regno == REGNO (y)
- && rtx_equal_p (m->set_src, x))
- return 1;
+ {
+ for (m = movables; m; m = m->next)
+ if (m->move_insn && m->regno == REGNO (y)
+ && rtx_equal_p (m->set_src, x))
+ return 1;
+ }
/* Otherwise, rtx's of different codes cannot be equal. */
if (code != GET_CODE (y))
@@ -1492,22 +1612,15 @@ add_label_notes (x, insns)
if (code == LABEL_REF && !LABEL_REF_NONLOCAL_P (x))
{
- rtx next = next_real_insn (XEXP (x, 0));
-
- /* Don't record labels that refer to dispatch tables.
- This is not necessary, since the tablejump references the same label.
- And if we did record them, flow.c would make worse code. */
- if (next == 0
- || ! (GET_CODE (next) == JUMP_INSN
- && (GET_CODE (PATTERN (next)) == ADDR_VEC
- || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC)))
- {
- for (insn = insns; insn; insn = NEXT_INSN (insn))
- if (reg_mentioned_p (XEXP (x, 0), insn))
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_LABEL, XEXP (x, 0),
- REG_NOTES (insn));
- }
- return;
+ /* This code used to ignore labels that referred to dispatch tables to
+ avoid flow generating (slighly) worse code.
+
+ We no longer ignore such label references (see LABEL_REF handling in
+ mark_jump_label for additional information). */
+ for (insn = insns; insn; insn = NEXT_INSN (insn))
+ if (reg_mentioned_p (XEXP (x, 0), insn))
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL, XEXP (x, 0),
+ REG_NOTES (insn));
}
fmt = GET_RTX_FORMAT (code);
@@ -1628,6 +1741,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
extra cost because something else was already moved. */
if (already_moved[regno]
+ || flag_move_all_movables
|| (threshold * savings * m->lifetime) >= insn_count
|| (m->forces && m->forces->done
&& n_times_used[m->forces->regno] == 1))
@@ -1656,9 +1770,10 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
REG_NOTES (i1) = REG_NOTES (m->insn);
r1 = SET_DEST (PATTERN (m->insn));
r2 = SET_DEST (PATTERN (m1->insn));
- regs_may_share = gen_rtx (EXPR_LIST, VOIDmode, r1,
- gen_rtx (EXPR_LIST, VOIDmode, r2,
- regs_may_share));
+ regs_may_share
+ = gen_rtx_EXPR_LIST (VOIDmode, r1,
+ gen_rtx_EXPR_LIST (VOIDmode, r2,
+ regs_may_share));
delete_insn (m->insn);
if (new_start == 0)
@@ -1708,9 +1823,8 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
i1 = emit_insns_before (temp, loop_start);
if (! find_reg_note (i1, REG_EQUAL, NULL_RTX))
REG_NOTES (i1)
- = gen_rtx (EXPR_LIST,
- m->is_equiv ? REG_EQUIV : REG_EQUAL,
- m->set_src, REG_NOTES (i1));
+ = gen_rtx_EXPR_LIST (m->is_equiv ? REG_EQUIV : REG_EQUAL,
+ m->set_src, REG_NOTES (i1));
if (loop_dump_stream)
fprintf (loop_dump_stream, " moved to %d", INSN_UID (i1));
@@ -1724,7 +1838,7 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
{
rtx i1, temp;
- /* If first insn of libcall sequence, skip to end. */
+ /* If first insn of libcall sequence, skip to end. */
/* Do this at start of loop, since p is guaranteed to
be an insn here. */
if (GET_CODE (p) != NOTE
@@ -1803,8 +1917,8 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
contains objects other than hard registers
we need to copy it. */
if (CALL_INSN_FUNCTION_USAGE (temp))
- CALL_INSN_FUNCTION_USAGE (i1) =
- copy_rtx (CALL_INSN_FUNCTION_USAGE (temp));
+ CALL_INSN_FUNCTION_USAGE (i1)
+ = copy_rtx (CALL_INSN_FUNCTION_USAGE (temp));
}
else
i1 = emit_insn_before (body, loop_start);
@@ -1847,23 +1961,44 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
contains objects other than hard registers
we need to copy it. */
if (CALL_INSN_FUNCTION_USAGE (p))
- CALL_INSN_FUNCTION_USAGE (i1) =
- copy_rtx (CALL_INSN_FUNCTION_USAGE (p));
+ CALL_INSN_FUNCTION_USAGE (i1)
+ = copy_rtx (CALL_INSN_FUNCTION_USAGE (p));
+ }
+ else if (count == m->consec && m->move_insn_first)
+ {
+ /* The SET_SRC might not be invariant, so we must
+ use the REG_EQUAL note. */
+ start_sequence ();
+ emit_move_insn (m->set_dest, m->set_src);
+ temp = get_insns ();
+ end_sequence ();
+
+ add_label_notes (m->set_src, temp);
+
+ i1 = emit_insns_before (temp, loop_start);
+ if (! find_reg_note (i1, REG_EQUAL, NULL_RTX))
+ REG_NOTES (i1)
+ = gen_rtx_EXPR_LIST ((m->is_equiv ? REG_EQUIV
+ : REG_EQUAL),
+ m->set_src, REG_NOTES (i1));
}
else
i1 = emit_insn_before (PATTERN (p), loop_start);
- REG_NOTES (i1) = REG_NOTES (p);
+ if (REG_NOTES (i1) == 0)
+ {
+ REG_NOTES (i1) = REG_NOTES (p);
- /* If there is a REG_EQUAL note present whose value is
- not loop invariant, then delete it, since it may
- cause problems with later optimization passes.
- It is possible for cse to create such notes
- like this as a result of record_jump_cond. */
+ /* If there is a REG_EQUAL note present whose value
+ is not loop invariant, then delete it, since it
+ may cause problems with later optimization passes.
+ It is possible for cse to create such notes
+ like this as a result of record_jump_cond. */
- if ((temp = find_reg_note (i1, REG_EQUAL, NULL_RTX))
- && ! invariant_p (XEXP (temp, 0)))
- remove_note (i1, temp);
+ if ((temp = find_reg_note (i1, REG_EQUAL, NULL_RTX))
+ && ! invariant_p (XEXP (temp, 0)))
+ remove_note (i1, temp);
+ }
if (new_start == 0)
new_start = i1;
@@ -1872,23 +2007,10 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
fprintf (loop_dump_stream, " moved to %d",
INSN_UID (i1));
-#if 0
- /* This isn't needed because REG_NOTES is copied
- below and is wrong since P might be a PARALLEL. */
- if (REG_NOTES (i1) == 0
- && ! m->partial /* But not if it's a zero-extend clr. */
- && ! m->global /* and not if used outside the loop
- (since it might get set outside). */
- && CONSTANT_P (SET_SRC (PATTERN (p))))
- REG_NOTES (i1)
- = gen_rtx (EXPR_LIST, REG_EQUAL,
- SET_SRC (PATTERN (p)), REG_NOTES (i1));
-#endif
-
/* If library call, now fix the REG_NOTES that contain
insn pointers, namely REG_LIBCALL on FIRST
and REG_RETVAL on I1. */
- if (temp = find_reg_note (i1, REG_RETVAL, NULL_RTX))
+ if ((temp = find_reg_note (i1, REG_RETVAL, NULL_RTX)))
{
XEXP (temp, 0) = first;
temp = find_reg_note (first, REG_LIBCALL, NULL_RTX);
@@ -1921,13 +2043,13 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
to say it lives at least the full length of this loop.
This will help guide optimizations in outer loops. */
- if (uid_luid[regno_first_uid[regno]] > INSN_LUID (loop_start))
+ if (uid_luid[REGNO_FIRST_UID (regno)] > INSN_LUID (loop_start))
/* This is the old insn before all the moved insns.
We can't use the moved insn because it is out of range
in uid_luid. Only the old insns have luids. */
- regno_first_uid[regno] = INSN_UID (loop_start);
- if (uid_luid[regno_last_uid[regno]] < INSN_LUID (end))
- regno_last_uid[regno] = INSN_UID (end);
+ REGNO_FIRST_UID (regno) = INSN_UID (loop_start);
+ if (uid_luid[REGNO_LAST_UID (regno)] < INSN_LUID (end))
+ REGNO_LAST_UID (regno) = INSN_UID (end);
/* Combine with this moved insn any other matching movables. */
@@ -1954,8 +2076,8 @@ move_movables (movables, threshold, insn_count, loop_start, end, nregs)
/* if library call, delete all insn except last, which
is deleted below */
- if (temp = find_reg_note (m1->insn, REG_RETVAL,
- NULL_RTX))
+ if ((temp = find_reg_note (m1->insn, REG_RETVAL,
+ NULL_RTX)))
{
for (temp = XEXP (temp, 0); temp != m1->insn;
temp = NEXT_INSN (temp))
@@ -2042,6 +2164,9 @@ replace_call_address (x, reg, addr)
abort ();
XEXP (x, 0) = addr;
return;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -2090,6 +2215,9 @@ count_nonfixed_reads (x)
case MEM:
return ((invariant_p (XEXP (x, 0)) != 1)
+ count_nonfixed_reads (XEXP (x, 0)));
+
+ default:
+ break;
}
value = 0;
@@ -2125,9 +2253,9 @@ constant_high_bytes (p, loop_start)
/* Try to change (SET (REG ...) (ZERO_EXTEND (..:B ...)))
to (SET (STRICT_LOW_PART (SUBREG:B (REG...))) ...). */
- new = gen_rtx (SET, VOIDmode,
- gen_rtx (STRICT_LOW_PART, VOIDmode,
- gen_rtx (SUBREG, GET_MODE (XEXP (SET_SRC (PATTERN (p)), 0)),
+ new = gen_rtx_SET (VOIDmode,
+ gen_rtx_STRICT_LOW_PART (VOIDmode,
+ gen_rtx_SUBREG (GET_MODE (XEXP (SET_SRC (PATTERN (p)), 0)),
SET_DEST (PATTERN (p)),
0)),
XEXP (SET_SRC (PATTERN (p)), 0));
@@ -2138,9 +2266,8 @@ constant_high_bytes (p, loop_start)
register int i;
/* Clear destination register before the loop. */
- emit_insn_before (gen_rtx (SET, VOIDmode,
- SET_DEST (PATTERN (p)),
- const0_rtx),
+ emit_insn_before (gen_rtx_SET (VOIDmode, SET_DEST (PATTERN (p)),
+ const0_rtx),
loop_start);
/* Inside the loop, just load the low part. */
@@ -2164,6 +2291,7 @@ prescan_loop (start, end)
unknown_address_altered = 0;
loop_has_call = 0;
loop_has_volatile = 0;
+ first_loop_store_insn = NULL_RTX;
loop_store_mems_idx = 0;
num_mem_sets = 0;
@@ -2198,7 +2326,8 @@ prescan_loop (start, end)
}
else if (GET_CODE (insn) == CALL_INSN)
{
- unknown_address_altered = 1;
+ if (! CONST_CALL_P (insn))
+ unknown_address_altered = 1;
loop_has_call = 1;
}
else
@@ -2209,6 +2338,9 @@ prescan_loop (start, end)
loop_has_volatile = 1;
note_stores (PATTERN (insn), note_addr_stored);
+ if (! first_loop_store_insn && loop_store_mems_idx != 0)
+ first_loop_store_insn = insn;
+
}
}
}
@@ -2271,6 +2403,8 @@ find_and_verify_loops (f)
current_loop = loop_outer_loop[current_loop];
break;
+ default:
+ break;
}
/* Note that this will mark the NOTE_INSN_LOOP_END note as being in the
@@ -2291,6 +2425,19 @@ find_and_verify_loops (f)
loop_invalid[loop_num] = 1;
}
+ /* Any loop containing a label used for an exception handler must be
+ invalidated, because it can be jumped into from anywhere. */
+
+ for (label = exception_handler_labels; label; label = XEXP (label, 1))
+ {
+ int loop_num;
+
+ for (loop_num = uid_loop_num[INSN_UID (XEXP (label, 0))];
+ loop_num != -1;
+ loop_num = loop_outer_loop[loop_num])
+ loop_invalid[loop_num] = 1;
+ }
+
/* Now scan all insn's in the function. If any JUMP_INSN branches into a
loop that it is not contained within, that loop is marked invalid.
If any INSN or CALL_INSN uses a label's address, then the loop containing
@@ -2416,11 +2563,32 @@ find_and_verify_loops (f)
LABEL_NUSES (cond_label)++;
/* Verify that uid_loop_num is large enough and that
- we can invert P. */
+ we can invert P. */
if (invert_jump (p, new_label))
{
rtx q, r;
+ /* If no suitable BARRIER was found, create a suitable
+ one before TARGET. Since TARGET is a fall through
+ path, we'll need to insert an jump around our block
+ and a add a BARRIER before TARGET.
+
+ This creates an extra unconditional jump outside
+ the loop. However, the benefits of removing rarely
+ executed instructions from inside the loop usually
+ outweighs the cost of the extra unconditional jump
+ outside the loop. */
+ if (loc == 0)
+ {
+ rtx temp;
+
+ temp = gen_jump (JUMP_LABEL (insn));
+ temp = emit_jump_insn_before (temp, target);
+ JUMP_LABEL (temp) = JUMP_LABEL (insn);
+ LABEL_NUSES (JUMP_LABEL (insn))++;
+ loc = emit_barrier_before (target);
+ }
+
/* Include the BARRIER after INSN and copy the
block after LOC. */
new_label = squeeze_notes (new_label, NEXT_INSN (insn));
@@ -2459,7 +2627,7 @@ find_and_verify_loops (f)
loop_num = loop_outer_loop[loop_num])
loop_number_exit_count[loop_num]--;
- /* If we didn't find it, then something is wrong. */
+ /* If we didn't find it, then something is wrong. */
if (! r)
abort ();
}
@@ -2533,6 +2701,11 @@ mark_loop_jump (x, loop_num)
mark_loop_jump (XEXP (x, 1), loop_num);
return;
+ case LO_SUM:
+ /* This may refer to a LABEL_REF or SYMBOL_REF. */
+ mark_loop_jump (XEXP (x, 1), loop_num);
+ return;
+
case SIGN_EXTEND:
case ZERO_EXTEND:
mark_loop_jump (XEXP (x, 0), loop_num);
@@ -2620,16 +2793,21 @@ mark_loop_jump (x, loop_num)
return;
default:
- /* Treat anything else (such as a symbol_ref)
- as a branch out of this loop, but not into any loop. */
-
+ /* Strictly speaking this is not a jump into the loop, only a possible
+ jump out of the loop. However, we have no way to link the destination
+ of this jump onto the list of exit labels. To be safe we mark this
+ loop and any containing loops as invalid. */
if (loop_num != -1)
{
- loop_number_exit_labels[loop_num] = x;
-
for (outer_loop = loop_num; outer_loop != -1;
outer_loop = loop_outer_loop[outer_loop])
- loop_number_exit_count[outer_loop]++;
+ {
+ if (loop_dump_stream && ! loop_invalid[outer_loop])
+ fprintf (loop_dump_stream,
+ "\nLoop at %d ignored due to unknown exit jump.\n",
+ INSN_UID (loop_number_loop_starts[outer_loop]));
+ loop_invalid[outer_loop] = 1;
+ }
}
return;
}
@@ -2658,8 +2836,9 @@ labels_in_range_p (insn, end)
/* Record that a memory reference X is being set. */
static void
-note_addr_stored (x)
+note_addr_stored (x, y)
rtx x;
+ rtx y ATTRIBUTE_UNUSED;
{
register int i;
@@ -2747,14 +2926,19 @@ invariant_p (x)
case REG:
/* We used to check RTX_UNCHANGING_P (x) here, but that is invalid
since the reg might be set by initialization within the loop. */
- if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
- || x == arg_pointer_rtx)
+
+ if ((x == frame_pointer_rtx || x == hard_frame_pointer_rtx
+ || x == arg_pointer_rtx)
+ && ! current_function_has_nonlocal_goto)
return 1;
+
if (loop_has_call
&& REGNO (x) < FIRST_PSEUDO_REGISTER && call_used_regs[REGNO (x)])
return 0;
+
if (n_times_set[REGNO (x)] < 0)
return 2;
+
return n_times_set[REGNO (x)] == 0;
case MEM:
@@ -2776,7 +2960,7 @@ invariant_p (x)
/* See if there is any dependence between a store and this load. */
for (i = loop_store_mems_idx - 1; i >= 0; i--)
- if (true_dependence (loop_store_mems[i], x))
+ if (true_dependence (loop_store_mems[i], VOIDmode, x, rtx_varies_p))
return 0;
/* It's not invalidated by a store in memory
@@ -2787,6 +2971,10 @@ invariant_p (x)
/* Don't mess with insns declared volatile. */
if (MEM_VOLATILE_P (x))
return 0;
+ break;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -2857,7 +3045,7 @@ consec_sets_invariant_p (reg, n_sets, insn)
p = NEXT_INSN (p);
code = GET_CODE (p);
- /* If library call, skip to end of of it. */
+ /* If library call, skip to end of it. */
if (code == INSN && (temp = find_reg_note (p, REG_LIBCALL, NULL_RTX)))
p = XEXP (temp, 0);
@@ -2870,7 +3058,7 @@ consec_sets_invariant_p (reg, n_sets, insn)
this = invariant_p (SET_SRC (set));
if (this != 0)
value |= this;
- else if (temp = find_reg_note (p, REG_EQUAL, NULL_RTX))
+ else if ((temp = find_reg_note (p, REG_EQUAL, NULL_RTX)))
{
/* If this is a libcall, then any invariant REG_EQUAL note is OK.
If this is an ordinary insn, then only CONSTANT_P REG_EQUAL
@@ -3176,10 +3364,10 @@ static rtx addr_placeholder;
it is safe to keep the value in a register for the duration of the
loop. One tricky thing is that the copying of the value back from the
register has to be done on all exits from the loop. You need to check that
- all the exits from the loop go to the same place. */
+ all the exits from the loop go to the same place. */
/* ??? The interaction of biv elimination, and recognition of 'constant'
- bivs, may cause problems. */
+ bivs, may cause problems. */
/* ??? Add heuristics so that DEST_ADDR strength reduction does not cause
performance problems.
@@ -3212,13 +3400,14 @@ static rtx addr_placeholder;
static void
strength_reduce (scan_start, end, loop_top, insn_count,
- loop_start, loop_end)
+ loop_start, loop_end, unroll_p)
rtx scan_start;
rtx end;
rtx loop_top;
int insn_count;
rtx loop_start;
rtx loop_end;
+ int unroll_p;
{
rtx p;
rtx set;
@@ -3322,8 +3511,9 @@ strength_reduce (scan_start, end, loop_top, insn_count,
/* Past CODE_LABEL, we get to insns that may be executed multiple
times. The only way we can be sure that they can't is if every
- every jump insn between here and the end of the loop either
- returns, exits the loop, or is a forward jump. */
+ jump insn between here and the end of the loop either
+ returns, exits the loop, is a forward jump, or is a jump
+ to the loop start. */
if (GET_CODE (p) == CODE_LABEL)
{
@@ -3350,31 +3540,46 @@ strength_reduce (scan_start, end, loop_top, insn_count,
&& GET_CODE (PATTERN (insn)) != RETURN
&& (! condjump_p (insn)
|| (JUMP_LABEL (insn) != 0
+ && JUMP_LABEL (insn) != scan_start
&& (INSN_UID (JUMP_LABEL (insn)) >= max_uid_for_loop
|| INSN_UID (insn) >= max_uid_for_loop
|| (INSN_LUID (JUMP_LABEL (insn))
< INSN_LUID (insn))))))
- {
- maybe_multiple = 1;
- break;
- }
+ {
+ maybe_multiple = 1;
+ break;
+ }
}
}
- /* Past a label or a jump, we get to insns for which we can't count
- on whether or how many times they will be executed during each
- iteration. */
- /* This code appears in three places, once in scan_loop, and twice
- in strength_reduce. */
- if ((GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
+ /* Past a jump, we get to insns for which we can't count
+ on whether they will be executed during each iteration. */
+ /* This code appears twice in strength_reduce. There is also similar
+ code in scan_loop. */
+ if (GET_CODE (p) == JUMP_INSN
/* If we enter the loop in the middle, and scan around to the
beginning, don't set not_every_iteration for that.
This can be any kind of jump, since we want to know if insns
will be executed if the loop is executed. */
- && ! (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == loop_top
+ && ! (JUMP_LABEL (p) == loop_top
&& ((NEXT_INSN (NEXT_INSN (p)) == loop_end && simplejump_p (p))
|| (NEXT_INSN (p) == loop_end && condjump_p (p)))))
- not_every_iteration = 1;
+ {
+ rtx label = 0;
+
+ /* If this is a jump outside the loop, then it also doesn't
+ matter. Check to see if the target of this branch is on the
+ loop_number_exits_labels list. */
+
+ for (label = loop_number_exit_labels[uid_loop_num[INSN_UID (loop_start)]];
+ label;
+ label = LABEL_NEXTREF (label))
+ if (XEXP (label, 0) == JUMP_LABEL (p))
+ break;
+
+ if (! label)
+ not_every_iteration = 1;
+ }
else if (GET_CODE (p) == NOTE)
{
@@ -3396,8 +3601,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
Therefore, if we have just passed a label and have no more labels
between here and the test insn of the loop, we know these insns
- will be executed each iteration. This can also happen if we
- have just passed a jump, for example, when there are nested loops. */
+ will be executed each iteration. */
if (not_every_iteration && GET_CODE (p) == CODE_LABEL
&& no_labels_between_p (p, loop_end))
@@ -3441,7 +3645,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
{
/* Can still unroll the loop anyways, but indicate that there is no
strength reduction info available. */
- if (flag_unroll_loops)
+ if (unroll_p)
unroll_loop (loop_end, insn_count, loop_start, end_insert_before, 0);
return;
@@ -3479,8 +3683,8 @@ strength_reduce (scan_start, end, loop_top, insn_count,
if (GET_CODE (test) == NE)
{
bl->init_insn = p;
- bl->init_set = gen_rtx (SET, VOIDmode,
- XEXP (test, 0), XEXP (test, 1));
+ bl->init_set = gen_rtx_SET (VOIDmode,
+ XEXP (test, 0), XEXP (test, 1));
}
else
bl->initial_test = test;
@@ -3493,11 +3697,20 @@ strength_reduce (scan_start, end, loop_top, insn_count,
for (bl = loop_iv_list; bl; bl = bl->next)
{
rtx src;
+ rtx note;
if (! bl->init_insn)
continue;
- src = SET_SRC (bl->init_set);
+ /* IF INIT_INSN has a REG_EQUAL or REG_EQUIV note and the value
+ is a constant, use the value of that. */
+ if (((note = find_reg_note (bl->init_insn, REG_EQUAL, 0)) != NULL
+ && CONSTANT_P (XEXP (note, 0)))
+ || ((note = find_reg_note (bl->init_insn, REG_EQUIV, 0)) != NULL
+ && CONSTANT_P (XEXP (note, 0))))
+ src = XEXP (note, 0);
+ else
+ src = SET_SRC (bl->init_set);
if (loop_dump_stream)
fprintf (loop_dump_stream,
@@ -3513,7 +3726,10 @@ strength_reduce (scan_start, end, loop_top, insn_count,
if (loop_dump_stream)
{
if (GET_CODE (src) == CONST_INT)
- fprintf (loop_dump_stream, "%d\n", INTVAL (src));
+ {
+ fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (src));
+ fputc ('\n', loop_dump_stream);
+ }
else
{
print_rtl (loop_dump_stream, src);
@@ -3576,7 +3792,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
((benefit = general_induction_var (SET_SRC (set),
&src_reg, &add_val,
&mult_val))
- /* Equivalent expression is a giv. */
+ /* Equivalent expression is a giv. */
|| ((regnote = find_reg_note (p, REG_EQUAL, NULL_RTX))
&& (benefit = general_induction_var (XEXP (regnote, 0),
&src_reg,
@@ -3588,7 +3804,7 @@ strength_reduce (scan_start, end, loop_top, insn_count,
&& dest_reg != src_reg
/* This must be the only place where the register is set. */
&& (n_times_set[REGNO (dest_reg)] == 1
- /* or all sets must be consecutive and make a giv. */
+ /* or all sets must be consecutive and make a giv. */
|| (benefit = consec_sets_giv (benefit, p,
src_reg, dest_reg,
&add_val, &mult_val))))
@@ -3639,20 +3855,34 @@ strength_reduce (scan_start, end, loop_top, insn_count,
|| GET_CODE (p) == CODE_LABEL)
update_giv_derive (p);
- /* Past a label or a jump, we get to insns for which we can't count
- on whether or how many times they will be executed during each
- iteration. */
- /* This code appears in three places, once in scan_loop, and twice
- in strength_reduce. */
- if ((GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN)
- /* If we enter the loop in the middle, and scan around
- to the beginning, don't set not_every_iteration for that.
+ /* Past a jump, we get to insns for which we can't count
+ on whether they will be executed during each iteration. */
+ /* This code appears twice in strength_reduce. There is also similar
+ code in scan_loop. */
+ if (GET_CODE (p) == JUMP_INSN
+ /* If we enter the loop in the middle, and scan around to the
+ beginning, don't set not_every_iteration for that.
This can be any kind of jump, since we want to know if insns
will be executed if the loop is executed. */
- && ! (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p) == loop_top
+ && ! (JUMP_LABEL (p) == loop_top
&& ((NEXT_INSN (NEXT_INSN (p)) == loop_end && simplejump_p (p))
|| (NEXT_INSN (p) == loop_end && condjump_p (p)))))
- not_every_iteration = 1;
+ {
+ rtx label = 0;
+
+ /* If this is a jump outside the loop, then it also doesn't
+ matter. Check to see if the target of this branch is on the
+ loop_number_exits_labels list. */
+
+ for (label = loop_number_exit_labels[uid_loop_num[INSN_UID (loop_start)]];
+ label;
+ label = LABEL_NEXTREF (label))
+ if (XEXP (label, 0) == JUMP_LABEL (p))
+ break;
+
+ if (! label)
+ not_every_iteration = 1;
+ }
else if (GET_CODE (p) == NOTE)
{
@@ -3707,6 +3937,16 @@ strength_reduce (scan_start, end, loop_top, insn_count,
so that "decrement and branch until zero" insn can be used. */
check_dbra_loop (loop_end, insn_count, loop_start);
+#ifdef HAIFA
+ /* record loop-variables relevant for BCT optimization before unrolling
+ the loop. Unrolling may update part of this information, and the
+ correct data will be used for generating the BCT. */
+#ifdef HAVE_decrement_and_branch_on_count
+ if (HAVE_decrement_and_branch_on_count)
+ analyze_loop_iterations (loop_start, loop_end);
+#endif
+#endif /* HAIFA */
+
/* Create reg_map to hold substitutions for replaceable giv regs. */
reg_map = (rtx *) alloca (max_reg_before_loop * sizeof (rtx));
bzero ((char *) reg_map, max_reg_before_loop * sizeof (rtx));
@@ -3737,10 +3977,10 @@ strength_reduce (scan_start, end, loop_top, insn_count,
long as init_insn doesn't use the biv itself.
March 14, 1989 -- self@bayes.arc.nasa.gov */
- if ((uid_luid[regno_last_uid[bl->regno]] < INSN_LUID (loop_end)
+ if ((uid_luid[REGNO_LAST_UID (bl->regno)] < INSN_LUID (loop_end)
&& bl->init_insn
&& INSN_UID (bl->init_insn) < max_uid_for_loop
- && uid_luid[regno_first_uid[bl->regno]] >= INSN_LUID (bl->init_insn)
+ && uid_luid[REGNO_FIRST_UID (bl->regno)] >= INSN_LUID (bl->init_insn)
#ifdef HAVE_decrement_and_branch_until_zero
&& ! bl->nonneg
#endif
@@ -3761,8 +4001,8 @@ strength_reduce (scan_start, end, loop_top, insn_count,
bl->regno);
fprintf (loop_dump_stream,
"First use: insn %d, last use: insn %d.\n",
- regno_first_uid[bl->regno],
- regno_last_uid[bl->regno]);
+ REGNO_FIRST_UID (bl->regno),
+ REGNO_LAST_UID (bl->regno));
}
}
@@ -3807,9 +4047,23 @@ strength_reduce (scan_start, end, loop_top, insn_count,
unchanged (recompute it from the biv each time it is used).
This decision can be made independently for each giv. */
- /* ??? Perhaps attempt to guess whether autoincrement will handle
- some of the new add insns; if so, can increase BENEFIT
- (undo the subtraction of add_cost that was done above). */
+#ifdef AUTO_INC_DEC
+ /* Attempt to guess whether autoincrement will handle some of the
+ new add insns; if so, increase BENEFIT (undo the subtraction of
+ add_cost that was done above). */
+ if (v->giv_type == DEST_ADDR
+ && GET_CODE (v->mult_val) == CONST_INT)
+ {
+#if defined (HAVE_POST_INCREMENT) || defined (HAVE_PRE_INCREMENT)
+ if (INTVAL (v->mult_val) == GET_MODE_SIZE (v->mem_mode))
+ benefit += add_cost * bl->biv_count;
+#endif
+#if defined (HAVE_POST_DECREMENT) || defined (HAVE_PRE_DECREMENT)
+ if (-INTVAL (v->mult_val) == GET_MODE_SIZE (v->mem_mode))
+ benefit += add_cost * bl->biv_count;
+#endif
+ }
+#endif
/* If an insn is not to be strength reduced, then set its ignore
flag, and clear all_reduced. */
@@ -3820,8 +4074,8 @@ strength_reduce (scan_start, end, loop_top, insn_count,
of such giv's whether or not we know they are used after the loop
exit. */
- if (v->lifetime * threshold * benefit < insn_count
- && ! bl->reversed)
+ if ( ! flag_reduce_all_givs && v->lifetime * threshold * benefit < insn_count
+ && ! bl->reversed )
{
if (loop_dump_stream)
fprintf (loop_dump_stream,
@@ -3858,20 +4112,108 @@ strength_reduce (scan_start, end, loop_top, insn_count,
struct induction *tv;
if (! v->ignore && v->same == 0)
{
+ int auto_inc_opt = 0;
+
v->new_reg = gen_reg_rtx (v->mode);
- /* For each place where the biv is incremented,
- add an insn to increment the new, reduced reg for the giv. */
+#ifdef AUTO_INC_DEC
+ /* If the target has auto-increment addressing modes, and
+ this is an address giv, then try to put the increment
+ immediately after its use, so that flow can create an
+ auto-increment addressing mode. */
+ if (v->giv_type == DEST_ADDR && bl->biv_count == 1
+ && bl->biv->always_executed && ! bl->biv->maybe_multiple
+ /* We don't handle reversed biv's because bl->biv->insn
+ does not have a valid INSN_LUID. */
+ && ! bl->reversed
+ && v->always_executed && ! v->maybe_multiple
+ && INSN_UID (v->insn) < max_uid_for_loop)
+ {
+ /* If other giv's have been combined with this one, then
+ this will work only if all uses of the other giv's occur
+ before this giv's insn. This is difficult to check.
+
+ We simplify this by looking for the common case where
+ there is one DEST_REG giv, and this giv's insn is the
+ last use of the dest_reg of that DEST_REG giv. If the
+ increment occurs after the address giv, then we can
+ perform the optimization. (Otherwise, the increment
+ would have to go before other_giv, and we would not be
+ able to combine it with the address giv to get an
+ auto-inc address.) */
+ if (v->combined_with)
+ {
+ struct induction *other_giv = 0;
+
+ for (tv = bl->giv; tv; tv = tv->next_iv)
+ if (tv->same == v)
+ {
+ if (other_giv)
+ break;
+ else
+ other_giv = tv;
+ }
+ if (! tv && other_giv
+ && REGNO (other_giv->dest_reg) < max_reg_before_loop
+ && (REGNO_LAST_UID (REGNO (other_giv->dest_reg))
+ == INSN_UID (v->insn))
+ && INSN_LUID (v->insn) < INSN_LUID (bl->biv->insn))
+ auto_inc_opt = 1;
+ }
+ /* Check for case where increment is before the address
+ giv. Do this test in "loop order". */
+ else if ((INSN_LUID (v->insn) > INSN_LUID (bl->biv->insn)
+ && (INSN_LUID (v->insn) < INSN_LUID (scan_start)
+ || (INSN_LUID (bl->biv->insn)
+ > INSN_LUID (scan_start))))
+ || (INSN_LUID (v->insn) < INSN_LUID (scan_start)
+ && (INSN_LUID (scan_start)
+ < INSN_LUID (bl->biv->insn))))
+ auto_inc_opt = -1;
+ else
+ auto_inc_opt = 1;
+
+#ifdef HAVE_cc0
+ {
+ rtx prev;
+
+ /* We can't put an insn immediately after one setting
+ cc0, or immediately before one using cc0. */
+ if ((auto_inc_opt == 1 && sets_cc0_p (PATTERN (v->insn)))
+ || (auto_inc_opt == -1
+ && (prev = prev_nonnote_insn (v->insn)) != 0
+ && GET_RTX_CLASS (GET_CODE (prev)) == 'i'
+ && sets_cc0_p (PATTERN (prev))))
+ auto_inc_opt = 0;
+ }
+#endif
+
+ if (auto_inc_opt)
+ v->auto_inc_opt = 1;
+ }
+#endif
+
+ /* For each place where the biv is incremented, add an insn
+ to increment the new, reduced reg for the giv. */
for (tv = bl->biv; tv; tv = tv->next_iv)
{
+ rtx insert_before;
+
+ if (! auto_inc_opt)
+ insert_before = tv->insn;
+ else if (auto_inc_opt == 1)
+ insert_before = NEXT_INSN (v->insn);
+ else
+ insert_before = v->insn;
+
if (tv->mult_val == const1_rtx)
emit_iv_add_mult (tv->add_val, v->mult_val,
- v->new_reg, v->new_reg, tv->insn);
+ v->new_reg, v->new_reg, insert_before);
else /* tv->mult_val == const0_rtx */
/* A multiply is acceptable here
since this is presumed to be seldom executed. */
emit_iv_add_mult (tv->add_val, v->mult_val,
- v->add_val, v->new_reg, tv->insn);
+ v->add_val, v->new_reg, insert_before);
}
/* Add code at loop start to initialize giv's reduced reg. */
@@ -3900,12 +4242,12 @@ strength_reduce (scan_start, end, loop_top, insn_count,
continue;
if (v->giv_type == DEST_REG
- && regno_first_uid[REGNO (v->dest_reg)] == INSN_UID (v->insn))
+ && REGNO_FIRST_UID (REGNO (v->dest_reg)) == INSN_UID (v->insn))
{
struct induction *v1;
for (v1 = bl->giv; v1; v1 = v1->next_iv)
- if (regno_last_uid[REGNO (v->dest_reg)] == INSN_UID (v1->insn))
+ if (REGNO_LAST_UID (REGNO (v->dest_reg)) == INSN_UID (v1->insn))
v->maybe_dead = 1;
}
@@ -4041,14 +4383,14 @@ strength_reduce (scan_start, end, loop_top, insn_count,
or otherwise drop straight in, based on this test, then
we might want to rewrite it also. This way some later
pass has more hope of removing the initialization of this
- biv entirely. */
+ biv entirely. */
/* If final_value != 0, then the biv may be used after loop end
and we must emit an insn to set it just in case.
Reversed bivs already have an insn after the loop setting their
value, so we don't need another one. We can't calculate the
- proper final value for such a biv here anyways. */
+ proper final value for such a biv here anyways. */
if (final_value != 0 && ! bl->reversed)
{
rtx insert_before;
@@ -4101,9 +4443,17 @@ strength_reduce (scan_start, end, loop_top, insn_count,
induction variable information that strength_reduce has already
collected. */
- if (flag_unroll_loops)
+ if (unroll_p)
unroll_loop (loop_end, insn_count, loop_start, end_insert_before, 1);
+#ifdef HAIFA
+ /* instrument the loop with bct insn */
+#ifdef HAVE_decrement_and_branch_on_count
+ if (HAVE_decrement_and_branch_on_count)
+ insert_bct (loop_start, loop_end);
+#endif
+#endif /* HAIFA */
+
if (loop_dump_stream)
fprintf (loop_dump_stream, "\n");
}
@@ -4135,10 +4485,8 @@ valid_initial_value_p (x, insn, call_seen, loop_start)
/* Don't use call-clobbered registers across a call which clobbers it. On
some machines, don't use any hard registers at all. */
if (REGNO (x) < FIRST_PSEUDO_REGISTER
-#ifndef SMALL_REGISTER_CLASSES
- && call_used_regs[REGNO (x)] && call_seen
-#endif
- )
+ && (SMALL_REGISTER_CLASSES
+ || (call_used_regs[REGNO (x)] && call_seen)))
return 0;
/* Don't use registers that have been clobbered before the start of the
@@ -4209,8 +4557,11 @@ find_mem_givs (x, insn, not_every_iteration, loop_start, loop_end)
v->mem_mode = GET_MODE (x);
}
- return;
}
+ return;
+
+ default:
+ break;
}
/* Recursively scan the subexpressions for other mem refs. */
@@ -4262,6 +4613,7 @@ record_biv (v, insn, dest_reg, inc_val, mult_val,
v->add_val = inc_val;
v->mode = GET_MODE (dest_reg);
v->always_computable = ! not_every_iteration;
+ v->always_executed = ! not_every_iteration;
v->maybe_multiple = maybe_multiple;
/* Add this to the reg's iv_class, creating a class
@@ -4313,8 +4665,11 @@ record_biv (v, insn, dest_reg, inc_val, mult_val,
"Insn %d: possible biv, reg %d,",
INSN_UID (insn), REGNO (dest_reg));
if (GET_CODE (inc_val) == CONST_INT)
- fprintf (loop_dump_stream, " const = %d\n",
- INTVAL (inc_val));
+ {
+ fprintf (loop_dump_stream, " const =");
+ fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (inc_val));
+ fputc ('\n', loop_dump_stream);
+ }
else
{
fprintf (loop_dump_stream, " const = ");
@@ -4354,7 +4709,6 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
struct induction *b;
struct iv_class *bl;
rtx set = single_set (insn);
- rtx p;
v->insn = insn;
v->src_reg = src_reg;
@@ -4374,6 +4728,9 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
v->new_reg = 0;
v->final_value = 0;
v->same_insn = 0;
+ v->auto_inc_opt = 0;
+ v->unrolled = 0;
+ v->shared = 0;
/* The v->always_computable field is used in update_giv_derive, to
determine whether a giv can be used to derive another giv. For a
@@ -4388,6 +4745,8 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
else
v->always_computable = ! not_every_iteration;
+ v->always_executed = ! not_every_iteration;
+
if (type == DEST_ADDR)
{
v->mode = GET_MODE (*location);
@@ -4398,14 +4757,14 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
{
v->mode = GET_MODE (SET_DEST (set));
- v->lifetime = (uid_luid[regno_last_uid[REGNO (dest_reg)]]
- - uid_luid[regno_first_uid[REGNO (dest_reg)]]);
+ v->lifetime = (uid_luid[REGNO_LAST_UID (REGNO (dest_reg))]
+ - uid_luid[REGNO_FIRST_UID (REGNO (dest_reg))]);
v->times_used = n_times_used[REGNO (dest_reg)];
/* If the lifetime is zero, it means that this register is
really a dead store. So mark this as a giv that can be
- ignored. This will not prevent the biv from being eliminated. */
+ ignored. This will not prevent the biv from being eliminated. */
if (v->lifetime == 0)
v->ignore = 1;
@@ -4444,9 +4803,9 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
- the giv is not used outside the loop
- no assignments to the biv occur during the giv's lifetime. */
- if (regno_first_uid[REGNO (dest_reg)] == INSN_UID (insn)
+ if (REGNO_FIRST_UID (REGNO (dest_reg)) == INSN_UID (insn)
/* Previous line always fails if INSN was moved by loop opt. */
- && uid_luid[regno_last_uid[REGNO (dest_reg)]] < INSN_LUID (loop_end)
+ && uid_luid[REGNO_LAST_UID (REGNO (dest_reg))] < INSN_LUID (loop_end)
&& (! not_every_iteration
|| last_use_this_basic_block (dest_reg, insn)))
{
@@ -4469,9 +4828,9 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
{
if (INSN_UID (b->insn) >= max_uid_for_loop
|| ((uid_luid[INSN_UID (b->insn)]
- >= uid_luid[regno_first_uid[REGNO (dest_reg)]])
+ >= uid_luid[REGNO_FIRST_UID (REGNO (dest_reg))])
&& (uid_luid[INSN_UID (b->insn)]
- <= uid_luid[regno_last_uid[REGNO (dest_reg)]])))
+ <= uid_luid[REGNO_LAST_UID (REGNO (dest_reg))])))
{
v->replaceable = 0;
v->not_replaceable = 1;
@@ -4517,8 +4876,10 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
fprintf (loop_dump_stream, " replaceable");
if (GET_CODE (mult_val) == CONST_INT)
- fprintf (loop_dump_stream, " mult %d",
- INTVAL (mult_val));
+ {
+ fprintf (loop_dump_stream, " mult ");
+ fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (mult_val));
+ }
else
{
fprintf (loop_dump_stream, " mult ");
@@ -4526,8 +4887,10 @@ record_giv (v, insn, src_reg, dest_reg, mult_val, add_val, benefit,
}
if (GET_CODE (add_val) == CONST_INT)
- fprintf (loop_dump_stream, " add %d",
- INTVAL (add_val));
+ {
+ fprintf (loop_dump_stream, " add ");
+ fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (add_val));
+ }
else
{
fprintf (loop_dump_stream, " add ");
@@ -4626,8 +4989,7 @@ check_final_value (v, loop_start, loop_end)
break;
}
}
- else if (GET_CODE (PATTERN (p)) == SET
- && SET_DEST (PATTERN (p)) == v->src_reg)
+ else if (reg_set_p (v->src_reg, PATTERN (p)))
biv_increment_seen = 1;
else if (reg_mentioned_p (v->dest_reg, PATTERN (p)))
last_giv_use = p;
@@ -4651,8 +5013,11 @@ check_final_value (v, loop_start, loop_end)
if (GET_CODE (p) == JUMP_INSN && JUMP_LABEL (p)
&& LABEL_NAME (JUMP_LABEL (p))
- && ((INSN_LUID (JUMP_LABEL (p)) < INSN_LUID (v->insn)
- && INSN_LUID (JUMP_LABEL (p)) > INSN_LUID (loop_start))
+ && ((INSN_UID (JUMP_LABEL (p)) >= max_uid_for_loop)
+ || (INSN_UID (v->insn) >= max_uid_for_loop)
+ || (INSN_UID (last_giv_use) >= max_uid_for_loop)
+ || (INSN_LUID (JUMP_LABEL (p)) < INSN_LUID (v->insn)
+ && INSN_LUID (JUMP_LABEL (p)) > INSN_LUID (loop_start))
|| (INSN_LUID (JUMP_LABEL (p)) > INSN_LUID (last_giv_use)
&& INSN_LUID (JUMP_LABEL (p)) < INSN_LUID (loop_end))))
{
@@ -4758,14 +5123,14 @@ update_giv_derive (p)
tem = 0;
if (biv->mult_val == const1_rtx)
- tem = simplify_giv_expr (gen_rtx (MULT, giv->mode,
- biv->add_val,
- giv->mult_val),
+ tem = simplify_giv_expr (gen_rtx_MULT (giv->mode,
+ biv->add_val,
+ giv->mult_val),
&dummy);
if (tem && giv->derive_adjustment)
- tem = simplify_giv_expr (gen_rtx (PLUS, giv->mode, tem,
- giv->derive_adjustment),
+ tem = simplify_giv_expr (gen_rtx_PLUS (giv->mode, tem,
+ giv->derive_adjustment),
&dummy);
if (tem)
giv->derive_adjustment = tem;
@@ -4858,6 +5223,7 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val)
if (SUBREG_PROMOTED_VAR_P (x))
return basic_induction_var (SUBREG_REG (x), GET_MODE (SUBREG_REG (x)),
dest_reg, p, inc_val, mult_val);
+ return 0;
case REG:
/* If this register is assigned in the previous insn, look at its
@@ -4884,7 +5250,7 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val)
: GET_MODE (SET_SRC (set))),
dest_reg, insn,
inc_val, mult_val);
- /* ... fall through ... */
+ /* ... fall through ... */
/* Can accept constant setting of biv only when inside inner most loop.
Otherwise, a biv of an inner loop may be incorrectly recognized
@@ -4896,7 +5262,12 @@ basic_induction_var (x, mode, dest_reg, p, inc_val, mult_val)
case CONST_INT:
case SYMBOL_REF:
case CONST:
- if (loops_enclosed == 1)
+ /* convert_modes aborts if we try to convert to or from CCmode, so just
+ exclude that case. It is very unlikely that a condition code value
+ would be a useful iterator anyways. */
+ if (loops_enclosed == 1
+ && GET_MODE_CLASS (mode) != MODE_CC
+ && GET_MODE_CLASS (GET_MODE (dest_reg)) != MODE_CC)
{
/* Possible bug here? Perhaps we don't know the mode of X. */
*inc_val = convert_modes (GET_MODE (dest_reg), mode, x, 0);
@@ -5094,16 +5465,26 @@ simplify_giv_expr (x, benefit)
case CONST_INT:
case USE:
/* Both invariant. Only valid if sum is machine operand.
- First strip off possible USE on first operand. */
+ First strip off possible USE on the operands. */
if (GET_CODE (arg0) == USE)
arg0 = XEXP (arg0, 0);
+ if (GET_CODE (arg1) == USE)
+ arg1 = XEXP (arg1, 0);
+
tem = 0;
if (CONSTANT_P (arg0) && GET_CODE (arg1) == CONST_INT)
{
tem = plus_constant (arg0, INTVAL (arg1));
if (GET_CODE (tem) != CONST_INT)
- tem = gen_rtx (USE, mode, tem);
+ tem = gen_rtx_USE (mode, tem);
+ }
+ else
+ {
+ /* Adding two invariants must result in an invariant,
+ so enclose addition operation inside a USE and
+ return it. */
+ tem = gen_rtx_USE (mode, gen_rtx_PLUS (mode, arg0, arg1));
}
return tem;
@@ -5111,14 +5492,14 @@ simplify_giv_expr (x, benefit)
case REG:
case MULT:
/* biv + invar or mult + invar. Return sum. */
- return gen_rtx (PLUS, mode, arg0, arg1);
+ return gen_rtx_PLUS (mode, arg0, arg1);
case PLUS:
/* (a + invar_1) + invar_2. Associate. */
- return simplify_giv_expr (gen_rtx (PLUS, mode,
- XEXP (arg0, 0),
- gen_rtx (PLUS, mode,
- XEXP (arg0, 1), arg1)),
+ return simplify_giv_expr (gen_rtx_PLUS (mode,
+ XEXP (arg0, 0),
+ gen_rtx_PLUS (mode,
+ XEXP (arg0, 1), arg1)),
benefit);
default:
@@ -5128,9 +5509,9 @@ simplify_giv_expr (x, benefit)
/* Each argument must be either REG, PLUS, or MULT. Convert REG to
MULT to reduce cases. */
if (GET_CODE (arg0) == REG)
- arg0 = gen_rtx (MULT, mode, arg0, const1_rtx);
+ arg0 = gen_rtx_MULT (mode, arg0, const1_rtx);
if (GET_CODE (arg1) == REG)
- arg1 = gen_rtx (MULT, mode, arg1, const1_rtx);
+ arg1 = gen_rtx_MULT (mode, arg1, const1_rtx);
/* Now have PLUS + PLUS, PLUS + MULT, MULT + PLUS, or MULT + MULT.
Put a MULT first, leaving PLUS + PLUS, MULT + PLUS, or MULT + MULT.
@@ -5139,10 +5520,10 @@ simplify_giv_expr (x, benefit)
tem = arg0, arg0 = arg1, arg1 = tem;
if (GET_CODE (arg1) == PLUS)
- return simplify_giv_expr (gen_rtx (PLUS, mode,
- gen_rtx (PLUS, mode,
- arg0, XEXP (arg1, 0)),
- XEXP (arg1, 1)),
+ return simplify_giv_expr (gen_rtx_PLUS (mode,
+ gen_rtx_PLUS (mode, arg0,
+ XEXP (arg1, 0)),
+ XEXP (arg1, 1)),
benefit);
/* Now must have MULT + MULT. Distribute if same biv, else not giv. */
@@ -5152,19 +5533,19 @@ simplify_giv_expr (x, benefit)
if (XEXP (arg0, 0) != XEXP (arg1, 0))
return 0;
- return simplify_giv_expr (gen_rtx (MULT, mode,
- XEXP (arg0, 0),
- gen_rtx (PLUS, mode,
- XEXP (arg0, 1),
- XEXP (arg1, 1))),
+ return simplify_giv_expr (gen_rtx_MULT (mode,
+ XEXP (arg0, 0),
+ gen_rtx_PLUS (mode,
+ XEXP (arg0, 1),
+ XEXP (arg1, 1))),
benefit);
case MINUS:
- /* Handle "a - b" as "a + b * (-1)". */
- return simplify_giv_expr (gen_rtx (PLUS, mode,
- XEXP (x, 0),
- gen_rtx (MULT, mode,
- XEXP (x, 1), constm1_rtx)),
+ /* Handle "a - b" as "a + b * (-1)". */
+ return simplify_giv_expr (gen_rtx_PLUS (mode,
+ XEXP (x, 0),
+ gen_rtx_MULT (mode, XEXP (x, 1),
+ constm1_rtx)),
benefit);
case MULT:
@@ -5193,31 +5574,33 @@ simplify_giv_expr (x, benefit)
{
case REG:
/* biv * invar. Done. */
- return gen_rtx (MULT, mode, arg0, arg1);
+ return gen_rtx_MULT (mode, arg0, arg1);
case CONST_INT:
/* Product of two constants. */
return GEN_INT (INTVAL (arg0) * INTVAL (arg1));
case USE:
- /* invar * invar. Not giv. */
+ /* invar * invar. Not giv. */
return 0;
case MULT:
/* (a * invar_1) * invar_2. Associate. */
- return simplify_giv_expr (gen_rtx (MULT, mode,
- XEXP (arg0, 0),
- gen_rtx (MULT, mode,
- XEXP (arg0, 1), arg1)),
+ return simplify_giv_expr (gen_rtx_MULT (mode, XEXP (arg0, 0),
+ gen_rtx_MULT (mode,
+ XEXP (arg0, 1),
+ arg1)),
benefit);
case PLUS:
/* (a + invar_1) * invar_2. Distribute. */
- return simplify_giv_expr (gen_rtx (PLUS, mode,
- gen_rtx (MULT, mode,
- XEXP (arg0, 0), arg1),
- gen_rtx (MULT, mode,
- XEXP (arg0, 1), arg1)),
+ return simplify_giv_expr (gen_rtx_PLUS (mode,
+ gen_rtx_MULT (mode,
+ XEXP (arg0, 0),
+ arg1),
+ gen_rtx_MULT (mode,
+ XEXP (arg0, 1),
+ arg1)),
benefit);
default:
@@ -5229,22 +5612,22 @@ simplify_giv_expr (x, benefit)
if (GET_CODE (XEXP (x, 1)) != CONST_INT)
return 0;
- return simplify_giv_expr (gen_rtx (MULT, mode,
- XEXP (x, 0),
- GEN_INT ((HOST_WIDE_INT) 1
- << INTVAL (XEXP (x, 1)))),
+ return simplify_giv_expr (gen_rtx_MULT (mode,
+ XEXP (x, 0),
+ GEN_INT ((HOST_WIDE_INT) 1
+ << INTVAL (XEXP (x, 1)))),
benefit);
case NEG:
/* "-a" is "a * (-1)" */
- return simplify_giv_expr (gen_rtx (MULT, mode, XEXP (x, 0), constm1_rtx),
+ return simplify_giv_expr (gen_rtx_MULT (mode, XEXP (x, 0), constm1_rtx),
benefit);
case NOT:
/* "~a" is "-a - 1". Silly, but easy. */
- return simplify_giv_expr (gen_rtx (MINUS, mode,
- gen_rtx (NEG, mode, XEXP (x, 0)),
- const1_rtx),
+ return simplify_giv_expr (gen_rtx_MINUS (mode,
+ gen_rtx_NEG (mode, XEXP (x, 0)),
+ const1_rtx),
benefit);
case USE:
@@ -5271,13 +5654,16 @@ simplify_giv_expr (x, benefit)
if (v->cant_derive)
return 0;
- tem = gen_rtx (PLUS, mode, gen_rtx (MULT, mode,
- v->src_reg, v->mult_val),
+ tem = gen_rtx_PLUS (mode, gen_rtx_MULT (mode, v->src_reg,
+ v->mult_val),
v->add_val);
if (v->derive_adjustment)
- tem = gen_rtx (MINUS, mode, tem, v->derive_adjustment);
+ tem = gen_rtx_MINUS (mode, tem, v->derive_adjustment);
return simplify_giv_expr (tem, benefit);
}
+
+ default:
+ break;
}
/* Fall through to general case. */
@@ -5292,7 +5678,7 @@ simplify_giv_expr (x, benefit)
if (GET_CODE (x) == CONST_INT)
return x;
else
- return gen_rtx (USE, mode, x);
+ return gen_rtx_USE (mode, x);
}
else
return 0;
@@ -5440,12 +5826,12 @@ express_from (g1, g2)
else if (mult == const1_rtx)
mult = g1->dest_reg;
else
- mult = gen_rtx (MULT, g2->mode, g1->dest_reg, mult);
+ mult = gen_rtx_MULT (g2->mode, g1->dest_reg, mult);
if (add == const0_rtx)
return mult;
else
- return gen_rtx (PLUS, g2->mode, mult, add);
+ return gen_rtx_PLUS (g2->mode, mult, add);
}
#endif
@@ -5458,7 +5844,9 @@ static int
combine_givs_p (g1, g2)
struct induction *g1, *g2;
{
+#ifdef ADDRESS_COST
rtx tem;
+#endif
/* If these givs are identical, they can be combined. */
if (rtx_equal_p (g1->mult_val, g2->mult_val)
@@ -5485,6 +5873,20 @@ combine_givs_p (g1, g2)
return 0;
}
+#ifdef GIV_SORT_CRITERION
+/* Compare two givs and sort the most desirable one for combinations first.
+ This is used only in one qsort call below. */
+
+static int
+giv_sort (x, y)
+ struct induction **x, **y;
+{
+ GIV_SORT_CRITERION (*x, *y);
+
+ return 0;
+}
+#endif
+
/* Check all pairs of givs for iv_class BL and see if any can be combined with
any other. If so, point SAME to the giv combined with and set NEW_REG to
be an expression (in terms of the other giv's DEST_REG) equivalent to the
@@ -5494,39 +5896,82 @@ static void
combine_givs (bl)
struct iv_class *bl;
{
- struct induction *g1, *g2;
- int pass;
+ struct induction *g1, *g2, **giv_array;
+ int i, j, giv_count, pass;
+
+ /* Count givs, because bl->giv_count is incorrect here. */
+ giv_count = 0;
+ for (g1 = bl->giv; g1; g1 = g1->next_iv)
+ giv_count++;
+ giv_array
+ = (struct induction **) alloca (giv_count * sizeof (struct induction *));
+ i = 0;
for (g1 = bl->giv; g1; g1 = g1->next_iv)
- for (pass = 0; pass <= 1; pass++)
- for (g2 = bl->giv; g2; g2 = g2->next_iv)
- if (g1 != g2
- /* First try to combine with replaceable givs, then all givs. */
- && (g1->replaceable || pass == 1)
- /* If either has already been combined or is to be ignored, can't
- combine. */
- && ! g1->ignore && ! g2->ignore && ! g1->same && ! g2->same
- /* If something has been based on G2, G2 cannot itself be based
- on something else. */
- && ! g2->combined_with
- && combine_givs_p (g1, g2))
+ giv_array[i++] = g1;
+
+#ifdef GIV_SORT_CRITERION
+ /* Sort the givs if GIV_SORT_CRITERION is defined.
+ This is usually defined for processors which lack
+ negative register offsets so more givs may be combined. */
+
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream, "%d givs counted, sorting...\n", giv_count);
+
+ qsort (giv_array, giv_count, sizeof (struct induction *), giv_sort);
+#endif
+
+ for (i = 0; i < giv_count; i++)
+ {
+ g1 = giv_array[i];
+ for (pass = 0; pass <= 1; pass++)
+ for (j = 0; j < giv_count; j++)
{
- /* g2->new_reg set by `combine_givs_p' */
- g2->same = g1;
- g1->combined_with = 1;
- g1->benefit += g2->benefit;
- /* ??? The new final_[bg]iv_value code does a much better job
- of finding replaceable giv's, and hence this code may no
- longer be necessary. */
- if (! g2->replaceable && REG_USERVAR_P (g2->dest_reg))
- g1->benefit -= copy_cost;
- g1->lifetime += g2->lifetime;
- g1->times_used += g2->times_used;
-
- if (loop_dump_stream)
- fprintf (loop_dump_stream, "giv at %d combined with giv at %d\n",
- INSN_UID (g2->insn), INSN_UID (g1->insn));
+ g2 = giv_array[j];
+ if (g1 != g2
+ /* First try to combine with replaceable givs, then all givs. */
+ && (g1->replaceable || pass == 1)
+ /* If either has already been combined or is to be ignored, can't
+ combine. */
+ && ! g1->ignore && ! g2->ignore && ! g1->same && ! g2->same
+ /* If something has been based on G2, G2 cannot itself be based
+ on something else. */
+ && ! g2->combined_with
+ && combine_givs_p (g1, g2))
+ {
+ /* g2->new_reg set by `combine_givs_p' */
+ g2->same = g1;
+ g1->combined_with = 1;
+
+ /* If one of these givs is a DEST_REG that was only used
+ once, by the other giv, this is actually a single use.
+ The DEST_REG has the correct cost, while the other giv
+ counts the REG use too often. */
+ if (g2->giv_type == DEST_REG
+ && n_times_used[REGNO (g2->dest_reg)] == 1
+ && reg_mentioned_p (g2->dest_reg, PATTERN (g1->insn)))
+ g1->benefit = g2->benefit;
+ else if (g1->giv_type != DEST_REG
+ || n_times_used[REGNO (g1->dest_reg)] != 1
+ || ! reg_mentioned_p (g1->dest_reg,
+ PATTERN (g2->insn)))
+ {
+ g1->benefit += g2->benefit;
+ g1->times_used += g2->times_used;
+ }
+ /* ??? The new final_[bg]iv_value code does a much better job
+ of finding replaceable giv's, and hence this code may no
+ longer be necessary. */
+ if (! g2->replaceable && REG_USERVAR_P (g2->dest_reg))
+ g1->benefit -= copy_cost;
+ g1->lifetime += g2->lifetime;
+
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream, "giv at %d combined with giv at %d\n",
+ INSN_UID (g2->insn), INSN_UID (g1->insn));
+ }
}
+ }
}
/* EMIT code before INSERT_BEFORE to set REG = B * M + A. */
@@ -5546,7 +5991,7 @@ emit_iv_add_mult (b, m, a, reg, insert_before)
a = copy_rtx (a);
b = copy_rtx (b);
- /* Increase the lifetime of any invariants moved further in code. */
+ /* Increase the lifetime of any invariants moved further in code. */
update_reg_last_use (a, insert_before);
update_reg_last_use (b, insert_before);
update_reg_last_use (m, insert_before);
@@ -5559,6 +6004,24 @@ emit_iv_add_mult (b, m, a, reg, insert_before)
end_sequence ();
emit_insn_before (seq, insert_before);
+
+ /* It is entirely possible that the expansion created lots of new
+ registers. Iterate over the sequence we just created and
+ record them all. */
+
+ if (GET_CODE (seq) == SEQUENCE)
+ {
+ int i;
+ for (i = 0; i < XVECLEN (seq, 0); ++i)
+ {
+ rtx set = single_set (XVECEXP (seq, 0, i));
+ if (set && GET_CODE (SET_DEST (set)) == REG)
+ record_base_value (REGNO (SET_DEST (set)), SET_SRC (set), 0);
+ }
+ }
+ else if (GET_CODE (seq) == SET
+ && GET_CODE (SET_DEST (seq)) == REG)
+ record_base_value (REGNO (SET_DEST (seq)), SET_SRC (seq), 0);
}
/* Test whether A * B can be computed without
@@ -5575,7 +6038,7 @@ product_cheap_p (a, b)
char *storage = (char *) obstack_alloc (&temp_obstack, 0);
int win = 1;
- /* If only one is constant, make it B. */
+ /* If only one is constant, make it B. */
if (GET_CODE (a) == CONST_INT)
tmp = a, a = b, b = tmp;
@@ -5666,14 +6129,28 @@ check_dbra_loop (loop_end, insn_count, loop_start)
rtx comparison;
rtx before_comparison;
rtx p;
+ rtx jump;
+ rtx first_compare;
+ int compare_and_branch;
/* If last insn is a conditional branch, and the insn before tests a
register value, try to optimize it. Otherwise, we can't do anything. */
- comparison = get_condition_for_loop (PREV_INSN (loop_end));
+ jump = PREV_INSN (loop_end);
+ comparison = get_condition_for_loop (jump);
if (comparison == 0)
return 0;
+ /* Try to compute whether the compare/branch at the loop end is one or
+ two instructions. */
+ get_condition (jump, &first_compare);
+ if (first_compare == jump)
+ compare_and_branch = 1;
+ else if (first_compare == prev_nonnote_insn (jump))
+ compare_and_branch = 2;
+ else
+ return 0;
+
/* Check all of the bivs to see if the compare uses one of them.
Skip biv's set more than once because we can't guarantee that
it will be zero on the last iteration. Also skip if the biv is
@@ -5684,7 +6161,7 @@ check_dbra_loop (loop_end, insn_count, loop_start)
if (bl->biv_count == 1
&& bl->biv->dest_reg == XEXP (comparison, 0)
&& ! reg_used_between_p (regno_reg_rtx[bl->regno], bl->biv->insn,
- PREV_INSN (PREV_INSN (loop_end))))
+ first_compare))
break;
}
@@ -5709,13 +6186,13 @@ check_dbra_loop (loop_end, insn_count, loop_start)
if (GET_CODE (bl->initial_value) == CONST_INT
&& INTVAL (bl->initial_value) > 0
- && (INTVAL (bl->initial_value) %
- (-INTVAL (bl->biv->add_val))) == 0)
+ && (INTVAL (bl->initial_value)
+ % (-INTVAL (bl->biv->add_val))) == 0)
{
/* register always nonnegative, add REG_NOTE to branch */
REG_NOTES (PREV_INSN (loop_end))
- = gen_rtx (EXPR_LIST, REG_NONNEG, NULL_RTX,
- REG_NOTES (PREV_INSN (loop_end)));
+ = gen_rtx_EXPR_LIST (REG_NONNEG, NULL_RTX,
+ REG_NOTES (PREV_INSN (loop_end)));
bl->nonneg = 1;
return 1;
@@ -5739,8 +6216,8 @@ check_dbra_loop (loop_end, insn_count, loop_start)
&& INTVAL (bl->biv->add_val) == -1)
{
REG_NOTES (PREV_INSN (loop_end))
- = gen_rtx (EXPR_LIST, REG_NONNEG, NULL_RTX,
- REG_NOTES (PREV_INSN (loop_end)));
+ = gen_rtx_EXPR_LIST (REG_NONNEG, NULL_RTX,
+ REG_NOTES (PREV_INSN (loop_end)));
bl->nonneg = 1;
return 1;
@@ -5777,7 +6254,7 @@ check_dbra_loop (loop_end, insn_count, loop_start)
rtx bivreg = regno_reg_rtx[bl->regno];
/* If there are no givs for this biv, and the only exit is the
- fall through at the end of the the loop, then
+ fall through at the end of the loop, then
see if perhaps there are no uses except to count. */
no_use_except_counting = 1;
for (p = loop_start; p != loop_end; p = NEXT_INSN (p))
@@ -5809,9 +6286,26 @@ check_dbra_loop (loop_end, insn_count, loop_start)
case, the insn should have been moved out of the loop. */
if (num_mem_sets == 1)
- reversible_mem_store
- = (! unknown_address_altered
- && ! invariant_p (XEXP (loop_store_mems[0], 0)));
+ {
+ struct induction *v;
+
+ reversible_mem_store
+ = (! unknown_address_altered
+ && ! invariant_p (XEXP (loop_store_mems[0], 0)));
+
+ /* If the store depends on a register that is set after the
+ store, it depends on the initial value, and is thus not
+ reversible. */
+ for (v = bl->giv; reversible_mem_store && v; v = v->next_iv)
+ {
+ if (v->giv_type == DEST_REG
+ && reg_mentioned_p (v->dest_reg, loop_store_mems[0])
+ && (INSN_UID (v->insn) >= max_uid_for_loop
+ || (INSN_LUID (v->insn)
+ > INSN_LUID (first_loop_store_insn))))
+ reversible_mem_store = 0;
+ }
+ }
/* This code only acts for innermost loops. Also it simplifies
the memory address check by only reversing loops with
@@ -5825,7 +6319,7 @@ check_dbra_loop (loop_end, insn_count, loop_start)
&& reversible_mem_store
&& (no_use_except_counting
|| ((bl->giv_count + bl->biv_count + num_mem_sets
- + num_movables + 2 == insn_count)
+ + num_movables + compare_and_branch == insn_count)
&& (bl == loop_iv_list && bl->next == 0))))
{
rtx tem;
@@ -5835,30 +6329,63 @@ check_dbra_loop (loop_end, insn_count, loop_start)
fprintf (loop_dump_stream, "Can reverse loop\n");
/* Now check other conditions:
- initial_value must be zero,
- final_value % add_val == 0, so that when reversed, the
- biv will be zero on the last iteration.
+
+ The increment must be a constant, as must the initial value,
+ and the comparison code must be LT.
This test can probably be improved since +/- 1 in the constant
can be obtained by changing LT to LE and vice versa; this is
confusing. */
- if (comparison && bl->initial_value == const0_rtx
+ if (comparison
&& GET_CODE (XEXP (comparison, 1)) == CONST_INT
/* LE gets turned into LT */
&& GET_CODE (comparison) == LT
- && (INTVAL (XEXP (comparison, 1))
- % INTVAL (bl->biv->add_val)) == 0)
+ && GET_CODE (bl->initial_value) == CONST_INT)
{
+ HOST_WIDE_INT add_val, comparison_val;
+ rtx initial_value;
+
+ add_val = INTVAL (bl->biv->add_val);
+ comparison_val = INTVAL (XEXP (comparison, 1));
+ final_value = XEXP (comparison, 1);
+ initial_value = bl->initial_value;
+
+ /* Normalize the initial value if it is an integer and
+ has no other use except as a counter. This will allow
+ a few more loops to be reversed. */
+ if (no_use_except_counting
+ && GET_CODE (initial_value) == CONST_INT)
+ {
+ comparison_val = comparison_val - INTVAL (bl->initial_value);
+ /* Check for overflow. If comparison_val ends up as a
+ negative value, then we can't reverse the loop. */
+ if (comparison_val >= 0)
+ initial_value = const0_rtx;
+ }
+
+ /* If the initial value is not zero, or if the comparison
+ value is not an exact multiple of the increment, then we
+ can not reverse this loop. */
+ if (initial_value != const0_rtx
+ || (comparison_val % add_val) != 0)
+ return 0;
+
+ /* Reset these in case we normalized the initial value
+ and comparison value above. */
+ bl->initial_value = initial_value;
+ XEXP (comparison, 1) = GEN_INT (comparison_val);
+
/* Register will always be nonnegative, with value
0 on last iteration if loop reversed */
/* Save some info needed to produce the new insns. */
reg = bl->biv->dest_reg;
jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 1);
+ if (jump_label == pc_rtx)
+ jump_label = XEXP (SET_SRC (PATTERN (PREV_INSN (loop_end))), 2);
new_add_val = GEN_INT (- INTVAL (bl->biv->add_val));
- final_value = XEXP (comparison, 1);
start_value = GEN_INT (INTVAL (XEXP (comparison, 1))
- INTVAL (bl->biv->add_val));
@@ -5884,16 +6411,16 @@ check_dbra_loop (loop_end, insn_count, loop_start)
/* Emit an insn after the end of the loop to set the biv's
proper exit value if it is used anywhere outside the loop. */
- if ((regno_last_uid[bl->regno]
- != INSN_UID (PREV_INSN (PREV_INSN (loop_end))))
+ if ((REGNO_LAST_UID (bl->regno) != INSN_UID (first_compare))
|| ! bl->init_insn
- || regno_first_uid[bl->regno] != INSN_UID (bl->init_insn))
+ || REGNO_FIRST_UID (bl->regno) != INSN_UID (bl->init_insn))
emit_insn_after (gen_move_insn (reg, final_value),
loop_end);
/* Delete compare/branch at end of loop. */
delete_insn (PREV_INSN (loop_end));
- delete_insn (PREV_INSN (loop_end));
+ if (compare_and_branch == 2)
+ delete_insn (first_compare);
/* Add new compare/branch insn at end of loop. */
start_sequence ();
@@ -5911,11 +6438,11 @@ check_dbra_loop (loop_end, insn_count, loop_start)
{
JUMP_LABEL (tem) = XEXP (jump_label, 0);
- /* Increment of LABEL_NUSES done above. */
+ /* Increment of LABEL_NUSES done above. */
/* Register is now always nonnegative,
so add REG_NONNEG note to the branch. */
- REG_NOTES (tem) = gen_rtx (EXPR_LIST, REG_NONNEG, NULL_RTX,
- REG_NOTES (tem));
+ REG_NOTES (tem) = gen_rtx_EXPR_LIST (REG_NONNEG, NULL_RTX,
+ REG_NOTES (tem));
}
bl->nonneg = 1;
@@ -6011,7 +6538,10 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
rtx reg = bl->biv->dest_reg;
enum machine_mode mode = GET_MODE (reg);
struct induction *v;
- rtx arg, new, tem;
+ rtx arg, tem;
+#ifdef HAVE_cc0
+ rtx new;
+#endif
int arg_operand;
char *fmt;
int i, j;
@@ -6037,7 +6567,42 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
return 1;
#ifdef HAVE_cc0
- if (SET_DEST (x) == cc0_rtx && SET_SRC (x) == reg)
+ /* The idea here is to replace the SET of cc0 by a REG with
+ a comparison involving related induction variables.
+ Unfortunately, however, such a replacement does not work
+ correctly if the REG is being used as signed and the
+ replacement value is unsigned, or vice versa. For
+ example, in:
+
+ for (int i = n; i >= 0; --i)
+ s[i] = 3;
+
+ `s' is an address (an unsigned quantity), while `i' is a
+ signed quantity. The exit test for the loop might look
+ something like:
+
+ (SET cc0 i)
+ (JUMP (SET (PC) (IF_THEN_ELSE (LT (CC0) (CONST_INT 0))
+ (LABEL_REF L) (PC))))
+
+ If we replace the SET of cc0 with a comparison of the
+ induction variable for `s + i' and the original value of `s',
+ however, we should be change the comparison in the
+ IF_THEN_ELSE to be unsigned. Otherwise, an array the spans
+ the boundary between "negative" and "positive" addresses will
+ confuse us.
+
+ There are related problems with overflow. If an induction
+ variable "wraps around" but the original value doest not, we
+ can get confused when doing the comparison.
+
+ Pointers can't wrap around, or overflow, in a conformant
+ program. Therefore, it's safe to do these optimizations if
+ both the original REG and the values in the replacement are
+ pointers. For now, though, we just disable these
+ optimizations. */
+
+ if (0 && SET_DEST (x) == cc0_rtx && SET_SRC (x) == reg)
{
/* Can replace with any giv that was reduced and
that has (MULT_VAL != 0) and (ADD_VAL == 0).
@@ -6052,14 +6617,25 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
&& v->mode == mode
&& 0)
{
+ /* If the giv V had the auto-inc address optimization applied
+ to it, and INSN occurs between the giv insn and the biv
+ insn, then we must adjust the value used here.
+ This is rare, so we don't bother to do so. */
+ if (v->auto_inc_opt
+ && ((INSN_LUID (v->insn) < INSN_LUID (insn)
+ && INSN_LUID (insn) < INSN_LUID (bl->biv->insn))
+ || (INSN_LUID (v->insn) > INSN_LUID (insn)
+ && INSN_LUID (insn) > INSN_LUID (bl->biv->insn))))
+ continue;
+
if (! eliminate_p)
return 1;
/* If the giv has the opposite direction of change,
then reverse the comparison. */
if (INTVAL (v->mult_val) < 0)
- new = gen_rtx (COMPARE, GET_MODE (v->new_reg),
- const0_rtx, v->new_reg);
+ new = gen_rtx_COMPARE (GET_MODE (v->new_reg),
+ const0_rtx, v->new_reg);
else
new = v->new_reg;
@@ -6084,17 +6660,28 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
|| (GET_CODE (v->add_val) == REG
&& REGNO_POINTER_FLAG (REGNO (v->add_val)))))
{
+ /* If the giv V had the auto-inc address optimization applied
+ to it, and INSN occurs between the giv insn and the biv
+ insn, then we must adjust the value used here.
+ This is rare, so we don't bother to do so. */
+ if (v->auto_inc_opt
+ && ((INSN_LUID (v->insn) < INSN_LUID (insn)
+ && INSN_LUID (insn) < INSN_LUID (bl->biv->insn))
+ || (INSN_LUID (v->insn) > INSN_LUID (insn)
+ && INSN_LUID (insn) > INSN_LUID (bl->biv->insn))))
+ continue;
+
if (! eliminate_p)
return 1;
/* If the giv has the opposite direction of change,
then reverse the comparison. */
if (INTVAL (v->mult_val) < 0)
- new = gen_rtx (COMPARE, VOIDmode, copy_rtx (v->add_val),
- v->new_reg);
+ new = gen_rtx_COMPARE (VOIDmode, copy_rtx (v->add_val),
+ v->new_reg);
else
- new = gen_rtx (COMPARE, VOIDmode, v->new_reg,
- copy_rtx (v->add_val));
+ new = gen_rtx_COMPARE (VOIDmode, v->new_reg,
+ copy_rtx (v->add_val));
/* Replace biv with the giv's reduced register. */
update_reg_last_use (v->add_val, insn);
@@ -6108,9 +6695,10 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
emit_insn_before (gen_move_insn (tem, copy_rtx (v->add_val)),
where);
- if (validate_change (insn, &SET_SRC (PATTERN (insn)),
- gen_rtx (COMPARE, VOIDmode,
- v->new_reg, tem), 0))
+ /* Substitute the new register for its invariant value in
+ the compare expression. */
+ XEXP (new, (INTVAL (v->mult_val) < 0) ? 0 : 1) = tem;
+ if (validate_change (insn, &SET_SRC (PATTERN (insn)), new, 0))
return 1;
}
}
@@ -6145,6 +6733,17 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
&& ! v->ignore && ! v->maybe_dead && v->always_computable
&& v->mode == mode)
{
+ /* If the giv V had the auto-inc address optimization applied
+ to it, and INSN occurs between the giv insn and the biv
+ insn, then we must adjust the value used here.
+ This is rare, so we don't bother to do so. */
+ if (v->auto_inc_opt
+ && ((INSN_LUID (v->insn) < INSN_LUID (insn)
+ && INSN_LUID (insn) < INSN_LUID (bl->biv->insn))
+ || (INSN_LUID (v->insn) > INSN_LUID (insn)
+ && INSN_LUID (insn) > INSN_LUID (bl->biv->insn))))
+ continue;
+
if (! eliminate_p)
return 1;
@@ -6185,6 +6784,17 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
{
rtx tem;
+ /* If the giv V had the auto-inc address optimization applied
+ to it, and INSN occurs between the giv insn and the biv
+ insn, then we must adjust the value used here.
+ This is rare, so we don't bother to do so. */
+ if (v->auto_inc_opt
+ && ((INSN_LUID (v->insn) < INSN_LUID (insn)
+ && INSN_LUID (insn) < INSN_LUID (bl->biv->insn))
+ || (INSN_LUID (v->insn) > INSN_LUID (insn)
+ && INSN_LUID (insn) > INSN_LUID (bl->biv->insn))))
+ continue;
+
if (! eliminate_p)
return 1;
@@ -6218,6 +6828,17 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
{
rtx tem;
+ /* If the giv V had the auto-inc address optimization applied
+ to it, and INSN occurs between the giv insn and the biv
+ insn, then we must adjust the value used here.
+ This is rare, so we don't bother to do so. */
+ if (v->auto_inc_opt
+ && ((INSN_LUID (v->insn) < INSN_LUID (insn)
+ && INSN_LUID (insn) < INSN_LUID (bl->biv->insn))
+ || (INSN_LUID (v->insn) > INSN_LUID (insn)
+ && INSN_LUID (insn) > INSN_LUID (bl->biv->insn))))
+ continue;
+
if (! eliminate_p)
return 1;
@@ -6269,6 +6890,17 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
&& rtx_equal_p (tv->add_val, v->add_val)
&& tv->mode == mode)
{
+ /* If the giv V had the auto-inc address optimization applied
+ to it, and INSN occurs between the giv insn and the biv
+ insn, then we must adjust the value used here.
+ This is rare, so we don't bother to do so. */
+ if (v->auto_inc_opt
+ && ((INSN_LUID (v->insn) < INSN_LUID (insn)
+ && INSN_LUID (insn) < INSN_LUID (bl->biv->insn))
+ || (INSN_LUID (v->insn) > INSN_LUID (insn)
+ && INSN_LUID (insn) > INSN_LUID (bl->biv->insn))))
+ continue;
+
if (! eliminate_p)
return 1;
@@ -6293,6 +6925,9 @@ maybe_eliminate_biv_1 (x, insn, bl, eliminate_p, where)
if (v->giv_type == DEST_ADDR && v->location == &XEXP (x, 0))
return 1;
break;
+
+ default:
+ break;
}
/* See if any subexpression fails elimination. */
@@ -6332,7 +6967,7 @@ last_use_this_basic_block (reg, insn)
n && GET_CODE (n) != CODE_LABEL && GET_CODE (n) != JUMP_INSN;
n = NEXT_INSN (n))
{
- if (regno_last_uid[REGNO (reg)] == INSN_UID (n))
+ if (REGNO_LAST_UID (REGNO (reg)) == INSN_UID (n))
return 1;
}
return 0;
@@ -6379,8 +7014,8 @@ update_reg_last_use (x, insn)
and hence this insn will never be the last use of x. */
if (GET_CODE (x) == REG && REGNO (x) < max_reg_before_loop
&& INSN_UID (insn) < max_uid_for_loop
- && uid_luid[regno_last_uid[REGNO (x)]] < uid_luid[INSN_UID (insn)])
- regno_last_uid[REGNO (x)] = INSN_UID (insn);
+ && uid_luid[REGNO_LAST_UID (REGNO (x))] < uid_luid[INSN_UID (insn)])
+ REGNO_LAST_UID (REGNO (x)) = INSN_UID (insn);
else
{
register int i, j;
@@ -6427,6 +7062,7 @@ get_condition (jump, earliest)
rtx op0, op1;
int reverse_code = 0;
int did_reverse_condition = 0;
+ enum machine_mode mode;
/* If this is not a standard conditional jump, we can't parse it. */
if (GET_CODE (jump) != JUMP_INSN
@@ -6434,6 +7070,7 @@ get_condition (jump, earliest)
return 0;
code = GET_CODE (XEXP (SET_SRC (PATTERN (jump)), 0));
+ mode = GET_MODE (XEXP (SET_SRC (PATTERN (jump)), 0));
op0 = XEXP (XEXP (SET_SRC (PATTERN (jump)), 0), 0);
op1 = XEXP (XEXP (SET_SRC (PATTERN (jump)), 0), 1);
@@ -6496,10 +7133,17 @@ get_condition (jump, earliest)
/* If this is setting OP0, get what it sets it to if it looks
relevant. */
- if (SET_DEST (set) == op0)
+ if (rtx_equal_p (SET_DEST (set), op0))
{
enum machine_mode inner_mode = GET_MODE (SET_SRC (set));
+ /* ??? We may not combine comparisons done in a CCmode with
+ comparisons not done in a CCmode. This is to aid targets
+ like Alpha that have an IEEE compliant EQ instruction, and
+ a non-IEEE compliant BEQ instruction. The use of CCmode is
+ actually artificial, simply to prevent the combination, but
+ should not affect other platforms. */
+
if ((GET_CODE (SET_SRC (set)) == COMPARE
|| (((code == NE
|| (code == LT
@@ -6515,7 +7159,9 @@ get_condition (jump, earliest)
&& FLOAT_STORE_FLAG_VALUE < 0)
#endif
))
- && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<')))
+ && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'))
+ && ((GET_MODE_CLASS (mode) == MODE_CC)
+ != (GET_MODE_CLASS (inner_mode) == MODE_CC)))
x = SET_SRC (set);
else if (((code == EQ
|| (code == GE
@@ -6531,7 +7177,9 @@ get_condition (jump, earliest)
&& FLOAT_STORE_FLAG_VALUE < 0)
#endif
))
- && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<')
+ && GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == '<'
+ && ((GET_MODE_CLASS (mode) == MODE_CC)
+ != (GET_MODE_CLASS (inner_mode) == MODE_CC)))
{
/* We might have reversed a LT to get a GE here. But this wasn't
actually the comparison of data, so we don't flag that we
@@ -6594,15 +7242,17 @@ get_condition (jump, earliest)
code = LT, op1 = GEN_INT (const_val + 1);
break;
+ /* When cross-compiling, const_val might be sign-extended from
+ BITS_PER_WORD to HOST_BITS_PER_WIDE_INT */
case GE:
- if (const_val
+ if ((const_val & max_val)
!= (((HOST_WIDE_INT) 1
<< (GET_MODE_BITSIZE (GET_MODE (op0)) - 1))))
code = GT, op1 = GEN_INT (const_val - 1);
break;
case LEU:
- if (uconst_val != max_val)
+ if (uconst_val < max_val)
code = LTU, op1 = GEN_INT (uconst_val + 1);
break;
@@ -6610,6 +7260,9 @@ get_condition (jump, earliest)
if (uconst_val != 0)
code = GTU, op1 = GEN_INT (uconst_val - 1);
break;
+
+ default:
+ break;
}
}
@@ -6627,7 +7280,7 @@ get_condition (jump, earliest)
return 0;
#endif
- return gen_rtx (code, VOIDmode, op0, op1);
+ return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
}
/* Similar to above routine, except that we also put an invariant last
@@ -6644,6 +7297,555 @@ get_condition_for_loop (x)
|| invariant_p (XEXP (comparison, 1)))
return comparison;
- return gen_rtx (swap_condition (GET_CODE (comparison)), VOIDmode,
- XEXP (comparison, 1), XEXP (comparison, 0));
+ return gen_rtx_fmt_ee (swap_condition (GET_CODE (comparison)), VOIDmode,
+ XEXP (comparison, 1), XEXP (comparison, 0));
+}
+
+#ifdef HAIFA
+/* Analyze a loop in order to instrument it with the use of count register.
+ loop_start and loop_end are the first and last insns of the loop.
+ This function works in cooperation with insert_bct ().
+ loop_can_insert_bct[loop_num] is set according to whether the optimization
+ is applicable to the loop. When it is applicable, the following variables
+ are also set:
+ loop_start_value[loop_num]
+ loop_comparison_value[loop_num]
+ loop_increment[loop_num]
+ loop_comparison_code[loop_num] */
+
+#ifdef HAVE_decrement_and_branch_on_count
+static
+void analyze_loop_iterations (loop_start, loop_end)
+ rtx loop_start, loop_end;
+{
+ rtx comparison, comparison_value;
+ rtx iteration_var, initial_value, increment;
+ enum rtx_code comparison_code;
+
+ rtx last_loop_insn;
+ rtx insn;
+ int i;
+
+ /* loop_variable mode */
+ enum machine_mode original_mode;
+
+ /* find the number of the loop */
+ int loop_num = uid_loop_num [INSN_UID (loop_start)];
+
+ /* we change our mind only when we are sure that loop will be instrumented */
+ loop_can_insert_bct[loop_num] = 0;
+
+ /* is the optimization suppressed. */
+ if ( !flag_branch_on_count_reg )
+ return;
+
+ /* make sure that count-reg is not in use */
+ if (loop_used_count_register[loop_num]){
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "analyze_loop_iterations %d: BCT instrumentation failed: count register already in use\n",
+ loop_num);
+ return;
+ }
+
+ /* make sure that the function has no indirect jumps. */
+ if (indirect_jump_in_function){
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "analyze_loop_iterations %d: BCT instrumentation failed: indirect jump in function\n",
+ loop_num);
+ return;
+ }
+
+ /* make sure that the last loop insn is a conditional jump */
+ last_loop_insn = PREV_INSN (loop_end);
+ if (GET_CODE (last_loop_insn) != JUMP_INSN || !condjump_p (last_loop_insn)) {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "analyze_loop_iterations %d: BCT instrumentation failed: invalid jump at loop end\n",
+ loop_num);
+ return;
+ }
+
+ /* First find the iteration variable. If the last insn is a conditional
+ branch, and the insn preceding it tests a register value, make that
+ register the iteration variable. */
+
+ /* We used to use prev_nonnote_insn here, but that fails because it might
+ accidentally get the branch for a contained loop if the branch for this
+ loop was deleted. We can only trust branches immediately before the
+ loop_end. */
+
+ comparison = get_condition_for_loop (last_loop_insn);
+ /* ??? Get_condition may switch position of induction variable and
+ invariant register when it canonicalizes the comparison. */
+
+ if (comparison == 0) {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "analyze_loop_iterations %d: BCT instrumentation failed: comparison not found\n",
+ loop_num);
+ return;
+ }
+
+ comparison_code = GET_CODE (comparison);
+ iteration_var = XEXP (comparison, 0);
+ comparison_value = XEXP (comparison, 1);
+
+ original_mode = GET_MODE (iteration_var);
+ if (GET_MODE_CLASS (original_mode) != MODE_INT
+ || GET_MODE_SIZE (original_mode) != UNITS_PER_WORD) {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "analyze_loop_iterations %d: BCT Instrumentation failed: loop variable not integer\n",
+ loop_num);
+ return;
+ }
+
+ /* get info about loop bounds and increment */
+ iteration_info (iteration_var, &initial_value, &increment,
+ loop_start, loop_end);
+
+ /* make sure that all required loop data were found */
+ if (!(initial_value && increment && comparison_value
+ && invariant_p (comparison_value) && invariant_p (increment)
+ && ! indirect_jump_in_function))
+ {
+ if (loop_dump_stream) {
+ fprintf (loop_dump_stream,
+ "analyze_loop_iterations %d: BCT instrumentation failed because of wrong loop: ", loop_num);
+ if (!(initial_value && increment && comparison_value)) {
+ fprintf (loop_dump_stream, "\tbounds not available: ");
+ if ( ! initial_value )
+ fprintf (loop_dump_stream, "initial ");
+ if ( ! increment )
+ fprintf (loop_dump_stream, "increment ");
+ if ( ! comparison_value )
+ fprintf (loop_dump_stream, "comparison ");
+ fprintf (loop_dump_stream, "\n");
+ }
+ if (!invariant_p (comparison_value) || !invariant_p (increment))
+ fprintf (loop_dump_stream, "\tloop bounds not invariant\n");
+ }
+ return;
+ }
+
+ /* make sure that the increment is constant */
+ if (GET_CODE (increment) != CONST_INT) {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "analyze_loop_iterations %d: instrumentation failed: not arithmetic loop\n",
+ loop_num);
+ return;
+ }
+
+ /* make sure that the loop contains neither function call, nor jump on table.
+ (the count register might be altered by the called function, and might
+ be used for a branch on table). */
+ for (insn = loop_start; insn && insn != loop_end; insn = NEXT_INSN (insn)) {
+ if (GET_CODE (insn) == CALL_INSN){
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "analyze_loop_iterations %d: BCT instrumentation failed: function call in the loop\n",
+ loop_num);
+ return;
+ }
+
+ if (GET_CODE (insn) == JUMP_INSN
+ && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
+ || GET_CODE (PATTERN (insn)) == ADDR_VEC)){
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "analyze_loop_iterations %d: BCT instrumentation failed: computed branch in the loop\n",
+ loop_num);
+ return;
+ }
+ }
+
+ /* At this point, we are sure that the loop can be instrumented with BCT.
+ Some of the loops, however, will not be instrumented - the final decision
+ is taken by insert_bct () */
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "analyze_loop_iterations: loop (luid =%d) can be BCT instrumented.\n",
+ loop_num);
+
+ /* mark all enclosing loops that they cannot use count register */
+ /* ???: In fact, since insert_bct may decide not to instrument this loop,
+ marking here may prevent instrumenting an enclosing loop that could
+ actually be instrumented. But since this is rare, it is safer to mark
+ here in case the order of calling (analyze/insert)_bct would be changed. */
+ for (i=loop_num; i != -1; i = loop_outer_loop[i])
+ loop_used_count_register[i] = 1;
+
+ /* Set data structures which will be used by the instrumentation phase */
+ loop_start_value[loop_num] = initial_value;
+ loop_comparison_value[loop_num] = comparison_value;
+ loop_increment[loop_num] = increment;
+ loop_comparison_code[loop_num] = comparison_code;
+ loop_can_insert_bct[loop_num] = 1;
+}
+
+
+/* instrument loop for insertion of bct instruction. We distinguish between
+ loops with compile-time bounds, to those with run-time bounds. The loop
+ behaviour is analized according to the following characteristics/variables:
+ ; Input variables:
+ ; comparison-value: the value to which the iteration counter is compared.
+ ; initial-value: iteration-counter initial value.
+ ; increment: iteration-counter increment.
+ ; Computed variables:
+ ; increment-direction: the sign of the increment.
+ ; compare-direction: '1' for GT, GTE, '-1' for LT, LTE, '0' for NE.
+ ; range-direction: sign (comparison-value - initial-value)
+ We give up on the following cases:
+ ; loop variable overflow.
+ ; run-time loop bounds with comparison code NE.
+ */
+
+static void
+insert_bct (loop_start, loop_end)
+ rtx loop_start, loop_end;
+{
+ rtx initial_value, comparison_value, increment;
+ enum rtx_code comparison_code;
+
+ int increment_direction, compare_direction;
+ int unsigned_p = 0;
+
+ /* if the loop condition is <= or >=, the number of iteration
+ is 1 more than the range of the bounds of the loop */
+ int add_iteration = 0;
+
+ /* the only machine mode we work with - is the integer of the size that the
+ machine has */
+ enum machine_mode loop_var_mode = SImode;
+
+ int loop_num = uid_loop_num [INSN_UID (loop_start)];
+
+ /* get loop-variables. No need to check that these are valid - already
+ checked in analyze_loop_iterations (). */
+ comparison_code = loop_comparison_code[loop_num];
+ initial_value = loop_start_value[loop_num];
+ comparison_value = loop_comparison_value[loop_num];
+ increment = loop_increment[loop_num];
+
+ /* check analyze_loop_iterations decision for this loop. */
+ if (! loop_can_insert_bct[loop_num]){
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "insert_bct: [%d] - was decided not to instrument by analyze_loop_iterations ()\n",
+ loop_num);
+ return;
+ }
+
+ /* It's impossible to instrument a competely unrolled loop. */
+ if (loop_unroll_factor [loop_num] == -1)
+ return;
+
+ /* make sure that the last loop insn is a conditional jump .
+ This check is repeated from analyze_loop_iterations (),
+ because unrolling might have changed that. */
+ if (GET_CODE (PREV_INSN (loop_end)) != JUMP_INSN
+ || !condjump_p (PREV_INSN (loop_end))) {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "insert_bct: not instrumenting BCT because of invalid branch\n");
+ return;
+ }
+
+ /* fix increment in case loop was unrolled. */
+ if (loop_unroll_factor [loop_num] > 1)
+ increment = GEN_INT ( INTVAL (increment) * loop_unroll_factor [loop_num] );
+
+ /* determine properties and directions of the loop */
+ increment_direction = (INTVAL (increment) > 0) ? 1:-1;
+ switch ( comparison_code ) {
+ case LEU:
+ unsigned_p = 1;
+ /* fallthrough */
+ case LE:
+ compare_direction = 1;
+ add_iteration = 1;
+ break;
+ case GEU:
+ unsigned_p = 1;
+ /* fallthrough */
+ case GE:
+ compare_direction = -1;
+ add_iteration = 1;
+ break;
+ case EQ:
+ /* in this case we cannot know the number of iterations */
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "insert_bct: %d: loop cannot be instrumented: == in condition\n",
+ loop_num);
+ return;
+ case LTU:
+ unsigned_p = 1;
+ /* fallthrough */
+ case LT:
+ compare_direction = 1;
+ break;
+ case GTU:
+ unsigned_p = 1;
+ /* fallthrough */
+ case GT:
+ compare_direction = -1;
+ break;
+ case NE:
+ compare_direction = 0;
+ break;
+ default:
+ abort ();
+ }
+
+
+ /* make sure that the loop does not end by an overflow */
+ if (compare_direction != increment_direction) {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "insert_bct: %d: loop cannot be instrumented: terminated by overflow\n",
+ loop_num);
+ return;
+ }
+
+ /* try to instrument the loop. */
+
+ /* Handle the simpler case, where the bounds are known at compile time. */
+ if (GET_CODE (initial_value) == CONST_INT && GET_CODE (comparison_value) == CONST_INT)
+ {
+ int n_iterations;
+ int increment_value_abs = INTVAL (increment) * increment_direction;
+
+ /* check the relation between compare-val and initial-val */
+ int difference = INTVAL (comparison_value) - INTVAL (initial_value);
+ int range_direction = (difference > 0) ? 1 : -1;
+
+ /* make sure the loop executes enough iterations to gain from BCT */
+ if (difference > -3 && difference < 3) {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "insert_bct: loop %d not BCT instrumented: too small iteration count.\n",
+ loop_num);
+ return;
+ }
+
+ /* make sure that the loop executes at least once */
+ if ((range_direction == 1 && compare_direction == -1)
+ || (range_direction == -1 && compare_direction == 1))
+ {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "insert_bct: loop %d: does not iterate even once. Not instrumenting.\n",
+ loop_num);
+ return;
+ }
+
+ /* make sure that the loop does not end by an overflow (in compile time
+ bounds we must have an additional check for overflow, because here
+ we also support the compare code of 'NE'. */
+ if (comparison_code == NE
+ && increment_direction != range_direction) {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "insert_bct (compile time bounds): %d: loop not instrumented: terminated by overflow\n",
+ loop_num);
+ return;
+ }
+
+ /* Determine the number of iterations by:
+ ;
+ ; compare-val - initial-val + (increment -1) + additional-iteration
+ ; num_iterations = -----------------------------------------------------------------
+ ; increment
+ */
+ difference = (range_direction > 0) ? difference : -difference;
+#if 0
+ fprintf (stderr, "difference is: %d\n", difference); /* @*/
+ fprintf (stderr, "increment_value_abs is: %d\n", increment_value_abs); /* @*/
+ fprintf (stderr, "add_iteration is: %d\n", add_iteration); /* @*/
+ fprintf (stderr, "INTVAL (comparison_value) is: %d\n", INTVAL (comparison_value)); /* @*/
+ fprintf (stderr, "INTVAL (initial_value) is: %d\n", INTVAL (initial_value)); /* @*/
+#endif
+
+ if (increment_value_abs == 0) {
+ fprintf (stderr, "insert_bct: error: increment == 0 !!!\n");
+ abort ();
+ }
+ n_iterations = (difference + increment_value_abs - 1 + add_iteration)
+ / increment_value_abs;
+
+#if 0
+ fprintf (stderr, "number of iterations is: %d\n", n_iterations); /* @*/
+#endif
+ instrument_loop_bct (loop_start, loop_end, GEN_INT (n_iterations));
+
+ /* Done with this loop. */
+ return;
+ }
+
+ /* Handle the more complex case, that the bounds are NOT known at compile time. */
+ /* In this case we generate run_time calculation of the number of iterations */
+
+ /* With runtime bounds, if the compare is of the form '!=' we give up */
+ if (comparison_code == NE) {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "insert_bct: fail for loop %d: runtime bounds with != comparison\n",
+ loop_num);
+ return;
+ }
+
+ else {
+ /* We rely on the existence of run-time guard to ensure that the
+ loop executes at least once. */
+ rtx sequence;
+ rtx iterations_num_reg;
+
+ int increment_value_abs = INTVAL (increment) * increment_direction;
+
+ /* make sure that the increment is a power of two, otherwise (an
+ expensive) divide is needed. */
+ if (exact_log2 (increment_value_abs) == -1)
+ {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "insert_bct: not instrumenting BCT because the increment is not power of 2\n");
+ return;
+ }
+
+ /* compute the number of iterations */
+ start_sequence ();
+ {
+ rtx temp_reg;
+
+ /* Again, the number of iterations is calculated by:
+ ;
+ ; compare-val - initial-val + (increment -1) + additional-iteration
+ ; num_iterations = -----------------------------------------------------------------
+ ; increment
+ */
+ /* ??? Do we have to call copy_rtx here before passing rtx to
+ expand_binop? */
+ if (compare_direction > 0) {
+ /* <, <= :the loop variable is increasing */
+ temp_reg = expand_binop (loop_var_mode, sub_optab, comparison_value,
+ initial_value, NULL_RTX, 0, OPTAB_LIB_WIDEN);
+ }
+ else {
+ temp_reg = expand_binop (loop_var_mode, sub_optab, initial_value,
+ comparison_value, NULL_RTX, 0, OPTAB_LIB_WIDEN);
+ }
+
+ if (increment_value_abs - 1 + add_iteration != 0)
+ temp_reg = expand_binop (loop_var_mode, add_optab, temp_reg,
+ GEN_INT (increment_value_abs - 1 + add_iteration),
+ NULL_RTX, 0, OPTAB_LIB_WIDEN);
+
+ if (increment_value_abs != 1)
+ {
+ /* ??? This will generate an expensive divide instruction for
+ most targets. The original authors apparently expected this
+ to be a shift, since they test for power-of-2 divisors above,
+ but just naively generating a divide instruction will not give
+ a shift. It happens to work for the PowerPC target because
+ the rs6000.md file has a divide pattern that emits shifts.
+ It will probably not work for any other target. */
+ iterations_num_reg = expand_binop (loop_var_mode, sdiv_optab,
+ temp_reg,
+ GEN_INT (increment_value_abs),
+ NULL_RTX, 0, OPTAB_LIB_WIDEN);
+ }
+ else
+ iterations_num_reg = temp_reg;
+ }
+ sequence = gen_sequence ();
+ end_sequence ();
+ emit_insn_before (sequence, loop_start);
+ instrument_loop_bct (loop_start, loop_end, iterations_num_reg);
+ }
+}
+
+/* instrument loop by inserting a bct in it. This is done in the following way:
+ 1. A new register is created and assigned the hard register number of the count
+ register.
+ 2. In the head of the loop the new variable is initialized by the value passed in the
+ loop_num_iterations parameter.
+ 3. At the end of the loop, comparison of the register with 0 is generated.
+ The created comparison follows the pattern defined for the
+ decrement_and_branch_on_count insn, so this insn will be generated in assembly
+ generation phase.
+ 4. The compare&branch on the old variable is deleted. So, if the loop-variable was
+ not used elsewhere, it will be eliminated by data-flow analisys. */
+
+static void
+instrument_loop_bct (loop_start, loop_end, loop_num_iterations)
+ rtx loop_start, loop_end;
+ rtx loop_num_iterations;
+{
+ rtx temp_reg1, temp_reg2;
+ rtx start_label;
+
+ rtx sequence;
+ enum machine_mode loop_var_mode = SImode;
+
+ if (HAVE_decrement_and_branch_on_count)
+ {
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream, "Loop: Inserting BCT\n");
+
+ /* eliminate the check on the old variable */
+ delete_insn (PREV_INSN (loop_end));
+ delete_insn (PREV_INSN (loop_end));
+
+ /* insert the label which will delimit the start of the loop */
+ start_label = gen_label_rtx ();
+ emit_label_after (start_label, loop_start);
+
+ /* insert initialization of the count register into the loop header */
+ start_sequence ();
+ temp_reg1 = gen_reg_rtx (loop_var_mode);
+ emit_insn (gen_move_insn (temp_reg1, loop_num_iterations));
+
+ /* this will be count register */
+ temp_reg2 = gen_rtx_REG (loop_var_mode, COUNT_REGISTER_REGNUM);
+ /* we have to move the value to the count register from an GPR
+ because rtx pointed to by loop_num_iterations could contain
+ expression which cannot be moved into count register */
+ emit_insn (gen_move_insn (temp_reg2, temp_reg1));
+
+ sequence = gen_sequence ();
+ end_sequence ();
+ emit_insn_after (sequence, loop_start);
+
+ /* insert new comparison on the count register instead of the
+ old one, generating the needed BCT pattern (that will be
+ later recognized by assembly generation phase). */
+ emit_jump_insn_before (gen_decrement_and_branch_on_count (temp_reg2, start_label),
+ loop_end);
+ LABEL_NUSES (start_label)++;
+ }
+
+}
+#endif /* HAVE_decrement_and_branch_on_count */
+
+#endif /* HAIFA */
+
+/* Scan the function and determine whether it has indirect (computed) jumps.
+
+ This is taken mostly from flow.c; similar code exists elsewhere
+ in the compiler. It may be useful to put this into rtlanal.c. */
+static int
+indirect_jump_in_function_p (start)
+ rtx start;
+{
+ rtx insn;
+
+ for (insn = start; insn; insn = NEXT_INSN (insn))
+ if (computed_jump_p (insn))
+ return 1;
+
+ return 0;
}
diff --git a/contrib/gcc/loop.h b/contrib/gcc/loop.h
index 4c9c483..25c16f0 100644
--- a/contrib/gcc/loop.h
+++ b/contrib/gcc/loop.h
@@ -75,7 +75,9 @@ struct induction
even if further info is available.
Both this and the above can be zero. */
unsigned ignore : 1; /* 1 prohibits further processing of giv */
- unsigned always_computable : 1;/* 1 if this set occurs each iteration */
+ unsigned always_computable : 1;/* 1 if this value is computable every
+ iteration. */
+ unsigned always_executed : 1; /* 1 if this set occurs each iteration. */
unsigned maybe_multiple : 1; /* Only used for a biv and 1 if this biv
update may be done multiple times per
iteration. */
@@ -88,6 +90,11 @@ struct induction
unsigned maybe_dead : 1; /* 1 if this giv might be dead. In that case,
we won't use it to eliminate a biv, it
would probably lose. */
+ unsigned auto_inc_opt : 1; /* 1 if this giv had its increment output next
+ to it to try to form an auto-inc address. */
+ unsigned unrolled : 1; /* 1 if new register has been allocated and
+ initialized in unrolled loop. */
+ unsigned shared : 1;
int lifetime; /* Length of life of this giv */
int times_used; /* # times this giv is used. */
rtx derive_adjustment; /* If nonzero, is an adjustment to be
@@ -174,3 +181,11 @@ rtx final_biv_value PROTO((struct iv_class *, rtx, rtx));
rtx final_giv_value PROTO((struct induction *, rtx, rtx));
void emit_unrolled_add PROTO((rtx, rtx, rtx));
int back_branch_in_range_p PROTO((rtx, rtx, rtx));
+
+extern int *loop_unroll_factor;
+#ifdef HAIFA
+/* variables for interaction between unroll.c and loop.c, for
+ the insertion of branch-on-count instruction. */
+extern rtx *loop_start_value;
+#endif /* HAIFA */
+
diff --git a/contrib/gcc/machmode.def b/contrib/gcc/machmode.def
index 625586c..ab2215e 100644
--- a/contrib/gcc/machmode.def
+++ b/contrib/gcc/machmode.def
@@ -1,6 +1,6 @@
/* This file contains the definitions and documentation for the
- machine modes used in the the GNU compiler.
- Copyright (C) 1987, 1992, 1994 Free Software Foundation, Inc.
+ machine modes used in the GNU compiler.
+ Copyright (C) 1987, 1992, 1994, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -42,7 +42,7 @@ Boston, MA 02111-1307, USA. */
Third argument states the kind of representation:
MODE_INT - integer
MODE_FLOAT - floating
- MODE_PARTIAL_INT - PSImode and PDImode
+ MODE_PARTIAL_INT - PQImode, PHImode, PSImode and PDImode
MODE_CC - modes used for representing the condition code in a register
MODE_COMPLEX_INT, MODE_COMPLEX_FLOAT - complex number
MODE_RANDOM - anything else
@@ -63,7 +63,9 @@ Boston, MA 02111-1307, USA. */
as for example on CONST_INT RTL expressions. */
DEF_MACHMODE (VOIDmode, "VOID", MODE_RANDOM, 0, 0, VOIDmode)
+DEF_MACHMODE (PQImode, "PQI", MODE_PARTIAL_INT, 1, 1, PHImode)
DEF_MACHMODE (QImode, "QI", MODE_INT, 1, 1, HImode) /* int types */
+DEF_MACHMODE (PHImode, "PHI", MODE_PARTIAL_INT, 2, 2, PSImode)
DEF_MACHMODE (HImode, "HI", MODE_INT, 2, 2, SImode)
/* Pointers on some machines use this type to distinguish them from ints.
Useful if a pointer is 4 bytes but has some bits that are not significant,
@@ -84,6 +86,8 @@ DEF_MACHMODE (XFmode, "XF", MODE_FLOAT, 12, 12, TFmode) /* IEEE extended */
DEF_MACHMODE (TFmode, "TF", MODE_FLOAT, 16, 16, VOIDmode)
/* Complex modes. */
+DEF_MACHMODE (QCmode, "QC", MODE_COMPLEX_FLOAT, 2, 1, HCmode)
+DEF_MACHMODE (HCmode, "HC", MODE_COMPLEX_FLOAT, 4, 2, SCmode)
DEF_MACHMODE (SCmode, "SC", MODE_COMPLEX_FLOAT, 8, 4, DCmode)
DEF_MACHMODE (DCmode, "DC", MODE_COMPLEX_FLOAT, 16, 8, XCmode)
DEF_MACHMODE (XCmode, "XC", MODE_COMPLEX_FLOAT, 24, 12, TCmode)
diff --git a/contrib/gcc/machmode.h b/contrib/gcc/machmode.h
index 85b5543..5f8459d 100644
--- a/contrib/gcc/machmode.h
+++ b/contrib/gcc/machmode.h
@@ -1,5 +1,5 @@
/* Machine mode definitions for GNU C-Compiler; included by rtl.h and tree.h.
- Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -18,17 +18,10 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-
-/* Add prototype support. */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
#ifndef HAVE_MACHINE_MODES
+#define HAVE_MACHINE_MODES
+
+#include "gansidecl.h"
/* Strictly speaking, this isn't the proper place to include these definitions,
but this file is included by every GCC file.
@@ -60,7 +53,76 @@ Boston, MA 02111-1307, USA. */
/* Provide a default way to print an address in hex via printf. */
#ifndef HOST_PTR_PRINTF
-#define HOST_PTR_PRINTF sizeof (int) == sizeof (char *) ? "%x" : "%lx"
+# ifdef HAVE_PRINTF_PTR
+# define HOST_PTR_PRINTF "%p"
+# else
+# define HOST_PTR_PRINTF \
+ (sizeof (int) == sizeof (char *) ? "%x" \
+ : sizeof (long) == sizeof (char *) ? "%lx" : "%llx")
+# endif
+#endif /* ! HOST_PTR_PRINTF */
+
+/* Provide defaults for the way to print a HOST_WIDE_INT
+ in various manners. */
+
+#ifndef HOST_WIDE_INT_PRINT_DEC
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+#define HOST_WIDE_INT_PRINT_DEC "%d"
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
+#define HOST_WIDE_INT_PRINT_DEC "%ld"
+#else
+#define HOST_WIDE_INT_PRINT_DEC "%lld"
+#endif
+#endif
+#endif
+
+#ifndef HOST_WIDE_INT_PRINT_UNSIGNED
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+#define HOST_WIDE_INT_PRINT_UNSIGNED "%u"
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
+#define HOST_WIDE_INT_PRINT_UNSIGNED "%lu"
+#else
+#define HOST_WIDE_INT_PRINT_UNSIGNED "%llu"
+#endif
+#endif
+#endif
+
+#ifndef HOST_WIDE_INT_PRINT_HEX
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+#define HOST_WIDE_INT_PRINT_HEX "0x%x"
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
+#define HOST_WIDE_INT_PRINT_HEX "0x%lx"
+#else
+#define HOST_WIDE_INT_PRINT_HEX "0x%llx"
+#endif
+#endif
+#endif
+
+#ifndef HOST_WIDE_INT_PRINT_DOUBLE_HEX
+#if HOST_BITS_PER_WIDE_INT == 64
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+#define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%x%016x"
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
+#define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%lx%016lx"
+#else
+#define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%llx%016llx"
+#endif
+#endif
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+#define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%x%08x"
+#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
+#define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%lx%08lx"
+#else
+#define HOST_WIDE_INT_PRINT_DOUBLE_HEX "0x%llx%08llx"
+#endif
+#endif
+#endif
#endif
/* Make an enum class that gives all the machine modes. */
@@ -77,8 +139,6 @@ MAX_MACHINE_MODE };
#undef DEF_MACHMODE
-#define HAVE_MACHINE_MODES
-
#ifndef NUM_MACHINE_MODES
#define NUM_MACHINE_MODES (int) MAX_MACHINE_MODE
#endif
@@ -86,7 +146,7 @@ MAX_MACHINE_MODE };
/* Get the name of mode MODE as a string. */
extern char *mode_name[];
-#define GET_MODE_NAME(MODE) (mode_name[(int)(MODE)])
+#define GET_MODE_NAME(MODE) (mode_name[(int) (MODE)])
enum mode_class { MODE_RANDOM, MODE_INT, MODE_FLOAT, MODE_PARTIAL_INT, MODE_CC,
MODE_COMPLEX_INT, MODE_COMPLEX_FLOAT, MAX_MODE_CLASS};
@@ -95,7 +155,7 @@ enum mode_class { MODE_RANDOM, MODE_INT, MODE_FLOAT, MODE_PARTIAL_INT, MODE_CC,
(integer, floating, complex, etc.) */
extern enum mode_class mode_class[];
-#define GET_MODE_CLASS(MODE) (mode_class[(int)(MODE)])
+#define GET_MODE_CLASS(MODE) (mode_class[(int) (MODE)])
/* Nonzero if MODE is an integral mode. */
#define INTEGRAL_MODE_P(MODE) \
@@ -108,15 +168,20 @@ extern enum mode_class mode_class[];
(GET_MODE_CLASS (MODE) == MODE_FLOAT \
|| GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)
+/* Nonzero if MODE is a complex mode. */
+#define COMPLEX_MODE_P(MODE) \
+ (GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT \
+ || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)
+
/* Get the size in bytes of an object of mode MODE. */
extern int mode_size[];
-#define GET_MODE_SIZE(MODE) (mode_size[(int)(MODE)])
+#define GET_MODE_SIZE(MODE) (mode_size[(int) (MODE)])
/* Get the size in bytes of the basic parts of an object of mode MODE. */
extern int mode_unit_size[];
-#define GET_MODE_UNIT_SIZE(MODE) (mode_unit_size[(int)(MODE)])
+#define GET_MODE_UNIT_SIZE(MODE) (mode_unit_size[(int) (MODE)])
/* Get the number of units in the object. */
@@ -126,7 +191,7 @@ extern int mode_unit_size[];
/* Get the size in bits of an object of mode MODE. */
-#define GET_MODE_BITSIZE(MODE) (BITS_PER_UNIT * mode_size[(int)(MODE)])
+#define GET_MODE_BITSIZE(MODE) (BITS_PER_UNIT * mode_size[(int) (MODE)])
/* Get a bitmask containing 1 for all bits in a word
that fit within mode MODE. */
@@ -138,7 +203,7 @@ extern int mode_unit_size[];
/* Get the next wider natural mode (eg, QI -> HI -> SI -> DI -> TI). */
extern enum machine_mode mode_wider_mode[];
-#define GET_MODE_WIDER_MODE(MODE) (mode_wider_mode[(int)(MODE)])
+#define GET_MODE_WIDER_MODE(MODE) (mode_wider_mode[(int) (MODE)])
/* Return the mode for data of a given size SIZE and mode class CLASS.
If LIMIT is nonzero, then don't use modes bigger than MAX_FIXED_MODE_SIZE.
@@ -159,7 +224,7 @@ extern enum machine_mode get_best_mode PROTO((int, int, int, enum machine_mode,
/* For each class, get the narrowest mode in that class. */
extern enum machine_mode class_narrowest_mode[];
-#define GET_CLASS_NARROWEST_MODE(CLASS) class_narrowest_mode[(int)(CLASS)]
+#define GET_CLASS_NARROWEST_MODE(CLASS) class_narrowest_mode[(int) (CLASS)]
/* Define the integer modes whose sizes are BITS_PER_UNIT and BITS_PER_WORD
and the mode whose class is Pmode and whose size is POINTER_SIZE. */
diff --git a/contrib/gcc/makefile.vms b/contrib/gcc/makefile.vms
new file mode 100644
index 0000000..7f0b7ae
--- /dev/null
+++ b/contrib/gcc/makefile.vms
@@ -0,0 +1,413 @@
+#
+# makefile for egcs
+#
+# Created by Klaus K"ampf, kkaempf@progis.de
+#
+
+# choose egcs or dec c
+#CC = gcc
+CC = cc
+
+# With or withou haifa scheduler ?
+#HAIFA=,"HAIFA"
+HAIFA=
+
+PWD=sys$$disk:[]
+RM=delete/nolog
+
+ifeq ($(CC),gcc)
+ifeq ($(ARCH),ALPHA)
+CFLAGS=/define=("HAVE_CONFIG_H=1","USE_COLLECT2" $(HAIFA))
+LIBS=,gnu_cc_library:libgcc.olb/lib,sys$$library:vaxcrtl.olb/lib,gnu_cc_library:crt0.obj
+else
+CFLAGS=/define=("HAVE_CONFIG_H=1","USE_COLLECT2" $(HAIFA))
+LIBS=,gnu_cc_library:libgcc.olb/lib,sys$$library:vaxcrtl.olb/lib
+endif
+LFLAGS=/map/full
+#LFLAGS=
+else
+ifeq ($(ARCH),ALPHA)
+CFLAGS=/names=as_is/float=ieee/noopt/debug/define=("HAVE_CONFIG_H=1","USE_COLLECT2" $(HAIFA))\
+/warning=disable=(missingreturn,implicitfunc,ptrmismatch,undefescap,longextern,duptypespec)
+else
+CFLAGS=/noopt/debug/define=("HAVE_CONFIG_H=1","USE_COLLECT2" $(HAIFA))
+endif
+LFLAGS=/nomap
+LIBS=,sys$$library:vaxcrtl.olb/lib
+endif
+
+BISON = bison
+BISON_FLAGS= /Yacc/Define/Verbose
+RENAME= rename/New_Version
+LINK = link #/noshare/nosysshr
+EDIT = edit
+SEARCH= search
+ABORT = exit %x002C
+echo = write sys$$output
+
+CINCL1 = /Incl=([],[.config])
+CINCL2 = /Incl=([],[.ginclude],[.config])
+CINCL_SUB = /Incl=([],[-],[-.ginclude],[-.config])
+CINCL_CP= /Incl=([],[.config],[.cp],[.cp.inc])
+
+MDFILE = [.config.$(ARCH)]$(ARCH).md
+
+ifeq ($(HAIFA),)
+SCHED=sched
+else
+SCHED=haifa-sched
+endif
+
+GENOBJS=[]rtl.obj,obstack.obj
+
+INDEPOBJS= []toplev.obj,version.obj,tree.obj,print-tree.obj,stor-layout.obj,\
+fold-const.obj,function.obj,stmt.obj,except.obj,expr.obj,calls.obj,expmed.obj,\
+explow.obj,optabs.obj,varasm.obj,rtl.obj,print-rtl.obj,rtlanal.obj,\
+emit-rtl.obj,genrtl.obj,real.obj,regmove.obj,dbxout.obj,sdbout.obj,dwarfout.obj,\
+dwarf2out.obj,xcoffout.obj,bitmap.obj,alias.obj,\
+integrate.obj,jump.obj,cse.obj,loop.obj,unroll.obj,flow.obj,stupid.obj,\
+combine.obj,regclass.obj,local-alloc.obj,global.obj,reload.obj,\
+reload1.obj,caller-save.obj,insn-peep.obj,reorg.obj,$(SCHED).obj,\
+final.obj,recog.obj,reg-stack.obj,insn-opinit.obj,insn-recog.obj,\
+insn-extract.obj,insn-output.obj,insn-emit.obj,\
+profile.obj,insn-attrtab.obj,\
+aux-output.obj,getpwd.obj,convert.obj
+
+CC1OBJS=[]c-parse.obj,c-lang.obj,c-lex.obj,c-pragma.obj,c-decl.obj,\
+c-typeck.obj,c-convert.obj,c-aux-info.obj,c-common.obj,c-iterate.obj,\
+obstack.obj
+
+OBJCOBJS=
+
+# list copied from cc1plus-objs.opt
+
+CC1PLUSOBJS=[.cp]call.obj,[.cp]decl2.obj,\
+[.cp]except.obj,[.cp]pt.obj,\
+[.cp]spew.obj,[.cp]xref.obj,[.cp]class.obj,\
+[.cp]expr.obj,[.cp]lex.obj,\
+[.cp]ptree.obj,[.cp]tree.obj,[.cp]cvt.obj,\
+[.cp]errfn.obj,[.cp]rtti.obj,[.cp]method.obj,\
+[.cp]search.obj,[.cp]typeck.obj,[.cp]decl.obj,\
+[.cp]error.obj,[.cp]friend.obj,[.cp]init.obj,[.cp]parse.obj,\
+[.cp]sig.obj,[.cp]typeck2.obj,[.cp]repo.obj,\
+[.cp]input.obj,\
+[]obstack.obj,\
+[]c-common.obj,[]c-pragma.obj
+
+CCCPOBJS=[]cccp.obj,cexp.obj,version.obj,prefix.obj
+
+ALLOCA=,[]alloca.obj
+
+LIBIBERTY = [-.libiberty]libiberty.olb
+
+CXX_LIB2FUNCS = [.cp]tinfo.obj,[.cp]tinfo2.obj,\
+[.cp]new.obj,[.cp]new1.obj,[.cp]new2.obj,[.cp]exception.obj
+
+.c.obj:
+ $(CC) $(CFLAGS) $(CINCL1) $</obj=$@
+
+.cc.obj:
+ $(CC)/plus/CPP="-nostdinc++" $(CFLAGS) $(CINCL_CP) $</obj=$@
+
+INSN_INCLUDES=insn-attr.h insn-codes.h insn-config.h insn-flags.h
+
+#
+#
+#
+
+all: cpp.exe cc1.exe float.h limits.h libgcc2.olb
+
+allplus: cc1plus.exe libgccplus.olb
+
+libplus: libgccplus.olb
+
+cc1.exe: $(CC1OBJS) $(ALLOCA) $(INDEPOBJS)
+ $(LINK)$(LFLAGS)/exe=$@ version.opt/opt,cc1-objs.opt/Opt,independent.opt/Opt$(ALLOCA)$(LIBS)
+
+cpp.exe: $(CCCPOBJS) $(ALLOCA)
+ $(LINK)$(LFLAGS)/exe=$@ $(CCCPOBJS),version.opt/opt$(ALLOCA)$(LIBS)
+
+cc1plus.exe: $(CC1PLUSOBJS) $(ALLOCA) $(INDEPOBJS)
+ $(LINK)$(LFLAGS)/exe=$@ version.opt/opt,cc1plus-objs.opt/Opt,independent.opt/Opt$(ALLOCA)$(LIBS)
+
+gcc.exe: gcc.obj version.obj choose-temp.obj pexecute.obj prefix.obj obstack.obj
+ $(LINK)$(LFLAGS)/exe=$@ $^$(ALLOCA)$(LIBS)
+
+install: cpp.exe cc1.exe gcc.exe libgcc2.olb
+ $(CP) $^ GNU_CC_LIBRARY
+
+installplus: cc1plus.exe libgccplus.olb
+ $(CP) $^ GNU_CC_LIBRARY
+
+float.h: enquire.exe
+ mcr $(PWD)enquire.exe -f > $@
+
+limits.h: enquire.exe
+ mcr $(PWD)enquire.exe -l > $@
+
+enquire.exe: enquire.obj
+ $(LINK)$(LFLAGS)/exe=$@ enquire.obj$(ALLOCA)$(LIBS)
+
+libgcc2.olb:
+ $$ @make-l2
+
+libgccplus.olb: $(CXX_LIB2FUNCS)
+ lib/create libgccplus $(CXX_LIB2FUNCS)
+
+genattr.exe: genattr.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-attr.h: genattr.exe $(MDFILE)
+ mcr $(PWD)genattr.exe $(MDFILE) > $@
+
+genflags.exe: genflags.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-flags.h: genflags.exe $(MDFILE)
+ mcr $(PWD)genflags.exe $(MDFILE) > $@
+
+gencodes.exe: gencodes.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-codes.h: gencodes.exe $(MDFILE)
+ mcr $(PWD)gencodes.exe $(MDFILE) > $@
+
+genconfig.exe: genconfig.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-config.h: genconfig.exe $(MDFILE)
+ mcr $(PWD)genconfig.exe $(MDFILE) > $@
+
+genpeep.exe: genpeep.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-peep.c: genpeep.exe $(MDFILE)
+ mcr $(PWD)genpeep.exe $(MDFILE) > $@
+
+genopinit.exe: genopinit.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-opinit.c: genopinit.exe $(MDFILE)
+ mcr $(PWD)genopinit.exe $(MDFILE) > $@
+
+genrecog.exe: genrecog.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-recog.c: genrecog.exe $(MDFILE)
+ mcr $(PWD)genrecog.exe $(MDFILE) > $@
+
+genextract.exe: genextract.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-extract.c: genextract.exe $(MDFILE)
+ mcr $(PWD)genextract.exe $(MDFILE) > $@
+
+genoutput.exe: genoutput.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-output.c: genoutput.exe $(MDFILE)
+ mcr $(PWD)genoutput.exe $(MDFILE) > $@
+
+genemit.exe: genemit.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-emit.c: genemit.exe $(MDFILE)
+ mcr $(PWD)genemit.exe $(MDFILE) > $@
+
+genattrtab.exe: genattrtab.obj,rtlanal.obj,$(GENOBJS)$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+insn-attrtab.c: genattrtab.exe $(MDFILE)
+ mcr $(PWD)genattrtab.exe $(MDFILE) > $@
+
+gengenrtl.exe: gengenrtl.obj,obstack.obj,$(ALLOCA)
+ $(LINK) $(LFLAGS)/exe=$@ $^$(LIBS)
+
+genrtl.h genrtl.c: gengenrtl.exe
+ mcr $(PWD)gengenrtl.exe genrtl.h genrtl.c
+
+cccp.obj: cccp.c config.h
+aux-output.obj: aux-output.c insn-attr.h insn-flags.h insn-config.h
+caller-save.obj: caller-save.c insn-config.h
+calls.obj: calls.c insn-flags.h
+combine.obj: combine.c insn-attr.h insn-flags.h insn-codes.h insn-config.h
+cse.obj: cse.c insn-config.h
+c-decl.obj: c-decl.c expr.h integrate.h insn-codes.h insn-config.h
+c-lex.obj: c-lex.c genrtl.h
+c-typeck.obj: c-typeck.c
+dbxout.obj: dbxout.c insn-config.h
+dwarfout.obj: dwarfout.c insn-config.h
+dwarf2out.obj: dwarf2out.c insn-config.h
+emit-rtl.obj: emit-rtl.c insn-config.h
+except.obj: except.c insn-flags.h insn-codes.h insn-config.h
+explow.obj: explow.c insn-flags.h insn-codes.h insn-config.h
+expmed.obj: expmed.c insn-flags.h insn-codes.h insn-config.h
+expr.obj: expr.c insn-flags.h insn-config.h
+final.obj: final.c tm.h insn-attr.h insn-flags.h insn-codes.h insn-config.h
+flow.obj: flow.c insn-config.h
+function.obj: function.c insn-flags.h insn-codes.h insn-config.h insn-codes.h insn-config.h
+genattrtab.obj: genattrtab.c insn-config.h
+genextract.obj: genextract.c insn-config.h
+global.obj: global.c insn-config.h
+integrate.obj: integrate.c integrate.h insn-flags.h insn-config.h
+jump.obj: jump.c insn-flags.h insn-config.h
+local-alloc.obj: local-alloc.c insn-config.h
+loop.obj: loop.c insn-flags.h insn-config.h
+optabs.obj: optabs.c insn-flags.h insn-codes.h insn-config.h
+print-rtl.obj: print-rtl.c
+profile.obj: profile.c insn-flags.h insn-config.h
+recog.obj: recog.c insn-attr.h insn-flags.h insn-codes.h insn-config.h
+regclass.obj: regclass.c insn-config.h
+reg-stack.obj: reg-stack.c insn-config.h
+reload.obj: reload.c insn-codes.h insn-config.h
+reload1.obj: reload1.c insn-flags.h insn-codes.h insn-config.h
+reorg.obj: reorg.c insn-attr.h insn-flags.h insn-config.h
+sched.obj: sched.c insn-attr.h insn-config.h
+haifa-sched.obj: haifa-sched.c insn-attr.h insn-config.h
+stmt.obj: stmt.c insn-flags.h insn-codes.h insn-config.h
+stor-layout.obj: stor-layout.c
+stupid.obj: stupid.c
+toplev.obj: toplev.c insn-attr.h insn-config.h
+unroll.obj: unroll.c insn-config.h
+
+insn-attrtab.obj: insn-attrtab.c insn-attr.h insn-config.h
+insn-output.obj: insn-output.c insn-attr.h insn-flags.h insn-codes.h
+insn-emit.obj: insn-emit.c insn-flags.h insn-codes.h insn-config.h
+insn-opinit.obj: insn-opinit.c insn-flags.h insn-codes.h insn-config.h
+insn-output.obj: insn-config.h
+insn-recog.obj: insn-config.h
+
+varasm.obj: varasm.c tm.h
+toplev.obj: toplev.c tm.h
+
+cexp.c: cexp.y
+ $(BISON) $(BISON_FLAGS)/output=$@ $<
+c-parse.c: c-parse.y
+ $(BISON) $(BISON_FLAGS)/output=$@ $<
+[.cp]parse.c: [.cp]parse.y
+ $(BISON) $(BISON_FLAGS)/output=$@ $<
+[.cp]parse.h: [.cp]parse.c
+ @$(ECHO) "Must copy YYEMPTY from [.cp]parse.c to [.cp]parse.h"
+ $$ stop
+aux-output.c: [.config.$(ARCH)]$(ARCH).c
+ copy $< $@
+
+expr.h: insn-codes.h
+reload.h: insn-config.h
+integrate.h: insn-config.h
+
+config.h:
+ $$ @vmsconfig
+
+cleancccp:
+ $$ purge
+ $(RM) cccp.obj;,cexp.obj;
+ $(RM) cpp.exe;
+
+cleanlib:
+ $$ purge
+ $(RM) libgcc2.olb;
+
+cleanlibplus:
+ $$ purge
+ $(RM) [.cp]tinfo.obj;
+ $(RM) [.cp]tinfo2.obj;
+ $(RM) [.cp]new.obj;
+ $(RM) [.cp]new1.obj;
+ $(RM) [.cp]new2.obj;
+ $(RM) [.cp]exception.obj;
+ $(RM) libgccplus.olb;
+
+clean:
+ $$ purge
+ $$ purge [.cp]
+ $(RM) *.obj;*
+ $(RM) [.cp]*.obj;*
+ $(RM) [.cp]parse.output;*
+ $(RM) *.cpp;*
+ $(RM) *.s;*
+ $(RM) *.rtl;*
+ $(RM) a.out;
+ $(RM) *.combine;
+ $(RM) *.cpp;
+ $(RM) *.cse;
+ $(RM) *.cse2;
+ $(RM) *.dbr;
+ $(RM) *.flow;
+ $(RM) *.greg;
+ $(RM) *.jump;
+ $(RM) *.jump2;
+ $(RM) *.loop;
+ $(RM) *.lreg;
+ $(RM) *.rtl;
+ $(RM) *.sched;
+ $(RM) *.sched2;
+ $(RM) *.map;
+ $(RM) genattr.exe;,insn-attr.h;
+ $(RM) genflags.exe;,insn-flags.h;
+ $(RM) gencodes.exe;,insn-codes.h;
+ $(RM) genconfig.exe;,insn-config.h;
+ $(RM) genpeep.exe;,insn-peep.c;
+ $(RM) genopinit.exe;,insn-opinit.c;
+ $(RM) genrecog.exe;,insn-recog.c;
+ $(RM) genextract.exe;,insn-extract.c;
+ $(RM) genoutput.exe;,insn-output.c;
+ $(RM) genemit.exe;,insn-emit.c;
+ $(RM) genattrtab.exe;,insn-attrtab.c;
+ $(RM) gengenrtl.exe;,genrtl.c;,genrtl.h;
+ $(RM) cc1.exe;
+ $(RM) cpp.exe;
+ $(RM) cc1plus.exe;
+ $(RM) libgcc2.olb;
+ $(RM) libgccplus.olb;
+ $(RM) enquire.exe;,float.h;,limits.h;
+#
+# clean everything axpconfig.com creates
+#
+distclean: clean cleancccp
+ purge [...]
+ $(RM) config.h;
+ $(RM) tconfig.h;
+ $(RM) hconfig.h;
+ $(RM) tm.h;
+ $(RM) options.h;
+ $(RM) specs.h;
+ $(RM) aux-output.c;
+
+[.cp]call.obj: [.cp]call.c
+[.cp]decl2.obj: [.cp]decl2.c
+[.cp]except.obj: [.cp]except.c insn-codes.h insn-flags.h
+[.cp]pt.obj: [.cp]pt.c
+[.cp]spew.obj: [.cp]spew.c
+[.cp]xref.obj: [.cp]xref.c
+[.cp]class.obj: [.cp]class.c
+[.cp]expr.obj: [.cp]expr.c insn-codes.h
+[.cp]lex.obj: [.cp]lex.c [.cp]parse.h
+[.cp]ptree.obj: [.cp]ptree.c
+[.cp]tree.obj: [.cp]tree.c
+[.cp]cvt.obj: [.cp]cvt.c
+[.cp]errfn.obj: [.cp]errfn.c
+[.cp]rtti.obj: [.cp]rtti.c
+[.cp]method.obj: [.cp]method.c insn-codes.h
+[.cp]search.obj: [.cp]search.c
+[.cp]typeck.obj: [.cp]typeck.c
+[.cp]decl.obj: [.cp]decl.c
+[.cp]error.obj: [.cp]error.c
+[.cp]friend.obj: [.cp]friend.c
+[.cp]init.obj: [.cp]init.c
+[.cp]parse.obj: [.cp]parse.c
+ $(CC) $(CFLAGS) $(CINCL_CP) $^/obj=$@
+[.cp]sig.obj: [.cp]sig.c
+[.cp]typeck2.obj: [.cp]typeck2.c
+[.cp]repo.obj: [.cp]repo.c
+[.cp]input.obj: [.cp]input.c
+ $(TOUCH) $@
+# g++ library
+[.cp]tinfo.obj: [.cp]tinfo.cc
+[.cp]tinfo2.obj: [.cp]tinfo2.cc
+[.cp]new.obj: [.cp]new.cc
+[.cp]new1.obj: [.cp]new1.cc
+[.cp]new2.obj: [.cp]new2.cc
+[.cp]exception.obj: [.cp]exception.cc
+
+#EOF
diff --git a/contrib/gcc/md.texi b/contrib/gcc/md.texi
index 6fcf419..e9d810c 100644
--- a/contrib/gcc/md.texi
+++ b/contrib/gcc/md.texi
@@ -1,4 +1,4 @@
-@c Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+@c Copyright (C) 1988, 89, 92, 93, 94, 96, 1998 Free Software Foundation, Inc.
@c This is part of the GCC manual.
@c For copying conditions, see the file gcc.texi.
@@ -174,7 +174,9 @@ Operand numbers must be chosen consecutively counting from zero in
each instruction pattern. There may be only one @code{match_operand}
expression in the pattern for each operand number. Usually operands
are numbered in the order of appearance in @code{match_operand}
-expressions.
+expressions. In the case of a @code{define_expand}, any operand numbers
+used only in @code{match_dup} expressions have higher values than all
+other operand numbers.
@var{predicate} is a string that is the name of a C function that accepts two
arguments, an expression and a machine mode. During matching, the
@@ -399,6 +401,25 @@ An insn that matches this pattern might look like:
Like @code{match_op_dup}, but for @code{match_parallel} instead of
@code{match_operator}.
+@findex match_insn
+@item (match_insn @var{predicate})
+Match a complete insn. Unlike the other @code{match_*} recognizers,
+@code{match_insn} does not take an operand number.
+
+The machine mode @var{m} of @code{match_insn} works like that of
+@code{match_operand}: it is passed as the second argument to the
+predicate function, and that function is solely responsible for
+deciding whether the expression to be matched ``has'' that mode.
+
+@findex match_insn2
+@item (match_insn2 @var{n} @var{predicate})
+Match a complete insn.
+
+The machine mode @var{m} of @code{match_insn2} works like that of
+@code{match_operand}: it is passed as the second argument to the
+predicate function, and that function is solely responsible for
+deciding whether the expression to be matched ``has'' that mode.
+
@findex address
@item (address (match_operand:@var{m} @var{n} "address_operand" ""))
This complex of expressions is a placeholder for an operand number
@@ -507,8 +528,8 @@ already defined, then you can simply use @code{#} as the output template
instead of writing an output template that emits the multiple assembler
instructions.
-If @code{ASSEMBLER_DIALECT} is defined, you can use
-@samp{@{option0|option1|option2@}} constructs in the templates. These
+If the macro @code{ASSEMBLER_DIALECT} is defined, you can use construct
+of the form @samp{@{option0|option1|option2@}} in the templates. These
describe multiple variants of assembler language syntax.
@xref{Instruction Output}.
@@ -621,7 +642,7 @@ as follows, having the output control string start with a @samp{@@}:
@cindex constraints
Each @code{match_operand} in an instruction pattern can specify a
-constraint for the type of operands allowed.
+constraint for the type of operands allowed.
@end ifset
@ifclear INTERNALS
@node Constraints
@@ -794,7 +815,7 @@ registers that are not general registers.
@ifset INTERNALS
Any operand whatsoever is allowed, even if it does not satisfy
@code{general_operand}. This is normally used in the constraint of
-a @code{match_scratch} when certain alternatives will not actually
+a @code{match_scratch} when certain alternatives will not actually
require a scratch register.
@end ifset
@ifclear INTERNALS
@@ -818,7 +839,7 @@ input operands and one output operand in the RTL, but on most CISC
@end ifset
@ifclear INTERNALS
which @code{asm} distinguishes. For example, an add instruction uses
-two input operands and an output operand, but on most CISC
+two input operands and an output operand, but on most CISC
@end ifclear
machines an add instruction really has only two operands, one of them an
input-output operand:
@@ -992,6 +1013,15 @@ If the operand's predicate can recognize registers, but the constraint does
not permit them, it can make the compiler crash. When this operand happens
to be a register, the reload pass will be stymied, because it does not know
how to copy a register temporarily into memory.
+
+If the predicate accepts a unary operator, the constraint applies to the
+operand. For example, the MIPS processor at ISA level 3 supports an
+instruction which adds two registers in @code{SImode} to produce a
+@code{DImode} result, but only if the registers are correctly sign
+extended. This predicate for the input operands accepts a
+@code{sign_extend} of an @code{SImode} register. Write the constraint
+to indicate the type of register that is required for the operand of the
+@code{sign_extend}.
@end ifset
@node Multi-Alternative
@@ -1108,17 +1138,25 @@ identifies an operand that is both input and output; all other operands
are assumed to be input only.
@cindex @samp{&} in constraint
+@cindex earlyclobber operand
@item &
-Means (in a particular alternative) that this operand is written
-before the instruction is finished using the input operands.
-Therefore, this operand may not lie in a register that is used as an
-input operand or as part of any memory address.
+Means (in a particular alternative) that this operand is an
+@dfn{earlyclobber} operand, which is modified before the instruction is
+finished using the input operands. Therefore, this operand may not lie
+in a register that is used as an input operand or as part of any memory
+address.
@samp{&} applies only to the alternative in which it is written. In
constraints with multiple alternatives, sometimes one alternative
requires @samp{&} while others do not. See, for example, the
@samp{movdf} insn of the 68000.
+An input operand can be tied to an earlyclobber operand if its only
+use as an input occurs before the early result is written. Adding
+alternatives of this form often allows GCC to produce better code
+when only some of the inputs can be affected by the earlyclobber.
+See, for example, the @samp{mulsi3} insn of the ARM.
+
@samp{&} does not obviate the need to write @samp{=}.
@cindex @samp{%} in constraint
@@ -1249,7 +1287,7 @@ Integer that satisfies constraint @samp{I} when negated (twos complement)
Integer in the range 0 to 32
@item Q
-A memory reference where the exact address is in a single register
+A memory reference where the exact address is in a single register
(`@samp{m}' is preferable for @code{asm} statements)
@item R
@@ -1370,6 +1408,18 @@ instruction per word
@item Q
Memory operand that is an offset from a register (@samp{m} is preferable
for @code{asm} statements)
+
+@item R
+AIX TOC entry
+
+@item S
+Windows NT SYMBOL_REF
+
+@item T
+Windows NT LABEL_REF
+
+@item U
+System V Release 4 small data area reference
@end table
@item Intel 386---@file{i386.h}
@@ -1552,6 +1602,9 @@ Signed number whose magnitude is greater than 0x80
@item L
Integer in the range -8 to -1
+@item M
+Signed number whose magnitude is greater than 0x100
+
@item G
Floating point constant that is not a 68881 constant
@@ -1563,7 +1616,10 @@ Floating point constant that can be used by Sun FPA
@item SPARC---@file{sparc.h}
@table @code
@item f
-Floating-point register
+Floating-point register that can hold 32 or 64 bit values.
+
+@item e
+Floating-point register that can hold 64 or 128 bit values.
@item I
Signed 13 bit constant
@@ -1591,7 +1647,7 @@ Constant, or memory address
@item T
Memory address aligned to an 8-byte boundary
-@item U
+@item U
Even register
@end table
@end table
@@ -1632,7 +1688,7 @@ now in existence use constraints.
Here is a table of the instruction names that are meaningful in the RTL
generation pass of the compiler. Giving one of these names to an
instruction pattern tells the RTL generation pass that it can use the
-pattern in to accomplish a certain task.
+pattern to accomplish a certain task.
@table @asis
@cindex @code{mov@var{m}} instruction pattern
@@ -1698,23 +1754,23 @@ scratch registers after reload, you must define
patterns @samp{reload_in@var{m}} or @samp{reload_out@var{m}} to handle
them. @xref{Register Classes}.
-The constraints on a @samp{move@var{m}} must permit moving any hard
+The constraints on a @samp{mov@var{m}} must permit moving any hard
register to any other hard register provided that
@code{HARD_REGNO_MODE_OK} permits mode @var{m} in both registers and
@code{REGISTER_MOVE_COST} applied to their classes returns a value of 2.
-It is obligatory to support floating point @samp{move@var{m}}
+It is obligatory to support floating point @samp{mov@var{m}}
instructions into and out of any registers that can hold fixed point
values, because unions and structures (which have modes @code{SImode} or
@code{DImode}) can be in those registers and they may have floating
point members.
-There may also be a need to support fixed point @samp{move@var{m}}
+There may also be a need to support fixed point @samp{mov@var{m}}
instructions in and out of floating point registers. Unfortunately, I
have forgotten why this was so, and I don't know whether it is still
true. If @code{HARD_REGNO_MODE_OK} rejects fixed point values in
floating point registers, then the constraints of the fixed point
-@samp{move@var{m}} instructions must be designed to avoid ever trying to
+@samp{mov@var{m}} instructions must be designed to avoid ever trying to
reload into a floating point register.
@cindex @code{reload_in} instruction pattern
@@ -1776,8 +1832,8 @@ means of constraints requiring operands 1 and 0 to be the same location.
@cindex @code{udiv@var{m}3} instruction pattern
@cindex @code{mod@var{m}3} instruction pattern
@cindex @code{umod@var{m}3} instruction pattern
-@cindex @code{min@var{m}3} instruction pattern
-@cindex @code{max@var{m}3} instruction pattern
+@cindex @code{smin@var{m}3} instruction pattern
+@cindex @code{smax@var{m}3} instruction pattern
@cindex @code{umin@var{m}3} instruction pattern
@cindex @code{umax@var{m}3} instruction pattern
@cindex @code{and@var{m}3} instruction pattern
@@ -1912,16 +1968,43 @@ The @samp{cmp@var{m}} patterns should be used instead.
@item @samp{movstr@var{m}}
Block move instruction. The addresses of the destination and source
strings are the first two operands, and both are in mode @code{Pmode}.
+
The number of bytes to move is the third operand, in mode @var{m}.
+Usually, you specify @code{word_mode} for @var{m}. However, if you can
+generate better code knowing the range of valid lengths is smaller than
+those representable in a full word, you should provide a pattern with a
+mode corresponding to the range of values you can handle efficiently
+(e.g., @code{QImode} for values in the range 0--127; note we avoid numbers
+that appear negative) and also a pattern with @code{word_mode}.
The fourth operand is the known shared alignment of the source and
destination, in the form of a @code{const_int} rtx. Thus, if the
compiler knows that both source and destination are word-aligned,
it may provide the value 4 for this operand.
+Descriptions of multiple @code{movstr@var{m}} patterns can only be
+beneficial if the patterns for smaller modes have fewer restrictions
+on their first, second and fourth operands. Note that the mode @var{m}
+in @code{movstr@var{m}} does not impose any restriction on the mode of
+individually moved data units in the block.
+
These patterns need not give special consideration to the possibility
that the source and destination strings might overlap.
+@cindex @code{clrstr@var{m}} instruction pattern
+@item @samp{clrstr@var{m}}
+Block clear instruction. The addresses of the destination string is the
+first operand, in mode @code{Pmode}. The number of bytes to clear is
+the second operand, in mode @var{m}. See @samp{movstr@var{m}} for
+a discussion of the choice of mode.
+
+The third operand is the known alignment of the destination, in the form
+of a @code{const_int} rtx. Thus, if the compiler knows that the
+destination is word-aligned, it may provide the value 4 for this
+operand.
+
+The use for multiple @code{clrstr@var{m}} is as for @code{movstr@var{m}}.
+
@cindex @code{cmpstr@var{m}} instruction pattern
@item @samp{cmpstr@var{m}}
Block compare instruction, with five operands. Operand 0 is the output;
@@ -1932,6 +2015,7 @@ to store a value in operand 0 whose sign indicates the result of the
comparison.
@cindex @code{strlen@var{m}} instruction pattern
+@item @samp{strlen@var{m}}
Compute the length of a string, with three operands.
Operand 0 is the result (of mode @var{m}), operand 1 is
a @code{mem} referring to the first character of the string,
@@ -1981,20 +2065,20 @@ of mode @var{m} by converting the value to an integer.
Like @samp{fixuns@var{m}@var{n}2} but works for any floating point
value of mode @var{m} by converting the value to an integer.
-@cindex @code{trunc@var{mn}} instruction pattern
-@item @samp{trunc@var{m}@var{n}}
+@cindex @code{trunc@var{mn}2} instruction pattern
+@item @samp{trunc@var{m}@var{n}2}
Truncate operand 1 (valid for mode @var{m}) to mode @var{n} and
store in operand 0 (which has mode @var{n}). Both modes must be fixed
point or both floating point.
-@cindex @code{extend@var{mn}} instruction pattern
-@item @samp{extend@var{m}@var{n}}
+@cindex @code{extend@var{mn}2} instruction pattern
+@item @samp{extend@var{m}@var{n}2}
Sign-extend operand 1 (valid for mode @var{m}) to mode @var{n} and
store in operand 0 (which has mode @var{n}). Both modes must be fixed
point or both floating point.
-@cindex @code{zero_extend@var{mn}} instruction pattern
-@item @samp{zero_extend@var{m}@var{n}}
+@cindex @code{zero_extend@var{mn}2} instruction pattern
+@item @samp{zero_extend@var{m}@var{n}2}
Zero-extend operand 1 (valid for mode @var{m}) to mode @var{n} and
store in operand 0 (which has mode @var{n}). Both modes must be fixed
point.
@@ -2091,7 +2175,7 @@ pattern or a @samp{tst@var{m}} pattern.
Machines that use a pseudo register for the condition code value, or
where the mode used for the comparison depends on the condition being
-tested, should also use the above mechanism. @xref{Jump Patterns}
+tested, should also use the above mechanism. @xref{Jump Patterns}.
The above discussion also applies to the @samp{mov@var{mode}cc} and
@samp{s@var{cond}} patterns.
@@ -2100,8 +2184,8 @@ The above discussion also applies to the @samp{mov@var{mode}cc} and
@item @samp{call}
Subroutine call instruction returning no value. Operand 0 is the
function to call; operand 1 is the number of bytes of arguments pushed
-(in mode @code{SImode}, except it is normally a @code{const_int});
-operand 2 is the number of registers used as operands.
+as a @code{const_int}; operand 2 is the number of registers used as
+operands.
On most machines, operand 2 is not actually stored into the RTL
pattern. It is supplied for the sake of some RISC machines which need
@@ -2254,9 +2338,9 @@ is no @samp{casesi} pattern.
This pattern requires two operands: the address or offset, and a label
which should immediately precede the jump table. If the macro
-@code{CASE_VECTOR_PC_RELATIVE} is defined then the first operand is an
-offset which counts from the address of the table; otherwise, it is an
-absolute address to jump to. In either case, the first operand has
+@code{CASE_VECTOR_PC_RELATIVE} evaluates to a nonzero value then the first
+operand is an offset which counts from the address of the table; otherwise,
+it is an absolute address to jump to. In either case, the first operand has
mode @code{Pmode}.
The @samp{tablejump} insn is always the last insn before the jump
@@ -2264,6 +2348,23 @@ table it uses. Its assembler code normally has no need to use the
second operand, but you should incorporate it in the RTL pattern so
that the jump optimizer will not delete the table as unreachable code.
+@cindex @code{canonicalize_funcptr_for_compare} instruction pattern
+@item @samp{canonicalize_funcptr_for_compare}
+Canonicalize the function pointer in operand 1 and store the result
+into operand 0.
+
+Operand 0 is always a @code{reg} and has mode @code{Pmode}; operand 1
+may be a @code{reg}, @code{mem}, @code{symbol_ref}, @code{const_int}, etc
+and also has mode @code{Pmode}.
+
+Canonicalization of a function pointer usually involves computing
+the address of the function which would be called if the function
+pointer were used in an indirect call.
+
+Only define this pattern if function pointers on the target machine
+can have different values but still call the same function when
+used in an indirect call.
+
@cindex @code{save_stack_block} instruction pattern
@cindex @code{save_stack_function} instruction pattern
@cindex @code{save_stack_nonlocal} instruction pattern
@@ -2311,14 +2412,15 @@ such required data.
@end enumerate
When saving the stack pointer, operand 0 is the save area and operand 1
-is the stack pointer. The mode used to allocate the save area is the
-mode of operand 0. You must specify an integral mode, or
-@code{VOIDmode} if no save area is needed for a particular type of save
-(either because no save is needed or because a machine-specific save
-area can be used). Operand 0 is the stack pointer and operand 1 is the
-save area for restore operations. If @samp{save_stack_block} is
-defined, operand 0 must not be @code{VOIDmode} since these saves can be
-arbitrarily nested.
+is the stack pointer. The mode used to allocate the save area defaults
+to @code{Pmode} but you can override that choice by defining the
+@code{STACK_SAVEAREA_MODE} macro (@pxref{Storage Layout}). You must
+specify an integral mode, or @code{VOIDmode} if no save area is needed
+for a particular type of save (either because no save is needed or
+because a machine-specific save area can be used). Operand 0 is the
+stack pointer and operand 1 is the save area for restore operations. If
+@samp{save_stack_block} is defined, operand 0 must not be
+@code{VOIDmode} since these saves can be arbitrarily nested.
A save area is a @code{mem} that is at a constant offset from
@code{virtual_stack_vars_rtx} when the stack pointer is saved for use by
@@ -2326,13 +2428,109 @@ nonlocal gotos and a @code{reg} in the other two cases.
@cindex @code{allocate_stack} instruction pattern
@item @samp{allocate_stack}
-Subtract (or add if @code{STACK_GROWS_DOWNWARD} is undefined) operand 0 from
+Subtract (or add if @code{STACK_GROWS_DOWNWARD} is undefined) operand 1 from
the stack pointer to create space for dynamically allocated data.
+Store the resultant pointer to this space into operand 0. If you
+are allocating space from the main stack, do this by emitting a
+move insn to copy @code{virtual_stack_dynamic_rtx} to operand 0.
+If you are allocating the space elsewhere, generate code to copy the
+location of the space to operand 0. In the latter case, you must
+ensure this space gets freed when the corresponding space on the main
+stack is free.
+
Do not define this pattern if all that must be done is the subtraction.
Some machines require other operations such as stack probes or
maintaining the back chain. Define this pattern to emit those
operations in addition to updating the stack pointer.
+
+@cindex @code{probe} instruction pattern
+@item @samp{probe}
+Some machines require instructions to be executed after space is
+allocated from the stack, for example to generate a reference at
+the bottom of the stack.
+
+If you need to emit instructions before the stack has been adjusted,
+put them into the @samp{allocate_stack} pattern. Otherwise, define
+this pattern to emit the required instructions.
+
+No operands are provided.
+
+@cindex @code{check_stack} instruction pattern
+@item @samp{check_stack}
+If stack checking cannot be done on your system by probing the stack with
+a load or store instruction (@pxref{Stack Checking}), define this pattern
+to perform the needed check and signaling an error if the stack
+has overflowed. The single operand is the location in the stack furthest
+from the current stack pointer that you need to validate. Normally,
+on machines where this pattern is needed, you would obtain the stack
+limit from a global or thread-specific variable or register.
+
+@cindex @code{nonlocal_goto} instruction pattern
+@item @samp{nonlocal_goto}
+Emit code to generate a non-local goto, e.g., a jump from one function
+to a label in an outer function. This pattern has four arguments,
+each representing a value to be used in the jump. The first
+argument is to be loaded into the frame pointer, the second is
+the address to branch to (code to dispatch to the actual label),
+the third is the address of a location where the stack is saved,
+and the last is the address of the label, to be placed in the
+location for the incoming static chain.
+
+On most machines you need not define this pattern, since GNU CC will
+already generate the correct code, which is to load the frame pointer
+and static chain, restore the stack (using the
+@samp{restore_stack_nonlocal} pattern, if defined), and jump indirectly
+to the dispatcher. You need only define this pattern if this code will
+not work on your machine.
+
+@cindex @code{nonlocal_goto_receiver} instruction pattern
+@item @samp{nonlocal_goto_receiver}
+This pattern, if defined, contains code needed at the target of a
+nonlocal goto after the code already generated by GNU CC. You will not
+normally need to define this pattern. A typical reason why you might
+need this pattern is if some value, such as a pointer to a global table,
+must be restored when the frame pointer is restored. Note that a nonlocal
+goto only ocurrs within a unit-of-translation, so a global table pointer
+that is shared by all functions of a given module need not be restored.
+There are no arguments.
+
+@cindex @code{exception_receiver} instruction pattern
+@item @samp{exception_receiver}
+This pattern, if defined, contains code needed at the site of an
+exception handler that isn't needed at the site of a nonlocal goto. You
+will not normally need to define this pattern. A typical reason why you
+might need this pattern is if some value, such as a pointer to a global
+table, must be restored after control flow is branched to the handler of
+an exception. There are no arguments.
+
+@cindex @code{builtin_setjmp_setup} instruction pattern
+@item @samp{builtin_setjmp_setup}
+This pattern, if defined, contains additional code needed to initialize
+the @code{jmp_buf}. You will not normally need to define this pattern.
+A typical reason why you might need this pattern is if some value, such
+as a pointer to a global table, must be restored. Though it is
+preferred that the pointer value be recalculated if possible (given the
+address of a label for instance). The single argument is a pointer to
+the @code{jmp_buf}. Note that the buffer is five words long and that
+the first three are normally used by the generic mechanism.
+
+@cindex @code{builtin_setjmp_receiver} instruction pattern
+@item @samp{builtin_setjmp_receiver}
+This pattern, if defined, contains code needed at the site of an
+builtin setjmp that isn't needed at the site of a nonlocal goto. You
+will not normally need to define this pattern. A typical reason why you
+might need this pattern is if some value, such as a pointer to a global
+table, must be restored. It takes one argument, which is the label
+to which builtin_longjmp transfered control; this pattern may be emitted
+at a small offset from that label.
+
+@cindex @code{builtin_longjmp} instruction pattern
+@item @samp{builtin_longjmp}
+This pattern, if defined, performs the entire action of the longjmp.
+You will not normally need to define this pattern unless you also define
+@code{builtin_setjmp_setup}. The single argument is a pointer to the
+@code{jmp_buf}.
@end table
@node Pattern Ordering
@@ -2608,6 +2806,7 @@ converted into the appropriate multiplication by a power of two.
@cindex @code{ior}, canonicalization of
@cindex @code{and}, canonicalization of
@cindex De Morgan's law
+@item
De`Morgan's Law is used to move bitwise negation inside a bitwise
logical-and or logical-or operation. If this results in only one
operand being a @code{not} expression, it will be the first one.
@@ -3051,8 +3250,7 @@ on this machine. So it must be copied into a register with
(match_dup 2)))]
""
"operands[2]
- = force_reg (SImode, gen_rtx (CONST_INT,
- VOIDmode, 65535)); ")
+ = force_reg (SImode, GEN_INT (65535)); ")
@end smallexample
@strong{Note:} If the @code{define_expand} is used to serve a
@@ -3183,8 +3381,8 @@ Here is an example of this use of @code{define_split}, taken from
if (low & 0x8000)
high++, low |= 0xffff0000;
- operands[3] = gen_rtx (CONST_INT, VOIDmode, high << 16);
- operands[4] = gen_rtx (CONST_INT, VOIDmode, low);
+ operands[3] = GEN_INT (high << 16);
+ operands[4] = GEN_INT (low);
@}")
@end smallexample
@@ -3209,16 +3407,16 @@ an equality comparison of a register and a large constant:
(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
+ /* 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_rtx (CONST_INT, VOIDmode, xorv);
- operands[5] = gen_rtx (CONST_INT, VOIDmode, sextc);
+ operands[4] = GEN_INT (xorv);
+ operands[5] = GEN_INT (sextc);
@}")
@end smallexample
@@ -3320,7 +3518,7 @@ defined and the function to obtain the attribute's value will return
@cindex attribute expressions
RTL expressions used to define attributes use the codes described above
-plus a few specific to attribute definitions, to be discussed below.
+plus a few specific to attribute definitions, to be discussed below.
Attribute value expressions must have one of the following forms:
@table @code
@@ -3485,21 +3683,21 @@ scheduled.
@var{name} is a string specifying one of a fixed set of flags to test.
Test the flags @code{forward} and @code{backward} to determine the
-direction of a conditional branch. Test the flags @code{very_likely},
-@code{likely}, @code{very_unlikely}, and @code{unlikely} to determine
+direction of a conditional branch. Test the flags @code{very_likely},
+@code{likely}, @code{very_unlikely}, and @code{unlikely} to determine
if a conditional branch is expected to be taken.
-If the @code{very_likely} flag is true, then the @code{likely} flag is also
+If the @code{very_likely} flag is true, then the @code{likely} flag is also
true. Likewise for the @code{very_unlikely} and @code{unlikely} flags.
This example describes a conditional branch delay slot which
-can be nullified for forward branches that are taken (annul-true) or
-for backward branches which are not taken (annul-false).
+can be nullified for forward branches that are taken (annul-true) or
+for backward branches which are not taken (annul-false).
@smallexample
(define_delay (eq_attr "type" "cbranch")
- [(eq_attr "in_branch_delay" "true")
- (and (eq_attr "in_branch_delay" "true")
+ [(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"))])
@@ -3508,12 +3706,12 @@ for backward branches which are not taken (annul-false).
The @code{forward} and @code{backward} flags are false if the current
@code{insn} being scheduled is not a conditional branch.
-The @code{very_likely} and @code{likely} flags are true if the
-@code{insn} being scheduled is not a conditional branch. The
+The @code{very_likely} and @code{likely} flags are true if the
+@code{insn} being scheduled is not a conditional branch.
The @code{very_unlikely} and @code{unlikely} flags are false if the
@code{insn} being scheduled is not a conditional branch.
-@code{attr_flag} is only used during delay slot scheduling and has no
+@code{attr_flag} is only used during delay slot scheduling and has no
meaning to other passes of the compiler.
@end table
@@ -3702,7 +3900,7 @@ must be a @code{label_ref}.
@item (pc)
This refers to the address of the @emph{current} insn. It might have
been more consistent with other usage to make this the address of the
-@emph{next} insn but this would be confusing because the length of the
+@emph{next} insn but this would be confusing because the length of the
current insn is to be computed.
@end table
@@ -3713,7 +3911,7 @@ For normal insns, the length will be determined by value of the
@code{addr_diff_vec} insn patterns, the length is computed as
the number of vectors multiplied by the size of each vector.
-Lengths are measured in addressable storage units (bytes).
+Lengths are measured in addressable storage units (bytes).
The following macros can be used to refine the length computation:
@@ -3729,8 +3927,7 @@ not specified, 0 is used.
If defined, modifies the length assigned to instruction @var{insn} as a
function of the context in which it is used. @var{length} is an lvalue
that contains the initially computed length of the insn and should be
-updated with the correct length of the insn. If updating is required,
-@var{insn} must not be a varying-length insn.
+updated with the correct length of the insn.
This macro will normally not be required. A case in which it is
required is the ROMP. On this machine, the size of an @code{addr_vec}
@@ -3813,7 +4010,7 @@ On some machines, conditional branch instructions can optionally
instruction will not be executed for certain branch outcomes. Both
instructions that annul if the branch is true and instructions that
annul if the branch is false are supported.
-
+
Delay slot scheduling differs from instruction scheduling in that
determining whether an instruction needs a delay slot is dependent only
on the type of instruction being generated, not on data flow between the
diff --git a/contrib/gcc/mips-tdump.c b/contrib/gcc/mips-tdump.c
index 36dfd15..558e090 100644
--- a/contrib/gcc/mips-tdump.c
+++ b/contrib/gcc/mips-tdump.c
@@ -1,5 +1,5 @@
/* Read and manage MIPS symbol tables from object modules.
- Copyright (C) 1991, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1994, 1995, 1997 Free Software Foundation, Inc.
Contributed by hartzell@boulder.colorado.edu,
Rewritten by meissner@osf.org.
@@ -20,13 +20,8 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/file.h>
-#include <time.h>
-#include <fcntl.h>
-#include <errno.h>
#include "config.h"
+#include "system.h"
#ifdef index
#undef index
@@ -44,7 +39,7 @@ Boston, MA 02111-1307, USA. */
which does not include mips.h.
These must match the corresponding definitions in gdb/mipsread.c.
- Unfortunately, gcc and gdb do not currently share any directories. */
+ Unfortunately, gcc and gdb do not currently share any directories. */
#define CODE_MASK 0x8F300
#define MIPS_IS_STAB(sym) (((sym)->index & 0xFFF00) == CODE_MASK)
@@ -86,7 +81,7 @@ typedef char *CPTR_T;
#define ptrdiff_t int
-/* Redefinition of of storage classes as an enumeration for better
+/* Redefinition of storage classes as an enumeration for better
debugging. */
#ifndef stStaParam
@@ -308,7 +303,7 @@ read_seek (ptr, size, offset, context)
if (size == 0) /* nothing to read */
return ptr;
- if ((ptr == (PTR_T)0 && (ptr = malloc (size)) == (PTR_T)0)
+ if ((ptr == (PTR_T) 0 && (ptr = malloc (size)) == (PTR_T) 0)
|| (tfile_offset != offset && lseek (tfile_fd, offset, 0) == -1)
|| (read_size = read (tfile_fd, ptr, size)) < 0)
{
@@ -721,7 +716,7 @@ type_to_string (aux_ptr, index, fdp)
int j;
/* Print array bounds reversed (ie, in the order the C
- programmer writes them). C is such a fun language.... */
+ programmer writes them). C is such a fun language.... */
while (i < 5 && qualifiers[i+1].type == tq_Array)
i++;
@@ -833,60 +828,60 @@ print_sym_hdr (sym_ptr)
printf(" %-*s %11s %11s %11s\n", width, "====", "======", "======", "=====\n");
printf(" %-*s %11ld %11ld %11ld [%d]\n", width, "Line numbers",
- (long)sym_ptr->cbLineOffset,
- (long)sym_ptr->cbLine,
- (long)sym_ptr->cbLine,
- (int)sym_ptr->ilineMax);
+ (long) sym_ptr->cbLineOffset,
+ (long) sym_ptr->cbLine,
+ (long) sym_ptr->cbLine,
+ (int) sym_ptr->ilineMax);
printf(" %-*s %11ld %11ld %11ld\n", width, "Dense numbers",
- (long)sym_ptr->cbDnOffset,
- (long)sym_ptr->idnMax,
- (long)(sym_ptr->idnMax * sizeof (DNR)));
+ (long) sym_ptr->cbDnOffset,
+ (long) sym_ptr->idnMax,
+ (long) (sym_ptr->idnMax * sizeof (DNR)));
printf(" %-*s %11ld %11ld %11ld\n", width, "Procedures Tables",
- (long)sym_ptr->cbPdOffset,
- (long)sym_ptr->ipdMax,
- (long)(sym_ptr->ipdMax * sizeof (PDR)));
+ (long) sym_ptr->cbPdOffset,
+ (long) sym_ptr->ipdMax,
+ (long) (sym_ptr->ipdMax * sizeof (PDR)));
printf(" %-*s %11ld %11ld %11ld\n", width, "Local Symbols",
- (long)sym_ptr->cbSymOffset,
- (long)sym_ptr->isymMax,
- (long)(sym_ptr->isymMax * sizeof (SYMR)));
+ (long) sym_ptr->cbSymOffset,
+ (long) sym_ptr->isymMax,
+ (long) (sym_ptr->isymMax * sizeof (SYMR)));
printf(" %-*s %11ld %11ld %11ld\n", width, "Optimization Symbols",
- (long)sym_ptr->cbOptOffset,
- (long)sym_ptr->ioptMax,
- (long)(sym_ptr->ioptMax * sizeof (OPTR)));
+ (long) sym_ptr->cbOptOffset,
+ (long) sym_ptr->ioptMax,
+ (long) (sym_ptr->ioptMax * sizeof (OPTR)));
printf(" %-*s %11ld %11ld %11ld\n", width, "Auxiliary Symbols",
- (long)sym_ptr->cbAuxOffset,
- (long)sym_ptr->iauxMax,
- (long)(sym_ptr->iauxMax * sizeof (AUXU)));
+ (long) sym_ptr->cbAuxOffset,
+ (long) sym_ptr->iauxMax,
+ (long) (sym_ptr->iauxMax * sizeof (AUXU)));
printf(" %-*s %11ld %11ld %11ld\n", width, "Local Strings",
- (long)sym_ptr->cbSsOffset,
- (long)sym_ptr->issMax,
- (long)sym_ptr->issMax);
+ (long) sym_ptr->cbSsOffset,
+ (long) sym_ptr->issMax,
+ (long) sym_ptr->issMax);
printf(" %-*s %11ld %11ld %11ld\n", width, "External Strings",
- (long)sym_ptr->cbSsExtOffset,
- (long)sym_ptr->issExtMax,
- (long)sym_ptr->issExtMax);
+ (long) sym_ptr->cbSsExtOffset,
+ (long) sym_ptr->issExtMax,
+ (long) sym_ptr->issExtMax);
printf(" %-*s %11ld %11ld %11ld\n", width, "File Tables",
- (long)sym_ptr->cbFdOffset,
- (long)sym_ptr->ifdMax,
- (long)(sym_ptr->ifdMax * sizeof (FDR)));
+ (long) sym_ptr->cbFdOffset,
+ (long) sym_ptr->ifdMax,
+ (long) (sym_ptr->ifdMax * sizeof (FDR)));
printf(" %-*s %11ld %11ld %11ld\n", width, "Relative Files",
- (long)sym_ptr->cbRfdOffset,
- (long)sym_ptr->crfd,
- (long)(sym_ptr->crfd * sizeof (ulong)));
+ (long) sym_ptr->cbRfdOffset,
+ (long) sym_ptr->crfd,
+ (long) (sym_ptr->crfd * sizeof (ulong)));
printf(" %-*s %11ld %11ld %11ld\n", width, "External Symbols",
- (long)sym_ptr->cbExtOffset,
- (long)sym_ptr->iextMax,
- (long)(sym_ptr->iextMax * sizeof (EXTR)));
+ (long) sym_ptr->cbExtOffset,
+ (long) sym_ptr->iextMax,
+ (long) (sym_ptr->iextMax * sizeof (EXTR)));
}
@@ -909,7 +904,7 @@ print_symbol (sym_ptr, number, strbase, aux_base, ifd, fdp)
printf ("\n Symbol# %d: \"%s\"\n", number, sym_ptr->iss + strbase);
- if (aux_base != (AUXU *)0 && index != indexNil)
+ if (aux_base != (AUXU *) 0 && index != indexNil)
switch (symbol_type)
{
case st_Nil:
@@ -921,7 +916,7 @@ print_symbol (sym_ptr, number, strbase, aux_base, ifd, fdp)
printf (" End+1 symbol: %ld\n", index);
if (want_scope)
{
- if (free_scope == (scope_t *)0)
+ if (free_scope == (scope_t *) 0)
scope_ptr = (scope_t *) malloc (sizeof (scope_t));
else
{
@@ -942,12 +937,12 @@ print_symbol (sym_ptr, number, strbase, aux_base, ifd, fdp)
else
{
used_ptr[index] = 1;
- printf (" First symbol: %ld\n", aux_base[index].isym);
+ printf (" First symbol: %ld\n", (long) aux_base[index].isym);
}
if (want_scope)
{
- if (cur_scope == (scope_t *)0)
+ if (cur_scope == (scope_t *) 0)
printf (" Can't pop end scope\n");
else
{
@@ -967,7 +962,7 @@ print_symbol (sym_ptr, number, strbase, aux_base, ifd, fdp)
{
used_ptr[index] = used_ptr[index+1] = 1;
printf (" End+1 symbol: %-7ld Type: %s\n",
- aux_base[index].isym,
+ (long) aux_base[index].isym,
type_to_string (aux_base, index+1, fdp));
}
else /* global symbol */
@@ -975,7 +970,7 @@ print_symbol (sym_ptr, number, strbase, aux_base, ifd, fdp)
if (want_scope)
{
- if (free_scope == (scope_t *)0)
+ if (free_scope == (scope_t *) 0)
scope_ptr = (scope_t *) malloc (sizeof (scope_t));
else
{
@@ -1011,12 +1006,12 @@ print_symbol (sym_ptr, number, strbase, aux_base, ifd, fdp)
if (want_scope)
{
printf (" Scopes: ");
- if (cur_scope == (scope_t *)0)
+ if (cur_scope == (scope_t *) 0)
printf (" none\n");
else
{
for (scope_ptr = cur_scope;
- scope_ptr != (scope_t *)0;
+ scope_ptr != (scope_t *) 0;
scope_ptr = scope_ptr->prev)
{
char *class;
@@ -1220,7 +1215,7 @@ print_file_desc (fdp, number)
(ulong) (fdp->rfdBase * sizeof(ulong) + sym_hdr.cbRfdOffset));
- if (want_scope && cur_scope != (scope_t *)0)
+ if (want_scope && cur_scope != (scope_t *) 0)
printf ("\n Warning scope does not start at 0!\n");
/*
@@ -1238,7 +1233,7 @@ print_file_desc (fdp, number)
-1,
fdp);
- if (want_scope && cur_scope != (scope_t *)0)
+ if (want_scope && cur_scope != (scope_t *) 0)
printf ("\n Warning scope does not end at 0!\n");
/*
@@ -1328,7 +1323,7 @@ print_file_desc (fdp, number)
if (pdi == fdp->cpd + fdp->ipdFirst - 1) /* last procedure */
line_end = ((uchar *)lines) + fdp->cbLine + fdp->cbLineOffset;
- else /* not last proc. */
+ else /* not last proc. */
line_end = (((uchar *)lines) + proc_desc[pdi+1].cbLineOffset
+ fdp->cbLineOffset);
@@ -1368,12 +1363,12 @@ read_tfile __proto((void))
short magic;
off_t sym_hdr_offset = 0;
- (void) read_seek ((PTR_T) &magic, sizeof (magic), (off_t)0, "Magic number");
+ (void) read_seek ((PTR_T) &magic, sizeof (magic), (off_t) 0, "Magic number");
if (!tfile)
{
/* Print out the global header, since this is not a T-file. */
- (void) read_seek ((PTR_T) &global_hdr, sizeof (global_hdr), (off_t)0,
+ (void) read_seek ((PTR_T) &global_hdr, sizeof (global_hdr), (off_t) 0,
"Global file header");
print_global_hdr (&global_hdr);
@@ -1394,32 +1389,32 @@ read_tfile __proto((void))
print_sym_hdr (&sym_hdr);
- lines = (LINER *) read_seek ((PTR_T)0,
+ lines = (LINER *) read_seek ((PTR_T) 0,
sym_hdr.cbLine,
sym_hdr.cbLineOffset,
"Line numbers");
- dense_nums = (DNR *) read_seek ((PTR_T)0,
+ dense_nums = (DNR *) read_seek ((PTR_T) 0,
sym_hdr.idnMax * sizeof (DNR),
sym_hdr.cbDnOffset,
"Dense numbers");
- proc_desc = (PDR *) read_seek ((PTR_T)0,
+ proc_desc = (PDR *) read_seek ((PTR_T) 0,
sym_hdr.ipdMax * sizeof (PDR),
sym_hdr.cbPdOffset,
"Procedure tables");
- l_symbols = (SYMR *) read_seek ((PTR_T)0,
+ l_symbols = (SYMR *) read_seek ((PTR_T) 0,
sym_hdr.isymMax * sizeof (SYMR),
sym_hdr.cbSymOffset,
"Local symbols");
- opt_symbols = (OPTR *) read_seek ((PTR_T)0,
+ opt_symbols = (OPTR *) read_seek ((PTR_T) 0,
sym_hdr.ioptMax * sizeof (OPTR),
sym_hdr.cbOptOffset,
"Optimization symbols");
- aux_symbols = (AUXU *) read_seek ((PTR_T)0,
+ aux_symbols = (AUXU *) read_seek ((PTR_T) 0,
sym_hdr.iauxMax * sizeof (AUXU),
sym_hdr.cbAuxOffset,
"Auxiliary symbols");
@@ -1427,34 +1422,34 @@ read_tfile __proto((void))
if (sym_hdr.iauxMax > 0)
{
aux_used = calloc (sym_hdr.iauxMax, 1);
- if (aux_used == (char *)0)
+ if (aux_used == (char *) 0)
{
perror ("calloc");
exit (1);
}
}
- l_strings = (char *) read_seek ((PTR_T)0,
+ l_strings = (char *) read_seek ((PTR_T) 0,
sym_hdr.issMax,
sym_hdr.cbSsOffset,
"Local string table");
- e_strings = (char *) read_seek ((PTR_T)0,
+ e_strings = (char *) read_seek ((PTR_T) 0,
sym_hdr.issExtMax,
sym_hdr.cbSsExtOffset,
"External string table");
- file_desc = (FDR *) read_seek ((PTR_T)0,
+ file_desc = (FDR *) read_seek ((PTR_T) 0,
sym_hdr.ifdMax * sizeof (FDR),
sym_hdr.cbFdOffset,
"File tables");
- rfile_desc = (ulong *) read_seek ((PTR_T)0,
+ rfile_desc = (ulong *) read_seek ((PTR_T) 0,
sym_hdr.crfd * sizeof (ulong),
sym_hdr.cbRfdOffset,
"Relative file tables");
- e_symbols = (EXTR *) read_seek ((PTR_T)0,
+ e_symbols = (EXTR *) read_seek ((PTR_T) 0,
sym_hdr.iextMax * sizeof (EXTR),
sym_hdr.cbExtOffset,
"External symbols");
@@ -1526,9 +1521,9 @@ main (argc, argv)
if (sym_hdr.ifdMax == 0)
last_aux_in_use = 0;
else
- last_aux_in_use =
- file_desc[sym_hdr.ifdMax-1].iauxBase +
- file_desc[sym_hdr.ifdMax-1].caux - 1;
+ last_aux_in_use
+ = (file_desc[sym_hdr.ifdMax-1].iauxBase
+ + file_desc[sym_hdr.ifdMax-1].caux - 1);
if (last_aux_in_use < sym_hdr.iauxMax-1)
{
diff --git a/contrib/gcc/mips-tfile.c b/contrib/gcc/mips-tfile.c
index cce203f..9918397 100644
--- a/contrib/gcc/mips-tfile.c
+++ b/contrib/gcc/mips-tfile.c
@@ -2,8 +2,8 @@
contain debugging information specified by the GNU compiler
in the form of comments (the mips assembler does not support
assembly access to debug information).
- Copyright (C) 1991, 1993, 1994. 1995 Free Software Foundation, Inc.
- Contributed by Michael Meissner, meissner@osf.org
+ Copyright (C) 1991, 93, 94, 95, 97, 1998 Free Software Foundation, Inc.
+ Contributed by Michael Meissner (meissner@cygnus.com).
This file is part of GNU CC.
@@ -599,13 +599,13 @@ Boston, MA 02111-1307, USA. */
*/
+#include "config.h"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
-#include "config.h"
-#include <stdio.h>
+#include "system.h"
#ifndef __SABER__
#define saber_stop()
@@ -671,15 +671,8 @@ extern PTR_T xcalloc __proto((Size_t, Size_t));
extern PTR_T xrealloc __proto((PTR_T, Size_t));
extern void xfree __proto((PTR_T));
-#ifdef HAVE_VPRINTF
extern void fatal PVPROTO((const char *format, ...));
extern void error PVPROTO((const char *format, ...));
-#else
-/* We must not provide any prototype here, even if ANSI C. */
-extern void fatal __proto(());
-extern void error __proto(());
-#endif
-
#ifndef MIPS_DEBUGGING_INFO
@@ -705,11 +698,6 @@ main ()
#undef rindex
#undef index
-#include <sys/types.h>
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <errno.h>
#include <signal.h>
#include <sys/stat.h>
@@ -719,35 +707,20 @@ main ()
#include "mips/a.out.h"
#endif /* CROSS_COMPILE */
-#if defined (USG) || defined (NO_STAB_H)
+#if defined (USG) || !defined (HAVE_STAB_H)
#include "gstab.h" /* If doing DBX on sysV, use our own stab.h. */
#else
#include <stab.h> /* On BSD, use the system's stab.h. */
#endif /* not USG */
+#include "machmode.h"
+
#ifdef __GNU_STAB__
#define STAB_CODE_TYPE enum __stab_debug_code
#else
#define STAB_CODE_TYPE int
#endif
-#ifdef _OSF_SOURCE
-#define HAS_STDLIB_H
-#define HAS_UNISTD_H
-#endif
-
-#ifdef HAS_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef HAS_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifndef errno
-extern int errno; /* MIPS errno.h doesn't declare this */
-#endif
-
#ifndef MALLOC_CHECK
#ifdef __SABER__
#define MALLOC_CHECK
@@ -755,10 +728,10 @@ extern int errno; /* MIPS errno.h doesn't declare this */
#endif
#define IS_ASM_IDENT(ch) \
- (isalnum (ch) || (ch) == '_' || (ch) == '.' || (ch) == '$')
+ (ISALNUM (ch) || (ch) == '_' || (ch) == '.' || (ch) == '$')
-/* Redefinition of of storage classes as an enumeration for better
+/* Redefinition of storage classes as an enumeration for better
debugging. */
typedef enum sc {
@@ -939,7 +912,7 @@ typedef enum coff_dt {
typedef enum hash_state {
hash_no = 0, /* don't hash type */
hash_yes = 1, /* ok to hash type, or use previous hash */
- hash_record = 2 /* ok to record hash, but don't use prev. */
+ hash_record = 2 /* ok to record hash, but don't use prev. */
} hash_state_t;
@@ -966,7 +939,7 @@ enum alloc_type {
grow linearly, and which are written in the object file as sequential
pages. On systems with a BSD malloc that define USE_MALLOC, the
MAX_CLUSTER_PAGES should be 1 less than a power of two, since malloc
- adds it's overhead, and rounds up to the next power of 2. Pages are
+ adds its overhead, and rounds up to the next power of 2. Pages are
linked together via a linked list.
If PAGE_SIZE is > 4096, the string length in the shash_t structure
@@ -1014,15 +987,15 @@ typedef struct varray {
#endif
#define INIT_VARRAY(type) { /* macro to initialize a varray */ \
- (vlinks_t *)0, /* first */ \
- (vlinks_t *)0, /* last */ \
+ (vlinks_t *) 0, /* first */ \
+ (vlinks_t *) 0, /* last */ \
0, /* num_allocated */ \
sizeof (type), /* object_size */ \
OBJECTS_PER_PAGE (type), /* objects_per_page */ \
OBJECTS_PER_PAGE (type), /* objects_last_page */ \
}
-/* Master type for indexes within the symbol table. */
+/* Master type for indexes within the symbol table. */
typedef unsigned long symint_t;
@@ -1171,12 +1144,12 @@ static efdr_t init_file =
0, /* cbLine: size of lines for this file */
},
- (FDR *)0, /* orig_fdr: original file header pointer */
- (char *)0, /* name: pointer to filename */
+ (FDR *) 0, /* orig_fdr: original file header pointer */
+ (char *) 0, /* name: pointer to filename */
0, /* name_len: length of filename */
0, /* void_type: ptr to aux node for void type */
0, /* int_type: ptr to aux node for int type */
- (scope_t *)0, /* cur_scope: current scope being processed */
+ (scope_t *) 0, /* cur_scope: current scope being processed */
0, /* file_index: current file # */
0, /* nested_scopes: # nested scopes */
INIT_VARRAY (char), /* strings: local string varray */
@@ -1184,9 +1157,9 @@ static efdr_t init_file =
INIT_VARRAY (PDR), /* procs: procedure varray */
INIT_VARRAY (AUXU), /* aux_syms: auxiliary symbols varray */
- (struct efdr *)0, /* next_file: next file structure */
+ (struct efdr *) 0, /* next_file: next file structure */
- (shash_t **)0, /* shash_head: string hash table */
+ (shash_t **) 0, /* shash_head: string hash table */
{ 0 }, /* thash_head: type hash table */
};
@@ -1609,17 +1582,17 @@ static PDR *cur_proc_ptr = (PDR *) 0; /* current procedure header */
static SYMR *cur_oproc_begin = (SYMR *) 0; /* original proc. sym begin info */
static SYMR *cur_oproc_end = (SYMR *) 0; /* original proc. sym end info */
static PDR *cur_oproc_ptr = (PDR *) 0; /* current original procedure*/
-static thead_t *cur_tag_head = (thead_t *)0; /* current tag head */
+static thead_t *cur_tag_head = (thead_t *) 0;/* current tag head */
static long file_offset = 0; /* current file offset */
static long max_file_offset = 0; /* maximum file offset */
-static FILE *object_stream = (FILE *)0; /* file desc. to output .o */
-static FILE *obj_in_stream = (FILE *)0; /* file desc. to input .o */
-static char *progname = (char *)0; /* program name for errors */
+static FILE *object_stream = (FILE *) 0; /* file desc. to output .o */
+static FILE *obj_in_stream = (FILE *) 0; /* file desc. to input .o */
+static char *progname = (char *) 0; /* program name for errors */
static char *input_name = "stdin"; /* name of input file */
-static char *object_name = (char *)0; /* tmp. name of object file */
-static char *obj_in_name = (char *)0; /* name of input object file */
-static char *cur_line_start = (char *)0; /* current line read in */
-static char *cur_line_ptr = (char *)0; /* ptr within current line */
+static char *object_name = (char *) 0; /* tmp. name of object file */
+static char *obj_in_name = (char *) 0; /* name of input object file */
+static char *cur_line_start = (char *) 0; /* current line read in */
+static char *cur_line_ptr = (char *) 0; /* ptr within current line */
static unsigned cur_line_nbytes = 0; /* # bytes for current line */
static unsigned cur_line_alloc = 0; /* # bytes total in buffer */
static long line_number = 0; /* current input line number */
@@ -1755,10 +1728,6 @@ STATIC void free_thead __proto((thead_t *));
STATIC char *local_index __proto((const char *, int));
STATIC char *local_rindex __proto((const char *, int));
-#ifndef __alpha
-extern char *sbrk __proto((int));
-extern void free __proto((PTR_T));
-#endif
extern char *mktemp __proto((char *));
extern long strtol __proto((const char *, char **, int));
@@ -1767,22 +1736,16 @@ extern int optind;
extern int opterr;
extern char *version_string;
#ifndef NO_SYS_SIGLIST
-#ifndef DONT_DECLARE_SYS_SIGLIST
+#ifndef SYS_SIGLIST_DECLARED
extern char *sys_siglist[NSIG + 1];
#endif
#endif
-#ifndef SEEK_SET /* Symbolic constants for the "fseek" function: */
-#define SEEK_SET 0 /* Set file pointer to offset */
-#define SEEK_CUR 1 /* Set file pointer to its current value plus offset */
-#define SEEK_END 2 /* Set file pointer to the size of the file plus offset */
-#endif
-
/* List of assembler pseudo ops and beginning sequences that need
special actions. Someday, this should be a hash table, and such,
but for now a linear list of names and calls to memcmp will
- do...... */
+ do...... */
typedef struct _pseudo_ops {
const char *name; /* pseudo-op in ascii */
@@ -1826,7 +1789,7 @@ add_varray_page (vp)
new_links->start_index = vp->num_allocated;
vp->objects_last_page = 0;
- if (vp->first == (vlinks_t *)0) /* first allocation? */
+ if (vp->first == (vlinks_t *) 0) /* first allocation? */
vp->first = vp->last = new_links;
else
{ /* 2nd or greater allocation */
@@ -1860,10 +1823,10 @@ hash_string (text, hash_len, hash_tbl, ret_hash_index)
hi &= (1 << HASHBITS) - 1;
hi %= SHASH_SIZE;
- if (ret_hash_index != (symint_t *)0)
+ if (ret_hash_index != (symint_t *) 0)
*ret_hash_index = hi;
- for (ptr = hash_tbl[hi]; ptr != (shash_t *)0; ptr = ptr->next)
+ for (ptr = hash_tbl[hi]; ptr != (shash_t *) 0; ptr = ptr->next)
if (hash_len == ptr->len
&& first_ch == ptr->string[0]
&& memcmp ((CPTR_T) text, (CPTR_T) ptr->string, hash_len) == 0)
@@ -1893,14 +1856,14 @@ add_string (vp, hash_tbl, start, end_p1, ret_hash)
fatal ("String too big (%ld bytes)", (long) len);
hash_ptr = hash_string (start, len, hash_tbl, &hi);
- if (hash_ptr == (shash_t *)0)
+ if (hash_ptr == (shash_t *) 0)
{
register char *p;
if (vp->objects_last_page + len >= PAGE_USIZE)
{
- vp->num_allocated =
- ((vp->num_allocated + PAGE_USIZE - 1) / PAGE_USIZE) * PAGE_USIZE;
+ vp->num_allocated
+ = ((vp->num_allocated + PAGE_USIZE - 1) / PAGE_USIZE) * PAGE_USIZE;
add_varray_page (vp);
}
@@ -1921,7 +1884,7 @@ add_string (vp, hash_tbl, start, end_p1, ret_hash)
*p = '\0';
}
- if (ret_hash != (shash_t **)0)
+ if (ret_hash != (shash_t **) 0)
*ret_hash = hash_ptr;
return hash_ptr->indx;
@@ -1947,7 +1910,7 @@ add_local_symbol (str_start, str_end_p1, type, storage, value, indx)
register tag_t *ptag_next;
register varray_t *vp = &cur_file_ptr->symbols;
register int scope_delta = 0;
- shash_t *hash_ptr = (shash_t *)0;
+ shash_t *hash_ptr = (shash_t *) 0;
if (vp->objects_last_page == vp->objects_per_page)
add_varray_page (vp);
@@ -1958,7 +1921,7 @@ add_local_symbol (str_start, str_end_p1, type, storage, value, indx)
psym->st = (unsigned) type;
psym->sc = (unsigned) storage;
psym->index = indx;
- psym->iss = (str_start == (const char *)0)
+ psym->iss = (str_start == (const char *) 0)
? 0
: add_string (&cur_file_ptr->strings,
&cur_file_ptr->shash_head[0],
@@ -1973,7 +1936,7 @@ add_local_symbol (str_start, str_end_p1, type, storage, value, indx)
/* Save the symbol within the hash table if this is a static
item, and it has a name. */
- if (hash_ptr != (shash_t *)0
+ if (hash_ptr != (shash_t *) 0
&& (type == st_Global || type == st_Static || type == st_Label
|| type == st_Proc || type == st_StaticProc))
hash_ptr->sym_ptr = psym;
@@ -2030,10 +1993,10 @@ add_local_symbol (str_start, str_end_p1, type, storage, value, indx)
cur_tag_head = ptag_head->prev;
for (ptag = ptag_head->first_tag;
- ptag != (tag_t *)0;
+ ptag != (tag_t *) 0;
ptag = ptag_next)
{
- if (ptag->forward_ref != (forward_t *)0)
+ if (ptag->forward_ref != (forward_t *) 0)
add_unknown_tag (ptag);
ptag_next = ptag->same_block;
@@ -2093,11 +2056,12 @@ add_local_symbol (str_start, str_end_p1, type, storage, value, indx)
value, depth, sc_str);
if (str_start && str_end_p1 - str_start > 0)
- fprintf (stderr, " st= %-11s name= %.*s\n", st_str, str_end_p1 - str_start, str_start);
+ fprintf (stderr, " st= %-11s name= %.*s\n",
+ st_str, (int) (str_end_p1 - str_start), str_start);
else
{
Size_t len = strlen (st_str);
- fprintf (stderr, " st= %.*s\n", len-1, st_str);
+ fprintf (stderr, " st= %.*s\n", (int) (len-1), st_str);
}
}
@@ -2119,7 +2083,7 @@ add_ext_symbol (str_start, str_end_p1, type, storage, value, indx, ifd)
{
register EXTR *psym;
register varray_t *vp = &ext_symbols;
- shash_t *hash_ptr = (shash_t *)0;
+ shash_t *hash_ptr = (shash_t *) 0;
if (debug > 1)
{
@@ -2131,7 +2095,8 @@ add_ext_symbol (str_start, str_end_p1, type, storage, value, indx, ifd)
value, ifd, sc_str);
if (str_start && str_end_p1 - str_start > 0)
- fprintf (stderr, " st= %-11s name= %.*s\n", st_str, str_end_p1 - str_start, str_start);
+ fprintf (stderr, " st= %-11s name= %.*s\n",
+ st_str, (int) (str_end_p1 - str_start), str_start);
else
fprintf (stderr, " st= %s\n", st_str);
}
@@ -2146,7 +2111,7 @@ add_ext_symbol (str_start, str_end_p1, type, storage, value, indx, ifd)
psym->asym.st = (unsigned) type;
psym->asym.sc = (unsigned) storage;
psym->asym.index = indx;
- psym->asym.iss = (str_start == (const char *)0)
+ psym->asym.iss = (str_start == (const char *) 0)
? 0
: add_string (&ext_strings,
&ext_str_hash[0],
@@ -2232,7 +2197,7 @@ add_aux_sym_tir (t, state, hash_tbl)
/* For anything that adds additional information, we must not hash,
- so check here, and reset our state. */
+ so check here, and reset our state. */
if (state != hash_no
&& (t->type_qualifiers[0] == tq_Array
@@ -2262,17 +2227,17 @@ add_aux_sym_tir (t, state, hash_tbl)
hi %= THASH_SIZE;
for (hash_ptr = hash_tbl[hi];
- hash_ptr != (thash_t *)0;
+ hash_ptr != (thash_t *) 0;
hash_ptr = hash_ptr->next)
{
if (aux.isym == hash_ptr->type.isym)
break;
}
- if (hash_ptr != (thash_t *)0 && state == hash_yes)
+ if (hash_ptr != (thash_t *) 0 && state == hash_yes)
return hash_ptr->indx;
- if (hash_ptr == (thash_t *)0)
+ if (hash_ptr == (thash_t *) 0)
{
hash_ptr = allocate_thash ();
hash_ptr->next = hash_tbl[hi];
@@ -2282,7 +2247,7 @@ add_aux_sym_tir (t, state, hash_tbl)
}
}
- /* Everything is set up, add the aux symbol. */
+ /* Everything is set up, add the aux symbol. */
if (vp->objects_last_page == vp->objects_per_page)
add_varray_page (vp);
@@ -2350,7 +2315,7 @@ add_aux_sym_tir (t, state, hash_tbl)
cur_file_ptr->int_type);
(void) add_aux_sym_symint (cur_file_ptr->file_index); /* file index*/
- (void) add_aux_sym_symint ((symint_t)0); /* low bound */
+ (void) add_aux_sym_symint ((symint_t) 0); /* low bound */
(void) add_aux_sym_symint (t->dimensions[i] - 1); /* high bound*/
(void) add_aux_sym_symint ((t->dimensions[i] == 0) /* stride */
? 0
@@ -2358,7 +2323,7 @@ add_aux_sym_tir (t, state, hash_tbl)
};
/* NOTE: Mips documentation claims that the bitfield width goes here.
- But it needs to be emitted earlier. */
+ But it needs to be emitted earlier. */
return ret;
}
@@ -2378,10 +2343,10 @@ get_tag (tag_start, tag_end_p1, indx, basic_type)
hash_ptr = hash_string (tag_start,
tag_end_p1 - tag_start,
&tag_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
- if (hash_ptr != (shash_t *)0
- && hash_ptr->tag_ptr != (tag_t *)0)
+ if (hash_ptr != (shash_t *) 0
+ && hash_ptr->tag_ptr != (tag_t *) 0)
{
tag_ptr = hash_ptr->tag_ptr;
if (indx != indexNil)
@@ -2440,25 +2405,25 @@ add_unknown_tag (ptag)
default: break;
}
- fprintf (stderr, "unknown %s %.*s found\n", agg_type,
- hash_ptr->len, name_start);
+ fprintf (stderr, "unknown %s %.*s found\n",
+ agg_type, (int) hash_ptr->len, name_start);
}
sym_index = add_local_symbol (name_start,
name_end_p1,
st_Block,
sc_Info,
- (symint_t)0,
- (symint_t)0);
+ (symint_t) 0,
+ (symint_t) 0);
(void) add_local_symbol (name_start,
name_end_p1,
st_End,
sc_Info,
- (symint_t)0,
- (symint_t)0);
+ (symint_t) 0,
+ (symint_t) 0);
- while (f_next != (forward_t *)0)
+ while (f_next != (forward_t *) 0)
{
f_cur = f_next;
f_next = f_next->next;
@@ -2490,7 +2455,7 @@ add_procedure (func_start, func_end_p1)
register shash_t *shash_ptr = hash_string (func_start,
func_end_p1 - func_start,
&orig_str_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
if (debug)
fputc ('\n', stderr);
@@ -2504,14 +2469,14 @@ add_procedure (func_start, func_end_p1)
/* Did the assembler create this procedure? If so, get the PDR information. */
- cur_oproc_ptr = (PDR *)0;
- if (shash_ptr != (shash_t *)0)
+ cur_oproc_ptr = (PDR *) 0;
+ if (shash_ptr != (shash_t *) 0)
{
register PDR *old_proc_ptr = shash_ptr->proc_ptr;
register SYMR *sym_ptr = shash_ptr->sym_ptr;
- if (old_proc_ptr != (PDR *)0
- && sym_ptr != (SYMR *)0
+ if (old_proc_ptr != (PDR *) 0
+ && sym_ptr != (SYMR *) 0
&& ((st_t)sym_ptr->st == st_Proc || (st_t)sym_ptr->st == st_StaticProc))
{
cur_oproc_begin = sym_ptr;
@@ -2524,17 +2489,17 @@ add_procedure (func_start, func_end_p1)
}
}
- if (cur_oproc_ptr == (PDR *)0)
+ if (cur_oproc_ptr == (PDR *) 0)
error ("Did not find a PDR block for %.*s", func_end_p1 - func_start, func_start);
- /* Determine the start of symbols. */
+ /* Determine the start of symbols. */
new_proc_ptr->isym = file_ptr->symbols.num_allocated;
/* Push the start of the function. */
(void) add_local_symbol (func_start, func_end_p1,
proc_type, sc_Text,
value,
- (symint_t)0);
+ (symint_t) 0);
}
@@ -2554,11 +2519,11 @@ add_file (file_start, file_end_p1)
register efdr_t *file_ptr;
if (debug)
- fprintf (stderr, "\tfile\t%.*s\n", len, file_start);
+ fprintf (stderr, "\tfile\t%.*s\n", (int) len, file_start);
/* See if the file has already been created. */
for (file_ptr = first_file;
- file_ptr != (efdr_t *)0;
+ file_ptr != (efdr_t *) 0;
file_ptr = file_ptr->next_file)
{
if (first_ch == file_ptr->name[0]
@@ -2570,14 +2535,14 @@ add_file (file_start, file_end_p1)
}
}
- /* If this is a new file, create it. */
- if (file_ptr == (efdr_t *)0)
+ /* If this is a new file, create it. */
+ if (file_ptr == (efdr_t *) 0)
{
if (file_desc.objects_last_page == file_desc.objects_per_page)
add_varray_page (&file_desc);
- file_ptr = cur_file_ptr =
- &file_desc.last->datum->file[ file_desc.objects_last_page++ ];
+ file_ptr = cur_file_ptr
+ = &file_desc.last->datum->file[ file_desc.objects_last_page++ ];
*file_ptr = init_file;
file_ptr->file_index = file_desc.num_allocated++;
@@ -2590,7 +2555,7 @@ add_file (file_start, file_end_p1)
&file_ptr->shash_head[0],
&zero_bytes[0],
&zero_bytes[0],
- (shash_t **)0);
+ (shash_t **) 0);
if (file_end_p1 - file_start > PAGE_USIZE-2)
fatal ("Filename goes over one page boundary.");
@@ -2598,7 +2563,7 @@ add_file (file_start, file_end_p1)
/* Push the start of the filename. We assume that the filename
will be stored at string offset 1. */
(void) add_local_symbol (file_start, file_end_p1, st_File, sc_Text,
- (symint_t)0, (symint_t)0);
+ (symint_t) 0, (symint_t) 0);
file_ptr->fdr.rss = 1;
file_ptr->name = &file_ptr->strings.last->datum->byte[1];
file_ptr->name_len = file_end_p1 - file_start;
@@ -2745,7 +2710,7 @@ read_line __proto((void))
register int ch;
register char *ptr;
- if (cur_line_start == (char *)0)
+ if (cur_line_start == (char *) 0)
{ /* allocate initial page */
cur_line_start = (char *) allocate_page ();
cur_line_alloc = PAGE_SIZE;
@@ -2804,8 +2769,8 @@ read_line __proto((void))
if (ferror (stdin))
pfatal_with_name (input_name);
- cur_line_ptr = (char *)0;
- return (char *)0;
+ cur_line_ptr = (char *) 0;
+ return (char *) 0;
}
@@ -2820,42 +2785,42 @@ parse_begin (start)
int ch;
shash_t *hash_ptr; /* hash pointer to lookup label */
- if (cur_file_ptr == (efdr_t *)0)
+ if (cur_file_ptr == (efdr_t *) 0)
{
error ("#.begin directive without a preceding .file directive");
return;
}
- if (cur_proc_ptr == (PDR *)0)
+ if (cur_proc_ptr == (PDR *) 0)
{
error ("#.begin directive without a preceding .ent directive");
return;
}
- for (end_p1 = start; (ch = *end_p1) != '\0' && !isspace (ch); end_p1++)
+ for (end_p1 = start; (ch = *end_p1) != '\0' && !ISSPACE (ch); end_p1++)
;
hash_ptr = hash_string (start,
end_p1 - start,
&orig_str_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
- if (hash_ptr == (shash_t *)0)
+ if (hash_ptr == (shash_t *) 0)
{
error ("Label %.*s not found for #.begin", end_p1 - start, start);
return;
}
- if (cur_oproc_begin == (SYMR *)0)
+ if (cur_oproc_begin == (SYMR *) 0)
{
error ("Procedure table %.*s not found for #.begin", end_p1 - start, start);
return;
}
- (void) add_local_symbol ((const char *)0, (const char *)0,
+ (void) add_local_symbol ((const char *) 0, (const char *) 0,
st_Block, sc_Text,
- (symint_t)hash_ptr->sym_ptr->value - cur_oproc_begin->value,
- (symint_t)0);
+ (symint_t) hash_ptr->sym_ptr->value - cur_oproc_begin->value,
+ (symint_t) 0);
}
@@ -2870,42 +2835,42 @@ parse_bend (start)
int ch;
shash_t *hash_ptr; /* hash pointer to lookup label */
- if (cur_file_ptr == (efdr_t *)0)
+ if (cur_file_ptr == (efdr_t *) 0)
{
error ("#.begin directive without a preceding .file directive");
return;
}
- if (cur_proc_ptr == (PDR *)0)
+ if (cur_proc_ptr == (PDR *) 0)
{
error ("#.bend directive without a preceding .ent directive");
return;
}
- for (end_p1 = start; (ch = *end_p1) != '\0' && !isspace (ch); end_p1++)
+ for (end_p1 = start; (ch = *end_p1) != '\0' && !ISSPACE (ch); end_p1++)
;
hash_ptr = hash_string (start,
end_p1 - start,
&orig_str_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
- if (hash_ptr == (shash_t *)0)
+ if (hash_ptr == (shash_t *) 0)
{
error ("Label %.*s not found for #.bend", end_p1 - start, start);
return;
}
- if (cur_oproc_begin == (SYMR *)0)
+ if (cur_oproc_begin == (SYMR *) 0)
{
error ("Procedure table %.*s not found for #.bend", end_p1 - start, start);
return;
}
- (void) add_local_symbol ((const char *)0, (const char *)0,
+ (void) add_local_symbol ((const char *) 0, (const char *) 0,
st_End, sc_Text,
(symint_t)hash_ptr->sym_ptr->value - cur_oproc_begin->value,
- (symint_t)0);
+ (symint_t) 0);
}
@@ -2929,12 +2894,12 @@ parse_def (name_start)
const char *arg_start; /* start of current argument */
const char *arg_end_p1; /* end+1 of current argument */
const char *name_end_p1; /* end+1 of label */
- const char *tag_start = (const char *)0; /* start of tag name */
- const char *tag_end_p1 = (const char *)0; /* end+1 of tag name */
+ const char *tag_start = (const char *) 0; /* start of tag name */
+ const char *tag_end_p1 = (const char *) 0; /* end+1 of tag name */
sc_t storage_class = sc_Nil;
st_t symbol_type = st_Nil;
type_info_t t;
- EXTR *eptr = (EXTR *)0; /* ext. sym equivalent to def*/
+ EXTR *eptr = (EXTR *) 0; /* ext. sym equivalent to def*/
int is_function = 0; /* != 0 if function */
symint_t value = 0;
symint_t indx = cur_file_ptr->void_type;
@@ -2992,7 +2957,7 @@ parse_def (name_start)
(ch = *dir_end_p1) != ' ' && ch != '\t';
dir_end_p1++)
{
- if (ch == '\0' || isspace (ch))
+ if (ch == '\0' || ISSPACE (ch))
{
error_line = __LINE__;
saber_stop ();
@@ -3002,13 +2967,13 @@ parse_def (name_start)
/* Pick up the subdirective argument now. */
arg_was_number = arg_number = 0;
- arg_end_p1 = (const char *)0;
+ arg_end_p1 = (const char *) 0;
arg_start = dir_end_p1+1;
ch = *arg_start;
while (ch == ' ' || ch == '\t')
ch = *++arg_start;
- if (isdigit (ch) || ch == '-' || ch == '+')
+ if (ISDIGIT (ch) || ch == '-' || ch == '+')
{
int ch2;
arg_number = strtol (arg_start, (char **) &arg_end_p1, 0);
@@ -3016,7 +2981,7 @@ parse_def (name_start)
arg_was_number++;
}
- else if (ch == '\0' || isspace (ch))
+ else if (ch == '\0' || ISSPACE (ch))
{
error_line = __LINE__;
saber_stop ();
@@ -3064,7 +3029,7 @@ parse_def (name_start)
ch = *++arg_start;
arg_was_number = 0;
- if (isdigit (ch) || ch == '-' || ch == '+')
+ if (ISDIGIT (ch) || ch == '-' || ch == '+')
{
int ch2;
arg_number = strtol (arg_start, (char **) &arg_end_p1, 0);
@@ -3138,7 +3103,7 @@ parse_def (name_start)
ch = *++arg_start;
arg_was_number = 0;
- if (isdigit (ch) || ch == '-' || ch == '+')
+ if (ISDIGIT (ch) || ch == '-' || ch == '+')
{
int ch2;
arg_number = strtol (arg_start, (char **) &arg_end_p1, 0);
@@ -3247,30 +3212,30 @@ parse_def (name_start)
ext_hash_ptr = hash_string (arg_start,
arg_end_p1 - arg_start,
&ext_str_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
- if (ext_hash_ptr != (shash_t *)0
- && ext_hash_ptr->esym_ptr != (EXTR *)0)
+ if (ext_hash_ptr != (shash_t *) 0
+ && ext_hash_ptr->esym_ptr != (EXTR *) 0)
eptr = ext_hash_ptr->esym_ptr;
orig_hash_ptr = hash_string (arg_start,
arg_end_p1 - arg_start,
&orig_str_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
- if ((orig_hash_ptr == (shash_t *)0
- || orig_hash_ptr->sym_ptr == (SYMR *)0)
- && eptr == (EXTR *)0)
+ if ((orig_hash_ptr == (shash_t *) 0
+ || orig_hash_ptr->sym_ptr == (SYMR *) 0)
+ && eptr == (EXTR *) 0)
{
fprintf (stderr, "warning, %.*s not found in original or external symbol tables, value defaults to 0\n",
- arg_end_p1 - arg_start,
+ (int) (arg_end_p1 - arg_start),
arg_start);
value = 0;
}
else
{
- SYMR *ptr = (orig_hash_ptr != (shash_t *)0
- && orig_hash_ptr->sym_ptr != (SYMR *)0)
+ SYMR *ptr = (orig_hash_ptr != (shash_t *) 0
+ && orig_hash_ptr->sym_ptr != (SYMR *) 0)
? orig_hash_ptr->sym_ptr
: &eptr->asym;
@@ -3294,14 +3259,22 @@ parse_def (name_start)
}
- t.extra_sizes = (tag_start != (char *)0);
+ if (storage_class == sc_Bits)
+ {
+ t.bitfield = 1;
+ t.extra_sizes = 1;
+ }
+ else
+ t.extra_sizes = 0;
+
if (t.num_dims > 0)
{
- int diff = t.num_dims - t.num_sizes;
+ int num_real_sizes = t.num_sizes - t.extra_sizes;
+ int diff = t.num_dims - num_real_sizes;
int i = t.num_dims - 1;
int j;
- if (t.num_sizes != 1 || diff < 0)
+ if (num_real_sizes != 1 || diff < 0)
{
error_line = __LINE__;
saber_stop ();
@@ -3312,7 +3285,6 @@ parse_def (name_start)
and sizes were passed, creating extra sizes for multiply
dimensioned arrays if not passed. */
- t.extra_sizes = 0;
if (diff)
{
for (j = (sizeof (t.sizes) / sizeof (t.sizes[0])) - 1; j >= 0; j--)
@@ -3329,14 +3301,6 @@ parse_def (name_start)
}
}
- else if (symbol_type == st_Member && t.num_sizes - t.extra_sizes == 1)
- { /* Is this a bitfield? This is indicated by a structure member
- having a size field that isn't an array. */
-
- t.bitfield = 1;
- }
-
-
/* Except for enumeration members & begin/ending of scopes, put the
type word in the aux. symbol table. */
@@ -3352,7 +3316,7 @@ parse_def (name_start)
|| t.basic_type == bt_Union
|| t.basic_type == bt_Enum)
{
- if (tag_start == (char *)0)
+ if (tag_start == (char *) 0)
{
error ("No tag specified for %.*s",
name_end_p1 - name_start,
@@ -3380,8 +3344,8 @@ parse_def (name_start)
/* If this is an external or static symbol, update the appropriate
external symbol. */
- if (eptr != (EXTR *)0
- && (eptr->asym.index == indexNil || cur_proc_ptr == (PDR *)0))
+ if (eptr != (EXTR *) 0
+ && (eptr->asym.index == indexNil || cur_proc_ptr == (PDR *) 0))
{
eptr->ifd = cur_file_ptr->file_index;
eptr->asym.index = indx;
@@ -3418,7 +3382,7 @@ parse_def (name_start)
that any error reporting above gives the correct name. */
case st_End:
- name_start = name_end_p1 = (const char *)0;
+ name_start = name_end_p1 = (const char *) 0;
value = inside_enumeration = 0;
break;
@@ -3440,9 +3404,9 @@ parse_def (name_start)
/* Add the symbol, except for global symbols outside of functions,
for which the external symbol table is fine enough. */
- if (eptr == (EXTR *)0
+ if (eptr == (EXTR *) 0
|| eptr->asym.st == (int)st_Nil
- || cur_proc_ptr != (PDR *)0)
+ || cur_proc_ptr != (PDR *) 0)
{
symint_t isym = add_local_symbol (name_start, name_end_p1,
symbol_type, storage_class,
@@ -3465,7 +3429,7 @@ parse_def (name_start)
forward_t *f_next = tag_ptr->forward_ref;
forward_t *f_cur;
- while (f_next != (forward_t *)0)
+ while (f_next != (forward_t *) 0)
{
f_cur = f_next;
f_next = f_next->next;
@@ -3476,7 +3440,7 @@ parse_def (name_start)
free_forward (f_cur);
}
- tag_ptr->forward_ref = (forward_t *)0;
+ tag_ptr->forward_ref = (forward_t *) 0;
}
}
@@ -3505,20 +3469,20 @@ parse_end (start)
register symint_t value;
register FDR *orig_fdr;
- if (cur_file_ptr == (efdr_t *)0)
+ if (cur_file_ptr == (efdr_t *) 0)
{
error (".end directive without a preceding .file directive");
return;
}
- if (cur_proc_ptr == (PDR *)0)
+ if (cur_proc_ptr == (PDR *) 0)
{
error (".end directive without a preceding .ent directive");
return;
}
/* Get the function name, skipping whitespace. */
- for (start_func = start; isspace (*start_func); start_func++)
+ for (start_func = start; ISSPACE (*start_func); start_func++)
;
ch = *start_func;
@@ -3541,7 +3505,7 @@ parse_end (start)
orig_fdr = cur_file_ptr->orig_fdr;
value = 0;
- if (orig_fdr != (FDR *)0 && cur_oproc_end != (SYMR *)0)
+ if (orig_fdr != (FDR *)0 && cur_oproc_end != (SYMR *) 0)
value = cur_oproc_end->value;
else
@@ -3550,9 +3514,9 @@ parse_end (start)
(void) add_local_symbol (start_func, end_func_p1,
st_End, sc_Text,
value,
- (symint_t)0);
+ (symint_t) 0);
- cur_proc_ptr = cur_oproc_ptr = (PDR *)0;
+ cur_proc_ptr = cur_oproc_ptr = (PDR *) 0;
}
@@ -3565,19 +3529,19 @@ parse_ent (start)
register const char *start_func, *end_func_p1;
register int ch;
- if (cur_file_ptr == (efdr_t *)0)
+ if (cur_file_ptr == (efdr_t *) 0)
{
error (".ent directive without a preceding .file directive");
return;
}
- if (cur_proc_ptr != (PDR *)0)
+ if (cur_proc_ptr != (PDR *) 0)
{
error ("second .ent directive found before .end directive");
return;
}
- for (start_func = start; isspace (*start_func); start_func++)
+ for (start_func = start; ISSPACE (*start_func); start_func++)
;
ch = *start_func;
@@ -3605,14 +3569,14 @@ parse_file (start)
(void) strtol (start, &p, 0);
if (start == p
- || (start_name = local_index (p, '"')) == (char *)0
- || (end_name_p1 = local_rindex (++start_name, '"')) == (char *)0)
+ || (start_name = local_index (p, '"')) == (char *) 0
+ || (end_name_p1 = local_rindex (++start_name, '"')) == (char *) 0)
{
error ("Invalid .file directive");
return;
}
- if (cur_proc_ptr != (PDR *)0)
+ if (cur_proc_ptr != (PDR *) 0)
{
error ("No way to handle .file within .ent/.end section");
return;
@@ -3630,7 +3594,7 @@ mark_stabs (start)
{
if (!stabs_seen)
{
- /* Add a dummy @stabs symbol. */
+ /* Add a dummy @stabs symbol. */
stabs_seen = 1;
(void) add_local_symbol (stabs_symbol,
stabs_symbol + sizeof (stabs_symbol),
@@ -3673,7 +3637,7 @@ STATIC void
parse_stabs_common (string_start, string_end, rest)
const char *string_start; /* start of string or NULL */
const char *string_end; /* end+1 of string or NULL */
- const char *rest; /* rest of the directive. */
+ const char *rest; /* rest of the directive. */
{
efdr_t *save_file_ptr = cur_file_ptr;
symint_t code;
@@ -3687,7 +3651,7 @@ parse_stabs_common (string_start, string_end, rest)
mark_stabs ("");
/* Read code from stabs. */
- if (!isdigit (*rest))
+ if (!ISDIGIT (*rest))
{
error ("Invalid .stabs/.stabn directive, code is non-numeric");
return;
@@ -3707,7 +3671,7 @@ parse_stabs_common (string_start, string_end, rest)
shash_t *shash_ptr;
/* Skip ,0, */
- if (p[0] != ',' || p[1] != '0' || p[2] != ',' || !isdigit (p[3]))
+ if (p[0] != ',' || p[1] != '0' || p[2] != ',' || !ISDIGIT (p[3]))
{
error ("Invalid line number .stabs/.stabn directive");
return;
@@ -3715,7 +3679,7 @@ parse_stabs_common (string_start, string_end, rest)
code = strtol (p+3, &p, 0);
ch = *++p;
- if (p[-1] != ',' || isdigit (ch) || !IS_ASM_IDENT (ch))
+ if (p[-1] != ',' || ISDIGIT (ch) || !IS_ASM_IDENT (ch))
{
error ("Invalid line number .stabs/.stabn directive");
return;
@@ -3733,10 +3697,10 @@ parse_stabs_common (string_start, string_end, rest)
shash_ptr = hash_string (p,
strlen (p) - 1,
&orig_str_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
- if (shash_ptr == (shash_t *)0
- || (sym_ptr = shash_ptr->sym_ptr) == (SYMR *)0)
+ if (shash_ptr == (shash_t *) 0
+ || (sym_ptr = shash_ptr->sym_ptr) == (SYMR *) 0)
{
error ("Invalid .stabs/.stabn directive, value not found");
return;
@@ -3757,11 +3721,11 @@ parse_stabs_common (string_start, string_end, rest)
/* Skip ,<num>,<num>, */
if (*p++ != ',')
goto failure;
- for (; isdigit (*p); p++)
+ for (; ISDIGIT (*p); p++)
;
if (*p++ != ',')
goto failure;
- for (; isdigit (*p); p++)
+ for (; ISDIGIT (*p); p++)
;
if (*p++ != ',')
goto failure;
@@ -3773,7 +3737,7 @@ parse_stabs_common (string_start, string_end, rest)
return;
}
- if (isdigit (ch) || ch == '-')
+ if (ISDIGIT (ch) || ch == '-')
{
st = st_Nil;
sc = sc_Nil;
@@ -3796,27 +3760,27 @@ parse_stabs_common (string_start, string_end, rest)
const char *start, *end_p1;
start = p;
- if ((end_p1 = strchr (start, '+')) == (char *)0)
+ if ((end_p1 = strchr (start, '+')) == (char *) 0)
{
- if ((end_p1 = strchr (start, '-')) == (char *)0)
+ if ((end_p1 = strchr (start, '-')) == (char *) 0)
end_p1 = start + strlen(start) - 1;
}
shash_ptr = hash_string (start,
end_p1 - start,
&orig_str_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
- if (shash_ptr == (shash_t *)0
- || (sym_ptr = shash_ptr->sym_ptr) == (SYMR *)0)
+ if (shash_ptr == (shash_t *) 0
+ || (sym_ptr = shash_ptr->sym_ptr) == (SYMR *) 0)
{
shash_ptr = hash_string (start,
end_p1 - start,
&ext_str_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
- if (shash_ptr == (shash_t *)0
- || shash_ptr->esym_ptr == (EXTR *)0)
+ if (shash_ptr == (shash_t *) 0
+ || shash_ptr->esym_ptr == (EXTR *) 0)
{
error ("Invalid .stabs/.stabn directive, value not found");
return;
@@ -3825,8 +3789,8 @@ parse_stabs_common (string_start, string_end, rest)
sym_ptr = &(shash_ptr->esym_ptr->asym);
}
- /* Traditionally, N_LBRAC and N_RBRAC are *not* relocated. */
- if (code == (int)N_LBRAC || code == (int)N_RBRAC)
+ /* Traditionally, N_LBRAC and N_RBRAC are *not* relocated. */
+ if (code == (int) N_LBRAC || code == (int) N_RBRAC)
{
sc = scNil;
st = stNil;
@@ -3841,7 +3805,7 @@ parse_stabs_common (string_start, string_end, rest)
ch = *end_p1++;
if (ch != '\n')
{
- if (((!isdigit (*end_p1)) && (*end_p1 != '-'))
+ if (((!ISDIGIT (*end_p1)) && (*end_p1 != '-'))
|| ((ch != '+') && (ch != '-')))
{
error ("Invalid .stabs/.stabn directive, badly formed value");
@@ -3874,7 +3838,7 @@ parse_stabs (start)
{
const char *end = local_index (start+1, '"');
- if (*start != '"' || end == (const char *)0 || end[1] != ',')
+ if (*start != '"' || end == (const char *) 0 || end[1] != ',')
{
error ("Invalid .stabs directive, no string");
return;
@@ -3888,7 +3852,7 @@ STATIC void
parse_stabn (start)
const char *start; /* start of directive */
{
- parse_stabs_common ((const char *)0, (const char *)0, start);
+ parse_stabs_common ((const char *) 0, (const char *) 0, start);
}
@@ -3914,19 +3878,19 @@ parse_input __proto((void))
ptag_head->prev = cur_tag_head;
cur_tag_head = ptag_head;
- while ((p = read_line ()) != (char *)0)
+ while ((p = read_line ()) != (char *) 0)
{
/* Skip leading blanks */
- while (isspace (*p))
+ while (ISSPACE (*p))
p++;
/* See if it's a directive we handle. If so, dispatch handler. */
for (i = 0; i < sizeof (pseudo_ops) / sizeof (pseudo_ops[0]); i++)
if (memcmp (p, pseudo_ops[i].name, pseudo_ops[i].len) == 0
- && isspace (p[pseudo_ops[i].len]))
+ && ISSPACE (p[pseudo_ops[i].len]))
{
p += pseudo_ops[i].len; /* skip to first argument */
- while (isspace (*p))
+ while (ISSPACE (*p))
p++;
(*pseudo_ops[i].func)( p );
@@ -3939,10 +3903,10 @@ parse_input __proto((void))
cur_tag_head = ptag_head->prev;
for (ptag = ptag_head->first_tag;
- ptag != (tag_t *)0;
+ ptag != (tag_t *) 0;
ptag = ptag_next)
{
- if (ptag->forward_ref != (forward_t *)0)
+ if (ptag->forward_ref != (forward_t *) 0)
add_unknown_tag (ptag);
ptag_next = ptag->same_block;
@@ -3985,7 +3949,7 @@ update_headers __proto((void))
for the filename. */
for (file_ptr = first_file;
- file_ptr != (efdr_t *)0;
+ file_ptr != (efdr_t *) 0;
file_ptr = file_ptr->next_file)
{
register SYMR *sym_start;
@@ -4015,8 +3979,8 @@ update_headers __proto((void))
hash_ptr = hash_string (str,
(Ptrdiff_t)len,
&file_ptr->shash_head[0],
- (symint_t *)0);
- if (hash_ptr == (shash_t *)0)
+ (symint_t *) 0);
+ if (hash_ptr == (shash_t *) 0)
{
(void) add_local_symbol (str, str + len,
(st_t)sym->st, (sc_t)sym->sc,
@@ -4025,10 +3989,10 @@ update_headers __proto((void))
}
}
}
- (void) add_local_symbol ((const char *)0, (const char *)0,
+ (void) add_local_symbol ((const char *) 0, (const char *) 0,
st_End, sc_Text,
- (symint_t)0,
- (symint_t)0);
+ (symint_t) 0,
+ (symint_t) 0);
file_ptr->fdr.cpd = file_ptr->procs.num_allocated;
file_ptr->fdr.ipdFirst = symbolic_header.ipdMax;
@@ -4092,7 +4056,7 @@ update_headers __proto((void))
file_offset = ALIGN_SYMTABLE_OFFSET (file_offset);
}
- i = symbolic_header.iauxMax; /* aux syms. */
+ i = symbolic_header.iauxMax; /* aux syms. */
if (i > 0)
{
symbolic_header.cbAuxOffset = file_offset;
@@ -4157,16 +4121,20 @@ write_varray (vp, offset, str)
return;
if (debug)
- fprintf (stderr, "\twarray\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n",
- vp, offset, vp->num_allocated * vp->object_size, str);
-
+ {
+ fputs ("\twarray\tvp = ", stderr);
+ fprintf (stderr, HOST_PTR_PRINTF, vp);
+ fprintf (stderr, ", offset = %7lu, size = %7lu, %s\n",
+ (unsigned long) offset, vp->num_allocated * vp->object_size, str);
+ }
+
if (file_offset != offset
&& fseek (object_stream, (long)offset, SEEK_SET) < 0)
pfatal_with_name (object_name);
- for (ptr = vp->first; ptr != (vlinks_t *)0; ptr = ptr->next)
+ for (ptr = vp->first; ptr != (vlinks_t *) 0; ptr = ptr->next)
{
- num_write = (ptr->next == (vlinks_t *)0)
+ num_write = (ptr->next == (vlinks_t *) 0)
? vp->objects_last_page * vp->object_size
: vp->objects_per_page * vp->object_size;
@@ -4195,9 +4163,12 @@ write_object __proto((void))
off_t offset;
if (debug)
- fprintf (stderr, "\n\twrite\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n",
- (PTR_T *) &symbolic_header, 0, sizeof (symbolic_header),
- "symbolic header");
+ {
+ fputs ("\n\twrite\tvp = ", stderr);
+ fprintf (stderr, HOST_PTR_PRINTF, (PTR_T *) &symbolic_header);
+ fprintf (stderr, ", offset = %7u, size = %7lu, %s\n",
+ 0, (unsigned long) sizeof (symbolic_header), "symbolic header");
+ }
sys_write = fwrite ((PTR_T) &symbolic_header,
1,
@@ -4225,9 +4196,13 @@ write_object __proto((void))
pfatal_with_name (object_name);
if (debug)
- fprintf (stderr, "\twrite\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n",
- (PTR_T *) &orig_linenum, symbolic_header.cbLineOffset,
- symbolic_header.cbLine, "Line numbers");
+ {
+ fputs ("\twrite\tvp = ", stderr);
+ fprintf (stderr, HOST_PTR_PRINTF, (PTR_T *) &orig_linenum);
+ fprintf (stderr, ", offset = %7lu, size = %7lu, %s\n",
+ (long) symbolic_header.cbLineOffset,
+ (long) symbolic_header.cbLine, "Line numbers");
+ }
sys_write = fwrite ((PTR_T) orig_linenum,
1,
@@ -4256,9 +4231,13 @@ write_object __proto((void))
pfatal_with_name (object_name);
if (debug)
- fprintf (stderr, "\twrite\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n",
- (PTR_T *) &orig_opt_syms, symbolic_header.cbOptOffset,
- num_write, "Optimizer symbols");
+ {
+ fputs ("\twrite\tvp = ", stderr);
+ fprintf (stderr, HOST_PTR_PRINTF, (PTR_T *) &orig_opt_syms);
+ fprintf (stderr, ", offset = %7lu, size = %7lu, %s\n",
+ (long) symbolic_header.cbOptOffset,
+ num_write, "Optimizer symbols");
+ }
sys_write = fwrite ((PTR_T) orig_opt_syms,
1,
@@ -4284,7 +4263,7 @@ write_object __proto((void))
{
offset = symbolic_header.cbPdOffset;
for (file_ptr = first_file;
- file_ptr != (efdr_t *)0;
+ file_ptr != (efdr_t *) 0;
file_ptr = file_ptr->next_file)
{
write_varray (&file_ptr->procs, offset, "Procedure tables");
@@ -4296,7 +4275,7 @@ write_object __proto((void))
{
offset = symbolic_header.cbSymOffset;
for (file_ptr = first_file;
- file_ptr != (efdr_t *)0;
+ file_ptr != (efdr_t *) 0;
file_ptr = file_ptr->next_file)
{
write_varray (&file_ptr->symbols, offset, "Local symbols");
@@ -4308,7 +4287,7 @@ write_object __proto((void))
{
offset = symbolic_header.cbAuxOffset;
for (file_ptr = first_file;
- file_ptr != (efdr_t *)0;
+ file_ptr != (efdr_t *) 0;
file_ptr = file_ptr->next_file)
{
write_varray (&file_ptr->aux_syms, offset, "Aux. symbols");
@@ -4320,7 +4299,7 @@ write_object __proto((void))
{
offset = symbolic_header.cbSsOffset;
for (file_ptr = first_file;
- file_ptr != (efdr_t *)0;
+ file_ptr != (efdr_t *) 0;
file_ptr = file_ptr->next_file)
{
write_varray (&file_ptr->strings, offset, "Local strings");
@@ -4340,12 +4319,17 @@ write_object __proto((void))
file_offset = offset;
for (file_ptr = first_file;
- file_ptr != (efdr_t *)0;
+ file_ptr != (efdr_t *) 0;
file_ptr = file_ptr->next_file)
{
if (debug)
- fprintf (stderr, "\twrite\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n",
- (PTR_T *) &file_ptr->fdr, file_offset, sizeof (FDR), "File header");
+ {
+ fputs ("\twrite\tvp = ", stderr);
+ fprintf (stderr, HOST_PTR_PRINTF, (PTR_T *) &file_ptr->fdr);
+ fprintf (stderr, ", offset = %7lu, size = %7lu, %s\n",
+ file_offset, (unsigned long) sizeof (FDR),
+ "File header");
+ }
sys_write = fwrite (&file_ptr->fdr,
1,
@@ -4375,9 +4359,13 @@ write_object __proto((void))
pfatal_with_name (object_name);
if (debug)
- fprintf (stderr, "\twrite\tvp = 0x%.8x, offset = %7u, size = %7u, %s\n",
- (PTR_T *) &orig_rfds, symbolic_header.cbRfdOffset,
- num_write, "Relative file descriptors");
+ {
+ fputs ("\twrite\tvp = ", stderr);
+ fprintf (stderr, HOST_PTR_PRINTF, (PTR_T *) &orig_rfds);
+ fprintf (stderr, ", offset = %7lu, size = %7lu, %s\n",
+ (long) symbolic_header.cbRfdOffset,
+ num_write, "Relative file descriptors");
+ }
sys_write = fwrite (orig_rfds,
1,
@@ -4416,11 +4404,12 @@ read_seek (size, offset, str)
long sys_read = 0;
if (size == 0) /* nothing to read */
- return (page_t *)0;
+ return (page_t *) 0;
if (debug)
- fprintf (stderr, "\trseek\tsize = %7u, offset = %7u, currently at %7u, %s\n",
- size, offset, file_offset, str);
+ fprintf (stderr,
+ "\trseek\tsize = %7lu, offset = %7lu, currently at %7lu, %s\n",
+ (unsigned long) size, (unsigned long) offset, file_offset, str);
#ifndef MALLOC_CHECK
ptr = allocate_multiple_pages ((size + PAGE_USIZE - 1) / PAGE_USIZE);
@@ -4542,7 +4531,7 @@ copy_object __proto((void))
sections, so in theory no extra seeks are done.
For simplicity sake, round each read up to a page boundary,
- we may want to revisit this later.... */
+ we may want to revisit this later.... */
file_offset = orig_file_header.f_symptr + sizeof (struct filehdr);
@@ -4623,7 +4612,7 @@ copy_object __proto((void))
char *filename = orig_local_strs + (orig_files->issBase + orig_files->rss);
char *suffix = local_rindex (filename, '.');
- if (suffix != (char *)0 && strcmp (suffix, ".s") == 0)
+ if (suffix != (char *) 0 && strcmp (suffix, ".s") == 0)
delete_ifd = 1;
}
@@ -4670,7 +4659,7 @@ copy_object __proto((void))
(st_t) eptr->asym.st,
(sc_t) eptr->asym.sc,
eptr->asym.value,
- (symint_t)((eptr->asym.index == indexNil) ? indexNil : 0),
+ (symint_t) ((eptr->asym.index == indexNil) ? indexNil : 0),
(ifd < orig_sym_hdr.ifdMax) ? remap_file_number[ ifd ] : ifd);
}
@@ -4735,7 +4724,7 @@ copy_object __proto((void))
&orig_str_hash[0],
&hash_index);
- if (shash_ptr != (shash_t *)0)
+ if (shash_ptr != (shash_t *) 0)
error ("internal error, %s is already in original symbol table", str);
else
@@ -4763,9 +4752,9 @@ copy_object __proto((void))
register shash_t *shash_ptr = hash_string (str,
(Ptrdiff_t)len,
&orig_str_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
- if (shash_ptr != (shash_t *)0)
+ if (shash_ptr != (shash_t *) 0)
shash_ptr->end_ptr = sym;
}
}
@@ -4793,9 +4782,9 @@ copy_object __proto((void))
register shash_t *shash_ptr = hash_string (str,
(Ptrdiff_t)len,
&orig_str_hash[0],
- (symint_t *)0);
+ (symint_t *) 0);
- if (shash_ptr == (shash_t *)0)
+ if (shash_ptr == (shash_t *) 0)
error ("internal error, function %s is not in original symbol table", str);
else
@@ -4811,12 +4800,12 @@ copy_object __proto((void))
/* Copy all of the object file up to the symbol table. Originally
we were going to use ftruncate, but that doesn't seem to work
- on Ultrix 3.1.... */
+ on Ultrix 3.1.... */
- if (fseek (obj_in_stream, (long)0, SEEK_SET) != 0)
+ if (fseek (obj_in_stream, (long) 0, SEEK_SET) != 0)
pfatal_with_name (obj_in_name);
- if (fseek (object_stream, (long)0, SEEK_SET) != 0)
+ if (fseek (object_stream, (long) 0, SEEK_SET) != 0)
pfatal_with_name (object_name);
for (remaining = orig_file_header.f_symptr;
@@ -4910,7 +4899,7 @@ main (argc, argv)
break;
case 'I':
- if (rename_output || obj_in_name != (char *)0)
+ if (rename_output || obj_in_name != (char *) 0)
had_errors++;
else
rename_output = 1;
@@ -4918,7 +4907,7 @@ main (argc, argv)
/* fall through to 'i' case. */
case 'i':
- if (obj_in_name == (char *)0)
+ if (obj_in_name == (char *) 0)
{
obj_in_name = optarg;
iflag++;
@@ -4928,7 +4917,7 @@ main (argc, argv)
break;
case 'o':
- if (object_name == (char *)0)
+ if (object_name == (char *) 0)
object_name = optarg;
else
had_errors++;
@@ -4939,22 +4928,22 @@ main (argc, argv)
break;
}
- if (obj_in_name == (char *)0 && optind <= argc - 2)
+ if (obj_in_name == (char *) 0 && optind <= argc - 2)
obj_in_name = argv[--argc];
- if (object_name == (char *)0 && optind <= argc - 2)
+ if (object_name == (char *) 0 && optind <= argc - 2)
object_name = argv[--argc];
/* If there is an output name, but no input name use
the same file for both, deleting the name between
opening it for input and opening it for output. */
- if (obj_in_name == (char *)0 && object_name != (char *)0)
+ if (obj_in_name == (char *) 0 && object_name != (char *)0)
{
obj_in_name = object_name;
delete_input = 1;
}
- if (object_name == (char *)0 || had_errors || optind != argc - 1)
+ if (object_name == (char *) 0 || had_errors || optind != argc - 1)
{
fprintf (stderr, "Calling Sequence:\n");
fprintf (stderr, "\tmips-tfile [-d <num>] [-v] [-i <o-in-file>] -o <o-out-file> <s-file> (or)\n");
@@ -4979,7 +4968,7 @@ main (argc, argv)
fputc ('\n', stderr);
}
- if (obj_in_name == (char *)0)
+ if (obj_in_name == (char *) 0)
obj_in_name = object_name;
if (rename_output && rename (object_name, obj_in_name) != 0)
@@ -5024,14 +5013,14 @@ main (argc, argv)
/* Must open input before output, since the output may be the same file, and
we need to get the input handle before truncating it. */
obj_in_stream = fopen (obj_in_name, "r");
- if (obj_in_stream == (FILE *)0)
+ if (obj_in_stream == (FILE *) 0)
pfatal_with_name (obj_in_name);
if (delete_input && unlink (obj_in_name) != 0)
pfatal_with_name (obj_in_name);
object_stream = fopen (object_name, "w");
- if (object_stream == (FILE *)0)
+ if (object_stream == (FILE *) 0)
pfatal_with_name (object_name);
if (strcmp (argv[optind], "-") != 0)
@@ -5072,7 +5061,7 @@ STATIC void
catch_signal (signum)
int signum;
{
- (void) signal (signum, SIG_DFL); /* just in case... */
+ (void) signal (signum, SIG_DFL); /* just in case... */
#ifdef NO_SYS_SIGLIST
fatal ("caught signal");
#else
@@ -5087,7 +5076,7 @@ void
pfatal_with_name (msg)
char *msg;
{
- int save_errno = errno; /* just in case.... */
+ int save_errno = errno; /* just in case.... */
if (line_number > 0)
fprintf (stderr, "%s, %s:%ld ", progname, input_name, line_number);
else
@@ -5117,7 +5106,7 @@ out_of_bounds (indx, max, str, prog_line)
if (indx < max) /* just in case */
return 0;
- fprintf (stderr, "%s, %s:%ld index %u is out of bounds for %s, max is %u, mips-tfile.c line# %d\n",
+ fprintf (stderr, "%s, %s:%ld index %lu is out of bounds for %s, max is %lu, mips-tfile.c line# %d\n",
progname, input_name, line_number, indx, str, max, prog_line);
exit (1);
@@ -5126,7 +5115,7 @@ out_of_bounds (indx, max, str, prog_line)
/* Allocate a cluster of pages. USE_MALLOC says that malloc does not
- like sbrk's behind it's back (or sbrk isn't available). If we use
+ like sbrk's behind its back (or sbrk isn't available). If we use
sbrk, we assume it gives us zeroed pages. */
#ifndef MALLOC_CHECK
@@ -5168,7 +5157,12 @@ allocate_cluster (npages)
pfatal_with_name ("allocate_cluster");
if (debug > 3)
- fprintf (stderr, "\talloc\tnpages = %d, value = 0x%.8x\n", npages, ptr);
+ {
+ fprintf (stderr, "\talloc\tnpages = %lu, value = ",
+ (unsigned long) npages);
+ fprintf (stderr, HOST_PTR_PRINTF, ptr);
+ fputs ("\n", stderr);
+ }
return ptr;
}
@@ -5275,7 +5269,7 @@ allocate_scope __proto((void))
#ifndef MALLOC_CHECK
ptr = alloc_counts[ (int)alloc_type_scope ].free_list.f_scope;
- if (ptr != (scope_t *)0)
+ if (ptr != (scope_t *) 0)
alloc_counts[ (int)alloc_type_scope ].free_list.f_scope = ptr->free;
else
@@ -5432,7 +5426,7 @@ allocate_tag __proto((void))
#ifndef MALLOC_CHECK
ptr = alloc_counts[ (int)alloc_type_tag ].free_list.f_tag;
- if (ptr != (tag_t *)0)
+ if (ptr != (tag_t *) 0)
alloc_counts[ (int)alloc_type_tag ].free_list.f_tag = ptr->free;
else
@@ -5490,7 +5484,7 @@ allocate_forward __proto((void))
#ifndef MALLOC_CHECK
ptr = alloc_counts[ (int)alloc_type_forward ].free_list.f_forward;
- if (ptr != (forward_t *)0)
+ if (ptr != (forward_t *) 0)
alloc_counts[ (int)alloc_type_forward ].free_list.f_forward = ptr->free;
else
@@ -5548,7 +5542,7 @@ allocate_thead __proto((void))
#ifndef MALLOC_CHECK
ptr = alloc_counts[ (int)alloc_type_thead ].free_list.f_thead;
- if (ptr != (thead_t *)0)
+ if (ptr != (thead_t *) 0)
alloc_counts[ (int)alloc_type_thead ].free_list.f_thead = ptr->free;
else
@@ -5598,8 +5592,6 @@ free_thead (ptr)
#endif /* MIPS_DEBUGGING_INFO */
-#ifdef HAVE_VPRINTF
-
/* Output an error message and exit */
/*VARARGS*/
@@ -5614,7 +5606,7 @@ fatal VPROTO((const char *format, ...))
VA_START (ap, format);
#ifndef __STDC__
- format = va_arg (ap, char*);
+ format = va_arg (ap, char *);
#endif
if (line_number > 0)
@@ -5644,7 +5636,7 @@ error VPROTO((const char *format, ...))
VA_START (ap, format);
#ifndef __STDC__
- format = va_arg (ap, char*);
+ format = va_arg (ap, char *);
#endif
if (line_number > 0)
@@ -5663,27 +5655,6 @@ error VPROTO((const char *format, ...))
saber_stop ();
}
-#else /* not HAVE_VPRINTF */
-
-void
-fatal (msg, arg1, arg2)
- char *msg, *arg1, *arg2;
-{
- error (msg, arg1, arg2);
- exit (1);
-}
-
-void
-error (msg, arg1, arg2)
- char *msg, *arg1, *arg2;
-{
- fprintf (stderr, "%s: ", progname);
- fprintf (stderr, msg, arg1, arg2);
- fprintf (stderr, "\n");
-}
-
-#endif /* not HAVE_VPRINTF */
-
/* More 'friendly' abort that prints the line and file.
config.h can #define abort fancy_abort if you like that sort of thing. */
@@ -5715,7 +5686,11 @@ xmalloc (size)
fatal ("Virtual memory exhausted.");
if (debug > 3)
- fprintf (stderr, "\tmalloc\tptr = 0x%.8x, size = %10u\n", value, size);
+ {
+ fputs ("\tmalloc\tptr = ", stderr);
+ fprintf (stderr, HOST_PTR_PRINTF, value);
+ fprintf (stderr, ", size = %10lu\n", (unsigned long) size);
+ }
return value;
}
@@ -5731,8 +5706,13 @@ xcalloc (size1, size2)
fatal ("Virtual memory exhausted.");
if (debug > 3)
- fprintf (stderr, "\tcalloc\tptr = 0x%.8x, size1 = %10u, size2 = %10u [%u]\n",
- value, size1, size2, size1+size2);
+ {
+ fputs ("\tcalloc\tptr = ", stderr);
+ fprintf (stderr, HOST_PTR_PRINTF, value);
+ fprintf (stderr, ", size1 = %10lu, size2 = %10lu [%lu]\n",
+ (unsigned long) size1, (unsigned long) size2,
+ (unsigned long) size1*size2);
+ }
return value;
}
@@ -5749,8 +5729,13 @@ xrealloc (ptr, size)
fatal ("Virtual memory exhausted.");
if (debug > 3)
- fprintf (stderr, "\trealloc\tptr = 0x%.8x, size = %10u, orig = 0x%.8x\n",
- result, size, ptr);
+ {
+ fputs ("\trealloc\tptr = ", stderr);
+ fprintf (stderr, HOST_PTR_PRINTF, result);
+ fprintf (stderr, ", size = %10lu, orig = ", size);
+ fprintf (stderr, HOST_PTR_PRINTF, ptr);
+ fputs ("\n", stderr);
+ }
return result;
}
@@ -5760,7 +5745,11 @@ xfree (ptr)
PTR_T ptr;
{
if (debug > 3)
- fprintf (stderr, "\tfree\tptr = 0x%.8x\n", ptr);
+ {
+ fputs ("\tfree\tptr = ", stderr);
+ fprintf (stderr, HOST_PTR_PRINTF, ptr);
+ fputs ("\n", stderr);
+ }
free (ptr);
}
@@ -5779,7 +5768,7 @@ local_index (str, sentinel)
for ( ; (ch = *str) != sentinel; str++)
{
if (ch == '\0')
- return (char *)0;
+ return (char *) 0;
}
return (char *)str;
@@ -5791,7 +5780,7 @@ local_rindex (str, sentinel)
int sentinel;
{
int ch;
- const char *ret = (const char *)0;
+ const char *ret = (const char *) 0;
for ( ; (ch = *str) != '\0'; str++)
{
diff --git a/contrib/gcc/objc/Make-lang.in b/contrib/gcc/objc/Make-lang.in
new file mode 100644
index 0000000..3774e22
--- /dev/null
+++ b/contrib/gcc/objc/Make-lang.in
@@ -0,0 +1,312 @@
+# Top level makefile fragment for GNU Objective-C
+# Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+#This file is part of GNU CC.
+
+#GNU CC 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, or (at your option)
+#any later version.
+
+#GNU CC 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 GNU CC; see the file COPYING. If not, write to
+#the Free Software Foundation, 59 Temple Place - Suite 330,
+#Boston, MA 02111-1307, USA.
+
+# This file provides the language dependent support in the main Makefile.
+# Each language makefile fragment must provide the following targets:
+#
+# foo.all.build, foo.all.cross, foo.start.encap, foo.rest.encap,
+# foo.info, foo.dvi,
+# foo.install-normal, foo.install-common, foo.install-info, foo.install-man,
+# foo.uninstall, foo.distdir,
+# foo.mostlyclean, foo.clean, foo.distclean, foo.extraclean,
+# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4
+#
+# where `foo' is the name of the language.
+#
+# It should also provide rules for:
+#
+# - making any compiler driver (eg: g++)
+# - the compiler proper (eg: cc1plus)
+# - define the names for selecting the language in LANGUAGES.
+#
+# Extra flags to pass to recursive makes.
+OBJC_FLAGS_TO_PASS = \
+ "OBJC_FOR_BUILD=$(OBJC_FOR_BUILD)" \
+ "OBJCFLAGS=$(OBJCFLAGS)" \
+ "OBJC_FOR_TARGET=$(OBJC_FOR_TARGET)" \
+
+# Actual names to use when installing a native compiler.
+#OBJC_INSTALL_NAME = `t='$(program_transform_name)'; echo c++ | sed $$t`
+
+# Actual names to use when installing a cross-compiler.
+#OBJC_CROSS_NAME = `t='$(program_transform_cross_name)'; echo c++ | sed $$t`
+
+#
+# Define the names for selecting Objective-C in LANGUAGES.
+OBJC objc: cc1obj$(exeext) objc-runtime
+OBJECTIVE-C objective-c: cc1obj$(exeext) objc-runtime
+
+# Tell GNU make to ignore these if they exist.
+.PHONY: objective-c objc ObjC
+
+# The Objective C thread file
+OBJC_THREAD_FILE=thr-$(GCC_THREAD_FILE)
+
+# Language-specific object files for Objective C.
+OBJC_OBJS = objc-parse.o objc-act.o $(C_AND_OBJC_OBJS)
+
+cc1obj$(exeext): $(P) $(OBJC_OBJS) $(OBJS) $(LIBDEPS)
+ $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(OBJC_OBJS) $(OBJS) \
+ $(LIBS)
+
+# Objective C language specific files.
+
+objc-parse.o : $(srcdir)/objc/objc-parse.c \
+ $(CONFIG_H) $(TREE_H) $(srcdir)/toplev.h \
+ $(srcdir)/c-lex.h $(srcdir)/c-tree.h $(srcdir)/input.h \
+ $(srcdir)/flags.h $(srcdir)/output.h $(srcdir)/objc/objc-act.h system.h
+ $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -I$(srcdir)/objc \
+ -c $(srcdir)/objc/objc-parse.c
+
+$(srcdir)/objc/objc-parse.c : $(srcdir)/objc/objc-parse.y
+ cd $(srcdir)/objc; \
+ $(BISON) $(BISONFLAGS) objc-parse.y -o objc-parse.c
+
+$(srcdir)/objc/objc-parse.y: $(srcdir)/c-parse.in
+ echo '/*WARNING: This file is automatically generated!*/' >tmp-objc-prs.y
+ sed -e "/^ifc$$/,/^end ifc$$/d" \
+ -e "/^ifobjc$$/d" -e "/^end ifobjc$$/d" \
+ $(srcdir)/c-parse.in >>tmp-objc-prs.y
+ $(srcdir)/move-if-change tmp-objc-prs.y $(srcdir)/objc/objc-parse.y
+
+objc-act.o : $(srcdir)/objc/objc-act.c \
+ $(CONFIG_H) $(TREE_H) $(RTL_H) system.h \
+ $(srcdir)/c-tree.h $(srcdir)/c-lex.h $(srcdir)/toplev.h \
+ $(srcdir)/flags.h $(srcdir)/objc/objc-act.h $(srcdir)/input.h \
+ $(srcdir)/function.h $(srcdir)/output.h $(srcdir)/c-parse.h
+ $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -I$(srcdir)/objc \
+ -c $(srcdir)/objc/objc-act.c
+
+objc-runtime: objc-headers libobjc.a
+
+# copy objc header files into build directory
+objc-headers: stmp-fixinc
+ if [ -d include ]; then true; else mkdir include; fi
+ cd objc; \
+ if [ -f Makefile ]; then \
+ $(MAKE) copy-headers \
+ tooldir=$(tooldir) \
+ AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" \
+ GCC_FOR_TARGET="../xgcc -B../" \
+ GCC_CFLAGS="$(GCC_CFLAGS)" incinstalldir=../include; \
+ fi
+ touch objc-headers
+
+# Objective C runtime library specific files.
+
+OBJC_O = objc/hash.o objc/sarray.o \
+ objc/class.o objc/sendmsg.o \
+ objc/init.o objc/archive.o \
+ objc/encoding.o objc/selector.o \
+ objc/objects.o objc/misc.o \
+ objc/NXConstStr.o objc/Object.o \
+ objc/Protocol.o objc/nil_method.o \
+ objc/thr.o objc/linking.o \
+ objc/$(OBJC_THREAD_FILE).o
+
+objc/hash.o: $(srcdir)/objc/hash.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/hash.c -o $@
+objc/sarray.o: $(srcdir)/objc/sarray.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/sarray.c -o $@
+objc/class.o: $(srcdir)/objc/class.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/class.c -o $@
+objc/sendmsg.o: $(srcdir)/objc/sendmsg.c $(GCC_PASSES) objc/runtime-info.h
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) -Iobjc \
+ -c $(srcdir)/objc/sendmsg.c -o $@
+objc/init.o: $(srcdir)/objc/init.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/init.c -o $@
+objc/archive.o: $(srcdir)/objc/archive.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/archive.c -o $@
+objc/encoding.o: $(srcdir)/objc/encoding.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/encoding.c -o $@
+objc/selector.o: $(srcdir)/objc/selector.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/selector.c -o $@
+objc/objects.o: $(srcdir)/objc/objects.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/objects.c -o $@
+objc/misc.o: $(srcdir)/objc/misc.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/misc.c -o $@
+objc/NXConstStr.o: $(srcdir)/objc/NXConstStr.m $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -fgnu-runtime -c $(srcdir)/objc/NXConstStr.m -o $@
+objc/Object.o: $(srcdir)/objc/Object.m $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -fgnu-runtime -c $(srcdir)/objc/Object.m -o $@
+objc/Protocol.o: $(srcdir)/objc/Protocol.m $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -fgnu-runtime -c $(srcdir)/objc/Protocol.m -o $@
+objc/thr.o: $(srcdir)/objc/thr.h $(srcdir)/objc/thr.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/thr.c -o $@
+objc/$(OBJC_THREAD_FILE).o: $(srcdir)/objc/$(OBJC_THREAD_FILE).c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/$(OBJC_THREAD_FILE).c -o $@
+objc/nil_method.o: $(srcdir)/objc/nil_method.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/nil_method.c -o $@
+objc/linking.o: $(srcdir)/objc/linking.m $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -fgnu-runtime -c $(srcdir)/objc/linking.m -o $@
+
+objc/libobjc_entry.o: $(srcdir)/objc/libobjc_entry.c $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(INCLUDES) \
+ -c $(srcdir)/objc/libobjc_entry.c -o $@
+
+$(OBJC_O): $(GCC_PASSES) cc1obj$(exeext)
+
+# Build the Objective C runtime library.
+libobjc.a: cc1obj$(exeext) specs stmp-int-hdrs libgcc2.ready \
+ $(USE_COLLECT2) $(EXTRA_PARTS) objc/runtime-info.h $(OBJC_O)
+ -rm -f libobjc.a
+ $(AR) $(AR_FLAGS) libobjc.a $(OBJC_O)
+ -if $(RANLIB_TEST) ; then $(RANLIB) libobjc.a; else true; fi
+
+libobjc_s.a: libobjc.a
+ mv libobjc.a libobjc_s.a
+
+# Create a relocatable DLL
+libobjc.dll: libobjc_s.a objc/libobjc_entry.o
+ $(GCC_FOR_TARGET) -mdll -Wl,--base-file -Wl,libobjc.base \
+ -o libobjc.dll libobjc_s.a \
+ objc/libobjc_entry.o -lkernel32
+ $(DLLTOOL) --dllname libobjc.dll --def $(srcdir)/objc/libobjc.def \
+ --base-file libobjc.base --output-exp libobjc.exp
+ $(GCC_FOR_TARGET) -mdll -Wl,--base-file libobjc.base libobjc.exp \
+ -o libobjc.dll libobjc_s.a \
+ objc/libobjc_entry.o -lkernel32
+ $(DLLTOOL) --dllname libobjc.dll --def $(srcdir)/objc/libobjc.def \
+ --base-file libobjc.base --output-exp libobjc.exp
+ $(GCC_FOR_TARGET) libobjc.exp -mdll \
+ -o libobjc.dll libobjc_s.a \
+ objc/libobjc_entry.o -lkernel32
+ $(DLLTOOL) --dllname libobjc.dll --def $(srcdir)/objc/libobjc.def \
+ --output-lib libobjc.a
+
+# Platform generated information needed by ObjC runtime
+objc/runtime-info.h: cc1obj$(exeext)
+ echo "" > tmp-runtime
+ echo "/* This file is automatically generated */" >$@
+ ./cc1obj -print-objc-runtime-info tmp-runtime >>$@
+ rm -f tmp-runtime
+#
+# Build hooks:
+
+objc.all.build:
+objc.all.cross:
+objc.start.encap:
+objc.rest.encap:
+
+objc.info:
+objc.dvi:
+
+#
+# Install hooks:
+# cc1obj is installed elsewhere as part of $(COMPILERS).
+
+objc.install-normal: installdirs
+ -if [ -f libobjc.a ] ; then \
+ rm -f $(libsubdir)/libobjc.a; \
+ $(INSTALL_DATA) libobjc.a $(libsubdir)/libobjc.a; \
+ if $(RANLIB_TEST) ; then \
+ (cd $(libsubdir); $(RANLIB) libobjc.a); else true; fi; \
+ chmod a-x $(libsubdir)/libobjc.a; \
+ else true; fi
+ -if [ -f libobjc_s.a ] ; then \
+ rm -f $(libsubdir)/libobjc_s.a; \
+ $(INSTALL_DATA) libobjc_s.a $(libsubdir)/libobjc_s.a; \
+ if $(RANLIB_TEST) ; then \
+ (cd $(libsubdir); $(RANLIB) libobjc_s.a); else true; fi; \
+ chmod a-x $(libsubdir)/libobjc_s.a; \
+ else true; fi
+ -if [ -f libobjc.dll ] ; then \
+ rm -f $(bindir)/libobjc.dll; \
+ $(INSTALL_DATA) libobjc.dll $(bindir)/libobjc.dll; \
+ else true; fi
+
+objc.install-common:
+
+objc.install-info:
+
+objc.install-man:
+
+objc.uninstall:
+#
+# Clean hooks:
+# A lot of the ancillary files are deleted by the main makefile.
+# We just have to delete files specific to us.
+objc.mostlyclean:
+ -rm -f tmp-objc-prs.y
+ -rm -f objc/*$(objext) objc/xforward objc/fflags
+ -rm -f objc/runtime-info.h
+ -rm -f libobjc.a libobjc_s.a libobjc.dll
+ -rm -f libobjc.base libobjc.exp
+objc.clean: objc.mostlyclean
+ -rm -rf objc-headers
+objc.distclean:
+ -rm -f objc/Makefile objc/Make-host objc/Make-target
+ -rm -f objc/config.status objc/config.cache
+ -rm -f objc-parse.output
+objc.extraclean:
+objc.maintainer-clean:
+ -rm -f objc/objc-parse.y
+ -rm -f objc/objc-parse.c objc/objc-parse.output
+
+#
+# Stage hooks:
+
+objc.stage1: stage1-start
+ -mv objc/*$(objext) stage1/objc
+ -mv cc1obj$(exeext) stage1
+ -mv libobjc.a stage1
+objc.stage2: stage2-start
+ -mv objc/*$(objext) stage2/objc
+ -mv cc1obj$(exeext) stage2
+ -mv libobjc.a stage2
+objc.stage3: stage3-start
+ -mv objc/*$(objext) stage3/objc
+ -mv cc1obj$(exeext) stage3
+ -mv libobjc.a stage3
+objc.stage4: stage4-start
+ -mv objc/*$(objext) stage4/objc
+ -mv cc1obj$(exeext) stage4
+ -mv libobjc.a stage4
+
+#
+# Maintenance hooks:
+
+# This target creates the files that can be rebuilt, but go in the
+# distribution anyway. It then copies the files to the distdir directory.
+# ??? Note that this should be fixed once the Makefile is fixed to do
+# the build in the inner directory.
+objc.distdir: $(srcdir)/objc/objc-parse.c
+ mkdir tmp/objc
+# cd objc ; $(MAKE) $(FLAGS_TO_PASS) objc-parse.c
+ cd objc; \
+ for file in *[0-9a-zA-Z+]; do \
+ ln $$file ../tmp/objc >/dev/null 2>&1 || cp $$file ../tmp/objc; \
+ done
diff --git a/contrib/gcc/objc/Makefile.in b/contrib/gcc/objc/Makefile.in
new file mode 100644
index 0000000..5f1bc88
--- /dev/null
+++ b/contrib/gcc/objc/Makefile.in
@@ -0,0 +1,91 @@
+# GNU Objective C Runtime Makefile
+# Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
+#
+# This file is part of GNU CC.
+#
+# GNU CC 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, or (at your option) any later version.
+#
+# GNU CC 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
+# GNU CC; see the file COPYING. If not, write to the Free Software
+# Foundation, 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# This makefile is run by the parent dir's makefile.
+# thisdir1=`pwd`; \
+# srcdir1=`cd $(srcdir); pwd`; \
+# cd objc; \
+# $(MAKE) $(MAKEFLAGS) -f $$srcdir1/objc/Makefile libobjc.a \
+# srcdir=$$srcdir1 tooldir=$(tooldir) AR="$(AR)" AR_FLAGS="$(AR_FLAGS)" \
+# GCC_FOR_TARGET="$$thisdir1/xgcc -B$$thisdir1/" \
+# GCC_CFLAGS="$(GCC_CFLAGS)" incinstalldir=$$thisdir1/include
+# OBJC_THREAD_FILE="$(OBJC_THREAD_FILE)"
+# Two targets are used by ../Makefile: `all' and `mostlyclean'.
+
+SHELL=/bin/sh
+
+.SUFFIXES: .m
+
+OPTIMIZE= -O
+
+srcdir = .
+VPATH = $(srcdir)
+
+AR = ar
+AR_FLAGS = rc
+
+# Define this as & to perform parallel make on a Sequent.
+# Note that this has some bugs, and it seems currently necessary
+# to compile all the gen* files first by hand to avoid erroneous results.
+P =
+
+# Definition of `all' is here so that new rules inserted by sed
+# do not specify the default target.
+all: all.indirect
+
+# sed inserts variable overrides after the following line.
+####target overrides
+####host overrides
+####cross overrides
+####build overrides
+#
+
+OBJC_H = hash.h objc-list.h sarray.h objc.h objc-api.h \
+ NXConstStr.h Object.h Protocol.h encoding.h typedstream.h thr.h
+
+# Now figure out from those variables how to compile and link.
+all.indirect: Makefile compiler objc-runtime
+
+compiler:
+ cd ..; $(MAKE) cc1obj$(exeext)
+
+objc-runtime:
+ cd ..; $(MAKE) libobjc.a
+
+# copy objc headers to installation include directory
+copy-headers:
+ -rm -fr $(incinstalldir)/objc
+ -mkdir $(incinstalldir)/objc
+ for file in $(OBJC_H); do \
+ realfile=$(srcdir)/$${file}; \
+ cp $${realfile} $(incinstalldir)/objc; \
+ chmod a+r $(incinstalldir)/objc/$${file}; \
+ done
+
+Makefile: $(srcdir)/Makefile.in $(srcdir)/../configure
+ cd ..; $(SHELL) config.status
+
+mostlyclean:
+ -rm -f *.o libobjc.a xforward fflags
+clean: mostlyclean
+distclean: mostlyclean
+extraclean: mostlyclean
+
+# For Sun VPATH.
+
diff --git a/contrib/gcc/objc/NXConstStr.h b/contrib/gcc/objc/NXConstStr.h
index 6899c74..c979954 100644
--- a/contrib/gcc/objc/NXConstStr.h
+++ b/contrib/gcc/objc/NXConstStr.h
@@ -11,7 +11,7 @@ later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+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
@@ -19,6 +19,12 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+/* As a special exception, if you link this library with files
+ compiled with GCC to produce an executable, this does not cause
+ the resulting executable to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
#ifndef __nxconstantstring_INCLUDE_GNU
#define __nxconstantstring_INCLUDE_GNU
diff --git a/contrib/gcc/objc/NXConstStr.m b/contrib/gcc/objc/NXConstStr.m
index d3b2117..4d2f3e1 100644
--- a/contrib/gcc/objc/NXConstStr.m
+++ b/contrib/gcc/objc/NXConstStr.m
@@ -11,7 +11,7 @@ later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+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
@@ -19,6 +19,12 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+/* As a special exception, if you link this library with files
+ compiled with GCC to produce an executable, this does not cause
+ the resulting executable to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
#include "objc/NXConstStr.h"
@implementation NXConstantString
diff --git a/contrib/gcc/objc/Object.h b/contrib/gcc/objc/Object.h
index 7fb8602..a762acc 100644
--- a/contrib/gcc/objc/Object.h
+++ b/contrib/gcc/objc/Object.h
@@ -10,7 +10,7 @@ later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+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
diff --git a/contrib/gcc/objc/Object.m b/contrib/gcc/objc/Object.m
index 518d02a..64b52f4 100644
--- a/contrib/gcc/objc/Object.m
+++ b/contrib/gcc/objc/Object.m
@@ -1,5 +1,5 @@
/* The implementation of class Object for Objective-C.
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1994, 1995, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -10,7 +10,7 @@ later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+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
@@ -29,8 +29,6 @@ Boston, MA 02111-1307, USA. */
#include "objc/Protocol.h"
#include "objc/objc-api.h"
-extern void (*_objc_error)(id object, const char *format, va_list);
-
extern int errno;
#define MAX_CLASS_NAME_LEN 256
@@ -215,7 +213,7 @@ extern int errno;
}
}
- if (parent = [self superClass])
+ if ((parent = [self superClass]))
return [parent conformsTo: aProtocol];
else
return NO;
@@ -337,7 +335,7 @@ extern size_t strlen(const char*);
object_is_instance(self)?"instance":"class",
(aString!=NULL)?aString:"");
va_start(ap, aString);
- (*_objc_error)(self, fmt, ap);
+ objc_verror(self, OBJC_ERR_UNKNOWN, fmt, ap);
va_end(ap);
return nil;
#undef FMT
diff --git a/contrib/gcc/objc/README b/contrib/gcc/objc/README
index 70cea30..f478d67 100644
--- a/contrib/gcc/objc/README
+++ b/contrib/gcc/objc/README
@@ -18,7 +18,7 @@ Runtime API functions
The runtime is modeled after the NeXT Objective C runtime. That is,
most functions have semantics as it is known from the NeXT. The
names, however, have changed. All runtime API functions have names
-of lowercase letters and and underscores as opposed to the
+of lowercase letters and underscores as opposed to the
`traditional' mixed case names.
The runtime api functions are not documented as of now.
Someone offered to write it, and did it, but we were not allowed to
diff --git a/contrib/gcc/objc/archive.c b/contrib/gcc/objc/archive.c
index 0d55152..c762fe6 100644
--- a/contrib/gcc/objc/archive.c
+++ b/contrib/gcc/objc/archive.c
@@ -1,5 +1,5 @@
/* GNU Objective C Runtime archiving
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
@@ -24,10 +24,15 @@ Boston, MA 02111-1307, USA. */
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
+#include "config.h"
#include "runtime.h"
#include "typedstream.h"
#include "encoding.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
extern int fflush(FILE*);
#define ROUND(V, A) \
@@ -37,11 +42,6 @@ extern int fflush(FILE*);
#define PTR2LONG(P) (((char*)(P))-(char*)0)
#define LONG2PTR(L) (((char*)0)+(L))
-#define __objc_fatal(format, args...) \
- { fprintf(stderr, "archiving: "); \
- fprintf(stderr, format, ## args); \
- fprintf(stderr, "\n"); abort(); }
-
/* Declare some functions... */
static int
@@ -141,7 +141,8 @@ __objc_code_unsigned_short (unsigned char* buf, unsigned short val)
}
int
-objc_write_unsigned_short (struct objc_typed_stream* stream, unsigned short value)
+objc_write_unsigned_short (struct objc_typed_stream* stream,
+ unsigned short value)
{
unsigned char buf[sizeof (unsigned short)+1];
int len = __objc_code_unsigned_short (buf, value);
@@ -252,7 +253,8 @@ __objc_code_unsigned_long (unsigned char* buf, unsigned long val)
}
int
-objc_write_unsigned_long (struct objc_typed_stream* stream, unsigned long value)
+objc_write_unsigned_long (struct objc_typed_stream* stream,
+ unsigned long value)
{
unsigned char buf[sizeof(unsigned long)+1];
int len = __objc_code_unsigned_long (buf, value);
@@ -315,7 +317,8 @@ objc_write_string_atomic (struct objc_typed_stream* stream,
}
static int
-objc_write_register_common (struct objc_typed_stream* stream, unsigned long key)
+objc_write_register_common (struct objc_typed_stream* stream,
+ unsigned long key)
{
unsigned char buf[sizeof (unsigned long)+2];
int len = __objc_code_unsigned_long (buf+1, key);
@@ -359,7 +362,11 @@ __objc_write_extension (struct objc_typed_stream* stream, unsigned char code)
return (*stream->write)(stream->physical, &buf, 1);
}
else
- abort();
+ {
+ objc_error(nil, OBJC_ERR_BAD_OPCODE,
+ "__objc_write_extension: bad opcode %c\n", code);
+ return -1;
+ }
}
__inline__ int
@@ -392,9 +399,10 @@ objc_write_object_reference (struct objc_typed_stream* stream, id object)
int
objc_write_root_object (struct objc_typed_stream* stream, id object)
{
- int len;
+ int len = 0;
if (stream->writing_root_p)
- __objc_fatal ("objc_write_root_object called recursively")
+ objc_error (nil, OBJC_ERR_RECURSE_ROOT,
+ "objc_write_root_object called recursively");
else
{
stream->writing_root_p = 1;
@@ -426,12 +434,6 @@ objc_write_object (struct objc_typed_stream* stream, id object)
}
}
-#ifdef __alpha__
-extern int atoi (const char*);
-extern size_t strlen(const char*);
-extern size_t strcpy(char*, const char*);
-#endif
-
__inline__ int
__objc_write_class (struct objc_typed_stream* stream, struct objc_class* class)
{
@@ -488,7 +490,8 @@ objc_write_selector (struct objc_typed_stream* stream, SEL selector)
else
{
int length;
- hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(sel_name)), (char*)sel_name);
+ hash_add (&stream->stream_table,
+ LONG2PTR(key=PTR2LONG(sel_name)), (char*)sel_name);
if ((length = objc_write_register_common (stream, key)))
return __objc_write_selector (stream, selector);
return length;
@@ -520,8 +523,9 @@ objc_read_char (struct objc_typed_stream* stream, char* val)
}
else
- __objc_fatal("expected 8bit signed int, got %dbit int",
- (int)(buf&_B_NUMBER)*8);
+ objc_error(nil, OBJC_ERR_BAD_DATA,
+ "expected 8bit signed int, got %dbit int",
+ (int)(buf&_B_NUMBER)*8);
}
return len;
}
@@ -541,8 +545,9 @@ objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val)
len = (*stream->read)(stream->physical, val, 1);
else
- __objc_fatal("expected 8bit unsigned int, got %dbit int",
- (int)(buf&_B_NUMBER)*8);
+ objc_error(nil, OBJC_ERR_BAD_DATA,
+ "expected 8bit unsigned int, got %dbit int",
+ (int)(buf&_B_NUMBER)*8);
}
return len;
}
@@ -562,7 +567,8 @@ objc_read_short (struct objc_typed_stream* stream, short* value)
int pos = 1;
int nbytes = buf[0] & _B_NUMBER;
if (nbytes > sizeof (short))
- __objc_fatal("expected short, got bigger (%dbits)", nbytes*8);
+ objc_error(nil, OBJC_ERR_BAD_DATA,
+ "expected short, got bigger (%dbits)", nbytes*8);
len = (*stream->read)(stream->physical, buf+1, nbytes);
(*value) = 0;
while (pos <= nbytes)
@@ -590,7 +596,8 @@ objc_read_unsigned_short (struct objc_typed_stream* stream,
int pos = 1;
int nbytes = buf[0] & _B_NUMBER;
if (nbytes > sizeof (short))
- __objc_fatal("expected short, got int or bigger");
+ objc_error(nil, OBJC_ERR_BAD_DATA,
+ "expected short, got int or bigger");
len = (*stream->read)(stream->physical, buf+1, nbytes);
(*value) = 0;
while (pos <= nbytes)
@@ -616,7 +623,7 @@ objc_read_int (struct objc_typed_stream* stream, int* value)
int pos = 1;
int nbytes = buf[0] & _B_NUMBER;
if (nbytes > sizeof (int))
- __objc_fatal("expected int, got bigger");
+ objc_error(nil, OBJC_ERR_BAD_DATA, "expected int, got bigger");
len = (*stream->read)(stream->physical, buf+1, nbytes);
(*value) = 0;
while (pos <= nbytes)
@@ -643,7 +650,7 @@ objc_read_long (struct objc_typed_stream* stream, long* value)
int pos = 1;
int nbytes = buf[0] & _B_NUMBER;
if (nbytes > sizeof (long))
- __objc_fatal("expected long, got bigger");
+ objc_error(nil, OBJC_ERR_BAD_DATA, "expected long, got bigger");
len = (*stream->read)(stream->physical, buf+1, nbytes);
(*value) = 0;
while (pos <= nbytes)
@@ -663,7 +670,7 @@ __objc_read_nbyte_uint (struct objc_typed_stream* stream,
unsigned char buf[sizeof(unsigned int)+1];
if (nbytes > sizeof (int))
- __objc_fatal("expected int, got bigger");
+ objc_error(nil, OBJC_ERR_BAD_DATA, "expected int, got bigger");
len = (*stream->read)(stream->physical, buf, nbytes);
(*val) = 0;
@@ -699,7 +706,7 @@ __objc_read_nbyte_ulong (struct objc_typed_stream* stream,
unsigned char buf[sizeof(unsigned long)+1];
if (nbytes > sizeof (long))
- __objc_fatal("expected long, got bigger");
+ objc_error(nil, OBJC_ERR_BAD_DATA, "expected long, got bigger");
len = (*stream->read)(stream->physical, buf, nbytes);
(*val) = 0;
@@ -747,7 +754,7 @@ objc_read_string (struct objc_typed_stream* stream,
case _B_SSTR:
{
int length = buf[0]&_B_VALUE;
- (*string) = (char*)__objc_xmalloc(length+1);
+ (*string) = (char*)objc_malloc(length+1);
if (key)
hash_add (&stream->stream_table, LONG2PTR(key), *string);
len = (*stream->read)(stream->physical, *string, length);
@@ -760,7 +767,7 @@ objc_read_string (struct objc_typed_stream* stream,
char *tmp;
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
tmp = hash_value_for_key (stream->stream_table, LONG2PTR (key));
- *string = __objc_xmalloc (strlen(tmp) + 1);
+ *string = objc_malloc (strlen(tmp) + 1);
strcpy (*string, tmp);
}
break;
@@ -770,7 +777,7 @@ objc_read_string (struct objc_typed_stream* stream,
unsigned int nbytes = buf[0]&_B_VALUE;
len = __objc_read_nbyte_uint(stream, nbytes, &nbytes);
if (len) {
- (*string) = (char*)__objc_xmalloc(nbytes+1);
+ (*string) = (char*)objc_malloc(nbytes+1);
if (key)
hash_add (&stream->stream_table, LONG2PTR(key), *string);
len = (*stream->read)(stream->physical, *string, nbytes);
@@ -780,7 +787,8 @@ objc_read_string (struct objc_typed_stream* stream,
break;
default:
- __objc_fatal("expected string, got opcode %c\n", (buf[0]&_B_CODE));
+ objc_error(nil, OBJC_ERR_BAD_DATA,
+ "expected string, got opcode %c\n", (buf[0]&_B_CODE));
}
}
@@ -825,13 +833,14 @@ objc_read_object (struct objc_typed_stream* stream, id* object)
/* check null-byte */
len = (*stream->read)(stream->physical, buf, 1);
if (buf[0] != '\0')
- __objc_fatal("expected null-byte, got opcode %c", buf[0]);
+ objc_error(nil, OBJC_ERR_BAD_DATA,
+ "expected null-byte, got opcode %c", buf[0]);
}
else if ((buf[0]&_B_CODE) == _B_UCOMM)
{
if (key)
- __objc_fatal("cannot register use upcode...");
+ objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
(*object) = hash_value_for_key (stream->object_table, LONG2PTR(key));
}
@@ -840,20 +849,24 @@ objc_read_object (struct objc_typed_stream* stream, id* object)
{
struct objc_list* other;
len = objc_read_unsigned_long (stream, &key);
- other = (struct objc_list*)hash_value_for_key (stream->object_refs, LONG2PTR(key));
- hash_add (&stream->object_refs, LONG2PTR(key), (void*)list_cons(object, other));
+ other = (struct objc_list*)hash_value_for_key (stream->object_refs,
+ LONG2PTR(key));
+ hash_add (&stream->object_refs, LONG2PTR(key),
+ (void*)list_cons(object, other));
}
else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
{
if (key)
- __objc_fatal("cannot register root object...");
+ objc_error(nil, OBJC_ERR_BAD_KEY,
+ "cannot register root object...");
len = objc_read_object (stream, object);
__objc_finish_read_root_object (stream);
}
else
- __objc_fatal("expected object, got opcode %c", buf[0]);
+ objc_error(nil, OBJC_ERR_BAD_DATA,
+ "expected object, got opcode %c", buf[0]);
}
return len;
}
@@ -881,7 +894,7 @@ objc_read_class (struct objc_typed_stream* stream, Class* class)
/* get class */
len = objc_read_string (stream, &class_name);
(*class) = objc_get_class(class_name);
- free (class_name);
+ objc_free(class_name);
/* register */
if (key)
@@ -894,15 +907,17 @@ objc_read_class (struct objc_typed_stream* stream, Class* class)
else if ((buf[0]&_B_CODE) == _B_UCOMM)
{
if (key)
- __objc_fatal("cannot register use upcode...");
+ objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
(*class) = hash_value_for_key (stream->stream_table, LONG2PTR(key));
if (!*class)
- __objc_fatal("cannot find class for key %lu", key);
+ objc_error(nil, OBJC_ERR_BAD_CLASS,
+ "cannot find class for key %lu", key);
}
else
- __objc_fatal("expected class, got opcode %c", buf[0]);
+ objc_error(nil, OBJC_ERR_BAD_DATA,
+ "expected class, got opcode %c", buf[0]);
}
return len;
}
@@ -936,7 +951,7 @@ objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
}
else
(*selector) = sel_get_any_uid(selector_name);
- free (selector_name);
+ objc_free(selector_name);
/* register */
if (key)
@@ -946,13 +961,15 @@ objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
else if ((buf[0]&_B_CODE) == _B_UCOMM)
{
if (key)
- __objc_fatal("cannot register use upcode...");
+ objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode...");
len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key);
- (*selector) = hash_value_for_key (stream->stream_table, LONG2PTR(key));
+ (*selector) = hash_value_for_key (stream->stream_table,
+ LONG2PTR(key));
}
else
- __objc_fatal("expected selector, got opcode %c", buf[0]);
+ objc_error(nil, OBJC_ERR_BAD_DATA,
+ "expected selector, got opcode %c", buf[0]);
}
return len;
}
@@ -1019,13 +1036,15 @@ objc_write_type(TypedStream* stream, const char* type, const void* data)
break;
case _C_ATOM:
- return objc_write_string_atomic (stream, *(char**)data, strlen(*(char**)data));
+ return objc_write_string_atomic (stream, *(char**)data,
+ strlen(*(char**)data));
break;
case _C_ARY_B:
{
int len = atoi(type+1);
- while (isdigit(*++type));
+ while (isdigit(*++type))
+ ;
return objc_write_array (stream, type, len, data);
}
break;
@@ -1034,8 +1053,9 @@ objc_write_type(TypedStream* stream, const char* type, const void* data)
{
int acc_size = 0;
int align;
- while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
- while (*type != _C_STRUCT_E);
+ while (*type != _C_STRUCT_E && *type++ != '=')
+ ; /* skip "<name>=" */
+ while (*type != _C_STRUCT_E)
{
align = objc_alignof_type (type); /* padd to alignment */
acc_size += ROUND (acc_size, align);
@@ -1047,8 +1067,11 @@ objc_write_type(TypedStream* stream, const char* type, const void* data)
}
default:
- fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
- abort();
+ {
+ objc_error(nil, OBJC_ERR_BAD_TYPE,
+ "objc_write_type: cannot parse typespec: %s\n", type);
+ return 0;
+ }
}
}
@@ -1116,7 +1139,8 @@ objc_read_type(TypedStream* stream, const char* type, void* data)
case _C_ARY_B:
{
int len = atoi(type+1);
- while (isdigit(*++type));
+ while (isdigit(*++type))
+ ;
return objc_read_array (stream, type, len, data);
}
break;
@@ -1125,8 +1149,9 @@ objc_read_type(TypedStream* stream, const char* type, void* data)
{
int acc_size = 0;
int align;
- while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
- while (*type != _C_STRUCT_E);
+ while (*type != _C_STRUCT_E && *type++ != '=')
+ ; /* skip "<name>=" */
+ while (*type != _C_STRUCT_E)
{
align = objc_alignof_type (type); /* padd to alignment */
acc_size += ROUND (acc_size, align);
@@ -1138,8 +1163,11 @@ objc_read_type(TypedStream* stream, const char* type, void* data)
}
default:
- fprintf(stderr, "objc_read_type: cannot parse typespec: %s\n", type);
- abort();
+ {
+ objc_error(nil, OBJC_ERR_BAD_TYPE,
+ "objc_read_type: cannot parse typespec: %s\n", type);
+ return 0;
+ }
}
}
@@ -1229,17 +1257,18 @@ objc_write_types (TypedStream* stream, const char* type, ...)
{
int len = atoi(c+1);
const char* t = c;
- while (isdigit(*++t));
+ while (isdigit(*++t))
+ ;
res = objc_write_array (stream, t, len, va_arg(args, void*));
t = objc_skip_typespec (t);
if (*t != _C_ARY_E)
- __objc_fatal("expected `]', got: %s", t);
+ objc_error(nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t);
}
break;
default:
- fprintf(stderr, "objc_write_types: cannot parse typespec: %s\n", type);
- abort();
+ objc_error(nil, OBJC_ERR_BAD_TYPE,
+ "objc_write_types: cannot parse typespec: %s\n", type);
}
}
va_end(args);
@@ -1320,17 +1349,18 @@ objc_read_types(TypedStream* stream, const char* type, ...)
{
int len = atoi(c+1);
const char* t = c;
- while (isdigit(*++t));
+ while (isdigit(*++t))
+ ;
res = objc_read_array (stream, t, len, va_arg(args, void*));
t = objc_skip_typespec (t);
if (*t != _C_ARY_E)
- __objc_fatal("expected `]', got: %s", t);
+ objc_error(nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t);
}
break;
default:
- fprintf(stderr, "objc_read_types: cannot parse typespec: %s\n", type);
- abort();
+ objc_error(nil, OBJC_ERR_BAD_TYPE,
+ "objc_read_types: cannot parse typespec: %s\n", type);
}
}
va_end(args);
@@ -1379,12 +1409,6 @@ objc_read_array (TypedStream* stream, const char* type,
return 1;
}
-static void
-__objc_free (void* p)
-{
- free (p);
-}
-
static int
__objc_fread(FILE* file, char* data, int len)
{
@@ -1406,13 +1430,15 @@ __objc_feof(FILE* file)
static int
__objc_no_write(FILE* file, char* data, int len)
{
- __objc_fatal ("TypedStream not open for writing");
+ objc_error (nil, OBJC_ERR_NO_WRITE, "TypedStream not open for writing");
+ return 0;
}
static int
__objc_no_read(FILE* file, char* data, int len)
{
- __objc_fatal ("TypedStream not open for reading");
+ objc_error (nil, OBJC_ERR_NO_READ, "TypedStream not open for reading");
+ return 0;
}
static int
@@ -1422,10 +1448,12 @@ __objc_read_typed_stream_signature (TypedStream* stream)
int pos = 0;
do
(*stream->read)(stream->physical, buffer+pos, 1);
- while (buffer[pos++] != '\0');
+ while (buffer[pos++] != '\0')
+ ;
sscanf (buffer, "GNU TypedStream %d", &stream->version);
if (stream->version != OBJC_TYPED_STREAM_VERSION)
- __objc_fatal ("cannot handle TypedStream version %d", stream->version);
+ objc_error (nil, OBJC_ERR_STREAM_VERSION,
+ "cannot handle TypedStream version %d", stream->version);
return 1;
}
@@ -1450,11 +1478,12 @@ static void __objc_finish_write_root_object(struct objc_typed_stream* stream)
static void __objc_finish_read_root_object(struct objc_typed_stream* stream)
{
node_ptr node;
- struct objc_list* free_list;
SEL awake_sel = sel_get_any_uid ("awake");
+ cache_ptr free_list = hash_new (64,
+ (hash_func_type) hash_ptr,
+ (compare_func_type) compare_ptrs);
/* resolve object forward references */
- free_list = list_cons(NULL, NULL);
for (node = hash_next (stream->object_refs, NULL); node;
node = hash_next (stream->object_refs, node))
{
@@ -1464,13 +1493,19 @@ static void __objc_finish_read_root_object(struct objc_typed_stream* stream)
while(reflist)
{
*((id*)reflist->head) = object;
- if (list_find(&free_list, reflist) == NULL)
- free_list = list_cons (reflist, free_list);
+ if (hash_value_for_key (free_list,reflist) == NULL)
+ hash_add (&free_list,reflist,reflist);
+
reflist = reflist->tail;
}
}
- list_mapcar (free_list, __objc_free);
- list_free (free_list);
+
+ /* apply __objc_free to all objects stored in free_list */
+ for (node = hash_next (free_list, NULL); node;
+ node = hash_next (free_list, node))
+ objc_free ((void *) node->key);
+
+ hash_delete (free_list);
/* empty object reference table */
hash_delete (stream->object_refs);
@@ -1503,7 +1538,7 @@ static void __objc_finish_read_root_object(struct objc_typed_stream* stream)
TypedStream*
objc_open_typed_stream (FILE* physical, int mode)
{
- TypedStream* s = (TypedStream*)__objc_xmalloc(sizeof(TypedStream));
+ TypedStream* s = (TypedStream*)objc_malloc(sizeof(TypedStream));
s->mode = mode;
s->physical = physical;
@@ -1590,7 +1625,7 @@ objc_close_typed_stream (TypedStream* stream)
if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
fclose ((FILE*)stream->physical);
- free (stream);
+ objc_free(stream);
}
BOOL
diff --git a/contrib/gcc/objc/class.c b/contrib/gcc/objc/class.c
index 3617a09..44aa1b9 100644
--- a/contrib/gcc/objc/class.c
+++ b/contrib/gcc/objc/class.c
@@ -1,5 +1,5 @@
/* GNU Objective C Runtime class related functions
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup and Dennis Glatting.
This file is part of GNU CC.
@@ -27,16 +27,16 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "sarray.h"
/* The table of classname->class. Used for objc_lookup_class and friends */
-static cache_ptr __objc_class_hash = 0;
+static cache_ptr __objc_class_hash = 0; /* !T:MUTEX */
/* This is a hook which is called by objc_get_class and
objc_lookup_class if the runtime is not able to find the class.
This may e.g. try to load in the class using dynamic loading */
-Class (*_objc_lookup_class)(const char* name) = 0;
+Class (*_objc_lookup_class)(const char* name) = 0; /* !T:SAFE */
/* True when class links has been resolved */
-BOOL __objc_class_links_resolved = NO;
+BOOL __objc_class_links_resolved = NO; /* !T:UNUSED */
/* Initial number of buckets size of class hash table. */
@@ -49,10 +49,14 @@ void __objc_init_class_tables()
if(__objc_class_hash)
return;
+ objc_mutex_lock(__objc_runtime_mutex);
+
__objc_class_hash
= hash_new (CLASS_HASH_SIZE,
(hash_func_type) hash_string,
(compare_func_type) compare_strings);
+
+ objc_mutex_unlock(__objc_runtime_mutex);
}
/* This function adds a class to the class hash table, and assigns the
@@ -62,6 +66,8 @@ __objc_add_class_to_hash(Class class)
{
Class h_class;
+ objc_mutex_lock(__objc_runtime_mutex);
+
/* make sure the table is there */
assert(__objc_class_hash);
@@ -82,6 +88,8 @@ __objc_add_class_to_hash(Class class)
++class_number;
hash_add (&__objc_class_hash, class->name, class);
}
+
+ objc_mutex_unlock(__objc_runtime_mutex);
}
/* Get the class object for the class named NAME. If NAME does not
@@ -91,11 +99,15 @@ Class objc_lookup_class (const char* name)
{
Class class;
+ objc_mutex_lock(__objc_runtime_mutex);
+
/* Make sure the class hash table exists. */
assert (__objc_class_hash);
class = hash_value_for_key (__objc_class_hash, name);
+ objc_mutex_unlock(__objc_runtime_mutex);
+
if (class)
return class;
@@ -113,11 +125,15 @@ objc_get_class (const char *name)
{
Class class;
+ objc_mutex_lock(__objc_runtime_mutex);
+
/* Make sure the class hash table exists. */
assert (__objc_class_hash);
class = hash_value_for_key (__objc_class_hash, name);
+ objc_mutex_unlock(__objc_runtime_mutex);
+
if (class)
return class;
@@ -127,8 +143,9 @@ objc_get_class (const char *name)
if(class)
return class;
- fprintf(stderr, "objc runtime: cannot find class %s\n", name);
- abort();
+ objc_error(nil, OBJC_ERR_BAD_CLASS,
+ "objc runtime: cannot find class %s\n", name);
+ return 0;
}
MetaClass
@@ -149,11 +166,16 @@ objc_get_meta_class(const char *name)
Class
objc_next_class(void **enum_state)
{
+ objc_mutex_lock(__objc_runtime_mutex);
+
/* make sure the table is there */
assert(__objc_class_hash);
*(node_ptr*)enum_state =
hash_next(__objc_class_hash, *(node_ptr*)enum_state);
+
+ objc_mutex_unlock(__objc_runtime_mutex);
+
if (*(node_ptr*)enum_state)
return (*(node_ptr*)enum_state)->value;
return (Class)0;
@@ -169,6 +191,8 @@ void __objc_resolve_class_links()
assert(object_class);
+ objc_mutex_lock(__objc_runtime_mutex);
+
/* Assign subclass links */
for (node = hash_next (__objc_class_hash, NULL); node;
node = hash_next (__objc_class_hash, node))
@@ -234,6 +258,8 @@ void __objc_resolve_class_links()
sub_class->class_pointer->super_class = class1->class_pointer;
}
}
+
+ objc_mutex_unlock(__objc_runtime_mutex);
}
@@ -281,7 +307,8 @@ class_pose_as (Class impostor, Class super_class)
if (CLS_ISCLASS (sub))
{
/* meta classes */
- CLASSOF (sub)->sibling_class = CLASSOF (impostor)->subclass_list;
+ CLASSOF (sub)->sibling_class =
+ CLASSOF (impostor)->subclass_list;
CLASSOF (sub)->super_class = CLASSOF (impostor);
CLASSOF (impostor)->subclass_list = CLASSOF (sub);
}
@@ -307,6 +334,8 @@ class_pose_as (Class impostor, Class super_class)
what the keys of the hashtable is, change all values that are
superclass into impostor. */
+ objc_mutex_lock(__objc_runtime_mutex);
+
for (node = hash_next (__objc_class_hash, NULL); node;
node = hash_next (__objc_class_hash, node))
{
@@ -317,6 +346,8 @@ class_pose_as (Class impostor, Class super_class)
}
}
+ objc_mutex_unlock(__objc_runtime_mutex);
+
/* next, we update the dispatch tables... */
__objc_update_dispatch_table_for_class (CLASSOF (impostor));
__objc_update_dispatch_table_for_class (impostor);
diff --git a/contrib/gcc/objc/config-lang.in b/contrib/gcc/objc/config-lang.in
new file mode 100644
index 0000000..6c9b203
--- /dev/null
+++ b/contrib/gcc/objc/config-lang.in
@@ -0,0 +1,37 @@
+# Top level configure fragment for the GNU Objective-C Runtime Library.
+# Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+#This file is part of GNU CC.
+
+#GNU CC 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, or (at your option)
+#any later version.
+
+#GNU CC 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 GNU CC; see the file COPYING. If not, write to
+#the Free Software Foundation, 59 Temple Place - Suite 330,
+#Boston, MA 02111-1307, USA.
+
+# Configure looks for the existence of this file to auto-config each language.
+# We define several parameters used by configure:
+#
+# language - name of language as it would appear in $(LANGUAGES)
+# compilers - value to add to $(COMPILERS)
+# stagestuff - files to add to $(STAGESTUFF)
+# diff_excludes - files to ignore when building diffs between two versions.
+
+language="objc"
+
+compilers="cc1obj\$(exeext)"
+
+stagestuff=""
+
+diff_excludes="-x objc-parse.c -x objc-parse.y "
+
+echo "Using \`$srcdir/objc/thr-${thread_file}.c' as Objective-C Runtime thread file."
diff --git a/contrib/gcc/objc/encoding.c b/contrib/gcc/objc/encoding.c
index 9620664..e6f84aa 100644
--- a/contrib/gcc/objc/encoding.c
+++ b/contrib/gcc/objc/encoding.c
@@ -1,5 +1,5 @@
/* Encoding of types for Objective C.
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
@@ -111,6 +111,9 @@ objc_sizeof_type(const char* type)
return sizeof(double);
break;
+ case _C_VOID:
+ return sizeof(void);
+ break;
case _C_PTR:
case _C_ATOM:
case _C_CHARPTR:
@@ -153,7 +156,10 @@ objc_sizeof_type(const char* type)
}
default:
- abort();
+ {
+ objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type);
+ return 0;
+ }
}
}
@@ -218,6 +224,7 @@ objc_alignof_type(const char* type)
return __alignof__(double);
break;
+ case _C_PTR:
case _C_ATOM:
case _C_CHARPTR:
return __alignof__(char*);
@@ -250,7 +257,10 @@ objc_alignof_type(const char* type)
}
default:
- abort();
+ {
+ objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type);
+ return 0;
+ }
}
}
@@ -341,6 +351,7 @@ objc_skip_typespec (const char* type)
case _C_FLT:
case _C_DBL:
case _C_VOID:
+ case _C_UNDEF:
return ++type;
break;
@@ -352,7 +363,10 @@ objc_skip_typespec (const char* type)
if (*type == _C_ARY_E)
return ++type;
else
- abort();
+ {
+ objc_error(nil, OBJC_ERR_BAD_TYPE, "bad array type %s\n", type);
+ return 0;
+ }
case _C_STRUCT_B:
/* skip name, and elements until closing '}' */
@@ -374,7 +388,10 @@ objc_skip_typespec (const char* type)
return objc_skip_typespec (++type);
default:
- abort();
+ {
+ objc_error(nil, OBJC_ERR_BAD_TYPE, "unknown type %s\n", type);
+ return 0;
+ }
}
}
diff --git a/contrib/gcc/objc/encoding.h b/contrib/gcc/objc/encoding.h
index c956034..141e9fe 100644
--- a/contrib/gcc/objc/encoding.h
+++ b/contrib/gcc/objc/encoding.h
@@ -1,5 +1,5 @@
/* Encoding of types for Objective C.
- Copyright (C) 1993 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1997 Free Software Foundation, Inc.
Author: Kresten Krab Thorup
@@ -57,7 +57,7 @@ const char* objc_skip_typespec (const char* type);
const char* objc_skip_offset (const char* type);
const char* objc_skip_argspec (const char* type);
int method_get_number_of_arguments (struct objc_method*);
-int method_get_size_of_arguments (struct objc_method*);
+int method_get_sizeof_arguments (struct objc_method*);
char* method_get_first_argument (struct objc_method*,
arglist_t argframe,
diff --git a/contrib/gcc/objc/hash.c b/contrib/gcc/objc/hash.c
index a307759..7534330 100644
--- a/contrib/gcc/objc/hash.c
+++ b/contrib/gcc/objc/hash.c
@@ -1,5 +1,5 @@
/* Hash tables for Objective C internal structures
- Copyright (C) 1993 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1996, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -27,7 +27,6 @@ Boston, MA 02111-1307, USA. */
#include "assert.h"
#include "objc/hash.h"
-#include "objc/objc.h"
#include "runtime.h" /* for DEBUG_PRINTF */
@@ -40,8 +39,6 @@ Boston, MA 02111-1307, USA. */
#define EXPANSION(cache) \
((cache)->size * 2)
-void *__objc_xcalloc (size_t, size_t);
-
cache_ptr
hash_new (unsigned int size, hash_func_type hash_func,
compare_func_type compare_func)
@@ -54,13 +51,13 @@ hash_new (unsigned int size, hash_func_type hash_func,
/* Allocate the cache structure. calloc insures
its initialization for default values. */
- cache = (cache_ptr) __objc_xcalloc (1, sizeof (struct cache));
+ cache = (cache_ptr) objc_calloc (1, sizeof (struct cache));
assert (cache);
/* Allocate the array of buckets for the cache.
calloc initializes all of the pointers to NULL. */
cache->node_table
- = (node_ptr *) __objc_xcalloc (size, sizeof (node_ptr));
+ = (node_ptr *) objc_calloc (size, sizeof (node_ptr));
assert (cache->node_table);
cache->size = size;
@@ -83,15 +80,28 @@ void
hash_delete (cache_ptr cache)
{
node_ptr node;
-
+ node_ptr next_node;
+ unsigned int i;
/* Purge all key/value pairs from the table. */
- while ((node = hash_next (cache, NULL)))
- hash_remove (cache, node->key);
+ /* Step through the nodes one by one and remove every node WITHOUT
+ using hash_next. this makes hash_delete much more efficient. */
+ for (i = 0;i < cache->size;i++) {
+ if ((node = cache->node_table[i])) {
+ /* an entry in the hash table has been found, now step through the
+ nodes next in the list and free them. */
+ while ((next_node = node->next)) {
+ hash_remove (cache,node->key);
+ node = next_node;
+ }
+
+ hash_remove (cache,node->key);
+ }
+ }
/* Release the array of nodes and the cache itself. */
- free (cache->node_table);
- free (cache);
+ objc_free(cache->node_table);
+ objc_free(cache);
}
@@ -99,7 +109,7 @@ void
hash_add (cache_ptr *cachep, const void *key, void *value)
{
size_t indx = (*(*cachep)->hash_func)(*cachep, key);
- node_ptr node = (node_ptr) __objc_xcalloc (1, sizeof (struct cache_node));
+ node_ptr node = (node_ptr) objc_calloc (1, sizeof (struct cache_node));
assert (node);
@@ -172,7 +182,7 @@ hash_remove (cache_ptr cache, const void *key)
/* Special case. First element is the key/value pair to be removed. */
if ((*cache->compare_func)(node->key, key)) {
cache->node_table[indx] = node->next;
- free (node);
+ objc_free(node);
} else {
/* Otherwise, find the hash entry. */
@@ -183,7 +193,7 @@ hash_remove (cache_ptr cache, const void *key)
if ((*cache->compare_func)(node->key, key)) {
prev->next = node->next, removed = YES;
- free (node);
+ objc_free(node);
} else
prev = node, node = node->next;
} while (!removed && node);
@@ -252,3 +262,22 @@ hash_value_for_key (cache_ptr cache, const void *key)
return retval;
}
+
+/* Given KEY, return YES if it exists in the CACHE.
+ Return NO if it does not */
+
+BOOL
+hash_is_key_in_hash (cache_ptr cache, const void *key)
+{
+ node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)];
+
+ if (node)
+ do {
+ if ((*cache->compare_func)(node->key, key))
+ return YES;
+ else
+ node = node->next;
+ } while (node);
+
+ return NO;
+}
diff --git a/contrib/gcc/objc/hash.h b/contrib/gcc/objc/hash.h
index 7a83b08..bddb791 100644
--- a/contrib/gcc/objc/hash.h
+++ b/contrib/gcc/objc/hash.h
@@ -1,5 +1,5 @@
/* Hash tables for Objective C method dispatch.
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -29,6 +29,7 @@ Boston, MA 02111-1307, USA. */
#define __hash_INCLUDE_GNU
#include <stddef.h>
+#include <objc/objc.h>
/*
* This data structure is used to hold items
@@ -140,6 +141,9 @@ node_ptr hash_next (cache_ptr cache, node_ptr node);
void *hash_value_for_key (cache_ptr cache, const void *key);
+/* Used to determine if the given key exists in the hash table */
+
+BOOL hash_is_key_in_hash (cache_ptr cache, const void *key);
/************************************************
diff --git a/contrib/gcc/objc/init.c b/contrib/gcc/objc/init.c
index 9560dc2..f1fea81 100644
--- a/contrib/gcc/objc/init.c
+++ b/contrib/gcc/objc/init.c
@@ -1,6 +1,7 @@
/* GNU Objective C Runtime initialization
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
+ +load support contributed by Ovidiu Predescu <ovidiu@net-community.com>
This file is part of GNU CC.
@@ -27,17 +28,23 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* The version number of this runtime. This must match the number
defined in gcc (objc-act.c) */
-#define OBJC_VERSION 7
+#define OBJC_VERSION 8
#define PROTOCOL_VERSION 2
/* This list contains all modules currently loaded into the runtime */
-static struct objc_list* __objc_module_list = 0;
+static struct objc_list* __objc_module_list = 0; /* !T:MUTEX */
/* This list contains all proto_list's not yet assigned class links */
-static struct objc_list* unclaimed_proto_list = 0;
+static struct objc_list* unclaimed_proto_list = 0; /* !T:MUTEX */
/* List of unresolved static instances. */
-static struct objc_list *uninitialized_statics;
+static struct objc_list *uninitialized_statics = 0; /* !T:MUTEX */
+
+/* Global runtime "write" mutex. */
+objc_mutex_t __objc_runtime_mutex = 0;
+
+/* Number of threads that are alive. */
+int __objc_runtime_threads_alive = 1; /* !T:MUTEX */
/* Check compiler vs runtime version */
static void init_check_module_version (Module_t);
@@ -52,23 +59,337 @@ static void __objc_class_add_protocols (Class, struct objc_protocol_list*);
or a category is loaded into the runtime. This may e.g. help a
dynamic loader determine the classes that have been loaded when
an object file is dynamically linked in */
-void (*_objc_load_callback)(Class class, Category* category) = 0;
+void (*_objc_load_callback)(Class class, Category* category); /* !T:SAFE */
/* Is all categories/classes resolved? */
-BOOL __objc_dangling_categories = NO;
+BOOL __objc_dangling_categories = NO; /* !T:UNUSED */
extern SEL
__sel_register_typed_name (const char *name, const char *types,
- struct objc_selector *orig);
+ struct objc_selector *orig, BOOL is_const);
+
+/* Sends +load to all classes and categories in certain situations. */
+static void objc_send_load (void);
+
+/* Inserts all the classes defined in module in a tree of classes that
+ resembles the class hierarchy. This tree is traversed in preorder and the
+ classes in its nodes receive the +load message if these methods were not
+ executed before. The algorithm ensures that when the +load method of a class
+ is executed all the superclasses have been already received the +load
+ message. */
+static void __objc_create_classes_tree (Module_t module);
+
+static void __objc_call_callback (Module_t module);
+
+/* A special version that works only before the classes are completely
+ installed in the runtime. */
+static BOOL class_is_subclass_of_class (Class class, Class superclass);
+
+typedef struct objc_class_tree {
+ Class class;
+ struct objc_list *subclasses; /* `head' is pointer to an objc_class_tree */
+} objc_class_tree;
+
+/* This is a linked list of objc_class_tree trees. The head of these trees
+ are root classes (their super class is Nil). These different trees
+ represent different class hierarchies. */
+static struct objc_list *__objc_class_tree_list = NULL;
+
+/* Keeps the +load methods who have been already executed. This hash should
+ not be destroyed during the execution of the program. */
+static cache_ptr __objc_load_methods = NULL;
+
+/* Creates a tree of classes whose topmost class is directly inherited from
+ `upper' and the bottom class in this tree is `bottom_class'. The classes
+ in this tree are super classes of `bottom_class'. `subclasses' member
+ of each tree node point to the next subclass tree node. */
+static objc_class_tree *
+create_tree_of_subclasses_inherited_from (Class bottom_class, Class upper)
+{
+ Class superclass = bottom_class->super_class ?
+ objc_lookup_class ((char*)bottom_class->super_class)
+ : Nil;
+
+ objc_class_tree *tree, *prev;
+
+ DEBUG_PRINTF ("create_tree_of_subclasses_inherited_from:");
+ DEBUG_PRINTF ("bottom_class = %s, upper = %s\n",
+ (bottom_class ? bottom_class->name : NULL),
+ (upper ? upper->name : NULL));
+
+ tree = prev = objc_calloc (1, sizeof (objc_class_tree));
+ prev->class = bottom_class;
+
+ while (superclass != upper)
+ {
+ tree = objc_calloc (1, sizeof (objc_class_tree));
+ tree->class = superclass;
+ tree->subclasses = list_cons (prev, tree->subclasses);
+ superclass = (superclass->super_class ?
+ objc_lookup_class ((char*)superclass->super_class)
+ : Nil);
+ prev = tree;
+ }
+
+ return tree;
+}
+
+/* Insert the `class' into the proper place in the `tree' class hierarchy. This
+ function returns a new tree if the class has been successfully inserted into
+ the tree or NULL if the class is not part of the classes hierarchy described
+ by `tree'. This function is private to objc_tree_insert_class(), you should
+ not call it directly. */
+static objc_class_tree *
+__objc_tree_insert_class (objc_class_tree *tree, Class class)
+{
+ DEBUG_PRINTF ("__objc_tree_insert_class: tree = %x, class = %s\n",
+ tree, class->name);
+
+ if (tree == NULL)
+ return create_tree_of_subclasses_inherited_from (class, NULL);
+ else if (class == tree->class)
+ {
+ /* `class' has been already inserted */
+ DEBUG_PRINTF ("1. class %s was previously inserted\n", class->name);
+ return tree;
+ }
+ else if ((class->super_class ?
+ objc_lookup_class ((char*)class->super_class)
+ : Nil)
+ == tree->class)
+ {
+ /* If class is a direct subclass of tree->class then add class to the
+ list of subclasses. First check to see if it wasn't already
+ inserted. */
+ struct objc_list *list = tree->subclasses;
+ objc_class_tree *node;
+
+ while (list)
+ {
+ /* Class has been already inserted; do nothing just return
+ the tree. */
+ if (((objc_class_tree*)list->head)->class == class)
+ {
+ DEBUG_PRINTF ("2. class %s was previously inserted\n",
+ class->name);
+ return tree;
+ }
+ list = list->tail;
+ }
+
+ /* Create a new node class and insert it into the list of subclasses */
+ node = objc_calloc (1, sizeof (objc_class_tree));
+ node->class = class;
+ tree->subclasses = list_cons (node, tree->subclasses);
+ DEBUG_PRINTF ("3. class %s inserted\n", class->name);
+ return tree;
+ }
+ else
+ {
+ /* The class is not a direct subclass of tree->class. Search for class's
+ superclasses in the list of subclasses. */
+ struct objc_list *subclasses = tree->subclasses;
+
+ /* Precondition: the class must be a subclass of tree->class; otherwise
+ return NULL to indicate our caller that it must take the next tree. */
+ if (!class_is_subclass_of_class (class, tree->class))
+ return NULL;
+
+ for (; subclasses != NULL; subclasses = subclasses->tail)
+ {
+ Class aClass = ((objc_class_tree*)(subclasses->head))->class;
+
+ if (class_is_subclass_of_class (class, aClass))
+ {
+ /* If we found one of class's superclasses we insert the class
+ into its subtree and return the original tree since nothing
+ has been changed. */
+ subclasses->head
+ = __objc_tree_insert_class (subclasses->head, class);
+ DEBUG_PRINTF ("4. class %s inserted\n", class->name);
+ return tree;
+ }
+ }
+
+ /* We haven't found a subclass of `class' in the `subclasses' list.
+ Create a new tree of classes whose topmost class is a direct subclass
+ of tree->class. */
+ {
+ objc_class_tree *new_tree
+ = create_tree_of_subclasses_inherited_from (class, tree->class);
+ tree->subclasses = list_cons (new_tree, tree->subclasses);
+ DEBUG_PRINTF ("5. class %s inserted\n", class->name);
+ return tree;
+ }
+ }
+}
+
+/* This function inserts `class' in the right tree hierarchy classes. */
+static void
+objc_tree_insert_class (Class class)
+{
+ struct objc_list *list_node;
+ objc_class_tree *tree;
+
+ list_node = __objc_class_tree_list;
+ while (list_node)
+ {
+ tree = __objc_tree_insert_class (list_node->head, class);
+ if (tree)
+ {
+ list_node->head = tree;
+ break;
+ }
+ else
+ list_node = list_node->tail;
+ }
+
+ /* If the list was finished but the class hasn't been inserted, insert it
+ here. */
+ if (!list_node)
+ {
+ __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list);
+ __objc_class_tree_list->head = __objc_tree_insert_class (NULL, class);
+ }
+}
+
+/* Traverse tree in preorder. Used to send +load. */
+static void
+objc_preorder_traverse (objc_class_tree *tree,
+ int level,
+ void (*function)(objc_class_tree*, int))
+{
+ struct objc_list *node;
+
+ (*function) (tree, level);
+ for (node = tree->subclasses; node; node = node->tail)
+ objc_preorder_traverse (node->head, level + 1, function);
+}
+
+/* Traverse tree in postorder. Used to destroy a tree. */
+static void
+objc_postorder_traverse (objc_class_tree *tree,
+ int level,
+ void (*function)(objc_class_tree*, int))
+{
+ struct objc_list *node;
+
+ for (node = tree->subclasses; node; node = node->tail)
+ objc_postorder_traverse (node->head, level + 1, function);
+ (*function) (tree, level);
+}
+
+/* Used to print a tree class hierarchy. */
+#ifdef DEBUG
+static void
+__objc_tree_print (objc_class_tree *tree, int level)
+{
+ int i;
+
+ for (i = 0; i < level; i++)
+ printf (" ");
+ printf ("%s\n", tree->class->name);
+}
+#endif
+
+/* Walks on a linked list of methods in the reverse order and executes all
+ the methods corresponding to `op' selector. Walking in the reverse order
+ assures the +load of class is executed first and then +load of categories
+ because of the way in which categories are added to the class methods. */
+static void
+__objc_send_message_in_list (MethodList_t method_list, Class class, SEL op)
+{
+ int i;
+
+ if (!method_list)
+ return;
+
+ /* First execute the `op' message in the following method lists */
+ __objc_send_message_in_list (method_list->method_next, class, op);
+
+ /* Search the method list. */
+ for (i = 0; i < method_list->method_count; i++)
+ {
+ Method_t mth = &method_list->method_list[i];
+
+ if (mth->method_name && sel_eq (mth->method_name, op)
+ && !hash_is_key_in_hash (__objc_load_methods, mth->method_name))
+ {
+ /* The method was found and wasn't previously executed. */
+ (*mth->method_imp) ((id)class, mth->method_name);
+
+ /* Add this method into the +load hash table */
+ hash_add (&__objc_load_methods, mth->method_imp, mth->method_imp);
+
+ DEBUG_PRINTF ("sending +load in class: %s\n", class->name);
+
+ break;
+ }
+ }
+}
+
+static void
+__objc_send_load (objc_class_tree *tree, int level)
+{
+ static SEL load_sel = 0;
+ Class class = tree->class;
+ MethodList_t method_list = class->class_pointer->methods;
+
+ if (!load_sel)
+ load_sel = sel_register_name ("load");
+
+ __objc_send_message_in_list (method_list, class, load_sel);
+}
+
+static void
+__objc_destroy_class_tree_node (objc_class_tree *tree, int level)
+{
+ objc_free (tree);
+}
+
+/* This is used to check if the relationship between two classes before the
+ runtime completely installs the classes. */
+static BOOL
+class_is_subclass_of_class (Class class, Class superclass)
+{
+ for (; class != Nil;)
+ {
+ if (class == superclass)
+ return YES;
+ class = (class->super_class ?
+ objc_lookup_class ((char*)class->super_class)
+ : Nil);
+ }
+
+ return NO;
+}
+
+/* This list contains all the classes in the runtime system for whom their
+ superclasses are not yet know to the runtime. */
+static struct objc_list* unresolved_classes = 0;
+
+/* Static function used to reference the Object and NXConstantString classes.
+ */
+static void
+__objc_force_linking (void)
+{
+ extern void __objc_linking (void);
+ __objc_linking ();
+
+ /* Call the function to avoid compiler warning */
+ __objc_force_linking ();
+}
/* Run through the statics list, removing modules as soon as all its statics
have been initialized. */
static void
-objc_init_statics ()
+objc_init_statics (void)
{
struct objc_list **cell = &uninitialized_statics;
struct objc_static_instances **statics_in_module;
+ objc_mutex_lock(__objc_runtime_mutex);
+
while (*cell)
{
int module_initialized = 1;
@@ -109,11 +430,13 @@ objc_init_statics ()
/* Remove this module from the uninitialized list. */
struct objc_list *this = *cell;
*cell = this->tail;
- free (this);
+ objc_free(this);
}
else
cell = &(*cell)->tail;
}
+
+ objc_mutex_unlock(__objc_runtime_mutex);
} /* objc_init_statics */
/* This function is called by constructor functions generated for each
@@ -133,6 +456,10 @@ __objc_exec_class (Module_t module)
/* The symbol table (defined in objc-api.h) generated by gcc */
Symtab_t symtab = module->symtab;
+ /* The statics in this module */
+ struct objc_static_instances **statics
+ = symtab->defs[symtab->cls_def_cnt + symtab->cat_def_cnt];
+
/* Entry used to traverse hash lists */
struct objc_list** cell;
@@ -150,13 +477,22 @@ __objc_exec_class (Module_t module)
/* On the first call of this routine, initialize some data structures. */
if (!previous_constructors)
{
+ /* Initialize thread-safe system */
+ __objc_init_thread_system();
+ __objc_runtime_threads_alive = 1;
+ __objc_runtime_mutex = objc_mutex_allocate();
+
__objc_init_selector_tables();
__objc_init_class_tables();
__objc_init_dispatch_tables();
+ __objc_class_tree_list = list_cons (NULL, __objc_class_tree_list);
+ __objc_load_methods
+ = hash_new (128, (hash_func_type)hash_ptr, compare_ptrs);
previous_constructors = 1;
}
/* Save the module pointer for later processing. (not currently used) */
+ objc_mutex_lock(__objc_runtime_mutex);
__objc_module_list = list_cons(module, __objc_module_list);
/* Replace referenced selectors from names to SEL's. */
@@ -167,8 +503,11 @@ __objc_exec_class (Module_t module)
const char *name, *type;
name = (char*)selectors[i].sel_id;
type = (char*)selectors[i].sel_types;
+ /* Constructors are constant static data so we can safely store
+ pointers to them in the runtime structures. is_const == YES */
__sel_register_typed_name (name, type,
- (struct objc_selector*)&(selectors[i]));
+ (struct objc_selector*)&(selectors[i]),
+ YES);
}
}
@@ -177,12 +516,17 @@ __objc_exec_class (Module_t module)
for (i = 0; i < symtab->cls_def_cnt; ++i)
{
Class class = (Class) symtab->defs[i];
+ const char* superclass = (char*)class->super_class;
/* Make sure we have what we think. */
assert (CLS_ISCLASS(class));
assert (CLS_ISMETA(class->class_pointer));
DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name);
+ /* Initialize the subclass list to be NULL.
+ In some cases it isn't and this crashes the program. */
+ class->subclass_list = NULL;
+
/* Store the class in the class table and assign class numbers. */
__objc_add_class_to_hash (class);
@@ -194,11 +538,17 @@ __objc_exec_class (Module_t module)
__objc_install_premature_dtable(class);
__objc_install_premature_dtable(class->class_pointer);
+ /* Register the instance methods as class methods, this is
+ only done for root classes. */
+ __objc_register_instance_methods_to_class(class);
+
if (class->protocols)
__objc_init_protocols (class->protocols);
- if (_objc_load_callback)
- _objc_load_callback(class, 0);
+ /* Check to see if the superclass is known in this point. If it's not
+ add the class to the unresolved_classes list. */
+ if (superclass && !objc_lookup_class (superclass))
+ unresolved_classes = list_cons (class, unresolved_classes);
}
/* Process category information from the module. */
@@ -230,8 +580,9 @@ __objc_exec_class (Module_t module)
__objc_class_add_protocols (class, category->protocols);
}
- if (_objc_load_callback)
- _objc_load_callback(class, category);
+ /* Register the instance methods as class methods, this is
+ only done for root classes. */
+ __objc_register_instance_methods_to_class(class);
}
else
{
@@ -241,8 +592,8 @@ __objc_exec_class (Module_t module)
}
}
- if (module->statics)
- uninitialized_statics = list_cons (module->statics, uninitialized_statics);
+ if (statics)
+ uninitialized_statics = list_cons (statics, uninitialized_statics);
if (uninitialized_statics)
objc_init_statics ();
@@ -268,15 +619,16 @@ __objc_exec_class (Module_t module)
if (category->class_methods)
class_add_method_list ((Class) class->class_pointer,
category->class_methods);
-
+
if (category->protocols)
{
__objc_init_protocols (category->protocols);
__objc_class_add_protocols (class, category->protocols);
}
-
- if (_objc_load_callback)
- _objc_load_callback(class, category);
+
+ /* Register the instance methods as class methods, this is
+ only done for root classes. */
+ __objc_register_instance_methods_to_class(class);
}
}
@@ -287,6 +639,119 @@ __objc_exec_class (Module_t module)
unclaimed_proto_list = 0;
}
+ objc_send_load ();
+
+ objc_mutex_unlock(__objc_runtime_mutex);
+}
+
+static void objc_send_load (void)
+{
+ if (!__objc_module_list)
+ return;
+
+ /* Try to find out if all the classes loaded so far also have their
+ superclasses known to the runtime. We suppose that the objects that are
+ allocated in the +load method are in general of a class declared in the
+ same module. */
+ if (unresolved_classes)
+ {
+ Class class = unresolved_classes->head;
+
+ while (objc_lookup_class ((char*)class->super_class))
+ {
+ list_remove_head (&unresolved_classes);
+ if (unresolved_classes)
+ class = unresolved_classes->head;
+ else
+ break;
+ }
+
+ /*
+ * If we still have classes for whom we don't have yet their super
+ * classes known to the runtime we don't send the +load messages.
+ */
+ if (unresolved_classes)
+ return;
+ }
+
+ /* Special check to allow creating and sending messages to constant strings
+ in +load methods. If these classes are not yet known, even if all the
+ other classes are known, delay sending of +load. */
+ if (!objc_lookup_class ("NXConstantString") ||
+ !objc_lookup_class ("Object"))
+ return;
+
+ /* Iterate over all modules in the __objc_module_list and call on them the
+ __objc_create_classes_tree function. This function creates a tree of
+ classes that resembles the class hierarchy. */
+ list_mapcar (__objc_module_list, (void(*)(void*))__objc_create_classes_tree);
+
+ while (__objc_class_tree_list)
+ {
+#ifdef DEBUG
+ objc_preorder_traverse (__objc_class_tree_list->head,
+ 0, __objc_tree_print);
+#endif
+ objc_preorder_traverse (__objc_class_tree_list->head,
+ 0, __objc_send_load);
+ objc_postorder_traverse (__objc_class_tree_list->head,
+ 0, __objc_destroy_class_tree_node);
+ list_remove_head (&__objc_class_tree_list);
+ }
+
+ list_mapcar (__objc_module_list, (void(*)(void*))__objc_call_callback);
+ list_free (__objc_module_list);
+ __objc_module_list = NULL;
+}
+
+static void
+__objc_create_classes_tree (Module_t module)
+{
+ /* The runtime mutex is locked in this point */
+
+ Symtab_t symtab = module->symtab;
+ int i;
+
+ /* Iterate thru classes defined in this module and insert them in the classes
+ tree hierarchy. */
+ for (i = 0; i < symtab->cls_def_cnt; i++)
+ {
+ Class class = (Class) symtab->defs[i];
+
+ objc_tree_insert_class (class);
+ }
+}
+
+static void
+__objc_call_callback (Module_t module)
+{
+ /* The runtime mutex is locked in this point */
+
+ Symtab_t symtab = module->symtab;
+ int i;
+
+ /* Iterate thru classes defined in this module and call the callback for
+ each one. */
+ for (i = 0; i < symtab->cls_def_cnt; i++)
+ {
+ Class class = (Class) symtab->defs[i];
+
+ /* Call the _objc_load_callback for this class. */
+ if (_objc_load_callback)
+ _objc_load_callback(class, 0);
+ }
+
+ /* Call the _objc_load_callback for categories. Don't register the instance
+ methods as class methods for categories to root classes since they were
+ already added in the class. */
+ for (i = 0; i < symtab->cat_def_cnt; i++)
+ {
+ Category_t category = symtab->defs[i + symtab->cls_def_cnt];
+ Class class = objc_lookup_class (category->class_name);
+
+ if (_objc_load_callback)
+ _objc_load_callback(class, category);
+ }
}
/* Sanity check the version of gcc used to compile `module'*/
@@ -294,15 +759,17 @@ static void init_check_module_version(Module_t module)
{
if ((module->version != OBJC_VERSION) || (module->size != sizeof (Module)))
{
- fprintf (stderr, "Module %s version %d doesn't match runtime %d\n",
- module->name, (int)module->version, OBJC_VERSION);
+ int code;
+
if(module->version > OBJC_VERSION)
- fprintf (stderr, "Runtime (libobjc.a) is out of date\n");
+ code = OBJC_ERR_OBJC_VERSION;
else if (module->version < OBJC_VERSION)
- fprintf (stderr, "Compiler (gcc) is out of date\n");
+ code = OBJC_ERR_GCC_VERSION;
else
- fprintf (stderr, "Objective C internal error -- bad Module size\n");
- abort ();
+ code = OBJC_ERR_MODULE_SIZE;
+
+ objc_error(nil, code, "Module %s version %d doesn't match runtime %d\n",
+ module->name, (int)module->version, OBJC_VERSION);
}
}
@@ -315,12 +782,15 @@ __objc_init_protocols (struct objc_protocol_list* protos)
if (! protos)
return;
+ objc_mutex_lock(__objc_runtime_mutex);
+
if (!proto_class)
proto_class = objc_lookup_class("Protocol");
if (!proto_class)
{
unclaimed_proto_list = list_cons (protos, unclaimed_proto_list);
+ objc_mutex_unlock(__objc_runtime_mutex);
return;
}
@@ -341,13 +811,14 @@ __objc_init_protocols (struct objc_protocol_list* protos)
}
else if (protos->list[i]->class_pointer != proto_class)
{
- fprintf (stderr,
- "Version %d doesn't match runtime protocol version %d\n",
- (int)((char*)protos->list[i]->class_pointer-(char*)0),
- PROTOCOL_VERSION);
- abort ();
+ objc_error(nil, OBJC_ERR_PROTOCOL_VERSION,
+ "Version %d doesn't match runtime protocol version %d\n",
+ (int)((char*)protos->list[i]->class_pointer-(char*)0),
+ PROTOCOL_VERSION);
}
}
+
+ objc_mutex_unlock(__objc_runtime_mutex);
}
static void __objc_class_add_protocols (Class class,
diff --git a/contrib/gcc/objc/makefile.dos b/contrib/gcc/objc/makefile.dos
index 5321733..3e1b187 100644
--- a/contrib/gcc/objc/makefile.dos
+++ b/contrib/gcc/objc/makefile.dos
@@ -1,5 +1,5 @@
# GNU Objective C Runtime Makefile for compiling with djgpp
-# Copyright (C) 1993, 1994 Free Software Foundation, Inc.
+# Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc.
#
# This file is part of GNU CC.
#
@@ -37,17 +37,17 @@ SUBDIR_INCLUDES = -I. -I.. -I../config
-c $(GCC_CFLAGS) $(SUBDIR_INCLUDES) $<
OBJC_O = hash.o sarray.o class.o sendmsg.o init.o archive.o \
- selector.o objects.o misc.o object.o protocol.o encoding.o
+ selector.o objects.o misc.o object.o protocol.o encoding.o thread.o
libobjc.a: $(OBJC_O)
-rm -f libobjc.a
ar rc libobjc.a $(OBJC_O)
ranlib libobjc.a
-OBJC_H = hash.h list.h sarray.h objc.h \
+OBJC_H = hash.h objc-list.h sarray.h objc.h \
objc-api.h \
object.h protocol.h mutex.h \
- typedstream.h
+ typedstream.h thread.h
mostlyclean:
-rm -f *.o libobjc.a xforward fflags
diff --git a/contrib/gcc/objc/misc.c b/contrib/gcc/objc/misc.c
index 033018e..01f9d3b 100644
--- a/contrib/gcc/objc/misc.c
+++ b/contrib/gcc/objc/misc.c
@@ -1,7 +1,6 @@
/* GNU Objective C Runtime Miscellaneous
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
-
-Author: Kresten Krab Thorup
+ Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Contributed by Kresten Krab Thorup
This file is part of GNU CC.
@@ -26,55 +25,128 @@ Boston, MA 02111-1307, USA. */
however invalidate any other reasons why the executable file might be
covered by the GNU General Public License. */
-#ifdef __alpha__
+#define __USE_FIXED_PROTOTYPES__
#include <stdlib.h>
-extern int write (int, const char*, int);
-extern size_t strlen (const char*);
-#endif
-
#include "runtime.h"
-void objc_error(id object, const char* fmt, va_list);
+/*
+** Error handler function
+** NULL so that default is to just print to stderr
+*/
+static objc_error_handler _objc_error_handler = NULL;
+
+/* Trigger an objc error */
+void
+objc_error(id object, int code, const char* fmt, ...)
+{
+ va_list ap;
-void (*_objc_error)(id, const char*, va_list) = objc_error;
+ va_start(ap, fmt);
+ objc_verror(object, code, fmt, ap);
+ va_end(ap);
+}
+/* Trigger an objc error */
void
-objc_error(id object, const char* fmt, va_list ap)
+objc_verror(id object, int code, const char* fmt, va_list ap)
+{
+ BOOL result = NO;
+
+ /* Call the error handler if its there
+ Otherwise print to stderr */
+ if (_objc_error_handler)
+ result = (*_objc_error_handler)(object, code, fmt, ap);
+ else
+ vfprintf (stderr, fmt, ap);
+
+ /* Continue if the error handler says its ok
+ Otherwise abort the program */
+ if (result)
+ return;
+ else
+ abort();
+}
+
+/* Set the error handler */
+objc_error_handler
+objc_set_error_handler(objc_error_handler func)
+{
+ objc_error_handler temp = _objc_error_handler;
+ _objc_error_handler = func;
+ return temp;
+}
+
+/*
+** Standard functions for memory allocation and disposal.
+** Users should use these functions in their ObjC programs so
+** that they work properly with garbage collectors as well as
+** can take advantage of the exception/error handling available.
+*/
+
+void *
+objc_malloc(size_t size)
{
- vfprintf (stderr, fmt, ap);
- abort ();
+ void* res = (void*) (*_objc_malloc)(size);
+ if(!res)
+ objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
+ return res;
}
-volatile void
-objc_fatal(const char* msg)
+void *
+objc_atomic_malloc(size_t size)
{
- write(2, msg, (int)strlen((const char*)msg));
- abort();
+ void* res = (void*) (*_objc_atomic_malloc)(size);
+ if(!res)
+ objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
+ return res;
}
-void*
-__objc_xmalloc(size_t size)
+void *
+objc_valloc(size_t size)
{
- void* res = (void*) malloc(size);
+ void* res = (void*) (*_objc_valloc)(size);
if(!res)
- objc_fatal("Virtual memory exhausted\n");
+ objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
return res;
}
-void*
-__objc_xrealloc(void* mem, size_t size)
+void *
+objc_realloc(void *mem, size_t size)
{
- void* res = (void*) realloc(mem, size);
+ void* res = (void*) (*_objc_realloc)(mem, size);
if(!res)
- objc_fatal("Virtual memory exhausted\n");
+ objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
return res;
}
-void*
-__objc_xcalloc(size_t nelem, size_t size)
+void *
+objc_calloc(size_t nelem, size_t size)
{
- void* res = (void*)calloc(nelem, size);
+ void* res = (void*) (*_objc_calloc)(nelem, size);
if(!res)
- objc_fatal("Virtual memory exhausted\n");
+ objc_error(nil, OBJC_ERR_MEMORY, "Virtual memory exhausted\n");
return res;
}
+
+void
+objc_free(void *mem)
+{
+ (*_objc_free)(mem);
+}
+
+/*
+** Hook functions for memory allocation and disposal.
+** This makes it easy to substitute garbage collection systems
+** such as Boehm's GC by assigning these function pointers
+** to the GC's allocation routines. By default these point
+** to the ANSI standard malloc, realloc, free, etc.
+**
+** Users should call the normal objc routines above for
+** memory allocation and disposal within their programs.
+*/
+void *(*_objc_malloc)(size_t) = malloc;
+void *(*_objc_atomic_malloc)(size_t) = malloc;
+void *(*_objc_valloc)(size_t) = malloc;
+void *(*_objc_realloc)(void *, size_t) = realloc;
+void *(*_objc_calloc)(size_t, size_t) = calloc;
+void (*_objc_free)(void *) = free;
diff --git a/contrib/gcc/objc/objc-act.c b/contrib/gcc/objc/objc-act.c
new file mode 100644
index 0000000..0f4058b
--- /dev/null
+++ b/contrib/gcc/objc/objc-act.c
@@ -0,0 +1,8455 @@
+/* Implement classes and message passing for Objective C.
+ Copyright (C) 1992, 93-95, 97, 1998 Free Software Foundation, Inc.
+ Contributed by Steve Naroff.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* Purpose: This module implements the Objective-C 4.0 language.
+
+ compatibility issues (with the Stepstone translator):
+
+ - does not recognize the following 3.3 constructs.
+ @requires, @classes, @messages, = (...)
+ - methods with variable arguments must conform to ANSI standard.
+ - tagged structure definitions that appear in BOTH the interface
+ and implementation are not allowed.
+ - public/private: all instance variables are public within the
+ context of the implementation...I consider this to be a bug in
+ the translator.
+ - statically allocated objects are not supported. the user will
+ receive an error if this service is requested.
+
+ code generation `options':
+
+ - OBJC_INT_SELECTORS */
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "c-tree.h"
+#include "c-lex.h"
+#include "flags.h"
+#include "objc-act.h"
+#include "input.h"
+#include "except.h"
+#include "function.h"
+#include "output.h"
+#include "toplev.h"
+
+#if USE_CPPLIB
+#include "cpplib.h"
+extern cpp_reader parse_in;
+extern cpp_options parse_options;
+static int cpp_initialized;
+#endif
+
+/* This is the default way of generating a method name. */
+/* I am not sure it is really correct.
+ Perhaps there's a danger that it will make name conflicts
+ if method names contain underscores. -- rms. */
+#ifndef OBJC_GEN_METHOD_LABEL
+#define OBJC_GEN_METHOD_LABEL(BUF, IS_INST, CLASS_NAME, CAT_NAME, SEL_NAME, NUM) \
+ do { \
+ char *temp; \
+ sprintf ((BUF), "_%s_%s_%s_%s", \
+ ((IS_INST) ? "i" : "c"), \
+ (CLASS_NAME), \
+ ((CAT_NAME)? (CAT_NAME) : ""), \
+ (SEL_NAME)); \
+ for (temp = (BUF); *temp; temp++) \
+ if (*temp == ':') *temp = '_'; \
+ } while (0)
+#endif
+
+/* These need specifying. */
+#ifndef OBJC_FORWARDING_STACK_OFFSET
+#define OBJC_FORWARDING_STACK_OFFSET 0
+#endif
+
+#ifndef OBJC_FORWARDING_MIN_OFFSET
+#define OBJC_FORWARDING_MIN_OFFSET 0
+#endif
+
+/* Define the special tree codes that we use. */
+
+/* Table indexed by tree code giving a string containing a character
+ classifying the tree code. Possibilities are
+ t, d, s, c, r, <, 1 and 2. See objc-tree.def for details. */
+
+#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
+
+char objc_tree_code_type[] = {
+ 'x',
+#include "objc-tree.def"
+};
+#undef DEFTREECODE
+
+/* Table indexed by tree code giving number of expression
+ operands beyond the fixed part of the node structure.
+ Not used for types or decls. */
+
+#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
+
+int objc_tree_code_length[] = {
+ 0,
+#include "objc-tree.def"
+};
+#undef DEFTREECODE
+
+/* Names of tree components.
+ Used for printing out the tree and error messages. */
+#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
+
+char *objc_tree_code_name[] = {
+ "@@dummy",
+#include "objc-tree.def"
+};
+#undef DEFTREECODE
+
+/* Set up for use of obstacks. */
+
+#include "obstack.h"
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+/* This obstack is used to accumulate the encoding of a data type. */
+static struct obstack util_obstack;
+/* This points to the beginning of obstack contents,
+ so we can free the whole contents. */
+char *util_firstobj;
+
+/* List of classes with list of their static instances. */
+static tree objc_static_instances = NULL_TREE;
+
+/* The declaration of the array administrating the static instances. */
+static tree static_instances_decl = NULL_TREE;
+
+/* for encode_method_def */
+#include "rtl.h"
+#include "c-parse.h"
+
+#define OBJC_VERSION (flag_next_runtime ? 5 : 8)
+#define PROTOCOL_VERSION 2
+
+#define OBJC_ENCODE_INLINE_DEFS 0
+#define OBJC_ENCODE_DONT_INLINE_DEFS 1
+
+/*** Private Interface (procedures) ***/
+
+/* Used by compile_file. */
+
+static void init_objc PROTO((void));
+static void finish_objc PROTO((void));
+
+/* Code generation. */
+
+static void synth_module_prologue PROTO((void));
+static tree build_constructor PROTO((tree, tree));
+static char *build_module_descriptor PROTO((void));
+static tree init_module_descriptor PROTO((tree));
+static tree build_objc_method_call PROTO((int, tree, tree,
+ tree, tree, tree));
+static void generate_strings PROTO((void));
+static tree get_proto_encoding PROTO((tree));
+static void build_selector_translation_table PROTO((void));
+static tree build_ivar_chain PROTO((tree, int));
+
+static tree objc_add_static_instance PROTO((tree, tree));
+
+static tree build_ivar_template PROTO((void));
+static tree build_method_template PROTO((void));
+static tree build_private_template PROTO((tree));
+static void build_class_template PROTO((void));
+static void build_selector_template PROTO((void));
+static void build_category_template PROTO((void));
+static tree build_super_template PROTO((void));
+static tree build_category_initializer PROTO((tree, tree, tree,
+ tree, tree, tree));
+static tree build_protocol_initializer PROTO((tree, tree, tree,
+ tree, tree));
+
+static void synth_forward_declarations PROTO((void));
+static void generate_ivar_lists PROTO((void));
+static void generate_dispatch_tables PROTO((void));
+static void generate_shared_structures PROTO((void));
+static tree generate_protocol_list PROTO((tree));
+static void generate_forward_declaration_to_string_table PROTO((void));
+static void build_protocol_reference PROTO((tree));
+
+#if 0
+static tree init_selector PROTO((int));
+#endif
+static tree build_keyword_selector PROTO((tree));
+static tree synth_id_with_class_suffix PROTO((char *, tree));
+
+static void generate_static_references PROTO((void));
+static int check_methods_accessible PROTO((tree, tree,
+ int));
+static void encode_aggregate_within PROTO((tree, int, int,
+ int, int));
+
+/* We handle printing method names ourselves for ObjC */
+extern char *(*decl_printable_name) ();
+
+/* Misc. bookkeeping */
+
+typedef struct hashed_entry *hash;
+typedef struct hashed_attribute *attr;
+
+struct hashed_attribute
+{
+ attr next;
+ tree value;
+};
+struct hashed_entry
+{
+ attr list;
+ hash next;
+ tree key;
+};
+
+static void hash_init PROTO((void));
+static void hash_enter PROTO((hash *, tree));
+static hash hash_lookup PROTO((hash *, tree));
+static void hash_add_attr PROTO((hash, tree));
+static tree lookup_method PROTO((tree, tree));
+static tree lookup_instance_method_static PROTO((tree, tree));
+static tree lookup_class_method_static PROTO((tree, tree));
+static tree add_class PROTO((tree));
+static void add_category PROTO((tree, tree));
+
+enum string_section
+{
+ class_names, /* class, category, protocol, module names */
+ meth_var_names, /* method and variable names */
+ meth_var_types /* method and variable type descriptors */
+};
+
+static tree add_objc_string PROTO((tree,
+ enum string_section));
+static tree get_objc_string_decl PROTO((tree,
+ enum string_section));
+static tree build_objc_string_decl PROTO((tree,
+ enum string_section));
+static tree build_selector_reference_decl PROTO((tree));
+
+/* Protocol additions. */
+
+static tree add_protocol PROTO((tree));
+static tree lookup_protocol PROTO((tree));
+static tree lookup_and_install_protocols PROTO((tree));
+
+/* Type encoding. */
+
+static void encode_type_qualifiers PROTO((tree));
+static void encode_pointer PROTO((tree, int, int));
+static void encode_array PROTO((tree, int, int));
+static void encode_aggregate PROTO((tree, int, int));
+static void encode_bitfield PROTO((int, int));
+static void encode_type PROTO((tree, int, int));
+static void encode_field_decl PROTO((tree, int, int));
+
+static void really_start_method PROTO((tree, tree));
+static int comp_method_with_proto PROTO((tree, tree));
+static int comp_proto_with_proto PROTO((tree, tree));
+static tree get_arg_type_list PROTO((tree, int, int));
+static tree expr_last PROTO((tree));
+
+/* Utilities for debugging and error diagnostics. */
+
+static void warn_with_method PROTO((char *, int, tree));
+static void error_with_ivar PROTO((char *, tree, tree));
+static char *gen_method_decl PROTO((tree, char *));
+static char *gen_declaration PROTO((tree, char *));
+static char *gen_declarator PROTO((tree, char *, char *));
+static int is_complex_decl PROTO((tree));
+static void adorn_decl PROTO((tree, char *));
+static void dump_interface PROTO((FILE *, tree));
+
+/* Everything else. */
+
+static void objc_fatal PROTO((void));
+static tree define_decl PROTO((tree, tree));
+static tree lookup_method_in_protocol_list PROTO((tree, tree, int));
+static tree lookup_protocol_in_reflist PROTO((tree, tree));
+static tree create_builtin_decl PROTO((enum tree_code,
+ tree, char *));
+static tree my_build_string PROTO((int, char *));
+static void build_objc_symtab_template PROTO((void));
+static tree init_def_list PROTO((tree));
+static tree init_objc_symtab PROTO((tree));
+static void forward_declare_categories PROTO((void));
+static void generate_objc_symtab_decl PROTO((void));
+static tree build_selector PROTO((tree));
+#if 0
+static tree build_msg_pool_reference PROTO((int));
+#endif
+static tree build_typed_selector_reference PROTO((tree, tree));
+static tree build_selector_reference PROTO((tree));
+static tree build_class_reference_decl PROTO((tree));
+static void add_class_reference PROTO((tree));
+static tree objc_copy_list PROTO((tree, tree *));
+static tree build_protocol_template PROTO((void));
+static tree build_descriptor_table_initializer PROTO((tree, tree));
+static tree build_method_prototype_list_template PROTO((tree, int));
+static tree build_method_prototype_template PROTO((void));
+static int forwarding_offset PROTO((tree));
+static tree encode_method_prototype PROTO((tree, tree));
+static tree generate_descriptor_table PROTO((tree, char *, int, tree, tree));
+static void generate_method_descriptors PROTO((tree));
+static tree build_tmp_function_decl PROTO((void));
+static void hack_method_prototype PROTO((tree, tree));
+static void generate_protocol_references PROTO((tree));
+static void generate_protocols PROTO((void));
+static void check_ivars PROTO((tree, tree));
+static tree build_ivar_list_template PROTO((tree, int));
+static tree build_method_list_template PROTO((tree, int));
+static tree build_ivar_list_initializer PROTO((tree, tree));
+static tree generate_ivars_list PROTO((tree, char *,
+ int, tree));
+static tree build_dispatch_table_initializer PROTO((tree, tree));
+static tree generate_dispatch_table PROTO((tree, char *,
+ int, tree));
+static tree build_shared_structure_initializer PROTO((tree, tree, tree, tree,
+ tree, int, tree, tree,
+ tree));
+static void generate_category PROTO((tree));
+static int is_objc_type_qualifier PROTO((tree));
+static tree adjust_type_for_id_default PROTO((tree));
+static tree check_duplicates PROTO((hash));
+static tree receiver_is_class_object PROTO((tree));
+static int check_methods PROTO((tree, tree, int));
+static int conforms_to_protocol PROTO((tree, tree));
+static void check_protocols PROTO((tree, char *, char *));
+static tree encode_method_def PROTO((tree));
+static void gen_declspecs PROTO((tree, char *, int));
+static void generate_classref_translation_entry PROTO((tree));
+static void handle_class_ref PROTO((tree));
+
+/*** Private Interface (data) ***/
+
+/* Reserved tag definitions. */
+
+#define TYPE_ID "id"
+#define TAG_OBJECT "objc_object"
+#define TAG_CLASS "objc_class"
+#define TAG_SUPER "objc_super"
+#define TAG_SELECTOR "objc_selector"
+
+#define UTAG_CLASS "_objc_class"
+#define UTAG_IVAR "_objc_ivar"
+#define UTAG_IVAR_LIST "_objc_ivar_list"
+#define UTAG_METHOD "_objc_method"
+#define UTAG_METHOD_LIST "_objc_method_list"
+#define UTAG_CATEGORY "_objc_category"
+#define UTAG_MODULE "_objc_module"
+#define UTAG_STATICS "_objc_statics"
+#define UTAG_SYMTAB "_objc_symtab"
+#define UTAG_SUPER "_objc_super"
+#define UTAG_SELECTOR "_objc_selector"
+
+#define UTAG_PROTOCOL "_objc_protocol"
+#define UTAG_PROTOCOL_LIST "_objc_protocol_list"
+#define UTAG_METHOD_PROTOTYPE "_objc_method_prototype"
+#define UTAG_METHOD_PROTOTYPE_LIST "_objc__method_prototype_list"
+
+#define STRING_OBJECT_CLASS_NAME "NXConstantString"
+#define PROTOCOL_OBJECT_CLASS_NAME "Protocol"
+
+static char *TAG_GETCLASS;
+static char *TAG_GETMETACLASS;
+static char *TAG_MSGSEND;
+static char *TAG_MSGSENDSUPER;
+static char *TAG_EXECCLASS;
+
+/* Set by `continue_class' and checked by `is_public'. */
+
+#define TREE_STATIC_TEMPLATE(record_type) (TREE_PUBLIC (record_type))
+#define TYPED_OBJECT(type) \
+ (TREE_CODE (type) == RECORD_TYPE && TREE_STATIC_TEMPLATE (type))
+
+/* Some commonly used instances of "identifier_node". */
+
+static tree self_id, ucmd_id;
+static tree unused_list;
+
+static tree self_decl, umsg_decl, umsg_super_decl;
+static tree objc_get_class_decl, objc_get_meta_class_decl;
+
+static tree super_type, selector_type, id_type, objc_class_type;
+static tree instance_type, protocol_type;
+
+/* Type checking macros. */
+
+#define IS_ID(TYPE) \
+ (TYPE_MAIN_VARIANT (TYPE) == TYPE_MAIN_VARIANT (id_type))
+#define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
+ (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
+#define IS_SUPER(TYPE) \
+ (super_type && TYPE_MAIN_VARIANT (TYPE) == TYPE_MAIN_VARIANT (super_type))
+
+static tree class_chain = NULL_TREE;
+static tree alias_chain = NULL_TREE;
+static tree interface_chain = NULL_TREE;
+static tree protocol_chain = NULL_TREE;
+
+/* Chains to manage selectors that are referenced and defined in the
+ module. */
+
+static tree cls_ref_chain = NULL_TREE; /* Classes referenced. */
+static tree sel_ref_chain = NULL_TREE; /* Selectors referenced. */
+
+/* Chains to manage uniquing of strings. */
+
+static tree class_names_chain = NULL_TREE;
+static tree meth_var_names_chain = NULL_TREE;
+static tree meth_var_types_chain = NULL_TREE;
+
+/* Hash tables to manage the global pool of method prototypes. */
+
+static hash *nst_method_hash_list = 0;
+static hash *cls_method_hash_list = 0;
+
+/* Backend data declarations. */
+
+static tree UOBJC_SYMBOLS_decl;
+static tree UOBJC_INSTANCE_VARIABLES_decl, UOBJC_CLASS_VARIABLES_decl;
+static tree UOBJC_INSTANCE_METHODS_decl, UOBJC_CLASS_METHODS_decl;
+static tree UOBJC_CLASS_decl, UOBJC_METACLASS_decl;
+static tree UOBJC_SELECTOR_TABLE_decl;
+static tree UOBJC_MODULES_decl;
+static tree UOBJC_STRINGS_decl;
+
+/* The following are used when compiling a class implementation.
+ implementation_template will normally be an interface, however if
+ none exists this will be equal to implementation_context...it is
+ set in start_class. */
+
+static tree implementation_context = NULL_TREE;
+static tree implementation_template = NULL_TREE;
+
+struct imp_entry
+{
+ struct imp_entry *next;
+ tree imp_context;
+ tree imp_template;
+ tree class_decl; /* _OBJC_CLASS_<my_name>; */
+ tree meta_decl; /* _OBJC_METACLASS_<my_name>; */
+};
+
+static void handle_impent PROTO((struct imp_entry *));
+
+static struct imp_entry *imp_list = 0;
+static int imp_count = 0; /* `@implementation' */
+static int cat_count = 0; /* `@category' */
+
+static tree objc_class_template, objc_category_template, uprivate_record;
+static tree objc_protocol_template, objc_selector_template;
+static tree ucls_super_ref, uucls_super_ref;
+
+static tree objc_method_template, objc_ivar_template;
+static tree objc_symtab_template, objc_module_template;
+static tree objc_super_template, objc_object_reference;
+
+static tree objc_object_id, objc_class_id, objc_id_id;
+static tree constant_string_id;
+static tree constant_string_type;
+static tree UOBJC_SUPER_decl;
+
+static tree method_context = NULL_TREE;
+static int method_slot = 0; /* Used by start_method_def, */
+
+#define BUFSIZE 1024
+
+static char *errbuf; /* Buffer for error diagnostics */
+
+/* Data imported from tree.c. */
+
+extern enum debug_info_type write_symbols;
+
+/* Data imported from toplev.c. */
+
+extern char *dump_base_name;
+
+/* Generate code for GNU or NeXT runtime environment. */
+
+#ifdef NEXT_OBJC_RUNTIME
+int flag_next_runtime = 1;
+#else
+int flag_next_runtime = 0;
+#endif
+
+int flag_typed_selectors;
+
+/* Open and close the file for outputting class declarations, if requested. */
+
+int flag_gen_declaration = 0;
+
+FILE *gen_declaration_file;
+
+/* Warn if multiple methods are seen for the same selector, but with
+ different argument types. */
+
+int warn_selector = 0;
+
+/* Warn if methods required by a protocol are not implemented in the
+ class adopting it. When turned off, methods inherited to that
+ class are also considered implemented */
+
+int flag_warn_protocol = 1;
+
+/* Tells "encode_pointer/encode_aggregate" whether we are generating
+ type descriptors for instance variables (as opposed to methods).
+ Type descriptors for instance variables contain more information
+ than methods (for static typing and embedded structures). This
+ was added to support features being planned for dbkit2. */
+
+static int generating_instance_variables = 0;
+
+/* Tells the compiler that this is a special run. Do not perform
+ any compiling, instead we are to test some platform dependent
+ features and output a C header file with appropriate definitions. */
+
+static int print_struct_values = 0;
+
+/* Some platforms pass small structures through registers versus through
+ an invisible pointer. Determine at what size structure is the
+ transition point between the two possibilities. */
+
+void
+generate_struct_by_value_array ()
+{
+ tree type;
+ tree field_decl, field_decl_chain;
+ int i, j;
+ int aggregate_in_mem[32];
+ int found = 0;
+
+ /* Presumbaly no platform passes 32 byte structures in a register. */
+ for (i = 1; i < 32; i++)
+ {
+ char buffer[5];
+
+ /* Create an unnamed struct that has `i' character components */
+ type = start_struct (RECORD_TYPE, NULL_TREE);
+
+ strcpy (buffer, "c1");
+ field_decl = create_builtin_decl (FIELD_DECL,
+ char_type_node,
+ buffer);
+ field_decl_chain = field_decl;
+
+ for (j = 1; j < i; j++)
+ {
+ sprintf (buffer, "c%d", j + 1);
+ field_decl = create_builtin_decl (FIELD_DECL,
+ char_type_node,
+ buffer);
+ chainon (field_decl_chain, field_decl);
+ }
+ finish_struct (type, field_decl_chain, NULL_TREE);
+
+ aggregate_in_mem[i] = aggregate_value_p (type);
+ if (!aggregate_in_mem[i])
+ found = 1;
+ }
+
+ /* We found some structures that are returned in registers instead of memory
+ so output the necessary data. */
+ if (found)
+ {
+ for (i = 31; i >= 0; i--)
+ if (!aggregate_in_mem[i])
+ break;
+ printf ("#define OBJC_MAX_STRUCT_BY_VALUE %d\n\n", i);
+
+ /* The first member of the structure is always 0 because we don't handle
+ structures with 0 members */
+ printf ("static int struct_forward_array[] = {\n 0");
+
+ for (j = 1; j <= i; j++)
+ printf (", %d", aggregate_in_mem[j]);
+ printf ("\n};\n");
+ }
+
+ exit (0);
+}
+
+void
+lang_init_options ()
+{
+}
+
+void
+lang_init ()
+{
+#if !USE_CPPLIB
+ /* The beginning of the file is a new line; check for #.
+ With luck, we discover the real source file's name from that
+ and put it in input_filename. */
+ ungetc (check_newline (), finput);
+#endif
+
+ /* The line number can be -1 if we had -g3 and the input file
+ had a directive specifying line 0. But we want predefined
+ functions to have a line number of 0, not -1. */
+ if (lineno == -1)
+ lineno = 0;
+
+ /* If gen_declaration desired, open the output file. */
+ if (flag_gen_declaration)
+ {
+ int dump_base_name_length = strlen (dump_base_name);
+ register char *dumpname = (char *) xmalloc (dump_base_name_length + 7);
+ strcpy (dumpname, dump_base_name);
+ strcat (dumpname, ".decl");
+ gen_declaration_file = fopen (dumpname, "w");
+ if (gen_declaration_file == 0)
+ pfatal_with_name (dumpname);
+ }
+
+ if (flag_next_runtime)
+ {
+ TAG_GETCLASS = "objc_getClass";
+ TAG_GETMETACLASS = "objc_getMetaClass";
+ TAG_MSGSEND = "objc_msgSend";
+ TAG_MSGSENDSUPER = "objc_msgSendSuper";
+ TAG_EXECCLASS = "__objc_execClass";
+ }
+ else
+ {
+ TAG_GETCLASS = "objc_get_class";
+ TAG_GETMETACLASS = "objc_get_meta_class";
+ TAG_MSGSEND = "objc_msg_lookup";
+ TAG_MSGSENDSUPER = "objc_msg_lookup_super";
+ TAG_EXECCLASS = "__objc_exec_class";
+ flag_typed_selectors = 1;
+ }
+
+ if (doing_objc_thang)
+ init_objc ();
+
+ if (print_struct_values)
+ generate_struct_by_value_array ();
+}
+
+static void
+objc_fatal ()
+{
+ fatal ("Objective-C text in C source file");
+}
+
+void
+finish_file ()
+{
+ if (doing_objc_thang)
+ finish_objc (); /* Objective-C finalization */
+
+ if (gen_declaration_file)
+ fclose (gen_declaration_file);
+}
+
+void
+lang_finish ()
+{
+}
+
+char *
+lang_identify ()
+{
+ return "objc";
+}
+
+int
+lang_decode_option (argc, argv)
+ int argc;
+ char **argv;
+{
+ char *p = argv[0];
+#if USE_CPPLIB
+ if (! cpp_initialized)
+ {
+ cpp_reader_init (&parse_in);
+ parse_in.data = &parse_options;
+ cpp_options_init (&parse_options);
+ cpp_initialized = 1;
+ }
+#endif
+ if (!strcmp (p, "-lang-objc"))
+ doing_objc_thang = 1;
+ else if (!strcmp (p, "-gen-decls"))
+ flag_gen_declaration = 1;
+ else if (!strcmp (p, "-Wselector"))
+ warn_selector = 1;
+ else if (!strcmp (p, "-Wno-selector"))
+ warn_selector = 0;
+ else if (!strcmp (p, "-Wprotocol"))
+ flag_warn_protocol = 1;
+ else if (!strcmp (p, "-Wno-protocol"))
+ flag_warn_protocol = 0;
+ else if (!strcmp (p, "-fgnu-runtime"))
+ flag_next_runtime = 0;
+ else if (!strcmp (p, "-fno-next-runtime"))
+ flag_next_runtime = 0;
+ else if (!strcmp (p, "-fno-gnu-runtime"))
+ flag_next_runtime = 1;
+ else if (!strcmp (p, "-fnext-runtime"))
+ flag_next_runtime = 1;
+ else if (!strcmp (p, "-print-objc-runtime-info"))
+ print_struct_values = 1;
+ else
+ return c_decode_option (argc, argv);
+
+ return 1;
+}
+
+/* used by print-tree.c */
+
+void
+lang_print_xnode (file, node, indent)
+ FILE *file ATTRIBUTE_UNUSED;
+ tree node ATTRIBUTE_UNUSED;
+ int indent ATTRIBUTE_UNUSED;
+{
+}
+
+
+static tree
+define_decl (declarator, declspecs)
+ tree declarator;
+ tree declspecs;
+{
+ tree decl = start_decl (declarator, declspecs, 0, NULL_TREE, NULL_TREE);
+ finish_decl (decl, NULL_TREE, NULL_TREE);
+ return decl;
+}
+
+/* Return 1 if LHS and RHS are compatible types for assignment or
+ various other operations. Return 0 if they are incompatible, and
+ return -1 if we choose to not decide. When the operation is
+ REFLEXIVE, check for compatibility in either direction.
+
+ For statically typed objects, an assignment of the form `a' = `b'
+ is permitted if:
+
+ `a' is of type "id",
+ `a' and `b' are the same class type, or
+ `a' and `b' are of class types A and B such that B is a descendant of A. */
+
+int
+maybe_objc_comptypes (lhs, rhs, reflexive)
+ tree lhs, rhs;
+ int reflexive;
+{
+ if (doing_objc_thang)
+ return objc_comptypes (lhs, rhs, reflexive);
+ return -1;
+}
+
+static tree
+lookup_method_in_protocol_list (rproto_list, sel_name, class_meth)
+ tree rproto_list;
+ tree sel_name;
+ int class_meth;
+{
+ tree rproto, p;
+ tree fnd = 0;
+
+ for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
+ {
+ p = TREE_VALUE (rproto);
+
+ if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
+ {
+ if ((fnd = lookup_method (class_meth
+ ? PROTOCOL_CLS_METHODS (p)
+ : PROTOCOL_NST_METHODS (p), sel_name)))
+ ;
+ else if (PROTOCOL_LIST (p))
+ fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p),
+ sel_name, class_meth);
+ }
+ else
+ {
+ ; /* An identifier...if we could not find a protocol. */
+ }
+
+ if (fnd)
+ return fnd;
+ }
+
+ return 0;
+}
+
+static tree
+lookup_protocol_in_reflist (rproto_list, lproto)
+ tree rproto_list;
+ tree lproto;
+{
+ tree rproto, p;
+
+ /* Make sure the protocol is support by the object on the rhs. */
+ if (TREE_CODE (lproto) == PROTOCOL_INTERFACE_TYPE)
+ {
+ tree fnd = 0;
+ for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
+ {
+ p = TREE_VALUE (rproto);
+
+ if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
+ {
+ if (lproto == p)
+ fnd = lproto;
+
+ else if (PROTOCOL_LIST (p))
+ fnd = lookup_protocol_in_reflist (PROTOCOL_LIST (p), lproto);
+ }
+
+ if (fnd)
+ return fnd;
+ }
+ }
+ else
+ {
+ ; /* An identifier...if we could not find a protocol. */
+ }
+
+ return 0;
+}
+
+/* Return 1 if LHS and RHS are compatible types for assignment
+ or various other operations. Return 0 if they are incompatible,
+ and return -1 if we choose to not decide. When the operation
+ is REFLEXIVE, check for compatibility in either direction. */
+
+int
+objc_comptypes (lhs, rhs, reflexive)
+ tree lhs;
+ tree rhs;
+ int reflexive;
+{
+ /* New clause for protocols. */
+
+ if (TREE_CODE (lhs) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (lhs)) == RECORD_TYPE
+ && TREE_CODE (rhs) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
+ {
+ int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
+ int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
+
+ if (lhs_is_proto)
+ {
+ tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
+ tree rproto, rproto_list;
+ tree p;
+
+ if (rhs_is_proto)
+ {
+ rproto_list = TYPE_PROTOCOL_LIST (rhs);
+
+ /* Make sure the protocol is supported by the object
+ on the rhs. */
+ for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
+ {
+ p = TREE_VALUE (lproto);
+ rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+ if (!rproto)
+ warning ("object does not conform to the `%s' protocol",
+ IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ }
+ }
+ else if (TYPED_OBJECT (TREE_TYPE (rhs)))
+ {
+ tree rname = TYPE_NAME (TREE_TYPE (rhs));
+ tree rinter;
+
+ /* Make sure the protocol is supported by the object
+ on the rhs. */
+ for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
+ {
+ p = TREE_VALUE (lproto);
+ rproto = 0;
+ rinter = lookup_interface (rname);
+
+ while (rinter && !rproto)
+ {
+ tree cat;
+
+ rproto_list = CLASS_PROTOCOL_LIST (rinter);
+ rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+ /* Check for protocols adopted by categories. */
+ cat = CLASS_CATEGORY_LIST (rinter);
+ while (cat && !rproto)
+ {
+ rproto_list = CLASS_PROTOCOL_LIST (cat);
+ rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+ cat = CLASS_CATEGORY_LIST (cat);
+ }
+
+ rinter = lookup_interface (CLASS_SUPER_NAME (rinter));
+ }
+
+ if (!rproto)
+ warning ("class `%s' does not implement the `%s' protocol",
+ IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))),
+ IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ }
+ }
+
+ /* May change...based on whether there was any mismatch */
+ return 1;
+ }
+ else if (rhs_is_proto)
+ /* Lhs is not a protocol...warn if it is statically typed */
+ return (TYPED_OBJECT (TREE_TYPE (lhs)) != 0);
+
+ else
+ /* Defer to comptypes .*/
+ return -1;
+ }
+
+ else if (TREE_CODE (lhs) == RECORD_TYPE && TREE_CODE (rhs) == RECORD_TYPE)
+ ; /* Fall thru. This is the case we have been handling all along */
+ else
+ /* Defer to comptypes. */
+ return -1;
+
+ /* `id' = `<class> *', `<class> *' = `id' */
+
+ if ((TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs))
+ || (TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs)))
+ return 1;
+
+ /* `id' = `Class', `Class' = `id' */
+
+ else if ((TYPE_NAME (lhs) == objc_object_id
+ && TYPE_NAME (rhs) == objc_class_id)
+ || (TYPE_NAME (lhs) == objc_class_id
+ && TYPE_NAME (rhs) == objc_object_id))
+ return 1;
+
+ /* `<class> *' = `<class> *' */
+
+ else if (TYPED_OBJECT (lhs) && TYPED_OBJECT (rhs))
+ {
+ tree lname = TYPE_NAME (lhs);
+ tree rname = TYPE_NAME (rhs);
+ tree inter;
+
+ if (lname == rname)
+ return 1;
+
+ /* If the left hand side is a super class of the right hand side,
+ allow it. */
+ for (inter = lookup_interface (rname); inter;
+ inter = lookup_interface (CLASS_SUPER_NAME (inter)))
+ if (lname == CLASS_SUPER_NAME (inter))
+ return 1;
+
+ /* Allow the reverse when reflexive. */
+ if (reflexive)
+ for (inter = lookup_interface (lname); inter;
+ inter = lookup_interface (CLASS_SUPER_NAME (inter)))
+ if (rname == CLASS_SUPER_NAME (inter))
+ return 1;
+
+ return 0;
+ }
+ else
+ /* Defer to comptypes. */
+ return -1;
+}
+
+/* Called from c-decl.c before all calls to rest_of_decl_compilation. */
+
+void
+objc_check_decl (decl)
+ tree decl;
+{
+ tree type = TREE_TYPE (decl);
+
+ if (TREE_CODE (type) == RECORD_TYPE
+ && TREE_STATIC_TEMPLATE (type)
+ && type != constant_string_type)
+ {
+ error_with_decl (decl, "`%s' cannot be statically allocated");
+ fatal ("statically allocated objects not supported");
+ }
+}
+
+void
+maybe_objc_check_decl (decl)
+ tree decl;
+{
+ if (doing_objc_thang)
+ objc_check_decl (decl);
+}
+
+/* Implement static typing. At this point, we know we have an interface. */
+
+tree
+get_static_reference (interface, protocols)
+ tree interface;
+ tree protocols;
+{
+ tree type = xref_tag (RECORD_TYPE, interface);
+
+ if (protocols)
+ {
+ tree t, m = TYPE_MAIN_VARIANT (type);
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ t = copy_node (type);
+ TYPE_BINFO (t) = make_tree_vec (2);
+ pop_obstacks ();
+
+ /* Add this type to the chain of variants of TYPE. */
+ TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
+ TYPE_NEXT_VARIANT (m) = t;
+
+ /* Look up protocols and install in lang specific list. */
+ TYPE_PROTOCOL_LIST (t) = lookup_and_install_protocols (protocols);
+
+ /* This forces a new pointer type to be created later
+ (in build_pointer_type)...so that the new template
+ we just created will actually be used...what a hack! */
+ if (TYPE_POINTER_TO (t))
+ TYPE_POINTER_TO (t) = 0;
+
+ type = t;
+ }
+
+ return type;
+}
+
+tree
+get_object_reference (protocols)
+ tree protocols;
+{
+ tree type_decl = lookup_name (objc_id_id);
+ tree type;
+
+ if (type_decl && TREE_CODE (type_decl) == TYPE_DECL)
+ {
+ type = TREE_TYPE (type_decl);
+ if (TYPE_MAIN_VARIANT (type) != id_type)
+ warning ("Unexpected type for `id' (%s)",
+ gen_declaration (type, errbuf));
+ }
+ else
+ fatal ("Undefined type `id', please import <objc/objc.h>");
+
+ /* This clause creates a new pointer type that is qualified with
+ the protocol specification...this info is used later to do more
+ elaborate type checking. */
+
+ if (protocols)
+ {
+ tree t, m = TYPE_MAIN_VARIANT (type);
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ t = copy_node (type);
+ TYPE_BINFO (t) = make_tree_vec (2);
+ pop_obstacks ();
+
+ /* Add this type to the chain of variants of TYPE. */
+ TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
+ TYPE_NEXT_VARIANT (m) = t;
+
+ /* Look up protocols...and install in lang specific list */
+ TYPE_PROTOCOL_LIST (t) = lookup_and_install_protocols (protocols);
+
+ /* This forces a new pointer type to be created later
+ (in build_pointer_type)...so that the new template
+ we just created will actually be used...what a hack! */
+ if (TYPE_POINTER_TO (t))
+ TYPE_POINTER_TO (t) = NULL;
+
+ type = t;
+ }
+ return type;
+}
+
+static tree
+lookup_and_install_protocols (protocols)
+ tree protocols;
+{
+ tree proto;
+ tree prev = NULL;
+ tree return_value = protocols;
+
+ for (proto = protocols; proto; proto = TREE_CHAIN (proto))
+ {
+ tree ident = TREE_VALUE (proto);
+ tree p = lookup_protocol (ident);
+
+ if (!p)
+ {
+ error ("Cannot find protocol declaration for `%s'",
+ IDENTIFIER_POINTER (ident));
+ if (prev)
+ TREE_CHAIN (prev) = TREE_CHAIN (proto);
+ else
+ return_value = TREE_CHAIN (proto);
+ }
+ else
+ {
+ /* Replace identifier with actual protocol node. */
+ TREE_VALUE (proto) = p;
+ prev = proto;
+ }
+ }
+
+ return return_value;
+}
+
+/* Create and push a decl for a built-in external variable or field NAME.
+ CODE says which.
+ TYPE is its data type. */
+
+static tree
+create_builtin_decl (code, type, name)
+ enum tree_code code;
+ tree type;
+ char *name;
+{
+ tree decl = build_decl (code, get_identifier (name), type);
+
+ if (code == VAR_DECL)
+ {
+ TREE_STATIC (decl) = 1;
+ make_decl_rtl (decl, 0, 1);
+ pushdecl (decl);
+ }
+
+ DECL_ARTIFICIAL (decl) = 1;
+ return decl;
+}
+
+/* Purpose: "play" parser, creating/installing representations
+ of the declarations that are required by Objective-C.
+
+ Model:
+
+ type_spec--------->sc_spec
+ (tree_list) (tree_list)
+ | |
+ | |
+ identifier_node identifier_node */
+
+static void
+synth_module_prologue ()
+{
+ tree temp_type;
+ tree super_p;
+
+ /* Defined in `objc.h' */
+ objc_object_id = get_identifier (TAG_OBJECT);
+
+ objc_object_reference = xref_tag (RECORD_TYPE, objc_object_id);
+
+ id_type = build_pointer_type (objc_object_reference);
+
+ objc_id_id = get_identifier (TYPE_ID);
+ objc_class_id = get_identifier (TAG_CLASS);
+
+ objc_class_type = build_pointer_type (xref_tag (RECORD_TYPE, objc_class_id));
+ protocol_type = build_pointer_type (xref_tag (RECORD_TYPE,
+ get_identifier (PROTOCOL_OBJECT_CLASS_NAME)));
+
+ /* Declare type of selector-objects that represent an operation name. */
+
+#ifdef OBJC_INT_SELECTORS
+ /* `unsigned int' */
+ selector_type = unsigned_type_node;
+#else
+ /* `struct objc_selector *' */
+ selector_type
+ = build_pointer_type (xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SELECTOR)));
+#endif /* not OBJC_INT_SELECTORS */
+
+ /* Forward declare type, or else the prototype for msgSendSuper will
+ complain. */
+
+ super_p = build_pointer_type (xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SUPER)));
+
+
+ /* id objc_msgSend (id, SEL, ...); */
+
+ temp_type
+ = build_function_type (id_type,
+ tree_cons (NULL_TREE, id_type,
+ tree_cons (NULL_TREE, selector_type,
+ NULL_TREE)));
+
+ if (! flag_next_runtime)
+ {
+ umsg_decl = build_decl (FUNCTION_DECL,
+ get_identifier (TAG_MSGSEND), temp_type);
+ DECL_EXTERNAL (umsg_decl) = 1;
+ TREE_PUBLIC (umsg_decl) = 1;
+ DECL_INLINE (umsg_decl) = 1;
+ DECL_ARTIFICIAL (umsg_decl) = 1;
+
+ if (flag_traditional && TAG_MSGSEND[0] != '_')
+ DECL_BUILT_IN_NONANSI (umsg_decl) = 1;
+
+ make_decl_rtl (umsg_decl, NULL_PTR, 1);
+ pushdecl (umsg_decl);
+ }
+ else
+ umsg_decl = builtin_function (TAG_MSGSEND, temp_type, NOT_BUILT_IN, 0);
+
+ /* id objc_msgSendSuper (struct objc_super *, SEL, ...); */
+
+ temp_type
+ = build_function_type (id_type,
+ tree_cons (NULL_TREE, super_p,
+ tree_cons (NULL_TREE, selector_type,
+ NULL_TREE)));
+
+ umsg_super_decl = builtin_function (TAG_MSGSENDSUPER,
+ temp_type, NOT_BUILT_IN, 0);
+
+ /* id objc_getClass (const char *); */
+
+ temp_type = build_function_type (id_type,
+ tree_cons (NULL_TREE,
+ const_string_type_node,
+ tree_cons (NULL_TREE, void_type_node,
+ NULL_TREE)));
+
+ objc_get_class_decl
+ = builtin_function (TAG_GETCLASS, temp_type, NOT_BUILT_IN, 0);
+
+ /* id objc_getMetaClass (const char *); */
+
+ objc_get_meta_class_decl
+ = builtin_function (TAG_GETMETACLASS, temp_type, NOT_BUILT_IN, 0);
+
+ /* static SEL _OBJC_SELECTOR_TABLE[]; */
+
+ if (! flag_next_runtime)
+ {
+ if (flag_typed_selectors)
+ {
+ /* Suppress outputting debug symbols, because
+ dbxout_init hasn'r been called yet. */
+ enum debug_info_type save_write_symbols = write_symbols;
+ write_symbols = NO_DEBUG;
+
+ build_selector_template ();
+ temp_type = build_array_type (objc_selector_template, NULL_TREE);
+
+ write_symbols = save_write_symbols;
+ }
+ else
+ temp_type = build_array_type (selector_type, NULL_TREE);
+
+ layout_type (temp_type);
+ UOBJC_SELECTOR_TABLE_decl
+ = create_builtin_decl (VAR_DECL, temp_type,
+ "_OBJC_SELECTOR_TABLE");
+
+ /* Avoid warning when not sending messages. */
+ TREE_USED (UOBJC_SELECTOR_TABLE_decl) = 1;
+ }
+
+ generate_forward_declaration_to_string_table ();
+
+ /* Forward declare constant_string_id and constant_string_type. */
+ constant_string_id = get_identifier (STRING_OBJECT_CLASS_NAME);
+ constant_string_type = xref_tag (RECORD_TYPE, constant_string_id);
+}
+
+/* Custom build_string which sets TREE_TYPE! */
+
+static tree
+my_build_string (len, str)
+ int len;
+ char *str;
+{
+ int wide_flag = 0;
+ tree a_string = build_string (len, str);
+
+ /* Some code from combine_strings, which is local to c-parse.y. */
+ if (TREE_TYPE (a_string) == int_array_type_node)
+ wide_flag = 1;
+
+ TREE_TYPE (a_string)
+ = build_array_type (wide_flag ? integer_type_node : char_type_node,
+ build_index_type (build_int_2 (len - 1, 0)));
+
+ TREE_CONSTANT (a_string) = 1; /* Puts string in the readonly segment */
+ TREE_STATIC (a_string) = 1;
+
+ return a_string;
+}
+
+/* Return a newly constructed OBJC_STRING_CST node whose value is
+ the LEN characters at STR.
+ The TREE_TYPE is not initialized. */
+
+tree
+build_objc_string (len, str)
+ int len;
+ char *str;
+{
+ tree s = build_string (len, str);
+
+ TREE_SET_CODE (s, OBJC_STRING_CST);
+ return s;
+}
+
+/* Given a chain of OBJC_STRING_CST's, build a static instance of
+ NXConstanString which points at the concatenation of those strings.
+ We place the string object in the __string_objects section of the
+ __OBJC segment. The Objective-C runtime will initialize the isa
+ pointers of the string objects to point at the NXConstandString class
+ object. */
+
+tree
+build_objc_string_object (strings)
+ tree strings;
+{
+ tree string, initlist, constructor;
+ int length;
+
+ if (!doing_objc_thang)
+ objc_fatal ();
+
+ if (lookup_interface (constant_string_id) == NULL_TREE)
+ {
+ error ("Cannot find interface declaration for `%s'",
+ IDENTIFIER_POINTER (constant_string_id));
+ return error_mark_node;
+ }
+
+ add_class_reference (constant_string_id);
+
+ /* Combine_strings will work for OBJC_STRING_CST's too. */
+ string = combine_strings (strings);
+ TREE_SET_CODE (string, STRING_CST);
+ length = TREE_STRING_LENGTH (string) - 1;
+
+ if (! flag_next_runtime)
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ if (! TREE_PERMANENT (strings))
+ string = my_build_string (length + 1,
+ TREE_STRING_POINTER (string));
+ }
+
+ /* & ((NXConstantString) {0, string, length}) */
+
+ initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0));
+ initlist
+ = tree_cons (NULL_TREE, copy_node (build_unary_op (ADDR_EXPR, string, 1)),
+ initlist);
+ initlist = tree_cons (NULL_TREE, build_int_2 (length, 0), initlist);
+ constructor = build_constructor (constant_string_type, nreverse (initlist));
+
+ if (!flag_next_runtime)
+ {
+ constructor
+ = objc_add_static_instance (constructor, constant_string_type);
+ pop_obstacks ();
+ }
+
+ return (build_unary_op (ADDR_EXPR, constructor, 1));
+}
+
+/* Declare a static instance of CLASS_DECL initialized by CONSTRUCTOR. */
+
+static tree
+objc_add_static_instance (constructor, class_decl)
+ tree constructor, class_decl;
+{
+ static int num_static_inst;
+ tree *chain, decl;
+ char buf[256];
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ /* Find the list of static instances for the CLASS_DECL. Create one if
+ not found. */
+ for (chain = &objc_static_instances;
+ *chain && TREE_VALUE (*chain) != class_decl;
+ chain = &TREE_CHAIN (*chain));
+ if (!*chain)
+ {
+ *chain = tree_cons (NULL_TREE, class_decl, NULL_TREE);
+ add_objc_string (TYPE_NAME (class_decl), class_names);
+ }
+
+ sprintf (buf, "_OBJC_INSTANCE_%d", num_static_inst++);
+ decl = build_decl (VAR_DECL, get_identifier (buf), class_decl);
+ DECL_COMMON (decl) = 1;
+ TREE_STATIC (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ pushdecl_top_level (decl);
+ rest_of_decl_compilation (decl, 0, 1, 0);
+
+ /* Do this here so it gets output later instead of possibly
+ inside something else we are writing. */
+ DECL_INITIAL (decl) = constructor;
+
+ /* Add the DECL to the head of this CLASS' list. */
+ TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, decl, TREE_PURPOSE (*chain));
+
+ pop_obstacks ();
+ return decl;
+}
+
+/* Build a static constant CONSTRUCTOR
+ with type TYPE and elements ELTS. */
+
+static tree
+build_constructor (type, elts)
+ tree type, elts;
+{
+ tree constructor = build (CONSTRUCTOR, type, NULL_TREE, elts);
+
+ TREE_CONSTANT (constructor) = 1;
+ TREE_STATIC (constructor) = 1;
+ TREE_READONLY (constructor) = 1;
+
+ return constructor;
+}
+
+/* Take care of defining and initializing _OBJC_SYMBOLS. */
+
+/* Predefine the following data type:
+
+ struct _objc_symtab
+ {
+ long sel_ref_cnt;
+ SEL *refs;
+ short cls_def_cnt;
+ short cat_def_cnt;
+ void *defs[cls_def_cnt + cat_def_cnt];
+ }; */
+
+static void
+build_objc_symtab_template ()
+{
+ tree field_decl, field_decl_chain, index;
+
+ objc_symtab_template
+ = start_struct (RECORD_TYPE, get_identifier (UTAG_SYMTAB));
+
+ /* long sel_ref_cnt; */
+
+ field_decl = create_builtin_decl (FIELD_DECL,
+ long_integer_type_node,
+ "sel_ref_cnt");
+ field_decl_chain = field_decl;
+
+ /* SEL *refs; */
+
+ field_decl = create_builtin_decl (FIELD_DECL,
+ build_pointer_type (selector_type),
+ "refs");
+ chainon (field_decl_chain, field_decl);
+
+ /* short cls_def_cnt; */
+
+ field_decl = create_builtin_decl (FIELD_DECL,
+ short_integer_type_node,
+ "cls_def_cnt");
+ chainon (field_decl_chain, field_decl);
+
+ /* short cat_def_cnt; */
+
+ field_decl = create_builtin_decl (FIELD_DECL,
+ short_integer_type_node,
+ "cat_def_cnt");
+ chainon (field_decl_chain, field_decl);
+
+ /* void *defs[cls_def_cnt + cat_def_cnt]; */
+
+ if (!flag_next_runtime)
+ index = build_index_type (build_int_2 (imp_count + cat_count, 0));
+ else
+ index = build_index_type (build_int_2 (imp_count + cat_count - 1,
+ imp_count == 0 && cat_count == 0
+ ? -1 : 0));
+ field_decl = create_builtin_decl (FIELD_DECL,
+ build_array_type (ptr_type_node, index),
+ "defs");
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (objc_symtab_template, field_decl_chain, NULL_TREE);
+}
+
+/* Create the initial value for the `defs' field of _objc_symtab.
+ This is a CONSTRUCTOR. */
+
+static tree
+init_def_list (type)
+ tree type;
+{
+ tree expr, initlist = NULL_TREE;
+ struct imp_entry *impent;
+
+ if (imp_count)
+ for (impent = imp_list; impent; impent = impent->next)
+ {
+ if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE)
+ {
+ expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+ }
+
+ if (cat_count)
+ for (impent = imp_list; impent; impent = impent->next)
+ {
+ if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
+ {
+ expr = build_unary_op (ADDR_EXPR, impent->class_decl, 0);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+ }
+
+ if (!flag_next_runtime)
+ {
+ /* statics = { ..., _OBJC_STATIC_INSTANCES, ... } */
+ tree expr;
+
+ if (static_instances_decl)
+ expr = build_unary_op (ADDR_EXPR, static_instances_decl, 0);
+ else
+ expr = build_int_2 (0, 0);
+
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+
+ return build_constructor (type, nreverse (initlist));
+}
+
+/* Construct the initial value for all of _objc_symtab. */
+
+static tree
+init_objc_symtab (type)
+ tree type;
+{
+ tree initlist;
+
+ /* sel_ref_cnt = { ..., 5, ... } */
+
+ initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0));
+
+ /* refs = { ..., _OBJC_SELECTOR_TABLE, ... } */
+
+ if (flag_next_runtime || ! sel_ref_chain)
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ else
+ initlist = tree_cons (NULL_TREE,
+ build_unary_op (ADDR_EXPR,
+ UOBJC_SELECTOR_TABLE_decl, 1),
+ initlist);
+
+ /* cls_def_cnt = { ..., 5, ... } */
+
+ initlist = tree_cons (NULL_TREE, build_int_2 (imp_count, 0), initlist);
+
+ /* cat_def_cnt = { ..., 5, ... } */
+
+ initlist = tree_cons (NULL_TREE, build_int_2 (cat_count, 0), initlist);
+
+ /* cls_def = { ..., { &Foo, &Bar, ...}, ... } */
+
+ if (imp_count || cat_count || static_instances_decl)
+ {
+
+ tree field = TYPE_FIELDS (type);
+ field = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (field))));
+
+ initlist = tree_cons (NULL_TREE, init_def_list (TREE_TYPE (field)),
+ initlist);
+ }
+
+ return build_constructor (type, nreverse (initlist));
+}
+
+/* Push forward-declarations of all the categories
+ so that init_def_list can use them in a CONSTRUCTOR. */
+
+static void
+forward_declare_categories ()
+{
+ struct imp_entry *impent;
+ tree sav = implementation_context;
+
+ for (impent = imp_list; impent; impent = impent->next)
+ {
+ if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
+ {
+ /* Set an invisible arg to synth_id_with_class_suffix. */
+ implementation_context = impent->imp_context;
+ impent->class_decl
+ = create_builtin_decl (VAR_DECL, objc_category_template,
+ IDENTIFIER_POINTER (synth_id_with_class_suffix ("_OBJC_CATEGORY", implementation_context)));
+ }
+ }
+ implementation_context = sav;
+}
+
+/* Create the declaration of _OBJC_SYMBOLS, with type `strict _objc_symtab'
+ and initialized appropriately. */
+
+static void
+generate_objc_symtab_decl ()
+{
+ tree sc_spec;
+
+ if (!objc_category_template)
+ build_category_template ();
+
+ /* forward declare categories */
+ if (cat_count)
+ forward_declare_categories ();
+
+ if (!objc_symtab_template)
+ build_objc_symtab_template ();
+
+ sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]);
+
+ UOBJC_SYMBOLS_decl = start_decl (get_identifier ("_OBJC_SYMBOLS"),
+ tree_cons (NULL_TREE,
+ objc_symtab_template, sc_spec),
+ 1,
+ NULL_TREE, NULL_TREE);
+
+ TREE_USED (UOBJC_SYMBOLS_decl) = 1;
+ DECL_IGNORED_P (UOBJC_SYMBOLS_decl) = 1;
+ DECL_ARTIFICIAL (UOBJC_SYMBOLS_decl) = 1;
+ finish_decl (UOBJC_SYMBOLS_decl,
+ init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl)),
+ NULL_TREE);
+}
+
+static tree
+init_module_descriptor (type)
+ tree type;
+{
+ tree initlist, expr;
+
+ /* version = { 1, ... } */
+
+ expr = build_int_2 (OBJC_VERSION, 0);
+ initlist = build_tree_list (NULL_TREE, expr);
+
+ /* size = { ..., sizeof (struct objc_module), ... } */
+
+ expr = size_in_bytes (objc_module_template);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+
+ /* name = { ..., "foo.m", ... } */
+
+ expr = add_objc_string (get_identifier (input_filename), class_names);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+
+ /* symtab = { ..., _OBJC_SYMBOLS, ... } */
+
+ if (UOBJC_SYMBOLS_decl)
+ expr = build_unary_op (ADDR_EXPR, UOBJC_SYMBOLS_decl, 0);
+ else
+ expr = build_int_2 (0, 0);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+
+ return build_constructor (type, nreverse (initlist));
+}
+
+/* Write out the data structures to describe Objective C classes defined.
+ If appropriate, compile and output a setup function to initialize them.
+ Return a string which is the name of a function to call to initialize
+ the Objective C data structures for this file (and perhaps for other files
+ also).
+
+ struct objc_module { ... } _OBJC_MODULE = { ... }; */
+
+static char *
+build_module_descriptor ()
+{
+ tree decl_specs, field_decl, field_decl_chain;
+
+ objc_module_template
+ = start_struct (RECORD_TYPE, get_identifier (UTAG_MODULE));
+
+ /* Long version; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]);
+ field_decl = get_identifier ("version");
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ /* long size; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]);
+ field_decl = get_identifier ("size");
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* char *name; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("name"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_symtab *symtab; */
+
+ decl_specs = get_identifier (UTAG_SYMTAB);
+ decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, decl_specs));
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("symtab"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (objc_module_template, field_decl_chain, NULL_TREE);
+
+ /* Create an instance of "objc_module". */
+
+ decl_specs = tree_cons (NULL_TREE, objc_module_template,
+ build_tree_list (NULL_TREE,
+ ridpointers[(int) RID_STATIC]));
+
+ UOBJC_MODULES_decl = start_decl (get_identifier ("_OBJC_MODULES"),
+ decl_specs, 1, NULL_TREE, NULL_TREE);
+
+ DECL_ARTIFICIAL (UOBJC_MODULES_decl) = 1;
+ DECL_IGNORED_P (UOBJC_MODULES_decl) = 1;
+ finish_decl (UOBJC_MODULES_decl,
+ init_module_descriptor (TREE_TYPE (UOBJC_MODULES_decl)),
+ NULL_TREE);
+
+ /* Mark the decl to avoid "defined but not used" warning. */
+ DECL_IN_SYSTEM_HEADER (UOBJC_MODULES_decl) = 1;
+
+ /* Generate a constructor call for the module descriptor.
+ This code was generated by reading the grammar rules
+ of c-parse.in; Therefore, it may not be the most efficient
+ way of generating the requisite code. */
+
+ if (flag_next_runtime)
+ return 0;
+
+ {
+ tree parms, function_decl, decelerator, void_list_node;
+ tree function_type;
+ tree init_function_name = get_file_function_name ('I');
+
+ /* Declare void __objc_execClass (void *); */
+
+ void_list_node = build_tree_list (NULL_TREE, void_type_node);
+ function_type
+ = build_function_type (void_type_node,
+ tree_cons (NULL_TREE, ptr_type_node,
+ void_list_node));
+ function_decl = build_decl (FUNCTION_DECL,
+ get_identifier (TAG_EXECCLASS),
+ function_type);
+ DECL_EXTERNAL (function_decl) = 1;
+ DECL_ARTIFICIAL (function_decl) = 1;
+ TREE_PUBLIC (function_decl) = 1;
+
+ pushdecl (function_decl);
+ rest_of_decl_compilation (function_decl, 0, 0, 0);
+
+ parms
+ = build_tree_list (NULL_TREE,
+ build_unary_op (ADDR_EXPR, UOBJC_MODULES_decl, 0));
+ decelerator = build_function_call (function_decl, parms);
+
+ /* void _GLOBAL_$I$<gnyf> () {objc_execClass (&L_OBJC_MODULES);} */
+
+ start_function (void_list_node,
+ build_parse_node (CALL_EXPR, init_function_name,
+ /* This has the format of the output
+ of get_parm_info. */
+ tree_cons (NULL_TREE, NULL_TREE,
+ void_list_node),
+ NULL_TREE),
+ NULL_TREE, NULL_TREE, 0);
+#if 0 /* This should be turned back on later
+ for the systems where collect is not needed. */
+ /* Make these functions nonglobal
+ so each file can use the same name. */
+ TREE_PUBLIC (current_function_decl) = 0;
+#endif
+ TREE_USED (current_function_decl) = 1;
+ store_parm_decls ();
+
+ assemble_external (function_decl);
+ c_expand_expr_stmt (decelerator);
+
+ TREE_PUBLIC (current_function_decl) = 1;
+
+ function_decl = current_function_decl;
+ finish_function (0);
+
+ /* Return the name of the constructor function. */
+ return XSTR (XEXP (DECL_RTL (function_decl), 0), 0);
+ }
+}
+
+/* extern const char _OBJC_STRINGS[]; */
+
+static void
+generate_forward_declaration_to_string_table ()
+{
+ tree sc_spec, decl_specs, expr_decl;
+
+ sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_EXTERN], NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
+
+ expr_decl
+ = build_nt (ARRAY_REF, get_identifier ("_OBJC_STRINGS"), NULL_TREE);
+
+ UOBJC_STRINGS_decl = define_decl (expr_decl, decl_specs);
+}
+
+/* Return the DECL of the string IDENT in the SECTION. */
+
+static tree
+get_objc_string_decl (ident, section)
+ tree ident;
+ enum string_section section;
+{
+ tree chain;
+
+ if (section == class_names)
+ chain = class_names_chain;
+ else if (section == meth_var_names)
+ chain = meth_var_names_chain;
+ else if (section == meth_var_types)
+ chain = meth_var_types_chain;
+
+ for (; chain != 0; chain = TREE_VALUE (chain))
+ if (TREE_VALUE (chain) == ident)
+ return (TREE_PURPOSE (chain));
+
+ abort ();
+ return NULL_TREE;
+}
+
+/* Output references to all statically allocated objects. Return the DECL
+ for the array built. */
+
+static void
+generate_static_references ()
+{
+ tree decls = NULL_TREE, ident, decl_spec, expr_decl, expr = NULL_TREE;
+ tree class_name, class, decl, initlist;
+ tree cl_chain, in_chain, type;
+ int num_inst, num_class;
+ char buf[256];
+
+ if (flag_next_runtime)
+ abort ();
+
+ for (cl_chain = objc_static_instances, num_class = 0;
+ cl_chain; cl_chain = TREE_CHAIN (cl_chain), num_class++)
+ {
+ for (num_inst = 0, in_chain = TREE_PURPOSE (cl_chain);
+ in_chain; num_inst++, in_chain = TREE_CHAIN (in_chain));
+
+ sprintf (buf, "_OBJC_STATIC_INSTANCES_%d", num_class);
+ ident = get_identifier (buf);
+
+ expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE);
+ decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node),
+ build_tree_list (NULL_TREE,
+ ridpointers[(int) RID_STATIC]));
+ decl = start_decl (expr_decl, decl_spec, 1, NULL_TREE, NULL_TREE);
+ DECL_CONTEXT (decl) = 0;
+ DECL_ARTIFICIAL (decl) = 1;
+
+ /* Output {class_name, ...}. */
+ class = TREE_VALUE (cl_chain);
+ class_name = get_objc_string_decl (TYPE_NAME (class), class_names);
+ initlist = build_tree_list (NULL_TREE,
+ build_unary_op (ADDR_EXPR, class_name, 1));
+
+ /* Output {..., instance, ...}. */
+ for (in_chain = TREE_PURPOSE (cl_chain);
+ in_chain; in_chain = TREE_CHAIN (in_chain))
+ {
+ expr = build_unary_op (ADDR_EXPR, TREE_VALUE (in_chain), 1);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+
+ /* Output {..., NULL}. */
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+
+ expr = build_constructor (TREE_TYPE (decl), nreverse (initlist));
+ finish_decl (decl, expr, NULL_TREE);
+ TREE_USED (decl) = 1;
+
+ type = build_array_type (build_pointer_type (void_type_node), 0);
+ decl = build_decl (VAR_DECL, ident, type);
+ make_decl_rtl (decl, 0, 1);
+ TREE_USED (decl) = 1;
+ decls
+ = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, decl, 1), decls);
+ }
+
+ decls = tree_cons (NULL_TREE, build_int_2 (0, 0), decls);
+ ident = get_identifier ("_OBJC_STATIC_INSTANCES");
+ expr_decl = build_nt (ARRAY_REF, ident, NULL_TREE);
+ decl_spec = tree_cons (NULL_TREE, build_pointer_type (void_type_node),
+ build_tree_list (NULL_TREE,
+ ridpointers[(int) RID_STATIC]));
+ static_instances_decl
+ = start_decl (expr_decl, decl_spec, 1, NULL_TREE, NULL_TREE);
+ TREE_USED (static_instances_decl) = 1;
+ DECL_CONTEXT (static_instances_decl) = 0;
+ DECL_ARTIFICIAL (static_instances_decl) = 1;
+ end_temporary_allocation ();
+ expr = build_constructor (TREE_TYPE (static_instances_decl),
+ nreverse (decls));
+ finish_decl (static_instances_decl, expr, NULL_TREE);
+}
+
+/* Output all strings. */
+
+static void
+generate_strings ()
+{
+ tree sc_spec, decl_specs, expr_decl;
+ tree chain, string_expr;
+ tree string, decl;
+
+ for (chain = class_names_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ string = TREE_VALUE (chain);
+ decl = TREE_PURPOSE (chain);
+ sc_spec
+ = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
+ expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+ decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE);
+ end_temporary_allocation ();
+ string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
+ IDENTIFIER_POINTER (string));
+ finish_decl (decl, string_expr, NULL_TREE);
+ }
+
+ for (chain = meth_var_names_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ string = TREE_VALUE (chain);
+ decl = TREE_PURPOSE (chain);
+ sc_spec
+ = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
+ expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+ decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE);
+ string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
+ IDENTIFIER_POINTER (string));
+ finish_decl (decl, string_expr, NULL_TREE);
+ }
+
+ for (chain = meth_var_types_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ string = TREE_VALUE (chain);
+ decl = TREE_PURPOSE (chain);
+ sc_spec
+ = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], sc_spec);
+ expr_decl = build_nt (ARRAY_REF, DECL_NAME (decl), NULL_TREE);
+ decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE);
+ string_expr = my_build_string (IDENTIFIER_LENGTH (string) + 1,
+ IDENTIFIER_POINTER (string));
+ finish_decl (decl, string_expr, NULL_TREE);
+ }
+}
+
+static tree
+build_selector_reference_decl (name)
+ tree name;
+{
+ tree decl, ident;
+ char buf[256];
+ static int idx = 0;
+
+ sprintf (buf, "_OBJC_SELECTOR_REFERENCES_%d", idx++);
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ ident = get_identifier (buf);
+
+ decl = build_decl (VAR_DECL, ident, selector_type);
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ TREE_USED (decl) = 1;
+ TREE_READONLY (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_CONTEXT (decl) = 0;
+
+ make_decl_rtl (decl, 0, 1);
+ pushdecl_top_level (decl);
+
+ pop_obstacks ();
+
+ return decl;
+}
+
+/* Just a handy wrapper for add_objc_string. */
+
+static tree
+build_selector (ident)
+ tree ident;
+{
+ tree expr = add_objc_string (ident, meth_var_names);
+ if (flag_typed_selectors)
+ return expr;
+ else
+ return build_c_cast (selector_type, expr); /* cast! */
+}
+
+/* Synthesize the following expr: (char *)&_OBJC_STRINGS[<offset>]
+ The cast stops the compiler from issuing the following message:
+ grok.m: warning: initialization of non-const * pointer from const *
+ grok.m: warning: initialization between incompatible pointer types. */
+
+#if 0
+static tree
+build_msg_pool_reference (offset)
+ int offset;
+{
+ tree expr = build_int_2 (offset, 0);
+ tree cast;
+
+ expr = build_array_ref (UOBJC_STRINGS_decl, expr);
+ expr = build_unary_op (ADDR_EXPR, expr, 0);
+
+ cast = build_tree_list (build_tree_list (NULL_TREE,
+ ridpointers[(int) RID_CHAR]),
+ build1 (INDIRECT_REF, NULL_TREE, NULL_TREE));
+ TREE_TYPE (expr) = groktypename (cast);
+ return expr;
+}
+
+static tree
+init_selector (offset)
+ int offset;
+{
+ tree expr = build_msg_pool_reference (offset);
+ TREE_TYPE (expr) = selector_type;
+ return expr;
+}
+#endif
+
+static void
+build_selector_translation_table ()
+{
+ tree sc_spec, decl_specs;
+ tree chain, initlist = NULL_TREE;
+ int offset = 0;
+ tree decl, var_decl, name;
+
+ /* The corresponding pop_obstacks is in finish_decl,
+ called at the end of this function. */
+ if (! flag_next_runtime)
+ push_obstacks_nochange ();
+
+ for (chain = sel_ref_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ tree expr;
+
+ expr = build_selector (TREE_VALUE (chain));
+
+ if (flag_next_runtime)
+ {
+ name = DECL_NAME (TREE_PURPOSE (chain));
+
+ sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]);
+
+ /* static SEL _OBJC_SELECTOR_REFERENCES_n = ...; */
+ decl_specs = tree_cons (NULL_TREE, selector_type, sc_spec);
+
+ var_decl = name;
+
+ /* The `decl' that is returned from start_decl is the one that we
+ forward declared in `build_selector_reference' */
+ decl = start_decl (var_decl, decl_specs, 1, NULL_TREE, NULL_TREE);
+ }
+
+ /* add one for the '\0' character */
+ offset += IDENTIFIER_LENGTH (TREE_VALUE (chain)) + 1;
+
+ if (flag_next_runtime)
+ finish_decl (decl, expr, NULL_TREE);
+ else
+ {
+ if (flag_typed_selectors)
+ {
+ tree eltlist = NULL_TREE;
+ tree encoding = get_proto_encoding (TREE_PURPOSE (chain));
+ eltlist = tree_cons (NULL_TREE, expr, NULL_TREE);
+ eltlist = tree_cons (NULL_TREE, encoding, eltlist);
+ expr = build_constructor (objc_selector_template,
+ nreverse (eltlist));
+ }
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+
+ }
+ }
+
+ if (! flag_next_runtime)
+ {
+ /* Cause the variable and its initial value to be actually output. */
+ DECL_EXTERNAL (UOBJC_SELECTOR_TABLE_decl) = 0;
+ TREE_STATIC (UOBJC_SELECTOR_TABLE_decl) = 1;
+ /* NULL terminate the list and fix the decl for output. */
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ DECL_INITIAL (UOBJC_SELECTOR_TABLE_decl) = (tree) 1;
+ initlist = build_constructor (TREE_TYPE (UOBJC_SELECTOR_TABLE_decl),
+ nreverse (initlist));
+ finish_decl (UOBJC_SELECTOR_TABLE_decl, initlist, NULL_TREE);
+ current_function_decl = NULL_TREE;
+ }
+}
+
+static tree
+get_proto_encoding (proto)
+ tree proto;
+{
+ tree encoding;
+ if (proto)
+ {
+ tree tmp_decl;
+
+ if (! METHOD_ENCODING (proto))
+ {
+ tmp_decl = build_tmp_function_decl ();
+ hack_method_prototype (proto, tmp_decl);
+ encoding = encode_method_prototype (proto, tmp_decl);
+ METHOD_ENCODING (proto) = encoding;
+ }
+ else
+ encoding = METHOD_ENCODING (proto);
+
+ return add_objc_string (encoding, meth_var_types);
+ }
+ else
+ return build_int_2 (0, 0);
+}
+
+/* sel_ref_chain is a list whose "value" fields will be instances of
+ identifier_node that represent the selector. */
+
+static tree
+build_typed_selector_reference (ident, proto)
+ tree ident, proto;
+{
+ tree *chain = &sel_ref_chain;
+ tree expr;
+ int index = 0;
+
+ while (*chain)
+ {
+ if (TREE_PURPOSE (*chain) == ident && TREE_VALUE (*chain) == proto)
+ goto return_at_index;
+
+ index++;
+ chain = &TREE_CHAIN (*chain);
+ }
+
+ *chain = perm_tree_cons (proto, ident, NULL_TREE);
+
+ return_at_index:
+ expr = build_unary_op (ADDR_EXPR,
+ build_array_ref (UOBJC_SELECTOR_TABLE_decl,
+ build_int_2 (index, 0)),
+ 1);
+ return build_c_cast (selector_type, expr);
+}
+
+static tree
+build_selector_reference (ident)
+ tree ident;
+{
+ tree *chain = &sel_ref_chain;
+ tree expr;
+ int index = 0;
+
+ while (*chain)
+ {
+ if (TREE_VALUE (*chain) == ident)
+ return (flag_next_runtime
+ ? TREE_PURPOSE (*chain)
+ : build_array_ref (UOBJC_SELECTOR_TABLE_decl,
+ build_int_2 (index, 0)));
+
+ index++;
+ chain = &TREE_CHAIN (*chain);
+ }
+
+ expr = build_selector_reference_decl (ident);
+
+ *chain = perm_tree_cons (expr, ident, NULL_TREE);
+
+ return (flag_next_runtime
+ ? expr
+ : build_array_ref (UOBJC_SELECTOR_TABLE_decl,
+ build_int_2 (index, 0)));
+}
+
+static tree
+build_class_reference_decl (name)
+ tree name;
+{
+ tree decl, ident;
+ char buf[256];
+ static int idx = 0;
+
+ sprintf (buf, "_OBJC_CLASS_REFERENCES_%d", idx++);
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ ident = get_identifier (buf);
+
+ decl = build_decl (VAR_DECL, ident, objc_class_type);
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ TREE_USED (decl) = 1;
+ TREE_READONLY (decl) = 1;
+ DECL_CONTEXT (decl) = 0;
+ DECL_ARTIFICIAL (decl) = 1;
+
+ make_decl_rtl (decl, 0, 1);
+ pushdecl_top_level (decl);
+
+ pop_obstacks ();
+
+ return decl;
+}
+
+/* Create a class reference, but don't create a variable to reference
+ it. */
+
+static void
+add_class_reference (ident)
+ tree ident;
+{
+ tree chain;
+
+ if ((chain = cls_ref_chain))
+ {
+ tree tail;
+ do
+ {
+ if (ident == TREE_VALUE (chain))
+ return;
+
+ tail = chain;
+ chain = TREE_CHAIN (chain);
+ }
+ while (chain);
+
+ /* Append to the end of the list */
+ TREE_CHAIN (tail) = perm_tree_cons (NULL_TREE, ident, NULL_TREE);
+ }
+ else
+ cls_ref_chain = perm_tree_cons (NULL_TREE, ident, NULL_TREE);
+}
+
+/* Get a class reference, creating it if necessary. Also create the
+ reference variable. */
+
+tree
+get_class_reference (ident)
+ tree ident;
+{
+ if (flag_next_runtime)
+ {
+ tree *chain;
+ tree decl;
+
+ for (chain = &cls_ref_chain; *chain; chain = &TREE_CHAIN (*chain))
+ if (TREE_VALUE (*chain) == ident)
+ {
+ if (! TREE_PURPOSE (*chain))
+ TREE_PURPOSE (*chain) = build_class_reference_decl (ident);
+
+ return TREE_PURPOSE (*chain);
+ }
+
+ decl = build_class_reference_decl (ident);
+ *chain = perm_tree_cons (decl, ident, NULL_TREE);
+ return decl;
+ }
+ else
+ {
+ tree params;
+
+ add_class_reference (ident);
+
+ params = build_tree_list (NULL_TREE,
+ my_build_string (IDENTIFIER_LENGTH (ident) + 1,
+ IDENTIFIER_POINTER (ident)));
+
+ assemble_external (objc_get_class_decl);
+ return build_function_call (objc_get_class_decl, params);
+ }
+}
+
+/* SEL_REFDEF_CHAIN is a list whose "value" fields will be instances
+ of identifier_node that represent the selector. It returns the
+ offset of the selector from the beginning of the _OBJC_STRINGS
+ pool. This offset is typically used by init_selector during code
+ generation.
+
+ For each string section we have a chain which maps identifier nodes
+ to decls for the strings. */
+
+static tree
+add_objc_string (ident, section)
+ tree ident;
+ enum string_section section;
+{
+ tree *chain, decl;
+
+ if (section == class_names)
+ chain = &class_names_chain;
+ else if (section == meth_var_names)
+ chain = &meth_var_names_chain;
+ else if (section == meth_var_types)
+ chain = &meth_var_types_chain;
+
+ while (*chain)
+ {
+ if (TREE_VALUE (*chain) == ident)
+ return build_unary_op (ADDR_EXPR, TREE_PURPOSE (*chain), 1);
+
+ chain = &TREE_CHAIN (*chain);
+ }
+
+ decl = build_objc_string_decl (ident, section);
+
+ *chain = perm_tree_cons (decl, ident, NULL_TREE);
+
+ return build_unary_op (ADDR_EXPR, decl, 1);
+}
+
+static tree
+build_objc_string_decl (name, section)
+ tree name;
+ enum string_section section;
+{
+ tree decl, ident;
+ char buf[256];
+ static int class_names_idx = 0;
+ static int meth_var_names_idx = 0;
+ static int meth_var_types_idx = 0;
+
+ if (section == class_names)
+ sprintf (buf, "_OBJC_CLASS_NAME_%d", class_names_idx++);
+ else if (section == meth_var_names)
+ sprintf (buf, "_OBJC_METH_VAR_NAME_%d", meth_var_names_idx++);
+ else if (section == meth_var_types)
+ sprintf (buf, "_OBJC_METH_VAR_TYPE_%d", meth_var_types_idx++);
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ ident = get_identifier (buf);
+
+ decl = build_decl (VAR_DECL, ident, build_array_type (char_type_node, 0));
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ TREE_USED (decl) = 1;
+ TREE_READONLY (decl) = 1;
+ TREE_CONSTANT (decl) = 1;
+ DECL_CONTEXT (decl) = 0;
+ DECL_ARTIFICIAL (decl) = 1;
+
+ make_decl_rtl (decl, 0, 1);
+ pushdecl_top_level (decl);
+
+ pop_obstacks ();
+
+ return decl;
+}
+
+
+void
+objc_declare_alias (alias_ident, class_ident)
+ tree alias_ident;
+ tree class_ident;
+{
+ if (!doing_objc_thang)
+ objc_fatal ();
+
+ if (is_class_name (class_ident) != class_ident)
+ warning ("Cannot find class `%s'", IDENTIFIER_POINTER (class_ident));
+ else if (is_class_name (alias_ident))
+ warning ("Class `%s' already exists", IDENTIFIER_POINTER (alias_ident));
+ else
+ alias_chain = tree_cons (class_ident, alias_ident, alias_chain);
+}
+
+void
+objc_declare_class (ident_list)
+ tree ident_list;
+{
+ tree list;
+
+ if (!doing_objc_thang)
+ objc_fatal ();
+
+ for (list = ident_list; list; list = TREE_CHAIN (list))
+ {
+ tree ident = TREE_VALUE (list);
+ tree decl;
+
+ if ((decl = lookup_name (ident)))
+ {
+ error ("`%s' redeclared as different kind of symbol",
+ IDENTIFIER_POINTER (ident));
+ error_with_decl (decl, "previous declaration of `%s'");
+ }
+
+ if (! is_class_name (ident))
+ {
+ tree record = xref_tag (RECORD_TYPE, ident);
+ TREE_STATIC_TEMPLATE (record) = 1;
+ class_chain = tree_cons (NULL_TREE, ident, class_chain);
+ }
+ }
+}
+
+tree
+is_class_name (ident)
+ tree ident;
+{
+ tree chain;
+
+ if (lookup_interface (ident))
+ return ident;
+
+ for (chain = class_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ if (ident == TREE_VALUE (chain))
+ return ident;
+ }
+
+ for (chain = alias_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ if (ident == TREE_VALUE (chain))
+ return TREE_PURPOSE (chain);
+ }
+
+ return 0;
+}
+
+tree
+lookup_interface (ident)
+ tree ident;
+{
+ tree chain;
+
+ for (chain = interface_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ if (ident == CLASS_NAME (chain))
+ return chain;
+ }
+ return NULL_TREE;
+}
+
+static tree
+objc_copy_list (list, head)
+ tree list;
+ tree *head;
+{
+ tree newlist = NULL_TREE, tail = NULL_TREE;
+
+ while (list)
+ {
+ tail = copy_node (list);
+
+ /* The following statement fixes a bug when inheriting instance
+ variables that are declared to be bitfields. finish_struct
+ expects to find the width of the bitfield in DECL_INITIAL,
+ which it nulls out after processing the decl of the super
+ class...rather than change the way finish_struct works (which
+ is risky), I create the situation it expects...s.naroff
+ (7/23/89). */
+
+ if (DECL_BIT_FIELD (tail) && DECL_INITIAL (tail) == 0)
+ DECL_INITIAL (tail) = build_int_2 (DECL_FIELD_SIZE (tail), 0);
+
+ newlist = chainon (newlist, tail);
+ list = TREE_CHAIN (list);
+ }
+
+ *head = newlist;
+ return tail;
+}
+
+/* Used by: build_private_template, get_class_ivars, and
+ continue_class. COPY is 1 when called from @defs. In this case
+ copy all fields. Otherwise don't copy leaf ivars since we rely on
+ them being side-effected exactly once by finish_struct. */
+
+static tree
+build_ivar_chain (interface, copy)
+ tree interface;
+ int copy;
+{
+ tree my_name, super_name, ivar_chain;
+
+ my_name = CLASS_NAME (interface);
+ super_name = CLASS_SUPER_NAME (interface);
+
+ /* Possibly copy leaf ivars. */
+ if (copy)
+ objc_copy_list (CLASS_IVARS (interface), &ivar_chain);
+ else
+ ivar_chain = CLASS_IVARS (interface);
+
+ while (super_name)
+ {
+ tree op1;
+ tree super_interface = lookup_interface (super_name);
+
+ if (!super_interface)
+ {
+ /* fatal did not work with 2 args...should fix */
+ error ("Cannot find interface declaration for `%s', superclass of `%s'",
+ IDENTIFIER_POINTER (super_name),
+ IDENTIFIER_POINTER (my_name));
+ exit (FATAL_EXIT_CODE);
+ }
+
+ if (super_interface == interface)
+ {
+ fatal ("Circular inheritance in interface declaration for `%s'",
+ IDENTIFIER_POINTER (super_name));
+ }
+
+ interface = super_interface;
+ my_name = CLASS_NAME (interface);
+ super_name = CLASS_SUPER_NAME (interface);
+
+ op1 = CLASS_IVARS (interface);
+ if (op1)
+ {
+ tree head, tail = objc_copy_list (op1, &head);
+
+ /* Prepend super class ivars...make a copy of the list, we
+ do not want to alter the original. */
+ TREE_CHAIN (tail) = ivar_chain;
+ ivar_chain = head;
+ }
+ }
+ return ivar_chain;
+}
+
+/* struct <classname> {
+ struct objc_class *isa;
+ ...
+ }; */
+
+static tree
+build_private_template (class)
+ tree class;
+{
+ tree ivar_context;
+
+ if (CLASS_STATIC_TEMPLATE (class))
+ {
+ uprivate_record = CLASS_STATIC_TEMPLATE (class);
+ ivar_context = TYPE_FIELDS (CLASS_STATIC_TEMPLATE (class));
+ }
+ else
+ {
+ uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class));
+
+ ivar_context = build_ivar_chain (class, 0);
+
+ finish_struct (uprivate_record, ivar_context, NULL_TREE);
+
+ CLASS_STATIC_TEMPLATE (class) = uprivate_record;
+
+ /* mark this record as class template - for class type checking */
+ TREE_STATIC_TEMPLATE (uprivate_record) = 1;
+ }
+
+ instance_type
+ = groktypename (build_tree_list (build_tree_list (NULL_TREE,
+ uprivate_record),
+ build1 (INDIRECT_REF, NULL_TREE,
+ NULL_TREE)));
+
+ return ivar_context;
+}
+
+/* Begin code generation for protocols... */
+
+/* struct objc_protocol {
+ char *protocol_name;
+ struct objc_protocol **protocol_list;
+ struct objc_method_desc *instance_methods;
+ struct objc_method_desc *class_methods;
+ }; */
+
+static tree
+build_protocol_template ()
+{
+ tree decl_specs, field_decl, field_decl_chain;
+ tree template;
+
+ template = start_struct (RECORD_TYPE, get_identifier (UTAG_PROTOCOL));
+
+ /* struct objc_class *isa; */
+
+ decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_CLASS)));
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("isa"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ /* char *protocol_name; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_name"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_protocol **protocol_list; */
+
+ decl_specs = build_tree_list (NULL_TREE, template);
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list"));
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl);
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_method_list *instance_methods; */
+
+ decl_specs
+ = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_PROTOTYPE_LIST)));
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("instance_methods"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_method_list *class_methods; */
+
+ decl_specs
+ = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_PROTOTYPE_LIST)));
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_methods"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ return finish_struct (template, field_decl_chain, NULL_TREE);
+}
+
+static tree
+build_descriptor_table_initializer (type, entries)
+ tree type;
+ tree entries;
+{
+ tree initlist = NULL_TREE;
+
+ do
+ {
+ tree eltlist = NULL_TREE;
+
+ eltlist
+ = tree_cons (NULL_TREE,
+ build_selector (METHOD_SEL_NAME (entries)), NULL_TREE);
+ eltlist
+ = tree_cons (NULL_TREE,
+ add_objc_string (METHOD_ENCODING (entries),
+ meth_var_types),
+ eltlist);
+
+ initlist
+ = tree_cons (NULL_TREE,
+ build_constructor (type, nreverse (eltlist)), initlist);
+
+ entries = TREE_CHAIN (entries);
+ }
+ while (entries);
+
+ return build_constructor (build_array_type (type, 0), nreverse (initlist));
+}
+
+/* struct objc_method_prototype_list {
+ int count;
+ struct objc_method_prototype {
+ SEL name;
+ char *types;
+ } list[1];
+ }; */
+
+static tree
+build_method_prototype_list_template (list_type, size)
+ tree list_type;
+ int size;
+{
+ tree objc_ivar_list_record;
+ tree decl_specs, field_decl, field_decl_chain;
+
+ /* Generate an unnamed struct definition. */
+
+ objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE);
+
+ /* int method_count; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]);
+ field_decl = get_identifier ("method_count");
+
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ /* struct objc_method method_list[]; */
+
+ decl_specs = build_tree_list (NULL_TREE, list_type);
+ field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"),
+ build_int_2 (size, 0));
+
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE);
+
+ return objc_ivar_list_record;
+}
+
+static tree
+build_method_prototype_template ()
+{
+ tree proto_record;
+ tree decl_specs, field_decl, field_decl_chain;
+
+ proto_record
+ = start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD_PROTOTYPE));
+
+#ifdef OBJC_INT_SELECTORS
+ /* unsigned int _cmd; */
+ decl_specs
+ = tree_cons (NULL_TREE, ridpointers[(int) RID_UNSIGNED], NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_INT], decl_specs);
+ field_decl = get_identifier ("_cmd");
+#else /* OBJC_INT_SELECTORS */
+ /* struct objc_selector *_cmd; */
+ decl_specs = tree_cons (NULL_TREE, xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SELECTOR)), NULL_TREE);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("_cmd"));
+#endif /* OBJC_INT_SELECTORS */
+
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], NULL_TREE);
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("method_types"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (proto_record, field_decl_chain, NULL_TREE);
+
+ return proto_record;
+}
+
+/* True if last call to forwarding_offset yielded a register offset. */
+static int offset_is_register;
+
+static int
+forwarding_offset (parm)
+ tree parm;
+{
+ int offset_in_bytes;
+
+ if (GET_CODE (DECL_INCOMING_RTL (parm)) == MEM)
+ {
+ rtx addr = XEXP (DECL_INCOMING_RTL (parm), 0);
+
+ /* ??? Here we assume that the parm address is indexed
+ off the frame pointer or arg pointer.
+ If that is not true, we produce meaningless results,
+ but do not crash. */
+ if (GET_CODE (addr) == PLUS
+ && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+ offset_in_bytes = INTVAL (XEXP (addr, 1));
+ else
+ offset_in_bytes = 0;
+
+ offset_in_bytes += OBJC_FORWARDING_STACK_OFFSET;
+ offset_is_register = 0;
+ }
+ else if (GET_CODE (DECL_INCOMING_RTL (parm)) == REG)
+ {
+ int regno = REGNO (DECL_INCOMING_RTL (parm));
+ offset_in_bytes = apply_args_register_offset (regno);
+ offset_is_register = 1;
+ }
+ else
+ return 0;
+
+ /* This is the case where the parm is passed as an int or double
+ and it is converted to a char, short or float and stored back
+ in the parmlist. In this case, describe the parm
+ with the variable's declared type, and adjust the address
+ if the least significant bytes (which we are using) are not
+ the first ones. */
+ if (BYTES_BIG_ENDIAN && TREE_TYPE (parm) != DECL_ARG_TYPE (parm))
+ offset_in_bytes += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parm)))
+ - GET_MODE_SIZE (GET_MODE (DECL_RTL (parm))));
+
+ return offset_in_bytes;
+}
+
+static tree
+encode_method_prototype (method_decl, func_decl)
+ tree method_decl;
+ tree func_decl;
+{
+ tree parms;
+ int stack_size, i;
+ tree user_args;
+ int max_parm_end = 0;
+ char buf[40];
+ tree result;
+
+ /* ONEWAY and BYCOPY, for remote object are the only method qualifiers. */
+ encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (method_decl)));
+
+ /* C type. */
+ encode_type (TREE_TYPE (TREE_TYPE (func_decl)),
+ obstack_object_size (&util_obstack),
+ OBJC_ENCODE_INLINE_DEFS);
+
+ /* Stack size. */
+ for (parms = DECL_ARGUMENTS (func_decl); parms;
+ parms = TREE_CHAIN (parms))
+ {
+ int parm_end = (forwarding_offset (parms)
+ + (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (parms)))
+ / BITS_PER_UNIT));
+
+ if (!offset_is_register && max_parm_end < parm_end)
+ max_parm_end = parm_end;
+ }
+
+ stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET;
+
+ sprintf (buf, "%d", stack_size);
+ obstack_grow (&util_obstack, buf, strlen (buf));
+
+ user_args = METHOD_SEL_ARGS (method_decl);
+
+ /* Argument types. */
+ for (parms = DECL_ARGUMENTS (func_decl), i = 0; parms;
+ parms = TREE_CHAIN (parms), i++)
+ {
+ /* Process argument qualifiers for user supplied arguments. */
+ if (i > 1)
+ {
+ encode_type_qualifiers (TREE_PURPOSE (TREE_TYPE (user_args)));
+ user_args = TREE_CHAIN (user_args);
+ }
+
+ /* Type. */
+ encode_type (TREE_TYPE (parms),
+ obstack_object_size (&util_obstack),
+ OBJC_ENCODE_INLINE_DEFS);
+
+ /* Compute offset. */
+ sprintf (buf, "%d", forwarding_offset (parms));
+
+ /* Indicate register. */
+ if (offset_is_register)
+ obstack_1grow (&util_obstack, '+');
+
+ obstack_grow (&util_obstack, buf, strlen (buf));
+ }
+
+ obstack_1grow (&util_obstack, '\0');
+ result = get_identifier (obstack_finish (&util_obstack));
+ obstack_free (&util_obstack, util_firstobj);
+ return result;
+}
+
+static tree
+generate_descriptor_table (type, name, size, list, proto)
+ tree type;
+ char *name;
+ int size;
+ tree list;
+ tree proto;
+{
+ tree sc_spec, decl_specs, decl, initlist;
+
+ sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, type, sc_spec);
+
+ decl = start_decl (synth_id_with_class_suffix (name, proto),
+ decl_specs, 1, NULL_TREE, NULL_TREE);
+
+ initlist = build_tree_list (NULL_TREE, build_int_2 (size, 0));
+ initlist = tree_cons (NULL_TREE, list, initlist);
+
+ finish_decl (decl, build_constructor (type, nreverse (initlist)),
+ NULL_TREE);
+
+ return decl;
+}
+
+static void
+generate_method_descriptors (protocol) /* generate_dispatch_tables */
+ tree protocol;
+{
+ static tree objc_method_prototype_template;
+ tree initlist, chain, method_list_template;
+ tree cast, variable_length_type;
+ int size;
+
+ if (!objc_method_prototype_template)
+ objc_method_prototype_template = build_method_prototype_template ();
+
+ cast = build_tree_list (build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_PROTOTYPE_LIST))),
+ NULL_TREE);
+ variable_length_type = groktypename (cast);
+
+ chain = PROTOCOL_CLS_METHODS (protocol);
+ if (chain)
+ {
+ size = list_length (chain);
+
+ method_list_template
+ = build_method_prototype_list_template (objc_method_prototype_template,
+ size);
+
+ initlist
+ = build_descriptor_table_initializer (objc_method_prototype_template,
+ chain);
+
+ UOBJC_CLASS_METHODS_decl
+ = generate_descriptor_table (method_list_template,
+ "_OBJC_PROTOCOL_CLASS_METHODS",
+ size, initlist, protocol);
+ TREE_TYPE (UOBJC_CLASS_METHODS_decl) = variable_length_type;
+ }
+ else
+ UOBJC_CLASS_METHODS_decl = 0;
+
+ chain = PROTOCOL_NST_METHODS (protocol);
+ if (chain)
+ {
+ size = list_length (chain);
+
+ method_list_template
+ = build_method_prototype_list_template (objc_method_prototype_template,
+ size);
+ initlist
+ = build_descriptor_table_initializer (objc_method_prototype_template,
+ chain);
+
+ UOBJC_INSTANCE_METHODS_decl
+ = generate_descriptor_table (method_list_template,
+ "_OBJC_PROTOCOL_INSTANCE_METHODS",
+ size, initlist, protocol);
+ TREE_TYPE (UOBJC_INSTANCE_METHODS_decl) = variable_length_type;
+ }
+ else
+ UOBJC_INSTANCE_METHODS_decl = 0;
+}
+
+static tree
+build_tmp_function_decl ()
+{
+ tree decl_specs, expr_decl, parms;
+ static int xxx = 0;
+ char buffer[80];
+
+ /* struct objc_object *objc_xxx (id, SEL, ...); */
+ pushlevel (0);
+ decl_specs = build_tree_list (NULL_TREE, objc_object_reference);
+ push_parm_decl (build_tree_list
+ (build_tree_list (decl_specs,
+ build1 (INDIRECT_REF, NULL_TREE,
+ NULL_TREE)),
+ build_tree_list (NULL_TREE, NULL_TREE)));
+
+ decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SELECTOR)));
+ expr_decl = build1 (INDIRECT_REF, NULL_TREE, NULL_TREE);
+
+ push_parm_decl (build_tree_list (build_tree_list (decl_specs, expr_decl),
+ build_tree_list (NULL_TREE, NULL_TREE)));
+ parms = get_parm_info (0);
+ poplevel (0, 0, 0);
+
+ decl_specs = build_tree_list (NULL_TREE, objc_object_reference);
+ sprintf (buffer, "__objc_tmp_%x", xxx++);
+ expr_decl = build_nt (CALL_EXPR, get_identifier (buffer), parms, NULL_TREE);
+ expr_decl = build1 (INDIRECT_REF, NULL_TREE, expr_decl);
+
+ return define_decl (expr_decl, decl_specs);
+}
+
+static void
+hack_method_prototype (nst_methods, tmp_decl)
+ tree nst_methods;
+ tree tmp_decl;
+{
+ tree parms;
+ tree parm;
+
+ /* Hack to avoid problem with static typing of self arg. */
+ TREE_SET_CODE (nst_methods, CLASS_METHOD_DECL);
+ start_method_def (nst_methods);
+ TREE_SET_CODE (nst_methods, INSTANCE_METHOD_DECL);
+
+ if (METHOD_ADD_ARGS (nst_methods) == (tree) 1)
+ parms = get_parm_info (0); /* we have a `, ...' */
+ else
+ parms = get_parm_info (1); /* place a `void_at_end' */
+
+ poplevel (0, 0, 0); /* Must be called BEFORE start_function. */
+
+ /* Usually called from store_parm_decls -> init_function_start. */
+
+ DECL_ARGUMENTS (tmp_decl) = TREE_PURPOSE (parms);
+ current_function_decl = tmp_decl;
+
+ {
+ /* Code taken from start_function. */
+ tree restype = TREE_TYPE (TREE_TYPE (tmp_decl));
+ /* Promote the value to int before returning it. */
+ if (TREE_CODE (restype) == INTEGER_TYPE
+ && TYPE_PRECISION (restype) < TYPE_PRECISION (integer_type_node))
+ restype = integer_type_node;
+ DECL_RESULT (tmp_decl) = build_decl (RESULT_DECL, 0, restype);
+ }
+
+ for (parm = DECL_ARGUMENTS (tmp_decl); parm; parm = TREE_CHAIN (parm))
+ DECL_CONTEXT (parm) = tmp_decl;
+
+ init_function_start (tmp_decl, "objc-act", 0);
+
+ /* Typically called from expand_function_start for function definitions. */
+ assign_parms (tmp_decl, 0);
+
+ /* install return type */
+ TREE_TYPE (TREE_TYPE (tmp_decl)) = groktypename (TREE_TYPE (nst_methods));
+
+}
+
+static void
+generate_protocol_references (plist)
+ tree plist;
+{
+ tree lproto;
+
+ /* Forward declare protocols referenced. */
+ for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
+ {
+ tree proto = TREE_VALUE (lproto);
+
+ if (TREE_CODE (proto) == PROTOCOL_INTERFACE_TYPE
+ && PROTOCOL_NAME (proto))
+ {
+ if (! PROTOCOL_FORWARD_DECL (proto))
+ build_protocol_reference (proto);
+
+ if (PROTOCOL_LIST (proto))
+ generate_protocol_references (PROTOCOL_LIST (proto));
+ }
+ }
+}
+
+static void
+generate_protocols ()
+{
+ tree p, tmp_decl, encoding;
+ tree sc_spec, decl_specs, decl;
+ tree initlist, protocol_name_expr, refs_decl, refs_expr;
+ tree cast_type2 = 0;
+
+ tmp_decl = build_tmp_function_decl ();
+
+ if (! objc_protocol_template)
+ objc_protocol_template = build_protocol_template ();
+
+ /* If a protocol was directly referenced, pull in indirect references. */
+ for (p = protocol_chain; p; p = TREE_CHAIN (p))
+ if (PROTOCOL_FORWARD_DECL (p) && PROTOCOL_LIST (p))
+ generate_protocol_references (PROTOCOL_LIST (p));
+
+ for (p = protocol_chain; p; p = TREE_CHAIN (p))
+ {
+ tree nst_methods = PROTOCOL_NST_METHODS (p);
+ tree cls_methods = PROTOCOL_CLS_METHODS (p);
+
+ /* If protocol wasn't referenced, don't generate any code. */
+ if (! PROTOCOL_FORWARD_DECL (p))
+ continue;
+
+ /* Make sure we link in the Protocol class. */
+ add_class_reference (get_identifier (PROTOCOL_OBJECT_CLASS_NAME));
+
+ while (nst_methods)
+ {
+ if (! METHOD_ENCODING (nst_methods))
+ {
+ hack_method_prototype (nst_methods, tmp_decl);
+ encoding = encode_method_prototype (nst_methods, tmp_decl);
+ METHOD_ENCODING (nst_methods) = encoding;
+ }
+ nst_methods = TREE_CHAIN (nst_methods);
+ }
+
+ while (cls_methods)
+ {
+ if (! METHOD_ENCODING (cls_methods))
+ {
+ hack_method_prototype (cls_methods, tmp_decl);
+ encoding = encode_method_prototype (cls_methods, tmp_decl);
+ METHOD_ENCODING (cls_methods) = encoding;
+ }
+
+ cls_methods = TREE_CHAIN (cls_methods);
+ }
+ generate_method_descriptors (p);
+
+ if (PROTOCOL_LIST (p))
+ refs_decl = generate_protocol_list (p);
+ else
+ refs_decl = 0;
+
+ /* static struct objc_protocol _OBJC_PROTOCOL_<mumble>; */
+
+ sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC],
+ NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, objc_protocol_template, sc_spec);
+
+ decl = start_decl (synth_id_with_class_suffix ("_OBJC_PROTOCOL", p),
+ decl_specs, 1, NULL_TREE, NULL_TREE);
+
+ protocol_name_expr = add_objc_string (PROTOCOL_NAME (p), class_names);
+
+ if (refs_decl)
+ {
+ if (!cast_type2)
+ cast_type2
+ = groktypename
+ (build_tree_list (build_tree_list (NULL_TREE,
+ objc_protocol_template),
+ build1 (INDIRECT_REF, NULL_TREE,
+ build1 (INDIRECT_REF, NULL_TREE,
+ NULL_TREE))));
+
+ refs_expr = build_unary_op (ADDR_EXPR, refs_decl, 0);
+ TREE_TYPE (refs_expr) = cast_type2;
+ }
+ else
+ refs_expr = build_int_2 (0, 0);
+
+ /* UOBJC_INSTANCE_METHODS_decl/UOBJC_CLASS_METHODS_decl are set
+ by generate_method_descriptors, which is called above. */
+ initlist = build_protocol_initializer (TREE_TYPE (decl),
+ protocol_name_expr, refs_expr,
+ UOBJC_INSTANCE_METHODS_decl,
+ UOBJC_CLASS_METHODS_decl);
+ finish_decl (decl, initlist, NULL_TREE);
+
+ /* Mark the decl as used to avoid "defined but not used" warning. */
+ TREE_USED (decl) = 1;
+ }
+}
+
+static tree
+build_protocol_initializer (type, protocol_name, protocol_list,
+ instance_methods, class_methods)
+ tree type;
+ tree protocol_name;
+ tree protocol_list;
+ tree instance_methods;
+ tree class_methods;
+{
+ tree initlist = NULL_TREE, expr;
+ static tree cast_type = 0;
+
+ if (!cast_type)
+ cast_type
+ = groktypename
+ (build_tree_list
+ (build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_CLASS))),
+ build1 (INDIRECT_REF, NULL_TREE, NULL_TREE)));
+
+ /* Filling the "isa" in with one allows the runtime system to
+ detect that the version change...should remove before final release. */
+
+ expr = build_int_2 (PROTOCOL_VERSION, 0);
+ TREE_TYPE (expr) = cast_type;
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ initlist = tree_cons (NULL_TREE, protocol_name, initlist);
+ initlist = tree_cons (NULL_TREE, protocol_list, initlist);
+
+ if (!instance_methods)
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ else
+ {
+ expr = build_unary_op (ADDR_EXPR, instance_methods, 0);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+
+ if (!class_methods)
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ else
+ {
+ expr = build_unary_op (ADDR_EXPR, class_methods, 0);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+
+ return build_constructor (type, nreverse (initlist));
+}
+
+/* struct objc_category {
+ char *category_name;
+ char *class_name;
+ struct objc_method_list *instance_methods;
+ struct objc_method_list *class_methods;
+ struct objc_protocol_list *protocols;
+ }; */
+
+static void
+build_category_template ()
+{
+ tree decl_specs, field_decl, field_decl_chain;
+
+ objc_category_template = start_struct (RECORD_TYPE,
+ get_identifier (UTAG_CATEGORY));
+ /* char *category_name; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("category_name"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ /* char *class_name; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_name"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_method_list *instance_methods; */
+
+ decl_specs = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_LIST)));
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("instance_methods"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_method_list *class_methods; */
+
+ decl_specs = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_LIST)));
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class_methods"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_protocol **protocol_list; */
+
+ decl_specs = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_PROTOCOL)));
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list"));
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl);
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (objc_category_template, field_decl_chain, NULL_TREE);
+}
+
+/* struct objc_selector {
+ void *sel_id;
+ char *sel_type;
+ }; */
+
+static void
+build_selector_template ()
+{
+
+ tree decl_specs, field_decl, field_decl_chain;
+
+ objc_selector_template
+ = start_struct (RECORD_TYPE, get_identifier (UTAG_SELECTOR));
+
+ /* void *sel_id; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_VOID]);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_id"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ /* char *sel_type; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sel_type"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (objc_selector_template, field_decl_chain, NULL_TREE);
+}
+
+/* struct objc_class {
+ struct objc_class *isa;
+ struct objc_class *super_class;
+ char *name;
+ long version;
+ long info;
+ long instance_size;
+ struct objc_ivar_list *ivars;
+ struct objc_method_list *methods;
+ if (flag_next_runtime)
+ struct objc_cache *cache;
+ else {
+ struct sarray *dtable;
+ struct objc_class *subclass_list;
+ struct objc_class *sibling_class;
+ }
+ struct objc_protocol_list *protocols;
+ }; */
+
+static void
+build_class_template ()
+{
+ tree decl_specs, field_decl, field_decl_chain;
+
+ objc_class_template
+ = start_struct (RECORD_TYPE, get_identifier (UTAG_CLASS));
+
+ /* struct objc_class *isa; */
+
+ decl_specs = build_tree_list (NULL_TREE, objc_class_template);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("isa"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ /* struct objc_class *super_class; */
+
+ decl_specs = build_tree_list (NULL_TREE, objc_class_template);
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("super_class"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* char *name; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("name"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* long version; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]);
+ field_decl = get_identifier ("version");
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* long info; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]);
+ field_decl = get_identifier ("info");
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* long instance_size; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_LONG]);
+ field_decl = get_identifier ("instance_size");
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_ivar_list *ivars; */
+
+ decl_specs = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_IVAR_LIST)));
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("ivars"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_method_list *methods; */
+
+ decl_specs = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_LIST)));
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("methods"));
+ field_decl
+ = grokfield (input_filename, lineno, field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ if (flag_next_runtime)
+ {
+ /* struct objc_cache *cache; */
+
+ decl_specs = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier ("objc_cache")));
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("cache"));
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+ }
+ else
+ {
+ /* struct sarray *dtable; */
+
+ decl_specs = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier ("sarray")));
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("dtable"));
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_class *subclass_list; */
+
+ decl_specs = build_tree_list (NULL_TREE, objc_class_template);
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("subclass_list"));
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_class *sibling_class; */
+
+ decl_specs = build_tree_list (NULL_TREE, objc_class_template);
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("sibling_class"));
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+ }
+
+ /* struct objc_protocol **protocol_list; */
+
+ decl_specs = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_PROTOCOL)));
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("protocol_list"));
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, field_decl);
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+
+ finish_struct (objc_class_template, field_decl_chain, NULL_TREE);
+}
+
+/* Generate appropriate forward declarations for an implementation. */
+
+static void
+synth_forward_declarations ()
+{
+ tree sc_spec, decl_specs, an_id;
+
+ /* extern struct objc_class _OBJC_CLASS_<my_name>; */
+
+ an_id = synth_id_with_class_suffix ("_OBJC_CLASS", implementation_context);
+
+ sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_EXTERN]);
+ decl_specs = tree_cons (NULL_TREE, objc_class_template, sc_spec);
+ UOBJC_CLASS_decl = define_decl (an_id, decl_specs);
+ TREE_USED (UOBJC_CLASS_decl) = 1;
+ DECL_ARTIFICIAL (UOBJC_CLASS_decl) = 1;
+
+ /* extern struct objc_class _OBJC_METACLASS_<my_name>; */
+
+ an_id = synth_id_with_class_suffix ("_OBJC_METACLASS",
+ implementation_context);
+
+ UOBJC_METACLASS_decl = define_decl (an_id, decl_specs);
+ TREE_USED (UOBJC_METACLASS_decl) = 1;
+ DECL_ARTIFICIAL(UOBJC_METACLASS_decl) = 1;
+
+ /* Pre-build the following entities - for speed/convenience. */
+
+ an_id = get_identifier ("super_class");
+ ucls_super_ref = build_component_ref (UOBJC_CLASS_decl, an_id);
+ uucls_super_ref = build_component_ref (UOBJC_METACLASS_decl, an_id);
+}
+
+static void
+error_with_ivar (message, decl, rawdecl)
+ char *message;
+ tree decl;
+ tree rawdecl;
+{
+ count_error (0);
+
+ report_error_function (DECL_SOURCE_FILE (decl));
+
+ fprintf (stderr, "%s:%d: ",
+ DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl));
+ bzero (errbuf, BUFSIZE);
+ fprintf (stderr, "%s `%s'\n", message, gen_declaration (rawdecl, errbuf));
+}
+
+#define USERTYPE(t) \
+ (TREE_CODE (t) == RECORD_TYPE || TREE_CODE (t) == UNION_TYPE \
+ || TREE_CODE (t) == ENUMERAL_TYPE)
+
+static void
+check_ivars (inter, imp)
+ tree inter;
+ tree imp;
+{
+ tree intdecls = CLASS_IVARS (inter);
+ tree impdecls = CLASS_IVARS (imp);
+ tree rawintdecls = CLASS_RAW_IVARS (inter);
+ tree rawimpdecls = CLASS_RAW_IVARS (imp);
+
+ while (1)
+ {
+ tree t1, t2;
+
+ if (intdecls == 0 && impdecls == 0)
+ break;
+ if (intdecls == 0 || impdecls == 0)
+ {
+ error ("inconsistent instance variable specification");
+ break;
+ }
+
+ t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls);
+
+ if (!comptypes (t1, t2))
+ {
+ if (DECL_NAME (intdecls) == DECL_NAME (impdecls))
+ {
+ error_with_ivar ("conflicting instance variable type",
+ impdecls, rawimpdecls);
+ error_with_ivar ("previous declaration of",
+ intdecls, rawintdecls);
+ }
+ else /* both the type and the name don't match */
+ {
+ error ("inconsistent instance variable specification");
+ break;
+ }
+ }
+
+ else if (DECL_NAME (intdecls) != DECL_NAME (impdecls))
+ {
+ error_with_ivar ("conflicting instance variable name",
+ impdecls, rawimpdecls);
+ error_with_ivar ("previous declaration of",
+ intdecls, rawintdecls);
+ }
+
+ intdecls = TREE_CHAIN (intdecls);
+ impdecls = TREE_CHAIN (impdecls);
+ rawintdecls = TREE_CHAIN (rawintdecls);
+ rawimpdecls = TREE_CHAIN (rawimpdecls);
+ }
+}
+
+/* Set super_type to the data type node for struct objc_super *,
+ first defining struct objc_super itself.
+ This needs to be done just once per compilation. */
+
+static tree
+build_super_template ()
+{
+ tree record, decl_specs, field_decl, field_decl_chain;
+
+ record = start_struct (RECORD_TYPE, get_identifier (UTAG_SUPER));
+
+ /* struct objc_object *self; */
+
+ decl_specs = build_tree_list (NULL_TREE, objc_object_reference);
+ field_decl = get_identifier ("self");
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, field_decl);
+ field_decl = grokfield (input_filename, lineno,
+ field_decl, decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ /* struct objc_class *class; */
+
+ decl_specs = get_identifier (UTAG_CLASS);
+ decl_specs = build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE, decl_specs));
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("class"));
+
+ field_decl = grokfield (input_filename, lineno,
+ field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (record, field_decl_chain, NULL_TREE);
+
+ /* `struct objc_super *' */
+ super_type = groktypename (build_tree_list (build_tree_list (NULL_TREE,
+ record),
+ build1 (INDIRECT_REF,
+ NULL_TREE, NULL_TREE)));
+ return record;
+}
+
+/* struct objc_ivar {
+ char *ivar_name;
+ char *ivar_type;
+ int ivar_offset;
+ }; */
+
+static tree
+build_ivar_template ()
+{
+ tree objc_ivar_id, objc_ivar_record;
+ tree decl_specs, field_decl, field_decl_chain;
+
+ objc_ivar_id = get_identifier (UTAG_IVAR);
+ objc_ivar_record = start_struct (RECORD_TYPE, objc_ivar_id);
+
+ /* char *ivar_name; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("ivar_name"));
+
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ /* char *ivar_type; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_CHAR]);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("ivar_type"));
+
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* int ivar_offset; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]);
+ field_decl = get_identifier ("ivar_offset");
+
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (objc_ivar_record, field_decl_chain, NULL_TREE);
+
+ return objc_ivar_record;
+}
+
+/* struct {
+ int ivar_count;
+ struct objc_ivar ivar_list[ivar_count];
+ }; */
+
+static tree
+build_ivar_list_template (list_type, size)
+ tree list_type;
+ int size;
+{
+ tree objc_ivar_list_record;
+ tree decl_specs, field_decl, field_decl_chain;
+
+ objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE);
+
+ /* int ivar_count; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]);
+ field_decl = get_identifier ("ivar_count");
+
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ /* struct objc_ivar ivar_list[]; */
+
+ decl_specs = build_tree_list (NULL_TREE, list_type);
+ field_decl = build_nt (ARRAY_REF, get_identifier ("ivar_list"),
+ build_int_2 (size, 0));
+
+ field_decl = grokfield (input_filename, lineno,
+ field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE);
+
+ return objc_ivar_list_record;
+}
+
+/* struct {
+ int method_next;
+ int method_count;
+ struct objc_method method_list[method_count];
+ }; */
+
+static tree
+build_method_list_template (list_type, size)
+ tree list_type;
+ int size;
+{
+ tree objc_ivar_list_record;
+ tree decl_specs, field_decl, field_decl_chain;
+
+ objc_ivar_list_record = start_struct (RECORD_TYPE, NULL_TREE);
+
+ /* int method_next; */
+
+ decl_specs
+ = build_tree_list
+ (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_PROTOTYPE_LIST)));
+ field_decl
+ = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("method_next"));
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ /* int method_count; */
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_INT]);
+ field_decl = get_identifier ("method_count");
+
+ field_decl = grokfield (input_filename, lineno,
+ field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* struct objc_method method_list[]; */
+
+ decl_specs = build_tree_list (NULL_TREE, list_type);
+ field_decl = build_nt (ARRAY_REF, get_identifier ("method_list"),
+ build_int_2 (size, 0));
+
+ field_decl = grokfield (input_filename, lineno,
+ field_decl, decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (objc_ivar_list_record, field_decl_chain, NULL_TREE);
+
+ return objc_ivar_list_record;
+}
+
+static tree
+build_ivar_list_initializer (type, field_decl)
+ tree type;
+ tree field_decl;
+{
+ tree initlist = NULL_TREE;
+
+ do
+ {
+ tree ivar = NULL_TREE;
+
+ /* Set name. */
+ if (DECL_NAME (field_decl))
+ ivar = tree_cons (NULL_TREE,
+ add_objc_string (DECL_NAME (field_decl),
+ meth_var_names),
+ ivar);
+ else
+ /* Unnamed bit-field ivar (yuck). */
+ ivar = tree_cons (NULL_TREE, build_int_2 (0, 0), ivar);
+
+ /* Set type. */
+ encode_field_decl (field_decl,
+ obstack_object_size (&util_obstack),
+ OBJC_ENCODE_DONT_INLINE_DEFS);
+
+ /* Null terminate string. */
+ obstack_1grow (&util_obstack, 0);
+ ivar
+ = tree_cons
+ (NULL_TREE,
+ add_objc_string (get_identifier (obstack_finish (&util_obstack)),
+ meth_var_types),
+ ivar);
+ obstack_free (&util_obstack, util_firstobj);
+
+ /* set offset */
+ ivar
+ = tree_cons
+ (NULL_TREE,
+ build_int_2 ((TREE_INT_CST_LOW (DECL_FIELD_BITPOS (field_decl))
+ / BITS_PER_UNIT),
+ 0),
+ ivar);
+
+ initlist = tree_cons (NULL_TREE,
+ build_constructor (type, nreverse (ivar)),
+ initlist);
+
+ field_decl = TREE_CHAIN (field_decl);
+ }
+ while (field_decl);
+
+ return build_constructor (build_array_type (type, 0), nreverse (initlist));
+}
+
+static tree
+generate_ivars_list (type, name, size, list)
+ tree type;
+ char *name;
+ int size;
+ tree list;
+{
+ tree sc_spec, decl_specs, decl, initlist;
+
+ sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, type, sc_spec);
+
+ decl = start_decl (synth_id_with_class_suffix (name, implementation_context),
+ decl_specs, 1, NULL_TREE, NULL_TREE);
+
+ initlist = build_tree_list (NULL_TREE, build_int_2 (size, 0));
+ initlist = tree_cons (NULL_TREE, list, initlist);
+
+ finish_decl (decl,
+ build_constructor (TREE_TYPE (decl), nreverse (initlist)),
+ NULL_TREE);
+
+ return decl;
+}
+
+static void
+generate_ivar_lists ()
+{
+ tree initlist, ivar_list_template, chain;
+ tree cast, variable_length_type;
+ int size;
+
+ generating_instance_variables = 1;
+
+ if (!objc_ivar_template)
+ objc_ivar_template = build_ivar_template ();
+
+ cast
+ = build_tree_list
+ (build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_IVAR_LIST))),
+ NULL_TREE);
+ variable_length_type = groktypename (cast);
+
+ /* Only generate class variables for the root of the inheritance
+ hierarchy since these will be the same for every class. */
+
+ if (CLASS_SUPER_NAME (implementation_template) == NULL_TREE
+ && (chain = TYPE_FIELDS (objc_class_template)))
+ {
+ size = list_length (chain);
+
+ ivar_list_template = build_ivar_list_template (objc_ivar_template, size);
+ initlist = build_ivar_list_initializer (objc_ivar_template, chain);
+
+ UOBJC_CLASS_VARIABLES_decl
+ = generate_ivars_list (ivar_list_template, "_OBJC_CLASS_VARIABLES",
+ size, initlist);
+ TREE_TYPE (UOBJC_CLASS_VARIABLES_decl) = variable_length_type;
+ }
+ else
+ UOBJC_CLASS_VARIABLES_decl = 0;
+
+ chain = CLASS_IVARS (implementation_template);
+ if (chain)
+ {
+ size = list_length (chain);
+ ivar_list_template = build_ivar_list_template (objc_ivar_template, size);
+ initlist = build_ivar_list_initializer (objc_ivar_template, chain);
+
+ UOBJC_INSTANCE_VARIABLES_decl
+ = generate_ivars_list (ivar_list_template, "_OBJC_INSTANCE_VARIABLES",
+ size, initlist);
+ TREE_TYPE (UOBJC_INSTANCE_VARIABLES_decl) = variable_length_type;
+ }
+ else
+ UOBJC_INSTANCE_VARIABLES_decl = 0;
+
+ generating_instance_variables = 0;
+}
+
+static tree
+build_dispatch_table_initializer (type, entries)
+ tree type;
+ tree entries;
+{
+ tree initlist = NULL_TREE;
+
+ do
+ {
+ tree elemlist = NULL_TREE;
+
+ elemlist = tree_cons (NULL_TREE,
+ build_selector (METHOD_SEL_NAME (entries)),
+ NULL_TREE);
+
+ elemlist = tree_cons (NULL_TREE,
+ add_objc_string (METHOD_ENCODING (entries),
+ meth_var_types),
+ elemlist);
+
+ elemlist = tree_cons (NULL_TREE,
+ build_unary_op (ADDR_EXPR,
+ METHOD_DEFINITION (entries), 1),
+ elemlist);
+
+ initlist = tree_cons (NULL_TREE,
+ build_constructor (type, nreverse (elemlist)),
+ initlist);
+
+ entries = TREE_CHAIN (entries);
+ }
+ while (entries);
+
+ return build_constructor (build_array_type (type, 0), nreverse (initlist));
+}
+
+/* To accomplish method prototyping without generating all kinds of
+ inane warnings, the definition of the dispatch table entries were
+ changed from:
+
+ struct objc_method { SEL _cmd; ...; id (*_imp)(); };
+ to:
+ struct objc_method { SEL _cmd; ...; void *_imp; }; */
+
+static tree
+build_method_template ()
+{
+ tree _SLT_record;
+ tree decl_specs, field_decl, field_decl_chain;
+
+ _SLT_record = start_struct (RECORD_TYPE, get_identifier (UTAG_METHOD));
+
+#ifdef OBJC_INT_SELECTORS
+ /* unsigned int _cmd; */
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_UNSIGNED],
+ NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_INT], decl_specs);
+ field_decl = get_identifier ("_cmd");
+#else /* not OBJC_INT_SELECTORS */
+ /* struct objc_selector *_cmd; */
+ decl_specs = tree_cons (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SELECTOR)),
+ NULL_TREE);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("_cmd"));
+#endif /* not OBJC_INT_SELECTORS */
+
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ field_decl_chain = field_decl;
+
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_CHAR], NULL_TREE);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE,
+ get_identifier ("method_types"));
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ /* void *_imp; */
+
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_VOID], NULL_TREE);
+ field_decl = build1 (INDIRECT_REF, NULL_TREE, get_identifier ("_imp"));
+ field_decl = grokfield (input_filename, lineno, field_decl,
+ decl_specs, NULL_TREE);
+ chainon (field_decl_chain, field_decl);
+
+ finish_struct (_SLT_record, field_decl_chain, NULL_TREE);
+
+ return _SLT_record;
+}
+
+
+static tree
+generate_dispatch_table (type, name, size, list)
+ tree type;
+ char *name;
+ int size;
+ tree list;
+{
+ tree sc_spec, decl_specs, decl, initlist;
+
+ sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, type, sc_spec);
+
+ decl = start_decl (synth_id_with_class_suffix (name, implementation_context),
+ decl_specs, 1, NULL_TREE, NULL_TREE);
+
+ initlist = build_tree_list (NULL_TREE, build_int_2 (0, 0));
+ initlist = tree_cons (NULL_TREE, build_int_2 (size, 0), initlist);
+ initlist = tree_cons (NULL_TREE, list, initlist);
+
+ finish_decl (decl,
+ build_constructor (TREE_TYPE (decl), nreverse (initlist)),
+ NULL_TREE);
+
+ return decl;
+}
+
+static void
+generate_dispatch_tables ()
+{
+ tree initlist, chain, method_list_template;
+ tree cast, variable_length_type;
+ int size;
+
+ if (!objc_method_template)
+ objc_method_template = build_method_template ();
+
+ cast
+ = build_tree_list
+ (build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_METHOD_LIST))),
+ NULL_TREE);
+
+ variable_length_type = groktypename (cast);
+
+ chain = CLASS_CLS_METHODS (implementation_context);
+ if (chain)
+ {
+ size = list_length (chain);
+
+ method_list_template
+ = build_method_list_template (objc_method_template, size);
+ initlist
+ = build_dispatch_table_initializer (objc_method_template, chain);
+
+ UOBJC_CLASS_METHODS_decl
+ = generate_dispatch_table (method_list_template,
+ ((TREE_CODE (implementation_context)
+ == CLASS_IMPLEMENTATION_TYPE)
+ ? "_OBJC_CLASS_METHODS"
+ : "_OBJC_CATEGORY_CLASS_METHODS"),
+ size, initlist);
+ TREE_TYPE (UOBJC_CLASS_METHODS_decl) = variable_length_type;
+ }
+ else
+ UOBJC_CLASS_METHODS_decl = 0;
+
+ chain = CLASS_NST_METHODS (implementation_context);
+ if (chain)
+ {
+ size = list_length (chain);
+
+ method_list_template
+ = build_method_list_template (objc_method_template, size);
+ initlist
+ = build_dispatch_table_initializer (objc_method_template, chain);
+
+ if (TREE_CODE (implementation_context) == CLASS_IMPLEMENTATION_TYPE)
+ UOBJC_INSTANCE_METHODS_decl
+ = generate_dispatch_table (method_list_template,
+ "_OBJC_INSTANCE_METHODS",
+ size, initlist);
+ else
+ /* We have a category. */
+ UOBJC_INSTANCE_METHODS_decl
+ = generate_dispatch_table (method_list_template,
+ "_OBJC_CATEGORY_INSTANCE_METHODS",
+ size, initlist);
+ TREE_TYPE (UOBJC_INSTANCE_METHODS_decl) = variable_length_type;
+ }
+ else
+ UOBJC_INSTANCE_METHODS_decl = 0;
+}
+
+static tree
+generate_protocol_list (i_or_p)
+ tree i_or_p;
+{
+ static tree cast_type = 0;
+ tree initlist, decl_specs, sc_spec;
+ tree refs_decl, expr_decl, lproto, e, plist;
+ int size = 0;
+
+ if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE
+ || TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE)
+ plist = CLASS_PROTOCOL_LIST (i_or_p);
+ else if (TREE_CODE (i_or_p) == PROTOCOL_INTERFACE_TYPE)
+ plist = PROTOCOL_LIST (i_or_p);
+ else
+ abort ();
+
+ if (!cast_type)
+ cast_type
+ = groktypename
+ (build_tree_list
+ (build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_PROTOCOL))),
+ build1 (INDIRECT_REF, NULL_TREE, NULL_TREE)));
+
+ /* Compute size. */
+ for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
+ if (TREE_CODE (TREE_VALUE (lproto)) == PROTOCOL_INTERFACE_TYPE
+ && PROTOCOL_FORWARD_DECL (TREE_VALUE (lproto)))
+ size++;
+
+ /* Build initializer. */
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), NULL_TREE);
+
+ e = build_int_2 (size, 0);
+ TREE_TYPE (e) = cast_type;
+ initlist = tree_cons (NULL_TREE, e, initlist);
+
+ for (lproto = plist; lproto; lproto = TREE_CHAIN (lproto))
+ {
+ tree pval = TREE_VALUE (lproto);
+
+ if (TREE_CODE (pval) == PROTOCOL_INTERFACE_TYPE
+ && PROTOCOL_FORWARD_DECL (pval))
+ {
+ e = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (pval), 0);
+ initlist = tree_cons (NULL_TREE, e, initlist);
+ }
+ }
+
+ /* static struct objc_protocol *refs[n]; */
+
+ sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_PROTOCOL)),
+ sc_spec);
+
+ if (TREE_CODE (i_or_p) == PROTOCOL_INTERFACE_TYPE)
+ expr_decl = build_nt (ARRAY_REF,
+ synth_id_with_class_suffix ("_OBJC_PROTOCOL_REFS",
+ i_or_p),
+ build_int_2 (size + 2, 0));
+ else if (TREE_CODE (i_or_p) == CLASS_INTERFACE_TYPE)
+ expr_decl = build_nt (ARRAY_REF,
+ synth_id_with_class_suffix ("_OBJC_CLASS_PROTOCOLS",
+ i_or_p),
+ build_int_2 (size + 2, 0));
+ else if (TREE_CODE (i_or_p) == CATEGORY_INTERFACE_TYPE)
+ expr_decl
+ = build_nt (ARRAY_REF,
+ synth_id_with_class_suffix ("_OBJC_CATEGORY_PROTOCOLS",
+ i_or_p),
+ build_int_2 (size + 2, 0));
+
+ expr_decl = build1 (INDIRECT_REF, NULL_TREE, expr_decl);
+
+ refs_decl = start_decl (expr_decl, decl_specs, 1, NULL_TREE, NULL_TREE);
+
+ finish_decl (refs_decl, build_constructor (TREE_TYPE (refs_decl),
+ nreverse (initlist)),
+ NULL_TREE);
+
+ return refs_decl;
+}
+
+static tree
+build_category_initializer (type, cat_name, class_name,
+ instance_methods, class_methods, protocol_list)
+ tree type;
+ tree cat_name;
+ tree class_name;
+ tree instance_methods;
+ tree class_methods;
+ tree protocol_list;
+{
+ tree initlist = NULL_TREE, expr;
+
+ initlist = tree_cons (NULL_TREE, cat_name, initlist);
+ initlist = tree_cons (NULL_TREE, class_name, initlist);
+
+ if (!instance_methods)
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ else
+ {
+ expr = build_unary_op (ADDR_EXPR, instance_methods, 0);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+ if (!class_methods)
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ else
+ {
+ expr = build_unary_op (ADDR_EXPR, class_methods, 0);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+
+ /* protocol_list = */
+ if (!protocol_list)
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ else
+ {
+ static tree cast_type2;
+
+ if (!cast_type2)
+ cast_type2
+ = groktypename
+ (build_tree_list
+ (build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_PROTOCOL))),
+ build1 (INDIRECT_REF, NULL_TREE,
+ build1 (INDIRECT_REF, NULL_TREE, NULL_TREE))));
+
+ expr = build_unary_op (ADDR_EXPR, protocol_list, 0);
+ TREE_TYPE (expr) = cast_type2;
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+
+ return build_constructor (type, nreverse (initlist));
+}
+
+/* struct objc_class {
+ struct objc_class *isa;
+ struct objc_class *super_class;
+ char *name;
+ long version;
+ long info;
+ long instance_size;
+ struct objc_ivar_list *ivars;
+ struct objc_method_list *methods;
+ if (flag_next_runtime)
+ struct objc_cache *cache;
+ else {
+ struct sarray *dtable;
+ struct objc_class *subclass_list;
+ struct objc_class *sibling_class;
+ }
+ struct objc_protocol_list *protocols;
+ }; */
+
+static tree
+build_shared_structure_initializer (type, isa, super, name, size, status,
+ dispatch_table, ivar_list, protocol_list)
+ tree type;
+ tree isa;
+ tree super;
+ tree name;
+ tree size;
+ int status;
+ tree dispatch_table;
+ tree ivar_list;
+ tree protocol_list;
+{
+ tree initlist = NULL_TREE, expr;
+
+ /* isa = */
+ initlist = tree_cons (NULL_TREE, isa, initlist);
+
+ /* super_class = */
+ initlist = tree_cons (NULL_TREE, super, initlist);
+
+ /* name = */
+ initlist = tree_cons (NULL_TREE, default_conversion (name), initlist);
+
+ /* version = */
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+
+ /* info = */
+ initlist = tree_cons (NULL_TREE, build_int_2 (status, 0), initlist);
+
+ /* instance_size = */
+ initlist = tree_cons (NULL_TREE, size, initlist);
+
+ /* objc_ivar_list = */
+ if (!ivar_list)
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ else
+ {
+ expr = build_unary_op (ADDR_EXPR, ivar_list, 0);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+
+ /* objc_method_list = */
+ if (!dispatch_table)
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ else
+ {
+ expr = build_unary_op (ADDR_EXPR, dispatch_table, 0);
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+
+ if (flag_next_runtime)
+ /* method_cache = */
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ else
+ {
+ /* dtable = */
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+
+ /* subclass_list = */
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+
+ /* sibling_class = */
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ }
+
+ /* protocol_list = */
+ if (! protocol_list)
+ initlist = tree_cons (NULL_TREE, build_int_2 (0, 0), initlist);
+ else
+ {
+ static tree cast_type2;
+
+ if (!cast_type2)
+ cast_type2
+ = groktypename
+ (build_tree_list
+ (build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (UTAG_PROTOCOL))),
+ build1 (INDIRECT_REF, NULL_TREE,
+ build1 (INDIRECT_REF, NULL_TREE, NULL_TREE))));
+
+ expr = build_unary_op (ADDR_EXPR, protocol_list, 0);
+ TREE_TYPE (expr) = cast_type2;
+ initlist = tree_cons (NULL_TREE, expr, initlist);
+ }
+
+ return build_constructor (type, nreverse (initlist));
+}
+
+/* static struct objc_category _OBJC_CATEGORY_<name> = { ... }; */
+
+static void
+generate_category (cat)
+ tree cat;
+{
+ tree sc_spec, decl_specs, decl;
+ tree initlist, cat_name_expr, class_name_expr;
+ tree protocol_decl, category;
+
+ add_class_reference (CLASS_NAME (cat));
+ cat_name_expr = add_objc_string (CLASS_SUPER_NAME (cat), class_names);
+
+ class_name_expr = add_objc_string (CLASS_NAME (cat), class_names);
+
+ category = CLASS_CATEGORY_LIST (implementation_template);
+
+ /* find the category interface from the class it is associated with */
+ while (category)
+ {
+ if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category))
+ break;
+ category = CLASS_CATEGORY_LIST (category);
+ }
+
+ if (category && CLASS_PROTOCOL_LIST (category))
+ {
+ generate_protocol_references (CLASS_PROTOCOL_LIST (category));
+ protocol_decl = generate_protocol_list (category);
+ }
+ else
+ protocol_decl = 0;
+
+ sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
+ decl_specs = tree_cons (NULL_TREE, objc_category_template, sc_spec);
+
+ decl = start_decl (synth_id_with_class_suffix ("_OBJC_CATEGORY",
+ implementation_context),
+ decl_specs, 1, NULL_TREE, NULL_TREE);
+
+ initlist = build_category_initializer (TREE_TYPE (decl),
+ cat_name_expr, class_name_expr,
+ UOBJC_INSTANCE_METHODS_decl,
+ UOBJC_CLASS_METHODS_decl,
+ protocol_decl);
+
+ TREE_USED (decl) = 1;
+ finish_decl (decl, initlist, NULL_TREE);
+}
+
+/* static struct objc_class _OBJC_METACLASS_Foo={ ... };
+ static struct objc_class _OBJC_CLASS_Foo={ ... }; */
+
+static void
+generate_shared_structures ()
+{
+ tree sc_spec, decl_specs, decl;
+ tree name_expr, super_expr, root_expr;
+ tree my_root_id = NULL_TREE, my_super_id = NULL_TREE;
+ tree cast_type, initlist, protocol_decl;
+
+ my_super_id = CLASS_SUPER_NAME (implementation_template);
+ if (my_super_id)
+ {
+ add_class_reference (my_super_id);
+
+ /* Compute "my_root_id" - this is required for code generation.
+ the "isa" for all meta class structures points to the root of
+ the inheritance hierarchy (e.g. "__Object")... */
+ my_root_id = my_super_id;
+ do
+ {
+ tree my_root_int = lookup_interface (my_root_id);
+
+ if (my_root_int && CLASS_SUPER_NAME (my_root_int))
+ my_root_id = CLASS_SUPER_NAME (my_root_int);
+ else
+ break;
+ }
+ while (1);
+ }
+ else
+ /* No super class. */
+ my_root_id = CLASS_NAME (implementation_template);
+
+ cast_type
+ = groktypename (build_tree_list (build_tree_list (NULL_TREE,
+ objc_class_template),
+ build1 (INDIRECT_REF,
+ NULL_TREE, NULL_TREE)));
+
+ name_expr = add_objc_string (CLASS_NAME (implementation_template),
+ class_names);
+
+ /* Install class `isa' and `super' pointers at runtime. */
+ if (my_super_id)
+ {
+ super_expr = add_objc_string (my_super_id, class_names);
+ super_expr = build_c_cast (cast_type, super_expr); /* cast! */
+ }
+ else
+ super_expr = build_int_2 (0, 0);
+
+ root_expr = add_objc_string (my_root_id, class_names);
+ root_expr = build_c_cast (cast_type, root_expr); /* cast! */
+
+ if (CLASS_PROTOCOL_LIST (implementation_template))
+ {
+ generate_protocol_references
+ (CLASS_PROTOCOL_LIST (implementation_template));
+ protocol_decl = generate_protocol_list (implementation_template);
+ }
+ else
+ protocol_decl = 0;
+
+ /* static struct objc_class _OBJC_METACLASS_Foo = { ... }; */
+
+ sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]);
+ decl_specs = tree_cons (NULL_TREE, objc_class_template, sc_spec);
+
+ decl = start_decl (DECL_NAME (UOBJC_METACLASS_decl), decl_specs, 1,
+ NULL_TREE, NULL_TREE);
+
+ initlist
+ = build_shared_structure_initializer
+ (TREE_TYPE (decl),
+ root_expr, super_expr, name_expr,
+ build_int_2 ((TREE_INT_CST_LOW (TYPE_SIZE (objc_class_template))
+ / BITS_PER_UNIT),
+ 0),
+ 2 /*CLS_META*/,
+ UOBJC_CLASS_METHODS_decl,
+ UOBJC_CLASS_VARIABLES_decl,
+ protocol_decl);
+
+ finish_decl (decl, initlist, NULL_TREE);
+
+ /* static struct objc_class _OBJC_CLASS_Foo={ ... }; */
+
+ decl = start_decl (DECL_NAME (UOBJC_CLASS_decl), decl_specs, 1,
+ NULL_TREE, NULL_TREE);
+
+ initlist
+ = build_shared_structure_initializer
+ (TREE_TYPE (decl),
+ build_unary_op (ADDR_EXPR, UOBJC_METACLASS_decl, 0),
+ super_expr, name_expr,
+ build_int_2
+ ((TREE_INT_CST_LOW
+ (TYPE_SIZE (CLASS_STATIC_TEMPLATE (implementation_template)))
+ / BITS_PER_UNIT),
+ 0),
+ 1 /*CLS_FACTORY*/,
+ UOBJC_INSTANCE_METHODS_decl,
+ UOBJC_INSTANCE_VARIABLES_decl,
+ protocol_decl);
+
+ finish_decl (decl, initlist, NULL_TREE);
+}
+
+static tree
+synth_id_with_class_suffix (preamble, ctxt)
+ char *preamble;
+ tree ctxt;
+{
+ char *string;
+ if (TREE_CODE (ctxt) == CLASS_IMPLEMENTATION_TYPE
+ || TREE_CODE (ctxt) == CLASS_INTERFACE_TYPE)
+ {
+ char *class_name
+ = IDENTIFIER_POINTER (CLASS_NAME (implementation_context));
+ string = (char *) alloca (strlen (preamble) + strlen (class_name) + 3);
+ sprintf (string, "%s_%s", preamble,
+ IDENTIFIER_POINTER (CLASS_NAME (ctxt)));
+ }
+ else if (TREE_CODE (ctxt) == CATEGORY_IMPLEMENTATION_TYPE
+ || TREE_CODE (ctxt) == CATEGORY_INTERFACE_TYPE)
+ {
+ /* We have a category. */
+ char *class_name
+ = IDENTIFIER_POINTER (CLASS_NAME (implementation_context));
+ char *class_super_name
+ = IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context));
+ string = (char *) alloca (strlen (preamble)
+ + strlen (class_name)
+ + strlen (class_super_name)
+ + 3);
+ sprintf (string, "%s_%s_%s", preamble, class_name, class_super_name);
+ }
+ else if (TREE_CODE (ctxt) == PROTOCOL_INTERFACE_TYPE)
+ {
+ char *protocol_name = IDENTIFIER_POINTER (PROTOCOL_NAME (ctxt));
+ string
+ = (char *) alloca (strlen (preamble) + strlen (protocol_name) + 3);
+ sprintf (string, "%s_%s", preamble, protocol_name);
+ }
+ return get_identifier (string);
+}
+
+static int
+is_objc_type_qualifier (node)
+ tree node;
+{
+ return (TREE_CODE (node) == IDENTIFIER_NODE
+ && (node == ridpointers [(int) RID_CONST]
+ || node == ridpointers [(int) RID_VOLATILE]
+ || node == ridpointers [(int) RID_IN]
+ || node == ridpointers [(int) RID_OUT]
+ || node == ridpointers [(int) RID_INOUT]
+ || node == ridpointers [(int) RID_BYCOPY]
+ || node == ridpointers [(int) RID_ONEWAY]));
+}
+
+/* If type is empty or only type qualifiers are present, add default
+ type of id (otherwise grokdeclarator will default to int). */
+
+static tree
+adjust_type_for_id_default (type)
+ tree type;
+{
+ tree declspecs, chain;
+
+ if (!type)
+ return build_tree_list (build_tree_list (NULL_TREE, objc_object_reference),
+ build1 (INDIRECT_REF, NULL_TREE, NULL_TREE));
+
+ declspecs = TREE_PURPOSE (type);
+
+ /* Determine if a typespec is present. */
+ for (chain = declspecs;
+ chain;
+ chain = TREE_CHAIN (chain))
+ {
+ if (!is_objc_type_qualifier (TREE_VALUE (chain)))
+ return type;
+ }
+
+ return build_tree_list (tree_cons (NULL_TREE, objc_object_reference,
+ declspecs),
+ build1 (INDIRECT_REF, NULL_TREE, NULL_TREE));
+}
+
+/* Usage:
+ keyworddecl:
+ selector ':' '(' typename ')' identifier
+
+ Purpose:
+ Transform an Objective-C keyword argument into
+ the C equivalent parameter declarator.
+
+ In: key_name, an "identifier_node" (optional).
+ arg_type, a "tree_list" (optional).
+ arg_name, an "identifier_node".
+
+ Note: It would be really nice to strongly type the preceding
+ arguments in the function prototype; however, then I
+ could not use the "accessor" macros defined in "tree.h".
+
+ Out: an instance of "keyword_decl". */
+
+tree
+build_keyword_decl (key_name, arg_type, arg_name)
+ tree key_name;
+ tree arg_type;
+ tree arg_name;
+{
+ tree keyword_decl;
+
+ /* If no type is specified, default to "id". */
+ arg_type = adjust_type_for_id_default (arg_type);
+
+ keyword_decl = make_node (KEYWORD_DECL);
+
+ TREE_TYPE (keyword_decl) = arg_type;
+ KEYWORD_ARG_NAME (keyword_decl) = arg_name;
+ KEYWORD_KEY_NAME (keyword_decl) = key_name;
+
+ return keyword_decl;
+}
+
+/* Given a chain of keyword_decl's, synthesize the full keyword selector. */
+
+static tree
+build_keyword_selector (selector)
+ tree selector;
+{
+ int len = 0;
+ tree key_chain, key_name;
+ char *buf;
+
+ for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain))
+ {
+ if (TREE_CODE (selector) == KEYWORD_DECL)
+ key_name = KEYWORD_KEY_NAME (key_chain);
+ else if (TREE_CODE (selector) == TREE_LIST)
+ key_name = TREE_PURPOSE (key_chain);
+
+ if (key_name)
+ len += IDENTIFIER_LENGTH (key_name) + 1;
+ else
+ /* Just a ':' arg. */
+ len++;
+ }
+
+ buf = (char *)alloca (len + 1);
+ bzero (buf, len + 1);
+
+ for (key_chain = selector; key_chain; key_chain = TREE_CHAIN (key_chain))
+ {
+ if (TREE_CODE (selector) == KEYWORD_DECL)
+ key_name = KEYWORD_KEY_NAME (key_chain);
+ else if (TREE_CODE (selector) == TREE_LIST)
+ key_name = TREE_PURPOSE (key_chain);
+
+ if (key_name)
+ strcat (buf, IDENTIFIER_POINTER (key_name));
+ strcat (buf, ":");
+ }
+
+ return get_identifier (buf);
+}
+
+/* Used for declarations and definitions. */
+
+tree
+build_method_decl (code, ret_type, selector, add_args)
+ enum tree_code code;
+ tree ret_type;
+ tree selector;
+ tree add_args;
+{
+ tree method_decl;
+
+ /* If no type is specified, default to "id". */
+ ret_type = adjust_type_for_id_default (ret_type);
+
+ method_decl = make_node (code);
+ TREE_TYPE (method_decl) = ret_type;
+
+ /* If we have a keyword selector, create an identifier_node that
+ represents the full selector name (`:' included)... */
+ if (TREE_CODE (selector) == KEYWORD_DECL)
+ {
+ METHOD_SEL_NAME (method_decl) = build_keyword_selector (selector);
+ METHOD_SEL_ARGS (method_decl) = selector;
+ METHOD_ADD_ARGS (method_decl) = add_args;
+ }
+ else
+ {
+ METHOD_SEL_NAME (method_decl) = selector;
+ METHOD_SEL_ARGS (method_decl) = NULL_TREE;
+ METHOD_ADD_ARGS (method_decl) = NULL_TREE;
+ }
+
+ return method_decl;
+}
+
+#define METHOD_DEF 0
+#define METHOD_REF 1
+
+/* Used by `build_message_expr' and `comp_method_types'. Return an
+ argument list for method METH. CONTEXT is either METHOD_DEF or
+ METHOD_REF, saying whether we are trying to define a method or call
+ one. SUPERFLAG says this is for a send to super; this makes a
+ difference for the NeXT calling sequence in which the lookup and
+ the method call are done together. */
+
+static tree
+get_arg_type_list (meth, context, superflag)
+ tree meth;
+ int context;
+ int superflag;
+{
+ tree arglist, akey;
+
+ /* Receiver type. */
+ if (flag_next_runtime && superflag)
+ arglist = build_tree_list (NULL_TREE, super_type);
+ else if (context == METHOD_DEF)
+ arglist = build_tree_list (NULL_TREE, TREE_TYPE (self_decl));
+ else
+ arglist = build_tree_list (NULL_TREE, id_type);
+
+ /* Selector type - will eventually change to `int'. */
+ chainon (arglist, build_tree_list (NULL_TREE, selector_type));
+
+ /* Build a list of argument types. */
+ for (akey = METHOD_SEL_ARGS (meth); akey; akey = TREE_CHAIN (akey))
+ {
+ tree arg_decl = groktypename_in_parm_context (TREE_TYPE (akey));
+ chainon (arglist, build_tree_list (NULL_TREE, TREE_TYPE (arg_decl)));
+ }
+
+ if (METHOD_ADD_ARGS (meth) == (tree)1)
+ /* We have a `, ...' immediately following the selector,
+ finalize the arglist...simulate get_parm_info (0). */
+ ;
+ else if (METHOD_ADD_ARGS (meth))
+ {
+ /* we have a variable length selector */
+ tree add_arg_list = TREE_CHAIN (METHOD_ADD_ARGS (meth));
+ chainon (arglist, add_arg_list);
+ }
+ else
+ /* finalize the arglist...simulate get_parm_info (1) */
+ chainon (arglist, build_tree_list (NULL_TREE, void_type_node));
+
+ return arglist;
+}
+
+static tree
+check_duplicates (hsh)
+ hash hsh;
+{
+ tree meth = NULL_TREE;
+
+ if (hsh)
+ {
+ meth = hsh->key;
+
+ if (hsh->list)
+ {
+ /* We have two methods with the same name and different types. */
+ attr loop;
+ char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL) ? '-' : '+';
+
+ warning ("multiple declarations for method `%s'",
+ IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
+
+ warn_with_method ("using", type, meth);
+ for (loop = hsh->list; loop; loop = loop->next)
+ warn_with_method ("also found", type, loop->value);
+ }
+ }
+ return meth;
+}
+
+/* If RECEIVER is a class reference, return the identifier node for the
+ referenced class. RECEIVER is created by get_class_reference, so we
+ check the exact form created depending on which runtimes are used. */
+
+static tree
+receiver_is_class_object (receiver)
+ tree receiver;
+{
+ tree chain, exp, arg;
+ if (flag_next_runtime)
+ {
+ /* The receiver is a variable created by build_class_reference_decl. */
+ if (TREE_CODE (receiver) == VAR_DECL
+ && TREE_TYPE (receiver) == objc_class_type)
+ /* Look up the identifier. */
+ for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain))
+ if (TREE_PURPOSE (chain) == receiver)
+ return TREE_VALUE (chain);
+ }
+ else
+ {
+ /* The receiver is a function call that returns an id. Check if
+ it is a call to objc_getClass, if so, pick up the class name. */
+ if ((exp = TREE_OPERAND (receiver, 0))
+ && TREE_CODE (exp) == ADDR_EXPR
+ && (exp = TREE_OPERAND (exp, 0))
+ && TREE_CODE (exp) == FUNCTION_DECL
+ && exp == objc_get_class_decl
+ /* we have a call to objc_getClass! */
+ && (arg = TREE_OPERAND (receiver, 1))
+ && TREE_CODE (arg) == TREE_LIST
+ && (arg = TREE_VALUE (arg)))
+ {
+ STRIP_NOPS (arg);
+ if (TREE_CODE (arg) == ADDR_EXPR
+ && (arg = TREE_OPERAND (arg, 0))
+ && TREE_CODE (arg) == STRING_CST)
+ /* Finally, we have the class name. */
+ return get_identifier (TREE_STRING_POINTER (arg));
+ }
+ }
+ return 0;
+}
+
+/* If we are currently building a message expr, this holds
+ the identifier of the selector of the message. This is
+ used when printing warnings about argument mismatches. */
+
+static tree building_objc_message_expr = 0;
+
+tree
+maybe_building_objc_message_expr ()
+{
+ return building_objc_message_expr;
+}
+
+/* Construct an expression for sending a message.
+ MESS has the object to send to in TREE_PURPOSE
+ and the argument list (including selector) in TREE_VALUE.
+
+ (*(<abstract_decl>(*)())_msg)(receiver, selTransTbl[n], ...);
+ (*(<abstract_decl>(*)())_msgSuper)(receiver, selTransTbl[n], ...); */
+
+tree
+build_message_expr (mess)
+ tree mess;
+{
+ tree receiver = TREE_PURPOSE (mess);
+ tree selector, self_object;
+ tree rtype, sel_name;
+ tree args = TREE_VALUE (mess);
+ tree method_params = NULL_TREE;
+ tree method_prototype = NULL_TREE;
+ tree retval;
+ int statically_typed = 0, statically_allocated = 0;
+ tree class_ident = 0;
+
+ /* 1 if this is sending to the superclass. */
+ int super;
+
+ if (!doing_objc_thang)
+ objc_fatal ();
+
+ if (TREE_CODE (receiver) == ERROR_MARK)
+ return error_mark_node;
+
+ /* Determine receiver type. */
+ rtype = TREE_TYPE (receiver);
+ super = IS_SUPER (rtype);
+
+ if (! super)
+ {
+ if (TREE_STATIC_TEMPLATE (rtype))
+ statically_allocated = 1;
+ else if (TREE_CODE (rtype) == POINTER_TYPE
+ && TREE_STATIC_TEMPLATE (TREE_TYPE (rtype)))
+ statically_typed = 1;
+ else if ((flag_next_runtime
+ || (TREE_CODE (receiver) == CALL_EXPR && IS_ID (rtype)))
+ && (class_ident = receiver_is_class_object (receiver)))
+ ;
+ else if (! IS_ID (rtype)
+ /* Allow any type that matches objc_class_type. */
+ && ! comptypes (rtype, objc_class_type))
+ {
+ bzero (errbuf, BUFSIZE);
+ warning ("invalid receiver type `%s'",
+ gen_declaration (rtype, errbuf));
+ }
+
+ if (statically_allocated)
+ receiver = build_unary_op (ADDR_EXPR, receiver, 0);
+
+ /* Don't evaluate the receiver twice. */
+ receiver = save_expr (receiver);
+ self_object = receiver;
+ }
+ else
+ /* If sending to `super', use current self as the object. */
+ self_object = self_decl;
+
+ /* Obtain the full selector name. */
+
+ if (TREE_CODE (args) == IDENTIFIER_NODE)
+ /* A unary selector. */
+ sel_name = args;
+ else if (TREE_CODE (args) == TREE_LIST)
+ sel_name = build_keyword_selector (args);
+
+ /* Build the parameter list to give to the method. */
+
+ method_params = NULL_TREE;
+ if (TREE_CODE (args) == TREE_LIST)
+ {
+ tree chain = args, prev = NULL_TREE;
+
+ /* We have a keyword selector--check for comma expressions. */
+ while (chain)
+ {
+ tree element = TREE_VALUE (chain);
+
+ /* We have a comma expression, must collapse... */
+ if (TREE_CODE (element) == TREE_LIST)
+ {
+ if (prev)
+ TREE_CHAIN (prev) = element;
+ else
+ args = element;
+ }
+ prev = chain;
+ chain = TREE_CHAIN (chain);
+ }
+ method_params = args;
+ }
+
+ /* Determine operation return type. */
+
+ if (IS_SUPER (rtype))
+ {
+ tree iface;
+
+ if (CLASS_SUPER_NAME (implementation_template))
+ {
+ iface
+ = lookup_interface (CLASS_SUPER_NAME (implementation_template));
+
+ if (TREE_CODE (method_context) == INSTANCE_METHOD_DECL)
+ method_prototype = lookup_instance_method_static (iface, sel_name);
+ else
+ method_prototype = lookup_class_method_static (iface, sel_name);
+
+ if (iface && !method_prototype)
+ warning ("`%s' does not respond to `%s'",
+ IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_template)),
+ IDENTIFIER_POINTER (sel_name));
+ }
+ else
+ {
+ error ("no super class declared in interface for `%s'",
+ IDENTIFIER_POINTER (CLASS_NAME (implementation_template)));
+ return error_mark_node;
+ }
+
+ }
+ else if (statically_allocated)
+ {
+ tree ctype = TREE_TYPE (rtype);
+ tree iface = lookup_interface (TYPE_NAME (rtype));
+
+ if (iface)
+ method_prototype = lookup_instance_method_static (iface, sel_name);
+
+ if (! method_prototype && TYPE_PROTOCOL_LIST (ctype))
+ method_prototype
+ = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype),
+ sel_name, 0);
+
+ if (!method_prototype)
+ warning ("`%s' does not respond to `%s'",
+ IDENTIFIER_POINTER (TYPE_NAME (rtype)),
+ IDENTIFIER_POINTER (sel_name));
+ }
+ else if (statically_typed)
+ {
+ tree ctype = TREE_TYPE (rtype);
+
+ /* `self' is now statically_typed. All methods should be visible
+ within the context of the implementation. */
+ if (implementation_context
+ && CLASS_NAME (implementation_context) == TYPE_NAME (ctype))
+ {
+ method_prototype
+ = lookup_instance_method_static (implementation_template,
+ sel_name);
+
+ if (! method_prototype && TYPE_PROTOCOL_LIST (ctype))
+ method_prototype
+ = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype),
+ sel_name, 0);
+
+ if (! method_prototype
+ && implementation_template != implementation_context)
+ /* The method is not published in the interface. Check
+ locally. */
+ method_prototype
+ = lookup_method (CLASS_NST_METHODS (implementation_context),
+ sel_name);
+ }
+ else
+ {
+ tree iface;
+
+ if ((iface = lookup_interface (TYPE_NAME (ctype))))
+ method_prototype = lookup_instance_method_static (iface, sel_name);
+
+ if (! method_prototype)
+ {
+ tree protocol_list = TYPE_PROTOCOL_LIST (ctype);
+ if (protocol_list)
+ method_prototype
+ = lookup_method_in_protocol_list (protocol_list,
+ sel_name, 0);
+ }
+ }
+
+ if (!method_prototype)
+ warning ("`%s' does not respond to `%s'",
+ IDENTIFIER_POINTER (TYPE_NAME (ctype)),
+ IDENTIFIER_POINTER (sel_name));
+ }
+ else if (class_ident)
+ {
+ if (implementation_context
+ && CLASS_NAME (implementation_context) == class_ident)
+ {
+ method_prototype
+ = lookup_class_method_static (implementation_template, sel_name);
+
+ if (!method_prototype
+ && implementation_template != implementation_context)
+ /* The method is not published in the interface. Check
+ locally. */
+ method_prototype
+ = lookup_method (CLASS_CLS_METHODS (implementation_context),
+ sel_name);
+ }
+ else
+ {
+ tree iface;
+
+ if ((iface = lookup_interface (class_ident)))
+ method_prototype = lookup_class_method_static (iface, sel_name);
+ }
+
+ if (!method_prototype)
+ {
+ warning ("cannot find class (factory) method.");
+ warning ("return type for `%s' defaults to id",
+ IDENTIFIER_POINTER (sel_name));
+ }
+ }
+ else if (IS_PROTOCOL_QUALIFIED_ID (rtype))
+ {
+ /* An anonymous object that has been qualified with a protocol. */
+
+ tree protocol_list = TYPE_PROTOCOL_LIST (rtype);
+
+ method_prototype = lookup_method_in_protocol_list (protocol_list,
+ sel_name, 0);
+
+ if (!method_prototype)
+ {
+ hash hsh;
+
+ warning ("method `%s' not implemented by protocol.",
+ IDENTIFIER_POINTER (sel_name));
+
+ /* Try and find the method signature in the global pools. */
+
+ if (!(hsh = hash_lookup (nst_method_hash_list, sel_name)))
+ hsh = hash_lookup (cls_method_hash_list, sel_name);
+
+ if (!(method_prototype = check_duplicates (hsh)))
+ warning ("return type defaults to id");
+ }
+ }
+ else
+ {
+ hash hsh;
+
+ /* We think we have an instance...loophole: extern id Object; */
+ hsh = hash_lookup (nst_method_hash_list, sel_name);
+ if (!hsh)
+ /* For various loopholes, like sending messages to self in a
+ factory context. */
+ hsh = hash_lookup (cls_method_hash_list, sel_name);
+
+ method_prototype = check_duplicates (hsh);
+ if (!method_prototype)
+ {
+ warning ("cannot find method.");
+ warning ("return type for `%s' defaults to id",
+ IDENTIFIER_POINTER (sel_name));
+ }
+ }
+
+ /* Save the selector name for printing error messages. */
+ building_objc_message_expr = sel_name;
+
+ /* Build the parameters list for looking up the method.
+ These are the object itself and the selector. */
+
+ if (flag_typed_selectors)
+ selector = build_typed_selector_reference (sel_name, method_prototype);
+ else
+ selector = build_selector_reference (sel_name);
+
+ retval = build_objc_method_call (super, method_prototype,
+ receiver, self_object,
+ selector, method_params);
+
+ building_objc_message_expr = 0;
+
+ return retval;
+}
+
+/* Build a tree expression to send OBJECT the operation SELECTOR,
+ looking up the method on object LOOKUP_OBJECT (often same as OBJECT),
+ assuming the method has prototype METHOD_PROTOTYPE.
+ (That is an INSTANCE_METHOD_DECL or CLASS_METHOD_DECL.)
+ Use METHOD_PARAMS as list of args to pass to the method.
+ If SUPER_FLAG is nonzero, we look up the superclass's method. */
+
+static tree
+build_objc_method_call (super_flag, method_prototype, lookup_object, object,
+ selector, method_params)
+ int super_flag;
+ tree method_prototype, lookup_object, object, selector, method_params;
+{
+ tree sender = (super_flag ? umsg_super_decl : umsg_decl);
+ tree rcv_p = (super_flag
+ ? build_pointer_type (xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SUPER)))
+ : id_type);
+
+ if (flag_next_runtime)
+ {
+ if (! method_prototype)
+ {
+ method_params = tree_cons (NULL_TREE, lookup_object,
+ tree_cons (NULL_TREE, selector,
+ method_params));
+ assemble_external (sender);
+ return build_function_call (sender, method_params);
+ }
+ else
+ {
+ /* This is a real kludge, but it is used only for the Next.
+ Clobber the data type of SENDER temporarily to accept
+ all the arguments for this operation, and to return
+ whatever this operation returns. */
+ tree arglist = NULL_TREE;
+ tree retval;
+
+ /* Save the proper contents of SENDER's data type. */
+ tree savarg = TYPE_ARG_TYPES (TREE_TYPE (sender));
+ tree savret = TREE_TYPE (TREE_TYPE (sender));
+
+ /* Install this method's argument types. */
+ arglist = get_arg_type_list (method_prototype, METHOD_REF,
+ super_flag);
+ TYPE_ARG_TYPES (TREE_TYPE (sender)) = arglist;
+
+ /* Install this method's return type. */
+ TREE_TYPE (TREE_TYPE (sender))
+ = groktypename (TREE_TYPE (method_prototype));
+
+ /* Call SENDER with all the parameters. This will do type
+ checking using the arg types for this method. */
+ method_params = tree_cons (NULL_TREE, lookup_object,
+ tree_cons (NULL_TREE, selector,
+ method_params));
+ assemble_external (sender);
+ retval = build_function_call (sender, method_params);
+
+ /* Restore SENDER's return/argument types. */
+ TYPE_ARG_TYPES (TREE_TYPE (sender)) = savarg;
+ TREE_TYPE (TREE_TYPE (sender)) = savret;
+ return retval;
+ }
+ }
+ else
+ {
+ /* This is the portable way.
+ First call the lookup function to get a pointer to the method,
+ then cast the pointer, then call it with the method arguments. */
+ tree method;
+
+ /* Avoid trouble since we may evaluate each of these twice. */
+ object = save_expr (object);
+ selector = save_expr (selector);
+
+ lookup_object = build_c_cast (rcv_p, lookup_object);
+
+ assemble_external (sender);
+ method
+ = build_function_call (sender,
+ tree_cons (NULL_TREE, lookup_object,
+ tree_cons (NULL_TREE, selector,
+ NULL_TREE)));
+
+ /* If we have a method prototype, construct the data type this
+ method needs, and cast what we got from SENDER into a pointer
+ to that type. */
+ if (method_prototype)
+ {
+ tree arglist = get_arg_type_list (method_prototype, METHOD_REF,
+ super_flag);
+ tree valtype = groktypename (TREE_TYPE (method_prototype));
+ tree fake_function_type = build_function_type (valtype, arglist);
+ TREE_TYPE (method) = build_pointer_type (fake_function_type);
+ }
+ else
+ TREE_TYPE (method)
+ = build_pointer_type (build_function_type (ptr_type_node, NULL_TREE));
+
+ /* Pass the object to the method. */
+ assemble_external (method);
+ return build_function_call (method,
+ tree_cons (NULL_TREE, object,
+ tree_cons (NULL_TREE, selector,
+ method_params)));
+ }
+}
+
+static void
+build_protocol_reference (p)
+ tree p;
+{
+ tree decl, ident, ptype;
+
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+
+ /* extern struct objc_protocol _OBJC_PROTOCOL_<mumble>; */
+
+ ident = synth_id_with_class_suffix ("_OBJC_PROTOCOL", p);
+ ptype
+ = groktypename (build_tree_list (build_tree_list (NULL_TREE,
+ objc_protocol_template),
+ NULL_TREE));
+
+ if (IDENTIFIER_GLOBAL_VALUE (ident))
+ decl = IDENTIFIER_GLOBAL_VALUE (ident); /* Set by pushdecl. */
+ else
+ {
+ decl = build_decl (VAR_DECL, ident, ptype);
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ TREE_USED (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+
+ make_decl_rtl (decl, 0, 1);
+ pushdecl_top_level (decl);
+ }
+
+ PROTOCOL_FORWARD_DECL (p) = decl;
+ pop_obstacks ();
+}
+
+tree
+build_protocol_expr (protoname)
+ tree protoname;
+{
+ tree expr;
+ tree p;
+
+ if (!doing_objc_thang)
+ objc_fatal ();
+
+ p = lookup_protocol (protoname);
+
+ if (!p)
+ {
+ error ("Cannot find protocol declaration for `%s'",
+ IDENTIFIER_POINTER (protoname));
+ return error_mark_node;
+ }
+
+ if (!PROTOCOL_FORWARD_DECL (p))
+ build_protocol_reference (p);
+
+ expr = build_unary_op (ADDR_EXPR, PROTOCOL_FORWARD_DECL (p), 0);
+
+ TREE_TYPE (expr) = protocol_type;
+
+ return expr;
+}
+
+tree
+build_selector_expr (selnamelist)
+ tree selnamelist;
+{
+ tree selname;
+
+ if (!doing_objc_thang)
+ objc_fatal ();
+
+ /* Obtain the full selector name. */
+ if (TREE_CODE (selnamelist) == IDENTIFIER_NODE)
+ /* A unary selector. */
+ selname = selnamelist;
+ else if (TREE_CODE (selnamelist) == TREE_LIST)
+ selname = build_keyword_selector (selnamelist);
+
+ if (flag_typed_selectors)
+ return build_typed_selector_reference (selname, 0);
+ else
+ return build_selector_reference (selname);
+}
+
+tree
+build_encode_expr (type)
+ tree type;
+{
+ tree result;
+ char *string;
+
+ if (!doing_objc_thang)
+ objc_fatal ();
+
+ encode_type (type, obstack_object_size (&util_obstack),
+ OBJC_ENCODE_INLINE_DEFS);
+ obstack_1grow (&util_obstack, 0); /* null terminate string */
+ string = obstack_finish (&util_obstack);
+
+ /* Synthesize a string that represents the encoded struct/union. */
+ result = my_build_string (strlen (string) + 1, string);
+ obstack_free (&util_obstack, util_firstobj);
+ return result;
+}
+
+tree
+build_ivar_reference (id)
+ tree id;
+{
+ if (TREE_CODE (method_context) == CLASS_METHOD_DECL)
+ {
+ /* Historically, a class method that produced objects (factory
+ method) would assign `self' to the instance that it
+ allocated. This would effectively turn the class method into
+ an instance method. Following this assignment, the instance
+ variables could be accessed. That practice, while safe,
+ violates the simple rule that a class method should not refer
+ to an instance variable. It's better to catch the cases
+ where this is done unknowingly than to support the above
+ paradigm. */
+ warning ("instance variable `%s' accessed in class method",
+ IDENTIFIER_POINTER (id));
+ TREE_TYPE (self_decl) = instance_type; /* cast */
+ }
+
+ return build_component_ref (build_indirect_ref (self_decl, "->"), id);
+}
+
+#define HASH_ALLOC_LIST_SIZE 170
+#define ATTR_ALLOC_LIST_SIZE 170
+#define SIZEHASHTABLE 257
+
+/* make positive */
+#define HASHFUNCTION(key) ((HOST_WIDE_INT) key & 0x7fffffff)
+
+static void
+hash_init ()
+{
+ nst_method_hash_list = (hash *)xmalloc (SIZEHASHTABLE * sizeof (hash));
+ cls_method_hash_list = (hash *)xmalloc (SIZEHASHTABLE * sizeof (hash));
+
+ if (!nst_method_hash_list || !cls_method_hash_list)
+ perror ("unable to allocate space in objc-tree.c");
+ else
+ {
+ int i;
+
+ for (i = 0; i < SIZEHASHTABLE; i++)
+ {
+ nst_method_hash_list[i] = 0;
+ cls_method_hash_list[i] = 0;
+ }
+ }
+}
+
+static void
+hash_enter (hashlist, method)
+ hash *hashlist;
+ tree method;
+{
+ static hash hash_alloc_list = 0;
+ static int hash_alloc_index = 0;
+ hash obj;
+ int slot = HASHFUNCTION (METHOD_SEL_NAME (method)) % SIZEHASHTABLE;
+
+ if (! hash_alloc_list || hash_alloc_index >= HASH_ALLOC_LIST_SIZE)
+ {
+ hash_alloc_index = 0;
+ hash_alloc_list = (hash) xmalloc (sizeof (struct hashed_entry)
+ * HASH_ALLOC_LIST_SIZE);
+ if (! hash_alloc_list)
+ perror ("unable to allocate in objc-tree.c");
+ }
+ obj = &hash_alloc_list[hash_alloc_index++];
+ obj->list = 0;
+ obj->next = hashlist[slot];
+ obj->key = method;
+
+ hashlist[slot] = obj; /* append to front */
+}
+
+static hash
+hash_lookup (hashlist, sel_name)
+ hash *hashlist;
+ tree sel_name;
+{
+ hash target;
+
+ target = hashlist[HASHFUNCTION (sel_name) % SIZEHASHTABLE];
+
+ while (target)
+ {
+ if (sel_name == METHOD_SEL_NAME (target->key))
+ return target;
+
+ target = target->next;
+ }
+ return 0;
+}
+
+static void
+hash_add_attr (entry, value)
+ hash entry;
+ tree value;
+{
+ static attr attr_alloc_list = 0;
+ static int attr_alloc_index = 0;
+ attr obj;
+
+ if (! attr_alloc_list || attr_alloc_index >= ATTR_ALLOC_LIST_SIZE)
+ {
+ attr_alloc_index = 0;
+ attr_alloc_list = (attr) xmalloc (sizeof (struct hashed_attribute)
+ * ATTR_ALLOC_LIST_SIZE);
+ if (! attr_alloc_list)
+ perror ("unable to allocate in objc-tree.c");
+ }
+ obj = &attr_alloc_list[attr_alloc_index++];
+ obj->next = entry->list;
+ obj->value = value;
+
+ entry->list = obj; /* append to front */
+}
+
+static tree
+lookup_method (mchain, method)
+ tree mchain;
+ tree method;
+{
+ tree key;
+
+ if (TREE_CODE (method) == IDENTIFIER_NODE)
+ key = method;
+ else
+ key = METHOD_SEL_NAME (method);
+
+ while (mchain)
+ {
+ if (METHOD_SEL_NAME (mchain) == key)
+ return mchain;
+ mchain = TREE_CHAIN (mchain);
+ }
+ return NULL_TREE;
+}
+
+static tree
+lookup_instance_method_static (interface, ident)
+ tree interface;
+ tree ident;
+{
+ tree inter = interface;
+ tree chain = CLASS_NST_METHODS (inter);
+ tree meth = NULL_TREE;
+
+ do
+ {
+ if ((meth = lookup_method (chain, ident)))
+ return meth;
+
+ if (CLASS_CATEGORY_LIST (inter))
+ {
+ tree category = CLASS_CATEGORY_LIST (inter);
+ chain = CLASS_NST_METHODS (category);
+
+ do
+ {
+ if ((meth = lookup_method (chain, ident)))
+ return meth;
+
+ /* Check for instance methods in protocols in categories. */
+ if (CLASS_PROTOCOL_LIST (category))
+ {
+ if ((meth = (lookup_method_in_protocol_list
+ (CLASS_PROTOCOL_LIST (category), ident, 0))))
+ return meth;
+ }
+
+ if ((category = CLASS_CATEGORY_LIST (category)))
+ chain = CLASS_NST_METHODS (category);
+ }
+ while (category);
+ }
+
+ if (CLASS_PROTOCOL_LIST (inter))
+ {
+ if ((meth = (lookup_method_in_protocol_list
+ (CLASS_PROTOCOL_LIST (inter), ident, 0))))
+ return meth;
+ }
+
+ if ((inter = lookup_interface (CLASS_SUPER_NAME (inter))))
+ chain = CLASS_NST_METHODS (inter);
+ }
+ while (inter);
+
+ return meth;
+}
+
+static tree
+lookup_class_method_static (interface, ident)
+ tree interface;
+ tree ident;
+{
+ tree inter = interface;
+ tree chain = CLASS_CLS_METHODS (inter);
+ tree meth = NULL_TREE;
+ tree root_inter = NULL_TREE;
+
+ do
+ {
+ if ((meth = lookup_method (chain, ident)))
+ return meth;
+
+ if (CLASS_CATEGORY_LIST (inter))
+ {
+ tree category = CLASS_CATEGORY_LIST (inter);
+ chain = CLASS_CLS_METHODS (category);
+
+ do
+ {
+ if ((meth = lookup_method (chain, ident)))
+ return meth;
+
+ /* Check for class methods in protocols in categories. */
+ if (CLASS_PROTOCOL_LIST (category))
+ {
+ if ((meth = (lookup_method_in_protocol_list
+ (CLASS_PROTOCOL_LIST (category), ident, 1))))
+ return meth;
+ }
+
+ if ((category = CLASS_CATEGORY_LIST (category)))
+ chain = CLASS_CLS_METHODS (category);
+ }
+ while (category);
+ }
+
+ /* Check for class methods in protocols. */
+ if (CLASS_PROTOCOL_LIST (inter))
+ {
+ if ((meth = (lookup_method_in_protocol_list
+ (CLASS_PROTOCOL_LIST (inter), ident, 1))))
+ return meth;
+ }
+
+ root_inter = inter;
+ if ((inter = lookup_interface (CLASS_SUPER_NAME (inter))))
+ chain = CLASS_CLS_METHODS (inter);
+ }
+ while (inter);
+
+ /* Simulate wrap around. */
+ return lookup_instance_method_static (root_inter, ident);
+}
+
+tree
+add_class_method (class, method)
+ tree class;
+ tree method;
+{
+ tree mth;
+ hash hsh;
+
+ /* We will have allocated the method parameter declarations on the
+ maybepermanent_obstack. Need to make sure they stick around! */
+ preserve_data ();
+
+ if (!(mth = lookup_method (CLASS_CLS_METHODS (class), method)))
+ {
+ /* put method on list in reverse order */
+ TREE_CHAIN (method) = CLASS_CLS_METHODS (class);
+ CLASS_CLS_METHODS (class) = method;
+ }
+ else
+ {
+ if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE)
+ error ("duplicate definition of class method `%s'.",
+ IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
+ else
+ {
+ /* Check types; if different, complain. */
+ if (!comp_proto_with_proto (method, mth))
+ error ("duplicate declaration of class method `%s'.",
+ IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
+ }
+ }
+
+ if (!(hsh = hash_lookup (cls_method_hash_list, METHOD_SEL_NAME (method))))
+ {
+ /* Install on a global chain. */
+ hash_enter (cls_method_hash_list, method);
+ }
+ else
+ {
+ /* Check types; if different, add to a list. */
+ if (!comp_proto_with_proto (method, hsh->key))
+ hash_add_attr (hsh, method);
+ }
+ return method;
+}
+
+tree
+add_instance_method (class, method)
+ tree class;
+ tree method;
+{
+ tree mth;
+ hash hsh;
+
+ /* We will have allocated the method parameter declarations on the
+ maybepermanent_obstack. Need to make sure they stick around! */
+ preserve_data ();
+
+ if (!(mth = lookup_method (CLASS_NST_METHODS (class), method)))
+ {
+ /* Put method on list in reverse order. */
+ TREE_CHAIN (method) = CLASS_NST_METHODS (class);
+ CLASS_NST_METHODS (class) = method;
+ }
+ else
+ {
+ if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE)
+ error ("duplicate definition of instance method `%s'.",
+ IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
+ else
+ {
+ /* Check types; if different, complain. */
+ if (!comp_proto_with_proto (method, mth))
+ error ("duplicate declaration of instance method `%s'.",
+ IDENTIFIER_POINTER (METHOD_SEL_NAME (mth)));
+ }
+ }
+
+ if (!(hsh = hash_lookup (nst_method_hash_list, METHOD_SEL_NAME (method))))
+ {
+ /* Install on a global chain. */
+ hash_enter (nst_method_hash_list, method);
+ }
+ else
+ {
+ /* Check types; if different, add to a list. */
+ if (!comp_proto_with_proto (method, hsh->key))
+ hash_add_attr (hsh, method);
+ }
+ return method;
+}
+
+static tree
+add_class (class)
+ tree class;
+{
+ /* Put interfaces on list in reverse order. */
+ TREE_CHAIN (class) = interface_chain;
+ interface_chain = class;
+ return interface_chain;
+}
+
+static void
+add_category (class, category)
+ tree class;
+ tree category;
+{
+ /* Put categories on list in reverse order. */
+ tree cat = CLASS_CATEGORY_LIST (class);
+
+ while (cat)
+ {
+ if (CLASS_SUPER_NAME (cat) == CLASS_SUPER_NAME (category))
+ warning ("duplicate interface declaration for category `%s(%s)'",
+ IDENTIFIER_POINTER (CLASS_NAME (class)),
+ IDENTIFIER_POINTER (CLASS_SUPER_NAME (category)));
+ cat = CLASS_CATEGORY_LIST (cat);
+ }
+
+ CLASS_CATEGORY_LIST (category) = CLASS_CATEGORY_LIST (class);
+ CLASS_CATEGORY_LIST (class) = category;
+}
+
+/* Called after parsing each instance variable declaration. Necessary to
+ preserve typedefs and implement public/private...
+
+ PUBLIC is 1 for public, 0 for protected, and 2 for private. */
+
+tree
+add_instance_variable (class, public, declarator, declspecs, width)
+ tree class;
+ int public;
+ tree declarator;
+ tree declspecs;
+ tree width;
+{
+ tree field_decl, raw_decl;
+
+ raw_decl = build_tree_list (declspecs, declarator);
+
+ if (CLASS_RAW_IVARS (class))
+ chainon (CLASS_RAW_IVARS (class), raw_decl);
+ else
+ CLASS_RAW_IVARS (class) = raw_decl;
+
+ field_decl = grokfield (input_filename, lineno,
+ declarator, declspecs, width);
+
+ /* Overload the public attribute, it is not used for FIELD_DECLs. */
+ switch (public)
+ {
+ case 0:
+ TREE_PUBLIC (field_decl) = 0;
+ TREE_PRIVATE (field_decl) = 0;
+ TREE_PROTECTED (field_decl) = 1;
+ break;
+
+ case 1:
+ TREE_PUBLIC (field_decl) = 1;
+ TREE_PRIVATE (field_decl) = 0;
+ TREE_PROTECTED (field_decl) = 0;
+ break;
+
+ case 2:
+ TREE_PUBLIC (field_decl) = 0;
+ TREE_PRIVATE (field_decl) = 1;
+ TREE_PROTECTED (field_decl) = 0;
+ break;
+
+ }
+
+ if (CLASS_IVARS (class))
+ chainon (CLASS_IVARS (class), field_decl);
+ else
+ CLASS_IVARS (class) = field_decl;
+
+ return class;
+}
+
+tree
+is_ivar (decl_chain, ident)
+ tree decl_chain;
+ tree ident;
+{
+ for ( ; decl_chain; decl_chain = TREE_CHAIN (decl_chain))
+ if (DECL_NAME (decl_chain) == ident)
+ return decl_chain;
+ return NULL_TREE;
+}
+
+/* True if the ivar is private and we are not in its implementation. */
+
+int
+is_private (decl)
+ tree decl;
+{
+ if (TREE_PRIVATE (decl)
+ && ! is_ivar (CLASS_IVARS (implementation_template), DECL_NAME (decl)))
+ {
+ error ("instance variable `%s' is declared private",
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/* We have an instance variable reference;, check to see if it is public. */
+
+int
+is_public (expr, identifier)
+ tree expr;
+ tree identifier;
+{
+ tree basetype = TREE_TYPE (expr);
+ enum tree_code code = TREE_CODE (basetype);
+ tree decl;
+
+ if (code == RECORD_TYPE)
+ {
+ if (TREE_STATIC_TEMPLATE (basetype))
+ {
+ if (!lookup_interface (TYPE_NAME (basetype)))
+ {
+ error ("Cannot find interface declaration for `%s'",
+ IDENTIFIER_POINTER (TYPE_NAME (basetype)));
+ return 0;
+ }
+
+ if ((decl = is_ivar (TYPE_FIELDS (basetype), identifier)))
+ {
+ if (TREE_PUBLIC (decl))
+ return 1;
+
+ /* Important difference between the Stepstone translator:
+ all instance variables should be public within the context
+ of the implementation. */
+ if (implementation_context
+ && (((TREE_CODE (implementation_context)
+ == CLASS_IMPLEMENTATION_TYPE)
+ || (TREE_CODE (implementation_context)
+ == CATEGORY_IMPLEMENTATION_TYPE))
+ && (CLASS_NAME (implementation_context)
+ == TYPE_NAME (basetype))))
+ return ! is_private (decl);
+
+ error ("instance variable `%s' is declared %s",
+ IDENTIFIER_POINTER (identifier),
+ TREE_PRIVATE (decl) ? "private" : "protected");
+ return 0;
+ }
+ }
+
+ else if (implementation_context && (basetype == objc_object_reference))
+ {
+ TREE_TYPE (expr) = uprivate_record;
+ warning ("static access to object of type `id'");
+ }
+ }
+
+ return 1;
+}
+
+/* Implement @defs (<classname>) within struct bodies. */
+
+tree
+get_class_ivars (interface)
+ tree interface;
+{
+ if (!doing_objc_thang)
+ objc_fatal ();
+
+ return build_ivar_chain (interface, 1);
+}
+
+/* Make sure all entries in CHAIN are also in LIST. */
+
+static int
+check_methods (chain, list, mtype)
+ tree chain;
+ tree list;
+ int mtype;
+{
+ int first = 1;
+
+ while (chain)
+ {
+ if (!lookup_method (list, chain))
+ {
+ if (first)
+ {
+ if (TREE_CODE (implementation_context)
+ == CLASS_IMPLEMENTATION_TYPE)
+ warning ("incomplete implementation of class `%s'",
+ IDENTIFIER_POINTER (CLASS_NAME (implementation_context)));
+ else if (TREE_CODE (implementation_context)
+ == CATEGORY_IMPLEMENTATION_TYPE)
+ warning ("incomplete implementation of category `%s'",
+ IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context)));
+ first = 0;
+ }
+
+ warning ("method definition for `%c%s' not found",
+ mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain)));
+ }
+
+ chain = TREE_CHAIN (chain);
+ }
+
+ return first;
+}
+
+static int
+conforms_to_protocol (class, protocol)
+ tree class;
+ tree protocol;
+{
+ while (protocol)
+ {
+ tree p = CLASS_PROTOCOL_LIST (class);
+
+ while (p && TREE_VALUE (p) != TREE_VALUE (protocol))
+ p = TREE_CHAIN (p);
+
+ if (!p)
+ {
+ tree super = (CLASS_SUPER_NAME (class)
+ ? lookup_interface (CLASS_SUPER_NAME (class))
+ : NULL_TREE);
+ int tmp = super ? conforms_to_protocol (super, protocol) : 0;
+ if (!tmp)
+ return 0;
+ }
+
+ protocol = TREE_CHAIN (protocol);
+ }
+
+ return 1;
+}
+
+/* Make sure all methods in CHAIN are accessible as MTYPE methods in
+ CONTEXT. This is one of two mechanisms to check protocol integrity. */
+
+static int
+check_methods_accessible (chain, context, mtype)
+ tree chain;
+ tree context;
+ int mtype;
+{
+ int first = 1;
+ tree list;
+ tree base_context = context;
+
+ while (chain)
+ {
+ context = base_context;
+ while (context)
+ {
+ if (mtype == '+')
+ list = CLASS_CLS_METHODS (context);
+ else
+ list = CLASS_NST_METHODS (context);
+
+ if (lookup_method (list, chain))
+ break;
+
+ else if (TREE_CODE (context) == CLASS_IMPLEMENTATION_TYPE
+ || TREE_CODE (context) == CLASS_INTERFACE_TYPE)
+ context = (CLASS_SUPER_NAME (context)
+ ? lookup_interface (CLASS_SUPER_NAME (context))
+ : NULL_TREE);
+
+ else if (TREE_CODE (context) == CATEGORY_IMPLEMENTATION_TYPE
+ || TREE_CODE (context) == CATEGORY_INTERFACE_TYPE)
+ context = (CLASS_NAME (context)
+ ? lookup_interface (CLASS_NAME (context))
+ : NULL_TREE);
+ else
+ abort ();
+ }
+
+ if (context == NULL_TREE)
+ {
+ if (first)
+ {
+ if (TREE_CODE (implementation_context)
+ == CLASS_IMPLEMENTATION_TYPE)
+ warning ("incomplete implementation of class `%s'",
+ IDENTIFIER_POINTER
+ (CLASS_NAME (implementation_context)));
+ else if (TREE_CODE (implementation_context)
+ == CATEGORY_IMPLEMENTATION_TYPE)
+ warning ("incomplete implementation of category `%s'",
+ IDENTIFIER_POINTER
+ (CLASS_SUPER_NAME (implementation_context)));
+ first = 0;
+ }
+ warning ("method definition for `%c%s' not found",
+ mtype, IDENTIFIER_POINTER (METHOD_SEL_NAME (chain)));
+ }
+
+ chain = TREE_CHAIN (chain); /* next method... */
+ }
+ return first;
+}
+
+static void
+check_protocols (proto_list, type, name)
+ tree proto_list;
+ char *type;
+ char *name;
+{
+ for ( ; proto_list; proto_list = TREE_CHAIN (proto_list))
+ {
+ tree p = TREE_VALUE (proto_list);
+
+ if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
+ {
+ int f1, f2;
+
+ /* Ensure that all protocols have bodies. */
+ if (flag_warn_protocol) {
+ f1 = check_methods (PROTOCOL_CLS_METHODS (p),
+ CLASS_CLS_METHODS (implementation_context),
+ '+');
+ f2 = check_methods (PROTOCOL_NST_METHODS (p),
+ CLASS_NST_METHODS (implementation_context),
+ '-');
+ } else {
+ f1 = check_methods_accessible (PROTOCOL_CLS_METHODS (p),
+ implementation_context,
+ '+');
+ f2 = check_methods_accessible (PROTOCOL_NST_METHODS (p),
+ implementation_context,
+ '-');
+ }
+
+ if (!f1 || !f2)
+ warning ("%s `%s' does not fully implement the `%s' protocol",
+ type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+
+ }
+ else
+ {
+ ; /* An identifier if we could not find a protocol. */
+ }
+
+ /* Check protocols recursively. */
+ if (PROTOCOL_LIST (p))
+ {
+ tree super_class
+ = lookup_interface (CLASS_SUPER_NAME (implementation_template));
+ if (! conforms_to_protocol (super_class, PROTOCOL_LIST (p)))
+ check_protocols (PROTOCOL_LIST (p), type, name);
+ }
+ }
+}
+
+/* Make sure that the class CLASS_NAME is defined
+ CODE says which kind of thing CLASS_NAME ought to be.
+ It can be CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
+ CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE.
+
+ If CODE is CLASS_INTERFACE_TYPE, we also do a push_obstacks_nochange
+ whose matching pop is in continue_class. */
+
+tree
+start_class (code, class_name, super_name, protocol_list)
+ enum tree_code code;
+ tree class_name;
+ tree super_name;
+ tree protocol_list;
+{
+ tree class, decl;
+
+ if (code == CLASS_INTERFACE_TYPE)
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ }
+
+ if (!doing_objc_thang)
+ objc_fatal ();
+
+ class = make_node (code);
+ TYPE_BINFO (class) = make_tree_vec (5);
+
+ CLASS_NAME (class) = class_name;
+ CLASS_SUPER_NAME (class) = super_name;
+ CLASS_CLS_METHODS (class) = NULL_TREE;
+
+ if (! is_class_name (class_name) && (decl = lookup_name (class_name)))
+ {
+ error ("`%s' redeclared as different kind of symbol",
+ IDENTIFIER_POINTER (class_name));
+ error_with_decl (decl, "previous declaration of `%s'");
+ }
+
+ if (code == CLASS_IMPLEMENTATION_TYPE)
+ {
+ {
+ static tree implemented_classes = 0;
+ tree chain = implemented_classes;
+ for (chain = implemented_classes; chain; chain = TREE_CHAIN (chain))
+ if (TREE_VALUE (chain) == class_name)
+ {
+ error ("reimplementation of class `%s'",
+ IDENTIFIER_POINTER (class_name));
+ return error_mark_node;
+ }
+ implemented_classes = perm_tree_cons (NULL_TREE, class_name,
+ implemented_classes);
+ }
+
+ /* Pre-build the following entities - for speed/convenience. */
+ if (!self_id)
+ self_id = get_identifier ("self");
+ if (!ucmd_id)
+ ucmd_id = get_identifier ("_cmd");
+ if (!unused_list)
+ unused_list
+ = build_tree_list (get_identifier ("__unused__"), NULL_TREE);
+ if (!objc_super_template)
+ objc_super_template = build_super_template ();
+
+ /* Reset for multiple classes per file. */
+ method_slot = 0;
+
+ implementation_context = class;
+
+ /* Lookup the interface for this implementation. */
+
+ if (!(implementation_template = lookup_interface (class_name)))
+ {
+ warning ("Cannot find interface declaration for `%s'",
+ IDENTIFIER_POINTER (class_name));
+ add_class (implementation_template = implementation_context);
+ }
+
+ /* If a super class has been specified in the implementation,
+ insure it conforms to the one specified in the interface. */
+
+ if (super_name
+ && (super_name != CLASS_SUPER_NAME (implementation_template)))
+ {
+ tree previous_name = CLASS_SUPER_NAME (implementation_template);
+ char *name = previous_name ? IDENTIFIER_POINTER (previous_name) : "";
+ error ("conflicting super class name `%s'",
+ IDENTIFIER_POINTER (super_name));
+ error ("previous declaration of `%s'", name);
+ }
+
+ else if (! super_name)
+ {
+ CLASS_SUPER_NAME (implementation_context)
+ = CLASS_SUPER_NAME (implementation_template);
+ }
+ }
+
+ else if (code == CLASS_INTERFACE_TYPE)
+ {
+ if (lookup_interface (class_name))
+ warning ("duplicate interface declaration for class `%s'",
+ IDENTIFIER_POINTER (class_name));
+ else
+ add_class (class);
+
+ if (protocol_list)
+ CLASS_PROTOCOL_LIST (class)
+ = lookup_and_install_protocols (protocol_list);
+ }
+
+ else if (code == CATEGORY_INTERFACE_TYPE)
+ {
+ tree class_category_is_assoc_with;
+
+ /* For a category, class_name is really the name of the class that
+ the following set of methods will be associated with. We must
+ find the interface so that can derive the objects template. */
+
+ if (!(class_category_is_assoc_with = lookup_interface (class_name)))
+ {
+ error ("Cannot find interface declaration for `%s'",
+ IDENTIFIER_POINTER (class_name));
+ exit (FATAL_EXIT_CODE);
+ }
+ else
+ add_category (class_category_is_assoc_with, class);
+
+ if (protocol_list)
+ CLASS_PROTOCOL_LIST (class)
+ = lookup_and_install_protocols (protocol_list);
+ }
+
+ else if (code == CATEGORY_IMPLEMENTATION_TYPE)
+ {
+ /* Pre-build the following entities for speed/convenience. */
+ if (!self_id)
+ self_id = get_identifier ("self");
+ if (!ucmd_id)
+ ucmd_id = get_identifier ("_cmd");
+ if (!unused_list)
+ unused_list
+ = build_tree_list (get_identifier ("__unused__"), NULL_TREE);
+ if (!objc_super_template)
+ objc_super_template = build_super_template ();
+
+ /* Reset for multiple classes per file. */
+ method_slot = 0;
+
+ implementation_context = class;
+
+ /* For a category, class_name is really the name of the class that
+ the following set of methods will be associated with. We must
+ find the interface so that can derive the objects template. */
+
+ if (!(implementation_template = lookup_interface (class_name)))
+ {
+ error ("Cannot find interface declaration for `%s'",
+ IDENTIFIER_POINTER (class_name));
+ exit (FATAL_EXIT_CODE);
+ }
+ }
+ return class;
+}
+
+tree
+continue_class (class)
+ tree class;
+{
+ if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE
+ || TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
+ {
+ struct imp_entry *imp_entry;
+ tree ivar_context;
+
+ /* Check consistency of the instance variables. */
+
+ if (CLASS_IVARS (class))
+ check_ivars (implementation_template, class);
+
+ /* code generation */
+
+ ivar_context = build_private_template (implementation_template);
+
+ if (!objc_class_template)
+ build_class_template ();
+
+ if (!(imp_entry
+ = (struct imp_entry *) xmalloc (sizeof (struct imp_entry))))
+ perror ("unable to allocate in objc-tree.c");
+
+ imp_entry->next = imp_list;
+ imp_entry->imp_context = class;
+ imp_entry->imp_template = implementation_template;
+
+ synth_forward_declarations ();
+ imp_entry->class_decl = UOBJC_CLASS_decl;
+ imp_entry->meta_decl = UOBJC_METACLASS_decl;
+
+ /* Append to front and increment count. */
+ imp_list = imp_entry;
+ if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE)
+ imp_count++;
+ else
+ cat_count++;
+
+ return ivar_context;
+ }
+
+ else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE)
+ {
+ tree record = xref_tag (RECORD_TYPE, CLASS_NAME (class));
+
+ if (!TYPE_FIELDS (record))
+ {
+ finish_struct (record, build_ivar_chain (class, 0), NULL_TREE);
+ CLASS_STATIC_TEMPLATE (class) = record;
+
+ /* Mark this record as a class template for static typing. */
+ TREE_STATIC_TEMPLATE (record) = 1;
+ }
+
+ return NULL_TREE;
+ }
+
+ else
+ return error_mark_node;
+}
+
+/* This is called once we see the "@end" in an interface/implementation. */
+
+void
+finish_class (class)
+ tree class;
+{
+ if (TREE_CODE (class) == CLASS_IMPLEMENTATION_TYPE)
+ {
+ /* All code generation is done in finish_objc. */
+
+ if (implementation_template != implementation_context)
+ {
+ /* Ensure that all method listed in the interface contain bodies. */
+ check_methods (CLASS_CLS_METHODS (implementation_template),
+ CLASS_CLS_METHODS (implementation_context), '+');
+ check_methods (CLASS_NST_METHODS (implementation_template),
+ CLASS_NST_METHODS (implementation_context), '-');
+
+ if (CLASS_PROTOCOL_LIST (implementation_template))
+ check_protocols (CLASS_PROTOCOL_LIST (implementation_template),
+ "class",
+ IDENTIFIER_POINTER (CLASS_NAME (implementation_context)));
+ }
+ }
+
+ else if (TREE_CODE (class) == CATEGORY_IMPLEMENTATION_TYPE)
+ {
+ tree category = CLASS_CATEGORY_LIST (implementation_template);
+
+ /* Find the category interface from the class it is associated with. */
+ while (category)
+ {
+ if (CLASS_SUPER_NAME (class) == CLASS_SUPER_NAME (category))
+ break;
+ category = CLASS_CATEGORY_LIST (category);
+ }
+
+ if (category)
+ {
+ /* Ensure all method listed in the interface contain bodies. */
+ check_methods (CLASS_CLS_METHODS (category),
+ CLASS_CLS_METHODS (implementation_context), '+');
+ check_methods (CLASS_NST_METHODS (category),
+ CLASS_NST_METHODS (implementation_context), '-');
+
+ if (CLASS_PROTOCOL_LIST (category))
+ check_protocols (CLASS_PROTOCOL_LIST (category),
+ "category",
+ IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context)));
+ }
+ }
+
+ else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE)
+ {
+ tree decl_specs;
+ char *class_name = IDENTIFIER_POINTER (CLASS_NAME (class));
+ char *string = (char *) alloca (strlen (class_name) + 3);
+
+ /* extern struct objc_object *_<my_name>; */
+
+ sprintf (string, "_%s", class_name);
+
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_EXTERN]);
+ decl_specs = tree_cons (NULL_TREE, objc_object_reference, decl_specs);
+ define_decl (build1 (INDIRECT_REF, NULL_TREE, get_identifier (string)),
+ decl_specs);
+ }
+}
+
+static tree
+add_protocol (protocol)
+ tree protocol;
+{
+ /* Put protocol on list in reverse order. */
+ TREE_CHAIN (protocol) = protocol_chain;
+ protocol_chain = protocol;
+ return protocol_chain;
+}
+
+static tree
+lookup_protocol (ident)
+ tree ident;
+{
+ tree chain;
+
+ for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ if (ident == PROTOCOL_NAME (chain))
+ return chain;
+ }
+
+ return NULL_TREE;
+}
+
+tree
+start_protocol (code, name, list)
+ enum tree_code code;
+ tree name;
+ tree list;
+{
+ tree protocol;
+
+ if (!doing_objc_thang)
+ objc_fatal ();
+
+ /* This is as good a place as any. Need to invoke push_tag_toplevel. */
+ if (!objc_protocol_template)
+ objc_protocol_template = build_protocol_template ();
+
+ protocol = make_node (code);
+ TYPE_BINFO (protocol) = make_tree_vec (2);
+
+ PROTOCOL_NAME (protocol) = name;
+ PROTOCOL_LIST (protocol) = list;
+
+ lookup_and_install_protocols (list);
+
+ if (lookup_protocol (name))
+ warning ("duplicate declaration for protocol `%s'",
+ IDENTIFIER_POINTER (name));
+ else
+ add_protocol (protocol);
+
+ PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
+
+ return protocol;
+}
+
+void
+finish_protocol (protocol)
+ tree protocol ATTRIBUTE_UNUSED;
+{
+}
+
+
+/* "Encode" a data type into a string, which grows in util_obstack.
+ ??? What is the FORMAT? Someone please document this! */
+
+static void
+encode_type_qualifiers (declspecs)
+ tree declspecs;
+{
+ tree spec;
+
+ for (spec = declspecs; spec; spec = TREE_CHAIN (spec))
+ {
+ if (ridpointers[(int) RID_CONST] == TREE_VALUE (spec))
+ obstack_1grow (&util_obstack, 'r');
+ else if (ridpointers[(int) RID_IN] == TREE_VALUE (spec))
+ obstack_1grow (&util_obstack, 'n');
+ else if (ridpointers[(int) RID_INOUT] == TREE_VALUE (spec))
+ obstack_1grow (&util_obstack, 'N');
+ else if (ridpointers[(int) RID_OUT] == TREE_VALUE (spec))
+ obstack_1grow (&util_obstack, 'o');
+ else if (ridpointers[(int) RID_BYCOPY] == TREE_VALUE (spec))
+ obstack_1grow (&util_obstack, 'O');
+ else if (ridpointers[(int) RID_ONEWAY] == TREE_VALUE (spec))
+ obstack_1grow (&util_obstack, 'V');
+ }
+}
+
+/* Encode a pointer type. */
+
+static void
+encode_pointer (type, curtype, format)
+ tree type;
+ int curtype;
+ int format;
+{
+ tree pointer_to = TREE_TYPE (type);
+
+ if (TREE_CODE (pointer_to) == RECORD_TYPE)
+ {
+ if (TYPE_NAME (pointer_to)
+ && TREE_CODE (TYPE_NAME (pointer_to)) == IDENTIFIER_NODE)
+ {
+ char *name = IDENTIFIER_POINTER (TYPE_NAME (pointer_to));
+
+ if (strcmp (name, TAG_OBJECT) == 0) /* '@' */
+ {
+ obstack_1grow (&util_obstack, '@');
+ return;
+ }
+ else if (TREE_STATIC_TEMPLATE (pointer_to))
+ {
+ if (generating_instance_variables)
+ {
+ obstack_1grow (&util_obstack, '@');
+ obstack_1grow (&util_obstack, '"');
+ obstack_grow (&util_obstack, name, strlen (name));
+ obstack_1grow (&util_obstack, '"');
+ return;
+ }
+ else
+ {
+ obstack_1grow (&util_obstack, '@');
+ return;
+ }
+ }
+ else if (strcmp (name, TAG_CLASS) == 0) /* '#' */
+ {
+ obstack_1grow (&util_obstack, '#');
+ return;
+ }
+#ifndef OBJC_INT_SELECTORS
+ else if (strcmp (name, TAG_SELECTOR) == 0) /* ':' */
+ {
+ obstack_1grow (&util_obstack, ':');
+ return;
+ }
+#endif /* OBJC_INT_SELECTORS */
+ }
+ }
+ else if (TREE_CODE (pointer_to) == INTEGER_TYPE
+ && TYPE_MODE (pointer_to) == QImode)
+ {
+ obstack_1grow (&util_obstack, '*');
+ return;
+ }
+
+ /* We have a type that does not get special treatment. */
+
+ /* NeXT extension */
+ obstack_1grow (&util_obstack, '^');
+ encode_type (pointer_to, curtype, format);
+}
+
+static void
+encode_array (type, curtype, format)
+ tree type;
+ int curtype;
+ int format;
+{
+ tree an_int_cst = TYPE_SIZE (type);
+ tree array_of = TREE_TYPE (type);
+ char buffer[40];
+
+ /* An incomplete array is treated like a pointer. */
+ if (an_int_cst == NULL)
+ {
+ encode_pointer (type, curtype, format);
+ return;
+ }
+
+ sprintf (buffer, "[%ld",
+ (long) (TREE_INT_CST_LOW (an_int_cst)
+ / TREE_INT_CST_LOW (TYPE_SIZE (array_of))));
+
+ obstack_grow (&util_obstack, buffer, strlen (buffer));
+ encode_type (array_of, curtype, format);
+ obstack_1grow (&util_obstack, ']');
+ return;
+}
+
+static void
+encode_aggregate_within (type, curtype, format, left, right)
+ tree type;
+ int curtype;
+ int format;
+ int left;
+ int right;
+{
+ if (obstack_object_size (&util_obstack) > 0
+ && *(obstack_next_free (&util_obstack) - 1) == '^')
+ {
+ tree name = TYPE_NAME (type);
+
+ /* we have a reference; this is a NeXT extension. */
+
+ if (obstack_object_size (&util_obstack) - curtype == 1
+ && format == OBJC_ENCODE_INLINE_DEFS)
+ {
+ /* Output format of struct for first level only. */
+ tree fields = TYPE_FIELDS (type);
+
+ if (name && TREE_CODE (name) == IDENTIFIER_NODE)
+ {
+ obstack_1grow (&util_obstack, left);
+ obstack_grow (&util_obstack,
+ IDENTIFIER_POINTER (name),
+ strlen (IDENTIFIER_POINTER (name)));
+ obstack_1grow (&util_obstack, '=');
+ }
+ else
+ {
+ obstack_1grow (&util_obstack, left);
+ obstack_grow (&util_obstack, "?=", 2);
+ }
+
+ for ( ; fields; fields = TREE_CHAIN (fields))
+ encode_field_decl (fields, curtype, format);
+
+ obstack_1grow (&util_obstack, right);
+ }
+
+ else if (name && TREE_CODE (name) == IDENTIFIER_NODE)
+ {
+ obstack_1grow (&util_obstack, left);
+ obstack_grow (&util_obstack,
+ IDENTIFIER_POINTER (name),
+ strlen (IDENTIFIER_POINTER (name)));
+ obstack_1grow (&util_obstack, right);
+ }
+
+ else
+ {
+ /* We have an untagged structure or a typedef. */
+ obstack_1grow (&util_obstack, left);
+ obstack_1grow (&util_obstack, '?');
+ obstack_1grow (&util_obstack, right);
+ }
+ }
+
+ else
+ {
+ tree name = TYPE_NAME (type);
+ tree fields = TYPE_FIELDS (type);
+
+ if (format == OBJC_ENCODE_INLINE_DEFS
+ || generating_instance_variables)
+ {
+ obstack_1grow (&util_obstack, left);
+ if (name && TREE_CODE (name) == IDENTIFIER_NODE)
+ obstack_grow (&util_obstack,
+ IDENTIFIER_POINTER (name),
+ strlen (IDENTIFIER_POINTER (name)));
+ else
+ obstack_1grow (&util_obstack, '?');
+
+ obstack_1grow (&util_obstack, '=');
+
+ for (; fields; fields = TREE_CHAIN (fields))
+ {
+ if (generating_instance_variables)
+ {
+ tree fname = DECL_NAME (fields);
+
+ obstack_1grow (&util_obstack, '"');
+ if (fname && TREE_CODE (fname) == IDENTIFIER_NODE)
+ {
+ obstack_grow (&util_obstack,
+ IDENTIFIER_POINTER (fname),
+ strlen (IDENTIFIER_POINTER (fname)));
+ }
+
+ obstack_1grow (&util_obstack, '"');
+ }
+
+ encode_field_decl (fields, curtype, format);
+ }
+
+ obstack_1grow (&util_obstack, right);
+ }
+
+ else
+ {
+ obstack_1grow (&util_obstack, left);
+ if (name && TREE_CODE (name) == IDENTIFIER_NODE)
+ obstack_grow (&util_obstack,
+ IDENTIFIER_POINTER (name),
+ strlen (IDENTIFIER_POINTER (name)));
+ else
+ /* We have an untagged structure or a typedef. */
+ obstack_1grow (&util_obstack, '?');
+
+ obstack_1grow (&util_obstack, right);
+ }
+ }
+}
+
+static void
+encode_aggregate (type, curtype, format)
+ tree type;
+ int curtype;
+ int format;
+{
+ enum tree_code code = TREE_CODE (type);
+
+ switch (code)
+ {
+ case RECORD_TYPE:
+ {
+ encode_aggregate_within(type, curtype, format, '{', '}');
+ break;
+ }
+ case UNION_TYPE:
+ {
+ encode_aggregate_within(type, curtype, format, '(', ')');
+ break;
+ }
+
+ case ENUMERAL_TYPE:
+ obstack_1grow (&util_obstack, 'i');
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Support bitfields. The current version of Objective-C does not support
+ them. The string will consist of one or more "b:n"'s where n is an
+ integer describing the width of the bitfield. Currently, classes in
+ the kit implement a method "-(char *)describeBitfieldStruct:" that
+ simulates this. If they do not implement this method, the archiver
+ assumes the bitfield is 16 bits wide (padded if necessary) and packed
+ according to the GNU compiler. After looking at the "kit", it appears
+ that all classes currently rely on this default behavior, rather than
+ hand generating this string (which is tedious). */
+
+static void
+encode_bitfield (width, format)
+ int width;
+ int format;
+{
+ char buffer[40];
+ sprintf (buffer, "b%d", width);
+ obstack_grow (&util_obstack, buffer, strlen (buffer));
+}
+
+/* FORMAT will be OBJC_ENCODE_INLINE_DEFS or OBJC_ENCODE_DONT_INLINE_DEFS. */
+
+static void
+encode_type (type, curtype, format)
+ tree type;
+ int curtype;
+ int format;
+{
+ enum tree_code code = TREE_CODE (type);
+
+ if (code == INTEGER_TYPE)
+ {
+ if (TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) == 0
+ && TREE_INT_CST_HIGH (TYPE_MIN_VALUE (type)) == 0)
+ {
+ /* Unsigned integer types. */
+
+ if (TYPE_MODE (type) == QImode)
+ obstack_1grow (&util_obstack, 'C');
+ else if (TYPE_MODE (type) == HImode)
+ obstack_1grow (&util_obstack, 'S');
+ else if (TYPE_MODE (type) == SImode)
+ {
+ if (type == long_unsigned_type_node)
+ obstack_1grow (&util_obstack, 'L');
+ else
+ obstack_1grow (&util_obstack, 'I');
+ }
+ else if (TYPE_MODE (type) == DImode)
+ obstack_1grow (&util_obstack, 'Q');
+ }
+
+ else
+ /* Signed integer types. */
+ {
+ if (TYPE_MODE (type) == QImode)
+ obstack_1grow (&util_obstack, 'c');
+ else if (TYPE_MODE (type) == HImode)
+ obstack_1grow (&util_obstack, 's');
+ else if (TYPE_MODE (type) == SImode)
+ {
+ if (type == long_integer_type_node)
+ obstack_1grow (&util_obstack, 'l');
+ else
+ obstack_1grow (&util_obstack, 'i');
+ }
+
+ else if (TYPE_MODE (type) == DImode)
+ obstack_1grow (&util_obstack, 'q');
+ }
+ }
+
+ else if (code == REAL_TYPE)
+ {
+ /* Floating point types. */
+
+ if (TYPE_MODE (type) == SFmode)
+ obstack_1grow (&util_obstack, 'f');
+ else if (TYPE_MODE (type) == DFmode
+ || TYPE_MODE (type) == TFmode)
+ obstack_1grow (&util_obstack, 'd');
+ }
+
+ else if (code == VOID_TYPE)
+ obstack_1grow (&util_obstack, 'v');
+
+ else if (code == ARRAY_TYPE)
+ encode_array (type, curtype, format);
+
+ else if (code == POINTER_TYPE)
+ encode_pointer (type, curtype, format);
+
+ else if (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE)
+ encode_aggregate (type, curtype, format);
+
+ else if (code == FUNCTION_TYPE) /* '?' */
+ obstack_1grow (&util_obstack, '?');
+}
+
+static void
+encode_field_decl (field_decl, curtype, format)
+ tree field_decl;
+ int curtype;
+ int format;
+{
+ tree type;
+
+ /* If this field is obviously a bitfield, or is a bitfield that has been
+ clobbered to look like a ordinary integer mode, go ahead and generate
+ the bitfield typing information. */
+ type = TREE_TYPE (field_decl);
+ if (DECL_BIT_FIELD (field_decl))
+ encode_bitfield (DECL_FIELD_SIZE (field_decl), format);
+ else if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
+ && DECL_FIELD_SIZE (field_decl)
+ && TYPE_MODE (type) > DECL_MODE (field_decl))
+ encode_bitfield (DECL_FIELD_SIZE (field_decl), format);
+ else
+ encode_type (TREE_TYPE (field_decl), curtype, format);
+}
+
+static tree
+expr_last (complex_expr)
+ tree complex_expr;
+{
+ tree next;
+
+ if (complex_expr)
+ while ((next = TREE_OPERAND (complex_expr, 0)))
+ complex_expr = next;
+
+ return complex_expr;
+}
+
+/* The selector of the current method,
+ or NULL if we aren't compiling a method. */
+
+tree
+maybe_objc_method_name (decl)
+ tree decl;
+{
+ if (method_context)
+ return METHOD_SEL_NAME (method_context);
+ else
+ return 0;
+}
+
+/* Transform a method definition into a function definition as follows:
+ - synthesize the first two arguments, "self" and "_cmd". */
+
+void
+start_method_def (method)
+ tree method;
+{
+ tree decl_specs;
+
+ /* Required to implement _msgSuper. */
+ method_context = method;
+ UOBJC_SUPER_decl = NULL_TREE;
+
+ /* Must be called BEFORE start_function. */
+ pushlevel (0);
+
+ /* Generate prototype declarations for arguments..."new-style". */
+
+ if (TREE_CODE (method_context) == INSTANCE_METHOD_DECL)
+ decl_specs = build_tree_list (NULL_TREE, uprivate_record);
+ else
+ /* Really a `struct objc_class *'. However, we allow people to
+ assign to self, which changes its type midstream. */
+ decl_specs = build_tree_list (NULL_TREE, objc_object_reference);
+
+ push_parm_decl (build_tree_list
+ (build_tree_list (decl_specs,
+ build1 (INDIRECT_REF, NULL_TREE, self_id)),
+ build_tree_list (unused_list, NULL_TREE)));
+
+#ifdef OBJC_INT_SELECTORS
+ decl_specs = build_tree_list (NULL_TREE, ridpointers[(int) RID_UNSIGNED]);
+ decl_specs = tree_cons (NULL_TREE, ridpointers[(int) RID_INT], decl_specs);
+ push_parm_decl (build_tree_list (build_tree_list (decl_specs, ucmd_id),
+ build_tree_list (unused_list, NULL_TREE)));
+#else /* not OBJC_INT_SELECTORS */
+ decl_specs = build_tree_list (NULL_TREE,
+ xref_tag (RECORD_TYPE,
+ get_identifier (TAG_SELECTOR)));
+ push_parm_decl (build_tree_list
+ (build_tree_list (decl_specs,
+ build1 (INDIRECT_REF, NULL_TREE, ucmd_id)),
+ build_tree_list (unused_list, NULL_TREE)));
+#endif /* not OBJC_INT_SELECTORS */
+
+ /* Generate argument declarations if a keyword_decl. */
+ if (METHOD_SEL_ARGS (method))
+ {
+ tree arglist = METHOD_SEL_ARGS (method);
+ do
+ {
+ tree arg_spec = TREE_PURPOSE (TREE_TYPE (arglist));
+ tree arg_decl = TREE_VALUE (TREE_TYPE (arglist));
+
+ if (arg_decl)
+ {
+ tree last_expr = expr_last (arg_decl);
+
+ /* Unite the abstract decl with its name. */
+ TREE_OPERAND (last_expr, 0) = KEYWORD_ARG_NAME (arglist);
+ push_parm_decl (build_tree_list
+ (build_tree_list (arg_spec, arg_decl),
+ build_tree_list (NULL_TREE, NULL_TREE)));
+
+ /* Unhook: restore the abstract declarator. */
+ TREE_OPERAND (last_expr, 0) = NULL_TREE;
+ }
+
+ else
+ push_parm_decl (build_tree_list
+ (build_tree_list (arg_spec,
+ KEYWORD_ARG_NAME (arglist)),
+ build_tree_list (NULL_TREE, NULL_TREE)));
+
+ arglist = TREE_CHAIN (arglist);
+ }
+ while (arglist);
+ }
+
+ if (METHOD_ADD_ARGS (method) > (tree)1)
+ {
+ /* We have a variable length selector - in "prototype" format. */
+ tree akey = TREE_PURPOSE (METHOD_ADD_ARGS (method));
+ while (akey)
+ {
+ /* This must be done prior to calling pushdecl. pushdecl is
+ going to change our chain on us. */
+ tree nextkey = TREE_CHAIN (akey);
+ pushdecl (akey);
+ akey = nextkey;
+ }
+ }
+}
+
+static void
+warn_with_method (message, mtype, method)
+ char *message;
+ int mtype;
+ tree method;
+{
+ if (count_error (1) == 0)
+ return;
+
+ report_error_function (DECL_SOURCE_FILE (method));
+
+ fprintf (stderr, "%s:%d: warning: ",
+ DECL_SOURCE_FILE (method), DECL_SOURCE_LINE (method));
+ bzero (errbuf, BUFSIZE);
+ fprintf (stderr, "%s `%c%s'\n",
+ message, mtype, gen_method_decl (method, errbuf));
+}
+
+/* Return 1 if METHOD is consistent with PROTO. */
+
+static int
+comp_method_with_proto (method, proto)
+ tree method, proto;
+{
+ static tree function_type = 0;
+
+ /* Create a function_type node once. */
+ if (!function_type)
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ function_type = make_node (FUNCTION_TYPE);
+ pop_obstacks ();
+ }
+
+ /* Install argument types - normally set by build_function_type. */
+ TYPE_ARG_TYPES (function_type) = get_arg_type_list (proto, METHOD_DEF, 0);
+
+ /* install return type */
+ TREE_TYPE (function_type) = groktypename (TREE_TYPE (proto));
+
+ return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function_type);
+}
+
+/* Return 1 if PROTO1 is consistent with PROTO2. */
+
+static int
+comp_proto_with_proto (proto1, proto2)
+ tree proto1, proto2;
+{
+ static tree function_type1 = 0, function_type2 = 0;
+
+ /* Create a couple function_type node's once. */
+ if (!function_type1)
+ {
+ push_obstacks_nochange ();
+ end_temporary_allocation ();
+ function_type1 = make_node (FUNCTION_TYPE);
+ function_type2 = make_node (FUNCTION_TYPE);
+ pop_obstacks ();
+ }
+
+ /* Install argument types; normally set by build_function_type. */
+ TYPE_ARG_TYPES (function_type1) = get_arg_type_list (proto1, METHOD_REF, 0);
+ TYPE_ARG_TYPES (function_type2) = get_arg_type_list (proto2, METHOD_REF, 0);
+
+ /* Install return type. */
+ TREE_TYPE (function_type1) = groktypename (TREE_TYPE (proto1));
+ TREE_TYPE (function_type2) = groktypename (TREE_TYPE (proto2));
+
+ return comptypes (function_type1, function_type2);
+}
+
+/* - Generate an identifier for the function. the format is "_n_cls",
+ where 1 <= n <= nMethods, and cls is the name the implementation we
+ are processing.
+ - Install the return type from the method declaration.
+ - If we have a prototype, check for type consistency. */
+
+static void
+really_start_method (method, parmlist)
+ tree method, parmlist;
+{
+ tree sc_spec, ret_spec, ret_decl, decl_specs;
+ tree method_decl, method_id;
+ char *buf, *sel_name, *class_name, *cat_name;
+
+ /* Synth the storage class & assemble the return type. */
+ sc_spec = tree_cons (NULL_TREE, ridpointers[(int) RID_STATIC], NULL_TREE);
+ ret_spec = TREE_PURPOSE (TREE_TYPE (method));
+ decl_specs = chainon (sc_spec, ret_spec);
+
+ sel_name = IDENTIFIER_POINTER (METHOD_SEL_NAME (method));
+ class_name = IDENTIFIER_POINTER (CLASS_NAME (implementation_context));
+ cat_name = ((TREE_CODE (implementation_context)
+ == CLASS_IMPLEMENTATION_TYPE)
+ ? NULL
+ : IDENTIFIER_POINTER (CLASS_SUPER_NAME (implementation_context)));
+ method_slot++;
+
+ /* Make sure this is big enough for any plausible method label. */
+ buf = (char *) alloca (50 + strlen (sel_name) + strlen (class_name)
+ + (cat_name ? strlen (cat_name) : 0));
+
+ OBJC_GEN_METHOD_LABEL (buf, TREE_CODE (method) == INSTANCE_METHOD_DECL,
+ class_name, cat_name, sel_name, method_slot);
+
+ method_id = get_identifier (buf);
+
+ method_decl = build_nt (CALL_EXPR, method_id, parmlist, NULL_TREE);
+
+ /* Check the declarator portion of the return type for the method. */
+ if ((ret_decl = TREE_VALUE (TREE_TYPE (method))))
+ {
+ /* Unite the complex decl (specified in the abstract decl) with the
+ function decl just synthesized..(int *), (int (*)()), (int (*)[]). */
+ tree save_expr = expr_last (ret_decl);
+
+ TREE_OPERAND (save_expr, 0) = method_decl;
+ method_decl = ret_decl;
+
+ /* Fool the parser into thinking it is starting a function. */
+ start_function (decl_specs, method_decl, NULL_TREE, NULL_TREE, 0);
+
+ /* Unhook: this has the effect of restoring the abstract declarator. */
+ TREE_OPERAND (save_expr, 0) = NULL_TREE;
+ }
+
+ else
+ {
+ TREE_VALUE (TREE_TYPE (method)) = method_decl;
+
+ /* Fool the parser into thinking it is starting a function. */
+ start_function (decl_specs, method_decl, NULL_TREE, NULL_TREE, 0);
+
+ /* Unhook: this has the effect of restoring the abstract declarator. */
+ TREE_VALUE (TREE_TYPE (method)) = NULL_TREE;
+ }
+
+ METHOD_DEFINITION (method) = current_function_decl;
+
+ if (implementation_template != implementation_context)
+ {
+ tree proto;
+
+ if (TREE_CODE (method) == INSTANCE_METHOD_DECL)
+ proto = lookup_instance_method_static (implementation_template,
+ METHOD_SEL_NAME (method));
+ else
+ proto = lookup_class_method_static (implementation_template,
+ METHOD_SEL_NAME (method));
+
+ if (proto && ! comp_method_with_proto (method, proto))
+ {
+ char type = (TREE_CODE (method) == INSTANCE_METHOD_DECL ? '-' : '+');
+
+ warn_with_method ("conflicting types for", type, method);
+ warn_with_method ("previous declaration of", type, proto);
+ }
+ }
+}
+
+/* The following routine is always called...this "architecture" is to
+ accommodate "old-style" variable length selectors.
+
+ - a:a b:b // prototype ; id c; id d; // old-style. */
+
+void
+continue_method_def ()
+{
+ tree parmlist;
+
+ if (METHOD_ADD_ARGS (method_context) == (tree)1)
+ /* We have a `, ...' immediately following the selector. */
+ parmlist = get_parm_info (0);
+ else
+ parmlist = get_parm_info (1); /* place a `void_at_end' */
+
+ /* Set self_decl from the first argument...this global is used by
+ build_ivar_reference calling build_indirect_ref. */
+ self_decl = TREE_PURPOSE (parmlist);
+
+ poplevel (0, 0, 0);
+ really_start_method (method_context, parmlist);
+ store_parm_decls ();
+}
+
+/* Called by the parser, from the `pushlevel' production. */
+
+void
+add_objc_decls ()
+{
+ if (!UOBJC_SUPER_decl)
+ {
+ UOBJC_SUPER_decl = start_decl (get_identifier (UTAG_SUPER),
+ build_tree_list (NULL_TREE,
+ objc_super_template),
+ 0, NULL_TREE, NULL_TREE);
+
+ finish_decl (UOBJC_SUPER_decl, NULL_TREE, NULL_TREE);
+
+ /* This prevents `unused variable' warnings when compiling with -Wall. */
+ TREE_USED (UOBJC_SUPER_decl) = 1;
+ DECL_ARTIFICIAL (UOBJC_SUPER_decl) = 1;
+ }
+}
+
+/* _n_Method (id self, SEL sel, ...)
+ {
+ struct objc_super _S;
+ _msgSuper ((_S.self = self, _S.class = _cls, &_S), ...);
+ } */
+
+tree
+get_super_receiver ()
+{
+ if (method_context)
+ {
+ tree super_expr, super_expr_list;
+
+ /* Set receiver to self. */
+ super_expr = build_component_ref (UOBJC_SUPER_decl, self_id);
+ super_expr = build_modify_expr (super_expr, NOP_EXPR, self_decl);
+ super_expr_list = build_tree_list (NULL_TREE, super_expr);
+
+ /* Set class to begin searching. */
+ super_expr = build_component_ref (UOBJC_SUPER_decl,
+ get_identifier ("class"));
+
+ if (TREE_CODE (implementation_context) == CLASS_IMPLEMENTATION_TYPE)
+ {
+ /* [_cls, __cls]Super are "pre-built" in
+ synth_forward_declarations. */
+
+ super_expr = build_modify_expr (super_expr, NOP_EXPR,
+ ((TREE_CODE (method_context)
+ == INSTANCE_METHOD_DECL)
+ ? ucls_super_ref
+ : uucls_super_ref));
+ }
+
+ else
+ /* We have a category. */
+ {
+ tree super_name = CLASS_SUPER_NAME (implementation_template);
+ tree super_class;
+
+ if (!super_name)
+ {
+ error ("no super class declared in interface for `%s'",
+ IDENTIFIER_POINTER (CLASS_NAME (implementation_template)));
+ return error_mark_node;
+ }
+
+ if (flag_next_runtime)
+ {
+ super_class = get_class_reference (super_name);
+ if (TREE_CODE (method_context) == CLASS_METHOD_DECL)
+ super_class
+ = build_component_ref (build_indirect_ref (super_class, "->"),
+ get_identifier ("isa"));
+ }
+ else
+ {
+ add_class_reference (super_name);
+ super_class = (TREE_CODE (method_context) == INSTANCE_METHOD_DECL
+ ? objc_get_class_decl : objc_get_meta_class_decl);
+ assemble_external (super_class);
+ super_class
+ = build_function_call
+ (super_class,
+ build_tree_list
+ (NULL_TREE,
+ my_build_string (IDENTIFIER_LENGTH (super_name) + 1,
+ IDENTIFIER_POINTER (super_name))));
+ }
+
+ TREE_TYPE (super_class) = TREE_TYPE (ucls_super_ref);
+ super_expr = build_modify_expr (super_expr, NOP_EXPR, super_class);
+ }
+
+ chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr));
+
+ super_expr = build_unary_op (ADDR_EXPR, UOBJC_SUPER_decl, 0);
+ chainon (super_expr_list, build_tree_list (NULL_TREE, super_expr));
+
+ return build_compound_expr (super_expr_list);
+ }
+ else
+ {
+ error ("[super ...] must appear in a method context");
+ return error_mark_node;
+ }
+}
+
+static tree
+encode_method_def (func_decl)
+ tree func_decl;
+{
+ tree parms;
+ int stack_size;
+ int max_parm_end = 0;
+ char buffer[40];
+ tree result;
+
+ /* Return type. */
+ encode_type (TREE_TYPE (TREE_TYPE (func_decl)),
+ obstack_object_size (&util_obstack),
+ OBJC_ENCODE_INLINE_DEFS);
+
+ /* Stack size. */
+ for (parms = DECL_ARGUMENTS (func_decl); parms;
+ parms = TREE_CHAIN (parms))
+ {
+ int parm_end = (forwarding_offset (parms)
+ + (TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (parms)))
+ / BITS_PER_UNIT));
+
+ if (!offset_is_register && parm_end > max_parm_end)
+ max_parm_end = parm_end;
+ }
+
+ stack_size = max_parm_end - OBJC_FORWARDING_MIN_OFFSET;
+
+ sprintf (buffer, "%d", stack_size);
+ obstack_grow (&util_obstack, buffer, strlen (buffer));
+
+ /* Argument types. */
+ for (parms = DECL_ARGUMENTS (func_decl); parms;
+ parms = TREE_CHAIN (parms))
+ {
+ /* Type. */
+ encode_type (TREE_TYPE (parms),
+ obstack_object_size (&util_obstack),
+ OBJC_ENCODE_INLINE_DEFS);
+
+ /* Compute offset. */
+ sprintf (buffer, "%d", forwarding_offset (parms));
+
+ /* Indicate register. */
+ if (offset_is_register)
+ obstack_1grow (&util_obstack, '+');
+
+ obstack_grow (&util_obstack, buffer, strlen (buffer));
+ }
+
+ obstack_1grow (&util_obstack, 0);
+ result = get_identifier (obstack_finish (&util_obstack));
+ obstack_free (&util_obstack, util_firstobj);
+ return result;
+}
+
+void
+finish_method_def ()
+{
+ METHOD_ENCODING (method_context) = encode_method_def (current_function_decl);
+
+ finish_function (0);
+
+ /* Required to implement _msgSuper. This must be done AFTER finish_function,
+ since the optimizer may find "may be used before set" errors. */
+ method_context = NULL_TREE;
+}
+
+#if 0
+int
+lang_report_error_function (decl)
+ tree decl;
+{
+ if (method_context)
+ {
+ fprintf (stderr, "In method `%s'\n",
+ IDENTIFIER_POINTER (METHOD_SEL_NAME (method_context)));
+ return 1;
+ }
+
+ else
+ return 0;
+}
+#endif
+
+static int
+is_complex_decl (type)
+ tree type;
+{
+ return (TREE_CODE (type) == ARRAY_TYPE
+ || TREE_CODE (type) == FUNCTION_TYPE
+ || (TREE_CODE (type) == POINTER_TYPE && ! IS_ID (type)));
+}
+
+
+/* Code to convert a decl node into text for a declaration in C. */
+
+static char tmpbuf[256];
+
+static void
+adorn_decl (decl, str)
+ tree decl;
+ char *str;
+{
+ enum tree_code code = TREE_CODE (decl);
+
+ if (code == ARRAY_REF)
+ {
+ tree an_int_cst = TREE_OPERAND (decl, 1);
+
+ if (an_int_cst && TREE_CODE (an_int_cst) == INTEGER_CST)
+ sprintf (str + strlen (str), "[%ld]",
+ (long) TREE_INT_CST_LOW (an_int_cst));
+ else
+ strcat (str, "[]");
+ }
+
+ else if (code == ARRAY_TYPE)
+ {
+ tree an_int_cst = TYPE_SIZE (decl);
+ tree array_of = TREE_TYPE (decl);
+
+ if (an_int_cst && TREE_CODE (an_int_cst) == INTEGER_TYPE)
+ sprintf (str + strlen (str), "[%ld]",
+ (long) (TREE_INT_CST_LOW (an_int_cst)
+ / TREE_INT_CST_LOW (TYPE_SIZE (array_of))));
+ else
+ strcat (str, "[]");
+ }
+
+ else if (code == CALL_EXPR)
+ {
+ tree chain = TREE_PURPOSE (TREE_OPERAND (decl, 1));
+
+ strcat (str, "(");
+ while (chain)
+ {
+ gen_declaration (chain, str);
+ chain = TREE_CHAIN (chain);
+ if (chain)
+ strcat (str, ", ");
+ }
+ strcat (str, ")");
+ }
+
+ else if (code == FUNCTION_TYPE)
+ {
+ tree chain = TYPE_ARG_TYPES (decl);
+
+ strcat (str, "(");
+ while (chain && TREE_VALUE (chain) != void_type_node)
+ {
+ gen_declaration (TREE_VALUE (chain), str);
+ chain = TREE_CHAIN (chain);
+ if (chain && TREE_VALUE (chain) != void_type_node)
+ strcat (str, ", ");
+ }
+ strcat (str, ")");
+ }
+
+ else if (code == INDIRECT_REF)
+ {
+ strcpy (tmpbuf, "*");
+ if (TREE_TYPE (decl) && TREE_CODE (TREE_TYPE (decl)) == TREE_LIST)
+ {
+ tree chain;
+
+ for (chain = nreverse (copy_list (TREE_TYPE (decl)));
+ chain;
+ chain = TREE_CHAIN (chain))
+ {
+ if (TREE_CODE (TREE_VALUE (chain)) == IDENTIFIER_NODE)
+ {
+ strcat (tmpbuf, " ");
+ strcat (tmpbuf, IDENTIFIER_POINTER (TREE_VALUE (chain)));
+ }
+ }
+ if (str[0])
+ strcat (tmpbuf, " ");
+ }
+ strcat (tmpbuf, str);
+ strcpy (str, tmpbuf);
+ }
+
+ else if (code == POINTER_TYPE)
+ {
+ strcpy (tmpbuf, "*");
+ if (TREE_READONLY (decl) || TYPE_VOLATILE (decl))
+ {
+ if (TREE_READONLY (decl))
+ strcat (tmpbuf, " const");
+ if (TYPE_VOLATILE (decl))
+ strcat (tmpbuf, " volatile");
+ if (str[0])
+ strcat (tmpbuf, " ");
+ }
+ strcat (tmpbuf, str);
+ strcpy (str, tmpbuf);
+ }
+}
+
+static char *
+gen_declarator (decl, buf, name)
+ tree decl;
+ char *buf;
+ char *name;
+{
+ if (decl)
+ {
+ enum tree_code code = TREE_CODE (decl);
+ char *str;
+ tree op;
+ int wrap = 0;
+
+ switch (code)
+ {
+ case ARRAY_REF:
+ case INDIRECT_REF:
+ case CALL_EXPR:
+ op = TREE_OPERAND (decl, 0);
+
+ /* We have a pointer to a function or array...(*)(), (*)[] */
+ if ((code == ARRAY_REF || code == CALL_EXPR)
+ && op && TREE_CODE (op) == INDIRECT_REF)
+ wrap = 1;
+
+ str = gen_declarator (op, buf, name);
+
+ if (wrap)
+ {
+ strcpy (tmpbuf, "(");
+ strcat (tmpbuf, str);
+ strcat (tmpbuf, ")");
+ strcpy (str, tmpbuf);
+ }
+
+ adorn_decl (decl, str);
+ break;
+
+ case ARRAY_TYPE:
+ case FUNCTION_TYPE:
+ case POINTER_TYPE:
+ strcpy (buf, name);
+ str = buf;
+
+ /* This clause is done iteratively rather than recursively. */
+ do
+ {
+ op = (is_complex_decl (TREE_TYPE (decl))
+ ? TREE_TYPE (decl) : NULL_TREE);
+
+ adorn_decl (decl, str);
+
+ /* We have a pointer to a function or array...(*)(), (*)[] */
+ if (code == POINTER_TYPE
+ && op && (TREE_CODE (op) == FUNCTION_TYPE
+ || TREE_CODE (op) == ARRAY_TYPE))
+ {
+ strcpy (tmpbuf, "(");
+ strcat (tmpbuf, str);
+ strcat (tmpbuf, ")");
+ strcpy (str, tmpbuf);
+ }
+
+ decl = (is_complex_decl (TREE_TYPE (decl))
+ ? TREE_TYPE (decl) : NULL_TREE);
+ }
+
+ while (decl && (code = TREE_CODE (decl)))
+ ;
+
+ break;
+
+ case IDENTIFIER_NODE:
+ /* Will only happen if we are processing a "raw" expr-decl. */
+ strcpy (buf, IDENTIFIER_POINTER (decl));
+ return buf;
+
+ default:
+ break;
+ }
+
+ return str;
+ }
+
+ else
+ /* We have an abstract declarator or a _DECL node. */
+ {
+ strcpy (buf, name);
+ return buf;
+ }
+}
+
+static void
+gen_declspecs (declspecs, buf, raw)
+ tree declspecs;
+ char *buf;
+ int raw;
+{
+ if (raw)
+ {
+ tree chain;
+
+ for (chain = nreverse (copy_list (declspecs));
+ chain; chain = TREE_CHAIN (chain))
+ {
+ tree aspec = TREE_VALUE (chain);
+
+ if (TREE_CODE (aspec) == IDENTIFIER_NODE)
+ strcat (buf, IDENTIFIER_POINTER (aspec));
+ else if (TREE_CODE (aspec) == RECORD_TYPE)
+ {
+ if (TYPE_NAME (aspec))
+ {
+ tree protocol_list = TYPE_PROTOCOL_LIST (aspec);
+
+ if (! TREE_STATIC_TEMPLATE (aspec))
+ strcat (buf, "struct ");
+ strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec)));
+
+ /* NEW!!! */
+ if (protocol_list)
+ {
+ tree chain = protocol_list;
+
+ strcat (buf, " <");
+ while (chain)
+ {
+ strcat (buf,
+ IDENTIFIER_POINTER
+ (PROTOCOL_NAME (TREE_VALUE (chain))));
+ chain = TREE_CHAIN (chain);
+ if (chain)
+ strcat (buf, ", ");
+ }
+ strcat (buf, ">");
+ }
+ }
+
+ else
+ strcat (buf, "untagged struct");
+ }
+
+ else if (TREE_CODE (aspec) == UNION_TYPE)
+ {
+ if (TYPE_NAME (aspec))
+ {
+ if (! TREE_STATIC_TEMPLATE (aspec))
+ strcat (buf, "union ");
+ strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec)));
+ }
+ else
+ strcat (buf, "untagged union");
+ }
+
+ else if (TREE_CODE (aspec) == ENUMERAL_TYPE)
+ {
+ if (TYPE_NAME (aspec))
+ {
+ if (! TREE_STATIC_TEMPLATE (aspec))
+ strcat (buf, "enum ");
+ strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (aspec)));
+ }
+ else
+ strcat (buf, "untagged enum");
+ }
+
+ else if (TREE_CODE (aspec) == TYPE_DECL && DECL_NAME (aspec))
+ strcat (buf, IDENTIFIER_POINTER (DECL_NAME (aspec)));
+
+ else if (IS_ID (aspec))
+ {
+ tree protocol_list = TYPE_PROTOCOL_LIST (aspec);
+
+ strcat (buf, "id");
+ if (protocol_list)
+ {
+ tree chain = protocol_list;
+
+ strcat (buf, " <");
+ while (chain)
+ {
+ strcat (buf,
+ IDENTIFIER_POINTER
+ (PROTOCOL_NAME (TREE_VALUE (chain))));
+ chain = TREE_CHAIN (chain);
+ if (chain)
+ strcat (buf, ", ");
+ }
+ strcat (buf, ">");
+ }
+ }
+ if (TREE_CHAIN (chain))
+ strcat (buf, " ");
+ }
+ }
+ else
+ {
+ /* Type qualifiers. */
+ if (TREE_READONLY (declspecs))
+ strcat (buf, "const ");
+ if (TYPE_VOLATILE (declspecs))
+ strcat (buf, "volatile ");
+
+ switch (TREE_CODE (declspecs))
+ {
+ /* Type specifiers. */
+
+ case INTEGER_TYPE:
+ declspecs = TYPE_MAIN_VARIANT (declspecs);
+
+ /* Signed integer types. */
+
+ if (declspecs == short_integer_type_node)
+ strcat (buf, "short int ");
+ else if (declspecs == integer_type_node)
+ strcat (buf, "int ");
+ else if (declspecs == long_integer_type_node)
+ strcat (buf, "long int ");
+ else if (declspecs == long_long_integer_type_node)
+ strcat (buf, "long long int ");
+ else if (declspecs == signed_char_type_node
+ || declspecs == char_type_node)
+ strcat (buf, "char ");
+
+ /* Unsigned integer types. */
+
+ else if (declspecs == short_unsigned_type_node)
+ strcat (buf, "unsigned short ");
+ else if (declspecs == unsigned_type_node)
+ strcat (buf, "unsigned int ");
+ else if (declspecs == long_unsigned_type_node)
+ strcat (buf, "unsigned long ");
+ else if (declspecs == long_long_unsigned_type_node)
+ strcat (buf, "unsigned long long ");
+ else if (declspecs == unsigned_char_type_node)
+ strcat (buf, "unsigned char ");
+ break;
+
+ case REAL_TYPE:
+ declspecs = TYPE_MAIN_VARIANT (declspecs);
+
+ if (declspecs == float_type_node)
+ strcat (buf, "float ");
+ else if (declspecs == double_type_node)
+ strcat (buf, "double ");
+ else if (declspecs == long_double_type_node)
+ strcat (buf, "long double ");
+ break;
+
+ case RECORD_TYPE:
+ if (TYPE_NAME (declspecs)
+ && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE)
+ {
+ tree protocol_list = TYPE_PROTOCOL_LIST (declspecs);
+
+ if (! TREE_STATIC_TEMPLATE (declspecs))
+ strcat (buf, "struct ");
+ strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs)));
+
+ if (protocol_list)
+ {
+ tree chain = protocol_list;
+
+ strcat (buf, " <");
+ while (chain)
+ {
+ strcat (buf,
+ IDENTIFIER_POINTER
+ (PROTOCOL_NAME (TREE_VALUE (chain))));
+ chain = TREE_CHAIN (chain);
+ if (chain)
+ strcat (buf, ", ");
+ }
+ strcat (buf, ">");
+ }
+ }
+
+ else
+ strcat (buf, "untagged struct");
+
+ strcat (buf, " ");
+ break;
+
+ case UNION_TYPE:
+ if (TYPE_NAME (declspecs)
+ && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE)
+ {
+ strcat (buf, "union ");
+ strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs)));
+ strcat (buf, " ");
+ }
+
+ else
+ strcat (buf, "untagged union ");
+ break;
+
+ case ENUMERAL_TYPE:
+ if (TYPE_NAME (declspecs)
+ && TREE_CODE (TYPE_NAME (declspecs)) == IDENTIFIER_NODE)
+ {
+ strcat (buf, "enum ");
+ strcat (buf, IDENTIFIER_POINTER (TYPE_NAME (declspecs)));
+ strcat (buf, " ");
+ }
+
+ else
+ strcat (buf, "untagged enum ");
+ break;
+
+ case VOID_TYPE:
+ strcat (buf, "void ");
+ break;
+
+ case POINTER_TYPE:
+ {
+ tree protocol_list = TYPE_PROTOCOL_LIST (declspecs);
+
+ strcat (buf, "id");
+ if (protocol_list)
+ {
+ tree chain = protocol_list;
+
+ strcat (buf, " <");
+ while (chain)
+ {
+ strcat (buf,
+ IDENTIFIER_POINTER
+ (PROTOCOL_NAME (TREE_VALUE (chain))));
+ chain = TREE_CHAIN (chain);
+ if (chain)
+ strcat (buf, ", ");
+ }
+
+ strcat (buf, ">");
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+static char *
+gen_declaration (atype_or_adecl, buf)
+ tree atype_or_adecl;
+ char *buf;
+{
+ char declbuf[256];
+
+ if (TREE_CODE (atype_or_adecl) == TREE_LIST)
+ {
+ tree declspecs; /* "identifier_node", "record_type" */
+ tree declarator; /* "array_ref", "indirect_ref", "call_expr"... */
+
+ /* We have a "raw", abstract declarator (typename). */
+ declarator = TREE_VALUE (atype_or_adecl);
+ declspecs = TREE_PURPOSE (atype_or_adecl);
+
+ gen_declspecs (declspecs, buf, 1);
+ if (declarator)
+ {
+ strcat (buf, " ");
+ strcat (buf, gen_declarator (declarator, declbuf, ""));
+ }
+ }
+
+ else
+ {
+ tree atype;
+ tree declspecs; /* "integer_type", "real_type", "record_type"... */
+ tree declarator; /* "array_type", "function_type", "pointer_type". */
+
+ if (TREE_CODE (atype_or_adecl) == FIELD_DECL
+ || TREE_CODE (atype_or_adecl) == PARM_DECL
+ || TREE_CODE (atype_or_adecl) == FUNCTION_DECL)
+ atype = TREE_TYPE (atype_or_adecl);
+ else
+ /* Assume we have a *_type node. */
+ atype = atype_or_adecl;
+
+ if (is_complex_decl (atype))
+ {
+ tree chain;
+
+ /* Get the declaration specifier; it is at the end of the list. */
+ declarator = chain = atype;
+ do
+ chain = TREE_TYPE (chain); /* not TREE_CHAIN (chain); */
+ while (is_complex_decl (chain));
+ declspecs = chain;
+ }
+
+ else
+ {
+ declspecs = atype;
+ declarator = NULL_TREE;
+ }
+
+ gen_declspecs (declspecs, buf, 0);
+
+ if (TREE_CODE (atype_or_adecl) == FIELD_DECL
+ || TREE_CODE (atype_or_adecl) == PARM_DECL
+ || TREE_CODE (atype_or_adecl) == FUNCTION_DECL)
+ {
+ char *decl_name = (DECL_NAME (atype_or_adecl)
+ ? IDENTIFIER_POINTER (DECL_NAME (atype_or_adecl))
+ : "");
+
+ if (declarator)
+ {
+ strcat (buf, " ");
+ strcat (buf, gen_declarator (declarator, declbuf, decl_name));
+ }
+
+ else if (decl_name[0])
+ {
+ strcat (buf, " ");
+ strcat (buf, decl_name);
+ }
+ }
+ else if (declarator)
+ {
+ strcat (buf, " ");
+ strcat (buf, gen_declarator (declarator, declbuf, ""));
+ }
+ }
+
+ return buf;
+}
+
+#define RAW_TYPESPEC(meth) (TREE_VALUE (TREE_PURPOSE (TREE_TYPE (meth))))
+
+static char *
+gen_method_decl (method, buf)
+ tree method;
+ char *buf;
+{
+ tree chain;
+
+ if (RAW_TYPESPEC (method) != objc_object_reference)
+ {
+ strcpy (buf, "(");
+ gen_declaration (TREE_TYPE (method), buf);
+ strcat (buf, ")");
+ }
+
+ chain = METHOD_SEL_ARGS (method);
+ if (chain)
+ {
+ /* We have a chain of keyword_decls. */
+ do
+ {
+ if (KEYWORD_KEY_NAME (chain))
+ strcat (buf, IDENTIFIER_POINTER (KEYWORD_KEY_NAME (chain)));
+
+ strcat (buf, ":");
+ if (RAW_TYPESPEC (chain) != objc_object_reference)
+ {
+ strcat (buf, "(");
+ gen_declaration (TREE_TYPE (chain), buf);
+ strcat (buf, ")");
+ }
+
+ strcat (buf, IDENTIFIER_POINTER (KEYWORD_ARG_NAME (chain)));
+ if ((chain = TREE_CHAIN (chain)))
+ strcat (buf, " ");
+ }
+ while (chain);
+
+ if (METHOD_ADD_ARGS (method) == (tree)1)
+ strcat (buf, ", ...");
+ else if (METHOD_ADD_ARGS (method))
+ {
+ /* We have a tree list node as generate by get_parm_info. */
+ chain = TREE_PURPOSE (METHOD_ADD_ARGS (method));
+
+ /* Know we have a chain of parm_decls. */
+ while (chain)
+ {
+ strcat (buf, ", ");
+ gen_declaration (chain, buf);
+ chain = TREE_CHAIN (chain);
+ }
+ }
+ }
+
+ else
+ /* We have a unary selector. */
+ strcat (buf, IDENTIFIER_POINTER (METHOD_SEL_NAME (method)));
+
+ return buf;
+}
+
+/* Debug info. */
+
+static void
+dump_interface (fp, chain)
+ FILE *fp;
+ tree chain;
+{
+ char *buf = (char *)xmalloc (256);
+ char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain));
+ tree ivar_decls = CLASS_RAW_IVARS (chain);
+ tree nst_methods = CLASS_NST_METHODS (chain);
+ tree cls_methods = CLASS_CLS_METHODS (chain);
+
+ fprintf (fp, "\n@interface %s", my_name);
+
+ if (CLASS_SUPER_NAME (chain))
+ {
+ char *super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain));
+ fprintf (fp, " : %s\n", super_name);
+ }
+ else
+ fprintf (fp, "\n");
+
+ if (ivar_decls)
+ {
+ fprintf (fp, "{\n");
+ do
+ {
+ bzero (buf, 256);
+ fprintf (fp, "\t%s;\n", gen_declaration (ivar_decls, buf));
+ ivar_decls = TREE_CHAIN (ivar_decls);
+ }
+ while (ivar_decls);
+ fprintf (fp, "}\n");
+ }
+
+ while (nst_methods)
+ {
+ bzero (buf, 256);
+ fprintf (fp, "- %s;\n", gen_method_decl (nst_methods, buf));
+ nst_methods = TREE_CHAIN (nst_methods);
+ }
+
+ while (cls_methods)
+ {
+ bzero (buf, 256);
+ fprintf (fp, "+ %s;\n", gen_method_decl (cls_methods, buf));
+ cls_methods = TREE_CHAIN (cls_methods);
+ }
+ fprintf (fp, "\n@end");
+}
+
+/* Demangle function for Objective-C */
+static const char *
+objc_demangle (mangled)
+ const char *mangled;
+{
+ char *demangled, *cp;
+
+ if (mangled[0] == '_' &&
+ (mangled[1] == 'i' || mangled[1] == 'c') &&
+ mangled[2] == '_')
+ {
+ cp = demangled = xmalloc(strlen(mangled) + 2);
+ if (mangled[1] == 'i')
+ *cp++ = '-'; /* for instance method */
+ else
+ *cp++ = '+'; /* for class method */
+ *cp++ = '['; /* opening left brace */
+ strcpy(cp, mangled+3); /* tack on the rest of the mangled name */
+ while (*cp && *cp == '_')
+ cp++; /* skip any initial underbars in class name */
+ cp = strchr(cp, '_'); /* find first non-initial underbar */
+ if (cp == NULL)
+ {
+ free(demangled); /* not mangled name */
+ return mangled;
+ }
+ if (cp[1] == '_') /* easy case: no category name */
+ {
+ *cp++ = ' '; /* replace two '_' with one ' ' */
+ strcpy(cp, mangled + (cp - demangled) + 2);
+ }
+ else
+ {
+ *cp++ = '('; /* less easy case: category name */
+ cp = strchr(cp, '_');
+ if (cp == 0)
+ {
+ free(demangled); /* not mangled name */
+ return mangled;
+ }
+ *cp++ = ')';
+ *cp++ = ' '; /* overwriting 1st char of method name... */
+ strcpy(cp, mangled + (cp - demangled)); /* get it back */
+ }
+ while (*cp && *cp == '_')
+ cp++; /* skip any initial underbars in method name */
+ for (; *cp; cp++)
+ if (*cp == '_')
+ *cp = ':'; /* replace remaining '_' with ':' */
+ *cp++ = ']'; /* closing right brace */
+ *cp++ = 0; /* string terminator */
+ return demangled;
+ }
+ else
+ return mangled; /* not an objc mangled name */
+}
+
+static const char *
+objc_printable_name (decl, kind)
+ tree decl;
+ char **kind;
+{
+ return objc_demangle (IDENTIFIER_POINTER (DECL_NAME (decl)));
+}
+
+static void
+init_objc ()
+{
+ /* Add the special tree codes of Objective C to the tables. */
+
+#define LAST_CODE LAST_AND_UNUSED_TREE_CODE
+
+ gcc_obstack_init (&util_obstack);
+ util_firstobj = (char *) obstack_finish (&util_obstack);
+
+ bcopy (objc_tree_code_type,
+ tree_code_type + (int) LAST_CODE,
+ (int) LAST_OBJC_TREE_CODE - (int) LAST_CODE);
+ bcopy ((char *) objc_tree_code_length,
+ (char *) (tree_code_length + (int) LAST_CODE),
+ (((int) LAST_OBJC_TREE_CODE - (int) LAST_CODE)
+ * sizeof (int)));
+ bcopy ((char *) objc_tree_code_name,
+ (char *) (tree_code_name + (int) LAST_CODE),
+ (((int) LAST_OBJC_TREE_CODE - (int) LAST_CODE)
+ * sizeof (char *)));
+
+ errbuf = (char *)xmalloc (BUFSIZE);
+ hash_init ();
+ synth_module_prologue ();
+
+ /* Change the default error function */
+ decl_printable_name = (char* (*)()) objc_printable_name;
+}
+
+static void
+finish_objc ()
+{
+ struct imp_entry *impent;
+ tree chain;
+ /* The internally generated initializers appear to have missing braces.
+ Don't warn about this. */
+ int save_warn_missing_braces = warn_missing_braces;
+ warn_missing_braces = 0;
+
+ generate_forward_declaration_to_string_table ();
+
+#ifdef OBJC_PROLOGUE
+ OBJC_PROLOGUE;
+#endif
+
+ /* Process the static instances here because initialization of objc_symtab
+ depends on them. */
+ if (objc_static_instances)
+ generate_static_references ();
+
+ if (implementation_context || class_names_chain
+ || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
+ generate_objc_symtab_decl ();
+
+ for (impent = imp_list; impent; impent = impent->next)
+ {
+ implementation_context = impent->imp_context;
+ implementation_template = impent->imp_template;
+
+ UOBJC_CLASS_decl = impent->class_decl;
+ UOBJC_METACLASS_decl = impent->meta_decl;
+
+ if (TREE_CODE (implementation_context) == CLASS_IMPLEMENTATION_TYPE)
+ {
+ /* all of the following reference the string pool... */
+ generate_ivar_lists ();
+ generate_dispatch_tables ();
+ generate_shared_structures ();
+ }
+ else
+ {
+ generate_dispatch_tables ();
+ generate_category (implementation_context);
+ }
+ }
+
+ /* If we are using an array of selectors, we must always
+ finish up the array decl even if no selectors were used. */
+ if (! flag_next_runtime || sel_ref_chain)
+ build_selector_translation_table ();
+
+ if (protocol_chain)
+ generate_protocols ();
+
+ if (implementation_context || class_names_chain || objc_static_instances
+ || meth_var_names_chain || meth_var_types_chain || sel_ref_chain)
+ {
+ /* Arrange for Objc data structures to be initialized at run time. */
+ char *init_name = build_module_descriptor ();
+ if (init_name)
+ assemble_constructor (init_name);
+ }
+
+ /* Dump the class references. This forces the appropriate classes
+ to be linked into the executable image, preserving unix archive
+ semantics. This can be removed when we move to a more dynamically
+ linked environment. */
+
+ for (chain = cls_ref_chain; chain; chain = TREE_CHAIN (chain))
+ {
+ handle_class_ref (chain);
+ if (TREE_PURPOSE (chain))
+ generate_classref_translation_entry (chain);
+ }
+
+ for (impent = imp_list; impent; impent = impent->next)
+ handle_impent (impent);
+
+ /* Dump the string table last. */
+
+ generate_strings ();
+
+ if (flag_gen_declaration)
+ {
+ add_class (implementation_context);
+ dump_interface (gen_declaration_file, implementation_context);
+ }
+
+ if (warn_selector)
+ {
+ int slot;
+ hash hsh;
+
+ /* Run through the selector hash tables and print a warning for any
+ selector which has multiple methods. */
+
+ for (slot = 0; slot < SIZEHASHTABLE; slot++)
+ for (hsh = cls_method_hash_list[slot]; hsh; hsh = hsh->next)
+ if (hsh->list)
+ {
+ tree meth = hsh->key;
+ char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL
+ ? '-' : '+');
+ attr loop;
+
+ warning ("potential selector conflict for method `%s'",
+ IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
+ warn_with_method ("found", type, meth);
+ for (loop = hsh->list; loop; loop = loop->next)
+ warn_with_method ("found", type, loop->value);
+ }
+
+ for (slot = 0; slot < SIZEHASHTABLE; slot++)
+ for (hsh = nst_method_hash_list[slot]; hsh; hsh = hsh->next)
+ if (hsh->list)
+ {
+ tree meth = hsh->key;
+ char type = (TREE_CODE (meth) == INSTANCE_METHOD_DECL
+ ? '-' : '+');
+ attr loop;
+
+ warning ("potential selector conflict for method `%s'",
+ IDENTIFIER_POINTER (METHOD_SEL_NAME (meth)));
+ warn_with_method ("found", type, meth);
+ for (loop = hsh->list; loop; loop = loop->next)
+ warn_with_method ("found", type, loop->value);
+ }
+ }
+
+ warn_missing_braces = save_warn_missing_braces;
+}
+
+/* Subroutines of finish_objc. */
+
+static void
+generate_classref_translation_entry (chain)
+ tree chain;
+{
+ tree expr, name, decl_specs, decl, sc_spec;
+ tree type;
+
+ type = TREE_TYPE (TREE_PURPOSE (chain));
+
+ expr = add_objc_string (TREE_VALUE (chain), class_names);
+ expr = build_c_cast (type, expr); /* cast! */
+
+ name = DECL_NAME (TREE_PURPOSE (chain));
+
+ sc_spec = build_tree_list (NULL_TREE, ridpointers[(int) RID_STATIC]);
+
+ /* static struct objc_class * _OBJC_CLASS_REFERENCES_n = ...; */
+ decl_specs = tree_cons (NULL_TREE, type, sc_spec);
+
+ /* The decl that is returned from start_decl is the one that we
+ forward declared in build_class_reference. */
+ decl = start_decl (name, decl_specs, 1, NULL_TREE, NULL_TREE);
+ finish_decl (decl, expr, NULL_TREE);
+ return;
+}
+
+static void
+handle_class_ref (chain)
+ tree chain;
+{
+ char *name = IDENTIFIER_POINTER (TREE_VALUE (chain));
+ if (! flag_next_runtime)
+ {
+ tree decl;
+ char *string = (char *) alloca (strlen (name) + 30);
+ tree exp;
+
+ sprintf (string, "%sobjc_class_name_%s",
+ (flag_next_runtime ? "." : "__"), name);
+
+ /* Make a decl for this name, so we can use its address in a tree. */
+ decl = build_decl (VAR_DECL, get_identifier (string), char_type_node);
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+
+ pushdecl (decl);
+ rest_of_decl_compilation (decl, 0, 0, 0);
+
+ /* Make following constant read-only (why not)? */
+ readonly_data_section ();
+
+ exp = build1 (ADDR_EXPR, string_type_node, decl);
+
+ /* Align the section properly. */
+ assemble_constant_align (exp);
+
+ /* Inform the assembler about this new external thing. */
+ assemble_external (decl);
+
+ /* Output a constant to reference this address. */
+ output_constant (exp, int_size_in_bytes (string_type_node));
+ }
+ else
+ {
+ /* This overreliance on our assembler (i.e. lack of portability)
+ should be dealt with at some point. The GNU strategy (above)
+ won't work either, but it is a start. */
+ char *string = (char *) alloca (strlen (name) + 30);
+ sprintf (string, ".reference .objc_class_name_%s", name);
+ assemble_asm (my_build_string (strlen (string) + 1, string));
+ }
+}
+
+static void
+handle_impent (impent)
+ struct imp_entry *impent;
+{
+ implementation_context = impent->imp_context;
+ implementation_template = impent->imp_template;
+
+ if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE)
+ {
+ char *class_name = IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context));
+ char *string = (char *) alloca (strlen (class_name) + 30);
+
+ if (flag_next_runtime)
+ {
+ /* Grossly unportable.
+ People should know better than to assume
+ such things about assembler syntax! */
+ sprintf (string, ".objc_class_name_%s=0", class_name);
+ assemble_asm (my_build_string (strlen (string) + 1, string));
+
+ sprintf (string, ".globl .objc_class_name_%s", class_name);
+ assemble_asm (my_build_string (strlen (string) + 1, string));
+ }
+
+ else
+ {
+ sprintf (string, "%sobjc_class_name_%s",
+ (flag_next_runtime ? "." : "__"), class_name);
+ assemble_global (string);
+ assemble_label (string);
+ }
+ }
+
+ else if (TREE_CODE (impent->imp_context) == CATEGORY_IMPLEMENTATION_TYPE)
+ {
+ char *class_name = IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context));
+ char *class_super_name
+ = IDENTIFIER_POINTER (CLASS_SUPER_NAME (impent->imp_context));
+ char *string = (char *) alloca (strlen (class_name)
+ + strlen (class_super_name) + 30);
+
+ /* Do the same for categories. Even though no references to these
+ symbols are generated automatically by the compiler, it gives
+ you a handle to pull them into an archive by hand. */
+ if (flag_next_runtime)
+ {
+ /* Grossly unportable. */
+ sprintf (string, ".objc_category_name_%s_%s=0",
+ class_name, class_super_name);
+ assemble_asm (my_build_string (strlen (string) + 1, string));
+
+ sprintf (string, ".globl .objc_category_name_%s_%s",
+ class_name, class_super_name);
+ assemble_asm (my_build_string (strlen (string) + 1, string));
+ }
+
+ else
+ {
+ sprintf (string, "%sobjc_category_name_%s_%s",
+ (flag_next_runtime ? "." : "__"),
+ class_name, class_super_name);
+ assemble_global (string);
+ assemble_label (string);
+ }
+ }
+}
+
+#ifdef DEBUG
+
+static void
+objc_debug (fp)
+ FILE *fp;
+{
+ char *buf = (char *)xmalloc (256);
+
+ { /* dump function prototypes */
+ tree loop = UOBJC_MODULES_decl;
+
+ fprintf (fp, "\n\nfunction prototypes:\n");
+ while (loop)
+ {
+ if (TREE_CODE (loop) == FUNCTION_DECL && DECL_INITIAL (loop))
+ {
+ /* We have a function definition: generate prototype. */
+ bzero (errbuf, BUFSIZE);
+ gen_declaration (loop, errbuf);
+ fprintf (fp, "%s;\n", errbuf);
+ }
+ loop = TREE_CHAIN (loop);
+ }
+ }
+ {
+ /* Dump global chains. */
+ tree loop;
+ int i, index = 0, offset = 0;
+ hash hashlist;
+
+ for (i = 0; i < SIZEHASHTABLE; i++)
+ {
+ if (hashlist = nst_method_hash_list[i])
+ {
+ fprintf (fp, "\n\nnst_method_hash_list[%d]:\n", i);
+ do
+ {
+ bzero (buf, 256);
+ fprintf (fp, "-%s;\n", gen_method_decl (hashlist->key, buf));
+ hashlist = hashlist->next;
+ }
+ while (hashlist);
+ }
+ }
+
+ for (i = 0; i < SIZEHASHTABLE; i++)
+ {
+ if (hashlist = cls_method_hash_list[i])
+ {
+ fprintf (fp, "\n\ncls_method_hash_list[%d]:\n", i);
+ do
+ {
+ bzero (buf, 256);
+ fprintf (fp, "-%s;\n", gen_method_decl (hashlist->key, buf));
+ hashlist = hashlist->next;
+ }
+ while (hashlist);
+ }
+ }
+
+ fprintf (fp, "\nsel_refdef_chain:\n");
+ for (loop = sel_refdef_chain; loop; loop = TREE_CHAIN (loop))
+ {
+ fprintf (fp, "(index: %4d offset: %4d) %s\n", index, offset,
+ IDENTIFIER_POINTER (TREE_VALUE (loop)));
+ index++;
+ /* add one for the '\0' character */
+ offset += IDENTIFIER_LENGTH (TREE_VALUE (loop)) + 1;
+ }
+
+ fprintf (fp, "\n (max_selector_index: %4d.\n", max_selector_index);
+ }
+}
+#endif
+
+void
+print_lang_statistics ()
+{
+}
diff --git a/contrib/gcc/objc/objc-act.h b/contrib/gcc/objc/objc-act.h
new file mode 100644
index 0000000..65224de
--- /dev/null
+++ b/contrib/gcc/objc/objc-act.h
@@ -0,0 +1,117 @@
+/* Declarations for objc-act.c.
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/*** Public Interface (procedures) ***/
+
+/* used by yyparse */
+
+void finish_file PROTO((void));
+tree start_class PROTO((enum tree_code, tree, tree, tree));
+tree continue_class PROTO((tree));
+void finish_class PROTO((tree));
+void start_method_def PROTO((tree));
+void continue_method_def PROTO((void));
+void finish_method_def PROTO((void));
+tree start_protocol PROTO((enum tree_code, tree, tree));
+void finish_protocol PROTO((tree));
+void add_objc_decls PROTO((void));
+
+tree is_ivar PROTO((tree, tree));
+int is_private PROTO((tree));
+int is_public PROTO((tree, tree));
+tree add_instance_variable PROTO((tree, int, tree, tree, tree));
+tree add_class_method PROTO((tree, tree));
+tree add_instance_method PROTO((tree, tree));
+tree get_super_receiver PROTO((void));
+tree get_class_ivars PROTO((tree));
+tree get_class_reference PROTO((tree));
+tree get_static_reference PROTO((tree, tree));
+tree get_object_reference PROTO((tree));
+tree build_message_expr PROTO((tree));
+tree build_selector_expr PROTO((tree));
+tree build_ivar_reference PROTO((tree));
+tree build_keyword_decl PROTO((tree, tree, tree));
+tree build_method_decl PROTO((enum tree_code, tree, tree, tree));
+tree build_protocol_expr PROTO((tree));
+tree build_objc_string_object PROTO((tree));
+
+extern tree objc_ivar_chain;
+extern tree objc_method_context;
+
+void objc_declare_alias PROTO((tree, tree));
+void objc_declare_class PROTO((tree));
+
+extern int objc_receiver_context;
+
+/* the following routines are used to implement statically typed objects */
+
+int objc_comptypes PROTO((tree, tree, int));
+void objc_check_decl PROTO((tree));
+
+/* NeXT extensions */
+
+tree build_encode_expr PROTO((tree));
+
+/* Objective-C structures */
+
+/* KEYWORD_DECL */
+#define KEYWORD_KEY_NAME(DECL) ((DECL)->decl.name)
+#define KEYWORD_ARG_NAME(DECL) ((DECL)->decl.arguments)
+
+/* INSTANCE_METHOD_DECL, CLASS_METHOD_DECL */
+#define METHOD_SEL_NAME(DECL) ((DECL)->decl.name)
+#define METHOD_SEL_ARGS(DECL) ((DECL)->decl.arguments)
+#define METHOD_ADD_ARGS(DECL) ((DECL)->decl.result)
+#define METHOD_DEFINITION(DECL) ((DECL)->decl.initial)
+#define METHOD_ENCODING(DECL) ((DECL)->decl.context)
+
+/* CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
+ CATEGORY_INTERFACE_TYPE, CATEGORY_IMPLEMENTATION_TYPE,
+ PROTOCOL_INTERFACE_TYPE */
+#define CLASS_NAME(CLASS) ((CLASS)->type.name)
+#define CLASS_SUPER_NAME(CLASS) ((CLASS)->type.context)
+#define CLASS_IVARS(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 0)
+#define CLASS_RAW_IVARS(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 1)
+#define CLASS_NST_METHODS(CLASS) ((CLASS)->type.minval)
+#define CLASS_CLS_METHODS(CLASS) ((CLASS)->type.maxval)
+#define CLASS_STATIC_TEMPLATE(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 2)
+#define CLASS_CATEGORY_LIST(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 3)
+#define CLASS_PROTOCOL_LIST(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 4)
+#define PROTOCOL_NAME(CLASS) ((CLASS)->type.name)
+#define PROTOCOL_LIST(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 0)
+#define PROTOCOL_NST_METHODS(CLASS) ((CLASS)->type.minval)
+#define PROTOCOL_CLS_METHODS(CLASS) ((CLASS)->type.maxval)
+#define PROTOCOL_FORWARD_DECL(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 1)
+#define TYPE_PROTOCOL_LIST(TYPE) ((TYPE)->type.context)
+
+/* Define the Objective-C or Objective-C++ language-specific tree codes. */
+
+#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM,
+enum objc_tree_code {
+#ifdef OBJCPLUS
+ dummy_tree_code = LAST_CPLUS_TREE_CODE,
+#else
+ dummy_tree_code = LAST_AND_UNUSED_TREE_CODE,
+#endif
+#include "objc-tree.def"
+ LAST_OBJC_TREE_CODE
+};
+#undef DEFTREECODE
diff --git a/contrib/gcc/objc/objc-api.h b/contrib/gcc/objc/objc-api.h
index c801033..9eb000b 100644
--- a/contrib/gcc/objc/objc-api.h
+++ b/contrib/gcc/objc/objc-api.h
@@ -1,5 +1,5 @@
/* GNU Objective-C Runtime API.
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -10,7 +10,7 @@ later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+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
@@ -29,7 +29,9 @@ Boston, MA 02111-1307, USA. */
#include "objc/objc.h"
#include "objc/hash.h"
+#include "objc/thr.h"
#include <stdio.h>
+#include <stdarg.h>
/* For functions which return Method_t */
#define METHOD_NULL (Method_t)0
@@ -73,6 +75,59 @@ struct objc_method_description
#define _C_STRUCT_E '}'
+/*
+** Error handling
+**
+** Call objc_error() or objc_verror() to record an error; this error
+** routine will generally exit the program but not necessarily if the
+** user has installed his own error handler.
+**
+** Call objc_set_error_handler to assign your own function for
+** handling errors. The function should return YES if it is ok
+** to continue execution, or return NO or just abort if the
+** program should be stopped. The default error handler is just to
+** print a message on stderr.
+**
+** The error handler function should be of type objc_error_handler
+** The first parameter is an object instance of relevance.
+** The second parameter is an error code.
+** The third parameter is a format string in the printf style.
+** The fourth parameter is a variable list of arguments.
+*/
+extern void objc_error(id object, int code, const char* fmt, ...);
+extern void objc_verror(id object, int code, const char* fmt, va_list ap);
+typedef BOOL (*objc_error_handler)(id, int code, const char *fmt, va_list ap);
+objc_error_handler objc_set_error_handler(objc_error_handler func);
+
+/*
+** Error codes
+** These are used by the runtime library, and your
+** error handling may use them to determine if the error is
+** hard or soft thus whether execution can continue or abort.
+*/
+#define OBJC_ERR_UNKNOWN 0 /* Generic error */
+
+#define OBJC_ERR_OBJC_VERSION 1 /* Incorrect runtime version */
+#define OBJC_ERR_GCC_VERSION 2 /* Incorrect compiler version */
+#define OBJC_ERR_MODULE_SIZE 3 /* Bad module size */
+#define OBJC_ERR_PROTOCOL_VERSION 4 /* Incorrect protocol version */
+
+#define OBJC_ERR_MEMORY 10 /* Out of memory */
+
+#define OBJC_ERR_RECURSE_ROOT 20 /* Attempt to archive the root
+ object more than once. */
+#define OBJC_ERR_BAD_DATA 21 /* Didn't read expected data */
+#define OBJC_ERR_BAD_KEY 22 /* Bad key for object */
+#define OBJC_ERR_BAD_CLASS 23 /* Unknown class */
+#define OBJC_ERR_BAD_TYPE 24 /* Bad type specification */
+#define OBJC_ERR_NO_READ 25 /* Cannot read stream */
+#define OBJC_ERR_NO_WRITE 26 /* Cannot write stream */
+#define OBJC_ERR_STREAM_VERSION 27 /* Incorrect stream version */
+#define OBJC_ERR_BAD_OPCODE 28 /* Bad opcode */
+
+#define OBJC_ERR_UNIMPLEMENTED 30 /* Method is not implemented */
+
+#define OBJC_ERR_BAD_STATE 40 /* Bad thread state */
/*
** Set this variable nonzero to print a line describing each
@@ -81,6 +136,16 @@ struct objc_method_description
extern BOOL objc_trace;
+/* For every class which happens to have statically allocated instances in
+ this module, one OBJC_STATIC_INSTANCES is allocated by the compiler.
+ INSTANCES is NULL terminated and points to all statically allocated
+ instances of this class. */
+struct objc_static_instances
+{
+ char *class_name;
+ id instances[0];
+};
+
/*
** Whereas a Module (defined further down) is the root (typically) of a file,
** a Symtab is the root of the class and category definitions within the
@@ -97,23 +162,16 @@ typedef struct objc_symtab {
unsigned short cat_def_cnt; /* Number of categories
compiled (defined) in the
module. */
+
void *defs[1]; /* Variable array of pointers.
cls_def_cnt of type Class
followed by cat_def_cnt of
- type Category_t. */
+ type Category_t, followed
+ by a NULL terminated array
+ of objc_static_instances. */
} Symtab, *Symtab_t;
-/* For every class which happens to have statically allocated instances in
- this module, one OBJC_STATIC_INSTANCES is allocated by the compiler.
- INSTANCES is NULL terminated and points to all statically allocated
- instances of this class. */
-struct objc_static_instances
-{
- char *class_name;
- id instances[0];
-};
-
/*
** The compiler generates one of these structures for each module that
** composes the executable (eg main.m).
@@ -130,12 +188,10 @@ typedef struct objc_module {
module was generated. The
name includes the path. */
- /* Pointer to a NULL terminated array of objc_static_instances. */
- struct objc_static_instances **statics;
-
Symtab_t symtab; /* Pointer to the Symtab of
the module. The Symtab
- holds an array of pointers to
+ holds an array of
+ pointers to
the classes and categories
defined in the module. */
} Module, *Module_t;
@@ -245,7 +301,7 @@ struct objc_protocol_list {
/*
** The class number of this class. This must be the same for both the
-** class and it's meta class object
+** class and its meta class object
*/
#define CLS_GETNUMBER(cls) (__CLS_INFO(cls) >> (HOST_BITS_PER_LONG/2))
#define CLS_SETNUMBER(cls, num) \
@@ -308,12 +364,54 @@ extern Class (*_objc_lookup_class)(const char *name);
*/
extern void (*_objc_load_callback)(Class class, Category* category);
+/*
+** Hook functions for allocating, copying and disposing of instances
+*/
extern id (*_objc_object_alloc)(Class class);
-
extern id (*_objc_object_copy)(id object);
-
extern id (*_objc_object_dispose)(id object);
+/*
+** Standard functions for memory allocation and disposal.
+** Users should use these functions in their ObjC programs so
+** that they work properly with garbage collectors as well as
+** can take advantage of the exception/error handling available.
+*/
+void *
+objc_malloc(size_t size);
+
+void *
+objc_atomic_malloc(size_t size);
+
+void *
+objc_valloc(size_t size);
+
+void *
+objc_realloc(void *mem, size_t size);
+
+void *
+objc_calloc(size_t nelem, size_t size);
+
+void
+objc_free(void *mem);
+
+/*
+** Hook functions for memory allocation and disposal.
+** This makes it easy to substitute garbage collection systems
+** such as Boehm's GC by assigning these function pointers
+** to the GC's allocation routines. By default these point
+** to the ANSI standard malloc, realloc, free, etc.
+**
+** Users should call the normal objc routines above for
+** memory allocation and disposal within their programs.
+*/
+extern void *(*_objc_malloc)(size_t);
+extern void *(*_objc_atomic_malloc)(size_t);
+extern void *(*_objc_valloc)(size_t);
+extern void *(*_objc_realloc)(void *, size_t);
+extern void *(*_objc_calloc)(size_t, size_t);
+extern void (*_objc_free)(void *);
+
Method_t class_get_class_method(MetaClass class, SEL aSel);
Method_t class_get_instance_method(Class class, SEL aSel);
@@ -405,6 +503,12 @@ method_get_imp(Method_t method)
IMP get_imp (Class class, SEL sel);
+/* Redefine on NeXTSTEP so as not to conflict with system function */
+#ifdef __NeXT__
+#define object_copy gnu_object_copy
+#define object_dispose gnu_object_dispose
+#endif
+
id object_copy(id object);
id object_dispose(id object);
@@ -471,6 +575,9 @@ object_is_meta_class(id object)
return CLS_ISMETA((Class)object);
}
+struct sarray*
+objc_get_uninstalled_dtable(void);
+
#endif /* not __objc_api_INCLUDE_GNU */
diff --git a/contrib/gcc/objc/objc-tree.def b/contrib/gcc/objc/objc-tree.def
new file mode 100644
index 0000000..9d6765b
--- /dev/null
+++ b/contrib/gcc/objc/objc-tree.def
@@ -0,0 +1,37 @@
+/* This file contains the definitions and documentation for the
+ additional tree codes used in the Objective C front end (see tree.def
+ for the standard codes).
+ Copyright (C) 1990 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Objective-C types. */
+DEFTREECODE (CLASS_INTERFACE_TYPE, "class_interface_type", 't', 0)
+DEFTREECODE (CLASS_IMPLEMENTATION_TYPE, "class_implementation_type", 't', 0)
+DEFTREECODE (CATEGORY_INTERFACE_TYPE, "category_interface_type", 't', 0)
+DEFTREECODE (CATEGORY_IMPLEMENTATION_TYPE,"category_implementation_type",'t',0)
+DEFTREECODE (PROTOCOL_INTERFACE_TYPE, "protocol_interface_type", 't', 0)
+
+/* Objective-C decls. */
+DEFTREECODE (KEYWORD_DECL, "keyword_decl", 'd', 0)
+DEFTREECODE (INSTANCE_METHOD_DECL, "instance_method_decl", 'd', 0)
+DEFTREECODE (CLASS_METHOD_DECL, "class_method_decl", 'd', 0)
+
+/* Objective-C constants. */
+DEFTREECODE (OBJC_STRING_CST, "objc_string_cst", 'c', 3)
diff --git a/contrib/gcc/objc/objc.gperf b/contrib/gcc/objc/objc.gperf
new file mode 100644
index 0000000..407459f
--- /dev/null
+++ b/contrib/gcc/objc/objc.gperf
@@ -0,0 +1,64 @@
+%{
+/* Command-line: gperf -p -j1 -i 1 -g -o -t -N is_reserved_word -k1,3,$ objc.gperf */
+%}
+struct resword { char *name; short token; enum rid rid; };
+%%
+@defs, DEFS, NORID
+@encode, ENCODE, NORID
+@end, END, NORID
+@implementation, IMPLEMENTATION, NORID
+@interface, INTERFACE, NORID
+@public, PUBLIC, NORID
+@selector, SELECTOR, NORID
+__alignof, ALIGNOF, NORID
+__alignof__, ALIGNOF, NORID
+__asm, ASM, NORID
+__asm__, ASM, NORID
+__attribute, ATTRIBUTE, NORID
+__attribute__, ATTRIBUTE, NORID
+__const, TYPE_QUAL, RID_CONST
+__const__, TYPE_QUAL, RID_CONST
+__extension__, EXTENSION, NORID
+__inline, SCSPEC, RID_INLINE
+__inline__, SCSPEC, RID_INLINE
+__signed, TYPESPEC, RID_SIGNED
+__signed__, TYPESPEC, RID_SIGNED
+__typeof, TYPEOF, NORID
+__typeof__, TYPEOF, NORID
+__volatile, TYPE_QUAL, RID_VOLATILE
+__volatile__, TYPE_QUAL, RID_VOLATILE
+asm, ASM, NORID
+auto, SCSPEC, RID_AUTO
+break, BREAK, NORID
+case, CASE, NORID
+char, TYPESPEC, RID_CHAR
+const, TYPE_QUAL, RID_CONST
+continue, CONTINUE, NORID
+default, DEFAULT, NORID
+do, DO, NORID
+double, TYPESPEC, RID_DOUBLE
+else, ELSE, NORID
+enum, ENUM, NORID
+extern, SCSPEC, RID_EXTERN
+float, TYPESPEC, RID_FLOAT
+for, FOR, NORID
+goto, GOTO, NORID
+if, IF, NORID
+inline, SCSPEC, RID_INLINE
+int, TYPESPEC, RID_INT
+long, TYPESPEC, RID_LONG
+register, SCSPEC, RID_REGISTER
+return, RETURN, NORID
+short, TYPESPEC, RID_SHORT
+signed, TYPESPEC, RID_SIGNED
+sizeof, SIZEOF, NORID
+static, SCSPEC, RID_STATIC
+struct, STRUCT, NORID
+switch, SWITCH, NORID
+typedef, SCSPEC, RID_TYPEDEF
+typeof, TYPEOF, NORID
+union, UNION, NORID
+unsigned, TYPESPEC, RID_UNSIGNED
+void, TYPESPEC, RID_VOID
+volatile, TYPE_QUAL, RID_VOLATILE
+while, WHILE, NORID
diff --git a/contrib/gcc/objc/objc.h b/contrib/gcc/objc/objc.h
index 979c5c8..e48b0fd 100644
--- a/contrib/gcc/objc/objc.h
+++ b/contrib/gcc/objc/objc.h
@@ -1,5 +1,5 @@
/* Basic data types for Objective C.
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -36,7 +36,11 @@ extern "C" {
/*
** Definition of the boolean type.
*/
+#ifdef __vxworks
+typedef int BOOL;
+#else
typedef unsigned char BOOL;
+#endif
#define YES (BOOL)1
#define NO (BOOL)0
@@ -103,9 +107,9 @@ struct objc_class {
unsigned long info; /* Bit mask. See class masks
defined above. */
long instance_size; /* Size in bytes of the class.
- The sum of the class definition
- and all super class
- definitions. */
+ The sum of the class
+ definition and all super
+ class definitions. */
struct objc_ivar_list* ivars; /* Pointer to a structure that
describes the instance
variables in the class
diff --git a/contrib/gcc/objc/objects.c b/contrib/gcc/objc/objects.c
index ebaf117..3e68334 100644
--- a/contrib/gcc/objc/objects.c
+++ b/contrib/gcc/objc/objects.c
@@ -1,5 +1,5 @@
/* GNU Objective C Runtime class related functions
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
@@ -31,9 +31,9 @@ id __objc_object_alloc(Class);
id __objc_object_dispose(id);
id __objc_object_copy(id);
-id (*_objc_object_alloc)(Class) = __objc_object_alloc;
-id (*_objc_object_dispose)(id) = __objc_object_dispose;
-id (*_objc_object_copy)(id) = __objc_object_copy;
+id (*_objc_object_alloc)(Class) = __objc_object_alloc; /* !T:SINGLE */
+id (*_objc_object_dispose)(id) = __objc_object_dispose; /* !T:SINGLE */
+id (*_objc_object_copy)(id) = __objc_object_copy; /* !T:SINGLE */
id
class_create_instance(Class class)
@@ -66,19 +66,19 @@ object_dispose(id object)
if (_objc_object_dispose)
(*_objc_object_dispose)(object);
else
- free(object);
+ objc_free(object);
}
return nil;
}
id __objc_object_alloc(Class class)
{
- return (id)__objc_xmalloc(class->instance_size);
+ return (id)objc_malloc(class->instance_size);
}
id __objc_object_dispose(id object)
{
- free(object);
+ objc_free(object);
return 0;
}
diff --git a/contrib/gcc/objc/runtime.h b/contrib/gcc/objc/runtime.h
index 0f4510f..b0eae4a 100644
--- a/contrib/gcc/objc/runtime.h
+++ b/contrib/gcc/objc/runtime.h
@@ -1,5 +1,5 @@
/* GNU Objective C Runtime internal declarations
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
@@ -37,21 +37,29 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "objc/objc.h" /* core data types */
#include "objc/objc-api.h" /* runtime api functions */
+#include "objc/thr.h" /* thread and mutex support */
+
#include "objc/hash.h" /* hash structures */
-#include "objc/list.h" /* linear lists */
+#include "objc/objc-list.h" /* linear lists */
extern void __objc_add_class_to_hash(Class); /* (objc-class.c) */
-extern void __objc_init_selector_tables(); /* (objc-sel.c) */
-extern void __objc_init_class_tables(); /* (objc-class.c) */
-extern void __objc_init_dispatch_tables(); /* (objc-dispatch.c) */
+extern void __objc_init_selector_tables(void); /* (objc-sel.c) */
+extern void __objc_init_class_tables(void); /* (objc-class.c) */
+extern void __objc_init_dispatch_tables(void); /* (objc-dispatch.c) */
extern void __objc_install_premature_dtable(Class); /* (objc-dispatch.c) */
-extern void __objc_resolve_class_links(); /* (objc-class.c) */
+extern void __objc_resolve_class_links(void); /* (objc-class.c) */
extern void __objc_register_selectors_from_class(Class); /* (objc-sel.c) */
extern void __objc_update_dispatch_table_for_class (Class);/* (objc-msg.c) */
+
+extern int __objc_init_thread_system(void); /* thread.c */
+extern int __objc_fini_thread_system(void); /* thread.c */
+extern void __objc_print_dtable_stats(void); /* sendmsg.c */
+
extern void class_add_method_list(Class, MethodList_t);
-extern void objc_error(id object, const char* fmt, va_list);
-extern void (*_objc_error)(id, const char*, va_list);
+/* Registering instance methods as class methods for root classes */
+extern void __objc_register_instance_methods_to_class(Class);
+extern Method_t search_for_method_in_list(MethodList_t list, SEL op);
/* True when class links has been resolved */
extern BOOL __objc_class_links_resolved;
@@ -59,6 +67,12 @@ extern BOOL __objc_class_links_resolved;
/* Number of selectors stored in each of the selector tables */
extern int __objc_selector_max_index;
+/* Mutex locking __objc_selector_max_index and its arrays. */
+extern objc_mutex_t __objc_runtime_mutex;
+
+/* Number of threads which are alive. */
+extern int __objc_runtime_threads_alive;
+
#ifdef DEBUG
#define DEBUG_PRINTF(format, args...) printf (format, ## args)
#else
@@ -67,7 +81,7 @@ extern int __objc_selector_max_index;
BOOL __objc_responds_to (id object, SEL sel); /* for internal use only! */
SEL __sel_register_typed_name (const char*, const char*,
- struct objc_selector*);
+ struct objc_selector*, BOOL is_const);
#endif /* not __objc_runtime_INCLUDE_GNU */
diff --git a/contrib/gcc/objc/sarray.c b/contrib/gcc/objc/sarray.c
index 9ed2196..7e40fba 100644
--- a/contrib/gcc/objc/sarray.c
+++ b/contrib/gcc/objc/sarray.c
@@ -1,5 +1,5 @@
/* Sparse Arrays for Objective C dispatch tables
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -25,13 +25,16 @@ Boston, MA 02111-1307, USA. */
the executable file might be covered by the GNU General Public License. */
#include "objc/sarray.h"
+#include "objc/runtime.h"
#include <stdio.h>
#include "assert.h"
-int nbuckets = 0;
-int nindices = 0;
-int narrays = 0;
-int idxsize = 0;
+int nbuckets = 0; /* !T:MUTEX */
+int nindices = 0; /* !T:MUTEX */
+int narrays = 0; /* !T:MUTEX */
+int idxsize = 0; /* !T:MUTEX */
+
+static void * first_free_data = NULL; /* !T:MUTEX */
#ifdef OBJC_SPARSE2
const char* __objc_sparse2_id = "2 level sparse indices";
@@ -43,16 +46,62 @@ const char* __objc_sparse3_id = "3 level sparse indices";
#ifdef __alpha__
const void *memcpy (void*, const void*, size_t);
-void free (const void*);
#endif
+/* This function removes any structures left over from free operations
+ that were not safe in a multi-threaded environment. */
+void
+sarray_remove_garbage(void)
+{
+ void **vp;
+ void *np;
+
+ objc_mutex_lock(__objc_runtime_mutex);
+
+ vp = first_free_data;
+ first_free_data = NULL;
+
+ while (vp) {
+ np = *vp;
+ objc_free(vp);
+ vp = np;
+ }
+
+ objc_mutex_unlock(__objc_runtime_mutex);
+}
+
+/* Free a block of dynamically allocated memory. If we are in multi-threaded
+ mode, it is ok to free it. If not, we add it to the garbage heap to be
+ freed later. */
+
+static void
+sarray_free_garbage(void *vp)
+{
+ objc_mutex_lock(__objc_runtime_mutex);
+
+ if (__objc_runtime_threads_alive == 1) {
+ objc_free(vp);
+ if (first_free_data)
+ sarray_remove_garbage();
+ }
+ else {
+ *(void **)vp = first_free_data;
+ first_free_data = vp;
+ }
+
+ objc_mutex_unlock(__objc_runtime_mutex);
+}
+
+/* sarray_at_put : copies data in such a way as to be thread reader safe. */
void
sarray_at_put(struct sarray* array, sidx index, void* element)
{
#ifdef OBJC_SPARSE3
struct sindex** the_index;
+ struct sindex* new_index;
#endif
struct sbucket** the_bucket;
+ struct sbucket* new_bucket;
#ifdef OBJC_SPARSE3
size_t ioffset;
#endif
@@ -96,22 +145,24 @@ sarray_at_put(struct sarray* array, sidx index, void* element)
if ((*the_index) == array->empty_index) {
/* The index was previously empty, allocate a new */
- *the_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex));
- memcpy(*the_index, array->empty_index, sizeof(struct sindex));
- (*the_index)->version = array->version;
+ new_index = (struct sindex*)objc_malloc(sizeof(struct sindex));
+ memcpy(new_index, array->empty_index, sizeof(struct sindex));
+ new_index->version.version = array->version.version;
+ *the_index = new_index; /* Prepared for install. */
the_bucket = &((*the_index)->buckets[boffset]);
- nindices += 1;
- } else if ((*the_index)->version != array->version) {
+ nindices += 1;
+ } else if ((*the_index)->version.version != array->version.version) {
/* This index must be lazy copied */
struct sindex* old_index = *the_index;
- *the_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex));
- memcpy( *the_index,old_index, sizeof(struct sindex));
- (*the_index)->version = array->version;
+ new_index = (struct sindex*)objc_malloc(sizeof(struct sindex));
+ memcpy( new_index, old_index, sizeof(struct sindex));
+ new_index->version.version = array->version.version;
+ *the_index = new_index; /* Prepared for install. */
the_bucket = &((*the_index)->buckets[boffset]);
- nindices += 1;
+ nindices += 1;
}
#endif /* OBJC_SPARSE3 */
@@ -122,18 +173,23 @@ sarray_at_put(struct sarray* array, sidx index, void* element)
/* The bucket was previously empty (or something like that), */
/* allocate a new. This is the effect of `lazy' allocation */
- *the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
- memcpy((void *) *the_bucket, (const void*)array->empty_bucket, sizeof(struct sbucket));
- (*the_bucket)->version = array->version;
+ new_bucket = (struct sbucket*)objc_malloc(sizeof(struct sbucket));
+ memcpy((void *) new_bucket, (const void*)array->empty_bucket,
+ sizeof(struct sbucket));
+ new_bucket->version.version = array->version.version;
+ *the_bucket = new_bucket; /* Prepared for install. */
+
nbuckets += 1;
- } else if ((*the_bucket)->version != array->version) {
+ } else if ((*the_bucket)->version.version != array->version.version) {
/* Perform lazy copy. */
struct sbucket* old_bucket = *the_bucket;
- *the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
- memcpy( *the_bucket,old_bucket, sizeof(struct sbucket));
- (*the_bucket)->version = array->version;
+ new_bucket = (struct sbucket*)objc_malloc(sizeof(struct sbucket));
+ memcpy( new_bucket, old_bucket, sizeof(struct sbucket));
+ new_bucket->version.version = array->version.version;
+ *the_bucket = new_bucket; /* Prepared for install. */
+
nbuckets += 1;
}
@@ -151,42 +207,48 @@ sarray_at_put_safe(struct sarray* array, sidx index, void* element)
struct sarray*
sarray_new (int size, void* default_element)
{
+ struct sarray* arr;
#ifdef OBJC_SPARSE3
size_t num_indices = ((size-1)/(INDEX_CAPACITY))+1;
+ struct sindex ** new_indices;
#else /* OBJC_SPARSE2 */
size_t num_indices = ((size-1)/BUCKET_SIZE)+1;
+ struct sbucket ** new_buckets;
#endif
int counter;
- struct sarray* arr;
assert(size > 0);
/* Allocate core array */
- arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray));
- arr->version = 0;
- narrays += 1;
+ arr = (struct sarray*) objc_malloc(sizeof(struct sarray));
+ arr->version.version = 0;
/* Initialize members */
#ifdef OBJC_SPARSE3
arr->capacity = num_indices*INDEX_CAPACITY;
- arr->indices = (struct sindex**)
- __objc_xmalloc(sizeof(struct sindex*)*num_indices);
- idxsize += num_indices;
+ new_indices = (struct sindex**)
+ objc_malloc(sizeof(struct sindex*)*num_indices);
- arr->empty_index = (struct sindex*) __objc_xmalloc(sizeof(struct sindex));
- arr->empty_index->version = 0;
+ arr->empty_index = (struct sindex*) objc_malloc(sizeof(struct sindex));
+ arr->empty_index->version.version = 0;
+
+ narrays += 1;
+ idxsize += num_indices;
nindices += 1;
#else /* OBJC_SPARSE2 */
arr->capacity = num_indices*BUCKET_SIZE;
- arr->buckets = (struct sbucket**)
- __objc_xmalloc(sizeof(struct sbucket*)*num_indices);
+ new_buckets = (struct sbucket**)
+ objc_malloc(sizeof(struct sbucket*)*num_indices);
+
+ narrays += 1;
idxsize += num_indices;
#endif
- arr->empty_bucket = (struct sbucket*) __objc_xmalloc(sizeof(struct sbucket));
- arr->empty_bucket->version = 0;
+ arr->empty_bucket = (struct sbucket*) objc_malloc(sizeof(struct sbucket));
+ arr->empty_bucket->version.version = 0;
+
nbuckets += 1;
arr->ref_count = 1;
@@ -200,20 +262,28 @@ sarray_new (int size, void* default_element)
arr->empty_index->buckets[counter] = arr->empty_bucket;
for (counter=0; counter<num_indices; counter++)
- arr->indices[counter] = arr->empty_index;
+ new_indices[counter] = arr->empty_index;
#else /* OBJC_SPARSE2 */
for (counter=0; counter<num_indices; counter++)
- arr->buckets[counter] = arr->empty_bucket;
+ new_buckets[counter] = arr->empty_bucket;
#endif
-
+
+#ifdef OBJC_SPARSE3
+ arr->indices = new_indices;
+#else /* OBJC_SPARSE2 */
+ arr->buckets = new_buckets;
+#endif
+
return arr;
}
-/* Reallocate the sparse array to hold `newsize' entries */
+/* Reallocate the sparse array to hold `newsize' entries
+ Note: We really allocate and then free. We have to do this to ensure that
+ any concurrent readers notice the update. */
void
sarray_realloc(struct sarray* array, int newsize)
@@ -223,11 +293,17 @@ sarray_realloc(struct sarray* array, int newsize)
size_t new_max_index = ((newsize-1)/INDEX_CAPACITY);
size_t rounded_size = (new_max_index+1)*INDEX_CAPACITY;
+ struct sindex ** new_indices;
+ struct sindex ** old_indices;
+
#else /* OBJC_SPARSE2 */
size_t old_max_index = (array->capacity-1)/BUCKET_SIZE;
size_t new_max_index = ((newsize-1)/BUCKET_SIZE);
size_t rounded_size = (new_max_index+1)*BUCKET_SIZE;
+ struct sbucket ** new_buckets;
+ struct sbucket ** old_buckets;
+
#endif
int counter;
@@ -235,87 +311,72 @@ sarray_realloc(struct sarray* array, int newsize)
assert(newsize > 0);
/* The size is the same, just ignore the request */
- if(rounded_size == array->capacity)
+ if(rounded_size <= array->capacity)
return;
assert(array->ref_count == 1); /* stop if lazy copied... */
- if(rounded_size < array->capacity)
+ /* We are asked to extend the array -- allocate new bucket table, */
+ /* and insert empty_bucket in newly allocated places. */
+ if(rounded_size > array->capacity)
{
+
+#ifdef OBJC_SPARSE3
+ new_max_index += 4;
+ rounded_size = (new_max_index+1)*INDEX_CAPACITY;
+
+#else /* OBJC_SPARSE2 */
+ new_max_index += 4;
+ rounded_size = (new_max_index+1)*BUCKET_SIZE;
+#endif
+
/* update capacity */
array->capacity = rounded_size;
- /* free buckets above new_max_index */
- for(counter = old_max_index; counter > new_max_index; counter-- ) {
#ifdef OBJC_SPARSE3
- struct sindex* idx = array->indices[counter];
- if((idx != array->empty_index) && (idx->version == array->version)) {
- int c2;
- for(c2=0; c2<INDEX_SIZE; c2++) {
- struct sbucket* bkt = idx->buckets[c2];
- if((bkt != array->empty_bucket) && (bkt->version == array->version))
- {
- free(bkt);
- nbuckets -= 1;
- }
- }
- free(idx);
- nindices -= 1;
- }
+ /* alloc to force re-read by any concurrent readers. */
+ old_indices = array->indices;
+ new_indices = (struct sindex**)
+ objc_malloc((new_max_index+1)*sizeof(struct sindex*));
#else /* OBJC_SPARSE2 */
- struct sbucket* bkt = array->buckets[counter];
- if ((bkt != array->empty_bucket) && (bkt->version == array->version))
- {
- free(bkt);
- nbuckets -= 1;
- }
+ old_buckets = array->buckets;
+ new_buckets = (struct sbucket**)
+ objc_malloc((new_max_index+1)*sizeof(struct sbucket*));
#endif
- }
-
+
+ /* copy buckets below old_max_index (they are still valid) */
+ for(counter = 0; counter <= old_max_index; counter++ ) {
#ifdef OBJC_SPARSE3
- /* realloc to free the space above new_max_index */
- array->indices = (struct sindex**)
- __objc_xrealloc(array->indices,
- (new_max_index+1)*sizeof(struct sindex*));
+ new_indices[counter] = old_indices[counter];
#else /* OBJC_SPARSE2 */
- array->buckets = (struct sbucket**)
- __objc_xrealloc(array->buckets,
- (new_max_index+1)*sizeof(struct sbucket*));
-#endif
- idxsize -= (old_max_index-new_max_index);
-
- return;
- }
-
- /* We are asked to extend the array -- reallocate the bucket table, */
- /* and insert empty_bucket in newly allocated places. */
- if(rounded_size > array->capacity)
- {
- /* update capacity */
- array->capacity = rounded_size;
+ new_buckets[counter] = old_buckets[counter];
+#endif
+ }
#ifdef OBJC_SPARSE3
- /* realloc to make room in table above old_max_index */
- array->indices = (struct sindex**)
- __objc_xrealloc(array->indices,
- (new_max_index+1)*sizeof(struct sindex*));
-
/* reset entries above old_max_index to empty_bucket */
for(counter = old_max_index+1; counter <= new_max_index; counter++)
- array->indices[counter] = array->empty_index;
-
+ new_indices[counter] = array->empty_index;
#else /* OBJC_SPARSE2 */
-
- /* realloc to make room in table above old_max_index */
- array->buckets = (struct sbucket**)
- __objc_xrealloc(array->buckets,
- (new_max_index+1)*sizeof(struct sbucket*));
-
/* reset entries above old_max_index to empty_bucket */
for(counter = old_max_index+1; counter <= new_max_index; counter++)
- array->buckets[counter] = array->empty_bucket;
+ new_buckets[counter] = array->empty_bucket;
+#endif
+
+#ifdef OBJC_SPARSE3
+ /* install the new indices */
+ array->indices = new_indices;
+#else /* OBJC_SPARSE2 */
+ array->buckets = new_buckets;
+#endif
+#ifdef OBJC_SPARSE3
+ /* free the old indices */
+ sarray_free_garbage(old_indices);
+#else /* OBJC_SPARSE2 */
+ sarray_free_garbage(old_buckets);
#endif
+
idxsize += (new_max_index-old_max_index);
return;
}
@@ -326,10 +387,13 @@ sarray_realloc(struct sarray* array, int newsize)
void
sarray_free(struct sarray* array) {
+
#ifdef OBJC_SPARSE3
size_t old_max_index = (array->capacity-1)/INDEX_CAPACITY;
+ struct sindex ** old_indices;
#else
size_t old_max_index = (array->capacity-1)/BUCKET_SIZE;
+ struct sbucket ** old_buckets;
#endif
int counter = 0;
@@ -338,31 +402,40 @@ sarray_free(struct sarray* array) {
if(--(array->ref_count) != 0) /* There exists copies of me */
return;
+#ifdef OBJC_SPARSE3
+ old_indices = array->indices;
+#else
+ old_buckets = array->buckets;
+#endif
+
if((array->is_copy_of) && ((array->is_copy_of->ref_count - 1) == 0))
sarray_free(array->is_copy_of);
/* Free all entries that do not point to empty_bucket */
for(counter = 0; counter <= old_max_index; counter++ ) {
#ifdef OBJC_SPARSE3
- struct sindex* idx = array->indices[counter];
- if((idx != array->empty_index) && (idx->version == array->version)) {
+ struct sindex* idx = old_indices[counter];
+ if((idx != array->empty_index) &&
+ (idx->version.version == array->version.version)) {
int c2;
for(c2=0; c2<INDEX_SIZE; c2++) {
struct sbucket* bkt = idx->buckets[c2];
- if((bkt != array->empty_bucket) && (bkt->version == array->version))
+ if((bkt != array->empty_bucket) &&
+ (bkt->version.version == array->version.version))
{
- free(bkt);
+ sarray_free_garbage(bkt);
nbuckets -= 1;
}
}
- free(idx);
+ sarray_free_garbage(idx);
nindices -= 1;
}
#else /* OBJC_SPARSE2 */
struct sbucket* bkt = array->buckets[counter];
- if ((bkt != array->empty_bucket) && (bkt->version == array->version))
+ if ((bkt != array->empty_bucket) &&
+ (bkt->version.version == array->version.version))
{
- free(bkt);
+ sarray_free_garbage(bkt);
nbuckets -= 1;
}
#endif
@@ -370,33 +443,32 @@ sarray_free(struct sarray* array) {
#ifdef OBJC_SPARSE3
/* free empty_index */
- if(array->empty_index->version == array->version) {
- free(array->empty_index);
+ if(array->empty_index->version.version == array->version.version) {
+ sarray_free_garbage(array->empty_index);
nindices -= 1;
}
#endif
/* free empty_bucket */
- if(array->empty_bucket->version == array->version) {
- free(array->empty_bucket);
+ if(array->empty_bucket->version.version == array->version.version) {
+ sarray_free_garbage(array->empty_bucket);
nbuckets -= 1;
}
+ idxsize -= (old_max_index+1);
+ narrays -= 1;
#ifdef OBJC_SPARSE3
/* free bucket table */
- free(array->indices);
- idxsize -= (old_max_index+1);
+ sarray_free_garbage(array->indices);
#else
/* free bucket table */
- free(array->buckets);
- idxsize -= (old_max_index+1);
+ sarray_free_garbage(array->buckets);
#endif
-
+
/* free array */
- free(array);
- narrays -= 1;
+ sarray_free_garbage(array);
}
/* This is a lazy copy. Only the core of the structure is actually */
@@ -405,37 +477,46 @@ sarray_free(struct sarray* array) {
struct sarray*
sarray_lazy_copy(struct sarray* oarr)
{
+ struct sarray* arr;
+
#ifdef OBJC_SPARSE3
size_t num_indices = ((oarr->capacity-1)/INDEX_CAPACITY)+1;
+ struct sindex ** new_indices;
#else /* OBJC_SPARSE2 */
size_t num_indices = ((oarr->capacity-1)/BUCKET_SIZE)+1;
+ struct sbucket ** new_buckets;
#endif
- struct sarray* arr;
/* Allocate core array */
- arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray));
- memcpy( arr,oarr, sizeof(struct sarray));
- arr->version = oarr->version + 1;
- arr->is_copy_of = oarr;
- oarr->ref_count += 1;
+ arr = (struct sarray*) objc_malloc(sizeof(struct sarray)); /* !!! */
+ arr->version.version = oarr->version.version + 1;
+#ifdef OBJC_SPARSE3
+ arr->empty_index = oarr->empty_index;
+#endif
+ arr->empty_bucket = oarr->empty_bucket;
arr->ref_count = 1;
+ oarr->ref_count += 1;
+ arr->is_copy_of = oarr;
+ arr->capacity = oarr->capacity;
#ifdef OBJC_SPARSE3
/* Copy bucket table */
- arr->indices = (struct sindex**)
- __objc_xmalloc(sizeof(struct sindex*)*num_indices);
- memcpy( arr->indices,oarr->indices,
+ new_indices = (struct sindex**)
+ objc_malloc(sizeof(struct sindex*)*num_indices);
+ memcpy( new_indices,oarr->indices,
sizeof(struct sindex*)*num_indices);
+ arr->indices = new_indices;
#else
/* Copy bucket table */
- arr->buckets = (struct sbucket**)
- __objc_xmalloc(sizeof(struct sbucket*)*num_indices);
- memcpy( arr->buckets,oarr->buckets,
+ new_buckets = (struct sbucket**)
+ objc_malloc(sizeof(struct sbucket*)*num_indices);
+ memcpy( new_buckets,oarr->buckets,
sizeof(struct sbucket*)*num_indices);
+ arr->buckets = new_buckets;
#endif
idxsize += num_indices;
narrays += 1;
-
+
return arr;
}
diff --git a/contrib/gcc/objc/sarray.h b/contrib/gcc/objc/sarray.h
index a3ec7a9..74fa386 100644
--- a/contrib/gcc/objc/sarray.h
+++ b/contrib/gcc/objc/sarray.h
@@ -1,7 +1,6 @@
/* Sparse Arrays for Objective C dispatch tables
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
-
-Author: Kresten Krab Thorup
+ Copyright (C) 1993, 1995, 1996 Free Software Foundation, Inc.
+ Contributed by Kresten Krab Thorup.
This file is part of GNU CC.
@@ -42,6 +41,8 @@ extern const char* __objc_sparse3_id;
#include <stddef.h>
+#include "objc/thr.h"
+
extern int nbuckets; /* for stats */
extern int nindices;
extern int narrays;
@@ -108,19 +109,21 @@ union sofftype {
#endif /* not PRECOMPUTE_SELECTORS */
-void * __objc_xrealloc (void *optr, size_t size);
-void * __objc_xmalloc (size_t size);
+union sversion {
+ int version;
+ void *next_free;
+};
struct sbucket {
void* elems[BUCKET_SIZE]; /* elements stored in array */
- short version; /* used for copy-on-write */
+ union sversion version; /* used for copy-on-write */
};
#ifdef OBJC_SPARSE3
struct sindex {
struct sbucket* buckets[INDEX_SIZE];
- short version;
+ union sversion version; /* used for copy-on-write */
};
#endif /* OBJC_SPARSE3 */
@@ -133,7 +136,7 @@ struct sarray {
struct sbucket** buckets;
#endif /* OBJC_SPARSE2 */
struct sbucket* empty_bucket;
- short version;
+ union sversion version; /* used for copy-on-write */
short ref_count;
struct sarray* is_copy_of;
size_t capacity;
@@ -142,10 +145,12 @@ struct sarray {
struct sarray* sarray_new(int, void* default_element);
void sarray_free(struct sarray*);
struct sarray* sarray_lazy_copy(struct sarray*);
-struct sarray* sarray_hard_copy(struct sarray*); /* ... like the name? */
void sarray_realloc(struct sarray*, int new_size);
void sarray_at_put(struct sarray*, sidx index, void* elem);
void sarray_at_put_safe(struct sarray*, sidx index, void* elem);
+
+struct sarray* sarray_hard_copy(struct sarray*); /* ... like the name? */
+void sarray_remove_garbage(void);
#ifdef PRECOMPUTE_SELECTORS
diff --git a/contrib/gcc/objc/selector.c b/contrib/gcc/objc/selector.c
index be68f4f..83c70e4 100644
--- a/contrib/gcc/objc/selector.c
+++ b/contrib/gcc/objc/selector.c
@@ -1,5 +1,5 @@
/* GNU Objective C Runtime selector related functions
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
@@ -31,14 +31,14 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#define SELECTOR_HASH_SIZE 128
/* Tables mapping selector names to uid and opposite */
-static struct sarray* __objc_selector_array = 0; /* uid -> sel */
-static struct sarray* __objc_selector_names = 0; /* uid -> name */
-static cache_ptr __objc_selector_hash = 0; /* name -> uid */
+static struct sarray* __objc_selector_array = 0; /* uid -> sel !T:MUTEX */
+static struct sarray* __objc_selector_names = 0; /* uid -> name !T:MUTEX */
+static cache_ptr __objc_selector_hash = 0; /* name -> uid !T:MUTEX */
static void register_selectors_from_list(MethodList_t);
/* Number of selectors stored in each of the above tables */
-int __objc_selector_max_index = 0;
+int __objc_selector_max_index = 0; /* !T:MUTEX */
void __objc_init_selector_tables()
{
@@ -88,6 +88,71 @@ register_selectors_from_list (MethodList_t method_list)
}
+/* Register instance methods as class methods for root classes */
+void __objc_register_instance_methods_to_class(Class class)
+{
+ MethodList_t method_list;
+ MethodList_t class_method_list;
+ int max_methods_no = 16;
+ MethodList_t new_list;
+ Method_t curr_method;
+
+ /* Only if a root class. */
+ if(class->super_class)
+ return;
+
+ /* Allocate a method list to hold the new class methods */
+ new_list = objc_calloc(sizeof(struct objc_method_list)
+ + sizeof(struct objc_method[max_methods_no]), 1);
+ method_list = class->methods;
+ class_method_list = class->class_pointer->methods;
+ curr_method = &new_list->method_list[0];
+
+ /* Iterate through the method lists for the class */
+ while (method_list)
+ {
+ int i;
+
+ /* Iterate through the methods from this method list */
+ for (i = 0; i < method_list->method_count; i++)
+ {
+ Method_t mth = &method_list->method_list[i];
+ if (mth->method_name
+ && !search_for_method_in_list (class_method_list,
+ mth->method_name))
+ {
+ /* This instance method isn't a class method.
+ Add it into the new_list. */
+ *curr_method = *mth;
+
+ /* Reallocate the method list if necessary */
+ if(++new_list->method_count == max_methods_no)
+ new_list =
+ objc_realloc(new_list, sizeof(struct objc_method_list)
+ + sizeof(struct
+ objc_method[max_methods_no += 16]));
+ curr_method = &new_list->method_list[new_list->method_count];
+ }
+ }
+
+ method_list = method_list->method_next;
+ }
+
+ /* If we created any new class methods
+ then attach the method list to the class */
+ if (new_list->method_count)
+ {
+ new_list =
+ objc_realloc(new_list, sizeof(struct objc_method_list)
+ + sizeof(struct objc_method[new_list->method_count]));
+ new_list->method_next = class->class_pointer->methods;
+ class->class_pointer->methods = new_list;
+ }
+
+ __objc_update_dispatch_table_for_class (class->class_pointer);
+}
+
+
/* Returns YES iff t1 and t2 have same method types, but we ignore
the argframe layout */
BOOL
@@ -122,11 +187,16 @@ sel_get_typed_uid (const char *name, const char *types)
struct objc_list *l;
sidx i;
+ objc_mutex_lock(__objc_runtime_mutex);
+
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (i == 0)
- return 0;
+ {
+ objc_mutex_unlock(__objc_runtime_mutex);
+ return 0;
+ }
- for (l = (struct objc_list*)sarray_get (__objc_selector_array, i);
+ for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
l; l = l->tail)
{
SEL s = (SEL)l->head;
@@ -134,15 +204,18 @@ sel_get_typed_uid (const char *name, const char *types)
{
if (s->sel_types == types)
{
+ objc_mutex_unlock(__objc_runtime_mutex);
return s;
}
}
else if (sel_types_match (s->sel_types, types))
{
+ objc_mutex_unlock(__objc_runtime_mutex);
return s;
}
}
+ objc_mutex_unlock(__objc_runtime_mutex);
return 0;
}
@@ -152,20 +225,29 @@ sel_get_any_typed_uid (const char *name)
{
struct objc_list *l;
sidx i;
- SEL s;
+ SEL s = NULL;
+
+ objc_mutex_lock(__objc_runtime_mutex);
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (i == 0)
- return 0;
+ {
+ objc_mutex_unlock(__objc_runtime_mutex);
+ return 0;
+ }
- for (l = (struct objc_list*)sarray_get (__objc_selector_array, i);
+ for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
l; l = l->tail)
{
s = (SEL) l->head;
if (s->sel_types)
- return s;
+ {
+ objc_mutex_unlock(__objc_runtime_mutex);
+ return s;
+ }
}
+ objc_mutex_unlock(__objc_runtime_mutex);
return s;
}
@@ -176,11 +258,18 @@ sel_get_any_uid (const char *name)
struct objc_list *l;
sidx i;
+ objc_mutex_lock(__objc_runtime_mutex);
+
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (soffset_decode (i) == 0)
- return 0;
+ {
+ objc_mutex_unlock(__objc_runtime_mutex);
+ return 0;
+ }
+
+ l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
+ objc_mutex_unlock(__objc_runtime_mutex);
- l = (struct objc_list*)sarray_get (__objc_selector_array, i);
if (l == 0)
return 0;
@@ -199,11 +288,16 @@ sel_get_uid (const char *name)
const char*
sel_get_name (SEL selector)
{
+ const char *ret;
+
+ objc_mutex_lock(__objc_runtime_mutex);
if ((soffset_decode((sidx)selector->sel_id) > 0)
&& (soffset_decode((sidx)selector->sel_id) <= __objc_selector_max_index))
- return sarray_get (__objc_selector_names, (sidx) selector->sel_id);
+ ret = sarray_get_safe (__objc_selector_names, (sidx) selector->sel_id);
else
- return 0;
+ ret = 0;
+ objc_mutex_unlock(__objc_runtime_mutex);
+ return ret;
}
BOOL
@@ -227,10 +321,15 @@ sel_get_type (SEL selector)
extern struct sarray* __objc_uninstalled_dtable;
/* Store the passed selector name in the selector record and return its
- selector value (value returned by sel_get_uid). */
+ selector value (value returned by sel_get_uid).
+ Assumes that the calling function has locked down __objc_runtime_mutex. */
+/* is_const parameter tells us if the name and types parameters
+ are really constant or not. If YES then they are constant and
+ we can just store the pointers. If NO then we need to copy
+ name and types because the pointers may disappear later on. */
SEL
__sel_register_typed_name (const char *name, const char *types,
- struct objc_selector *orig)
+ struct objc_selector *orig, BOOL is_const)
{
struct objc_selector* j;
sidx i;
@@ -239,7 +338,7 @@ __sel_register_typed_name (const char *name, const char *types,
i = (sidx) hash_value_for_key (__objc_selector_hash, name);
if (soffset_decode (i) != 0)
{
- for (l = (struct objc_list*)sarray_get (__objc_selector_array, i);
+ for (l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
l; l = l->tail)
{
SEL s = (SEL)l->head;
@@ -270,11 +369,17 @@ __sel_register_typed_name (const char *name, const char *types,
if (orig)
j = orig;
else
- j = __objc_xmalloc (sizeof (struct objc_selector));
+ j = objc_malloc (sizeof (struct objc_selector));
j->sel_id = (void*)i;
- j->sel_types = (const char*)types;
- l = (struct objc_list*)sarray_get (__objc_selector_array, i);
+ /* Can we use the pointer or must copy types? Don't copy if NULL */
+ if ((is_const) || (types == 0))
+ j->sel_types = (const char*)types;
+ else {
+ j->sel_types = (char *) objc_malloc(strlen(types)+1);
+ strcpy((char *)j->sel_types, types);
+ }
+ l = (struct objc_list*)sarray_get_safe (__objc_selector_array, i);
}
else
{
@@ -283,10 +388,16 @@ __sel_register_typed_name (const char *name, const char *types,
if (orig)
j = orig;
else
- j = __objc_xmalloc (sizeof (struct objc_selector));
+ j = objc_malloc (sizeof (struct objc_selector));
j->sel_id = (void*)i;
- j->sel_types = (const char*)types;
+ /* Can we use the pointer or must copy types? Don't copy if NULL */
+ if ((is_const) || (types == 0))
+ j->sel_types = (const char*)types;
+ else {
+ j->sel_types = (char *) objc_malloc(strlen(types)+1);
+ strcpy((char *)j->sel_types, types);
+ }
l = 0;
}
@@ -295,11 +406,21 @@ __sel_register_typed_name (const char *name, const char *types,
{
int is_new = (l == 0);
+ const char *new_name;
+
+ /* Can we use the pointer or must copy name? Don't copy if NULL */
+ if ((is_const) || (name == 0))
+ new_name = name;
+ else {
+ new_name = (char *) objc_malloc(strlen(name)+1);
+ strcpy((char *)new_name, name);
+ }
+
l = list_cons ((void*)j, l);
- sarray_at_put_safe (__objc_selector_names, i, (void *) name);
+ sarray_at_put_safe (__objc_selector_names, i, (void *) new_name);
sarray_at_put_safe (__objc_selector_array, i, (void *) l);
if (is_new)
- hash_add (&__objc_selector_hash, (void *) name, (void *) i);
+ hash_add (&__objc_selector_hash, (void *) new_name, (void *) i);
}
sarray_realloc(__objc_uninstalled_dtable, __objc_selector_max_index+1);
@@ -310,12 +431,28 @@ __sel_register_typed_name (const char *name, const char *types,
SEL
sel_register_name (const char *name)
{
- return __sel_register_typed_name (name, 0, 0);
+ SEL ret;
+
+ objc_mutex_lock(__objc_runtime_mutex);
+ /* Assume that name is not constant static memory and needs to be
+ copied before put into a runtime structure. is_const == NO */
+ ret = __sel_register_typed_name (name, 0, 0, NO);
+ objc_mutex_unlock(__objc_runtime_mutex);
+
+ return ret;
}
SEL
sel_register_typed_name (const char *name, const char *type)
{
- return __sel_register_typed_name (name, type, 0);
+ SEL ret;
+
+ objc_mutex_lock(__objc_runtime_mutex);
+ /* Assume that name and type are not constant static memory and need to
+ be copied before put into a runtime structure. is_const == NO */
+ ret = __sel_register_typed_name (name, type, 0, NO);
+ objc_mutex_unlock(__objc_runtime_mutex);
+
+ return ret;
}
diff --git a/contrib/gcc/objc/sendmsg.c b/contrib/gcc/objc/sendmsg.c
index 79d4a6b..245b8b9 100644
--- a/contrib/gcc/objc/sendmsg.c
+++ b/contrib/gcc/objc/sendmsg.c
@@ -1,5 +1,5 @@
/* GNU Objective C Runtime message lookup
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
Contributed by Kresten Krab Thorup
This file is part of GNU CC.
@@ -28,19 +28,21 @@ Boston, MA 02111-1307, USA. */
#include "runtime.h"
#include "sarray.h"
#include "encoding.h"
+#include "runtime-info.h"
/* this is how we hack STRUCT_VALUE to be 1 or 0 */
#define gen_rtx(args...) 1
+#define gen_rtx_MEM(args...) 1
#define rtx int
-#if STRUCT_VALUE == 0
+#if !defined(STRUCT_VALUE) || STRUCT_VALUE == 0
#define INVISIBLE_STRUCT_RETURN 1
#else
#define INVISIBLE_STRUCT_RETURN 0
#endif
/* The uninstalled dispatch table */
-struct sarray* __objc_uninstalled_dtable = 0;
+struct sarray* __objc_uninstalled_dtable = 0; /* !T:MUTEX */
/* Send +initialize to class */
static void __objc_send_initialize(Class);
@@ -49,6 +51,14 @@ static void __objc_install_dispatch_table_for_class (Class);
/* Forward declare some functions */
static void __objc_init_install_dtable(id, SEL);
+
+/* Various forwarding functions that are used based upon the
+ return type for the selector.
+ __objc_block_forward for structures.
+ __objc_double_forward for floats/doubles.
+ __objc_word_forward for pointers or types that fit in registers.
+ */
+static double __objc_double_forward(id, SEL, ...);
static id __objc_word_forward(id, SEL, ...);
typedef struct { id many[8]; } __big;
#if INVISIBLE_STRUCT_RETURN
@@ -58,13 +68,26 @@ static id
#endif
__objc_block_forward(id, SEL, ...);
static Method_t search_for_method_in_hierarchy (Class class, SEL sel);
-static Method_t search_for_method_in_list(MethodList_t list, SEL op);
+Method_t search_for_method_in_list(MethodList_t list, SEL op);
id nil_method(id, SEL, ...);
-id
-nil_method(id receiver, SEL op, ...)
+/* Given a selector, return the proper forwarding implementation. */
+__inline__
+IMP
+__objc_get_forward_imp (SEL sel)
{
- return receiver;
+ const char *t = sel->sel_types;
+
+ if (t && (*t == '[' || *t == '(' || *t == '{')
+#ifdef OBJC_MAX_STRUCT_BY_VALUE
+ && objc_sizeof_type(t) > OBJC_MAX_STRUCT_BY_VALUE
+#endif
+ )
+ return (IMP)__objc_block_forward;
+ else if (t && (*t == 'f' || *t == 'd'))
+ return (IMP)__objc_double_forward;
+ else
+ return (IMP)__objc_word_forward;
}
/* Given a class and selector, return the selector's implementation. */
@@ -72,54 +95,84 @@ __inline__
IMP
get_imp (Class class, SEL sel)
{
- IMP impl;
- void* res = sarray_get (class->dtable, (size_t) sel->sel_id);
- if(res == __objc_init_install_dtable)
- {
- __objc_install_dispatch_table_for_class (class);
- res = sarray_get (class->dtable, (size_t) sel->sel_id);
- }
+ void* res = sarray_get_safe (class->dtable, (size_t) sel->sel_id);
if (res == 0)
{
- const char *t = sel->sel_types;
- if (t && (*t == '[' || *t == '(' || *t == '{'))
- res = (IMP)__objc_block_forward;
+ /* Not a valid method */
+ if(class->dtable == __objc_uninstalled_dtable)
+ {
+ /* The dispatch table needs to be installed. */
+ objc_mutex_lock(__objc_runtime_mutex);
+ __objc_install_dispatch_table_for_class (class);
+ objc_mutex_unlock(__objc_runtime_mutex);
+ /* Call ourselves with the installed dispatch table
+ and get the real method */
+ res = get_imp(class, sel);
+ }
else
- res = (IMP)__objc_word_forward;
+ {
+ /* The dispatch table has been installed so the
+ method just doesn't exist for the class.
+ Return the forwarding implementation. */
+ res = __objc_get_forward_imp(sel);
+ }
}
return res;
}
-__inline__ BOOL
+/* Query if an object can respond to a selector, returns YES if the
+object implements the selector otherwise NO. Does not check if the
+method can be forwarded. */
+__inline__
+BOOL
__objc_responds_to (id object, SEL sel)
{
- void* res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id);
- if(res == __objc_init_install_dtable)
+ void* res;
+
+ /* Install dispatch table if need be */
+ if (object->class_pointer->dtable == __objc_uninstalled_dtable)
{
+ objc_mutex_lock(__objc_runtime_mutex);
__objc_install_dispatch_table_for_class (object->class_pointer);
- res = sarray_get (object->class_pointer->dtable, (size_t) sel->sel_id);
+ objc_mutex_unlock(__objc_runtime_mutex);
}
+
+ /* Get the method from the dispatch table */
+ res = sarray_get_safe (object->class_pointer->dtable, (size_t) sel->sel_id);
return (res != 0);
}
/* This is the lookup function. All entries in the table are either a
- valid method *or* one of `__objc_missing_method' which calls
- forward:: etc, or `__objc_init_install_dtable' which installs the
- real dtable */
-__inline__ IMP
+ valid method *or* zero. If zero then either the dispatch table
+ needs to be installed or it doesn't exist and forwarding is attempted. */
+__inline__
+IMP
objc_msg_lookup(id receiver, SEL op)
{
IMP result;
if(receiver)
{
- result = sarray_get(receiver->class_pointer->dtable, (sidx)op->sel_id);
+ result = sarray_get_safe (receiver->class_pointer->dtable,
+ (sidx)op->sel_id);
if (result == 0)
{
- const char *t = op->sel_types;
- if (t && (*t == '[' || *t == '(' || *t == '{'))
- result = (IMP)__objc_block_forward;
+ /* Not a valid method */
+ if(receiver->class_pointer->dtable == __objc_uninstalled_dtable)
+ {
+ /* The dispatch table needs to be installed.
+ This happens on the very first method call to the class. */
+ __objc_init_install_dtable(receiver, op);
+
+ /* Get real method for this in newly installed dtable */
+ result = get_imp(receiver->class_pointer, op);
+ }
else
- result = (IMP)__objc_word_forward;
+ {
+ /* The dispatch table has been installed so the
+ method just doesn't exist for the class.
+ Attempt to forward the method. */
+ result = __objc_get_forward_imp(op);
+ }
}
return result;
}
@@ -150,27 +203,25 @@ objc_msg_sendv(id object, SEL op, arglist_t arg_frame)
method_get_sizeof_arguments (m));
}
-void __objc_init_dispatch_tables()
+void
+__objc_init_dispatch_tables()
{
__objc_uninstalled_dtable
- = sarray_new(200, __objc_init_install_dtable);
+ = sarray_new(200, 0);
}
-/* This one is a bit hairy. This function is installed in the
- premature dispatch table, and thus called once for each class,
- namely when the very first message is send to it. */
-
-static void __objc_init_install_dtable(id receiver, SEL op)
+/* This function is called by objc_msg_lookup when the
+ dispatch table needs to be installed; thus it is called once
+ for each class, namely when the very first message is sent to it. */
+static void
+__objc_init_install_dtable(id receiver, SEL op)
{
- __label__ already_initialized;
- IMP imp;
- void* args;
- void* result;
-
/* This may happen, if the programmer has taken the address of a
method before the dtable was initialized... too bad for him! */
if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
- goto already_initialized;
+ return;
+
+ objc_mutex_lock(__objc_runtime_mutex);
if(CLS_ISCLASS(receiver->class_pointer))
{
@@ -198,31 +249,21 @@ static void __objc_init_install_dtable(id receiver, SEL op)
else
CLS_SETINITIALIZED((Class)receiver);
}
-
-already_initialized:
-
- /* Get real method for this in newly installed dtable */
- imp = get_imp(receiver->class_pointer, op);
-
- args = __builtin_apply_args();
- result = __builtin_apply((apply_t)imp, args, 96);
- if (result)
- __builtin_return (result);
- else
- return;
-
+ objc_mutex_unlock(__objc_runtime_mutex);
}
/* Install dummy table for class which causes the first message to
that class (or instances hereof) to be initialized properly */
-void __objc_install_premature_dtable(Class class)
+void
+__objc_install_premature_dtable(Class class)
{
assert(__objc_uninstalled_dtable);
class->dtable = __objc_uninstalled_dtable;
}
/* Send +initialize to class if not already done */
-static void __objc_send_initialize(Class class)
+static void
+__objc_send_initialize(Class class)
{
/* This *must* be a class object */
assert(CLS_ISCLASS(class));
@@ -250,7 +291,8 @@ static void __objc_send_initialize(Class class)
for (i=0;i<method_list->method_count;i++) {
method = &(method_list->method_list[i]);
- if (method->method_name->sel_id == op->sel_id) {
+ if (method->method_name
+ && method->method_name->sel_id == op->sel_id) {
imp = method->method_imp;
break;
}
@@ -267,16 +309,41 @@ static void __objc_send_initialize(Class class)
}
}
-}
+}
+
+/* Walk on the methods list of class and install the methods in the reverse
+ order of the lists. Since methods added by categories are before the methods
+ of class in the methods list, this allows categories to substitute methods
+ declared in class. However if more than one category replaces the same
+ method nothing is guaranteed about what method will be used.
+ Assumes that __objc_runtime_mutex is locked down. */
+static void
+__objc_install_methods_in_dtable (Class class, MethodList_t method_list)
+{
+ int i;
+
+ if (!method_list)
+ return;
+
+ if (method_list->method_next)
+ __objc_install_methods_in_dtable (class, method_list->method_next);
+
+ for (i = 0; i < method_list->method_count; i++)
+ {
+ Method_t method = &(method_list->method_list[i]);
+ sarray_at_put_safe (class->dtable,
+ (sidx) method->method_name->sel_id,
+ method->method_imp);
+ }
+}
+/* Assumes that __objc_runtime_mutex is locked down. */
static void
__objc_install_dispatch_table_for_class (Class class)
{
Class super;
- MethodList_t mlist;
- int counter;
- /* If the class has not yet had it's class links resolved, we must
+ /* If the class has not yet had its class links resolved, we must
re-compute all class links */
if(!CLS_ISRESOLV(class))
__objc_resolve_class_links();
@@ -289,47 +356,46 @@ __objc_install_dispatch_table_for_class (Class class)
/* Allocate dtable if necessary */
if (super == 0)
{
+ objc_mutex_lock(__objc_runtime_mutex);
class->dtable = sarray_new (__objc_selector_max_index, 0);
+ objc_mutex_unlock(__objc_runtime_mutex);
}
else
class->dtable = sarray_lazy_copy (super->dtable);
- for (mlist = class->methods; mlist; mlist = mlist->method_next)
- {
- counter = mlist->method_count - 1;
- while (counter >= 0)
- {
- Method_t method = &(mlist->method_list[counter]);
- sarray_at_put_safe (class->dtable,
- (sidx) method->method_name->sel_id,
- method->method_imp);
- counter -= 1;
- }
- }
+ __objc_install_methods_in_dtable (class, class->methods);
}
-void __objc_update_dispatch_table_for_class (Class class)
+void
+__objc_update_dispatch_table_for_class (Class class)
{
Class next;
+ struct sarray *arr;
/* not yet installed -- skip it */
if (class->dtable == __objc_uninstalled_dtable)
return;
- sarray_free (class->dtable); /* release memory */
+ objc_mutex_lock(__objc_runtime_mutex);
+
+ arr = class->dtable;
__objc_install_premature_dtable (class); /* someone might require it... */
- __objc_install_dispatch_table_for_class (class); /* could have been lazy... */
+ sarray_free (arr); /* release memory */
+
+ /* could have been lazy... */
+ __objc_install_dispatch_table_for_class (class);
if (class->subclass_list) /* Traverse subclasses */
for (next = class->subclass_list; next; next = next->sibling_class)
__objc_update_dispatch_table_for_class (next);
+ objc_mutex_unlock(__objc_runtime_mutex);
}
/* This function adds a method list to a class. This function is
typically called by another function specific to the run-time. As
- such this function does not worry about thread safe issued.
+ such this function does not worry about thread safe issues.
This one is only called for categories. Class objects have their
methods installed right away, and their selectors are made into
@@ -338,9 +404,6 @@ void
class_add_method_list (Class class, MethodList_t list)
{
int i;
- static SEL initialize_sel = 0;
- if (!initialize_sel)
- initialize_sel = sel_register_name ("initialize");
/* Passing of a linked list is not allowed. Do multiple calls. */
assert (!list->method_next);
@@ -356,24 +419,16 @@ class_add_method_list (Class class, MethodList_t list)
method->method_name =
sel_register_typed_name ((const char*)method->method_name,
method->method_types);
-
- if (search_for_method_in_list (class->methods, method->method_name)
- && method->method_name->sel_id != initialize_sel->sel_id)
- {
- /* Duplication. Print a error message an change the method name
- to NULL. */
- fprintf (stderr, "attempt to add a existing method: %s\n",
- sel_get_name(method->method_name));
- method->method_name = 0;
- }
}
}
/* Add the methods to the class's method list. */
list->method_next = class->methods;
class->methods = list;
-}
+ /* Update the dispatch table of class */
+ __objc_update_dispatch_table_for_class (class);
+}
Method_t
class_get_instance_method(Class class, SEL op)
@@ -414,7 +469,7 @@ search_for_method_in_hierarchy (Class cls, SEL sel)
/* Given a linked list of method and a method's name. Search for the named
method's method structure. Return a pointer to the method's method
structure if found. NULL otherwise. */
-static Method_t
+Method_t
search_for_method_in_list (MethodList_t list, SEL op)
{
MethodList_t method_list = list;
@@ -447,6 +502,7 @@ search_for_method_in_list (MethodList_t list, SEL op)
static retval_t __objc_forward (id object, SEL sel, arglist_t args);
+/* Forwarding pointers/integers through the normal registers */
static id
__objc_word_forward (id rcv, SEL op, ...)
{
@@ -460,6 +516,21 @@ __objc_word_forward (id rcv, SEL op, ...)
return res;
}
+/* Specific routine for forwarding floats/double because of
+ architectural differences on some processors. i386s for
+ example which uses a floating point stack versus general
+ registers for floating point numbers. This forward routine
+ makes sure that GCC restores the proper return values */
+static double
+__objc_double_forward (id rcv, SEL op, ...)
+{
+ void *args, *res;
+
+ args = __builtin_apply_args ();
+ res = __objc_forward (rcv, op, args);
+ __builtin_return (res);
+}
+
#if INVISIBLE_STRUCT_RETURN
static __big
#else
@@ -473,6 +544,12 @@ __objc_block_forward (id rcv, SEL op, ...)
res = __objc_forward (rcv, op, args);
if (res)
__builtin_return (res);
+ else
+#if INVISIBLE_STRUCT_RETURN
+ return (__big) {{0, 0, 0, 0, 0, 0, 0, 0}};
+#else
+ return nil;
+#endif
}
@@ -482,7 +559,7 @@ static retval_t
__objc_forward (id object, SEL sel, arglist_t args)
{
IMP imp;
- static SEL frwd_sel = 0;
+ static SEL frwd_sel = 0; /* !T:SAFE2 */
SEL err_sel;
/* first try if the object understands forward:: */
@@ -526,14 +603,19 @@ __objc_forward (id object, SEL sel, arglist_t args)
/* The object doesn't respond to doesNotRecognize: or error:; Therefore,
a default action is taken. */
- fprintf (stderr, "fatal: %s\n", msg);
- abort ();
+ objc_error (object, OBJC_ERR_UNIMPLEMENTED, "%s\n", msg);
+
+ return 0;
}
}
-void __objc_print_dtable_stats()
+void
+__objc_print_dtable_stats()
{
int total = 0;
+
+ objc_mutex_lock(__objc_runtime_mutex);
+
printf("memory usage: (%s)\n",
#ifdef OBJC_SPARSE2
"2-level sparse arrays"
@@ -542,17 +624,28 @@ void __objc_print_dtable_stats()
#endif
);
- printf("arrays: %d = %ld bytes\n", narrays, (int)narrays*sizeof(struct sarray));
+ printf("arrays: %d = %ld bytes\n", narrays,
+ (long)narrays*sizeof(struct sarray));
total += narrays*sizeof(struct sarray);
- printf("buckets: %d = %ld bytes\n", nbuckets, (int)nbuckets*sizeof(struct sbucket));
+ printf("buckets: %d = %ld bytes\n", nbuckets,
+ (long)nbuckets*sizeof(struct sbucket));
total += nbuckets*sizeof(struct sbucket);
- printf("idxtables: %d = %ld bytes\n", idxsize, (int)idxsize*sizeof(void*));
+ printf("idxtables: %d = %ld bytes\n", idxsize, (long)idxsize*sizeof(void*));
total += idxsize*sizeof(void*);
printf("-----------------------------------\n");
printf("total: %d bytes\n", total);
printf("===================================\n");
-}
-
+ objc_mutex_unlock(__objc_runtime_mutex);
+}
+/* Returns the uninstalled dispatch table indicator.
+ If a class' dispatch table points to __objc_uninstalled_dtable
+ then that means it needs its dispatch table to be installed. */
+__inline__
+struct sarray*
+objc_get_uninstalled_dtable()
+{
+ return __objc_uninstalled_dtable;
+}
diff --git a/contrib/gcc/objc/typedstream.h b/contrib/gcc/objc/typedstream.h
index 50bd654..eb4642f 100644
--- a/contrib/gcc/objc/typedstream.h
+++ b/contrib/gcc/objc/typedstream.h
@@ -10,7 +10,7 @@ later version.
GNU CC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+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
diff --git a/contrib/gcc/obstack.c b/contrib/gcc/obstack.c
index 3853c8c..bc318b3 100644
--- a/contrib/gcc/obstack.c
+++ b/contrib/gcc/obstack.c
@@ -1,19 +1,28 @@
/* obstack.c - subroutines used implicitly by object stack macros
- Copyright (C) 1988, 89, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Copyright (C) 1988,89,90,91,92,93,94,96,97 Free Software Foundation, Inc.
-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, 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.
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@gnu.org.
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ 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, 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. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
#include "obstack.h"
@@ -52,7 +61,7 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Determine default alignment. */
struct fooalign {char x; double d;};
#define DEFAULT_ALIGNMENT \
- ((PTR_INT_TYPE) ((char *)&((struct fooalign *) 0)->d - (char *)0))
+ ((PTR_INT_TYPE) ((char *) &((struct fooalign *) 0)->d - (char *) 0))
/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
But in fact it might be less smart and round addresses to as much as
DEFAULT_ROUNDING. So we prepare for it to do that. */
@@ -67,6 +76,28 @@ union fooround {long x; double d;};
#define COPYING_UNIT int
#endif
+
+/* The functions allocating more room by calling `obstack_chunk_alloc'
+ jump to the handler pointed to by `obstack_alloc_failed_handler'.
+ This variable by default points to the internal function
+ `print_and_abort'. */
+#if defined (__STDC__) && __STDC__
+static void print_and_abort (void);
+void (*obstack_alloc_failed_handler) (void) = print_and_abort;
+#else
+static void print_and_abort ();
+void (*obstack_alloc_failed_handler) () = print_and_abort;
+#endif
+
+/* Exit value used when `print_and_abort' is used. */
+#if defined __GNU_LIBRARY__ || defined HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+int obstack_exit_failure = EXIT_FAILURE;
+
/* The non-GNU-C macros copy the obstack into this global variable
to avoid multiple evaluation. */
@@ -78,18 +109,33 @@ struct obstack *_obstack;
For free, do not use ?:, since some compilers, like the MIPS compilers,
do not allow (expr) ? void : void. */
+#if defined (__STDC__) && __STDC__
#define CALL_CHUNKFUN(h, size) \
(((h) -> use_extra_arg) \
? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
- : (*(h)->chunkfun) ((size)))
+ : (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size)))
#define CALL_FREEFUN(h, old_chunk) \
do { \
if ((h) -> use_extra_arg) \
(*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
else \
- (*(h)->freefun) ((old_chunk)); \
+ (*(void (*) (void *)) (h)->freefun) ((old_chunk)); \
} while (0)
+#else
+#define CALL_CHUNKFUN(h, size) \
+ (((h) -> use_extra_arg) \
+ ? (*(h)->chunkfun) ((h)->extra_arg, (size)) \
+ : (*(struct _obstack_chunk *(*) ()) (h)->chunkfun) ((size)))
+
+#define CALL_FREEFUN(h, old_chunk) \
+ do { \
+ if ((h) -> use_extra_arg) \
+ (*(h)->freefun) ((h)->extra_arg, (old_chunk)); \
+ else \
+ (*(void (*) ()) (h)->freefun) ((old_chunk)); \
+ } while (0)
+#endif
/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default).
@@ -106,13 +152,18 @@ _obstack_begin (h, size, alignment, chunkfun, freefun)
struct obstack *h;
int size;
int alignment;
+#if defined (__STDC__) && __STDC__
+ POINTER (*chunkfun) (long);
+ void (*freefun) (void *);
+#else
POINTER (*chunkfun) ();
void (*freefun) ();
+#endif
{
- register struct _obstack_chunk* chunk; /* points to new chunk */
+ register struct _obstack_chunk *chunk; /* points to new chunk */
if (alignment == 0)
- alignment = DEFAULT_ALIGNMENT;
+ alignment = (int) DEFAULT_ALIGNMENT;
if (size == 0)
/* Default size is what GNU malloc can fit in a 4096-byte block. */
{
@@ -130,25 +181,27 @@ _obstack_begin (h, size, alignment, chunkfun, freefun)
size = 4096 - extra;
}
+#if defined (__STDC__) && __STDC__
+ h->chunkfun = (struct _obstack_chunk * (*)(void *, long)) chunkfun;
+ h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+#else
h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
h->freefun = freefun;
+#endif
h->chunk_size = size;
h->alignment_mask = alignment - 1;
h->use_extra_arg = 0;
chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
if (!chunk)
- {
- h->alloc_failed = 1;
- return 0;
- }
- h->alloc_failed = 0;
+ (*obstack_alloc_failed_handler) ();
h->next_free = h->object_base = chunk->contents;
h->chunk_limit = chunk->limit
= (char *) chunk + h->chunk_size;
chunk->prev = 0;
/* The initial chunk now contains no empty object. */
h->maybe_empty_object = 0;
+ h->alloc_failed = 0;
return 1;
}
@@ -157,14 +210,19 @@ _obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg)
struct obstack *h;
int size;
int alignment;
+#if defined (__STDC__) && __STDC__
+ POINTER (*chunkfun) (POINTER, long);
+ void (*freefun) (POINTER, POINTER);
+#else
POINTER (*chunkfun) ();
void (*freefun) ();
+#endif
POINTER arg;
{
- register struct _obstack_chunk* chunk; /* points to new chunk */
+ register struct _obstack_chunk *chunk; /* points to new chunk */
if (alignment == 0)
- alignment = DEFAULT_ALIGNMENT;
+ alignment = (int) DEFAULT_ALIGNMENT;
if (size == 0)
/* Default size is what GNU malloc can fit in a 4096-byte block. */
{
@@ -182,8 +240,13 @@ _obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg)
size = 4096 - extra;
}
+#if defined(__STDC__) && __STDC__
+ h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun;
+ h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+#else
h->chunkfun = (struct _obstack_chunk * (*)()) chunkfun;
h->freefun = freefun;
+#endif
h->chunk_size = size;
h->alignment_mask = alignment - 1;
h->extra_arg = arg;
@@ -191,17 +254,14 @@ _obstack_begin_1 (h, size, alignment, chunkfun, freefun, arg)
chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
if (!chunk)
- {
- h->alloc_failed = 1;
- return 0;
- }
- h->alloc_failed = 0;
+ (*obstack_alloc_failed_handler) ();
h->next_free = h->object_base = chunk->contents;
h->chunk_limit = chunk->limit
= (char *) chunk + h->chunk_size;
chunk->prev = 0;
/* The initial chunk now contains no empty object. */
h->maybe_empty_object = 0;
+ h->alloc_failed = 0;
return 1;
}
@@ -216,12 +276,12 @@ _obstack_newchunk (h, length)
struct obstack *h;
int length;
{
- register struct _obstack_chunk* old_chunk = h->chunk;
- register struct _obstack_chunk* new_chunk;
+ register struct _obstack_chunk *old_chunk = h->chunk;
+ register struct _obstack_chunk *new_chunk;
register long new_size;
- register int obj_size = h->next_free - h->object_base;
- register int i;
- int already;
+ register long obj_size = h->next_free - h->object_base;
+ register long i;
+ long already;
/* Compute size for new chunk. */
new_size = (obj_size + length) + (obj_size >> 3) + 100;
@@ -231,11 +291,7 @@ _obstack_newchunk (h, length)
/* Allocate and initialize the new chunk. */
new_chunk = CALL_CHUNKFUN (h, new_size);
if (!new_chunk)
- {
- h->alloc_failed = 1;
- return;
- }
- h->alloc_failed = 0;
+ (*obstack_alloc_failed_handler) ();
h->chunk = new_chunk;
new_chunk->prev = old_chunk;
new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
@@ -290,14 +346,14 @@ _obstack_allocated_p (h, obj)
struct obstack *h;
POINTER obj;
{
- register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
- register struct _obstack_chunk* plp; /* point to previous chunk if any */
+ register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk *plp; /* point to previous chunk if any */
lp = (h)->chunk;
/* We use >= rather than > since the object cannot be exactly at
the beginning of the chunk but might be an empty object exactly
- at the end of an adjacent chunk. */
- while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ at the end of an adjacent chunk. */
+ while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj))
{
plp = lp->prev;
lp = plp;
@@ -318,14 +374,14 @@ _obstack_free (h, obj)
struct obstack *h;
POINTER obj;
{
- register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
- register struct _obstack_chunk* plp; /* point to previous chunk if any */
+ register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk *plp; /* point to previous chunk if any */
lp = h->chunk;
/* We use >= because there cannot be an object at the beginning of a chunk.
But there can be an empty object at that address
at the end of another chunk. */
- while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj))
{
plp = lp->prev;
CALL_FREEFUN (h, lp);
@@ -336,7 +392,7 @@ _obstack_free (h, obj)
}
if (lp)
{
- h->object_base = h->next_free = (char *)(obj);
+ h->object_base = h->next_free = (char *) (obj);
h->chunk_limit = lp->limit;
h->chunk = lp;
}
@@ -352,14 +408,14 @@ obstack_free (h, obj)
struct obstack *h;
POINTER obj;
{
- register struct _obstack_chunk* lp; /* below addr of any objects in this chunk */
- register struct _obstack_chunk* plp; /* point to previous chunk if any */
+ register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */
+ register struct _obstack_chunk *plp; /* point to previous chunk if any */
lp = h->chunk;
/* We use >= because there cannot be an object at the beginning of a chunk.
But there can be an empty object at that address
at the end of another chunk. */
- while (lp != 0 && ((POINTER)lp >= obj || (POINTER)(lp)->limit < obj))
+ while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj))
{
plp = lp->prev;
CALL_FREEFUN (h, lp);
@@ -370,7 +426,7 @@ obstack_free (h, obj)
}
if (lp)
{
- h->object_base = h->next_free = (char *)(obj);
+ h->object_base = h->next_free = (char *) (obj);
h->chunk_limit = lp->limit;
h->chunk = lp;
}
@@ -379,6 +435,39 @@ obstack_free (h, obj)
abort ();
}
+int
+_obstack_memory_used (h)
+ struct obstack *h;
+{
+ register struct _obstack_chunk* lp;
+ register int nbytes = 0;
+
+ for (lp = h->chunk; lp != 0; lp = lp->prev)
+ {
+ nbytes += lp->limit - (char *) lp;
+ }
+ return nbytes;
+}
+
+/* Define the error handler. */
+#ifndef _
+# ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# ifndef _
+# define _(Str) gettext (Str)
+# endif
+# else
+# define _(Str) (Str)
+# endif
+#endif
+
+static void
+print_and_abort ()
+{
+ fputs (_("memory exhausted\n"), stderr);
+ exit (obstack_exit_failure);
+}
+
#if 0
/* These are now turned off because the applications do not use it
and it uses bcopy via obstack_grow, which causes trouble on sysV. */
@@ -417,6 +506,13 @@ int (obstack_room) (obstack)
return obstack_room (obstack);
}
+int (obstack_make_room) (obstack, length)
+ struct obstack *obstack;
+ int length;
+{
+ return obstack_make_room (obstack, length);
+}
+
void (obstack_grow) (obstack, pointer, length)
struct obstack *obstack;
POINTER pointer;
diff --git a/contrib/gcc/obstack.h b/contrib/gcc/obstack.h
index 28bcd44..38e9677 100644
--- a/contrib/gcc/obstack.h
+++ b/contrib/gcc/obstack.h
@@ -1,19 +1,24 @@
/* obstack.h - object stack macros
- Copyright (C) 1988, 89, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+ Copyright (C) 1988,89,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.
-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, 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.
+ NOTE: The canonical source of this file is maintained with the GNU C Library.
+ Bugs can be reported to bug-glibc@gnu.org.
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ 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, 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. */
/* Summary:
@@ -100,42 +105,51 @@ Summary:
/* Don't do the contents of this file more than once. */
-#ifndef __OBSTACK_H__
-#define __OBSTACK_H__
+#ifndef _OBSTACK_H
+#define _OBSTACK_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
-/* We use subtraction of (char *)0 instead of casting to int
+/* We use subtraction of (char *) 0 instead of casting to int
because on word-addressable machines a simple cast to int
may ignore the byte-within-word field of the pointer. */
#ifndef __PTR_TO_INT
-#define __PTR_TO_INT(P) ((P) - (char *)0)
+# define __PTR_TO_INT(P) ((P) - (char *) 0)
#endif
#ifndef __INT_TO_PTR
-#define __INT_TO_PTR(P) ((P) + (char *)0)
+# define __INT_TO_PTR(P) ((P) + (char *) 0)
#endif
-/* We need the type of the resulting object. In ANSI C it is ptrdiff_t
- but in traditional C it is usually long. If we are in ANSI C and
- don't already have ptrdiff_t get it. */
-
-#if defined (__STDC__) && __STDC__ && ! defined (offsetof)
-#if defined (__GNUC__) && defined (IN_GCC)
-/* On Next machine, the system's stddef.h screws up if included
- after we have defined just ptrdiff_t, so include all of stddef.h.
- Otherwise, define just ptrdiff_t, which is all we need. */
-#ifndef __NeXT__
-#define __need_ptrdiff_t
-#endif
-#endif
+/* We need the type of the resulting object. If __PTRDIFF_TYPE__ is
+ defined, as with GNU C, use that; that way we don't pollute the
+ namespace with <stddef.h>'s symbols. Otherwise, if <stddef.h> is
+ available, include it and use ptrdiff_t. In traditional C, long is
+ the best that we can do. */
-#include <stddef.h>
+#ifdef __PTRDIFF_TYPE__
+# define PTR_INT_TYPE __PTRDIFF_TYPE__
+#else
+# ifdef HAVE_STDDEF_H
+# include <stddef.h>
+# define PTR_INT_TYPE ptrdiff_t
+# else
+# define PTR_INT_TYPE long
+# endif
#endif
-#if defined (__STDC__) && __STDC__
-#define PTR_INT_TYPE ptrdiff_t
+#if defined _LIBC || defined HAVE_STRING_H
+# include <string.h>
+# define _obstack_memcpy(To, From, N) memcpy ((To), (From), (N))
#else
-#define PTR_INT_TYPE long
+# ifdef memcpy
+# define _obstack_memcpy(To, From, N) memcpy ((To), (From), (N))
+# else
+# define _obstack_memcpy(To, From, N) bcopy ((From), (To), (N))
+# endif
#endif
struct _obstack_chunk /* Lives at front of each chunk. */
@@ -148,40 +162,54 @@ struct _obstack_chunk /* Lives at front of each chunk. */
struct obstack /* control current object in current chunk */
{
long chunk_size; /* preferred size to allocate chunks in */
- struct _obstack_chunk* chunk; /* address of current struct obstack_chunk */
+ struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */
char *object_base; /* address of object we are building */
char *next_free; /* where to add next char to current object */
char *chunk_limit; /* address of char after current chunk */
PTR_INT_TYPE temp; /* Temporary for some macros. */
int alignment_mask; /* Mask of alignment for each object. */
+#if defined __STDC__ && __STDC__
+ /* These prototypes vary based on `use_extra_arg', and we use
+ casts to the prototypeless function type in all assignments,
+ but having prototypes here quiets -Wstrict-prototypes. */
+ struct _obstack_chunk *(*chunkfun) (void *, long);
+ void (*freefun) (void *, struct _obstack_chunk *);
+ void *extra_arg; /* first arg for chunk alloc/dealloc funcs */
+#else
struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */
void (*freefun) (); /* User's function to free a chunk. */
char *extra_arg; /* first arg for chunk alloc/dealloc funcs */
+#endif
unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */
unsigned maybe_empty_object:1;/* There is a possibility that the current
chunk contains a zero-length object. This
prevents freeing the chunk if we allocate
a bigger chunk to replace it. */
- unsigned alloc_failed:1; /* chunk alloc func returned 0 */
+ unsigned alloc_failed:1; /* No longer used, as we now call the failed
+ handler on error, but retained for binary
+ compatibility. */
};
/* Declare the external functions we use; they are in obstack.c. */
-#if defined (__STDC__) && __STDC__
+#if defined __STDC__ && __STDC__
extern void _obstack_newchunk (struct obstack *, int);
extern void _obstack_free (struct obstack *, void *);
extern int _obstack_begin (struct obstack *, int, int,
- void *(*) (), void (*) ());
+ void *(*) (long), void (*) (void *));
extern int _obstack_begin_1 (struct obstack *, int, int,
- void *(*) (), void (*) (), void *);
+ void *(*) (void *, long),
+ void (*) (void *, void *), void *);
+extern int _obstack_memory_used (struct obstack *);
#else
extern void _obstack_newchunk ();
extern void _obstack_free ();
extern int _obstack_begin ();
extern int _obstack_begin_1 ();
+extern int _obstack_memory_used ();
#endif
-#if defined (__STDC__) && __STDC__
+#if defined __STDC__ && __STDC__
/* Do the function-declarations after the structs
but before defining the macros. */
@@ -209,6 +237,7 @@ void * obstack_finish (struct obstack *obstack);
int obstack_object_size (struct obstack *obstack);
int obstack_room (struct obstack *obstack);
+void obstack_make_room (struct obstack *obstack, int size);
void obstack_1grow_fast (struct obstack *obstack, int data_char);
void obstack_ptr_grow_fast (struct obstack *obstack, void *data);
void obstack_int_grow_fast (struct obstack *obstack, int data);
@@ -218,17 +247,30 @@ void * obstack_base (struct obstack *obstack);
void * obstack_next_free (struct obstack *obstack);
int obstack_alignment_mask (struct obstack *obstack);
int obstack_chunk_size (struct obstack *obstack);
+int obstack_memory_used (struct obstack *obstack);
#endif /* __STDC__ */
/* Non-ANSI C cannot really support alternative functions for these macros,
so we do not declare them. */
+
+/* Error handler called when `obstack_chunk_alloc' failed to allocate
+ more memory. This can be set to a user defined function. The
+ default action is to print a message and abort. */
+#if defined __STDC__ && __STDC__
+extern void (*obstack_alloc_failed_handler) (void);
+#else
+extern void (*obstack_alloc_failed_handler) ();
+#endif
+
+/* Exit value used when `print_and_abort' is used. */
+extern int obstack_exit_failure;
/* Pointer to beginning of object being allocated or to be allocated next.
Note that this might not be the final address of the object
because a new chunk might be needed to hold the final size. */
-#define obstack_base(h) ((h)->alloc_failed ? 0 : (h)->object_base)
+#define obstack_base(h) ((h)->object_base)
/* Size for allocating ordinary chunks. */
@@ -236,146 +278,181 @@ int obstack_chunk_size (struct obstack *obstack);
/* Pointer to next byte not yet allocated in current chunk. */
-#define obstack_next_free(h) ((h)->alloc_failed ? 0 : (h)->next_free)
+#define obstack_next_free(h) ((h)->next_free)
/* Mask specifying low bits that should be clear in address of an object. */
#define obstack_alignment_mask(h) ((h)->alignment_mask)
-#define obstack_init(h) \
+/* To prevent prototype warnings provide complete argument list in
+ standard C version. */
+#if defined __STDC__ && __STDC__
+
+# define obstack_init(h) \
+ _obstack_begin ((h), 0, 0, \
+ (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free)
+
+# define obstack_begin(h, size) \
+ _obstack_begin ((h), (size), 0, \
+ (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free)
+
+# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
+ _obstack_begin ((h), (size), (alignment), \
+ (void *(*) (long)) (chunkfun), (void (*) (void *)) (freefun))
+
+# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+ _obstack_begin_1 ((h), (size), (alignment), \
+ (void *(*) (void *, long)) (chunkfun), \
+ (void (*) (void *, void *)) (freefun), (arg))
+
+# define obstack_chunkfun(h, newchunkfun) \
+ ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun))
+
+# define obstack_freefun(h, newfreefun) \
+ ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
+
+#else
+
+# define obstack_init(h) \
_obstack_begin ((h), 0, 0, \
(void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
-#define obstack_begin(h, size) \
+# define obstack_begin(h, size) \
_obstack_begin ((h), (size), 0, \
(void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free)
-#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
+# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \
_obstack_begin ((h), (size), (alignment), \
(void *(*) ()) (chunkfun), (void (*) ()) (freefun))
-#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
_obstack_begin_1 ((h), (size), (alignment), \
(void *(*) ()) (chunkfun), (void (*) ()) (freefun), (arg))
-#define obstack_chunkfun(h, newchunkfun) \
+# define obstack_chunkfun(h, newchunkfun) \
((h) -> chunkfun = (struct _obstack_chunk *(*)()) (newchunkfun))
-#define obstack_freefun(h, newfreefun) \
+# define obstack_freefun(h, newfreefun) \
((h) -> freefun = (void (*)()) (newfreefun))
+#endif
+
#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar)
#define obstack_blank_fast(h,n) ((h)->next_free += (n))
+
+#define obstack_memory_used(h) _obstack_memory_used (h)
-#if defined (__GNUC__) && defined (__STDC__) && __STDC__
+#if defined __GNUC__ && defined __STDC__ && __STDC__
/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
does not implement __extension__. But that compiler doesn't define
__GNUC_MINOR__. */
-#if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
-#define __extension__
-#endif
+# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
+# define __extension__
+# endif
/* For GNU C, if not -traditional,
we can define these macros to compute all args only once
without using a global variable.
Also, we can avoid using the `temp' slot, to make faster code. */
-#define obstack_object_size(OBSTACK) \
+# define obstack_object_size(OBSTACK) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
- __o->alloc_failed ? 0 : \
(unsigned) (__o->next_free - __o->object_base); })
-#define obstack_room(OBSTACK) \
+# define obstack_room(OBSTACK) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
(unsigned) (__o->chunk_limit - __o->next_free); })
-#define obstack_grow(OBSTACK,where,length) \
+# define obstack_make_room(OBSTACK,length) \
+__extension__ \
+({ struct obstack *__o = (OBSTACK); \
+ int __len = (length); \
+ if (__o->chunk_limit - __o->next_free < __len) \
+ _obstack_newchunk (__o, __len); \
+ (void) 0; })
+
+# define obstack_empty_p(OBSTACK) \
+ __extension__ \
+ ({ struct obstack *__o = (OBSTACK); \
+ (__o->chunk->prev == 0 && __o->next_free - __o->chunk->contents == 0); })
+
+# define obstack_grow(OBSTACK,where,length) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
int __len = (length); \
if (__o->next_free + __len > __o->chunk_limit) \
_obstack_newchunk (__o, __len); \
- if (!__o->alloc_failed) \
- { \
- bcopy ((char *) (where), __o->next_free, __len); \
- __o->next_free += __len; \
- } \
+ _obstack_memcpy (__o->next_free, (char *) (where), __len); \
+ __o->next_free += __len; \
(void) 0; })
-#define obstack_grow0(OBSTACK,where,length) \
+# define obstack_grow0(OBSTACK,where,length) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
int __len = (length); \
if (__o->next_free + __len + 1 > __o->chunk_limit) \
_obstack_newchunk (__o, __len + 1); \
- if (!__o->alloc_failed) \
- { \
- bcopy ((char *) (where), __o->next_free, __len); \
- __o->next_free += __len; \
- *(__o->next_free)++ = 0; \
- } \
+ _obstack_memcpy (__o->next_free, (char *) (where), __len); \
+ __o->next_free += __len; \
+ *(__o->next_free)++ = 0; \
(void) 0; })
-#define obstack_1grow(OBSTACK,datum) \
+# define obstack_1grow(OBSTACK,datum) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
if (__o->next_free + 1 > __o->chunk_limit) \
_obstack_newchunk (__o, 1); \
- if (!__o->alloc_failed) \
- *(__o->next_free)++ = (datum); \
+ *(__o->next_free)++ = (datum); \
(void) 0; })
/* These assume that the obstack alignment is good enough for pointers or ints,
and that the data added so far to the current object
shares that much alignment. */
-
-#define obstack_ptr_grow(OBSTACK,datum) \
+
+# define obstack_ptr_grow(OBSTACK,datum) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
if (__o->next_free + sizeof (void *) > __o->chunk_limit) \
_obstack_newchunk (__o, sizeof (void *)); \
- if (!__o->alloc_failed) \
- *((void **)__o->next_free)++ = ((void *)datum); \
+ *((void **)__o->next_free)++ = ((void *)datum); \
(void) 0; })
-#define obstack_int_grow(OBSTACK,datum) \
+# define obstack_int_grow(OBSTACK,datum) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
if (__o->next_free + sizeof (int) > __o->chunk_limit) \
_obstack_newchunk (__o, sizeof (int)); \
- if (!__o->alloc_failed) \
- *((int *)__o->next_free)++ = ((int)datum); \
+ *((int *)__o->next_free)++ = ((int)datum); \
(void) 0; })
-#define obstack_ptr_grow_fast(h,aptr) (*((void **)(h)->next_free)++ = (void *)aptr)
-#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint)
+# define obstack_ptr_grow_fast(h,aptr) (*((void **) (h)->next_free)++ = (void *)aptr)
+# define obstack_int_grow_fast(h,aint) (*((int *) (h)->next_free)++ = (int) aint)
-#define obstack_blank(OBSTACK,length) \
+# define obstack_blank(OBSTACK,length) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
int __len = (length); \
if (__o->chunk_limit - __o->next_free < __len) \
_obstack_newchunk (__o, __len); \
- if (!__o->alloc_failed) \
- __o->next_free += __len; \
+ __o->next_free += __len; \
(void) 0; })
-#define obstack_alloc(OBSTACK,length) \
+# define obstack_alloc(OBSTACK,length) \
__extension__ \
({ struct obstack *__h = (OBSTACK); \
obstack_blank (__h, (length)); \
obstack_finish (__h); })
-#define obstack_copy(OBSTACK,where,length) \
+# define obstack_copy(OBSTACK,where,length) \
__extension__ \
({ struct obstack *__h = (OBSTACK); \
obstack_grow (__h, (where), (length)); \
obstack_finish (__h); })
-#define obstack_copy0(OBSTACK,where,length) \
+# define obstack_copy0(OBSTACK,where,length) \
__extension__ \
({ struct obstack *__h = (OBSTACK); \
obstack_grow0 (__h, (where), (length)); \
@@ -383,28 +460,23 @@ __extension__ \
/* The local variable is named __o1 to avoid a name conflict
when obstack_blank is called. */
-#define obstack_finish(OBSTACK) \
+# define obstack_finish(OBSTACK) \
__extension__ \
({ struct obstack *__o1 = (OBSTACK); \
void *value; \
- if (__o1->alloc_failed) \
- value = 0; \
- else \
- { \
- value = (void *) __o1->object_base; \
- if (__o1->next_free == value) \
- __o1->maybe_empty_object = 1; \
- __o1->next_free \
- = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\
- & ~ (__o1->alignment_mask)); \
- if (__o1->next_free - (char *)__o1->chunk \
- > __o1->chunk_limit - (char *)__o1->chunk) \
- __o1->next_free = __o1->chunk_limit; \
- __o1->object_base = __o1->next_free; \
- } \
+ value = (void *) __o1->object_base; \
+ if (__o1->next_free == value) \
+ __o1->maybe_empty_object = 1; \
+ __o1->next_free \
+ = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\
+ & ~ (__o1->alignment_mask)); \
+ if (__o1->next_free - (char *)__o1->chunk \
+ > __o1->chunk_limit - (char *)__o1->chunk) \
+ __o1->next_free = __o1->chunk_limit; \
+ __o1->object_base = __o1->next_free; \
value; })
-#define obstack_free(OBSTACK, OBJ) \
+# define obstack_free(OBSTACK, OBJ) \
__extension__ \
({ struct obstack *__o = (OBSTACK); \
void *__obj = (OBJ); \
@@ -414,103 +486,108 @@ __extension__ \
#else /* not __GNUC__ or not __STDC__ */
-#define obstack_object_size(h) \
- (unsigned) ((h)->alloc_failed ? 0 : (h)->next_free - (h)->object_base)
+# define obstack_object_size(h) \
+ (unsigned) ((h)->next_free - (h)->object_base)
-#define obstack_room(h) \
+# define obstack_room(h) \
(unsigned) ((h)->chunk_limit - (h)->next_free)
+# define obstack_empty_p(h) \
+ ((h)->chunk->prev == 0 && (h)->next_free - (h)->chunk->contents == 0)
+
/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
so that we can avoid having void expressions
in the arms of the conditional expression.
Casting the third operand to void was tried before,
but some compilers won't accept it. */
-#define obstack_grow(h,where,length) \
+# define obstack_make_room(h,length) \
+( (h)->temp = (length), \
+ (((h)->next_free + (h)->temp > (h)->chunk_limit) \
+ ? (_obstack_newchunk ((h), (h)->temp), 0) : 0))
+
+# define obstack_grow(h,where,length) \
( (h)->temp = (length), \
(((h)->next_free + (h)->temp > (h)->chunk_limit) \
? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
- ((h)->alloc_failed ? 0 : \
- (bcopy ((char *) (where), (h)->next_free, (h)->temp), \
- (h)->next_free += (h)->temp)))
+ _obstack_memcpy ((h)->next_free, (char *) (where), (h)->temp), \
+ (h)->next_free += (h)->temp)
-#define obstack_grow0(h,where,length) \
+# define obstack_grow0(h,where,length) \
( (h)->temp = (length), \
(((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \
? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \
- ((h)->alloc_failed ? 0 : \
- (bcopy ((char *) (where), (h)->next_free, (h)->temp), \
+ _obstack_memcpy ((h)->next_free, (char *) (where), (h)->temp), \
(h)->next_free += (h)->temp, \
- *((h)->next_free)++ = 0)))
+ *((h)->next_free)++ = 0)
-#define obstack_1grow(h,datum) \
+# define obstack_1grow(h,datum) \
( (((h)->next_free + 1 > (h)->chunk_limit) \
? (_obstack_newchunk ((h), 1), 0) : 0), \
- ((h)->alloc_failed ? 0 : \
- (*((h)->next_free)++ = (datum))))
+ (*((h)->next_free)++ = (datum)))
-#define obstack_ptr_grow(h,datum) \
+# define obstack_ptr_grow(h,datum) \
( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \
? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \
- ((h)->alloc_failed ? 0 : \
- (*((char **)(((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *)datum))))
+ (*((char **) (((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *) datum)))
-#define obstack_int_grow(h,datum) \
+# define obstack_int_grow(h,datum) \
( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \
? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \
- ((h)->alloc_failed ? 0 : \
- (*((int *)(((h)->next_free+=sizeof(int))-sizeof(int))) = ((int)datum))))
+ (*((int *) (((h)->next_free+=sizeof(int))-sizeof(int))) = ((int) datum)))
-#define obstack_ptr_grow_fast(h,aptr) (*((char **)(h)->next_free)++ = (char *)aptr)
-#define obstack_int_grow_fast(h,aint) (*((int *)(h)->next_free)++ = (int)aint)
+# define obstack_ptr_grow_fast(h,aptr) (*((char **) (h)->next_free)++ = (char *) aptr)
+# define obstack_int_grow_fast(h,aint) (*((int *) (h)->next_free)++ = (int) aint)
-#define obstack_blank(h,length) \
+# define obstack_blank(h,length) \
( (h)->temp = (length), \
(((h)->chunk_limit - (h)->next_free < (h)->temp) \
? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \
- ((h)->alloc_failed ? 0 : \
- ((h)->next_free += (h)->temp)))
+ ((h)->next_free += (h)->temp))
-#define obstack_alloc(h,length) \
+# define obstack_alloc(h,length) \
(obstack_blank ((h), (length)), obstack_finish ((h)))
-#define obstack_copy(h,where,length) \
+# define obstack_copy(h,where,length) \
(obstack_grow ((h), (where), (length)), obstack_finish ((h)))
-#define obstack_copy0(h,where,length) \
+# define obstack_copy0(h,where,length) \
(obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
-#define obstack_finish(h) \
-( (h)->alloc_failed ? 0 : \
- (((h)->next_free == (h)->object_base \
+# define obstack_finish(h) \
+( ((h)->next_free == (h)->object_base \
? (((h)->maybe_empty_object = 1), 0) \
: 0), \
(h)->temp = __PTR_TO_INT ((h)->object_base), \
(h)->next_free \
= __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \
& ~ ((h)->alignment_mask)), \
- (((h)->next_free - (char *)(h)->chunk \
- > (h)->chunk_limit - (char *)(h)->chunk) \
+ (((h)->next_free - (char *) (h)->chunk \
+ > (h)->chunk_limit - (char *) (h)->chunk) \
? ((h)->next_free = (h)->chunk_limit) : 0), \
(h)->object_base = (h)->next_free, \
- __INT_TO_PTR ((h)->temp)))
+ __INT_TO_PTR ((h)->temp))
-#if defined (__STDC__) && __STDC__
-#define obstack_free(h,obj) \
-( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
+# if defined __STDC__ && __STDC__
+# define obstack_free(h,obj) \
+( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \
(((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
? (int) ((h)->next_free = (h)->object_base \
= (h)->temp + (char *) (h)->chunk) \
: (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0)))
-#else
-#define obstack_free(h,obj) \
-( (h)->temp = (char *)(obj) - (char *) (h)->chunk, \
+# else
+# define obstack_free(h,obj) \
+( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \
(((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\
? (int) ((h)->next_free = (h)->object_base \
= (h)->temp + (char *) (h)->chunk) \
: (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0)))
-#endif
+# endif
#endif /* not __GNUC__ or not __STDC__ */
-#endif /* not __OBSTACK_H__ */
+#ifdef __cplusplus
+} /* C++ */
+#endif
+
+#endif /* obstack.h */
diff --git a/contrib/gcc/optabs.c b/contrib/gcc/optabs.c
index 2732ebe..4b31fe0 100644
--- a/contrib/gcc/optabs.c
+++ b/contrib/gcc/optabs.c
@@ -1,5 +1,5 @@
/* Expand the basic unary and binary arithmetic operations, for GNU compiler.
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,6 +20,7 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
@@ -29,7 +30,6 @@ Boston, MA 02111-1307, USA. */
#include "insn-config.h"
#include "recog.h"
#include "reload.h"
-#include <ctype.h>
/* Each optab contains info on how this target machine
can perform a particular operation
@@ -88,7 +88,7 @@ optab strlen_optab;
/* Tables of patterns for extending one integer mode to another. */
enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
-/* Tables of patterns for converting between fixed and floating point. */
+/* Tables of patterns for converting between fixed and floating point. */
enum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
enum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
enum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
@@ -118,6 +118,13 @@ rtx bcmp_libfunc;
rtx memset_libfunc;
rtx bzero_libfunc;
+rtx throw_libfunc;
+rtx sjthrow_libfunc;
+rtx sjpopnthrow_libfunc;
+rtx terminate_libfunc;
+rtx setjmp_libfunc;
+rtx longjmp_libfunc;
+
rtx eqhf2_libfunc;
rtx nehf2_libfunc;
rtx gthf2_libfunc;
@@ -201,6 +208,12 @@ rtx fixunstfsi_libfunc;
rtx fixunstfdi_libfunc;
rtx fixunstfti_libfunc;
+rtx chkr_check_addr_libfunc;
+rtx chkr_set_right_libfunc;
+rtx chkr_copy_bitmap_libfunc;
+rtx chkr_check_exec_libfunc;
+rtx chkr_check_str_libfunc;
+
/* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
gives the gen_function to make a branch to test that condition. */
@@ -233,7 +246,9 @@ static optab init_optab PROTO((enum rtx_code));
static void init_libfuncs PROTO((optab, int, int, char *, int));
static void init_integral_libfuncs PROTO((optab, char *, int));
static void init_floating_libfuncs PROTO((optab, char *, int));
-static void init_complex_libfuncs PROTO((optab, char *, int));
+#ifdef HAVE_conditional_trap
+static void init_traps PROTO((void));
+#endif
/* Add a REG_EQUAL note to the last insn in SEQ. TARGET is being set to
the result of operation CODE applied to OP0 (and OP1 if it is a binary
@@ -278,13 +293,13 @@ add_equal_note (seq, target, code, op0, op1)
return 0;
if (GET_RTX_CLASS (code) == '1')
- note = gen_rtx (code, GET_MODE (target), copy_rtx (op0));
+ note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0));
else
- note = gen_rtx (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));
+ note = gen_rtx_fmt_ee (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));
REG_NOTES (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1))
- = gen_rtx (EXPR_LIST, REG_EQUAL, note,
- REG_NOTES (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1)));
+ = gen_rtx_EXPR_LIST (REG_EQUAL, note,
+ REG_NOTES (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1)));
return 1;
}
@@ -315,13 +330,13 @@ widen_operand (op, mode, oldmode, unsignedp, no_extend)
/* If MODE is no wider than a single word, we return a paradoxical
SUBREG. */
if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
- return gen_rtx (SUBREG, mode, force_reg (GET_MODE (op), op), 0);
+ return gen_rtx_SUBREG (mode, force_reg (GET_MODE (op), op), 0);
/* Otherwise, get an object of MODE, clobber it, and set the low-order
part to OP. */
result = gen_reg_rtx (mode);
- emit_insn (gen_rtx (CLOBBER, VOIDmode, result));
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, result));
emit_move_insn (gen_lowpart (GET_MODE (op), result), op);
return result;
}
@@ -438,7 +453,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
temp = gen_reg_rtx (mode);
/* If it is a commutative operator and the modes would match
- if we would swap the operands, we can save the conversions. */
+ if we would swap the operands, we can save the conversions. */
if (commutative_op)
{
if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
@@ -615,7 +630,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
{
if (binoptab->code != UNKNOWN)
equiv_value
- = gen_rtx (binoptab->code, mode, copy_rtx (op0), copy_rtx (op1));
+ = gen_rtx_fmt_ee (binoptab->code, mode,
+ copy_rtx (op0), copy_rtx (op1));
else
equiv_value = 0;
@@ -734,7 +750,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (inter != 0)
{
if (binoptab->code != UNKNOWN)
- equiv_value = gen_rtx (binoptab->code, mode, op0, op1);
+ equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
else
equiv_value = 0;
@@ -848,7 +864,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (inter != 0)
{
if (binoptab->code != UNKNOWN)
- equiv_value = gen_rtx (binoptab->code, mode, op0, op1);
+ equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
else
equiv_value = 0;
@@ -897,7 +913,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
/* Indicate for flow that the entire target reg is being set. */
if (GET_CODE (target) == REG)
- emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
/* Do the actual arithmetic. */
for (i = 0; i < nwords; i++)
@@ -919,12 +935,11 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
{
/* Store carry from main add/subtract. */
carry_out = gen_reg_rtx (word_mode);
- carry_out = emit_store_flag (carry_out,
- binoptab == add_optab ? LTU : GTU,
- x, op0_piece,
- word_mode, 1, normalizep);
- if (carry_out == 0)
- break;
+ carry_out = emit_store_flag_force (carry_out,
+ (binoptab == add_optab
+ ? LTU : GTU),
+ x, op0_piece,
+ word_mode, 1, normalizep);
}
if (i > 0)
@@ -943,11 +958,11 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
{
/* THIS CODE HAS NOT BEEN TESTED. */
/* Get out carry from adding/subtracting carry in. */
- carry_tmp = emit_store_flag (carry_tmp,
- binoptab == add_optab
- ? LTU : GTU,
- x, carry_in,
- word_mode, 1, normalizep);
+ carry_tmp = emit_store_flag_force (carry_tmp,
+ binoptab == add_optab
+ ? LTU : GTU,
+ x, carry_in,
+ word_mode, 1, normalizep);
/* Logical-ior the two poss. carry together. */
carry_out = expand_binop (word_mode, ior_optab,
@@ -963,13 +978,17 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
{
- rtx temp = emit_move_insn (target, target);
-
- REG_NOTES (temp) = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (binoptab->code, mode,
- copy_rtx (xop0),
- copy_rtx (xop1)),
- REG_NOTES (temp));
+ if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ {
+ rtx temp = emit_move_insn (target, target);
+
+ REG_NOTES (temp)
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ gen_rtx_fmt_ee (binoptab->code, mode,
+ copy_rtx (xop0),
+ copy_rtx (xop1)),
+ REG_NOTES (temp));
+ }
return target;
}
else
@@ -1143,12 +1162,16 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (temp != 0)
{
- temp = emit_move_insn (product, product);
- REG_NOTES (temp) = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (MULT, mode, copy_rtx (op0),
- copy_rtx (op1)),
- REG_NOTES (temp));
-
+ if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ {
+ temp = emit_move_insn (product, product);
+ REG_NOTES (temp)
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ gen_rtx_fmt_ee (MULT, mode,
+ copy_rtx (op0),
+ copy_rtx (op1)),
+ REG_NOTES (temp));
+ }
return product;
}
}
@@ -1366,7 +1389,6 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
X/(a+ib) */
rtx divisor;
rtx real_t, imag_t;
- rtx lhs, rhs;
rtx temp1, temp2;
/* Don't fetch these from memory more than once. */
@@ -1482,7 +1504,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
{
if (binoptab->code != UNKNOWN)
equiv_value
- = gen_rtx (binoptab->code, mode, copy_rtx (op0), copy_rtx (op1));
+ = gen_rtx_fmt_ee (binoptab->code, mode,
+ copy_rtx (op0), copy_rtx (op1));
else
equiv_value = 0;
@@ -1499,7 +1522,6 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
&& (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
{
rtx insns;
- rtx funexp = binoptab->handlers[(int) mode].libfunc;
rtx op1x = op1;
enum machine_mode op1_mode = mode;
rtx value;
@@ -1529,7 +1551,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
target = gen_reg_rtx (mode);
emit_libcall_block (insns, target, value,
- gen_rtx (binoptab->code, mode, op0, op1));
+ gen_rtx_fmt_ee (binoptab->code, mode, op0, op1));
return target;
}
@@ -1673,7 +1695,7 @@ sign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)
[(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))].
Either TARG0 or TARG1 may be zero, but what that means is that
- that result is not actually wanted. We will generate it into
+ the result is not actually wanted. We will generate it into
a dummy pseudo-reg and discard it. They may not both be zero.
Returns 1 if this operation can be performed; 0 if not. */
@@ -1943,7 +1965,8 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
end_sequence ();
emit_no_conflict_block (insns, target, op0, NULL_RTX,
- gen_rtx (unoptab->code, mode, copy_rtx (op0)));
+ gen_rtx_fmt_e (unoptab->code, mode,
+ copy_rtx (op0)));
return target;
}
@@ -1987,7 +2010,8 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
end_sequence ();
emit_no_conflict_block (seq, target, op0, 0,
- gen_rtx (unoptab->code, mode, copy_rtx (op0)));
+ gen_rtx_fmt_e (unoptab->code, mode,
+ copy_rtx (op0)));
return target;
}
@@ -1995,7 +2019,6 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
if (unoptab->handlers[(int) mode].libfunc)
{
rtx insns;
- rtx funexp = unoptab->handlers[(int) mode].libfunc;
rtx value;
start_sequence ();
@@ -2009,7 +2032,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
target = gen_reg_rtx (mode);
emit_libcall_block (insns, target, value,
- gen_rtx (unoptab->code, mode, op0));
+ gen_rtx_fmt_e (unoptab->code, mode, op0));
return target;
}
@@ -2116,6 +2139,13 @@ expand_abs (mode, op0, target, unsignedp, safe)
}
/* If that does not win, use conditional jump and negate. */
+
+ /* It is safe to use the target if it is the same
+ as the source if this is also a pseudo register */
+ if (op0 == target && GET_CODE (op0) == REG
+ && REGNO (op0) >= FIRST_PSEUDO_REGISTER)
+ safe = 1;
+
op1 = gen_label_rtx ();
if (target == 0 || ! safe
|| GET_MODE (target) != mode
@@ -2298,7 +2328,6 @@ expand_complex_abs (mode, op0, target, unsignedp)
if (abs_optab->handlers[(int) mode].libfunc)
{
rtx insns;
- rtx funexp = abs_optab->handlers[(int) mode].libfunc;
rtx value;
start_sequence ();
@@ -2312,7 +2341,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
target = gen_reg_rtx (submode);
emit_libcall_block (insns, target, value,
- gen_rtx (abs_optab->code, mode, op0));
+ gen_rtx_fmt_e (abs_optab->code, mode, op0));
return target;
}
@@ -2374,7 +2403,10 @@ emit_unop_insn (icode, target, op0, code)
op0 = protect_from_queue (op0, 0);
- if (flag_force_mem)
+ /* Sign and zero extension from memory is often done specially on
+ RISC machines, so forcing into a register here can pessimize
+ code. */
+ if (flag_force_mem && code != SIGN_EXTEND && code != ZERO_EXTEND)
op0 = force_not_mem (op0);
/* Now, if insn does not accept our operands, put them into pseudos. */
@@ -2485,7 +2517,7 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
/* Now write the CLOBBER of the output, followed by the setting of each
of the words, followed by the final copy. */
if (target != op0 && target != op1)
- emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
for (insn = insns; insn; insn = next)
{
@@ -2493,12 +2525,12 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
add_insn (insn);
if (op1 && GET_CODE (op1) == REG)
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_NO_CONFLICT, op1,
- REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1,
+ REG_NOTES (insn));
if (op0 && GET_CODE (op0) == REG)
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_NO_CONFLICT, op0,
- REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0,
+ REG_NOTES (insn));
}
if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
@@ -2507,7 +2539,7 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
last = emit_move_insn (target, target);
if (equiv)
REG_NOTES (last)
- = gen_rtx (EXPR_LIST, REG_EQUAL, equiv, REG_NOTES (last));
+ = gen_rtx_EXPR_LIST (REG_EQUAL, equiv, REG_NOTES (last));
}
else
last = get_last_insn ();
@@ -2518,9 +2550,9 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
first = NEXT_INSN (prev);
/* Encapsulate the block so it gets manipulated as a unit. */
- REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last,
- REG_NOTES (first));
- REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first, REG_NOTES (last));
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
return last;
}
@@ -2603,8 +2635,10 @@ emit_libcall_block (insns, target, result, equiv)
}
last = emit_move_insn (target, result);
- REG_NOTES (last) = gen_rtx (EXPR_LIST,
- REG_EQUAL, copy_rtx (equiv), REG_NOTES (last));
+ if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
+ != CODE_FOR_nothing)
+ REG_NOTES (last) = gen_rtx_EXPR_LIST (REG_EQUAL, copy_rtx (equiv),
+ REG_NOTES (last));
if (prev == 0)
first = get_insns ();
@@ -2612,9 +2646,9 @@ emit_libcall_block (insns, target, result, equiv)
first = NEXT_INSN (prev);
/* Encapsulate the block so it gets manipulated as a unit. */
- REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last,
- REG_NOTES (first));
- REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first, REG_NOTES (last));
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
}
/* Generate code to store zero in X. */
@@ -2741,18 +2775,32 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
else
#endif
{
+ rtx result;
+
#ifdef TARGET_MEM_FUNCTIONS
emit_library_call (memcmp_libfunc, 0,
TYPE_MODE (integer_type_node), 3,
XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
- size, Pmode);
+ convert_to_mode (TYPE_MODE (sizetype), size,
+ TREE_UNSIGNED (sizetype)),
+ TYPE_MODE (sizetype));
#else
emit_library_call (bcmp_libfunc, 0,
TYPE_MODE (integer_type_node), 3,
XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
- size, Pmode);
+ convert_to_mode (TYPE_MODE (integer_type_node),
+ size,
+ TREE_UNSIGNED (integer_type_node)),
+ TYPE_MODE (integer_type_node));
#endif
- emit_cmp_insn (hard_libcall_value (TYPE_MODE (integer_type_node)),
+
+ /* Immediately move the result of the libcall into a pseudo
+ register so reload doesn't clobber the value if it needs
+ the return register for a spill reg. */
+ result = gen_reg_rtx (TYPE_MODE (integer_type_node));
+ emit_move_insn (result,
+ hard_libcall_value (TYPE_MODE (integer_type_node)));
+ emit_cmp_insn (result,
const0_rtx, comparison, NULL_RTX,
TYPE_MODE (integer_type_node), 0, 0);
}
@@ -2829,6 +2877,8 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
&& class != MODE_FLOAT)
{
rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
+ rtx result;
+
/* If we want unsigned, and this mode has a distinct unsigned
comparison routine, use that. */
if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
@@ -2837,11 +2887,16 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
emit_library_call (libfunc, 1,
word_mode, 2, x, mode, y, mode);
+ /* Immediately move the result of the libcall into a pseudo
+ register so reload doesn't clobber the value if it needs
+ the return register for a spill reg. */
+ result = gen_reg_rtx (word_mode);
+ emit_move_insn (result, hard_libcall_value (word_mode));
+
/* Integer comparison returns a result that must be compared against 1,
so that even if we do an unsigned compare afterward,
there is still a value that can represent the result "less than". */
-
- emit_cmp_insn (hard_libcall_value (word_mode), const1_rtx,
+ emit_cmp_insn (result, const1_rtx,
comparison, NULL_RTX, word_mode, unsignedp, 0);
return;
}
@@ -2880,6 +2935,7 @@ emit_float_lib_cmp (x, y, comparison)
{
enum machine_mode mode = GET_MODE (x);
rtx libfunc = 0;
+ rtx result;
if (mode == HFmode)
switch (comparison)
@@ -2907,6 +2963,9 @@ emit_float_lib_cmp (x, y, comparison)
case LE:
libfunc = lehf2_libfunc;
break;
+
+ default:
+ break;
}
else if (mode == SFmode)
switch (comparison)
@@ -2934,6 +2993,9 @@ emit_float_lib_cmp (x, y, comparison)
case LE:
libfunc = lesf2_libfunc;
break;
+
+ default:
+ break;
}
else if (mode == DFmode)
switch (comparison)
@@ -2961,6 +3023,9 @@ emit_float_lib_cmp (x, y, comparison)
case LE:
libfunc = ledf2_libfunc;
break;
+
+ default:
+ break;
}
else if (mode == XFmode)
switch (comparison)
@@ -2988,6 +3053,9 @@ emit_float_lib_cmp (x, y, comparison)
case LE:
libfunc = lexf2_libfunc;
break;
+
+ default:
+ break;
}
else if (mode == TFmode)
switch (comparison)
@@ -3015,6 +3083,9 @@ emit_float_lib_cmp (x, y, comparison)
case LE:
libfunc = letf2_libfunc;
break;
+
+ default:
+ break;
}
else
{
@@ -3044,7 +3115,13 @@ emit_float_lib_cmp (x, y, comparison)
emit_library_call (libfunc, 1,
word_mode, 2, x, mode, y, mode);
- emit_cmp_insn (hard_libcall_value (word_mode), const0_rtx, comparison,
+ /* Immediately move the result of the libcall into a pseudo
+ register so reload doesn't clobber the value if it needs
+ the return register for a spill reg. */
+ result = gen_reg_rtx (word_mode);
+ emit_move_insn (result, hard_libcall_value (word_mode));
+
+ emit_cmp_insn (result, const0_rtx, comparison,
NULL_RTX, word_mode, 0, 0);
}
@@ -3107,15 +3184,14 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
if (cmode == VOIDmode)
cmode = GET_MODE (op0);
- if ((CONSTANT_P (op2) && ! CONSTANT_P (op3))
- || (GET_CODE (op2) == CONST_INT && GET_CODE (op3) != CONST_INT))
+ if (((CONSTANT_P (op2) && ! CONSTANT_P (op3))
+ || (GET_CODE (op2) == CONST_INT && GET_CODE (op3) != CONST_INT))
+ && (GET_MODE_CLASS (GET_MODE (op1)) != MODE_FLOAT
+ || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT || flag_fast_math))
{
tem = op2;
op2 = op3;
op3 = tem;
- /* ??? This may not be appropriate (consider IEEE). Perhaps we should
- call can_reverse_comparison_p here and bail out if necessary.
- It's not clear whether we need to do this canonicalization though. */
code = reverse_condition (code);
}
@@ -3306,7 +3382,7 @@ gen_move_insn (x, y)
x = gen_lowpart_common (tmode, x1);
if (x == 0 && GET_CODE (x1) == MEM)
{
- x = gen_rtx (MEM, tmode, XEXP (x1, 0));
+ x = gen_rtx_MEM (tmode, XEXP (x1, 0));
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (x1);
MEM_IN_STRUCT_P (x) = MEM_IN_STRUCT_P (x1);
MEM_VOLATILE_P (x) = MEM_VOLATILE_P (x1);
@@ -3316,7 +3392,7 @@ gen_move_insn (x, y)
y = gen_lowpart_common (tmode, y1);
if (y == 0 && GET_CODE (y1) == MEM)
{
- y = gen_rtx (MEM, tmode, XEXP (y1, 0));
+ y = gen_rtx_MEM (tmode, XEXP (y1, 0));
RTX_UNCHANGING_P (y) = RTX_UNCHANGING_P (y1);
MEM_IN_STRUCT_P (y) = MEM_IN_STRUCT_P (y1);
MEM_VOLATILE_P (y) = MEM_VOLATILE_P (y1);
@@ -3487,7 +3563,7 @@ expand_float (to, from, unsignedp)
/* There is no such mode. Pretend the target is wide enough. */
fmode = GET_MODE (to);
- /* Avoid double-rounding when TO is narrower than FROM. */
+ /* Avoid double-rounding when TO is narrower than FROM. */
if ((significand_size (fmode) + 1)
< GET_MODE_BITSIZE (GET_MODE (from)))
{
@@ -3644,7 +3720,7 @@ expand_float (to, from, unsignedp)
end_sequence ();
emit_libcall_block (insns, target, value,
- gen_rtx (FLOAT, GET_MODE (to), from));
+ gen_rtx_FLOAT (GET_MODE (to), from));
}
done:
@@ -3785,13 +3861,18 @@ expand_fix (to, from, unsignedp)
emit_label (lab2);
- /* Make a place for a REG_NOTE and add it. */
- insn = emit_move_insn (to, to);
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL,
- gen_rtx (UNSIGNED_FIX, GET_MODE (to),
- copy_rtx (from)),
- REG_NOTES (insn));
-
+ if (mov_optab->handlers[(int) GET_MODE (to)].insn_code
+ != CODE_FOR_nothing)
+ {
+ /* Make a place for a REG_NOTE and add it. */
+ insn = emit_move_insn (to, to);
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ gen_rtx_fmt_e (UNSIGNED_FIX,
+ GET_MODE (to),
+ copy_rtx (from)),
+ REG_NOTES (insn));
+ }
return;
}
#endif
@@ -3873,14 +3954,17 @@ expand_fix (to, from, unsignedp)
end_sequence ();
emit_libcall_block (insns, target, value,
- gen_rtx (unsignedp ? UNSIGNED_FIX : FIX,
- GET_MODE (to), from));
+ gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
+ GET_MODE (to), from));
}
- if (GET_MODE (to) == GET_MODE (target))
- emit_move_insn (to, target);
- else
- convert_move (to, target, 0);
+ if (target != to)
+ {
+ if (GET_MODE (to) == GET_MODE (target))
+ emit_move_insn (to, target);
+ else
+ convert_move (to, target, 0);
+ }
}
static optab
@@ -3950,7 +4034,7 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
*p++ = suffix;
*p++ = '\0';
optable->handlers[(int) mode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, libfunc_name);
+ = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
}
}
@@ -3982,19 +4066,6 @@ init_floating_libfuncs (optable, opname, suffix)
init_libfuncs (optable, SFmode, TFmode, opname, suffix);
}
-/* Initialize the libfunc fields of an entire group of entries in some
- optab which correspond to all complex floating modes. The parameters
- have the same meaning as similarly named ones for the `init_libfuncs'
- routine. (See above). */
-
-static void
-init_complex_libfuncs (optable, opname, suffix)
- register optab optable;
- register char *opname;
- register int suffix;
-{
- init_libfuncs (optable, SCmode, TCmode, opname, suffix);
-}
/* Call this once to initialize the contents of the optabs
appropriately for the current target machine. */
@@ -4002,7 +4073,11 @@ init_complex_libfuncs (optable, opname, suffix)
void
init_optabs ()
{
- int i, j;
+ int i;
+#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
+ int j;
+#endif
+
enum insn_code *p;
/* Start by initializing all tables to contain CODE_FOR_nothing. */
@@ -4079,6 +4154,7 @@ init_optabs ()
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
movstr_optab[i] = CODE_FOR_nothing;
+ clrstr_optab[i] = CODE_FOR_nothing;
#ifdef HAVE_SECONDARY_RELOADS
reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
@@ -4139,162 +4215,185 @@ init_optabs ()
#ifdef MULSI3_LIBCALL
smul_optab->handlers[(int) SImode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, MULSI3_LIBCALL);
+ = gen_rtx_SYMBOL_REF (Pmode, MULSI3_LIBCALL);
#endif
#ifdef MULDI3_LIBCALL
smul_optab->handlers[(int) DImode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, MULDI3_LIBCALL);
+ = gen_rtx_SYMBOL_REF (Pmode, MULDI3_LIBCALL);
#endif
#ifdef DIVSI3_LIBCALL
sdiv_optab->handlers[(int) SImode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, DIVSI3_LIBCALL);
+ = gen_rtx_SYMBOL_REF (Pmode, DIVSI3_LIBCALL);
#endif
#ifdef DIVDI3_LIBCALL
sdiv_optab->handlers[(int) DImode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, DIVDI3_LIBCALL);
+ = gen_rtx_SYMBOL_REF (Pmode, DIVDI3_LIBCALL);
#endif
#ifdef UDIVSI3_LIBCALL
udiv_optab->handlers[(int) SImode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, UDIVSI3_LIBCALL);
+ = gen_rtx_SYMBOL_REF (Pmode, UDIVSI3_LIBCALL);
#endif
#ifdef UDIVDI3_LIBCALL
udiv_optab->handlers[(int) DImode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, UDIVDI3_LIBCALL);
+ = gen_rtx_SYMBOL_REF (Pmode, UDIVDI3_LIBCALL);
#endif
#ifdef MODSI3_LIBCALL
smod_optab->handlers[(int) SImode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, MODSI3_LIBCALL);
+ = gen_rtx_SYMBOL_REF (Pmode, MODSI3_LIBCALL);
#endif
#ifdef MODDI3_LIBCALL
smod_optab->handlers[(int) DImode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, MODDI3_LIBCALL);
+ = gen_rtx_SYMBOL_REF (Pmode, MODDI3_LIBCALL);
#endif
#ifdef UMODSI3_LIBCALL
umod_optab->handlers[(int) SImode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, UMODSI3_LIBCALL);
+ = gen_rtx_SYMBOL_REF (Pmode, UMODSI3_LIBCALL);
#endif
#ifdef UMODDI3_LIBCALL
umod_optab->handlers[(int) DImode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, UMODDI3_LIBCALL);
+ = gen_rtx_SYMBOL_REF (Pmode, UMODDI3_LIBCALL);
#endif
/* Use cabs for DC complex abs, since systems generally have cabs.
Don't define any libcall for SCmode, so that cabs will be used. */
abs_optab->handlers[(int) DCmode].libfunc
- = gen_rtx (SYMBOL_REF, Pmode, "cabs");
+ = gen_rtx_SYMBOL_REF (Pmode, "cabs");
/* The ffs function operates on `int'. */
#ifndef INT_TYPE_SIZE
#define INT_TYPE_SIZE BITS_PER_WORD
#endif
ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)] .libfunc
- = gen_rtx (SYMBOL_REF, Pmode, "ffs");
-
- extendsfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extendsfdf2");
- extendsfxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extendsfxf2");
- extendsftf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extendsftf2");
- extenddfxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extenddfxf2");
- extenddftf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extenddftf2");
-
- truncdfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncdfsf2");
- truncxfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncxfsf2");
- trunctfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__trunctfsf2");
- truncxfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncxfdf2");
- trunctfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__trunctfdf2");
-
- memcpy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcpy");
- bcopy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcopy");
- memcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcmp");
- bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gcc_bcmp");
- memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset");
- bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
-
- eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2");
- nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2");
- gthf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gthf2");
- gehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gehf2");
- lthf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lthf2");
- lehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lehf2");
-
- eqsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqsf2");
- nesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nesf2");
- gtsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtsf2");
- gesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gesf2");
- ltsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ltsf2");
- lesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lesf2");
-
- eqdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqdf2");
- nedf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nedf2");
- gtdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtdf2");
- gedf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gedf2");
- ltdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ltdf2");
- ledf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ledf2");
-
- eqxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqxf2");
- nexf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nexf2");
- gtxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtxf2");
- gexf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gexf2");
- ltxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ltxf2");
- lexf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lexf2");
-
- eqtf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqtf2");
- netf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__netf2");
- gttf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gttf2");
- getf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__getf2");
- lttf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lttf2");
- letf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__letf2");
-
- floatsisf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsisf");
- floatdisf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatdisf");
- floattisf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattisf");
-
- floatsidf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsidf");
- floatdidf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatdidf");
- floattidf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattidf");
-
- floatsixf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsixf");
- floatdixf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatdixf");
- floattixf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattixf");
-
- floatsitf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsitf");
- floatditf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatditf");
- floattitf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattitf");
-
- fixsfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixsfsi");
- fixsfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixsfdi");
- fixsfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixsfti");
-
- fixdfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixdfsi");
- fixdfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixdfdi");
- fixdfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixdfti");
-
- fixxfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixxfsi");
- fixxfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixxfdi");
- fixxfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixxfti");
-
- fixtfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixtfsi");
- fixtfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixtfdi");
- fixtfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixtfti");
-
- fixunssfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunssfsi");
- fixunssfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunssfdi");
- fixunssfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunssfti");
-
- fixunsdfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsdfsi");
- fixunsdfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsdfdi");
- fixunsdfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsdfti");
-
- fixunsxfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsxfsi");
- fixunsxfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsxfdi");
- fixunsxfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsxfti");
-
- fixunstfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfsi");
- fixunstfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfdi");
- fixunstfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfti");
+ = gen_rtx_SYMBOL_REF (Pmode, "ffs");
+
+ extendsfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsfdf2");
+ extendsfxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsfxf2");
+ extendsftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsftf2");
+ extenddfxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extenddfxf2");
+ extenddftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extenddftf2");
+
+ truncdfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncdfsf2");
+ truncxfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncxfsf2");
+ trunctfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__trunctfsf2");
+ truncxfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncxfdf2");
+ trunctfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__trunctfdf2");
+
+ memcpy_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memcpy");
+ bcopy_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bcopy");
+ memcmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memcmp");
+ bcmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gcc_bcmp");
+ memset_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memset");
+ bzero_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bzero");
+
+ throw_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__throw");
+ sjthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjthrow");
+ sjpopnthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjpopnthrow");
+ terminate_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__terminate");
+#ifndef DONT_USE_BUILTIN_SETJMP
+ setjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__builtin_setjmp");
+ longjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__builtin_longjmp");
+#else
+ setjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "setjmp");
+ longjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "longjmp");
+#endif
+
+ eqhf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqhf2");
+ nehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nehf2");
+ gthf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gthf2");
+ gehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gehf2");
+ lthf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lthf2");
+ lehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lehf2");
+
+ eqsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqsf2");
+ nesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nesf2");
+ gtsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtsf2");
+ gesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gesf2");
+ ltsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltsf2");
+ lesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lesf2");
+
+ eqdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqdf2");
+ nedf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nedf2");
+ gtdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtdf2");
+ gedf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gedf2");
+ ltdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltdf2");
+ ledf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ledf2");
+
+ eqxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqxf2");
+ nexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nexf2");
+ gtxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtxf2");
+ gexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gexf2");
+ ltxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltxf2");
+ lexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lexf2");
+
+ eqtf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqtf2");
+ netf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__netf2");
+ gttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gttf2");
+ getf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__getf2");
+ lttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lttf2");
+ letf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__letf2");
+
+ floatsisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsisf");
+ floatdisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdisf");
+ floattisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattisf");
+
+ floatsidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsidf");
+ floatdidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdidf");
+ floattidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattidf");
+
+ floatsixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsixf");
+ floatdixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdixf");
+ floattixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattixf");
+
+ floatsitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsitf");
+ floatditf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatditf");
+ floattitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattitf");
+
+ fixsfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfsi");
+ fixsfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfdi");
+ fixsfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfti");
+
+ fixdfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfsi");
+ fixdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfdi");
+ fixdfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfti");
+
+ fixxfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfsi");
+ fixxfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfdi");
+ fixxfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfti");
+
+ fixtfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfsi");
+ fixtfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfdi");
+ fixtfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfti");
+
+ fixunssfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfsi");
+ fixunssfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfdi");
+ fixunssfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfti");
+
+ fixunsdfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfsi");
+ fixunsdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfdi");
+ fixunsdfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfti");
+
+ fixunsxfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfsi");
+ fixunsxfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfdi");
+ fixunsxfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfti");
+
+ fixunstfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfsi");
+ fixunstfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfdi");
+ fixunstfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfti");
+
+ /* For check-memory-usage. */
+ chkr_check_addr_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_check_addr");
+ chkr_set_right_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_set_right");
+ chkr_copy_bitmap_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_copy_bitmap");
+ chkr_check_exec_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_check_exec");
+ chkr_check_str_libfunc = gen_rtx_SYMBOL_REF (VOIDmode, "chkr_check_str");
+
+#ifdef HAVE_conditional_trap
+ init_traps ();
+#endif
#ifdef INIT_TARGET_OPTABS
/* Allow the target to add more libcalls or rename some, etc. */
@@ -4304,7 +4403,7 @@ init_optabs ()
#ifdef BROKEN_LDEXP
-/* SCO 3.2 apparently has a broken ldexp. */
+/* SCO 3.2 apparently has a broken ldexp. */
double
ldexp(x,n)
@@ -4318,3 +4417,49 @@ ldexp(x,n)
return x;
}
#endif /* BROKEN_LDEXP */
+
+#ifdef HAVE_conditional_trap
+/* The insn generating function can not take an rtx_code argument.
+ TRAP_RTX is used as an rtx argument. Its code is replaced with
+ the code to be used in the trap insn and all other fields are
+ ignored.
+
+ ??? Will need to change to support garbage collection. */
+static rtx trap_rtx;
+
+static void
+init_traps ()
+{
+ if (HAVE_conditional_trap)
+ trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
+}
+#endif
+
+/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
+ CODE. Return 0 on failure. */
+
+rtx
+gen_cond_trap (code, op1, op2, tcode)
+ enum rtx_code code;
+ rtx op1, op2, tcode;
+{
+ enum machine_mode mode = GET_MODE (op1);
+
+ if (mode == VOIDmode)
+ return 0;
+
+#ifdef HAVE_conditional_trap
+ if (HAVE_conditional_trap
+ && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+ {
+ rtx insn;
+ emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
+ PUT_CODE (trap_rtx, code);
+ insn = gen_conditional_trap (trap_rtx, tcode);
+ if (insn)
+ return insn;
+ }
+#endif
+
+ return 0;
+}
diff --git a/contrib/gcc/output.h b/contrib/gcc/output.h
index 7ef8b2c..e2c9f4d 100644
--- a/contrib/gcc/output.h
+++ b/contrib/gcc/output.h
@@ -1,6 +1,6 @@
/* Declarations for insn-output.c. These functions are defined in recog.c,
final.c, and varasm.c.
- Copyright (C) 1987, 1991, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1991, 1994, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -56,20 +56,20 @@ extern void shorten_branches PROTO((rtx));
for the new function. The label for the function and associated
assembler pseudo-ops have already been output in
`assemble_start_function'. */
-extern void final_start_function STDIO_PROTO((rtx, FILE *, int));
+extern void final_start_function PROTO((rtx, FILE *, int));
/* Output assembler code for the end of a function.
For clarity, args are same as those of `final_start_function'
even though not all of them are needed. */
-extern void final_end_function STDIO_PROTO((rtx, FILE *, int));
+extern void final_end_function PROTO((rtx, FILE *, int));
/* Output assembler code for some insns: all or part of a function. */
-extern void final STDIO_PROTO((rtx, FILE *, int, int));
+extern void final PROTO((rtx, FILE *, int, int));
/* The final scan for one insn, INSN. Args are same as in `final', except
that INSN is the insn being scanned. Value returned is the next insn to
be scanned. */
-extern rtx final_scan_insn STDIO_PROTO((rtx, FILE *, int, int, int));
+extern rtx final_scan_insn PROTO((rtx, FILE *, int, int, int));
/* Replace a SUBREG with a REG or a MEM, based on the thing it is a
subreg of. */
@@ -83,6 +83,11 @@ extern void output_operand_lossage PROTO((char *));
Defined in final.c. */
extern void output_asm_insn PROTO((char *, rtx *));
+/* Compute a worst-case reference address of a branch so that it
+ can be safely used in the presence of aligned labels.
+ Defined in final.c. */
+extern int insn_current_reference_address PROTO((rtx));
+
/* Output a LABEL_REF, or a bare CODE_LABEL, as an assembler symbol. */
extern void output_asm_label PROTO((rtx));
@@ -93,12 +98,11 @@ extern void output_address PROTO((rtx));
/* Print an integer constant expression in assembler syntax.
Addition and subtraction are the only arithmetic
that may appear in these expressions. */
-extern void output_addr_const STDIO_PROTO((FILE *, rtx));
+extern void output_addr_const PROTO((FILE *, rtx));
/* Output a string of assembler code, substituting numbers, strings
and fixed syntactic prefixes. */
-extern void asm_fprintf STDIO_PROTO(PVPROTO((FILE *file,
- char *p, ...)));
+extern void asm_fprintf PROTO(PVPROTO((FILE *file, char *p, ...)));
/* Split up a CONST_DOUBLE or integer constant rtx into two rtx's for single
words. */
@@ -114,6 +118,16 @@ extern int only_leaf_regs_used PROTO((void));
/* Scan IN_RTX and its subexpressions, and renumber all regs into those
available in leaf functions. */
extern void leaf_renumber_regs_insn PROTO((rtx));
+
+/* Functions in flow.c */
+extern void allocate_for_life_analysis PROTO((void));
+extern int regno_uninitialized PROTO((int));
+extern int regno_clobbered_at_setjmp PROTO((int));
+extern void dump_flow_info PROTO((FILE *));
+extern void find_basic_blocks PROTO((rtx, int, FILE *, int));
+extern void free_basic_block_vars PROTO((int));
+extern void set_block_num PROTO((rtx, int));
+extern void life_analysis PROTO((rtx, int, FILE *));
#endif
/* Functions in varasm.c. */
@@ -131,20 +145,35 @@ extern void readonly_data_section PROTO((void));
/* Determine if we're in the text section. */
extern int in_text_section PROTO((void));
+#ifdef EH_FRAME_SECTION_ASM_OP
+extern void eh_frame_section PROTO ((void));
+#endif
+
#ifdef TREE_CODE
/* Tell assembler to change to section NAME for DECL.
If DECL is NULL, just switch to section NAME.
- If NAME is NULL, get the name from DECL. */
-extern void named_section PROTO((tree, char *));
+ If NAME is NULL, get the name from DECL.
+ If RELOC is 1, the initializer for DECL contains relocs. */
+extern void named_section PROTO((tree, char *, int));
/* Tell assembler to switch to the section for function DECL. */
extern void function_section PROTO((tree));
+/* Tell assembler to switch to the section for the exception table. */
+extern void exception_section PROTO((void));
+
/* Create the rtl to represent a function, for a function definition.
DECL is a FUNCTION_DECL node which describes which function.
The rtl is stored into DECL. */
extern void make_function_rtl PROTO((tree));
+/* Declare DECL to be a weak symbol. */
+extern void declare_weak PROTO ((tree));
+#endif /* TREE_CODE */
+
+/* Emit any pending weak declarations. */
+extern void weak_finish PROTO ((void));
+
/* Decode an `asm' spec for a declaration as a register name.
Return the register number, or -1 if nothing specified,
or -2 if the ASMSPEC is not `cc' or `memory' and is not recognized,
@@ -154,6 +183,7 @@ extern void make_function_rtl PROTO((tree));
Prefixes such as % are optional. */
extern int decode_reg_name PROTO((char *));
+#ifdef TREE_CODE
/* Create the DECL_RTL for a declaration for a static or external variable
or static or external function.
ASMSPEC, if not 0, is the string which the user specified
@@ -170,6 +200,8 @@ extern void make_var_volatile PROTO((tree));
/* Output alignment directive to align for constant expression EXP. */
extern void assemble_constant_align PROTO((tree));
+extern void assemble_alias PROTO((tree, tree));
+
/* Output a string of literal assembler code
for an `asm' keyword used between functions. */
extern void assemble_asm PROTO((tree));
@@ -218,17 +250,11 @@ extern void assemble_string PROTO((char *, int));
initial value (that will be done by the caller). */
extern void assemble_variable PROTO((tree, int, int, int));
-/* Output text storage for constructor CONSTR. */
-extern void bc_output_constructor PROTO((tree, int));
-
-/* Create storage for constructor CONSTR. */
-extern void bc_output_data_constructor PROTO((tree));
-
/* Output something to declare an external symbol to the assembler.
(Most assemblers don't need this, so we normally output nothing.)
Do nothing if DECL is not external. */
extern void assemble_external PROTO((tree));
-#endif
+#endif /* TREE_CODE */
#ifdef RTX_CODE
/* Similar, for calling a library function FUN. */
@@ -246,7 +272,7 @@ extern void assemble_label PROTO((char *));
Otherwise NAME is transformed in an implementation-defined way
(usually by the addition of an underscore).
Many macros in the tm file are defined to call this function. */
-extern void assemble_name STDIO_PROTO((FILE *, char *));
+extern void assemble_name PROTO((FILE *, char *));
#ifdef RTX_CODE
/* Assemble the integer constant X into an object of SIZE bytes.
@@ -414,6 +440,9 @@ extern int current_function_uses_pic_offset_table;
/* This is nonzero if the current function uses the constant pool. */
extern int current_function_uses_const_pool;
+/* Language-specific reason why the current function cannot be made inline. */
+extern char *current_function_cannot_inline;
+
/* The line number of the beginning of the current function.
sdbout.c needs this so that it can output relative linenumbers. */
@@ -426,3 +455,14 @@ extern int sdb_begin_function_line;
#ifdef BUFSIZ
extern FILE *asm_out_file;
#endif
+
+/* Decide whether DECL needs to be in a writable section. RELOC is the same
+ as for SELECT_SECTION. */
+
+#define DECL_READONLY_SECTION(DECL,RELOC) \
+ (TREE_READONLY (DECL) \
+ && ! TREE_THIS_VOLATILE (DECL) \
+ && DECL_INITIAL (DECL) \
+ && (DECL_INITIAL (DECL) == error_mark_node \
+ || TREE_CONSTANT (DECL_INITIAL (DECL))) \
+ && ! (RELOC && (flag_pic || DECL_ONE_ONLY (DECL))))
diff --git a/contrib/gcc/patch-apollo-includes b/contrib/gcc/patch-apollo-includes
new file mode 100755
index 0000000..8daf88c
--- /dev/null
+++ b/contrib/gcc/patch-apollo-includes
@@ -0,0 +1,69 @@
+#!/bin/sh
+# patch-apollo-includes -- fix some (but not all!) Apollo brain damage.
+
+FILES_TO_PATCH='sys/types.h setjmp.h'
+
+mkdir sys
+
+for i in $FILES_TO_PATCH;
+do
+ cp /bsd4.3/usr/include/$i ./$i
+done
+
+patch -b -apollo <<'EOP'
+*** /bsd4.3/usr/include/sys/types.h Fri Apr 8 20:29:06 1988
+--- sys/types.h Wed Feb 26 21:17:57 1992
+***************
+*** 38,44 ****
+--- 38,47 ----
+ typedef char * caddr_t;
+ typedef u_long ino_t;
+ typedef long swblk_t;
++ #ifndef _SIZE_T
++ #define _SIZE_T
+ typedef long size_t;
++ #endif
+ typedef long time_t;
+ typedef long dev_t;
+ typedef long off_t;
+*** /bsd4.3/usr/include/setjmp.h Fri Feb 3 21:40:21 1989
+--- setjmp.h Sun Feb 23 19:06:55 1992
+***************
+*** 24,30 ****
+--- 24,39 ----
+ #endif
+
+
++ #ifdef __GNUC__
+ #ifdef _PROTOTYPES
++ extern int sigsetjmp (sigjmp_buf env, int savemask);
++ extern void siglongjmp (sigjmp_buf env, int val);
++ #else
++ extern int sigsetjmp();
++ extern void siglongjmp();
++ #endif /* _PROTOTYPES */
++ #else /* not __GNUC__ */
++ #ifdef _PROTOTYPES
+ extern int sigsetjmp(
+ sigjmp_buf env,
+ int savemask
+***************
+*** 37,43 ****
+ extern int sigsetjmp() #options(abnormal);
+ extern void siglongjmp() #options(noreturn);
+ #endif /* _PROTOTYPES */
+!
+ #undef _PROTOTYPES
+
+ #ifdef __cplusplus
+--- 46,52 ----
+ extern int sigsetjmp() #options(abnormal);
+ extern void siglongjmp() #options(noreturn);
+ #endif /* _PROTOTYPES */
+! #endif /* not __GNUC__ */
+ #undef _PROTOTYPES
+
+ #ifdef __cplusplus
+EOP
+
+exit 0
diff --git a/contrib/gcc/pexecute.c b/contrib/gcc/pexecute.c
new file mode 100644
index 0000000..804f314
--- /dev/null
+++ b/contrib/gcc/pexecute.c
@@ -0,0 +1,775 @@
+/* Utilities to execute a program in a subprocess (possibly linked by pipes
+ with other subprocesses), and wait for it.
+ Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If not,
+write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file exports two functions: pexecute and pwait. */
+
+/* This file lives in at least two places: libiberty and gcc.
+ Don't change one without the other. */
+
+#ifdef IN_GCC
+#include "config.h"
+#endif
+
+#include "system.h"
+
+#ifdef IN_GCC
+#include "gansidecl.h"
+/* ??? Need to find a suitable header file. */
+#define PEXECUTE_FIRST 1
+#define PEXECUTE_LAST 2
+#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST)
+#define PEXECUTE_SEARCH 4
+#define PEXECUTE_VERBOSE 8
+#else
+#include "libiberty.h"
+#endif
+
+/* stdin file number. */
+#define STDIN_FILE_NO 0
+
+/* stdout file number. */
+#define STDOUT_FILE_NO 1
+
+/* value of `pipe': port index for reading. */
+#define READ_PORT 0
+
+/* value of `pipe': port index for writing. */
+#define WRITE_PORT 1
+
+static char *install_error_msg = "installation problem, cannot exec `%s'";
+
+/* pexecute: execute a program.
+
+ PROGRAM and ARGV are the arguments to execv/execvp.
+
+ THIS_PNAME is name of the calling program (i.e. argv[0]).
+
+ TEMP_BASE is the path name, sans suffix, of a temporary file to use
+ if needed. This is currently only needed for MSDOS ports that don't use
+ GO32 (do any still exist?). Ports that don't need it can pass NULL.
+
+ (FLAGS & PEXECUTE_SEARCH) is non-zero if $PATH should be searched
+ (??? It's not clear that GCC passes this flag correctly).
+ (FLAGS & PEXECUTE_FIRST) is nonzero for the first process in chain.
+ (FLAGS & PEXECUTE_FIRST) is nonzero for the last process in chain.
+ FIRST_LAST could be simplified to only mark the last of a chain of processes
+ but that requires the caller to always mark the last one (and not give up
+ early if some error occurs). It's more robust to require the caller to
+ mark both ends of the chain.
+
+ The result is the pid on systems like Unix where we fork/exec and on systems
+ like WIN32 and OS2 where we use spawn. It is up to the caller to wait for
+ the child.
+
+ The result is the WEXITSTATUS on systems like MSDOS where we spawn and wait
+ for the child here.
+
+ Upon failure, ERRMSG_FMT and ERRMSG_ARG are set to the text of the error
+ message with an optional argument (if not needed, ERRMSG_ARG is set to
+ NULL), and -1 is returned. `errno' is available to the caller to use.
+
+ pwait: cover function for wait.
+
+ PID is the process id of the task to wait for.
+ STATUS is the `status' argument to wait.
+ FLAGS is currently unused (allows future enhancement without breaking
+ upward compatibility). Pass 0 for now.
+
+ The result is the pid of the child reaped,
+ or -1 for failure (errno says why).
+
+ On systems that don't support waiting for a particular child, PID is
+ ignored. On systems like MSDOS that don't really multitask pwait
+ is just a mechanism to provide a consistent interface for the caller.
+
+ pfinish: finish generation of script
+
+ pfinish is necessary for systems like MPW where a script is generated that
+ runs the requested programs.
+*/
+
+#ifdef __MSDOS__
+
+/* MSDOS doesn't multitask, but for the sake of a consistent interface
+ the code behaves like it does. pexecute runs the program, tucks the
+ exit code away, and returns a "pid". pwait must be called to fetch the
+ exit code. */
+
+#include <process.h>
+
+/* For communicating information from pexecute to pwait. */
+static int last_pid = 0;
+static int last_status = 0;
+static int last_reaped = 0;
+
+int
+pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
+ const char *program;
+ char * const *argv;
+ const char *this_pname;
+ const char *temp_base;
+ char **errmsg_fmt, **errmsg_arg;
+ int flags;
+{
+ int rc;
+
+ last_pid++;
+ if (last_pid < 0)
+ last_pid = 1;
+
+ if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
+ abort ();
+
+#ifdef __GO32__
+ /* ??? What are the possible return values from spawnv? */
+ rc = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv);
+#else
+ char *scmd, *rf;
+ FILE *argfile;
+ int i, el = flags & PEXECUTE_SEARCH ? 4 : 0;
+
+ scmd = (char *) xmalloc (strlen (program) + strlen (temp_base) + 6 + el);
+ rf = scmd + strlen(program) + 2 + el;
+ sprintf (scmd, "%s%s @%s.gp", program,
+ (flags & PEXECUTE_SEARCH ? ".exe" : ""), temp_base);
+ argfile = fopen (rf, "w");
+ if (argfile == 0)
+ {
+ int errno_save = errno;
+ free (scmd);
+ errno = errno_save;
+ *errmsg_fmt = "cannot open `%s.gp'";
+ *errmsg_arg = temp_base;
+ return -1;
+ }
+
+ for (i=1; argv[i]; i++)
+ {
+ char *cp;
+ for (cp = argv[i]; *cp; cp++)
+ {
+ if (*cp == '"' || *cp == '\'' || *cp == '\\' || ISSPACE (*cp))
+ fputc ('\\', argfile);
+ fputc (*cp, argfile);
+ }
+ fputc ('\n', argfile);
+ }
+ fclose (argfile);
+
+ rc = system (scmd);
+
+ {
+ int errno_save = errno;
+ remove (rf);
+ free (scmd);
+ errno = errno_save;
+ }
+#endif
+
+ if (rc == -1)
+ {
+ *errmsg_fmt = install_error_msg;
+ *errmsg_arg = program;
+ return -1;
+ }
+
+ /* Tuck the status away for pwait, and return a "pid". */
+ last_status = rc << 8;
+ return last_pid;
+}
+
+int
+pwait (pid, status, flags)
+ int pid;
+ int *status;
+ int flags;
+{
+ /* On MSDOS each pexecute must be followed by it's associated pwait. */
+ if (pid != last_pid
+ /* Called twice for the same child? */
+ || pid == last_reaped)
+ {
+ /* ??? ECHILD would be a better choice. Can we use it here? */
+ errno = EINVAL;
+ return -1;
+ }
+ /* ??? Here's an opportunity to canonicalize the values in STATUS.
+ Needed? */
+ *status = last_status;
+ last_reaped = last_pid;
+ return last_pid;
+}
+
+#endif /* MSDOS */
+
+#if defined (_WIN32)
+
+#include <process.h>
+
+#ifdef __CYGWIN32__
+
+#define fix_argv(argvec) (argvec)
+
+extern int _spawnv ();
+extern int _spawnvp ();
+
+int
+pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
+ const char *program;
+ char * const *argv;
+ const char *this_pname;
+ const char *temp_base;
+ char **errmsg_fmt, **errmsg_arg;
+ int flags;
+{
+ int pid;
+
+ if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
+ abort ();
+ pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv)
+ (_P_NOWAIT, program, fix_argv(argv));
+ if (pid == -1)
+ {
+ *errmsg_fmt = install_error_msg;
+ *errmsg_arg = program;
+ return -1;
+ }
+ return pid;
+}
+
+int
+pwait (pid, status, flags)
+ int pid;
+ int *status;
+ int flags;
+{
+ /* ??? Here's an opportunity to canonicalize the values in STATUS.
+ Needed? */
+ return cwait (status, pid, WAIT_CHILD);
+}
+
+#else /* ! __CYGWIN32__ */
+
+/* This is a kludge to get around the Microsoft C spawn functions' propensity
+ to remove the outermost set of double quotes from all arguments. */
+
+const char * const *
+fix_argv (argvec)
+ char **argvec;
+{
+ int i;
+
+ for (i = 1; argvec[i] != 0; i++)
+ {
+ int len, j;
+ char *temp, *newtemp;
+
+ temp = argvec[i];
+ len = strlen (temp);
+ for (j = 0; j < len; j++)
+ {
+ if (temp[j] == '"')
+ {
+ newtemp = xmalloc (len + 2);
+ strncpy (newtemp, temp, j);
+ newtemp [j] = '\\';
+ strncpy (&newtemp [j+1], &temp [j], len-j);
+ newtemp [len+1] = 0;
+ temp = newtemp;
+ len++;
+ j++;
+ }
+ }
+
+ argvec[i] = temp;
+ }
+
+ return (const char * const *) argvec;
+}
+
+#include <io.h>
+#include <fcntl.h>
+#include <signal.h>
+
+/* mingw32 headers may not define the following. */
+
+#ifndef _P_WAIT
+# define _P_WAIT 0
+# define _P_NOWAIT 1
+# define _P_OVERLAY 2
+# define _P_NOWAITO 3
+# define _P_DETACH 4
+
+# define WAIT_CHILD 0
+# define WAIT_GRANDCHILD 1
+#endif
+
+/* Win32 supports pipes */
+int
+pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
+ const char *program;
+ char * const *argv;
+ const char *this_pname;
+ const char *temp_base;
+ char **errmsg_fmt, **errmsg_arg;
+ int flags;
+{
+ int pid;
+ int pdes[2], org_stdin, org_stdout;
+ int input_desc, output_desc;
+ int retries, sleep_interval;
+
+ /* Pipe waiting from last process, to be used as input for the next one.
+ Value is STDIN_FILE_NO if no pipe is waiting
+ (i.e. the next command is the first of a group). */
+ static int last_pipe_input;
+
+ /* If this is the first process, initialize. */
+ if (flags & PEXECUTE_FIRST)
+ last_pipe_input = STDIN_FILE_NO;
+
+ input_desc = last_pipe_input;
+
+ /* If this isn't the last process, make a pipe for its output,
+ and record it as waiting to be the input to the next process. */
+ if (! (flags & PEXECUTE_LAST))
+ {
+ if (_pipe (pdes, 256, O_BINARY) < 0)
+ {
+ *errmsg_fmt = "pipe";
+ *errmsg_arg = NULL;
+ return -1;
+ }
+ output_desc = pdes[WRITE_PORT];
+ last_pipe_input = pdes[READ_PORT];
+ }
+ else
+ {
+ /* Last process. */
+ output_desc = STDOUT_FILE_NO;
+ last_pipe_input = STDIN_FILE_NO;
+ }
+
+ if (input_desc != STDIN_FILE_NO)
+ {
+ org_stdin = dup (STDIN_FILE_NO);
+ dup2 (input_desc, STDIN_FILE_NO);
+ close (input_desc);
+ }
+
+ if (output_desc != STDOUT_FILE_NO)
+ {
+ org_stdout = dup (STDOUT_FILE_NO);
+ dup2 (output_desc, STDOUT_FILE_NO);
+ close (output_desc);
+ }
+
+ pid = (flags & PEXECUTE_SEARCH ? _spawnvp : _spawnv)
+ (_P_NOWAIT, program, fix_argv(argv));
+
+ if (input_desc != STDIN_FILE_NO)
+ {
+ dup2 (org_stdin, STDIN_FILE_NO);
+ close (org_stdin);
+ }
+
+ if (output_desc != STDOUT_FILE_NO)
+ {
+ dup2 (org_stdout, STDOUT_FILE_NO);
+ close (org_stdout);
+ }
+
+ if (pid == -1)
+ {
+ *errmsg_fmt = install_error_msg;
+ *errmsg_arg = program;
+ return -1;
+ }
+
+ return pid;
+}
+
+/* MS CRTDLL doesn't return enough information in status to decide if the
+ child exited due to a signal or not, rather it simply returns an
+ integer with the exit code of the child; eg., if the child exited with
+ an abort() call and didn't have a handler for SIGABRT, it simply returns
+ with status = 3. We fix the status code to conform to the usual WIF*
+ macros. Note that WIFSIGNALED will never be true under CRTDLL. */
+
+int
+pwait (pid, status, flags)
+ int pid;
+ int *status;
+ int flags;
+{
+ int termstat;
+
+ pid = _cwait (&termstat, pid, WAIT_CHILD);
+
+ /* ??? Here's an opportunity to canonicalize the values in STATUS.
+ Needed? */
+
+ /* cwait returns the child process exit code in termstat.
+ A value of 3 indicates that the child caught a signal, but not
+ which one. Since only SIGABRT, SIGFPE and SIGINT do anything, we
+ report SIGABRT. */
+ if (termstat == 3)
+ *status = SIGABRT;
+ else
+ *status = (((termstat) & 0xff) << 8);
+
+ return pid;
+}
+
+#endif /* ! defined (__CYGWIN32__) */
+
+#endif /* _WIN32 */
+
+#ifdef OS2
+
+/* ??? Does OS2 have process.h? */
+extern int spawnv ();
+extern int spawnvp ();
+
+int
+pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
+ const char *program;
+ char * const *argv;
+ const char *this_pname;
+ const char *temp_base;
+ char **errmsg_fmt, **errmsg_arg;
+ int flags;
+{
+ int pid;
+
+ if ((flags & PEXECUTE_ONE) != PEXECUTE_ONE)
+ abort ();
+ /* ??? Presumably 1 == _P_NOWAIT. */
+ pid = (flags & PEXECUTE_SEARCH ? spawnvp : spawnv) (1, program, argv);
+ if (pid == -1)
+ {
+ *errmsg_fmt = install_error_msg;
+ *errmsg_arg = program;
+ return -1;
+ }
+ return pid;
+}
+
+int
+pwait (pid, status, flags)
+ int pid;
+ int *status;
+ int flags;
+{
+ /* ??? Here's an opportunity to canonicalize the values in STATUS.
+ Needed? */
+ int pid = wait (status);
+ return pid;
+}
+
+#endif /* OS2 */
+
+#ifdef MPW
+
+/* MPW pexecute doesn't actually run anything; instead, it writes out
+ script commands that, when run, will do the actual executing.
+
+ For example, in GCC's case, GCC will write out several script commands:
+
+ cpp ...
+ cc1 ...
+ as ...
+ ld ...
+
+ and then exit. None of the above programs will have run yet. The task
+ that called GCC will then execute the script and cause cpp,etc. to run.
+ The caller must invoke pfinish before calling exit. This adds
+ the finishing touches to the generated script. */
+
+static int first_time = 1;
+
+int
+pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
+ const char *program;
+ char * const *argv;
+ const char *this_pname;
+ const char *temp_base;
+ char **errmsg_fmt, **errmsg_arg;
+ int flags;
+{
+ char tmpprogram[255];
+ char *cp, *tmpname;
+ int i;
+
+ mpwify_filename (program, tmpprogram);
+ if (first_time)
+ {
+ printf ("Set Failed 0\n");
+ first_time = 0;
+ }
+
+ fputs ("If {Failed} == 0\n", stdout);
+ /* If being verbose, output a copy of the command. It should be
+ accurate enough and escaped enough to be "clickable". */
+ if (flags & PEXECUTE_VERBOSE)
+ {
+ fputs ("\tEcho ", stdout);
+ fputc ('\'', stdout);
+ fputs (tmpprogram, stdout);
+ fputc ('\'', stdout);
+ fputc (' ', stdout);
+ for (i=1; argv[i]; i++)
+ {
+ fputc ('\'', stdout);
+ /* See if we have an argument that needs fixing. */
+ if (strchr(argv[i], '/'))
+ {
+ tmpname = (char *) xmalloc (256);
+ mpwify_filename (argv[i], tmpname);
+ argv[i] = tmpname;
+ }
+ for (cp = argv[i]; *cp; cp++)
+ {
+ /* Write an Option-d escape char in front of special chars. */
+ if (strchr("'+", *cp))
+ fputc ('\266', stdout);
+ fputc (*cp, stdout);
+ }
+ fputc ('\'', stdout);
+ fputc (' ', stdout);
+ }
+ fputs ("\n", stdout);
+ }
+ fputs ("\t", stdout);
+ fputs (tmpprogram, stdout);
+ fputc (' ', stdout);
+
+ for (i=1; argv[i]; i++)
+ {
+ /* See if we have an argument that needs fixing. */
+ if (strchr(argv[i], '/'))
+ {
+ tmpname = (char *) xmalloc (256);
+ mpwify_filename (argv[i], tmpname);
+ argv[i] = tmpname;
+ }
+ if (strchr (argv[i], ' '))
+ fputc ('\'', stdout);
+ for (cp = argv[i]; *cp; cp++)
+ {
+ /* Write an Option-d escape char in front of special chars. */
+ if (strchr("'+", *cp))
+ fputc ('\266', stdout);
+ fputc (*cp, stdout);
+ }
+ if (strchr (argv[i], ' '))
+ fputc ('\'', stdout);
+ fputc (' ', stdout);
+ }
+
+ fputs ("\n", stdout);
+
+ /* Output commands that arrange to clean up and exit if a failure occurs.
+ We have to be careful to collect the status from the program that was
+ run, rather than some other script command. Also, we don't exit
+ immediately, since necessary cleanups are at the end of the script. */
+ fputs ("\tSet TmpStatus {Status}\n", stdout);
+ fputs ("\tIf {TmpStatus} != 0\n", stdout);
+ fputs ("\t\tSet Failed {TmpStatus}\n", stdout);
+ fputs ("\tEnd\n", stdout);
+ fputs ("End\n", stdout);
+
+ /* We're just composing a script, can't fail here. */
+ return 0;
+}
+
+int
+pwait (pid, status, flags)
+ int pid;
+ int *status;
+ int flags;
+{
+ *status = 0;
+ return 0;
+}
+
+/* Write out commands that will exit with the correct error code
+ if something in the script failed. */
+
+void
+pfinish ()
+{
+ printf ("\tExit \"{Failed}\"\n");
+}
+
+#endif /* MPW */
+
+/* include for Unix-like environments but not for Dos-like environments */
+#if ! defined (__MSDOS__) && ! defined (OS2) && ! defined (MPW) \
+ && ! defined (_WIN32)
+
+#ifdef VMS
+#define vfork() (decc$$alloc_vfork_blocks() >= 0 ? \
+ lib$get_current_invo_context(decc$$get_vfork_jmpbuf()) : -1)
+#else
+#ifdef USG
+#define vfork fork
+#endif
+#endif
+
+extern int execv ();
+extern int execvp ();
+#ifdef IN_GCC
+extern char * my_strerror PROTO ((int));
+#endif
+
+int
+pexecute (program, argv, this_pname, temp_base, errmsg_fmt, errmsg_arg, flags)
+ const char *program;
+ char * const *argv;
+ const char *this_pname;
+ const char *temp_base;
+ char **errmsg_fmt, **errmsg_arg;
+ int flags;
+{
+ int (*func)() = (flags & PEXECUTE_SEARCH ? execvp : execv);
+ int pid;
+ int pdes[2];
+ int input_desc, output_desc;
+ int retries, sleep_interval;
+ /* Pipe waiting from last process, to be used as input for the next one.
+ Value is STDIN_FILE_NO if no pipe is waiting
+ (i.e. the next command is the first of a group). */
+ static int last_pipe_input;
+
+ /* If this is the first process, initialize. */
+ if (flags & PEXECUTE_FIRST)
+ last_pipe_input = STDIN_FILE_NO;
+
+ input_desc = last_pipe_input;
+
+ /* If this isn't the last process, make a pipe for its output,
+ and record it as waiting to be the input to the next process. */
+ if (! (flags & PEXECUTE_LAST))
+ {
+ if (pipe (pdes) < 0)
+ {
+ *errmsg_fmt = "pipe";
+ *errmsg_arg = NULL;
+ return -1;
+ }
+ output_desc = pdes[WRITE_PORT];
+ last_pipe_input = pdes[READ_PORT];
+ }
+ else
+ {
+ /* Last process. */
+ output_desc = STDOUT_FILE_NO;
+ last_pipe_input = STDIN_FILE_NO;
+ }
+
+ /* Fork a subprocess; wait and retry if it fails. */
+ sleep_interval = 1;
+ for (retries = 0; retries < 4; retries++)
+ {
+ pid = vfork ();
+ if (pid >= 0)
+ break;
+ sleep (sleep_interval);
+ sleep_interval *= 2;
+ }
+
+ switch (pid)
+ {
+ case -1:
+ {
+#ifdef vfork
+ *errmsg_fmt = "fork";
+#else
+ *errmsg_fmt = "vfork";
+#endif
+ *errmsg_arg = NULL;
+ return -1;
+ }
+
+ case 0: /* child */
+ /* Move the input and output pipes into place, if necessary. */
+ if (input_desc != STDIN_FILE_NO)
+ {
+ close (STDIN_FILE_NO);
+ dup (input_desc);
+ close (input_desc);
+ }
+ if (output_desc != STDOUT_FILE_NO)
+ {
+ close (STDOUT_FILE_NO);
+ dup (output_desc);
+ close (output_desc);
+ }
+
+ /* Close the parent's descs that aren't wanted here. */
+ if (last_pipe_input != STDIN_FILE_NO)
+ close (last_pipe_input);
+
+ /* Exec the program. */
+ (*func) (program, argv);
+
+ /* Note: Calling fprintf and exit here doesn't seem right for vfork. */
+ fprintf (stderr, "%s: ", this_pname);
+ fprintf (stderr, install_error_msg, program);
+#ifdef IN_GCC
+ fprintf (stderr, ": %s\n", my_strerror (errno));
+#else
+ fprintf (stderr, ": %s\n", xstrerror (errno));
+#endif
+ exit (-1);
+ /* NOTREACHED */
+ return 0;
+
+ default:
+ /* In the parent, after forking.
+ Close the descriptors that we made for this child. */
+ if (input_desc != STDIN_FILE_NO)
+ close (input_desc);
+ if (output_desc != STDOUT_FILE_NO)
+ close (output_desc);
+
+ /* Return child's process number. */
+ return pid;
+ }
+}
+
+int
+pwait (pid, status, flags)
+ int pid;
+ int *status;
+ int flags;
+{
+ /* ??? Here's an opportunity to canonicalize the values in STATUS.
+ Needed? */
+#ifdef VMS
+ pid = waitpid (-1, status, 0);
+#else
+ pid = wait (status);
+#endif
+ return pid;
+}
+
+#endif /* ! __MSDOS__ && ! OS2 && ! MPW && ! _WIN32 */
diff --git a/contrib/gcc/prefix.c b/contrib/gcc/prefix.c
new file mode 100644
index 0000000..1c96c58
--- /dev/null
+++ b/contrib/gcc/prefix.c
@@ -0,0 +1,331 @@
+/* Utility to update paths from internal to external forms.
+ Copyright (C) 1997, 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+GCC 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This file contains routines to update a path, both to canonicalize
+ the directory format and to handle any prefix translation.
+
+ This file must be compiled with -DPREFIX= to specify the "prefix"
+ value used by configure. If a filename does not begin with this
+ prefix, it will not be affected other than by directory canonicalization.
+
+ Each caller of 'update_path' may specify both a filename and
+ a translation prefix and consist of the name of the package that contains
+ the file ("@GCC", "@BINUTIL", "@GNU", etc).
+
+ If the prefix is not specified, the filename will only undergo
+ directory canonicalization.
+
+ If it is specified, the string given by PREFIX will be replaced
+ by the specified prefix (with a '@' in front unless the prefix begins
+ with a '$') and further translation will be done as follows
+ until none of the two conditions below are met:
+
+ 1) If the filename begins with '@', the string between the '@' and
+ the end of the name or the first '/' or directory separator will
+ be considered a "key" and looked up as follows:
+
+ -- If this is a Win32 OS, then the Registry will be examined for
+ an entry of "key" in
+
+ HKEY_LOCAL_MACHINE\SOFTWARE\Free Software Foundation\
+
+ if found, that value will be used.
+
+ -- If not found (or not a Win32 OS), the environment variable
+ key_ROOT (the value of "key" concatenated with the constant "_ROOT")
+ is tried. If that fails, then PREFIX (see above) is used.
+
+ 2) If the filename begins with a '$', the rest of the string up
+ to the end or the first '/' or directory separator will be used
+ as an environment variable, whose value will be returned.
+
+ Once all this is done, any '/' will be converted to DIR_SEPARATOR,
+ if they are different.
+
+ NOTE: using resolve_keyed_path under Win32 requires linking with
+ advapi32.dll. */
+
+
+#include "config.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#include "system.h"
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#include "gansidecl.h"
+
+static char *std_prefix = PREFIX;
+
+static char *get_key_value PROTO((char *));
+static char *translate_name PROTO((char *));
+static char *concat PVPROTO((char *, ...));
+static char *save_string PROTO((char *, int));
+
+#ifdef _WIN32
+static char *lookup_key PROTO((char *));
+static HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
+#endif
+
+/* Given KEY, as above, return its value. */
+
+static char *
+get_key_value (key)
+ char *key;
+{
+ char *prefix = 0;
+ char *temp = 0;
+
+#ifdef _WIN32
+ prefix = lookup_key (key);
+#endif
+
+ if (prefix == 0)
+ prefix = getenv (temp = concat (key, "_ROOT", NULL_PTR));
+
+ if (prefix == 0)
+ prefix = std_prefix;
+
+ if (temp)
+ free (temp);
+
+ return prefix;
+}
+
+/* Concatenate a sequence of strings, returning the result.
+
+ This function is based on the one in libiberty. */
+
+static char *
+concat VPROTO((char *first, ...))
+{
+ register int length;
+ register char *newstr;
+ register char *end;
+ register char *arg;
+ va_list args;
+#ifndef __STDC__
+ char *first;
+#endif
+
+ /* First compute the size of the result and get sufficient memory. */
+
+ VA_START (args, first);
+#ifndef __STDC__
+ first = va_arg (args, char *);
+#endif
+
+ arg = first;
+ length = 0;
+
+ while (arg != 0)
+ {
+ length += strlen (arg);
+ arg = va_arg (args, char *);
+ }
+
+ newstr = (char *) malloc (length + 1);
+ va_end (args);
+
+ /* Now copy the individual pieces to the result string. */
+
+ VA_START (args, first);
+#ifndef __STDC__
+ first = va_arg (args, char *);
+#endif
+
+ end = newstr;
+ arg = first;
+ while (arg != 0)
+ {
+ while (*arg)
+ *end++ = *arg++;
+ arg = va_arg (args, char *);
+ }
+ *end = '\000';
+ va_end (args);
+
+ return (newstr);
+}
+
+/* Return a copy of a string that has been placed in the heap. */
+
+static char *
+save_string (s, len)
+ char *s;
+ int len;
+{
+ register char *result = (char *) malloc (len + 1);
+
+ bcopy (s, result, len);
+ result[len] = 0;
+ return result;
+}
+
+#ifdef _WIN32
+
+/* Look up "key" in the registry, as above. */
+
+static char *
+lookup_key (key)
+ char *key;
+{
+ char *dst;
+ DWORD size;
+ DWORD type;
+ LONG res;
+
+ if (reg_key == (HKEY) INVALID_HANDLE_VALUE)
+ {
+ res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, "SOFTWARE", 0,
+ KEY_READ, &reg_key);
+
+ if (res == ERROR_SUCCESS)
+ res = RegOpenKeyExA (reg_key, "Free Software Foundation", 0,
+ KEY_READ, &reg_key);
+
+ if (res != ERROR_SUCCESS)
+ {
+ reg_key = (HKEY) INVALID_HANDLE_VALUE;
+ return 0;
+ }
+ }
+
+ size = 32;
+ dst = (char *) malloc (size);
+
+ res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size);
+ if (res == ERROR_MORE_DATA && type == REG_SZ)
+ {
+ dst = (char *) realloc (dst, size);
+ res = RegQueryValueExA (reg_key, key, 0, &type, dst, &size);
+ }
+
+ if (type != REG_SZ || res != ERROR_SUCCESS)
+ {
+ free (dst);
+ dst = 0;
+ }
+
+ return dst;
+}
+#endif
+
+/* If NAME starts with a '@' or '$', apply the translation rules above
+ and return a new name. Otherwise, return the given name. */
+
+static char *
+translate_name (name)
+ char *name;
+{
+ char code = name[0];
+ char *key, *prefix = 0;
+ int keylen;
+
+ if (code != '@' && code != '$')
+ return name;
+
+ for (keylen = 0;
+ (name[keylen + 1] != 0 && name[keylen + 1] != '/'
+#ifdef DIR_SEPARATOR
+ && name[keylen + 1] != DIR_SEPARATOR
+#endif
+ );
+ keylen++)
+ ;
+
+ key = alloca (keylen + 1);
+ strncpy (key, &name[1], keylen);
+ key[keylen] = 0;
+
+ name = &name[keylen + 1];
+
+ if (code == '@')
+ {
+ prefix = get_key_value (key);
+ if (prefix == 0)
+ prefix = std_prefix;
+ }
+ else
+ prefix = getenv (key);
+
+ if (prefix == 0)
+ prefix = PREFIX;
+
+ /* Remove any trailing directory separator from what we got. */
+ if (prefix[strlen (prefix) - 1] == '/'
+#ifdef DIR_SEPARATOR
+ || prefix[strlen (prefix) - 1] == DIR_SEPARATOR
+#endif
+ )
+ {
+ prefix = save_string (prefix, strlen (prefix));
+ prefix[strlen (prefix) - 1] = 0;
+ }
+
+ return concat (prefix, name, NULL_PTR);
+}
+
+/* Update PATH using KEY if PATH starts with PREFIX. */
+
+char *
+update_path (path, key)
+ char *path;
+ char *key;
+{
+ if (! strncmp (path, std_prefix, strlen (std_prefix)) && key != 0)
+ {
+ if (key[0] != '$')
+ key = concat ("@", key, NULL_PTR);
+
+ path = concat (key, &path[strlen (std_prefix)], NULL_PTR);
+
+ while (path[0] == '@' || path[0] == '$')
+ path = translate_name (path);
+ }
+
+#ifdef DIR_SEPARATOR
+ if (DIR_SEPARATOR != '/')
+ {
+ int i;
+ int len = strlen (path);
+
+ path = save_string (path, len);
+ for (i = 0; i < len; i++)
+ if (path[i] == '/')
+ path[i] = DIR_SEPARATOR;
+ }
+#endif
+
+ return path;
+}
+
+/* Reset the standard prefix */
+void
+set_std_prefix (prefix, len)
+ char *prefix;
+ int len;
+{
+ std_prefix = save_string (prefix, len);
+}
diff --git a/contrib/gcc/print-rtl.c b/contrib/gcc/print-rtl.c
index 20d34db..947a9b7 100644
--- a/contrib/gcc/print-rtl.c
+++ b/contrib/gcc/print-rtl.c
@@ -1,5 +1,5 @@
/* Print RTL for GNU C Compiler.
- Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1992, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,9 +20,10 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
-#include <ctype.h>
-#include <stdio.h>
+#include "system.h"
#include "rtl.h"
+#include "bitmap.h"
+#include "real.h"
/* How to print out a register name.
@@ -47,17 +48,19 @@ char spaces[] = "
static int sawclose = 0;
+static int indent;
+
/* Names for patterns. Non-zero only when linked with insn-output.c. */
extern char **insn_name_ptr;
+int flag_dump_unnumbered = 0;
/* Print IN_RTX onto OUTFILE. This is the recursive part of printing. */
static void
print_rtx (in_rtx)
register rtx in_rtx;
{
- static int indent;
register int i, j;
register char *format_ptr;
register int is_insn;
@@ -108,6 +111,39 @@ print_rtx (in_rtx)
{
case 'S':
case 's':
+ if (i == 3 && GET_CODE (in_rtx) == NOTE
+ && (NOTE_LINE_NUMBER (in_rtx) == NOTE_INSN_EH_REGION_BEG
+ || NOTE_LINE_NUMBER (in_rtx) == NOTE_INSN_EH_REGION_END
+ || NOTE_LINE_NUMBER (in_rtx) == NOTE_INSN_BLOCK_BEG
+ || NOTE_LINE_NUMBER (in_rtx) == NOTE_INSN_BLOCK_END))
+ {
+ fprintf (outfile, " %d", NOTE_BLOCK_NUMBER (in_rtx));
+ sawclose = 1;
+ break;
+ }
+
+ if (i == 3 && GET_CODE (in_rtx) == NOTE
+ && (NOTE_LINE_NUMBER (in_rtx) == NOTE_INSN_RANGE_START
+ || NOTE_LINE_NUMBER (in_rtx) == NOTE_INSN_RANGE_END))
+ {
+ indent += 2;
+ if (!sawclose)
+ fprintf (outfile, " ");
+ print_rtx (NOTE_RANGE_INFO (in_rtx));
+ indent -= 2;
+ break;
+ }
+
+ if (i == 3 && GET_CODE (in_rtx) == NOTE
+ && NOTE_LINE_NUMBER (in_rtx) == NOTE_INSN_LIVE)
+ {
+ if (XBITMAP (in_rtx, i) == NULL)
+ fprintf (outfile, " {null}");
+ else
+ bitmap_print (outfile, XBITMAP (in_rtx, i), " {", "}");
+ sawclose = 0;
+ }
+
if (XSTR (in_rtx, i) == 0)
fprintf (outfile, " \"\"");
else
@@ -158,13 +194,8 @@ print_rtx (in_rtx)
break;
case 'w':
- fprintf (outfile,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- " %d",
-#else
- " %ld",
-#endif
- XWINT (in_rtx, i));
+ fprintf (outfile, " ");
+ fprintf (outfile, HOST_WIDE_INT_PRINT_DEC, XWINT (in_rtx, i));
break;
case 'i':
@@ -176,6 +207,9 @@ print_rtx (in_rtx)
fputc (' ', outfile);
DEBUG_PRINT_REG (in_rtx, 0, outfile);
}
+ else if (flag_dump_unnumbered
+ && (is_insn || GET_CODE (in_rtx) == NOTE))
+ fprintf (outfile, "#");
else
fprintf (outfile, " %d", value);
}
@@ -198,12 +232,30 @@ print_rtx (in_rtx)
case 'u':
if (XEXP (in_rtx, i) != NULL)
- fprintf (outfile, " %d", INSN_UID (XEXP (in_rtx, i)));
+ {
+ if (flag_dump_unnumbered)
+ fprintf (outfile, "#");
+ else
+ fprintf (outfile, " %d", INSN_UID (XEXP (in_rtx, i)));
+ }
else
fprintf (outfile, " 0");
sawclose = 0;
break;
+ case 'b':
+ if (XBITMAP (in_rtx, i) == NULL)
+ fprintf (outfile, " {null}");
+ else
+ bitmap_print (outfile, XBITMAP (in_rtx, i), " {", "}");
+ sawclose = 0;
+ break;
+
+ case 't':
+ putc (' ', outfile);
+ fprintf (outfile, HOST_PTR_PRINTF, (char *) XTREE (in_rtx, i));
+ break;
+
case '*':
fprintf (outfile, " Unknown");
sawclose = 0;
@@ -216,10 +268,39 @@ print_rtx (in_rtx)
abort ();
}
+#if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && LONG_DOUBLE_TYPE_SIZE == 64
+ if (GET_CODE (in_rtx) == CONST_DOUBLE && FLOAT_MODE_P (GET_MODE (in_rtx)))
+ {
+ double val;
+ REAL_VALUE_FROM_CONST_DOUBLE (val, in_rtx);
+ fprintf (outfile, " [%.16g]", val);
+ }
+#endif
+
fprintf (outfile, ")");
sawclose = 1;
}
+/* Print an rtx on the current line of FILE. Initially indent IND
+ characters. */
+
+void
+print_inline_rtx (outf, x, ind)
+ FILE *outf;
+ rtx x;
+ int ind;
+{
+ int oldsaw = sawclose;
+ int oldindent = indent;
+
+ sawclose = 0;
+ indent = ind;
+ outfile = outf;
+ print_rtx (x);
+ sawclose = oldsaw;
+ indent = oldindent;
+}
+
/* Call this function from the debugger to see what X looks like. */
void
@@ -271,7 +352,7 @@ debug_rtx_list (x, n)
The found insn is returned to enable further debugging analysis. */
rtx
-debug_rtx_find(x, uid)
+debug_rtx_find (x, uid)
rtx x;
int uid;
{
@@ -318,8 +399,13 @@ print_rtl (outf, rtx_first)
case BARRIER:
for (tmp_rtx = rtx_first; NULL != tmp_rtx; tmp_rtx = NEXT_INSN (tmp_rtx))
{
- print_rtx (tmp_rtx);
- fprintf (outfile, "\n");
+ if (! flag_dump_unnumbered
+ || GET_CODE (tmp_rtx) != NOTE
+ || NOTE_LINE_NUMBER (tmp_rtx) < 0)
+ {
+ print_rtx (tmp_rtx);
+ fprintf (outfile, "\n");
+ }
}
break;
@@ -327,3 +413,20 @@ print_rtl (outf, rtx_first)
print_rtx (rtx_first);
}
}
+
+/* Like print_rtx, except specify a file. */
+
+void
+print_rtl_single (outf, x)
+ FILE *outf;
+ rtx x;
+{
+ outfile = outf;
+ sawclose = 0;
+ if (! flag_dump_unnumbered
+ || GET_CODE (x) != NOTE || NOTE_LINE_NUMBER (x) < 0)
+ {
+ print_rtx (x);
+ putc ('\n', outf);
+ }
+}
diff --git a/contrib/gcc/print-tree.c b/contrib/gcc/print-tree.c
index 7f9dd10..6163b1f 100644
--- a/contrib/gcc/print-tree.c
+++ b/contrib/gcc/print-tree.c
@@ -1,5 +1,5 @@
/* Prints out tree in human readable form - GNU C-compiler
- Copyright (C) 1990, 1991, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1990, 91, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,10 +20,8 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "tree.h"
-#include <stdio.h>
-
-extern char **tree_code_name;
extern char *mode_name[];
@@ -82,7 +80,7 @@ print_node_brief (file, prefix, node, indent)
if (indent > 0)
fprintf (file, " ");
fprintf (file, "%s <%s ", prefix, tree_code_name[(int) TREE_CODE (node)]);
- fprintf (file, HOST_PTR_PRINTF, (HOST_WIDE_INT) node);
+ fprintf (file, HOST_PTR_PRINTF, (char *) node);
if (class == 'd')
{
@@ -109,38 +107,18 @@ print_node_brief (file, prefix, node, indent)
if (TREE_CONSTANT_OVERFLOW (node))
fprintf (file, " overflow");
+ fprintf (file, " ");
if (TREE_INT_CST_HIGH (node) == 0)
- fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- " %1u",
-#else
- " %1lu",
-#endif
- TREE_INT_CST_LOW (node));
+ fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED, TREE_INT_CST_LOW (node));
else if (TREE_INT_CST_HIGH (node) == -1
&& TREE_INT_CST_LOW (node) != 0)
- fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- " -%1u",
-#else
- " -%1lu",
-#endif
+ {
+ fprintf (file, "-");
+ fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED,
-TREE_INT_CST_LOW (node));
+ }
else
- fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == 64
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
- " 0x%lx%016lx",
-#else
- " 0x%x%016x",
-#endif
-#else
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
- " 0x%lx%08lx",
-#else
- " 0x%x%08x",
-#endif
-#endif
+ fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
TREE_INT_CST_HIGH (node), TREE_INT_CST_LOW (node));
}
if (TREE_CODE (node) == REAL_CST)
@@ -231,14 +209,14 @@ print_node (file, prefix, node, indent)
return;
}
- /* It is unsafe to look at any other filds of an ERROR_MARK node. */
+ /* It is unsafe to look at any other filds of an ERROR_MARK node. */
if (TREE_CODE (node) == ERROR_MARK)
{
print_node_brief (file, prefix, node, indent);
return;
}
- hash = ((unsigned HOST_WIDE_INT) node) % HASH_SIZE;
+ hash = ((unsigned long) node) % HASH_SIZE;
/* If node is in the table, just mention its address. */
for (b = table[hash]; b; b = b->next)
@@ -259,7 +237,7 @@ print_node (file, prefix, node, indent)
/* Print the slot this node is in, and its code, and address. */
fprintf (file, "%s <%s ", prefix, tree_code_name[(int) TREE_CODE (node)]);
- fprintf (file, HOST_PTR_PRINTF, (HOST_WIDE_INT) node);
+ fprintf (file, HOST_PTR_PRINTF, (char *) node);
/* Print the name, if any. */
if (class == 'd')
@@ -417,7 +395,6 @@ print_node (file, prefix, node, indent)
DECL_SOURCE_FILE (node), DECL_SOURCE_LINE (node));
print_node (file, "size", DECL_SIZE (node), indent + 4);
- print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4);
indent_to (file, indent + 3);
if (TREE_CODE (node) != FUNCTION_DECL)
fprintf (file, " align %d", DECL_ALIGN (node));
@@ -456,7 +433,7 @@ print_node (file, prefix, node, indent)
{
fprintf (file, "saved-insns ");
fprintf (file, HOST_PTR_PRINTF,
- (HOST_WIDE_INT) DECL_SAVED_INSNS (node));
+ (char *) DECL_SAVED_INSNS (node));
}
}
@@ -502,6 +479,7 @@ print_node (file, prefix, node, indent)
fprintf (file, " align %d", TYPE_ALIGN (node));
fprintf (file, " symtab %d", TYPE_SYMTAB_ADDRESS (node));
+ fprintf (file, " alias set %d", TYPE_ALIAS_SET (node));
print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4);
@@ -562,36 +540,18 @@ print_node (file, prefix, node, indent)
case '2':
case 'r':
case 's':
- switch (TREE_CODE (node))
+ if (TREE_CODE (node) == BIND_EXPR)
{
- case BIND_EXPR:
print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4);
print_node (file, "body", TREE_OPERAND (node, 1), indent + 4);
print_node (file, "block", TREE_OPERAND (node, 2), indent + 4);
return;
}
- first_rtl = len = tree_code_length[(int) TREE_CODE (node)];
- /* These kinds of nodes contain rtx's, not trees,
+ len = tree_code_length[(int) TREE_CODE (node)];
+ /* Some nodes contain rtx's, not trees,
after a certain point. Print the rtx's as rtx's. */
- switch (TREE_CODE (node))
- {
- case SAVE_EXPR:
- first_rtl = 2;
- break;
- case CALL_EXPR:
- first_rtl = 2;
- break;
- case METHOD_CALL_EXPR:
- first_rtl = 3;
- break;
- case WITH_CLEANUP_EXPR:
- /* Should be defined to be 2. */
- first_rtl = 1;
- break;
- case RTL_EXPR:
- first_rtl = 0;
- }
+ first_rtl = first_rtl_op (TREE_CODE (node));
for (i = 0; i < len; i++)
{
if (i >= first_rtl)
@@ -612,6 +572,15 @@ print_node (file, prefix, node, indent)
print_node (file, temp, TREE_OPERAND (node, i), indent + 4);
}
}
+
+ if (TREE_CODE (node) == EXPR_WITH_FILE_LOCATION)
+ {
+ indent_to (file, indent+4);
+ fprintf (file, "%s:%d:%d",
+ (EXPR_WFL_FILENAME_NODE (node ) ?
+ EXPR_WFL_FILENAME (node) : "(no file info)"),
+ EXPR_WFL_LINENO (node), EXPR_WFL_COLNO (node));
+ }
break;
case 'c':
@@ -622,38 +591,19 @@ print_node (file, prefix, node, indent)
if (TREE_CONSTANT_OVERFLOW (node))
fprintf (file, " overflow");
+ fprintf (file, " ");
if (TREE_INT_CST_HIGH (node) == 0)
- fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- " %1u",
-#else
- " %1lu",
-#endif
+ fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED,
TREE_INT_CST_LOW (node));
else if (TREE_INT_CST_HIGH (node) == -1
&& TREE_INT_CST_LOW (node) != 0)
- fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
- " -%1u",
-#else
- " -%1lu",
-#endif
- -TREE_INT_CST_LOW (node));
+ {
+ fprintf (file, "-");
+ fprintf (file, HOST_WIDE_INT_PRINT_UNSIGNED,
+ -TREE_INT_CST_LOW (node));
+ }
else
- fprintf (file,
-#if HOST_BITS_PER_WIDE_INT == 64
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
- " 0x%lx%016lx",
-#else
- " 0x%x%016x",
-#endif
-#else
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
- " 0x%lx%08lx",
-#else
- " 0x%x%08x",
-#endif
-#endif
+ fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
TREE_INT_CST_HIGH (node), TREE_INT_CST_LOW (node));
break;
@@ -729,6 +679,12 @@ print_node (file, prefix, node, indent)
case OP_IDENTIFIER:
print_node (file, "op1", TREE_PURPOSE (node), indent + 4);
print_node (file, "op2", TREE_VALUE (node), indent + 4);
+ break;
+
+ default:
+ if (TREE_CODE_CLASS (TREE_CODE (node)) == 'x')
+ lang_print_xnode (file, node, indent);
+ break;
}
break;
diff --git a/contrib/gcc/profile.c b/contrib/gcc/profile.c
new file mode 100644
index 0000000..b06f91b
--- /dev/null
+++ b/contrib/gcc/profile.c
@@ -0,0 +1,1702 @@
+/* Calculate branch probabilities, and basic block execution counts.
+ Copyright (C) 1990, 91-94, 96, 97, 1998 Free Software Foundation, Inc.
+ Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
+ based on some ideas from Dain Samples of UC Berkeley.
+ Further mangling by Bob Manson, Cygnus Support.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* ??? Really should not put insns inside of LIBCALL sequences, when putting
+ insns after a call, should look for the insn setting the retval, and
+ insert the insns after that one. */
+
+/* ??? Register allocation should use basic block execution counts to
+ give preference to the most commonly executed blocks. */
+
+/* ??? The .da files are not safe. Changing the program after creating .da
+ files or using different options when compiling with -fbranch-probabilities
+ can result the arc data not matching the program. Maybe add instrumented
+ arc count to .bbg file? Maybe check whether PFG matches the .bbg file? */
+
+/* ??? Should calculate branch probabilities before instrumenting code, since
+ then we can use arc counts to help decide which arcs to instrument. */
+
+/* ??? Rearrange code so that the most frequently executed arcs become from
+ one block to the next block (i.e. a fall through), move seldom executed
+ code outside of loops even at the expense of adding a few branches to
+ achieve this, see Dain Sample's UC Berkeley thesis. */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "flags.h"
+#include "insn-flags.h"
+#include "insn-config.h"
+#include "output.h"
+#include "regs.h"
+#include "tree.h"
+#include "output.h"
+#include "gcov-io.h"
+#include "toplev.h"
+
+extern char * xmalloc ();
+
+/* One of these is dynamically created whenever we identify an arc in the
+ function. */
+
+struct adj_list
+{
+ int source;
+ int target;
+ int arc_count;
+ unsigned int count_valid : 1;
+ unsigned int on_tree : 1;
+ unsigned int fake : 1;
+ unsigned int fall_through : 1;
+ rtx branch_insn;
+ struct adj_list *pred_next;
+ struct adj_list *succ_next;
+};
+
+#define ARC_TARGET(ARCPTR) (ARCPTR->target)
+#define ARC_SOURCE(ARCPTR) (ARCPTR->source)
+#define ARC_COUNT(ARCPTR) (ARCPTR->arc_count)
+
+/* Count the number of basic blocks, and create an array of these structures,
+ one for each bb in the function. */
+
+struct bb_info
+{
+ struct adj_list *succ;
+ struct adj_list *pred;
+ int succ_count;
+ int pred_count;
+ int exec_count;
+ unsigned int count_valid : 1;
+ unsigned int on_tree : 1;
+ rtx first_insn;
+};
+
+/* Indexed by label number, gives the basic block number containing that
+ label. */
+
+static int *label_to_bb;
+
+/* Number of valid entries in the label_to_bb array. */
+
+static int label_to_bb_size;
+
+/* Indexed by block index, holds the basic block graph. */
+
+static struct bb_info *bb_graph;
+
+/* Name and file pointer of the output file for the basic block graph. */
+
+static char *bbg_file_name;
+static FILE *bbg_file;
+
+/* Name and file pointer of the input file for the arc count data. */
+
+static char *da_file_name;
+static FILE *da_file;
+
+/* Pointer of the output file for the basic block/line number map. */
+static FILE *bb_file;
+
+/* Last source file name written to bb_file. */
+
+static char *last_bb_file_name;
+
+/* Indicates whether the next line number note should be output to
+ bb_file or not. Used to eliminate a redundant note after an
+ expanded inline function call. */
+
+static int ignore_next_note;
+
+/* Used by final, for allocating the proper amount of storage for the
+ instrumented arc execution counts. */
+
+int count_instrumented_arcs;
+
+/* Number of executions for the return label. */
+
+int return_label_execution_count;
+
+/* Collect statistics on the performance of this pass for the entire source
+ file. */
+
+static int total_num_blocks;
+static int total_num_arcs;
+static int total_num_arcs_instrumented;
+static int total_num_blocks_created;
+static int total_num_passes;
+static int total_num_times_called;
+static int total_hist_br_prob[20];
+static int total_num_never_executed;
+static int total_num_branches;
+
+/* Forward declarations. */
+static void init_arc PROTO((struct adj_list *, int, int, rtx));
+static void find_spanning_tree PROTO((int));
+static void expand_spanning_tree PROTO((int));
+static void fill_spanning_tree PROTO((int));
+static void init_arc_profiler PROTO((void));
+static void output_arc_profiler PROTO((int, rtx));
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+/* If non-zero, we need to output a constructor to set up the
+ per-object-file data. */
+static int need_func_profiler = 0;
+
+
+/* Add arc instrumentation code to the entire insn chain.
+
+ F is the first insn of the chain.
+ NUM_BLOCKS is the number of basic blocks found in F.
+ DUMP_FILE, if nonzero, is an rtl dump file we can write to. */
+
+static void
+instrument_arcs (f, num_blocks, dump_file)
+ rtx f;
+ int num_blocks;
+ FILE *dump_file;
+{
+ register int i;
+ register struct adj_list *arcptr, *backptr;
+ int num_arcs = 0;
+ int num_instr_arcs = 0;
+ rtx insn;
+
+ /* Instrument the program start. */
+ /* Handle block 0 specially, since it will always be instrumented,
+ but it doesn't have a valid first_insn or branch_insn. We must
+ put the instructions before the NOTE_INSN_FUNCTION_BEG note, so
+ that they don't clobber any of the parameters of the current
+ function. */
+ for (insn = f; insn; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG)
+ break;
+ insn = PREV_INSN (insn);
+ need_func_profiler = 1;
+ output_arc_profiler (total_num_arcs_instrumented + num_instr_arcs++, insn);
+
+ for (i = 1; i < num_blocks; i++)
+ for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
+ if (! arcptr->on_tree)
+ {
+ if (dump_file)
+ fprintf (dump_file, "Arc %d to %d instrumented\n", i,
+ ARC_TARGET (arcptr));
+
+ /* Check to see if this arc is the only exit from its source block,
+ or the only entrance to its target block. In either case,
+ we don't need to create a new block to instrument the arc. */
+
+ if (bb_graph[i].succ == arcptr && arcptr->succ_next == 0)
+ {
+ /* Instrument the source block. */
+ output_arc_profiler (total_num_arcs_instrumented
+ + num_instr_arcs++,
+ PREV_INSN (bb_graph[i].first_insn));
+ }
+ else if (arcptr == bb_graph[ARC_TARGET (arcptr)].pred
+ && arcptr->pred_next == 0)
+ {
+ /* Instrument the target block. */
+ output_arc_profiler (total_num_arcs_instrumented
+ + num_instr_arcs++,
+ PREV_INSN (bb_graph[ARC_TARGET (arcptr)].first_insn));
+ }
+ else if (arcptr->fall_through)
+ {
+ /* This is a fall-through; put the instrumentation code after
+ the branch that ends this block. */
+
+ for (backptr = bb_graph[i].succ; backptr;
+ backptr = backptr->succ_next)
+ if (backptr != arcptr)
+ break;
+
+ output_arc_profiler (total_num_arcs_instrumented
+ + num_instr_arcs++,
+ backptr->branch_insn);
+ }
+ else
+ {
+ /* Must emit a new basic block to hold the arc counting code. */
+ enum rtx_code code = GET_CODE (PATTERN (arcptr->branch_insn));
+
+ if (code == SET)
+ {
+ /* Create the new basic block right after the branch.
+ Invert the branch so that it jumps past the end of the new
+ block. The new block will consist of the instrumentation
+ code, and a jump to the target of this arc. */
+ int this_is_simplejump = simplejump_p (arcptr->branch_insn);
+ rtx new_label = gen_label_rtx ();
+ rtx old_label, set_src;
+ rtx after = arcptr->branch_insn;
+
+ /* Simplejumps can't reach here. */
+ if (this_is_simplejump)
+ abort ();
+
+ /* We can't use JUMP_LABEL, because it won't be set if we
+ are compiling without optimization. */
+
+ set_src = SET_SRC (single_set (arcptr->branch_insn));
+ if (GET_CODE (set_src) == LABEL_REF)
+ old_label = set_src;
+ else if (GET_CODE (set_src) != IF_THEN_ELSE)
+ abort ();
+ else if (XEXP (set_src, 1) == pc_rtx)
+ old_label = XEXP (XEXP (set_src, 2), 0);
+ else
+ old_label = XEXP (XEXP (set_src, 1), 0);
+
+ /* Set the JUMP_LABEL so that redirect_jump will work. */
+ JUMP_LABEL (arcptr->branch_insn) = old_label;
+
+ /* Add a use for OLD_LABEL that will be needed when we emit
+ the JUMP_INSN below. If we don't do this here,
+ `invert_jump' might delete it for us. We must add two
+ when not optimizing, because the NUSES is zero now,
+ but must be at least two to prevent the label from being
+ deleted. */
+ LABEL_NUSES (old_label) += 2;
+
+ /* Emit the insns for the new block in reverse order,
+ since that is most convenient. */
+
+ if (this_is_simplejump)
+ {
+ after = NEXT_INSN (arcptr->branch_insn);
+ if (! redirect_jump (arcptr->branch_insn, new_label))
+ /* Don't know what to do if this branch won't
+ redirect. */
+ abort ();
+ }
+ else
+ {
+ if (! invert_jump (arcptr->branch_insn, new_label))
+ /* Don't know what to do if this branch won't invert. */
+ abort ();
+
+ emit_label_after (new_label, after);
+ LABEL_NUSES (new_label)++;
+ }
+ emit_barrier_after (after);
+ emit_jump_insn_after (gen_jump (old_label), after);
+ JUMP_LABEL (NEXT_INSN (after)) = old_label;
+
+ /* Instrument the source arc. */
+ output_arc_profiler (total_num_arcs_instrumented
+ + num_instr_arcs++,
+ after);
+ if (this_is_simplejump)
+ {
+ emit_label_after (new_label, after);
+ LABEL_NUSES (new_label)++;
+ }
+ }
+ else if (code == ADDR_VEC || code == ADDR_DIFF_VEC)
+ {
+ /* A table jump. Create a new basic block immediately
+ after the table, by emitting a barrier, a label, a
+ counting note, and a jump to the old label. Put the
+ new label in the table. */
+
+ rtx new_label = gen_label_rtx ();
+ rtx old_lref, new_lref;
+ int index;
+
+ /* Must determine the old_label reference, do this
+ by counting the arcs after this one, which will
+ give the index of our label in the table. */
+
+ index = 0;
+ for (backptr = arcptr->succ_next; backptr;
+ backptr = backptr->succ_next)
+ index++;
+
+ old_lref = XVECEXP (PATTERN (arcptr->branch_insn),
+ (code == ADDR_DIFF_VEC), index);
+
+ /* Emit the insns for the new block in reverse order,
+ since that is most convenient. */
+ emit_jump_insn_after (gen_jump (XEXP (old_lref, 0)),
+ arcptr->branch_insn);
+ JUMP_LABEL (NEXT_INSN (arcptr->branch_insn))
+ = XEXP (old_lref, 0);
+
+ /* Instrument the source arc. */
+ output_arc_profiler (total_num_arcs_instrumented
+ + num_instr_arcs++,
+ arcptr->branch_insn);
+
+ emit_label_after (new_label, arcptr->branch_insn);
+ LABEL_NUSES (NEXT_INSN (arcptr->branch_insn))++;
+ emit_barrier_after (arcptr->branch_insn);
+
+ /* Fix up the table jump. */
+ new_lref = gen_rtx_LABEL_REF (Pmode, new_label);
+ XVECEXP (PATTERN (arcptr->branch_insn),
+ (code == ADDR_DIFF_VEC), index) = new_lref;
+ }
+ else
+ abort ();
+
+ num_arcs += 1;
+ if (dump_file)
+ fprintf (dump_file,
+ "Arc %d to %d needed new basic block\n", i,
+ ARC_TARGET (arcptr));
+ }
+ }
+
+ total_num_arcs_instrumented += num_instr_arcs;
+ count_instrumented_arcs = total_num_arcs_instrumented;
+
+ total_num_blocks_created += num_arcs;
+ if (dump_file)
+ {
+ fprintf (dump_file, "%d arcs instrumented\n", num_instr_arcs);
+ fprintf (dump_file, "%d extra basic blocks created\n", num_arcs);
+ }
+}
+
+/* Output STRING to bb_file, surrounded by DELIMITER. */
+
+static void
+output_gcov_string (string, delimiter)
+ char *string;
+ long delimiter;
+{
+ long temp;
+
+ /* Write a delimiter to indicate that a file name follows. */
+ __write_long (delimiter, bb_file, 4);
+
+ /* Write the string. */
+ temp = strlen (string) + 1;
+ fwrite (string, temp, 1, bb_file);
+
+ /* Append a few zeros, to align the output to a 4 byte boundary. */
+ temp = temp & 0x3;
+ if (temp)
+ {
+ char c[4];
+
+ c[0] = c[1] = c[2] = c[3] = 0;
+ fwrite (c, sizeof (char), 4 - temp, bb_file);
+ }
+
+ /* Store another delimiter in the .bb file, just to make it easy to find the
+ end of the file name. */
+ __write_long (delimiter, bb_file, 4);
+}
+
+/* Return TRUE if this insn must be a tablejump entry insn. This works for
+ the MIPS port, but may give false negatives for some targets. */
+
+int
+tablejump_entry_p (insn, label)
+ rtx insn, label;
+{
+ rtx next = next_active_insn (insn);
+ enum rtx_code code = GET_CODE (PATTERN (next));
+
+ if (code != ADDR_DIFF_VEC && code != ADDR_VEC)
+ return 0;
+
+ if (PREV_INSN (next) == XEXP (label, 0))
+ return 1;
+
+ return 0;
+}
+
+/* Instrument and/or analyze program behavior based on program flow graph.
+ In either case, this function builds a flow graph for the function being
+ compiled. The flow graph is stored in BB_GRAPH.
+
+ When FLAG_PROFILE_ARCS is nonzero, this function instruments the arcs in
+ the flow graph that are needed to reconstruct the dynamic behavior of the
+ flow graph.
+
+ When FLAG_BRANCH_PROBABILITIES is nonzero, this function reads auxiliary
+ information from a data file containing arc count information from previous
+ executions of the function being compiled. In this case, the flow graph is
+ annotated with actual execution counts, which are later propagated into the
+ rtl for optimization purposes.
+
+ Main entry point of this file. */
+
+void
+branch_prob (f, dump_file)
+ rtx f;
+ FILE *dump_file;
+{
+ int i, num_blocks;
+ struct adj_list *arcptr;
+ int num_arcs, changes, passes;
+ int total, prob;
+ int hist_br_prob[20], num_never_executed, num_branches;
+ /* Set to non-zero if we got bad count information. */
+ int bad_counts = 0;
+
+ /* start of a function. */
+ if (flag_test_coverage)
+ output_gcov_string (current_function_name, (long) -2);
+
+ /* Execute this only if doing arc profiling or branch probabilities. */
+ if (! profile_arc_flag && ! flag_branch_probabilities
+ && ! flag_test_coverage)
+ abort ();
+
+ total_num_times_called++;
+
+ /* Create an array label_to_bb of ints of size max_label_num. */
+ label_to_bb_size = max_label_num ();
+ label_to_bb = (int *) oballoc (label_to_bb_size * sizeof (int));
+ bzero ((char *) label_to_bb, label_to_bb_size * sizeof (int));
+
+ /* Scan the insns in the function, count the number of basic blocks
+ present. When a code label is passed, set label_to_bb[label] = bb
+ number. */
+
+ /* The first block found will be block 1, so that function entry can be
+ block 0. */
+
+ {
+ register RTX_CODE prev_code = JUMP_INSN;
+ register RTX_CODE code;
+ register rtx insn;
+ register int i;
+ int block_separator_emitted = 0;
+
+ ignore_next_note = 0;
+
+ for (insn = NEXT_INSN (f), i = 0; insn; insn = NEXT_INSN (insn))
+ {
+ code = GET_CODE (insn);
+
+ if (code == BARRIER)
+ ;
+ else if (code == CODE_LABEL)
+ /* This label is part of the next block, but we can't increment
+ block number yet since there might be multiple labels. */
+ label_to_bb[CODE_LABEL_NUMBER (insn)] = i + 1;
+ /* We make NOTE_INSN_SETJMP notes into a block of their own, so that
+ they can be the target of the fake arc for the setjmp call.
+ This avoids creating cycles of fake arcs, which would happen if
+ the block after the setjmp call contained a call insn. */
+ else if ((prev_code == JUMP_INSN || prev_code == CALL_INSN
+ || prev_code == CODE_LABEL || prev_code == BARRIER)
+ && (GET_RTX_CLASS (code) == 'i'
+ || (code == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)))
+ {
+ i += 1;
+
+ /* Emit the block separator if it hasn't already been emitted. */
+ if (flag_test_coverage && ! block_separator_emitted)
+ {
+ /* Output a zero to the .bb file to indicate that a new
+ block list is starting. */
+ __write_long (0, bb_file, 4);
+ }
+ block_separator_emitted = 0;
+ }
+ /* If flag_test_coverage is true, then we must add an entry to the
+ .bb file for every note. */
+ else if (code == NOTE && flag_test_coverage)
+ {
+ /* Must ignore the line number notes that immediately follow the
+ end of an inline function to avoid counting it twice. There
+ is a note before the call, and one after the call. */
+ if (NOTE_LINE_NUMBER (insn) == NOTE_REPEATED_LINE_NUMBER)
+ ignore_next_note = 1;
+ else if (NOTE_LINE_NUMBER (insn) > 0)
+ {
+ if (ignore_next_note)
+ ignore_next_note = 0;
+ else
+ {
+ /* Emit a block separator here to ensure that a NOTE
+ immediately following a JUMP_INSN or CALL_INSN will end
+ up in the right basic block list. */
+ if ((prev_code == JUMP_INSN || prev_code == CALL_INSN
+ || prev_code == CODE_LABEL || prev_code == BARRIER)
+ && ! block_separator_emitted)
+ {
+ /* Output a zero to the .bb file to indicate that
+ a new block list is starting. */
+ __write_long (0, bb_file, 4);
+
+ block_separator_emitted = 1;
+ }
+
+ /* If this is a new source file, then output the file's
+ name to the .bb file. */
+ if (! last_bb_file_name
+ || strcmp (NOTE_SOURCE_FILE (insn),
+ last_bb_file_name))
+ {
+ if (last_bb_file_name)
+ free (last_bb_file_name);
+ last_bb_file_name
+ = xmalloc (strlen (NOTE_SOURCE_FILE (insn)) + 1);
+ strcpy (last_bb_file_name, NOTE_SOURCE_FILE (insn));
+ output_gcov_string (NOTE_SOURCE_FILE (insn), (long)-1);
+ }
+
+ /* Output the line number to the .bb file. Must be done
+ after the output_bb_profile_data() call, and after the
+ file name is written, to ensure that it is correctly
+ handled by gcov. */
+ __write_long (NOTE_LINE_NUMBER (insn), bb_file, 4);
+ }
+ }
+ }
+
+ if (code != NOTE)
+ prev_code = code;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+ prev_code = CALL_INSN;
+ }
+
+ /* Allocate last `normal' entry for bb_graph. */
+
+ /* The last insn was a jump, call, or label. In that case we have
+ a block at the end of the function with no insns. */
+ if (prev_code == JUMP_INSN || prev_code == CALL_INSN
+ || prev_code == CODE_LABEL || prev_code == BARRIER)
+ {
+ i++;
+
+ /* Emit the block separator if it hasn't already been emitted. */
+ if (flag_test_coverage && ! block_separator_emitted)
+ {
+ /* Output a zero to the .bb file to indicate that a new
+ block list is starting. */
+ __write_long (0, bb_file, 4);
+ }
+ }
+
+ /* Create another block to stand for EXIT, and make all return insns, and
+ the last basic block point here. Add one more to account for block
+ zero. */
+ num_blocks = i + 2;
+ }
+
+ total_num_blocks += num_blocks;
+ if (dump_file)
+ fprintf (dump_file, "%d basic blocks\n", num_blocks);
+
+ /* If we are only doing test coverage here, then return now. */
+ if (! profile_arc_flag && ! flag_branch_probabilities)
+ return;
+
+ /* Create and initialize the arrays that will hold bb_graph
+ and execution count info. */
+
+ bb_graph = (struct bb_info *) alloca (num_blocks * sizeof (struct bb_info));
+ bzero ((char *) bb_graph, (sizeof (struct bb_info) * num_blocks));
+
+ {
+ /* Scan the insns again:
+ - at the entry to each basic block, increment the predecessor count
+ (and successor of previous block) if it is a fall through entry,
+ create adj_list entries for this and the previous block
+ - at each jump insn, increment predecessor/successor counts for
+ target/source basic blocks, add this insn to pred/succ lists.
+
+ This also cannot be broken out as a separate subroutine
+ because it uses `alloca'. */
+
+ register RTX_CODE prev_code = JUMP_INSN;
+ register RTX_CODE code;
+ register rtx insn;
+ register int i;
+ int fall_through = 0;
+ struct adj_list *arcptr;
+ int dest = 0;
+
+ /* Block 0 always falls through to block 1. */
+ num_arcs = 0;
+ arcptr = (struct adj_list *) alloca (sizeof (struct adj_list));
+ init_arc (arcptr, 0, 1, 0);
+ arcptr->fall_through = 1;
+ num_arcs++;
+
+ /* Add a fake fall through arc from the last block to block 0, to make the
+ graph complete. */
+ arcptr = (struct adj_list *) alloca (sizeof (struct adj_list));
+ init_arc (arcptr, num_blocks - 1, 0, 0);
+ arcptr->fake = 1;
+ num_arcs++;
+
+ /* Exit must be one node of the graph, and all exits from the function
+ must point there. When see a return branch, must point the arc to the
+ exit node. */
+
+ /* Must start scan with second insn in function as above. */
+ for (insn = NEXT_INSN (f), i = 0; insn; insn = NEXT_INSN (insn))
+ {
+ code = GET_CODE (insn);
+
+ if (code == BARRIER)
+ fall_through = 0;
+ else if (code == CODE_LABEL)
+ ;
+ /* We make NOTE_INSN_SETJMP notes into a block of their own, so that
+ they can be the target of the fake arc for the setjmp call.
+ This avoids creating cycles of fake arcs, which would happen if
+ the block after the setjmp call ended with a call. */
+ else if ((prev_code == JUMP_INSN || prev_code == CALL_INSN
+ || prev_code == CODE_LABEL || prev_code == BARRIER)
+ && (GET_RTX_CLASS (code) == 'i'
+ || (code == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)))
+ {
+ /* This is the first insn of the block. */
+ i += 1;
+ if (fall_through)
+ {
+ arcptr = (struct adj_list *) alloca (sizeof (struct adj_list));
+ init_arc (arcptr, i - 1, i, 0);
+ arcptr->fall_through = 1;
+
+ num_arcs++;
+ }
+ fall_through = 1;
+ bb_graph[i].first_insn = insn;
+ }
+ else if (code == NOTE)
+ {;}
+
+ if (code == CALL_INSN)
+ {
+ /* In the normal case, the call returns, and this is just like
+ a branch fall through. */
+ fall_through = 1;
+
+ /* Setjmp may return more times than called, so to make the graph
+ solvable, add a fake arc from the function entrance to the
+ next block.
+
+ All other functions may return fewer times than called (if
+ a descendent call longjmp or exit), so to make the graph
+ solvable, add a fake arc to the function exit from the
+ current block.
+
+ Distinguish the cases by checking for a SETJUMP note.
+ A call_insn can be the last ins of a function, so must check
+ to see if next insn actually exists. */
+ arcptr = (struct adj_list *) alloca (sizeof (struct adj_list));
+ if (NEXT_INSN (insn)
+ && GET_CODE (NEXT_INSN (insn)) == NOTE
+ && NOTE_LINE_NUMBER (NEXT_INSN (insn)) == NOTE_INSN_SETJMP)
+ init_arc (arcptr, 0, i+1, insn);
+ else
+ init_arc (arcptr, i, num_blocks-1, insn);
+ arcptr->fake = 1;
+ num_arcs++;
+ }
+ else if (code == JUMP_INSN)
+ {
+ rtx tem, pattern = PATTERN (insn);
+ rtx tablejump = 0;
+
+ /* If running without optimization, then jump label won't be valid,
+ so we must search for the destination label in that case.
+ We have to handle tablejumps and returns specially anyways, so
+ we don't check the JUMP_LABEL at all here. */
+
+ /* ??? This code should be rewritten. We need a more elegant way
+ to find the LABEL_REF. We need a more elegant way to
+ differentiate tablejump entries from computed gotos.
+ We should perhaps reuse code from flow to compute the CFG
+ instead of trying to compute it here.
+
+ We can't use current_function_has_computed_jump, because that
+ is calculated later by flow. We can't use computed_jump_p,
+ because that returns true for tablejump entry insns for some
+ targets, e.g. HPPA and MIPS. */
+
+ if (GET_CODE (pattern) == PARALLEL)
+ {
+ /* This assumes that PARALLEL jumps with a USE are
+ tablejump entry jumps. The same assumption can be found
+ in computed_jump_p. */
+ /* Make an arc from this jump to the label of the
+ jump table. This will instrument the number of
+ times the switch statement is executed. */
+ if (GET_CODE (XVECEXP (pattern, 0, 1)) == USE)
+ {
+ tem = XEXP (XVECEXP (pattern, 0, 1), 0);
+ if (GET_CODE (tem) != LABEL_REF)
+ abort ();
+ dest = label_to_bb[CODE_LABEL_NUMBER (XEXP (tem, 0))];
+ }
+ else if (GET_CODE (XVECEXP (pattern, 0, 0)) == SET
+ && SET_DEST (XVECEXP (pattern, 0, 0)) == pc_rtx)
+ {
+ tem = SET_SRC (XVECEXP (pattern, 0, 0));
+ if (GET_CODE (tem) == PLUS
+ && GET_CODE (XEXP (tem, 1)) == LABEL_REF)
+ {
+ tem = XEXP (tem, 1);
+ dest = label_to_bb [CODE_LABEL_NUMBER (XEXP (tem, 0))];
+ }
+ }
+ else
+ abort ();
+ }
+ else if (GET_CODE (pattern) == ADDR_VEC
+ || GET_CODE (pattern) == ADDR_DIFF_VEC)
+ tablejump = pattern;
+ else if (GET_CODE (pattern) == RETURN)
+ dest = num_blocks - 1;
+ else if (GET_CODE (pattern) != SET)
+ abort ();
+ else if ((tem = SET_SRC (pattern))
+ && GET_CODE (tem) == LABEL_REF)
+ dest = label_to_bb[CODE_LABEL_NUMBER (XEXP (tem, 0))];
+ /* Recognize HPPA table jump entry. This code is similar to
+ the code above in the PARALLEL case. */
+ else if (GET_CODE (tem) == PLUS
+ && GET_CODE (XEXP (tem, 0)) == MEM
+ && GET_CODE (XEXP (XEXP (tem, 0), 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (XEXP (tem, 0), 0), 0)) == PC
+ && GET_CODE (XEXP (tem, 1)) == LABEL_REF
+ && tablejump_entry_p (insn, XEXP (tem, 1)))
+ dest = label_to_bb[CODE_LABEL_NUMBER (XEXP (XEXP (tem, 1), 0))];
+ /* Recognize the MIPS table jump entry. */
+ else if (GET_CODE (tem) == PLUS
+ && GET_CODE (XEXP (tem, 0)) == REG
+ && GET_CODE (XEXP (tem, 1)) == LABEL_REF
+ && tablejump_entry_p (insn, XEXP (tem, 1)))
+ dest = label_to_bb[CODE_LABEL_NUMBER (XEXP (XEXP (tem, 1), 0))];
+ else
+ {
+ rtx label_ref;
+
+ /* Must be an IF_THEN_ELSE branch. If it isn't, assume it
+ is a computed goto, which aren't supported yet. */
+ if (GET_CODE (tem) != IF_THEN_ELSE)
+ fatal ("-fprofile-arcs does not support computed gotos");
+ if (XEXP (tem, 1) != pc_rtx)
+ label_ref = XEXP (tem, 1);
+ else
+ label_ref = XEXP (tem, 2);
+ dest = label_to_bb[CODE_LABEL_NUMBER (XEXP (label_ref, 0))];
+ }
+
+ if (tablejump)
+ {
+ int diff_vec_p = GET_CODE (tablejump) == ADDR_DIFF_VEC;
+ int len = XVECLEN (tablejump, diff_vec_p);
+ int k;
+
+ for (k = 0; k < len; k++)
+ {
+ rtx tem = XEXP (XVECEXP (tablejump, diff_vec_p, k), 0);
+ dest = label_to_bb[CODE_LABEL_NUMBER (tem)];
+
+ arcptr = (struct adj_list *) alloca (sizeof(struct adj_list));
+ init_arc (arcptr, i, dest, insn);
+
+ num_arcs++;
+ }
+ }
+ else
+ {
+ arcptr = (struct adj_list *) alloca (sizeof (struct adj_list));
+ init_arc (arcptr, i, dest, insn);
+
+ num_arcs++;
+ }
+
+ /* Determine whether or not this jump will fall through.
+ Unconditional jumps and returns are not always followed by
+ barriers. */
+ pattern = PATTERN (insn);
+ if (GET_CODE (pattern) == PARALLEL
+ || GET_CODE (pattern) == RETURN)
+ fall_through = 0;
+ else if (GET_CODE (pattern) == ADDR_VEC
+ || GET_CODE (pattern) == ADDR_DIFF_VEC)
+ /* These aren't actually jump insns, but they never fall
+ through, so... */
+ fall_through = 0;
+ else
+ {
+ if (GET_CODE (pattern) != SET || SET_DEST (pattern) != pc_rtx)
+ abort ();
+ if (GET_CODE (SET_SRC (pattern)) != IF_THEN_ELSE)
+ fall_through = 0;
+ }
+ }
+
+ if (code != NOTE)
+ prev_code = code;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+ {
+ /* Make a fake insn to tag our notes on. */
+ bb_graph[i].first_insn = insn
+ = emit_insn_after (gen_rtx_USE (VOIDmode, stack_pointer_rtx),
+ insn);
+ prev_code = CALL_INSN;
+ }
+ }
+
+ /* If the code at the end of the function would give a new block, then
+ do the following. */
+
+ if (prev_code == JUMP_INSN || prev_code == CALL_INSN
+ || prev_code == CODE_LABEL || prev_code == BARRIER)
+ {
+ if (fall_through)
+ {
+ arcptr = (struct adj_list *) alloca (sizeof (struct adj_list));
+ init_arc (arcptr, i, i + 1, 0);
+ arcptr->fall_through = 1;
+
+ num_arcs++;
+ }
+
+ /* This may not be a real insn, but that should not cause a problem. */
+ bb_graph[i+1].first_insn = get_last_insn ();
+ }
+
+ /* There is always a fake arc from the last block of the function
+ to the function exit block. */
+ arcptr = (struct adj_list *) alloca (sizeof (struct adj_list));
+ init_arc (arcptr, num_blocks-2, num_blocks-1, 0);
+ arcptr->fake = 1;
+ num_arcs++;
+ }
+
+ total_num_arcs += num_arcs;
+ if (dump_file)
+ fprintf (dump_file, "%d arcs\n", num_arcs);
+
+ /* Create spanning tree from basic block graph, mark each arc that is
+ on the spanning tree. */
+
+ /* To reduce the instrumentation cost, make two passes over the tree.
+ First, put as many must-split (crowded and fake) arcs on the tree as
+ possible, then on the second pass fill in the rest of the tree.
+ Note that the spanning tree is considered undirected, so that as many
+ must-split arcs as possible can be put on it.
+
+ Fallthrough arcs which are crowded should not be chosen on the first
+ pass, since they do not require creating a new basic block. These
+ arcs will have fall_through set. */
+
+ find_spanning_tree (num_blocks);
+
+ /* Create a .bbg file from which gcov can reconstruct the basic block
+ graph. First output the number of basic blocks, and then for every
+ arc output the source and target basic block numbers.
+ NOTE: The format of this file must be compatible with gcov. */
+
+ if (flag_test_coverage)
+ {
+ int flag_bits;
+
+ __write_long (num_blocks, bbg_file, 4);
+ __write_long (num_arcs, bbg_file, 4);
+
+ for (i = 0; i < num_blocks; i++)
+ {
+ long count = 0;
+ for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
+ count++;
+ __write_long (count, bbg_file, 4);
+
+ for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
+ {
+ flag_bits = 0;
+ if (arcptr->on_tree)
+ flag_bits |= 0x1;
+ if (arcptr->fake)
+ flag_bits |= 0x2;
+ if (arcptr->fall_through)
+ flag_bits |= 0x4;
+
+ __write_long (ARC_TARGET (arcptr), bbg_file, 4);
+ __write_long (flag_bits, bbg_file, 4);
+ }
+ }
+
+ /* Emit a -1 to separate the list of all arcs from the list of
+ loop back edges that follows. */
+ __write_long (-1, bbg_file, 4);
+ }
+
+ /* For each arc not on the spanning tree, add counting code as rtl. */
+
+ if (profile_arc_flag)
+ {
+ instrument_arcs (f, num_blocks, dump_file);
+ allocate_reg_info (max_reg_num (), FALSE, FALSE);
+ }
+
+ /* Execute the rest only if doing branch probabilities. */
+ if (! flag_branch_probabilities)
+ return;
+
+ /* For each arc not on the spanning tree, set its execution count from
+ the .da file. */
+
+ /* The first count in the .da file is the number of times that the function
+ was entered. This is the exec_count for block zero. */
+
+ num_arcs = 0;
+ for (i = 0; i < num_blocks; i++)
+ for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
+ if (! arcptr->on_tree)
+ {
+ num_arcs++;
+ if (da_file)
+ {
+ long value;
+ __read_long (&value, da_file, 8);
+ ARC_COUNT (arcptr) = value;
+ }
+ else
+ ARC_COUNT (arcptr) = 0;
+ arcptr->count_valid = 1;
+ bb_graph[i].succ_count--;
+ bb_graph[ARC_TARGET (arcptr)].pred_count--;
+ }
+
+ if (dump_file)
+ fprintf (dump_file, "%d arc counts read\n", num_arcs);
+
+ /* For every block in the file,
+ - if every exit/entrance arc has a known count, then set the block count
+ - if the block count is known, and every exit/entrance arc but one has
+ a known execution count, then set the count of the remaining arc
+
+ As arc counts are set, decrement the succ/pred count, but don't delete
+ the arc, that way we can easily tell when all arcs are known, or only
+ one arc is unknown. */
+
+ /* The order that the basic blocks are iterated through is important.
+ Since the code that finds spanning trees starts with block 0, low numbered
+ arcs are put on the spanning tree in preference to high numbered arcs.
+ Hence, most instrumented arcs are at the end. Graph solving works much
+ faster if we propagate numbers from the end to the start.
+
+ This takes an average of slightly more than 3 passes. */
+
+ changes = 1;
+ passes = 0;
+ while (changes)
+ {
+ passes++;
+ changes = 0;
+
+ for (i = num_blocks - 1; i >= 0; i--)
+ {
+ struct bb_info *binfo = &bb_graph[i];
+ if (! binfo->count_valid)
+ {
+ if (binfo->succ_count == 0)
+ {
+ total = 0;
+ for (arcptr = binfo->succ; arcptr;
+ arcptr = arcptr->succ_next)
+ total += ARC_COUNT (arcptr);
+ binfo->exec_count = total;
+ binfo->count_valid = 1;
+ changes = 1;
+ }
+ else if (binfo->pred_count == 0)
+ {
+ total = 0;
+ for (arcptr = binfo->pred; arcptr;
+ arcptr = arcptr->pred_next)
+ total += ARC_COUNT (arcptr);
+ binfo->exec_count = total;
+ binfo->count_valid = 1;
+ changes = 1;
+ }
+ }
+ if (binfo->count_valid)
+ {
+ if (binfo->succ_count == 1)
+ {
+ total = 0;
+ /* One of the counts will be invalid, but it is zero,
+ so adding it in also doesn't hurt. */
+ for (arcptr = binfo->succ; arcptr;
+ arcptr = arcptr->succ_next)
+ total += ARC_COUNT (arcptr);
+ /* Calculate count for remaining arc by conservation. */
+ total = binfo->exec_count - total;
+ /* Search for the invalid arc, and set its count. */
+ for (arcptr = binfo->succ; arcptr;
+ arcptr = arcptr->succ_next)
+ if (! arcptr->count_valid)
+ break;
+ if (! arcptr)
+ abort ();
+ arcptr->count_valid = 1;
+ ARC_COUNT (arcptr) = total;
+ binfo->succ_count--;
+
+ bb_graph[ARC_TARGET (arcptr)].pred_count--;
+ changes = 1;
+ }
+ if (binfo->pred_count == 1)
+ {
+ total = 0;
+ /* One of the counts will be invalid, but it is zero,
+ so adding it in also doesn't hurt. */
+ for (arcptr = binfo->pred; arcptr;
+ arcptr = arcptr->pred_next)
+ total += ARC_COUNT (arcptr);
+ /* Calculate count for remaining arc by conservation. */
+ total = binfo->exec_count - total;
+ /* Search for the invalid arc, and set its count. */
+ for (arcptr = binfo->pred; arcptr;
+ arcptr = arcptr->pred_next)
+ if (! arcptr->count_valid)
+ break;
+ if (! arcptr)
+ abort ();
+ arcptr->count_valid = 1;
+ ARC_COUNT (arcptr) = total;
+ binfo->pred_count--;
+
+ bb_graph[ARC_SOURCE (arcptr)].succ_count--;
+ changes = 1;
+ }
+ }
+ }
+ }
+
+ total_num_passes += passes;
+ if (dump_file)
+ fprintf (dump_file, "Graph solving took %d passes.\n\n", passes);
+
+ /* If the graph has been correctly solved, every block will have a
+ succ and pred count of zero. */
+ for (i = 0; i < num_blocks; i++)
+ {
+ struct bb_info *binfo = &bb_graph[i];
+ if (binfo->succ_count || binfo->pred_count)
+ abort ();
+ }
+
+ /* For every arc, calculate its branch probability and add a reg_note
+ to the branch insn to indicate this. */
+
+ for (i = 0; i < 20; i++)
+ hist_br_prob[i] = 0;
+ num_never_executed = 0;
+ num_branches = 0;
+
+ for (i = 0; i < num_blocks; i++)
+ {
+ struct bb_info *binfo = &bb_graph[i];
+
+ total = binfo->exec_count;
+ for (arcptr = binfo->succ; arcptr; arcptr = arcptr->succ_next)
+ {
+ if (arcptr->branch_insn)
+ {
+ /* This calculates the branch probability as an integer between
+ 0 and REG_BR_PROB_BASE, properly rounded to the nearest
+ integer. Perform the arithmetic in double to avoid
+ overflowing the range of ints. */
+
+ if (total == 0)
+ prob = -1;
+ else
+ {
+ rtx pat = PATTERN (arcptr->branch_insn);
+
+ prob = (((double)ARC_COUNT (arcptr) * REG_BR_PROB_BASE)
+ + (total >> 1)) / total;
+ if (prob < 0 || prob > REG_BR_PROB_BASE)
+ {
+ if (dump_file)
+ fprintf (dump_file, "bad count: prob for %d-%d thought to be %d (forcibly normalized)\n",
+ ARC_SOURCE (arcptr), ARC_TARGET (arcptr),
+ prob);
+
+ bad_counts = 1;
+ prob = REG_BR_PROB_BASE / 2;
+ }
+
+ /* Match up probability with JUMP pattern. */
+
+ if (GET_CODE (pat) == SET
+ && GET_CODE (SET_SRC (pat)) == IF_THEN_ELSE)
+ {
+ if (ARC_TARGET (arcptr) == ARC_SOURCE (arcptr) + 1)
+ {
+ /* A fall through arc should never have a
+ branch insn. */
+ abort ();
+ }
+ else
+ {
+ /* This is the arc for the taken branch. */
+ if (GET_CODE (XEXP (SET_SRC (pat), 2)) != PC)
+ prob = REG_BR_PROB_BASE - prob;
+ }
+ }
+ }
+
+ if (prob == -1)
+ num_never_executed++;
+ else
+ {
+ int index = prob * 20 / REG_BR_PROB_BASE;
+ if (index == 20)
+ index = 19;
+ hist_br_prob[index]++;
+ }
+ num_branches++;
+
+ REG_NOTES (arcptr->branch_insn)
+ = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (prob),
+ REG_NOTES (arcptr->branch_insn));
+ }
+ }
+
+ /* Add a REG_EXEC_COUNT note to the first instruction of this block. */
+ if (! binfo->first_insn
+ || GET_RTX_CLASS (GET_CODE (binfo->first_insn)) != 'i')
+ {
+ /* Block 0 is a fake block representing function entry, and does
+ not have a real first insn. The second last block might not
+ begin with a real insn. */
+ if (i == num_blocks - 1)
+ return_label_execution_count = total;
+ else if (i != 0 && i != num_blocks - 2)
+ abort ();
+ }
+ else
+ {
+ REG_NOTES (binfo->first_insn)
+ = gen_rtx_EXPR_LIST (REG_EXEC_COUNT, GEN_INT (total),
+ REG_NOTES (binfo->first_insn));
+ if (i == num_blocks - 1)
+ return_label_execution_count = total;
+ }
+ }
+
+ /* This should never happen. */
+ if (bad_counts)
+ warning ("Arc profiling: some arc counts were bad.");
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "%d branches\n", num_branches);
+ fprintf (dump_file, "%d branches never executed\n",
+ num_never_executed);
+ if (num_branches)
+ for (i = 0; i < 10; i++)
+ fprintf (dump_file, "%d%% branches in range %d-%d%%\n",
+ (hist_br_prob[i]+hist_br_prob[19-i])*100/num_branches,
+ 5*i, 5*i+5);
+
+ total_num_branches += num_branches;
+ total_num_never_executed += num_never_executed;
+ for (i = 0; i < 20; i++)
+ total_hist_br_prob[i] += hist_br_prob[i];
+ }
+
+}
+
+/* Initialize a new arc.
+ ARCPTR is the empty adj_list this function fills in.
+ SOURCE is the block number of the source block.
+ TARGET is the block number of the target block.
+ INSN is the insn which transfers control from SOURCE to TARGET,
+ or zero if the transfer is implicit. */
+
+static void
+init_arc (arcptr, source, target, insn)
+ struct adj_list *arcptr;
+ int source, target;
+ rtx insn;
+{
+ ARC_TARGET (arcptr) = target;
+ ARC_SOURCE (arcptr) = source;
+
+ ARC_COUNT (arcptr) = 0;
+ arcptr->count_valid = 0;
+ arcptr->on_tree = 0;
+ arcptr->fake = 0;
+ arcptr->fall_through = 0;
+ arcptr->branch_insn = insn;
+
+ arcptr->succ_next = bb_graph[source].succ;
+ bb_graph[source].succ = arcptr;
+ bb_graph[source].succ_count++;
+
+ arcptr->pred_next = bb_graph[target].pred;
+ bb_graph[target].pred = arcptr;
+ bb_graph[target].pred_count++;
+}
+
+/* This function searches all of the arcs in the program flow graph, and puts
+ as many bad arcs as possible onto the spanning tree. Bad arcs include
+ fake arcs (needed for setjmp(), longjmp(), exit()) which MUST be on the
+ spanning tree as they can't be instrumented. Also, arcs which must be
+ split when instrumented should be part of the spanning tree if possible. */
+
+static void
+find_spanning_tree (num_blocks)
+ int num_blocks;
+{
+ int i;
+ struct adj_list *arcptr;
+ struct bb_info *binfo = &bb_graph[0];
+
+ /* Fake arcs must be part of the spanning tree, and are always safe to put
+ on the spanning tree. Fake arcs will either be a successor of node 0,
+ a predecessor of the last node, or from the last node to node 0. */
+
+ for (arcptr = bb_graph[0].succ; arcptr; arcptr = arcptr->succ_next)
+ if (arcptr->fake)
+ {
+ /* Adding this arc should never cause a cycle. This is a fatal
+ error if it would. */
+ if (bb_graph[ARC_TARGET (arcptr)].on_tree && binfo->on_tree)
+ abort();
+ else
+ {
+ arcptr->on_tree = 1;
+ bb_graph[ARC_TARGET (arcptr)].on_tree = 1;
+ binfo->on_tree = 1;
+ }
+ }
+
+ binfo = &bb_graph[num_blocks-1];
+ for (arcptr = binfo->pred; arcptr; arcptr = arcptr->pred_next)
+ if (arcptr->fake)
+ {
+ /* Adding this arc should never cause a cycle. This is a fatal
+ error if it would. */
+ if (bb_graph[ARC_SOURCE (arcptr)].on_tree && binfo->on_tree)
+ abort();
+ else
+ {
+ arcptr->on_tree = 1;
+ bb_graph[ARC_SOURCE (arcptr)].on_tree = 1;
+ binfo->on_tree = 1;
+ }
+ }
+ /* The only entrace to node zero is a fake arc. */
+ bb_graph[0].pred->on_tree = 1;
+
+ /* Arcs which are crowded at both the source and target should be put on
+ the spanning tree if possible, except for fall_throuch arcs which never
+ require adding a new block even if crowded, add arcs with the same source
+ and dest which must always be instrumented. */
+ for (i = 0; i < num_blocks; i++)
+ {
+ binfo = &bb_graph[i];
+
+ for (arcptr = binfo->succ; arcptr; arcptr = arcptr->succ_next)
+ if (! ((binfo->succ == arcptr && arcptr->succ_next == 0)
+ || (bb_graph[ARC_TARGET (arcptr)].pred
+ && arcptr->pred_next == 0))
+ && ! arcptr->fall_through
+ && ARC_TARGET (arcptr) != i)
+ {
+ /* This is a crowded arc at both source and target. Try to put
+ in on the spanning tree. Can do this if either the source or
+ target block is not yet on the tree. */
+ if (! bb_graph[ARC_TARGET (arcptr)].on_tree || ! binfo->on_tree)
+ {
+ arcptr->on_tree = 1;
+ bb_graph[ARC_TARGET (arcptr)].on_tree = 1;
+ binfo->on_tree = 1;
+ }
+ }
+ }
+
+ /* Clear all of the basic block on_tree bits, so that we can use them to
+ create the spanning tree. */
+ for (i = 0; i < num_blocks; i++)
+ bb_graph[i].on_tree = 0;
+
+ /* Now fill in the spanning tree until every basic block is on it.
+ Don't put the 0 to 1 fall through arc on the tree, since it is
+ always cheap to instrument, so start filling the tree from node 1. */
+
+ for (i = 1; i < num_blocks; i++)
+ for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
+ if (! arcptr->on_tree
+ && ! bb_graph[ARC_TARGET (arcptr)].on_tree)
+ {
+ fill_spanning_tree (i);
+ break;
+ }
+}
+
+/* Add arcs reached from BLOCK to the spanning tree if they are needed and
+ not already there. */
+
+static void
+fill_spanning_tree (block)
+ int block;
+{
+ struct adj_list *arcptr;
+
+ expand_spanning_tree (block);
+
+ for (arcptr = bb_graph[block].succ; arcptr; arcptr = arcptr->succ_next)
+ if (! arcptr->on_tree
+ && ! bb_graph[ARC_TARGET (arcptr)].on_tree)
+ {
+ arcptr->on_tree = 1;
+ fill_spanning_tree (ARC_TARGET (arcptr));
+ }
+}
+
+/* When first visit a block, must add all blocks that are already connected
+ to this block via tree arcs to the spanning tree. */
+
+static void
+expand_spanning_tree (block)
+ int block;
+{
+ struct adj_list *arcptr;
+
+ bb_graph[block].on_tree = 1;
+
+ for (arcptr = bb_graph[block].succ; arcptr; arcptr = arcptr->succ_next)
+ if (arcptr->on_tree && ! bb_graph[ARC_TARGET (arcptr)].on_tree)
+ expand_spanning_tree (ARC_TARGET (arcptr));
+
+ for (arcptr = bb_graph[block].pred;
+ arcptr; arcptr = arcptr->pred_next)
+ if (arcptr->on_tree && ! bb_graph[ARC_SOURCE (arcptr)].on_tree)
+ expand_spanning_tree (ARC_SOURCE (arcptr));
+}
+
+/* Perform file-level initialization for branch-prob processing. */
+
+void
+init_branch_prob (filename)
+ char *filename;
+{
+ long len;
+ int i;
+
+ if (flag_test_coverage)
+ {
+ /* Open an output file for the basic block/line number map. */
+ int len = strlen (filename);
+ char *data_file = (char *) alloca (len + 4);
+ strcpy (data_file, filename);
+ strip_off_ending (data_file, len);
+ strcat (data_file, ".bb");
+ if ((bb_file = fopen (data_file, "w")) == 0)
+ pfatal_with_name (data_file);
+
+ /* Open an output file for the program flow graph. */
+ len = strlen (filename);
+ bbg_file_name = (char *) alloca (len + 5);
+ strcpy (bbg_file_name, filename);
+ strip_off_ending (bbg_file_name, len);
+ strcat (bbg_file_name, ".bbg");
+ if ((bbg_file = fopen (bbg_file_name, "w")) == 0)
+ pfatal_with_name (bbg_file_name);
+
+ /* Initialize to zero, to ensure that the first file name will be
+ written to the .bb file. */
+ last_bb_file_name = 0;
+ }
+
+ if (flag_branch_probabilities)
+ {
+ len = strlen (filename);
+ da_file_name = (char *) alloca (len + 4);
+ strcpy (da_file_name, filename);
+ strip_off_ending (da_file_name, len);
+ strcat (da_file_name, ".da");
+ if ((da_file = fopen (da_file_name, "r")) == 0)
+ warning ("file %s not found, execution counts assumed to be zero.",
+ da_file_name);
+
+ /* The first word in the .da file gives the number of instrumented arcs,
+ which is not needed for our purposes. */
+
+ if (da_file)
+ __read_long (&len, da_file, 8);
+ }
+
+ if (profile_arc_flag)
+ init_arc_profiler ();
+
+ total_num_blocks = 0;
+ total_num_arcs = 0;
+ total_num_arcs_instrumented = 0;
+ total_num_blocks_created = 0;
+ total_num_passes = 0;
+ total_num_times_called = 0;
+ total_num_branches = 0;
+ total_num_never_executed = 0;
+ for (i = 0; i < 20; i++)
+ total_hist_br_prob[i] = 0;
+}
+
+/* Performs file-level cleanup after branch-prob processing
+ is completed. */
+
+void
+end_branch_prob (dump_file)
+ FILE *dump_file;
+{
+ if (flag_test_coverage)
+ {
+ fclose (bb_file);
+ fclose (bbg_file);
+ }
+
+ if (flag_branch_probabilities)
+ {
+ if (da_file)
+ {
+ long temp;
+ /* This seems slightly dangerous, as it presumes the EOF
+ flag will not be set until an attempt is made to read
+ past the end of the file. */
+ if (feof (da_file))
+ warning (".da file contents exhausted too early\n");
+ /* Should be at end of file now. */
+ if (__read_long (&temp, da_file, 8) == 0)
+ warning (".da file contents not exhausted\n");
+ fclose (da_file);
+ }
+ }
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "\n");
+ fprintf (dump_file, "Total number of blocks: %d\n", total_num_blocks);
+ fprintf (dump_file, "Total number of arcs: %d\n", total_num_arcs);
+ fprintf (dump_file, "Total number of instrumented arcs: %d\n",
+ total_num_arcs_instrumented);
+ fprintf (dump_file, "Total number of blocks created: %d\n",
+ total_num_blocks_created);
+ fprintf (dump_file, "Total number of graph solution passes: %d\n",
+ total_num_passes);
+ if (total_num_times_called != 0)
+ fprintf (dump_file, "Average number of graph solution passes: %d\n",
+ (total_num_passes + (total_num_times_called >> 1))
+ / total_num_times_called);
+ fprintf (dump_file, "Total number of branches: %d\n", total_num_branches);
+ fprintf (dump_file, "Total number of branches never executed: %d\n",
+ total_num_never_executed);
+ if (total_num_branches)
+ {
+ int i;
+
+ for (i = 0; i < 10; i++)
+ fprintf (dump_file, "%d%% branches in range %d-%d%%\n",
+ (total_hist_br_prob[i] + total_hist_br_prob[19-i]) * 100
+ / total_num_branches, 5*i, 5*i+5);
+ }
+ }
+}
+
+/* The label used by the arc profiling code. */
+
+static rtx profiler_label;
+
+/* Initialize the profiler_label. */
+
+static void
+init_arc_profiler ()
+{
+ /* Generate and save a copy of this so it can be shared. */
+ char *name = xmalloc (20);
+ ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
+ profiler_label = gen_rtx_SYMBOL_REF (Pmode, name);
+}
+
+/* Output instructions as RTL to increment the arc execution count. */
+
+static void
+output_arc_profiler (arcno, insert_after)
+ int arcno;
+ rtx insert_after;
+{
+ rtx profiler_target_addr
+ = (arcno
+ ? gen_rtx_CONST (Pmode,
+ gen_rtx_PLUS (Pmode, profiler_label,
+ GEN_INT (LONG_TYPE_SIZE / BITS_PER_UNIT * arcno)))
+ : profiler_label);
+ enum machine_mode mode = mode_for_size (LONG_TYPE_SIZE, MODE_INT, 0);
+ rtx profiler_reg = gen_reg_rtx (mode);
+ rtx address_reg = gen_reg_rtx (Pmode);
+ rtx mem_ref, add_ref;
+ rtx sequence;
+
+ /* In this case, reload can use explicitly mentioned hard registers for
+ reloads. It is not safe to output profiling code between a call
+ and the instruction that copies the result to a pseudo-reg. This
+ is because reload may allocate one of the profiling code pseudo-regs
+ to the return value reg, thus clobbering the return value. So we
+ must check for calls here, and emit the profiling code after the
+ instruction that uses the return value, if any.
+
+ ??? The code here performs the same tests that reload does so hopefully
+ all the bases are covered. */
+
+ if (SMALL_REGISTER_CLASSES
+ && GET_CODE (insert_after) == CALL_INSN
+ && (GET_CODE (PATTERN (insert_after)) == SET
+ || (GET_CODE (PATTERN (insert_after)) == PARALLEL
+ && GET_CODE (XVECEXP (PATTERN (insert_after), 0, 0)) == SET)))
+ {
+ rtx return_reg;
+ rtx next_insert_after = next_nonnote_insn (insert_after);
+
+ /* The first insn after the call may be a stack pop, skip it. */
+ if (next_insert_after
+ && GET_CODE (next_insert_after) == INSN
+ && GET_CODE (PATTERN (next_insert_after)) == SET
+ && SET_DEST (PATTERN (next_insert_after)) == stack_pointer_rtx)
+ next_insert_after = next_nonnote_insn (next_insert_after);
+
+ if (next_insert_after
+ && GET_CODE (next_insert_after) == INSN)
+ {
+ if (GET_CODE (PATTERN (insert_after)) == SET)
+ return_reg = SET_DEST (PATTERN (insert_after));
+ else
+ return_reg = SET_DEST (XVECEXP (PATTERN (insert_after), 0, 0));
+
+ /* Now, NEXT_INSERT_AFTER may be an instruction that uses the
+ return value. However, it could also be something else,
+ like a CODE_LABEL, so check that the code is INSN. */
+ if (next_insert_after != 0
+ && GET_RTX_CLASS (GET_CODE (next_insert_after)) == 'i'
+ && reg_referenced_p (return_reg, PATTERN (next_insert_after)))
+ insert_after = next_insert_after;
+ }
+ }
+
+ start_sequence ();
+
+ emit_move_insn (address_reg, profiler_target_addr);
+ mem_ref = gen_rtx_MEM (mode, address_reg);
+ emit_move_insn (profiler_reg, mem_ref);
+
+ add_ref = gen_rtx_PLUS (mode, profiler_reg, GEN_INT (1));
+ emit_move_insn (profiler_reg, add_ref);
+
+ /* This is the same rtx as above, but it is not legal to share this rtx. */
+ mem_ref = gen_rtx_MEM (mode, address_reg);
+ emit_move_insn (mem_ref, profiler_reg);
+
+ sequence = gen_sequence ();
+ end_sequence ();
+ emit_insn_after (sequence, insert_after);
+}
+
+/* Output code for a constructor that will invoke __bb_init_func, if
+ this has not already been done. */
+
+void
+output_func_start_profiler ()
+{
+ tree fnname, fndecl;
+ char *name, *cfnname;
+ rtx table_address;
+ enum machine_mode mode = mode_for_size (LONG_TYPE_SIZE, MODE_INT, 0);
+ int save_flag_inline_functions = flag_inline_functions;
+
+ /* It's either already been output, or we don't need it because we're
+ not doing profile-arcs. */
+ if (! need_func_profiler)
+ return;
+
+ need_func_profiler = 0;
+
+ /* Synthesize a constructor function to invoke __bb_init_func with a
+ pointer to this object file's profile block. */
+ start_sequence ();
+
+ /* Try and make a unique name given the "file function name".
+
+ And no, I don't like this either. */
+
+ fnname = get_file_function_name ('I');
+ cfnname = IDENTIFIER_POINTER (fnname);
+ name = xmalloc (strlen (cfnname) + 5);
+ sprintf (name, "%sGCOV",cfnname);
+ fnname = get_identifier (name);
+ free (name);
+
+ fndecl = build_decl (FUNCTION_DECL, fnname,
+ build_function_type (void_type_node, NULL_TREE));
+ DECL_EXTERNAL (fndecl) = 0;
+ TREE_PUBLIC (fndecl) = 1;
+ DECL_ASSEMBLER_NAME (fndecl) = fnname;
+ DECL_RESULT (fndecl) = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
+ current_function_decl = fndecl;
+ pushlevel (0);
+ make_function_rtl (fndecl);
+ init_function_start (fndecl, input_filename, lineno);
+ expand_function_start (fndecl, 0);
+
+ /* Actually generate the code to call __bb_init_func. */
+ name = xmalloc (20);
+ ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
+ table_address = force_reg (Pmode, gen_rtx_SYMBOL_REF (Pmode, name));
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__bb_init_func"), 0,
+ mode, 1, table_address, Pmode);
+
+ expand_function_end (input_filename, lineno, 0);
+ poplevel (1, 0, 1);
+
+ /* Since fndecl isn't in the list of globals, it would never be emitted
+ when it's considered to be 'safe' for inlining, so turn off
+ flag_inline_functions. */
+ flag_inline_functions = 0;
+
+ rest_of_compilation (fndecl);
+
+ /* Reset flag_inline_functions to its original value. */
+ flag_inline_functions = save_flag_inline_functions;
+
+ if (! quiet_flag)
+ fflush (asm_out_file);
+ current_function_decl = NULL_TREE;
+
+ assemble_constructor (IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+}
diff --git a/contrib/gcc/protoize.c b/contrib/gcc/protoize.c
index 9728bf2..48908e5 100644
--- a/contrib/gcc/protoize.c
+++ b/contrib/gcc/protoize.c
@@ -1,5 +1,5 @@
/* Protoize program - Original version by Ron Guilmette (rfg@segfault.us.com).
- Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1989, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,7 +20,7 @@ Boston, MA 02111-1307, USA. */
/* Any reasonable C++ compiler should have all of the same features
as __STDC__ plus more, so make sure that __STDC__ is defined if
- __cplusplus is defined. */
+ __cplusplus is defined. */
#if defined(__cplusplus) && !defined(__STDC__)
#define __STDC__ 1
@@ -57,15 +57,14 @@ Boston, MA 02111-1307, USA. */
#define _POSIX_SOURCE
#endif
+#ifdef __STDC__
+#include <stdarg.h>
+#else
#include <varargs.h>
-/* On some systems stdio.h includes stdarg.h;
- we must bring in varargs.h first. */
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
-#include <sys/types.h>
+#endif
+#include "system.h"
#include <sys/stat.h>
-#ifndef _WIN32
+#if ! defined (_WIN32) || defined (__CYGWIN32__)
#if defined(POSIX) || defined(CONCURRENT)
#include <dirent.h>
#else
@@ -73,6 +72,19 @@ Boston, MA 02111-1307, USA. */
#endif
#endif
#include <setjmp.h>
+#include "gansidecl.h"
+
+/* Some systems like Linux don't declare rindex if _POSIX_SOURCE is declared,
+ but it normally does declare it. This means that configure thinks we don't
+ need to declare it. Favor using strrchr if it is available. */
+
+#ifndef strrchr
+#ifndef HAVE_STRRCHR
+#ifdef HAVE_RINDEX
+#define strrchr rindex
+#endif
+#endif
+#endif
/* Include getopt.h for the sake of getopt_long.
We don't need the declaration of getopt, and it could conflict
@@ -81,21 +93,6 @@ Boston, MA 02111-1307, USA. */
#include "getopt.h"
#undef getopt
-#ifndef errno
-extern int errno;
-#endif
-
-#ifndef HAVE_STRERROR
-extern int sys_nerr;
-#if defined(bsd4_4)
-extern const char *const sys_errlist[];
-#else
-extern char *sys_errlist[];
-#endif
-#else
-extern char *strerror();
-#endif
-
extern char *version_string;
/* Systems which are compatible only with POSIX 1003.1-1988 (but *not*
@@ -107,14 +104,28 @@ extern char *version_string;
#define my_access(file,flag) access((char *)file, flag)
#define my_stat(file,pkt) stat((char *)file, pkt)
-#define my_execvp(prog,argv) execvp((char *)prog, (char **)argv)
+#ifdef __MINGW32__
+#define my_link(file1, file2) -1
+#else
#define my_link(file1, file2) link((char *)file1, (char *)file2)
+#endif
#define my_unlink(file) unlink((char *)file)
#define my_open(file, mode, flag) open((char *)file, mode, flag)
#define my_chmod(file, mode) chmod((char *)file, mode)
extern char *getpwd ();
+extern char *choose_temp_base PROTO ((void));
+extern char * my_strerror PROTO ((int));
+
+extern int pexecute PROTO ((const char *, char * const *, const char *,
+ const char *, char **, char **, int));
+extern int pwait PROTO ((int, int *, int));
+/* Flag arguments to pexecute. */
+#define PEXECUTE_FIRST 1
+#define PEXECUTE_LAST 2
+#define PEXECUTE_SEARCH 4
+
/* Aliases for pointers to void.
These were made to facilitate compilation with old brain-dead DEC C
compilers which didn't properly grok `void*' types. */
@@ -129,27 +140,11 @@ typedef char * const_pointer_type;
#if defined(POSIX)
-#include <stdlib.h>
-#include <unistd.h>
#include <signal.h>
-#include <fcntl.h>
#include <sys/wait.h>
#else /* !defined(POSIX) */
-#define R_OK 4 /* Test for Read permission */
-#define W_OK 2 /* Test for Write permission */
-#define X_OK 1 /* Test for eXecute permission */
-#define F_OK 0 /* Test for existence of File */
-
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
-
-#ifndef O_WRONLY
-#define O_WRONLY 1
-#endif
-
#ifndef WIFSIGNALED
#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
#endif
@@ -166,33 +161,22 @@ typedef char * const_pointer_type;
/* Declaring stat or __flsbuf with a prototype
causes conflicts with system headers on some systems. */
-#ifndef abort
-typedef void voidfn ();
-extern VOLATILE voidfn abort;
-#endif
-#ifndef _WIN32
-extern int kill ();
-#endif
-extern int creat ();
#if 0 /* These conflict with stdio.h on some systems. */
+extern int creat ();
extern int fprintf (FILE *, const char *, ...);
extern int printf (const char *, ...);
extern int open (const char *, int, ...);
-#endif /* 0 */
-extern void exit ();
-extern void free ();
extern int read ();
extern int write ();
+#endif /* 0 */
extern int close ();
extern int fflush ();
extern int atoi ();
extern int puts ();
extern int fputs ();
extern int fputc ();
-extern int link ();
extern int unlink ();
extern int access ();
-extern int execvp ();
#if 0 /* size_t from sys/types.h may fail to match GCC.
If so, we would get a warning from this. */
@@ -207,20 +191,10 @@ extern size_t strlen ()
#endif /* !defined (POSIX) */
-extern char *rindex ();
-
/* Look for these where the `const' qualifier is intentionally cast aside. */
#define NONCONST
-/* Define a STRINGIFY macro that's right for ANSI or traditional C. */
-
-#ifdef __STDC__
-#define STRINGIFY(STRING) #STRING
-#else
-#define STRINGIFY(STRING) "STRING"
-#endif
-
/* Define a default place to find the SYSCALLS.X file. */
#ifndef STD_PROTO_DIR
@@ -254,7 +228,7 @@ static char * syscalls_absolute_filename;
#endif /* !defined (UNPROTOIZE) */
-/* Type of the structure that holds information about macro unexpansions. */
+/* Type of the structure that holds information about macro unexpansions. */
struct unexpansion_struct {
const char *expanded;
@@ -295,39 +269,41 @@ static const int hash_mask = (HASH_TABLE_SIZE - 1);
#define LOCAL_INCLUDE_DIR "/usr/local/include"
#endif
-struct default_include { const char *fname; int x1, x2; } include_defaults[]
+struct default_include { const char *fname;
+ const char *component;
+ int x1, x2; } include_defaults[]
#ifdef INCLUDE_DEFAULTS
= INCLUDE_DEFAULTS;
#else
= {
/* Pick up GNU C++ specific include files. */
- { GPLUSPLUS_INCLUDE_DIR, 1, 1 },
+ { GPLUSPLUS_INCLUDE_DIR, "G++", 1, 1 },
#ifdef CROSS_COMPILE
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
- { GCC_INCLUDE_DIR, 0, 0 },
+ { GCC_INCLUDE_DIR, "GCC", 0, 0 },
/* For cross-compilation, this dir name is generated
automatically in Makefile.in. */
- { CROSS_INCLUDE_DIR, 0, 0 },
+ { CROSS_INCLUDE_DIR, 0, 0, 0 },
/* This is another place that the target system's headers might be. */
- { TOOL_INCLUDE_DIR, 0, 0 },
+ { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 },
#else /* not CROSS_COMPILE */
/* This should be /use/local/include and should come before
the fixincludes-fixed header files. */
- { LOCAL_INCLUDE_DIR, 0, 1 },
+ { LOCAL_INCLUDE_DIR, 0, 0, 1 },
/* This is here ahead of GCC_INCLUDE_DIR because assert.h goes here.
Likewise, behind LOCAL_INCLUDE_DIR, where glibc puts its assert.h. */
- { TOOL_INCLUDE_DIR, 0, 0 },
+ { TOOL_INCLUDE_DIR, "BINUTILS", 0, 0 },
/* This is the dir for fixincludes. Put it just before
the files that we fix. */
- { GCC_INCLUDE_DIR, 0, 0 },
+ { GCC_INCLUDE_DIR, "GCC", 0, 0 },
/* Some systems have an extra dir of include files. */
#ifdef SYSTEM_INCLUDE_DIR
- { SYSTEM_INCLUDE_DIR, 0, 0 },
+ { SYSTEM_INCLUDE_DIR, 0, 0, 0 },
#endif
- { STANDARD_INCLUDE_DIR, 0, 0},
+ { STANDARD_INCLUDE_DIR, 0, 0, 0},
#endif /* not CROSS_COMPILE */
- { 0, 0, 0}
+ { 0, 0, 0, 0}
};
#endif /* no INCLUDE_DEFAULTS */
@@ -501,7 +477,7 @@ static const char *indent_string = " "; /* Indentation for newly
static int local_flag = 0; /* Insert new local decls (when?). */
static int global_flag = 0; /* set by -g option */
static int cplusplus_flag = 0; /* Rename converted files to *.C. */
-static const char* nondefault_syscalls_dir = 0; /* Dir to look for
+static const char *nondefault_syscalls_dir = 0; /* Dir to look for
SYSCALLS.c.X in. */
#endif /* !defined (UNPROTOIZE) */
@@ -536,7 +512,7 @@ static const char *convert_filename;
/* Pointer to relative root string (taken from aux_info file) which indicates
where directory the user was in when he did the compilation step that
- produced the containing aux_info file. */
+ produced the containing aux_info file. */
static const char *invocation_filename;
@@ -659,7 +635,7 @@ xmalloc (byte_count)
if (rv == NULL)
{
fprintf (stderr, "\n%s: virtual memory exceeded\n", pname);
- exit (1);
+ exit (FATAL_EXIT_CODE);
return 0; /* avoid warnings */
}
else
@@ -679,7 +655,7 @@ xrealloc (old_space, byte_count)
if (rv == NULL)
{
fprintf (stderr, "\n%s: virtual memory exceeded\n", pname);
- exit (1);
+ exit (FATAL_EXIT_CODE);
return 0; /* avoid warnings */
}
else
@@ -732,7 +708,7 @@ void
fancy_abort ()
{
fprintf (stderr, "%s: internal abort\n", pname);
- exit (1);
+ exit (FATAL_EXIT_CODE);
}
/* Make a duplicate of the first N bytes of a given string in a newly
@@ -764,7 +740,7 @@ substr (s1, s2)
const char *p2;
int c;
- for (p1 = s1, p2 = s2; c = *p2; p1++, p2++)
+ for (p1 = s1, p2 = s2; (c = *p2); p1++, p2++)
if (*p1 != c)
goto outer;
return s1;
@@ -816,12 +792,13 @@ safe_write (desc, ptr, len, out_fname)
int written = write (desc, ptr, len);
if (written < 0)
{
+ int errno_val = errno;
#ifdef EINTR
- if (errno == EINTR)
+ if (errno_val == EINTR)
continue;
#endif
fprintf (stderr, "%s: error writing file `%s': %s\n",
- pname, shortpath (NULL, out_fname), my_strerror(errno));
+ pname, shortpath (NULL, out_fname), my_strerror (errno_val));
return;
}
ptr += written;
@@ -854,7 +831,7 @@ static int
is_id_char (ch)
char ch;
{
- return (isalnum (ch) || (ch == '_') || (ch == '$'));
+ return (ISALNUM (ch) || (ch == '_') || (ch == '$'));
}
/* Give a message indicating the proper way to invoke this program and then
@@ -867,10 +844,10 @@ usage ()
fprintf (stderr, "%s: usage '%s [ -VqfnkN ] [ -i <istring> ] [ filename ... ]'\n",
pname, pname);
#else /* !defined (UNPROTOIZE) */
- fprintf (stderr, "%s: usage '%s [ -VqfnkNlgC ] [ -B <diname> ] [ filename ... ]'\n",
+ fprintf (stderr, "%s: usage '%s [ -VqfnkNlgC ] [ -B <dirname> ] [ filename ... ]'\n",
pname, pname);
#endif /* !defined (UNPROTOIZE) */
- exit (1);
+ exit (FATAL_EXIT_CODE);
}
/* Return true if the given filename (assumed to be an absolute filename)
@@ -910,7 +887,7 @@ file_could_be_converted (const char *path)
char *dir_last_slash;
strcpy (dir_name, path);
- dir_last_slash = rindex (dir_name, '/');
+ dir_last_slash = strrchr (dir_name, '/');
if (dir_last_slash)
*dir_last_slash = '\0';
else
@@ -944,7 +921,7 @@ file_normally_convertible (const char *path)
char *dir_last_slash;
strcpy (dir_name, path);
- dir_last_slash = rindex (dir_name, '/');
+ dir_last_slash = strrchr (dir_name, '/');
if (dir_last_slash)
*dir_last_slash = '\0';
else
@@ -1023,14 +1000,14 @@ needs_to_be_converted (file_p)
#ifndef UNPROTOIZE
- /* ... and if we a protoizing and this function is in old style ... */
+ /* ... and if we a protoizing and this function is in old style ... */
!ddp->prototyped
- /* ... and if this a definition or is a decl with an associated def ... */
+ /* ... and if this a definition or is a decl with an associated def ... */
&& (ddp->is_func_def || (!ddp->is_func_def && ddp->definition))
#else /* defined (UNPROTOIZE) */
- /* ... and if we are unprotoizing and this function is in new style ... */
+ /* ... and if we are unprotoizing and this function is in new style ... */
ddp->prototyped
#endif /* defined (UNPROTOIZE) */
@@ -1216,7 +1193,7 @@ unexpand_if_needed (aux_info_line)
{
static char *line_buf = 0;
static int line_buf_size = 0;
- const unexpansion* unexp_p;
+ const unexpansion *unexp_p;
int got_unexpanded = 0;
const char *s;
char *copy_p = line_buf;
@@ -1314,12 +1291,12 @@ abspath (cwd, rel_filename)
if (rel_filename[0] != '/')
{
src_p = cwd2;
- while (*endp++ = *src_p++)
+ while ((*endp++ = *src_p++))
continue;
*(endp-1) = '/'; /* overwrite null */
}
src_p = rel_filename;
- while (*endp++ = *src_p++)
+ while ((*endp++ = *src_p++))
continue;
}
@@ -1357,18 +1334,18 @@ abspath (cwd, rel_filename)
while (outp >= abs_buffer && *outp != '/')
outp--;
if (outp < abs_buffer)
- {
- /* Catch cases like /.. where we try to backup to a
- point above the absolute root of the logical file
- system. */
-
- fprintf (stderr, "%s: invalid file name: %s\n",
- pname, rel_filename);
- exit (1);
- }
+ {
+ /* Catch cases like /.. where we try to backup to a
+ point above the absolute root of the logical file
+ system. */
+
+ fprintf (stderr, "%s: invalid file name: %s\n",
+ pname, rel_filename);
+ exit (FATAL_EXIT_CODE);
+ }
*++outp = '\0';
continue;
- }
+ }
}
*outp++ = *inp++;
}
@@ -1471,7 +1448,7 @@ shortpath (cwd, filename)
if (rel_buffer + filename_len <= rel_buf_p)
return filename;
}
- while (*rel_buf_p++ = *path_p++);
+ while ((*rel_buf_p++ = *path_p++));
--rel_buf_p;
if (*(rel_buf_p-1) == '/')
@@ -1512,8 +1489,10 @@ find_file (filename, do_not_stat)
{
if (my_stat (filename, &stat_buf) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: %s: can't get status: %s\n",
- pname, shortpath (NULL, filename), my_strerror(errno));
+ pname, shortpath (NULL, filename),
+ my_strerror (errno_val));
stat_buf.st_mtime = (time_t) -1;
}
}
@@ -1534,7 +1513,7 @@ aux_info_corrupted ()
{
fprintf (stderr, "\n%s: fatal error: aux info file corrupted at line %d\n",
pname, current_aux_info_lineno);
- exit (1);
+ exit (FATAL_EXIT_CODE);
}
/* ??? This comment is vague. Say what the condition is for. */
@@ -1690,7 +1669,7 @@ save_def_or_dec (l, is_syscalls)
/* Check that this record describes a new-style, old-style, or implicit
definition or declaration. */
- p++; /* Skip over the `:'. */
+ p++; /* Skip over the `:'. */
check_aux_info ((*p == 'N') || (*p == 'O') || (*p == 'I'));
/* Is this a new style (ANSI prototyped) definition or declaration? */
@@ -1781,8 +1760,8 @@ save_def_or_dec (l, is_syscalls)
const char *left_paren_p = find_corresponding_lparen (p);
#ifndef UNPROTOIZE
{
- f_list_chain_item *cip =
- (f_list_chain_item *) xmalloc (sizeof (f_list_chain_item));
+ f_list_chain_item *cip
+ = (f_list_chain_item *) xmalloc (sizeof (f_list_chain_item));
cip->formals_list
= dupnstr (left_paren_p + 1, (size_t) (p - (left_paren_p+1)));
@@ -1860,7 +1839,7 @@ save_def_or_dec (l, is_syscalls)
def_dec_p->file->hash_entry->symbol,
def_dec_p->line,
def_dec_p->hash_entry->symbol);
- exit (1);
+ exit (FATAL_EXIT_CODE);
}
free_def_dec (def_dec_p);
return;
@@ -1896,7 +1875,7 @@ save_def_or_dec (l, is_syscalls)
check_aux_info (*++p == '(');
{
- const char *kr_names_start = ++p; /* Point just inside '('. */
+ const char *kr_names_start = ++p; /* Point just inside '('. */
while (*p++ != ')')
continue;
@@ -1938,7 +1917,7 @@ save_def_or_dec (l, is_syscalls)
}
/* Handle a special case. If we have a function definition marked as
- being in "old" style, and if it's formal names list is empty, then
+ being in "old" style, and if its formal names list is empty, then
it may actually have the string "void" in its real formals list
in the original source code. Just to make sure, we will get setup
to convert such things anyway.
@@ -2028,12 +2007,12 @@ munge_compile_params (params_list)
temp_params[param_count++] = compiler_file_name;
for (;;)
{
- while (isspace (*params_list))
+ while (ISSPACE (*params_list))
params_list++;
if (!*params_list)
break;
param = params_list;
- while (*params_list && !isspace (*params_list))
+ while (*params_list && !ISSPACE (*params_list))
params_list++;
if (param[0] != '-')
temp_params[param_count++]
@@ -2048,9 +2027,9 @@ munge_compile_params (params_list)
case 'c':
break; /* Don't copy these. */
case 'o':
- while (isspace (*params_list))
+ while (ISSPACE (*params_list))
params_list++;
- while (*params_list && !isspace (*params_list))
+ while (*params_list && !ISSPACE (*params_list))
params_list++;
break;
default:
@@ -2085,14 +2064,14 @@ munge_compile_params (params_list)
}
/* Do a recompilation for the express purpose of generating a new aux_info
- file to go with a specific base source file. */
+ file to go with a specific base source file.
+
+ The result is a boolean indicating success. */
static int
gen_aux_info_file (base_filename)
const char *base_filename;
{
- int child_pid;
-
if (!input_file_name_index)
munge_compile_params ("");
@@ -2109,79 +2088,48 @@ gen_aux_info_file (base_filename)
fprintf (stderr, "%s: compiling `%s'\n",
pname, compile_params[input_file_name_index]);
- if (child_pid = fork ())
- {
- if (child_pid == -1)
- {
- fprintf (stderr, "%s: could not fork process: %s\n",
- pname, my_strerror(errno));
- return 0;
- }
-
-#if 0
- /* Print out the command line that the other process is now executing. */
+ {
+ char *errmsg_fmt, *errmsg_arg;
+ int wait_status, pid;
+ char *temp_base = choose_temp_base ();
- if (!quiet_flag)
- {
- const char **arg;
-
- fputs ("\t", stderr);
- for (arg = compile_params; *arg; arg++)
- {
- fputs (*arg, stderr);
- fputc (' ', stderr);
- }
- fputc ('\n', stderr);
- fflush (stderr);
- }
-#endif /* 0 */
+ pid = pexecute (compile_params[0], (char * const *) compile_params,
+ pname, temp_base, &errmsg_fmt, &errmsg_arg,
+ PEXECUTE_FIRST | PEXECUTE_LAST | PEXECUTE_SEARCH);
+ if (pid == -1)
{
- int wait_status;
+ int errno_val = errno;
+ fprintf (stderr, "%s: ", pname);
+ fprintf (stderr, errmsg_fmt, errmsg_arg);
+ fprintf (stderr, ": %s\n", my_strerror (errno_val));
+ return 0;
+ }
- if (wait (&wait_status) == -1)
- {
- fprintf (stderr, "%s: wait failed: %s\n",
- pname, my_strerror(errno));
- return 0;
- }
- if (WIFSIGNALED (wait_status))
- {
- fprintf (stderr, "%s: subprocess got fatal signal %d",
- pname, WTERMSIG (wait_status));
- return 0;
- }
- if (WIFEXITED (wait_status) && WEXITSTATUS (wait_status) != 0)
+ pid = pwait (pid, &wait_status, 0);
+ if (pid == -1)
+ {
+ fprintf (stderr, "%s: wait: %s\n", pname, my_strerror (errno));
+ return 0;
+ }
+ if (WIFSIGNALED (wait_status))
+ {
+ fprintf (stderr, "%s: subprocess got fatal signal %d\n",
+ pname, WTERMSIG (wait_status));
+ return 0;
+ }
+ if (WIFEXITED (wait_status))
+ {
+ if (WEXITSTATUS (wait_status) != 0)
{
fprintf (stderr, "%s: %s exited with status %d\n",
- pname, base_filename, WEXITSTATUS (wait_status));
+ pname, compile_params[0], WEXITSTATUS (wait_status));
return 0;
}
return 1;
}
- }
- else
- {
- if (my_execvp (compile_params[0], (char *const *) compile_params))
- {
- int e = errno, f = fileno (stderr);
- write (f, pname, strlen (pname));
- write (f, ": ", 2);
- write (f, compile_params[0], strlen (compile_params[0]));
- write (f, ": ", 2);
-#ifdef HAVE_STRERROR
- {
- char *p = strerror(e);
- write (f, p, strlen (p));
- }
-#else
- write (f, sys_errlist[e], strlen (sys_errlist[e]));
-#endif
- write (f, "\n", 1);
- _exit (1);
- }
- return 1; /* Never executed. */
- }
+ abort ();
+ }
}
/* Read in all of the information contained in a single aux_info file.
@@ -2234,9 +2182,10 @@ start_over: ;
}
else
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't read aux info file `%s': %s\n",
pname, shortpath (NULL, aux_info_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
errors++;
return;
}
@@ -2262,9 +2211,10 @@ start_over: ;
}
if (my_access (aux_info_filename, R_OK) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't read aux info file `%s': %s\n",
pname, shortpath (NULL, aux_info_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
errors++;
return;
}
@@ -2277,9 +2227,10 @@ start_over: ;
if (my_stat (aux_info_filename, &stat_buf) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't get status of aux info file `%s': %s\n",
pname, shortpath (NULL, aux_info_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
errors++;
return;
}
@@ -2304,9 +2255,10 @@ start_over: ;
if (my_stat (base_source_filename, &stat_buf) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't get status of aux info file `%s': %s\n",
pname, shortpath (NULL, base_source_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
errors++;
return;
}
@@ -2325,9 +2277,10 @@ start_over: ;
if ((aux_info_file = my_open (aux_info_filename, O_RDONLY, 0444 )) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't open aux info file `%s' for reading: %s\n",
pname, shortpath (NULL, aux_info_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
return;
}
@@ -2341,9 +2294,10 @@ start_over: ;
if (safe_read (aux_info_file, aux_info_base, aux_info_size) != aux_info_size)
{
+ int errno_val = errno;
fprintf (stderr, "%s: error reading aux info file `%s': %s\n",
pname, shortpath (NULL, aux_info_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
free (aux_info_base);
close (aux_info_file);
return;
@@ -2353,9 +2307,10 @@ start_over: ;
if (close (aux_info_file))
{
+ int errno_val = errno;
fprintf (stderr, "%s: error closing aux info file `%s': %s\n",
pname, shortpath (NULL, aux_info_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
free (aux_info_base);
close (aux_info_file);
return;
@@ -2367,9 +2322,12 @@ start_over: ;
if (must_create && !keep_it)
if (my_unlink (aux_info_filename) == -1)
- fprintf (stderr, "%s: can't delete aux info file `%s': %s\n",
- pname, shortpath (NULL, aux_info_filename),
- my_strerror(errno));
+ {
+ int errno_val = errno;
+ fprintf (stderr, "%s: can't delete aux info file `%s': %s\n",
+ pname, shortpath (NULL, aux_info_filename),
+ my_strerror (errno_val));
+ }
/* Save a pointer into the first line of the aux_info file which
contains the filename of the directory from which the compiler
@@ -2402,7 +2360,7 @@ start_over: ;
char *dir_end;
aux_info_relocated_name = xmalloc (base_len + (p-invocation_filename));
strcpy (aux_info_relocated_name, base_source_filename);
- dir_end = rindex (aux_info_relocated_name, '/');
+ dir_end = strrchr (aux_info_relocated_name, '/');
if (dir_end)
dir_end++;
else
@@ -2433,9 +2391,10 @@ start_over: ;
xfree (aux_info_relocated_name);
if (keep_it && my_unlink (aux_info_filename) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't delete file `%s': %s\n",
pname, shortpath (NULL, aux_info_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
return;
}
must_create = 1;
@@ -2509,17 +2468,19 @@ rename_c_file (hp)
if (my_link (filename, new_filename) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: warning: can't link file `%s' to `%s': %s\n",
pname, shortpath (NULL, filename),
- shortpath (NULL, new_filename), my_strerror(errno));
+ shortpath (NULL, new_filename), my_strerror (errno_val));
errors++;
return;
}
if (my_unlink (filename) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: warning: can't delete file `%s': %s\n",
- pname, shortpath (NULL, filename), my_strerror(errno));
+ pname, shortpath (NULL, filename), my_strerror (errno_val));
errors++;
return;
}
@@ -2618,7 +2579,7 @@ find_extern_def (head, user)
if (dd_p->is_func_def && !dd_p->is_static)
{
if (!extern_def_p) /* Previous definition? */
- extern_def_p = dd_p; /* Remember the first definition found. */
+ extern_def_p = dd_p; /* Remember the first definition found. */
else
{
/* Ignore definition just found if it came from SYSCALLS.c.X. */
@@ -2738,7 +2699,7 @@ find_extern_def (head, user)
/* Find the (only?) static definition for a particular function name in a
given file. Here we get the function-name and the file info indirectly
- from the def_dec_info record pointer which is passed in. */
+ from the def_dec_info record pointer which is passed in. */
static const def_dec_info *
find_static_definition (user)
@@ -2806,7 +2767,7 @@ connect_defs_and_decs (hp)
Also, for each item which is only a function declaration, but which
nonetheless has its own prototype already (obviously supplied by the user)
- declare the item as it's own definition.
+ declare the item as its own definition.
Note that when/if there are multiple user-supplied prototypes already
present for multiple declarations of any given function, these multiple
@@ -2999,7 +2960,7 @@ static const char *
forward_to_next_token_char (ptr)
const char *ptr;
{
- for (++ptr; isspace (*ptr); check_source (++ptr < clean_text_limit, 0))
+ for (++ptr; ISSPACE (*ptr); check_source (++ptr < clean_text_limit, 0))
continue;
return ptr;
}
@@ -3367,7 +3328,7 @@ edit_formals_lists (end_formals, f_list_count, def_dec_p)
next_end = start_formals - 1;
check_source (next_end > clean_read_ptr, 0);
- while (isspace (*next_end))
+ while (ISSPACE (*next_end))
check_source (--next_end > clean_read_ptr, 0);
check_source (*next_end == ')', next_end);
check_source (--next_end > clean_read_ptr, 0);
@@ -3387,7 +3348,7 @@ edit_formals_lists (end_formals, f_list_count, def_dec_p)
const char *func_name_limit;
size_t func_name_len;
- for (func_name_limit = start_formals-1; isspace (*func_name_limit); )
+ for (func_name_limit = start_formals-1; ISSPACE (*func_name_limit); )
check_source (--func_name_limit > clean_read_ptr, 0);
for (func_name_start = func_name_limit++;
@@ -3434,11 +3395,11 @@ edit_formals_lists (end_formals, f_list_count, def_dec_p)
return 0;
}
-/* Given a pointer to a byte in the clean text buffer which points to the
- beginning of a line that contains a "follower" token for a function
- definition header, do whatever is necessary to find the right closing
- paren for the rightmost formals list of the function definition header.
-*/
+/* Given a pointer to a byte in the clean text buffer which points to
+ the beginning of a line that contains a "follower" token for a
+ function definition header, do whatever is necessary to find the
+ right closing paren for the rightmost formals list of the function
+ definition header. */
static const char *
find_rightmost_formals_list (clean_text_p)
@@ -3483,8 +3444,8 @@ find_rightmost_formals_list (clean_text_p)
while (*end_formals != ')')
{
- if (isspace (*end_formals))
- while (isspace (*end_formals))
+ if (ISSPACE (*end_formals))
+ while (ISSPACE (*end_formals))
check_source (--end_formals > clean_read_ptr, 0);
else
check_source (--end_formals > clean_read_ptr, 0);
@@ -3513,8 +3474,8 @@ find_rightmost_formals_list (clean_text_p)
while (*end_formals != ')')
{
- if (isspace (*end_formals))
- while (isspace (*end_formals))
+ if (ISSPACE (*end_formals))
+ while (ISSPACE (*end_formals))
check_source (--end_formals > clean_read_ptr, 0);
else
check_source (--end_formals > clean_read_ptr, 0);
@@ -3532,7 +3493,7 @@ find_rightmost_formals_list (clean_text_p)
by an alphabetic character, while others *cannot* validly be followed
by such characters. */
- if ((ch == '{') || isalpha (ch))
+ if ((ch == '{') || ISALPHA (ch))
break;
/* At this point, we have found a right paren, but we know that it is
@@ -3628,7 +3589,7 @@ add_local_decl (def_dec_p, clean_text_p)
We can now just scan backwards and find the left end of the existing
indentation string, and then copy it to the output buffer. */
- for (sp = ep; isspace (*sp) && *sp != '\n'; sp--)
+ for (sp = ep; ISSPACE (*sp) && *sp != '\n'; sp--)
continue;
/* Now write out the open { which began this block, and any following
@@ -3706,10 +3667,10 @@ add_global_decls (file_p, clean_text_p)
/* Now scan forward for the first non-whitespace character. In theory,
this should be the first character of the following function definition
- header. We will put in the added declarations just prior to that. */
+ header. We will put in the added declarations just prior to that. */
scan_p++;
- while (isspace (*scan_p))
+ while (ISSPACE (*scan_p))
scan_p++;
scan_p--;
@@ -3878,7 +3839,7 @@ edit_fn_definition (def_dec_p, clean_text_p)
{
have_newlines |= (*scan_orig == '\n');
/* Leave identical whitespace alone. */
- if (!isspace (*scan_orig))
+ if (!ISSPACE (*scan_orig))
*((NONCONST char *)scan_orig) = ' '; /* identical - so whiteout */
}
else
@@ -3922,7 +3883,7 @@ do_cleaning (new_clean_text_base, new_clean_text_limit)
scan_p += 2;
while (scan_p[1] != '/' || scan_p[0] != '*')
{
- if (!isspace (*scan_p))
+ if (!ISSPACE (*scan_p))
*scan_p = ' ';
if (++scan_p >= new_clean_text_limit)
abort ();
@@ -3937,7 +3898,7 @@ do_cleaning (new_clean_text_base, new_clean_text_limit)
*scan_p = ' ';
while (scan_p[1] != '\n' || scan_p[0] == '\\')
{
- if (!isspace (*scan_p))
+ if (!ISSPACE (*scan_p))
*scan_p = ' ';
if (++scan_p >= new_clean_text_limit)
abort ();
@@ -3949,9 +3910,9 @@ do_cleaning (new_clean_text_base, new_clean_text_limit)
non_whitespace_since_newline = 1;
while (scan_p[1] != '\'' || scan_p[0] == '\\')
{
- if (scan_p[0] == '\\' && !isspace (scan_p[1]))
+ if (scan_p[0] == '\\' && !ISSPACE (scan_p[1]))
scan_p[1] = ' ';
- if (!isspace (*scan_p))
+ if (!ISSPACE (*scan_p))
*scan_p = ' ';
if (++scan_p >= new_clean_text_limit)
abort ();
@@ -3963,14 +3924,14 @@ do_cleaning (new_clean_text_base, new_clean_text_limit)
non_whitespace_since_newline = 1;
while (scan_p[1] != '"' || scan_p[0] == '\\')
{
- if (scan_p[0] == '\\' && !isspace (scan_p[1]))
+ if (scan_p[0] == '\\' && !ISSPACE (scan_p[1]))
scan_p[1] = ' ';
- if (!isspace (*scan_p))
+ if (!ISSPACE (*scan_p))
*scan_p = ' ';
if (++scan_p >= new_clean_text_limit)
abort ();
}
- if (!isspace (*scan_p))
+ if (!ISSPACE (*scan_p))
*scan_p = ' ';
scan_p++;
break;
@@ -4063,12 +4024,12 @@ scan_for_missed_items (file_p)
last_r_paren = scan_p;
- for (ahead_p = scan_p + 1; isspace (*ahead_p); )
+ for (ahead_p = scan_p + 1; ISSPACE (*ahead_p); )
check_source (++ahead_p < limit, limit);
scan_p = ahead_p - 1;
- if (isalpha (*ahead_p) || *ahead_p == '{')
+ if (ISALPHA (*ahead_p) || *ahead_p == '{')
{
const char *last_l_paren;
const int lineno = identify_lineno (ahead_p);
@@ -4082,7 +4043,7 @@ scan_for_missed_items (file_p)
do
{
last_l_paren = careful_find_l_paren (last_r_paren);
- for (last_r_paren = last_l_paren-1; isspace (*last_r_paren); )
+ for (last_r_paren = last_l_paren-1; ISSPACE (*last_r_paren); )
check_source (--last_r_paren >= backup_limit, backup_limit);
}
while (*last_r_paren == ')');
@@ -4216,8 +4177,10 @@ edit_file (hp)
/* The cast avoids an erroneous warning on AIX. */
if (my_stat ((char *)convert_filename, &stat_buf) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't get status for file `%s': %s\n",
- pname, shortpath (NULL, convert_filename), my_strerror(errno));
+ pname, shortpath (NULL, convert_filename),
+ my_strerror (errno_val));
return;
}
orig_size = stat_buf.st_size;
@@ -4250,9 +4213,10 @@ edit_file (hp)
if ((input_file = my_open (convert_filename, O_RDONLY, 0444)) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't open file `%s' for reading: %s\n",
pname, shortpath (NULL, convert_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
return;
}
@@ -4262,10 +4226,11 @@ edit_file (hp)
if (safe_read (input_file, new_orig_text_base, orig_size) != orig_size)
{
+ int errno_val = errno;
close (input_file);
fprintf (stderr, "\n%s: error reading input file `%s': %s\n",
pname, shortpath (NULL, convert_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
return;
}
@@ -4296,9 +4261,10 @@ edit_file (hp)
strcat (clean_filename, ".clean");
if ((clean_file = creat (clean_filename, 0666)) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't create/open clean file `%s': %s\n",
pname, shortpath (NULL, clean_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
return;
}
@@ -4386,14 +4352,15 @@ edit_file (hp)
if (!nosave_flag)
{
- char *new_filename =
- (char *) xmalloc (strlen (convert_filename) + strlen (save_suffix) + 2);
+ char *new_filename
+ = (char *) xmalloc (strlen (convert_filename) + strlen (save_suffix) + 2);
strcpy (new_filename, convert_filename);
strcat (new_filename, save_suffix);
if (my_link (convert_filename, new_filename) == -1)
{
- if (errno == EEXIST)
+ int errno_val = errno;
+ if (errno_val == EEXIST)
{
if (!quiet_flag)
fprintf (stderr, "%s: warning: file `%s' already saved in `%s'\n",
@@ -4407,7 +4374,7 @@ edit_file (hp)
pname,
shortpath (NULL, convert_filename),
shortpath (NULL, new_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
return;
}
}
@@ -4415,8 +4382,10 @@ edit_file (hp)
if (my_unlink (convert_filename) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't delete file `%s': %s\n",
- pname, shortpath (NULL, convert_filename), my_strerror(errno));
+ pname, shortpath (NULL, convert_filename),
+ my_strerror (errno_val));
return;
}
@@ -4427,9 +4396,10 @@ edit_file (hp)
if ((output_file = creat (convert_filename, 0666)) == -1)
{
+ int errno_val = errno;
fprintf (stderr, "%s: can't create/open output file `%s': %s\n",
pname, shortpath (NULL, convert_filename),
- my_strerror(errno));
+ my_strerror (errno_val));
return;
}
@@ -4454,8 +4424,12 @@ edit_file (hp)
/* The cast avoids an erroneous warning on AIX. */
if (my_chmod ((char *)convert_filename, stat_buf.st_mode) == -1)
- fprintf (stderr, "%s: can't change mode of file `%s': %s\n",
- pname, shortpath (NULL, convert_filename), my_strerror(errno));
+ {
+ int errno_val = errno;
+ fprintf (stderr, "%s: can't change mode of file `%s': %s\n",
+ pname, shortpath (NULL, convert_filename),
+ my_strerror (errno_val));
+ }
/* Note: We would try to change the owner and group of the output file
to match those of the input file here, except that may not be a good
@@ -4591,7 +4565,7 @@ main (argc, argv)
int c;
const char *params = "";
- pname = rindex (argv[0], '/');
+ pname = strrchr (argv[0], '/');
pname = pname ? pname+1 : argv[0];
cwd_buffer = getpwd ();
@@ -4599,7 +4573,7 @@ main (argc, argv)
{
fprintf (stderr, "%s: cannot get working directory: %s\n",
pname, my_strerror(errno));
- exit (1);
+ exit (FATAL_EXIT_CODE);
}
/* By default, convert the files in the current directory. */
@@ -4613,7 +4587,7 @@ main (argc, argv)
#endif
longopts, &longind)) != EOF)
{
- if (c == 0) /* Long option. */
+ if (c == 0) /* Long option. */
c = longopts[longind].val;
switch (c)
{
@@ -4683,8 +4657,8 @@ main (argc, argv)
/* Now actually make a list of the base source filenames. */
- base_source_filenames =
- (const char **) xmalloc ((n_base_source_files + 1) * sizeof (char *));
+ base_source_filenames
+ = (const char **) xmalloc ((n_base_source_files + 1) * sizeof (char *));
n_base_source_files = 0;
for (; optind < argc; optind++)
{
@@ -4708,7 +4682,7 @@ main (argc, argv)
{
const char *cp;
- for (cp = varargs_style_indicator; isalnum (*cp) || *cp == '_'; cp++)
+ for (cp = varargs_style_indicator; ISALNUM (*cp) || *cp == '_'; cp++)
continue;
if (*cp != 0)
varargs_style_indicator = savestring (varargs_style_indicator,
@@ -4724,9 +4698,8 @@ main (argc, argv)
fprintf (stderr, "%s: %s\n", pname, version_string);
do_processing ();
}
- if (errors)
- exit (1);
- else
- exit (0);
+
+ exit (errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
+
return 1;
}
diff --git a/contrib/gcc/real.c b/contrib/gcc/real.c
index 082cfd0..ed854e0 100644
--- a/contrib/gcc/real.c
+++ b/contrib/gcc/real.c
@@ -1,6 +1,6 @@
/* real.c - implementation of REAL_ARITHMETIC, REAL_VALUE_ATOF,
and support for XFmode IEEE extended real floating point arithmetic.
- Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
Contributed by Stephen L. Moshier (moshier@world.std.com).
This file is part of GNU CC.
@@ -20,14 +20,10 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
-#include <errno.h>
#include "config.h"
+#include "system.h"
#include "tree.h"
-
-#ifndef errno
-extern int errno;
-#endif
+#include "toplev.h"
/* To enable support of XFmode extended real floating point, define
LONG_DOUBLE_TYPE_SIZE 96 in the tm.h file (m68k.h or i386.h).
@@ -55,7 +51,7 @@ XFmode and TFmode transcendental functions, can be obtained by ftp from
netlib.att.com: netlib/cephes. */
/* Type of computer arithmetic.
- Only one of DEC, IBM, IEEE, or UNK should get defined.
+ Only one of DEC, IBM, IEEE, C4X, or UNK should get defined.
`IEEE', when REAL_WORDS_BIG_ENDIAN is non-zero, refers generically
to big-endian IEEE floating-point data structure. This definition
@@ -80,6 +76,11 @@ netlib.att.com: netlib/cephes. */
no type wider than DFmode. The IBM conversions were contributed by
frank@atom.ansto.gov.au (Frank Crawford).
+ `C4X' refers specifically to the floating point format used on
+ Texas Instruments TMS320C3x and TMS320C4x digital signal
+ processors. This supports QFmode (32-bit float, double) and HFmode
+ (40-bit long double) where BITS_PER_BYTE is 32.
+
If LONG_DOUBLE_TYPE_SIZE = 64 (the default, unless tm.h defines it)
then `long double' and `double' are both implemented, but they
both mean DFmode. In this case, the software floating-point
@@ -117,13 +118,18 @@ netlib.att.com: netlib/cephes. */
/* IBM System/370 style */
#define IBM 1
#else /* it's also not an IBM */
+#if TARGET_FLOAT_FORMAT == C4X_FLOAT_FORMAT
+/* TMS320C3x/C4x style */
+#define C4X 1
+#else /* it's also not a C4X */
#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
#define IEEE
#else /* it's not IEEE either */
-/* UNKnown arithmetic. We don't support this and can't go on. */
+/* UNKnown arithmetic. We don't support this and can't go on. */
unknown arithmetic type
#define UNK 1
#endif /* not IEEE */
+#endif /* not C4X */
#endif /* not IBM */
#endif /* not VAX */
@@ -158,12 +164,12 @@ unknown arithmetic type
/* Define INFINITY for support of infinity.
Define NANS for support of Not-a-Number's (NaN's). */
-#if !defined(DEC) && !defined(IBM)
+#if !defined(DEC) && !defined(IBM) && !defined(C4X)
#define INFINITY
#define NANS
#endif
-/* Support of NaNs requires support of infinity. */
+/* Support of NaNs requires support of infinity. */
#ifdef NANS
#ifndef INFINITY
#define INFINITY
@@ -171,7 +177,7 @@ unknown arithmetic type
#endif
/* Find a host integer type that is at least 16 bits wide,
- and another type at least twice whatever that size is. */
+ and another type at least twice whatever that size is. */
#if HOST_BITS_PER_CHAR >= 16
#define EMUSHORT char
@@ -193,7 +199,7 @@ unknown arithmetic type
#define EMUSHORT_SIZE HOST_BITS_PER_LONG
#define EMULONG_SIZE (2 * HOST_BITS_PER_LONG)
#else
-/* You will have to modify this program to have a smaller unit size. */
+/* You will have to modify this program to have a smaller unit size. */
#define EMU_NON_COMPILE
#endif
#endif
@@ -209,10 +215,10 @@ unknown arithmetic type
#if HOST_BITS_PER_LONG >= EMULONG_SIZE
#define EMULONG long
#else
-#if HOST_BITS_PER_LONG_LONG >= EMULONG_SIZE
+#if HOST_BITS_PER_LONGLONG >= EMULONG_SIZE
#define EMULONG long long int
#else
-/* You will have to modify this program to have a smaller unit size. */
+/* You will have to modify this program to have a smaller unit size. */
#define EMU_NON_COMPILE
#endif
#endif
@@ -220,12 +226,12 @@ unknown arithmetic type
#endif
-/* The host interface doesn't work if no 16-bit size exists. */
+/* The host interface doesn't work if no 16-bit size exists. */
#if EMUSHORT_SIZE != 16
#define EMU_NON_COMPILE
#endif
-/* OK to continue compilation. */
+/* OK to continue compilation. */
#ifndef EMU_NON_COMPILE
/* Construct macros to translate between REAL_VALUE_TYPE and e type.
@@ -253,12 +259,12 @@ unknown arithmetic type
#define MINDECEXP -4956
#ifdef REAL_ARITHMETIC
/* Emulator uses target format internally
- but host stores it in host endian-ness. */
+ but host stores it in host endian-ness. */
#define GET_REAL(r,e) \
do { \
if (HOST_FLOAT_WORDS_BIG_ENDIAN == REAL_WORDS_BIG_ENDIAN) \
- e53toe ((unsigned EMUSHORT*) (r), (e)); \
+ e53toe ((unsigned EMUSHORT *) (r), (e)); \
else \
{ \
unsigned EMUSHORT w[4]; \
@@ -293,7 +299,7 @@ do { \
#endif /* not REAL_ARITHMETIC */
#endif /* not TFmode */
-#endif /* no XFmode */
+#endif /* not XFmode */
/* Number of 16 bit words in internal format */
@@ -324,7 +330,9 @@ static void endian PROTO((unsigned EMUSHORT *, long *,
enum machine_mode));
static void eclear PROTO((unsigned EMUSHORT *));
static void emov PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
+#if 0
static void eabs PROTO((unsigned EMUSHORT *));
+#endif
static void eneg PROTO((unsigned EMUSHORT *));
static int eisneg PROTO((unsigned EMUSHORT *));
static int eisinf PROTO((unsigned EMUSHORT *));
@@ -339,7 +347,9 @@ static void emovz PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void einan PROTO((unsigned EMUSHORT *));
static int eiisnan PROTO((unsigned EMUSHORT *));
static int eiisneg PROTO((unsigned EMUSHORT *));
+#if 0
static void eiinfin PROTO((unsigned EMUSHORT *));
+#endif
static int eiisinf PROTO((unsigned EMUSHORT *));
static int ecmpm PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void eshdn1 PROTO((unsigned EMUSHORT *));
@@ -378,7 +388,9 @@ static void toe53 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void etoe24 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void toe24 PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static int ecmp PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
+#if 0
static void eround PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
+#endif
static void ltoe PROTO((HOST_WIDE_INT *, unsigned EMUSHORT *));
static void ultoe PROTO((unsigned HOST_WIDE_INT *, unsigned EMUSHORT *));
static void eifrac PROTO((unsigned EMUSHORT *, HOST_WIDE_INT *,
@@ -387,10 +399,12 @@ static void euifrac PROTO((unsigned EMUSHORT *, unsigned HOST_WIDE_INT *,
unsigned EMUSHORT *));
static int eshift PROTO((unsigned EMUSHORT *, int));
static int enormlz PROTO((unsigned EMUSHORT *));
+#if 0
static void e24toasc PROTO((unsigned EMUSHORT *, char *, int));
static void e53toasc PROTO((unsigned EMUSHORT *, char *, int));
static void e64toasc PROTO((unsigned EMUSHORT *, char *, int));
static void e113toasc PROTO((unsigned EMUSHORT *, char *, int));
+#endif /* 0 */
static void etoasc PROTO((unsigned EMUSHORT *, char *, int));
static void asctoe24 PROTO((char *, unsigned EMUSHORT *));
static void asctoe53 PROTO((char *, unsigned EMUSHORT *));
@@ -399,28 +413,46 @@ static void asctoe113 PROTO((char *, unsigned EMUSHORT *));
static void asctoe PROTO((char *, unsigned EMUSHORT *));
static void asctoeg PROTO((char *, unsigned EMUSHORT *, int));
static void efloor PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
+#if 0
static void efrexp PROTO((unsigned EMUSHORT *, int *,
unsigned EMUSHORT *));
+#endif
static void eldexp PROTO((unsigned EMUSHORT *, int, unsigned EMUSHORT *));
+#if 0
static void eremain PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
unsigned EMUSHORT *));
+#endif
static void eiremain PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void mtherr PROTO((char *, int));
+#ifdef DEC
static void dectoe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void etodec PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void todec PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
+#endif
+#ifdef IBM
static void ibmtoe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
enum machine_mode));
static void etoibm PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
enum machine_mode));
static void toibm PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
enum machine_mode));
+#endif
+#ifdef C4X
+static void c4xtoe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
+ enum machine_mode));
+static void etoc4x PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
+ enum machine_mode));
+static void toc4x PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *,
+ enum machine_mode));
+#endif
static void make_nan PROTO((unsigned EMUSHORT *, int, enum machine_mode));
+#if 0
static void uditoe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void ditoe PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void etoudi PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void etodi PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
static void esqrt PROTO((unsigned EMUSHORT *, unsigned EMUSHORT *));
+#endif
/* Copy 32-bit numbers obtained from array containing 16-bit numbers,
swapping ends if required, into output array of longs. The
@@ -438,17 +470,15 @@ endian (e, x, mode)
{
switch (mode)
{
-
case TFmode:
- /* Swap halfwords in the fourth long. */
+ /* Swap halfwords in the fourth long. */
th = (unsigned long) e[6] & 0xffff;
t = (unsigned long) e[7] & 0xffff;
t |= th << 16;
x[3] = (long) t;
case XFmode:
-
- /* Swap halfwords in the third long. */
+ /* Swap halfwords in the third long. */
th = (unsigned long) e[4] & 0xffff;
t = (unsigned long) e[5] & 0xffff;
t |= th << 16;
@@ -456,22 +486,20 @@ endian (e, x, mode)
/* fall into the double case */
case DFmode:
-
- /* swap halfwords in the second word */
+ /* Swap halfwords in the second word. */
th = (unsigned long) e[2] & 0xffff;
t = (unsigned long) e[3] & 0xffff;
t |= th << 16;
x[1] = (long) t;
/* fall into the float case */
- case HFmode:
case SFmode:
-
- /* swap halfwords in the first word */
+ case HFmode:
+ /* Swap halfwords in the first word. */
th = (unsigned long) e[0] & 0xffff;
t = (unsigned long) e[1] & 0xffff;
t |= th << 16;
- x[0] = t;
+ x[0] = (long) t;
break;
default:
@@ -480,21 +508,18 @@ endian (e, x, mode)
}
else
{
- /* Pack the output array without swapping. */
+ /* Pack the output array without swapping. */
switch (mode)
{
-
case TFmode:
-
- /* Pack the fourth long. */
+ /* Pack the fourth long. */
th = (unsigned long) e[7] & 0xffff;
t = (unsigned long) e[6] & 0xffff;
t |= th << 16;
x[3] = (long) t;
case XFmode:
-
/* Pack the third long.
Each element of the input REAL_VALUE_TYPE array has 16 useful bits
in it. */
@@ -505,22 +530,20 @@ endian (e, x, mode)
/* fall into the double case */
case DFmode:
-
- /* pack the second long */
+ /* Pack the second long */
th = (unsigned long) e[3] & 0xffff;
t = (unsigned long) e[2] & 0xffff;
t |= th << 16;
x[1] = (long) t;
/* fall into the float case */
- case HFmode:
case SFmode:
-
- /* pack the first long */
+ case HFmode:
+ /* Pack the first long */
th = (unsigned long) e[1] & 0xffff;
t = (unsigned long) e[0] & 0xffff;
t |= th << 16;
- x[0] = t;
+ x[0] = (long) t;
break;
default:
@@ -545,7 +568,7 @@ earith (value, icode, r1, r2)
GET_REAL (r1, d1);
GET_REAL (r2, d2);
#ifdef NANS
-/* Return NaN input back to the caller. */
+/* Return NaN input back to the caller. */
if (eisnan (d1))
{
PUT_REAL (d1, value);
@@ -668,23 +691,36 @@ ereal_atof (s, t)
switch (t)
{
+#ifdef C4X
+ case QFmode:
+ case HFmode:
+ asctoe53 (s, tem);
+ e53toe (tem, e);
+ break;
+#else
case HFmode:
+#endif
+
case SFmode:
asctoe24 (s, tem);
e24toe (tem, e);
break;
+
case DFmode:
asctoe53 (s, tem);
e53toe (tem, e);
break;
+
case XFmode:
asctoe64 (s, tem);
e64toe (tem, e);
break;
+
case TFmode:
asctoe113 (s, tem);
e113toe (tem, e);
break;
+
default:
asctoe (s, e);
}
@@ -758,14 +794,17 @@ efixui (x)
/* REAL_VALUE_FROM_INT macro. */
void
-ereal_from_int (d, i, j)
+ereal_from_int (d, i, j, mode)
REAL_VALUE_TYPE *d;
HOST_WIDE_INT i, j;
+ enum machine_mode mode;
{
unsigned EMUSHORT df[NE], dg[NE];
HOST_WIDE_INT low, high;
int sign;
+ if (GET_MODE_CLASS (mode) != MODE_FLOAT)
+ abort ();
sign = 0;
low = i;
if ((high = j) < 0)
@@ -785,6 +824,36 @@ ereal_from_int (d, i, j)
eadd (df, dg, dg);
if (sign)
eneg (dg);
+
+ /* A REAL_VALUE_TYPE may not be wide enough to hold the two HOST_WIDE_INTS.
+ Avoid double-rounding errors later by rounding off now from the
+ extra-wide internal format to the requested precision. */
+ switch (GET_MODE_BITSIZE (mode))
+ {
+ case 32:
+ etoe24 (dg, df);
+ e24toe (df, dg);
+ break;
+
+ case 64:
+ etoe53 (dg, df);
+ e53toe (df, dg);
+ break;
+
+ case 96:
+ etoe64 (dg, df);
+ e64toe (df, dg);
+ break;
+
+ case 128:
+ etoe113 (dg, df);
+ e113toe (df, dg);
+ break;
+
+ default:
+ abort ();
+ }
+
PUT_REAL (dg, d);
}
@@ -792,13 +861,16 @@ ereal_from_int (d, i, j)
/* REAL_VALUE_FROM_UNSIGNED_INT macro. */
void
-ereal_from_uint (d, i, j)
+ereal_from_uint (d, i, j, mode)
REAL_VALUE_TYPE *d;
unsigned HOST_WIDE_INT i, j;
+ enum machine_mode mode;
{
unsigned EMUSHORT df[NE], dg[NE];
unsigned HOST_WIDE_INT low, high;
+ if (GET_MODE_CLASS (mode) != MODE_FLOAT)
+ abort ();
low = i;
high = j;
eldexp (eone, HOST_BITS_PER_WIDE_INT, df);
@@ -806,6 +878,36 @@ ereal_from_uint (d, i, j)
emul (dg, df, dg);
ultoe (&low, df);
eadd (df, dg, dg);
+
+ /* A REAL_VALUE_TYPE may not be wide enough to hold the two HOST_WIDE_INTS.
+ Avoid double-rounding errors later by rounding off now from the
+ extra-wide internal format to the requested precision. */
+ switch (GET_MODE_BITSIZE (mode))
+ {
+ case 32:
+ etoe24 (dg, df);
+ e24toe (df, dg);
+ break;
+
+ case 64:
+ etoe53 (dg, df);
+ e53toe (df, dg);
+ break;
+
+ case 96:
+ etoe64 (dg, df);
+ e64toe (df, dg);
+ break;
+
+ case 128:
+ etoe113 (dg, df);
+ e113toe (df, dg);
+ break;
+
+ default:
+ abort ();
+ }
+
PUT_REAL (dg, d);
}
@@ -879,7 +981,7 @@ ereal_ldexp (x, n)
#ifdef REAL_ARITHMETIC
-/* Check for infinity in a REAL_VALUE_TYPE. */
+/* Check for infinity in a REAL_VALUE_TYPE. */
int
target_isinf (x)
@@ -895,7 +997,7 @@ target_isinf (x)
#endif
}
-/* Check whether a REAL_VALUE_TYPE item is a NaN. */
+/* Check whether a REAL_VALUE_TYPE item is a NaN. */
int
target_isnan (x)
@@ -913,7 +1015,7 @@ target_isnan (x)
/* Check for a negative REAL_VALUE_TYPE number.
- This just checks the sign bit, so that -0 counts as negative. */
+ This just checks the sign bit, so that -0 counts as negative. */
int
target_negative (x)
@@ -956,12 +1058,22 @@ real_value_truncate (mode, arg)
e53toe (t, t);
break;
- case HFmode:
case SFmode:
+#ifndef C4X
+ case HFmode:
+#endif
etoe24 (e, t);
e24toe (t, t);
break;
+#ifdef C4X
+ case HFmode:
+ case QFmode:
+ etoe53 (e, t);
+ e53toe (t, t);
+ break;
+#endif
+
case SImode:
r = etrunci (arg);
return (r);
@@ -977,6 +1089,68 @@ real_value_truncate (mode, arg)
return (r);
}
+/* Try to change R into its exact multiplicative inverse in machine mode
+ MODE. Return nonzero function value if successful. */
+
+int
+exact_real_inverse (mode, r)
+ enum machine_mode mode;
+ REAL_VALUE_TYPE *r;
+{
+ unsigned EMUSHORT e[NE], einv[NE];
+ REAL_VALUE_TYPE rinv;
+ int i;
+
+ GET_REAL (r, e);
+
+ /* Test for input in range. Don't transform IEEE special values. */
+ if (eisinf (e) || eisnan (e) || (ecmp (e, ezero) == 0))
+ return 0;
+
+ /* Test for a power of 2: all significand bits zero except the MSB.
+ We are assuming the target has binary (or hex) arithmetic. */
+ if (e[NE - 2] != 0x8000)
+ return 0;
+
+ for (i = 0; i < NE - 2; i++)
+ {
+ if (e[i] != 0)
+ return 0;
+ }
+
+ /* Compute the inverse and truncate it to the required mode. */
+ ediv (e, eone, einv);
+ PUT_REAL (einv, &rinv);
+ rinv = real_value_truncate (mode, rinv);
+
+#ifdef CHECK_FLOAT_VALUE
+ /* This check is not redundant. It may, for example, flush
+ a supposedly IEEE denormal value to zero. */
+ i = 0;
+ if (CHECK_FLOAT_VALUE (mode, rinv, i))
+ return 0;
+#endif
+ GET_REAL (&rinv, einv);
+
+ /* Check the bits again, because the truncation might have
+ generated an arbitrary saturation value on overflow. */
+ if (einv[NE - 2] != 0x8000)
+ return 0;
+
+ for (i = 0; i < NE - 2; i++)
+ {
+ if (einv[i] != 0)
+ return 0;
+ }
+
+ /* Fail if the computed inverse is out of range. */
+ if (eisinf (einv) || eisnan (einv) || (ecmp (einv, ezero) == 0))
+ return 0;
+
+ /* Output the reciprocal and return success flag. */
+ PUT_REAL (einv, r);
+ return 1;
+}
#endif /* REAL_ARITHMETIC defined */
/* Used for debugging--print the value of R in human-readable format
@@ -1150,7 +1324,9 @@ ereal_isneg (x)
e53toe (&d, e) IEEE double precision to e type
e64toe (&d, e) IEEE long double precision to e type
e113toe (&d, e) 128-bit long double precision to e type
+#if 0
eabs (e) absolute value
+#endif
eadd (a, b, c) c = b + a
eclear (e) e = 0
ecmp (a, b) Returns 1 if a > b, 0 if a == b,
@@ -1165,12 +1341,16 @@ ereal_isneg (x)
emov (a, b) b = a
emul (a, b, c) c = b * a
eneg (e) e = -e
+#if 0
eround (a, b) b = nearest integer value to a
+#endif
esub (a, b, c) c = b - a
+#if 0
e24toasc (&f, str, n) single to ASCII string, n digits after decimal
e53toasc (&d, str, n) double to ASCII string, n digits after decimal
e64toasc (&d, str, n) 80-bit long double to ASCII string
e113toasc (&d, str, n) 128-bit long double to ASCII string
+#endif
etoasc (e, str, n) e to ASCII string, n digits after decimal
etoe24 (e, &f) convert e type to IEEE single precision
etoe53 (e, &d) convert e type to IEEE double precision
@@ -1208,7 +1388,9 @@ ereal_isneg (x)
eiisnan (ai) 1 if a NaN
eiisneg (ai) 1 if sign bit of ai != 0, else 0
einan (ai) set ai = NaN
+#if 0
eiinfin (ai) set ai = infinity
+#endif
The result is always normalized and rounded to NI-4 word precision
after each arithmetic operation.
@@ -1264,7 +1446,7 @@ ereal_isneg (x)
ensure that these values are correct for your computer.
For ANSI C compatibility, define ANSIC equal to 1. Currently
- this affects only the atan2 function and others that use it. */
+ this affects only the atan2 function and others that use it. */
/* Constant definitions for math error conditions. */
@@ -1378,6 +1560,7 @@ emov (a, b)
}
+#if 0
/* Absolute value of e-type X. */
static void
@@ -1387,6 +1570,7 @@ eabs (x)
/* sign is top bit of last word of external format */
x[NE - 1] &= 0x7fff;
}
+#endif /* 0 */
/* Negate the e-type number X. */
@@ -1441,7 +1625,7 @@ eisnan (x)
/* NaN has maximum exponent */
if ((x[NE - 1] & 0x7fff) != 0x7fff)
return (0);
- /* ... and non-zero significand field. */
+ /* ... and non-zero significand field. */
for (i = 0; i < NE - 1; i++)
{
if (*x++ != 0)
@@ -1453,7 +1637,7 @@ eisnan (x)
}
/* Fill e-type number X with infinity pattern (IEEE)
- or largest possible number (non-IEEE). */
+ or largest possible number (non-IEEE). */
static void
einfin (x)
@@ -1609,7 +1793,7 @@ ecleaz (xi)
*xi++ = 0;
}
-/* Clear out exploded e-type XI, but don't touch the sign. */
+/* Clear out exploded e-type XI, but don't touch the sign. */
static void
ecleazs (xi)
@@ -1650,7 +1834,7 @@ einan (x)
x[M + 1] = 0xc000;
}
-/* Return nonzero if exploded e-type X is a NaN. */
+/* Return nonzero if exploded e-type X is a NaN. */
static int
eiisnan (x)
@@ -1679,6 +1863,7 @@ eiisneg (x)
return x[0] != 0;
}
+#if 0
/* Fill exploded e-type X with infinity pattern.
This has maximum exponent and significand all zeros. */
@@ -1690,8 +1875,9 @@ eiinfin (x)
ecleaz (x);
x[E] = 0x7fff;
}
+#endif /* 0 */
-/* Return nonzero if exploded e-type X is infinite. */
+/* Return nonzero if exploded e-type X is infinite. */
static int
eiisinf (x)
@@ -2024,6 +2210,7 @@ edivm (den, num)
/* Multiply significands */
+
int
emulm (a, b)
unsigned EMUSHORT a[], b[];
@@ -2074,7 +2261,7 @@ emulm (a, b)
/* Radix 65536 versions of multiply and divide. */
/* Multiply significand of e-type number B
- by 16-bit quantity A, return e-type result to C. */
+ by 16-bit quantity A, return e-type result to C. */
static void
m16m (a, b, c)
@@ -2142,17 +2329,17 @@ edivm (den, num)
tdenm = den[M+1];
for (i=M; i<NI; i++)
{
- /* Find trial quotient digit (the radix is 65536). */
+ /* Find trial quotient digit (the radix is 65536). */
tnum = (((unsigned EMULONG) num[M]) << 16) + num[M+1];
- /* Do not execute the divide instruction if it will overflow. */
+ /* Do not execute the divide instruction if it will overflow. */
if ((tdenm * 0xffffL) < tnum)
tquot = 0xffff;
else
tquot = tnum / tdenm;
- /* Multiply denominator by trial quotient digit. */
+ /* Multiply denominator by trial quotient digit. */
m16m ((unsigned int)tquot, den, tprod);
- /* The quotient digit may have been overestimated. */
+ /* The quotient digit may have been overestimated. */
if (ecmpm (tprod, num) > 0)
{
tquot -= 1;
@@ -2275,7 +2462,7 @@ emdnorm (s, lost, subflg, exp, rcntrl)
/* Normalize */
j = enormlz (s);
- /* a blank significand could mean either zero or infinity. */
+ /* a blank significand could mean either zero or infinity. */
#ifndef INFINITY
if (j > NBITS)
{
@@ -2309,10 +2496,10 @@ emdnorm (s, lost, subflg, exp, rcntrl)
return;
}
}
- /* Round off, unless told not to by rcntrl. */
+ /* Round off, unless told not to by rcntrl. */
if (rcntrl == 0)
goto mdfin;
- /* Set up rounding parameters if the control register changed. */
+ /* Set up rounding parameters if the control register changed. */
if (rndprc != rlast)
{
ecleaz (rbit);
@@ -2326,6 +2513,7 @@ emdnorm (s, lost, subflg, exp, rcntrl)
re = rw - 1;
rebit = 1;
break;
+
case 113:
rw = 10;
rmsk = 0x7fff;
@@ -2333,6 +2521,7 @@ emdnorm (s, lost, subflg, exp, rcntrl)
rebit = 0x8000;
re = rw;
break;
+
case 64:
rw = 7;
rmsk = 0xffff;
@@ -2340,6 +2529,7 @@ emdnorm (s, lost, subflg, exp, rcntrl)
re = rw - 1;
rebit = 1;
break;
+
/* For DEC or IBM arithmetic */
case 56:
rw = 6;
@@ -2348,6 +2538,7 @@ emdnorm (s, lost, subflg, exp, rcntrl)
rebit = 0x100;
re = rw;
break;
+
case 53:
rw = 6;
rmsk = 0x7ff;
@@ -2355,6 +2546,16 @@ emdnorm (s, lost, subflg, exp, rcntrl)
rebit = 0x800;
re = rw;
break;
+
+ /* For C4x arithmetic */
+ case 32:
+ rw = 5;
+ rmsk = 0xffff;
+ rmbit = 0x8000;
+ rebit = 1;
+ re = rw - 1;
+ break;
+
case 24:
rw = 4;
rmsk = 0xff;
@@ -2409,7 +2610,7 @@ emdnorm (s, lost, subflg, exp, rcntrl)
eaddm (rbit, s);
}
mddone:
-/* Undo the temporary shift for denormal values. */
+/* Undo the temporary shift for denormal values. */
if ((exp <= 0) && (rndprc != NBITS)
&& ((rndprc != 64) || ((rndprc == 64) && ! REAL_WORDS_BIG_ENDIAN)))
{
@@ -2478,7 +2679,7 @@ esub (a, b, c)
return;
}
/* Infinity minus infinity is a NaN.
- Test for subtracting infinities of the same sign. */
+ Test for subtracting infinities of the same sign. */
if (eisinf (a) && eisinf (b)
&& ((eisneg (a) ^ eisneg (b)) == 0))
{
@@ -2491,7 +2692,7 @@ esub (a, b, c)
eadd1 (a, b, c);
}
-/* Add. C = A + B, all e type. */
+/* Add. C = A + B, all e type. */
static void
eadd (a, b, c)
@@ -2499,7 +2700,7 @@ eadd (a, b, c)
{
#ifdef NANS
-/* NaN plus anything is a NaN. */
+/* NaN plus anything is a NaN. */
if (eisnan (a))
{
emov (a, c);
@@ -2511,7 +2712,7 @@ eadd (a, b, c)
return;
}
/* Infinity minus infinity is a NaN.
- Test for adding infinities of opposite signs. */
+ Test for adding infinities of opposite signs. */
if (eisinf (a) && eisinf (b)
&& ((eisneg (a) ^ eisneg (b)) != 0))
{
@@ -2597,8 +2798,15 @@ eadd1 (a, b, c)
{
if (bi[j] != 0)
{
- /* This could overflow, but let emovo take care of that. */
ltb += 1;
+ if (ltb >= 0x7fff)
+ {
+ eclear (c);
+ if (ai[0] != 0)
+ eneg (c);
+ einfin (c);
+ return;
+ }
break;
}
}
@@ -2643,7 +2851,7 @@ ediv (a, b, c)
sign = eisneg(a) ^ eisneg(b);
#ifdef NANS
-/* Return any NaN input. */
+/* Return any NaN input. */
if (eisnan (a))
{
emov (a, c);
@@ -2654,7 +2862,7 @@ ediv (a, b, c)
emov (b, c);
return;
}
-/* Zero over zero, or infinity over infinity, is a NaN. */
+/* Zero over zero, or infinity over infinity, is a NaN. */
if (((ecmp (a, ezero) == 0) && (ecmp (b, ezero) == 0))
|| (eisinf (a) && eisinf (b)))
{
@@ -2663,14 +2871,14 @@ ediv (a, b, c)
return;
}
#endif
-/* Infinity over anything else is infinity. */
+/* Infinity over anything else is infinity. */
#ifdef INFINITY
if (eisinf (b))
{
einfin (c);
goto divsign;
}
-/* Anything else over infinity is zero. */
+/* Anything else over infinity is zero. */
if (eisinf (a))
{
eclear (c);
@@ -2682,7 +2890,7 @@ ediv (a, b, c)
lta = ai[E];
ltb = bi[E];
if (bi[E] == 0)
- { /* See if numerator is zero. */
+ { /* See if numerator is zero. */
for (i = 1; i < NI - 1; i++)
{
if (bi[i] != 0)
@@ -2747,7 +2955,7 @@ emul (a, b, c)
sign = eisneg(a) ^ eisneg(b);
#ifdef NANS
-/* NaN times anything is the same NaN. */
+/* NaN times anything is the same NaN. */
if (eisnan (a))
{
emov (a, c);
@@ -2758,7 +2966,7 @@ emul (a, b, c)
emov (b, c);
return;
}
-/* Zero times infinity is a NaN. */
+/* Zero times infinity is a NaN. */
if ((eisinf (a) && (ecmp (b, ezero) == 0))
|| (eisinf (b) && (ecmp (a, ezero) == 0)))
{
@@ -2767,7 +2975,7 @@ emul (a, b, c)
return;
}
#endif
-/* Infinity times anything else is infinity. */
+/* Infinity times anything else is infinity. */
#ifdef INFINITY
if (eisinf (a) || eisinf (b))
{
@@ -2844,6 +3052,11 @@ e53toe (pe, y)
ibmtoe (pe, y, DFmode);
#else
+#ifdef C4X
+
+ c4xtoe (pe, y, HFmode);
+
+#else
register unsigned EMUSHORT r;
register unsigned EMUSHORT *e, *p;
unsigned EMUSHORT yy[NI];
@@ -2892,7 +3105,7 @@ e53toe (pe, y)
#endif /* INFINITY */
r >>= 4;
/* If zero exponent, then the significand is denormalized.
- So take back the understood high significand bit. */
+ So take back the understood high significand bit. */
if (r == 0)
{
@@ -2919,13 +3132,15 @@ e53toe (pe, y)
#endif
eshift (yy, -5);
if (denorm)
- { /* if zero exponent, then normalize the significand */
+ {
+ /* If zero exponent, then normalize the significand. */
if ((k = enormlz (yy)) > NBITS)
ecleazs (yy);
else
yy[E] -= (unsigned EMUSHORT) (k - 1);
}
emovo (yy, y);
+#endif /* not C4X */
#endif /* not IBM */
#endif /* not DEC */
}
@@ -2944,7 +3159,7 @@ e64toe (pe, y)
p = yy;
for (i = 0; i < NE - 5; i++)
*p++ = 0;
-/* This precision is not ordinarily supported on DEC or IBM. */
+/* This precision is not ordinarily supported on DEC or IBM. */
#ifdef DEC
for (i = 0; i < 5; i++)
*p++ = *e++;
@@ -2978,8 +3193,14 @@ e64toe (pe, y)
else
{
p = &yy[0] + (NE - 1);
+#ifdef ARM_EXTENDED_IEEE_FORMAT
+ /* For ARMs, the exponent is in the lowest 15 bits of the word. */
+ *p-- = (e[0] & 0x8000) | (e[1] & 0x7ffff);
+ e += 2;
+#else
*p-- = *e++;
++e;
+#endif
for (i = 0; i < 4; i++)
*p-- = *e++;
}
@@ -2987,7 +3208,7 @@ e64toe (pe, y)
#ifdef INFINITY
/* Point to the exponent field and check max exponent cases. */
p = &yy[NE - 1];
- if (*p == 0x7fff)
+ if ((*p & 0x7fff) == 0x7fff)
{
#ifdef NANS
if (! REAL_WORDS_BIG_ENDIAN)
@@ -3005,7 +3226,8 @@ e64toe (pe, y)
}
else
{
- for (i = 1; i <= 4; i++)
+#ifdef ARM_EXTENDED_IEEE_FORMAT
+ for (i = 2; i <= 5; i++)
{
if (pe[i] != 0)
{
@@ -3013,6 +3235,23 @@ e64toe (pe, y)
return;
}
}
+#else /* not ARM */
+ /* In Motorola extended precision format, the most significant
+ bit of an infinity mantissa could be either 1 or 0. It is
+ the lower order bits that tell whether the value is a NaN. */
+ if ((pe[2] & 0x7fff) != 0)
+ goto bigend_nan;
+
+ for (i = 3; i <= 5; i++)
+ {
+ if (pe[i] != 0)
+ {
+bigend_nan:
+ enan (y, (*p & 0x8000) != 0);
+ return;
+ }
+ }
+#endif /* not ARM */
}
#endif /* NANS */
eclear (y);
@@ -3100,7 +3339,7 @@ e113toe (pe, y)
*p++ = *e++;
}
#endif
-/* If denormal, remove the implied bit; else shift down 1. */
+/* If denormal, remove the implied bit; else shift down 1. */
if (r == 0)
{
yy[M] = 0;
@@ -3124,6 +3363,13 @@ e24toe (pe, y)
ibmtoe (pe, y, SFmode);
#else
+
+#ifdef C4X
+
+ c4xtoe (pe, y, QFmode);
+
+#else
+
register unsigned EMUSHORT r;
register unsigned EMUSHORT *e, *p;
unsigned EMUSHORT yy[NI];
@@ -3175,7 +3421,7 @@ e24toe (pe, y)
#endif /* INFINITY */
r >>= 7;
/* If zero exponent, then the significand is denormalized.
- So take back the understood high significand bit. */
+ So take back the understood high significand bit. */
if (r == 0)
{
denorm = 1;
@@ -3205,6 +3451,7 @@ e24toe (pe, y)
yy[E] -= (unsigned EMUSHORT) (k - 1);
}
emovo (yy, y);
+#endif /* not C4X */
#endif /* not IBM */
}
@@ -3263,7 +3510,7 @@ toe113 (a, b)
else
q = b + 7; /* point to output exponent */
- /* If not denormal, delete the implied bit. */
+ /* If not denormal, delete the implied bit. */
if (a[E] != 0)
{
eshup1 (a);
@@ -3390,11 +3637,17 @@ toe64 (a, b)
#ifdef IEEE
if (REAL_WORDS_BIG_ENDIAN)
{
+#ifdef ARM_EXTENDED_IEEE_FORMAT
+ /* The exponent is in the lowest 15 bits of the first word. */
+ *q++ = i ? 0x8000 : 0;
+ *q++ = *p++;
+#else
if (i)
*q++ = *p++ | 0x8000;
else
*q++ = *p++;
*q++ = 0;
+#endif
}
else
{
@@ -3483,7 +3736,28 @@ toe53 (x, y)
toibm (x, y, DFmode);
}
-#else /* it's neither DEC nor IBM */
+#else /* it's neither DEC nor IBM */
+#ifdef C4X
+/* Convert e-type X to C4X-format long double E. */
+
+static void
+etoe53 (x, e)
+ unsigned EMUSHORT *x, *e;
+{
+ etoc4x (x, e, HFmode);
+}
+
+/* Convert exploded e-type X, that has already been rounded to
+ 56-bit precision, to IBM 370 double Y. */
+
+static void
+toe53 (x, y)
+ unsigned EMUSHORT *x, *y;
+{
+ toc4x (x, y, HFmode);
+}
+
+#else /* it's neither DEC nor IBM nor C4X */
/* Convert e-type X to IEEE double E. */
@@ -3546,7 +3820,8 @@ toe53 (x, y)
i = *p++;
if (i >= (unsigned int) 2047)
- { /* Saturate at largest number less than infinity. */
+ {
+ /* Saturate at largest number less than infinity. */
#ifdef INFINITY
*y |= 0x7ff0;
if (! REAL_WORDS_BIG_ENDIAN)
@@ -3606,6 +3881,7 @@ toe53 (x, y)
}
}
+#endif /* not C4X */
#endif /* not IBM */
#endif /* not DEC */
@@ -3634,6 +3910,29 @@ toe24 (x, y)
}
#else
+
+#ifdef C4X
+/* Convert e-type X to C4X float E. */
+
+static void
+etoe24 (x, e)
+ unsigned EMUSHORT *x, *e;
+{
+ etoc4x (x, e, QFmode);
+}
+
+/* Convert exploded e-type X, that has already been rounded to
+ float precision, to IBM 370 float Y. */
+
+static void
+toe24 (x, y)
+ unsigned EMUSHORT *x, *y;
+{
+ toc4x (x, y, QFmode);
+}
+
+#else
+
/* Convert e-type X to IEEE float E. DEC float is the same as IEEE float. */
static void
@@ -3697,7 +3996,7 @@ toe24 (x, y)
*y = 0x8000; /* output sign bit */
i = *p++;
-/* Handle overflow cases. */
+/* Handle overflow cases. */
if (i >= 255)
{
#ifdef INFINITY
@@ -3759,6 +4058,7 @@ toe24 (x, y)
}
#endif
}
+#endif /* not C4X */
#endif /* not IBM */
/* Compare two e type numbers.
@@ -3827,6 +4127,7 @@ ecmp (a, b)
return (-msign); /* p is littler */
}
+#if 0
/* Find e-type nearest integer to X, as floor (X + 0.5). */
static void
@@ -3836,6 +4137,7 @@ eround (x, y)
eadd (ehalf, x, y);
efloor (y, y);
}
+#endif /* 0 */
/* Convert HOST_WIDE_INT LP to e type Y. */
@@ -4057,7 +4359,7 @@ euifrac (x, i, frac)
*i = (HOST_WIDE_INT) xi[M] & 0xffff;
}
- if (xi[0]) /* A negative value yields unsigned integer 0. */
+ if (xi[0]) /* A negative value yields unsigned integer 0. */
*i = 0L;
xi[0] = 0;
@@ -4307,6 +4609,7 @@ static unsigned EMUSHORT emtens[NTEN + 1][NE] =
};
#endif
+#if 0
/* Convert float value X to ASCII string STRING with NDIG digits after
the decimal point. */
@@ -4366,6 +4669,7 @@ e113toasc (x, string, ndigs)
e113toe (x, w);
etoasc (w, string, ndigs);
}
+#endif /* 0 */
/* Convert e-type X to ASCII string STRING with NDIGS digits after
the decimal point. */
@@ -4425,7 +4729,7 @@ etoasc (x, string, ndigs)
}
tnzro:
- /* Test for infinity. */
+ /* Test for infinity. */
if (y[NE - 1] == 0x7fff)
{
if (sign)
@@ -4455,7 +4759,7 @@ etoasc (x, string, ndigs)
if (i < 0)
{ /* Number is greater than 1 */
- /* Convert significand to an integer and strip trailing decimal zeros. */
+ /* Convert significand to an integer and strip trailing decimal zeros. */
emov (y, u);
u[NE - 1] = EXONE + NBITS - 1;
@@ -4485,7 +4789,7 @@ etoasc (x, string, ndigs)
emov (eone, t);
m = MAXP;
p = &etens[0][0];
- /* An unordered compare result shouldn't happen here. */
+ /* An unordered compare result shouldn't happen here. */
while (ecmp (ten, u) <= 0)
{
if (ecmp (p, u) <= 0)
@@ -4502,7 +4806,7 @@ etoasc (x, string, ndigs)
}
else
{ /* Number is less than 1.0 */
- /* Pad significand with trailing decimal zeros. */
+ /* Pad significand with trailing decimal zeros. */
if (y[NE - 1] == 0)
{
while ((y[NE - 2] & 0x8000) == 0)
@@ -4560,7 +4864,7 @@ etoasc (x, string, ndigs)
ediv (t, eone, t);
}
isone:
- /* Find the first (leading) digit. */
+ /* Find the first (leading) digit. */
emovi (t, w);
emovz (w, t);
emovi (y, w);
@@ -4583,7 +4887,7 @@ etoasc (x, string, ndigs)
*s++ = '-';
else
*s++ = ' ';
- /* Examine number of digits requested by caller. */
+ /* Examine number of digits requested by caller. */
if (ndigs < 0)
ndigs = 0;
if (ndigs > NDEC)
@@ -4604,7 +4908,7 @@ etoasc (x, string, ndigs)
*s++ = (char)digit + '0';
*s++ = '.';
}
- /* Generate digits after the decimal point. */
+ /* Generate digits after the decimal point. */
for (k = 0; k <= ndigs; k++)
{
/* multiply current number by 10, without normalizing */
@@ -4622,7 +4926,7 @@ etoasc (x, string, ndigs)
/* round off the ASCII string */
if (digit > 4)
{
- /* Test for critical rounding case in ASCII output. */
+ /* Test for critical rounding case in ASCII output. */
if (digit == 5)
{
emovo (y, t);
@@ -4707,8 +5011,12 @@ asctoe53 (s, y)
#if defined(DEC) || defined(IBM)
asctoeg (s, y, 56);
#else
+#if defined(C4X)
+ asctoeg (s, y, 32);
+#else
asctoeg (s, y, 53);
#endif
+#endif
}
@@ -4743,7 +5051,7 @@ asctoe (s, y)
}
/* Convert ASCII string SS to e type Y, with a specified rounding precision
- of OPREC bits. */
+ of OPREC bits. */
static void
asctoeg (ss, y, oprec)
@@ -4758,7 +5066,7 @@ asctoeg (ss, y, oprec)
unsigned EMUSHORT nsign, *p;
char *sp, *s, *lstr;
- /* Copy the input string. */
+ /* Copy the input string. */
lstr = (char *) alloca (strlen (ss) + 1);
s = ss;
while (*s == ' ') /* skip leading spaces */
@@ -4787,7 +5095,7 @@ asctoeg (ss, y, oprec)
/* Ignore leading zeros */
if ((prec == 0) && (decflg == 0) && (k == 0))
goto donchr;
- /* Identify and strip trailing zeros after the decimal point. */
+ /* Identify and strip trailing zeros after the decimal point. */
if ((trail == 0) && (decflg != 0))
{
sp = s;
@@ -4885,7 +5193,15 @@ asctoeg (ss, y, oprec)
/* Exponent interpretation */
expnt:
+ /* 0.0eXXX is zero, regardless of XXX. Check for the 0.0. */
+ for (k = 0; k < NI; k++)
+ {
+ if (yy[k] != 0)
+ goto read_expnt;
+ }
+ goto aexit;
+read_expnt:
esign = 1;
exp = 0;
++s;
@@ -4927,7 +5243,7 @@ asctoeg (ss, y, oprec)
daldone:
nexp = exp - nexp;
- /* Pad trailing zeros to minimize power of 10, per IEEE spec. */
+ /* Pad trailing zeros to minimize power of 10, per IEEE spec. */
while ((nexp > 0) && (yy[2] == 0))
{
emovz (yy, xt);
@@ -4969,7 +5285,7 @@ asctoeg (ss, y, oprec)
esign = -1;
if (nexp > 4096)
{
- /* Punt. Can't handle this without 2 divides. */
+ /* Punt. Can't handle this without 2 divides. */
emovi (etens[0], tt);
lexp -= tt[E];
k = edivm (tt, yy);
@@ -5008,13 +5324,18 @@ asctoeg (ss, y, oprec)
/* Round and convert directly to the destination type */
if (oprec == 53)
lexp -= EXONE - 0x3ff;
+#ifdef C4X
+ else if (oprec == 24 || oprec == 32)
+ lexp -= (EXONE - 0x7f);
+#else
#ifdef IBM
else if (oprec == 24 || oprec == 56)
lexp -= EXONE - (0x41 << 2);
#else
else if (oprec == 24)
lexp -= EXONE - 0177;
-#endif
+#endif /* IBM */
+#endif /* C4X */
#ifdef DEC
else if (oprec == 56)
lexp -= EXONE - 0201;
@@ -5038,6 +5359,12 @@ asctoeg (ss, y, oprec)
toibm (yy, y, DFmode);
break;
#endif
+#ifdef C4X
+ case 32:
+ toc4x (yy, y, HFmode);
+ break;
+#endif
+
case 53:
toe53 (yy, y);
break;
@@ -5129,6 +5456,7 @@ efloor (x, y)
}
+#if 0
/* Return S and EXP such that S * 2^EXP = X and .5 <= S < 1.
For example, 1.1 = 0.55 * 2^1. */
@@ -5153,6 +5481,7 @@ efrexp (x, exp, s)
emovo (xi, s);
*exp = (int) (li - 0x3ffe);
}
+#endif
/* Return e type Y = X * 2^PWR2. */
@@ -5175,6 +5504,7 @@ eldexp (x, pwr2, y)
}
+#if 0
/* C = remainder after dividing B by A, all e type values.
Least significant integer quotient bits left in EQUOT. */
@@ -5210,6 +5540,7 @@ eremain (a, b, c)
num[0] = 0xffff;
emovo (num, c);
}
+#endif
/* Return quotient of exploded e-types NUM / DEN in EQUOT,
remainder in NUM. */
@@ -5525,11 +5856,259 @@ toibm (x, y, mode)
}
#endif /* IBM */
+
+#ifdef C4X
+/* Convert C4X single/double precision to e type. */
+
+static void
+c4xtoe (d, e, mode)
+ unsigned EMUSHORT *d;
+ unsigned EMUSHORT *e;
+ enum machine_mode mode;
+{
+ unsigned EMUSHORT y[NI];
+ int r;
+ int rndsav;
+ int isnegative;
+ int size;
+ int i;
+ int carry;
+
+ /* Short-circuit the zero case. */
+ if ((d[0] == 0x8000)
+ && (d[1] == 0x0000)
+ && ((mode == QFmode) || ((d[2] == 0x0000) && (d[3] == 0x0000))))
+ {
+ e[0] = 0;
+ e[1] = 0;
+ e[2] = 0;
+ e[3] = 0;
+ e[4] = 0;
+ e[5] = 0;
+ return;
+ }
+
+ ecleaz (y); /* start with a zero */
+ r = d[0]; /* get sign/exponent part */
+ if (r & (unsigned int) 0x0080)
+ {
+ y[0] = 0xffff; /* fill in our sign */
+ isnegative = TRUE;
+ }
+ else
+ {
+ isnegative = FALSE;
+ }
+
+ r >>= 8; /* Shift exponent word down 8 bits. */
+ if (r & 0x80) /* Make the exponent negative if it is. */
+ {
+ r = r | (~0 & ~0xff);
+ }
+
+ if (isnegative)
+ {
+ /* Now do the high order mantissa. We don't "or" on the high bit
+ because it is 2 (not 1) and is handled a little differently
+ below. */
+ y[M] = d[0] & 0x7f;
+
+ y[M+1] = d[1];
+ if (mode != QFmode) /* There are only 2 words in QFmode. */
+ {
+ y[M+2] = d[2]; /* Fill in the rest of our mantissa. */
+ y[M+3] = d[3];
+ size = 4;
+ }
+ else
+ {
+ size = 2;
+ }
+ eshift(y, -8);
+
+ /* Now do the two's complement on the data. */
+
+ carry = 1; /* Initially add 1 for the two's complement. */
+ for (i=size + M; i > M; i--)
+ {
+ if (carry && (y[i] == 0x0000))
+ {
+ /* We overflowed into the next word, carry is the same. */
+ y[i] = carry ? 0x0000 : 0xffff;
+ }
+ else
+ {
+ /* No overflow, just invert and add carry. */
+ y[i] = ((~y[i]) + carry) & 0xffff;
+ carry = 0;
+ }
+ }
+
+ if (carry)
+ {
+ eshift(y, -1);
+ y[M+1] |= 0x8000;
+ r++;
+ }
+ y[1] = r + EXONE;
+ }
+ else
+ {
+ /* Add our e type exponent offset to form our exponent. */
+ r += EXONE;
+ y[1] = r;
+
+ /* Now do the high order mantissa strip off the exponent and sign
+ bits and add the high 1 bit. */
+ y[M] = d[0] & 0x7f | 0x80;
+
+ y[M+1] = d[1];
+ if (mode != QFmode) /* There are only 2 words in QFmode. */
+ {
+ y[M+2] = d[2]; /* Fill in the rest of our mantissa. */
+ y[M+3] = d[3];
+ }
+ eshift(y, -8);
+ }
+
+ emovo (y, e);
+}
+
+
+/* Convert e type to C4X single/double precision. */
+
+static void
+etoc4x (x, d, mode)
+ unsigned EMUSHORT *x, *d;
+ enum machine_mode mode;
+{
+ unsigned EMUSHORT xi[NI];
+ EMULONG exp;
+ int rndsav;
+
+ emovi (x, xi);
+
+ /* Adjust exponent for offsets. */
+ exp = (EMULONG) xi[E] - (EXONE - 0x7f);
+
+ /* Round off to nearest or even. */
+ rndsav = rndprc;
+ rndprc = mode == QFmode ? 24 : 32;
+ emdnorm (xi, 0, 0, exp, 64);
+ rndprc = rndsav;
+ toc4x (xi, d, mode);
+}
+
+static void
+toc4x (x, y, mode)
+ unsigned EMUSHORT *x, *y;
+ enum machine_mode mode;
+{
+ int i;
+ int r;
+ int v;
+ int carry;
+
+ /* Short-circuit the zero case */
+ if ((x[0] == 0) /* Zero exponent and sign */
+ && (x[1] == 0)
+ && (x[M] == 0) /* The rest is for zero mantissa */
+ && (x[M+1] == 0)
+ /* Only check for double if necessary */
+ && ((mode == QFmode) || ((x[M+2] == 0) && (x[M+3] == 0))))
+ {
+ /* We have a zero. Put it into the output and return. */
+ *y++ = 0x8000;
+ *y++ = 0x0000;
+ if (mode != QFmode)
+ {
+ *y++ = 0x0000;
+ *y++ = 0x0000;
+ }
+ return;
+ }
+
+ *y = 0;
+
+ /* Negative number require a two's complement conversion of the
+ mantissa. */
+ if (x[0])
+ {
+ *y = 0x0080;
+
+ i = ((int) x[1]) - 0x7f;
+
+ /* Now add 1 to the inverted data to do the two's complement. */
+ if (mode != QFmode)
+ v = 4 + M;
+ else
+ v = 2 + M;
+ carry = 1;
+ while (v > M)
+ {
+ if (x[v] == 0x0000)
+ {
+ x[v] = carry ? 0x0000 : 0xffff;
+ }
+ else
+ {
+ x[v] = ((~x[v]) + carry) & 0xffff;
+ carry = 0;
+ }
+ v--;
+ }
+
+ /* The following is a special case. The C4X negative float requires
+ a zero in the high bit (because the format is (2 - x) x 2^m), so
+ if a one is in that bit, we have to shift left one to get rid
+ of it. This only occurs if the number is -1 x 2^m. */
+ if (x[M+1] & 0x8000)
+ {
+ /* This is the case of -1 x 2^m, we have to rid ourselves of the
+ high sign bit and shift the exponent. */
+ eshift(x, 1);
+ i--;
+ }
+ }
+ else
+ {
+ i = ((int) x[1]) - 0x7f;
+ }
+
+ if ((i < -128) || (i > 127))
+ {
+ y[0] |= 0xff7f;
+ y[1] = 0xffff;
+ if (mode != QFmode)
+ {
+ y[2] = 0xffff;
+ y[3] = 0xffff;
+ }
+#ifdef ERANGE
+ errno = ERANGE;
+#endif
+ return;
+ }
+
+ y[0] |= ((i & 0xff) << 8);
+
+ eshift (x, 8);
+
+ y[0] |= x[M] & 0x7f;
+ y[1] = x[M + 1];
+ if (mode != QFmode)
+ {
+ y[2] = x[M + 2];
+ y[3] = x[M + 3];
+ }
+}
+#endif /* C4X */
+
/* Output a binary NaN bit pattern in the target machine's format. */
/* If special NaN bit patterns are required, define them in tm.h
as arrays of unsigned 16-bit shorts. Otherwise, use the default
- patterns here. */
+ patterns here. */
#ifdef TFMODE_NAN
TFMODE_NAN;
#else
@@ -5581,8 +6160,8 @@ make_nan (nan, sign, mode)
switch (mode)
{
/* Possibly the `reserved operand' patterns on a VAX can be
- used like NaN's, but probably not in the same way as IEEE. */
-#if !defined(DEC) && !defined(IBM)
+ used like NaN's, but probably not in the same way as IEEE. */
+#if !defined(DEC) && !defined(IBM) && !defined(C4X)
case TFmode:
n = 8;
if (REAL_WORDS_BIG_ENDIAN)
@@ -5590,6 +6169,7 @@ make_nan (nan, sign, mode)
else
p = TFlittlenan;
break;
+
case XFmode:
n = 6;
if (REAL_WORDS_BIG_ENDIAN)
@@ -5597,6 +6177,7 @@ make_nan (nan, sign, mode)
else
p = XFlittlenan;
break;
+
case DFmode:
n = 4;
if (REAL_WORDS_BIG_ENDIAN)
@@ -5604,8 +6185,9 @@ make_nan (nan, sign, mode)
else
p = DFlittlenan;
break;
- case HFmode:
+
case SFmode:
+ case HFmode:
n = 2;
if (REAL_WORDS_BIG_ENDIAN)
p = SFbignan;
@@ -5613,6 +6195,7 @@ make_nan (nan, sign, mode)
p = SFlittlenan;
break;
#endif
+
default:
abort ();
}
@@ -5624,13 +6207,12 @@ make_nan (nan, sign, mode)
*nan = (sign << 15) | *p;
}
-/* Convert an SFmode target `float' value to a REAL_VALUE_TYPE.
- This is the inverse of the function `etarsingle' invoked by
+/* This is the inverse of the function `etarsingle' invoked by
REAL_VALUE_TO_TARGET_SINGLE. */
REAL_VALUE_TYPE
-ereal_from_float (f)
- HOST_WIDE_INT f;
+ereal_unto_float (f)
+ long f;
{
REAL_VALUE_TYPE r;
unsigned EMUSHORT s[2];
@@ -5656,9 +6238,76 @@ ereal_from_float (f)
}
+/* This is the inverse of the function `etardouble' invoked by
+ REAL_VALUE_TO_TARGET_DOUBLE. */
+
+REAL_VALUE_TYPE
+ereal_unto_double (d)
+ long d[];
+{
+ REAL_VALUE_TYPE r;
+ unsigned EMUSHORT s[4];
+ unsigned EMUSHORT e[NE];
+
+ /* Convert array of HOST_WIDE_INT to equivalent array of 16-bit pieces. */
+ if (REAL_WORDS_BIG_ENDIAN)
+ {
+ s[0] = (unsigned EMUSHORT) (d[0] >> 16);
+ s[1] = (unsigned EMUSHORT) d[0];
+ s[2] = (unsigned EMUSHORT) (d[1] >> 16);
+ s[3] = (unsigned EMUSHORT) d[1];
+ }
+ else
+ {
+ /* Target float words are little-endian. */
+ s[0] = (unsigned EMUSHORT) d[0];
+ s[1] = (unsigned EMUSHORT) (d[0] >> 16);
+ s[2] = (unsigned EMUSHORT) d[1];
+ s[3] = (unsigned EMUSHORT) (d[1] >> 16);
+ }
+ /* Convert target double to E-type. */
+ e53toe (s, e);
+ /* Output E-type to REAL_VALUE_TYPE. */
+ PUT_REAL (e, &r);
+ return r;
+}
+
+
+/* Convert an SFmode target `float' value to a REAL_VALUE_TYPE.
+ This is somewhat like ereal_unto_float, but the input types
+ for these are different. */
+
+REAL_VALUE_TYPE
+ereal_from_float (f)
+ HOST_WIDE_INT f;
+{
+ REAL_VALUE_TYPE r;
+ unsigned EMUSHORT s[2];
+ unsigned EMUSHORT e[NE];
+
+ /* Convert 32 bit integer to array of 16 bit pieces in target machine order.
+ This is the inverse operation to what the function `endian' does. */
+ if (REAL_WORDS_BIG_ENDIAN)
+ {
+ s[0] = (unsigned EMUSHORT) (f >> 16);
+ s[1] = (unsigned EMUSHORT) f;
+ }
+ else
+ {
+ s[0] = (unsigned EMUSHORT) f;
+ s[1] = (unsigned EMUSHORT) (f >> 16);
+ }
+ /* Convert and promote the target float to E-type. */
+ e24toe (s, e);
+ /* Output E-type to REAL_VALUE_TYPE. */
+ PUT_REAL (e, &r);
+ return r;
+}
+
+
/* Convert a DFmode target `double' value to a REAL_VALUE_TYPE.
- This is the inverse of the function `etardouble' invoked by
- REAL_VALUE_TO_TARGET_DOUBLE.
+ This is somewhat like ereal_unto_double, but the input types
+ for these are different.
The DFmode is stored as an array of HOST_WIDE_INT in the target's
data format, with no holes in the bit packing. The first element
@@ -5702,21 +6351,22 @@ ereal_from_double (d)
s[3] = (unsigned EMUSHORT) (d[0] >> 48);
#endif
}
- /* Convert target double to E-type. */
+ /* Convert target double to E-type. */
e53toe (s, e);
- /* Output E-type to REAL_VALUE_TYPE. */
+ /* Output E-type to REAL_VALUE_TYPE. */
PUT_REAL (e, &r);
return r;
}
+#if 0
/* Convert target computer unsigned 64-bit integer to e-type.
The endian-ness of DImode follows the convention for integers,
so we use WORDS_BIG_ENDIAN here, not REAL_WORDS_BIG_ENDIAN. */
static void
uditoe (di, e)
- unsigned EMUSHORT *di; /* Address of the 64-bit int. */
+ unsigned EMUSHORT *di; /* Address of the 64-bit int. */
unsigned EMUSHORT *e;
{
unsigned EMUSHORT yi[NI];
@@ -5741,11 +6391,11 @@ uditoe (di, e)
emovo (yi, e);
}
-/* Convert target computer signed 64-bit integer to e-type. */
+/* Convert target computer signed 64-bit integer to e-type. */
static void
ditoe (di, e)
- unsigned EMUSHORT *di; /* Address of the 64-bit int. */
+ unsigned EMUSHORT *di; /* Address of the 64-bit int. */
unsigned EMUSHORT *e;
{
unsigned EMULONG acc;
@@ -5790,7 +6440,7 @@ ditoe (di, e)
}
-/* Convert e-type to unsigned 64-bit int. */
+/* Convert e-type to unsigned 64-bit int. */
static void
etoudi (x, i)
@@ -5873,7 +6523,7 @@ noshift:
}
-/* Convert e-type to signed 64-bit int. */
+/* Convert e-type to signed 64-bit int. */
static void
etodi (x, i)
@@ -5971,7 +6621,7 @@ etodi (x, i)
}
-/* Longhand square root routine. */
+/* Longhand square root routine. */
static int esqinited = 0;
@@ -6013,7 +6663,7 @@ esqrt (x, y)
return;
}
#endif
- /* Bring in the arg and renormalize if it is denormal. */
+ /* Bring in the arg and renormalize if it is denormal. */
emovi (x, xx);
m = (EMULONG) xx[1]; /* local long word exponent */
if (m == 0)
@@ -6042,7 +6692,7 @@ esqrt (x, y)
/* bring in next word of arg */
if (j < NE)
num[NI - 1] = xx[j + 3];
- /* Do additional bit on last outer loop, for roundoff. */
+ /* Do additional bit on last outer loop, for roundoff. */
if (nlups <= 8)
n = nlups + 1;
for (i = 0; i < n; i++)
@@ -6068,18 +6718,19 @@ esqrt (x, y)
j += 1;
}
- /* Adjust for extra, roundoff loop done. */
+ /* Adjust for extra, roundoff loop done. */
exp += (NBITS - 1) - rndprc;
- /* Sticky bit = 1 if the remainder is nonzero. */
+ /* Sticky bit = 1 if the remainder is nonzero. */
k = 0;
for (i = 3; i < NI; i++)
k |= (int) num[i];
- /* Renormalize and round off. */
+ /* Renormalize and round off. */
emdnorm (sq, k, 0, exp, 64);
emovo (sq, y);
}
+#endif
#endif /* EMU_NON_COMPILE not defined */
/* Return the binary precision of the significand for a given
@@ -6091,12 +6742,20 @@ significand_size (mode)
enum machine_mode mode;
{
-switch (mode)
+/* Don't test the modes, but their sizes, lest this
+ code won't work for BITS_PER_UNIT != 8 . */
+
+switch (GET_MODE_BITSIZE (mode))
{
- case SFmode:
+ case 32:
+
+#if TARGET_FLOAT_FORMAT == C4X_FLOAT_FORMAT
+ return 56;
+#endif
+
return 24;
- case DFmode:
+ case 64:
#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
return 53;
#else
@@ -6106,14 +6765,18 @@ switch (mode)
#if TARGET_FLOAT_FORMAT == VAX_FLOAT_FORMAT
return 56;
#else
+#if TARGET_FLOAT_FORMAT == C4X_FLOAT_FORMAT
+ return 56;
+#else
abort ();
#endif
#endif
#endif
+#endif
- case XFmode:
+ case 96:
return 64;
- case TFmode:
+ case 128:
return 113;
default:
diff --git a/contrib/gcc/real.h b/contrib/gcc/real.h
index 799e158..0719c26 100644
--- a/contrib/gcc/real.h
+++ b/contrib/gcc/real.h
@@ -1,5 +1,5 @@
-/* Front-end tree definitions for GNU compiler.
- Copyright (C) 1989, 1991, 1994 Free Software Foundation, Inc.
+/* Definitions of floating-point access for GNU compiler.
+ Copyright (C) 1989, 1991, 1994, 1996, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -26,6 +26,7 @@ Boston, MA 02111-1307, USA. */
#define IEEE_FLOAT_FORMAT 1
#define VAX_FLOAT_FORMAT 2
#define IBM_FLOAT_FORMAT 3
+#define C4X_FLOAT_FORMAT 4
/* Default to IEEE float if not specified. Nearly all machines use it. */
@@ -136,10 +137,12 @@ extern REAL_VALUE_TYPE ereal_negate PROTO((REAL_VALUE_TYPE));
extern HOST_WIDE_INT efixi PROTO((REAL_VALUE_TYPE));
extern unsigned HOST_WIDE_INT efixui PROTO((REAL_VALUE_TYPE));
extern void ereal_from_int PROTO((REAL_VALUE_TYPE *,
- HOST_WIDE_INT, HOST_WIDE_INT));
+ HOST_WIDE_INT, HOST_WIDE_INT,
+ enum machine_mode));
extern void ereal_from_uint PROTO((REAL_VALUE_TYPE *,
unsigned HOST_WIDE_INT,
- unsigned HOST_WIDE_INT));
+ unsigned HOST_WIDE_INT,
+ enum machine_mode));
extern void ereal_to_int PROTO((HOST_WIDE_INT *, HOST_WIDE_INT *,
REAL_VALUE_TYPE));
extern REAL_VALUE_TYPE ereal_ldexp PROTO((REAL_VALUE_TYPE, int));
@@ -151,6 +154,8 @@ extern long etarsingle PROTO((REAL_VALUE_TYPE));
extern void ereal_to_decimal PROTO((REAL_VALUE_TYPE, char *));
extern int ereal_cmp PROTO((REAL_VALUE_TYPE, REAL_VALUE_TYPE));
extern int ereal_isneg PROTO((REAL_VALUE_TYPE));
+extern REAL_VALUE_TYPE ereal_unto_float PROTO((long));
+extern REAL_VALUE_TYPE ereal_unto_double PROTO((long *));
extern REAL_VALUE_TYPE ereal_from_float PROTO((HOST_WIDE_INT));
extern REAL_VALUE_TYPE ereal_from_double PROTO((HOST_WIDE_INT *));
@@ -162,7 +167,8 @@ extern REAL_VALUE_TYPE ereal_from_double PROTO((HOST_WIDE_INT *));
/* These return REAL_VALUE_TYPE: */
#define REAL_VALUE_RNDZINT(x) (etrunci (x))
#define REAL_VALUE_UNSIGNED_RNDZINT(x) (etruncui (x))
-extern REAL_VALUE_TYPE real_value_truncate ();
+extern REAL_VALUE_TYPE real_value_truncate PROTO ((enum machine_mode,
+ REAL_VALUE_TYPE));
#define REAL_VALUE_TRUNCATE(mode, x) real_value_truncate (mode, x)
/* These return HOST_WIDE_INT: */
@@ -181,10 +187,11 @@ extern REAL_VALUE_TYPE real_value_truncate ();
#define REAL_VALUE_TO_INT ereal_to_int
/* Here the cast to HOST_WIDE_INT sign-extends arguments such as ~0. */
-#define REAL_VALUE_FROM_INT(d, lo, hi) \
- ereal_from_int (&d, (HOST_WIDE_INT) (lo), (HOST_WIDE_INT) (hi))
+#define REAL_VALUE_FROM_INT(d, lo, hi, mode) \
+ ereal_from_int (&d, (HOST_WIDE_INT) (lo), (HOST_WIDE_INT) (hi), mode)
-#define REAL_VALUE_FROM_UNSIGNED_INT(d, lo, hi) (ereal_from_uint (&d, lo, hi))
+#define REAL_VALUE_FROM_UNSIGNED_INT(d, lo, hi, mode) \
+ ereal_from_uint (&d, lo, hi, mode)
/* IN is a REAL_VALUE_TYPE. OUT is an array of longs. */
#if LONG_DOUBLE_TYPE_SIZE == 96
@@ -197,6 +204,12 @@ extern REAL_VALUE_TYPE real_value_truncate ();
/* IN is a REAL_VALUE_TYPE. OUT is a long. */
#define REAL_VALUE_TO_TARGET_SINGLE(IN, OUT) ((OUT) = etarsingle ((IN)))
+/* Inverse of REAL_VALUE_TO_TARGET_DOUBLE. */
+#define REAL_VALUE_UNTO_TARGET_DOUBLE(d) (ereal_unto_double (d))
+
+/* Inverse of REAL_VALUE_TO_TARGET_SINGLE. */
+#define REAL_VALUE_UNTO_TARGET_SINGLE(f) (ereal_unto_float (f))
+
/* d is an array of HOST_WIDE_INT that holds a double precision
value in the target computer's floating point format. */
#define REAL_VALUE_FROM_TARGET_DOUBLE(d) (ereal_from_double (d))
@@ -251,10 +264,18 @@ typedef struct {
value in host format and then to a single type `long' value which
is the bitwise equivalent of the `float' value. */
#ifndef REAL_VALUE_TO_TARGET_SINGLE
-#define REAL_VALUE_TO_TARGET_SINGLE(IN, OUT) \
-do { float f = (float) (IN); \
- (OUT) = *(long *) &f; \
- } while (0)
+#define REAL_VALUE_TO_TARGET_SINGLE(IN, OUT) \
+do { \
+ union { \
+ float f; \
+ HOST_WIDE_INT l; \
+ } u; \
+ if (sizeof(HOST_WIDE_INT) < sizeof(float)) \
+ abort(); \
+ u.l = 0; \
+ u.f = (IN); \
+ (OUT) = u.l; \
+} while (0)
#endif
/* Convert a type `double' value in host format to a pair of type `long'
@@ -262,18 +283,20 @@ do { float f = (float) (IN); \
proper word order for the target. */
#ifndef REAL_VALUE_TO_TARGET_DOUBLE
#define REAL_VALUE_TO_TARGET_DOUBLE(IN, OUT) \
-do { REAL_VALUE_TYPE in = (IN); /* Make sure it's not in a register. */\
- if (HOST_FLOAT_WORDS_BIG_ENDIAN == FLOAT_WORDS_BIG_ENDIAN) \
- { \
- (OUT)[0] = ((long *) &in)[0]; \
- (OUT)[1] = ((long *) &in)[1]; \
- } \
- else \
- { \
- (OUT)[1] = ((long *) &in)[0]; \
- (OUT)[0] = ((long *) &in)[1]; \
- } \
- } while (0)
+do { \
+ union { \
+ REAL_VALUE_TYPE f; \
+ HOST_WIDE_INT l[2]; \
+ } u; \
+ if (sizeof(HOST_WIDE_INT) * 2 < sizeof(REAL_VALUE_TYPE)) \
+ abort(); \
+ u.l[0] = u.l[1] = 0; \
+ u.f = (IN); \
+ if (HOST_FLOAT_WORDS_BIG_ENDIAN == FLOAT_WORDS_BIG_ENDIAN) \
+ (OUT)[0] = u.l[0], (OUT)[1] = u.l[1]; \
+ else \
+ (OUT)[1] = u.l[0], (OUT)[0] = u.l[1]; \
+} while (0)
#endif
#endif /* HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT */
@@ -282,6 +305,13 @@ do { REAL_VALUE_TYPE in = (IN); /* Make sure it's not in a register. */\
#define REAL_VALUE_TO_TARGET_LONG_DOUBLE(a, b) REAL_VALUE_TO_TARGET_DOUBLE (a, b)
#endif
+/* Compare two floating-point objects for bitwise identity.
+ This is not the same as comparing for equality on IEEE hosts:
+ -0.0 equals 0.0 but they are not identical, and conversely
+ two NaNs might be identical but they cannot be equal. */
+#define REAL_VALUES_IDENTICAL(x, y) \
+ (!bcmp ((char *) &(x), (char *) &(y), sizeof (REAL_VALUE_TYPE)))
+
/* Compare two floating-point values for equality. */
#ifndef REAL_VALUES_EQUAL
#define REAL_VALUES_EQUAL(x, y) ((x) == (y))
@@ -349,7 +379,7 @@ extern double (atof) ();
size and where `float' is SFmode. */
/* Don't use REAL_VALUE_TRUNCATE directly--always call real_value_truncate. */
-extern REAL_VALUE_TYPE real_value_truncate ();
+extern REAL_VALUE_TYPE real_value_truncate PROTO((enum machine_mode, REAL_VALUE_TYPE));
#ifndef REAL_VALUE_TRUNCATE
#define REAL_VALUE_TRUNCATE(mode, x) \
@@ -372,6 +402,10 @@ extern REAL_VALUE_TYPE real_value_truncate ();
#define REAL_VALUE_NEGATIVE(x) (target_negative (x))
#endif
+extern int target_isnan PROTO ((REAL_VALUE_TYPE));
+extern int target_isinf PROTO ((REAL_VALUE_TYPE));
+extern int target_negative PROTO ((REAL_VALUE_TYPE));
+
/* Determine whether a floating-point value X is minus 0. */
#ifndef REAL_VALUE_MINUS_ZERO
#define REAL_VALUE_MINUS_ZERO(x) ((x) == 0 && REAL_VALUE_NEGATIVE (x))
@@ -410,11 +444,12 @@ union real_extract
or cc0_rtx if it is not on the chain. */
#define CONST_DOUBLE_MEM(r) XEXP (r, 0)
+/* Given a CONST_DOUBLE in FROM, store into TO the value it represents. */
/* Function to return a real value (not a tree node)
from a given integer constant. */
-REAL_VALUE_TYPE real_value_from_int_cst ();
-
-/* Given a CONST_DOUBLE in FROM, store into TO the value it represents. */
+union tree_node;
+REAL_VALUE_TYPE real_value_from_int_cst PROTO ((union tree_node *,
+ union tree_node *));
#define REAL_VALUE_FROM_CONST_DOUBLE(to, from) \
do { union real_extract u; \
@@ -435,4 +470,12 @@ extern struct rtx_def *immed_real_const_1 PROTO((REAL_VALUE_TYPE,
#define REAL_VALUE_TO_DECIMAL(r, fmt, s) (sprintf (s, fmt, r))
#endif
+/* Replace R by 1/R in the given machine mode, if the result is exact. */
+extern int exact_real_inverse PROTO((enum machine_mode, REAL_VALUE_TYPE *));
+
+extern void debug_real PROTO ((REAL_VALUE_TYPE));
+
+/* In varasm.c */
+extern void assemble_real PROTO ((REAL_VALUE_TYPE,
+ enum machine_mode));
#endif /* Not REAL_H_INCLUDED */
diff --git a/contrib/gcc/recog.c b/contrib/gcc/recog.c
index 745d628..ded35f7 100644
--- a/contrib/gcc/recog.c
+++ b/contrib/gcc/recog.c
@@ -1,5 +1,5 @@
/* Subroutines used by or related to instruction recognition.
- Copyright (C) 1987, 88, 91, 92, 93, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 91-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,8 +20,8 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
-#include <stdio.h>
#include "insn-config.h"
#include "insn-attr.h"
#include "insn-flags.h"
@@ -43,8 +43,9 @@ Boston, MA 02111-1307, USA. */
/* Import from final.c: */
extern rtx alter_subreg ();
-int strict_memory_address_p ();
-int memory_address_p ();
+static void validate_replace_rtx_1 PROTO((rtx *, rtx, rtx, rtx));
+static rtx *find_single_use_1 PROTO((rtx, rtx *));
+static rtx *find_constant_term_loc PROTO((rtx *));
/* Nonzero means allow operands to be volatile.
This should be 0 if you are generating rtl, such as if you are calling
@@ -260,8 +261,8 @@ apply_change_group ()
{
int j;
- newpat = gen_rtx (PARALLEL, VOIDmode,
- gen_rtvec (XVECLEN (pat, 0) - 1));
+ newpat = gen_rtx_PARALLEL (VOIDmode,
+ gen_rtvec (XVECLEN (pat, 0) - 1));
for (j = 0; j < XVECLEN (newpat, 0); j++)
XVECEXP (newpat, 0, j) = XVECEXP (pat, 0, j);
}
@@ -365,24 +366,38 @@ validate_replace_rtx_1 (loc, from, to, object)
if (prev_changes != num_changes && CONSTANT_P (XEXP (x, 0)))
{
validate_change (object, loc,
- gen_rtx (GET_RTX_CLASS (code) == 'c' ? code
- : swap_condition (code),
- GET_MODE (x), XEXP (x, 1), XEXP (x, 0)),
+ gen_rtx_fmt_ee (GET_RTX_CLASS (code) == 'c' ? code
+ : swap_condition (code),
+ GET_MODE (x), XEXP (x, 1),
+ XEXP (x, 0)),
1);
x = *loc;
code = GET_CODE (x);
}
}
+ /* Note that if CODE's RTX_CLASS is "c" or "<" we will have already
+ done the substitution, otherwise we won't. */
+
switch (code)
{
case PLUS:
- /* If we have have a PLUS whose second operand is now a CONST_INT, use
+ /* If we have a PLUS whose second operand is now a CONST_INT, use
plus_constant to try to simplify it. */
if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
- validate_change (object, loc,
- plus_constant (XEXP (x, 0), INTVAL (XEXP (x, 1))), 1);
+ validate_change (object, loc, plus_constant (XEXP (x, 0), INTVAL (to)),
+ 1);
return;
+
+ case MINUS:
+ if (GET_CODE (to) == CONST_INT && XEXP (x, 1) == from)
+ {
+ validate_change (object, loc,
+ plus_constant (XEXP (x, 0), - INTVAL (to)),
+ 1);
+ return;
+ }
+ break;
case ZERO_EXTEND:
case SIGN_EXTEND:
@@ -400,7 +415,7 @@ validate_replace_rtx_1 (loc, from, to, object)
rtx new = simplify_unary_operation (code, GET_MODE (x), to,
GET_MODE (from));
if (new == 0)
- new = gen_rtx (CLOBBER, GET_MODE (x), const0_rtx);
+ new = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx);
validate_change (object, loc, new, 1);
return;
@@ -429,7 +444,7 @@ validate_replace_rtx_1 (loc, from, to, object)
GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
- MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
- new = gen_rtx (MEM, mode, plus_constant (XEXP (to, 0), offset));
+ new = gen_rtx_MEM (mode, plus_constant (XEXP (to, 0), offset));
MEM_VOLATILE_P (new) = MEM_VOLATILE_P (to);
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (to);
MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (to);
@@ -453,7 +468,6 @@ validate_replace_rtx_1 (loc, from, to, object)
{
enum machine_mode wanted_mode = VOIDmode;
enum machine_mode is_mode = GET_MODE (to);
- int width = INTVAL (XEXP (x, 1));
int pos = INTVAL (XEXP (x, 2));
#ifdef HAVE_extzv
@@ -480,8 +494,8 @@ validate_replace_rtx_1 (loc, from, to, object)
pos %= GET_MODE_BITSIZE (wanted_mode);
- newmem = gen_rtx (MEM, wanted_mode,
- plus_constant (XEXP (to, 0), offset));
+ newmem = gen_rtx_MEM (wanted_mode,
+ plus_constant (XEXP (to, 0), offset));
RTX_UNCHANGING_P (newmem) = RTX_UNCHANGING_P (to);
MEM_VOLATILE_P (newmem) = MEM_VOLATILE_P (to);
MEM_IN_STRUCT_P (newmem) = MEM_IN_STRUCT_P (to);
@@ -492,16 +506,24 @@ validate_replace_rtx_1 (loc, from, to, object)
}
break;
+
+ default:
+ break;
}
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ /* For commutative or comparison operations we've already performed
+ replacements. Don't try to perform them again. */
+ if (GET_RTX_CLASS (code) != '<' && GET_RTX_CLASS (code) != 'c')
{
- if (fmt[i] == 'e')
- validate_replace_rtx_1 (&XEXP (x, i), from, to, object);
- else if (fmt[i] == 'E')
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object);
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ validate_replace_rtx_1 (&XEXP (x, i), from, to, object);
+ else if (fmt[i] == 'E')
+ for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ validate_replace_rtx_1 (&XVECEXP (x, i, j), from, to, object);
+ }
}
}
@@ -515,6 +537,25 @@ validate_replace_rtx (from, to, insn)
validate_replace_rtx_1 (&PATTERN (insn), from, to, insn);
return apply_change_group ();
}
+
+/* Try replacing every occurrence of FROM in INSN with TO, avoiding
+ SET_DESTs. After all changes have been made, validate by seeing if
+ INSN is still valid. */
+
+int
+validate_replace_src (from, to, insn)
+ rtx from, to, insn;
+{
+ if ((GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
+ || GET_CODE (PATTERN (insn)) != SET)
+ abort ();
+
+ validate_replace_rtx_1 (&SET_SRC (PATTERN (insn)), from, to, insn);
+ if (GET_CODE (SET_DEST (PATTERN (insn))) == MEM)
+ validate_replace_rtx_1 (&XEXP (SET_DEST (PATTERN (insn)), 0),
+ from, to, insn);
+ return apply_change_group ();
+}
#ifdef HAVE_cc0
/* Return 1 if the insn using CC0 set by INSN does not contain
@@ -614,6 +655,9 @@ find_single_use_1 (dest, loc)
case MEM:
case SUBREG:
return find_single_use_1 (dest, &XEXP (x, 0));
+
+ default:
+ break;
}
/* If it wasn't one of the common cases above, check each expression and
@@ -806,10 +850,18 @@ general_operand (op, mode)
register rtx y = XEXP (op, 0);
if (! volatile_ok && MEM_VOLATILE_P (op))
return 0;
+ if (GET_CODE (y) == ADDRESSOF)
+ return 1;
/* Use the mem's mode, since it will be reloaded thus. */
mode = GET_MODE (op);
GO_IF_LEGITIMATE_ADDRESS (mode, y, win);
}
+
+ /* Pretend this is an operand for now; we'll run force_operand
+ on its replacement in fixup_var_refs_1. */
+ if (code == ADDRESSOF)
+ return 1;
+
return 0;
win:
@@ -871,7 +923,9 @@ register_operand (op, mode)
&& TEST_HARD_REG_BIT (reg_class_contents[(int) CLASS_CANNOT_CHANGE_SIZE],
REGNO (SUBREG_REG (op)))
&& (GET_MODE_SIZE (mode)
- != GET_MODE_SIZE (GET_MODE (SUBREG_REG (op)))))
+ != GET_MODE_SIZE (GET_MODE (SUBREG_REG (op))))
+ && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_INT
+ && GET_MODE_CLASS (GET_MODE (SUBREG_REG (op))) != MODE_COMPLEX_FLOAT)
return 0;
#endif
@@ -1043,6 +1097,9 @@ memory_address_p (mode, addr)
enum machine_mode mode;
register rtx addr;
{
+ if (GET_CODE (addr) == ADDRESSOF)
+ return 1;
+
GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
return 0;
@@ -1545,7 +1602,7 @@ adj_offsettable_operand (op, offset)
if (CONSTANT_ADDRESS_P (y))
{
- new = gen_rtx (MEM, GET_MODE (op), plus_constant_for_output (y, offset));
+ new = gen_rtx_MEM (GET_MODE (op), plus_constant_for_output (y, offset));
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (op);
return new;
}
@@ -1565,7 +1622,7 @@ adj_offsettable_operand (op, offset)
}
}
- new = gen_rtx (MEM, GET_MODE (op), plus_constant_for_output (y, offset));
+ new = gen_rtx_MEM (GET_MODE (op), plus_constant_for_output (y, offset));
RTX_UNCHANGING_P (new) = RTX_UNCHANGING_P (op);
return new;
}
@@ -1650,6 +1707,11 @@ constrain_operands (insn_code_num, strict)
earlyclobber[opno] = 0;
+ /* A unary operator may be accepted by the predicate, but it
+ is irrelevant for matching constraints. */
+ if (GET_RTX_CLASS (GET_CODE (op)) == '1')
+ op = XEXP (op, 0);
+
if (GET_CODE (op) == SUBREG)
{
if (GET_CODE (SUBREG_REG (op)) == REG
@@ -1765,8 +1827,9 @@ constrain_operands (insn_code_num, strict)
break;
case 'X':
- /* This is used for a MATCH_SCRATCH in the cases when we
- don't actually need anything. So anything goes any time. */
+ /* This is used for a MATCH_SCRATCH in the cases when
+ we don't actually need anything. So anything goes
+ any time. */
win = 1;
break;
@@ -1862,7 +1925,12 @@ constrain_operands (insn_code_num, strict)
case 'V':
if (GET_CODE (op) == MEM
- && ! offsettable_memref_p (op))
+ && ((strict > 0 && ! offsettable_memref_p (op))
+ || (strict < 0
+ && !(CONSTANT_P (op) || GET_CODE (op) == MEM))
+ || (reload_in_progress
+ && !(GET_CODE (op) == REG
+ && REGNO (op) >= FIRST_PSEUDO_REGISTER))))
win = 1;
break;
@@ -1916,11 +1984,11 @@ constrain_operands (insn_code_num, strict)
if ((GET_CODE (recog_operand[opno]) == MEM
|| op_types[opno] != OP_OUT)
&& opno != eopno
- /* Ignore things like match_operator operands. */
- && *constraints[opno] != 0
+ /* Ignore things like match_operator operands. */
+ && *insn_operand_constraint[insn_code_num][opno] != 0
&& ! (matching_operands[opno] == eopno
- && rtx_equal_p (recog_operand[opno],
- recog_operand[eopno]))
+ && operands_match_p (recog_operand[opno],
+ recog_operand[eopno]))
&& ! safe_from_earlyclobber (recog_operand[opno],
recog_operand[eopno]))
lose = 1;
@@ -1949,7 +2017,7 @@ constrain_operands (insn_code_num, strict)
}
/* Return 1 iff OPERAND (assumed to be a REG rtx)
- is a hard reg in class CLASS when its regno is offsetted by OFFSET
+ is a hard reg in class CLASS when its regno is offset by OFFSET
and changed to mode MODE.
If REG occupies multiple hard regs, all of them must be in CLASS. */
diff --git a/contrib/gcc/recog.h b/contrib/gcc/recog.h
index fc0d5ff..6e6bb06 100644
--- a/contrib/gcc/recog.h
+++ b/contrib/gcc/recog.h
@@ -1,5 +1,5 @@
/* Declarations for interface to insn recognizer and insn-output.c.
- Copyright (C) 1987 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1996, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -18,46 +18,52 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* Add prototype support. */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
-/* Recognize an insn and return its insn-code,
- which is the sequence number of the DEFINE_INSN that it matches.
- If the insn does not match, return -1. */
-
-extern int recog_memoized PROTO((rtx));
-
-/* Determine whether a proposed change to an insn or MEM will make it
- invalid. Make the change if not. */
-
-extern int validate_change PROTO((rtx, rtx *, rtx, int));
-
-/* Apply a group of changes if valid. */
-
-extern int apply_change_group PROTO((void));
-
-/* Return the number of changes so far in the current group. */
-
-extern int num_validated_changes PROTO((void));
-
-/* Retract some changes. */
-
-extern void cancel_changes PROTO((int));
+#include "gansidecl.h"
+
+extern void init_recog PROTO((void));
+extern void init_recog_no_volatile PROTO((void));
+extern int recog_memoized PROTO((rtx));
+extern int check_asm_operands PROTO((rtx));
+extern int validate_change PROTO((rtx, rtx *, rtx, int));
+extern int apply_change_group PROTO((void));
+extern int num_validated_changes PROTO((void));
+extern void cancel_changes PROTO((int));
+extern int constrain_operands PROTO((int, int));
+extern int memory_address_p PROTO((enum machine_mode, rtx));
+extern int strict_memory_address_p PROTO((enum machine_mode, rtx));
+extern int validate_replace_rtx PROTO((rtx, rtx, rtx));
+extern int validate_replace_src PROTO((rtx, rtx, rtx));
+extern int reg_fits_class_p PROTO((rtx, enum reg_class, int,
+ enum machine_mode));
+extern rtx *find_single_use PROTO((rtx, rtx, rtx *));
+
+extern int general_operand PROTO((rtx, enum machine_mode));
+extern int address_operand PROTO((rtx, enum machine_mode));
+extern int register_operand PROTO((rtx, enum machine_mode));
+extern int scratch_operand PROTO((rtx, enum machine_mode));
+extern int immediate_operand PROTO((rtx, enum machine_mode));
+extern int const_int_operand PROTO((rtx, enum machine_mode));
+extern int cosnt_double_operand PROTO((rtx, enum machine_mode));
+extern int nonimmediate_operand PROTO((rtx, enum machine_mode));
+extern int nonmemory_operand PROTO((rtx, enum machine_mode));
+extern int push_operand PROTO((rtx, enum machine_mode));
+extern int memory_operand PROTO((rtx, enum machine_mode));
+extern int indirect_operand PROTO((rtx, enum machine_mode));
+extern int mode_independent_operand PROTO((rtx, enum machine_mode));
+extern int comparison_operator PROTO((rtx, enum machine_mode));
+
+extern int offsettable_memref_p PROTO((rtx));
+extern int offsettable_nonstrict_memref_p PROTO((rtx));
+extern int offsettable_address_p PROTO((int, enum machine_mode, rtx));
+extern int mode_dependent_address_p PROTO((rtx));
+
+extern int recog PROTO((rtx, rtx, int *));
+extern void add_clobbers PROTO((rtx, int));
+extern void insn_extract PROTO((rtx));
/* Nonzero means volatile operands are recognized. */
-
extern int volatile_ok;
-/* Extract the operands from an insn that has been recognized. */
-
-extern void insn_extract PROTO((rtx));
-
/* The following vectors hold the results from insn_extract. */
/* Indexed by N, gives value of operand N. */
@@ -74,12 +80,6 @@ extern rtx *recog_dup_loc[];
Nth duplicate-appearance of an operand. */
extern char recog_dup_num[];
-#ifndef __STDC__
-#ifndef const
-#define const
-#endif
-#endif
-
/* Access the output function for CODE. */
#define OUT_FCN(CODE) (*insn_outfun[(int) (CODE)])
diff --git a/contrib/gcc/reg-stack.c b/contrib/gcc/reg-stack.c
index c099c61..d92a1f9 100644
--- a/contrib/gcc/reg-stack.c
+++ b/contrib/gcc/reg-stack.c
@@ -1,5 +1,5 @@
/* Register to Stack convert for GNU compiler.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -157,14 +157,16 @@ Boston, MA 02111-1307, USA. */
*/
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "insn-config.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "flags.h"
+#include "insn-flags.h"
+#include "toplev.h"
#ifdef STACK_REGS
@@ -213,7 +215,7 @@ static HARD_REG_SET *block_out_reg_set;
up by find_blocks and used there and in life_analysis. It can be used
later, but only to look up an insn that is the head or tail of some
block. life_analysis and the stack register conversion process can
- add insns within a block. */
+ add insns within a block. */
static int *block_number;
/* This is the register file for all register after conversion */
@@ -224,28 +226,52 @@ static rtx
(FP_mode_reg[(regno)-FIRST_STACK_REG][(int)(mode)])
/* Get the basic block number of an insn. See note at block_number
- definition are validity of this information. */
+ definition are validity of this information. */
#define BLOCK_NUM(INSN) \
((INSN_UID (INSN) > max_uid) \
? (abort() , -1) : block_number[INSN_UID (INSN)])
extern rtx forced_labels;
-extern rtx gen_jump ();
-extern rtx gen_movdf (), gen_movxf ();
-extern rtx find_regno_note ();
-extern rtx emit_jump_insn_before ();
-extern rtx emit_label_after ();
/* Forward declarations */
-static void find_blocks ();
-static uses_reg_or_mem ();
-static void stack_reg_life_analysis ();
-static void record_reg_life_pat ();
-static void change_stack ();
-static void convert_regs ();
-static void dump_stack_info ();
+static void mark_regs_pat PROTO((rtx, HARD_REG_SET *));
+static void straighten_stack PROTO((rtx, stack));
+static void pop_stack PROTO((stack, int));
+static void record_label_references PROTO((rtx, rtx));
+static rtx *get_true_reg PROTO((rtx *));
+static int constrain_asm_operands PROTO((int, rtx *, char **, int *,
+ enum reg_class *));
+
+static void record_asm_reg_life PROTO((rtx,stack, rtx *, char **,
+ int, int));
+static void record_reg_life_pat PROTO((rtx, HARD_REG_SET *,
+ HARD_REG_SET *, int));
+static void get_asm_operand_lengths PROTO((rtx, int, int *, int *));
+static void record_reg_life PROTO((rtx, int, stack));
+static void find_blocks PROTO((rtx));
+static rtx stack_result PROTO((tree));
+static void stack_reg_life_analysis PROTO((rtx, HARD_REG_SET *));
+static void replace_reg PROTO((rtx *, int));
+static void remove_regno_note PROTO((rtx, enum reg_note, int));
+static int get_hard_regnum PROTO((stack, rtx));
+static void delete_insn_for_stacker PROTO((rtx));
+static rtx emit_pop_insn PROTO((rtx, stack, rtx, rtx (*) ()));
+static void emit_swap_insn PROTO((rtx, stack, rtx));
+static void move_for_stack_reg PROTO((rtx, stack, rtx));
+static void swap_rtx_condition PROTO((rtx));
+static void compare_for_stack_reg PROTO((rtx, stack, rtx));
+static void subst_stack_regs_pat PROTO((rtx, stack, rtx));
+static void subst_asm_stack_regs PROTO((rtx, stack, rtx *, rtx **,
+ char **, int, int));
+static void subst_stack_regs PROTO((rtx, stack));
+static void change_stack PROTO((rtx, stack, stack, rtx (*) ()));
+
+static void goto_block_pat PROTO((rtx, stack, rtx));
+static void convert_regs PROTO((void));
+static void print_blocks PROTO((FILE *, rtx, rtx));
+static void dump_stack_info PROTO((FILE *));
/* Mark all registers needed for this pattern. */
@@ -283,6 +309,13 @@ straighten_stack (insn, regstack)
struct stack_def temp_stack;
int top;
+ /* If there is only a single register on the stack, then the stack is
+ already in increasing order and no reorganization is needed.
+
+ Similarly if the stack is empty. */
+ if (regstack->top <= 0)
+ return;
+
temp_stack.reg_set = regstack->reg_set;
for (top = temp_stack.top = regstack->top; top >= 0; top--)
@@ -290,6 +323,32 @@ straighten_stack (insn, regstack)
change_stack (insn, regstack, &temp_stack, emit_insn_after);
}
+
+/* Pop a register from the stack */
+
+static void
+pop_stack (regstack, regno)
+ stack regstack;
+ int regno;
+{
+ int top = regstack->top;
+
+ CLEAR_HARD_REG_BIT (regstack->reg_set, regno);
+ regstack->top--;
+ /* If regno was not at the top of stack then adjust stack */
+ if (regstack->reg [top] != regno)
+ {
+ int i;
+ for (i = regstack->top; i >= 0; i--)
+ if (regstack->reg [i] == regno)
+ {
+ int j;
+ for (j = i; j < top; j++)
+ regstack->reg [j] = regstack->reg [j + 1];
+ break;
+ }
+ }
+}
/* Return non-zero if any stack register is mentioned somewhere within PAT. */
@@ -345,7 +404,7 @@ reg_to_stack (first, file)
CLEAR_HARD_REG_SET (stackentry);
{
- static initialised;
+ static int initialised;
if (!initialised)
{
#if 0
@@ -358,10 +417,10 @@ reg_to_stack (first, file)
{
for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
- FP_MODE_REG (i, mode) = gen_rtx (REG, mode, i);
+ FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
- FP_MODE_REG (i, mode) = gen_rtx (REG, mode, i);
+ FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
}
}
}
@@ -370,7 +429,7 @@ reg_to_stack (first, file)
{
register RTX_CODE prev_code = BARRIER;
register RTX_CODE code;
- register before_function_beg = 1;
+ register int before_function_beg = 1;
max_uid = 0;
blocks = 0;
@@ -396,7 +455,7 @@ reg_to_stack (first, file)
before_function_beg = 0;
/* Remember whether or not this insn mentions an FP regs.
- Check JUMP_INSNs too, in case someone creates a funny PARALLEL. */
+ Check JUMP_INSNs too, in case someone creates a funny PARALLEL. */
if (GET_RTX_CLASS (code) == 'i'
&& stack_regs_mentioned_p (PATTERN (insn)))
@@ -408,7 +467,7 @@ reg_to_stack (first, file)
if (before_function_beg && code == INSN
&& GET_CODE (PATTERN (insn)) == USE)
- record_reg_life_pat (PATTERN (insn), (HARD_REG_SET*) 0,
+ record_reg_life_pat (PATTERN (insn), (HARD_REG_SET *) 0,
&stackentry, 1);
}
else
@@ -428,13 +487,13 @@ reg_to_stack (first, file)
if (! stack_reg_seen)
return;
- /* If there are stack registers, there must be at least one block. */
+ /* If there are stack registers, there must be at least one block. */
if (! blocks)
abort ();
/* Allocate some tables that last till end of compiling this function
- and some needed only in find_blocks and life_analysis. */
+ and some needed only in find_blocks and life_analysis. */
block_begin = (rtx *) alloca (blocks * sizeof (rtx));
block_end = (rtx *) alloca (blocks * sizeof (rtx));
@@ -452,7 +511,7 @@ reg_to_stack (first, file)
/* Dump the life analysis debug information before jump
optimization, as that will destroy the LABEL_REFS we keep the
- information in. */
+ information in. */
if (file)
dump_stack_info (file);
@@ -465,7 +524,7 @@ reg_to_stack (first, file)
/* Check PAT, which is in INSN, for LABEL_REFs. Add INSN to the
label's chain of references, and note which insn contains each
- reference. */
+ reference. */
static void
record_label_references (insn, pat)
@@ -483,7 +542,12 @@ record_label_references (insn, pat)
if (GET_CODE (label) != CODE_LABEL)
abort ();
- /* Don't make a duplicate in the code_label's chain. */
+ /* If this is an undefined label, LABEL_REFS (label) contains
+ garbage. */
+ if (INSN_UID (label) == 0)
+ return;
+
+ /* Don't make a duplicate in the code_label's chain. */
for (ref = LABEL_REFS (label);
ref && ref != label;
@@ -514,7 +578,7 @@ record_label_references (insn, pat)
/* Return a pointer to the REG expression within PAT. If PAT is not a
REG, possible enclosed by a conversion rtx, return the inner part of
- PAT that stopped the search. */
+ PAT that stopped the search. */
static rtx *
get_true_reg (pat)
@@ -525,7 +589,7 @@ get_true_reg (pat)
{
case SUBREG:
/* eliminate FP subregister accesses in favour of the
- actual FP register in use. */
+ actual FP register in use. */
{
rtx subreg;
if (FP_REG_P (subreg = SUBREG_REG (*pat)))
@@ -558,7 +622,7 @@ get_true_reg (pat)
OPERAND_CLASS is set to `class' as required by the constraints, not to
the subclass. If an alternative allows more than one class,
OPERAND_CLASS is set to the smallest class that is a union of the
- allowed classes. */
+ allowed classes. */
static int
constrain_asm_operands (n_operands, operands, operand_constraints,
@@ -582,9 +646,14 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
already guaranteed that all operands have the same number of
alternatives. */
- n_alternatives = 1;
- for (q = constraints[0]; *q; q++)
- n_alternatives += (*q == ',');
+ if (n_operands == 0)
+ n_alternatives = 0;
+ else
+ {
+ n_alternatives = 1;
+ for (q = constraints[0]; *q; q++)
+ n_alternatives += (*q == ',');
+ }
this_alternative = 0;
while (this_alternative < n_alternatives)
@@ -631,11 +700,11 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
case '!':
case '*':
case '%':
- /* Ignore these. */
+ /* Ignore these. */
break;
case '#':
- /* Ignore rest of this alternative. */
+ /* Ignore rest of this alternative. */
while (*p && *p != ',') p++;
break;
@@ -649,7 +718,7 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
This kind of constraint is used for instructions such
as add when they take only two operands.
- Note that the lower-numbered operand is passed first. */
+ Note that the lower-numbered operand is passed first. */
if (operands_match_p (operands[c - '0'],
operands[this_operand]))
@@ -661,7 +730,7 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
case 'p':
/* p is used for address_operands. Since this is an asm,
- just to make sure that the operand is valid for Pmode. */
+ just to make sure that the operand is valid for Pmode. */
if (strict_memory_address_p (Pmode, op))
win = 1;
@@ -694,7 +763,7 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
case 'X':
/* This is used for a MATCH_SCRATCH in the cases when we
- don't actually need anything. So anything goes any time. */
+ don't actually need anything. So anything goes any time. */
win = 1;
break;
@@ -818,7 +887,7 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
}
/* For operands constrained to match another operand, copy the other
- operand's class to this operand's class. */
+ operand's class to this operand's class. */
for (j = 0; j < n_operands; j++)
if (operand_matches[j] >= 0)
operand_class[j] = operand_class[operand_matches[j]];
@@ -834,7 +903,7 @@ constrain_asm_operands (n_operands, operands, operand_constraints,
There are many rules that an asm statement for stack-like regs must
follow. Those rules are explained at the top of this file: the rule
- numbers below refer to that explanation. */
+ numbers below refer to that explanation. */
static void
record_asm_reg_life (insn, regstack, operands, constraints,
@@ -869,7 +938,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
if (i < 0)
malformed_asm = 1;
- /* Strip SUBREGs here to make the following code simpler. */
+ /* Strip SUBREGs here to make the following code simpler. */
for (i = 0; i < n_operands; i++)
if (GET_CODE (operands[i]) == SUBREG
&& GET_CODE (SUBREG_REG (operands[i])) == REG)
@@ -905,19 +974,20 @@ record_asm_reg_life (insn, regstack, operands, constraints,
operand constraints must select a class with a single reg.
Also enforce rule #5: Output operands must start at the top of
- the reg-stack: output operands may not "skip" a reg. */
+ the reg-stack: output operands may not "skip" a reg. */
bzero ((char *) reg_used_as_output, sizeof (reg_used_as_output));
for (i = 0; i < n_outputs; i++)
if (STACK_REG_P (operands[i]))
- if (reg_class_size[(int) operand_class[i]] != 1)
- {
- error_for_asm
- (insn, "Output constraint %d must specify a single register", i);
- malformed_asm = 1;
- }
- else
- reg_used_as_output[REGNO (operands[i])] = 1;
+ {
+ if (reg_class_size[(int) operand_class[i]] != 1)
+ {
+ error_for_asm (insn, "Output constraint %d must specify a single register", i);
+ malformed_asm = 1;
+ }
+ else
+ reg_used_as_output[REGNO (operands[i])] = 1;
+ }
/* Search for first non-popped reg. */
@@ -938,14 +1008,14 @@ record_asm_reg_life (insn, regstack, operands, constraints,
/* Enforce rule #2: All implicitly popped input regs must be closer
to the top of the reg-stack than any input that is not implicitly
- popped. */
+ popped. */
bzero ((char *) implicitly_dies, sizeof (implicitly_dies));
for (i = first_input; i < first_input + n_inputs; i++)
if (STACK_REG_P (operands[i]))
{
/* An input reg is implicitly popped if it is tied to an
- output, or if there is a CLOBBER for it. */
+ output, or if there is a CLOBBER for it. */
int j;
for (j = 0; j < n_clobbers; j++)
@@ -977,7 +1047,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
output constraints must use the "&" earlyclobber.
??? Detect this more deterministically by having constraint_asm_operands
- record any earlyclobber. */
+ record any earlyclobber. */
for (i = first_input; i < first_input + n_inputs; i++)
if (operand_matches[i] == -1)
@@ -996,7 +1066,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
if (malformed_asm)
{
/* Avoid further trouble with this insn. */
- PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
PUT_MODE (insn, VOIDmode);
return;
}
@@ -1007,18 +1077,20 @@ record_asm_reg_life (insn, regstack, operands, constraints,
rtx op = operands[i];
if (! STACK_REG_P (op))
- if (stack_regs_mentioned_p (op))
- abort ();
- else
- continue;
+ {
+ if (stack_regs_mentioned_p (op))
+ abort ();
+ else
+ continue;
+ }
/* Each destination is dead before this insn. If the
destination is not used after this insn, record this with
REG_UNUSED. */
if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (op)))
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED, op,
- REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED, op,
+ REG_NOTES (insn));
CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (op));
}
@@ -1027,10 +1099,12 @@ record_asm_reg_life (insn, regstack, operands, constraints,
for (i = first_input; i < first_input + n_inputs; i++)
{
if (! STACK_REG_P (operands[i]))
- if (stack_regs_mentioned_p (operands[i]))
- abort ();
- else
- continue;
+ {
+ if (stack_regs_mentioned_p (operands[i]))
+ abort ();
+ else
+ continue;
+ }
/* If an input is dead after the insn, record a death note.
But don't record a death note if there is already a death note,
@@ -1039,8 +1113,8 @@ record_asm_reg_life (insn, regstack, operands, constraints,
if (! TEST_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]))
&& operand_matches[i] == -1
&& find_regno_note (insn, REG_DEAD, REGNO (operands[i])) == NULL_RTX)
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD, operands[i],
- REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, operands[i],
+ REG_NOTES (insn));
SET_HARD_REG_BIT (regstack->reg_set, REGNO (operands[i]));
}
@@ -1050,7 +1124,7 @@ record_asm_reg_life (insn, regstack, operands, constraints,
a SET_DEST in DEST, and other registers in SRC.
This function does not know about SET_DESTs that are both input and
- output (such as ZERO_EXTRACT) - this cannot happen on a 387. */
+ output (such as ZERO_EXTRACT) - this cannot happen on a 387. */
static void
record_reg_life_pat (pat, src, dest, douse)
@@ -1062,7 +1136,7 @@ record_reg_life_pat (pat, src, dest, douse)
register int i;
if (STACK_REG_P (pat)
- || GET_CODE (pat) == SUBREG && STACK_REG_P (SUBREG_REG (pat)))
+ || (GET_CODE (pat) == SUBREG && STACK_REG_P (SUBREG_REG (pat))))
{
if (src)
mark_regs_pat (pat, src);
@@ -1080,8 +1154,8 @@ record_reg_life_pat (pat, src, dest, douse)
return;
}
- /* We don't need to consider either of these cases. */
- if (GET_CODE (pat) == USE && !douse || GET_CODE (pat) == CLOBBER)
+ /* We don't need to consider either of these cases. */
+ if ((GET_CODE (pat) == USE && !douse) || GET_CODE (pat) == CLOBBER)
return;
fmt = GET_RTX_FORMAT (GET_CODE (pat));
@@ -1102,7 +1176,7 @@ record_reg_life_pat (pat, src, dest, douse)
/* Calculate the number of inputs and outputs in BODY, an
asm_operands. N_OPERANDS is the total number of operands, and
N_INPUTS and N_OUTPUTS are pointers to ints into which the results are
- placed. */
+ placed. */
static void
get_asm_operand_lengths (body, n_operands, n_inputs, n_outputs)
@@ -1139,7 +1213,7 @@ get_asm_operand_lengths (body, n_operands, n_inputs, n_outputs)
register. The block_end[] data is kept accurate.
Existing death and unset notes for stack registers are deleted
- before processing the insn. */
+ before processing the insn. */
static void
record_reg_life (insn, block, regstack)
@@ -1165,13 +1239,13 @@ record_reg_life (insn, block, regstack)
else
note_link = &XEXP (note, 1);
- /* Process all patterns in the insn. */
+ /* Process all patterns in the insn. */
n_operands = asm_noperands (PATTERN (insn));
if (n_operands >= 0)
{
/* This insn is an `asm' with operands. Decode the operands,
- decide how many are inputs, and record the life information. */
+ decide how many are inputs, and record the life information. */
rtx operands[MAX_RECOG_OPERANDS];
rtx body = PATTERN (insn);
@@ -1205,13 +1279,13 @@ record_reg_life (insn, block, regstack)
{
if (TEST_HARD_REG_BIT (src, regno)
&& ! TEST_HARD_REG_BIT (dest, regno))
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
- FP_MODE_REG (regno, DFmode),
- REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
+ FP_MODE_REG (regno, DFmode),
+ REG_NOTES (insn));
else if (TEST_HARD_REG_BIT (dest, regno))
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_UNUSED,
- FP_MODE_REG (regno, DFmode),
- REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED,
+ FP_MODE_REG (regno, DFmode),
+ REG_NOTES (insn));
}
if (GET_CODE (insn) == CALL_INSN)
@@ -1220,7 +1294,7 @@ record_reg_life (insn, block, regstack)
/* There might be a reg that is live after a function call.
Initialize it to zero so that the program does not crash. See
- comment towards the end of stack_reg_life_analysis(). */
+ comment towards the end of stack_reg_life_analysis(). */
for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)
if (! TEST_HARD_REG_BIT (dest, reg)
@@ -1231,17 +1305,17 @@ record_reg_life (insn, block, regstack)
/* The insn will use virtual register numbers, and so
convert_regs is expected to process these. But BLOCK_NUM
cannot be used on these insns, because they do not appear in
- block_number[]. */
+ block_number[]. */
- pat = gen_rtx (SET, VOIDmode, FP_MODE_REG (reg, DFmode),
- CONST0_RTX (DFmode));
+ pat = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, DFmode),
+ CONST0_RTX (DFmode));
init = emit_insn_after (pat, insn);
PUT_MODE (init, QImode);
CLEAR_HARD_REG_BIT (regstack->reg_set, reg);
/* If the CALL_INSN was the end of a block, move the
- block_end to point to the new insn. */
+ block_end to point to the new insn. */
if (block_end[block] == insn)
block_end[block] = init;
@@ -1257,7 +1331,7 @@ record_reg_life (insn, block, regstack)
}
/* Find all basic blocks of the function, which starts with FIRST.
- For each JUMP_INSN, build the chain of LABEL_REFS on each CODE_LABEL. */
+ For each JUMP_INSN, build the chain of LABEL_REFS on each CODE_LABEL. */
static void
find_blocks (first)
@@ -1270,7 +1344,7 @@ find_blocks (first)
rtx label_value_list = 0;
/* Record where all the blocks start and end.
- Record which basic blocks control can drop in to. */
+ Record which basic blocks control can drop in to. */
block = -1;
for (insn = first; insn; insn = NEXT_INSN (insn))
@@ -1301,8 +1375,8 @@ find_blocks (first)
/* Make a list of all labels referred to other than by jumps. */
for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
if (REG_NOTE_KIND (note) == REG_LABEL)
- label_value_list = gen_rtx (EXPR_LIST, VOIDmode, XEXP (note, 0),
- label_value_list);
+ label_value_list = gen_rtx_EXPR_LIST (VOIDmode, XEXP (note, 0),
+ label_value_list);
}
block_number[INSN_UID (insn)] = block;
@@ -1322,43 +1396,19 @@ find_blocks (first)
if (GET_CODE (insn) == JUMP_INSN)
{
rtx pat = PATTERN (insn);
- int computed_jump = 0;
rtx x;
- if (GET_CODE (pat) == PARALLEL)
- {
- int len = XVECLEN (pat, 0);
- int has_use_labelref = 0;
- int i;
-
- for (i = len - 1; i >= 0; i--)
- if (GET_CODE (XVECEXP (pat, 0, i)) == USE
- && GET_CODE (XEXP (XVECEXP (pat, 0, i), 0)) == LABEL_REF)
- has_use_labelref = 1;
-
- if (! has_use_labelref)
- for (i = len - 1; i >= 0; i--)
- if (GET_CODE (XVECEXP (pat, 0, i)) == SET
- && SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx
- && uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))
- computed_jump = 1;
- }
- else if (GET_CODE (pat) == SET
- && SET_DEST (pat) == pc_rtx
- && uses_reg_or_mem (SET_SRC (pat)))
- computed_jump = 1;
-
- if (computed_jump)
+ if (computed_jump_p (insn))
{
for (x = label_value_list; x; x = XEXP (x, 1))
record_label_references (insn,
- gen_rtx (LABEL_REF, VOIDmode,
- XEXP (x, 0)));
+ gen_rtx_LABEL_REF (VOIDmode,
+ XEXP (x, 0)));
for (x = forced_labels; x; x = XEXP (x, 1))
record_label_references (insn,
- gen_rtx (LABEL_REF, VOIDmode,
- XEXP (x, 0)));
+ gen_rtx_LABEL_REF (VOIDmode,
+ XEXP (x, 0)));
}
record_label_references (insn, pat);
@@ -1366,38 +1416,6 @@ find_blocks (first)
}
}
-/* Return 1 if X contain a REG or MEM that is not in the constant pool. */
-
-static int
-uses_reg_or_mem (x)
- rtx x;
-{
- enum rtx_code code = GET_CODE (x);
- int i, j;
- char *fmt;
-
- if (code == REG
- || (code == MEM
- && ! (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
- && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)))))
- return 1;
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e'
- && uses_reg_or_mem (XEXP (x, i)))
- return 1;
-
- if (fmt[i] == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- if (uses_reg_or_mem (XVECEXP (x, i, j)))
- return 1;
- }
-
- return 0;
-}
-
/* If current function returns its result in an fp stack register,
return the REG. Otherwise, return 0. */
@@ -1450,7 +1468,7 @@ stack_result (decl)
If there are registers that are live at the start of the function,
insns are emitted to initialize these registers. Something similar is
- done after CALL_INSNs in record_reg_life. */
+ done after CALL_INSNs in record_reg_life. */
static void
stack_reg_life_analysis (first, stackentry)
@@ -1463,9 +1481,9 @@ stack_reg_life_analysis (first, stackentry)
{
rtx retvalue;
- if (retvalue = stack_result (current_function_decl))
+ if ((retvalue = stack_result (current_function_decl)))
{
- /* Find all RETURN insns and mark them. */
+ /* Find all RETURN insns and mark them. */
for (block = blocks - 1; --block >= 0;)
if (GET_CODE (block_end[block]) == JUMP_INSN
@@ -1473,7 +1491,7 @@ stack_reg_life_analysis (first, stackentry)
mark_regs_pat (retvalue, block_out_reg_set+block);
/* Mark off the end of last block if we "fall off" the end of the
- function into the epilogue. */
+ function into the epilogue. */
if (GET_CODE (block_end[blocks-1]) != JUMP_INSN
|| GET_CODE (PATTERN (block_end[blocks-1])) == RETURN)
@@ -1500,7 +1518,7 @@ stack_reg_life_analysis (first, stackentry)
/* If the insn is a CALL_INSN, we need to ensure that
everything dies. But otherwise don't process unless there
- are some stack regs present. */
+ are some stack regs present. */
if (GET_MODE (insn) == QImode || GET_CODE (insn) == CALL_INSN)
record_reg_life (insn, block, &regstack);
@@ -1508,13 +1526,13 @@ stack_reg_life_analysis (first, stackentry)
} while (insn != block_begin[block]);
/* Set the state at the start of the block. Mark that no
- register mapping information known yet. */
+ register mapping information known yet. */
COPY_HARD_REG_SET (block_stack_in[block].reg_set, regstack.reg_set);
block_stack_in[block].top = -2;
/* If there is a label, propagate our register life to all jumps
- to this label. */
+ to this label. */
if (GET_CODE (insn) == CODE_LABEL)
{
@@ -1535,7 +1553,7 @@ stack_reg_life_analysis (first, stackentry)
processed. If there are registers that were not known
to be live then, but are live now, we must back up
and restart life analysis from that point with the new
- life information. */
+ life information. */
GO_IF_HARD_REG_SUBSET (block_stack_in[block].reg_set,
block_out_reg_set[jump_block],
@@ -1546,6 +1564,7 @@ stack_reg_life_analysis (first, stackentry)
block = jump_block;
must_restart = 1;
+ break;
win:
;
@@ -1565,7 +1584,7 @@ stack_reg_life_analysis (first, stackentry)
/* If any reg is live at the start of the first block of a
function, then we must guarantee that the reg holds some value by
generating our own "load" of that register. Otherwise a 387 would
- fault trying to access an empty register. */
+ fault trying to access an empty register. */
/* Load zero into each live register. The fact that a register
appears live at the function start necessarily implies an error
@@ -1576,7 +1595,7 @@ stack_reg_life_analysis (first, stackentry)
Note that we are inserting virtual register references here:
these insns must be processed by convert_regs later. Also, these
- insns will not be in block_number, so BLOCK_NUM() will fail for them. */
+ insns will not be in block_number, so BLOCK_NUM() will fail for them. */
for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; reg--)
if (TEST_HARD_REG_BIT (block_stack_in[0].reg_set, reg)
@@ -1584,8 +1603,8 @@ stack_reg_life_analysis (first, stackentry)
{
rtx init_rtx;
- init_rtx = gen_rtx (SET, VOIDmode, FP_MODE_REG(reg, DFmode),
- CONST0_RTX (DFmode));
+ init_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG(reg, DFmode),
+ CONST0_RTX (DFmode));
block_begin[0] = emit_insn_after (init_rtx, first);
PUT_MODE (block_begin[0], QImode);
@@ -1599,7 +1618,7 @@ stack_reg_life_analysis (first, stackentry)
*****************************************************************************/
/* Replace REG, which is a pointer to a stack reg RTX, with an RTX for
- the desired hard REGNO. */
+ the desired hard REGNO. */
static void
replace_reg (reg, regno)
@@ -1621,7 +1640,7 @@ replace_reg (reg, regno)
}
/* Remove a note of type NOTE, which must be found, for register
- number REGNO from INSN. Remove only one such note. */
+ number REGNO from INSN. Remove only one such note. */
static void
remove_regno_note (insn, note, regno)
@@ -1647,7 +1666,7 @@ remove_regno_note (insn, note, regno)
/* Find the hard register number of virtual register REG in REGSTACK.
The hard register number is relative to the top of the stack. -1 is
- returned if the register is not found. */
+ returned if the register is not found. */
static int
get_hard_regnum (regstack, reg)
@@ -1668,7 +1687,7 @@ get_hard_regnum (regstack, reg)
/* Delete INSN from the RTL. Mark the insn, but don't remove it from
the chain of insns. Doing so could confuse block_begin and block_end
- if this were the only insn in the block. */
+ if this were the only insn in the block. */
static void
delete_insn_for_stacker (insn)
@@ -1684,7 +1703,7 @@ delete_insn_for_stacker (insn)
pop. WHEN is either emit_insn_before or emit_insn_after. A pop insn
is represented as a SET whose destination is the register to be popped
and source is the top of stack. A death note for the top of stack
- cases the movdf pattern to pop. */
+ cases the movdf pattern to pop. */
static rtx
emit_pop_insn (insn, regstack, reg, when)
@@ -1701,16 +1720,16 @@ emit_pop_insn (insn, regstack, reg, when)
if (hard_regno < FIRST_STACK_REG)
abort ();
- pop_rtx = gen_rtx (SET, VOIDmode, FP_MODE_REG (hard_regno, DFmode),
- FP_MODE_REG (FIRST_STACK_REG, DFmode));
+ pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode),
+ FP_MODE_REG (FIRST_STACK_REG, DFmode));
pop_insn = (*when) (pop_rtx, insn);
- /* ??? This used to be VOIDmode, but that seems wrong. */
+ /* ??? This used to be VOIDmode, but that seems wrong. */
PUT_MODE (pop_insn, QImode);
- REG_NOTES (pop_insn) = gen_rtx (EXPR_LIST, REG_DEAD,
- FP_MODE_REG (FIRST_STACK_REG, DFmode),
- REG_NOTES (pop_insn));
+ REG_NOTES (pop_insn) = gen_rtx_EXPR_LIST (REG_DEAD,
+ FP_MODE_REG (FIRST_STACK_REG, DFmode),
+ REG_NOTES (pop_insn));
regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)]
= regstack->reg[regstack->top];
@@ -1726,7 +1745,7 @@ emit_pop_insn (insn, regstack, reg, when)
the swap. A swap insn is represented as a PARALLEL of two patterns:
each pattern moves one reg to the other.
- If REG is already at the top of the stack, no insn is emitted. */
+ If REG is already at the top of the stack, no insn is emitted. */
static void
emit_swap_insn (insn, regstack, reg)
@@ -1765,12 +1784,11 @@ emit_swap_insn (insn, regstack, reg)
if (i1set)
{
- rtx i2; /* the stack-reg insn prior to I1 */
rtx i1src = *get_true_reg (&SET_SRC (i1set));
rtx i1dest = *get_true_reg (&SET_DEST (i1set));
/* If the previous register stack push was from the reg we are to
- swap with, omit the swap. */
+ swap with, omit the swap. */
if (GET_CODE (i1dest) == REG && REGNO (i1dest) == FIRST_STACK_REG
&& GET_CODE (i1src) == REG && REGNO (i1src) == hard_regno - 1
@@ -1796,12 +1814,12 @@ emit_swap_insn (insn, regstack, reg)
swap_rtx = gen_swapdf (FP_MODE_REG (hard_regno, DFmode),
FP_MODE_REG (FIRST_STACK_REG, DFmode));
swap_insn = emit_insn_after (swap_rtx, i1);
- /* ??? This used to be VOIDmode, but that seems wrong. */
+ /* ??? This used to be VOIDmode, but that seems wrong. */
PUT_MODE (swap_insn, QImode);
}
/* Handle a move to or from a stack register in PAT, which is in INSN.
- REGSTACK is the current stack. */
+ REGSTACK is the current stack. */
static void
move_for_stack_reg (insn, regstack, pat)
@@ -1819,14 +1837,14 @@ move_for_stack_reg (insn, regstack, pat)
if (STACK_REG_P (src) && STACK_REG_P (dest))
{
/* Write from one stack reg to another. If SRC dies here, then
- just change the register mapping and delete the insn. */
+ just change the register mapping and delete the insn. */
note = find_regno_note (insn, REG_DEAD, REGNO (src));
if (note)
{
int i;
- /* If this is a no-op move, there must not be a REG_DEAD note. */
+ /* If this is a no-op move, there must not be a REG_DEAD note. */
if (REGNO (src) == REGNO (dest))
abort ();
@@ -1834,12 +1852,12 @@ move_for_stack_reg (insn, regstack, pat)
if (regstack->reg[i] == REGNO (src))
break;
- /* The source must be live, and the dest must be dead. */
+ /* The source must be live, and the dest must be dead. */
if (i < 0 || get_hard_regnum (regstack, dest) >= FIRST_STACK_REG)
abort ();
/* It is possible that the dest is unused after this insn.
- If so, just pop the src. */
+ If so, just pop the src. */
if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
{
@@ -1859,12 +1877,12 @@ move_for_stack_reg (insn, regstack, pat)
return;
}
- /* The source reg does not die. */
+ /* The source reg does not die. */
/* If this appears to be a no-op move, delete it, or else it
will confuse the machine description output patterns. But if
it is REG_UNUSED, we must pop the reg now, as per-insn processing
- for REG_UNUSED will not work for deleted insns. */
+ for REG_UNUSED will not work for deleted insns. */
if (REGNO (src) == REGNO (dest))
{
@@ -1889,7 +1907,7 @@ move_for_stack_reg (insn, regstack, pat)
{
/* Save from a stack reg to MEM, or possibly integer reg. Since
only top of stack may be saved, emit an exchange first if
- needs be. */
+ needs be. */
emit_swap_insn (insn, regstack, src);
@@ -1900,7 +1918,7 @@ move_for_stack_reg (insn, regstack, pat)
regstack->top--;
CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
}
- else if (GET_MODE (src) == XFmode && regstack->top != REG_STACK_SIZE)
+ else if (GET_MODE (src) == XFmode && regstack->top < REG_STACK_SIZE - 1)
{
/* A 387 cannot write an XFmode value to a MEM without
clobbering the source reg. The output code can handle
@@ -1915,8 +1933,8 @@ move_for_stack_reg (insn, regstack, pat)
push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
push_insn = emit_insn_before (push_rtx, insn);
PUT_MODE (push_insn, QImode);
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD, top_stack_reg,
- REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, top_stack_reg,
+ REG_NOTES (insn));
}
replace_reg (psrc, FIRST_STACK_REG);
@@ -1943,7 +1961,7 @@ move_for_stack_reg (insn, regstack, pat)
abort ();
}
-void
+static void
swap_rtx_condition (pat)
rtx pat;
{
@@ -1977,7 +1995,7 @@ swap_rtx_condition (pat)
Also, a pop insn may need to be emitted. The 387 does have an
`fcompp' insn that can pop two regs, but it is sometimes too expensive
to do this - a `fcomp' followed by a `fstpl %st(0)' may be easier to
- set up. */
+ set up. */
static void
compare_for_stack_reg (insn, regstack, pat)
@@ -1987,12 +2005,37 @@ compare_for_stack_reg (insn, regstack, pat)
{
rtx *src1, *src2;
rtx src1_note, src2_note;
+ rtx cc0_user;
+ int have_cmove;
src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
src2 = get_true_reg (&XEXP (SET_SRC (pat), 1));
+ cc0_user = next_cc0_user (insn);
+
+ /* If the insn that uses cc0 is an FP-conditional move, then the destination
+ must be the top of stack */
+ if (GET_CODE (PATTERN (cc0_user)) == SET
+ && SET_DEST (PATTERN (cc0_user)) != pc_rtx
+ && GET_CODE (SET_SRC (PATTERN (cc0_user))) == IF_THEN_ELSE
+ && (GET_MODE_CLASS (GET_MODE (SET_DEST (PATTERN (cc0_user))))
+ == MODE_FLOAT))
+ {
+ rtx *dest;
+
+ dest = get_true_reg (&SET_DEST (PATTERN (cc0_user)));
+
+ have_cmove = 1;
+ if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG
+ && REGNO (*dest) != regstack->reg[regstack->top])
+ {
+ emit_swap_insn (insn, regstack, *dest);
+ }
+ }
+ else
+ have_cmove = 0;
/* ??? If fxch turns out to be cheaper than fstp, give priority to
- registers that die in this insn - move those to stack top first. */
+ registers that die in this insn - move those to stack top first. */
if (! STACK_REG_P (*src1)
|| (STACK_REG_P (*src2)
&& get_hard_regnum (regstack, *src2) == FIRST_STACK_REG))
@@ -2015,7 +2058,7 @@ compare_for_stack_reg (insn, regstack, pat)
INSN_CODE (insn) = -1;
}
- /* We will fix any death note later. */
+ /* We will fix any death note later. */
src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
@@ -2024,7 +2067,8 @@ compare_for_stack_reg (insn, regstack, pat)
else
src2_note = NULL_RTX;
- emit_swap_insn (insn, regstack, *src1);
+ if (! have_cmove)
+ emit_swap_insn (insn, regstack, *src1);
replace_reg (src1, FIRST_STACK_REG);
@@ -2033,14 +2077,13 @@ compare_for_stack_reg (insn, regstack, pat)
if (src1_note)
{
- CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (XEXP (src1_note, 0)));
+ pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
- regstack->top--;
}
/* If the second operand dies, handle that. But if the operands are
the same stack register, don't bother, because only one death is
- needed, and it was just handled. */
+ needed, and it was just handled. */
if (src2_note
&& ! (STACK_REG_P (*src1) && STACK_REG_P (*src2)
@@ -2049,20 +2092,19 @@ compare_for_stack_reg (insn, regstack, pat)
/* As a special case, two regs may die in this insn if src2 is
next to top of stack and the top of stack also dies. Since
we have already popped src1, "next to top of stack" is really
- at top (FIRST_STACK_REG) now. */
+ at top (FIRST_STACK_REG) now. */
if (get_hard_regnum (regstack, XEXP (src2_note, 0)) == FIRST_STACK_REG
&& src1_note)
{
- CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (XEXP (src2_note, 0)));
+ pop_stack (regstack, REGNO (XEXP (src2_note, 0)));
replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1);
- regstack->top--;
}
else
{
/* The 386 can only represent death of the first operand in
the case handled above. In all other cases, emit a separate
- pop and remove the death note from here. */
+ pop and remove the death note from here. */
link_cc0_insns (insn);
@@ -2075,7 +2117,7 @@ compare_for_stack_reg (insn, regstack, pat)
}
/* Substitute new registers in PAT, which is part of INSN. REGSTACK
- is the current register layout. */
+ is the current register layout. */
static void
subst_stack_regs_pat (insn, regstack, pat)
@@ -2093,7 +2135,7 @@ subst_stack_regs_pat (insn, regstack, pat)
dest = get_true_reg (&SET_DEST (pat));
src = get_true_reg (&SET_SRC (pat));
- /* See if this is a `movM' pattern, and handle elsewhere if so. */
+ /* See if this is a `movM' pattern, and handle elsewhere if so. */
if (*dest != cc0_rtx
&& (STACK_REG_P (*src)
@@ -2122,13 +2164,13 @@ subst_stack_regs_pat (insn, regstack, pat)
break;
case REG:
- /* This is a `tstM2' case. */
+ /* This is a `tstM2' case. */
if (*dest != cc0_rtx)
abort ();
src1 = src;
- /* Fall through. */
+ /* Fall through. */
case FLOAT_TRUNCATE:
case SQRT:
@@ -2164,18 +2206,18 @@ subst_stack_regs_pat (insn, regstack, pat)
case DIV:
/* On i386, reversed forms of subM3 and divM3 exist for
MODE_FLOAT, so the same code that works for addM3 and mulM3
- can be used. */
+ can be used. */
case MULT:
case PLUS:
/* These insns can accept the top of stack as a destination
from a stack reg or mem, or can use the top of stack as a
source and some other stack register (possibly top of stack)
- as a destination. */
+ as a destination. */
src1 = get_true_reg (&XEXP (SET_SRC (pat), 0));
src2 = get_true_reg (&XEXP (SET_SRC (pat), 1));
- /* We will fix any death note later. */
+ /* We will fix any death note later. */
if (STACK_REG_P (*src1))
src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
@@ -2187,7 +2229,7 @@ subst_stack_regs_pat (insn, regstack, pat)
src2_note = NULL_RTX;
/* If either operand is not a stack register, then the dest
- must be top of stack. */
+ must be top of stack. */
if (! STACK_REG_P (*src1) || ! STACK_REG_P (*src2))
emit_swap_insn (insn, regstack, *dest);
@@ -2220,7 +2262,7 @@ subst_stack_regs_pat (insn, regstack, pat)
the destination is somewhere else - merely substitute it.
But if the reg that dies is not at top of stack, then
move the top of stack to the dead reg, as though we had
- done the insn and then a store-with-pop. */
+ done the insn and then a store-with-pop. */
if (REGNO (XEXP (src1_note, 0)) == regstack->reg[regstack->top])
{
@@ -2306,6 +2348,70 @@ subst_stack_regs_pat (insn, regstack, pat)
}
break;
+ case IF_THEN_ELSE:
+ /* dest has to be on stack. */
+ if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG)
+ abort ();
+
+ /* This insn requires the top of stack to be the destination. */
+
+ /* If the comparison operator is an FP comparison operator,
+ it is handled correctly by compare_for_stack_reg () who
+ will move the destination to the top of stack. But if the
+ comparison operator is not an FP comparison operator, we
+ have to handle it here. */
+ if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG
+ && REGNO (*dest) != regstack->reg[regstack->top])
+ emit_swap_insn (insn, regstack, *dest);
+
+ src1 = get_true_reg (&XEXP (SET_SRC (pat), 1));
+ src2 = get_true_reg (&XEXP (SET_SRC (pat), 2));
+
+ src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+ src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
+
+ {
+ rtx src_note [3];
+ int i;
+
+ src_note[0] = 0;
+ src_note[1] = src1_note;
+ src_note[2] = src2_note;
+
+ if (STACK_REG_P (*src1))
+ replace_reg (src1, get_hard_regnum (regstack, *src1));
+ if (STACK_REG_P (*src2))
+ replace_reg (src2, get_hard_regnum (regstack, *src2));
+
+ for (i = 1; i <= 2; i++)
+ if (src_note [i])
+ {
+ /* If the register that dies is not at the top of stack, then
+ move the top of stack to the dead reg */
+ if (REGNO (XEXP (src_note[i], 0))
+ != regstack->reg[regstack->top])
+ {
+ remove_regno_note (insn, REG_DEAD,
+ REGNO (XEXP (src_note [i], 0)));
+ emit_pop_insn (insn, regstack, XEXP (src_note[i], 0),
+ emit_insn_after);
+ }
+ else
+ {
+ CLEAR_HARD_REG_BIT (regstack->reg_set,
+ REGNO (XEXP (src_note[i], 0)));
+ replace_reg (&XEXP (src_note[i], 0), FIRST_STACK_REG);
+ regstack->top--;
+ }
+ }
+ }
+
+ /* Make dest the top of stack. */
+ SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+ replace_reg (dest, FIRST_STACK_REG);
+
+ break;
+
default:
abort ();
}
@@ -2359,14 +2465,14 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
/* Find out what the constraints required. If no constraint
alternative matches, that is a compiler bug: we should have caught
such an insn during the life analysis pass (and reload should have
- caught it regardless). */
+ caught it regardless). */
i = constrain_asm_operands (n_operands, operands, constraints,
operand_matches, operand_class);
if (i < 0)
abort ();
- /* Strip SUBREGs here to make the following code simpler. */
+ /* Strip SUBREGs here to make the following code simpler. */
for (i = 0; i < n_operands; i++)
if (GET_CODE (operands[i]) == SUBREG
&& GET_CODE (SUBREG_REG (operands[i])) == REG)
@@ -2452,7 +2558,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
these constraints are for single register classes, and reload
guaranteed that operand[i] is already in that class, we can
just use REGNO (operands[i]) to know which actual reg this
- operand needs to be in. */
+ operand needs to be in. */
int regno = get_hard_regnum (&temp_stack, operands[i]);
@@ -2464,7 +2570,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
/* operands[i] is not in the right place. Find it
and swap it with whatever is already in I's place.
K is where operands[i] is now. J is where it should
- be. */
+ be. */
int j, k, temp;
k = temp_stack.top - (regno - FIRST_STACK_REG);
@@ -2483,7 +2589,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
change_stack (insn, regstack, &temp_stack, emit_insn_before);
/* Make the needed input register substitutions. Do death notes and
- clobbers too, because these are for inputs, not outputs. */
+ clobbers too, because these are for inputs, not outputs. */
for (i = first_input; i < first_input + n_inputs; i++)
if (STACK_REG_P (operands[i]))
@@ -2523,13 +2629,13 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
}
}
- /* Now remove from REGSTACK any inputs that the asm implicitly popped. */
+ /* Now remove from REGSTACK any inputs that the asm implicitly popped. */
for (i = first_input; i < first_input + n_inputs; i++)
if (STACK_REG_P (operands[i]))
{
/* An input reg is implicitly popped if it is tied to an
- output, or if there is a CLOBBER for it. */
+ output, or if there is a CLOBBER for it. */
int j;
for (j = 0; j < n_clobbers; j++)
@@ -2552,7 +2658,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
/* Now add to REGSTACK any outputs that the asm implicitly pushed.
Note that there isn't any need to substitute register numbers.
- ??? Explain why this is true. */
+ ??? Explain why this is true. */
for (i = LAST_STACK_REG; i >= FIRST_STACK_REG; i--)
{
@@ -2610,7 +2716,7 @@ subst_asm_stack_regs (insn, regstack, operands, operands_loc, constraints,
/* Substitute stack hard reg numbers for stack virtual registers in
INSN. Non-stack register numbers are not changed. REGSTACK is the
current stack content. Insns may be emitted as needed to arrange the
- stack for the 387 based on the contents of the insn. */
+ stack for the 387 based on the contents of the insn. */
static void
subst_stack_regs (insn, regstack)
@@ -2647,7 +2753,7 @@ subst_stack_regs (insn, regstack)
Since we only record whether entire insn mentions stack regs, and
subst_stack_regs_pat only works for patterns that contain stack regs,
we must check each pattern in a parallel here. A call_value_pop could
- fail otherwise. */
+ fail otherwise. */
if (GET_MODE (insn) == QImode)
{
@@ -2656,7 +2762,7 @@ subst_stack_regs (insn, regstack)
{
/* This insn is an `asm' with operands. Decode the operands,
decide how many are inputs, and do register substitution.
- Any REG_UNUSED notes will be handled by subst_asm_stack_regs. */
+ Any REG_UNUSED notes will be handled by subst_asm_stack_regs. */
rtx operands[MAX_RECOG_OPERANDS];
rtx *operands_loc[MAX_RECOG_OPERANDS];
@@ -2685,7 +2791,7 @@ subst_stack_regs (insn, regstack)
}
/* subst_stack_regs_pat may have deleted a no-op insn. If so, any
- REG_UNUSED will already have been dealt with, so just return. */
+ REG_UNUSED will already have been dealt with, so just return. */
if (GET_CODE (insn) == NOTE)
return;
@@ -2693,7 +2799,7 @@ subst_stack_regs (insn, regstack)
/* If there is a REG_UNUSED note on a stack register on this insn,
the indicated reg must be popped. The REG_UNUSED note is removed,
since the form of the newly emitted pop insn references the reg,
- making it no longer `unset'. */
+ making it no longer `unset'. */
note_link = &REG_NOTES(insn);
for (note = *note_link; note; note = XEXP (note, 1))
@@ -2716,7 +2822,7 @@ subst_stack_regs (insn, regstack)
will be the same as NEW upon return.
This function will not preserve block_end[]. But that information
- is no longer needed once this has executed. */
+ is no longer needed once this has executed. */
static void
change_stack (insn, old, new, when)
@@ -2734,7 +2840,7 @@ change_stack (insn, old, new, when)
if (when == emit_insn_after)
insn = NEXT_INSN (insn);
- /* Pop any registers that are not needed in the new block. */
+ /* Pop any registers that are not needed in the new block. */
for (reg = old->top; reg >= 0; reg--)
if (! TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]))
@@ -2744,7 +2850,7 @@ change_stack (insn, old, new, when)
if (new->top == -2)
{
/* If the new block has never been processed, then it can inherit
- the old stack order. */
+ the old stack order. */
new->top = old->top;
bcopy (old->reg, new->reg, sizeof (new->reg));
@@ -2752,10 +2858,10 @@ change_stack (insn, old, new, when)
else
{
/* This block has been entered before, and we must match the
- previously selected stack order. */
+ previously selected stack order. */
/* By now, the only difference should be the order of the stack,
- not their depth or liveliness. */
+ not their depth or liveliness. */
GO_IF_HARD_REG_EQUAL (old->reg_set, new->reg_set, win);
@@ -2771,12 +2877,12 @@ change_stack (insn, old, new, when)
depth of the stack. In some cases, the reg at the top of
stack may be correct, but swapped anyway in order to fix
other regs. But since we never swap any other reg away from
- its correct slot, this algorithm will converge. */
+ its correct slot, this algorithm will converge. */
do
{
/* Swap the reg at top of stack into the position it is
- supposed to be in, until the correct top of stack appears. */
+ supposed to be in, until the correct top of stack appears. */
while (old->reg[old->top] != new->reg[new->top])
{
@@ -2793,7 +2899,7 @@ change_stack (insn, old, new, when)
/* See if any regs remain incorrect. If so, bring an
incorrect reg to the top of stack, and let the while loop
- above fix it. */
+ above fix it. */
for (reg = new->top; reg >= 0; reg--)
if (new->reg[reg] != old->reg[reg])
@@ -2804,7 +2910,7 @@ change_stack (insn, old, new, when)
}
} while (reg >= 0);
- /* At this point there must be no differences. */
+ /* At this point there must be no differences. */
for (reg = old->top; reg >= 0; reg--)
if (old->reg[reg] != new->reg[reg])
@@ -2820,7 +2926,7 @@ change_stack (insn, old, new, when)
is the order of the register stack in INSN.
Any code that is emitted here must not be later processed as part
- of any block, as it will already contain hard register numbers. */
+ of any block, as it will already contain hard register numbers. */
static void
goto_block_pat (insn, regstack, pat)
@@ -2862,7 +2968,7 @@ goto_block_pat (insn, regstack, pat)
if (GET_CODE (label) != CODE_LABEL)
abort ();
- /* First, see if in fact anything needs to be done to the stack at all. */
+ /* First, see if in fact anything needs to be done to the stack at all. */
if (INSN_UID (label) <= 0)
return;
@@ -2871,7 +2977,7 @@ goto_block_pat (insn, regstack, pat)
if (label_stack->top == -2)
{
/* If the target block hasn't had a stack order selected, then
- we need merely ensure that no pops are needed. */
+ we need merely ensure that no pops are needed. */
for (reg = regstack->top; reg >= 0; reg--)
if (! TEST_HARD_REG_BIT (label_stack->reg_set, regstack->reg[reg]))
@@ -2879,7 +2985,7 @@ goto_block_pat (insn, regstack, pat)
if (reg == -1)
{
- /* change_stack will not emit any code in this case. */
+ /* change_stack will not emit any code in this case. */
change_stack (label, regstack, label_stack, emit_insn_after);
return;
@@ -2899,7 +3005,7 @@ goto_block_pat (insn, regstack, pat)
a jump around the code we are about to emit. Emit a label for the new
code, and point the original insn at this new label. We can't use
redirect_jump here, because we're using fld[4] of the code labels as
- LABEL_REF chains, no NUSES counters. */
+ LABEL_REF chains, no NUSES counters. */
new_jump = emit_jump_insn_before (gen_jump (label), label);
record_label_references (new_jump, PATTERN (new_jump));
@@ -2912,7 +3018,7 @@ goto_block_pat (insn, regstack, pat)
LABEL_REFS (new_label) = new_label;
/* The old label_ref will no longer point to the code_label if now uses,
- so strip the label_ref from the code_label's chain of references. */
+ so strip the label_ref from the code_label's chain of references. */
for (ref = &LABEL_REFS (label); *ref != label; ref = &LABEL_NEXTREF (*ref))
if (*ref == pat)
@@ -2929,7 +3035,7 @@ goto_block_pat (insn, regstack, pat)
if (JUMP_LABEL (insn) == label)
JUMP_LABEL (insn) = new_label;
- /* Now emit the needed code. */
+ /* Now emit the needed code. */
temp_stack = *regstack;
@@ -2938,7 +3044,7 @@ goto_block_pat (insn, regstack, pat)
/* Traverse all basic blocks in a function, converting the register
references in each insn from the "flat" register file that gcc uses, to
- the stack-like registers the 387 uses. */
+ the stack-like registers the 387 uses. */
static void
convert_regs ()
@@ -2963,7 +3069,7 @@ convert_regs ()
/* Process all insns in this block. Keep track of `next' here,
so that we don't process any insns emitted while making
- substitutions in INSN. */
+ substitutions in INSN. */
next = block_begin[block];
regstack = block_stack_in[block];
@@ -2974,14 +3080,26 @@ convert_regs ()
/* Don't bother processing unless there is a stack reg
mentioned or if it's a CALL_INSN (register passing of
- floating point values). */
+ floating point values). */
if (GET_MODE (insn) == QImode || GET_CODE (insn) == CALL_INSN)
subst_stack_regs (insn, &regstack);
} while (insn != block_end[block]);
+
+ /* For all further actions, INSN needs to be the last insn in
+ this basic block. If subst_stack_regs inserted additional
+ instructions after INSN, it is no longer the last one at
+ this point. */
+ next = PREV_INSN (next);
+
+ /* If subst_stack_regs inserted something after a JUMP_INSN, that
+ is almost certainly a bug. */
+ if (GET_CODE (insn) == JUMP_INSN && insn != next)
+ abort ();
+ insn = next;
- /* Something failed if the stack life doesn't match. */
+ /* Something failed if the stack life doesn't match. */
GO_IF_HARD_REG_EQUAL (regstack.reg_set, block_out_reg_set[block], win);
@@ -2992,12 +3110,12 @@ convert_regs ()
/* Adjust the stack of this block on exit to match the stack of
the target block, or copy stack information into stack of
jump target if the target block's stack order hasn't been set
- yet. */
+ yet. */
if (GET_CODE (insn) == JUMP_INSN)
goto_block_pat (insn, &regstack, PATTERN (insn));
- /* Likewise handle the case where we fall into the next block. */
+ /* Likewise handle the case where we fall into the next block. */
if ((block < blocks - 1) && block_drops_in[block+1])
change_stack (insn, &regstack, &block_stack_in[block+1],
@@ -3006,14 +3124,14 @@ convert_regs ()
/* If the last basic block is the end of a loop, and that loop has
regs live at its start, then the last basic block will have regs live
- at its end that need to be popped before the function returns. */
+ at its end that need to be popped before the function returns. */
{
int value_reg_low, value_reg_high;
value_reg_low = value_reg_high = -1;
{
rtx retvalue;
- if (retvalue = stack_result (current_function_decl))
+ if ((retvalue = stack_result (current_function_decl)))
{
value_reg_low = REGNO (retvalue);
value_reg_high = value_reg_low +
@@ -3022,8 +3140,8 @@ convert_regs ()
}
for (reg = regstack.top; reg >= 0; reg--)
- if (regstack.reg[reg] < value_reg_low ||
- regstack.reg[reg] > value_reg_high)
+ if (regstack.reg[reg] < value_reg_low
+ || regstack.reg[reg] > value_reg_high)
insn = emit_pop_insn (insn, &regstack,
FP_MODE_REG (regstack.reg[reg], DFmode),
emit_insn_after);
@@ -3032,7 +3150,7 @@ convert_regs ()
}
/* Check expression PAT, which is in INSN, for label references. if
- one is found, print the block number of destination to FILE. */
+ one is found, print the block number of destination to FILE. */
static void
print_blocks (file, insn, pat)
@@ -3071,6 +3189,7 @@ print_blocks (file, insn, pat)
/* Write information about stack registers and stack blocks into FILE.
This is part of making a debugging dump. */
+
static void
dump_stack_info (file)
FILE *file;
diff --git a/contrib/gcc/regclass.c b/contrib/gcc/regclass.c
index 9b9a4d5..25cac8f 100644
--- a/contrib/gcc/regclass.c
+++ b/contrib/gcc/regclass.c
@@ -1,5 +1,5 @@
/* Compute register class preferences for pseudo-registers.
- Copyright (C) 1987, 88, 91, 92, 93, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA. */
and a function init_reg_sets to initialize the tables. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "hard-reg-set.h"
#include "flags.h"
@@ -33,16 +34,13 @@ Boston, MA 02111-1307, USA. */
#include "recog.h"
#include "reload.h"
#include "real.h"
-#include "bytecode.h"
+#include "toplev.h"
+#include "output.h"
#ifndef REGISTER_MOVE_COST
#define REGISTER_MOVE_COST(x, y) 2
#endif
-#ifndef MEMORY_MOVE_COST
-#define MEMORY_MOVE_COST(x) 4
-#endif
-
/* If we have auto-increment or auto-decrement and we can have secondary
reloads, we are not allowed to use classes requiring secondary
reloads for pseudos auto-incremented since reload can't handle it. */
@@ -81,6 +79,9 @@ char call_used_regs[FIRST_PSEUDO_REGISTER];
HARD_REG_SET call_used_reg_set;
+/* HARD_REG_SET of registers we want to avoid caller saving. */
+HARD_REG_SET losing_caller_save_reg_set;
+
/* Data for initializing the above. */
static char initial_call_used_regs[] = CALL_USED_REGISTERS;
@@ -160,15 +161,6 @@ char *reg_names[] = REGISTER_NAMES;
enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
-/* Indexed by n, gives number of times (REG n) is set or clobbered.
- This information remains valid for the rest of the compilation
- of the current function; it is used to control register allocation.
-
- This information applies to both hard registers and pseudo registers,
- unlike much of the information above. */
-
-short *reg_n_sets;
-
/* Maximum cost of moving from a register in one class to a register in
another class. Based on REGISTER_MOVE_COST. */
@@ -193,6 +185,29 @@ static char *in_inc_dec;
#endif /* FORBIDDEN_INC_DEC_CLASSES */
+#ifdef HAVE_SECONDARY_RELOADS
+
+/* Sample MEM values for use by memory_move_secondary_cost. */
+
+static rtx top_of_stack[MAX_MACHINE_MODE];
+
+#endif /* HAVE_SECONDARY_RELOADS */
+
+/* Linked list of reg_info structures allocated for reg_n_info array.
+ Grouping all of the allocated structures together in one lump
+ means only one call to bzero to clear them, rather than n smaller
+ calls. */
+struct reg_info_data {
+ struct reg_info_data *next; /* next set of reg_info structures */
+ size_t min_index; /* minimum index # */
+ size_t max_index; /* maximum index # */
+ char used_p; /* non-zero if this has been used previously */
+ reg_info data[1]; /* beginning of the reg_info data */
+};
+
+static struct reg_info_data *reg_info_head;
+
+
/* Function called only once to initialize the above data on reg usage.
Once this is done, various switches may override. */
@@ -321,37 +336,8 @@ init_reg_sets ()
}
}
- /* Initialize the move cost table. Find every subset of each class
- and take the maximum cost of moving any subset to any other. */
-
- for (i = 0; i < N_REG_CLASSES; i++)
- for (j = 0; j < N_REG_CLASSES; j++)
- {
- int cost = i == j ? 2 : REGISTER_MOVE_COST (i, j);
- enum reg_class *p1, *p2;
-
- for (p2 = &reg_class_subclasses[j][0]; *p2 != LIM_REG_CLASSES; p2++)
- if (*p2 != i)
- cost = MAX (cost, REGISTER_MOVE_COST (i, *p2));
-
- for (p1 = &reg_class_subclasses[i][0]; *p1 != LIM_REG_CLASSES; p1++)
- {
- if (*p1 != j)
- cost = MAX (cost, REGISTER_MOVE_COST (*p1, j));
-
- for (p2 = &reg_class_subclasses[j][0];
- *p2 != LIM_REG_CLASSES; p2++)
- if (*p1 != *p2)
- cost = MAX (cost, REGISTER_MOVE_COST (*p1, *p2));
- }
-
- move_cost[i][j] = cost;
-
- if (reg_class_subset_p (i, j))
- cost = 0;
-
- may_move_cost[i][j] = cost;
- }
+ /* Do any additional initialization regsets may need */
+ INIT_ONCE_REG_SET ();
}
/* After switches have been processed, which perhaps alter
@@ -360,7 +346,7 @@ init_reg_sets ()
static void
init_reg_sets_1 ()
{
- register int i;
+ register unsigned int i, j;
/* This macro allows the fixed or call-used registers
to depend on target flags. */
@@ -390,7 +376,41 @@ init_reg_sets_1 ()
SET_HARD_REG_BIT (call_used_reg_set, i);
if (call_fixed_regs[i])
SET_HARD_REG_BIT (call_fixed_reg_set, i);
+ if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (i)))
+ SET_HARD_REG_BIT (losing_caller_save_reg_set, i);
}
+
+ /* Initialize the move cost table. Find every subset of each class
+ and take the maximum cost of moving any subset to any other. */
+
+ for (i = 0; i < N_REG_CLASSES; i++)
+ for (j = 0; j < N_REG_CLASSES; j++)
+ {
+ int cost = i == j ? 2 : REGISTER_MOVE_COST (i, j);
+ enum reg_class *p1, *p2;
+
+ for (p2 = &reg_class_subclasses[j][0]; *p2 != LIM_REG_CLASSES; p2++)
+ if (*p2 != i)
+ cost = MAX (cost, REGISTER_MOVE_COST (i, *p2));
+
+ for (p1 = &reg_class_subclasses[i][0]; *p1 != LIM_REG_CLASSES; p1++)
+ {
+ if (*p1 != j)
+ cost = MAX (cost, REGISTER_MOVE_COST (*p1, j));
+
+ for (p2 = &reg_class_subclasses[j][0];
+ *p2 != LIM_REG_CLASSES; p2++)
+ if (*p1 != *p2)
+ cost = MAX (cost, REGISTER_MOVE_COST (*p1, *p2));
+ }
+
+ move_cost[i][j] = cost;
+
+ if (reg_class_subset_p (i, j))
+ cost = 0;
+
+ may_move_cost[i][j] = cost;
+ }
}
/* Compute the table of register modes.
@@ -406,14 +426,13 @@ init_reg_modes ()
{
reg_raw_mode[i] = choose_hard_reg_mode (i, 1);
- /* If we couldn't find a valid mode, fall back to `word_mode'.
- ??? We assume `word_mode' has already been initialized.
+ /* If we couldn't find a valid mode, just use the previous mode.
??? One situation in which we need to do this is on the mips where
HARD_REGNO_NREGS (fpreg, [SD]Fmode) returns 2. Ideally we'd like
to use DF mode for the even registers and VOIDmode for the odd
(for the cpu models where the odd ones are inaccessible). */
if (reg_raw_mode[i] == VOIDmode)
- reg_raw_mode[i] = word_mode;
+ reg_raw_mode[i] = i == 0 ? word_mode : reg_raw_mode[i-1];
}
}
@@ -425,12 +444,78 @@ init_regs ()
{
/* This finishes what was started by init_reg_sets, but couldn't be done
until after register usage was specified. */
- if (!output_bytecode)
- init_reg_sets_1 ();
+ init_reg_sets_1 ();
init_reg_modes ();
+
+#ifdef HAVE_SECONDARY_RELOADS
+ {
+ /* Make some fake stack-frame MEM references for use in
+ memory_move_secondary_cost. */
+ int i;
+ for (i = 0; i < MAX_MACHINE_MODE; i++)
+ top_of_stack[i] = gen_rtx_MEM (i, stack_pointer_rtx);
+ }
+#endif
}
+#ifdef HAVE_SECONDARY_RELOADS
+
+/* Compute extra cost of moving registers to/from memory due to reloads.
+ Only needed if secondary reloads are required for memory moves. */
+
+int
+memory_move_secondary_cost (mode, class, in)
+ enum machine_mode mode;
+ enum reg_class class;
+ int in;
+{
+ enum reg_class altclass;
+ int partial_cost = 0;
+ /* We need a memory reference to feed to SECONDARY... macros. */
+ rtx mem = top_of_stack[(int) mode];
+
+ if (in)
+ {
+#ifdef SECONDARY_INPUT_RELOAD_CLASS
+ altclass = SECONDARY_INPUT_RELOAD_CLASS (class, mode, mem);
+#else
+ altclass = NO_REGS;
+#endif
+ }
+ else
+ {
+#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
+ altclass = SECONDARY_OUTPUT_RELOAD_CLASS (class, mode, mem);
+#else
+ altclass = NO_REGS;
+#endif
+ }
+
+ if (altclass == NO_REGS)
+ return 0;
+
+ if (in)
+ partial_cost = REGISTER_MOVE_COST (altclass, class);
+ else
+ partial_cost = REGISTER_MOVE_COST (class, altclass);
+
+ if (class == altclass)
+ /* This isn't simply a copy-to-temporary situation. Can't guess
+ what it is, so MEMORY_MOVE_COST really ought not to be calling
+ here in that case.
+
+ I'm tempted to put in an abort here, but returning this will
+ probably only give poor estimates, which is what we would've
+ had before this code anyways. */
+ return partial_cost;
+
+ /* Check if the secondary reload register will also need a
+ secondary reload. */
+ return memory_move_secondary_cost (mode, altclass, in) + partial_cost;
+}
+#endif
+
/* Return a machine mode that is legitimate for hard reg REGNO and large
enough to save nregs. If we can't find one, return VOIDmode. */
@@ -484,13 +569,6 @@ fix_register (name, fixed, call_used)
{
int i;
- if (output_bytecode)
- {
- warning ("request to mark `%s' as %s ignored by bytecode compiler",
- name, call_used ? "call-used" : "fixed");
- return;
- }
-
/* Decode the name and update the primary form of
the register info. */
@@ -574,6 +652,10 @@ static char *prefclass;
static char *altclass;
+/* Allocated buffers for prefclass and altclass. */
+static char *prefclass_buffer;
+static char *altclass_buffer;
+
/* Record the depth of loops that we are in. */
static int loop_depth;
@@ -588,8 +670,10 @@ static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *,
static int copy_cost PROTO((rtx, enum machine_mode,
enum reg_class, int));
static void record_address_regs PROTO((rtx, enum reg_class, int));
-static auto_inc_dec_reg_p PROTO((rtx, enum machine_mode));
-static void reg_scan_mark_refs PROTO((rtx, rtx, int));
+#ifdef FORBIDDEN_INC_DEC_CLASSES
+static int auto_inc_dec_reg_p PROTO((rtx, enum machine_mode));
+#endif
+static void reg_scan_mark_refs PROTO((rtx, rtx, int, int));
/* Return the reg_class in which pseudo reg number REGNO is best allocated.
This function is sometimes called before the info has been computed.
@@ -606,6 +690,7 @@ reg_preferred_class (regno)
enum reg_class
reg_alternate_class (regno)
+ int regno;
{
if (prefclass == 0)
return ALL_REGS;
@@ -654,7 +739,7 @@ regclass (f, nregs)
for (i = 0; i < N_REG_CLASSES; i++)
{
- rtx r = gen_rtx (REG, VOIDmode, 0);
+ rtx r = gen_rtx_REG (VOIDmode, 0);
enum machine_mode m;
for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
@@ -674,6 +759,10 @@ regclass (f, nregs)
being used in such addresses. */
if ((0
+#ifdef SECONDARY_RELOAD_CLASS
+ || (SECONDARY_RELOAD_CLASS (BASE_REG_CLASS, m, r)
+ != NO_REGS)
+#else
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
!= NO_REGS)
@@ -682,6 +771,7 @@ regclass (f, nregs)
|| (SECONDARY_OUTPUT_RELOAD_CLASS (BASE_REG_CLASS, m, r)
!= NO_REGS)
#endif
+#endif
)
&& ! auto_inc_dec_reg_p (r, m))
forbidden_inc_dec_class[i] = 1;
@@ -772,7 +862,8 @@ regclass (f, nregs)
&& GET_CODE (XEXP (note, 0)) == MEM)
{
costs[REGNO (SET_DEST (set))].mem_cost
- -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)))
+ -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)),
+ GENERAL_REGS, 1)
* loop_cost);
record_address_regs (XEXP (SET_SRC (set), 0),
BASE_REG_CLASS, loop_cost * 2);
@@ -824,8 +915,8 @@ regclass (f, nregs)
basic_block_head[b] = newinsn;
}
- /* This makes one more setting of new insns's dest. */
- reg_n_sets[REGNO (recog_operand[0])]++;
+ /* This makes one more setting of new insns's dest. */
+ REG_N_SETS (REGNO (recog_operand[0]))++;
*recog_operand_loc[1] = recog_operand[0];
for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)
@@ -915,8 +1006,8 @@ regclass (f, nregs)
if (pass == 0)
{
- prefclass = (char *) oballoc (nregs);
- altclass = (char *) oballoc (nregs);
+ prefclass = prefclass_buffer;
+ altclass = altclass_buffer;
}
for (i = FIRST_PSEUDO_REGISTER; i < nregs; i++)
@@ -968,7 +1059,7 @@ regclass (f, nregs)
/* If we don't add any classes, nothing to try. */
if (alt == best)
- alt = (int) NO_REGS;
+ alt = NO_REGS;
/* We cast to (int) because (char) hits bugs in some compilers. */
prefclass[i] = (int) best;
@@ -1142,8 +1233,10 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
p++;
break;
+ case '?':
+ alt_cost += 2;
case '%':
- case '?': case '!': case '#':
+ case '!': case '#':
case '&':
case '0': case '1': case '2': case '3': case '4':
case 'p':
@@ -1289,7 +1382,8 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
a bit cheaper since we won't need an extra insn to
load it. */
- pp->mem_cost = MEMORY_MOVE_COST (mode) - allows_mem;
+ pp->mem_cost = (MEMORY_MOVE_COST (mode, classes[i], 1)
+ - allows_mem);
/* If we have assigned a class to this register in our
first pass, add a cost to this alternative corresponding
@@ -1327,7 +1421,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
constant that could be placed into memory. */
else if (CONSTANT_P (op) && allows_mem)
- alt_cost += MEMORY_MOVE_COST (mode);
+ alt_cost += MEMORY_MOVE_COST (mode, classes[i], 1);
else
alt_fail = 1;
}
@@ -1407,7 +1501,9 @@ copy_cost (x, mode, class, to_p)
enum reg_class class;
int to_p;
{
+#ifdef HAVE_SECONDARY_RELOADS
enum reg_class secondary_class = NO_REGS;
+#endif
/* If X is a SCRATCH, there is actually nothing to move since we are
assuming optimal allocation. */
@@ -1444,7 +1540,7 @@ copy_cost (x, mode, class, to_p)
else (constants). */
if (GET_CODE (x) == MEM || class == NO_REGS)
- return MEMORY_MOVE_COST (mode);
+ return MEMORY_MOVE_COST (mode, class, to_p);
else if (GET_CODE (x) == REG)
return move_cost[(int) REGNO_REG_CLASS (REGNO (x))][(int) class];
@@ -1536,38 +1632,54 @@ record_address_regs (x, class, scale)
else if (code1 == SYMBOL_REF || code1 == CONST || code1 == LABEL_REF)
record_address_regs (arg0, INDEX_REG_CLASS, scale);
- /* If this the sum of two registers where the first is known to be a
- pointer, it must be a base register with the second an index. */
+ /* If both operands are registers but one is already a hard register
+ of index or base class, give the other the class that the hard
+ register is not. */
+#ifdef REG_OK_FOR_BASE_P
else if (code0 == REG && code1 == REG
- && REGNO_POINTER_FLAG (REGNO (arg0)))
+ && REGNO (arg0) < FIRST_PSEUDO_REGISTER
+ && (REG_OK_FOR_BASE_P (arg0) || REG_OK_FOR_INDEX_P (arg0)))
+ record_address_regs (arg1,
+ REG_OK_FOR_BASE_P (arg0)
+ ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ scale);
+ else if (code0 == REG && code1 == REG
+ && REGNO (arg1) < FIRST_PSEUDO_REGISTER
+ && (REG_OK_FOR_BASE_P (arg1) || REG_OK_FOR_INDEX_P (arg1)))
+ record_address_regs (arg0,
+ REG_OK_FOR_BASE_P (arg1)
+ ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ scale);
+#endif
+
+ /* If one operand is known to be a pointer, it must be the base
+ with the other operand the index. Likewise if the other operand
+ is a MULT. */
+
+ else if ((code0 == REG && REGNO_POINTER_FLAG (REGNO (arg0)))
+ || code1 == MULT)
{
record_address_regs (arg0, BASE_REG_CLASS, scale);
record_address_regs (arg1, INDEX_REG_CLASS, scale);
}
+ else if ((code1 == REG && REGNO_POINTER_FLAG (REGNO (arg1)))
+ || code0 == MULT)
+ {
+ record_address_regs (arg0, INDEX_REG_CLASS, scale);
+ record_address_regs (arg1, BASE_REG_CLASS, scale);
+ }
- /* If this is the sum of two registers and neither is known to
- be a pointer, count equal chances that each might be a base
+ /* Otherwise, count equal chances that each might be a base
or index register. This case should be rare. */
- else if (code0 == REG && code1 == REG
- && ! REGNO_POINTER_FLAG (REGNO (arg0))
- && ! REGNO_POINTER_FLAG (REGNO (arg1)))
+ else
{
record_address_regs (arg0, BASE_REG_CLASS, scale / 2);
record_address_regs (arg0, INDEX_REG_CLASS, scale / 2);
record_address_regs (arg1, BASE_REG_CLASS, scale / 2);
record_address_regs (arg1, INDEX_REG_CLASS, scale / 2);
}
-
- /* In all other cases, the first operand is an index and the
- second is the base. */
-
- else
- {
- record_address_regs (arg0, INDEX_REG_CLASS, scale);
- record_address_regs (arg1, BASE_REG_CLASS, scale);
- }
}
break;
@@ -1594,7 +1706,7 @@ record_address_regs (x, class, scale)
register struct costs *pp = &costs[REGNO (x)];
register int i;
- pp->mem_cost += (MEMORY_MOVE_COST (Pmode) * scale) / 2;
+ pp->mem_cost += (MEMORY_MOVE_COST (Pmode, class, 1) * scale) / 2;
for (i = 0; i < N_REG_CLASSES; i++)
pp->cost[i] += (may_move_cost[i][(int) class] * scale) / 2;
@@ -1617,28 +1729,28 @@ record_address_regs (x, class, scale)
/* Return 1 if REG is valid as an auto-increment memory reference
to an object of MODE. */
-static
+static int
auto_inc_dec_reg_p (reg, mode)
rtx reg;
enum machine_mode mode;
{
#ifdef HAVE_POST_INCREMENT
- if (memory_address_p (mode, gen_rtx (POST_INC, Pmode, reg)))
+ if (memory_address_p (mode, gen_rtx_POST_INC (Pmode, reg)))
return 1;
#endif
#ifdef HAVE_POST_DECREMENT
- if (memory_address_p (mode, gen_rtx (POST_DEC, Pmode, reg)))
+ if (memory_address_p (mode, gen_rtx_POST_DEC (Pmode, reg)))
return 1;
#endif
#ifdef HAVE_PRE_INCREMENT
- if (memory_address_p (mode, gen_rtx (PRE_INC, Pmode, reg)))
+ if (memory_address_p (mode, gen_rtx_PRE_INC (Pmode, reg)))
return 1;
#endif
#ifdef HAVE_PRE_DECREMENT
- if (memory_address_p (mode, gen_rtx (PRE_DEC, Pmode, reg)))
+ if (memory_address_p (mode, gen_rtx_PRE_DEC (Pmode, reg)))
return 1;
#endif
@@ -1648,35 +1760,160 @@ auto_inc_dec_reg_p (reg, mode)
#endif /* REGISTER_CONSTRAINTS */
-/* This is the `regscan' pass of the compiler, run just before cse
- and again just before loop.
+/* Allocate enough space to hold NUM_REGS registers for the tables used for
+ reg_scan and flow_analysis that are indexed by the register number. If
+ NEW_P is non zero, initialize all of the registers, otherwise only
+ initialize the new registers allocated. The same table is kept from
+ function to function, only reallocating it when we need more room. If
+ RENUMBER_P is non zero, allocate the reg_renumber array also. */
- It finds the first and last use of each pseudo-register
- and records them in the vectors regno_first_uid, regno_last_uid
- and counts the number of sets in the vector reg_n_sets.
+void
+allocate_reg_info (num_regs, new_p, renumber_p)
+ size_t num_regs;
+ int new_p;
+ int renumber_p;
+{
+ static size_t regno_allocated = 0;
+ static short *renumber = (short *)0;
+ int i;
+ size_t size_info;
+ size_t size_renumber;
+ size_t min = (new_p) ? 0 : reg_n_max;
+ struct reg_info_data *reg_data;
+ struct reg_info_data *reg_next;
+
+ /* Free up all storage allocated */
+ if (num_regs < 0)
+ {
+ if (reg_n_info)
+ {
+ VARRAY_FREE (reg_n_info);
+ for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
+ {
+ reg_next = reg_data->next;
+ free ((char *)reg_data);
+ }
- REPEAT is nonzero the second time this is called. */
+ free (prefclass_buffer);
+ free (altclass_buffer);
+ prefclass_buffer = (char *)0;
+ altclass_buffer = (char *)0;
+ reg_info_head = (struct reg_info_data *)0;
+ renumber = (short *)0;
+ }
+ regno_allocated = 0;
+ reg_n_max = 0;
+ return;
+ }
-/* Indexed by pseudo register number, gives uid of first insn using the reg
- (as of the time reg_scan is called). */
+ if (num_regs > regno_allocated)
+ {
+ size_t old_allocated = regno_allocated;
-int *regno_first_uid;
+ regno_allocated = num_regs + (num_regs / 20); /* add some slop space */
+ size_renumber = regno_allocated * sizeof (short);
-/* Indexed by pseudo register number, gives uid of last insn using the reg
- (as of the time reg_scan is called). */
+ if (!reg_n_info)
+ {
+ VARRAY_REG_INIT (reg_n_info, regno_allocated, "reg_n_info");
+ renumber = (short *) xmalloc (size_renumber);
+ prefclass_buffer = (char *) xmalloc (regno_allocated);
+ altclass_buffer = (char *) xmalloc (regno_allocated);
+ }
-int *regno_last_uid;
+ else
+ {
+ VARRAY_GROW (reg_n_info, regno_allocated);
+
+ if (new_p) /* if we're zapping everything, no need to realloc */
+ {
+ free ((char *)renumber);
+ free ((char *)prefclass_buffer);
+ free ((char *)altclass_buffer);
+ renumber = (short *) xmalloc (size_renumber);
+ prefclass_buffer = (char *) xmalloc (regno_allocated);
+ altclass_buffer = (char *) xmalloc (regno_allocated);
+ }
+
+ else
+ {
+ renumber = (short *) xrealloc ((char *)renumber, size_renumber);
+ prefclass_buffer = (char *) xrealloc ((char *)prefclass_buffer,
+ regno_allocated);
-/* Indexed by pseudo register number, gives uid of last insn using the reg
- or mentioning it in a note (as of the time reg_scan is called). */
+ altclass_buffer = (char *) xrealloc ((char *)altclass_buffer,
+ regno_allocated);
+ }
+ }
-int *regno_last_note_uid;
+ size_info = (regno_allocated - old_allocated) * sizeof (reg_info)
+ + sizeof (struct reg_info_data) - sizeof (reg_info);
+ reg_data = (struct reg_info_data *) xcalloc (size_info, 1);
+ reg_data->min_index = old_allocated;
+ reg_data->max_index = regno_allocated - 1;
+ reg_data->next = reg_info_head;
+ reg_info_head = reg_data;
+ }
-/* Record the number of registers we used when we allocated the above two
- tables. If we are called again with more than this, we must re-allocate
- the tables. */
+ reg_n_max = num_regs;
+ if (min < num_regs)
+ {
+ /* Loop through each of the segments allocated for the actual
+ reg_info pages, and set up the pointers, zero the pages, etc. */
+ for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
+ {
+ size_t min_index = reg_data->min_index;
+ size_t max_index = reg_data->max_index;
-static int highest_regno_in_uid_map;
+ reg_next = reg_data->next;
+ if (min <= max_index)
+ {
+ size_t max = max_index;
+ size_t local_min = min - min_index;
+ if (min < min_index)
+ local_min = 0;
+ if (!reg_data->used_p) /* page just allocated with calloc */
+ reg_data->used_p = 1; /* no need to zero */
+ else
+ bzero ((char *) &reg_data->data[local_min],
+ sizeof (reg_info) * (max - min_index - local_min + 1));
+
+ for (i = min_index+local_min; i <= max; i++)
+ {
+ VARRAY_REG (reg_n_info, i) = &reg_data->data[i-min_index];
+ REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
+ renumber[i] = -1;
+ prefclass_buffer[i] = (char) NO_REGS;
+ altclass_buffer[i] = (char) NO_REGS;
+ }
+ }
+ }
+ }
+
+ /* If {pref,alt}class have already been allocated, update the pointers to
+ the newly realloced ones. */
+ if (prefclass)
+ {
+ prefclass = prefclass_buffer;
+ altclass = altclass_buffer;
+ }
+
+ if (renumber_p)
+ reg_renumber = renumber;
+
+ /* Tell the regset code about the new number of registers */
+ MAX_REGNO_REG_SET (num_regs, new_p, renumber_p);
+}
+
+
+/* This is the `regscan' pass of the compiler, run just before cse
+ and again just before loop.
+
+ It finds the first and last use of each pseudo-register
+ and records them in the vectors regno_first_uid, regno_last_uid
+ and counts the number of sets in the vector reg_n_sets.
+
+ REPEAT is nonzero the second time this is called. */
/* Maximum number of parallel sets and clobbers in any insn in this fn.
Always at least 3, since the combiner could put that many together
@@ -1692,26 +1929,7 @@ reg_scan (f, nregs, repeat)
{
register rtx insn;
- if (!repeat || nregs > highest_regno_in_uid_map)
- {
- /* Leave some spare space in case more regs are allocated. */
- highest_regno_in_uid_map = nregs + nregs / 20;
- regno_first_uid
- = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
- regno_last_uid
- = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
- regno_last_note_uid
- = (int *) oballoc (highest_regno_in_uid_map * sizeof (int));
- reg_n_sets
- = (short *) oballoc (highest_regno_in_uid_map * sizeof (short));
- }
-
- bzero ((char *) regno_first_uid, highest_regno_in_uid_map * sizeof (int));
- bzero ((char *) regno_last_uid, highest_regno_in_uid_map * sizeof (int));
- bzero ((char *) regno_last_note_uid,
- highest_regno_in_uid_map * sizeof (int));
- bzero ((char *) reg_n_sets, highest_regno_in_uid_map * sizeof (short));
-
+ allocate_reg_info (nregs, TRUE, FALSE);
max_parallel = 3;
for (insn = f; insn; insn = NEXT_INSN (insn))
@@ -1722,26 +1940,67 @@ reg_scan (f, nregs, repeat)
if (GET_CODE (PATTERN (insn)) == PARALLEL
&& XVECLEN (PATTERN (insn), 0) > max_parallel)
max_parallel = XVECLEN (PATTERN (insn), 0);
- reg_scan_mark_refs (PATTERN (insn), insn, 0);
+ reg_scan_mark_refs (PATTERN (insn), insn, 0, 0);
if (REG_NOTES (insn))
- reg_scan_mark_refs (REG_NOTES (insn), insn, 1);
+ reg_scan_mark_refs (REG_NOTES (insn), insn, 1, 0);
+ }
+}
+
+/* Update 'regscan' information by looking at the insns
+ from FIRST to LAST. Some new REGs have been created,
+ and any REG with number greater than OLD_MAX_REGNO is
+ such a REG. We only update information for those. */
+
+void
+reg_scan_update(first, last, old_max_regno)
+ rtx first;
+ rtx last;
+ int old_max_regno;
+{
+ register rtx insn;
+
+ allocate_reg_info (max_reg_num (), FALSE, FALSE);
+
+ for (insn = first; insn != last; insn = NEXT_INSN (insn))
+ if (GET_CODE (insn) == INSN
+ || GET_CODE (insn) == CALL_INSN
+ || GET_CODE (insn) == JUMP_INSN)
+ {
+ if (GET_CODE (PATTERN (insn)) == PARALLEL
+ && XVECLEN (PATTERN (insn), 0) > max_parallel)
+ max_parallel = XVECLEN (PATTERN (insn), 0);
+ reg_scan_mark_refs (PATTERN (insn), insn, 0, old_max_regno);
+
+ if (REG_NOTES (insn))
+ reg_scan_mark_refs (REG_NOTES (insn), insn, 1, old_max_regno);
}
}
/* X is the expression to scan. INSN is the insn it appears in.
- NOTE_FLAG is nonzero if X is from INSN's notes rather than its body. */
+ NOTE_FLAG is nonzero if X is from INSN's notes rather than its body.
+ We should only record information for REGs with numbers
+ greater than or equal to MIN_REGNO. */
static void
-reg_scan_mark_refs (x, insn, note_flag)
+reg_scan_mark_refs (x, insn, note_flag, min_regno)
rtx x;
rtx insn;
int note_flag;
+ int min_regno;
{
- register enum rtx_code code = GET_CODE (x);
+ register enum rtx_code code;
register rtx dest;
register rtx note;
+ /* This can happen when scanning insns referenced by certain notes.
+
+ It is unclear if we should be scanning such insns; until someone can
+ say for sure this seems like the safest fix. */
+ if (x == NULL_RTX)
+ return;
+
+ code = GET_CODE (x);
switch (code)
{
case CONST_INT:
@@ -1759,24 +2018,27 @@ reg_scan_mark_refs (x, insn, note_flag)
{
register int regno = REGNO (x);
- regno_last_note_uid[regno] = INSN_UID (insn);
- if (!note_flag)
- regno_last_uid[regno] = INSN_UID (insn);
- if (regno_first_uid[regno] == 0)
- regno_first_uid[regno] = INSN_UID (insn);
+ if (regno >= min_regno)
+ {
+ REGNO_LAST_NOTE_UID (regno) = INSN_UID (insn);
+ if (!note_flag)
+ REGNO_LAST_UID (regno) = INSN_UID (insn);
+ if (REGNO_FIRST_UID (regno) == 0)
+ REGNO_FIRST_UID (regno) = INSN_UID (insn);
+ }
}
break;
case EXPR_LIST:
if (XEXP (x, 0))
- reg_scan_mark_refs (XEXP (x, 0), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, 0), insn, note_flag, min_regno);
if (XEXP (x, 1))
- reg_scan_mark_refs (XEXP (x, 1), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
break;
case INSN_LIST:
if (XEXP (x, 1))
- reg_scan_mark_refs (XEXP (x, 1), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, 1), insn, note_flag, min_regno);
break;
case SET:
@@ -1787,8 +2049,9 @@ reg_scan_mark_refs (x, insn, note_flag)
dest = XEXP (dest, 0))
;
- if (GET_CODE (dest) == REG)
- reg_n_sets[REGNO (dest)]++;
+ if (GET_CODE (dest) == REG
+ && REGNO (dest) >= min_regno)
+ REG_N_SETS (REGNO (dest))++;
/* If this is setting a pseudo from another pseudo or the sum of a
pseudo and a constant integer and the other pseudo is known to be
@@ -1804,6 +2067,13 @@ reg_scan_mark_refs (x, insn, note_flag)
if (GET_CODE (SET_DEST (x)) == REG
&& REGNO (SET_DEST (x)) >= FIRST_PSEUDO_REGISTER
+ && REGNO (SET_DEST (x)) >= min_regno
+ /* If the destination pseudo is set more than once, then other
+ sets might not be to a pointer value (consider access to a
+ union in two threads of control in the presense of global
+ optimizations). So only set REGNO_POINTER_FLAG on the destination
+ pseudo if this is the only set of that pseudo. */
+ && REG_N_SETS (REGNO (SET_DEST (x))) == 1
&& ! REG_USERVAR_P (SET_DEST (x))
&& ! REGNO_POINTER_FLAG (REGNO (SET_DEST (x)))
&& ((GET_CODE (SET_SRC (x)) == REG
@@ -1831,7 +2101,7 @@ reg_scan_mark_refs (x, insn, note_flag)
|| GET_CODE (XEXP (note, 0)) == LABEL_REF))))
REGNO_POINTER_FLAG (REGNO (SET_DEST (x))) = 1;
- /* ... fall through ... */
+ /* ... fall through ... */
default:
{
@@ -1840,12 +2110,12 @@ reg_scan_mark_refs (x, insn, note_flag)
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
- reg_scan_mark_refs (XEXP (x, i), insn, note_flag);
+ reg_scan_mark_refs (XEXP (x, i), insn, note_flag, min_regno);
else if (fmt[i] == 'E' && XVEC (x, i) != 0)
{
register int j;
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag);
+ reg_scan_mark_refs (XVECEXP (x, i, j), insn, note_flag, min_regno);
}
}
}
@@ -1898,3 +2168,17 @@ reg_classes_intersect_p (c1, c2)
return 0;
}
+/* Release any memory allocated by register sets. */
+
+void
+regset_release_memory ()
+{
+ if (basic_block_live_at_start)
+ {
+ free_regset_vector (basic_block_live_at_start, n_basic_blocks);
+ basic_block_live_at_start = 0;
+ }
+
+ FREE_REG_SET (regs_live_at_setjmp);
+ bitmap_release_memory ();
+}
diff --git a/contrib/gcc/regmove.c b/contrib/gcc/regmove.c
new file mode 100644
index 0000000..605169a
--- /dev/null
+++ b/contrib/gcc/regmove.c
@@ -0,0 +1,1983 @@
+/* Move registers around to reduce number of move instructions needed.
+ Copyright (C) 1987, 88, 89, 92-98, 1999 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+/* This module looks for cases where matching constraints would force
+ an instruction to need a reload, and this reload would be a register
+ to register move. It then attempts to change the registers used by the
+ instruction to avoid the move instruction. */
+
+#include "config.h"
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+/* stdio.h must precede rtl.h for FFS. */
+#include "system.h"
+
+#include "rtl.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "output.h"
+#include "reload.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "flags.h"
+#include "expr.h"
+#include "insn-flags.h"
+#include "basic-block.h"
+#include "toplev.h"
+
+static int optimize_reg_copy_1 PROTO((rtx, rtx, rtx));
+static void optimize_reg_copy_2 PROTO((rtx, rtx, rtx));
+static void optimize_reg_copy_3 PROTO((rtx, rtx, rtx));
+static rtx gen_add3_insn PROTO((rtx, rtx, rtx));
+static void copy_src_to_dest PROTO((rtx, rtx, rtx, int));
+static int *regmove_bb_head;
+
+struct match {
+ int with[MAX_RECOG_OPERANDS];
+ enum { READ, WRITE, READWRITE } use[MAX_RECOG_OPERANDS];
+ int commutative[MAX_RECOG_OPERANDS];
+ int early_clobber[MAX_RECOG_OPERANDS];
+};
+
+#ifdef AUTO_INC_DEC
+static int try_auto_increment PROTO((rtx, rtx, rtx, rtx, HOST_WIDE_INT, int));
+#endif
+static int find_matches PROTO((rtx, struct match *));
+static int fixup_match_1 PROTO((rtx, rtx, rtx, rtx, rtx, int, int, int, FILE *))
+;
+static int reg_is_remote_constant_p PROTO((rtx, rtx, rtx));
+static int stable_but_for_p PROTO((rtx, rtx, rtx));
+static int loop_depth;
+
+/* Generate and return an insn body to add r1 and c,
+ storing the result in r0. */
+static rtx
+gen_add3_insn (r0, r1, c)
+ rtx r0, r1, c;
+{
+ int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
+
+ if (icode == CODE_FOR_nothing
+ || ! (*insn_operand_predicate[icode][0]) (r0, insn_operand_mode[icode][0])
+ || ! (*insn_operand_predicate[icode][1]) (r1, insn_operand_mode[icode][1])
+ || ! (*insn_operand_predicate[icode][2]) (c, insn_operand_mode[icode][2]))
+ return NULL_RTX;
+
+ return (GEN_FCN (icode) (r0, r1, c));
+}
+
+#ifdef AUTO_INC_DEC
+
+/* INC_INSN is an instruction that adds INCREMENT to REG.
+ Try to fold INC_INSN as a post/pre in/decrement into INSN.
+ Iff INC_INSN_SET is nonzero, inc_insn has a destination different from src.
+ Return nonzero for success. */
+static int
+try_auto_increment (insn, inc_insn, inc_insn_set, reg, increment, pre)
+ rtx reg, insn, inc_insn ,inc_insn_set;
+ HOST_WIDE_INT increment;
+ int pre;
+{
+ enum rtx_code inc_code;
+
+ rtx pset = single_set (insn);
+ if (pset)
+ {
+ /* Can't use the size of SET_SRC, we might have something like
+ (sign_extend:SI (mem:QI ... */
+ rtx use = find_use_as_address (pset, reg, 0);
+ if (use != 0 && use != (rtx) 1)
+ {
+ int size = GET_MODE_SIZE (GET_MODE (use));
+ if (0
+#ifdef HAVE_POST_INCREMENT
+ || (pre == 0 && (inc_code = POST_INC, increment == size))
+#endif
+#ifdef HAVE_PRE_INCREMENT
+ || (pre == 1 && (inc_code = PRE_INC, increment == size))
+#endif
+#ifdef HAVE_POST_DECREMENT
+ || (pre == 0 && (inc_code = POST_DEC, increment == -size))
+#endif
+#ifdef HAVE_PRE_DECREMENT
+ || (pre == 1 && (inc_code = PRE_DEC, increment == -size))
+#endif
+ )
+ {
+ if (inc_insn_set)
+ validate_change
+ (inc_insn,
+ &SET_SRC (inc_insn_set),
+ XEXP (SET_SRC (inc_insn_set), 0), 1);
+ validate_change (insn, &XEXP (use, 0),
+ gen_rtx_fmt_e (inc_code, Pmode, reg), 1);
+ if (apply_change_group ())
+ {
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_INC,
+ reg, REG_NOTES (insn));
+ if (! inc_insn_set)
+ {
+ PUT_CODE (inc_insn, NOTE);
+ NOTE_LINE_NUMBER (inc_insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (inc_insn) = 0;
+ }
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+#endif /* AUTO_INC_DEC */
+
+static int *regno_src_regno;
+
+/* Indicate how good a choice REG (which appears as a source) is to replace
+ a destination register with. The higher the returned value, the better
+ the choice. The main objective is to avoid using a register that is
+ a candidate for tying to a hard register, since the output might in
+ turn be a candidate to be tied to a different hard register. */
+int
+replacement_quality(reg)
+ rtx reg;
+{
+ int src_regno;
+
+ /* Bad if this isn't a register at all. */
+ if (GET_CODE (reg) != REG)
+ return 0;
+
+ /* If this register is not meant to get a hard register,
+ it is a poor choice. */
+ if (REG_LIVE_LENGTH (REGNO (reg)) < 0)
+ return 0;
+
+ src_regno = regno_src_regno[REGNO (reg)];
+
+ /* If it was not copied from another register, it is fine. */
+ if (src_regno < 0)
+ return 3;
+
+ /* Copied from a hard register? */
+ if (src_regno < FIRST_PSEUDO_REGISTER)
+ return 1;
+
+ /* Copied from a pseudo register - not as bad as from a hard register,
+ yet still cumbersome, since the register live length will be lengthened
+ when the registers get tied. */
+ return 2;
+}
+
+/* INSN is a copy from SRC to DEST, both registers, and SRC does not die
+ in INSN.
+
+ Search forward to see if SRC dies before either it or DEST is modified,
+ but don't scan past the end of a basic block. If so, we can replace SRC
+ with DEST and let SRC die in INSN.
+
+ This will reduce the number of registers live in that range and may enable
+ DEST to be tied to SRC, thus often saving one register in addition to a
+ register-register copy. */
+
+static int
+optimize_reg_copy_1 (insn, dest, src)
+ rtx insn;
+ rtx dest;
+ rtx src;
+{
+ rtx p, q;
+ rtx note;
+ rtx dest_death = 0;
+ int sregno = REGNO (src);
+ int dregno = REGNO (dest);
+
+ /* We don't want to mess with hard regs if register classes are small. */
+ if (sregno == dregno
+ || (SMALL_REGISTER_CLASSES
+ && (sregno < FIRST_PSEUDO_REGISTER
+ || dregno < FIRST_PSEUDO_REGISTER))
+ /* We don't see all updates to SP if they are in an auto-inc memory
+ reference, so we must disallow this optimization on them. */
+ || sregno == STACK_POINTER_REGNUM || dregno == STACK_POINTER_REGNUM)
+ return 0;
+
+ for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
+ {
+ if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
+ || (GET_CODE (p) == NOTE
+ && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
+ break;
+
+ /* ??? We can't scan past the end of a basic block without updating
+ the register lifetime info (REG_DEAD/basic_block_live_at_start).
+ A CALL_INSN might be the last insn of a basic block, if it is inside
+ an EH region. There is no easy way to tell, so we just always break
+ when we see a CALL_INSN if flag_exceptions is nonzero. */
+ if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ break;
+
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+
+ if (reg_set_p (src, p) || reg_set_p (dest, p)
+ /* Don't change a USE of a register. */
+ || (GET_CODE (PATTERN (p)) == USE
+ && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
+ break;
+
+ /* See if all of SRC dies in P. This test is slightly more
+ conservative than it needs to be. */
+ if ((note = find_regno_note (p, REG_DEAD, sregno)) != 0
+ && GET_MODE (XEXP (note, 0)) == GET_MODE (src))
+ {
+ int failed = 0;
+ int d_length = 0;
+ int s_length = 0;
+ int d_n_calls = 0;
+ int s_n_calls = 0;
+
+ /* We can do the optimization. Scan forward from INSN again,
+ replacing regs as we go. Set FAILED if a replacement can't
+ be done. In that case, we can't move the death note for SRC.
+ This should be rare. */
+
+ /* Set to stop at next insn. */
+ for (q = next_real_insn (insn);
+ q != next_real_insn (p);
+ q = next_real_insn (q))
+ {
+ if (reg_overlap_mentioned_p (src, PATTERN (q)))
+ {
+ /* If SRC is a hard register, we might miss some
+ overlapping registers with validate_replace_rtx,
+ so we would have to undo it. We can't if DEST is
+ present in the insn, so fail in that combination
+ of cases. */
+ if (sregno < FIRST_PSEUDO_REGISTER
+ && reg_mentioned_p (dest, PATTERN (q)))
+ failed = 1;
+
+ /* Replace all uses and make sure that the register
+ isn't still present. */
+ else if (validate_replace_rtx (src, dest, q)
+ && (sregno >= FIRST_PSEUDO_REGISTER
+ || ! reg_overlap_mentioned_p (src,
+ PATTERN (q))))
+ {
+ /* We assume that a register is used exactly once per
+ insn in the REG_N_REFS updates below. If this is not
+ correct, no great harm is done.
+
+ Since we do not know if we will change the lifetime of
+ SREGNO or DREGNO, we must not update REG_LIVE_LENGTH
+ or REG_N_CALLS_CROSSED at this time. */
+ if (sregno >= FIRST_PSEUDO_REGISTER)
+ REG_N_REFS (sregno) -= loop_depth;
+
+ if (dregno >= FIRST_PSEUDO_REGISTER)
+ REG_N_REFS (dregno) += loop_depth;
+ }
+ else
+ {
+ validate_replace_rtx (dest, src, q);
+ failed = 1;
+ }
+ }
+
+ /* For SREGNO, count the total number of insns scanned.
+ For DREGNO, count the total number of insns scanned after
+ passing the death note for DREGNO. */
+ s_length++;
+ if (dest_death)
+ d_length++;
+
+ /* If the insn in which SRC dies is a CALL_INSN, don't count it
+ as a call that has been crossed. Otherwise, count it. */
+ if (q != p && GET_CODE (q) == CALL_INSN)
+ {
+ /* Similarly, total calls for SREGNO, total calls beyond
+ the death note for DREGNO. */
+ s_n_calls++;
+ if (dest_death)
+ d_n_calls++;
+ }
+
+ /* If DEST dies here, remove the death note and save it for
+ later. Make sure ALL of DEST dies here; again, this is
+ overly conservative. */
+ if (dest_death == 0
+ && (dest_death = find_regno_note (q, REG_DEAD, dregno)) != 0)
+ {
+ if (GET_MODE (XEXP (dest_death, 0)) != GET_MODE (dest))
+ failed = 1, dest_death = 0;
+ else
+ remove_note (q, dest_death);
+ }
+ }
+
+ if (! failed)
+ {
+ /* These counters need to be updated if and only if we are
+ going to move the REG_DEAD note. */
+ if (sregno >= FIRST_PSEUDO_REGISTER)
+ {
+ if (REG_LIVE_LENGTH (sregno) >= 0)
+ {
+ REG_LIVE_LENGTH (sregno) -= s_length;
+ /* REG_LIVE_LENGTH is only an approximation after
+ combine if sched is not run, so make sure that we
+ still have a reasonable value. */
+ if (REG_LIVE_LENGTH (sregno) < 2)
+ REG_LIVE_LENGTH (sregno) = 2;
+ }
+
+ REG_N_CALLS_CROSSED (sregno) -= s_n_calls;
+ }
+
+ /* Move death note of SRC from P to INSN. */
+ remove_note (p, note);
+ XEXP (note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = note;
+ }
+
+ /* Put death note of DEST on P if we saw it die. */
+ if (dest_death)
+ {
+ XEXP (dest_death, 1) = REG_NOTES (p);
+ REG_NOTES (p) = dest_death;
+
+ if (dregno >= FIRST_PSEUDO_REGISTER)
+ {
+ /* If and only if we are moving the death note for DREGNO,
+ then we need to update its counters. */
+ if (REG_LIVE_LENGTH (dregno) >= 0)
+ REG_LIVE_LENGTH (dregno) += d_length;
+ REG_N_CALLS_CROSSED (dregno) += d_n_calls;
+ }
+ }
+
+ return ! failed;
+ }
+
+ /* If SRC is a hard register which is set or killed in some other
+ way, we can't do this optimization. */
+ else if (sregno < FIRST_PSEUDO_REGISTER
+ && dead_or_set_p (p, src))
+ break;
+ }
+ return 0;
+}
+
+/* INSN is a copy of SRC to DEST, in which SRC dies. See if we now have
+ a sequence of insns that modify DEST followed by an insn that sets
+ SRC to DEST in which DEST dies, with no prior modification of DEST.
+ (There is no need to check if the insns in between actually modify
+ DEST. We should not have cases where DEST is not modified, but
+ the optimization is safe if no such modification is detected.)
+ In that case, we can replace all uses of DEST, starting with INSN and
+ ending with the set of SRC to DEST, with SRC. We do not do this
+ optimization if a CALL_INSN is crossed unless SRC already crosses a
+ call or if DEST dies before the copy back to SRC.
+
+ It is assumed that DEST and SRC are pseudos; it is too complicated to do
+ this for hard registers since the substitutions we may make might fail. */
+
+static void
+optimize_reg_copy_2 (insn, dest, src)
+ rtx insn;
+ rtx dest;
+ rtx src;
+{
+ rtx p, q;
+ rtx set;
+ int sregno = REGNO (src);
+ int dregno = REGNO (dest);
+
+ for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
+ {
+ if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
+ || (GET_CODE (p) == NOTE
+ && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
+ break;
+
+ /* ??? We can't scan past the end of a basic block without updating
+ the register lifetime info (REG_DEAD/basic_block_live_at_start).
+ A CALL_INSN might be the last insn of a basic block, if it is inside
+ an EH region. There is no easy way to tell, so we just always break
+ when we see a CALL_INSN if flag_exceptions is nonzero. */
+ if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ break;
+
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+
+ set = single_set (p);
+ if (set && SET_SRC (set) == dest && SET_DEST (set) == src
+ && find_reg_note (p, REG_DEAD, dest))
+ {
+ /* We can do the optimization. Scan forward from INSN again,
+ replacing regs as we go. */
+
+ /* Set to stop at next insn. */
+ for (q = insn; q != NEXT_INSN (p); q = NEXT_INSN (q))
+ if (GET_RTX_CLASS (GET_CODE (q)) == 'i')
+ {
+ if (reg_mentioned_p (dest, PATTERN (q)))
+ {
+ PATTERN (q) = replace_rtx (PATTERN (q), dest, src);
+
+ /* We assume that a register is used exactly once per
+ insn in the updates below. If this is not correct,
+ no great harm is done. */
+ REG_N_REFS (dregno) -= loop_depth;
+ REG_N_REFS (sregno) += loop_depth;
+ }
+
+
+ if (GET_CODE (q) == CALL_INSN)
+ {
+ REG_N_CALLS_CROSSED (dregno)--;
+ REG_N_CALLS_CROSSED (sregno)++;
+ }
+ }
+
+ remove_note (p, find_reg_note (p, REG_DEAD, dest));
+ REG_N_DEATHS (dregno)--;
+ remove_note (insn, find_reg_note (insn, REG_DEAD, src));
+ REG_N_DEATHS (sregno)--;
+ return;
+ }
+
+ if (reg_set_p (src, p)
+ || find_reg_note (p, REG_DEAD, dest)
+ || (GET_CODE (p) == CALL_INSN && REG_N_CALLS_CROSSED (sregno) == 0))
+ break;
+ }
+}
+/* INSN is a ZERO_EXTEND or SIGN_EXTEND of SRC to DEST.
+ Look if SRC dies there, and if it is only set once, by loading
+ it from memory. If so, try to encorporate the zero/sign extension
+ into the memory read, change SRC to the mode of DEST, and alter
+ the remaining accesses to use the appropriate SUBREG. This allows
+ SRC and DEST to be tied later. */
+static void
+optimize_reg_copy_3 (insn, dest, src)
+ rtx insn;
+ rtx dest;
+ rtx src;
+{
+ rtx src_reg = XEXP (src, 0);
+ int src_no = REGNO (src_reg);
+ int dst_no = REGNO (dest);
+ rtx p, set, subreg;
+ enum machine_mode old_mode;
+
+ /* This code has been disabled on the egcs-1.1 release branch due to
+ a potentially serious bug.
+
+ In a nutshell, if we perform a series of substitutions, then have a
+ later substitution fail we will not be able to undo the previous
+ substitutions, leaving bogus RTL.
+
+ A fix for this can be found in the mainline sources, but it did not
+ seem worth the trouble and potential problems to migrate the real
+ fix to the egcs-1.1 branch. */
+ return;
+
+ if (src_no < FIRST_PSEUDO_REGISTER
+ || dst_no < FIRST_PSEUDO_REGISTER
+ || ! find_reg_note (insn, REG_DEAD, src_reg)
+ || REG_N_SETS (src_no) != 1)
+ return;
+ for (p = PREV_INSN (insn); ! reg_set_p (src_reg, p); p = PREV_INSN (p))
+ {
+ if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
+ || (GET_CODE (p) == NOTE
+ && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
+ return;
+
+ /* ??? We can't scan past the end of a basic block without updating
+ the register lifetime info (REG_DEAD/basic_block_live_at_start).
+ A CALL_INSN might be the last insn of a basic block, if it is inside
+ an EH region. There is no easy way to tell, so we just always break
+ when we see a CALL_INSN if flag_exceptions is nonzero. */
+ if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ return;
+
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+ }
+ if (! (set = single_set (p))
+ || GET_CODE (SET_SRC (set)) != MEM
+ || SET_DEST (set) != src_reg)
+ return;
+ old_mode = GET_MODE (src_reg);
+ PUT_MODE (src_reg, GET_MODE (src));
+ XEXP (src, 0) = SET_SRC (set);
+ if (! validate_change (p, &SET_SRC (set), src, 0))
+ {
+ PUT_MODE (src_reg, old_mode);
+ XEXP (src, 0) = src_reg;
+ return;
+ }
+ subreg = gen_rtx_SUBREG (old_mode, src_reg, 0);
+ while (p = NEXT_INSN (p), p != insn)
+ {
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+ validate_replace_rtx (src_reg, subreg, p);
+ }
+ validate_replace_rtx (src, src_reg, insn);
+}
+
+
+/* If we were not able to update the users of src to use dest directly, try
+ instead moving the value to dest directly before the operation. */
+
+static void
+copy_src_to_dest (insn, src, dest, loop_depth)
+ rtx insn;
+ rtx src;
+ rtx dest;
+ int loop_depth;
+{
+ rtx seq;
+ rtx link;
+ rtx next;
+ rtx set;
+ rtx move_insn;
+ rtx *p_insn_notes;
+ rtx *p_move_notes;
+ int src_regno;
+ int dest_regno;
+ int bb;
+ int insn_uid;
+ int move_uid;
+
+ /* A REG_LIVE_LENGTH of -1 indicates the register is equivalent to a constant
+ or memory location and is used infrequently; a REG_LIVE_LENGTH of -2 is
+ parameter when there is no frame pointer that is not allocated a register.
+ For now, we just reject them, rather than incrementing the live length. */
+
+ if (GET_CODE (src) == REG
+ && REG_LIVE_LENGTH (REGNO (src)) > 0
+ && GET_CODE (dest) == REG
+ && REG_LIVE_LENGTH (REGNO (dest)) > 0
+ && (set = single_set (insn)) != NULL_RTX
+ && !reg_mentioned_p (dest, SET_SRC (set))
+ && validate_replace_rtx (src, dest, insn))
+ {
+ /* Generate the src->dest move. */
+ start_sequence ();
+ emit_move_insn (dest, src);
+ seq = gen_sequence ();
+ end_sequence ();
+ emit_insn_before (seq, insn);
+ move_insn = PREV_INSN (insn);
+ p_move_notes = &REG_NOTES (move_insn);
+ p_insn_notes = &REG_NOTES (insn);
+
+ /* Move any notes mentioning src to the move instruction */
+ for (link = REG_NOTES (insn); link != NULL_RTX; link = next)
+ {
+ next = XEXP (link, 1);
+ if (XEXP (link, 0) == src)
+ {
+ *p_move_notes = link;
+ p_move_notes = &XEXP (link, 1);
+ }
+ else
+ {
+ *p_insn_notes = link;
+ p_insn_notes = &XEXP (link, 1);
+ }
+ }
+
+ *p_move_notes = NULL_RTX;
+ *p_insn_notes = NULL_RTX;
+
+ /* Is the insn the head of a basic block? If so extend it */
+ insn_uid = INSN_UID (insn);
+ move_uid = INSN_UID (move_insn);
+ bb = regmove_bb_head[insn_uid];
+ if (bb >= 0)
+ {
+ basic_block_head[bb] = move_insn;
+ regmove_bb_head[insn_uid] = -1;
+ }
+
+ /* Update the various register tables. */
+ dest_regno = REGNO (dest);
+ REG_N_SETS (dest_regno) += loop_depth;
+ REG_N_REFS (dest_regno) += loop_depth;
+ REG_LIVE_LENGTH (dest_regno)++;
+ if (REGNO_FIRST_UID (dest_regno) == insn_uid)
+ REGNO_FIRST_UID (dest_regno) = move_uid;
+
+ src_regno = REGNO (src);
+ if (! find_reg_note (move_insn, REG_DEAD, src))
+ REG_LIVE_LENGTH (src_regno)++;
+
+ if (REGNO_FIRST_UID (src_regno) == insn_uid)
+ REGNO_FIRST_UID (src_regno) = move_uid;
+
+ if (REGNO_LAST_UID (src_regno) == insn_uid)
+ REGNO_LAST_UID (src_regno) = move_uid;
+
+ if (REGNO_LAST_NOTE_UID (src_regno) == insn_uid)
+ REGNO_LAST_NOTE_UID (src_regno) = move_uid;
+ }
+}
+
+
+/* Return whether REG is set in only one location, and is set to a
+ constant, but is set in a different basic block from INSN (an
+ instructions which uses REG). In this case REG is equivalent to a
+ constant, and we don't want to break that equivalence, because that
+ may increase register pressure and make reload harder. If REG is
+ set in the same basic block as INSN, we don't worry about it,
+ because we'll probably need a register anyhow (??? but what if REG
+ is used in a different basic block as well as this one?). FIRST is
+ the first insn in the function. */
+
+static int
+reg_is_remote_constant_p (reg, insn, first)
+ rtx reg;
+ rtx insn;
+ rtx first;
+{
+ register rtx p;
+
+ if (REG_N_SETS (REGNO (reg)) != 1)
+ return 0;
+
+ /* Look for the set. */
+ for (p = LOG_LINKS (insn); p; p = XEXP (p, 1))
+ {
+ rtx s;
+
+ if (REG_NOTE_KIND (p) != 0)
+ continue;
+ s = single_set (XEXP (p, 0));
+ if (s != 0
+ && GET_CODE (SET_DEST (s)) == REG
+ && REGNO (SET_DEST (s)) == REGNO (reg))
+ {
+ /* The register is set in the same basic block. */
+ return 0;
+ }
+ }
+
+ for (p = first; p && p != insn; p = NEXT_INSN (p))
+ {
+ rtx s;
+
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+ s = single_set (p);
+ if (s != 0
+ && GET_CODE (SET_DEST (s)) == REG
+ && REGNO (SET_DEST (s)) == REGNO (reg))
+ {
+ /* This is the instruction which sets REG. If there is a
+ REG_EQUAL note, then REG is equivalent to a constant. */
+ if (find_reg_note (p, REG_EQUAL, NULL_RTX))
+ return 1;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/* INSN is adding a CONST_INT to a REG. We search backwards looking for
+ another add immediate instruction with the same source and dest registers,
+ and if we find one, we change INSN to an increment, and return 1. If
+ no changes are made, we return 0.
+
+ This changes
+ (set (reg100) (plus reg1 offset1))
+ ...
+ (set (reg100) (plus reg1 offset2))
+ to
+ (set (reg100) (plus reg1 offset1))
+ ...
+ (set (reg100) (plus reg100 offset2-offset1)) */
+
+/* ??? What does this comment mean? */
+/* cse disrupts preincrement / postdecrement squences when it finds a
+ hard register as ultimate source, like the frame pointer. */
+
+int
+fixup_match_2 (insn, dst, src, offset, regmove_dump_file)
+ rtx insn, dst, src, offset;
+ FILE *regmove_dump_file;
+{
+ rtx p, dst_death = 0;
+ int length, num_calls = 0;
+
+ /* If SRC dies in INSN, we'd have to move the death note. This is
+ considered to be very unlikely, so we just skip the optimization
+ in this case. */
+ if (find_regno_note (insn, REG_DEAD, REGNO (src)))
+ return 0;
+
+ /* Scan backward to find the first instruction that sets DST. */
+
+ for (length = 0, p = PREV_INSN (insn); p; p = PREV_INSN (p))
+ {
+ rtx pset;
+
+ if (GET_CODE (p) == CODE_LABEL
+ || GET_CODE (p) == JUMP_INSN
+ || (GET_CODE (p) == NOTE
+ && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
+ break;
+
+ /* ??? We can't scan past the end of a basic block without updating
+ the register lifetime info (REG_DEAD/basic_block_live_at_start).
+ A CALL_INSN might be the last insn of a basic block, if it is inside
+ an EH region. There is no easy way to tell, so we just always break
+ when we see a CALL_INSN if flag_exceptions is nonzero. */
+ if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ break;
+
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+
+ if (find_regno_note (p, REG_DEAD, REGNO (dst)))
+ dst_death = p;
+ if (! dst_death)
+ length++;
+
+ pset = single_set (p);
+ if (pset && SET_DEST (pset) == dst
+ && GET_CODE (SET_SRC (pset)) == PLUS
+ && XEXP (SET_SRC (pset), 0) == src
+ && GET_CODE (XEXP (SET_SRC (pset), 1)) == CONST_INT)
+ {
+ HOST_WIDE_INT newconst
+ = INTVAL (offset) - INTVAL (XEXP (SET_SRC (pset), 1));
+ rtx add = gen_add3_insn (dst, dst, GEN_INT (newconst));
+
+ if (add && validate_change (insn, &PATTERN (insn), add, 0))
+ {
+ /* Remove the death note for DST from DST_DEATH. */
+ if (dst_death)
+ {
+ remove_death (REGNO (dst), dst_death);
+ REG_LIVE_LENGTH (REGNO (dst)) += length;
+ REG_N_CALLS_CROSSED (REGNO (dst)) += num_calls;
+ }
+
+ REG_N_REFS (REGNO (dst)) += loop_depth;
+ REG_N_REFS (REGNO (src)) -= loop_depth;
+
+ if (regmove_dump_file)
+ fprintf (regmove_dump_file,
+ "Fixed operand of insn %d.\n",
+ INSN_UID (insn));
+
+#ifdef AUTO_INC_DEC
+ for (p = PREV_INSN (insn); p; p = PREV_INSN (p))
+ {
+ if (GET_CODE (p) == CODE_LABEL
+ || GET_CODE (p) == JUMP_INSN
+ || (GET_CODE (p) == NOTE
+ && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
+ break;
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+ if (reg_overlap_mentioned_p (dst, PATTERN (p)))
+ {
+ if (try_auto_increment (p, insn, 0, dst, newconst, 0))
+ return 1;
+ break;
+ }
+ }
+ for (p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
+ {
+ if (GET_CODE (p) == CODE_LABEL
+ || GET_CODE (p) == JUMP_INSN
+ || (GET_CODE (p) == NOTE
+ && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
+ break;
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+ if (reg_overlap_mentioned_p (dst, PATTERN (p)))
+ {
+ try_auto_increment (p, insn, 0, dst, newconst, 1);
+ break;
+ }
+ }
+#endif
+ return 1;
+ }
+ }
+
+ if (reg_set_p (dst, PATTERN (p)))
+ break;
+
+ /* If we have passed a call instruction, and the
+ pseudo-reg SRC is not already live across a call,
+ then don't perform the optimization. */
+ /* reg_set_p is overly conservative for CALL_INSNS, thinks that all
+ hard regs are clobbered. Thus, we only use it for src for
+ non-call insns. */
+ if (GET_CODE (p) == CALL_INSN)
+ {
+ if (! dst_death)
+ num_calls++;
+
+ if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
+ break;
+
+ if (call_used_regs [REGNO (dst)]
+ || find_reg_fusage (p, CLOBBER, dst))
+ break;
+ }
+ else if (reg_set_p (src, PATTERN (p)))
+ break;
+ }
+
+ return 0;
+}
+
+void
+regmove_optimize (f, nregs, regmove_dump_file)
+ rtx f;
+ int nregs;
+ FILE *regmove_dump_file;
+{
+ rtx insn;
+ struct match match;
+ int pass;
+ int maxregnum = max_reg_num (), i;
+ rtx copy_src, copy_dst;
+
+ regno_src_regno = (int *)alloca (sizeof *regno_src_regno * maxregnum);
+ for (i = maxregnum; --i >= 0; ) regno_src_regno[i] = -1;
+
+ regmove_bb_head = (int *)alloca (sizeof (int) * (get_max_uid () + 1));
+ for (i = get_max_uid (); i >= 0; i--) regmove_bb_head[i] = -1;
+ for (i = 0; i < n_basic_blocks; i++)
+ regmove_bb_head[INSN_UID (basic_block_head[i])] = i;
+
+ /* A forward/backward pass. Replace output operands with input operands. */
+
+ loop_depth = 1;
+
+ for (pass = 0; pass <= 2; pass++)
+ {
+ if (! flag_regmove && pass >= flag_expensive_optimizations)
+ return;
+
+ if (regmove_dump_file)
+ fprintf (regmove_dump_file, "Starting %s pass...\n",
+ pass ? "backward" : "forward");
+
+ for (insn = pass ? get_last_insn () : f; insn;
+ insn = pass ? PREV_INSN (insn) : NEXT_INSN (insn))
+ {
+ rtx set;
+ int insn_code_number;
+ int operand_number, match_number;
+
+ if (GET_CODE (insn) == NOTE)
+ {
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+ loop_depth++;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+ loop_depth--;
+ }
+
+ set = single_set (insn);
+ if (! set)
+ continue;
+
+ if (flag_expensive_optimizations && ! pass
+ && (GET_CODE (SET_SRC (set)) == SIGN_EXTEND
+ || GET_CODE (SET_SRC (set)) == ZERO_EXTEND)
+ && GET_CODE (XEXP (SET_SRC (set), 0)) == REG
+ && GET_CODE (SET_DEST(set)) == REG)
+ optimize_reg_copy_3 (insn, SET_DEST (set), SET_SRC (set));
+
+ if (flag_expensive_optimizations && ! pass
+ && GET_CODE (SET_SRC (set)) == REG
+ && GET_CODE (SET_DEST(set)) == REG)
+ {
+ /* If this is a register-register copy where SRC is not dead,
+ see if we can optimize it. If this optimization succeeds,
+ it will become a copy where SRC is dead. */
+ if ((find_reg_note (insn, REG_DEAD, SET_SRC (set))
+ || optimize_reg_copy_1 (insn, SET_DEST (set), SET_SRC (set)))
+ && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
+ {
+ /* Similarly for a pseudo-pseudo copy when SRC is dead. */
+ if (REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
+ optimize_reg_copy_2 (insn, SET_DEST (set), SET_SRC (set));
+ if (regno_src_regno[REGNO (SET_DEST (set))] < 0
+ && SET_SRC (set) != SET_DEST (set))
+ {
+ int srcregno = REGNO (SET_SRC(set));
+ if (regno_src_regno[srcregno] >= 0)
+ srcregno = regno_src_regno[srcregno];
+ regno_src_regno[REGNO (SET_DEST (set))] = srcregno;
+ }
+ }
+ }
+#ifdef REGISTER_CONSTRAINTS
+ insn_code_number
+ = find_matches (insn, &match);
+
+ if (insn_code_number < 0)
+ continue;
+
+ /* Now scan through the operands looking for a source operand
+ which is supposed to match the destination operand.
+ Then scan forward for an instruction which uses the dest
+ operand.
+ If it dies there, then replace the dest in both operands with
+ the source operand. */
+
+ for (operand_number = 0;
+ operand_number < insn_n_operands[insn_code_number];
+ operand_number++)
+ {
+ rtx src, dst, src_subreg;
+ enum reg_class src_class, dst_class;
+
+ match_number = match.with[operand_number];
+
+ /* Nothing to do if the two operands aren't supposed to match. */
+ if (match_number < 0)
+ continue;
+
+ src = recog_operand[operand_number];
+ dst = recog_operand[match_number];
+
+ if (GET_CODE (src) != REG)
+ continue;
+
+ src_subreg = src;
+ if (GET_CODE (dst) == SUBREG
+ && GET_MODE_SIZE (GET_MODE (dst))
+ >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dst))))
+ {
+ src_subreg
+ = gen_rtx_SUBREG (GET_MODE (SUBREG_REG (dst)),
+ src, SUBREG_WORD (dst));
+ dst = SUBREG_REG (dst);
+ }
+ if (GET_CODE (dst) != REG
+ || REGNO (dst) < FIRST_PSEUDO_REGISTER)
+ continue;
+
+ if (REGNO (src) < FIRST_PSEUDO_REGISTER)
+ {
+ if (match.commutative[operand_number] < operand_number)
+ regno_src_regno[REGNO (dst)] = REGNO (src);
+ continue;
+ }
+
+ if (REG_LIVE_LENGTH (REGNO (src)) < 0)
+ continue;
+
+ /* operand_number/src must be a read-only operand, and
+ match_operand/dst must be a write-only operand. */
+ if (match.use[operand_number] != READ
+ || match.use[match_number] != WRITE)
+ continue;
+
+ if (match.early_clobber[match_number]
+ && count_occurrences (PATTERN (insn), src) > 1)
+ continue;
+
+ /* Make sure match_operand is the destination. */
+ if (recog_operand[match_number] != SET_DEST (set))
+ continue;
+
+ /* If the operands already match, then there is nothing to do. */
+ /* But in the commutative case, we might find a better match. */
+ if (operands_match_p (src, dst)
+ || (match.commutative[operand_number] >= 0
+ && operands_match_p (recog_operand[match.commutative
+ [operand_number]], dst)
+ && (replacement_quality (recog_operand[match.commutative
+ [operand_number]])
+ >= replacement_quality (src))))
+ continue;
+
+ src_class = reg_preferred_class (REGNO (src));
+ dst_class = reg_preferred_class (REGNO (dst));
+ if (src_class != dst_class
+ && (! reg_class_subset_p (src_class, dst_class)
+ || CLASS_LIKELY_SPILLED_P (src_class))
+ && (! reg_class_subset_p (dst_class, src_class)
+ || CLASS_LIKELY_SPILLED_P (dst_class)))
+ continue;
+
+ if (fixup_match_1 (insn, set, src, src_subreg, dst, pass,
+ operand_number, match_number,
+ regmove_dump_file))
+ break;
+ }
+ }
+ }
+
+ /* A backward pass. Replace input operands with output operands. */
+
+ if (regmove_dump_file)
+ fprintf (regmove_dump_file, "Starting backward pass...\n");
+
+ loop_depth = 1;
+
+ for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
+ {
+ if (GET_CODE (insn) == NOTE)
+ {
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END)
+ loop_depth++;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG)
+ loop_depth--;
+ }
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ {
+ int insn_code_number = find_matches (insn, &match);
+ int operand_number, match_number;
+ int success = 0;
+
+ if (insn_code_number < 0)
+ continue;
+
+ /* Now scan through the operands looking for a destination operand
+ which is supposed to match a source operand.
+ Then scan backward for an instruction which sets the source
+ operand. If safe, then replace the source operand with the
+ dest operand in both instructions. */
+
+ copy_src = NULL_RTX;
+ copy_dst = NULL_RTX;
+ for (operand_number = 0;
+ operand_number < insn_n_operands[insn_code_number];
+ operand_number++)
+ {
+ rtx set, p, src, dst;
+ rtx src_note, dst_note;
+ int num_calls = 0;
+ enum reg_class src_class, dst_class;
+ int length;
+
+ match_number = match.with[operand_number];
+
+ /* Nothing to do if the two operands aren't supposed to match. */
+ if (match_number < 0)
+ continue;
+
+ dst = recog_operand[match_number];
+ src = recog_operand[operand_number];
+
+ if (GET_CODE (src) != REG)
+ continue;
+
+ if (GET_CODE (dst) != REG
+ || REGNO (dst) < FIRST_PSEUDO_REGISTER
+ || REG_LIVE_LENGTH (REGNO (dst)) < 0)
+ continue;
+
+ /* If the operands already match, then there is nothing to do. */
+ if (operands_match_p (src, dst)
+ || (match.commutative[operand_number] >= 0
+ && operands_match_p (recog_operand[match.commutative[operand_number]], dst)))
+ continue;
+
+ set = single_set (insn);
+ if (! set)
+ continue;
+
+ /* match_number/dst must be a write-only operand, and
+ operand_operand/src must be a read-only operand. */
+ if (match.use[operand_number] != READ
+ || match.use[match_number] != WRITE)
+ continue;
+
+ if (match.early_clobber[match_number]
+ && count_occurrences (PATTERN (insn), src) > 1)
+ continue;
+
+ /* Make sure match_number is the destination. */
+ if (recog_operand[match_number] != SET_DEST (set))
+ continue;
+
+ if (REGNO (src) < FIRST_PSEUDO_REGISTER)
+ {
+ if (GET_CODE (SET_SRC (set)) == PLUS
+ && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT
+ && XEXP (SET_SRC (set), 0) == src
+ && fixup_match_2 (insn, dst, src,
+ XEXP (SET_SRC (set), 1),
+ regmove_dump_file))
+ break;
+ continue;
+ }
+ src_class = reg_preferred_class (REGNO (src));
+ dst_class = reg_preferred_class (REGNO (dst));
+ if (src_class != dst_class
+ && (! reg_class_subset_p (src_class, dst_class)
+ || CLASS_LIKELY_SPILLED_P (src_class))
+ && (! reg_class_subset_p (dst_class, src_class)
+ || CLASS_LIKELY_SPILLED_P (dst_class)))
+ {
+ if (!copy_src)
+ {
+ copy_src = src;
+ copy_dst = dst;
+ }
+ continue;
+ }
+
+ /* Can not modify an earlier insn to set dst if this insn
+ uses an old value in the source. */
+ if (reg_overlap_mentioned_p (dst, SET_SRC (set)))
+ {
+ if (!copy_src)
+ {
+ copy_src = src;
+ copy_dst = dst;
+ }
+ continue;
+ }
+
+ if (! (src_note = find_reg_note (insn, REG_DEAD, src)))
+ {
+ if (!copy_src)
+ {
+ copy_src = src;
+ copy_dst = dst;
+ }
+ continue;
+ }
+
+
+ /* If src is set once in a different basic block,
+ and is set equal to a constant, then do not use
+ it for this optimization, as this would make it
+ no longer equivalent to a constant. */
+
+ if (reg_is_remote_constant_p (src, insn, f))
+ {
+ if (!copy_src)
+ {
+ copy_src = src;
+ copy_dst = dst;
+ }
+ continue;
+ }
+
+
+ if (regmove_dump_file)
+ fprintf (regmove_dump_file,
+ "Could fix operand %d of insn %d matching operand %d.\n",
+ operand_number, INSN_UID (insn), match_number);
+
+ /* Scan backward to find the first instruction that uses
+ the input operand. If the operand is set here, then
+ replace it in both instructions with match_number. */
+
+ for (length = 0, p = PREV_INSN (insn); p; p = PREV_INSN (p))
+ {
+ rtx pset;
+
+ if (GET_CODE (p) == CODE_LABEL
+ || GET_CODE (p) == JUMP_INSN
+ || (GET_CODE (p) == NOTE
+ && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
+ break;
+
+ /* ??? We can't scan past the end of a basic block without
+ updating the register lifetime info
+ (REG_DEAD/basic_block_live_at_start).
+ A CALL_INSN might be the last insn of a basic block, if
+ it is inside an EH region. There is no easy way to tell,
+ so we just always break when we see a CALL_INSN if
+ flag_exceptions is nonzero. */
+ if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ break;
+
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+
+ length++;
+
+ /* ??? See if all of SRC is set in P. This test is much
+ more conservative than it needs to be. */
+ pset = single_set (p);
+ if (pset && SET_DEST (pset) == src)
+ {
+ /* We use validate_replace_rtx, in case there
+ are multiple identical source operands. All of
+ them have to be changed at the same time. */
+ if (validate_replace_rtx (src, dst, insn))
+ {
+ if (validate_change (p, &SET_DEST (pset),
+ dst, 0))
+ success = 1;
+ else
+ {
+ /* Change all source operands back.
+ This modifies the dst as a side-effect. */
+ validate_replace_rtx (dst, src, insn);
+ /* Now make sure the dst is right. */
+ validate_change (insn,
+ recog_operand_loc[match_number],
+ dst, 0);
+ }
+ }
+ break;
+ }
+
+ if (reg_overlap_mentioned_p (src, PATTERN (p))
+ || reg_overlap_mentioned_p (dst, PATTERN (p)))
+ break;
+
+ /* If we have passed a call instruction, and the
+ pseudo-reg DST is not already live across a call,
+ then don't perform the optimization. */
+ if (GET_CODE (p) == CALL_INSN)
+ {
+ num_calls++;
+
+ if (REG_N_CALLS_CROSSED (REGNO (dst)) == 0)
+ break;
+ }
+ }
+
+ if (success)
+ {
+ int dstno, srcno;
+
+ /* Remove the death note for SRC from INSN. */
+ remove_note (insn, src_note);
+ /* Move the death note for SRC to P if it is used
+ there. */
+ if (reg_overlap_mentioned_p (src, PATTERN (p)))
+ {
+ XEXP (src_note, 1) = REG_NOTES (p);
+ REG_NOTES (p) = src_note;
+ }
+ /* If there is a REG_DEAD note for DST on P, then remove
+ it, because DST is now set there. */
+ if ((dst_note = find_reg_note (p, REG_DEAD, dst)))
+ remove_note (p, dst_note);
+
+ dstno = REGNO (dst);
+ srcno = REGNO (src);
+
+ REG_N_SETS (dstno)++;
+ REG_N_SETS (srcno)--;
+
+ REG_N_CALLS_CROSSED (dstno) += num_calls;
+ REG_N_CALLS_CROSSED (srcno) -= num_calls;
+
+ REG_LIVE_LENGTH (dstno) += length;
+ if (REG_LIVE_LENGTH (srcno) >= 0)
+ {
+ REG_LIVE_LENGTH (srcno) -= length;
+ /* REG_LIVE_LENGTH is only an approximation after
+ combine if sched is not run, so make sure that we
+ still have a reasonable value. */
+ if (REG_LIVE_LENGTH (srcno) < 2)
+ REG_LIVE_LENGTH (srcno) = 2;
+ }
+
+ /* We assume that a register is used exactly once per
+ insn in the updates above. If this is not correct,
+ no great harm is done. */
+
+ REG_N_REFS (dstno) += 2 * loop_depth;
+ REG_N_REFS (srcno) -= 2 * loop_depth;
+
+ /* If that was the only time src was set,
+ and src was not live at the start of the
+ function, we know that we have no more
+ references to src; clear REG_N_REFS so it
+ won't make reload do any work. */
+ if (REG_N_SETS (REGNO (src)) == 0
+ && ! regno_uninitialized (REGNO (src)))
+ REG_N_REFS (REGNO (src)) = 0;
+
+ if (regmove_dump_file)
+ fprintf (regmove_dump_file,
+ "Fixed operand %d of insn %d matching operand %d.\n",
+ operand_number, INSN_UID (insn), match_number);
+
+ break;
+ }
+ }
+
+ /* If we weren't able to replace any of the alternatives, try an
+ alternative appoach of copying the source to the destination. */
+ if (!success && copy_src != NULL_RTX)
+ copy_src_to_dest (insn, copy_src, copy_dst, loop_depth);
+
+ }
+ }
+#endif /* REGISTER_CONSTRAINTS */
+}
+
+/* Returns the INSN_CODE for INSN if its pattern has matching constraints for
+ any operand. Returns -1 if INSN can't be recognized, or if the alternative
+ can't be determined.
+
+ Initialize the info in MATCHP based on the constraints. */
+
+static int
+find_matches (insn, matchp)
+ rtx insn;
+ struct match *matchp;
+{
+ int likely_spilled[MAX_RECOG_OPERANDS];
+ int operand_number;
+ int insn_code_number = recog_memoized (insn);
+ int any_matches = 0;
+
+ if (insn_code_number < 0)
+ return -1;
+
+ insn_extract (insn);
+ if (! constrain_operands (insn_code_number, 0))
+ return -1;
+
+ /* Must initialize this before main loop, because the code for
+ the commutative case may set matches for operands other than
+ the current one. */
+ for (operand_number = insn_n_operands[insn_code_number];
+ --operand_number >= 0; )
+ matchp->with[operand_number] = matchp->commutative[operand_number] = -1;
+
+ for (operand_number = 0; operand_number < insn_n_operands[insn_code_number];
+ operand_number++)
+ {
+ char *p, c;
+ int i = 0;
+
+ p = insn_operand_constraint[insn_code_number][operand_number];
+
+ likely_spilled[operand_number] = 0;
+ matchp->use[operand_number] = READ;
+ matchp->early_clobber[operand_number] = 0;
+ if (*p == '=')
+ matchp->use[operand_number] = WRITE;
+ else if (*p == '+')
+ matchp->use[operand_number] = READWRITE;
+
+ for (;*p && i < which_alternative; p++)
+ if (*p == ',')
+ i++;
+
+ while ((c = *p++) != '\0' && c != ',')
+ switch (c)
+ {
+ case '=':
+ break;
+ case '+':
+ break;
+ case '&':
+ matchp->early_clobber[operand_number] = 1;
+ break;
+ case '%':
+ matchp->commutative[operand_number] = operand_number + 1;
+ matchp->commutative[operand_number + 1] = operand_number;
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ c -= '0';
+ if (c < operand_number && likely_spilled[(unsigned char) c])
+ break;
+ matchp->with[operand_number] = c;
+ any_matches = 1;
+ if (matchp->commutative[operand_number] >= 0)
+ matchp->with[matchp->commutative[operand_number]] = c;
+ break;
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h':
+ case 'j': case 'k': case 'l': case 'p': case 'q': case 't': case 'u':
+ case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
+ case 'C': case 'D': case 'W': case 'Y': case 'Z':
+ if (CLASS_LIKELY_SPILLED_P (REG_CLASS_FROM_LETTER (c)))
+ likely_spilled[operand_number] = 1;
+ break;
+ }
+ }
+ return any_matches ? insn_code_number : -1;
+}
+
+/* Try to replace output operand DST in SET, with input operand SRC. SET is
+ the only set in INSN. INSN has just been recgnized and constrained.
+ SRC is operand number OPERAND_NUMBER in INSN.
+ DST is operand number MATCH_NUMBER in INSN.
+ If BACKWARD is nonzero, we have been called in a backward pass.
+ Return nonzero for success. */
+static int
+fixup_match_1 (insn, set, src, src_subreg, dst, backward, operand_number,
+ match_number, regmove_dump_file)
+ rtx insn, set, src, src_subreg, dst;
+ int backward, operand_number, match_number;
+ FILE *regmove_dump_file;
+{
+ rtx p;
+ rtx post_inc = 0, post_inc_set = 0, search_end = 0;
+ int success = 0;
+ int num_calls = 0, s_num_calls = 0;
+ enum rtx_code code = NOTE;
+ HOST_WIDE_INT insn_const, newconst;
+ rtx overlap = 0; /* need to move insn ? */
+ rtx src_note = find_reg_note (insn, REG_DEAD, src), dst_note;
+ int length, s_length, true_loop_depth;
+
+ if (! src_note)
+ {
+ /* Look for (set (regX) (op regA constX))
+ (set (regY) (op regA constY))
+ and change that to
+ (set (regA) (op regA constX)).
+ (set (regY) (op regA constY-constX)).
+ This works for add and shift operations, if
+ regA is dead after or set by the second insn. */
+
+ code = GET_CODE (SET_SRC (set));
+ if ((code == PLUS || code == LSHIFTRT
+ || code == ASHIFT || code == ASHIFTRT)
+ && XEXP (SET_SRC (set), 0) == src
+ && GET_CODE (XEXP (SET_SRC (set), 1)) == CONST_INT)
+ insn_const = INTVAL (XEXP (SET_SRC (set), 1));
+ else if (! stable_but_for_p (SET_SRC (set), src, dst))
+ return 0;
+ else
+ /* We might find a src_note while scanning. */
+ code = NOTE;
+ }
+
+ if (regmove_dump_file)
+ fprintf (regmove_dump_file,
+ "Could fix operand %d of insn %d matching operand %d.\n",
+ operand_number, INSN_UID (insn), match_number);
+
+ /* If SRC is equivalent to a constant set in a different basic block,
+ then do not use it for this optimization. We want the equivalence
+ so that if we have to reload this register, we can reload the
+ constant, rather than extending the lifespan of the register. */
+ if (reg_is_remote_constant_p (src, insn, get_insns ()))
+ return 0;
+
+ /* Scan forward to find the next instruction that
+ uses the output operand. If the operand dies here,
+ then replace it in both instructions with
+ operand_number. */
+
+ for (length = s_length = 0, p = NEXT_INSN (insn); p; p = NEXT_INSN (p))
+ {
+ if (GET_CODE (p) == CODE_LABEL || GET_CODE (p) == JUMP_INSN
+ || (GET_CODE (p) == NOTE
+ && (NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (p) == NOTE_INSN_LOOP_END)))
+ break;
+
+ /* ??? We can't scan past the end of a basic block without updating
+ the register lifetime info (REG_DEAD/basic_block_live_at_start).
+ A CALL_INSN might be the last insn of a basic block, if it is
+ inside an EH region. There is no easy way to tell, so we just
+ always break when we see a CALL_INSN if flag_exceptions is nonzero. */
+ if (flag_exceptions && GET_CODE (p) == CALL_INSN)
+ break;
+
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i')
+ continue;
+
+ length++;
+ if (src_note)
+ s_length++;
+
+ if (reg_set_p (src, p) || reg_set_p (dst, p)
+ || (GET_CODE (PATTERN (p)) == USE
+ && reg_overlap_mentioned_p (src, XEXP (PATTERN (p), 0))))
+ break;
+
+ /* See if all of DST dies in P. This test is
+ slightly more conservative than it needs to be. */
+ if ((dst_note = find_regno_note (p, REG_DEAD, REGNO (dst)))
+ && (GET_MODE (XEXP (dst_note, 0)) == GET_MODE (dst)))
+ {
+ if (! src_note)
+ {
+ rtx q;
+ rtx set2;
+
+ /* If an optimization is done, the value of SRC while P
+ is executed will be changed. Check that this is OK. */
+ if (reg_overlap_mentioned_p (src, PATTERN (p)))
+ break;
+ for (q = p; q; q = NEXT_INSN (q))
+ {
+ if (GET_CODE (q) == CODE_LABEL || GET_CODE (q) == JUMP_INSN
+ || (GET_CODE (q) == NOTE
+ && (NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_END)))
+ {
+ q = 0;
+ break;
+ }
+
+ /* ??? We can't scan past the end of a basic block without
+ updating the register lifetime info
+ (REG_DEAD/basic_block_live_at_start).
+ A CALL_INSN might be the last insn of a basic block, if
+ it is inside an EH region. There is no easy way to tell,
+ so we just always break when we see a CALL_INSN if
+ flag_exceptions is nonzero. */
+ if (flag_exceptions && GET_CODE (q) == CALL_INSN)
+ {
+ q = 0;
+ break;
+ }
+
+ if (GET_RTX_CLASS (GET_CODE (q)) != 'i')
+ continue;
+ if (reg_overlap_mentioned_p (src, PATTERN (q))
+ || reg_set_p (src, q))
+ break;
+ }
+ if (q)
+ set2 = single_set (q);
+ if (! q || ! set2 || GET_CODE (SET_SRC (set2)) != code
+ || XEXP (SET_SRC (set2), 0) != src
+ || GET_CODE (XEXP (SET_SRC (set2), 1)) != CONST_INT
+ || (SET_DEST (set2) != src
+ && ! find_reg_note (q, REG_DEAD, src)))
+ {
+ /* If this is a PLUS, we can still save a register by doing
+ src += insn_const;
+ P;
+ src -= insn_const; .
+ This also gives opportunities for subsequent
+ optimizations in the backward pass, so do it there. */
+ if (code == PLUS && backward
+#ifdef HAVE_cc0
+ /* We may not emit an insn directly
+ after P if the latter sets CC0. */
+ && ! sets_cc0_p (PATTERN (p))
+#endif
+ )
+
+ {
+ search_end = q;
+ q = insn;
+ set2 = set;
+ newconst = -insn_const;
+ code = MINUS;
+ }
+ else
+ break;
+ }
+ else
+ {
+ newconst = INTVAL (XEXP (SET_SRC (set2), 1)) - insn_const;
+ /* Reject out of range shifts. */
+ if (code != PLUS
+ && (newconst < 0
+ || (newconst
+ >= GET_MODE_BITSIZE (GET_MODE (SET_SRC (set2))))))
+ break;
+ if (code == PLUS)
+ {
+ post_inc = q;
+ if (SET_DEST (set2) != src)
+ post_inc_set = set2;
+ }
+ }
+ /* We use 1 as last argument to validate_change so that all
+ changes are accepted or rejected together by apply_change_group
+ when it is called by validate_replace_rtx . */
+ validate_change (q, &XEXP (SET_SRC (set2), 1),
+ GEN_INT (newconst), 1);
+ }
+ validate_change (insn, recog_operand_loc[match_number], src, 1);
+ if (validate_replace_rtx (dst, src_subreg, p))
+ success = 1;
+ break;
+ }
+
+ if (reg_overlap_mentioned_p (dst, PATTERN (p)))
+ break;
+ if (! src_note && reg_overlap_mentioned_p (src, PATTERN (p)))
+ {
+ /* INSN was already checked to be movable when
+ we found no REG_DEAD note for src on it. */
+ overlap = p;
+ src_note = find_reg_note (p, REG_DEAD, src);
+ }
+
+ /* If we have passed a call instruction, and the pseudo-reg SRC is not
+ already live across a call, then don't perform the optimization. */
+ if (GET_CODE (p) == CALL_INSN)
+ {
+ if (REG_N_CALLS_CROSSED (REGNO (src)) == 0)
+ break;
+
+ num_calls++;
+
+ if (src_note)
+ s_num_calls++;
+
+ }
+ }
+
+ if (! success)
+ return 0;
+
+ true_loop_depth = backward ? 2 - loop_depth : loop_depth;
+
+ /* Remove the death note for DST from P. */
+ remove_note (p, dst_note);
+ if (code == MINUS)
+ {
+ post_inc = emit_insn_after (copy_rtx (PATTERN (insn)), p);
+#if defined (HAVE_PRE_INCREMENT) || defined (HAVE_PRE_DECREMENT)
+ if (search_end
+ && try_auto_increment (search_end, post_inc, 0, src, newconst, 1))
+ post_inc = 0;
+#endif
+ validate_change (insn, &XEXP (SET_SRC (set), 1), GEN_INT (insn_const), 0);
+ REG_N_SETS (REGNO (src))++;
+ REG_N_REFS (REGNO (src)) += true_loop_depth;
+ REG_LIVE_LENGTH (REGNO (src))++;
+ }
+ if (overlap)
+ {
+ /* The lifetime of src and dest overlap,
+ but we can change this by moving insn. */
+ rtx pat = PATTERN (insn);
+ if (src_note)
+ remove_note (overlap, src_note);
+#if defined (HAVE_POST_INCREMENT) || defined (HAVE_POST_DECREMENT)
+ if (code == PLUS
+ && try_auto_increment (overlap, insn, 0, src, insn_const, 0))
+ insn = overlap;
+ else
+#endif
+ {
+ rtx notes = REG_NOTES (insn);
+
+ emit_insn_after_with_line_notes (pat, PREV_INSN (p), insn);
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ /* emit_insn_after_with_line_notes has no
+ return value, so search for the new insn. */
+ for (insn = p; PATTERN (insn) != pat; )
+ insn = PREV_INSN (insn);
+
+ REG_NOTES (insn) = notes;
+ }
+ }
+ /* Sometimes we'd generate src = const; src += n;
+ if so, replace the instruction that set src
+ in the first place. */
+
+ if (! overlap && (code == PLUS || code == MINUS))
+ {
+ rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+ rtx q, set2;
+ int num_calls2 = 0, s_length2 = 0;
+
+ if (note && CONSTANT_P (XEXP (note, 0)))
+ {
+ for (q = PREV_INSN (insn); q; q = PREV_INSN(q))
+ {
+ if (GET_CODE (q) == CODE_LABEL || GET_CODE (q) == JUMP_INSN
+ || (GET_CODE (q) == NOTE
+ && (NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_END)))
+ {
+ q = 0;
+ break;
+ }
+
+ /* ??? We can't scan past the end of a basic block without
+ updating the register lifetime info
+ (REG_DEAD/basic_block_live_at_start).
+ A CALL_INSN might be the last insn of a basic block, if
+ it is inside an EH region. There is no easy way to tell,
+ so we just always break when we see a CALL_INSN if
+ flag_exceptions is nonzero. */
+ if (flag_exceptions && GET_CODE (q) == CALL_INSN)
+ {
+ q = 0;
+ break;
+ }
+
+ if (GET_RTX_CLASS (GET_CODE (q)) != 'i')
+ continue;
+ s_length2++;
+ if (reg_set_p (src, q))
+ {
+ set2 = single_set (q);
+ break;
+ }
+ if (reg_overlap_mentioned_p (src, PATTERN (q)))
+ {
+ q = 0;
+ break;
+ }
+ if (GET_CODE (p) == CALL_INSN)
+ num_calls2++;
+ }
+ if (q && set2 && SET_DEST (set2) == src && CONSTANT_P (SET_SRC (set2))
+ && validate_change (insn, &SET_SRC (set), XEXP (note, 0), 0))
+ {
+ PUT_CODE (q, NOTE);
+ NOTE_LINE_NUMBER (q) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (q) = 0;
+ REG_N_SETS (REGNO (src))--;
+ REG_N_CALLS_CROSSED (REGNO (src)) -= num_calls2;
+ REG_N_REFS (REGNO (src)) -= true_loop_depth;
+ REG_LIVE_LENGTH (REGNO (src)) -= s_length2;
+ insn_const = 0;
+ }
+ }
+ }
+
+ /* Don't remove this seemingly useless if, it is needed to pair with the
+ else in the next two conditionally included code blocks. */
+ if (0)
+ {;}
+#if defined (HAVE_PRE_INCREMENT) || defined (HAVE_PRE_DECREMENT)
+ else if ((code == PLUS || code == MINUS) && insn_const
+ && try_auto_increment (p, insn, 0, src, insn_const, 1))
+ insn = p;
+#endif
+#if defined (HAVE_POST_INCREMENT) || defined (HAVE_POST_DECREMENT)
+ else if (post_inc
+ && try_auto_increment (p, post_inc, post_inc_set, src, newconst, 0))
+ post_inc = 0;
+#endif
+#if defined (HAVE_PRE_INCREMENT) || defined (HAVE_PRE_DECREMENT)
+ /* If post_inc still prevails, try to find an
+ insn where it can be used as a pre-in/decrement.
+ If code is MINUS, this was already tried. */
+ if (post_inc && code == PLUS
+ /* Check that newconst is likely to be usable
+ in a pre-in/decrement before starting the search. */
+ && (0
+#if defined (HAVE_PRE_INCREMENT)
+ || (newconst > 0 && newconst <= MOVE_MAX)
+#endif
+#if defined (HAVE_PRE_DECREMENT)
+ || (newconst < 0 && newconst >= -MOVE_MAX)
+#endif
+ ) && exact_log2 (newconst))
+ {
+ rtx q, inc_dest;
+
+ inc_dest = post_inc_set ? SET_DEST (post_inc_set) : src;
+ for (q = post_inc; (q = NEXT_INSN (q)); )
+ {
+ if (GET_CODE (q) == CODE_LABEL || GET_CODE (q) == JUMP_INSN
+ || (GET_CODE (q) == NOTE
+ && (NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_BEG
+ || NOTE_LINE_NUMBER (q) == NOTE_INSN_LOOP_END)))
+ break;
+
+ /* ??? We can't scan past the end of a basic block without updating
+ the register lifetime info (REG_DEAD/basic_block_live_at_start).
+ A CALL_INSN might be the last insn of a basic block, if it
+ is inside an EH region. There is no easy way to tell so we
+ just always break when we see a CALL_INSN if flag_exceptions
+ is nonzero. */
+ if (flag_exceptions && GET_CODE (q) == CALL_INSN)
+ break;
+
+ if (GET_RTX_CLASS (GET_CODE (q)) != 'i')
+ continue;
+ if (src != inc_dest && (reg_overlap_mentioned_p (src, PATTERN (q))
+ || reg_set_p (src, q)))
+ break;
+ if (reg_set_p (inc_dest, q))
+ break;
+ if (reg_overlap_mentioned_p (inc_dest, PATTERN (q)))
+ {
+ try_auto_increment (q, post_inc,
+ post_inc_set, inc_dest, newconst, 1);
+ break;
+ }
+ }
+ }
+#endif /* defined (HAVE_PRE_INCREMENT) || defined (HAVE_PRE_DECREMENT) */
+ /* Move the death note for DST to INSN if it is used
+ there. */
+ if (reg_overlap_mentioned_p (dst, PATTERN (insn)))
+ {
+ XEXP (dst_note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = dst_note;
+ }
+
+ if (src_note)
+ {
+ /* Move the death note for SRC from INSN to P. */
+ if (! overlap)
+ remove_note (insn, src_note);
+ XEXP (src_note, 1) = REG_NOTES (p);
+ REG_NOTES (p) = src_note;
+
+ REG_N_CALLS_CROSSED (REGNO (src)) += s_num_calls;
+ }
+
+ REG_N_SETS (REGNO (src))++;
+ REG_N_SETS (REGNO (dst))--;
+
+ REG_N_CALLS_CROSSED (REGNO (dst)) -= num_calls;
+
+ REG_LIVE_LENGTH (REGNO (src)) += s_length;
+ if (REG_LIVE_LENGTH (REGNO (dst)) >= 0)
+ {
+ REG_LIVE_LENGTH (REGNO (dst)) -= length;
+ /* REG_LIVE_LENGTH is only an approximation after
+ combine if sched is not run, so make sure that we
+ still have a reasonable value. */
+ if (REG_LIVE_LENGTH (REGNO (dst)) < 2)
+ REG_LIVE_LENGTH (REGNO (dst)) = 2;
+ }
+
+ /* We assume that a register is used exactly once per
+ insn in the updates above. If this is not correct,
+ no great harm is done. */
+
+ REG_N_REFS (REGNO (src)) += 2 * true_loop_depth;
+ REG_N_REFS (REGNO (dst)) -= 2 * true_loop_depth;
+
+ /* If that was the only time dst was set,
+ and dst was not live at the start of the
+ function, we know that we have no more
+ references to dst; clear REG_N_REFS so it
+ won't make reload do any work. */
+ if (REG_N_SETS (REGNO (dst)) == 0
+ && ! regno_uninitialized (REGNO (dst)))
+ REG_N_REFS (REGNO (dst)) = 0;
+
+ if (regmove_dump_file)
+ fprintf (regmove_dump_file,
+ "Fixed operand %d of insn %d matching operand %d.\n",
+ operand_number, INSN_UID (insn), match_number);
+ return 1;
+}
+
+
+/* return nonzero if X is stable but for mentioning SRC or mentioning /
+ changing DST . If in doubt, presume it is unstable. */
+static int
+stable_but_for_p (x, src, dst)
+ rtx x, src, dst;
+{
+ RTX_CODE code = GET_CODE (x);
+ switch (GET_RTX_CLASS (code))
+ {
+ case '<': case '1': case 'c': case '2': case 'b': case '3':
+ {
+ int i;
+ char *fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ if (fmt[i] == 'e' && ! stable_but_for_p (XEXP (x, i), src, dst))
+ return 0;
+ return 1;
+ }
+ case 'o':
+ if (x == src || x == dst)
+ return 1;
+ /* fall through */
+ default:
+ return ! rtx_unstable_p (x);
+ }
+}
+
+/* Test if regmove seems profitable for this target. Regmove is useful only
+ if some common patterns are two address, i.e. require matching constraints,
+ so we check that condition here. */
+
+int
+regmove_profitable_p ()
+{
+#ifdef REGISTER_CONSTRAINTS
+ struct match match;
+ enum machine_mode mode;
+ optab tstoptab = add_optab;
+ do /* check add_optab and ashl_optab */
+ for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
+ mode = GET_MODE_WIDER_MODE (mode))
+ {
+ int icode = (int) tstoptab->handlers[(int) mode].insn_code;
+ rtx reg0, reg1, reg2, pat;
+ int i;
+
+ if (GET_MODE_BITSIZE (mode) < 32 || icode == CODE_FOR_nothing)
+ continue;
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (reg_class_contents[GENERAL_REGS], i))
+ break;
+ if (i + 2 >= FIRST_PSEUDO_REGISTER)
+ break;
+ reg0 = gen_rtx_REG (insn_operand_mode[icode][0], i);
+ reg1 = gen_rtx_REG (insn_operand_mode[icode][1], i + 1);
+ reg2 = gen_rtx_REG (insn_operand_mode[icode][2], i + 2);
+ if (! (*insn_operand_predicate[icode][0]) (reg0, VOIDmode)
+ || ! (*insn_operand_predicate[icode][1]) (reg1, VOIDmode)
+ || ! (*insn_operand_predicate[icode][2]) (reg2, VOIDmode))
+ break;
+ pat = GEN_FCN (icode) (reg0, reg1, reg2);
+ if (! pat)
+ continue;
+ if (GET_CODE (pat) == SEQUENCE)
+ pat = XVECEXP (pat, 0, XVECLEN (pat, 0) - 1);
+ else
+ pat = make_insn_raw (pat);
+ if (! single_set (pat)
+ || GET_CODE (SET_SRC (single_set (pat))) != tstoptab->code)
+ /* Unexpected complexity; don't need to handle this unless
+ we find a machine where this occurs and regmove should
+ be enabled. */
+ break;
+ if (find_matches (pat, &match) >= 0)
+ return 1;
+ break;
+ }
+ while (tstoptab != ashl_optab && (tstoptab = ashl_optab, 1));
+#endif /* REGISTER_CONSTRAINTS */
+ return 0;
+}
diff --git a/contrib/gcc/regs.h b/contrib/gcc/regs.h
index daa012e..e248665 100644
--- a/contrib/gcc/regs.h
+++ b/contrib/gcc/regs.h
@@ -1,5 +1,5 @@
/* Define per-register tables for data flow info and register allocation.
- Copyright (C) 1987, 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1993, 1994, 1995, 1997, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,6 +19,7 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#include "varray.h"
#define REG_BYTES(R) mode_size[(int) GET_MODE (R)]
@@ -29,6 +30,10 @@ Boston, MA 02111-1307, USA. */
#define REG_SIZE(R) \
((mode_size[(int) GET_MODE (R)] + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+#ifndef SMALL_REGISTER_CLASSES
+#define SMALL_REGISTER_CLASSES 0
+#endif
+
/* Maximum register number used in this function, plus one. */
extern int max_regno;
@@ -37,14 +42,39 @@ extern int max_regno;
extern int max_scratch;
+/* Register information indexed by register number */
+typedef struct reg_info_def {
+ /* fields set by reg_scan */
+ int first_uid; /* UID of first insn to use (REG n) */
+ int last_uid; /* UID of last insn to use (REG n) */
+ int last_note_uid; /* UID of last note to use (REG n) */
+
+ /* fields set by both reg_scan and flow_analysis */
+ int sets; /* # of times (REG n) is set */
+
+ /* fields set by flow_analysis */
+ int refs; /* # of times (REG n) is used or set */
+ int deaths; /* # of times (REG n) dies */
+ int live_length; /* # of instructions (REG n) is live */
+ int calls_crossed; /* # of calls (REG n) is live across */
+ int basic_block; /* # of basic blocks (REG n) is used in */
+ char changes_size; /* whether (SUBREG (REG n)) changes size */
+} reg_info;
+
+extern varray_type reg_n_info;
+
+extern unsigned int reg_n_max;
+
/* Indexed by n, gives number of times (REG n) is used or set.
References within loops may be counted more times. */
-extern int *reg_n_refs;
+#define REG_N_REFS(N) (VARRAY_REG (reg_n_info, N)->refs)
-/* Indexed by n, gives number of times (REG n) is set. */
+/* Indexed by n, gives number of times (REG n) is set.
+ ??? both regscan and flow allocate space for this. We should settle
+ on just copy. */
-extern short *reg_n_sets;
+#define REG_N_SETS(N) (VARRAY_REG (reg_n_info, N)->sets)
/* Indexed by N, gives number of insns in which register N dies.
Note that if register N is live around loops, it can die
@@ -52,13 +82,13 @@ extern short *reg_n_sets;
So this is only a reliable indicator of how many regions of life there are
for registers that are contained in one basic block. */
-extern short *reg_n_deaths;
+#define REG_N_DEATHS(N) (VARRAY_REG (reg_n_info, N)->deaths)
/* Indexed by N; says whether a pseudo register N was ever used
within a SUBREG that changes the size of the reg. Some machines prohibit
such objects to be in certain (usually floating-point) registers. */
-extern char *reg_changes_size;
+#define REG_CHANGES_SIZE(N) (VARRAY_REG (reg_n_info, N)->changes_size)
/* Get the number of consecutive words required to hold pseudo-reg N. */
@@ -77,7 +107,7 @@ extern char *reg_changes_size;
/* Indexed by N, gives number of CALL_INSNS across which (REG n) is live. */
-extern int *reg_n_calls_crossed;
+#define REG_N_CALLS_CROSSED(N) (VARRAY_REG (reg_n_info, N)->calls_crossed)
/* Total number of instructions at which (REG n) is live.
The larger this is, the less priority (REG n) gets for
@@ -94,10 +124,14 @@ extern int *reg_n_calls_crossed;
is not required. global.c makes an allocno for this but does
not try to assign a hard register to it. */
-extern int *reg_live_length;
+#define REG_LIVE_LENGTH(N) (VARRAY_REG (reg_n_info, N)->live_length)
/* Vector of substitutions of register numbers,
- used to map pseudo regs into hardware regs. */
+ used to map pseudo regs into hardware regs.
+
+ This can't be folded into reg_n_info without changing all of the
+ machine dependent directories, since the reload functions
+ in the machine dependent files access it. */
extern short *reg_renumber;
@@ -122,7 +156,7 @@ extern enum machine_mode reg_raw_mode[FIRST_PSEUDO_REGISTER];
It is sometimes adjusted for subsequent changes during loop,
but not adjusted by cse even if cse invalidates it. */
-extern int *regno_first_uid;
+#define REGNO_FIRST_UID(N) (VARRAY_REG (reg_n_info, N)->first_uid)
/* Vector indexed by regno; gives uid of last insn using that reg.
This is computed by reg_scan for use by cse and loop.
@@ -130,11 +164,16 @@ extern int *regno_first_uid;
but not adjusted by cse even if cse invalidates it.
This is harmless since cse won't scan through a loop end. */
-extern int *regno_last_uid;
+#define REGNO_LAST_UID(N) (VARRAY_REG (reg_n_info, N)->last_uid)
/* Similar, but includes insns that mention the reg in their notes. */
-extern int *regno_last_note_uid;
+#define REGNO_LAST_NOTE_UID(N) (VARRAY_REG (reg_n_info, N)->last_note_uid)
+
+/* This is reset to LAST_VIRTUAL_REGISTER + 1 at the start of each function.
+ After rtl generation, it is 1 plus the largest register number used. */
+
+extern int reg_rtx_no;
/* Vector indexed by regno; contains 1 for a register is considered a pointer.
Reloading, etc. will use a pointer register rather than a non-pointer
@@ -142,6 +181,7 @@ extern int *regno_last_note_uid;
extern char *regno_pointer_flag;
#define REGNO_POINTER_FLAG(REGNO) regno_pointer_flag[REGNO]
+extern int regno_pointer_flag_length;
/* List made of EXPR_LIST rtx's which gives pairs of pseudo registers
that have to go in the same hard reg. */
@@ -165,6 +205,12 @@ extern int caller_save_needed;
#define CALLER_SAVE_PROFITABLE(REFS, CALLS) (4 * (CALLS) < (REFS))
#endif
+/* On most machines a register class is likely to be spilled if it
+ only has one register. */
+#ifndef CLASS_LIKELY_SPILLED_P
+#define CLASS_LIKELY_SPILLED_P(CLASS) (reg_class_size[(int) (CLASS)] == 1)
+#endif
+
/* Allocated in local_alloc. */
/* A list of SCRATCH rtl allocated by local-alloc. */
@@ -173,3 +219,6 @@ extern rtx *scratch_list;
extern int *scratch_block;
/* The length of the arrays pointed to by scratch_block and scratch_list. */
extern int scratch_list_length;
+
+/* Allocate reg_n_info tables */
+extern void allocate_reg_info PROTO((size_t, int, int));
diff --git a/contrib/gcc/reload.c b/contrib/gcc/reload.c
index d797e74..b1483d1 100644
--- a/contrib/gcc/reload.c
+++ b/contrib/gcc/reload.c
@@ -1,5 +1,5 @@
/* Search an insn for pseudo regs that must be in hard regs and are not.
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -87,8 +87,8 @@ a register with any other reload. */
#define REG_OK_STRICT
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "insn-config.h"
#include "insn-codes.h"
@@ -99,10 +99,20 @@ a register with any other reload. */
#include "flags.h"
#include "real.h"
#include "output.h"
+#include "expr.h"
+#include "toplev.h"
#ifndef REGISTER_MOVE_COST
#define REGISTER_MOVE_COST(x, y) 2
#endif
+
+#ifndef REGNO_MODE_OK_FOR_BASE_P
+#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) REGNO_OK_FOR_BASE_P (REGNO)
+#endif
+
+#ifndef REG_MODE_OK_FOR_BASE_P
+#define REG_MODE_OK_FOR_BASE_P(REGNO, MODE) REG_OK_FOR_BASE_P (REGNO)
+#endif
/* The variables set up by `find_reloads' are:
@@ -119,6 +129,8 @@ a register with any other reload. */
reload_optional char, nonzero for an optional reload.
Optional reloads are ignored unless the
value is already sitting in a register.
+ reload_nongroup char, nonzero when a reload must use a register
+ not already allocated to a group.
reload_inc int, positive amount to increment or decrement by if
reload_in is a PRE_DEC, PRE_INC, POST_DEC, POST_INC.
Ignored otherwise (don't assume it is zero).
@@ -166,6 +178,7 @@ enum machine_mode reload_inmode[MAX_RELOADS];
enum machine_mode reload_outmode[MAX_RELOADS];
rtx reload_reg_rtx[MAX_RELOADS];
char reload_optional[MAX_RELOADS];
+char reload_nongroup[MAX_RELOADS];
int reload_inc[MAX_RELOADS];
rtx reload_in_reg[MAX_RELOADS];
char reload_nocombine[MAX_RELOADS];
@@ -212,10 +225,10 @@ static int n_replacements;
/* Used to track what is modified by an operand. */
struct decomposition
{
- int reg_flag; /* Nonzero if referencing a register. */
- int safe; /* Nonzero if this can't conflict with anything. */
- rtx base; /* Base address for MEM. */
- HOST_WIDE_INT start; /* Starting offset or register number. */
+ int reg_flag; /* Nonzero if referencing a register. */
+ int safe; /* Nonzero if this can't conflict with anything. */
+ rtx base; /* Base address for MEM. */
+ HOST_WIDE_INT start; /* Starting offset or register number. */
HOST_WIDE_INT end; /* Ending offset or register number. */
};
@@ -251,7 +264,7 @@ static int this_insn_is_asm;
static int hard_regs_live_known;
/* Indexed by hard reg number,
- element is nonegative if hard reg has been spilled.
+ element is nonnegative if hard reg has been spilled.
This vector is passed to `find_reloads' as an argument
and is not changed here. */
static short *static_reload_reg_p;
@@ -288,9 +301,21 @@ static int output_reloadnum;
|| (when1) == RELOAD_FOR_OPERAND_ADDRESS \
|| (when1) == RELOAD_FOR_OTHER_ADDRESS))
+ /* If we are going to reload an address, compute the reload type to
+ use. */
+#define ADDR_TYPE(type) \
+ ((type) == RELOAD_FOR_INPUT_ADDRESS \
+ ? RELOAD_FOR_INPADDR_ADDRESS \
+ : ((type) == RELOAD_FOR_OUTPUT_ADDRESS \
+ ? RELOAD_FOR_OUTADDR_ADDRESS \
+ : (type)))
+
+#ifdef HAVE_SECONDARY_RELOADS
static int push_secondary_reload PROTO((int, rtx, int, int, enum reg_class,
enum machine_mode, enum reload_type,
enum insn_code *));
+#endif
+static enum reg_class find_valid_class PROTO((enum machine_mode, int));
static int push_reload PROTO((rtx, rtx, rtx *, rtx *, enum reg_class,
enum machine_mode, enum machine_mode,
int, int, int, enum reload_type));
@@ -298,7 +323,7 @@ static void push_replacement PROTO((rtx *, int, enum machine_mode));
static void combine_reloads PROTO((void));
static rtx find_dummy_reload PROTO((rtx, rtx, rtx *, rtx *,
enum machine_mode, enum machine_mode,
- enum reg_class, int));
+ enum reg_class, int, int));
static int earlyclobber_operand_p PROTO((rtx));
static int hard_reg_set_here_p PROTO((int, int, rtx));
static struct decomposition decompose PROTO((rtx));
@@ -307,11 +332,11 @@ static int alternative_allows_memconst PROTO((char *, int));
static rtx find_reloads_toplev PROTO((rtx, int, enum reload_type, int, int));
static rtx make_memloc PROTO((rtx, int));
static int find_reloads_address PROTO((enum machine_mode, rtx *, rtx, rtx *,
- int, enum reload_type, int));
+ int, enum reload_type, int, rtx));
static rtx subst_reg_equivs PROTO((rtx));
static rtx subst_indexed_address PROTO((rtx));
-static int find_reloads_address_1 PROTO((rtx, int, rtx *, int,
- enum reload_type,int));
+static int find_reloads_address_1 PROTO((enum machine_mode, rtx, int, rtx *,
+ int, enum reload_type,int, rtx));
static void find_reloads_address_part PROTO((rtx, rtx *, enum reg_class,
enum machine_mode, int,
enum reload_type, int));
@@ -347,10 +372,12 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
enum machine_mode t_mode = VOIDmode;
enum insn_code t_icode = CODE_FOR_nothing;
enum reload_type secondary_type;
- int i;
int s_reload, t_reload = -1;
- if (type == RELOAD_FOR_INPUT_ADDRESS || type == RELOAD_FOR_OUTPUT_ADDRESS)
+ if (type == RELOAD_FOR_INPUT_ADDRESS
+ || type == RELOAD_FOR_OUTPUT_ADDRESS
+ || type == RELOAD_FOR_INPADDR_ADDRESS
+ || type == RELOAD_FOR_OUTADDR_ADDRESS)
secondary_type = type;
else
secondary_type = in_p ? RELOAD_FOR_INPUT_ADDRESS : RELOAD_FOR_OUTPUT_ADDRESS;
@@ -474,11 +501,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
== CODE_FOR_nothing))
|| (! in_p &&(reload_secondary_out_icode[t_reload]
== CODE_FOR_nothing)))
- && (reg_class_size[(int) t_class] == 1
-#ifdef SMALL_REGISTER_CLASSES
- || 1
-#endif
- )
+ && (reg_class_size[(int) t_class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (secondary_type,
reload_when_needed[t_reload],
opnum, reload_opnum[t_reload]))
@@ -508,6 +531,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
reload_outmode[t_reload] = ! in_p ? t_mode : VOIDmode;
reload_reg_rtx[t_reload] = 0;
reload_optional[t_reload] = optional;
+ reload_nongroup[t_reload] = 0;
reload_inc[t_reload] = 0;
/* Maybe we could combine these, but it seems too tricky. */
reload_nocombine[t_reload] = 1;
@@ -535,11 +559,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
|| (! in_p && reload_secondary_out_reload[s_reload] == t_reload))
&& ((in_p && reload_secondary_in_icode[s_reload] == t_icode)
|| (! in_p && reload_secondary_out_icode[s_reload] == t_icode))
- && (reg_class_size[(int) class] == 1
-#ifdef SMALL_REGISTER_CLASSES
- || 1
-#endif
- )
+ && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (secondary_type, reload_when_needed[s_reload],
opnum, reload_opnum[s_reload]))
{
@@ -561,6 +581,17 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
if (s_reload == n_reloads)
{
+#ifdef SECONDARY_MEMORY_NEEDED
+ /* If we need a memory location to copy between the two reload regs,
+ set it up now. Note that we do the input case before making
+ the reload and the output case after. This is due to the
+ way reloads are output. */
+
+ if (in_p && icode == CODE_FOR_nothing
+ && SECONDARY_MEMORY_NEEDED (class, reload_class, mode))
+ get_secondary_mem (x, reload_mode, opnum, type);
+#endif
+
/* We need to make a new secondary reload for this register class. */
reload_in[s_reload] = reload_out[s_reload] = 0;
reload_reg_class[s_reload] = class;
@@ -569,6 +600,7 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
reload_outmode[s_reload] = ! in_p ? mode : VOIDmode;
reload_reg_rtx[s_reload] = 0;
reload_optional[s_reload] = optional;
+ reload_nongroup[s_reload] = 0;
reload_inc[s_reload] = 0;
/* Maybe we could combine these, but it seems too tricky. */
reload_nocombine[s_reload] = 1;
@@ -585,16 +617,9 @@ push_secondary_reload (in_p, x, opnum, optional, reload_class, reload_mode,
n_reloads++;
#ifdef SECONDARY_MEMORY_NEEDED
- /* If we need a memory location to copy between the two reload regs,
- set it up now. */
-
- if (in_p && icode == CODE_FOR_nothing
- && SECONDARY_MEMORY_NEEDED (class, reload_class, reload_mode))
- get_secondary_mem (x, reload_mode, opnum, type);
-
if (! in_p && icode == CODE_FOR_nothing
- && SECONDARY_MEMORY_NEEDED (reload_class, class, reload_mode))
- get_secondary_mem (x, reload_mode, opnum, type);
+ && SECONDARY_MEMORY_NEEDED (reload_class, class, mode))
+ get_secondary_mem (x, mode, opnum, type);
#endif
}
@@ -672,7 +697,7 @@ get_secondary_mem (x, mode, opnum, type)
: RELOAD_OTHER);
find_reloads_address (mode, NULL_PTR, XEXP (loc, 0), &XEXP (loc, 0),
- opnum, type, 0);
+ opnum, type, 0, 0);
}
secondary_memlocs_elim[(int) mode][opnum] = loc;
@@ -688,6 +713,38 @@ clear_secondary_mem ()
}
#endif /* SECONDARY_MEMORY_NEEDED */
+/* Find the largest class for which every register number plus N is valid in
+ M1 (if in range). Abort if no such class exists. */
+
+static enum reg_class
+find_valid_class (m1, n)
+ enum machine_mode m1;
+ int n;
+{
+ int class;
+ int regno;
+ enum reg_class best_class;
+ int best_size = 0;
+
+ for (class = 1; class < N_REG_CLASSES; class++)
+ {
+ int bad = 0;
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER && ! bad; regno++)
+ if (TEST_HARD_REG_BIT (reg_class_contents[class], regno)
+ && TEST_HARD_REG_BIT (reg_class_contents[class], regno + n)
+ && ! HARD_REGNO_MODE_OK (regno + n, m1))
+ bad = 1;
+
+ if (! bad && reg_class_size[class] > best_size)
+ best_class = class, best_size = reg_class_size[class];
+ }
+
+ if (best_size == 0)
+ abort ();
+
+ return best_class;
+}
+
/* Record one reload that needs to be performed.
IN is an rtx saying where the data are to be found before this instruction.
OUT says where they must be stored after the instruction.
@@ -780,10 +837,10 @@ push_reload (in, out, inloc, outloc, class,
{
if (GET_CODE (XEXP (in, 0)) == POST_INC
|| GET_CODE (XEXP (in, 0)) == POST_DEC)
- in = gen_rtx (MEM, GET_MODE (in), XEXP (XEXP (in, 0), 0));
+ in = gen_rtx_MEM (GET_MODE (in), XEXP (XEXP (in, 0), 0));
if (GET_CODE (XEXP (in, 0)) == PRE_INC
|| GET_CODE (XEXP (in, 0)) == PRE_DEC)
- out = gen_rtx (MEM, GET_MODE (out), XEXP (XEXP (out, 0), 0));
+ out = gen_rtx_MEM (GET_MODE (out), XEXP (XEXP (out, 0), 0));
}
/* If we are reloading a (SUBREG constant ...), really reload just the
@@ -813,7 +870,7 @@ push_reload (in, out, inloc, outloc, class,
the class whose registers cannot be referenced in a different size
and M1 is not the same size as M2. If SUBREG_WORD is nonzero, we
cannot reload just the inside since we might end up with the wrong
- register class. */
+ register class. */
if (in != 0 && GET_CODE (in) == SUBREG && SUBREG_WORD (in) == 0
#ifdef CLASS_CANNOT_CHANGE_SIZE
@@ -836,6 +893,13 @@ push_reload (in, out, inloc, outloc, class,
&& INTEGRAL_MODE_P (GET_MODE (SUBREG_REG (in)))
&& LOAD_EXTEND_OP (GET_MODE (SUBREG_REG (in))) != NIL)
#endif
+#ifdef WORD_REGISTER_OPERATIONS
+ || ((GET_MODE_SIZE (inmode)
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))))
+ && ((GET_MODE_SIZE (inmode) - 1) / UNITS_PER_WORD ==
+ ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in))) - 1)
+ / UNITS_PER_WORD)))
+#endif
))
|| (GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
@@ -873,7 +937,7 @@ push_reload (in, out, inloc, outloc, class,
in_subreg_loc = inloc;
inloc = &SUBREG_REG (in);
in = *inloc;
-#ifndef LOAD_EXTEND_OP
+#if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS)
if (GET_CODE (in) == MEM)
/* This is supposed to happen only for paradoxical subregs made by
combine.c. (SUBREG (MEM)) isn't supposed to occur other ways. */
@@ -890,17 +954,23 @@ push_reload (in, out, inloc, outloc, class,
However, we must reload the inner reg *as well as* the subreg in
that case. */
+ /* Similar issue for (SUBREG constant ...) if it was not handled by the
+ code above. This can happen if SUBREG_WORD != 0. */
+
if (in != 0 && GET_CODE (in) == SUBREG
- && GET_CODE (SUBREG_REG (in)) == REG
- && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
- && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in)), inmode)
- || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
- > UNITS_PER_WORD)
- && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
- / UNITS_PER_WORD)
- != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
- GET_MODE (SUBREG_REG (in)))))))
+ && (CONSTANT_P (SUBREG_REG (in))
+ || (GET_CODE (SUBREG_REG (in)) == REG
+ && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
+ && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (in))
+ + SUBREG_WORD (in),
+ inmode)
+ || (GET_MODE_SIZE (inmode) <= UNITS_PER_WORD
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+ > UNITS_PER_WORD)
+ && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (in)))
+ / UNITS_PER_WORD)
+ != HARD_REGNO_NREGS (REGNO (SUBREG_REG (in)),
+ GET_MODE (SUBREG_REG (in)))))))))
{
/* This relies on the fact that emit_reload_insns outputs the
instructions for input reloads of type RELOAD_OTHER in the same
@@ -908,11 +978,11 @@ push_reload (in, out, inloc, outloc, class,
RELOAD_OTHER, we are guaranteed that this inner reload will be
output before the outer reload. */
push_reload (SUBREG_REG (in), NULL_RTX, &SUBREG_REG (in), NULL_PTR,
- GENERAL_REGS, VOIDmode, VOIDmode, 0, 0, opnum, type);
+ find_valid_class (inmode, SUBREG_WORD (in)),
+ VOIDmode, VOIDmode, 0, 0, opnum, type);
dont_remove_subreg = 1;
}
-
/* Similarly for paradoxical and problematical SUBREGs on the output.
Note that there is no reason we need worry about the previous value
of SUBREG_REG (out); even if wider than out,
@@ -929,7 +999,15 @@ push_reload (in, out, inloc, outloc, class,
&& REGNO (SUBREG_REG (out)) >= FIRST_PSEUDO_REGISTER)
|| GET_CODE (SUBREG_REG (out)) == MEM)
&& ((GET_MODE_SIZE (outmode)
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
+#ifdef WORD_REGISTER_OPERATIONS
+ || ((GET_MODE_SIZE (outmode)
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))))
+ && ((GET_MODE_SIZE (outmode) - 1) / UNITS_PER_WORD ==
+ ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (out))) - 1)
+ / UNITS_PER_WORD)))
+#endif
+ ))
|| (GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& ((GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
@@ -963,7 +1041,7 @@ push_reload (in, out, inloc, outloc, class,
out_subreg_loc = outloc;
outloc = &SUBREG_REG (out);
out = *outloc;
-#ifndef LOAD_EXTEND_OP
+#if ! defined (LOAD_EXTEND_OP) && ! defined (WORD_REGISTER_OPERATIONS)
if (GET_CODE (out) == MEM
&& GET_MODE_SIZE (GET_MODE (out)) > GET_MODE_SIZE (outmode))
abort ();
@@ -981,7 +1059,8 @@ push_reload (in, out, inloc, outloc, class,
if (out != 0 && GET_CODE (out) == SUBREG
&& GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
- && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (out)), outmode)
+ && (! HARD_REGNO_MODE_OK (REGNO (SUBREG_REG (out)) + SUBREG_WORD (out),
+ outmode)
|| (GET_MODE_SIZE (outmode) <= UNITS_PER_WORD
&& (GET_MODE_SIZE (GET_MODE (SUBREG_REG (out)))
> UNITS_PER_WORD)
@@ -997,7 +1076,9 @@ push_reload (in, out, inloc, outloc, class,
output after the outer reload. */
dont_remove_subreg = 1;
push_reload (SUBREG_REG (out), SUBREG_REG (out), &SUBREG_REG (out),
- &SUBREG_REG (out), ALL_REGS, VOIDmode, VOIDmode, 0, 0,
+ &SUBREG_REG (out),
+ find_valid_class (outmode, SUBREG_WORD (out)),
+ VOIDmode, VOIDmode, 0, 0,
opnum, RELOAD_OTHER);
}
@@ -1013,16 +1094,16 @@ push_reload (in, out, inloc, outloc, class,
if (in != 0 && GET_CODE (in) == SUBREG && GET_CODE (SUBREG_REG (in)) == REG
&& REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER
&& ! dont_remove_subreg)
- in = gen_rtx (REG, GET_MODE (in),
- REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
+ in = gen_rtx_REG (GET_MODE (in),
+ REGNO (SUBREG_REG (in)) + SUBREG_WORD (in));
/* Similarly for OUT. */
if (out != 0 && GET_CODE (out) == SUBREG
&& GET_CODE (SUBREG_REG (out)) == REG
&& REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER
&& ! dont_remove_subreg)
- out = gen_rtx (REG, GET_MODE (out),
- REGNO (SUBREG_REG (out)) + SUBREG_WORD (out));
+ out = gen_rtx_REG (GET_MODE (out),
+ REGNO (SUBREG_REG (out)) + SUBREG_WORD (out));
/* Narrow down the class of register wanted if that is
desirable on this machine for efficiency. */
@@ -1113,11 +1194,7 @@ push_reload (in, out, inloc, outloc, class,
||
(out != 0 && MATCHES (reload_out[i], out)
&& (in == 0 || reload_in[i] == 0 || MATCHES (reload_in[i], in))))
- && (reg_class_size[(int) class] == 1
-#ifdef SMALL_REGISTER_CLASSES
- || 1
-#endif
- )
+ && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (type, reload_when_needed[i],
opnum, reload_opnum[i]))
break;
@@ -1149,11 +1226,7 @@ push_reload (in, out, inloc, outloc, class,
|| GET_CODE (in) == PRE_INC
|| GET_CODE (in) == PRE_DEC)
&& MATCHES (XEXP (in, 0), reload_in[i])))
- && (reg_class_size[(int) class] == 1
-#ifdef SMALL_REGISTER_CLASSES
- || 1
-#endif
- )
+ && (reg_class_size[(int) class] == 1 || SMALL_REGISTER_CLASSES)
&& MERGABLE_RELOADS (type, reload_when_needed[i],
opnum, reload_opnum[i]))
{
@@ -1187,6 +1260,15 @@ push_reload (in, out, inloc, outloc, class,
/* We found no existing reload suitable for re-use.
So add an additional reload. */
+#ifdef SECONDARY_MEMORY_NEEDED
+ /* If a memory location is needed for the copy, make one. */
+ if (in != 0 && GET_CODE (in) == REG
+ && REGNO (in) < FIRST_PSEUDO_REGISTER
+ && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
+ class, inmode))
+ get_secondary_mem (in, inmode, opnum, type);
+#endif
+
i = n_reloads;
reload_in[i] = in;
reload_out[i] = out;
@@ -1195,6 +1277,7 @@ push_reload (in, out, inloc, outloc, class,
reload_outmode[i] = outmode;
reload_reg_rtx[i] = 0;
reload_optional[i] = optional;
+ reload_nongroup[i] = 0;
reload_inc[i] = 0;
reload_nocombine[i] = 0;
reload_in_reg[i] = inloc ? *inloc : 0;
@@ -1209,13 +1292,6 @@ push_reload (in, out, inloc, outloc, class,
n_reloads++;
#ifdef SECONDARY_MEMORY_NEEDED
- /* If a memory location is needed for the copy, make one. */
- if (in != 0 && GET_CODE (in) == REG
- && REGNO (in) < FIRST_PSEUDO_REGISTER
- && SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (REGNO (in)),
- class, inmode))
- get_secondary_mem (in, inmode, opnum, type);
-
if (out != 0 && GET_CODE (out) == REG
&& REGNO (out) < FIRST_PSEUDO_REGISTER
&& SECONDARY_MEMORY_NEEDED (class, REGNO_REG_CLASS (REGNO (out)),
@@ -1230,9 +1306,13 @@ push_reload (in, out, inloc, outloc, class,
For example, we may now have both IN and OUT
while the old one may have just one of them. */
- if (inmode != VOIDmode)
+ /* The modes can be different. If they are, we want to reload in
+ the larger mode, so that the value is valid for both modes. */
+ if (inmode != VOIDmode
+ && GET_MODE_SIZE (inmode) > GET_MODE_SIZE (reload_inmode[i]))
reload_inmode[i] = inmode;
- if (outmode != VOIDmode)
+ if (outmode != VOIDmode
+ && GET_MODE_SIZE (outmode) > GET_MODE_SIZE (reload_outmode[i]))
reload_outmode[i] = outmode;
if (in != 0)
reload_in[i] = in;
@@ -1312,7 +1392,8 @@ push_reload (in, out, inloc, outloc, class,
{
reload_reg_rtx[i] = find_dummy_reload (in, out, inloc, outloc,
inmode, outmode,
- reload_reg_class[i], i);
+ reload_reg_class[i], i,
+ earlyclobber_operand_p (out));
/* If the outgoing register already contains the same value
as the incoming one, we can dispense with loading it.
@@ -1378,7 +1459,7 @@ push_reload (in, out, inloc, outloc, class,
&& TEST_HARD_REG_BIT (reg_class_contents[(int) class], regno)
&& !fixed_regs[regno])
{
- reload_reg_rtx[i] = gen_rtx (REG, inmode, regno);
+ reload_reg_rtx[i] = gen_rtx_REG (inmode, regno);
break;
}
}
@@ -1425,6 +1506,21 @@ transfer_replacements (to, from)
replacements[i].what = to;
}
+/* Remove all replacements in reload FROM. */
+void
+remove_replacements (from)
+ int from;
+{
+ int i, j;
+
+ for (i = 0, j = 0; i < n_replacements; i++)
+ {
+ if (replacements[i].what == from)
+ continue;
+ replacements[j++] = replacements[i];
+ }
+}
+
/* If there is only one output reload, and it is not for an earlyclobber
operand, try to combine it with a (logically unrelated) input reload
to reduce the number of reload registers needed.
@@ -1474,6 +1570,7 @@ combine_reloads ()
if (reload_in[i] && ! reload_optional[i] && ! reload_nocombine[i]
/* Life span of this reload must not extend past main insn. */
&& reload_when_needed[i] != RELOAD_FOR_OUTPUT_ADDRESS
+ && reload_when_needed[i] != RELOAD_FOR_OUTADDR_ADDRESS
&& reload_when_needed[i] != RELOAD_OTHER
&& (CLASS_MAX_NREGS (reload_reg_class[i], reload_inmode[i])
== CLASS_MAX_NREGS (reload_reg_class[output_reload],
@@ -1488,14 +1585,12 @@ combine_reloads ()
|| rtx_equal_p (secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]],
secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]]))
#endif
-#ifdef SMALL_REGISTER_CLASSES
- && reload_reg_class[i] == reload_reg_class[output_reload]
-#else
- && (reg_class_subset_p (reload_reg_class[i],
- reload_reg_class[output_reload])
- || reg_class_subset_p (reload_reg_class[output_reload],
- reload_reg_class[i]))
-#endif
+ && (SMALL_REGISTER_CLASSES
+ ? (reload_reg_class[i] == reload_reg_class[output_reload])
+ : (reg_class_subset_p (reload_reg_class[i],
+ reload_reg_class[output_reload])
+ || reg_class_subset_p (reload_reg_class[output_reload],
+ reload_reg_class[i])))
&& (MATCHES (reload_in[i], reload_out[output_reload])
/* Args reversed because the first arg seems to be
the one that we imagine being modified
@@ -1512,10 +1607,7 @@ combine_reloads ()
&& reg_overlap_mentioned_for_reload_p (reload_in[i],
reload_out[output_reload]))))
&& (reg_class_size[(int) reload_reg_class[i]]
-#ifdef SMALL_REGISTER_CLASSES
- || 1
-#endif
- )
+ || SMALL_REGISTER_CLASSES)
/* We will allow making things slightly worse by combining an
input and an output, but no worse than that. */
&& (reload_when_needed[i] == RELOAD_FOR_INPUT
@@ -1530,7 +1622,7 @@ combine_reloads ()
reload_out[output_reload] = 0;
/* The combined reload is needed for the entire insn. */
reload_when_needed[i] = RELOAD_OTHER;
- /* If the output reload had a secondary reload, copy it. */
+ /* If the output reload had a secondary reload, copy it. */
if (reload_secondary_out_reload[output_reload] != -1)
{
reload_secondary_out_reload[i]
@@ -1545,7 +1637,7 @@ combine_reloads ()
secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[i]]
= secondary_memlocs_elim[(int) reload_outmode[output_reload]][reload_opnum[output_reload]];
#endif
- /* If required, minimize the register class. */
+ /* If required, minimize the register class. */
if (reg_class_subset_p (reload_reg_class[output_reload],
reload_reg_class[i]))
reload_reg_class[i] = reload_reg_class[output_reload];
@@ -1598,9 +1690,9 @@ combine_reloads ()
REGNO (XEXP (note, 0)))))))
&& ! fixed_regs[REGNO (XEXP (note, 0))])
{
- reload_reg_rtx[output_reload] = gen_rtx (REG,
- reload_outmode[output_reload],
- REGNO (XEXP (note, 0)));
+ reload_reg_rtx[output_reload]
+ = gen_rtx_REG (reload_outmode[output_reload],
+ REGNO (XEXP (note, 0)));
return;
}
}
@@ -1618,16 +1710,22 @@ combine_reloads ()
to be computed, clear out reload_out[FOR_REAL].
If FOR_REAL is -1, this should not be done, because this call
- is just to see if a register can be found, not to find and install it. */
+ is just to see if a register can be found, not to find and install it.
+
+ EARLYCLOBBER is non-zero if OUT is an earlyclobber operand. This
+ puts an additional constraint on being able to use IN for OUT since
+ IN must not appear elsewhere in the insn (it is assumed that IN itself
+ is safe from the earlyclobber). */
static rtx
find_dummy_reload (real_in, real_out, inloc, outloc,
- inmode, outmode, class, for_real)
+ inmode, outmode, class, for_real, earlyclobber)
rtx real_in, real_out;
rtx *inloc, *outloc;
enum machine_mode inmode, outmode;
enum reg_class class;
int for_real;
+ int earlyclobber;
{
rtx in = real_in;
rtx out = real_out;
@@ -1698,7 +1796,7 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
if (GET_CODE (real_out) == REG)
value = real_out;
else
- value = gen_rtx (REG, outmode, regno);
+ value = gen_rtx_REG (outmode, regno);
}
}
@@ -1709,7 +1807,8 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
or if OUT dies in this insn (like the quotient in a divmod insn).
We can't use IN unless it is dies in this insn,
which means we must know accurately which hard regs are live.
- Also, the result can't go in IN if IN is used within OUT. */
+ Also, the result can't go in IN if IN is used within OUT,
+ or if OUT is an earlyclobber and IN appears elsewhere in the insn. */
if (hard_regs_live_known
&& GET_CODE (in) == REG
&& REGNO (in) < FIRST_PSEUDO_REGISTER
@@ -1730,7 +1829,10 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
if (! refers_to_regno_for_reload_p (regno, regno + nwords, out, NULL_PTR)
&& ! hard_reg_set_here_p (regno, regno + nwords,
- PATTERN (this_insn)))
+ PATTERN (this_insn))
+ && (! earlyclobber
+ || ! refers_to_regno_for_reload_p (regno, regno + nwords,
+ PATTERN (this_insn), inloc)))
{
int i;
for (i = 0; i < nwords; i++)
@@ -1748,7 +1850,7 @@ find_dummy_reload (real_in, real_out, inloc, outloc,
if (GET_CODE (real_in) == REG)
value = real_in;
else
- value = gen_rtx (REG, inmode, regno);
+ value = gen_rtx_REG (inmode, regno);
}
}
}
@@ -1995,6 +2097,7 @@ decompose (x)
val.reg_flag = 0;
val.safe = 0;
+ val.base = 0;
if (GET_CODE (x) == MEM)
{
rtx base, offset = 0;
@@ -2040,28 +2143,28 @@ decompose (x)
{
if (GET_CODE (XEXP (offset, 0)) == CONST_INT)
{
- base = gen_rtx (PLUS, GET_MODE (base), base, XEXP (offset, 1));
+ base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 1));
offset = XEXP (offset, 0);
}
else if (GET_CODE (XEXP (offset, 1)) == CONST_INT)
{
- base = gen_rtx (PLUS, GET_MODE (base), base, XEXP (offset, 0));
+ base = gen_rtx_PLUS (GET_MODE (base), base, XEXP (offset, 0));
offset = XEXP (offset, 1);
}
else
{
- base = gen_rtx (PLUS, GET_MODE (base), base, offset);
+ base = gen_rtx_PLUS (GET_MODE (base), base, offset);
offset = const0_rtx;
}
}
else if (GET_CODE (offset) != CONST_INT)
{
- base = gen_rtx (PLUS, GET_MODE (base), base, offset);
+ base = gen_rtx_PLUS (GET_MODE (base), base, offset);
offset = const0_rtx;
}
if (all_const && GET_CODE (base) == PLUS)
- base = gen_rtx (CONST, GET_MODE (base), base);
+ base = gen_rtx_CONST (GET_MODE (base), base);
if (GET_CODE (offset) != CONST_INT)
abort ();
@@ -2234,12 +2337,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
int goal_alternative_swapped;
int best;
int commutative;
+ int changed;
char operands_match[MAX_RECOG_OPERANDS][MAX_RECOG_OPERANDS];
rtx substed_operand[MAX_RECOG_OPERANDS];
rtx body = PATTERN (insn);
rtx set = single_set (insn);
int goal_earlyclobber, this_earlyclobber;
enum machine_mode operand_mode[MAX_RECOG_OPERANDS];
+ /* Cache the last regno for the last pseudo we did an output reload
+ for in case the next insn uses it. */
+ static int last_output_reload_regno = -1;
this_insn = insn;
this_insn_is_asm = 0; /* Tentative. */
@@ -2327,7 +2434,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
error_for_asm (insn, "operand constraints differ in number of alternatives");
/* Avoid further trouble with this insn. */
- PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
return;
}
@@ -2380,7 +2487,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* Scan this operand's constraint to see if it is an output operand,
an in-out operand, is commutative, or should match another. */
- while (c = *p++)
+ while ((c = *p++))
{
if (c == '=')
modified[i] = RELOAD_WRITE;
@@ -2468,7 +2575,21 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
find_reloads_address (VOIDmode, NULL_PTR,
recog_operand[i], recog_operand_loc[i],
- i, operand_type[i], ind_levels);
+ i, operand_type[i], ind_levels, insn);
+
+ /* If we now have a simple operand where we used to have a
+ PLUS or MULT, re-recognize and try again. */
+ if ((GET_RTX_CLASS (GET_CODE (*recog_operand_loc[i])) == 'o'
+ || GET_CODE (*recog_operand_loc[i]) == SUBREG)
+ && (GET_CODE (recog_operand[i]) == MULT
+ || GET_CODE (recog_operand[i]) == PLUS))
+ {
+ INSN_CODE (insn) = -1;
+ find_reloads (insn, replace, ind_levels, live_known,
+ reload_reg_p);
+ return;
+ }
+
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
}
else if (code == MEM)
@@ -2477,19 +2598,38 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
recog_operand_loc[i],
XEXP (recog_operand[i], 0),
&XEXP (recog_operand[i], 0),
- i, address_type[i], ind_levels))
+ i, address_type[i], ind_levels, insn))
address_reloaded[i] = 1;
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
}
else if (code == SUBREG)
- substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
- = find_reloads_toplev (recog_operand[i], i, address_type[i],
- ind_levels,
- set != 0
- && &SET_DEST (set) == recog_operand_loc[i]);
- else if (code == PLUS)
- /* We can get a PLUS as an "operand" as a result of
- register elimination. See eliminate_regs and gen_reload. */
+ {
+ rtx reg = SUBREG_REG (recog_operand[i]);
+ rtx op
+ = find_reloads_toplev (recog_operand[i], i, address_type[i],
+ ind_levels,
+ set != 0
+ && &SET_DEST (set) == recog_operand_loc[i]);
+
+ /* If we made a MEM to load (a part of) the stackslot of a pseudo
+ that didn't get a hard register, emit a USE with a REG_EQUAL
+ note in front so that we might inherit a previous, possibly
+ wider reload. */
+
+ if (GET_CODE (op) == MEM
+ && GET_CODE (reg) == REG
+ && (GET_MODE_SIZE (GET_MODE (reg))
+ >= GET_MODE_SIZE (GET_MODE (op))))
+ REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode, reg), insn))
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ reg_equiv_memory_loc[REGNO (reg)], NULL_RTX);
+
+ substed_operand[i] = recog_operand[i] = *recog_operand_loc[i] = op;
+ }
+ else if (code == PLUS || GET_RTX_CLASS (code) == '1')
+ /* We can get a PLUS as an "operand" as a result of register
+ elimination. See eliminate_regs and gen_reload. We handle
+ a unary operator by reloading the operand. */
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i]
= find_reloads_toplev (recog_operand[i], i, address_type[i],
ind_levels, 0);
@@ -2504,8 +2644,16 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
register int regno = REGNO (recog_operand[i]);
if (reg_equiv_constant[regno] != 0
&& (set == 0 || &SET_DEST (set) != recog_operand_loc[i]))
- substed_operand[i] = recog_operand[i]
- = reg_equiv_constant[regno];
+ {
+ /* Record the existing mode so that the check if constants are
+ allowed will work when operand_mode isn't specified. */
+
+ if (operand_mode[i] == VOIDmode)
+ operand_mode[i] = GET_MODE (recog_operand[i]);
+
+ substed_operand[i] = recog_operand[i]
+ = reg_equiv_constant[regno];
+ }
#if 0 /* This might screw code in reload1.c to delete prior output-reload
that feeds this insn. */
if (reg_equiv_mem[regno] != 0)
@@ -2525,26 +2673,23 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (rtx_varies_p (address))
address = copy_rtx (address);
- /* If this is an output operand, we must output a CLOBBER
- after INSN so find_equiv_reg knows REGNO is being written.
- Mark this insn specially, do we can put our output reloads
- after it. */
-
- if (modified[i] != RELOAD_READ)
- PUT_MODE (emit_insn_after (gen_rtx (CLOBBER, VOIDmode,
- recog_operand[i]),
- insn),
- DImode);
+ /* Emit a USE that shows what register is being used/modified. */
+ REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode,
+ recog_operand[i]),
+ insn))
+ = gen_rtx_EXPR_LIST (REG_EQUAL,
+ reg_equiv_memory_loc[regno],
+ NULL_RTX);
*recog_operand_loc[i] = recog_operand[i]
- = gen_rtx (MEM, GET_MODE (recog_operand[i]), address);
+ = gen_rtx_MEM (GET_MODE (recog_operand[i]), address);
RTX_UNCHANGING_P (recog_operand[i])
= RTX_UNCHANGING_P (regno_reg_rtx[regno]);
find_reloads_address (GET_MODE (recog_operand[i]),
recog_operand_loc[i],
XEXP (recog_operand[i], 0),
&XEXP (recog_operand[i], 0),
- i, address_type[i], ind_levels);
+ i, address_type[i], ind_levels, insn);
substed_operand[i] = recog_operand[i] = *recog_operand_loc[i];
}
}
@@ -2574,7 +2719,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
or got the wrong kind of hard reg. For this, we must consider
all the operands together against the register constraints. */
- best = MAX_RECOG_OPERANDS + 300;
+ best = MAX_RECOG_OPERANDS * 2 + 600;
swapped = 0;
goal_alternative_swapped = 0;
@@ -2628,6 +2773,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
int constmemok = 0;
int earlyclobber = 0;
+ /* If the predicate accepts a unary operator, it means that
+ we need to reload the operand, but do not do this for
+ match_operator and friends. */
+ if (GET_RTX_CLASS (GET_CODE (operand)) == '1' && *p != 0)
+ operand = XEXP (operand, 0);
+
/* If the operand is a SUBREG, extract
the REG or MEM (or maybe even a constant) within.
(Constants can occur as a result of reg_equiv_constant.) */
@@ -2636,7 +2787,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
offset += SUBREG_WORD (operand);
operand = SUBREG_REG (operand);
- /* Force reload if this is a constant or PLUS or if there may may
+ /* Force reload if this is a constant or PLUS or if there may
be a problem accessing OPERAND in the outer mode. */
if (CONSTANT_P (operand)
|| GET_CODE (operand) == PLUS
@@ -2654,10 +2805,20 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
register access. If the data is, in fact, in memory we
must always load using the size assumed to be in the
register and let the insn do the different-sized
- accesses. */
+ accesses.
+
+ This is doubly true if WORD_REGISTER_OPERATIONS. In
+ this case eliminate_regs has left non-paradoxical
+ subregs for push_reloads to see. Make sure it does
+ by forcing the reload.
+
+ ??? When is it right at this stage to have a subreg
+ of a mem that is _not_ to be handled specialy? IMO
+ those should have been reduced to just a mem. */
|| ((GET_CODE (operand) == MEM
|| (GET_CODE (operand)== REG
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER))
+#ifndef WORD_REGISTER_OPERATIONS
&& (((GET_MODE_BITSIZE (GET_MODE (operand))
< BIGGEST_ALIGNMENT)
&& (GET_MODE_SIZE (operand_mode[i])
@@ -2672,7 +2833,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& INTEGRAL_MODE_P (GET_MODE (operand))
&& LOAD_EXTEND_OP (GET_MODE (operand)) != NIL)
#endif
- ))
+ )
+#endif
+ )
/* Subreg of a hard reg which can't handle the subreg's mode
or which would handle that mode in the wrong number of
registers for subregging to work. */
@@ -2723,11 +2886,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
break;
case '?':
- reject += 3;
+ reject += 6;
break;
case '!':
- reject = 300;
+ reject = 600;
break;
case '#':
@@ -2763,7 +2926,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
[(i == commutative || i == commutative + 1)
? 2*commutative + 1 - i : i])
: operands_match[c][i])
- win = this_alternative_win[c];
+ {
+ /* If we are matching a non-offsettable address where an
+ offsettable address was expected, then we must reject
+ this combination, because we can't reload it. */
+ if (this_alternative_offmemok[c]
+ && GET_CODE (recog_operand[c]) == MEM
+ && this_alternative[c] == (int) NO_REGS
+ && ! this_alternative_win[c])
+ bad = 1;
+
+ win = this_alternative_win[c];
+ }
else
{
/* Operands don't match. */
@@ -2781,7 +2955,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
= find_dummy_reload (recog_operand[i], recog_operand[c],
recog_operand_loc[i], recog_operand_loc[c],
operand_mode[i], operand_mode[c],
- this_alternative[c], -1);
+ this_alternative[c], -1,
+ this_alternative_earlyclobber[c]);
if (value != 0)
losers--;
@@ -2818,7 +2993,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER
&& reg_renumber[REGNO (operand)] < 0))
win = 1;
- if (CONSTANT_P (operand))
+ if (CONSTANT_P (operand)
+ /* force_const_mem does not accept HIGH. */
+ && GET_CODE (operand) != HIGH)
badop = 0;
constmemok = 1;
break;
@@ -2893,7 +3070,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& offsettable_memref_p (reg_equiv_mem[REGNO (operand)]))
|| (reg_equiv_address[REGNO (operand)] != 0))))
win = 1;
- if (CONSTANT_P (operand) || GET_CODE (operand) == MEM)
+ /* force_const_mem does not accept HIGH. */
+ if ((CONSTANT_P (operand) && GET_CODE (operand) != HIGH)
+ || GET_CODE (operand) == MEM)
badop = 0;
constmemok = 1;
offmemok = 1;
@@ -3043,15 +3222,20 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& this_alternative_matches[i] < 0)
bad = 1;
- /* Alternative loses if it requires a type of reload not
- permitted for this insn. We can always reload SCRATCH
- and objects with a REG_UNUSED note. */
- if (GET_CODE (operand) != SCRATCH
- && modified[i] != RELOAD_READ && no_output_reloads
- && ! find_reg_note (insn, REG_UNUSED, operand))
- bad = 1;
- else if (modified[i] != RELOAD_WRITE && no_input_reloads)
- bad = 1;
+#if 0
+ /* If this is a pseudo-register that is set in the previous
+ insns, there's a good chance that it will already be in a
+ spill register and we can use that spill register. So
+ make this case cheaper.
+
+ Disabled for egcs. egcs has better inheritance code and
+ this change causes problems with the improved reload
+ inheritance code. */
+ if (GET_CODE (operand) == REG
+ && REGNO (operand) >= FIRST_PSEUDO_REGISTER
+ && REGNO (operand) == last_output_reload_regno)
+ reject--;
+#endif
/* If this is a constant that is reloaded into the desired
class by copying it to memory first, count that as another
@@ -3064,9 +3248,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (CONSTANT_P (operand)
/* force_const_mem does not accept HIGH. */
&& GET_CODE (operand) != HIGH
- && (PREFERRED_RELOAD_CLASS (operand,
+ && ((PREFERRED_RELOAD_CLASS (operand,
(enum reg_class) this_alternative[i])
- == NO_REGS)
+ == NO_REGS)
+ || no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
const_to_mem = 1;
@@ -3086,6 +3271,18 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
== NO_REGS))
bad = 1;
+ /* Alternative loses if it requires a type of reload not
+ permitted for this insn. We can always reload SCRATCH
+ and objects with a REG_UNUSED note. */
+ else if (GET_CODE (operand) != SCRATCH
+ && modified[i] != RELOAD_READ && no_output_reloads
+ && ! find_reg_note (insn, REG_UNUSED, operand))
+ bad = 1;
+ else if (modified[i] != RELOAD_WRITE && no_input_reloads
+ && ! const_to_mem)
+ bad = 1;
+
+
/* We prefer to reload pseudos over reloading other things,
since such reloads may be able to be eliminated later.
If we are reloading a SCRATCH, we won't be generating any
@@ -3098,6 +3295,12 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& REGNO (operand) >= FIRST_PSEUDO_REGISTER)
&& GET_CODE (operand) != SCRATCH
&& ! (const_to_mem && constmemok))
+ reject += 2;
+
+ /* Input reloads can be inherited more often than output
+ reloads can be removed, so penalize output reloads. */
+ if (operand_type[i] != RELOAD_FOR_INPUT
+ && GET_CODE (operand) != SCRATCH)
reject++;
}
@@ -3138,7 +3341,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
this_alternative[i]))
this_alternative[i] = (int) preferred_class[i];
else
- reject += (1 + pref_or_nothing[i]);
+ reject += (2 + 2 * pref_or_nothing[i]);
}
}
}
@@ -3245,9 +3448,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* REJECT, set by the ! and ? constraint characters and when a register
would be reloaded into a non-preferred class, discourages the use of
- this alternative for a reload goal. REJECT is incremented by three
- for each ? and one for each non-preferred class. */
- losers = losers * 3 + reject;
+ this alternative for a reload goal. REJECT is incremented by six
+ for each ? and two for each non-preferred class. */
+ losers = losers * 6 + reject;
/* If this alternative can be made to work by reloading,
and it needs less reloading than the others checked so far,
@@ -3314,14 +3517,14 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
that we could reach by reloading the fewest operands.
Reload so as to fit it. */
- if (best == MAX_RECOG_OPERANDS + 300)
+ if (best == MAX_RECOG_OPERANDS * 2 + 600)
{
/* No alternative works with reloads?? */
if (insn_code_number >= 0)
abort ();
error_for_asm (insn, "inconsistent operand constraints in an `asm'");
/* Avoid further trouble with this insn. */
- PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
return;
}
@@ -3389,11 +3592,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
a SCRATCH). In this case, we only need have the reload live
through the insn itself, but not for any of our input or output
reloads.
+ But we must not accidentally narrow the scope of an existing
+ RELOAD_OTHER reload - leave these alone.
In any case, anything needed to address this operand can remain
however they were previously categorized. */
- if (goal_alternative_earlyclobber[i])
+ if (goal_alternative_earlyclobber[i] && operand_type[i] != RELOAD_OTHER)
operand_type[i]
= (find_reg_note (insn, REG_UNUSED, recog_operand[i])
? RELOAD_FOR_INSN : RELOAD_OTHER);
@@ -3406,9 +3611,10 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
&& CONSTANT_P (recog_operand[i])
/* force_const_mem does not accept HIGH. */
&& GET_CODE (recog_operand[i]) != HIGH
- && (PREFERRED_RELOAD_CLASS (recog_operand[i],
+ && ((PREFERRED_RELOAD_CLASS (recog_operand[i],
(enum reg_class) goal_alternative[i])
- == NO_REGS)
+ == NO_REGS)
+ || no_input_reloads)
&& operand_mode[i] != VOIDmode)
{
*recog_operand_loc[i] = recog_operand[i]
@@ -3427,6 +3633,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
reload_earlyclobbers[n_earlyclobbers++] = recog_operand[i];
/* Now record reloads for all the operands that need them. */
+ last_output_reload_regno = -1;
for (i = 0; i < noperands; i++)
if (! goal_alternative_win[i])
{
@@ -3458,26 +3665,42 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
we must change these to RELOAD_FOR_INPUT_ADDRESS. */
if (modified[i] == RELOAD_WRITE)
- for (j = 0; j < n_reloads; j++)
- if (reload_opnum[j] == i
- && reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS)
- reload_when_needed[j] = RELOAD_FOR_INPUT_ADDRESS;
+ {
+ for (j = 0; j < n_reloads; j++)
+ {
+ if (reload_opnum[j] == i)
+ {
+ if (reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS)
+ reload_when_needed[j] = RELOAD_FOR_INPUT_ADDRESS;
+ else if (reload_when_needed[j]
+ == RELOAD_FOR_OUTADDR_ADDRESS)
+ reload_when_needed[j] = RELOAD_FOR_INPADDR_ADDRESS;
+ }
+ }
+ }
}
else if (goal_alternative_matched[i] == -1)
- operand_reloadnum[i] =
- push_reload (modified[i] != RELOAD_WRITE ? recog_operand[i] : 0,
- modified[i] != RELOAD_READ ? recog_operand[i] : 0,
- (modified[i] != RELOAD_WRITE ?
- recog_operand_loc[i] : 0),
- modified[i] != RELOAD_READ ? recog_operand_loc[i] : 0,
- (enum reg_class) goal_alternative[i],
- (modified[i] == RELOAD_WRITE
- ? VOIDmode : operand_mode[i]),
- (modified[i] == RELOAD_READ
- ? VOIDmode : operand_mode[i]),
- (insn_code_number < 0 ? 0
- : insn_operand_strict_low[insn_code_number][i]),
- 0, i, operand_type[i]);
+ {
+ operand_reloadnum[i]
+ = push_reload ((modified[i] != RELOAD_WRITE
+ ? recog_operand[i] : 0),
+ modified[i] != RELOAD_READ ? recog_operand[i] : 0,
+ (modified[i] != RELOAD_WRITE
+ ? recog_operand_loc[i] : 0),
+ (modified[i] != RELOAD_READ
+ ? recog_operand_loc[i] : 0),
+ (enum reg_class) goal_alternative[i],
+ (modified[i] == RELOAD_WRITE
+ ? VOIDmode : operand_mode[i]),
+ (modified[i] == RELOAD_READ
+ ? VOIDmode : operand_mode[i]),
+ (insn_code_number < 0 ? 0
+ : insn_operand_strict_low[insn_code_number][i]),
+ 0, i, operand_type[i]);
+ if (modified[i] != RELOAD_READ
+ && GET_CODE (recog_operand[i]) == REG)
+ last_output_reload_regno = REGNO (recog_operand[i]);
+ }
/* In a matching pair of operands, one must be input only
and the other must be output only.
Pass the input operand as IN and the other as OUT. */
@@ -3494,6 +3717,9 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
operand_mode[goal_alternative_matched[i]],
0, 0, i, RELOAD_OTHER);
operand_reloadnum[goal_alternative_matched[i]] = output_reloadnum;
+ if (GET_CODE (recog_operand[goal_alternative_matched[i]]) == REG)
+ last_output_reload_regno
+ = REGNO (recog_operand[goal_alternative_matched[i]]);
}
else if (modified[i] == RELOAD_WRITE
&& modified[goal_alternative_matched[i]] == RELOAD_READ)
@@ -3508,6 +3734,8 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
operand_mode[i],
0, 0, i, RELOAD_OTHER);
operand_reloadnum[i] = output_reloadnum;
+ if (GET_CODE (recog_operand[i]) == REG)
+ last_output_reload_regno = REGNO (recog_operand[i]);
}
else if (insn_code_number >= 0)
abort ();
@@ -3515,7 +3743,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
{
error_for_asm (insn, "inconsistent operand constraints in an `asm'");
/* Avoid further trouble with this insn. */
- PATTERN (insn) = gen_rtx (USE, VOIDmode, const0_rtx);
+ PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
n_reloads = 0;
return;
}
@@ -3640,7 +3868,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
/* If we have a pair of reloads for parts of an address, they are reloading
the same object, the operands themselves were not reloaded, and they
are for two operands that are supposed to match, merge the reloads and
- change the type of the surviving reload to RELOAD_FOR_OPERAND_ADDRESS. */
+ change the type of the surviving reload to RELOAD_FOR_OPERAND_ADDRESS. */
for (i = 0; i < n_reloads; i++)
{
@@ -3648,9 +3876,13 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
for (j = i + 1; j < n_reloads; j++)
if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS)
+ || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
&& (reload_when_needed[j] == RELOAD_FOR_INPUT_ADDRESS
- || reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS)
+ || reload_when_needed[j] == RELOAD_FOR_OUTPUT_ADDRESS
+ || reload_when_needed[j] == RELOAD_FOR_INPADDR_ADDRESS
+ || reload_when_needed[j] == RELOAD_FOR_OUTADDR_ADDRESS)
&& rtx_equal_p (reload_in[i], reload_in[j])
&& (operand_reloadnum[reload_opnum[i]] < 0
|| reload_optional[operand_reloadnum[reload_opnum[i]]])
@@ -3664,7 +3896,11 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (replacements[k].what == j)
replacements[k].what = i;
- reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
+ if (reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
+ reload_when_needed[i] = RELOAD_FOR_OPADDR_ADDR;
+ else
+ reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
reload_in[j] = 0;
}
}
@@ -3693,46 +3929,52 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
reload_when_needed[i] = address_type[reload_opnum[i]];
if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
- || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS)
+ || reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
&& (operand_reloadnum[reload_opnum[i]] < 0
|| reload_optional[operand_reloadnum[reload_opnum[i]]]))
{
/* If we have a secondary reload to go along with this reload,
- change its type to RELOAD_FOR_OPADDR_ADDR. */
+ change its type to RELOAD_FOR_OPADDR_ADDR. */
- if (reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+ if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
&& reload_secondary_in_reload[i] != -1)
{
int secondary_in_reload = reload_secondary_in_reload[i];
- reload_when_needed[secondary_in_reload] =
- RELOAD_FOR_OPADDR_ADDR;
+ reload_when_needed[secondary_in_reload]
+ = RELOAD_FOR_OPADDR_ADDR;
- /* If there's a tertiary reload we have to change it also. */
+ /* If there's a tertiary reload we have to change it also. */
if (secondary_in_reload > 0
&& reload_secondary_in_reload[secondary_in_reload] != -1)
reload_when_needed[reload_secondary_in_reload[secondary_in_reload]]
= RELOAD_FOR_OPADDR_ADDR;
}
- if (reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
+ if ((reload_when_needed[i] == RELOAD_FOR_OUTPUT_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_OUTADDR_ADDRESS)
&& reload_secondary_out_reload[i] != -1)
{
int secondary_out_reload = reload_secondary_out_reload[i];
- reload_when_needed[secondary_out_reload] =
- RELOAD_FOR_OPADDR_ADDR;
+ reload_when_needed[secondary_out_reload]
+ = RELOAD_FOR_OPADDR_ADDR;
- /* If there's a tertiary reload we have to change it also. */
+ /* If there's a tertiary reload we have to change it also. */
if (secondary_out_reload
&& reload_secondary_out_reload[secondary_out_reload] != -1)
reload_when_needed[reload_secondary_out_reload[secondary_out_reload]]
= RELOAD_FOR_OPADDR_ADDR;
}
+
reload_when_needed[i] = RELOAD_FOR_OPERAND_ADDRESS;
}
- if (reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+ if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
&& operand_reloadnum[reload_opnum[i]] >= 0
&& (reload_when_needed[operand_reloadnum[reload_opnum[i]]]
== RELOAD_OTHER))
@@ -3742,6 +3984,100 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
reload_opnum[i] = goal_alternative_matches[reload_opnum[i]];
}
+ /* Scan all the reloads, and check for RELOAD_FOR_OPERAND_ADDRESS reloads.
+ If we have more than one, then convert all RELOAD_FOR_OPADDR_ADDR
+ reloads to RELOAD_FOR_OPERAND_ADDRESS reloads.
+
+ choose_reload_regs assumes that RELOAD_FOR_OPADDR_ADDR reloads never
+ conflict with RELOAD_FOR_OPERAND_ADDRESS reloads. This is true for a
+ single pair of RELOAD_FOR_OPADDR_ADDR/RELOAD_FOR_OPERAND_ADDRESS reloads.
+ However, if there is more than one RELOAD_FOR_OPERAND_ADDRESS reload,
+ then a RELOAD_FOR_OPADDR_ADDR reload conflicts with all
+ RELOAD_FOR_OPERAND_ADDRESS reloads other than the one that uses it.
+ This is complicated by the fact that a single operand can have more
+ than one RELOAD_FOR_OPERAND_ADDRESS reload. It is very difficult to fix
+ choose_reload_regs without affecting code quality, and cases that
+ actually fail are extremely rare, so it turns out to be better to fix
+ the problem here by not generating cases that choose_reload_regs will
+ fail for. */
+ /* There is a similar problem with RELAOD_FOR_INPUT_ADDRESS /
+ RELOAD_FOR_OUTPUT_ADDRESS when there is more than one of a kind for
+ a single operand.
+ We can reduce the register pressure by exploiting that a
+ RELOAD_FOR_X_ADDR_ADDR that precedes all RELOAD_FOR_X_ADDRESS reloads
+ does not conflict with any of them. */
+ {
+ int first_op_addr_num = -2;
+ int first_inpaddr_num[MAX_RECOG_OPERANDS];
+ int first_outpaddr_num[MAX_RECOG_OPERANDS];
+ int need_change= 0;
+ /* We use last_op_addr_reload and the contents of the above arrays
+ first as flags - -2 means no instance encountered, -1 means exactly
+ one instance encountered.
+ If more than one instance has been encountered, we store the reload
+ number of the first reload of the kind in question; reload numbers
+ are known to be non-negative. */
+ for (i = 0; i < noperands; i++)
+ first_inpaddr_num[i] = first_outpaddr_num[i] = -2;
+ for (i = n_reloads - 1; i >= 0; i--)
+ {
+ switch (reload_when_needed[i])
+ {
+ case RELOAD_FOR_OPERAND_ADDRESS:
+ if (! ++first_op_addr_num)
+ {
+ first_op_addr_num= i;
+ need_change = 1;
+ }
+ break;
+ case RELOAD_FOR_INPUT_ADDRESS:
+ if (! ++first_inpaddr_num[reload_opnum[i]])
+ {
+ first_inpaddr_num[reload_opnum[i]] = i;
+ need_change = 1;
+ }
+ break;
+ case RELOAD_FOR_OUTPUT_ADDRESS:
+ if (! ++first_outpaddr_num[reload_opnum[i]])
+ {
+ first_outpaddr_num[reload_opnum[i]] = i;
+ need_change = 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (need_change)
+ {
+ for (i = 0; i < n_reloads; i++)
+ {
+ int first_num, type;
+
+ switch (reload_when_needed[i])
+ {
+ case RELOAD_FOR_OPADDR_ADDR:
+ first_num = first_op_addr_num;
+ type = RELOAD_FOR_OPERAND_ADDRESS;
+ break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ first_num = first_inpaddr_num[reload_opnum[i]];
+ type = RELOAD_FOR_INPUT_ADDRESS;
+ break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ first_num = first_outpaddr_num[reload_opnum[i]];
+ type = RELOAD_FOR_OUTPUT_ADDRESS;
+ break;
+ default:
+ continue;
+ }
+ if (i > first_num)
+ reload_when_needed[i] = type;
+ }
+ }
+ }
+
/* See if we have any reloads that are now allowed to be merged
because we've changed when the reload is needed to
RELOAD_FOR_OPERAND_ADDRESS or RELOAD_FOR_OTHER_ADDRESS. Only
@@ -3750,6 +4086,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
for (i = 0; i < n_reloads; i++)
if (reload_in[i] != 0 && reload_out[i] == 0
&& (reload_when_needed[i] == RELOAD_FOR_OPERAND_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_OPADDR_ADDR
|| reload_when_needed[i] == RELOAD_FOR_OTHER_ADDRESS))
for (j = 0; j < n_reloads; j++)
if (i != j && reload_in[j] != 0 && reload_out[j] == 0
@@ -3764,6 +4101,67 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
reload_in[j] = 0;
}
+ /* Set which reloads must use registers not used in any group. Start
+ with those that conflict with a group and then include ones that
+ conflict with ones that are already known to conflict with a group. */
+
+ changed = 0;
+ for (i = 0; i < n_reloads; i++)
+ {
+ enum machine_mode mode = reload_inmode[i];
+ enum reg_class class = reload_reg_class[i];
+ int size;
+
+ if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
+ mode = reload_outmode[i];
+ size = CLASS_MAX_NREGS (class, mode);
+
+ if (size == 1)
+ for (j = 0; j < n_reloads; j++)
+ if ((CLASS_MAX_NREGS (reload_reg_class[j],
+ (GET_MODE_SIZE (reload_outmode[j])
+ > GET_MODE_SIZE (reload_inmode[j]))
+ ? reload_outmode[j] : reload_inmode[j])
+ > 1)
+ && !reload_optional[j]
+ && (reload_in[j] != 0 || reload_out[j] != 0
+ || reload_secondary_p[j])
+ && reloads_conflict (i, j)
+ && reg_classes_intersect_p (class, reload_reg_class[j]))
+ {
+ reload_nongroup[i] = 1;
+ changed = 1;
+ break;
+ }
+ }
+
+ while (changed)
+ {
+ changed = 0;
+
+ for (i = 0; i < n_reloads; i++)
+ {
+ enum machine_mode mode = reload_inmode[i];
+ enum reg_class class = reload_reg_class[i];
+ int size;
+
+ if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
+ mode = reload_outmode[i];
+ size = CLASS_MAX_NREGS (class, mode);
+
+ if (! reload_nongroup[i] && size == 1)
+ for (j = 0; j < n_reloads; j++)
+ if (reload_nongroup[j]
+ && reloads_conflict (i, j)
+ && reg_classes_intersect_p (class, reload_reg_class[j]))
+ {
+ reload_nongroup[i] = 1;
+ changed = 1;
+ break;
+ }
+ }
+ }
+
#else /* no REGISTER_CONSTRAINTS */
int noperands;
int insn_code_number;
@@ -3833,7 +4231,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
if (insn_operand_address_p[insn_code_number][i])
find_reloads_address (VOIDmode, NULL_PTR,
recog_operand[i], recog_operand_loc[i],
- i, RELOAD_FOR_INPUT, ind_levels);
+ i, RELOAD_FOR_INPUT, ind_levels, insn);
/* In these cases, we can't tell if the operand is an input
or an output, so be conservative. In practice it won't be
@@ -3844,7 +4242,7 @@ find_reloads (insn, replace, ind_levels, live_known, reload_reg_p)
recog_operand_loc[i],
XEXP (recog_operand[i], 0),
&XEXP (recog_operand[i], 0),
- i, RELOAD_OTHER, ind_levels);
+ i, RELOAD_OTHER, ind_levels, insn);
if (code == SUBREG)
recog_operand[i] = *recog_operand_loc[i]
= find_reloads_toplev (recog_operand[i], i, RELOAD_OTHER,
@@ -3946,11 +4344,11 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
if (rtx_varies_p (addr))
addr = copy_rtx (addr);
- x = gen_rtx (MEM, GET_MODE (x), addr);
+ x = gen_rtx_MEM (GET_MODE (x), addr);
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
find_reloads_address (GET_MODE (x), NULL_PTR,
XEXP (x, 0),
- &XEXP (x, 0), opnum, type, ind_levels);
+ &XEXP (x, 0), opnum, type, ind_levels, 0);
}
return x;
}
@@ -3958,7 +4356,7 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
{
rtx tem = x;
find_reloads_address (GET_MODE (x), &tem, XEXP (x, 0), &XEXP (x, 0),
- opnum, type, ind_levels);
+ opnum, type, ind_levels, 0);
return tem;
}
@@ -3989,7 +4387,41 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
&& (tem = operand_subword (reg_equiv_constant[regno],
SUBREG_WORD (x), 0,
GET_MODE (SUBREG_REG (x)))) != 0)
- return tem;
+ {
+ /* TEM is now a word sized constant for the bits from X that
+ we wanted. However, TEM may be the wrong representation.
+
+ Use gen_lowpart_common to convert a CONST_INT into a
+ CONST_DOUBLE and vice versa as needed according to by the mode
+ of the SUBREG. */
+ tem = gen_lowpart_common (GET_MODE (x), tem);
+ if (!tem)
+ abort ();
+ return tem;
+ }
+
+ /* If the SUBREG is wider than a word, the above test will fail.
+ For example, we might have a SImode SUBREG of a DImode SUBREG_REG
+ for a 16 bit target, or a DImode SUBREG of a TImode SUBREG_REG for
+ a 32 bit target. We still can - and have to - handle this
+ for non-paradoxical subregs of CONST_INTs. */
+ if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
+ && reg_equiv_constant[regno] != 0
+ && GET_CODE (reg_equiv_constant[regno]) == CONST_INT
+ && (GET_MODE_SIZE (GET_MODE (x))
+ < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+ {
+ int shift = SUBREG_WORD (x) * BITS_PER_WORD;
+ if (WORDS_BIG_ENDIAN)
+ shift = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (x)))
+ - GET_MODE_BITSIZE (GET_MODE (x))
+ - shift);
+ /* Here we use the knowledge that CONST_INTs have a
+ HOST_WIDE_INT field. */
+ if (shift >= HOST_BITS_PER_WIDE_INT)
+ shift = HOST_BITS_PER_WIDE_INT - 1;
+ return GEN_INT (INTVAL (reg_equiv_constant[regno]) >> shift);
+ }
if (regno >= FIRST_PSEUDO_REGISTER && reg_renumber[regno] < 0
&& reg_equiv_constant[regno] != 0
@@ -4035,11 +4467,11 @@ find_reloads_toplev (x, opnum, type, ind_levels, is_set_dest)
offset -= MIN (size, UNITS_PER_WORD);
}
addr = plus_constant (addr, offset);
- x = gen_rtx (MEM, GET_MODE (x), addr);
+ x = gen_rtx_MEM (GET_MODE (x), addr);
RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
find_reloads_address (GET_MODE (x), NULL_PTR,
XEXP (x, 0),
- &XEXP (x, 0), opnum, type, ind_levels);
+ &XEXP (x, 0), opnum, type, ind_levels, 0);
}
}
@@ -4061,11 +4493,12 @@ make_memloc (ad, regno)
rtx ad;
int regno;
{
+#if 0
register int i;
+#endif
/* We must rerun eliminate_regs, in case the elimination
offsets have changed. */
- rtx tem = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX),
- 0);
+ rtx tem = XEXP (eliminate_regs (reg_equiv_memory_loc[regno], 0, NULL_RTX), 0);
#if 0 /* We cannot safely reuse a memloc made here;
if the pseudo appears twice, and its mem needs a reload,
@@ -4082,7 +4515,7 @@ make_memloc (ad, regno)
if (rtx_varies_p (tem))
tem = copy_rtx (tem);
- tem = gen_rtx (MEM, GET_MODE (ad), tem);
+ tem = gen_rtx_MEM (GET_MODE (ad), tem);
RTX_UNCHANGING_P (tem) = RTX_UNCHANGING_P (regno_reg_rtx[regno]);
memlocs[n_memlocs++] = tem;
return tem;
@@ -4099,6 +4532,9 @@ make_memloc (ad, regno)
IND_LEVELS says how many levels of indirect addressing this machine
supports.
+ INSN, if nonzero, is the insn in which we do the reload. It is used
+ to determine if we may generate output reloads.
+
Value is nonzero if this address is reloaded or replaced as a whole.
This is interesting to the caller if the address is an autoincrement.
@@ -4109,7 +4545,7 @@ make_memloc (ad, regno)
to a hard register, and frame pointer elimination. */
static int
-find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
+find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels, insn)
enum machine_mode mode;
rtx *memrefloc;
rtx ad;
@@ -4117,6 +4553,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
int opnum;
enum reload_type type;
int ind_levels;
+ rtx insn;
{
register int regno;
rtx tem;
@@ -4140,8 +4577,10 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
{
tem = make_memloc (ad, regno);
find_reloads_address (GET_MODE (tem), NULL_PTR, XEXP (tem, 0),
- &XEXP (tem, 0), opnum, type, ind_levels);
- push_reload (tem, NULL_RTX, loc, NULL_PTR, BASE_REG_CLASS,
+ &XEXP (tem, 0), opnum, ADDR_TYPE (type),
+ ind_levels, insn);
+ push_reload (tem, NULL_RTX, loc, NULL_PTR,
+ reload_address_base_reg_class,
GET_MODE (ad), VOIDmode, 0, 0,
opnum, type);
return 1;
@@ -4164,12 +4603,13 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
hard register that is valid as a base register and which is not the
subject of a CLOBBER in this insn. */
- else if (regno < FIRST_PSEUDO_REGISTER && REGNO_OK_FOR_BASE_P (regno)
+ else if (regno < FIRST_PSEUDO_REGISTER
+ && REGNO_MODE_OK_FOR_BASE_P (regno, mode)
&& ! regno_clobbered_p (regno, this_insn))
return 0;
/* If we do not have one of the cases above, we must do the reload. */
- push_reload (ad, NULL_RTX, loc, NULL_PTR, BASE_REG_CLASS,
+ push_reload (ad, NULL_RTX, loc, NULL_PTR, reload_address_base_reg_class,
GET_MODE (ad), VOIDmode, 0, 0, opnum, type);
return 1;
}
@@ -4201,6 +4641,24 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
return 0;
}
+#ifdef LEGITIMIZE_RELOAD_ADDRESS
+ do
+ {
+ if (memrefloc)
+ {
+ LEGITIMIZE_RELOAD_ADDRESS (ad, GET_MODE (*memrefloc), opnum, type,
+ ind_levels, win);
+ }
+ break;
+ win:
+ *memrefloc = copy_rtx (*memrefloc);
+ XEXP (*memrefloc, 0) = ad;
+ move_replacements (&ad, &XEXP (*memrefloc, 0));
+ return 1;
+ }
+ while (0);
+#endif
+
/* The address is not valid. We have to figure out why. One possibility
is that it is itself a MEM. This can happen when the frame pointer is
being eliminated, a pseudo is not allocated to a hard register, and the
@@ -4213,7 +4671,8 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
indirect addresses are valid, reload the MEM into a register. */
tem = ad;
find_reloads_address (GET_MODE (ad), &tem, XEXP (ad, 0), &XEXP (ad, 0),
- opnum, type, ind_levels == 0 ? 0 : ind_levels - 1);
+ opnum, ADDR_TYPE (type),
+ ind_levels == 0 ? 0 : ind_levels - 1, insn);
/* If tem was changed, then we must create a new memory reference to
hold it and store it back into memrefloc. */
@@ -4239,7 +4698,8 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
/* Must use TEM here, not AD, since it is the one that will
have any subexpressions reloaded, if needed. */
push_reload (tem, NULL_RTX, loc, NULL_PTR,
- BASE_REG_CLASS, GET_MODE (tem), VOIDmode, 0,
+ reload_address_base_reg_class, GET_MODE (tem),
+ VOIDmode, 0,
0, opnum, type);
return 1;
}
@@ -4255,7 +4715,7 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
else if (GET_CODE (ad) == PLUS
&& GET_CODE (XEXP (ad, 0)) == REG
&& REGNO (XEXP (ad, 0)) < FIRST_PSEUDO_REGISTER
- && REG_OK_FOR_BASE_P (XEXP (ad, 0))
+ && REG_MODE_OK_FOR_BASE_P (XEXP (ad, 0), mode)
&& GET_CODE (XEXP (ad, 1)) == CONST_INT)
{
/* Unshare the MEM rtx so we can safely alter it. */
@@ -4271,16 +4731,16 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
/* Reload the displacement into an index reg.
We assume the frame pointer or arg pointer is a base reg. */
find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1),
- INDEX_REG_CLASS, GET_MODE (ad), opnum,
- type, ind_levels);
+ reload_address_index_reg_class,
+ GET_MODE (ad), opnum, type, ind_levels);
}
else
{
/* If the sum of two regs is not necessarily valid,
reload the sum into a base reg.
That will at least work. */
- find_reloads_address_part (ad, loc, BASE_REG_CLASS, Pmode,
- opnum, type, ind_levels);
+ find_reloads_address_part (ad, loc, reload_address_base_reg_class,
+ Pmode, opnum, type, ind_levels);
}
return 1;
}
@@ -4326,13 +4786,15 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
|| XEXP (XEXP (ad, 0), 0) == stack_pointer_rtx)
&& ! memory_address_p (mode, ad))
{
- *loc = ad = gen_rtx (PLUS, GET_MODE (ad),
- plus_constant (XEXP (XEXP (ad, 0), 0),
- INTVAL (XEXP (ad, 1))),
+ *loc = ad = gen_rtx_PLUS (GET_MODE (ad),
+ plus_constant (XEXP (XEXP (ad, 0), 0),
+ INTVAL (XEXP (ad, 1))),
XEXP (XEXP (ad, 0), 1));
- find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0), BASE_REG_CLASS,
+ find_reloads_address_part (XEXP (ad, 0), &XEXP (ad, 0),
+ reload_address_base_reg_class,
GET_MODE (ad), opnum, type, ind_levels);
- find_reloads_address_1 (XEXP (ad, 1), 1, &XEXP (ad, 1), opnum, type, 0);
+ find_reloads_address_1 (mode, XEXP (ad, 1), 1, &XEXP (ad, 1), opnum,
+ type, 0, insn);
return 1;
}
@@ -4349,13 +4811,15 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
|| XEXP (XEXP (ad, 0), 1) == stack_pointer_rtx)
&& ! memory_address_p (mode, ad))
{
- *loc = ad = gen_rtx (PLUS, GET_MODE (ad),
- XEXP (XEXP (ad, 0), 0),
- plus_constant (XEXP (XEXP (ad, 0), 1),
- INTVAL (XEXP (ad, 1))));
- find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1), BASE_REG_CLASS,
+ *loc = ad = gen_rtx_PLUS (GET_MODE (ad),
+ XEXP (XEXP (ad, 0), 0),
+ plus_constant (XEXP (XEXP (ad, 0), 1),
+ INTVAL (XEXP (ad, 1))));
+ find_reloads_address_part (XEXP (ad, 1), &XEXP (ad, 1),
+ reload_address_base_reg_class,
GET_MODE (ad), opnum, type, ind_levels);
- find_reloads_address_1 (XEXP (ad, 0), 1, &XEXP (ad, 0), opnum, type, 0);
+ find_reloads_address_1 (mode, XEXP (ad, 0), 1, &XEXP (ad, 0), opnum,
+ type, 0, insn);
return 1;
}
@@ -4396,12 +4860,14 @@ find_reloads_address (mode, memrefloc, ad, loc, opnum, type, ind_levels)
loc = &XEXP (*memrefloc, 0);
}
- find_reloads_address_part (ad, loc, BASE_REG_CLASS, Pmode, opnum, type,
+ find_reloads_address_part (ad, loc, reload_address_base_reg_class,
+ Pmode, opnum, type,
ind_levels);
return 1;
}
- return find_reloads_address_1 (ad, 0, loc, opnum, type, ind_levels);
+ return find_reloads_address_1 (mode, ad, 0, loc, opnum, type, ind_levels,
+ insn);
}
/* Find all pseudo regs appearing in AD
@@ -4445,6 +4911,10 @@ subst_reg_equivs (ad)
if (XEXP (ad, 0) == frame_pointer_rtx
&& GET_CODE (XEXP (ad, 1)) == CONST_INT)
return ad;
+ break;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -4498,10 +4968,10 @@ form_sum (x, y)
if (GET_CODE (y) == CONST)
y = XEXP (y, 0);
- return gen_rtx (CONST, VOIDmode, gen_rtx (PLUS, mode, x, y));
+ return gen_rtx_CONST (VOIDmode, gen_rtx_PLUS (mode, x, y));
}
- return gen_rtx (PLUS, mode, x, y);
+ return gen_rtx_PLUS (mode, x, y);
}
/* If ADDR is a sum containing a pseudo register that should be
@@ -4564,9 +5034,11 @@ subst_indexed_address (addr)
return addr;
}
-/* Record the pseudo registers we must reload into hard registers
- in a subexpression of a would-be memory address, X.
- (This function is not called if the address we find is strictly valid.)
+/* Record the pseudo registers we must reload into hard registers in a
+ subexpression of a would-be memory address, X referring to a value
+ in mode MODE. (This function is not called if the address we find
+ is strictly valid.)
+
CONTEXT = 1 means we are considering regs as index regs,
= 0 means we are considering them as base regs.
@@ -4575,6 +5047,9 @@ subst_indexed_address (addr)
IND_LEVELS says how many levels of indirect addressing are
supported at this point in the address.
+ INSN, if nonzero, is the insn in which we do the reload. It is used
+ to determine if we may generate output reloads.
+
We return nonzero if X, as a whole, is reloaded or replaced. */
/* Note that we take shortcuts assuming that no multi-reg machine mode
@@ -4584,13 +5059,15 @@ subst_indexed_address (addr)
could have addressing modes that this does not handle right. */
static int
-find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
+find_reloads_address_1 (mode, x, context, loc, opnum, type, ind_levels, insn)
+ enum machine_mode mode;
rtx x;
int context;
rtx *loc;
int opnum;
enum reload_type type;
int ind_levels;
+ rtx insn;
{
register RTX_CODE code = GET_CODE (x);
@@ -4610,8 +5087,8 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
op0 = SUBREG_REG (op0);
code0 = GET_CODE (op0);
if (code0 == REG && REGNO (op0) < FIRST_PSEUDO_REGISTER)
- op0 = gen_rtx (REG, word_mode,
- REGNO (op0) + SUBREG_WORD (orig_op0));
+ op0 = gen_rtx_REG (word_mode,
+ REGNO (op0) + SUBREG_WORD (orig_op0));
}
if (GET_CODE (op1) == SUBREG)
@@ -4619,81 +5096,81 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
op1 = SUBREG_REG (op1);
code1 = GET_CODE (op1);
if (code1 == REG && REGNO (op1) < FIRST_PSEUDO_REGISTER)
- op1 = gen_rtx (REG, GET_MODE (op1),
- REGNO (op1) + SUBREG_WORD (orig_op1));
+ op1 = gen_rtx_REG (GET_MODE (op1),
+ REGNO (op1) + SUBREG_WORD (orig_op1));
}
if (code0 == MULT || code0 == SIGN_EXTEND || code0 == TRUNCATE
|| code0 == ZERO_EXTEND || code1 == MEM)
{
- find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
- ind_levels);
- find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
- ind_levels);
+ find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
+ type, ind_levels, insn);
+ find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+ type, ind_levels, insn);
}
else if (code1 == MULT || code1 == SIGN_EXTEND || code1 == TRUNCATE
|| code1 == ZERO_EXTEND || code0 == MEM)
{
- find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
- ind_levels);
- find_reloads_address_1 (orig_op1, 1, &XEXP (x, 1), opnum, type,
- ind_levels);
+ find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
+ type, ind_levels, insn);
+ find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
+ type, ind_levels, insn);
}
else if (code0 == CONST_INT || code0 == CONST
|| code0 == SYMBOL_REF || code0 == LABEL_REF)
- find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
- ind_levels);
+ find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+ type, ind_levels, insn);
else if (code1 == CONST_INT || code1 == CONST
|| code1 == SYMBOL_REF || code1 == LABEL_REF)
- find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
- ind_levels);
+ find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
+ type, ind_levels, insn);
else if (code0 == REG && code1 == REG)
{
if (REG_OK_FOR_INDEX_P (op0)
- && REG_OK_FOR_BASE_P (op1))
+ && REG_MODE_OK_FOR_BASE_P (op1, mode))
return 0;
else if (REG_OK_FOR_INDEX_P (op1)
- && REG_OK_FOR_BASE_P (op0))
+ && REG_MODE_OK_FOR_BASE_P (op0, mode))
return 0;
- else if (REG_OK_FOR_BASE_P (op1))
- find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
- ind_levels);
- else if (REG_OK_FOR_BASE_P (op0))
- find_reloads_address_1 (orig_op1, 1, &XEXP (x, 1), opnum, type,
- ind_levels);
+ else if (REG_MODE_OK_FOR_BASE_P (op1, mode))
+ find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
+ type, ind_levels, insn);
+ else if (REG_MODE_OK_FOR_BASE_P (op0, mode))
+ find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
+ type, ind_levels, insn);
else if (REG_OK_FOR_INDEX_P (op1))
- find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
- ind_levels);
+ find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
+ type, ind_levels, insn);
else if (REG_OK_FOR_INDEX_P (op0))
- find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
- ind_levels);
+ find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+ type, ind_levels, insn);
else
{
- find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
- ind_levels);
- find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
- ind_levels);
+ find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
+ type, ind_levels, insn);
+ find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+ type, ind_levels, insn);
}
}
else if (code0 == REG)
{
- find_reloads_address_1 (orig_op0, 1, &XEXP (x, 0), opnum, type,
- ind_levels);
- find_reloads_address_1 (orig_op1, 0, &XEXP (x, 1), opnum, type,
- ind_levels);
+ find_reloads_address_1 (mode, orig_op0, 1, &XEXP (x, 0), opnum,
+ type, ind_levels, insn);
+ find_reloads_address_1 (mode, orig_op1, 0, &XEXP (x, 1), opnum,
+ type, ind_levels, insn);
}
else if (code1 == REG)
{
- find_reloads_address_1 (orig_op1, 1, &XEXP (x, 1), opnum, type,
- ind_levels);
- find_reloads_address_1 (orig_op0, 0, &XEXP (x, 0), opnum, type,
- ind_levels);
+ find_reloads_address_1 (mode, orig_op1, 1, &XEXP (x, 1), opnum,
+ type, ind_levels, insn);
+ find_reloads_address_1 (mode, orig_op0, 0, &XEXP (x, 0), opnum,
+ type, ind_levels, insn);
}
}
@@ -4719,11 +5196,15 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
if (reg_equiv_address[regno] != 0)
{
rtx tem = make_memloc (XEXP (x, 0), regno);
- /* First reload the memory location's address. */
+ /* First reload the memory location's address.
+ We can't use ADDR_TYPE (type) here, because we need to
+ write back the value after reading it, hence we actually
+ need two registers. */
find_reloads_address (GET_MODE (tem), 0, XEXP (tem, 0),
- &XEXP (tem, 0), opnum, type, ind_levels);
+ &XEXP (tem, 0), opnum, type,
+ ind_levels, insn);
/* Put this inside a new increment-expression. */
- x = gen_rtx (GET_CODE (x), GET_MODE (x), tem);
+ x = gen_rtx_fmt_e (GET_CODE (x), GET_MODE (x), tem);
/* Proceed to reload that, as if it contained a register. */
}
@@ -4742,19 +5223,55 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
regno = reg_renumber[regno];
if ((regno >= FIRST_PSEUDO_REGISTER
|| !(context ? REGNO_OK_FOR_INDEX_P (regno)
- : REGNO_OK_FOR_BASE_P (regno))))
+ : REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
{
+#ifdef AUTO_INC_DEC
register rtx link;
-
- int reloadnum
- = push_reload (x, NULL_RTX, loc, NULL_PTR,
- context ? INDEX_REG_CLASS : BASE_REG_CLASS,
- GET_MODE (x), GET_MODE (x), VOIDmode, 0,
- opnum, type);
- reload_inc[reloadnum]
- = find_inc_amount (PATTERN (this_insn), XEXP (x_orig, 0));
-
- value = 1;
+#endif
+ int reloadnum;
+
+ /* If we can output the register afterwards, do so, this
+ saves the extra update.
+ We can do so if we have an INSN - i.e. no JUMP_INSN nor
+ CALL_INSN - and it does not set CC0.
+ But don't do this if we cannot directly address the
+ memory location, since this will make it harder to
+ reuse address reloads, and increases register pressure.
+ Also don't do this if we can probably update x directly. */
+ rtx equiv = reg_equiv_mem[regno];
+ int icode = (int) add_optab->handlers[(int) Pmode].insn_code;
+ if (insn && GET_CODE (insn) == INSN && equiv
+#ifdef HAVE_cc0
+ && ! sets_cc0_p (PATTERN (insn))
+#endif
+ && ! (icode != CODE_FOR_nothing
+ && (*insn_operand_predicate[icode][0]) (equiv, Pmode)
+ && (*insn_operand_predicate[icode][1]) (equiv, Pmode)))
+ {
+ loc = &XEXP (x, 0);
+ x = XEXP (x, 0);
+ reloadnum
+ = push_reload (x, x, loc, loc,
+ (context
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
+ GET_MODE (x), GET_MODE (x), 0, 0,
+ opnum, RELOAD_OTHER);
+ }
+ else
+ {
+ reloadnum
+ = push_reload (x, NULL_RTX, loc, NULL_PTR,
+ (context
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
+ GET_MODE (x), GET_MODE (x), 0, 0,
+ opnum, type);
+ reload_inc[reloadnum]
+ = find_inc_amount (PATTERN (this_insn), XEXP (x_orig, 0));
+
+ value = 1;
+ }
#ifdef AUTO_INC_DEC
/* Update the REG_INC notes. */
@@ -4785,12 +5302,17 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
Note that this is actually conservative: it would be slightly
more efficient to use the value of SPILL_INDIRECT_LEVELS from
reload1.c here. */
+ /* We can't use ADDR_TYPE (type) here, because we need to
+ write back the value after reading it, hence we actually
+ need two registers. */
find_reloads_address (GET_MODE (x), &XEXP (x, 0),
XEXP (XEXP (x, 0), 0), &XEXP (XEXP (x, 0), 0),
- opnum, type, ind_levels);
+ opnum, type, ind_levels, insn);
reloadnum = push_reload (x, NULL_RTX, loc, NULL_PTR,
- context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ (context
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
reload_inc[reloadnum]
= find_inc_amount (PATTERN (this_insn), XEXP (x, 0));
@@ -4817,9 +5339,10 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
reload1.c here. */
find_reloads_address (GET_MODE (x), loc, XEXP (x, 0), &XEXP (x, 0),
- opnum, type, ind_levels);
+ opnum, ADDR_TYPE (type), ind_levels, insn);
push_reload (*loc, NULL_RTX, loc, NULL_PTR,
- context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ (context ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
@@ -4830,8 +5353,9 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
if (reg_equiv_constant[regno] != 0)
{
find_reloads_address_part (reg_equiv_constant[regno], loc,
- (context ? INDEX_REG_CLASS
- : BASE_REG_CLASS),
+ (context
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
GET_MODE (x), opnum, type, ind_levels);
return 1;
}
@@ -4841,7 +5365,9 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
if (reg_equiv_mem[regno] != 0)
{
push_reload (reg_equiv_mem[regno], NULL_RTX, loc, NULL_PTR,
- context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ (context
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
@@ -4851,7 +5377,7 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
{
x = make_memloc (x, regno);
find_reloads_address (GET_MODE (x), 0, XEXP (x, 0), &XEXP (x, 0),
- opnum, type, ind_levels);
+ opnum, ADDR_TYPE (type), ind_levels, insn);
}
if (reg_renumber[regno] >= 0)
@@ -4859,10 +5385,12 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
if ((regno >= FIRST_PSEUDO_REGISTER
|| !(context ? REGNO_OK_FOR_INDEX_P (regno)
- : REGNO_OK_FOR_BASE_P (regno))))
+ : REGNO_MODE_OK_FOR_BASE_P (regno, mode))))
{
push_reload (x, NULL_RTX, loc, NULL_PTR,
- context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ (context
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
@@ -4874,7 +5402,9 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
if (regno_clobbered_p (regno, this_insn))
{
push_reload (x, NULL_RTX, loc, NULL_PTR,
- context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ (context
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
@@ -4892,10 +5422,12 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
int regno = REGNO (SUBREG_REG (x)) + SUBREG_WORD (x);
if (! (context ? REGNO_OK_FOR_INDEX_P (regno)
- : REGNO_OK_FOR_BASE_P (regno)))
+ : REGNO_MODE_OK_FOR_BASE_P (regno, mode)))
{
push_reload (x, NULL_RTX, loc, NULL_PTR,
- context ? INDEX_REG_CLASS : BASE_REG_CLASS,
+ (context
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class),
GET_MODE (x), VOIDmode, 0, 0, opnum, type);
return 1;
}
@@ -4905,7 +5437,8 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
else
{
enum reg_class class = (context
- ? INDEX_REG_CLASS : BASE_REG_CLASS);
+ ? reload_address_index_reg_class
+ : reload_address_base_reg_class);
if (CLASS_MAX_NREGS (class, GET_MODE (SUBREG_REG (x)))
> reg_class_size[class])
{
@@ -4916,6 +5449,9 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
}
}
break;
+
+ default:
+ break;
}
{
@@ -4925,8 +5461,8 @@ find_reloads_address_1 (x, context, loc, opnum, type, ind_levels)
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'e')
- find_reloads_address_1 (XEXP (x, i), context, &XEXP (x, i),
- opnum, type, ind_levels);
+ find_reloads_address_1 (mode, XEXP (x, i), context, &XEXP (x, i),
+ opnum, type, ind_levels, insn);
}
}
@@ -4964,7 +5500,7 @@ find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels)
{
rtx tem = x = force_const_mem (mode, x);
find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
- opnum, type, ind_levels);
+ opnum, type, ind_levels, 0);
}
else if (GET_CODE (x) == PLUS
@@ -4974,9 +5510,9 @@ find_reloads_address_part (x, loc, class, mode, opnum, type, ind_levels)
{
rtx tem = force_const_mem (GET_MODE (x), XEXP (x, 1));
- x = gen_rtx (PLUS, GET_MODE (x), XEXP (x, 0), tem);
+ x = gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0), tem);
find_reloads_address (mode, &tem, XEXP (tem, 0), &XEXP (tem, 0),
- opnum, type, ind_levels);
+ opnum, type, ind_levels, 0);
}
push_reload (x, NULL_RTX, loc, NULL_PTR, class,
@@ -5006,7 +5542,7 @@ subst_reloads ()
do the wrong thing if RELOADREG is multi-word. RELOADREG
will always be a REG here. */
if (GET_MODE (reloadreg) != r->mode && r->mode != VOIDmode)
- reloadreg = gen_rtx (REG, r->mode, REGNO (reloadreg));
+ reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
/* If we are putting this into a SUBREG and RELOADREG is a
SUBREG, we would be making nested SUBREGs, so we have to fix
@@ -5073,6 +5609,25 @@ copy_replacements (x, y)
}
}
}
+
+/* Change any replacements being done to *X to be done to *Y */
+
+void
+move_replacements (x, y)
+ rtx *x;
+ rtx *y;
+{
+ int i;
+
+ for (i = 0; i < n_replacements; i++)
+ if (replacements[i].subreg_loc == x)
+ replacements[i].subreg_loc = y;
+ else if (replacements[i].where == x)
+ {
+ replacements[i].where = y;
+ replacements[i].subreg_loc = 0;
+ }
+}
/* If LOC was scheduled to be replaced by something, return the replacement.
Otherwise, return *LOC. */
@@ -5090,7 +5645,7 @@ find_replacement (loc)
if (reloadreg && r->where == loc)
{
if (r->mode != VOIDmode && GET_MODE (reloadreg) != r->mode)
- reloadreg = gen_rtx (REG, r->mode, REGNO (reloadreg));
+ reloadreg = gen_rtx_REG (r->mode, REGNO (reloadreg));
return reloadreg;
}
@@ -5101,16 +5656,28 @@ find_replacement (loc)
??? Is it actually still ever a SUBREG? If so, why? */
if (GET_CODE (reloadreg) == REG)
- return gen_rtx (REG, GET_MODE (*loc),
- REGNO (reloadreg) + SUBREG_WORD (*loc));
+ return gen_rtx_REG (GET_MODE (*loc),
+ REGNO (reloadreg) + SUBREG_WORD (*loc));
else if (GET_MODE (reloadreg) == GET_MODE (*loc))
return reloadreg;
else
- return gen_rtx (SUBREG, GET_MODE (*loc), SUBREG_REG (reloadreg),
- SUBREG_WORD (reloadreg) + SUBREG_WORD (*loc));
+ return gen_rtx_SUBREG (GET_MODE (*loc), SUBREG_REG (reloadreg),
+ SUBREG_WORD (reloadreg) + SUBREG_WORD (*loc));
}
}
+ /* If *LOC is a PLUS, MINUS, or MULT, see if a replacement is scheduled for
+ what's inside and make a new rtl if so. */
+ if (GET_CODE (*loc) == PLUS || GET_CODE (*loc) == MINUS
+ || GET_CODE (*loc) == MULT)
+ {
+ rtx x = find_replacement (&XEXP (*loc, 0));
+ rtx y = find_replacement (&XEXP (*loc, 1));
+
+ if (x != XEXP (*loc, 0) || y != XEXP (*loc, 1))
+ return gen_rtx_fmt_ee (GET_CODE (*loc), GET_MODE (*loc), x, y);
+ }
+
return *loc;
}
@@ -5205,6 +5772,9 @@ refers_to_regno_for_reload_p (regno, endregno, x, loc)
return 0;
x = SET_SRC (x);
goto repeat;
+
+ default:
+ break;
}
/* X does not match, so try its subexpressions. */
@@ -5252,7 +5822,14 @@ reg_overlap_mentioned_for_reload_p (x, in)
{
int regno, endregno;
- if (GET_CODE (x) == SUBREG)
+ /* Overly conservative. */
+ if (GET_CODE (x) == STRICT_LOW_PART)
+ x = XEXP (x, 0);
+
+ /* If either argument is a constant, then modifying X can not affect IN. */
+ if (CONSTANT_P (x) || CONSTANT_P (in))
+ return 0;
+ else if (GET_CODE (x) == SUBREG)
{
regno = REGNO (SUBREG_REG (x));
if (regno < FIRST_PSEUDO_REGISTER)
@@ -5274,8 +5851,6 @@ reg_overlap_mentioned_for_reload_p (x, in)
abort ();
}
}
- else if (CONSTANT_P (x))
- return 0;
else if (GET_CODE (x) == MEM)
return refers_to_mem_for_reload_p (in);
else if (GET_CODE (x) == SCRATCH || GET_CODE (x) == PC
@@ -5385,6 +5960,8 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
case POST_DEC:
case PRE_DEC:
return 0;
+ default:
+ break;
}
goal_mem = 1;
}
@@ -5394,6 +5971,10 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
&& XEXP (goal, 0) == stack_pointer_rtx
&& CONSTANT_P (XEXP (goal, 1)))
goal_const = need_stable_sp = 1;
+ else if (GET_CODE (goal) == PLUS
+ && XEXP (goal, 0) == frame_pointer_rtx
+ && CONSTANT_P (XEXP (goal, 1)))
+ goal_const = 1;
else
return 0;
@@ -5416,7 +5997,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
if (p == 0 || GET_CODE (p) == CODE_LABEL)
return 0;
if (GET_CODE (p) == INSN
- /* If we don't want spill regs ... */
+ /* If we don't want spill regs ... */
&& (! (reload_reg_p != 0
&& reload_reg_p != (short *) (HOST_WIDE_INT) 1)
/* ... then ignore insns introduced by reload; they aren't useful
@@ -5441,6 +6022,9 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
&& (valueno = true_regnum (valtry = SET_SRC (pat))) >= 0)
||
(goal_const && rtx_equal_p (SET_SRC (pat), goal)
+ /* When looking for stack pointer + const,
+ make sure we don't use a stack adjust. */
+ && !reg_overlap_mentioned_for_reload_p (SET_DEST (pat), goal)
&& (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0)
|| (goal_mem
&& (valueno = true_regnum (valtry = SET_DEST (pat))) >= 0
@@ -5505,7 +6089,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
/* If we propose to get the value from the stack pointer or if GOAL is
a MEM based on the stack pointer, we need a stable SP. */
- if (valueno == STACK_POINTER_REGNUM
+ if (valueno == STACK_POINTER_REGNUM || regno == STACK_POINTER_REGNUM
|| (goal_mem && reg_overlap_mentioned_for_reload_p (stack_pointer_rtx,
goal)))
need_stable_sp = 1;
@@ -5517,7 +6101,7 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
/* Reject VALUE if it was loaded from GOAL
and is also a register that appears in the address of GOAL. */
- if (goal_mem && value == SET_DEST (PATTERN (where))
+ if (goal_mem && value == SET_DEST (single_set (where))
&& refers_to_regno_for_reload_p (valueno,
(valueno
+ HARD_REGNO_NREGS (valueno, mode)),
@@ -5614,12 +6198,17 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
{
+ pat = PATTERN (p);
+
+ /* Watch out for unspec_volatile, and volatile asms. */
+ if (volatile_insn_p (pat))
+ return 0;
+
/* If this insn P stores in either GOAL or VALUE, return 0.
If GOAL is a memory ref and this insn writes memory, return 0.
If GOAL is a memory ref and its address is not constant,
and this insn P changes a register used in GOAL, return 0. */
- pat = PATTERN (p);
if (GET_CODE (pat) == SET || GET_CODE (pat) == CLOBBER)
{
register rtx dest = SET_DEST (pat);
@@ -5644,6 +6233,8 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
if (goal_mem_addr_varies
&& reg_overlap_mentioned_for_reload_p (dest, goal))
return 0;
+ if (xregno == STACK_POINTER_REGNUM && need_stable_sp)
+ return 0;
}
else if (goal_mem && GET_CODE (dest) == MEM
&& ! push_operand (dest, GET_MODE (dest)))
@@ -5686,10 +6277,15 @@ find_equiv_reg (goal, insn, class, other, reload_reg_p, goalreg, mode)
&& reg_overlap_mentioned_for_reload_p (dest,
goal))
return 0;
+ if (xregno == STACK_POINTER_REGNUM && need_stable_sp)
+ return 0;
}
else if (goal_mem && GET_CODE (dest) == MEM
&& ! push_operand (dest, GET_MODE (dest)))
return 0;
+ else if (GET_CODE (dest) == MEM && regno >= FIRST_PSEUDO_REGISTER
+ && reg_equiv_memory_loc[regno] != 0)
+ return 0;
else if (need_stable_sp
&& push_operand (dest, GET_MODE (dest)))
return 0;
@@ -5849,8 +6445,10 @@ static char *reload_when_needed_name[] =
"RELOAD_FOR_INPUT",
"RELOAD_FOR_OUTPUT",
"RELOAD_FOR_INSN",
- "RELOAD_FOR_INPUT_ADDRESS",
+ "RELOAD_FOR_INPUT_ADDRESS",
+ "RELOAD_FOR_INPADDR_ADDRESS",
"RELOAD_FOR_OUTPUT_ADDRESS",
+ "RELOAD_FOR_OUTADDR_ADDRESS",
"RELOAD_FOR_OPERAND_ADDRESS",
"RELOAD_FOR_OPADDR_ADDR",
"RELOAD_OTHER",
@@ -5859,97 +6457,100 @@ static char *reload_when_needed_name[] =
static char *reg_class_names[] = REG_CLASS_NAMES;
-/* This function is used to print the variables set by 'find_reloads' */
+/* These functions are used to print the variables set by 'find_reloads' */
void
-debug_reload()
+debug_reload_to_stream (f)
+ FILE *f;
{
int r;
+ char *prefix;
- fprintf (stderr, "\nn_reloads = %d\n", n_reloads);
-
+ if (! f)
+ f = stderr;
for (r = 0; r < n_reloads; r++)
{
- fprintf (stderr, "\nRELOAD %d\n", r);
+ fprintf (f, "Reload %d: ", r);
- if (reload_in[r])
+ if (reload_in[r] != 0)
{
- fprintf (stderr, "\nreload_in (%s) = ",
+ fprintf (f, "reload_in (%s) = ",
GET_MODE_NAME (reload_inmode[r]));
- debug_rtx (reload_in[r]);
+ print_inline_rtx (f, reload_in[r], 24);
+ fprintf (f, "\n\t");
}
- if (reload_out[r])
+ if (reload_out[r] != 0)
{
- fprintf (stderr, "\nreload_out (%s) = ",
+ fprintf (f, "reload_out (%s) = ",
GET_MODE_NAME (reload_outmode[r]));
- debug_rtx (reload_out[r]);
+ print_inline_rtx (f, reload_out[r], 24);
+ fprintf (f, "\n\t");
}
- fprintf (stderr, "%s, ", reg_class_names[(int) reload_reg_class[r]]);
+ fprintf (f, "%s, ", reg_class_names[(int) reload_reg_class[r]]);
- fprintf (stderr, "%s (opnum = %d)",
- reload_when_needed_name[(int)reload_when_needed[r]],
+ fprintf (f, "%s (opnum = %d)",
+ reload_when_needed_name[(int) reload_when_needed[r]],
reload_opnum[r]);
if (reload_optional[r])
- fprintf (stderr, ", optional");
+ fprintf (f, ", optional");
- if (reload_in[r])
- fprintf (stderr, ", inc by %d\n", reload_inc[r]);
+ if (reload_nongroup[r])
+ fprintf (stderr, ", nongroup");
+
+ if (reload_inc[r] != 0)
+ fprintf (f, ", inc by %d", reload_inc[r]);
if (reload_nocombine[r])
- fprintf (stderr, ", can combine", reload_nocombine[r]);
+ fprintf (f, ", can't combine");
if (reload_secondary_p[r])
- fprintf (stderr, ", secondary_reload_p");
+ fprintf (f, ", secondary_reload_p");
- if (reload_in_reg[r])
+ if (reload_in_reg[r] != 0)
{
- fprintf (stderr, "\nreload_in_reg:\t\t\t");
- debug_rtx (reload_in_reg[r]);
+ fprintf (f, "\n\treload_in_reg: ");
+ print_inline_rtx (f, reload_in_reg[r], 24);
}
- if (reload_reg_rtx[r])
+ if (reload_reg_rtx[r] != 0)
{
- fprintf (stderr, "\nreload_reg_rtx:\t\t\t");
- debug_rtx (reload_reg_rtx[r]);
+ fprintf (f, "\n\treload_reg_rtx: ");
+ print_inline_rtx (f, reload_reg_rtx[r], 24);
}
+ prefix = "\n\t";
if (reload_secondary_in_reload[r] != -1)
{
- fprintf (stderr, "\nsecondary_in_reload = ");
- fprintf (stderr, "%d ", reload_secondary_in_reload[r]);
+ fprintf (f, "%ssecondary_in_reload = %d",
+ prefix, reload_secondary_in_reload[r]);
+ prefix = ", ";
}
if (reload_secondary_out_reload[r] != -1)
- {
- if (reload_secondary_in_reload[r] != -1)
- fprintf (stderr, ", secondary_out_reload = ");
- else
- fprintf (stderr, "\nsecondary_out_reload = ");
-
- fprintf (stderr, "%d", reload_secondary_out_reload[r]);
- }
-
+ fprintf (f, "%ssecondary_out_reload = %d\n",
+ prefix, reload_secondary_out_reload[r]);
+ prefix = "\n\t";
if (reload_secondary_in_icode[r] != CODE_FOR_nothing)
{
- fprintf (stderr, "\nsecondary_in_icode = ");
- fprintf (stderr, "%s", insn_name[r]);
+ fprintf (stderr, "%ssecondary_in_icode = %s", prefix,
+ insn_name[reload_secondary_in_icode[r]]);
+ prefix = ", ";
}
if (reload_secondary_out_icode[r] != CODE_FOR_nothing)
- {
- if (reload_secondary_in_icode[r] != CODE_FOR_nothing)
- fprintf (stderr, ", secondary_out_icode = ");
- else
- fprintf (stderr, "\nsecondary_out_icode = ");
+ fprintf (stderr, "%ssecondary_out_icode = %s", prefix,
+ insn_name[reload_secondary_out_icode[r]]);
- fprintf (stderr, "%s ", insn_name[r]);
- }
- fprintf (stderr, "\n");
+ fprintf (f, "\n");
}
+}
- fprintf (stderr, "\n");
+void
+debug_reload ()
+{
+ debug_reload_to_stream (stderr);
}
diff --git a/contrib/gcc/reload.h b/contrib/gcc/reload.h
index d10efb5..d99b0c1 100644
--- a/contrib/gcc/reload.h
+++ b/contrib/gcc/reload.h
@@ -1,5 +1,5 @@
/* Communication between reload.c and reload1.c.
- Copyright (C) 1987, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 91-95, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -34,11 +34,24 @@ Boston, MA 02111-1307, USA. */
#define HAVE_SECONDARY_RELOADS
#endif
+/* If MEMORY_MOVE_COST isn't defined, give it a default here. */
+#ifndef MEMORY_MOVE_COST
+#ifdef HAVE_SECONDARY_RELOADS
+#define MEMORY_MOVE_COST(MODE,CLASS,IN) \
+ (4 + memory_move_secondary_cost ((MODE), (CLASS), (IN)))
+#else
+#define MEMORY_MOVE_COST(MODE,CLASS,IN) 4
+#endif
+#endif
+extern int memory_move_secondary_cost PROTO ((enum machine_mode, enum reg_class, int));
+
/* See reload.c and reload1.c for comments on these variables. */
/* Maximum number of reloads we can need. */
#define MAX_RELOADS (2 * MAX_RECOG_OPERANDS * (MAX_REGS_PER_ADDRESS + 1))
+extern enum reg_class reload_address_base_reg_class;
+extern enum reg_class reload_address_index_reg_class;
extern rtx reload_in[MAX_RELOADS];
extern rtx reload_out[MAX_RELOADS];
extern rtx reload_in_reg[MAX_RELOADS];
@@ -46,6 +59,7 @@ extern enum reg_class reload_reg_class[MAX_RELOADS];
extern enum machine_mode reload_inmode[MAX_RELOADS];
extern enum machine_mode reload_outmode[MAX_RELOADS];
extern char reload_optional[MAX_RELOADS];
+extern char reload_nongroup[MAX_RELOADS];
extern int reload_inc[MAX_RELOADS];
extern int reload_opnum[MAX_RELOADS];
extern int reload_secondary_p[MAX_RELOADS];
@@ -68,7 +82,9 @@ extern rtx reload_reg_rtx[MAX_RELOADS];
something used before or after the insn
RELOAD_FOR_INPUT_ADDRESS reload for parts of the address of an object
that is an input reload
- RELOAD_FOR_OUTPUT_ADDRESS likewise, for output reload
+ RELOAD_FOR_INPADDR_ADDRESS reload needed for RELOAD_FOR_INPUT_ADDRESS
+ RELOAD_FOR_OUTPUT_ADDRESS like RELOAD_FOR INPUT_ADDRESS, for output
+ RELOAD_FOR_OUTADDR_ADDRESS reload needed for RELOAD_FOR_OUTPUT_ADDRESS
RELOAD_FOR_OPERAND_ADDRESS reload for the address of a non-reloaded
operand; these don't conflict with
any other addresses.
@@ -84,7 +100,8 @@ extern rtx reload_reg_rtx[MAX_RELOADS];
enum reload_type
{
RELOAD_FOR_INPUT, RELOAD_FOR_OUTPUT, RELOAD_FOR_INSN,
- RELOAD_FOR_INPUT_ADDRESS, RELOAD_FOR_OUTPUT_ADDRESS,
+ RELOAD_FOR_INPUT_ADDRESS, RELOAD_FOR_INPADDR_ADDRESS,
+ RELOAD_FOR_OUTPUT_ADDRESS, RELOAD_FOR_OUTADDR_ADDRESS,
RELOAD_FOR_OPERAND_ADDRESS, RELOAD_FOR_OPADDR_ADDR,
RELOAD_OTHER, RELOAD_FOR_OTHER_ADDRESS
};
@@ -140,10 +157,8 @@ extern void clear_secondary_mem PROTO((void));
reload TO. */
extern void transfer_replacements PROTO((int, int));
-/* Return 1 if ADDR is a valid memory address for mode MODE,
- and check that each pseudo reg has the proper kind of
- hard reg. */
-extern int strict_memory_address_p PROTO((enum machine_mode, rtx));
+/* Remove all replacements in reload FROM. */
+extern void remove_replacements PROTO((int));
/* Like rtx_equal_p except that it allows a REG and a SUBREG to match
if they are the same hard reg, and has special hacks for
@@ -176,6 +191,9 @@ extern void subst_reloads PROTO((void));
the RTL. */
extern void copy_replacements PROTO((rtx, rtx));
+/* Change any replacements being done to *X to be done to *Y */
+extern void move_replacements PROTO((rtx *x, rtx *y));
+
/* If LOC was scheduled to be replaced by something, return the replacement.
Otherwise, return *LOC. */
extern rtx find_replacement PROTO((rtx *));
@@ -200,14 +218,17 @@ extern rtx find_equiv_reg PROTO((rtx, rtx, enum reg_class, int, short *,
/* Return 1 if register REGNO is the subject of a clobber in insn INSN. */
extern int regno_clobbered_p PROTO((int, rtx));
-
/* Functions in reload1.c: */
+extern int reloads_conflict PROTO ((int, int));
+
+int count_occurrences PROTO((rtx, rtx));
+
/* Initialize the reload pass once per compilation. */
extern void init_reload PROTO((void));
/* The reload pass itself. */
-extern int reload STDIO_PROTO((rtx, int, FILE *));
+extern int reload PROTO((rtx, int, FILE *));
/* Mark the slots in regs_ever_live for the hard regs
used by pseudo-reg number REGNO. */
diff --git a/contrib/gcc/reload1.c b/contrib/gcc/reload1.c
index 33c77e4..c2987bb 100644
--- a/contrib/gcc/reload1.c
+++ b/contrib/gcc/reload1.c
@@ -1,5 +1,5 @@
/* Reload pseudo regs into hard regs for insns that require hard regs.
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -19,8 +19,11 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
+
+#include "machmode.h"
+#include "hard-reg-set.h"
#include "rtl.h"
#include "obstack.h"
#include "insn-config.h"
@@ -29,12 +32,12 @@ Boston, MA 02111-1307, USA. */
#include "flags.h"
#include "expr.h"
#include "regs.h"
-#include "hard-reg-set.h"
#include "reload.h"
#include "recog.h"
#include "basic-block.h"
#include "output.h"
#include "real.h"
+#include "toplev.h"
/* This file contains the reload pass of the compiler, which is
run after register allocation has been done. It checks that
@@ -73,13 +76,9 @@ Boston, MA 02111-1307, USA. */
#ifndef REGISTER_MOVE_COST
#define REGISTER_MOVE_COST(x, y) 2
#endif
-
-#ifndef MEMORY_MOVE_COST
-#define MEMORY_MOVE_COST(x) 4
-#endif
/* During reload_as_needed, element N contains a REG rtx for the hard reg
- into which reg N has been reloaded (perhaps for a previous insn). */
+ into which reg N has been reloaded (perhaps for a previous insn). */
static rtx *reg_last_reload_reg;
/* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn
@@ -118,19 +117,23 @@ static int *reg_max_ref_width;
constant or memory slot. */
static rtx *reg_equiv_init;
-/* During reload_as_needed, element N contains the last pseudo regno
- reloaded into the Nth reload register. This vector is in parallel
- with spill_regs. If that pseudo reg occupied more than one register,
+/* During reload_as_needed, element N contains the last pseudo regno reloaded
+ into hard register N. If that pseudo reg occupied more than one register,
reg_reloaded_contents points to that pseudo for each spill register in
use; all of these must remain set for an inheritance to occur. */
static int reg_reloaded_contents[FIRST_PSEUDO_REGISTER];
/* During reload_as_needed, element N contains the insn for which
- the Nth reload register was last used. This vector is in parallel
- with spill_regs, and its contents are significant only when
- reg_reloaded_contents is significant. */
+ hard register N was last used. Its contents are significant only
+ when reg_reloaded_valid is set for this register. */
static rtx reg_reloaded_insn[FIRST_PSEUDO_REGISTER];
+/* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid */
+static HARD_REG_SET reg_reloaded_valid;
+/* Indicate if the register was dead at the end of the reload.
+ This is only valid if reg_reloaded_contents is set and valid. */
+static HARD_REG_SET reg_reloaded_dead;
+
/* Number of spill-regs so far; number of valid elements of spill_regs. */
static int n_spills;
@@ -159,7 +162,7 @@ HARD_REG_SET forbidden_regs;
/* This reg set indicates registers that are not good for spill registers.
They will not be used to complete groups of spill registers. This includes
all fixed registers, registers that may be eliminated, and, if
- SMALL_REGISTER_CLASSES is not defined, registers explicitly used in the rtl.
+ SMALL_REGISTER_CLASSES is zero, registers explicitly used in the rtl.
(spill_reg_order prevents these registers from being used to start a
group.) */
@@ -170,6 +173,13 @@ static HARD_REG_SET bad_spill_regs;
elements that are actually valid; new ones are added at the end. */
static short spill_regs[FIRST_PSEUDO_REGISTER];
+/* This reg set indicates those registers that have been used a spill
+ registers. This information is used in reorg.c, to help figure out
+ what registers are live at any point. It is assumed that all spill_regs
+ are dead at every CODE_LABEL. */
+
+HARD_REG_SET used_spill_regs;
+
/* Index of last register assigned as a spill register. We allocate in
a round-robin fashion. */
@@ -197,12 +207,6 @@ static HARD_REG_SET counted_for_groups;
as part of a group, even if it seems to be otherwise ok. */
static HARD_REG_SET counted_for_nongroups;
-/* Indexed by pseudo reg number N,
- says may not delete stores into the real (memory) home of pseudo N.
- This is set if we already substituted a memory equivalent in some uses,
- which happens when we have to eliminate the fp from it. */
-static char *cannot_omit_stores;
-
/* Nonzero if indirect addressing is supported on the machine; this means
that spilling (REG n) does not require reloading it into a register in
order to do (MEM (REG n)) or (MEM (PLUS (REG n) (CONST_INT c))). The
@@ -246,6 +250,18 @@ int reload_first_uid;
int caller_save_needed;
+/* The register class to use for a base register when reloading an
+ address. This is normally BASE_REG_CLASS, but it may be different
+ when using SMALL_REGISTER_CLASSES and passing parameters in
+ registers. */
+enum reg_class reload_address_base_reg_class;
+
+/* The register class to use for an index register when reloading an
+ address. This is normally INDEX_REG_CLASS, but it may be different
+ when using SMALL_REGISTER_CLASSES and passing parameters in
+ registers. */
+enum reg_class reload_address_index_reg_class;
+
/* Set to 1 while reload_as_needed is operating.
Required by some machines to handle any generated moves differently. */
@@ -270,6 +286,9 @@ char *reload_firstobj;
/* List of labels that must never be deleted. */
extern rtx forced_labels;
+
+/* Allocation number table from global register allocation. */
+extern int *reg_allocno;
/* This structure is used to record information about register eliminations.
Each array entry describes one possible way of eliminating a register
@@ -278,22 +297,22 @@ extern rtx forced_labels;
static struct elim_table
{
- int from; /* Register number to be eliminated. */
- int to; /* Register number used as replacement. */
- int initial_offset; /* Initial difference between values. */
- int can_eliminate; /* Non-zero if this elimination can be done. */
+ int from; /* Register number to be eliminated. */
+ int to; /* Register number used as replacement. */
+ int initial_offset; /* Initial difference between values. */
+ int can_eliminate; /* Non-zero if this elimination can be done. */
int can_eliminate_previous; /* Value of CAN_ELIMINATE in previous scan over
- insns made by reload. */
- int offset; /* Current offset between the two regs. */
- int max_offset; /* Maximum offset between the two regs. */
- int previous_offset; /* Offset at end of previous insn. */
- int ref_outside_mem; /* "to" has been referenced outside a MEM. */
+ insns made by reload. */
+ int offset; /* Current offset between the two regs. */
+ int max_offset; /* Maximum offset between the two regs. */
+ int previous_offset; /* Offset at end of previous insn. */
+ int ref_outside_mem; /* "to" has been referenced outside a MEM. */
rtx from_rtx; /* REG rtx for the register to be eliminated.
We cannot simply compare the number since
we might then spuriously replace a hard
register corresponding to a pseudo
- assigned to the reg to be eliminated. */
- rtx to_rtx; /* REG rtx for the replacement. */
+ assigned to the reg to be eliminated. */
+ rtx to_rtx; /* REG rtx for the replacement. */
} reg_eliminate[] =
/* If a set of eliminable registers was specified, define the table from it.
@@ -349,21 +368,20 @@ static int eliminate_regs_in_insn PROTO((rtx, int));
static void mark_not_eliminable PROTO((rtx, rtx));
static int spill_hard_reg PROTO((int, int, FILE *, int));
static void scan_paradoxical_subregs PROTO((rtx));
-static int hard_reg_use_compare PROTO((struct hard_reg_n_uses *,
- struct hard_reg_n_uses *));
-static void order_regs_for_reload PROTO((void));
-static int compare_spill_regs PROTO((short *, short *));
+static int hard_reg_use_compare PROTO((const GENERIC_PTR, const GENERIC_PTR));
+static void order_regs_for_reload PROTO((int));
+static int compare_spill_regs PROTO((const GENERIC_PTR, const GENERIC_PTR));
static void reload_as_needed PROTO((rtx, int));
static void forget_old_reloads_1 PROTO((rtx, rtx));
-static int reload_reg_class_lower PROTO((short *, short *));
+static int reload_reg_class_lower PROTO((const GENERIC_PTR, const GENERIC_PTR));
static void mark_reload_reg_in_use PROTO((int, int, enum reload_type,
enum machine_mode));
static void clear_reload_reg_in_use PROTO((int, int, enum reload_type,
enum machine_mode));
static int reload_reg_free_p PROTO((int, int, enum reload_type));
static int reload_reg_free_before_p PROTO((int, int, enum reload_type));
+static int reload_reg_free_for_value_p PROTO((int, int, enum reload_type, rtx, rtx, int));
static int reload_reg_reaches_end_p PROTO((int, int, enum reload_type));
-static int reloads_conflict PROTO((int, int));
static int allocate_reload_reg PROTO((int, rtx, int, int));
static void choose_reload_regs PROTO((rtx, rtx));
static void merge_assigned_reloads PROTO((rtx));
@@ -371,7 +389,18 @@ static void emit_reload_insns PROTO((rtx));
static void delete_output_reload PROTO((rtx, int, rtx));
static void inc_for_reload PROTO((rtx, rtx, int));
static int constraint_accepts_reg_p PROTO((char *, rtx));
-static int count_occurrences PROTO((rtx, rtx));
+static void reload_cse_invalidate_regno PROTO((int, enum machine_mode, int));
+static int reload_cse_mem_conflict_p PROTO((rtx, rtx));
+static void reload_cse_invalidate_mem PROTO((rtx));
+static void reload_cse_invalidate_rtx PROTO((rtx, rtx));
+static int reload_cse_regno_equal_p PROTO((int, rtx, enum machine_mode));
+static int reload_cse_noop_set_p PROTO((rtx, rtx));
+static int reload_cse_simplify_set PROTO((rtx, rtx));
+static int reload_cse_simplify_operands PROTO((rtx));
+static void reload_cse_check_clobber PROTO((rtx, rtx));
+static void reload_cse_record_set PROTO((rtx, rtx));
+static void reload_cse_delete_death_notes PROTO((rtx));
+static void reload_cse_no_longer_dead PROTO((int, enum machine_mode));
/* Initialize the reload pass once per compilation. */
@@ -385,30 +414,30 @@ init_reload ()
permitted, zero if it is not permitted at all. */
register rtx tem
- = gen_rtx (MEM, Pmode,
- gen_rtx (PLUS, Pmode,
- gen_rtx (REG, Pmode, LAST_VIRTUAL_REGISTER + 1),
- GEN_INT (4)));
+ = gen_rtx_MEM (Pmode,
+ gen_rtx_PLUS (Pmode,
+ gen_rtx_REG (Pmode, LAST_VIRTUAL_REGISTER + 1),
+ GEN_INT (4)));
spill_indirect_levels = 0;
while (memory_address_p (QImode, tem))
{
spill_indirect_levels++;
- tem = gen_rtx (MEM, Pmode, tem);
+ tem = gen_rtx_MEM (Pmode, tem);
}
/* See if indirect addressing is valid for (MEM (SYMBOL_REF ...)). */
- tem = gen_rtx (MEM, Pmode, gen_rtx (SYMBOL_REF, Pmode, "foo"));
+ tem = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (Pmode, "foo"));
indirect_symref_ok = memory_address_p (QImode, tem);
/* See if reg+reg is a valid (and offsettable) address. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
- tem = gen_rtx (PLUS, Pmode,
- gen_rtx (REG, Pmode, HARD_FRAME_POINTER_REGNUM),
- gen_rtx (REG, Pmode, i));
+ tem = gen_rtx_PLUS (Pmode,
+ gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM),
+ gen_rtx_REG (Pmode, i));
/* This way, we make sure that reg+reg is an offsettable address. */
tem = plus_constant (tem, 4);
@@ -419,9 +448,67 @@ init_reload ()
}
}
- /* Initialize obstack for our rtl allocation. */
+ /* Initialize obstack for our rtl allocation. */
gcc_obstack_init (&reload_obstack);
reload_firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+
+ /* Decide which register class should be used when reloading
+ addresses. If we are using SMALL_REGISTER_CLASSES, and any
+ parameters are passed in registers, then we do not want to use
+ those registers when reloading an address. Otherwise, if a
+ function argument needs a reload, we may wind up clobbering
+ another argument to the function which was already computed. If
+ we find a subset class which simply avoids those registers, we
+ use it instead. ??? It would be better to only use the
+ restricted class when we actually are loading function arguments,
+ but that is hard to determine. */
+ reload_address_base_reg_class = BASE_REG_CLASS;
+ reload_address_index_reg_class = INDEX_REG_CLASS;
+ if (SMALL_REGISTER_CLASSES)
+ {
+ int regno;
+ HARD_REG_SET base, index;
+ enum reg_class *p;
+
+ COPY_HARD_REG_SET (base, reg_class_contents[BASE_REG_CLASS]);
+ COPY_HARD_REG_SET (index, reg_class_contents[INDEX_REG_CLASS]);
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ {
+ if (FUNCTION_ARG_REGNO_P (regno))
+ {
+ CLEAR_HARD_REG_BIT (base, regno);
+ CLEAR_HARD_REG_BIT (index, regno);
+ }
+ }
+
+ GO_IF_HARD_REG_EQUAL (base, reg_class_contents[BASE_REG_CLASS],
+ baseok);
+ for (p = reg_class_subclasses[BASE_REG_CLASS];
+ *p != LIM_REG_CLASSES;
+ p++)
+ {
+ GO_IF_HARD_REG_EQUAL (base, reg_class_contents[*p], usebase);
+ continue;
+ usebase:
+ reload_address_base_reg_class = *p;
+ break;
+ }
+ baseok:;
+
+ GO_IF_HARD_REG_EQUAL (index, reg_class_contents[INDEX_REG_CLASS],
+ indexok);
+ for (p = reg_class_subclasses[INDEX_REG_CLASS];
+ *p != LIM_REG_CLASSES;
+ p++)
+ {
+ GO_IF_HARD_REG_EQUAL (index, reg_class_contents[*p], useindex);
+ continue;
+ useindex:
+ reload_address_index_reg_class = *p;
+ break;
+ }
+ indexok:;
+ }
}
/* Main entry point for the reload pass.
@@ -453,6 +540,11 @@ reload (first, global, dumpfile)
register rtx insn;
register struct elim_table *ep;
+ /* The two pointers used to track the true location of the memory used
+ for label offsets. */
+ char *real_known_ptr = NULL_PTR;
+ int (*real_at_ptr)[NUM_ELIMINABLE_REGS];
+
int something_changed;
int something_needs_reloads;
int something_needs_elimination;
@@ -497,10 +589,18 @@ reload (first, global, dumpfile)
as homes for pseudo registers.
This is done here rather than (eg) in global_alloc
because this point is reached even if not optimizing. */
-
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
mark_home_live (i);
+ /* A function that receives a nonlocal goto must save all call-saved
+ registers. */
+ if (current_function_has_nonlocal_label)
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (! call_used_regs[i] && ! fixed_regs[i])
+ regs_ever_live[i] = 1;
+ }
+
for (i = 0; i < scratch_list_length; i++)
if (scratch_list[i])
mark_scratch_live (scratch_list[i]);
@@ -531,22 +631,27 @@ reload (first, global, dumpfile)
bzero ((char *) reg_equiv_address, max_regno * sizeof (rtx));
reg_max_ref_width = (int *) alloca (max_regno * sizeof (int));
bzero ((char *) reg_max_ref_width, max_regno * sizeof (int));
- cannot_omit_stores = (char *) alloca (max_regno);
- bzero (cannot_omit_stores, max_regno);
-#ifdef SMALL_REGISTER_CLASSES
- CLEAR_HARD_REG_SET (forbidden_regs);
-#endif
+ if (SMALL_REGISTER_CLASSES)
+ CLEAR_HARD_REG_SET (forbidden_regs);
/* Look for REG_EQUIV notes; record what each pseudo is equivalent to.
Also find all paradoxical subregs and find largest such for each pseudo.
On machines with small register classes, record hard registers that
- are used for user variables. These can never be used for spills. */
+ are used for user variables. These can never be used for spills.
+ Also look for a "constant" NOTE_INSN_SETJMP. This means that all
+ caller-saved registers must be marked live. */
for (insn = first; insn; insn = NEXT_INSN (insn))
{
rtx set = single_set (insn);
+ if (GET_CODE (insn) == NOTE && CONST_CALL_P (insn)
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (! call_used_regs[i])
+ regs_ever_live[i] = 1;
+
if (set != 0 && GET_CODE (SET_DEST (set)) == REG)
{
rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX);
@@ -562,7 +667,14 @@ reload (first, global, dumpfile)
if (i > LAST_VIRTUAL_REGISTER)
{
if (GET_CODE (x) == MEM)
- reg_equiv_memory_loc[i] = x;
+ {
+ /* If the operand is a PLUS, the MEM may be shared,
+ so make sure we have an unshared copy here. */
+ if (GET_CODE (XEXP (x, 0)) == PLUS)
+ x = copy_rtx (x);
+
+ reg_equiv_memory_loc[i] = x;
+ }
else if (CONSTANT_P (x))
{
if (LEGITIMATE_CONSTANT_P (x))
@@ -635,20 +747,24 @@ reload (first, global, dumpfile)
for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
{
num_eliminable += ep->can_eliminate;
- ep->from_rtx = gen_rtx (REG, Pmode, ep->from);
- ep->to_rtx = gen_rtx (REG, Pmode, ep->to);
+ ep->from_rtx = gen_rtx_REG (Pmode, ep->from);
+ ep->to_rtx = gen_rtx_REG (Pmode, ep->to);
}
num_labels = max_label_num () - get_first_label_num ();
/* Allocate the tables used to store offset information at labels. */
- offsets_known_at = (char *) alloca (num_labels);
- offsets_at
+ /* We used to use alloca here, but the size of what it would try to
+ allocate would occasionally cause it to exceed the stack limit and
+ cause a core dump. */
+ real_known_ptr = xmalloc (num_labels);
+ real_at_ptr
= (int (*)[NUM_ELIMINABLE_REGS])
- alloca (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
+ xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
- offsets_known_at -= get_first_label_num ();
- offsets_at -= get_first_label_num ();
+ offsets_known_at = real_known_ptr - get_first_label_num ();
+ offsets_at
+ = (int (*)[NUM_ELIMINABLE_REGS]) (real_at_ptr - get_first_label_num ());
/* Alter each pseudo-reg rtx to contain its hard reg number.
Assign stack slots to the pseudos that lack hard regs or equivalents.
@@ -657,11 +773,6 @@ reload (first, global, dumpfile)
for (i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++)
alter_reg (i, -1);
- /* Round size of stack frame to BIGGEST_ALIGNMENT. This must be done here
- because the stack size may be a part of the offset computation for
- register elimination. */
- assign_stack_local (BLKmode, 0, 0);
-
/* If we have some registers we think can be eliminated, scan all insns to
see if there is an insn that sets one of these registers to something
other than itself plus a constant. If so, the register cannot be
@@ -681,17 +792,21 @@ reload (first, global, dumpfile)
in that case some pseudos might be in the wrong kind of hard reg. */
for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++)
- if (reg_renumber[i] == -1 && reg_n_refs[i] != 0)
+ if (reg_renumber[i] == -1 && REG_N_REFS (i) != 0)
break;
if (i == max_regno && num_eliminable == 0 && ! caller_save_needed)
- return;
+ {
+ free (real_known_ptr);
+ free (real_at_ptr);
+ return;
+ }
#endif
/* Compute the order of preference for hard registers to spill.
Store them by decreasing preference in potential_reload_regs. */
- order_regs_for_reload ();
+ order_regs_for_reload (global);
/* So far, no hard regs have been spilled. */
n_spills = 0;
@@ -705,9 +820,8 @@ reload (first, global, dumpfile)
rtl as a spill register. But on some, we have to. Those will have
taken care to keep the life of hard regs as short as possible. */
-#ifndef SMALL_REGISTER_CLASSES
- COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);
-#endif
+ if (! SMALL_REGISTER_CLASSES)
+ COPY_HARD_REG_SET (forbidden_regs, bad_spill_regs);
/* Spill any hard regs that we know we can't eliminate. */
for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
@@ -770,8 +884,10 @@ reload (first, global, dumpfile)
rtx max_groups_insn[N_REG_CLASSES];
rtx max_nongroups_insn[N_REG_CLASSES];
rtx x;
- int starting_frame_size = get_frame_size ();
+ HOST_WIDE_INT starting_frame_size;
+#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
int previous_frame_pointer_needed = frame_pointer_needed;
+#endif
static char *reg_class_names[] = REG_CLASS_NAMES;
something_changed = 0;
@@ -792,6 +908,14 @@ reload (first, global, dumpfile)
changes from 0 to 1 in this pass. */
new_basic_block_needs = 0;
+ /* Round size of stack frame to BIGGEST_ALIGNMENT. This must be done
+ here because the stack size may be a part of the offset computation
+ for register elimination, and there might have been new stack slots
+ created in the last iteration of this loop. */
+ assign_stack_local (BLKmode, 0, 0);
+
+ starting_frame_size = get_frame_size ();
+
/* Reset all offsets on eliminable registers to their initial values. */
#ifdef ELIMINABLE_REGS
for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
@@ -959,17 +1083,18 @@ reload (first, global, dumpfile)
struct needs op_addr;
struct needs op_addr_reload;
struct needs in_addr[MAX_RECOG_OPERANDS];
+ struct needs in_addr_addr[MAX_RECOG_OPERANDS];
struct needs out_addr[MAX_RECOG_OPERANDS];
+ struct needs out_addr_addr[MAX_RECOG_OPERANDS];
} insn_needs;
/* If needed, eliminate any eliminable registers. */
if (num_eliminable)
did_elimination = eliminate_regs_in_insn (insn, 0);
-#ifdef SMALL_REGISTER_CLASSES
/* Set avoid_return_reg if this is an insn
that might use the value of a function call. */
- if (GET_CODE (insn) == CALL_INSN)
+ if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
{
if (GET_CODE (PATTERN (insn)) == SET)
after_call = SET_DEST (PATTERN (insn));
@@ -979,15 +1104,15 @@ reload (first, global, dumpfile)
else
after_call = 0;
}
- else if (after_call != 0
+ else if (SMALL_REGISTER_CLASSES && after_call != 0
&& !(GET_CODE (PATTERN (insn)) == SET
- && SET_DEST (PATTERN (insn)) == stack_pointer_rtx))
+ && SET_DEST (PATTERN (insn)) == stack_pointer_rtx)
+ && GET_CODE (PATTERN (insn)) != USE)
{
if (reg_referenced_p (after_call, PATTERN (insn)))
avoid_return_reg = after_call;
after_call = 0;
}
-#endif /* SMALL_REGISTER_CLASSES */
/* Analyze the instruction. */
find_reloads (insn, 0, spill_indirect_levels, global,
@@ -1043,7 +1168,6 @@ reload (first, global, dumpfile)
enum reg_class class = reload_reg_class[i];
int size;
enum machine_mode mode;
- int nongroup_need;
struct needs *this_needs;
/* Don't count the dummy reloads, for which one of the
@@ -1066,37 +1190,11 @@ reload (first, global, dumpfile)
new_basic_block_needs = 1;
}
-
mode = reload_inmode[i];
if (GET_MODE_SIZE (reload_outmode[i]) > GET_MODE_SIZE (mode))
mode = reload_outmode[i];
size = CLASS_MAX_NREGS (class, mode);
- /* If this class doesn't want a group, determine if we have
- a nongroup need or a regular need. We have a nongroup
- need if this reload conflicts with a group reload whose
- class intersects with this reload's class. */
-
- nongroup_need = 0;
- if (size == 1)
- for (j = 0; j < n_reloads; j++)
- if ((CLASS_MAX_NREGS (reload_reg_class[j],
- (GET_MODE_SIZE (reload_outmode[j])
- > GET_MODE_SIZE (reload_inmode[j]))
- ? reload_outmode[j]
- : reload_inmode[j])
- > 1)
- && (!reload_optional[j])
- && (reload_in[j] != 0 || reload_out[j] != 0
- || reload_secondary_p[j])
- && reloads_conflict (i, j)
- && reg_classes_intersect_p (class,
- reload_reg_class[j]))
- {
- nongroup_need = 1;
- break;
- }
-
/* Decide which time-of-use to count this reload for. */
switch (reload_when_needed[i])
{
@@ -1118,9 +1216,15 @@ reload (first, global, dumpfile)
case RELOAD_FOR_INPUT_ADDRESS:
this_needs = &insn_needs.in_addr[reload_opnum[i]];
break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ this_needs = &insn_needs.in_addr_addr[reload_opnum[i]];
+ break;
case RELOAD_FOR_OUTPUT_ADDRESS:
this_needs = &insn_needs.out_addr[reload_opnum[i]];
break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ this_needs = &insn_needs.out_addr_addr[reload_opnum[i]];
+ break;
case RELOAD_FOR_OPERAND_ADDRESS:
this_needs = &insn_needs.op_addr;
break;
@@ -1168,10 +1272,10 @@ reload (first, global, dumpfile)
}
else if (size == 1)
{
- this_needs->regs[nongroup_need][(int) class] += 1;
+ this_needs->regs[reload_nongroup[i]][(int) class] += 1;
p = reg_class_superclasses[(int) class];
while (*p != LIM_REG_CLASSES)
- this_needs->regs[nongroup_need][(int) *p++] += 1;
+ this_needs->regs[reload_nongroup[i]][(int) *p++] += 1;
}
else
abort ();
@@ -1193,16 +1297,21 @@ reload (first, global, dumpfile)
k < reload_n_operands; k++)
{
in_max
- = MAX (in_max, insn_needs.in_addr[k].regs[j][i]);
+ = MAX (in_max,
+ (insn_needs.in_addr[k].regs[j][i]
+ + insn_needs.in_addr_addr[k].regs[j][i]));
out_max
= MAX (out_max, insn_needs.out_addr[k].regs[j][i]);
+ out_max
+ = MAX (out_max,
+ insn_needs.out_addr_addr[k].regs[j][i]);
}
/* RELOAD_FOR_INSN reloads conflict with inputs, outputs,
and operand addresses but not things used to reload
them. Similarly, RELOAD_FOR_OPERAND_ADDRESS reloads
don't conflict with things needed to reload inputs or
- outputs. */
+ outputs. */
in_max = MAX (MAX (insn_needs.op_addr.regs[j][i],
insn_needs.op_addr_reload.regs[j][i]),
@@ -1229,8 +1338,12 @@ reload (first, global, dumpfile)
j < reload_n_operands; j++)
{
in_max = MAX (in_max, insn_needs.in_addr[j].groups[i]);
+ in_max = MAX (in_max,
+ insn_needs.in_addr_addr[j].groups[i]);
out_max
= MAX (out_max, insn_needs.out_addr[j].groups[i]);
+ out_max
+ = MAX (out_max, insn_needs.out_addr_addr[j].groups[i]);
}
in_max = MAX (MAX (insn_needs.op_addr.groups[i],
@@ -1270,20 +1383,21 @@ reload (first, global, dumpfile)
if (GET_CODE (insn) == CALL_INSN
&& caller_save_spill_class != NO_REGS)
{
- /* See if this register would conflict with any reload
- that needs a group. */
+ /* See if this register would conflict with any reload that
+ needs a group or any reload that needs a nongroup. */
int nongroup_need = 0;
int *caller_save_needs;
for (j = 0; j < n_reloads; j++)
- if ((CLASS_MAX_NREGS (reload_reg_class[j],
- (GET_MODE_SIZE (reload_outmode[j])
- > GET_MODE_SIZE (reload_inmode[j]))
- ? reload_outmode[j]
- : reload_inmode[j])
- > 1)
- && reg_classes_intersect_p (caller_save_spill_class,
- reload_reg_class[j]))
+ if (reg_classes_intersect_p (caller_save_spill_class,
+ reload_reg_class[j])
+ && ((CLASS_MAX_NREGS
+ (reload_reg_class[j],
+ (GET_MODE_SIZE (reload_outmode[j])
+ > GET_MODE_SIZE (reload_inmode[j]))
+ ? reload_outmode[j] : reload_inmode[j])
+ > 1)
+ || reload_nongroup[j]))
{
nongroup_need = 1;
break;
@@ -1318,16 +1432,15 @@ reload (first, global, dumpfile)
}
}
-#ifdef SMALL_REGISTER_CLASSES
/* If this insn stores the value of a function call,
and that value is in a register that has been spilled,
and if the insn needs a reload in a class
that might use that register as the reload register,
- then add add an extra need in that class.
+ then add an extra need in that class.
This makes sure we have a register available that does
not overlap the return value. */
- if (avoid_return_reg)
+ if (SMALL_REGISTER_CLASSES && avoid_return_reg)
{
int regno = REGNO (avoid_return_reg);
int nregs
@@ -1360,7 +1473,7 @@ reload (first, global, dumpfile)
}
/* Now count extra regs if there might be a conflict with
- the return value register. */
+ the return value register. */
for (r = regno; r < regno + nregs; r++)
if (spill_reg_order[r] >= 0)
@@ -1387,7 +1500,6 @@ reload (first, global, dumpfile)
}
}
}
-#endif /* SMALL_REGISTER_CLASSES */
/* For each class, collect maximum need of any insn. */
@@ -1442,19 +1554,26 @@ reload (first, global, dumpfile)
/* If we have caller-saves, set up the save areas and see if caller-save
will need a spill register. */
- if (caller_save_needed
- && ! setup_save_areas (&something_changed)
- && caller_save_spill_class == NO_REGS)
+ if (caller_save_needed)
{
- /* The class we will need depends on whether the machine
- supports the sum of two registers for an address; see
- find_address_reloads for details. */
-
- caller_save_spill_class
- = double_reg_address_ok ? INDEX_REG_CLASS : BASE_REG_CLASS;
- caller_save_group_size
- = CLASS_MAX_NREGS (caller_save_spill_class, Pmode);
- something_changed = 1;
+ /* Set the offsets for setup_save_areas. */
+ for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS];
+ ep++)
+ ep->previous_offset = ep->max_offset;
+
+ if ( ! setup_save_areas (&something_changed)
+ && caller_save_spill_class == NO_REGS)
+ {
+ /* The class we will need depends on whether the machine
+ supports the sum of two registers for an address; see
+ find_address_reloads for details. */
+
+ caller_save_spill_class
+ = double_reg_address_ok ? INDEX_REG_CLASS : BASE_REG_CLASS;
+ caller_save_group_size
+ = CLASS_MAX_NREGS (caller_save_spill_class, Pmode);
+ something_changed = 1;
+ }
}
/* See if anything that happened changes which eliminations are valid.
@@ -1676,9 +1795,8 @@ reload (first, global, dumpfile)
}
}
/* We can't complete a group, so start one. */
-#ifdef SMALL_REGISTER_CLASSES
/* Look for a pair neither of which is explicitly used. */
- if (i == FIRST_PSEUDO_REGISTER)
+ if (SMALL_REGISTER_CLASSES && i == FIRST_PSEUDO_REGISTER)
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
int k;
@@ -1701,7 +1819,6 @@ reload (first, global, dumpfile)
&& ! regs_explicitly_used[j + 1])
break;
}
-#endif
/* Now try any group at all
whose registers are not in bad_spill_regs. */
if (i == FIRST_PSEUDO_REGISTER)
@@ -1808,10 +1925,6 @@ reload (first, global, dumpfile)
while (max_needs[class] > 0 || max_nongroups[class] > 0)
{
-#ifdef SMALL_REGISTER_CLASSES
- /* This should be right for all machines, but only the 386
- is known to need it, so this conditional plays safe.
- ??? For 2.5, try making this unconditional. */
/* If we spilled enough regs, but they weren't counted
against the non-group need, see if we can count them now.
If so, we can avoid some actual spilling. */
@@ -1835,7 +1948,6 @@ reload (first, global, dumpfile)
}
if (max_needs[class] <= 0 && max_nongroups[class] <= 0)
break;
-#endif
/* Consider the potential reload regs that aren't
yet in use as reload regs, in order of preference.
@@ -1945,9 +2057,8 @@ reload (first, global, dumpfile)
if (! frame_pointer_needed)
for (i = 0; i < n_basic_blocks; i++)
- basic_block_live_at_start[i][HARD_FRAME_POINTER_REGNUM / REGSET_ELT_BITS]
- &= ~ ((REGSET_ELT_TYPE) 1 << (HARD_FRAME_POINTER_REGNUM
- % REGSET_ELT_BITS));
+ CLEAR_REGNO_REG_SET (basic_block_live_at_start[i],
+ HARD_FRAME_POINTER_REGNUM);
/* Come here (with failure set nonzero) if we can't get enough spill regs
and we decide not to abort about it. */
@@ -1969,13 +2080,20 @@ reload (first, global, dumpfile)
{
rtx addr = 0;
int in_struct = 0;
- if (reg_equiv_mem[i])
+ int is_readonly = 0;
+
+ if (reg_equiv_memory_loc[i])
{
- addr = XEXP (reg_equiv_mem[i], 0);
- in_struct = MEM_IN_STRUCT_P (reg_equiv_mem[i]);
+ in_struct = MEM_IN_STRUCT_P (reg_equiv_memory_loc[i]);
+ is_readonly = RTX_UNCHANGING_P (reg_equiv_memory_loc[i]);
}
+
+ if (reg_equiv_mem[i])
+ addr = XEXP (reg_equiv_mem[i], 0);
+
if (reg_equiv_address[i])
addr = reg_equiv_address[i];
+
if (addr)
{
if (reg_renumber[i] < 0)
@@ -1983,7 +2101,11 @@ reload (first, global, dumpfile)
rtx reg = regno_reg_rtx[i];
XEXP (reg, 0) = addr;
REG_USERVAR_P (reg) = 0;
+ RTX_UNCHANGING_P (reg) = is_readonly;
MEM_IN_STRUCT_P (reg) = in_struct;
+ /* We have no alias information about this newly created
+ MEM. */
+ MEM_ALIAS_SET (reg) = 0;
PUT_CODE (reg, MEM);
}
else if (reg_equiv_mem[i])
@@ -1991,16 +2113,28 @@ reload (first, global, dumpfile)
}
}
-#ifdef PRESERVE_DEATH_INFO_REGNO_P
- /* Make a pass over all the insns and remove death notes for things that
- are no longer registers or no longer die in the insn (e.g., an input
- and output pseudo being tied). */
+ /* Make a pass over all the insns and delete all USEs which we inserted
+ only to tag a REG_EQUAL note on them; if PRESERVE_DEATH_INFO_REGNO_P
+ is defined, also remove death notes for things that are no longer
+ registers or no longer die in the insn (e.g., an input and output
+ pseudo being tied). */
for (insn = first; insn; insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
{
+#ifdef PRESERVE_DEATH_INFO_REGNO_P
rtx note, next;
+#endif
+ if (GET_CODE (PATTERN (insn)) == USE
+ && find_reg_note (insn, REG_EQUAL, NULL_RTX))
+ {
+ PUT_CODE (insn, NOTE);
+ NOTE_SOURCE_FILE (insn) = 0;
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ continue;
+ }
+#ifdef PRESERVE_DEATH_INFO_REGNO_P
for (note = REG_NOTES (insn); note; note = next)
{
next = XEXP (note, 1);
@@ -2009,13 +2143,32 @@ reload (first, global, dumpfile)
|| reg_set_p (XEXP (note, 0), PATTERN (insn))))
remove_note (insn, note);
}
- }
#endif
+ }
+
+ /* If we are doing stack checking, give a warning if this function's
+ frame size is larger than we expect. */
+ if (flag_stack_check && ! STACK_CHECK_BUILTIN)
+ {
+ HOST_WIDE_INT size = get_frame_size () + STACK_CHECK_FIXED_FRAME_SIZE;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (regs_ever_live[i] && ! fixed_regs[i] && call_used_regs[i])
+ size += UNITS_PER_WORD;
+ if (size > STACK_CHECK_MAX_FRAME_SIZE)
+ warning ("frame size too large for reliable stack checking");
+ }
+
/* Indicate that we no longer have known memory locations or constants. */
reg_equiv_constant = 0;
reg_equiv_memory_loc = 0;
+ if (real_known_ptr)
+ free (real_known_ptr);
+ if (real_at_ptr)
+ free (real_at_ptr);
+
if (scratch_list)
free (scratch_list);
scratch_list = 0;
@@ -2023,6 +2176,10 @@ reload (first, global, dumpfile)
free (scratch_block);
scratch_block = 0;
+ CLEAR_HARD_REG_SET (used_spill_regs);
+ for (i = 0; i < n_spills; i++)
+ SET_HARD_REG_BIT (used_spill_regs, spill_regs[i]);
+
return failure;
}
@@ -2219,9 +2376,12 @@ new_spill_reg (i, class, max_needs, max_nongroups, global, dumpfile)
abort (); /* Caller failed to find any register. */
if (fixed_regs[regno] || TEST_HARD_REG_BIT (forbidden_regs, regno))
- fatal ("fixed or forbidden register was spilled.\n\
+ {
+ static char *reg_class_names[] = REG_CLASS_NAMES;
+ fatal ("fixed or forbidden register %d (%s) was spilled for class %s.\n\
This may be due to a compiler bug or to impossible asm\n\
-statements or clauses.");
+statements or clauses.", regno, reg_names[regno], reg_class_names[class]);
+ }
/* Make reg REGNO an additional reload reg. */
@@ -2289,7 +2449,8 @@ delete_dead_insn (insn)
if (prev && GET_CODE (PATTERN (prev)) == SET
&& (prev_dest = SET_DEST (PATTERN (prev)), GET_CODE (prev_dest) == REG)
&& reg_mentioned_p (prev_dest, PATTERN (insn))
- && find_regno_note (insn, REG_DEAD, REGNO (prev_dest)))
+ && find_regno_note (insn, REG_DEAD, REGNO (prev_dest))
+ && ! side_effects_p (SET_SRC (PATTERN (prev))))
delete_dead_insn (prev);
PUT_CODE (insn, NOTE);
@@ -2329,7 +2490,7 @@ alter_reg (i, from_reg)
allocate a stack slot for it. */
if (reg_renumber[i] < 0
- && reg_n_refs[i] > 0
+ && REG_N_REFS (i) > 0
&& reg_equiv_constant[i] == 0
&& reg_equiv_memory_loc[i] == 0)
{
@@ -2349,7 +2510,8 @@ alter_reg (i, from_reg)
if (from_reg == -1)
{
/* No known place to spill from => no slot to reuse. */
- x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size, -1);
+ x = assign_stack_local (GET_MODE (regno_reg_rtx[i]), total_size,
+ inherent_size == total_size ? 0 : -1);
if (BYTES_BIG_ENDIAN)
/* Cancel the big-endian correction done in assign_stack_local.
Get the address of the beginning of the slot.
@@ -2381,7 +2543,8 @@ alter_reg (i, from_reg)
total_size = spill_stack_slot_width[from_reg];
}
/* Make a slot with that size. */
- x = assign_stack_local (mode, total_size, -1);
+ x = assign_stack_local (mode, total_size,
+ inherent_size == total_size ? 0 : -1);
stack_slot = x;
if (BYTES_BIG_ENDIAN)
{
@@ -2391,9 +2554,9 @@ alter_reg (i, from_reg)
below. */
adjust = GET_MODE_SIZE (mode) - total_size;
if (adjust)
- stack_slot = gen_rtx (MEM, mode_for_size (total_size
- * BITS_PER_UNIT,
- MODE_INT, 1),
+ stack_slot = gen_rtx_MEM (mode_for_size (total_size
+ * BITS_PER_UNIT,
+ MODE_INT, 1),
plus_constant (XEXP (x, 0), adjust));
}
spill_stack_slot[from_reg] = stack_slot;
@@ -2409,9 +2572,16 @@ alter_reg (i, from_reg)
wrong mode, make a new stack slot. */
if (adjust != 0 || GET_MODE (x) != GET_MODE (regno_reg_rtx[i]))
{
- x = gen_rtx (MEM, GET_MODE (regno_reg_rtx[i]),
+ x = gen_rtx_MEM (GET_MODE (regno_reg_rtx[i]),
plus_constant (XEXP (x, 0), adjust));
- RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
+
+ /* If this was shared among registers, must ensure we never
+ set it readonly since that can cause scheduling
+ problems. Note we would only have in this adjustment
+ case in any event, since the code above doesn't set it. */
+
+ if (from_reg == -1)
+ RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (regno_reg_rtx[i]);
}
/* Save the stack slot for later. */
@@ -2478,7 +2648,7 @@ set_label_offsets (x, insn, initial_p)
x = XEXP (x, 0);
- /* ... fall through ... */
+ /* ... fall through ... */
case CODE_LABEL:
/* If we know nothing about this label, set the desired offsets. Note
@@ -2533,7 +2703,7 @@ set_label_offsets (x, insn, initial_p)
case JUMP_INSN:
set_label_offsets (PATTERN (insn), insn, initial_p);
- /* ... fall through ... */
+ /* ... fall through ... */
case INSN:
case CALL_INSN:
@@ -2547,7 +2717,7 @@ set_label_offsets (x, insn, initial_p)
case ADDR_VEC:
case ADDR_DIFF_VEC:
/* Each of the labels in the address vector must be at their initial
- offsets. We want the first first for ADDR_VEC and the second
+ offsets. We want the first field for ADDR_VEC and the second
field for ADDR_DIFF_VEC. */
for (i = 0; i < XVECLEN (x, code == ADDR_DIFF_VEC); i++)
@@ -2594,6 +2764,9 @@ set_label_offsets (x, insn, initial_p)
else if (GET_CODE (tem) != PC && GET_CODE (tem) != RETURN)
break;
return;
+
+ default:
+ break;
}
/* If we reach here, all eliminations must be at their initial
@@ -2601,6 +2774,10 @@ set_label_offsets (x, insn, initial_p)
for (p = reg_eliminate; p < &reg_eliminate[NUM_ELIMINABLE_REGS]; p++)
if (p->offset != p->initial_offset)
p->can_eliminate = 0;
+ break;
+
+ default:
+ break;
}
}
@@ -2621,7 +2798,7 @@ static struct rtvec_def *old_asm_operands_vec, *new_asm_operands_vec;
If INSN is an insn, it is the insn containing X. If we replace a REG
in a SET_DEST with an equivalent MEM and INSN is non-zero, write a
CLOBBER of the pseudo after INSN so find_equiv_regs will know that
- that the REG is being modified.
+ the REG is being modified.
Alternatively, INSN may be a note (an EXPR_LIST or INSN_LIST).
That's used when we eliminate in expressions stored in notes.
@@ -2666,6 +2843,15 @@ eliminate_regs (x, mem_mode, insn)
case RETURN:
return x;
+ case ADDRESSOF:
+ /* This is only for the benefit of the debugging backends, which call
+ eliminate_regs on DECL_RTL; any ADDRESSOFs in the actual insns are
+ removed after CSE. */
+ new = eliminate_regs (XEXP (x, 0), 0, insn);
+ if (GET_CODE (new) == MEM)
+ return XEXP (new, 0);
+ return x;
+
case REG:
regno = REGNO (x);
@@ -2697,11 +2883,13 @@ eliminate_regs (x, mem_mode, insn)
elimination) and ignore the fact that this is actually a
reference to the pseudo. Ensure we make a copy of the
address in case it is shared. */
- new = eliminate_regs (reg_equiv_memory_loc[regno],
- mem_mode, insn);
+ new = eliminate_regs (reg_equiv_memory_loc[regno], mem_mode, insn);
if (new != reg_equiv_memory_loc[regno])
{
- cannot_omit_stores[regno] = 1;
+ if (insn != 0 && GET_CODE (insn) != EXPR_LIST
+ && GET_CODE (insn) != INSN_LIST)
+ REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode, x), insn))
+ = gen_rtx_EXPR_LIST (REG_EQUAL, new, NULL_RTX);
return copy_rtx (new);
}
}
@@ -2736,9 +2924,9 @@ eliminate_regs (x, mem_mode, insn)
&& INTVAL (XEXP (x, 1)) == - ep->previous_offset)
return ep->to_rtx;
else
- return gen_rtx (PLUS, Pmode, ep->to_rtx,
- plus_constant (XEXP (x, 1),
- ep->previous_offset));
+ return gen_rtx_PLUS (Pmode, ep->to_rtx,
+ plus_constant (XEXP (x, 1),
+ ep->previous_offset));
}
/* If the register is not eliminable, we are done since the other
@@ -2787,7 +2975,7 @@ eliminate_regs (x, mem_mode, insn)
turn a PLUS into something else. We might try to do so here
for an addition of 0 if we aren't optimizing. */
if (! mem_mode && GET_CODE (new) != PLUS)
- return gen_rtx (PLUS, GET_MODE (x), new, const0_rtx);
+ return gen_rtx_PLUS (GET_MODE (x), new, const0_rtx);
else
return new;
}
@@ -2814,11 +3002,11 @@ eliminate_regs (x, mem_mode, insn)
ep->ref_outside_mem = 1;
return
- plus_constant (gen_rtx (MULT, Pmode, ep->to_rtx, XEXP (x, 1)),
+ plus_constant (gen_rtx_MULT (Pmode, ep->to_rtx, XEXP (x, 1)),
ep->previous_offset * INTVAL (XEXP (x, 1)));
}
- /* ... fall through ... */
+ /* ... fall through ... */
case CALL:
case COMPARE:
@@ -2837,7 +3025,7 @@ eliminate_regs (x, mem_mode, insn)
= XEXP (x, 1) ? eliminate_regs (XEXP (x, 1), mem_mode, insn) : 0;
if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))
- return gen_rtx (code, GET_MODE (x), new0, new1);
+ return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1);
}
return x;
@@ -2847,10 +3035,10 @@ eliminate_regs (x, mem_mode, insn)
{
new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
if (new != XEXP (x, 0))
- x = gen_rtx (EXPR_LIST, REG_NOTE_KIND (x), new, XEXP (x, 1));
+ x = gen_rtx_EXPR_LIST (REG_NOTE_KIND (x), new, XEXP (x, 1));
}
- /* ... fall through ... */
+ /* ... fall through ... */
case INSN_LIST:
/* Now do eliminations in the rest of the chain. If this was
@@ -2860,7 +3048,7 @@ eliminate_regs (x, mem_mode, insn)
{
new = eliminate_regs (XEXP (x, 1), mem_mode, insn);
if (new != XEXP (x, 1))
- return gen_rtx (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new);
+ return gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new);
}
return x;
@@ -2885,7 +3073,6 @@ eliminate_regs (x, mem_mode, insn)
}
/* Fall through to generic unary operation case. */
- case USE:
case STRICT_LOW_PART:
case NEG: case NOT:
case SIGN_EXTEND: case ZERO_EXTEND:
@@ -2897,7 +3084,7 @@ eliminate_regs (x, mem_mode, insn)
case FFS:
new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
if (new != XEXP (x, 0))
- return gen_rtx (code, GET_MODE (x), new);
+ return gen_rtx_fmt_e (code, GET_MODE (x), new);
return x;
case SUBREG:
@@ -2921,16 +3108,17 @@ eliminate_regs (x, mem_mode, insn)
new = SUBREG_REG (x);
else
{
- /* Otherwise, ensure NEW isn't shared in case we have to reload
- it. */
- new = copy_rtx (new);
-
/* In this case, we must show that the pseudo is used in this
insn so that delete_output_reload will do the right thing. */
if (insn != 0 && GET_CODE (insn) != EXPR_LIST
&& GET_CODE (insn) != INSN_LIST)
- emit_insn_before (gen_rtx (USE, VOIDmode, SUBREG_REG (x)),
- insn);
+ REG_NOTES (emit_insn_before (gen_rtx_USE (VOIDmode,
+ SUBREG_REG (x)),
+ insn))
+ = gen_rtx_EXPR_LIST (REG_EQUAL, new, NULL_RTX);
+
+ /* Ensure NEW isn't shared in case we have to reload it. */
+ new = copy_rtx (new);
}
}
else
@@ -2938,22 +3126,23 @@ eliminate_regs (x, mem_mode, insn)
if (new != XEXP (x, 0))
{
+ int x_size = GET_MODE_SIZE (GET_MODE (x));
+ int new_size = GET_MODE_SIZE (GET_MODE (new));
+
if (GET_CODE (new) == MEM
- && (GET_MODE_SIZE (GET_MODE (x))
- <= GET_MODE_SIZE (GET_MODE (new)))
-#ifdef LOAD_EXTEND_OP
- /* On these machines we will be reloading what is
- inside the SUBREG if it originally was a pseudo and
- the inner and outer modes are both a word or
- smaller. So leave the SUBREG then. */
- && ! (GET_CODE (SUBREG_REG (x)) == REG
- && GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
- && GET_MODE_SIZE (GET_MODE (new)) <= UNITS_PER_WORD
- && (GET_MODE_SIZE (GET_MODE (x))
- > GET_MODE_SIZE (GET_MODE (new)))
- && INTEGRAL_MODE_P (GET_MODE (new))
- && LOAD_EXTEND_OP (GET_MODE (new)) != NIL)
+ && ((x_size < new_size
+#ifdef WORD_REGISTER_OPERATIONS
+ /* On these machines, combine can create rtl of the form
+ (set (subreg:m1 (reg:m2 R) 0) ...)
+ where m1 < m2, and expects something interesting to
+ happen to the entire word. Moreover, it will use the
+ (reg:m2 R) later, expecting all bits to be preserved.
+ So if the number of words is the same, preserve the
+ subreg so that push_reloads can see it. */
+ && ! ((x_size-1)/UNITS_PER_WORD == (new_size-1)/UNITS_PER_WORD)
#endif
+ )
+ || (x_size == new_size))
)
{
int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
@@ -2969,11 +3158,24 @@ eliminate_regs (x, mem_mode, insn)
return new;
}
else
- return gen_rtx (SUBREG, GET_MODE (x), new, SUBREG_WORD (x));
+ return gen_rtx_SUBREG (GET_MODE (x), new, SUBREG_WORD (x));
}
return x;
+ case USE:
+ /* If using a register that is the source of an eliminate we still
+ think can be performed, note it cannot be performed since we don't
+ know how this register is used. */
+ for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
+ if (ep->from_rtx == XEXP (x, 0))
+ ep->can_eliminate = 0;
+
+ new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
+ if (new != XEXP (x, 0))
+ return gen_rtx_fmt_e (code, GET_MODE (x), new);
+ return x;
+
case CLOBBER:
/* If clobbering a register that is the replacement register for an
elimination we still think can be performed, note that it cannot
@@ -2984,7 +3186,7 @@ eliminate_regs (x, mem_mode, insn)
new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
if (new != XEXP (x, 0))
- return gen_rtx (code, GET_MODE (x), new);
+ return gen_rtx_fmt_e (code, GET_MODE (x), new);
return x;
case ASM_OPERANDS:
@@ -3017,12 +3219,13 @@ eliminate_regs (x, mem_mode, insn)
if (new_asm_operands_vec == old_asm_operands_vec)
return x;
- new = gen_rtx (ASM_OPERANDS, VOIDmode, ASM_OPERANDS_TEMPLATE (x),
- ASM_OPERANDS_OUTPUT_CONSTRAINT (x),
- ASM_OPERANDS_OUTPUT_IDX (x), new_asm_operands_vec,
- ASM_OPERANDS_INPUT_CONSTRAINT_VEC (x),
- ASM_OPERANDS_SOURCE_FILE (x),
- ASM_OPERANDS_SOURCE_LINE (x));
+ new = gen_rtx_ASM_OPERANDS (VOIDmode, ASM_OPERANDS_TEMPLATE (x),
+ ASM_OPERANDS_OUTPUT_CONSTRAINT (x),
+ ASM_OPERANDS_OUTPUT_IDX (x),
+ new_asm_operands_vec,
+ ASM_OPERANDS_INPUT_CONSTRAINT_VEC (x),
+ ASM_OPERANDS_SOURCE_FILE (x),
+ ASM_OPERANDS_SOURCE_LINE (x));
new->volatil = x->volatil;
return new;
}
@@ -3079,22 +3282,28 @@ eliminate_regs (x, mem_mode, insn)
if (GET_CODE (SET_DEST (x)) == REG && GET_CODE (new0) == MEM
&& insn != 0 && GET_CODE (insn) != EXPR_LIST
&& GET_CODE (insn) != INSN_LIST)
- emit_insn_after (gen_rtx (CLOBBER, VOIDmode, SET_DEST (x)), insn);
+ emit_insn_after (gen_rtx_CLOBBER (VOIDmode, SET_DEST (x)), insn);
if (new0 != SET_DEST (x) || new1 != SET_SRC (x))
- return gen_rtx (SET, VOIDmode, new0, new1);
+ return gen_rtx_SET (VOIDmode, new0, new1);
}
return x;
case MEM:
+ /* This is only for the benefit of the debugging backends, which call
+ eliminate_regs on DECL_RTL; any ADDRESSOFs in the actual insns are
+ removed after CSE. */
+ if (GET_CODE (XEXP (x, 0)) == ADDRESSOF)
+ return eliminate_regs (XEXP (XEXP (x, 0), 0), 0, insn);
+
/* Our only special processing is to pass the mode of the MEM to our
recursive call and copy the flags. While we are here, handle this
case more efficiently. */
new = eliminate_regs (XEXP (x, 0), GET_MODE (x), insn);
if (new != XEXP (x, 0))
{
- new = gen_rtx (MEM, GET_MODE (x), new);
+ new = gen_rtx_MEM (GET_MODE (x), new);
new->volatil = x->volatil;
new->unchanging = x->unchanging;
new->in_struct = x->in_struct;
@@ -3102,6 +3311,9 @@ eliminate_regs (x, mem_mode, insn)
}
else
return x;
+
+ default:
+ break;
}
/* Process each of our operands recursively. If any have changed, make a
@@ -3131,8 +3343,8 @@ eliminate_regs (x, mem_mode, insn)
new = eliminate_regs (XVECEXP (x, i, j), mem_mode, insn);
if (new != XVECEXP (x, i, j) && ! copied_vec)
{
- rtvec new_v = gen_rtvec_v (XVECLEN (x, i),
- &XVECEXP (x, i, 0));
+ rtvec new_v = gen_rtvec_vv (XVECLEN (x, i),
+ XVEC (x, i)->elem);
if (! copied)
{
rtx new_x = rtx_alloc (code);
@@ -3199,12 +3411,34 @@ eliminate_regs_in_insn (insn, replace)
{
rtx src = SET_SRC (old_set);
int offset, ok = 0;
+ rtx prev_insn, prev_set;
if (src == ep->to_rtx)
offset = 0, ok = 1;
else if (GET_CODE (src) == PLUS
- && GET_CODE (XEXP (src, 0)) == CONST_INT)
+ && GET_CODE (XEXP (src, 0)) == CONST_INT
+ && XEXP (src, 1) == ep->to_rtx)
offset = INTVAL (XEXP (src, 0)), ok = 1;
+ else if (GET_CODE (src) == PLUS
+ && GET_CODE (XEXP (src, 1)) == CONST_INT
+ && XEXP (src, 0) == ep->to_rtx)
+ offset = INTVAL (XEXP (src, 1)), ok = 1;
+ else if ((prev_insn = prev_nonnote_insn (insn)) != 0
+ && (prev_set = single_set (prev_insn)) != 0
+ && rtx_equal_p (SET_DEST (prev_set), src))
+ {
+ src = SET_SRC (prev_set);
+ if (src == ep->to_rtx)
+ offset = 0, ok = 1;
+ else if (GET_CODE (src) == PLUS
+ && GET_CODE (XEXP (src, 0)) == CONST_INT
+ && XEXP (src, 1) == ep->to_rtx)
+ offset = INTVAL (XEXP (src, 0)), ok = 1;
+ else if (GET_CODE (src) == PLUS
+ && GET_CODE (XEXP (src, 1)) == CONST_INT
+ && XEXP (src, 0) == ep->to_rtx)
+ offset = INTVAL (XEXP (src, 1)), ok = 1;
+ }
if (ok)
{
@@ -3268,8 +3502,9 @@ eliminate_regs_in_insn (insn, replace)
/* We assume here that we don't need a PARALLEL of
any CLOBBERs for this assignment. There's not
much we can do if we do need it. */
- PATTERN (insn) = gen_rtx (SET, VOIDmode,
- SET_DEST (old_set), ep->to_rtx);
+ PATTERN (insn) = gen_rtx_SET (VOIDmode,
+ SET_DEST (old_set),
+ ep->to_rtx);
INSN_CODE (insn) = -1;
val = 1;
goto done;
@@ -3287,7 +3522,7 @@ eliminate_regs_in_insn (insn, replace)
If we are replacing a body that was a (set X (plus Y Z)), try to
re-recognize the insn. We do this in case we had a simple addition
but now can do this as a load-address. This saves an insn in this
- common case. */
+ common case. */
new_body = eliminate_regs (old_body, 0, replace ? insn : NULL_RTX);
if (new_body != old_body)
@@ -3295,7 +3530,7 @@ eliminate_regs_in_insn (insn, replace)
/* If we aren't replacing things permanently and we changed something,
make another copy to ensure that all the RTL is new. Otherwise
things can go wrong if find_reload swaps commutative operands
- and one is inside RTL that has been copied while the other is not. */
+ and one is inside RTL that has been copied while the other is not. */
/* Don't copy an asm_operands because (1) there's no need and (2)
copy_rtx can't do it properly when there are multiple outputs. */
@@ -3475,14 +3710,14 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
if (! cant_eliminate
&& basic_block_needs[0]
- && reg_basic_block[i] >= 0
- && basic_block_needs[(int) class][reg_basic_block[i]] == 0)
+ && REG_BASIC_BLOCK (i) >= 0
+ && basic_block_needs[(int) class][REG_BASIC_BLOCK (i)] == 0)
{
enum reg_class *p;
for (p = reg_class_superclasses[(int) class];
*p != LIM_REG_CLASSES; p++)
- if (basic_block_needs[(int) *p][reg_basic_block[i]] > 0)
+ if (basic_block_needs[(int) *p][REG_BASIC_BLOCK (i)] > 0)
break;
if (*p == LIM_REG_CLASSES)
@@ -3494,7 +3729,7 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
/* We will need to scan everything again. */
something_changed = 1;
if (global)
- retry_global_alloc (i, forbidden_regs);
+ retry_global_alloc (i, forbidden_regs);
alter_reg (i, regno);
if (dumpfile)
@@ -3508,7 +3743,11 @@ spill_hard_reg (regno, global, dumpfile, cant_eliminate)
}
for (i = 0; i < scratch_list_length; i++)
{
- if (scratch_list[i] && REGNO (scratch_list[i]) == regno)
+ if (scratch_list[i]
+ && regno >= REGNO (scratch_list[i])
+ && regno < REGNO (scratch_list[i])
+ + HARD_REGNO_NREGS (REGNO (scratch_list[i]),
+ GET_MODE (scratch_list[i])))
{
if (! cant_eliminate && basic_block_needs[0]
&& ! basic_block_needs[(int) class][scratch_block[i]])
@@ -3548,10 +3787,9 @@ scan_paradoxical_subregs (x)
switch (code)
{
case REG:
-#ifdef SMALL_REGISTER_CLASSES
- if (REGNO (x) < FIRST_PSEUDO_REGISTER && REG_USERVAR_P (x))
+ if (SMALL_REGISTER_CLASSES && REGNO (x) < FIRST_PSEUDO_REGISTER
+ && REG_USERVAR_P (x))
SET_HARD_REG_BIT (forbidden_regs, REGNO (x));
-#endif
return;
case CONST_INT:
@@ -3571,6 +3809,9 @@ scan_paradoxical_subregs (x)
reg_max_ref_width[REGNO (SUBREG_REG (x))]
= GET_MODE_SIZE (GET_MODE (x));
return;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -3588,9 +3829,12 @@ scan_paradoxical_subregs (x)
}
static int
-hard_reg_use_compare (p1, p2)
- struct hard_reg_n_uses *p1, *p2;
+hard_reg_use_compare (p1p, p2p)
+ const GENERIC_PTR p1p;
+ const GENERIC_PTR p2p;
{
+ struct hard_reg_n_uses *p1 = (struct hard_reg_n_uses *)p1p,
+ *p2 = (struct hard_reg_n_uses *)p2p;
int tem = p1->uses - p2->uses;
if (tem != 0) return tem;
/* If regs are equally good, sort by regno,
@@ -3603,7 +3847,8 @@ hard_reg_use_compare (p1, p2)
Store them in order of decreasing preference in potential_reload_regs. */
static void
-order_regs_for_reload ()
+order_regs_for_reload (global)
+ int global;
{
register int i;
register int o = 0;
@@ -3632,9 +3877,17 @@ order_regs_for_reload ()
{
int lim = regno + HARD_REGNO_NREGS (regno, PSEUDO_REGNO_MODE (i));
while (regno < lim)
- hard_reg_n_uses[regno++].uses += reg_n_refs[i];
+ {
+ /* If allocated by local-alloc, show more uses since
+ we're not going to be able to reallocate it, but
+ we might if allocated by global alloc. */
+ if (global && reg_allocno[i] < 0)
+ hard_reg_n_uses[regno].uses += (REG_N_REFS (i) + 1) / 2;
+
+ hard_reg_n_uses[regno++].uses += REG_N_REFS (i);
+ }
}
- large += reg_n_refs[i];
+ large += REG_N_REFS (i);
}
/* Now fixed registers (which cannot safely be used for reloading)
@@ -3651,14 +3904,13 @@ order_regs_for_reload ()
else if (regs_explicitly_used[i])
{
hard_reg_n_uses[i].uses += large + 1;
-#ifndef SMALL_REGISTER_CLASSES
- /* ??? We are doing this here because of the potential that
- bad code may be generated if a register explicitly used in
- an insn was used as a spill register for that insn. But
- not using these are spill registers may lose on some machine.
- We'll have to see how this works out. */
- SET_HARD_REG_BIT (bad_spill_regs, i);
-#endif
+ if (! SMALL_REGISTER_CLASSES)
+ /* ??? We are doing this here because of the potential
+ that bad code may be generated if a register explicitly
+ used in an insn was used as a spill register for that
+ insn. But not using these are spill registers may lose
+ on some machine. We'll have to see how this works out. */
+ SET_HARD_REG_BIT (bad_spill_regs, i);
}
}
hard_reg_n_uses[HARD_FRAME_POINTER_REGNUM].uses += 2 * large + 2;
@@ -3714,10 +3966,12 @@ order_regs_for_reload ()
/* Used in reload_as_needed to sort the spilled regs. */
static int
-compare_spill_regs (r1, r2)
- short *r1, *r2;
+compare_spill_regs (r1p, r2p)
+ const GENERIC_PTR r1p;
+ const GENERIC_PTR r2p;
{
- return *r1 - *r2;
+ short r1 = *(short *)r1p, r2 = *(short *)r2p;
+ return r1 - r2;
}
/* Reload pseudo-registers into hard regs around each insn as needed.
@@ -3745,11 +3999,7 @@ reload_as_needed (first, live_known)
reg_last_reload_reg = (rtx *) alloca (max_regno * sizeof (rtx));
bzero ((char *) reg_last_reload_reg, max_regno * sizeof (rtx));
reg_has_output_reload = (char *) alloca (max_regno);
- for (i = 0; i < n_spills; i++)
- {
- reg_reloaded_contents[i] = -1;
- reg_reloaded_insn[i] = 0;
- }
+ CLEAR_HARD_REG_SET (reg_reloaded_valid);
/* Reset all offsets on eliminable registers to their initial values. */
#ifdef ELIMINABLE_REGS
@@ -3807,10 +4057,9 @@ reload_as_needed (first, live_known)
rtx avoid_return_reg = 0;
rtx oldpat = PATTERN (insn);
-#ifdef SMALL_REGISTER_CLASSES
/* Set avoid_return_reg if this is an insn
that might use the value of a function call. */
- if (GET_CODE (insn) == CALL_INSN)
+ if (SMALL_REGISTER_CLASSES && GET_CODE (insn) == CALL_INSN)
{
if (GET_CODE (PATTERN (insn)) == SET)
after_call = SET_DEST (PATTERN (insn));
@@ -3820,15 +4069,15 @@ reload_as_needed (first, live_known)
else
after_call = 0;
}
- else if (after_call != 0
+ else if (SMALL_REGISTER_CLASSES && after_call != 0
&& !(GET_CODE (PATTERN (insn)) == SET
- && SET_DEST (PATTERN (insn)) == stack_pointer_rtx))
+ && SET_DEST (PATTERN (insn)) == stack_pointer_rtx)
+ && GET_CODE (PATTERN (insn)) != USE)
{
if (reg_referenced_p (after_call, PATTERN (insn)))
avoid_return_reg = after_call;
after_call = 0;
}
-#endif /* SMALL_REGISTER_CLASSES */
/* If this is a USE and CLOBBER of a MEM, ensure that any
references to eliminable registers have been removed. */
@@ -3838,7 +4087,8 @@ reload_as_needed (first, live_known)
&& GET_CODE (XEXP (PATTERN (insn), 0)) == MEM)
XEXP (XEXP (PATTERN (insn), 0), 0)
= eliminate_regs (XEXP (XEXP (PATTERN (insn), 0), 0),
- GET_MODE (XEXP (PATTERN (insn), 0)), NULL_RTX);
+ GET_MODE (XEXP (PATTERN (insn), 0)),
+ NULL_RTX);
/* If we need to do register elimination processing, do so.
This might delete the insn, in which case we are done. */
@@ -3894,12 +4144,11 @@ reload_as_needed (first, live_known)
Record the choices of reload reg in reload_reg_rtx. */
choose_reload_regs (insn, avoid_return_reg);
-#ifdef SMALL_REGISTER_CLASSES
/* Merge any reloads that we didn't combine for fear of
increasing the number of spill registers needed but now
discover can be safely merged. */
- merge_assigned_reloads (insn);
-#endif
+ if (SMALL_REGISTER_CLASSES)
+ merge_assigned_reloads (insn);
/* Generate the insns to reload operands into or out of
their reload regs. */
@@ -3964,32 +4213,21 @@ reload_as_needed (first, live_known)
}
/* A reload reg's contents are unknown after a label. */
if (GET_CODE (insn) == CODE_LABEL)
- for (i = 0; i < n_spills; i++)
- {
- reg_reloaded_contents[i] = -1;
- reg_reloaded_insn[i] = 0;
- }
+ CLEAR_HARD_REG_SET (reg_reloaded_valid);
/* Don't assume a reload reg is still good after a call insn
if it is a call-used reg. */
else if (GET_CODE (insn) == CALL_INSN)
- for (i = 0; i < n_spills; i++)
- if (call_used_regs[spill_regs[i]])
- {
- reg_reloaded_contents[i] = -1;
- reg_reloaded_insn[i] = 0;
- }
+ AND_COMPL_HARD_REG_SET(reg_reloaded_valid, call_used_reg_set);
/* In case registers overlap, allow certain insns to invalidate
particular hard registers. */
#ifdef INSN_CLOBBERS_REGNO_P
- for (i = 0 ; i < n_spills ; i++)
- if (INSN_CLOBBERS_REGNO_P (insn, spill_regs[i]))
- {
- reg_reloaded_contents[i] = -1;
- reg_reloaded_insn[i] = 0;
- }
+ for (i = 0 ; i < FIRST_PSEUDO_REGISTER; i++)
+ if (TEST_HARD_REG_BIT (reg_reloaded_valid, i)
+ && INSN_CLOBBERS_REGNO_P (insn, i))
+ CLEAR_HARD_REG_BIT (reg_reloaded_valid, i);
#endif
insn = next;
@@ -4010,44 +4248,56 @@ reload_as_needed (first, live_known)
static void
forget_old_reloads_1 (x, ignored)
rtx x;
- rtx ignored;
+ rtx ignored ATTRIBUTE_UNUSED;
{
register int regno;
+ enum machine_mode mode = GET_MODE (x);
int nr;
- int offset = 0;
- /* note_stores does give us subregs of hard regs. */
+ /* note_stores does give us subregs of hard regs.
+
+ This is a egcs-1.1 tree hack only. A better solution is being
+ developed for mainline sources. Do not import this back to the
+ mainline tree.
+
+ We want to strip all the SUBREGs, but also keep track of the
+ largest mode we encounter so that we can invalidate all the
+ hard regs which are needed to hold the widest mode.
+
+ This avoids a bug in choose_reload_regs (which is where the real
+ fix for the mainline tree will be). */
+
while (GET_CODE (x) == SUBREG)
{
- offset += SUBREG_WORD (x);
+ if (GET_MODE_BITSIZE (GET_MODE (x)) > GET_MODE_BITSIZE (mode))
+ mode = GET_MODE (x);
x = SUBREG_REG (x);
}
+ if (GET_MODE_BITSIZE (GET_MODE (x)) > GET_MODE_BITSIZE (mode))
+ mode = GET_MODE (x);
+
if (GET_CODE (x) != REG)
return;
- regno = REGNO (x) + offset;
+ regno = REGNO (x);
if (regno >= FIRST_PSEUDO_REGISTER)
nr = 1;
else
{
int i;
- nr = HARD_REGNO_NREGS (regno, GET_MODE (x));
+ nr = HARD_REGNO_NREGS (regno, mode);
/* Storing into a spilled-reg invalidates its contents.
This can happen if a block-local pseudo is allocated to that reg
and it wasn't spilled because this block's total need is 0.
Then some insn might have an optional reload and use this reg. */
for (i = 0; i < nr; i++)
- if (spill_reg_order[regno + i] >= 0
- /* But don't do this if the reg actually serves as an output
- reload reg in the current instruction. */
- && (n_reloads == 0
- || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i)))
- {
- reg_reloaded_contents[spill_reg_order[regno + i]] = -1;
- reg_reloaded_insn[spill_reg_order[regno + i]] = 0;
- }
+ /* But don't do this if the reg actually serves as an output
+ reload reg in the current instruction. */
+ if (n_reloads == 0
+ || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i))
+ CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i);
}
/* Since value of X has changed,
@@ -4070,10 +4320,11 @@ static int reload_nregs[MAX_RELOADS];
should be handled first. *P1 and *P2 are the reload numbers. */
static int
-reload_reg_class_lower (p1, p2)
- short *p1, *p2;
+reload_reg_class_lower (r1p, r2p)
+ const GENERIC_PTR r1p;
+ const GENERIC_PTR r2p;
{
- register int r1 = *p1, r2 = *p2;
+ register int r1 = *(short *)r1p, r2 = *(short *)r2p;
register int t;
/* Consider required reloads before optional ones. */
@@ -4109,8 +4360,12 @@ reload_reg_class_lower (p1, p2)
static HARD_REG_SET reload_reg_used;
/* If reg is in use for a RELOAD_FOR_INPUT_ADDRESS reload for operand I. */
static HARD_REG_SET reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS];
+/* If reg is in use for a RELOAD_FOR_INPADDR_ADDRESS reload for operand I. */
+static HARD_REG_SET reload_reg_used_in_inpaddr_addr[MAX_RECOG_OPERANDS];
/* If reg is in use for a RELOAD_FOR_OUTPUT_ADDRESS reload for operand I. */
static HARD_REG_SET reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS];
+/* If reg is in use for a RELOAD_FOR_OUTADDR_ADDRESS reload for operand I. */
+static HARD_REG_SET reload_reg_used_in_outaddr_addr[MAX_RECOG_OPERANDS];
/* If reg is in use for a RELOAD_FOR_INPUT reload for operand I. */
static HARD_REG_SET reload_reg_used_in_input[MAX_RECOG_OPERANDS];
/* If reg is in use for a RELOAD_FOR_OUTPUT reload for operand I. */
@@ -4157,10 +4412,18 @@ mark_reload_reg_in_use (regno, opnum, type, mode)
SET_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ SET_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i);
+ break;
+
case RELOAD_FOR_OUTPUT_ADDRESS:
SET_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ SET_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
+ break;
+
case RELOAD_FOR_OPERAND_ADDRESS:
SET_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
break;
@@ -4214,10 +4477,18 @@ clear_reload_reg_in_use (regno, opnum, type, mode)
CLEAR_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], i);
break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], i);
+ break;
+
case RELOAD_FOR_OUTPUT_ADDRESS:
CLEAR_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], i);
break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ CLEAR_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], i);
+ break;
+
case RELOAD_FOR_OPERAND_ADDRESS:
CLEAR_HARD_REG_BIT (reload_reg_used_in_op_addr, i);
break;
@@ -4256,27 +4527,24 @@ reload_reg_free_p (regno, opnum, type)
{
int i;
- /* In use for a RELOAD_OTHER means it's not available for anything except
- RELOAD_FOR_OTHER_ADDRESS. Recall that RELOAD_FOR_OTHER_ADDRESS is known
- to be used only for inputs. */
-
- if (type != RELOAD_FOR_OTHER_ADDRESS
- && TEST_HARD_REG_BIT (reload_reg_used, regno))
+ /* In use for a RELOAD_OTHER means it's not available for anything. */
+ if (TEST_HARD_REG_BIT (reload_reg_used, regno))
return 0;
switch (type)
{
case RELOAD_OTHER:
- /* In use for anything except RELOAD_FOR_OTHER_ADDRESS means
- we can't use it for RELOAD_OTHER. */
- if (TEST_HARD_REG_BIT (reload_reg_used, regno)
+ /* In use for anything means we can't use it for RELOAD_OTHER. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno))
return 0;
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
return 0;
@@ -4298,7 +4566,8 @@ reload_reg_free_p (regno, opnum, type)
/* If it is used in a later operand's address, can't use it. */
for (i = opnum + 1; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
return 1;
@@ -4306,7 +4575,21 @@ reload_reg_free_p (regno, opnum, type)
case RELOAD_FOR_INPUT_ADDRESS:
/* Can't use a register if it is used for an input address for this
operand or used as an input in an earlier one. */
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno))
+ return 0;
+
+ for (i = 0; i < opnum; i++)
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
+ return 0;
+
+ return 1;
+
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ /* Can't use a register if it is used for an input address
+ for this operand or used as an input in an earlier
+ one. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno))
return 0;
for (i = 0; i < opnum; i++)
@@ -4327,6 +4610,19 @@ reload_reg_free_p (regno, opnum, type)
return 1;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ /* Can't use a register if it is used for an output address
+ for this operand or used as an output in this or a
+ later operand. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno))
+ return 0;
+
+ for (i = opnum; i < reload_n_operands; i++)
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
+ return 0;
+
+ return 1;
+
case RELOAD_FOR_OPERAND_ADDRESS:
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
@@ -4353,7 +4649,8 @@ reload_reg_free_p (regno, opnum, type)
return 0;
for (i = 0; i <= opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
return 0;
return 1;
@@ -4407,12 +4704,18 @@ reload_reg_free_before_p (regno, opnum, type)
the first place, since we know that it was allocated. */
case RELOAD_FOR_OUTPUT_ADDRESS:
+ /* Earlier reloads include RELOAD_FOR_OUTADDR_ADDRESS reloads. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno))
+ return 0;
+ /* ... fall through ... */
+ case RELOAD_FOR_OUTADDR_ADDRESS:
/* Earlier reloads are for earlier outputs or their addresses,
any RELOAD_FOR_INSN reloads, any inputs or their addresses, or any
RELOAD_FOR_OTHER_ADDRESS reloads (we know it can't conflict with
RELOAD_OTHER).. */
for (i = 0; i < opnum; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
return 0;
@@ -4421,42 +4724,35 @@ reload_reg_free_before_p (regno, opnum, type)
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
return 0;
return (! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno)
&& ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)
+ && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)
&& ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno));
case RELOAD_FOR_OUTPUT:
- /* This can't be used in the output address for this operand and
- anything that can't be used for it, except that we've already
- tested for RELOAD_FOR_INSN objects. */
+ /* There is no reason to call this function for output reloads, thus
+ anything we'd put here wouldn't be tested. So just abort. */
+ abort ();
- if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno))
+ case RELOAD_FOR_OPERAND_ADDRESS:
+ /* Earlier reloads include RELOAD_FOR_OPADDR_ADDR reloads. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno))
return 0;
- for (i = 0; i < opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
- return 0;
-
- for (i = 0; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)
- || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno))
- return 0;
-
- return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
+ /* ... fall through ... */
- case RELOAD_FOR_OPERAND_ADDRESS:
case RELOAD_FOR_OPADDR_ADDR:
case RELOAD_FOR_INSN:
/* These can't conflict with inputs, or each other, so all we have to
test is input addresses and the addresses of OTHER items. */
for (i = 0; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
@@ -4467,16 +4763,23 @@ reload_reg_free_before_p (regno, opnum, type)
with), and addresses of RELOAD_OTHER objects. */
for (i = 0; i <= opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
case RELOAD_FOR_INPUT_ADDRESS:
+ /* Earlier reloads include RELOAD_FOR_INPADDR_ADDRESS reloads. */
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno))
+ return 0;
+ /* ... fall through ... */
+ case RELOAD_FOR_INPADDR_ADDRESS:
/* Similarly, all we have to check is for use in earlier inputs'
addresses. */
for (i = 0; i < opnum; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno);
@@ -4518,8 +4821,10 @@ reload_reg_reaches_end_p (regno, opnum, type)
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
return 0;
@@ -4528,6 +4833,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
&& ! TEST_HARD_REG_BIT (reload_reg_used, regno));
case RELOAD_FOR_INPUT_ADDRESS:
+ case RELOAD_FOR_INPADDR_ADDRESS:
/* Similar, except that we check only for this and subsequent inputs
and the address of only subsequent inputs and we do not need
to check for RELOAD_OTHER objects since they are known not to
@@ -4538,11 +4844,13 @@ reload_reg_reaches_end_p (regno, opnum, type)
return 0;
for (i = opnum + 1; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno))
return 0;
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
return 0;
@@ -4560,16 +4868,18 @@ reload_reg_reaches_end_p (regno, opnum, type)
for (i = opnum + 1; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno))
return 0;
- /* ... fall through ... */
+ /* ... fall through ... */
case RELOAD_FOR_OPERAND_ADDRESS:
/* Check outputs and their addresses. */
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
return 0;
@@ -4578,6 +4888,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
case RELOAD_FOR_OPADDR_ADDR:
for (i = 0; i < reload_n_operands; i++)
if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)
|| TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno))
return 0;
@@ -4590,14 +4901,16 @@ reload_reg_reaches_end_p (regno, opnum, type)
opnum = -1;
- /* ... fall through ... */
+ /* ... fall through ... */
case RELOAD_FOR_OUTPUT:
case RELOAD_FOR_OUTPUT_ADDRESS:
+ case RELOAD_FOR_OUTADDR_ADDRESS:
/* We already know these can't conflict with a later output. So the
only thing to check are later output addresses. */
for (i = opnum + 1; i < reload_n_operands; i++)
- if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno))
+ if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno)
+ || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno))
return 0;
return 1;
@@ -4611,7 +4924,7 @@ reload_reg_reaches_end_p (regno, opnum, type)
This function uses the same algorithm as reload_reg_free_p above. */
-static int
+int
reloads_conflict (r1, r2)
int r1, r2;
{
@@ -4620,9 +4933,8 @@ reloads_conflict (r1, r2)
int r1_opnum = reload_opnum[r1];
int r2_opnum = reload_opnum[r2];
- /* RELOAD_OTHER conflicts with everything except RELOAD_FOR_OTHER_ADDRESS. */
-
- if (r2_type == RELOAD_OTHER && r1_type != RELOAD_FOR_OTHER_ADDRESS)
+ /* RELOAD_OTHER conflicts with everything. */
+ if (r2_type == RELOAD_OTHER)
return 1;
/* Otherwise, check conflicts differently for each type. */
@@ -4634,16 +4946,26 @@ reloads_conflict (r1, r2)
|| r2_type == RELOAD_FOR_OPERAND_ADDRESS
|| r2_type == RELOAD_FOR_OPADDR_ADDR
|| r2_type == RELOAD_FOR_INPUT
- || (r2_type == RELOAD_FOR_INPUT_ADDRESS && r2_opnum > r1_opnum));
+ || ((r2_type == RELOAD_FOR_INPUT_ADDRESS
+ || r2_type == RELOAD_FOR_INPADDR_ADDRESS)
+ && r2_opnum > r1_opnum));
case RELOAD_FOR_INPUT_ADDRESS:
return ((r2_type == RELOAD_FOR_INPUT_ADDRESS && r1_opnum == r2_opnum)
|| (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum));
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ return ((r2_type == RELOAD_FOR_INPADDR_ADDRESS && r1_opnum == r2_opnum)
+ || (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum));
+
case RELOAD_FOR_OUTPUT_ADDRESS:
return ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS && r2_opnum == r1_opnum)
|| (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum));
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ return ((r2_type == RELOAD_FOR_OUTADDR_ADDRESS && r2_opnum == r1_opnum)
+ || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum >= r1_opnum));
+
case RELOAD_FOR_OPERAND_ADDRESS:
return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN
|| r2_type == RELOAD_FOR_OPERAND_ADDRESS);
@@ -4654,7 +4976,8 @@ reloads_conflict (r1, r2)
case RELOAD_FOR_OUTPUT:
return (r2_type == RELOAD_FOR_INSN || r2_type == RELOAD_FOR_OUTPUT
- || (r2_type == RELOAD_FOR_OUTPUT_ADDRESS
+ || ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS
+ || r2_type == RELOAD_FOR_OUTADDR_ADDRESS)
&& r2_opnum >= r1_opnum));
case RELOAD_FOR_INSN:
@@ -4666,7 +4989,7 @@ reloads_conflict (r1, r2)
return r2_type == RELOAD_FOR_OTHER_ADDRESS;
case RELOAD_OTHER:
- return r2_type != RELOAD_FOR_OTHER_ADDRESS;
+ return 1;
default:
abort ();
@@ -4689,10 +5012,138 @@ rtx reload_inheritance_insn[MAX_RELOADS];
rather than using reload_in. */
rtx reload_override_in[MAX_RELOADS];
-/* For each reload, the index in spill_regs of the spill register used,
- or -1 if we did not need one of the spill registers for this reload. */
+/* For each reload, the hard register number of the register used,
+ or -1 if we did not need a register for this reload. */
int reload_spill_index[MAX_RELOADS];
+/* Return 1 if the value in reload reg REGNO, as used by a reload
+ needed for the part of the insn specified by OPNUM and TYPE,
+ may be used to load VALUE into it.
+
+ Other read-only reloads with the same value do not conflict
+ unless OUT is non-zero and these other reloads have to live while
+ output reloads live.
+
+ RELOADNUM is the number of the reload we want to load this value for;
+ a reload does not conflict with itself.
+
+ The caller has to make sure that there is no conflict with the return
+ register. */
+static int
+reload_reg_free_for_value_p (regno, opnum, type, value, out, reloadnum)
+ int regno;
+ int opnum;
+ enum reload_type type;
+ rtx value, out;
+ int reloadnum;
+{
+ int time1;
+ int i;
+
+ /* We use some pseudo 'time' value to check if the lifetimes of the
+ new register use would overlap with the one of a previous reload
+ that is not read-only or uses a different value.
+ The 'time' used doesn't have to be linear in any shape or form, just
+ monotonic.
+ Some reload types use different 'buckets' for each operand.
+ So there are MAX_RECOG_OPERANDS different time values for each
+ such reload type.
+ We compute TIME1 as the time when the register for the prospective
+ new reload ceases to be live, and TIME2 for each existing
+ reload as the time when that the reload register of that reload
+ becomes live.
+ Where there is little to be gained by exact lifetime calculations,
+ we just make conservative assumptions, i.e. a longer lifetime;
+ this is done in the 'default:' cases. */
+ switch (type)
+ {
+ case RELOAD_FOR_OTHER_ADDRESS:
+ time1 = 0;
+ break;
+ /* For each input, we might have a sequence of RELOAD_FOR_INPADDR_ADDRESS,
+ RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_INPUT. By adding 0 / 1 / 2 ,
+ respectively, to the time values for these, we get distinct time
+ values. To get distinct time values for each operand, we have to
+ multiply opnum by at least three. We round that up to four because
+ multiply by four is often cheaper. */
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ time1 = opnum * 4 + 1;
+ break;
+ case RELOAD_FOR_INPUT_ADDRESS:
+ time1 = opnum * 4 + 2;
+ break;
+ case RELOAD_FOR_INPUT:
+ /* All RELOAD_FOR_INPUT reloads remain live till just before the
+ instruction is executed. */
+ time1 = (MAX_RECOG_OPERANDS - 1) * 4 + 3;
+ break;
+ /* opnum * 4 + 3 < opnum * 4 + 4
+ <= (MAX_RECOG_OPERANDS - 1) * 4 + 4 == MAX_RECOG_OPERANDS * 4 */
+ case RELOAD_FOR_OUTPUT_ADDRESS:
+ time1 = MAX_RECOG_OPERANDS * 4 + opnum;
+ break;
+ default:
+ time1 = MAX_RECOG_OPERANDS * 5;
+ }
+
+ for (i = 0; i < n_reloads; i++)
+ {
+ rtx reg = reload_reg_rtx[i];
+ if (reg && GET_CODE (reg) == REG
+ && ((unsigned) regno - true_regnum (reg)
+ <= HARD_REGNO_NREGS (REGNO (reg), GET_MODE (reg)) - (unsigned)1)
+ && i != reloadnum)
+ {
+ if (out
+ && reload_when_needed[i] != RELOAD_FOR_INPUT
+ && reload_when_needed[i] != RELOAD_FOR_INPUT_ADDRESS
+ && reload_when_needed[i] != RELOAD_FOR_INPADDR_ADDRESS)
+ return 0;
+ if (! reload_in[i] || ! rtx_equal_p (reload_in[i], value)
+ || reload_out[i])
+ {
+ int time2;
+ switch (reload_when_needed[i])
+ {
+ case RELOAD_FOR_OTHER_ADDRESS:
+ time2 = 0;
+ break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ time2 = reload_opnum[i] * 4 + 1;
+ break;
+ case RELOAD_FOR_INPUT_ADDRESS:
+ time2 = reload_opnum[i] * 4 + 2;
+ break;
+ case RELOAD_FOR_INPUT:
+ time2 = reload_opnum[i] * 4 + 3;
+ break;
+ case RELOAD_FOR_OUTPUT:
+ /* All RELOAD_FOR_OUTPUT reloads become live just after the
+ instruction is executed. */
+ time2 = MAX_RECOG_OPERANDS * 4;
+ break;
+ /* The first RELOAD_FOR_OUTPUT_ADDRESS reload conflicts with the
+ RELOAD_FOR_OUTPUT reloads, so assign it the same time value. */
+ case RELOAD_FOR_OUTPUT_ADDRESS:
+ time2 = MAX_RECOG_OPERANDS * 4 + reload_opnum[i];
+ break;
+ case RELOAD_OTHER:
+ if (! reload_in[i] || rtx_equal_p (reload_in[i], value))
+ {
+ time2 = MAX_RECOG_OPERANDS * 4;
+ break;
+ }
+ default:
+ time2 = 0;
+ }
+ if (time1 >= time2)
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
/* Find a spill register to use as a reload register for reload R.
LAST_RELOAD is non-zero if this is the last reload for the insn being
processed.
@@ -4765,8 +5216,17 @@ allocate_reload_reg (r, insn, last_reload, noerror)
i = (i + 1) % n_spills;
- if (reload_reg_free_p (spill_regs[i], reload_opnum[r],
- reload_when_needed[r])
+ if ((reload_reg_free_p (spill_regs[i], reload_opnum[r],
+ reload_when_needed[r])
+ || (reload_in[r]
+ /* We check reload_reg_used to make sure we
+ don't clobber the return register. */
+ && ! TEST_HARD_REG_BIT (reload_reg_used, spill_regs[i])
+ && reload_reg_free_for_value_p (spill_regs[i],
+ reload_opnum[r],
+ reload_when_needed[r],
+ reload_in[r],
+ reload_out[r], r)))
&& TEST_HARD_REG_BIT (reg_class_contents[class], spill_regs[i])
&& HARD_REGNO_MODE_OK (spill_regs[i], reload_mode[r])
/* Look first for regs to share, then for unshared. But
@@ -4834,7 +5294,7 @@ allocate_reload_reg (r, insn, last_reload, noerror)
if (new == 0 || GET_MODE (new) != reload_mode[r])
spill_reg_rtx[i] = new
- = gen_rtx (REG, reload_mode[r], spill_regs[i]);
+ = gen_rtx_REG (reload_mode[r], spill_regs[i]);
regno = true_regnum (new);
@@ -4865,7 +5325,7 @@ allocate_reload_reg (r, insn, last_reload, noerror)
reload_when_needed[r], reload_mode[r]);
reload_reg_rtx[r] = new;
- reload_spill_index[r] = i;
+ reload_spill_index[r] = spill_regs[i];
return 1;
}
}
@@ -4916,7 +5376,9 @@ choose_reload_regs (insn, avoid_return_reg)
int save_reload_spill_index[MAX_RELOADS];
HARD_REG_SET save_reload_reg_used;
HARD_REG_SET save_reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS];
+ HARD_REG_SET save_reload_reg_used_in_inpaddr_addr[MAX_RECOG_OPERANDS];
HARD_REG_SET save_reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS];
+ HARD_REG_SET save_reload_reg_used_in_outaddr_addr[MAX_RECOG_OPERANDS];
HARD_REG_SET save_reload_reg_used_in_input[MAX_RECOG_OPERANDS];
HARD_REG_SET save_reload_reg_used_in_output[MAX_RECOG_OPERANDS];
HARD_REG_SET save_reload_reg_used_in_op_addr;
@@ -4941,13 +5403,14 @@ choose_reload_regs (insn, avoid_return_reg)
CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]);
CLEAR_HARD_REG_SET (reload_reg_used_in_input[i]);
CLEAR_HARD_REG_SET (reload_reg_used_in_input_addr[i]);
+ CLEAR_HARD_REG_SET (reload_reg_used_in_inpaddr_addr[i]);
CLEAR_HARD_REG_SET (reload_reg_used_in_output_addr[i]);
+ CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]);
}
-#ifdef SMALL_REGISTER_CLASSES
/* Don't bother with avoiding the return reg
if we have no mandatory reload that could use it. */
- if (avoid_return_reg)
+ if (SMALL_REGISTER_CLASSES && avoid_return_reg)
{
int do_avoid = 0;
int regno = REGNO (avoid_return_reg);
@@ -4967,7 +5430,6 @@ choose_reload_regs (insn, avoid_return_reg)
if (!do_avoid)
avoid_return_reg = 0;
}
-#endif /* SMALL_REGISTER_CLASSES */
#if 0 /* Not needed, now that we can always retry without inheritance. */
/* See if we have more mandatory reloads than spill regs.
@@ -4978,10 +5440,7 @@ choose_reload_regs (insn, avoid_return_reg)
unless it is equal to reload_in or reload_out, count such reloads. */
{
- int tem = 0;
-#ifdef SMALL_REGISTER_CLASSES
- int tem = (avoid_return_reg != 0);
-#endif
+ int tem = SMALL_REGISTER_CLASSES? (avoid_return_reg != 0): 0;
for (j = 0; j < n_reloads; j++)
if (! reload_optional[j]
&& (reload_in[j] != 0 || reload_out[j] != 0 || reload_secondary_p[j])
@@ -4994,10 +5453,9 @@ choose_reload_regs (insn, avoid_return_reg)
}
#endif
-#ifdef SMALL_REGISTER_CLASSES
/* Don't use the subroutine call return reg for a reload
if we are supposed to avoid it. */
- if (avoid_return_reg)
+ if (SMALL_REGISTER_CLASSES && avoid_return_reg)
{
int regno = REGNO (avoid_return_reg);
int nregs
@@ -5008,7 +5466,6 @@ choose_reload_regs (insn, avoid_return_reg)
if (spill_reg_order[r] >= 0)
SET_HARD_REG_BIT (reload_reg_used, r);
}
-#endif /* SMALL_REGISTER_CLASSES */
/* In order to be certain of getting the registers we need,
we must sort the reloads into order of increasing register class.
@@ -5079,8 +5536,12 @@ choose_reload_regs (insn, avoid_return_reg)
reload_reg_used_in_input[i]);
COPY_HARD_REG_SET (save_reload_reg_used_in_input_addr[i],
reload_reg_used_in_input_addr[i]);
+ COPY_HARD_REG_SET (save_reload_reg_used_in_inpaddr_addr[i],
+ reload_reg_used_in_inpaddr_addr[i]);
COPY_HARD_REG_SET (save_reload_reg_used_in_output_addr[i],
reload_reg_used_in_output_addr[i]);
+ COPY_HARD_REG_SET (save_reload_reg_used_in_outaddr_addr[i],
+ reload_reg_used_in_outaddr_addr[i]);
}
/* If -O, try first with inheritance, then turning it off.
@@ -5116,12 +5577,14 @@ choose_reload_regs (insn, avoid_return_reg)
register int r = reload_order[j];
/* Ignore reloads that got marked inoperative. */
- if (reload_out[r] == 0 && reload_in[r] == 0 && ! reload_secondary_p[r])
+ if (reload_out[r] == 0 && reload_in[r] == 0
+ && ! reload_secondary_p[r])
continue;
/* If find_reloads chose a to use reload_in or reload_out as a reload
- register, we don't need to chose one. Otherwise, try even if it found
- one since we might save an insn if we find the value lying around. */
+ register, we don't need to chose one. Otherwise, try even if it
+ found one since we might save an insn if we find the value lying
+ around. */
if (reload_in[r] != 0 && reload_reg_rtx[r] != 0
&& (rtx_equal_p (reload_in[r], reload_reg_rtx[r])
|| rtx_equal_p (reload_out[r], reload_reg_rtx[r])))
@@ -5153,9 +5616,9 @@ choose_reload_regs (insn, avoid_return_reg)
an object that is already in a register of the desired class.
This would avoid the need for the secondary reload register.
But this is complex because we can't easily determine what
- objects might want to be loaded via this reload. So let a register
- be allocated here. In `emit_reload_insns' we suppress one of the
- loads in the case described above. */
+ objects might want to be loaded via this reload. So let a
+ register be allocated here. In `emit_reload_insns' we suppress
+ one of the loads in the case described above. */
if (inheritance)
{
@@ -5174,6 +5637,33 @@ choose_reload_regs (insn, avoid_return_reg)
regno = REGNO (reload_in_reg[r]);
mode = GET_MODE (reload_in_reg[r]);
}
+ else if (GET_CODE (reload_in[r]) == MEM)
+ {
+ rtx prev = prev_nonnote_insn (insn), note;
+
+ if (prev && GET_CODE (prev) == INSN
+ && GET_CODE (PATTERN (prev)) == USE
+ && GET_CODE (XEXP (PATTERN (prev), 0)) == REG
+ && (REGNO (XEXP (PATTERN (prev), 0))
+ >= FIRST_PSEUDO_REGISTER)
+ && (note = find_reg_note (prev, REG_EQUAL, NULL_RTX))
+ && GET_CODE (XEXP (note, 0)) == MEM)
+ {
+ rtx addr = XEXP (XEXP (note, 0), 0);
+ int size_diff
+ = (GET_MODE_SIZE (GET_MODE (addr))
+ - GET_MODE_SIZE (GET_MODE (reload_in[r])));
+ if (size_diff >= 0
+ && rtx_equal_p ((BYTES_BIG_ENDIAN
+ ? plus_constant (addr, size_diff)
+ : addr),
+ XEXP (reload_in[r], 0)))
+ {
+ regno = REGNO (XEXP (PATTERN (prev), 0));
+ mode = GET_MODE (reload_in[r]);
+ }
+ }
+ }
#if 0
/* This won't work, since REGNO can be a pseudo reg number.
Also, it takes much more hair to keep track of all the things
@@ -5185,32 +5675,36 @@ choose_reload_regs (insn, avoid_return_reg)
if (regno >= 0 && reg_last_reload_reg[regno] != 0)
{
- i = spill_reg_order[REGNO (reg_last_reload_reg[regno])];
+ i = REGNO (reg_last_reload_reg[regno]);
if (reg_reloaded_contents[i] == regno
+ && TEST_HARD_REG_BIT (reg_reloaded_valid, i)
&& (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno]))
>= GET_MODE_SIZE (mode))
- && HARD_REGNO_MODE_OK (spill_regs[i], reload_mode[r])
+ && HARD_REGNO_MODE_OK (i, reload_mode[r])
&& TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
- spill_regs[i])
+ i)
&& (reload_nregs[r] == max_group_size
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) group_class],
- spill_regs[i]))
- && reload_reg_free_p (spill_regs[i], reload_opnum[r],
- reload_when_needed[r])
- && reload_reg_free_before_p (spill_regs[i],
- reload_opnum[r],
- reload_when_needed[r]))
+ i))
+ && ((reload_reg_free_p (i, reload_opnum[r],
+ reload_when_needed[r])
+ && reload_reg_free_before_p (i, reload_opnum[r],
+ reload_when_needed[r]))
+ || reload_reg_free_for_value_p (i, reload_opnum[r],
+ reload_when_needed[r],
+ reload_in[r],
+ reload_out[r], r)))
{
/* If a group is needed, verify that all the subsequent
- registers still have their values intact. */
+ registers still have their values intact. */
int nr
- = HARD_REGNO_NREGS (spill_regs[i], reload_mode[r]);
+ = HARD_REGNO_NREGS (i, reload_mode[r]);
int k;
for (k = 1; k < nr; k++)
- if (reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
- != regno)
+ if (reg_reloaded_contents[i + k] != regno
+ || ! TEST_HARD_REG_BIT (reg_reloaded_valid, i + k))
break;
if (k == nr)
@@ -5231,6 +5725,10 @@ choose_reload_regs (insn, avoid_return_reg)
break;
if (i1 != n_earlyclobbers
+ /* Don't use it if we'd clobber a pseudo reg. */
+ || (spill_reg_order[i] < 0
+ && reload_out[r]
+ && ! TEST_HARD_REG_BIT (reg_reloaded_dead, i))
/* Don't really use the inherited spill reg
if we need it wider than we've got it. */
|| (GET_MODE_SIZE (reload_mode[r])
@@ -5242,7 +5740,7 @@ choose_reload_regs (insn, avoid_return_reg)
/* We can use this as a reload reg. */
/* Mark the register as in use for this part of
the insn. */
- mark_reload_reg_in_use (spill_regs[i],
+ mark_reload_reg_in_use (i,
reload_opnum[r],
reload_when_needed[r],
reload_mode[r]);
@@ -5253,7 +5751,7 @@ choose_reload_regs (insn, avoid_return_reg)
reload_spill_index[r] = i;
for (k = 0; k < nr; k++)
SET_HARD_REG_BIT (reload_reg_used_for_inherit,
- spill_regs[i + k]);
+ i + k);
}
}
}
@@ -5288,7 +5786,7 @@ choose_reload_regs (insn, avoid_return_reg)
address and not all machines support SUBREGs
there. */
regno = REGNO (SUBREG_REG (equiv)) + SUBREG_WORD (equiv);
- equiv = gen_rtx (REG, reload_mode[r], regno);
+ equiv = gen_rtx_REG (reload_mode[r], regno);
}
else
abort ();
@@ -5298,8 +5796,13 @@ choose_reload_regs (insn, avoid_return_reg)
and of the desired class. */
if (equiv != 0
&& ((spill_reg_order[regno] >= 0
- && ! reload_reg_free_before_p (regno, reload_opnum[r],
- reload_when_needed[r]))
+ && ! (reload_reg_free_before_p (regno, reload_opnum[r],
+ reload_when_needed[r])
+ || reload_reg_free_for_value_p (regno,
+ reload_opnum[r],
+ reload_when_needed[r],
+ reload_in[r],
+ reload_out[r], r)))
|| ! TEST_HARD_REG_BIT (reg_class_contents[(int) reload_reg_class[r]],
regno)))
equiv = 0;
@@ -5325,33 +5828,60 @@ choose_reload_regs (insn, avoid_return_reg)
break;
}
- /* JRV: If the equiv register we have found is explicitly
- clobbered in the current insn, mark but don't use, as above. */
+ /* If the equiv register we have found is explicitly clobbered
+ in the current insn, it depends on the reload type if we
+ can use it, use it for reload_override_in, or not at all.
+ In particular, we then can't use EQUIV for a
+ RELOAD_FOR_OUTPUT_ADDRESS reload. */
if (equiv != 0 && regno_clobbered_p (regno, insn))
{
- reload_override_in[r] = equiv;
- equiv = 0;
+ switch (reload_when_needed[r])
+ {
+ case RELOAD_FOR_OTHER_ADDRESS:
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ case RELOAD_FOR_INPUT_ADDRESS:
+ case RELOAD_FOR_OPADDR_ADDR:
+ break;
+ case RELOAD_OTHER:
+ case RELOAD_FOR_INPUT:
+ case RELOAD_FOR_OPERAND_ADDRESS:
+ reload_override_in[r] = equiv;
+ /* Fall through. */
+ default:
+ equiv = 0;
+ break;
+ }
}
/* If we found an equivalent reg, say no code need be generated
to load it, and use it as our reload reg. */
if (equiv != 0 && regno != HARD_FRAME_POINTER_REGNUM)
{
+ int nr = HARD_REGNO_NREGS (regno, reload_mode[r]);
+ int k;
reload_reg_rtx[r] = equiv;
reload_inherited[r] = 1;
- /* If it is a spill reg,
- mark the spill reg as in use for this insn. */
- i = spill_reg_order[regno];
- if (i >= 0)
+
+ /* If reg_reloaded_valid is not set for this register,
+ there might be a stale spill_reg_store lying around.
+ We must clear it, since otherwise emit_reload_insns
+ might delete the store. */
+ if (! TEST_HARD_REG_BIT (reg_reloaded_valid, regno))
+ spill_reg_store[regno] = NULL_RTX;
+ /* If any of the hard registers in EQUIV are spill
+ registers, mark them as in use for this insn. */
+ for (k = 0; k < nr; k++)
{
- int nr = HARD_REGNO_NREGS (regno, reload_mode[r]);
- int k;
- mark_reload_reg_in_use (regno, reload_opnum[r],
- reload_when_needed[r],
- reload_mode[r]);
- for (k = 0; k < nr; k++)
- SET_HARD_REG_BIT (reload_reg_used_for_inherit, regno + k);
+ i = spill_reg_order[regno + k];
+ if (i >= 0)
+ {
+ mark_reload_reg_in_use (regno, reload_opnum[r],
+ reload_when_needed[r],
+ reload_mode[r]);
+ SET_HARD_REG_BIT (reload_reg_used_for_inherit,
+ regno + k);
+ }
}
}
}
@@ -5407,7 +5937,7 @@ choose_reload_regs (insn, avoid_return_reg)
continue;
/* Skip reloads that already have a register allocated or are
- optional. */
+ optional. */
if (reload_reg_rtx[r] != 0 || reload_optional[r])
continue;
@@ -5453,8 +5983,12 @@ choose_reload_regs (insn, avoid_return_reg)
save_reload_reg_used_in_output[i]);
COPY_HARD_REG_SET (reload_reg_used_in_input_addr[i],
save_reload_reg_used_in_input_addr[i]);
+ COPY_HARD_REG_SET (reload_reg_used_in_inpaddr_addr[i],
+ save_reload_reg_used_in_inpaddr_addr[i]);
COPY_HARD_REG_SET (reload_reg_used_in_output_addr[i],
save_reload_reg_used_in_output_addr[i]);
+ COPY_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i],
+ save_reload_reg_used_in_outaddr_addr[i]);
}
}
@@ -5467,10 +6001,56 @@ choose_reload_regs (insn, avoid_return_reg)
register int r = reload_order[j];
if (reload_inherited[r] && reload_reg_rtx[r] != 0
- && ! reload_reg_free_before_p (true_regnum (reload_reg_rtx[r]),
- reload_opnum[r],
- reload_when_needed[r]))
+ && ! (reload_reg_free_before_p (true_regnum (reload_reg_rtx[r]),
+ reload_opnum[r],
+ reload_when_needed[r])
+ || reload_reg_free_for_value_p (true_regnum (reload_reg_rtx[r]),
+ reload_opnum[r],
+ reload_when_needed[r],
+ reload_in[r],
+ reload_out[r], r)))
reload_inherited[r] = 0;
+ /* If we can inherit a RELOAD_FOR_INPUT, then we do not need its related
+ RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS reloads.
+ ??? This could be extended to other reload types, but these are
+ more tricky to handle:
+ RELOAD_FOR_OTHER_ADDRESS reloads might have been merged, so we
+ can't eliminate them without a check that *all* references are
+ now unused due to inheritance.
+ While RELOAD_FOR_INPADDR_ADDRESS and RELOAD_FOR_OUTADDR_ADDRESS are
+ not merged, we can't be sure that we have eliminated the use of
+ that particular reload if we have seen just one
+ RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_OUTPUT_ADDRESS being inherited,
+ since there might be multiple of the latter two reloads for a single
+ operand.
+ RELOAD_FOR_OPADDR_ADDR reloads for different operands are not
+ merged, but might share the same register by courtesy of
+ reload_reg_free_for_value_p. reload_reg_used_in_op_addr_reload
+ does not differentiate by opnum, thus calling clear_reload_reg_in_use
+ for one of these reloads would mark the register as free even though
+ another RELOAD_FOR_OPADDR_ADDR reload might still use it. */
+ else if (reload_inherited[r] && reload_when_needed[r] == RELOAD_FOR_INPUT)
+ {
+ for (i = 0; i < n_reloads; i++)
+ {
+ if ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
+ && reload_opnum[i] == reload_opnum[r]
+ && reload_in[i] && reload_reg_rtx[i])
+ {
+ int regno = true_regnum (reload_reg_rtx[i]);
+
+ reload_in[i] = 0;
+ if (spill_reg_order[regno] >= 0)
+ clear_reload_reg_in_use (regno, reload_opnum[i],
+ reload_when_needed[i],
+ reload_mode[i]);
+ reload_reg_rtx[i] = 0;
+ reload_spill_index[i] = -1;
+ remove_replacements (i);
+ }
+ }
+ }
/* If we found a better place to reload from,
validate it in the same fashion, if it is a reload reg. */
@@ -5516,7 +6096,7 @@ choose_reload_regs (insn, avoid_return_reg)
i = reload_spill_index[r];
- /* I is nonneg if this reload used one of the spill regs.
+ /* I is nonneg if this reload uses a register.
If reload_reg_rtx[r] is 0, this is an optional reload
that we opted to ignore. */
if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG
@@ -5533,9 +6113,9 @@ choose_reload_regs (insn, avoid_return_reg)
if (i >= 0)
{
- nr = HARD_REGNO_NREGS (spill_regs[i], reload_mode[r]);
+ nr = HARD_REGNO_NREGS (i, reload_mode[r]);
while (--nr >= 0)
- SET_HARD_REG_BIT (reg_is_output_reload, spill_regs[i] + nr);
+ SET_HARD_REG_BIT (reg_is_output_reload, i + nr);
}
if (reload_when_needed[r] != RELOAD_OTHER
@@ -5546,7 +6126,7 @@ choose_reload_regs (insn, avoid_return_reg)
}
}
-/* If SMALL_REGISTER_CLASSES are defined, we may not have merged two
+/* If SMALL_REGISTER_CLASSES is non-zero, we may not have merged two
reloads of the same item for fear that we might not have enough reload
registers. However, normally they will get the same reload register
and hence actually need not be loaded twice.
@@ -5559,8 +6139,6 @@ choose_reload_regs (insn, avoid_return_reg)
This will not increase the number of spill registers needed and will
prevent redundant code. */
-#ifdef SMALL_REGISTER_CLASSES
-
static void
merge_assigned_reloads (insn)
rtx insn;
@@ -5573,6 +6151,10 @@ merge_assigned_reloads (insn)
for (i = 0; i < n_reloads; i++)
{
+ int conflicting_input = 0;
+ int max_input_address_opnum = -1;
+ int min_conflicting_input_opnum = MAX_RECOG_OPERANDS;
+
if (reload_in[i] == 0 || reload_when_needed[i] == RELOAD_OTHER
|| reload_out[i] != 0 || reload_reg_rtx[i] == 0
|| reg_set_p (reload_reg_rtx[i], insn))
@@ -5591,27 +6173,46 @@ merge_assigned_reloads (insn)
reload_reg_rtx[i]))
continue;
+ if (reload_when_needed[j] == RELOAD_FOR_INPUT_ADDRESS
+ && reload_opnum[j] > max_input_address_opnum)
+ max_input_address_opnum = reload_opnum[j];
+
/* If the reload regs aren't exactly the same (e.g, different modes)
- or if the values are different, we can't merge anything with this
- reload register. */
+ or if the values are different, we can't merge this reload.
+ But if it is an input reload, we might still merge
+ RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_OTHER_ADDRESS reloads. */
if (! rtx_equal_p (reload_reg_rtx[i], reload_reg_rtx[j])
|| reload_out[j] != 0 || reload_in[j] == 0
|| ! rtx_equal_p (reload_in[i], reload_in[j]))
- break;
+ {
+ if (reload_when_needed[j] != RELOAD_FOR_INPUT
+ || ((reload_when_needed[i] != RELOAD_FOR_INPUT_ADDRESS
+ || reload_opnum[i] > reload_opnum[j])
+ && reload_when_needed[i] != RELOAD_FOR_OTHER_ADDRESS))
+ break;
+ conflicting_input = 1;
+ if (min_conflicting_input_opnum > reload_opnum[j])
+ min_conflicting_input_opnum = reload_opnum[j];
+ }
}
/* If all is OK, merge the reloads. Only set this to RELOAD_OTHER if
we, in fact, found any matching reloads. */
- if (j == n_reloads)
+ if (j == n_reloads
+ && max_input_address_opnum <= min_conflicting_input_opnum)
{
for (j = 0; j < n_reloads; j++)
if (i != j && reload_reg_rtx[j] != 0
- && rtx_equal_p (reload_reg_rtx[i], reload_reg_rtx[j]))
+ && rtx_equal_p (reload_reg_rtx[i], reload_reg_rtx[j])
+ && (! conflicting_input
+ || reload_when_needed[j] == RELOAD_FOR_INPUT_ADDRESS
+ || reload_when_needed[j] == RELOAD_FOR_OTHER_ADDRESS))
{
reload_when_needed[i] = RELOAD_OTHER;
reload_in[j] = 0;
+ reload_spill_index[j] = -1;
transfer_replacements (i, j);
}
@@ -5628,12 +6229,13 @@ merge_assigned_reloads (insn)
&& reg_overlap_mentioned_for_reload_p (reload_in[j],
reload_in[i]))
reload_when_needed[j]
- = reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
- ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER;
+ = ((reload_when_needed[i] == RELOAD_FOR_INPUT_ADDRESS
+ || reload_when_needed[i] == RELOAD_FOR_INPADDR_ADDRESS)
+ ? RELOAD_FOR_OTHER_ADDRESS : RELOAD_OTHER);
}
}
}
-#endif /* SMALL_RELOAD_CLASSES */
+
/* Output insns to reload values in and out of the chosen reload regs. */
@@ -5646,20 +6248,28 @@ emit_reload_insns (insn)
rtx other_input_address_reload_insns = 0;
rtx other_input_reload_insns = 0;
rtx input_address_reload_insns[MAX_RECOG_OPERANDS];
+ rtx inpaddr_address_reload_insns[MAX_RECOG_OPERANDS];
rtx output_reload_insns[MAX_RECOG_OPERANDS];
rtx output_address_reload_insns[MAX_RECOG_OPERANDS];
+ rtx outaddr_address_reload_insns[MAX_RECOG_OPERANDS];
rtx operand_reload_insns = 0;
rtx other_operand_reload_insns = 0;
- rtx other_output_reload_insns = 0;
+ rtx other_output_reload_insns[MAX_RECOG_OPERANDS];
rtx following_insn = NEXT_INSN (insn);
rtx before_insn = insn;
int special;
/* Values to be put in spill_reg_store are put here first. */
rtx new_spill_reg_store[FIRST_PSEUDO_REGISTER];
+ HARD_REG_SET reg_reloaded_died;
+
+ CLEAR_HARD_REG_SET (reg_reloaded_died);
for (j = 0; j < reload_n_operands; j++)
input_reload_insns[j] = input_address_reload_insns[j]
- = output_reload_insns[j] = output_address_reload_insns[j] = 0;
+ = inpaddr_address_reload_insns[j]
+ = output_reload_insns[j] = output_address_reload_insns[j]
+ = outaddr_address_reload_insns[j]
+ = other_output_reload_insns[j] = 0;
/* Now output the instructions to copy the data into and out of the
reload registers. Do these in the order that the reloads were reported,
@@ -5670,6 +6280,8 @@ emit_reload_insns (insn)
{
register rtx old;
rtx oldequiv_reg = 0;
+ rtx this_reload_insn = 0;
+ int expect_occurrences = 1;
if (reload_spill_index[j] >= 0)
new_spill_reg_store[reload_spill_index[j]] = 0;
@@ -5789,15 +6401,15 @@ emit_reload_insns (insn)
&& ((REGNO_REG_CLASS (regno) != reload_reg_class[j]
&& (REGISTER_MOVE_COST (REGNO_REG_CLASS (regno),
reload_reg_class[j])
- >= MEMORY_MOVE_COST (mode)))
+ >= MEMORY_MOVE_COST (mode, reload_reg_class[j], 1)))
#ifdef SECONDARY_INPUT_RELOAD_CLASS
|| (SECONDARY_INPUT_RELOAD_CLASS (reload_reg_class[j],
mode, oldequiv)
!= NO_REGS)
#endif
#ifdef SECONDARY_MEMORY_NEEDED
- || SECONDARY_MEMORY_NEEDED (reload_reg_class[j],
- REGNO_REG_CLASS (regno),
+ || SECONDARY_MEMORY_NEEDED (REGNO_REG_CLASS (regno),
+ reload_reg_class[j],
mode)
#endif
))
@@ -5817,14 +6429,12 @@ emit_reload_insns (insn)
if (optimize && GET_CODE (oldequiv) == REG
&& REGNO (oldequiv) < FIRST_PSEUDO_REGISTER
- && spill_reg_order[REGNO (oldequiv)] >= 0
- && spill_reg_store[spill_reg_order[REGNO (oldequiv)]] != 0
- && find_reg_note (insn, REG_DEAD, reload_in[j])
+ && spill_reg_store[REGNO (oldequiv)]
+ && GET_CODE (old) == REG && dead_or_set_p (insn, old)
/* This is unsafe if operand occurs more than once in current
insn. Perhaps some occurrences weren't reloaded. */
- && count_occurrences (PATTERN (insn), reload_in[j]) == 1)
- delete_output_reload
- (insn, j, spill_reg_store[spill_reg_order[REGNO (oldequiv)]]);
+ && count_occurrences (PATTERN (insn), old) == 1)
+ delete_output_reload (insn, j, spill_reg_store[REGNO (oldequiv)]);
/* Encapsulate both RELOADREG and OLDEQUIV into that mode,
then load RELOADREG from OLDEQUIV. Note that we cannot use
@@ -5833,12 +6443,12 @@ emit_reload_insns (insn)
must always be a REG here. */
if (GET_MODE (reloadreg) != mode)
- reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
+ reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode)
oldequiv = SUBREG_REG (oldequiv);
if (GET_MODE (oldequiv) != VOIDmode
&& mode != GET_MODE (oldequiv))
- oldequiv = gen_rtx (SUBREG, mode, oldequiv, 0);
+ oldequiv = gen_rtx_SUBREG (mode, oldequiv, 0);
/* Switch to the right place to emit the reload insns. */
switch (reload_when_needed[j])
@@ -5852,9 +6462,15 @@ emit_reload_insns (insn)
case RELOAD_FOR_INPUT_ADDRESS:
where = &input_address_reload_insns[reload_opnum[j]];
break;
+ case RELOAD_FOR_INPADDR_ADDRESS:
+ where = &inpaddr_address_reload_insns[reload_opnum[j]];
+ break;
case RELOAD_FOR_OUTPUT_ADDRESS:
where = &output_address_reload_insns[reload_opnum[j]];
break;
+ case RELOAD_FOR_OUTADDR_ADDRESS:
+ where = &outaddr_address_reload_insns[reload_opnum[j]];
+ break;
case RELOAD_FOR_OPERAND_ADDRESS:
where = &operand_reload_insns;
break;
@@ -5923,8 +6539,8 @@ emit_reload_insns (insn)
SET_DEST (PATTERN (temp)) = reloadreg;
/* If these are the only uses of the pseudo reg,
pretend for GDB it lives in the reload reg we used. */
- if (reg_n_deaths[REGNO (old)] == 1
- && reg_n_sets[REGNO (old)] == 1)
+ if (REG_N_DEATHS (REGNO (old)) == 1
+ && REG_N_SETS (REGNO (old)) == 1)
{
reg_renumber[REGNO (old)] = REGNO (reload_reg_rtx[j]);
alter_reg (REGNO (old), -1);
@@ -6015,8 +6631,8 @@ emit_reload_insns (insn)
oldequiv = old, real_oldequiv = real_old;
else
second_reload_reg
- = gen_rtx (REG, new_mode,
- REGNO (second_reload_reg));
+ = gen_rtx_REG (new_mode,
+ REGNO (second_reload_reg));
}
}
}
@@ -6083,20 +6699,34 @@ emit_reload_insns (insn)
&& reg_overlap_mentioned_for_reload_p (second_reload_reg,
PATTERN (prev)))
{
- REG_NOTES (prev) = gen_rtx (EXPR_LIST, REG_DEAD,
- second_reload_reg,
- REG_NOTES (prev));
+ REG_NOTES (prev) = gen_rtx_EXPR_LIST (REG_DEAD,
+ second_reload_reg,
+ REG_NOTES (prev));
break;
}
}
#endif
}
+ this_reload_insn = get_last_insn ();
/* End this sequence. */
*where = get_insns ();
end_sequence ();
}
+ /* When inheriting a wider reload, we have a MEM in reload_in[j],
+ e.g. inheriting a SImode output reload for
+ (mem:HI (plus:SI (reg:SI 14 fp) (const_int 10))) */
+ if (optimize && reload_inherited[j] && reload_in[j]
+ && GET_CODE (reload_in[j]) == MEM
+ && reload_spill_index[j] >= 0
+ && TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
+ {
+ expect_occurrences
+ = count_occurrences (PATTERN (insn), reload_in[j]) == 1 ? 0 : -1;
+ reload_in[j]
+ = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
+ }
/* Add a note saying the input reload reg
dies in this insn, if anyone cares. */
#ifdef PRESERVE_DEATH_INFO_REGNO_P
@@ -6125,8 +6755,8 @@ emit_reload_insns (insn)
|| reload_when_needed[j] == RELOAD_FOR_INPUT)
&& ! dead_or_set_p (insn, reloadreg))
REG_NOTES (insn)
- = gen_rtx (EXPR_LIST, REG_DEAD,
- reloadreg, REG_NOTES (insn));
+ = gen_rtx_EXPR_LIST (REG_DEAD,
+ reloadreg, REG_NOTES (insn));
}
/* When we inherit a reload, the last marked death of the reload reg
@@ -6198,9 +6828,9 @@ emit_reload_insns (insn)
&& reg_overlap_mentioned_for_reload_p (oldequiv_reg,
PATTERN (prev1)))
{
- REG_NOTES (prev1) = gen_rtx (EXPR_LIST, REG_DEAD,
- oldequiv_reg,
- REG_NOTES (prev1));
+ REG_NOTES (prev1) = gen_rtx_EXPR_LIST (REG_DEAD,
+ oldequiv_reg,
+ REG_NOTES (prev1));
break;
}
remove_death (REGNO (oldequiv_reg), prev);
@@ -6225,12 +6855,13 @@ emit_reload_insns (insn)
#endif
&& spill_reg_store[reload_spill_index[j]] != 0
/* This is unsafe if some other reload uses the same reg first. */
- && reload_reg_free_before_p (spill_regs[reload_spill_index[j]],
+ && reload_reg_free_before_p (reload_spill_index[j],
reload_opnum[j], reload_when_needed[j])
&& dead_or_set_p (insn, reload_in[j])
/* This is unsafe if operand occurs more than once in current
insn. Perhaps some occurrences weren't reloaded. */
- && count_occurrences (PATTERN (insn), reload_in[j]) == 1)
+ && (count_occurrences (PATTERN (insn), reload_in[j])
+ == expect_occurrences))
delete_output_reload (insn, j,
spill_reg_store[reload_spill_index[j]]);
@@ -6246,7 +6877,9 @@ emit_reload_insns (insn)
&& reload_reg_rtx[j] != 0)
{
register rtx reloadreg = reload_reg_rtx[j];
+#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
register rtx second_reloadreg = 0;
+#endif
rtx note, p;
enum machine_mode mode;
int special = 0;
@@ -6307,11 +6940,11 @@ emit_reload_insns (insn)
error_for_asm (insn, "output operand is constant in `asm'");
/* Prevent crash--use something we know is valid. */
mode = word_mode;
- old = gen_rtx (REG, mode, REGNO (reloadreg));
+ old = gen_rtx_REG (mode, REGNO (reloadreg));
}
if (GET_MODE (reloadreg) != mode)
- reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
+ reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
@@ -6352,7 +6985,7 @@ emit_reload_insns (insn)
= reload_secondary_out_icode[secondary_reload];
if (GET_MODE (reloadreg) != mode)
- reloadreg = gen_rtx (REG, mode, REGNO (reloadreg));
+ reloadreg = gen_rtx_REG (mode, REGNO (reloadreg));
if (tertiary_icode != CODE_FOR_nothing)
{
@@ -6395,8 +7028,20 @@ emit_reload_insns (insn)
/* Output the last reload insn. */
if (! special)
- gen_reload (old, reloadreg, reload_opnum[j],
- reload_when_needed[j]);
+ {
+ rtx set;
+
+ /* Don't output the last reload if OLD is not the dest of
+ INSN and is in the src and is clobbered by INSN. */
+ if (! flag_expensive_optimizations
+ || GET_CODE (old) != REG
+ || !(set = single_set (insn))
+ || rtx_equal_p (old, SET_DEST (set))
+ || !reg_mentioned_p (old, SET_SRC (set))
+ || !regno_clobbered_p (REGNO (old), insn))
+ gen_reload (old, reloadreg, reload_opnum[j],
+ reload_when_needed[j]);
+ }
#ifdef PRESERVE_DEATH_INFO_REGNO_P
/* If final will look at death notes for this reg,
@@ -6407,40 +7052,83 @@ emit_reload_insns (insn)
if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
&& reg_overlap_mentioned_for_reload_p (reloadreg,
PATTERN (p)))
- REG_NOTES (p) = gen_rtx (EXPR_LIST, REG_DEAD,
- reloadreg, REG_NOTES (p));
+ REG_NOTES (p) = gen_rtx_EXPR_LIST (REG_DEAD,
+ reloadreg, REG_NOTES (p));
#ifdef SECONDARY_OUTPUT_RELOAD_CLASS
- if (! special
+ if (! special && second_reloadreg
&& PRESERVE_DEATH_INFO_REGNO_P (REGNO (second_reloadreg)))
for (p = get_last_insn (); p; p = PREV_INSN (p))
if (GET_RTX_CLASS (GET_CODE (p)) == 'i'
&& reg_overlap_mentioned_for_reload_p (second_reloadreg,
PATTERN (p)))
- REG_NOTES (p) = gen_rtx (EXPR_LIST, REG_DEAD,
- second_reloadreg, REG_NOTES (p));
+ REG_NOTES (p) = gen_rtx_EXPR_LIST (REG_DEAD,
+ second_reloadreg,
+ REG_NOTES (p));
#endif
#endif
/* Look at all insns we emitted, just to be safe. */
for (p = get_insns (); p; p = NEXT_INSN (p))
if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
{
+ rtx pat = PATTERN (p);
+
/* If this output reload doesn't come from a spill reg,
clear any memory of reloaded copies of the pseudo reg.
If this output reload comes from a spill reg,
reg_has_output_reload will make this do nothing. */
- note_stores (PATTERN (p), forget_old_reloads_1);
+ note_stores (pat, forget_old_reloads_1);
+
+ if (reg_mentioned_p (reload_reg_rtx[j], pat))
+ {
+ if (reload_spill_index[j] < 0
+ && GET_CODE (pat) == SET
+ && SET_SRC (pat) == reload_reg_rtx[j])
+ {
+ int src = REGNO (SET_SRC (pat));
- if (reg_mentioned_p (reload_reg_rtx[j], PATTERN (p))
- && reload_spill_index[j] >= 0)
- new_spill_reg_store[reload_spill_index[j]] = p;
+ reload_spill_index[j] = src;
+ SET_HARD_REG_BIT (reg_is_output_reload, src);
+ if (find_regno_note (insn, REG_DEAD, src))
+ SET_HARD_REG_BIT (reg_reloaded_died, src);
+ }
+ if (reload_spill_index[j] >= 0)
+ {
+ int s = reload_secondary_out_reload[j];
+ rtx set = single_set (p);
+ /* If this reload copies only to the secondary reload
+ register, the secondary reload does the actual
+ store. */
+ if (s >= 0 && set == NULL_RTX)
+ ; /* We can't tell what function the secondary reload
+ has and where the actual store to the pseudo is
+ made; leave new_spill_reg_store alone. */
+ else if (s >= 0
+ && SET_SRC (set) == reload_reg_rtx[j]
+ && SET_DEST (set) == reload_reg_rtx[s])
+ {
+ /* Usually the next instruction will be the
+ secondary reload insn; if we can confirm
+ that it is, setting new_spill_reg_store to
+ that insn will allow an extra optimization. */
+ rtx s_reg = reload_reg_rtx[s];
+ rtx next = NEXT_INSN (p);
+ reload_out[s] = reload_out[j];
+ set = single_set (next);
+ if (set && SET_SRC (set) == s_reg
+ && ! new_spill_reg_store[REGNO (s_reg)])
+ new_spill_reg_store[REGNO (s_reg)] = next;
+ }
+ else
+ new_spill_reg_store[reload_spill_index[j]] = p;
+ }
+ }
}
if (reload_when_needed[j] == RELOAD_OTHER)
{
- if (other_output_reload_insns)
- emit_insns (other_output_reload_insns);
- other_output_reload_insns = get_insns ();
+ emit_insns (other_output_reload_insns[reload_opnum[j]]);
+ other_output_reload_insns[reload_opnum[j]] = get_insns ();
}
else
output_reload_insns[reload_opnum[j]] = get_insns ();
@@ -6455,10 +7143,11 @@ emit_reload_insns (insn)
RELOAD_FOR_OTHER_ADDRESS reloads for input addresses.
- RELOAD_OTHER reloads, output in ascending order by reload number.
+ RELOAD_OTHER reloads.
- For each operand, any RELOAD_FOR_INPUT_ADDRESS reloads followed by
- the RELOAD_FOR_INPUT reload for the operand.
+ For each operand, any RELOAD_FOR_INPADDR_ADDRESS reloads followed
+ by any RELOAD_FOR_INPUT_ADDRESS reloads followed by the
+ RELOAD_FOR_INPUT reload for the operand.
RELOAD_FOR_OPADDR_ADDRS reloads.
@@ -6466,17 +7155,18 @@ emit_reload_insns (insn)
After the insn being reloaded, we write the following:
- For each operand, any RELOAD_FOR_OUTPUT_ADDRESS reload followed by
- the RELOAD_FOR_OUTPUT reload for that operand.
-
- Any RELOAD_OTHER output reloads, output in descending order by
- reload number. */
+ For each operand, any RELOAD_FOR_OUTADDR_ADDRESS reloads followed
+ by any RELOAD_FOR_OUTPUT_ADDRESS reload followed by the
+ RELOAD_FOR_OUTPUT reload, followed by any RELOAD_OTHER output
+ reloads for the operand. The RELOAD_OTHER output reloads are
+ output in descending order by reload number. */
emit_insns_before (other_input_address_reload_insns, before_insn);
emit_insns_before (other_input_reload_insns, before_insn);
for (j = 0; j < reload_n_operands; j++)
{
+ emit_insns_before (inpaddr_address_reload_insns[j], before_insn);
emit_insns_before (input_address_reload_insns[j], before_insn);
emit_insns_before (input_reload_insns[j], before_insn);
}
@@ -6486,12 +7176,12 @@ emit_reload_insns (insn)
for (j = 0; j < reload_n_operands; j++)
{
+ emit_insns_before (outaddr_address_reload_insns[j], following_insn);
emit_insns_before (output_address_reload_insns[j], following_insn);
emit_insns_before (output_reload_insns[j], following_insn);
+ emit_insns_before (other_output_reload_insns[j], following_insn);
}
- emit_insns_before (other_output_reload_insns, following_insn);
-
/* Move death notes from INSN
to output-operand-address and output reload insns. */
#ifdef PRESERVE_DEATH_INFO_REGNO_P
@@ -6548,109 +7238,137 @@ emit_reload_insns (insn)
register int r = reload_order[j];
register int i = reload_spill_index[r];
- /* I is nonneg if this reload used one of the spill regs.
+ /* I is nonneg if this reload used a register.
If reload_reg_rtx[r] is 0, this is an optional reload
- that we opted to ignore.
-
- Also ignore reloads that don't reach the end of the insn,
- since we will eventually see the one that does. */
+ that we opted to ignore. */
- if (i >= 0 && reload_reg_rtx[r] != 0
- && reload_reg_reaches_end_p (spill_regs[i], reload_opnum[r],
- reload_when_needed[r]))
+ if (i >= 0 && reload_reg_rtx[r] != 0)
{
- /* First, clear out memory of what used to be in this spill reg.
- If consecutive registers are used, clear them all. */
int nr
- = HARD_REGNO_NREGS (spill_regs[i], GET_MODE (reload_reg_rtx[r]));
+ = HARD_REGNO_NREGS (i, GET_MODE (reload_reg_rtx[r]));
int k;
+ int part_reaches_end = 0;
+ int all_reaches_end = 1;
+ /* For a multi register reload, we need to check if all or part
+ of the value lives to the end. */
for (k = 0; k < nr; k++)
{
- reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]] = -1;
- reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = 0;
+ if (reload_reg_reaches_end_p (i + k, reload_opnum[r],
+ reload_when_needed[r]))
+ part_reaches_end = 1;
+ else
+ all_reaches_end = 0;
}
- /* Maybe the spill reg contains a copy of reload_out. */
- if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
+ /* Ignore reloads that don't reach the end of the insn in
+ entirety. */
+ if (all_reaches_end)
{
- register int nregno = REGNO (reload_out[r]);
- int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
- : HARD_REGNO_NREGS (nregno,
- GET_MODE (reload_reg_rtx[r])));
-
- spill_reg_store[i] = new_spill_reg_store[i];
- reg_last_reload_reg[nregno] = reload_reg_rtx[r];
-
- /* If NREGNO is a hard register, it may occupy more than
- one register. If it does, say what is in the
- rest of the registers assuming that both registers
- agree on how many words the object takes. If not,
- invalidate the subsequent registers. */
-
- if (nregno < FIRST_PSEUDO_REGISTER)
- for (k = 1; k < nnr; k++)
- reg_last_reload_reg[nregno + k]
- = (nr == nnr ? gen_rtx (REG,
- reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
- REGNO (reload_reg_rtx[r]) + k)
- : 0);
+ /* First, clear out memory of what used to be in this spill reg.
+ If consecutive registers are used, clear them all. */
- /* Now do the inverse operation. */
for (k = 0; k < nr; k++)
+ CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k);
+
+ /* Maybe the spill reg contains a copy of reload_out. */
+ if (reload_out[r] != 0 && GET_CODE (reload_out[r]) == REG)
{
- reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
- = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
- : nregno + k);
- reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]] = insn;
+ register int nregno = REGNO (reload_out[r]);
+ int nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (nregno,
+ GET_MODE (reload_reg_rtx[r])));
+
+ spill_reg_store[i] = new_spill_reg_store[i];
+ reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+
+ /* If NREGNO is a hard register, it may occupy more than
+ one register. If it does, say what is in the
+ rest of the registers assuming that both registers
+ agree on how many words the object takes. If not,
+ invalidate the subsequent registers. */
+
+ if (nregno < FIRST_PSEUDO_REGISTER)
+ for (k = 1; k < nnr; k++)
+ reg_last_reload_reg[nregno + k]
+ = (nr == nnr
+ ? gen_rtx_REG (reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
+ REGNO (reload_reg_rtx[r]) + k)
+ : 0);
+
+ /* Now do the inverse operation. */
+ for (k = 0; k < nr; k++)
+ {
+ CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
+ reg_reloaded_contents[i + k]
+ = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+ ? nregno
+ : nregno + k);
+ reg_reloaded_insn[i + k] = insn;
+ SET_HARD_REG_BIT (reg_reloaded_valid, i + k);
+ }
}
- }
-
- /* Maybe the spill reg contains a copy of reload_in. Only do
- something if there will not be an output reload for
- the register being reloaded. */
- else if (reload_out[r] == 0
- && reload_in[r] != 0
- && ((GET_CODE (reload_in[r]) == REG
- && ! reg_has_output_reload[REGNO (reload_in[r])]
- || (GET_CODE (reload_in_reg[r]) == REG
- && ! reg_has_output_reload[REGNO (reload_in_reg[r])]))))
- {
- register int nregno;
- int nnr;
-
- if (GET_CODE (reload_in[r]) == REG)
- nregno = REGNO (reload_in[r]);
- else
- nregno = REGNO (reload_in_reg[r]);
-
- nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
- : HARD_REGNO_NREGS (nregno,
- GET_MODE (reload_reg_rtx[r])));
- reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+ /* Maybe the spill reg contains a copy of reload_in. Only do
+ something if there will not be an output reload for
+ the register being reloaded. */
+ else if (reload_out[r] == 0
+ && reload_in[r] != 0
+ && spill_reg_order[i] >= 0
+ && ((GET_CODE (reload_in[r]) == REG
+ && ! reg_has_output_reload[REGNO (reload_in[r])])
+ || (GET_CODE (reload_in_reg[r]) == REG
+ && ! reg_has_output_reload[REGNO (reload_in_reg[r])])))
+ {
+ register int nregno;
+ int nnr;
- if (nregno < FIRST_PSEUDO_REGISTER)
- for (k = 1; k < nnr; k++)
- reg_last_reload_reg[nregno + k]
- = (nr == nnr ? gen_rtx (REG,
- reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
- REGNO (reload_reg_rtx[r]) + k)
- : 0);
+ if (GET_CODE (reload_in[r]) == REG)
+ nregno = REGNO (reload_in[r]);
+ else
+ nregno = REGNO (reload_in_reg[r]);
- /* Unless we inherited this reload, show we haven't
- recently done a store. */
- if (! reload_inherited[r])
- spill_reg_store[i] = 0;
+ nnr = (nregno >= FIRST_PSEUDO_REGISTER ? 1
+ : HARD_REGNO_NREGS (nregno,
+ GET_MODE (reload_reg_rtx[r])));
+
+ reg_last_reload_reg[nregno] = reload_reg_rtx[r];
+
+ if (nregno < FIRST_PSEUDO_REGISTER)
+ for (k = 1; k < nnr; k++)
+ reg_last_reload_reg[nregno + k]
+ = (nr == nnr
+ ? gen_rtx_REG (reg_raw_mode[REGNO (reload_reg_rtx[r]) + k],
+ REGNO (reload_reg_rtx[r]) + k)
+ : 0);
+
+ /* Unless we inherited this reload, show we haven't
+ recently done a store. */
+ if (! reload_inherited[r])
+ spill_reg_store[i] = 0;
+
+ for (k = 0; k < nr; k++)
+ {
+ CLEAR_HARD_REG_BIT (reg_reloaded_dead, i + k);
+ reg_reloaded_contents[i + k]
+ = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr
+ ? nregno
+ : nregno + k);
+ reg_reloaded_insn[i + k] = insn;
+ SET_HARD_REG_BIT (reg_reloaded_valid, i + k);
+ }
+ }
+ }
+ /* However, if part of the reload reaches the end, then we must
+ invalidate the old info for the part that survives to the end. */
+ else if (part_reaches_end)
+ {
for (k = 0; k < nr; k++)
- {
- reg_reloaded_contents[spill_reg_order[spill_regs[i] + k]]
- = (nregno >= FIRST_PSEUDO_REGISTER || nr != nnr ? nregno
- : nregno + k);
- reg_reloaded_insn[spill_reg_order[spill_regs[i] + k]]
- = insn;
- }
+ if (reload_reg_reaches_end_p (i + k,
+ reload_opnum[r],
+ reload_when_needed[r]))
+ CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k);
}
}
@@ -6676,6 +7394,7 @@ emit_reload_insns (insn)
}
}
}
+ IOR_HARD_REG_SET (reg_reloaded_dead, reg_reloaded_died);
}
/* Emit code to perform a reload from IN (which may be a reload register) to
@@ -6735,8 +7454,10 @@ gen_reload (out, in, opnum, type)
if (GET_CODE (in) == PLUS
&& (GET_CODE (XEXP (in, 0)) == REG
+ || GET_CODE (XEXP (in, 0)) == SUBREG
|| GET_CODE (XEXP (in, 0)) == MEM)
&& (GET_CODE (XEXP (in, 1)) == REG
+ || GET_CODE (XEXP (in, 1)) == SUBREG
|| CONSTANT_P (XEXP (in, 1))
|| GET_CODE (XEXP (in, 1)) == MEM))
{
@@ -6764,16 +7485,16 @@ gen_reload (out, in, opnum, type)
if the add instruction is two-address and the second operand
of the add is the same as the reload reg, which is frequently
the case. If the insn would be A = B + A, rearrange it so
- it will be A = A + B as constrain_operands expects. */
+ it will be A = A + B as constrain_operands expects. */
if (GET_CODE (XEXP (in, 1)) == REG
&& REGNO (out) == REGNO (XEXP (in, 1)))
tem = op0, op0 = op1, op1 = tem;
if (op0 != XEXP (in, 0) || op1 != XEXP (in, 1))
- in = gen_rtx (PLUS, GET_MODE (in), op0, op1);
+ in = gen_rtx_PLUS (GET_MODE (in), op0, op1);
- insn = emit_insn (gen_rtx (SET, VOIDmode, out, in));
+ insn = emit_insn (gen_rtx_SET (VOIDmode, out, in));
code = recog_memoized (insn);
if (code >= 0)
@@ -6797,12 +7518,12 @@ gen_reload (out, in, opnum, type)
DEFINE_PEEPHOLE should be specified that recognizes the sequence
we emit below. */
- if (CONSTANT_P (op1) || GET_CODE (op1) == MEM
+ if (CONSTANT_P (op1) || GET_CODE (op1) == MEM || GET_CODE (op1) == SUBREG
|| (GET_CODE (op1) == REG
&& REGNO (op1) >= FIRST_PSEUDO_REGISTER))
tem = op0, op0 = op1, op1 = tem;
- emit_insn (gen_move_insn (out, op0));
+ gen_reload (out, op0, opnum, type);
/* If OP0 and OP1 are the same, we can use OUT for OP1.
This fixes a problem on the 32K where the stack pointer cannot
@@ -6814,7 +7535,7 @@ gen_reload (out, in, opnum, type)
insn = emit_insn (gen_add2_insn (out, op1));
/* If that failed, copy the address register to the reload register.
- Then add the constant to the reload register. */
+ Then add the constant to the reload register. */
code = recog_memoized (insn);
@@ -6825,13 +7546,19 @@ gen_reload (out, in, opnum, type)
its validity determination, i.e., the way it would after reload
has completed. */
if (constrain_operands (code, 1))
- return insn;
+ {
+ /* Add a REG_EQUIV note so that find_equiv_reg can find it. */
+ REG_NOTES (insn)
+ = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn));
+ return insn;
+ }
}
delete_insns_since (last);
- emit_insn (gen_move_insn (out, op1));
- emit_insn (gen_add2_insn (out, op0));
+ gen_reload (out, op1, opnum, type);
+ insn = emit_insn (gen_add2_insn (out, op0));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUIV, in, REG_NOTES (insn));
}
#ifdef SECONDARY_MEMORY_NEEDED
@@ -6846,13 +7573,13 @@ gen_reload (out, in, opnum, type)
rtx loc = get_secondary_mem (in, GET_MODE (out), opnum, type);
if (GET_MODE (loc) != GET_MODE (out))
- out = gen_rtx (REG, GET_MODE (loc), REGNO (out));
+ out = gen_rtx_REG (GET_MODE (loc), REGNO (out));
if (GET_MODE (loc) != GET_MODE (in))
- in = gen_rtx (REG, GET_MODE (loc), REGNO (in));
+ in = gen_rtx_REG (GET_MODE (loc), REGNO (in));
- emit_insn (gen_move_insn (loc, in));
- emit_insn (gen_move_insn (out, loc));
+ gen_reload (loc, in, opnum, type);
+ gen_reload (out, loc, opnum, type);
}
#endif
@@ -6867,7 +7594,7 @@ gen_reload (out, in, opnum, type)
/* Otherwise, just write (set OUT IN) and hope for the best. */
else
- emit_insn (gen_rtx (SET, VOIDmode, out, in));
+ emit_insn (gen_rtx_SET (VOIDmode, out, in));
/* Return the first insn emitted.
We can not just return get_last_insn, because there may have
@@ -6912,23 +7639,40 @@ delete_output_reload (insn, j, output_reload_insn)
return;
if ((GET_CODE (i1) == INSN || GET_CODE (i1) == CALL_INSN)
&& reg_mentioned_p (reg, PATTERN (i1)))
- return;
+ {
+ /* If this is just a single USE with an REG_EQUAL note in front
+ of INSN, this is no problem, because this mentions just the
+ address that we are using here.
+ But if there is more than one such USE, the insn might use
+ the operand directly, or another reload might do that.
+ This is analogous to the count_occurences check in the callers. */
+ int num_occurences = 0;
+
+ while (GET_CODE (i1) == INSN && GET_CODE (PATTERN (i1)) == USE
+ && find_reg_note (i1, REG_EQUAL, NULL_RTX))
+ {
+ num_occurences += rtx_equal_p (reg, XEXP (PATTERN (i1), 0)) != 0;
+ i1 = NEXT_INSN (i1);
+ }
+ if (num_occurences == 1 && i1 == insn)
+ break;
+ return;
+ }
}
- if (cannot_omit_stores[REGNO (reg)])
- return;
-
- /* If this insn will store in the pseudo again,
- the previous store can be removed. */
- if (reload_out[j] == reload_in[j])
- delete_insn (output_reload_insn);
-
- /* See if the pseudo reg has been completely replaced
+ /* The caller has already checked that REG dies or is set in INSN.
+ It has also checked that we are optimizing, and thus some inaccurancies
+ in the debugging information are acceptable.
+ So we could just delete output_reload_insn.
+ But in some cases we can improve the debugging information without
+ sacrificing optimization - maybe even improving the code:
+ See if the pseudo reg has been completely replaced
with reload regs. If so, delete the store insn
and forget we had a stack slot for the pseudo. */
- else if (reg_n_deaths[REGNO (reg)] == 1
- && reg_basic_block[REGNO (reg)] >= 0
- && find_regno_note (insn, REG_DEAD, REGNO (reg)))
+ if (reload_out[j] != reload_in[j]
+ && REG_N_DEATHS (REGNO (reg)) == 1
+ && REG_BASIC_BLOCK (REGNO (reg)) >= 0
+ && find_regno_note (insn, REG_DEAD, REGNO (reg)))
{
rtx i2;
@@ -6950,9 +7694,12 @@ delete_output_reload (insn, j, output_reload_insn)
break;
if ((GET_CODE (i2) == INSN || GET_CODE (i2) == CALL_INSN)
&& reg_mentioned_p (reg, PATTERN (i2)))
- /* Some other ref remains;
- we can't do anything. */
- return;
+ {
+ /* Some other ref remains; just delete the output reload we
+ know to be dead. */
+ delete_insn (output_reload_insn);
+ return;
+ }
}
/* Delete the now-dead stores into this pseudo. */
@@ -6961,7 +7708,13 @@ delete_output_reload (insn, j, output_reload_insn)
rtx set = single_set (i2);
if (set != 0 && SET_DEST (set) == reg)
- delete_insn (i2);
+ {
+ /* This might be a basic block head,
+ thus don't use delete_insn. */
+ PUT_CODE (i2, NOTE);
+ NOTE_SOURCE_FILE (i2) = 0;
+ NOTE_LINE_NUMBER (i2) = NOTE_INSN_DELETED;
+ }
if (GET_CODE (i2) == CODE_LABEL
|| GET_CODE (i2) == JUMP_INSN)
break;
@@ -6972,6 +7725,8 @@ delete_output_reload (insn, j, output_reload_insn)
reg_renumber[REGNO (reg)] = REGNO (reload_reg_rtx[j]);
alter_reg (REGNO (reg), -1);
}
+ delete_insn (output_reload_insn);
+
}
/* Output reload-insns to reload VALUE into RELOADREG.
@@ -7017,9 +7772,9 @@ inc_for_reload (reloadreg, value, inc_amount)
in gen_reload. */
last = get_last_insn ();
- add_insn = emit_insn (gen_rtx (SET, VOIDmode, incloc,
- gen_rtx (PLUS, GET_MODE (incloc),
- incloc, inc)));
+ add_insn = emit_insn (gen_rtx_SET (VOIDmode, incloc,
+ gen_rtx_PLUS (GET_MODE (incloc),
+ incloc, inc)));
code = recog_memoized (add_insn);
if (code >= 0)
@@ -7118,7 +7873,7 @@ constraint_accepts_reg_p (string, reg)
/* Return the number of places FIND appears within X, but don't count
an occurrence if some SET_DEST is FIND. */
-static int
+int
count_occurrences (x, find)
register rtx x, find;
{
@@ -7150,6 +7905,9 @@ count_occurrences (x, find)
if (SET_DEST (x) == find)
return count_occurrences (SET_SRC (x), find);
break;
+
+ default:
+ break;
}
format_ptr = GET_RTX_FORMAT (code);
@@ -7174,3 +7932,1073 @@ count_occurrences (x, find)
}
return count;
}
+
+/* This array holds values which are equivalent to a hard register
+ during reload_cse_regs. Each array element is an EXPR_LIST of
+ values. Each time a hard register is set, we set the corresponding
+ array element to the value. Each time a hard register is copied
+ into memory, we add the memory location to the corresponding array
+ element. We don't store values or memory addresses with side
+ effects in this array.
+
+ If the value is a CONST_INT, then the mode of the containing
+ EXPR_LIST is the mode in which that CONST_INT was referenced.
+
+ We sometimes clobber a specific entry in a list. In that case, we
+ just set XEXP (list-entry, 0) to 0. */
+
+static rtx *reg_values;
+
+/* This is a preallocated REG rtx which we use as a temporary in
+ reload_cse_invalidate_regno, so that we don't need to allocate a
+ new one each time through a loop in that function. */
+
+static rtx invalidate_regno_rtx;
+
+/* This is a set of registers for which we must remove REG_DEAD notes in
+ previous insns, because our modifications made them invalid. That can
+ happen if we introduced the register into the current insn, or we deleted
+ the current insn which used to set the register. */
+
+static HARD_REG_SET no_longer_dead_regs;
+
+/* Invalidate any entries in reg_values which depend on REGNO,
+ including those for REGNO itself. This is called if REGNO is
+ changing. If CLOBBER is true, then always forget anything we
+ currently know about REGNO. MODE is the mode of the assignment to
+ REGNO, which is used to determine how many hard registers are being
+ changed. If MODE is VOIDmode, then only REGNO is being changed;
+ this is used when invalidating call clobbered registers across a
+ call. */
+
+static void
+reload_cse_invalidate_regno (regno, mode, clobber)
+ int regno;
+ enum machine_mode mode;
+ int clobber;
+{
+ int endregno;
+ register int i;
+
+ /* Our callers don't always go through true_regnum; we may see a
+ pseudo-register here from a CLOBBER or the like. We probably
+ won't ever see a pseudo-register that has a real register number,
+ for we check anyhow for safety. */
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ regno = reg_renumber[regno];
+ if (regno < 0)
+ return;
+
+ if (mode == VOIDmode)
+ endregno = regno + 1;
+ else
+ endregno = regno + HARD_REGNO_NREGS (regno, mode);
+
+ if (clobber)
+ for (i = regno; i < endregno; i++)
+ reg_values[i] = 0;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ rtx x;
+
+ for (x = reg_values[i]; x; x = XEXP (x, 1))
+ {
+ if (XEXP (x, 0) != 0
+ && refers_to_regno_p (regno, endregno, XEXP (x, 0), NULL_PTR))
+ {
+ /* If this is the only entry on the list, clear
+ reg_values[i]. Otherwise, just clear this entry on
+ the list. */
+ if (XEXP (x, 1) == 0 && x == reg_values[i])
+ {
+ reg_values[i] = 0;
+ break;
+ }
+ XEXP (x, 0) = 0;
+ }
+ }
+ }
+
+ /* We must look at earlier registers, in case REGNO is part of a
+ multi word value but is not the first register. If an earlier
+ register has a value in a mode which overlaps REGNO, then we must
+ invalidate that earlier register. Note that we do not need to
+ check REGNO or later registers (we must not check REGNO itself,
+ because we would incorrectly conclude that there was a conflict). */
+
+ for (i = 0; i < regno; i++)
+ {
+ rtx x;
+
+ for (x = reg_values[i]; x; x = XEXP (x, 1))
+ {
+ if (XEXP (x, 0) != 0)
+ {
+ PUT_MODE (invalidate_regno_rtx, GET_MODE (x));
+ REGNO (invalidate_regno_rtx) = i;
+ if (refers_to_regno_p (regno, endregno, invalidate_regno_rtx,
+ NULL_PTR))
+ {
+ reload_cse_invalidate_regno (i, VOIDmode, 1);
+ break;
+ }
+ }
+ }
+ }
+}
+
+/* The memory at address MEM_BASE is being changed.
+ Return whether this change will invalidate VAL. */
+
+static int
+reload_cse_mem_conflict_p (mem_base, val)
+ rtx mem_base;
+ rtx val;
+{
+ enum rtx_code code;
+ char *fmt;
+ int i;
+
+ code = GET_CODE (val);
+ switch (code)
+ {
+ /* Get rid of a few simple cases quickly. */
+ case REG:
+ case PC:
+ case CC0:
+ case SCRATCH:
+ case CONST:
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ case LABEL_REF:
+ return 0;
+
+ case MEM:
+ if (GET_MODE (mem_base) == BLKmode
+ || GET_MODE (val) == BLKmode)
+ return 1;
+ if (anti_dependence (val, mem_base))
+ return 1;
+ /* The address may contain nested MEMs. */
+ break;
+
+ default:
+ break;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e')
+ {
+ if (reload_cse_mem_conflict_p (mem_base, XEXP (val, i)))
+ return 1;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+
+ for (j = 0; j < XVECLEN (val, i); j++)
+ if (reload_cse_mem_conflict_p (mem_base, XVECEXP (val, i, j)))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Invalidate any entries in reg_values which are changed because of a
+ store to MEM_RTX. If this is called because of a non-const call
+ instruction, MEM_RTX is (mem:BLK const0_rtx). */
+
+static void
+reload_cse_invalidate_mem (mem_rtx)
+ rtx mem_rtx;
+{
+ register int i;
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ rtx x;
+
+ for (x = reg_values[i]; x; x = XEXP (x, 1))
+ {
+ if (XEXP (x, 0) != 0
+ && reload_cse_mem_conflict_p (mem_rtx, XEXP (x, 0)))
+ {
+ /* If this is the only entry on the list, clear
+ reg_values[i]. Otherwise, just clear this entry on
+ the list. */
+ if (XEXP (x, 1) == 0 && x == reg_values[i])
+ {
+ reg_values[i] = 0;
+ break;
+ }
+ XEXP (x, 0) = 0;
+ }
+ }
+ }
+}
+
+/* Invalidate DEST, which is being assigned to or clobbered. The
+ second parameter exists so that this function can be passed to
+ note_stores; it is ignored. */
+
+static void
+reload_cse_invalidate_rtx (dest, ignore)
+ rtx dest;
+ rtx ignore ATTRIBUTE_UNUSED;
+{
+ while (GET_CODE (dest) == STRICT_LOW_PART
+ || GET_CODE (dest) == SIGN_EXTRACT
+ || GET_CODE (dest) == ZERO_EXTRACT
+ || GET_CODE (dest) == SUBREG)
+ dest = XEXP (dest, 0);
+
+ if (GET_CODE (dest) == REG)
+ reload_cse_invalidate_regno (REGNO (dest), GET_MODE (dest), 1);
+ else if (GET_CODE (dest) == MEM)
+ reload_cse_invalidate_mem (dest);
+}
+
+/* Possibly delete death notes on the insns before INSN if modifying INSN
+ extended the lifespan of the registers. */
+
+static void
+reload_cse_delete_death_notes (insn)
+ rtx insn;
+{
+ int dreg;
+
+ for (dreg = 0; dreg < FIRST_PSEUDO_REGISTER; dreg++)
+ {
+ rtx trial;
+
+ if (! TEST_HARD_REG_BIT (no_longer_dead_regs, dreg))
+ continue;
+
+ for (trial = prev_nonnote_insn (insn);
+ (trial
+ && GET_CODE (trial) != CODE_LABEL
+ && GET_CODE (trial) != BARRIER);
+ trial = prev_nonnote_insn (trial))
+ {
+ if (find_regno_note (trial, REG_DEAD, dreg))
+ {
+ remove_death (dreg, trial);
+ break;
+ }
+ }
+ }
+}
+
+/* Record that the current insn uses hard reg REGNO in mode MODE. This
+ will be used in reload_cse_delete_death_notes to delete prior REG_DEAD
+ notes for this register. */
+
+static void
+reload_cse_no_longer_dead (regno, mode)
+ int regno;
+ enum machine_mode mode;
+{
+ int nregs = HARD_REGNO_NREGS (regno, mode);
+ while (nregs-- > 0)
+ {
+ SET_HARD_REG_BIT (no_longer_dead_regs, regno);
+ regno++;
+ }
+}
+
+
+/* Do a very simple CSE pass over the hard registers.
+
+ This function detects no-op moves where we happened to assign two
+ different pseudo-registers to the same hard register, and then
+ copied one to the other. Reload will generate a useless
+ instruction copying a register to itself.
+
+ This function also detects cases where we load a value from memory
+ into two different registers, and (if memory is more expensive than
+ registers) changes it to simply copy the first register into the
+ second register.
+
+ Another optimization is performed that scans the operands of each
+ instruction to see whether the value is already available in a
+ hard register. It then replaces the operand with the hard register
+ if possible, much like an optional reload would. */
+
+void
+reload_cse_regs (first)
+ rtx first;
+{
+ char *firstobj;
+ rtx callmem;
+ register int i;
+ rtx insn;
+
+ init_alias_analysis ();
+
+ reg_values = (rtx *) alloca (FIRST_PSEUDO_REGISTER * sizeof (rtx));
+ bzero ((char *)reg_values, FIRST_PSEUDO_REGISTER * sizeof (rtx));
+
+ /* Create our EXPR_LIST structures on reload_obstack, so that we can
+ free them when we are done. */
+ push_obstacks (&reload_obstack, &reload_obstack);
+ firstobj = (char *) obstack_alloc (&reload_obstack, 0);
+
+ /* We pass this to reload_cse_invalidate_mem to invalidate all of
+ memory for a non-const call instruction. */
+ callmem = gen_rtx_MEM (BLKmode, const0_rtx);
+
+ /* This is used in reload_cse_invalidate_regno to avoid consing a
+ new REG in a loop in that function. */
+ invalidate_regno_rtx = gen_rtx_REG (VOIDmode, 0);
+
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ {
+ rtx body;
+
+ if (GET_CODE (insn) == CODE_LABEL)
+ {
+ /* Forget all the register values at a code label. We don't
+ try to do anything clever around jumps. */
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ reg_values[i] = 0;
+
+ continue;
+ }
+
+#ifdef NON_SAVING_SETJMP
+ if (NON_SAVING_SETJMP && GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+ {
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ reg_values[i] = 0;
+
+ continue;
+ }
+#endif
+
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ continue;
+
+ CLEAR_HARD_REG_SET (no_longer_dead_regs);
+
+ /* If this is a call instruction, forget anything stored in a
+ call clobbered register, or, if this is not a const call, in
+ memory. */
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (call_used_regs[i])
+ reload_cse_invalidate_regno (i, VOIDmode, 1);
+
+ if (! CONST_CALL_P (insn))
+ reload_cse_invalidate_mem (callmem);
+ }
+
+ body = PATTERN (insn);
+ if (GET_CODE (body) == SET)
+ {
+ int count = 0;
+ if (reload_cse_noop_set_p (body, insn))
+ {
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ reload_cse_delete_death_notes (insn);
+
+ /* We're done with this insn. */
+ continue;
+ }
+
+ /* It's not a no-op, but we can try to simplify it. */
+ CLEAR_HARD_REG_SET (no_longer_dead_regs);
+ count += reload_cse_simplify_set (body, insn);
+
+ if (count > 0 && apply_change_group ())
+ reload_cse_delete_death_notes (insn);
+ else if (reload_cse_simplify_operands (insn))
+ reload_cse_delete_death_notes (insn);
+
+ reload_cse_record_set (body, body);
+ }
+ else if (GET_CODE (body) == PARALLEL)
+ {
+ int count = 0;
+
+ /* If every action in a PARALLEL is a noop, we can delete
+ the entire PARALLEL. */
+ for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+ if ((GET_CODE (XVECEXP (body, 0, i)) != SET
+ || ! reload_cse_noop_set_p (XVECEXP (body, 0, i), insn))
+ && GET_CODE (XVECEXP (body, 0, i)) != CLOBBER)
+ break;
+ if (i < 0)
+ {
+ PUT_CODE (insn, NOTE);
+ NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
+ NOTE_SOURCE_FILE (insn) = 0;
+ reload_cse_delete_death_notes (insn);
+
+ /* We're done with this insn. */
+ continue;
+ }
+
+ /* It's not a no-op, but we can try to simplify it. */
+ CLEAR_HARD_REG_SET (no_longer_dead_regs);
+ for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+ if (GET_CODE (XVECEXP (body, 0, i)) == SET)
+ count += reload_cse_simplify_set (XVECEXP (body, 0, i), insn);
+
+ if (count > 0 && apply_change_group ())
+ reload_cse_delete_death_notes (insn);
+ else if (reload_cse_simplify_operands (insn))
+ reload_cse_delete_death_notes (insn);
+
+ /* Look through the PARALLEL and record the values being
+ set, if possible. Also handle any CLOBBERs. */
+ for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+ {
+ rtx x = XVECEXP (body, 0, i);
+
+ if (GET_CODE (x) == SET)
+ reload_cse_record_set (x, body);
+ else
+ note_stores (x, reload_cse_invalidate_rtx);
+ }
+ }
+ else
+ note_stores (body, reload_cse_invalidate_rtx);
+
+#ifdef AUTO_INC_DEC
+ /* Clobber any registers which appear in REG_INC notes. We
+ could keep track of the changes to their values, but it is
+ unlikely to help. */
+ {
+ rtx x;
+
+ for (x = REG_NOTES (insn); x; x = XEXP (x, 1))
+ if (REG_NOTE_KIND (x) == REG_INC)
+ reload_cse_invalidate_rtx (XEXP (x, 0), NULL_RTX);
+ }
+#endif
+
+ /* Look for any CLOBBERs in CALL_INSN_FUNCTION_USAGE, but only
+ after we have processed the insn. */
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ rtx x;
+
+ for (x = CALL_INSN_FUNCTION_USAGE (insn); x; x = XEXP (x, 1))
+ if (GET_CODE (XEXP (x, 0)) == CLOBBER)
+ reload_cse_invalidate_rtx (XEXP (XEXP (x, 0), 0), NULL_RTX);
+ }
+ }
+
+ /* Free all the temporary structures we created, and go back to the
+ regular obstacks. */
+ obstack_free (&reload_obstack, firstobj);
+ pop_obstacks ();
+}
+
+/* Return whether the values known for REGNO are equal to VAL. MODE
+ is the mode of the object that VAL is being copied to; this matters
+ if VAL is a CONST_INT. */
+
+static int
+reload_cse_regno_equal_p (regno, val, mode)
+ int regno;
+ rtx val;
+ enum machine_mode mode;
+{
+ rtx x;
+
+ if (val == 0)
+ return 0;
+
+ for (x = reg_values[regno]; x; x = XEXP (x, 1))
+ if (XEXP (x, 0) != 0
+ && rtx_equal_p (XEXP (x, 0), val)
+ && (! flag_float_store || GET_CODE (XEXP (x, 0)) != MEM
+ || GET_MODE_CLASS (GET_MODE (x)) != MODE_FLOAT)
+ && (GET_CODE (val) != CONST_INT
+ || mode == GET_MODE (x)
+ || (GET_MODE_SIZE (mode) < GET_MODE_SIZE (GET_MODE (x))
+ /* On a big endian machine if the value spans more than
+ one register then this register holds the high part of
+ it and we can't use it.
+
+ ??? We should also compare with the high part of the
+ value. */
+ && !(WORDS_BIG_ENDIAN
+ && HARD_REGNO_NREGS (regno, GET_MODE (x)) > 1)
+ && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+ GET_MODE_BITSIZE (GET_MODE (x))))))
+ return 1;
+
+ return 0;
+}
+
+/* See whether a single set is a noop. SET is the set instruction we
+ are should check, and INSN is the instruction from which it came. */
+
+static int
+reload_cse_noop_set_p (set, insn)
+ rtx set;
+ rtx insn;
+{
+ rtx src, dest;
+ enum machine_mode dest_mode;
+ int dreg, sreg;
+ int ret;
+
+ src = SET_SRC (set);
+ dest = SET_DEST (set);
+ dest_mode = GET_MODE (dest);
+
+ if (side_effects_p (src))
+ return 0;
+
+ dreg = true_regnum (dest);
+ sreg = true_regnum (src);
+
+ /* Check for setting a register to itself. In this case, we don't
+ have to worry about REG_DEAD notes. */
+ if (dreg >= 0 && dreg == sreg)
+ return 1;
+
+ ret = 0;
+ if (dreg >= 0)
+ {
+ /* Check for setting a register to itself. */
+ if (dreg == sreg)
+ ret = 1;
+
+ /* Check for setting a register to a value which we already know
+ is in the register. */
+ else if (reload_cse_regno_equal_p (dreg, src, dest_mode))
+ ret = 1;
+
+ /* Check for setting a register DREG to another register SREG
+ where SREG is equal to a value which is already in DREG. */
+ else if (sreg >= 0)
+ {
+ rtx x;
+
+ for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+ {
+ rtx tmp;
+
+ if (XEXP (x, 0) == 0)
+ continue;
+
+ if (dest_mode == GET_MODE (x))
+ tmp = XEXP (x, 0);
+ else if (GET_MODE_BITSIZE (dest_mode)
+ < GET_MODE_BITSIZE (GET_MODE (x)))
+ tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+ else
+ continue;
+
+ if (tmp
+ && reload_cse_regno_equal_p (dreg, tmp, dest_mode))
+ {
+ ret = 1;
+ break;
+ }
+ }
+ }
+ }
+ else if (GET_CODE (dest) == MEM)
+ {
+ /* Check for storing a register to memory when we know that the
+ register is equivalent to the memory location. */
+ if (sreg >= 0
+ && reload_cse_regno_equal_p (sreg, dest, dest_mode)
+ && ! side_effects_p (dest))
+ ret = 1;
+ }
+
+ /* If we can delete this SET, then we need to look for an earlier
+ REG_DEAD note on DREG, and remove it if it exists. */
+ if (ret && dreg >= 0)
+ {
+ if (! find_regno_note (insn, REG_UNUSED, dreg))
+ reload_cse_no_longer_dead (dreg, dest_mode);
+ }
+
+ return ret;
+}
+
+/* Try to simplify a single SET instruction. SET is the set pattern.
+ INSN is the instruction it came from.
+ This function only handles one case: if we set a register to a value
+ which is not a register, we try to find that value in some other register
+ and change the set into a register copy. */
+
+static int
+reload_cse_simplify_set (set, insn)
+ rtx set;
+ rtx insn;
+{
+ int dreg;
+ rtx src;
+ enum machine_mode dest_mode;
+ enum reg_class dclass;
+ register int i;
+
+ dreg = true_regnum (SET_DEST (set));
+ if (dreg < 0)
+ return 0;
+
+ src = SET_SRC (set);
+ if (side_effects_p (src) || true_regnum (src) >= 0)
+ return 0;
+
+ dclass = REGNO_REG_CLASS (dreg);
+
+ /* If memory loads are cheaper than register copies, don't change them. */
+ if (GET_CODE (src) == MEM
+ && MEMORY_MOVE_COST (GET_MODE (src), dclass, 1) < 2)
+ return 0;
+
+ /* If the constant is cheaper than a register, don't change it. */
+ if (CONSTANT_P (src)
+ && rtx_cost (src, SET) < 2)
+ return 0;
+
+ dest_mode = GET_MODE (SET_DEST (set));
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (i != dreg
+ && REGISTER_MOVE_COST (REGNO_REG_CLASS (i), dclass) == 2
+ && reload_cse_regno_equal_p (i, src, dest_mode))
+ {
+ int validated;
+
+ /* Pop back to the real obstacks while changing the insn. */
+ pop_obstacks ();
+
+ validated = validate_change (insn, &SET_SRC (set),
+ gen_rtx_REG (dest_mode, i), 1);
+
+ /* Go back to the obstack we are using for temporary
+ storage. */
+ push_obstacks (&reload_obstack, &reload_obstack);
+
+ if (validated && ! find_regno_note (insn, REG_UNUSED, i))
+ {
+ reload_cse_no_longer_dead (i, dest_mode);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Try to replace operands in INSN with equivalent values that are already
+ in registers. This can be viewed as optional reloading.
+
+ For each non-register operand in the insn, see if any hard regs are
+ known to be equivalent to that operand. Record the alternatives which
+ can accept these hard registers. Among all alternatives, select the
+ ones which are better or equal to the one currently matching, where
+ "better" is in terms of '?' and '!' constraints. Among the remaining
+ alternatives, select the one which replaces most operands with
+ hard registers. */
+
+static int
+reload_cse_simplify_operands (insn)
+ rtx insn;
+{
+#ifdef REGISTER_CONSTRAINTS
+ int insn_code_number, n_operands, n_alternatives;
+ int i,j;
+
+ char *constraints[MAX_RECOG_OPERANDS];
+
+ /* Vector recording how bad an alternative is. */
+ int *alternative_reject;
+ /* Vector recording how many registers can be introduced by choosing
+ this alternative. */
+ int *alternative_nregs;
+ /* Array of vectors recording, for each operand and each alternative,
+ which hard register to substitute, or -1 if the operand should be
+ left as it is. */
+ int *op_alt_regno[MAX_RECOG_OPERANDS];
+ /* Array of alternatives, sorted in order of decreasing desirability. */
+ int *alternative_order;
+ rtx reg = gen_rtx_REG (VOIDmode, -1);
+
+ /* Find out some information about this insn. */
+ insn_code_number = recog_memoized (insn);
+ /* We don't modify asm instructions. */
+ if (insn_code_number < 0)
+ return 0;
+
+ n_operands = insn_n_operands[insn_code_number];
+ n_alternatives = insn_n_alternatives[insn_code_number];
+
+ if (n_alternatives == 0 || n_operands == 0)
+ return 0;
+ insn_extract (insn);
+
+ /* Figure out which alternative currently matches. */
+ if (! constrain_operands (insn_code_number, 1))
+ fatal_insn_not_found (insn);
+
+ alternative_reject = (int *) alloca (n_alternatives * sizeof (int));
+ alternative_nregs = (int *) alloca (n_alternatives * sizeof (int));
+ alternative_order = (int *) alloca (n_alternatives * sizeof (int));
+ bzero ((char *)alternative_reject, n_alternatives * sizeof (int));
+ bzero ((char *)alternative_nregs, n_alternatives * sizeof (int));
+
+ for (i = 0; i < n_operands; i++)
+ {
+ enum machine_mode mode;
+ int regno;
+ char *p;
+
+ op_alt_regno[i] = (int *) alloca (n_alternatives * sizeof (int));
+ for (j = 0; j < n_alternatives; j++)
+ op_alt_regno[i][j] = -1;
+
+ p = constraints[i] = insn_operand_constraint[insn_code_number][i];
+ mode = insn_operand_mode[insn_code_number][i];
+
+ /* Add the reject values for each alternative given by the constraints
+ for this operand. */
+ j = 0;
+ while (*p != '\0')
+ {
+ char c = *p++;
+ if (c == ',')
+ j++;
+ else if (c == '?')
+ alternative_reject[j] += 3;
+ else if (c == '!')
+ alternative_reject[j] += 300;
+ }
+
+ /* We won't change operands which are already registers. We
+ also don't want to modify output operands. */
+ regno = true_regnum (recog_operand[i]);
+ if (regno >= 0
+ || constraints[i][0] == '='
+ || constraints[i][0] == '+')
+ continue;
+
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ {
+ int class = (int) NO_REGS;
+
+ if (! reload_cse_regno_equal_p (regno, recog_operand[i], mode))
+ continue;
+
+ REGNO (reg) = regno;
+ PUT_MODE (reg, mode);
+
+ /* We found a register equal to this operand. Now look for all
+ alternatives that can accept this register and have not been
+ assigned a register they can use yet. */
+ j = 0;
+ p = constraints[i];
+ for (;;)
+ {
+ char c = *p++;
+
+ switch (c)
+ {
+ case '=': case '+': case '?':
+ case '#': case '&': case '!':
+ case '*': case '%':
+ case '0': case '1': case '2': case '3': case '4':
+ case 'm': case '<': case '>': case 'V': case 'o':
+ case 'E': case 'F': case 'G': case 'H':
+ case 's': case 'i': case 'n':
+ case 'I': case 'J': case 'K': case 'L':
+ case 'M': case 'N': case 'O': case 'P':
+#ifdef EXTRA_CONSTRAINT
+ case 'Q': case 'R': case 'S': case 'T': case 'U':
+#endif
+ case 'p': case 'X':
+ /* These don't say anything we care about. */
+ break;
+
+ case 'g': case 'r':
+ class = reg_class_subunion[(int) class][(int) GENERAL_REGS];
+ break;
+
+ default:
+ class
+ = reg_class_subunion[(int) class][(int) REG_CLASS_FROM_LETTER (c)];
+ break;
+
+ case ',': case '\0':
+ /* See if REGNO fits this alternative, and set it up as the
+ replacement register if we don't have one for this
+ alternative yet and the operand being replaced is not
+ a cheap CONST_INT. */
+ if (op_alt_regno[i][j] == -1
+ && reg_fits_class_p (reg, class, 0, mode)
+ && (GET_CODE (recog_operand[i]) != CONST_INT
+ || rtx_cost (recog_operand[i], SET) > rtx_cost (reg, SET)))
+ {
+ alternative_nregs[j]++;
+ op_alt_regno[i][j] = regno;
+ }
+ j++;
+ break;
+ }
+
+ if (c == '\0')
+ break;
+ }
+ }
+ }
+
+ /* Record all alternatives which are better or equal to the currently
+ matching one in the alternative_order array. */
+ for (i = j = 0; i < n_alternatives; i++)
+ if (alternative_reject[i] <= alternative_reject[which_alternative])
+ alternative_order[j++] = i;
+ n_alternatives = j;
+
+ /* Sort it. Given a small number of alternatives, a dumb algorithm
+ won't hurt too much. */
+ for (i = 0; i < n_alternatives - 1; i++)
+ {
+ int best = i;
+ int best_reject = alternative_reject[alternative_order[i]];
+ int best_nregs = alternative_nregs[alternative_order[i]];
+ int tmp;
+
+ for (j = i + 1; j < n_alternatives; j++)
+ {
+ int this_reject = alternative_reject[alternative_order[j]];
+ int this_nregs = alternative_nregs[alternative_order[j]];
+
+ if (this_reject < best_reject
+ || (this_reject == best_reject && this_nregs < best_nregs))
+ {
+ best = j;
+ best_reject = this_reject;
+ best_nregs = this_nregs;
+ }
+ }
+
+ tmp = alternative_order[best];
+ alternative_order[best] = alternative_order[i];
+ alternative_order[i] = tmp;
+ }
+
+ /* Substitute the operands as determined by op_alt_regno for the best
+ alternative. */
+ j = alternative_order[0];
+ CLEAR_HARD_REG_SET (no_longer_dead_regs);
+
+ /* Pop back to the real obstacks while changing the insn. */
+ pop_obstacks ();
+
+ for (i = 0; i < n_operands; i++)
+ {
+ enum machine_mode mode = insn_operand_mode[insn_code_number][i];
+ if (op_alt_regno[i][j] == -1)
+ continue;
+
+ reload_cse_no_longer_dead (op_alt_regno[i][j], mode);
+ validate_change (insn, recog_operand_loc[i],
+ gen_rtx_REG (mode, op_alt_regno[i][j]), 1);
+ }
+
+ for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)
+ {
+ int op = recog_dup_num[i];
+ enum machine_mode mode = insn_operand_mode[insn_code_number][op];
+
+ if (op_alt_regno[op][j] == -1)
+ continue;
+
+ reload_cse_no_longer_dead (op_alt_regno[op][j], mode);
+ validate_change (insn, recog_dup_loc[i],
+ gen_rtx_REG (mode, op_alt_regno[op][j]), 1);
+ }
+
+ /* Go back to the obstack we are using for temporary
+ storage. */
+ push_obstacks (&reload_obstack, &reload_obstack);
+
+ return apply_change_group ();
+#else
+ return 0;
+#endif
+}
+
+/* These two variables are used to pass information from
+ reload_cse_record_set to reload_cse_check_clobber. */
+
+static int reload_cse_check_clobbered;
+static rtx reload_cse_check_src;
+
+/* See if DEST overlaps with RELOAD_CSE_CHECK_SRC. If it does, set
+ RELOAD_CSE_CHECK_CLOBBERED. This is called via note_stores. The
+ second argument, which is passed by note_stores, is ignored. */
+
+static void
+reload_cse_check_clobber (dest, ignore)
+ rtx dest;
+ rtx ignore ATTRIBUTE_UNUSED;
+{
+ if (reg_overlap_mentioned_p (dest, reload_cse_check_src))
+ reload_cse_check_clobbered = 1;
+}
+
+/* Record the result of a SET instruction. SET is the set pattern.
+ BODY is the pattern of the insn that it came from. */
+
+static void
+reload_cse_record_set (set, body)
+ rtx set;
+ rtx body;
+{
+ rtx dest, src, x;
+ int dreg, sreg;
+ enum machine_mode dest_mode;
+
+ dest = SET_DEST (set);
+ src = SET_SRC (set);
+ dreg = true_regnum (dest);
+ sreg = true_regnum (src);
+ dest_mode = GET_MODE (dest);
+
+ /* Some machines don't define AUTO_INC_DEC, but they still use push
+ instructions. We need to catch that case here in order to
+ invalidate the stack pointer correctly. Note that invalidating
+ the stack pointer is different from invalidating DEST. */
+ x = dest;
+ while (GET_CODE (x) == SUBREG
+ || GET_CODE (x) == ZERO_EXTRACT
+ || GET_CODE (x) == SIGN_EXTRACT
+ || GET_CODE (x) == STRICT_LOW_PART)
+ x = XEXP (x, 0);
+ if (push_operand (x, GET_MODE (x)))
+ {
+ reload_cse_invalidate_rtx (stack_pointer_rtx, NULL_RTX);
+ reload_cse_invalidate_rtx (dest, NULL_RTX);
+ return;
+ }
+
+ /* We can only handle an assignment to a register, or a store of a
+ register to a memory location. For other cases, we just clobber
+ the destination. We also have to just clobber if there are side
+ effects in SRC or DEST. */
+ if ((dreg < 0 && GET_CODE (dest) != MEM)
+ || side_effects_p (src)
+ || side_effects_p (dest))
+ {
+ reload_cse_invalidate_rtx (dest, NULL_RTX);
+ return;
+ }
+
+#ifdef HAVE_cc0
+ /* We don't try to handle values involving CC, because it's a pain
+ to keep track of when they have to be invalidated. */
+ if (reg_mentioned_p (cc0_rtx, src)
+ || reg_mentioned_p (cc0_rtx, dest))
+ {
+ reload_cse_invalidate_rtx (dest, NULL_RTX);
+ return;
+ }
+#endif
+
+ /* If BODY is a PARALLEL, then we need to see whether the source of
+ SET is clobbered by some other instruction in the PARALLEL. */
+ if (GET_CODE (body) == PARALLEL)
+ {
+ int i;
+
+ for (i = XVECLEN (body, 0) - 1; i >= 0; --i)
+ {
+ rtx x;
+
+ x = XVECEXP (body, 0, i);
+ if (x == set)
+ continue;
+
+ reload_cse_check_clobbered = 0;
+ reload_cse_check_src = src;
+ note_stores (x, reload_cse_check_clobber);
+ if (reload_cse_check_clobbered)
+ {
+ reload_cse_invalidate_rtx (dest, NULL_RTX);
+ return;
+ }
+ }
+ }
+
+ if (dreg >= 0)
+ {
+ int i;
+
+ /* This is an assignment to a register. Update the value we
+ have stored for the register. */
+ if (sreg >= 0)
+ {
+ rtx x;
+
+ /* This is a copy from one register to another. Any values
+ which were valid for SREG are now valid for DREG. If the
+ mode changes, we use gen_lowpart_common to extract only
+ the part of the value that is copied. */
+ reg_values[dreg] = 0;
+ for (x = reg_values[sreg]; x; x = XEXP (x, 1))
+ {
+ rtx tmp;
+
+ if (XEXP (x, 0) == 0)
+ continue;
+ if (dest_mode == GET_MODE (XEXP (x, 0)))
+ tmp = XEXP (x, 0);
+ else if (GET_MODE_BITSIZE (dest_mode)
+ > GET_MODE_BITSIZE (GET_MODE (XEXP (x, 0))))
+ continue;
+ else
+ tmp = gen_lowpart_common (dest_mode, XEXP (x, 0));
+ if (tmp)
+ reg_values[dreg] = gen_rtx_EXPR_LIST (dest_mode, tmp,
+ reg_values[dreg]);
+ }
+ }
+ else
+ reg_values[dreg] = gen_rtx_EXPR_LIST (dest_mode, src, NULL_RTX);
+
+ /* We've changed DREG, so invalidate any values held by other
+ registers that depend upon it. */
+ reload_cse_invalidate_regno (dreg, dest_mode, 0);
+
+ /* If this assignment changes more than one hard register,
+ forget anything we know about the others. */
+ for (i = 1; i < HARD_REGNO_NREGS (dreg, dest_mode); i++)
+ reg_values[dreg + i] = 0;
+ }
+ else if (GET_CODE (dest) == MEM)
+ {
+ /* Invalidate conflicting memory locations. */
+ reload_cse_invalidate_mem (dest);
+
+ /* If we're storing a register to memory, add DEST to the list
+ in REG_VALUES. */
+ if (sreg >= 0 && ! side_effects_p (dest))
+ reg_values[sreg] = gen_rtx_EXPR_LIST (dest_mode, dest,
+ reg_values[sreg]);
+ }
+ else
+ {
+ /* We should have bailed out earlier. */
+ abort ();
+ }
+}
diff --git a/contrib/gcc/reorg.c b/contrib/gcc/reorg.c
index edd76d5..4e823e4 100644
--- a/contrib/gcc/reorg.c
+++ b/contrib/gcc/reorg.c
@@ -1,5 +1,5 @@
/* Perform instruction reorganizations for delay slot filling.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu).
Hacked by Michael Tiemann (tiemann@cygnus.com).
@@ -115,9 +115,10 @@ Boston, MA 02111-1307, USA. */
The HP-PA can conditionally nullify insns, providing a similar
effect to the ARM, differing mostly in which insn is "in charge". */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "rtl.h"
+#include "expr.h"
#include "insn-config.h"
#include "conditions.h"
#include "hard-reg-set.h"
@@ -130,6 +131,13 @@ Boston, MA 02111-1307, USA. */
#include "obstack.h"
#include "insn-attr.h"
+/* Import list of registers used as spill regs from reload. */
+extern HARD_REG_SET used_spill_regs;
+
+/* Import highest label used in function at end of reload. */
+extern int max_label_num_after_reload;
+
+
#ifdef DELAY_SLOTS
#define obstack_chunk_alloc xmalloc
@@ -163,8 +171,8 @@ static rtx *unfilled_firstobj;
struct resources
{
char memory; /* Insn sets or needs a memory location. */
- char unch_memory; /* Insn sets of needs a "unchanging" MEM. */
- char volatil; /* Insn sets or needs a volatile memory loc. */
+ char unch_memory; /* Insn sets of needs a "unchanging" MEM. */
+ char volatil; /* Insn sets or needs a volatile memory loc. */
char cc; /* Insn sets or needs the condition codes. */
HARD_REG_SET regs; /* Which registers are set or needed. */
};
@@ -222,9 +230,9 @@ static int stop_search_p PROTO((rtx, int));
static int resource_conflicts_p PROTO((struct resources *,
struct resources *));
static int insn_references_resource_p PROTO((rtx, struct resources *, int));
-static int insn_sets_resources_p PROTO((rtx, struct resources *, int));
+static int insn_sets_resource_p PROTO((rtx, struct resources *, int));
static rtx find_end_label PROTO((void));
-static rtx emit_delay_sequence PROTO((rtx, rtx, int, int));
+static rtx emit_delay_sequence PROTO((rtx, rtx, int));
static rtx add_to_delay_list PROTO((rtx, rtx));
static void delete_from_delay_slot PROTO((rtx));
static void delete_scheduled_jump PROTO((rtx));
@@ -252,21 +260,25 @@ static int find_basic_block PROTO((rtx));
static void update_block PROTO((rtx, rtx));
static int reorg_redirect_jump PROTO((rtx, rtx));
static void update_reg_dead_notes PROTO((rtx, rtx));
+static void fix_reg_dead_note PROTO((rtx, rtx));
static void update_reg_unused_notes PROTO((rtx, rtx));
static void update_live_status PROTO((rtx, rtx));
static rtx next_insn_no_annul PROTO((rtx));
+static rtx find_dead_or_set_registers PROTO ((rtx, struct resources *, rtx *,
+ int, struct resources,
+ struct resources));
static void mark_target_live_regs PROTO((rtx, struct resources *));
-static void fill_simple_delay_slots PROTO((rtx, int));
+static void fill_simple_delay_slots PROTO((int));
static rtx fill_slots_from_thread PROTO((rtx, rtx, rtx, rtx, int, int,
- int, int, int, int *));
-static void fill_eager_delay_slots PROTO((rtx));
+ int, int, int *, rtx));
+static void fill_eager_delay_slots PROTO((void));
static void relax_delay_slots PROTO((rtx));
static void make_return_insns PROTO((rtx));
static int redirect_with_delay_slots_safe_p PROTO ((rtx, rtx, rtx));
static int redirect_with_delay_list_safe_p PROTO ((rtx, rtx, rtx));
/* Given X, some rtl, and RES, a pointer to a `struct resource', mark
- which resources are references by the insn. If INCLUDE_CALLED_ROUTINE
+ which resources are references by the insn. If INCLUDE_DELAYED_EFFECTS
is TRUE, resources used by the called routine will be included for
CALL_INSNs. */
@@ -332,6 +344,10 @@ mark_referenced_resources (x, res, include_delayed_effects)
res->volatil = 1;
return;
+ case TRAP_IF:
+ res->volatil = 1;
+ break;
+
case ASM_OPERANDS:
res->volatil = MEM_VOLATILE_P (x);
@@ -386,7 +402,7 @@ mark_referenced_resources (x, res, include_delayed_effects)
rtx next = NEXT_INSN (x);
int i;
- /* If we are part of a delay slot sequence, point at the SEQUENCE. */
+ /* If we are part of a delay slot sequence, point at the SEQUENCE. */
if (NEXT_INSN (insn) != x)
{
next = NEXT_INSN (NEXT_INSN (insn));
@@ -445,7 +461,7 @@ mark_referenced_resources (x, res, include_delayed_effects)
}
}
- /* ... fall through to other INSN processing ... */
+ /* ... fall through to other INSN processing ... */
case INSN:
case JUMP_INSN:
@@ -459,6 +475,9 @@ mark_referenced_resources (x, res, include_delayed_effects)
/* No special processing, just speed up. */
mark_referenced_resources (PATTERN (x), res, include_delayed_effects);
return;
+
+ default:
+ break;
}
/* Process each sub-expression and flag what it needs. */
@@ -478,9 +497,10 @@ mark_referenced_resources (x, res, include_delayed_effects)
}
}
-/* Given X, a part of an insn, and a pointer to a `struct resource', RES,
- indicate which resources are modified by the insn. If INCLUDE_CALLED_ROUTINE
- is nonzero, also mark resources potentially set by the called routine.
+/* Given X, a part of an insn, and a pointer to a `struct resource',
+ RES, indicate which resources are modified by the insn. If
+ INCLUDE_DELAYED_EFFECTS is nonzero, also mark resources potentially
+ set by the called routine.
If IN_DEST is nonzero, it means we are inside a SET. Otherwise,
objects are being referenced instead of set.
@@ -559,7 +579,7 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
SET_HARD_REG_SET (res->regs);
}
- /* ... and also what it's RTL says it modifies, if anything. */
+ /* ... and also what its RTL says it modifies, if anything. */
case JUMP_INSN:
case INSN:
@@ -648,6 +668,9 @@ mark_set_resources (x, res, in_dest, include_delayed_effects)
for (i = 0; i < HARD_REGNO_NREGS (REGNO (x), GET_MODE (x)); i++)
SET_HARD_REG_BIT (res->regs, REGNO (x) + i);
return;
+
+ default:
+ break;
}
/* Process each sub-expression and flag what it needs. */
@@ -731,7 +754,7 @@ resource_conflicts_p (res1, res2)
}
/* Return TRUE if any resource marked in RES, a `struct resources', is
- referenced by INSN. If INCLUDE_CALLED_ROUTINE is set, return if the called
+ referenced by INSN. If INCLUDE_DELAYED_EFFECTS is set, return if the called
routine is using those resources.
We compute this by computing all the resources referenced by INSN and
@@ -753,7 +776,7 @@ insn_references_resource_p (insn, res, include_delayed_effects)
}
/* Return TRUE if INSN modifies resources that are marked in RES.
- INCLUDE_CALLED_ROUTINE is set if the actions of that routine should be
+ INCLUDE_DELAYED_EFFECTS is set if the actions of that routine should be
included. CC0 is only modified if it is explicitly set; see comments
in front of mark_set_resources for details. */
@@ -804,7 +827,7 @@ find_end_label ()
end_of_function_label = gen_label_rtx ();
LABEL_NUSES (end_of_function_label) = 0;
- /* Put the label before an USE insns that may proceed the RETURN insn. */
+ /* Put the label before an USE insns that may proceed the RETURN insn. */
while (GET_CODE (temp) == USE)
temp = PREV_INSN (temp);
@@ -851,24 +874,23 @@ find_end_label ()
Returns the SEQUENCE that replaces INSN. */
static rtx
-emit_delay_sequence (insn, list, length, avail)
+emit_delay_sequence (insn, list, length)
rtx insn;
rtx list;
int length;
- int avail;
{
register int i = 1;
register rtx li;
int had_barrier = 0;
- /* Allocate the the rtvec to hold the insns and the SEQUENCE. */
+ /* Allocate the rtvec to hold the insns and the SEQUENCE. */
rtvec seqv = rtvec_alloc (length + 1);
- rtx seq = gen_rtx (SEQUENCE, VOIDmode, seqv);
+ rtx seq = gen_rtx_SEQUENCE (VOIDmode, seqv);
rtx seq_insn = make_insn_raw (seq);
rtx first = get_insns ();
rtx last = get_last_insn ();
- /* Make a copy of the insn having delay slots. */
+ /* Make a copy of the insn having delay slots. */
rtx delay_insn = copy_rtx (insn);
/* If INSN is followed by a BARRIER, delete the BARRIER since it will only
@@ -885,15 +907,22 @@ emit_delay_sequence (insn, list, length, avail)
NEXT_INSN (seq_insn) = NEXT_INSN (insn);
PREV_INSN (seq_insn) = PREV_INSN (insn);
+ if (insn != last)
+ PREV_INSN (NEXT_INSN (seq_insn)) = seq_insn;
+
+ if (insn != first)
+ NEXT_INSN (PREV_INSN (seq_insn)) = seq_insn;
+
+ /* Note the calls to set_new_first_and_last_insn must occur after
+ SEQ_INSN has been completely spliced into the insn stream.
+
+ Otherwise CUR_INSN_UID will get set to an incorrect value because
+ set_new_first_and_last_insn will not find SEQ_INSN in the chain. */
if (insn == last)
set_new_first_and_last_insn (first, seq_insn);
- else
- PREV_INSN (NEXT_INSN (seq_insn)) = seq_insn;
if (insn == first)
set_new_first_and_last_insn (seq_insn, last);
- else
- NEXT_INSN (PREV_INSN (seq_insn)) = seq_insn;
/* Build our SEQUENCE and rebuild the insn chain. */
XVECEXP (seq, 0, 0) = delay_insn;
@@ -954,7 +983,7 @@ add_to_delay_list (insn, delay_list)
rtx delay_list;
{
/* If we have an empty list, just make a new list element. If
- INSN has it's block number recorded, clear it since we may
+ INSN has its block number recorded, clear it since we may
be moving the insn to a new block. */
if (delay_list == 0)
@@ -969,7 +998,7 @@ add_to_delay_list (insn, delay_list)
if (tinfo)
tinfo->block = -1;
- return gen_rtx (INSN_LIST, VOIDmode, insn, NULL_RTX);
+ return gen_rtx_INSN_LIST (VOIDmode, insn, NULL_RTX);
}
/* Otherwise this must be an INSN_LIST. Add INSN to the end of the
@@ -979,7 +1008,7 @@ add_to_delay_list (insn, delay_list)
return delay_list;
}
-/* Delete INSN from the the delay slot of the insn that it is in. This may
+/* Delete INSN from the delay slot of the insn that it is in. This may
produce an insn without anything in its delay slots. */
static void
@@ -1023,7 +1052,7 @@ delete_from_delay_slot (insn)
/* If there are any delay insns, remit them. Otherwise clear the
annul flag. */
if (delay_list)
- trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2, 0);
+ trial = emit_delay_sequence (trial, delay_list, XVECLEN (seq, 0) - 2);
else
INSN_ANNULLED_BRANCH_P (trial) = 0;
@@ -1218,6 +1247,7 @@ optimize_skip (insn)
Non conditional branches return no direction information and
are predicted as very likely taken. */
+
static int
get_jump_flags (insn, label)
rtx insn, label;
@@ -1314,6 +1344,9 @@ rare_destination (insn)
next = JUMP_LABEL (insn);
else
return 0;
+
+ default:
+ break;
}
}
@@ -1340,6 +1373,26 @@ mostly_true_jump (jump_insn, condition)
int rare_dest = rare_destination (target_label);
int rare_fallthrough = rare_destination (NEXT_INSN (jump_insn));
+ /* If branch probabilities are available, then use that number since it
+ always gives a correct answer. */
+ if (flag_branch_probabilities)
+ {
+ rtx note = find_reg_note (jump_insn, REG_BR_PROB, 0);;
+ if (note)
+ {
+ int prob = XINT (note, 0);
+
+ if (prob >= REG_BR_PROB_BASE * 9 / 10)
+ return 2;
+ else if (prob >= REG_BR_PROB_BASE / 2)
+ return 1;
+ else if (prob >= REG_BR_PROB_BASE / 10)
+ return 0;
+ else
+ return -1;
+ }
+ }
+
/* If this is a branch outside a loop, it is highly unlikely. */
if (GET_CODE (PATTERN (jump_insn)) == SET
&& GET_CODE (SET_SRC (PATTERN (jump_insn))) == IF_THEN_ELSE
@@ -1373,7 +1426,7 @@ mostly_true_jump (jump_insn, condition)
}
/* Look at the relative rarities of the fallthrough and destination. If
- they differ, we can predict the branch that way. */
+ they differ, we can predict the branch that way. */
switch (rare_fallthrough - rare_dest)
{
@@ -1416,6 +1469,9 @@ mostly_true_jump (jump_insn, condition)
if (XEXP (condition, 1) == const0_rtx)
return 1;
break;
+
+ default:
+ break;
}
/* Predict backward branches usually take, forward branches usually not. If
@@ -1465,9 +1521,9 @@ get_branch_condition (insn, target)
|| (GET_CODE (XEXP (src, 2)) == LABEL_REF
&& XEXP (XEXP (src, 2), 0) == target))
&& XEXP (src, 1) == pc_rtx)
- return gen_rtx (reverse_condition (GET_CODE (XEXP (src, 0))),
- GET_MODE (XEXP (src, 0)),
- XEXP (XEXP (src, 0), 0), XEXP (XEXP (src, 0), 1));
+ return gen_rtx_fmt_ee (reverse_condition (GET_CODE (XEXP (src, 0))),
+ GET_MODE (XEXP (src, 0)),
+ XEXP (XEXP (src, 0), 0), XEXP (XEXP (src, 0), 1));
return 0;
}
@@ -1507,7 +1563,7 @@ static int
redirect_with_delay_slots_safe_p (jump, newlabel, seq)
rtx jump, newlabel, seq;
{
- int flags, slots, i;
+ int flags, i;
rtx pat = PATTERN (seq);
/* Make sure all the delay slots of this jump would still
@@ -1842,7 +1898,7 @@ try_merge_delay_insns (insn, thread)
INSN_FROM_TARGET_P (next_to_match) = 0;
}
else
- merged_insns = gen_rtx (INSN_LIST, VOIDmode, trial, merged_insns);
+ merged_insns = gen_rtx_INSN_LIST (VOIDmode, trial, merged_insns);
if (++slot_number == num_slots)
break;
@@ -1890,8 +1946,8 @@ try_merge_delay_insns (insn, thread)
INSN_FROM_TARGET_P (next_to_match) = 0;
}
else
- merged_insns = gen_rtx (INSN_LIST, SImode, dtrial,
- merged_insns);
+ merged_insns = gen_rtx_INSN_LIST (SImode, dtrial,
+ merged_insns);
if (++slot_number == num_slots)
break;
@@ -1903,7 +1959,7 @@ try_merge_delay_insns (insn, thread)
/* If all insns in the delay slot have been matched and we were previously
annulling the branch, we need not any more. In that case delete all the
- merged insns. Also clear the INSN_FROM_TARGET_P bit of each insn the
+ merged insns. Also clear the INSN_FROM_TARGET_P bit of each insn in
the delay list so that we know that it isn't only being used at the
target. */
if (slot_number == num_slots && annul_p)
@@ -1960,6 +2016,11 @@ redundant_insn (insn, target, delay_list)
struct resources needed, set;
int i;
+ /* If INSN has any REG_UNUSED notes, it can't match anything since we
+ are allowed to not actually assign to such a register. */
+ if (find_reg_note (insn, REG_UNUSED, NULL_RTX) != 0)
+ return 0;
+
/* Scan backwards looking for a match. */
for (trial = PREV_INSN (target); trial; trial = PREV_INSN (trial))
{
@@ -1998,7 +2059,8 @@ redundant_insn (insn, target, delay_list)
resource requirements as we go. */
for (i = XVECLEN (pat, 0) - 1; i > 0; i--)
if (GET_CODE (XVECEXP (pat, 0, i)) == GET_CODE (insn)
- && rtx_equal_p (PATTERN (XVECEXP (pat, 0, i)), ipat))
+ && rtx_equal_p (PATTERN (XVECEXP (pat, 0, i)), ipat)
+ && ! find_reg_note (XVECEXP (pat, 0, i), REG_UNUSED, NULL_RTX))
break;
/* If found a match, exit this loop early. */
@@ -2006,7 +2068,8 @@ redundant_insn (insn, target, delay_list)
break;
}
- else if (GET_CODE (trial) == GET_CODE (insn) && rtx_equal_p (pat, ipat))
+ else if (GET_CODE (trial) == GET_CODE (insn) && rtx_equal_p (pat, ipat)
+ && ! find_reg_note (trial, REG_UNUSED, NULL_RTX))
break;
}
@@ -2079,7 +2142,7 @@ redundant_insn (insn, target, delay_list)
if (GET_CODE (XVECEXP (pat, 0, 0)) == CALL_INSN)
return 0;
- /* If this this is an INSN or JUMP_INSN with delayed effects, it
+ /* If this is an INSN or JUMP_INSN with delayed effects, it
is hard to track the resource needs properly, so give up. */
#ifdef INSN_SETS_ARE_DELAYED
@@ -2241,7 +2304,7 @@ update_block (insn, where)
if (INSN_FROM_TARGET_P (insn))
return;
- emit_insn_before (gen_rtx (USE, VOIDmode, insn), where);
+ emit_insn_before (gen_rtx_USE (VOIDmode, insn), where);
/* INSN might be making a value live in a block where it didn't use to
be. So recompute liveness information for this block. */
@@ -2304,6 +2367,38 @@ update_reg_dead_notes (insn, delayed_insn)
}
}
+/* Called when an insn redundant with start_insn is deleted. If there
+ is a REG_DEAD note for the target of start_insn between start_insn
+ and stop_insn, then the REG_DEAD note needs to be deleted since the
+ value no longer dies there.
+
+ If the REG_DEAD note isn't deleted, then mark_target_live_regs may be
+ confused into thinking the register is dead. */
+
+static void
+fix_reg_dead_note (start_insn, stop_insn)
+ rtx start_insn, stop_insn;
+{
+ rtx p, link, next;
+
+ for (p = next_nonnote_insn (start_insn); p != stop_insn;
+ p = next_nonnote_insn (p))
+ for (link = REG_NOTES (p); link; link = next)
+ {
+ next = XEXP (link, 1);
+
+ if (REG_NOTE_KIND (link) != REG_DEAD
+ || GET_CODE (XEXP (link, 0)) != REG)
+ continue;
+
+ if (reg_set_p (XEXP (link, 0), PATTERN (start_insn)))
+ {
+ remove_note (p, link);
+ return;
+ }
+ }
+}
+
/* Delete any REG_UNUSED notes that exist on INSN but not on REDUNDANT_INSN.
This handles the case of udivmodXi4 instructions which optimize their
@@ -2315,7 +2410,7 @@ static void
update_reg_unused_notes (insn, redundant_insn)
rtx insn, redundant_insn;
{
- rtx p, link, next;
+ rtx link, next;
for (link = REG_NOTES (insn); link; link = next)
{
@@ -2399,6 +2494,191 @@ next_insn_no_annul (insn)
return insn;
}
+/* A subroutine of mark_target_live_regs. Search forward from TARGET
+ looking for registers that are set before they are used. These are dead.
+ Stop after passing a few conditional jumps, and/or a small
+ number of unconditional branches. */
+
+static rtx
+find_dead_or_set_registers (target, res, jump_target, jump_count, set, needed)
+ rtx target;
+ struct resources *res;
+ rtx *jump_target;
+ int jump_count;
+ struct resources set, needed;
+{
+ HARD_REG_SET scratch;
+ rtx insn, next;
+ rtx jump_insn = 0;
+ int i;
+
+ for (insn = target; insn; insn = next)
+ {
+ rtx this_jump_insn = insn;
+
+ next = NEXT_INSN (insn);
+ switch (GET_CODE (insn))
+ {
+ case CODE_LABEL:
+ /* After a label, any pending dead registers that weren't yet
+ used can be made dead. */
+ AND_COMPL_HARD_REG_SET (pending_dead_regs, needed.regs);
+ AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs);
+ CLEAR_HARD_REG_SET (pending_dead_regs);
+
+ if (CODE_LABEL_NUMBER (insn) < max_label_num_after_reload)
+ {
+ /* All spill registers are dead at a label, so kill all of the
+ ones that aren't needed also. */
+ COPY_HARD_REG_SET (scratch, used_spill_regs);
+ AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+ AND_COMPL_HARD_REG_SET (res->regs, scratch);
+ }
+ continue;
+
+ case BARRIER:
+ case NOTE:
+ continue;
+
+ case INSN:
+ if (GET_CODE (PATTERN (insn)) == USE)
+ {
+ /* If INSN is a USE made by update_block, we care about the
+ underlying insn. Any registers set by the underlying insn
+ are live since the insn is being done somewhere else. */
+ if (GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
+ mark_set_resources (XEXP (PATTERN (insn), 0), res, 0, 1);
+
+ /* All other USE insns are to be ignored. */
+ continue;
+ }
+ else if (GET_CODE (PATTERN (insn)) == CLOBBER)
+ continue;
+ else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
+ {
+ /* An unconditional jump can be used to fill the delay slot
+ of a call, so search for a JUMP_INSN in any position. */
+ for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+ {
+ this_jump_insn = XVECEXP (PATTERN (insn), 0, i);
+ if (GET_CODE (this_jump_insn) == JUMP_INSN)
+ break;
+ }
+ }
+
+ default:
+ break;
+ }
+
+ if (GET_CODE (this_jump_insn) == JUMP_INSN)
+ {
+ if (jump_count++ < 10)
+ {
+ if (simplejump_p (this_jump_insn)
+ || GET_CODE (PATTERN (this_jump_insn)) == RETURN)
+ {
+ next = JUMP_LABEL (this_jump_insn);
+ if (jump_insn == 0)
+ {
+ jump_insn = insn;
+ if (jump_target)
+ *jump_target = JUMP_LABEL (this_jump_insn);
+ }
+ }
+ else if (condjump_p (this_jump_insn)
+ || condjump_in_parallel_p (this_jump_insn))
+ {
+ struct resources target_set, target_res;
+ struct resources fallthrough_res;
+
+ /* We can handle conditional branches here by following
+ both paths, and then IOR the results of the two paths
+ together, which will give us registers that are dead
+ on both paths. Since this is expensive, we give it
+ a much higher cost than unconditional branches. The
+ cost was chosen so that we will follow at most 1
+ conditional branch. */
+
+ jump_count += 4;
+ if (jump_count >= 10)
+ break;
+
+ mark_referenced_resources (insn, &needed, 1);
+
+ /* For an annulled branch, mark_set_resources ignores slots
+ filled by instructions from the target. This is correct
+ if the branch is not taken. Since we are following both
+ paths from the branch, we must also compute correct info
+ if the branch is taken. We do this by inverting all of
+ the INSN_FROM_TARGET_P bits, calling mark_set_resources,
+ and then inverting the INSN_FROM_TARGET_P bits again. */
+
+ if (GET_CODE (PATTERN (insn)) == SEQUENCE
+ && INSN_ANNULLED_BRANCH_P (this_jump_insn))
+ {
+ for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+ INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i))
+ = ! INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i));
+
+ target_set = set;
+ mark_set_resources (insn, &target_set, 0, 1);
+
+ for (i = 1; i < XVECLEN (PATTERN (insn), 0); i++)
+ INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i))
+ = ! INSN_FROM_TARGET_P (XVECEXP (PATTERN (insn), 0, i));
+
+ mark_set_resources (insn, &set, 0, 1);
+ }
+ else
+ {
+ mark_set_resources (insn, &set, 0, 1);
+ target_set = set;
+ }
+
+ target_res = *res;
+ COPY_HARD_REG_SET (scratch, target_set.regs);
+ AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+ AND_COMPL_HARD_REG_SET (target_res.regs, scratch);
+
+ fallthrough_res = *res;
+ COPY_HARD_REG_SET (scratch, set.regs);
+ AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+ AND_COMPL_HARD_REG_SET (fallthrough_res.regs, scratch);
+
+ find_dead_or_set_registers (JUMP_LABEL (this_jump_insn),
+ &target_res, 0, jump_count,
+ target_set, needed);
+ find_dead_or_set_registers (next,
+ &fallthrough_res, 0, jump_count,
+ set, needed);
+ IOR_HARD_REG_SET (fallthrough_res.regs, target_res.regs);
+ AND_HARD_REG_SET (res->regs, fallthrough_res.regs);
+ break;
+ }
+ else
+ break;
+ }
+ else
+ {
+ /* Don't try this optimization if we expired our jump count
+ above, since that would mean there may be an infinite loop
+ in the function being compiled. */
+ jump_insn = 0;
+ break;
+ }
+ }
+
+ mark_referenced_resources (insn, &needed, 1);
+ mark_set_resources (insn, &set, 0, 1);
+
+ COPY_HARD_REG_SET (scratch, set.regs);
+ AND_COMPL_HARD_REG_SET (scratch, needed.regs);
+ AND_COMPL_HARD_REG_SET (res->regs, scratch);
+ }
+
+ return jump_insn;
+}
+
/* Set the resources that are live at TARGET.
If TARGET is zero, we refer to the end of the current function and can
@@ -2445,12 +2725,11 @@ mark_target_live_regs (target, res)
int b = -1;
int i;
struct target_info *tinfo;
- rtx insn, next;
+ rtx insn;
rtx jump_insn = 0;
rtx jump_target;
HARD_REG_SET scratch;
struct resources set, needed;
- int jump_count = 0;
/* Handle end of function. */
if (target == 0)
@@ -2509,8 +2788,7 @@ mark_target_live_regs (target, res)
if (b != -1)
{
regset regs_live = basic_block_live_at_start[b];
- int offset, j;
- REGSET_ELT_TYPE bit;
+ int j;
int regno;
rtx start_insn, stop_insn;
@@ -2518,26 +2796,18 @@ mark_target_live_regs (target, res)
marked live, plus live pseudo regs that have been renumbered to
hard regs. */
-#ifdef HARD_REG_SET
- current_live_regs = *regs_live;
-#else
- COPY_HARD_REG_SET (current_live_regs, regs_live);
-#endif
+ REG_SET_TO_HARD_REG_SET (current_live_regs, regs_live);
- for (offset = 0, i = 0; offset < regset_size; offset++)
- {
- if (regs_live[offset] == 0)
- i += REGSET_ELT_BITS;
- else
- for (bit = 1; bit && i < max_regno; bit <<= 1, i++)
- if ((regs_live[offset] & bit)
- && (regno = reg_renumber[i]) >= 0)
- for (j = regno;
- j < regno + HARD_REGNO_NREGS (regno,
- PSEUDO_REGNO_MODE (i));
- j++)
- SET_HARD_REG_BIT (current_live_regs, j);
- }
+ EXECUTE_IF_SET_IN_REG_SET
+ (regs_live, FIRST_PSEUDO_REGISTER, i,
+ {
+ if ((regno = reg_renumber[i]) >= 0)
+ for (j = regno;
+ j < regno + HARD_REGNO_NREGS (regno,
+ PSEUDO_REGNO_MODE (i));
+ j++)
+ SET_HARD_REG_BIT (current_live_regs, j);
+ });
/* Get starting and ending insn, handling the case where each might
be a SEQUENCE. */
@@ -2669,92 +2939,18 @@ mark_target_live_regs (target, res)
in use. This should happen only extremely rarely. */
SET_HARD_REG_SET (res->regs);
- /* Now step forward from TARGET looking for registers that are set before
- they are used. These are dead. If we pass a label, any pending dead
- registers that weren't yet used can be made dead. Stop when we pass a
- conditional JUMP_INSN; follow the first few unconditional branches. */
-
CLEAR_RESOURCE (&set);
CLEAR_RESOURCE (&needed);
- for (insn = target; insn; insn = next)
- {
- rtx this_jump_insn = insn;
-
- next = NEXT_INSN (insn);
- switch (GET_CODE (insn))
- {
- case CODE_LABEL:
- AND_COMPL_HARD_REG_SET (pending_dead_regs, needed.regs);
- AND_COMPL_HARD_REG_SET (res->regs, pending_dead_regs);
- CLEAR_HARD_REG_SET (pending_dead_regs);
- continue;
-
- case BARRIER:
- case NOTE:
- continue;
-
- case INSN:
- if (GET_CODE (PATTERN (insn)) == USE)
- {
- /* If INSN is a USE made by update_block, we care about the
- underlying insn. Any registers set by the underlying insn
- are live since the insn is being done somewhere else. */
- if (GET_RTX_CLASS (GET_CODE (XEXP (PATTERN (insn), 0))) == 'i')
- mark_set_resources (XEXP (PATTERN (insn), 0), res, 0, 1);
-
- /* All other USE insns are to be ignored. */
- continue;
- }
- else if (GET_CODE (PATTERN (insn)) == CLOBBER)
- continue;
- else if (GET_CODE (PATTERN (insn)) == SEQUENCE)
- {
- /* An unconditional jump can be used to fill the delay slot
- of a call, so search for a JUMP_INSN in any position. */
- for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
- {
- this_jump_insn = XVECEXP (PATTERN (insn), 0, i);
- if (GET_CODE (this_jump_insn) == JUMP_INSN)
- break;
- }
- }
- }
-
- if (GET_CODE (this_jump_insn) == JUMP_INSN)
- {
- if (jump_count++ < 10
- && (simplejump_p (this_jump_insn)
- || GET_CODE (PATTERN (this_jump_insn)) == RETURN))
- {
- next = next_active_insn (JUMP_LABEL (this_jump_insn));
- if (jump_insn == 0)
- {
- jump_insn = insn;
- jump_target = JUMP_LABEL (this_jump_insn);
- }
- }
- else
- break;
- }
-
- mark_referenced_resources (insn, &needed, 1);
- mark_set_resources (insn, &set, 0, 1);
-
- COPY_HARD_REG_SET (scratch, set.regs);
- AND_COMPL_HARD_REG_SET (scratch, needed.regs);
- AND_COMPL_HARD_REG_SET (res->regs, scratch);
- }
+ jump_insn = find_dead_or_set_registers (target, res, &jump_target, 0,
+ set, needed);
/* If we hit an unconditional branch, we have another way of finding out
what is live: we can see what is live at the branch target and include
anything used but not set before the branch. The only things that are
- live are those that are live using the above test and the test below.
-
- Don't try this if we expired our jump count above, since that would
- mean there may be an infinite loop in the function being compiled. */
+ live are those that are live using the above test and the test below. */
- if (jump_insn && jump_count < 10)
+ if (jump_insn)
{
struct resources new_resources;
rtx stop_insn = next_active_insn (jump_insn);
@@ -2796,15 +2992,14 @@ mark_target_live_regs (target, res)
through FINAL_SEQUENCE. */
static void
-fill_simple_delay_slots (first, non_jumps_p)
- rtx first;
+fill_simple_delay_slots (non_jumps_p)
int non_jumps_p;
{
register rtx insn, pat, trial, next_trial;
- register int i, j;
+ register int i;
int num_unfilled_slots = unfilled_slots_next - unfilled_slots_base;
struct resources needed, set;
- register int slots_to_fill, slots_filled;
+ int slots_to_fill, slots_filled;
rtx delay_list;
for (i = 0; i < num_unfilled_slots; i++)
@@ -2827,8 +3022,20 @@ fill_simple_delay_slots (first, non_jumps_p)
else
flags = get_jump_flags (insn, NULL_RTX);
slots_to_fill = num_delay_slots (insn);
+
+ /* Some machine description have defined instructions to have
+ delay slots only in certain circumstances which may depend on
+ nearby insns (which change due to reorg's actions).
+
+ For example, the PA port normally has delay slots for unconditional
+ jumps.
+
+ However, the PA port claims such jumps do not have a delay slot
+ if they are immediate successors of certain CALL_INSNs. This
+ allows the port to favor filling the delay slot of the call with
+ the unconditional jump. */
if (slots_to_fill == 0)
- abort ();
+ continue;
/* This insn needs, or can use, some delay slots. SLOTS_TO_FILL
says how many. After initialization, first try optimizing
@@ -2938,8 +3145,8 @@ fill_simple_delay_slots (first, non_jumps_p)
tail, of the list. */
update_reg_dead_notes (trial, insn);
- delay_list = gen_rtx (INSN_LIST, VOIDmode,
- trial, delay_list);
+ delay_list = gen_rtx_INSN_LIST (VOIDmode,
+ trial, delay_list);
update_block (trial, trial);
delete_insn (trial);
if (slots_to_fill == ++slots_filled)
@@ -3136,10 +3343,23 @@ fill_simple_delay_slots (first, non_jumps_p)
}
}
+ /* If this is an unconditional jump, then try to get insns from the
+ target of the jump. */
+ if (GET_CODE (insn) == JUMP_INSN
+ && simplejump_p (insn)
+ && slots_filled != slots_to_fill)
+ delay_list
+ = fill_slots_from_thread (insn, const_true_rtx,
+ next_active_insn (JUMP_LABEL (insn)),
+ NULL, 1, 1,
+ own_thread_p (JUMP_LABEL (insn),
+ JUMP_LABEL (insn), 0),
+ slots_to_fill, &slots_filled,
+ delay_list);
+
if (delay_list)
unfilled_slots_base[i]
- = emit_delay_sequence (insn, delay_list,
- slots_filled, slots_to_fill);
+ = emit_delay_sequence (insn, delay_list, slots_filled);
if (slots_to_fill == slots_filled)
unfilled_slots_base[i] = 0;
@@ -3181,6 +3401,14 @@ fill_simple_delay_slots (first, non_jumps_p)
else
SET_HARD_REG_BIT (needed.regs, STACK_POINTER_REGNUM);
+#ifdef EPILOGUE_USES
+ for (i = 0; i <FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (EPILOGUE_USES (i))
+ SET_HARD_REG_BIT (needed.regs, i);
+ }
+#endif
+
for (trial = get_last_insn (); ! stop_search_p (trial, 1);
trial = PREV_INSN (trial))
{
@@ -3206,8 +3434,8 @@ fill_simple_delay_slots (first, non_jumps_p)
insns we find on the head of the list. */
current_function_epilogue_delay_list
- = gen_rtx (INSN_LIST, VOIDmode, trial,
- current_function_epilogue_delay_list);
+ = gen_rtx_INSN_LIST (VOIDmode, trial,
+ current_function_epilogue_delay_list);
mark_referenced_resources (trial, &end_of_function_needs, 1);
update_block (trial, trial);
delete_insn (trial);
@@ -3255,18 +3483,18 @@ fill_simple_delay_slots (first, non_jumps_p)
static rtx
fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
- thread_if_true, own_thread, own_opposite_thread,
- slots_to_fill, pslots_filled)
+ thread_if_true, own_thread,
+ slots_to_fill, pslots_filled, delay_list)
rtx insn;
rtx condition;
rtx thread, opposite_thread;
int likely;
int thread_if_true;
- int own_thread, own_opposite_thread;
+ int own_thread;
int slots_to_fill, *pslots_filled;
+ rtx delay_list;
{
rtx new_thread;
- rtx delay_list = 0;
struct resources opposite_needed, set, needed;
rtx trial;
int lose = 0;
@@ -3283,7 +3511,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
/* If our thread is the end of subroutine, we can't get any delay
insns from that. */
if (thread == 0)
- return 0;
+ return delay_list;
/* If this is an unconditional branch, nothing is needed at the
opposite thread. Otherwise, compute what is needed there. */
@@ -3345,8 +3573,9 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
/* If TRIAL is redundant with some insn before INSN, we don't
actually need to add it to the delay list; we can merely pretend
we did. */
- if (prior_insn = redundant_insn (trial, insn, delay_list))
+ if ((prior_insn = redundant_insn (trial, insn, delay_list)))
{
+ fix_reg_dead_note (prior_insn, insn);
if (own_thread)
{
update_block (trial, thread);
@@ -3422,6 +3651,12 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
if (own_thread)
{
update_block (trial, thread);
+ if (trial == thread)
+ {
+ thread = next_active_insn (thread);
+ if (new_thread == trial)
+ new_thread = thread;
+ }
delete_insn (trial);
}
else
@@ -3433,6 +3668,8 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
delay_list = add_to_delay_list (temp, delay_list);
+ mark_set_resources (trial, &opposite_needed, 0, 1);
+
if (slots_to_fill == ++(*pslots_filled))
{
/* Even though we have filled all the slots, we
@@ -3443,8 +3680,16 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
&& ! insn_sets_resource_p (new_thread, &needed, 1)
&& ! insn_references_resource_p (new_thread,
&set, 1)
- && redundant_insn (new_thread, insn, delay_list))
- new_thread = next_active_insn (new_thread);
+ && (prior_insn
+ = redundant_insn (new_thread, insn,
+ delay_list)))
+ {
+ /* We know we do not own the thread, so no need
+ to call update_block and delete_insn. */
+ fix_reg_dead_note (prior_insn, insn);
+ update_reg_unused_notes (prior_insn, new_thread);
+ new_thread = next_active_insn (new_thread);
+ }
break;
}
@@ -3502,7 +3747,9 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
{
/* If this is the `true' thread, we will want to follow the jump,
so we can only do this if we have taken everything up to here. */
- if (thread_if_true && trial == new_thread)
+ if (thread_if_true && trial == new_thread
+ && ! insn_references_resource_p (XVECEXP (PATTERN (trial), 0, 0),
+ &opposite_needed, 0))
delay_list
= steal_delay_list_from_target (insn, condition, PATTERN (trial),
delay_list, &set, &needed,
@@ -3524,7 +3771,10 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
depend on the destination register. If so, try to place the opposite
arithmetic insn after the jump insn and put the arithmetic insn in the
delay slot. If we can't do this, return. */
- if (delay_list == 0 && likely && new_thread && GET_CODE (new_thread) == INSN)
+ if (delay_list == 0 && likely && new_thread
+ && GET_CODE (new_thread) == INSN
+ && GET_CODE (PATTERN (new_thread)) != ASM_INPUT
+ && asm_noperands (PATTERN (new_thread)) < 0)
{
rtx pat = PATTERN (new_thread);
rtx dest;
@@ -3550,13 +3800,13 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
the negated constant. Otherwise, reverse the sense of the
arithmetic. */
if (GET_CODE (other) == CONST_INT)
- new_arith = gen_rtx (GET_CODE (src), GET_MODE (src), dest,
- negate_rtx (GET_MODE (src), other));
+ new_arith = gen_rtx_fmt_ee (GET_CODE (src), GET_MODE (src), dest,
+ negate_rtx (GET_MODE (src), other));
else
- new_arith = gen_rtx (GET_CODE (src) == PLUS ? MINUS : PLUS,
- GET_MODE (src), dest, other);
+ new_arith = gen_rtx_fmt_ee (GET_CODE (src) == PLUS ? MINUS : PLUS,
+ GET_MODE (src), dest, other);
- ninsn = emit_insn_after (gen_rtx (SET, VOIDmode, dest, new_arith),
+ ninsn = emit_insn_after (gen_rtx_SET (VOIDmode, dest, new_arith),
insn);
if (recog_memoized (ninsn) < 0
@@ -3570,6 +3820,12 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
if (own_thread)
{
update_block (trial, thread);
+ if (trial == thread)
+ {
+ thread = next_active_insn (thread);
+ if (new_thread == trial)
+ new_thread = thread;
+ }
delete_insn (trial);
}
else
@@ -3629,8 +3885,7 @@ fill_slots_from_thread (insn, condition, thread, opposite_thread, likely,
if safe. */
static void
-fill_eager_delay_slots (first)
- rtx first;
+fill_eager_delay_slots ()
{
register rtx insn;
register int i;
@@ -3653,8 +3908,19 @@ fill_eager_delay_slots (first)
continue;
slots_to_fill = num_delay_slots (insn);
+ /* Some machine description have defined instructions to have
+ delay slots only in certain circumstances which may depend on
+ nearby insns (which change due to reorg's actions).
+
+ For example, the PA port normally has delay slots for unconditional
+ jumps.
+
+ However, the PA port claims such jumps do not have a delay slot
+ if they are immediate successors of certain CALL_INSNs. This
+ allows the port to favor filling the delay slot of the call with
+ the unconditional jump. */
if (slots_to_fill == 0)
- abort ();
+ continue;
slots_filled = 0;
target_label = JUMP_LABEL (insn);
@@ -3692,8 +3958,8 @@ fill_eager_delay_slots (first)
delay_list
= fill_slots_from_thread (insn, condition, insn_at_target,
fallthrough_insn, prediction == 2, 1,
- own_target, own_fallthrough,
- slots_to_fill, &slots_filled);
+ own_target,
+ slots_to_fill, &slots_filled, delay_list);
if (delay_list == 0 && own_fallthrough)
{
@@ -3707,8 +3973,9 @@ fill_eager_delay_slots (first)
delay_list
= fill_slots_from_thread (insn, condition, fallthrough_insn,
insn_at_target, 0, 0,
- own_fallthrough, own_target,
- slots_to_fill, &slots_filled);
+ own_fallthrough,
+ slots_to_fill, &slots_filled,
+ delay_list);
}
}
else
@@ -3717,21 +3984,22 @@ fill_eager_delay_slots (first)
delay_list
= fill_slots_from_thread (insn, condition, fallthrough_insn,
insn_at_target, 0, 0,
- own_fallthrough, own_target,
- slots_to_fill, &slots_filled);
+ own_fallthrough,
+ slots_to_fill, &slots_filled,
+ delay_list);
if (delay_list == 0)
delay_list
= fill_slots_from_thread (insn, condition, insn_at_target,
next_active_insn (insn), 0, 1,
- own_target, own_fallthrough,
- slots_to_fill, &slots_filled);
+ own_target,
+ slots_to_fill, &slots_filled,
+ delay_list);
}
if (delay_list)
unfilled_slots_base[i]
- = emit_delay_sequence (insn, delay_list,
- slots_filled, slots_to_fill);
+ = emit_delay_sequence (insn, delay_list, slots_filled);
if (slots_to_fill == slots_filled)
unfilled_slots_base[i] = 0;
@@ -3903,11 +4171,20 @@ relax_delay_slots (first)
if (trial && GET_CODE (PATTERN (trial)) != SEQUENCE
&& redundant_insn (trial, insn, 0))
{
- trial = next_active_insn (trial);
- if (trial == 0)
- target_label = find_end_label ();
- else
- target_label = get_label_before (trial);
+ rtx tmp;
+
+ /* Figure out where to emit the special USE insn so we don't
+ later incorrectly compute register live/death info. */
+ tmp = next_active_insn (trial);
+ if (tmp == 0)
+ tmp = find_end_label ();
+
+ /* Insert the special USE insn and update dataflow info. */
+ update_block (trial, tmp);
+
+ /* Now emit a label before the special USE insn, and
+ redirect our jump to the new label. */
+ target_label = get_label_before (PREV_INSN (tmp));
reorg_redirect_jump (delay_insn, target_label);
next = insn;
continue;
@@ -4167,8 +4444,8 @@ make_return_insns (first)
if (--LABEL_NUSES (real_return_label) == 0)
delete_insn (real_return_label);
- fill_simple_delay_slots (first, 1);
- fill_simple_delay_slots (first, 0);
+ fill_simple_delay_slots (1);
+ fill_simple_delay_slots (0);
}
#endif
@@ -4271,13 +4548,16 @@ dbr_schedule (first, file)
else
SET_HARD_REG_BIT (end_of_function_needs.regs, STACK_POINTER_REGNUM);
- if (current_function_return_rtx != 0
- && GET_CODE (current_function_return_rtx) == REG)
+ if (current_function_return_rtx != 0)
mark_referenced_resources (current_function_return_rtx,
&end_of_function_needs, 1);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (global_regs[i])
+ if (global_regs[i]
+#ifdef EPILOGUE_USES
+ || EPILOGUE_USES (i)
+#endif
+ )
SET_HARD_REG_BIT (end_of_function_needs.regs, i);
/* The registers required to be live at the end of the function are
@@ -4299,7 +4579,7 @@ dbr_schedule (first, file)
start_of_epilogue_needs = end_of_function_needs;
- while (epilogue_insn = next_nonnote_insn (epilogue_insn))
+ while ((epilogue_insn = next_nonnote_insn (epilogue_insn)))
mark_set_resources (epilogue_insn, &end_of_function_needs, 0, 1);
/* Show we haven't computed an end-of-function label yet. */
@@ -4326,9 +4606,9 @@ dbr_schedule (first, file)
reorg_pass_number < MAX_REORG_PASSES;
reorg_pass_number++)
{
- fill_simple_delay_slots (first, 1);
- fill_simple_delay_slots (first, 0);
- fill_eager_delay_slots (first);
+ fill_simple_delay_slots (1);
+ fill_simple_delay_slots (0);
+ fill_eager_delay_slots ();
relax_delay_slots (first);
}
@@ -4393,5 +4673,23 @@ dbr_schedule (first, file)
}
}
}
+
+ /* For all JUMP insns, fill in branch prediction notes, so that during
+ assembler output a target can set branch prediction bits in the code.
+ We have to do this now, as up until this point the destinations of
+ JUMPS can be moved around and changed, but past right here that cannot
+ happen. */
+ for (insn = first; insn; insn = NEXT_INSN (insn))
+ {
+ int pred_flags;
+
+ if (GET_CODE (insn) != JUMP_INSN)
+ continue;
+
+ pred_flags = get_jump_flags (insn, JUMP_LABEL (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_BR_PRED,
+ GEN_INT (pred_flags),
+ REG_NOTES (insn));
+ }
}
#endif /* DELAY_SLOTS */
diff --git a/contrib/gcc/rtl.c b/contrib/gcc/rtl.c
index 3063d3e..396566d 100644
--- a/contrib/gcc/rtl.c
+++ b/contrib/gcc/rtl.c
@@ -1,5 +1,5 @@
/* Allocate and read RTL for GNU C Compiler.
- Copyright (C) 1987, 1988, 1991, 1994 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1991, 1994, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,10 +20,10 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
-#include <ctype.h>
-#include <stdio.h>
+#include "system.h"
#include "rtl.h"
#include "real.h"
+#include "bitmap.h"
#include "obstack.h"
#define obstack_chunk_alloc xmalloc
@@ -36,10 +36,6 @@ Boston, MA 02111-1307, USA. */
During optimization and output, this is function_obstack. */
extern struct obstack *rtl_obstack;
-
-#if HOST_BITS_PER_WIDE_INT != HOST_BITS_PER_INT
-extern long atol();
-#endif
/* Indexed by rtx code, gives number of operands for an rtx with that code.
Does NOT include rtx header data (code and links).
@@ -148,7 +144,9 @@ char *rtx_format[] = {
"V" like "E", but optional:
the containing rtx may end before this operand
"u" a pointer to another insn
- prints the uid of the insn. */
+ prints the uid of the insn.
+ "b" is a pointer to a bitmap header.
+ "t" is a tree pointer. */
#define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) FORMAT ,
#include "rtl.def" /* rtl expressions are defined here */
@@ -172,14 +170,22 @@ char *note_insn_name[] = { 0 , "NOTE_INSN_DELETED",
"NOTE_INSN_FUNCTION_END", "NOTE_INSN_SETJMP",
"NOTE_INSN_LOOP_CONT", "NOTE_INSN_LOOP_VTOP",
"NOTE_INSN_PROLOGUE_END", "NOTE_INSN_EPILOGUE_BEG",
- "NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG"};
+ "NOTE_INSN_DELETED_LABEL", "NOTE_INSN_FUNCTION_BEG",
+ "NOTE_INSN_EH_REGION_BEG", "NOTE_INSN_EH_REGION_END",
+ "NOTE_REPEATED_LINE_NUMBER", "NOTE_INSN_RANGE_START",
+ "NOTE_INSN_RANGE_END", "NOTE_INSN_LIVE" };
char *reg_note_name[] = { "", "REG_DEAD", "REG_INC", "REG_EQUIV", "REG_WAS_0",
"REG_EQUAL", "REG_RETVAL", "REG_LIBCALL",
"REG_NONNEG", "REG_NO_CONFLICT", "REG_UNUSED",
"REG_CC_SETTER", "REG_CC_USER", "REG_LABEL",
- "REG_DEP_ANTI", "REG_DEP_OUTPUT" };
+ "REG_DEP_ANTI", "REG_DEP_OUTPUT", "REG_BR_PROB",
+ "REG_EXEC_COUNT", "REG_NOALIAS", "REG_SAVE_AREA",
+ "REG_BR_PRED", "REG_EH_CONTEXT" };
+static void dump_and_abort PROTO((int, int, FILE *));
+static void read_name PROTO((char *, FILE *));
+
/* Allocate an rtx vector of N elements.
Store the length, and initialize all elements to zero. */
@@ -195,9 +201,10 @@ rtvec_alloc (n)
+ (( n - 1) * sizeof (rtunion)));
/* clear out the vector */
- PUT_NUM_ELEM(rt, n);
- for (i=0; i < n; i++)
- rt->elem[i].rtvec = NULL; /* @@ not portable due to rtunion */
+ PUT_NUM_ELEM (rt, n);
+
+ for (i = 0; i < n; i++)
+ rt->elem[i].rtwint = 0;
return rt;
}
@@ -278,7 +285,8 @@ copy_rtx (orig)
case PC:
case CC0:
case SCRATCH:
- /* SCRATCH must be shared because they represent distinct values. */
+ /* SCRATCH must be shared because they represent distinct values. */
+ case ADDRESSOF:
return orig;
case CONST:
@@ -294,6 +302,9 @@ copy_rtx (orig)
the constant address may need to be reloaded. If the mem is shared,
then reloading one copy of this mem will cause all copies to appear
to have been reloaded. */
+
+ default:
+ break;
}
copy = rtx_alloc (code);
@@ -331,6 +342,18 @@ copy_rtx (orig)
}
break;
+ case 'b':
+ {
+ bitmap new_bits = BITMAP_OBSTACK_ALLOC (rtl_obstack);
+ bitmap_copy (new_bits, XBITMAP (orig, i));
+ XBITMAP (copy, i) = new_bits;
+ break;
+ }
+
+ case 't':
+ XTREE (copy, i) = XTREE (orig, i);
+ break;
+
case 'w':
XWINT (copy, i) = XWINT (orig, i);
break;
@@ -380,6 +403,8 @@ copy_most_rtx (orig, may_share)
case PC:
case CC0:
return orig;
+ default:
+ break;
}
copy = rtx_alloc (code);
@@ -477,13 +502,14 @@ read_skip_spaces (infile)
FILE *infile;
{
register int c;
- while (c = getc (infile))
+ while ((c = getc (infile)))
{
if (c == ' ' || c == '\n' || c == '\t' || c == '\f')
;
else if (c == ';')
{
- while ((c = getc (infile)) && c != '\n') ;
+ while ((c = getc (infile)) && c != '\n' && c != EOF)
+ ;
}
else if (c == '/')
{
@@ -493,7 +519,7 @@ read_skip_spaces (infile)
dump_and_abort ('*', c, infile);
prevc = 0;
- while (c = getc (infile))
+ while ((c = getc (infile)) && c != EOF)
{
if (prevc == '*' && c == '/')
break;
@@ -541,6 +567,43 @@ read_name (str, infile)
*p = 0;
}
+/* Provide a version of a function to read a long long if the system does
+ not provide one. */
+#if HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_LONG && !defined(HAVE_ATOLL) && !defined(HAVE_ATOQ)
+HOST_WIDE_INT
+atoll(p)
+ const char *p;
+{
+ int neg = 0;
+ HOST_WIDE_INT tmp_wide;
+
+ while (ISSPACE(*p))
+ p++;
+ if (*p == '-')
+ neg = 1, p++;
+ else if (*p == '+')
+ p++;
+
+ tmp_wide = 0;
+ while (ISDIGIT(*p))
+ {
+ HOST_WIDE_INT new_wide = tmp_wide*10 + (*p - '0');
+ if (new_wide < tmp_wide)
+ {
+ /* Return INT_MAX equiv on overflow. */
+ tmp_wide = (~(unsigned HOST_WIDE_INT)0) >> 1;
+ break;
+ }
+ tmp_wide = new_wide;
+ p++;
+ }
+
+ if (neg)
+ tmp_wide = -tmp_wide;
+ return tmp_wide;
+}
+#endif
+
/* Read an rtx in printed representation from INFILE
and return an actual rtx in core constructed accordingly.
read_rtx is not used in the compiler proper, but rather in
@@ -648,7 +711,7 @@ read_rtx (infile)
case 'E':
{
register struct rtx_list *next_rtx, *rtx_list_link;
- struct rtx_list *list_rtx;
+ struct rtx_list *list_rtx = NULL;
c = read_skip_spaces (infile);
if (c != '[')
@@ -748,7 +811,17 @@ read_rtx (infile)
#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
tmp_wide = atoi (tmp_char);
#else
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
tmp_wide = atol (tmp_char);
+#else
+ /* Prefer atoll over atoq, since the former is in the ISO C9X draft.
+ But prefer not to use our hand-rolled function above either. */
+#if defined(HAVE_ATOLL) || !defined(HAVE_ATOQ)
+ tmp_wide = atoll (tmp_char);
+#else
+ tmp_wide = atoq (tmp_char);
+#endif
+#endif
#endif
XWINT (return_rtx, i) = tmp_wide;
break;
@@ -838,14 +911,3 @@ init_rtl ()
}
}
}
-
-#ifdef memset
-gcc_memset (dest, value, len)
- char *dest;
- int value;
- int len;
-{
- while (len-- > 0)
- *dest++ = value;
-}
-#endif /* memset */
diff --git a/contrib/gcc/rtl.def b/contrib/gcc/rtl.def
index acb3a7d..1e45157 100644
--- a/contrib/gcc/rtl.def
+++ b/contrib/gcc/rtl.def
@@ -1,7 +1,7 @@
/* This file contains the definitions and documentation for the
Register Transfer Expressions (rtx's) that make up the
Register Transfer Language (rtl) used in the Back End of the GNU compiler.
- Copyright (C) 1987, 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92, 94, 95, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -54,6 +54,7 @@ Boston, MA 02111-1307, USA. */
"b" an rtx code for a bit-field operation (ZERO_EXTRACT, SIGN_EXTRACT)
"i" an rtx code for a machine insn (INSN, JUMP_INSN, CALL_INSN)
"m" an rtx code for something that matches in insns (e.g, MATCH_DUP)
+ "g" an rtx code for grouping insns together (e.g, GROUP_PARALLEL)
"x" everything else
*/
@@ -102,7 +103,7 @@ DEF_RTL_EXPR(INSN_LIST, "insn_list", "ue", 'x')
'=' to indicate the operand is only written to.
'+' to indicate the operand is both read and written to.
- Each character in the string represents an allocatable class for an operand.
+ Each character in the string represents an allocable class for an operand.
'g' indicates the operand can be any valid class.
'i' indicates the operand can be immediate (in the instruction) data.
'r' indicates the operand can be in a register.
@@ -160,6 +161,16 @@ DEF_RTL_EXPR(MATCH_OP_DUP, "match_op_dup", "iE", 'm')
DEF_RTL_EXPR(MATCH_PAR_DUP, "match_par_dup", "iE", 'm')
/* Appears only in machine descriptions.
+ Should be used only in attribute tests.
+ The predicate in operand 0 is applied to the whole insn being checked. */
+DEF_RTL_EXPR(MATCH_INSN, "match_insn", "s", 'm')
+
+/* Appears only in machine descriptions.
+ Operand 0 is the operand number, as in match_operand.
+ Operand 1 is the predicate to apply to the insn. */
+DEF_RTL_EXPR(MATCH_INSN2, "match_insn2", "is", 'm')
+
+/* Appears only in machine descriptions.
Defines the pattern for one kind of instruction.
Operand:
0: names this instruction.
@@ -257,7 +268,7 @@ DEF_RTL_EXPR(DEFINE_DELAY, "define_delay", "eE", 'x')
unit with no issue constraints. If only one operation can
be executed a time and the unit is busy for the entire time,
the 3rd operand should be specified as 1, the 6th operand
- sould be specified as 0, and the 7th operand should not
+ should be specified as 0, and the 7th operand should not
be specified.
If this operand is specified, it is a list of attribute
@@ -368,8 +379,8 @@ DEF_RTL_EXPR(BARRIER, "barrier", "iuu", 'x')
3: is a number that is unique in the entire compilation.
4: is the user-given name of the label, if any.
5: is used in jump.c for the use-count of the label.
- and in flow.c to point to the chain of label_ref's to this label. */
-DEF_RTL_EXPR(CODE_LABEL, "code_label", "iuuis0", 'x')
+ 6: is used in flow.c to point to the chain of label_ref's to this label. */
+DEF_RTL_EXPR(CODE_LABEL, "code_label", "iuuis00", 'x')
/* Say where in the code a source line starts, for symbol table's sake.
Contains a filename and a line number. Line numbers <= 0 are special:
@@ -385,7 +396,7 @@ DEF_RTL_EXPR(NOTE, "note", "iuusn", 'x')
it contains helps to build the mapping function between the rtx's of
the function to be inlined and the current function being expanded. */
-DEF_RTL_EXPR(INLINE_HEADER, "inline_header", "iuuuiiiiiieeiiEe", 'x')
+DEF_RTL_EXPR(INLINE_HEADER, "inline_header", "iuuuiiiiiieeiiEeEssE", 'x')
/* ----------------------------------------------------------------------
Top level constituents of INSN, JUMP_INSN and CALL_INSN.
@@ -437,8 +448,27 @@ DEF_RTL_EXPR(ADDR_VEC, "addr_vec", "E", 'x')
/* Vector of address differences X0 - BASE, X1 - BASE, ...
First operand is BASE; the vector contains the X's.
The machine mode of this rtx says how much space to leave
- for each difference. */
-DEF_RTL_EXPR(ADDR_DIFF_VEC, "addr_diff_vec", "eE", 'x')
+ for each difference and is adjusted by branch shortening if
+ CASE_VECTOR_SHORTEN_MODE is defined.
+ The third and fourth operands store the target labels with the
+ minimum and maximum addresses respectively.
+ The fifth operand stores flags for use by branch shortening.
+ Set at the start of shorten_branches:
+ min_align: the minimum alignment for any of the target labels.
+ base_after_vec: true iff BASE is after the ADDR_DIFF_VEC.
+ min_after_vec: true iff minimum addr target label is after the ADDR_DIFF_VEC.
+ max_after_vec: true iff maximum addr target label is after the ADDR_DIFF_VEC.
+ min_after_base: true iff minimum address target label is after BASE.
+ max_after_base: true iff maximum address target label is after BASE.
+ Set by the actual branch shortening process:
+ offset_unsigned: true iff offsets have to be treated as unsigned.
+ scale: scaling that is necessary to make offsets fit into the mode.
+
+ The third, fourth and fifth operands are only valid when
+ CASE_VECTOR_SHORTEN_MODE is defined, and only in an optimizing
+ compilations. */
+
+DEF_RTL_EXPR(ADDR_DIFF_VEC, "addr_diff_vec", "eEeei", 'x')
/* ----------------------------------------------------------------------
At the top level of an instruction (perhaps under PARALLEL).
@@ -476,7 +506,7 @@ DEF_RTL_EXPR(RETURN, "return", "", 'x')
Operand 1 is the condition.
Operand 2 is the trap code.
For an unconditional trap, make the condition (const_int 1). */
-DEF_RTL_EXPR(TRAP_IF, "trap_if", "ei", 'x')
+DEF_RTL_EXPR(TRAP_IF, "trap_if", "ee", 'x')
/* ----------------------------------------------------------------------
Primitive values for use in expressions.
@@ -507,10 +537,16 @@ DEF_RTL_EXPR(CONST, "const", "e", 'o')
by a SET whose first operand is (PC). */
DEF_RTL_EXPR(PC, "pc", "", 'o')
-/* A register. The "operand" is the register number, accessed
- with the REGNO macro. If this number is less than FIRST_PSEUDO_REGISTER
- than a hardware register is being referred to. */
-DEF_RTL_EXPR(REG, "reg", "i", 'o')
+/* A register. The "operand" is the register number, accessed with
+ the REGNO macro. If this number is less than FIRST_PSEUDO_REGISTER
+ than a hardware register is being referred to. The second operand
+ doesn't really exist. Unfortunately, however, the compiler
+ implicitly assumes that a REG can be transformed in place into a
+ MEM, and therefore that a REG is at least as big as a MEM. To
+ avoid this memory overhead, which is likely to be substantial,
+ search for uses of PUT_CODE that turn REGs into MEMs, and fix them
+ somehow. Then, the trailing `0' can be removed here. */
+DEF_RTL_EXPR(REG, "reg", "i0", 'o')
/* A scratch register. This represents a register used only within a
single insn. It will be turned into a REG during register allocation
@@ -548,9 +584,11 @@ DEF_RTL_EXPR(STRICT_LOW_PART, "strict_low_part", "e", 'x')
in DECL_RTLs and during RTL generation, but not in the insn chain. */
DEF_RTL_EXPR(CONCAT, "concat", "ee", 'o')
-/* A memory location; operand is the address.
- Can be nested inside a VOLATILE. */
-DEF_RTL_EXPR(MEM, "mem", "e", 'o')
+/* A memory location; operand is the address. Can be nested inside a
+ VOLATILE. The second operand is the alias set to which this MEM
+ belongs. We use `0' instead of `i' for this field so that the
+ field need not be specified in machine descriptions. */
+DEF_RTL_EXPR(MEM, "mem", "e0", 'o')
/* Reference to an assembler label in the code for this function.
The operand is a CODE_LABEL found in the insn chain.
@@ -571,6 +609,15 @@ DEF_RTL_EXPR(SYMBOL_REF, "symbol_ref", "s", 'o')
pretend to be looking at the entire value and comparing it. */
DEF_RTL_EXPR(CC0, "cc0", "", 'o')
+/* Reference to the address of a register. Removed by purge_addressof after
+ CSE has elided as many as possible.
+ 1st operand: the register we may need the address of.
+ 2nd operand: the original pseudo regno we were generated for.
+ 3rd operand: the decl for the object in the register, for
+ put_reg_in_stack. */
+
+DEF_RTL_EXPR(ADDRESSOF, "addressof", "ei0", 'o')
+
/* =====================================================================
A QUEUED expression really points to a member of the queue of instructions
to be output later for postincrement/postdecrement.
@@ -757,9 +804,51 @@ DEF_RTL_EXPR(HIGH, "high", "e", 'o')
of a constant expression. */
DEF_RTL_EXPR(LO_SUM, "lo_sum", "ee", 'o')
+/* Header for range information. Operand 0 is the NOTE_INSN_RANGE_START insn.
+ Operand 1 is the NOTE_INSN_RANGE_END insn. Operand 2 is a vector of all of
+ the registers that can be substituted within this range. Operand 3 is the
+ number of calls in the range. Operand 4 is the number of insns in the
+ range. Operand 5 is the unique range number for this range. Operand 6 is
+ the basic block # of the start of the live range. Operand 7 is the basic
+ block # of the end of the live range. Operand 8 is the loop depth. Operand
+ 9 is a bitmap of the registers live at the start of the range. Operand 10
+ is a bitmap of the registers live at the end of the range. Operand 11 is
+ marker number for the start of the range. Operand 12 is the marker number
+ for the end of the range. */
+DEF_RTL_EXPR(RANGE_INFO, "range_info", "uuEiiiiiibbii", 'x')
+
+/* Registers that can be substituted within the range. Operand 0 is the
+ original pseudo register number. Operand 1 will be filled in with the
+ pseudo register the value is copied for the duration of the range. Operand
+ 2 is the number of references within the range to the register. Operand 3
+ is the number of sets or clobbers of the register in the range. Operand 4
+ is the number of deaths the register has. Operand 5 is the copy flags that
+ give the status of whether a copy is needed from the original register to
+ the new register at the beginning of the range, or whether a copy from the
+ new register back to the original at the end of the range. Operand 6 is the
+ live length. Operand 7 is the number of calls that this register is live
+ across. Operand 8 is the symbol node of the variable if the register is a
+ user variable. Operand 9 is the block node that the variable is declared
+ in if the register is a user variable. */
+DEF_RTL_EXPR(RANGE_REG, "range_reg", "iiiiiiiitt", 'x')
+
+/* Information about a local variable's ranges. Operand 0 is an EXPR_LIST of
+ the different ranges a variable is in where it is copied to a different
+ pseudo register. Operand 1 is the block that the variable is declared in.
+ Operand 2 is the number of distinct ranges. */
+DEF_RTL_EXPR(RANGE_VAR, "range_var", "eti", 'x')
+
+/* Information about the registers that are live at the current point. Operand
+ 0 is the live bitmap. Operand 1 is the original block number. */
+DEF_RTL_EXPR(RANGE_LIVE, "range_live", "bi", 'x')
+
+/* A unary `__builtin_constant_p' expression. These are only emitted
+ during RTL generation, and then only if optimize > 0. They are
+ eliminated by the first CSE pass. */
+DEF_RTL_EXPR(CONSTANT_P_RTX, "constant_p", "e", 'x')
+
/*
Local variables:
mode:c
-version-control: t
End:
*/
diff --git a/contrib/gcc/rtl.h b/contrib/gcc/rtl.h
index b757aec..4aa25b2 100644
--- a/contrib/gcc/rtl.h
+++ b/contrib/gcc/rtl.h
@@ -1,5 +1,5 @@
/* Register Transfer Language (RTL) definitions for GNU C-Compiler
- Copyright (C) 1987, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 91-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -18,6 +18,8 @@ along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#ifndef _RTL_H
+#define _RTL_H
#include "machmode.h"
@@ -47,17 +49,35 @@ enum rtx_code {
/* The cast here, saves many elsewhere. */
extern int rtx_length[];
-#define GET_RTX_LENGTH(CODE) (rtx_length[(int)(CODE)])
+#define GET_RTX_LENGTH(CODE) (rtx_length[(int) (CODE)])
extern char *rtx_name[];
-#define GET_RTX_NAME(CODE) (rtx_name[(int)(CODE)])
+#define GET_RTX_NAME(CODE) (rtx_name[(int) (CODE)])
extern char *rtx_format[];
-#define GET_RTX_FORMAT(CODE) (rtx_format[(int)(CODE)])
+#define GET_RTX_FORMAT(CODE) (rtx_format[(int) (CODE)])
extern char rtx_class[];
-#define GET_RTX_CLASS(CODE) (rtx_class[(int)(CODE)])
+#define GET_RTX_CLASS(CODE) (rtx_class[(int) (CODE)])
+/* The flags and bitfields of an ADDR_DIFF_VEC. BASE is the base label
+ relative to which the offsets are calculated, as explained in rtl.def. */
+typedef struct
+{
+ /* Set at the start of shorten_branches - ONLY WHEN OPTIMIZING - : */
+ unsigned min_align: 8;
+ /* Flags: */
+ unsigned base_after_vec: 1; /* BASE is after the ADDR_DIFF_VEC. */
+ unsigned min_after_vec: 1; /* minimum address target label is after the ADDR_DIFF_VEC. */
+ unsigned max_after_vec: 1; /* maximum address target label is after the ADDR_DIFF_VEC. */
+ unsigned min_after_base: 1; /* minimum address target label is after BASE. */
+ unsigned max_after_base: 1; /* maximum address target label is after BASE. */
+ /* Set by the actual branch shortening process - ONLY WHEN OPTIMIZING - : */
+ unsigned offset_unsigned: 1; /* offsets have to be treated as unsigned. */
+ unsigned : 2;
+ unsigned scale : 8;
+} addr_diff_vec_flags;
+
/* Common union for an element of an rtx. */
typedef union rtunion_def
@@ -68,6 +88,9 @@ typedef union rtunion_def
struct rtx_def *rtx;
struct rtvec_def *rtvec;
enum machine_mode rttype;
+ addr_diff_vec_flags rt_addr_diff_vec_flags;
+ struct bitmap_head_def *rtbit;
+ union tree_node *rttree;
} rtunion;
/* RTL expression ("rtx"). */
@@ -113,7 +136,7 @@ typedef struct rtx_def
In a SYMBOL_REF, this flag is used for machine-specific purposes.
In a LABEL_REF or in a REG_LABEL note, this is LABEL_REF_NONLOCAL_P. */
unsigned int volatil : 1;
- /* 1 in a MEM referring to a field of a structure (not a union!).
+ /* 1 in a MEM referring to a field of an aggregate.
0 if the MEM was a variable or the result of a * operator in C;
1 if it was the result of a . or -> operator (on a struct) in C.
1 in a REG if the register is used only in exit code a loop.
@@ -140,62 +163,20 @@ typedef struct rtx_def
In a REG, nonzero means this reg refers to the return value
of the current function. */
unsigned integrated : 1;
+ /* Nonzero if this rtx is related to the call frame, either changing how
+ we compute the frame address or saving and restoring registers in
+ the prologue and epilogue. */
+ unsigned frame_related : 1;
/* The first element of the operands of this rtx.
The number of operands and their types are controlled
by the `code' field, according to rtl.def. */
rtunion fld[1];
} *rtx;
-
-/* Add prototype support. */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
-#ifndef VPROTO
-#ifdef __STDC__
-#define PVPROTO(ARGS) ARGS
-#define VPROTO(ARGS) ARGS
-#define VA_START(va_list,var) va_start(va_list,var)
-#else
-#define PVPROTO(ARGS) ()
-#define VPROTO(ARGS) (va_alist) va_dcl
-#define VA_START(va_list,var) va_start(va_list)
-#endif
-#endif
-
-#ifndef STDIO_PROTO
-#ifdef BUFSIZ
-#define STDIO_PROTO(ARGS) PROTO(ARGS)
-#else
-#define STDIO_PROTO(ARGS) ()
-#endif
-#endif
+#include "gansidecl.h"
#define NULL_RTX (rtx) 0
-/* Define a generic NULL if one hasn't already been defined. */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
-#endif
-#endif
-
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
-#endif
-
/* Define macros to access the `code' field of the rtx. */
#ifdef SHORT_ENUM_BUG
@@ -211,20 +192,21 @@ typedef struct rtx_def
#define RTX_INTEGRATED_P(RTX) ((RTX)->integrated)
#define RTX_UNCHANGING_P(RTX) ((RTX)->unchanging)
+#define RTX_FRAME_RELATED_P(RTX) ((RTX)->frame_related)
/* RTL vector. These appear inside RTX's when there is a need
for a variable number of things. The principle use is inside
PARALLEL expressions. */
typedef struct rtvec_def{
- unsigned num_elem; /* number of elements */
+ int num_elem; /* number of elements */
rtunion elem[1];
} *rtvec;
#define NULL_RTVEC (rtvec) 0
#define GET_NUM_ELEM(RTVEC) ((RTVEC)->num_elem)
-#define PUT_NUM_ELEM(RTVEC, NUM) ((RTVEC)->num_elem = (unsigned) NUM)
+#define PUT_NUM_ELEM(RTVEC, NUM) ((RTVEC)->num_elem = (NUM))
#define RTVEC_ELT(RTVEC, I) ((RTVEC)->elem[(I)].rtx)
@@ -237,7 +219,8 @@ typedef struct rtvec_def{
#define CONSTANT_P(X) \
(GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
|| GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE \
- || GET_CODE (X) == CONST || GET_CODE (X) == HIGH)
+ || GET_CODE (X) == CONST || GET_CODE (X) == HIGH \
+ || GET_CODE (X) == CONSTANT_P_RTX)
/* General accessor macros for accessing the fields of an rtx. */
@@ -248,6 +231,9 @@ typedef struct rtvec_def{
#define XVEC(RTX, N) ((RTX)->fld[N].rtvec)
#define XVECLEN(RTX, N) ((RTX)->fld[N].rtvec->num_elem)
#define XVECEXP(RTX,N,M)((RTX)->fld[N].rtvec->elem[M].rtx)
+#define XBITMAP(RTX, N) ((RTX)->fld[N].rtbit)
+#define XTREE(RTX, N) ((RTX)->fld[N].rttree)
+
/* ACCESS MACROS for particular fields of insns. */
@@ -298,13 +284,15 @@ typedef struct rtvec_def{
not needed past this insn). If REG is set in this insn, the REG_DEAD
note may, but need not, be omitted.
REG_INC means that the REG is autoincremented or autodecremented.
- REG_EQUIV describes the insn as a whole; it says that the
- insn sets a register to a constant value or to be equivalent to
- a memory address. If the
- register is spilled to the stack then the constant value
- should be substituted for it. The contents of the REG_EQUIV
+ REG_EQUIV describes the insn as a whole; it says that the insn
+ sets a register to a constant value or to be equivalent to a memory
+ address. If the register is spilled to the stack then the constant
+ value should be substituted for it. The contents of the REG_EQUIV
is the constant value or memory address, which may be different
- from the source of the SET although it has the same value.
+ from the source of the SET although it has the same value. A
+ REG_EQUIV note may also appear on an insn which copies a register
+ parameter to a pseudo-register, if there is a memory address which
+ could be used to hold that pseudo-register throughout the function.
REG_EQUAL is like REG_EQUIV except that the destination
is only momentarily equal to the specified rtx. Therefore, it
cannot be used for substitution; but it can be used for cse.
@@ -340,15 +328,33 @@ typedef struct rtvec_def{
dependencies. REG_DEP_OUTPUT is used in LOG_LINKS which represent output
(write after write) dependencies. Data dependencies, which are the only
type of LOG_LINK created by flow, are represented by a 0 reg note kind. */
+/* REG_BR_PROB is attached to JUMP_INSNs and CALL_INSNs when the flag
+ -fbranch-probabilities is given. It has an integer value. For jumps,
+ it is the probability that this is a taken branch. For calls, it is the
+ probability that this call won't return.
+ REG_EXEC_COUNT is attached to the first insn of each basic block, and
+ the first insn after each CALL_INSN. It indicates how many times this
+ block was executed.
+ REG_SAVE_AREA is used to optimize rtl generated by dynamic stack
+ allocations for targets where SETJMP_VIA_SAVE_AREA is true.
+ REG_BR_PRED is attached to JUMP_INSNs only, it holds the branch prediction
+ flags computed by get_jump_flags() after dbr scheduling is complete. */
+
#define REG_NOTES(INSN) ((INSN)->fld[6].rtx)
+#define ADDR_DIFF_VEC_FLAGS(RTX) ((RTX)->fld[4].rt_addr_diff_vec_flags)
+
/* Don't forget to change reg_note_name in rtl.c. */
enum reg_note { REG_DEAD = 1, REG_INC = 2, REG_EQUIV = 3, REG_WAS_0 = 4,
REG_EQUAL = 5, REG_RETVAL = 6, REG_LIBCALL = 7,
REG_NONNEG = 8, REG_NO_CONFLICT = 9, REG_UNUSED = 10,
REG_CC_SETTER = 11, REG_CC_USER = 12, REG_LABEL = 13,
- REG_DEP_ANTI = 14, REG_DEP_OUTPUT = 15 };
+ REG_DEP_ANTI = 14, REG_DEP_OUTPUT = 15, REG_BR_PROB = 16,
+ REG_EXEC_COUNT = 17, REG_NOALIAS = 18, REG_SAVE_AREA = 19,
+ REG_BR_PRED = 20, REG_EH_CONTEXT = 21 };
+/* The base value for branch probability notes. */
+#define REG_BR_PROB_BASE 10000
/* Define macros to extract and insert the reg-note kind in an EXPR_LIST. */
#define REG_NOTE_KIND(LINK) ((enum reg_note) GET_MODE (LINK))
@@ -357,7 +363,7 @@ enum reg_note { REG_DEAD = 1, REG_INC = 2, REG_EQUIV = 3, REG_WAS_0 = 4,
/* Names for REG_NOTE's in EXPR_LIST insn's. */
extern char *reg_note_name[];
-#define GET_REG_NOTE_NAME(MODE) (reg_note_name[(int)(MODE)])
+#define GET_REG_NOTE_NAME(MODE) (reg_note_name[(int) (MODE)])
/* This field is only present on CALL_INSNs. It holds a chain of EXPR_LIST of
USE and CLOBBER expressions.
@@ -375,14 +381,21 @@ extern char *reg_note_name[];
#define LINE_NUMBER NOTE
-/* In a NOTE that is a line number, this is a string for the file name
- that the line is in. We use the same field to record block numbers
- temporarily in NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes.
- (We avoid lots of casts between ints and pointers if we use a
- different macro for the bock number.) */
+/* In a NOTE that is a line number, this is a string for the file name that the
+ line is in. We use the same field to record block numbers temporarily in
+ NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes. (We avoid lots of casts
+ between ints and pointers if we use a different macro for the block number.)
+ The NOTE_INSN_RANGE_{START,END} and NOTE_INSN_LIVE notes record their
+ information as a rtx in the field. */
#define NOTE_SOURCE_FILE(INSN) ((INSN)->fld[3].rtstr)
#define NOTE_BLOCK_NUMBER(INSN) ((INSN)->fld[3].rtint)
+#define NOTE_RANGE_INFO(INSN) ((INSN)->fld[3].rtx)
+#define NOTE_LIVE_INFO(INSN) ((INSN)->fld[3].rtx)
+
+/* If the NOTE_BLOCK_NUMBER field gets a -1, it means create a new
+ block node for a live range block. */
+#define NOTE_BLOCK_LIVE_RANGE_BLOCK -1
/* In a NOTE that is a line number, this is the line number.
Other kinds of NOTEs are identified by negative numbers here. */
@@ -430,7 +443,20 @@ extern char *reg_note_name[];
i.e. the point just after all of the parms have been moved into
their homes, etc. */
#define NOTE_INSN_FUNCTION_BEG -13
-
+/* These note where exception handling regions begin and end. */
+#define NOTE_INSN_EH_REGION_BEG -14
+#define NOTE_INSN_EH_REGION_END -15
+/* Generated whenever a duplicate line number note is output. For example,
+ one is output after the end of an inline function, in order to prevent
+ the line containing the inline call from being counted twice in gcov. */
+#define NOTE_REPEATED_LINE_NUMBER -16
+
+/* Start/end of a live range region, where pseudos allocated on the stack can
+ be allocated to temporary registers. */
+#define NOTE_INSN_RANGE_START -17
+#define NOTE_INSN_RANGE_END -18
+/* Record which registers are currently live. */
+#define NOTE_INSN_LIVE -19
#if 0 /* These are not used, and I don't know what they were for. --rms. */
#define NOTE_DECL_NAME(INSN) ((INSN)->fld[3].rtstr)
@@ -453,16 +479,12 @@ extern char *note_insn_name[];
of LABEL_REFs that point at it, so unused labels can be deleted. */
#define LABEL_NUSES(LABEL) ((LABEL)->fld[5].rtint)
-/* The rest is used instead of the above, in a CODE_LABEL,
- if bytecode is being output.
- We make the slightly kludgy assumption that a LABEL has enough slots
- to hold these things. That happens to be true. */
-
-/* For static or external objects. */
-#define BYTECODE_LABEL(X) (XEXP ((X), 0))
+/* The original regno this ADDRESSOF was built for. */
+#define ADDRESSOF_REGNO(RTX) ((RTX)->fld[1].rtint)
-/* For goto labels inside bytecode functions. */
-#define BYTECODE_BC_LABEL(X) (*(struct bc_label **) &XEXP ((X), 1))
+/* The variable in the register we took the address of. */
+#define ADDRESSOF_DECL(X) ((tree) XEXP ((X), 2))
+#define SET_ADDRESSOF_DECL(X, T) (XEXP ((X), 2) = (rtx) (T))
/* In jump.c, each JUMP_INSN can point to a label that it can jump to,
so that if the JUMP_INSN is deleted, the label's LABEL_NUSES can
@@ -473,7 +495,7 @@ extern char *note_insn_name[];
each CODE_LABEL starts a chain that goes through
all the LABEL_REFs that jump to that label.
The chain eventually winds up at the CODE_LABEL; it is circular. */
-#define LABEL_REFS(LABEL) ((LABEL)->fld[5].rtx)
+#define LABEL_REFS(LABEL) ((LABEL)->fld[6].rtx)
/* This is the field in the LABEL_REF through which the circular chain
of references to a particular label is linked.
@@ -537,9 +559,20 @@ extern char *note_insn_name[];
Also in an ASM_OPERANDS rtx. */
#define MEM_VOLATILE_P(RTX) ((RTX)->volatil)
-/* For a MEM rtx, 1 if it refers to a structure or union component. */
+/* For a MEM rtx, 1 if it refers to a field of an aggregate. */
#define MEM_IN_STRUCT_P(RTX) ((RTX)->in_struct)
+/* For a MEM rtx, the alias set. If 0, this MEM is not in any alias
+ set, and may alias anything. Otherwise, the MEM can only alias
+ MEMs in the same alias set. This value is set in a
+ language-dependent manner in the front-end, and should not be
+ altered in the back-end. These set numbers are tested for zero,
+ and compared for equality; they have no other significance. In
+ some front-ends, these numbers may correspond in some way to types,
+ or other language-level entities, but they need not, and the
+ back-end makes no such assumptions. */
+#define MEM_ALIAS_SET(RTX) (XINT (RTX, 1))
+
/* For a LABEL_REF, 1 means that this reference is to a label outside the
loop containing the reference. */
#define LABEL_OUTSIDE_LOOP_P(RTX) ((RTX)->in_struct)
@@ -575,6 +608,7 @@ extern char *note_insn_name[];
/* For a TRAP_IF rtx, TRAP_CONDITION is an expression. */
#define TRAP_CONDITION(RTX) ((RTX)->fld[0].rtx)
+#define TRAP_CODE(RTX) (RTX)->fld[1].rtx
/* 1 in a SYMBOL_REF if it addresses this function's constants pool. */
#define CONSTANT_POOL_ADDRESS_P(RTX) ((RTX)->unchanging)
@@ -604,6 +638,8 @@ extern char *note_insn_name[];
for the function arguments.
ORIGINAL_DECL_INITIAL is a pointer to the original DECL_INITIAL for the
function.
+ INLINE_REGNO_REG_RTX, INLINE_REGNO_POINTER_FLAG, and
+ INLINE_REGNO_POINTER_ALIGN are pointers to the corresponding arrays.
We want this to lay down like an INSN. The PREV_INSN field
is always NULL. The NEXT_INSN field always points to the
@@ -623,6 +659,10 @@ extern char *note_insn_name[];
#define OUTGOING_ARGS_SIZE(RTX) ((RTX)->fld[13].rtint)
#define ORIGINAL_ARG_VECTOR(RTX) ((RTX)->fld[14].rtvec)
#define ORIGINAL_DECL_INITIAL(RTX) ((RTX)->fld[15].rtx)
+#define INLINE_REGNO_REG_RTX(RTX) ((RTX)->fld[16].rtvec)
+#define INLINE_REGNO_POINTER_FLAG(RTX) ((RTX)->fld[17].rtstr)
+#define INLINE_REGNO_POINTER_ALIGN(RTX) ((RTX)->fld[18].rtstr)
+#define PARMREG_STACK_LOC(RTX) ((RTX)->fld[19].rtvec)
/* In FUNCTION_FLAGS we save some variables computed when emitting the code
for the function and which must be `or'ed into the current flag values when
@@ -657,6 +697,99 @@ extern char *note_insn_name[];
#if (defined (HAVE_PRE_INCREMENT) || defined (HAVE_PRE_DECREMENT) || defined (HAVE_POST_INCREMENT) || defined (HAVE_POST_DECREMENT))
#define AUTO_INC_DEC
#endif
+
+/* Accessors for RANGE_INFO. */
+/* For RANGE_{START,END} notes return the RANGE_START note. */
+#define RANGE_INFO_NOTE_START(INSN) (XEXP (INSN, 0))
+
+/* For RANGE_{START,END} notes return the RANGE_START note. */
+#define RANGE_INFO_NOTE_END(INSN) (XEXP (INSN, 1))
+
+/* For RANGE_{START,END} notes, return the vector containing the registers used
+ in the range. */
+#define RANGE_INFO_REGS(INSN) (XVEC (INSN, 2))
+#define RANGE_INFO_REGS_REG(INSN, N) (XVECEXP (INSN, 2, N))
+#define RANGE_INFO_NUM_REGS(INSN) (XVECLEN (INSN, 2))
+
+/* For RANGE_{START,END} notes, the number of calls within the range. */
+#define RANGE_INFO_NCALLS(INSN) (XINT (INSN, 3))
+
+/* For RANGE_{START,END} notes, the number of insns within the range. */
+#define RANGE_INFO_NINSNS(INSN) (XINT (INSN, 4))
+
+/* For RANGE_{START,END} notes, a unique # to identify this range. */
+#define RANGE_INFO_UNIQUE(INSN) (XINT (INSN, 5))
+
+/* For RANGE_{START,END} notes, the basic block # the range starts with. */
+#define RANGE_INFO_BB_START(INSN) (XINT (INSN, 6))
+
+/* For RANGE_{START,END} notes, the basic block # the range ends with. */
+#define RANGE_INFO_BB_END(INSN) (XINT (INSN, 7))
+
+/* For RANGE_{START,END} notes, the loop depth the range is in. */
+#define RANGE_INFO_LOOP_DEPTH(INSN) (XINT (INSN, 8))
+
+/* For RANGE_{START,END} notes, the bitmap of live registers at the start
+ of the range. */
+#define RANGE_INFO_LIVE_START(INSN) (XBITMAP (INSN, 9))
+
+/* For RANGE_{START,END} notes, the bitmap of live registers at the end
+ of the range. */
+#define RANGE_INFO_LIVE_END(INSN) (XBITMAP (INSN, 10))
+
+/* For RANGE_START notes, the marker # of the start of the range. */
+#define RANGE_INFO_MARKER_START(INSN) (XINT (INSN, 11))
+
+/* For RANGE_START notes, the marker # of the end of the range. */
+#define RANGE_INFO_MARKER_END(INSN) (XINT (INSN, 12))
+
+/* Original pseudo register # for a live range note. */
+#define RANGE_REG_PSEUDO(INSN,N) (XINT (XVECEXP (INSN, 2, N), 0))
+
+/* Pseudo register # original register is copied into or -1. */
+#define RANGE_REG_COPY(INSN,N) (XINT (XVECEXP (INSN, 2, N), 1))
+
+/* How many times a register in a live range note was referenced. */
+#define RANGE_REG_REFS(INSN,N) (XINT (XVECEXP (INSN, 2, N), 2))
+
+/* How many times a register in a live range note was set. */
+#define RANGE_REG_SETS(INSN,N) (XINT (XVECEXP (INSN, 2, N), 3))
+
+/* How many times a register in a live range note died. */
+#define RANGE_REG_DEATHS(INSN,N) (XINT (XVECEXP (INSN, 2, N), 4))
+
+/* Whether the original value is needed to be copied into the range register at
+ the start of the range. */
+#define RANGE_REG_COPY_FLAGS(INSN,N) (XINT (XVECEXP (INSN, 2, N), 5))
+
+/* # of insns the register copy is live over. */
+#define RANGE_REG_LIVE_LENGTH(INSN,N) (XINT (XVECEXP (INSN, 2, N), 6))
+
+/* # of calls the register copy is live over. */
+#define RANGE_REG_N_CALLS(INSN,N) (XINT (XVECEXP (INSN, 2, N), 7))
+
+/* DECL_NODE pointer of the declaration if the register is a user defined
+ variable. */
+#define RANGE_REG_SYMBOL_NODE(INSN,N) (XTREE (XVECEXP (INSN, 2, N), 8))
+
+/* BLOCK_NODE pointer to the block the variable is declared in if the
+ register is a user defined variable. */
+#define RANGE_REG_BLOCK_NODE(INSN,N) (XTREE (XVECEXP (INSN, 2, N), 9))
+
+/* EXPR_LIST of the distinct ranges a variable is in. */
+#define RANGE_VAR_LIST(INSN) (XEXP (INSN, 0))
+
+/* Block a variable is declared in. */
+#define RANGE_VAR_BLOCK(INSN) (XTREE (INSN, 1))
+
+/* # of distinct ranges a variable is in. */
+#define RANGE_VAR_NUM(INSN) (XINT (INSN, 2))
+
+/* For a NOTE_INSN_LIVE note, the registers which are currently live. */
+#define RANGE_LIVE_BITMAP(INSN) (XBITMAP (INSN, 0))
+
+/* For a NOTE_INSN_LIVE note, the original basic block number. */
+#define RANGE_LIVE_ORIG_BLOCK(INSN) (XINT (INSN, 1))
/* Generally useful functions. */
@@ -665,62 +798,61 @@ extern char *note_insn_name[];
defined here and in tree.h. */
#ifndef exact_log2
-#define exact_log2(N) exact_log2_wide ((HOST_WIDE_INT) (N))
-#define floor_log2(N) floor_log2_wide ((HOST_WIDE_INT) (N))
+#define exact_log2(N) exact_log2_wide ((unsigned HOST_WIDE_INT) (N))
+#define floor_log2(N) floor_log2_wide ((unsigned HOST_WIDE_INT) (N))
#endif
+extern int exact_log2_wide PROTO((unsigned HOST_WIDE_INT));
+extern int floor_log2_wide PROTO((unsigned HOST_WIDE_INT));
+
+/* In expmed.c */
+extern int ceil_log2 PROTO((unsigned HOST_WIDE_INT));
#define plus_constant(X,C) plus_constant_wide (X, (HOST_WIDE_INT) (C))
#define plus_constant_for_output(X,C) \
plus_constant_for_output_wide (X, (HOST_WIDE_INT) (C))
+/* In explow.c */
extern rtx plus_constant_wide PROTO((rtx, HOST_WIDE_INT));
extern rtx plus_constant_for_output_wide PROTO((rtx, HOST_WIDE_INT));
-
-#define GEN_INT(N) gen_rtx (CONST_INT, VOIDmode, (HOST_WIDE_INT) (N))
-
-extern rtx bc_gen_rtx ();
+extern void optimize_save_area_alloca PROTO((rtx));
extern rtx gen_rtx PVPROTO((enum rtx_code,
enum machine_mode, ...));
extern rtvec gen_rtvec PVPROTO((int, ...));
-extern rtx read_rtx STDIO_PROTO((FILE *));
+#ifdef BUFSIZ
+extern rtx read_rtx PROTO((FILE *));
+#endif
#if 0
/* At present, don't prototype xrealloc, since all of the callers don't
cast their pointers to char *, and all of the xrealloc's don't use
void * yet. */
extern char *xmalloc PROTO((size_t));
+extern char *xcalloc PROTO((size_t, size_t));
extern char *xrealloc PROTO((void *, size_t));
#else
extern char *xmalloc ();
+extern char *xcalloc ();
extern char *xrealloc ();
#endif
extern char *oballoc PROTO((int));
extern char *permalloc PROTO((int));
-extern void free PROTO((void *));
extern rtx rtx_alloc PROTO((RTX_CODE));
extern rtvec rtvec_alloc PROTO((int));
-extern rtx find_reg_note PROTO((rtx, enum reg_note, rtx));
-extern rtx find_regno_note PROTO((rtx, enum reg_note, int));
-extern int find_reg_fusage PROTO((rtx, enum rtx_code, rtx));
-extern int find_regno_fusage PROTO((rtx, enum rtx_code, int));
-extern HOST_WIDE_INT get_integer_term PROTO((rtx));
-extern rtx get_related_value PROTO((rtx));
-extern rtx single_set PROTO((rtx));
-extern rtx find_last_value PROTO((rtx, rtx *, rtx));
extern rtx copy_rtx PROTO((rtx));
extern rtx copy_rtx_if_shared PROTO((rtx));
extern rtx copy_most_rtx PROTO((rtx, rtx));
-extern rtx replace_rtx PROTO((rtx, rtx, rtx));
extern rtvec gen_rtvec_v PROTO((int, rtx *));
+extern rtvec gen_rtvec_vv PROTO((int, rtunion *));
extern rtx gen_reg_rtx PROTO((enum machine_mode));
extern rtx gen_label_rtx PROTO((void));
extern rtx gen_inline_header_rtx PROTO((rtx, rtx, int, int, int, int,
int, int, rtx, rtx, int, int,
- rtvec, rtx));
+ rtvec, rtx,
+ rtvec, char *, char *, rtvec));
extern rtx gen_lowpart_common PROTO((enum machine_mode, rtx));
extern rtx gen_lowpart PROTO((enum machine_mode, rtx));
extern rtx gen_lowpart_if_possible PROTO((enum machine_mode, rtx));
@@ -747,8 +879,12 @@ extern rtx get_pool_constant PROTO((rtx));
extern enum machine_mode get_pool_mode PROTO((rtx));
extern int get_pool_offset PROTO((rtx));
extern rtx simplify_subtraction PROTO((rtx));
-extern rtx assign_stack_local PROTO((enum machine_mode, int, int));
-extern rtx assign_stack_temp PROTO((enum machine_mode, int, int));
+extern rtx assign_stack_local PROTO((enum machine_mode,
+ HOST_WIDE_INT, int));
+extern rtx assign_stack_temp PROTO((enum machine_mode,
+ HOST_WIDE_INT, int));
+extern rtx assign_temp PROTO((union tree_node *,
+ int, int, int));
extern rtx protect_from_queue PROTO((rtx, int));
extern void emit_queue PROTO((void));
extern rtx emit_move_insn PROTO((rtx, rtx));
@@ -787,7 +923,6 @@ extern rtx prev_label PROTO((rtx));
extern rtx next_label PROTO((rtx));
extern rtx next_cc0_user PROTO((rtx));
extern rtx prev_cc0_setter PROTO((rtx));
-extern rtx reg_set_last PROTO((rtx, rtx));
extern rtx next_nondeleted_insn PROTO((rtx));
extern enum rtx_code reverse_condition PROTO((enum rtx_code));
extern enum rtx_code swap_condition PROTO((enum rtx_code));
@@ -813,9 +948,58 @@ extern rtx gen_jump PROTO((rtx));
extern rtx gen_beq PROTO((rtx));
extern rtx gen_bge PROTO((rtx));
extern rtx gen_ble PROTO((rtx));
+extern rtx gen_mem_addressof PROTO((rtx, union tree_node *));
extern rtx eliminate_constant_term PROTO((rtx, rtx *));
extern rtx expand_complex_abs PROTO((enum machine_mode, rtx, rtx, int));
extern enum machine_mode choose_hard_reg_mode PROTO((int, int));
+extern int rtx_varies_p PROTO((rtx));
+extern int may_trap_p PROTO((rtx));
+extern int side_effects_p PROTO((rtx));
+extern int volatile_refs_p PROTO((rtx));
+extern int volatile_insn_p PROTO((rtx));
+extern void remove_note PROTO((rtx, rtx));
+extern int refers_to_regno_p PROTO((int, int, rtx, rtx *));
+extern int reg_overlap_mentioned_p PROTO((rtx, rtx));
+
+/* Functions in rtlanal.c */
+
+extern int rtx_unstable_p PROTO((rtx));
+extern int rtx_varies_p PROTO((rtx));
+extern int rtx_addr_varies_p PROTO((rtx));
+extern HOST_WIDE_INT get_integer_term PROTO((rtx));
+extern rtx get_related_value PROTO((rtx));
+extern int reg_mentioned_p PROTO((rtx, rtx));
+extern int reg_referenced_p PROTO((rtx, rtx));
+extern int reg_used_between_p PROTO((rtx, rtx, rtx));
+extern int reg_referenced_between_p PROTO((rtx, rtx, rtx));
+extern int reg_set_between_p PROTO((rtx, rtx, rtx));
+extern int modified_between_p PROTO((rtx, rtx, rtx));
+extern int no_labels_between_p PROTO((rtx, rtx));
+extern int modified_in_p PROTO((rtx, rtx));
+extern int reg_set_p PROTO((rtx, rtx));
+extern rtx single_set PROTO((rtx));
+extern rtx find_last_value PROTO((rtx, rtx *, rtx));
+extern int refers_to_regno_p PROTO((int, int, rtx, rtx *));
+extern int reg_overlap_mentioned_p PROTO((rtx, rtx));
+extern rtx find_use_as_address PROTO((rtx, rtx, HOST_WIDE_INT));
+extern void note_stores PROTO((rtx, void (*)()));
+extern rtx reg_set_last PROTO((rtx, rtx));
+extern int rtx_equal_p PROTO((rtx, rtx));
+extern int dead_or_set_p PROTO((rtx, rtx));
+extern int dead_or_set_regno_p PROTO((rtx, int));
+extern rtx find_reg_note PROTO((rtx, enum reg_note, rtx));
+extern rtx find_regno_note PROTO((rtx, enum reg_note, int));
+extern int find_reg_fusage PROTO((rtx, enum rtx_code, rtx));
+extern int find_regno_fusage PROTO((rtx, enum rtx_code, int));
+extern void remove_note PROTO((rtx, rtx));
+extern int side_effects_p PROTO((rtx));
+extern int volatile_refs_p PROTO((rtx));
+extern int volatile_insn_p PROTO((rtx));
+extern int may_trap_p PROTO((rtx));
+extern int inequality_comparison_p PROTO((rtx));
+extern rtx replace_rtx PROTO((rtx, rtx, rtx));
+extern rtx replace_regs PROTO((rtx, rtx *, int, int));
+extern int computed_jump_p PROTO((rtx));
/* Maximum number of parallel sets and clobbers in any insn in this fn.
Always at least 3, since the combiner could put that many togetherm
@@ -832,12 +1016,16 @@ extern enum reg_class reg_alternate_class PROTO((int));
extern rtx get_first_nonparm_insn PROTO((void));
/* Standard pieces of rtx, to be substituted directly into things. */
-extern rtx pc_rtx;
-extern rtx cc0_rtx;
-extern rtx const0_rtx;
-extern rtx const1_rtx;
-extern rtx const2_rtx;
-extern rtx constm1_rtx;
+#define pc_rtx (&global_rtl.pc_val)
+#define cc0_rtx (&global_rtl.cc0_val)
+
+#define MAX_SAVED_CONST_INT 64
+extern struct rtx_def const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
+
+#define const0_rtx (&const_int_rtx[MAX_SAVED_CONST_INT])
+#define const1_rtx (&const_int_rtx[MAX_SAVED_CONST_INT+1])
+#define const2_rtx (&const_int_rtx[MAX_SAVED_CONST_INT+2])
+#define constm1_rtx (&const_int_rtx[MAX_SAVED_CONST_INT-1])
extern rtx const_true_rtx;
extern rtx const_tiny_rtx[3][(int) MAX_MACHINE_MODE];
@@ -852,19 +1040,51 @@ extern rtx const_tiny_rtx[3][(int) MAX_MACHINE_MODE];
#define CONST1_RTX(MODE) (const_tiny_rtx[1][(int) (MODE)])
#define CONST2_RTX(MODE) (const_tiny_rtx[2][(int) (MODE)])
+extern struct _global_rtl
+{
+ struct rtx_def pc_val, cc0_val;
+ struct rtx_def stack_pointer_val, frame_pointer_val;
+ struct rtx_def hard_frame_pointer_val;
+ struct rtx_def arg_pointer_val;
+ struct rtx_def virtual_incoming_args_val;
+ struct rtx_def virtual_stack_vars_val;
+ struct rtx_def virtual_stack_dynamic_val;
+ struct rtx_def virtual_outgoing_args_val;
+} global_rtl;
+
/* All references to certain hard regs, except those created
by allocating pseudo regs into them (when that's possible),
go through these unique rtx objects. */
-extern rtx stack_pointer_rtx;
-extern rtx frame_pointer_rtx;
-extern rtx hard_frame_pointer_rtx;
-extern rtx arg_pointer_rtx;
+#define stack_pointer_rtx (&global_rtl.stack_pointer_val)
+#define frame_pointer_rtx (&global_rtl.frame_pointer_val)
+
extern rtx pic_offset_table_rtx;
extern rtx struct_value_rtx;
extern rtx struct_value_incoming_rtx;
extern rtx static_chain_rtx;
extern rtx static_chain_incoming_rtx;
+
+/* Include the RTL generation functions. */
+
+#ifndef NO_GENRTL_H
+#include "genrtl.h"
+#endif
+
+/* There are some RTL codes that require special attention; the
+ generation functions included above do the raw handling. If you
+ add to this list, modify special_rtx in gengenrtl.c as well. You
+ should also modify gen_rtx to use the special function. */
+
+extern rtx gen_rtx_CONST_INT PROTO((enum machine_mode, HOST_WIDE_INT));
+extern rtx gen_rtx_REG PROTO((enum machine_mode, int));
+extern rtx gen_rtx_MEM PROTO((enum machine_mode, rtx));
+
+/* We need the cast here to ensure that we get the same result both with
+ and without prototypes. */
+#define GEN_INT(N) gen_rtx_CONST_INT (VOIDmode, (HOST_WIDE_INT) (N))
+
+
/* If HARD_FRAME_POINTER_REGNUM is defined, then a special dummy reg
is used to represent the frame pointer. This is because the
hard frame pointer and the automatic variables are separated by an amount
@@ -875,6 +1095,25 @@ extern rtx static_chain_incoming_rtx;
#define HARD_FRAME_POINTER_REGNUM FRAME_POINTER_REGNUM
#endif
+/* For register elimination to work properly these hard_frame_pointer_rtx,
+ frame_pointer_rtx, and arg_pointer_rtx must be the same if they refer to
+ the same register. */
+#if HARD_FRAME_POINTER_REGNUM == FRAME_POINTER_REGNUM
+#define hard_frame_pointer_rtx (&global_rtl.frame_pointer_val)
+#else
+#define hard_frame_pointer_rtx (&global_rtl.hard_frame_pointer_val)
+#endif
+
+#if FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM
+#define arg_pointer_rtx (&global_rtl.frame_pointer_val)
+#else
+#if HARD_FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM
+#define arg_pointer_rtx (&global_rtl.hard_frame_pointer_val)
+#else
+#define arg_pointer_rtx (&global_rtl.arg_pointer_val)
+#endif
+#endif
+
/* Virtual registers are used during RTL generation to refer to locations into
the stack frame when the actual location isn't known until RTL generation
is complete. The routine instantiate_virtual_regs replaces these with
@@ -887,7 +1126,7 @@ extern rtx static_chain_incoming_rtx;
either by the caller or by the callee when pretending it was passed by the
caller. */
-extern rtx virtual_incoming_args_rtx;
+#define virtual_incoming_args_rtx (&global_rtl.virtual_incoming_args_val)
#define VIRTUAL_INCOMING_ARGS_REGNUM (FIRST_VIRTUAL_REGISTER)
@@ -895,7 +1134,7 @@ extern rtx virtual_incoming_args_rtx;
variable on the stack. Otherwise, it points to the first variable on
the stack. */
-extern rtx virtual_stack_vars_rtx;
+#define virtual_stack_vars_rtx (&global_rtl.virtual_stack_vars_val)
#define VIRTUAL_STACK_VARS_REGNUM ((FIRST_VIRTUAL_REGISTER) + 1)
@@ -903,7 +1142,7 @@ extern rtx virtual_stack_vars_rtx;
immediately after the stack pointer has been adjusted by the amount
desired. */
-extern rtx virtual_stack_dynamic_rtx;
+#define virtual_stack_dynamic_rtx (&global_rtl.virtual_stack_dynamic_val)
#define VIRTUAL_STACK_DYNAMIC_REGNUM ((FIRST_VIRTUAL_REGISTER) + 2)
@@ -911,7 +1150,7 @@ extern rtx virtual_stack_dynamic_rtx;
be written when the stack is pre-pushed (arguments pushed using push
insns always use sp). */
-extern rtx virtual_outgoing_args_rtx;
+#define virtual_outgoing_args_rtx (&global_rtl.virtual_outgoing_args_val)
#define VIRTUAL_OUTGOING_ARGS_REGNUM ((FIRST_VIRTUAL_REGISTER) + 3)
@@ -920,11 +1159,6 @@ extern rtx virtual_outgoing_args_rtx;
extern rtx find_next_ref PROTO((rtx, rtx));
extern rtx *find_single_use PROTO((rtx, rtx, rtx *));
-/* It is hard to write the prototype for expand_expr, since it needs
- expr.h to be included for the enumeration. */
-
-extern rtx expand_expr ();
-
extern rtx output_constant_def PROTO((union tree_node *));
extern rtx immed_real_const PROTO((union tree_node *));
extern union tree_node *make_tree PROTO((union tree_node *, rtx));
@@ -961,8 +1195,359 @@ extern int cse_not_expected;
Allocated in parallel with regno_pointer_flag. */
extern rtx *regno_reg_rtx;
+/* Vector indexed by regno; contain the alignment in bytes and type
+ pointed to for a register that contains a pointer, if known. */
+extern char *regno_pointer_align;
+#define REGNO_POINTER_ALIGN(REGNO) regno_pointer_align[REGNO]
+
/* Translates rtx code to tree code, for those codes needed by
REAL_ARITHMETIC. The function returns an int because the caller may not
know what `enum tree_code' means. */
extern int rtx_to_tree_code PROTO((enum rtx_code));
+
+/* In rtlanal.c */
+extern int reg_set_p PROTO ((rtx, rtx));
+extern int reg_mentioned_p PROTO ((rtx, rtx));
+extern int reg_referenced_p PROTO ((rtx, rtx));
+extern int reg_used_between_p PROTO ((rtx, rtx, rtx));
+extern int reg_set_p PROTO ((rtx, rtx));
+extern int reg_referenced_between_p PROTO ((rtx, rtx, rtx));
+extern int reg_set_between_p PROTO ((rtx, rtx, rtx));
+extern int rtx_unstable_p PROTO ((rtx));
+extern int rtx_addr_varies_p PROTO ((rtx));
+extern int rtx_equal_p PROTO ((rtx, rtx));
+extern int inequality_comparisons_p PROTO ((rtx));
+extern int dead_or_set_p PROTO ((rtx, rtx));
+extern int dead_or_set_regno_p PROTO ((rtx, int));
+extern int no_labels_between_p PROTO ((rtx, rtx));
+extern int modified_between_p PROTO ((rtx, rtx, rtx));
+extern int modified_in_p PROTO ((rtx, rtx));
+
+/* In tree.c */
+extern void obfree PROTO ((char *));
+struct obstack;
+extern void gcc_obstack_init PROTO ((struct obstack *));
+extern void pop_obstacks PROTO ((void));
+extern void push_obstacks PROTO ((struct obstack *,
+ struct obstack *));
+#ifdef BUFSIZ
+extern int read_skip_spaces PROTO ((FILE *));
+#endif
+
+/* In cse.c */
+struct cse_basic_block_data;
+extern int rtx_cost PROTO ((rtx, enum rtx_code));
+extern void delete_trivially_dead_insns PROTO ((rtx, int));
+#ifdef BUFSIZ
+extern int cse_main PROTO ((rtx, int, int, FILE *));
+#endif
+extern void cse_end_of_basic_block PROTO ((rtx,
+ struct cse_basic_block_data *,
+ int, int, int));
+
+/* In jump.c */
+extern int comparison_dominates_p PROTO ((enum rtx_code, enum rtx_code));
+extern int condjump_p PROTO ((rtx));
+extern int simplejump_p PROTO ((rtx));
+extern int sets_cc0_p PROTO ((rtx));
+extern int invert_jump PROTO ((rtx, rtx));
+extern int rtx_renumbered_equal_p PROTO ((rtx, rtx));
+extern int true_regnum PROTO ((rtx));
+extern int redirect_jump PROTO ((rtx, rtx));
+extern void jump_optimize PROTO ((rtx, int, int, int));
+extern void thread_jumps PROTO ((rtx, int, int));
+extern int redirect_exp PROTO ((rtx *, rtx, rtx, rtx));
+extern int rtx_equal_for_thread_p PROTO ((rtx, rtx, rtx));
+extern int invert_exp PROTO ((rtx, rtx));
+extern int can_reverse_comparison_p PROTO ((rtx, rtx));
+extern void delete_for_peephole PROTO ((rtx, rtx));
+extern int condjump_in_parallel_p PROTO ((rtx));
+
+/* Flags for jump_optimize() */
+#define JUMP_CROSS_JUMP 1
+#define JUMP_NOOP_MOVES 1
+#define JUMP_AFTER_REGSCAN 1
+
+/* In emit-rtl.c. */
+extern int max_reg_num PROTO ((void));
+extern int max_label_num PROTO ((void));
+extern int get_first_label_num PROTO ((void));
+extern void delete_insns_since PROTO ((rtx));
+extern void mark_reg_pointer PROTO ((rtx, int));
+extern void mark_user_reg PROTO ((rtx));
+extern void reset_used_flags PROTO ((rtx));
+extern void reorder_insns PROTO ((rtx, rtx, rtx));
+extern int get_max_uid PROTO ((void));
+extern int in_sequence_p PROTO ((void));
+extern void force_next_line_note PROTO ((void));
+extern void init_emit PROTO ((void));
+extern void init_emit_once PROTO ((int));
+extern void push_topmost_sequence PROTO ((void));
+extern void pop_topmost_sequence PROTO ((void));
+extern int subreg_realpart_p PROTO ((rtx));
+extern void reverse_comparison PROTO ((rtx));
+extern void set_new_first_and_last_insn PROTO ((rtx, rtx));
+extern void set_new_first_and_last_label_num PROTO ((int, int));
+extern void unshare_all_rtl PROTO ((rtx));
+extern void set_last_insn PROTO ((rtx));
+extern void link_cc0_insns PROTO ((rtx));
+extern void add_insn PROTO ((rtx));
+extern void add_insn_before PROTO ((rtx, rtx));
+extern void add_insn_after PROTO ((rtx, rtx));
+extern void reorder_insns_with_line_notes PROTO ((rtx, rtx, rtx));
+extern void emit_insn_after_with_line_notes PROTO ((rtx, rtx, rtx));
+extern enum rtx_code classify_insn PROTO ((rtx));
+extern rtx emit PROTO ((rtx));
+/* Query and clear/ restore no_line_numbers. This is used by the
+ switch / case handling in stmt.c to give proper line numbers in
+ warnings about unreachable code. */
+int force_line_numbers PROTO((void));
+void restore_line_number_status PROTO((int old_value));
+
+/* In insn-emit.c */
+extern void add_clobbers PROTO ((rtx, int));
+
+/* In combine.c */
+extern void combine_instructions PROTO ((rtx, int));
+extern int extended_count PROTO ((rtx, enum machine_mode, int));
+extern rtx remove_death PROTO ((int, rtx));
+#ifdef BUFSIZ
+extern void dump_combine_stats PROTO ((FILE *));
+extern void dump_combine_total_stats PROTO ((FILE *));
+#endif
+
+/* In sched.c. */
+#ifdef BUFSIZ
+extern void schedule_insns PROTO ((FILE *));
+#endif
+#ifdef HAIFA
+extern void fix_sched_param PROTO ((char *, char *));
+#endif
+
+/* In print-rtl.c */
+extern void debug_rtx PROTO ((rtx));
+extern void debug_rtx_list PROTO ((rtx, int));
+extern rtx debug_rtx_find PROTO ((rtx, int));
+#ifdef BUFSIZ
+extern void print_rtl PROTO ((FILE *, rtx));
+extern void print_rtl_single PROTO ((FILE *, rtx));
+extern void print_inline_rtx PROTO ((FILE *, rtx, int));
+#endif
+
+/* In loop.c */
+extern void init_loop PROTO ((void));
+#ifdef BUFSIZ
+extern void loop_optimize PROTO ((rtx, FILE *, int));
+#endif
+extern void record_excess_regs PROTO ((rtx, rtx, rtx *));
+
+/* In function.c */
+extern void reposition_prologue_and_epilogue_notes PROTO ((rtx));
+extern void thread_prologue_and_epilogue_insns PROTO ((rtx));
+extern void use_variable PROTO ((rtx));
+extern HOST_WIDE_INT get_frame_size PROTO ((void));
+extern void preserve_rtl_expr_result PROTO ((rtx));
+extern void mark_temp_addr_taken PROTO ((rtx));
+extern void update_temp_slot_address PROTO ((rtx, rtx));
+extern void use_variable_after PROTO ((rtx, rtx));
+extern void purge_addressof PROTO ((rtx));
+
+/* In reload.c */
+extern int operands_match_p PROTO ((rtx, rtx));
+extern int safe_from_earlyclobber PROTO ((rtx, rtx));
+extern int strict_memory_address_p PROTO ((enum machine_mode, rtx));
+
+/* In recog.c */
+extern int memory_address_p PROTO ((enum machine_mode, rtx));
+extern int constrain_operands PROTO ((int, int));
+extern int mode_dependent_address_p PROTO ((rtx));
+extern void init_recog_no_volatile PROTO ((void));
+extern int offsettable_memref_p PROTO ((rtx));
+extern int offsettable_nonstrict_memref_p PROTO ((rtx));
+extern int reg_fits_class_p PROTO ((rtx, register enum reg_class,
+ int, enum machine_mode));
+extern int check_asm_operands PROTO ((rtx));
+extern int address_operand PROTO ((rtx, enum machine_mode));
+extern int const_int_operand PROTO ((rtx, enum machine_mode));
+extern int const_double_operand PROTO ((rtx, enum machine_mode));
+extern int general_operand PROTO ((rtx, enum machine_mode));
+extern int immediate_operand PROTO ((rtx, enum machine_mode));
+extern int nonimmediate_operand PROTO ((rtx, enum machine_mode));
+extern int memory_operand PROTO ((rtx, enum machine_mode));
+extern int nonmemory_operand PROTO ((rtx, enum machine_mode));
+extern int push_operand PROTO ((rtx, enum machine_mode));
+extern int register_operand PROTO ((rtx, enum machine_mode));
+extern int scratch_operand PROTO ((rtx, enum machine_mode));
+extern int indirect_operand PROTO ((rtx, enum machine_mode));
+extern int mode_independent_operand PROTO ((rtx, enum machine_mode));
+extern int comparison_operator PROTO ((rtx, enum machine_mode));
+extern void init_recog_no_volatile PROTO ((void));
+extern void init_recog PROTO ((void));
+extern int validate_replace_rtx PROTO ((rtx, rtx, rtx));
+extern int offsettable_address_p PROTO ((int, enum machine_mode, rtx));
+extern int next_insn_tests_no_inequality PROTO ((rtx));
+extern int recog_memoized PROTO ((rtx));
+extern int validate_change PROTO ((rtx, rtx *, rtx, int));
+extern int apply_change_group PROTO ((void));
+extern void cancel_changes PROTO ((int));
+extern int num_validated_changes PROTO ((void));
+
+/* In insn-recog.c */
+extern int recog PROTO ((rtx, rtx, int *));
+
+/* In stmt.c */
+extern void expand_null_return PROTO((void));
+extern void emit_jump PROTO ((rtx));
+extern int preserve_subexpressions_p PROTO ((void));
+
+/* In expr.c */
+extern void init_expr_once PROTO ((void));
+
+/* In stupid.c */
+#ifdef BUFSIZ
+extern void stupid_life_analysis PROTO ((rtx, int, FILE *));
+#endif
+
+/* In flow.c */
+extern void allocate_for_life_analysis PROTO ((void));
+extern void recompute_reg_usage PROTO ((rtx));
+#ifdef BUFSIZ
+extern void dump_flow_info PROTO ((FILE *));
+#endif
+
+/* In expmed.c */
+extern void init_expmed PROTO ((void));
+extern void expand_inc PROTO ((rtx, rtx));
+extern void expand_dec PROTO ((rtx, rtx));
+extern rtx expand_mult_highpart PROTO ((enum machine_mode, rtx,
+ unsigned HOST_WIDE_INT, rtx,
+ int, int));
+
+/* In gcse.c */
+#ifdef BUFSIZ
+extern void gcse_main PROTO ((rtx, FILE *));
+#endif
+
+/* In global.c */
+extern void mark_elimination PROTO ((int, int));
+#ifdef BUFSIZ
+extern int global_alloc PROTO ((FILE *));
+extern void dump_global_regs PROTO ((FILE *));
+#endif
+#ifdef HARD_CONST
+extern void retry_global_alloc PROTO ((int, HARD_REG_SET));
+#endif
+
+/* In regclass.c */
+extern int reg_classes_intersect_p PROTO ((enum reg_class, enum reg_class));
+extern int reg_class_subset_p PROTO ((enum reg_class, enum reg_class));
+extern void globalize_reg PROTO ((int));
+extern void init_regs PROTO ((void));
+extern void init_reg_sets PROTO ((void));
+extern void regset_release_memory PROTO ((void));
+extern void regclass_init PROTO ((void));
+extern void regclass PROTO ((rtx, int));
+extern void reg_scan PROTO ((rtx, int, int));
+extern void reg_scan_update PROTO ((rtx, rtx, int));
+extern void fix_register PROTO ((char *, int, int));
+
+/* In regmove.c */
+#ifdef BUFSIZ
+extern void regmove_optimize PROTO ((rtx, int, FILE *));
+#endif
+
+/* In reorg.c */
+#ifdef BUFSIZ
+extern void dbr_schedule PROTO ((rtx, FILE *));
+#endif
+
+/* In optabs.c */
+extern void init_optabs PROTO ((void));
+
+/* In local-alloc.c */
+#ifdef BUFSIZ
+extern void dump_local_alloc PROTO ((FILE *));
+#endif
+extern void local_alloc PROTO ((void));
+
+/* In reload1.c */
+extern void reload_cse_regs PROTO ((rtx));
+extern void init_reload PROTO ((void));
+extern void mark_home_live PROTO ((int));
+#ifdef BUFSIZ
+extern int reload PROTO ((rtx, int, FILE *));
+#endif
+
+/* In caller-save.c */
+extern void init_caller_save PROTO ((void));
+
+/* In profile.c */
+extern void init_branch_prob PROTO ((char *));
+#ifdef BUFSIZ
+extern void branch_prob PROTO ((rtx, FILE *));
+extern void end_branch_prob PROTO ((FILE *));
+#endif
+extern void output_func_start_profiler PROTO ((void));
+
+/* In reg-stack.c */
+#ifdef BUFSIZ
+extern void reg_to_stack PROTO ((rtx, FILE *));
+#endif
+extern int stack_regs_mentioned_p PROTO ((rtx));
+
+/* In fold-const.c */
+extern int add_double PROTO ((HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT *, HOST_WIDE_INT *));
+extern int neg_double PROTO ((HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT *, HOST_WIDE_INT *));
+extern int mul_double PROTO ((HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT *, HOST_WIDE_INT *));
+extern void lshift_double PROTO ((HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT, int, HOST_WIDE_INT *,
+ HOST_WIDE_INT *, int));
+extern void rshift_double PROTO ((HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT, int,
+ HOST_WIDE_INT *, HOST_WIDE_INT *, int));
+extern void lrotate_double PROTO ((HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT, int, HOST_WIDE_INT *,
+ HOST_WIDE_INT *));
+extern void rrotate_double PROTO ((HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT, int, HOST_WIDE_INT *,
+ HOST_WIDE_INT *));
+
+/* In calls.c */
+/* Emit library call. */
+extern void emit_library_call PVPROTO ((rtx, int, enum machine_mode,
+ int, ...));
+extern rtx emit_library_call_value PVPROTO((rtx, rtx, int,
+ enum machine_mode,
+ int, ...));
+
+/* In unroll.c */
+extern int set_dominates_use PROTO ((int, int, int, rtx, rtx));
+
+/* In varasm.c */
+extern void bss_section PROTO ((void));
+extern int in_data_section PROTO ((void));
+extern int supports_one_only PROTO ((void));
+
+/* In rtl.c */
+extern void init_rtl PROTO ((void));
+extern void rtx_free PROTO ((rtx));
+
+/* In alias.c */
+extern int true_dependence PROTO ((rtx, enum machine_mode, rtx,
+ int (*)(rtx)));
+extern int read_dependence PROTO ((rtx, rtx));
+extern int anti_dependence PROTO ((rtx, rtx));
+extern int output_dependence PROTO ((rtx, rtx));
+extern void init_alias_once PROTO ((void));
+extern void init_alias_analysis PROTO ((void));
+extern void end_alias_analysis PROTO ((void));
+
+extern void record_base_value PROTO ((int, rtx, int));
+
+#endif /* _RTL_H */
diff --git a/contrib/gcc/rtl.texi b/contrib/gcc/rtl.texi
index 1e1f5b7..baba532 100644
--- a/contrib/gcc/rtl.texi
+++ b/contrib/gcc/rtl.texi
@@ -1,4 +1,4 @@
-@c Copyright (C) 1988, 1989, 1992, 1994 Free Software Foundation, Inc.
+@c Copyright (C) 1988, 89, 92, 94, 97, 1998 Free Software Foundation, Inc.
@c This is part of the GCC manual.
@c For copying conditions, see the file gcc.texi.
@@ -287,9 +287,9 @@ to access them.
@section Flags in an RTL Expression
@cindex flags in RTL expression
-RTL expressions contain several flags (one-bit bitfields) that are used
-in certain types of expression. Most often they are accessed with the
-following macros:
+RTL expressions contain several flags (one-bit bitfields) and other
+values that are used in certain types of expression. Most often they
+are accessed with the following macros:
@table @code
@findex MEM_VOLATILE_P
@@ -310,6 +310,15 @@ structure, union or array, or to a component of one. Zero for
references to a scalar variable or through a pointer to a scalar.
Stored in the @code{in_struct} field and printed as @samp{/s}.
+@findex MEM_ALIAS_SET
+@item MEM_ALIAS_SET (@var{x})
+In @code{mem} expressions, the alias set to which @var{x} belongs. If
+zero, @var{x} is not in any alias set, and may alias anything. If
+nonzero, @var{x} may only alias objects in the same alias set. This
+value is set (in a language-specific manner) by the front-end. This
+field is not a bit-field; it is in an integer, found as the second
+argument to the @code{mem}.
+
@findex REG_LOOP_TEST_P
@cindex @code{reg} and @samp{/s}
@cindex @code{in_struct}, in @code{reg}
@@ -380,8 +389,7 @@ other functions or by aliasing.) Stored in the
@cindex @code{integrated}, in @code{insn}
@item RTX_INTEGRATED_P (@var{insn})
Nonzero in an insn if it resulted from an in-line function call.
-Stored in the @code{integrated} field and printed as @samp{/i}. This
-may be deleted; nothing currently depends on it.
+Stored in the @code{integrated} field and printed as @samp{/i}.
@findex SYMBOL_REF_USED
@cindex @code{used}, in @code{symbol_ref}
@@ -427,10 +435,12 @@ as @samp{/u}.
@item INSN_FROM_TARGET_P (@var{insn})
In an @code{insn} in a delay slot of a branch, indicates that the insn
is from the target of the branch. If the branch insn has
-@code{INSN_ANNULLED_BRANCH_P} set, this insn should only be executed if
-the branch is taken. For annulled branches with this bit clear, the
-insn should be executed only if the branch is not taken. Stored in the
-@code{in_struct} field and printed as @samp{/s}.
+@code{INSN_ANNULLED_BRANCH_P} set, this insn will only be executed if
+the branch is taken. For annulled branches with
+@code{INSN_FROM_TARGET_P} clear, the insn will be executed only if the
+branch is not taken. When @code{INSN_ANNULLED_BRANCH_P} is not set,
+this insn will always be executed. Stored in the @code{in_struct}
+field and printed as @samp{/s}.
@findex CONSTANT_POOL_ADDRESS_P
@cindex @code{symbol_ref} and @samp{/u}
@@ -1096,6 +1106,15 @@ The compilation parameter @code{WORDS_BIG_ENDIAN}, if set to 1, says
that word number zero is the most significant part; otherwise, it is
the least significant part.
+@cindex @code{FLOAT_WORDS_BIG_ENDIAN}, (lack of) effect on @code{subreg}
+On a few targets, @code{FLOAT_WORDS_BIG_ENDIAN} disagrees with
+@code{WORDS_BIG_ENDIAN}.
+However, most parts of the compiler treat floating point values as if
+they had the same endianness as integer values. This works because
+they handle them solely as a collection of integer values, with no
+particular numerical value. Only real.c and the runtime libraries
+care about @code{FLOAT_WORDS_BIG_ENDIAN}.
+
@cindex combiner pass
@cindex reload pass
@cindex @code{subreg}, special reload handling
@@ -1212,6 +1231,14 @@ by incrementing it, but there is no need to mention this in the RTL.
This RTX represents a reference to main memory at an address
represented by the expression @var{addr}. @var{m} specifies how large
a unit of memory is accessed.
+
+@findex addressof
+@item (addressof:@var{m} @var{reg})
+This RTX represents a request for the address of register @var{reg}. Its mode
+is always @code{Pmode}. If there are any @code{addressof}
+expressions left in the function after CSE, @var{reg} is forced into the
+stack and the @code{addressof} expression is replaced with a @code{plus}
+expression for the address of its stack slot.
@end table
@node Arithmetic, Comparisons, Regs and Memory, RTL
@@ -1584,7 +1611,8 @@ option @code{BITS_BIG_ENDIAN} says which end of the memory unit
If @var{loc} is in memory, its mode must be a single-byte integer mode.
If @var{loc} is in a register, the mode to use is specified by the
operand of the @code{insv} or @code{extv} pattern
-(@pxref{Standard Names}) and is usually a full-word integer mode.
+(@pxref{Standard Names}) and is usually a full-word integer mode,
+which is the default if none is specified.
The mode of @var{pos} is machine-specific and is also specified
in the @code{insv} or @code{extv} pattern.
@@ -1872,6 +1900,10 @@ it may not be apparent why this is so. Therefore, the compiler will
not attempt to delete previous instructions whose only effect is to
store a value in @var{x}. @var{x} must be a @code{reg} expression.
+During the reload phase, an insn that has a @code{use} as pattern
+can carry a reg_equal note. These @code{use} insns will be deleted
+before the reload phase exits.
+
During the delayed branch scheduling phase, @var{x} may be an insn.
This indicates that @var{x} previously was located at this place in the
code and its data dependencies need to be taken into account. These
@@ -1986,11 +2018,15 @@ how much space is given to each address; normally @var{m} would be
@code{Pmode}.
@findex addr_diff_vec
-@item (addr_diff_vec:@var{m} @var{base} [@var{lr0} @var{lr1} @dots{}])
+@item (addr_diff_vec:@var{m} @var{base} [@var{lr0} @var{lr1} @dots{}] @var{min} @var{max} @var{flags})
Represents a table of jump addresses expressed as offsets from
@var{base}. The vector elements @var{lr0}, etc., are @code{label_ref}
expressions and so is @var{base}. The mode @var{m} specifies how much
-space is given to each address-difference.@refill
+space is given to each address-difference. @var{min} and @var{max}
+are set up by branch shortening and hold a label with a minimum and a
+maximum address, respectively. @var{flags} indicates the relative
+position of @var{base}, @var{min} and @var{max} to the cointaining insn
+and of @var{min} and @var{max} to @var{base}. See rtl.def for details.@refill
@end table
@node Incdec, Assembler, Side Effects, RTL
@@ -2290,6 +2326,14 @@ These types of notes indicate the position of the beginning and end
of a level of scoping of variable names. They control the output
of debugging information.
+@findex NOTE_INSN_EH_REGION_BEG
+@findex NOTE_INSN_EH_REGION_END
+@item NOTE_INSN_EH_REGION_BEG
+@itemx NOTE_INSN_EH_REGION_END
+These types of notes indicate the position of the beginning and end of a
+level of scoping for exception handling. @code{NOTE_BLOCK_NUMBER}
+identifies which @code{CODE_LABEL} is associated with the given region.
+
@findex NOTE_INSN_LOOP_BEG
@findex NOTE_INSN_LOOP_END
@item NOTE_INSN_LOOP_BEG
@@ -2376,8 +2420,8 @@ nor a label may come between the related insns.
@findex REG_NOTES
@item REG_NOTES (@var{i})
A list (chain of @code{expr_list} and @code{insn_list} expressions)
-giving miscellaneous information about the insn. It is often information
-pertaining to the registers used in this insn.
+giving miscellaneous information about the insn. It is often
+information pertaining to the registers used in this insn.
@end table
The @code{LOG_LINKS} field of an insn is a chain of @code{insn_list}
@@ -2402,11 +2446,11 @@ mode @code{VOIDmode}.
The @code{REG_NOTES} field of an insn is a chain similar to the
@code{LOG_LINKS} field but it includes @code{expr_list} expressions in
-addition to @code{insn_list} expressions. There are several kinds
-of register notes, which are distinguished by the machine mode, which
-in a register note is really understood as being an @code{enum reg_note}.
+addition to @code{insn_list} expressions. There are several kinds of
+register notes, which are distinguished by the machine mode, which in a
+register note is really understood as being an @code{enum reg_note}.
The first operand @var{op} of the note is data whose meaning depends on
-the kind of note.
+the kind of note.
@findex REG_NOTE_KIND
@findex PUT_REG_NOTE_KIND
@@ -2504,6 +2548,17 @@ slot where the parameter was passed. Although in this case the register
may be set by other insns, it is still valid to replace the register
by the stack slot throughout the function.
+A @code{REG_EQUIV} note is also used on an instruction which copies a
+register parameter into a pseudo-register at entry to a function, if
+there is a stack slot where that parameter could be stored. Although
+other insns may set the pseudo-register, it is valid for the compiler to
+replace the pseudo-register by stack slot throughout the function,
+provided the compiler ensures that the stack slot is properly
+initialized by making the replacement in the initial copy instruction as
+well. This is used on machines for which the calling convention
+allocates stack space for register parameters. See
+@code{REG_PARM_STACK_SPACE} in @ref{Stack Arguments}.
+
In the case of @code{REG_EQUAL}, the register that is set by this insn
will be equal to @var{op} at run time at the end of this insn but not
necessarily elsewhere in the function. In this case, @var{op}
@@ -2604,6 +2659,31 @@ This indicates an anti dependence (a write after read dependence).
This indicates an output dependence (a write after write dependence).
@end table
+These notes describe information gathered from gcov profile data. They
+are stored in the @code{REG_NOTES} field of an insn as an
+@code{expr_list}.
+
+@table @code
+@findex REG_EXEC_COUNT
+@item REG_EXEC_COUNT
+This is used to indicate the number of times a basic block was executed
+according to the profile data. The note is attached to the first insn in
+the basic block.
+
+@findex REG_BR_PROB
+@item REG_BR_PROB
+This is used to specify the ratio of branches to non-branches of a
+branch insn according to the profile data. The value is stored as a
+value between 0 and REG_BR_PROB_BASE; larger values indicate a higher
+probability that the branch will be taken.
+
+@findex REG_BR_PRED
+@item REG_BR_PRED
+These notes are found in JUMP insns after delayed branch scheduling
+has taken place. They indicate both the direction and the likelyhood
+of the JUMP. The format is a bitmask of ATTR_FLAG_* values.
+@end table
+
For convenience, the machine mode in an @code{insn_list} or
@code{expr_list} is printed using these symbolic codes in debugging dumps.
diff --git a/contrib/gcc/rtlanal.c b/contrib/gcc/rtlanal.c
index 17cfd36..221b3fa 100644
--- a/contrib/gcc/rtlanal.c
+++ b/contrib/gcc/rtlanal.c
@@ -1,5 +1,5 @@
/* Analyze RTL for C-Compiler
- Copyright (C) 1987, 88, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,10 +20,16 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
+#include "system.h"
#include "rtl.h"
-void note_stores ();
-int reg_set_p ();
+static int rtx_addr_can_trap_p PROTO((rtx));
+static void reg_set_p_1 PROTO((rtx, rtx));
+static void reg_set_last_1 PROTO((rtx, rtx));
+
+
+/* Forward declarations */
+static int jmp_uses_reg_or_mem PROTO((rtx));
/* Bit flags that specify the machine subtype we are compiling for.
Bits are tested using macros TARGET_... defined in the tm.h file
@@ -99,12 +105,15 @@ rtx_varies_p (x)
eliminated the frame and/or arg pointer and are using it
for pseudos. */
return ! (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
- || x == arg_pointer_rtx);
+ || x == arg_pointer_rtx || x == pic_offset_table_rtx);
case LO_SUM:
/* The operand 0 of a LO_SUM is considered constant
(in fact is it related specifically to operand 1). */
return rtx_varies_p (XEXP (x, 1));
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -117,7 +126,7 @@ rtx_varies_p (x)
/* Return 0 if the use of X as an address in a MEM can cause a trap. */
-int
+static int
rtx_addr_can_trap_p (x)
register rtx x;
{
@@ -149,6 +158,9 @@ rtx_addr_can_trap_p (x)
case LO_SUM:
return rtx_addr_can_trap_p (XEXP (x, 1));
+
+ default:
+ break;
}
/* If it isn't one of the case above, it can cause a trap. */
@@ -177,8 +189,17 @@ rtx_addr_varies_p (x)
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
if (fmt[i] == 'e')
- if (rtx_addr_varies_p (XEXP (x, i)))
- return 1;
+ {
+ if (rtx_addr_varies_p (XEXP (x, i)))
+ return 1;
+ }
+ else if (fmt[i] == 'E')
+ {
+ int j;
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (rtx_addr_varies_p (XVECEXP (x, i, j)))
+ return 1;
+ }
return 0;
}
@@ -265,6 +286,9 @@ reg_mentioned_p (reg, in)
case CONST_DOUBLE:
/* These are kept unique for a given value. */
return 0;
+
+ default:
+ break;
}
if (GET_CODE (reg) == code && rtx_equal_p (reg, in))
@@ -355,13 +379,13 @@ reg_referenced_p (x, body)
+ (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)))
&& reg_overlap_mentioned_p (x, SET_DEST (body)))
return 1;
- break;
+ return 0;
case ASM_OPERANDS:
for (i = ASM_OPERANDS_INPUT_LENGTH (body) - 1; i >= 0; i--)
if (reg_overlap_mentioned_p (x, ASM_OPERANDS_INPUT (body, i)))
return 1;
- break;
+ return 0;
case CALL:
case USE:
@@ -376,15 +400,16 @@ reg_referenced_p (x, body)
for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
if (reg_referenced_p (x, XVECEXP (body, 0, i)))
return 1;
- break;
+ return 0;
+
+ default:
+ return 0;
}
-
- return 0;
}
/* Nonzero if register REG is referenced in an insn between
FROM_INSN and TO_INSN (exclusive of those two). Sets of REG do
- not count. */
+ not count. */
int
reg_referenced_between_p (reg, from_insn, to_insn)
@@ -431,6 +456,7 @@ static int reg_set_flag;
static void
reg_set_p_1 (x, pat)
rtx x;
+ rtx pat ATTRIBUTE_UNUSED;
{
/* We don't want to return 1 if X is a MEM that contains a register
within REG_SET_REG. */
@@ -508,6 +534,9 @@ modified_between_p (x, start, end)
case REG:
return reg_set_between_p (x, start, end);
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -560,6 +589,9 @@ modified_in_p (x, insn)
case REG:
return reg_set_p (x, insn);
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -740,6 +772,9 @@ refers_to_regno_p (regno, endregno, x, loc)
return 0;
x = SET_SRC (x);
goto repeat;
+
+ default:
+ break;
}
/* X does not match, so try its subexpressions. */
@@ -782,7 +817,14 @@ reg_overlap_mentioned_p (x, in)
{
int regno, endregno;
- if (GET_CODE (x) == SUBREG)
+ /* Overly conservative. */
+ if (GET_CODE (x) == STRICT_LOW_PART)
+ x = XEXP (x, 0);
+
+ /* If either argument is a constant, then modifying X can not affect IN. */
+ if (CONSTANT_P (x) || CONSTANT_P (in))
+ return 0;
+ else if (GET_CODE (x) == SUBREG)
{
regno = REGNO (SUBREG_REG (x));
if (regno < FIRST_PSEUDO_REGISTER)
@@ -790,8 +832,6 @@ reg_overlap_mentioned_p (x, in)
}
else if (GET_CODE (x) == REG)
regno = REGNO (x);
- else if (CONSTANT_P (x))
- return 0;
else if (GET_CODE (x) == MEM)
{
char *fmt;
@@ -915,7 +955,7 @@ reg_set_last (x, insn)
return 0;
}
-/* This is 1 until after reload pass. */
+/* This is 1 until after the rtl generation pass. */
int rtx_equal_function_value_matters;
/* Return 1 if X and Y are identical-looking rtx's.
@@ -1125,19 +1165,30 @@ dead_or_set_regno_p (insn, test_regno)
int regno, endregno;
rtx link;
- /* See if there is a death note for something that includes TEST_REGNO. */
- for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ /* REG_READ notes are not normally maintained after reload, so we
+ ignore them if the are invalid. */
+ if (! reload_completed
+#ifdef PRESERVE_DEATH_INFO_REGNO_P
+ || PRESERVE_DEATH_INFO_REGNO_P (test_regno)
+#endif
+ )
{
- if (REG_NOTE_KIND (link) != REG_DEAD || GET_CODE (XEXP (link, 0)) != REG)
- continue;
+ /* See if there is a death note for something that includes
+ TEST_REGNO. */
+ for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
+ {
+ if (REG_NOTE_KIND (link) != REG_DEAD
+ || GET_CODE (XEXP (link, 0)) != REG)
+ continue;
- regno = REGNO (XEXP (link, 0));
- endregno = (regno >= FIRST_PSEUDO_REGISTER ? regno + 1
- : regno + HARD_REGNO_NREGS (regno,
- GET_MODE (XEXP (link, 0))));
+ regno = REGNO (XEXP (link, 0));
+ endregno = (regno >= FIRST_PSEUDO_REGISTER ? regno + 1
+ : regno + HARD_REGNO_NREGS (regno,
+ GET_MODE (XEXP (link, 0))));
- if (test_regno >= regno && test_regno < endregno)
- return 1;
+ if (test_regno >= regno && test_regno < endregno)
+ return 1;
+ }
}
if (GET_CODE (insn) == CALL_INSN
@@ -1213,6 +1264,10 @@ find_reg_note (insn, kind, datum)
{
register rtx link;
+ /* Ignore anything that is not an INSN, JUMP_INSN or CALL_INSN. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ return 0;
+
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == kind
&& (datum == 0 || datum == XEXP (link, 0)))
@@ -1233,6 +1288,10 @@ find_regno_note (insn, kind, regno)
{
register rtx link;
+ /* Ignore anything that is not an INSN, JUMP_INSN or CALL_INSN. */
+ if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+ return 0;
+
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
if (REG_NOTE_KIND (link) == kind
/* Verify that it is a register, so that scratch and MEM won't cause a
@@ -1395,6 +1454,9 @@ volatile_insn_p (x)
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
return 1;
+
+ default:
+ break;
}
/* Recursively scan the operands of this expression. */
@@ -1458,6 +1520,9 @@ volatile_refs_p (x)
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
return 1;
+
+ default:
+ break;
}
/* Recursively scan the operands of this expression. */
@@ -1530,6 +1595,9 @@ side_effects_p (x)
case ASM_OPERANDS:
if (MEM_VOLATILE_P (x))
return 1;
+
+ default:
+ break;
}
/* Recursively scan the operands of this expression. */
@@ -1598,16 +1666,20 @@ may_trap_p (x)
case MOD:
case UDIV:
case UMOD:
- if (! CONSTANT_P (XEXP (x, 1)))
+ if (! CONSTANT_P (XEXP (x, 1))
+ || GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
return 1;
/* This was const0_rtx, but by not using that,
we can link this file into other programs. */
if (GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 0)
return 1;
+ break;
+
case EXPR_LIST:
/* An EXPR_LIST is used to represent a function call. This
certainly may trap. */
return 1;
+
default:
/* Any floating arithmetic may trap. */
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
@@ -1666,6 +1738,9 @@ inequality_comparisons_p (x)
case GE:
case GEU:
return 1;
+
+ default:
+ break;
}
len = GET_RTX_LENGTH (code);
@@ -1690,7 +1765,8 @@ inequality_comparisons_p (x)
return 0;
}
-/* Replace any occurrence of FROM in X with TO.
+/* Replace any occurrence of FROM in X with TO. The function does
+ not enter into CONST_DOUBLE for the replace.
Note that copying is not done so X must not be shared unless all copies
are to be modified. */
@@ -1702,6 +1778,11 @@ replace_rtx (x, from, to)
register int i, j;
register char *fmt;
+ /* The following prevents loops occurrence when we change MEM in
+ CONST_DOUBLE onto the same CONST_DOUBLE. */
+ if (x != 0 && GET_CODE (x) == CONST_DOUBLE)
+ return x;
+
if (x == from)
return to;
@@ -1821,6 +1902,9 @@ replace_regs (x, reg_map, nregs, replace_dest)
SET_SRC (x) = replace_regs (SET_SRC (x), reg_map, nregs, 0);
return x;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -1838,3 +1922,96 @@ replace_regs (x, reg_map, nregs, replace_dest)
}
return x;
}
+
+/* Return 1 if X, the SRC_SRC of SET of (pc) contain a REG or MEM that is
+ not in the constant pool and not in the condition of an IF_THEN_ELSE. */
+
+static int
+jmp_uses_reg_or_mem (x)
+ rtx x;
+{
+ enum rtx_code code = GET_CODE (x);
+ int i, j;
+ char *fmt;
+
+ switch (code)
+ {
+ case CONST:
+ case LABEL_REF:
+ case PC:
+ return 0;
+
+ case REG:
+ return 1;
+
+ case MEM:
+ return ! (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+ && CONSTANT_POOL_ADDRESS_P (XEXP (x, 0)));
+
+ case IF_THEN_ELSE:
+ return (jmp_uses_reg_or_mem (XEXP (x, 1))
+ || jmp_uses_reg_or_mem (XEXP (x, 2)));
+
+ case PLUS: case MINUS: case MULT:
+ return (jmp_uses_reg_or_mem (XEXP (x, 0))
+ || jmp_uses_reg_or_mem (XEXP (x, 1)));
+
+ default:
+ break;
+ }
+
+ fmt = GET_RTX_FORMAT (code);
+ for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+ {
+ if (fmt[i] == 'e'
+ && jmp_uses_reg_or_mem (XEXP (x, i)))
+ return 1;
+
+ if (fmt[i] == 'E')
+ for (j = 0; j < XVECLEN (x, i); j++)
+ if (jmp_uses_reg_or_mem (XVECEXP (x, i, j)))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return nonzero if INSN is an indirect jump (aka computed jump).
+
+ Tablejumps and casesi insns are not considered indirect jumps;
+ we can recognize them by a (use (lael_ref)). */
+
+int
+computed_jump_p (insn)
+ rtx insn;
+{
+ int i;
+ if (GET_CODE (insn) == JUMP_INSN)
+ {
+ rtx pat = PATTERN (insn);
+
+ if (GET_CODE (pat) == PARALLEL)
+ {
+ int len = XVECLEN (pat, 0);
+ int has_use_labelref = 0;
+
+ for (i = len - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (pat, 0, i)) == USE
+ && (GET_CODE (XEXP (XVECEXP (pat, 0, i), 0))
+ == LABEL_REF))
+ has_use_labelref = 1;
+
+ if (! has_use_labelref)
+ for (i = len - 1; i >= 0; i--)
+ if (GET_CODE (XVECEXP (pat, 0, i)) == SET
+ && SET_DEST (XVECEXP (pat, 0, i)) == pc_rtx
+ && jmp_uses_reg_or_mem (SET_SRC (XVECEXP (pat, 0, i))))
+ return 1;
+ }
+ else if (GET_CODE (pat) == SET
+ && SET_DEST (pat) == pc_rtx
+ && jmp_uses_reg_or_mem (SET_SRC (pat)))
+ return 1;
+ }
+ return 0;
+}
diff --git a/contrib/gcc/scan-decls.c b/contrib/gcc/scan-decls.c
index e8309b8..d2f32a8 100644
--- a/contrib/gcc/scan-decls.c
+++ b/contrib/gcc/scan-decls.c
@@ -1,5 +1,5 @@
/* scan-decls.c - Extracts declarations from cpp output.
- Copyright (C) 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1995, 1997, 1998 Free Software Foundation, Inc.
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
@@ -17,10 +17,11 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Written by Per Bothner <bothner@cygnus.com>, July 1993. */
-#include <stdio.h>
-#include <ctype.h>
#include "hconfig.h"
+#include "system.h"
+#include "gansidecl.h"
#include "cpplib.h"
+#include "scan.h"
int brace_nesting = 0;
@@ -78,19 +79,20 @@ int
scan_decls (pfile, argc, argv)
cpp_reader *pfile;
int argc;
- char**argv;
+ char **argv;
{
int saw_extern, saw_inline;
- int old_written;
+ int start_written;
/* If declarator_start is non-zero, it marks the start of the current
declarator. If it is zero, we are either still parsing the
- decl-specs, or prev_id_start marks the start of the declarator. */
+ decl-specs, or prev_id_start marks the start of the declarator. */
int declarator_start;
int prev_id_start, prev_id_end;
enum cpp_token token;
new_statement:
CPP_SET_WRITTEN (pfile, 0);
+ start_written = 0;
token = cpp_get_token (pfile);
handle_statement:
@@ -122,13 +124,10 @@ scan_decls (pfile, argc, argv)
declarator_start = 0;
for (;;)
{
- int start_written = CPP_WRITTEN (pfile);
- token = cpp_get_token (pfile);
- handle_token:
switch (token)
{
case CPP_LPAREN:
- /* Looks like this is the start of a formal parameter list. */
+ /* Looks like this is the start of a formal parameter list. */
if (prev_id_start)
{
int nesting = 1;
@@ -187,7 +186,7 @@ scan_decls (pfile, argc, argv)
pfile->token_buffer,
prev_id_start);
}
- /* ... fall through ... */
+ /* ... fall through ... */
maybe_handle_comma:
if (token != CPP_COMMA)
goto new_statement;
@@ -225,22 +224,22 @@ scan_decls (pfile, argc, argv)
}
}
else
- goto handle_token;
+ continue;
break;
}
- /* This may be the name of a variable or function. */
+ /* This may be the name of a variable or function. */
prev_id_start = start_written;
prev_id_end = CPP_WRITTEN (pfile);
break;
case CPP_EOF:
- return; /* ??? FIXME */
+ return 0;
case CPP_LBRACE: case CPP_RBRACE: case CPP_DIRECTIVE:
goto new_statement; /* handle_statement? */
case CPP_HSPACE: case CPP_VSPACE: case CPP_COMMENT: case CPP_POP:
- /* Skip initial white space. */
+ /* Skip initial white space. */
if (start_written == 0)
CPP_SET_WRITTEN (pfile, 0);
break;
@@ -248,5 +247,8 @@ scan_decls (pfile, argc, argv)
default:
prev_id_start = 0;
}
+
+ start_written = CPP_WRITTEN (pfile);
+ token = cpp_get_token (pfile);
}
}
diff --git a/contrib/gcc/scan.c b/contrib/gcc/scan.c
index 1086c38..63e2470 100644
--- a/contrib/gcc/scan.c
+++ b/contrib/gcc/scan.c
@@ -15,9 +15,9 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#include "scan.h"
#include "hconfig.h"
-#include <ctype.h>
+#include "system.h"
+#include "scan.h"
int lineno = 1;
int source_lineno = 1;
@@ -49,7 +49,7 @@ sstring_append (dst, src)
sstring *src;
{
register char *d, *s;
- register count = SSTRING_LENGTH(src);
+ register int count = SSTRING_LENGTH(src);
MAKE_SSTRING_SPACE(dst, count + 1);
d = dst->ptr;
s = src->base;
@@ -65,13 +65,13 @@ scan_ident (fp, s, c)
int c;
{
s->ptr = s->base;
- if (isalpha(c) || c == '_')
+ if (ISALPHA(c) || c == '_')
{
for (;;)
{
SSTRING_PUT(s, c);
c = getc (fp);
- if (c == EOF || !(isalnum(c) || c == '_'))
+ if (c == EOF || !(ISALNUM(c) || c == '_'))
break;
}
}
@@ -84,6 +84,7 @@ int
scan_string (fp, s, init)
register FILE *fp;
register sstring *s;
+ int init;
{
int c;
for (;;)
@@ -111,7 +112,7 @@ scan_string (fp, s, init)
return c;
}
-/* Skip horizontal white spaces (spaces, tabs, and C-style comments). */
+/* Skip horizontal white spaces (spaces, tabs, and C-style comments). */
int
skip_spaces (fp, c)
@@ -209,18 +210,18 @@ get_token (fp, s)
}
if (c == EOF)
return EOF;
- if (isdigit (c))
+ if (ISDIGIT (c))
{
do
{
SSTRING_PUT(s, c);
c = getc (fp);
- } while (c != EOF && isdigit(c));
+ } while (c != EOF && ISDIGIT(c));
ungetc (c, fp);
c = INT_TOKEN;
goto done;
}
- if (isalpha (c) || c == '_')
+ if (ISALPHA (c) || c == '_')
{
c = scan_ident (fp, s, c);
ungetc (c, fp);
diff --git a/contrib/gcc/scan.h b/contrib/gcc/scan.h
index e56dd15..12879c0 100644
--- a/contrib/gcc/scan.h
+++ b/contrib/gcc/scan.h
@@ -51,22 +51,24 @@ struct fn_decl
};
extern int lineno;
-extern void sstring_append _PARAMS((sstring*, sstring*));
-extern void make_sstring_space _PARAMS((sstring*, int));
-extern int skip_spaces _PARAMS((FILE*, int));
+extern void sstring_append _PARAMS((sstring *, sstring *));
+extern void make_sstring_space _PARAMS((sstring *, int));
+extern int skip_spaces _PARAMS((FILE *, int));
extern int scan_ident _PARAMS((FILE *, sstring *, int));
-extern int scan_string _PARAMS((FILE*, sstring *, int));
-extern int read_upto _PARAMS((FILE*, sstring*, int));
+extern int scan_string _PARAMS((FILE *, sstring *, int));
+extern int read_upto _PARAMS((FILE *, sstring *, int));
extern char *xmalloc _PARAMS((unsigned));
extern char *xrealloc _PARAMS((char *, unsigned));
-extern unsigned long hash _PARAMS((const char*));
+extern unsigned long hash _PARAMS((const char *));
+extern void recognized_function _PARAMS((char *, int, int, char *, int, int, char *, int));
+extern void recognized_extern _PARAMS((char *, int, char *, int));
/* get_token is a simple C lexer. */
#define IDENTIFIER_TOKEN 300
#define CHAR_TOKEN 301
#define STRING_TOKEN 302
#define INT_TOKEN 303
-extern int get_token _PARAMS ((FILE*, sstring*));
+extern int get_token _PARAMS ((FILE *, sstring *));
/* Current file and line numer, taking #-directives into account */
extern int source_lineno;
diff --git a/contrib/gcc/sched.c b/contrib/gcc/sched.c
index 81d77bf..5b54028 100644
--- a/contrib/gcc/sched.c
+++ b/contrib/gcc/sched.c
@@ -1,5 +1,5 @@
/* Instruction scheduling pass.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93-97, 1998 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
Enhanced by, and currently maintained by, Jim Wilson (wilson@cygnus.com)
@@ -111,12 +111,14 @@ Boston, MA 02111-1307, USA. */
reg_n_calls_crossed, and reg_live_length. Also, basic_block_head,
basic_block_end.
- The information in the line number notes is carefully retained by this
- pass. All other NOTE insns are grouped in their same relative order at
- the beginning of basic blocks that have been scheduled. */
+ The information in the line number notes is carefully retained by
+ this pass. Notes that refer to the starting and ending of
+ exception regions are also carefully retained by this pass. All
+ other NOTE insns are grouped in their same relative order at the
+ beginning of basic blocks that have been scheduled. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "basic-block.h"
#include "regs.h"
@@ -125,6 +127,9 @@ Boston, MA 02111-1307, USA. */
#include "insn-config.h"
#include "insn-attr.h"
+extern char *reg_known_equiv_p;
+extern rtx *reg_known_value;
+
#ifdef INSN_SCHEDULING
/* Arrays set up by scheduling for the same respective purposes as
similar-named arrays set up by flow analysis. We work with these
@@ -133,7 +138,6 @@ Boston, MA 02111-1307, USA. */
Values of these arrays are copied at the end of this pass into the
arrays set up by flow analysis. */
-static short *sched_reg_n_deaths;
static int *sched_reg_n_calls_crossed;
static int *sched_reg_live_length;
@@ -175,7 +179,7 @@ static unsigned int *insn_blockage;
#define UNIT_BLOCKED(B) ((B) >> (2 * BLOCKAGE_BITS))
#define BLOCKAGE_RANGE(B) \
(((((B) >> BLOCKAGE_BITS) & BLOCKAGE_MASK) << (HOST_BITS_PER_INT / 2)) \
- | (B) & BLOCKAGE_MASK)
+ | ((B) & BLOCKAGE_MASK))
/* Encodings of the `<name>_unit_blockage_range' function. */
#define MIN_BLOCKAGE_COST(R) ((R) >> (HOST_BITS_PER_INT / 2))
@@ -260,7 +264,7 @@ static rtx dead_notes;
The transition (R->S) is implemented in the scheduling loop in
`schedule_block' when the best insn to schedule is chosen.
The transition (R->Q) is implemented in `schedule_select' when an
- insn is found to to have a function unit conflict with the already
+ insn is found to have a function unit conflict with the already
committed insns.
The transitions (P->R and P->Q) are implemented in `schedule_insn' as
insns move from the ready list to the scheduled list.
@@ -288,16 +292,12 @@ static int *insn_tick;
struct sometimes
{
- short offset; short bit;
- short live_length; short calls_crossed;
+ int regno;
+ int live_length;
+ int calls_crossed;
};
/* Forward declarations. */
-static rtx canon_rtx PROTO((rtx));
-static int rtx_equal_for_memref_p PROTO((rtx, rtx));
-static rtx find_symbolic_term PROTO((rtx));
-static int memrefs_conflict_p PROTO((int, rtx, int, rtx,
- HOST_WIDE_INT));
static void add_dependence PROTO((rtx, rtx, enum reg_note));
static void remove_dependence PROTO((rtx, rtx));
static rtx find_insn_list PROTO((rtx, rtx));
@@ -313,16 +313,16 @@ static int insn_cost PROTO((rtx, rtx, rtx));
static int priority PROTO((rtx));
static void free_pending_lists PROTO((void));
static void add_insn_mem_dependence PROTO((rtx *, rtx *, rtx, rtx));
-static void flush_pending_lists PROTO((rtx));
+static void flush_pending_lists PROTO((rtx, int));
static void sched_analyze_1 PROTO((rtx, rtx));
static void sched_analyze_2 PROTO((rtx, rtx));
static void sched_analyze_insn PROTO((rtx, rtx, rtx));
static int sched_analyze PROTO((rtx, rtx));
static void sched_note_set PROTO((int, rtx, int));
-static int rank_for_schedule PROTO((rtx *, rtx *));
+static int rank_for_schedule PROTO((const GENERIC_PTR, const GENERIC_PTR));
static void swap_sort PROTO((rtx *, int));
static void queue_insn PROTO((rtx, int));
-static int birthing_insn PROTO((rtx));
+static int birthing_insn_p PROTO((rtx));
static void adjust_priority PROTO((rtx));
static int schedule_insn PROTO((rtx, rtx *, int, int));
static int schedule_select PROTO((rtx *, int, int, FILE *));
@@ -330,9 +330,9 @@ static void create_reg_dead_note PROTO((rtx, rtx));
static void attach_deaths PROTO((rtx, rtx, int));
static void attach_deaths_insn PROTO((rtx));
static rtx unlink_notes PROTO((rtx, rtx));
-static int new_sometimes_live PROTO((struct sometimes *, int, int,
- int));
+static int new_sometimes_live PROTO((struct sometimes *, int, int));
static void finish_sometimes_live PROTO((struct sometimes *, int));
+static rtx reemit_notes PROTO((rtx, rtx));
static void schedule_block PROTO((int, FILE *));
static rtx regno_use_in PROTO((int, rtx));
static void split_hard_reg_notes PROTO((rtx, rtx, rtx, rtx));
@@ -347,540 +347,6 @@ void schedule_insns PROTO((FILE *));
#define SIZE_FOR_MODE(X) (GET_MODE_SIZE (GET_MODE (X)))
-/* Vector indexed by N giving the initial (unchanging) value known
- for pseudo-register N. */
-static rtx *reg_known_value;
-
-/* Vector recording for each reg_known_value whether it is due to a
- REG_EQUIV note. Future passes (viz., reload) may replace the
- pseudo with the equivalent expression and so we account for the
- dependences that would be introduced if that happens. */
-/* ??? This is a problem only on the Convex. The REG_EQUIV notes created in
- assign_parms mention the arg pointer, and there are explicit insns in the
- RTL that modify the arg pointer. Thus we must ensure that such insns don't
- get scheduled across each other because that would invalidate the REG_EQUIV
- notes. One could argue that the REG_EQUIV notes are wrong, but solving
- the problem in the scheduler will likely give better code, so we do it
- here. */
-static char *reg_known_equiv_p;
-
-/* Indicates number of valid entries in reg_known_value. */
-static int reg_known_value_size;
-
-static rtx
-canon_rtx (x)
- rtx x;
-{
- if (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER
- && REGNO (x) <= reg_known_value_size)
- return reg_known_value[REGNO (x)];
- else if (GET_CODE (x) == PLUS)
- {
- rtx x0 = canon_rtx (XEXP (x, 0));
- rtx x1 = canon_rtx (XEXP (x, 1));
-
- if (x0 != XEXP (x, 0) || x1 != XEXP (x, 1))
- {
- /* We can tolerate LO_SUMs being offset here; these
- rtl are used for nothing other than comparisons. */
- if (GET_CODE (x0) == CONST_INT)
- return plus_constant_for_output (x1, INTVAL (x0));
- else if (GET_CODE (x1) == CONST_INT)
- return plus_constant_for_output (x0, INTVAL (x1));
- return gen_rtx (PLUS, GET_MODE (x), x0, x1);
- }
- }
- return x;
-}
-
-/* Set up all info needed to perform alias analysis on memory references. */
-
-void
-init_alias_analysis ()
-{
- int maxreg = max_reg_num ();
- rtx insn;
- rtx note;
- rtx set;
-
- reg_known_value_size = maxreg;
-
- reg_known_value
- = (rtx *) oballoc ((maxreg-FIRST_PSEUDO_REGISTER) * sizeof (rtx))
- - FIRST_PSEUDO_REGISTER;
- bzero ((char *) (reg_known_value + FIRST_PSEUDO_REGISTER),
- (maxreg-FIRST_PSEUDO_REGISTER) * sizeof (rtx));
-
- reg_known_equiv_p
- = (char *) oballoc ((maxreg -FIRST_PSEUDO_REGISTER) * sizeof (char))
- - FIRST_PSEUDO_REGISTER;
- bzero (reg_known_equiv_p + FIRST_PSEUDO_REGISTER,
- (maxreg - FIRST_PSEUDO_REGISTER) * sizeof (char));
-
- /* Fill in the entries with known constant values. */
- for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
- if ((set = single_set (insn)) != 0
- && GET_CODE (SET_DEST (set)) == REG
- && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
- && (((note = find_reg_note (insn, REG_EQUAL, 0)) != 0
- && reg_n_sets[REGNO (SET_DEST (set))] == 1)
- || (note = find_reg_note (insn, REG_EQUIV, NULL_RTX)) != 0)
- && GET_CODE (XEXP (note, 0)) != EXPR_LIST)
- {
- int regno = REGNO (SET_DEST (set));
- reg_known_value[regno] = XEXP (note, 0);
- reg_known_equiv_p[regno] = REG_NOTE_KIND (note) == REG_EQUIV;
- }
-
- /* Fill in the remaining entries. */
- while (--maxreg >= FIRST_PSEUDO_REGISTER)
- if (reg_known_value[maxreg] == 0)
- reg_known_value[maxreg] = regno_reg_rtx[maxreg];
-}
-
-/* Return 1 if X and Y are identical-looking rtx's.
-
- We use the data in reg_known_value above to see if two registers with
- different numbers are, in fact, equivalent. */
-
-static int
-rtx_equal_for_memref_p (x, y)
- rtx x, y;
-{
- register int i;
- register int j;
- register enum rtx_code code;
- register char *fmt;
-
- if (x == 0 && y == 0)
- return 1;
- if (x == 0 || y == 0)
- return 0;
- x = canon_rtx (x);
- y = canon_rtx (y);
-
- if (x == y)
- return 1;
-
- code = GET_CODE (x);
- /* Rtx's of different codes cannot be equal. */
- if (code != GET_CODE (y))
- return 0;
-
- /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
- (REG:SI x) and (REG:HI x) are NOT equivalent. */
-
- if (GET_MODE (x) != GET_MODE (y))
- return 0;
-
- /* REG, LABEL_REF, and SYMBOL_REF can be compared nonrecursively. */
-
- if (code == REG)
- return REGNO (x) == REGNO (y);
- if (code == LABEL_REF)
- return XEXP (x, 0) == XEXP (y, 0);
- if (code == SYMBOL_REF)
- return XSTR (x, 0) == XSTR (y, 0);
-
- /* For commutative operations, the RTX match if the operand match in any
- order. Also handle the simple binary and unary cases without a loop. */
- if (code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
- return ((rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0))
- && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 1)))
- || (rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 1))
- && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 0))));
- else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
- return (rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0))
- && rtx_equal_for_memref_p (XEXP (x, 1), XEXP (y, 1)));
- else if (GET_RTX_CLASS (code) == '1')
- return rtx_equal_for_memref_p (XEXP (x, 0), XEXP (y, 0));
-
- /* Compare the elements. If any pair of corresponding elements
- fail to match, return 0 for the whole things. */
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- switch (fmt[i])
- {
- case 'w':
- if (XWINT (x, i) != XWINT (y, i))
- return 0;
- break;
-
- case 'n':
- case 'i':
- if (XINT (x, i) != XINT (y, i))
- return 0;
- break;
-
- case 'V':
- case 'E':
- /* Two vectors must have the same length. */
- if (XVECLEN (x, i) != XVECLEN (y, i))
- return 0;
-
- /* And the corresponding elements must match. */
- for (j = 0; j < XVECLEN (x, i); j++)
- if (rtx_equal_for_memref_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0)
- return 0;
- break;
-
- case 'e':
- if (rtx_equal_for_memref_p (XEXP (x, i), XEXP (y, i)) == 0)
- return 0;
- break;
-
- case 'S':
- case 's':
- if (strcmp (XSTR (x, i), XSTR (y, i)))
- return 0;
- break;
-
- case 'u':
- /* These are just backpointers, so they don't matter. */
- break;
-
- case '0':
- break;
-
- /* It is believed that rtx's at this level will never
- contain anything but integers and other rtx's,
- except for within LABEL_REFs and SYMBOL_REFs. */
- default:
- abort ();
- }
- }
- return 1;
-}
-
-/* Given an rtx X, find a SYMBOL_REF or LABEL_REF within
- X and return it, or return 0 if none found. */
-
-static rtx
-find_symbolic_term (x)
- rtx x;
-{
- register int i;
- register enum rtx_code code;
- register char *fmt;
-
- code = GET_CODE (x);
- if (code == SYMBOL_REF || code == LABEL_REF)
- return x;
- if (GET_RTX_CLASS (code) == 'o')
- return 0;
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- rtx t;
-
- if (fmt[i] == 'e')
- {
- t = find_symbolic_term (XEXP (x, i));
- if (t != 0)
- return t;
- }
- else if (fmt[i] == 'E')
- break;
- }
- return 0;
-}
-
-/* Return nonzero if X and Y (memory addresses) could reference the
- same location in memory. C is an offset accumulator. When
- C is nonzero, we are testing aliases between X and Y + C.
- XSIZE is the size in bytes of the X reference,
- similarly YSIZE is the size in bytes for Y.
-
- If XSIZE or YSIZE is zero, we do not know the amount of memory being
- referenced (the reference was BLKmode), so make the most pessimistic
- assumptions.
-
- We recognize the following cases of non-conflicting memory:
-
- (1) addresses involving the frame pointer cannot conflict
- with addresses involving static variables.
- (2) static variables with different addresses cannot conflict.
-
- Nice to notice that varying addresses cannot conflict with fp if no
- local variables had their addresses taken, but that's too hard now. */
-
-/* ??? In Fortran, references to a array parameter can never conflict with
- another array parameter. */
-
-static int
-memrefs_conflict_p (xsize, x, ysize, y, c)
- rtx x, y;
- int xsize, ysize;
- HOST_WIDE_INT c;
-{
- if (GET_CODE (x) == HIGH)
- x = XEXP (x, 0);
- else if (GET_CODE (x) == LO_SUM)
- x = XEXP (x, 1);
- else
- x = canon_rtx (x);
- if (GET_CODE (y) == HIGH)
- y = XEXP (y, 0);
- else if (GET_CODE (y) == LO_SUM)
- y = XEXP (y, 1);
- else
- y = canon_rtx (y);
-
- if (rtx_equal_for_memref_p (x, y))
- return (xsize == 0 || ysize == 0 ||
- (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
-
- if (y == frame_pointer_rtx || y == hard_frame_pointer_rtx
- || y == stack_pointer_rtx)
- {
- rtx t = y;
- int tsize = ysize;
- y = x; ysize = xsize;
- x = t; xsize = tsize;
- }
-
- if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx
- || x == stack_pointer_rtx)
- {
- rtx y1;
-
- if (CONSTANT_P (y))
- return 0;
-
- if (GET_CODE (y) == PLUS
- && canon_rtx (XEXP (y, 0)) == x
- && (y1 = canon_rtx (XEXP (y, 1)))
- && GET_CODE (y1) == CONST_INT)
- {
- c += INTVAL (y1);
- return (xsize == 0 || ysize == 0
- || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
- }
-
- if (GET_CODE (y) == PLUS
- && (y1 = canon_rtx (XEXP (y, 0)))
- && CONSTANT_P (y1))
- return 0;
-
- return 1;
- }
-
- if (GET_CODE (x) == PLUS)
- {
- /* The fact that X is canonicalized means that this
- PLUS rtx is canonicalized. */
- rtx x0 = XEXP (x, 0);
- rtx x1 = XEXP (x, 1);
-
- if (GET_CODE (y) == PLUS)
- {
- /* The fact that Y is canonicalized means that this
- PLUS rtx is canonicalized. */
- rtx y0 = XEXP (y, 0);
- rtx y1 = XEXP (y, 1);
-
- if (rtx_equal_for_memref_p (x1, y1))
- return memrefs_conflict_p (xsize, x0, ysize, y0, c);
- if (rtx_equal_for_memref_p (x0, y0))
- return memrefs_conflict_p (xsize, x1, ysize, y1, c);
- if (GET_CODE (x1) == CONST_INT)
- if (GET_CODE (y1) == CONST_INT)
- return memrefs_conflict_p (xsize, x0, ysize, y0,
- c - INTVAL (x1) + INTVAL (y1));
- else
- return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1));
- else if (GET_CODE (y1) == CONST_INT)
- return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
-
- /* Handle case where we cannot understand iteration operators,
- but we notice that the base addresses are distinct objects. */
- x = find_symbolic_term (x);
- if (x == 0)
- return 1;
- y = find_symbolic_term (y);
- if (y == 0)
- return 1;
- return rtx_equal_for_memref_p (x, y);
- }
- else if (GET_CODE (x1) == CONST_INT)
- return memrefs_conflict_p (xsize, x0, ysize, y, c - INTVAL (x1));
- }
- else if (GET_CODE (y) == PLUS)
- {
- /* The fact that Y is canonicalized means that this
- PLUS rtx is canonicalized. */
- rtx y0 = XEXP (y, 0);
- rtx y1 = XEXP (y, 1);
-
- if (GET_CODE (y1) == CONST_INT)
- return memrefs_conflict_p (xsize, x, ysize, y0, c + INTVAL (y1));
- else
- return 1;
- }
-
- if (GET_CODE (x) == GET_CODE (y))
- switch (GET_CODE (x))
- {
- case MULT:
- {
- /* Handle cases where we expect the second operands to be the
- same, and check only whether the first operand would conflict
- or not. */
- rtx x0, y0;
- rtx x1 = canon_rtx (XEXP (x, 1));
- rtx y1 = canon_rtx (XEXP (y, 1));
- if (! rtx_equal_for_memref_p (x1, y1))
- return 1;
- x0 = canon_rtx (XEXP (x, 0));
- y0 = canon_rtx (XEXP (y, 0));
- if (rtx_equal_for_memref_p (x0, y0))
- return (xsize == 0 || ysize == 0
- || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
-
- /* Can't properly adjust our sizes. */
- if (GET_CODE (x1) != CONST_INT)
- return 1;
- xsize /= INTVAL (x1);
- ysize /= INTVAL (x1);
- c /= INTVAL (x1);
- return memrefs_conflict_p (xsize, x0, ysize, y0, c);
- }
- }
-
- if (CONSTANT_P (x))
- {
- if (GET_CODE (x) == CONST_INT && GET_CODE (y) == CONST_INT)
- {
- c += (INTVAL (y) - INTVAL (x));
- return (xsize == 0 || ysize == 0
- || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0));
- }
-
- if (GET_CODE (x) == CONST)
- {
- if (GET_CODE (y) == CONST)
- return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)),
- ysize, canon_rtx (XEXP (y, 0)), c);
- else
- return memrefs_conflict_p (xsize, canon_rtx (XEXP (x, 0)),
- ysize, y, c);
- }
- if (GET_CODE (y) == CONST)
- return memrefs_conflict_p (xsize, x, ysize,
- canon_rtx (XEXP (y, 0)), c);
-
- if (CONSTANT_P (y))
- return (rtx_equal_for_memref_p (x, y)
- && (xsize == 0 || ysize == 0
- || (c >= 0 && xsize > c) || (c < 0 && ysize+c > 0)));
-
- return 1;
- }
- return 1;
-}
-
-/* Functions to compute memory dependencies.
-
- Since we process the insns in execution order, we can build tables
- to keep track of what registers are fixed (and not aliased), what registers
- are varying in known ways, and what registers are varying in unknown
- ways.
-
- If both memory references are volatile, then there must always be a
- dependence between the two references, since their order can not be
- changed. A volatile and non-volatile reference can be interchanged
- though.
-
- A MEM_IN_STRUCT reference at a non-QImode varying address can never
- conflict with a non-MEM_IN_STRUCT reference at a fixed address. We must
- allow QImode aliasing because the ANSI C standard allows character
- pointers to alias anything. We are assuming that characters are
- always QImode here. */
-
-/* Read dependence: X is read after read in MEM takes place. There can
- only be a dependence here if both reads are volatile. */
-
-int
-read_dependence (mem, x)
- rtx mem;
- rtx x;
-{
- return MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem);
-}
-
-/* True dependence: X is read after store in MEM takes place. */
-
-int
-true_dependence (mem, x)
- rtx mem;
- rtx x;
-{
- /* If X is an unchanging read, then it can't possibly conflict with any
- non-unchanging store. It may conflict with an unchanging write though,
- because there may be a single store to this address to initialize it.
- Just fall through to the code below to resolve the case where we have
- both an unchanging read and an unchanging write. This won't handle all
- cases optimally, but the possible performance loss should be
- negligible. */
- if (RTX_UNCHANGING_P (x) && ! RTX_UNCHANGING_P (mem))
- return 0;
-
- return ((MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
- || (memrefs_conflict_p (SIZE_FOR_MODE (mem), XEXP (mem, 0),
- SIZE_FOR_MODE (x), XEXP (x, 0), 0)
- && ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
- && GET_MODE (mem) != QImode
- && ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
- && ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
- && GET_MODE (x) != QImode
- && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem))));
-}
-
-/* Anti dependence: X is written after read in MEM takes place. */
-
-int
-anti_dependence (mem, x)
- rtx mem;
- rtx x;
-{
- /* If MEM is an unchanging read, then it can't possibly conflict with
- the store to X, because there is at most one store to MEM, and it must
- have occurred somewhere before MEM. */
- if (RTX_UNCHANGING_P (mem))
- return 0;
-
- return ((MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
- || (memrefs_conflict_p (SIZE_FOR_MODE (mem), XEXP (mem, 0),
- SIZE_FOR_MODE (x), XEXP (x, 0), 0)
- && ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
- && GET_MODE (mem) != QImode
- && ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
- && ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
- && GET_MODE (x) != QImode
- && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem))));
-}
-
-/* Output dependence: X is written after store in MEM takes place. */
-
-int
-output_dependence (mem, x)
- rtx mem;
- rtx x;
-{
- return ((MEM_VOLATILE_P (x) && MEM_VOLATILE_P (mem))
- || (memrefs_conflict_p (SIZE_FOR_MODE (mem), XEXP (mem, 0),
- SIZE_FOR_MODE (x), XEXP (x, 0), 0)
- && ! (MEM_IN_STRUCT_P (mem) && rtx_addr_varies_p (mem)
- && GET_MODE (mem) != QImode
- && ! MEM_IN_STRUCT_P (x) && ! rtx_addr_varies_p (x))
- && ! (MEM_IN_STRUCT_P (x) && rtx_addr_varies_p (x)
- && GET_MODE (x) != QImode
- && ! MEM_IN_STRUCT_P (mem) && ! rtx_addr_varies_p (mem))));
-}
-
/* Helper functions for instruction scheduling. */
/* Add ELEM wrapped in an INSN_LIST with reg note kind DEP_TYPE to the
@@ -912,7 +378,8 @@ add_dependence (insn, elem, dep_type)
next = NEXT_INSN (next);
#endif
- if (next && SCHED_GROUP_P (next))
+ if (next && SCHED_GROUP_P (next)
+ && GET_CODE (next) != CODE_LABEL)
{
/* Notes will never intervene here though, so don't bother checking
for them. */
@@ -964,17 +431,19 @@ remove_dependence (insn, elem)
rtx prev, link;
int found = 0;
- for (prev = 0, link = LOG_LINKS (insn); link;
- prev = link, link = XEXP (link, 1))
+ for (prev = 0, link = LOG_LINKS (insn); link; link = XEXP (link, 1))
{
if (XEXP (link, 0) == elem)
{
+ RTX_INTEGRATED_P (link) = 1;
if (prev)
XEXP (prev, 1) = XEXP (link, 1);
else
LOG_LINKS (insn) = XEXP (link, 1);
found = 1;
}
+ else
+ prev = link;
}
if (! found)
@@ -1278,9 +747,9 @@ actual_hazard (unit, insn, clock, cost)
int instance = unit;
int best_cost = actual_hazard_this_instance (unit, instance, insn,
clock, cost);
+#if MAX_MULTIPLICITY > 1
int this_cost;
-#if MAX_MULTIPLICITY > 1
if (best_cost > cost)
{
for (i = function_units[unit].multiplicity - 1; i > 0; i--)
@@ -1452,6 +921,11 @@ priority (insn)
{
rtx x = XEXP (prev, 0);
+ /* If this was a duplicate of a dependence we already deleted,
+ ignore it. */
+ if (RTX_INTEGRATED_P (prev))
+ continue;
+
/* A dependence pointing to a note or deleted insn is always
obsolete, because sched_analyze_insn will have created any
necessary new dependences which replace it. Notes and deleted
@@ -1608,15 +1082,17 @@ add_insn_mem_dependence (insn_list, mem_list, insn, mem)
}
/* Make a dependency between every memory reference on the pending lists
- and INSN, thus flushing the pending lists. */
+ and INSN, thus flushing the pending lists. If ONLY_WRITE, don't flush
+ the read list. */
static void
-flush_pending_lists (insn)
+flush_pending_lists (insn, only_write)
rtx insn;
+ int only_write;
{
rtx link;
- while (pending_read_insns)
+ while (pending_read_insns && ! only_write)
{
add_dependence (insn, XEXP (pending_read_insns, 0), REG_DEP_ANTI);
@@ -1699,8 +1175,7 @@ sched_analyze_1 (x, insn)
if (reg_last_sets[regno + i])
add_dependence (insn, reg_last_sets[regno + i],
REG_DEP_OUTPUT);
- reg_pending_sets[(regno + i) / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << ((regno + i) % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (reg_pending_sets, regno + i);
if ((call_used_regs[i] || global_regs[i])
&& last_function_call)
/* Function calls clobber all call_used regs. */
@@ -1716,8 +1191,7 @@ sched_analyze_1 (x, insn)
reg_last_uses[regno] = 0;
if (reg_last_sets[regno])
add_dependence (insn, reg_last_sets[regno], REG_DEP_OUTPUT);
- reg_pending_sets[regno / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (reg_pending_sets, regno);
/* Pseudos that are REG_EQUIV to something may be replaced
by that during reloading. We need only add dependencies for
@@ -1729,7 +1203,7 @@ sched_analyze_1 (x, insn)
/* Don't let it cross a call after scheduling if it doesn't
already cross one. */
- if (reg_n_calls_crossed[regno] == 0 && last_function_call)
+ if (REG_N_CALLS_CROSSED (regno) == 0 && last_function_call)
add_dependence (insn, last_function_call, REG_DEP_ANTI);
}
}
@@ -1745,7 +1219,7 @@ sched_analyze_1 (x, insn)
seems like a reasonable number. When compiling GCC with itself,
this flush occurs 8 times for sparc, and 10 times for m88k using
the number 32. */
- flush_pending_lists (insn);
+ flush_pending_lists (insn, 0);
}
else
{
@@ -1825,22 +1299,19 @@ sched_analyze_2 (x, insn)
{
rtx link, prev;
+ /* User of CC0 depends on immediately preceding insn. */
+ SCHED_GROUP_P (insn) = 1;
+
/* There may be a note before this insn now, but all notes will
be removed before we actually try to schedule the insns, so
it won't cause a problem later. We must avoid it here though. */
-
- /* User of CC0 depends on immediately preceding insn. */
- SCHED_GROUP_P (insn) = 1;
+ prev = prev_nonnote_insn (insn);
/* Make a copy of all dependencies on the immediately previous insn,
and add to this insn. This is so that all the dependencies will
apply to the group. Remove an explicit dependence on this insn
as SCHED_GROUP_P now represents it. */
- prev = PREV_INSN (insn);
- while (GET_CODE (prev) == NOTE)
- prev = PREV_INSN (prev);
-
if (find_insn_list (prev, LOG_LINKS (insn)))
remove_dependence (insn, prev);
@@ -1862,8 +1333,8 @@ sched_analyze_2 (x, insn)
while (--i >= 0)
{
reg_last_uses[regno + i]
- = gen_rtx (INSN_LIST, VOIDmode,
- insn, reg_last_uses[regno + i]);
+ = gen_rtx_INSN_LIST (VOIDmode,
+ insn, reg_last_uses[regno + i]);
if (reg_last_sets[regno + i])
add_dependence (insn, reg_last_sets[regno + i], 0);
if ((call_used_regs[regno + i] || global_regs[regno + i])
@@ -1875,7 +1346,7 @@ sched_analyze_2 (x, insn)
else
{
reg_last_uses[regno]
- = gen_rtx (INSN_LIST, VOIDmode, insn, reg_last_uses[regno]);
+ = gen_rtx_INSN_LIST (VOIDmode, insn, reg_last_uses[regno]);
if (reg_last_sets[regno])
add_dependence (insn, reg_last_sets[regno], 0);
@@ -1890,7 +1361,7 @@ sched_analyze_2 (x, insn)
/* If the register does not already cross any calls, then add this
insn to the sched_before_next_call list so that it will still
not cross calls after scheduling. */
- if (reg_n_calls_crossed[regno] == 0)
+ if (REG_N_CALLS_CROSSED (regno) == 0)
add_dependence (sched_before_next_call, insn, REG_DEP_ANTI);
}
return;
@@ -1921,7 +1392,8 @@ sched_analyze_2 (x, insn)
{
/* If a dependency already exists, don't create a new one. */
if (! find_insn_list (XEXP (pending, 0), LOG_LINKS (insn)))
- if (true_dependence (XEXP (pending_mem, 0), x))
+ if (true_dependence (XEXP (pending_mem, 0), VOIDmode,
+ x, rtx_varies_p))
add_dependence (insn, XEXP (pending, 0), 0);
pending = XEXP (pending, 1);
@@ -1967,7 +1439,7 @@ sched_analyze_2 (x, insn)
}
reg_pending_sets_all = 1;
- flush_pending_lists (insn);
+ flush_pending_lists (insn, 0);
}
/* For all ASM_OPERANDS, we must traverse the vector of input operands.
@@ -1997,6 +1469,9 @@ sched_analyze_2 (x, insn)
sched_analyze_2 (XEXP (x, 0), insn);
sched_analyze_1 (x, insn);
return;
+
+ default:
+ break;
}
/* Other cases: walk the insn. */
@@ -2050,7 +1525,7 @@ sched_analyze_insn (x, insn, loop_notes)
sched_analyze_2 (XEXP (link, 0), insn);
}
- /* If there is a LOOP_{BEG,END} note in the middle of a basic block, then
+ /* If there is a {LOOP,EHREGION}_{BEG,END} note in the middle of a basic block, then
we must be sure that no instructions are scheduled across it.
Otherwise, the reg_n_refs info (which depends on loop_depth) would
become incorrect. */
@@ -2071,7 +1546,7 @@ sched_analyze_insn (x, insn, loop_notes)
}
reg_pending_sets_all = 1;
- flush_pending_lists (insn);
+ flush_pending_lists (insn, 0);
link = loop_notes;
while (XEXP (link, 1))
@@ -2101,18 +1576,12 @@ sched_analyze_insn (x, insn, loop_notes)
sched_analyze_2 (XEXP (note, 0), insn);
}
- for (i = 0; i < regset_size; i++)
- {
- REGSET_ELT_TYPE sets = reg_pending_sets[i];
- if (sets)
- {
- register int bit;
- for (bit = 0; bit < REGSET_ELT_BITS; bit++)
- if (sets & ((REGSET_ELT_TYPE) 1 << bit))
- reg_last_sets[i * REGSET_ELT_BITS + bit] = insn;
- reg_pending_sets[i] = 0;
- }
- }
+ EXECUTE_IF_SET_IN_REG_SET (reg_pending_sets, 0, i,
+ {
+ reg_last_sets[i] = insn;
+ });
+ CLEAR_REG_SET (reg_pending_sets);
+
if (reg_pending_sets_all)
{
for (i = 0; i < maxreg; i++)
@@ -2212,11 +1681,16 @@ sched_analyze (head, tail)
}
reg_pending_sets_all = 1;
- /* Add a fake REG_NOTE which we will later convert
- back into a NOTE_INSN_SETJMP note. */
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_DEAD,
- GEN_INT (NOTE_INSN_SETJMP),
- REG_NOTES (insn));
+ /* Add a pair of fake REG_NOTEs which we will later
+ convert back into a NOTE_INSN_SETJMP note. See
+ reemit_notes for why we use a pair of NOTEs. */
+
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
+ GEN_INT (0),
+ REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD,
+ GEN_INT (NOTE_INSN_SETJMP),
+ REG_NOTES (insn));
}
else
{
@@ -2228,8 +1702,7 @@ sched_analyze (head, tail)
reg_last_uses[i] = 0;
if (reg_last_sets[i])
add_dependence (insn, reg_last_sets[i], REG_DEP_ANTI);
- reg_pending_sets[i / REGSET_ELT_BITS]
- |= (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
+ SET_REGNO_REG_SET (reg_pending_sets, i);
}
}
@@ -2246,30 +1719,43 @@ sched_analyze (head, tail)
sched_analyze_insn (PATTERN (insn), insn, loop_notes);
loop_notes = 0;
- /* We don't need to flush memory for a function call which does
- not involve memory. */
- if (! CONST_CALL_P (insn))
- {
- /* In the absence of interprocedural alias analysis,
- we must flush all pending reads and writes, and
- start new dependencies starting from here. */
- flush_pending_lists (insn);
- }
+ /* In the absence of interprocedural alias analysis, we must flush
+ all pending reads and writes, and start new dependencies starting
+ from here. But only flush writes for constant calls (which may
+ be passed a pointer to something we haven't written yet). */
+ flush_pending_lists (insn, CONST_CALL_P (insn));
/* Depend this function call (actually, the user of this
function call) on all hard register clobberage. */
last_function_call = insn;
n_insns += 1;
}
+
+ /* See comments on reemit_notes as to why we do this. */
else if (GET_CODE (insn) == NOTE
&& (NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END))
- loop_notes = gen_rtx (EXPR_LIST, REG_DEAD,
- GEN_INT (NOTE_LINE_NUMBER (insn)), loop_notes);
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_LOOP_END
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_START
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_RANGE_END
+ || (NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP
+ && GET_CODE (PREV_INSN (insn)) != CALL_INSN)))
+ {
+ loop_notes = gen_rtx_EXPR_LIST (REG_DEAD,
+ GEN_INT (NOTE_BLOCK_NUMBER (insn)),
+ loop_notes);
+ loop_notes = gen_rtx_EXPR_LIST (REG_DEAD,
+ GEN_INT (NOTE_LINE_NUMBER (insn)),
+ loop_notes);
+ CONST_CALL_P (loop_notes) = CONST_CALL_P (insn);
+ }
if (insn == tail)
return n_insns;
}
+
+ abort ();
}
/* Called when we see a set of a register. If death is true, then we are
@@ -2313,10 +1799,6 @@ sched_note_set (b, x, death)
regno = REGNO (reg);
if (regno >= FIRST_PSEUDO_REGISTER || ! global_regs[regno])
{
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
-
if (death)
{
/* If we only set part of the register, then this set does not
@@ -2330,17 +1812,14 @@ sched_note_set (b, x, death)
int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (--j >= 0)
{
- offset = (regno + j) / REGSET_ELT_BITS;
- bit = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
+ SET_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+ SET_REGNO_REG_SET (bb_dead_regs, regno);
}
}
else
@@ -2351,17 +1830,14 @@ sched_note_set (b, x, death)
int j = HARD_REGNO_NREGS (regno, GET_MODE (reg));
while (--j >= 0)
{
- offset = (regno + j) / REGSET_ELT_BITS;
- bit = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-
- bb_live_regs[offset] |= bit;
- bb_dead_regs[offset] &= ~bit;
+ SET_REGNO_REG_SET (bb_live_regs, regno + j);
+ CLEAR_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
- bb_live_regs[offset] |= bit;
- bb_dead_regs[offset] &= ~bit;
+ SET_REGNO_REG_SET (bb_live_regs, regno);
+ CLEAR_REGNO_REG_SET (bb_dead_regs, regno);
}
}
}
@@ -2383,16 +1859,17 @@ sched_note_set (b, x, death)
static int
rank_for_schedule (x, y)
- rtx *x, *y;
+ const GENERIC_PTR x;
+ const GENERIC_PTR y;
{
- rtx tmp = *y;
- rtx tmp2 = *x;
+ rtx tmp = *(rtx *)y;
+ rtx tmp2 = *(rtx *)x;
rtx link;
int tmp_class, tmp2_class;
int value;
/* Choose the instruction with the highest priority, if different. */
- if (value = INSN_PRIORITY (tmp) - INSN_PRIORITY (tmp2))
+ if ((value = INSN_PRIORITY (tmp) - INSN_PRIORITY (tmp2)))
return value;
if (last_scheduled_insn)
@@ -2418,7 +1895,7 @@ rank_for_schedule (x, y)
else
tmp2_class = 2;
- if (value = tmp_class - tmp2_class)
+ if ((value = tmp_class - tmp2_class))
return value;
}
@@ -2479,15 +1956,13 @@ birthing_insn_p (pat)
{
rtx dest = SET_DEST (pat);
int i = REGNO (dest);
- int offset = i / REGSET_ELT_BITS;
- REGSET_ELT_TYPE bit = (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
/* It would be more accurate to use refers_to_regno_p or
reg_mentioned_p to determine when the dest is not live before this
insn. */
- if (bb_live_regs[offset] & bit)
- return (reg_n_sets[i] == 1);
+ if (REGNO_REG_SET_P (bb_live_regs, i))
+ return (REG_N_SETS (i) == 1);
return 0;
}
@@ -2545,6 +2020,9 @@ adjust_priority (prev)
}
break;
}
+#ifdef ADJUST_PRIORITY
+ ADJUST_PRIORITY (prev);
+#endif
}
}
@@ -2745,6 +2223,12 @@ create_reg_dead_note (reg, insn)
GET_MODE (XEXP (link, 0))));
while (reg_note_regs < regs_killed)
{
+ /* LINK might be zero if we killed more registers after scheduling
+ than before, and the last hard register we kill is actually
+ multiple hard regs. */
+ if (link == NULL_RTX)
+ abort ();
+
link = XEXP (link, 1);
reg_note_regs += (REGNO (XEXP (link, 0)) >= FIRST_PSEUDO_REGISTER ? 1
: HARD_REGNO_NREGS (REGNO (XEXP (link, 0)),
@@ -2757,7 +2241,7 @@ create_reg_dead_note (reg, insn)
{
rtx temp_reg, temp_link;
- temp_reg = gen_rtx (REG, word_mode, 0);
+ temp_reg = gen_rtx_REG (word_mode, 0);
temp_link = rtx_alloc (EXPR_LIST);
PUT_REG_NOTE_KIND (temp_link, REG_DEAD);
XEXP (temp_link, 0) = temp_reg;
@@ -2811,16 +2295,15 @@ attach_deaths (x, insn, set_p)
/* This code is very similar to mark_used_1 (if set_p is false)
and mark_set_1 (if set_p is true) in flow.c. */
- register int regno = REGNO (x);
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
- REGSET_ELT_TYPE all_needed = (old_live_regs[offset] & bit);
- REGSET_ELT_TYPE some_needed = (old_live_regs[offset] & bit);
+ register int regno;
+ int some_needed;
+ int all_needed;
if (set_p)
return;
+ regno = REGNO (x);
+ all_needed = some_needed = REGNO_REG_SET_P (old_live_regs, regno);
if (regno < FIRST_PSEUDO_REGISTER)
{
int n;
@@ -2828,12 +2311,9 @@ attach_deaths (x, insn, set_p)
n = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--n > 0)
{
- some_needed |= (old_live_regs[(regno + n) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno + n) % REGSET_ELT_BITS)));
- all_needed &= (old_live_regs[(regno + n) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno + n) % REGSET_ELT_BITS)));
+ int needed = (REGNO_REG_SET_P (old_live_regs, regno + n));
+ some_needed |= needed;
+ all_needed &= needed;
}
}
@@ -2865,12 +2345,7 @@ attach_deaths (x, insn, set_p)
#endif
&& regno != STACK_POINTER_REGNUM)
{
- /* ??? It is perhaps a dead_or_set_p bug that it does
- not check for REG_UNUSED notes itself. This is necessary
- for the case where the SET_DEST is a subreg of regno, as
- dead_or_set_p handles subregs specially. */
- if (! all_needed && ! dead_or_set_p (insn, x)
- && ! find_reg_note (insn, REG_UNUSED, x))
+ if (! all_needed && ! dead_or_set_p (insn, x))
{
/* Check for the case where the register dying partially
overlaps the register set by this insn. */
@@ -2895,13 +2370,10 @@ attach_deaths (x, insn, set_p)
register that is set in the insn. */
for (i = HARD_REGNO_NREGS (regno, GET_MODE (x)) - 1;
i >= 0; i--)
- if ((old_live_regs[(regno + i) / REGSET_ELT_BITS]
- & ((REGSET_ELT_TYPE) 1
- << ((regno +i) % REGSET_ELT_BITS))) == 0
+ if (! REGNO_REG_SET_P (old_live_regs, regno + i)
&& ! dead_or_set_regno_p (insn, regno + i))
- create_reg_dead_note (gen_rtx (REG,
- reg_raw_mode[regno + i],
- regno + i),
+ create_reg_dead_note (gen_rtx_REG (reg_raw_mode[regno + i],
+ regno + i),
insn);
}
}
@@ -2912,18 +2384,14 @@ attach_deaths (x, insn, set_p)
int j = HARD_REGNO_NREGS (regno, GET_MODE (x));
while (--j >= 0)
{
- offset = (regno + j) / REGSET_ELT_BITS;
- bit
- = (REGSET_ELT_TYPE) 1 << ((regno + j) % REGSET_ELT_BITS);
-
- bb_dead_regs[offset] &= ~bit;
- bb_live_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_dead_regs, regno + j);
+ SET_REGNO_REG_SET (bb_live_regs, regno + j);
}
}
else
{
- bb_dead_regs[offset] &= ~bit;
- bb_live_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_dead_regs, regno);
+ SET_REGNO_REG_SET (bb_live_regs, regno);
}
}
return;
@@ -2935,17 +2403,20 @@ attach_deaths (x, insn, set_p)
return;
case SUBREG:
+ attach_deaths (SUBREG_REG (x), insn,
+ set_p && ((GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+ <= UNITS_PER_WORD)
+ || (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))
+ == GET_MODE_SIZE (GET_MODE ((x))))));
+ return;
+
case STRICT_LOW_PART:
- /* These two cases preserve the value of SET_P, so handle them
- separately. */
- attach_deaths (XEXP (x, 0), insn, set_p);
+ attach_deaths (XEXP (x, 0), insn, 0);
return;
case ZERO_EXTRACT:
case SIGN_EXTRACT:
- /* This case preserves the value of SET_P for the first operand, but
- clears it for the other two. */
- attach_deaths (XEXP (x, 0), insn, set_p);
+ attach_deaths (XEXP (x, 0), insn, 0);
attach_deaths (XEXP (x, 1), insn, 0);
attach_deaths (XEXP (x, 2), insn, 0);
return;
@@ -3043,10 +2514,14 @@ unlink_notes (insn, tail)
/* Don't save away NOTE_INSN_SETJMPs, because they must remain
immediately after the call they follow. We use a fake
(REG_DEAD (const_int -1)) note to remember them.
- Likewise with NOTE_INSN_LOOP_BEG and NOTE_INSN_LOOP_END. */
+ Likewise with NOTE_INSN_{LOOP,EHREGION}_{BEG, END}. */
else if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_SETJMP
&& NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_BEG
- && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END)
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_LOOP_END
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_START
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_RANGE_END
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_BEG
+ && NOTE_LINE_NUMBER (insn) != NOTE_INSN_EH_REGION_END)
{
/* Insert the note at the end of the notes list. */
PREV_INSN (insn) = note_list;
@@ -3063,13 +2538,12 @@ unlink_notes (insn, tail)
/* Constructor for `sometimes' data structure. */
static int
-new_sometimes_live (regs_sometimes_live, offset, bit, sometimes_max)
+new_sometimes_live (regs_sometimes_live, regno, sometimes_max)
struct sometimes *regs_sometimes_live;
- int offset, bit;
+ int regno;
int sometimes_max;
{
register struct sometimes *p;
- register int regno = offset * REGSET_ELT_BITS + bit;
/* There should never be a register greater than max_regno here. If there
is, it means that a define_split has created a new pseudo reg. This
@@ -3079,8 +2553,7 @@ new_sometimes_live (regs_sometimes_live, offset, bit, sometimes_max)
abort ();
p = &regs_sometimes_live[sometimes_max];
- p->offset = offset;
- p->bit = bit;
+ p->regno = regno;
p->live_length = 0;
p->calls_crossed = 0;
sometimes_max++;
@@ -3100,19 +2573,19 @@ finish_sometimes_live (regs_sometimes_live, sometimes_max)
for (i = 0; i < sometimes_max; i++)
{
register struct sometimes *p = &regs_sometimes_live[i];
- int regno;
-
- regno = p->offset * REGSET_ELT_BITS + p->bit;
+ int regno = p->regno;
sched_reg_live_length[regno] += p->live_length;
sched_reg_n_calls_crossed[regno] += p->calls_crossed;
}
}
-/* Search INSN for fake REG_DEAD notes for NOTE_INSN_SETJMP,
- NOTE_INSN_LOOP_BEG, and NOTE_INSN_LOOP_END; and convert them back
- into NOTEs. LAST is the last instruction output by the instruction
- scheduler. Return the new value of LAST. */
+/* Search INSN for fake REG_DEAD note pairs for NOTE_INSN_SETJMP,
+ NOTE_INSN_{LOOP,EHREGION}_{BEG,END}; and convert them back into
+ NOTEs. The REG_DEAD note following first one is contains the saved
+ value for NOTE_BLOCK_NUMBER which is useful for
+ NOTE_INSN_EH_REGION_{BEG,END} NOTEs. LAST is the last instruction
+ output by the instruction scheduler. Return the new value of LAST. */
static rtx
reemit_notes (insn, last)
@@ -3127,9 +2600,19 @@ reemit_notes (insn, last)
&& GET_CODE (XEXP (note, 0)) == CONST_INT)
{
if (INTVAL (XEXP (note, 0)) == NOTE_INSN_SETJMP)
- emit_note_after (INTVAL (XEXP (note, 0)), insn);
+ {
+ CONST_CALL_P (emit_note_after (INTVAL (XEXP (note, 0)), insn))
+ = CONST_CALL_P (note);
+ remove_note (insn, note);
+ note = XEXP (note, 1);
+ }
else
- last = emit_note_before (INTVAL (XEXP (note, 0)), last);
+ {
+ last = emit_note_before (INTVAL (XEXP (note, 0)), last);
+ remove_note (insn, note);
+ note = XEXP (note, 1);
+ NOTE_BLOCK_NUMBER (last) = INTVAL (XEXP (note, 0));
+ }
remove_note (insn, note);
}
}
@@ -3147,7 +2630,7 @@ schedule_block (b, file)
{
rtx insn, last;
rtx *ready, link;
- int i, j, n_ready = 0, new_ready, n_insns = 0;
+ int i, j, n_ready = 0, new_ready, n_insns;
int sched_n_insns = 0;
int clock;
#define NEED_NOTHING 0
@@ -3178,11 +2661,19 @@ schedule_block (b, file)
bzero ((char *) reg_last_uses, i * sizeof (rtx));
reg_last_sets = (rtx *) alloca (i * sizeof (rtx));
bzero ((char *) reg_last_sets, i * sizeof (rtx));
- reg_pending_sets = (regset) alloca (regset_bytes);
- bzero ((char *) reg_pending_sets, regset_bytes);
+ reg_pending_sets = ALLOCA_REG_SET ();
+ CLEAR_REG_SET (reg_pending_sets);
reg_pending_sets_all = 0;
clear_units ();
+#if 0
+ /* We used to have code to avoid getting parameters moved from hard
+ argument registers into pseudos.
+
+ However, it was removed when it proved to be of marginal benefit and
+ caused problems because of different notions of what the "head" insn
+ was. */
+
/* Remove certain insns at the beginning from scheduling,
by advancing HEAD. */
@@ -3213,6 +2704,7 @@ schedule_block (b, file)
head = NEXT_INSN (head);
}
}
+#endif
/* Don't include any notes or labels at the beginning of the
basic block, or notes at the ends of basic blocks. */
@@ -3230,7 +2722,7 @@ schedule_block (b, file)
to schedule this block. */
if (head == tail
&& (GET_CODE (head) == NOTE || GET_CODE (head) == CODE_LABEL))
- return;
+ goto ret;
#if 0
/* This short-cut doesn't work. It does not count call insns crossed by
@@ -3243,7 +2735,7 @@ schedule_block (b, file)
has one insn, so this won't slow down this pass by much. */
if (head == tail)
- return;
+ goto ret;
#endif
/* Now HEAD through TAIL are the insns actually to be rearranged;
@@ -3264,11 +2756,11 @@ schedule_block (b, file)
LOG_LINKS (sched_before_next_call) = 0;
- n_insns += sched_analyze (head, tail);
+ n_insns = sched_analyze (head, tail);
if (n_insns == 0)
{
free_pending_lists ();
- return;
+ goto ret;
}
/* Allocate vector to hold insns to be rearranged (except those
@@ -3358,9 +2850,7 @@ schedule_block (b, file)
{
while (SCHED_GROUP_P (insn))
{
- insn = PREV_INSN (insn);
- while (GET_CODE (insn) == NOTE)
- insn = PREV_INSN (insn);
+ insn = prev_nonnote_insn (insn);
priority (insn);
}
continue;
@@ -3400,7 +2890,7 @@ schedule_block (b, file)
finish_sometimes_live (regs_sometimes_live, sometimes_max);
}
free_pending_lists ();
- return;
+ goto ret;
}
#endif
@@ -3414,9 +2904,8 @@ schedule_block (b, file)
if (reload_completed == 0)
{
- bcopy ((char *) basic_block_live_at_start[b], (char *) bb_live_regs,
- regset_bytes);
- bzero ((char *) bb_dead_regs, regset_bytes);
+ COPY_REG_SET (bb_live_regs, basic_block_live_at_start[b]);
+ CLEAR_REG_SET (bb_dead_regs);
if (b == 0)
{
@@ -3455,6 +2944,22 @@ schedule_block (b, file)
sched_note_set (b, XVECEXP (PATTERN (insn), 0, j), 0);
}
+ /* Each call clobbers (makes live) all call-clobbered regs
+ that are not global or fixed. Note that the function-value
+ reg is a call_clobbered reg. */
+
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ int j;
+ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+ if (call_used_regs[j] && ! global_regs[j]
+ && ! fixed_regs[j])
+ {
+ SET_REGNO_REG_SET (bb_live_regs, j);
+ CLEAR_REGNO_REG_SET (bb_dead_regs, j);
+ }
+ }
+
for (link = REG_NOTES (insn); link; link = XEXP (link, 1))
{
if ((REG_NOTE_KIND (link) == REG_DEAD
@@ -3463,9 +2968,6 @@ schedule_block (b, file)
&& GET_CODE (XEXP (link, 0)) == REG)
{
register int regno = REGNO (XEXP (link, 0));
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
if (regno < FIRST_PSEUDO_REGISTER)
{
@@ -3473,18 +2975,14 @@ schedule_block (b, file)
GET_MODE (XEXP (link, 0)));
while (--j >= 0)
{
- offset = (regno + j) / REGSET_ELT_BITS;
- bit = ((REGSET_ELT_TYPE) 1
- << ((regno + j) % REGSET_ELT_BITS));
-
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
+ SET_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+ SET_REGNO_REG_SET (bb_dead_regs, regno);
}
}
}
@@ -3556,6 +3054,22 @@ schedule_block (b, file)
sched_note_set (b, XVECEXP (PATTERN (insn), 0, j), 0);
}
+ /* Each call clobbers (makes live) all call-clobbered regs that are
+ not global or fixed. Note that the function-value reg is a
+ call_clobbered reg. */
+
+ if (GET_CODE (insn) == CALL_INSN)
+ {
+ int j;
+ for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
+ if (call_used_regs[j] && ! global_regs[j]
+ && ! fixed_regs[j])
+ {
+ SET_REGNO_REG_SET (bb_live_regs, j);
+ CLEAR_REGNO_REG_SET (bb_dead_regs, j);
+ }
+ }
+
/* Need to know what registers this insn kills. */
for (prev = 0, link = REG_NOTES (insn); link; link = next)
{
@@ -3566,9 +3080,6 @@ schedule_block (b, file)
&& GET_CODE (XEXP (link, 0)) == REG)
{
register int regno = REGNO (XEXP (link, 0));
- register int offset = regno / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (regno % REGSET_ELT_BITS);
/* Only unlink REG_DEAD notes; leave REG_UNUSED notes
alone. */
@@ -3590,18 +3101,14 @@ schedule_block (b, file)
GET_MODE (XEXP (link, 0)));
while (--j >= 0)
{
- offset = (regno + j) / REGSET_ELT_BITS;
- bit = ((REGSET_ELT_TYPE) 1
- << ((regno + j) % REGSET_ELT_BITS));
-
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno + j);
+ SET_REGNO_REG_SET (bb_dead_regs, regno + j);
}
}
else
{
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, regno);
+ SET_REGNO_REG_SET (bb_dead_regs, regno);
}
}
else
@@ -3613,25 +3120,19 @@ schedule_block (b, file)
if (reload_completed == 0)
{
/* Keep track of register lives. */
- old_live_regs = (regset) alloca (regset_bytes);
+ old_live_regs = ALLOCA_REG_SET ();
regs_sometimes_live
= (struct sometimes *) alloca (max_regno * sizeof (struct sometimes));
sometimes_max = 0;
/* Start with registers live at end. */
- for (j = 0; j < regset_size; j++)
- {
- REGSET_ELT_TYPE live = bb_live_regs[j];
- old_live_regs[j] = live;
- if (live)
- {
- register int bit;
- for (bit = 0; bit < REGSET_ELT_BITS; bit++)
- if (live & ((REGSET_ELT_TYPE) 1 << bit))
- sometimes_max = new_sometimes_live (regs_sometimes_live, j,
- bit, sometimes_max);
- }
- }
+ COPY_REG_SET (old_live_regs, bb_live_regs);
+ EXECUTE_IF_SET_IN_REG_SET (bb_live_regs, 0, j,
+ {
+ sometimes_max
+ = new_sometimes_live (regs_sometimes_live,
+ j, sometimes_max);
+ });
}
SCHED_SORT (ready, n_ready, 1);
@@ -3692,7 +3193,7 @@ schedule_block (b, file)
register int stalls;
for (stalls = 1; stalls < INSN_QUEUE_SIZE; stalls++)
- if (insn = insn_queue[NEXT_Q_AFTER (q_ptr, stalls)])
+ if ((insn = insn_queue[NEXT_Q_AFTER (q_ptr, stalls)]))
{
for (; insn; insn = NEXT_INSN (insn))
{
@@ -3795,18 +3296,15 @@ schedule_block (b, file)
{
register struct sometimes *p;
- /* A call kills all call used and global registers, except
- for those mentioned in the call pattern which will be
- made live again later. */
+ /* A call kills all call used registers that are not
+ global or fixed, except for those mentioned in the call
+ pattern which will be made live again later. */
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (call_used_regs[i] || global_regs[i])
+ if (call_used_regs[i] && ! global_regs[i]
+ && ! fixed_regs[i])
{
- register int offset = i / REGSET_ELT_BITS;
- register REGSET_ELT_TYPE bit
- = (REGSET_ELT_TYPE) 1 << (i % REGSET_ELT_BITS);
-
- bb_live_regs[offset] &= ~bit;
- bb_dead_regs[offset] |= bit;
+ CLEAR_REGNO_REG_SET (bb_live_regs, i);
+ SET_REGNO_REG_SET (bb_dead_regs, i);
}
/* Regs live at the time of a call instruction must not
@@ -3817,8 +3315,7 @@ schedule_block (b, file)
(below). */
p = regs_sometimes_live;
for (i = 0; i < sometimes_max; i++, p++)
- if (bb_live_regs[p->offset]
- & ((REGSET_ELT_TYPE) 1 << p->bit))
+ if (REGNO_REG_SET_P (bb_live_regs, p->regno))
p->calls_crossed += 1;
}
@@ -3827,20 +3324,13 @@ schedule_block (b, file)
attach_deaths_insn (insn);
/* Find registers now made live by that instruction. */
- for (i = 0; i < regset_size; i++)
- {
- REGSET_ELT_TYPE diff = bb_live_regs[i] & ~old_live_regs[i];
- if (diff)
- {
- register int bit;
- old_live_regs[i] |= diff;
- for (bit = 0; bit < REGSET_ELT_BITS; bit++)
- if (diff & ((REGSET_ELT_TYPE) 1 << bit))
- sometimes_max
- = new_sometimes_live (regs_sometimes_live, i, bit,
- sometimes_max);
- }
- }
+ EXECUTE_IF_AND_COMPL_IN_REG_SET (bb_live_regs, old_live_regs, 0, i,
+ {
+ sometimes_max
+ = new_sometimes_live (regs_sometimes_live,
+ i, sometimes_max);
+ });
+ IOR_REG_SET (old_live_regs, bb_live_regs);
/* Count lengths of all regs we are worrying about now,
and handle registers no longer live. */
@@ -3848,20 +3338,18 @@ schedule_block (b, file)
for (i = 0; i < sometimes_max; i++)
{
register struct sometimes *p = &regs_sometimes_live[i];
- int regno = p->offset*REGSET_ELT_BITS + p->bit;
+ int regno = p->regno;
p->live_length += 1;
- if ((bb_live_regs[p->offset]
- & ((REGSET_ELT_TYPE) 1 << p->bit)) == 0)
+ if (!REGNO_REG_SET_P (bb_live_regs, p->regno))
{
/* This is the end of one of this register's lifetime
segments. Save the lifetime info collected so far,
and clear its bit in the old_live_regs entry. */
sched_reg_live_length[regno] += p->live_length;
sched_reg_n_calls_crossed[regno] += p->calls_crossed;
- old_live_regs[p->offset]
- &= ~((REGSET_ELT_TYPE) 1 << p->bit);
+ CLEAR_REGNO_REG_SET (old_live_regs, p->regno);
/* Delete the reg_sometimes_live entry for this reg by
copying the last entry over top of it. */
@@ -3888,10 +3376,6 @@ schedule_block (b, file)
sched_n_insns += 1;
NEXT_INSN (insn) = last;
PREV_INSN (last) = insn;
- last = insn;
-
- /* Check to see if we need to re-emit any notes here. */
- last = reemit_notes (insn, last);
/* Everything that precedes INSN now either becomes "ready", if
it can execute immediately before INSN, or "pending", if
@@ -3918,22 +3402,42 @@ schedule_block (b, file)
/* Now handle each group insn like the main insn was handled
above. */
- while (SCHED_GROUP_P (insn))
+ link = insn;
+ while (SCHED_GROUP_P (link))
{
- insn = PREV_INSN (insn);
+ link = PREV_INSN (link);
sched_n_insns += 1;
- NEXT_INSN (insn) = last;
- PREV_INSN (last) = insn;
- last = insn;
-
- last = reemit_notes (insn, last);
/* ??? Why don't we set LAUNCH_PRIORITY here? */
- new_ready = schedule_insn (insn, ready, new_ready, clock);
- INSN_PRIORITY (insn) = DONE_PRIORITY;
+ new_ready = schedule_insn (link, ready, new_ready, clock);
+ INSN_PRIORITY (link) = DONE_PRIORITY;
}
}
+
+ /* Put back NOTE_INSN_SETJMP,
+ NOTE_INSN_{LOOP,EHREGION}_{BEGIN,END} notes. */
+
+ /* To prime the loop. We need to handle INSN and all the insns in the
+ sched group. */
+ last = NEXT_INSN (insn);
+ do
+ {
+ insn = PREV_INSN (last);
+
+ /* Maintain a valid chain so emit_note_before works.
+ This is necessary because PREV_INSN (insn) isn't valid
+ (if ! SCHED_GROUP_P) and if it points to an insn already
+ scheduled, a circularity will result. */
+ if (! SCHED_GROUP_P (insn))
+ {
+ NEXT_INSN (prev_head) = insn;
+ PREV_INSN (insn) = prev_head;
+ }
+
+ last = reemit_notes (insn, insn);
+ }
+ while (SCHED_GROUP_P (insn));
}
if (q_size != 0)
abort ();
@@ -3944,7 +3448,7 @@ schedule_block (b, file)
/* HEAD is now the first insn in the chain of insns that
been scheduled by the loop above.
TAIL is the last of those insns. */
- head = insn;
+ head = last;
/* NOTE_LIST is the end of a chain of notes previously found
among the insns. Insert them at the beginning of the insns. */
@@ -4017,7 +3521,7 @@ schedule_block (b, file)
prev = PREV_INSN (insn);
if (LINE_NOTE (note))
{
- /* Re-use the original line-number note. */
+ /* Re-use the original line-number note. */
LINE_NOTE (note) = 0;
PREV_INSN (note) = prev;
NEXT_INSN (prev) = note;
@@ -4029,6 +3533,7 @@ schedule_block (b, file)
notes++;
new = emit_note_after (NOTE_LINE_NUMBER (note), prev);
NOTE_SOURCE_FILE (new) = NOTE_SOURCE_FILE (note);
+ RTX_INTEGRATED_P (new) = RTX_INTEGRATED_P (note);
}
}
if (file && notes)
@@ -4044,6 +3549,10 @@ schedule_block (b, file)
/* Yow! We're done! */
free_pending_lists ();
+ret:
+ FREE_REG_SET (reg_pending_sets);
+ FREE_REG_SET (old_live_regs);
+
return;
}
@@ -4068,12 +3577,12 @@ regno_use_in (regno, x)
{
if (fmt[i] == 'e')
{
- if (tem = regno_use_in (regno, XEXP (x, i)))
+ if ((tem = regno_use_in (regno, XEXP (x, i))))
return tem;
}
else if (fmt[i] == 'E')
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- if (tem = regno_use_in (regno , XVECEXP (x, i, j)))
+ if ((tem = regno_use_in (regno , XVECEXP (x, i, j))))
return tem;
}
@@ -4150,6 +3659,13 @@ new_insn_dead_notes (pat, insn, last, orig_insn)
if (GET_CODE (dest) == REG)
{
+ /* If the original insn already used this register, we may not add new
+ notes for it. One example for a split that needs this test is
+ when a multi-word memory access with register-indirect addressing
+ is split into multiple memory accesses with auto-increment and
+ one adjusting add instruction for the address register. */
+ if (reg_referenced_p (dest, PATTERN (orig_insn)))
+ return;
for (tem = last; tem != insn; tem = PREV_INSN (tem))
{
if (GET_RTX_CLASS (GET_CODE (tem)) == 'i'
@@ -4256,10 +3772,10 @@ update_n_sets (x, inc)
int endregno = regno + HARD_REGNO_NREGS (regno, GET_MODE (dest));
for (i = regno; i < endregno; i++)
- reg_n_sets[i] += inc;
+ REG_N_SETS (i) += inc;
}
else
- reg_n_sets[regno] += inc;
+ REG_N_SETS (regno) += inc;
}
}
@@ -4321,6 +3837,7 @@ update_flow_info (notes, first, last, orig_insn)
/* ??? This won't handle multiple word registers correctly,
but should be good enough for now. */
if (REG_NOTE_KIND (note) == REG_UNUSED
+ && GET_CODE (XEXP (note, 0)) != SCRATCH
&& ! dead_or_set_p (insn, XEXP (note, 0)))
PUT_REG_NOTE_KIND (note, REG_DEAD);
@@ -4335,6 +3852,15 @@ update_flow_info (notes, first, last, orig_insn)
pattern, so we can safely ignore it. */
if (insn == first)
{
+ /* After reload, REG_DEAD notes come sometimes an
+ instruction after the register actually dies. */
+ if (reload_completed && REG_NOTE_KIND (note) == REG_DEAD)
+ {
+ XEXP (note, 1) = REG_NOTES (insn);
+ REG_NOTES (insn) = note;
+ break;
+ }
+
if (REG_NOTE_KIND (note) != REG_UNUSED)
abort ();
@@ -4344,6 +3870,14 @@ update_flow_info (notes, first, last, orig_insn)
break;
case REG_WAS_0:
+ /* If the insn that set the register to 0 was deleted, this
+ note cannot be relied on any longer. The destination might
+ even have been moved to memory.
+ This was observed for SH4 with execute/920501-6.c compilation,
+ -O2 -fomit-frame-pointer -finline-functions . */
+ if (GET_CODE (XEXP (note, 0)) == NOTE
+ || INSN_DELETED_P (XEXP (note, 0)))
+ break;
/* This note applies to the dest of the original insn. Find the
first new insn that now has the same dest, and move the note
there. */
@@ -4363,6 +3897,15 @@ update_flow_info (notes, first, last, orig_insn)
uses it. */
break;
}
+ /* If this note refers to a multiple word hard
+ register, it may have been split into several smaller
+ hard register references. We could split the notes,
+ but simply dropping them is good enough. */
+ if (GET_CODE (orig_dest) == REG
+ && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_NREGS (REGNO (orig_dest),
+ GET_MODE (orig_dest)) > 1)
+ break;
/* It must be set somewhere, fail if we couldn't find where it
was set. */
if (insn == last)
@@ -4399,7 +3942,22 @@ update_flow_info (notes, first, last, orig_insn)
/* The original dest must still be set someplace. Abort if we
couldn't find it. */
if (insn == first)
- abort ();
+ {
+ /* However, if this note refers to a multiple word hard
+ register, it may have been split into several smaller
+ hard register references. We could split the notes,
+ but simply dropping them is good enough. */
+ if (GET_CODE (orig_dest) == REG
+ && REGNO (orig_dest) < FIRST_PSEUDO_REGISTER
+ && HARD_REGNO_NREGS (REGNO (orig_dest),
+ GET_MODE (orig_dest)) > 1)
+ break;
+ /* Likewise for multi-word memory references. */
+ if (GET_CODE (orig_dest) == MEM
+ && SIZE_FOR_MODE (orig_dest) > MOVE_MAX)
+ break;
+ abort ();
+ }
}
break;
@@ -4415,6 +3973,12 @@ update_flow_info (notes, first, last, orig_insn)
XEXP (note, 0) = first;
break;
+ case REG_EXEC_COUNT:
+ /* Move a REG_EXEC_COUNT note to the first insn created. */
+ XEXP (note, 1) = REG_NOTES (first);
+ REG_NOTES (first) = note;
+ break;
+
case REG_RETVAL:
/* Move a REG_RETVAL note to the last insn created, and update
the corresponding REG_LIBCALL note. */
@@ -4428,6 +3992,7 @@ update_flow_info (notes, first, last, orig_insn)
break;
case REG_NONNEG:
+ case REG_BR_PROB:
/* This should be moved to whichever instruction is a JUMP_INSN. */
for (insn = last; ; insn = PREV_INSN (insn))
@@ -4446,6 +4011,9 @@ update_flow_info (notes, first, last, orig_insn)
break;
case REG_INC:
+ /* reload sometimes leaves obsolete REG_INC notes around. */
+ if (reload_completed)
+ break;
/* This should be moved to whichever instruction now has the
increment operation. */
abort ();
@@ -4455,8 +4023,9 @@ update_flow_info (notes, first, last, orig_insn)
for (insn = first; insn != NEXT_INSN (last); insn = NEXT_INSN (insn))
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& reg_mentioned_p (XEXP (note, 0), PATTERN (insn)))
- REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_LABEL,
- XEXP (note, 0), REG_NOTES (insn));
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_LABEL,
+ XEXP (note, 0),
+ REG_NOTES (insn));
break;
case REG_CC_SETTER:
@@ -4496,10 +4065,7 @@ update_flow_info (notes, first, last, orig_insn)
/* If any insn, except the last, uses the register set by the last insn,
then we need a new REG_DEAD note on that insn. In this case, there
would not have been a REG_DEAD note for this register in the original
- insn because it was used and set within one insn.
-
- There is no new REG_DEAD note needed if the last insn uses the register
- that it is setting. */
+ insn because it was used and set within one insn. */
set = single_set (last);
if (set)
@@ -4512,9 +4078,34 @@ update_flow_info (notes, first, last, orig_insn)
dest = XEXP (dest, 0);
if (GET_CODE (dest) == REG
- && ! reg_overlap_mentioned_p (dest, SET_SRC (set)))
+ /* Global registers are always live, so the code below does not
+ apply to them. */
+ && (REGNO (dest) >= FIRST_PSEUDO_REGISTER
+ || ! global_regs[REGNO (dest)]))
{
- for (insn = PREV_INSN (last); ; insn = PREV_INSN (insn))
+ rtx stop_insn = PREV_INSN (first);
+
+ /* If the last insn uses the register that it is setting, then
+ we don't want to put a REG_DEAD note there. Search backwards
+ to find the first insn that sets but does not use DEST. */
+
+ insn = last;
+ if (reg_overlap_mentioned_p (dest, SET_SRC (set)))
+ {
+ for (insn = PREV_INSN (insn); insn != first;
+ insn = PREV_INSN (insn))
+ {
+ if ((set = single_set (insn))
+ && reg_mentioned_p (dest, SET_DEST (set))
+ && ! reg_overlap_mentioned_p (dest, SET_SRC (set)))
+ break;
+ }
+ }
+
+ /* Now find the first insn that uses but does not set DEST. */
+
+ for (insn = PREV_INSN (insn); insn != stop_insn;
+ insn = PREV_INSN (insn))
{
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
&& reg_mentioned_p (dest, PATTERN (insn))
@@ -4540,8 +4131,6 @@ update_flow_info (notes, first, last, orig_insn)
break;
}
}
- if (insn == first)
- break;
}
}
}
@@ -4565,21 +4154,29 @@ update_flow_info (notes, first, last, orig_insn)
for (insn = first; ; insn = NEXT_INSN (insn))
{
- set = single_set (insn);
- if (set)
+ rtx pat = PATTERN (insn);
+ int i = GET_CODE (pat) == PARALLEL ? XVECLEN (pat, 0) : 0;
+ set = pat;
+ for (;;)
{
- if (GET_CODE (SET_DEST (set)) == REG
- && REGNO (SET_DEST (set)) == REGNO (orig_dest))
+ if (GET_CODE (set) == SET)
{
- found_orig_dest = 1;
- break;
- }
- else if (GET_CODE (SET_DEST (set)) == SUBREG
- && SUBREG_REG (SET_DEST (set)) == orig_dest)
- {
- found_split_dest = 1;
- break;
+ if (GET_CODE (SET_DEST (set)) == REG
+ && REGNO (SET_DEST (set)) == REGNO (orig_dest))
+ {
+ found_orig_dest = 1;
+ break;
+ }
+ else if (GET_CODE (SET_DEST (set)) == SUBREG
+ && SUBREG_REG (SET_DEST (set)) == orig_dest)
+ {
+ found_split_dest = 1;
+ break;
+ }
}
+ if (--i < 0)
+ break;
+ set = XVECEXP (pat, 0, i);
}
if (insn == last)
@@ -4677,8 +4274,8 @@ schedule_insns (dump_file)
/* Create an insn here so that we can hang dependencies off of it later. */
sched_before_next_call
- = gen_rtx (INSN, VOIDmode, 0, NULL_RTX, NULL_RTX,
- NULL_RTX, 0, NULL_RTX, 0);
+ = gen_rtx_INSN (VOIDmode, 0, NULL_RTX, NULL_RTX,
+ NULL_RTX, 0, NULL_RTX, NULL_RTX);
/* Initialize the unused_*_lists. We can't use the ones left over from
the previous function, because gcc has freed that memory. We can use
@@ -4696,44 +4293,42 @@ schedule_insns (dump_file)
remember how far we can cut back the stack on exit. */
/* Allocate data for this pass. See comments, above,
- for what these vectors do. */
- insn_luid = (int *) alloca (max_uid * sizeof (int));
- insn_priority = (int *) alloca (max_uid * sizeof (int));
- insn_tick = (int *) alloca (max_uid * sizeof (int));
- insn_costs = (short *) alloca (max_uid * sizeof (short));
- insn_units = (short *) alloca (max_uid * sizeof (short));
- insn_blockage = (unsigned int *) alloca (max_uid * sizeof (unsigned int));
- insn_ref_count = (int *) alloca (max_uid * sizeof (int));
+ for what these vectors do.
+
+ We use xmalloc instead of alloca, because max_uid can be very large
+ when there is a lot of function inlining. If we used alloca, we could
+ exceed stack limits on some hosts for some inputs. */
+ insn_luid = (int *) xmalloc (max_uid * sizeof (int));
+ insn_priority = (int *) xmalloc (max_uid * sizeof (int));
+ insn_tick = (int *) xmalloc (max_uid * sizeof (int));
+ insn_costs = (short *) xmalloc (max_uid * sizeof (short));
+ insn_units = (short *) xmalloc (max_uid * sizeof (short));
+ insn_blockage = (unsigned int *) xmalloc (max_uid * sizeof (unsigned int));
+ insn_ref_count = (int *) xmalloc (max_uid * sizeof (int));
if (reload_completed == 0)
{
- sched_reg_n_deaths = (short *) alloca (max_regno * sizeof (short));
sched_reg_n_calls_crossed = (int *) alloca (max_regno * sizeof (int));
sched_reg_live_length = (int *) alloca (max_regno * sizeof (int));
- bb_dead_regs = (regset) alloca (regset_bytes);
- bb_live_regs = (regset) alloca (regset_bytes);
+ bb_dead_regs = ALLOCA_REG_SET ();
+ bb_live_regs = ALLOCA_REG_SET ();
bzero ((char *) sched_reg_n_calls_crossed, max_regno * sizeof (int));
bzero ((char *) sched_reg_live_length, max_regno * sizeof (int));
- bcopy ((char *) reg_n_deaths, (char *) sched_reg_n_deaths,
- max_regno * sizeof (short));
- init_alias_analysis ();
}
else
{
- sched_reg_n_deaths = 0;
sched_reg_n_calls_crossed = 0;
sched_reg_live_length = 0;
bb_dead_regs = 0;
bb_live_regs = 0;
- if (! flag_schedule_insns)
- init_alias_analysis ();
}
+ init_alias_analysis ();
if (write_symbols != NO_DEBUG)
{
rtx line;
- line_note = (rtx *) alloca (max_uid * sizeof (rtx));
+ line_note = (rtx *) xmalloc (max_uid * sizeof (rtx));
bzero ((char *) line_note, max_uid * sizeof (rtx));
line_note_head = (rtx *) alloca (n_basic_blocks * sizeof (rtx));
bzero ((char *) line_note_head, n_basic_blocks * sizeof (rtx));
@@ -4764,6 +4359,8 @@ schedule_insns (dump_file)
/* ??? Add a NOTE after the last insn of the last basic block. It is not
known why this is done. */
+ /* ??? Perhaps it's done to ensure NEXT_TAIL in schedule_block is a
+ valid insn. */
insn = basic_block_end[n_basic_blocks-1];
if (NEXT_INSN (insn) == 0
@@ -4822,7 +4419,10 @@ schedule_insns (dump_file)
/* Split insns here to get max fine-grain parallelism. */
prev = PREV_INSN (insn);
- if (reload_completed == 0)
+ /* It is probably not worthwhile to try to split again in the
+ second pass. However, if flag_schedule_insns is not set,
+ the first and only (if any) scheduling pass is after reload. */
+ if (reload_completed == 0 || ! flag_schedule_insns)
{
rtx last, first = PREV_INSN (insn);
rtx notes = REG_NOTES (insn);
@@ -4916,35 +4516,35 @@ schedule_insns (dump_file)
{
if (dump_file)
{
- if (reg_live_length[regno] > sched_reg_live_length[regno])
+ if (REG_LIVE_LENGTH (regno) > sched_reg_live_length[regno])
fprintf (dump_file,
";; register %d life shortened from %d to %d\n",
- regno, reg_live_length[regno],
+ regno, REG_LIVE_LENGTH (regno),
sched_reg_live_length[regno]);
/* Negative values are special; don't overwrite the current
reg_live_length value if it is negative. */
- else if (reg_live_length[regno] < sched_reg_live_length[regno]
- && reg_live_length[regno] >= 0)
+ else if (REG_LIVE_LENGTH (regno) < sched_reg_live_length[regno]
+ && REG_LIVE_LENGTH (regno) >= 0)
fprintf (dump_file,
";; register %d life extended from %d to %d\n",
- regno, reg_live_length[regno],
+ regno, REG_LIVE_LENGTH (regno),
sched_reg_live_length[regno]);
- if (! reg_n_calls_crossed[regno]
+ if (! REG_N_CALLS_CROSSED (regno)
&& sched_reg_n_calls_crossed[regno])
fprintf (dump_file,
";; register %d now crosses calls\n", regno);
- else if (reg_n_calls_crossed[regno]
+ else if (REG_N_CALLS_CROSSED (regno)
&& ! sched_reg_n_calls_crossed[regno]
- && reg_basic_block[regno] != REG_BLOCK_GLOBAL)
+ && REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL)
fprintf (dump_file,
";; register %d no longer crosses calls\n", regno);
}
/* Negative values are special; don't overwrite the current
reg_live_length value if it is negative. */
- if (reg_live_length[regno] >= 0)
- reg_live_length[regno] = sched_reg_live_length[regno];
+ if (REG_LIVE_LENGTH (regno) >= 0)
+ REG_LIVE_LENGTH (regno) = sched_reg_live_length[regno];
/* We can't change the value of reg_n_calls_crossed to zero for
pseudos which are live in more than one block.
@@ -4960,9 +4560,27 @@ schedule_insns (dump_file)
Alternatively, we could try to correctly update basic block live
at start here in sched, but that seems complicated. */
if (sched_reg_n_calls_crossed[regno]
- || reg_basic_block[regno] != REG_BLOCK_GLOBAL)
- reg_n_calls_crossed[regno] = sched_reg_n_calls_crossed[regno];
+ || REG_BASIC_BLOCK (regno) != REG_BLOCK_GLOBAL)
+ REG_N_CALLS_CROSSED (regno) = sched_reg_n_calls_crossed[regno];
}
}
+
+ free (insn_luid);
+ free (insn_priority);
+ free (insn_tick);
+ free (insn_costs);
+ free (insn_units);
+ free (insn_blockage);
+ free (insn_ref_count);
+
+ if (write_symbols != NO_DEBUG)
+ free (line_note);
+
+ if (reload_completed == 0)
+ {
+ FREE_REG_SET (bb_dead_regs);
+ FREE_REG_SET (bb_live_regs);
+ }
+
}
#endif /* INSN_SCHEDULING */
diff --git a/contrib/gcc/sdbout.c b/contrib/gcc/sdbout.c
index 8fdb72c..62559a9 100644
--- a/contrib/gcc/sdbout.c
+++ b/contrib/gcc/sdbout.c
@@ -1,5 +1,5 @@
/* Output sdb-format symbol table information from GNU compiler.
- Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1988, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -44,25 +44,30 @@ AT&T C compiler. From the example below I would conclude the following:
#ifdef SDB_DEBUGGING_INFO
+#include "system.h"
#include "tree.h"
#include "rtl.h"
-#include <stdio.h>
#include "regs.h"
+#include "defaults.h"
#include "flags.h"
#include "insn-config.h"
#include "reload.h"
+#include "output.h"
+#include "toplev.h"
-/* Mips systems use the SDB functions to dump out symbols, but
- do not supply usable syms.h include files. */
-#if defined(USG) && !defined(MIPS) && !defined (hpux) && !defined(_WIN32) && !defined(__linux__)
+/* Mips systems use the SDB functions to dump out symbols, but do not
+ supply usable syms.h include files. Which syms.h file to use is a
+ target parameter so don't use the native one if we're cross compiling. */
+
+#if defined(USG) && !defined(MIPS) && !defined (hpux) && !defined(_WIN32) && !defined(__linux__) && !defined(CROSS_COMPILE)
#include <syms.h>
/* Use T_INT if we don't have T_VOID. */
#ifndef T_VOID
#define T_VOID T_INT
#endif
-#else /* not USG, or MIPS */
+#else
#include "gsyms.h"
-#endif /* not USG, or MIPS */
+#endif
/* #include <storclass.h> used to be this instead of syms.h. */
@@ -97,16 +102,22 @@ extern FILE *asm_out_file;
extern tree current_function_decl;
-void sdbout_init ();
-void sdbout_symbol ();
-void sdbout_types();
-
-static void sdbout_typedefs ();
-static void sdbout_syms ();
-static void sdbout_one_type ();
-static void sdbout_queue_anonymous_type ();
-static void sdbout_dequeue_anonymous_types ();
-static int plain_type_1 ();
+#include "sdbout.h"
+
+static char *gen_fake_label PROTO((void));
+static int plain_type PROTO((tree));
+static int template_name_p PROTO((tree));
+static void sdbout_record_type_name PROTO((tree));
+static int plain_type_1 PROTO((tree, int));
+static void sdbout_block PROTO((tree));
+static void sdbout_syms PROTO((tree));
+static void sdbout_queue_anonymous_type PROTO((tree));
+static void sdbout_dequeue_anonymous_types PROTO((void));
+static void sdbout_type PROTO((tree));
+static void sdbout_field_types PROTO((tree));
+static void sdbout_one_type PROTO((tree));
+static void sdbout_parms PROTO((tree));
+static void sdbout_reg_parms PROTO((tree));
/* Define the default sizes for various types. */
@@ -162,7 +173,13 @@ static int plain_type_1 ();
#endif
#ifndef PUT_SDB_INT_VAL
-#define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\t.val\t%d%s", (a), SDB_DELIM)
+#define PUT_SDB_INT_VAL(a) \
+ do { \
+ fputs ("\t.val\t", asm_out_file); \
+ fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)(a)); \
+ fprintf (asm_out_file, "%s", SDB_DELIM); \
+ } while (0)
+
#endif
#ifndef PUT_SDB_VAL
@@ -192,7 +209,12 @@ do { fprintf (asm_out_file, "\t.def\t"); \
#endif
#ifndef PUT_SDB_SIZE
-#define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\t.size\t%d%s", a, SDB_DELIM)
+#define PUT_SDB_SIZE(a) \
+ do { \
+ fputs ("\t.size\t", asm_out_file); \
+ fprintf (asm_out_file, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT)(a)); \
+ fprintf (asm_out_file, "%s", SDB_DELIM); \
+ } while(0)
#endif
#ifndef PUT_SDB_START_DIM
@@ -277,6 +299,38 @@ do { fprintf (asm_out_file, "\t.def\t"); \
/* Ensure we don't output a negative line number. */
#define MAKE_LINE_SAFE(line) \
if (line <= sdb_begin_function_line) line = sdb_begin_function_line + 1
+
+/* Perform linker optimization of merging header file definitions together
+ for targets with MIPS_DEBUGGING_INFO defined. This won't work without a
+ post 960826 version of GAS. Nothing breaks with earlier versions of GAS,
+ the optimization just won't be done. The native assembler already has the
+ necessary support. */
+
+#ifdef MIPS_DEBUGGING_INFO
+
+#ifndef PUT_SDB_SRC_FILE
+#define PUT_SDB_SRC_FILE(FILENAME) \
+output_file_directive (asm_out_file, (FILENAME))
+#endif
+
+/* ECOFF linkers have an optimization that does the same kind of thing as
+ N_BINCL/E_INCL in stabs: eliminate duplicate debug information in the
+ executable. To achieve this, GCC must output a .file for each file
+ name change. */
+
+/* This is a stack of input files. */
+
+struct sdb_file
+{
+ struct sdb_file *next;
+ char *name;
+};
+
+/* This is the top of the stack. */
+
+static struct sdb_file *current_file;
+
+#endif /* MIPS_DEBUGGING_INFO */
/* Set up for SDB output at the start of compilation. */
@@ -286,6 +340,12 @@ sdbout_init (asm_file, input_file_name, syms)
char *input_file_name;
tree syms;
{
+#ifdef MIPS_DEBUGGING_INFO
+ current_file = (struct sdb_file *) xmalloc (sizeof *current_file);
+ current_file->next = NULL;
+ current_file->name = input_file_name;
+#endif
+
#ifdef RMS_QUICK_HACK_1
tree t;
for (t = syms; t; t = TREE_CHAIN (t))
@@ -293,13 +353,6 @@ sdbout_init (asm_file, input_file_name, syms)
&& !strcmp (IDENTIFIER_POINTER (DECL_NAME (t)), "__vtbl_ptr_type"))
sdbout_symbol (t, 0);
#endif
-
-#if 0 /* Nothing need be output for the predefined types. */
- /* Get all permanent types that have typedef names,
- and output them all, except for those already output. */
-
- sdbout_typedefs (syms);
-#endif
}
#if 0
@@ -489,10 +542,14 @@ plain_type_1 (type, level)
{
char *name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+ if (!strcmp (name, "char"))
+ return T_CHAR;
if (!strcmp (name, "unsigned char"))
return T_UCHAR;
if (!strcmp (name, "signed char"))
return T_CHAR;
+ if (!strcmp (name, "int"))
+ return T_INT;
if (!strcmp (name, "unsigned int"))
return T_UINT;
if (!strcmp (name, "short int"))
@@ -505,12 +562,12 @@ plain_type_1 (type, level)
return T_ULONG;
}
+ if (size == INT_TYPE_SIZE)
+ return (TREE_UNSIGNED (type) ? T_UINT : T_INT);
if (size == CHAR_TYPE_SIZE)
return (TREE_UNSIGNED (type) ? T_UCHAR : T_CHAR);
if (size == SHORT_TYPE_SIZE)
return (TREE_UNSIGNED (type) ? T_USHORT : T_SHORT);
- if (size == INT_TYPE_SIZE)
- return (TREE_UNSIGNED (type) ? T_UINT : T_INT);
if (size == LONG_TYPE_SIZE)
return (TREE_UNSIGNED (type) ? T_ULONG : T_LONG);
if (size == LONG_LONG_TYPE_SIZE) /* better than nothing */
@@ -520,11 +577,18 @@ plain_type_1 (type, level)
case REAL_TYPE:
{
- int size = int_size_in_bytes (type) * BITS_PER_UNIT;
- if (size == FLOAT_TYPE_SIZE)
+ int precision = TYPE_PRECISION (type);
+ if (precision == FLOAT_TYPE_SIZE)
return T_FLOAT;
- if (size == DOUBLE_TYPE_SIZE)
+ if (precision == DOUBLE_TYPE_SIZE)
return T_DOUBLE;
+#ifdef EXTENDED_SDB_BASIC_TYPES
+ if (precision == LONG_DOUBLE_TYPE_SIZE)
+ return T_LNGDBL;
+#else
+ if (precision == LONG_DOUBLE_TYPE_SIZE)
+ return T_DOUBLE; /* better than nothing */
+#endif
return 0;
}
@@ -538,7 +602,11 @@ plain_type_1 (type, level)
if (sdb_n_dims < SDB_MAX_DIM)
sdb_dims[sdb_n_dims++]
= (TYPE_DOMAIN (type)
- ? TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + 1
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (type))
+ && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
+ && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
+ ? (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
+ - TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) + 1)
: 0);
return PUSH_DERIVED_LEVEL (DT_ARY, m);
}
@@ -564,8 +632,8 @@ plain_type_1 (type, level)
only if the .def has already been finished.
At least on 386, the Unix assembler
cannot handle forward references to tags. */
- /* But the 88100, it requires them, sigh... */
- /* And the MIPS requires unknown refs as well... */
+ /* But the 88100, it requires them, sigh... */
+ /* And the MIPS requires unknown refs as well... */
tag = KNOWN_TYPE_TAG (type);
PUT_SDB_TAG (tag);
/* These 3 lines used to follow the close brace.
@@ -691,7 +759,10 @@ sdbout_symbol (decl, local)
context = decl_function_context (decl);
if (context == current_function_decl)
return;
- if (DECL_EXTERNAL (decl))
+ /* Check DECL_INITIAL to distinguish declarations from definitions.
+ Don't output debug info here for declarations; they will have
+ a DECL_INITIAL value of 0. */
+ if (! DECL_INITIAL (decl))
return;
if (GET_CODE (DECL_RTL (decl)) != MEM
|| GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
@@ -898,6 +969,9 @@ sdbout_symbol (decl, local)
return;
}
break;
+
+ default:
+ break;
}
PUT_SDB_TYPE (plain_type (type));
PUT_SDB_ENDEF;
@@ -936,7 +1010,7 @@ sdbout_toplevel_data (decl)
#ifdef SDB_ALLOW_FORWARD_REFERENCES
-/* Machinery to record and output anonymous types. */
+/* Machinery to record and output anonymous types. */
static tree anonymous_types;
@@ -1006,8 +1080,9 @@ sdbout_field_types (type)
tree type;
{
tree tail;
+
for (tail = TYPE_FIELDS (type); tail; tail = TREE_CHAIN (tail))
- if (TREE_CODE (TREE_TYPE (tail)) == POINTER_TYPE)
+ if (POINTER_TYPE_P (TREE_TYPE (tail)))
sdbout_one_type (TREE_TYPE (TREE_TYPE (tail)));
else
sdbout_one_type (TREE_TYPE (tail));
@@ -1113,6 +1188,9 @@ sdbout_one_type (type)
PUT_SDB_TYPE (T_ENUM);
member_scl = C_MOE;
break;
+
+ default:
+ break;
}
PUT_SDB_SIZE (size);
@@ -1205,6 +1283,9 @@ sdbout_one_type (type)
PUT_SDB_SIZE (size);
PUT_SDB_ENDEF;
break;
+
+ default:
+ break;
}
}
}
@@ -1236,8 +1317,8 @@ sdbout_parms (parms)
/* Perform any necessary register eliminations on the parameter's rtl,
so that the debugging output will be accurate. */
- DECL_INCOMING_RTL (parms) =
- eliminate_regs (DECL_INCOMING_RTL (parms), 0, NULL_RTX);
+ DECL_INCOMING_RTL (parms)
+ = eliminate_regs (DECL_INCOMING_RTL (parms), 0, NULL_RTX);
DECL_RTL (parms) = eliminate_regs (DECL_RTL (parms), 0, NULL_RTX);
if (PARM_PASSED_IN_MEMORY (parms))
@@ -1315,7 +1396,7 @@ sdbout_parms (parms)
PUT_SDB_DEF (name);
PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (best_rtl)));
PUT_SDB_SCL (C_REGPARM);
- PUT_SDB_TYPE (plain_type (TREE_TYPE (parms), 0));
+ PUT_SDB_TYPE (plain_type (TREE_TYPE (parms)));
PUT_SDB_ENDEF;
}
else if (GET_CODE (DECL_RTL (parms)) == MEM
@@ -1338,7 +1419,7 @@ sdbout_parms (parms)
PUT_SDB_INT_VAL (DEBUGGER_ARG_OFFSET (current_sym_value,
XEXP (DECL_RTL (parms), 0)));
PUT_SDB_SCL (C_ARG);
- PUT_SDB_TYPE (plain_type (TREE_TYPE (parms), 0));
+ PUT_SDB_TYPE (plain_type (TREE_TYPE (parms)));
PUT_SDB_ENDEF;
}
}
@@ -1376,7 +1457,7 @@ sdbout_reg_parms (parms)
PUT_SDB_DEF (name);
PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (DECL_RTL (parms))));
PUT_SDB_SCL (C_REG);
- PUT_SDB_TYPE (plain_type (TREE_TYPE (parms), 0));
+ PUT_SDB_TYPE (plain_type (TREE_TYPE (parms)));
PUT_SDB_ENDEF;
}
/* Report parms that live in memory but not where they were passed. */
@@ -1544,4 +1625,35 @@ sdbout_label (insn)
PUT_SDB_ENDEF;
}
+/* Change to reading from a new source file. */
+
+void
+sdbout_start_new_source_file (filename)
+ char *filename;
+{
+#ifdef MIPS_DEBUGGING_INFO
+ struct sdb_file *n = (struct sdb_file *) xmalloc (sizeof *n);
+
+ n->next = current_file;
+ n->name = filename;
+ current_file = n;
+ PUT_SDB_SRC_FILE (filename);
+#endif
+}
+
+/* Revert to reading a previous source file. */
+
+void
+sdbout_resume_previous_source_file ()
+{
+#ifdef MIPS_DEBUGGING_INFO
+ struct sdb_file *next;
+
+ next = current_file->next;
+ free (current_file);
+ current_file = next;
+ PUT_SDB_SRC_FILE (current_file->name);
+#endif
+}
+
#endif /* SDB_DEBUGGING_INFO */
diff --git a/contrib/gcc/sdbout.h b/contrib/gcc/sdbout.h
new file mode 100644
index 0000000..dcbd6c1
--- /dev/null
+++ b/contrib/gcc/sdbout.h
@@ -0,0 +1,39 @@
+/* sdbout.h - Various declarations for functions found in sdbout.c
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+extern void sdbout_init PROTO ((FILE *, char*, tree));
+
+extern void sdbout_begin_function PROTO ((int));
+extern void sdbout_end_function PROTO ((int));
+
+extern void sdbout_begin_block PROTO ((FILE *, int, int));
+extern void sdbout_end_block PROTO ((FILE *, int, int));
+
+extern void sdbout_label PROTO ((rtx));
+extern void sdbout_symbol PROTO ((tree, int));
+extern void sdbout_toplevel_data PROTO ((tree));
+extern void sdbout_types PROTO ((tree));
+
+extern void sdbout_end_epilogue PROTO ((void));
+
+extern void sdbout_start_new_source_file PROTO ((char *));
+extern void sdbout_resume_previous_source_file PROTO ((void));
+extern void sdbout_mark_begin_function PROTO ((void));
+
diff --git a/contrib/gcc/stab.def b/contrib/gcc/stab.def
index dd4fbf0..48ea231 100644
--- a/contrib/gcc/stab.def
+++ b/contrib/gcc/stab.def
@@ -1,19 +1,21 @@
/* Table of DBX symbol codes for the GNU system.
- Copyright (C) 1988 Free Software Foundation, Inc.
+ Copyright (C) 1988, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
- 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 1, or (at your option)
- any later version.
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library 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,
+ The GNU C Library 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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
/* This contains contribution from Cygnus Support. */
diff --git a/contrib/gcc/stmt.c b/contrib/gcc/stmt.c
index 7ce2dd9..8d11a75 100644
--- a/contrib/gcc/stmt.c
+++ b/contrib/gcc/stmt.c
@@ -1,5 +1,5 @@
/* Expands front end tree to back end RTL for GNU C-Compiler
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -34,13 +34,12 @@ Boston, MA 02111-1307, USA. */
after parsing the then-clause. */
#include "config.h"
-
-#include <stdio.h>
-#include <ctype.h>
+#include "system.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
+#include "except.h"
#include "function.h"
#include "insn-flags.h"
#include "insn-config.h"
@@ -51,17 +50,18 @@ Boston, MA 02111-1307, USA. */
#include "loop.h"
#include "recog.h"
#include "machmode.h"
-
-#include "bytecode.h"
-#include "bc-typecd.h"
-#include "bc-opcode.h"
-#include "bc-optab.h"
-#include "bc-emit.h"
+#include "toplev.h"
+#include "output.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
struct obstack stmt_obstack;
+/* Assume that case vectors are not pc-relative. */
+#ifndef CASE_VECTOR_PC_RELATIVE
+#define CASE_VECTOR_PC_RELATIVE 0
+#endif
+
/* Filename and line number of last line-number note,
whether we actually emitted it or not. */
char *emit_filename;
@@ -106,10 +106,6 @@ extern rtx cleanup_label;
extern rtx return_label;
-/* List (chain of EXPR_LISTs) of pseudo-regs of SAVE_EXPRs.
- So we can mark them all live at the end of the function, if nonopt. */
-extern rtx save_expr_regs;
-
/* Offset to end of allocated area of stack frame.
If stack grows down, this is the address of the last stack slot allocated.
If stack grows up, this is the address for the next slot. */
@@ -131,15 +127,6 @@ extern rtx arg_pointer_save_area;
/* Chain of all RTL_EXPRs that have insns in them. */
extern tree rtl_expr_chain;
-
-#if 0 /* Turned off because 0 seems to work just as well. */
-/* Cleanup lists are required for binding levels regardless of whether
- that binding level has cleanups or not. This node serves as the
- cleanup list whenever an empty list is required. */
-static tree empty_cleanup_list;
-#endif
-
-extern void (*interim_eh_hook) PROTO((tree));
/* Functions and data structures for expanding case statements. */
@@ -147,8 +134,9 @@ extern void (*interim_eh_hook) PROTO((tree));
statements. We handle "range" labels; for a single-value label
as in C, the high and low limits are the same.
- A chain of case nodes is initially maintained via the RIGHT fields
- in the nodes. Nodes with higher case values are later in the list.
+ An AVL tree of case nodes is initially created, and later transformed
+ to a list linked via the RIGHT fields in the nodes. Nodes with
+ higher case values are later in the list.
Switch statements can be output in one of two forms. A branch table
is used if there are more than a few labels and the labels are dense
@@ -172,6 +160,7 @@ struct case_node
tree low; /* Lowest index value for this label */
tree high; /* Highest index value for this label */
tree code_label; /* Label to jump to when node matches */
+ int balance;
};
typedef struct case_node case_node;
@@ -224,7 +213,7 @@ struct nesting
and no `else' has been seen yet. */
rtx endif_label;
/* Label for the end of this alternative.
- This may be the end of the if or the next else/elseif. */
+ This may be the end of the if or the next else/elseif. */
rtx next_label;
} cond;
/* For loops. */
@@ -247,8 +236,7 @@ struct nesting
/* Sequence number of this binding contour within the function,
in order of entry. */
int block_start_count;
- /* Nonzero => value to restore stack to on exit. Complemented by
- bc_stack_level (see below) when generating bytecodes. */
+ /* Nonzero => value to restore stack to on exit. */
rtx stack_level;
/* The NOTE that starts this contour.
Used by expand_goto to check whether the destination
@@ -265,7 +253,7 @@ struct nesting
as they were at the locus where this block appears.
There is an element for each containing block,
ordered innermost containing block first.
- The tail of this list can be 0 (was empty_cleanup_list),
+ The tail of this list can be 0,
if all remaining elements would be empty lists.
The element's TREE_VALUE is the cleanup-list of that block,
which may be null. */
@@ -275,8 +263,28 @@ struct nesting
struct label_chain *label_chain;
/* Number of function calls seen, as of start of this block. */
int function_call_count;
- /* Bytecode specific: stack level to restore stack to on exit. */
- int bc_stack_level;
+ /* Nonzero if this is associated with a EH region. */
+ int exception_region;
+ /* The saved target_temp_slot_level from our outer block.
+ We may reset target_temp_slot_level to be the level of
+ this block, if that is done, target_temp_slot_level
+ reverts to the saved target_temp_slot_level at the very
+ end of the block. */
+ int target_temp_slot_level;
+ /* True if we are currently emitting insns in an area of
+ output code that is controlled by a conditional
+ expression. This is used by the cleanup handling code to
+ generate conditional cleanup actions. */
+ int conditional_code;
+ /* A place to move the start of the exception region for any
+ of the conditional cleanups, must be at the end or after
+ the start of the last unconditional cleanup, and before any
+ conditional branch points. */
+ rtx last_unconditional_cleanup;
+ /* When in a conditional context, this is the specific
+ cleanup list associated with last_unconditional_cleanup,
+ where we place the conditionalized cleanups. */
+ tree *cleanup_ptr;
} block;
/* For switch (C) or case (Pascal) statements,
and also for dummies (see `expand_start_case_dummy'). */
@@ -285,14 +293,9 @@ struct nesting
/* The insn after which the case dispatch should finally
be emitted. Zero for a dummy. */
rtx start;
- /* For bytecodes, the case table is in-lined right in the code.
- A label is needed for skipping over this block. It is only
- used when generating bytecodes. */
- rtx skip_label;
- /* A list of case labels, kept in ascending order by value
- as the list is built.
- During expand_end_case, this list may be rearranged into a
- nearly balanced binary tree. */
+ /* A list of case labels; it is first built as an AVL tree.
+ During expand_end_case, this is converted to a list, and may be
+ rearranged into a nearly balanced binary tree. */
struct case_node *case_list;
/* Label to jump to if no case matches. */
tree default_label;
@@ -304,8 +307,10 @@ struct nesting
int num_ranges;
/* Name of this kind of statement, for warnings. */
char *printname;
- /* Nonzero if a case label has been seen in this case stmt. */
- char seenlabel;
+ /* Used to save no_line_numbers till we see the first case label.
+ We set this to -1 when we see the first case label in this
+ case statement. */
+ int line_number_status;
} case_stmt;
} data;
};
@@ -395,27 +400,12 @@ struct goto_fixup
rtx stack_level;
/* List of lists of cleanup expressions to be run by this goto.
There is one element for each block that this goto is within.
- The tail of this list can be 0 (was empty_cleanup_list),
+ The tail of this list can be 0,
if all remaining elements would be empty.
The TREE_VALUE contains the cleanup list of that block as of the
time this goto was seen.
The TREE_ADDRESSABLE flag is 1 for a block that has been exited. */
tree cleanup_list_list;
-
- /* Bytecode specific members follow */
-
- /* The label that this jump is jumping to, or 0 for break, continue
- or return. */
- struct bc_label *bc_target;
-
- /* The label we use for the fixup patch */
- struct bc_label *label;
-
- /* True (non-0) if fixup has been handled */
- int bc_handled:1;
-
- /* Like stack_level above, except refers to the interpreter stack */
- int bc_stack_level;
};
static struct goto_fixup *goto_fixup_chain;
@@ -429,33 +419,21 @@ struct label_chain
struct label_chain *next;
tree label;
};
+
+
+/* Non-zero if we are using EH to handle cleanus. */
+static int using_eh_for_cleanups_p = 0;
+
+
static void expand_goto_internal PROTO((tree, rtx, rtx));
-static void bc_expand_goto_internal PROTO((enum bytecode_opcode,
- struct bc_label *, tree));
static int expand_fixup PROTO((tree, rtx, rtx));
-static void bc_expand_fixup PROTO((enum bytecode_opcode,
- struct bc_label *, int));
static void fixup_gotos PROTO((struct nesting *, rtx, tree,
rtx, int));
-static void bc_fixup_gotos PROTO((struct nesting *, int, tree,
- rtx, int));
-static void bc_expand_start_cond PROTO((tree, int));
-static void bc_expand_end_cond PROTO((void));
-static void bc_expand_start_else PROTO((void));
-static void bc_expand_end_loop PROTO((void));
-static void bc_expand_end_bindings PROTO((tree, int, int));
-static void bc_expand_decl PROTO((tree, tree));
-static void bc_expand_variable_local_init PROTO((tree));
-static void bc_expand_decl_init PROTO((tree));
static void expand_null_return_1 PROTO((rtx, int));
static void expand_value_return PROTO((rtx));
static int tail_recursion_args PROTO((tree, tree));
static void expand_cleanups PROTO((tree, tree, int, int));
-static void bc_expand_start_case PROTO((struct nesting *, tree,
- tree, char *));
-static int bc_pushcase PROTO((tree, tree));
-static void bc_check_for_full_enumeration_handling PROTO((tree));
-static void bc_expand_end_case PROTO((tree));
+static void check_seenlabel PROTO((void));
static void do_jump_if_equal PROTO((rtx, rtx, rtx, int));
static int estimate_case_costs PROTO((case_node_ptr));
static void group_case_nodes PROTO((case_node_ptr));
@@ -466,17 +444,20 @@ static int node_has_high_bound PROTO((case_node_ptr, tree));
static int node_is_bounded PROTO((case_node_ptr, tree));
static void emit_jump_if_reachable PROTO((rtx));
static void emit_case_nodes PROTO((rtx, case_node_ptr, rtx, tree));
-
-extern rtx bc_allocate_local ();
-extern rtx bc_allocate_variable_array ();
+static int add_case_node PROTO((tree, tree, tree, tree *));
+static struct case_node *case_tree2list PROTO((case_node *, case_node *));
void
+using_eh_for_cleanups ()
+{
+ using_eh_for_cleanups_p = 1;
+}
+
+void
init_stmt ()
{
gcc_obstack_init (&stmt_obstack);
-#if 0
- empty_cleanup_list = build_tree_list (NULL_TREE, NULL_TREE);
-#endif
+ init_eh ();
}
void
@@ -499,6 +480,8 @@ init_stmt_for_function ()
/* We are not processing a ({...}) grouping. */
expr_stmts_for_value = 0;
last_expr_type = 0;
+
+ init_eh_for_function ();
}
void
@@ -519,6 +502,7 @@ save_stmt_status (p)
p->emit_filename = emit_filename;
p->emit_lineno = emit_lineno;
p->goto_fixup_chain = goto_fixup_chain;
+ save_eh_status (p);
}
void
@@ -539,6 +523,7 @@ restore_stmt_status (p)
emit_filename = p->emit_filename;
emit_lineno = p->emit_lineno;
goto_fixup_chain = p->goto_fixup_chain;
+ restore_eh_status (p);
}
/* Emit a no-op instruction. */
@@ -548,15 +533,12 @@ emit_nop ()
{
rtx last_insn;
- if (!output_bytecode)
- {
- last_insn = get_last_insn ();
- if (!optimize
- && (GET_CODE (last_insn) == CODE_LABEL
- || (GET_CODE (last_insn) == NOTE
- && prev_real_insn (last_insn) == 0)))
- emit_insn (gen_nop ());
- }
+ last_insn = get_last_insn ();
+ if (!optimize
+ && (GET_CODE (last_insn) == CODE_LABEL
+ || (GET_CODE (last_insn) == NOTE
+ && prev_real_insn (last_insn) == 0)))
+ emit_insn (gen_nop ());
}
/* Return the rtx-label that corresponds to a LABEL_DECL,
@@ -593,23 +575,20 @@ void
expand_computed_goto (exp)
tree exp;
{
- if (output_bytecode)
- {
- bc_expand_expr (exp);
- bc_emit_instruction (jumpP);
- }
- else
- {
- rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0);
+ rtx x = expand_expr (exp, NULL_RTX, VOIDmode, 0);
#ifdef POINTERS_EXTEND_UNSIGNED
- x = convert_memory_address (Pmode, x);
+ x = convert_memory_address (Pmode, x);
#endif
- emit_queue ();
- do_pending_stack_adjust ();
- emit_indirect_jump (x);
- }
+ emit_queue ();
+ /* Be sure the function is executable. */
+ if (flag_check_memory_usage)
+ emit_library_call (chkr_check_exec_libfunc, 1,
+ VOIDmode, 1, x, ptr_mode);
+
+ do_pending_stack_adjust ();
+ emit_indirect_jump (x);
}
/* Handle goto statements and the labels that they can go to. */
@@ -631,15 +610,6 @@ expand_label (label)
{
struct label_chain *p;
- if (output_bytecode)
- {
- if (! DECL_RTL (label))
- DECL_RTL (label) = bc_gen_rtx ((char *) 0, 0, bc_get_bytecode_label ());
- if (! bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (DECL_RTL (label))))
- error ("multiply defined label");
- return;
- }
-
do_pending_stack_adjust ();
emit_label (label_rtx (label));
if (DECL_NAME (label))
@@ -683,18 +653,12 @@ expand_goto (label)
{
tree context;
- if (output_bytecode)
- {
- expand_goto_internal (label, label_rtx (label), NULL_RTX);
- return;
- }
-
/* Check for a nonlocal goto to a containing function. */
context = decl_function_context (label);
if (context != 0 && context != current_function_decl)
{
struct function *p = find_function_data (context);
- rtx label_ref = gen_rtx (LABEL_REF, Pmode, label_rtx (label));
+ rtx label_ref = gen_rtx_LABEL_REF (Pmode, label_rtx (label));
rtx temp;
p->has_nonlocal_label = 1;
@@ -747,9 +711,9 @@ expand_goto (label)
emit_move_insn (static_chain_rtx, label_ref);
/* USE of hard_frame_pointer_rtx added for consistency; not clear if
really needed. */
- emit_insn (gen_rtx (USE, VOIDmode, hard_frame_pointer_rtx));
- emit_insn (gen_rtx (USE, VOIDmode, stack_pointer_rtx));
- emit_insn (gen_rtx (USE, VOIDmode, static_chain_rtx));
+ emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
+ emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
+ emit_insn (gen_rtx_USE (VOIDmode, static_chain_rtx));
emit_indirect_jump (temp);
}
}
@@ -771,16 +735,6 @@ expand_goto_internal (body, label, last_insn)
struct nesting *block;
rtx stack_level = 0;
- /* NOTICE! If a bytecode instruction other than `jump' is needed,
- then the caller has to call bc_expand_goto_internal()
- directly. This is rather an exceptional case, and there aren't
- that many places where this is necessary. */
- if (output_bytecode)
- {
- expand_goto_internal (body, label, last_insn);
- return;
- }
-
if (GET_CODE (label) != CODE_LABEL)
abort ();
@@ -809,8 +763,9 @@ expand_goto_internal (body, label, last_insn)
if (stack_level)
{
- /* Ensure stack adjust isn't done by emit_jump, as this would clobber
- the stack pointer. This one should be deleted as dead by flow. */
+ /* Ensure stack adjust isn't done by emit_jump, as this
+ would clobber the stack pointer. This one should be
+ deleted as dead by flow. */
clear_pending_stack_adjust ();
do_pending_stack_adjust ();
emit_stack_restore (SAVE_BLOCK, stack_level, NULL_RTX);
@@ -833,78 +788,6 @@ expand_goto_internal (body, label, last_insn)
emit_jump (label);
}
-/* Generate a jump with OPCODE to the given bytecode LABEL which is
- found within BODY. */
-
-static void
-bc_expand_goto_internal (opcode, label, body)
- enum bytecode_opcode opcode;
- struct bc_label *label;
- tree body;
-{
- struct nesting *block;
- int stack_level = -1;
-
- /* If the label is defined, adjust the stack as necessary.
- If it's not defined, we have to push the reference on the
- fixup list. */
-
- if (label->defined)
- {
-
- /* Find the innermost pending block that contains the label.
- (Check containment by comparing bytecode uids.) Then restore the
- outermost stack level within that block. */
-
- for (block = block_stack; block; block = block->next)
- {
- if (BYTECODE_BC_LABEL (block->data.block.first_insn)->uid < label->uid)
- break;
- if (block->data.block.bc_stack_level)
- stack_level = block->data.block.bc_stack_level;
-
- /* Execute the cleanups for blocks we are exiting. */
- if (block->data.block.cleanups != 0)
- {
- expand_cleanups (block->data.block.cleanups, NULL_TREE, 1, 1);
- do_pending_stack_adjust ();
- }
- }
-
- /* Restore the stack level. If we need to adjust the stack, we
- must do so after the jump, since the jump may depend on
- what's on the stack. Thus, any stack-modifying conditional
- jumps (these are the only ones that rely on what's on the
- stack) go into the fixup list. */
-
- if (stack_level >= 0
- && stack_depth != stack_level
- && opcode != jump)
-
- bc_expand_fixup (opcode, label, stack_level);
- else
- {
- if (stack_level >= 0)
- bc_adjust_stack (stack_depth - stack_level);
-
- if (body && DECL_BIT_FIELD (body))
- error ("jump to `%s' invalidly jumps into binding contour",
- IDENTIFIER_POINTER (DECL_NAME (body)));
-
- /* Emit immediate jump */
- bc_emit_bytecode (opcode);
- bc_emit_bytecode_labelref (label);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
- }
- }
- else
- /* Put goto in the fixup list */
- bc_expand_fixup (opcode, label, stack_level);
-}
-
/* Generate if necessary a fixup for a goto
whose target label in tree structure (if any) is TREE_LABEL
and whose target in rtl is RTL_LABEL.
@@ -1002,29 +885,31 @@ expand_fixup (tree_label, rtl_label, last_insn)
code which we might later insert at this point in the insn
stream. Also, the BLOCK node will be the parent (i.e. the
`SUPERBLOCK') of any other BLOCK nodes which we might create
- later on when we are expanding the fixup code. */
+ later on when we are expanding the fixup code.
+
+ Note that optimization passes (including expand_end_loop)
+ might move the *_BLOCK notes away, so we use a NOTE_INSN_DELETED
+ as a placeholder. */
{
register rtx original_before_jump
= last_insn ? last_insn : get_last_insn ();
+ rtx start;
start_sequence ();
pushlevel (0);
- fixup->before_jump = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
+ start = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
+ fixup->before_jump = emit_note (NULL_PTR, NOTE_INSN_DELETED);
last_block_end_note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_END);
fixup->context = poplevel (1, 0, 0); /* Create the BLOCK node now! */
end_sequence ();
- emit_insns_after (fixup->before_jump, original_before_jump);
+ emit_insns_after (start, original_before_jump);
}
fixup->block_start_count = block_start_count;
fixup->stack_level = 0;
fixup->cleanup_list_list
- = (((block->data.block.outer_cleanups
-#if 0
- && block->data.block.outer_cleanups != empty_cleanup_list
-#endif
- )
+ = ((block->data.block.outer_cleanups
|| block->data.block.cleanups)
? tree_cons (NULL_TREE, block->data.block.cleanups,
block->data.block.outer_cleanups)
@@ -1037,34 +922,6 @@ expand_fixup (tree_label, rtl_label, last_insn)
}
-/* Generate bytecode jump with OPCODE to a fixup routine that links to LABEL.
- Make the fixup restore the stack level to STACK_LEVEL. */
-
-static void
-bc_expand_fixup (opcode, label, stack_level)
- enum bytecode_opcode opcode;
- struct bc_label *label;
- int stack_level;
-{
- struct goto_fixup *fixup
- = (struct goto_fixup *) oballoc (sizeof (struct goto_fixup));
-
- fixup->label = bc_get_bytecode_label ();
- fixup->bc_target = label;
- fixup->bc_stack_level = stack_level;
- fixup->bc_handled = FALSE;
-
- fixup->next = goto_fixup_chain;
- goto_fixup_chain = fixup;
-
- /* Insert a jump to the fixup code */
- bc_emit_bytecode (opcode);
- bc_emit_bytecode_labelref (fixup->label);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-}
/* Expand any needed fixups in the outputmost binding level of the
function. FIRST_INSN is the first insn in the function. */
@@ -1099,15 +956,6 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
{
register struct goto_fixup *f, *prev;
- if (output_bytecode)
- {
- /* ??? The second arg is the bc stack level, which is not the same
- as STACK_LEVEL. I have no idea what should go here, so I'll
- just pass 0. */
- bc_fixup_gotos (thisblock, 0, cleanup_list, first_insn, dont_jump_in);
- return;
- }
-
/* F is the fixup we are considering; PREV is the previous one. */
/* We run this loop in two passes so that cleanups of exited blocks
are run first, and blocks that are exited are marked so
@@ -1148,12 +996,12 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
&& (after_label == 0
|| INSN_UID (first_insn) < INSN_UID (after_label))
&& INSN_UID (first_insn) > INSN_UID (f->before_jump)
- && ! DECL_REGISTER (f->target))
+ && ! DECL_ERROR_ISSUED (f->target))
{
error_with_decl (f->target,
"label `%s' used before containing binding contour");
/* Prevent multiple errors for one label. */
- DECL_REGISTER (f->target) = 1;
+ DECL_ERROR_ISSUED (f->target) = 1;
}
/* We will expand the cleanups into a sequence of their own and
@@ -1213,7 +1061,7 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
/* For any still-undefined labels, do the cleanups for this block now.
We must do this now since items in the cleanup list may go out
- of scope when the block ends. */
+ of scope when the block ends. */
for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
if (f->before_jump != 0
&& PREV_INSN (f->target_rtl) == 0
@@ -1243,8 +1091,9 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
cleanup_insns = get_insns ();
poplevel (1, 0, 0);
end_sequence ();
- f->before_jump
- = emit_insns_after (cleanup_insns, f->before_jump);
+ if (cleanup_insns != 0)
+ f->before_jump
+ = emit_insns_after (cleanup_insns, f->before_jump);
f->cleanup_list_list = TREE_CHAIN (lists);
}
@@ -1255,70 +1104,6 @@ fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
}
-/* When exiting a binding contour, process all pending gotos requiring fixups.
- Note: STACK_DEPTH is not altered.
-
- The arguments are currently not used in the bytecode compiler, but we may
- need them one day for languages other than C.
-
- THISBLOCK is the structure that describes the block being exited.
- STACK_LEVEL is the rtx for the stack level to restore exiting this contour.
- CLEANUP_LIST is a list of expressions to evaluate on exiting this contour.
- FIRST_INSN is the insn that began this contour.
-
- Gotos that jump out of this contour must restore the
- stack level and do the cleanups before actually jumping.
-
- DONT_JUMP_IN nonzero means report error there is a jump into this
- contour from before the beginning of the contour.
- This is also done if STACK_LEVEL is nonzero. */
-
-static void
-bc_fixup_gotos (thisblock, stack_level, cleanup_list, first_insn, dont_jump_in)
- struct nesting *thisblock;
- int stack_level;
- tree cleanup_list;
- rtx first_insn;
- int dont_jump_in;
-{
- register struct goto_fixup *f, *prev;
- int saved_stack_depth;
-
- /* F is the fixup we are considering; PREV is the previous one. */
-
- for (prev = 0, f = goto_fixup_chain; f; prev = f, f = f->next)
- {
- /* Test for a fixup that is inactive because it is already handled. */
- if (f->before_jump == 0)
- {
- /* Delete inactive fixup from the chain, if that is easy to do. */
- if (prev)
- prev->next = f->next;
- }
-
- /* Emit code to restore the stack and continue */
- bc_emit_bytecode_labeldef (f->label);
-
- /* Save stack_depth across call, since bc_adjust_stack () will alter
- the perceived stack depth via the instructions generated. */
-
- if (f->bc_stack_level >= 0)
- {
- saved_stack_depth = stack_depth;
- bc_adjust_stack (stack_depth - f->bc_stack_level);
- stack_depth = saved_stack_depth;
- }
-
- bc_emit_bytecode (jump);
- bc_emit_bytecode_labelref (f->bc_target);
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
- }
-
- goto_fixup_chain = NULL;
-}
/* Generate RTL for an asm statement (explicit assembler code).
BODY is a STRING_CST node containing the assembler code text,
@@ -1328,17 +1113,17 @@ void
expand_asm (body)
tree body;
{
- if (output_bytecode)
+ if (flag_check_memory_usage)
{
- error ("`asm' is invalid when generating bytecode");
+ error ("`asm' cannot be used with `-fcheck-memory-usage'");
return;
}
if (TREE_CODE (body) == ADDR_EXPR)
body = TREE_OPERAND (body, 0);
- emit_insn (gen_rtx (ASM_INPUT, VOIDmode,
- TREE_STRING_POINTER (body)));
+ emit_insn (gen_rtx_ASM_INPUT (VOIDmode,
+ TREE_STRING_POINTER (body)));
last_expr_type = 0;
}
@@ -1368,17 +1153,25 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
rtx body;
int ninputs = list_length (inputs);
int noutputs = list_length (outputs);
+ int ninout = 0;
int nclobbers;
tree tail;
register int i;
/* Vector of RTX's of evaluated output operands. */
rtx *output_rtx = (rtx *) alloca (noutputs * sizeof (rtx));
+ int *inout_opnum = (int *) alloca (noutputs * sizeof (int));
+ enum machine_mode *inout_mode
+ = (enum machine_mode *) alloca (noutputs * sizeof (enum machine_mode));
/* The insn we have emitted. */
rtx insn;
- if (output_bytecode)
+ /* An ASM with no outputs needs to be treated as volatile, for now. */
+ if (noutputs == 0)
+ vol = 1;
+
+ if (flag_check_memory_usage)
{
- error ("`asm' is invalid when generating bytecode");
+ error ("`asm' cannot be used with `-fcheck-memory-usage'");
return;
}
@@ -1401,9 +1194,9 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
{
tree val = TREE_VALUE (tail);
tree type = TREE_TYPE (val);
- tree val1;
int j;
int found_equal = 0;
+ int found_plus = 0;
int allows_reg = 0;
/* If there's an erroneous arg, emit no insn. */
@@ -1419,15 +1212,23 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
switch (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j])
{
case '+':
- error ("output operand constraint contains `+'");
- return;
+ /* Make sure we can specify the matching operand. */
+ if (i > 9)
+ {
+ error ("output operand constraint %d contains `+'", i);
+ return;
+ }
+
+ /* Replace '+' with '='. */
+ TREE_STRING_POINTER (TREE_PURPOSE (tail))[j] = '=';
+ found_plus = 1;
+ break;
case '=':
found_equal = 1;
break;
case '?': case '!': case '*': case '%': case '&':
- case '0': case '1': case '2': case '3': case '4':
case 'V': case 'm': case 'o': case '<': case '>':
case 'E': case 'F': case 'G': case 'H': case 'X':
case 's': case 'i': case 'n':
@@ -1438,13 +1239,18 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
#endif
break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ error ("matching constraint not valid in output operand");
+ break;
+
case 'p': case 'g': case 'r':
default:
allows_reg = 1;
break;
}
- if (! found_equal)
+ if (! found_equal && ! found_plus)
{
error ("output operand constraint lacks `='");
return;
@@ -1459,32 +1265,33 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|| (TREE_CODE_CLASS (TREE_CODE (val)) == 'd'
&& ! (GET_CODE (DECL_RTL (val)) == REG
&& GET_MODE (DECL_RTL (val)) != TYPE_MODE (type)))
- || ! allows_reg)
+ || ! allows_reg
+ || found_plus)
{
if (! allows_reg)
mark_addressable (TREE_VALUE (tail));
output_rtx[i]
- = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode, 0);
+ = expand_expr (TREE_VALUE (tail), NULL_RTX, VOIDmode,
+ EXPAND_MEMORY_USE_WO);
if (! allows_reg && GET_CODE (output_rtx[i]) != MEM)
error ("output number %d not directly addressable", i);
}
else
{
- if (TYPE_MODE (type) == BLKmode)
- {
- output_rtx[i] = assign_stack_temp (BLKmode,
- int_size_in_bytes (type), 0);
- MEM_IN_STRUCT_P (output_rtx[i]) = AGGREGATE_TYPE_P (type);
- }
- else
- output_rtx[i] = gen_reg_rtx (TYPE_MODE (type));
-
+ output_rtx[i] = assign_temp (type, 0, 0, 0);
TREE_VALUE (tail) = make_tree (type, output_rtx[i]);
}
+
+ if (found_plus)
+ {
+ inout_mode[ninout] = TYPE_MODE (TREE_TYPE (TREE_VALUE (tail)));
+ inout_opnum[ninout++] = i;
+ }
}
+ ninputs += ninout;
if (ninputs + noutputs > MAX_RECOG_OPERANDS)
{
error ("more than %d operands in `asm'", MAX_RECOG_OPERANDS);
@@ -1496,9 +1303,10 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
argvec = rtvec_alloc (ninputs);
constraints = rtvec_alloc (ninputs);
- body = gen_rtx (ASM_OPERANDS, VOIDmode,
- TREE_STRING_POINTER (string), "", 0, argvec, constraints,
- filename, line);
+ body = gen_rtx_ASM_OPERANDS (VOIDmode,
+ TREE_STRING_POINTER (string), "", 0, argvec,
+ constraints, filename, line);
+
MEM_VOLATILE_P (body) = vol;
/* Eval the inputs and put them into ARGVEC.
@@ -1543,7 +1351,23 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
#endif
break;
+ /* Whether or not a numeric constraint allows a register is
+ decided by the matching constraint, and so there is no need
+ to do anything special with them. We must handle them in
+ the default case, so that we don't unnecessarily force
+ operands to memory. */
case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (TREE_STRING_POINTER (TREE_PURPOSE (tail))[j]
+ >= '0' + noutputs)
+ {
+ error
+ ("matching constraint references invalid operand number");
+ return;
+ }
+
+ /* ... fall through ... */
+
case 'p': case 'g': case 'r':
default:
allows_reg = 1;
@@ -1575,29 +1399,40 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|| GET_CODE (XVECEXP (body, 3, i)) == CONCAT))
{
tree type = TREE_TYPE (TREE_VALUE (tail));
- rtx memloc = assign_stack_temp (TYPE_MODE (type),
- int_size_in_bytes (type), 1);
+ rtx memloc = assign_temp (type, 1, 1, 1);
- MEM_IN_STRUCT_P (memloc) = AGGREGATE_TYPE_P (type);
emit_move_insn (memloc, XVECEXP (body, 3, i));
XVECEXP (body, 3, i) = memloc;
}
XVECEXP (body, 4, i) /* constraints */
- = gen_rtx (ASM_INPUT, TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
- TREE_STRING_POINTER (TREE_PURPOSE (tail)));
+ = gen_rtx_ASM_INPUT (TYPE_MODE (TREE_TYPE (TREE_VALUE (tail))),
+ TREE_STRING_POINTER (TREE_PURPOSE (tail)));
i++;
}
/* Protect all the operands from the queue,
now that they have all been evaluated. */
- for (i = 0; i < ninputs; i++)
+ for (i = 0; i < ninputs - ninout; i++)
XVECEXP (body, 3, i) = protect_from_queue (XVECEXP (body, 3, i), 0);
for (i = 0; i < noutputs; i++)
output_rtx[i] = protect_from_queue (output_rtx[i], 1);
+ /* For in-out operands, copy output rtx to input rtx. */
+ for (i = 0; i < ninout; i++)
+ {
+ static char match[9+1][2]
+ = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
+ int j = inout_opnum[i];
+
+ XVECEXP (body, 3, ninputs - ninout + i) /* argvec */
+ = output_rtx[j];
+ XVECEXP (body, 4, ninputs - ninout + i) /* constraints */
+ = gen_rtx_ASM_INPUT (inout_mode[j], match[j]);
+ }
+
/* Now, for each output, construct an rtx
(set OUTPUT (asm_operands INSN OUTPUTNUMBER OUTPUTCONSTRAINT
ARGVEC CONSTRAINTS))
@@ -1606,7 +1441,7 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
if (noutputs == 1 && nclobbers == 0)
{
XSTR (body, 1) = TREE_STRING_POINTER (TREE_PURPOSE (outputs));
- insn = emit_insn (gen_rtx (SET, VOIDmode, output_rtx[0], body));
+ insn = emit_insn (gen_rtx_SET (VOIDmode, output_rtx[0], body));
}
else if (noutputs == 0 && nclobbers == 0)
{
@@ -1618,20 +1453,20 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
rtx obody = body;
int num = noutputs;
if (num == 0) num = 1;
- body = gen_rtx (PARALLEL, VOIDmode, rtvec_alloc (num + nclobbers));
+ body = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num + nclobbers));
/* For each output operand, store a SET. */
for (i = 0, tail = outputs; tail; tail = TREE_CHAIN (tail), i++)
{
XVECEXP (body, 0, i)
- = gen_rtx (SET, VOIDmode,
- output_rtx[i],
- gen_rtx (ASM_OPERANDS, VOIDmode,
- TREE_STRING_POINTER (string),
- TREE_STRING_POINTER (TREE_PURPOSE (tail)),
- i, argvec, constraints,
- filename, line));
+ = gen_rtx_SET (VOIDmode,
+ output_rtx[i],
+ gen_rtx_ASM_OPERANDS (VOIDmode,
+ TREE_STRING_POINTER (string),
+ TREE_STRING_POINTER (TREE_PURPOSE (tail)),
+ i, argvec, constraints,
+ filename, line));
MEM_VOLATILE_P (SET_SRC (XVECEXP (body, 0, i))) = vol;
}
@@ -1656,19 +1491,19 @@ expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
if (j == -4) /* `memory', don't cache memory across asm */
{
XVECEXP (body, 0, i++)
- = gen_rtx (CLOBBER, VOIDmode,
- gen_rtx (MEM, BLKmode,
- gen_rtx (SCRATCH, VOIDmode, 0)));
+ = gen_rtx_CLOBBER (VOIDmode,
+ gen_rtx_MEM (BLKmode,
+ gen_rtx_SCRATCH (VOIDmode)));
continue;
}
- /* Ignore unknown register, error already signalled. */
+ /* Ignore unknown register, error already signaled. */
continue;
}
/* Use QImode since that's guaranteed to clobber just one reg. */
XVECEXP (body, 0, i++)
- = gen_rtx (CLOBBER, VOIDmode, gen_rtx (REG, QImode, j));
+ = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (QImode, j));
}
insn = emit_insn (body);
@@ -1684,22 +1519,6 @@ void
expand_expr_stmt (exp)
tree exp;
{
- if (output_bytecode)
- {
- int org_stack_depth = stack_depth;
-
- bc_expand_expr (exp);
-
- /* Restore stack depth */
- if (stack_depth < org_stack_depth)
- abort ();
-
- bc_emit_instruction (drop);
-
- last_expr_type = TREE_TYPE (exp);
- return;
- }
-
/* If -W, warn about statements with no side effects,
except for an explicit cast to void (e.g. for assert()), and
except inside a ({...}) where they may be useful. */
@@ -1720,7 +1539,9 @@ expand_expr_stmt (exp)
exp = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (exp)), exp);
last_expr_type = TREE_TYPE (exp);
- if (! flag_syntax_only)
+ if (flag_syntax_only && ! expr_stmts_for_value)
+ last_expr_value = 0;
+ else
last_expr_value = expand_expr (exp,
(expr_stmts_for_value
? NULL_RTX : const0_rtx),
@@ -1784,6 +1605,7 @@ warn_if_unused_value (exp)
case CALL_EXPR:
case METHOD_CALL_EXPR:
case RTL_EXPR:
+ case TRY_CATCH_EXPR:
case WITH_CLEANUP_EXPR:
case EXIT_EXPR:
/* We don't warn about COND_EXPR because it may be a useful
@@ -1843,7 +1665,7 @@ warn_if_unused_value (exp)
the user cannot control it. */
if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == REFERENCE_TYPE)
return warn_if_unused_value (TREE_OPERAND (exp, 0));
- /* ... fall through ... */
+ /* ... fall through ... */
default:
/* Referencing a volatile value is a side effect, so don't warn. */
@@ -1876,10 +1698,6 @@ expand_start_stmt_expr ()
int momentary;
tree t;
- /* When generating bytecode just note down the stack depth */
- if (output_bytecode)
- return (build_int_2 (stack_depth, 0));
-
/* Make the RTL_EXPR node temporary, not momentary,
so that rtl_expr_chain doesn't become garbage. */
momentary = suspend_momentary ();
@@ -1908,38 +1726,6 @@ tree
expand_end_stmt_expr (t)
tree t;
{
- if (output_bytecode)
- {
- int i;
- tree t;
-
-
- /* At this point, all expressions have been evaluated in order.
- However, all expression values have been popped when evaluated,
- which means we have to recover the last expression value. This is
- the last value removed by means of a `drop' instruction. Instead
- of adding code to inhibit dropping the last expression value, it
- is here recovered by undoing the `drop'. Since `drop' is
- equivalent to `adjustackSI [1]', it can be undone with `adjstackSI
- [-1]'. */
-
- bc_adjust_stack (-1);
-
- if (!last_expr_type)
- last_expr_type = void_type_node;
-
- t = make_node (RTL_EXPR);
- TREE_TYPE (t) = last_expr_type;
- RTL_EXPR_RTL (t) = NULL;
- RTL_EXPR_SEQUENCE (t) = NULL;
-
- /* Don't consider deleting this expr or containing exprs at tree level. */
- TREE_THIS_VOLATILE (t) = 1;
-
- last_expr_type = 0;
- return t;
- }
-
OK_DEFER_POP;
if (last_expr_type == 0)
@@ -2003,10 +1789,7 @@ expand_start_cond (cond, exitflag)
cond_stack = thiscond;
nesting_stack = thiscond;
- if (output_bytecode)
- bc_expand_start_cond (cond, exitflag);
- else
- do_jump (cond, thiscond->data.cond.next_label, NULL_RTX);
+ do_jump (cond, thiscond->data.cond.next_label, NULL_RTX);
}
/* Generate RTL between then-clause and the elseif-clause
@@ -2033,15 +1816,9 @@ expand_start_else ()
if (cond_stack->data.cond.endif_label == 0)
cond_stack->data.cond.endif_label = gen_label_rtx ();
- if (output_bytecode)
- {
- bc_expand_start_else ();
- return;
- }
-
emit_jump (cond_stack->data.cond.endif_label);
emit_label (cond_stack->data.cond.next_label);
- cond_stack->data.cond.next_label = 0; /* No more _else or _elseif calls. */
+ cond_stack->data.cond.next_label = 0; /* No more _else or _elseif calls. */
}
/* After calling expand_start_else, turn this "else" into an "else if"
@@ -2063,76 +1840,17 @@ expand_end_cond ()
{
struct nesting *thiscond = cond_stack;
- if (output_bytecode)
- bc_expand_end_cond ();
- else
- {
- do_pending_stack_adjust ();
- if (thiscond->data.cond.next_label)
- emit_label (thiscond->data.cond.next_label);
- if (thiscond->data.cond.endif_label)
- emit_label (thiscond->data.cond.endif_label);
- }
+ do_pending_stack_adjust ();
+ if (thiscond->data.cond.next_label)
+ emit_label (thiscond->data.cond.next_label);
+ if (thiscond->data.cond.endif_label)
+ emit_label (thiscond->data.cond.endif_label);
POPSTACK (cond_stack);
last_expr_type = 0;
}
-/* Generate code for the start of an if-then. COND is the expression
- whose truth is to be tested; if EXITFLAG is nonzero this conditional
- is to be visible to exit_something. It is assumed that the caller
- has pushed the previous context on the cond stack. */
-
-static void
-bc_expand_start_cond (cond, exitflag)
- tree cond;
- int exitflag;
-{
- struct nesting *thiscond = cond_stack;
-
- thiscond->data.case_stmt.nominal_type = cond;
- if (! exitflag)
- thiscond->exit_label = gen_label_rtx ();
- bc_expand_expr (cond);
- bc_emit_bytecode (xjumpifnot);
- bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscond->exit_label));
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-}
-
-/* Generate the label for the end of an if with
- no else- clause. */
-
-static void
-bc_expand_end_cond ()
-{
- struct nesting *thiscond = cond_stack;
-
- bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscond->exit_label));
-}
-
-/* Generate code for the start of the else- clause of
- an if-then-else. */
-
-static void
-bc_expand_start_else ()
-{
- struct nesting *thiscond = cond_stack;
-
- thiscond->data.cond.endif_label = thiscond->exit_label;
- thiscond->exit_label = gen_label_rtx ();
- bc_emit_bytecode (jump);
- bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscond->exit_label));
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-
- bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscond->data.cond.endif_label));
-}
/* Generate RTL for the start of a loop. EXIT_FLAG is nonzero if this
loop should be exited by `exit_something'. This is a loop for which
@@ -2160,12 +1878,6 @@ expand_start_loop (exit_flag)
loop_stack = thisloop;
nesting_stack = thisloop;
- if (output_bytecode)
- {
- bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thisloop->data.loop.start_label));
- return thisloop;
- }
-
do_pending_stack_adjust ();
emit_queue ();
emit_note (NULL_PTR, NOTE_INSN_LOOP_BEG);
@@ -2194,36 +1906,11 @@ expand_start_loop_continue_elsewhere (exit_flag)
void
expand_loop_continue_here ()
{
- if (output_bytecode)
- {
- bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (loop_stack->data.loop.continue_label));
- return;
- }
do_pending_stack_adjust ();
emit_note (NULL_PTR, NOTE_INSN_LOOP_CONT);
emit_label (loop_stack->data.loop.continue_label);
}
-/* End a loop. */
-
-static void
-bc_expand_end_loop ()
-{
- struct nesting *thisloop = loop_stack;
-
- bc_emit_bytecode (jump);
- bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thisloop->data.loop.start_label));
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-
- bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thisloop->exit_label));
- POPSTACK (loop_stack);
- last_expr_type = 0;
-}
-
-
/* Finish a loop. Generate a jump back to the top and the loop-exit label.
Pop the block off of loop_stack. */
@@ -2235,12 +1922,6 @@ expand_end_loop ()
rtx last_test_insn = 0;
int num_insns = 0;
- if (output_bytecode)
- {
- bc_expand_end_loop ();
- return;
- }
-
insn = get_last_insn ();
start_label = loop_stack->data.loop.start_label;
@@ -2250,17 +1931,33 @@ expand_end_loop ()
do_pending_stack_adjust ();
- /* If optimizing, perhaps reorder the loop. If the loop
- starts with a conditional exit, roll that to the end
- where it will optimize together with the jump back.
-
- We look for the last conditional branch to the exit that we encounter
- before hitting 30 insns or a CALL_INSN. If we see an unconditional
- branch to the exit first, use it.
-
- We must also stop at NOTE_INSN_BLOCK_BEG and NOTE_INSN_BLOCK_END notes
- because moving them is not valid. */
-
+ /* If optimizing, perhaps reorder the loop. If the loop starts with
+ a loop exit, roll that to the end where it will optimize together
+ with the jump back.
+
+ We look for the conditional branch to the exit, except that once
+ we find such a branch, we don't look past 30 instructions.
+
+ In more detail, if the loop presently looks like this (in pseudo-C):
+
+ start_label:
+ if (test) goto end_label;
+ body;
+ goto start_label;
+ end_label;
+
+ transform it to look like:
+
+ goto start_label;
+ newstart_label:
+ body;
+ start_label:
+ if (test) goto end_label;
+ goto newstart_label;
+ end_label;
+
+ Here, the `test' may actually consist of some reasonably complex
+ code, terminating in a test. */
if (optimize
&&
! (GET_CODE (insn) == JUMP_INSN
@@ -2268,18 +1965,46 @@ expand_end_loop ()
&& SET_DEST (PATTERN (insn)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE))
{
+ int eh_regions = 0;
+
/* Scan insns from the top of the loop looking for a qualified
conditional exit. */
for (insn = NEXT_INSN (loop_stack->data.loop.start_label); insn;
insn = NEXT_INSN (insn))
{
- if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == CODE_LABEL)
- break;
+ if (GET_CODE (insn) == NOTE)
+ {
+ if (optimize < 2
+ && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
+ /* The code that actually moves the exit test will
+ carefully leave BLOCK notes in their original
+ location. That means, however, that we can't debug
+ the exit test itself. So, we refuse to move code
+ containing BLOCK notes at low optimization levels. */
+ break;
- if (GET_CODE (insn) == NOTE
- && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
- || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
- break;
+ if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+ ++eh_regions;
+ else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_END)
+ {
+ --eh_regions;
+ if (eh_regions < 0)
+ /* We've come to the end of an EH region, but
+ never saw the beginning of that region. That
+ means that an EH region begins before the top
+ of the loop, and ends in the middle of it. The
+ existence of such a situation violates a basic
+ assumption in this code, since that would imply
+ that even when EH_REGIONS is zero, we might
+ move code out of an exception region. */
+ abort ();
+ }
+
+ /* We already know this INSN is a NOTE, so there's no
+ point in looking at it to see if it's a JUMP. */
+ continue;
+ }
if (GET_CODE (insn) == JUMP_INSN || GET_CODE (insn) == INSN)
num_insns++;
@@ -2287,6 +2012,36 @@ expand_end_loop ()
if (last_test_insn && num_insns > 30)
break;
+ if (eh_regions > 0)
+ /* We don't want to move a partial EH region. Consider:
+
+ while ( ( { try {
+ if (cond ()) 0;
+ else {
+ bar();
+ 1;
+ }
+ } catch (...) {
+ 1;
+ } )) {
+ body;
+ }
+
+ This isn't legal C++, but here's what it's supposed to
+ mean: if cond() is true, stop looping. Otherwise,
+ call bar, and keep looping. In addition, if cond
+ throws an exception, catch it and keep looping. Such
+ constructs are certainy legal in LISP.
+
+ We should not move the `if (cond()) 0' test since then
+ the EH-region for the try-block would be broken up.
+ (In this case we would the EH_BEG note for the `try'
+ and `if cond()' but not the call to bar() or the
+ EH_END note.)
+
+ So we don't look for tests within an EH region. */
+ continue;
+
if (GET_CODE (insn) == JUMP_INSN && GET_CODE (PATTERN (insn)) == SET
&& SET_DEST (PATTERN (insn)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE
@@ -2321,6 +2076,7 @@ expand_end_loop ()
to jump to there. */
register rtx newstart_label = gen_label_rtx ();
register rtx start_move = start_label;
+ rtx next_insn;
/* If the start label is preceded by a NOTE_INSN_LOOP_CONT note,
then we want to move this note also. */
@@ -2330,7 +2086,38 @@ expand_end_loop ()
start_move = PREV_INSN (start_move);
emit_label_after (newstart_label, PREV_INSN (start_move));
- reorder_insns (start_move, last_test_insn, get_last_insn ());
+
+ /* Actually move the insns. Start at the beginning, and
+ keep copying insns until we've copied the
+ last_test_insn. */
+ for (insn = start_move; insn; insn = next_insn)
+ {
+ /* Figure out which insn comes after this one. We have
+ to do this before we move INSN. */
+ if (insn == last_test_insn)
+ /* We've moved all the insns. */
+ next_insn = NULL_RTX;
+ else
+ next_insn = NEXT_INSN (insn);
+
+ if (GET_CODE (insn) == NOTE
+ && (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
+ || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END))
+ /* We don't want to move NOTE_INSN_BLOCK_BEGs or
+ NOTE_INSN_BLOCK_ENDs because the correct generation
+ of debugging information depends on these appearing
+ in the same order in the RTL and in the tree
+ structure, where they are represented as BLOCKs.
+ So, we don't move block notes. Of course, moving
+ the code inside the block is likely to make it
+ impossible to debug the instructions in the exit
+ test, but such is the price of optimization. */
+ continue;
+
+ /* Move the INSN. */
+ reorder_insns (insn, insn, get_last_insn ());
+ }
+
emit_jump_insn_after (gen_jump (start_label),
PREV_INSN (newstart_label));
emit_barrier_after (PREV_INSN (newstart_label));
@@ -2391,35 +2178,26 @@ expand_exit_loop_if_false (whichloop, cond)
struct nesting *whichloop;
tree cond;
{
+ rtx label = gen_label_rtx ();
+ rtx last_insn;
last_expr_type = 0;
+
if (whichloop == 0)
whichloop = loop_stack;
if (whichloop == 0)
return 0;
- if (output_bytecode)
- {
- bc_expand_expr (cond);
- bc_expand_goto_internal (xjumpifnot,
- BYTECODE_BC_LABEL (whichloop->exit_label),
- NULL_TREE);
- }
- else
- {
- /* In order to handle fixups, we actually create a conditional jump
- around a unconditional branch to exit the loop. If fixups are
- necessary, they go before the unconditional branch. */
+ /* In order to handle fixups, we actually create a conditional jump
+ around a unconditional branch to exit the loop. If fixups are
+ necessary, they go before the unconditional branch. */
- rtx label = gen_label_rtx ();
- rtx last_insn;
-
- do_jump (cond, NULL_RTX, label);
- last_insn = get_last_insn ();
- if (GET_CODE (last_insn) == CODE_LABEL)
- whichloop->data.loop.alt_end_label = last_insn;
- expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label,
- NULL_RTX);
- emit_label (label);
- }
+
+ do_jump (cond, NULL_RTX, label);
+ last_insn = get_last_insn ();
+ if (GET_CODE (last_insn) == CODE_LABEL)
+ whichloop->data.loop.alt_end_label = last_insn;
+ expand_goto_internal (NULL_TREE, whichloop->data.loop.end_label,
+ NULL_RTX);
+ emit_label (label);
return 1;
}
@@ -2483,12 +2261,6 @@ expand_null_return ()
struct nesting *block = block_stack;
rtx last_insn = 0;
- if (output_bytecode)
- {
- bc_emit_instruction (ret);
- return;
- }
-
/* Does any pending block have cleanups? */
while (block && block->data.block.cleanups == 0)
@@ -2529,7 +2301,22 @@ expand_value_return (val)
}
if (GET_CODE (return_reg) == REG
&& REGNO (return_reg) < FIRST_PSEUDO_REGISTER)
- emit_insn (gen_rtx (USE, VOIDmode, return_reg));
+ emit_insn (gen_rtx_USE (VOIDmode, return_reg));
+ /* Handle calls that return values in multiple non-contiguous locations.
+ The Irix 6 ABI has examples of this. */
+ else if (GET_CODE (return_reg) == PARALLEL)
+ {
+ int i;
+
+ for (i = 0; i < XVECLEN (return_reg, 0); i++)
+ {
+ rtx x = XEXP (XVECEXP (return_reg, 0, i), 0);
+
+ if (GET_CODE (x) == REG
+ && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ emit_insn (gen_rtx_USE (VOIDmode, x));
+ }
+ }
/* Does any pending block have cleanups? */
@@ -2603,17 +2390,7 @@ expand_return (retval)
register rtx op0;
tree retval_rhs;
int cleanups;
- struct nesting *block;
- /* Bytecode returns are quite simple, just leave the result on the
- arithmetic stack. */
- if (output_bytecode)
- {
- bc_expand_expr (retval);
- bc_emit_instruction (ret);
- return;
- }
-
/* If function wants no value, give it none. */
if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE)
{
@@ -2665,14 +2442,14 @@ expand_return (retval)
tree expr;
do_jump (TREE_OPERAND (retval_rhs, 0), label, NULL_RTX);
- expr = build (MODIFY_EXPR, TREE_TYPE (current_function_decl),
+ expr = build (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (current_function_decl)),
DECL_RESULT (current_function_decl),
TREE_OPERAND (retval_rhs, 1));
TREE_SIDE_EFFECTS (expr) = 1;
expand_return (expr);
emit_label (label);
- expr = build (MODIFY_EXPR, TREE_TYPE (current_function_decl),
+ expr = build (MODIFY_EXPR, TREE_TYPE (TREE_TYPE (current_function_decl)),
DECL_RESULT (current_function_decl),
TREE_OPERAND (retval_rhs, 2));
TREE_SIDE_EFFECTS (expr) = 1;
@@ -2718,29 +2495,55 @@ expand_return (retval)
{
/* If this is return x == y; then generate
if (x == y) return 1; else return 0;
- if we can do it with explicit return insns and
- branches are cheap. */
+ if we can do it with explicit return insns and branches are cheap,
+ but not if we have the corresponding scc insn. */
+ int has_scc = 0;
if (retval_rhs)
switch (TREE_CODE (retval_rhs))
{
case EQ_EXPR:
+#ifdef HAVE_seq
+ has_scc = HAVE_seq;
+#endif
case NE_EXPR:
+#ifdef HAVE_sne
+ has_scc = HAVE_sne;
+#endif
case GT_EXPR:
+#ifdef HAVE_sgt
+ has_scc = HAVE_sgt;
+#endif
case GE_EXPR:
+#ifdef HAVE_sge
+ has_scc = HAVE_sge;
+#endif
case LT_EXPR:
+#ifdef HAVE_slt
+ has_scc = HAVE_slt;
+#endif
case LE_EXPR:
+#ifdef HAVE_sle
+ has_scc = HAVE_sle;
+#endif
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_NOT_EXPR:
case TRUTH_XOR_EXPR:
- op0 = gen_label_rtx ();
- jumpifnot (retval_rhs, op0);
- expand_value_return (const1_rtx);
- emit_label (op0);
- expand_value_return (const0_rtx);
- return;
+ if (! has_scc)
+ {
+ op0 = gen_label_rtx ();
+ jumpifnot (retval_rhs, op0);
+ expand_value_return (const1_rtx);
+ emit_label (op0);
+ expand_value_return (const0_rtx);
+ return;
+ }
+ break;
+
+ default:
+ break;
}
}
#endif /* HAVE_return */
@@ -2763,7 +2566,7 @@ expand_return (retval)
int n_regs = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
int bitsize = MIN (TYPE_ALIGN (TREE_TYPE (retval_rhs)),BITS_PER_WORD);
rtx *result_pseudos = (rtx *) alloca (sizeof (rtx) * n_regs);
- rtx result_reg, src, dst;
+ rtx result_reg, src = NULL_RTX, dst = NULL_RTX;
rtx result_val = expand_expr (retval_rhs, NULL_RTX, VOIDmode, 0);
enum machine_mode tmpmode, result_reg_mode;
@@ -2791,7 +2594,7 @@ expand_return (retval)
result_pseudos[xbitpos / BITS_PER_WORD] = dst;
/* Clobber the destination before we move anything into it. */
- emit_insn (gen_rtx (CLOBBER, VOIDmode, dst));
+ emit_insn (gen_rtx_CLOBBER (VOIDmode, dst));
}
/* We need a new source operand each time bitpos is on a word
@@ -2838,9 +2641,7 @@ expand_return (retval)
result_reg_mode = tmpmode;
result_reg = gen_reg_rtx (result_reg_mode);
- /* Now that the value is in pseudos, copy it to the result reg(s). */
emit_queue ();
- free_temp_slots ();
for (i = 0; i < n_regs; i++)
emit_move_insn (operand_subword (result_reg, i, 0, result_reg_mode),
result_pseudos[i]);
@@ -2856,10 +2657,10 @@ expand_return (retval)
&& GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) == REG)
{
/* Calculate the return value into a pseudo reg. */
- val = expand_expr (retval_rhs, NULL_RTX, VOIDmode, 0);
+ val = gen_reg_rtx (DECL_MODE (DECL_RESULT (current_function_decl)));
+ val = expand_expr (retval_rhs, val, GET_MODE (val), 0);
+ val = force_not_mem (val);
emit_queue ();
- /* All temporaries have now been used. */
- free_temp_slots ();
/* Return the calculated value, doing cleanups first. */
expand_value_return (val);
}
@@ -2869,7 +2670,6 @@ expand_return (retval)
calculate value into hard return reg. */
expand_expr (retval, const0_rtx, VOIDmode, 0);
emit_queue ();
- free_temp_slots ();
expand_value_return (DECL_RTL (DECL_RESULT (current_function_decl)));
}
}
@@ -2909,7 +2709,8 @@ tail_recursion_args (actuals, formals)
for (a = actuals, f = formals, i = 0; a && f; a = TREE_CHAIN (a), f = TREE_CHAIN (f), i++)
{
- if (TREE_TYPE (TREE_VALUE (a)) != TREE_TYPE (f))
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (a)))
+ != TYPE_MAIN_VARIANT (TREE_TYPE (f)))
return 0;
if (GET_CODE (DECL_RTL (f)) != REG || DECL_MODE (f) == BLKmode)
return 0;
@@ -2965,7 +2766,7 @@ expand_start_bindings (exit_flag)
int exit_flag;
{
struct nesting *thisblock = ALLOC_NESTING ();
- rtx note = output_bytecode ? 0 : emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
+ rtx note = emit_note (NULL_PTR, NOTE_INSN_BLOCK_BEG);
/* Make an entry on block_stack for the block we are entering. */
@@ -2975,22 +2776,13 @@ expand_start_bindings (exit_flag)
thisblock->data.block.stack_level = 0;
thisblock->data.block.cleanups = 0;
thisblock->data.block.function_call_count = 0;
-#if 0
- if (block_stack)
- {
- if (block_stack->data.block.cleanups == NULL_TREE
- && (block_stack->data.block.outer_cleanups == NULL_TREE
- || block_stack->data.block.outer_cleanups == empty_cleanup_list))
- thisblock->data.block.outer_cleanups = empty_cleanup_list;
- else
- thisblock->data.block.outer_cleanups
- = tree_cons (NULL_TREE, block_stack->data.block.cleanups,
- block_stack->data.block.outer_cleanups);
- }
- else
- thisblock->data.block.outer_cleanups = 0;
-#endif
-#if 1
+ thisblock->data.block.exception_region = 0;
+ thisblock->data.block.target_temp_slot_level = target_temp_slot_level;
+
+ thisblock->data.block.conditional_code = 0;
+ thisblock->data.block.last_unconditional_cleanup = note;
+ thisblock->data.block.cleanup_ptr = &thisblock->data.block.cleanups;
+
if (block_stack
&& !(block_stack->data.block.cleanups == NULL_TREE
&& block_stack->data.block.outer_cleanups == NULL_TREE))
@@ -2999,7 +2791,6 @@ expand_start_bindings (exit_flag)
block_stack->data.block.outer_cleanups);
else
thisblock->data.block.outer_cleanups = 0;
-#endif
thisblock->data.block.label_chain = 0;
thisblock->data.block.innermost_stack_block = stack_block_stack;
thisblock->data.block.first_insn = note;
@@ -3008,13 +2799,95 @@ expand_start_bindings (exit_flag)
block_stack = thisblock;
nesting_stack = thisblock;
- if (!output_bytecode)
+ /* Make a new level for allocating stack slots. */
+ push_temp_slots ();
+}
+
+/* Specify the scope of temporaries created by TARGET_EXPRs. Similar
+ to CLEANUP_POINT_EXPR, but handles cases when a series of calls to
+ expand_expr are made. After we end the region, we know that all
+ space for all temporaries that were created by TARGET_EXPRs will be
+ destroyed and their space freed for reuse. */
+
+void
+expand_start_target_temps ()
+{
+ /* This is so that even if the result is preserved, the space
+ allocated will be freed, as we know that it is no longer in use. */
+ push_temp_slots ();
+
+ /* Start a new binding layer that will keep track of all cleanup
+ actions to be performed. */
+ expand_start_bindings (0);
+
+ target_temp_slot_level = temp_slot_level;
+}
+
+void
+expand_end_target_temps ()
+{
+ expand_end_bindings (NULL_TREE, 0, 0);
+
+ /* This is so that even if the result is preserved, the space
+ allocated will be freed, as we know that it is no longer in use. */
+ pop_temp_slots ();
+}
+
+/* Mark top block of block_stack as an implicit binding for an
+ exception region. This is used to prevent infinite recursion when
+ ending a binding with expand_end_bindings. It is only ever called
+ by expand_eh_region_start, as that it the only way to create a
+ block stack for a exception region. */
+
+void
+mark_block_as_eh_region ()
+{
+ block_stack->data.block.exception_region = 1;
+ if (block_stack->next
+ && block_stack->next->data.block.conditional_code)
{
- /* Make a new level for allocating stack slots. */
- push_temp_slots ();
+ block_stack->data.block.conditional_code
+ = block_stack->next->data.block.conditional_code;
+ block_stack->data.block.last_unconditional_cleanup
+ = block_stack->next->data.block.last_unconditional_cleanup;
+ block_stack->data.block.cleanup_ptr
+ = block_stack->next->data.block.cleanup_ptr;
}
}
+/* True if we are currently emitting insns in an area of output code
+ that is controlled by a conditional expression. This is used by
+ the cleanup handling code to generate conditional cleanup actions. */
+
+int
+conditional_context ()
+{
+ return block_stack && block_stack->data.block.conditional_code;
+}
+
+/* Mark top block of block_stack as not for an implicit binding for an
+ exception region. This is only ever done by expand_eh_region_end
+ to let expand_end_bindings know that it is being called explicitly
+ to end the binding layer for just the binding layer associated with
+ the exception region, otherwise expand_end_bindings would try and
+ end all implicit binding layers for exceptions regions, and then
+ one normal binding layer. */
+
+void
+mark_block_as_not_eh_region ()
+{
+ block_stack->data.block.exception_region = 0;
+}
+
+/* True if the top block of block_stack was marked as for an exception
+ region by mark_block_as_eh_region. */
+
+int
+is_eh_region ()
+{
+ return block_stack && block_stack->data.block.exception_region;
+}
+
/* Given a pointer to a BLOCK node, save a pointer to the most recently
generated NOTE_INSN_BLOCK_END in the BLOCK_END_NOTE field of the given
BLOCK node. */
@@ -3042,19 +2915,33 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
int mark_ends;
int dont_jump_in;
{
- register struct nesting *thisblock = block_stack;
+ register struct nesting *thisblock;
register tree decl;
- if (output_bytecode)
+ while (block_stack->data.block.exception_region)
{
- bc_expand_end_bindings (vars, mark_ends, dont_jump_in);
- return;
+ /* Because we don't need or want a new temporary level and
+ because we didn't create one in expand_eh_region_start,
+ create a fake one now to avoid removing one in
+ expand_end_bindings. */
+ push_temp_slots ();
+
+ block_stack->data.block.exception_region = 0;
+
+ expand_end_bindings (NULL_TREE, 0, 0);
}
+ /* Since expand_eh_region_start does an expand_start_bindings, we
+ have to first end all the bindings that were created by
+ expand_eh_region_start. */
+
+ thisblock = block_stack;
+
if (warn_unused)
for (decl = vars; decl; decl = TREE_CHAIN (decl))
if (! TREE_USED (decl) && TREE_CODE (decl) == VAR_DECL
- && ! DECL_IN_SYSTEM_HEADER (decl))
+ && ! DECL_IN_SYSTEM_HEADER (decl)
+ && DECL_NAME (decl) && ! DECL_ARTIFICIAL (decl))
warning_with_decl (decl, "unused variable `%s'");
if (thisblock->exit_label)
@@ -3099,7 +2986,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
start_sequence ();
emit_move_insn (nonlocal_goto_handler_slot,
- gen_rtx (LABEL_REF, Pmode, handler_label));
+ gen_rtx_LABEL_REF (Pmode, handler_label));
insns = get_insns ();
end_sequence ();
emit_insns_before (insns, thisblock->data.block.first_insn);
@@ -3134,7 +3021,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
This is the case on all known machines; if we don't make this
assumption, we do unnecessary saving on many machines. */
static struct elims {int from, to;} elim_regs[] = ELIMINABLE_REGS;
- int i;
+ size_t i;
for (i = 0; i < sizeof elim_regs / sizeof elim_regs[0]; i++)
if (elim_regs[i].from == ARG_POINTER_REGNUM
@@ -3159,6 +3046,11 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
}
#endif
+#ifdef HAVE_nonlocal_goto_receiver
+ if (HAVE_nonlocal_goto_receiver)
+ emit_insn (gen_nonlocal_goto_receiver ());
+#endif
+
/* The handler expects the desired label address in the static chain
register. It tests the address and does an appropriate jump
to whatever label is desired. */
@@ -3169,7 +3061,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
rtx not_this = gen_label_rtx ();
rtx this = gen_label_rtx ();
do_jump_if_equal (static_chain_rtx,
- gen_rtx (LABEL_REF, Pmode, DECL_RTL (TREE_VALUE (link))),
+ gen_rtx_LABEL_REF (Pmode, DECL_RTL (TREE_VALUE (link))),
this, 0);
emit_jump (not_this);
emit_label (this);
@@ -3177,16 +3069,16 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
emit_label (not_this);
}
/* If label is not recognized, abort. */
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "abort"), 0,
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "abort"), 0,
VOIDmode, 0);
emit_barrier ();
emit_label (afterward);
}
- /* Don't allow jumping into a block that has cleanups or a stack level. */
+ /* Don't allow jumping into a block that has a stack level.
+ Cleanups are allowed, though. */
if (dont_jump_in
- || thisblock->data.block.stack_level != 0
- || thisblock->data.block.cleanups != 0)
+ || thisblock->data.block.stack_level != 0)
{
struct label_chain *chain;
@@ -3197,7 +3089,7 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
DECL_TOO_LATE (chain->label) = 1;
/* If any goto without a fixup came to this label,
that must be an error, because gotos without fixups
- come from outside all saved stack-levels and all cleanups. */
+ come from outside all saved stack-levels. */
if (TREE_ADDRESSABLE (chain->label))
error_with_decl (chain->label,
"label `%s' used before containing binding contour");
@@ -3271,6 +3163,9 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
use_variable (rtl);
}
+ /* Restore the temporary level of TARGET_EXPRs. */
+ target_temp_slot_level = thisblock->data.block.target_temp_slot_level;
+
/* Restore block_stack level for containing block. */
stack_block_stack = thisblock->data.block.innermost_stack_block;
@@ -3281,33 +3176,6 @@ expand_end_bindings (vars, mark_ends, dont_jump_in)
}
-/* End a binding contour.
- VARS is the chain of VAR_DECL nodes for the variables bound
- in this contour. MARK_ENDS is nonzer if we should put a note
- at the beginning and end of this binding contour.
- DONT_JUMP_IN is nonzero if it is not valid to jump into this
- contour. */
-
-static void
-bc_expand_end_bindings (vars, mark_ends, dont_jump_in)
- tree vars;
- int mark_ends;
- int dont_jump_in;
-{
- struct nesting *thisbind = nesting_stack;
- tree decl;
-
- if (warn_unused)
- for (decl = vars; decl; decl = TREE_CHAIN (decl))
- if (! TREE_USED (TREE_VALUE (decl)) && TREE_CODE (TREE_VALUE (decl)) == VAR_DECL)
- warning_with_decl (decl, "unused variable `%s'");
-
- if (thisbind->exit_label)
- bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thisbind->exit_label));
-
- /* Pop block/bindings off stack */
- POPSTACK (block_stack);
-}
/* Generate RTL for the automatic variable declaration DECL.
(Other kinds of declarations are simply ignored if seen here.) */
@@ -3319,12 +3187,6 @@ expand_decl (decl)
struct nesting *thisblock = block_stack;
tree type;
- if (output_bytecode)
- {
- bc_expand_decl (decl, 0);
- return;
- }
-
type = TREE_TYPE (decl);
/* Only automatic variables need any expansion done.
@@ -3341,7 +3203,7 @@ expand_decl (decl)
/* Create the RTL representation for the variable. */
if (type == error_mark_node)
- DECL_RTL (decl) = gen_rtx (MEM, BLKmode, const0_rtx);
+ DECL_RTL (decl) = gen_rtx_MEM (BLKmode, const0_rtx);
else if (DECL_SIZE (decl) == 0)
/* Variable with incomplete type. */
{
@@ -3351,7 +3213,7 @@ expand_decl (decl)
else
/* An initializer is going to decide the size of this array.
Until we know the size, represent its address with a reg. */
- DECL_RTL (decl) = gen_rtx (MEM, BLKmode, gen_reg_rtx (Pmode));
+ DECL_RTL (decl) = gen_rtx_MEM (BLKmode, gen_reg_rtx (Pmode));
MEM_IN_STRUCT_P (DECL_RTL (decl)) = AGGREGATE_TYPE_P (type);
}
else if (DECL_MODE (decl) != BLKmode
@@ -3361,36 +3223,29 @@ expand_decl (decl)
&& TREE_CODE (type) == REAL_TYPE)
&& ! TREE_THIS_VOLATILE (decl)
&& ! TREE_ADDRESSABLE (decl)
- && (DECL_REGISTER (decl) || ! obey_regdecls))
+ && (DECL_REGISTER (decl) || ! obey_regdecls)
+ /* if -fcheck-memory-usage, check all variables. */
+ && ! flag_check_memory_usage)
{
/* Automatic variable that can go in a register. */
int unsignedp = TREE_UNSIGNED (type);
enum machine_mode reg_mode
= promote_mode (type, DECL_MODE (decl), &unsignedp, 0);
- if (TREE_CODE (type) == COMPLEX_TYPE)
- {
- rtx realpart, imagpart;
- enum machine_mode partmode = TYPE_MODE (TREE_TYPE (type));
-
- /* For a complex type variable, make a CONCAT of two pseudos
- so that the real and imaginary parts
- can be allocated separately. */
- realpart = gen_reg_rtx (partmode);
- REG_USERVAR_P (realpart) = 1;
- imagpart = gen_reg_rtx (partmode);
- REG_USERVAR_P (imagpart) = 1;
- DECL_RTL (decl) = gen_rtx (CONCAT, reg_mode, realpart, imagpart);
- }
- else
- {
- DECL_RTL (decl) = gen_reg_rtx (reg_mode);
- if (TREE_CODE (type) == POINTER_TYPE)
- mark_reg_pointer (DECL_RTL (decl));
- REG_USERVAR_P (DECL_RTL (decl)) = 1;
- }
+ DECL_RTL (decl) = gen_reg_rtx (reg_mode);
+ mark_user_reg (DECL_RTL (decl));
+
+ if (POINTER_TYPE_P (type))
+ mark_reg_pointer (DECL_RTL (decl),
+ (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl)))
+ / BITS_PER_UNIT));
}
- else if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
+
+ else if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST
+ && ! (flag_stack_check && ! STACK_CHECK_BUILTIN
+ && (TREE_INT_CST_HIGH (DECL_SIZE (decl)) != 0
+ || (TREE_INT_CST_LOW (DECL_SIZE (decl))
+ > STACK_CHECK_MAX_VAR_SIZE * BITS_PER_UNIT))))
{
/* Variable of fixed size that goes on the stack. */
rtx oldaddr = 0;
@@ -3437,6 +3292,8 @@ expand_decl (decl)
if (flag_float_store && TREE_CODE (type) == REAL_TYPE)
MEM_VOLATILE_P (DECL_RTL (decl)) = 1;
#endif
+
+ MEM_ALIAS_SET (DECL_RTL (decl)) = get_alias_set (decl);
}
else
/* Dynamic-size object: must push space on the stack. */
@@ -3461,12 +3318,15 @@ expand_decl (decl)
NULL_RTX, VOIDmode, 0);
free_temp_slots ();
- /* Allocate space on the stack for the variable. */
+ /* Allocate space on the stack for the variable. Note that
+ DECL_ALIGN says how the variable is to be aligned and we
+ cannot use it to conclude anything about the alignment of
+ the size. */
address = allocate_dynamic_stack_space (size, NULL_RTX,
- DECL_ALIGN (decl));
+ TYPE_ALIGN (TREE_TYPE (decl)));
/* Reference the variable indirect through that rtx. */
- DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl), address);
+ DECL_RTL (decl) = gen_rtx_MEM (DECL_MODE (decl), address);
/* If this is a memory ref that contains aggregate components,
mark it as such for cse and loop optimize. */
@@ -3500,50 +3360,6 @@ expand_decl (decl)
}
-/* Generate code for the automatic variable declaration DECL. For
- most variables this just means we give it a stack offset. The
- compiler sometimes emits cleanups without variables and we will
- have to deal with those too. */
-
-static void
-bc_expand_decl (decl, cleanup)
- tree decl;
- tree cleanup;
-{
- tree type;
-
- if (!decl)
- {
- /* A cleanup with no variable. */
- if (!cleanup)
- abort ();
-
- return;
- }
-
- /* Only auto variables need any work. */
- if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl) || DECL_EXTERNAL (decl))
- return;
-
- type = TREE_TYPE (decl);
-
- if (type == error_mark_node)
- DECL_RTL (decl) = bc_gen_rtx ((char *) 0, 0, (struct bc_label *) 0);
-
- else if (DECL_SIZE (decl) == 0)
-
- /* Variable with incomplete type. The stack offset herein will be
- fixed later in expand_decl_init (). */
- DECL_RTL (decl) = bc_gen_rtx ((char *) 0, 0, (struct bc_label *) 0);
-
- else if (TREE_CONSTANT (DECL_SIZE (decl)))
- {
- DECL_RTL (decl) = bc_allocate_local (TREE_INT_CST_LOW (DECL_SIZE (decl)) / BITS_PER_UNIT,
- DECL_ALIGN (decl));
- }
- else
- DECL_RTL (decl) = bc_allocate_variable_array (DECL_SIZE (decl));
-}
/* Emit code to perform the initialization of a declaration DECL. */
@@ -3553,12 +3369,6 @@ expand_decl_init (decl)
{
int was_used = TREE_USED (decl);
- if (output_bytecode)
- {
- bc_expand_decl_init (decl);
- return;
- }
-
/* If this is a CONST_DECL, we don't have to generate any code, but
if DECL_INITIAL is a constant, call expand_expr to force TREE_CST_RTL
to be set while in the obstack containing the constant. If we don't
@@ -3581,8 +3391,9 @@ expand_decl_init (decl)
if (DECL_INITIAL (decl) == error_mark_node)
{
enum tree_code code = TREE_CODE (TREE_TYPE (decl));
+
if (code == INTEGER_TYPE || code == REAL_TYPE || code == ENUMERAL_TYPE
- || code == POINTER_TYPE)
+ || code == POINTER_TYPE || code == REFERENCE_TYPE)
expand_assignment (decl, convert (TREE_TYPE (decl), integer_zero_node),
0, 0);
emit_queue ();
@@ -3602,116 +3413,212 @@ expand_decl_init (decl)
free_temp_slots ();
}
-/* Expand initialization for variable-sized types. Allocate array
- using newlocalSI and set local variable, which is a pointer to the
- storage. */
+/* CLEANUP is an expression to be executed at exit from this binding contour;
+ for example, in C++, it might call the destructor for this variable.
-static void
-bc_expand_variable_local_init (decl)
- tree decl;
+ We wrap CLEANUP in an UNSAVE_EXPR node, so that we can expand the
+ CLEANUP multiple times, and have the correct semantics. This
+ happens in exception handling, for gotos, returns, breaks that
+ leave the current scope.
+
+ If CLEANUP is nonzero and DECL is zero, we record a cleanup
+ that is not associated with any particular variable. */
+
+int
+expand_decl_cleanup (decl, cleanup)
+ tree decl, cleanup;
{
- /* Evaluate size expression and coerce to SI */
- bc_expand_expr (DECL_SIZE (decl));
+ struct nesting *thisblock = block_stack;
- /* Type sizes are always (?) of TREE_CODE INTEGER_CST, so
- no coercion is necessary (?) */
+ /* Error if we are not in any block. */
+ if (thisblock == 0)
+ return 0;
-/* emit_typecode_conversion (preferred_typecode (TYPE_MODE (DECL_SIZE (decl)),
- TREE_UNSIGNED (DECL_SIZE (decl))), SIcode); */
+ /* Record the cleanup if there is one. */
- /* Emit code to allocate array */
- bc_emit_instruction (newlocalSI);
+ if (cleanup != 0)
+ {
+ tree t;
+ rtx seq;
+ tree *cleanups = &thisblock->data.block.cleanups;
+ int cond_context = conditional_context ();
- /* Store array pointer in local variable. This is the only instance
- where we actually want the address of the pointer to the
- variable-size block, rather than the pointer itself. We avoid
- using expand_address() since that would cause the pointer to be
- pushed rather than its address. Hence the hard-coded reference;
- notice also that the variable is always local (no global
- variable-size type variables). */
+ if (cond_context)
+ {
+ rtx flag = gen_reg_rtx (word_mode);
+ rtx set_flag_0;
+ tree cond;
- bc_load_localaddr (DECL_RTL (decl));
- bc_emit_instruction (storeP);
-}
+ start_sequence ();
+ emit_move_insn (flag, const0_rtx);
+ set_flag_0 = get_insns ();
+ end_sequence ();
+ thisblock->data.block.last_unconditional_cleanup
+ = emit_insns_after (set_flag_0,
+ thisblock->data.block.last_unconditional_cleanup);
-/* Emit code to initialize a declaration. */
+ emit_move_insn (flag, const1_rtx);
-static void
-bc_expand_decl_init (decl)
- tree decl;
-{
- int org_stack_depth;
+ /* All cleanups must be on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
- /* Statical initializers are handled elsewhere */
+ cond = build_decl (VAR_DECL, NULL_TREE, type_for_mode (word_mode, 1));
+ DECL_RTL (cond) = flag;
- if (TREE_STATIC (decl))
- return;
+ /* Conditionalize the cleanup. */
+ cleanup = build (COND_EXPR, void_type_node,
+ truthvalue_conversion (cond),
+ cleanup, integer_zero_node);
+ cleanup = fold (cleanup);
- /* Memory original stack depth */
- org_stack_depth = stack_depth;
+ pop_obstacks ();
- /* If the type is variable-size, we first create its space (we ASSUME
- it CAN'T be static). We do this regardless of whether there's an
- initializer assignment or not. */
+ cleanups = thisblock->data.block.cleanup_ptr;
+ }
- if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
- bc_expand_variable_local_init (decl);
+ /* All cleanups must be on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+ cleanup = unsave_expr (cleanup);
+ pop_obstacks ();
- /* Expand initializer assignment */
- if (DECL_INITIAL (decl) == error_mark_node)
- {
- enum tree_code code = TREE_CODE (TREE_TYPE (decl));
+ t = *cleanups = temp_tree_cons (decl, cleanup, *cleanups);
- if (code == INTEGER_TYPE || code == REAL_TYPE || code == ENUMERAL_TYPE
- || code == POINTER_TYPE)
+ if (! cond_context)
+ /* If this block has a cleanup, it belongs in stack_block_stack. */
+ stack_block_stack = thisblock;
- expand_assignment (TREE_TYPE (decl), decl, 0, 0);
+ if (cond_context)
+ {
+ start_sequence ();
+ }
+
+ /* If this was optimized so that there is no exception region for the
+ cleanup, then mark the TREE_LIST node, so that we can later tell
+ if we need to call expand_eh_region_end. */
+ if (! using_eh_for_cleanups_p
+ || expand_eh_region_start_tree (decl, cleanup))
+ TREE_ADDRESSABLE (t) = 1;
+ /* If that started a new EH region, we're in a new block. */
+ thisblock = block_stack;
+
+ if (cond_context)
+ {
+ seq = get_insns ();
+ end_sequence ();
+ if (seq)
+ thisblock->data.block.last_unconditional_cleanup
+ = emit_insns_after (seq,
+ thisblock->data.block.last_unconditional_cleanup);
+ }
+ else
+ {
+ thisblock->data.block.last_unconditional_cleanup
+ = get_last_insn ();
+ thisblock->data.block.cleanup_ptr = &thisblock->data.block.cleanups;
+ }
}
- else if (DECL_INITIAL (decl))
- expand_assignment (TREE_TYPE (decl), decl, 0, 0);
+ return 1;
+}
- /* Restore stack depth */
- if (org_stack_depth > stack_depth)
- abort ();
+/* Like expand_decl_cleanup, but suppress generating an exception handler
+ to perform the cleanup. */
+
+int
+expand_decl_cleanup_no_eh (decl, cleanup)
+ tree decl, cleanup;
+{
+ int save_eh = using_eh_for_cleanups_p;
+ int result;
+
+ using_eh_for_cleanups_p = 0;
+ result = expand_decl_cleanup (decl, cleanup);
+ using_eh_for_cleanups_p = save_eh;
- bc_adjust_stack (stack_depth - org_stack_depth);
+ return result;
}
-
-/* CLEANUP is an expression to be executed at exit from this binding contour;
- for example, in C++, it might call the destructor for this variable.
+/* Arrange for the top element of the dynamic cleanup chain to be
+ popped if we exit the current binding contour. DECL is the
+ associated declaration, if any, otherwise NULL_TREE. If the
+ current contour is left via an exception, then __sjthrow will pop
+ the top element off the dynamic cleanup chain. The code that
+ avoids doing the action we push into the cleanup chain in the
+ exceptional case is contained in expand_cleanups.
- If CLEANUP contains any SAVE_EXPRs, then you must preevaluate them
- either before or after calling `expand_decl_cleanup' but before compiling
- any subsequent expressions. This is because CLEANUP may be expanded
- more than once, on different branches of execution.
- For the same reason, CLEANUP may not contain a CALL_EXPR
- except as its topmost node--else `preexpand_calls' would get confused.
+ This routine is only used by expand_eh_region_start, and that is
+ the only way in which an exception region should be started. This
+ routine is only used when using the setjmp/longjmp codegen method
+ for exception handling. */
- If CLEANUP is nonzero and DECL is zero, we record a cleanup
- that is not associated with any particular variable. */
+int
+expand_dcc_cleanup (decl)
+ tree decl;
+{
+ struct nesting *thisblock = block_stack;
+ tree cleanup;
+
+ /* Error if we are not in any block. */
+ if (thisblock == 0)
+ return 0;
+
+ /* Record the cleanup for the dynamic handler chain. */
+
+ /* All cleanups must be on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+ cleanup = make_node (POPDCC_EXPR);
+ pop_obstacks ();
+
+ /* Add the cleanup in a manner similar to expand_decl_cleanup. */
+ thisblock->data.block.cleanups
+ = temp_tree_cons (decl, cleanup, thisblock->data.block.cleanups);
+
+ /* If this block has a cleanup, it belongs in stack_block_stack. */
+ stack_block_stack = thisblock;
+ return 1;
+}
+
+/* Arrange for the top element of the dynamic handler chain to be
+ popped if we exit the current binding contour. DECL is the
+ associated declaration, if any, otherwise NULL_TREE. If the current
+ contour is left via an exception, then __sjthrow will pop the top
+ element off the dynamic handler chain. The code that avoids doing
+ the action we push into the handler chain in the exceptional case
+ is contained in expand_cleanups.
+
+ This routine is only used by expand_eh_region_start, and that is
+ the only way in which an exception region should be started. This
+ routine is only used when using the setjmp/longjmp codegen method
+ for exception handling. */
int
-expand_decl_cleanup (decl, cleanup)
- tree decl, cleanup;
+expand_dhc_cleanup (decl)
+ tree decl;
{
struct nesting *thisblock = block_stack;
+ tree cleanup;
/* Error if we are not in any block. */
if (thisblock == 0)
return 0;
- /* Record the cleanup if there is one. */
+ /* Record the cleanup for the dynamic handler chain. */
- if (cleanup != 0)
- {
- thisblock->data.block.cleanups
- = temp_tree_cons (decl, cleanup, thisblock->data.block.cleanups);
- /* If this block has a cleanup, it belongs in stack_block_stack. */
- stack_block_stack = thisblock;
- (*interim_eh_hook) (NULL_TREE);
- }
+ /* All cleanups must be on the function_obstack. */
+ push_obstacks_nochange ();
+ resume_temporary_allocation ();
+ cleanup = make_node (POPDHC_EXPR);
+ pop_obstacks ();
+
+ /* Add the cleanup in a manner similar to expand_decl_cleanup. */
+ thisblock->data.block.cleanups
+ = temp_tree_cons (decl, cleanup, thisblock->data.block.cleanups);
+
+ /* If this block has a cleanup, it belongs in stack_block_stack. */
+ stack_block_stack = thisblock;
return 1;
}
@@ -3755,7 +3662,7 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
DECL_RTL (decl_elt) = x;
else
{
- DECL_RTL (decl_elt) = gen_rtx (MEM, mode, copy_rtx (XEXP (x, 0)));
+ DECL_RTL (decl_elt) = gen_rtx_MEM (mode, copy_rtx (XEXP (x, 0)));
MEM_IN_STRUCT_P (DECL_RTL (decl_elt)) = MEM_IN_STRUCT_P (x);
RTX_UNCHANGING_P (DECL_RTL (decl_elt)) = RTX_UNCHANGING_P (x);
}
@@ -3765,7 +3672,7 @@ expand_anon_union_decl (decl, cleanup, decl_elts)
if (mode == GET_MODE (x))
DECL_RTL (decl_elt) = x;
else
- DECL_RTL (decl_elt) = gen_rtx (SUBREG, mode, x, 0);
+ DECL_RTL (decl_elt) = gen_rtx_SUBREG (mode, x, 0);
}
else
abort ();
@@ -3811,7 +3718,19 @@ expand_cleanups (list, dont_do, in_fixup, reachable)
else
{
if (! in_fixup)
- (*interim_eh_hook) (TREE_VALUE (tail));
+ {
+ tree cleanup = TREE_VALUE (tail);
+
+ /* See expand_d{h,c}c_cleanup for why we avoid this. */
+ if (TREE_CODE (cleanup) != POPDHC_EXPR
+ && TREE_CODE (cleanup) != POPDCC_EXPR
+ /* See expand_eh_region_start_tree for this case. */
+ && ! TREE_ADDRESSABLE (tail))
+ {
+ cleanup = protect_with_terminate (cleanup);
+ expand_eh_region_end (cleanup);
+ }
+ }
if (reachable)
{
@@ -3823,13 +3742,51 @@ expand_cleanups (list, dont_do, in_fixup, reachable)
the target. Though the cleanups are expanded multiple
times, the control paths are non-overlapping so the
cleanups will not be executed twice. */
+
+ /* We may need to protect fixups with rethrow regions. */
+ int protect = (in_fixup && ! TREE_ADDRESSABLE (tail));
+
+ if (protect)
+ expand_fixup_region_start ();
+
expand_expr (TREE_VALUE (tail), const0_rtx, VOIDmode, 0);
+ if (protect)
+ expand_fixup_region_end (TREE_VALUE (tail));
free_temp_slots ();
}
}
}
}
+/* Mark when the context we are emitting RTL for as a conditional
+ context, so that any cleanup actions we register with
+ expand_decl_init will be properly conditionalized when those
+ cleanup actions are later performed. Must be called before any
+ expression (tree) is expanded that is within a conditional context. */
+
+void
+start_cleanup_deferral ()
+{
+ /* block_stack can be NULL if we are inside the parameter list. It is
+ OK to do nothing, because cleanups aren't possible here. */
+ if (block_stack)
+ ++block_stack->data.block.conditional_code;
+}
+
+/* Mark the end of a conditional region of code. Because cleanup
+ deferrals may be nested, we may still be in a conditional region
+ after we end the currently deferred cleanups, only after we end all
+ deferred cleanups, are we back in unconditional code. */
+
+void
+end_cleanup_deferral ()
+{
+ /* block_stack can be NULL if we are inside the parameter list. It is
+ OK to do nothing, because cleanups aren't possible here. */
+ if (block_stack)
+ --block_stack->data.block.conditional_code;
+}
+
/* Move all cleanups from the current block_stack
to the containing block_stack, where they are assumed to
have been created. If anything can cause a temporary to
@@ -3873,11 +3830,7 @@ any_pending_cleanups (this_contour)
if (this_contour && block_stack->data.block.cleanups != NULL)
return 1;
if (block_stack->data.block.cleanups == 0
- && (block_stack->data.block.outer_cleanups == 0
-#if 0
- || block_stack->data.block.outer_cleanups == empty_cleanup_list
-#endif
- ))
+ && block_stack->data.block.outer_cleanups == 0)
return 0;
for (block = block_stack->next; block; block = block->next)
@@ -3920,16 +3873,10 @@ expand_start_case (exit_flag, expr, type, printname)
thiscase->data.case_stmt.default_label = 0;
thiscase->data.case_stmt.num_ranges = 0;
thiscase->data.case_stmt.printname = printname;
- thiscase->data.case_stmt.seenlabel = 0;
+ thiscase->data.case_stmt.line_number_status = force_line_numbers ();
case_stack = thiscase;
nesting_stack = thiscase;
- if (output_bytecode)
- {
- bc_expand_start_case (thiscase, expr, type, printname);
- return;
- }
-
do_pending_stack_adjust ();
/* Make sure case_stmt.start points to something that won't
@@ -3938,32 +3885,8 @@ expand_start_case (exit_flag, expr, type, printname)
emit_note (NULL_PTR, NOTE_INSN_DELETED);
thiscase->data.case_stmt.start = get_last_insn ();
-}
-
-/* Enter a case statement. It is assumed that the caller has pushed
- the current context onto the case stack. */
-
-static void
-bc_expand_start_case (thiscase, expr, type, printname)
- struct nesting *thiscase;
- tree expr;
- tree type;
- char *printname;
-{
- bc_expand_expr (expr);
- bc_expand_conversion (TREE_TYPE (expr), type);
-
- /* For cases, the skip is a place we jump to that's emitted after
- the size of the jump table is known. */
-
- thiscase->data.case_stmt.skip_label = gen_label_rtx ();
- bc_emit_bytecode (jump);
- bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscase->data.case_stmt.skip_label));
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
+ start_cleanup_deferral ();
}
@@ -3990,6 +3913,7 @@ expand_start_case_dummy ()
thiscase->data.case_stmt.num_ranges = 0;
case_stack = thiscase;
nesting_stack = thiscase;
+ start_cleanup_deferral ();
}
/* End a dummy case statement. */
@@ -3997,6 +3921,7 @@ expand_start_case_dummy ()
void
expand_end_case_dummy ()
{
+ end_cleanup_deferral ();
POPSTACK (case_stack);
}
@@ -4011,6 +3936,43 @@ case_index_expr_type ()
return 0;
}
+static void
+check_seenlabel ()
+{
+ /* If this is the first label, warn if any insns have been emitted. */
+ if (case_stack->data.case_stmt.line_number_status >= 0)
+ {
+ rtx insn;
+
+ restore_line_number_status
+ (case_stack->data.case_stmt.line_number_status);
+ case_stack->data.case_stmt.line_number_status = -1;
+
+ for (insn = case_stack->data.case_stmt.start;
+ insn;
+ insn = NEXT_INSN (insn))
+ {
+ if (GET_CODE (insn) == CODE_LABEL)
+ break;
+ if (GET_CODE (insn) != NOTE
+ && (GET_CODE (insn) != INSN || GET_CODE (PATTERN (insn)) != USE))
+ {
+ do
+ insn = PREV_INSN (insn);
+ while (insn && (GET_CODE (insn) != NOTE || NOTE_LINE_NUMBER (insn) < 0));
+
+ /* If insn is zero, then there must have been a syntax error. */
+ if (insn)
+ warning_with_file_and_line (NOTE_SOURCE_FILE(insn),
+ NOTE_LINE_NUMBER(insn),
+ "unreachable code at beginning of %s",
+ case_stack->data.case_stmt.printname);
+ break;
+ }
+ }
+ }
+}
+
/* Accumulate one case or default label inside a case or switch statement.
VALUE is the value of the case (a null pointer, for a default label).
The function CONVERTER, when applied to arguments T and V,
@@ -4021,7 +3983,7 @@ case_index_expr_type ()
If VALUE is a duplicate or overlaps, return 2 and do nothing
except store the (first) duplicate node in *DUPLICATE.
If VALUE is out of range, return 3 and do nothing.
- If we are jumping into the scope of a cleaup or var-sized array, return 5.
+ If we are jumping into the scope of a cleanup or var-sized array, return 5.
Return 0 on success.
Extended to handle range statements. */
@@ -4033,14 +3995,9 @@ pushcase (value, converter, label, duplicate)
register tree label;
tree *duplicate;
{
- register struct case_node **l;
- register struct case_node *n;
tree index_type;
tree nominal_type;
- if (output_bytecode)
- return bc_pushcase (value, label);
-
/* Fail if not inside a real case statement. */
if (! (case_stack && case_stack->data.case_stmt.start))
return 1;
@@ -4060,26 +4017,7 @@ pushcase (value, converter, label, duplicate)
if (value != 0)
value = (*converter) (nominal_type, value);
- /* If this is the first label, warn if any insns have been emitted. */
- if (case_stack->data.case_stmt.seenlabel == 0)
- {
- rtx insn;
- for (insn = case_stack->data.case_stmt.start;
- insn;
- insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == CODE_LABEL)
- break;
- if (GET_CODE (insn) != NOTE
- && (GET_CODE (insn) != INSN || GET_CODE (PATTERN (insn)) != USE))
- {
- warning ("unreachable code at beginning of %s",
- case_stack->data.case_stmt.printname);
- break;
- }
- }
- }
- case_stack->data.case_stmt.seenlabel = 1;
+ check_seenlabel ();
/* Fail if this value is out of range for the actual type of the index
(which may be narrower than NOMINAL_TYPE). */
@@ -4097,46 +4035,20 @@ pushcase (value, converter, label, duplicate)
case_stack->data.case_stmt.default_label = label;
}
else
- {
- /* Find the elt in the chain before which to insert the new value,
- to keep the chain sorted in increasing order.
- But report an error if this element is a duplicate. */
- for (l = &case_stack->data.case_stmt.case_list;
- /* Keep going past elements distinctly less than VALUE. */
- *l != 0 && tree_int_cst_lt ((*l)->high, value);
- l = &(*l)->right)
- ;
- if (*l)
- {
- /* Element we will insert before must be distinctly greater;
- overlap means error. */
- if (! tree_int_cst_lt (value, (*l)->low))
- {
- *duplicate = (*l)->code_label;
- return 2;
- }
- }
-
- /* Add this label to the chain, and succeed.
- Copy VALUE so it is on temporary rather than momentary
- obstack and will thus survive till the end of the case statement. */
- n = (struct case_node *) oballoc (sizeof (struct case_node));
- n->left = 0;
- n->right = *l;
- n->high = n->low = copy_node (value);
- n->code_label = label;
- *l = n;
- }
+ return add_case_node (value, value, label, duplicate);
expand_label (label);
return 0;
}
-/* Like pushcase but this case applies to all values
- between VALUE1 and VALUE2 (inclusive).
- The return value is the same as that of pushcase
- but there is one additional error code:
- 4 means the specified range was empty. */
+/* Like pushcase but this case applies to all values between VALUE1 and
+ VALUE2 (inclusive). If VALUE1 is NULL, the range starts at the lowest
+ value of the index type and ends at VALUE2. If VALUE2 is NULL, the range
+ starts at VALUE1 and ends at the highest value of the index type.
+ If both are NULL, this case applies to all values.
+
+ The return value is the same as that of pushcase but there is one
+ additional error code: 4 means the specified range was empty. */
int
pushcase_range (value1, value2, converter, label, duplicate)
@@ -4145,8 +4057,6 @@ pushcase_range (value1, value2, converter, label, duplicate)
register tree label;
tree *duplicate;
{
- register struct case_node **l;
- register struct case_node *n;
tree index_type;
tree nominal_type;
@@ -4165,144 +4075,271 @@ pushcase_range (value1, value2, converter, label, duplicate)
if (index_type == error_mark_node)
return 0;
- /* If this is the first label, warn if any insns have been emitted. */
- if (case_stack->data.case_stmt.seenlabel == 0)
- {
- rtx insn;
- for (insn = case_stack->data.case_stmt.start;
- insn;
- insn = NEXT_INSN (insn))
- {
- if (GET_CODE (insn) == CODE_LABEL)
- break;
- if (GET_CODE (insn) != NOTE
- && (GET_CODE (insn) != INSN || GET_CODE (PATTERN (insn)) != USE))
- {
- warning ("unreachable code at beginning of %s",
- case_stack->data.case_stmt.printname);
- break;
- }
- }
- }
- case_stack->data.case_stmt.seenlabel = 1;
+ check_seenlabel ();
+
+ /* Convert VALUEs to type in which the comparisons are nominally done
+ and replace any unspecified value with the corresponding bound. */
+ if (value1 == 0)
+ value1 = TYPE_MIN_VALUE (index_type);
+ if (value2 == 0)
+ value2 = TYPE_MAX_VALUE (index_type);
+
+ /* Fail if the range is empty. Do this before any conversion since
+ we want to allow out-of-range empty ranges. */
+ if (value2 && tree_int_cst_lt (value2, value1))
+ return 4;
- /* Convert VALUEs to type in which the comparisons are nominally done. */
- if (value1 == 0) /* Negative infinity. */
- value1 = TYPE_MIN_VALUE(index_type);
value1 = (*converter) (nominal_type, value1);
- if (value2 == 0) /* Positive infinity. */
- value2 = TYPE_MAX_VALUE(index_type);
+ /* If the max was unbounded, use the max of the nominal_type we are
+ converting to. Do this after the < check above to suppress false
+ positives. */
+ if (!value2)
+ value2 = TYPE_MAX_VALUE (nominal_type);
value2 = (*converter) (nominal_type, value2);
/* Fail if these values are out of range. */
- if (! int_fits_type_p (value1, index_type))
+ if (TREE_CONSTANT_OVERFLOW (value1)
+ || ! int_fits_type_p (value1, index_type))
return 3;
- if (! int_fits_type_p (value2, index_type))
+ if (TREE_CONSTANT_OVERFLOW (value2)
+ || ! int_fits_type_p (value2, index_type))
return 3;
- /* Fail if the range is empty. */
- if (tree_int_cst_lt (value2, value1))
- return 4;
+ return add_case_node (value1, value2, label, duplicate);
+}
- /* If the bounds are equal, turn this into the one-value case. */
- if (tree_int_cst_equal (value1, value2))
- return pushcase (value1, converter, label, duplicate);
-
- /* Find the elt in the chain before which to insert the new value,
- to keep the chain sorted in increasing order.
- But report an error if this element is a duplicate. */
- for (l = &case_stack->data.case_stmt.case_list;
- /* Keep going past elements distinctly less than this range. */
- *l != 0 && tree_int_cst_lt ((*l)->high, value1);
- l = &(*l)->right)
- ;
- if (*l)
+/* Do the actual insertion of a case label for pushcase and pushcase_range
+ into case_stack->data.case_stmt.case_list. Use an AVL tree to avoid
+ slowdown for large switch statements. */
+
+static int
+add_case_node (low, high, label, duplicate)
+ tree low, high;
+ tree label;
+ tree *duplicate;
+{
+ struct case_node *p, **q, *r;
+
+ q = &case_stack->data.case_stmt.case_list;
+ p = *q;
+
+ while ((r = *q))
{
- /* Element we will insert before must be distinctly greater;
- overlap means error. */
- if (! tree_int_cst_lt (value2, (*l)->low))
+ p = r;
+
+ /* Keep going past elements distinctly greater than HIGH. */
+ if (tree_int_cst_lt (high, p->low))
+ q = &p->left;
+
+ /* or distinctly less than LOW. */
+ else if (tree_int_cst_lt (p->high, low))
+ q = &p->right;
+
+ else
{
- *duplicate = (*l)->code_label;
+ /* We have an overlap; this is an error. */
+ *duplicate = p->code_label;
return 2;
}
}
/* Add this label to the chain, and succeed.
- Copy VALUE1, VALUE2 so they are on temporary rather than momentary
+ Copy LOW, HIGH so they are on temporary rather than momentary
obstack and will thus survive till the end of the case statement. */
- n = (struct case_node *) oballoc (sizeof (struct case_node));
- n->left = 0;
- n->right = *l;
- n->low = copy_node (value1);
- n->high = copy_node (value2);
- n->code_label = label;
- *l = n;
+ r = (struct case_node *) oballoc (sizeof (struct case_node));
+ r->low = copy_node (low);
+
+ /* If the bounds are equal, turn this into the one-value case. */
+ if (tree_int_cst_equal (low, high))
+ r->high = r->low;
+ else
+ {
+ r->high = copy_node (high);
+ case_stack->data.case_stmt.num_ranges++;
+ }
+
+ r->code_label = label;
expand_label (label);
- case_stack->data.case_stmt.num_ranges++;
+ *q = r;
+ r->parent = p;
+ r->left = 0;
+ r->right = 0;
+ r->balance = 0;
- return 0;
-}
+ while (p)
+ {
+ struct case_node *s;
+ if (r == p->left)
+ {
+ int b;
-/* Accumulate one case or default label; VALUE is the value of the
- case, or nil for a default label. If not currently inside a case,
- return 1 and do nothing. If VALUE is a duplicate or overlaps, return
- 2 and do nothing. If VALUE is out of range, return 3 and do nothing.
- Return 0 on success. This function is a leftover from the earlier
- bytecode compiler, which was based on gcc 1.37. It should be
- merged into pushcase. */
+ if (! (b = p->balance))
+ /* Growth propagation from left side. */
+ p->balance = -1;
+ else if (b < 0)
+ {
+ if (r->balance < 0)
+ {
+ /* R-Rotation */
+ if ((p->left = s = r->right))
+ s->parent = p;
-static int
-bc_pushcase (value, label)
- tree value;
- tree label;
-{
- struct nesting *thiscase = case_stack;
- struct case_node *case_label, *new_label;
+ r->right = p;
+ p->balance = 0;
+ r->balance = 0;
+ s = p->parent;
+ p->parent = r;
- if (! thiscase)
- return 1;
+ if ((r->parent = s))
+ {
+ if (s->left == p)
+ s->left = r;
+ else
+ s->right = r;
+ }
+ else
+ case_stack->data.case_stmt.case_list = r;
+ }
+ else
+ /* r->balance == +1 */
+ {
+ /* LR-Rotation */
+
+ int b2;
+ struct case_node *t = r->right;
+
+ if ((p->left = s = t->right))
+ s->parent = p;
+
+ t->right = p;
+ if ((r->right = s = t->left))
+ s->parent = r;
+
+ t->left = r;
+ b = t->balance;
+ b2 = b < 0;
+ p->balance = b2;
+ b2 = -b2 - b;
+ r->balance = b2;
+ t->balance = 0;
+ s = p->parent;
+ p->parent = t;
+ r->parent = t;
+
+ if ((t->parent = s))
+ {
+ if (s->left == p)
+ s->left = t;
+ else
+ s->right = t;
+ }
+ else
+ case_stack->data.case_stmt.case_list = t;
+ }
+ break;
+ }
- /* Fail if duplicate, overlap, or out of type range. */
- if (value)
- {
- value = convert (thiscase->data.case_stmt.nominal_type, value);
- if (! int_fits_type_p (value, thiscase->data.case_stmt.nominal_type))
- return 3;
-
- for (case_label = thiscase->data.case_stmt.case_list;
- case_label->left; case_label = case_label->left)
- if (! tree_int_cst_lt (case_label->left->high, value))
- break;
-
- if (case_label != thiscase->data.case_stmt.case_list
- && ! tree_int_cst_lt (case_label->high, value)
- || case_label->left && ! tree_int_cst_lt (value, case_label->left->low))
- return 2;
-
- new_label = (struct case_node *) oballoc (sizeof (struct case_node));
- new_label->low = new_label->high = copy_node (value);
- new_label->code_label = label;
- new_label->left = case_label->left;
-
- case_label->left = new_label;
- thiscase->data.case_stmt.num_ranges++;
- }
- else
- {
- if (thiscase->data.case_stmt.default_label)
- return 2;
- thiscase->data.case_stmt.default_label = label;
+ else
+ {
+ /* p->balance == +1; growth of left side balances the node. */
+ p->balance = 0;
+ break;
+ }
+ }
+ else
+ /* r == p->right */
+ {
+ int b;
+
+ if (! (b = p->balance))
+ /* Growth propagation from right side. */
+ p->balance++;
+ else if (b > 0)
+ {
+ if (r->balance > 0)
+ {
+ /* L-Rotation */
+
+ if ((p->right = s = r->left))
+ s->parent = p;
+
+ r->left = p;
+ p->balance = 0;
+ r->balance = 0;
+ s = p->parent;
+ p->parent = r;
+ if ((r->parent = s))
+ {
+ if (s->left == p)
+ s->left = r;
+ else
+ s->right = r;
+ }
+
+ else
+ case_stack->data.case_stmt.case_list = r;
+ }
+
+ else
+ /* r->balance == -1 */
+ {
+ /* RL-Rotation */
+ int b2;
+ struct case_node *t = r->left;
+
+ if ((p->right = s = t->left))
+ s->parent = p;
+
+ t->left = p;
+
+ if ((r->left = s = t->right))
+ s->parent = r;
+
+ t->right = r;
+ b = t->balance;
+ b2 = b < 0;
+ r->balance = b2;
+ b2 = -b2 - b;
+ p->balance = b2;
+ t->balance = 0;
+ s = p->parent;
+ p->parent = t;
+ r->parent = t;
+
+ if ((t->parent = s))
+ {
+ if (s->left == p)
+ s->left = t;
+ else
+ s->right = t;
+ }
+
+ else
+ case_stack->data.case_stmt.case_list = t;
+ }
+ break;
+ }
+ else
+ {
+ /* p->balance == -1; growth of right side balances the node. */
+ p->balance = 0;
+ break;
+ }
+ }
+
+ r = p;
+ p = p->parent;
}
- expand_label (label);
return 0;
}
+
/* Returns the number of possible values of TYPE.
Returns -1 if the number is unknown or variable.
@@ -4317,7 +4354,7 @@ all_cases_count (type, spareness)
tree type;
int *spareness;
{
- HOST_WIDE_INT count, count_high = 0;
+ HOST_WIDE_INT count;
*spareness = 0;
switch (TREE_CODE (type))
@@ -4332,6 +4369,7 @@ all_cases_count (type, spareness)
default:
case INTEGER_TYPE:
if (TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
+ || TYPE_MAX_VALUE (type) == NULL
|| TREE_CODE (TYPE_MAX_VALUE (type)) != INTEGER_CST)
return -1;
else
@@ -4339,7 +4377,7 @@ all_cases_count (type, spareness)
/* count
= TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))
- TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + 1
- but with overflow checking. */
+ but with overflow checking. */
tree mint = TYPE_MIN_VALUE (type);
tree maxt = TYPE_MAX_VALUE (type);
HOST_WIDE_INT lo, hi;
@@ -4384,11 +4422,11 @@ all_cases_count (type, spareness)
#define BITARRAY_TEST(ARRAY, INDEX) \
- ((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
- & (1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR)))
+ ((ARRAY)[(unsigned) (INDEX) / HOST_BITS_PER_CHAR]\
+ & (1 << ((unsigned) (INDEX) % HOST_BITS_PER_CHAR)))
#define BITARRAY_SET(ARRAY, INDEX) \
- ((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
- |= 1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR))
+ ((ARRAY)[(unsigned) (INDEX) / HOST_BITS_PER_CHAR]\
+ |= 1 << ((unsigned) (INDEX) % HOST_BITS_PER_CHAR))
/* Set the elements of the bitstring CASES_SEEN (which has length COUNT),
with the case values we have seen, assuming the case expression
@@ -4405,41 +4443,65 @@ mark_seen_cases (type, cases_seen, count, sparseness)
long count;
int sparseness;
{
- long i;
-
tree next_node_to_try = NULL_TREE;
long next_node_offset = 0;
- register struct case_node *n;
+ register struct case_node *n, *root = case_stack->data.case_stmt.case_list;
tree val = make_node (INTEGER_CST);
TREE_TYPE (val) = type;
- for (n = case_stack->data.case_stmt.case_list; n;
- n = n->right)
+ if (! root)
+ ; /* Do nothing */
+ else if (sparseness == 2)
{
- TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (n->low);
- TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (n->low);
- while ( ! tree_int_cst_lt (n->high, val))
+ tree t;
+ HOST_WIDE_INT xlo;
+
+ /* This less efficient loop is only needed to handle
+ duplicate case values (multiple enum constants
+ with the same value). */
+ TREE_TYPE (val) = TREE_TYPE (root->low);
+ for (t = TYPE_VALUES (type), xlo = 0; t != NULL_TREE;
+ t = TREE_CHAIN (t), xlo++)
{
- /* Calculate (into xlo) the "offset" of the integer (val).
- The element with lowest value has offset 0, the next smallest
- element has offset 1, etc. */
-
- HOST_WIDE_INT xlo, xhi;
- tree t;
- if (sparseness == 2)
+ TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (TREE_VALUE (t));
+ TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (TREE_VALUE (t));
+ n = root;
+ do
{
- /* This less efficient loop is only needed to handle
- duplicate case values (multiple enum constants
- with the same value). */
- for (t = TYPE_VALUES (type), xlo = 0; t != NULL_TREE;
- t = TREE_CHAIN (t), xlo++)
+ /* Keep going past elements distinctly greater than VAL. */
+ if (tree_int_cst_lt (val, n->low))
+ n = n->left;
+
+ /* or distinctly less than VAL. */
+ else if (tree_int_cst_lt (n->high, val))
+ n = n->right;
+
+ else
{
- if (tree_int_cst_equal (val, TREE_VALUE (t)))
- BITARRAY_SET (cases_seen, xlo);
+ /* We have found a matching range. */
+ BITARRAY_SET (cases_seen, xlo);
+ break;
}
}
- else
+ while (n);
+ }
+ }
+ else
+ {
+ if (root->left)
+ case_stack->data.case_stmt.case_list = root = case_tree2list (root, 0);
+ for (n = root; n; n = n->right)
+ {
+ TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (n->low);
+ TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (n->low);
+ while ( ! tree_int_cst_lt (n->high, val))
{
+ /* Calculate (into xlo) the "offset" of the integer (val).
+ The element with lowest value has offset 0, the next smallest
+ element has offset 1, etc. */
+
+ HOST_WIDE_INT xlo, xhi;
+ tree t;
if (sparseness && TYPE_VALUES (type) != NULL_TREE)
{
/* The TYPE_VALUES will be in increasing order, so
@@ -4463,7 +4525,10 @@ mark_seen_cases (type, cases_seen, count, sparseness)
xlo++;
t = TREE_CHAIN (t);
if (t == next_node_to_try)
- break;
+ {
+ xlo = -1;
+ break;
+ }
}
}
else
@@ -4481,10 +4546,10 @@ mark_seen_cases (type, cases_seen, count, sparseness)
if (xhi == 0 && xlo >= 0 && xlo < count)
BITARRAY_SET (cases_seen, xlo);
+ add_double (TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
+ 1, 0,
+ &TREE_INT_CST_LOW (val), &TREE_INT_CST_HIGH (val));
}
- add_double (TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
- 1, 0,
- &TREE_INT_CST_LOW (val), &TREE_INT_CST_HIGH (val));
}
}
}
@@ -4505,29 +4570,24 @@ check_for_full_enumeration_handling (type)
tree type;
{
register struct case_node *n;
- register struct case_node **l;
register tree chain;
+#if 0 /* variable used by 'if 0'ed code below. */
+ register struct case_node **l;
int all_values = 1;
+#endif
- /* True iff the selector type is a numbered set mode. */
+ /* True iff the selector type is a numbered set mode. */
int sparseness = 0;
- /* The number of possible selector values. */
+ /* The number of possible selector values. */
HOST_WIDE_INT size;
/* For each possible selector value. a one iff it has been matched
- by a case value alternative. */
+ by a case value alternative. */
unsigned char *cases_seen;
- /* The allocated size of cases_seen, in chars. */
+ /* The allocated size of cases_seen, in chars. */
long bytes_needed;
- tree t;
-
- if (output_bytecode)
- {
- bc_check_for_full_enumeration_handling (type);
- return;
- }
if (! warn_switch)
return;
@@ -4536,7 +4596,7 @@ check_for_full_enumeration_handling (type)
bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
if (size > 0 && size < 600000
- /* We deliberately use malloc here - not xmalloc. */
+ /* We deliberately use malloc here - not xmalloc. */
&& (cases_seen = (unsigned char *) malloc (bytes_needed)) != NULL)
{
long i;
@@ -4546,7 +4606,7 @@ check_for_full_enumeration_handling (type)
/* The time complexity of this code is normally O(N), where
N being the number of members in the enumerated type.
However, if type is a ENUMERAL_TYPE whose values do not
- increase monotonically, quadratic time may be needed. */
+ increase monotonically, O(N*log(N)) time may be needed. */
mark_seen_cases (type, cases_seen, size, sparseness);
@@ -4563,8 +4623,12 @@ check_for_full_enumeration_handling (type)
/* Now we go the other way around; we warn if there are case
expressions that don't correspond to enumerators. This can
occur since C and C++ don't enforce type-checking of
- assignments to enumeration variables. */
+ assignments to enumeration variables. */
+ if (case_stack->data.case_stmt.case_list
+ && case_stack->data.case_stmt.case_list->left)
+ case_stack->data.case_stmt.case_list
+ = case_tree2list (case_stack->data.case_stmt.case_list, 0);
if (warn_switch)
for (n = case_stack->data.case_stmt.case_list; n; n = n->right)
{
@@ -4576,11 +4640,11 @@ check_for_full_enumeration_handling (type)
if (!chain)
{
if (TYPE_NAME (type) == 0)
- warning ("case value `%d' not in enumerated type",
- TREE_INT_CST_LOW (n->low));
+ warning ("case value `%ld' not in enumerated type",
+ (long) TREE_INT_CST_LOW (n->low));
else
- warning ("case value `%d' not in enumerated type `%s'",
- TREE_INT_CST_LOW (n->low),
+ warning ("case value `%ld' not in enumerated type `%s'",
+ (long) TREE_INT_CST_LOW (n->low),
IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
== IDENTIFIER_NODE)
? TYPE_NAME (type)
@@ -4596,11 +4660,11 @@ check_for_full_enumeration_handling (type)
if (!chain)
{
if (TYPE_NAME (type) == 0)
- warning ("case value `%d' not in enumerated type",
- TREE_INT_CST_LOW (n->high));
+ warning ("case value `%ld' not in enumerated type",
+ (long) TREE_INT_CST_LOW (n->high));
else
- warning ("case value `%d' not in enumerated type `%s'",
- TREE_INT_CST_LOW (n->high),
+ warning ("case value `%ld' not in enumerated type `%s'",
+ (long) TREE_INT_CST_LOW (n->high),
IDENTIFIER_POINTER ((TREE_CODE (TYPE_NAME (type))
== IDENTIFIER_NODE)
? TYPE_NAME (type)
@@ -4632,46 +4696,6 @@ check_for_full_enumeration_handling (type)
#endif /* 0 */
}
-
-/* Check that all enumeration literals are covered by the case
- expressions of a switch. Also warn if there are any cases
- that are not elements of the enumerated type. */
-
-static void
-bc_check_for_full_enumeration_handling (type)
- tree type;
-{
- struct nesting *thiscase = case_stack;
- struct case_node *c;
- tree e;
-
- /* Check for enums not handled. */
- for (e = TYPE_VALUES (type); e; e = TREE_CHAIN (e))
- {
- for (c = thiscase->data.case_stmt.case_list->left;
- c && tree_int_cst_lt (c->high, TREE_VALUE (e));
- c = c->left)
- ;
- if (! (c && tree_int_cst_equal (c->low, TREE_VALUE (e))))
- warning ("enumerated value `%s' not handled in switch",
- IDENTIFIER_POINTER (TREE_PURPOSE (e)));
- }
-
- /* Check for cases not in the enumeration. */
- for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
- {
- for (e = TYPE_VALUES (type);
- e && !tree_int_cst_equal (c->low, TREE_VALUE (e));
- e = TREE_CHAIN (e))
- ;
- if (! e)
- warning ("case value `%d' not in enumerated type `%s'",
- TREE_INT_CST_LOW (c->low),
- IDENTIFIER_POINTER (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE
- ? TYPE_NAME (type)
- : DECL_NAME (TYPE_NAME (type))));
- }
-}
/* Terminate a case (Pascal) or switch (C) statement
in which ORIG_INDEX is the expression to be tested.
@@ -4684,7 +4708,7 @@ expand_end_case (orig_index)
tree minval, maxval, range, orig_minval;
rtx default_label = 0;
register struct case_node *n;
- int count;
+ unsigned int count;
rtx index;
rtx table_label;
int ncases;
@@ -4695,12 +4719,6 @@ expand_end_case (orig_index)
tree index_expr, index_type;
int unsignedp;
- if (output_bytecode)
- {
- bc_expand_end_case (orig_index);
- return;
- }
-
table_label = gen_label_rtx ();
index_expr = thiscase->data.case_stmt.index_expr;
index_type = TREE_TYPE (index_expr);
@@ -4708,6 +4726,15 @@ expand_end_case (orig_index)
do_pending_stack_adjust ();
+ /* This might get an spurious warning in the presence of a syntax error;
+ it could be fixed by moving the call to check_seenlabel after the
+ check for error_mark_node, and copying the code of check_seenlabel that
+ deals with case_stack->data.case_stmt.line_number_status /
+ restore_line_number_status in front of the call to end_cleanup_deferral;
+ However, this might miss some useful warnings in the presence of
+ non-syntax errors. */
+ check_seenlabel ();
+
/* An ERROR_MARK occurs for various reasons including invalid data type. */
if (index_type != error_mark_node)
{
@@ -4720,22 +4747,6 @@ expand_end_case (orig_index)
&& TREE_CODE (index_expr) != INTEGER_CST)
check_for_full_enumeration_handling (TREE_TYPE (orig_index));
- /* If this is the first label, warn if any insns have been emitted. */
- if (thiscase->data.case_stmt.seenlabel == 0)
- {
- rtx insn;
- for (insn = get_last_insn ();
- insn != case_stack->data.case_stmt.start;
- insn = PREV_INSN (insn))
- if (GET_CODE (insn) != NOTE
- && (GET_CODE (insn) != INSN || GET_CODE (PATTERN (insn))!= USE))
- {
- warning ("unreachable code at beginning of %s",
- case_stack->data.case_stmt.printname);
- break;
- }
- }
-
/* If we don't have a default-label, create one here,
after the body of the switch. */
if (thiscase->data.case_stmt.default_label == 0)
@@ -4748,6 +4759,11 @@ expand_end_case (orig_index)
before_case = get_last_insn ();
+ if (thiscase->data.case_stmt.case_list
+ && thiscase->data.case_stmt.case_list->left)
+ thiscase->data.case_stmt.case_list
+ = case_tree2list(thiscase->data.case_stmt.case_list, 0);
+
/* Simplify the case-list before we count it. */
group_case_nodes (thiscase->data.case_stmt.case_list);
@@ -4791,6 +4807,8 @@ expand_end_case (orig_index)
if (count != 0)
range = fold (build (MINUS_EXPR, index_type, maxval, minval));
+ end_cleanup_deferral ();
+
if (count == 0)
{
expand_expr (index_expr, const0_rtx, VOIDmode, 0);
@@ -4818,6 +4836,9 @@ expand_end_case (orig_index)
|| count < CASE_VALUES_THRESHOLD
|| ((unsigned HOST_WIDE_INT) (TREE_INT_CST_LOW (range))
> 10 * count)
+#ifndef ASM_OUTPUT_ADDR_DIFF_ELT
+ || flag_pic
+#endif
|| TREE_CODE (index_expr) == INTEGER_CST
/* These will reduce to a constant. */
|| (TREE_CODE (index_expr) == CALL_EXPR
@@ -5011,7 +5032,7 @@ expand_end_case (orig_index)
while (1)
{
labelvec[i]
- = gen_rtx (LABEL_REF, Pmode, label_rtx (n->code_label));
+ = gen_rtx_LABEL_REF (Pmode, label_rtx (n->code_label));
if (i + TREE_INT_CST_LOW (orig_minval)
== TREE_INT_CST_LOW (n->high))
break;
@@ -5022,24 +5043,19 @@ expand_end_case (orig_index)
/* Fill in the gaps with the default. */
for (i = 0; i < ncases; i++)
if (labelvec[i] == 0)
- labelvec[i] = gen_rtx (LABEL_REF, Pmode, default_label);
+ labelvec[i] = gen_rtx_LABEL_REF (Pmode, default_label);
/* Output the table */
emit_label (table_label);
- /* This would be a lot nicer if CASE_VECTOR_PC_RELATIVE
- were an expression, instead of an #ifdef/#ifndef. */
- if (
-#ifdef CASE_VECTOR_PC_RELATIVE
- 1 ||
-#endif
- flag_pic)
- emit_jump_insn (gen_rtx (ADDR_DIFF_VEC, CASE_VECTOR_MODE,
- gen_rtx (LABEL_REF, Pmode, table_label),
- gen_rtvec_v (ncases, labelvec)));
+ if (CASE_VECTOR_PC_RELATIVE || flag_pic)
+ emit_jump_insn (gen_rtx_ADDR_DIFF_VEC (CASE_VECTOR_MODE,
+ gen_rtx_LABEL_REF (Pmode, table_label),
+ gen_rtvec_v (ncases, labelvec),
+ const0_rtx, const0_rtx, 0));
else
- emit_jump_insn (gen_rtx (ADDR_VEC, CASE_VECTOR_MODE,
- gen_rtvec_v (ncases, labelvec)));
+ emit_jump_insn (gen_rtx_ADDR_VEC (CASE_VECTOR_MODE,
+ gen_rtvec_v (ncases, labelvec)));
/* If the case insn drops through the table,
after the table we must jump to the default-label.
@@ -5055,6 +5071,8 @@ expand_end_case (orig_index)
reorder_insns (before_case, get_last_insn (),
thiscase->data.case_stmt.start);
}
+ else
+ end_cleanup_deferral ();
if (thiscase->exit_label)
emit_label (thiscase->exit_label);
@@ -5064,109 +5082,27 @@ expand_end_case (orig_index)
free_temp_slots ();
}
+/* Convert the tree NODE into a list linked by the right field, with the left
+ field zeroed. RIGHT is used for recursion; it is a list to be placed
+ rightmost in the resulting list. */
-/* Terminate a case statement. EXPR is the original index
- expression. */
-
-static void
-bc_expand_end_case (expr)
- tree expr;
+static struct case_node *
+case_tree2list (node, right)
+ struct case_node *node, *right;
{
- struct nesting *thiscase = case_stack;
- enum bytecode_opcode opcode;
- struct bc_label *jump_label;
- struct case_node *c;
-
- bc_emit_bytecode (jump);
- bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscase->exit_label));
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-
- /* Now that the size of the jump table is known, emit the actual
- indexed jump instruction. */
- bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscase->data.case_stmt.skip_label));
-
- opcode = TYPE_MODE (thiscase->data.case_stmt.nominal_type) == SImode
- ? TREE_UNSIGNED (thiscase->data.case_stmt.nominal_type) ? caseSU : caseSI
- : TREE_UNSIGNED (thiscase->data.case_stmt.nominal_type) ? caseDU : caseDI;
-
- bc_emit_bytecode (opcode);
-
- /* Now emit the case instructions literal arguments, in order.
- In addition to the value on the stack, it uses:
- 1. The address of the jump table.
- 2. The size of the jump table.
- 3. The default label. */
-
- jump_label = bc_get_bytecode_label ();
- bc_emit_bytecode_labelref (jump_label);
- bc_emit_bytecode_const ((char *) &thiscase->data.case_stmt.num_ranges,
- sizeof thiscase->data.case_stmt.num_ranges);
-
- if (thiscase->data.case_stmt.default_label)
- bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (DECL_RTL (thiscase->data.case_stmt.default_label)));
- else
- bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (thiscase->exit_label));
-
- /* Output the jump table. */
-
- bc_align_bytecode (3 /* PTR_ALIGN */);
- bc_emit_bytecode_labeldef (jump_label);
-
- if (TYPE_MODE (thiscase->data.case_stmt.nominal_type) == SImode)
- for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
- {
- opcode = TREE_INT_CST_LOW (c->low);
- bc_emit_bytecode_const ((char *) &opcode, sizeof opcode);
-
- opcode = TREE_INT_CST_LOW (c->high);
- bc_emit_bytecode_const ((char *) &opcode, sizeof opcode);
-
- bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (DECL_RTL (c->code_label)));
- }
- else
- if (TYPE_MODE (thiscase->data.case_stmt.nominal_type) == DImode)
- for (c = thiscase->data.case_stmt.case_list->left; c; c = c->left)
- {
- bc_emit_bytecode_DI_const (c->low);
- bc_emit_bytecode_DI_const (c->high);
-
- bc_emit_bytecode_labelref (BYTECODE_BC_LABEL (DECL_RTL (c->code_label)));
- }
- else
- /* Bad mode */
- abort ();
-
-
- bc_emit_bytecode_labeldef (BYTECODE_BC_LABEL (thiscase->exit_label));
-
- /* Possibly issue enumeration warnings. */
-
- if (!thiscase->data.case_stmt.default_label
- && TREE_CODE (TREE_TYPE (expr)) == ENUMERAL_TYPE
- && TREE_CODE (expr) != INTEGER_CST
- && warn_switch)
- check_for_full_enumeration_handling (TREE_TYPE (expr));
-
-
-#ifdef DEBUG_PRINT_CODE
- fputc ('\n', stderr);
-#endif
-
- POPSTACK (case_stack);
-}
+ struct case_node *left;
+ if (node->right)
+ right = case_tree2list (node->right, right);
-/* Return unique bytecode ID. */
-
-int
-bc_new_uid ()
-{
- static int bc_uid = 0;
+ node->right = right;
+ if ((left = node->left))
+ {
+ node->left = 0;
+ return case_tree2list (left, node);
+ }
- return (++bc_uid);
+ return node;
}
/* Generate code to jump to LABEL if OP1 and OP2 are equal. */
@@ -5234,11 +5170,11 @@ estimate_case_costs (node)
for (i = 0; i < 128; i++)
{
- if (isalnum (i))
+ if (ISALNUM (i))
cost_table[i] = 16;
- else if (ispunct (i))
+ else if (ISPUNCT (i))
cost_table[i] = 8;
- else if (iscntrl (i))
+ else if (ISCNTRL (i))
cost_table[i] = -1;
}
@@ -5286,12 +5222,18 @@ group_case_nodes (head)
while (node)
{
rtx lb = next_real_insn (label_rtx (node->code_label));
+ rtx lb2;
case_node_ptr np = node;
/* Try to group the successors of NODE with NODE. */
while (((np = np->right) != 0)
/* Do they jump to the same place? */
- && next_real_insn (label_rtx (np->code_label)) == lb
+ && ((lb2 = next_real_insn (label_rtx (np->code_label))) == lb
+ || (lb != 0 && lb2 != 0
+ && simplejump_p (lb)
+ && simplejump_p (lb2)
+ && rtx_equal_p (SET_SRC (PATTERN (lb)),
+ SET_SRC (PATTERN (lb2)))))
/* Are their ranges consecutive? */
&& tree_int_cst_equal (np->low,
fold (build (PLUS_EXPR,
@@ -5322,7 +5264,7 @@ group_case_nodes (head)
The transformation is performed by splitting the ordered
list into two equal sections plus a pivot. The parts are
then attached to the pivot as left and right branches. Each
- branch is is then transformed recursively. */
+ branch is then transformed recursively. */
static void
balance_case_nodes (head, parent)
@@ -5498,6 +5440,11 @@ node_has_high_bound (node, index_type)
tree high_plus_one;
case_node_ptr pnode;
+ /* If there is no upper bound, obviously no test is needed. */
+
+ if (TYPE_MAX_VALUE (index_type) == NULL)
+ return 1;
+
/* If the upper bound of this node is the highest value in the type
of the index expression, we need not test against it. */
@@ -5566,7 +5513,7 @@ emit_jump_if_reachable (label)
check for bounded nodes. In this case conditional and/or
unconditional jumps as a result of the boundary check for the
current node are arranged to target the subordinates associated
- code for out of bound conditions on the current node node.
+ code for out of bound conditions on the current node.
We can assume that when control reaches the code generated here,
the index value has already been compared with the parents
@@ -5600,7 +5547,7 @@ emit_case_nodes (index, node, default_label, index_type)
else if (tree_int_cst_equal (node->low, node->high))
{
/* Node is single valued. First see if the index expression matches
- this node and then check our children, if any. */
+ this node and then check our children, if any. */
do_jump_if_equal (index, expand_expr (node->low, NULL_RTX, VOIDmode, 0),
label_rtx (node->code_label), unsignedp);
@@ -5857,7 +5804,10 @@ emit_case_nodes (index, node, default_label, index_type)
/* These routines are used by the loop unrolling code. They copy BLOCK trees
so that the debugging info will be correct for the unrolled loop. */
-/* Indexed by block number, contains a pointer to the N'th block node. */
+/* Indexed by block number, contains a pointer to the N'th block node.
+
+ Allocated by the call to identify_blocks, then released after the call
+ to reorder_blocks in the function unroll_block_trees. */
static tree *block_vector;
@@ -5866,10 +5816,6 @@ find_loop_tree_blocks ()
{
tree block = DECL_INITIAL (current_function_decl);
- /* There first block is for the function body, and does not have
- corresponding block notes. Don't include it in the block vector. */
- block = BLOCK_SUBBLOCKS (block);
-
block_vector = identify_blocks (block, get_insns ());
}
@@ -5879,5 +5825,8 @@ unroll_block_trees ()
tree block = DECL_INITIAL (current_function_decl);
reorder_blocks (block_vector, block, get_insns ());
-}
+ /* Release any memory allocated by identify_blocks. */
+ if (block_vector)
+ free (block_vector);
+}
diff --git a/contrib/gcc/stor-layout.c b/contrib/gcc/stor-layout.c
index e743c37..043ad28 100644
--- a/contrib/gcc/stor-layout.c
+++ b/contrib/gcc/stor-layout.c
@@ -1,5 +1,5 @@
/* C-compiler utilities for types and variables storage layout
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -20,19 +20,22 @@ Boston, MA 02111-1307, USA. */
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "tree.h"
+#include "rtl.h"
#include "flags.h"
+#include "except.h"
#include "function.h"
+#include "expr.h"
+#include "toplev.h"
#define CEIL(x,y) (((x) + (y) - 1) / (y))
/* Data type for the expressions representing sizes of data types.
- It is the first integer type laid out.
- In C, this is int. */
+ It is the first integer type laid out. */
-tree sizetype;
+struct sizetype_tab sizetype_tab;
/* An integer constant with value 0 whose type is sizetype. */
@@ -50,10 +53,6 @@ int maximum_field_alignment;
May be overridden by front-ends. */
int set_alignment = 0;
-#define GET_MODE_ALIGNMENT(MODE) \
- MIN (BIGGEST_ALIGNMENT, \
- MAX (1, (GET_MODE_UNIT_SIZE (MODE) * BITS_PER_UNIT)))
-
static enum machine_mode smallest_mode_for_size PROTO((unsigned int,
enum mode_class));
static tree layout_record PROTO((tree));
@@ -254,13 +253,14 @@ layout_decl (decl, known_align)
DECL_BIT_FIELD_TYPE (decl) = DECL_BIT_FIELD (decl) ? type : 0;
if (maximum_field_alignment != 0)
DECL_ALIGN (decl) = MIN (DECL_ALIGN (decl), maximum_field_alignment);
- else if (flag_pack_struct)
+ else if (DECL_PACKED (decl))
DECL_ALIGN (decl) = MIN (DECL_ALIGN (decl), BITS_PER_UNIT);
}
if (DECL_BIT_FIELD (decl)
&& TYPE_SIZE (type) != 0
- && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
+ && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
+ && GET_MODE_CLASS (TYPE_MODE (type)) == MODE_INT)
{
register enum machine_mode xmode
= mode_for_size (TREE_INT_CST_LOW (DECL_SIZE (decl)), MODE_INT, 1);
@@ -277,6 +277,15 @@ layout_decl (decl, known_align)
}
}
+ /* Turn off DECL_BIT_FIELD if we won't need it set. */
+ if (DECL_BIT_FIELD (decl) && TYPE_MODE (type) == BLKmode
+ && known_align % TYPE_ALIGN (type) == 0
+ && DECL_SIZE (decl) != 0
+ && (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST
+ || (TREE_INT_CST_LOW (DECL_SIZE (decl)) % BITS_PER_UNIT) == 0)
+ && DECL_ALIGN (decl) >= TYPE_ALIGN (type))
+ DECL_BIT_FIELD (decl) = 0;
+
/* Evaluate nonconstant size only once, either now or as soon as safe. */
if (DECL_SIZE (decl) != 0 && TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
DECL_SIZE (decl) = variable_size (DECL_SIZE (decl));
@@ -299,11 +308,7 @@ layout_record (rec)
tree rec;
{
register tree field;
-#ifdef STRUCTURE_SIZE_BOUNDARY
- unsigned record_align = MAX (STRUCTURE_SIZE_BOUNDARY, TYPE_ALIGN (rec));
-#else
unsigned record_align = MAX (BITS_PER_UNIT, TYPE_ALIGN (rec));
-#endif
/* These must be laid out *after* the record is. */
tree pending_statics = NULL_TREE;
/* Record size so far is CONST_SIZE + VAR_SIZE bits,
@@ -311,17 +316,22 @@ layout_record (rec)
and VAR_SIZE is a tree expression.
If VAR_SIZE is null, the size is just CONST_SIZE.
Naturally we try to avoid using VAR_SIZE. */
- register int const_size = 0;
+ register HOST_WIDE_INT const_size = 0;
register tree var_size = 0;
/* Once we start using VAR_SIZE, this is the maximum alignment
that we know VAR_SIZE has. */
register int var_align = BITS_PER_UNIT;
+#ifdef STRUCTURE_SIZE_BOUNDARY
+ /* Packed structures don't need to have minimum size. */
+ if (! TYPE_PACKED (rec))
+ record_align = MAX (record_align, STRUCTURE_SIZE_BOUNDARY);
+#endif
for (field = TYPE_FIELDS (rec); field; field = TREE_CHAIN (field))
{
register int known_align = var_size ? var_align : const_size;
- register int desired_align;
+ register int desired_align = 0;
/* If FIELD is static, then treat it like a separate variable,
not really like a structure field.
@@ -329,7 +339,7 @@ layout_record (rec)
In both cases, all we do is lay out the decl,
and we do it *after* the record is laid out. */
- if (TREE_STATIC (field))
+ if (TREE_CODE (field) == VAR_DECL)
{
pending_statics = tree_cons (NULL_TREE, field, pending_statics);
continue;
@@ -352,6 +362,9 @@ layout_record (rec)
#ifdef BIGGEST_FIELD_ALIGNMENT
desired_align = MIN (desired_align, BIGGEST_FIELD_ALIGNMENT);
#endif
+#ifdef ADJUST_FIELD_ALIGN
+ desired_align = ADJUST_FIELD_ALIGN (field, desired_align);
+#endif
/* Record must have at least as much alignment as any field.
Otherwise, the alignment of the field within the record
@@ -379,7 +392,7 @@ layout_record (rec)
int type_align = TYPE_ALIGN (TREE_TYPE (field));
if (maximum_field_alignment != 0)
type_align = MIN (type_align, maximum_field_alignment);
- else if (flag_pack_struct)
+ else if (DECL_PACKED (field))
type_align = MIN (type_align, BITS_PER_UNIT);
record_align = MAX (record_align, type_align);
@@ -408,7 +421,7 @@ layout_record (rec)
{
if (const_size > 0)
var_size = size_binop (PLUS_EXPR, var_size,
- size_int (const_size));
+ bitsize_int (const_size, 0L));
const_size = 0;
var_size = round_up (var_size, desired_align);
var_align = MIN (var_align, desired_align);
@@ -421,23 +434,18 @@ layout_record (rec)
&& TREE_TYPE (field) != error_mark_node
&& DECL_BIT_FIELD_TYPE (field)
&& !DECL_PACKED (field)
- /* If #pragma pack is in effect, turn off this feature. */
&& maximum_field_alignment == 0
- && !flag_pack_struct
&& !integer_zerop (DECL_SIZE (field)))
{
int type_align = TYPE_ALIGN (TREE_TYPE (field));
register tree dsize = DECL_SIZE (field);
int field_size = TREE_INT_CST_LOW (dsize);
- /* A bit field may not span the unit of alignment of its type.
- Advance to next boundary if necessary. */
- /* ??? There is some uncertainty here as to what
- should be done if type_align is less than the width of the type.
- That can happen because the width exceeds BIGGEST_ALIGNMENT
- or because it exceeds maximum_field_alignment. */
- if (const_size / type_align
- != (const_size + (field_size % type_align) - 1) / type_align)
+ /* A bit field may not span more units of alignment of its type
+ than its type itself. Advance to next boundary if necessary. */
+ if (((const_size + field_size + type_align - 1) / type_align
+ - const_size / type_align)
+ > TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (field))) / type_align)
const_size = CEIL (const_size, type_align) * type_align;
}
#endif
@@ -458,11 +466,15 @@ layout_record (rec)
if (maximum_field_alignment != 0)
type_align = MIN (type_align, maximum_field_alignment);
- else if (flag_pack_struct)
+ /* ??? This test is opposite the test in the containing if
+ statement, so this code is unreachable currently. */
+ else if (DECL_PACKED (field))
type_align = MIN (type_align, BITS_PER_UNIT);
/* A bit field may not span the unit of alignment of its type.
Advance to next boundary if necessary. */
+ /* ??? This code should match the code above for the
+ PCC_BITFIELD_TYPE_MATTERS case. */
if (const_size / type_align
!= (const_size + field_size - 1) / type_align)
const_size = CEIL (const_size, type_align) * type_align;
@@ -473,7 +485,7 @@ layout_record (rec)
if (var_size && const_size)
DECL_FIELD_BITPOS (field)
- = size_binop (PLUS_EXPR, var_size, size_int (const_size));
+ = size_binop (PLUS_EXPR, var_size, bitsize_int (const_size, 0L));
else if (var_size)
DECL_FIELD_BITPOS (field) = var_size;
else
@@ -499,8 +511,9 @@ layout_record (rec)
if (dsize == 0)
/* Do nothing. */;
else if (TREE_CODE (dsize) == INTEGER_CST
+ && ! TREE_CONSTANT_OVERFLOW (dsize)
&& TREE_INT_CST_HIGH (dsize) == 0
- && TREE_INT_CST_LOW (dsize) + const_size > const_size)
+ && TREE_INT_CST_LOW (dsize) + const_size >= const_size)
/* Use const_size if there's no overflow. */
const_size += TREE_INT_CST_LOW (dsize);
else
@@ -525,7 +538,7 @@ layout_record (rec)
{
if (const_size)
var_size
- = size_binop (PLUS_EXPR, var_size, size_int (const_size));
+ = size_binop (PLUS_EXPR, var_size, bitsize_int (const_size, 0L));
TYPE_SIZE (rec) = var_size;
}
@@ -536,6 +549,11 @@ layout_record (rec)
TYPE_ALIGN (rec) = MAX (TYPE_ALIGN (rec), record_align);
#endif
+ /* Record the un-rounded size in the binfo node. But first we check
+ the size of TYPE_BINFO to make sure that BINFO_SIZE is available. */
+ if (TYPE_BINFO (rec) && TREE_VEC_LENGTH (TYPE_BINFO (rec)) > 6)
+ TYPE_BINFO_SIZE (rec) = TYPE_SIZE (rec);
+
#ifdef ROUND_TYPE_SIZE
TYPE_SIZE (rec) = ROUND_TYPE_SIZE (rec, TYPE_SIZE (rec), TYPE_ALIGN (rec));
#else
@@ -557,11 +575,7 @@ layout_union (rec)
tree rec;
{
register tree field;
-#ifdef STRUCTURE_SIZE_BOUNDARY
- unsigned union_align = STRUCTURE_SIZE_BOUNDARY;
-#else
unsigned union_align = BITS_PER_UNIT;
-#endif
/* The size of the union, based on the fields scanned so far,
is max (CONST_SIZE, VAR_SIZE).
@@ -569,6 +583,12 @@ layout_union (rec)
register int const_size = 0;
register tree var_size = 0;
+#ifdef STRUCTURE_SIZE_BOUNDARY
+ /* Packed structures don't need to have minimum size. */
+ if (! TYPE_PACKED (rec))
+ union_align = STRUCTURE_SIZE_BOUNDARY;
+#endif
+
/* If this is a QUAL_UNION_TYPE, we want to process the fields in
the reverse order in building the COND_EXPR that denotes its
size. We reverse them again later. */
@@ -582,7 +602,7 @@ layout_union (rec)
continue;
layout_decl (field, 0);
- DECL_FIELD_BITPOS (field) = size_int (0);
+ DECL_FIELD_BITPOS (field) = bitsize_int (0L, 0L);
/* Union must be at least as aligned as any field requires. */
@@ -612,7 +632,7 @@ layout_union (rec)
else if (TREE_CODE (rec) == QUAL_UNION_TYPE)
var_size = fold (build (COND_EXPR, sizetype, DECL_QUALIFIER (field),
DECL_SIZE (field),
- var_size ? var_size : integer_zero_node));
+ var_size ? var_size : bitsize_int (0L, 0L)));
}
if (TREE_CODE (rec) == QUAL_UNION_TYPE)
@@ -620,13 +640,13 @@ layout_union (rec)
/* Determine the ultimate size of the union (in bytes). */
if (NULL == var_size)
- TYPE_SIZE (rec) = size_int (CEIL (const_size, BITS_PER_UNIT)
- * BITS_PER_UNIT);
+ TYPE_SIZE (rec) = bitsize_int (CEIL (const_size, BITS_PER_UNIT)
+ * BITS_PER_UNIT, 0L);
else if (const_size == 0)
TYPE_SIZE (rec) = var_size;
else
TYPE_SIZE (rec) = size_binop (MAX_EXPR, var_size,
- round_up (size_int (const_size),
+ round_up (bitsize_int (const_size, 0L),
BITS_PER_UNIT));
/* Determine the desired alignment. */
@@ -685,20 +705,28 @@ layout_type (type)
of the language-specific code. */
abort ();
+ case BOOLEAN_TYPE: /* Used for Java, Pascal, and Chill. */
+ if (TYPE_PRECISION (type) == 0)
+ TYPE_PRECISION (type) = 1; /* default to one byte/boolean. */
+ /* ... fall through ... */
+
case INTEGER_TYPE:
case ENUMERAL_TYPE:
+ case CHAR_TYPE:
if (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
&& tree_int_cst_sgn (TYPE_MIN_VALUE (type)) >= 0)
TREE_UNSIGNED (type) = 1;
TYPE_MODE (type) = smallest_mode_for_size (TYPE_PRECISION (type),
MODE_INT);
- TYPE_SIZE (type) = size_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
+ TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)), 0L);
+ TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
break;
case REAL_TYPE:
TYPE_MODE (type) = mode_for_size (TYPE_PRECISION (type), MODE_FLOAT, 0);
- TYPE_SIZE (type) = size_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
+ TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)), 0L);
+ TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
break;
case COMPLEX_TYPE:
@@ -708,30 +736,35 @@ layout_type (type)
(TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE
? MODE_COMPLEX_INT : MODE_COMPLEX_FLOAT),
0);
- TYPE_SIZE (type) = size_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
+ TYPE_SIZE (type) = bitsize_int (GET_MODE_BITSIZE (TYPE_MODE (type)), 0L);
+ TYPE_SIZE_UNIT (type) = size_int (GET_MODE_SIZE (TYPE_MODE (type)));
break;
case VOID_TYPE:
TYPE_SIZE (type) = size_zero_node;
+ TYPE_SIZE_UNIT (type) = size_zero_node;
TYPE_ALIGN (type) = 1;
TYPE_MODE (type) = VOIDmode;
break;
case OFFSET_TYPE:
- TYPE_SIZE (type) = size_int (POINTER_SIZE);
+ TYPE_SIZE (type) = bitsize_int (POINTER_SIZE, 0L);
+ TYPE_SIZE_UNIT (type) = size_int (POINTER_SIZE / BITS_PER_UNIT);
TYPE_MODE (type) = ptr_mode;
break;
case FUNCTION_TYPE:
case METHOD_TYPE:
TYPE_MODE (type) = mode_for_size (2 * POINTER_SIZE, MODE_INT, 0);
- TYPE_SIZE (type) = size_int (2 * POINTER_SIZE);
+ TYPE_SIZE (type) = bitsize_int (2 * POINTER_SIZE, 0);
+ TYPE_SIZE_UNIT (type) = size_int ((2 * POINTER_SIZE) / BITS_PER_UNIT);
break;
case POINTER_TYPE:
case REFERENCE_TYPE:
TYPE_MODE (type) = ptr_mode;
- TYPE_SIZE (type) = size_int (POINTER_SIZE);
+ TYPE_SIZE (type) = bitsize_int (POINTER_SIZE, 0L);
+ TYPE_SIZE_UNIT (type) = size_int (POINTER_SIZE / BITS_PER_UNIT);
TREE_UNSIGNED (type) = 1;
TYPE_PRECISION (type) = POINTER_SIZE;
break;
@@ -767,8 +800,11 @@ layout_type (type)
lb, 0))
ub = TREE_OPERAND (ub, 0);
+ /* The initial subtraction should happen in the original type so
+ that (possible) negative values are handled appropriately. */
length = size_binop (PLUS_EXPR, size_one_node,
- size_binop (MINUS_EXPR, ub, lb));
+ fold (build (MINUS_EXPR, TREE_TYPE (lb),
+ ub, lb)));
/* If neither bound is a constant and sizetype is signed, make
sure the size is never negative. We should really do this
@@ -779,8 +815,19 @@ layout_type (type)
&& TREE_CODE (TYPE_MAX_VALUE (index)) != INTEGER_CST)
length = size_binop (MAX_EXPR, length, size_zero_node);
- TYPE_SIZE (type) = size_binop (MULT_EXPR, length,
- TYPE_SIZE (element));
+ TYPE_SIZE (type) = size_binop (MULT_EXPR, TYPE_SIZE (element),
+ length);
+
+ /* If we know the size of the element, calculate the total
+ size directly, rather than do some division thing below.
+ This optimization helps Fortran assumed-size arrays
+ (where the size of the array is determined at runtime)
+ substantially. */
+ if (TYPE_SIZE_UNIT (element) != 0)
+ {
+ TYPE_SIZE_UNIT (type)
+ = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (element), length);
+ }
}
/* Now round the alignment and size,
@@ -795,8 +842,15 @@ layout_type (type)
#ifdef ROUND_TYPE_SIZE
if (TYPE_SIZE (type) != 0)
- TYPE_SIZE (type)
- = ROUND_TYPE_SIZE (type, TYPE_SIZE (type), TYPE_ALIGN (type));
+ {
+ tree tmp;
+ tmp = ROUND_TYPE_SIZE (type, TYPE_SIZE (type), TYPE_ALIGN (type));
+ /* If the rounding changed the size of the type, remove any
+ pre-calculated TYPE_SIZE_UNIT. */
+ if (simple_cst_equal (TYPE_SIZE (type), tmp) != 1)
+ TYPE_SIZE_UNIT (type) = NULL;
+ TYPE_SIZE (type) = tmp;
+ }
#endif
TYPE_MODE (type) = BLKmode;
@@ -828,6 +882,8 @@ layout_type (type)
if (TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
{
tree field;
+ enum machine_mode mode = VOIDmode;
+
/* A record which has any BLKmode members must itself be BLKmode;
it can't go in a register.
Unless the member is BLKmode only because it isn't aligned. */
@@ -853,13 +909,23 @@ layout_type (type)
!= ((TREE_INT_CST_LOW (DECL_SIZE (field)) + bitpos - 1)
/ BITS_PER_WORD)
/* But there is no problem if the field is entire words. */
- && TREE_INT_CST_LOW (DECL_SIZE (field)) % BITS_PER_WORD == 0)
+ && TREE_INT_CST_LOW (DECL_SIZE (field)) % BITS_PER_WORD != 0)
goto record_lose;
+
+ /* If this field is the whole struct, remember its mode so
+ that, say, we can put a double in a class into a DF
+ register instead of forcing it to live in the stack. */
+ if (simple_cst_equal (TYPE_SIZE (type), DECL_SIZE (field)))
+ mode = DECL_MODE (field);
}
- TYPE_MODE (type)
- = mode_for_size (TREE_INT_CST_LOW (TYPE_SIZE (type)),
- MODE_INT, 1);
+ if (mode != VOIDmode)
+ /* We only have one real field; use its mode. */
+ TYPE_MODE (type) = mode;
+ else
+ TYPE_MODE (type)
+ = mode_for_size (TREE_INT_CST_LOW (TYPE_SIZE (type)),
+ MODE_INT, 1);
/* If structure's known alignment is less than
what the scalar mode would need, and it matters,
@@ -922,25 +988,7 @@ layout_type (type)
}
break;
- /* Pascal and Chill types */
- case BOOLEAN_TYPE: /* store one byte/boolean for now. */
- TYPE_MODE (type) = QImode;
- TYPE_SIZE (type) = size_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
- TYPE_PRECISION (type) = 1;
- TYPE_ALIGN (type) = GET_MODE_ALIGNMENT (TYPE_MODE (type));
- if (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
- && tree_int_cst_sgn (TYPE_MIN_VALUE (type)) >= 0)
- TREE_UNSIGNED (type) = 1;
- break;
-
- case CHAR_TYPE:
- TYPE_MODE (type) = QImode;
- TYPE_SIZE (type) = size_int (GET_MODE_BITSIZE (TYPE_MODE (type)));
- TYPE_PRECISION (type) = GET_MODE_BITSIZE (TYPE_MODE (type));
- TYPE_ALIGN (type) = GET_MODE_ALIGNMENT (TYPE_MODE (type));
- break;
-
- case SET_TYPE:
+ case SET_TYPE: /* Used by Chill and Pascal. */
if (TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) != INTEGER_CST
|| TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) != INTEGER_CST)
abort();
@@ -950,16 +998,17 @@ layout_type (type)
#define SET_WORD_SIZE BITS_PER_WORD
#endif
int alignment = set_alignment ? set_alignment : SET_WORD_SIZE;
- int size_in_bits =
- TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
- - TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) + 1;
+ int size_in_bits
+ = (TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
+ - TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) + 1);
int rounded_size
= ((size_in_bits + alignment - 1) / alignment) * alignment;
if (rounded_size > alignment)
TYPE_MODE (type) = BLKmode;
else
TYPE_MODE (type) = mode_for_size (alignment, MODE_INT, 1);
- TYPE_SIZE (type) = size_int (rounded_size);
+ TYPE_SIZE (type) = bitsize_int (rounded_size, 0L);
+ TYPE_SIZE_UNIT (type) = size_int (rounded_size / BITS_PER_UNIT);
TYPE_ALIGN (type) = alignment;
TYPE_PRECISION (type) = size_in_bits;
}
@@ -992,6 +1041,19 @@ layout_type (type)
if (TYPE_SIZE (type) != 0 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
TYPE_SIZE (type) = variable_size (TYPE_SIZE (type));
+ /* If we failed to find a simple way to calculate the unit size
+ of the type above, find it by division. */
+ if (TYPE_SIZE_UNIT (type) == 0 && TYPE_SIZE (type) != 0)
+ {
+ TYPE_SIZE_UNIT (type) = size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (type),
+ size_int (BITS_PER_UNIT));
+ }
+
+ /* Once again evaluate only once, either now or as soon as safe. */
+ if (TYPE_SIZE_UNIT (type) != 0
+ && TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
+ TYPE_SIZE_UNIT (type) = variable_size (TYPE_SIZE_UNIT (type));
+
/* Also layout any other variants of the type. */
if (TYPE_NEXT_VARIANT (type)
|| type != TYPE_MAIN_VARIANT (type))
@@ -999,6 +1061,7 @@ layout_type (type)
tree variant;
/* Record layout info of this variant. */
tree size = TYPE_SIZE (type);
+ tree size_unit = TYPE_SIZE_UNIT (type);
int align = TYPE_ALIGN (type);
enum machine_mode mode = TYPE_MODE (type);
@@ -1008,6 +1071,7 @@ layout_type (type)
variant = TYPE_NEXT_VARIANT (variant))
{
TYPE_SIZE (variant) = size;
+ TYPE_SIZE_UNIT (variant) = size_unit;
TYPE_ALIGN (variant) = align;
TYPE_MODE (variant) = mode;
}
@@ -1053,9 +1117,7 @@ make_signed_type (precision)
is the type for size values. */
if (sizetype == 0)
- {
- sizetype = type;
- }
+ set_sizetype (type);
/* Lay out the type: set its alignment, size, etc. */
@@ -1079,13 +1141,65 @@ make_unsigned_type (precision)
if (sizetype == 0)
{
- sizetype = type;
+ TREE_UNSIGNED (type) = 1;
+ set_sizetype (type);
}
fixup_unsigned_type (type);
return type;
}
+/* Set sizetype to TYPE, and initialize *sizetype accordingly.
+ Also update the type of any standard type's sizes made so far. */
+
+void
+set_sizetype (type)
+ tree type;
+{
+ int oprecision = TYPE_PRECISION (type), precision;
+
+ sizetype = type;
+
+ /* The *bitsizetype types use a precision that avoids overflows when
+ calculating signed sizes / offsets in bits.
+
+ We are allocating bitsizetype once and change it in place when
+ we decide later that we want to change it. This way, we avoid the
+ hassle of changing all the TYPE_SIZE (TREE_TYPE (sometype))
+ individually in each front end. */
+ if (! bitsizetype)
+ bitsizetype = make_node (INTEGER_TYPE);
+ if (TYPE_NAME (sizetype) && ! TYPE_NAME (bitsizetype))
+ TYPE_NAME (bitsizetype) = TYPE_NAME (sizetype);
+
+ precision = oprecision + BITS_PER_UNIT_LOG + 1;
+ /* However, when cross-compiling from a 32 bit to a 64 bit host,
+ we are limited to 64 bit precision. */
+ if (precision > 2 * HOST_BITS_PER_WIDE_INT)
+ precision = 2 * HOST_BITS_PER_WIDE_INT;
+ TYPE_PRECISION (bitsizetype) = precision;
+ if (TREE_UNSIGNED (type))
+ fixup_unsigned_type (bitsizetype);
+ else
+ fixup_signed_type (bitsizetype);
+ layout_type (bitsizetype);
+
+ if (TREE_UNSIGNED (type))
+ {
+ usizetype = sizetype;
+ ubitsizetype = bitsizetype;
+ ssizetype = make_signed_type (oprecision);
+ sbitsizetype = make_signed_type (precision);
+ }
+ else
+ {
+ ssizetype = sizetype;
+ sbitsizetype = bitsizetype;
+ usizetype = make_unsigned_type (oprecision);
+ ubitsizetype = make_unsigned_type (precision);
+ }
+}
+
/* Set the extreme values of TYPE based on its precision in bits,
then lay it out. Used when make_signed_type won't do
because the tree code is not INTEGER_TYPE.
@@ -1170,14 +1284,14 @@ get_best_mode (bitsize, bitpos, align, largest_mode, volatilep)
int volatilep;
{
enum machine_mode mode;
- int unit;
+ int unit = 0;
/* Find the narrowest integer mode that contains the bit field. */
for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
mode = GET_MODE_WIDER_MODE (mode))
{
unit = GET_MODE_BITSIZE (mode);
- if (bitpos / unit == (bitpos + bitsize - 1) / unit)
+ if ((bitpos % unit) + bitsize <= unit)
break;
}
diff --git a/contrib/gcc/stupid.c b/contrib/gcc/stupid.c
index ed1afcf..718c39b 100644
--- a/contrib/gcc/stupid.c
+++ b/contrib/gcc/stupid.c
@@ -1,5 +1,5 @@
/* Dummy data flow analysis for GNU compiler in nonoptimizing mode.
- Copyright (C) 1987, 1991, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 91, 94, 95, 96, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -22,7 +22,7 @@ Boston, MA 02111-1307, USA. */
/* This file performs stupid register allocation, which is used
when cc1 gets the -noreg switch (which is when cc does not get -O).
- Stupid register allocation goes in place of the the flow_analysis,
+ Stupid register allocation goes in place of the flow_analysis,
local_alloc and global_alloc passes. combine_instructions cannot
be done with stupid allocation because the data flow info that it needs
is not computed here.
@@ -42,12 +42,14 @@ Boston, MA 02111-1307, USA. */
pseudo reg is computed. Then the pseudo regs are ordered by priority
and assigned hard regs in priority order. */
-#include <stdio.h>
#include "config.h"
+#include "system.h"
+
#include "rtl.h"
#include "hard-reg-set.h"
#include "regs.h"
#include "flags.h"
+#include "toplev.h"
/* Vector mapping INSN_UIDs to suids.
The suids are like uids but increase monotonically always.
@@ -65,6 +67,11 @@ static int *uid_suid;
static int last_call_suid;
+/* Record the suid of the last NOTE_INSN_SETJMP
+ so we can tell whether a pseudo reg crosses any setjmp. */
+
+static int last_setjmp_suid;
+
/* Element N is suid of insn where life span of pseudo reg N ends.
Element is 0 if register N has not been seen yet on backward scan. */
@@ -88,6 +95,10 @@ static char *regs_live;
static char *regs_change_size;
+/* Indexed by reg number, nonzero if reg crosses a setjmp. */
+
+static char *regs_crosses_setjmp;
+
/* Indexed by insn's suid, the set of hard regs live after that insn. */
static HARD_REG_SET *after_insn_hard_regs;
@@ -97,7 +108,7 @@ static HARD_REG_SET *after_insn_hard_regs;
#define MARK_LIVE_AFTER(INSN,REGNO) \
SET_HARD_REG_BIT (after_insn_hard_regs[INSN_SUID (INSN)], (REGNO))
-static int stupid_reg_compare PROTO((int *, int *));
+static int stupid_reg_compare PROTO((const GENERIC_PTR,const GENERIC_PTR));
static int stupid_find_reg PROTO((int, enum reg_class, enum machine_mode,
int, int, int));
static void stupid_mark_refs PROTO((rtx, rtx));
@@ -120,6 +131,8 @@ stupid_life_analysis (f, nregs, file)
register rtx last, insn;
int max_uid, max_suid;
+ current_function_has_computed_jump = 0;
+
bzero (regs_ever_live, sizeof regs_ever_live);
regs_live = (char *) alloca (nregs);
@@ -148,6 +161,7 @@ stupid_life_analysis (f, nregs, file)
}
last_call_suid = i + 1;
+ last_setjmp_suid = i + 1;
max_suid = i + 1;
max_regno = nregs;
@@ -166,13 +180,14 @@ stupid_life_analysis (f, nregs, file)
regs_change_size = (char *) alloca (nregs * sizeof (char));
bzero ((char *) regs_change_size, nregs * sizeof (char));
- reg_renumber = (short *) oballoc (nregs * sizeof (short));
+ regs_crosses_setjmp = (char *) alloca (nregs * sizeof (char));
+ bzero ((char *) regs_crosses_setjmp, nregs * sizeof (char));
+
+ /* Allocate the reg_renumber array */
+ allocate_reg_info (max_regno, FALSE, TRUE);
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
reg_renumber[i] = i;
- for (i = FIRST_VIRTUAL_REGISTER; i < max_regno; i++)
- reg_renumber[i] = -1;
-
after_insn_hard_regs
= (HARD_REG_SET *) alloca (max_suid * sizeof (HARD_REG_SET));
@@ -184,7 +199,7 @@ stupid_life_analysis (f, nregs, file)
allocate_for_life_analysis ();
for (i = 0; i < max_regno; i++)
- reg_n_deaths[i] = 1;
+ REG_N_DEATHS (i) = 1;
bzero (regs_live, nregs);
@@ -215,27 +230,46 @@ stupid_life_analysis (f, nregs, file)
if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
stupid_mark_refs (PATTERN (insn), insn);
- /* Mark all call-clobbered regs as live after each call insn
- so that a pseudo whose life span includes this insn
- will not go in one of them.
+ if (GET_CODE (insn) == NOTE
+ && NOTE_LINE_NUMBER (insn) == NOTE_INSN_SETJMP)
+ last_setjmp_suid = INSN_SUID (insn);
+
+ /* Mark all call-clobbered regs as dead after each call insn so that
+ a pseudo whose life span includes this insn will not go in one of
+ them. If the function contains a non-local goto, mark all hard
+ registers dead (except for stack related bits).
+
Then mark those regs as all dead for the continuing scan
of the insns before the call. */
if (GET_CODE (insn) == CALL_INSN)
{
last_call_suid = INSN_SUID (insn);
- IOR_HARD_REG_SET (after_insn_hard_regs[last_call_suid],
- call_used_reg_set);
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (call_used_regs[i])
- regs_live[i] = 0;
+ if (current_function_has_nonlocal_label)
+ {
+ IOR_COMPL_HARD_REG_SET (after_insn_hard_regs[last_call_suid],
+ fixed_reg_set);
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (! fixed_regs[i])
+ regs_live[i] = 0;
+ }
+ else
+ {
+ IOR_HARD_REG_SET (after_insn_hard_regs[last_call_suid],
+ call_used_reg_set);
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ if (call_used_regs[i])
+ regs_live[i] = 0;
+ }
/* It is important that this be done after processing the insn's
pattern because we want the function result register to still
be live if it's also used to pass arguments. */
stupid_mark_refs (CALL_INSN_FUNCTION_USAGE (insn), insn);
}
+ if (GET_CODE (insn) == JUMP_INSN && computed_jump_p (insn))
+ current_function_has_computed_jump = 1;
}
/* Now decide the order in which to allocate the pseudo registers. */
@@ -253,13 +287,17 @@ stupid_life_analysis (f, nregs, file)
{
register int r = reg_order[i];
- /* Some regnos disappear from the rtl. Ignore them to avoid crash. */
- if (regno_reg_rtx[r] == 0)
+ /* Some regnos disappear from the rtl. Ignore them to avoid crash.
+ Also don't allocate registers that cross a setjmp, or live across
+ a call if this function receives a nonlocal goto. */
+ if (regno_reg_rtx[r] == 0 || regs_crosses_setjmp[r]
+ || (REG_N_CALLS_CROSSED (r) > 0
+ && current_function_has_nonlocal_label))
continue;
/* Now find the best hard-register class for this pseudo register */
if (N_REG_CLASSES > 1)
- reg_renumber[r] = stupid_find_reg (reg_n_calls_crossed[r],
+ reg_renumber[r] = stupid_find_reg (REG_N_CALLS_CROSSED (r),
reg_preferred_class (r),
PSEUDO_REGNO_MODE (r),
reg_where_born[r],
@@ -268,7 +306,7 @@ stupid_life_analysis (f, nregs, file)
/* If no reg available in that class, try alternate class. */
if (reg_renumber[r] == -1 && reg_alternate_class (r) != NO_REGS)
- reg_renumber[r] = stupid_find_reg (reg_n_calls_crossed[r],
+ reg_renumber[r] = stupid_find_reg (REG_N_CALLS_CROSSED (r),
reg_alternate_class (r),
PSEUDO_REGNO_MODE (r),
reg_where_born[r],
@@ -285,9 +323,10 @@ stupid_life_analysis (f, nregs, file)
static int
stupid_reg_compare (r1p, r2p)
- int *r1p, *r2p;
+ const GENERIC_PTR r1p;
+ const GENERIC_PTR r2p;
{
- register int r1 = *r1p, r2 = *r2p;
+ register int r1 = *(int *)r1p, r2 = *(int *)r2p;
register int len1 = reg_where_dead[r1] - reg_where_born[r1];
register int len2 = reg_where_dead[r2] - reg_where_born[r2];
int tem;
@@ -296,7 +335,7 @@ stupid_reg_compare (r1p, r2p)
if (tem != 0)
return tem;
- tem = reg_n_refs[r1] - reg_n_refs[r2];
+ tem = REG_N_REFS (r1) - REG_N_REFS (r2);
if (tem != 0)
return tem;
@@ -308,8 +347,8 @@ stupid_reg_compare (r1p, r2p)
/* Find a block of SIZE words of hard registers in reg_class CLASS
that can hold a value of machine-mode MODE
(but actually we test only the first of the block for holding MODE)
- currently free from after insn whose suid is BIRTH
- through the insn whose suid is DEATH,
+ currently free from after insn whose suid is BORN_INSN
+ through the insn whose suid is DEAD_INSN,
and return the number of the first of them.
Return -1 if such a block cannot be found.
@@ -337,6 +376,13 @@ stupid_find_reg (call_preserved, class, mode,
static struct {int from, to; } eliminables[] = ELIMINABLE_REGS;
#endif
+ /* If this register's life is more than 5,000 insns, we probably
+ can't allocate it, so don't waste the time trying. This avoids
+ quadratic behavior on programs that have regularly-occurring
+ SAVE_EXPRs. */
+ if (dead_insn > born_insn + 5000)
+ return -1;
+
COPY_HARD_REG_SET (used,
call_preserved ? call_used_reg_set : fixed_reg_set);
@@ -353,6 +399,12 @@ stupid_find_reg (call_preserved, class, mode,
for (ins = born_insn; ins < dead_insn; ins++)
IOR_HARD_REG_SET (used, after_insn_hard_regs[ins]);
+#ifdef STACK_REGS
+ if (current_function_has_computed_jump)
+ for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
+ SET_HARD_REG_BIT (used, i);
+#endif
+
IOR_COMPL_HARD_REG_SET (used, reg_class_contents[(int) class]);
#ifdef CLASS_CANNOT_CHANGE_SIZE
@@ -450,13 +502,13 @@ stupid_mark_refs (x, insn)
/* The following line is for unused outputs;
they do get stored even though never used again. */
- MARK_LIVE_AFTER (insn, regno);
+ MARK_LIVE_AFTER (insn, regno+j);
/* When a hard reg is clobbered, mark it in use
just before this insn, so it is live all through. */
if (code == CLOBBER && INSN_SUID (insn) > 0)
SET_HARD_REG_BIT (after_insn_hard_regs[INSN_SUID (insn) - 1],
- regno);
+ regno+j);
}
}
/* For pseudo regs, record where born, where dead, number of
@@ -483,10 +535,27 @@ stupid_mark_refs (x, insn)
}
/* Count the refs of this reg. */
- reg_n_refs[regno]++;
+ REG_N_REFS (regno)++;
if (last_call_suid < reg_where_dead[regno])
- reg_n_calls_crossed[regno] += 1;
+ REG_N_CALLS_CROSSED (regno) += 1;
+
+ if (last_setjmp_suid < reg_where_dead[regno])
+ regs_crosses_setjmp[regno] = 1;
+
+ /* If this register is only used in this insn and is only
+ set, mark it unused. We have to do this even when not
+ optimizing so that MD patterns which count on this
+ behavior (e.g., it not causing an output reload on
+ an insn setting CC) will operate correctly. */
+ if (GET_CODE (SET_DEST (x)) == REG
+ && REGNO_FIRST_UID (regno) == INSN_UID (insn)
+ && REGNO_LAST_UID (regno) == INSN_UID (insn)
+ && (code == CLOBBER || ! reg_mentioned_p (SET_DEST (x),
+ SET_SRC (x))))
+ REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_UNUSED,
+ SET_DEST (x),
+ REG_NOTES (insn));
}
}
@@ -531,7 +600,7 @@ stupid_mark_refs (x, insn)
/* Pseudo reg: record first use, last use and number of uses. */
reg_where_born[regno] = INSN_SUID (insn);
- reg_n_refs[regno]++;
+ REG_N_REFS (regno)++;
if (regs_live[regno] == 0)
{
regs_live[regno] = 1;
diff --git a/contrib/gcc/sys-protos.h b/contrib/gcc/sys-protos.h
index c9b8c4b..ab6e407 100644
--- a/contrib/gcc/sys-protos.h
+++ b/contrib/gcc/sys-protos.h
@@ -127,8 +127,8 @@ extern AUTH * authunix_create(char *, int, int, int, int *);
extern AUTH * authunix_create_default(void);
extern char * basename(char *);
extern int baudrate(void);
-extern int bcmp(const void *, const void *, int);
-extern void bcopy(const void *, void *, int);
+extern int bcmp(const void *, const void *, size_t);
+extern void bcopy(const void *, void *, size_t);
extern int beep(void);
extern void (* berk_signal(int, void (*) (int, ...))) (int, ...);
extern char * bgets(char *, size_t, FILE *, char *);
@@ -449,8 +449,12 @@ extern int getgroups(int, gid_t *);
extern struct hostent * gethostbyaddr(/* ??? */);
extern struct hostent * gethostbyname(/* ??? */);
extern struct hostent * gethostent(/* ??? */);
+#ifdef __alpha__
+extern int gethostid(void);
+#else
extern long gethostid(void);
-extern int gethostname(char *, int);
+#endif
+extern int gethostname(char *, size_t);
extern int getitimer(int, struct itimerval *);
extern char * getlogin(void);
extern int getmaxx(WINDOW *);
@@ -645,7 +649,7 @@ extern dl_t lmul(/* ??? */);
extern struct lconv * localeconv(void);
extern struct tm * localtime(const time_t *);
extern int lock(int, int, long);
-extern int lockf(int, int, long int);
+extern int lockf(int, int, off_t);
extern double log(double);
extern double log10(double);
extern float log10f(float);
@@ -858,9 +862,9 @@ extern int raise(int);
extern int rand(void);
extern long random(void);
extern int raw(void);
-extern int read(int, void *, size_t);
+extern ssize_t read(int, void *, size_t);
extern struct dirent * readdir(DIR *);
-extern int readlink(const char *, void *, int);
+extern ssize_t readlink(const char *, char *, size_t);
extern void * realloc(void *, size_t);
extern char * realpath(char *, char *);
extern int redrawwin(WINDOW *);
@@ -1048,6 +1052,7 @@ extern int slk_restore(void);
extern int slk_set(int, char *, int);
extern int slk_start(int, int *);
extern int slk_touch(void);
+extern int socket (int, int, int);
extern void * sprayproc_clear_1(/* ??? */);
extern spraycumul * sprayproc_get_1(/* ??? */);
extern void * sprayproc_spray_1(/* ??? */);
@@ -1069,6 +1074,7 @@ extern int stime(const time_t *);
extern struct netbuf * stoa(char *, struct netbuf *);
extern void store(datum, datum);
extern char * strcadd(char *, const char *);
+extern int strcasecmp(const char *, const char *);
extern char * strcat(char *, const char *);
extern char * strccpy(char *, const char *);
extern char * strchr(const char *, int);
@@ -1086,6 +1092,7 @@ extern char * strerror(int);
extern int strfind(const char *, const char *);
extern size_t strftime(char *, size_t, const char *, const struct tm *);
extern size_t strlen(const char *);
+extern int strncasecmp(const char *, const char *, size_t);
extern char * strncat(char *, const char *, size_t);
extern int strncmp(const char *, const char *, size_t);
extern char * strncpy(char *, const char *, size_t);
@@ -1264,7 +1271,7 @@ extern int wnoutrefresh(WINDOW *);
extern int wprintw(WINDOW *, ...);
extern int wredrawln(WINDOW *, int, int);
extern int wrefresh(WINDOW *);
-extern int write(int, const void *, size_t);
+extern ssize_t write(int, const void *, size_t);
extern int wscanw(WINDOW *, ...);
extern int wscrl(WINDOW *, int);
extern int wsetscrreg(WINDOW *, int, int);
diff --git a/contrib/gcc/sys-types.h b/contrib/gcc/sys-types.h
index 527472f..7db46f1 100644
--- a/contrib/gcc/sys-types.h
+++ b/contrib/gcc/sys-types.h
@@ -86,6 +86,7 @@ union wait;
#include <stddef.h>
/* #include "sys/types.h" */
+#define ssize_t int
/* The actual types used here are mostly wrong,
but it is not supposed to matter what types we use here. */
diff --git a/contrib/gcc/system.h b/contrib/gcc/system.h
new file mode 100644
index 0000000..27b1fee
--- /dev/null
+++ b/contrib/gcc/system.h
@@ -0,0 +1,316 @@
+/* system.h - Get common system includes and various definitions and
+ declarations based on autoconf macros.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+
+ */
+
+#ifndef __GCC_SYSTEM_H__
+#define __GCC_SYSTEM_H__
+
+#include <stdio.h>
+
+/* Define a generic NULL if one hasn't already been defined. */
+#ifndef NULL
+#define NULL 0
+#endif
+
+#include <ctype.h>
+
+/* Jim Meyering writes:
+
+ "... Some ctype macros are valid only for character codes that
+ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+ using /bin/cc or gcc but without giving an ansi option). So, all
+ ctype uses should be through macros like ISPRINT... If
+ STDC_HEADERS is defined, then autoconf has verified that the ctype
+ macros don't need to be guarded with references to isascii. ...
+ Defining isascii to 1 should let any compiler worth its salt
+ eliminate the && through constant folding."
+
+ Bruno Haible adds:
+
+ "... Furthermore, isupper(c) etc. have an undefined result if c is
+ outside the range -1 <= c <= 255. One is tempted to write isupper(c)
+ with c being of type `char', but this is wrong if c is an 8-bit
+ character >= 128 which gets sign-extended to a negative value.
+ The macro ISUPPER protects against this as well." */
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+#ifdef isblank
+# define ISBLANK(c) (IN_CTYPE_DOMAIN (c) && isblank (c))
+#else
+# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isgraph (c))
+#else
+# define ISGRAPH(c) (IN_CTYPE_DOMAIN (c) && isprint (c) && !isspace (c))
+#endif
+
+#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
+#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISCNTRL(c) (IN_CTYPE_DOMAIN (c) && iscntrl (c))
+#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c))
+#define ISPUNCT(c) (IN_CTYPE_DOMAIN (c) && ispunct (c))
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
+#define ISXDIGIT(c) (IN_CTYPE_DOMAIN (c) && isxdigit (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+ only '0' through '9' are digits. Prefer ISDIGIT to ISDIGIT_LOCALE unless
+ it's important to use the locale's definition of `digit' even when the
+ host does not conform to Posix. */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+
+#include <sys/types.h>
+#include <errno.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#else
+# ifdef HAVE_STRINGS_H
+# include <strings.h>
+# endif
+#endif
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+
+#if HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# ifdef HAVE_TIME_H
+# include <time.h>
+# endif
+# endif
+#endif
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#else
+# ifdef HAVE_SYS_FILE_H
+# include <sys/file.h>
+# endif
+#endif
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+# define SEEK_CUR 1
+# define SEEK_END 2
+#endif
+#ifndef F_OK
+# define F_OK 0
+# define X_OK 1
+# define W_OK 2
+# define R_OK 4
+#endif
+#ifndef O_RDONLY
+# define O_RDONLY 0
+#endif
+#ifndef O_WRONLY
+# define O_WRONLY 1
+#endif
+
+
+
+#ifndef bcopy
+# ifdef HAVE_BCOPY
+# ifdef NEED_DECLARATION_BCOPY
+extern void bcopy ();
+# endif
+# else /* ! HAVE_BCOPY */
+# define bcopy(src,dst,len) memcpy ((dst),(src),(len))
+# endif
+#endif
+
+#ifndef bcmp
+# ifdef HAVE_BCMP
+# ifdef NEED_DECLARATION_BCMP
+extern int bcmp ();
+# endif
+# else /* ! HAVE_BCMP */
+# define bcmp(left,right,len) memcmp ((left),(right),(len))
+# endif
+#endif
+
+#ifndef bzero
+# ifdef HAVE_BZERO
+# ifdef NEED_DECLARATION_BZERO
+extern void bzero ();
+# endif
+# else /* ! HAVE_BZERO */
+# define bzero(dst,len) memset ((dst),0,(len))
+# endif
+#endif
+
+#ifndef index
+# ifdef HAVE_INDEX
+# ifdef NEED_DECLARATION_INDEX
+extern char *index ();
+# endif
+# else /* ! HAVE_INDEX */
+# define index strchr
+# endif
+#endif
+
+#ifndef rindex
+# ifdef HAVE_RINDEX
+# ifdef NEED_DECLARATION_RINDEX
+extern char *rindex ();
+# endif
+# else /* ! HAVE_RINDEX */
+# define rindex strrchr
+# endif
+#endif
+
+#ifdef NEED_DECLARATION_ATOF
+extern double atof ();
+#endif
+
+#ifdef NEED_DECLARATION_ATOL
+extern long atol();
+#endif
+
+#ifdef NEED_DECLARATION_FREE
+extern void free ();
+#endif
+
+#ifdef NEED_DECLARATION_GETCWD
+extern char *getcwd ();
+#endif
+
+#ifdef NEED_DECLARATION_GETENV
+extern char *getenv ();
+#endif
+
+#ifdef NEED_DECLARATION_GETWD
+extern char *getwd ();
+#endif
+
+#ifdef NEED_DECLARATION_SBRK
+extern char *sbrk ();
+#endif
+
+#ifdef HAVE_STRERROR
+# ifdef NEED_DECLARATION_STRERROR
+# ifndef strerror
+extern char *strerror ();
+# endif
+# endif
+#else /* ! HAVE_STRERROR */
+extern int sys_nerr;
+extern char *sys_errlist[];
+#endif /* HAVE_STRERROR */
+
+#ifdef HAVE_GETRLIMIT
+# ifdef NEED_DECLARATION_GETRLIMIT
+# ifndef getrlimit
+extern int getrlimit ();
+# endif
+# endif
+#endif
+
+#ifdef HAVE_SETRLIMIT
+# ifdef NEED_DECLARATION_SETRLIMIT
+# ifndef setrlimit
+extern int setrlimit ();
+# endif
+# endif
+#endif
+
+/* HAVE_VOLATILE only refers to the stage1 compiler. We also check
+ __STDC__ and assume gcc sets it and has volatile in stage >=2. */
+#if !defined(HAVE_VOLATILE) && !defined(__STDC__) && !defined(volatile)
+#define volatile
+#endif
+
+/* Redefine abort to report an internal error w/o coredump, and reporting the
+ location of the error in the source file. */
+#ifndef abort
+#ifndef __STDC__
+#ifndef __GNUC__
+#ifndef USE_SYSTEM_ABORT
+#define USE_SYSTEM_ABORT
+#endif /* !USE_SYSTEM_ABORT */
+#endif /* !__GNUC__ */
+#endif /* !__STDC__ */
+
+#ifdef USE_SYSTEM_ABORT
+# ifdef NEED_DECLARATION_ABORT
+extern void abort ();
+# endif
+#else
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+#define abort() \
+(fprintf (stderr, \
+ "%s:%d: Internal compiler error\n", __FILE__, __LINE__), \
+ exit (FATAL_EXIT_CODE))
+
+#else
+#define abort() \
+(fprintf (stderr, \
+ "%s:%d: Internal compiler error in function %s\n", \
+ __FILE__, __LINE__, __PRETTY_FUNCTION__), \
+ exit (FATAL_EXIT_CODE))
+
+#endif /* recent gcc */
+#endif /* USE_SYSTEM_ABORT */
+#endif /* !abort */
+
+
+/* Define a STRINGIFY macro that's right for ANSI or traditional C.
+ HAVE_CPP_STRINGIFY only refers to the stage1 compiler. Assume that
+ (non-traditional) gcc used in stage2 or later has this feature.
+
+ Note: if the argument passed to STRINGIFY is itself a macro, eg
+ #define foo bar, STRINGIFY(foo) will produce "foo", not "bar".
+ Although the __STDC__ case could be made to expand this via a layer
+ of indirection, the traditional C case can not do so. Therefore
+ this behavior is not supported. */
+#ifndef STRINGIFY
+# if defined(HAVE_CPP_STRINGIFY) || (defined(__GNUC__) && defined(__STDC__))
+# define STRINGIFY(STRING) #STRING
+# else
+# define STRINGIFY(STRING) "STRING"
+# endif
+#endif /* ! STRINGIFY */
+
+
+/* These macros are here in preparation for the use of gettext in egcs. */
+#define _(String) String
+#define N_(String) String
+
+#endif /* __GCC_SYSTEM_H__ */
diff --git a/contrib/gcc/tlink.c b/contrib/gcc/tlink.c
new file mode 100644
index 0000000..d5fa00c
--- /dev/null
+++ b/contrib/gcc/tlink.c
@@ -0,0 +1,633 @@
+/* Scan linker error messages for missing template instantiations and provide
+ them.
+
+ Copyright (C) 1995, 1998 Free Software Foundation, Inc.
+ Contributed by Jason Merrill (jason@cygnus.com).
+
+This file is part of GNU CC.
+
+GNU CC 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, or (at your option)
+any later version.
+
+GNU CC 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 GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "hash.h"
+#include "demangle.h"
+#include "toplev.h"
+
+#define MAX_ITERATIONS 17
+
+/* Obstack allocation and deallocation routines. */
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+extern char * xmalloc PARAMS((unsigned));
+
+/* Defined in collect2.c. */
+extern int vflag, debug;
+extern char *ldout;
+extern char *c_file_name;
+extern struct obstack temporary_obstack;
+extern struct obstack permanent_obstack;
+extern char * temporary_firstobj;
+
+/* Defined in the automatically-generated underscore.c. */
+extern int prepends_underscore;
+
+static int tlink_verbose;
+
+/* Hash table code. */
+
+typedef struct symbol_hash_entry
+{
+ struct hash_entry root;
+ struct file_hash_entry *file;
+ int chosen;
+ int tweaking;
+ int tweaked;
+} symbol;
+
+typedef struct file_hash_entry
+{
+ struct hash_entry root;
+ const char *args;
+ const char *dir;
+ const char *main;
+ int tweaking;
+} file;
+
+typedef struct demangled_hash_entry
+{
+ struct hash_entry root;
+ const char *mangled;
+} demangled;
+
+static struct hash_table symbol_table;
+
+static struct hash_entry *
+symbol_hash_newfunc (entry, table, string)
+ struct hash_entry *entry;
+ struct hash_table *table;
+ const char *string;
+{
+ struct symbol_hash_entry *ret = (struct symbol_hash_entry *) entry;
+ if (ret == NULL)
+ {
+ ret = ((struct symbol_hash_entry *)
+ hash_allocate (table, sizeof (struct symbol_hash_entry)));
+ if (ret == NULL)
+ return NULL;
+ }
+ ret = ((struct symbol_hash_entry *)
+ hash_newfunc ((struct hash_entry *) ret, table, string));
+ ret->file = NULL;
+ ret->chosen = 0;
+ ret->tweaking = 0;
+ ret->tweaked = 0;
+ return (struct hash_entry *) ret;
+}
+
+static struct symbol_hash_entry *
+symbol_hash_lookup (string, create)
+ const char *string;
+ boolean create;
+{
+ return ((struct symbol_hash_entry *)
+ hash_lookup (&symbol_table, string, create, true));
+}
+
+static struct hash_table file_table;
+
+static struct hash_entry *
+file_hash_newfunc (entry, table, string)
+ struct hash_entry *entry;
+ struct hash_table *table;
+ const char *string;
+{
+ struct file_hash_entry *ret = (struct file_hash_entry *) entry;
+ if (ret == NULL)
+ {
+ ret = ((struct file_hash_entry *)
+ hash_allocate (table, sizeof (struct file_hash_entry)));
+ if (ret == NULL)
+ return NULL;
+ }
+ ret = ((struct file_hash_entry *)
+ hash_newfunc ((struct hash_entry *) ret, table, string));
+ ret->args = NULL;
+ ret->dir = NULL;
+ ret->main = NULL;
+ ret->tweaking = 0;
+ return (struct hash_entry *) ret;
+}
+
+static struct file_hash_entry *
+file_hash_lookup (string)
+ const char *string;
+{
+ return ((struct file_hash_entry *)
+ hash_lookup (&file_table, string, true, true));
+}
+
+static struct hash_table demangled_table;
+
+static struct hash_entry *
+demangled_hash_newfunc (entry, table, string)
+ struct hash_entry *entry;
+ struct hash_table *table;
+ const char *string;
+{
+ struct demangled_hash_entry *ret = (struct demangled_hash_entry *) entry;
+ if (ret == NULL)
+ {
+ ret = ((struct demangled_hash_entry *)
+ hash_allocate (table, sizeof (struct demangled_hash_entry)));
+ if (ret == NULL)
+ return NULL;
+ }
+ ret = ((struct demangled_hash_entry *)
+ hash_newfunc ((struct hash_entry *) ret, table, string));
+ ret->mangled = NULL;
+ return (struct hash_entry *) ret;
+}
+
+static struct demangled_hash_entry *
+demangled_hash_lookup (string, create)
+ const char *string;
+ boolean create;
+{
+ return ((struct demangled_hash_entry *)
+ hash_lookup (&demangled_table, string, create, true));
+}
+
+/* Stack code. */
+
+struct symbol_stack_entry
+{
+ symbol *value;
+ struct symbol_stack_entry *next;
+};
+struct obstack symbol_stack_obstack;
+struct symbol_stack_entry *symbol_stack;
+
+struct file_stack_entry
+{
+ file *value;
+ struct file_stack_entry *next;
+};
+struct obstack file_stack_obstack;
+struct file_stack_entry *file_stack;
+
+static void
+symbol_push (p)
+ symbol *p;
+{
+ struct symbol_stack_entry *ep = (struct symbol_stack_entry *) obstack_alloc
+ (&symbol_stack_obstack, sizeof (struct symbol_stack_entry));
+ ep->value = p;
+ ep->next = symbol_stack;
+ symbol_stack = ep;
+}
+
+static symbol *
+symbol_pop ()
+{
+ struct symbol_stack_entry *ep = symbol_stack;
+ symbol *p;
+ if (ep == NULL)
+ return NULL;
+ p = ep->value;
+ symbol_stack = ep->next;
+ obstack_free (&symbol_stack_obstack, ep);
+ return p;
+}
+
+static void
+file_push (p)
+ file *p;
+{
+ struct file_stack_entry *ep;
+
+ if (p->tweaking)
+ return;
+
+ ep = (struct file_stack_entry *) obstack_alloc
+ (&file_stack_obstack, sizeof (struct file_stack_entry));
+ ep->value = p;
+ ep->next = file_stack;
+ file_stack = ep;
+ p->tweaking = 1;
+}
+
+static file *
+file_pop ()
+{
+ struct file_stack_entry *ep = file_stack;
+ file *p;
+ if (ep == NULL)
+ return NULL;
+ p = ep->value;
+ file_stack = ep->next;
+ obstack_free (&file_stack_obstack, ep);
+ p->tweaking = 0;
+ return p;
+}
+
+/* Other machinery. */
+
+static void
+tlink_init ()
+{
+ char *p;
+
+ hash_table_init (&symbol_table, symbol_hash_newfunc);
+ hash_table_init (&file_table, file_hash_newfunc);
+ hash_table_init (&demangled_table, demangled_hash_newfunc);
+ obstack_begin (&symbol_stack_obstack, 0);
+ obstack_begin (&file_stack_obstack, 0);
+
+ p = getenv ("TLINK_VERBOSE");
+ if (p)
+ tlink_verbose = atoi (p);
+ else
+ {
+ tlink_verbose = 1;
+ if (vflag)
+ tlink_verbose = 2;
+ if (debug)
+ tlink_verbose = 3;
+ }
+}
+
+static int
+tlink_execute (prog, argv, redir)
+ char *prog;
+ char **argv;
+ char *redir;
+{
+ collect_execute (prog, argv, redir);
+ return collect_wait (prog);
+}
+
+static char *
+frob_extension (s, ext)
+ char *s, *ext;
+{
+ char *p = rindex (s, '/');
+ if (! p)
+ p = s;
+ p = rindex (p, '.');
+ if (! p)
+ p = s + strlen (s);
+
+ obstack_grow (&temporary_obstack, s, p - s);
+ return obstack_copy0 (&temporary_obstack, ext, strlen (ext));
+}
+
+static char *
+obstack_fgets (stream, ob)
+ FILE *stream;
+ struct obstack *ob;
+{
+ int c;
+ while ((c = getc (stream)) != EOF && c != '\n')
+ obstack_1grow (ob, c);
+ if (obstack_object_size (ob) == 0)
+ return NULL;
+ obstack_1grow (ob, '\0');
+ return obstack_finish (ob);
+}
+
+static char *
+tfgets (stream)
+ FILE *stream;
+{
+ return obstack_fgets (stream, &temporary_obstack);
+}
+
+static char *
+pfgets (stream)
+ FILE *stream;
+{
+ return obstack_fgets (stream, &permanent_obstack);
+}
+
+/* Real tlink code. */
+
+static void
+freadsym (stream, f, chosen)
+ FILE *stream;
+ file *f;
+ int chosen;
+{
+ symbol *sym;
+
+ {
+ char *name = tfgets (stream);
+ sym = symbol_hash_lookup (name, true);
+ }
+
+ if (sym->file == NULL)
+ {
+ symbol_push (sym);
+ sym->file = f;
+ sym->chosen = chosen;
+ }
+ else if (chosen)
+ {
+ if (sym->chosen && sym->file != f)
+ {
+ if (sym->chosen == 1)
+ file_push (sym->file);
+ else
+ {
+ file_push (f);
+ f = sym->file;
+ chosen = sym->chosen;
+ }
+ }
+ sym->file = f;
+ sym->chosen = chosen;
+ }
+}
+
+static void
+read_repo_file (f)
+ file *f;
+{
+ char c;
+ FILE *stream = fopen (f->root.string, "r");
+
+ if (tlink_verbose >= 2)
+ fprintf (stderr, "collect: reading %s\n", f->root.string);
+
+ while (fscanf (stream, "%c ", &c) == 1)
+ {
+ switch (c)
+ {
+ case 'A':
+ f->args = pfgets (stream);
+ break;
+ case 'D':
+ f->dir = pfgets (stream);
+ break;
+ case 'M':
+ f->main = pfgets (stream);
+ break;
+ case 'P':
+ freadsym (stream, f, 2);
+ break;
+ case 'C':
+ freadsym (stream, f, 1);
+ break;
+ case 'O':
+ freadsym (stream, f, 0);
+ break;
+ }
+ obstack_free (&temporary_obstack, temporary_firstobj);
+ }
+ fclose (stream);
+ if (f->args == NULL)
+ f->args = getenv ("COLLECT_GCC_OPTIONS");
+ if (f->dir == NULL)
+ f->dir = ".";
+}
+
+static void
+maybe_tweak (line, f)
+ char *line;
+ file *f;
+{
+ symbol *sym = symbol_hash_lookup (line + 2, false);
+
+ if ((sym->file == f && sym->tweaking)
+ || (sym->file != f && line[0] == 'C'))
+ {
+ sym->tweaking = 0;
+ sym->tweaked = 1;
+
+ if (line[0] == 'O')
+ line[0] = 'C';
+ else
+ line[0] = 'O';
+ }
+}
+
+static int
+recompile_files ()
+{
+ file *f;
+
+ while ((f = file_pop ()) != NULL)
+ {
+ char *line, *command;
+ FILE *stream = fopen (f->root.string, "r");
+ char *outname = frob_extension (f->root.string, ".rnw");
+ FILE *output = fopen (outname, "w");
+
+ while ((line = tfgets (stream)) != NULL)
+ {
+ switch (line[0])
+ {
+ case 'C':
+ case 'O':
+ maybe_tweak (line, f);
+ }
+ fprintf (output, "%s\n", line);
+ }
+ fclose (stream);
+ fclose (output);
+ rename (outname, f->root.string);
+
+ obstack_grow (&temporary_obstack, "cd ", 3);
+ obstack_grow (&temporary_obstack, f->dir, strlen (f->dir));
+ obstack_grow (&temporary_obstack, "; ", 2);
+ obstack_grow (&temporary_obstack, c_file_name, strlen (c_file_name));
+ obstack_1grow (&temporary_obstack, ' ');
+ obstack_grow (&temporary_obstack, f->args, strlen (f->args));
+ obstack_1grow (&temporary_obstack, ' ');
+ command = obstack_copy0 (&temporary_obstack, f->main, strlen (f->main));
+
+ if (tlink_verbose)
+ fprintf (stderr, "collect: recompiling %s\n", f->main);
+ if (tlink_verbose >= 3)
+ fprintf (stderr, "%s\n", command);
+
+ if (system (command) != 0)
+ return 0;
+
+ read_repo_file (f);
+
+ obstack_free (&temporary_obstack, temporary_firstobj);
+ }
+ return 1;
+}
+
+static int
+read_repo_files (object_lst)
+ char **object_lst;
+{
+ char **object = object_lst;
+
+ for (; *object; object++)
+ {
+ char *p = frob_extension (*object, ".rpo");
+ file *f;
+
+ if (! file_exists (p))
+ continue;
+
+ f = file_hash_lookup (p);
+
+ read_repo_file (f);
+ }
+
+ if (file_stack != NULL && ! recompile_files ())
+ return 0;
+
+ return (symbol_stack != NULL);
+}
+
+static void
+demangle_new_symbols ()
+{
+ symbol *sym;
+
+ while ((sym = symbol_pop ()) != NULL)
+ {
+ demangled *dem;
+ char *p = cplus_demangle (sym->root.string, DMGL_PARAMS | DMGL_ANSI);
+
+ if (! p)
+ continue;
+
+ dem = demangled_hash_lookup (p, true);
+ dem->mangled = sym->root.string;
+ }
+}
+
+static int
+scan_linker_output (fname)
+ char *fname;
+{
+ FILE *stream = fopen (fname, "r");
+ char *line;
+
+ while ((line = tfgets (stream)) != NULL)
+ {
+ char *p = line, *q;
+ symbol *sym;
+ int end;
+
+ while (*p && ISSPACE (*p))
+ ++p;
+
+ if (! *p)
+ continue;
+
+ for (q = p; *q && ! ISSPACE (*q); ++q)
+ ;
+
+ /* Try the first word on the line. */
+ if (*p == '.')
+ ++p;
+ if (*p == '_' && prepends_underscore)
+ ++p;
+
+ end = ! *q;
+ *q = 0;
+ sym = symbol_hash_lookup (p, false);
+
+ if (! sym && ! end)
+ /* Try a mangled name in `quotes'. */
+ {
+ demangled *dem = 0;
+ p = index (q+1, '`');
+ q = 0;
+
+#define MUL "multiple definition of "
+#define UND "undefined reference to "
+
+ if (p && (p - line > sizeof (MUL)))
+ {
+ char *beg = p - sizeof (MUL) + 1;
+ *p = 0;
+ if (!strcmp (beg, MUL) || !strcmp (beg, UND))
+ p++, q = index (p, '\'');
+ }
+ if (q)
+ *q = 0, dem = demangled_hash_lookup (p, false);
+ if (dem)
+ sym = symbol_hash_lookup (dem->mangled, false);
+ }
+
+ if (sym && sym->tweaked)
+ {
+ fclose (stream);
+ return 0;
+ }
+ if (sym && !sym->tweaking)
+ {
+ if (tlink_verbose >= 2)
+ fprintf (stderr, "collect: tweaking %s in %s\n",
+ sym->root.string, sym->file->root.string);
+ sym->tweaking = 1;
+ file_push (sym->file);
+ }
+
+ obstack_free (&temporary_obstack, temporary_firstobj);
+ }
+
+ fclose (stream);
+ return (file_stack != NULL);
+}
+
+void
+do_tlink (ld_argv, object_lst)
+ char **ld_argv, **object_lst;
+{
+ int exit = tlink_execute ("ld", ld_argv, ldout);
+
+ tlink_init ();
+
+ if (exit)
+ {
+ int i = 0;
+
+ /* Until collect does a better job of figuring out which are object
+ files, assume that everything on the command line could be. */
+ if (read_repo_files (ld_argv))
+ while (exit && i++ < MAX_ITERATIONS)
+ {
+ if (tlink_verbose >= 3)
+ dump_file (ldout);
+ demangle_new_symbols ();
+ if (! scan_linker_output (ldout))
+ break;
+ if (! recompile_files ())
+ break;
+ if (tlink_verbose)
+ fprintf (stderr, "collect: relinking\n");
+ exit = tlink_execute ("ld", ld_argv, ldout);
+ }
+ }
+
+ dump_file (ldout);
+ unlink (ldout);
+ if (exit)
+ {
+ error ("ld returned %d exit status", exit);
+ collect_exit (exit);
+ }
+}
diff --git a/contrib/gcc/tm.texi b/contrib/gcc/tm.texi
index 85bdf3a..8265773 100644
--- a/contrib/gcc/tm.texi
+++ b/contrib/gcc/tm.texi
@@ -1,4 +1,4 @@
-@c Copyright (C) 1988, 1989, 1992, 1993, 1994 Free Software Foundation, Inc.
+@c Copyright (C) 1988,89,92,93,94,96,97,1998 Free Software Foundation, Inc.
@c This is part of the GCC manual.
@c For copying conditions, see the file gcc.texi.
@@ -55,9 +55,12 @@ A C expression which determines whether the option @samp{-@var{char}}
takes arguments. The value should be the number of arguments that
option takes--zero, for many options.
-By default, this macro is defined to handle the standard options
-properly. You need not define it unless you wish to add additional
-options which take arguments.
+By default, this macro is defined as
+@code{DEFAULT_SWITCH_TAKES_ARG}, which handles the standard options
+properly. You need not define @code{SWITCH_TAKES_ARG} unless you
+wish to add additional options which take arguments. Any redefinition
+should call @code{DEFAULT_SWITCH_TAKES_ARG} and then check for
+additional options.
@findex WORD_SWITCH_TAKES_ARG
@item WORD_SWITCH_TAKES_ARG (@var{name})
@@ -73,12 +76,27 @@ wish to add additional options which take arguments. Any redefinition
should call @code{DEFAULT_WORD_SWITCH_TAKES_ARG} and then check for
additional options.
+@findex SWITCH_CURTAILS_COMPILATION
+@item SWITCH_CURTAILS_COMPILATION (@var{char})
+A C expression which determines whether the option @samp{-@var{char}}
+stops compilation before the generation of an executable. The value is
+boolean, non-zero if the option does stop an executable from being
+generated, zero otherwise.
+
+By default, this macro is defined as
+@code{DEFAULT_SWITCH_CURTAILS_COMPILATION}, which handles the standard
+options properly. You need not define
+@code{SWITCH_CURTAILS_COMPILATION} unless you wish to add additional
+options which affect the generation of an executable. Any redefinition
+should call @code{DEFAULT_SWITCH_CURTAILS_COMPILATION} and then check
+for additional options.
+
@findex SWITCHES_NEED_SPACES
@item SWITCHES_NEED_SPACES
-A string-valued C expression which is nonempty if the linker needs a
-space between the @samp{-L} or @samp{-o} option and its argument.
+A string-valued C expression which enumerates the options for which
+the linker needs a space between the option and its argument.
-If this macro is not defined, the default value is 0.
+If this macro is not defined, the default value is @code{""}.
@findex CPP_SPEC
@item CPP_SPEC
@@ -197,6 +215,58 @@ the very end of the command given to the linker.
Do not define this macro if it does not need to do anything.
+@findex EXTRA_SPECS
+@item EXTRA_SPECS
+Define this macro to provide additional specifications to put in the
+@file{specs} file that can be used in various specifications like
+@code{CC1_SPEC}.
+
+The definition should be an initializer for an array of structures,
+containing a string constant, that defines the specification name, and a
+string constant that provides the specification.
+
+Do not define this macro if it does not need to do anything.
+
+@code{EXTRA_SPECS} is useful when an architecture contains several
+related targets, which have various @code{..._SPECS} which are similar
+to each other, and the maintainer would like one central place to keep
+these definitions.
+
+For example, the PowerPC System V.4 targets use @code{EXTRA_SPECS} to
+define either @code{_CALL_SYSV} when the System V calling sequence is
+used or @code{_CALL_AIX} when the older AIX-based calling sequence is
+used.
+
+The @file{config/rs6000/rs6000.h} target file defines:
+
+@example
+#define EXTRA_SPECS \
+ @{ "cpp_sysv_default", CPP_SYSV_DEFAULT @},
+
+#define CPP_SYS_DEFAULT ""
+@end example
+
+The @file{config/rs6000/sysv.h} target file defines:
+@smallexample
+#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"
+@end smallexample
+
+while the @file{config/rs6000/eabiaix.h} target file defines
+@code{CPP_SYSV_DEFAULT} as:
+
+@smallexample
+#undef CPP_SYSV_DEFAULT
+#define CPP_SYSV_DEFAULT "-D_CALL_AIX"
+@end smallexample
+
@findex LINK_LIBGCC_SPECIAL
@item LINK_LIBGCC_SPECIAL
Define this macro if the driver program should find the library
@@ -213,12 +283,21 @@ the argument @samp{-lgcc} to tell the linker to do the search.
This macro is similar to @code{LINK_LIBGCC_SPECIAL}, except that it does
not affect @samp{-L} options.
+@findex LINK_COMMAND_SPEC
+@item LINK_COMMAND_SPEC
+A C string constant giving the complete command line need to execute the
+linker. When you do this, you will need to update your port each time a
+change is made to the link command line within @file{gcc.c}. Therefore,
+define this macro only if you need to completely redefine the command
+line for invoking the linker and there is no other way to accomplish
+the effect you need.
+
@findex MULTILIB_DEFAULTS
@item MULTILIB_DEFAULTS
Define this macro as a C expression for the initializer of an array of
string to tell the driver program which options are defaults for this
target and thus do not need to be handled specially when using
-@code{MULTILIB_OPTIONS}.
+@code{MULTILIB_OPTIONS}.
Do not define this macro if @code{MULTILIB_OPTIONS} is not defined in
the target makefile fragment or if none of the options listed in
@@ -265,7 +344,7 @@ used, or when the compiler is built as a cross compiler.
@findex INIT_ENVIRONMENT
@item INIT_ENVIRONMENT
-Define this macro as a C string constant if you with to set environment
+Define this macro as a C string constant if you wish to set environment
variables for programs called by the driver, such as the assembler and
loader. The driver passes the value of this macro to @code{putenv} to
initialize the necessary environment variables.
@@ -299,11 +378,17 @@ try when searching for header files.
Cross compilers do not use this macro and do not search either
@file{/usr/include} or its replacement.
+@findex STANDARD_INCLUDE_COMPONENT
+@item STANDARD_INCLUDE_COMPONENT
+The ``component'' corresponding to @code{STANDARD_INCLUDE_DIR}.
+See @code{INCLUDE_DEFAULTS}, below, for the description of components.
+If you do not define this macro, no component is used.
+
@findex INCLUDE_DEFAULTS
@item INCLUDE_DEFAULTS
Define this macro if you wish to override the entire default search path
-for include files. The default search path includes
-@code{GCC_INCLUDE_DIR}, @code{LOCAL_INCLUDE_DIR},
+for include files. For a native compiler, the default search path
+usually consists of @code{GCC_INCLUDE_DIR}, @code{LOCAL_INCLUDE_DIR},
@code{SYSTEM_INCLUDE_DIR}, @code{GPLUSPLUS_INCLUDE_DIR}, and
@code{STANDARD_INCLUDE_DIR}. In addition, @code{GPLUSPLUS_INCLUDE_DIR}
and @code{GCC_INCLUDE_DIR} are defined automatically by @file{Makefile},
@@ -311,19 +396,28 @@ and specify private search areas for GCC. The directory
@code{GPLUSPLUS_INCLUDE_DIR} is used only for C++ programs.
The definition should be an initializer for an array of structures.
-Each array element should have two elements: the directory name (a
-string constant) and a flag for C++-only directories. Mark the end of
-the array with a null element. For example, here is the definition used
-for VMS:
+Each array element should have four elements: the directory name (a
+string constant), the component name, and flag for C++-only directories,
+and a flag showing that the includes in the directory don't need to be
+wrapped in @code{extern @samp{C}} when compiling C++. Mark the end of
+the array with a null element.
+
+The component name denotes what GNU package the include file is part of,
+if any, in all upper-case letters. For example, it might be @samp{GCC}
+or @samp{BINUTILS}. If the package is part of the a vendor-supplied
+operating system, code the component name as @samp{0}.
+
+
+For example, here is the definition used for VAX/VMS:
@example
#define INCLUDE_DEFAULTS \
@{ \
- @{ "GNU_GXX_INCLUDE:", 1@}, \
- @{ "GNU_CC_INCLUDE:", 0@}, \
- @{ "SYS$SYSROOT:[SYSLIB.]", 0@}, \
- @{ ".", 0@}, \
- @{ 0, 0@} \
+ @{ "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@} \
@}
@end example
@end table
@@ -452,10 +546,13 @@ bits in @code{target_flags}. Its definition is an initializer
with a subgrouping for each command option.
Each subgrouping contains a string constant, that defines the option
-name, and a number, which contains the bits to set in
-@code{target_flags}. A negative number says to clear bits instead;
-the negative of the number is which bits to clear. The actual option
-name is made by appending @samp{-m} to the specified name.
+name, a number, which contains the bits to set in
+@code{target_flags}, and a second string which is the description
+displayed by --help. If the number is negative then the bits specified
+by the number are cleared instead of being set. If the description
+string is present but empty, then no help information will be displayed
+for that option, but it will not count as an undocumented option. The
+actual option name is made by appending @samp{-m} to the specified name.
One of the subgroupings should have a null string. The number in
this grouping is the default value for @code{target_flags}. Any
@@ -466,31 +563,31 @@ with opposite meanings, and picks the latter as the default:
@smallexample
#define TARGET_SWITCHES \
- @{ @{ "68020", 1@}, \
- @{ "68000", -1@}, \
- @{ "", 1@}@}
+ @{ @{ "68020", 1, "" @}, \
+ @{ "68000", -1, "Compile for the 68000" @}, \
+ @{ "", 1, "" @}@}
@end smallexample
@findex TARGET_OPTIONS
@item TARGET_OPTIONS
This macro is similar to @code{TARGET_SWITCHES} but defines names of command
options that have values. Its definition is an initializer with a
-subgrouping for each command option.
+subgrouping for each command option.
Each subgrouping contains a string constant, that defines the fixed part
-of the option name, and the address of a variable. The variable, type
-@code{char *}, is set to the variable part of the given option if the fixed
-part matches. The actual option name is made by appending @samp{-m} to the
-specified name.
+of the option name, the address of a variable, and a description string.
+The variable, type @code{char *}, is set to the variable part of the
+given option if the fixed part matches. The actual option name is made
+by appending @samp{-m} to the specified name.
Here is an example which defines @samp{-mshort-data-@var{number}}. If the
given option is @samp{-mshort-data-512}, the variable @code{m88k_short_data}
-will be set to the string @code{"512"}.
+will be set to the string @code{"512"}.
@smallexample
extern char *m88k_short_data;
#define TARGET_OPTIONS \
- @{ @{ "short-data-", &m88k_short_data @} @}
+ @{ @{ "short-data-", &m88k_short_data, "Specify the size of the short data section" @} @}
@end smallexample
@findex TARGET_VERSION
@@ -521,7 +618,7 @@ Don't use this macro to turn on various extra optimizations for
@samp{-O}. That is what @code{OPTIMIZATION_OPTIONS} is for.
@findex OPTIMIZATION_OPTIONS
-@item OPTIMIZATION_OPTIONS (@var{level})
+@item OPTIMIZATION_OPTIONS (@var{level}, @var{size})
Some machines may desire to change what optimizations are performed for
various optimization levels. This macro, if defined, is executed once
just after the optimization level is determined and before the remainder
@@ -531,10 +628,12 @@ used as the default values for the other command line options.
@var{level} is the optimization level specified; 2 if @samp{-O2} is
specified, 1 if @samp{-O} is specified, and 0 if neither is specified.
+@var{size} is non-zero if @samp{-Os} is specified and zero otherwise.
+
You should not use this macro to change options that are not
machine-specific. These should uniformly selected by the same
optimization level on all supported machines. Use this macro to enable
-machbine-specific optimizations.
+machine-specific optimizations.
@strong{Do not examine @code{write_symbols} in
this macro!} The debugging options are not supposed to alter the
@@ -632,9 +731,9 @@ you must define @code{POINTERS_EXTEND_UNSIGNED}.
@findex POINTERS_EXTEND_UNSIGNED
@item POINTERS_EXTEND_UNSIGNED
-A C expression whose value is nonzero if pointers that need to be
-extended from being @code{POINTER_SIZE} bits wide to @code{Pmode}
-are sign-extended and zero if they are zero-extended.
+A C expression whose value is nonzero if pointers that need to be
+extended from being @code{POINTER_SIZE} bits wide to @code{Pmode} are to
+be zero-extended and zero if they are to be sign-extended.
You need not define this macro if the @code{POINTER_SIZE} is equal
to the width of @code{Pmode}.
@@ -665,7 +764,7 @@ Do not define this macro if it would never modify @var{m}.
@findex PROMOTE_FUNCTION_ARGS
@item PROMOTE_FUNCTION_ARGS
Define this macro if the promotion described by @code{PROMOTE_MODE}
-should also be done for outgoing function arguments.
+should also be done for outgoing function arguments.
@findex PROMOTE_FUNCTION_RETURN
@item PROMOTE_FUNCTION_RETURN
@@ -709,12 +808,26 @@ Alignment required for a function entry point, in bits.
@item BIGGEST_ALIGNMENT
Biggest alignment that any data type can require on this machine, in bits.
+@findex MINIMUM_ATOMIC_ALIGNMENT
+@item MINIMUM_ATOMIC_ALIGNMENT
+If defined, the smallest alignment, in bits, that can be given to an
+object that can be referenced in one operation, without disturbing any
+nearby object. Normally, this is @code{BITS_PER_UNIT}, but may be larger
+on machines that don't have byte or half-word store operations.
+
@findex BIGGEST_FIELD_ALIGNMENT
@item BIGGEST_FIELD_ALIGNMENT
Biggest alignment that any structure field can require on this machine,
in bits. If defined, this overrides @code{BIGGEST_ALIGNMENT} for
structure fields only.
+@findex ADJUST_FIELD_ALIGN
+@item ADJUST_FIELD_ALIGN (@var{field}, @var{computed})
+An expression for the alignment of a structure field @var{field} if the
+alignment computed in the usual way is @var{computed}. GNU CC uses
+this value instead of the value in @code{BIGGEST_ALIGNMENT} or
+@code{BIGGEST_FIELD_ALIGNMENT}, if defined, for structure fields only.
+
@findex MAX_OFILE_ALIGNMENT
@item MAX_OFILE_ALIGNMENT
Biggest alignment supported by the object file format of this machine.
@@ -724,9 +837,9 @@ the default value is @code{BIGGEST_ALIGNMENT}.
@findex DATA_ALIGNMENT
@item DATA_ALIGNMENT (@var{type}, @var{basic-align})
-If defined, a C expression to compute the alignment for a static
-variable. @var{type} is the data type, and @var{basic-align} is the
-alignment that the object would ordinarily have. The value of this
+If defined, a C expression to compute the alignment for a variables in
+the static store. @var{type} is the data type, and @var{basic-align} is
+the alignment that the object would ordinarily have. The value of this
macro is used instead of that alignment to align the object.
If this macro is not defined, then @var{basic-align} is used.
@@ -845,7 +958,7 @@ aligning a bitfield within the structure.
@findex ROUND_TYPE_SIZE
@item ROUND_TYPE_SIZE (@var{struct}, @var{size}, @var{align})
-Define this macro as an expression for the overall size of a structure
+Define this macro as an expression for the overall size of a structure
(given by @var{struct} as a tree node) when the size computed from the
fields is @var{size} and the alignment is @var{align}.
@@ -853,7 +966,7 @@ The default is to round @var{size} up to a multiple of @var{align}.
@findex ROUND_TYPE_ALIGN
@item ROUND_TYPE_ALIGN (@var{struct}, @var{computed}, @var{specified})
-Define this macro as an expression for the alignment of a structure
+Define this macro as an expression for the alignment of a structure
(given by @var{struct} as a tree node) if the alignment computed in the
usual way is @var{computed} and the alignment explicitly specified was
@var{specified}.
@@ -869,6 +982,30 @@ this size or smaller can be used for structures and unions with the
appropriate sizes. If this macro is undefined, @code{GET_MODE_BITSIZE
(DImode)} is assumed.
+@findex STACK_SAVEAREA_MODE
+@item STACK_SAVEAREA_MODE (@var{save_level})
+If defined, an expression of type @code{enum machine_mode} that
+specifies the mode of the save area operand of a
+@code{save_stack_@var{level}} named pattern (@pxref{Standard Names}).
+@var{save_level} is one of @code{SAVE_BLOCK}, @code{SAVE_FUNCTION}, or
+@code{SAVE_NONLOCAL} and selects which of the three named patterns is
+having its mode specified.
+
+You need not define this macro if it always returns @code{Pmode}. You
+would most commonly define this macro if the
+@code{save_stack_@var{level}} patterns need to support both a 32- and a
+64-bit mode.
+
+@findex STACK_SIZE_MODE
+@item STACK_SIZE_MODE
+If defined, an expression of type @code{enum machine_mode} that
+specifies the mode of the size increment operand of an
+@code{allocate_stack} named pattern (@pxref{Standard Names}).
+
+You need not define this macro if it always returns @code{word_mode}.
+You would most commonly define this macro if the @code{allocate_stack}
+pattern needs to support both a 32- and a 64-bit mode.
+
@findex CHECK_FLOAT_VALUE
@item CHECK_FLOAT_VALUE (@var{mode}, @var{value}, @var{overflow})
A C statement to validate the value @var{value} (of type
@@ -913,6 +1050,20 @@ supported machines, new codes should be defined for them.
The ordering of the component words of floating point values stored in
memory is controlled by @code{FLOAT_WORDS_BIG_ENDIAN} for the target
machine and @code{HOST_FLOAT_WORDS_BIG_ENDIAN} for the host.
+
+@findex DEFAULT_VTABLE_THUNKS
+@item DEFAULT_VTABLE_THUNKS
+GNU CC supports two ways of implementing C++ vtables: traditional or with
+so-called ``thunks''. The flag @samp{-fvtable-thunk} chooses between them.
+Define this macro to be a C expression for the default value of that flag.
+If @code{DEFAULT_VTABLE_THUNKS} is 0, GNU CC uses the traditional
+implementation by default. The ``thunk'' implementation is more efficient
+(especially if you have provided an implementation of
+@code{ASM_OUTPUT_MI_THUNK}, see @ref{Function Entry}), but is not binary
+compatible with code compiled using the traditional implementation.
+If you are writing a new ports, define @code{DEFAULT_VTABLE_THUNKS} to 1.
+
+If you do not define this macro, the default for @samp{-fvtable-thunk} is 0.
@end table
@node Type Layout
@@ -995,6 +1146,14 @@ A C expression for the size in bits of the type @code{long double} on
the target machine. If you don't define this, the default is two
words.
+@findex WIDEST_HARDWARE_FP_SIZE
+@item WIDEST_HARDWARE_FP_SIZE
+A C expression for the size in bits of the widest floating-point format
+supported by the hardware. If you define this macro, you must specify a
+value less than or equal to the value of @code{LONG_DOUBLE_TYPE_SIZE}.
+If you do not define this macro, the value of @code{LONG_DOUBLE_TYPE_SIZE}
+is the default.
+
@findex DEFAULT_SIGNED_CHAR
@item DEFAULT_SIGNED_CHAR
An expression whose value is 1 or 0, according to whether the type
@@ -1004,7 +1163,7 @@ and @samp{-funsigned-char}.
@findex DEFAULT_SHORT_ENUMS
@item DEFAULT_SHORT_ENUMS
-A C expression to determine whether to give an @code{enum} type
+A C expression to determine whether to give an @code{enum} type
only as many bytes as it takes to represent the range of possible values
of that type. A nonzero value means to do that; a zero value means all
@code{enum} types should be allocated like @code{int}.
@@ -1188,7 +1347,7 @@ on target flags.
You need not define this macro if it has no work to do.
@cindex disabling certain registers
-@cindex controlling register usage
+@cindex controlling register usage
If the usage of an entire class of registers depends on the target
flags, you may indicate this to GCC by using this macro to modify
@code{fixed_regs} and @code{call_used_regs} to 1 for each of the
@@ -1255,7 +1414,7 @@ One use of this macro is on machines where the highest numbered
registers must always be saved and the save-multiple-registers
instruction supports only sequences of consecutive registers. On such
machines, define @code{REG_ALLOC_ORDER} to be an initializer that lists
-the highest numbered allocatable register first.
+the highest numbered allocable register first.
@findex ORDER_REGS_FOR_LOCAL_ALLOC
@item ORDER_REGS_FOR_LOCAL_ALLOC
@@ -1295,6 +1454,17 @@ definition of this macro is
/ UNITS_PER_WORD))
@end smallexample
+@findex ALTER_HARD_SUBREG
+@item ALTER_HARD_SUBREG (@var{tgt_mode}, @var{word}, @var{src_mode}, @var{regno})
+A C expression that returns an adjusted hard register number for
+
+@smallexample
+(subreg:@var{tgt_mode} (reg:@var{src_mode} @var{regno}) @var{word})
+@end smallexample
+
+This may be needed if the target machine has mixed sized big-endian
+registers, like Sparc v9.
+
@findex HARD_REGNO_MODE_OK
@item HARD_REGNO_MODE_OK (@var{regno}, @var{mode})
A C expression that is nonzero if it is permissible to store a value
@@ -1306,30 +1476,21 @@ are equivalent, a suitable definition is
#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
@end smallexample
-It is not necessary for this macro to check for the numbers of fixed
-registers, because the allocation mechanism considers them to be always
-occupied.
+You need not include code to check for the numbers of fixed registers,
+because the allocation mechanism considers them to be always occupied.
@cindex register pairs
On some machines, double-precision values must be kept in even/odd
-register pairs. The way to implement that is to define this macro
-to reject odd register numbers for such modes.
-
-@ignore
-@c I think this is not true now
-GNU CC assumes that it can always move values between registers and
-(suitably addressed) memory locations. If it is impossible to move a
-value of a certain mode between memory and certain registers, then
-@code{HARD_REGNO_MODE_OK} must not allow this mode in those registers.
-@end ignore
+register pairs. You can implement that by defining this macro to reject
+odd register numbers for such modes.
The minimum requirement for a mode to be OK in a register is that the
@samp{mov@var{mode}} instruction pattern support moves between the
-register and any other hard register for which the mode is OK; and that
-moving a value into the register and back out not alter it.
+register and other hard register in the same class and that moving a
+value into the register and back out not alter it.
-Since the same instruction used to move @code{SImode} will work for all
-narrower integer modes, it is not necessary on any machine for
+Since the same instruction used to move @code{word_mode} will work for
+all narrower integer modes, it is not necessary on any machine for
@code{HARD_REGNO_MODE_OK} to distinguish between these modes, provided
you define patterns @samp{movhi}, etc., to take advantage of this. This
is useful because of the interaction between @code{HARD_REGNO_MODE_OK}
@@ -1367,14 +1528,25 @@ be used unless some pattern's constraint asks for one.
@findex MODES_TIEABLE_P
@item MODES_TIEABLE_P (@var{mode1}, @var{mode2})
-A C expression that is nonzero if it is desirable to choose register
-allocation so as to avoid move instructions between a value of mode
-@var{mode1} and a value of mode @var{mode2}.
+A C expression that is nonzero if a value of mode
+@var{mode1} is accessible in mode @var{mode2} without copying.
If @code{HARD_REGNO_MODE_OK (@var{r}, @var{mode1})} and
-@code{HARD_REGNO_MODE_OK (@var{r}, @var{mode2})} are ever different
-for any @var{r}, then @code{MODES_TIEABLE_P (@var{mode1},
-@var{mode2})} must be zero.
+@code{HARD_REGNO_MODE_OK (@var{r}, @var{mode2})} are always the same for
+any @var{r}, then @code{MODES_TIEABLE_P (@var{mode1}, @var{mode2})}
+should be nonzero. If they differ for any @var{r}, you should define
+this macro to return zero unless some other mechanism ensures the
+accessibility of the value in a narrower mode.
+
+You should define this macro to return nonzero in as many cases as
+possible since doing so will allow GNU CC to perform better register
+allocation.
+
+@findex AVOID_CCMODE_COPIES
+@item AVOID_CCMODE_COPIES
+Define this macro if the compiler should avoid copies to/from @code{CCmode}
+registers. You should only define this macro if support fo copying to/from
+@code{CCmode} is incomplete.
@end table
@node Leaf Functions
@@ -1437,7 +1609,7 @@ treat leaf functions specially. It can test the C variable
@code{leaf_function} is defined only if @code{LEAF_REGISTERS} is
defined.)
@c changed this to fix overfull. ALSO: why the "it" at the beginning
-@c of the next paragraph?! --mew 2feb93
+@c of the next paragraph?! --mew 2feb93
@node Stack Registers
@subsection Registers That Form a Stack
@@ -1475,7 +1647,7 @@ be required to generate correct code for the 80387 coprocessor of the
removed in a later version of the compiler. Don't use them!
@table @code
-@findex OVERLAPPING_REGNO_P
+@findex OVERLAPPING_REGNO_P
@item OVERLAPPING_REGNO_P (@var{regno})
If defined, this is a C expression whose value is nonzero if hard
register number @var{regno} is an overlapping register. This means a
@@ -1504,12 +1676,9 @@ it is best for the RTL expression to show all the activity.
@cindex death notes
@findex PRESERVE_DEATH_INFO_REGNO_P
@item PRESERVE_DEATH_INFO_REGNO_P (@var{regno})
-If defined, this is a C expression whose value is nonzero if accurate
+If defined, this is a C expression whose value is nonzero if correct
@code{REG_DEAD} notes are needed for hard register number @var{regno}
-at the time of outputting the assembler code. When this is so, a few
-optimizations that take place after register allocation and could
-invalidate the death notes are not done when this register is
-involved.
+after reload.
You would arrange to preserve death info for a register when some of the
code in the machine description which is executed to write the assembler
@@ -1518,8 +1687,10 @@ hardware feature which GNU CC thinks of as a register is not actually a
register of the usual sort. (It might, for example, be a hardware
stack.)
+It is also useful for peepholes and linker relaxation.
+
If this macro is not defined, it means that no death notes need to be
-preserved. This is the usual situation.
+preserved, and some may even be incorrect. This is the usual situation.
@end table
@node Register Classes
@@ -1623,7 +1794,7 @@ Then the integers are replaced by sub-initializers, braced groupings containing
several integers. Each sub-initializer must be suitable as an initializer
for the type @code{HARD_REG_SET} which is defined in @file{hard-reg-set.h}.
-@findex REGNO_REG_CLASS
+@findex REGNO_REG_CLASS
@item REGNO_REG_CLASS (@var{regno})
A C expression whose value is a register class containing hard register
@var{regno}. In general there is more than one such class; choose a class
@@ -1659,6 +1830,15 @@ suitable for use as a base register in operand addresses. It may be
either a suitable hard register or a pseudo register that has been
allocated such a hard register.
+@findex REGNO_MODE_OK_FOR_BASE_P
+@item REGNO_MODE_OK_FOR_BASE_P (@var{num}, @var{mode})
+A C expression that is just like @code{REGNO_OK_FOR_BASE_P}, except that
+that expression may examine the mode of the memory reference in
+@var{mode}. You should define this macro if the mode of the memory
+reference affects whether a register may be used as a base register. If
+you define this macro, the compiler will use it instead of
+@code{REGNO_OK_FOR_BASE_P}.
+
@findex REGNO_OK_FOR_INDEX_P
@item REGNO_OK_FOR_INDEX_P (@var{num})
A C expression which is nonzero if register number @var{num} is
@@ -1681,7 +1861,7 @@ A C expression that places additional restrictions on the register class
to use when it is necessary to copy value @var{x} into a register in class
@var{class}. The value is a register class; perhaps @var{class}, or perhaps
another, smaller class. On many machines, the following definition is
-safe:
+safe:
@example
#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS
@@ -1763,7 +1943,7 @@ intermediate register), you should define patterns for
(@pxref{Standard Names}. These patterns, which will normally be
implemented with a @code{define_expand}, should be similar to the
@samp{mov@var{m}} patterns, except that operand 2 is the scratch
-register.
+register.
Define constraints for the reload register and scratch register that
contain a single register class. If the original reload register (whose
@@ -1794,7 +1974,7 @@ those machines to be a C expression that is non-zero if objects of mode
class @var{class2} by storing a register of @var{class1} into memory
and loading that memory location into a register of @var{class2}.
-Do not define this macro if its value would always be zero.
+Do not define this macro if its value would always be zero.
@findex SECONDARY_MEMORY_NEEDED_RTX
@item SECONDARY_MEMORY_NEEDED_RTX (@var{mode})
@@ -1839,16 +2019,17 @@ some machines have so few registers of certain classes that there
would not be enough registers to use as spill registers if this were
done.
-Define @code{SMALL_REGISTER_CLASSES} on these machines. When it is
-defined, the compiler allows registers explicitly used in the rtl to be
-used as spill registers but avoids extending the lifetime of these
-registers.
+Define @code{SMALL_REGISTER_CLASSES} to be an expression with a non-zero
+value on these machines. When this macro has a non-zero value, the
+compiler allows registers explicitly used in the rtl to be used as spill
+registers but avoids extending the lifetime of these registers.
-It is always safe to define this macro, but if you unnecessarily define
-it, you will reduce the amount of optimizations that can be performed in
-some cases. If you do not define this macro when it is required, the
-compiler will run out of spill registers and print a fatal error
-message. For most machines, you should not define this macro.
+It is always safe to define this macro with a non-zero value, but if you
+unnecessarily define it, you will reduce the amount of optimizations
+that can be performed in some cases. If you do not define this macro
+with a non-zero value when it is required, the compiler will run out of
+spill registers and print a fatal error message. For most machines, you
+should not define this macro at all.
@findex CLASS_LIKELY_SPILLED_P
@item CLASS_LIKELY_SPILLED_P (@var{class})
@@ -1858,7 +2039,7 @@ registers of @var{class} are needed for spill registers.
The default value of this macro returns 1 if @var{class} has exactly one
register and zero otherwise. On most machines, this default should be
-used. Only define this macro to some other expression if pseudo
+used. Only define this macro to some other expression if pseudos
allocated by @file{local-alloc.c} end up in memory because their hard
registers were needed for spill registers. If this macro returns nonzero
for those classes, those pseudos will only be allocated by
@@ -1900,16 +2081,19 @@ letters.
@table @code
@findex CONST_OK_FOR_LETTER_P
@item CONST_OK_FOR_LETTER_P (@var{value}, @var{c})
-A C expression that defines the machine-dependent operand constraint letters
-that specify particular ranges of integer values. If @var{c} is one
-of those letters, the expression should check that @var{value}, an integer,
-is in the appropriate range and return 1 if so, 0 otherwise. If @var{c} is
-not one of those letters, the value should be 0 regardless of @var{value}.
+A C expression that defines the machine-dependent operand constraint
+letters (@samp{I}, @samp{J}, @samp{K}, @dots{} @samp{P}) that specify
+particular ranges of integer values. If @var{c} is one of those
+letters, the expression should check that @var{value}, an integer, is in
+the appropriate range and return 1 if so, 0 otherwise. If @var{c} is
+not one of those letters, the value should be 0 regardless of
+@var{value}.
@findex CONST_DOUBLE_OK_FOR_LETTER_P
@item CONST_DOUBLE_OK_FOR_LETTER_P (@var{value}, @var{c})
A C expression that defines the machine-dependent operand constraint
-letters that specify particular ranges of @code{const_double} values.
+letters that specify particular ranges of @code{const_double} values
+(@samp{G} or @samp{H}).
If @var{c} is one of those letters, the expression should check that
@var{value}, an RTX of code @code{const_double}, is in the appropriate
@@ -1924,13 +2108,13 @@ between these kinds.
@findex EXTRA_CONSTRAINT
@item EXTRA_CONSTRAINT (@var{value}, @var{c})
A C expression that defines the optional machine-dependent constraint
-letters that can be used to segregate specific types of operands,
-usually memory references, for the target machine. Normally this macro
-will not be defined. If it is required for a particular target machine,
-it should return 1 if @var{value} corresponds to the operand type
-represented by the constraint letter @var{c}. If @var{c} is not defined
-as an extra constraint, the value returned should be 0 regardless of
-@var{value}.
+letters (@samp{Q}, @samp{R}, @samp{S}, @samp{T}, @samp{U}) that can
+be used to segregate specific types of operands, usually memory
+references, for the target machine. Normally this macro will not be
+defined. If it is required for a particular target machine, it should
+return 1 if @var{value} corresponds to the operand type represented by
+the constraint letter @var{c}. If @var{c} is not defined as an extra
+constraint, the value returned should be 0 regardless of @var{value}.
For example, on the ROMP, load instructions cannot have their output in r0 if
the memory reference contains a symbolic address. Constraint letter
@@ -1950,8 +2134,9 @@ This describes the stack layout and calling conventions.
@menu
* Frame Layout::
+* Stack Checking::
* Frame Registers::
-* Elimination::
+* Elimination::
* Stack Arguments::
* Register Arguments::
* Scalar Return::
@@ -2013,7 +2198,7 @@ the first location at which outgoing arguments are placed.
@item FIRST_PARM_OFFSET (@var{fundecl})
Offset from the argument pointer register to the first argument's
address. On some machines it may depend on the data type of the
-function.
+function.
If @code{ARGS_GROW_DOWNWARD}, this is the offset to the location above
the first argument's address.
@@ -2039,33 +2224,149 @@ of @var{frameaddr}---that is, the stack frame address is also the
address of the stack word that points to the previous frame.
@findex SETUP_FRAME_ADDRESSES
-@item SETUP_FRAME_ADDRESSES ()
+@item SETUP_FRAME_ADDRESSES
If defined, a C expression that produces the machine-specific code to
setup the stack so that arbitrary frames can be accessed. For example,
on the Sparc, we must flush all of the register windows to the stack
-before we can access arbitrary stack frames.
-This macro will seldom need to be defined.
+before we can access arbitrary stack frames. You will seldom need to
+define this macro.
+
+@findex BUILTIN_SETJMP_FRAME_VALUE
+@item BUILTIN_SETJMP_FRAME_VALUE
+If defined, a C expression that contains an rtx that is used to store
+the address of the current frame into the built in @code{setjmp} buffer.
+The default value, @code{virtual_stack_vars_rtx}, is correct for most
+machines. One reason you may need to define this macro is if
+@code{hard_frame_pointer_rtx} is the appropriate value on your machine.
@findex RETURN_ADDR_RTX
@item RETURN_ADDR_RTX (@var{count}, @var{frameaddr})
A C expression whose value is RTL representing the value of the return
-address for the frame @var{count} steps up from the current frame.
-@var{frameaddr} is the frame pointer of the @var{count} frame, or
-the frame pointer of the @var{count} @minus{} 1 frame if
+address for the frame @var{count} steps up from the current frame, after
+the prologue. @var{frameaddr} is the frame pointer of the @var{count}
+frame, or the frame pointer of the @var{count} @minus{} 1 frame if
@code{RETURN_ADDR_IN_PREVIOUS_FRAME} is defined.
+The value of the expression must always be the correct address when
+@var{count} is zero, but may be @code{NULL_RTX} if there is not way to
+determine the return address of other frames.
+
@findex RETURN_ADDR_IN_PREVIOUS_FRAME
@item RETURN_ADDR_IN_PREVIOUS_FRAME
Define this if the return address of a particular stack frame is accessed
from the frame pointer of the previous stack frame.
+
+@findex INCOMING_RETURN_ADDR_RTX
+@item INCOMING_RETURN_ADDR_RTX
+A C expression whose value is RTL representing the location of the
+incoming return address at the beginning of any function, before the
+prologue. This RTL is either a @code{REG}, indicating that the return
+value is saved in @samp{REG}, or a @code{MEM} representing a location in
+the stack.
+
+You only need to define this macro if you want to support call frame
+debugging information like that provided by DWARF 2.
+
+@findex INCOMING_FRAME_SP_OFFSET
+@item INCOMING_FRAME_SP_OFFSET
+A C expression whose value is an integer giving the offset, in bytes,
+from the value of the stack pointer register to the top of the stack
+frame at the beginning of any function, before the prologue. The top of
+the frame is defined to be the value of the stack pointer in the
+previous frame, just before the call instruction.
+
+You only need to define this macro if you want to support call frame
+debugging information like that provided by DWARF 2.
+@end table
+
+@node Stack Checking
+@subsection Specifying How Stack Checking is Done
+
+GNU CC will check that stack references are within the boundaries of
+the stack, if the @samp{-fstack-check} is specified, in one of three ways:
+
+@enumerate
+@item
+If the value of the @code{STACK_CHECK_BUILTIN} macro is nonzero, GNU CC
+will assume that you have arranged for stack checking to be done at
+appropriate places in the configuration files, e.g., in
+@code{FUNCTION_PROLOGUE}. GNU CC will do not other special processing.
+
+@item
+If @code{STACK_CHECK_BUILTIN} is zero and you defined a named pattern
+called @code{check_stack} in your @file{md} file, GNU CC will call that
+pattern with one argument which is the address to compare the stack
+value against. You must arrange for this pattern to report an error if
+the stack pointer is out of range.
+
+@item
+If neither of the above are true, GNU CC will generate code to periodically
+``probe'' the stack pointer using the values of the macros defined below.
+@end enumerate
+
+Normally, you will use the default values of these macros, so GNU CC
+will use the third approach.
+
+@table @code
+@findex STACK_CHECK_BUILTIN
+@item STACK_CHECK_BUILTIN
+A nonzero value if stack checking is done by the configuration files in a
+machine-dependent manner. You should define this macro if stack checking
+is require by the ABI of your machine or if you would like to have to stack
+checking in some more efficient way than GNU CC's portable approach.
+The default value of this macro is zero.
+
+@findex STACK_CHECK_PROBE_INTERVAL
+@item STACK_CHECK_PROBE_INTERVAL
+An integer representing the interval at which GNU CC must generate stack
+probe instructions. You will normally define this macro to be no larger
+than the size of the ``guard pages'' at the end of a stack area. The
+default value of 4096 is suitable for most systems.
+
+@findex STACK_CHECK_PROBE_LOAD
+@item STACK_CHECK_PROBE_LOAD
+A integer which is nonzero if GNU CC should perform the stack probe
+as a load instruction and zero if GNU CC should use a store instruction.
+The default is zero, which is the most efficient choice on most systems.
+
+@findex STACK_CHECK_PROTECT
+@item STACK_CHECK_PROTECT
+The number of bytes of stack needed to recover from a stack overflow,
+for languages where such a recovery is supported. The default value of
+75 words should be adequate for most machines.
+
+@findex STACK_CHECK_MAX_FRAME_SIZE
+@item STACK_CHECK_MAX_FRAME_SIZE
+The maximum size of a stack frame, in bytes. GNU CC will generate probe
+instructions in non-leaf functions to ensure at least this many bytes of
+stack are available. If a stack frame is larger than this size, stack
+checking will not be reliable and GNU CC will issue a warning. The
+default is chosen so that GNU CC only generates one instruction on most
+systems. You should normally not change the default value of this macro.
+
+@findex STACK_CHECK_FIXED_FRAME_SIZE
+@item STACK_CHECK_FIXED_FRAME_SIZE
+GNU CC uses this value to generate the above warning message. It
+represents the amount of fixed frame used by a function, not including
+space for any callee-saved registers, temporaries and user variables.
+You need only specify an upper bound for this amount and will normally
+use the default of four words.
+
+@findex STACK_CHECK_MAX_VAR_SIZE
+@item STACK_CHECK_MAX_VAR_SIZE
+The maximum size, in bytes, of an object that GNU CC will place in the
+fixed area of the stack frame when the user specifies
+@samp{-fstack-check}.
+GNU CC computed the default from the values of the above macros and you will
+normally not need to override that default.
@end table
@need 2000
@node Frame Registers
-@subsection Registers That Address the Stack Frame
+@subsection Registers That Address the Stack Frame
@c prevent bad page break with this line
-This discusses registers that address the stack frame.
+This discusses registers that address the stack frame.
@table @code
@findex STACK_POINTER_REGNUM
@@ -2089,7 +2390,7 @@ allocation has been done (for example, because the saved registers are
between these two locations). On those machines, define
@code{FRAME_POINTER_REGNUM} the number of a special, fixed register to
be used internally until the offset is known, and define
-@code{HARD_FRAME_POINTER_REGNUM} to be actual the hard register number
+@code{HARD_FRAME_POINTER_REGNUM} to be the actual hard register number
used for the frame pointer.
You should define this macro only in the very rare circumstances when it
@@ -2114,6 +2415,18 @@ pointer register, then you must mark it as a fixed register according to
@code{FIXED_REGISTERS}, or arrange to be able to eliminate it
(@pxref{Elimination}).
+@findex RETURN_ADDRESS_POINTER_REGNUM
+@item RETURN_ADDRESS_POINTER_REGNUM
+The register number of the return address pointer register, which is used to
+access the current function's return address from the stack. On some
+machines, the return address is not at a fixed offset from the frame
+pointer or stack pointer or argument pointer. This register can be defined
+to point to the return address on the stack, and then be converted by
+@code{ELIMINABLE_REGS} into either the frame pointer or stack pointer.
+
+Do not define this macro unless there is no other way to get the return
+address from the stack.
+
@findex STATIC_CHAIN_REGNUM
@findex STATIC_CHAIN_INCOMING_REGNUM
@item STATIC_CHAIN_REGNUM
@@ -2371,11 +2684,10 @@ arguments that a function pops on returning, or 0 if the
function pops no arguments and the caller must therefore pop them all
after the function returns.
-@var{fundecl} is a C variable whose value is a tree node that
-describes the function in question. Normally it is a node of type
+@var{fundecl} is a C variable whose value is a tree node that describes
+the function in question. Normally it is a node of type
@code{FUNCTION_DECL} that describes the declaration of the function.
-From this it is possible to obtain the DECL_MACHINE_ATTRIBUTES of
-the function.
+From this you can obtain the DECL_MACHINE_ATTRIBUTES of the function.
@var{funtype} is a C variable whose value is a tree node that
describes the function in question. Normally it is a node of type
@@ -2383,7 +2695,7 @@ describes the function in question. Normally it is a node of type
From this it is possible to obtain the data types of the value and
arguments (if known).
-When a call to a library function is being considered, @var{funtype}
+When a call to a library function is being considered, @var{fundecl}
will contain an identifier node for the library function. Thus, if
you need to distinguish among various library functions, you can do so
by their names. Note that ``library function'' in this context means
@@ -2427,13 +2739,25 @@ the data type of the argument as a tree node or 0 if that is not known
which is 1 for an ordinary argument and 0 for nameless arguments that
correspond to @samp{@dots{}} in the called function's prototype.
-The value of the expression should either be a @code{reg} RTX for the
+The value of the expression is usually either a @code{reg} RTX for the
hard register in which to pass the argument, or zero to pass the
argument on the stack.
For machines like the Vax and 68000, where normally all arguments are
pushed, zero suffices as a definition.
+The value of the expression can also be a @code{parallel} RTX. This is
+used when an argument is passed in multiple locations. The mode of the
+of the @code{parallel} should be the mode of the entire argument. The
+@code{parallel} holds any number of @code{expr_list} pairs; each one
+describes where part of the argument is passed. In each @code{expr_list},
+the first operand can be either a @code{reg} RTX for the hard register
+in which to pass this part of the argument, or zero to pass the argument
+on the stack. If this operand is a @code{reg}, then the mode indicates
+how large this part of the argument is. The second operand of the
+@code{expr_list} is a @code{const_int} which gives the offset in bytes
+into the entire argument where this part starts.
+
@cindex @file{stdarg.h} and register arguments
The usual way to make the ANSI library @file{stdarg.h} work on a machine
where some arguments are usually passed in registers, is to cause
@@ -2450,6 +2774,13 @@ argument, the compiler will abort. If @code{REG_PARM_STACK_SPACE} is
defined, the argument will be computed in the stack and then loaded into
a register.
+@findex MUST_PASS_IN_STACK
+@item MUST_PASS_IN_STACK (@var{mode}, @var{type})
+Define as a C expression that evaluates to nonzero if we do not know how
+to pass TYPE solely in registers. The file @file{expr.h} defines a
+definition that is usually appropriate, refer to @file{expr.h} for additional
+documentation.
+
@findex FUNCTION_INCOMING_ARG
@item FUNCTION_INCOMING_ARG (@var{cum}, @var{mode}, @var{type}, @var{named})
Define this macro if the target machine has ``register windows'', so
@@ -2500,7 +2831,7 @@ definition of this macro might be
(CUM, MODE, TYPE, NAMED) \
MUST_PASS_IN_STACK (MODE, TYPE)
@end smallexample
-@c this is *still* too long. --mew 5feb93
+@c this is *still* too long. --mew 5feb93
@findex FUNCTION_ARG_CALLEE_COPIES
@item FUNCTION_ARG_CALLEE_COPIES (@var{cum}, @var{mode}, @var{type}, @var{named})
@@ -2528,12 +2859,17 @@ arguments are passed on the stack, there is no need to store anything in
should not be empty, so use @code{int}.
@findex INIT_CUMULATIVE_ARGS
-@item INIT_CUMULATIVE_ARGS (@var{cum}, @var{fntype}, @var{libname})
+@item INIT_CUMULATIVE_ARGS (@var{cum}, @var{fntype}, @var{libname}, @var{indirect})
A C statement (sans semicolon) for initializing the variable @var{cum}
for the state at the beginning of the argument list. The variable has
type @code{CUMULATIVE_ARGS}. The value of @var{fntype} is the tree node
for the data type of the function which will receive the args, or 0
-if the args are to a compiler support library function.
+if the args are to a compiler support library function. The value of
+@var{indirect} is nonzero when processing an indirect call, for example
+a call through a function pointer. The value of @var{indirect} is zero
+for a call to an explicitly named function, a library function call, or when
+@code{INIT_CUMULATIVE_ARGS} is used to find arguments for the function
+being compiled.
When processing a call to a compiler support library function,
@var{libname} identifies which one. It is a @code{symbol_ref} rtx which
@@ -2586,7 +2922,7 @@ constant size shorter than an @code{int}, and upward otherwise.
@findex FUNCTION_ARG_BOUNDARY
@item FUNCTION_ARG_BOUNDARY (@var{mode}, @var{type})
If defined, a C expression that gives the alignment boundary, in bits,
-of an argument with the specified mode and type. If it is not defined,
+of an argument with the specified mode and type. If it is not defined,
@code{PARM_BOUNDARY} is used for all arguments.
@findex FUNCTION_ARG_REGNO_P
@@ -2597,6 +2933,14 @@ register in which function arguments are sometimes passed. This does
the structure-value address. On many machines, no registers can be
used for this purpose since all function arguments are pushed on the
stack.
+
+@findex LOAD_ARGS_REVERSED
+@item LOAD_ARGS_REVERSED
+If defined, the order in which arguments are loaded into their
+respective argument registers is reversed so that the last
+argument is loaded first. This macro only effects arguments
+passed in registers.
+
@end table
@node Scalar Return
@@ -2611,7 +2955,7 @@ values---values that can fit in registers.
@table @code
@findex TRADITIONAL_RETURN_FLOAT
@item TRADITIONAL_RETURN_FLOAT
-Define this macro if @samp{-traditional} should not cause functions
+Define this macro if @samp{-traditional} should not cause functions
declared to return @code{float} to convert the value to @code{double}.
@findex FUNCTION_VALUE
@@ -2624,6 +2968,11 @@ On many machines, only the mode is relevant. (Actually, on most
machines, scalar values are returned in the same place regardless of
mode).@refill
+The value of the expression is usually a @code{reg} RTX for the hard
+register where the return value is stored. The value can also be a
+@code{parallel} RTX, if the return value is in multiple places. See
+@code{FUNCTION_ARG} for an explanation of the @code{parallel} form.
+
If @code{PROMOTE_FUNCTION_RETURN} is defined, you must apply the same
promotion rules specified in @code{PROMOTE_MODE} if @var{valtype} is a
scalar type.
@@ -2921,6 +3270,12 @@ frame pointers are maintained. It is never safe to delete a final
stack adjustment in a function that has no frame pointer, and the
compiler knows this regardless of @code{EXIT_IGNORE_STACK}.
+@findex EPILOGUE_USES
+@item EPILOGUE_USES (@var{regno})
+Define this macro as a C expression that is nonzero for registers are
+used by the epilogue or the @samp{return} pattern. The stack and frame
+pointer registers are already be assumed to be used as needed.
+
@findex FUNCTION_EPILOGUE
@item FUNCTION_EPILOGUE (@var{file}, @var{size})
A C compound statement that outputs the assembler code for exit from a
@@ -3000,6 +3355,40 @@ insns in this list, usually by calling @code{final_scan_insn}.
You need not define this macro if you did not define
@code{DELAY_SLOTS_FOR_EPILOGUE}.
+
+@findex ASM_OUTPUT_MI_THUNK
+@item ASM_OUTPUT_MI_THUNK (@var{file}, @var{thunk_fndecl}, @var{delta}, @var{function})
+A C compound statement that outputs the assembler code for a thunk
+function, used to implement C++ virtual function calls with multiple
+inheritance. The thunk acts as a wrapper around a virtual function,
+adjusting the implicit object parameter before handing control off to
+the real function.
+
+First, emit code to add the integer @var{delta} to the location that
+contains the incoming first argument. Assume that this argument
+contains a pointer, and is the one used to pass the @code{this} pointer
+in C++. This is the incoming argument @emph{before} the function prologue,
+e.g. @samp{%o0} on a sparc. The addition must preserve the values of
+all other incoming arguments.
+
+After the addition, emit code to jump to @var{function}, which is a
+@code{FUNCTION_DECL}. This is a direct pure jump, not a call, and does
+not touch the return address. Hence returning from @var{FUNCTION} will
+return to whoever called the current @samp{thunk}.
+
+The effect must be as if @var{function} had been called directly with
+the adjusted first argument. This macro is responsible for emitting all
+of the code for a thunk function; @code{FUNCTION_PROLOGUE} and
+@code{FUNCTION_EPILOGUE} are not invoked.
+
+The @var{thunk_fndecl} is redundant. (@var{delta} and @var{function}
+have already been extracted from it.) It might possibly be useful on
+some targets, but probably not.
+
+If you do not define this macro, the target-independent code in the C++
+frontend will generate a less efficient heavyweight thunk that calls
+@var{function} instead of jumping to it. The generic approach does
+not support varargs.
@end table
@node Profiling
@@ -3009,7 +3398,7 @@ You need not define this macro if you did not define
These macros will help you generate code for profiling.
@table @code
-@findex FUNCTION_PROFILER
+@findex FUNCTION_PROFILER
@item FUNCTION_PROFILER (@var{file}, @var{labelno})
A C statement or compound statement to output to @var{file} some
assembler code to call the profiling subroutine @code{mcount}.
@@ -3032,19 +3421,25 @@ Define this macro if the code for function profiling should come before
the function prologue. Normally, the profiling code comes after.
@findex FUNCTION_BLOCK_PROFILER
-@findex __bb_init_func
+@vindex profile_block_flag
@item FUNCTION_BLOCK_PROFILER (@var{file}, @var{labelno})
A C statement or compound statement to output to @var{file} some
assembler code to initialize basic-block profiling for the current
-object module. This code should call the subroutine
-@code{__bb_init_func} once per object module, passing it as its sole
-argument the address of a block allocated in the object module.
+object module. The global compile flag @code{profile_block_flag}
+distinguishes two profile modes.
+
+@table @code
+@findex __bb_init_func
+@item profile_block_flag != 2
+Output code to call the subroutine @code{__bb_init_func} once per
+object module, passing it as its sole argument the address of a block
+allocated in the object module.
The name of the block is a local symbol made with this statement:
-@example
+@smallexample
ASM_GENERATE_INTERNAL_LABEL (@var{buffer}, "LPBX", 0);
-@end example
+@end smallexample
Of course, since you are writing the definition of
@code{ASM_GENERATE_INTERNAL_LABEL} as well as that of this macro, you
@@ -3053,20 +3448,57 @@ that you know will result.
The first word of this block is a flag which will be nonzero if the
object module has already been initialized. So test this word first,
-and do not call @code{__bb_init_func} if the flag is nonzero.
+and do not call @code{__bb_init_func} if the flag is
+nonzero. BLOCK_OR_LABEL contains a unique number which may be used to
+generate a label as a branch destination when @code{__bb_init_func}
+will not be called.
+
+Described in assembler language, the code to be output looks like:
+
+@example
+ cmp (LPBX0),0
+ bne local_label
+ parameter1 <- LPBX0
+ call __bb_init_func
+local_label:
+@end example
+
+@findex __bb_init_trace_func
+@item profile_block_flag == 2
+Output code to call the subroutine @code{__bb_init_trace_func}
+and pass two parameters to it. The first parameter is the same as
+for @code{__bb_init_func}. The second parameter is the number of the
+first basic block of the function as given by BLOCK_OR_LABEL. Note
+that @code{__bb_init_trace_func} has to be called, even if the object
+module has been initialized already.
+
+Described in assembler language, the code to be output looks like:
+@example
+parameter1 <- LPBX0
+parameter2 <- BLOCK_OR_LABEL
+call __bb_init_trace_func
+@end example
+@end table
@findex BLOCK_PROFILER
+@vindex profile_block_flag
@item BLOCK_PROFILER (@var{file}, @var{blockno})
-A C statement or compound statement to increment the count associated
-with the basic block number @var{blockno}. Basic blocks are numbered
-separately from zero within each compilation. The count associated
-with block number @var{blockno} is at index @var{blockno} in a vector
-of words; the name of this array is a local symbol made with this
-statement:
+A C statement or compound statement to output to @var{file} some
+assembler code to increment the count associated with the basic
+block number @var{blockno}. The global compile flag
+@code{profile_block_flag} distinguishes two profile modes.
-@example
+@table @code
+@item profile_block_flag != 2
+Output code to increment the counter directly. Basic blocks are
+numbered separately from zero within each compilation. The count
+associated with block number @var{blockno} is at index
+@var{blockno} in a vector of words; the name of this array is a local
+symbol made with this statement:
+
+@smallexample
ASM_GENERATE_INTERNAL_LABEL (@var{buffer}, "LPBX", 2);
-@end example
+@end smallexample
@c This paragraph is the same as one a few paragraphs up.
@c That is not an error.
@@ -3075,6 +3507,82 @@ Of course, since you are writing the definition of
can take a short cut in the definition of this macro and use the name
that you know will result.
+Described in assembler language, the code to be output looks like:
+
+@smallexample
+inc (LPBX2+4*BLOCKNO)
+@end smallexample
+
+@vindex __bb
+@findex __bb_trace_func
+@item profile_block_flag == 2
+Output code to initialize the global structure @code{__bb} and
+call the function @code{__bb_trace_func}, which will increment the
+counter.
+
+@code{__bb} consists of two words. In the first word, the current
+basic block number, as given by BLOCKNO, has to be stored. In
+the second word, the address of a block allocated in the object
+module has to be stored. The address is given by the label created
+with this statement:
+
+@smallexample
+ASM_GENERATE_INTERNAL_LABEL (@var{buffer}, "LPBX", 0);
+@end smallexample
+
+Described in assembler language, the code to be output looks like:
+@example
+move BLOCKNO -> (__bb)
+move LPBX0 -> (__bb+4)
+call __bb_trace_func
+@end example
+@end table
+
+@findex FUNCTION_BLOCK_PROFILER_EXIT
+@findex __bb_trace_ret
+@vindex profile_block_flag
+@item FUNCTION_BLOCK_PROFILER_EXIT (@var{file})
+A C statement or compound statement to output to @var{file}
+assembler code to call function @code{__bb_trace_ret}. The
+assembler code should only be output
+if the global compile flag @code{profile_block_flag} == 2. This
+macro has to be used at every place where code for returning from
+a function is generated (e.g. @code{FUNCTION_EPILOGUE}). Although
+you have to write the definition of @code{FUNCTION_EPILOGUE}
+as well, you have to define this macro to tell the compiler, that
+the proper call to @code{__bb_trace_ret} is produced.
+
+@findex MACHINE_STATE_SAVE
+@findex __bb_init_trace_func
+@findex __bb_trace_func
+@findex __bb_trace_ret
+@item MACHINE_STATE_SAVE (@var{id})
+A C statement or compound statement to save all registers, which may
+be clobbered by a function call, including condition codes. The
+@code{asm} statement will be mostly likely needed to handle this
+task. Local labels in the assembler code can be concatenated with the
+string @var{id}, to obtain a unique lable name.
+
+Registers or condition codes clobbered by @code{FUNCTION_PROLOGUE} or
+@code{FUNCTION_EPILOGUE} must be saved in the macros
+@code{FUNCTION_BLOCK_PROFILER}, @code{FUNCTION_BLOCK_PROFILER_EXIT} and
+@code{BLOCK_PROFILER} prior calling @code{__bb_init_trace_func},
+@code{__bb_trace_ret} and @code{__bb_trace_func} respectively.
+
+@findex MACHINE_STATE_RESTORE
+@findex __bb_init_trace_func
+@findex __bb_trace_func
+@findex __bb_trace_ret
+@item MACHINE_STATE_RESTORE (@var{id})
+A C statement or compound statement to restore all registers, including
+condition codes, saved by @code{MACHINE_STATE_SAVE}.
+
+Registers or condition codes clobbered by @code{FUNCTION_PROLOGUE} or
+@code{FUNCTION_EPILOGUE} must be restored in the macros
+@code{FUNCTION_BLOCK_PROFILER}, @code{FUNCTION_BLOCK_PROFILER_EXIT} and
+@code{BLOCK_PROFILER} after calling @code{__bb_init_trace_func},
+@code{__bb_trace_ret} and @code{__bb_trace_func} respectively.
+
@findex BLOCK_PROFILER_CODE
@item BLOCK_PROFILER_CODE
A C function or functions which are needed in the library to
@@ -3121,7 +3629,7 @@ beginning of the function, as opposed to where the call to
This is because the registers must be saved before the function starts
to use them for its own purposes.
@c i rewrote the first sentence above to fix an overfull hbox. --mew
-@c 10feb93
+@c 10feb93
@findex __builtin_args_info
@item __builtin_args_info (@var{category})
@@ -3174,7 +3682,7 @@ The file @file{typeclass.h} defines an enumeration that you can use to
interpret the values of @code{__builtin_classify_type}.
@end table
-These machine description macros help implement varargs:
+These machine description macros help implement varargs:
@table @code
@findex EXPAND_BUILTIN_SAVEREGS
@@ -3195,7 +3703,7 @@ call to the library function @samp{__builtin_saveregs}.
@c more than one line of text... help... --mew 10feb93
@findex SETUP_INCOMING_VARARGS
@item SETUP_INCOMING_VARARGS (@var{args_so_far}, @var{mode}, @var{type},
-@var{pretend_args_size}, @var{second_time})
+@var{pretend_args_size}, @var{second_time})
This macro offers an alternative to using @code{__builtin_saveregs} and
defining the macro @code{EXPAND_BUILTIN_SAVEREGS}. Use it to store the
anonymous register arguments into the stack so that all the arguments
@@ -3229,15 +3737,18 @@ not generate any instructions in this case.
@findex STRICT_ARGUMENT_NAMING
@item STRICT_ARGUMENT_NAMING
-Define this macro if the location where a function argument is passed
-depends on whether or not it is a named argument.
+Define this macro to be a nonzero value if the location where a function
+argument is passed depends on whether or not it is a named argument.
This macro controls how the @var{named} argument to @code{FUNCTION_ARG}
-is set for varargs and stdarg functions. With this macro defined,
-the @var{named} argument is always true for named arguments, and false for
-unnamed arguments. If this is not defined, but @code{SETUP_INCOMING_VARARGS}
-is defined, then all arguments are treated as named. Otherwise, all named
-arguments except the last are treated as named.
+is set for varargs and stdarg functions. If this macro returns a
+nonzero value, the @var{named} argument is always true for named
+arguments, and false for unnamed arguments. If it returns a value of
+zero, but @code{SETUP_INCOMING_VARARGS} is defined, then all arguments
+are treated as named. Otherwise, all named arguments except the last
+are treated as named.
+
+You need not define this macro if it always returns zero.
@end table
@node Trampolines
@@ -3276,12 +3787,17 @@ block of data that contains the constant parts of a trampoline. This
code should not include a label---the label is taken care of
automatically.
+If you do not define this macro, it means no template is needed
+for the target. Do not define this macro on systems where the block move
+code to copy the trampoline into place would be larger than the code
+to generate it on the spot.
+
@findex TRAMPOLINE_SECTION
@item TRAMPOLINE_SECTION
The name of a subroutine to switch to the section in which the
trampoline template is to be placed (@pxref{Sections}). The default is
a value of @samp{readonly_data_section}, which places the trampoline in
-the section containing read-only data.
+the section containing read-only data.
@findex TRAMPOLINE_SIZE
@item TRAMPOLINE_SIZE
@@ -3350,7 +3866,7 @@ The total size in bytes of the cache.
The length in bytes of each cache line. The cache is divided into cache
lines which are disjoint slots, each holding a contiguous chunk of data
fetched from memory. Each time data is brought into the cache, an
-entire line is read at once. The data loaded into a cache line is
+entire line is read at once. The data loaded into a cache line is
always aligned on a boundary equal to the line size.
@findex INSN_CACHE_DEPTH
@@ -3369,8 +3885,8 @@ If defined, expands to a C expression clearing the @emph{instruction
cache} in the specified interval. If it is not defined, and the macro
INSN_CACHE_SIZE is defined, some generic code is generated to clear the
cache. The definition of this macro would typically be a series of
-@code{asm} statements. Both @var{BEG} and @var{END} are both pointer
-expressions.
+@code{asm} statements. Both @var{BEG} and @var{END} are both pointer
+expressions.
@end table
To use a standard subroutine, define the following macro. In addition,
@@ -3558,7 +4074,7 @@ traditional C compilers gratuitously convert values declared as
@item INTIFY (@var{float-value})
Define this macro to override the way the value of a
@code{float}-returning library routine should be packaged in order to
-return it. These functions are actually declared to return type
+return it. These functions are actually declared to return type
@code{FLOAT_VALUE_TYPE} (normally @code{int}).
These values can't be returned as type @code{float} because traditional
@@ -3582,7 +4098,7 @@ is.
@findex nongcc_word_type
@item nongcc_word_type
-Define this macro as the name of the data type corresponding to the
+Define this macro as the name of the data type corresponding to the
word_mode in the system's own C compiler.
You need not define this macro if that type is @code{long int}, as it usually
@@ -3725,6 +4241,15 @@ controlled by @code{REG_OK_STRICT} as described above. This usually
requires two variant definitions, of which @code{REG_OK_STRICT}
controls the one actually used.
+@findex REG_MODE_OK_FOR_BASE_P
+@item REG_MODE_OK_FOR_BASE_P (@var{x}, @var{mode})
+A C expression that is just like @code{REG_OK_FOR_BASE_P}, except that
+that expression may examine the mode of the memory reference in
+@var{mode}. You should define this macro if the mode of the memory
+reference affects whether a register may be used as a base register. If
+you define this macro, the compiler will use it instead of
+@code{REG_OK_FOR_BASE_P}.
+
@findex REG_OK_FOR_INDEX_P
@item REG_OK_FOR_INDEX_P (@var{x})
A C expression that is nonzero if @var{x} (assumed to be a @code{reg}
@@ -3766,6 +4291,55 @@ address. The compiler has standard ways of doing so in all cases. In
fact, it is safe for this macro to do nothing. But often a
machine-dependent strategy can generate better code.
+@findex LEGITIMIZE_RELOAD_ADDRESS
+@item LEGITIMIZE_RELOAD_ADDRESS (@var{x}, @var{mode}, @var{opnum}, @var{type}, @var{ind_levels}, @var{win})
+A C compound statement that attempts to replace @var{x}, which is an address
+that needs reloading, with a valid memory address for an operand of mode
+@var{mode}. @var{win} will be a C statement label elsewhere in the code.
+It is not necessary to define this macro, but it might be useful for
+performance reasons.
+
+For example, on the i386, it is sometimes possible to use a single
+reload register instead of two by reloading a sum of two pseudo
+registers into a register. On the other hand, for number of RISC
+processors offsets are limited so that often an intermediate address
+needs to be generated in order to address a stack slot. By defining
+LEGITIMIZE_RELOAD_ADDRESS appropriately, the intermediate addresses
+generated for adjacent some stack slots can be made identical, and thus
+be shared.
+
+@emph{Note}: This macro should be used with caution. It is necessary
+to know something of how reload works in order to effectively use this,
+and it is quite easy to produce macros that build in too much knowledge
+of reload internals.
+
+@emph{Note}: This macro must be able to reload an address created by a
+previous invocation of this macro. If it fails to handle such addresses
+then the compiler may generate incorrect code or abort.
+
+@findex push_reload
+The macro definition should use @code{push_reload} to indicate parts that
+need reloading; @var{opnum}, @var{type} and @var{ind_levels} are usually
+suitable to be passed unaltered to @code{push_reload}.
+
+The code generated by this macro must not alter the substructure of
+@var{x}. If it transforms @var{x} into a more legitimate form, it
+should assign @var{x} (which will always be a C variable) a new value.
+This also applies to parts that you change indirectly by calling
+@code{push_reload}.
+
+@findex strict_memory_address_p
+The macro definition may use @code{strict_memory_address_p} to test if
+the address has become legitimate.
+
+@findex copy_rtx
+If you want to change only a part of @var{x}, one standard way of doing
+this is to use @code{copy_rtx}. Note, however, that is unshares only a
+single level of rtl. Thus, if the part to be changed is not at the
+top level, you'll need to replace first the top leve
+It is not necessary for this macro to come up with a legitimate
+address; but often a machine-dependent strategy can generate better code.
+
@findex GO_IF_MODE_DEPENDENT_ADDRESS
@item GO_IF_MODE_DEPENDENT_ADDRESS (@var{addr}, @var{label})
A C statement or compound statement with a conditional @code{goto
@@ -3788,6 +4362,16 @@ an immediate operand on the target machine. You can assume that
@var{x} satisfies @code{CONSTANT_P}, so you need not check this. In fact,
@samp{1} is a suitable definition for this macro on machines where
anything @code{CONSTANT_P} is valid.@refill
+
+@findex DONT_RECORD_EQUIVALENCE
+@item DONT_RECORD_EQUIVALENCE (@var{note})
+A C expression that is nonzero if the @code{REG_EQUAL} note @var{x} should not
+be promoted to a @code{REG_EQUIV} note.
+
+Define this macro if @var{note} refers to a constant that must be accepted
+by @code{LEGITIMATE_CONSTANT_P}, but must not appear as an immediate operand.
+
+Most machine descriptions do not need to define this macro.
@end table
@node Condition Code
@@ -3915,11 +4499,11 @@ On such machines, define this macro to be a C statement to do any
required conversions. @var{code} is the initial comparison code
and @var{op0} and @var{op1} are the left and right operands of the
comparison, respectively. You should modify @var{code}, @var{op0}, and
-@var{op1} as required.
+@var{op1} as required.
GNU CC will not assume that the comparison resulting from this macro is
valid but will see if the resulting insn matches a pattern in the
-@file{md} file.
+@file{md} file.
You need not define this macro if it would never change the comparison
code or operands.
@@ -3952,7 +4536,7 @@ These macros let you describe the relative speed of various operations
on the target machine.
@table @code
-@findex CONST_COSTS
+@findex CONST_COSTS
@item CONST_COSTS (@var{x}, @var{code}, @var{outer_code})
A part of a C @code{switch} statement that describes the relative costs
of constant RTL expressions. It must contain @code{case} labels for
@@ -3967,7 +4551,7 @@ found in @var{outer_code}.
@var{code} is the expression code---redundant, since it can be
obtained with @code{GET_CODE (@var{x})}.
-@findex RTX_COSTS
+@findex RTX_COSTS
@findex COSTS_N_INSNS
@item RTX_COSTS (@var{x}, @var{code}, @var{outer_code})
Like @code{CONST_COSTS} but applies to nonconstant RTL expressions.
@@ -3980,6 +4564,21 @@ instructions. @var{outer_code} is the code of the expression in which
This macro is optional; do not define it if the default cost assumptions
are adequate for the target machine.
+@findex DEFAULT_RTX_COSTS
+@item DEFAULT_RTX_COSTS (@var{x}, @var{code}, @var{outer_code})
+This macro, if defined, is called for any case not handled by the
+@code{RTX_COSTS} or @code{CONST_COSTS} macros. This eliminates the need
+to put case labels into the macro, but the code, or any functions it
+calls, must assume that the RTL in @var{x} could be of any type that has
+not already been handled. The arguments are the same as for
+@code{RTX_COSTS}, and the macro should execute a return statement giving
+the cost of any RTL expressions that it can handle. The default cost
+calculation is used for any RTL for which this macro does not return a
+value.
+
+This macro is optional; do not define it if the default cost assumptions
+are adequate for the target machine.
+
@findex ADDRESS_COST
@item ADDRESS_COST (@var{address})
An expression giving the cost of an addressing mode that contains
@@ -4026,7 +4625,7 @@ constant.
@item REGISTER_MOVE_COST (@var{from}, @var{to})
A C expression for the cost of moving data from a register in class
@var{from} to one in class @var{to}. The classes are expressed using
-the enumeration values such as @code{GENERAL_REGS}. A value of 4 is the
+the enumeration values such as @code{GENERAL_REGS}. A value of 2 is the
default; other values are interpreted relative to that.
It is not required that the cost always equal 2 when @var{from} is the
@@ -4041,13 +4640,28 @@ allow reload to verify that the constraints are met. You should do this
if the @samp{mov@var{m}} pattern's constraints do not allow such copying.
@findex MEMORY_MOVE_COST
-@item MEMORY_MOVE_COST (@var{m})
-A C expression for the cost of moving data of mode @var{m} between a
-register and memory. A value of 2 is the default; this cost is relative
-to those in @code{REGISTER_MOVE_COST}.
-
-If moving between registers and memory is more expensive than between
-two registers, you should define this macro to express the relative cost.
+@item MEMORY_MOVE_COST (@var{mode}, @var{class}, @var{in})
+A C expression for the cost of moving data of mode @var{mode} between a
+register of class @var{class} and memory; @var{in} is zero if the value
+is to be written to memory, non-zero if it is to be read in. This cost
+is relative to those in @code{REGISTER_MOVE_COST}. If moving between
+registers and memory is more expensive than between two registers, you
+should define this macro to express the relative cost.
+
+If you do not define this macro, GNU CC uses a default cost of 4 plus
+the cost of copying via a secondary reload register, if one is
+needed. If your machine requires a secondary reload register to copy
+between memory and a register of @var{class} but the reload mechanism is
+more complex than copying via an intermediate, define this macro to
+reflect the actual cost of the move.
+
+GNU CC defines the function @code{memory_move_secondary_cost} if
+secondary reloads are needed. It computes the costs due to copying via
+a secondary register. If your machine copies from memory using a
+secondary register in the conventional way but the default base value of
+4 is not correct for your machine, define this macro to add some other
+value to the result of that function. The arguments to that function
+are the same as to this macro.
@findex BRANCH_COST
@item BRANCH_COST
@@ -4138,6 +4752,14 @@ based on the relationship between @var{insn} that is dependent on
make no adjustment to @var{cost}. This can be used for example to
specify to the scheduler that an output- or anti-dependence does not
incur the same cost as a data-dependence.
+
+@findex ADJUST_PRIORITY
+@item ADJUST_PRIORITY (@var{insn})
+A C statement (sans semicolon) to update the integer scheduling
+priority @code{INSN_PRIORITY(@var{insn})}. Reduce the priority
+to execute the @var{insn} earlier, increase the priority to execute
+@var{insn} later. Do not define this macro if you do not need to
+adjust the scheduling priorities of insns.
@end table
@node Sections
@@ -4171,13 +4793,29 @@ Normally @code{".data"} is right.
@findex SHARED_SECTION_ASM_OP
@item SHARED_SECTION_ASM_OP
-if defined, a C expression whose value is a string containing the
+If defined, a C expression whose value is a string containing the
assembler operation to identify the following data as shared data. If
not defined, @code{DATA_SECTION_ASM_OP} will be used.
+@findex BSS_SECTION_ASM_OP
+@item BSS_SECTION_ASM_OP
+If defined, a C expression whose value is a string containing the
+assembler operation to identify the following data as uninitialized global
+data. If not defined, and neither @code{ASM_OUTPUT_BSS} nor
+@code{ASM_OUTPUT_ALIGNED_BSS} are defined, uninitialized global data will be
+output in the data section if @samp{-fno-common} is passed, otherwise
+@code{ASM_OUTPUT_COMMON} will be used.
+
+@findex SHARED_BSS_SECTION_ASM_OP
+@item SHARED_BSS_SECTION_ASM_OP
+If defined, a C expression whose value is a string containing the
+assembler operation to identify the following data as uninitialized global
+shared data. If not defined, and @code{BSS_SECTION_ASM_OP} is, the latter
+will be used.
+
@findex INIT_SECTION_ASM_OP
@item INIT_SECTION_ASM_OP
-if defined, a C expression whose value is a string containing the
+If defined, a C expression whose value is a string containing the
assembler operation to identify the following data as initialization
code. If not defined, GNU CC will assume such a section does not
exist.
@@ -4236,9 +4874,10 @@ data section.
@findex JUMP_TABLES_IN_TEXT_SECTION
@item JUMP_TABLES_IN_TEXT_SECTION
-Define this macro if jump tables (for @code{tablejump} insns) should be
-output in the text section, along with the assembler instructions.
-Otherwise, the readonly data section is used.
+Define this macro to be an expression with a non-zero value if jump
+tables (for @code{tablejump} insns) should be output in the text
+section, along with the assembler instructions. Otherwise, the
+readonly data section is used.
This macro is irrelevant if there is no separate readonly data section.
@@ -4264,6 +4903,22 @@ information).
Decode @var{sym_name} and store the real name part in @var{var}, sans
the characters that encode section info. Define this macro if
@code{ENCODE_SECTION_INFO} alters the symbol's name string.
+
+@findex UNIQUE_SECTION_P
+@item UNIQUE_SECTION_P (@var{decl})
+A C expression which evaluates to true if @var{decl} should be placed
+into a unique section for some target-specific reason. If you do not
+define this macro, the default is @samp{0}. Note that the flag
+@samp{-ffunction-sections} will also cause functions to be placed into
+unique sections.
+
+@findex UNIQUE_SECTION
+@item UNIQUE_SECTION (@var{decl}, @var{reloc})
+A C statement to build up a unique section name, expressed as a
+STRING_CST node, and assign it to @samp{DECL_SECTION_NAME (@var{decl})}.
+@var{reloc} indicates whether the initial value of @var{exp} requires
+link-time relocations. If you do not define this macro, GNU CC will use
+the symbol name prefixed by @samp{.} as the section name.
@end table
@node PIC
@@ -4280,7 +4935,7 @@ well as @code{LEGITIMIZE_ADDRESS}. You must modify the definition of
contains a symbolic address. You may also need to alter the handling of
switch statements so that they use relative addresses.
@c i rearranged the order of the macros above to try to force one of
-@c them to the next line, to eliminate an overfull hbox. --mew 10feb93
+@c them to the next line, to eliminate an overfull hbox. --mew 10feb93
@table @code
@findex PIC_OFFSET_TABLE_REGNUM
@@ -4321,8 +4976,8 @@ A C expression that is nonzero if @var{x} is a legitimate immediate
operand on the target machine when generating position independent code.
You can assume that @var{x} satisfies @code{CONSTANT_P}, so you need not
check this. You can also assume @var{flag_pic} is true, so you need not
-check it either. You need not define this macro if all constants
-(including @code{SYMBOL_REF}) can be immediate operands when generating
+check it either. You need not define this macro if all constants
+(including @code{SYMBOL_REF}) can be immediate operands when generating
position independent code.
@end table
@@ -4341,20 +4996,21 @@ instructions do.
* Initialization:: General principles of initialization
and termination routines.
* Macros for Initialization::
- Specific macros that control the handling of
+ Specific macros that control the handling of
initialization and termination routines.
* Instruction Output:: Output of actual instructions.
* Dispatch Tables:: Output of jump tables.
+* Exception Region Output:: Output of exception region code.
* Alignment Output:: Pseudo ops for alignment and skipping data.
@end menu
@node File Framework
-@subsection The Overall Framework of an Assembler File
+@subsection The Overall Framework of an Assembler File
@cindex assembler format
@cindex output of assembler code
@c prevent bad page break with this line
-This describes the overall framework of an assembler file.
+This describes the overall framework of an assembler file.
@table @code
@findex ASM_FILE_START
@@ -4428,6 +5084,14 @@ the stdio stream @var{stream}.
This macro need not be defined if the standard form of output
for the file format in use is appropriate.
+@findex OUTPUT_QUOTED_STRING
+@item OUTPUT_QUOTED_STRING (@var{stream}, @var{name})
+A C statement to output the string @var{string} to the stdio stream
+@var{stream}. If you do not call the function @code{output_quoted_string}
+in your config files, GNU CC will only call it to output filenames to
+the assembler source. So you can use it to canonicalize the format
+of the filename using this macro.
+
@findex ASM_OUTPUT_SOURCE_LINE
@item ASM_OUTPUT_SOURCE_LINE (@var{stream}, @var{line})
A C statement to output DBX or SDB debugging information before code
@@ -4444,10 +5108,12 @@ A C statement to output something to the assembler file to handle a
macro is not defined, nothing is output for a @samp{#ident} directive.
@findex ASM_OUTPUT_SECTION_NAME
-@item ASM_OUTPUT_SECTION_NAME (@var{stream}, @var{decl}, @var{name})
+@item ASM_OUTPUT_SECTION_NAME (@var{stream}, @var{decl}, @var{name}, @var{reloc})
A C statement to output something to the assembler file to switch to section
@var{name} for object @var{decl} which is either a @code{FUNCTION_DECL}, a
-@code{VAR_DECL} or @code{NULL_TREE}. Some target formats do not support
+@code{VAR_DECL} or @code{NULL_TREE}. @var{reloc}
+indicates whether the initial value of @var{exp} requires link-time
+relocations. Some target formats do not support
arbitrary sections. Do not define this macro in such cases.
At present this macro is only used to support section attributes.
@@ -4530,6 +5196,15 @@ If the assembler has a @code{.ascii} pseudo-op as found in the
Berkeley Unix assembler, do not define the macro
@code{ASM_OUTPUT_ASCII}.
+@findex CONSTANT_POOL_BEFORE_FUNCTION
+@item CONSTANT_POOL_BEFORE_FUNCTION
+You may define this macro as a C expression. You should define the
+expression to have a non-zero value if GNU CC should output the constant
+pool for a function before the code for the function, or a zero value if
+GNU CC should output the constant pool after the function. If you do
+not define this macro, the usual case, GNU CC will output the constant
+pool before the function.
+
@findex ASM_OUTPUT_POOL_PROLOGUE
@item ASM_OUTPUT_POOL_PROLOGUE (@var{file} @var{funname} @var{fundecl} @var{size})
A C statement to output assembler commands to define the start of the
@@ -4570,6 +5245,24 @@ entry from being output a second time in the usual manner.
You need not define this macro if it would do nothing.
+@findex CONSTANT_AFTER_FUNCTION_P
+@item CONSTANT_AFTER_FUNCTION_P (@var{exp})
+Define this macro as a C expression which is nonzero if the constant
+@var{exp}, of type @code{tree}, should be output after the code for a
+function. The compiler will normally output all constants before the
+function; you need not define this macro if this is OK.
+
+@findex ASM_OUTPUT_POOL_EPILOGUE
+@item ASM_OUTPUT_POOL_EPILOGUE (@var{file} @var{funname} @var{fundecl} @var{size})
+A C statement to output assembler commands to at the end of the constant
+pool for a function. @var{funname} is a string giving the name of the
+function. Should the return type of the function be required, you can
+obtain it via @var{fundecl}. @var{size} is the size, in bytes, of the
+constant pool that GNU CC wrote immediately before this call.
+
+If no constant-pool epilogue is required, the usual case, you need not
+define this macro.
+
@findex IS_ASM_LOGICAL_LINE_SEPARATOR
@item IS_ASM_LOGICAL_LINE_SEPARATOR (@var{C})
Define this macro as a C expression which is nonzero if @var{C} is
@@ -4645,7 +5338,7 @@ output the name itself; before and after that, output the additional
assembler syntax for defining the name, and a newline.
This macro controls how the assembler definitions of uninitialized
-global variables are output.
+common global variables are output.
@findex ASM_OUTPUT_ALIGNED_COMMON
@item ASM_OUTPUT_ALIGNED_COMMON (@var{stream}, @var{name}, @var{size}, @var{alignment})
@@ -4655,12 +5348,59 @@ place of @code{ASM_OUTPUT_COMMON}, and gives you more flexibility in
handling the required alignment of the variable. The alignment is specified
as the number of bits.
+@findex ASM_OUTPUT_ALIGNED_DECL_COMMON
+@item ASM_OUTPUT_ALIGNED_DECL_COMMON (@var{stream}, @var{decl}, @var{name}, @var{size}, @var{alignment})
+Like @code{ASM_OUTPUT_ALIGNED_COMMON} except that @var{decl} of the
+variable to be output, if there is one, or @code{NULL_TREE} if there
+is not corresponding variable. If you define this macro, GNU CC wil use it
+in place of both @code{ASM_OUTPUT_COMMON} and
+@code{ASM_OUTPUT_ALIGNED_COMMON}. Define this macro when you need to see
+the variable's decl in order to chose what to output.
+
@findex ASM_OUTPUT_SHARED_COMMON
@item ASM_OUTPUT_SHARED_COMMON (@var{stream}, @var{name}, @var{size}, @var{rounded})
If defined, it is similar to @code{ASM_OUTPUT_COMMON}, except that it
is used when @var{name} is shared. If not defined, @code{ASM_OUTPUT_COMMON}
will be used.
+@findex ASM_OUTPUT_BSS
+@item ASM_OUTPUT_BSS (@var{stream}, @var{decl}, @var{name}, @var{size}, @var{rounded})
+A C statement (sans semicolon) to output to the stdio stream
+@var{stream} the assembler definition of uninitialized global @var{decl} named
+@var{name} whose size is @var{size} bytes. The variable @var{rounded}
+is the size rounded up to whatever alignment the caller wants.
+
+Try to use function @code{asm_output_bss} defined in @file{varasm.c} when
+defining this macro. If unable, use the expression
+@code{assemble_name (@var{stream}, @var{name})} to output the name itself;
+before and after that, output the additional assembler syntax for defining
+the name, and a newline.
+
+This macro controls how the assembler definitions of uninitialized global
+variables are output. This macro exists to properly support languages like
+@code{c++} which do not have @code{common} data. However, this macro currently
+is not defined for all targets. If this macro and
+@code{ASM_OUTPUT_ALIGNED_BSS} are not defined then @code{ASM_OUTPUT_COMMON}
+or @code{ASM_OUTPUT_ALIGNED_COMMON} or
+@code{ASM_OUTPUT_ALIGNED_DECL_COMMON} is used.
+
+@findex ASM_OUTPUT_ALIGNED_BSS
+@item ASM_OUTPUT_ALIGNED_BSS (@var{stream}, @var{decl}, @var{name}, @var{size}, @var{alignment})
+Like @code{ASM_OUTPUT_BSS} except takes the required alignment as a
+separate, explicit argument. If you define this macro, it is used in
+place of @code{ASM_OUTPUT_BSS}, and gives you more flexibility in
+handling the required alignment of the variable. The alignment is specified
+as the number of bits.
+
+Try to use function @code{asm_output_aligned_bss} defined in file
+@file{varasm.c} when defining this macro.
+
+@findex ASM_OUTPUT_SHARED_BSS
+@item ASM_OUTPUT_SHARED_BSS (@var{stream}, @var{decl}, @var{name}, @var{size}, @var{rounded})
+If defined, it is similar to @code{ASM_OUTPUT_BSS}, except that it
+is used when @var{name} is shared. If not defined, @code{ASM_OUTPUT_BSS}
+will be used.
+
@findex ASM_OUTPUT_LOCAL
@item ASM_OUTPUT_LOCAL (@var{stream}, @var{name}, @var{size}, @var{rounded})
A C statement (sans semicolon) to output to the stdio stream
@@ -4683,6 +5423,16 @@ place of @code{ASM_OUTPUT_LOCAL}, and gives you more flexibility in
handling the required alignment of the variable. The alignment is specified
as the number of bits.
+@findex ASM_OUTPUT_ALIGNED_DECL_LOCAL
+@item ASM_OUTPUT_ALIGNED_DECL_LOCAL (@var{stream}, @var{decl}, @var{name}, @var{size}, @var{alignment})
+Like @code{ASM_OUTPUT_ALIGNED_DECL} except that @var{decl} of the
+variable to be output, if there is one, or @code{NULL_TREE} if there
+is not corresponding variable. If you define this macro, GNU CC wil use it
+in place of both @code{ASM_OUTPUT_DECL} and
+@code{ASM_OUTPUT_ALIGNED_DECL}. Define this macro when you need to see
+the variable's decl in order to chose what to output.
+
+
@findex ASM_OUTPUT_SHARED_LOCAL
@item ASM_OUTPUT_SHARED_LOCAL (@var{stream}, @var{name}, @var{size}, @var{rounded})
If defined, it is similar to @code{ASM_OUTPUT_LOCAL}, except that it
@@ -4782,6 +5532,27 @@ definition is @samp{1}; otherwise, it is @samp{0}. Define this macro if
you want to control weak symbol support with a compiler flag such as
@samp{-melf}.
+@findex MAKE_DECL_ONE_ONLY (@var{decl})
+@item MAKE_DECL_ONE_ONLY
+A C statement (sans semicolon) to mark @var{decl} to be emitted as a
+public symbol such that extra copies in multiple translation units will
+be discarded by the linker. Define this macro if your object file
+format provides support for this concept, such as the @samp{COMDAT}
+section flags in the Microsoft Windows PE/COFF format, and this support
+requires changes to @var{decl}, such as putting it in a separate section.
+
+@findex SUPPORTS_ONE_ONLY
+@item SUPPORTS_ONE_ONLY
+A C expression which evaluates to true if the target supports one-only
+semantics.
+
+If you don't define this macro, @file{varasm.c} provides a default
+definition. If @code{MAKE_DECL_ONE_ONLY} is defined, the default
+definition is @samp{1}; otherwise, it is @samp{0}. Define this macro if
+you want to control one-only symbol support with a compiler flag, or if
+setting the @code{DECL_ONE_ONLY} flag is enough to mark a declaration to
+be emitted as one-only.
+
@findex ASM_OUTPUT_EXTERNAL
@item ASM_OUTPUT_EXTERNAL (@var{stream}, @var{decl}, @var{name})
A C statement (sans semicolon) to output to the stdio stream
@@ -4883,6 +5654,28 @@ which defines (equates) the symbol @var{name} to have the value @var{value}.
If SET_ASM_OP is defined, a default definition is provided which is
correct for most systems.
+
+@findex ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL
+@item ASM_OUTPUT_DEFINE_LABEL_DIFFERENCE_SYMBOL (@var{stream}, @var{symbol}, @var{high}, @var{low})
+A C statement to output to the stdio stream @var{stream} assembler code
+which defines (equates) the symbol @var{symbol} to have a value equal to
+the difference of the two symbols @var{high} and @var{low}, i.e.
+@var{high} minus @var{low}. GNU CC guarantees that the symbols @var{high}
+and @var{low} are already known by the assembler so that the difference
+resolves into a constant.
+
+If SET_ASM_OP is defined, a default definition is provided which is
+correct for most systems.
+
+@findex ASM_OUTPUT_WEAK_ALIAS
+@item ASM_OUTPUT_WEAK_ALIAS (@var{stream}, @var{name}, @var{value})
+A C statement to output to the stdio stream @var{stream} assembler code
+which defines (equates) the weak symbol @var{name} to have the value
+@var{value}.
+
+Define this macro if the target only supports weak aliases; define
+ASM_OUTPUT_DEF instead if possible.
+
@findex OBJC_GEN_METHOD_LABEL
@item OBJC_GEN_METHOD_LABEL (@var{buf}, @var{is_inst}, @var{class_name}, @var{cat_name}, @var{sel_name})
Define this macro to override the default assembler names used for
@@ -5113,13 +5906,20 @@ names.
@findex ASM_OUTPUT_DESTRUCTOR
This is like @code{ASM_OUTPUT_CONSTRUCTOR} but used for termination
functions rather than initialization functions.
+
+When @code{ASM_OUTPUT_CONSTRUCTOR} and @code{ASM_OUTPUT_DESTRUCTOR} are
+defined, the initializaiton routine generated for the generated object
+file will have static linkage.
@end table
If your system uses @code{collect2} as the means of processing
constructors, then that program normally uses @code{nm} to scan an
-object file for constructor functions to be called. On certain kinds of
-systems, you can define these macros to make @code{collect2} work faster
-(and, in some cases, make it work at all):
+object file for constructor functions to be called. On such systems you
+must not define @code{ASM_OUTPUT_CONSTRUCTOR} and @code{ASM_OUTPUT_DESTRUCTOR}
+as the object file's initialization routine must have global scope.
+
+On certain kinds of systems, you can define these macros to make
+@code{collect2} work faster (and, in some cases, make it work at all):
@table @code
@findex OBJECT_FORMAT_COFF
@@ -5233,6 +6033,12 @@ writing conditional output routines in those patterns.
If this macro is not defined, it is equivalent to a null statement.
+@findex FINAL_PRESCAN_LABEL
+@item FINAL_PRESCAN_LABEL
+If defined, @code{FINAL_PRESCAN_INSN} will be called on each
+@code{CODE_LABEL}. In that case, @var{opvec} will be a null pointer and
+@var{noperands} will be zero.
+
@findex PRINT_OPERAND
@item PRINT_OPERAND (@var{stream}, @var{x}, @var{code})
A C compound statement to output to stdio stream @var{stream} the
@@ -5321,8 +6127,8 @@ different opcodes), define this macro as a C expression that gives the
numeric index of the assembler language dialect to use, with zero as the
first variant.
-If this macro is defined, you may use
-@samp{@{option0|option1|option2@dots{}@}} constructs in the output
+If this macro is defined, you may use constructs of the form
+@samp{@{option0|option1|option2@dots{}@}} in the output
templates of patterns (@pxref{Output Template}) or in the first argument
of @code{asm_fprintf}. This construct outputs @samp{option0},
@samp{option1} or @samp{option2}, etc., if the value of
@@ -5335,7 +6141,7 @@ operands to @code{asm_fprintf}.
Define the macros @code{REGISTER_PREFIX}, @code{LOCAL_LABEL_PREFIX},
@code{USER_LABEL_PREFIX} and @code{IMMEDIATE_PREFIX} if you can express
-the variations in assemble language syntax with that mechanism. Define
+the variations in assembler language syntax with that mechanism. Define
@code{ASSEMBLER_DIALECT} and use the @samp{@{option0|option1@}} syntax
if the syntax variant are larger and involve such things as different
opcodes or operand order.
@@ -5364,14 +6170,11 @@ This concerns dispatch tables.
@table @code
@cindex dispatch table
@findex ASM_OUTPUT_ADDR_DIFF_ELT
-@item ASM_OUTPUT_ADDR_DIFF_ELT (@var{stream}, @var{value}, @var{rel})
-This macro should be provided on machines where the addresses
-in a dispatch table are relative to the table's own address.
-
-The definition should be a C statement to output to the stdio stream
-@var{stream} an assembler pseudo-instruction to generate a difference
-between two labels. @var{value} and @var{rel} are the numbers of two
-internal labels. The definitions of these labels are output using
+@item ASM_OUTPUT_ADDR_DIFF_ELT (@var{stream}, @var{body}, @var{value}, @var{rel})
+A C statement to output to the stdio stream @var{stream} an assembler
+pseudo-instruction to generate a difference between two labels.
+@var{value} and @var{rel} are the numbers of two internal labels. The
+definitions of these labels are output using
@code{ASM_OUTPUT_INTERNAL_LABEL}, and they must be printed in the same
way here. For example,
@@ -5380,6 +6183,12 @@ fprintf (@var{stream}, "\t.word L%d-L%d\n",
@var{value}, @var{rel})
@end example
+You must provide this macro on machines where the addresses in a
+dispatch table are relative to the table's own address. If defined, GNU
+CC will also use this macro on all machines when producing PIC.
+@var{body} is the body of the ADDR_DIFF_VEC; it is provided so that the
+mode and flags can be read.
+
@findex ASM_OUTPUT_ADDR_VEC_ELT
@item ASM_OUTPUT_ADDR_VEC_ELT (@var{stream}, @var{value})
This macro should be provided on machines where the addresses
@@ -5422,6 +6231,90 @@ If this macro is not defined, nothing special is output at the end of
the jump-table.
@end table
+@node Exception Region Output
+@subsection Assembler Commands for Exception Regions
+
+@c prevent bad page break with this line
+
+This describes commands marking the start and the end of an exception
+region.
+
+@table @code
+@findex ASM_OUTPUT_EH_REGION_BEG
+@item ASM_OUTPUT_EH_REGION_BEG ()
+A C expression to output text to mark the start of an exception region.
+
+This macro need not be defined on most platforms.
+
+@findex ASM_OUTPUT_EH_REGION_END
+@item ASM_OUTPUT_EH_REGION_END ()
+A C expression to output text to mark the end of an exception region.
+
+This macro need not be defined on most platforms.
+
+@findex EXCEPTION_SECTION
+@item EXCEPTION_SECTION ()
+A C expression to switch to the section in which the main
+exception table is to be placed (@pxref{Sections}). The default is a
+section named @code{.gcc_except_table} on machines that support named
+sections via @code{ASM_OUTPUT_SECTION_NAME}, otherwise if @samp{-fpic}
+or @samp{-fPIC} is in effect, the @code{data_section}, otherwise the
+@code{readonly_data_section}.
+
+@findex EH_FRAME_SECTION_ASM_OP
+@item EH_FRAME_SECTION_ASM_OP
+If defined, a C string constant for the assembler operation to switch to
+the section for exception handling frame unwind information. If not
+defined, GNU CC will provide a default definition if the target supports
+named sections. @file{crtstuff.c} uses this macro to switch to the
+appropriate section.
+
+You should define this symbol if your target supports DWARF 2 frame
+unwind information and the default definition does not work.
+
+@findex OMIT_EH_TABLE
+@item OMIT_EH_TABLE ()
+A C expression that is nonzero if the normal exception table output
+should be omitted.
+
+This macro need not be defined on most platforms.
+
+@findex EH_TABLE_LOOKUP
+@item EH_TABLE_LOOKUP ()
+Alternate runtime support for looking up an exception at runtime and
+finding the associated handler, if the default method won't work.
+
+This macro need not be defined on most platforms.
+
+@findex DOESNT_NEED_UNWINDER
+@item DOESNT_NEED_UNWINDER
+A C expression that decides whether or not the current function needs to
+have a function unwinder generated for it. See the file @code{except.c}
+for details on when to define this, and how.
+
+@findex MASK_RETURN_ADDR
+@item MASK_RETURN_ADDR
+An rtx used to mask the return address found via RETURN_ADDR_RTX, so
+that it does not contain any extraneous set bits in it.
+
+@findex DWARF2_UNWIND_INFO
+@item DWARF2_UNWIND_INFO
+Define this macro to 0 if your target supports DWARF 2 frame unwind
+information, but it does not yet work with exception handling.
+Otherwise, if your target supports this information (if it defines
+@samp{INCOMING_RETURN_ADDR_RTX} and either @samp{UNALIGNED_INT_ASM_OP}
+or @samp{OBJECT_FORMAT_ELF}), GCC will provide a default definition of
+1.
+
+If this macro is defined to 1, the DWARF 2 unwinder will be the default
+exception handling mechanism; otherwise, setjmp/longjmp will be used by
+default.
+
+If this macro is defined to anything, the DWARF 2 unwinder will be used
+instead of inline unwinders and __unwind_function in the non-setjmp case.
+
+@end table
+
@node Alignment Output
@subsection Assembler Commands for Alignment
@@ -5429,25 +6322,30 @@ the jump-table.
This describes commands for alignment.
@table @code
-@findex ASM_OUTPUT_ALIGN_CODE
-@item ASM_OUTPUT_ALIGN_CODE (@var{file})
-A C expression to output text to align the location counter in the way
-that is desirable at a point in the code that is reached only by
-jumping.
+@findex LABEL_ALIGN_AFTER_BARRIER
+@item LABEL_ALIGN_AFTER_BARRIER (@var{label})
+The alignment (log base 2) to put in front of @var{label}, which follows
+a BARRIER.
This macro need not be defined if you don't want any special alignment
to be done at such a time. Most machine descriptions do not currently
define the macro.
-@findex ASM_OUTPUT_LOOP_ALIGN
-@item ASM_OUTPUT_LOOP_ALIGN (@var{file})
-A C expression to output text to align the location counter in the way
-that is desirable at the beginning of a loop.
+@findex LOOP_ALIGN
+@item LOOP_ALIGN (@var{label})
+The alignment (log base 2) to put in front of @var{label}, which follows
+a NOTE_INSN_LOOP_BEG note.
This macro need not be defined if you don't want any special alignment
to be done at such a time. Most machine descriptions do not currently
define the macro.
+@findex LABEL_ALIGN
+@item LABEL_ALIGN (@var{label})
+The alignment (log base 2) to put in front of @var{label}.
+If LABEL_ALIGN_AFTER_BARRIER / LOOP_ALIGN specify a different alignment,
+the maximum of the specified values is used.
+
@findex ASM_OUTPUT_SKIP
@item ASM_OUTPUT_SKIP (@var{stream}, @var{nbytes})
A C statement to output to the stdio stream @var{stream} an assembler
@@ -5458,7 +6356,7 @@ expression of type @code{int}.
@findex ASM_NO_SKIP_IN_TEXT
@item ASM_NO_SKIP_IN_TEXT
Define this macro if @code{ASM_OUTPUT_SKIP} should not be used in the
-text section because it fails put zeros in the bytes that are skipped.
+text section because it fails to put zeros in the bytes that are skipped.
This is true on many Unix systems, where the pseudo--op to skip bytes
produces no-op instructions rather than zeros when used in the text
section.
@@ -5475,7 +6373,7 @@ command to advance the location counter to a multiple of 2 to the
@section Controlling Debugging Information Format
@c prevent bad page break with this line
-This describes how to specify debugging information.
+This describes how to specify debugging information.
@menu
* All Debuggers:: Macros that affect all debugging formats uniformly.
@@ -5529,15 +6427,23 @@ having address @var{x} (an RTL expression). The nominal offset is
@findex PREFERRED_DEBUGGING_TYPE
@item PREFERRED_DEBUGGING_TYPE
-A C expression that returns the type of debugging output GNU CC produces
-when the user specifies @samp{-g} or @samp{-ggdb}. Define this if you
-have arranged for GNU CC to support more than one format of debugging
-output. Currently, the allowable values are @code{DBX_DEBUG},
-@code{SDB_DEBUG}, @code{DWARF_DEBUG}, and @code{XCOFF_DEBUG}.
+A C expression that returns the type of debugging output GNU CC should
+produce when the user specifies just @samp{-g}. Define
+this if you have arranged for GNU CC to support more than one format of
+debugging output. Currently, the allowable values are @code{DBX_DEBUG},
+@code{SDB_DEBUG}, @code{DWARF_DEBUG}, @code{DWARF2_DEBUG}, and
+@code{XCOFF_DEBUG}.
+
+When the user specifies @samp{-ggdb}, GNU CC normally also uses the
+value of this macro to select the debugging output format, but with two
+exceptions. If @code{DWARF2_DEBUGGING_INFO} is defined and
+@code{LINKER_DOES_NOT_WORK_WITH_DWARF2} is not defined, GNU CC uses the
+value @code{DWARF2_DEBUG}. Otherwise, if @code{DBX_DEBUGGING_INFO} is
+defined, GNU CC uses @code{DBX_DEBUG}.
The value of this macro only affects the default debugging output; the
user can always get a specific type of output by using @samp{-gstabs},
-@samp{-gcoff}, @samp{-gdwarf}, or @samp{-gxcoff}.
+@samp{-gcoff}, @samp{-gdwarf-1}, @samp{-gdwarf-2}, or @samp{-gxcoff}.
@end table
@node DBX Options
@@ -5669,6 +6575,15 @@ first.
Define this macro if the value of a symbol describing the scope of a
block (@code{N_LBRAC} or @code{N_RBRAC}) should be relative to the start
of the enclosing function. Normally, GNU C uses an absolute address.
+
+@findex DBX_USE_BINCL
+@item DBX_USE_BINCL
+Define this macro if GNU C should generate @code{N_BINCL} and
+@code{N_EINCL} stabs for included header files, as on Sun systems. This
+macro also directs GNU C to output a type number as a pair of a file
+number and a type number within the file. Normally, GNU C does not
+generate @code{N_BINCL} or @code{N_EINCL} stabs, and it outputs a single
+number for a type number.
@end table
@node DBX Hooks
@@ -5762,6 +6677,14 @@ Here is another way of finding a particular type:
@}
@end group
@end smallexample
+
+@findex NO_DBX_FUNCTION_END
+@item NO_DBX_FUNCTION_END
+Some stabs encapsulation formats (in particular ECOFF), cannot handle the
+@code{.stabs "",N_FUN,,0,0,Lscope-function-1} gdb dbx extention construct.
+On those machines, define this macro to turn this feature off without
+disturbing the rest of the gdb extensions.
+
@end table
@node File Names and DBX
@@ -5833,9 +6756,34 @@ for SDB in response to the @samp{-g} option.
@findex DWARF_DEBUGGING_INFO
@item DWARF_DEBUGGING_INFO
-Define this macro if GNU CC should produce dwarf format debugging output
+Define this macro if GNU CC should produce dwarf format debugging output
in response to the @samp{-g} option.
+@findex DWARF2_DEBUGGING_INFO
+@item DWARF2_DEBUGGING_INFO
+Define this macro if GNU CC should produce dwarf version 2 format
+debugging output in response to the @samp{-g} option.
+
+To support optional call frame debugging information, you must also
+define @code{INCOMING_RETURN_ADDR_RTX} and either set
+@code{RTX_FRAME_RELATED_P} on the prologue insns if you use RTL for the
+prologue, or call @code{dwarf2out_def_cfa} and @code{dwarf2out_reg_save}
+as appropriate from @code{FUNCTION_PROLOGUE} if you don't.
+
+@findex DWARF2_FRAME_INFO
+@item DWARF2_FRAME_INFO
+Define this macro to a nonzero value if GNU CC should always output
+Dwarf 2 frame information. If @code{DWARF2_UNWIND_INFO}
+(@pxref{Exception Region Output} is nonzero, GNU CC will output this
+information not matter how you define @code{DWARF2_FRAME_INFO}.
+
+@findex LINKER_DOES_NOT_WORK_WITH_DWARF2
+@item LINKER_DOES_NOT_WORK_WITH_DWARF2
+Define this macro if the linker does not work with Dwarf version 2.
+Normally, if the user specifies only @samp{-ggdb} GNU CC will use Dwarf
+version 2 if available; this macro disables this. See the description
+of the @code{PREFERRED_DEBUGGING_TYPE} macro for more details.
+
@findex PUT_SDB_@dots{}
@item PUT_SDB_@dots{}
Define these macros to override the assembler syntax for the special
@@ -5873,7 +6821,7 @@ assemblers choke if forward tags are used, while some require it.
@node Cross-compilation
@section Cross Compilation and Floating Point
-@cindex cross compilation and floating point
+@cindex cross compilation and floating point
@cindex floating point and cross compilation
While all modern machines use 2's complement representation for integers,
@@ -6037,11 +6985,13 @@ A macro for a C expression which converts a floating point value
@var{x} into a double-precision integer which is then stored into
@var{low} and @var{high}, two variables of type @var{int}.
-@item REAL_VALUE_FROM_INT (@var{x}, @var{low}, @var{high})
+@item REAL_VALUE_FROM_INT (@var{x}, @var{low}, @var{high}, @var{mode})
@findex REAL_VALUE_FROM_INT
A macro for a C expression which converts a double-precision integer
found in @var{low} and @var{high}, two variables of type @var{int},
into a floating point value which is then stored into @var{x}.
+The value is in the target machine's representation for mode @var{mode}
+and has the type @code{REAL_VALUE_TYPE}.
@end table
@node Misc
@@ -6073,7 +7023,7 @@ incorrect definitions that omit an rtl code that may be matched by the
predicate can cause the compiler to malfunction). Instead, it allows
the table built by @file{genrecog} to be more compact and efficient,
thus speeding up the compiler. The most important predicates to include
-in the list specified by this macro are thoses used in the most insn
+in the list specified by this macro are those used in the most insn
patterns.
@findex CASE_VECTOR_MODE
@@ -6081,9 +7031,21 @@ patterns.
An alias for a machine mode name. This is the machine mode that
elements of a jump-table should have.
+@findex CASE_VECTOR_SHORTEN_MODE
+@item CASE_VECTOR_SHORTEN_MODE (@var{min_offset}, @var{max_offset}, @var{body})
+Optional: return the preferred mode for an @code{addr_diff_vec}
+when the minimum and maximum offset are known. If you define this,
+it enables extra code in branch shortening to deal with @code{addr_diff_vec}.
+To make this work, you also have to define INSN_ALIGN and
+make the alignment for @code{addr_diff_vec} explicit.
+The @var{body} argument is provided so that teh offset_unsigned and scale
+flags can be updated.
+
@findex CASE_VECTOR_PC_RELATIVE
@item CASE_VECTOR_PC_RELATIVE
-Define this macro if jump-tables should contain relative addresses.
+Define this macro to be a C expression to indicate when jump-tables
+should contain relative addresses. If jump-tables never contain
+relative addresses, then you need not define this macro.
@findex CASE_DROPS_THROUGH
@item CASE_DROPS_THROUGH
@@ -6120,6 +7082,11 @@ value in this case. Do not define this macro if it would always return
@code{NIL}. On machines where this macro is defined, you will normally
define it as the constant @code{SIGN_EXTEND} or @code{ZERO_EXTEND}.
+@findex SHORT_IMMEDIATES_SIGN_EXTEND
+@item SHORT_IMMEDIATES_SIGN_EXTEND
+Define this macro if loading short immediate values into registers sign
+extends.
+
@findex IMPLICIT_FIX_EXPR
@item IMPLICIT_FIX_EXPR
An alias for a tree code that should be used by default for conversion
@@ -6145,14 +7112,15 @@ choice should be made on the basis of efficiency.@refill
@findex MOVE_MAX
@item MOVE_MAX
The maximum number of bytes that a single instruction can move quickly
-from memory to memory.
+between memory and registers or between two memory locations.
@findex MAX_MOVE_MAX
@item MAX_MOVE_MAX
The maximum number of bytes that a single instruction can move quickly
-from memory to memory. If this is undefined, the default is
-@code{MOVE_MAX}. Otherwise, it is the constant value that is the
-largest value that @code{MOVE_MAX} can have at run-time.
+between memory and registers or between two memory locations. If this
+is undefined, the default is @code{MOVE_MAX}. Otherwise, it is the
+constant value that is the largest value that @code{MOVE_MAX} can have
+at run-time.
@findex SHIFT_COUNT_TRUNCATED
@item SHIFT_COUNT_TRUNCATED
@@ -6290,7 +7258,7 @@ Some machines can also perform @code{and} or @code{plus} operations on
condition code values with less instructions than the corresponding
@samp{s@var{cond}} insn followed by @code{and} or @code{plus}. On those
machines, define the appropriate patterns. Use the names @code{incscc}
-and @code{decscc}, respectively, for the the patterns which perform
+and @code{decscc}, respectively, for the patterns which perform
@code{plus} or @code{minus} operations on condition code values. See
@file{rs6000.md} for some examples. The GNU Superoptizer can be used to
find such instruction sequences on other machines.
@@ -6350,11 +7318,12 @@ C++, which is to pretend that the file's contents are enclosed in
@findex HANDLE_PRAGMA
@findex #pragma
@findex pragma
-@item HANDLE_PRAGMA (@var{stream})
+@item HANDLE_PRAGMA (@var{stream}, @var{node})
Define this macro if you want to implement any pragmas. If defined, it
-should be a C statement to be executed when @code{#pragma} is seen. The
-argument @var{stream} is the stdio input stream from which the source
-text can be read.
+is a C expression whose value is 1 if the pragma was handled by the function.
+The argument @var{stream} is the stdio input stream from which the source text
+can be read. @var{node} is the tree node for the identifier after the
+@code{#pragma}.
It is generally a bad idea to implement new uses of @code{#pragma}. The
only reason to define this macro is for compatibility with other
@@ -6385,13 +7354,33 @@ generated).
If defined, a C statement that assigns default attributes to
newly defined @var{type}.
+@findex MERGE_MACHINE_TYPE_ATTRIBUTES
+@item MERGE_MACHINE_TYPE_ATTRIBUTES (@var{type1}, @var{type2})
+Define this macro if the merging of type attributes needs special handling.
+If defined, the result is a list of the combined TYPE_ATTRIBUTES of
+@var{type1} and @var{type2}. It is assumed that comptypes has already been
+called and returned 1.
+
+@findex MERGE_MACHINE_DECL_ATTRIBUTES
+@item MERGE_MACHINE_DECL_ATTRIBUTES (@var{olddecl}, @var{newdecl})
+Define this macro if the merging of decl attributes needs special handling.
+If defined, the result is a list of the combined DECL_MACHINE_ATTRIBUTES of
+@var{olddecl} and @var{newdecl}. @var{newdecl} is a duplicate declaration
+of @var{olddecl}. Examples of when this is needed are when one attribute
+overrides another, or when an attribute is nullified by a subsequent
+definition.
+
+@findex SET_DEFAULT_DECL_ATTRIBUTES
+@item SET_DEFAULT_DECL_ATTRIBUTES (@var{decl}, @var{attributes})
+If defined, a C statement that assigns default attributes to
+newly defined @var{decl}.
+
@findex DOLLARS_IN_IDENTIFIERS
@item DOLLARS_IN_IDENTIFIERS
Define this macro to control use of the character @samp{$} in identifier
-names. The value should be 0, 1, or 2. 0 means @samp{$} is not allowed
-by default; 1 means it is allowed by default if @samp{-traditional} is
-used; 2 means it is allowed by default provided @samp{-ansi} is not used.
+names. 0 means @samp{$} is not allowed by default; 1 means it is allowed.
1 is the default; there is no need to define this macro in that case.
+This macro controls the compiler proper; it does not affect the preprocessor.
@findex NO_DOLLAR_IN_LABEL
@item NO_DOLLAR_IN_LABEL
@@ -6429,7 +7418,7 @@ and @code{INIT_SECTION_ASM_OP} is not defined, a default
Define this if your @code{exit} function needs to do something
besides calling an external function @code{_cleanup} before
terminating with @code{_exit}. The @code{EXIT_BODY} macro is
-only needed if netiher @code{HAVE_ATEXIT} nor
+only needed if neither @code{HAVE_ATEXIT} nor
@code{INIT_SECTION_ASM_OP} are defined.
@findex INSN_SETS_ARE_DELAYED
@@ -6437,9 +7426,9 @@ only needed if netiher @code{HAVE_ATEXIT} nor
Define this macro as a C expression that is nonzero if it is safe for the
delay slot scheduler to place instructions in the delay slot of @var{insn},
even if they appear to use a resource set or clobbered in @var{insn}.
-@var{insn} is always a @code{jump_insn} or an @code{insn}; GNU CC knows that
-every @code{call_insn} has this behavior. On machines where some @code{insn}
-or @code{jump_insn} is really a function call and hence has this behavior,
+@var{insn} is always a @code{jump_insn} or an @code{insn}; GNU CC knows that
+every @code{call_insn} has this behavior. On machines where some @code{insn}
+or @code{jump_insn} is really a function call and hence has this behavior,
you should define this macro.
You need not define this macro if it would always return zero.
@@ -6448,20 +7437,92 @@ You need not define this macro if it would always return zero.
@item INSN_REFERENCES_ARE_DELAYED (@var{insn})
Define this macro as a C expression that is nonzero if it is safe for the
delay slot scheduler to place instructions in the delay slot of @var{insn},
-even if they appear to set or clobber a resource referenced in @var{insn}.
+even if they appear to set or clobber a resource referenced in @var{insn}.
@var{insn} is always a @code{jump_insn} or an @code{insn}. On machines where
some @code{insn} or @code{jump_insn} is really a function call and its operands
are registers whose use is actually in the subroutine it calls, you should
-define this macro. Doing so allows the delay slot scheduler to move
-instructions which copy arguments into the argument registers into the delay
+define this macro. Doing so allows the delay slot scheduler to move
+instructions which copy arguments into the argument registers into the delay
slot of @var{insn}.
You need not define this macro if it would always return zero.
-@findex MACHINE_DEPENDENT_REORG
-@item MACHINE_DEPENDENT_REORG (@var{insn})
+@findex MACHINE_DEPENDENT_REORG
+@item MACHINE_DEPENDENT_REORG (@var{insn})
In rare cases, correct code generation requires extra machine
dependent processing between the second jump optimization pass and
delayed branch scheduling. On those machines, define this macro as a C
statement to act on the code starting at @var{insn}.
+
+@findex MULTIPLE_SYMBOL_SPACES
+@item MULTIPLE_SYMBOL_SPACES
+Define this macro if in some cases global symbols from one translation
+unit may not be bound to undefined symbols in another translation unit
+without user intervention. For instance, under Microsoft Windows
+symbols must be explicitly imported from shared libraries (DLLs).
+
+@findex GIV_SORT_CRITERION
+@item GIV_SORT_CRITERION (@var{giv1}, @var{giv2})
+In some cases, the strength reduction optimization pass can produce better
+code if this is defined. This macro controls the order that induction
+variables are combined. This macro is particularly useful if the target has
+limited addressing modes. For instance, the SH target has only positive
+offsets in addresses. Thus sorting to put the smallest address first
+allows the most combinations to be found.
+
+@findex ISSUE_RATE
+@item ISSUE_RATE
+A C expression that returns how many instructions can be issued at the
+same time if the machine is a superscalar machine. This is only used by
+the @samp{Haifa} scheduler, and not the traditional scheduler.
+
+@findex MD_SCHED_INIT
+@item MD_SCHED_INIT (@var{file}, @var{verbose}
+A C statement which is executed by the @samp{Haifa} scheduler at the
+beginning of each block of instructions that are to be scheduled.
+@var{file} is either a null pointer, or a stdio stream to write any
+debug output to. @var{verbose} is the verbose level provided by
+@samp{-fsched-verbose-}@var{n}.
+
+@findex MD_SCHED_REORDER
+@item MD_SCHED_REORDER (@var{file}, @var{verbose}, @var{ready}, @var{n_ready})
+A C statement which is executed by the @samp{Haifa} scheduler after it
+has scheduled the ready list to allow the machine description to reorder
+it (for example to combine two small instructions together on
+@samp{VLIW} machines). @var{file} is either a null pointer, or a stdio
+stream to write any debug output to. @var{verbose} is the verbose level
+provided by @samp{-fsched-verbose-}@var{n}. @var{ready} is a pointer to
+the ready list of instructions that are ready to be scheduled.
+@var{n_ready} is the number of elements in the ready list. The
+scheduler reads the ready list in reverse order, starting with
+@var{ready}[@var{n_ready}-1] and going to @var{ready}[0].
+
+@findex MD_SCHED_VARIABLE_ISSUE
+@item MD_SCHED_VARIABLE_ISSUE (@var{file}, @var{verbose}, @var{insn}, @var{more})
+A C statement which is executed by the @samp{Haifa} scheduler after it
+has scheduled an insn from the ready list. @var{file} is either a null
+pointer, or a stdio stream to write any debug output to. @var{verbose}
+is the verbose level provided by @samp{-fsched-verbose-}@var{n}.
+@var{insn} is the instruction that was scheduled. @var{more} is the
+number of instructions that can be issued in the current cycle. The
+@samp{MD_SCHED_VARIABLE_ISSUE} macro is responsible for updating the
+value of @var{more} (typically by @var{more}--).
+
+@findex MAX_INTEGER_COMPUTATION_MODE
+@item MAX_INTEGER_COMPUTATION_MODE
+Define this to the largest integer machine mode which can be used for
+operations other than load, store and copy operations.
+
+You need only define this macro if the target holds values larger than
+@code{word_mode} in general purpose registers. Most targets should not define
+this macro.
+
+@findex NEED_MATH_LIBRARY
+@item NEED_MATH_LIBRARY
+Define this macro as a C expression that is nonzero if @code{g++} should
+automatically link in the math library or to zero if @code{g++} should not
+automatically link in the math library.
+
+You need only define this macro if the target does not always need the math
+library linked into C++ programs.
@end table
diff --git a/contrib/gcc/toplev.c b/contrib/gcc/toplev.c
index 1b6fccb..497359e 100644
--- a/contrib/gcc/toplev.c
+++ b/contrib/gcc/toplev.c
@@ -1,5 +1,5 @@
/* Top level of GNU C compiler
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-7, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -29,28 +29,19 @@ Boston, MA 02111-1307, USA. */
#else
#include <varargs.h>
#endif
-#include <stdio.h>
+#undef FLOAT /* This is for hpux. They should change hpux. */
+#undef FFS /* Some systems define this in param.h. */
+#include "system.h"
#include <signal.h>
#include <setjmp.h>
-#include <sys/types.h>
-#include <ctype.h>
#include <sys/stat.h>
-#ifndef _WIN32
-#ifdef USG
-#undef FLOAT
-#include <sys/param.h>
-/* This is for hpux. It is a real screw. They should change hpux. */
-#undef FLOAT
-#include <sys/times.h>
-#include <time.h> /* Correct for hpux at least. Is it good on other USG? */
-#undef FFS /* Some systems define this in param.h. */
-#else
-#ifndef VMS
-#include <sys/time.h>
-#include <sys/resource.h>
-#endif
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
#endif
+
+#ifdef HAVE_SYS_TIMES_H
+# include <sys/times.h>
#endif
#include "input.h"
@@ -58,10 +49,29 @@ Boston, MA 02111-1307, USA. */
#include "rtl.h"
#include "flags.h"
#include "insn-attr.h"
+#include "insn-codes.h"
+#include "insn-config.h"
+#include "recog.h"
#include "defaults.h"
#include "output.h"
-#include "bytecode.h"
-#include "bc-emit.h"
+#include "except.h"
+#include "toplev.h"
+
+#ifdef DWARF_DEBUGGING_INFO
+#include "dwarfout.h"
+#endif
+
+#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
+#include "dwarf2out.h"
+#endif
+
+#if defined(DBX_DEBUGGING_INFO) || defined(XCOFF_DEBUGGING_INFO)
+#include "dbxout.h"
+#endif
+
+#ifdef SDB_DEBUGGING_INFO
+#include "sdbout.h"
+#endif
#ifdef XCOFF_DEBUGGING_INFO
#include "xcoffout.h"
@@ -92,6 +102,39 @@ vms_fopen (fname, type)
#define DEFAULT_GDB_EXTENSIONS 1
#endif
+/* If more than one debugging type is supported, you must define
+ PREFERRED_DEBUGGING_TYPE to choose a format in a system-dependent way.
+
+ This is one long line cause VAXC can't handle a \-newline. */
+#if 1 < (defined (DBX_DEBUGGING_INFO) + defined (SDB_DEBUGGING_INFO) + defined (DWARF_DEBUGGING_INFO) + defined (DWARF2_DEBUGGING_INFO) + defined (XCOFF_DEBUGGING_INFO))
+#ifndef PREFERRED_DEBUGGING_TYPE
+You Lose! You must define PREFERRED_DEBUGGING_TYPE!
+#endif /* no PREFERRED_DEBUGGING_TYPE */
+#else /* Only one debugging format supported. Define PREFERRED_DEBUGGING_TYPE
+ so the following code needn't care. */
+#ifdef DBX_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE DBX_DEBUG
+#endif
+#ifdef SDB_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE SDB_DEBUG
+#endif
+#ifdef DWARF_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE DWARF_DEBUG
+#endif
+#ifdef DWARF2_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+#endif
+#ifdef XCOFF_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE XCOFF_DEBUG
+#endif
+#endif /* More than one debugger format enabled. */
+
+/* If still not defined, must have been because no debugging formats
+ are supported. */
+#ifndef PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE NO_DEBUG
+#endif
+
extern int rtx_equal_function_value_matters;
#if ! (defined (VMS) || defined (OS2))
@@ -105,7 +148,8 @@ extern char *version_string, *language_string;
extern int size_directive_output;
extern tree last_assemble_variable_decl;
-extern void init_lex ();
+extern char *init_parse PVPROTO((char *));
+extern void finish_parse ();
extern void init_decl_processing ();
extern void init_obstacks ();
extern void init_tree_codes ();
@@ -117,16 +161,18 @@ extern void init_reg_sets ();
extern void dump_flow_info ();
extern void dump_sched_info ();
extern void dump_local_alloc ();
+extern void regset_release_memory ();
+
+extern void print_rtl ();
+extern void print_rtl_with_bb ();
void rest_of_decl_compilation ();
void error_with_file_and_line PVPROTO((char *file, int line, char *s, ...));
void error_with_decl PVPROTO((tree decl, char *s, ...));
-void error_for_asm PVPROTO((rtx insn, char *s, ...));
void error PVPROTO((char *s, ...));
void fatal PVPROTO((char *s, ...));
void warning_with_file_and_line PVPROTO((char *file, int line, char *s, ...));
void warning_with_decl PVPROTO((tree decl, char *s, ...));
-void warning_for_asm PVPROTO((rtx insn, char *s, ...));
void warning PVPROTO((char *s, ...));
void pedwarn PVPROTO((char *s, ...));
void pedwarn_with_decl PVPROTO((tree decl, char *s, ...));
@@ -134,16 +180,42 @@ void pedwarn_with_file_and_line PVPROTO((char *file, int line, char *s, ...));
void sorry PVPROTO((char *s, ...));
void really_sorry PVPROTO((char *s, ...));
void fancy_abort ();
-#ifndef abort
-void abort ();
-#endif
void set_target_switch ();
-static void print_switch_values ();
-static char *decl_name ();
-
-#ifdef __alpha
-extern char *sbrk ();
-#endif
+static char *decl_name PROTO((tree, int));
+static void vmessage PROTO((char *, char *, va_list));
+static void v_message_with_file_and_line PROTO((char *, int, char *,
+ char *, va_list));
+static void v_message_with_decl PROTO((tree, char *, char *, va_list));
+static void file_and_line_for_asm PROTO((rtx, char **, int *));
+static void v_error_with_file_and_line PROTO((char *, int, char *, va_list));
+static void v_error_with_decl PROTO((tree, char *, va_list));
+static void v_error_for_asm PROTO((rtx, char *, va_list));
+static void verror PROTO((char *, va_list));
+static void vfatal PROTO((char *, va_list));
+static void v_warning_with_file_and_line PROTO ((char *, int, char *, va_list));
+static void v_warning_with_decl PROTO((tree, char *, va_list));
+static void v_warning_for_asm PROTO((rtx, char *, va_list));
+static void vwarning PROTO((char *, va_list));
+static void vpedwarn PROTO((char *, va_list));
+static void v_pedwarn_with_decl PROTO((tree, char *, va_list));
+static void v_pedwarn_with_file_and_line PROTO((char *, int, char *, va_list));
+static void vsorry PROTO((char *, va_list));
+static void v_really_sorry PROTO((char *, va_list));
+static void float_signal PROTO((int));
+static void pipe_closed PROTO((int));
+static void output_lang_identify PROTO((FILE *));
+static void open_dump_file PROTO((char *, char *));
+static void close_dump_file PROTO((void (*) (FILE *, rtx), rtx));
+static void dump_rtl PROTO((char *, tree, void (*) (FILE *, rtx), rtx));
+static void clean_dump_file PROTO((char *));
+static void compile_file PROTO((char *));
+static void display_help PROTO ((void));
+
+void print_version ();
+int print_single_switch ();
+void print_switch_values ();
+/* Length of line when printing switch values. */
+#define MAX_LINE 75
/* Name of program invoked, sans directories. */
@@ -164,10 +236,6 @@ char *input_filename;
char *main_input_filename;
-/* Stream for reading from the input file. */
-
-FILE *finput;
-
/* Current line number in real source file. */
int lineno;
@@ -198,19 +266,30 @@ extern int target_flags;
int rtl_dump = 0;
int rtl_dump_and_exit = 0;
int jump_opt_dump = 0;
+int addressof_dump = 0;
int cse_dump = 0;
+int gcse_dump = 0;
int loop_dump = 0;
int cse2_dump = 0;
+int branch_prob_dump = 0;
int flow_dump = 0;
int combine_dump = 0;
+int regmove_dump = 0;
int sched_dump = 0;
int local_reg_dump = 0;
int global_reg_dump = 0;
int sched2_dump = 0;
int jump2_opt_dump = 0;
+#ifdef DELAY_SLOTS
int dbr_sched_dump = 0;
+#endif
int flag_print_asm_name = 0;
+#ifdef STACK_REGS
int stack_reg_dump = 0;
+#endif
+#ifdef MACHINE_DEPENDENT_REORG
+int mach_dep_reorg_dump = 0;
+#endif
/* Name for output file of assembly code, specified with -o. */
@@ -244,18 +323,28 @@ int use_gnu_debug_info_extensions = 0;
int optimize = 0;
+/* Nonzero means optimize for size. -Os.
+ The only valid values are zero and non-zero. When optimize_size is
+ non-zero, optimize defaults to 2, but certain individual code
+ bloating optimizations are disabled. */
+
+int optimize_size = 0;
+
/* Number of error messages and warning messages so far. */
int errorcount = 0;
int warningcount = 0;
int sorrycount = 0;
-/* Flag to output bytecode instead of native assembler */
-int output_bytecode = 0;
+/* Pointer to function to compute the name to use to print a declaration.
+ DECL is the declaration in question.
+ VERBOSITY determines what information will be printed:
+ 0: DECL_NAME, demangled as necessary.
+ 1: and scope information.
+ 2: and any other information that might be interesting, such as function
+ parameter types in C++. */
-/* Pointer to function to compute the name to use to print a declaration. */
-
-char *(*decl_printable_name) ();
+char *(*decl_printable_name) (/* tree decl, int verbosity */);
/* Pointer to function to compute rtl for a language-specific tree code. */
@@ -266,11 +355,9 @@ struct rtx_def *(*lang_expand_expr) ();
void (*incomplete_decl_finalize_hook) () = 0;
-/* Pointer to function for interim exception handling implementation.
- This interface will change, and it is only here until a better interface
- replaces it. */
+/* Highest label number used at the end of reload. */
-void (*interim_eh_hook) PROTO((tree));
+int max_label_num_after_reload;
/* Nonzero if generating code to do profiling. */
@@ -280,6 +367,18 @@ int profile_flag = 0;
int profile_block_flag;
+/* Nonzero if generating code to profile program flow graph arcs. */
+
+int profile_arc_flag = 0;
+
+/* Nonzero if generating info for gcov to calculate line test coverage. */
+
+int flag_test_coverage = 0;
+
+/* Nonzero indicates that branch taken probabilities should be calculated. */
+
+int flag_branch_probabilities = 0;
+
/* Nonzero for -pedantic switch: warn about anything
that standard spec forbids. */
@@ -387,6 +486,21 @@ int flag_unroll_loops;
int flag_unroll_all_loops;
+/* Nonzero forces all invariant computations in loops to be moved
+ outside the loop. */
+
+int flag_move_all_movables = 0;
+
+/* Nonzero forces all general induction variables in loops to be
+ strength reduced. */
+
+int flag_reduce_all_givs = 0;
+
+/* Nonzero to perform full register move optimization passes. This is the
+ default for -O2. */
+
+int flag_regmove = 0;
+
/* Nonzero for -fwritable-strings:
store string constants in data segment and don't uniquize them. */
@@ -403,6 +517,11 @@ int flag_no_function_cse = 0;
int flag_omit_frame_pointer = 0;
+/* Nonzero means place each function into its own section on those platforms
+ which support arbitrary section names and unlimited numbers of sections. */
+
+int flag_function_sections = 0;
+
/* Nonzero to inhibit use of define_optimization peephole opts. */
int flag_no_peephole = 0;
@@ -410,7 +529,7 @@ int flag_no_peephole = 0;
/* Nonzero allows GCC to violate some IEEE or ANSI rules regarding math
operations in the interest of optimization. For example it allows
GCC to assume arguments to sqrt are nonnegative numbers, allowing
- faster code for sqrt to be generated. */
+ faster code for sqrt to be generated. */
int flag_fast_math = 0;
@@ -426,11 +545,24 @@ int flag_volatile_global;
int flag_syntax_only = 0;
+/* Nonzero means perform global cse. */
+
+static int flag_gcse;
+
/* Nonzero means to rerun cse after loop optimization. This increases
compilation time about 20% and picks up a few more common expressions. */
static int flag_rerun_cse_after_loop;
+/* Nonzero means to assume that a structure or an array reference at
+ a varying address cannot alias a scalar at a fixed address. */
+
+int flag_structure_noalias = 0;
+
+/* Nonzero means to run loop optimizations twice. */
+
+int flag_rerun_loop_opt;
+
/* Nonzero for -finline-functions: ok to inline functions that look like
good inline candidates. */
@@ -446,6 +578,11 @@ int flag_keep_inline_functions;
int flag_no_inline;
+/* Nonzero means that we should emit static const variables
+ regardless of whether or not optimization is turned on. */
+
+int flag_keep_static_consts = 1;
+
/* Nonzero means we should be saving declaration info into a .X file. */
int flag_gen_aux_info = 0;
@@ -462,10 +599,6 @@ int flag_shared_data;
int flag_delayed_branch;
-/* Nonzero means to run cleanups after CALL_EXPRs. */
-
-int flag_short_temps;
-
/* Nonzero if we are compiling pure (sharable) code.
Value is 1 if we are doing reasonable (i.e. simple
offset into offset table) pic. Value is 2 if we can
@@ -473,7 +606,18 @@ int flag_short_temps;
int flag_pic;
-/* Nonzero means place uninitialized global data in the bss section. */
+/* Nonzero means generate extra code for exception handling and enable
+ exception handling. */
+
+int flag_exceptions;
+
+/* Nonzero means use the new model for exception handling. Replaces
+ -DNEW_EH_MODEL as a compile option. */
+
+int flag_new_exceptions = 0;
+
+/* Nonzero means don't place uninitialized global data in common storage
+ by default. */
int flag_no_common;
@@ -496,6 +640,28 @@ int flag_pedantic_errors = 0;
int flag_schedule_insns = 0;
int flag_schedule_insns_after_reload = 0;
+#ifdef HAIFA
+/* The following flags have effect only for scheduling before register
+ allocation:
+
+ flag_schedule_interblock means schedule insns accross basic blocks.
+ flag_schedule_speculative means allow speculative motion of non-load insns.
+ flag_schedule_speculative_load means allow speculative motion of some
+ load insns.
+ flag_schedule_speculative_load_dangerous allows speculative motion of more
+ load insns. */
+
+int flag_schedule_interblock = 1;
+int flag_schedule_speculative = 1;
+int flag_schedule_speculative_load = 0;
+int flag_schedule_speculative_load_dangerous = 0;
+
+/* flag_on_branch_count_reg means try to replace add-1,compare,branch tupple
+ by a cheaper branch, on a count register. */
+int flag_branch_on_count_reg;
+#endif /* HAIFA */
+
+
/* -finhibit-size-directive inhibits output of .size for ELF.
This is used only for compiling crtstuff.c,
and it may be extended to other effects
@@ -505,10 +671,21 @@ int flag_inhibit_size_directive = 0;
/* -fverbose-asm causes extra commentary information to be produced in
the generated assembly code (to make it more readable). This option
is generally only of use to those who actually need to read the
- generated assembly code (perhaps while debugging the compiler itself). */
+ generated assembly code (perhaps while debugging the compiler itself).
+ -fno-verbose-asm, the default, causes the extra information
+ to be omitted and is useful when comparing two assembler files. */
int flag_verbose_asm = 0;
+/* -dA causes debug commentary information to be produced in
+ the generated assembly code (to make it more readable). This option
+ is generally only of use to those who actually need to read the
+ generated assembly code (perhaps while debugging the compiler itself).
+ Currently, this switch is only used by dwarfout.c; however, it is intended
+ to be a catchall for printing debug information in the assembler file. */
+
+int flag_debug_asm = 0;
+
/* -fgnu-linker specifies use of the GNU linker for initializations.
(Or, more generally, a linker that handles initializations.)
-fno-gnu-linker says that collect2 will be used. */
@@ -521,148 +698,409 @@ int flag_gnu_linker = 1;
/* Tag all structures with __attribute__(packed) */
int flag_pack_struct = 0;
+/* Emit code to check for stack overflow; also may cause large objects
+ to be allocated dynamically. */
+int flag_stack_check;
+
+/* -fcheck-memory-usage causes extra code to be generated in order to check
+ memory accesses. This is used by a detector of bad memory accesses such
+ as Checker. */
+int flag_check_memory_usage = 0;
+
+/* -fprefix-function-name causes function name to be prefixed. This
+ can be used with -fcheck-memory-usage to isolate code compiled with
+ -fcheck-memory-usage. */
+int flag_prefix_function_name = 0;
+
+/* 0 if pointer arguments may alias each other. True in C.
+ 1 if pointer arguments may not alias each other but may alias
+ global variables.
+ 2 if pointer arguments may not alias each other and may not
+ alias global variables. True in Fortran.
+ This defaults to 0 for C. */
+int flag_argument_noalias = 0;
+
+/* Nonzero if we should do (language-dependent) alias analysis.
+ Typically, this analysis will assume that expressions of certain
+ types do not alias expressions of certain other types. Only used
+ if alias analysis (in general) is enabled. */
+int flag_strict_aliasing = 0;
+
+extern int flag_dump_unnumbered;
+
+
+/* Table of supported debugging formats. */
+static struct
+{
+ char * arg;
+ /* Since PREFERRED_DEBUGGING_TYPE isn't necessarily a
+ constant expression, we use NO_DEBUG in its place. */
+ enum debug_info_type debug_type;
+ int use_extensions_p;
+ char * description;
+} *da,
+debug_args[] =
+{
+ { "g", NO_DEBUG, DEFAULT_GDB_EXTENSIONS,
+ "Generate default debug format output" },
+ { "ggdb", NO_DEBUG, 1, "Generate default extended debug format output" },
+#ifdef DBX_DEBUGGING_INFO
+ { "gstabs", DBX_DEBUG, 0, "Generate STABS format debug output" },
+ { "gstabs+", DBX_DEBUG, 1, "Generate extended STABS format debug output" },
+#endif
+#ifdef DWARF_DEBUGGING_INFO
+ { "gdwarf", DWARF_DEBUG, 0, "Generate DWARF-1 format debug output"},
+ { "gdwarf+", DWARF_DEBUG, 1,
+ "Generated extended DWARF-1 format debug output" },
+#endif
+#ifdef DWARF2_DEBUGGING_INFO
+ { "gdwarf-2", DWARF2_DEBUG, 0, "Enable DWARF-2 debug output" },
+#endif
+#ifdef XCOFF_DEBUGGING_INFO
+ { "gxcoff", XCOFF_DEBUG, 0, "Generate XCOFF format debug output" },
+ { "gxcoff+", XCOFF_DEBUG, 1, "Generate extended XCOFF format debug output" },
+#endif
+#ifdef SDB_DEBUGGING_INFO
+ { "gcoff", SDB_DEBUG, 0, "Generate COFF format debug output" },
+#endif
+ { 0, 0, 0 }
+};
+
+typedef struct
+{
+ char * string;
+ int * variable;
+ int on_value;
+ char * description;
+}
+lang_independent_options;
+
/* Table of language-independent -f options.
STRING is the option name. VARIABLE is the address of the variable.
ON_VALUE is the value to store in VARIABLE
if `-fSTRING' is seen as an option.
(If `-fno-STRING' is seen as an option, the opposite value is stored.) */
-struct { char *string; int *variable; int on_value;} f_options[] =
-{
- {"float-store", &flag_float_store, 1},
- {"volatile", &flag_volatile, 1},
- {"volatile-global", &flag_volatile_global, 1},
- {"defer-pop", &flag_defer_pop, 1},
- {"omit-frame-pointer", &flag_omit_frame_pointer, 1},
- {"cse-follow-jumps", &flag_cse_follow_jumps, 1},
- {"cse-skip-blocks", &flag_cse_skip_blocks, 1},
- {"expensive-optimizations", &flag_expensive_optimizations, 1},
- {"thread-jumps", &flag_thread_jumps, 1},
- {"strength-reduce", &flag_strength_reduce, 1},
- {"unroll-loops", &flag_unroll_loops, 1},
- {"unroll-all-loops", &flag_unroll_all_loops, 1},
- {"writable-strings", &flag_writable_strings, 1},
- {"peephole", &flag_no_peephole, 0},
- {"force-mem", &flag_force_mem, 1},
- {"force-addr", &flag_force_addr, 1},
- {"function-cse", &flag_no_function_cse, 0},
- {"inline-functions", &flag_inline_functions, 1},
- {"keep-inline-functions", &flag_keep_inline_functions, 1},
- {"inline", &flag_no_inline, 0},
- {"syntax-only", &flag_syntax_only, 1},
- {"shared-data", &flag_shared_data, 1},
- {"caller-saves", &flag_caller_saves, 1},
- {"pcc-struct-return", &flag_pcc_struct_return, 1},
- {"reg-struct-return", &flag_pcc_struct_return, 0},
- {"delayed-branch", &flag_delayed_branch, 1},
- {"rerun-cse-after-loop", &flag_rerun_cse_after_loop, 1},
- {"pretend-float", &flag_pretend_float, 1},
- {"schedule-insns", &flag_schedule_insns, 1},
- {"schedule-insns2", &flag_schedule_insns_after_reload, 1},
- {"pic", &flag_pic, 1},
- {"PIC", &flag_pic, 2},
- {"fast-math", &flag_fast_math, 1},
- {"common", &flag_no_common, 0},
- {"inhibit-size-directive", &flag_inhibit_size_directive, 1},
- {"verbose-asm", &flag_verbose_asm, 1},
- {"gnu-linker", &flag_gnu_linker, 1},
- {"pack-struct", &flag_pack_struct, 1},
- {"bytecode", &output_bytecode, 1}
+lang_independent_options f_options[] =
+{
+ {"float-store", &flag_float_store, 1,
+ "Do not store floats in registers" },
+ {"volatile", &flag_volatile, 1,
+ "Consider all mem refs through pointers as volatile"},
+ {"volatile-global", &flag_volatile_global, 1,
+ "Consider all mem refs to global data to be volatile" },
+ {"defer-pop", &flag_defer_pop, 1,
+ "Defer popping functions args from stack until later" },
+ {"omit-frame-pointer", &flag_omit_frame_pointer, 1,
+ "When possible do not generate stack frames"},
+ {"cse-follow-jumps", &flag_cse_follow_jumps, 1,
+ "When running CSE, follow jumps to their targets" },
+ {"cse-skip-blocks", &flag_cse_skip_blocks, 1,
+ "When running CSE, follow conditional jumps" },
+ {"expensive-optimizations", &flag_expensive_optimizations, 1,
+ "Perform a number of minor, expensive optimisations" },
+ {"thread-jumps", &flag_thread_jumps, 1,
+ "Perform jump threading optimisations"},
+ {"strength-reduce", &flag_strength_reduce, 1,
+ "Perform strength reduction optimisations" },
+ {"unroll-loops", &flag_unroll_loops, 1,
+ "Perform loop unrolling when interation count is known" },
+ {"unroll-all-loops", &flag_unroll_all_loops, 1,
+ "Perofm loop onrolling for all loops" },
+ {"move-all-movables", &flag_move_all_movables, 1,
+ "Force all loop invariant computations out of loops" },
+ {"reduce-all-givs", &flag_reduce_all_givs, 1,
+ "Strength reduce all loop general induction variables" },
+ {"writable-strings", &flag_writable_strings, 1,
+ "Store strings in writable data section" },
+ {"peephole", &flag_no_peephole, 0,
+ "Enable machine specific peephole optimisations" },
+ {"force-mem", &flag_force_mem, 1,
+ "Copy memory operands into registers before using" },
+ {"force-addr", &flag_force_addr, 1,
+ "Copy memory address constants into regs before using" },
+ {"function-cse", &flag_no_function_cse, 0,
+ "Allow function addresses to be held in registers" },
+ {"inline-functions", &flag_inline_functions, 1,
+ "Integrate simple functions into their callers" },
+ {"keep-inline-functions", &flag_keep_inline_functions, 1,
+ "Generate code for funcs even if they are fully inlined" },
+ {"inline", &flag_no_inline, 0,
+ "Pay attention to the 'inline' keyword"},
+ {"keep-static-consts", &flag_keep_static_consts, 1,
+ "Emit static const variables even if they are not used" },
+ {"syntax-only", &flag_syntax_only, 1,
+ "Check for syntax errors, then stop" },
+ {"shared-data", &flag_shared_data, 1,
+ "Mark data as shared rather than private" },
+ {"caller-saves", &flag_caller_saves, 1,
+ "Enable saving registers around function calls" },
+ {"pcc-struct-return", &flag_pcc_struct_return, 1,
+ "Return 'short' aggregates in memory, not registers" },
+ {"reg-struct-return", &flag_pcc_struct_return, 0,
+ "Return 'short' aggregates in registers" },
+ {"delayed-branch", &flag_delayed_branch, 1,
+ "Attempt to fill delay slots of branch instructions" },
+ {"gcse", &flag_gcse, 1,
+ "Perform the global common subexpression elimination" },
+ {"rerun-cse-after-loop", &flag_rerun_cse_after_loop, 1,
+ "Run CSE pass after loop optimisations"},
+ {"structure-noalias", &flag_structure_noalias, 1,
+ "Assume structure / array reference and fixed scalar cannot alias"},
+ {"rerun-loop-opt", &flag_rerun_loop_opt, 1,
+ "Run the loop optimiser twice"},
+ {"pretend-float", &flag_pretend_float, 1,
+ "Pretend that host and target use the same FP format"},
+ {"schedule-insns", &flag_schedule_insns, 1,
+ "Reschedule instructions to avoid pipeline stalls"},
+ {"schedule-insns2", &flag_schedule_insns_after_reload, 1,
+ "Run two passes of the instruction scheduler"},
+#ifdef HAIFA
+ {"sched-interblock",&flag_schedule_interblock, 1,
+ "Enable scheduling across basic blocks" },
+ {"sched-spec",&flag_schedule_speculative, 1,
+ "Allow speculative motion of non-loads" },
+ {"sched-spec-load",&flag_schedule_speculative_load, 1,
+ "Allow speculative motion of some loads" },
+ {"sched-spec-load-dangerous",&flag_schedule_speculative_load_dangerous, 1,
+ "Allow speculative motion of more loads" },
+ {"branch-count-reg",&flag_branch_on_count_reg, 1,
+ "Replace add,compare,branch with branch on count reg"},
+#endif /* HAIFA */
+ {"pic", &flag_pic, 1,
+ "Generate position independent code, if possible"},
+ {"PIC", &flag_pic, 2, ""},
+ {"exceptions", &flag_exceptions, 1,
+ "Enable exception handling" },
+ {"new-exceptions", &flag_new_exceptions, 1,
+ "Use the new model for exception handling" },
+ {"sjlj-exceptions", &exceptions_via_longjmp, 1,
+ "Use setjmp/longjmp to handle exceptions" },
+ {"asynchronous-exceptions", &asynchronous_exceptions, 1,
+ "Support asynchronous exceptions" },
+ {"profile-arcs", &profile_arc_flag, 1,
+ "Insert arc based program profiling code" },
+ {"test-coverage", &flag_test_coverage, 1,
+ "Create data files needed by gcov" },
+ {"branch-probabilities", &flag_branch_probabilities, 1,
+ "Use profiling information for branch porbabilities" },
+ {"fast-math", &flag_fast_math, 1,
+ "Improve FP speed by violating ANSI & IEEE rules" },
+ {"common", &flag_no_common, 0,
+ "Do not put unitialised globals in the common section" },
+ {"inhibit-size-directive", &flag_inhibit_size_directive, 1,
+ "Do not generate .size directives" },
+ {"function-sections", &flag_function_sections, 1,
+ "place each function into its own section" },
+ {"verbose-asm", &flag_verbose_asm, 1,
+ "Add extra commentry to assembler output"},
+ {"gnu-linker", &flag_gnu_linker, 1,
+ "Output GNU ld formatted global initialisers"},
+ {"regmove", &flag_regmove, 1,
+ "Enables a regoster move optimisation"},
+ {"optimize-register-move", &flag_regmove, 1},
+ {"pack-struct", &flag_pack_struct, 1,
+ "Pack structure members together without holes" },
+ {"stack-check", &flag_stack_check, 1,
+ "Insert stack checking code into the program" },
+ {"argument-alias", &flag_argument_noalias, 0,
+ "Specify that arguments may alias each other & globals"},
+ {"argument-noalias", &flag_argument_noalias, 1,
+ "Assume arguments may alias globals but not each other"},
+ {"argument-noalias-global", &flag_argument_noalias, 2,
+ "Assume arguments do not alias each other or globals" },
+ {"strict-aliasing", &flag_strict_aliasing, 1,
+ "Assume strict aliasing rules apply" },
+ {"check-memory-usage", &flag_check_memory_usage, 1,
+ "Generate code to check every memory access" },
+ {"prefix-function-name", &flag_prefix_function_name, 1,
+ "Add a prefix to all function names" },
+ {"dump-unnumbered", &flag_dump_unnumbered, 1}
};
+#define NUM_ELEM(a) (sizeof (a) / sizeof ((a)[0]))
+
/* Table of language-specific options. */
-char *lang_options[] =
-{
- "-ansi",
- "-fallow-single-precision",
-
- "-fsigned-bitfields",
- "-funsigned-bitfields",
- "-fno-signed-bitfields",
- "-fno-unsigned-bitfields",
- "-fsigned-char",
- "-funsigned-char",
- "-fno-signed-char",
- "-fno-unsigned-char",
-
- "-ftraditional",
- "-traditional",
- "-fnotraditional",
- "-fno-traditional",
-
- "-fasm",
- "-fno-asm",
- "-fbuiltin",
- "-fno-builtin",
- "-fcond-mismatch",
- "-fno-cond-mismatch",
- "-fdollars-in-identifiers",
- "-fno-dollars-in-identifiers",
- "-fident",
- "-fno-ident",
- "-fshort-double",
- "-fno-short-double",
- "-fshort-enums",
- "-fno-short-enums",
-
- "-Wall",
- "-Wbad-function-cast",
- "-Wno-bad-function-cast",
- "-Wcast-qual",
- "-Wno-cast-qual",
- "-Wchar-subscripts",
- "-Wno-char-subscripts",
- "-Wcomment",
- "-Wno-comment",
- "-Wcomments",
- "-Wno-comments",
- "-Wconversion",
- "-Wno-conversion",
- "-Wformat",
- "-Wno-format",
- "-Wimport",
- "-Wno-import",
- "-Wimplicit",
- "-Wno-implicit",
- "-Wmissing-braces",
- "-Wno-missing-braces",
- "-Wmissing-declarations",
- "-Wno-missing-declarations",
- "-Wmissing-prototypes",
- "-Wno-missing-prototypes",
- "-Wnested-externs",
- "-Wno-nested-externs",
- "-Wparentheses",
- "-Wno-parentheses",
- "-Wpointer-arith",
- "-Wno-pointer-arith",
- "-Wredundant-decls",
- "-Wno-redundant-decls",
- "-Wstrict-prototypes",
- "-Wno-strict-prototypes",
- "-Wtraditional",
- "-Wno-traditional",
- "-Wtrigraphs",
- "-Wno-trigraphs",
- "-Wwrite-strings",
- "-Wno-write-strings",
-
- /* these are for obj c */
- "-lang-objc",
- "-gen-decls",
- "-fgnu-runtime",
- "-fno-gnu-runtime",
- "-fnext-runtime",
- "-fno-next-runtime",
- "-Wselector",
- "-Wno-selector",
- "-Wprotocol",
- "-Wno-protocol",
+static struct lang_opt
+{
+ char * option;
+ char * description;
+}
+documented_lang_options[] =
+{
+ /* In order not to overload the --help output, the convention
+ used here is to only describe those options which are not
+ enabled by default. */
+
+ { "-ansi", "Compile just for ANSI C" },
+ { "-fallow-single-precision",
+ "Do not promote floats to double if using -traditional" },
+
+ { "-fsigned-bitfields", "" },
+ { "-funsigned-bitfields","Make bitfields by unsigned by default" },
+ { "-fno-signed-bitfields", "" },
+ { "-fno-unsigned-bitfields","" },
+ { "-fsigned-char", "Make 'char' be signed by default"},
+ { "-funsigned-char", "Make 'char' be unsigned by default"},
+ { "-fno-signed-char", "" },
+ { "-fno-unsigned-char", "" },
+
+ { "-ftraditional", "" },
+ { "-traditional", "Attempt to support traditional K&R style C"},
+ { "-fnotraditional", "" },
+ { "-fno-traditional", "" },
+
+ { "-fasm", "" },
+ { "-fno-asm", "Do not recognise the 'asm' keyword" },
+ { "-fbuiltin", "" },
+ { "-fno-builtin", "Do not recognise any built in functions" },
+ { "-fhosted", "Assume normal C execution environment" },
+ { "-fno-hosted", "" },
+ { "-ffreestanding",
+ "Assume that standard libraries & main might not exist" },
+ { "-fno-freestanding", "" },
+ { "-fcond-mismatch", "Allow different types as args of ? operator"},
+ { "-fno-cond-mismatch", "" },
+ { "-fdollars-in-identifiers", "Allow the use of $ inside indentifiers" },
+ { "-fno-dollars-in-identifiers", "" },
+ { "-fident", "" },
+ { "-fno-ident", "Ignore #ident directives" },
+ { "-fshort-double", "Use the same size for double as for float" },
+ { "-fno-short-double", "" },
+ { "-fshort-enums", "Use the smallest fitting integer to hold enums"},
+ { "-fno-short-enums", "" },
+
+ { "-Wall", "Enable most warning messages" },
+ { "-Wbad-function-cast",
+ "Warn about casting functions to incompatible types" },
+ { "-Wno-bad-function-cast", "" },
+ { "-Wcast-qual", "Warn about casts which discard qualifiers"},
+ { "-Wno-cast-qual", "" },
+ { "-Wchar-subscripts", "Warn about subscripts whoes type is 'char'"},
+ { "-Wno-char-subscripts", "" },
+ { "-Wcomment", "Warn if nested comments are detected" },
+ { "-Wno-comment", },
+ { "-Wcomments", },
+ { "-Wno-comments", },
+ { "-Wconversion", "Warn about possibly confusing type conversions" },
+ { "-Wno-conversion", "" },
+ { "-Wformat", "Warn about printf format anomalies" },
+ { "-Wno-format", "" },
+ { "-Wimplicit-function-declaration",
+ "Warn about implicit function declarations" },
+ { "-Wno-implicit-function-declaration", "" },
+ { "-Werror-implicit-function-declaration", "" },
+ { "-Wimplicit-int", "Warn when a declaration does not specify a type" },
+ { "-Wno-implicit-int", "" },
+ { "-Wimplicit", "" },
+ { "-Wno-implicit", "" },
+ { "-Wimport", "Warn about the use of the #import directive" },
+ { "-Wno-import", "" },
+ { "-Wlong-long","" },
+ { "-Wno-long-long", "Do not warn about using 'long long' when -pedantic" },
+ { "-Wmain", "Warn about suspicious declarations of main" },
+ { "-Wno-main", "" },
+ { "-Wmissing-braces",
+ "Warn about possibly missing braces around initialisers" },
+ { "-Wno-missing-braces", "" },
+ { "-Wmissing-declarations",
+ "Warn about global funcs without previous declarations"},
+ { "-Wno-missing-declarations", "" },
+ { "-Wmissing-prototypes", "Warn about global funcs without prototypes" },
+ { "-Wno-missing-prototypes", "" },
+ { "-Wmultichar", "Warn about use of multicharacter literals"},
+ { "-Wno-multichar", "" },
+ { "-Wnested-externs", "Warn about externs not at file scope level" },
+ { "-Wno-nested-externs", "" },
+ { "-Wparentheses", "Warn about possible missing parentheses" },
+ { "-Wno-parentheses", "" },
+ { "-Wpointer-arith", "Warn about function pointer arithmetic" },
+ { "-Wno-pointer-arith", "" },
+ { "-Wredundant-decls",
+ "Warn about multiple declarations of the same object" },
+ { "-Wno-redundant-decls", "" },
+ { "-Wsign-compare", "Warn about signed/unsigned comparisons" },
+ { "-Wno-sign-compare", "" },
+ { "-Wunknown-pragmas", "Warn about unrecognised pragmas" },
+ { "-Wno-unknown-pragmas", "" },
+ { "-Wstrict-prototypes", "Warn about non-prototyped function decls" },
+ { "-Wno-strict-prototypes", "" },
+ { "-Wtraditional", "Warn about constructs whoes meaning change in ANSI C"},
+ { "-Wno-traditional", "" },
+ { "-Wtrigraphs", "Warn when trigraphs are encountered" },
+ { "-Wno-trigraphs", "" },
+ { "-Wundef", "" },
+ { "-Wno-undef", "" },
+ { "-Wwrite-strings", "Mark strings as 'const char *'"},
+ { "-Wno-write-strings", "" },
+
+ /* These are for languages with USE_CPPLIB. */
+ /* These options are already documented in cpplib.c */
+ { "--help", "" },
+ { "-A", "" },
+ { "-D", "" },
+ { "-I", "" },
+ { "-U", "" },
+ { "-idirafter", "" },
+ { "-iprefix", "" },
+ { "-isystem", "" },
+ { "-lang-c", "" },
+ { "-lang-c89", "" },
+ { "-lang-c++", "" },
+ { "-nostdinc", "" },
+ { "-nostdinc++", "" },
+ { "-trigraphs", "" },
+ { "-undef", "" },
+ { "-remap", "" },
+
+#define DEFINE_LANG_NAME(NAME) { NULL, NAME },
+
+ /* These are for obj c. */
+ DEFINE_LANG_NAME ("Objective C")
+
+ { "-lang-objc", "" },
+ { "-gen-decls", "Dump decls to a .decl file" },
+ { "-fgnu-runtime", "Generate code for GNU runtime envrionment" },
+ { "-fno-gnu-runtime", "" },
+ { "-fnext-runtime", "Generate code for NeXT runtime environment" },
+ { "-fno-next-runtime", "" },
+ { "-Wselector", "Warn if a selector has multiple methods" },
+ { "-Wno-selector", "" },
+ { "-Wprotocol", "" },
+ { "-Wno-protocol", "Do not warn if inherited methods are unimplemented"},
+ { "-print-objc-runtime-info",
+ "Generate C header of platform specific features" },
#include "options.h"
- 0
+
};
+
+/* Here is a table, controlled by the tm.h file, listing each -m switch
+ and which bits in `target_switches' it should set or clear.
+ If VALUE is positive, it is bits to set.
+ If VALUE is negative, -VALUE is bits to clear.
+ (The sign bit is not used so there is no confusion.) */
+
+struct
+{
+ char * name;
+ int value;
+ char * description;
+}
+target_switches [] = TARGET_SWITCHES;
+
+/* This table is similar, but allows the switch to have a value. */
+
+#ifdef TARGET_OPTIONS
+struct
+{
+ char * prefix;
+ char ** variable;
+ char * description;
+}
+target_options [] = TARGET_OPTIONS;
+#endif
/* Options controlling warnings */
@@ -729,16 +1167,21 @@ int warn_aggregate_return;
/* Likewise for -W. */
-struct { char *string; int *variable; int on_value;} W_options[] =
+lang_independent_options W_options[] =
{
- {"unused", &warn_unused, 1},
- {"error", &warnings_are_errors, 1},
- {"shadow", &warn_shadow, 1},
- {"switch", &warn_switch, 1},
- {"aggregate-return", &warn_aggregate_return, 1},
- {"cast-align", &warn_cast_align, 1},
- {"uninitialized", &warn_uninitialized, 1},
- {"inline", &warn_inline, 1}
+ {"unused", &warn_unused, 1, "Warn when a variable is unused" },
+ {"error", &warnings_are_errors, 1, ""},
+ {"shadow", &warn_shadow, 1, "Warn when one local variable shadows another" },
+ {"switch", &warn_switch, 1,
+ "Warn about enumerated switches missing a specific case" },
+ {"aggregate-return", &warn_aggregate_return, 1,
+ "Warn about returning structures, unions or arrays" },
+ {"cast-align", &warn_cast_align, 1,
+ "Warn about pointer casts which increase alignment" },
+ {"uninitialized", &warn_uninitialized, 1,
+ "Warn about unitialized automatic variables"},
+ {"inline", &warn_inline, 1,
+ "Warn when an inlined function cannot be inlined"}
};
/* Output files for assembler code (real compiler output)
@@ -746,20 +1189,7 @@ struct { char *string; int *variable; int on_value;} W_options[] =
FILE *asm_out_file;
FILE *aux_info_file;
-FILE *rtl_dump_file;
-FILE *jump_opt_dump_file;
-FILE *cse_dump_file;
-FILE *loop_dump_file;
-FILE *cse2_dump_file;
-FILE *flow_dump_file;
-FILE *combine_dump_file;
-FILE *sched_dump_file;
-FILE *local_reg_dump_file;
-FILE *global_reg_dump_file;
-FILE *sched2_dump_file;
-FILE *jump2_opt_dump_file;
-FILE *dbr_sched_dump_file;
-FILE *stack_reg_dump_file;
+FILE *rtl_dump_file = NULL;
/* Time accumulators, to count the total time spent in various passes. */
@@ -768,15 +1198,20 @@ int varconst_time;
int integration_time;
int jump_time;
int cse_time;
+int gcse_time;
int loop_time;
int cse2_time;
+int branch_prob_time;
int flow_time;
int combine_time;
+int regmove_time;
int sched_time;
int local_alloc_time;
int global_alloc_time;
int sched2_time;
+#ifdef DELAY_SLOTS
int dbr_sched_time;
+#endif
int shorten_branch_time;
int stack_reg_time;
int final_time;
@@ -788,46 +1223,68 @@ int dump_time;
int
get_run_time ()
{
-#ifndef _WIN32
-#ifdef USG
- struct tms tms;
-#else
-#ifndef VMS
- struct rusage rusage;
-#else
- struct
- {
- int proc_user_time;
- int proc_system_time;
- int child_user_time;
- int child_system_time;
- } vms_times;
-#endif
-#endif
-#endif
-
if (quiet_flag)
return 0;
-#ifdef _WIN32
+
+#ifdef __BEOS__
+ return 0;
+#else /* not BeOS */
+#if defined (_WIN32) && !defined (__CYGWIN32__)
if (clock() < 0)
return 0;
else
return (clock() * 1000);
#else /* not _WIN32 */
+#ifdef _SC_CLK_TCK
+ {
+ static int tick;
+ struct tms tms;
+ if (tick == 0)
+ tick = 1000000 / sysconf(_SC_CLK_TCK);
+ times (&tms);
+ return (tms.tms_utime + tms.tms_stime) * tick;
+ }
+#else
#ifdef USG
- times (&tms);
- return (tms.tms_utime + tms.tms_stime) * (1000000 / HZ);
+ {
+ struct tms tms;
+# if HAVE_SYSCONF && defined _SC_CLK_TCK
+# define TICKS_PER_SECOND sysconf (_SC_CLK_TCK) /* POSIX 1003.1-1996 */
+# else
+# ifdef CLK_TCK
+# define TICKS_PER_SECOND CLK_TCK /* POSIX 1003.1-1988; obsolescent */
+# else
+# define TICKS_PER_SECOND HZ /* traditional UNIX */
+# endif
+# endif
+ times (&tms);
+ return (tms.tms_utime + tms.tms_stime) * (1000000 / TICKS_PER_SECOND);
+ }
#else
#ifndef VMS
- getrusage (0, &rusage);
- return (rusage.ru_utime.tv_sec * 1000000 + rusage.ru_utime.tv_usec
- + rusage.ru_stime.tv_sec * 1000000 + rusage.ru_stime.tv_usec);
+ {
+ struct rusage rusage;
+ getrusage (0, &rusage);
+ return (rusage.ru_utime.tv_sec * 1000000 + rusage.ru_utime.tv_usec
+ + rusage.ru_stime.tv_sec * 1000000 + rusage.ru_stime.tv_usec);
+ }
#else /* VMS */
- times (&vms_times);
- return (vms_times.proc_user_time + vms_times.proc_system_time) * 10000;
-#endif
-#endif
-#endif
+ {
+ struct
+ {
+ int proc_user_time;
+ int proc_system_time;
+ int child_user_time;
+ int child_system_time;
+ } vms_times;
+ times ((void *) &vms_times);
+ return (vms_times.proc_user_time + vms_times.proc_system_time) * 10000;
+ }
+#endif /* VMS */
+#endif /* USG */
+#endif /* _SC_CLK_TCK */
+#endif /* _WIN32 */
+#endif /* __BEOS__ */
}
#define TIMEVAR(VAR, BODY) \
@@ -897,43 +1354,16 @@ fatal_insn (message, insn)
char *message;
rtx insn;
{
- if (!output_bytecode)
- {
- error (message);
- debug_rtx (insn);
- }
+ error (message);
+ debug_rtx (insn);
if (asm_out_file)
fflush (asm_out_file);
if (aux_info_file)
fflush (aux_info_file);
- if (rtl_dump_file)
+ if (rtl_dump_file != NULL)
fflush (rtl_dump_file);
- if (jump_opt_dump_file)
- fflush (jump_opt_dump_file);
- if (cse_dump_file)
- fflush (cse_dump_file);
- if (loop_dump_file)
- fflush (loop_dump_file);
- if (cse2_dump_file)
- fflush (cse2_dump_file);
- if (flow_dump_file)
- fflush (flow_dump_file);
- if (combine_dump_file)
- fflush (combine_dump_file);
- if (sched_dump_file)
- fflush (sched_dump_file);
- if (local_reg_dump_file)
- fflush (local_reg_dump_file);
- if (global_reg_dump_file)
- fflush (global_reg_dump_file);
- if (sched2_dump_file)
- fflush (sched2_dump_file);
- if (jump2_opt_dump_file)
- fflush (jump2_opt_dump_file);
- if (dbr_sched_dump_file)
- fflush (dbr_sched_dump_file);
- if (stack_reg_dump_file)
- fflush (stack_reg_dump_file);
+ fflush (stdout);
+ fflush (stderr);
abort ();
}
@@ -954,21 +1384,12 @@ fatal_insn_not_found (insn)
/* This is the default decl_printable_name function. */
static char *
-decl_name (decl, kind)
+decl_name (decl, verbosity)
tree decl;
- char **kind;
+ int verbosity;
{
return IDENTIFIER_POINTER (DECL_NAME (decl));
}
-
-/* This is the default interim_eh_hook function. */
-
-void
-interim_eh (finalization)
- tree finalization;
-{
- /* Don't do anything by default. */
-}
static int need_error_newline;
@@ -989,11 +1410,10 @@ announce_function (decl)
{
if (! quiet_flag)
{
- char *junk;
if (rtl_dump_and_exit)
fprintf (stderr, "%s ", IDENTIFIER_POINTER (DECL_NAME (decl)));
else
- fprintf (stderr, " %s", (*decl_printable_name) (decl, &junk));
+ fprintf (stderr, " %s", (*decl_printable_name) (decl, 2));
fflush (stderr);
need_error_newline = 1;
last_error_function = current_function_decl;
@@ -1021,7 +1441,7 @@ default_print_error_function (file)
fprintf (stderr, "At top level:\n");
else
{
- char *name = (*decl_printable_name) (current_function_decl, &kind);
+ char *name = (*decl_printable_name) (current_function_decl, 2);
fprintf (stderr, "In %s `%s':\n", kind, name);
}
@@ -1030,9 +1450,9 @@ default_print_error_function (file)
}
/* Called by report_error_function to print out function name.
- * Default may be overridden by language front-ends. */
+ * Default may be overridden by language front-ends. */
-void (*print_error_function) PROTO((char*)) = default_print_error_function;
+void (*print_error_function) PROTO((char *)) = default_print_error_function;
/* Prints out, if necessary, the name of the current function
that caused an error. Called from all error and warning functions. */
@@ -1078,17 +1498,7 @@ vmessage (prefix, s, ap)
if (prefix)
fprintf (stderr, "%s: ", prefix);
-#ifdef HAVE_VPRINTF
vfprintf (stderr, s, ap);
-#else
- {
- HOST_WIDE_INT v1 = va_arg(ap, HOST_WIDE_INT);
- HOST_WIDE_INT v2 = va_arg(ap, HOST_WIDE_INT);
- HOST_WIDE_INT v3 = va_arg(ap, HOST_WIDE_INT);
- HOST_WIDE_INT v4 = va_arg(ap, HOST_WIDE_INT);
- fprintf (stderr, s, v1, v2, v3, v4);
- }
-#endif
}
/* Print a message relevant to line LINE of file FILE. */
@@ -1119,7 +1529,7 @@ v_message_with_decl (decl, prefix, s, ap)
char *s;
va_list ap;
{
- char *n, *p, *junk;
+ char *p;
fprintf (stderr, "%s:%d: ",
DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl));
@@ -1155,13 +1565,13 @@ v_message_with_decl (decl, prefix, s, ap)
if (*p == '%') /* Print the name. */
{
char *n = (DECL_NAME (decl)
- ? (*decl_printable_name) (decl, &junk)
+ ? (*decl_printable_name) (decl, 2)
: "((anonymous))");
fputs (n, stderr);
while (*p)
{
++p;
- if (isalpha (*(p - 1) & 0xFF))
+ if (ISALPHA (*(p - 1) & 0xFF))
break;
}
}
@@ -1725,6 +2135,7 @@ do_abort ()
void
botch (s)
+ char * s;
{
abort ();
}
@@ -1735,22 +2146,69 @@ char *
xmalloc (size)
unsigned size;
{
- register char *value = (char *) malloc (size);
+ register char *value;
+
+ if (size == 0)
+ size = 1;
+
+ value = (char *) malloc (size);
if (value == 0)
fatal ("virtual memory exhausted");
return value;
}
-/* Same as `realloc' but report error if no memory available. */
+/* Same as `calloc' but report error if no memory available. */
+
+char *
+xcalloc (size1, size2)
+ unsigned size1, size2;
+{
+ register char *value;
+
+ if (size1 == 0 || size2 == 0)
+ size1 = size2 = 1;
+
+ value = (char *) calloc (size1, size2);
+ if (value == 0)
+ fatal ("virtual memory exhausted");
+ return value;
+}
+
+
+/* Same as `realloc' but report error if no memory available.
+ Also handle null PTR even if the vendor realloc gets it wrong. */
char *
xrealloc (ptr, size)
char *ptr;
int size;
{
- char *result = (char *) realloc (ptr, size);
+ char *result;
+
+ if (size == 0)
+ size = 1;
+
+ result = (ptr
+ ? (char *) realloc (ptr, size)
+ : (char *) malloc (size));
+
if (!result)
fatal ("virtual memory exhausted");
+
+ return result;
+}
+
+/* Same as `strdup' but report error if no memory available. */
+
+char *
+xstrdup (s)
+ register char *s;
+{
+ register char *result = (char *) malloc (strlen (s) + 1);
+
+ if (! result)
+ fatal ("virtual memory exhausted");
+ strcpy (result, s);
return result;
}
@@ -1788,9 +2246,27 @@ floor_log2_wide (x)
return log;
}
+static int float_handler_set;
int float_handled;
jmp_buf float_handler;
+/* Signals actually come here. */
+
+static void
+float_signal (signo)
+ /* If this is missing, some compilers complain. */
+ int signo ATTRIBUTE_UNUSED;
+{
+ if (float_handled == 0)
+ abort ();
+#if defined (USG) || defined (hpux)
+ signal (SIGFPE, float_signal); /* re-enable the signal catcher */
+#endif
+ float_handled = 0;
+ signal (SIGFPE, float_signal);
+ longjmp (float_handler, 1);
+}
+
/* Specify where to longjmp to when a floating arithmetic error happens.
If HANDLER is 0, it means don't handle the errors any more. */
@@ -1801,6 +2277,12 @@ set_float_handler (handler)
float_handled = (handler != 0);
if (handler)
bcopy ((char *) handler, (char *) float_handler, sizeof (float_handler));
+
+ if (float_handled && ! float_handler_set)
+ {
+ signal (SIGFPE, float_signal);
+ float_handler_set = 1;
+ }
}
/* Specify, in HANDLER, where to longjmp to when a floating arithmetic
@@ -1835,57 +2317,47 @@ pop_float_handler (handled, handler)
bcopy ((char *) handler, (char *) float_handler, sizeof (float_handler));
}
-/* Signals actually come here. */
-
-static void
-float_signal (signo)
- /* If this is missing, some compilers complain. */
- int signo;
-{
- if (float_handled == 0)
- abort ();
-#if defined (USG) || defined (hpux)
- signal (SIGFPE, float_signal); /* re-enable the signal catcher */
-#endif
- float_handled = 0;
- signal (SIGFPE, float_signal);
- longjmp (float_handler, 1);
-}
-
/* Handler for SIGPIPE. */
static void
pipe_closed (signo)
/* If this is missing, some compilers complain. */
- int signo;
+ int signo ATTRIBUTE_UNUSED;
{
fatal ("output pipe has been closed");
}
/* Strip off a legitimate source ending from the input string NAME of
length LEN. Rather than having to know the names used by all of
- our front ends, we strip off an ending of a period followed by one,
- two, or three characters. */
+ our front ends, we strip off an ending of a period followed by
+ up to five characters. (Java uses ".class".) */
void
strip_off_ending (name, len)
char *name;
int len;
{
- if (len > 2 && name[len - 2] == '.')
- name[len - 2] = '\0';
- else if (len > 3 && name[len - 3] == '.')
- name[len - 3] = '\0';
- else if (len > 4 && name[len - 4] == '.')
- name[len - 4] = '\0';
+ int i;
+ for (i = 2; i < 6 && len > i; i++)
+ {
+ if (name[len - i] == '.')
+ {
+ name[len - i] = '\0';
+ break;
+ }
+ }
}
/* Output a quoted string. */
+
void
output_quoted_string (asm_file, string)
FILE *asm_file;
char *string;
{
+#ifdef OUTPUT_QUOTED_STRING
+ OUTPUT_QUOTED_STRING (asm_file, string);
+#else
char c;
putc ('\"', asm_file);
@@ -1896,6 +2368,7 @@ output_quoted_string (asm_file, string)
putc (c, asm_file);
}
putc ('\"', asm_file);
+#endif
}
/* Output a file name in the form wanted by System V. */
@@ -1929,7 +2402,8 @@ output_file_directive (asm_file, input_name)
#endif
}
-/* Routine to build language identifier for object file. */
+/* Routine to build language identifier for object file. */
+
static void
output_lang_identify (asm_out_file)
FILE *asm_out_file;
@@ -1941,22 +2415,97 @@ output_lang_identify (asm_out_file)
}
/* Routine to open a dump file. */
-static FILE *
-open_dump_file (base_name, suffix)
- char *base_name;
+static void
+open_dump_file (suffix, function_name)
+ char *suffix;
+ char *function_name;
+{
+ char *dumpname;
+
+ TIMEVAR
+ (dump_time,
+ {
+ dumpname = (char *) xmalloc (strlen (dump_base_name) + strlen (suffix) + 1);
+
+ if (rtl_dump_file != NULL)
+ fclose (rtl_dump_file);
+
+ strcpy (dumpname, dump_base_name);
+ strcat (dumpname, suffix);
+
+ rtl_dump_file = fopen (dumpname, "a");
+
+ if (rtl_dump_file == NULL)
+ pfatal_with_name (dumpname);
+
+ free (dumpname);
+
+ if (function_name)
+ fprintf (rtl_dump_file, "\n;; Function %s\n\n", function_name);
+ });
+
+ return;
+}
+
+/* Routine to close a dump file. */
+static void
+close_dump_file (func, insns)
+ void (*func) PROTO ((FILE *, rtx));
+ rtx insns;
+{
+ TIMEVAR
+ (dump_time,
+ {
+ if (func)
+ func (rtl_dump_file, insns);
+
+ fflush (rtl_dump_file);
+ fclose (rtl_dump_file);
+
+ rtl_dump_file = NULL;
+ });
+
+ return;
+}
+
+/* Routine to dump rtl into a file. */
+static void
+dump_rtl (suffix, decl, func, insns)
char *suffix;
+ tree decl;
+ void (*func) PROTO ((FILE *, rtx));
+ rtx insns;
{
- FILE *f;
- char *dumpname = (char *) alloca (strlen (base_name) + strlen (suffix) + 1);
+ open_dump_file (suffix, decl_printable_name (decl, 2));
+ close_dump_file (func, insns);
+}
- strcpy (dumpname, base_name);
+/* Routine to empty a dump file. */
+static void
+clean_dump_file (suffix)
+ char * suffix;
+{
+ char * dumpname;
+
+ dumpname = (char *) xmalloc (strlen (dump_base_name) + strlen (suffix) + 1);
+
+ strcpy (dumpname, dump_base_name);
strcat (dumpname, suffix);
- f = fopen (dumpname, "w");
- if (f == 0)
- pfatal_with_name (dumpname);
- return f;
+
+ rtl_dump_file = fopen (dumpname, "w");
+
+ if (rtl_dump_file == NULL)
+ pfatal_with_name (dumpname);
+
+ free (dumpname);
+
+ fclose (rtl_dump_file);
+ rtl_dump_file = NULL;
+
+ return;
}
+
/* Compile an entire file of output from cpp, named NAME.
Write a file of assembly output and various debugging dumps. */
@@ -1977,47 +2526,35 @@ compile_file (name)
integration_time = 0;
jump_time = 0;
cse_time = 0;
+ gcse_time = 0;
loop_time = 0;
cse2_time = 0;
+ branch_prob_time = 0;
flow_time = 0;
combine_time = 0;
+ regmove_time = 0;
sched_time = 0;
local_alloc_time = 0;
global_alloc_time = 0;
sched2_time = 0;
+#ifdef DELAY_SLOTS
dbr_sched_time = 0;
+#endif
shorten_branch_time = 0;
stack_reg_time = 0;
final_time = 0;
symout_time = 0;
dump_time = 0;
- /* Open input file. */
-
- if (name == 0 || !strcmp (name, "-"))
- {
- finput = stdin;
- name = "stdin";
- }
- else
- finput = fopen (name, "r");
- if (finput == 0)
- pfatal_with_name (name);
-
-#ifdef IO_BUFFER_SIZE
- setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE);
-#endif
-
/* Initialize data in various passes. */
init_obstacks ();
init_tree_codes ();
- init_lex ();
- /* Some of these really don't need to be called when generating bytecode,
- but the options would have to be parsed first to know that. -bson */
+ name = init_parse (name);
init_rtl ();
init_emit_once (debug_info_level == DINFO_LEVEL_NORMAL
- || debug_info_level == DINFO_LEVEL_VERBOSE);
+ || debug_info_level == DINFO_LEVEL_VERBOSE
+ || flag_test_coverage);
init_regs ();
init_decl_processing ();
init_optabs ();
@@ -2026,6 +2563,7 @@ compile_file (name)
init_expr_once ();
init_loop ();
init_reload ();
+ init_alias_once ();
if (flag_caller_saves)
init_caller_save ();
@@ -2040,64 +2578,50 @@ compile_file (name)
pfatal_with_name (aux_info_file_name);
}
- /* If rtl dump desired, open the output file. */
+ /* Clear the dump files file. */
if (rtl_dump)
- rtl_dump_file = open_dump_file (dump_base_name, ".rtl");
-
- /* If jump_opt dump desired, open the output file. */
+ clean_dump_file (".rtl");
if (jump_opt_dump)
- jump_opt_dump_file = open_dump_file (dump_base_name, ".jump");
-
- /* If cse dump desired, open the output file. */
+ clean_dump_file (".jump");
+ if (addressof_dump)
+ clean_dump_file (".addressof");
if (cse_dump)
- cse_dump_file = open_dump_file (dump_base_name, ".cse");
-
- /* If loop dump desired, open the output file. */
+ clean_dump_file (".cse");
if (loop_dump)
- loop_dump_file = open_dump_file (dump_base_name, ".loop");
-
- /* If cse2 dump desired, open the output file. */
+ clean_dump_file (".loop");
if (cse2_dump)
- cse2_dump_file = open_dump_file (dump_base_name, ".cse2");
-
- /* If flow dump desired, open the output file. */
+ clean_dump_file (".cse2");
+ if (branch_prob_dump)
+ clean_dump_file (".bp");
if (flow_dump)
- flow_dump_file = open_dump_file (dump_base_name, ".flow");
-
- /* If combine dump desired, open the output file. */
+ clean_dump_file (".flow");
if (combine_dump)
- combine_dump_file = open_dump_file (dump_base_name, ".combine");
-
- /* If scheduling dump desired, open the output file. */
+ clean_dump_file (".combine");
+ if (regmove_dump)
+ clean_dump_file (".regmove");
if (sched_dump)
- sched_dump_file = open_dump_file (dump_base_name, ".sched");
-
- /* If local_reg dump desired, open the output file. */
+ clean_dump_file (".sched");
if (local_reg_dump)
- local_reg_dump_file = open_dump_file (dump_base_name, ".lreg");
-
- /* If global_reg dump desired, open the output file. */
+ clean_dump_file (".lreg");
if (global_reg_dump)
- global_reg_dump_file = open_dump_file (dump_base_name, ".greg");
-
- /* If 2nd scheduling dump desired, open the output file. */
+ clean_dump_file (".greg");
if (sched2_dump)
- sched2_dump_file = open_dump_file (dump_base_name, ".sched2");
-
- /* If jump2_opt dump desired, open the output file. */
+ clean_dump_file (".sched2");
if (jump2_opt_dump)
- jump2_opt_dump_file = open_dump_file (dump_base_name, ".jump2");
-
- /* If dbr_sched dump desired, open the output file. */
+ clean_dump_file (".jump2");
+#ifdef DELAY_SLOTS
if (dbr_sched_dump)
- dbr_sched_dump_file = open_dump_file (dump_base_name, ".dbr");
-
+ clean_dump_file (".dbr");
+#endif
+ if (gcse_dump)
+ clean_dump_file (".gcse");
#ifdef STACK_REGS
-
- /* If stack_reg dump desired, open the output file. */
if (stack_reg_dump)
- stack_reg_dump_file = open_dump_file (dump_base_name, ".stack");
-
+ clean_dump_file (".stack");
+#endif
+#ifdef MACHINE_DEPENDENT_REORG
+ if (mach_dep_reorg_dump)
+ clean_dump_file (".mach");
#endif
/* Open assembler code output file. */
@@ -2146,49 +2670,70 @@ compile_file (name)
if (main_input_filename == 0)
main_input_filename = name;
- if (!output_bytecode)
+ ASM_FILE_START (asm_out_file);
+
+#ifdef ASM_COMMENT_START
+ if (flag_verbose_asm)
{
- ASM_FILE_START (asm_out_file);
+ /* Print the list of options in effect. */
+ print_version (asm_out_file, ASM_COMMENT_START);
+ print_switch_values (asm_out_file, 0, MAX_LINE,
+ ASM_COMMENT_START, " ", "\n");
+ /* Add a blank line here so it appears in assembler output but not
+ screen output. */
+ fprintf (asm_out_file, "\n");
}
+#endif
- /* Output something to inform GDB that this compilation was by GCC. Also
- serves to tell GDB file consists of bytecodes. */
- if (output_bytecode)
- fprintf (asm_out_file, "bc_gcc2_compiled.:\n");
- else
- {
+ /* Output something to inform GDB that this compilation was by GCC. */
#ifndef ASM_IDENTIFY_GCC
- fprintf (asm_out_file, "gcc2_compiled.:\n");
+ fprintf (asm_out_file, "gcc2_compiled.:\n");
#else
- ASM_IDENTIFY_GCC (asm_out_file);
+ ASM_IDENTIFY_GCC (asm_out_file);
#endif
- }
- /* Output something to identify which front-end produced this file. */
+ /* Output something to identify which front-end produced this file. */
#ifdef ASM_IDENTIFY_LANGUAGE
ASM_IDENTIFY_LANGUAGE (asm_out_file);
#endif
- if (output_bytecode)
+#ifndef ASM_OUTPUT_SECTION_NAME
+ if (flag_function_sections)
{
- if (profile_flag || profile_block_flag)
- error ("profiling not supported in bytecode compilation");
+ warning ("-ffunction-sections not supported for this target.");
+ flag_function_sections = 0;
}
- else
+#endif
+
+ if (flag_function_sections
+ && (profile_flag || profile_block_flag))
{
- /* ??? Note: There used to be a conditional here
- to call assemble_zeros without fail if DBX_DEBUGGING_INFO is defined.
- This was to guarantee separation between gcc_compiled. and
- the first function, for the sake of dbx on Suns.
- However, having the extra zero here confused the Emacs
- code for unexec, and might confuse other programs too.
- Therefore, I took out that change.
- In future versions we should find another way to solve
- that dbx problem. -- rms, 23 May 93. */
+ warning ("-ffunction-sections disabled; it makes profiling impossible.");
+ flag_function_sections = 0;
+ }
+
+ if (flag_function_sections && write_symbols != NO_DEBUG)
+ warning ("-ffunction-sections may affect debugging on some targets.");
+
+ /* ??? Note: There used to be a conditional here
+ to call assemble_zeros without fail if DBX_DEBUGGING_INFO is defined.
+ This was to guarantee separation between gcc_compiled. and
+ the first function, for the sake of dbx on Suns.
+ However, having the extra zero here confused the Emacs
+ code for unexec, and might confuse other programs too.
+ Therefore, I took out that change.
+ In future versions we should find another way to solve
+ that dbx problem. -- rms, 23 May 93. */
- /* Don't let the first function fall at the same address
- as gcc_compiled., if profiling. */
- if (profile_flag || profile_block_flag)
+ /* Don't let the first function fall at the same address
+ as gcc_compiled., if profiling. */
+ if (profile_flag || profile_block_flag)
+ {
+ /* It's best if we can write a nop here since some
+ assemblers don't tolerate zeros in the text section. */
+ if (insn_template[CODE_FOR_nop] != 0)
+ output_asm_insn (insn_template[CODE_FOR_nop], NULL_PTR);
+ else
assemble_zeros (UNITS_PER_WORD);
}
@@ -2208,11 +2753,19 @@ compile_file (name)
if (write_symbols == DWARF_DEBUG)
TIMEVAR (symout_time, dwarfout_init (asm_out_file, main_input_filename));
#endif
+#ifdef DWARF2_UNWIND_INFO
+ if (dwarf2out_do_frame ())
+ dwarf2out_frame_init ();
+#endif
+#ifdef DWARF2_DEBUGGING_INFO
+ if (write_symbols == DWARF2_DEBUG)
+ TIMEVAR (symout_time, dwarf2out_init (asm_out_file, main_input_filename));
+#endif
/* Initialize yet another pass. */
- if (!output_bytecode)
- init_final (main_input_filename);
+ init_final (main_input_filename);
+ init_branch_prob (dump_base_name);
start_time = get_run_time ();
@@ -2230,6 +2783,8 @@ compile_file (name)
poplevel (0, 0, 0);
}
+ output_func_start_profiler ();
+
/* Compilation is now finished except for writing
what's left of the symbol table output. */
@@ -2284,7 +2839,8 @@ compile_file (name)
/* Don't write out static consts, unless we still need them.
- We also keep static consts if not optimizing (for debugging).
+ We also keep static consts if not optimizing (for debugging),
+ unless the user specified -fno-keep-static-consts.
??? They might be better written into the debug information.
This is possible when using DWARF.
@@ -2304,12 +2860,12 @@ compile_file (name)
??? A tempting alternative (for both C and C++) would be
to force a constant to be written if and only if it is
- defined in a main file, as opposed to an include file. */
+ defined in a main file, as opposed to an include file. */
if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)
&& (! TREE_READONLY (decl)
|| TREE_PUBLIC (decl)
- || !optimize
+ || (!optimize && flag_keep_static_consts)
|| TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
{
reconsider = 1;
@@ -2320,6 +2876,7 @@ compile_file (name)
&& DECL_INITIAL (decl) != 0
&& DECL_SAVED_INSNS (decl) != 0
&& (flag_keep_inline_functions
+ || TREE_PUBLIC (decl)
|| TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
{
reconsider = 1;
@@ -2330,6 +2887,11 @@ compile_file (name)
}
}
+ /* Now that all possible functions have been output, we can dump
+ the exception table. */
+
+ output_exception_table ();
+
for (i = 0; i < len; i++)
{
decl = vec[i];
@@ -2351,6 +2913,7 @@ compile_file (name)
|| TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
&& DECL_INITIAL (decl) == 0
&& DECL_EXTERNAL (decl)
+ && ! DECL_ARTIFICIAL (decl)
&& ! TREE_PUBLIC (decl))
{
pedwarn_with_decl (decl,
@@ -2370,7 +2933,7 @@ compile_file (name)
&& ! DECL_EXTERNAL (decl)
&& ! TREE_PUBLIC (decl)
&& ! TREE_USED (decl)
- && ! DECL_REGISTER (decl)
+ && (TREE_CODE (decl) == FUNCTION_DECL || ! DECL_REGISTER (decl))
/* The TREE_USED bit for file-scope decls
is kept in the identifier, to handle multiple
external decls in different scopes. */
@@ -2389,7 +2952,7 @@ compile_file (name)
TIMEVAR (symout_time, sdbout_symbol (decl, 0));
/* Output COFF information for non-global
- file-scope initialized variables. */
+ file-scope initialized variables. */
if (write_symbols == SDB_DEBUG
&& TREE_CODE (decl) == VAR_DECL
&& DECL_INITIAL (decl)
@@ -2408,6 +2971,16 @@ compile_file (name)
&& (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl)))
TIMEVAR (symout_time, dwarfout_file_scope_decl (decl, 1));
#endif
+#ifdef DWARF2_DEBUGGING_INFO
+ /* Output DWARF2 information for file-scope tentative data object
+ declarations, file-scope (extern) function declarations (which
+ had no corresponding body) and file-scope tagged type declarations
+ and definitions which have not yet been forced out. */
+
+ if (write_symbols == DWARF2_DEBUG
+ && (TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl)))
+ TIMEVAR (symout_time, dwarf2out_decl (decl));
+#endif
}
}
@@ -2432,24 +3005,39 @@ compile_file (name)
});
#endif
- /* Output some stuff at end of file if nec. */
+#ifdef DWARF2_UNWIND_INFO
+ if (dwarf2out_do_frame ())
+ dwarf2out_frame_finish ();
+#endif
- if (!output_bytecode)
- {
- end_final (main_input_filename);
+#ifdef DWARF2_DEBUGGING_INFO
+ if (write_symbols == DWARF2_DEBUG)
+ TIMEVAR (symout_time,
+ {
+ dwarf2out_finish ();
+ });
+#endif
+ /* Output some stuff at end of file if nec. */
+
+ end_final (dump_base_name);
+
+ if (branch_prob_dump)
+ open_dump_file (".bp", NULL);
+
+ TIMEVAR (dump_time, end_branch_prob (rtl_dump_file));
+
+ if (branch_prob_dump)
+ close_dump_file (NULL, NULL_RTX);
+
#ifdef ASM_FILE_END
- ASM_FILE_END (asm_out_file);
+ ASM_FILE_END (asm_out_file);
#endif
- }
/* Language-specific end of compilation actions. */
lang_finish ();
- if (output_bytecode)
- bc_write_file (asm_out_file);
-
/* Close the dump files. */
if (flag_gen_aux_info)
@@ -2459,58 +3047,19 @@ compile_file (name)
unlink (aux_info_file_name);
}
- if (rtl_dump)
- fclose (rtl_dump_file);
-
- if (jump_opt_dump)
- fclose (jump_opt_dump_file);
-
- if (cse_dump)
- fclose (cse_dump_file);
-
- if (loop_dump)
- fclose (loop_dump_file);
-
- if (cse2_dump)
- fclose (cse2_dump_file);
-
- if (flow_dump)
- fclose (flow_dump_file);
-
if (combine_dump)
{
- dump_combine_total_stats (combine_dump_file);
- fclose (combine_dump_file);
+ open_dump_file (".combine", NULL);
+ TIMEVAR (dump_time, dump_combine_total_stats (rtl_dump_file));
+ close_dump_file (NULL, NULL_RTX);
}
- if (sched_dump)
- fclose (sched_dump_file);
-
- if (local_reg_dump)
- fclose (local_reg_dump_file);
-
- if (global_reg_dump)
- fclose (global_reg_dump_file);
-
- if (sched2_dump)
- fclose (sched2_dump_file);
-
- if (jump2_opt_dump)
- fclose (jump2_opt_dump_file);
-
- if (dbr_sched_dump)
- fclose (dbr_sched_dump_file);
-
-#ifdef STACK_REGS
- if (stack_reg_dump)
- fclose (stack_reg_dump_file);
-#endif
-
/* Close non-debugging input and output files. Take special care to note
whether fclose returns an error, since the pages might still be on the
buffer chain while the file is open. */
- fclose (finput);
+ finish_parse ();
+
if (ferror (asm_out_file) != 0 || fclose (asm_out_file) != 0)
fatal_io_error (asm_file_name);
@@ -2521,27 +3070,29 @@ compile_file (name)
fprintf (stderr,"\n");
print_time ("parse", parse_time);
- if (!output_bytecode)
- {
- print_time ("integration", integration_time);
- print_time ("jump", jump_time);
- print_time ("cse", cse_time);
- print_time ("loop", loop_time);
- print_time ("cse2", cse2_time);
- print_time ("flow", flow_time);
- print_time ("combine", combine_time);
- print_time ("sched", sched_time);
- print_time ("local-alloc", local_alloc_time);
- print_time ("global-alloc", global_alloc_time);
- print_time ("sched2", sched2_time);
- print_time ("dbranch", dbr_sched_time);
- print_time ("shorten-branch", shorten_branch_time);
- print_time ("stack-reg", stack_reg_time);
- print_time ("final", final_time);
- print_time ("varconst", varconst_time);
- print_time ("symout", symout_time);
- print_time ("dump", dump_time);
- }
+ print_time ("integration", integration_time);
+ print_time ("jump", jump_time);
+ print_time ("cse", cse_time);
+ print_time ("gcse", gcse_time);
+ print_time ("loop", loop_time);
+ print_time ("cse2", cse2_time);
+ print_time ("branch-prob", branch_prob_time);
+ print_time ("flow", flow_time);
+ print_time ("combine", combine_time);
+ print_time ("regmove", regmove_time);
+ print_time ("sched", sched_time);
+ print_time ("local-alloc", local_alloc_time);
+ print_time ("global-alloc", global_alloc_time);
+ print_time ("sched2", sched2_time);
+#ifdef DELAY_SLOTS
+ print_time ("dbranch", dbr_sched_time);
+#endif
+ print_time ("shorten-branch", shorten_branch_time);
+ print_time ("stack-reg", stack_reg_time);
+ print_time ("final", final_time);
+ print_time ("varconst", varconst_time);
+ print_time ("symout", symout_time);
+ print_time ("dump", dump_time);
}
}
@@ -2658,29 +3209,23 @@ rest_of_compilation (decl)
tree saved_arguments = 0;
int failure = 0;
- if (output_bytecode)
- return;
-
/* If we are reconsidering an inline function
at the end of compilation, skip the stuff for making it inline. */
if (DECL_SAVED_INSNS (decl) == 0)
{
- int specd = DECL_INLINE (decl);
+ int inlinable = 0;
char *lose;
/* If requested, consider whether to make this function inline. */
- if (specd || flag_inline_functions)
+ if (DECL_INLINE (decl) || flag_inline_functions)
TIMEVAR (integration_time,
{
lose = function_cannot_inline_p (decl);
- /* If not optimizing, then make sure the DECL_INLINE
- bit is off. */
if (lose || ! optimize)
{
- if (warn_inline && specd)
+ if (warn_inline && DECL_INLINE (decl))
warning_with_decl (decl, lose);
- DECL_INLINE (decl) = 0;
DECL_ABSTRACT_ORIGIN (decl) = 0;
/* Don't really compile an extern inline function.
If we can't make it inline, pretend
@@ -2692,7 +3237,11 @@ rest_of_compilation (decl)
}
}
else
- DECL_INLINE (decl) = 1;
+ /* ??? Note that this has the effect of making it look
+ like "inline" was specified for a function if we choose
+ to inline it. This isn't quite right, but it's
+ probably not worth the trouble to fix. */
+ inlinable = DECL_INLINE (decl) = 1;
});
insns = get_insns ();
@@ -2700,52 +3249,98 @@ rest_of_compilation (decl)
/* Dump the rtl code if we are dumping rtl. */
if (rtl_dump)
- TIMEVAR (dump_time,
- {
- fprintf (rtl_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- if (DECL_SAVED_INSNS (decl))
- fprintf (rtl_dump_file, ";; (integrable)\n\n");
- print_rtl (rtl_dump_file, insns);
- fflush (rtl_dump_file);
- });
+ {
+ open_dump_file (".rtl", decl_printable_name (decl, 2));
+
+ if (DECL_SAVED_INSNS (decl))
+ fprintf (rtl_dump_file, ";; (integrable)\n\n");
+
+ close_dump_file (print_rtl, insns);
+ }
+
+ /* If we can, defer compiling inlines until EOF.
+ save_for_inline_copying can be extremely expensive. */
+ if (inlinable && ! decl_function_context (decl))
+ DECL_DEFER_OUTPUT (decl) = 1;
/* If function is inline, and we don't yet know whether to
compile it by itself, defer decision till end of compilation.
finish_compilation will call rest_of_compilation again
for those functions that need to be output. Also defer those
- functions that we are supposed to defer. */
+ functions that we are supposed to defer. We cannot defer
+ functions containing nested functions since the nested function
+ data is in our non-saved obstack. We cannot defer nested
+ functions for the same reason. */
+
+ /* If this is a nested inline, remove ADDRESSOF now so we can
+ finish compiling ourselves. Otherwise, wait until EOF.
+ We have to do this because the purge_addressof transformation
+ changes the DECL_RTL for many variables, which confuses integrate. */
+ if (inlinable)
+ {
+ if (decl_function_context (decl))
+ purge_addressof (insns);
+ else
+ DECL_DEFER_OUTPUT (decl) = 1;
+ }
- if (DECL_DEFER_OUTPUT (decl)
- || ((specd || DECL_INLINE (decl))
- && ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl)
- && ! flag_keep_inline_functions)
- || DECL_EXTERNAL (decl))))
+ if (! current_function_contains_functions
+ && (DECL_DEFER_OUTPUT (decl)
+ || (DECL_INLINE (decl)
+ && ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl)
+ && ! flag_keep_inline_functions)
+ || DECL_EXTERNAL (decl)))))
{
DECL_DEFER_OUTPUT (decl) = 1;
- /* If -Wreturn-type, we have to do a bit of compilation. */
- if (! warn_return_type)
+ /* If -Wreturn-type, we have to do a bit of compilation.
+ However, if we just fall through we will call
+ save_for_inline_copying() which results in excessive
+ memory use. Instead, we just want to call
+ jump_optimize() to figure out whether or not we can fall
+ off the end of the function; we do the minimum amount of
+ work necessary to make that safe. And, we set optimize
+ to zero to keep jump_optimize from working too hard. */
+ if (warn_return_type)
{
+ int saved_optimize = optimize;
+ optimize = 0;
+ find_exception_handler_labels ();
+ jump_optimize (get_insns(), !JUMP_CROSS_JUMP, !JUMP_NOOP_MOVES,
+ !JUMP_AFTER_REGSCAN);
+ optimize = saved_optimize;
+ }
+
#ifdef DWARF_DEBUGGING_INFO
- /* Generate the DWARF info for the "abstract" instance
- of a function which we may later generate inlined and/or
- out-of-line instances of. */
- if (write_symbols == DWARF_DEBUG)
- {
- set_decl_abstract_flags (decl, 1);
- TIMEVAR (symout_time, dwarfout_file_scope_decl (decl, 0));
- set_decl_abstract_flags (decl, 0);
- }
+ /* Generate the DWARF info for the "abstract" instance
+ of a function which we may later generate inlined and/or
+ out-of-line instances of. */
+ if (write_symbols == DWARF_DEBUG)
+ {
+ set_decl_abstract_flags (decl, 1);
+ TIMEVAR (symout_time, dwarfout_file_scope_decl (decl, 0));
+ set_decl_abstract_flags (decl, 0);
+ }
#endif
- TIMEVAR (integration_time, save_for_inline_nocopy (decl));
- goto exit_rest_of_compilation;
+#ifdef DWARF2_DEBUGGING_INFO
+ /* Generate the DWARF2 info for the "abstract" instance
+ of a function which we may later generate inlined and/or
+ out-of-line instances of. */
+ if (write_symbols == DWARF2_DEBUG)
+ {
+ set_decl_abstract_flags (decl, 1);
+ TIMEVAR (symout_time, dwarf2out_decl (decl));
+ set_decl_abstract_flags (decl, 0);
}
+#endif
+ TIMEVAR (integration_time, save_for_inline_nocopy (decl));
+ RTX_INTEGRATED_P (DECL_SAVED_INSNS (decl)) = inlinable;
+ goto exit_rest_of_compilation;
}
/* If we have to compile the function now, save its rtl and subdecls
so that its compilation will not affect what others get. */
- if (DECL_INLINE (decl) || DECL_DEFER_OUTPUT (decl))
+ if (inlinable || DECL_DEFER_OUTPUT (decl))
{
#ifdef DWARF_DEBUGGING_INFO
/* Generate the DWARF info for the "abstract" instance of
@@ -2759,14 +3354,27 @@ rest_of_compilation (decl)
set_decl_abstract_flags (decl, 0);
}
#endif
+#ifdef DWARF2_DEBUGGING_INFO
+ /* Generate the DWARF2 info for the "abstract" instance of
+ a function which we will generate an out-of-line instance
+ of almost immediately (and which we may also later generate
+ various inlined instances of). */
+ if (write_symbols == DWARF2_DEBUG)
+ {
+ set_decl_abstract_flags (decl, 1);
+ TIMEVAR (symout_time, dwarf2out_decl (decl));
+ set_decl_abstract_flags (decl, 0);
+ }
+#endif
saved_block_tree = DECL_INITIAL (decl);
saved_arguments = DECL_ARGUMENTS (decl);
TIMEVAR (integration_time, save_for_inline_copying (decl));
+ RTX_INTEGRATED_P (DECL_SAVED_INSNS (decl)) = inlinable;
}
/* If specified extern inline but we aren't inlining it, we are
done. */
- if (specd && DECL_EXTERNAL (decl))
+ if (DECL_INLINE (decl) && DECL_EXTERNAL (decl))
goto exit_rest_of_compilation;
}
@@ -2784,12 +3392,8 @@ rest_of_compilation (decl)
goto exit_rest_of_compilation;
}
- /* From now on, allocate rtl in current_obstack, not in saveable_obstack.
- Note that that may have been done above, in save_for_inline_copying.
- The call to resume_temporary_allocation near the end of this function
- goes back to the usual state of affairs. */
-
- rtl_in_current_obstack ();
+ /* Emit code to get eh context, if needed. */
+ emit_eh_context ();
#ifdef FINALIZE_PIC
/* If we are doing position-independent code generation, now
@@ -2800,12 +3404,27 @@ rest_of_compilation (decl)
FINALIZE_PIC;
#endif
+ /* From now on, allocate rtl in current_obstack, not in saveable_obstack.
+ Note that that may have been done above, in save_for_inline_copying.
+ The call to resume_temporary_allocation near the end of this function
+ goes back to the usual state of affairs. This must be done after
+ we've built up any unwinders for exception handling, and done
+ the FINALIZE_PIC work, if necessary. */
+
+ rtl_in_current_obstack ();
+
insns = get_insns ();
/* Copy any shared structure that should not be shared. */
unshare_all_rtl (insns);
+#ifdef SETJMP_VIA_SAVE_AREA
+ /* This must be performed before virutal register instantiation. */
+ if (current_function_calls_alloca)
+ optimize_save_area_alloca (insns);
+#endif
+
/* Instantiate all virtual registers. */
instantiate_virtual_regs (current_function_decl, get_insns ());
@@ -2815,17 +3434,15 @@ rest_of_compilation (decl)
for all references to such slots. */
/* fixup_stack_slots (); */
- /* Do jump optimization the first time, if -opt.
- Also do it if -W, but in that case it doesn't change the rtl code,
- it only computes whether control can drop off the end of the function. */
+ /* Find all the EH handlers. */
+ find_exception_handler_labels ();
- if (optimize > 0 || extra_warnings || warn_return_type
- /* If function is `noreturn', we should warn if it tries to return. */
- || TREE_THIS_VOLATILE (decl))
- {
- TIMEVAR (jump_time, reg_scan (insns, max_reg_num (), 0));
- TIMEVAR (jump_time, jump_optimize (insns, 0, 0, 1));
- }
+ /* Always do one jump optimization pass to ensure that JUMP_LABEL fields
+ are initialized and to compute whether control can drop off the end
+ of the function. */
+ TIMEVAR (jump_time, reg_scan (insns, max_reg_num (), 0));
+ TIMEVAR (jump_time, jump_optimize (insns, !JUMP_CROSS_JUMP, !JUMP_NOOP_MOVES,
+ JUMP_AFTER_REGSCAN));
/* Now is when we stop if -fsyntax-only and -Wreturn-type. */
if (rtl_dump_and_exit || flag_syntax_only || DECL_DEFER_OUTPUT (decl))
@@ -2833,29 +3450,19 @@ rest_of_compilation (decl)
/* Dump rtl code after jump, if we are doing that. */
- if (jump_opt_dump)
- TIMEVAR (dump_time,
- {
- fprintf (jump_opt_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- print_rtl (jump_opt_dump_file, insns);
- fflush (jump_opt_dump_file);
- });
+ if (jump_opt_dump)
+ dump_rtl (".jump", decl, print_rtl, insns);
/* Perform common subexpression elimination.
Nonzero value from `cse_main' means that jumps were simplified
and some code may now be unreachable, so do
jump optimization again. */
- if (cse_dump)
- TIMEVAR (dump_time,
- {
- fprintf (cse_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- });
-
if (optimize > 0)
{
+ if (cse_dump)
+ open_dump_file (".cse", decl_printable_name (decl, 2));
+
TIMEVAR (cse_time, reg_scan (insns, max_reg_num (), 1));
if (flag_thread_jumps)
@@ -2863,86 +3470,129 @@ rest_of_compilation (decl)
TIMEVAR (jump_time, thread_jumps (insns, max_reg_num (), 1));
TIMEVAR (cse_time, tem = cse_main (insns, max_reg_num (),
- 0, cse_dump_file));
- TIMEVAR (cse_time, delete_dead_from_cse (insns, max_reg_num ()));
+ 0, rtl_dump_file));
+ TIMEVAR (cse_time, delete_trivially_dead_insns (insns, max_reg_num ()));
if (tem || optimize > 1)
- TIMEVAR (jump_time, jump_optimize (insns, 0, 0, 0));
+ TIMEVAR (jump_time, jump_optimize (insns, !JUMP_CROSS_JUMP,
+ !JUMP_NOOP_MOVES,
+ !JUMP_AFTER_REGSCAN));
+
+ /* Dump rtl code after cse, if we are doing that. */
+
+ if (cse_dump)
+ close_dump_file (print_rtl, insns);
}
- /* Dump rtl code after cse, if we are doing that. */
+ purge_addressof (insns);
+ reg_scan (insns, max_reg_num (), 1);
- if (cse_dump)
- TIMEVAR (dump_time,
- {
- print_rtl (cse_dump_file, insns);
- fflush (cse_dump_file);
- });
+ if (addressof_dump)
+ dump_rtl (".addressof", decl, print_rtl, insns);
+
+ /* Perform global cse. */
- if (loop_dump)
- TIMEVAR (dump_time,
- {
- fprintf (loop_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- });
+ if (optimize > 0 && flag_gcse)
+ {
+ if (gcse_dump)
+ open_dump_file (".gcse", IDENTIFIER_POINTER (DECL_NAME (decl)));
+
+ TIMEVAR (gcse_time, gcse_main (insns, rtl_dump_file));
+ if (gcse_dump)
+ close_dump_file (print_rtl, insns);
+ }
/* Move constant computations out of loops. */
if (optimize > 0)
{
- TIMEVAR (loop_time,
- {
- loop_optimize (insns, loop_dump_file);
- });
- }
-
- /* Dump rtl code after loop opt, if we are doing that. */
-
- if (loop_dump)
- TIMEVAR (dump_time,
- {
- print_rtl (loop_dump_file, insns);
- fflush (loop_dump_file);
- });
-
- if (cse2_dump)
- TIMEVAR (dump_time,
+ if (loop_dump)
+ open_dump_file (".loop", decl_printable_name (decl, 2));
+
+ TIMEVAR
+ (loop_time,
+ {
+ if (flag_rerun_loop_opt)
{
- fprintf (cse2_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- });
+ /* We only want to perform unrolling once. */
+
+ loop_optimize (insns, rtl_dump_file, 0);
+
+
+ /* The first call to loop_optimize makes some instructions
+ trivially dead. We delete those instructions now in the
+ hope that doing so will make the heuristics in loop work
+ better and possibly speed up compilation. */
+ delete_trivially_dead_insns (insns, max_reg_num ());
+
+ /* The regscan pass is currently necessary as the alias
+ analysis code depends on this information. */
+ reg_scan (insns, max_reg_num (), 1);
+ }
+ loop_optimize (insns, rtl_dump_file, flag_unroll_loops);
+ });
+
+ /* Dump rtl code after loop opt, if we are doing that. */
+
+ if (loop_dump)
+ close_dump_file (print_rtl, insns);
+ }
- if (optimize > 0 && flag_rerun_cse_after_loop)
+ if (optimize > 0)
{
- /* Running another jump optimization pass before the second
- cse pass sometimes simplifies the RTL enough to allow
- the second CSE pass to do a better job. Jump_optimize can change
- max_reg_num so we must rerun reg_scan afterwards.
- ??? Rework to not call reg_scan so often. */
- TIMEVAR (jump_time, reg_scan (insns, max_reg_num (), 0));
- TIMEVAR (jump_time, jump_optimize (insns, 0, 0, 1));
+ if (cse2_dump)
+ open_dump_file (".cse2", decl_printable_name (decl, 2));
+
+ if (flag_rerun_cse_after_loop)
+ {
+ /* Running another jump optimization pass before the second
+ cse pass sometimes simplifies the RTL enough to allow
+ the second CSE pass to do a better job. Jump_optimize can change
+ max_reg_num so we must rerun reg_scan afterwards.
+ ??? Rework to not call reg_scan so often. */
+ TIMEVAR (jump_time, reg_scan (insns, max_reg_num (), 0));
+ TIMEVAR (jump_time, jump_optimize (insns, !JUMP_CROSS_JUMP,
+ !JUMP_NOOP_MOVES,
+ JUMP_AFTER_REGSCAN));
+
+ TIMEVAR (cse2_time, reg_scan (insns, max_reg_num (), 0));
+ TIMEVAR (cse2_time, tem = cse_main (insns, max_reg_num (),
+ 1, rtl_dump_file));
+ if (tem)
+ TIMEVAR (jump_time, jump_optimize (insns, !JUMP_CROSS_JUMP,
+ !JUMP_NOOP_MOVES,
+ !JUMP_AFTER_REGSCAN));
+ }
- TIMEVAR (cse2_time, reg_scan (insns, max_reg_num (), 0));
- TIMEVAR (cse2_time, tem = cse_main (insns, max_reg_num (),
- 1, cse2_dump_file));
- if (tem)
- TIMEVAR (jump_time, jump_optimize (insns, 0, 0, 0));
+ if (flag_thread_jumps)
+ {
+ /* This pass of jump threading straightens out code
+ that was kinked by loop optimization. */
+ TIMEVAR (jump_time, reg_scan (insns, max_reg_num (), 0));
+ TIMEVAR (jump_time, thread_jumps (insns, max_reg_num (), 0));
+ }
+
+ /* Dump rtl code after cse, if we are doing that. */
+
+ if (cse2_dump)
+ close_dump_file (print_rtl, insns);
}
-
- if (optimize > 0 && flag_thread_jumps)
- /* This pass of jump threading straightens out code
- that was kinked by loop optimization. */
- TIMEVAR (jump_time, thread_jumps (insns, max_reg_num (), 0));
-
- /* Dump rtl code after cse, if we are doing that. */
-
- if (cse2_dump)
- TIMEVAR (dump_time,
- {
- print_rtl (cse2_dump_file, insns);
- fflush (cse2_dump_file);
- });
-
+
+ if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
+ {
+ if (branch_prob_dump)
+ open_dump_file (".bp", decl_printable_name (decl, 2));
+
+ TIMEVAR
+ (branch_prob_time,
+ {
+ branch_prob (insns, rtl_dump_file);
+ });
+
+ if (branch_prob_dump)
+ close_dump_file (print_rtl, insns);
+ }
+
/* We are no longer anticipating cse in this function, at least. */
cse_not_expected = 1;
@@ -2960,19 +3610,15 @@ rest_of_compilation (decl)
because doing the flow analysis makes some of the dump. */
if (flow_dump)
- TIMEVAR (dump_time,
- {
- fprintf (flow_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- });
-
+ open_dump_file (".flow", decl_printable_name (decl, 2));
+
if (obey_regdecls)
{
TIMEVAR (flow_time,
{
regclass (insns, max_reg_num ());
stupid_life_analysis (insns, max_reg_num (),
- flow_dump_file);
+ rtl_dump_file);
});
}
else
@@ -2980,8 +3626,13 @@ rest_of_compilation (decl)
/* Do control and data flow analysis,
and write some of the results to dump file. */
- TIMEVAR (flow_time, flow_analysis (insns, max_reg_num (),
- flow_dump_file));
+ TIMEVAR
+ (flow_time,
+ {
+ find_basic_blocks (insns, max_reg_num (), rtl_dump_file, 1);
+ life_analysis (insns, max_reg_num (), rtl_dump_file);
+ });
+
if (warn_uninitialized)
{
uninitialized_vars_warning (DECL_INITIAL (decl));
@@ -2992,62 +3643,60 @@ rest_of_compilation (decl)
/* Dump rtl after flow analysis. */
if (flow_dump)
- TIMEVAR (dump_time,
- {
- print_rtl (flow_dump_file, insns);
- fflush (flow_dump_file);
- });
-
+ close_dump_file (print_rtl_with_bb, insns);
+
/* If -opt, try combining insns through substitution. */
if (optimize > 0)
- TIMEVAR (combine_time, combine_instructions (insns, max_reg_num ()));
-
- /* Dump rtl code after insn combination. */
+ {
+ TIMEVAR (combine_time, combine_instructions (insns, max_reg_num ()));
+
+ /* Dump rtl code after insn combination. */
+
+ if (combine_dump)
+ dump_rtl (".combine", decl, print_rtl_with_bb, insns);
+ }
- if (combine_dump)
- TIMEVAR (dump_time,
- {
- fprintf (combine_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- dump_combine_stats (combine_dump_file);
- print_rtl (combine_dump_file, insns);
- fflush (combine_dump_file);
- });
+ /* Register allocation pre-pass, to reduce number of moves
+ necessary for two-address machines. */
+ if (optimize > 0 && (flag_regmove || flag_expensive_optimizations))
+ {
+ if (regmove_dump)
+ open_dump_file (".regmove", decl_printable_name (decl, 2));
+
+ TIMEVAR (regmove_time, regmove_optimize (insns, max_reg_num (),
+ rtl_dump_file));
+
+ if (regmove_dump)
+ close_dump_file (print_rtl_with_bb, insns);
+ }
/* Print function header into sched dump now
because doing the sched analysis makes some of the dump. */
- if (sched_dump)
- TIMEVAR (dump_time,
- {
- fprintf (sched_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- });
-
if (optimize > 0 && flag_schedule_insns)
{
+ if (sched_dump)
+ open_dump_file (".sched", decl_printable_name (decl, 2));
+
/* Do control and data sched analysis,
and write some of the results to dump file. */
- TIMEVAR (sched_time, schedule_insns (sched_dump_file));
+ TIMEVAR (sched_time, schedule_insns (rtl_dump_file));
+
+ /* Dump rtl after instruction scheduling. */
+
+ if (sched_dump)
+ close_dump_file (print_rtl_with_bb, insns);
}
- /* Dump rtl after instruction scheduling. */
-
- if (sched_dump)
- TIMEVAR (dump_time,
- {
- print_rtl (sched_dump_file, insns);
- fflush (sched_dump_file);
- });
-
/* Unless we did stupid register allocation,
allocate pseudo-regs that are used only within 1 basic block. */
if (!obey_regdecls)
TIMEVAR (local_alloc_time,
{
+ recompute_reg_usage (insns);
regclass (insns, max_reg_num ());
local_alloc ();
});
@@ -3055,20 +3704,21 @@ rest_of_compilation (decl)
/* Dump rtl code after allocating regs within basic blocks. */
if (local_reg_dump)
- TIMEVAR (dump_time,
- {
- fprintf (local_reg_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- dump_flow_info (local_reg_dump_file);
- dump_local_alloc (local_reg_dump_file);
- print_rtl (local_reg_dump_file, insns);
- fflush (local_reg_dump_file);
- });
+ {
+ open_dump_file (".lreg", decl_printable_name (decl, 2));
+
+ TIMEVAR (dump_time, dump_flow_info (rtl_dump_file));
+ TIMEVAR (dump_time, dump_local_alloc (rtl_dump_file));
+
+ close_dump_file (print_rtl_with_bb, insns);
+ }
if (global_reg_dump)
- TIMEVAR (dump_time,
- fprintf (global_reg_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl))));
+ open_dump_file (".greg", decl_printable_name (decl, 2));
+
+ /* Save the last label number used so far, so reorg can tell
+ when it's safe to kill spill regs. */
+ max_label_num_after_reload = max_label_num ();
/* Unless we did stupid register allocation,
allocate remaining pseudo-regs, then do the reload pass
@@ -3077,24 +3727,21 @@ rest_of_compilation (decl)
TIMEVAR (global_alloc_time,
{
if (!obey_regdecls)
- failure = global_alloc (global_reg_dump_file);
+ failure = global_alloc (rtl_dump_file);
else
- failure = reload (insns, 0, global_reg_dump_file);
+ failure = reload (insns, 0, rtl_dump_file);
});
- if (global_reg_dump)
- TIMEVAR (dump_time,
- {
- dump_global_regs (global_reg_dump_file);
- print_rtl (global_reg_dump_file, insns);
- fflush (global_reg_dump_file);
- });
if (failure)
goto exit_rest_of_compilation;
reload_completed = 1;
+ /* Do a very simple CSE pass over just the hard registers. */
+ if (optimize > 0)
+ reload_cse_regs (insns);
+
/* On some machines, the prologue and epilogue code, or parts thereof,
can be represented as RTL. Doing so lets us schedule insns between
it and the rest of the code and also allows delayed branch
@@ -3102,28 +3749,25 @@ rest_of_compilation (decl)
thread_prologue_and_epilogue_insns (insns);
+ if (global_reg_dump)
+ {
+ TIMEVAR (dump_time, dump_global_regs (rtl_dump_file));
+ close_dump_file (print_rtl_with_bb, insns);
+ }
if (optimize > 0 && flag_schedule_insns_after_reload)
{
if (sched2_dump)
- TIMEVAR (dump_time,
- {
- fprintf (sched2_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- });
+ open_dump_file (".sched2", decl_printable_name (decl, 2));
/* Do control and data sched analysis again,
and write some more of the results to dump file. */
- TIMEVAR (sched2_time, schedule_insns (sched2_dump_file));
+ TIMEVAR (sched2_time, schedule_insns (rtl_dump_file));
/* Dump rtl after post-reorder instruction scheduling. */
if (sched2_dump)
- TIMEVAR (dump_time,
- {
- print_rtl (sched2_dump_file, insns);
- fflush (sched2_dump_file);
- });
+ close_dump_file (print_rtl_with_bb, insns);
}
#ifdef LEAF_REGISTERS
@@ -3139,42 +3783,34 @@ rest_of_compilation (decl)
if (optimize > 0)
{
- TIMEVAR (jump_time, jump_optimize (insns, 1, 1, 0));
- }
-
- /* Dump rtl code after jump, if we are doing that. */
+ TIMEVAR (jump_time, jump_optimize (insns, JUMP_CROSS_JUMP,
+ JUMP_NOOP_MOVES,
+ !JUMP_AFTER_REGSCAN));
+
+ /* Dump rtl code after jump, if we are doing that. */
- if (jump2_opt_dump)
- TIMEVAR (dump_time,
- {
- fprintf (jump2_opt_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- print_rtl (jump2_opt_dump_file, insns);
- fflush (jump2_opt_dump_file);
- });
+ if (jump2_opt_dump)
+ dump_rtl (".jump2", decl, print_rtl_with_bb, insns);
+ }
/* If a machine dependent reorganization is needed, call it. */
#ifdef MACHINE_DEPENDENT_REORG
MACHINE_DEPENDENT_REORG (insns);
+
+ if (mach_dep_reorg_dump)
+ dump_rtl (".mach", decl, print_rtl_with_bb, insns);
#endif
/* If a scheduling pass for delayed branches is to be done,
- call the scheduling code. */
+ call the scheduling code. */
#ifdef DELAY_SLOTS
if (optimize > 0 && flag_delayed_branch)
{
- TIMEVAR (dbr_sched_time, dbr_schedule (insns, dbr_sched_dump_file));
+ TIMEVAR (dbr_sched_time, dbr_schedule (insns, rtl_dump_file));
+
if (dbr_sched_dump)
- {
- TIMEVAR (dump_time,
- {
- fprintf (dbr_sched_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- print_rtl (dbr_sched_dump_file, insns);
- fflush (dbr_sched_dump_file);
- });
- }
+ dump_rtl (".dbr", decl, print_rtl_with_bb, insns);
}
#endif
@@ -3185,17 +3821,10 @@ rest_of_compilation (decl)
});
#ifdef STACK_REGS
- TIMEVAR (stack_reg_time, reg_to_stack (insns, stack_reg_dump_file));
+ TIMEVAR (stack_reg_time, reg_to_stack (insns, rtl_dump_file));
+
if (stack_reg_dump)
- {
- TIMEVAR (dump_time,
- {
- fprintf (stack_reg_dump_file, "\n;; Function %s\n\n",
- IDENTIFIER_POINTER (DECL_NAME (decl)));
- print_rtl (stack_reg_dump_file, insns);
- fflush (stack_reg_dump_file);
- });
- }
+ dump_rtl (".stack", decl, print_rtl_with_bb, insns);
#endif
/* Now turn the rtl into assembler code. */
@@ -3222,7 +3851,11 @@ rest_of_compilation (decl)
final (insns, asm_out_file, optimize, 0);
final_end_function (insns, asm_out_file, optimize);
assemble_end_function (decl, fnname);
- fflush (asm_out_file);
+ if (! quiet_flag)
+ fflush (asm_out_file);
+
+ /* Release all memory held by regsets now */
+ regset_release_memory ();
});
/* Write DBX symbols if requested */
@@ -3245,6 +3878,11 @@ rest_of_compilation (decl)
TIMEVAR (symout_time, dwarfout_file_scope_decl (decl, 0));
#endif
+#ifdef DWARF2_DEBUGGING_INFO
+ if (write_symbols == DWARF2_DEBUG)
+ TIMEVAR (symout_time, dwarf2out_decl (decl));
+#endif
+
exit_rest_of_compilation:
/* In case the function was not output,
@@ -3261,23 +3899,41 @@ rest_of_compilation (decl)
the copy, but the original is unchanged. */
if (saved_block_tree != 0)
- DECL_INITIAL (decl) = saved_block_tree;
- if (saved_arguments != 0)
- DECL_ARGUMENTS (decl) = saved_arguments;
+ {
+ DECL_INITIAL (decl) = saved_block_tree;
+ DECL_ARGUMENTS (decl) = saved_arguments;
+ DECL_ABSTRACT_ORIGIN (decl) = NULL_TREE;
+ }
reload_completed = 0;
- /* Clear out the insn_length contents now that they are no longer valid. */
- init_insn_lengths ();
+ TIMEVAR (final_time,
+ {
+ /* Clear out the insn_length contents now that they are no
+ longer valid. */
+ init_insn_lengths ();
- /* Clear out the real_constant_chain before some of the rtx's
- it runs through become garbage. */
+ /* Clear out the real_constant_chain before some of the rtx's
+ it runs through become garbage. */
+ clear_const_double_mem ();
- clear_const_double_mem ();
+ /* Cancel the effect of rtl_in_current_obstack. */
+ resume_temporary_allocation ();
- /* Cancel the effect of rtl_in_current_obstack. */
+ /* Show no temporary slots allocated. */
+ init_temp_slots ();
+ });
- resume_temporary_allocation ();
+ /* Make sure volatile mem refs aren't considered valid operands for
+ arithmetic insns. We must call this here if this is a nested inline
+ function, since the above code leaves us in the init_recog state
+ (from final.c), and the function context push/pop code does not
+ save/restore volatile_ok.
+
+ ??? Maybe it isn't necessary for expand_start_function to call this
+ anymore if we do it here? */
+
+ init_recog_no_volatile ();
/* The parsing time is all the time spent in yyparse
*except* what is spent in this function. */
@@ -3285,6 +3941,234 @@ rest_of_compilation (decl)
parse_time -= get_run_time () - start_time;
}
+static void
+display_help ()
+{
+ int undoc;
+ long i;
+ char * lang;
+
+#ifndef USE_CPPLIB
+ printf ("Usage: %s input [switches]\n", progname);
+ printf ("Switches:\n");
+#endif
+ printf (" -ffixed-<register> Mark <register> as being unavailable to the compiler\n");
+ printf (" -fcall-used-<register> Mark <register> as being corrupted by function calls\n");
+ printf (" -fcall-saved-<register> Mark <register> as being preserved across functions\n");
+
+ for (i = NUM_ELEM (f_options); i--;)
+ {
+ char * description = f_options[i].description;
+
+ if (description != NULL && * description != 0)
+ printf (" -f%-21s %s\n",
+ f_options[i].string, description);
+ }
+
+ printf (" -O[number] Set optimisation level to [number]\n");
+ printf (" -Os Optimise for space rather than speed\n");
+ printf (" -pedantic Issue warnings needed by strict compliance to ANSI C\n");
+ printf (" -pedantic-errors Like -pedantic except that errors are produced\n");
+ printf (" -w Suppress warnings\n");
+ printf (" -W Enable extra warnings\n");
+
+ for (i = NUM_ELEM (W_options); i--;)
+ {
+ char * description = W_options[i].description;
+
+ if (description != NULL && * description != 0)
+ printf (" -W%-21s %s\n",
+ W_options[i].string, description);
+ }
+
+ printf (" -Wid-clash-<num> Warn if 2 identifiers have the same first <num> chars\n");
+ printf (" -Wlarger-than-<number> Warn if an object is larger than <number> bytes\n");
+ printf (" -p Enable function profiling\n");
+#if defined (BLOCK_PROFILER) || defined (FUNCTION_BLOCK_PROFILER)
+ printf (" -a Enable block profiling \n");
+#endif
+#if defined (BLOCK_PROFILER) || defined (FUNCTION_BLOCK_PROFILER) || defined FUNCTION_BLOCK_PROFILER_EXIT
+ printf (" -ax Enable jump profiling \n");
+#endif
+ printf (" -o <file> Place output into <file> \n");
+ printf (" -G <number> Put global and static data smaller than <number>\n");
+ printf (" bytes into a special section (on some targets)\n");
+
+ for (i = NUM_ELEM (debug_args); i--;)
+ {
+ if (debug_args[i].description != NULL)
+ printf (" -%-22s %s\n", debug_args[i].arg, debug_args[i].description);
+ }
+
+ printf (" -aux-info <file> Emit declaration info into <file>.X\n");
+ printf (" -quiet Do not display functions compiled or elapsed time\n");
+ printf (" -version Display the compiler's version\n");
+ printf (" -d[letters] Enable dumps from specific passes of the compiler\n");
+ printf (" -dumpbase <file> Base name to be used for dumps from specific passes\n");
+#if defined HAIFA || defined INSN_SCHEDULING
+ printf (" -sched-verbose-<number> Set the verbosity level of the scheduler\n");
+#endif
+ printf (" --help Display this information\n");
+
+ undoc = 0;
+ lang = "language";
+
+ /* Display descriptions of language specific options.
+ If there is no description, note that there is an undocumented option.
+ If the description is empty, do not display anything. (This allows
+ options to be deliberately undocumented, for whatever reason).
+ If the option string is missing, then this is a marker, indicating
+ that the description string is in fact the name of a language, whoes
+ language specific options are to follow. */
+
+ if (NUM_ELEM (documented_lang_options) > 1)
+ {
+ int looking_for_start = 0;
+
+ printf ("\nLanguage specific options:\n");
+
+ for (i = 0; i < NUM_ELEM (documented_lang_options); i++)
+ {
+ char * description = documented_lang_options[i].description;
+ char * option = documented_lang_options[i].option;
+
+ if (description == NULL)
+ undoc = 1;
+ else if (* description == 0)
+ continue;
+ else if (option == NULL)
+ {
+ if (undoc)
+ printf
+ ("\nThere are undocumented %s specific options as well.\n",
+ lang);
+ undoc = 0;
+
+ printf ("\n Options for %s:\n", description);
+
+ lang = description;
+ }
+ else
+ printf (" %-23.23s %s\n", option, description);
+ }
+ }
+
+ if (undoc)
+ printf ("\nThere are undocumented %s specific options as well.\n", lang);
+
+ if (NUM_ELEM (target_switches) > 1
+#ifdef TARGET_OPTIONS
+ || NUM_ELEM (target_options) > 1
+#endif
+ )
+ {
+ int doc = 0;
+
+ undoc = 0;
+
+ printf ("\nTarget specific options:\n");
+
+ for (i = NUM_ELEM (target_switches); i--;)
+ {
+ char * option = target_switches[i].name;
+ char * description = target_switches[i].description;
+
+ if (option == NULL)
+ continue;
+ else if (description == NULL)
+ undoc = 1;
+ else if (* description != 0)
+ doc += printf (" %-23.23s %s\n", option, description);
+ }
+
+#ifdef TARGET_OPTIONS
+ for (i = NUM_ELEM (target_options); i--;)
+ {
+ char * option = target_options[i].prefix;
+ char * description = target_options[i].description;
+
+ if (option == NULL)
+ continue;
+ else if (description == NULL)
+ undoc = 1;
+ else if (* description != 0)
+ doc += printf (" %-23.23s %s\n", option, description);
+ }
+#endif
+ if (undoc)
+ if (doc)
+ printf ("\nThere are undocumented target specific options as well.\n");
+ else
+ printf (" They exist, but they are not documented.\n");
+ }
+}
+
+/* Compare the user specified 'option' with the language
+ specific 'lang_option'. Return true if they match, or
+ if 'option' is a viable prefix of 'lang_option'. */
+
+static int
+check_lang_option (option, lang_option)
+ char * option;
+ char * lang_option;
+{
+ lang_independent_options * indep_options;
+ int len;
+ long k;
+
+ /* Ignore NULL entries. */
+ if (option == NULL || lang_option == NULL)
+ return 0;
+
+ len = strlen (lang_option);
+
+ /* If they do not match to the first n characters then fail. */
+ if (strncmp (option, lang_option, len) != 0)
+ return 0;
+
+ /* Do not accept a lang option, if it matches a normal -f or -W
+ option. Chill defines a -fpack, but we want to support
+ -fpack-struct. */
+
+ /* An exact match is OK */
+ if (strlen (option) == len)
+ return 1;
+
+ /* If it is not an -f or -W option allow the match */
+ if (option[0] != '-')
+ return 1;
+
+ switch (option[1])
+ {
+ case 'f': indep_options = f_options; break;
+ case 'W': indep_options = W_options; break;
+ default: return 1;
+ }
+
+ /* The option is a -f or -W option.
+ Skip past the prefix and search for the remainder in the
+ appropriate table of options. */
+ option += 2;
+
+ if (option[0] == 'n' && option[1] == 'o' && option[2] == '-')
+ option += 3;
+
+ for (k = NUM_ELEM (indep_options); k--;)
+ {
+ if (!strcmp (option, indep_options[k].string))
+ {
+ /* The option matched a language independent option,
+ do not allow the language specific match. */
+
+ return 0;
+ }
+ }
+
+ /* The option matches the start of the langauge specific option
+ and it is not an exact match for a language independent option. */
+ return 1;
+}
+
/* Entry point of cc1/c++. Decode command args, then call compile_file.
Exit code is 35 if can't open files, 34 if fatal error,
33 if had nonfatal errors, else success. */
@@ -3314,17 +4198,17 @@ main (argc, argv, envp)
--p;
progname = p;
-#ifdef RLIMIT_STACK
+#if defined (RLIMIT_STACK) && defined (HAVE_GETRLIMIT) && defined (HAVE_SETRLIMIT)
/* Get rid of any avoidable limit on stack size. */
{
struct rlimit rlim;
- /* Set the stack limit huge so that alloca does not fail. */
+ /* Set the stack limit huge so that alloca does not fail. */
getrlimit (RLIMIT_STACK, &rlim);
rlim.rlim_cur = rlim.rlim_max;
setrlimit (RLIMIT_STACK, &rlim);
}
-#endif /* RLIMIT_STACK */
+#endif
signal (SIGFPE, float_signal);
@@ -3334,7 +4218,6 @@ main (argc, argv, envp)
decl_printable_name = decl_name;
lang_expand_expr = (struct rtx_def *(*)()) do_abort;
- interim_eh_hook = interim_eh;
/* Initialize whether `char' is signed. */
flag_signed_char = DEFAULT_SIGNED_CHAR;
@@ -3343,6 +4226,9 @@ main (argc, argv, envp)
flag_short_enums = DEFAULT_SHORT_ENUMS;
#endif
+ /* Perform language-specific options intialization. */
+ lang_init_options ();
+
/* Scan to see what optimization level has been specified. That will
determine the default value of many flags. */
for (i = 1; i < argc; i++)
@@ -3353,24 +4239,28 @@ main (argc, argv, envp)
}
else if (argv[i][0] == '-' && argv[i][1] == 'O')
{
- /* Handle -O2, -O3, -O69, ... */
+ /* Handle -Os, -O2, -O3, -O69, ... */
char *p = &argv[i][2];
int c;
-
- while (c = *p++)
- if (! (c >= '0' && c <= '9'))
- break;
- if (c == 0)
- optimize = atoi (&argv[i][2]);
+
+ if ((p[0] == 's') && (p[1] == 0))
+ optimize_size = 1;
+ else
+ {
+ while ((c = *p++))
+ if (! (c >= '0' && c <= '9'))
+ break;
+ if (c == 0)
+ optimize = atoi (&argv[i][2]);
+ }
}
}
+ /* Optimizing for size forces optimize to be no less than 2. */
+ if (optimize_size && (optimize < 2))
+ optimize = 2;
+
obey_regdecls = (optimize == 0);
- if (optimize == 0)
- {
- flag_no_inline = 1;
- warn_inline = 0;
- }
if (optimize >= 1)
{
@@ -3388,15 +4278,21 @@ main (argc, argv, envp)
{
flag_cse_follow_jumps = 1;
flag_cse_skip_blocks = 1;
+ flag_gcse = 1;
flag_expensive_optimizations = 1;
flag_strength_reduce = 1;
flag_rerun_cse_after_loop = 1;
+ flag_rerun_loop_opt = 1;
flag_caller_saves = 1;
flag_force_mem = 1;
#ifdef INSN_SCHEDULING
flag_schedule_insns = 1;
flag_schedule_insns_after_reload = 1;
#endif
+ flag_regmove = 1;
+ /* We don't set flag_strict_aliasing here because we're still
+ testing the functionality. After it has been tested, it
+ should be turned on here. */
}
if (optimize >= 3)
@@ -3404,30 +4300,46 @@ main (argc, argv, envp)
flag_inline_functions = 1;
}
+ /* Initialize target_flags before OPTIMIZATION_OPTIONS so the latter can
+ modify it. */
+ target_flags = 0;
+ set_target_switch ("");
+
#ifdef OPTIMIZATION_OPTIONS
/* Allow default optimizations to be specified on a per-machine basis. */
- OPTIMIZATION_OPTIONS (optimize);
+ OPTIMIZATION_OPTIONS (optimize, optimize_size);
#endif
/* Initialize register usage now so switches may override. */
init_reg_sets ();
- target_flags = 0;
- set_target_switch ("");
-
for (i = 1; i < argc; i++)
{
- int j;
+ size_t j;
+
/* If this is a language-specific option,
decode it in a language-specific way. */
- for (j = 0; lang_options[j] != 0; j++)
- if (!strncmp (argv[i], lang_options[j],
- strlen (lang_options[j])))
+ for (j = NUM_ELEM (documented_lang_options); j--;)
+ if (check_lang_option (argv[i], documented_lang_options[j].option))
break;
- if (lang_options[j] != 0)
- /* If the option is valid for *some* language,
- treat it as valid even if this language doesn't understand it. */
- lang_decode_option (argv[i]);
+
+ if (j != -1)
+ {
+ /* If the option is valid for *some* language,
+ treat it as valid even if this language doesn't understand it. */
+ int strings_processed = lang_decode_option (argc - i, argv + i);
+
+ /* BEGIN CYGNUS LOCAL --help/nickc */
+ if (!strcmp (argv[i], "--help"))
+ {
+ display_help ();
+ exit (0);
+ }
+ /* END CYGNUS LOCAL */
+
+ if (strings_processed != 0)
+ i += strings_processed - 1;
+ }
else if (argv[i][0] == '-' && argv[i][1] != 0)
{
register char *str = argv[i] + 1;
@@ -3447,41 +4359,68 @@ main (argc, argv, envp)
switch (*p++)
{
case 'a':
+ branch_prob_dump = 1;
combine_dump = 1;
+#ifdef DELAY_SLOTS
dbr_sched_dump = 1;
+#endif
flow_dump = 1;
global_reg_dump = 1;
jump_opt_dump = 1;
+ addressof_dump = 1;
jump2_opt_dump = 1;
local_reg_dump = 1;
loop_dump = 1;
+ regmove_dump = 1;
rtl_dump = 1;
cse_dump = 1, cse2_dump = 1;
+ gcse_dump = 1;
sched_dump = 1;
sched2_dump = 1;
+#ifdef STACK_REGS
stack_reg_dump = 1;
+#endif
+#ifdef MACHINE_DEPENDENT_REORG
+ mach_dep_reorg_dump = 1;
+#endif
break;
- case 'k':
- stack_reg_dump = 1;
+ case 'A':
+ flag_debug_asm = 1;
+ break;
+ case 'b':
+ branch_prob_dump = 1;
break;
case 'c':
combine_dump = 1;
break;
+#ifdef DELAY_SLOTS
case 'd':
dbr_sched_dump = 1;
break;
+#endif
case 'f':
flow_dump = 1;
break;
+ case 'F':
+ addressof_dump = 1;
+ break;
case 'g':
global_reg_dump = 1;
break;
+ case 'G':
+ gcse_dump = 1;
+ break;
case 'j':
jump_opt_dump = 1;
break;
case 'J':
jump2_opt_dump = 1;
break;
+#ifdef STACK_REGS
+ case 'k':
+ stack_reg_dump = 1;
+ break;
+#endif
case 'l':
local_reg_dump = 1;
break;
@@ -3491,31 +4430,41 @@ main (argc, argv, envp)
case 'm':
flag_print_mem = 1;
break;
+#ifdef MACHINE_DEPENDENT_REORG
+ case 'M':
+ mach_dep_reorg_dump = 1;
+ break;
+#endif
case 'p':
flag_print_asm_name = 1;
break;
case 'r':
rtl_dump = 1;
break;
+ case 'R':
+ sched2_dump = 1;
+ break;
case 's':
cse_dump = 1;
break;
- case 't':
- cse2_dump = 1;
- break;
case 'S':
sched_dump = 1;
break;
- case 'R':
- sched2_dump = 1;
+ case 't':
+ cse2_dump = 1;
+ break;
+ case 'N':
+ regmove_dump = 1;
break;
case 'y':
set_yydebug (1);
break;
-
case 'x':
rtl_dump_and_exit = 1;
break;
+ default:
+ warning ("unrecognised gcc debugging option: %c", p[-1]);
+ break;
}
}
else if (str[0] == 'f')
@@ -3548,6 +4497,12 @@ main (argc, argv, envp)
if (found)
;
+#ifdef HAIFA
+#ifdef INSN_SCHEDULING
+ else if (!strncmp (p, "sched-verbose-",14))
+ fix_sched_param("verbose",&p[14]);
+#endif
+#endif /* HAIFA */
else if (!strncmp (p, "fixed-", 6))
fix_register (&p[6], 1, 1);
else if (!strncmp (p, "call-used-", 10))
@@ -3560,8 +4515,11 @@ main (argc, argv, envp)
else if (str[0] == 'O')
{
register char *p = str+1;
- while (*p && *p >= '0' && *p <= '9')
+ if (*p == 's')
p++;
+ else
+ while (*p && *p >= '0' && *p <= '9')
+ p++;
if (*p == '\0')
;
else
@@ -3657,146 +4615,133 @@ main (argc, argv, envp)
}
else if (!strcmp (str, "p"))
{
- if (!output_bytecode)
- profile_flag = 1;
- else
- error ("profiling not supported in bytecode compilation");
+ profile_flag = 1;
}
else if (!strcmp (str, "a"))
{
#if !defined (BLOCK_PROFILER) || !defined (FUNCTION_BLOCK_PROFILER)
warning ("`-a' option (basic block profile) not supported");
#else
- profile_block_flag = 1;
+ profile_block_flag = (profile_block_flag < 2) ? 1 : 3;
+#endif
+ }
+ else if (!strcmp (str, "ax"))
+ {
+#if !defined (FUNCTION_BLOCK_PROFILER_EXIT) || !defined (BLOCK_PROFILER) || !defined (FUNCTION_BLOCK_PROFILER)
+ warning ("`-ax' option (jump profiling) not supported");
+#else
+ profile_block_flag = (!profile_block_flag
+ || profile_block_flag == 2) ? 2 : 3;
#endif
}
else if (str[0] == 'g')
{
- char *p = str + 1;
- char *q;
unsigned len;
unsigned level;
+ /* A lot of code assumes write_symbols == NO_DEBUG if the
+ debugging level is 0 (thus -gstabs1 -gstabs0 would lose track
+ of what debugging type has been selected). This records the
+ selected type. It is an error to specify more than one
+ debugging type. */
+ static enum debug_info_type selected_debug_type = NO_DEBUG;
+ /* Non-zero if debugging format has been explicitly set.
+ -g and -ggdb don't explicitly set the debugging format so
+ -gdwarf -g3 is equivalent to -gdwarf3. */
+ static int type_explicitly_set_p = 0;
+ /* Indexed by enum debug_info_type. */
+ static char *debug_type_names[] =
+ {
+ "none", "stabs", "coff", "dwarf-1", "dwarf-2", "xcoff"
+ };
- while (*p && (*p < '0' || *p > '9'))
- p++;
- len = p - str;
- q = p;
- while (*q && (*q >= '0' && *q <= '9'))
- q++;
- if (*p)
- level = atoi (p);
- else
- level = 2; /* default debugging info level */
- if (*q || level > 3)
+ /* Look up STR in the table. */
+ for (da = debug_args; da->arg; da++)
{
- warning ("invalid debug level specification in option: `-%s'",
- str);
- warning ("no debugging information will be generated");
- level = 0;
- }
+ if (! strncmp (str, da->arg, strlen (da->arg)))
+ {
+ enum debug_info_type type = da->debug_type;
+ char *p, *q;
+
+ p = str + strlen (da->arg);
+ if (*p && (*p < '0' || *p > '9'))
+ continue;
+ len = p - str;
+ q = p;
+ while (*q && (*q >= '0' && *q <= '9'))
+ q++;
+ if (*p)
+ {
+ level = atoi (p);
+ if (len > 1 && !strncmp (str, "gdwarf", len))
+ {
+ error ("use -gdwarf -g%d for DWARF v1, level %d",
+ level, level);
+ if (level == 2)
+ error ("use -gdwarf-2 for DWARF v2");
+ }
+ }
+ else
+ level = 2; /* default debugging info level */
+ if (*q || level > 3)
+ {
+ warning ("invalid debug level specification in option: `-%s'",
+ str);
+ /* ??? This error message is incorrect in the case of
+ -g4 -g. */
+ warning ("no debugging information will be generated");
+ level = 0;
+ }
- /* If more than one debugging type is supported,
- you must define PREFERRED_DEBUGGING_TYPE
- to choose a format in a system-dependent way. */
- /* This is one long line cause VAXC can't handle a \-newline. */
-#if 1 < (defined (DBX_DEBUGGING_INFO) + defined (SDB_DEBUGGING_INFO) + defined (DWARF_DEBUGGING_INFO) + defined (XCOFF_DEBUGGING_INFO))
-#ifdef PREFERRED_DEBUGGING_TYPE
- if (!strncmp (str, "ggdb", len))
- write_symbols = PREFERRED_DEBUGGING_TYPE;
-#else /* no PREFERRED_DEBUGGING_TYPE */
-You Lose! You must define PREFERRED_DEBUGGING_TYPE!
-#endif /* no PREFERRED_DEBUGGING_TYPE */
-#endif /* More than one debugger format enabled. */
+ if (type == NO_DEBUG)
+ {
+ type = PREFERRED_DEBUGGING_TYPE;
+ if (len > 1 && strncmp (str, "ggdb", len) == 0)
+ {
+#if defined (DWARF2_DEBUGGING_INFO) && !defined (LINKER_DOES_NOT_WORK_WITH_DWARF2)
+ type = DWARF2_DEBUG;
+#else
#ifdef DBX_DEBUGGING_INFO
- if (write_symbols != NO_DEBUG)
- ;
- else if (!strncmp (str, "ggdb", len))
- write_symbols = DBX_DEBUG;
- else if (!strncmp (str, "gstabs", len))
- write_symbols = DBX_DEBUG;
- else if (!strncmp (str, "gstabs+", len))
- write_symbols = DBX_DEBUG;
-
- /* Always enable extensions for -ggdb or -gstabs+,
- always disable for -gstabs.
- For plain -g, use system-specific default. */
- if (write_symbols == DBX_DEBUG && !strncmp (str, "ggdb", len)
- && len >= 2)
- use_gnu_debug_info_extensions = 1;
- else if (write_symbols == DBX_DEBUG && !strncmp (str, "gstabs+", len)
- && len >= 7)
- use_gnu_debug_info_extensions = 1;
- else if (write_symbols == DBX_DEBUG
- && !strncmp (str, "gstabs", len) && len >= 2)
- use_gnu_debug_info_extensions = 0;
- else
- use_gnu_debug_info_extensions = DEFAULT_GDB_EXTENSIONS;
-#endif /* DBX_DEBUGGING_INFO */
-#ifdef DWARF_DEBUGGING_INFO
- if (write_symbols != NO_DEBUG)
- ;
- else if (!strncmp (str, "g", len))
- write_symbols = DWARF_DEBUG;
- else if (!strncmp (str, "ggdb", len))
- write_symbols = DWARF_DEBUG;
- else if (!strncmp (str, "gdwarf", len))
- write_symbols = DWARF_DEBUG;
-
- /* Always enable extensions for -ggdb or -gdwarf+,
- always disable for -gdwarf.
- For plain -g, use system-specific default. */
- if (write_symbols == DWARF_DEBUG && !strncmp (str, "ggdb", len)
- && len >= 2)
- use_gnu_debug_info_extensions = 1;
- else if (write_symbols == DWARF_DEBUG && !strcmp (str, "gdwarf+"))
- use_gnu_debug_info_extensions = 1;
- else if (write_symbols == DWARF_DEBUG
- && !strncmp (str, "gdwarf", len) && len >= 2)
- use_gnu_debug_info_extensions = 0;
- else
- use_gnu_debug_info_extensions = DEFAULT_GDB_EXTENSIONS;
+ type = DBX_DEBUG;
#endif
-#ifdef SDB_DEBUGGING_INFO
- if (write_symbols != NO_DEBUG)
- ;
- else if (!strncmp (str, "g", len))
- write_symbols = SDB_DEBUG;
- else if (!strncmp (str, "gdb", len))
- write_symbols = SDB_DEBUG;
- else if (!strncmp (str, "gcoff", len))
- write_symbols = SDB_DEBUG;
-#endif /* SDB_DEBUGGING_INFO */
-#ifdef XCOFF_DEBUGGING_INFO
- if (write_symbols != NO_DEBUG)
- ;
- else if (!strncmp (str, "g", len))
- write_symbols = XCOFF_DEBUG;
- else if (!strncmp (str, "ggdb", len))
- write_symbols = XCOFF_DEBUG;
- else if (!strncmp (str, "gxcoff", len))
- write_symbols = XCOFF_DEBUG;
-
- /* Always enable extensions for -ggdb or -gxcoff+,
- always disable for -gxcoff.
- For plain -g, use system-specific default. */
- if (write_symbols == XCOFF_DEBUG && !strncmp (str, "ggdb", len)
- && len >= 2)
- use_gnu_debug_info_extensions = 1;
- else if (write_symbols == XCOFF_DEBUG && !strcmp (str, "gxcoff+"))
- use_gnu_debug_info_extensions = 1;
- else if (write_symbols == XCOFF_DEBUG
- && !strncmp (str, "gxcoff", len) && len >= 2)
- use_gnu_debug_info_extensions = 0;
- else
- use_gnu_debug_info_extensions = DEFAULT_GDB_EXTENSIONS;
-#endif
- if (write_symbols == NO_DEBUG)
+#endif
+ }
+ }
+
+ if (type == NO_DEBUG)
+ warning ("`-%s' not supported by this configuration of GCC",
+ str);
+
+ /* Does it conflict with an already selected type? */
+ if (type_explicitly_set_p
+ /* -g/-ggdb don't conflict with anything */
+ && da->debug_type != NO_DEBUG
+ && type != selected_debug_type)
+ warning ("`-%s' ignored, conflicts with `-g%s'",
+ str, debug_type_names[(int) selected_debug_type]);
+ else
+ {
+ /* If the format has already been set, -g/-ggdb
+ only change the debug level. */
+ if (type_explicitly_set_p
+ && da->debug_type == NO_DEBUG)
+ ; /* don't change debugging type */
+ else
+ {
+ selected_debug_type = type;
+ type_explicitly_set_p = da->debug_type != NO_DEBUG;
+ }
+ write_symbols = (level == 0
+ ? NO_DEBUG
+ : selected_debug_type);
+ use_gnu_debug_info_extensions = da->use_extensions_p;
+ debug_info_level = (enum debug_info_level) level;
+ }
+ break;
+ }
+ }
+ if (! da->arg)
warning ("`-%s' not supported by this configuration of GCC",
str);
- else if (level == 0)
- write_symbols = NO_DEBUG;
- else
- debug_info_level = (enum debug_info_level) level;
}
else if (!strcmp (str, "o"))
{
@@ -3812,6 +4757,11 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
flag_gen_aux_info = 1;
aux_info_file_name = (str[8] != '\0' ? str+8 : argv[++i]);
}
+ else if (!strcmp (str, "-help"))
+ {
+ display_help ();
+ exit (0);
+ }
else
error ("Invalid option `%s'", argv[i]);
}
@@ -3821,17 +4771,9 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
filename = argv[i];
}
- /* Initialize for bytecode output. A good idea to do this as soon as
- possible after the "-f" options have been parsed. */
- if (output_bytecode)
- {
-#ifndef TARGET_SUPPORTS_BYTECODE
- /* Just die with a fatal error if not supported */
- fatal ("-fbytecode not supporter for this target");
-#else
- bc_initialize ();
-#endif
- }
+ /* Checker uses the frame pointer. */
+ if (flag_check_memory_usage)
+ flag_omit_frame_pointer = 0;
if (optimize == 0)
{
@@ -3847,20 +4789,26 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
warning ("-Wuninitialized is not supported without -O");
}
-#if defined(DWARF_DEBUGGING_INFO)
- if (write_symbols == DWARF_DEBUG
- && strcmp (language_string, "GNU C++") == 0)
- {
- warning ("-g option not supported for C++ on systems using the DWARF debugging format");
- write_symbols = NO_DEBUG;
- }
-#endif /* defined(DWARF_DEBUGGING_INFO) */
-
#ifdef OVERRIDE_OPTIONS
/* Some machines may reject certain combinations of options. */
OVERRIDE_OPTIONS;
#endif
+ if (exceptions_via_longjmp == 2)
+ {
+#ifdef DWARF2_UNWIND_INFO
+ exceptions_via_longjmp = ! DWARF2_UNWIND_INFO;
+#else
+ exceptions_via_longjmp = 1;
+#endif
+ }
+
+ if (profile_block_flag == 3)
+ {
+ warning ("`-ax' and `-a' are conflicting options. `-a' ignored.");
+ profile_block_flag = 2;
+ }
+
/* Unrolling all loops implies that standard loop unrolling must also
be done. */
if (flag_unroll_all_loops)
@@ -3889,40 +4837,30 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
option flags in use. */
if (version_flag)
{
- fprintf (stderr, "%s version %s", language_string, version_string);
-#ifdef TARGET_VERSION
- TARGET_VERSION;
-#endif
-#ifdef __GNUC__
-#ifndef __VERSION__
-#define __VERSION__ "[unknown]"
-#endif
- fprintf (stderr, " compiled by GNU C version %s.\n", __VERSION__);
-#else
- fprintf (stderr, " compiled by CC.\n");
-#endif
+ print_version (stderr, "");
if (! quiet_flag)
- print_switch_values ();
+ print_switch_values (stderr, 0, MAX_LINE, "", " ", "\n");
}
compile_file (filename);
-#if !defined(OS2) && !defined(VMS) && !defined(_WIN32)
+#if !defined(OS2) && !defined(VMS) && (!defined(_WIN32) || defined (__CYGWIN32__))
if (flag_print_mem)
{
char *lim = (char *) sbrk (0);
- fprintf (stderr, "Data size %d.\n",
- lim - (char *) &environ);
+ fprintf (stderr, "Data size %ld.\n", (long)(lim - (char *) &environ));
fflush (stderr);
+#ifndef __MSDOS__
#ifdef USG
system ("ps -l 1>&2");
#else /* not USG */
system ("ps v");
#endif /* not USG */
+#endif
}
-#endif /* not OS2 and not VMS and not _WIN32 */
+#endif /* ! OS2 && ! VMS && (! _WIN32 || CYGWIN32) */
if (errorcount)
exit (FATAL_EXIT_CODE);
@@ -3933,30 +4871,13 @@ You Lose! You must define PREFERRED_DEBUGGING_TYPE!
}
/* Decode -m switches. */
-
-/* Here is a table, controlled by the tm.h file, listing each -m switch
- and which bits in `target_switches' it should set or clear.
- If VALUE is positive, it is bits to set.
- If VALUE is negative, -VALUE is bits to clear.
- (The sign bit is not used so there is no confusion.) */
-
-struct {char *name; int value;} target_switches []
- = TARGET_SWITCHES;
-
-/* This table is similar, but allows the switch to have a value. */
-
-#ifdef TARGET_OPTIONS
-struct {char *prefix; char ** variable;} target_options []
- = TARGET_OPTIONS;
-#endif
-
/* Decode the switch -mNAME. */
void
set_target_switch (name)
char *name;
{
- register int j;
+ register size_t j;
int valid = 0;
for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++)
@@ -3986,51 +4907,228 @@ set_target_switch (name)
error ("Invalid option `%s'", name);
}
-/* Variable used for communication between the following two routines. */
+/* Print version information to FILE.
+ Each line begins with INDENT (for the case where FILE is the
+ assembler output file). */
-static int line_position;
+void
+print_version (file, indent)
+ FILE *file;
+ char *indent;
+{
+ fprintf (file, "%s%s%s version %s", indent, *indent != 0 ? " " : "",
+ language_string, version_string);
+ fprintf (file, " (%s)", TARGET_NAME);
+#ifdef __GNUC__
+#ifndef __VERSION__
+#define __VERSION__ "[unknown]"
+#endif
+ fprintf (file, " compiled by GNU C version %s.\n", __VERSION__);
+#else
+ fprintf (file, " compiled by CC.\n");
+#endif
+}
-/* Print an option value and adjust the position in the line. */
+/* Print an option value and return the adjusted position in the line.
+ ??? We don't handle error returns from fprintf (disk full); presumably
+ other code will catch a disk full though. */
-static void
-print_single_switch (type, name)
- char *type, *name;
+int
+print_single_switch (file, pos, max, indent, sep, term, type, name)
+ FILE *file;
+ int pos, max;
+ char *indent, *sep, *term, *type, *name;
{
- fprintf (stderr, " %s%s", type, name);
-
- line_position += strlen (type) + strlen (name) + 1;
+ /* The ultrix fprintf returns 0 on success, so compute the result we want
+ here since we need it for the following test. */
+ int len = strlen (sep) + strlen (type) + strlen (name);
- if (line_position > 65)
+ if (pos != 0
+ && pos + len > max)
{
- fprintf (stderr, "\n\t");
- line_position = 8;
+ fprintf (file, "%s", term);
+ pos = 0;
}
+ if (pos == 0)
+ {
+ fprintf (file, "%s", indent);
+ pos = strlen (indent);
+ }
+ fprintf (file, "%s%s%s", sep, type, name);
+ pos += len;
+ return pos;
}
-/* Print default target switches for -version. */
+/* Print active target switches to FILE.
+ POS is the current cursor position and MAX is the size of a "line".
+ Each line begins with INDENT and ends with TERM.
+ Each switch is separated from the next by SEP. */
-static void
-print_switch_values ()
+void
+print_switch_values (file, pos, max, indent, sep, term)
+ FILE *file;
+ int pos, max;
+ char *indent, *sep, *term;
{
- register int j;
+ size_t j;
+ char **p;
+
+ /* Print the options as passed. */
- fprintf (stderr, "enabled:");
- line_position = 8;
+ pos = print_single_switch (file, pos, max, indent, *indent ? " " : "", term,
+ "options passed: ", "");
+
+ for (p = &save_argv[1]; *p != NULL; p++)
+ if (**p == '-')
+ {
+ /* Ignore these. */
+ if (strcmp (*p, "-o") == 0)
+ {
+ if (p[1] != NULL)
+ p++;
+ continue;
+ }
+ if (strcmp (*p, "-quiet") == 0)
+ continue;
+ if (strcmp (*p, "-version") == 0)
+ continue;
+ if ((*p)[1] == 'd')
+ continue;
+
+ pos = print_single_switch (file, pos, max, indent, sep, term, *p, "");
+ }
+ if (pos > 0)
+ fprintf (file, "%s", term);
+
+ /* Print the -f and -m options that have been enabled.
+ We don't handle language specific options but printing argv
+ should suffice. */
+
+ pos = print_single_switch (file, 0, max, indent, *indent ? " " : "", term,
+ "options enabled: ", "");
for (j = 0; j < sizeof f_options / sizeof f_options[0]; j++)
if (*f_options[j].variable == f_options[j].on_value)
- print_single_switch ("-f", f_options[j].string);
+ pos = print_single_switch (file, pos, max, indent, sep, term,
+ "-f", f_options[j].string);
- for (j = 0; j < sizeof W_options / sizeof W_options[0]; j++)
- if (*W_options[j].variable == W_options[j].on_value)
- print_single_switch ("-W", W_options[j].string);
+ /* Print target specific options. */
for (j = 0; j < sizeof target_switches / sizeof target_switches[0]; j++)
if (target_switches[j].name[0] != '\0'
&& target_switches[j].value > 0
&& ((target_switches[j].value & target_flags)
== target_switches[j].value))
- print_single_switch ("-m", target_switches[j].name);
+ {
+ pos = print_single_switch (file, pos, max, indent, sep, term,
+ "-m", target_switches[j].name);
+ }
+
+#ifdef TARGET_OPTIONS
+ for (j = 0; j < sizeof target_options / sizeof target_options[0]; j++)
+ if (*target_options[j].variable != NULL)
+ {
+ char prefix[256];
+ sprintf (prefix, "-m%s", target_options[j].prefix);
+ pos = print_single_switch (file, pos, max, indent, sep, term,
+ prefix, *target_options[j].variable);
+ }
+#endif
- fprintf (stderr, "\n");
+ fprintf (file, "%s", term);
+}
+
+/* Record the beginning of a new source file, named FILENAME. */
+
+void
+debug_start_source_file (filename)
+ register char *filename;
+{
+#ifdef DBX_DEBUGGING_INFO
+ if (write_symbols == DBX_DEBUG)
+ dbxout_start_new_source_file (filename);
+#endif
+#ifdef DWARF_DEBUGGING_INFO
+ if (debug_info_level == DINFO_LEVEL_VERBOSE
+ && write_symbols == DWARF_DEBUG)
+ dwarfout_start_new_source_file (filename);
+#endif /* DWARF_DEBUGGING_INFO */
+#ifdef DWARF2_DEBUGGING_INFO
+ if (debug_info_level == DINFO_LEVEL_VERBOSE
+ && write_symbols == DWARF2_DEBUG)
+ dwarf2out_start_source_file (filename);
+#endif /* DWARF2_DEBUGGING_INFO */
+#ifdef SDB_DEBUGGING_INFO
+ if (write_symbols == SDB_DEBUG)
+ sdbout_start_new_source_file (filename);
+#endif
+}
+
+/* Record the resumption of a source file. LINENO is the line number in
+ the source file we are returning to. */
+
+void
+debug_end_source_file (lineno)
+ register unsigned lineno;
+{
+#ifdef DBX_DEBUGGING_INFO
+ if (write_symbols == DBX_DEBUG)
+ dbxout_resume_previous_source_file ();
+#endif
+#ifdef DWARF_DEBUGGING_INFO
+ if (debug_info_level == DINFO_LEVEL_VERBOSE
+ && write_symbols == DWARF_DEBUG)
+ dwarfout_resume_previous_source_file (lineno);
+#endif /* DWARF_DEBUGGING_INFO */
+#ifdef DWARF2_DEBUGGING_INFO
+ if (debug_info_level == DINFO_LEVEL_VERBOSE
+ && write_symbols == DWARF2_DEBUG)
+ dwarf2out_end_source_file ();
+#endif /* DWARF2_DEBUGGING_INFO */
+#ifdef SDB_DEBUGGING_INFO
+ if (write_symbols == SDB_DEBUG)
+ sdbout_resume_previous_source_file ();
+#endif
+}
+
+/* Called from check_newline in c-parse.y. The `buffer' parameter contains
+ the tail part of the directive line, i.e. the part which is past the
+ initial whitespace, #, whitespace, directive-name, whitespace part. */
+
+void
+debug_define (lineno, buffer)
+ register unsigned lineno;
+ register char *buffer;
+{
+#ifdef DWARF_DEBUGGING_INFO
+ if (debug_info_level == DINFO_LEVEL_VERBOSE
+ && write_symbols == DWARF_DEBUG)
+ dwarfout_define (lineno, buffer);
+#endif /* DWARF_DEBUGGING_INFO */
+#ifdef DWARF2_DEBUGGING_INFO
+ if (debug_info_level == DINFO_LEVEL_VERBOSE
+ && write_symbols == DWARF2_DEBUG)
+ dwarf2out_define (lineno, buffer);
+#endif /* DWARF2_DEBUGGING_INFO */
+}
+
+/* Called from check_newline in c-parse.y. The `buffer' parameter contains
+ the tail part of the directive line, i.e. the part which is past the
+ initial whitespace, #, whitespace, directive-name, whitespace part. */
+
+void
+debug_undef (lineno, buffer)
+ register unsigned lineno;
+ register char *buffer;
+{
+#ifdef DWARF_DEBUGGING_INFO
+ if (debug_info_level == DINFO_LEVEL_VERBOSE
+ && write_symbols == DWARF_DEBUG)
+ dwarfout_undef (lineno, buffer);
+#endif /* DWARF_DEBUGGING_INFO */
+#ifdef DWARF2_DEBUGGING_INFO
+ if (debug_info_level == DINFO_LEVEL_VERBOSE
+ && write_symbols == DWARF2_DEBUG)
+ dwarf2out_undef (lineno, buffer);
+#endif /* DWARF2_DEBUGGING_INFO */
}
diff --git a/contrib/gcc/toplev.h b/contrib/gcc/toplev.h
new file mode 100644
index 0000000..d206000
--- /dev/null
+++ b/contrib/gcc/toplev.h
@@ -0,0 +1,65 @@
+/* toplev.h - Various declarations for functions found in toplev.c
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ */
+
+#ifndef __GCC_TOPLEV_H__
+#define __GCC_TOPLEV_H__
+
+#ifdef __STDC__
+union tree_node;
+struct rtx_def;
+#endif
+
+extern int count_error PROTO ((int));
+extern void strip_off_ending PROTO ((char *, int));
+extern void print_time PROTO ((char *, int));
+extern int get_run_time PROTO ((void));
+extern void debug_start_source_file PROTO ((char *));
+extern void debug_end_source_file PROTO ((unsigned));
+extern void debug_define PROTO ((unsigned, char *));
+extern void debug_undef PROTO ((unsigned, char *));
+extern void fatal PVPROTO ((char *, ...))
+ ATTRIBUTE_PRINTF_1;
+extern void fatal_io_error PROTO ((char *));
+extern void pfatal_with_name PROTO ((char *));
+extern void warning PVPROTO ((char *, ...))
+ ATTRIBUTE_PRINTF_1;
+extern void error PVPROTO ((char *, ...))
+ ATTRIBUTE_PRINTF_1;
+extern void pedwarn PVPROTO ((char *, ...))
+ ATTRIBUTE_PRINTF_1;
+extern void pedwarn_with_file_and_line PVPROTO ((char *, int, char *, ...))
+ ATTRIBUTE_PRINTF_3;
+extern void warning_with_file_and_line PVPROTO ((char *, int, char *, ...))
+ ATTRIBUTE_PRINTF_3;
+extern void error_with_file_and_line PVPROTO ((char *, int, char *, ...))
+ ATTRIBUTE_PRINTF_3;
+extern void sorry PVPROTO ((char *s, ...))
+ ATTRIBUTE_PRINTF_1;
+extern void default_print_error_function PROTO ((char *));
+extern void report_error_function PROTO ((char *));
+
+extern void rest_of_decl_compilation PROTO ((union tree_node *, char *, int, int));
+extern void rest_of_type_compilation PROTO ((union tree_node *, int));
+extern void rest_of_compilation PROTO ((union tree_node *));
+extern void pedwarn_with_decl PVPROTO ((union tree_node *, char *, ...));
+extern void warning_with_decl PVPROTO ((union tree_node *, char *, ...));
+extern void error_with_decl PVPROTO ((union tree_node *, char *, ...));
+extern void announce_function PROTO ((union tree_node *));
+
+extern void error_for_asm PVPROTO((struct rtx_def *, char *, ...))
+ ATTRIBUTE_PRINTF_2;
+extern void warning_for_asm PVPROTO((struct rtx_def *, char *, ...))
+ ATTRIBUTE_PRINTF_2;
+#ifdef _JBLEN
+extern void set_float_handler PROTO((jmp_buf));
+#endif
+
+#ifdef BUFSIZ
+extern void output_quoted_string PROTO ((FILE *, char *));
+extern void output_file_directive PROTO ((FILE *, char *));
+#endif
+
+extern void fancy_abort PROTO ((void));
+
+#endif /* __GCC_TOPLEV_H */
diff --git a/contrib/gcc/tree.c b/contrib/gcc/tree.c
index 8281e9c..ebe6e14 100644
--- a/contrib/gcc/tree.c
+++ b/contrib/gcc/tree.c
@@ -1,5 +1,5 @@
/* Language-independent node constructors for parse phase of GNU compiler.
- Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -33,21 +33,25 @@ Boston, MA 02111-1307, USA. */
are used also for allocating many other kinds of objects
by all passes of the compiler. */
-#include <setjmp.h>
#include "config.h"
-#include "flags.h"
-#include "tree.h"
-#include "function.h"
-#include "obstack.h"
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
-#include <stdio.h>
+#include "system.h"
+#include <setjmp.h>
+#include "flags.h"
+#include "tree.h"
+#include "except.h"
+#include "function.h"
+#include "obstack.h"
+#include "toplev.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
+/* obstack.[ch] explicitly declined to prototype this. */
+extern int _obstack_allocated_p PROTO ((struct obstack *h, GENERIC_PTR obj));
/* Tree nodes of permanent duration are allocated in this obstack.
They are the identifier nodes, and everything outside of
@@ -72,6 +76,10 @@ struct obstack maybepermanent_obstack;
struct simple_obstack_stack *toplev_inline_obstacks;
+/* Former elements of toplev_inline_obstacks that have been recycled. */
+
+struct simple_obstack_stack *extra_inline_obstacks;
+
/* This is a list of function_maybepermanent_obstacks for inline functions
nested in the current function that were compiled in the middle of
compiling other functions. */
@@ -172,7 +180,7 @@ struct momentary_level *momentary_stack;
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
-char *standard_tree_code_type[] = {
+char tree_code_type[MAX_TREE_CODES] = {
#include "tree.def"
};
#undef DEFTREECODE
@@ -183,7 +191,7 @@ char *standard_tree_code_type[] = {
#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
-int standard_tree_code_length[] = {
+int tree_code_length[MAX_TREE_CODES] = {
#include "tree.def"
};
#undef DEFTREECODE
@@ -192,27 +200,11 @@ int standard_tree_code_length[] = {
Used for printing out the tree and error messages. */
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
-char *standard_tree_code_name[] = {
+char *tree_code_name[MAX_TREE_CODES] = {
#include "tree.def"
};
#undef DEFTREECODE
-/* Table indexed by tree code giving a string containing a character
- classifying the tree code. Possibilities are
- t, d, s, c, r, e, <, 1 and 2. See tree.def for details. */
-
-char **tree_code_type;
-
-/* Table indexed by tree code giving number of expression
- operands beyond the fixed part of the node structure.
- Not used for types or decls. */
-
-int *tree_code_length;
-
-/* Table indexed by tree code giving name of tree code, as a string. */
-
-char **tree_code_name;
-
/* Statistics-gathering stuff. */
typedef enum
{
@@ -269,9 +261,15 @@ static int next_decl_uid;
/* Unique id for next type created. */
static int next_type_uid = 1;
+/* The language-specific function for alias analysis. If NULL, the
+ language does not do any special alias analysis. */
+int (*lang_get_alias_set) PROTO((tree));
+
/* Here is how primitive or already-canonicalized types' hash
codes are made. */
-#define TYPE_HASH(TYPE) ((HOST_WIDE_INT) (TYPE) & 0777777)
+#define TYPE_HASH(TYPE) ((unsigned long) (TYPE) & 0777777)
+
+static void append_random_chars PROTO((char *));
extern char *mode_name[];
@@ -340,6 +338,7 @@ save_tree_status (p, context)
p->all_types_permanent = all_types_permanent;
p->momentary_stack = momentary_stack;
p->maybepermanent_firstobj = maybepermanent_firstobj;
+ p->temporary_firstobj = temporary_firstobj;
p->momentary_firstobj = momentary_firstobj;
p->momentary_function_firstobj = momentary_function_firstobj;
p->function_obstack = function_obstack;
@@ -371,12 +370,22 @@ save_tree_status (p, context)
head = &f->inline_obstacks;
}
- current = ((struct simple_obstack_stack *)
- xmalloc (sizeof (struct simple_obstack_stack)));
+ if (context == NULL_TREE && extra_inline_obstacks)
+ {
+ current = extra_inline_obstacks;
+ extra_inline_obstacks = current->next;
+ }
+ else
+ {
+ current = ((struct simple_obstack_stack *)
+ xmalloc (sizeof (struct simple_obstack_stack)));
+
+ current->obstack
+ = (struct obstack *) xmalloc (sizeof (struct obstack));
+ gcc_obstack_init (current->obstack);
+ }
- current->obstack = (struct obstack *) xmalloc (sizeof (struct obstack));
function_maybepermanent_obstack = current->obstack;
- gcc_obstack_init (function_maybepermanent_obstack);
current->next = *head;
*head = current;
@@ -392,6 +401,7 @@ save_tree_status (p, context)
expression_obstack = &permanent_obstack;
rtl_obstack = saveable_obstack = &permanent_obstack;
+ temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
momentary_firstobj = (char *) obstack_finish (&momentary_obstack);
momentary_function_firstobj = momentary_firstobj;
}
@@ -400,8 +410,9 @@ save_tree_status (p, context)
This is used after a nested function. */
void
-restore_tree_status (p)
+restore_tree_status (p, context)
struct function *p;
+ tree context;
{
all_types_permanent = p->all_types_permanent;
momentary_stack = p->momentary_stack;
@@ -417,9 +428,36 @@ restore_tree_status (p)
past the nested function's end. */
obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
+ /* If we were compiling a toplevel function, we can free this space now. */
+ if (context == NULL_TREE)
+ {
+ obstack_free (&temporary_obstack, temporary_firstobj);
+ obstack_free (&momentary_obstack, momentary_function_firstobj);
+ }
+
+ /* If we were compiling a toplevel function that we don't actually want
+ to save anything from, return the obstack to the pool. */
+ if (context == NULL_TREE
+ && obstack_empty_p (function_maybepermanent_obstack))
+ {
+ struct simple_obstack_stack *current, **p = &toplev_inline_obstacks;
+
+ if ((*p) != NULL)
+ {
+ while ((*p)->obstack != function_maybepermanent_obstack)
+ p = &((*p)->next);
+ current = *p;
+ *p = current->next;
+
+ current->next = extra_inline_obstacks;
+ extra_inline_obstacks = current;
+ }
+ }
+
obstack_free (function_obstack, 0);
free (function_obstack);
+ temporary_firstobj = p->temporary_firstobj;
momentary_firstobj = p->momentary_firstobj;
momentary_function_firstobj = p->momentary_function_firstobj;
maybepermanent_firstobj = p->maybepermanent_firstobj;
@@ -692,6 +730,16 @@ savealloc (size)
{
return (char *) obstack_alloc (saveable_obstack, size);
}
+
+/* Allocate SIZE bytes in the expression obstack
+ and return a pointer to them. */
+
+char *
+expralloc (size)
+ int size;
+{
+ return (char *) obstack_alloc (expression_obstack, size);
+}
/* Print out which obstack an object is in. */
@@ -750,7 +798,7 @@ print_obstack_name (object, file, prefix)
obstack_name = "temp_decl_obstack";
}
- /* Check to see if the object is in the free area of the obstack. */
+ /* Check to see if the object is in the free area of the obstack. */
if (obstack != NULL)
{
if (object >= obstack->next_free
@@ -878,15 +926,7 @@ resume_momentary (yes)
void
init_tree_codes ()
{
- tree_code_type = (char **) xmalloc (sizeof (standard_tree_code_type));
- tree_code_length = (int *) xmalloc (sizeof (standard_tree_code_length));
- tree_code_name = (char **) xmalloc (sizeof (standard_tree_code_name));
- bcopy ((char *) standard_tree_code_type, (char *) tree_code_type,
- sizeof (standard_tree_code_type));
- bcopy ((char *) standard_tree_code_length, (char *) tree_code_length,
- sizeof (standard_tree_code_length));
- bcopy ((char *) standard_tree_code_name, (char *) tree_code_name,
- sizeof (standard_tree_code_name));
+
}
/* Return a newly allocated node of code CODE.
@@ -902,10 +942,12 @@ make_node (code)
{
register tree t;
register int type = TREE_CODE_CLASS (code);
- register int length;
+ register int length = 0;
register struct obstack *obstack = current_obstack;
register int i;
+#ifdef GATHER_STATISTICS
register tree_node_kind kind;
+#endif
switch (type)
{
@@ -1076,6 +1118,9 @@ make_node (code)
#ifdef SET_DEFAULT_TYPE_ATTRIBUTES
SET_DEFAULT_TYPE_ATTRIBUTES (t);
#endif
+ /* Note that we have not yet computed the alias set for this
+ type. */
+ TYPE_ALIAS_SET (t) = -1;
break;
case 'c':
@@ -1095,7 +1140,7 @@ copy_node (node)
{
register tree t;
register enum tree_code code = TREE_CODE (node);
- register int length;
+ register int length = 0;
register int i;
switch (TREE_CODE_CLASS (code))
@@ -1129,15 +1174,13 @@ copy_node (node)
for REAL_CST, since the number of words is machine-dependent due
to varying size and alignment of `double'. */
if (code == INTEGER_CST)
- {
- length = sizeof (struct tree_int_cst);
- break;
- }
+ length = sizeof (struct tree_int_cst);
else if (code == REAL_CST)
- {
- length = sizeof (struct tree_real_cst);
- break;
- }
+ length = sizeof (struct tree_real_cst);
+ else
+ length = (sizeof (struct tree_common)
+ + tree_code_length[(int) code] * sizeof (char *));
+ break;
case 'x': /* something random, like an identifier. */
length = sizeof (struct tree_common)
@@ -1154,7 +1197,10 @@ copy_node (node)
for (i = length / sizeof (int) * sizeof (int); i < length; i++)
((char *) t)[i] = ((char *) node)[i];
- TREE_CHAIN (t) = 0;
+ /* EXPR_WITH_FILE_LOCATION must keep filename info stored in TREE_CHAIN */
+ if (TREE_CODE (node) != EXPR_WITH_FILE_LOCATION)
+ TREE_CHAIN (t) = 0;
+ TREE_ASM_WRITTEN (t) = 0;
if (TREE_CODE_CLASS (code) == 'd')
DECL_UID (t) = next_decl_uid++;
@@ -1162,6 +1208,14 @@ copy_node (node)
{
TYPE_UID (t) = next_type_uid++;
TYPE_OBSTACK (t) = current_obstack;
+
+ /* The following is so that the debug code for
+ the copy is different from the original type.
+ The two statements usually duplicate each other
+ (because they clear fields of the same union),
+ but the optimizer should catch that. */
+ TYPE_SYMTAB_POINTER (t) = 0;
+ TYPE_SYMTAB_ADDRESS (t) = 0;
}
TREE_PERMANENT (t) = (current_obstack == &permanent_obstack);
@@ -1217,9 +1271,9 @@ get_identifier (text)
hash_len = id_clash_len;
/* Compute hash code */
- hi = hash_len * 613 + (unsigned)text[0];
+ hi = hash_len * 613 + (unsigned) text[0];
for (i = 1; i < hash_len; i += 2)
- hi = ((hi * 613) + (unsigned)(text[i]));
+ hi = ((hi * 613) + (unsigned) (text[i]));
hi &= (1 << HASHBITS) - 1;
hi %= MAX_HASH_TABLE;
@@ -1258,6 +1312,45 @@ get_identifier (text)
return idp; /* <-- return if created */
}
+/* If an identifier with the name TEXT (a null-terminated string) has
+ previously been referred to, return that node; otherwise return
+ NULL_TREE. */
+
+tree
+maybe_get_identifier (text)
+ register char *text;
+{
+ register int hi;
+ register int i;
+ register tree idp;
+ register int len, hash_len;
+
+ /* Compute length of text in len. */
+ for (len = 0; text[len]; len++);
+
+ /* Decide how much of that length to hash on */
+ hash_len = len;
+ if (warn_id_clash && len > id_clash_len)
+ hash_len = id_clash_len;
+
+ /* Compute hash code */
+ hi = hash_len * 613 + (unsigned) text[0];
+ for (i = 1; i < hash_len; i += 2)
+ hi = ((hi * 613) + (unsigned) (text[i]));
+
+ hi &= (1 << HASHBITS) - 1;
+ hi %= MAX_HASH_TABLE;
+
+ /* Search table for identifier */
+ for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
+ if (IDENTIFIER_LENGTH (idp) == len
+ && IDENTIFIER_POINTER (idp)[0] == text[0]
+ && !bcmp (IDENTIFIER_POINTER (idp), text, len))
+ return idp; /* <-- return if found */
+
+ return NULL_TREE;
+}
+
/* Enable warnings on similar identifiers (if requested).
Done after the built-in identifiers are created. */
@@ -1326,22 +1419,25 @@ build_real (type, d)
#if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
REAL_VALUE_TYPE
-real_value_from_int_cst (i)
- tree i;
+real_value_from_int_cst (type, i)
+ tree type, i;
{
REAL_VALUE_TYPE d;
- REAL_VALUE_TYPE e;
- /* Some 386 compilers mishandle unsigned int to float conversions,
- so introduce a temporary variable E to avoid those bugs. */
#ifdef REAL_ARITHMETIC
if (! TREE_UNSIGNED (TREE_TYPE (i)))
- REAL_VALUE_FROM_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i));
+ REAL_VALUE_FROM_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i),
+ TYPE_MODE (type));
else
- REAL_VALUE_FROM_UNSIGNED_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i));
+ REAL_VALUE_FROM_UNSIGNED_INT (d, TREE_INT_CST_LOW (i),
+ TREE_INT_CST_HIGH (i), TYPE_MODE (type));
#else /* not REAL_ARITHMETIC */
+ /* Some 386 compilers mishandle unsigned int to float conversions,
+ so introduce a temporary variable E to avoid those bugs. */
if (TREE_INT_CST_HIGH (i) < 0 && ! TREE_UNSIGNED (TREE_TYPE (i)))
{
+ REAL_VALUE_TYPE e;
+
d = (double) (~ TREE_INT_CST_HIGH (i));
e = ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
* (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
@@ -1352,6 +1448,8 @@ real_value_from_int_cst (i)
}
else
{
+ REAL_VALUE_TYPE e;
+
d = (double) (unsigned HOST_WIDE_INT) TREE_INT_CST_HIGH (i);
e = ((double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2))
* (double) ((HOST_WIDE_INT) 1 << (HOST_BITS_PER_WIDE_INT / 2)));
@@ -1388,7 +1486,12 @@ build_real_from_int_cst (type, i)
set_float_handler (float_error);
- d = REAL_VALUE_TRUNCATE (TYPE_MODE (type), real_value_from_int_cst (i));
+#ifdef REAL_ARITHMETIC
+ d = real_value_from_int_cst (type, i);
+#else
+ d = REAL_VALUE_TRUNCATE (TYPE_MODE (type),
+ real_value_from_int_cst (type, i));
+#endif
/* Check for valid float value for this type on this target machine. */
@@ -1427,18 +1530,19 @@ build_string (len, str)
/* Return a newly constructed COMPLEX_CST node whose value is
specified by the real and imaginary parts REAL and IMAG.
- Both REAL and IMAG should be constant nodes.
- The TREE_TYPE is not initialized. */
+ Both REAL and IMAG should be constant nodes. TYPE, if specified,
+ will be the type of the COMPLEX_CST; otherwise a new type will be made. */
tree
-build_complex (real, imag)
+build_complex (type, real, imag)
+ tree type;
tree real, imag;
{
register tree t = make_node (COMPLEX_CST);
TREE_REALPART (t) = real;
TREE_IMAGPART (t) = imag;
- TREE_TYPE (t) = build_complex_type (TREE_TYPE (real));
+ TREE_TYPE (t) = type ? type : build_complex_type (TREE_TYPE (real));
TREE_OVERFLOW (t) = TREE_OVERFLOW (real) | TREE_OVERFLOW (imag);
TREE_CONSTANT_OVERFLOW (t)
= TREE_CONSTANT_OVERFLOW (real) | TREE_CONSTANT_OVERFLOW (imag);
@@ -1446,6 +1550,7 @@ build_complex (real, imag)
}
/* Build a newly constructed TREE_VEC node of length LEN. */
+
tree
make_tree_vec (len)
int len;
@@ -1483,6 +1588,7 @@ integer_zerop (expr)
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == INTEGER_CST
+ && ! TREE_CONSTANT_OVERFLOW (expr)
&& TREE_INT_CST_LOW (expr) == 0
&& TREE_INT_CST_HIGH (expr) == 0)
|| (TREE_CODE (expr) == COMPLEX_CST
@@ -1500,6 +1606,7 @@ integer_onep (expr)
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == INTEGER_CST
+ && ! TREE_CONSTANT_OVERFLOW (expr)
&& TREE_INT_CST_LOW (expr) == 1
&& TREE_INT_CST_HIGH (expr) == 0)
|| (TREE_CODE (expr) == COMPLEX_CST
@@ -1524,7 +1631,8 @@ integer_all_onesp (expr)
&& integer_zerop (TREE_IMAGPART (expr)))
return 1;
- else if (TREE_CODE (expr) != INTEGER_CST)
+ else if (TREE_CODE (expr) != INTEGER_CST
+ || TREE_CONSTANT_OVERFLOW (expr))
return 0;
uns = TREE_UNSIGNED (TREE_TYPE (expr));
@@ -1564,6 +1672,7 @@ int
integer_pow2p (expr)
tree expr;
{
+ int prec;
HOST_WIDE_INT high, low;
STRIP_NOPS (expr);
@@ -1573,12 +1682,28 @@ integer_pow2p (expr)
&& integer_zerop (TREE_IMAGPART (expr)))
return 1;
- if (TREE_CODE (expr) != INTEGER_CST)
+ if (TREE_CODE (expr) != INTEGER_CST || TREE_CONSTANT_OVERFLOW (expr))
return 0;
+ prec = (POINTER_TYPE_P (TREE_TYPE (expr))
+ ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
high = TREE_INT_CST_HIGH (expr);
low = TREE_INT_CST_LOW (expr);
+ /* First clear all bits that are beyond the type's precision in case
+ we've been sign extended. */
+
+ if (prec == 2 * HOST_BITS_PER_WIDE_INT)
+ ;
+ else if (prec > HOST_BITS_PER_WIDE_INT)
+ high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
+ else
+ {
+ high = 0;
+ if (prec < HOST_BITS_PER_WIDE_INT)
+ low &= ~((HOST_WIDE_INT) (-1) << prec);
+ }
+
if (high == 0 && low == 0)
return 0;
@@ -1586,6 +1711,45 @@ integer_pow2p (expr)
|| (low == 0 && (high & (high - 1)) == 0));
}
+/* Return the power of two represented by a tree node known to be a
+ power of two. */
+
+int
+tree_log2 (expr)
+ tree expr;
+{
+ int prec;
+ HOST_WIDE_INT high, low;
+
+ STRIP_NOPS (expr);
+
+ if (TREE_CODE (expr) == COMPLEX_CST)
+ return tree_log2 (TREE_REALPART (expr));
+
+ prec = (POINTER_TYPE_P (TREE_TYPE (expr))
+ ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
+
+ high = TREE_INT_CST_HIGH (expr);
+ low = TREE_INT_CST_LOW (expr);
+
+ /* First clear all bits that are beyond the type's precision in case
+ we've been sign extended. */
+
+ if (prec == 2 * HOST_BITS_PER_WIDE_INT)
+ ;
+ else if (prec > HOST_BITS_PER_WIDE_INT)
+ high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
+ else
+ {
+ high = 0;
+ if (prec < HOST_BITS_PER_WIDE_INT)
+ low &= ~((HOST_WIDE_INT) (-1) << prec);
+ }
+
+ return (high != 0 ? HOST_BITS_PER_WIDE_INT + exact_log2 (high)
+ : exact_log2 (low));
+}
+
/* Return 1 if EXPR is the real constant zero. */
int
@@ -1595,6 +1759,7 @@ real_zerop (expr)
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (expr)
&& REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0))
|| (TREE_CODE (expr) == COMPLEX_CST
&& real_zerop (TREE_REALPART (expr))
@@ -1610,6 +1775,7 @@ real_onep (expr)
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (expr)
&& REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1))
|| (TREE_CODE (expr) == COMPLEX_CST
&& real_onep (TREE_REALPART (expr))
@@ -1625,6 +1791,7 @@ real_twop (expr)
STRIP_NOPS (expr);
return ((TREE_CODE (expr) == REAL_CST
+ && ! TREE_CONSTANT_OVERFLOW (expr)
&& REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2))
|| (TREE_CODE (expr) == COMPLEX_CST
&& real_twop (TREE_REALPART (expr))
@@ -1693,7 +1860,7 @@ binfo_member (elem, list)
return NULL_TREE;
}
-/* Return nonzero if ELEM is part of the chain CHAIN. */
+/* Return nonzero if ELEM is part of the chain CHAIN. */
int
chain_member (elem, chain)
@@ -1710,7 +1877,7 @@ chain_member (elem, chain)
}
/* Return nonzero if ELEM is equal to TREE_VALUE (CHAIN) for any piece of
- chain CHAIN. */
+ chain CHAIN. */
/* ??? This function was added for machine specific attributes but is no
longer used. It could be deleted if we could confirm all front ends
don't use it. */
@@ -1730,7 +1897,7 @@ chain_member_value (elem, chain)
}
/* Return nonzero if ELEM is equal to TREE_PURPOSE (CHAIN)
- for any piece of chain CHAIN. */
+ for any piece of chain CHAIN. */
/* ??? This function was added for machine specific attributes but is no
longer used. It could be deleted if we could confirm all front ends
don't use it. */
@@ -1799,7 +1966,7 @@ tree_last (chain)
{
register tree next;
if (chain)
- while (next = TREE_CHAIN (chain))
+ while ((next = TREE_CHAIN (chain)))
chain = next;
return chain;
}
@@ -1873,6 +2040,20 @@ build_decl_list (parm, value)
return node;
}
+/* Similar, but build on the expression_obstack. */
+
+tree
+build_expr_list (parm, value)
+ tree parm, value;
+{
+ register tree node;
+ register struct obstack *ambient_obstack = current_obstack;
+ current_obstack = expression_obstack;
+ node = build_tree_list (parm, value);
+ current_obstack = ambient_obstack;
+ return node;
+}
+
/* Return a newly created TREE_LIST node whose
purpose and value fields are PARM and VALUE
and whose TREE_CHAIN is CHAIN. */
@@ -1919,6 +2100,20 @@ decl_tree_cons (purpose, value, chain)
return node;
}
+/* Similar, but build on the expression_obstack. */
+
+tree
+expr_tree_cons (purpose, value, chain)
+ tree purpose, value, chain;
+{
+ register tree node;
+ register struct obstack *ambient_obstack = current_obstack;
+ current_obstack = expression_obstack;
+ node = tree_cons (purpose, value, chain);
+ current_obstack = ambient_obstack;
+ return node;
+}
+
/* Same as `tree_cons' but make a permanent object. */
tree
@@ -1978,58 +2173,86 @@ size_in_bytes (type)
if (type == error_mark_node)
return integer_zero_node;
+
type = TYPE_MAIN_VARIANT (type);
- if (TYPE_SIZE (type) == 0)
+ t = TYPE_SIZE_UNIT (type);
+ if (t == 0)
{
incomplete_type_error (NULL_TREE, type);
return integer_zero_node;
}
- t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
- size_int (BITS_PER_UNIT));
if (TREE_CODE (t) == INTEGER_CST)
force_fit_type (t, 0);
+
return t;
}
-/* Return the size of TYPE (in bytes) as an integer,
- or return -1 if the size can vary. */
+/* Return the size of TYPE (in bytes) as a wide integer
+ or return -1 if the size can vary or is larger than an integer. */
-int
+HOST_WIDE_INT
int_size_in_bytes (type)
tree type;
{
- unsigned int size;
+ tree t;
+
if (type == error_mark_node)
return 0;
+
type = TYPE_MAIN_VARIANT (type);
- if (TYPE_SIZE (type) == 0)
+ t = TYPE_SIZE_UNIT (type);
+ if (t == 0
+ || TREE_CODE (t) != INTEGER_CST
+ || TREE_INT_CST_HIGH (t) != 0)
return -1;
- if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
- return -1;
- if (TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0)
- {
- tree t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
- size_int (BITS_PER_UNIT));
- return TREE_INT_CST_LOW (t);
- }
- size = TREE_INT_CST_LOW (TYPE_SIZE (type));
- return (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
+
+ return TREE_INT_CST_LOW (t);
}
/* Return, as a tree node, the number of elements for TYPE (which is an
- ARRAY_TYPE) minus one. This counts only elements of the top array. */
+ ARRAY_TYPE) minus one. This counts only elements of the top array.
+
+ Don't let any SAVE_EXPRs escape; if we are called as part of a cleanup
+ action, they would get unsaved. */
tree
array_type_nelts (type)
tree type;
{
- tree index_type = TYPE_DOMAIN (type);
+ tree index_type, min, max;
+
+ /* If they did it with unspecified bounds, then we should have already
+ given an error about it before we got here. */
+ if (! TYPE_DOMAIN (type))
+ return error_mark_node;
- return (integer_zerop (TYPE_MIN_VALUE (index_type))
- ? TYPE_MAX_VALUE (index_type)
- : fold (build (MINUS_EXPR, TREE_TYPE (TYPE_MAX_VALUE (index_type)),
- TYPE_MAX_VALUE (index_type),
- TYPE_MIN_VALUE (index_type))));
+ index_type = TYPE_DOMAIN (type);
+ min = TYPE_MIN_VALUE (index_type);
+ max = TYPE_MAX_VALUE (index_type);
+
+ if (! TREE_CONSTANT (min))
+ {
+ STRIP_NOPS (min);
+ if (TREE_CODE (min) == SAVE_EXPR)
+ min = build (RTL_EXPR, TREE_TYPE (TYPE_MIN_VALUE (index_type)), 0,
+ SAVE_EXPR_RTL (min));
+ else
+ min = TYPE_MIN_VALUE (index_type);
+ }
+
+ if (! TREE_CONSTANT (max))
+ {
+ STRIP_NOPS (max);
+ if (TREE_CODE (max) == SAVE_EXPR)
+ max = build (RTL_EXPR, TREE_TYPE (TYPE_MAX_VALUE (index_type)), 0,
+ SAVE_EXPR_RTL (max));
+ else
+ max = TYPE_MAX_VALUE (index_type);
+ }
+
+ return (integer_zerop (min)
+ ? max
+ : fold (build (MINUS_EXPR, TREE_TYPE (max), max, min)));
}
/* Return nonzero if arg is static -- a reference to an object in
@@ -2044,9 +2267,12 @@ staticp (arg)
case FUNCTION_DECL:
/* Nested functions aren't static, since taking their address
involves a trampoline. */
- return decl_function_context (arg) == 0;
+ return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
+ && ! DECL_NON_ADDR_CONST_P (arg);
+
case VAR_DECL:
- return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
+ return (TREE_STATIC (arg) || DECL_EXTERNAL (arg))
+ && ! DECL_NON_ADDR_CONST_P (arg);
case CONSTRUCTOR:
return TREE_STATIC (arg);
@@ -2054,9 +2280,14 @@ staticp (arg)
case STRING_CST:
return 1;
+ /* If we are referencing a bitfield, we can't evaluate an
+ ADDR_EXPR at compile time and so it isn't a constant. */
case COMPONENT_REF:
+ return (! DECL_BIT_FIELD (TREE_OPERAND (arg, 1))
+ && staticp (TREE_OPERAND (arg, 0)));
+
case BIT_FIELD_REF:
- return staticp (TREE_OPERAND (arg, 0));
+ return 0;
#if 0
/* This case is technically correct, but results in setting
@@ -2070,9 +2301,10 @@ staticp (arg)
if (TREE_CODE (TYPE_SIZE (TREE_TYPE (arg))) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (arg, 1)) == INTEGER_CST)
return staticp (TREE_OPERAND (arg, 0));
- }
- return 0;
+ default:
+ return 0;
+ }
}
/* Wrap a SAVE_EXPR around EXPR, if appropriate.
@@ -2112,7 +2344,7 @@ save_expr (expr)
fact (i.e. this allows further folding, and direct checks for constants).
However, a read-only object that has side effects cannot be bypassed.
Since it is no problem to reevaluate literals, we just return the
- literal node. */
+ literal node. */
if (TREE_CONSTANT (t) || (TREE_READONLY (t) && ! TREE_SIDE_EFFECTS (t))
|| TREE_CODE (t) == SAVE_EXPR || TREE_CODE (t) == ERROR_MARK)
@@ -2138,55 +2370,269 @@ save_expr (expr)
TREE_SIDE_EFFECTS (t) = 1;
return t;
}
+
+/* Arrange for an expression to be expanded multiple independent
+ times. This is useful for cleanup actions, as the backend can
+ expand them multiple times in different places. */
+
+tree
+unsave_expr (expr)
+ tree expr;
+{
+ tree t;
+
+ /* If this is already protected, no sense in protecting it again. */
+ if (TREE_CODE (expr) == UNSAVE_EXPR)
+ return expr;
+
+ t = build1 (UNSAVE_EXPR, TREE_TYPE (expr), expr);
+ TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (expr);
+ return t;
+}
+
+/* Returns the index of the first non-tree operand for CODE, or the number
+ of operands if all are trees. */
+
+int
+first_rtl_op (code)
+ enum tree_code code;
+{
+ switch (code)
+ {
+ case SAVE_EXPR:
+ return 2;
+ case RTL_EXPR:
+ return 0;
+ case CALL_EXPR:
+ return 2;
+ case WITH_CLEANUP_EXPR:
+ /* Should be defined to be 2. */
+ return 1;
+ case METHOD_CALL_EXPR:
+ return 3;
+ default:
+ return tree_code_length [(int) code];
+ }
+}
+
+/* Modify a tree in place so that all the evaluate only once things
+ are cleared out. Return the EXPR given. */
+
+tree
+unsave_expr_now (expr)
+ tree expr;
+{
+ enum tree_code code;
+ register int i;
+ int first_rtl;
+
+ if (expr == NULL_TREE)
+ return expr;
+
+ code = TREE_CODE (expr);
+ first_rtl = first_rtl_op (code);
+ switch (code)
+ {
+ case SAVE_EXPR:
+ SAVE_EXPR_RTL (expr) = 0;
+ break;
+
+ case TARGET_EXPR:
+ TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 3);
+ TREE_OPERAND (expr, 3) = NULL_TREE;
+ break;
+
+ case RTL_EXPR:
+ /* I don't yet know how to emit a sequence multiple times. */
+ if (RTL_EXPR_SEQUENCE (expr) != 0)
+ abort ();
+ break;
+
+ case CALL_EXPR:
+ CALL_EXPR_RTL (expr) = 0;
+ if (TREE_OPERAND (expr, 1)
+ && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
+ {
+ tree exp = TREE_OPERAND (expr, 1);
+ while (exp)
+ {
+ unsave_expr_now (TREE_VALUE (exp));
+ exp = TREE_CHAIN (exp);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ switch (TREE_CODE_CLASS (code))
+ {
+ case 'c': /* a constant */
+ case 't': /* a type node */
+ case 'x': /* something random, like an identifier or an ERROR_MARK. */
+ case 'd': /* A decl node */
+ case 'b': /* A block node */
+ return expr;
+
+ case 'e': /* an expression */
+ case 'r': /* a reference */
+ case 's': /* an expression with side effects */
+ case '<': /* a comparison expression */
+ case '2': /* a binary arithmetic expression */
+ case '1': /* a unary arithmetic expression */
+ for (i = first_rtl - 1; i >= 0; i--)
+ unsave_expr_now (TREE_OPERAND (expr, i));
+ return expr;
+
+ default:
+ abort ();
+ }
+}
/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
- or offset that depends on a field within a record.
-
- Note that we only allow such expressions within simple arithmetic
- or a COND_EXPR. */
+ or offset that depends on a field within a record. */
int
contains_placeholder_p (exp)
tree exp;
{
register enum tree_code code = TREE_CODE (exp);
- tree inner;
+ int result;
/* If we have a WITH_RECORD_EXPR, it "cancels" any PLACEHOLDER_EXPR
in it since it is supplying a value for it. */
if (code == WITH_RECORD_EXPR)
return 0;
+ else if (code == PLACEHOLDER_EXPR)
+ return 1;
switch (TREE_CODE_CLASS (code))
{
case 'r':
- for (inner = TREE_OPERAND (exp, 0);
- TREE_CODE_CLASS (TREE_CODE (inner)) == 'r';
- inner = TREE_OPERAND (inner, 0))
- ;
- return TREE_CODE (inner) == PLACEHOLDER_EXPR;
+ /* Don't look at any PLACEHOLDER_EXPRs that might be in index or bit
+ position computations since they will be converted into a
+ WITH_RECORD_EXPR involving the reference, which will assume
+ here will be valid. */
+ return contains_placeholder_p (TREE_OPERAND (exp, 0));
+ case 'x':
+ if (code == TREE_LIST)
+ return (contains_placeholder_p (TREE_VALUE (exp))
+ || (TREE_CHAIN (exp) != 0
+ && contains_placeholder_p (TREE_CHAIN (exp))));
+ break;
+
case '1':
case '2': case '<':
case 'e':
+ switch (code)
+ {
+ case COMPOUND_EXPR:
+ /* Ignoring the first operand isn't quite right, but works best. */
+ return contains_placeholder_p (TREE_OPERAND (exp, 1));
+
+ case RTL_EXPR:
+ case CONSTRUCTOR:
+ return 0;
+
+ case COND_EXPR:
+ return (contains_placeholder_p (TREE_OPERAND (exp, 0))
+ || contains_placeholder_p (TREE_OPERAND (exp, 1))
+ || contains_placeholder_p (TREE_OPERAND (exp, 2)));
+
+ case SAVE_EXPR:
+ /* If we already know this doesn't have a placeholder, don't
+ check again. */
+ if (SAVE_EXPR_NOPLACEHOLDER (exp) || SAVE_EXPR_RTL (exp) != 0)
+ return 0;
+
+ SAVE_EXPR_NOPLACEHOLDER (exp) = 1;
+ result = contains_placeholder_p (TREE_OPERAND (exp, 0));
+ if (result)
+ SAVE_EXPR_NOPLACEHOLDER (exp) = 0;
+
+ return result;
+
+ case CALL_EXPR:
+ return (TREE_OPERAND (exp, 1) != 0
+ && contains_placeholder_p (TREE_OPERAND (exp, 1)));
+
+ default:
+ break;
+ }
+
switch (tree_code_length[(int) code])
{
case 1:
return contains_placeholder_p (TREE_OPERAND (exp, 0));
case 2:
- return (code != RTL_EXPR
- && code != CONSTRUCTOR
- && ! (code == SAVE_EXPR && SAVE_EXPR_RTL (exp) != 0)
- && code != WITH_RECORD_EXPR
- && (contains_placeholder_p (TREE_OPERAND (exp, 0))
- || contains_placeholder_p (TREE_OPERAND (exp, 1))));
- case 3:
- return (code == COND_EXPR
- && (contains_placeholder_p (TREE_OPERAND (exp, 0))
- || contains_placeholder_p (TREE_OPERAND (exp, 1))
- || contains_placeholder_p (TREE_OPERAND (exp, 2))));
+ return (contains_placeholder_p (TREE_OPERAND (exp, 0))
+ || contains_placeholder_p (TREE_OPERAND (exp, 1)));
+ default:
+ return 0;
}
+
+ default:
+ return 0;
}
+ return 0;
+}
+
+/* Return 1 if EXP contains any expressions that produce cleanups for an
+ outer scope to deal with. Used by fold. */
+
+int
+has_cleanups (exp)
+ tree exp;
+{
+ int i, nops, cmp;
+
+ if (! TREE_SIDE_EFFECTS (exp))
+ return 0;
+
+ switch (TREE_CODE (exp))
+ {
+ case TARGET_EXPR:
+ case WITH_CLEANUP_EXPR:
+ return 1;
+
+ case CLEANUP_POINT_EXPR:
+ return 0;
+
+ case CALL_EXPR:
+ for (exp = TREE_OPERAND (exp, 1); exp; exp = TREE_CHAIN (exp))
+ {
+ cmp = has_cleanups (TREE_VALUE (exp));
+ if (cmp)
+ return cmp;
+ }
+ return 0;
+
+ default:
+ break;
+ }
+
+ /* This general rule works for most tree codes. All exceptions should be
+ handled above. If this is a language-specific tree code, we can't
+ trust what might be in the operand, so say we don't know
+ the situation. */
+ if ((int) TREE_CODE (exp) >= (int) LAST_AND_UNUSED_TREE_CODE)
+ return -1;
+
+ nops = first_rtl_op (TREE_CODE (exp));
+ for (i = 0; i < nops; i++)
+ if (TREE_OPERAND (exp, i) != 0)
+ {
+ int type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i)));
+ if (type == 'e' || type == '<' || type == '1' || type == '2'
+ || type == 'r' || type == 's')
+ {
+ cmp = has_cleanups (TREE_OPERAND (exp, i));
+ if (cmp)
+ return cmp;
+ }
+ }
return 0;
}
@@ -2194,7 +2640,8 @@ contains_placeholder_p (exp)
/* Given a tree EXP, a FIELD_DECL F, and a replacement value R,
return a tree with all occurrences of references to F in a
PLACEHOLDER_EXPR replaced by R. Note that we assume here that EXP
- contains only arithmetic expressions. */
+ contains only arithmetic expressions or a CALL_EXPR with a
+ PLACEHOLDER_EXPR occurring only in its arglist. */
tree
substitute_in_expr (exp, f, r)
@@ -2203,7 +2650,8 @@ substitute_in_expr (exp, f, r)
tree r;
{
enum tree_code code = TREE_CODE (exp);
- tree new = 0;
+ tree op0, op1, op2;
+ tree new;
tree inner;
switch (TREE_CODE_CLASS (code))
@@ -2215,7 +2663,18 @@ substitute_in_expr (exp, f, r)
case 'x':
if (code == PLACEHOLDER_EXPR)
return exp;
- break;
+ else if (code == TREE_LIST)
+ {
+ op0 = (TREE_CHAIN (exp) == 0
+ ? 0 : substitute_in_expr (TREE_CHAIN (exp), f, r));
+ op1 = substitute_in_expr (TREE_VALUE (exp), f, r);
+ if (op0 == TREE_CHAIN (exp) && op1 == TREE_VALUE (exp))
+ return exp;
+
+ return tree_cons (TREE_PURPOSE (exp), op1, op0);
+ }
+
+ abort ();
case '1':
case '2':
@@ -2224,9 +2683,11 @@ substitute_in_expr (exp, f, r)
switch (tree_code_length[(int) code])
{
case 1:
- new = fold (build1 (code, TREE_TYPE (exp),
- substitute_in_expr (TREE_OPERAND (exp, 0),
- f, r)));
+ op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+ if (op0 == TREE_OPERAND (exp, 0))
+ return exp;
+
+ new = fold (build1 (code, TREE_TYPE (exp), op0));
break;
case 2:
@@ -2237,10 +2698,12 @@ substitute_in_expr (exp, f, r)
else if (code == CONSTRUCTOR)
abort ();
- new = fold (build (code, TREE_TYPE (exp),
- substitute_in_expr (TREE_OPERAND (exp, 0), f, r),
- substitute_in_expr (TREE_OPERAND (exp, 1),
- f, r)));
+ op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+ op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r);
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
+ return exp;
+
+ new = fold (build (code, TREE_TYPE (exp), op0, op1));
break;
case 3:
@@ -2249,14 +2712,31 @@ substitute_in_expr (exp, f, r)
if (code == SAVE_EXPR)
return exp;
- if (code != COND_EXPR)
+ else if (code == CALL_EXPR)
+ {
+ op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r);
+ if (op1 == TREE_OPERAND (exp, 1))
+ return exp;
+
+ return build (code, TREE_TYPE (exp),
+ TREE_OPERAND (exp, 0), op1, NULL_TREE);
+ }
+
+ else if (code != COND_EXPR)
abort ();
- new = fold (build (code, TREE_TYPE (exp),
- substitute_in_expr (TREE_OPERAND (exp, 0), f, r),
- substitute_in_expr (TREE_OPERAND (exp, 1), f, r),
- substitute_in_expr (TREE_OPERAND (exp, 2),
- f, r)));
+ op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+ op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r);
+ op2 = substitute_in_expr (TREE_OPERAND (exp, 2), f, r);
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
+ && op2 == TREE_OPERAND (exp, 2))
+ return exp;
+
+ new = fold (build (code, TREE_TYPE (exp), op0, op1, op2));
+ break;
+
+ default:
+ abort ();
}
break;
@@ -2275,181 +2755,53 @@ substitute_in_expr (exp, f, r)
&& TREE_OPERAND (exp, 1) == f)
return r;
- new = fold (build (code, TREE_TYPE (exp),
- substitute_in_expr (TREE_OPERAND (exp, 0), f, r),
+ /* If this expression hasn't been completed let, leave it
+ alone. */
+ if (TREE_CODE (inner) == PLACEHOLDER_EXPR
+ && TREE_TYPE (inner) == 0)
+ return exp;
+
+ op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+ if (op0 == TREE_OPERAND (exp, 0))
+ return exp;
+
+ new = fold (build (code, TREE_TYPE (exp), op0,
TREE_OPERAND (exp, 1)));
break;
case BIT_FIELD_REF:
- new = fold (build (code, TREE_TYPE (exp),
- substitute_in_expr (TREE_OPERAND (exp, 0), f, r),
- substitute_in_expr (TREE_OPERAND (exp, 1), f, r),
- substitute_in_expr (TREE_OPERAND (exp, 2), f, r)));
+ op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+ op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r);
+ op2 = substitute_in_expr (TREE_OPERAND (exp, 2), f, r);
+ if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
+ && op2 == TREE_OPERAND (exp, 2))
+ return exp;
+
+ new = fold (build (code, TREE_TYPE (exp), op0, op1, op2));
break;
case INDIRECT_REF:
case BUFFER_REF:
- new = fold (build1 (code, TREE_TYPE (exp),
- substitute_in_expr (TREE_OPERAND (exp, 0),
- f, r)));
- break;
+ op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+ if (op0 == TREE_OPERAND (exp, 0))
+ return exp;
- case OFFSET_REF:
- new = fold (build (code, TREE_TYPE (exp),
- substitute_in_expr (TREE_OPERAND (exp, 0), f, r),
- substitute_in_expr (TREE_OPERAND (exp, 1), f, r)));
+ new = fold (build1 (code, TREE_TYPE (exp), op0));
break;
+
+ default:
+ abort ();
}
+ break;
+
+ default:
+ abort ();
}
- /* If it wasn't one of the cases we handle, give up. */
- if (new == 0)
- abort ();
-
TREE_READONLY (new) = TREE_READONLY (exp);
return new;
}
-/* Given a type T, a FIELD_DECL F, and a replacement value R,
- return a new type with all size expressions that contain F
- updated by replacing F with R. */
-
-tree
-substitute_in_type (t, f, r)
- tree t, f, r;
-{
- switch (TREE_CODE (t))
- {
- case POINTER_TYPE:
- case VOID_TYPE:
- return t;
- case INTEGER_TYPE:
- case ENUMERAL_TYPE:
- case BOOLEAN_TYPE:
- case CHAR_TYPE:
- if ((TREE_CODE (TYPE_MIN_VALUE (t)) != INTEGER_CST
- && contains_placeholder_p (TYPE_MIN_VALUE (t)))
- || (TREE_CODE (TYPE_MAX_VALUE (t)) != INTEGER_CST
- && contains_placeholder_p (TYPE_MAX_VALUE (t))))
- return build_range_type (t,
- substitute_in_expr (TYPE_MIN_VALUE (t), f, r),
- substitute_in_expr (TYPE_MAX_VALUE (t), f, r));
- return t;
-
- case REAL_TYPE:
- if ((TYPE_MIN_VALUE (t) != 0
- && TREE_CODE (TYPE_MIN_VALUE (t)) != REAL_CST
- && contains_placeholder_p (TYPE_MIN_VALUE (t)))
- || (TYPE_MAX_VALUE (t) != 0
- && TREE_CODE (TYPE_MAX_VALUE (t)) != REAL_CST
- && contains_placeholder_p (TYPE_MAX_VALUE (t))))
- {
- t = build_type_copy (t);
-
- if (TYPE_MIN_VALUE (t))
- TYPE_MIN_VALUE (t) = substitute_in_expr (TYPE_MIN_VALUE (t), f, r);
- if (TYPE_MAX_VALUE (t))
- TYPE_MAX_VALUE (t) = substitute_in_expr (TYPE_MAX_VALUE (t), f, r);
- }
- return t;
-
- case COMPLEX_TYPE:
- return build_complex_type (substitute_in_type (TREE_TYPE (t), f, r));
-
- case OFFSET_TYPE:
- case METHOD_TYPE:
- case REFERENCE_TYPE:
- case FILE_TYPE:
- case SET_TYPE:
- case FUNCTION_TYPE:
- case LANG_TYPE:
- /* Don't know how to do these yet. */
- abort ();
-
- case ARRAY_TYPE:
- t = build_array_type (substitute_in_type (TREE_TYPE (t), f, r),
- substitute_in_type (TYPE_DOMAIN (t), f, r));
- TYPE_SIZE (t) = 0;
- layout_type (t);
- return t;
-
- case RECORD_TYPE:
- case UNION_TYPE:
- case QUAL_UNION_TYPE:
- {
- tree new = copy_node (t);
- tree field;
- tree last_field = 0;
-
- /* Start out with no fields, make new fields, and chain them
- in. */
-
- TYPE_FIELDS (new) = 0;
- TYPE_SIZE (new) = 0;
-
- for (field = TYPE_FIELDS (t); field;
- field = TREE_CHAIN (field))
- {
- tree new_field = copy_node (field);
-
- TREE_TYPE (new_field)
- = substitute_in_type (TREE_TYPE (new_field), f, r);
-
- /* If this is an anonymous field and the type of this field is
- a UNION_TYPE or RECORD_TYPE with no elements, ignore it. If
- the type just has one element, treat that as the field.
- But don't do this if we are processing a QUAL_UNION_TYPE. */
- if (TREE_CODE (t) != QUAL_UNION_TYPE && DECL_NAME (new_field) == 0
- && (TREE_CODE (TREE_TYPE (new_field)) == UNION_TYPE
- || TREE_CODE (TREE_TYPE (new_field)) == RECORD_TYPE))
- {
- if (TYPE_FIELDS (TREE_TYPE (new_field)) == 0)
- continue;
-
- if (TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (new_field))) == 0)
- new_field = TYPE_FIELDS (TREE_TYPE (new_field));
- }
-
- DECL_CONTEXT (new_field) = new;
- DECL_SIZE (new_field) = 0;
-
- if (TREE_CODE (t) == QUAL_UNION_TYPE)
- {
- /* Do the substitution inside the qualifier and if we find
- that this field will not be present, omit it. */
- DECL_QUALIFIER (new_field)
- = substitute_in_expr (DECL_QUALIFIER (field), f, r);
- if (integer_zerop (DECL_QUALIFIER (new_field)))
- continue;
- }
-
- if (last_field == 0)
- TYPE_FIELDS (new) = new_field;
- else
- TREE_CHAIN (last_field) = new_field;
-
- last_field = new_field;
-
- /* If this is a qualified type and this field will always be
- present, we are done. */
- if (TREE_CODE (t) == QUAL_UNION_TYPE
- && integer_onep (DECL_QUALIFIER (new_field)))
- break;
- }
-
- /* If this used to be a qualified union type, but we now know what
- field will be present, make this a normal union. */
- if (TREE_CODE (new) == QUAL_UNION_TYPE
- && (TYPE_FIELDS (new) == 0
- || integer_onep (DECL_QUALIFIER (TYPE_FIELDS (new)))))
- TREE_SET_CODE (new, UNION_TYPE);
-
- layout_type (new);
- return new;
- }
- }
-}
-
/* Stabilize a reference so that we can use it any number of times
without causing its operands to be evaluated more than once.
Returns the stabilized reference. This works by means of save_expr,
@@ -2508,10 +2860,10 @@ stabilize_reference (ref)
break;
case COMPOUND_EXPR:
- result = build_nt (COMPOUND_EXPR,
- stabilize_reference_1 (TREE_OPERAND (ref, 0)),
- stabilize_reference (TREE_OPERAND (ref, 1)));
- break;
+ /* We cannot wrap the first expression in a SAVE_EXPR, as then
+ it wouldn't be ignored. This matters when dealing with
+ volatiles. */
+ return stabilize_reference_1 (ref);
case RTL_EXPR:
result = build1 (INDIRECT_REF, TREE_TYPE (ref),
@@ -2699,15 +3051,18 @@ build VPROTO((enum tree_code code, tree tt, ...))
/* Same as above, but only builds for unary operators.
Saves lions share of calls to `build'; cuts down use
of varargs, which is expensive for RISC machines. */
+
tree
build1 (code, type, node)
enum tree_code code;
tree type;
tree node;
{
- register struct obstack *obstack = current_obstack;
+ register struct obstack *obstack = expression_obstack;
register int i, length;
+#ifdef GATHER_STATISTICS
register tree_node_kind kind;
+#endif
register tree t;
#ifdef GATHER_STATISTICS
@@ -2717,7 +3072,6 @@ build1 (code, type, node)
kind = e_kind;
#endif
- obstack = expression_obstack;
length = sizeof (struct tree_exp);
t = (tree) obstack_alloc (obstack, length);
@@ -2876,9 +3230,40 @@ build_block (vars, tags, subblocks, supercontext, chain)
BLOCK_CHAIN (block) = chain;
return block;
}
+
+/* EXPR_WITH_FILE_LOCATION are used to keep track of the exact
+ location where an expression or an identifier were encountered. It
+ is necessary for languages where the frontend parser will handle
+ recursively more than one file (Java is one of them). */
+
+tree
+build_expr_wfl (node, file, line, col)
+ tree node;
+ char *file;
+ int line, col;
+{
+ static char *last_file = 0;
+ static tree last_filenode = NULL_TREE;
+ register tree wfl = make_node (EXPR_WITH_FILE_LOCATION);
+
+ EXPR_WFL_NODE (wfl) = node;
+ EXPR_WFL_SET_LINECOL (wfl, line, col);
+ if (file != last_file)
+ {
+ last_file = file;
+ last_filenode = file ? get_identifier (file) : NULL_TREE;
+ }
+ EXPR_WFL_FILENAME_NODE (wfl) = last_filenode;
+ if (node)
+ {
+ TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node);
+ TREE_TYPE (wfl) = TREE_TYPE (node);
+ }
+ return wfl;
+}
/* Return a declaration like DDECL except that its DECL_MACHINE_ATTRIBUTE
- is ATTRIBUTE. */
+ is ATTRIBUTE. */
tree
build_decl_attribute_variant (ddecl, attribute)
@@ -2924,18 +3309,20 @@ build_type_attribute_variant (ttype, attribute)
switch (TREE_CODE (ntype))
{
- case FUNCTION_TYPE:
- hashcode += TYPE_HASH (TYPE_ARG_TYPES (ntype));
- break;
- case ARRAY_TYPE:
- hashcode += TYPE_HASH (TYPE_DOMAIN (ntype));
- break;
- case INTEGER_TYPE:
- hashcode += TYPE_HASH (TYPE_MAX_VALUE (ntype));
- break;
- case REAL_TYPE:
- hashcode += TYPE_HASH (TYPE_PRECISION (ntype));
- break;
+ case FUNCTION_TYPE:
+ hashcode += TYPE_HASH (TYPE_ARG_TYPES (ntype));
+ break;
+ case ARRAY_TYPE:
+ hashcode += TYPE_HASH (TYPE_DOMAIN (ntype));
+ break;
+ case INTEGER_TYPE:
+ hashcode += TYPE_HASH (TYPE_MAX_VALUE (ntype));
+ break;
+ case REAL_TYPE:
+ hashcode += TYPE_HASH (TYPE_PRECISION (ntype));
+ break;
+ default:
+ break;
}
ntype = type_hash_canon (hashcode, ntype);
@@ -2948,7 +3335,7 @@ build_type_attribute_variant (ttype, attribute)
/* Return a 1 if ATTR_NAME and ATTR_ARGS is valid for either declaration DECL
or type TYPE and 0 otherwise. Validity is determined the configuration
- macros VALID_MACHINE_DECL_ATTRIBUTE and VALID_MACHINE_TYPE_ATTRIBUTE. */
+ macros VALID_MACHINE_DECL_ATTRIBUTE and VALID_MACHINE_TYPE_ATTRIBUTE. */
int
valid_machine_attribute (attr_name, attr_args, decl, type)
@@ -2957,8 +3344,12 @@ valid_machine_attribute (attr_name, attr_args, decl, type)
tree type;
{
int valid = 0;
+#ifdef VALID_MACHINE_DECL_ATTRIBUTE
tree decl_attr_list = decl != 0 ? DECL_MACHINE_ATTRIBUTES (decl) : 0;
+#endif
+#ifdef VALID_MACHINE_TYPE_ATTRIBUTE
tree type_attr_list = TYPE_ATTRIBUTES (type);
+#endif
if (TREE_CODE (attr_name) != IDENTIFIER_NODE)
abort ();
@@ -3002,8 +3393,14 @@ valid_machine_attribute (attr_name, attr_args, decl, type)
}
else
{
+ /* If this is part of a declaration, create a type variant,
+ otherwise, this is part of a type definition, so add it
+ to the base type. */
type_attr_list = tree_cons (attr_name, attr_args, type_attr_list);
- type = build_type_attribute_variant (type, type_attr_list);
+ if (decl != 0)
+ type = build_type_attribute_variant (type, type_attr_list);
+ else
+ TYPE_ATTRIBUTES (type) = type_attr_list;
}
if (decl != 0)
TREE_TYPE (decl) = type;
@@ -3012,7 +3409,7 @@ valid_machine_attribute (attr_name, attr_args, decl, type)
/* Handle putting a type attribute on pointer-to-function-type by putting
the attribute on the function type. */
- else if (TREE_CODE (type) == POINTER_TYPE
+ else if (POINTER_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
&& VALID_MACHINE_TYPE_ATTRIBUTE (TREE_TYPE (type), type_attr_list,
attr_name, attr_args))
@@ -3111,6 +3508,76 @@ lookup_attribute (attr_name, list)
return NULL_TREE;
}
+
+/* Return an attribute list that is the union of a1 and a2. */
+
+tree
+merge_attributes (a1, a2)
+ register tree a1, a2;
+{
+ tree attributes;
+
+ /* Either one unset? Take the set one. */
+
+ if (! (attributes = a1))
+ attributes = a2;
+
+ /* One that completely contains the other? Take it. */
+
+ else if (a2 && ! attribute_list_contained (a1, a2))
+ {
+ if (attribute_list_contained (a2, a1))
+ attributes = a2;
+ else
+ {
+ /* Pick the longest list, and hang on the other list. */
+ /* ??? For the moment we punt on the issue of attrs with args. */
+
+ if (list_length (a1) < list_length (a2))
+ attributes = a2, a2 = a1;
+
+ for (; a2; a2 = TREE_CHAIN (a2))
+ if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
+ attributes) == NULL_TREE)
+ {
+ a1 = copy_node (a2);
+ TREE_CHAIN (a1) = attributes;
+ attributes = a1;
+ }
+ }
+ }
+ return attributes;
+}
+
+/* Given types T1 and T2, merge their attributes and return
+ the result. */
+
+tree
+merge_machine_type_attributes (t1, t2)
+ tree t1, t2;
+{
+#ifdef MERGE_MACHINE_TYPE_ATTRIBUTES
+ return MERGE_MACHINE_TYPE_ATTRIBUTES (t1, t2);
+#else
+ return merge_attributes (TYPE_ATTRIBUTES (t1),
+ TYPE_ATTRIBUTES (t2));
+#endif
+}
+
+/* Given decls OLDDECL and NEWDECL, merge their attributes and return
+ the result. */
+
+tree
+merge_machine_decl_attributes (olddecl, newdecl)
+ tree olddecl, newdecl;
+{
+#ifdef MERGE_MACHINE_DECL_ATTRIBUTES
+ return MERGE_MACHINE_DECL_ATTRIBUTES (olddecl, newdecl);
+#else
+ return merge_attributes (DECL_MACHINE_ATTRIBUTES (olddecl),
+ DECL_MACHINE_ATTRIBUTES (newdecl));
+#endif
+}
/* Return a type like TYPE except that its TYPE_READONLY is CONSTP
and its TYPE_VOLATILE is VOLATILEP.
@@ -3140,7 +3607,7 @@ build_type_variant (type, constp, volatilep)
like the one we need to have. If so, use that existing one. We must
preserve the TYPE_NAME, since there is code that depends on this. */
- for (t = TYPE_MAIN_VARIANT(type); t; t = TYPE_NEXT_VARIANT (t))
+ for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
if (constp == TYPE_READONLY (t) && volatilep == TYPE_VOLATILE (t)
&& TYPE_NAME (t) == TYPE_NAME (type))
return t;
@@ -3154,34 +3621,6 @@ build_type_variant (type, constp, volatilep)
return t;
}
-/* Give TYPE a new main variant: NEW_MAIN.
- This is the right thing to do only when something else
- about TYPE is modified in place. */
-
-void
-change_main_variant (type, new_main)
- tree type, new_main;
-{
- tree t;
- tree omain = TYPE_MAIN_VARIANT (type);
-
- /* Remove TYPE from the TYPE_NEXT_VARIANT chain of its main variant. */
- if (TYPE_NEXT_VARIANT (omain) == type)
- TYPE_NEXT_VARIANT (omain) = TYPE_NEXT_VARIANT (type);
- else
- for (t = TYPE_NEXT_VARIANT (omain); t && TYPE_NEXT_VARIANT (t);
- t = TYPE_NEXT_VARIANT (t))
- if (TYPE_NEXT_VARIANT (t) == type)
- {
- TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (type);
- break;
- }
-
- TYPE_MAIN_VARIANT (type) = new_main;
- TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (new_main);
- TYPE_NEXT_VARIANT (new_main) = type;
-}
-
/* Create a new variant of TYPE, equivalent but distinct.
This is so the caller can modify it. */
@@ -3539,7 +3978,7 @@ simple_cst_equal (t1, t2)
&& TREE_INT_CST_HIGH (t1) == TREE_INT_CST_HIGH (t2);
case REAL_CST:
- return REAL_VALUES_EQUAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
+ return REAL_VALUES_IDENTICAL (TREE_REAL_CST (t1), TREE_REAL_CST (t2));
case STRING_CST:
return TREE_STRING_LENGTH (t1) == TREE_STRING_LENGTH (t2)
@@ -3547,7 +3986,10 @@ simple_cst_equal (t1, t2)
TREE_STRING_LENGTH (t1));
case CONSTRUCTOR:
- abort ();
+ if (CONSTRUCTOR_ELTS (t1) == CONSTRUCTOR_ELTS (t2))
+ return 1;
+ else
+ abort ();
case SAVE_EXPR:
return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
@@ -3592,14 +4034,16 @@ simple_cst_equal (t1, t2)
case CONST_DECL:
case FUNCTION_DECL:
return 0;
+
+ default:
+ break;
}
/* This general rule works for most tree codes. All exceptions should be
handled above. If this is a language-specific tree code, we can't
trust what might be in the operand, so say we don't know
the situation. */
- if ((int) code1
- >= sizeof standard_tree_code_type / sizeof standard_tree_code_type[0])
+ if ((int) code1 >= (int) LAST_AND_UNUSED_TREE_CODE)
return -1;
switch (TREE_CODE_CLASS (code1))
@@ -3619,9 +4063,10 @@ simple_cst_equal (t1, t2)
return cmp;
}
return cmp;
- }
- return -1;
+ default:
+ return -1;
+ }
}
/* Constructors for pointer, array and function types.
@@ -3662,19 +4107,29 @@ build_pointer_type (to_type)
/* Create a type of integers to be the TYPE_DOMAIN of an ARRAY_TYPE.
MAXVAL should be the maximum value in the domain
- (one less than the length of the array). */
+ (one less than the length of the array).
+
+ The maximum value that MAXVAL can have is INT_MAX for a HOST_WIDE_INT.
+ We don't enforce this limit, that is up to caller (e.g. language front end).
+ The limit exists because the result is a signed type and we don't handle
+ sizes that use more than one HOST_WIDE_INT. */
tree
build_index_type (maxval)
tree maxval;
{
register tree itype = make_node (INTEGER_TYPE);
+
TYPE_PRECISION (itype) = TYPE_PRECISION (sizetype);
- TYPE_MIN_VALUE (itype) = build_int_2 (0, 0);
- TREE_TYPE (TYPE_MIN_VALUE (itype)) = sizetype;
+ TYPE_MIN_VALUE (itype) = size_zero_node;
+
+ push_obstacks (TYPE_OBSTACK (itype), TYPE_OBSTACK (itype));
TYPE_MAX_VALUE (itype) = convert (sizetype, maxval);
+ pop_obstacks ();
+
TYPE_MODE (itype) = TYPE_MODE (sizetype);
TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
+ TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
if (TREE_CODE (maxval) == INTEGER_CST)
{
@@ -3695,28 +4150,40 @@ build_index_type (maxval)
/* Create a range of some discrete type TYPE (an INTEGER_TYPE,
ENUMERAL_TYPE, BOOLEAN_TYPE, or CHAR_TYPE), with
low bound LOWVAL and high bound HIGHVAL.
- if TYPE==NULL_TREE, sizetype is used. */
+ if TYPE==NULL_TREE, sizetype is used. */
tree
build_range_type (type, lowval, highval)
tree type, lowval, highval;
{
register tree itype = make_node (INTEGER_TYPE);
+
TREE_TYPE (itype) = type;
if (type == NULL_TREE)
type = sizetype;
- TYPE_PRECISION (itype) = TYPE_PRECISION (type);
+
+ push_obstacks (TYPE_OBSTACK (itype), TYPE_OBSTACK (itype));
TYPE_MIN_VALUE (itype) = convert (type, lowval);
- TYPE_MAX_VALUE (itype) = convert (type, highval);
+ TYPE_MAX_VALUE (itype) = highval ? convert (type, highval) : NULL;
+ pop_obstacks ();
+
+ TYPE_PRECISION (itype) = TYPE_PRECISION (type);
TYPE_MODE (itype) = TYPE_MODE (type);
TYPE_SIZE (itype) = TYPE_SIZE (type);
+ TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (type);
TYPE_ALIGN (itype) = TYPE_ALIGN (type);
- if ((TREE_CODE (lowval) == INTEGER_CST)
- && (TREE_CODE (highval) == INTEGER_CST))
+ if (TREE_CODE (lowval) == INTEGER_CST)
{
- HOST_WIDE_INT highint = TREE_INT_CST_LOW (highval);
- HOST_WIDE_INT lowint = TREE_INT_CST_LOW (lowval);
- int maxint = (int) (highint - lowint);
+ HOST_WIDE_INT lowint, highint;
+ int maxint;
+
+ lowint = TREE_INT_CST_LOW (lowval);
+ if (highval && TREE_CODE (highval) == INTEGER_CST)
+ highint = TREE_INT_CST_LOW (highval);
+ else
+ highint = (~(unsigned HOST_WIDE_INT)0) >> 1;
+
+ maxint = (int) (highint - lowint);
return type_hash_canon (maxint < 0 ? ~maxint : maxint, itype);
}
else
@@ -3724,7 +4191,7 @@ build_range_type (type, lowval, highval)
}
/* Just like build_index_type, but takes lowval and highval instead
- of just highval (maxval). */
+ of just highval (maxval). */
tree
build_index_2_type (lowval,highval)
@@ -3795,20 +4262,26 @@ build_array_type (elt_type, index_type)
hashcode = TYPE_HASH (elt_type) + TYPE_HASH (index_type);
t = type_hash_canon (hashcode, t);
-#if 0 /* This led to crashes, because it could put a temporary node
- on the TYPE_NEXT_VARIANT chain of a permanent one. */
- /* The main variant of an array type should always
- be an array whose element type is the main variant. */
- if (elt_type != TYPE_MAIN_VARIANT (elt_type))
- change_main_variant (t, build_array_type (TYPE_MAIN_VARIANT (elt_type),
- index_type));
-#endif
-
if (TYPE_SIZE (t) == 0)
layout_type (t);
return t;
}
+/* Return the TYPE of the elements comprising
+ the innermost dimension of ARRAY. */
+
+tree
+get_inner_array_type (array)
+ tree array;
+{
+ tree type = TREE_TYPE (array);
+
+ while (TREE_CODE (type) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+
+ return type;
+}
+
/* Construct, lay out and return
the type of functions returning type VALUE_TYPE
given arguments of types ARG_TYPES.
@@ -3850,22 +4323,17 @@ build_reference_type (to_type)
tree to_type;
{
register tree t = TYPE_REFERENCE_TO (to_type);
- register struct obstack *ambient_obstack = current_obstack;
- register struct obstack *ambient_saveable_obstack = saveable_obstack;
/* First, if we already have a type for pointers to TO_TYPE, use it. */
if (t)
return t;
- /* We need a new one. If TO_TYPE is permanent, make this permanent too. */
- if (TREE_PERMANENT (to_type))
- {
- current_obstack = &permanent_obstack;
- saveable_obstack = &permanent_obstack;
- }
-
+ /* We need a new one. Put this in the same obstack as TO_TYPE. */
+ push_obstacks (TYPE_OBSTACK (to_type), TYPE_OBSTACK (to_type));
t = make_node (REFERENCE_TYPE);
+ pop_obstacks ();
+
TREE_TYPE (t) = to_type;
/* Record this type as the pointer to TO_TYPE. */
@@ -3873,8 +4341,6 @@ build_reference_type (to_type)
layout_type (t);
- current_obstack = ambient_obstack;
- saveable_obstack = ambient_saveable_obstack;
return t;
}
@@ -3998,8 +4464,6 @@ get_unwidened (op, for_type)
tree for_type;
{
/* Set UNS initially if converting OP to FOR_TYPE is a zero-extension. */
- /* TYPE_PRECISION is safe in place of type_precision since
- pointer types are not allowed. */
register tree type = TREE_TYPE (op);
register unsigned final_prec
= TYPE_PRECISION (for_type != 0 ? for_type : type);
@@ -4050,7 +4514,9 @@ get_unwidened (op, for_type)
if (TREE_CODE (op) == COMPONENT_REF
/* Since type_for_size always gives an integer type. */
- && TREE_CODE (type) != REAL_TYPE)
+ && TREE_CODE (type) != REAL_TYPE
+ /* Don't crash if field not laid out yet. */
+ && DECL_SIZE (TREE_OPERAND (op, 1)) != 0)
{
unsigned innerprec = TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1)));
type = type_for_size (innerprec, TREE_UNSIGNED (TREE_OPERAND (op, 1)));
@@ -4163,21 +4629,6 @@ get_narrower (op, unsignedp_ptr)
return win;
}
-/* Return the precision of a type, for arithmetic purposes.
- Supports all types on which arithmetic is possible
- (including pointer types).
- It's not clear yet what will be right for complex types. */
-
-int
-type_precision (type)
- register tree type;
-{
- return ((TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE
- || TREE_CODE (type) == REAL_TYPE)
- ? TYPE_PRECISION (type) : POINTER_SIZE);
-}
-
/* Nonzero if integer constant C has a value that is permissible
for type TYPE (an INTEGER_TYPE). */
@@ -4189,12 +4640,18 @@ int_fits_type_p (c, type)
return (! (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST
&& INT_CST_LT_UNSIGNED (TYPE_MAX_VALUE (type), c))
&& ! (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
- && INT_CST_LT_UNSIGNED (c, TYPE_MIN_VALUE (type))));
+ && INT_CST_LT_UNSIGNED (c, TYPE_MIN_VALUE (type)))
+ /* Negative ints never fit unsigned types. */
+ && ! (TREE_INT_CST_HIGH (c) < 0
+ && ! TREE_UNSIGNED (TREE_TYPE (c))));
else
return (! (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST
&& INT_CST_LT (TYPE_MAX_VALUE (type), c))
&& ! (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
- && INT_CST_LT (c, TYPE_MIN_VALUE (type))));
+ && INT_CST_LT (c, TYPE_MIN_VALUE (type)))
+ /* Unsigned ints with top bit set never fit signed types. */
+ && ! (TREE_INT_CST_HIGH (c) < 0
+ && TREE_UNSIGNED (TREE_TYPE (c))));
}
/* Return the innermost context enclosing DECL that is
@@ -4216,10 +4673,9 @@ decl_function_context (decl)
while (context && TREE_CODE (context) != FUNCTION_DECL)
{
- if (TREE_CODE (context) == RECORD_TYPE
- || TREE_CODE (context) == UNION_TYPE)
- context = NULL_TREE;
- else if (TREE_CODE (context) == TYPE_DECL)
+ if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
+ context = TYPE_CONTEXT (context);
+ else if (TREE_CODE_CLASS (TREE_CODE (context)) == 'd')
context = DECL_CONTEXT (context);
else if (TREE_CODE (context) == BLOCK)
context = BLOCK_SUPERCONTEXT (context);
@@ -4259,29 +4715,65 @@ decl_type_context (decl)
return NULL_TREE;
}
+/* Print debugging information about the size of the
+ toplev_inline_obstacks. */
+
+void
+print_inline_obstack_statistics ()
+{
+ struct simple_obstack_stack *current = toplev_inline_obstacks;
+ int n_obstacks = 0;
+ int n_alloc = 0;
+ int n_chunks = 0;
+
+ for (; current; current = current->next, ++n_obstacks)
+ {
+ struct obstack *o = current->obstack;
+ struct _obstack_chunk *chunk = o->chunk;
+
+ n_alloc += o->next_free - chunk->contents;
+ chunk = chunk->prev;
+ ++n_chunks;
+ for (; chunk; chunk = chunk->prev, ++n_chunks)
+ n_alloc += chunk->limit - &chunk->contents[0];
+ }
+ fprintf (stderr, "inline obstacks: %d obstacks, %d bytes, %d chunks\n",
+ n_obstacks, n_alloc, n_chunks);
+}
+
+/* Print debugging information about the obstack O, named STR. */
+
void
print_obstack_statistics (str, o)
char *str;
struct obstack *o;
{
struct _obstack_chunk *chunk = o->chunk;
- int n_chunks = 0;
+ int n_chunks = 1;
int n_alloc = 0;
+ n_alloc += o->next_free - chunk->contents;
+ chunk = chunk->prev;
while (chunk)
{
n_chunks += 1;
n_alloc += chunk->limit - &chunk->contents[0];
chunk = chunk->prev;
}
- fprintf (stderr, "obstack %s: %d bytes, %d chunks\n",
+ fprintf (stderr, "obstack %s: %u bytes, %d chunks\n",
str, n_alloc, n_chunks);
}
+
+/* Print debugging information about tree nodes generated during the compile,
+ and any language-specific information. */
+
void
dump_tree_statistics ()
{
+#ifdef GATHER_STATISTICS
int i;
int total_nodes, total_bytes;
+#endif
fprintf (stderr, "\n??? tree nodes created\n\n");
#ifdef GATHER_STATISTICS
@@ -4302,47 +4794,116 @@ dump_tree_statistics ()
#else
fprintf (stderr, "(No per-node statistics)\n");
#endif
+ print_obstack_statistics ("permanent_obstack", &permanent_obstack);
+ print_obstack_statistics ("maybepermanent_obstack", &maybepermanent_obstack);
+ print_obstack_statistics ("temporary_obstack", &temporary_obstack);
+ print_obstack_statistics ("momentary_obstack", &momentary_obstack);
+ print_obstack_statistics ("temp_decl_obstack", &temp_decl_obstack);
+ print_inline_obstack_statistics ();
print_lang_statistics ();
}
#define FILE_FUNCTION_PREFIX_LEN 9
#ifndef NO_DOLLAR_IN_LABEL
-#define FILE_FUNCTION_FORMAT "_GLOBAL_$D$%s"
+#define FILE_FUNCTION_FORMAT "_GLOBAL_$%s$%s"
#else /* NO_DOLLAR_IN_LABEL */
#ifndef NO_DOT_IN_LABEL
-#define FILE_FUNCTION_FORMAT "_GLOBAL_.D.%s"
+#define FILE_FUNCTION_FORMAT "_GLOBAL_.%s.%s"
#else /* NO_DOT_IN_LABEL */
-#define FILE_FUNCTION_FORMAT "_GLOBAL__D_%s"
+#define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"
#endif /* NO_DOT_IN_LABEL */
#endif /* NO_DOLLAR_IN_LABEL */
extern char * first_global_object_name;
+extern char * weak_global_object_name;
-/* If KIND=='I', return a suitable global initializer (constructor) name.
- If KIND=='D', return a suitable global clean-up (destructor) name. */
+/* Appends 6 random characters to TEMPLATE to (hopefully) avoid name
+ clashes in cases where we can't reliably choose a unique name.
+
+ Derived from mkstemp.c in libiberty. */
+
+static void
+append_random_chars (template)
+ char *template;
+{
+ static const char letters[]
+ = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static unsigned HOST_WIDE_INT value;
+ unsigned HOST_WIDE_INT v;
+
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+#endif
+
+ template += strlen (template);
+
+#ifdef HAVE_GETTIMEOFDAY
+ /* Get some more or less random data. */
+ gettimeofday (&tv, NULL);
+ value += ((unsigned HOST_WIDE_INT) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
+#else
+ value += getpid ();
+#endif
+
+ v = value;
+
+ /* Fill in the random bits. */
+ template[0] = letters[v % 62];
+ v /= 62;
+ template[1] = letters[v % 62];
+ v /= 62;
+ template[2] = letters[v % 62];
+ v /= 62;
+ template[3] = letters[v % 62];
+ v /= 62;
+ template[4] = letters[v % 62];
+ v /= 62;
+ template[5] = letters[v % 62];
+
+ template[6] = '\0';
+}
+
+/* Generate a name for a function unique to this translation unit.
+ TYPE is some string to identify the purpose of this function to the
+ linker or collect2. */
tree
-get_file_function_name (kind)
- int kind;
+get_file_function_name_long (type)
+ char *type;
{
char *buf;
register char *p;
if (first_global_object_name)
p = first_global_object_name;
- else if (main_input_filename)
- p = main_input_filename;
else
- p = input_filename;
+ {
+ /* We don't have anything that we know to be unique to this translation
+ unit, so use what we do have and throw in some randomness. */
+
+ char *name = weak_global_object_name;
+ char *file = main_input_filename;
+
+ if (! name)
+ name = "";
+ if (! file)
+ file = input_filename;
- buf = (char *) alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p));
+ p = (char *) alloca (7 + strlen (name) + strlen (file));
+
+ sprintf (p, "%s%s", name, file);
+ append_random_chars (p);
+ }
+
+ buf = (char *) alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p)
+ + strlen (type));
/* Set up the name of the file-level functions we may need. */
/* Use a global object (which is already required to be unique over
the program) rather than the file name (which imposes extra
constraints). -- Raeburn@MIT.EDU, 10 Jan 1990. */
- sprintf (buf, FILE_FUNCTION_FORMAT, p);
+ sprintf (buf, FILE_FUNCTION_FORMAT, type, p);
/* Don't need to pull weird characters out of global names. */
if (p != first_global_object_name)
@@ -4357,7 +4918,7 @@ get_file_function_name (kind)
#ifndef NO_DOLLAR_IN_LABEL /* this for `$'; unlikely, but... -- kr */
|| *p == '$'
#endif
-#ifndef NO_DOT_IN_LABEL /* this for `.'; unlikely, but... */
+#ifndef NO_DOT_IN_LABEL /* this for `.'; unlikely, but... */
|| *p == '.'
#endif
|| (*p >= 'A' && *p <= 'Z')
@@ -4365,17 +4926,30 @@ get_file_function_name (kind)
*p = '_';
}
- buf[FILE_FUNCTION_PREFIX_LEN] = kind;
-
return get_identifier (buf);
}
+
+/* If KIND=='I', return a suitable global initializer (constructor) name.
+ If KIND=='D', return a suitable global clean-up (destructor) name. */
+
+tree
+get_file_function_name (kind)
+ int kind;
+{
+ char p[2];
+ p[0] = kind;
+ p[1] = 0;
+
+ return get_file_function_name_long (p);
+}
+
/* Expand (the constant part of) a SET_TYPE CONSTRUCTOR node.
The result is placed in BUFFER (which has length BIT_SIZE),
with one bit in each char ('\000' or '\001').
If the constructor is constant, NULL_TREE is returned.
- Otherwise, a TREE_LIST of the non-constant elements is emitted. */
+ Otherwise, a TREE_LIST of the non-constant elements is emitted. */
tree
get_set_constructor_bits (init, buffer, bit_size)
@@ -4397,11 +4971,11 @@ get_set_constructor_bits (init, buffer, bit_size)
if (TREE_CODE (TREE_VALUE (vals)) != INTEGER_CST
|| (TREE_PURPOSE (vals) != NULL_TREE
&& TREE_CODE (TREE_PURPOSE (vals)) != INTEGER_CST))
- non_const_bits =
- tree_cons (TREE_PURPOSE (vals), TREE_VALUE (vals), non_const_bits);
+ non_const_bits
+ = tree_cons (TREE_PURPOSE (vals), TREE_VALUE (vals), non_const_bits);
else if (TREE_PURPOSE (vals) != NULL_TREE)
{
- /* Set a range of bits to ones. */
+ /* Set a range of bits to ones. */
HOST_WIDE_INT lo_index
= TREE_INT_CST_LOW (TREE_PURPOSE (vals)) - domain_min;
HOST_WIDE_INT hi_index
@@ -4414,7 +4988,7 @@ get_set_constructor_bits (init, buffer, bit_size)
}
else
{
- /* Set a single bit to one. */
+ /* Set a single bit to one. */
HOST_WIDE_INT index
= TREE_INT_CST_LOW (TREE_VALUE (vals)) - domain_min;
if (index < 0 || index >= bit_size)
@@ -4431,7 +5005,7 @@ get_set_constructor_bits (init, buffer, bit_size)
/* Expand (the constant part of) a SET_TYPE CONSTRUCTOR node.
The result is placed in BUFFER (which is an array of bytes).
If the constructor is constant, NULL_TREE is returned.
- Otherwise, a TREE_LIST of the non-constant elements is emitted. */
+ Otherwise, a TREE_LIST of the non-constant elements is emitted. */
tree
get_set_constructor_bytes (init, buffer, wd_size)
@@ -4440,12 +5014,11 @@ get_set_constructor_bytes (init, buffer, wd_size)
int wd_size;
{
int i;
- tree vals = TREE_OPERAND (init, 1);
int set_word_size = BITS_PER_UNIT;
int bit_size = wd_size * set_word_size;
int bit_pos = 0;
unsigned char *bytep = buffer;
- char *bit_buffer = (char*)alloca(bit_size);
+ char *bit_buffer = (char *) alloca(bit_size);
tree non_const_bits = get_set_constructor_bits (init, bit_buffer, bit_size);
for (i = 0; i < wd_size; i++)
@@ -4466,3 +5039,95 @@ get_set_constructor_bytes (init, buffer, wd_size)
}
return non_const_bits;
}
+
+#ifdef ENABLE_CHECKING
+
+/* Complain if the tree code does not match the expected one.
+ NODE is the tree node in question, CODE is the expected tree code,
+ and FILE and LINE are the filename and line number, respectively,
+ of the line on which the check was done. If NONFATAL is nonzero,
+ don't abort if the reference is invalid; instead, return 0.
+ If the reference is valid, return NODE. */
+
+tree
+tree_check (node, code, file, line, nofatal)
+ tree node;
+ enum tree_code code;
+ char *file;
+ int line;
+ int nofatal;
+{
+ if (TREE_CODE (node) == code)
+ return node;
+ else if (nofatal)
+ return 0;
+ else
+ fatal ("%s:%d: Expect %s, have %s\n", file, line,
+ tree_code_name[code], tree_code_name[TREE_CODE (node)]);
+}
+
+/* Similar to above, except that we check for a class of tree
+ code, given in CL. */
+
+tree
+tree_class_check (node, cl, file, line, nofatal)
+ tree node;
+ char cl;
+ char *file;
+ int line;
+ int nofatal;
+{
+ if (TREE_CODE_CLASS (TREE_CODE (node)) == cl)
+ return node;
+ else if (nofatal)
+ return 0;
+ else
+ fatal ("%s:%d: Expect '%c', have '%s'\n", file, line,
+ cl, tree_code_name[TREE_CODE (node)]);
+}
+
+/* Likewise, but complain if the tree node is not an expression. */
+
+tree
+expr_check (node, ignored, file, line, nofatal)
+ tree node;
+ int ignored;
+ char *file;
+ int line;
+ int nofatal;
+{
+ switch (TREE_CODE_CLASS (TREE_CODE (node)))
+ {
+ case 'r':
+ case 's':
+ case 'e':
+ case '<':
+ case '1':
+ case '2':
+ break;
+
+ default:
+ if (nofatal)
+ return 0;
+ else
+ fatal ("%s:%d: Expect expression, have '%s'\n", file, line,
+ tree_code_name[TREE_CODE (node)]);
+ }
+
+ return node;
+}
+#endif
+
+/* Return the alias set for T, which may be either a type or an
+ expression. */
+
+int get_alias_set (t)
+ tree t;
+{
+ if (!flag_strict_aliasing || !lang_get_alias_set)
+ /* If we're not doing any lanaguage-specific alias analysis, just
+ assume everything aliases everything else. */
+ return 0;
+ else
+ return (*lang_get_alias_set) (t);
+}
diff --git a/contrib/gcc/tree.def b/contrib/gcc/tree.def
index 8240447..632358b 100644
--- a/contrib/gcc/tree.def
+++ b/contrib/gcc/tree.def
@@ -1,6 +1,6 @@
/* This file contains the definitions and documentation for the
tree codes used in the GNU C compiler.
- Copyright (C) 1987, 1988, 1993, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1993, 1995, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -21,17 +21,17 @@ Boston, MA 02111-1307, USA. */
/* The third argument can be:
- "x" for an exceptional code (fits no category).
- "t" for a type object code.
- "b" for a lexical block.
- "c" for codes for constants.
- "d" for codes for declarations (also serving as variable refs).
- "r" for codes for references to storage.
- "<" for codes for comparison expressions.
- "1" for codes for unary arithmetic expressions.
- "2" for codes for binary arithmetic expressions.
- "s" for codes for expressions with inherent side effects.
- "e" for codes for other kinds of expressions. */
+ 'x' for an exceptional code (fits no category).
+ 't' for a type object code.
+ 'b' for a lexical block.
+ 'c' for codes for constants.
+ 'd' for codes for declarations (also serving as variable refs).
+ 'r' for codes for references to storage.
+ '<' for codes for comparison expressions.
+ '1' for codes for unary arithmetic expressions.
+ '2' for codes for binary arithmetic expressions.
+ 's' for codes for expressions with inherent side effects.
+ 'e' for codes for other kinds of expressions. */
/* For `r', `e', `<', `1', `2', `s' and `x' nodes,
the 4th element is the number of argument slots to allocate.
@@ -42,28 +42,28 @@ Boston, MA 02111-1307, USA. */
by later parsing activities, to avoid multiple error messages
for one error.
No fields in these nodes are used except the TREE_CODE. */
-DEFTREECODE (ERROR_MARK, "error_mark", "x", 0)
+DEFTREECODE (ERROR_MARK, "error_mark", 'x', 0)
/* Used to represent a name (such as, in the DECL_NAME of a decl node).
Internally it looks like a STRING_CST node.
There is only one IDENTIFIER_NODE ever made for any particular name.
Use `get_identifier' to get it (or create it, the first time). */
-DEFTREECODE (IDENTIFIER_NODE, "identifier_node", "x", -1)
+DEFTREECODE (IDENTIFIER_NODE, "identifier_node", 'x', -1)
/* Used to hold information to identify an operator (or combination
of two operators) considered as a `noun' rather than a `verb'.
The first operand is encoded in the TREE_TYPE field. */
-DEFTREECODE (OP_IDENTIFIER, "op_identifier", "x", 2)
+DEFTREECODE (OP_IDENTIFIER, "op_identifier", 'x', 2)
/* Has the TREE_VALUE and TREE_PURPOSE fields. */
/* These nodes are made into lists by chaining through the
TREE_CHAIN field. The elements of the list live in the
TREE_VALUE fields, while TREE_PURPOSE fields are occasionally
used as well to get the effect of Lisp association lists. */
-DEFTREECODE (TREE_LIST, "tree_list", "x", 2)
+DEFTREECODE (TREE_LIST, "tree_list", 'x', 2)
/* These nodes contain an array of tree nodes. */
-DEFTREECODE (TREE_VEC, "tree_vec", "x", 2)
+DEFTREECODE (TREE_VEC, "tree_vec", 'x', 2)
/* A symbol binding block. These are arranged in a tree,
where the BLOCK_SUBBLOCKS field contains a chain of subblocks
@@ -83,7 +83,7 @@ DEFTREECODE (TREE_VEC, "tree_vec", "x", 2)
BLOCK_ABSTRACT is non-zero if the block represents an abstract
instance of a block (i.e. one which is nested within an abstract
instance of a inline function. */
-DEFTREECODE (BLOCK, "block", "b", 0)
+DEFTREECODE (BLOCK, "block", 'b', 0)
/* Each data type is represented by a tree node whose code is one of
the following: */
@@ -122,7 +122,7 @@ DEFTREECODE (BLOCK, "block", "b", 0)
ENUMERAL_TYPE, RECORD_TYPE, UNION_TYPE, and QUAL_UNION_TYPE nodes;
see below. */
-DEFTREECODE (VOID_TYPE, "void_type", "t", 0) /* The void type in C */
+DEFTREECODE (VOID_TYPE, "void_type", 't', 0) /* The void type in C */
/* Integer types in all languages, including char in C.
Also used for sub-ranges of other discrete types.
@@ -132,15 +132,15 @@ DEFTREECODE (VOID_TYPE, "void_type", "t", 0) /* The void type in C */
of this will point at the supertype (another INTEGER_TYPE,
or an ENUMERAL_TYPE, CHAR_TYPE, or BOOLEAN_TYPE).
Otherwise, the TREE_TYPE is zero. */
-DEFTREECODE (INTEGER_TYPE, "integer_type", "t", 0)
+DEFTREECODE (INTEGER_TYPE, "integer_type", 't', 0)
/* C's float and double. Different floating types are distinguished
by machine mode and by the TYPE_SIZE and the TYPE_PRECISION. */
-DEFTREECODE (REAL_TYPE, "real_type", "t", 0)
+DEFTREECODE (REAL_TYPE, "real_type", 't', 0)
/* Complex number types. The TREE_TYPE field is the data type
of the real and imaginary parts. */
-DEFTREECODE (COMPLEX_TYPE, "complex_type", "t", 0)
+DEFTREECODE (COMPLEX_TYPE, "complex_type", 't', 0)
/* C enums. The type node looks just like an INTEGER_TYPE node.
The symbols for the values of the enum type are defined by
@@ -153,39 +153,39 @@ DEFTREECODE (COMPLEX_TYPE, "complex_type", "t", 0)
fields are filled in.
RECORD_TYPE, UNION_TYPE, and QUAL_UNION_TYPE forward refs are
treated similarly. */
-DEFTREECODE (ENUMERAL_TYPE, "enumeral_type", "t", 0)
+DEFTREECODE (ENUMERAL_TYPE, "enumeral_type", 't', 0)
/* Pascal's boolean type (true or false are the only values);
no special fields needed. */
-DEFTREECODE (BOOLEAN_TYPE, "boolean_type", "t", 0)
+DEFTREECODE (BOOLEAN_TYPE, "boolean_type", 't', 0)
/* CHAR in Pascal; not used in C.
No special fields needed. */
-DEFTREECODE (CHAR_TYPE, "char_type", "t", 0)
+DEFTREECODE (CHAR_TYPE, "char_type", 't', 0)
/* All pointer-to-x types have code POINTER_TYPE.
The TREE_TYPE points to the node for the type pointed to. */
-DEFTREECODE (POINTER_TYPE, "pointer_type", "t", 0)
+DEFTREECODE (POINTER_TYPE, "pointer_type", 't', 0)
/* An offset is a pointer relative to an object.
The TREE_TYPE field is the type of the object at the offset.
The TYPE_OFFSET_BASETYPE points to the node for the type of object
that the offset is relative to. */
-DEFTREECODE (OFFSET_TYPE, "offset_type", "t", 0)
+DEFTREECODE (OFFSET_TYPE, "offset_type", 't', 0)
/* A reference is like a pointer except that it is coerced
automatically to the value it points to. Used in C++. */
-DEFTREECODE (REFERENCE_TYPE, "reference_type", "t", 0)
+DEFTREECODE (REFERENCE_TYPE, "reference_type", 't', 0)
/* METHOD_TYPE is the type of a function which takes an extra first
argument for "self", which is not present in the declared argument list.
The TREE_TYPE is the return type of the method. The TYPE_METHOD_BASETYPE
is the type of "self". TYPE_ARG_TYPES is the real argument list, which
includes the hidden argument for "self". */
-DEFTREECODE (METHOD_TYPE, "method_type", "t", 0)
+DEFTREECODE (METHOD_TYPE, "method_type", 't', 0)
/* Used for Pascal; details not determined right now. */
-DEFTREECODE (FILE_TYPE, "file_type", "t", 0)
+DEFTREECODE (FILE_TYPE, "file_type", 't', 0)
/* Types of arrays. Special fields:
TREE_TYPE Type of an array element.
@@ -198,33 +198,35 @@ DEFTREECODE (FILE_TYPE, "file_type", "t", 0)
TYPE_STRING_FLAG indicates a string (in contrast to an array of chars)
in languages (such as Chill) that make a distinction. */
/* Array types in C or Pascal */
-DEFTREECODE (ARRAY_TYPE, "array_type", "t", 0)
+DEFTREECODE (ARRAY_TYPE, "array_type", 't', 0)
/* Types of sets for Pascal. Special fields are the same as
in an array type. The target type is always a boolean type.
Used for both bitstrings and powersets in Chill;
TYPE_STRING_FLAG indicates a bitstring. */
-DEFTREECODE (SET_TYPE, "set_type", "t", 0)
+DEFTREECODE (SET_TYPE, "set_type", 't', 0)
/* Struct in C, or record in Pascal. */
/* Special fields:
- TYPE_FIELDS chain of FIELD_DECLs for the fields of the struct.
+ TYPE_FIELDS chain of FIELD_DECLs for the fields of the struct,
+ and VAR_DECLs, TYPE_DECLs and CONST_DECLs for record-scope variables,
+ types and enumerators.
A few may need to be added for Pascal. */
/* See the comment above, before ENUMERAL_TYPE, for how
forward references to struct tags are handled in C. */
-DEFTREECODE (RECORD_TYPE, "record_type", "t", 0)
+DEFTREECODE (RECORD_TYPE, "record_type", 't', 0)
/* Union in C. Like a struct, except that the offsets of the fields
will all be zero. */
/* See the comment above, before ENUMERAL_TYPE, for how
forward references to union tags are handled in C. */
-DEFTREECODE (UNION_TYPE, "union_type", "t", 0) /* C union type */
+DEFTREECODE (UNION_TYPE, "union_type", 't', 0) /* C union type */
/* Similar to UNION_TYPE, except that the expressions in DECL_QUALIFIER
in each FIELD_DECL determine what the union contains. The first
field whose DECL_QUALIFIER expression is true is deemed to occupy
the union. */
-DEFTREECODE (QUAL_UNION_TYPE, "qual_union_type", "t", 0)
+DEFTREECODE (QUAL_UNION_TYPE, "qual_union_type", 't', 0)
/* Type of functions. Special fields:
TREE_TYPE type of value returned.
@@ -232,13 +234,13 @@ DEFTREECODE (QUAL_UNION_TYPE, "qual_union_type", "t", 0)
this list is made of TREE_LIST nodes.
Types of "Procedures" in languages where they are different from functions
have code FUNCTION_TYPE also, but then TREE_TYPE is zero or void type. */
-DEFTREECODE (FUNCTION_TYPE, "function_type", "t", 0)
+DEFTREECODE (FUNCTION_TYPE, "function_type", 't', 0)
/* This is a language-specific kind of type.
Its meaning is defined by the language front end.
layout_type does not know how to lay this out,
so the front-end must do so manually. */
-DEFTREECODE (LANG_TYPE, "lang_type", "t", 0)
+DEFTREECODE (LANG_TYPE, "lang_type", 't', 0)
/* Expressions */
@@ -249,19 +251,19 @@ DEFTREECODE (LANG_TYPE, "lang_type", "t", 0)
Note: constants of type char in Pascal are INTEGER_CST,
and so are pointer constants such as nil in Pascal or NULL in C.
`(int *) 1' in C also results in an INTEGER_CST. */
-DEFTREECODE (INTEGER_CST, "integer_cst", "c", 2)
+DEFTREECODE (INTEGER_CST, "integer_cst", 'c', 2)
/* Contents are in TREE_REAL_CST field. Also there is TREE_CST_RTL. */
-DEFTREECODE (REAL_CST, "real_cst", "c", 3)
+DEFTREECODE (REAL_CST, "real_cst", 'c', 3)
/* Contents are in TREE_REALPART and TREE_IMAGPART fields,
whose contents are other constant nodes.
Also there is TREE_CST_RTL. */
-DEFTREECODE (COMPLEX_CST, "complex_cst", "c", 3)
+DEFTREECODE (COMPLEX_CST, "complex_cst", 'c', 3)
/* Contents are TREE_STRING_LENGTH and TREE_STRING_POINTER fields.
Also there is TREE_CST_RTL. */
-DEFTREECODE (STRING_CST, "string_cst", "c", 3)
+DEFTREECODE (STRING_CST, "string_cst", 'c', 3)
/* Declarations. All references to names are represented as ..._DECL nodes.
The decls in one binding context are chained through the TREE_CHAIN field.
@@ -271,9 +273,9 @@ DEFTREECODE (STRING_CST, "string_cst", "c", 3)
this declaration has its scope. For FIELD_DECLs, this is the
RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE node that the field
is a member of. For VAR_DECL, PARM_DECL, FUNCTION_DECL, LABEL_DECL,
- and CONST_DECL nodes, this points to the FUNCTION_DECL for the
- containing function, or else yields NULL_TREE if the given decl
- has "file scope".
+ and CONST_DECL nodes, this points to either the FUNCTION_DECL for the
+ containing function, the RECORD_TYPE or UNION_TYPE for the containing
+ type, or NULL_TREE if the given decl has "file scope".
DECL_ABSTRACT_ORIGIN, if non-NULL, points to the original (abstract)
..._DECL node of which this decl is an (inlined or template expanded)
instance.
@@ -321,21 +323,25 @@ DEFTREECODE (STRING_CST, "string_cst", "c", 3)
of a decl (i.e. one which is nested within an abstract instance of a
inline function. */
-DEFTREECODE (FUNCTION_DECL, "function_decl", "d", 0)
-DEFTREECODE (LABEL_DECL, "label_decl", "d", 0)
-DEFTREECODE (CONST_DECL, "const_decl", "d", 0)
-DEFTREECODE (TYPE_DECL, "type_decl", "d", 0)
-DEFTREECODE (VAR_DECL, "var_decl", "d", 0)
-DEFTREECODE (PARM_DECL, "parm_decl", "d", 0)
-DEFTREECODE (RESULT_DECL, "result_decl", "d", 0)
-DEFTREECODE (FIELD_DECL, "field_decl", "d", 0)
+DEFTREECODE (FUNCTION_DECL, "function_decl", 'd', 0)
+DEFTREECODE (LABEL_DECL, "label_decl", 'd', 0)
+DEFTREECODE (CONST_DECL, "const_decl", 'd', 0)
+DEFTREECODE (TYPE_DECL, "type_decl", 'd', 0)
+DEFTREECODE (VAR_DECL, "var_decl", 'd', 0)
+DEFTREECODE (PARM_DECL, "parm_decl", 'd', 0)
+DEFTREECODE (RESULT_DECL, "result_decl", 'd', 0)
+DEFTREECODE (FIELD_DECL, "field_decl", 'd', 0)
+
+/* A namespace declaration. Namespaces appear in DECL_CONTEXT of other
+ _DECLs, providing a hierarchy of names. */
+DEFTREECODE (NAMESPACE_DECL, "namespace_decl", 'd', 0)
/* References to storage. */
/* Value is structure or union component.
Operand 0 is the structure or union (an expression);
operand 1 is the field (a node of type FIELD_DECL). */
-DEFTREECODE (COMPONENT_REF, "component_ref", "r", 2)
+DEFTREECODE (COMPONENT_REF, "component_ref", 'r', 2)
/* Reference to a group of bits within an object. Similar to COMPONENT_REF
except the position is given explicitly rather than via a FIELD_DECL.
@@ -344,59 +350,74 @@ DEFTREECODE (COMPONENT_REF, "component_ref", "r", 2)
operand 2 is a tree giving the position of the first referenced bit.
The field can be either a signed or unsigned field;
TREE_UNSIGNED says which. */
-DEFTREECODE (BIT_FIELD_REF, "bit_field_ref", "r", 3)
+DEFTREECODE (BIT_FIELD_REF, "bit_field_ref", 'r', 3)
/* C unary `*' or Pascal `^'. One operand, an expression for a pointer. */
-DEFTREECODE (INDIRECT_REF, "indirect_ref", "r", 1)
-
-/* Reference to the contents of an offset
- (a value whose type is an OFFSET_TYPE).
- Operand 0 is the object within which the offset is taken.
- Operand 1 is the offset. */
-DEFTREECODE (OFFSET_REF, "offset_ref", "r", 2)
+DEFTREECODE (INDIRECT_REF, "indirect_ref", 'r', 1)
/* Pascal `^` on a file. One operand, an expression for the file. */
-DEFTREECODE (BUFFER_REF, "buffer_ref", "r", 1)
+DEFTREECODE (BUFFER_REF, "buffer_ref", 'r', 1)
/* Array indexing in languages other than C.
Operand 0 is the array; operand 1 is a list of indices
stored as a chain of TREE_LIST nodes. */
-DEFTREECODE (ARRAY_REF, "array_ref", "r", 2)
+DEFTREECODE (ARRAY_REF, "array_ref", 'r', 2)
/* Constructor: return an aggregate value made from specified components.
In C, this is used only for structure and array initializers.
+ Also used for SET_TYPE in Chill (and potentially Pascal).
The first "operand" is really a pointer to the RTL,
for constant constructors only.
The second operand is a list of component values
- made out of a chain of TREE_LIST nodes. */
-DEFTREECODE (CONSTRUCTOR, "constructor", "e", 2)
+ made out of a chain of TREE_LIST nodes.
+
+ For ARRAY_TYPE:
+ The TREE_PURPOSE of each node is the corresponding index.
+ If the TREE_PURPOSE is a RANGE_EXPR, it is a short-hand for many nodes,
+ one for each index in the range. (If the corresponding TREE_VALUE
+ has side-effects, they are evaluated once for each element. Wrap the
+ value in a SAVE_EXPR if you want to evaluate side effects only once.)
+
+ For RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE:
+ The TREE_PURPOSE of each node is a FIELD_DECL.
-/* The expression types are mostly straightforward,
- with the fourth argument of DEFTREECODE saying
- how many operands there are.
- Unless otherwise specified, the operands are expressions. */
+ For SET_TYPE:
+ The TREE_VALUE specifies a value (index) in the set that is true.
+ If TREE_PURPOSE is non-NULL, it specifies the lower limit of a
+ range of true values. Elements not listed are false (not in the set). */
+DEFTREECODE (CONSTRUCTOR, "constructor", 'e', 2)
+
+/* The expression types are mostly straightforward, with the fourth argument
+ of DEFTREECODE saying how many operands there are.
+ Unless otherwise specified, the operands are expressions and the
+ types of all the operands and the expression must all be the same. */
/* Contains two expressions to compute, one followed by the other.
- the first value is ignored. The second one's value is used. */
-DEFTREECODE (COMPOUND_EXPR, "compound_expr", "e", 2)
+ the first value is ignored. The second one's value is used. The
+ type of the first expression need not agree with the other types. */
+DEFTREECODE (COMPOUND_EXPR, "compound_expr", 'e', 2)
/* Assignment expression. Operand 0 is the what to set; 1, the new value. */
-DEFTREECODE (MODIFY_EXPR, "modify_expr", "e", 2)
+DEFTREECODE (MODIFY_EXPR, "modify_expr", 'e', 2)
/* Initialization expression. Operand 0 is the variable to initialize;
Operand 1 is the initializer. */
-DEFTREECODE (INIT_EXPR, "init_expr", "e", 2)
+DEFTREECODE (INIT_EXPR, "init_expr", 'e', 2)
/* For TARGET_EXPR, operand 0 is the target of an initialization,
operand 1 is the initializer for the target,
- and operand 2 is the cleanup for this node, if any. */
-DEFTREECODE (TARGET_EXPR, "target_expr", "e", 3)
+ and operand 2 is the cleanup for this node, if any.
+ and operand 3 is the saved initializer after this node has been
+ expanded once, this is so we can re-expand the tree later. */
+DEFTREECODE (TARGET_EXPR, "target_expr", 'e', 4)
/* Conditional expression ( ... ? ... : ... in C).
Operand 0 is the condition.
Operand 1 is the then-value.
- Operand 2 is the else-value. */
-DEFTREECODE (COND_EXPR, "cond_expr", "e", 3)
+ Operand 2 is the else-value.
+ Operand 0 may be of any type, but the types of operands 1 and 2
+ must be the same and the same as the type of this expression. */
+DEFTREECODE (COND_EXPR, "cond_expr", 'e', 3)
/* Declare local variables, including making RTL and allocating space.
Operand 0 is a chain of VAR_DECL nodes for the variables.
@@ -419,19 +440,19 @@ DEFTREECODE (COND_EXPR, "cond_expr", "e", 3)
In order for the BIND_EXPR to be known at all, the code that creates it
must also install it as a subblock in the tree of BLOCK
nodes for the function. */
-DEFTREECODE (BIND_EXPR, "bind_expr", "e", 3)
+DEFTREECODE (BIND_EXPR, "bind_expr", 'e', 3)
/* Function call. Operand 0 is the function.
Operand 1 is the argument list, a list of expressions
made out of a chain of TREE_LIST nodes.
There is no operand 2. That slot is used for the
CALL_EXPR_RTL macro (see preexpand_calls). */
-DEFTREECODE (CALL_EXPR, "call_expr", "e", 3)
+DEFTREECODE (CALL_EXPR, "call_expr", 'e', 3)
/* Call a method. Operand 0 is the method, whose type is a METHOD_TYPE.
Operand 1 is the expression for "self".
Operand 2 is the list of explicit arguments. */
-DEFTREECODE (METHOD_CALL_EXPR, "method_call_expr", "e", 4)
+DEFTREECODE (METHOD_CALL_EXPR, "method_call_expr", 'e', 4)
/* Specify a value to compute along with its corresponding cleanup.
Operand 0 argument is an expression whose value needs a cleanup.
@@ -441,8 +462,11 @@ DEFTREECODE (METHOD_CALL_EXPR, "method_call_expr", "e", 4)
manages to act on the proper value.
The cleanup is executed by the first enclosing CLEANUP_POINT_EXPR, if
it exists, otherwise it is the responsibility of the caller to manually
- call expand_cleanups_to, as needed. */
-DEFTREECODE (WITH_CLEANUP_EXPR, "with_cleanup_expr", "e", 3)
+ call expand_start_target_temps/expand_end_target_temps, as needed.
+
+ This differs from TRY_CATCH_EXPR in that operand 2 is always
+ evaluated when an exception isn't thrown when cleanups are run. */
+DEFTREECODE (WITH_CLEANUP_EXPR, "with_cleanup_expr", 'e', 3)
/* Specify a cleanup point.
Operand 0 is an expression that may have cleanups. If it does, those
@@ -459,7 +483,7 @@ DEFTREECODE (WITH_CLEANUP_EXPR, "with_cleanup_expr", "e", 3)
As a consequence, the operand of a CLEANUP_POINT_EXPR must not have
BLKmode, because it will not be forced out of memory. */
-DEFTREECODE (CLEANUP_POINT_EXPR, "cleanup_point_expr", "e", 1)
+DEFTREECODE (CLEANUP_POINT_EXPR, "cleanup_point_expr", 'e', 1)
/* The following two codes are used in languages that have types where
the position and/or sizes of fields vary from object to object of the
@@ -499,106 +523,97 @@ DEFTREECODE (CLEANUP_POINT_EXPR, "cleanup_point_expr", "e", 1)
/* Denotes a record to later be supplied with a WITH_RECORD_EXPR when
evaluating this expression. The type of this expression is used to
find the record to replace it. */
-DEFTREECODE (PLACEHOLDER_EXPR, "placeholder_expr", "x", 0)
+DEFTREECODE (PLACEHOLDER_EXPR, "placeholder_expr", 'x', 0)
/* Provide an expression that references a record to be used in place
of a PLACEHOLDER_EXPR. The record to be used is the record within
operand 1 that has the same type as the PLACEHOLDER_EXPR in
operand 0. */
-DEFTREECODE (WITH_RECORD_EXPR, "with_record_expr", "e", 2)
+DEFTREECODE (WITH_RECORD_EXPR, "with_record_expr", 'e', 2)
-/* Simple arithmetic. Operands must have the same machine mode
- and the value shares that mode. */
-DEFTREECODE (PLUS_EXPR, "plus_expr", "2", 2)
-DEFTREECODE (MINUS_EXPR, "minus_expr", "2", 2)
-DEFTREECODE (MULT_EXPR, "mult_expr", "2", 2)
+/* Simple arithmetic. */
+DEFTREECODE (PLUS_EXPR, "plus_expr", '2', 2)
+DEFTREECODE (MINUS_EXPR, "minus_expr", '2', 2)
+DEFTREECODE (MULT_EXPR, "mult_expr", '2', 2)
/* Division for integer result that rounds the quotient toward zero. */
-/* Operands must have the same machine mode.
- In principle they may be real, but that is not currently supported.
- The result is always fixed point, and it has the same type as the
- operands if they are fixed point. */
-DEFTREECODE (TRUNC_DIV_EXPR, "trunc_div_expr", "2", 2)
+DEFTREECODE (TRUNC_DIV_EXPR, "trunc_div_expr", '2', 2)
/* Division for integer result that rounds the quotient toward infinity. */
-DEFTREECODE (CEIL_DIV_EXPR, "ceil_div_expr", "2", 2)
+DEFTREECODE (CEIL_DIV_EXPR, "ceil_div_expr", '2', 2)
/* Division for integer result that rounds toward minus infinity. */
-DEFTREECODE (FLOOR_DIV_EXPR, "floor_div_expr", "2", 2)
+DEFTREECODE (FLOOR_DIV_EXPR, "floor_div_expr", '2', 2)
/* Division for integer result that rounds toward nearest integer. */
-DEFTREECODE (ROUND_DIV_EXPR, "round_div_expr", "2", 2)
+DEFTREECODE (ROUND_DIV_EXPR, "round_div_expr", '2', 2)
/* Four kinds of remainder that go with the four kinds of division. */
-DEFTREECODE (TRUNC_MOD_EXPR, "trunc_mod_expr", "2", 2)
-DEFTREECODE (CEIL_MOD_EXPR, "ceil_mod_expr", "2", 2)
-DEFTREECODE (FLOOR_MOD_EXPR, "floor_mod_expr", "2", 2)
-DEFTREECODE (ROUND_MOD_EXPR, "round_mod_expr", "2", 2)
+DEFTREECODE (TRUNC_MOD_EXPR, "trunc_mod_expr", '2', 2)
+DEFTREECODE (CEIL_MOD_EXPR, "ceil_mod_expr", '2', 2)
+DEFTREECODE (FLOOR_MOD_EXPR, "floor_mod_expr", '2', 2)
+DEFTREECODE (ROUND_MOD_EXPR, "round_mod_expr", '2', 2)
-/* Division for real result. The two operands must have the same type.
- In principle they could be integers, but currently only real
- operands are supported. The result must have the same type
- as the operands. */
-DEFTREECODE (RDIV_EXPR, "rdiv_expr", "2", 2)
+/* Division for real result. */
+DEFTREECODE (RDIV_EXPR, "rdiv_expr", '2', 2)
/* Division which is not supposed to need rounding.
Used for pointer subtraction in C. */
-DEFTREECODE (EXACT_DIV_EXPR, "exact_div_expr", "2", 2)
+DEFTREECODE (EXACT_DIV_EXPR, "exact_div_expr", '2', 2)
/* Conversion of real to fixed point: four ways to round,
like the four ways to divide.
CONVERT_EXPR can also be used to convert a real to an integer,
and that is what is used in languages that do not have ways of
specifying which of these is wanted. Maybe these are not needed. */
-DEFTREECODE (FIX_TRUNC_EXPR, "fix_trunc_expr", "1", 1)
-DEFTREECODE (FIX_CEIL_EXPR, "fix_ceil_expr", "1", 1)
-DEFTREECODE (FIX_FLOOR_EXPR, "fix_floor_expr", "1", 1)
-DEFTREECODE (FIX_ROUND_EXPR, "fix_round_expr", "1", 1)
+DEFTREECODE (FIX_TRUNC_EXPR, "fix_trunc_expr", '1', 1)
+DEFTREECODE (FIX_CEIL_EXPR, "fix_ceil_expr", '1', 1)
+DEFTREECODE (FIX_FLOOR_EXPR, "fix_floor_expr", '1', 1)
+DEFTREECODE (FIX_ROUND_EXPR, "fix_round_expr", '1', 1)
/* Conversion of an integer to a real. */
-DEFTREECODE (FLOAT_EXPR, "float_expr", "1", 1)
+DEFTREECODE (FLOAT_EXPR, "float_expr", '1', 1)
/* Exponentiation. Operands may have any types;
constraints on value type are not known yet. */
-DEFTREECODE (EXPON_EXPR, "expon_expr", "2", 2)
+DEFTREECODE (EXPON_EXPR, "expon_expr", '2', 2)
-/* Unary negation. Value has same type as operand. */
-DEFTREECODE (NEGATE_EXPR, "negate_expr", "1", 1)
+/* Unary negation. */
+DEFTREECODE (NEGATE_EXPR, "negate_expr", '1', 1)
-DEFTREECODE (MIN_EXPR, "min_expr", "2", 2)
-DEFTREECODE (MAX_EXPR, "max_expr", "2", 2)
-DEFTREECODE (ABS_EXPR, "abs_expr", "1", 1)
-DEFTREECODE (FFS_EXPR, "ffs_expr", "1", 1)
+DEFTREECODE (MIN_EXPR, "min_expr", '2', 2)
+DEFTREECODE (MAX_EXPR, "max_expr", '2', 2)
+DEFTREECODE (ABS_EXPR, "abs_expr", '1', 1)
+DEFTREECODE (FFS_EXPR, "ffs_expr", '1', 1)
/* Shift operations for shift and rotate.
Shift is supposed to mean logical shift if done on an
unsigned type, arithmetic shift on a signed type.
The second operand is the number of bits to
- shift by, and must always have mode SImode.
- The result has the same mode as the first operand. */
-DEFTREECODE (LSHIFT_EXPR, "alshift_expr", "2", 2)
-DEFTREECODE (RSHIFT_EXPR, "arshift_expr", "2", 2)
-DEFTREECODE (LROTATE_EXPR, "lrotate_expr", "2", 2)
-DEFTREECODE (RROTATE_EXPR, "rrotate_expr", "2", 2)
+ shift by; it need not be the same type as the first operand and result. */
+DEFTREECODE (LSHIFT_EXPR, "lshift_expr", '2', 2)
+DEFTREECODE (RSHIFT_EXPR, "rshift_expr", '2', 2)
+DEFTREECODE (LROTATE_EXPR, "lrotate_expr", '2', 2)
+DEFTREECODE (RROTATE_EXPR, "rrotate_expr", '2', 2)
/* Bitwise operations. Operands have same mode as result. */
-DEFTREECODE (BIT_IOR_EXPR, "bit_ior_expr", "2", 2)
-DEFTREECODE (BIT_XOR_EXPR, "bit_xor_expr", "2", 2)
-DEFTREECODE (BIT_AND_EXPR, "bit_and_expr", "2", 2)
-DEFTREECODE (BIT_ANDTC_EXPR, "bit_andtc_expr", "2", 2)
-DEFTREECODE (BIT_NOT_EXPR, "bit_not_expr", "1", 1)
+DEFTREECODE (BIT_IOR_EXPR, "bit_ior_expr", '2', 2)
+DEFTREECODE (BIT_XOR_EXPR, "bit_xor_expr", '2', 2)
+DEFTREECODE (BIT_AND_EXPR, "bit_and_expr", '2', 2)
+DEFTREECODE (BIT_ANDTC_EXPR, "bit_andtc_expr", '2', 2)
+DEFTREECODE (BIT_NOT_EXPR, "bit_not_expr", '1', 1)
/* Combination of boolean values or of integers considered only
as zero or nonzero. ANDIF and ORIF allow the second operand
not to be computed if the value of the expression is determined
from the first operand. AND, OR, and XOR always compute the second
operand whether its value is needed or not (for side effects). */
-DEFTREECODE (TRUTH_ANDIF_EXPR, "truth_andif_expr", "e", 2)
-DEFTREECODE (TRUTH_ORIF_EXPR, "truth_orif_expr", "e", 2)
-DEFTREECODE (TRUTH_AND_EXPR, "truth_and_expr", "e", 2)
-DEFTREECODE (TRUTH_OR_EXPR, "truth_or_expr", "e", 2)
-DEFTREECODE (TRUTH_XOR_EXPR, "truth_xor_expr", "e", 2)
-DEFTREECODE (TRUTH_NOT_EXPR, "truth_not_expr", "e", 1)
+DEFTREECODE (TRUTH_ANDIF_EXPR, "truth_andif_expr", 'e', 2)
+DEFTREECODE (TRUTH_ORIF_EXPR, "truth_orif_expr", 'e', 2)
+DEFTREECODE (TRUTH_AND_EXPR, "truth_and_expr", 'e', 2)
+DEFTREECODE (TRUTH_OR_EXPR, "truth_or_expr", 'e', 2)
+DEFTREECODE (TRUTH_XOR_EXPR, "truth_xor_expr", 'e', 2)
+DEFTREECODE (TRUTH_NOT_EXPR, "truth_not_expr", 'e', 1)
/* Relational operators.
`EQ_EXPR' and `NE_EXPR' are allowed for any types.
@@ -606,73 +621,99 @@ DEFTREECODE (TRUTH_NOT_EXPR, "truth_not_expr", "e", 1)
or real types.
In all cases the operands will have the same type,
and the value is always the type used by the language for booleans. */
-DEFTREECODE (LT_EXPR, "lt_expr", "<", 2)
-DEFTREECODE (LE_EXPR, "le_expr", "<", 2)
-DEFTREECODE (GT_EXPR, "gt_expr", "<", 2)
-DEFTREECODE (GE_EXPR, "ge_expr", "<", 2)
-DEFTREECODE (EQ_EXPR, "eq_expr", "<", 2)
-DEFTREECODE (NE_EXPR, "ne_expr", "<", 2)
+DEFTREECODE (LT_EXPR, "lt_expr", '<', 2)
+DEFTREECODE (LE_EXPR, "le_expr", '<', 2)
+DEFTREECODE (GT_EXPR, "gt_expr", '<', 2)
+DEFTREECODE (GE_EXPR, "ge_expr", '<', 2)
+DEFTREECODE (EQ_EXPR, "eq_expr", '<', 2)
+DEFTREECODE (NE_EXPR, "ne_expr", '<', 2)
/* Operations for Pascal sets. Not used now. */
-DEFTREECODE (IN_EXPR, "in_expr", "2", 2)
-DEFTREECODE (SET_LE_EXPR, "set_le_expr", "<", 2)
-DEFTREECODE (CARD_EXPR, "card_expr", "1", 1)
-DEFTREECODE (RANGE_EXPR, "range_expr", "2", 2)
+DEFTREECODE (IN_EXPR, "in_expr", '2', 2)
+DEFTREECODE (SET_LE_EXPR, "set_le_expr", '<', 2)
+DEFTREECODE (CARD_EXPR, "card_expr", '1', 1)
+DEFTREECODE (RANGE_EXPR, "range_expr", '2', 2)
/* Represents a conversion of type of a value.
All conversions, including implicit ones, must be
- represented by CONVERT_EXPR nodes. */
-DEFTREECODE (CONVERT_EXPR, "convert_expr", "1", 1)
+ represented by CONVERT_EXPR or NOP_EXPR nodes. */
+DEFTREECODE (CONVERT_EXPR, "convert_expr", '1', 1)
/* Represents a conversion expected to require no code to be generated. */
-DEFTREECODE (NOP_EXPR, "nop_expr", "1", 1)
+DEFTREECODE (NOP_EXPR, "nop_expr", '1', 1)
/* Value is same as argument, but guaranteed not an lvalue. */
-DEFTREECODE (NON_LVALUE_EXPR, "non_lvalue_expr", "1", 1)
+DEFTREECODE (NON_LVALUE_EXPR, "non_lvalue_expr", '1', 1)
/* Represents something we computed once and will use multiple times.
First operand is that expression. Second is the function decl
in which the SAVE_EXPR was created. The third operand is the RTL,
nonzero only after the expression has been computed. */
-DEFTREECODE (SAVE_EXPR, "save_expr", "e", 3)
+DEFTREECODE (SAVE_EXPR, "save_expr", 'e', 3)
+
+/* For a UNSAVE_EXPR, operand 0 is the value to unsave. By unsave, we
+ mean that all _EXPRs such as TARGET_EXPRs, SAVE_EXPRs,
+ CALL_EXPRs and RTL_EXPRs, that are protected
+ from being evaluated more than once should be reset so that a new
+ expand_expr call of this expr will cause those to be re-evaluated.
+ This is useful when we want to reuse a tree in different places,
+ but where we must re-expand. */
+DEFTREECODE (UNSAVE_EXPR, "unsave_expr", 'e', 1)
/* Represents something whose RTL has already been expanded
as a sequence which should be emitted when this expression is expanded.
The first operand is the RTL to emit. It is the first of a chain of insns.
The second is the RTL expression for the result. */
-DEFTREECODE (RTL_EXPR, "rtl_expr", "e", 2)
+DEFTREECODE (RTL_EXPR, "rtl_expr", 'e', 2)
/* & in C. Value is the address at which the operand's value resides.
Operand may have any mode. Result mode is Pmode. */
-DEFTREECODE (ADDR_EXPR, "addr_expr", "e", 1)
+DEFTREECODE (ADDR_EXPR, "addr_expr", 'e', 1)
/* Non-lvalue reference or pointer to an object. */
-DEFTREECODE (REFERENCE_EXPR, "reference_expr", "e", 1)
+DEFTREECODE (REFERENCE_EXPR, "reference_expr", 'e', 1)
/* Operand is a function constant; result is a function variable value
of typeEPmode. Used only for languages that need static chains. */
-DEFTREECODE (ENTRY_VALUE_EXPR, "entry_value_expr", "e", 1)
+DEFTREECODE (ENTRY_VALUE_EXPR, "entry_value_expr", 'e', 1)
/* Given two real or integer operands of the same type,
returns a complex value of the corresponding complex type. */
-DEFTREECODE (COMPLEX_EXPR, "complex_expr", "2", 2)
+DEFTREECODE (COMPLEX_EXPR, "complex_expr", '2', 2)
-/* Complex conjugate of operand. Used only on complex types.
- The value has the same type as the operand. */
-DEFTREECODE (CONJ_EXPR, "conj_expr", "1", 1)
+/* Complex conjugate of operand. Used only on complex types. */
+DEFTREECODE (CONJ_EXPR, "conj_expr", '1', 1)
/* Used only on an operand of complex type, these return
a value of the corresponding component type. */
-DEFTREECODE (REALPART_EXPR, "realpart_expr", "1", 1)
-DEFTREECODE (IMAGPART_EXPR, "imagpart_expr", "1", 1)
+DEFTREECODE (REALPART_EXPR, "realpart_expr", '1', 1)
+DEFTREECODE (IMAGPART_EXPR, "imagpart_expr", '1', 1)
/* Nodes for ++ and -- in C.
The second arg is how much to increment or decrement by.
For a pointer, it would be the size of the object pointed to. */
-DEFTREECODE (PREDECREMENT_EXPR, "predecrement_expr", "e", 2)
-DEFTREECODE (PREINCREMENT_EXPR, "preincrement_expr", "e", 2)
-DEFTREECODE (POSTDECREMENT_EXPR, "postdecrement_expr", "e", 2)
-DEFTREECODE (POSTINCREMENT_EXPR, "postincrement_expr", "e", 2)
+DEFTREECODE (PREDECREMENT_EXPR, "predecrement_expr", 'e', 2)
+DEFTREECODE (PREINCREMENT_EXPR, "preincrement_expr", 'e', 2)
+DEFTREECODE (POSTDECREMENT_EXPR, "postdecrement_expr", 'e', 2)
+DEFTREECODE (POSTINCREMENT_EXPR, "postincrement_expr", 'e', 2)
+
+/* Evaluate operand 1. If and only if an exception is thrown during
+ the evaluation of operand 1, evaluate operand 2.
+
+ This differs from WITH_CLEANUP_EXPR, in that operand 2 is never
+ evaluated unless an exception is throw. */
+DEFTREECODE (TRY_CATCH_EXPR, "try_catch_expr", 'e', 2)
+
+/* Pop the top element off the dynamic handler chain. Used in
+ conjunction with setjmp/longjmp based exception handling, see
+ except.c for more details. This is meant to be used only by the
+ exception handling backend, expand_dhc_cleanup specifically. */
+DEFTREECODE (POPDHC_EXPR, "popdhc_expr", 's', 0)
+
+/* Pop the top element off the dynamic cleanup chain. Used in
+ conjunction with the exception handling. This is meant to be used
+ only by the exception handling backend. */
+DEFTREECODE (POPDCC_EXPR, "popdcc_expr", 's', 0)
/* These types of expressions have no useful value,
and always have side effects. */
@@ -680,31 +721,35 @@ DEFTREECODE (POSTINCREMENT_EXPR, "postincrement_expr", "e", 2)
/* A label definition, encapsulated as a statement.
Operand 0 is the LABEL_DECL node for the label that appears here.
The type should be void and the value should be ignored. */
-DEFTREECODE (LABEL_EXPR, "label_expr", "s", 1)
+DEFTREECODE (LABEL_EXPR, "label_expr", 's', 1)
/* GOTO. Operand 0 is a LABEL_DECL node.
The type should be void and the value should be ignored. */
-DEFTREECODE (GOTO_EXPR, "goto_expr", "s", 1)
+DEFTREECODE (GOTO_EXPR, "goto_expr", 's', 1)
/* RETURN. Evaluates operand 0, then returns from the current function.
Presumably that operand is an assignment that stores into the
RESULT_DECL that hold the value to be returned.
The operand may be null.
The type should be void and the value should be ignored. */
-DEFTREECODE (RETURN_EXPR, "return_expr", "s", 1)
+DEFTREECODE (RETURN_EXPR, "return_expr", 's', 1)
/* Exit the inner most loop conditionally. Operand 0 is the condition.
The type should be void and the value should be ignored. */
-DEFTREECODE (EXIT_EXPR, "exit_expr", "s", 1)
+DEFTREECODE (EXIT_EXPR, "exit_expr", 's', 1)
/* A loop. Operand 0 is the body of the loop.
It must contain an EXIT_EXPR or is an infinite loop.
The type should be void and the value should be ignored. */
-DEFTREECODE (LOOP_EXPR, "loop_expr", "s", 1)
+DEFTREECODE (LOOP_EXPR, "loop_expr", 's', 1)
+/* Used to represent a tree node, such as IDENTIFIER_NODE or an EXPR
+ node, adding several location information: a file name, a line
+ number and column number. It is expanded as the node it refers to
+ and can be considered a no-op "conversion" with an annotation. */
+DEFTREECODE (EXPR_WITH_FILE_LOCATION, "expr_with_file_location", '1', 2)
/*
Local variables:
mode:c
-version-control: t
End:
*/
diff --git a/contrib/gcc/tree.h b/contrib/gcc/tree.h
index 1c4b438..039170e 100644
--- a/contrib/gcc/tree.h
+++ b/contrib/gcc/tree.h
@@ -1,5 +1,5 @@
/* Front-end tree definitions for GNU compiler.
- Copyright (C) 1989, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1989, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -47,16 +47,23 @@ enum tree_code {
constant, `d' for a decl, `t' for a type, `s' for a statement,
and `x' for anything else (TREE_LIST, IDENTIFIER, etc). */
-extern char **tree_code_type;
-#define TREE_CODE_CLASS(CODE) (*tree_code_type[(int) (CODE)])
+#define MAX_TREE_CODES 256
+extern char tree_code_type[MAX_TREE_CODES];
+#define TREE_CODE_CLASS(CODE) tree_code_type[(int) (CODE)]
+
+/* Returns non-zero iff CLASS is the tree-code class of an
+ expression. */
+
+#define IS_EXPR_CODE_CLASS(CLASS) \
+ (CLASS == '<' || CLASS == '1' || CLASS == '2' || CLASS == 'e')
/* Number of argument-words in each kind of tree-node. */
-extern int *tree_code_length;
+extern int tree_code_length[MAX_TREE_CODES];
/* Names of tree components. */
-extern char **tree_code_name;
+extern char *tree_code_name[MAX_TREE_CODES];
/* Codes that identify the various built in functions
so that expand_call can identify them quickly. */
@@ -93,10 +100,26 @@ enum built_in_function
BUILT_IN_CONSTANT_P,
BUILT_IN_FRAME_ADDRESS,
BUILT_IN_RETURN_ADDRESS,
+ BUILT_IN_AGGREGATE_INCOMING_ADDRESS,
BUILT_IN_CALLER_RETURN_ADDRESS,
BUILT_IN_APPLY_ARGS,
BUILT_IN_APPLY,
BUILT_IN_RETURN,
+ BUILT_IN_SETJMP,
+ BUILT_IN_LONGJMP,
+ BUILT_IN_TRAP,
+
+ /* Various hooks for the DWARF 2 __throw routine. */
+ BUILT_IN_FP, BUILT_IN_SP,
+ BUILT_IN_UNWIND_INIT,
+ BUILT_IN_DWARF_FP_REGNUM,
+ BUILT_IN_DWARF_REG_SIZE,
+ BUILT_IN_FROB_RETURN_ADDR,
+ BUILT_IN_EXTRACT_RETURN_ADDR,
+ BUILT_IN_SET_RETURN_ADDR_REG,
+ BUILT_IN_EH_STUB_OLD,
+ BUILT_IN_EH_STUB,
+ BUILT_IN_SET_EH_REGS,
/* C++ extensions */
BUILT_IN_NEW,
@@ -131,7 +154,11 @@ typedef union tree_node *tree;
/* Every kind of tree node starts with this structure,
so all nodes have these fields.
- See the accessor macros, defined below, for documentation of the fields. */
+ See the accessor macros, defined below, for documentation of the fields.
+
+ DO NOT change the layout of tree_common unless absolutely necessary. Some
+ front-ends (namely g++) depend on the internal layout of this tructure.
+ See my_tree_cons in the cp subdir for such uglyness. Ugh. */
struct tree_common
{
@@ -166,9 +193,112 @@ struct tree_common
unsigned lang_flag_4 : 1;
unsigned lang_flag_5 : 1;
unsigned lang_flag_6 : 1;
- /* There is room for two more flags. */
+ /* There is room for three more flags. */
};
+/* The following table lists the uses of each of the above flags and
+ for which types of nodes they are defined. Note that expressions
+ include decls.
+
+ addressable_flag:
+
+ TREE_ADDRESSABLE in
+ VAR_DECL, FUNCTION_DECL, CONSTRUCTOR, LABEL_DECL, ..._TYPE
+ IDENTIFIER_NODE
+
+ static_flag:
+
+ TREE_STATIC in
+ VAR_DECL, FUNCTION_DECL, CONSTRUCTOR, ADDR_EXPR
+ TREE_NO_UNUSED_WARNING in
+ CONVERT_EXPR, NOP_EXPR, COMPOUND_EXPR
+ TREE_VIA_VIRTUAL in
+ TREE_LIST or TREE_VEC
+ TREE_CONSTANT_OVERFLOW in
+ INTEGER_CST, REAL_CST, COMPLEX_CST
+ TREE_SYMBOL_REFERENCED in
+ IDENTIFIER_NODE
+
+ public_flag:
+
+ TREE_OVERFLOW in
+ INTEGER_CST, REAL_CST, COMPLEX_CST
+ TREE_PUBLIC in
+ VAR_DECL or FUNCTION_DECL
+ TREE_VIA_PUBLIC in
+ TREE_LIST or TREE_VEC
+
+ private_flag:
+
+ TREE_VIA_PRIVATE in
+ TREE_LIST or TREE_VEC
+ TREE_PRIVATE in
+ ??? unspecified nodes
+
+ protected_flag:
+
+ TREE_VIA_PROTECTED in
+ TREE_LIST
+ TREE_PROTECTED in
+ BLOCK
+ ??? unspecified nodes
+
+ side_effects_flag:
+
+ TREE_SIDE_EFFECTS in
+ all expressions
+
+ volatile_flag:
+
+ TREE_THIS_VOLATILE in
+ all expressions
+ TYPE_VOLATILE in
+ ..._TYPE
+
+ readonly_flag:
+
+ TREE_READONLY in
+ all expressions
+ ITERATOR_BOUND_P in
+ VAR_DECL if iterator (C)
+ TYPE_READONLY in
+ ..._TYPE
+
+ constant_flag:
+
+ TREE_CONSTANT in
+ all expressions
+
+ permanent_flag: TREE_PERMANENT in all nodes
+
+ unsigned_flag:
+
+ TREE_UNSIGNED in
+ INTEGER_TYPE, ENUMERAL_TYPE, FIELD_DECL
+ DECL_BUILT_IN_NONANSI in
+ FUNCTION_DECL
+ TREE_PARMLIST in
+ TREE_PARMLIST (C++)
+ SAVE_EXPR_NOPLACEHOLDER in
+ SAVE_EXPR
+
+ asm_written_flag:
+
+ TREE_ASM_WRITTEN in
+ VAR_DECL, FUNCTION_DECL, RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE
+ BLOCK
+
+ used_flag:
+
+ TREE_USED in
+ expressions, IDENTIFIER_NODE
+
+ raises_flag:
+
+ TREE_RAISES in
+ expressions
+
+ */
/* Define accessors for the fields that all tree nodes have
(though some fields are not used for all kinds of nodes). */
@@ -177,6 +307,40 @@ struct tree_common
#define TREE_CODE(NODE) ((enum tree_code) (NODE)->common.code)
#define TREE_SET_CODE(NODE, VALUE) ((NODE)->common.code = (int) (VALUE))
+/* When checking is enabled, errors will be generated if a tree node
+ is accessed incorrectly. The macros abort with a fatal error,
+ except for the *1 variants, which just return 0 on failure. The
+ latter variants should only be used for combination checks, which
+ succeed when one of the checks succeed. The CHAIN_CHECK macro helps
+ defining such checks. */
+
+#ifdef ENABLE_CHECKING
+#define DO_CHECK(FUNC, t, param) FUNC (t, param, __FILE__, __LINE__, 0)
+#define DO_CHECK1(FUNC, t, param) FUNC (t, param, __FILE__, __LINE__, 1)
+#define CHAIN_CHECK(t, c1, c2) (c1 (t) ? t : c2 (t))
+#else
+#define DO_CHECK(FUNC, t, param) (t)
+#define DO_CHECK1(FUNC, t, param) (t)
+#define CHAIN_CHECK(t, c1, c2) (t)
+#endif
+
+#define TREE_CHECK(t, code) DO_CHECK (tree_check, t, code)
+#define TREE_CHECK1(t, code) DO_CHECK1 (tree_check, t, code)
+
+#include "tree-check.h"
+
+#define TYPE_CHECK(t) DO_CHECK (tree_class_check, t, 't')
+#define TYPE_CHECK1(t) DO_CHECK1 (tree_class_check, t, 't')
+#define DECL_CHECK(t) DO_CHECK (tree_class_check, t, 'd')
+#define DECL_CHECK1(t) DO_CHECK1 (tree_class_check, t, 'd')
+#define CST_CHECK(t) DO_CHECK (tree_class_check, t, 'c')
+#define CST_CHECK1(t) DO_CHECK1 (tree_class_check, t, 'c')
+#define EXPR_CHECK(t) DO_CHECK (expr_check, t, 0)
+
+/* Chained checks. The last check has to succeed, the others may fail. */
+#define CST_OR_CONSTRUCTOR_CHECK(t) \
+ CHAIN_CHECK (t, CST_CHECK1, CONSTRUCTOR_CHECK)
+
/* In all nodes that are expressions, this is the data type of the expression.
In POINTER_TYPE nodes, this is the type that the pointer points to.
In ARRAY_TYPE nodes, this is the type of the elements. */
@@ -240,6 +404,10 @@ struct tree_common
#define POINTER_TYPE_P(TYPE) \
(TREE_CODE (TYPE) == POINTER_TYPE || TREE_CODE (TYPE) == REFERENCE_TYPE)
+
+/* Nonzero if TYPE represents a type. */
+
+#define TYPE_P(TYPE) (TREE_CODE_CLASS (TREE_CODE (TYPE)) == 't')
/* Define many boolean fields that all tree nodes have. */
@@ -387,8 +555,8 @@ struct tree_common
If the data type is signed, the value is sign-extended to 2 words
even though not all of them may really be in use.
In an unsigned constant shorter than 2 words, the extra bits are 0. */
-#define TREE_INT_CST_LOW(NODE) ((NODE)->int_cst.int_cst_low)
-#define TREE_INT_CST_HIGH(NODE) ((NODE)->int_cst.int_cst_high)
+#define TREE_INT_CST_LOW(NODE) (INTEGER_CST_CHECK (NODE)->int_cst.int_cst_low)
+#define TREE_INT_CST_HIGH(NODE) (INTEGER_CST_CHECK (NODE)->int_cst.int_cst_high)
#define INT_CST_LT(A, B) \
(TREE_INT_CST_HIGH (A) < TREE_INT_CST_HIGH (B) \
@@ -407,6 +575,8 @@ struct tree_common
struct tree_int_cst
{
char common[sizeof (struct tree_common)];
+ struct rtx_def *rtl; /* acts as link to register transfer language
+ (rtl) info */
HOST_WIDE_INT int_cst_low;
HOST_WIDE_INT int_cst_high;
};
@@ -415,14 +585,14 @@ struct tree_int_cst
and generally in all kinds of constants that could
be given labels (rather than being immediate). */
-#define TREE_CST_RTL(NODE) ((NODE)->real_cst.rtl)
+#define TREE_CST_RTL(NODE) (CST_OR_CONSTRUCTOR_CHECK (NODE)->real_cst.rtl)
/* In a REAL_CST node. */
/* We can represent a real value as either a `double' or a string.
Strings don't allow for any optimization, but they do allow
for cross-compilation. */
-#define TREE_REAL_CST(NODE) ((NODE)->real_cst.real_cst)
+#define TREE_REAL_CST(NODE) (REAL_CST_CHECK (NODE)->real_cst.real_cst)
#include "real.h"
@@ -435,8 +605,8 @@ struct tree_real_cst
};
/* In a STRING_CST */
-#define TREE_STRING_LENGTH(NODE) ((NODE)->string.length)
-#define TREE_STRING_POINTER(NODE) ((NODE)->string.pointer)
+#define TREE_STRING_LENGTH(NODE) (STRING_CST_CHECK (NODE)->string.length)
+#define TREE_STRING_POINTER(NODE) (STRING_CST_CHECK (NODE)->string.pointer)
struct tree_string
{
@@ -448,8 +618,8 @@ struct tree_string
};
/* In a COMPLEX_CST node. */
-#define TREE_REALPART(NODE) ((NODE)->complex.real)
-#define TREE_IMAGPART(NODE) ((NODE)->complex.imag)
+#define TREE_REALPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.real)
+#define TREE_IMAGPART(NODE) (COMPLEX_CST_CHECK (NODE)->complex.imag)
struct tree_complex
{
@@ -462,8 +632,8 @@ struct tree_complex
/* Define fields and accessors for some special-purpose tree nodes. */
-#define IDENTIFIER_LENGTH(NODE) ((NODE)->identifier.length)
-#define IDENTIFIER_POINTER(NODE) ((NODE)->identifier.pointer)
+#define IDENTIFIER_LENGTH(NODE) (IDENTIFIER_NODE_CHECK (NODE)->identifier.length)
+#define IDENTIFIER_POINTER(NODE) (IDENTIFIER_NODE_CHECK (NODE)->identifier.pointer)
struct tree_identifier
{
@@ -473,8 +643,8 @@ struct tree_identifier
};
/* In a TREE_LIST node. */
-#define TREE_PURPOSE(NODE) ((NODE)->list.purpose)
-#define TREE_VALUE(NODE) ((NODE)->list.value)
+#define TREE_PURPOSE(NODE) (TREE_LIST_CHECK (NODE)->list.purpose)
+#define TREE_VALUE(NODE) (TREE_LIST_CHECK (NODE)->list.value)
struct tree_list
{
@@ -484,9 +654,9 @@ struct tree_list
};
/* In a TREE_VEC node. */
-#define TREE_VEC_LENGTH(NODE) ((NODE)->vec.length)
-#define TREE_VEC_ELT(NODE,I) ((NODE)->vec.a[I])
-#define TREE_VEC_END(NODE) (&((NODE)->vec.a[(NODE)->vec.length]))
+#define TREE_VEC_LENGTH(NODE) (TREE_VEC_CHECK (NODE)->vec.length)
+#define TREE_VEC_ELT(NODE,I) (TREE_VEC_CHECK (NODE)->vec.a[I])
+#define TREE_VEC_END(NODE) ((void) TREE_VEC_CHECK (NODE),&((NODE)->vec.a[(NODE)->vec.length]))
struct tree_vec
{
@@ -499,21 +669,33 @@ struct tree_vec
/* In a SAVE_EXPR node. */
#define SAVE_EXPR_CONTEXT(NODE) TREE_OPERAND(NODE, 1)
-#define SAVE_EXPR_RTL(NODE) (*(struct rtx_def **) &(NODE)->exp.operands[2])
+#define SAVE_EXPR_RTL(NODE) (*(struct rtx_def **) &EXPR_CHECK (NODE)->exp.operands[2])
+#define SAVE_EXPR_NOPLACEHOLDER(NODE) TREE_UNSIGNED (NODE)
/* In a RTL_EXPR node. */
-#define RTL_EXPR_SEQUENCE(NODE) (*(struct rtx_def **) &(NODE)->exp.operands[0])
-#define RTL_EXPR_RTL(NODE) (*(struct rtx_def **) &(NODE)->exp.operands[1])
+#define RTL_EXPR_SEQUENCE(NODE) (*(struct rtx_def **) &EXPR_CHECK (NODE)->exp.operands[0])
+#define RTL_EXPR_RTL(NODE) (*(struct rtx_def **) &EXPR_CHECK (NODE)->exp.operands[1])
/* In a CALL_EXPR node. */
-#define CALL_EXPR_RTL(NODE) (*(struct rtx_def **) &(NODE)->exp.operands[2])
+#define CALL_EXPR_RTL(NODE) (*(struct rtx_def **) &EXPR_CHECK (NODE)->exp.operands[2])
/* In a CONSTRUCTOR node. */
#define CONSTRUCTOR_ELTS(NODE) TREE_OPERAND (NODE, 1)
/* In ordinary expression nodes. */
-#define TREE_OPERAND(NODE, I) ((NODE)->exp.operands[I])
-#define TREE_COMPLEXITY(NODE) ((NODE)->exp.complexity)
+#define TREE_OPERAND(NODE, I) (EXPR_CHECK (NODE)->exp.operands[I])
+#define TREE_COMPLEXITY(NODE) (EXPR_CHECK (NODE)->exp.complexity)
+
+/* In expression with file location information. */
+#define EXPR_WFL_NODE(NODE) TREE_OPERAND((NODE), 0)
+#define EXPR_WFL_FILENAME(NODE) (IDENTIFIER_POINTER ((NODE)->common.chain))
+#define EXPR_WFL_FILENAME_NODE(NODE) ((NODE)->common.chain)
+#define EXPR_WFL_LINENO(NODE) (EXPR_CHECK (NODE)->exp.complexity >> 12)
+#define EXPR_WFL_COLNO(NODE) (EXPR_CHECK (NODE)->exp.complexity & 0xfff)
+#define EXPR_WFL_LINECOL(NODE) (EXPR_CHECK (NODE)->exp.complexity)
+#define EXPR_WFL_SET_LINECOL(NODE, LINE, COL) \
+ (EXPR_WFL_LINECOL(NODE) = ((LINE) << 12) | ((COL) & 0xfff))
+#define EXPR_WFL_EMIT_LINE_NOTE(NODE) ((NODE)->common.lang_flag_0)
struct tree_exp
{
@@ -523,20 +705,32 @@ struct tree_exp
};
/* In a BLOCK node. */
-#define BLOCK_VARS(NODE) ((NODE)->block.vars)
-#define BLOCK_TYPE_TAGS(NODE) ((NODE)->block.type_tags)
-#define BLOCK_SUBBLOCKS(NODE) ((NODE)->block.subblocks)
-#define BLOCK_SUPERCONTEXT(NODE) ((NODE)->block.supercontext)
+#define BLOCK_VARS(NODE) (BLOCK_CHECK (NODE)->block.vars)
+#define BLOCK_TYPE_TAGS(NODE) (BLOCK_CHECK (NODE)->block.type_tags)
+#define BLOCK_SUBBLOCKS(NODE) (BLOCK_CHECK (NODE)->block.subblocks)
+#define BLOCK_SUPERCONTEXT(NODE) (BLOCK_CHECK (NODE)->block.supercontext)
/* Note: when changing this, make sure to find the places
that use chainon or nreverse. */
#define BLOCK_CHAIN(NODE) TREE_CHAIN (NODE)
-#define BLOCK_ABSTRACT_ORIGIN(NODE) ((NODE)->block.abstract_origin)
-#define BLOCK_ABSTRACT(NODE) ((NODE)->block.abstract_flag)
-#define BLOCK_END_NOTE(NODE) ((NODE)->block.end_note)
+#define BLOCK_ABSTRACT_ORIGIN(NODE) (BLOCK_CHECK (NODE)->block.abstract_origin)
+#define BLOCK_ABSTRACT(NODE) (BLOCK_CHECK (NODE)->block.abstract_flag)
+#define BLOCK_END_NOTE(NODE) (BLOCK_CHECK (NODE)->block.end_note)
+/* Nonzero means that this block has separate live range regions */
+#define BLOCK_LIVE_RANGE_FLAG(NOTE) (BLOCK_CHECK (NOTE)->block.live_range_flag)
+
+/* Nonzero means that this block has a variable declared in it
+ that is split into separate live ranges. */
+#define BLOCK_LIVE_RANGE_VAR_FLAG(NOTE) (BLOCK_CHECK (NOTE)->block.live_range_var_flag)
+
+/* Index for marking the start of the block for live ranges. */
+#define BLOCK_LIVE_RANGE_START(NOTE) (BLOCK_CHECK (NOTE)->block.live_range_start)
+
+/* Index for marking the end of the block for live ranges. */
+#define BLOCK_LIVE_RANGE_END(NOTE) (BLOCK_CHECK (NOTE)->block.live_range_end)
/* Nonzero means that this block is prepared to handle exceptions
listed in the BLOCK_VARS slot. */
-#define BLOCK_HANDLER_BLOCK(NODE) ((NODE)->block.handler_block_flag)
+#define BLOCK_HANDLER_BLOCK(NODE) (BLOCK_CHECK (NODE)->block.handler_block_flag)
struct tree_block
{
@@ -544,6 +738,8 @@ struct tree_block
unsigned handler_block_flag : 1;
unsigned abstract_flag : 1;
+ unsigned live_range_flag : 1;
+ unsigned live_range_var_flag : 1;
union tree_node *vars;
union tree_node *type_tags;
@@ -551,6 +747,8 @@ struct tree_block
union tree_node *supercontext;
union tree_node *abstract_origin;
struct rtx_def *end_note;
+ int live_range_start;
+ int live_range_end;
};
/* Define fields and accessors for nodes representing data types. */
@@ -558,47 +756,60 @@ struct tree_block
/* See tree.def for documentation of the use of these fields.
Look at the documentation of the various ..._TYPE tree codes. */
-#define TYPE_UID(NODE) ((NODE)->type.uid)
-#define TYPE_SIZE(NODE) ((NODE)->type.size)
-#define TYPE_MODE(NODE) ((NODE)->type.mode)
-#define TYPE_VALUES(NODE) ((NODE)->type.values)
-#define TYPE_DOMAIN(NODE) ((NODE)->type.values)
-#define TYPE_FIELDS(NODE) ((NODE)->type.values)
-#define TYPE_METHODS(NODE) ((NODE)->type.maxval)
-#define TYPE_VFIELD(NODE) ((NODE)->type.minval)
-#define TYPE_ARG_TYPES(NODE) ((NODE)->type.values)
-#define TYPE_METHOD_BASETYPE(NODE) ((NODE)->type.maxval)
-#define TYPE_OFFSET_BASETYPE(NODE) ((NODE)->type.maxval)
-#define TYPE_POINTER_TO(NODE) ((NODE)->type.pointer_to)
-#define TYPE_REFERENCE_TO(NODE) ((NODE)->type.reference_to)
-#define TYPE_MIN_VALUE(NODE) ((NODE)->type.minval)
-#define TYPE_MAX_VALUE(NODE) ((NODE)->type.maxval)
-#define TYPE_PRECISION(NODE) ((NODE)->type.precision)
-#define TYPE_SYMTAB_ADDRESS(NODE) ((NODE)->type.symtab.address)
-#define TYPE_SYMTAB_POINTER(NODE) ((NODE)->type.symtab.pointer)
-#define TYPE_NAME(NODE) ((NODE)->type.name)
-#define TYPE_NEXT_VARIANT(NODE) ((NODE)->type.next_variant)
-#define TYPE_MAIN_VARIANT(NODE) ((NODE)->type.main_variant)
-#define TYPE_BINFO(NODE) ((NODE)->type.binfo)
-#define TYPE_NONCOPIED_PARTS(NODE) ((NODE)->type.noncopied_parts)
-#define TYPE_CONTEXT(NODE) ((NODE)->type.context)
-#define TYPE_OBSTACK(NODE) ((NODE)->type.obstack)
-#define TYPE_LANG_SPECIFIC(NODE) ((NODE)->type.lang_specific)
+#define TYPE_UID(NODE) (TYPE_CHECK (NODE)->type.uid)
+#define TYPE_SIZE(NODE) (TYPE_CHECK (NODE)->type.size)
+#define TYPE_SIZE_UNIT(NODE) (TYPE_CHECK (NODE)->type.size_unit)
+#define TYPE_MODE(NODE) (TYPE_CHECK (NODE)->type.mode)
+#define TYPE_VALUES(NODE) (TYPE_CHECK (NODE)->type.values)
+#define TYPE_DOMAIN(NODE) (TYPE_CHECK (NODE)->type.values)
+#define TYPE_FIELDS(NODE) (TYPE_CHECK (NODE)->type.values)
+#define TYPE_METHODS(NODE) (TYPE_CHECK (NODE)->type.maxval)
+#define TYPE_VFIELD(NODE) (TYPE_CHECK (NODE)->type.minval)
+#define TYPE_ARG_TYPES(NODE) (TYPE_CHECK (NODE)->type.values)
+#define TYPE_METHOD_BASETYPE(NODE) (TYPE_CHECK (NODE)->type.maxval)
+#define TYPE_OFFSET_BASETYPE(NODE) (TYPE_CHECK (NODE)->type.maxval)
+#define TYPE_POINTER_TO(NODE) (TYPE_CHECK (NODE)->type.pointer_to)
+#define TYPE_REFERENCE_TO(NODE) (TYPE_CHECK (NODE)->type.reference_to)
+#define TYPE_MIN_VALUE(NODE) (TYPE_CHECK (NODE)->type.minval)
+#define TYPE_MAX_VALUE(NODE) (TYPE_CHECK (NODE)->type.maxval)
+#define TYPE_PRECISION(NODE) (TYPE_CHECK (NODE)->type.precision)
+#define TYPE_SYMTAB_ADDRESS(NODE) (TYPE_CHECK (NODE)->type.symtab.address)
+#define TYPE_SYMTAB_POINTER(NODE) (TYPE_CHECK (NODE)->type.symtab.pointer)
+#define TYPE_NAME(NODE) (TYPE_CHECK (NODE)->type.name)
+#define TYPE_NEXT_VARIANT(NODE) (TYPE_CHECK (NODE)->type.next_variant)
+#define TYPE_MAIN_VARIANT(NODE) (TYPE_CHECK (NODE)->type.main_variant)
+#define TYPE_BINFO(NODE) (TYPE_CHECK (NODE)->type.binfo)
+#define TYPE_NONCOPIED_PARTS(NODE) (TYPE_CHECK (NODE)->type.noncopied_parts)
+#define TYPE_CONTEXT(NODE) (TYPE_CHECK (NODE)->type.context)
+#define TYPE_OBSTACK(NODE) (TYPE_CHECK (NODE)->type.obstack)
+#define TYPE_LANG_SPECIFIC(NODE) (TYPE_CHECK (NODE)->type.lang_specific)
+
+/* The (language-specific) typed-based alias set for this type.
+ Objects whose TYPE_ALIAS_SETs are different cannot alias each
+ other. If the TYPE_ALIAS_SET is -1, no alias set has yet been
+ assigned to this type. If the TYPE_ALIAS_SET is 0, objects of this
+ type can alias objects of any type. */
+#define TYPE_ALIAS_SET(NODE) (TYPE_CHECK (NODE)->type.alias_set)
+
+/* Nonzero iff the typed-based alias set for this type has been
+ calculated. */
+#define TYPE_ALIAS_SET_KNOWN_P(NODE) \
+ (TYPE_CHECK (NODE)->type.alias_set != -1)
/* A TREE_LIST of IDENTIFIER nodes of the attributes that apply
to this type. */
-#define TYPE_ATTRIBUTES(NODE) ((NODE)->type.attributes)
+#define TYPE_ATTRIBUTES(NODE) (TYPE_CHECK (NODE)->type.attributes)
/* The alignment necessary for objects of this type.
The value is an int, measured in bits. */
-#define TYPE_ALIGN(NODE) ((NODE)->type.align)
+#define TYPE_ALIGN(NODE) (TYPE_CHECK (NODE)->type.align)
#define TYPE_STUB_DECL(NODE) (TREE_CHAIN (NODE))
/* In a RECORD_TYPE, UNION_TYPE or QUAL_UNION_TYPE, it means the type
has BLKmode only because it lacks the alignment requirement for
its size. */
-#define TYPE_NO_FORCE_BLK(NODE) ((NODE)->type.no_force_blk_flag)
+#define TYPE_NO_FORCE_BLK(NODE) (TYPE_CHECK (NODE)->type.no_force_blk_flag)
/* Nonzero in a type considered volatile as a whole. */
#define TYPE_VOLATILE(NODE) ((NODE)->common.volatile_flag)
@@ -607,36 +818,41 @@ struct tree_block
#define TYPE_READONLY(NODE) ((NODE)->common.readonly_flag)
/* These flags are available for each language front end to use internally. */
-#define TYPE_LANG_FLAG_0(NODE) ((NODE)->type.lang_flag_0)
-#define TYPE_LANG_FLAG_1(NODE) ((NODE)->type.lang_flag_1)
-#define TYPE_LANG_FLAG_2(NODE) ((NODE)->type.lang_flag_2)
-#define TYPE_LANG_FLAG_3(NODE) ((NODE)->type.lang_flag_3)
-#define TYPE_LANG_FLAG_4(NODE) ((NODE)->type.lang_flag_4)
-#define TYPE_LANG_FLAG_5(NODE) ((NODE)->type.lang_flag_5)
-#define TYPE_LANG_FLAG_6(NODE) ((NODE)->type.lang_flag_6)
+#define TYPE_LANG_FLAG_0(NODE) (TYPE_CHECK (NODE)->type.lang_flag_0)
+#define TYPE_LANG_FLAG_1(NODE) (TYPE_CHECK (NODE)->type.lang_flag_1)
+#define TYPE_LANG_FLAG_2(NODE) (TYPE_CHECK (NODE)->type.lang_flag_2)
+#define TYPE_LANG_FLAG_3(NODE) (TYPE_CHECK (NODE)->type.lang_flag_3)
+#define TYPE_LANG_FLAG_4(NODE) (TYPE_CHECK (NODE)->type.lang_flag_4)
+#define TYPE_LANG_FLAG_5(NODE) (TYPE_CHECK (NODE)->type.lang_flag_5)
+#define TYPE_LANG_FLAG_6(NODE) (TYPE_CHECK (NODE)->type.lang_flag_6)
/* If set in an ARRAY_TYPE, indicates a string type (for languages
that distinguish string from array of char).
If set in a SET_TYPE, indicates a bitstring type. */
-#define TYPE_STRING_FLAG(NODE) ((NODE)->type.string_flag)
+#define TYPE_STRING_FLAG(NODE) (TYPE_CHECK (NODE)->type.string_flag)
+
+/* If non-NULL, this is a upper bound of the size (in bytes) of an
+ object of the given ARRAY_TYPE. This allows temporaries to be allocated. */
+#define TYPE_ARRAY_MAX_SIZE(ARRAY_TYPE) TYPE_MAX_VALUE (ARRAY_TYPE)
/* Indicates that objects of this type must be initialized by calling a
function when they are created. */
-#define TYPE_NEEDS_CONSTRUCTING(NODE) ((NODE)->type.needs_constructing_flag)
+#define TYPE_NEEDS_CONSTRUCTING(NODE) (TYPE_CHECK (NODE)->type.needs_constructing_flag)
/* Indicates that objects of this type (a UNION_TYPE), should be passed
the same way that the first union alternative would be passed. */
-#define TYPE_TRANSPARENT_UNION(NODE) ((NODE)->type.transparent_union_flag)
+#define TYPE_TRANSPARENT_UNION(NODE) (TYPE_CHECK (NODE)->type.transparent_union_flag)
-/* Indicated that objects of this type should be layed out in as
+/* Indicated that objects of this type should be laid out in as
compact a way as possible. */
-#define TYPE_PACKED(NODE) ((NODE)->type.packed_flag)
+#define TYPE_PACKED(NODE) (TYPE_CHECK (NODE)->type.packed_flag)
struct tree_type
{
char common[sizeof (struct tree_common)];
union tree_node *values;
union tree_node *size;
+ union tree_node *size_unit;
union tree_node *attributes;
unsigned uid;
@@ -674,6 +890,7 @@ struct tree_type
union tree_node *noncopied_parts;
union tree_node *context;
struct obstack *obstack;
+ int alias_set;
/* Points to a structure whose details depend on the language in use. */
struct lang_type *lang_specific;
};
@@ -704,7 +921,7 @@ struct tree_type
#define BINFO_OFFSET(NODE) TREE_VEC_ELT ((NODE), 1)
#define TYPE_BINFO_OFFSET(NODE) BINFO_OFFSET (TYPE_BINFO (NODE))
-#define BINFO_OFFSET_ZEROP(NODE) (BINFO_OFFSET (NODE) == integer_zero_node)
+#define BINFO_OFFSET_ZEROP(NODE) (integer_zerop (BINFO_OFFSET (NODE)))
/* The virtual function table belonging to this basetype. Virtual
function tables provide a mechanism for run-time method dispatching.
@@ -732,15 +949,19 @@ struct tree_type
#define BINFO_BASETYPES(NODE) TREE_VEC_ELT ((NODE), 4)
#define TYPE_BINFO_BASETYPES(NODE) TREE_VEC_ELT (TYPE_BINFO (NODE), 4)
+/* Accessor macro to get to the Nth basetype of this basetype. */
+#define BINFO_BASETYPE(NODE,N) TREE_VEC_ELT (BINFO_BASETYPES (NODE), (N))
+#define TYPE_BINFO_BASETYPE(NODE,N) BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (NODE)), (N)))
+
/* For a BINFO record describing an inheritance, this yields a pointer
to the artificial FIELD_DECL node which contains the "virtual base
class pointer" for the given inheritance. */
-
#define BINFO_VPTR_FIELD(NODE) TREE_VEC_ELT ((NODE), 5)
-/* Accessor macro to get to the Nth basetype of this basetype. */
-#define BINFO_BASETYPE(NODE,N) TREE_VEC_ELT (BINFO_BASETYPES (NODE), (N))
-#define TYPE_BINFO_BASETYPE(NODE,N) BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (NODE)), (N)))
+/* The size of a base class subobject of this type. Not all frontends
+ currently allocate the space for this field. */
+#define BINFO_SIZE(NODE) TREE_VEC_ELT ((NODE), 6)
+#define TYPE_BINFO_SIZE(NODE) BINFO_SIZE (TYPE_BINFO (NODE))
/* Slot used to build a chain that represents a use of inheritance.
For example, if X is derived from Y, and Y is derived from Z,
@@ -759,84 +980,90 @@ struct tree_type
/* This is the name of the object as written by the user.
It is an IDENTIFIER_NODE. */
-#define DECL_NAME(NODE) ((NODE)->decl.name)
+#define DECL_NAME(NODE) (DECL_CHECK (NODE)->decl.name)
/* This is the name of the object as the assembler will see it
(but before any translations made by ASM_OUTPUT_LABELREF).
Often this is the same as DECL_NAME.
It is an IDENTIFIER_NODE. */
-#define DECL_ASSEMBLER_NAME(NODE) ((NODE)->decl.assembler_name)
+#define DECL_ASSEMBLER_NAME(NODE) (DECL_CHECK (NODE)->decl.assembler_name)
/* Records the section name in a section attribute. Used to pass
the name from decl_attributes to make_function_rtl and make_decl_rtl. */
-#define DECL_SECTION_NAME(NODE) ((NODE)->decl.section_name)
+#define DECL_SECTION_NAME(NODE) (DECL_CHECK (NODE)->decl.section_name)
/* For FIELD_DECLs, this is the
RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE node that the field is
a member of. For VAR_DECL, PARM_DECL, FUNCTION_DECL, LABEL_DECL,
- and CONST_DECL nodes, this points to the FUNCTION_DECL for the
- containing function, or else yields NULL_TREE if the given decl has "file scope". */
-#define DECL_CONTEXT(NODE) ((NODE)->decl.context)
-#define DECL_FIELD_CONTEXT(NODE) ((NODE)->decl.context)
+ and CONST_DECL nodes, this points to either the FUNCTION_DECL for the
+ containing function, the RECORD_TYPE or UNION_TYPE for the containing
+ type, or NULL_TREE if the given decl has "file scope". */
+#define DECL_CONTEXT(NODE) (DECL_CHECK (NODE)->decl.context)
+#define DECL_FIELD_CONTEXT(NODE) (DECL_CHECK (NODE)->decl.context)
/* In a DECL this is the field where configuration dependent machine
attributes are store */
-#define DECL_MACHINE_ATTRIBUTES(NODE) ((NODE)->decl.machine_attributes)
+#define DECL_MACHINE_ATTRIBUTES(NODE) (DECL_CHECK (NODE)->decl.machine_attributes)
/* In a FIELD_DECL, this is the field position, counting in bits,
of the bit closest to the beginning of the structure. */
-#define DECL_FIELD_BITPOS(NODE) ((NODE)->decl.arguments)
+#define DECL_FIELD_BITPOS(NODE) (DECL_CHECK (NODE)->decl.arguments)
/* In a FIELD_DECL, this indicates whether the field was a bit-field and
if so, the type that was originally specified for it.
TREE_TYPE may have been modified (in finish_struct). */
-#define DECL_BIT_FIELD_TYPE(NODE) ((NODE)->decl.result)
+#define DECL_BIT_FIELD_TYPE(NODE) (DECL_CHECK (NODE)->decl.result)
/* In FUNCTION_DECL, a chain of ..._DECL nodes. */
/* VAR_DECL and PARM_DECL reserve the arguments slot
for language-specific uses. */
-#define DECL_ARGUMENTS(NODE) ((NODE)->decl.arguments)
+#define DECL_ARGUMENTS(NODE) (DECL_CHECK (NODE)->decl.arguments)
/* In FUNCTION_DECL, holds the decl for the return value. */
-#define DECL_RESULT(NODE) ((NODE)->decl.result)
+#define DECL_RESULT(NODE) (DECL_CHECK (NODE)->decl.result)
+/* For a TYPE_DECL, holds the "original" type. (TREE_TYPE has the copy.) */
+#define DECL_ORIGINAL_TYPE(NODE) (DECL_CHECK (NODE)->decl.result)
/* In PARM_DECL, holds the type as written (perhaps a function or array). */
-#define DECL_ARG_TYPE_AS_WRITTEN(NODE) ((NODE)->decl.result)
+#define DECL_ARG_TYPE_AS_WRITTEN(NODE) (DECL_CHECK (NODE)->decl.result)
/* For a FUNCTION_DECL, holds the tree of BINDINGs.
For a VAR_DECL, holds the initial value.
For a PARM_DECL, not used--default
values for parameters are encoded in the type of the function,
not in the PARM_DECL slot. */
-#define DECL_INITIAL(NODE) ((NODE)->decl.initial)
+#define DECL_INITIAL(NODE) (DECL_CHECK (NODE)->decl.initial)
/* For a PARM_DECL, records the data type used to pass the argument,
which may be different from the type seen in the program. */
-#define DECL_ARG_TYPE(NODE) ((NODE)->decl.initial) /* In PARM_DECL. */
+#define DECL_ARG_TYPE(NODE) (DECL_CHECK (NODE)->decl.initial) /* In PARM_DECL. */
/* For a FIELD_DECL in a QUAL_UNION_TYPE, records the expression, which
if nonzero, indicates that the field occupies the type. */
-#define DECL_QUALIFIER(NODE) ((NODE)->decl.initial)
+#define DECL_QUALIFIER(NODE) (DECL_CHECK (NODE)->decl.initial)
/* These two fields describe where in the source code the declaration was. */
-#define DECL_SOURCE_FILE(NODE) ((NODE)->decl.filename)
-#define DECL_SOURCE_LINE(NODE) ((NODE)->decl.linenum)
+#define DECL_SOURCE_FILE(NODE) (DECL_CHECK (NODE)->decl.filename)
+#define DECL_SOURCE_LINE(NODE) (DECL_CHECK (NODE)->decl.linenum)
/* Holds the size of the datum, as a tree expression.
Need not be constant. */
-#define DECL_SIZE(NODE) ((NODE)->decl.size)
+#define DECL_SIZE(NODE) (DECL_CHECK (NODE)->decl.size)
/* Holds the alignment required for the datum. */
-#define DECL_ALIGN(NODE) ((NODE)->decl.frame_size.u)
+#define DECL_ALIGN(NODE) (DECL_CHECK (NODE)->decl.frame_size.u)
/* Holds the machine mode corresponding to the declaration of a variable or
field. Always equal to TYPE_MODE (TREE_TYPE (decl)) except for a
FIELD_DECL. */
-#define DECL_MODE(NODE) ((NODE)->decl.mode)
+#define DECL_MODE(NODE) (DECL_CHECK (NODE)->decl.mode)
/* Holds the RTL expression for the value of a variable or function. If
PROMOTED_MODE is defined, the mode of this expression may not be same
as DECL_MODE. In that case, DECL_MODE contains the mode corresponding
to the variable's data type, while the mode
of DECL_RTL is the mode actually used to contain the data. */
-#define DECL_RTL(NODE) ((NODE)->decl.rtl)
+#define DECL_RTL(NODE) (DECL_CHECK (NODE)->decl.rtl)
+/* Holds an INSN_LIST of all of the live ranges in which the variable
+ has been moved to a possibly different register. */
+#define DECL_LIVE_RANGE_RTL(NODE) (DECL_CHECK (NODE)->decl.live_range_rtl)
/* For PARM_DECL, holds an RTL for the stack slot or register
where the data was actually passed. */
-#define DECL_INCOMING_RTL(NODE) ((NODE)->decl.saved_insns.r)
+#define DECL_INCOMING_RTL(NODE) (DECL_CHECK (NODE)->decl.saved_insns.r)
/* For FUNCTION_DECL, if it is inline, holds the saved insn chain. */
-#define DECL_SAVED_INSNS(NODE) ((NODE)->decl.saved_insns.r)
+#define DECL_SAVED_INSNS(NODE) (DECL_CHECK (NODE)->decl.saved_insns.r)
/* For FUNCTION_DECL, if it is inline,
holds the size of the stack frame, as an integer. */
-#define DECL_FRAME_SIZE(NODE) ((NODE)->decl.frame_size.i)
+#define DECL_FRAME_SIZE(NODE) (DECL_CHECK (NODE)->decl.frame_size.i)
/* For FUNCTION_DECL, if it is built-in,
this identifies which built-in operation it is. */
-#define DECL_FUNCTION_CODE(NODE) ((NODE)->decl.frame_size.f)
-#define DECL_SET_FUNCTION_CODE(NODE,VAL) ((NODE)->decl.frame_size.f = (VAL))
+#define DECL_FUNCTION_CODE(NODE) (DECL_CHECK (NODE)->decl.frame_size.f)
+#define DECL_SET_FUNCTION_CODE(NODE,VAL) (DECL_CHECK (NODE)->decl.frame_size.f = (VAL))
/* For a FIELD_DECL, holds the size of the member as an integer. */
-#define DECL_FIELD_SIZE(NODE) ((NODE)->decl.saved_insns.i)
+#define DECL_FIELD_SIZE(NODE) (DECL_CHECK (NODE)->decl.saved_insns.i)
/* The DECL_VINDEX is used for FUNCTION_DECLS in two different ways.
Before the struct containing the FUNCTION_DECL is laid out,
@@ -845,19 +1072,21 @@ struct tree_type
function. When the class is laid out, this pointer is changed
to an INTEGER_CST node which is suitable for use as an index
into the virtual function table. */
-#define DECL_VINDEX(NODE) ((NODE)->decl.vindex)
+#define DECL_VINDEX(NODE) (DECL_CHECK (NODE)->decl.vindex)
/* For FIELD_DECLS, DECL_FCONTEXT is the *first* baseclass in
which this FIELD_DECL is defined. This information is needed when
writing debugging information about vfield and vbase decls for C++. */
-#define DECL_FCONTEXT(NODE) ((NODE)->decl.vindex)
+#define DECL_FCONTEXT(NODE) (DECL_CHECK (NODE)->decl.vindex)
/* Every ..._DECL node gets a unique number. */
-#define DECL_UID(NODE) ((NODE)->decl.uid)
+#define DECL_UID(NODE) (DECL_CHECK (NODE)->decl.uid)
/* For any sort of a ..._DECL node, this points to the original (abstract)
decl node which this decl is an instance of, or else it is NULL indicating
- that this decl is not an instance of some other decl. */
-#define DECL_ABSTRACT_ORIGIN(NODE) ((NODE)->decl.abstract_origin)
+ that this decl is not an instance of some other decl. For example,
+ in a nested declaration of an inline function, this points back to the
+ definition. */
+#define DECL_ABSTRACT_ORIGIN(NODE) (DECL_CHECK (NODE)->decl.abstract_origin)
/* Nonzero for any sort of ..._DECL node means this decl node represents
an inline instance of some original (abstract) decl from an inline function;
@@ -866,7 +1095,7 @@ struct tree_type
/* Nonzero if a _DECL means that the name of this decl should be ignored
for symbolic debug purposes. */
-#define DECL_IGNORED_P(NODE) ((NODE)->decl.ignored_flag)
+#define DECL_IGNORED_P(NODE) (DECL_CHECK (NODE)->decl.ignored_flag)
/* Nonzero for a given ..._DECL node means that this node represents an
"abstract instance" of the given declaration (e.g. in the original
@@ -874,38 +1103,42 @@ struct tree_type
information, we mustn't try to generate any address information for nodes
marked as "abstract instances" because we don't actually generate
any code or allocate any data space for such instances. */
-#define DECL_ABSTRACT(NODE) ((NODE)->decl.abstract_flag)
+#define DECL_ABSTRACT(NODE) (DECL_CHECK (NODE)->decl.abstract_flag)
/* Nonzero if a _DECL means that no warnings should be generated just
because this decl is unused. */
-#define DECL_IN_SYSTEM_HEADER(NODE) ((NODE)->decl.in_system_header_flag)
+#define DECL_IN_SYSTEM_HEADER(NODE) (DECL_CHECK (NODE)->decl.in_system_header_flag)
/* Nonzero for a given ..._DECL node means that this node should be
put in .common, if possible. If a DECL_INITIAL is given, and it
is not error_mark_node, then the decl cannot be put in .common. */
-#define DECL_COMMON(NODE) ((NODE)->decl.common_flag)
+#define DECL_COMMON(NODE) (DECL_CHECK (NODE)->decl.common_flag)
/* Language-specific decl information. */
-#define DECL_LANG_SPECIFIC(NODE) ((NODE)->decl.lang_specific)
+#define DECL_LANG_SPECIFIC(NODE) (DECL_CHECK (NODE)->decl.lang_specific)
/* In a VAR_DECL or FUNCTION_DECL,
nonzero means external reference:
do not allocate storage, and refer to a definition elsewhere. */
-#define DECL_EXTERNAL(NODE) ((NODE)->decl.external_flag)
+#define DECL_EXTERNAL(NODE) (DECL_CHECK (NODE)->decl.external_flag)
/* In a TYPE_DECL
nonzero means the detail info about this type is not dumped into stabs.
Instead it will generate cross reference ('x') of names.
This uses the same flag as DECL_EXTERNAL. */
-#define TYPE_DECL_SUPPRESS_DEBUG(NODE) ((NODE)->decl.external_flag)
+#define TYPE_DECL_SUPPRESS_DEBUG(NODE) (DECL_CHECK (NODE)->decl.external_flag)
-/* In VAR_DECL and PARM_DECL nodes, nonzero means declared `register'.
- In LABEL_DECL nodes, nonzero means that an error message about
+/* In VAR_DECL and PARM_DECL nodes, nonzero means declared `register'. */
+#define DECL_REGISTER(NODE) (DECL_CHECK (NODE)->decl.regdecl_flag)
+/* In LABEL_DECL nodes, nonzero means that an error message about
jumping into such a binding contour has been printed for this label. */
-#define DECL_REGISTER(NODE) ((NODE)->decl.regdecl_flag)
+#define DECL_ERROR_ISSUED(NODE) (DECL_CHECK (NODE)->decl.regdecl_flag)
/* In a FIELD_DECL, indicates this field should be bit-packed. */
-#define DECL_PACKED(NODE) ((NODE)->decl.regdecl_flag)
+#define DECL_PACKED(NODE) (DECL_CHECK (NODE)->decl.regdecl_flag)
+/* In a FUNCTION_DECL with a non-zero DECL_CONTEXT, indicates that a
+ static chain is not needed. */
+#define DECL_NO_STATIC_CHAIN(NODE) (DECL_CHECK (NODE)->decl.regdecl_flag)
/* Nonzero in a ..._DECL means this variable is ref'd from a nested function.
For VAR_DECL nodes, PARM_DECL nodes, and FUNCTION_DECL nodes.
@@ -914,11 +1147,11 @@ struct tree_type
Also set in some languages for variables, etc., outside the normal
lexical scope, such as class instance variables. */
-#define DECL_NONLOCAL(NODE) ((NODE)->decl.nonlocal_flag)
+#define DECL_NONLOCAL(NODE) (DECL_CHECK (NODE)->decl.nonlocal_flag)
/* Nonzero in a FUNCTION_DECL means this function can be substituted
where it is called. */
-#define DECL_INLINE(NODE) ((NODE)->decl.inline_flag)
+#define DECL_INLINE(NODE) (DECL_CHECK (NODE)->decl.inline_flag)
/* Nonzero in a FUNCTION_DECL means this is a built-in function
that is not specified by ansi C and that users are supposed to be allowed
@@ -927,58 +1160,66 @@ struct tree_type
/* Nonzero in a FIELD_DECL means it is a bit field, and must be accessed
specially. */
-#define DECL_BIT_FIELD(NODE) ((NODE)->decl.bit_field_flag)
+#define DECL_BIT_FIELD(NODE) (DECL_CHECK (NODE)->decl.bit_field_flag)
/* In a LABEL_DECL, nonzero means label was defined inside a binding
contour that restored a stack level and which is now exited. */
-#define DECL_TOO_LATE(NODE) ((NODE)->decl.bit_field_flag)
+#define DECL_TOO_LATE(NODE) (DECL_CHECK (NODE)->decl.bit_field_flag)
/* In a FUNCTION_DECL, nonzero means a built in function. */
-#define DECL_BUILT_IN(NODE) ((NODE)->decl.bit_field_flag)
+#define DECL_BUILT_IN(NODE) (DECL_CHECK (NODE)->decl.bit_field_flag)
/* In a VAR_DECL that's static,
nonzero if the space is in the text section. */
-#define DECL_IN_TEXT_SECTION(NODE) ((NODE)->decl.bit_field_flag)
+#define DECL_IN_TEXT_SECTION(NODE) (DECL_CHECK (NODE)->decl.bit_field_flag)
/* Used in VAR_DECLs to indicate that the variable is a vtable.
Used in FIELD_DECLs for vtable pointers.
Used in FUNCTION_DECLs to indicate that the function is virtual. */
-#define DECL_VIRTUAL_P(NODE) ((NODE)->decl.virtual_flag)
+#define DECL_VIRTUAL_P(NODE) (DECL_CHECK (NODE)->decl.virtual_flag)
/* Used to indicate that the linkage status of this DECL is not yet known,
so it should not be output now. */
-#define DECL_DEFER_OUTPUT(NODE) ((NODE)->decl.defer_output)
+#define DECL_DEFER_OUTPUT(NODE) (DECL_CHECK (NODE)->decl.defer_output)
/* Used in PARM_DECLs whose type are unions to indicate that the
argument should be passed in the same way that the first union
alternative would be passed. */
-#define DECL_TRANSPARENT_UNION(NODE) ((NODE)->decl.transparent_union)
+#define DECL_TRANSPARENT_UNION(NODE) (DECL_CHECK (NODE)->decl.transparent_union)
/* Used in FUNCTION_DECLs to indicate that they should be run automatically
at the beginning or end of execution. */
-#define DECL_STATIC_CONSTRUCTOR(NODE) ((NODE)->decl.static_ctor_flag)
-#define DECL_STATIC_DESTRUCTOR(NODE) ((NODE)->decl.static_dtor_flag)
+#define DECL_STATIC_CONSTRUCTOR(NODE) (DECL_CHECK (NODE)->decl.static_ctor_flag)
+#define DECL_STATIC_DESTRUCTOR(NODE) (DECL_CHECK (NODE)->decl.static_dtor_flag)
/* Used to indicate that this DECL represents a compiler-generated entity. */
-#define DECL_ARTIFICIAL(NODE) ((NODE)->decl.artificial_flag)
+#define DECL_ARTIFICIAL(NODE) (DECL_CHECK (NODE)->decl.artificial_flag)
/* Used to indicate that this DECL has weak linkage. */
-#define DECL_WEAK(NODE) ((NODE)->decl.weak_flag)
+#define DECL_WEAK(NODE) (DECL_CHECK (NODE)->decl.weak_flag)
+
+/* Used in TREE_PUBLIC decls to indicate that copies of this DECL in
+ multiple translation units should be merged. */
+#define DECL_ONE_ONLY(NODE) (DECL_CHECK (NODE)->decl.transparent_union)
/* Additional flags for language-specific uses. */
-#define DECL_LANG_FLAG_0(NODE) ((NODE)->decl.lang_flag_0)
-#define DECL_LANG_FLAG_1(NODE) ((NODE)->decl.lang_flag_1)
-#define DECL_LANG_FLAG_2(NODE) ((NODE)->decl.lang_flag_2)
-#define DECL_LANG_FLAG_3(NODE) ((NODE)->decl.lang_flag_3)
-#define DECL_LANG_FLAG_4(NODE) ((NODE)->decl.lang_flag_4)
-#define DECL_LANG_FLAG_5(NODE) ((NODE)->decl.lang_flag_5)
-#define DECL_LANG_FLAG_6(NODE) ((NODE)->decl.lang_flag_6)
-#define DECL_LANG_FLAG_7(NODE) ((NODE)->decl.lang_flag_7)
+#define DECL_LANG_FLAG_0(NODE) (DECL_CHECK (NODE)->decl.lang_flag_0)
+#define DECL_LANG_FLAG_1(NODE) (DECL_CHECK (NODE)->decl.lang_flag_1)
+#define DECL_LANG_FLAG_2(NODE) (DECL_CHECK (NODE)->decl.lang_flag_2)
+#define DECL_LANG_FLAG_3(NODE) (DECL_CHECK (NODE)->decl.lang_flag_3)
+#define DECL_LANG_FLAG_4(NODE) (DECL_CHECK (NODE)->decl.lang_flag_4)
+#define DECL_LANG_FLAG_5(NODE) (DECL_CHECK (NODE)->decl.lang_flag_5)
+#define DECL_LANG_FLAG_6(NODE) (DECL_CHECK (NODE)->decl.lang_flag_6)
+#define DECL_LANG_FLAG_7(NODE) (DECL_CHECK (NODE)->decl.lang_flag_7)
+
+/* Used to indicate that the pointer to this DECL cannot be treated as
+ an address constant. */
+#define DECL_NON_ADDR_CONST_P(NODE) (DECL_CHECK (NODE)->decl.non_addr_const_p)
struct tree_decl
{
char common[sizeof (struct tree_common)];
char *filename;
int linenum;
- union tree_node *size;
unsigned int uid;
+ union tree_node *size;
#ifdef ONLY_INT_FIELDS
int mode : 8;
#else
@@ -1013,6 +1254,17 @@ struct tree_decl
unsigned lang_flag_6 : 1;
unsigned lang_flag_7 : 1;
+ unsigned non_addr_const_p : 1;
+
+ /* For a FUNCTION_DECL, if inline, this is the size of frame needed.
+ If built-in, this is the code for which built-in function.
+ For other kinds of decls, this is DECL_ALIGN. */
+ union {
+ int i;
+ unsigned int u;
+ enum built_in_function f;
+ } frame_size;
+
union tree_node *name;
union tree_node *context;
union tree_node *arguments;
@@ -1024,20 +1276,12 @@ struct tree_decl
union tree_node *machine_attributes;
struct rtx_def *rtl; /* acts as link to register transfer language
(rtl) info */
- /* For a FUNCTION_DECL, if inline, this is the size of frame needed.
- If built-in, this is the code for which built-in function.
- For other kinds of decls, this is DECL_ALIGN. */
- union {
- int i;
- unsigned int u;
- enum built_in_function f;
- } frame_size;
+ struct rtx_def *live_range_rtl;
/* For FUNCTION_DECLs: points to insn that constitutes its definition
- on the permanent obstack. For any other kind of decl, this is the
- alignment. */
+ on the permanent obstack. For FIELD_DECL, this is DECL_FIELD_SIZE. */
union {
struct rtx_def *r;
- int i;
+ HOST_WIDE_INT i;
} saved_insns;
union tree_node *vindex;
/* Points to a structure whose details depend on the language in use. */
@@ -1063,80 +1307,41 @@ union tree_node
struct tree_exp exp;
struct tree_block block;
};
-
-/* Add prototype support. */
-#ifndef PROTO
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define PROTO(ARGS) ARGS
-#else
-#define PROTO(ARGS) ()
-#endif
-#endif
-
-#ifndef VPROTO
-#ifdef __STDC__
-#define PVPROTO(ARGS) ARGS
-#define VPROTO(ARGS) ARGS
-#define VA_START(va_list,var) va_start(va_list,var)
-#else
-#define PVPROTO(ARGS) ()
-#define VPROTO(ARGS) (va_alist) va_dcl
-#define VA_START(va_list,var) va_start(va_list)
-#endif
-#endif
-
-#ifndef STDIO_PROTO
-#ifdef BUFSIZ
-#define STDIO_PROTO(ARGS) PROTO(ARGS)
-#else
-#define STDIO_PROTO(ARGS) ()
-#endif
-#endif
+
+#include "gansidecl.h"
#define NULL_TREE (tree) NULL
-/* Define a generic NULL if one hasn't already been defined. */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-#ifndef GENERIC_PTR
-#if defined (USE_PROTOTYPES) ? USE_PROTOTYPES : defined (__STDC__)
-#define GENERIC_PTR void *
-#else
-#define GENERIC_PTR char *
-#endif
-#endif
-
-#ifndef NULL_PTR
-#define NULL_PTR ((GENERIC_PTR)0)
-#endif
-
/* The following functions accept a wide integer argument. Rather than
having to cast on every function call, we use a macro instead, that is
defined here and in rtl.h. */
#ifndef exact_log2
-#define exact_log2(N) exact_log2_wide ((HOST_WIDE_INT) (N))
-#define floor_log2(N) floor_log2_wide ((HOST_WIDE_INT) (N))
+#define exact_log2(N) exact_log2_wide ((unsigned HOST_WIDE_INT) (N))
+#define floor_log2(N) floor_log2_wide ((unsigned HOST_WIDE_INT) (N))
#endif
+extern int exact_log2_wide PROTO((unsigned HOST_WIDE_INT));
+extern int floor_log2_wide PROTO((unsigned HOST_WIDE_INT));
#if 0
/* At present, don't prototype xrealloc, since all of the callers don't
cast their pointers to char *, and all of the xrealloc's don't use
void * yet. */
extern char *xmalloc PROTO((size_t));
+extern char *xcalloc PROTO((size_t, size_t));
extern char *xrealloc PROTO((void *, size_t));
#else
extern char *xmalloc ();
+extern char *xcalloc ();
extern char *xrealloc ();
#endif
+extern char *xstrdup PROTO((char *));
+
extern char *oballoc PROTO((int));
extern char *permalloc PROTO((int));
extern char *savealloc PROTO((int));
-extern void free PROTO((void *));
+extern char *expralloc PROTO((int));
/* Lowest level primitive for allocating a node.
The TREE_CODE is the only argument. Contents are initialized
@@ -1163,6 +1368,12 @@ extern tree make_tree_vec PROTO((int));
extern tree get_identifier PROTO((char *));
+/* If an identifier with the name TEXT (a null-terminated string) has
+ previously been referred to, return that node; otherwise return
+ NULL_TREE. */
+
+extern tree maybe_get_identifier PROTO((char *));
+
/* Construct various types of nodes. */
#define build_int_2(LO,HI) \
@@ -1175,18 +1386,21 @@ extern tree build_parse_node PVPROTO((enum tree_code, ...));
extern tree build_int_2_wide PROTO((HOST_WIDE_INT, HOST_WIDE_INT));
extern tree build_real PROTO((tree, REAL_VALUE_TYPE));
extern tree build_real_from_int_cst PROTO((tree, tree));
-extern tree build_complex PROTO((tree, tree));
+extern tree build_complex PROTO((tree, tree, tree));
extern tree build_string PROTO((int, char *));
extern tree build1 PROTO((enum tree_code, tree, tree));
extern tree build_tree_list PROTO((tree, tree));
extern tree build_decl_list PROTO((tree, tree));
+extern tree build_expr_list PROTO((tree, tree));
extern tree build_decl PROTO((enum tree_code, tree, tree));
extern tree build_block PROTO((tree, tree, tree, tree, tree));
+extern tree build_expr_wfl PROTO((tree, char *, int, int));
/* Construct various nodes representing data types. */
extern tree make_signed_type PROTO((int));
extern tree make_unsigned_type PROTO((int));
+extern void set_sizetype PROTO((tree));
extern tree signed_or_unsigned_type PROTO((int, tree));
extern void fixup_unsigned_type PROTO((tree));
extern tree build_pointer_type PROTO((tree));
@@ -1210,12 +1424,13 @@ extern int tree_int_cst_equal PROTO((tree, tree));
extern int tree_int_cst_lt PROTO((tree, tree));
extern int tree_int_cst_sgn PROTO((tree));
extern int index_type_equal PROTO((tree, tree));
+extern tree get_inner_array_type PROTO((tree));
/* From expmed.c. Since rtl.h is included after tree.h, we can't
put the prototype here. Rtl.h does declare the prototype if
tree.h had been included. */
-extern tree make_tree ();
+extern tree make_tree PROTO((tree, struct rtx_def *));
/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
is ATTRIBUTE.
@@ -1226,19 +1441,34 @@ extern tree make_tree ();
extern tree build_type_attribute_variant PROTO((tree, tree));
extern tree build_decl_attribute_variant PROTO((tree, tree));
+extern tree merge_machine_decl_attributes PROTO((tree, tree));
+extern tree merge_machine_type_attributes PROTO((tree, tree));
+
+/* Split a list of declspecs and attributes into two. */
+
+extern void split_specs_attrs PROTO((tree, tree *, tree *));
+
+/* Strip attributes from a list of combined specs and attrs. */
+
+extern tree strip_attrs PROTO((tree));
+
/* Return 1 if an attribute and its arguments are valid for a decl or type. */
-int valid_machine_attribute PROTO((tree, tree, tree, tree));
+extern int valid_machine_attribute PROTO((tree, tree, tree, tree));
/* Given a tree node and a string, return non-zero if the tree node is
a valid attribute name for the string. */
-int is_attribute_p PROTO((char *, tree));
+extern int is_attribute_p PROTO((char *, tree));
/* Given an attribute name and a list of attributes, return the list element
of the attribute or NULL_TREE if not found. */
-tree lookup_attribute PROTO((char *, tree));
+extern tree lookup_attribute PROTO((char *, tree));
+
+/* Given two attributes lists, return a list of their union. */
+
+extern tree merge_attributes PROTO((tree, tree));
/* Given a type node TYPE, and CONSTP and VOLATILEP, return a type
for the same kind of data as TYPE describes.
@@ -1284,16 +1514,43 @@ extern tree pedantic_non_lvalue PROTO((tree));
extern tree convert PROTO((tree, tree));
extern tree size_in_bytes PROTO((tree));
-extern int int_size_in_bytes PROTO((tree));
+extern HOST_WIDE_INT int_size_in_bytes PROTO((tree));
extern tree size_binop PROTO((enum tree_code, tree, tree));
-extern tree size_int PROTO((unsigned HOST_WIDE_INT));
+extern tree ssize_binop PROTO((enum tree_code, tree, tree));
+extern tree size_int_wide PROTO((unsigned HOST_WIDE_INT,
+ unsigned HOST_WIDE_INT, int));
+#define size_int(L) size_int_2 ((L), 0, 0)
+#define bitsize_int(L, H) size_int_2 ((L), (H), 1)
+#define size_int_2(L, H, T) \
+ size_int_wide ((unsigned HOST_WIDE_INT) (L), \
+ (unsigned HOST_WIDE_INT) (H), (T))
+
extern tree round_up PROTO((tree, int));
extern tree get_pending_sizes PROTO((void));
extern void put_pending_sizes PROTO((tree));
/* Type for sizes of data-type. */
-extern tree sizetype;
+#define BITS_PER_UNIT_LOG \
+ ((BITS_PER_UNIT > 1) + (BITS_PER_UNIT > 2) + (BITS_PER_UNIT > 4) \
+ + (BITS_PER_UNIT > 8) + (BITS_PER_UNIT > 16) + (BITS_PER_UNIT > 32) \
+ + (BITS_PER_UNIT > 64) + (BITS_PER_UNIT > 128) + (BITS_PER_UNIT > 256))
+
+struct sizetype_tab
+{
+ tree xsizetype, xbitsizetype;
+ tree xssizetype, xusizetype;
+ tree xsbitsizetype, xubitsizetype;
+};
+
+extern struct sizetype_tab sizetype_tab;
+
+#define sizetype sizetype_tab.xsizetype
+#define bitsizetype sizetype_tab.xbitsizetype
+#define ssizetype sizetype_tab.xssizetype
+#define usizetype sizetype_tab.xusizetype
+#define sbitsizetype sizetype_tab.xsbitsizetype
+#define ubitsizetype sizetype_tab.xubitsizetype
/* If nonzero, an upper limit on alignment of structure fields, in bits. */
extern int maximum_field_alignment;
@@ -1314,6 +1571,7 @@ extern tree perm_tree_cons PROTO((tree, tree, tree));
extern tree temp_tree_cons PROTO((tree, tree, tree));
extern tree saveable_tree_cons PROTO((tree, tree, tree));
extern tree decl_tree_cons PROTO((tree, tree, tree));
+extern tree expr_tree_cons PROTO((tree, tree, tree));
/* Return the last tree node in a chain. */
@@ -1362,6 +1620,22 @@ extern int lvalue_or_else PROTO((tree, char *));
extern tree save_expr PROTO((tree));
+/* Returns the index of the first non-tree operand for CODE, or the number
+ of operands if all are trees. */
+
+extern int first_rtl_op PROTO((enum tree_code));
+
+/* unsave_expr (EXP) returns an expression equivalent to EXP but it
+ can be used multiple times and will evaluate EXP, in its entirety
+ each time. */
+
+extern tree unsave_expr PROTO((tree));
+
+/* unsave_expr_now (EXP) resets EXP in place, so that it can be
+ expanded again. */
+
+extern tree unsave_expr_now PROTO((tree));
+
/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
or offset that depends on a field within a record.
@@ -1370,6 +1644,11 @@ extern tree save_expr PROTO((tree));
extern int contains_placeholder_p PROTO((tree));
+/* Return 1 if EXP contains any expressions that produce cleanups for an
+ outer scope to deal with. Used by fold. */
+
+extern int has_cleanups PROTO((tree));
+
/* Given a tree EXP, a FIELD_DECL F, and a replacement value R,
return a tree with all occurrences of references to F in a
PLACEHOLDER_EXPR replaced by R. Note that we assume here that EXP
@@ -1377,12 +1656,6 @@ extern int contains_placeholder_p PROTO((tree));
extern tree substitute_in_expr PROTO((tree, tree, tree));
-/* Given a type T, a FIELD_DECL F, and a replacement value R,
- return a new type with all size expressions that contain F
- updated by replacing the reference to F with R. */
-
-extern tree substitute_in_type PROTO((tree, tree, tree));
-
/* variable_size (EXP) is like save_expr (EXP) except that it
is for the special case of something that is part of a
variable size for a data type. It makes special arrangements
@@ -1455,7 +1728,9 @@ extern tree maybe_build_cleanup PROTO((tree));
look for nested component-refs or array-refs at constant positions
and find the ultimate containing object, which is returned. */
-extern tree get_inner_reference PROTO((tree, int *, int *, tree *, enum machine_mode *, int *, int *));
+extern tree get_inner_reference PROTO((tree, int *, int *, tree *,
+ enum machine_mode *, int *,
+ int *, int *));
/* Return the FUNCTION_DECL which provides this _DECL with its context,
or zero if none. */
@@ -1544,20 +1819,29 @@ extern int current_function_calls_longjmp;
extern int all_types_permanent;
-/* Pointer to function to compute the name to use to print a declaration. */
+/* Pointer to function to compute the name to use to print a declaration.
+ DECL is the declaration in question.
+ VERBOSITY determines what information will be printed:
+ 0: DECL_NAME, demangled as necessary.
+ 1: and scope information.
+ 2: and any other information that might be interesting, such as function
+ parameter types in C++. */
-extern char *(*decl_printable_name) ();
+extern char *(*decl_printable_name) PROTO((tree, int));
/* Pointer to function to finish handling an incomplete decl at the
end of compilation. */
-extern void (*incomplete_decl_finalize_hook) ();
+extern void (*incomplete_decl_finalize_hook) PROTO((tree));
/* In tree.c */
extern char *perm_calloc PROTO((int, long));
-extern tree get_set_constructor_bits PROTO((tree, char*, int));
+extern tree get_file_function_name PROTO((int));
+extern tree get_set_constructor_bits PROTO((tree, char *, int));
extern tree get_set_constructor_bytes PROTO((tree,
- unsigned char*, int));
+ unsigned char *, int));
+extern int get_alias_set PROTO((tree));
+extern int (*lang_get_alias_set) PROTO((tree));
/* In stmt.c */
@@ -1589,7 +1873,15 @@ extern void expand_null_return PROTO((void));
extern void expand_return PROTO((tree));
extern void expand_start_bindings PROTO((int));
extern void expand_end_bindings PROTO((tree, int, int));
+extern void start_cleanup_deferral PROTO((void));
+extern void end_cleanup_deferral PROTO((void));
+extern void mark_block_as_eh_region PROTO((void));
+extern void mark_block_as_not_eh_region PROTO((void));
+extern int is_eh_region PROTO((void));
+extern int conditional_context PROTO((void));
extern tree last_cleanup_this_contour PROTO((void));
+extern int expand_dhc_cleanup PROTO((tree));
+extern int expand_dcc_cleanup PROTO((tree));
extern void expand_start_case PROTO((int, tree, tree,
char *));
extern void expand_end_case PROTO((tree));
@@ -1599,6 +1891,7 @@ extern int pushcase PROTO((tree,
extern int pushcase_range PROTO((tree, tree,
tree (*) (tree, tree),
tree, tree *));
+extern void using_eh_for_cleanups PROTO((void));
/* In fold-const.c */
@@ -1634,8 +1927,57 @@ extern void rrotate_double PROTO((HOST_WIDE_INT, HOST_WIDE_INT,
extern int operand_equal_p PROTO((tree, tree, int));
extern tree invert_truthvalue PROTO((tree));
+/* Interface of the DWARF2 unwind info support. */
+
+/* Decide whether we want to emit frame unwind information for the current
+ translation unit. */
+
+extern int dwarf2out_do_frame PROTO((void));
+
+/* Generate a new label for the CFI info to refer to. */
+
+extern char *dwarf2out_cfi_label PROTO((void));
+
+/* Entry point to update the canonical frame address (CFA). */
+
+extern void dwarf2out_def_cfa PROTO((char *, unsigned, long));
+
+/* Add the CFI for saving a register window. */
+
+extern void dwarf2out_window_save PROTO((char *));
+
+/* Add a CFI to update the running total of the size of arguments pushed
+ onto the stack. */
+
+extern void dwarf2out_args_size PROTO((char *, long));
+
+/* Entry point for saving a register to the stack. */
+
+extern void dwarf2out_reg_save PROTO((char *, unsigned, long));
+
+/* Entry point for saving the return address in the stack. */
+
+extern void dwarf2out_return_save PROTO((char *, long));
+
+/* Entry point for saving the return address in a register. */
+
+extern void dwarf2out_return_reg PROTO((char *, unsigned));
+
+/* Output a marker (i.e. a label) for the beginning of a function, before
+ the prologue. */
+
+extern void dwarf2out_begin_prologue PROTO((void));
+
+/* Output a marker (i.e. a label) for the absolute end of the generated
+ code for a function definition. */
+
+extern void dwarf2out_end_epilogue PROTO((void));
+
/* The language front-end must define these functions. */
+/* Function of no arguments for initializing options. */
+extern void lang_init_options PROTO((void));
+
/* Function of no arguments for initializing lexical scanning. */
extern void init_lex PROTO((void));
/* Function of no arguments for initializing the symbol table. */
@@ -1657,7 +1999,7 @@ extern int yyparse PROTO((void));
/* Function called with option as argument
to decode options starting with -f or -W or +.
It should return nonzero if it handles the option. */
-extern int lang_decode_option PROTO((char *));
+extern int lang_decode_option PROTO((int, char **));
/* Functions for processing symbol declarations. */
/* Function to enter a new lexical scope.
@@ -1714,3 +2056,237 @@ extern void end_temporary_allocation PROTO((void));
/* Pop the obstack selection stack. */
extern void pop_obstacks PROTO((void));
+
+/* In tree.c */
+extern int really_constant_p PROTO ((tree));
+extern void push_obstacks PROTO ((struct obstack *,
+ struct obstack *));
+extern void pop_momentary_nofree PROTO ((void));
+extern void preserve_momentary PROTO ((void));
+extern void saveable_allocation PROTO ((void));
+extern void temporary_allocation PROTO ((void));
+extern void resume_temporary_allocation PROTO ((void));
+extern tree get_file_function_name PROTO ((int));
+extern void set_identifier_size PROTO ((int));
+extern int int_fits_type_p PROTO ((tree, tree));
+extern int tree_log2 PROTO ((tree));
+extern void preserve_initializer PROTO ((void));
+extern void preserve_data PROTO ((void));
+extern int object_permanent_p PROTO ((tree));
+extern int type_precision PROTO ((tree));
+extern int simple_cst_equal PROTO ((tree, tree));
+extern int type_list_equal PROTO ((tree, tree));
+extern int chain_member PROTO ((tree, tree));
+extern int chain_member_purpose PROTO ((tree, tree));
+extern int chain_member_value PROTO ((tree, tree));
+extern tree listify PROTO ((tree));
+extern tree type_hash_lookup PROTO ((int, tree));
+extern void type_hash_add PROTO ((int, tree));
+extern int type_hash_list PROTO ((tree));
+extern int simple_cst_list_equal PROTO ((tree, tree));
+extern void debug_obstack PROTO ((char *));
+extern void rtl_in_current_obstack PROTO ((void));
+extern void rtl_in_saveable_obstack PROTO ((void));
+extern void init_tree_codes PROTO ((void));
+extern void dump_tree_statistics PROTO ((void));
+extern void print_obstack_statistics PROTO ((char *, struct obstack *));
+#ifdef BUFSIZ
+extern void print_obstack_name PROTO ((char *, FILE *, char *));
+#endif
+extern void expand_function_end PROTO ((char *, int, int));
+extern void expand_function_start PROTO ((tree, int));
+extern int real_onep PROTO ((tree));
+extern int real_twop PROTO ((tree));
+extern void start_identifier_warnings PROTO ((void));
+extern void gcc_obstack_init PROTO ((struct obstack *));
+extern void init_obstacks PROTO ((void));
+extern void obfree PROTO ((char *));
+extern tree tree_check PROTO ((tree, enum tree_code, char*, int, int));
+extern tree tree_class_check PROTO ((tree, char, char*, int, int));
+extern tree expr_check PROTO ((tree, int, char*, int, int));
+
+/* In function.c */
+extern void setjmp_protect_args PROTO ((void));
+extern void setjmp_protect PROTO ((tree));
+extern void expand_main_function PROTO ((void));
+extern void mark_varargs PROTO ((void));
+extern void init_function_start PROTO ((tree, char *, int));
+extern void assign_parms PROTO ((tree, int));
+extern void put_var_into_stack PROTO ((tree));
+extern void uninitialized_vars_warning PROTO ((tree));
+extern void setjmp_args_warning PROTO ((void));
+extern void mark_all_temps_used PROTO ((void));
+extern void init_temp_slots PROTO ((void));
+extern void combine_temp_slots PROTO ((void));
+extern void free_temp_slots PROTO ((void));
+extern void pop_temp_slots PROTO ((void));
+extern void push_temp_slots PROTO ((void));
+extern void preserve_temp_slots PROTO ((struct rtx_def *));
+extern int aggregate_value_p PROTO ((tree));
+extern tree reorder_blocks PROTO ((tree *, tree,
+ struct rtx_def *));
+extern void free_temps_for_rtl_expr PROTO ((tree));
+extern void instantiate_virtual_regs PROTO ((tree, struct rtx_def *));
+extern int max_parm_reg_num PROTO ((void));
+extern void push_function_context PROTO ((void));
+extern void pop_function_context PROTO ((void));
+extern void push_function_context_to PROTO ((tree));
+extern void pop_function_context_from PROTO ((tree));
+
+/* In print-rtl.c */
+#ifdef BUFSIZ
+extern void print_rtl PROTO ((FILE *, struct rtx_def *));
+#endif
+
+/* In print-tree.c */
+extern void debug_tree PROTO ((tree));
+#ifdef BUFSIZ
+extern void print_node PROTO ((FILE *, char *, tree, int));
+extern void print_node_brief PROTO ((FILE *, char *, tree, int));
+extern void indent_to PROTO ((FILE *, int));
+#endif
+
+/* In expr.c */
+extern void emit_queue PROTO ((void));
+extern int apply_args_register_offset PROTO ((int));
+extern struct rtx_def *expand_builtin_return_addr
+ PROTO ((enum built_in_function, int, struct rtx_def *));
+extern void do_pending_stack_adjust PROTO ((void));
+extern struct rtx_def *expand_assignment PROTO ((tree, tree, int, int));
+extern struct rtx_def *store_expr PROTO ((tree, struct rtx_def *,
+ int));
+extern void check_max_integer_computation_mode PROTO ((tree));
+
+/* In emit-rtl.c */
+extern void start_sequence_for_rtl_expr PROTO ((tree));
+extern struct rtx_def *emit_line_note_after PROTO ((char *, int,
+ struct rtx_def *));
+extern struct rtx_def *emit_line_note PROTO ((char *, int));
+extern struct rtx_def *emit_line_note_force PROTO ((char *, int));
+
+/* In c-typeck.c */
+extern int mark_addressable PROTO ((tree));
+extern void incomplete_type_error PROTO ((tree, tree));
+
+/* In c-lang.c */
+extern void print_lang_statistics PROTO ((void));
+
+/* In c-common.c */
+extern tree truthvalue_conversion PROTO ((tree));
+extern int min_precision PROTO ((tree, int));
+extern void split_specs_attrs PROTO ((tree, tree *, tree *));
+
+/* In c-decl.c */
+#ifdef BUFSIZ
+extern void print_lang_decl PROTO ((FILE *, tree, int));
+extern void print_lang_type PROTO ((FILE *, tree, int));
+extern void print_lang_identifier PROTO ((FILE *, tree, int));
+#endif
+extern int global_bindings_p PROTO ((void));
+extern void insert_block PROTO ((tree));
+
+/* In integrate.c */
+extern void save_for_inline_nocopy PROTO ((tree));
+extern void save_for_inline_copying PROTO ((tree));
+extern void set_decl_abstract_flags PROTO ((tree, int));
+extern void output_inline_function PROTO ((tree));
+
+/* In c-lex.c */
+extern void set_yydebug PROTO ((int));
+
+/* In stor-layout.c */
+extern void fixup_signed_type PROTO ((tree));
+
+/* varasm.c */
+extern void make_decl_rtl PROTO ((tree, char *, int));
+extern void make_decl_one_only PROTO ((tree));
+extern int supports_one_only PROTO ((void));
+extern void variable_section PROTO ((tree, int));
+
+/* In fold-const.c */
+extern int div_and_round_double PROTO ((enum tree_code, int,
+ HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT, HOST_WIDE_INT,
+ HOST_WIDE_INT *,
+ HOST_WIDE_INT *,
+ HOST_WIDE_INT *,
+ HOST_WIDE_INT *));
+
+/* In stmt.c */
+extern void emit_nop PROTO ((void));
+extern void expand_computed_goto PROTO ((tree));
+extern struct rtx_def *label_rtx PROTO ((tree));
+extern void expand_asm_operands PROTO ((tree, tree, tree, tree, int,
+ char *, int));
+extern int any_pending_cleanups PROTO ((int));
+extern void init_stmt PROTO ((void));
+extern void init_stmt_for_function PROTO ((void));
+extern void remember_end_note PROTO ((tree));
+extern int drop_through_at_end_p PROTO ((void));
+extern void expand_start_target_temps PROTO ((void));
+extern void expand_end_target_temps PROTO ((void));
+extern void expand_elseif PROTO ((tree));
+extern void expand_decl PROTO ((tree));
+extern int expand_decl_cleanup PROTO ((tree, tree));
+extern void expand_anon_union_decl PROTO ((tree, tree, tree));
+extern void move_cleanups_up PROTO ((void));
+extern void expand_start_case_dummy PROTO ((void));
+extern void expand_end_case_dummy PROTO ((void));
+extern tree case_index_expr_type PROTO ((void));
+extern HOST_WIDE_INT all_cases_count PROTO ((tree, int *));
+extern void check_for_full_enumeration_handling PROTO ((tree));
+extern void declare_nonlocal_label PROTO ((tree));
+#ifdef BUFSIZ
+extern void lang_print_xnode PROTO ((FILE *, tree, int));
+#endif
+
+
+/* If KIND=='I', return a suitable global initializer (constructor) name.
+ If KIND=='D', return a suitable global clean-up (destructor) name. */
+extern tree get_file_function_name PROTO((int));
+
+/* Interface of the DWARF2 unwind info support. */
+
+/* Decide whether we want to emit frame unwind information for the current
+ translation unit. */
+
+extern int dwarf2out_do_frame PROTO((void));
+
+/* Generate a new label for the CFI info to refer to. */
+
+extern char *dwarf2out_cfi_label PROTO((void));
+
+/* Entry point to update the canonical frame address (CFA). */
+
+extern void dwarf2out_def_cfa PROTO((char *, unsigned, long));
+
+/* Add the CFI for saving a register window. */
+
+extern void dwarf2out_window_save PROTO((char *));
+
+/* Add a CFI to update the running total of the size of arguments pushed
+ onto the stack. */
+
+extern void dwarf2out_args_size PROTO((char *, long));
+
+/* Entry point for saving a register to the stack. */
+
+extern void dwarf2out_reg_save PROTO((char *, unsigned, long));
+
+/* Entry point for saving the return address in the stack. */
+
+extern void dwarf2out_return_save PROTO((char *, long));
+
+/* Entry point for saving the return address in a register. */
+
+extern void dwarf2out_return_reg PROTO((char *, unsigned));
+
+/* Output a marker (i.e. a label) for the beginning of a function, before
+ the prologue. */
+
+extern void dwarf2out_begin_prologue PROTO((void));
+
+/* Output a marker (i.e. a label) for the absolute end of the generated
+ code for a function definition. */
+
+extern void dwarf2out_end_epilogue PROTO((void));
diff --git a/contrib/gcc/unprotoize.c b/contrib/gcc/unprotoize.c
index bfdb7d2..bebac0a 100644
--- a/contrib/gcc/unprotoize.c
+++ b/contrib/gcc/unprotoize.c
@@ -1 +1,2 @@
+#define UNPROTOIZE
#include "protoize.c"
diff --git a/contrib/gcc/unroll.c b/contrib/gcc/unroll.c
index 4ba6efb..cfb51f6 100644
--- a/contrib/gcc/unroll.c
+++ b/contrib/gcc/unroll.c
@@ -1,5 +1,5 @@
/* Try to unroll loops, and split induction variables.
- Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 93, 94, 95, 97, 98, 1999 Free Software Foundation, Inc.
Contributed by James E. Wilson, Cygnus Support/UC Berkeley.
This file is part of GNU CC.
@@ -147,14 +147,16 @@ struct _factor { int factor, count; } factors[NUM_FACTORS]
enum unroll_types { UNROLL_COMPLETELY, UNROLL_MODULO, UNROLL_NAIVE };
#include "config.h"
+#include "system.h"
#include "rtl.h"
#include "insn-config.h"
#include "integrate.h"
#include "regs.h"
+#include "recog.h"
#include "flags.h"
#include "expr.h"
-#include <stdio.h>
#include "loop.h"
+#include "toplev.h"
/* This controls which loops are unrolled, and by how much we unroll
them. */
@@ -191,6 +193,7 @@ static rtx loop_iteration_var;
static rtx loop_initial_value;
static rtx loop_increment;
static rtx loop_final_value;
+static enum rtx_code loop_comparison_code;
/* Forward declarations. */
@@ -201,13 +204,14 @@ static rtx initial_reg_note_copy PROTO((rtx, struct inline_remap *));
static void final_reg_note_copy PROTO((rtx, struct inline_remap *));
static void copy_loop_body PROTO((rtx, rtx, struct inline_remap *, rtx, int,
enum unroll_types, rtx, rtx, rtx, rtx));
-static void iteration_info PROTO((rtx, rtx *, rtx *, rtx, rtx));
+void iteration_info PROTO((rtx, rtx *, rtx *, rtx, rtx));
static rtx approx_final_value PROTO((enum rtx_code, rtx, int *, int *));
static int find_splittable_regs PROTO((enum unroll_types, rtx, rtx, rtx, int));
static int find_splittable_givs PROTO((struct iv_class *,enum unroll_types,
rtx, rtx, rtx, int));
static int reg_dead_after_loop PROTO((rtx, rtx, rtx));
static rtx fold_rtx_mult_add PROTO((rtx, rtx, rtx, enum machine_mode));
+static int verify_addresses PROTO((struct induction *, rtx, int));
static rtx remap_split_bivs PROTO((rtx));
/* Try to unroll one loop and split induction variables in the loop.
@@ -233,7 +237,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
int i, j, temp;
int unroll_number = 1;
rtx copy_start, copy_end;
- rtx insn, copy, sequence, pattern, tem;
+ rtx insn, sequence, pattern, tem;
int max_labelno, max_insnno;
rtx insert_before;
struct inline_remap *map;
@@ -267,8 +271,12 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
of block_beg and block_end notes, because that would unbalance the block
structure of the function. This can happen as a result of the
"if (foo) bar; else break;" optimization in jump.c. */
+ /* ??? Gcc has a general policy that -g is never supposed to change the code
+ that the compiler emits, so we must disable this optimization always,
+ even if debug info is not being output. This is rare, so this should
+ not be a significant performance problem. */
- if (write_symbols != NO_DEBUG)
+ if (1 /* write_symbols != NO_DEBUG */)
{
int block_begins = 0;
int block_ends = 0;
@@ -305,8 +313,11 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
loop_n_iterations = 0;
if (loop_dump_stream && loop_n_iterations > 0)
- fprintf (loop_dump_stream,
- "Loop unrolling: %d iterations.\n", loop_n_iterations);
+ {
+ fputs ("Loop unrolling: ", loop_dump_stream);
+ fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC, loop_n_iterations);
+ fputs (" iterations.\n", loop_dump_stream);
+ }
/* Find and save a pointer to the last nonnote insn in the loop. */
@@ -420,15 +431,34 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
if (unroll_type == UNROLL_COMPLETELY || unroll_type == UNROLL_MODULO)
{
- /* Loops of these types should never start with a jump down to
- the exit condition test. For now, check for this case just to
- be sure. UNROLL_NAIVE loops can be of this form, this case is
- handled below. */
+ /* Loops of these types can start with jump down to the exit condition
+ in rare circumstances.
+
+ Consider a pair of nested loops where the inner loop is part
+ of the exit code for the outer loop.
+
+ In this case jump.c will not duplicate the exit test for the outer
+ loop, so it will start with a jump to the exit code.
+
+ Then consider if the inner loop turns out to iterate once and
+ only once. We will end up deleting the jumps associated with
+ the inner loop. However, the loop notes are not removed from
+ the instruction stream.
+
+ And finally assume that we can compute the number of iterations
+ for the outer loop.
+
+ In this case unroll may want to unroll the outer loop even though
+ it starts with a jump to the outer loop's exit code.
+
+ We could try to optimize this case, but it hardly seems worth it.
+ Just return without unrolling the loop in such cases. */
+
insn = loop_start;
while (GET_CODE (insn) != CODE_LABEL && GET_CODE (insn) != JUMP_INSN)
insn = NEXT_INSN (insn);
if (GET_CODE (insn) == JUMP_INSN)
- abort ();
+ return;
}
if (unroll_type == UNROLL_COMPLETELY)
@@ -632,6 +662,23 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
copy_end = last_loop_insn;
}
+ if (unroll_type == UNROLL_NAIVE
+ && GET_CODE (last_loop_insn) == JUMP_INSN
+ && start_label != JUMP_LABEL (last_loop_insn))
+ {
+ /* ??? The loop ends with a conditional branch that does not branch back
+ to the loop start label. In this case, we must emit an unconditional
+ branch to the loop exit after emitting the final branch.
+ copy_loop_body does not have support for this currently, so we
+ give up. It doesn't seem worthwhile to unroll anyways since
+ unrolling would increase the number of branch instructions
+ executed. */
+ if (loop_dump_stream)
+ fprintf (loop_dump_stream,
+ "Unrolling failure: final conditional branch not to loop start\n");
+ return;
+ }
+
/* Allocate a translation table for the labels and insn numbers.
They will be filled in as we copy the insns in the loop. */
@@ -663,13 +710,16 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
for (insn = copy_start; insn != loop_end; insn = NEXT_INSN (insn))
{
+ rtx note;
+
if (GET_CODE (insn) == CODE_LABEL)
local_label[CODE_LABEL_NUMBER (insn)] = 1;
else if (GET_CODE (insn) == JUMP_INSN)
{
if (JUMP_LABEL (insn))
- map->label_map[CODE_LABEL_NUMBER (JUMP_LABEL (insn))]
- = JUMP_LABEL (insn);
+ set_label_in_map (map,
+ CODE_LABEL_NUMBER (JUMP_LABEL (insn)),
+ JUMP_LABEL (insn));
else if (GET_CODE (PATTERN (insn)) == ADDR_VEC
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC)
{
@@ -681,10 +731,15 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
for (i = 0; i < len; i++)
{
label = XEXP (XVECEXP (pat, diff_vec_p, i), 0);
- map->label_map[CODE_LABEL_NUMBER (label)] = label;
+ set_label_in_map (map,
+ CODE_LABEL_NUMBER (label),
+ label);
}
}
}
+ else if ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)))
+ set_label_in_map (map, CODE_LABEL_NUMBER (XEXP (note, 0)),
+ XEXP (note, 0));
}
/* Allocate space for the insn map. */
@@ -743,12 +798,37 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
if (copy_start == loop_start)
copy_start_luid++;
+ /* If a pseudo's lifetime is entirely contained within this loop, then we
+ can use a different pseudo in each unrolled copy of the loop. This
+ results in better code. */
for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; ++j)
- if (regno_first_uid[j] > 0 && regno_first_uid[j] <= max_uid_for_loop
- && uid_luid[regno_first_uid[j]] >= copy_start_luid
- && regno_last_uid[j] > 0 && regno_last_uid[j] <= max_uid_for_loop
- && uid_luid[regno_last_uid[j]] <= copy_end_luid)
- local_regno[j] = 1;
+ if (REGNO_FIRST_UID (j) > 0 && REGNO_FIRST_UID (j) <= max_uid_for_loop
+ && uid_luid[REGNO_FIRST_UID (j)] >= copy_start_luid
+ && REGNO_LAST_UID (j) > 0 && REGNO_LAST_UID (j) <= max_uid_for_loop
+ && uid_luid[REGNO_LAST_UID (j)] <= copy_end_luid)
+ {
+ /* However, we must also check for loop-carried dependencies.
+ If the value the pseudo has at the end of iteration X is
+ used by iteration X+1, then we can not use a different pseudo
+ for each unrolled copy of the loop. */
+ /* A pseudo is safe if regno_first_uid is a set, and this
+ set dominates all instructions from regno_first_uid to
+ regno_last_uid. */
+ /* ??? This check is simplistic. We would get better code if
+ this check was more sophisticated. */
+ if (set_dominates_use (j, REGNO_FIRST_UID (j), REGNO_LAST_UID (j),
+ copy_start, copy_end))
+ local_regno[j] = 1;
+
+ if (loop_dump_stream)
+ {
+ if (local_regno[j])
+ fprintf (loop_dump_stream, "Marked reg %d as local\n", j);
+ else
+ fprintf (loop_dump_stream, "Did not mark reg %d as local\n",
+ j);
+ }
+ }
}
/* If this loop requires exit tests when unrolled, check to see if we
@@ -780,7 +860,7 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
if (precondition_loop_p (&initial_value, &final_value, &increment,
loop_start, loop_end))
{
- register rtx diff, temp;
+ register rtx diff ;
enum machine_mode mode;
rtx *labels;
int abs_inc, neg_inc;
@@ -853,18 +933,23 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
for (i = 0; i < unroll_number; i++)
labels[i] = gen_label_rtx ();
- /* Check for the case where the initial value is greater than or equal
- to the final value. In that case, we want to execute exactly
- one loop iteration. The code below will fail for this case. */
+ /* Check for the case where the initial value is greater than or
+ equal to the final value. In that case, we want to execute
+ exactly one loop iteration. The code below will fail for this
+ case. This check does not apply if the loop has a NE
+ comparison at the end. */
- emit_cmp_insn (initial_value, final_value, neg_inc ? LE : GE,
- NULL_RTX, mode, 0, 0);
- if (neg_inc)
- emit_jump_insn (gen_ble (labels[1]));
- else
- emit_jump_insn (gen_bge (labels[1]));
- JUMP_LABEL (get_last_insn ()) = labels[1];
- LABEL_NUSES (labels[1])++;
+ if (loop_comparison_code != NE)
+ {
+ emit_cmp_insn (initial_value, final_value, neg_inc ? LE : GE,
+ NULL_RTX, mode, 0, 0);
+ if (neg_inc)
+ emit_jump_insn (gen_ble (labels[1]));
+ else
+ emit_jump_insn (gen_bge (labels[1]));
+ JUMP_LABEL (get_last_insn ()) = labels[1];
+ LABEL_NUSES (labels[1])++;
+ }
/* Assuming the unroll_number is 4, and the increment is 2, then
for a negative increment: for a positive increment:
@@ -990,12 +1075,15 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
for (j = 0; j < max_labelno; j++)
if (local_label[j])
- map->label_map[j] = gen_label_rtx ();
+ set_label_in_map (map, j, gen_label_rtx ());
for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)
if (local_regno[j])
- map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
-
+ {
+ map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
+ record_base_value (REGNO (map->reg_map[j]),
+ regno_reg_rtx[j], 0);
+ }
/* The last copy needs the compare/branch insns at the end,
so reset copy_end here if the loop ends with a conditional
branch. */
@@ -1039,6 +1127,13 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
/* Set unroll type to MODULO now. */
unroll_type = UNROLL_MODULO;
loop_preconditioned = 1;
+
+#ifdef HAIFA
+ /* Fix the initial value for the loop as needed. */
+ if (loop_n_iterations <= 0)
+ loop_start_value [uid_loop_num [INSN_UID (loop_start)]]
+ = initial_value;
+#endif
}
}
@@ -1053,6 +1148,13 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
/* At this point, we are guaranteed to unroll the loop. */
+ /* Keep track of the unroll factor for each loop. */
+ if (unroll_type == UNROLL_COMPLETELY)
+ loop_unroll_factor [uid_loop_num [INSN_UID (loop_start)]] = -1;
+ else
+ loop_unroll_factor [uid_loop_num [INSN_UID (loop_start)]] = unroll_number;
+
+
/* For each biv and giv, determine whether it can be safely split into
a different variable for each unrolled copy of the loop body.
We precalculate and save this info here, since computing it is
@@ -1105,6 +1207,10 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
#endif
}
+ /* Use our current register alignment and pointer flags. */
+ map->regno_pointer_flag = regno_pointer_flag;
+ map->regno_pointer_align = regno_pointer_align;
+
/* If the loop is being partially unrolled, and the iteration variables
are being split, and are being renamed for the split, then must fix up
the compare/jump instruction at the end of the loop to refer to the new
@@ -1131,11 +1237,15 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
for (j = 0; j < max_labelno; j++)
if (local_label[j])
- map->label_map[j] = gen_label_rtx ();
+ set_label_in_map (map, j, gen_label_rtx ());
for (j = FIRST_PSEUDO_REGISTER; j < max_reg_before_loop; j++)
if (local_regno[j])
- map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
+ {
+ map->reg_map[j] = gen_reg_rtx (GET_MODE (regno_reg_rtx[j]));
+ record_base_value (REGNO (map->reg_map[j]),
+ regno_reg_rtx[j], 0);
+ }
/* If loop starts with a branch to the test, then fix it so that
it points to the test of the first unrolled copy of the loop. */
@@ -1144,9 +1254,10 @@ unroll_loop (loop_end, insn_count, loop_start, end_insert_before,
insn = PREV_INSN (copy_start);
pattern = PATTERN (insn);
- tem = map->label_map[CODE_LABEL_NUMBER
- (XEXP (SET_SRC (pattern), 0))];
- SET_SRC (pattern) = gen_rtx (LABEL_REF, VOIDmode, tem);
+ tem = get_label_from_map (map,
+ CODE_LABEL_NUMBER
+ (XEXP (SET_SRC (pattern), 0)));
+ SET_SRC (pattern) = gen_rtx_LABEL_REF (VOIDmode, tem);
/* Set the jump label so that it can be used by later loop unrolling
passes. */
@@ -1228,9 +1339,13 @@ precondition_loop_p (initial_value, final_value, increment, loop_start,
*final_value = GEN_INT (loop_n_iterations);
if (loop_dump_stream)
- fprintf (loop_dump_stream,
- "Preconditioning: Success, number of iterations known, %d.\n",
- loop_n_iterations);
+ {
+ fputs ("Preconditioning: Success, number of iterations known, ",
+ loop_dump_stream);
+ fprintf (loop_dump_stream, HOST_WIDE_INT_PRINT_DEC,
+ loop_n_iterations);
+ fputs (".\n", loop_dump_stream);
+ }
return 1;
}
@@ -1319,7 +1434,7 @@ precondition_loop_p (initial_value, final_value, increment, loop_start,
/* Fail if loop_iteration_var is not live before loop_start, since we need
to test its value in the preconditioning code. */
- if (uid_luid[regno_first_uid[REGNO (loop_iteration_var)]]
+ if (uid_luid[REGNO_FIRST_UID (REGNO (loop_iteration_var))]
> INSN_LUID (loop_start))
{
if (loop_dump_stream)
@@ -1370,6 +1485,7 @@ init_reg_map (map, maxregnum)
to the iv. This procedure reconstructs the pattern computing the iv;
verifying that all operands are of the proper form.
+ PATTERN must be the result of single_set.
The return value is the amount that the giv is incremented by. */
static rtx
@@ -1412,11 +1528,22 @@ calculate_giv_inc (pattern, src_insn, regno)
one of the LO_SUM rtx. */
if (GET_CODE (increment) == LO_SUM)
increment = XEXP (increment, 1);
+
+ /* Some ports store large constants in memory and add a REG_EQUAL
+ note to the store insn. */
+ else if (GET_CODE (increment) == MEM)
+ {
+ rtx note = find_reg_note (src_insn, REG_EQUAL, 0);
+ if (note)
+ increment = XEXP (note, 0);
+ }
+
else if (GET_CODE (increment) == IOR
- || GET_CODE (increment) == ASHIFT)
+ || GET_CODE (increment) == ASHIFT
+ || GET_CODE (increment) == PLUS)
{
/* The rs6000 port loads some constants with IOR.
- The alpha port loads some constants with ASHIFT. */
+ The alpha port loads some constants with ASHIFT and PLUS. */
rtx second_part = XEXP (increment, 1);
enum rtx_code code = GET_CODE (increment);
@@ -1431,6 +1558,8 @@ calculate_giv_inc (pattern, src_insn, regno)
if (code == IOR)
increment = GEN_INT (INTVAL (increment) | INTVAL (second_part));
+ else if (code == PLUS)
+ increment = GEN_INT (INTVAL (increment) + INTVAL (second_part));
else
increment = GEN_INT (INTVAL (increment) << INTVAL (second_part));
}
@@ -1534,9 +1663,11 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
rtx start_label, loop_end, insert_before, copy_notes_from;
{
rtx insn, pattern;
- rtx tem, copy;
+ rtx set, tem, copy;
int dest_reg_was_split, i;
+#ifdef HAVE_cc0
rtx cc0_insn = 0;
+#endif
rtx final_label = 0;
rtx giv_inc, giv_dest_reg, giv_src_reg;
@@ -1549,10 +1680,11 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
if (! last_iteration)
{
final_label = gen_label_rtx ();
- map->label_map[CODE_LABEL_NUMBER (start_label)] = final_label;
+ set_label_in_map (map, CODE_LABEL_NUMBER (start_label),
+ final_label);
}
else
- map->label_map[CODE_LABEL_NUMBER (start_label)] = start_label;
+ set_label_in_map (map, CODE_LABEL_NUMBER (start_label), start_label);
start_sequence ();
@@ -1578,15 +1710,15 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
Do this before splitting the giv, since that may map the
SET_DEST to a new register. */
- if (GET_CODE (pattern) == SET
- && GET_CODE (SET_DEST (pattern)) == REG
- && addr_combined_regs[REGNO (SET_DEST (pattern))])
+ if ((set = single_set (insn))
+ && GET_CODE (SET_DEST (set)) == REG
+ && addr_combined_regs[REGNO (SET_DEST (set))])
{
struct iv_class *bl;
struct induction *v, *tv;
- int regno = REGNO (SET_DEST (pattern));
+ int regno = REGNO (SET_DEST (set));
- v = addr_combined_regs[REGNO (SET_DEST (pattern))];
+ v = addr_combined_regs[REGNO (SET_DEST (set))];
bl = reg_biv_class[REGNO (v->src_reg)];
/* Although the giv_inc amount is not needed here, we must call
@@ -1595,17 +1727,22 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
we might accidentally delete insns generated immediately
below by emit_unrolled_add. */
- giv_inc = calculate_giv_inc (pattern, insn, regno);
+ giv_inc = calculate_giv_inc (set, insn, regno);
/* Now find all address giv's that were combined with this
giv 'v'. */
for (tv = bl->giv; tv; tv = tv->next_iv)
if (tv->giv_type == DEST_ADDR && tv->same == v)
{
- int this_giv_inc = INTVAL (giv_inc);
+ int this_giv_inc;
+
+ /* If this DEST_ADDR giv was not split, then ignore it. */
+ if (*tv->location != tv->dest_reg)
+ continue;
/* Scale this_giv_inc if the multiplicative factors of
the two givs are different. */
+ this_giv_inc = INTVAL (giv_inc);
if (tv->mult_val != v->mult_val)
this_giv_inc = (this_giv_inc / INTVAL (v->mult_val)
* INTVAL (tv->mult_val));
@@ -1630,7 +1767,7 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
/* Check for shared address givs, and avoid
incrementing the shared pseudo reg more than
once. */
- if (! tv->same_insn)
+ if (! tv->same_insn && ! tv->shared)
{
/* tv->dest_reg may actually be a (PLUS (REG)
(CONST)) here, so we must call plus_constant
@@ -1664,11 +1801,11 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
dest_reg_was_split = 0;
- if (GET_CODE (pattern) == SET
- && GET_CODE (SET_DEST (pattern)) == REG
- && splittable_regs[REGNO (SET_DEST (pattern))])
+ if ((set = single_set (insn))
+ && GET_CODE (SET_DEST (set)) == REG
+ && splittable_regs[REGNO (SET_DEST (set))])
{
- int regno = REGNO (SET_DEST (pattern));
+ int regno = REGNO (SET_DEST (set));
dest_reg_was_split = 1;
@@ -1676,9 +1813,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
already computed above. */
if (giv_inc == 0)
- giv_inc = calculate_giv_inc (pattern, insn, regno);
- giv_dest_reg = SET_DEST (pattern);
- giv_src_reg = SET_DEST (pattern);
+ giv_inc = calculate_giv_inc (set, insn, regno);
+ giv_dest_reg = SET_DEST (set);
+ giv_src_reg = SET_DEST (set);
if (unroll_type == UNROLL_COMPLETELY)
{
@@ -1756,6 +1893,12 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
tem = gen_reg_rtx (GET_MODE (giv_src_reg));
giv_dest_reg = tem;
map->reg_map[regno] = tem;
+ record_base_value (REGNO (tem),
+ giv_inc == const0_rtx
+ ? giv_src_reg
+ : gen_rtx_PLUS (GET_MODE (giv_src_reg),
+ giv_src_reg, giv_inc),
+ 1);
}
else
map->reg_map[regno] = giv_src_reg;
@@ -1831,8 +1974,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
if (invert_exp (pattern, copy))
{
if (! redirect_exp (&pattern,
- map->label_map[CODE_LABEL_NUMBER
- (JUMP_LABEL (insn))],
+ get_label_from_map (map,
+ CODE_LABEL_NUMBER
+ (JUMP_LABEL (insn))),
exit_label, copy))
abort ();
}
@@ -1849,8 +1993,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
emit_label_after (lab, jmp);
LABEL_NUSES (lab) = 0;
if (! redirect_exp (&pattern,
- map->label_map[CODE_LABEL_NUMBER
- (JUMP_LABEL (insn))],
+ get_label_from_map (map,
+ CODE_LABEL_NUMBER
+ (JUMP_LABEL (insn))),
lab, copy))
abort ();
}
@@ -1871,9 +2016,9 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
/* Can't use the label_map for every insn, since this may be
the backward branch, and hence the label was not mapped. */
- if (GET_CODE (pattern) == SET)
+ if ((set = single_set (copy)))
{
- tem = SET_SRC (pattern);
+ tem = SET_SRC (set);
if (GET_CODE (tem) == LABEL_REF)
label = XEXP (tem, 0);
else if (GET_CODE (tem) == IF_THEN_ELSE)
@@ -1893,7 +2038,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
for a switch statement. This label must have been mapped,
so just use the label_map to get the new jump label. */
JUMP_LABEL (copy)
- = map->label_map[CODE_LABEL_NUMBER (JUMP_LABEL (insn))];
+ = get_label_from_map (map,
+ CODE_LABEL_NUMBER (JUMP_LABEL (insn)));
}
/* If this is a non-local jump, then must increase the label
@@ -1950,8 +2096,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
/* Because the USAGE information potentially contains objects other
than hard registers, we need to copy it. */
- CALL_INSN_FUNCTION_USAGE (copy) =
- copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn), map);
+ CALL_INSN_FUNCTION_USAGE (copy)
+ = copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn), map);
#ifdef HAVE_cc0
if (cc0_insn)
@@ -1971,7 +2117,8 @@ copy_loop_body (copy_start, copy_end, map, exit_label, last_iteration,
if (insn != start_label)
{
- copy = emit_label (map->label_map[CODE_LABEL_NUMBER (insn)]);
+ copy = emit_label (get_label_from_map (map,
+ CODE_LABEL_NUMBER (insn)));
map->const_age++;
}
break;
@@ -2073,6 +2220,7 @@ back_branch_in_range_p (insn, loop_start, loop_end)
rtx loop_start, loop_end;
{
rtx p, q, target_insn;
+ rtx orig_loop_end = loop_end;
/* Stop before we get to the backward branch at the end of the loop. */
loop_end = prev_nonnote_insn (loop_end);
@@ -2084,8 +2232,10 @@ back_branch_in_range_p (insn, loop_start, loop_end)
while (INSN_DELETED_P (insn))
insn = NEXT_INSN (insn);
- /* Check for the case where insn is the last insn in the loop. */
- if (insn == loop_end)
+ /* Check for the case where insn is the last insn in the loop. Deal
+ with the case where INSN was a deleted loop test insn, in which case
+ it will now be the NOTE_LOOP_END. */
+ if (insn == loop_end || insn == orig_loop_end)
return 0;
for (p = NEXT_INSN (insn); p != loop_end; p = NEXT_INSN (p))
@@ -2136,7 +2286,7 @@ fold_rtx_mult_add (mult1, mult2, add1, mode)
mult_res = simplify_binary_operation (MULT, mode, mult1, mult2);
if (! mult_res)
- mult_res = gen_rtx (MULT, mode, mult1, mult2);
+ mult_res = gen_rtx_MULT (mode, mult1, mult2);
/* Again, put the constant second. */
if (GET_CODE (add1) == CONST_INT)
@@ -2148,7 +2298,7 @@ fold_rtx_mult_add (mult1, mult2, add1, mode)
result = simplify_binary_operation (PLUS, mode, add1, mult_res);
if (! result)
- result = gen_rtx (PLUS, mode, add1, mult_res);
+ result = gen_rtx_PLUS (mode, add1, mult_res);
return result;
}
@@ -2169,7 +2319,7 @@ biv_total_increment (bl, loop_start, loop_end)
/* For increment, must check every instruction that sets it. Each
instruction must be executed only once each time through the loop.
- To verify this, we check that the the insn is always executed, and that
+ To verify this, we check that the insn is always executed, and that
there are no backward branches after the insn that branch to before it.
Also, the insn must have a mult_val of one (to make sure it really is
an increment). */
@@ -2194,13 +2344,15 @@ biv_total_increment (bl, loop_start, loop_end)
Initial_value and/or increment are set to zero if their values could not
be calculated. */
-static void
+void
iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
rtx iteration_var, *initial_value, *increment;
rtx loop_start, loop_end;
{
struct iv_class *bl;
- struct induction *v, *b;
+#if 0
+ struct induction *v;
+#endif
/* Clear the result values, in case no answer can be found. */
*initial_value = 0;
@@ -2219,14 +2371,16 @@ iteration_info (iteration_var, initial_value, increment, loop_start, loop_end)
"Loop unrolling: No reg_iv_type entry for iteration var.\n");
return;
}
- /* Reject iteration variables larger than the host long size, since they
+
+ /* Reject iteration variables larger than the host wide int size, since they
could result in a number of iterations greater than the range of our
- `unsigned long' variable loop_n_iterations. */
- else if (GET_MODE_BITSIZE (GET_MODE (iteration_var)) > HOST_BITS_PER_LONG)
+ `unsigned HOST_WIDE_INT' variable loop_n_iterations. */
+ else if ((GET_MODE_BITSIZE (GET_MODE (iteration_var))
+ > HOST_BITS_PER_WIDE_INT))
{
if (loop_dump_stream)
fprintf (loop_dump_stream,
- "Loop unrolling: Iteration var rejected because mode larger than host long.\n");
+ "Loop unrolling: Iteration var rejected because mode too large.\n");
return;
}
else if (GET_MODE_CLASS (GET_MODE (iteration_var)) != MODE_INT)
@@ -2401,10 +2555,10 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
if (unroll_type != UNROLL_COMPLETELY
&& (loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]]
|| unroll_type == UNROLL_NAIVE)
- && (uid_luid[regno_last_uid[bl->regno]] >= INSN_LUID (loop_end)
+ && (uid_luid[REGNO_LAST_UID (bl->regno)] >= INSN_LUID (loop_end)
|| ! bl->init_insn
|| INSN_UID (bl->init_insn) >= max_uid_for_loop
- || (uid_luid[regno_first_uid[bl->regno]]
+ || (uid_luid[REGNO_FIRST_UID (bl->regno)]
< INSN_LUID (bl->init_insn))
|| reg_mentioned_p (bl->biv->dest_reg, SET_SRC (bl->init_set)))
&& ! (biv_final_value = final_biv_value (bl, loop_start, loop_end)))
@@ -2442,7 +2596,8 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
|| ! invariant_p (bl->initial_value)))
{
rtx tem = gen_reg_rtx (bl->biv->mode);
-
+
+ record_base_value (REGNO (tem), bl->biv->add_val, 0);
emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
loop_start);
@@ -2499,6 +2654,8 @@ find_splittable_regs (unroll_type, loop_start, loop_end, end_insert_before,
this insn will always be executed, no matter how the loop
exits. */
rtx tem = gen_reg_rtx (bl->biv->mode);
+ record_base_value (REGNO (tem), bl->biv->add_val, 0);
+
emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
loop_start);
emit_insn_before (gen_move_insn (bl->biv->src_reg,
@@ -2533,14 +2690,16 @@ verify_addresses (v, giv_inc, unroll_number)
rtx last_addr = plus_constant (v->dest_reg,
INTVAL (giv_inc) * (unroll_number - 1));
- /* First check to see if either address would fail. */
- if (! validate_change (v->insn, v->location, v->dest_reg, 0)
- || ! validate_change (v->insn, v->location, last_addr, 0))
+ /* First check to see if either address would fail. Handle the fact
+ that we have may have a match_dup. */
+ if (! validate_replace_rtx (*v->location, v->dest_reg, v->insn)
+ || ! validate_replace_rtx (*v->location, last_addr, v->insn))
ret = 0;
- /* Now put things back the way they were before. This will always
+ /* Now put things back the way they were before. This should always
succeed. */
- validate_change (v->insn, v->location, orig_addr, 0);
+ if (! validate_replace_rtx (*v->location, orig_addr, v->insn))
+ abort ();
return ret;
}
@@ -2613,15 +2772,19 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
&& (loop_number_exit_count[uid_loop_num[INSN_UID (loop_start)]]
|| unroll_type == UNROLL_NAIVE)
&& v->giv_type != DEST_ADDR
- && ((regno_first_uid[REGNO (v->dest_reg)] != INSN_UID (v->insn)
- /* Check for the case where the pseudo is set by a shift/add
- sequence, in which case the first insn setting the pseudo
- is the first insn of the shift/add sequence. */
- && (! (tem = find_reg_note (v->insn, REG_RETVAL, NULL_RTX))
- || (regno_first_uid[REGNO (v->dest_reg)]
- != INSN_UID (XEXP (tem, 0)))))
+ /* The next part is true if the pseudo is used outside the loop.
+ We assume that this is true for any pseudo created after loop
+ starts, because we don't have a reg_n_info entry for them. */
+ && (REGNO (v->dest_reg) >= max_reg_before_loop
+ || (REGNO_FIRST_UID (REGNO (v->dest_reg)) != INSN_UID (v->insn)
+ /* Check for the case where the pseudo is set by a shift/add
+ sequence, in which case the first insn setting the pseudo
+ is the first insn of the shift/add sequence. */
+ && (! (tem = find_reg_note (v->insn, REG_RETVAL, NULL_RTX))
+ || (REGNO_FIRST_UID (REGNO (v->dest_reg))
+ != INSN_UID (XEXP (tem, 0)))))
/* Line above always fails if INSN was moved by loop opt. */
- || (uid_luid[regno_last_uid[REGNO (v->dest_reg)]]
+ || (uid_luid[REGNO_LAST_UID (REGNO (v->dest_reg))]
>= INSN_LUID (loop_end)))
&& ! (final_value = v->final_value))
continue;
@@ -2674,6 +2837,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
{
rtx tem = gen_reg_rtx (bl->biv->mode);
+ record_base_value (REGNO (tem), bl->biv->add_val, 0);
emit_insn_before (gen_move_insn (tem, bl->biv->src_reg),
loop_start);
biv_initial_value = tem;
@@ -2715,6 +2879,7 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
|| GET_CODE (XEXP (value, 1)) != CONST_INT))
{
rtx tem = gen_reg_rtx (v->mode);
+ record_base_value (REGNO (tem), v->add_val, 0);
emit_iv_add_mult (bl->initial_value, v->mult_val,
v->add_val, tem, loop_start);
value = tem;
@@ -2733,16 +2898,9 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
what we want for split addr regs. We always create a new
register for the split addr giv, just to be safe. */
- /* ??? If there are multiple address givs which have been
- combined with the same dest_reg giv, then we may only need
- one new register for them. Pulling out constants below will
- catch some of the common cases of this. Currently, I leave
- the work of simplifying multiple address givs to the
- following cse pass. */
-
- /* As a special case, if we have multiple identical address givs
- within a single instruction, then we do use a single pseudo
- reg for both. This is necessary in case one is a match_dup
+ /* If we have multiple identical address givs within a
+ single instruction, then use a single pseudo reg for
+ both. This is necessary in case one is a match_dup
of the other. */
v->const_adjust = 0;
@@ -2755,12 +2913,35 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
"Sharing address givs in insn %d\n",
INSN_UID (v->insn));
}
+ /* If multiple address GIVs have been combined with the
+ same dest_reg GIV, do not create a new register for
+ each. */
+ else if (unroll_type != UNROLL_COMPLETELY
+ && v->giv_type == DEST_ADDR
+ && v->same && v->same->giv_type == DEST_ADDR
+ && v->same->unrolled
+ /* combine_givs_p may return true for some cases
+ where the add and mult values are not equal.
+ To share a register here, the values must be
+ equal. */
+ && rtx_equal_p (v->same->mult_val, v->mult_val)
+ && rtx_equal_p (v->same->add_val, v->add_val)
+ /* If the memory references have different modes,
+ then the address may not be valid and we must
+ not share registers. */
+ && verify_addresses (v, giv_inc, unroll_number))
+ {
+ v->dest_reg = v->same->dest_reg;
+ v->shared = 1;
+ }
else if (unroll_type != UNROLL_COMPLETELY)
{
/* If not completely unrolling the loop, then create a new
register to hold the split value of the DEST_ADDR giv.
Emit insn to initialize its value before loop start. */
- tem = gen_reg_rtx (v->mode);
+
+ rtx tem = gen_reg_rtx (v->mode);
+ record_base_value (REGNO (tem), v->add_val, 0);
/* If the address giv has a constant in its new_reg value,
then this constant can be pulled out and put in value,
@@ -2771,12 +2952,12 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
{
v->dest_reg
= plus_constant (tem, INTVAL (XEXP (v->new_reg,1)));
-
+
/* Only succeed if this will give valid addresses.
Try to validate both the first and the last
address resulting from loop unrolling, if
one fails, then can't do const elim here. */
- if (! verify_addresses (v, giv_inc, unroll_number))
+ if (verify_addresses (v, giv_inc, unroll_number))
{
/* Save the negative of the eliminated const, so
that we can calculate the dest_reg's increment
@@ -2802,6 +2983,10 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
if (v->dest_reg == tem
&& ! verify_addresses (v, giv_inc, unroll_number))
{
+ for (v2 = v->next_iv; v2; v2 = v2->next_iv)
+ if (v2->same_insn == v)
+ v2->same_insn = 0;
+
if (loop_dump_stream)
fprintf (loop_dump_stream,
"Invalid address for giv at insn %d\n",
@@ -2809,13 +2994,17 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
continue;
}
+ /* We set this after the address check, to guarantee that
+ the register will be initialized. */
+ v->unrolled = 1;
+
/* To initialize the new register, just move the value of
new_reg into it. This is not guaranteed to give a valid
instruction on machines with complex addressing modes.
If we can't recognize it, then delete it and emit insns
to calculate the value from scratch. */
- emit_insn_before (gen_rtx (SET, VOIDmode, tem,
- copy_rtx (v->new_reg)),
+ emit_insn_before (gen_rtx_SET (VOIDmode, tem,
+ copy_rtx (v->new_reg)),
loop_start);
if (recog_memoized (PREV_INSN (loop_start)) < 0)
{
@@ -2848,6 +3037,10 @@ find_splittable_givs (bl, unroll_type, loop_start, loop_end, increment,
if the resulting address would be invalid. */
if (! verify_addresses (v, giv_inc, unroll_number))
{
+ for (v2 = v->next_iv; v2; v2 = v2->next_iv)
+ if (v2->same_insn == v)
+ v2->same_insn = 0;
+
if (loop_dump_stream)
fprintf (loop_dump_stream,
"Invalid address for giv at insn %d\n",
@@ -2975,7 +3168,7 @@ reg_dead_after_loop (reg, loop_start, loop_end)
/* HACK: Must also search the loop fall through exit, create a label_ref
here which points to the loop_end, and append the loop_number_exit_labels
list to it. */
- label = gen_rtx (LABEL_REF, VOIDmode, loop_end);
+ label = gen_rtx_LABEL_REF (VOIDmode, loop_end);
LABEL_NEXTREF (label) = loop_number_exit_labels[this_loop_num];
for ( ; label; label = LABEL_NEXTREF (label))
@@ -3005,7 +3198,7 @@ reg_dead_after_loop (reg, loop_start, loop_end)
if (GET_CODE (PATTERN (insn)) == RETURN)
break;
else if (! simplejump_p (insn)
- /* Prevent infinite loop following infinite loops. */
+ /* Prevent infinite loop following infinite loops. */
|| jump_count++ > 20)
return 0;
else
@@ -3067,6 +3260,7 @@ final_biv_value (bl, loop_start, loop_end)
case it is needed later. */
tem = gen_reg_rtx (bl->biv->mode);
+ record_base_value (REGNO (tem), bl->biv->add_val, 0);
/* Make sure loop_end is not the last insn. */
if (NEXT_INSN (loop_end) == 0)
emit_note_after (NOTE_INSN_DELETED, loop_end);
@@ -3142,9 +3336,14 @@ final_giv_value (v, loop_start, loop_end)
determine whether giv's are replaceable so that we can use the
biv value here if it is not eliminable. */
+ /* We are emitting code after the end of the loop, so we must make
+ sure that bl->initial_value is still valid then. It will still
+ be valid if it is invariant. */
+
increment = biv_total_increment (bl, loop_start, loop_end);
- if (increment && invariant_p (increment))
+ if (increment && invariant_p (increment)
+ && invariant_p (bl->initial_value))
{
/* Can calculate the loop exit value of its biv as
(loop_n_iterations * increment) + initial_value */
@@ -3160,6 +3359,7 @@ final_giv_value (v, loop_start, loop_end)
/* Put the final biv value in tem. */
tem = gen_reg_rtx (bl->biv->mode);
+ record_base_value (REGNO (tem), bl->biv->add_val, 0);
emit_iv_add_mult (increment, GEN_INT (loop_n_iterations),
bl->initial_value, tem, insert_before);
@@ -3328,6 +3528,7 @@ loop_iterations (loop_start, loop_end)
loop_initial_value = initial_value;
loop_increment = increment;
loop_final_value = final_value;
+ loop_comparison_code = comparison_code;
if (increment == 0)
{
@@ -3492,6 +3693,10 @@ remap_split_bivs (x)
if (REGNO (x) < max_reg_before_loop
&& reg_iv_type[REGNO (x)] == BASIC_INDUCT)
return reg_biv_class[REGNO (x)]->biv->src_reg;
+ break;
+
+ default:
+ break;
}
fmt = GET_RTX_FORMAT (code);
@@ -3508,3 +3713,65 @@ remap_split_bivs (x)
}
return x;
}
+
+/* If FIRST_UID is a set of REGNO, and FIRST_UID dominates LAST_UID (e.g.
+ FIST_UID is always executed if LAST_UID is), then return 1. Otherwise
+ return 0. COPY_START is where we can start looking for the insns
+ FIRST_UID and LAST_UID. COPY_END is where we stop looking for these
+ insns.
+
+ If there is no JUMP_INSN between LOOP_START and FIRST_UID, then FIRST_UID
+ must dominate LAST_UID.
+
+ If there is a CODE_LABEL between FIRST_UID and LAST_UID, then FIRST_UID
+ may not dominate LAST_UID.
+
+ If there is no CODE_LABEL between FIRST_UID and LAST_UID, then FIRST_UID
+ must dominate LAST_UID. */
+
+int
+set_dominates_use (regno, first_uid, last_uid, copy_start, copy_end)
+ int regno;
+ int first_uid;
+ int last_uid;
+ rtx copy_start;
+ rtx copy_end;
+{
+ int passed_jump = 0;
+ rtx p = NEXT_INSN (copy_start);
+
+ while (INSN_UID (p) != first_uid)
+ {
+ if (GET_CODE (p) == JUMP_INSN)
+ passed_jump= 1;
+ /* Could not find FIRST_UID. */
+ if (p == copy_end)
+ return 0;
+ p = NEXT_INSN (p);
+ }
+
+ /* Verify that FIRST_UID is an insn that entirely sets REGNO. */
+ if (GET_RTX_CLASS (GET_CODE (p)) != 'i'
+ || ! dead_or_set_regno_p (p, regno))
+ return 0;
+
+ /* FIRST_UID is always executed. */
+ if (passed_jump == 0)
+ return 1;
+
+ while (INSN_UID (p) != last_uid)
+ {
+ /* If we see a CODE_LABEL between FIRST_UID and LAST_UID, then we
+ can not be sure that FIRST_UID dominates LAST_UID. */
+ if (GET_CODE (p) == CODE_LABEL)
+ return 0;
+ /* Could not find LAST_UID, but we reached the end of the loop, so
+ it must be safe. */
+ else if (p == copy_end)
+ return 1;
+ p = NEXT_INSN (p);
+ }
+
+ /* FIRST_UID is always executed if LAST_UID is executed. */
+ return 1;
+}
diff --git a/contrib/gcc/varasm.c b/contrib/gcc/varasm.c
index 12c935e..0055d68 100644
--- a/contrib/gcc/varasm.c
+++ b/contrib/gcc/varasm.c
@@ -1,5 +1,5 @@
/* Output variables, constants and external declarations, for GNU compiler.
- Copyright (C) 1987, 88, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 89, 92-97, 1998 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -26,13 +26,14 @@ Boston, MA 02111-1307, USA. */
We also output the assembler code for constants stored in memory
and are responsible for combining constants with the same value. */
-#include <stdio.h>
+#include "config.h"
+#include "system.h"
#include <setjmp.h>
/* #include <stab.h> */
-#include "config.h"
#include "rtl.h"
#include "tree.h"
#include "flags.h"
+#include "except.h"
#include "function.h"
#include "expr.h"
#include "output.h"
@@ -40,7 +41,9 @@ Boston, MA 02111-1307, USA. */
#include "regs.h"
#include "defaults.h"
#include "real.h"
-#include "bytecode.h"
+#include "toplev.h"
+#include "dbxout.h"
+#include "sdbout.h"
#include "obstack.h"
#include "c-pragma.h"
@@ -49,12 +52,26 @@ Boston, MA 02111-1307, USA. */
#include "xcoffout.h"
#endif
-#include <ctype.h>
+#ifndef TRAMPOLINE_ALIGNMENT
+#define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
+#endif
#ifndef ASM_STABS_OP
#define ASM_STABS_OP ".stabs"
#endif
+/* Define the prefix to use when check_memory_usage_flag is enable. */
+#ifdef NO_DOLLAR_IN_LABEL
+#ifdef NO_DOT_IN_LABEL
+#define CHKR_PREFIX "chkr_prefix_"
+#else /* !NO_DOT_IN_LABEL */
+#define CHKR_PREFIX "chkr."
+#endif
+#else /* !NO_DOLLAR_IN_LABEL */
+#define CHKR_PREFIX "chkr$"
+#endif
+#define CHKR_PREFIX_SIZE (sizeof (CHKR_PREFIX) - 1)
+
/* This macro gets just the user-specified name
out of the string in a SYMBOL_REF. On most machines,
we discard the * if any and that's all. */
@@ -69,6 +86,7 @@ extern FILE *asm_out_file;
/* The (assembler) name of the first globally-visible object output. */
char *first_global_object_name;
+char *weak_global_object_name;
extern struct obstack *current_obstack;
extern struct obstack *saveable_obstack;
@@ -121,9 +139,7 @@ struct constant_descriptor;
struct rtx_const;
struct pool_constant;
-static void bc_make_decl_rtl PROTO((tree, char *, int));
static char *strip_reg_name PROTO((char *));
-static void bc_output_ascii PROTO((FILE *, char *, int));
static int contains_pointers_p PROTO((tree));
static void decode_addr_const PROTO((tree, struct addr_const *));
static int const_hash PROTO((tree));
@@ -142,17 +158,31 @@ static int compare_constant_rtx PROTO((enum machine_mode, rtx,
static struct constant_descriptor *record_constant_rtx PROTO((enum machine_mode,
rtx));
static struct pool_constant *find_pool_constant PROTO((rtx));
+static void mark_constant_pool PROTO((void));
+static void mark_constants PROTO((rtx));
static int output_addressed_constants PROTO((tree));
-static void bc_assemble_integer PROTO((tree, int));
+static void output_after_function_constants PROTO((void));
static void output_constructor PROTO((tree, int));
+#ifdef ASM_OUTPUT_BSS
+static void asm_output_bss PROTO((FILE *, tree, char *, int, int));
+#endif
+#ifdef BSS_SECTION_ASM_OP
+#ifdef ASM_OUTPUT_ALIGNED_BSS
+static void asm_output_aligned_bss PROTO((FILE *, tree, char *, int, int));
+#endif
+#endif /* BSS_SECTION_ASM_OP */
+static enum in_section { no_section, in_text, in_data, in_named
+#ifdef BSS_SECTION_ASM_OP
+ , in_bss
+#endif
+#ifdef EH_FRAME_SECTION_ASM_OP
+ , in_eh_frame
+#endif
#ifdef EXTRA_SECTIONS
-static enum in_section {no_section, in_text, in_data, in_named, EXTRA_SECTIONS} in_section
- = no_section;
-#else
-static enum in_section {no_section, in_text, in_data, in_named} in_section
- = no_section;
+ , EXTRA_SECTIONS
#endif
+} in_section = no_section;
/* Return a non-zero value if DECL has a section attribute. */
#define IN_NAMED_SECTION(DECL) \
@@ -174,11 +204,7 @@ text_section ()
{
if (in_section != in_text)
{
- if (output_bytecode)
- bc_text ();
- else
- fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
-
+ fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
in_section = in_text;
}
}
@@ -190,21 +216,16 @@ data_section ()
{
if (in_section != in_data)
{
- if (output_bytecode)
- bc_data ();
- else
+ if (flag_shared_data)
{
- if (flag_shared_data)
- {
#ifdef SHARED_SECTION_ASM_OP
- fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
+ fprintf (asm_out_file, "%s\n", SHARED_SECTION_ASM_OP);
#else
- fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
+ fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
#endif
- }
- else
- fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
}
+ else
+ fprintf (asm_out_file, "%s\n", DATA_SECTION_ASM_OP);
in_section = in_data;
}
@@ -223,7 +244,7 @@ readonly_data_section ()
#endif
}
-/* Determine if we're in the text section. */
+/* Determine if we're in the text section. */
int
in_text_section ()
@@ -231,37 +252,162 @@ in_text_section ()
return in_section == in_text;
}
+/* Determine if we're in the data section. */
+
+int
+in_data_section ()
+{
+ return in_section == in_data;
+}
+
/* Tell assembler to change to section NAME for DECL.
If DECL is NULL, just switch to section NAME.
- If NAME is NULL, get the name from DECL. */
+ If NAME is NULL, get the name from DECL.
+ If RELOC is 1, the initializer for DECL contains relocs. */
void
-named_section (decl, name)
+named_section (decl, name, reloc)
tree decl;
char *name;
+ int reloc;
{
if (decl != NULL_TREE
- && (TREE_CODE (decl) != FUNCTION_DECL && TREE_CODE (decl) != VAR_DECL))
+ && TREE_CODE_CLASS (TREE_CODE (decl)) != 'd')
abort ();
if (name == NULL)
name = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
if (in_section != in_named || strcmp (name, in_named_name))
{
- in_named_name = name;
- in_section = in_named;
-
#ifdef ASM_OUTPUT_SECTION_NAME
- ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name);
+ ASM_OUTPUT_SECTION_NAME (asm_out_file, decl, name, reloc);
#else
/* Section attributes are not supported if this macro isn't provided -
some host formats don't support them at all. The front-end should
already have flagged this as an error. */
abort ();
#endif
+
+ in_named_name = obstack_alloc (&permanent_obstack, strlen (name) + 1);
+ strcpy (in_named_name, name);
+ in_section = in_named;
+ }
+}
+
+#ifdef ASM_OUTPUT_SECTION_NAME
+#ifndef UNIQUE_SECTION
+#define UNIQUE_SECTION(DECL,RELOC) \
+do { \
+ int len; \
+ char *name, *string; \
+ \
+ name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (DECL)); \
+ /* Strip off any encoding in name. */ \
+ STRIP_NAME_ENCODING (name, name); \
+ \
+ len = strlen (name) + 1; \
+ string = alloca (len + 1); \
+ sprintf (string, ".%s", name); \
+ \
+ DECL_SECTION_NAME (DECL) = build_string (len, string); \
+} while (0)
+#endif
+#ifndef UNIQUE_SECTION_P
+#define UNIQUE_SECTION_P(DECL) 0
+#endif
+#endif
+
+#ifdef BSS_SECTION_ASM_OP
+
+/* Tell the assembler to switch to the bss section. */
+
+void
+bss_section ()
+{
+ if (in_section != in_bss)
+ {
+#ifdef SHARED_BSS_SECTION_ASM_OP
+ if (flag_shared_data)
+ fprintf (asm_out_file, "%s\n", SHARED_BSS_SECTION_ASM_OP);
+ else
+#endif
+ fprintf (asm_out_file, "%s\n", BSS_SECTION_ASM_OP);
+
+ in_section = in_bss;
}
}
+#ifdef ASM_OUTPUT_BSS
+
+/* Utility function for ASM_OUTPUT_BSS for targets to use if
+ they don't support alignments in .bss.
+ ??? It is believed that this function will work in most cases so such
+ support is localized here. */
+
+static void
+asm_output_bss (file, decl, name, size, rounded)
+ FILE *file;
+ tree decl;
+ char *name;
+ int size, rounded;
+{
+ ASM_GLOBALIZE_LABEL (file, name);
+ bss_section ();
+#ifdef ASM_DECLARE_OBJECT_NAME
+ last_assemble_variable_decl = decl;
+ ASM_DECLARE_OBJECT_NAME (file, name, decl);
+#else
+ /* Standard thing is just output label for the object. */
+ ASM_OUTPUT_LABEL (file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+ ASM_OUTPUT_SKIP (file, rounded);
+}
+
+#endif
+
+#ifdef ASM_OUTPUT_ALIGNED_BSS
+
+/* Utility function for targets to use in implementing
+ ASM_OUTPUT_ALIGNED_BSS.
+ ??? It is believed that this function will work in most cases so such
+ support is localized here. */
+
+static void
+asm_output_aligned_bss (file, decl, name, size, align)
+ FILE *file;
+ tree decl;
+ char *name;
+ int size, align;
+{
+ ASM_GLOBALIZE_LABEL (file, name);
+ bss_section ();
+ ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));
+#ifdef ASM_DECLARE_OBJECT_NAME
+ last_assemble_variable_decl = decl;
+ ASM_DECLARE_OBJECT_NAME (file, name, decl);
+#else
+ /* Standard thing is just output label for the object. */
+ ASM_OUTPUT_LABEL (file, name);
+#endif /* ASM_DECLARE_OBJECT_NAME */
+ ASM_OUTPUT_SKIP (file, size ? size : 1);
+}
+
+#endif
+
+#endif /* BSS_SECTION_ASM_OP */
+
+#ifdef EH_FRAME_SECTION_ASM_OP
+void
+eh_frame_section ()
+{
+ if (in_section != in_eh_frame)
+ {
+ fprintf (asm_out_file, "%s\n", EH_FRAME_SECTION_ASM_OP);
+ in_section = in_eh_frame;
+ }
+}
+#endif
+
/* Switch to the section for function DECL.
If DECL is NULL_TREE, switch to the text section.
@@ -274,9 +420,66 @@ function_section (decl)
{
if (decl != NULL_TREE
&& DECL_SECTION_NAME (decl) != NULL_TREE)
- named_section (decl, (char *) 0);
- else
- text_section ();
+ named_section (decl, (char *) 0, 0);
+ else
+ text_section ();
+}
+
+/* Switch to section for variable DECL.
+
+ RELOC is the `reloc' argument to SELECT_SECTION. */
+
+void
+variable_section (decl, reloc)
+ tree decl;
+ int reloc;
+{
+ if (IN_NAMED_SECTION (decl))
+ named_section (decl, NULL, reloc);
+ else
+ {
+ /* C++ can have const variables that get initialized from constructors,
+ and thus can not be in a readonly section. We prevent this by
+ verifying that the initial value is constant for objects put in a
+ readonly section.
+
+ error_mark_node is used by the C front end to indicate that the
+ initializer has not been seen yet. In this case, we assume that
+ the initializer must be constant.
+
+ C++ uses error_mark_node for variables that have complicated
+ initializers, but these variables go in BSS so we won't be called
+ for them. */
+
+#ifdef SELECT_SECTION
+ SELECT_SECTION (decl, reloc);
+#else
+ if (DECL_READONLY_SECTION (decl, reloc))
+ readonly_data_section ();
+ else
+ data_section ();
+#endif
+ }
+}
+
+/* Tell assembler to switch to the section for the exception handling
+ table. */
+
+void
+exception_section ()
+{
+#if defined (EXCEPTION_SECTION)
+ EXCEPTION_SECTION ();
+#else
+#ifdef ASM_OUTPUT_SECTION_NAME
+ named_section (NULL_TREE, ".gcc_except_table", 0);
+#else
+ if (flag_pic)
+ data_section ();
+ else
+ readonly_data_section ();
+#endif
+#endif
}
/* Create the rtl to represent a function, for a function definition.
@@ -288,16 +491,7 @@ make_function_rtl (decl)
tree decl;
{
char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-
- if (output_bytecode)
- {
- if (DECL_RTL (decl) == 0)
- DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
-
- /* Record that at least one function has been defined. */
- function_defined = 1;
- return;
- }
+ char *new_name = name;
/* Rename a nested function to avoid conflicts. */
if (decl_function_context (decl) != 0
@@ -311,12 +505,26 @@ make_function_rtl (decl)
name = obstack_copy0 (saveable_obstack, label, strlen (label));
var_labelno++;
}
+ else
+ {
+ /* When -fprefix-function-name is used, every function name is
+ prefixed. Even static functions are prefixed because they
+ could be declared latter. Note that a nested function name
+ is not prefixed. */
+ if (flag_prefix_function_name)
+ {
+ new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE + 1);
+ strcpy (new_name, CHKR_PREFIX);
+ strcpy (new_name + CHKR_PREFIX_SIZE, name);
+ name = obstack_copy0 (saveable_obstack, new_name, strlen (new_name));
+ }
+ }
if (DECL_RTL (decl) == 0)
{
DECL_RTL (decl)
- = gen_rtx (MEM, DECL_MODE (decl),
- gen_rtx (SYMBOL_REF, Pmode, name));
+ = gen_rtx_MEM (DECL_MODE (decl),
+ gen_rtx_SYMBOL_REF (Pmode, name));
/* Optionally set flags or add text to the name to record information
such as that it is a function name. If the name is changed, the macro
@@ -325,54 +533,25 @@ make_function_rtl (decl)
ENCODE_SECTION_INFO (decl);
#endif
}
+ else
+ {
+ /* ??? Another way to do this would be to do what halfpic.c does
+ and maintain a hashed table of such critters. */
+ /* ??? Another way to do this would be to pass a flag bit to
+ ENCODE_SECTION_INFO saying whether this is a new decl or not. */
+ /* Let the target reassign the RTL if it wants.
+ This is necessary, for example, when one machine specific
+ decl attribute overrides another. */
+#ifdef REDO_SECTION_INFO_P
+ if (REDO_SECTION_INFO_P (decl))
+ ENCODE_SECTION_INFO (decl);
+#endif
+ }
/* Record at least one function has been defined. */
function_defined = 1;
}
-/* Create the DECL_RTL for a declaration for a static or external
- variable or static or external function.
- ASMSPEC, if not 0, is the string which the user specified
- as the assembler symbol name.
- TOP_LEVEL is nonzero if this is a file-scope variable.
- This is never called for PARM_DECLs. */
-
-static void
-bc_make_decl_rtl (decl, asmspec, top_level)
- tree decl;
- char *asmspec;
- int top_level;
-{
- register char *name = TREE_STRING_POINTER (DECL_ASSEMBLER_NAME (decl));
-
- if (DECL_RTL (decl) == 0)
- {
- /* Print an error message for register variables. */
- if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL)
- error ("function declared `register'");
- else if (DECL_REGISTER (decl))
- error ("global register variables not supported in the interpreter");
-
- /* Handle ordinary static variables and functions. */
- if (DECL_RTL (decl) == 0)
- {
- /* Can't use just the variable's own name for a variable
- whose scope is less than the whole file.
- Concatenate a distinguishing number. */
- if (!top_level && !DECL_EXTERNAL (decl) && asmspec == 0)
- {
- char *label;
-
- ASM_FORMAT_PRIVATE_NAME (label, name, var_labelno);
- name = obstack_copy0 (saveable_obstack, label, strlen (label));
- var_labelno++;
- }
-
- DECL_RTL (decl) = bc_gen_rtx (name, 0, (struct bc_label *) 0);
- }
- }
-}
-
/* Given NAME, a putative register name, discard any customary prefixes. */
static char *
@@ -465,12 +644,6 @@ make_decl_rtl (decl, asmspec, top_level)
register char *name = 0;
int reg_number;
- if (output_bytecode)
- {
- bc_make_decl_rtl (decl, asmspec, top_level);
- return;
- }
-
reg_number = decode_reg_name (asmspec);
if (DECL_ASSEMBLER_NAME (decl) != NULL_TREE)
@@ -489,33 +662,35 @@ make_decl_rtl (decl, asmspec, top_level)
same DECL node. Don't discard the RTL already made. */
if (DECL_RTL (decl) == 0)
{
- DECL_RTL (decl) = 0;
-
/* First detect errors in declaring global registers. */
- if (DECL_REGISTER (decl) && reg_number == -1)
+ if (TREE_CODE (decl) != FUNCTION_DECL
+ && DECL_REGISTER (decl) && reg_number == -1)
error_with_decl (decl,
"register name not specified for `%s'");
- else if (DECL_REGISTER (decl) && reg_number < 0)
+ else if (TREE_CODE (decl) != FUNCTION_DECL
+ && DECL_REGISTER (decl) && reg_number < 0)
error_with_decl (decl,
"invalid register name for `%s'");
- else if ((reg_number >= 0 || reg_number == -3) && ! DECL_REGISTER (decl))
+ else if ((reg_number >= 0 || reg_number == -3)
+ && (TREE_CODE (decl) == FUNCTION_DECL
+ && ! DECL_REGISTER (decl)))
error_with_decl (decl,
"register name given for non-register variable `%s'");
- else if (DECL_REGISTER (decl) && TREE_CODE (decl) == FUNCTION_DECL)
- error ("function declared `register'");
- else if (DECL_REGISTER (decl) && TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
- error_with_decl (decl, "data type of `%s' isn't suitable for a register");
- else if (DECL_REGISTER (decl)
- && ! HARD_REGNO_MODE_OK (reg_number, TYPE_MODE (TREE_TYPE (decl))))
- error_with_decl (decl, "register number for `%s' isn't suitable for the data type");
+ else if (TREE_CODE (decl) != FUNCTION_DECL
+ && DECL_REGISTER (decl)
+ && TYPE_MODE (TREE_TYPE (decl)) == BLKmode)
+ error_with_decl (decl,
+ "data type of `%s' isn't suitable for a register");
+ else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl)
+ && ! HARD_REGNO_MODE_OK (reg_number,
+ TYPE_MODE (TREE_TYPE (decl))))
+ error_with_decl (decl,
+ "register number for `%s' isn't suitable for data type");
/* Now handle properly declared static register variables. */
- else if (DECL_REGISTER (decl))
+ else if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
{
int nregs;
-#if 0 /* yylex should print the warning for this */
- if (pedantic)
- pedwarn ("ANSI C forbids global register variables");
-#endif
+
if (DECL_INITIAL (decl) != 0 && top_level)
{
DECL_INITIAL (decl) = 0;
@@ -534,7 +709,7 @@ make_decl_rtl (decl, asmspec, top_level)
kludge to avoid setting DECL_RTL to frame_pointer_rtx. */
DECL_RTL (decl)
- = gen_rtx (REG, DECL_MODE (decl), FIRST_PSEUDO_REGISTER);
+ = gen_rtx_REG (DECL_MODE (decl), FIRST_PSEUDO_REGISTER);
REGNO (DECL_RTL (decl)) = reg_number;
REG_USERVAR_P (DECL_RTL (decl)) = 1;
@@ -547,24 +722,13 @@ make_decl_rtl (decl, asmspec, top_level)
globalize_reg (reg_number + --nregs);
}
}
- /* Specifying a section attribute on an uninitialized variable does not
- (and cannot) cause it to be put in the given section. The linker
- can only put initialized objects in specific sections, everything
- else goes in bss for the linker to sort out later (otherwise the
- linker would give a duplicate definition error for each compilation
- unit that behaved thusly). So warn the user. */
+ /* Specifying a section attribute on a variable forces it into a
+ non-.bss section, and thus it cannot be common. */
else if (TREE_CODE (decl) == VAR_DECL
&& DECL_SECTION_NAME (decl) != NULL_TREE
&& DECL_INITIAL (decl) == NULL_TREE
- && DECL_COMMON (decl)
- && ! flag_no_common)
- {
- warning_with_decl (decl,
- "section attribute ignored for uninitialized variable `%s'");
- /* Remove the section name so subsequent declarations won't see it.
- We are ignoring it, remember. */
- DECL_SECTION_NAME (decl) = NULL_TREE;
- }
+ && DECL_COMMON (decl))
+ DECL_COMMON (decl) = 0;
/* Now handle ordinary static variables and functions (in memory).
Also handle vars declared register invalidly. */
@@ -573,7 +737,7 @@ make_decl_rtl (decl, asmspec, top_level)
/* Can't use just the variable's own name for a variable
whose scope is less than the whole file.
Concatenate a distinguishing number. */
- if (!top_level && !DECL_EXTERNAL (decl) && asmspec == 0)
+ if (!top_level && !TREE_PUBLIC (decl) && asmspec == 0)
{
char *label;
@@ -585,9 +749,24 @@ make_decl_rtl (decl, asmspec, top_level)
if (name == 0)
abort ();
- DECL_RTL (decl) = gen_rtx (MEM, DECL_MODE (decl),
- gen_rtx (SYMBOL_REF, Pmode, name));
+ /* When -fprefix-function-name is used, the functions
+ names are prefixed. Only nested function names are not
+ prefixed. */
+ if (flag_prefix_function_name && TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ char *new_name;
+ new_name = (char *) alloca (strlen (name) + CHKR_PREFIX_SIZE
+ + 1);
+ strcpy (new_name, CHKR_PREFIX);
+ strcpy (new_name + CHKR_PREFIX_SIZE, name);
+ name = obstack_copy0 (saveable_obstack,
+ new_name, strlen (new_name));
+ }
+ DECL_RTL (decl) = gen_rtx_MEM (DECL_MODE (decl),
+ gen_rtx_SYMBOL_REF (Pmode, name));
+ MEM_ALIAS_SET (DECL_RTL (decl)) = get_alias_set (decl);
+
/* If this variable is to be treated as volatile, show its
tree node has side effects. If it has side effects, either
because of this test or from TREE_THIS_VOLATILE also
@@ -612,11 +791,26 @@ make_decl_rtl (decl, asmspec, top_level)
#endif
}
}
- /* If the old RTL had the wrong mode, fix the mode. */
- else if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
+ else
{
- rtx rtl = DECL_RTL (decl);
- PUT_MODE (rtl, DECL_MODE (decl));
+ /* If the old RTL had the wrong mode, fix the mode. */
+ if (GET_MODE (DECL_RTL (decl)) != DECL_MODE (decl))
+ {
+ rtx rtl = DECL_RTL (decl);
+ PUT_MODE (rtl, DECL_MODE (decl));
+ }
+
+ /* ??? Another way to do this would be to do what halfpic.c does
+ and maintain a hashed table of such critters. */
+ /* ??? Another way to do this would be to pass a flag bit to
+ ENCODE_SECTION_INFO saying whether this is a new decl or not. */
+ /* Let the target reassign the RTL if it wants.
+ This is necessary, for example, when one machine specific
+ decl attribute overrides another. */
+#ifdef REDO_SECTION_INFO_P
+ if (REDO_SECTION_INFO_P (decl))
+ ENCODE_SECTION_INFO (decl);
+#endif
}
}
@@ -658,12 +852,6 @@ void
assemble_asm (string)
tree string;
{
- if (output_bytecode)
- {
- error ("asm statements not allowed in interpreter");
- return;
- }
-
app_enable ();
if (TREE_CODE (string) == ADDR_EXPR)
@@ -751,6 +939,16 @@ assemble_gc_entry (name)
#endif
}
+/* CONSTANT_POOL_BEFORE_FUNCTION may be defined as an expression with
+ a non-zero value if the constant pool should be output before the
+ start of the function, or a zero value if the pool should output
+ after the end of the function. The default is to put it before the
+ start. */
+
+#ifndef CONSTANT_POOL_BEFORE_FUNCTION
+#define CONSTANT_POOL_BEFORE_FUNCTION 1
+#endif
+
/* Output assembler code for the constant pool of a function and associated
with defining the name of the function. DECL describes the function.
NAME is the function's name. For the constant pool, we use the current
@@ -767,19 +965,24 @@ assemble_start_function (decl, fnname)
app_disable ();
- output_constant_pool (fnname, decl);
+ if (CONSTANT_POOL_BEFORE_FUNCTION)
+ output_constant_pool (fnname, decl);
+
+#ifdef ASM_OUTPUT_SECTION_NAME
+ /* If the function is to be put in its own section and it's not in a section
+ already, indicate so. */
+ if ((flag_function_sections
+ && DECL_SECTION_NAME (decl) == NULL_TREE)
+ || UNIQUE_SECTION_P (decl))
+ UNIQUE_SECTION (decl, 0);
+#endif
function_section (decl);
/* Tell assembler to move to target machine's alignment for functions. */
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)
- {
- if (output_bytecode)
- BC_OUTPUT_ALIGN (asm_out_file, align);
- else
- ASM_OUTPUT_ALIGN (asm_out_file, align);
- }
+ ASM_OUTPUT_ALIGN (asm_out_file, align);
#ifdef ASM_OUTPUT_FUNCTION_PREFIX
ASM_OUTPUT_FUNCTION_PREFIX (asm_out_file, fnname);
@@ -801,13 +1004,19 @@ assemble_start_function (decl, fnname)
if (TREE_PUBLIC (decl))
{
- if (!first_global_object_name)
+ if (! first_global_object_name)
{
char *p;
+ char **name;
+
+ if (! DECL_WEAK (decl) && ! DECL_ONE_ONLY (decl))
+ name = &first_global_object_name;
+ else
+ name = &weak_global_object_name;
STRIP_NAME_ENCODING (p, fnname);
- first_global_object_name = permalloc (strlen (p) + 1);
- strcpy (first_global_object_name, p);
+ *name = permalloc (strlen (p) + 1);
+ strcpy (*name, p);
}
#ifdef ASM_WEAKEN_LABEL
@@ -815,10 +1024,7 @@ assemble_start_function (decl, fnname)
ASM_WEAKEN_LABEL (asm_out_file, fnname);
else
#endif
- if (output_bytecode)
- BC_GLOBALIZE_LABEL (asm_out_file, fnname);
- else
- ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
+ ASM_GLOBALIZE_LABEL (asm_out_file, fnname);
}
/* Do any machine/system dependent processing of the function name */
@@ -826,10 +1032,7 @@ assemble_start_function (decl, fnname)
ASM_DECLARE_FUNCTION_NAME (asm_out_file, fnname, current_function_decl);
#else
/* Standard thing is just output label for the function. */
- if (output_bytecode)
- BC_OUTPUT_LABEL (asm_out_file, fnname);
- else
- ASM_OUTPUT_LABEL (asm_out_file, fnname);
+ ASM_OUTPUT_LABEL (asm_out_file, fnname);
#endif /* ASM_DECLARE_FUNCTION_NAME */
}
@@ -844,6 +1047,14 @@ assemble_end_function (decl, fnname)
#ifdef ASM_DECLARE_FUNCTION_SIZE
ASM_DECLARE_FUNCTION_SIZE (asm_out_file, fnname, decl);
#endif
+ if (! CONSTANT_POOL_BEFORE_FUNCTION)
+ {
+ output_constant_pool (fnname, decl);
+ function_section (decl); /* need to switch back */
+ }
+
+ /* Output any constants which should appear after the function. */
+ output_after_function_constants ();
}
/* Assemble code to leave SIZE bytes of zeros. */
@@ -852,12 +1063,6 @@ void
assemble_zeros (size)
int size;
{
- if (output_bytecode)
- {
- bc_emit_const_skip (size);
- return;
- }
-
#ifdef ASM_NO_SKIP_IN_TEXT
/* The `space' pseudo in the text section outputs nop insns rather than 0s,
so we must output 0s explicitly in the text section. */
@@ -891,12 +1096,7 @@ assemble_zeros (size)
else
#endif
if (size > 0)
- {
- if (output_bytecode)
- BC_OUTPUT_SKIP (asm_out_file, size);
- else
- ASM_OUTPUT_SKIP (asm_out_file, size);
- }
+ ASM_OUTPUT_SKIP (asm_out_file, size);
}
/* Assemble an alignment pseudo op for an ALIGN-bit boundary. */
@@ -916,16 +1116,9 @@ assemble_string (p, size)
char *p;
int size;
{
- register int i;
int pos = 0;
int maximum = 2000;
- if (output_bytecode)
- {
- bc_emit (p, size);
- return;
- }
-
/* If the string is very long, split it up. */
while (pos < size)
@@ -934,26 +1127,13 @@ assemble_string (p, size)
if (thissize > maximum)
thissize = maximum;
- if (output_bytecode)
- bc_output_ascii (asm_out_file, p, thissize);
- else
- {
- ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
- }
+ ASM_OUTPUT_ASCII (asm_out_file, p, thissize);
pos += thissize;
p += thissize;
}
}
-static void
-bc_output_ascii (file, p, size)
- FILE *file;
- char *p;
- int size;
-{
- BC_OUTPUT_ASCII (file, p, size);
-}
/* Assemble everything that is needed for a variable or function declaration.
Not used for automatic variables, and not used for function definitions.
@@ -973,16 +1153,13 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
int dont_output_data;
{
register char *name;
- int align;
+ unsigned int align;
tree size_tree;
int reloc = 0;
enum in_section saved_in_section;
last_assemble_variable_decl = 0;
- if (output_bytecode)
- return;
-
if (GET_CODE (DECL_RTL (decl)) == REG)
{
/* Do output symbol info for global register variables, but do nothing
@@ -992,22 +1169,19 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
return;
TREE_ASM_WRITTEN (decl) = 1;
- if (!output_bytecode)
- {
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
- /* File-scope global variables are output here. */
- if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
- && top_level)
- dbxout_symbol (decl, 0);
+ /* File-scope global variables are output here. */
+ if ((write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
+ && top_level)
+ dbxout_symbol (decl, 0);
#endif
#ifdef SDB_DEBUGGING_INFO
- if (write_symbols == SDB_DEBUG && top_level
- /* Leave initialized global vars for end of compilation;
- see comment in compile_file. */
- && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
- sdbout_symbol (decl, 0);
+ if (write_symbols == SDB_DEBUG && top_level
+ /* Leave initialized global vars for end of compilation;
+ see comment in compile_file. */
+ && (TREE_PUBLIC (decl) == 0 || DECL_INITIAL (decl) == 0))
+ sdbout_symbol (decl, 0);
#endif
- }
/* Don't output any DWARF debugging information for variables here.
In the case of local variables, the information for them is output
@@ -1066,14 +1240,18 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
if (! dont_output_data)
{
+ int size;
+
if (TREE_CODE (DECL_SIZE (decl)) != INTEGER_CST)
goto finish;
/* This is better than explicit arithmetic, since it avoids overflow. */
size_tree = size_binop (CEIL_DIV_EXPR,
- DECL_SIZE (decl), size_int (BITS_PER_UNIT));
+ DECL_SIZE (decl), size_int (BITS_PER_UNIT));
- if (TREE_INT_CST_HIGH (size_tree) != 0)
+ size = TREE_INT_CST_LOW (size_tree);
+ if (TREE_INT_CST_HIGH (size_tree) != 0
+ || size != TREE_INT_CST_LOW (size_tree))
{
error_with_decl (decl, "size of variable `%s' is too large");
goto finish;
@@ -1082,23 +1260,70 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+ if (TREE_PUBLIC (decl) && DECL_NAME (decl)
+ && ! first_global_object_name
+ && ! (DECL_COMMON (decl) && (DECL_INITIAL (decl) == 0
+ || DECL_INITIAL (decl) == error_mark_node))
+ && ! DECL_WEAK (decl)
+ && ! DECL_ONE_ONLY (decl))
+ {
+ char *p;
+
+ STRIP_NAME_ENCODING (p, name);
+ first_global_object_name = permalloc (strlen (p) + 1);
+ strcpy (first_global_object_name, p);
+ }
+
+ /* Compute the alignment of this data. */
+
+ align = DECL_ALIGN (decl);
+
+ /* In the case for initialing an array whose length isn't specified,
+ where we have not yet been able to do the layout,
+ figure out the proper alignment now. */
+ if (dont_output_data && DECL_SIZE (decl) == 0
+ && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+ align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
+
+ /* Some object file formats have a maximum alignment which they support.
+ In particular, a.out format supports a maximum alignment of 4. */
+#ifndef MAX_OFILE_ALIGNMENT
+#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
+#endif
+ if (align > MAX_OFILE_ALIGNMENT)
+ {
+ warning_with_decl (decl,
+ "alignment of `%s' is greater than maximum object file alignment. Using %d.",
+ MAX_OFILE_ALIGNMENT/BITS_PER_UNIT);
+ align = MAX_OFILE_ALIGNMENT;
+ }
+
+ /* On some machines, it is good to increase alignment sometimes. */
+#ifdef DATA_ALIGNMENT
+ align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
+#endif
+#ifdef CONSTANT_ALIGNMENT
+ if (DECL_INITIAL (decl) != 0 && DECL_INITIAL (decl) != error_mark_node)
+ align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
+#endif
+
+ /* Reset the alignment in case we have made it tighter, so we can benefit
+ from it in get_pointer_alignment. */
+ DECL_ALIGN (decl) = align;
+
/* Handle uninitialized definitions. */
- /* ANSI specifies that a tentative definition which is not merged with
- a non-tentative definition behaves exactly like a definition with an
- initializer equal to zero. (Section 3.7.2)
- -fno-common gives strict ANSI behavior. Usually you don't want it.
- This matters only for variables with external linkage. */
- if ((! flag_no_common || ! TREE_PUBLIC (decl))
+ if ((DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)
+ /* If the target can't output uninitialized but not common global data
+ in .bss, then we have to use .data. */
+#if ! defined (ASM_OUTPUT_BSS) && ! defined (ASM_OUTPUT_ALIGNED_BSS)
&& DECL_COMMON (decl)
- && ! dont_output_data
- && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
+#endif
+ && ! dont_output_data)
{
int size = TREE_INT_CST_LOW (size_tree);
int rounded = size;
- if (TREE_INT_CST_HIGH (size_tree) != 0)
- error_with_decl (decl, "size of variable `%s' is too large");
/* Don't allocate zero bytes of common,
since that means "undefined external" in the linker. */
if (size == 0) rounded = 1;
@@ -1107,7 +1332,13 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-
+
+#if !defined(ASM_OUTPUT_ALIGNED_COMMON) && !defined(ASM_OUTPUT_ALIGNED_BSS)
+ if ( (DECL_ALIGN (decl) / BITS_PER_UNIT) > rounded)
+ warning_with_decl
+ (decl, "requested alignment for %s is greater than implemented alignment of %d.",rounded);
+#endif
+
#ifdef DBX_DEBUGGING_INFO
/* File-scope global variables are output here. */
if (write_symbols == DBX_DEBUG && top_level)
@@ -1129,31 +1360,55 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
while we are doing our final traversal of the chain of file-scope
declarations. */
-#if 0
+#if 0 /* ??? We should either delete this or add a comment describing what
+ it was intended to do and why we shouldn't delete it. */
if (flag_shared_data)
data_section ();
#endif
- if (TREE_PUBLIC (decl))
+
+ if (TREE_PUBLIC (decl)
+#if defined (ASM_OUTPUT_BSS) || defined (ASM_OUTPUT_ALIGNED_BSS)
+ && DECL_COMMON (decl)
+#endif
+ )
{
#ifdef ASM_OUTPUT_SHARED_COMMON
if (flag_shared_data)
ASM_OUTPUT_SHARED_COMMON (asm_out_file, name, size, rounded);
else
#endif
- if (output_bytecode)
- {
- BC_OUTPUT_COMMON (asm_out_file, name, size, rounded);
- }
- else
{
+#ifdef ASM_OUTPUT_ALIGNED_DECL_COMMON
+ ASM_OUTPUT_ALIGNED_DECL_COMMON (asm_out_file, decl, name, size,
+ DECL_ALIGN (decl));
+#else
#ifdef ASM_OUTPUT_ALIGNED_COMMON
ASM_OUTPUT_ALIGNED_COMMON (asm_out_file, name, size,
DECL_ALIGN (decl));
#else
ASM_OUTPUT_COMMON (asm_out_file, name, size, rounded);
#endif
+#endif
+ }
+ }
+#if defined (ASM_OUTPUT_BSS) || defined (ASM_OUTPUT_ALIGNED_BSS)
+ else if (TREE_PUBLIC (decl))
+ {
+#ifdef ASM_OUTPUT_SHARED_BSS
+ if (flag_shared_data)
+ ASM_OUTPUT_SHARED_BSS (asm_out_file, decl, name, size, rounded);
+ else
+#endif
+ {
+#ifdef ASM_OUTPUT_ALIGNED_BSS
+ ASM_OUTPUT_ALIGNED_BSS (asm_out_file, decl, name, size,
+ DECL_ALIGN (decl));
+#else
+ ASM_OUTPUT_BSS (asm_out_file, decl, name, size, rounded);
+#endif
}
}
+#endif /* ASM_OUTPUT_BSS || ASM_OUTPUT_ALIGNED_BSS */
else
{
#ifdef ASM_OUTPUT_SHARED_LOCAL
@@ -1161,37 +1416,30 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
else
#endif
- if (output_bytecode)
- {
- BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
- }
- else
{
+#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
+ ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, decl, name, size,
+ DECL_ALIGN (decl));
+#else
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
DECL_ALIGN (decl));
#else
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
#endif
+#endif
}
}
goto finish;
}
- /* Handle initialized definitions. */
+ /* Handle initialized definitions.
+ Also handle uninitialized global definitions if -fno-common and the
+ target doesn't support ASM_OUTPUT_BSS. */
/* First make the assembler name(s) global if appropriate. */
if (TREE_PUBLIC (decl) && DECL_NAME (decl))
{
- if (!first_global_object_name)
- {
- char *p;
-
- STRIP_NAME_ENCODING (p, name);
- first_global_object_name = permalloc (strlen (p) + 1);
- strcpy (first_global_object_name, p);
- }
-
#ifdef ASM_WEAKEN_LABEL
if (DECL_WEAK (decl))
ASM_WEAKEN_LABEL (asm_out_file, name);
@@ -1215,33 +1463,13 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
else if (DECL_INITIAL (decl))
reloc = output_addressed_constants (DECL_INITIAL (decl));
- /* Switch to the proper section for this data. */
- if (IN_NAMED_SECTION (decl))
- named_section (decl, NULL);
- else
- {
- /* C++ can have const variables that get initialized from constructors,
- and thus can not be in a readonly section. We prevent this by
- verifying that the initial value is constant for objects put in a
- readonly section.
-
- error_mark_node is used by the C front end to indicate that the
- initializer has not been seen yet. In this case, we assume that
- the initializer must be constant. */
-#ifdef SELECT_SECTION
- SELECT_SECTION (decl, reloc);
-#else
- if (TREE_READONLY (decl)
- && ! TREE_THIS_VOLATILE (decl)
- && DECL_INITIAL (decl)
- && (DECL_INITIAL (decl) == error_mark_node
- || TREE_CONSTANT (DECL_INITIAL (decl)))
- && ! (flag_pic && reloc))
- readonly_data_section ();
- else
- data_section ();
+#ifdef ASM_OUTPUT_SECTION_NAME
+ if (UNIQUE_SECTION_P (decl))
+ UNIQUE_SECTION (decl, reloc);
#endif
- }
+
+ /* Switch to the appropriate section. */
+ variable_section (decl, reloc);
/* dbxout.c needs to know this. */
if (in_text_section ())
@@ -1276,64 +1504,12 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
/* If the debugging output changed sections, reselect the section
that's supposed to be selected. */
if (in_section != saved_in_section)
- {
- /* Switch to the proper section for this data. */
-#ifdef SELECT_SECTION
- SELECT_SECTION (decl, reloc);
-#else
- if (TREE_READONLY (decl)
- && ! TREE_THIS_VOLATILE (decl)
- && DECL_INITIAL (decl)
- && (DECL_INITIAL (decl) == error_mark_node
- || TREE_CONSTANT (DECL_INITIAL (decl)))
- && ! (flag_pic && reloc))
- readonly_data_section ();
- else
- data_section ();
-#endif
- }
-
- /* Compute and output the alignment of this data. */
-
- align = DECL_ALIGN (decl);
- /* In the case for initialing an array whose length isn't specified,
- where we have not yet been able to do the layout,
- figure out the proper alignment now. */
- if (dont_output_data && DECL_SIZE (decl) == 0
- && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
- align = MAX (align, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
-
- /* Some object file formats have a maximum alignment which they support.
- In particular, a.out format supports a maximum alignment of 4. */
-#ifndef MAX_OFILE_ALIGNMENT
-#define MAX_OFILE_ALIGNMENT BIGGEST_ALIGNMENT
-#endif
- if (align > MAX_OFILE_ALIGNMENT)
- {
- warning_with_decl (decl,
- "alignment of `%s' is greater than maximum object file alignment");
- align = MAX_OFILE_ALIGNMENT;
- }
-#ifdef DATA_ALIGNMENT
- /* On some machines, it is good to increase alignment sometimes. */
- align = DATA_ALIGNMENT (TREE_TYPE (decl), align);
-#endif
-#ifdef CONSTANT_ALIGNMENT
- if (DECL_INITIAL (decl))
- align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
-#endif
-
- /* Reset the alignment in case we have made it tighter, so we can benefit
- from it in get_pointer_alignment. */
- DECL_ALIGN (decl) = align;
+ variable_section (decl, reloc);
+ /* Output the alignment of this data. */
if (align > BITS_PER_UNIT)
- {
- if (output_bytecode)
- BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
- else
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
- }
+ ASM_OUTPUT_ALIGN (asm_out_file,
+ floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT));
/* Do any machine/system dependent processing of the object. */
#ifdef ASM_DECLARE_OBJECT_NAME
@@ -1341,10 +1517,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
ASM_DECLARE_OBJECT_NAME (asm_out_file, name, decl);
#else
/* Standard thing is just output label for the object. */
- if (output_bytecode)
- BC_OUTPUT_LABEL (asm_out_file, name);
- else
- ASM_OUTPUT_LABEL (asm_out_file, name);
+ ASM_OUTPUT_LABEL (asm_out_file, name);
#endif /* ASM_DECLARE_OBJECT_NAME */
if (!dont_output_data)
@@ -1373,22 +1546,7 @@ assemble_variable (decl, top_level, at_end, dont_output_data)
dbxout_symbol (decl, 0);
if (in_section != saved_in_section)
- {
- /* Switch to the proper section for this data. */
-#ifdef SELECT_SECTION
- SELECT_SECTION (decl, reloc);
-#else
- if (TREE_READONLY (decl)
- && ! TREE_THIS_VOLATILE (decl)
- && DECL_INITIAL (decl)
- && (DECL_INITIAL (decl) == error_mark_node
- || TREE_CONSTANT (DECL_INITIAL (decl)))
- && ! (flag_pic && reloc))
- readonly_data_section ();
- else
- data_section ();
-#endif
- }
+ variable_section (decl, reloc);
}
#else
/* There must be a statement after a label. */
@@ -1433,55 +1591,6 @@ contains_pointers_p (type)
}
}
-/* Output text storage for constructor CONSTR. */
-
-void
-bc_output_constructor (constr, size)
- tree constr;
- int size;
-{
- int i;
-
- /* Must always be a literal; non-literal constructors are handled
- differently. */
-
- if (!TREE_CONSTANT (constr))
- abort ();
-
- /* Always const */
- text_section ();
-
- /* Align */
- for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++)
- ;
-
- if (i > 0)
- BC_OUTPUT_ALIGN (asm_out_file, i);
-
- /* Output data */
- output_constant (constr, size);
-}
-
-/* Create storage for constructor CONSTR. */
-
-void
-bc_output_data_constructor (constr)
- tree constr;
-{
- int i;
-
- /* Put in data section */
- data_section ();
-
- /* Align */
- for (i = 0; TYPE_ALIGN (constr) >= BITS_PER_UNIT << (i + 1); i++);
- if (i > 0)
- BC_OUTPUT_ALIGN (asm_out_file, i);
-
- /* The constructor is filled in at runtime. */
- BC_OUTPUT_SKIP (asm_out_file, int_size_in_bytes (TREE_TYPE (constr)));
-}
-
/* Output something to declare an external symbol to the assembler.
(Most assemblers don't need this, so we normally output nothing.)
Do nothing if DECL is not external. */
@@ -1490,9 +1599,6 @@ void
assemble_external (decl)
tree decl;
{
- if (output_bytecode)
- return;
-
#ifdef ASM_OUTPUT_EXTERNAL
if (TREE_CODE_CLASS (TREE_CODE (decl)) == 'd'
&& DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
@@ -1517,14 +1623,11 @@ assemble_external_libcall (fun)
rtx fun;
{
#ifdef ASM_OUTPUT_EXTERNAL_LIBCALL
- if (!output_bytecode)
+ /* Declare library function name external when first used, if nec. */
+ if (! SYMBOL_REF_USED (fun))
{
- /* Declare library function name external when first used, if nec. */
- if (! SYMBOL_REF_USED (fun))
- {
- SYMBOL_REF_USED (fun) = 1;
- ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
- }
+ SYMBOL_REF_USED (fun) = 1;
+ ASM_OUTPUT_EXTERNAL_LIBCALL (asm_out_file, fun);
}
#endif
}
@@ -1544,10 +1647,7 @@ void
assemble_label (name)
char *name;
{
- if (output_bytecode)
- BC_OUTPUT_LABEL (asm_out_file, name);
- else
- ASM_OUTPUT_LABEL (asm_out_file, name);
+ ASM_OUTPUT_LABEL (asm_out_file, name);
}
/* Output to FILE a reference to the assembler name of a C-level name NAME.
@@ -1562,30 +1662,21 @@ assemble_name (file, name)
char *name;
{
char *real_name;
- int save_warn_id_clash = warn_id_clash;
+ tree id;
STRIP_NAME_ENCODING (real_name, name);
+ if (flag_prefix_function_name
+ && ! bcmp (real_name, CHKR_PREFIX, CHKR_PREFIX_SIZE))
+ real_name = real_name + CHKR_PREFIX_SIZE;
- /* Don't warn about an identifier name length clash on this name, since
- it can be a user symbol suffixed by a number. */
- warn_id_clash = 0;
- TREE_SYMBOL_REFERENCED (get_identifier (real_name)) = 1;
- warn_id_clash = save_warn_id_clash;
+ id = maybe_get_identifier (real_name);
+ if (id)
+ TREE_SYMBOL_REFERENCED (id) = 1;
if (name[0] == '*')
- {
- if (output_bytecode)
- bc_emit_labelref (name, 0);
- else
- fputs (&name[1], file);
- }
+ fputs (&name[1], file);
else
- {
- if (output_bytecode)
- BC_OUTPUT_LABELREF (file, name);
- else
- ASM_OUTPUT_LABELREF (file, name);
- }
+ ASM_OUTPUT_LABELREF (file, name);
}
/* Allocate SIZE bytes writable static space with a gensym name
@@ -1598,11 +1689,6 @@ assemble_static_space (size)
char name[12];
char *namestring;
rtx x;
- /* Round size up to multiple of BIGGEST_ALIGNMENT bits
- so that each uninitialized object starts on such a boundary. */
- int rounded = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
- / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
- * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
#if 0
if (flag_shared_data)
@@ -1616,23 +1702,25 @@ assemble_static_space (size)
strlen (name) + 2);
strcpy (namestring, name);
- if (output_bytecode)
- x = bc_gen_rtx (namestring, 0, (struct bc_label *) 0);
- else
- x = gen_rtx (SYMBOL_REF, Pmode, namestring);
+ x = gen_rtx_SYMBOL_REF (Pmode, namestring);
- if (output_bytecode)
- {
- BC_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
- }
- else
- {
+#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
+ ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name, size,
+ BIGGEST_ALIGNMENT);
+#else
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
- ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
+ ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size, BIGGEST_ALIGNMENT);
#else
- ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+ {
+ /* Round size up to multiple of BIGGEST_ALIGNMENT bits
+ so that each uninitialized object starts on such a boundary. */
+ int rounded = ((size + (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1)
+ / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
+ * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+ ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
+ }
+#endif
#endif
- }
return x;
}
@@ -1648,10 +1736,6 @@ assemble_trampoline_template ()
char *name;
int align;
- /* Shouldn't get here */
- if (output_bytecode)
- abort ();
-
/* By default, put trampoline templates in read-only data section. */
#ifdef TRAMPOLINE_SECTION
@@ -1661,7 +1745,7 @@ assemble_trampoline_template ()
#endif
/* Write the assembler code to define one. */
- align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+ align = floor_log2 (TRAMPOLINE_ALIGNMENT / BITS_PER_UNIT);
if (align > 0)
ASM_OUTPUT_ALIGN (asm_out_file, align);
@@ -1672,7 +1756,7 @@ assemble_trampoline_template ()
ASM_GENERATE_INTERNAL_LABEL (label, "LTRAMP", 0);
name
= (char *) obstack_copy0 (&permanent_obstack, label, strlen (label));
- return gen_rtx (SYMBOL_REF, Pmode, name);
+ return gen_rtx_SYMBOL_REF (Pmode, name);
}
#endif
@@ -1689,7 +1773,7 @@ assemble_integer (x, size, force)
int force;
{
/* First try to use the standard 1, 2, 4, 8, and 16 byte
- ASM_OUTPUT... macros. */
+ ASM_OUTPUT... macros. */
switch (size)
{
@@ -1861,7 +1945,6 @@ immed_double_const (i0, i1, mode)
enum machine_mode mode;
{
register rtx r;
- int in_current_obstack;
if (GET_MODE_CLASS (mode) == MODE_INT
|| GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
@@ -1912,7 +1995,7 @@ immed_double_const (i0, i1, mode)
is being broken. */
if (width <= HOST_BITS_PER_WIDE_INT)
- i1 = (i0 < 0) ? ~0 : 0;
+ i1 = (i0 < 0) ? ~(HOST_WIDE_INT) 0 : 0;
/* If this integer fits in one word, return a CONST_INT. */
if ((i1 == 0 && i0 >= 0)
@@ -1941,7 +2024,7 @@ immed_double_const (i0, i1, mode)
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
- r = gen_rtx (CONST_DOUBLE, mode, 0, i0, i1);
+ r = gen_rtx_CONST_DOUBLE (mode, NULL_RTX, i0, i1);
pop_obstacks ();
/* Don't touch const_double_chain in nested function; see force_const_mem.
@@ -1970,7 +2053,6 @@ immed_real_const_1 (d, mode)
{
union real_extract u;
register rtx r;
- int in_current_obstack;
/* Get the desired `double' value as a sequence of ints
since that is how they are stored in a CONST_DOUBLE. */
@@ -1979,8 +2061,7 @@ immed_real_const_1 (d, mode)
/* Detect special cases. */
- /* Avoid REAL_VALUES_EQUAL here in order to distinguish minus zero. */
- if (!bcmp ((char *) &dconst0, (char *) &d, sizeof d))
+ if (REAL_VALUES_IDENTICAL (dconst0, d))
return CONST0_RTX (mode);
/* Check for NaN first, because some ports (specifically the i386) do not
emit correct ieee-fp code by default, and thus will generate a core
@@ -1989,6 +2070,8 @@ immed_real_const_1 (d, mode)
else if (! REAL_VALUE_ISNAN (d) && REAL_VALUES_EQUAL (dconst1, d))
return CONST1_RTX (mode);
+ if (sizeof u == sizeof (HOST_WIDE_INT))
+ return immed_double_const (u.i[0], 0, mode);
if (sizeof u == 2 * sizeof (HOST_WIDE_INT))
return immed_double_const (u.i[0], u.i[1], mode);
@@ -2120,19 +2203,16 @@ decode_addr_const (exp, value)
break;
case LABEL_DECL:
- if (output_bytecode)
- /* FIXME: this may not be correct, check it */
- x = bc_gen_rtx (TREE_STRING_POINTER (target), 0, (struct bc_label *) 0);
- else
- x = gen_rtx (MEM, FUNCTION_MODE,
- gen_rtx (LABEL_REF, VOIDmode,
- label_rtx (TREE_OPERAND (exp, 0))));
+ x = gen_rtx_MEM (FUNCTION_MODE,
+ gen_rtx_LABEL_REF (VOIDmode,
+ label_rtx (TREE_OPERAND (exp, 0))));
break;
case REAL_CST:
case STRING_CST:
case COMPLEX_CST:
case CONSTRUCTOR:
+ case INTEGER_CST:
x = TREE_CST_RTL (target);
break;
@@ -2140,12 +2220,9 @@ decode_addr_const (exp, value)
abort ();
}
- if (!output_bytecode)
- {
- if (GET_CODE (x) != MEM)
- abort ();
- x = XEXP (x, 0);
- }
+ if (GET_CODE (x) != MEM)
+ abort ();
+ x = XEXP (x, 0);
value->base = x;
value->offset = offset;
@@ -2181,80 +2258,103 @@ const_hash (exp)
register int len, hi, i;
register enum tree_code code = TREE_CODE (exp);
- if (code == INTEGER_CST)
+ /* Either set P and LEN to the address and len of something to hash and
+ exit the switch or return a value. */
+
+ switch (code)
{
+ case INTEGER_CST:
p = (char *) &TREE_INT_CST_LOW (exp);
len = 2 * sizeof TREE_INT_CST_LOW (exp);
- }
- else if (code == REAL_CST)
- {
+ break;
+
+ case REAL_CST:
p = (char *) &TREE_REAL_CST (exp);
len = sizeof TREE_REAL_CST (exp);
- }
- else if (code == STRING_CST)
- p = TREE_STRING_POINTER (exp), len = TREE_STRING_LENGTH (exp);
- else if (code == COMPLEX_CST)
- return const_hash (TREE_REALPART (exp)) * 5
- + const_hash (TREE_IMAGPART (exp));
- else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
- {
- len = int_size_in_bytes (TREE_TYPE (exp));
- p = (char*) alloca (len);
- get_set_constructor_bytes (exp, (unsigned char *) p, len);
- }
- else if (code == CONSTRUCTOR)
- {
- register tree link;
-
- /* For record type, include the type in the hashing.
- We do not do so for array types
- because (1) the sizes of the elements are sufficient
- and (2) distinct array types can have the same constructor.
- Instead, we include the array size because the constructor could
- be shorter. */
- if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
- hi = ((HOST_WIDE_INT) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
- % MAX_HASH_TABLE;
- else
- hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
- & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE;
+ break;
- for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
- if (TREE_VALUE (link))
- hi = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE;
+ case STRING_CST:
+ p = TREE_STRING_POINTER (exp);
+ len = TREE_STRING_LENGTH (exp);
+ break;
- return hi;
- }
- else if (code == ADDR_EXPR)
- {
- struct addr_const value;
- decode_addr_const (exp, &value);
- if (GET_CODE (value.base) == SYMBOL_REF)
+ case COMPLEX_CST:
+ return (const_hash (TREE_REALPART (exp)) * 5
+ + const_hash (TREE_IMAGPART (exp)));
+
+ case CONSTRUCTOR:
+ if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
+ {
+ len = int_size_in_bytes (TREE_TYPE (exp));
+ p = (char *) alloca (len);
+ get_set_constructor_bytes (exp, (unsigned char *) p, len);
+ break;
+ }
+ else
{
- /* Don't hash the address of the SYMBOL_REF;
- only use the offset and the symbol name. */
- hi = value.offset;
- p = XSTR (value.base, 0);
- for (i = 0; p[i] != 0; i++)
- hi = ((hi * 613) + (unsigned)(p[i]));
+ register tree link;
+
+ /* For record type, include the type in the hashing.
+ We do not do so for array types
+ because (1) the sizes of the elements are sufficient
+ and (2) distinct array types can have the same constructor.
+ Instead, we include the array size because the constructor could
+ be shorter. */
+ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
+ hi = ((unsigned long) TREE_TYPE (exp) & ((1 << HASHBITS) - 1))
+ % MAX_HASH_TABLE;
+ else
+ hi = ((5 + int_size_in_bytes (TREE_TYPE (exp)))
+ & ((1 << HASHBITS) - 1)) % MAX_HASH_TABLE;
+
+ for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+ if (TREE_VALUE (link))
+ hi
+ = (hi * 603 + const_hash (TREE_VALUE (link))) % MAX_HASH_TABLE;
+
+ return hi;
}
- else if (GET_CODE (value.base) == LABEL_REF)
- hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
- hi &= (1 << HASHBITS) - 1;
- hi %= MAX_HASH_TABLE;
+ case ADDR_EXPR:
+ {
+ struct addr_const value;
+
+ decode_addr_const (exp, &value);
+ if (GET_CODE (value.base) == SYMBOL_REF)
+ {
+ /* Don't hash the address of the SYMBOL_REF;
+ only use the offset and the symbol name. */
+ hi = value.offset;
+ p = XSTR (value.base, 0);
+ for (i = 0; p[i] != 0; i++)
+ hi = ((hi * 613) + (unsigned) (p[i]));
+ }
+ else if (GET_CODE (value.base) == LABEL_REF)
+ hi = value.offset + CODE_LABEL_NUMBER (XEXP (value.base, 0)) * 13;
+
+ hi &= (1 << HASHBITS) - 1;
+ hi %= MAX_HASH_TABLE;
+ }
return hi;
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ return (const_hash (TREE_OPERAND (exp, 0)) * 9
+ + const_hash (TREE_OPERAND (exp, 1)));
+
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
+
+ default:
+ abort ();
}
- else if (code == PLUS_EXPR || code == MINUS_EXPR)
- return const_hash (TREE_OPERAND (exp, 0)) * 9
- + const_hash (TREE_OPERAND (exp, 1));
- else if (code == NOP_EXPR || code == CONVERT_EXPR)
- return const_hash (TREE_OPERAND (exp, 0)) * 7 + 2;
/* Compute hashing function */
hi = len;
for (i = 0; i < len; i++)
- hi = ((hi * 613) + (unsigned)(p[i]));
+ hi = ((hi * 613) + (unsigned) (p[i]));
hi &= (1 << HASHBITS) - 1;
hi %= MAX_HASH_TABLE;
@@ -2293,119 +2393,189 @@ compare_constant_1 (exp, p)
if (code != (enum tree_code) *p++)
return 0;
- if (code == INTEGER_CST)
+ /* Either set STRP, P and LEN to pointers and length to compare and exit the
+ switch, or return the result of the comparison. */
+
+ switch (code)
{
+ case INTEGER_CST:
/* Integer constants are the same only if the same width of type. */
if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
return 0;
+
strp = (char *) &TREE_INT_CST_LOW (exp);
len = 2 * sizeof TREE_INT_CST_LOW (exp);
- }
- else if (code == REAL_CST)
- {
+ break;
+
+ case REAL_CST:
/* Real constants are the same only if the same width of type. */
if (*p++ != TYPE_PRECISION (TREE_TYPE (exp)))
return 0;
+
strp = (char *) &TREE_REAL_CST (exp);
len = sizeof TREE_REAL_CST (exp);
- }
- else if (code == STRING_CST)
- {
+ break;
+
+ case STRING_CST:
if (flag_writable_strings)
return 0;
+
+ if (*p++ != TYPE_MODE (TREE_TYPE (exp)))
+ return 0;
+
strp = TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
if (bcmp ((char *) &TREE_STRING_LENGTH (exp), p,
sizeof TREE_STRING_LENGTH (exp)))
return 0;
+
p += sizeof TREE_STRING_LENGTH (exp);
- }
- else if (code == COMPLEX_CST)
- {
- p = compare_constant_1 (TREE_REALPART (exp), p);
- if (p == 0) return 0;
- p = compare_constant_1 (TREE_IMAGPART (exp), p);
- return p;
- }
- else if (code == CONSTRUCTOR && TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
- {
- len = int_size_in_bytes (TREE_TYPE (exp));
- strp = (char*) alloca (len);
- get_set_constructor_bytes (exp, (unsigned char *) strp, len);
- }
- else if (code == CONSTRUCTOR)
- {
- register tree link;
- int length = list_length (CONSTRUCTOR_ELTS (exp));
- tree type;
+ break;
- if (bcmp ((char *) &length, p, sizeof length))
+ case COMPLEX_CST:
+ p = compare_constant_1 (TREE_REALPART (exp), p);
+ if (p == 0)
return 0;
- p += sizeof length;
- /* For record constructors, insist that the types match.
- For arrays, just verify both constructors are for arrays. */
- if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
- type = TREE_TYPE (exp);
- else
- type = 0;
- if (bcmp ((char *) &type, p, sizeof type))
- return 0;
- p += sizeof type;
+ return compare_constant_1 (TREE_IMAGPART (exp), p);
- /* For arrays, insist that the size in bytes match. */
- if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
+ case CONSTRUCTOR:
+ if (TREE_CODE (TREE_TYPE (exp)) == SET_TYPE)
{
- int size = int_size_in_bytes (TREE_TYPE (exp));
- if (bcmp ((char *) &size, p, sizeof size))
+ int xlen = len = int_size_in_bytes (TREE_TYPE (exp));
+
+ strp = (char *) alloca (len);
+ get_set_constructor_bytes (exp, (unsigned char *) strp, len);
+ if (bcmp ((char *) &xlen, p, sizeof xlen))
return 0;
- p += sizeof size;
- }
- for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+ p += sizeof xlen;
+ break;
+ }
+ else
{
- if (TREE_VALUE (link))
+ register tree link;
+ int length = list_length (CONSTRUCTOR_ELTS (exp));
+ tree type;
+ int have_purpose = 0;
+
+ for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+ if (TREE_PURPOSE (link))
+ have_purpose = 1;
+
+ if (bcmp ((char *) &length, p, sizeof length))
+ return 0;
+
+ p += sizeof length;
+
+ /* For record constructors, insist that the types match.
+ For arrays, just verify both constructors are for arrays.
+ Then insist that either both or none have any TREE_PURPOSE
+ values. */
+ if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
+ type = TREE_TYPE (exp);
+ else
+ type = 0;
+
+ if (bcmp ((char *) &type, p, sizeof type))
+ return 0;
+
+ p += sizeof type;
+
+ if (bcmp ((char *) &have_purpose, p, sizeof have_purpose))
+ return 0;
+
+ p += sizeof have_purpose;
+
+ /* For arrays, insist that the size in bytes match. */
+ if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
{
- if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+
+ if (bcmp ((char *) &size, p, sizeof size))
return 0;
+
+ p += sizeof size;
}
- else
+
+ for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
{
- tree zero = 0;
+ if (TREE_VALUE (link))
+ {
+ if ((p = compare_constant_1 (TREE_VALUE (link), p)) == 0)
+ return 0;
+ }
+ else
+ {
+ tree zero = 0;
- if (bcmp ((char *) &zero, p, sizeof zero))
- return 0;
- p += sizeof zero;
+ if (bcmp ((char *) &zero, p, sizeof zero))
+ return 0;
+
+ p += sizeof zero;
+ }
+
+ if (TREE_PURPOSE (link)
+ && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
+ {
+ if (bcmp ((char *) &TREE_PURPOSE (link), p,
+ sizeof TREE_PURPOSE (link)))
+ return 0;
+
+ p += sizeof TREE_PURPOSE (link);
+ }
+ else if (TREE_PURPOSE (link))
+ {
+ if ((p = compare_constant_1 (TREE_PURPOSE (link), p)) == 0)
+ return 0;
+ }
+ else if (have_purpose)
+ {
+ int zero = 0;
+
+ if (bcmp ((char *) &zero, p, sizeof zero))
+ return 0;
+
+ p += sizeof zero;
+ }
}
+
+ return p;
}
- return p;
- }
- else if (code == ADDR_EXPR)
- {
- struct addr_const value;
- decode_addr_const (exp, &value);
- strp = (char *) &value.offset;
- len = sizeof value.offset;
- /* Compare the offset. */
- while (--len >= 0)
- if (*p++ != *strp++)
- return 0;
- /* Compare symbol name. */
- strp = XSTR (value.base, 0);
- len = strlen (strp) + 1;
- }
- else if (code == PLUS_EXPR || code == MINUS_EXPR)
- {
- p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
- if (p == 0) return 0;
- p = compare_constant_1 (TREE_OPERAND (exp, 1), p);
- return p;
- }
- else if (code == NOP_EXPR || code == CONVERT_EXPR)
- {
+ case ADDR_EXPR:
+ {
+ struct addr_const value;
+
+ decode_addr_const (exp, &value);
+ strp = (char *) &value.offset;
+ len = sizeof value.offset;
+ /* Compare the offset. */
+ while (--len >= 0)
+ if (*p++ != *strp++)
+ return 0;
+
+ /* Compare symbol name. */
+ strp = XSTR (value.base, 0);
+ len = strlen (strp) + 1;
+ }
+ break;
+
+ case PLUS_EXPR:
+ case MINUS_EXPR:
p = compare_constant_1 (TREE_OPERAND (exp, 0), p);
- return p;
+ if (p == 0)
+ return 0;
+
+ return compare_constant_1 (TREE_OPERAND (exp, 1), p);
+
+ case NOP_EXPR:
+ case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
+ return compare_constant_1 (TREE_OPERAND (exp, 0), p);
+
+ default:
+ abort ();
}
/* Compare constant contents. */
@@ -2468,6 +2638,7 @@ record_constant_1 (exp)
if (flag_writable_strings)
return;
+ obstack_1grow (&permanent_obstack, TYPE_MODE (TREE_TYPE (exp)));
strp = TREE_STRING_POINTER (exp);
len = TREE_STRING_LENGTH (exp);
obstack_grow (&permanent_obstack, (char *) &TREE_STRING_LENGTH (exp),
@@ -2486,7 +2657,8 @@ record_constant_1 (exp)
obstack_grow (&permanent_obstack, &nbytes, sizeof (nbytes));
obstack_blank (&permanent_obstack, nbytes);
get_set_constructor_bytes
- (exp, (unsigned char *) permanent_obstack.next_free, nbytes);
+ (exp, (unsigned char *) permanent_obstack.next_free-nbytes,
+ nbytes);
return;
}
else
@@ -2494,21 +2666,30 @@ record_constant_1 (exp)
register tree link;
int length = list_length (CONSTRUCTOR_ELTS (exp));
tree type;
+ int have_purpose = 0;
+
+ for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
+ if (TREE_PURPOSE (link))
+ have_purpose = 1;
obstack_grow (&permanent_obstack, (char *) &length, sizeof length);
/* For record constructors, insist that the types match.
- For arrays, just verify both constructors are for arrays. */
+ For arrays, just verify both constructors are for arrays.
+ Then insist that either both or none have any TREE_PURPOSE
+ values. */
if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE)
type = TREE_TYPE (exp);
else
type = 0;
obstack_grow (&permanent_obstack, (char *) &type, sizeof type);
+ obstack_grow (&permanent_obstack, (char *) &have_purpose,
+ sizeof have_purpose);
/* For arrays, insist that the size in bytes match. */
if (TREE_CODE (TREE_TYPE (exp)) == ARRAY_TYPE)
{
- int size = int_size_in_bytes (TREE_TYPE (exp));
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
obstack_grow (&permanent_obstack, (char *) &size, sizeof size);
}
@@ -2523,6 +2704,21 @@ record_constant_1 (exp)
obstack_grow (&permanent_obstack,
(char *) &zero, sizeof zero);
}
+
+ if (TREE_PURPOSE (link)
+ && TREE_CODE (TREE_PURPOSE (link)) == FIELD_DECL)
+ obstack_grow (&permanent_obstack,
+ (char *) &TREE_PURPOSE (link),
+ sizeof TREE_PURPOSE (link));
+ else if (TREE_PURPOSE (link))
+ record_constant_1 (TREE_PURPOSE (link));
+ else if (have_purpose)
+ {
+ int zero = 0;
+
+ obstack_grow (&permanent_obstack,
+ (char *) &zero, sizeof zero);
+ }
}
}
return;
@@ -2574,6 +2770,10 @@ struct deferred_constant
static struct deferred_constant *deferred_constants;
+/* Another list of constants which should be output after the
+ function. */
+static struct deferred_constant *after_function_constants;
+
/* Nonzero means defer output of addressed subconstants
(i.e., those for which output_constant_def is called.) */
static int defer_addressed_constants_flag;
@@ -2609,6 +2809,23 @@ output_deferred_addressed_constants ()
deferred_constants = 0;
}
+/* Output any constants which should appear after a function. */
+
+static void
+output_after_function_constants ()
+{
+ struct deferred_constant *p, *next;
+
+ for (p = after_function_constants; p; p = next)
+ {
+ output_constant_def_contents (p->exp, p->reloc, p->labelno);
+ next = p->next;
+ free (p);
+ }
+
+ after_function_constants = 0;
+}
+
/* Make a copy of the whole tree structure for a constant.
This handles the same types of nodes that compare_constant
and record_constant handle. */
@@ -2634,7 +2851,8 @@ copy_constant (exp)
return copy_node (exp);
case COMPLEX_CST:
- return build_complex (copy_constant (TREE_REALPART (exp)),
+ return build_complex (TREE_TYPE (exp),
+ copy_constant (TREE_REALPART (exp)),
copy_constant (TREE_IMAGPART (exp)));
case PLUS_EXPR:
@@ -2645,6 +2863,7 @@ copy_constant (exp)
case NOP_EXPR:
case CONVERT_EXPR:
+ case NON_LVALUE_EXPR:
return build1 (TREE_CODE (exp), TREE_TYPE (exp),
copy_constant (TREE_OPERAND (exp, 0)));
@@ -2691,9 +2910,6 @@ output_constant_def (exp)
int reloc;
register rtx def;
- if (TREE_CODE (exp) == INTEGER_CST)
- abort (); /* No TREE_CST_RTL slot in these. */
-
if (TREE_CST_RTL (exp))
return TREE_CST_RTL (exp);
@@ -2743,10 +2959,10 @@ output_constant_def (exp)
if (TREE_PERMANENT (exp))
end_temporary_allocation ();
- def = gen_rtx (SYMBOL_REF, Pmode, desc->label);
+ def = gen_rtx_SYMBOL_REF (Pmode, desc->label);
TREE_CST_RTL (exp)
- = gen_rtx (MEM, TYPE_MODE (TREE_TYPE (exp)), def);
+ = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (exp)), def);
RTX_UNCHANGING_P (TREE_CST_RTL (exp)) = 1;
if (AGGREGATE_TYPE_P (TREE_TYPE (exp)))
MEM_IN_STRUCT_P (TREE_CST_RTL (exp)) = 1;
@@ -2764,7 +2980,15 @@ output_constant_def (exp)
output it (or defer its output for later). */
if (found == 0)
{
- if (defer_addressed_constants_flag)
+ int after_function = 0;
+
+#ifdef CONSTANT_AFTER_FUNCTION_P
+ if (current_function_decl != 0
+ && CONSTANT_AFTER_FUNCTION_P (exp))
+ after_function = 1;
+#endif
+
+ if (defer_addressed_constants_flag || after_function)
{
struct deferred_constant *p;
p = (struct deferred_constant *) xmalloc (sizeof (struct deferred_constant));
@@ -2775,8 +2999,16 @@ output_constant_def (exp)
pop_obstacks ();
p->reloc = reloc;
p->labelno = const_labelno++;
- p->next = deferred_constants;
- deferred_constants = p;
+ if (after_function)
+ {
+ p->next = after_function_constants;
+ after_function_constants = p;
+ }
+ else
+ {
+ p->next = deferred_constants;
+ deferred_constants = p;
+ }
}
else
output_constant_def_contents (exp, reloc, const_labelno++);
@@ -2797,7 +3029,7 @@ output_constant_def_contents (exp, reloc, labelno)
int align;
if (IN_NAMED_SECTION (exp))
- named_section (exp, NULL);
+ named_section (exp, NULL, reloc);
else
{
/* First switch to text section, except for writable strings. */
@@ -2819,16 +3051,7 @@ output_constant_def_contents (exp, reloc, labelno)
#endif
if (align > BITS_PER_UNIT)
- {
- if (!output_bytecode)
- {
- ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
- }
- else
- {
- BC_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
- }
- }
+ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
/* Output the label itself. */
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LC", labelno);
@@ -2869,6 +3092,7 @@ struct pool_constant
int labelno;
int align;
int offset;
+ int mark;
};
/* Pointers to first and last constant in pool. */
@@ -2896,7 +3120,7 @@ static struct pool_sym **const_rtx_sym_hash_table;
The argument is XSTR (... , 0) */
#define SYMHASH(LABEL) \
- ((((HOST_WIDE_INT) (LABEL)) & ((1 << HASHBITS) - 1)) % MAX_RTX_HASH_TABLE)
+ ((((unsigned long) (LABEL)) & ((1 << HASHBITS) - 1)) % MAX_RTX_HASH_TABLE)
/* Initialize constant pool hashing for next function. */
@@ -2921,14 +3145,20 @@ init_const_rtx_hash_table ()
/* Save and restore status for a nested function. */
void
-save_varasm_status (p)
+save_varasm_status (p, context)
struct function *p;
+ tree context;
{
p->const_rtx_hash_table = const_rtx_hash_table;
p->const_rtx_sym_hash_table = const_rtx_sym_hash_table;
p->first_pool = first_pool;
p->last_pool = last_pool;
p->pool_offset = pool_offset;
+ p->const_double_chain = const_double_chain;
+
+ /* If we are pushing to toplevel, we can't reuse const_double_chain. */
+ if (context == NULL_TREE)
+ const_double_chain = 0;
}
void
@@ -2940,6 +3170,7 @@ restore_varasm_status (p)
first_pool = p->first_pool;
last_pool = p->last_pool;
pool_offset = p->pool_offset;
+ const_double_chain = p->const_double_chain;
}
enum kind { RTX_DOUBLE, RTX_INT };
@@ -2979,7 +3210,7 @@ decode_rtx_const (mode, x, value)
*p++ = 0;
}
- value->kind = RTX_INT; /* Most usual kind. */
+ value->kind = RTX_INT; /* Most usual kind. */
value->mode = mode;
switch (GET_CODE (x))
@@ -3042,6 +3273,9 @@ decode_rtx_const (mode, x, value)
for the sake of addresses of library routines.
For a LABEL_REF, compare labels. */
value->un.addr.base = XEXP (value->un.addr.base, 0);
+
+ default:
+ break;
}
}
@@ -3069,7 +3303,8 @@ const_hash_rtx (mode, x)
enum machine_mode mode;
rtx x;
{
- register int hi, i;
+ register int hi;
+ register size_t i;
struct rtx_const value;
decode_rtx_const (mode, x, &value);
@@ -3200,24 +3435,34 @@ force_const_mem (mode, x)
align = (mode == VOIDmode) ? UNITS_PER_WORD : GET_MODE_SIZE (mode);
if (align > BIGGEST_ALIGNMENT / BITS_PER_UNIT)
align = BIGGEST_ALIGNMENT / BITS_PER_UNIT;
+#ifdef CONSTANT_ALIGNMENT
+ align = CONSTANT_ALIGNMENT (make_tree (type_for_mode (mode, 0), x),
+ align * BITS_PER_UNIT) / BITS_PER_UNIT;
+#endif
pool_offset += align - 1;
pool_offset &= ~ (align - 1);
/* If RTL is not being placed into the saveable obstack, make a
- copy of X that is in the saveable obstack in case we are being
- called from combine or some other phase that discards memory
- it allocates. We need only do this if it is a CONST, since
- no other RTX should be allocated in this situation. */
+ copy of X that is in the saveable obstack in case we are
+ being called from combine or some other phase that discards
+ memory it allocates. We used to only do this if it is a
+ CONST; however, reload can allocate a CONST_INT when
+ eliminating registers. */
if (rtl_obstack != saveable_obstack
- && GET_CODE (x) == CONST)
+ && (GET_CODE (x) == CONST || GET_CODE (x) == CONST_INT))
{
push_obstacks_nochange ();
rtl_in_saveable_obstack ();
- x = gen_rtx (CONST, GET_MODE (x),
- gen_rtx (PLUS, GET_MODE (x),
- XEXP (XEXP (x, 0), 0), XEXP (XEXP (x, 0), 1)));
+ if (GET_CODE (x) == CONST)
+ x = gen_rtx_CONST (GET_MODE (x),
+ gen_rtx_PLUS (GET_MODE (x),
+ XEXP (XEXP (x, 0), 0),
+ XEXP (XEXP (x, 0), 1)));
+ else
+ x = GEN_INT (INTVAL (x));
+
pop_obstacks ();
}
@@ -3230,6 +3475,7 @@ force_const_mem (mode, x)
pool->labelno = const_labelno;
pool->align = align;
pool->offset = pool_offset;
+ pool->mark = 1;
pool->next = 0;
if (last_pool == 0)
@@ -3259,7 +3505,7 @@ force_const_mem (mode, x)
/* We have a symbol name; construct the SYMBOL_REF and the MEM. */
- def = gen_rtx (MEM, mode, gen_rtx (SYMBOL_REF, Pmode, found));
+ def = gen_rtx_MEM (mode, gen_rtx_SYMBOL_REF (Pmode, found));
RTX_UNCHANGING_P (def) = 1;
/* Mark the symbol_ref as belonging to this constants pool. */
@@ -3343,6 +3589,12 @@ output_constant_pool (fnname, fndecl)
rtx x;
union real_extract u;
+ /* It is possible for gcc to call force_const_mem and then to later
+ discard the instructions which refer to the constant. In such a
+ case we do not need to output the constant. */
+ if (optimize >= 0 && flag_expensive_optimizations)
+ mark_constant_pool ();
+
#ifdef ASM_OUTPUT_POOL_PROLOGUE
ASM_OUTPUT_POOL_PROLOGUE (asm_out_file, fnname, fndecl, pool_offset);
#endif
@@ -3351,6 +3603,9 @@ output_constant_pool (fnname, fndecl)
{
x = pool->constant;
+ if (! pool->mark)
+ continue;
+
/* See if X is a LABEL_REF (or a CONST referring to a LABEL_REF)
whose CODE_LABEL has been deleted. This can occur if a jump table
is eliminated by optimization. If so, write a constant of zero
@@ -3403,12 +3658,113 @@ output_constant_pool (fnname, fndecl)
abort ();
}
+#ifdef ASM_OUTPUT_SPECIAL_POOL_ENTRY
done: ;
+#endif
+
}
+#ifdef ASM_OUTPUT_POOL_EPILOGUE
+ ASM_OUTPUT_POOL_EPILOGUE (asm_out_file, fnname, fndecl, pool_offset);
+#endif
+
/* Done with this pool. */
first_pool = last_pool = 0;
}
+
+/* Look through the instructions for this function, and mark all the
+ entries in the constant pool which are actually being used. */
+
+static void
+mark_constant_pool ()
+{
+ register rtx insn;
+ struct pool_constant *pool;
+
+ if (first_pool == 0)
+ return;
+
+ for (pool = first_pool; pool; pool = pool->next)
+ pool->mark = 0;
+
+ for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ mark_constants (PATTERN (insn));
+
+ for (insn = current_function_epilogue_delay_list;
+ insn;
+ insn = XEXP (insn, 1))
+ if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+ mark_constants (PATTERN (insn));
+}
+
+static void
+mark_constants (x)
+ register rtx x;
+{
+ register int i;
+ register char *format_ptr;
+
+ if (x == 0)
+ return;
+
+ if (GET_CODE (x) == SYMBOL_REF)
+ {
+ if (CONSTANT_POOL_ADDRESS_P (x))
+ find_pool_constant (x)->mark = 1;
+ return;
+ }
+ /* Never search inside a CONST_DOUBLE, because CONST_DOUBLE_MEM may be
+ a MEM, but does not constitute a use of that MEM. This is particularly
+ important inside a nested function, because CONST_DOUBLE_MEM may be
+ a reference to a MEM in the parent's constant pool. See the comment
+ in force_const_mem. */
+ else if (GET_CODE (x) == CONST_DOUBLE)
+ return;
+
+ /* Insns may appear inside a SEQUENCE. Only check the patterns of
+ insns, not any notes that may be attached. We don't want to mark
+ a constant just because it happens to appear in a REG_EQUIV note. */
+ if (GET_RTX_CLASS (GET_CODE (x)) == 'i')
+ {
+ mark_constants (PATTERN (x));
+ return;
+ }
+
+ format_ptr = GET_RTX_FORMAT (GET_CODE (x));
+
+ for (i = 0; i < GET_RTX_LENGTH (GET_CODE (x)); i++)
+ {
+ switch (*format_ptr++)
+ {
+ case 'e':
+ mark_constants (XEXP (x, i));
+ break;
+
+ case 'E':
+ if (XVEC (x, i) != 0)
+ {
+ register int j;
+
+ for (j = 0; j < XVECLEN (x, i); j++)
+ mark_constants (XVECEXP (x, i, j));
+ }
+ break;
+
+ case 'S':
+ case 's':
+ case '0':
+ case 'i':
+ case 'w':
+ case 'n':
+ case 'u':
+ break;
+
+ default:
+ abort ();
+ }
+ }
+}
/* Find all the constants whose addresses are referenced inside of EXP,
and make sure assembler code with a label has been output for each one.
@@ -3461,7 +3817,7 @@ output_addressed_constants (exp)
}
break;
- case ERROR_MARK:
+ default:
break;
}
return reloc;
@@ -3491,7 +3847,6 @@ output_constant (exp, size)
register int size;
{
register enum tree_code code = TREE_CODE (TREE_TYPE (exp));
- rtx x;
if (size == 0)
return;
@@ -3509,10 +3864,7 @@ output_constant (exp, size)
This means to fill the space with zeros. */
if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
{
- if (output_bytecode)
- bc_emit_const_skip (size);
- else
- assemble_zeros (size);
+ assemble_zeros (size);
return;
}
@@ -3597,110 +3949,15 @@ output_constant (exp, size)
else
error ("unknown set constructor type");
return;
+
+ default:
+ break; /* ??? */
}
if (size > 0)
assemble_zeros (size);
}
-/* Bytecode specific code to output assembler for integer. */
-
-static void
-bc_assemble_integer (exp, size)
- tree exp;
- int size;
-{
- tree const_part;
- tree addr_part;
- tree tmp;
-
- /* FIXME: is this fold() business going to be as good as the
- expand_expr() using EXPAND_SUM above in the RTL case? I
- hate RMS.
- FIXME: Copied as is from BC-GCC1; may need work. Don't hate. -bson */
-
- exp = fold (exp);
-
- while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR)
- exp = TREE_OPERAND (exp, 0);
- if (TREE_CODE (exp) == INTEGER_CST)
- {
- const_part = exp;
- addr_part = 0;
- }
- else if (TREE_CODE (exp) == PLUS_EXPR)
- {
- const_part = TREE_OPERAND (exp, 0);
- while (TREE_CODE (const_part) == NOP_EXPR
- || TREE_CODE (const_part) == CONVERT_EXPR)
- const_part = TREE_OPERAND (const_part, 0);
- addr_part = TREE_OPERAND (exp, 1);
- while (TREE_CODE (addr_part) == NOP_EXPR
- || TREE_CODE (addr_part) == CONVERT_EXPR)
- addr_part = TREE_OPERAND (addr_part, 0);
- if (TREE_CODE (const_part) != INTEGER_CST)
- tmp = const_part, const_part = addr_part, addr_part = tmp;
- if (TREE_CODE (const_part) != INTEGER_CST
- || TREE_CODE (addr_part) != ADDR_EXPR)
- abort (); /* FIXME: we really haven't considered
- all the possible cases here. */
- }
- else if (TREE_CODE (exp) == ADDR_EXPR)
- {
- const_part = integer_zero_node;
- addr_part = exp;
- }
- else
- abort (); /* FIXME: ditto previous. */
-
- if (addr_part == 0)
- {
- if (size == 1)
- {
- char c = TREE_INT_CST_LOW (const_part);
- bc_emit (&c, 1);
- size -= 1;
- }
- else if (size == 2)
- {
- short s = TREE_INT_CST_LOW (const_part);
- bc_emit ((char *) &s, 2);
- size -= 2;
- }
- else if (size == 4)
- {
- int i = TREE_INT_CST_LOW (const_part);
- bc_emit ((char *) &i, 4);
- size -= 4;
- }
- else if (size == 8)
- {
- if (WORDS_BIG_ENDIAN)
- {
- int i = TREE_INT_CST_HIGH (const_part);
- bc_emit ((char *) &i, 4);
- i = TREE_INT_CST_LOW (const_part);
- bc_emit ((char *) &i, 4);
- }
- else
- {
- int i = TREE_INT_CST_LOW (const_part);
- bc_emit ((char *) &i, 4);
- i = TREE_INT_CST_HIGH (const_part);
- bc_emit ((char *) &i, 4);
- }
- size -= 8;
- }
- }
- else
- if (size == 4
- && TREE_CODE (TREE_OPERAND (addr_part, 0)) == VAR_DECL)
- bc_emit_labelref (IDENTIFIER_POINTER
- (DECL_ASSEMBLER_NAME (TREE_OPERAND (addr_part, 0))),
- TREE_INT_CST_LOW (const_part));
- else
- abort (); /* FIXME: there may be more cases. */
-}
/* Subroutine of output_constant, used for CONSTRUCTORs
(aggregate constants).
@@ -3761,7 +4018,26 @@ output_constructor (exp, size)
if (val != 0)
STRIP_NOPS (val);
- if (field == 0 || !DECL_BIT_FIELD (field))
+ if (index && TREE_CODE (index) == RANGE_EXPR)
+ {
+ register int fieldsize
+ = int_size_in_bytes (TREE_TYPE (TREE_TYPE (exp)));
+ HOST_WIDE_INT lo_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 0));
+ HOST_WIDE_INT hi_index = TREE_INT_CST_LOW (TREE_OPERAND (index, 1));
+ HOST_WIDE_INT index;
+ for (index = lo_index; index <= hi_index; index++)
+ {
+ /* Output the element's initial value. */
+ if (val == 0)
+ assemble_zeros (fieldsize);
+ else
+ output_constant (val, fieldsize);
+
+ /* Count its size. */
+ total_bytes += fieldsize;
+ }
+ }
+ else if (field == 0 || !DECL_BIT_FIELD (field))
{
/* An element that is not a bit-field. */
@@ -3789,10 +4065,7 @@ output_constructor (exp, size)
if each element has the proper size. */
if ((field != 0 || index != 0) && bitpos != total_bytes)
{
- if (!output_bytecode)
- assemble_zeros (bitpos - total_bytes);
- else
- bc_emit_const_skip (bitpos - total_bytes);
+ assemble_zeros (bitpos - total_bytes);
total_bytes = bitpos;
}
@@ -3942,7 +4215,7 @@ output_constructor (exp, size)
}
/* Now get the bits from the appropriate constant word. */
- if (shift < HOST_BITS_PER_INT)
+ if (shift < HOST_BITS_PER_WIDE_INT)
value = TREE_INT_CST_LOW (val);
else if (shift < 2 * HOST_BITS_PER_WIDE_INT)
{
@@ -3970,6 +4243,7 @@ output_constructor (exp, size)
}
/* Output asm to handle ``#pragma weak'' */
+
void
handle_pragma_weak (what, name, value)
enum pragma_state what;
@@ -4012,6 +4286,13 @@ declare_weak (decl)
error_with_decl (decl, "weak declaration of `%s' must precede definition");
else if (SUPPORTS_WEAK)
DECL_WEAK (decl) = 1;
+
+#ifdef HANDLE_PRAGMA_WEAK
+ /* Make sure this function name gets on the weak declaration list. */
+ handle_pragma_weak (ps_name,
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)),
+ NULL);
+#endif
}
/* Emit any pending weak declarations. */
@@ -4037,12 +4318,12 @@ void
assemble_alias (decl, target)
tree decl, target;
{
-#ifdef ASM_OUTPUT_DEF
char *name;
- make_decl_rtl (decl, (char*)0, 1);
+ make_decl_rtl (decl, (char *) 0, 1);
name = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+#ifdef ASM_OUTPUT_DEF
/* Make name accessible from other files, if appropriate. */
if (TREE_PUBLIC (decl))
@@ -4052,15 +4333,70 @@ assemble_alias (decl, target)
ASM_WEAKEN_LABEL (asm_out_file, name);
else
#endif
- if (output_bytecode)
- BC_GLOBALIZE_LABEL (asm_out_file, name);
- else
ASM_GLOBALIZE_LABEL (asm_out_file, name);
}
ASM_OUTPUT_DEF (asm_out_file, name, IDENTIFIER_POINTER (target));
TREE_ASM_WRITTEN (decl) = 1;
#else
- warning ("alias definitions not supported in this configuration");
+#ifdef ASM_OUTPUT_WEAK_ALIAS
+ if (! DECL_WEAK (decl))
+ warning ("only weak aliases are supported in this configuration");
+
+ ASM_OUTPUT_WEAK_ALIAS (asm_out_file, name, IDENTIFIER_POINTER (target));
+ TREE_ASM_WRITTEN (decl) = 1;
+#else
+ warning ("alias definitions not supported in this configuration; ignored");
+#endif
+#endif
+}
+
+/* This determines whether or not we support link-once semantics. */
+#ifndef SUPPORTS_ONE_ONLY
+#ifdef MAKE_DECL_ONE_ONLY
+#define SUPPORTS_ONE_ONLY 1
+#else
+#define SUPPORTS_ONE_ONLY 0
+#endif
+#endif
+
+/* Returns 1 if the target configuration supports defining public symbols
+ so that one of them will be chosen at link time instead of generating a
+ multiply-defined symbol error, whether through the use of weak symbols or
+ a target-specific mechanism for having duplicates discarded. */
+
+int
+supports_one_only ()
+{
+ if (SUPPORTS_ONE_ONLY)
+ return 1;
+ return SUPPORTS_WEAK;
+}
+
+/* Set up DECL as a public symbol that can be defined in multiple
+ translation units without generating a linker error. */
+
+void
+make_decl_one_only (decl)
+ tree decl;
+{
+ if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL)
+ abort ();
+
+ TREE_PUBLIC (decl) = 1;
+
+ if (TREE_CODE (decl) == VAR_DECL
+ && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node))
+ DECL_COMMON (decl) = 1;
+ else if (SUPPORTS_ONE_ONLY)
+ {
+#ifdef MAKE_DECL_ONE_ONLY
+ MAKE_DECL_ONE_ONLY (decl);
#endif
+ DECL_ONE_ONLY (decl) = 1;
+ }
+ else if (SUPPORTS_WEAK)
+ DECL_WEAK (decl) = 1;
+ else
+ abort ();
}
diff --git a/contrib/gcc/varray.c b/contrib/gcc/varray.c
new file mode 100644
index 0000000..80f15b2
--- /dev/null
+++ b/contrib/gcc/varray.c
@@ -0,0 +1,70 @@
+/* Virtual array support.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions.
+
+ This file is part of GNU CC.
+
+ GNU CC 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, or (at your option)
+ any later version.
+
+ GNU CC 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 GNU CC; see the file COPYING. If not, write to the Free
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "rtl.h"
+#include "tree.h"
+#include "bitmap.h"
+#include "varray.h"
+
+#define VARRAY_HDR_SIZE (sizeof (struct varray_head_tag) - sizeof (varray_data))
+
+/* Allocate a virtual array with NUM_ELEMENT elements, each of which is
+ ELEMENT_SIZE bytes long, named NAME. Array elements are zeroed. */
+varray_type
+varray_init (num_elements, element_size, name)
+ size_t num_elements;
+ size_t element_size;
+ const char *name;
+{
+ size_t data_size = num_elements * element_size;
+ varray_type ptr = (varray_type) xcalloc (VARRAY_HDR_SIZE + data_size, 1);
+
+ ptr->num_elements = num_elements;
+ ptr->element_size = element_size;
+ ptr->name = name;
+ return ptr;
+}
+
+/* Grow/shrink the virtual array VA to N elements. Zero any new elements
+ allocated. */
+varray_type
+varray_grow (va, n)
+ varray_type va;
+ size_t n;
+{
+ size_t old_elements = va->num_elements;
+
+ if (n != old_elements)
+ {
+ size_t element_size = va->element_size;
+ size_t old_data_size = old_elements * element_size;
+ size_t data_size = n * element_size;
+
+ va = (varray_type) xrealloc ((char *)va, VARRAY_HDR_SIZE + data_size);
+ va->num_elements = n;
+ if (n > old_elements)
+ bzero (&va->data.c[old_data_size], data_size - old_data_size);
+ }
+
+ return va;
+}
diff --git a/contrib/gcc/varray.h b/contrib/gcc/varray.h
new file mode 100644
index 0000000..df3ca31
--- /dev/null
+++ b/contrib/gcc/varray.h
@@ -0,0 +1,166 @@
+/* Virtual array support.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions.
+
+ This file is part of GNU CC.
+
+ GNU CC 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, or (at your option)
+ any later version.
+
+ GNU CC 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 GNU CC; see the file COPYING. If not, write to the Free
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _VARRAY_H_
+#define _VARRAY_H_
+
+#ifndef PROTO
+#include "gansidecl.h"
+#endif
+
+#ifndef HOST_WIDE_INT
+#include "machmode.h"
+#endif
+
+#ifndef __GCC_SYSTEM_H__
+#include "system.h"
+#endif
+
+/* Union of various array types that are used. */
+typedef union varray_data_tag {
+ char c[1];
+ unsigned char uc[1];
+ short s[1];
+ unsigned short us[1];
+ int i[1];
+ unsigned int u[1];
+ long l[1];
+ unsigned long ul[1];
+ HOST_WIDE_INT hint[1];
+ unsigned HOST_WIDE_INT uhint[1];
+ GENERIC_PTR generic[1];
+ char *cptr[1];
+ struct rtx_def *rtx[1];
+ struct rtvec_def *rtvec[1];
+ union tree_node *tree[1];
+ struct bitmap_head_def *bitmap[1];
+ struct sched_info_tag *sched[1];
+ struct reg_info_def *reg[1];
+} varray_data;
+
+/* Virtual array of pointers header. */
+typedef struct varray_head_tag {
+ size_t num_elements; /* maximum element number allocated */
+ size_t element_size; /* size of each data element */
+ const char *name; /* name of the varray for reporting errors */
+ varray_data data; /* data elements follow, must be last */
+} *varray_type;
+
+/* Allocate a virtual array with NUM elements, each of which is SIZE bytes
+ long, named NAME. Array elements are zeroed. */
+extern varray_type varray_init PROTO ((size_t, size_t, const char *));
+
+#define VARRAY_CHAR_INIT(va, num, name) \
+ va = varray_init (num, sizeof (char), name)
+
+#define VARRAY_UCHAR_INIT(va, num, name) \
+ va = varray_init (num, sizeof (unsigned char), name)
+
+#define VARRAY_SHORT_INIT(va, num, name) \
+ va = varray_init (num, sizeof (short), name)
+
+#define VARRAY_USHORT_INIT(va, num, name) \
+ va = varray_init (num, sizeof (unsigned short), name)
+
+#define VARRAY_INT_INIT(va, num, name) \
+ va = varray_init (num, sizeof (int), name)
+
+#define VARRAY_UINT_INIT(va, num, name) \
+ va = varray_init (num, sizeof (unsigned int), name)
+
+#define VARRAY_LONG_INIT(va, num, name) \
+ va = varray_init (num, sizeof (long), name)
+
+#define VARRAY_ULONG_INIT(va, num, name) \
+ va = varray_init (num, sizeof (unsigned long), name)
+
+#define VARRAY_WIDE_INT_INIT(va, num, name) \
+ va = varray_init (num, sizeof (HOST_WIDE_INT), name)
+
+#define VARRAY_UWIDE_INT_INIT(va, num, name) \
+ va = varray_init (num, sizeof (unsigned HOST_WIDE_INT), name)
+
+#define VARRAY_GENERIC_PTR_INIT(va, num, name) \
+ va = varray_init (num, sizeof (GENERIC_PTR), name)
+
+#define VARRAY_CHAR_PTR_INIT(va, num, name) \
+ va = varray_init (num, sizeof (char *), name)
+
+#define VARRAY_RTX_INIT(va, num, name) \
+ va = varray_init (num, sizeof (struct rtx_def *), name)
+
+#define VARRAY_RTVEC_INIT(va, num, name) \
+ va = varray_init (num, sizeof (struct rtvec_def), name)
+
+#define VARRAY_TREE_INIT(va, num, name) \
+ va = varray_init (num, sizeof (union tree_node *), name)
+
+#define VARRAY_BITMAP_INIT(va, num, name) \
+ va = varray_init (num, sizeof (struct bitmap_head_def *), name)
+
+#define VARRAY_SCHED_INIT(va, num, name) \
+ va = varray_init (num, sizeof (struct sched_info_tag *), name)
+
+#define VARRAY_REG_INIT(va, num, name) \
+ va = varray_init (num, sizeof (struct reg_info_def *), name)
+
+/* Free up memory allocated by the virtual array, but do not free any of the
+ elements involved. */
+#define VARRAY_FREE(vp) ((vp) && (free (vp), (vp = (varray_type)0)))
+
+/* Grow/shrink the virtual array VA to N elements. */
+extern varray_type varray_grow PROTO((varray_type, size_t));
+
+#define VARRAY_GROW(VA, N) ((VA) = varray_grow (VA, N))
+
+/* Check for VARRAY_xxx macros being in bound, return N for use as an
+ index. */
+#ifdef ENABLE_CHECKING
+#define VARRAY_CHECK(VA, N) \
+((((size_t)(N) < (VA)->num_elements) \
+ ? 0 \
+ : (fatal ("Virtual array %s element %ld out of bounds, at %s:%d", \
+ (VA)->name, (long)(N), __FILE__, __LINE__), 0)), \
+ (N))
+#else
+#define VARRAY_CHECK(VA, N) (N)
+#endif
+
+#define VARRAY_CHAR(VA, N) ((VA)->data.c[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_UCHAR(VA, N) ((VA)->data.uc[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_SHORT(VA, N) ((VA)->data.s[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_USHORT(VA, N) ((VA)->data.us[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_INT(VA, N) ((VA)->data.i[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_UINT(VA, N) ((VA)->data.u[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_LONG(VA, N) ((VA)->data.l[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_ULONG(VA, N) ((VA)->data.ul[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_WIDE_INT(VA, N) ((VA)->data.hint[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_UWIDE_INT(VA, N) ((VA)->data.uhint[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_GENERIC_PTR(VA,N) ((VA)->data.generic[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_CHAR_PTR(VA,N) ((VA)->data.cptr[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_RTX(VA, N) ((VA)->data.rtx[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_RTVEC(VA, N) ((VA)->data.rtvec[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_TREE(VA, N) ((VA)->data.tree[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_BITMAP(VA, N) ((VA)->data.bitmap[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_SCHED(VA, N) ((VA)->data.sched[ VARRAY_CHECK (VA, N) ])
+#define VARRAY_REG(VA, N) ((VA)->data.reg[ VARRAY_CHECK (VA, N) ])
+
+#endif /* _VARRAY_H_ */
diff --git a/contrib/gcc/version.c b/contrib/gcc/version.c
index dd8c145..573f16b 100644
--- a/contrib/gcc/version.c
+++ b/contrib/gcc/version.c
@@ -1 +1 @@
-char *version_string = "2.7.2.3";
+char *version_string = "egcs-2.91.66 19990314 (egcs-1.1.2 release)";
diff --git a/contrib/gcc/xcoffout.c b/contrib/gcc/xcoffout.c
index 14ebce8..baa0cd2 100644
--- a/contrib/gcc/xcoffout.c
+++ b/contrib/gcc/xcoffout.c
@@ -1,5 +1,5 @@
/* Output xcoff-format symbol table information from GNU compiler.
- Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1992, 1994, 1995, 1997 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -24,13 +24,13 @@ Boston, MA 02111-1307, USA. */
interface. Many functions are very similar to their counterparts in
sdbout.c. */
-/* Include this first, because it may define MIN and MAX. */
-#include <stdio.h>
-
#include "config.h"
+#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "flags.h"
+#include "toplev.h"
+#include "output.h"
#ifdef XCOFF_DEBUGGING_INFO
@@ -38,8 +38,9 @@ Boston, MA 02111-1307, USA. */
#include <dbxstclass.h>
#include "xcoffout.h"
+#include "dbxout.h"
-#if defined (USG) || defined (NO_STAB_H)
+#if defined (USG) || !defined (HAVE_STAB_H)
#include "gstab.h"
#else
#include <stab.h>
@@ -53,8 +54,8 @@ Boston, MA 02111-1307, USA. */
/* Line number of beginning of current function, minus one.
Negative means not in a function or not using xcoff. */
-int xcoff_begin_function_line = -1;
-int xcoff_inlining = 0;
+static int xcoff_begin_function_line = -1;
+static int xcoff_inlining = 0;
/* Name of the current include file. */
@@ -65,7 +66,7 @@ char *xcoff_current_include_file;
(by including that file of course), then the line number will be
absolute. */
-char *xcoff_current_function_file;
+static char *xcoff_current_function_file;
/* Names of bss and data sections. These should be unique names for each
compilation unit. */
@@ -113,6 +114,9 @@ char *xcoff_lastfile;
#define ASM_OUTPUT_LBE(FILE,LINENUM,BLOCKNUM) \
fprintf (FILE, "\t.eb\t%d\n", ABS_OR_RELATIVE_LINENO (LINENUM))
+
+static void assign_type_number PROTO((tree, char *, int));
+static void xcoffout_block PROTO((tree, int, tree));
/* Support routines for XCOFF debugging info. */
@@ -145,14 +149,14 @@ xcoff_output_standard_types (syms)
{
/* Handle built-in C types here. */
- assign_type_number (syms, "int", (TARGET_64BIT ? -31 : -1));
+ assign_type_number (syms, "int", -1);
assign_type_number (syms, "char", -2);
assign_type_number (syms, "short int", -3);
assign_type_number (syms, "long int", (TARGET_64BIT ? -31 : -4));
assign_type_number (syms, "unsigned char", -5);
assign_type_number (syms, "signed char", -6);
assign_type_number (syms, "short unsigned int", -7);
- assign_type_number (syms, "unsigned int", (TARGET_64BIT ? -32 : -8));
+ assign_type_number (syms, "unsigned int", -8);
/* No such type "unsigned". */
assign_type_number (syms, "long unsigned int", (TARGET_64BIT ? -32 : -10));
assign_type_number (syms, "void", -11);
@@ -496,6 +500,16 @@ xcoffout_begin_function (file, last_linenum)
{
ASM_OUTPUT_LFB (file, last_linenum);
dbxout_parms (DECL_ARGUMENTS (current_function_decl));
+
+ /* Emit the symbols for the outermost BLOCK's variables. sdbout.c does this
+ in sdbout_begin_block, but there is no guarantee that there will be any
+ inner block 1, so we must do it here. This gives a result similar to
+ dbxout, so it does make some sense. */
+ do_block = 0;
+ next_block_number = 0;
+ xcoffout_block (DECL_INITIAL (current_function_decl), 0,
+ DECL_ARGUMENTS (current_function_decl));
+
ASM_OUTPUT_SOURCE_LINE (file, last_linenum);
}
diff --git a/contrib/gcc/xcoffout.h b/contrib/gcc/xcoffout.h
index 432a5de..2781a79 100644
--- a/contrib/gcc/xcoffout.h
+++ b/contrib/gcc/xcoffout.h
@@ -58,8 +58,8 @@
#define DBX_STATIC_BLOCK_END(ASMFILE,CODE) \
{ \
- if (current_sym_code == N_STSYM || current_sym_code == N_LCSYM) \
- fprintf (asmfile, "\t.es\n"); \
+ if ((CODE) == N_STSYM || (CODE) == N_LCSYM) \
+ fputs ("\t.es\n", (ASMFILE)); \
}
/* We must use N_RPYSM instead of N_RSYM for register parameters. */
@@ -115,22 +115,10 @@
#define N_RPSYM 0x8e
#endif
-/* The line number of the beginning of the current function.
- xcoffout.c needs this so that it can output relative linenumbers. */
-
-extern int xcoff_begin_function_line;
-
/* Name of the current include file. */
extern char *xcoff_current_include_file;
-/* Name of the current function file. This is the file the `.bf' is
- emitted from. In case a line is emitted from a different file,
- (by including that file of course), then the line number will be
- absolute. */
-
-extern char *xcoff_current_function_file;
-
/* Names of bss and data sections. These should be unique names for each
compilation unit. */
@@ -151,16 +139,16 @@ extern char *xcoff_lastfile;
is already emitting a .file directory, so we don't output one here also.
Initialize xcoff_lastfile. */
#define DBX_OUTPUT_MAIN_SOURCE_FILENAME(FILE,FILENAME) \
- xcoff_lastfile = input_file_name
+ xcoff_lastfile = (FILENAME)
/* If we are still in an include file, its end must be marked. */
#define DBX_OUTPUT_MAIN_SOURCE_FILE_END(FILE, FILENAME) \
{ \
if (xcoff_current_include_file) \
{ \
- fprintf (FILE, "\t.ei\t"); \
- output_quoted_string (FILE, xcoff_current_include_file); \
- fprintf (FILE, "\n"); \
+ fputs ("\t.ei\t", (FILE)); \
+ output_quoted_string ((FILE), xcoff_current_include_file); \
+ putc ('\n', (FILE)); \
xcoff_current_include_file = NULL; \
} \
}
@@ -178,3 +166,27 @@ extern char *xcoff_lastfile;
can't find them. */
#define DEBUG_SYMS_TEXT
+
+/* Prototype functions in xcoffout.c. */
+
+extern int stab_to_sclass PROTO ((int));
+#ifdef BUFSIZ
+extern void xcoffout_begin_function PROTO ((FILE *, int));
+extern void xcoffout_begin_block PROTO ((FILE *, int, int));
+extern void xcoffout_end_epilogue PROTO ((FILE *));
+extern void xcoffout_end_function PROTO ((FILE *, int));
+extern void xcoffout_end_block PROTO ((FILE *, int, int));
+#endif /* BUFSIZ */
+
+#ifdef TREE_CODE
+extern void xcoff_output_standard_types PROTO ((tree));
+#ifdef BUFSIZ
+extern void xcoffout_declare_function PROTO ((FILE *, tree, char *));
+#endif /* BUFSIZ */
+#endif /* TREE_CODE */
+
+#ifdef RTX_CODE
+#ifdef BUFSIZ
+extern void xcoffout_source_line PROTO ((FILE *, char *, rtx));
+#endif /* BUFSIZ */
+#endif /* RTX_CODE */
OpenPOWER on IntegriCloud